summaryrefslogtreecommitdiff
path: root/chromium/components
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-04 14:17:57 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-05 10:05:06 +0000
commit39d357e3248f80abea0159765ff39554affb40db (patch)
treeaba0e6bfb76de0244bba0f5fdbd64b830dd6e621 /chromium/components
parent87778abf5a1f89266f37d1321b92a21851d8244d (diff)
downloadqtwebengine-chromium-39d357e3248f80abea0159765ff39554affb40db.tar.gz
BASELINE: Update Chromium to 55.0.2883.105
And updates ninja to 1.7.2 Change-Id: I20d43c737f82764d857ada9a55586901b18b9243 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components')
-rw-r--r--chromium/components/BUILD.gn49
-rw-r--r--chromium/components/OWNERS33
-rw-r--r--chromium/components/README15
-rw-r--r--chromium/components/about_handler.gypi27
-rw-r--r--chromium/components/about_handler/BUILD.gn2
-rw-r--r--chromium/components/app_modal.gypi47
-rw-r--r--chromium/components/arc.gypi247
-rw-r--r--chromium/components/arc/BUILD.gn103
-rw-r--r--chromium/components/arc/arc_bridge_bootstrap.cc458
-rw-r--r--chromium/components/arc/arc_bridge_bootstrap.h39
-rw-r--r--chromium/components/arc/arc_bridge_host_impl.cc247
-rw-r--r--chromium/components/arc/arc_bridge_host_impl.h100
-rw-r--r--chromium/components/arc/arc_bridge_service.cc189
-rw-r--r--chromium/components/arc/arc_bridge_service.h193
-rw-r--r--chromium/components/arc/arc_bridge_service_impl.cc91
-rw-r--r--chromium/components/arc/arc_bridge_service_impl.h34
-rw-r--r--chromium/components/arc/arc_bridge_service_unittest.cc142
-rw-r--r--chromium/components/arc/arc_features.cc14
-rw-r--r--chromium/components/arc/arc_features.h18
-rw-r--r--chromium/components/arc/arc_service_manager.cc48
-rw-r--r--chromium/components/arc/arc_service_manager.h7
-rw-r--r--chromium/components/arc/audio/arc_audio_bridge.cc23
-rw-r--r--chromium/components/arc/bitmap/OWNERS2
-rw-r--r--chromium/components/arc/bitmap/bitmap_struct_traits.cc36
-rw-r--r--chromium/components/arc/bitmap/bitmap_struct_traits.h30
-rw-r--r--chromium/components/arc/bitmap/bitmap_type_converters.cc36
-rw-r--r--chromium/components/arc/bitmap/bitmap_type_converters.h20
-rw-r--r--chromium/components/arc/bluetooth/arc_bluetooth_bridge.cc820
-rw-r--r--chromium/components/arc/bluetooth/arc_bluetooth_bridge.h100
-rw-r--r--chromium/components/arc/bluetooth/arc_bluetooth_bridge_unittest.cc331
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_struct_traits.cc238
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_struct_traits.h42
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc153
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_type_converters.cc43
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_type_converters.h16
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc32
-rw-r--r--chromium/components/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc57
-rw-r--r--chromium/components/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h44
-rw-r--r--chromium/components/arc/clipboard/arc_clipboard_bridge.cc13
-rw-r--r--chromium/components/arc/common/OWNERS3
-rw-r--r--chromium/components/arc/common/app_struct_traits.cc5
-rw-r--r--chromium/components/arc/common/app_struct_traits.h2
-rw-r--r--chromium/components/arc/common/arc_bridge.mojom23
-rw-r--r--chromium/components/arc/common/auth.mojom25
-rw-r--r--chromium/components/arc/common/bitmap.typemap13
-rw-r--r--chromium/components/arc/common/bluetooth.mojom36
-rw-r--r--chromium/components/arc/common/bluetooth.typemap4
-rw-r--r--chromium/components/arc/common/boot_phase_monitor.mojom19
-rw-r--r--chromium/components/arc/common/enterprise_reporting.mojom8
-rw-r--r--chromium/components/arc/common/intent_helper.mojom20
-rw-r--r--chromium/components/arc/common/notifications.mojom5
-rw-r--r--chromium/components/arc/common/print.mojom18
-rw-r--r--chromium/components/arc/common/process.mojom15
-rw-r--r--chromium/components/arc/common/tts.mojom43
-rw-r--r--chromium/components/arc/common/typemaps.gni1
-rw-r--r--chromium/components/arc/common/wallpaper.mojom28
-rw-r--r--chromium/components/arc/common/window_manager.mojom16
-rw-r--r--chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc67
-rw-r--r--chromium/components/arc/crash_collector/arc_crash_collector_bridge.h10
-rw-r--r--chromium/components/arc/ime/arc_ime_bridge_impl.cc56
-rw-r--r--chromium/components/arc/ime/arc_ime_service.cc40
-rw-r--r--chromium/components/arc/ime/arc_ime_service.h14
-rw-r--r--chromium/components/arc/ime/arc_ime_service_unittest.cc13
-rw-r--r--chromium/components/arc/instance_holder.h121
-rw-r--r--chromium/components/arc/intent_helper/activity_icon_loader.cc38
-rw-r--r--chromium/components/arc/intent_helper/activity_icon_loader.h1
-rw-r--r--chromium/components/arc/intent_helper/activity_icon_loader_unittest.cc1
-rw-r--r--chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc79
-rw-r--r--chromium/components/arc/intent_helper/arc_intent_helper_bridge.h29
-rw-r--r--chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc40
-rw-r--r--chromium/components/arc/intent_helper/intent_filter.cc6
-rw-r--r--chromium/components/arc/intent_helper/link_handler_model_impl.cc37
-rw-r--r--chromium/components/arc/intent_helper/link_handler_model_impl.h4
-rw-r--r--chromium/components/arc/intent_helper/link_handler_model_impl_unittest.cc2
-rw-r--r--chromium/components/arc/intent_helper/local_activity_resolver.h2
-rw-r--r--chromium/components/arc/metrics/arc_metrics_service.cc19
-rw-r--r--chromium/components/arc/metrics/arc_metrics_service.h2
-rw-r--r--chromium/components/arc/metrics/oom_kills_monitor.cc68
-rw-r--r--chromium/components/arc/metrics/oom_kills_monitor.h47
-rw-r--r--chromium/components/arc/net/arc_net_host_impl.cc60
-rw-r--r--chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc3
-rw-r--r--chromium/components/arc/power/arc_power_bridge.cc21
-rw-r--r--chromium/components/arc/set_wallpaper_delegate.h25
-rw-r--r--chromium/components/arc/standalone/arc_standalone_bridge_main.cc29
-rw-r--r--chromium/components/arc/standalone/arc_standalone_bridge_runner.cc34
-rw-r--r--chromium/components/arc/standalone/arc_standalone_bridge_runner.h42
-rw-r--r--chromium/components/arc/standalone/service_helper.cc73
-rw-r--r--chromium/components/arc/standalone/service_helper.h46
-rw-r--r--chromium/components/arc/standalone/service_helper_unittest.cc86
-rw-r--r--chromium/components/arc/storage_manager/arc_storage_manager.cc37
-rw-r--r--chromium/components/arc/storage_manager/arc_storage_manager.h2
-rw-r--r--chromium/components/arc/user_data/arc_user_data_service.cc24
-rw-r--r--chromium/components/arc/user_data/arc_user_data_service.h24
-rw-r--r--chromium/components/arc/window_manager/arc_window_manager_bridge.cc56
-rw-r--r--chromium/components/arc/window_manager/arc_window_manager_bridge.h12
-rw-r--r--chromium/components/audio_modem.gypi54
-rw-r--r--chromium/components/audio_modem/BUILD.gn72
-rw-r--r--chromium/components/audio_modem/DEPS5
-rw-r--r--chromium/components/audio_modem/OWNERS3
-rw-r--r--chromium/components/audio_modem/audio_modem_switches.cc22
-rw-r--r--chromium/components/audio_modem/audio_modem_switches.h18
-rw-r--r--chromium/components/audio_modem/audio_player.h43
-rw-r--r--chromium/components/audio_modem/audio_player_impl.cc163
-rw-r--r--chromium/components/audio_modem/audio_player_impl.h89
-rw-r--r--chromium/components/audio_modem/audio_player_unittest.cc224
-rw-r--r--chromium/components/audio_modem/audio_recorder.h39
-rw-r--r--chromium/components/audio_modem/audio_recorder_impl.cc205
-rw-r--r--chromium/components/audio_modem/audio_recorder_impl.h102
-rw-r--r--chromium/components/audio_modem/audio_recorder_unittest.cc282
-rw-r--r--chromium/components/audio_modem/constants.cc15
-rw-r--r--chromium/components/audio_modem/modem_impl.cc344
-rw-r--r--chromium/components/audio_modem/modem_impl.h127
-rw-r--r--chromium/components/audio_modem/modem_unittest.cc155
-rw-r--r--chromium/components/audio_modem/public/audio_modem_types.h75
-rw-r--r--chromium/components/audio_modem/public/modem.h46
-rw-r--r--chromium/components/audio_modem/public/whispernet_client.h62
-rw-r--r--chromium/components/auto_login_parser.gypi23
-rw-r--r--chromium/components/auto_login_parser/BUILD.gn27
-rw-r--r--chromium/components/auto_login_parser/DEPS3
-rw-r--r--chromium/components/auto_login_parser/OWNERS1
-rw-r--r--chromium/components/auto_login_parser/auto_login_parser.cc86
-rw-r--r--chromium/components/auto_login_parser/auto_login_parser.h50
-rw-r--r--chromium/components/auto_login_parser/auto_login_parser_unittest.cc92
-rw-r--r--chromium/components/autofill.gypi639
-rw-r--r--chromium/components/autofill/android/BUILD.gn24
-rw-r--r--chromium/components/autofill/android/OWNERS1
-rw-r--r--chromium/components/autofill/android/java/res/drawable/autofill_chip_inset.xml15
-rw-r--r--chromium/components/autofill/android/java/res/layout/autofill_keyboard_accessory_icon.xml13
-rw-r--r--chromium/components/autofill/android/java/res/layout/autofill_keyboard_accessory_item.xml40
-rw-r--r--chromium/components/autofill/android/java/res/values/dimens.xml18
-rw-r--r--chromium/components/autofill/content/DEPS2
-rw-r--r--chromium/components/autofill/content/browser/BUILD.gn16
-rw-r--r--chromium/components/autofill/content/browser/DEPS1
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.cc156
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.h41
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_factory.cc11
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_factory.h6
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc382
-rw-r--r--chromium/components/autofill/content/browser/payments/payments_client_unittest.cc89
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint.cc46
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc21
-rw-r--r--chromium/components/autofill/content/common/BUILD.gn8
-rw-r--r--chromium/components/autofill/content/common/DEPS2
-rw-r--r--chromium/components/autofill/content/common/OWNERS2
-rw-r--r--chromium/components/autofill/content/common/autofill_messages.h295
-rw-r--r--chromium/components/autofill/content/common/autofill_param_traits_macros.h1
-rw-r--r--chromium/components/autofill/content/public/cpp/DEPS3
-rw-r--r--chromium/components/autofill/content/public/cpp/autofill_types.typemap12
-rw-r--r--chromium/components/autofill/content/public/cpp/autofill_types_struct_traits.cc408
-rw-r--r--chromium/components/autofill/content/public/cpp/autofill_types_struct_traits.h295
-rw-r--r--chromium/components/autofill/content/public/cpp/autofill_types_struct_traits_unittest.cc181
-rw-r--r--chromium/components/autofill/content/public/interfaces/BUILD.gn4
-rw-r--r--chromium/components/autofill/content/public/interfaces/autofill_agent.mojom96
-rw-r--r--chromium/components/autofill/content/public/interfaces/autofill_driver.mojom102
-rw-r--r--chromium/components/autofill/content/public/interfaces/autofill_types.mojom110
-rw-r--r--chromium/components/autofill/content/public/interfaces/test_autofill_types.mojom3
-rw-r--r--chromium/components/autofill/content/renderer/BUILD.gn6
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.cc254
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.h67
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.cc114
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.h20
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.cc4
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.cc270
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.h60
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.cc76
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.h11
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc15
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.cc97
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.h35
-rw-r--r--chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.cc12
-rw-r--r--chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.h22
-rw-r--r--chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc97
-rw-r--r--chromium/components/autofill/content/renderer/test_password_generation_agent.h1
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn34
-rw-r--r--chromium/components/autofill/core/browser/DEPS3
-rw-r--r--chromium/components/autofill/core/browser/address_rewriter_rules.cc3327
-rw-r--r--chromium/components/autofill/core/browser/autofill_assistant.cc68
-rw-r--r--chromium/components/autofill/core/browser/autofill_assistant.h65
-rw-r--r--chromium/components/autofill/core/browser/autofill_assistant_unittest.cc207
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.h26
-rw-r--r--chromium/components/autofill/core/browser/autofill_country.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_country_unittest.cc16
-rw-r--r--chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.cc100
-rw-r--r--chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h75
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_util.cc260
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_util.h28
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_util_unittest.cc123
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.cc42
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.h8
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.cc36
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.h22
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.cc85
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.h10
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc112
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.cc28
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.h9
-rw-r--r--chromium/components/autofill/core/browser/autofill_field_trial_ios.cc33
-rw-r--r--chromium/components/autofill/core/browser/autofill_field_trial_ios.h28
-rw-r--r--chromium/components/autofill/core/browser/autofill_field_unittest.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc129
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h44
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager_unittest.cc426
-rw-r--r--chromium/components/autofill/core/browser/autofill_merge_unittest.cc9
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.cc22
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.h9
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics_unittest.cc122
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile.cc39
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_comparator.cc106
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_comparator.h15
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_comparator_unittest.cc78
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_unittest.cc24
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.cc8
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.h4
-rw-r--r--chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc61
-rw-r--r--chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h33
-rw-r--r--chromium/components/autofill/core/browser/contact_info.cc12
-rw-r--r--chromium/components/autofill/core/browser/country_data.cc25
-rw-r--r--chromium/components/autofill/core/browser/credit_card.cc13
-rw-r--r--chromium/components/autofill/core/browser/credit_card.h9
-rw-r--r--chromium/components/autofill/core/browser/credit_card_unittest.cc28
-rw-r--r--chromium/components/autofill/core/browser/form_field.cc1
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc150
-rw-r--r--chromium/components/autofill/core/browser/form_structure.h26
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc357
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.cc12
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.h11
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc174
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.cc56
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.h13
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc44
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.h56
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc189
-rw-r--r--chromium/components/autofill/core/browser/phone_field_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/popup_item_ids.h1
-rw-r--r--chromium/components/autofill/core/browser/proto/server.proto13
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.cc14
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.h10
-rw-r--r--chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc7
-rw-r--r--chromium/components/autofill/core/browser/validation.cc5
-rw-r--r--chromium/components/autofill/core/browser/validation_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/DEPS2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc9
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h18
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.cc27
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.h14
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc41
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc40
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h19
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc9
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h14
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc23
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.cc2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc20
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc10
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc10
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc5
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h2
-rw-r--r--chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc22
-rw-r--r--chromium/components/autofill/core/common/BUILD.gn5
-rw-r--r--chromium/components/autofill/core/common/DEPS3
-rw-r--r--chromium/components/autofill/core/common/autofill_constants.h4
-rw-r--r--chromium/components/autofill/core/common/autofill_pref_names.cc4
-rw-r--r--chromium/components/autofill/core/common/autofill_pref_names.h1
-rw-r--r--chromium/components/autofill/core/common/autofill_switches.cc14
-rw-r--r--chromium/components/autofill/core/common/autofill_switches.h4
-rw-r--r--chromium/components/autofill/core/common/autofill_util.cc27
-rw-r--r--chromium/components/autofill/core/common/autofill_util.h9
-rw-r--r--chromium/components/autofill/core/common/form_data.cc11
-rw-r--r--chromium/components/autofill/core/common/form_data.h5
-rw-r--r--chromium/components/autofill/core/common/form_field_data.cc68
-rw-r--r--chromium/components/autofill/core/common/form_field_data.h30
-rw-r--r--chromium/components/autofill/core/common/form_field_data_unittest.cc42
-rw-r--r--chromium/components/autofill/core/common/password_form.cc11
-rw-r--r--chromium/components/autofill/core/common/password_form.h15
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.cc4
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.h2
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data_unittest.cc44
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.h17
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.cc66
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.h22
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc6
-rw-r--r--chromium/components/autofill/core/common/signatures_util.cc107
-rw-r--r--chromium/components/autofill/core/common/signatures_util.h43
-rw-r--r--chromium/components/autofill/ios/browser/js_autofill_manager.h11
-rw-r--r--chromium/components/autofill/ios/browser/js_autofill_manager.mm56
-rw-r--r--chromium/components/autofill/ios/browser/js_suggestion_manager.mm34
-rw-r--r--chromium/components/autofill/ios/browser/resources/autofill_controller.js40
-rw-r--r--chromium/components/autofill/ios/browser/resources/suggestion_controller.js5
-rw-r--r--chromium/components/autofill_strings.grdp25
-rw-r--r--chromium/components/base32.gypi23
-rw-r--r--chromium/components/base32/BUILD.gn2
-rw-r--r--chromium/components/bitmap_uploader/BUILD.gn21
-rw-r--r--chromium/components/bitmap_uploader/DEPS9
-rw-r--r--chromium/components/bitmap_uploader/OWNERS11
-rw-r--r--chromium/components/bitmap_uploader/bitmap_uploader.cc210
-rw-r--r--chromium/components/bitmap_uploader/bitmap_uploader.h94
-rw-r--r--chromium/components/bitmap_uploader/bitmap_uploader_export.h32
-rw-r--r--chromium/components/bookmarks.gypi205
-rw-r--r--chromium/components/bookmarks/browser/BUILD.gn9
-rw-r--r--chromium/components/bookmarks/browser/bookmark_codec.cc19
-rw-r--r--chromium/components/bookmarks/browser/bookmark_codec.h5
-rw-r--r--chromium/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc2
-rw-r--r--chromium/components/bookmarks/browser/bookmark_index.cc1
-rw-r--r--chromium/components/bookmarks/browser/bookmark_index_unittest.cc2
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model.cc156
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model.h9
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model_unittest.cc19
-rw-r--r--chromium/components/bookmarks/browser/bookmark_node_data_unittest.cc15
-rw-r--r--chromium/components/bookmarks/browser/bookmark_storage.cc2
-rw-r--r--chromium/components/bookmarks/browser/bookmark_storage.h26
-rw-r--r--chromium/components/bookmarks/browser/bookmark_utils_unittest.cc29
-rw-r--r--chromium/components/bookmarks/common/BUILD.gn2
-rw-r--r--chromium/components/bookmarks/common/android/BUILD.gn7
-rw-r--r--chromium/components/bookmarks/common/android/bookmark_id.cc4
-rw-r--r--chromium/components/bookmarks/common/android/bookmark_id.h2
-rw-r--r--chromium/components/bookmarks/managed/BUILD.gn2
-rw-r--r--chromium/components/bookmarks/managed/managed_bookmark_service.cc5
-rw-r--r--chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc5
-rw-r--r--chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc19
-rw-r--r--chromium/components/browser_sync.gypi111
-rw-r--r--chromium/components/browser_sync/BUILD.gn135
-rw-r--r--chromium/components/browser_sync/DEPS28
-rw-r--r--chromium/components/browser_sync/abstract_profile_sync_service_test.cc239
-rw-r--r--chromium/components/browser_sync/abstract_profile_sync_service_test.h110
-rw-r--r--chromium/components/browser_sync/browser/BUILD.gn136
-rw-r--r--chromium/components/browser_sync/browser/DEPS29
-rw-r--r--chromium/components/browser_sync/browser/abstract_profile_sync_service_test.cc238
-rw-r--r--chromium/components/browser_sync/browser/abstract_profile_sync_service_test.h107
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_components_factory_impl.cc392
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_components_factory_impl.h122
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_service.cc2543
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_service.h1029
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_service_autofill_unittest.cc1489
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_service_bookmark_unittest.cc2594
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_service_mock.cc17
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_service_mock.h102
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_service_startup_unittest.cc485
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_service_typed_url_unittest.cc1089
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_service_unittest.cc973
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_test_util.cc275
-rw-r--r--chromium/components/browser_sync/browser/profile_sync_test_util.h186
-rw-r--r--chromium/components/browser_sync/browser/signin_confirmation_helper.cc118
-rw-r--r--chromium/components/browser_sync/browser/signin_confirmation_helper.h70
-rw-r--r--chromium/components/browser_sync/browser/test_http_bridge_factory.cc46
-rw-r--r--chromium/components/browser_sync/browser/test_http_bridge_factory.h52
-rw-r--r--chromium/components/browser_sync/browser/test_profile_sync_service.cc32
-rw-r--r--chromium/components/browser_sync/browser/test_profile_sync_service.h50
-rw-r--r--chromium/components/browser_sync/browser_sync_switches.cc22
-rw-r--r--chromium/components/browser_sync/browser_sync_switches.h18
-rw-r--r--chromium/components/browser_sync/common/BUILD.gn16
-rw-r--r--chromium/components/browser_sync/common/browser_sync_switches.cc22
-rw-r--r--chromium/components/browser_sync/common/browser_sync_switches.h18
-rw-r--r--chromium/components/browser_sync/profile_sync_components_factory_impl.cc430
-rw-r--r--chromium/components/browser_sync/profile_sync_components_factory_impl.h133
-rw-r--r--chromium/components/browser_sync/profile_sync_service.cc2500
-rw-r--r--chromium/components/browser_sync/profile_sync_service.h1017
-rw-r--r--chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc1474
-rw-r--r--chromium/components/browser_sync/profile_sync_service_bookmark_unittest.cc2601
-rw-r--r--chromium/components/browser_sync/profile_sync_service_mock.cc21
-rw-r--r--chromium/components/browser_sync/profile_sync_service_mock.h105
-rw-r--r--chromium/components/browser_sync/profile_sync_service_startup_unittest.cc474
-rw-r--r--chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc1055
-rw-r--r--chromium/components/browser_sync/profile_sync_service_unittest.cc955
-rw-r--r--chromium/components/browser_sync/profile_sync_test_util.cc275
-rw-r--r--chromium/components/browser_sync/profile_sync_test_util.h187
-rw-r--r--chromium/components/browser_sync/signin_confirmation_helper.cc120
-rw-r--r--chromium/components/browser_sync/signin_confirmation_helper.h70
-rw-r--r--chromium/components/browser_sync/test_http_bridge_factory.cc44
-rw-r--r--chromium/components/browser_sync/test_http_bridge_factory.h54
-rw-r--r--chromium/components/browser_sync/test_profile_sync_service.cc36
-rw-r--r--chromium/components/browser_sync/test_profile_sync_service.h54
-rw-r--r--chromium/components/browser_watcher.gypi46
-rw-r--r--chromium/components/browser_watcher/BUILD.gn79
-rw-r--r--chromium/components/browser_watcher/DEPS3
-rw-r--r--chromium/components/browser_watcher/OWNERS1
-rw-r--r--chromium/components/browser_watcher/dump_postmortem_minidump_main_win.cc105
-rw-r--r--chromium/components/browser_watcher/features.cc13
-rw-r--r--chromium/components/browser_watcher/features.h16
-rw-r--r--chromium/components/browser_watcher/postmortem_minidump_writer.h48
-rw-r--r--chromium/components/browser_watcher/postmortem_minidump_writer_win.cc419
-rw-r--r--chromium/components/browser_watcher/postmortem_minidump_writer_win_unittest.cc160
-rw-r--r--chromium/components/browser_watcher/postmortem_report_collector.cc217
-rw-r--r--chromium/components/browser_watcher/postmortem_report_collector.h105
-rw-r--r--chromium/components/browser_watcher/postmortem_report_collector_unittest.cc429
-rw-r--r--chromium/components/browser_watcher/stability_debugging_win.cc63
-rw-r--r--chromium/components/browser_watcher/stability_debugging_win.h28
-rw-r--r--chromium/components/browser_watcher/stability_debugging_win_unittest.cc85
-rw-r--r--chromium/components/browser_watcher/stability_report.proto78
-rw-r--r--chromium/components/browser_watcher/watcher_metrics_provider_win.cc101
-rw-r--r--chromium/components/browser_watcher/watcher_metrics_provider_win.h42
-rw-r--r--chromium/components/browser_watcher/watcher_metrics_provider_win_unittest.cc23
-rw-r--r--chromium/components/browser_watcher/window_hang_monitor_win.cc4
-rw-r--r--chromium/components/browsing_data.gypi27
-rw-r--r--chromium/components/browsing_data/BUILD.gn21
-rw-r--r--chromium/components/browsing_data/conditional_cache_deletion_helper.cc96
-rw-r--r--chromium/components/browsing_data/conditional_cache_deletion_helper.h73
-rw-r--r--chromium/components/browsing_data/content/BUILD.gn20
-rw-r--r--chromium/components/browsing_data/content/DEPS (renamed from chromium/components/browsing_data/DEPS)0
-rw-r--r--chromium/components/browsing_data/content/conditional_cache_deletion_helper.cc96
-rw-r--r--chromium/components/browsing_data/content/conditional_cache_deletion_helper.h73
-rw-r--r--chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.cc310
-rw-r--r--chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.h116
-rw-r--r--chromium/components/browsing_data/core/BUILD.gn69
-rw-r--r--chromium/components/browsing_data/core/DEPS18
-rw-r--r--chromium/components/browsing_data/core/OWNERS1
-rw-r--r--chromium/components/browsing_data/core/browsing_data_utils.cc176
-rw-r--r--chromium/components/browsing_data/core/browsing_data_utils.h60
-rw-r--r--chromium/components/browsing_data/core/browsing_data_utils_unittest.cc79
-rw-r--r--chromium/components/browsing_data/core/counters/autofill_counter.cc172
-rw-r--r--chromium/components/browsing_data/core/counters/autofill_counter.h93
-rw-r--r--chromium/components/browsing_data/core/counters/browsing_data_counter.cc96
-rw-r--r--chromium/components/browsing_data/core/counters/browsing_data_counter.h120
-rw-r--r--chromium/components/browsing_data/core/counters/history_counter.cc172
-rw-r--r--chromium/components/browsing_data/core/counters/history_counter.h89
-rw-r--r--chromium/components/browsing_data/core/counters/passwords_counter.cc52
-rw-r--r--chromium/components/browsing_data/core/counters/passwords_counter.h48
-rw-r--r--chromium/components/browsing_data/core/history_notice_utils.cc115
-rw-r--r--chromium/components/browsing_data/core/history_notice_utils.h58
-rw-r--r--chromium/components/browsing_data/core/history_notice_utils_unittest.cc187
-rw-r--r--chromium/components/browsing_data/core/pref_names.cc70
-rw-r--r--chromium/components/browsing_data/core/pref_names.h37
-rw-r--r--chromium/components/browsing_data/storage_partition_http_cache_data_remover.cc310
-rw-r--r--chromium/components/browsing_data/storage_partition_http_cache_data_remover.h116
-rw-r--r--chromium/components/browsing_data_strings.grdp99
-rw-r--r--chromium/components/browsing_data_ui.gypi27
-rw-r--r--chromium/components/browsing_data_ui/BUILD.gn36
-rw-r--r--chromium/components/browsing_data_ui/DEPS10
-rw-r--r--chromium/components/browsing_data_ui/OWNERS2
-rw-r--r--chromium/components/browsing_data_ui/history_notice_utils.cc115
-rw-r--r--chromium/components/browsing_data_ui/history_notice_utils.h58
-rw-r--r--chromium/components/browsing_data_ui/history_notice_utils_unittest.cc187
-rw-r--r--chromium/components/bubble.gypi43
-rw-r--r--chromium/components/bubble/BUILD.gn4
-rw-r--r--chromium/components/bubble/bubble_manager.cc4
-rw-r--r--chromium/components/captive_portal.gypi48
-rw-r--r--chromium/components/captive_portal/BUILD.gn2
-rw-r--r--chromium/components/cast_certificate.gypi42
-rw-r--r--chromium/components/cast_certificate/BUILD.gn9
-rw-r--r--chromium/components/cast_certificate/DEPS1
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator.cc169
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator.h59
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc6
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator_test_helpers.h4
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator_unittest.cc192
-rw-r--r--chromium/components/cast_certificate/cast_crl.cc363
-rw-r--r--chromium/components/cast_certificate/cast_crl.h66
-rw-r--r--chromium/components/cast_certificate/cast_crl_root_ca_cert_der-inc.h150
-rw-r--r--chromium/components/cast_certificate/cast_crl_unittest.cc260
-rw-r--r--chromium/components/cast_certificate/proto/BUILD.gn37
-rw-r--r--chromium/components/cast_certificate/proto/revocation.proto60
-rw-r--r--chromium/components/cast_certificate/proto/test_suite.proto56
-rw-r--r--chromium/components/cdm.gypi80
-rw-r--r--chromium/components/cdm/common/BUILD.gn2
-rw-r--r--chromium/components/cdm/renderer/BUILD.gn2
-rw-r--r--chromium/components/cdm/renderer/android_key_systems.cc6
-rw-r--r--chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc89
-rw-r--r--chromium/components/cdm/renderer/external_clear_key_key_system_properties.h48
-rw-r--r--chromium/components/certificate_reporting.gypi57
-rw-r--r--chromium/components/certificate_reporting/BUILD.gn3
-rw-r--r--chromium/components/certificate_reporting/error_reporter.cc25
-rw-r--r--chromium/components/certificate_reporting/error_reporter.h3
-rw-r--r--chromium/components/certificate_reporting/error_reporter_unittest.cc115
-rw-r--r--chromium/components/certificate_transparency.gypi37
-rw-r--r--chromium/components/certificate_transparency/BUILD.gn10
-rw-r--r--chromium/components/certificate_transparency/DEPS2
-rw-r--r--chromium/components/certificate_transparency/log_dns_client.cc330
-rw-r--r--chromium/components/certificate_transparency/log_dns_client.h136
-rw-r--r--chromium/components/certificate_transparency/log_dns_client_unittest.cc615
-rw-r--r--chromium/components/certificate_transparency/log_proof_fetcher.cc81
-rw-r--r--chromium/components/certificate_transparency/log_proof_fetcher.h5
-rw-r--r--chromium/components/certificate_transparency/mock_log_dns_traffic.cc271
-rw-r--r--chromium/components/certificate_transparency/mock_log_dns_traffic.h162
-rw-r--r--chromium/components/certificate_transparency/single_tree_tracker.cc44
-rw-r--r--chromium/components/certificate_transparency/single_tree_tracker_unittest.cc48
-rw-r--r--chromium/components/chooser_controller.gypi43
-rw-r--r--chromium/components/chooser_controller/BUILD.gn34
-rw-r--r--chromium/components/chooser_controller/DEPS3
-rw-r--r--chromium/components/chooser_controller/OWNERS2
-rw-r--r--chromium/components/chooser_controller/README2
-rw-r--r--chromium/components/chooser_controller/chooser_controller.cc18
-rw-r--r--chromium/components/chooser_controller/chooser_controller.h92
-rw-r--r--chromium/components/chooser_controller/mock_chooser_controller.cc36
-rw-r--r--chromium/components/chooser_controller/mock_chooser_controller.h36
-rw-r--r--chromium/components/chrome_apps.gypi51
-rw-r--r--chromium/components/chrome_apps/BUILD.gn6
-rw-r--r--chromium/components/client_update_protocol.gypi41
-rw-r--r--chromium/components/client_update_protocol/BUILD.gn2
-rw-r--r--chromium/components/cloud_devices.gypi35
-rw-r--r--chromium/components/cloud_devices/common/description_items_inl.h16
-rw-r--r--chromium/components/cloud_devices/common/printer_description.cc7
-rw-r--r--chromium/components/component_updater.gypi59
-rw-r--r--chromium/components/component_updater/BUILD.gn8
-rw-r--r--chromium/components/component_updater/README.md80
-rw-r--r--chromium/components/component_updater/component_updater_service.cc105
-rw-r--r--chromium/components/component_updater/component_updater_service.h33
-rw-r--r--chromium/components/component_updater/component_updater_service_internal.h26
-rw-r--r--chromium/components/component_updater/component_updater_service_unittest.cc69
-rw-r--r--chromium/components/component_updater/configurator_impl.cc19
-rw-r--r--chromium/components/component_updater/configurator_impl.h9
-rw-r--r--chromium/components/component_updater/configurator_impl_unittest.cc53
-rw-r--r--chromium/components/component_updater/default_component_installer.cc42
-rw-r--r--chromium/components/component_updater/default_component_installer.h9
-rw-r--r--chromium/components/component_updater/default_component_installer_unittest.cc17
-rw-r--r--chromium/components/component_updater/mock_component_updater_service.h6
-rw-r--r--chromium/components/component_updater/pref_names.cc4
-rw-r--r--chromium/components/component_updater/pref_names.h1
-rw-r--r--chromium/components/component_updater/updater_state_unittest_win.cc103
-rw-r--r--chromium/components/component_updater/updater_state_win.cc195
-rw-r--r--chromium/components/component_updater/updater_state_win.h57
-rw-r--r--chromium/components/components.gyp221
-rw-r--r--chromium/components/components_browsertests.isolate85
-rw-r--r--chromium/components/components_browsertests_apk.isolate28
-rw-r--r--chromium/components/components_chromium_strings.grd2
-rw-r--r--chromium/components/components_google_chrome_strings.grd2
-rw-r--r--chromium/components/components_locale_settings.grd2
-rw-r--r--chromium/components/components_resources.gyp93
-rw-r--r--chromium/components/components_strings.grd20
-rw-r--r--chromium/components/components_strings.gyp51
-rw-r--r--chromium/components/components_tests.gyp2058
-rw-r--r--chromium/components/components_unittests.isolate96
-rw-r--r--chromium/components/components_unittests_apk.isolate26
-rw-r--r--chromium/components/constrained_window.gypi24
-rw-r--r--chromium/components/constrained_window/BUILD.gn30
-rw-r--r--chromium/components/constrained_window/DEPS3
-rw-r--r--chromium/components/constrained_window/constrained_window_views.cc55
-rw-r--r--chromium/components/constrained_window/constrained_window_views.h21
-rw-r--r--chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views.cc233
-rw-r--r--chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views.h92
-rw-r--r--chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views_mac.h33
-rw-r--r--chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views_mac.mm98
-rw-r--r--chromium/components/constrained_window/show_modal_dialog_cocoa.cc34
-rw-r--r--chromium/components/constrained_window/show_modal_dialog_views.cc27
-rw-r--r--chromium/components/constrained_window/test_create_native_web_modal_manager_cocoa.cc16
-rw-r--r--chromium/components/content_settings.gypi148
-rw-r--r--chromium/components/content_settings/DEPS3
-rw-r--r--chromium/components/content_settings/content/DEPS4
-rw-r--r--chromium/components/content_settings/content/common/BUILD.gn19
-rw-r--r--chromium/components/content_settings/content/common/DEPS3
-rw-r--r--chromium/components/content_settings/content/common/content_settings_message_generator.cc39
-rw-r--r--chromium/components/content_settings/content/common/content_settings_message_generator.h7
-rw-r--r--chromium/components/content_settings/content/common/content_settings_messages.h96
-rw-r--r--chromium/components/content_settings/core/browser/BUILD.gn11
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_binary_value_map.cc18
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_binary_value_map.h1
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_client.h70
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_default_provider.cc57
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_default_provider.h5
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_info.cc2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc22
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h1
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_policy_provider.cc9
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref.h1
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref_provider.cc32
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref_provider.h5
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_provider.h1
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_registry.cc40
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_rule.cc18
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_rule.h7
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_usages_state.cc12
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_usages_state.h4
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_utils.cc2
-rw-r--r--chromium/components/content_settings/core/browser/host_content_settings_map.cc198
-rw-r--r--chromium/components/content_settings/core/browser/host_content_settings_map.h30
-rw-r--r--chromium/components/content_settings/core/browser/local_shared_objects_counter.h28
-rw-r--r--chromium/components/content_settings/core/browser/plugins_field_trial.cc23
-rw-r--r--chromium/components/content_settings/core/browser/plugins_field_trial.h28
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_info.h6
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_registry.cc26
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_registry_unittest.cc14
-rw-r--r--chromium/components/content_settings/core/common/content_settings.cc6
-rw-r--r--chromium/components/content_settings/core/common/content_settings_pattern.cc61
-rw-r--r--chromium/components/content_settings/core/common/content_settings_pattern.h12
-rw-r--r--chromium/components/content_settings/core/common/content_settings_pattern_unittest.cc96
-rw-r--r--chromium/components/content_settings/core/common/content_settings_types.h3
-rw-r--r--chromium/components/content_settings/core/common/pref_names.cc6
-rw-r--r--chromium/components/content_settings/core/common/pref_names.h1
-rw-r--r--chromium/components/contextual_search.gypi59
-rw-r--r--chromium/components/contextual_search/BUILD.gn22
-rw-r--r--chromium/components/contextual_search/OWNERS1
-rw-r--r--chromium/components/contextual_search/browser/contextual_search_js_api_service_impl.cc13
-rw-r--r--chromium/components/contextual_search/browser/contextual_search_js_api_service_impl.h8
-rw-r--r--chromium/components/contextual_search/browser/ctr_aggregator.cc118
-rw-r--r--chromium/components/contextual_search/browser/ctr_aggregator.h118
-rw-r--r--chromium/components/contextual_search/browser/ctr_aggregator_unittest.cc138
-rw-r--r--chromium/components/contextual_search/browser/weekly_activity_storage.cc129
-rw-r--r--chromium/components/contextual_search/browser/weekly_activity_storage.h88
-rw-r--r--chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.cc20
-rw-r--r--chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.h4
-rw-r--r--chromium/components/contextual_search/renderer/overlay_page_notifier_service_impl.cc8
-rw-r--r--chromium/components/contextual_search/renderer/overlay_page_notifier_service_impl.h11
-rw-r--r--chromium/components/cookie_config.gypi26
-rw-r--r--chromium/components/cookie_config/BUILD.gn3
-rw-r--r--chromium/components/copresence.gypi98
-rw-r--r--chromium/components/copresence/BUILD.gn87
-rw-r--r--chromium/components/copresence/DEPS8
-rw-r--r--chromium/components/copresence/OWNERS4
-rw-r--r--chromium/components/copresence/copresence_manager_impl.cc270
-rw-r--r--chromium/components/copresence/copresence_manager_impl.h105
-rw-r--r--chromium/components/copresence/copresence_state_impl.cc179
-rw-r--r--chromium/components/copresence/copresence_state_impl.h71
-rw-r--r--chromium/components/copresence/copresence_state_unittest.cc149
-rw-r--r--chromium/components/copresence/copresence_switches.cc18
-rw-r--r--chromium/components/copresence/copresence_switches.h17
-rw-r--r--chromium/components/copresence/handlers/audio/audio_directive_handler.h42
-rw-r--r--chromium/components/copresence/handlers/audio/audio_directive_handler_impl.cc241
-rw-r--r--chromium/components/copresence/handlers/audio/audio_directive_handler_impl.h86
-rw-r--r--chromium/components/copresence/handlers/audio/audio_directive_handler_unittest.cc179
-rw-r--r--chromium/components/copresence/handlers/audio/audio_directive_list.cc93
-rw-r--r--chromium/components/copresence/handlers/audio/audio_directive_list.h88
-rw-r--r--chromium/components/copresence/handlers/audio/audio_directive_list_unittest.cc84
-rw-r--r--chromium/components/copresence/handlers/audio/tick_clock_ref_counted.cc26
-rw-r--r--chromium/components/copresence/handlers/audio/tick_clock_ref_counted.h41
-rw-r--r--chromium/components/copresence/handlers/directive_handler.h50
-rw-r--r--chromium/components/copresence/handlers/directive_handler_impl.cc126
-rw-r--r--chromium/components/copresence/handlers/directive_handler_impl.h52
-rw-r--r--chromium/components/copresence/handlers/directive_handler_unittest.cc147
-rw-r--r--chromium/components/copresence/handlers/gcm_handler.h40
-rw-r--r--chromium/components/copresence/handlers/gcm_handler_impl.cc158
-rw-r--r--chromium/components/copresence/handlers/gcm_handler_impl.h84
-rw-r--r--chromium/components/copresence/handlers/gcm_handler_unittest.cc72
-rw-r--r--chromium/components/copresence/proto/BUILD.gn18
-rw-r--r--chromium/components/copresence/proto/codes.proto23
-rw-r--r--chromium/components/copresence/proto/config_data.proto91
-rw-r--r--chromium/components/copresence/proto/data.proto138
-rw-r--r--chromium/components/copresence/proto/enums.proto91
-rw-r--r--chromium/components/copresence/proto/identity.proto20
-rw-r--r--chromium/components/copresence/proto/push_message.proto20
-rw-r--r--chromium/components/copresence/proto/rpcs.proto67
-rw-r--r--chromium/components/copresence/public/copresence_constants.h36
-rw-r--r--chromium/components/copresence/public/copresence_delegate.h77
-rw-r--r--chromium/components/copresence/public/copresence_manager.h46
-rw-r--r--chromium/components/copresence/public/copresence_observer.h35
-rw-r--r--chromium/components/copresence/public/copresence_state.h47
-rw-r--r--chromium/components/copresence/rpc/http_post.cc110
-rw-r--r--chromium/components/copresence/rpc/http_post.h75
-rw-r--r--chromium/components/copresence/rpc/http_post_unittest.cc143
-rw-r--r--chromium/components/copresence/rpc/rpc_handler.cc620
-rw-r--r--chromium/components/copresence/rpc/rpc_handler.h213
-rw-r--r--chromium/components/copresence/rpc/rpc_handler_unittest.cc348
-rw-r--r--chromium/components/copresence/timed_map.h114
-rw-r--r--chromium/components/copresence/timed_map_unittest.cc131
-rw-r--r--chromium/components/copresence/tokens.cc25
-rw-r--r--chromium/components/copresence/tokens.h49
-rw-r--r--chromium/components/crash.gypi484
-rw-r--r--chromium/components/crash/content/app/BUILD.gn33
-rw-r--r--chromium/components/crash/content/app/breakpad_linux.cc22
-rw-r--r--chromium/components/crash/content/app/breakpad_linux.h4
-rw-r--r--chromium/components/crash/content/app/breakpad_mac.mm2
-rw-r--r--chromium/components/crash/content/app/breakpad_win.cc8
-rw-r--r--chromium/components/crash/content/app/crash_reporter_client.cc17
-rw-r--r--chromium/components/crash/content/app/crash_reporter_client.h23
-rw-r--r--chromium/components/crash/content/app/crashpad.cc234
-rw-r--r--chromium/components/crash/content/app/crashpad.h36
-rw-r--r--chromium/components/crash/content/app/crashpad_mac.mm48
-rw-r--r--chromium/components/crash/content/app/crashpad_win.cc36
-rw-r--r--chromium/components/crash/content/browser/crash_dump_manager_android.cc3
-rw-r--r--chromium/components/crash/content/browser/crash_handler_host_linux.cc71
-rw-r--r--chromium/components/crash/content/browser/crash_handler_host_linux.h18
-rw-r--r--chromium/components/crash/content/tools/BUILD.gn2
-rwxr-xr-xchromium/components/crash/content/tools/generate_breakpad_symbols.py2
-rw-r--r--chromium/components/crash/core/browser/BUILD.gn2
-rw-r--r--chromium/components/crash/core/browser/DEPS1
-rw-r--r--chromium/components/crash/core/browser/crashes_ui_util.cc8
-rw-r--r--chromium/components/crash/core/browser/crashes_ui_util.h1
-rw-r--r--chromium/components/crash/core/browser/resources/crashes.html10
-rw-r--r--chromium/components/crash/core/browser/resources/crashes.js70
-rw-r--r--chromium/components/crash/core/common/BUILD.gn32
-rw-r--r--chromium/components/crash/core/common/crash_export.h29
-rw-r--r--chromium/components/crash/core/common/objc_zombie.h5
-rw-r--r--chromium/components/crash_strings.grdp10
-rw-r--r--chromium/components/cronet.gypi962
-rw-r--r--chromium/components/cronet/android/BUILD.gn322
-rw-r--r--chromium/components/cronet/android/cronet_test_instrumentation_apk.isolate14
-rw-r--r--chromium/components/cronet/cronet_static.gypi87
-rw-r--r--chromium/components/cronet/ios/BUILD.gn100
-rw-r--r--chromium/components/crx_file.gypi25
-rw-r--r--chromium/components/crx_file/BUILD.gn2
-rw-r--r--chromium/components/data_reduction_proxy.gypi303
-rw-r--r--chromium/components/data_reduction_proxy/DEPS1
-rw-r--r--chromium/components/data_reduction_proxy/OWNERS1
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/BUILD.gn7
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/DEPS1
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.cc22
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc99
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service.cc12
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service.h13
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc31
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc56
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h48
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc69
-rw-r--r--chromium/components/data_reduction_proxy/content/common/BUILD.gn16
-rw-r--r--chromium/components/data_reduction_proxy/content/common/DEPS4
-rw-r--r--chromium/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.cc39
-rw-r--r--chromium/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h15
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/BUILD.gn14
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc17
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc15
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc13
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h4
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc25
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc109
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h37
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc68
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc72
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h30
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc65
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h12
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc180
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc9
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h3
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc190
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc11
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h30
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc38
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc123
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h49
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc614
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc29
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc12
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc10
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc16
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h23
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc6
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc136
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h22
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc181
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc132
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h18
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc146
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc4
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc7
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc21
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h23
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc8
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h1
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc37
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc18
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc16
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc14
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc13
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc73
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc14
-rw-r--r--chromium/components/data_reduction_proxy/core/common/BUILD.gn11
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.cc134
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h64
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc47
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h5
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc47
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc14
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h16
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc32
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h38
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc83
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h23
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc52
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc12
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h2
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc10
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h2
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_util.cc22
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_util.h12
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_savings_recorder.h30
-rw-r--r--chromium/components/data_reduction_proxy/core/common/lofi_decider.h5
-rw-r--r--chromium/components/data_reduction_proxy/core/common/lofi_ui_service.h6
-rw-r--r--chromium/components/data_reduction_proxy/proto/data_store.proto10
-rw-r--r--chromium/components/data_reduction_proxy/proto/pageload_metrics.proto32
-rw-r--r--chromium/components/data_usage.gypi44
-rw-r--r--chromium/components/data_usage/core/BUILD.gn2
-rw-r--r--chromium/components/data_usage/core/data_use_aggregator_unittest.cc2
-rw-r--r--chromium/components/data_use_measurement.gypi39
-rw-r--r--chromium/components/data_use_measurement/OWNERS4
-rw-r--r--chromium/components/data_use_measurement/content/BUILD.gn3
-rw-r--r--chromium/components/data_use_measurement/content/data_use_measurement.cc215
-rw-r--r--chromium/components/data_use_measurement/content/data_use_measurement.h69
-rw-r--r--chromium/components/data_use_measurement/content/data_use_measurement_unittest.cc163
-rw-r--r--chromium/components/data_use_measurement/core/BUILD.gn10
-rw-r--r--chromium/components/data_use_measurement/core/data_use.cc18
-rw-r--r--chromium/components/data_use_measurement/core/data_use.h55
-rw-r--r--chromium/components/data_use_measurement/core/data_use_ascriber.cc52
-rw-r--r--chromium/components/data_use_measurement/core/data_use_ascriber.h57
-rw-r--r--chromium/components/data_use_measurement/core/data_use_network_delegate.cc54
-rw-r--r--chromium/components/data_use_measurement/core/data_use_network_delegate.h58
-rw-r--r--chromium/components/data_use_measurement/core/data_use_recorder.cc53
-rw-r--r--chromium/components/data_use_measurement/core/data_use_recorder.h79
-rw-r--r--chromium/components/data_use_measurement/core/data_use_user_data.cc34
-rw-r--r--chromium/components/data_use_measurement/core/data_use_user_data.h17
-rw-r--r--chromium/components/device_event_log.gypi27
-rw-r--r--chromium/components/devtools_discovery.gypi27
-rw-r--r--chromium/components/devtools_discovery/BUILD.gn20
-rw-r--r--chromium/components/devtools_discovery/DEPS5
-rw-r--r--chromium/components/devtools_discovery/OWNERS2
-rw-r--r--chromium/components/devtools_discovery/basic_target_descriptor.cc105
-rw-r--r--chromium/components/devtools_discovery/basic_target_descriptor.h58
-rw-r--r--chromium/components/devtools_discovery/devtools_discovery_manager.cc65
-rw-r--r--chromium/components/devtools_discovery/devtools_discovery_manager.h57
-rw-r--r--chromium/components/devtools_discovery/devtools_target_descriptor.h69
-rw-r--r--chromium/components/devtools_http_handler.gypi27
-rw-r--r--chromium/components/devtools_http_handler/BUILD.gn35
-rw-r--r--chromium/components/devtools_http_handler/DEPS7
-rw-r--r--chromium/components/devtools_http_handler/OWNERS2
-rw-r--r--chromium/components/devtools_http_handler/devtools_http_handler.cc939
-rw-r--r--chromium/components/devtools_http_handler/devtools_http_handler.h151
-rw-r--r--chromium/components/devtools_http_handler/devtools_http_handler_delegate.h42
-rw-r--r--chromium/components/devtools_http_handler/devtools_http_handler_unittest.cc199
-rw-r--r--chromium/components/display_compositor.gypi116
-rw-r--r--chromium/components/display_compositor/BUILD.gn3
-rw-r--r--chromium/components/display_compositor/DEPS1
-rw-r--r--chromium/components/display_compositor/buffer_queue.cc24
-rw-r--r--chromium/components/display_compositor/buffer_queue.h9
-rw-r--r--chromium/components/display_compositor/buffer_queue_unittest.cc64
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_android.cc3
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc27
-rw-r--r--chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.h6
-rw-r--r--chromium/components/display_compositor/gl_helper_benchmark.cc4
-rw-r--r--chromium/components/display_compositor/gl_helper_unittest.cc10
-rw-r--r--chromium/components/display_compositor/yuv_readback_unittest.cc5
-rw-r--r--chromium/components/dom_distiller.gypi366
-rw-r--r--chromium/components/dom_distiller/DEPS6
-rw-r--r--chromium/components/dom_distiller/android/BUILD.gn60
-rw-r--r--chromium/components/dom_distiller/content/browser/BUILD.gn9
-rw-r--r--chromium/components/dom_distiller/content/browser/android/BUILD.gn21
-rw-r--r--chromium/components/dom_distiller/content/browser/android/DEPS (renamed from chromium/components/dom_distiller/android/DEPS)0
-rw-r--r--chromium/components/dom_distiller/content/browser/android/java/src/org/chromium/components/dom_distiller/content/DEPS (renamed from chromium/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/content/DEPS)0
-rw-r--r--chromium/components/dom_distiller/content/browser/distillability_driver.cc12
-rw-r--r--chromium/components/dom_distiller/content/browser/distillable_page_utils_android.cc1
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc16
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h14
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc2
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc6
-rw-r--r--chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc91
-rw-r--r--chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.h3
-rw-r--r--chromium/components/dom_distiller/content/common/BUILD.gn3
-rw-r--r--chromium/components/dom_distiller/content/common/distiller_javascript_service.mojom4
-rw-r--r--chromium/components/dom_distiller/content/renderer/BUILD.gn1
-rw-r--r--chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc6
-rw-r--r--chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h2
-rw-r--r--chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc19
-rw-r--r--chromium/components/dom_distiller/content/renderer/distiller_native_javascript.h4
-rw-r--r--chromium/components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.cc6
-rw-r--r--chromium/components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.h5
-rw-r--r--chromium/components/dom_distiller/core/BUILD.gn20
-rw-r--r--chromium/components/dom_distiller/core/android/BUILD.gn41
-rw-r--r--chromium/components/dom_distiller/core/android/DEPS3
-rw-r--r--chromium/components/dom_distiller/core/android/java/src/org/chromium/components/dom_distiller/core/FontFamily.template (renamed from chromium/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/FontFamily.template)0
-rw-r--r--chromium/components/dom_distiller/core/android/java/src/org/chromium/components/dom_distiller/core/Theme.template (renamed from chromium/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/Theme.template)0
-rw-r--r--chromium/components/dom_distiller/core/article_attachments_data.h4
-rw-r--r--chromium/components/dom_distiller/core/article_entry.cc2
-rw-r--r--chromium/components/dom_distiller/core/article_entry.h6
-rw-r--r--chromium/components/dom_distiller/core/article_entry_unittest.cc2
-rw-r--r--chromium/components/dom_distiller/core/distillable_page_detector_unittest.cc4
-rw-r--r--chromium/components/dom_distiller/core/distilled_page_prefs_android.cc12
-rw-r--r--chromium/components/dom_distiller/core/distiller_url_fetcher_unittest.cc3
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_model.h6
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_service_android.cc1
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_store.cc7
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_store.h12
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_store_unittest.cc9
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_switches.cc1
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_switches.h3
-rw-r--r--chromium/components/dom_distiller/core/experiments.cc13
-rw-r--r--chromium/components/dom_distiller/core/proto/BUILD.gn1
-rw-r--r--chromium/components/dom_distiller/core/url_utils_android.cc3
-rw-r--r--chromium/components/dom_distiller/ios/distiller_page_ios.h5
-rw-r--r--chromium/components/dom_distiller/ios/distiller_page_ios.mm103
-rw-r--r--chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc5
-rw-r--r--chromium/components/dom_distiller/webui/BUILD.gn3
-rw-r--r--chromium/components/dom_distiller/webui/dom_distiller_handler.cc9
-rw-r--r--chromium/components/domain_reliability.gypi92
-rw-r--r--chromium/components/domain_reliability/BUILD.gn40
-rw-r--r--chromium/components/domain_reliability/OWNERS2
-rw-r--r--chromium/components/domain_reliability/baked_in_configs.gypi27
-rw-r--r--chromium/components/domain_reliability/config.cc2
-rw-r--r--chromium/components/domain_reliability/context.cc11
-rw-r--r--chromium/components/domain_reliability/context.h5
-rw-r--r--chromium/components/domain_reliability/context_manager.cc30
-rw-r--r--chromium/components/domain_reliability/context_manager.h15
-rw-r--r--chromium/components/domain_reliability/context_unittest.cc5
-rw-r--r--chromium/components/domain_reliability/dispatcher.cc26
-rw-r--r--chromium/components/domain_reliability/dispatcher.h6
-rw-r--r--chromium/components/domain_reliability/google_configs.cc35
-rw-r--r--chromium/components/domain_reliability/google_configs.h2
-rw-r--r--chromium/components/domain_reliability/google_configs_unittest.cc8
-rw-r--r--chromium/components/domain_reliability/header.cc2
-rw-r--r--chromium/components/domain_reliability/monitor.cc17
-rw-r--r--chromium/components/domain_reliability/monitor.h12
-rw-r--r--chromium/components/domain_reliability/monitor_unittest.cc60
-rw-r--r--chromium/components/domain_reliability/quic_error_mapping.cc21
-rw-r--r--chromium/components/domain_reliability/quic_error_mapping.h2
-rw-r--r--chromium/components/domain_reliability/scheduler.cc3
-rw-r--r--chromium/components/domain_reliability/service.cc10
-rw-r--r--chromium/components/domain_reliability/service.h7
-rw-r--r--chromium/components/domain_reliability/uploader.cc27
-rw-r--r--chromium/components/domain_reliability/uploader_unittest.cc5
-rw-r--r--chromium/components/domain_reliability/util.cc6
-rw-r--r--chromium/components/drive.gypi218
-rw-r--r--chromium/components/drive/BUILD.gn187
-rw-r--r--chromium/components/error_page.gypi64
-rw-r--r--chromium/components/error_page/OWNERS4
-rw-r--r--chromium/components/error_page/common/OWNERS1
-rw-r--r--chromium/components/error_page/common/localized_error.cc173
-rw-r--r--chromium/components/error_page/renderer/BUILD.gn3
-rw-r--r--chromium/components/error_page/renderer/DEPS1
-rw-r--r--chromium/components/error_page/renderer/net_error_helper_core.cc15
-rw-r--r--chromium/components/error_page/renderer/net_error_helper_core_unittest.cc6
-rw-r--r--chromium/components/error_page_strings.grdp22
-rw-r--r--chromium/components/exo.gypi125
-rw-r--r--chromium/components/exo/BUILD.gn21
-rw-r--r--chromium/components/exo/DEPS2
-rw-r--r--chromium/components/exo/buffer.cc202
-rw-r--r--chromium/components/exo/display.cc37
-rw-r--r--chromium/components/exo/display.h4
-rw-r--r--chromium/components/exo/display_unittest.cc11
-rw-r--r--chromium/components/exo/gamepad.cc49
-rw-r--r--chromium/components/exo/gamepad.h5
-rw-r--r--chromium/components/exo/gamepad_unittest.cc3
-rw-r--r--chromium/components/exo/keyboard.cc16
-rw-r--r--chromium/components/exo/keyboard.h5
-rw-r--r--chromium/components/exo/pointer.cc144
-rw-r--r--chromium/components/exo/pointer.h9
-rw-r--r--chromium/components/exo/pointer_unittest.cc161
-rw-r--r--chromium/components/exo/shared_memory.cc16
-rw-r--r--chromium/components/exo/shared_memory_unittest.cc2
-rw-r--r--chromium/components/exo/shell_surface.cc162
-rw-r--r--chromium/components/exo/shell_surface.h22
-rw-r--r--chromium/components/exo/shell_surface_unittest.cc109
-rw-r--r--chromium/components/exo/sub_surface_unittest.cc2
-rw-r--r--chromium/components/exo/surface.cc89
-rw-r--r--chromium/components/exo/surface.h18
-rw-r--r--chromium/components/exo/surface_unittest.cc28
-rw-r--r--chromium/components/exo/touch.cc6
-rw-r--r--chromium/components/exo/touch_unittest.cc94
-rw-r--r--chromium/components/exo/wayland/server.cc422
-rw-r--r--chromium/components/exo/wayland/server_unittest.cc2
-rw-r--r--chromium/components/exo/wm_helper.cc97
-rw-r--r--chromium/components/exo/wm_helper.h115
-rw-r--r--chromium/components/exo/wm_helper_ash.cc120
-rw-r--r--chromium/components/exo/wm_helper_ash.h65
-rw-r--r--chromium/components/exo/wm_helper_mus.cc142
-rw-r--r--chromium/components/exo/wm_helper_mus.h54
-rw-r--r--chromium/components/external_video_surface.gypi49
-rw-r--r--chromium/components/external_video_surface/BUILD.gn41
-rw-r--r--chromium/components/external_video_surface/DEPS6
-rw-r--r--chromium/components/external_video_surface/OWNERS2
-rw-r--r--chromium/components/external_video_surface/browser/android/external_video_surface_container_impl.cc118
-rw-r--r--chromium/components/external_video_surface/browser/android/external_video_surface_container_impl.h64
-rw-r--r--chromium/components/favicon.gypi112
-rw-r--r--chromium/components/favicon/content/BUILD.gn4
-rw-r--r--chromium/components/favicon/content/content_favicon_driver.cc8
-rw-r--r--chromium/components/favicon/content/content_favicon_driver.h3
-rw-r--r--chromium/components/favicon/core/BUILD.gn2
-rw-r--r--chromium/components/favicon/core/favicon_service.cc55
-rw-r--r--chromium/components/favicon/core/large_icon_service_unittest.cc11
-rw-r--r--chromium/components/favicon_base.gypi45
-rw-r--r--chromium/components/favicon_base/BUILD.gn2
-rw-r--r--chromium/components/favicon_base/fallback_icon_style.cc12
-rw-r--r--chromium/components/favicon_base/fallback_icon_style.h1
-rw-r--r--chromium/components/favicon_base/fallback_icon_url_parser.cc9
-rw-r--r--chromium/components/favicon_base/fallback_icon_url_parser_unittest.cc9
-rw-r--r--chromium/components/favicon_base/favicon_util.cc50
-rw-r--r--chromium/components/favicon_base/favicon_util.h9
-rw-r--r--chromium/components/feedback.gypi71
-rw-r--r--chromium/components/feedback/BUILD.gn2
-rw-r--r--chromium/components/feedback/OWNERS3
-rw-r--r--chromium/components/feedback/anonymizer_tool.cc2
-rw-r--r--chromium/components/feedback/feedback_common.cc211
-rw-r--r--chromium/components/feedback/feedback_common.h46
-rw-r--r--chromium/components/feedback/feedback_common_unittest.cc41
-rw-r--r--chromium/components/feedback/feedback_data.cc23
-rw-r--r--chromium/components/feedback/feedback_data.h6
-rw-r--r--chromium/components/feedback/feedback_data_unittest.cc2
-rw-r--r--chromium/components/feedback/feedback_report.cc16
-rw-r--r--chromium/components/feedback/feedback_report.h14
-rw-r--r--chromium/components/feedback/feedback_uploader_unittest.cc4
-rw-r--r--chromium/components/feedback/feedback_util.cc38
-rw-r--r--chromium/components/feedback/proto/BUILD.gn1
-rw-r--r--chromium/components/filesystem/BUILD.gn18
-rw-r--r--chromium/components/filesystem/directory_impl.cc39
-rw-r--r--chromium/components/filesystem/directory_impl.h15
-rw-r--r--chromium/components/filesystem/directory_impl_unittest.cc118
-rw-r--r--chromium/components/filesystem/file_impl.cc25
-rw-r--r--chromium/components/filesystem/file_impl.h11
-rw-r--r--chromium/components/filesystem/file_impl_unittest.cc392
-rw-r--r--chromium/components/filesystem/file_system_app.cc21
-rw-r--r--chromium/components/filesystem/file_system_app.h20
-rw-r--r--chromium/components/filesystem/file_system_impl.cc23
-rw-r--r--chromium/components/filesystem/file_system_impl.h11
-rw-r--r--chromium/components/filesystem/files_test_base.cc11
-rw-r--r--chromium/components/filesystem/files_test_base.h6
-rw-r--r--chromium/components/filesystem/filesystem.gyp71
-rw-r--r--chromium/components/filesystem/main.cc8
-rw-r--r--chromium/components/filesystem/manifest.json2
-rw-r--r--chromium/components/filesystem/public/cpp/prefs/pref_service_factory.cc2
-rw-r--r--chromium/components/filesystem/public/interfaces/BUILD.gn2
-rw-r--r--chromium/components/filesystem/public/interfaces/directory.mojom2
-rw-r--r--chromium/components/filesystem/public/interfaces/file.mojom11
-rw-r--r--chromium/components/filesystem/public/interfaces/file_system.mojom2
-rw-r--r--chromium/components/filesystem/test_manifest.json2
-rw-r--r--chromium/components/flags_ui.gypi79
-rw-r--r--chromium/components/flags_ui/BUILD.gn5
-rw-r--r--chromium/components/flags_ui/feature_entry.cc12
-rw-r--r--chromium/components/flags_ui/feature_entry.h14
-rw-r--r--chromium/components/flags_ui/feature_entry_macros.h2
-rw-r--r--chromium/components/flags_ui/flags_state.cc223
-rw-r--r--chromium/components/flags_ui/flags_state.h38
-rw-r--r--chromium/components/flags_ui/flags_state_unittest.cc81
-rw-r--r--chromium/components/flags_ui/resources/flags.css4
-rw-r--r--chromium/components/font_service/BUILD.gn10
-rw-r--r--chromium/components/font_service/font_service_app.cc13
-rw-r--r--chromium/components/font_service/font_service_app.h19
-rw-r--r--chromium/components/font_service/main.cc10
-rw-r--r--chromium/components/font_service/manifest.json2
-rw-r--r--chromium/components/font_service/public/cpp/font_loader.cc2
-rw-r--r--chromium/components/font_service/public/cpp/font_service_thread.cc2
-rw-r--r--chromium/components/font_service/public/interfaces/BUILD.gn2
-rw-r--r--chromium/components/gcm_driver.gypi372
-rw-r--r--chromium/components/gcm_driver/BUILD.gn28
-rw-r--r--chromium/components/gcm_driver/android/BUILD.gn3
-rw-r--r--chromium/components/gcm_driver/common/BUILD.gn1
-rw-r--r--chromium/components/gcm_driver/crypto/BUILD.gn6
-rw-r--r--chromium/components/gcm_driver/crypto/proto/BUILD.gn1
-rw-r--r--chromium/components/gcm_driver/instance_id/BUILD.gn9
-rw-r--r--chromium/components/gcm_driver/instance_id/android/BUILD.gn4
-rw-r--r--chromium/components/google.gypi39
-rw-r--r--chromium/components/guest_view.gypi99
-rw-r--r--chromium/components/guest_view/browser/BUILD.gn8
-rw-r--r--chromium/components/guest_view/browser/guest_view.h8
-rw-r--r--chromium/components/guest_view/browser/guest_view_base.cc19
-rw-r--r--chromium/components/guest_view/browser/guest_view_manager.cc22
-rw-r--r--chromium/components/guest_view/browser/guest_view_message_filter.cc7
-rw-r--r--chromium/components/guest_view/renderer/BUILD.gn2
-rw-r--r--chromium/components/guest_view/renderer/guest_view_container.cc21
-rw-r--r--chromium/components/guest_view/renderer/guest_view_container.h9
-rw-r--r--chromium/components/guest_view/renderer/iframe_guest_view_container.cc4
-rw-r--r--chromium/components/handoff.gypi33
-rw-r--r--chromium/components/handoff/handoff_manager.mm2
-rw-r--r--chromium/components/history.gypi268
-rw-r--r--chromium/components/history/DEPS3
-rw-r--r--chromium/components/history/core/browser/BUILD.gn8
-rw-r--r--chromium/components/history/core/browser/android/android_urls_sql_handler.cc11
-rw-r--r--chromium/components/history/core/browser/delete_directive_handler.cc9
-rw-r--r--chromium/components/history/core/browser/delete_directive_handler.h4
-rw-r--r--chromium/components/history/core/browser/download_database.cc11
-rw-r--r--chromium/components/history/core/browser/expire_history_backend_unittest.cc2
-rw-r--r--chromium/components/history/core/browser/history_backend.cc68
-rw-r--r--chromium/components/history/core/browser/history_backend.h11
-rw-r--r--chromium/components/history/core/browser/history_backend_unittest.cc140
-rw-r--r--chromium/components/history/core/browser/history_client.h3
-rw-r--r--chromium/components/history/core/browser/history_database.cc31
-rw-r--r--chromium/components/history/core/browser/history_database.h5
-rw-r--r--chromium/components/history/core/browser/history_database_unittest.cc2
-rw-r--r--chromium/components/history/core/browser/history_delete_directives_data_type_controller.cc23
-rw-r--r--chromium/components/history/core/browser/history_delete_directives_data_type_controller.h25
-rw-r--r--chromium/components/history/core/browser/history_model_worker.h2
-rw-r--r--chromium/components/history/core/browser/history_querying_unittest.cc2
-rw-r--r--chromium/components/history/core/browser/history_service.cc111
-rw-r--r--chromium/components/history/core/browser/history_service.h5
-rw-r--r--chromium/components/history/core/browser/history_service_unittest.cc24
-rw-r--r--chromium/components/history/core/browser/history_types.cc9
-rw-r--r--chromium/components/history/core/browser/history_types.h12
-rw-r--r--chromium/components/history/core/browser/in_memory_database.cc2
-rw-r--r--chromium/components/history/core/browser/thumbnail_database_unittest.cc2
-rw-r--r--chromium/components/history/core/browser/top_sites_database.cc2
-rw-r--r--chromium/components/history/core/browser/top_sites_database_unittest.cc2
-rw-r--r--chromium/components/history/core/browser/top_sites_impl_unittest.cc4
-rw-r--r--chromium/components/history/core/browser/typed_url_data_type_controller.cc45
-rw-r--r--chromium/components/history/core/browser/typed_url_data_type_controller.h27
-rw-r--r--chromium/components/history/core/browser/typed_url_syncable_service.cc14
-rw-r--r--chromium/components/history/core/browser/typed_url_syncable_service.h10
-rw-r--r--chromium/components/history/core/browser/typed_url_syncable_service_unittest.cc65
-rw-r--r--chromium/components/history/core/browser/url_database.cc3
-rw-r--r--chromium/components/history/core/browser/url_database_unittest.cc2
-rw-r--r--chromium/components/history/core/browser/visit_database_unittest.cc2
-rw-r--r--chromium/components/history/core/browser/visit_tracker.cc30
-rw-r--r--chromium/components/history/core/browser/visit_tracker.h3
-rw-r--r--chromium/components/history/core/browser/visitsegment_database.cc2
-rw-r--r--chromium/components/history/core/browser/web_history_service.cc44
-rw-r--r--chromium/components/history/core/browser/web_history_service.h9
-rw-r--r--chromium/components/history/core/browser/web_history_service_observer.h27
-rw-r--r--chromium/components/history/core/test/BUILD.gn2
-rw-r--r--chromium/components/history_strings.grdp31
-rw-r--r--chromium/components/image_fetcher.gypi30
-rw-r--r--chromium/components/image_fetcher/BUILD.gn3
-rw-r--r--chromium/components/image_fetcher/DEPS3
-rw-r--r--chromium/components/image_fetcher/image_data_fetcher.cc12
-rw-r--r--chromium/components/image_fetcher/image_data_fetcher.h8
-rw-r--r--chromium/components/image_fetcher/image_fetcher.h7
-rw-r--r--chromium/components/image_fetcher/image_fetcher_impl.cc5
-rw-r--r--chromium/components/image_fetcher/image_fetcher_impl.h3
-rw-r--r--chromium/components/infobars.gypi65
-rw-r--r--chromium/components/infobars/core/BUILD.gn1
-rw-r--r--chromium/components/infobars/core/infobar_delegate.cc25
-rw-r--r--chromium/components/infobars/core/infobar_delegate.h23
-rw-r--r--chromium/components/invalidation.gypi269
-rw-r--r--chromium/components/invalidation/impl/BUILD.gn9
-rw-r--r--chromium/components/json_schema.gypi25
-rw-r--r--chromium/components/json_schema/BUILD.gn2
-rw-r--r--chromium/components/json_schema/json_schema_validator_unittest_base.cc3
-rw-r--r--chromium/components/keyed_service.gypi111
-rw-r--r--chromium/components/keyed_service/content/BUILD.gn7
-rw-r--r--chromium/components/keyed_service/core/dependency_manager.cc8
-rw-r--r--chromium/components/keyed_service/core/keyed_service_factory.cc2
-rw-r--r--chromium/components/keyed_service/core/refcounted_keyed_service.h2
-rw-r--r--chromium/components/keyed_service/core/refcounted_keyed_service_factory.cc2
-rw-r--r--chromium/components/language_usage_metrics.gypi22
-rw-r--r--chromium/components/language_usage_metrics/BUILD.gn2
-rw-r--r--chromium/components/leveldb/BUILD.gn23
-rw-r--r--chromium/components/leveldb/env_mojo.cc17
-rw-r--r--chromium/components/leveldb/leveldb.gyp80
-rw-r--r--chromium/components/leveldb/leveldb_app.cc20
-rw-r--r--chromium/components/leveldb/leveldb_app.h19
-rw-r--r--chromium/components/leveldb/leveldb_database_impl.cc72
-rw-r--r--chromium/components/leveldb/leveldb_database_impl.h24
-rw-r--r--chromium/components/leveldb/leveldb_mojo_proxy.cc1
-rw-r--r--chromium/components/leveldb/leveldb_mojo_proxy.h5
-rw-r--r--chromium/components/leveldb/leveldb_service_impl.cc17
-rw-r--r--chromium/components/leveldb/leveldb_service_impl.h4
-rw-r--r--chromium/components/leveldb/leveldb_service_unittest.cc422
-rw-r--r--chromium/components/leveldb/main.cc8
-rw-r--r--chromium/components/leveldb/manifest.json2
-rw-r--r--chromium/components/leveldb/public/cpp/BUILD.gn2
-rw-r--r--chromium/components/leveldb/public/cpp/remote_iterator.cc12
-rw-r--r--chromium/components/leveldb/public/cpp/remote_iterator.h5
-rw-r--r--chromium/components/leveldb/public/cpp/util.cc19
-rw-r--r--chromium/components/leveldb/public/cpp/util.h10
-rw-r--r--chromium/components/leveldb/remote_iterator_unittest.cc59
-rw-r--r--chromium/components/leveldb/test_manifest.json4
-rw-r--r--chromium/components/leveldb_proto.gypi44
-rw-r--r--chromium/components/leveldb_proto/BUILD.gn2
-rw-r--r--chromium/components/leveldb_proto/leveldb_database.cc68
-rw-r--r--chromium/components/leveldb_proto/leveldb_database.h12
-rw-r--r--chromium/components/leveldb_proto/proto_database.h7
-rw-r--r--chromium/components/leveldb_proto/proto_database_impl.h36
-rw-r--r--chromium/components/leveldb_proto/proto_database_impl_unittest.cc94
-rw-r--r--chromium/components/leveldb_proto/testing/fake_db.h37
-rw-r--r--chromium/components/link_header_util/link_header_util.gyp21
-rw-r--r--chromium/components/location/android/BUILD.gn1
-rw-r--r--chromium/components/login.gypi29
-rw-r--r--chromium/components/login/OWNERS1
-rw-r--r--chromium/components/memory_coordinator.gypi42
-rw-r--r--chromium/components/memory_coordinator/DEPS3
-rw-r--r--chromium/components/memory_coordinator/OWNERS3
-rw-r--r--chromium/components/memory_coordinator/child/BUILD.gn30
-rw-r--r--chromium/components/memory_coordinator/child/child_memory_coordinator_impl.cc22
-rw-r--r--chromium/components/memory_coordinator/child/child_memory_coordinator_impl.h40
-rw-r--r--chromium/components/memory_coordinator/child/child_memory_coordinator_impl_unittest.cc137
-rw-r--r--chromium/components/memory_coordinator/common/BUILD.gn13
-rw-r--r--chromium/components/memory_coordinator/common/memory_coordinator_client.h24
-rw-r--r--chromium/components/memory_coordinator/public/interfaces/BUILD.gn11
-rw-r--r--chromium/components/memory_coordinator/public/interfaces/OWNERS4
-rw-r--r--chromium/components/memory_coordinator/public/interfaces/child_memory_coordinator.mojom22
-rw-r--r--chromium/components/memory_pressure.gypi35
-rw-r--r--chromium/components/memory_pressure/BUILD.gn3
-rw-r--r--chromium/components/memory_pressure/direct_memory_pressure_calculator_linux.cc119
-rw-r--r--chromium/components/memory_pressure/direct_memory_pressure_calculator_linux.h53
-rw-r--r--chromium/components/memory_pressure/direct_memory_pressure_calculator_linux_unittest.cc104
-rw-r--r--chromium/components/memory_pressure/direct_memory_pressure_calculator_win.cc5
-rw-r--r--chromium/components/memory_pressure/direct_memory_pressure_calculator_win.h3
-rw-r--r--chromium/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc4
-rw-r--r--chromium/components/memory_pressure/memory_pressure_stats_collector.cc38
-rw-r--r--chromium/components/memory_pressure/memory_pressure_stats_collector_unittest.cc9
-rw-r--r--chromium/components/metrics.gypi347
-rw-r--r--chromium/components/metrics/BUILD.gn121
-rw-r--r--chromium/components/metrics/DEPS2
-rw-r--r--chromium/components/metrics/call_stack_profile_collector.cc41
-rw-r--r--chromium/components/metrics/call_stack_profile_collector.h41
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider.cc127
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider.h39
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc60
-rw-r--r--chromium/components/metrics/call_stack_profile_params.cc22
-rw-r--r--chromium/components/metrics/call_stack_profile_params.h87
-rw-r--r--chromium/components/metrics/child_call_stack_profile_collector.cc86
-rw-r--r--chromium/components/metrics/child_call_stack_profile_collector.h120
-rw-r--r--chromium/components/metrics/child_call_stack_profile_collector_unittest.cc175
-rw-r--r--chromium/components/metrics/file_metrics_provider.cc6
-rw-r--r--chromium/components/metrics/file_metrics_provider_unittest.cc44
-rw-r--r--chromium/components/metrics/leak_detector/BUILD.gn66
-rw-r--r--chromium/components/metrics/leak_detector/OWNERS5
-rw-r--r--chromium/components/metrics/leak_detector/gnu_build_id_reader.cc124
-rw-r--r--chromium/components/metrics/leak_detector/gnu_build_id_reader.h24
-rw-r--r--chromium/components/metrics/leak_detector/leak_detector.mojom40
-rw-r--r--chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.cc67
-rw-r--r--chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.h36
-rw-r--r--chromium/components/metrics/leak_detector/protobuf_to_mojo_converter_unittest.cc139
-rw-r--r--chromium/components/metrics/metrics_log.cc108
-rw-r--r--chromium/components/metrics/metrics_log.h8
-rw-r--r--chromium/components/metrics/metrics_log_manager.cc2
-rw-r--r--chromium/components/metrics/metrics_log_manager_unittest.cc46
-rw-r--r--chromium/components/metrics/metrics_log_unittest.cc27
-rw-r--r--chromium/components/metrics/metrics_pref_names.cc60
-rw-r--r--chromium/components/metrics/metrics_pref_names.h7
-rw-r--r--chromium/components/metrics/metrics_provider.cc3
-rw-r--r--chromium/components/metrics/metrics_provider.h7
-rw-r--r--chromium/components/metrics/metrics_service.cc110
-rw-r--r--chromium/components/metrics/metrics_service.h34
-rw-r--r--chromium/components/metrics/metrics_service_accessor.cc22
-rw-r--r--chromium/components/metrics/metrics_service_accessor.h31
-rw-r--r--chromium/components/metrics/metrics_service_client.h7
-rw-r--r--chromium/components/metrics/metrics_service_unittest.cc47
-rw-r--r--chromium/components/metrics/metrics_state_manager.cc17
-rw-r--r--chromium/components/metrics/net/cellular_logic_helper.cc21
-rw-r--r--chromium/components/metrics/persisted_logs.cc86
-rw-r--r--chromium/components/metrics/persisted_logs.h26
-rw-r--r--chromium/components/metrics/persisted_logs_unittest.cc12
-rw-r--r--chromium/components/metrics/profiler/profiler_metrics_provider.cc3
-rw-r--r--chromium/components/metrics/profiler/tracking_synchronizer.cc2
-rw-r--r--chromium/components/metrics/profiler/tracking_synchronizer_unittest.cc4
-rw-r--r--chromium/components/metrics/proto/BUILD.gn2
-rw-r--r--chromium/components/metrics/proto/cast_logs.proto18
-rw-r--r--chromium/components/metrics/proto/chrome_user_metrics_extension.proto3
-rw-r--r--chromium/components/metrics/proto/execution_context.proto49
-rw-r--r--chromium/components/metrics/proto/memory_leak_report.proto43
-rw-r--r--chromium/components/metrics/proto/omnibox_event.proto11
-rw-r--r--chromium/components/metrics/proto/sampled_profile.proto11
-rw-r--r--chromium/components/metrics/proto/system_profile.proto61
-rw-r--r--chromium/components/metrics/public/cpp/BUILD.gn19
-rw-r--r--chromium/components/metrics/public/cpp/OWNERS4
-rw-r--r--chromium/components/metrics/public/cpp/call_stack_profile.typemap26
-rw-r--r--chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h384
-rw-r--r--chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc402
-rw-r--r--chromium/components/metrics/public/cpp/typemaps.gni5
-rw-r--r--chromium/components/metrics/public/interfaces/BUILD.gn26
-rw-r--r--chromium/components/metrics/public/interfaces/OWNERS4
-rw-r--r--chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom81
-rw-r--r--chromium/components/metrics/public/interfaces/call_stack_profile_collector_test.mojom33
-rw-r--r--chromium/components/metrics/serialization/serialization_utils_unittest.cc6
-rw-r--r--chromium/components/metrics/stability_metrics_helper.cc119
-rw-r--r--chromium/components/metrics/stability_metrics_helper.h5
-rw-r--r--chromium/components/metrics/stability_metrics_helper_unittest.cc48
-rw-r--r--chromium/components/metrics/system_memory_stats_recorder_win.cc2
-rw-r--r--chromium/components/metrics/test_metrics_service_client.cc7
-rw-r--r--chromium/components/metrics/test_metrics_service_client.h2
-rw-r--r--chromium/components/metrics/url_constants.cc2
-rw-r--r--chromium/components/metrics_services_manager.gypi28
-rw-r--r--chromium/components/metrics_services_manager/BUILD.gn3
-rw-r--r--chromium/components/metrics_services_manager/metrics_services_manager.cc9
-rw-r--r--chromium/components/metrics_services_manager/metrics_services_manager.h11
-rw-r--r--chromium/components/metrics_services_manager/metrics_services_manager_client.h7
-rw-r--r--chromium/components/mime_util/mime_util.cc41
-rw-r--r--chromium/components/mime_util/mime_util.gyp29
-rw-r--r--chromium/components/mus/BUILD.gn143
-rw-r--r--chromium/components/mus/DEPS12
-rw-r--r--chromium/components/mus/OWNERS4
-rw-r--r--chromium/components/mus/clipboard/BUILD.gn57
-rw-r--r--chromium/components/mus/clipboard/clipboard_impl.cc108
-rw-r--r--chromium/components/mus/clipboard/clipboard_impl.h65
-rw-r--r--chromium/components/mus/clipboard/clipboard_unittest.cc145
-rw-r--r--chromium/components/mus/clipboard/test_manifest.json10
-rw-r--r--chromium/components/mus/common/BUILD.gn100
-rw-r--r--chromium/components/mus/common/DEPS12
-rw-r--r--chromium/components/mus/common/event_matcher_util.cc28
-rw-r--r--chromium/components/mus/common/event_matcher_util.h22
-rw-r--r--chromium/components/mus/common/generic_shared_memory_id_generator.cc21
-rw-r--r--chromium/components/mus/common/generic_shared_memory_id_generator.h19
-rw-r--r--chromium/components/mus/common/gpu_memory_buffer_impl.cc46
-rw-r--r--chromium/components/mus/common/gpu_memory_buffer_impl.h61
-rw-r--r--chromium/components/mus/common/gpu_service.cc256
-rw-r--r--chromium/components/mus/common/gpu_service.h86
-rw-r--r--chromium/components/mus/common/gpu_type_converters.cc164
-rw-r--r--chromium/components/mus/common/gpu_type_converters.h95
-rw-r--r--chromium/components/mus/common/gpu_type_converters_unittest.cc94
-rw-r--r--chromium/components/mus/common/mojo_buffer_backing.cc34
-rw-r--r--chromium/components/mus/common/mojo_buffer_backing.h40
-rw-r--r--chromium/components/mus/common/mojo_gpu_memory_buffer.cc107
-rw-r--r--chromium/components/mus/common/mojo_gpu_memory_buffer.h54
-rw-r--r--chromium/components/mus/common/mojo_gpu_memory_buffer_manager.cc46
-rw-r--r--chromium/components/mus/common/mojo_gpu_memory_buffer_manager.h43
-rw-r--r--chromium/components/mus/common/mus_common_export.h29
-rw-r--r--chromium/components/mus/common/mus_common_unittests_app_manifest.json10
-rw-r--r--chromium/components/mus/common/run_all_shelltests.cc34
-rw-r--r--chromium/components/mus/common/switches.cc20
-rw-r--r--chromium/components/mus/common/switches.h21
-rw-r--r--chromium/components/mus/common/transient_window_utils.h126
-rw-r--r--chromium/components/mus/common/types.h25
-rw-r--r--chromium/components/mus/common/util.h32
-rw-r--r--chromium/components/mus/demo/BUILD.gn42
-rw-r--r--chromium/components/mus/demo/DEPS4
-rw-r--r--chromium/components/mus/demo/OWNERS2
-rw-r--r--chromium/components/mus/demo/main.cc13
-rw-r--r--chromium/components/mus/demo/manifest.json14
-rw-r--r--chromium/components/mus/demo/mus_demo.cc179
-rw-r--r--chromium/components/mus/demo/mus_demo.h92
-rw-r--r--chromium/components/mus/gles2/BUILD.gn89
-rw-r--r--chromium/components/mus/gles2/DEPS8
-rw-r--r--chromium/components/mus/gles2/OWNERS2
-rw-r--r--chromium/components/mus/gles2/command_buffer_driver.cc568
-rw-r--r--chromium/components/mus/gles2/command_buffer_driver.h173
-rw-r--r--chromium/components/mus/gles2/command_buffer_driver_manager.cc50
-rw-r--r--chromium/components/mus/gles2/command_buffer_driver_manager.h46
-rw-r--r--chromium/components/mus/gles2/command_buffer_impl.cc301
-rw-r--r--chromium/components/mus/gles2/command_buffer_impl.h126
-rw-r--r--chromium/components/mus/gles2/command_buffer_local.cc576
-rw-r--r--chromium/components/mus/gles2/command_buffer_local.h185
-rw-r--r--chromium/components/mus/gles2/command_buffer_local_client.h31
-rw-r--r--chromium/components/mus/gles2/command_buffer_task_runner.cc77
-rw-r--r--chromium/components/mus/gles2/command_buffer_task_runner.h78
-rw-r--r--chromium/components/mus/gles2/gl_surface_adapter.cc57
-rw-r--r--chromium/components/mus/gles2/gl_surface_adapter.h71
-rw-r--r--chromium/components/mus/gles2/gpu_impl.cc27
-rw-r--r--chromium/components/mus/gles2/gpu_impl.h39
-rw-r--r--chromium/components/mus/gles2/gpu_memory_tracker.cc36
-rw-r--r--chromium/components/mus/gles2/gpu_memory_tracker.h39
-rw-r--r--chromium/components/mus/gles2/gpu_state.cc82
-rw-r--r--chromium/components/mus/gles2/gpu_state.h107
-rw-r--r--chromium/components/mus/gles2/ozone_gpu_memory_buffer.cc115
-rw-r--r--chromium/components/mus/gles2/ozone_gpu_memory_buffer.h71
-rw-r--r--chromium/components/mus/gles2/raster_thread_helper.cc27
-rw-r--r--chromium/components/mus/gles2/raster_thread_helper.h34
-rw-r--r--chromium/components/mus/gpu/BUILD.gn65
-rw-r--r--chromium/components/mus/gpu/DEPS21
-rw-r--r--chromium/components/mus/gpu/OWNERS2
-rw-r--r--chromium/components/mus/gpu/display_compositor/BUILD.gn30
-rw-r--r--chromium/components/mus/gpu/display_compositor/compositor_frame_sink_delegate.h27
-rw-r--r--chromium/components/mus/gpu/display_compositor/compositor_frame_sink_factory_impl.cc46
-rw-r--r--chromium/components/mus/gpu/display_compositor/compositor_frame_sink_factory_impl.h55
-rw-r--r--chromium/components/mus/gpu/display_compositor/compositor_frame_sink_impl.cc112
-rw-r--r--chromium/components/mus/gpu/display_compositor/compositor_frame_sink_impl.h74
-rw-r--r--chromium/components/mus/gpu/display_compositor/display_compositor_impl.cc28
-rw-r--r--chromium/components/mus/gpu/display_compositor/display_compositor_impl.h37
-rw-r--r--chromium/components/mus/gpu/display_compositor/display_impl.cc43
-rw-r--r--chromium/components/mus/gpu/display_compositor/display_impl.h44
-rw-r--r--chromium/components/mus/gpu/gpu_service_impl.cc63
-rw-r--r--chromium/components/mus/gpu/gpu_service_impl.h49
-rw-r--r--chromium/components/mus/gpu/gpu_service_mus.cc273
-rw-r--r--chromium/components/mus/gpu/gpu_service_mus.h173
-rw-r--r--chromium/components/mus/gpu/mus_gpu_memory_buffer_manager.cc115
-rw-r--r--chromium/components/mus/gpu/mus_gpu_memory_buffer_manager.h57
-rw-r--r--chromium/components/mus/gpu/mus_gpu_unittests_app_manifest.json10
-rw-r--r--chromium/components/mus/input_devices/BUILD.gn21
-rw-r--r--chromium/components/mus/input_devices/input_device_server.cc110
-rw-r--r--chromium/components/mus/input_devices/input_device_server.h69
-rw-r--r--chromium/components/mus/main.cc13
-rw-r--r--chromium/components/mus/manifest.json26
-rw-r--r--chromium/components/mus/mus_app.cc388
-rw-r--r--chromium/components/mus/mus_app.h182
-rw-r--r--chromium/components/mus/public/cpp/BUILD.gn74
-rw-r--r--chromium/components/mus/public/cpp/DEPS3
-rw-r--r--chromium/components/mus/public/cpp/context_provider.h54
-rw-r--r--chromium/components/mus/public/cpp/gles2_context.h61
-rw-r--r--chromium/components/mus/public/cpp/input_devices/BUILD.gn21
-rw-r--r--chromium/components/mus/public/cpp/input_devices/input_device_client.cc112
-rw-r--r--chromium/components/mus/public/cpp/input_devices/input_device_client.h84
-rw-r--r--chromium/components/mus/public/cpp/input_event_handler.h43
-rw-r--r--chromium/components/mus/public/cpp/lib/DEPS3
-rw-r--r--chromium/components/mus/public/cpp/lib/command_buffer_client_impl.cc370
-rw-r--r--chromium/components/mus/public/cpp/lib/command_buffer_client_impl.h117
-rw-r--r--chromium/components/mus/public/cpp/lib/context_provider.cc61
-rw-r--r--chromium/components/mus/public/cpp/lib/gles2_context.cc109
-rw-r--r--chromium/components/mus/public/cpp/lib/in_flight_change.cc220
-rw-r--r--chromium/components/mus/public/cpp/lib/in_flight_change.h298
-rw-r--r--chromium/components/mus/public/cpp/lib/output_surface.cc70
-rw-r--r--chromium/components/mus/public/cpp/lib/property_type_converters.cc207
-rw-r--r--chromium/components/mus/public/cpp/lib/scoped_window_ptr.cc44
-rw-r--r--chromium/components/mus/public/cpp/lib/window.cc891
-rw-r--r--chromium/components/mus/public/cpp/lib/window_observer.cc18
-rw-r--r--chromium/components/mus/public/cpp/lib/window_private.cc31
-rw-r--r--chromium/components/mus/public/cpp/lib/window_private.h100
-rw-r--r--chromium/components/mus/public/cpp/lib/window_surface.cc69
-rw-r--r--chromium/components/mus/public/cpp/lib/window_tree_client.cc1181
-rw-r--r--chromium/components/mus/public/cpp/lib/window_tree_client_delegate.cc11
-rw-r--r--chromium/components/mus/public/cpp/lib/window_tree_host_factory.cc32
-rw-r--r--chromium/components/mus/public/cpp/output_surface.h45
-rw-r--r--chromium/components/mus/public/cpp/property_type_converters.h96
-rw-r--r--chromium/components/mus/public/cpp/scoped_window_ptr.h42
-rw-r--r--chromium/components/mus/public/cpp/tests/BUILD.gn82
-rw-r--r--chromium/components/mus/public/cpp/window.h356
-rw-r--r--chromium/components/mus/public/cpp/window_manager_delegate.h116
-rw-r--r--chromium/components/mus/public/cpp/window_observer.h110
-rw-r--r--chromium/components/mus/public/cpp/window_property.h156
-rw-r--r--chromium/components/mus/public/cpp/window_surface.h85
-rw-r--r--chromium/components/mus/public/cpp/window_surface_client.h24
-rw-r--r--chromium/components/mus/public/cpp/window_tracker.h21
-rw-r--r--chromium/components/mus/public/cpp/window_tree_client.h407
-rw-r--r--chromium/components/mus/public/cpp/window_tree_client_delegate.h53
-rw-r--r--chromium/components/mus/public/cpp/window_tree_client_observer.h27
-rw-r--r--chromium/components/mus/public/cpp/window_tree_host_factory.h37
-rw-r--r--chromium/components/mus/public/interfaces/BUILD.gn46
-rw-r--r--chromium/components/mus/public/interfaces/accelerator_registrar.mojom22
-rw-r--r--chromium/components/mus/public/interfaces/animations.mojom61
-rw-r--r--chromium/components/mus/public/interfaces/channel_handle.mojom13
-rw-r--r--chromium/components/mus/public/interfaces/clipboard.mojom50
-rw-r--r--chromium/components/mus/public/interfaces/command_buffer.mojom62
-rw-r--r--chromium/components/mus/public/interfaces/cursor.mojom57
-rw-r--r--chromium/components/mus/public/interfaces/display.mojom25
-rw-r--r--chromium/components/mus/public/interfaces/event_matcher.mojom55
-rw-r--r--chromium/components/mus/public/interfaces/gpu.mojom23
-rw-r--r--chromium/components/mus/public/interfaces/gpu/BUILD.gn17
-rw-r--r--chromium/components/mus/public/interfaces/gpu/OWNERS2
-rw-r--r--chromium/components/mus/public/interfaces/gpu/display_compositor.mojom72
-rw-r--r--chromium/components/mus/public/interfaces/gpu/display_compositor_host.mojom32
-rw-r--r--chromium/components/mus/public/interfaces/gpu_memory_buffer.mojom63
-rw-r--r--chromium/components/mus/public/interfaces/gpu_service.mojom32
-rw-r--r--chromium/components/mus/public/interfaces/input_devices/BUILD.gn15
-rw-r--r--chromium/components/mus/public/interfaces/input_devices/input_device_server.mojom43
-rw-r--r--chromium/components/mus/public/interfaces/mus_constants.mojom15
-rw-r--r--chromium/components/mus/public/interfaces/surface.mojom22
-rw-r--r--chromium/components/mus/public/interfaces/user_access_manager.mojom11
-rw-r--r--chromium/components/mus/public/interfaces/user_activity_monitor.mojom31
-rw-r--r--chromium/components/mus/public/interfaces/window_manager.mojom134
-rw-r--r--chromium/components/mus/public/interfaces/window_manager_constants.mojom78
-rw-r--r--chromium/components/mus/public/interfaces/window_manager_window_tree_factory.mojom16
-rw-r--r--chromium/components/mus/public/interfaces/window_server_test.mojom9
-rw-r--r--chromium/components/mus/public/interfaces/window_tree.mojom378
-rw-r--r--chromium/components/mus/public/interfaces/window_tree_constants.mojom57
-rw-r--r--chromium/components/mus/public/interfaces/window_tree_host.mojom25
-rw-r--r--chromium/components/mus/surfaces/BUILD.gn51
-rw-r--r--chromium/components/mus/surfaces/DEPS10
-rw-r--r--chromium/components/mus/surfaces/OWNERS2
-rw-r--r--chromium/components/mus/surfaces/direct_output_surface.cc81
-rw-r--r--chromium/components/mus/surfaces/direct_output_surface.h47
-rw-r--r--chromium/components/mus/surfaces/direct_output_surface_ozone.cc166
-rw-r--r--chromium/components/mus/surfaces/direct_output_surface_ozone.h84
-rw-r--r--chromium/components/mus/surfaces/display_compositor.cc124
-rw-r--r--chromium/components/mus/surfaces/display_compositor.h80
-rw-r--r--chromium/components/mus/surfaces/ozone_gpu_memory_buffer_manager.cc49
-rw-r--r--chromium/components/mus/surfaces/ozone_gpu_memory_buffer_manager.h39
-rw-r--r--chromium/components/mus/surfaces/surfaces_context_provider.cc206
-rw-r--r--chromium/components/mus/surfaces/surfaces_context_provider.h109
-rw-r--r--chromium/components/mus/surfaces/surfaces_context_provider_delegate.h28
-rw-r--r--chromium/components/mus/surfaces/surfaces_state.cc13
-rw-r--r--chromium/components/mus/surfaces/surfaces_state.h49
-rw-r--r--chromium/components/mus/test_wm/BUILD.gn31
-rw-r--r--chromium/components/mus/test_wm/manifest.json10
-rw-r--r--chromium/components/mus/test_wm/test_wm.cc107
-rw-r--r--chromium/components/mus/ws/BUILD.gn254
-rw-r--r--chromium/components/mus/ws/accelerator.cc33
-rw-r--r--chromium/components/mus/ws/accelerator.h57
-rw-r--r--chromium/components/mus/ws/access_policy.h84
-rw-r--r--chromium/components/mus/ws/access_policy_delegate.h41
-rw-r--r--chromium/components/mus/ws/animation_runner.cc163
-rw-r--r--chromium/components/mus/ws/animation_runner.h119
-rw-r--r--chromium/components/mus/ws/animation_runner_observer.h25
-rw-r--r--chromium/components/mus/ws/animation_runner_unittest.cc639
-rw-r--r--chromium/components/mus/ws/cursor_unittest.cc198
-rw-r--r--chromium/components/mus/ws/default_access_policy.cc203
-rw-r--r--chromium/components/mus/ws/default_access_policy.h76
-rw-r--r--chromium/components/mus/ws/display.cc419
-rw-r--r--chromium/components/mus/ws/display.h224
-rw-r--r--chromium/components/mus/ws/display_binding.cc39
-rw-r--r--chromium/components/mus/ws/display_binding.h60
-rw-r--r--chromium/components/mus/ws/display_manager.cc167
-rw-r--r--chromium/components/mus/ws/display_manager.h102
-rw-r--r--chromium/components/mus/ws/display_manager_delegate.h38
-rw-r--r--chromium/components/mus/ws/display_unittest.cc308
-rw-r--r--chromium/components/mus/ws/event_dispatcher.cc559
-rw-r--r--chromium/components/mus/ws/event_dispatcher.h236
-rw-r--r--chromium/components/mus/ws/event_dispatcher_delegate.h73
-rw-r--r--chromium/components/mus/ws/event_dispatcher_unittest.cc1614
-rw-r--r--chromium/components/mus/ws/event_matcher.cc113
-rw-r--r--chromium/components/mus/ws/event_matcher.h56
-rw-r--r--chromium/components/mus/ws/event_matcher_unittest.cc71
-rw-r--r--chromium/components/mus/ws/focus_controller.cc311
-rw-r--r--chromium/components/mus/ws/focus_controller.h104
-rw-r--r--chromium/components/mus/ws/focus_controller_delegate.h26
-rw-r--r--chromium/components/mus/ws/focus_controller_observer.h29
-rw-r--r--chromium/components/mus/ws/focus_controller_unittest.cc312
-rw-r--r--chromium/components/mus/ws/ids.h113
-rw-r--r--chromium/components/mus/ws/modal_window_controller.cc121
-rw-r--r--chromium/components/mus/ws/modal_window_controller.h87
-rw-r--r--chromium/components/mus/ws/mus_ws_unittests_app_manifest.json16
-rw-r--r--chromium/components/mus/ws/operation.cc30
-rw-r--r--chromium/components/mus/ws/operation.h77
-rw-r--r--chromium/components/mus/ws/platform_display.cc414
-rw-r--r--chromium/components/mus/ws/platform_display.h195
-rw-r--r--chromium/components/mus/ws/platform_display_delegate.h53
-rw-r--r--chromium/components/mus/ws/platform_display_factory.h23
-rw-r--r--chromium/components/mus/ws/platform_display_init_params.cc21
-rw-r--r--chromium/components/mus/ws/platform_display_init_params.h39
-rw-r--r--chromium/components/mus/ws/platform_screen.h43
-rw-r--r--chromium/components/mus/ws/platform_screen_impl.cc43
-rw-r--r--chromium/components/mus/ws/platform_screen_impl.h39
-rw-r--r--chromium/components/mus/ws/platform_screen_impl_ozone.cc126
-rw-r--r--chromium/components/mus/ws/platform_screen_impl_ozone.h72
-rw-r--r--chromium/components/mus/ws/scheduled_animation_group.cc356
-rw-r--r--chromium/components/mus/ws/scheduled_animation_group.h116
-rw-r--r--chromium/components/mus/ws/scheduled_animation_group_unittest.cc92
-rw-r--r--chromium/components/mus/ws/server_window.cc470
-rw-r--r--chromium/components/mus/ws/server_window.h249
-rw-r--r--chromium/components/mus/ws/server_window_delegate.h46
-rw-r--r--chromium/components/mus/ws/server_window_drawn_tracker.cc136
-rw-r--r--chromium/components/mus/ws/server_window_drawn_tracker.h65
-rw-r--r--chromium/components/mus/ws/server_window_drawn_tracker_observer.h41
-rw-r--r--chromium/components/mus/ws/server_window_drawn_tracker_unittest.cc235
-rw-r--r--chromium/components/mus/ws/server_window_observer.h97
-rw-r--r--chromium/components/mus/ws/server_window_surface.cc110
-rw-r--r--chromium/components/mus/ws/server_window_surface.h86
-rw-r--r--chromium/components/mus/ws/server_window_surface_manager.cc102
-rw-r--r--chromium/components/mus/ws/server_window_surface_manager.h84
-rw-r--r--chromium/components/mus/ws/server_window_surface_manager_test_api.cc39
-rw-r--r--chromium/components/mus/ws/server_window_surface_manager_test_api.h39
-rw-r--r--chromium/components/mus/ws/server_window_tracker.h25
-rw-r--r--chromium/components/mus/ws/test_change_tracker.cc448
-rw-r--r--chromium/components/mus/ws/test_change_tracker.h185
-rw-r--r--chromium/components/mus/ws/test_server_window_delegate.cc34
-rw-r--r--chromium/components/mus/ws/test_server_window_delegate.h41
-rw-r--r--chromium/components/mus/ws/test_utils.cc496
-rw-r--r--chromium/components/mus/ws/test_utils.h537
-rw-r--r--chromium/components/mus/ws/touch_controller.cc105
-rw-r--r--chromium/components/mus/ws/touch_controller.h37
-rw-r--r--chromium/components/mus/ws/transient_windows_unittest.cc342
-rw-r--r--chromium/components/mus/ws/user_activity_monitor.cc134
-rw-r--r--chromium/components/mus/ws/user_activity_monitor.h82
-rw-r--r--chromium/components/mus/ws/user_activity_monitor_unittest.cc218
-rw-r--r--chromium/components/mus/ws/user_display_manager.cc151
-rw-r--r--chromium/components/mus/ws/user_display_manager.h118
-rw-r--r--chromium/components/mus/ws/user_display_manager_unittest.cc244
-rw-r--r--chromium/components/mus/ws/user_id.h22
-rw-r--r--chromium/components/mus/ws/user_id_tracker.cc68
-rw-r--r--chromium/components/mus/ws/user_id_tracker.h62
-rw-r--r--chromium/components/mus/ws/user_id_tracker_observer.h29
-rw-r--r--chromium/components/mus/ws/window_coordinate_conversions.cc74
-rw-r--r--chromium/components/mus/ws/window_coordinate_conversions.h39
-rw-r--r--chromium/components/mus/ws/window_coordinate_conversions_unittest.cc62
-rw-r--r--chromium/components/mus/ws/window_finder.cc68
-rw-r--r--chromium/components/mus/ws/window_finder.h33
-rw-r--r--chromium/components/mus/ws/window_finder_unittest.cc79
-rw-r--r--chromium/components/mus/ws/window_manager_access_policy.cc184
-rw-r--r--chromium/components/mus/ws/window_manager_access_policy.h76
-rw-r--r--chromium/components/mus/ws/window_manager_client_unittest.cc1171
-rw-r--r--chromium/components/mus/ws/window_manager_display_root.cc34
-rw-r--r--chromium/components/mus/ws/window_manager_display_root.h62
-rw-r--r--chromium/components/mus/ws/window_manager_state.cc485
-rw-r--r--chromium/components/mus/ws/window_manager_state.h183
-rw-r--r--chromium/components/mus/ws/window_manager_state_unittest.cc419
-rw-r--r--chromium/components/mus/ws/window_manager_window_tree_factory.cc64
-rw-r--r--chromium/components/mus/ws/window_manager_window_tree_factory.h68
-rw-r--r--chromium/components/mus/ws/window_manager_window_tree_factory_set.cc99
-rw-r--r--chromium/components/mus/ws/window_manager_window_tree_factory_set.h93
-rw-r--r--chromium/components/mus/ws/window_manager_window_tree_factory_set_observer.h26
-rw-r--r--chromium/components/mus/ws/window_server.cc707
-rw-r--r--chromium/components/mus/ws/window_server.h342
-rw-r--r--chromium/components/mus/ws/window_server_delegate.cc25
-rw-r--r--chromium/components/mus/ws/window_server_delegate.h67
-rw-r--r--chromium/components/mus/ws/window_server_test_impl.cc66
-rw-r--r--chromium/components/mus/ws/window_server_test_impl.h45
-rw-r--r--chromium/components/mus/ws/window_tree.cc1539
-rw-r--r--chromium/components/mus/ws/window_tree.h497
-rw-r--r--chromium/components/mus/ws/window_tree_binding.cc62
-rw-r--r--chromium/components/mus/ws/window_tree_binding.h72
-rw-r--r--chromium/components/mus/ws/window_tree_client_unittest.cc2042
-rw-r--r--chromium/components/mus/ws/window_tree_factory.cc42
-rw-r--r--chromium/components/mus/ws/window_tree_factory.h42
-rw-r--r--chromium/components/mus/ws/window_tree_host_factory.cc42
-rw-r--r--chromium/components/mus/ws/window_tree_host_factory.h46
-rw-r--r--chromium/components/mus/ws/window_tree_unittest.cc1017
-rw-r--r--chromium/components/nacl.gyp466
-rw-r--r--chromium/components/nacl/broker/BUILD.gn8
-rw-r--r--chromium/components/nacl/browser/BUILD.gn7
-rw-r--r--chromium/components/nacl/common/BUILD.gn6
-rw-r--r--chromium/components/nacl/loader/BUILD.gn37
-rw-r--r--chromium/components/nacl/renderer/BUILD.gn3
-rw-r--r--chromium/components/nacl/renderer/plugin/BUILD.gn2
-rw-r--r--chromium/components/nacl/renderer/plugin/plugin.gyp33
-rw-r--r--chromium/components/nacl_helper_nonsfi_unittests.isolate18
-rw-r--r--chromium/components/nacl_loader_unittests.isolate18
-rw-r--r--chromium/components/nacl_nonsfi.gyp297
-rw-r--r--chromium/components/navigation_interception.gypi81
-rw-r--r--chromium/components/navigation_interception/BUILD.gn5
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_delegate.cc14
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_delegate.h2
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc8
-rw-r--r--chromium/components/navigation_interception/navigation_params_android.cc19
-rw-r--r--chromium/components/navigation_interception/navigation_params_android.h2
-rw-r--r--chromium/components/navigation_metrics.gypi26
-rw-r--r--chromium/components/navigation_metrics/BUILD.gn2
-rw-r--r--chromium/components/net_log.gypi31
-rw-r--r--chromium/components/net_log/BUILD.gn8
-rw-r--r--chromium/components/net_log/chrome_net_log.cc58
-rw-r--r--chromium/components/net_log/chrome_net_log.h10
-rw-r--r--chromium/components/net_log/net_log_file_writer.cc246
-rw-r--r--chromium/components/net_log/net_log_file_writer.h177
-rw-r--r--chromium/components/net_log/net_log_file_writer_unittest.cc446
-rw-r--r--chromium/components/net_log/net_log_temp_file.cc232
-rw-r--r--chromium/components/net_log/net_log_temp_file.h174
-rw-r--r--chromium/components/net_log/net_log_temp_file_unittest.cc394
-rw-r--r--chromium/components/net_log/resources/net_export.html2
-rw-r--r--chromium/components/net_log/resources/net_export.js7
-rw-r--r--chromium/components/neterror/OWNERS1
-rw-r--r--chromium/components/neterror/resources/offline.js50
-rw-r--r--chromium/components/network_hints.gypi74
-rw-r--r--chromium/components/network_hints/browser/BUILD.gn1
-rw-r--r--chromium/components/network_hints/browser/network_hints_message_filter.cc15
-rw-r--r--chromium/components/network_hints/common/BUILD.gn3
-rw-r--r--chromium/components/network_hints/common/OWNERS (renamed from chromium/components/content_settings/content/common/OWNERS)0
-rw-r--r--chromium/components/network_hints/common/network_hints_messages.h9
-rw-r--r--chromium/components/network_hints/renderer/BUILD.gn5
-rw-r--r--chromium/components/network_hints/renderer/prescient_networking_dispatcher.cc12
-rw-r--r--chromium/components/network_hints/renderer/prescient_networking_dispatcher.h6
-rw-r--r--chromium/components/network_session_configurator.gypi40
-rw-r--r--chromium/components/network_session_configurator/BUILD.gn14
-rw-r--r--chromium/components/network_session_configurator/network_session_configurator.cc412
-rw-r--r--chromium/components/network_session_configurator/network_session_configurator.h19
-rw-r--r--chromium/components/network_session_configurator/network_session_configurator_unittest.cc363
-rw-r--r--chromium/components/network_session_configurator/switches.cc55
-rw-r--r--chromium/components/network_session_configurator/switches.h27
-rw-r--r--chromium/components/network_time.gypi28
-rw-r--r--chromium/components/network_time/OWNERS2
-rw-r--r--chromium/components/network_time/network_time_tracker.cc83
-rw-r--r--chromium/components/network_time/network_time_tracker.h38
-rw-r--r--chromium/components/network_time/network_time_tracker_unittest.cc222
-rw-r--r--chromium/components/new_or_sad_tab_strings.grdp10
-rw-r--r--chromium/components/ntp_snippets.gypi62
-rw-r--r--chromium/components/ntp_snippets/BUILD.gn113
-rw-r--r--chromium/components/ntp_snippets/DEPS6
-rw-r--r--chromium/components/ntp_snippets/bookmarks/DEPS3
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc273
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h74
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils_unittest.cc122
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc327
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h122
-rw-r--r--chromium/components/ntp_snippets/category.cc37
-rw-r--r--chromium/components/ntp_snippets/category.h89
-rw-r--r--chromium/components/ntp_snippets/category_factory.cc85
-rw-r--r--chromium/components/ntp_snippets/category_factory.h61
-rw-r--r--chromium/components/ntp_snippets/category_factory_unittest.cc126
-rw-r--r--chromium/components/ntp_snippets/category_info.cc20
-rw-r--r--chromium/components/ntp_snippets/category_info.h60
-rw-r--r--chromium/components/ntp_snippets/category_status.cc21
-rw-r--r--chromium/components/ntp_snippets/category_status.h52
-rw-r--r--chromium/components/ntp_snippets/content_suggestion.cc35
-rw-r--r--chromium/components/ntp_snippets/content_suggestion.h78
-rw-r--r--chromium/components/ntp_snippets/content_suggestion_category.h18
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_metrics.cc272
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_metrics.h56
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_provider.cc18
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_provider.h148
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_provider_type.h19
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.cc337
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.h273
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service_unittest.cc604
-rw-r--r--chromium/components/ntp_snippets/features.cc55
-rw-r--r--chromium/components/ntp_snippets/features.h37
-rw-r--r--chromium/components/ntp_snippets/mock_content_suggestions_provider_observer.cc26
-rw-r--r--chromium/components/ntp_snippets/mock_content_suggestions_provider_observer.h47
-rw-r--r--chromium/components/ntp_snippets/ntp_snippet.cc300
-rw-r--r--chromium/components/ntp_snippets/ntp_snippet.h156
-rw-r--r--chromium/components/ntp_snippets/ntp_snippet_unittest.cc51
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_constants.cc9
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_constants.h6
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_database.cc292
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_database.h131
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_database_unittest.cc289
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_fetcher.cc533
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_fetcher.h223
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_fetcher_unittest.cc572
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_scheduler.h40
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_service.cc766
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_service.h326
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_service_unittest.cc876
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_status_service.cc80
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_status_service.h82
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_status_service_unittest.cc70
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_test_utils.cc74
-rw-r--r--chromium/components/ntp_snippets/ntp_snippets_test_utils.h68
-rw-r--r--chromium/components/ntp_snippets/offline_pages/DEPS3
-rw-r--r--chromium/components/ntp_snippets/offline_pages/offline_page_proxy.cc66
-rw-r--r--chromium/components/ntp_snippets/offline_pages/offline_page_proxy.h84
-rw-r--r--chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc274
-rw-r--r--chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h119
-rw-r--r--chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc272
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/DEPS2
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc125
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h72
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc63
-rw-r--r--chromium/components/ntp_snippets/pref_names.cc49
-rw-r--r--chromium/components/ntp_snippets/pref_names.h62
-rw-r--r--chromium/components/ntp_snippets/pref_util.cc40
-rw-r--r--chromium/components/ntp_snippets/pref_util.h28
-rw-r--r--chromium/components/ntp_snippets/proto/ntp_snippets.proto31
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippet.cc303
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippet.h160
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippet_unittest.cc268
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_database.cc303
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_database.h139
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_database_unittest.cc371
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_fetcher.cc650
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_fetcher.h265
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_fetcher_unittest.cc781
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_scheduler.h36
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_service.cc1121
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_service.h366
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_service_unittest.cc1305
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_status_service.cc119
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_status_service.h86
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_status_service_unittest.cc59
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_test_utils.cc71
-rw-r--r--chromium/components/ntp_snippets/remote/ntp_snippets_test_utils.h66
-rw-r--r--chromium/components/ntp_snippets/remote/proto/BUILD.gn (renamed from chromium/components/ntp_snippets/proto/BUILD.gn)0
-rw-r--r--chromium/components/ntp_snippets/remote/proto/ntp_snippets.proto32
-rw-r--r--chromium/components/ntp_snippets/remote/request_throttler.cc192
-rw-r--r--chromium/components/ntp_snippets/remote/request_throttler.h96
-rw-r--r--chromium/components/ntp_snippets/remote/request_throttler_unittest.cc72
-rw-r--r--chromium/components/ntp_snippets/sessions/DEPS4
-rw-r--r--chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc314
-rw-r--r--chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h85
-rw-r--r--chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc326
-rw-r--r--chromium/components/ntp_snippets/sessions/tab_delegate_sync_adapter.cc64
-rw-r--r--chromium/components/ntp_snippets/sessions/tab_delegate_sync_adapter.h53
-rw-r--r--chromium/components/ntp_snippets/switches.cc11
-rw-r--r--chromium/components/ntp_snippets/switches.h5
-rw-r--r--chromium/components/ntp_snippets/user_classifier.cc373
-rw-r--r--chromium/components/ntp_snippets/user_classifier.h109
-rw-r--r--chromium/components/ntp_snippets_strings.grdp42
-rw-r--r--chromium/components/ntp_tiles.gypi90
-rw-r--r--chromium/components/ntp_tiles/BUILD.gn10
-rw-r--r--chromium/components/ntp_tiles/DEPS2
-rw-r--r--chromium/components/ntp_tiles/OWNERS1
-rw-r--r--chromium/components/ntp_tiles/android/BUILD.gn2
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.cc432
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.h159
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites_unittest.cc71
-rw-r--r--chromium/components/ntp_tiles/ntp_tile.cc15
-rw-r--r--chromium/components/ntp_tiles/ntp_tile.h49
-rw-r--r--chromium/components/ntp_tiles/popular_sites.cc42
-rw-r--r--chromium/components/ntp_tiles/popular_sites.h46
-rw-r--r--chromium/components/ntp_tiles/pref_names.cc10
-rw-r--r--chromium/components/ntp_tiles/pref_names.h7
-rw-r--r--chromium/components/offline_pages.gypi126
-rw-r--r--chromium/components/offline_pages/BUILD.gn9
-rw-r--r--chromium/components/offline_pages/archive_manager_unittest.cc4
-rw-r--r--chromium/components/offline_pages/background/BUILD.gn8
-rw-r--r--chromium/components/offline_pages/background/change_requests_state_task.cc90
-rw-r--r--chromium/components/offline_pages/background/change_requests_state_task.h63
-rw-r--r--chromium/components/offline_pages/background/change_requests_state_task_unittest.cc183
-rw-r--r--chromium/components/offline_pages/background/device_conditions.h6
-rw-r--r--chromium/components/offline_pages/background/offliner.h41
-rw-r--r--chromium/components/offline_pages/background/offliner_policy.h93
-rw-r--r--chromium/components/offline_pages/background/remove_requests_task.cc52
-rw-r--r--chromium/components/offline_pages/background/remove_requests_task.h53
-rw-r--r--chromium/components/offline_pages/background/remove_requests_task_unittest.cc176
-rw-r--r--chromium/components/offline_pages/background/request_coordinator.cc659
-rw-r--r--chromium/components/offline_pages/background/request_coordinator.h246
-rw-r--r--chromium/components/offline_pages/background/request_coordinator_event_logger.cc107
-rw-r--r--chromium/components/offline_pages/background/request_coordinator_event_logger.h23
-rw-r--r--chromium/components/offline_pages/background/request_coordinator_event_logger_unittest.cc31
-rw-r--r--chromium/components/offline_pages/background/request_coordinator_unittest.cc921
-rw-r--r--chromium/components/offline_pages/background/request_notifier.h44
-rw-r--r--chromium/components/offline_pages/background/request_picker.cc251
-rw-r--r--chromium/components/offline_pages/background/request_picker.h80
-rw-r--r--chromium/components/offline_pages/background/request_picker_unittest.cc329
-rw-r--r--chromium/components/offline_pages/background/request_queue.cc131
-rw-r--r--chromium/components/offline_pages/background/request_queue.h44
-rw-r--r--chromium/components/offline_pages/background/request_queue_in_memory_store.cc80
-rw-r--r--chromium/components/offline_pages/background/request_queue_in_memory_store.h13
-rw-r--r--chromium/components/offline_pages/background/request_queue_store.h31
-rw-r--r--chromium/components/offline_pages/background/request_queue_store_sql.cc467
-rw-r--r--chromium/components/offline_pages/background/request_queue_store_sql.h46
-rw-r--r--chromium/components/offline_pages/background/request_queue_store_unittest.cc214
-rw-r--r--chromium/components/offline_pages/background/request_queue_unittest.cc240
-rw-r--r--chromium/components/offline_pages/background/save_page_request.cc69
-rw-r--r--chromium/components/offline_pages/background/save_page_request.h66
-rw-r--r--chromium/components/offline_pages/background/save_page_request_unittest.cc73
-rw-r--r--chromium/components/offline_pages/background/scheduler.h8
-rw-r--r--chromium/components/offline_pages/client_namespace_constants.cc4
-rw-r--r--chromium/components/offline_pages/client_namespace_constants.h4
-rw-r--r--chromium/components/offline_pages/client_policy_controller.cc44
-rw-r--r--chromium/components/offline_pages/client_policy_controller.h6
-rw-r--r--chromium/components/offline_pages/client_policy_controller_unittest.cc45
-rw-r--r--chromium/components/offline_pages/core/BUILD.gn49
-rw-r--r--chromium/components/offline_pages/core/task.cc43
-rw-r--r--chromium/components/offline_pages/core/task.h82
-rw-r--r--chromium/components/offline_pages/core/task_queue.cc49
-rw-r--r--chromium/components/offline_pages/core/task_queue.h64
-rw-r--r--chromium/components/offline_pages/core/task_queue_unittest.cc123
-rw-r--r--chromium/components/offline_pages/core/task_unittest.cc81
-rw-r--r--chromium/components/offline_pages/core/test_task.cc58
-rw-r--r--chromium/components/offline_pages/core/test_task.h59
-rw-r--r--chromium/components/offline_pages/downloads/BUILD.gn44
-rw-r--r--chromium/components/offline_pages/downloads/download_notifying_observer.cc82
-rw-r--r--chromium/components/offline_pages/downloads/download_notifying_observer.h61
-rw-r--r--chromium/components/offline_pages/downloads/download_notifying_observer_unittest.cc251
-rw-r--r--chromium/components/offline_pages/downloads/download_ui_adapter.cc217
-rw-r--r--chromium/components/offline_pages/downloads/download_ui_adapter.h136
-rw-r--r--chromium/components/offline_pages/downloads/download_ui_adapter_unittest.cc305
-rw-r--r--chromium/components/offline_pages/downloads/download_ui_item.cc41
-rw-r--r--chromium/components/offline_pages/downloads/download_ui_item.h51
-rw-r--r--chromium/components/offline_pages/downloads/offline_page_download_notifier.h26
-rw-r--r--chromium/components/offline_pages/offline_page_archiver.h4
-rw-r--r--chromium/components/offline_pages/offline_page_client_policy.h76
-rw-r--r--chromium/components/offline_pages/offline_page_feature.cc19
-rw-r--r--chromium/components/offline_pages/offline_page_feature.h14
-rw-r--r--chromium/components/offline_pages/offline_page_item.cc34
-rw-r--r--chromium/components/offline_pages/offline_page_item.h9
-rw-r--r--chromium/components/offline_pages/offline_page_metadata_store.cc2
-rw-r--r--chromium/components/offline_pages/offline_page_metadata_store.h24
-rw-r--r--chromium/components/offline_pages/offline_page_metadata_store_impl_unittest.cc835
-rw-r--r--chromium/components/offline_pages/offline_page_metadata_store_sql.cc591
-rw-r--r--chromium/components/offline_pages/offline_page_metadata_store_sql.h81
-rw-r--r--chromium/components/offline_pages/offline_page_model.h55
-rw-r--r--chromium/components/offline_pages/offline_page_model_event_logger.cc4
-rw-r--r--chromium/components/offline_pages/offline_page_model_event_logger.h3
-rw-r--r--chromium/components/offline_pages/offline_page_model_event_logger_unittest.cc12
-rw-r--r--chromium/components/offline_pages/offline_page_model_impl.cc503
-rw-r--r--chromium/components/offline_pages/offline_page_model_impl.h92
-rw-r--r--chromium/components/offline_pages/offline_page_model_impl_unittest.cc330
-rw-r--r--chromium/components/offline_pages/offline_page_storage_manager.cc6
-rw-r--r--chromium/components/offline_pages/offline_page_storage_manager_unittest.cc15
-rw-r--r--chromium/components/offline_pages/offline_page_test_archiver.cc7
-rw-r--r--chromium/components/offline_pages/offline_page_test_archiver.h3
-rw-r--r--chromium/components/offline_pages/offline_page_test_store.cc74
-rw-r--r--chromium/components/offline_pages/offline_page_test_store.h9
-rw-r--r--chromium/components/offline_pages/offline_page_types.h7
-rw-r--r--chromium/components/offline_pages/offline_store_types.h62
-rw-r--r--chromium/components/offline_pages/request_header/BUILD.gn32
-rw-r--r--chromium/components/offline_pages/request_header/offline_page_header.cc132
-rw-r--r--chromium/components/offline_pages/request_header/offline_page_header.h80
-rw-r--r--chromium/components/offline_pages/request_header/offline_page_header_unittest.cc82
-rw-r--r--chromium/components/offline_pages/stub_offline_page_model.cc19
-rw-r--r--chromium/components/offline_pages/stub_offline_page_model.h23
-rw-r--r--chromium/components/omnibox.gypi222
-rw-r--r--chromium/components/omnibox/browser/BUILD.gn10
-rw-r--r--chromium/components/omnibox_strings.grdp19
-rw-r--r--chromium/components/onc.gypi27
-rw-r--r--chromium/components/onc/BUILD.gn1
-rw-r--r--chromium/components/open_from_clipboard.gypi43
-rw-r--r--chromium/components/open_from_clipboard/BUILD.gn4
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content.h5
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_ios.h42
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_ios.mm113
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm43
-rw-r--r--chromium/components/open_from_clipboard/fake_clipboard_recent_content.cc4
-rw-r--r--chromium/components/open_from_clipboard/fake_clipboard_recent_content.h3
-rw-r--r--chromium/components/os_crypt.gypi138
-rw-r--r--chromium/components/os_crypt/BUILD.gn70
-rw-r--r--chromium/components/os_crypt/OWNERS1
-rw-r--r--chromium/components/os_crypt/features.gni11
-rw-r--r--chromium/components/os_crypt/key_storage_keyring.cc98
-rw-r--r--chromium/components/os_crypt/key_storage_keyring.h49
-rw-r--r--chromium/components/os_crypt/key_storage_keyring_unittest.cc153
-rw-r--r--chromium/components/os_crypt/key_storage_kwallet.cc131
-rw-r--r--chromium/components/os_crypt/key_storage_kwallet.h55
-rw-r--r--chromium/components/os_crypt/key_storage_kwallet_unittest.cc319
-rw-r--r--chromium/components/os_crypt/key_storage_libsecret.cc122
-rw-r--r--chromium/components/os_crypt/key_storage_libsecret.h8
-rw-r--r--chromium/components/os_crypt/key_storage_libsecret_unittest.cc245
-rw-r--r--chromium/components/os_crypt/key_storage_linux.cc106
-rw-r--r--chromium/components/os_crypt/key_storage_linux.h19
-rw-r--r--chromium/components/os_crypt/key_storage_util_linux.cc50
-rw-r--r--chromium/components/os_crypt/key_storage_util_linux.h35
-rw-r--r--chromium/components/os_crypt/keychain_password_mac.mm2
-rw-r--r--chromium/components/os_crypt/keyring_util_linux.cc95
-rw-r--r--chromium/components/os_crypt/keyring_util_linux.h76
-rw-r--r--chromium/components/os_crypt/kwallet_dbus.cc106
-rw-r--r--chromium/components/os_crypt/kwallet_dbus.h114
-rw-r--r--chromium/components/os_crypt/kwallet_dbus_unittest.cc196
-rw-r--r--chromium/components/os_crypt/libsecret_util_linux.cc51
-rw-r--r--chromium/components/os_crypt/libsecret_util_linux.h5
-rw-r--r--chromium/components/os_crypt/os_crypt.h15
-rw-r--r--chromium/components/os_crypt/os_crypt_linux.cc63
-rw-r--r--chromium/components/os_crypt/os_crypt_mocker.cc4
-rw-r--r--chromium/components/os_crypt/os_crypt_posix.cc4
-rw-r--r--chromium/components/os_crypt/os_crypt_unittest.cc55
-rw-r--r--chromium/components/os_crypt/os_crypt_util_linux_unittest.cc177
-rw-r--r--chromium/components/ownership.gypi49
-rw-r--r--chromium/components/ownership/BUILD.gn4
-rw-r--r--chromium/components/ownership/DEPS4
-rw-r--r--chromium/components/ownership/owner_key_util_impl_unittest.cc2
-rw-r--r--chromium/components/ownership/owner_settings_service.h2
-rw-r--r--chromium/components/packed_ct_ev_whitelist.gypi30
-rw-r--r--chromium/components/page_load_metrics.gypi70
-rw-r--r--chromium/components/page_load_metrics/DEPS11
-rw-r--r--chromium/components/page_load_metrics/OWNERS4
-rw-r--r--chromium/components/page_load_metrics/README15
-rw-r--r--chromium/components/page_load_metrics/browser/BUILD.gn45
-rw-r--r--chromium/components/page_load_metrics/browser/DEPS8
-rw-r--r--chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc921
-rw-r--r--chromium/components/page_load_metrics/browser/metrics_web_contents_observer.h350
-rw-r--r--chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc451
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_observer.cc30
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_observer.h192
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_util.cc45
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_util.h48
-rw-r--r--chromium/components/page_load_metrics/common/BUILD.gn17
-rw-r--r--chromium/components/page_load_metrics/common/page_load_metrics_messages.cc39
-rw-r--r--chromium/components/page_load_metrics/common/page_load_metrics_messages.h41
-rw-r--r--chromium/components/page_load_metrics/common/page_load_timing.cc51
-rw-r--r--chromium/components/page_load_metrics/common/page_load_timing.h92
-rw-r--r--chromium/components/page_load_metrics/renderer/BUILD.gn41
-rw-r--r--chromium/components/page_load_metrics/renderer/DEPS5
-rw-r--r--chromium/components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.cc54
-rw-r--r--chromium/components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.h72
-rw-r--r--chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc156
-rw-r--r--chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h53
-rw-r--r--chromium/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc195
-rw-r--r--chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc81
-rw-r--r--chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h59
-rw-r--r--chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc135
-rw-r--r--chromium/components/pageinfo_strings.grdp3
-rw-r--r--chromium/components/pairing.gypi54
-rw-r--r--chromium/components/pairing/OWNERS1
-rw-r--r--chromium/components/pairing/bluetooth_controller_pairing_controller.cc2
-rw-r--r--chromium/components/password_manager.gypi365
-rw-r--r--chromium/components/password_manager/DEPS4
-rw-r--r--chromium/components/password_manager/content/DEPS1
-rw-r--r--chromium/components/password_manager/content/browser/BUILD.gn7
-rw-r--r--chromium/components/password_manager/content/browser/DEPS4
-rw-r--r--chromium/components/password_manager/content/browser/bad_message.cc3
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.cc165
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.h61
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc45
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_factory.h11
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc90
-rw-r--r--chromium/components/password_manager/content/browser/credential_manager_impl.cc67
-rw-r--r--chromium/components/password_manager/content/browser/credential_manager_impl.h6
-rw-r--r--chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc193
-rw-r--r--chromium/components/password_manager/content/public/cpp/BUILD.gn22
-rw-r--r--chromium/components/password_manager/content/public/cpp/OWNERS2
-rw-r--r--chromium/components/password_manager/content/public/cpp/credential_manager.typemap20
-rw-r--r--chromium/components/password_manager/content/public/cpp/credential_manager_struct_traits.cc64
-rw-r--r--chromium/components/password_manager/content/public/cpp/credential_manager_struct_traits.h60
-rw-r--r--chromium/components/password_manager/content/public/cpp/type_converters.cc127
-rw-r--r--chromium/components/password_manager/content/public/cpp/type_converters.h52
-rw-r--r--chromium/components/password_manager/content/public/interfaces/credential_manager.mojom8
-rw-r--r--chromium/components/password_manager/content/renderer/BUILD.gn2
-rw-r--r--chromium/components/password_manager/content/renderer/DEPS1
-rw-r--r--chromium/components/password_manager/content/renderer/credential_manager_client.cc60
-rw-r--r--chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc15
-rw-r--r--chromium/components/password_manager/core/browser/BUILD.gn25
-rw-r--r--chromium/components/password_manager/core/browser/DEPS2
-rw-r--r--chromium/components/password_manager/core/browser/affiliated_match_helper.cc22
-rw-r--r--chromium/components/password_manager/core/browser/affiliated_match_helper.h16
-rw-r--r--chromium/components/password_manager/core/browser/affiliated_match_helper_unittest.cc95
-rw-r--r--chromium/components/password_manager/core/browser/affiliation_database_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/affiliation_fetch_throttler_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc31
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_logger.cc58
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_logger.h41
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_logger_unittest.cc78
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc4
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h2
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc82
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h5
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.cc8
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.h2
-rw-r--r--chromium/components/password_manager/core/browser/credentials_filter.h14
-rw-r--r--chromium/components/password_manager/core/browser/export/password_csv_writer_unittest.cc6
-rw-r--r--chromium/components/password_manager/core/browser/export/password_exporter.cc4
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher.h77
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl.cc111
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl.h86
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc247
-rw-r--r--chromium/components/password_manager/core/browser/form_saver.h16
-rw-r--r--chromium/components/password_manager/core/browser/form_saver_impl.cc51
-rw-r--r--chromium/components/password_manager/core/browser/form_saver_impl.h23
-rw-r--r--chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc103
-rw-r--r--chromium/components/password_manager/core/browser/import/password_importer_unittest.cc3
-rw-r--r--chromium/components/password_manager/core/browser/keychain_migration_status_mac.h6
-rw-r--r--chromium/components/password_manager/core/browser/login_database.cc744
-rw-r--r--chromium/components/password_manager/core/browser/login_database.h50
-rw-r--r--chromium/components/password_manager/core/browser/login_database_ios_unittest.cc12
-rw-r--r--chromium/components/password_manager/core/browser/login_database_unittest.cc342
-rw-r--r--chromium/components/password_manager/core/browser/login_database_win.cc13
-rw-r--r--chromium/components/password_manager/core/browser/mock_affiliated_match_helper.cc10
-rw-r--r--chromium/components/password_manager/core/browser/mock_affiliated_match_helper.h14
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_store.h22
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager.h7
-rw-r--r--chromium/components/password_manager/core/browser/password_bubble_experiment.cc17
-rw-r--r--chromium/components/password_manager/core/browser/password_bubble_experiment.h14
-rw-r--r--chromium/components/password_manager/core/browser/password_bubble_experiment_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.cc390
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.h135
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_unittest.cc745
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_manager.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc45
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.cc91
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.h32
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.h10
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.cc44
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.h20
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_unittest.cc128
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.cc36
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.h6
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util_unittest.cc23
-rw-r--r--chromium/components/password_manager/core/browser/password_store.cc153
-rw-r--r--chromium/components/password_manager/core/browser/password_store.h94
-rw-r--r--chromium/components/password_manager/core/browser/password_store_change.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_store_change.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_store_consumer.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_store_consumer.h10
-rw-r--r--chromium/components/password_manager/core/browser/password_store_default.cc48
-rw-r--r--chromium/components/password_manager/core/browser/password_store_default.h17
-rw-r--r--chromium/components/password_manager/core/browser/password_store_default_unittest.cc68
-rw-r--r--chromium/components/password_manager/core/browser/password_store_factory_util.cc7
-rw-r--r--chromium/components/password_manager/core/browser/password_store_factory_util.h6
-rw-r--r--chromium/components/password_manager/core/browser/password_store_origin_unittest.h1
-rw-r--r--chromium/components/password_manager/core/browser/password_store_sync.h13
-rw-r--r--chromium/components/password_manager/core/browser/password_store_unittest.cc289
-rw-r--r--chromium/components/password_manager/core/browser/password_syncable_service.cc26
-rw-r--r--chromium/components/password_manager/core/browser/password_syncable_service.h12
-rw-r--r--chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc15
-rw-r--r--chromium/components/password_manager/core/browser/sql_table_builder.cc319
-rw-r--r--chromium/components/password_manager/core/browser/sql_table_builder.h149
-rw-r--r--chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc253
-rw-r--r--chromium/components/password_manager/core/browser/statistics_table.cc73
-rw-r--r--chromium/components/password_manager/core/browser/statistics_table.h15
-rw-r--r--chromium/components/password_manager/core/browser/statistics_table_unittest.cc54
-rw-r--r--chromium/components/password_manager/core/browser/stub_credentials_filter.cc31
-rw-r--r--chromium/components/password_manager/core/browser/stub_credentials_filter.h41
-rw-r--r--chromium/components/password_manager/core/browser/stub_form_saver.h15
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.cc11
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.h15
-rw-r--r--chromium/components/password_manager/core/browser/test_password_store.cc24
-rw-r--r--chromium/components/password_manager/core/browser/test_password_store.h17
-rw-r--r--chromium/components/password_manager/core/common/BUILD.gn2
-rw-r--r--chromium/components/password_manager/core/common/credential_manager_types.cc16
-rw-r--r--chromium/components/password_manager/core/common/credential_manager_types.h1
-rw-r--r--chromium/components/password_manager/sync/browser/BUILD.gn8
-rw-r--r--chromium/components/password_manager/sync/browser/DEPS6
-rw-r--r--chromium/components/password_manager/sync/browser/password_data_type_controller.cc22
-rw-r--r--chromium/components/password_manager/sync/browser/password_data_type_controller.h25
-rw-r--r--chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service.cc4
-rw-r--r--chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service.h7
-rw-r--r--chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc14
-rw-r--r--chromium/components/password_manager/sync/browser/password_model_worker.h2
-rw-r--r--chromium/components/password_manager/sync/browser/password_sync_util.cc10
-rw-r--r--chromium/components/password_manager/sync/browser/password_sync_util.h6
-rw-r--r--chromium/components/password_manager/sync/browser/password_sync_util_unittest.cc4
-rw-r--r--chromium/components/password_manager/sync/browser/sync_credentials_filter.cc23
-rw-r--r--chromium/components/password_manager/sync/browser/sync_credentials_filter.h14
-rw-r--r--chromium/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc161
-rw-r--r--chromium/components/password_manager/sync/browser/sync_username_test_base.h14
-rw-r--r--chromium/components/pdf.gypi66
-rw-r--r--chromium/components/pdf/browser/pdf_web_contents_helper.cc4
-rw-r--r--chromium/components/pdf/browser/pdf_web_contents_helper.h3
-rw-r--r--chromium/components/pdf/renderer/pdf_accessibility_tree.cc84
-rw-r--r--chromium/components/pdf/renderer/pdf_accessibility_tree.h16
-rw-r--r--chromium/components/pdf/renderer/pepper_pdf_host.cc82
-rw-r--r--chromium/components/pdf/renderer/pepper_pdf_host.h17
-rw-r--r--chromium/components/physical_web/OWNERS2
-rw-r--r--chromium/components/physical_web/data_source/BUILD.gn29
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source.h49
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source_impl.cc37
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source_impl.h37
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc158
-rw-r--r--chromium/components/physical_web/data_source/physical_web_listener.h26
-rw-r--r--chromium/components/physical_web/webui/BUILD.gn14
-rw-r--r--chromium/components/physical_web/webui/physical_web_ui_constants.cc27
-rw-r--r--chromium/components/physical_web/webui/physical_web_ui_constants.h33
-rw-r--r--chromium/components/physical_web/webui/resources/physical_web.css50
-rw-r--r--chromium/components/physical_web/webui/resources/physical_web.html43
-rw-r--r--chromium/components/physical_web/webui/resources/physical_web.js31
-rw-r--r--chromium/components/physical_web_ui_strings.grdp6
-rw-r--r--chromium/components/plugins.gypi50
-rw-r--r--chromium/components/plugins/renderer/loadable_plugin_placeholder.cc25
-rw-r--r--chromium/components/plugins/renderer/loadable_plugin_placeholder.h6
-rw-r--r--chromium/components/plugins/renderer/mobile_youtube_plugin.cc1
-rw-r--r--chromium/components/plugins/renderer/webview_plugin.cc74
-rw-r--r--chromium/components/plugins/renderer/webview_plugin.h40
-rw-r--r--chromium/components/policy.gypi598
-rw-r--r--chromium/components/policy/BUILD.gn181
-rw-r--r--chromium/components/policy/android/BUILD.gn6
-rw-r--r--chromium/components/policy/core/browser/BUILD.gn51
-rw-r--r--chromium/components/policy/core/common/BUILD.gn87
-rw-r--r--chromium/components/policy/policy_browser.gypi84
-rw-r--r--chromium/components/policy/policy_common.gypi238
-rw-r--r--chromium/components/policy/proto/BUILD.gn3
-rw-r--r--chromium/components/policy_strings.grdp15
-rw-r--r--chromium/components/power.gypi25
-rw-r--r--chromium/components/power/BUILD.gn1
-rw-r--r--chromium/components/power/origin_power_map.cc26
-rw-r--r--chromium/components/power/origin_power_map.h5
-rw-r--r--chromium/components/power/origin_power_map_unittest.cc63
-rw-r--r--chromium/components/precache.gypi107
-rw-r--r--chromium/components/precache/DEPS1
-rw-r--r--chromium/components/precache/OWNERS1
-rw-r--r--chromium/components/precache/android/BUILD.gn2
-rw-r--r--chromium/components/precache/content/BUILD.gn4
-rw-r--r--chromium/components/precache/content/DEPS2
-rw-r--r--chromium/components/precache/content/precache_manager.cc48
-rw-r--r--chromium/components/precache/content/precache_manager.h8
-rw-r--r--chromium/components/precache/content/precache_manager_unittest.cc66
-rw-r--r--chromium/components/precache/core/BUILD.gn8
-rw-r--r--chromium/components/precache/core/DEPS1
-rw-r--r--chromium/components/precache/core/fetcher_pool_unittest.cc7
-rw-r--r--chromium/components/precache/core/precache_database.cc211
-rw-r--r--chromium/components/precache/core/precache_database.h56
-rw-r--r--chromium/components/precache/core/precache_database_unittest.cc213
-rw-r--r--chromium/components/precache/core/precache_fetcher.cc556
-rw-r--r--chromium/components/precache/core/precache_fetcher.h116
-rw-r--r--chromium/components/precache/core/precache_fetcher_unittest.cc987
-rw-r--r--chromium/components/precache/core/precache_referrer_host_table.cc123
-rw-r--r--chromium/components/precache/core/precache_referrer_host_table.h82
-rw-r--r--chromium/components/precache/core/precache_referrer_host_table_unittest.cc154
-rw-r--r--chromium/components/precache/core/precache_session_table.cc77
-rw-r--r--chromium/components/precache/core/precache_session_table.h35
-rw-r--r--chromium/components/precache/core/precache_session_table_unittest.cc63
-rw-r--r--chromium/components/precache/core/precache_url_table.cc113
-rw-r--r--chromium/components/precache/core/precache_url_table.h50
-rw-r--r--chromium/components/precache/core/precache_url_table_unittest.cc101
-rw-r--r--chromium/components/precache/core/proto/precache.proto35
-rw-r--r--chromium/components/precache/core/proto/quota.proto20
-rw-r--r--chromium/components/precache/core/proto/timestamp.proto17
-rw-r--r--chromium/components/precache/core/proto/unfinished_work.proto17
-rw-r--r--chromium/components/precache/precache_defines.gypi24
-rw-r--r--chromium/components/pref_registry.gypi41
-rw-r--r--chromium/components/pref_registry/BUILD.gn4
-rw-r--r--chromium/components/prefs/BUILD.gn2
-rw-r--r--chromium/components/prefs/in_memory_pref_store_unittest.cc8
-rw-r--r--chromium/components/prefs/json_pref_store.cc77
-rw-r--r--chromium/components/prefs/json_pref_store.h38
-rw-r--r--chromium/components/prefs/json_pref_store_unittest.cc392
-rw-r--r--chromium/components/prefs/overlay_user_pref_store_unittest.cc18
-rw-r--r--chromium/components/prefs/pref_filter.h16
-rw-r--r--chromium/components/prefs/pref_notifier_impl.cc41
-rw-r--r--chromium/components/prefs/pref_notifier_impl.h4
-rw-r--r--chromium/components/prefs/pref_notifier_impl_unittest.cc2
-rw-r--r--chromium/components/prefs/pref_registry.cc4
-rw-r--r--chromium/components/prefs/pref_service.cc2
-rw-r--r--chromium/components/prefs/pref_value_map.cc12
-rw-r--r--chromium/components/prefs/pref_value_map.h1
-rw-r--r--chromium/components/prefs/pref_value_map_unittest.cc48
-rw-r--r--chromium/components/prefs/prefs.gyp89
-rw-r--r--chromium/components/prefs/testing_pref_store.cc6
-rw-r--r--chromium/components/previews/OWNERS1
-rw-r--r--chromium/components/previews/PRESUBMIT.py12
-rw-r--r--chromium/components/previews/README2
-rw-r--r--chromium/components/previews/core/BUILD.gn52
-rw-r--r--chromium/components/previews/core/DEPS5
-rw-r--r--chromium/components/previews/core/previews_black_list.cc182
-rw-r--r--chromium/components/previews/core/previews_black_list.h124
-rw-r--r--chromium/components/previews/core/previews_black_list_item.cc60
-rw-r--r--chromium/components/previews/core/previews_black_list_item.h80
-rw-r--r--chromium/components/previews/core/previews_black_list_item_unittest.cc89
-rw-r--r--chromium/components/previews/core/previews_black_list_unittest.cc318
-rw-r--r--chromium/components/previews/core/previews_data_savings.cc71
-rw-r--r--chromium/components/previews/core/previews_data_savings.h51
-rw-r--r--chromium/components/previews/core/previews_data_savings_unittest.cc166
-rw-r--r--chromium/components/previews/core/previews_decider.h29
-rw-r--r--chromium/components/previews/core/previews_experiments.cc126
-rw-r--r--chromium/components/previews/core/previews_experiments.h43
-rw-r--r--chromium/components/previews/core/previews_experiments_unittest.cc29
-rw-r--r--chromium/components/previews/core/previews_io_data.cc92
-rw-r--r--chromium/components/previews/core/previews_io_data.h84
-rw-r--r--chromium/components/previews/core/previews_io_data_unittest.cc82
-rw-r--r--chromium/components/previews/core/previews_opt_out_store.h61
-rw-r--r--chromium/components/previews/core/previews_ui_service.cc49
-rw-r--r--chromium/components/previews/core/previews_ui_service.h62
-rw-r--r--chromium/components/previews/core/previews_ui_service_unittest.cc87
-rw-r--r--chromium/components/printing.gypi82
-rw-r--r--chromium/components/printing/browser/BUILD.gn2
-rw-r--r--chromium/components/printing/common/BUILD.gn2
-rw-r--r--chromium/components/printing/common/print_messages.h1
-rw-r--r--chromium/components/printing/renderer/BUILD.gn2
-rw-r--r--chromium/components/printing/renderer/print_web_view_helper.cc104
-rw-r--r--chromium/components/printing/renderer/print_web_view_helper.h11
-rw-r--r--chromium/components/printing/renderer/print_web_view_helper_linux.cc2
-rw-r--r--chromium/components/printing/renderer/print_web_view_helper_mac.mm6
-rw-r--r--chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc7
-rw-r--r--chromium/components/printing/test/BUILD.gn2
-rw-r--r--chromium/components/profile_metrics.gypi24
-rw-r--r--chromium/components/profile_metrics/BUILD.gn1
-rw-r--r--chromium/components/proximity_auth.gypi268
-rw-r--r--chromium/components/proximity_auth/BUILD.gn4
-rw-r--r--chromium/components/proximity_auth/ble/BUILD.gn5
-rw-r--r--chromium/components/proximity_auth/cryptauth/BUILD.gn4
-rw-r--r--chromium/components/proximity_auth/cryptauth/proto/BUILD.gn1
-rw-r--r--chromium/components/proximity_auth/logging/BUILD.gn2
-rw-r--r--chromium/components/proximity_auth/webui/BUILD.gn1
-rw-r--r--chromium/components/proxy_config.gypi41
-rw-r--r--chromium/components/proxy_config/BUILD.gn1
-rw-r--r--chromium/components/query_parser.gypi26
-rw-r--r--chromium/components/query_parser/query_parser.cc2
-rw-r--r--chromium/components/quirks.gypi36
-rw-r--r--chromium/components/quirks/quirks_manager.cc49
-rw-r--r--chromium/components/quirks/quirks_manager.h17
-rw-r--r--chromium/components/rappor.gypi76
-rw-r--r--chromium/components/rappor/BUILD.gn4
-rw-r--r--chromium/components/rappor/byte_vector_utils.cc14
-rw-r--r--chromium/components/rappor/byte_vector_utils.h3
-rw-r--r--chromium/components/rappor/rappor_service.cc8
-rw-r--r--chromium/components/rappor/reports.cc5
-rw-r--r--chromium/components/renderer_context_menu.gypi32
-rw-r--r--chromium/components/renderer_context_menu/render_view_context_menu_base.cc25
-rw-r--r--chromium/components/renderer_context_menu/render_view_context_menu_base.h16
-rw-r--r--chromium/components/renderer_context_menu/views/toolkit_delegate_views.cc7
-rw-r--r--chromium/components/resources/BUILD.gn6
-rw-r--r--chromium/components/resources/OWNERS1
-rw-r--r--chromium/components/resources/autofill_scaled_resources.grdp33
-rw-r--r--chromium/components/resources/components_resources.grd3
-rw-r--r--chromium/components/resources/components_scaled_resources.grd2
-rw-r--r--chromium/components/resources/default_100_percent/omnibox/ios/location_bar_http.pngbin2833 -> 0 bytes
-rw-r--r--chromium/components/resources/default_100_percent/omnibox/ios/omnibox_http.pngbin382 -> 225 bytes
-rw-r--r--chromium/components/resources/default_100_percent/omnibox/ios/omnibox_https_invalid.pngbin254 -> 171 bytes
-rw-r--r--chromium/components/resources/default_100_percent/omnibox/ios/omnibox_https_valid.pngbin178 -> 141 bytes
-rw-r--r--chromium/components/resources/default_200_percent/omnibox/ios/location_bar_http.pngbin2912 -> 0 bytes
-rw-r--r--chromium/components/resources/default_200_percent/omnibox/ios/omnibox_http.pngbin779 -> 425 bytes
-rw-r--r--chromium/components/resources/default_200_percent/omnibox/ios/omnibox_https_invalid.pngbin407 -> 320 bytes
-rw-r--r--chromium/components/resources/default_200_percent/omnibox/ios/omnibox_https_valid.pngbin292 -> 217 bytes
-rw-r--r--chromium/components/resources/default_300_percent/omnibox/ios/location_bar_http.pngbin3083 -> 0 bytes
-rw-r--r--chromium/components/resources/default_300_percent/omnibox/ios/omnibox_http.pngbin1060 -> 600 bytes
-rw-r--r--chromium/components/resources/default_300_percent/omnibox/ios/omnibox_https_invalid.pngbin532 -> 468 bytes
-rw-r--r--chromium/components/resources/default_300_percent/omnibox/ios/omnibox_https_valid.pngbin377 -> 312 bytes
-rw-r--r--chromium/components/resources/omnibox_scaled_resources.grdp2
-rw-r--r--chromium/components/resources/physical_web_ui_resources.grdp6
-rw-r--r--chromium/components/resources/sync_driver_resources.grdp22
-rw-r--r--chromium/components/rlz.gypi38
-rw-r--r--chromium/components/rlz/BUILD.gn2
-rw-r--r--chromium/components/safe_browsing_db.gypi144
-rw-r--r--chromium/components/safe_browsing_db/BUILD.gn142
-rw-r--r--chromium/components/safe_browsing_db/DEPS2
-rw-r--r--chromium/components/safe_browsing_db/database_manager.cc277
-rw-r--r--chromium/components/safe_browsing_db/database_manager.h183
-rw-r--r--chromium/components/safe_browsing_db/database_manager_unittest.cc490
-rw-r--r--chromium/components/safe_browsing_db/prefix_set_unittest.cc2
-rw-r--r--chromium/components/safe_browsing_db/remote_database_manager.cc136
-rw-r--r--chromium/components/safe_browsing_db/remote_database_manager.h28
-rw-r--r--chromium/components/safe_browsing_db/remote_database_manager_unittest.cc5
-rw-r--r--chromium/components/safe_browsing_db/safebrowsing.proto4
-rw-r--r--chromium/components/safe_browsing_db/test_database_manager.cc42
-rw-r--r--chromium/components/safe_browsing_db/test_database_manager.h16
-rw-r--r--chromium/components/safe_browsing_db/testing_util.h12
-rw-r--r--chromium/components/safe_browsing_db/util.cc270
-rw-r--r--chromium/components/safe_browsing_db/util.h59
-rw-r--r--chromium/components/safe_browsing_db/util_unittest.cc267
-rw-r--r--chromium/components/safe_browsing_db/v4_database.cc69
-rw-r--r--chromium/components/safe_browsing_db/v4_database.h62
-rw-r--r--chromium/components/safe_browsing_db/v4_database_unittest.cc229
-rw-r--r--chromium/components/safe_browsing_db/v4_feature_list.cc32
-rw-r--r--chromium/components/safe_browsing_db/v4_feature_list.h24
-rw-r--r--chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.cc728
-rw-r--r--chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.h270
-rw-r--r--chromium/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc705
-rw-r--r--chromium/components/safe_browsing_db/v4_local_database_manager.cc426
-rw-r--r--chromium/components/safe_browsing_db/v4_local_database_manager.h202
-rw-r--r--chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc220
-rw-r--r--chromium/components/safe_browsing_db/v4_protocol_manager_util.cc415
-rw-r--r--chromium/components/safe_browsing_db/v4_protocol_manager_util.h222
-rw-r--r--chromium/components/safe_browsing_db/v4_protocol_manager_util_unittest.cc131
-rw-r--r--chromium/components/safe_browsing_db/v4_rice.cc296
-rw-r--r--chromium/components/safe_browsing_db/v4_rice.h169
-rw-r--r--chromium/components/safe_browsing_db/v4_rice_unittest.cc269
-rw-r--r--chromium/components/safe_browsing_db/v4_store.cc562
-rw-r--r--chromium/components/safe_browsing_db/v4_store.h212
-rw-r--r--chromium/components/safe_browsing_db/v4_store_unittest.cc667
-rw-r--r--chromium/components/safe_browsing_db/v4_update_protocol_manager.cc27
-rw-r--r--chromium/components/safe_browsing_db/v4_update_protocol_manager.h9
-rw-r--r--chromium/components/safe_browsing_db/v4_update_protocol_manager_unittest.cc52
-rw-r--r--chromium/components/safe_json.gypi126
-rw-r--r--chromium/components/safe_json/BUILD.gn7
-rw-r--r--chromium/components/safe_json/android/BUILD.gn2
-rw-r--r--chromium/components/safe_json/json_sanitizer_android.cc4
-rw-r--r--chromium/components/safe_json/public/interfaces/BUILD.gn2
-rw-r--r--chromium/components/safe_json/utility/BUILD.gn2
-rw-r--r--chromium/components/safe_json/utility/safe_json_parser_mojo_impl.cc15
-rw-r--r--chromium/components/safe_json/utility/safe_json_parser_mojo_impl.h10
-rw-r--r--chromium/components/scheduler/BUILD.gn178
-rw-r--r--chromium/components/scheduler/DEPS4
-rw-r--r--chromium/components/scheduler/OWNERS3
-rw-r--r--chromium/components/scheduler/base/DEPS9
-rw-r--r--chromium/components/scheduler/base/cancelable_closure_holder.cc28
-rw-r--r--chromium/components/scheduler/base/cancelable_closure_holder.h40
-rw-r--r--chromium/components/scheduler/base/enqueue_order.cc20
-rw-r--r--chromium/components/scheduler/base/enqueue_order.h32
-rw-r--r--chromium/components/scheduler/base/lazy_now.cc17
-rw-r--r--chromium/components/scheduler/base/lazy_now.h36
-rw-r--r--chromium/components/scheduler/base/pollable_thread_safe_flag.cc19
-rw-r--r--chromium/components/scheduler/base/pollable_thread_safe_flag.h36
-rw-r--r--chromium/components/scheduler/base/real_time_domain.cc73
-rw-r--r--chromium/components/scheduler/base/real_time_domain.h44
-rw-r--r--chromium/components/scheduler/base/task_queue.h216
-rw-r--r--chromium/components/scheduler/base/task_queue_impl.cc705
-rw-r--r--chromium/components/scheduler/base/task_queue_impl.h309
-rw-r--r--chromium/components/scheduler/base/task_queue_manager.cc418
-rw-r--r--chromium/components/scheduler/base/task_queue_manager.h257
-rw-r--r--chromium/components/scheduler/base/task_queue_manager_delegate.h34
-rw-r--r--chromium/components/scheduler/base/task_queue_manager_delegate_for_test.cc56
-rw-r--r--chromium/components/scheduler/base/task_queue_manager_delegate_for_test.h48
-rw-r--r--chromium/components/scheduler/base/task_queue_manager_perftest.cc163
-rw-r--r--chromium/components/scheduler/base/task_queue_manager_unittest.cc1929
-rw-r--r--chromium/components/scheduler/base/task_queue_selector.cc380
-rw-r--r--chromium/components/scheduler/base/task_queue_selector.h206
-rw-r--r--chromium/components/scheduler/base/task_queue_selector_unittest.cc494
-rw-r--r--chromium/components/scheduler/base/test_always_fail_time_source.cc21
-rw-r--r--chromium/components/scheduler/base/test_always_fail_time_source.h26
-rw-r--r--chromium/components/scheduler/base/test_time_source.cc20
-rw-r--r--chromium/components/scheduler/base/test_time_source.h31
-rw-r--r--chromium/components/scheduler/base/time_domain.cc215
-rw-r--r--chromium/components/scheduler/base/time_domain.h156
-rw-r--r--chromium/components/scheduler/base/time_domain_unittest.cc230
-rw-r--r--chromium/components/scheduler/base/virtual_time_domain.cc64
-rw-r--r--chromium/components/scheduler/base/virtual_time_domain.h55
-rw-r--r--chromium/components/scheduler/base/work_queue.cc105
-rw-r--r--chromium/components/scheduler/base/work_queue.h96
-rw-r--r--chromium/components/scheduler/base/work_queue_sets.cc146
-rw-r--r--chromium/components/scheduler/base/work_queue_sets.h68
-rw-r--r--chromium/components/scheduler/base/work_queue_sets_unittest.cc259
-rw-r--r--chromium/components/scheduler/child/DEPS13
-rw-r--r--chromium/components/scheduler/child/OWNERS3
-rw-r--r--chromium/components/scheduler/child/child_scheduler.h70
-rw-r--r--chromium/components/scheduler/child/compositor_worker_scheduler.cc166
-rw-r--r--chromium/components/scheduler/child/compositor_worker_scheduler.h53
-rw-r--r--chromium/components/scheduler/child/idle_helper.cc486
-rw-r--r--chromium/components/scheduler/child/idle_helper.h221
-rw-r--r--chromium/components/scheduler/child/idle_helper_unittest.cc1159
-rw-r--r--chromium/components/scheduler/child/scheduler_helper.cc164
-rw-r--r--chromium/components/scheduler/child/scheduler_helper.h125
-rw-r--r--chromium/components/scheduler/child/scheduler_helper_unittest.cc228
-rw-r--r--chromium/components/scheduler/child/scheduler_tqm_delegate.h37
-rw-r--r--chromium/components/scheduler/child/scheduler_tqm_delegate_for_test.cc67
-rw-r--r--chromium/components/scheduler/child/scheduler_tqm_delegate_for_test.h59
-rw-r--r--chromium/components/scheduler/child/scheduler_tqm_delegate_impl.cc67
-rw-r--r--chromium/components/scheduler/child/scheduler_tqm_delegate_impl.h56
-rw-r--r--chromium/components/scheduler/child/scheduler_tqm_delegate_impl_unittest.cc31
-rw-r--r--chromium/components/scheduler/child/single_thread_idle_task_runner.cc90
-rw-r--r--chromium/components/scheduler/child/single_thread_idle_task_runner.h99
-rw-r--r--chromium/components/scheduler/child/web_scheduler_impl.cc97
-rw-r--r--chromium/components/scheduler/child/web_scheduler_impl.h66
-rw-r--r--chromium/components/scheduler/child/web_task_runner_impl.cc73
-rw-r--r--chromium/components/scheduler/child/web_task_runner_impl.h53
-rw-r--r--chromium/components/scheduler/child/webthread_base.cc106
-rw-r--r--chromium/components/scheduler/child/webthread_base.h67
-rw-r--r--chromium/components/scheduler/child/webthread_impl_for_worker_scheduler.cc129
-rw-r--r--chromium/components/scheduler/child/webthread_impl_for_worker_scheduler.h77
-rw-r--r--chromium/components/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc206
-rw-r--r--chromium/components/scheduler/child/worker_scheduler.cc28
-rw-r--r--chromium/components/scheduler/child/worker_scheduler.h40
-rw-r--r--chromium/components/scheduler/child/worker_scheduler_impl.cc93
-rw-r--r--chromium/components/scheduler/child/worker_scheduler_impl.h66
-rw-r--r--chromium/components/scheduler/child/worker_scheduler_impl_unittest.cc385
-rw-r--r--chromium/components/scheduler/common/scheduler_switches.cc15
-rw-r--r--chromium/components/scheduler/common/scheduler_switches.h16
-rw-r--r--chromium/components/scheduler/renderer/DEPS18
-rw-r--r--chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain.cc43
-rw-r--r--chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain.h45
-rw-r--r--chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc94
-rw-r--r--chromium/components/scheduler/renderer/deadline_task_runner.cc40
-rw-r--r--chromium/components/scheduler/renderer/deadline_task_runner.h50
-rw-r--r--chromium/components/scheduler/renderer/deadline_task_runner_unittest.cc101
-rw-r--r--chromium/components/scheduler/renderer/idle_time_estimator.cc74
-rw-r--r--chromium/components/scheduler/renderer/idle_time_estimator.h58
-rw-r--r--chromium/components/scheduler/renderer/idle_time_estimator_unittest.cc167
-rw-r--r--chromium/components/scheduler/renderer/render_widget_scheduling_state.cc65
-rw-r--r--chromium/components/scheduler/renderer/render_widget_scheduling_state.h34
-rw-r--r--chromium/components/scheduler/renderer/render_widget_signals.cc63
-rw-r--r--chromium/components/scheduler/renderer/render_widget_signals.h58
-rw-r--r--chromium/components/scheduler/renderer/render_widget_signals_unittest.cpp266
-rw-r--r--chromium/components/scheduler/renderer/renderer_scheduler.cc77
-rw-r--r--chromium/components/scheduler/renderer/renderer_scheduler.h184
-rw-r--r--chromium/components/scheduler/renderer/renderer_scheduler_impl.cc1418
-rw-r--r--chromium/components/scheduler/renderer/renderer_scheduler_impl.h462
-rw-r--r--chromium/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc3371
-rw-r--r--chromium/components/scheduler/renderer/renderer_web_scheduler_impl.cc49
-rw-r--r--chromium/components/scheduler/renderer/renderer_web_scheduler_impl.h33
-rw-r--r--chromium/components/scheduler/renderer/task_cost_estimator.cc43
-rw-r--r--chromium/components/scheduler/renderer/task_cost_estimator.h50
-rw-r--r--chromium/components/scheduler/renderer/task_cost_estimator_unittest.cc80
-rw-r--r--chromium/components/scheduler/renderer/throttled_time_domain.cc39
-rw-r--r--chromium/components/scheduler/renderer/throttled_time_domain.h34
-rw-r--r--chromium/components/scheduler/renderer/throttling_helper.cc191
-rw-r--r--chromium/components/scheduler/renderer/throttling_helper.h99
-rw-r--r--chromium/components/scheduler/renderer/throttling_helper_unittest.cc455
-rw-r--r--chromium/components/scheduler/renderer/user_model.cc222
-rw-r--r--chromium/components/scheduler/renderer/user_model.h84
-rw-r--r--chromium/components/scheduler/renderer/user_model_unittest.cc254
-rw-r--r--chromium/components/scheduler/renderer/web_frame_scheduler_impl.cc124
-rw-r--r--chromium/components/scheduler/renderer/web_frame_scheduler_impl.h70
-rw-r--r--chromium/components/scheduler/renderer/web_view_scheduler_impl.cc115
-rw-r--r--chromium/components/scheduler/renderer/web_view_scheduler_impl.h79
-rw-r--r--chromium/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc504
-rw-r--r--chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc59
-rw-r--r--chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h51
-rw-r--r--chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc213
-rw-r--r--chromium/components/scheduler/scheduler.gyp68
-rw-r--r--chromium/components/scheduler/scheduler.gypi104
-rw-r--r--chromium/components/scheduler/scheduler_export.h29
-rw-r--r--chromium/components/search.gypi27
-rw-r--r--chromium/components/search/BUILD.gn2
-rw-r--r--chromium/components/search/search.cc45
-rw-r--r--chromium/components/search/search.h15
-rw-r--r--chromium/components/search/search_android_unittest.cc8
-rw-r--r--chromium/components/search/search_switches.cc7
-rw-r--r--chromium/components/search/search_switches.h4
-rw-r--r--chromium/components/search/search_unittest.cc67
-rw-r--r--chromium/components/search_engines.gypi113
-rw-r--r--chromium/components/search_engines/BUILD.gn18
-rw-r--r--chromium/components/search_engines/DEPS6
-rw-r--r--chromium/components/search_engines/default_search_manager.cc34
-rw-r--r--chromium/components/search_engines/default_search_manager_unittest.cc18
-rw-r--r--chromium/components/search_engines/default_search_policy_handler.cc41
-rw-r--r--chromium/components/search_engines/default_search_policy_handler.h3
-rw-r--r--chromium/components/search_engines/default_search_policy_handler_unittest.cc23
-rw-r--r--chromium/components/search_engines/default_search_pref_migration.cc2
-rw-r--r--chromium/components/search_engines/default_search_pref_migration_unittest.cc2
-rw-r--r--chromium/components/search_engines/keyword_table.cc2
-rw-r--r--chromium/components/search_engines/keyword_table_unittest.cc3
-rw-r--r--chromium/components/search_engines/prepopulated_engines.gyp25
-rw-r--r--chromium/components/search_engines/prepopulated_engines.json35
-rw-r--r--chromium/components/search_engines/search_engine_data_type_controller.cc21
-rw-r--r--chromium/components/search_engines/search_engine_data_type_controller.h20
-rw-r--r--chromium/components/search_engines/search_engine_data_type_controller_unittest.cc133
-rw-r--r--chromium/components/search_engines/search_engine_type.h1
-rw-r--r--chromium/components/search_engines/search_host_to_urls_map.cc13
-rw-r--r--chromium/components/search_engines/search_host_to_urls_map.h4
-rw-r--r--chromium/components/search_engines/search_host_to_urls_map_unittest.cc46
-rw-r--r--chromium/components/search_engines/template_url.cc70
-rw-r--r--chromium/components/search_engines/template_url.h33
-rw-r--r--chromium/components/search_engines/template_url_fetcher.cc23
-rw-r--r--chromium/components/search_engines/template_url_fetcher.h4
-rw-r--r--chromium/components/search_engines/template_url_parser.cc31
-rw-r--r--chromium/components/search_engines/template_url_parser.h27
-rw-r--r--chromium/components/search_engines/template_url_prepopulate_data.cc117
-rw-r--r--chromium/components/search_engines/template_url_prepopulate_data.h17
-rw-r--r--chromium/components/search_engines/template_url_prepopulate_data_unittest.cc19
-rw-r--r--chromium/components/search_engines/template_url_service.cc490
-rw-r--r--chromium/components/search_engines/template_url_service.h76
-rw-r--r--chromium/components/search_engines/template_url_service_client.h5
-rw-r--r--chromium/components/search_engines/template_url_service_util_unittest.cc64
-rw-r--r--chromium/components/search_engines/template_url_unittest.cc26
-rw-r--r--chromium/components/search_engines/util.cc125
-rw-r--r--chromium/components/search_engines/util.h20
-rw-r--r--chromium/components/search_provider_logos.gypi32
-rw-r--r--chromium/components/search_provider_logos/BUILD.gn4
-rw-r--r--chromium/components/search_provider_logos/google_logo_api.cc12
-rw-r--r--chromium/components/search_provider_logos/logo_cache.cc2
-rw-r--r--chromium/components/search_provider_logos/logo_cache_unittest.cc2
-rw-r--r--chromium/components/search_provider_logos/logo_tracker.cc32
-rw-r--r--chromium/components/search_provider_logos/logo_tracker.h3
-rw-r--r--chromium/components/search_provider_logos/logo_tracker_unittest.cc4
-rw-r--r--chromium/components/search_provider_logos/switches.cc14
-rw-r--r--chromium/components/search_provider_logos/switches.h16
-rw-r--r--chromium/components/security_interstitials.gypi42
-rw-r--r--chromium/components/security_interstitials/core/BUILD.gn1
-rw-r--r--chromium/components/security_interstitials/core/bad_clock_ui.cc4
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/extended_reporting.js6
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/images/1x/triangle_red.pngbin0 -> 1005 bytes
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/images/1x/triangle_white.pngbin0 -> 1000 bytes
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/images/2x/triangle_red.pngbin0 -> 1849 bytes
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/images/2x/triangle_white.pngbin0 -> 1860 bytes
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/interstitial_v2.css16
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/interstitial_v2.js28
-rw-r--r--chromium/components/security_interstitials/core/common_string_util.cc11
-rw-r--r--chromium/components/security_interstitials/core/common_string_util.h3
-rw-r--r--chromium/components/security_interstitials/core/controller_client.cc19
-rw-r--r--chromium/components/security_interstitials/core/controller_client.h7
-rw-r--r--chromium/components/security_interstitials/core/metrics_helper.h1
-rw-r--r--chromium/components/security_interstitials/core/ssl_error_ui.cc6
-rw-r--r--chromium/components/security_interstitials_strings.grdp43
-rw-r--r--chromium/components/security_state.gypi42
-rw-r--r--chromium/components/security_state/BUILD.gn4
-rw-r--r--chromium/components/security_state/security_state_model.cc253
-rw-r--r--chromium/components/security_state/security_state_model.h110
-rw-r--r--chromium/components/security_state/security_state_model_unittest.cc176
-rw-r--r--chromium/components/security_state/switches.cc7
-rw-r--r--chromium/components/security_state/switches.h7
-rw-r--r--chromium/components/service_tab_launcher.gypi52
-rw-r--r--chromium/components/service_tab_launcher/BUILD.gn38
-rw-r--r--chromium/components/service_tab_launcher/DEPS4
-rw-r--r--chromium/components/service_tab_launcher/OWNERS3
-rw-r--r--chromium/components/service_tab_launcher/android/DEPS3
-rw-r--r--chromium/components/service_tab_launcher/browser/android/service_tab_launcher.cc105
-rw-r--r--chromium/components/service_tab_launcher/browser/android/service_tab_launcher.h62
-rw-r--r--chromium/components/session_manager.gypi27
-rw-r--r--chromium/components/session_manager/OWNERS1
-rw-r--r--chromium/components/sessions.gypi165
-rw-r--r--chromium/components/sessions/BUILD.gn14
-rw-r--r--chromium/components/sessions/DEPS4
-rw-r--r--chromium/components/sessions/OWNERS1
-rw-r--r--chromium/components/sessions/content/content_live_tab.cc4
-rw-r--r--chromium/components/sessions/content/content_platform_specific_tab_data.cc7
-rw-r--r--chromium/components/sessions/content/content_platform_specific_tab_data.h3
-rw-r--r--chromium/components/sessions/content/content_record_password_state.cc42
-rw-r--r--chromium/components/sessions/content/content_record_password_state.h27
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_builder.cc29
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_builder_unittest.cc80
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_driver.cc29
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_driver.h24
-rw-r--r--chromium/components/sessions/content/extended_info_handler.h40
-rw-r--r--chromium/components/sessions/core/in_memory_tab_restore_service.cc8
-rw-r--r--chromium/components/sessions/core/in_memory_tab_restore_service.h3
-rw-r--r--chromium/components/sessions/core/persistent_tab_restore_service.cc231
-rw-r--r--chromium/components/sessions/core/persistent_tab_restore_service.h3
-rw-r--r--chromium/components/sessions/core/serialized_navigation_entry.cc35
-rw-r--r--chromium/components/sessions/core/serialized_navigation_entry.h28
-rw-r--r--chromium/components/sessions/core/serialized_navigation_entry_test_helper.cc14
-rw-r--r--chromium/components/sessions/core/serialized_navigation_entry_test_helper.h6
-rw-r--r--chromium/components/sessions/core/serialized_navigation_entry_unittest.cc16
-rw-r--r--chromium/components/sessions/core/session_backend.cc2
-rw-r--r--chromium/components/sessions/core/session_backend_unittest.cc2
-rw-r--r--chromium/components/sessions/core/session_service_commands.cc241
-rw-r--r--chromium/components/sessions/core/session_service_commands.h9
-rw-r--r--chromium/components/sessions/core/session_types.cc9
-rw-r--r--chromium/components/sessions/core/session_types.h6
-rw-r--r--chromium/components/sessions/core/session_types_unittest.cc4
-rw-r--r--chromium/components/sessions/core/tab_restore_service.cc65
-rw-r--r--chromium/components/sessions/core/tab_restore_service.h46
-rw-r--r--chromium/components/sessions/core/tab_restore_service_client.h5
-rw-r--r--chromium/components/sessions/core/tab_restore_service_helper.cc343
-rw-r--r--chromium/components/sessions/core/tab_restore_service_helper.h30
-rw-r--r--chromium/components/signin.gypi268
-rw-r--r--chromium/components/signin/DEPS7
-rw-r--r--chromium/components/signin/core/account_id/BUILD.gn2
-rw-r--r--chromium/components/signin/core/browser/BUILD.gn15
-rw-r--r--chromium/components/signin/core/browser/about_signin_internals.cc10
-rw-r--r--chromium/components/signin/core/browser/about_signin_internals.h2
-rw-r--r--chromium/components/signin/core/browser/account_investigator.cc3
-rw-r--r--chromium/components/signin/core/browser/account_investigator_unittest.cc5
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.cc15
-rw-r--r--chromium/components/signin/core/browser/account_tracker_service.cc19
-rw-r--r--chromium/components/signin/core/browser/account_tracker_service_unittest.cc31
-rw-r--r--chromium/components/signin/core/browser/android/BUILD.gn43
-rw-r--r--chromium/components/signin/core/browser/android/java/DEPS3
-rw-r--r--chromium/components/signin/core/browser/child_account_info_fetcher_android.cc6
-rw-r--r--chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc9
-rw-r--r--chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h4
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service.cc157
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service.h51
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc113
-rw-r--r--chromium/components/signin/core/browser/signin_cookie_changed_subscription.cc10
-rw-r--r--chromium/components/signin/core/browser/signin_cookie_changed_subscription.h5
-rw-r--r--chromium/components/signin/core/browser/signin_error_controller_unittest.cc4
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper.cc119
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper.h12
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper_unittest.cc200
-rw-r--r--chromium/components/signin/core/browser/signin_manager.cc3
-rw-r--r--chromium/components/signin/core/browser/signin_metrics.h2
-rw-r--r--chromium/components/signin/core/browser/signin_status_metrics_provider_base.cc2
-rw-r--r--chromium/components/signin/core/browser/test_signin_client.cc4
-rw-r--r--chromium/components/signin/core/browser/webdata/token_service_table_unittest.cc2
-rw-r--r--chromium/components/signin/core/browser/webdata/token_web_data.cc4
-rw-r--r--chromium/components/signin/core/common/BUILD.gn2
-rw-r--r--chromium/components/signin/core/common/signin_switches.cc4
-rw-r--r--chromium/components/signin/ios/browser/BUILD.gn2
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service.h5
-rw-r--r--chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h61
-rw-r--r--chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.mm132
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h4
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm6
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm44
-rw-r--r--chromium/components/spellcheck/OWNERS5
-rw-r--r--chromium/components/spellcheck/browser/BUILD.gn82
-rw-r--r--chromium/components/spellcheck/browser/DEPS12
-rw-r--r--chromium/components/spellcheck/browser/android/BUILD.gn20
-rw-r--r--chromium/components/spellcheck/browser/feedback.cc193
-rw-r--r--chromium/components/spellcheck/browser/feedback.h123
-rw-r--r--chromium/components/spellcheck/browser/feedback_sender.cc461
-rw-r--r--chromium/components/spellcheck/browser/feedback_sender.h196
-rw-r--r--chromium/components/spellcheck/browser/feedback_sender_unittest.cc729
-rw-r--r--chromium/components/spellcheck/browser/feedback_unittest.cc302
-rw-r--r--chromium/components/spellcheck/browser/misspelling.cc86
-rw-r--r--chromium/components/spellcheck/browser/misspelling.h79
-rw-r--r--chromium/components/spellcheck/browser/misspelling_unittest.cc53
-rw-r--r--chromium/components/spellcheck/browser/pref_names.cc24
-rw-r--r--chromium/components/spellcheck/browser/pref_names.h19
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_action.cc74
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_action.h83
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_action_unittest.cc100
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_dictionary.h23
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_host_metrics.cc149
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_host_metrics.h97
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc116
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_message_filter_platform.h77
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_message_filter_platform_android.cc105
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_platform.h115
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_platform_android.cc75
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_platform_mac.mm309
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_platform_mac_unittest.cc396
-rw-r--r--chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc131
-rw-r--r--chromium/components/spellcheck/browser/spellchecker_session_bridge_android.h65
-rw-r--r--chromium/components/spellcheck/browser/spelling_service_client.cc274
-rw-r--r--chromium/components/spellcheck/browser/spelling_service_client.h129
-rw-r--r--chromium/components/spellcheck/browser/word_trimmer.cc50
-rw-r--r--chromium/components/spellcheck/browser/word_trimmer.h34
-rw-r--r--chromium/components/spellcheck/browser/word_trimmer_unittest.cc67
-rw-r--r--chromium/components/spellcheck/common/BUILD.gn26
-rw-r--r--chromium/components/spellcheck/common/DEPS3
-rw-r--r--chromium/components/spellcheck/common/OWNERS2
-rw-r--r--chromium/components/spellcheck/common/spellcheck_bdict_language.h17
-rw-r--r--chromium/components/spellcheck/common/spellcheck_common.cc190
-rw-r--r--chromium/components/spellcheck/common/spellcheck_common.h67
-rw-r--r--chromium/components/spellcheck/common/spellcheck_features.cc37
-rw-r--r--chromium/components/spellcheck/common/spellcheck_features.h21
-rw-r--r--chromium/components/spellcheck/common/spellcheck_marker.h39
-rw-r--r--chromium/components/spellcheck/common/spellcheck_message_generator.cc39
-rw-r--r--chromium/components/spellcheck/common/spellcheck_message_generator.h9
-rw-r--r--chromium/components/spellcheck/common/spellcheck_messages.h146
-rw-r--r--chromium/components/spellcheck/common/spellcheck_result.h43
-rw-r--r--chromium/components/spellcheck/common/spellcheck_switches.cc33
-rw-r--r--chromium/components/spellcheck/common/spellcheck_switches.h22
-rw-r--r--chromium/components/spellcheck/renderer/BUILD.gn107
-rw-r--r--chromium/components/spellcheck/renderer/DEPS6
-rw-r--r--chromium/components/spellcheck/renderer/custom_dictionary_engine.cc49
-rw-r--r--chromium/components/spellcheck/renderer/custom_dictionary_engine.h43
-rw-r--r--chromium/components/spellcheck/renderer/custom_dictionary_engine_unittest.cc30
-rw-r--r--chromium/components/spellcheck/renderer/hunspell_engine.cc140
-rw-r--r--chromium/components/spellcheck/renderer/hunspell_engine.h63
-rw-r--r--chromium/components/spellcheck/renderer/platform_spelling_engine.cc47
-rw-r--r--chromium/components/spellcheck/renderer/platform_spelling_engine.h23
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck.cc544
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck.h164
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_language.cc151
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_language.h99
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc256
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.cc350
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.h134
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc183
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_mac_unittest.cc92
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_test.cc100
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_test.h68
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_unittest.cc1570
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_worditerator.cc443
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_worditerator.h200
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc508
-rw-r--r--chromium/components/spellcheck/renderer/spelling_engine.h34
-rw-r--r--chromium/components/ssl_config.gypi31
-rw-r--r--chromium/components/ssl_config/BUILD.gn4
-rw-r--r--chromium/components/ssl_config/ssl_config_prefs.cc1
-rw-r--r--chromium/components/ssl_config/ssl_config_prefs.h1
-rw-r--r--chromium/components/ssl_config/ssl_config_service_manager_pref.cc14
-rw-r--r--chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc7
-rw-r--r--chromium/components/ssl_config/ssl_config_switches.cc7
-rw-r--r--chromium/components/ssl_config/ssl_config_switches.h1
-rw-r--r--chromium/components/ssl_errors.gypi31
-rw-r--r--chromium/components/ssl_errors/BUILD.gn3
-rw-r--r--chromium/components/ssl_errors/error_classification.cc71
-rw-r--r--chromium/components/ssl_errors/error_classification.h2
-rw-r--r--chromium/components/ssl_errors/error_classification_unittest.cc5
-rw-r--r--chromium/components/ssl_errors_strings.grdp48
-rw-r--r--chromium/components/startup_metric_utils.gypi90
-rw-r--r--chromium/components/startup_metric_utils/OWNERS2
-rw-r--r--chromium/components/startup_metric_utils/browser/BUILD.gn4
-rw-r--r--chromium/components/startup_metric_utils/browser/startup_metric_host_impl.cc17
-rw-r--r--chromium/components/startup_metric_utils/browser/startup_metric_host_impl.h11
-rw-r--r--chromium/components/startup_metric_utils/browser/startup_metric_utils.cc450
-rw-r--r--chromium/components/startup_metric_utils/browser/startup_metric_utils.h40
-rw-r--r--chromium/components/startup_metric_utils/common/BUILD.gn15
-rw-r--r--chromium/components/startup_metric_utils/common/DEPS3
-rw-r--r--chromium/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc151
-rw-r--r--chromium/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h64
-rw-r--r--chromium/components/storage_monitor.gypi132
-rw-r--r--chromium/components/storage_monitor/BUILD.gn41
-rw-r--r--chromium/components/storage_monitor/image_capture_device_manager_unittest.mm4
-rw-r--r--chromium/components/storage_monitor/media_storage_util_unittest.cc4
-rw-r--r--chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc252
-rw-r--r--chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h95
-rw-r--r--chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos_unittest.cc177
-rw-r--r--chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux.cc252
-rw-r--r--chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux.h95
-rw-r--r--chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc176
-rw-r--r--chromium/components/storage_monitor/portable_device_watcher_win.cc4
-rw-r--r--chromium/components/storage_monitor/storage_monitor.cc2
-rw-r--r--chromium/components/storage_monitor/storage_monitor.h2
-rw-r--r--chromium/components/storage_monitor/storage_monitor_chromeos.cc10
-rw-r--r--chromium/components/storage_monitor/storage_monitor_chromeos.h4
-rw-r--r--chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc8
-rw-r--r--chromium/components/storage_monitor/storage_monitor_linux.cc40
-rw-r--r--chromium/components/storage_monitor/storage_monitor_linux.h12
-rw-r--r--chromium/components/storage_monitor/storage_monitor_linux_unittest.cc10
-rw-r--r--chromium/components/storage_monitor/storage_monitor_mac_unittest.mm6
-rw-r--r--chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.cc110
-rw-r--r--chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h72
-rw-r--r--chromium/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc110
-rw-r--r--chromium/components/storage_monitor/test_media_transfer_protocol_manager_linux.h72
-rw-r--r--chromium/components/storage_monitor/test_storage_monitor.cc10
-rw-r--r--chromium/components/storage_monitor/test_storage_monitor.h4
-rw-r--r--chromium/components/storage_monitor/test_volume_mount_watcher_win.cc2
-rw-r--r--chromium/components/storage_monitor/transient_device_ids.cc4
-rw-r--r--chromium/components/storage_monitor/volume_mount_watcher_win.cc2
-rw-r--r--chromium/components/strings/BUILD.gn8
-rw-r--r--chromium/components/strings/components_chromium_strings_ko.xtb2
-rw-r--r--chromium/components/strings/components_google_chrome_strings_tr.xtb2
-rw-r--r--chromium/components/strings/components_strings_am.xtb129
-rw-r--r--chromium/components/strings/components_strings_ar.xtb129
-rw-r--r--chromium/components/strings/components_strings_bg.xtb129
-rw-r--r--chromium/components/strings/components_strings_bn.xtb131
-rw-r--r--chromium/components/strings/components_strings_ca.xtb133
-rw-r--r--chromium/components/strings/components_strings_cs.xtb127
-rw-r--r--chromium/components/strings/components_strings_da.xtb143
-rw-r--r--chromium/components/strings/components_strings_de.xtb130
-rw-r--r--chromium/components/strings/components_strings_el.xtb131
-rw-r--r--chromium/components/strings/components_strings_en-GB.xtb129
-rw-r--r--chromium/components/strings/components_strings_es-419.xtb129
-rw-r--r--chromium/components/strings/components_strings_es.xtb129
-rw-r--r--chromium/components/strings/components_strings_et.xtb129
-rw-r--r--chromium/components/strings/components_strings_fa.xtb133
-rw-r--r--chromium/components/strings/components_strings_fi.xtb129
-rw-r--r--chromium/components/strings/components_strings_fil.xtb129
-rw-r--r--chromium/components/strings/components_strings_fr.xtb129
-rw-r--r--chromium/components/strings/components_strings_gu.xtb129
-rw-r--r--chromium/components/strings/components_strings_hi.xtb129
-rw-r--r--chromium/components/strings/components_strings_hr.xtb129
-rw-r--r--chromium/components/strings/components_strings_hu.xtb129
-rw-r--r--chromium/components/strings/components_strings_id.xtb131
-rw-r--r--chromium/components/strings/components_strings_it.xtb129
-rw-r--r--chromium/components/strings/components_strings_iw.xtb131
-rw-r--r--chromium/components/strings/components_strings_ja.xtb129
-rw-r--r--chromium/components/strings/components_strings_kn.xtb149
-rw-r--r--chromium/components/strings/components_strings_ko.xtb143
-rw-r--r--chromium/components/strings/components_strings_lt.xtb129
-rw-r--r--chromium/components/strings/components_strings_lv.xtb129
-rw-r--r--chromium/components/strings/components_strings_ml.xtb131
-rw-r--r--chromium/components/strings/components_strings_mr.xtb137
-rw-r--r--chromium/components/strings/components_strings_ms.xtb131
-rw-r--r--chromium/components/strings/components_strings_nl.xtb127
-rw-r--r--chromium/components/strings/components_strings_no.xtb131
-rw-r--r--chromium/components/strings/components_strings_pl.xtb139
-rw-r--r--chromium/components/strings/components_strings_pt-BR.xtb129
-rw-r--r--chromium/components/strings/components_strings_pt-PT.xtb129
-rw-r--r--chromium/components/strings/components_strings_ro.xtb133
-rw-r--r--chromium/components/strings/components_strings_ru.xtb129
-rw-r--r--chromium/components/strings/components_strings_sk.xtb127
-rw-r--r--chromium/components/strings/components_strings_sl.xtb130
-rw-r--r--chromium/components/strings/components_strings_sr.xtb141
-rw-r--r--chromium/components/strings/components_strings_sv.xtb131
-rw-r--r--chromium/components/strings/components_strings_sw.xtb131
-rw-r--r--chromium/components/strings/components_strings_ta.xtb129
-rw-r--r--chromium/components/strings/components_strings_te.xtb129
-rw-r--r--chromium/components/strings/components_strings_th.xtb133
-rw-r--r--chromium/components/strings/components_strings_tr.xtb129
-rw-r--r--chromium/components/strings/components_strings_uk.xtb129
-rw-r--r--chromium/components/strings/components_strings_vi.xtb131
-rw-r--r--chromium/components/strings/components_strings_zh-CN.xtb134
-rw-r--r--chromium/components/strings/components_strings_zh-TW.xtb129
-rw-r--r--chromium/components/subresource_filter.gypi151
-rw-r--r--chromium/components/subresource_filter/DEPS4
-rw-r--r--chromium/components/subresource_filter/content/browser/BUILD.gn7
-rw-r--r--chromium/components/subresource_filter/content/browser/content_ruleset_distributor_unittest.cc2
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver.h4
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc136
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h100
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc438
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.cc42
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.h48
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle_unittests.cc278
-rw-r--r--chromium/components/subresource_filter/content/common/BUILD.gn2
-rw-r--r--chromium/components/subresource_filter/content/common/subresource_filter_messages.h9
-rw-r--r--chromium/components/subresource_filter/content/renderer/BUILD.gn26
-rw-r--r--chromium/components/subresource_filter/content/renderer/document_subresource_filter.cc144
-rw-r--r--chromium/components/subresource_filter/content/renderer/document_subresource_filter.h89
-rw-r--r--chromium/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc124
-rw-r--r--chromium/components/subresource_filter/content/renderer/ruleset_dealer.cc9
-rw-r--r--chromium/components/subresource_filter/content/renderer/ruleset_dealer.h7
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc140
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h44
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc410
-rw-r--r--chromium/components/subresource_filter/core/browser/BUILD.gn8
-rw-r--r--chromium/components/subresource_filter/core/browser/ruleset_service.cc373
-rw-r--r--chromium/components/subresource_filter/core/browser/ruleset_service.h196
-rw-r--r--chromium/components/subresource_filter/core/browser/ruleset_service_unittest.cc675
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_client.h25
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_constants.cc16
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_constants.h28
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features.cc41
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features.h22
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc32
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.h13
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc139
-rw-r--r--chromium/components/subresource_filter/core/common/BUILD.gn44
-rw-r--r--chromium/components/subresource_filter/core/common/activation_list.h19
-rw-r--r--chromium/components/subresource_filter/core/common/activation_scope.cc31
-rw-r--r--chromium/components/subresource_filter/core/common/activation_scope.h29
-rw-r--r--chromium/components/subresource_filter/core/common/activation_state.h2
-rw-r--r--chromium/components/subresource_filter/core/common/copying_file_stream.cc31
-rw-r--r--chromium/components/subresource_filter/core/common/copying_file_stream.h51
-rw-r--r--chromium/components/subresource_filter/core/common/flat/BUILD.gn11
-rw-r--r--chromium/components/subresource_filter/core/common/flat/rules.fbs117
-rw-r--r--chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.cc32
-rw-r--r--chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.h49
-rw-r--r--chromium/components/subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc20
-rw-r--r--chromium/components/subresource_filter/core/common/indexed_ruleset.cc511
-rw-r--r--chromium/components/subresource_filter/core/common/indexed_ruleset.h150
-rw-r--r--chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc612
-rw-r--r--chromium/components/subresource_filter/core/common/knuth_morris_pratt.h55
-rw-r--r--chromium/components/subresource_filter/core/common/proto/BUILD.gn11
-rw-r--r--chromium/components/subresource_filter/core/common/proto/rules.proto194
-rw-r--r--chromium/components/subresource_filter/core/common/string_splitter.h10
-rw-r--r--chromium/components/subresource_filter/core/common/test_ruleset_creator.cc128
-rw-r--r--chromium/components/subresource_filter/core/common/test_ruleset_creator.h87
-rw-r--r--chromium/components/subresource_filter/core/common/unindexed_ruleset.cc70
-rw-r--r--chromium/components/subresource_filter/core/common/unindexed_ruleset.h100
-rw-r--r--chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc203
-rw-r--r--chromium/components/subresource_filter/core/common/url_pattern.cc76
-rw-r--r--chromium/components/subresource_filter/core/common/url_pattern.h53
-rw-r--r--chromium/components/subresource_filter/core/common/url_pattern_matching.h277
-rw-r--r--chromium/components/subresource_filter/core/common/url_pattern_matching_unittest.cc152
-rw-r--r--chromium/components/suggestions.gypi59
-rw-r--r--chromium/components/suggestions/BUILD.gn6
-rw-r--r--chromium/components/suggestions/DEPS2
-rw-r--r--chromium/components/suggestions/image_encoder_ios.mm4
-rw-r--r--chromium/components/suggestions/image_manager_unittest.cc1
-rw-r--r--chromium/components/suggestions/suggestions_service.cc6
-rw-r--r--chromium/components/suggestions/suggestions_service.h24
-rw-r--r--chromium/components/suggestions/suggestions_service_unittest.cc32
-rw-r--r--chromium/components/supervised_user_error_page.gypi22
-rw-r--r--chromium/components/supervised_user_error_page/BUILD.gn26
-rw-r--r--chromium/components/supervised_user_error_page/DEPS8
-rw-r--r--chromium/components/supervised_user_error_page/gin_wrapper.cc112
-rw-r--r--chromium/components/supervised_user_error_page/gin_wrapper.h78
-rw-r--r--chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.js14
-rw-r--r--chromium/components/supervised_user_error_page/supervised_user_error_page.cc31
-rw-r--r--chromium/components/supervised_user_error_page/supervised_user_error_page.h10
-rw-r--r--chromium/components/supervised_user_error_page/supervised_user_error_page_android.cc36
-rw-r--r--chromium/components/supervised_user_error_page/supervised_user_error_page_android.h18
-rw-r--r--chromium/components/supervised_user_error_page/supervised_user_error_page_unittest.cc12
-rw-r--r--chromium/components/sync/BUILD.gn1099
-rw-r--r--chromium/components/sync/android/BUILD.gn69
-rw-r--r--chromium/components/sync/core_impl/attachments/proto/BUILD.gn14
-rw-r--r--chromium/components/sync/protocol/BUILD.gn11
-rw-r--r--chromium/components/sync/protocol/protocol_sources.gni52
-rw-r--r--chromium/components/sync/tools/BUILD.gn54
-rw-r--r--chromium/components/sync_bookmarks.gypi35
-rw-r--r--chromium/components/sync_bookmarks/BUILD.gn10
-rw-r--r--chromium/components/sync_bookmarks/DEPS3
-rw-r--r--chromium/components/sync_bookmarks/bookmark_change_processor.cc56
-rw-r--r--chromium/components/sync_bookmarks/bookmark_change_processor.h37
-rw-r--r--chromium/components/sync_bookmarks/bookmark_data_type_controller.cc34
-rw-r--r--chromium/components/sync_bookmarks/bookmark_data_type_controller.h23
-rw-r--r--chromium/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc57
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_associator.cc46
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_associator.h30
-rw-r--r--chromium/components/sync_driver.gypi207
-rw-r--r--chromium/components/sync_driver/BUILD.gn265
-rw-r--r--chromium/components/sync_sessions.gypi98
-rw-r--r--chromium/components/sync_sessions/BUILD.gn28
-rw-r--r--chromium/components/sync_sessions/DEPS3
-rw-r--r--chromium/components/sync_sessions/fake_sync_sessions_client.cc4
-rw-r--r--chromium/components/sync_sessions/fake_sync_sessions_client.h7
-rw-r--r--chromium/components/sync_sessions/favicon_cache.cc16
-rw-r--r--chromium/components/sync_sessions/favicon_cache.h10
-rw-r--r--chromium/components/sync_sessions/favicon_cache_unittest.cc34
-rw-r--r--chromium/components/sync_sessions/local_session_event_router.h4
-rw-r--r--chromium/components/sync_sessions/lost_navigations_recorder.cc136
-rw-r--r--chromium/components/sync_sessions/lost_navigations_recorder.h58
-rw-r--r--chromium/components/sync_sessions/lost_navigations_recorder_unittest.cc399
-rw-r--r--chromium/components/sync_sessions/open_tabs_ui_delegate.cc4
-rw-r--r--chromium/components/sync_sessions/open_tabs_ui_delegate.h4
-rw-r--r--chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer.h2
-rw-r--r--chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc6
-rw-r--r--chromium/components/sync_sessions/revisit/current_tab_matcher_unittest.cc6
-rw-r--r--chromium/components/sync_sessions/revisit/offset_tab_matcher_unittest.cc6
-rw-r--r--chromium/components/sync_sessions/revisit/page_revisit_broadcaster.cc53
-rw-r--r--chromium/components/sync_sessions/revisit/page_revisit_broadcaster.h12
-rw-r--r--chromium/components/sync_sessions/revisit/page_revisit_broadcaster_unittest.cc8
-rw-r--r--chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.cc13
-rw-r--r--chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.h7
-rw-r--r--chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc82
-rw-r--r--chromium/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc2
-rw-r--r--chromium/components/sync_sessions/revisit/typed_url_page_revisit_task_unittest.cc3
-rw-r--r--chromium/components/sync_sessions/session_data_type_controller.cc47
-rw-r--r--chromium/components/sync_sessions/session_data_type_controller.h32
-rw-r--r--chromium/components/sync_sessions/session_data_type_controller_unittest.cc128
-rw-r--r--chromium/components/sync_sessions/session_sync_test_helper.cc142
-rw-r--r--chromium/components/sync_sessions/session_sync_test_helper.h69
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager.cc117
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager.h48
-rw-r--r--chromium/components/sync_sessions/sync_sessions_client.h13
-rw-r--r--chromium/components/sync_sessions/sync_sessions_metrics.cc13
-rw-r--r--chromium/components/sync_sessions/sync_sessions_metrics.h13
-rw-r--r--chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc31
-rw-r--r--chromium/components/sync_sessions/synced_session.cc15
-rw-r--r--chromium/components/sync_sessions/synced_session.h16
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker.cc322
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker.h163
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker_unittest.cc37
-rw-r--r--chromium/components/sync_sessions/synced_tab_delegate.cc9
-rw-r--r--chromium/components/sync_sessions/synced_tab_delegate.h10
-rw-r--r--chromium/components/sync_sessions/synced_window_delegate.h4
-rw-r--r--chromium/components/sync_sessions/synced_window_delegates_getter.cc4
-rw-r--r--chromium/components/sync_sessions/synced_window_delegates_getter.h4
-rw-r--r--chromium/components/sync_sessions/tab_node_pool.cc14
-rw-r--r--chromium/components/sync_sessions/tab_node_pool.h8
-rw-r--r--chromium/components/sync_sessions/tab_node_pool_unittest.cc12
-rw-r--r--chromium/components/sync_ui_strings.grdp3
-rw-r--r--chromium/components/syncable_prefs.gypi64
-rw-r--r--chromium/components/syncable_prefs/BUILD.gn13
-rw-r--r--chromium/components/syncable_prefs/DEPS2
-rw-r--r--chromium/components/syncable_prefs/pref_model_associator.cc49
-rw-r--r--chromium/components/syncable_prefs/pref_model_associator.h18
-rw-r--r--chromium/components/syncable_prefs/pref_service_syncable.cc6
-rw-r--r--chromium/components/syncable_prefs/pref_service_syncable.h2
-rw-r--r--chromium/components/syncable_prefs/pref_service_syncable_unittest.cc36
-rw-r--r--chromium/components/test_runner/BUILD.gn17
-rw-r--r--chromium/components/test_runner/test_runner.gyp224
-rw-r--r--chromium/components/timers.gypi23
-rw-r--r--chromium/components/toolbar.gypi63
-rw-r--r--chromium/components/toolbar/BUILD.gn5
-rw-r--r--chromium/components/toolbar/test_toolbar_model.cc16
-rw-r--r--chromium/components/toolbar/test_toolbar_model.h8
-rw-r--r--chromium/components/toolbar/toolbar_model.cc18
-rw-r--r--chromium/components/toolbar/toolbar_model.h38
-rw-r--r--chromium/components/toolbar/toolbar_model_delegate.h9
-rw-r--r--chromium/components/toolbar/toolbar_model_impl.cc43
-rw-r--r--chromium/components/toolbar/toolbar_model_impl.h13
-rwxr-xr-xchromium/components/tools/metrics/browser_components_metrics.py65
-rwxr-xr-xchromium/components/tools/metrics/count_ifdefs.py77
-rwxr-xr-xchromium/components/tools/metrics/count_ifdefs_unittest.py30
-rw-r--r--chromium/components/tracing.gyp60
-rw-r--r--chromium/components/tracing/BUILD.gn41
-rw-r--r--chromium/components/tracing/OWNERS6
-rw-r--r--chromium/components/tracing/browser/trace_config_file_unittest.cc16
-rw-r--r--chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.cc2
-rw-r--r--chromium/components/tracing/child/child_trace_message_filter.cc4
-rw-r--r--chromium/components/tracing/child/child_trace_message_filter.h2
-rw-r--r--chromium/components/tracing/child/child_trace_message_filter_unittest.cc1
-rw-r--r--chromium/components/tracing/common/graphics_memory_dump_provider_android_unittest.cc4
-rw-r--r--chromium/components/tracing/common/process_metrics_memory_dump_provider.cc8
-rw-r--r--chromium/components/tracing/core/proto_utils.cc89
-rw-r--r--chromium/components/tracing/core/proto_utils.h182
-rw-r--r--chromium/components/tracing/core/proto_utils_unittest.cc192
-rw-r--r--chromium/components/tracing/core/proto_zero_message.cc129
-rw-r--r--chromium/components/tracing/core/proto_zero_message.h213
-rw-r--r--chromium/components/tracing/core/proto_zero_message_handle.cc67
-rw-r--r--chromium/components/tracing/core/proto_zero_message_handle.h69
-rw-r--r--chromium/components/tracing/core/proto_zero_message_unittest.cc327
-rw-r--r--chromium/components/tracing/core/scattered_stream_writer.cc4
-rw-r--r--chromium/components/tracing/core/scattered_stream_writer.h18
-rw-r--r--chromium/components/tracing/core/scattered_stream_writer_unittest.cc52
-rw-r--r--chromium/components/tracing/core/trace_buffer_writer.cc206
-rw-r--r--chromium/components/tracing/core/trace_buffer_writer.h103
-rw-r--r--chromium/components/tracing/core/trace_buffer_writer_unittest.cc312
-rw-r--r--chromium/components/tracing/core/trace_ring_buffer.cc42
-rw-r--r--chromium/components/tracing/core/trace_ring_buffer.h45
-rw-r--r--chromium/components/tracing/core/trace_ring_buffer_unittest.cc39
-rw-r--r--chromium/components/tracing/docs/adding_memory_infra_tracing.md2
-rw-r--r--chromium/components/tracing/proto/BUILD.gn37
-rw-r--r--chromium/components/tracing/proto/event.proto35
-rw-r--r--chromium/components/tracing/proto/events_chunk.proto36
-rw-r--r--chromium/components/tracing/tools/proto_zero_plugin/BUILD.gn16
-rw-r--r--chromium/components/tracing/tools/proto_zero_plugin/DEPS3
-rw-r--r--chromium/components/tracing/tools/proto_zero_plugin/proto_zero_generator.cc660
-rw-r--r--chromium/components/tracing/tools/proto_zero_plugin/proto_zero_generator.h30
-rw-r--r--chromium/components/tracing/tools/proto_zero_plugin/proto_zero_plugin.cc12
-rw-r--r--chromium/components/tracing_nacl.gyp52
-rw-r--r--chromium/components/translate.gypi249
-rw-r--r--chromium/components/translate/content/browser/BUILD.gn7
-rw-r--r--chromium/components/translate/content/common/BUILD.gn18
-rw-r--r--chromium/components/translate/content/common/translate.mojom65
-rw-r--r--chromium/components/translate/content/common/translate.typemap23
-rw-r--r--chromium/components/translate/content/renderer/BUILD.gn4
-rw-r--r--chromium/components/translate/core/browser/BUILD.gn15
-rw-r--r--chromium/components/translate/core/browser/proto/BUILD.gn11
-rw-r--r--chromium/components/translate/core/common/BUILD.gn2
-rw-r--r--chromium/components/translate/core/language_detection/BUILD.gn4
-rw-r--r--chromium/components/typemaps.gni2
-rw-r--r--chromium/components/undo.gypi33
-rw-r--r--chromium/components/undo/undo_manager_test.cc2
-rw-r--r--chromium/components/update_client.gypi98
-rw-r--r--chromium/components/update_client/BUILD.gn11
-rw-r--r--chromium/components/update_client/action.cc39
-rw-r--r--chromium/components/update_client/action.h1
-rw-r--r--chromium/components/update_client/action_update.cc4
-rw-r--r--chromium/components/update_client/action_update_check.cc11
-rw-r--r--chromium/components/update_client/action_wait.cc2
-rw-r--r--chromium/components/update_client/background_downloader_win.cc13
-rw-r--r--chromium/components/update_client/background_downloader_win.h6
-rw-r--r--chromium/components/update_client/component_patcher.h2
-rw-r--r--chromium/components/update_client/component_patcher_operation.cc6
-rw-r--r--chromium/components/update_client/component_patcher_unittest.cc37
-rw-r--r--chromium/components/update_client/configurator.h21
-rw-r--r--chromium/components/update_client/crx_update_item.h10
-rw-r--r--chromium/components/update_client/persisted_data.cc85
-rw-r--r--chromium/components/update_client/persisted_data.h20
-rw-r--r--chromium/components/update_client/persisted_data_unittest.cc38
-rw-r--r--chromium/components/update_client/ping_manager.cc8
-rw-r--r--chromium/components/update_client/request_sender.cc4
-rw-r--r--chromium/components/update_client/request_sender_unittest.cc1
-rw-r--r--chromium/components/update_client/test_configurator.cc35
-rw-r--r--chromium/components/update_client/test_configurator.h24
-rw-r--r--chromium/components/update_client/test_installer.cc2
-rw-r--r--chromium/components/update_client/test_installer.h2
-rw-r--r--chromium/components/update_client/update_checker.cc59
-rw-r--r--chromium/components/update_client/update_checker.h1
-rw-r--r--chromium/components/update_client/update_checker_unittest.cc128
-rw-r--r--chromium/components/update_client/update_client.cc10
-rw-r--r--chromium/components/update_client/update_client.h11
-rw-r--r--chromium/components/update_client/update_client_internal.h2
-rw-r--r--chromium/components/update_client/update_client_unittest.cc305
-rw-r--r--chromium/components/update_client/update_engine.cc12
-rw-r--r--chromium/components/update_client/update_engine.h6
-rw-r--r--chromium/components/update_client/update_response.cc37
-rw-r--r--chromium/components/update_client/update_response.h11
-rw-r--r--chromium/components/update_client/update_response_unittest.cc55
-rw-r--r--chromium/components/update_client/url_fetcher_downloader.cc7
-rw-r--r--chromium/components/update_client/url_fetcher_downloader.h5
-rw-r--r--chromium/components/update_client/utils.cc41
-rw-r--r--chromium/components/update_client/utils.h5
-rw-r--r--chromium/components/update_client/utils_unittest.cc25
-rw-r--r--chromium/components/upload_list.gypi25
-rw-r--r--chromium/components/upload_list/BUILD.gn2
-rw-r--r--chromium/components/upload_list/crash_upload_list.cc16
-rw-r--r--chromium/components/upload_list/crash_upload_list.h6
-rw-r--r--chromium/components/upload_list/upload_list.cc69
-rw-r--r--chromium/components/upload_list/upload_list.h40
-rw-r--r--chromium/components/upload_list/upload_list_unittest.cc35
-rw-r--r--chromium/components/url_formatter/BUILD.gn15
-rw-r--r--chromium/components/url_formatter/DEPS1
-rw-r--r--chromium/components/url_formatter/android/BUILD.gn23
-rw-r--r--chromium/components/url_formatter/elide_url.cc15
-rw-r--r--chromium/components/url_formatter/elide_url.h8
-rw-r--r--chromium/components/url_formatter/elide_url_unittest.cc4
-rw-r--r--chromium/components/url_formatter/url_fixer.cc5
-rw-r--r--chromium/components/url_formatter/url_fixer_unittest.cc52
-rw-r--r--chromium/components/url_formatter/url_formatter.cc7
-rw-r--r--chromium/components/url_formatter/url_formatter.gyp39
-rw-r--r--chromium/components/url_formatter/url_formatter.h3
-rw-r--r--chromium/components/url_formatter/url_formatter_android.cc77
-rw-r--r--chromium/components/url_formatter/url_formatter_android.h20
-rw-r--r--chromium/components/url_matcher.gypi43
-rw-r--r--chromium/components/url_matcher/regex_set_matcher.cc2
-rw-r--r--chromium/components/url_matcher/regex_set_matcher_unittest.cc10
-rw-r--r--chromium/components/url_matcher/url_matcher.cc42
-rw-r--r--chromium/components/url_matcher/url_matcher_factory.cc4
-rw-r--r--chromium/components/user_manager.gypi84
-rw-r--r--chromium/components/user_manager/OWNERS1
-rw-r--r--chromium/components/user_manager/known_user.cc3
-rw-r--r--chromium/components/user_manager/user_manager_base.cc8
-rw-r--r--chromium/components/user_prefs.gypi101
-rw-r--r--chromium/components/user_prefs/tracked/BUILD.gn9
-rw-r--r--chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc127
-rw-r--r--chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h22
-rw-r--r--chromium/components/user_prefs/tracked/hash_store_contents.h73
-rw-r--r--chromium/components/user_prefs/tracked/mock_validation_delegate.cc27
-rw-r--r--chromium/components/user_prefs/tracked/mock_validation_delegate.h29
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc7
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_filter.cc172
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_filter.h37
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc360
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_store.h22
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_store_impl.cc153
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_store_impl.h20
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc106
-rw-r--r--chromium/components/user_prefs/tracked/pref_hash_store_transaction.h8
-rw-r--r--chromium/components/user_prefs/tracked/pref_service_hash_store_contents.cc146
-rw-r--r--chromium/components/user_prefs/tracked/pref_service_hash_store_contents.h72
-rw-r--r--chromium/components/user_prefs/tracked/pref_service_hash_store_contents_unittest.cc152
-rw-r--r--chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc182
-rw-r--r--chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h49
-rw-r--r--chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc119
-rw-r--r--chromium/components/user_prefs/tracked/segregated_pref_store.cc10
-rw-r--r--chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc12
-rw-r--r--chromium/components/user_prefs/tracked/tracked_atomic_preference.cc34
-rw-r--r--chromium/components/user_prefs/tracked/tracked_atomic_preference.h7
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference.h12
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference_helper.cc72
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference_helper.h5
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc1
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h1
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h3
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preferences_migration.cc58
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preferences_migration.h12
-rw-r--r--chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc255
-rw-r--r--chromium/components/user_prefs/tracked/tracked_split_preference.cc41
-rw-r--r--chromium/components/user_prefs/tracked/tracked_split_preference.h7
-rw-r--r--chromium/components/variations.gypi179
-rw-r--r--chromium/components/variations/BUILD.gn3
-rw-r--r--chromium/components/variations/android/BUILD.gn1
-rw-r--r--chromium/components/variations/android/variations_associated_data_android.cc2
-rw-r--r--chromium/components/variations/android/variations_seed_bridge.cc12
-rw-r--r--chromium/components/variations/android/variations_seed_bridge.h2
-rw-r--r--chromium/components/variations/entropy_provider_unittest.cc8
-rw-r--r--chromium/components/variations/net/BUILD.gn2
-rw-r--r--chromium/components/variations/processed_study.cc4
-rw-r--r--chromium/components/variations/service/BUILD.gn2
-rw-r--r--chromium/components/variations/service/variations_service.cc31
-rw-r--r--chromium/components/variations/service/variations_service_unittest.cc48
-rw-r--r--chromium/components/variations/study_filtering.cc8
-rw-r--r--chromium/components/variations/study_filtering_unittest.cc18
-rw-r--r--chromium/components/variations/variations_associated_data.cc28
-rw-r--r--chromium/components/variations/variations_associated_data.h38
-rw-r--r--chromium/components/variations/variations_associated_data_unittest.cc21
-rw-r--r--chromium/components/variations/variations_http_header_provider.cc30
-rw-r--r--chromium/components/variations/variations_http_header_provider.h17
-rw-r--r--chromium/components/variations/variations_http_header_provider_unittest.cc13
-rw-r--r--chromium/components/variations/variations_request_scheduler.cc2
-rw-r--r--chromium/components/variations/variations_seed_processor_unittest.cc23
-rw-r--r--chromium/components/variations/variations_seed_store.cc5
-rw-r--r--chromium/components/variations/variations_url_constants.cc7
-rw-r--r--chromium/components/version_info.gypi94
-rw-r--r--chromium/components/version_info/BUILD.gn10
-rw-r--r--chromium/components/version_ui.gypi27
-rw-r--r--chromium/components/version_ui/BUILD.gn2
-rw-r--r--chromium/components/version_ui/resources/about_version.html3
-rw-r--r--chromium/components/version_ui/version_ui_constants.cc1
-rw-r--r--chromium/components/visitedlink.gypi66
-rw-r--r--chromium/components/visitedlink/DEPS4
-rw-r--r--chromium/components/visitedlink/browser/BUILD.gn2
-rw-r--r--chromium/components/visitedlink/browser/visitedlink_event_listener.cc70
-rw-r--r--chromium/components/visitedlink/browser/visitedlink_event_listener.h27
-rw-r--r--chromium/components/visitedlink/browser/visitedlink_master.cc159
-rw-r--r--chromium/components/visitedlink/browser/visitedlink_master.h29
-rw-r--r--chromium/components/visitedlink/common/BUILD.gn17
-rw-r--r--chromium/components/visitedlink/common/OWNERS4
-rw-r--r--chromium/components/visitedlink/common/visitedlink.mojom22
-rw-r--r--chromium/components/visitedlink/common/visitedlink_message_generator.cc40
-rw-r--r--chromium/components/visitedlink/common/visitedlink_message_generator.h7
-rw-r--r--chromium/components/visitedlink/common/visitedlink_messages.h32
-rw-r--r--chromium/components/visitedlink/renderer/BUILD.gn2
-rw-r--r--chromium/components/visitedlink/renderer/visitedlink_slave.cc95
-rw-r--r--chromium/components/visitedlink/renderer/visitedlink_slave.h30
-rw-r--r--chromium/components/wallpaper.gypi47
-rw-r--r--chromium/components/wallpaper/wallpaper_manager_base.cc12
-rw-r--r--chromium/components/wallpaper/wallpaper_manager_base.h4
-rw-r--r--chromium/components/wallpaper/wallpaper_resizer.cc27
-rw-r--r--chromium/components/wallpaper/wallpaper_resizer.h10
-rw-r--r--chromium/components/wallpaper/wallpaper_resizer_unittest.cc18
-rw-r--r--chromium/components/web_cache.gypi48
-rw-r--r--chromium/components/web_cache/browser/BUILD.gn2
-rw-r--r--chromium/components/web_cache/renderer/BUILD.gn2
-rw-r--r--chromium/components/web_contents_delegate_android.gypi76
-rw-r--r--chromium/components/web_contents_delegate_android/BUILD.gn4
-rw-r--r--chromium/components/web_contents_delegate_android/OWNERS2
-rw-r--r--chromium/components/web_contents_delegate_android/color_chooser_android.cc15
-rw-r--r--chromium/components/web_contents_delegate_android/validation_message_bubble_android.cc28
-rw-r--r--chromium/components/web_contents_delegate_android/validation_message_bubble_android.h2
-rw-r--r--chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc140
-rw-r--r--chromium/components/web_contents_delegate_android/web_contents_delegate_android.h6
-rw-r--r--chromium/components/web_modal.gypi48
-rw-r--r--chromium/components/web_modal/web_contents_modal_dialog_manager.cc6
-rw-r--r--chromium/components/web_modal/web_contents_modal_dialog_manager.h9
-rw-r--r--chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc11
-rw-r--r--chromium/components/web_resource.gypi50
-rw-r--r--chromium/components/web_resource/BUILD.gn2
-rw-r--r--chromium/components/web_resource/promo_resource_service.cc31
-rw-r--r--chromium/components/web_resource/promo_resource_service.h33
-rw-r--r--chromium/components/web_resource/web_resource_pref_names.cc3
-rw-r--r--chromium/components/web_resource/web_resource_pref_names.h1
-rw-r--r--chromium/components/web_resource/web_resource_service.cc2
-rw-r--r--chromium/components/web_restrictions.gypi117
-rw-r--r--chromium/components/web_restrictions/BUILD.gn42
-rw-r--r--chromium/components/web_restrictions/browser/DEPS1
-rw-r--r--chromium/components/web_restrictions/browser/mock_web_restrictions_client.cc4
-rw-r--r--chromium/components/web_restrictions/browser/mock_web_restrictions_client.h2
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_client.cc187
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_client.h73
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_client_result.cc54
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_client_result.h36
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_client_unittest.cc56
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_mojo_implementation.cc69
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_mojo_implementation.h35
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_resource_throttle.cc2
-rw-r--r--chromium/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc16
-rw-r--r--chromium/components/web_restrictions/interfaces/OWNERS (renamed from chromium/components/mus/public/interfaces/OWNERS)0
-rw-r--r--chromium/components/web_restrictions/interfaces/web_restrictions.mojom22
-rw-r--r--chromium/components/web_restrictions/renderer/DEPS5
-rw-r--r--chromium/components/web_restrictions/renderer/web_restrictions_gin_wrapper.cc60
-rw-r--r--chromium/components/web_restrictions/renderer/web_restrictions_gin_wrapper.h46
-rw-r--r--chromium/components/webcrypto/BUILD.gn20
-rw-r--r--chromium/components/webcrypto/DEPS1
-rw-r--r--chromium/components/webcrypto/algorithm_dispatch.cc57
-rw-r--r--chromium/components/webcrypto/algorithm_implementation.cc92
-rw-r--r--chromium/components/webcrypto/algorithm_implementation.h143
-rw-r--r--chromium/components/webcrypto/algorithms/aes.cc40
-rw-r--r--chromium/components/webcrypto/algorithms/aes.h45
-rw-r--r--chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc4
-rw-r--r--chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc4
-rw-r--r--chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc7
-rw-r--r--chromium/components/webcrypto/algorithms/asymmetric_key_util.cc52
-rw-r--r--chromium/components/webcrypto/algorithms/asymmetric_key_util.h20
-rw-r--r--chromium/components/webcrypto/algorithms/ec.cc163
-rw-r--r--chromium/components/webcrypto/algorithms/ec.h50
-rw-r--r--chromium/components/webcrypto/algorithms/ecdh.cc15
-rw-r--r--chromium/components/webcrypto/algorithms/ecdh_unittest.cc2
-rw-r--r--chromium/components/webcrypto/algorithms/ecdsa.cc6
-rw-r--r--chromium/components/webcrypto/algorithms/hkdf.cc31
-rw-r--r--chromium/components/webcrypto/algorithms/hmac.cc64
-rw-r--r--chromium/components/webcrypto/algorithms/pbkdf2.cc30
-rw-r--r--chromium/components/webcrypto/algorithms/rsa.cc54
-rw-r--r--chromium/components/webcrypto/algorithms/rsa.h41
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc4
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc18
-rw-r--r--chromium/components/webcrypto/algorithms/secret_key_util.cc7
-rw-r--r--chromium/components/webcrypto/algorithms/secret_key_util.h5
-rw-r--r--chromium/components/webcrypto/algorithms/sha.cc2
-rw-r--r--chromium/components/webcrypto/algorithms/test_helpers.cc8
-rw-r--r--chromium/components/webcrypto/algorithms/util.cc10
-rw-r--r--chromium/components/webcrypto/algorithms/util.h11
-rw-r--r--chromium/components/webcrypto/ec_import_key_raw_fuzzer.cc15
-rw-r--r--chromium/components/webcrypto/fuzzer_support.cc61
-rw-r--r--chromium/components/webcrypto/fuzzer_support.h2
-rw-r--r--chromium/components/webcrypto/status.cc11
-rw-r--r--chromium/components/webcrypto/status.h7
-rw-r--r--chromium/components/webcrypto/webcrypto.gyp69
-rw-r--r--chromium/components/webcrypto/webcrypto_impl.cc110
-rw-r--r--chromium/components/webcrypto/webcrypto_impl.h30
-rw-r--r--chromium/components/webdata.gypi41
-rw-r--r--chromium/components/webdata/common/web_data_service_base.h3
-rw-r--r--chromium/components/webdata/common/web_database.cc5
-rw-r--r--chromium/components/webdata/common/web_database.h9
-rw-r--r--chromium/components/webdata/common/web_database_backend.cc75
-rw-r--r--chromium/components/webdata/common/web_database_backend.h28
-rw-r--r--chromium/components/webdata/common/web_database_migration_unittest.cc2
-rw-r--r--chromium/components/webdata/common/web_database_service.cc49
-rw-r--r--chromium/components/webdata/common/web_database_service.h16
-rw-r--r--chromium/components/webdata_services.gypi49
-rw-r--r--chromium/components/webdata_services/BUILD.gn4
-rw-r--r--chromium/components/webdata_services/DEPS2
-rw-r--r--chromium/components/webdata_services/web_data_service_wrapper.h11
-rw-r--r--chromium/components/webmessaging.gypi69
-rw-r--r--chromium/components/webmessaging/BUILD.gn17
-rw-r--r--chromium/components/webmessaging/DEPS3
-rw-r--r--chromium/components/webmessaging/OWNERS1
-rw-r--r--chromium/components/webmessaging/broadcast_channel_provider.cc115
-rw-r--r--chromium/components/webmessaging/broadcast_channel_provider.h46
-rw-r--r--chromium/components/webmessaging/public/interfaces/BUILD.gn14
-rw-r--r--chromium/components/webmessaging/public/interfaces/OWNERS2
-rw-r--r--chromium/components/webmessaging/public/interfaces/broadcast_channel.mojom34
-rw-r--r--chromium/components/webp_transcode.gypi26
-rw-r--r--chromium/components/webp_transcode/BUILD.gn52
-rw-r--r--chromium/components/webp_transcode/DEPS12
-rw-r--r--chromium/components/webp_transcode/OWNERS2
-rw-r--r--chromium/components/webp_transcode/README2
-rw-r--r--chromium/components/webp_transcode/webp_decoder.h78
-rw-r--r--chromium/components/webp_transcode/webp_decoder.mm252
-rw-r--r--chromium/components/webp_transcode/webp_decoder_unittest.mm291
-rw-r--r--chromium/components/webusb.gypi25
-rw-r--r--chromium/components/webusb/BUILD.gn38
-rw-r--r--chromium/components/webusb/DEPS5
-rw-r--r--chromium/components/webusb/OWNERS3
-rw-r--r--chromium/components/webusb/webusb_browser_client.h31
-rw-r--r--chromium/components/webusb/webusb_detector.cc56
-rw-r--r--chromium/components/webusb/webusb_detector.h46
-rw-r--r--chromium/components/webusb/webusb_detector_unittest.cc445
-rw-r--r--chromium/components/wifi.gypi81
-rw-r--r--chromium/components/wifi/BUILD.gn2
-rw-r--r--chromium/components/wifi_sync.gypi34
-rw-r--r--chromium/components/wifi_sync/BUILD.gn4
-rw-r--r--chromium/components/wifi_sync/DEPS6
-rw-r--r--chromium/components/wifi_sync/wifi_config_delegate_chromeos_unittest.cc2
-rw-r--r--chromium/components/wifi_sync/wifi_credential.cc2
-rw-r--r--chromium/components/wifi_sync/wifi_credential_syncable_service.cc13
-rw-r--r--chromium/components/wifi_sync/wifi_credential_syncable_service.h4
-rw-r--r--chromium/components/wifi_sync/wifi_credential_syncable_service_factory.cc4
-rw-r--r--chromium/components/wifi_sync/wifi_credential_syncable_service_unittest.cc19
-rw-r--r--chromium/components/wifi_sync/wifi_security_class.h2
-rw-r--r--chromium/components/zoom.gypi53
-rw-r--r--chromium/components/zoom/BUILD.gn4
-rw-r--r--chromium/components/zoom/page_zoom_constants.cc11
-rw-r--r--chromium/components/zoom/zoom_controller.cc2
3236 files changed, 124333 insertions, 149083 deletions
diff --git a/chromium/components/BUILD.gn b/chromium/components/BUILD.gn
index abf71d07af2..15071c3f5d0 100644
--- a/chromium/components/BUILD.gn
+++ b/chromium/components/BUILD.gn
@@ -57,17 +57,15 @@ test("components_unittests") {
deps = [
"//base",
"//base/test:test_support",
- "//components/auto_login_parser:unit_tests",
"//components/autofill/core/browser:unit_tests",
"//components/autofill/core/common:unit_tests",
"//components/base32:unit_tests",
"//components/bookmarks/browser:unit_tests",
"//components/bookmarks/managed:unit_tests",
- "//components/browser_sync/browser:unit_tests",
- "//components/browsing_data_ui:unit_tests",
+ "//components/browser_sync:unit_tests",
+ "//components/browsing_data/core:unit_tests",
"//components/bubble:unit_tests",
"//components/captive_portal:unit_tests",
- "//components/certificate_reporting:unit_tests",
"//components/client_update_protocol:unit_tests",
"//components/cloud_devices/common:unit_tests",
"//components/component_updater:unit_tests",
@@ -100,16 +98,22 @@ test("components_unittests") {
"//components/network_session_configurator:unit_tests",
"//components/network_time:unit_tests",
"//components/ntp_snippets:unit_tests",
+ "//components/ntp_tiles:unit_tests",
"//components/offline_pages:unit_tests",
"//components/offline_pages/background:unit_tests",
+ "//components/offline_pages/core:unit_tests",
+ "//components/offline_pages/downloads:unit_tests",
+ "//components/offline_pages/request_header:unit_tests",
"//components/omnibox/browser:unit_tests",
"//components/open_from_clipboard:unit_tests",
"//components/os_crypt:unit_tests",
"//components/password_manager/core/browser:unit_tests",
"//components/password_manager/core/common:unit_tests",
"//components/password_manager/sync/browser:unit_tests",
+ "//components/physical_web/data_source:unit_tests",
"//components/precache/core:unit_tests",
"//components/prefs:unit_tests",
+ "//components/previews/core:unit_tests",
"//components/proxy_config:unit_tests",
"//components/query_parser:unit_tests",
"//components/rappor:unit_tests",
@@ -125,8 +129,8 @@ test("components_unittests") {
"//components/subresource_filter/core/common:unit_tests",
"//components/suggestions:unit_tests",
"//components/supervised_user_error_page:unit_tests",
+ "//components/sync:unit_tests",
"//components/sync_bookmarks:unit_tests",
- "//components/sync_driver:unit_tests",
"//components/sync_sessions:unit_tests",
"//components/syncable_prefs:unit_tests",
"//components/translate/core/browser:unit_tests",
@@ -161,23 +165,19 @@ test("components_unittests") {
"//components/signin/ios/browser:unit_tests",
"//components/translate/ios/browser:unit_tests",
]
-
- if (current_cpu != "arm") {
- # TODO(GYP): iOS arm builds of libwebp don't work yet.
- deps += [ "//components/webp_transcode:unit_tests" ]
- }
} else { # !iOS
deps += [
"//components/autofill/content/browser:unit_tests",
"//components/autofill/content/public/cpp:unit_tests",
"//components/autofill/content/renderer:unit_tests",
"//components/cast_certificate:unit_tests",
+ "//components/certificate_reporting:unit_tests",
"//components/certificate_transparency:unit_tests",
+ "//components/contextual_search:unit_tests",
"//components/crash/content/app:unit_tests",
"//components/crash/core/common:unit_tests",
"//components/data_reduction_proxy/content/browser:unit_tests",
"//components/data_use_measurement/content:unit_tests",
- "//components/devtools_http_handler:unit_tests",
"//components/display_compositor:unit_tests",
"//components/dom_distiller/content/browser:unit_tests",
"//components/domain_reliability:unit_tests",
@@ -189,21 +189,18 @@ test("components_unittests") {
"//components/invalidation/impl:unit_tests",
"//components/keyed_service/content:unit_tests",
"//components/link_header_util:unit_tests",
- "//components/memory_coordinator/child:unit_tests",
"//components/navigation_interception:unit_tests",
"//components/network_hints/renderer:unit_tests",
- "//components/ntp_tiles:unit_tests",
"//components/packed_ct_ev_whitelist:unit_tests",
- "//components/page_load_metrics/browser:unit_tests",
- "//components/page_load_metrics/renderer:unit_tests",
"//components/password_manager/content/browser:unit_tests",
"//components/power:unit_tests",
"//components/precache/content:unit_tests",
"//components/safe_browsing_db:unit_tests",
"//components/safe_json:unit_tests",
- "//components/scheduler:unit_tests",
+ "//components/spellcheck/browser:unit_tests",
+ "//components/spellcheck/renderer:unit_tests",
"//components/subresource_filter/content/browser:unit_tests",
- "//components/test_runner:test_runner",
+ "//components/subresource_filter/content/renderer:unit_tests",
"//components/tracing:unit_tests",
"//components/visitedlink/test:unit_tests",
"//components/wallpaper:unit_tests",
@@ -212,7 +209,7 @@ test("components_unittests") {
"//components/zoom:unit_tests",
# These are the deps required by the code in this target.
- "//components/policy:policy_component",
+ "//components/policy/core/browser",
"//content/test:test_support",
"//ui/gl:test_support",
]
@@ -228,7 +225,7 @@ test("components_unittests") {
deps += [ ":components_tests_pak_bundle_data" ]
}
- if (is_mac) {
+ if (is_mac || is_linux) {
data_deps += [ "//content/shell:pak" ]
}
@@ -243,6 +240,7 @@ test("components_unittests") {
"//components/safe_json/android:safe_json_java",
"//components/signin/core/browser",
"//components/signin/core/browser/android:java",
+ "//components/spellcheck/browser/android:java",
"//components/variations/android:variations_java",
"//components/web_restrictions:test_support",
"//components/web_restrictions:test_support_java",
@@ -253,6 +251,7 @@ test("components_unittests") {
"//ui/android:ui_java",
"//ui/base",
"//ui/gfx",
+ "//v8:v8_external_startup_data_assets",
]
if (enable_configuration_policy) {
@@ -263,13 +262,10 @@ test("components_unittests") {
# Desktop-only deps.
if (!is_android && !is_ios) {
deps += [
- "//components/audio_modem:unit_tests",
- "//components/copresence:unit_tests",
"//components/feedback:unit_tests",
"//components/proximity_auth:unit_tests",
"//components/storage_monitor:unit_tests",
"//components/web_modal:unit_tests",
- "//components/webusb:unit_tests",
]
}
@@ -378,7 +374,6 @@ if (is_android) {
custom_package = "org.chromium.components_browsertests_apk"
}
- # GYP: //components/components_tests.gyp:components_junit_tests
# TODO(GYP_GONE): Delete this target once recipes no longer require it.
junit_binary("components_junit_tests") {
java_files = [ "//testing/android/junit/DummyTest.java" ]
@@ -422,10 +417,10 @@ if (!is_ios) {
"//components/strings",
"//components/tracing",
"//content/shell:content_shell_lib",
- "//content/test:browsertest_base",
"//content/test:browsertest_support",
"//content/test:test_support",
"//device/bluetooth",
+ "//device/geolocation",
"//ipc:test_support",
"//net:test_support",
"//services/shell/public/cpp",
@@ -480,9 +475,6 @@ if (!is_ios) {
test("components_perftests") {
sources = [
- "scheduler/base/task_queue_manager_delegate_for_test.cc",
- "scheduler/base/task_queue_manager_delegate_for_test.h",
- "scheduler/base/task_queue_manager_perftest.cc",
"visitedlink/test/visitedlink_perftest.cc",
]
@@ -492,10 +484,9 @@ if (!is_ios) {
deps = [
"//base",
"//base/test:test_support",
- "//base/test:test_support_perf",
- "//components/scheduler",
"//components/visitedlink/browser",
"//content/test:test_support",
+ "//mojo/edk/test:run_all_perftests",
"//testing/gtest",
"//testing/perf",
"//url",
diff --git a/chromium/components/OWNERS b/chromium/components/OWNERS
index eb164853d31..ea727790c91 100644
--- a/chromium/components/OWNERS
+++ b/chromium/components/OWNERS
@@ -10,8 +10,6 @@ per-file app_modal_strings.grdp=file://components/app_modal/OWNERS
per-file arc.gypi=file://components/arc/OWNERS
-per-file audio_modem.gypi=file://components/audio_modem/OWNERS
-
per-file autofill.gypi=file://components/autofill/OWNERS
per-file autofill_strings.grdp=file://components/autofill/OWNERS
@@ -20,6 +18,7 @@ per-file bookmarks.gypi=file://components/bookmarks/OWNERS
per-file browser_sync.gypi=file://components/browser_sync/OWNERS
+per-file browsing_data_strings.grdp=file://components/browsing_data/OWNERS
per-file browsing_data.gypi=file://components/browsing_data/OWNERS
per-file bubble.gypi=file://components/bubble/OWNERS
@@ -30,8 +29,6 @@ per-file cdm.gypi=file://components/cdm/OWNERS
per-file certificate_transparency.gypi=file://components/certificate_transparency/OWNERS
-per-file chooser_controller.gypi=file://components/chooser_controller/OWNERS
-
per-file chrome_apps.gypi=file://components/chrome_apps/OWNERS
per-file cloud_devices.gypi=file://components/cloud_devices/OWNERS
@@ -42,13 +39,11 @@ per-file constrained_window.gypi=file://components/constrained_window/OWNERS
per-file content_settings.gypi=file://components/content_settings/OWNERS
-per-file copresence.gypi=file://components/copresence/OWNERS
+per-file contextual_search.gypi=file://components/contextual_search/OWNERS
per-file crash.gypi=file://components/crash/OWNERS
per-file crash_strings.grdp=file://components/crash/OWNERS
-per-file cronet.gypi=file://components/cronet/OWNERS
-
per-file data_reduction_proxy.gypi=file://components/data_reduction_proxy/OWNERS
per-file data_usage.gypi=file://components/data_usage/OWNERS
@@ -57,10 +52,6 @@ per-file data_use_measurement.gypi=file://components/data_use_measurement/OWNERS
per-file device_event_log.gypi=file://components/device_event_log/OWNERS
-per-file devtools_discovery.gypi=file://components/devtools_discovery/OWNERS
-
-per-file devtools_http_handler.gypi=file://components/devtools_http_handler/OWNERS
-
per-file display_compositor.gypi=file://components/display_compositor/OWNERS
per-file dom_distiller.gypi=file://components/dom_distiller/OWNERS
@@ -75,8 +66,6 @@ per-file error_page_strings.grdp=file://components/error_page/OWNERS
per-file exo.gypi=file://components/exo/OWNERS
-per-file external_video_surface.gypi=file://components/external_video_surface/OWNERS
-
per-file favicon.gypi=file://components/favicon/OWNERS
per-file favicon_base.gypi=file://components/favicon_base/OWNERS
@@ -106,7 +95,6 @@ per-file leveldb_proto.gypi=file://components/leveldb_proto/OWNERS
per-file login.gypi=file://components/login/OWNERS
-per-file memory_coordinator.gypi=file://components/memory_coordinator/OWNERS
per-file memory_pressure.gypi=file://components/memory_pressure/OWNERS
per-file metrics.gypi=file://components/metrics/OWNERS
@@ -133,6 +121,7 @@ per-file ntp_tiles.gypi=file://components/ntp_tiles/OWNERS
per-file offline_pages.gypi=file://components/offline_pages/OWNERS
per-file omnibox.gypi=file://components/omnibox/OWNERS
+per-file omnibox_strings.grdp=file://components/omnibox/OWNERS
per-file onc.gypi=file://components/onc/OWNERS
@@ -144,8 +133,6 @@ per-file ownership.gypi=file://components/ownership/OWNERS
per-file packed_ct_ev_whitelist.gypi=file://components/packed_ct_ev_whitelist/OWNERS
-per-file page_load_metrics.gypi=file://components/page_load_metrics/OWNERS
-
per-file pairing.gypi=file://components/pairing/OWNERS
per-file password_manager.gypi=file://components/password_manager/OWNERS
@@ -162,6 +149,8 @@ per-file policy_strings.grdp=file://components/policy/OWNERS
per-file precache.gypi=file://components/precache/OWNERS
+per-file previews.gypi=file://components/previews/OWNERS
+
per-file printing.gypi=file://components/printing/OWNERS
per-file profile_metrics.gypi=file://components/profile_metrics/OWNERS
@@ -197,6 +186,8 @@ per-file sessions.gypi=file://components/sessions/OWNERS
per-file signin.gypi=file://components/signin/OWNERS
+per-file spellcheck.gypi=file://components/spellcheck/OWNERS
+
per-file ssl_errors.gypi=file://components/ssl_errors/OWNERS
per-file ssl_errors_strings.grdp=file://components/ssl_errors/OWNERS
@@ -211,10 +202,12 @@ per-file suggestions.gypi=file://components/suggestions/OWNERS
per-file supervised_user_error_page.gypi=file://components/supervised_user_error_page/OWNERS
per-file supervised_user_error_page_strings.grdp=file://components/supervised_user_error_page/OWNERS
-per-file sync_driver.gypi=file://components/sync_driver/OWNERS
+per-file sync.gyp=file://components/sync/OWNERS
per-file sync_sessions.gypi=file://components/sync_sessions/OWNERS
+per-file sync_ui_strings.grdp=file://components/sync/OWNERS
+
per-file timers.gypi=file://components/timers/OWNERS
per-file tracing.gyp=file://components/tracing/OWNERS
@@ -249,12 +242,6 @@ per-file web_restrictions.gypi=file://components/web_restrictions/OWNERS
per-file webdata.gypi=file://components/webdata/OWNERS
per-file webdata_services.gypi=file://components/webdata_services/OWNERS
-per-file webmessaging.gypi=file://components/webmessaging/OWNERS
-
-per-file webp_transcode.gypi=file://components/webp_transcode/OWNERS
-
-per-file webusb.gypi=file://components/webusb/OWNERS
-
per-file wifi.gypi=file://components/wifi/OWNERS
per-file *.isolate=maruel@chromium.org
diff --git a/chromium/components/README b/chromium/components/README
index 8112f6e25d7..b3bb2ffb652 100644
--- a/chromium/components/README
+++ b/chromium/components/README
@@ -1,8 +1,17 @@
-This directory is for features that are intended for reuse across multiple
-embedders (e.g., Android WebView and Chrome).
+This directory is for features that are intended for reuse. Example use cases:
+-code that is shared by Chrome on iOS and other Chrome platforms (since the iOS
+ port doesn't use src/chrome)
+-code that is shared between multiple embedders of content (e.g., Android
+ WebView and Chrome)
+-code that is shared between Blink and the browser process (since code in the
+ browser doesn't use Blink, while Blink doesn't include content or chrome to
+ avoid circular dependencies)
+
+In general, if some code is used by a directory "foo" and things above "foo" in
+the dependency tree, the code should probably live in "foo".
By default, components can depend only on the lower layers of the Chromium
-codebase(e.g. base/, net/, etc.). Individual components may additionally allow
+codebase (e.g. base/, net/, etc.). Individual components may additionally allow
dependencies on the content API and IPC; however, if such a component is used
by Chrome for iOS (which does not use the content API or IPC), the component
will have to be in the form of a layered component
diff --git a/chromium/components/about_handler.gypi b/chromium/components/about_handler.gypi
deleted file mode 100644
index fce5b8c8b55..00000000000
--- a/chromium/components/about_handler.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/about_handler
- 'target_name': 'about_handler',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'about_handler/about_protocol_handler.cc',
- 'about_handler/about_protocol_handler.h',
- 'about_handler/url_request_about_job.cc',
- 'about_handler/url_request_about_job.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/about_handler/BUILD.gn b/chromium/components/about_handler/BUILD.gn
index eeaff47f027..d1450023996 100644
--- a/chromium/components/about_handler/BUILD.gn
+++ b/chromium/components/about_handler/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("about_handler") {
+static_library("about_handler") {
sources = [
"about_protocol_handler.cc",
"about_protocol_handler.h",
diff --git a/chromium/components/app_modal.gypi b/chromium/components/app_modal.gypi
deleted file mode 100644
index 045b1ec219a..00000000000
--- a/chromium/components/app_modal.gypi
+++ /dev/null
@@ -1,47 +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.
-{
- 'targets': [
- {
- 'target_name': 'app_modal',
- 'type': 'static_library',
- 'dependencies': [
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../skia/skia.gyp:skia',
- 'components_strings.gyp:components_strings',
- 'url_formatter/url_formatter.gyp:url_formatter',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'app_modal/app_modal_dialog.cc',
- 'app_modal/app_modal_dialog.h',
- 'app_modal/app_modal_dialog_queue.cc',
- 'app_modal/app_modal_dialog_queue.h',
- 'app_modal/javascript_app_modal_dialog.cc',
- 'app_modal/javascript_app_modal_dialog.h',
- 'app_modal/javascript_dialog_extensions_client.h',
- 'app_modal/javascript_dialog_manager.cc',
- 'app_modal/javascript_dialog_manager.h',
- 'app_modal/javascript_native_dialog_factory.h',
- 'app_modal/native_app_modal_dialog.h'
- ],
- 'conditions': [
- ['use_aura==1',{
- 'dependencies': [
- '../ui/aura/aura.gyp:aura',
- ],
- }],
- ['toolkit_views==1', {
- 'sources': [
- 'app_modal/views/javascript_app_modal_dialog_views.cc',
- 'app_modal/views/javascript_app_modal_dialog_views.h',
- ],
- }],
- ],
- },
- ],
-}
diff --git a/chromium/components/arc.gypi b/chromium/components/arc.gypi
deleted file mode 100644
index bb3ab9e65d4..00000000000
--- a/chromium/components/arc.gypi
+++ /dev/null
@@ -1,247 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/arc
- 'target_name': 'arc',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'arc_base',
- 'arc_mojo_bindings',
- 'components.gyp:exo',
- 'components.gyp:onc_component',
- '../base/base.gyp:base',
- '../chromeos/chromeos.gyp:chromeos',
- '../chromeos/chromeos.gyp:power_manager_proto',
- '../device/bluetooth/bluetooth.gyp:device_bluetooth',
- '../ipc/ipc.gyp:ipc',
- '../third_party/re2/re2.gyp:re2',
- '../skia/skia.gyp:skia',
- '../ui/arc/arc.gyp:arc',
- '../ui/aura/aura.gyp:aura',
- '../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/base/ui_base.gyp:ui_base_test_support',
- '../ui/events/events.gyp:events_base',
- '../ui/keyboard/keyboard.gyp:keyboard',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'arc/arc_bridge_bootstrap.cc',
- 'arc/arc_bridge_bootstrap.h',
- 'arc/arc_bridge_service_impl.cc',
- 'arc/arc_bridge_service_impl.h',
- 'arc/arc_service_manager.cc',
- 'arc/arc_service_manager.h',
- 'arc/audio/arc_audio_bridge.cc',
- 'arc/audio/arc_audio_bridge.h',
- 'arc/bluetooth/arc_bluetooth_bridge.cc',
- 'arc/bluetooth/arc_bluetooth_bridge.h',
- 'arc/bluetooth/bluetooth_type_converters.cc',
- 'arc/bluetooth/bluetooth_type_converters.h',
- 'arc/clipboard/arc_clipboard_bridge.cc',
- 'arc/clipboard/arc_clipboard_bridge.h',
- 'arc/crash_collector/arc_crash_collector_bridge.cc',
- 'arc/crash_collector/arc_crash_collector_bridge.h',
- 'arc/ime/arc_ime_bridge.h',
- 'arc/ime/arc_ime_bridge_impl.cc',
- 'arc/ime/arc_ime_bridge_impl.h',
- 'arc/ime/arc_ime_service.cc',
- 'arc/ime/arc_ime_service.h',
- 'arc/instance_holder.h',
- 'arc/intent_helper/activity_icon_loader.cc',
- 'arc/intent_helper/activity_icon_loader.h',
- 'arc/intent_helper/arc_intent_helper_bridge.cc',
- 'arc/intent_helper/arc_intent_helper_bridge.h',
- 'arc/intent_helper/font_size_util.cc',
- 'arc/intent_helper/font_size_util.h',
- 'arc/intent_helper/intent_filter.cc',
- 'arc/intent_helper/intent_filter.h',
- 'arc/intent_helper/link_handler_model_impl.cc',
- 'arc/intent_helper/link_handler_model_impl.h',
- 'arc/intent_helper/local_activity_resolver.cc',
- 'arc/intent_helper/local_activity_resolver.h',
- 'arc/metrics/arc_metrics_service.cc',
- 'arc/metrics/arc_metrics_service.h',
- 'arc/metrics/oom_kills_histogram.h',
- 'arc/metrics/oom_kills_monitor.cc',
- 'arc/metrics/oom_kills_monitor.h',
- 'arc/net/arc_net_host_impl.cc',
- 'arc/net/arc_net_host_impl.h',
- 'arc/obb_mounter/arc_obb_mounter_bridge.cc',
- 'arc/obb_mounter/arc_obb_mounter_bridge.h',
- 'arc/power/arc_power_bridge.cc',
- 'arc/power/arc_power_bridge.h',
- 'arc/set_wallpaper_delegate.h',
- 'arc/storage_manager/arc_storage_manager.cc',
- 'arc/storage_manager/arc_storage_manager.h',
- 'arc/user_data/arc_user_data_service.cc',
- 'arc/user_data/arc_user_data_service.h',
- 'arc/window_manager/arc_window_manager_bridge.cc',
- 'arc/window_manager/arc_window_manager_bridge.h',
- ],
- },
- {
- # GN version: //components/arc:arc_base
- 'target_name': 'arc_base',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../chromeos/chromeos.gyp:chromeos',
- ],
- 'sources': [
- 'arc/arc_bridge_service.cc',
- 'arc/arc_bridge_service.h',
- 'arc/arc_service.cc',
- 'arc/arc_service.h',
- ],
- },
- {
- # GN version: //components/arc:arc_bitmap
- 'target_name': 'arc_bitmap',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'arc_mojo_bindings',
- '../skia/skia.gyp:skia',
- ],
- 'sources': [
- 'arc/bitmap/bitmap_type_converters.cc',
- 'arc/bitmap/bitmap_type_converters.h',
- ],
- },
- {
- # GN version: //components/arc_test_support
- 'target_name': 'arc_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'arc',
- 'arc_mojo_bindings',
- ],
- 'sources': [
- 'arc/test/fake_app_instance.cc',
- 'arc/test/fake_app_instance.h',
- 'arc/test/fake_arc_bridge_bootstrap.cc',
- 'arc/test/fake_arc_bridge_bootstrap.h',
- 'arc/test/fake_arc_bridge_instance.cc',
- 'arc/test/fake_arc_bridge_instance.h',
- 'arc/test/fake_arc_bridge_service.cc',
- 'arc/test/fake_arc_bridge_service.h',
- 'arc/test/fake_notifications_instance.cc',
- 'arc/test/fake_notifications_instance.h',
- 'arc/test/fake_policy_instance.cc',
- 'arc/test/fake_policy_instance.h',
- ],
- },
- {
- # GN version: //components/arc:mojo_bindings
- 'target_name': 'arc_mojo_bindings',
- 'type': 'static_library',
- 'variables': {
- 'mojom_typemaps': [
- 'arc/common/app.typemap',
- 'arc/common/bluetooth.typemap',
- '../mojo/common/common_custom_types.typemap',
- ],
- },
- 'sources': [
- 'arc/common/app.mojom',
- 'arc/common/arc_bridge.mojom',
- 'arc/common/audio.mojom',
- 'arc/common/auth.mojom',
- 'arc/common/bitmap.mojom',
- 'arc/common/bluetooth.mojom',
- 'arc/common/clipboard.mojom',
- 'arc/common/crash_collector.mojom',
- 'arc/common/enterprise_reporting.mojom',
- 'arc/common/file_system.mojom',
- 'arc/common/ime.mojom',
- 'arc/common/intent_helper.mojom',
- 'arc/common/metrics.mojom',
- 'arc/common/net.mojom',
- 'arc/common/notifications.mojom',
- 'arc/common/obb_mounter.mojom',
- 'arc/common/policy.mojom',
- 'arc/common/power.mojom',
- 'arc/common/process.mojom',
- 'arc/common/scale_factor.mojom',
- 'arc/common/screen_rect.mojom',
- 'arc/common/storage_manager.mojom',
- 'arc/common/video.mojom',
- 'arc/common/video_accelerator.mojom',
- 'arc/common/window_manager.mojom',
- 'arc/common/app_struct_traits.cc',
- ],
- 'includes': [ '../mojo/mojom_bindings_generator.gypi' ],
- 'dependencies': [
- '../ui/gfx/gfx.gyp:gfx_geometry',
- '../mojo/mojo_base.gyp:mojo_common_custom_types_mojom',
- ],
- },
- {
- # GN version: //components/arc:arc_standalone_service
- 'target_name': 'arc_standalone_service',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../ipc/ipc.gyp:ipc',
- '../mojo/mojo_edk.gyp:mojo_system_impl',
- ],
- 'sources': [
- 'arc/standalone/service_helper.cc',
- 'arc/standalone/service_helper.h',
- ],
- },
- {
- # GN version: //components/arc:arc_standalone
- 'target_name': 'arc_standalone',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'arc',
- '../base/base.gyp:base',
- '../ipc/ipc.gyp:ipc',
- '../mojo/mojo_edk.gyp:mojo_system_impl',
- ],
- 'sources': [
- 'arc/standalone/arc_standalone_bridge_runner.cc',
- 'arc/standalone/arc_standalone_bridge_runner.h',
- ]
- },
- {
- # GN version: //components/arc:arc_standalone_bridge
- 'target_name': 'arc_standalone_bridge',
- 'type': 'executable',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'arc_standalone',
- 'arc_standalone_service',
- '../base/base.gyp:base',
- '../ipc/ipc.gyp:ipc',
- '../mojo/mojo_edk.gyp:mojo_system_impl',
- ],
- 'sources': [
- 'arc/standalone/arc_standalone_bridge_main.cc',
- ]
- }
- ],
-}
diff --git a/chromium/components/arc/BUILD.gn b/chromium/components/arc/BUILD.gn
index 8b190f8a69f..d1e3d7b9978 100644
--- a/chromium/components/arc/BUILD.gn
+++ b/chromium/components/arc/BUILD.gn
@@ -9,17 +9,24 @@ static_library("arc") {
sources = [
"arc_bridge_bootstrap.cc",
"arc_bridge_bootstrap.h",
+ "arc_bridge_host_impl.cc",
+ "arc_bridge_host_impl.h",
"arc_bridge_service_impl.cc",
"arc_bridge_service_impl.h",
+ "arc_features.cc",
+ "arc_features.h",
"arc_service_manager.cc",
"arc_service_manager.h",
"audio/arc_audio_bridge.cc",
"audio/arc_audio_bridge.h",
"bluetooth/arc_bluetooth_bridge.cc",
"bluetooth/arc_bluetooth_bridge.h",
+ "bluetooth/bluetooth_struct_traits.cc",
"bluetooth/bluetooth_struct_traits.h",
"bluetooth/bluetooth_type_converters.cc",
"bluetooth/bluetooth_type_converters.h",
+ "boot_phase_monitor/arc_boot_phase_monitor_bridge.cc",
+ "boot_phase_monitor/arc_boot_phase_monitor_bridge.h",
"clipboard/arc_clipboard_bridge.cc",
"clipboard/arc_clipboard_bridge.h",
"crash_collector/arc_crash_collector_bridge.cc",
@@ -52,17 +59,18 @@ static_library("arc") {
"obb_mounter/arc_obb_mounter_bridge.h",
"power/arc_power_bridge.cc",
"power/arc_power_bridge.h",
- "set_wallpaper_delegate.h",
"storage_manager/arc_storage_manager.cc",
"storage_manager/arc_storage_manager.h",
"user_data/arc_user_data_service.cc",
"user_data/arc_user_data_service.h",
- "window_manager/arc_window_manager_bridge.cc",
- "window_manager/arc_window_manager_bridge.h",
]
- deps = [
+ public_deps = [
":arc_base",
+ ":arc_bindings",
+ ]
+
+ deps = [
"//ash:ash",
"//base",
"//chromeos",
@@ -89,10 +97,6 @@ static_library("arc") {
"//ui/keyboard:keyboard",
"//url:url",
]
-
- public_deps = [
- ":arc_bindings",
- ]
}
static_library("arc_base") {
@@ -114,21 +118,6 @@ static_library("arc_base") {
]
}
-static_library("arc_bitmap") {
- sources = [
- "bitmap/bitmap_type_converters.cc",
- "bitmap/bitmap_type_converters.h",
- ]
-
- deps = [
- "//skia",
- ]
-
- public_deps = [
- ":arc_bindings",
- ]
-}
-
mojom("arc_bindings") {
sources = [
"common/app.mojom",
@@ -137,6 +126,7 @@ mojom("arc_bindings") {
"common/auth.mojom",
"common/bitmap.mojom",
"common/bluetooth.mojom",
+ "common/boot_phase_monitor.mojom",
"common/clipboard.mojom",
"common/crash_collector.mojom",
"common/enterprise_reporting.mojom",
@@ -149,19 +139,23 @@ mojom("arc_bindings") {
"common/obb_mounter.mojom",
"common/policy.mojom",
"common/power.mojom",
+ "common/print.mojom",
"common/process.mojom",
"common/scale_factor.mojom",
"common/screen_rect.mojom",
"common/storage_manager.mojom",
+ "common/tts.mojom",
"common/video.mojom",
"common/video_accelerator.mojom",
- "common/window_manager.mojom",
+ "common/wallpaper.mojom",
]
public_deps = [
"//mojo/common:common_custom_types",
"//ui/gfx/geometry/mojo",
]
+
+ use_new_wrapper_types = false
}
static_library("arc_test_support") {
@@ -171,10 +165,12 @@ static_library("arc_test_support") {
"test/fake_app_instance.h",
"test/fake_arc_bridge_bootstrap.cc",
"test/fake_arc_bridge_bootstrap.h",
- "test/fake_arc_bridge_instance.cc",
- "test/fake_arc_bridge_instance.h",
"test/fake_arc_bridge_service.cc",
"test/fake_arc_bridge_service.h",
+ "test/fake_bluetooth_instance.cc",
+ "test/fake_bluetooth_instance.h",
+ "test/fake_intent_helper_instance.cc",
+ "test/fake_intent_helper_instance.h",
"test/fake_notifications_instance.cc",
"test/fake_notifications_instance.h",
"test/fake_policy_instance.cc",
@@ -194,6 +190,9 @@ source_set("unit_tests") {
testonly = true
sources = [
"arc_bridge_service_unittest.cc",
+ "bluetooth/arc_bluetooth_bridge_unittest.cc",
+ "bluetooth/bluetooth_struct_traits_unittest.cc",
+ "bluetooth/bluetooth_type_converters_unittest.cc",
"ime/arc_ime_service_unittest.cc",
"intent_helper/activity_icon_loader_unittest.cc",
"intent_helper/arc_intent_helper_bridge_unittest.cc",
@@ -208,6 +207,7 @@ source_set("unit_tests") {
":arc_test_support",
"//base",
"//chromeos",
+ "//device/bluetooth",
"//mojo/public/cpp/system:system",
"//testing/gtest",
"//ui/aura",
@@ -218,54 +218,3 @@ source_set("unit_tests") {
"//url:url",
]
}
-
-static_library("arc_standalone_service") {
- sources = [
- "standalone/service_helper.cc",
- "standalone/service_helper.h",
- ]
-
- deps = [
- "//base",
- ]
-}
-
-static_library("arc_standalone") {
- sources = [
- "standalone/arc_standalone_bridge_runner.cc",
- "standalone/arc_standalone_bridge_runner.h",
- ]
-
- deps = [
- ":arc",
- ":arc_standalone_service",
- "//base",
- "//ipc:ipc",
- ]
-}
-
-test("arc_standalone_service_unittests") {
- sources = [
- "standalone/service_helper_unittest.cc",
- ]
-
- deps = [
- ":arc_standalone_service",
- "//base/test:test_support",
- "//testing/gtest",
- ]
-}
-
-executable("arc_standalone_bridge") {
- sources = [
- "standalone/arc_standalone_bridge_main.cc",
- ]
-
- deps = [
- ":arc_standalone",
- ":arc_standalone_service",
- "//base",
- "//ipc:ipc",
- "//mojo/edk/system",
- ]
-}
diff --git a/chromium/components/arc/arc_bridge_bootstrap.cc b/chromium/components/arc/arc_bridge_bootstrap.cc
index af771f1e183..845d0ae1467 100644
--- a/chromium/components/arc/arc_bridge_bootstrap.cc
+++ b/chromium/components/arc/arc_bridge_bootstrap.cc
@@ -6,6 +6,7 @@
#include <fcntl.h>
#include <grp.h>
+#include <poll.h>
#include <unistd.h>
#include <utility>
@@ -25,6 +26,8 @@
#include "chromeos/dbus/dbus_method_call_status.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/session_manager_client.h"
+#include "components/arc/arc_bridge_host_impl.h"
+#include "components/arc/arc_features.h"
#include "components/user_manager/user_manager.h"
#include "ipc/unix_domain_socket_util.h"
#include "mojo/edk/embedder/embedder.h"
@@ -62,61 +65,144 @@ chromeos::SessionManagerClient* GetSessionManagerClient() {
return chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
}
+// Creates a pipe. Returns true on success, otherwise false.
+// On success, |read_fd| will be set to the fd of the read side, and
+// |write_fd| will be set to the one of write side.
+bool CreatePipe(base::ScopedFD* read_fd, base::ScopedFD* write_fd) {
+ int fds[2];
+ if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0) {
+ PLOG(ERROR) << "pipe2()";
+ return false;
+ }
+
+ read_fd->reset(fds[0]);
+ write_fd->reset(fds[1]);
+ return true;
+}
+
+// Waits until |raw_socket_fd| is readable.
+// The operation may be cancelled originally triggered by user interaction to
+// disable ARC, or ARC instance is unexpectedly stopped (e.g. crash).
+// To notify such a situation, |raw_cancel_fd| is also passed to here, and the
+// write side will be closed in such a case.
+bool WaitForSocketReadable(int raw_socket_fd, int raw_cancel_fd) {
+ struct pollfd fds[2] = {
+ {raw_socket_fd, POLLIN, 0}, {raw_cancel_fd, POLLIN, 0},
+ };
+
+ if (HANDLE_EINTR(poll(fds, arraysize(fds), -1)) <= 0) {
+ PLOG(ERROR) << "poll()";
+ return false;
+ }
+
+ if (fds[1].revents) {
+ // Notified that Stop() is invoked. Cancel the Mojo connecting.
+ VLOG(1) << "Stop() was called during ConnectMojo()";
+ return false;
+ }
+
+ DCHECK(fds[0].revents);
+ return true;
+}
+
+// TODO(hidehiko): Refactor more to make this class unittest-able, for at least
+// state-machine part.
class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap,
public chromeos::SessionManagerClient::Observer {
public:
// The possible states of the bootstrap connection. In the normal flow,
// the state changes in the following sequence:
//
- // STOPPED
+ // NOT_STARTED
// Start() ->
- // DISK_SPACE_CHECKING
- // CheckDiskSpace() -> OnDiskSpaceChecked() ->
- // SOCKET_CREATING
+ // CHECKING_DISK_SPACE
+ // OnDiskSpaceChecked() ->
+ // CREATING_SOCKET
// CreateSocket() -> OnSocketCreated() ->
- // STARTING
- // StartArcInstance() -> OnInstanceStarted() ->
- // STARTED
- // AcceptInstanceConnection() -> OnInstanceConnected() ->
- // READY
+ // STARTING_INSTANCE
+ // -> OnInstanceStarted() ->
+ // CONNECTING_MOJO
+ // ConnectMojo() -> OnMojoConnected() ->
+ // RUNNING
+ //
+ // At any state, Stop() can be called. It does not immediately stop the
+ // instance, but will eventually stop it.
+ // The actual stop will be notified via Observer::OnStopped().
+ //
+ // When Stop() is called, it makes various behavior based on the current
+ // phase.
//
- // When Stop() or AbortBoot() is called from any state, either because an
- // operation resulted in an error or because the user is logging out:
+ // NOT_STARTED:
+ // Do nothing. Immediately transition to the STOPPED state.
+ // CHECKING_DISK_SPACE, CREATING_SOCKET:
+ // The main task of those phases runs on WorkerPool thread. So, Stop()
+ // just sets the flag and return. On the main task completion, a callback
+ // will run on the main (practically UI) thread, and the flag is checked
+ // at the beginning of them. This should work under the assumption that
+ // the main tasks do not block indefinitely.
+ // STARTING_INSTANCE:
+ // The ARC instance is starting via SessionManager. So, similar to
+ // CHECKING_DISK_SPACE/CREATING_SOCKET cases, Stop() just sets the flag
+ // and return. In its callback, it checks if ARC instance is successfully
+ // started or not. In case of success, a request to stop the ARC instance
+ // is sent to SessionManager. Its completion will be notified via
+ // ArcInstanceStopped. Otherwise, it just turns into STOPPED state.
+ // CONNECTING_MOJO:
+ // The main task runs on WorkerPool thread, but it is blocking call.
+ // So, Stop() sends a request to cancel the blocking by closing the pipe
+ // whose read side is also polled. Then, in its callback, similar to
+ // STARTING_INSTANCE, a request to stop the ARC instance is sent to
+ // SessionManager, and ArcInstanceStopped handles remaining procedure.
+ // RUNNING:
+ // There is no more callback which runs on normal flow, so Stop() requests
+ // to stop the ARC instance via SessionManager.
//
- // (any)
- // Stop()/AbortBoot() ->
- // STOPPING
- // StopInstance() ->
- // STOPPED
+ // Another trigger to change the state coming from outside of this class
+ // is an event ArcInstanceStopped() sent from SessionManager, when ARC
+ // instace unexpectedly terminates. ArcInstanceStopped() turns the state into
+ // STOPPED immediately.
+ // This happens only when STARTING_INSTANCE, CONNECTING_MOJO or RUNNING
+ // state.
//
- // When the instance crashes while it was ready, it will be stopped:
- // READY -> STOPPING -> STOPPED
- // and then restarted:
- // STOPPED -> DISK_SPACE_CHECKING -> ... -> READY).
+ // STARTING_INSTANCE:
+ // In OnInstanceStarted(), |state_| is checked at the beginning. If it is
+ // STOPPED, then ArcInstanceStopped() is called. Do nothing in that case.
+ // CONNECTING_MOJO:
+ // Similar to Stop() case above, ArcInstanceStopped() also notifies to
+ // WorkerPool() thread to cancel it to unblock the thread. In
+ // OnMojoConnected(), similar to OnInstanceStarted(), check if |state_| is
+ // STOPPED, then do nothing.
+ // RUNNING:
+ // It is not necessary to do anything special here.
+ //
+ // In NOT_STARTED or STOPPED state, the instance can be safely destructed.
+ // Specifically, in STOPPED state, there may be inflight operations or
+ // pending callbacks. Though, what they do is just do-nothing conceptually
+ // and they can be safely ignored.
//
// Note: Order of constants below matters. Please make sure to sort them
// in chronological order.
enum class State {
- // ARC is not currently running.
- STOPPED,
+ // ARC is not yet started.
+ NOT_STARTED,
// Checking the disk space.
- DISK_SPACE_CHECKING,
+ CHECKING_DISK_SPACE,
// An UNIX socket is being created.
- SOCKET_CREATING,
+ CREATING_SOCKET,
// The request to start the instance has been sent.
- STARTING,
+ STARTING_INSTANCE,
// The instance has started. Waiting for it to connect to the IPC bridge.
- STARTED,
+ CONNECTING_MOJO,
- // The instance is fully connected.
- READY,
+ // The instance is fully set up.
+ RUNNING,
- // The request to shut down the instance has been sent.
- STOPPING,
+ // ARC is terminated.
+ STOPPED,
};
ArcBridgeBootstrapImpl();
@@ -127,37 +213,44 @@ class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap,
void Stop() override;
private:
- // Aborts ARC instance boot. This is called from various state-machine
- // functions when they encounter an error during boot.
- void AbortBoot(ArcBridgeService::StopReason reason);
-
// Called after getting the device free disk space.
- void OnDiskSpaceChecked(int64_t disk_free_bytes);
+ void OnFreeDiskSpaceObtained(int64_t disk_free_bytes);
// Creates the UNIX socket on the bootstrap thread and then processes its
// file descriptor.
static base::ScopedFD CreateSocket();
void OnSocketCreated(base::ScopedFD fd);
+ // DBus callback for StartArcInstance().
+ void OnInstanceStarted(base::ScopedFD socket_fd, bool success);
+
// Synchronously accepts a connection on |socket_fd| and then processes the
// connected socket's file descriptor.
- static base::ScopedFD AcceptInstanceConnection(base::ScopedFD socket_fd);
- void OnInstanceConnected(base::ScopedFD fd);
-
- void SetState(State state);
+ static base::ScopedFD ConnectMojo(base::ScopedFD socket_fd,
+ base::ScopedFD cancel_fd);
+ void OnMojoConnected(base::ScopedFD fd);
- // DBus callbacks.
- void OnInstanceStarted(base::ScopedFD socket_fd, bool success);
+ // Request to stop ARC instance via DBus.
+ void StopArcInstance();
// chromeos::SessionManagerClient::Observer:
void ArcInstanceStopped(bool clean) override;
+ // Completes the termination procedure.
+ void OnStopped(ArcBridgeService::StopReason reason);
+
// The state of the bootstrap connection.
- State state_ = State::STOPPED;
+ State state_ = State::NOT_STARTED;
+
+ // When Stop() is called, this flag is set.
+ bool stop_requested_ = false;
- // The reason the ARC instance is stopped.
- ArcBridgeService::StopReason stop_reason_ =
- ArcBridgeService::StopReason::SHUTDOWN;
+ // In CONNECTING_MOJO state, this is set to the write side of the pipe
+ // to notify cancelling of the procedure.
+ base::ScopedFD accept_cancel_pipe_;
+
+ // Mojo endpoint.
+ std::unique_ptr<mojom::ArcBridgeHost> arc_bridge_host_;
base::ThreadChecker thread_checker_;
@@ -178,7 +271,8 @@ ArcBridgeBootstrapImpl::ArcBridgeBootstrapImpl()
ArcBridgeBootstrapImpl::~ArcBridgeBootstrapImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(state_ == State::STOPPED || state_ == State::STOPPING);
+ // TODO(hidehiko): CHECK if |state_| is in NOT_STARTED or STOPPED.
+ // Currently, specifically on shutdown, the state_ can be any value.
chromeos::SessionManagerClient* client = GetSessionManagerClient();
if (client == nullptr)
return;
@@ -187,39 +281,43 @@ ArcBridgeBootstrapImpl::~ArcBridgeBootstrapImpl() {
void ArcBridgeBootstrapImpl::Start() {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(delegate_);
- if (state_ != State::STOPPED) {
- VLOG(1) << "Start() called when instance is not stopped";
- return;
- }
- stop_reason_ = ArcBridgeService::StopReason::SHUTDOWN;
+ DCHECK_EQ(state_, State::NOT_STARTED);
+ VLOG(2) << "Starting ARC session.";
+ VLOG(2) << "Checking disk space...";
+ state_ = State::CHECKING_DISK_SPACE;
+
// TODO(crbug.com/628124): Move disk space checking logic to session_manager.
- SetState(State::DISK_SPACE_CHECKING);
base::PostTaskAndReplyWithResult(
base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
base::Bind(&base::SysInfo::AmountOfFreeDiskSpace,
base::FilePath(kDiskCheckPath)),
- base::Bind(&ArcBridgeBootstrapImpl::OnDiskSpaceChecked,
+ base::Bind(&ArcBridgeBootstrapImpl::OnFreeDiskSpaceObtained,
weak_factory_.GetWeakPtr()));
}
-void ArcBridgeBootstrapImpl::OnDiskSpaceChecked(int64_t disk_free_bytes) {
+void ArcBridgeBootstrapImpl::OnFreeDiskSpaceObtained(int64_t disk_free_bytes) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (state_ != State::DISK_SPACE_CHECKING) {
+ DCHECK_EQ(state_, State::CHECKING_DISK_SPACE);
+
+ if (stop_requested_) {
VLOG(1) << "Stop() called while checking disk space";
+ OnStopped(ArcBridgeService::StopReason::SHUTDOWN);
return;
}
+
if (disk_free_bytes < 0) {
LOG(ERROR) << "ARC: Failed to get free disk space";
- AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
+ OnStopped(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
return;
}
if (disk_free_bytes < kCriticalDiskFreeBytes) {
LOG(ERROR) << "ARC: The device is too low on disk space to start ARC";
- AbortBoot(ArcBridgeService::StopReason::LOW_DISK_SPACE);
+ OnStopped(ArcBridgeService::StopReason::LOW_DISK_SPACE);
return;
}
- SetState(State::SOCKET_CREATING);
+
+ VLOG(2) << "Disk space check is done. Creating socket...";
+ state_ = State::CREATING_SOCKET;
base::PostTaskAndReplyWithResult(
base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
base::Bind(&ArcBridgeBootstrapImpl::CreateSocket),
@@ -232,22 +330,10 @@ base::ScopedFD ArcBridgeBootstrapImpl::CreateSocket() {
base::FilePath socket_path(kArcBridgeSocketPath);
int raw_fd = -1;
- if (!IPC::CreateServerUnixDomainSocket(socket_path, &raw_fd)) {
+ if (!IPC::CreateServerUnixDomainSocket(socket_path, &raw_fd))
return base::ScopedFD();
- }
base::ScopedFD socket_fd(raw_fd);
- // Make socket blocking.
- int flags = HANDLE_EINTR(fcntl(socket_fd.get(), F_GETFL));
- if (flags == -1) {
- PLOG(ERROR) << "fcntl(F_GETFL)";
- return base::ScopedFD();
- }
- if (HANDLE_EINTR(fcntl(socket_fd.get(), F_SETFL, flags & ~O_NONBLOCK)) < 0) {
- PLOG(ERROR) << "fcntl(O_NONBLOCK)";
- return base::ScopedFD();
- }
-
// Change permissions on the socket.
struct group arc_bridge_group;
struct group* arc_bridge_group_res = nullptr;
@@ -279,27 +365,35 @@ base::ScopedFD ArcBridgeBootstrapImpl::CreateSocket() {
void ArcBridgeBootstrapImpl::OnSocketCreated(base::ScopedFD socket_fd) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (state_ != State::SOCKET_CREATING) {
+ DCHECK_EQ(state_, State::CREATING_SOCKET);
+
+ if (stop_requested_) {
VLOG(1) << "Stop() called while connecting";
+ OnStopped(ArcBridgeService::StopReason::SHUTDOWN);
return;
}
- SetState(State::STARTING);
if (!socket_fd.is_valid()) {
LOG(ERROR) << "ARC: Error creating socket";
- AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
+ OnStopped(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
return;
}
+ VLOG(2) << "Socket is created. Starting ARC instance...";
+ state_ = State::STARTING_INSTANCE;
user_manager::UserManager* user_manager = user_manager::UserManager::Get();
DCHECK(user_manager->GetPrimaryUser());
const cryptohome::Identification cryptohome_id(
user_manager->GetPrimaryUser()->GetAccountId());
+ bool disable_boot_completed_broadcast =
+ !base::FeatureList::IsEnabled(arc::kBootCompletedBroadcastFeature);
+
chromeos::SessionManagerClient* session_manager_client =
chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
session_manager_client->StartArcInstance(
cryptohome_id,
+ disable_boot_completed_broadcast,
base::Bind(&ArcBridgeBootstrapImpl::OnInstanceStarted,
weak_factory_.GetWeakPtr(), base::Passed(&socket_fd)));
}
@@ -307,33 +401,60 @@ void ArcBridgeBootstrapImpl::OnSocketCreated(base::ScopedFD socket_fd) {
void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd,
bool success) {
DCHECK(thread_checker_.CalledOnValidThread());
+ if (state_ == State::STOPPED) {
+ // This is the case that error is notified via DBus before the
+ // OnInstanceStarted() callback is invoked. The stopping procedure has
+ // been run, so do nothing.
+ return;
+ }
+
+ DCHECK_EQ(state_, State::STARTING_INSTANCE);
+
+ if (stop_requested_) {
+ if (success) {
+ // The ARC instance has started to run. Request to stop.
+ StopArcInstance();
+ return;
+ }
+ OnStopped(ArcBridgeService::StopReason::SHUTDOWN);
+ return;
+ }
+
if (!success) {
LOG(ERROR) << "Failed to start ARC instance";
- // Roll back the state to SOCKET_CREATING to avoid sending the D-Bus signal
- // to stop the failed instance.
- SetState(State::SOCKET_CREATING);
- AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
+ OnStopped(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
return;
}
- if (state_ != State::STARTING) {
- VLOG(1) << "Stop() called when ARC is not running";
+
+ VLOG(2) << "ARC instance is successfully started. Connecting Mojo...";
+ state_ = State::CONNECTING_MOJO;
+
+ // Prepare a pipe so that AcceptInstanceConnection can be interrupted on
+ // Stop().
+ base::ScopedFD cancel_fd;
+ if (!CreatePipe(&cancel_fd, &accept_cancel_pipe_)) {
+ OnStopped(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
return;
}
- SetState(State::STARTED);
base::PostTaskAndReplyWithResult(
base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
- base::Bind(&ArcBridgeBootstrapImpl::AcceptInstanceConnection,
- base::Passed(&socket_fd)),
- base::Bind(&ArcBridgeBootstrapImpl::OnInstanceConnected,
+ base::Bind(&ArcBridgeBootstrapImpl::ConnectMojo, base::Passed(&socket_fd),
+ base::Passed(&cancel_fd)),
+ base::Bind(&ArcBridgeBootstrapImpl::OnMojoConnected,
weak_factory_.GetWeakPtr()));
}
// static
-base::ScopedFD ArcBridgeBootstrapImpl::AcceptInstanceConnection(
- base::ScopedFD socket_fd) {
+base::ScopedFD ArcBridgeBootstrapImpl::ConnectMojo(base::ScopedFD socket_fd,
+ base::ScopedFD cancel_fd) {
+ if (!WaitForSocketReadable(socket_fd.get(), cancel_fd.get())) {
+ VLOG(1) << "Mojo connection was cancelled.";
+ return base::ScopedFD();
+ }
+
int raw_fd = -1;
- if (!IPC::ServerAcceptConnection(socket_fd.get(), &raw_fd)) {
+ if (!IPC::ServerOnConnect(socket_fd.get(), &raw_fd)) {
return base::ScopedFD();
}
base::ScopedFD scoped_fd(raw_fd);
@@ -361,90 +482,165 @@ base::ScopedFD ArcBridgeBootstrapImpl::AcceptInstanceConnection(
return scoped_fd;
}
-void ArcBridgeBootstrapImpl::OnInstanceConnected(base::ScopedFD fd) {
+void ArcBridgeBootstrapImpl::OnMojoConnected(base::ScopedFD fd) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (state_ != State::STARTED) {
- VLOG(1) << "Stop() called when ARC is not running";
+
+ if (state_ == State::STOPPED) {
+ // This is the case that error is notified via DBus before the
+ // OnMojoConnected() callback is invoked. The stopping procedure has
+ // been run, so do nothing.
+ return;
+ }
+
+ DCHECK_EQ(state_, State::CONNECTING_MOJO);
+ accept_cancel_pipe_.reset();
+
+ if (stop_requested_) {
+ StopArcInstance();
return;
}
+
if (!fd.is_valid()) {
LOG(ERROR) << "Invalid handle";
- AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
+ StopArcInstance();
return;
}
+
mojo::ScopedMessagePipeHandle server_pipe = mojo::edk::CreateMessagePipe(
mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release())));
if (!server_pipe.is_valid()) {
LOG(ERROR) << "Invalid pipe";
- AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
+ StopArcInstance();
return;
}
- SetState(State::READY);
+
mojom::ArcBridgeInstancePtr instance;
instance.Bind(mojo::InterfacePtrInfo<mojom::ArcBridgeInstance>(
std::move(server_pipe), 0u));
- delegate_->OnConnectionEstablished(std::move(instance));
+ arc_bridge_host_.reset(new ArcBridgeHostImpl(std::move(instance)));
+
+ VLOG(2) << "Mojo is connected. ARC is running.";
+ state_ = State::RUNNING;
+ FOR_EACH_OBSERVER(ArcBridgeBootstrap::Observer, observer_list_, OnReady());
}
void ArcBridgeBootstrapImpl::Stop() {
DCHECK(thread_checker_.CalledOnValidThread());
- if (state_ == State::STOPPED || state_ == State::STOPPING) {
- VLOG(1) << "Stop() called when ARC is not running";
- return;
- }
- if (state_ < State::STARTING) {
- // This was stopped before the D-Bus command to start the instance. Skip
- // the D-Bus command to stop it.
- SetState(State::STOPPED);
+ VLOG(2) << "Stopping ARC session is requested.";
+
+ // For second time or later, just do nothing.
+ // It is already in the stopping phase.
+ if (stop_requested_)
return;
+
+ stop_requested_ = true;
+ arc_bridge_host_.reset();
+ switch (state_) {
+ case State::NOT_STARTED:
+ OnStopped(ArcBridgeService::StopReason::SHUTDOWN);
+ return;
+
+ case State::CHECKING_DISK_SPACE:
+ case State::CREATING_SOCKET:
+ case State::STARTING_INSTANCE:
+ // Before starting the ARC instance, we do nothing here.
+ // At some point, a callback will be invoked on UI thread,
+ // and stopping procedure will be run there.
+ // On Chrome shutdown, it is not the case because the message loop is
+ // already stopped here. Practically, it is not a problem because;
+ // - On disk space checking or on socket creating, it is ok to simply
+ // ignore such cases, because we no-longer continue the bootstrap
+ // procedure.
+ // - On starting instance, the container instance can be leaked.
+ // Practically it is not problematic because the session manager will
+ // clean it up.
+ return;
+
+ case State::CONNECTING_MOJO:
+ // Mojo connection is being waited on a WorkerPool thread.
+ // Request to cancel it. Following stopping procedure will run
+ // in its callback.
+ DCHECK(accept_cancel_pipe_.get());
+ accept_cancel_pipe_.reset();
+ return;
+
+ case State::RUNNING:
+ // Now ARC instance is running. Request to stop it.
+ StopArcInstance();
+ return;
+
+ case State::STOPPED:
+ // The instance is already stopped. Do nothing.
+ return;
}
- SetState(State::STOPPING);
+}
+
+void ArcBridgeBootstrapImpl::StopArcInstance() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(state_ == State::STARTING_INSTANCE ||
+ state_ == State::CONNECTING_MOJO || state_ == State::RUNNING);
+
// Notification will arrive through ArcInstanceStopped().
+ VLOG(2) << "Requesting to stop ARC instance";
chromeos::SessionManagerClient* session_manager_client =
chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
session_manager_client->StopArcInstance(
base::Bind(&DoNothingInstanceStopped));
}
-void ArcBridgeBootstrapImpl::AbortBoot(ArcBridgeService::StopReason reason) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(reason != ArcBridgeService::StopReason::SHUTDOWN);
- // In case of multiple errors, report the first one.
- if (stop_reason_ == ArcBridgeService::StopReason::SHUTDOWN) {
- stop_reason_ = reason;
- }
- Stop();
-}
-
void ArcBridgeBootstrapImpl::ArcInstanceStopped(bool clean) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!clean) {
- LOG(ERROR) << "ARC instance crashed";
- // In case of multiple errors, report the first one.
- if (stop_reason_ == ArcBridgeService::StopReason::SHUTDOWN) {
- stop_reason_ = ArcBridgeService::StopReason::CRASH;
- }
+ VLOG(1) << "Notified that ARC instance is stopped "
+ << (clean ? "cleanly" : "uncleanly");
+
+ // In case that crash happens during before the Mojo channel is connected,
+ // unlock the WorkerPool thread.
+ accept_cancel_pipe_.reset();
+
+ ArcBridgeService::StopReason reason;
+ if (stop_requested_) {
+ // If the ARC instance is stopped after its explicit request,
+ // return SHUTDOWN.
+ reason = ArcBridgeService::StopReason::SHUTDOWN;
+ } else if (clean) {
+ // If the ARC instance is stopped, but it is not explicitly requested,
+ // then this is triggered by some failure during the starting procedure.
+ // Return GENERIC_BOOT_FAILURE for the case.
+ reason = ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE;
+ } else {
+ // Otherwise, this is caused by CRASH occured inside of the ARC instance.
+ reason = ArcBridgeService::StopReason::CRASH;
}
- SetState(State::STOPPED);
+ OnStopped(reason);
}
-void ArcBridgeBootstrapImpl::SetState(State state) {
+void ArcBridgeBootstrapImpl::OnStopped(ArcBridgeService::StopReason reason) {
DCHECK(thread_checker_.CalledOnValidThread());
- // DCHECK on enum classes not supported.
- DCHECK(state_ != state);
- state_ = state;
- VLOG(2) << "State: " << static_cast<uint32_t>(state_);
- if (state_ == State::STOPPED) {
- DCHECK(delegate_);
- delegate_->OnStopped(stop_reason_);
- }
+ // OnStopped() should be called once per instance.
+ DCHECK_NE(state_, State::STOPPED);
+ VLOG(2) << "ARC session is stopped.";
+ arc_bridge_host_.reset();
+ state_ = State::STOPPED;
+ FOR_EACH_OBSERVER(ArcBridgeBootstrap::Observer, observer_list_,
+ OnStopped(reason));
}
} // namespace
+ArcBridgeBootstrap::ArcBridgeBootstrap() = default;
+ArcBridgeBootstrap::~ArcBridgeBootstrap() = default;
+
+void ArcBridgeBootstrap::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void ArcBridgeBootstrap::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
// static
std::unique_ptr<ArcBridgeBootstrap> ArcBridgeBootstrap::Create() {
- return base::WrapUnique(new ArcBridgeBootstrapImpl());
+ return base::MakeUnique<ArcBridgeBootstrapImpl>();
}
} // namespace arc
diff --git a/chromium/components/arc/arc_bridge_bootstrap.h b/chromium/components/arc/arc_bridge_bootstrap.h
index 25a59f88dbf..45d2d72d014 100644
--- a/chromium/components/arc/arc_bridge_bootstrap.h
+++ b/chromium/components/arc/arc_bridge_bootstrap.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/macros.h"
+#include "base/observer_list.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "components/arc/arc_bridge_service.h"
@@ -18,39 +19,51 @@ namespace arc {
// Starts the ARC instance and bootstraps the bridge connection.
// Clients should implement the Delegate to be notified upon communications
// being available.
+// The instance can be safely removed 1) before Start() is called, or 2) after
+// OnStopped() is called.
+// The number of instances must be at most one. Otherwise, ARC instances will
+// conflict.
+// TODO(hidehiko): This class manages more than "bootstrap" procedure now.
+// Rename this to ArcSession.
class ArcBridgeBootstrap {
public:
- class Delegate {
+ class Observer {
public:
+ Observer() = default;
+ virtual ~Observer() = default;
+
// Called when the connection with ARC instance has been established.
- virtual void OnConnectionEstablished(
- mojom::ArcBridgeInstancePtr instance_ptr) = 0;
+ virtual void OnReady() = 0;
- // Called when ARC instance is stopped.
+ // Called when ARC instance is stopped. This is called exactly once
+ // per instance which is Start()ed.
virtual void OnStopped(ArcBridgeService::StopReason reason) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Observer);
};
// Creates a default instance of ArcBridgeBootstrap.
static std::unique_ptr<ArcBridgeBootstrap> Create();
- virtual ~ArcBridgeBootstrap() = default;
-
- // This must be called before calling Start() or Stop(). |delegate| is owned
- // by the caller and must outlive this instance.
- void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+ virtual ~ArcBridgeBootstrap();
// Starts and bootstraps a connection with the instance. The Delegate's
// OnConnectionEstablished() will be called if the bootstrapping is
// successful, or OnStopped() if it is not.
+ // Start() should not be called twice or more.
virtual void Start() = 0;
- // Stops the currently-running instance.
+ // Requests to stop the currently-running instance.
+ // The completion is notified via OnStopped() of the Delegate.
virtual void Stop() = 0;
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
protected:
- ArcBridgeBootstrap() = default;
+ ArcBridgeBootstrap();
- // Owned by the caller.
- Delegate* delegate_ = nullptr;
+ base::ObserverList<Observer> observer_list_;
private:
DISALLOW_COPY_AND_ASSIGN(ArcBridgeBootstrap);
diff --git a/chromium/components/arc/arc_bridge_host_impl.cc b/chromium/components/arc/arc_bridge_host_impl.cc
new file mode 100644
index 00000000000..94e558985ae
--- /dev/null
+++ b/chromium/components/arc/arc_bridge_host_impl.cc
@@ -0,0 +1,247 @@
+// 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 "components/arc/arc_bridge_host_impl.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/arc/instance_holder.h"
+
+namespace arc {
+
+// Thin interface to wrap InterfacePtr<T> with type erasure.
+class ArcBridgeHostImpl::MojoChannel {
+ public:
+ virtual ~MojoChannel() = default;
+
+ protected:
+ MojoChannel() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MojoChannel);
+};
+
+namespace {
+
+// The thin wrapper for InterfacePtr<T>, where T is one of ARC mojo Instance
+// class.
+template <typename T>
+class MojoChannelImpl : public ArcBridgeHostImpl::MojoChannel {
+ public:
+ MojoChannelImpl(InstanceHolder<T>* holder, mojo::InterfacePtr<T> ptr)
+ : holder_(holder), ptr_(std::move(ptr)) {
+ // Delay registration to the InstanceHolder until the version is ready.
+ }
+
+ ~MojoChannelImpl() override { holder_->SetInstance(nullptr, 0); }
+
+ void set_connection_error_handler(const base::Closure& error_handler) {
+ ptr_.set_connection_error_handler(error_handler);
+ }
+
+ void QueryVersion() {
+ // Note: the callback will not be called if |ptr_| is destroyed.
+ ptr_.QueryVersion(base::Bind(&MojoChannelImpl<T>::OnVersionReady,
+ base::Unretained(this)));
+ }
+
+ private:
+ void OnVersionReady(uint32_t unused_version) {
+ holder_->SetInstance(ptr_.get(), ptr_.version());
+ }
+
+ // Owned by ArcBridgeService.
+ InstanceHolder<T>* const holder_;
+
+ // Put as a last member to ensure that any callback tied to the |ptr_|
+ // is not invoked.
+ mojo::InterfacePtr<T> ptr_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoChannelImpl);
+};
+
+} // namespace
+
+ArcBridgeHostImpl::ArcBridgeHostImpl(mojom::ArcBridgeInstancePtr instance)
+ : binding_(this), instance_(std::move(instance)) {
+ DCHECK(instance_.is_bound());
+ instance_.set_connection_error_handler(
+ base::Bind(&ArcBridgeHostImpl::OnClosed, base::Unretained(this)));
+ instance_->Init(binding_.CreateInterfacePtrAndBind());
+}
+
+ArcBridgeHostImpl::~ArcBridgeHostImpl() {
+ OnClosed();
+}
+
+void ArcBridgeHostImpl::OnAppInstanceReady(mojom::AppInstancePtr app_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->app(), std::move(app_ptr));
+}
+
+void ArcBridgeHostImpl::OnAudioInstanceReady(
+ mojom::AudioInstancePtr audio_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->audio(), std::move(audio_ptr));
+}
+
+void ArcBridgeHostImpl::OnAuthInstanceReady(mojom::AuthInstancePtr auth_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->auth(), std::move(auth_ptr));
+}
+
+void ArcBridgeHostImpl::OnBluetoothInstanceReady(
+ mojom::BluetoothInstancePtr bluetooth_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->bluetooth(),
+ std::move(bluetooth_ptr));
+}
+
+void ArcBridgeHostImpl::OnBootPhaseMonitorInstanceReady(
+ mojom::BootPhaseMonitorInstancePtr boot_phase_monitor_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->boot_phase_monitor(),
+ std::move(boot_phase_monitor_ptr));
+}
+
+void ArcBridgeHostImpl::OnClipboardInstanceReady(
+ mojom::ClipboardInstancePtr clipboard_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->clipboard(),
+ std::move(clipboard_ptr));
+}
+
+void ArcBridgeHostImpl::OnCrashCollectorInstanceReady(
+ mojom::CrashCollectorInstancePtr crash_collector_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->crash_collector(),
+ std::move(crash_collector_ptr));
+}
+
+void ArcBridgeHostImpl::OnEnterpriseReportingInstanceReady(
+ mojom::EnterpriseReportingInstancePtr enterprise_reporting_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->enterprise_reporting(),
+ std::move(enterprise_reporting_ptr));
+}
+
+void ArcBridgeHostImpl::OnFileSystemInstanceReady(
+ mojom::FileSystemInstancePtr file_system_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->file_system(),
+ std::move(file_system_ptr));
+}
+
+void ArcBridgeHostImpl::OnImeInstanceReady(mojom::ImeInstancePtr ime_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->ime(), std::move(ime_ptr));
+}
+
+void ArcBridgeHostImpl::OnIntentHelperInstanceReady(
+ mojom::IntentHelperInstancePtr intent_helper_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->intent_helper(),
+ std::move(intent_helper_ptr));
+}
+
+void ArcBridgeHostImpl::OnMetricsInstanceReady(
+ mojom::MetricsInstancePtr metrics_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->metrics(), std::move(metrics_ptr));
+}
+
+void ArcBridgeHostImpl::OnNetInstanceReady(mojom::NetInstancePtr net_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->net(), std::move(net_ptr));
+}
+
+void ArcBridgeHostImpl::OnNotificationsInstanceReady(
+ mojom::NotificationsInstancePtr notifications_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->notifications(),
+ std::move(notifications_ptr));
+}
+
+void ArcBridgeHostImpl::OnObbMounterInstanceReady(
+ mojom::ObbMounterInstancePtr obb_mounter_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->obb_mounter(),
+ std::move(obb_mounter_ptr));
+}
+
+void ArcBridgeHostImpl::OnPolicyInstanceReady(
+ mojom::PolicyInstancePtr policy_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->policy(), std::move(policy_ptr));
+}
+
+void ArcBridgeHostImpl::OnPowerInstanceReady(
+ mojom::PowerInstancePtr power_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->power(), std::move(power_ptr));
+}
+
+void ArcBridgeHostImpl::OnPrintInstanceReady(
+ mojom::PrintInstancePtr print_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->print(), std::move(print_ptr));
+}
+
+void ArcBridgeHostImpl::OnProcessInstanceReady(
+ mojom::ProcessInstancePtr process_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->process(), std::move(process_ptr));
+}
+
+void ArcBridgeHostImpl::OnStorageManagerInstanceReady(
+ mojom::StorageManagerInstancePtr storage_manager_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->storage_manager(),
+ std::move(storage_manager_ptr));
+}
+
+void ArcBridgeHostImpl::OnTtsInstanceReady(mojom::TtsInstancePtr tts_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->tts(), std::move(tts_ptr));
+}
+
+void ArcBridgeHostImpl::OnVideoInstanceReady(
+ mojom::VideoInstancePtr video_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->video(), std::move(video_ptr));
+}
+
+void ArcBridgeHostImpl::OnWallpaperInstanceReady(
+ mojom::WallpaperInstancePtr wallpaper_ptr) {
+ OnInstanceReady(ArcBridgeService::Get()->wallpaper(),
+ std::move(wallpaper_ptr));
+}
+
+void ArcBridgeHostImpl::OnClosed() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ VLOG(1) << "Mojo connection lost";
+
+ // Close all mojo channels.
+ mojo_channels_.clear();
+ instance_.reset();
+ if (binding_.is_bound())
+ binding_.Close();
+}
+
+template <typename T>
+void ArcBridgeHostImpl::OnInstanceReady(InstanceHolder<T>* holder,
+ mojo::InterfacePtr<T> ptr) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(binding_.is_bound());
+ DCHECK(ptr.is_bound());
+
+ // Track |channel|'s lifetime via |mojo_channels_| so that it will be
+ // closed on ArcBridgeHost/Instance closing or the ArcBridgeHostImpl's
+ // destruction.
+ auto* channel = new MojoChannelImpl<T>(holder, std::move(ptr));
+ mojo_channels_.emplace_back(channel);
+
+ // Since |channel| is managed by |mojo_channels_|, its lifetime is shorter
+ // than |this|. Thus, the connection error handler will be invoked only
+ // when |this| is alive and base::Unretained is safe here.
+ channel->set_connection_error_handler(base::Bind(
+ &ArcBridgeHostImpl::OnChannelClosed, base::Unretained(this), channel));
+
+ // Call QueryVersion so that the version info is properly stored in the
+ // InterfacePtr<T>.
+ channel->QueryVersion();
+}
+
+void ArcBridgeHostImpl::OnChannelClosed(MojoChannel* channel) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ mojo_channels_.erase(
+ std::find_if(mojo_channels_.begin(), mojo_channels_.end(),
+ [channel](std::unique_ptr<MojoChannel>& ptr) {
+ return ptr.get() == channel;
+ }));
+}
+
+} // namespace arc
diff --git a/chromium/components/arc/arc_bridge_host_impl.h b/chromium/components/arc/arc_bridge_host_impl.h
new file mode 100644
index 00000000000..0b7972a7294
--- /dev/null
+++ b/chromium/components/arc/arc_bridge_host_impl.h
@@ -0,0 +1,100 @@
+// 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 COMPONENTS_ARC_ARC_BRIDGE_HOST_IMPL_H_
+#define COMPONENTS_ARC_ARC_BRIDGE_HOST_IMPL_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "components/arc/common/arc_bridge.mojom.h"
+#include "components/arc/instance_holder.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+
+namespace arc {
+
+// Implementation of the ArcBridgeHost.
+// The lifetime of ArcBridgeHost and ArcBridgeInstance mojo channels are tied
+// to this instance. Also, any ARC related Mojo channel will be closed if
+// either ArcBridgeHost or ArcBridgeInstance Mojo channels is closed on error.
+// When ARC Instance (not Host) Mojo channel gets ready (= passed via
+// OnFooInstanceReady(), and the QueryVersion() gets completed), then this sets
+// the raw pointer to the ArcBridgeService so that other services can access
+// to the pointer, and resets it on channel closing.
+// Note that ArcBridgeService must be alive while ArcBridgeHostImpl is alive.
+class ArcBridgeHostImpl : public mojom::ArcBridgeHost {
+ public:
+ // Interface to keep the Mojo channel InterfacePtr.
+ class MojoChannel;
+
+ explicit ArcBridgeHostImpl(mojom::ArcBridgeInstancePtr instance);
+ ~ArcBridgeHostImpl() override;
+
+ // ArcBridgeHost overrides.
+ void OnAppInstanceReady(mojom::AppInstancePtr app_ptr) override;
+ void OnAudioInstanceReady(mojom::AudioInstancePtr audio_ptr) override;
+ void OnAuthInstanceReady(mojom::AuthInstancePtr auth_ptr) override;
+ void OnBluetoothInstanceReady(
+ mojom::BluetoothInstancePtr bluetooth_ptr) override;
+ void OnBootPhaseMonitorInstanceReady(
+ mojom::BootPhaseMonitorInstancePtr boot_phase_monitor_ptr) override;
+ void OnClipboardInstanceReady(
+ mojom::ClipboardInstancePtr clipboard_ptr) override;
+ void OnCrashCollectorInstanceReady(
+ mojom::CrashCollectorInstancePtr crash_collector_ptr) override;
+ void OnEnterpriseReportingInstanceReady(
+ mojom::EnterpriseReportingInstancePtr enterprise_reporting_ptr) override;
+ void OnFileSystemInstanceReady(
+ mojom::FileSystemInstancePtr file_system_ptr) override;
+ void OnImeInstanceReady(mojom::ImeInstancePtr ime_ptr) override;
+ void OnIntentHelperInstanceReady(
+ mojom::IntentHelperInstancePtr intent_helper_ptr) override;
+ void OnMetricsInstanceReady(mojom::MetricsInstancePtr metrics_ptr) override;
+ void OnNetInstanceReady(mojom::NetInstancePtr net_ptr) override;
+ void OnNotificationsInstanceReady(
+ mojom::NotificationsInstancePtr notifications_ptr) override;
+ void OnObbMounterInstanceReady(
+ mojom::ObbMounterInstancePtr obb_mounter_ptr) override;
+ void OnPolicyInstanceReady(mojom::PolicyInstancePtr policy_ptr) override;
+ void OnPowerInstanceReady(mojom::PowerInstancePtr power_ptr) override;
+ void OnPrintInstanceReady(mojom::PrintInstancePtr print_ptr) override;
+ void OnProcessInstanceReady(mojom::ProcessInstancePtr process_ptr) override;
+ void OnStorageManagerInstanceReady(
+ mojom::StorageManagerInstancePtr storage_manager_ptr) override;
+ void OnTtsInstanceReady(mojom::TtsInstancePtr tts_ptr) override;
+ void OnVideoInstanceReady(mojom::VideoInstancePtr video_ptr) override;
+ void OnWallpaperInstanceReady(
+ mojom::WallpaperInstancePtr wallpaper_ptr) override;
+
+ private:
+ // Called when the bridge channel is closed. This typically only happens when
+ // the ARC instance crashes.
+ void OnClosed();
+
+ // The common implementation to handle ArcBridgeHost overrides.
+ // |T| is a ARC Mojo Instance type.
+ template <typename T>
+ void OnInstanceReady(InstanceHolder<T>* holder, mojo::InterfacePtr<T> ptr);
+
+ // Called if one of the established channels is closed.
+ void OnChannelClosed(MojoChannel* channel);
+
+ base::ThreadChecker thread_checker_;
+
+ mojo::Binding<mojom::ArcBridgeHost> binding_;
+ mojom::ArcBridgeInstancePtr instance_;
+
+ // Put as a last member to ensure that any callback tied to the elements
+ // is not invoked.
+ std::vector<std::unique_ptr<MojoChannel>> mojo_channels_;
+
+ DISALLOW_COPY_AND_ASSIGN(ArcBridgeHostImpl);
+};
+
+} // namespace arc
+
+#endif // COMPONENTS_ARC_ARC_BRIDGE_HOST_IMPL_H_
diff --git a/chromium/components/arc/arc_bridge_service.cc b/chromium/components/arc/arc_bridge_service.cc
index c2fe6c5e906..20cbb7da43b 100644
--- a/chromium/components/arc/arc_bridge_service.cc
+++ b/chromium/components/arc/arc_bridge_service.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/chromeos_switches.h"
@@ -15,25 +16,22 @@ namespace arc {
namespace {
-// Weak pointer. This class is owned by ArcServiceManager.
-ArcBridgeService* g_arc_bridge_service = nullptr;
+const base::Feature kArcEnabledFeature{"EnableARC",
+ base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace
+// Weak pointer. This class is owned by ArcServiceManager.
+ArcBridgeService* g_arc_bridge_service = nullptr;
+
ArcBridgeService::ArcBridgeService()
- : available_(false),
- state_(State::STOPPED),
+ : state_(State::STOPPED),
stop_reason_(StopReason::SHUTDOWN),
- weak_factory_(this) {
- DCHECK(!g_arc_bridge_service);
- g_arc_bridge_service = this;
-}
+ weak_factory_(this) {}
ArcBridgeService::~ArcBridgeService() {
DCHECK(CalledOnValidThread());
DCHECK(state() == State::STOPPING || state() == State::STOPPED);
- DCHECK(g_arc_bridge_service == this);
- g_arc_bridge_service = nullptr;
}
// static
@@ -50,7 +48,14 @@ ArcBridgeService* ArcBridgeService::Get() {
// static
bool ArcBridgeService::GetEnabled(const base::CommandLine* command_line) {
- return command_line->HasSwitch(chromeos::switches::kEnableArc);
+ return command_line->HasSwitch(chromeos::switches::kEnableArc) ||
+ (command_line->HasSwitch(chromeos::switches::kArcAvailable) &&
+ base::FeatureList::IsEnabled(kArcEnabledFeature));
+}
+
+// static
+bool ArcBridgeService::GetAvailable(const base::CommandLine* command_line) {
+ return command_line->HasSwitch(chromeos::switches::kArcAvailable);
}
void ArcBridgeService::AddObserver(Observer* observer) {
@@ -63,138 +68,17 @@ void ArcBridgeService::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
-void ArcBridgeService::OnAppInstanceReady(mojom::AppInstancePtr app_ptr) {
- DCHECK(CalledOnValidThread());
- app_.OnInstanceReady(std::move(app_ptr));
-}
-
-void ArcBridgeService::OnAudioInstanceReady(mojom::AudioInstancePtr audio_ptr) {
- DCHECK(CalledOnValidThread());
- audio_.OnInstanceReady(std::move(audio_ptr));
-}
-
-void ArcBridgeService::OnAuthInstanceReady(mojom::AuthInstancePtr auth_ptr) {
- DCHECK(CalledOnValidThread());
- auth_.OnInstanceReady(std::move(auth_ptr));
-}
-
-void ArcBridgeService::OnBluetoothInstanceReady(
- mojom::BluetoothInstancePtr bluetooth_ptr) {
- DCHECK(CalledOnValidThread());
- bluetooth_.OnInstanceReady(std::move(bluetooth_ptr));
-}
-
-void ArcBridgeService::OnClipboardInstanceReady(
- mojom::ClipboardInstancePtr clipboard_ptr) {
- DCHECK(CalledOnValidThread());
- clipboard_.OnInstanceReady(std::move(clipboard_ptr));
-}
-
-void ArcBridgeService::OnCrashCollectorInstanceReady(
- mojom::CrashCollectorInstancePtr crash_collector_ptr) {
- DCHECK(CalledOnValidThread());
- crash_collector_.OnInstanceReady(std::move(crash_collector_ptr));
-}
-
-void ArcBridgeService::OnEnterpriseReportingInstanceReady(
- mojom::EnterpriseReportingInstancePtr enterprise_reporting_ptr) {
- enterprise_reporting_.OnInstanceReady(std::move(enterprise_reporting_ptr));
-}
-
-void ArcBridgeService::OnFileSystemInstanceReady(
- mojom::FileSystemInstancePtr file_system_ptr) {
- DCHECK(CalledOnValidThread());
- file_system_.OnInstanceReady(std::move(file_system_ptr));
-}
-
-void ArcBridgeService::OnImeInstanceReady(mojom::ImeInstancePtr ime_ptr) {
- DCHECK(CalledOnValidThread());
- ime_.OnInstanceReady(std::move(ime_ptr));
-}
-
-void ArcBridgeService::OnIntentHelperInstanceReady(
- mojom::IntentHelperInstancePtr intent_helper_ptr) {
- DCHECK(CalledOnValidThread());
- intent_helper_.OnInstanceReady(std::move(intent_helper_ptr));
-}
-
-void ArcBridgeService::OnMetricsInstanceReady(
- mojom::MetricsInstancePtr metrics_ptr) {
- DCHECK(CalledOnValidThread());
- metrics_.OnInstanceReady(std::move(metrics_ptr));
-}
-
-void ArcBridgeService::OnNetInstanceReady(mojom::NetInstancePtr net_ptr) {
- DCHECK(CalledOnValidThread());
- net_.OnInstanceReady(std::move(net_ptr));
-}
-
-void ArcBridgeService::OnNotificationsInstanceReady(
- mojom::NotificationsInstancePtr notifications_ptr) {
- DCHECK(CalledOnValidThread());
- notifications_.OnInstanceReady(std::move(notifications_ptr));
-}
-
-void ArcBridgeService::OnObbMounterInstanceReady(
- mojom::ObbMounterInstancePtr obb_mounter_ptr) {
- DCHECK(CalledOnValidThread());
- obb_mounter_.OnInstanceReady(std::move(obb_mounter_ptr));
-}
-
-void ArcBridgeService::OnPolicyInstanceReady(
- mojom::PolicyInstancePtr policy_ptr) {
- DCHECK(CalledOnValidThread());
- policy_.OnInstanceReady(std::move(policy_ptr));
-}
-
-void ArcBridgeService::OnPowerInstanceReady(mojom::PowerInstancePtr power_ptr) {
- DCHECK(CalledOnValidThread());
- power_.OnInstanceReady(std::move(power_ptr));
-}
-
-void ArcBridgeService::OnProcessInstanceReady(
- mojom::ProcessInstancePtr process_ptr) {
- DCHECK(CalledOnValidThread());
- process_.OnInstanceReady(std::move(process_ptr));
-}
-
-void ArcBridgeService::OnStorageManagerInstanceReady(
- mojom::StorageManagerInstancePtr storage_manager_ptr) {
- DCHECK(CalledOnValidThread());
- storage_manager_.OnInstanceReady(std::move(storage_manager_ptr));
-}
-
-void ArcBridgeService::OnVideoInstanceReady(mojom::VideoInstancePtr video_ptr) {
- DCHECK(CalledOnValidThread());
- video_.OnInstanceReady(std::move(video_ptr));
-}
-
-void ArcBridgeService::OnWindowManagerInstanceReady(
- mojom::WindowManagerInstancePtr window_manager_ptr) {
- DCHECK(CalledOnValidThread());
- window_manager_.OnInstanceReady(std::move(window_manager_ptr));
-}
-
void ArcBridgeService::SetState(State state) {
DCHECK(CalledOnValidThread());
- // DCHECK on enum classes not supported.
- DCHECK(state_ != state);
+ DCHECK_NE(state_, state);
state_ = state;
VLOG(2) << "State: " << static_cast<uint32_t>(state_);
- FOR_EACH_OBSERVER(Observer, observer_list(), OnStateChanged(state_));
if (state_ == State::READY)
FOR_EACH_OBSERVER(Observer, observer_list(), OnBridgeReady());
else if (state == State::STOPPED)
FOR_EACH_OBSERVER(Observer, observer_list(), OnBridgeStopped(stop_reason_));
}
-void ArcBridgeService::SetAvailable(bool available) {
- DCHECK(CalledOnValidThread());
- DCHECK(available_ != available);
- available_ = available;
- FOR_EACH_OBSERVER(Observer, observer_list(), OnAvailableChanged(available_));
-}
-
void ArcBridgeService::SetStopReason(StopReason stop_reason) {
DCHECK(CalledOnValidThread());
stop_reason_ = stop_reason;
@@ -204,29 +88,22 @@ bool ArcBridgeService::CalledOnValidThread() {
return thread_checker_.CalledOnValidThread();
}
-void ArcBridgeService::CloseAllChannels() {
- // Call all the error handlers of all the channels to both close the channel
- // and notify any observers that the channel is closed.
- app_.CloseChannel();
- audio_.CloseChannel();
- auth_.CloseChannel();
- bluetooth_.CloseChannel();
- clipboard_.CloseChannel();
- crash_collector_.CloseChannel();
- enterprise_reporting_.CloseChannel();
- file_system_.CloseChannel();
- ime_.CloseChannel();
- intent_helper_.CloseChannel();
- metrics_.CloseChannel();
- net_.CloseChannel();
- notifications_.CloseChannel();
- obb_mounter_.CloseChannel();
- policy_.CloseChannel();
- power_.CloseChannel();
- process_.CloseChannel();
- storage_manager_.CloseChannel();
- video_.CloseChannel();
- window_manager_.CloseChannel();
+std::ostream& operator<<(
+ std::ostream& os, ArcBridgeService::StopReason reason) {
+ switch (reason) {
+#define CASE_IMPL(val) \
+ case ArcBridgeService::StopReason::val: \
+ return os << #val
+
+ CASE_IMPL(SHUTDOWN);
+ CASE_IMPL(GENERIC_BOOT_FAILURE);
+ CASE_IMPL(LOW_DISK_SPACE);
+ CASE_IMPL(CRASH);
+#undef CASE_IMPL
+ }
+
+ // In case of unexpected value, output the int value.
+ return os << "StopReason(" << static_cast<int>(reason) << ")";
}
} // namespace arc
diff --git a/chromium/components/arc/arc_bridge_service.h b/chromium/components/arc/arc_bridge_service.h
index c88b21b7a79..d3ee567d7e3 100644
--- a/chromium/components/arc/arc_bridge_service.h
+++ b/chromium/components/arc/arc_bridge_service.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_ARC_ARC_BRIDGE_SERVICE_H_
#define COMPONENTS_ARC_ARC_BRIDGE_SERVICE_H_
+#include <iosfwd>
#include <string>
#include <vector>
@@ -22,46 +23,13 @@ class CommandLine;
namespace arc {
+class ArcBridgeTest;
+
// The Chrome-side service that handles ARC instances and ARC bridge creation.
// This service handles the lifetime of ARC instances and sets up the
// communication channel (the ARC bridge) used to send and receive messages.
-class ArcBridgeService : public mojom::ArcBridgeHost {
+class ArcBridgeService {
public:
- // The possible states of the bridge. In the normal flow, the state changes
- // in the following sequence:
- //
- // STOPPED
- // PrerequisitesChanged() ->
- // CONNECTING
- // OnConnectionEstablished() ->
- // READY
- //
- // The ArcBridgeBootstrap state machine can be thought of being substates of
- // ArcBridgeService's CONNECTING state.
- //
- // *
- // StopInstance() ->
- // STOPPING
- // OnStopped() ->
- // STOPPED
- enum class State {
- // ARC is not currently running.
- STOPPED,
-
- // The request to connect has been sent.
- CONNECTING,
-
- // The instance has started, and the bridge is fully established.
- CONNECTED,
-
- // The ARC instance has finished initializing and is now ready for user
- // interaction.
- READY,
-
- // The ARC instance has started shutting down.
- STOPPING,
- };
-
// Describes the reason the bridge is stopped.
enum class StopReason {
// ARC instance has been gracefully shut down.
@@ -83,19 +51,14 @@ class ArcBridgeService : public mojom::ArcBridgeHost {
class Observer {
public:
// Called whenever the state of the bridge has changed.
- // TODO(lchavez): Rename to OnStateChangedForTest
- virtual void OnStateChanged(State state) {}
virtual void OnBridgeReady() {}
virtual void OnBridgeStopped(StopReason reason) {}
- // Called whenever ARC's availability has changed for this system.
- virtual void OnAvailableChanged(bool available) {}
-
protected:
virtual ~Observer() {}
};
- ~ArcBridgeService() override;
+ virtual ~ArcBridgeService();
// Gets the global instance of the ARC Bridge Service. This can only be
// called on the thread that this class was created on.
@@ -105,13 +68,11 @@ class ArcBridgeService : public mojom::ArcBridgeHost {
// switch.
static bool GetEnabled(const base::CommandLine* command_line);
- // SetDetectedAvailability() should be called once CheckArcAvailability() on
- // the session_manager is called. This can only be called on the thread that
- // this class was created on.
- virtual void SetDetectedAvailability(bool availability) = 0;
+ // Return true if ARC is available on the current board.
+ static bool GetAvailable(const base::CommandLine* command_line);
// HandleStartup() should be called upon profile startup. This will only
- // launch an instance if the instance service is available and it is enabled.
+ // launch an instance if the instance is enabled.
// This can only be called on the thread that this class was created on.
virtual void HandleStartup() = 0;
@@ -129,6 +90,9 @@ class ArcBridgeService : public mojom::ArcBridgeHost {
InstanceHolder<mojom::AudioInstance>* audio() { return &audio_; }
InstanceHolder<mojom::AuthInstance>* auth() { return &auth_; }
InstanceHolder<mojom::BluetoothInstance>* bluetooth() { return &bluetooth_; }
+ InstanceHolder<mojom::BootPhaseMonitorInstance>* boot_phase_monitor() {
+ return &boot_phase_monitor_;
+ }
InstanceHolder<mojom::ClipboardInstance>* clipboard() { return &clipboard_; }
InstanceHolder<mojom::CrashCollectorInstance>* crash_collector() {
return &crash_collector_;
@@ -153,87 +117,66 @@ class ArcBridgeService : public mojom::ArcBridgeHost {
}
InstanceHolder<mojom::PolicyInstance>* policy() { return &policy_; }
InstanceHolder<mojom::PowerInstance>* power() { return &power_; }
+ InstanceHolder<mojom::PrintInstance>* print() { return &print_; }
InstanceHolder<mojom::ProcessInstance>* process() { return &process_; }
InstanceHolder<mojom::StorageManagerInstance>* storage_manager() {
return &storage_manager_;
}
+ InstanceHolder<mojom::TtsInstance>* tts() { return &tts_; }
InstanceHolder<mojom::VideoInstance>* video() { return &video_; }
- InstanceHolder<mojom::WindowManagerInstance>* window_manager() {
- return &window_manager_;
- }
+ InstanceHolder<mojom::WallpaperInstance>* wallpaper() { return &wallpaper_; }
- // ArcHost:
- void OnAppInstanceReady(mojom::AppInstancePtr app_ptr) override;
- void OnAudioInstanceReady(mojom::AudioInstancePtr audio_ptr) override;
- void OnAuthInstanceReady(mojom::AuthInstancePtr auth_ptr) override;
- void OnBluetoothInstanceReady(
- mojom::BluetoothInstancePtr bluetooth_ptr) override;
- void OnClipboardInstanceReady(
- mojom::ClipboardInstancePtr clipboard_ptr) override;
- void OnCrashCollectorInstanceReady(
- mojom::CrashCollectorInstancePtr crash_collector_ptr) override;
- void OnEnterpriseReportingInstanceReady(
- mojom::EnterpriseReportingInstancePtr enterprise_reporting_ptr) override;
- void OnFileSystemInstanceReady(
- mojom::FileSystemInstancePtr file_system_ptr) override;
- void OnImeInstanceReady(mojom::ImeInstancePtr ime_ptr) override;
- void OnIntentHelperInstanceReady(
- mojom::IntentHelperInstancePtr intent_helper_ptr) override;
- void OnMetricsInstanceReady(mojom::MetricsInstancePtr metrics_ptr) override;
- void OnNetInstanceReady(mojom::NetInstancePtr net_ptr) override;
- void OnNotificationsInstanceReady(
- mojom::NotificationsInstancePtr notifications_ptr) override;
- void OnObbMounterInstanceReady(
- mojom::ObbMounterInstancePtr obb_mounter_ptr) override;
- void OnPolicyInstanceReady(mojom::PolicyInstancePtr policy_ptr) override;
- void OnPowerInstanceReady(mojom::PowerInstancePtr power_ptr) override;
- void OnProcessInstanceReady(mojom::ProcessInstancePtr process_ptr) override;
- void OnStorageManagerInstanceReady(
- mojom::StorageManagerInstancePtr storage_manager_ptr) override;
- void OnVideoInstanceReady(mojom::VideoInstancePtr video_ptr) override;
- void OnWindowManagerInstanceReady(
- mojom::WindowManagerInstancePtr window_manager_ptr) override;
+ // Gets if ARC is currently running.
+ bool ready() const { return state() == State::READY; }
- // Gets the current state of the bridge service.
- State state() const { return state_; }
-
- // Gets if ARC is available in this system.
- bool available() const { return available_; }
+ // Gets if ARC is currently stopped. This is not exactly !ready() since there
+ // are transient states between ready() and stopped().
+ bool stopped() const { return state() == State::STOPPED; }
protected:
- ArcBridgeService();
-
- // Changes the current state and notifies all observers.
- void SetState(State state);
-
- // Changes the current availability and notifies all observers.
- void SetAvailable(bool availability);
+ // The possible states of the bridge. In the normal flow, the state changes
+ // in the following sequence:
+ //
+ // STOPPED
+ // PrerequisitesChanged() ->
+ // CONNECTING
+ // OnConnectionEstablished() ->
+ // READY
+ //
+ // The ArcBridgeBootstrap state machine can be thought of being substates of
+ // ArcBridgeService's CONNECTING state.
+ //
+ // *
+ // StopInstance() ->
+ // STOPPING
+ // OnStopped() ->
+ // STOPPED
+ enum class State {
+ // ARC is not currently running.
+ STOPPED,
- // Sets the reason the bridge is stopped. This function must be always called
- // before SetState(State::STOPPED) to report a correct reason with
- // Observer::OnBridgeStopped().
- void SetStopReason(StopReason stop_reason);
+ // The request to connect has been sent.
+ CONNECTING,
- base::ObserverList<Observer>& observer_list() { return observer_list_; }
+ // The instance has started, and the bridge is fully established.
+ CONNECTED,
- bool CalledOnValidThread();
+ // The ARC instance has finished initializing and is now ready for user
+ // interaction.
+ READY,
- // Closes all Mojo channels.
- void CloseAllChannels();
+ // The ARC instance has started shutting down.
+ STOPPING,
+ };
- private:
- friend class ArcBridgeTest;
- FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Basic);
- FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Prerequisites);
- FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, ShutdownMidStartup);
- FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Restart);
- FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, OnBridgeStopped);
+ ArcBridgeService();
// Instance holders.
InstanceHolder<mojom::AppInstance> app_;
InstanceHolder<mojom::AudioInstance> audio_;
InstanceHolder<mojom::AuthInstance> auth_;
InstanceHolder<mojom::BluetoothInstance> bluetooth_;
+ InstanceHolder<mojom::BootPhaseMonitorInstance> boot_phase_monitor_;
InstanceHolder<mojom::ClipboardInstance> clipboard_;
InstanceHolder<mojom::CrashCollectorInstance> crash_collector_;
InstanceHolder<mojom::EnterpriseReportingInstance> enterprise_reporting_;
@@ -246,18 +189,40 @@ class ArcBridgeService : public mojom::ArcBridgeHost {
InstanceHolder<mojom::ObbMounterInstance> obb_mounter_;
InstanceHolder<mojom::PolicyInstance> policy_;
InstanceHolder<mojom::PowerInstance> power_;
+ InstanceHolder<mojom::PrintInstance> print_;
InstanceHolder<mojom::ProcessInstance> process_;
InstanceHolder<mojom::StorageManagerInstance> storage_manager_;
+ InstanceHolder<mojom::TtsInstance> tts_;
InstanceHolder<mojom::VideoInstance> video_;
- InstanceHolder<mojom::WindowManagerInstance> window_manager_;
+ InstanceHolder<mojom::WallpaperInstance> wallpaper_;
+
+ // Gets the current state of the bridge service.
+ State state() const { return state_; }
+
+ // Changes the current state and notifies all observers.
+ void SetState(State state);
+
+ // Sets the reason the bridge is stopped. This function must be always called
+ // before SetState(State::STOPPED) to report a correct reason with
+ // Observer::OnBridgeStopped().
+ void SetStopReason(StopReason stop_reason);
+
+ base::ObserverList<Observer>& observer_list() { return observer_list_; }
+
+ bool CalledOnValidThread();
+
+ private:
+ friend class ArcBridgeTest;
+ FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Basic);
+ FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Prerequisites);
+ FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, ShutdownMidStartup);
+ FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Restart);
+ FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, OnBridgeStopped);
base::ObserverList<Observer> observer_list_;
base::ThreadChecker thread_checker_;
- // If the ARC instance service is available.
- bool available_;
-
// The current state of the bridge.
ArcBridgeService::State state_;
@@ -270,6 +235,10 @@ class ArcBridgeService : public mojom::ArcBridgeHost {
DISALLOW_COPY_AND_ASSIGN(ArcBridgeService);
};
+// Defines "<<" operator for LOGging purpose.
+std::ostream& operator<<(
+ std::ostream& os, ArcBridgeService::StopReason reason);
+
} // namespace arc
#endif // COMPONENTS_ARC_ARC_BRIDGE_SERVICE_H_
diff --git a/chromium/components/arc/arc_bridge_service_impl.cc b/chromium/components/arc/arc_bridge_service_impl.cc
index ed3dc985ffb..388ab0ce068 100644
--- a/chromium/components/arc/arc_bridge_service_impl.cc
+++ b/chromium/components/arc/arc_bridge_service_impl.cc
@@ -9,7 +9,6 @@
#include "base/command_line.h"
#include "base/json/json_writer.h"
-#include "base/message_loop/message_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/sys_info.h"
#include "base/task_runner_util.h"
@@ -18,26 +17,32 @@
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/dbus_method_call_status.h"
#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
namespace arc {
+extern ArcBridgeService* g_arc_bridge_service;
+
namespace {
constexpr int64_t kReconnectDelayInSeconds = 5;
} // namespace
-ArcBridgeServiceImpl::ArcBridgeServiceImpl(
- std::unique_ptr<ArcBridgeBootstrap> bootstrap)
- : bootstrap_(std::move(bootstrap)),
- binding_(this),
- session_started_(false),
+ArcBridgeServiceImpl::ArcBridgeServiceImpl()
+ : session_started_(false),
+ factory_(base::Bind(ArcBridgeBootstrap::Create)),
weak_factory_(this) {
- bootstrap_->set_delegate(this);
+ DCHECK(!g_arc_bridge_service);
+ g_arc_bridge_service = this;
}
-ArcBridgeServiceImpl::~ArcBridgeServiceImpl() {}
+ArcBridgeServiceImpl::~ArcBridgeServiceImpl() {
+ if (bootstrap_)
+ bootstrap_->RemoveObserver(this);
+
+ DCHECK(g_arc_bridge_service == this);
+ g_arc_bridge_service = nullptr;
+}
void ArcBridgeServiceImpl::HandleStartup() {
DCHECK(CalledOnValidThread());
@@ -57,6 +62,13 @@ void ArcBridgeServiceImpl::Shutdown() {
PrerequisitesChanged();
}
+void ArcBridgeServiceImpl::SetArcBridgeBootstrapFactoryForTesting(
+ const ArcBridgeBootstrapFactory& factory) {
+ DCHECK(!factory.is_null());
+ factory_ = factory;
+}
+
+
void ArcBridgeServiceImpl::DisableReconnectDelayForTesting() {
use_delay_before_reconnecting_ = false;
}
@@ -65,17 +77,22 @@ void ArcBridgeServiceImpl::PrerequisitesChanged() {
DCHECK(CalledOnValidThread());
VLOG(1) << "Prerequisites changed. "
<< "state=" << static_cast<uint32_t>(state())
- << ", available=" << available()
<< ", session_started=" << session_started_;
if (state() == State::STOPPED) {
- if (!available() || !session_started_)
+ if (!session_started_)
return;
VLOG(0) << "Prerequisites met, starting ARC";
SetStopReason(StopReason::SHUTDOWN);
+
+ if (bootstrap_)
+ bootstrap_->RemoveObserver(this);
+
SetState(State::CONNECTING);
+ bootstrap_ = factory_.Run();
+ bootstrap_->AddObserver(this);
bootstrap_->Start();
} else {
- if (available() && session_started_)
+ if (session_started_)
return;
VLOG(0) << "Prerequisites stopped being met, stopping ARC";
StopInstance();
@@ -89,40 +106,24 @@ void ArcBridgeServiceImpl::StopInstance() {
return;
}
- VLOG(1) << "Stopping ARC";
- SetState(State::STOPPING);
- instance_ptr_.reset();
- if (binding_.is_bound())
- binding_.Close();
- bootstrap_->Stop();
-
// We were explicitly asked to stop, so do not reconnect.
reconnect_ = false;
-}
-void ArcBridgeServiceImpl::SetDetectedAvailability(bool arc_available) {
- DCHECK(CalledOnValidThread());
- if (available() == arc_available)
- return;
- VLOG(1) << "ARC available: " << arc_available;
- SetAvailable(arc_available);
- PrerequisitesChanged();
+ VLOG(1) << "Stopping ARC";
+ DCHECK(bootstrap_.get());
+ SetState(State::STOPPING);
+
+ // Note: this can call OnStopped() internally as a callback.
+ bootstrap_->Stop();
}
-void ArcBridgeServiceImpl::OnConnectionEstablished(
- mojom::ArcBridgeInstancePtr instance) {
+void ArcBridgeServiceImpl::OnReady() {
DCHECK(CalledOnValidThread());
if (state() != State::CONNECTING) {
VLOG(1) << "StopInstance() called while connecting";
return;
}
- instance_ptr_ = std::move(instance);
- instance_ptr_.set_connection_error_handler(base::Bind(
- &ArcBridgeServiceImpl::OnChannelClosed, weak_factory_.GetWeakPtr()));
-
- instance_ptr_->Init(binding_.CreateInterfacePtrAndBind());
-
// The container can be considered to have been successfully launched, so
// restart if the connection goes down without being requested.
reconnect_ = true;
@@ -132,9 +133,12 @@ void ArcBridgeServiceImpl::OnConnectionEstablished(
void ArcBridgeServiceImpl::OnStopped(StopReason stop_reason) {
DCHECK(CalledOnValidThread());
+ VLOG(0) << "ARC stopped: " << stop_reason;
+ bootstrap_->RemoveObserver(this);
+ bootstrap_.reset();
SetStopReason(stop_reason);
SetState(State::STOPPED);
- VLOG(0) << "ARC stopped";
+
if (reconnect_) {
// There was a previous invocation and it crashed for some reason. Try
// starting the container again.
@@ -144,7 +148,7 @@ void ArcBridgeServiceImpl::OnStopped(StopReason stop_reason) {
// Instead of immediately trying to restart the container, give it some
// time to finish tearing down in case it is still in the process of
// stopping.
- base::MessageLoop::current()->task_runner()->PostDelayedTask(
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::Bind(&ArcBridgeServiceImpl::PrerequisitesChanged,
weak_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(kReconnectDelayInSeconds));
@@ -155,17 +159,4 @@ void ArcBridgeServiceImpl::OnStopped(StopReason stop_reason) {
}
}
-void ArcBridgeServiceImpl::OnChannelClosed() {
- DCHECK(CalledOnValidThread());
- if (state() == State::STOPPED || state() == State::STOPPING) {
- // This will happen when the instance is shut down. Ignore that case.
- return;
- }
- VLOG(1) << "Mojo connection lost";
- instance_ptr_.reset();
- if (binding_.is_bound())
- binding_.Close();
- CloseAllChannels();
-}
-
} // namespace arc
diff --git a/chromium/components/arc/arc_bridge_service_impl.h b/chromium/components/arc/arc_bridge_service_impl.h
index 938054058bc..1c3afaec5d9 100644
--- a/chromium/components/arc/arc_bridge_service_impl.h
+++ b/chromium/components/arc/arc_bridge_service_impl.h
@@ -25,17 +25,28 @@ namespace arc {
// Real IPC based ArcBridgeService that is used in production.
class ArcBridgeServiceImpl : public ArcBridgeService,
- public ArcBridgeBootstrap::Delegate {
+ public ArcBridgeBootstrap::Observer {
public:
- explicit ArcBridgeServiceImpl(std::unique_ptr<ArcBridgeBootstrap> bootstrap);
- ~ArcBridgeServiceImpl() override;
+ // This is the factory interface to inject ArcBridgeBootstrap instance
+ // for testing purpose.
+ using ArcBridgeBootstrapFactory =
+ base::Callback<std::unique_ptr<ArcBridgeBootstrap>()>;
- void SetDetectedAvailability(bool available) override;
+ ArcBridgeServiceImpl();
+ ~ArcBridgeServiceImpl() override;
void HandleStartup() override;
void Shutdown() override;
+ // Inject a factory to create ArcBridgeBootstrap instance for testing
+ // purpose. |factory| must not be null.
+ void SetArcBridgeBootstrapFactoryForTesting(
+ const ArcBridgeBootstrapFactory& factory);
+
+ // Returns the current bootstrap instance for testing purpose.
+ ArcBridgeBootstrap* GetBootstrapForTesting() { return bootstrap_.get(); }
+
// Normally, reconnecting after connection shutdown happens after a short
// delay. When testing, however, we'd like it to happen immediately to avoid
// adding unnecessary delays.
@@ -54,20 +65,12 @@ class ArcBridgeServiceImpl : public ArcBridgeService,
// Stops the running instance.
void StopInstance();
- // ArcBridgeBootstrap::Delegate:
- void OnConnectionEstablished(mojom::ArcBridgeInstancePtr instance) override;
+ // ArcBridgeBootstrap::Observer:
+ void OnReady() override;
void OnStopped(StopReason reason) override;
- // Called when the bridge channel is closed. This typically only happens when
- // the ARC instance crashes. This is not called during shutdown.
- void OnChannelClosed();
-
std::unique_ptr<ArcBridgeBootstrap> bootstrap_;
- // Mojo endpoints.
- mojo::Binding<mojom::ArcBridgeHost> binding_;
- mojom::ArcBridgeInstancePtr instance_ptr_;
-
// If the user's session has started.
bool session_started_;
@@ -78,6 +81,9 @@ class ArcBridgeServiceImpl : public ArcBridgeService,
// Delay the reconnection.
bool use_delay_before_reconnecting_ = true;
+ // Factory to inject a fake ArcBridgeBootstrap instance for testing.
+ ArcBridgeBootstrapFactory factory_;
+
// WeakPtrFactory to use callbacks.
base::WeakPtrFactory<ArcBridgeServiceImpl> weak_factory_;
diff --git a/chromium/components/arc/arc_bridge_service_unittest.cc b/chromium/components/arc/arc_bridge_service_unittest.cc
index 4dc107bd388..8eb7e477c8f 100644
--- a/chromium/components/arc/arc_bridge_service_unittest.cc
+++ b/chromium/components/arc/arc_bridge_service_unittest.cc
@@ -9,10 +9,10 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "components/arc/arc_bridge_service_impl.h"
#include "components/arc/test/fake_arc_bridge_bootstrap.h"
-#include "components/arc/test/fake_arc_bridge_instance.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -20,39 +20,54 @@ namespace arc {
namespace {
-class ArcBridgeTest : public testing::Test, public ArcBridgeService::Observer {
+class DummyObserver : public ArcBridgeService::Observer {};
+
+} // namespace
+
+// TODO(hidehiko): ArcBridgeTest gets complicated and has stale code.
+// Simplify the code.
+class ArcBridgeTest : public testing::Test,
+ public ArcBridgeService::Observer {
public:
- ArcBridgeTest() : ready_(false) {}
- ~ArcBridgeTest() override {}
-
- void OnStateChanged(ArcBridgeService::State state) override {
- state_ = state;
- switch (state) {
- case ArcBridgeService::State::READY:
- ready_ = true;
- break;
-
- case ArcBridgeService::State::STOPPED:
- message_loop_.PostTask(FROM_HERE, message_loop_.QuitWhenIdleClosure());
- break;
-
- default:
- break;
- }
+ ArcBridgeTest() = default;
+
+ void OnBridgeReady() override {
+ state_ = ArcBridgeService::State::READY;
+ ready_ = true;
}
void OnBridgeStopped(ArcBridgeService::StopReason stop_reason) override {
+ // The instance is already destructed in ArcBridgeServiceImpl::OnStopped().
+ state_ = ArcBridgeService::State::STOPPED;
stop_reason_ = stop_reason;
+ message_loop_.task_runner()->PostTask(FROM_HERE,
+ message_loop_.QuitWhenIdleClosure());
}
bool ready() const { return ready_; }
ArcBridgeService::State state() const { return state_; }
+ FakeArcBridgeBootstrap* bootstrap() const {
+ return static_cast<FakeArcBridgeBootstrap*>(
+ service_->GetBootstrapForTesting());
+ }
protected:
std::unique_ptr<ArcBridgeServiceImpl> service_;
- std::unique_ptr<FakeArcBridgeInstance> instance_;
ArcBridgeService::StopReason stop_reason_;
+ static std::unique_ptr<ArcBridgeBootstrap> CreateSuspendedBootstrap() {
+ auto bootstrap = base::MakeUnique<FakeArcBridgeBootstrap>();
+ bootstrap->SuspendBoot();
+ return std::move(bootstrap);
+ }
+
+ static std::unique_ptr<ArcBridgeBootstrap> CreateBootFailureBootstrap(
+ ArcBridgeService::StopReason reason) {
+ auto bootstrap = base::MakeUnique<FakeArcBridgeBootstrap>();
+ bootstrap->EnableBootFailureEmulation(reason);
+ return std::move(bootstrap);
+ }
+
private:
void SetUp() override {
chromeos::DBusThreadManager::Initialize();
@@ -61,90 +76,79 @@ class ArcBridgeTest : public testing::Test, public ArcBridgeService::Observer {
state_ = ArcBridgeService::State::STOPPED;
stop_reason_ = ArcBridgeService::StopReason::SHUTDOWN;
- instance_.reset(new FakeArcBridgeInstance());
- service_.reset(new ArcBridgeServiceImpl(
- base::MakeUnique<FakeArcBridgeBootstrap>(instance_.get())));
-
+ service_.reset(new ArcBridgeServiceImpl());
+ service_->SetArcBridgeBootstrapFactoryForTesting(
+ base::Bind(FakeArcBridgeBootstrap::Create));
service_->AddObserver(this);
}
void TearDown() override {
service_->RemoveObserver(this);
- instance_.reset();
service_.reset();
chromeos::DBusThreadManager::Shutdown();
}
- bool ready_;
+ bool ready_ = false;
ArcBridgeService::State state_;
base::MessageLoopForUI message_loop_;
DISALLOW_COPY_AND_ASSIGN(ArcBridgeTest);
};
-class DummyObserver : public ArcBridgeService::Observer {};
-
-} // namespace
-
// Exercises the basic functionality of the ARC Bridge Service. A message from
// within the instance should cause the observer to be notified.
TEST_F(ArcBridgeTest, Basic) {
ASSERT_FALSE(ready());
ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
- service_->SetAvailable(true);
service_->HandleStartup();
- instance_->WaitForInitCall();
ASSERT_EQ(ArcBridgeService::State::READY, state());
service_->Shutdown();
ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
}
-// If not all pre-requisites are met, the instance is not started.
-TEST_F(ArcBridgeTest, Prerequisites) {
- ASSERT_FALSE(ready());
- ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
- service_->SetAvailable(true);
- ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
- service_->SetAvailable(false);
- service_->HandleStartup();
- ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
-}
-
// If the ArcBridgeService is shut down, it should be stopped, even
// mid-startup.
TEST_F(ArcBridgeTest, ShutdownMidStartup) {
ASSERT_FALSE(ready());
- service_->SetAvailable(true);
+ service_->SetArcBridgeBootstrapFactoryForTesting(
+ base::Bind(ArcBridgeTest::CreateSuspendedBootstrap));
service_->HandleStartup();
- // WaitForInitCall() omitted.
- ASSERT_EQ(ArcBridgeService::State::READY, state());
+ ASSERT_FALSE(service_->stopped());
+ ASSERT_FALSE(service_->ready());
service_->Shutdown();
ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
}
+// If the boot procedure is failed, then restarting mechanism should not
+// triggered.
+TEST_F(ArcBridgeTest, BootFailure) {
+ ASSERT_TRUE(service_->stopped());
+
+ service_->SetArcBridgeBootstrapFactoryForTesting(
+ base::Bind(ArcBridgeTest::CreateBootFailureBootstrap,
+ ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE));
+ service_->HandleStartup();
+ EXPECT_EQ(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE, stop_reason_);
+ ASSERT_TRUE(service_->stopped());
+}
+
// If the instance is stopped, it should be re-started.
TEST_F(ArcBridgeTest, Restart) {
ASSERT_FALSE(ready());
- ASSERT_EQ(0, instance_->init_calls());
- service_->SetAvailable(true);
service_->HandleStartup();
- instance_->WaitForInitCall();
ASSERT_EQ(ArcBridgeService::State::READY, state());
- ASSERT_EQ(1, instance_->init_calls());
// Simulate a connection loss.
service_->DisableReconnectDelayForTesting();
- service_->OnChannelClosed();
- instance_->Stop(ArcBridgeService::StopReason::CRASH);
- instance_->WaitForInitCall();
- ASSERT_EQ(ArcBridgeService::State::READY, state());
- ASSERT_EQ(2, instance_->init_calls());
+ ASSERT_TRUE(bootstrap());
+ bootstrap()->StopWithReason(ArcBridgeService::StopReason::CRASH);
+ ASSERT_TRUE(service_->ready());
service_->Shutdown();
ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
@@ -155,24 +159,21 @@ TEST_F(ArcBridgeTest, OnBridgeStopped) {
ASSERT_FALSE(ready());
service_->DisableReconnectDelayForTesting();
- service_->SetAvailable(true);
service_->HandleStartup();
- instance_->WaitForInitCall();
ASSERT_EQ(ArcBridgeService::State::READY, state());
// Simulate boot failure.
- service_->OnChannelClosed();
- instance_->Stop(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
- instance_->WaitForInitCall();
- ASSERT_EQ(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE, stop_reason_);
- ASSERT_EQ(ArcBridgeService::State::READY, state());
+ ASSERT_TRUE(bootstrap());
+ bootstrap()->StopWithReason(
+ ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
+ EXPECT_EQ(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE, stop_reason_);
+ ASSERT_TRUE(service_->ready());
// Simulate crash.
- service_->OnChannelClosed();
- instance_->Stop(ArcBridgeService::StopReason::CRASH);
- instance_->WaitForInitCall();
- ASSERT_EQ(ArcBridgeService::StopReason::CRASH, stop_reason_);
- ASSERT_EQ(ArcBridgeService::State::READY, state());
+ ASSERT_TRUE(bootstrap());
+ bootstrap()->StopWithReason(ArcBridgeService::StopReason::CRASH);
+ EXPECT_EQ(ArcBridgeService::StopReason::CRASH, stop_reason_);
+ ASSERT_TRUE(service_->ready());
// Graceful shutdown.
service_->Shutdown();
@@ -183,8 +184,11 @@ TEST_F(ArcBridgeTest, OnBridgeStopped) {
// Removing the same observer more than once should be okay.
TEST_F(ArcBridgeTest, RemoveObserverTwice) {
ASSERT_FALSE(ready());
- service_->RemoveObserver(this);
- // The teardown method will also remove |this|.
+ auto dummy_observer = base::MakeUnique<DummyObserver>();
+ service_->AddObserver(dummy_observer.get());
+ // Call RemoveObserver() twice.
+ service_->RemoveObserver(dummy_observer.get());
+ service_->RemoveObserver(dummy_observer.get());
}
// Removing an unknown observer should be allowed.
diff --git a/chromium/components/arc/arc_features.cc b/chromium/components/arc/arc_features.cc
new file mode 100644
index 00000000000..5cf10d6beeb
--- /dev/null
+++ b/chromium/components/arc/arc_features.cc
@@ -0,0 +1,14 @@
+// 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 "components/arc/arc_features.h"
+
+namespace arc {
+
+// Controls ACTION_BOOT_COMPLETED broadcast for third party applications on ARC.
+// When disabled, third party apps will not receive this broadcast.
+const base::Feature kBootCompletedBroadcastFeature{
+ "ArcBootCompletedBroadcast", base::FEATURE_ENABLED_BY_DEFAULT};
+
+} // namespace arc
diff --git a/chromium/components/arc/arc_features.h b/chromium/components/arc/arc_features.h
new file mode 100644
index 00000000000..b9b01c12598
--- /dev/null
+++ b/chromium/components/arc/arc_features.h
@@ -0,0 +1,18 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines the public base::FeatureList features for ARC.
+
+#ifndef CHROMEOS_COMPONENTS_ARC_ARC_FEATURES_H_
+#define CHROMEOS_COMPONENTS_ARC_ARC_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace arc {
+
+extern const base::Feature kBootCompletedBroadcastFeature;
+
+} // namespace arc
+
+#endif // CHROMEOS_COMPONENTS_ARC_ARC_FEATURES_H_
diff --git a/chromium/components/arc/arc_service_manager.cc b/chromium/components/arc/arc_service_manager.cc
index b3cbe7a16d4..0e47eb5017f 100644
--- a/chromium/components/arc/arc_service_manager.cc
+++ b/chromium/components/arc/arc_service_manager.cc
@@ -4,14 +4,16 @@
#include "components/arc/arc_service_manager.h"
+#include <utility>
+
#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/arc/arc_bridge_bootstrap.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_bridge_service_impl.h"
#include "components/arc/audio/arc_audio_bridge.h"
#include "components/arc/bluetooth/arc_bluetooth_bridge.h"
+#include "components/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h"
#include "components/arc/clipboard/arc_clipboard_bridge.h"
#include "components/arc/crash_collector/arc_crash_collector_bridge.h"
#include "components/arc/ime/arc_ime_service.h"
@@ -22,7 +24,6 @@
#include "components/arc/power/arc_power_bridge.h"
#include "components/arc/storage_manager/arc_storage_manager.h"
#include "components/arc/user_data/arc_user_data_service.h"
-#include "components/arc/window_manager/arc_window_manager_bridge.h"
#include "components/prefs/pref_member.h"
#include "ui/arc/notification/arc_notification_manager.h"
@@ -50,21 +51,21 @@ ArcServiceManager::ArcServiceManager(
arc_bridge_service_.reset(g_arc_bridge_service_for_testing);
g_arc_bridge_service_for_testing = nullptr;
} else {
- arc_bridge_service_.reset(new ArcBridgeServiceImpl(
- ArcBridgeBootstrap::Create()));
+ arc_bridge_service_.reset(new ArcBridgeServiceImpl());
}
- AddService(base::WrapUnique(new ArcAudioBridge(arc_bridge_service())));
- AddService(base::WrapUnique(new ArcBluetoothBridge(arc_bridge_service())));
- AddService(base::WrapUnique(new ArcClipboardBridge(arc_bridge_service())));
- AddService(
- base::WrapUnique(new ArcCrashCollectorBridge(arc_bridge_service())));
- AddService(base::WrapUnique(new ArcImeService(arc_bridge_service())));
- AddService(base::WrapUnique(new ArcMetricsService(arc_bridge_service())));
- AddService(base::WrapUnique(new ArcNetHostImpl(arc_bridge_service())));
- AddService(base::WrapUnique(new ArcObbMounterBridge(arc_bridge_service())));
- AddService(base::WrapUnique(new ArcPowerBridge(arc_bridge_service())));
- AddService(base::WrapUnique(new ArcStorageManager(arc_bridge_service())));
+ AddService(base::MakeUnique<ArcAudioBridge>(arc_bridge_service()));
+ AddService(base::MakeUnique<ArcBluetoothBridge>(arc_bridge_service()));
+ AddService(base::MakeUnique<ArcBootPhaseMonitorBridge>(arc_bridge_service()));
+ AddService(base::MakeUnique<ArcClipboardBridge>(arc_bridge_service()));
+ AddService(base::MakeUnique<ArcCrashCollectorBridge>(arc_bridge_service(),
+ blocking_task_runner_));
+ AddService(base::MakeUnique<ArcImeService>(arc_bridge_service()));
+ AddService(base::MakeUnique<ArcMetricsService>(arc_bridge_service()));
+ AddService(base::MakeUnique<ArcNetHostImpl>(arc_bridge_service()));
+ AddService(base::MakeUnique<ArcObbMounterBridge>(arc_bridge_service()));
+ AddService(base::MakeUnique<ArcPowerBridge>(arc_bridge_service()));
+ AddService(base::MakeUnique<ArcStorageManager>(arc_bridge_service()));
}
ArcServiceManager::~ArcServiceManager() {
@@ -98,19 +99,8 @@ void ArcServiceManager::OnPrimaryUserProfilePrepared(
const AccountId& account_id,
std::unique_ptr<BooleanPrefMember> arc_enabled_pref) {
DCHECK(thread_checker_.CalledOnValidThread());
- AddService(base::WrapUnique(
- new ArcNotificationManager(arc_bridge_service(), account_id)));
-}
-
-void ArcServiceManager::OnAshStarted() {
- DCHECK(thread_checker_.CalledOnValidThread());
- // We might come here multiple times. As such we should only do this once.
- if (on_ash_started_called_)
- return;
-
- on_ash_started_called_ = true;
- AddService(
- base::WrapUnique(new ArcWindowManagerBridge(arc_bridge_service())));
+ AddService(base::MakeUnique<ArcNotificationManager>(arc_bridge_service(),
+ account_id));
}
void ArcServiceManager::Shutdown() {
@@ -119,7 +109,7 @@ void ArcServiceManager::Shutdown() {
services_.clear();
}
-//static
+// static
void ArcServiceManager::SetArcBridgeServiceForTesting(
std::unique_ptr<ArcBridgeService> arc_bridge_service) {
if (g_arc_bridge_service_for_testing) {
diff --git a/chromium/components/arc/arc_service_manager.h b/chromium/components/arc/arc_service_manager.h
index ac2f4a552aa..256a1992eb9 100644
--- a/chromium/components/arc/arc_service_manager.h
+++ b/chromium/components/arc/arc_service_manager.h
@@ -46,9 +46,6 @@ class ArcServiceManager {
const AccountId& account_id,
std::unique_ptr<BooleanPrefMember> arc_enabled_pref);
- // Called once the windowing system (ash) has been started.
- void OnAshStarted();
-
// Called to shut down all ARC services.
void Shutdown();
@@ -78,10 +75,6 @@ class ArcServiceManager {
scoped_refptr<ActivityIconLoader> icon_loader_;
scoped_refptr<LocalActivityResolver> activity_resolver_;
- // True once the window manager service got added, barring adding any more
- // of those since OnAshStarted() might be called multiple times.
- bool on_ash_started_called_ = false;
-
DISALLOW_COPY_AND_ASSIGN(ArcServiceManager);
};
diff --git a/chromium/components/arc/audio/arc_audio_bridge.cc b/chromium/components/arc/audio/arc_audio_bridge.cc
index 222b5bc4fcb..02f4cecead2 100644
--- a/chromium/components/arc/audio/arc_audio_bridge.cc
+++ b/chromium/components/arc/audio/arc_audio_bridge.cc
@@ -11,6 +11,14 @@
namespace arc {
+namespace {
+
+// Note: unlike most of our mojom definitions, AudioInstance::Init's minimum
+// version is not zero.
+constexpr uint32_t kMinInstanceVersionForInit = 1;
+
+} // namespace
+
ArcAudioBridge::ArcAudioBridge(ArcBridgeService* bridge_service)
: ArcService(bridge_service), binding_(this) {
arc_bridge_service()->audio()->AddObserver(this);
@@ -29,16 +37,9 @@ ArcAudioBridge::~ArcAudioBridge() {
void ArcAudioBridge::OnInstanceReady() {
mojom::AudioInstance* audio_instance =
- arc_bridge_service()->audio()->instance();
- if (!audio_instance) {
- LOG(ERROR) << "OnAudioInstanceReady called, "
- << "but no audio instance found";
- return;
- }
- if (arc_bridge_service()->audio()->version() < 1) {
- LOG(WARNING) << "Audio instance is too old and does not support Init()";
- return;
- }
+ arc_bridge_service()->audio()->GetInstanceForMethod(
+ "Init", kMinInstanceVersionForInit);
+ DCHECK(audio_instance); // the instance on ARC side is too old.
audio_instance->Init(binding_.CreateInterfacePtrAndBind());
}
@@ -82,7 +83,7 @@ void ArcAudioBridge::SendSwitchState(bool headphone_inserted,
VLOG(1) << "Send switch state " << switch_state;
mojom::AudioInstance* audio_instance =
- arc_bridge_service()->audio()->instance();
+ arc_bridge_service()->audio()->GetInstanceForMethod("NotifySwitchState");
if (audio_instance)
audio_instance->NotifySwitchState(switch_state);
}
diff --git a/chromium/components/arc/bitmap/OWNERS b/chromium/components/arc/bitmap/OWNERS
new file mode 100644
index 00000000000..bb6511619b7
--- /dev/null
+++ b/chromium/components/arc/bitmap/OWNERS
@@ -0,0 +1,2 @@
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/arc/bitmap/bitmap_struct_traits.cc b/chromium/components/arc/bitmap/bitmap_struct_traits.cc
new file mode 100644
index 00000000000..51aa30f44f0
--- /dev/null
+++ b/chromium/components/arc/bitmap/bitmap_struct_traits.cc
@@ -0,0 +1,36 @@
+// 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 "components/arc/bitmap/bitmap_struct_traits.h"
+
+namespace mojo {
+
+bool StructTraits<arc::mojom::ArcBitmapDataView, SkBitmap>::
+ Read(arc::mojom::ArcBitmapDataView data, SkBitmap* out) {
+ mojo::ArrayDataView<uint8_t> pixel_data;
+ data.GetPixelDataDataView(&pixel_data);
+
+ SkImageInfo info = SkImageInfo::Make(
+ data.width(), data.height(),
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+ if (info.getSafeSize(info.minRowBytes()) > pixel_data.size()) {
+ // Insufficient buffer size.
+ return false;
+ }
+
+ // Create the SkBitmap object which wraps the arc bitmap pixels. This
+ // doesn't copy and |data| and |bitmap| share the buffer.
+ SkBitmap bitmap;
+ if (!bitmap.installPixels(info,
+ const_cast<uint8_t*>(pixel_data.data()),
+ info.minRowBytes())) {
+ // Error in installing pixels.
+ return false;
+ }
+
+ // Copy the pixels with converting color type.
+ return bitmap.copyTo(out, kN32_SkColorType);
+}
+
+} // namespace mojo
diff --git a/chromium/components/arc/bitmap/bitmap_struct_traits.h b/chromium/components/arc/bitmap/bitmap_struct_traits.h
new file mode 100644
index 00000000000..e4e61e3c1e4
--- /dev/null
+++ b/chromium/components/arc/bitmap/bitmap_struct_traits.h
@@ -0,0 +1,30 @@
+// 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 COMPONENT_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_
+#define COMPONENT_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_
+
+#include "components/arc/common/bitmap.mojom.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<arc::mojom::ArcBitmapDataView, SkBitmap> {
+ static const mojo::CArray<uint8_t> pixel_data(const SkBitmap& r) {
+ const SkImageInfo& info = r.info();
+ DCHECK_EQ(info.colorType(), kRGBA_8888_SkColorType);
+
+ return mojo::CArray<uint8_t>(
+ r.getSize(), r.getSize(), static_cast<uint8_t*>(r.getPixels()));
+ }
+ static uint32_t width(const SkBitmap& r) { return r.width(); }
+ static uint32_t height(const SkBitmap& r) { return r.height(); }
+
+ static bool Read(arc::mojom::ArcBitmapDataView data, SkBitmap* out);
+};
+
+}
+
+#endif // COMPONENT_ARC_BITMAP_BITMAP_STRUCT_TRAITS_H_
diff --git a/chromium/components/arc/bitmap/bitmap_type_converters.cc b/chromium/components/arc/bitmap/bitmap_type_converters.cc
deleted file mode 100644
index ab9e58b3bf2..00000000000
--- a/chromium/components/arc/bitmap/bitmap_type_converters.cc
+++ /dev/null
@@ -1,36 +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 "components/arc/bitmap/bitmap_type_converters.h"
-
-namespace mojo {
-
-SkBitmap TypeConverter<SkBitmap, arc::mojom::ArcBitmapPtr>::Convert(
- const arc::mojom::ArcBitmapPtr& arcBitmap) {
- if (arcBitmap.is_null())
- return SkBitmap();
-
- SkImageInfo info = SkImageInfo::Make(
- arcBitmap->width, arcBitmap->height,
- kRGBA_8888_SkColorType, kPremul_SkAlphaType);
- if (info.getSafeSize(info.minRowBytes()) > arcBitmap->pixel_data.size())
- return SkBitmap();
-
- // Create the SkBitmap object which wraps the arc bitmap pixels.
- SkBitmap bitmap;
- if (!bitmap.installPixels(info,
- const_cast<uint8_t*>(arcBitmap->pixel_data.storage().data()),
- info.minRowBytes())) {
- return SkBitmap();
- }
-
- // Copy the pixels with converting color type.
- SkBitmap nativeColorBitmap;
- if (!bitmap.copyTo(&nativeColorBitmap, kN32_SkColorType))
- return SkBitmap();
-
- return nativeColorBitmap;
-}
-
-} // namespace mojo
diff --git a/chromium/components/arc/bitmap/bitmap_type_converters.h b/chromium/components/arc/bitmap/bitmap_type_converters.h
deleted file mode 100644
index 815b96513e1..00000000000
--- a/chromium/components/arc/bitmap/bitmap_type_converters.h
+++ /dev/null
@@ -1,20 +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 COMPONENTS_ARC_BITMAP_BITMAP_TYPE_CONVERTERS_H_
-#define COMPONENTS_ARC_BITMAP_BITMAP_TYPE_CONVERTERS_H_
-
-#include "components/arc/common/bitmap.mojom.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace mojo {
-
-template <>
-struct TypeConverter<SkBitmap, arc::mojom::ArcBitmapPtr> {
- static SkBitmap Convert(const arc::mojom::ArcBitmapPtr& bitmap);
-};
-
-} // namespace mojo
-
-#endif // COMPONENTS_ARC_BITMAP_BITMAP_TYPE_CONVERTERS_H_
diff --git a/chromium/components/arc/bluetooth/arc_bluetooth_bridge.cc b/chromium/components/arc/bluetooth/arc_bluetooth_bridge.cc
index 4d7449e13df..ed9b0a0f809 100644
--- a/chromium/components/arc/bluetooth/arc_bluetooth_bridge.cc
+++ b/chromium/components/arc/bluetooth/arc_bluetooth_bridge.cc
@@ -11,6 +11,7 @@
#include <iomanip>
#include <string>
+#include <utility>
#include "base/bind.h"
#include "base/logging.h"
@@ -52,11 +53,11 @@ using device::BluetoothTransport;
using device::BluetoothUUID;
namespace {
-constexpr int32_t kMinBtleVersion = 1;
-constexpr int32_t kMinBtleNotifyVersion = 2;
-constexpr int32_t kMinGattServerVersion = 3;
-constexpr int32_t kMinAddrChangeVersion = 4;
-constexpr int32_t kMinSdpSupportVersion = 5;
+constexpr uint32_t kMinBtleVersion = 1;
+constexpr uint32_t kMinBtleNotifyVersion = 2;
+constexpr uint32_t kMinGattServerVersion = 3;
+constexpr uint32_t kMinAddrChangeVersion = 4;
+constexpr uint32_t kMinSdpSupportVersion = 5;
constexpr uint32_t kGattReadPermission =
BluetoothGattCharacteristic::Permission::PERMISSION_READ |
BluetoothGattCharacteristic::Permission::PERMISSION_READ_ENCRYPTED |
@@ -68,14 +69,26 @@ constexpr uint32_t kGattWritePermission =
BluetoothGattCharacteristic::Permission::
PERMISSION_WRITE_ENCRYPTED_AUTHENTICATED;
constexpr int32_t kInvalidGattAttributeHandle = -1;
+constexpr int32_t kInvalidAdvertisementHandle = -1;
// Bluetooth Specification Version 4.2 Vol 3 Part F Section 3.2.2
// An attribute handle of value 0xFFFF is known as the maximum attribute handle.
constexpr int32_t kMaxGattAttributeHandle = 0xFFFF;
// Bluetooth Specification Version 4.2 Vol 3 Part F Section 3.2.9
// The maximum length of an attribute value shall be 512 octets.
constexpr int kMaxGattAttributeLength = 512;
+// Copied from Android at system/bt/stack/btm/btm_ble_int.h
+// https://goo.gl/k7PM6u
+constexpr uint16_t kAndroidMBluetoothVersionNumber = 95;
// Bluetooth SDP Service Class ID List Attribute identifier
constexpr uint16_t kServiceClassIDListAttributeID = 0x0001;
+// Timeout for Bluetooth Discovery (scan)
+// 120 seconds is used here as the upper bound of the time need to do device
+// discovery once, 20 seconds for inquiry scan and 100 seconds for page scan
+// for 100 new devices.
+constexpr base::TimeDelta kDiscoveryTimeout = base::TimeDelta::FromSeconds(120);
+// From https://www.bluetooth.com/specifications/assigned-numbers/baseband
+// The Class of Device for generic computer.
+constexpr uint32_t kBluetoothComputerClass = 0x100;
using GattStatusCallback =
base::Callback<void(arc::mojom::BluetoothGattStatus)>;
@@ -102,7 +115,7 @@ arc::mojom::BluetoothGattDBElementPtr CreateGattDBElement(
arc::mojom::BluetoothGattDBElementPtr element =
arc::mojom::BluetoothGattDBElement::New();
element->type = type;
- element->uuid = arc::mojom::BluetoothUUID::From(attribute->GetUUID());
+ element->uuid = attribute->GetUUID();
element->id = element->attribute_handle = element->start_handle =
element->end_handle =
ConvertGattIdentifierToId(attribute->GetIdentifier());
@@ -181,20 +194,18 @@ bool IsGattOffsetValid(int offset) {
return 0 <= offset && offset < kMaxGattAttributeLength;
}
-// This is needed because Android only support UUID 16 bits in advertising data.
+// This is needed because Android only support UUID 16 bits in service data
+// section in advertising data
uint16_t GetUUID16(const BluetoothUUID& uuid) {
// Convert xxxxyyyy-xxxx-xxxx-xxxx-xxxxxxxxxxxx to int16 yyyy
return std::stoi(uuid.canonical_value().substr(4, 4), nullptr, 16);
}
-mojo::Array<arc::mojom::BluetoothPropertyPtr> GetDiscoveryTimeoutProperty(
- uint32_t timeout) {
+arc::mojom::BluetoothPropertyPtr GetDiscoveryTimeoutProperty(uint32_t timeout) {
arc::mojom::BluetoothPropertyPtr property =
arc::mojom::BluetoothProperty::New();
property->set_discovery_timeout(timeout);
- mojo::Array<arc::mojom::BluetoothPropertyPtr> properties;
- properties.push_back(std::move(property));
- return properties;
+ return property;
}
void OnCreateServiceRecordDone(const CreateSdpRecordCallback& callback,
@@ -246,13 +257,12 @@ namespace arc {
ArcBluetoothBridge::ArcBluetoothBridge(ArcBridgeService* bridge_service)
: ArcService(bridge_service), binding_(this), weak_factory_(this) {
if (BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
- VLOG(1) << "registering bluetooth adapter";
+ VLOG(1) << "Registering bluetooth adapter.";
BluetoothAdapterFactory::GetAdapter(base::Bind(
&ArcBluetoothBridge::OnAdapterInitialized, weak_factory_.GetWeakPtr()));
} else {
- VLOG(1) << "no bluetooth adapter available";
+ VLOG(1) << "No bluetooth adapter available.";
}
-
arc_bridge_service()->bluetooth()->AddObserver(this);
}
@@ -273,53 +283,69 @@ void ArcBluetoothBridge::OnAdapterInitialized(
// so our adapter uses BlueZ.
bluetooth_adapter_ =
static_cast<bluez::BluetoothAdapterBlueZ*>(adapter.get());
- bluetooth_adapter_->AddObserver(this);
+
+ // The ARC instance was ready before the Bluetooth adapter, hence we didn't
+ // register ourselves as an observer with it then. Since our adapter is
+ // ready, we should register it now.
+ if (!bluetooth_adapter_->HasObserver(this) &&
+ arc_bridge_service()->bluetooth()->has_instance()) {
+ bluetooth_adapter_->AddObserver(this);
+ }
}
void ArcBluetoothBridge::OnInstanceReady() {
mojom::BluetoothInstance* bluetooth_instance =
- arc_bridge_service()->bluetooth()->instance();
- if (!bluetooth_instance) {
- LOG(ERROR) << "OnBluetoothInstanceReady called, "
- << "but no bluetooth instance found";
- return;
- }
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod("Init");
+ DCHECK(bluetooth_instance);
+
bluetooth_instance->Init(binding_.CreateInterfacePtrAndBind());
-}
-void ArcBluetoothBridge::AdapterPoweredChanged(BluetoothAdapter* adapter,
- bool powered) {
- if (!HasBluetoothInstance())
- return;
+ // The Bluetooth adapter was ready before the ARC instance, hence we didn't
+ // register ourselves as an observer with it then. Since our instance is
+ // ready, we should register it now.
+ if (bluetooth_adapter_ && !bluetooth_adapter_->HasObserver(this))
+ bluetooth_adapter_->AddObserver(this);
+}
- // TODO(smbarber): Invoke EnableAdapter or DisableAdapter via ARC bridge
- // service.
+void ArcBluetoothBridge::OnInstanceClosed() {
+ if (bluetooth_adapter_)
+ bluetooth_adapter_->RemoveObserver(this);
}
-void ArcBluetoothBridge::DeviceAdded(BluetoothAdapter* adapter,
- BluetoothDevice* device) {
- if (!HasBluetoothInstance())
+void ArcBluetoothBridge::SendDevice(const BluetoothDevice* device) const {
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod("OnDeviceFound");
+ if (!bluetooth_instance)
return;
mojo::Array<mojom::BluetoothPropertyPtr> properties =
GetDeviceProperties(mojom::BluetoothPropertyType::ALL, device);
- arc_bridge_service()->bluetooth()->instance()->OnDeviceFound(
- std::move(properties));
+ bluetooth_instance->OnDeviceFound(std::move(properties));
- if (!CheckBluetoothInstanceVersion(kMinBtleVersion))
- return;
if (!(device->GetType() & device::BLUETOOTH_TRANSPORT_LE))
return;
- mojom::BluetoothAddressPtr addr =
- mojom::BluetoothAddress::From(device->GetAddress());
- int rssi = device->GetInquiryRSSI();
- mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data =
- GetAdvertisingData(device);
- arc_bridge_service()->bluetooth()->instance()->OnLEDeviceFound(
- std::move(addr), rssi, std::move(adv_data));
+ base::Optional<int8_t> rssi = device->GetInquiryRSSI();
+ mojom::BluetoothAddressPtr addr;
+
+ // We only want to send updated advertise data to Android only when we are
+ // scanning which is checked by the validity of rssi. Here are the 2 cases
+ // that we don't want to send updated advertise data to Android.
+ // 1) Cached found device and 2) rssi became invalid when we stop scanning.
+ if (rssi.has_value()) {
+ auto* btle_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnLEDeviceFound", kMinBtleVersion);
+ if (!btle_instance)
+ return;
+ mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data =
+ GetAdvertisingData(device);
+ addr = mojom::BluetoothAddress::From(device->GetAddress());
+ btle_instance->OnLEDeviceFound(std::move(addr), rssi.value(),
+ std::move(adv_data));
+ }
if (!device->IsConnected())
return;
@@ -328,8 +354,15 @@ void ArcBluetoothBridge::DeviceAdded(BluetoothAdapter* adapter,
OnGattConnectStateChanged(std::move(addr), true);
}
+void ArcBluetoothBridge::DeviceAdded(BluetoothAdapter* adapter,
+ BluetoothDevice* device) {
+ SendDevice(device);
+}
+
void ArcBluetoothBridge::DeviceChanged(BluetoothAdapter* adapter,
BluetoothDevice* device) {
+ SendDevice(device);
+
if (!(device->GetType() & device::BLUETOOTH_TRANSPORT_LE))
return;
@@ -366,18 +399,17 @@ void ArcBluetoothBridge::DeviceAddressChanged(BluetoothAdapter* adapter,
gatt_connection_cache_.erase(it);
gatt_connection_cache_.insert(device->GetAddress());
- if (!HasBluetoothInstance())
- return;
-
- if (!CheckBluetoothInstanceVersion(kMinAddrChangeVersion))
+ auto* btle_instance = arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnLEDeviceAddressChange", kMinAddrChangeVersion);
+ if (!btle_instance)
return;
mojom::BluetoothAddressPtr old_addr =
mojom::BluetoothAddress::From(old_address);
mojom::BluetoothAddressPtr new_addr =
mojom::BluetoothAddress::From(device->GetAddress());
- arc_bridge_service()->bluetooth()->instance()->OnLEDeviceAddressChange(
- std::move(old_addr), std::move(new_addr));
+ btle_instance->OnLEDeviceAddressChange(std::move(old_addr),
+ std::move(new_addr));
}
void ArcBluetoothBridge::DevicePairedChanged(BluetoothAdapter* adapter,
@@ -434,17 +466,16 @@ void ArcBluetoothBridge::GattServiceRemoved(
void ArcBluetoothBridge::GattServicesDiscovered(BluetoothAdapter* adapter,
BluetoothDevice* device) {
- if (!HasBluetoothInstance())
- return;
-
- if (!CheckBluetoothInstanceVersion(kMinBtleVersion))
+ auto* btle_instance = arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnSearchComplete", kMinBtleVersion);
+ if (!btle_instance)
return;
mojom::BluetoothAddressPtr addr =
mojom::BluetoothAddress::From(device->GetAddress());
- arc_bridge_service()->bluetooth()->instance()->OnSearchComplete(
- std::move(addr), mojom::BluetoothGattStatus::GATT_SUCCESS);
+ btle_instance->OnSearchComplete(std::move(addr),
+ mojom::BluetoothGattStatus::GATT_SUCCESS);
}
void ArcBluetoothBridge::GattDiscoveryCompleteForService(
@@ -487,10 +518,9 @@ void ArcBluetoothBridge::GattCharacteristicValueChanged(
BluetoothAdapter* adapter,
BluetoothRemoteGattCharacteristic* characteristic,
const std::vector<uint8_t>& value) {
- if (!HasBluetoothInstance())
- return;
-
- if (!CheckBluetoothInstanceVersion(kMinBtleNotifyVersion))
+ auto* btle_instance = arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnGattNotify", kMinBtleNotifyVersion);
+ if (!btle_instance)
return;
BluetoothRemoteGattService* service = characteristic->GetService();
@@ -502,15 +532,15 @@ void ArcBluetoothBridge::GattCharacteristicValueChanged(
service_id->is_primary = service->IsPrimary();
service_id->id = mojom::BluetoothGattID::New();
service_id->id->inst_id = ConvertGattIdentifierToId(service->GetIdentifier());
- service_id->id->uuid = mojom::BluetoothUUID::From(service->GetUUID());
+ service_id->id->uuid = service->GetUUID();
mojom::BluetoothGattIDPtr char_id = mojom::BluetoothGattID::New();
char_id->inst_id = ConvertGattIdentifierToId(characteristic->GetIdentifier());
- char_id->uuid = mojom::BluetoothUUID::From(characteristic->GetUUID());
+ char_id->uuid = characteristic->GetUUID();
- arc_bridge_service()->bluetooth()->instance()->OnGattNotify(
- std::move(address), std::move(service_id), std::move(char_id),
- true /* is_notify */, mojo::Array<uint8_t>::From(value));
+ btle_instance->OnGattNotify(std::move(address), std::move(service_id),
+ std::move(char_id), true /* is_notify */,
+ mojo::Array<uint8_t>::From(value));
}
void ArcBluetoothBridge::GattDescriptorValueChanged(
@@ -528,16 +558,17 @@ void ArcBluetoothBridge::OnGattAttributeReadRequest(
const ValueCallback& success_callback,
const ErrorCallback& error_callback) {
DCHECK(CalledOnValidThread());
- if (!HasBluetoothInstance() ||
- !CheckBluetoothInstanceVersion(kMinGattServerVersion) ||
- !IsGattOffsetValid(offset)) {
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "RequestGattRead", kMinGattServerVersion);
+ if (!bluetooth_instance || !IsGattOffsetValid(offset)) {
error_callback.Run();
return;
}
DCHECK(gatt_handle_.find(attribute->GetIdentifier()) != gatt_handle_.end());
- arc_bridge_service()->bluetooth()->instance()->RequestGattRead(
+ bluetooth_instance->RequestGattRead(
mojom::BluetoothAddress::From(device->GetAddress()),
gatt_handle_[attribute->GetIdentifier()], offset, false /* is_long */,
base::Bind(&OnGattServerRead, success_callback, error_callback));
@@ -552,16 +583,17 @@ void ArcBluetoothBridge::OnGattAttributeWriteRequest(
const base::Closure& success_callback,
const ErrorCallback& error_callback) {
DCHECK(CalledOnValidThread());
- if (!HasBluetoothInstance() ||
- !CheckBluetoothInstanceVersion(kMinGattServerVersion) ||
- !IsGattOffsetValid(offset)) {
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "RequestGattWrite", kMinGattServerVersion);
+ if (!bluetooth_instance || !IsGattOffsetValid(offset)) {
error_callback.Run();
return;
}
DCHECK(gatt_handle_.find(attribute->GetIdentifier()) != gatt_handle_.end());
- arc_bridge_service()->bluetooth()->instance()->RequestGattWrite(
+ bluetooth_instance->RequestGattWrite(
mojom::BluetoothAddress::From(device->GetAddress()),
gatt_handle_[attribute->GetIdentifier()], offset,
mojo::Array<uint8_t>::From(value),
@@ -644,14 +676,17 @@ void ArcBluetoothBridge::DisableAdapter(
void ArcBluetoothBridge::GetAdapterProperty(mojom::BluetoothPropertyType type) {
DCHECK(bluetooth_adapter_);
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnAdapterProperties");
+ if (!bluetooth_instance)
return;
mojo::Array<mojom::BluetoothPropertyPtr> properties =
GetAdapterProperties(type);
- arc_bridge_service()->bluetooth()->instance()->OnAdapterProperties(
- mojom::BluetoothStatus::SUCCESS, std::move(properties));
+ bluetooth_instance->OnAdapterProperties(mojom::BluetoothStatus::SUCCESS,
+ std::move(properties));
}
void ArcBluetoothBridge::OnSetDiscoverable(bool discoverable,
@@ -666,17 +701,9 @@ void ArcBluetoothBridge::OnSetDiscoverable(bool discoverable,
weak_factory_.GetWeakPtr(), false, 0));
}
- if (!HasBluetoothInstance())
- return;
-
- if (success) {
- arc_bridge_service()->bluetooth()->instance()->OnAdapterProperties(
- mojom::BluetoothStatus::SUCCESS, GetDiscoveryTimeoutProperty(timeout));
- } else {
- arc_bridge_service()->bluetooth()->instance()->OnAdapterProperties(
- mojom::BluetoothStatus::FAIL,
- mojo::Array<arc::mojom::BluetoothPropertyPtr>::New(0));
- }
+ auto status =
+ success ? mojom::BluetoothStatus::SUCCESS : mojom::BluetoothStatus::FAIL;
+ OnSetAdapterProperty(status, GetDiscoveryTimeoutProperty(timeout));
}
// Set discoverable state to on / off.
@@ -696,11 +723,10 @@ void ArcBluetoothBridge::SetDiscoverable(bool discoverable, uint32_t timeout) {
discoverable_off_timer_.GetCurrentDelay()) {
// Restart discoverable_off_timer_ if new timeout is greater
OnSetDiscoverable(true, true, timeout);
- } else if (HasBluetoothInstance()) {
+ } else {
// Just send message to Android if new timeout is lower.
- arc_bridge_service()->bluetooth()->instance()->OnAdapterProperties(
- mojom::BluetoothStatus::SUCCESS,
- GetDiscoveryTimeoutProperty(timeout));
+ OnSetAdapterProperty(mojom::BluetoothStatus::SUCCESS,
+ GetDiscoveryTimeoutProperty(timeout));
}
return;
}
@@ -713,26 +739,56 @@ void ArcBluetoothBridge::SetDiscoverable(bool discoverable, uint32_t timeout) {
weak_factory_.GetWeakPtr(), discoverable, false, timeout));
}
+void ArcBluetoothBridge::OnSetAdapterProperty(
+ mojom::BluetoothStatus status,
+ mojom::BluetoothPropertyPtr property) {
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnAdapterProperties");
+ DCHECK(bluetooth_instance);
+
+ auto properties = mojo::Array<arc::mojom::BluetoothPropertyPtr>::New(0);
+ properties.push_back(std::move(property));
+
+ bluetooth_instance->OnAdapterProperties(status, std::move(properties));
+}
+
void ArcBluetoothBridge::SetAdapterProperty(
mojom::BluetoothPropertyPtr property) {
DCHECK(bluetooth_adapter_);
- if (!HasBluetoothInstance())
- return;
if (property->is_discovery_timeout()) {
uint32_t discovery_timeout = property->get_discovery_timeout();
if (discovery_timeout > 0) {
SetDiscoverable(true, discovery_timeout);
} else {
- arc_bridge_service()->bluetooth()->instance()->OnAdapterProperties(
- mojom::BluetoothStatus::PARM_INVALID,
- mojo::Array<arc::mojom::BluetoothPropertyPtr>::New(0));
+ OnSetAdapterProperty(mojom::BluetoothStatus::PARM_INVALID,
+ std::move(property));
}
+ } else if (property->is_bdname()) {
+ auto property_clone = property.Clone();
+ bluetooth_adapter_->SetName(
+ property->get_bdname(),
+ base::Bind(&ArcBluetoothBridge::OnSetAdapterProperty,
+ weak_factory_.GetWeakPtr(), mojom::BluetoothStatus::SUCCESS,
+ base::Passed(&property)),
+ base::Bind(&ArcBluetoothBridge::OnSetAdapterProperty,
+ weak_factory_.GetWeakPtr(), mojom::BluetoothStatus::FAIL,
+ base::Passed(&property_clone)));
+ } else if (property->is_adapter_scan_mode()) {
+ // Android will set adapter scan mode in these 3 situations.
+ // 1) Set to BT_SCAN_MODE_NONE just before turning BT off.
+ // 2) Set to BT_SCAN_MODE_CONNECTABLE just after turning on.
+ // 3) Set to BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE just before set the
+ // discoverable timeout.
+ // Since turning BT off/on implied scan mode none/connectable and setting
+ // discovery timeout implied scan mode discoverable, we don't need to
+ // do anything here. We will just call success callback in this case.
+ OnSetAdapterProperty(mojom::BluetoothStatus::SUCCESS, std::move(property));
} else {
- // TODO(puthik) Implement other case.
- arc_bridge_service()->bluetooth()->instance()->OnAdapterProperties(
- mojom::BluetoothStatus::UNSUPPORTED,
- mojo::Array<arc::mojom::BluetoothPropertyPtr>::New(0));
+ // Android does not set any other property type.
+ OnSetAdapterProperty(mojom::BluetoothStatus::UNSUPPORTED,
+ std::move(property));
}
}
@@ -740,7 +796,10 @@ void ArcBluetoothBridge::GetRemoteDeviceProperty(
mojom::BluetoothAddressPtr remote_addr,
mojom::BluetoothPropertyType type) {
DCHECK(bluetooth_adapter_);
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnRemoteDeviceProperties");
+ if (!bluetooth_instance)
return;
std::string addr_str = remote_addr->To<std::string>();
@@ -755,26 +814,30 @@ void ArcBluetoothBridge::GetRemoteDeviceProperty(
status = mojom::BluetoothStatus::FAIL;
}
- arc_bridge_service()->bluetooth()->instance()->OnRemoteDeviceProperties(
- status, std::move(remote_addr), std::move(properties));
+ bluetooth_instance->OnRemoteDeviceProperties(status, std::move(remote_addr),
+ std::move(properties));
}
void ArcBluetoothBridge::SetRemoteDeviceProperty(
mojom::BluetoothAddressPtr remote_addr,
mojom::BluetoothPropertyPtr property) {
DCHECK(bluetooth_adapter_);
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnRemoteDeviceProperties");
+ if (!bluetooth_instance)
return;
- // TODO(smbarber): Implement SetRemoteDeviceProperty
- arc_bridge_service()->bluetooth()->instance()->OnRemoteDeviceProperties(
- mojom::BluetoothStatus::FAIL, std::move(remote_addr),
+ // Unsupported. Only used by Android hidden API, BluetoothDevice.SetAlias().
+ // And only Android Settings App / Android TV / NFC used that.
+ bluetooth_instance->OnRemoteDeviceProperties(
+ mojom::BluetoothStatus::UNSUPPORTED, std::move(remote_addr),
mojo::Array<mojom::BluetoothPropertyPtr>::New(0));
}
void ArcBluetoothBridge::GetRemoteServiceRecord(
mojom::BluetoothAddressPtr remote_addr,
- mojom::BluetoothUUIDPtr uuid) {
+ const BluetoothUUID& uuid) {
// TODO(smbarber): Implement GetRemoteServiceRecord
}
@@ -785,9 +848,13 @@ void ArcBluetoothBridge::GetRemoteServices(
void ArcBluetoothBridge::StartDiscovery() {
DCHECK(bluetooth_adapter_);
- // TODO(smbarber): Add timeout
+ DCHECK(CalledOnValidThread());
+
if (discovery_session_) {
- LOG(ERROR) << "Discovery session already running; leaving alone";
+ LOG(ERROR) << "Discovery session already running; Reset timeout.";
+ discovery_off_timer_.Start(FROM_HERE, kDiscoveryTimeout,
+ base::Bind(&ArcBluetoothBridge::CancelDiscovery,
+ weak_factory_.GetWeakPtr()));
SendCachedDevicesFound();
return;
}
@@ -832,24 +899,40 @@ void ArcBluetoothBridge::OnPoweredError(
void ArcBluetoothBridge::OnDiscoveryStarted(
std::unique_ptr<BluetoothDiscoverySession> session) {
- if (!HasBluetoothInstance())
+ DCHECK(CalledOnValidThread());
+
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnDiscoveryStateChanged");
+ if (!bluetooth_instance)
return;
discovery_session_ = std::move(session);
- arc_bridge_service()->bluetooth()->instance()->OnDiscoveryStateChanged(
+ // We need to set timer to turn device discovery off because of the difference
+ // between Android API (do device discovery once) and Chrome API (do device
+ // discovery until user turns it off).
+ discovery_off_timer_.Start(FROM_HERE, kDiscoveryTimeout,
+ base::Bind(&ArcBluetoothBridge::CancelDiscovery,
+ weak_factory_.GetWeakPtr()));
+
+ bluetooth_instance->OnDiscoveryStateChanged(
mojom::BluetoothDiscoveryState::STARTED);
SendCachedDevicesFound();
}
void ArcBluetoothBridge::OnDiscoveryStopped() {
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnDiscoveryStateChanged");
+ if (!bluetooth_instance)
return;
discovery_session_.reset();
+ discovery_off_timer_.Stop();
- arc_bridge_service()->bluetooth()->instance()->OnDiscoveryStateChanged(
+ bluetooth_instance->OnDiscoveryStateChanged(
mojom::BluetoothDiscoveryState::STOPPED);
}
@@ -940,8 +1023,8 @@ void ArcBluetoothBridge::StartLEScan() {
return;
}
bluetooth_adapter_->StartDiscoverySessionWithFilter(
- base::WrapUnique(
- new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE)),
+ base::MakeUnique<BluetoothDiscoveryFilter>(
+ device::BLUETOOTH_TRANSPORT_LE),
base::Bind(&ArcBluetoothBridge::OnDiscoveryStarted,
weak_factory_.GetWeakPtr()),
base::Bind(&ArcBluetoothBridge::OnDiscoveryError,
@@ -955,16 +1038,14 @@ void ArcBluetoothBridge::StopLEScan() {
void ArcBluetoothBridge::OnGattConnectStateChanged(
mojom::BluetoothAddressPtr addr,
bool connected) const {
- if (!HasBluetoothInstance())
- return;
-
- if (!CheckBluetoothInstanceVersion(kMinBtleVersion))
+ auto* btle_instance = arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnLEConnectionStateChange", kMinBtleVersion);
+ if (!btle_instance)
return;
DCHECK(addr);
- arc_bridge_service()->bluetooth()->instance()->OnLEConnectionStateChange(
- std::move(addr), connected);
+ btle_instance->OnLEConnectionStateChange(std::move(addr), connected);
}
void ArcBluetoothBridge::OnGattConnected(
@@ -997,7 +1078,10 @@ void ArcBluetoothBridge::OnGattDisconnected(
void ArcBluetoothBridge::ConnectLEDevice(
mojom::BluetoothAddressPtr remote_addr) {
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnLEConnectionStateChange", kMinBtleVersion);
+ if (!bluetooth_instance)
return;
BluetoothDevice* device =
@@ -1005,8 +1089,7 @@ void ArcBluetoothBridge::ConnectLEDevice(
DCHECK(device);
if (device->IsConnected()) {
- arc_bridge_service()->bluetooth()->instance()->OnLEConnectionStateChange(
- std::move(remote_addr), true);
+ bluetooth_instance->OnLEConnectionStateChange(std::move(remote_addr), true);
return;
}
@@ -1022,7 +1105,10 @@ void ArcBluetoothBridge::ConnectLEDevice(
void ArcBluetoothBridge::DisconnectLEDevice(
mojom::BluetoothAddressPtr remote_addr) {
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnLEConnectionStateChange", kMinBtleVersion);
+ if (!bluetooth_instance)
return;
BluetoothDevice* device =
@@ -1030,8 +1116,8 @@ void ArcBluetoothBridge::DisconnectLEDevice(
DCHECK(device);
if (!device->IsConnected()) {
- arc_bridge_service()->bluetooth()->instance()->OnLEConnectionStateChange(
- std::move(remote_addr), false);
+ bluetooth_instance->OnLEConnectionStateChange(std::move(remote_addr),
+ false);
return;
}
@@ -1044,7 +1130,10 @@ void ArcBluetoothBridge::DisconnectLEDevice(
}
void ArcBluetoothBridge::SearchService(mojom::BluetoothAddressPtr remote_addr) {
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnSearchComplete", kMinBtleVersion);
+ if (!bluetooth_instance)
return;
BluetoothDevice* device =
@@ -1053,7 +1142,7 @@ void ArcBluetoothBridge::SearchService(mojom::BluetoothAddressPtr remote_addr) {
// Call the callback if discovery is completed
if (device->IsGattServicesDiscoveryComplete()) {
- arc_bridge_service()->bluetooth()->instance()->OnSearchComplete(
+ bluetooth_instance->OnSearchComplete(
std::move(remote_addr), mojom::BluetoothGattStatus::GATT_SUCCESS);
return;
}
@@ -1081,8 +1170,8 @@ void ArcBluetoothBridge::OnStartLEListenError(
void ArcBluetoothBridge::StartLEListen(const StartLEListenCallback& callback) {
DCHECK(CalledOnValidThread());
std::unique_ptr<BluetoothAdvertisement::Data> adv_data =
- base::WrapUnique(new BluetoothAdvertisement::Data(
- BluetoothAdvertisement::ADVERTISEMENT_TYPE_BROADCAST));
+ base::MakeUnique<BluetoothAdvertisement::Data>(
+ BluetoothAdvertisement::ADVERTISEMENT_TYPE_BROADCAST);
bluetooth_adapter_->RegisterAdvertisement(
std::move(adv_data), base::Bind(&ArcBluetoothBridge::OnStartLEListenDone,
weak_factory_.GetWeakPtr(), callback),
@@ -1119,7 +1208,10 @@ void ArcBluetoothBridge::StopLEListen(const StopLEListenCallback& callback) {
}
void ArcBluetoothBridge::GetGattDB(mojom::BluetoothAddressPtr remote_addr) {
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod("OnGetGattDB",
+ kMinBtleVersion);
+ if (!bluetooth_instance)
return;
BluetoothDevice* device =
@@ -1159,8 +1251,7 @@ void ArcBluetoothBridge::GetGattDB(mojom::BluetoothAddressPtr remote_addr) {
}
}
- arc_bridge_service()->bluetooth()->instance()->OnGetGattDB(
- std::move(remote_addr), std::move(db));
+ bluetooth_instance->OnGetGattDB(std::move(remote_addr), std::move(db));
}
BluetoothRemoteGattCharacteristic* ArcBluetoothBridge::FindGattCharacteristic(
@@ -1176,13 +1267,12 @@ BluetoothRemoteGattCharacteristic* ArcBluetoothBridge::FindGattCharacteristic(
if (!device)
return nullptr;
- BluetoothRemoteGattService* service = FindGattAttributeByUuid(
- device->GetGattServices(), service_id->id->uuid.To<BluetoothUUID>());
+ BluetoothRemoteGattService* service =
+ FindGattAttributeByUuid(device->GetGattServices(), service_id->id->uuid);
if (!service)
return nullptr;
- return FindGattAttributeByUuid(service->GetCharacteristics(),
- char_id->uuid.To<BluetoothUUID>());
+ return FindGattAttributeByUuid(service->GetCharacteristics(), char_id->uuid);
}
BluetoothRemoteGattDescriptor* ArcBluetoothBridge::FindGattDescriptor(
@@ -1196,7 +1286,7 @@ BluetoothRemoteGattDescriptor* ArcBluetoothBridge::FindGattDescriptor(
return nullptr;
return FindGattAttributeByUuid(characteristic->GetDescriptors(),
- desc_id->uuid.To<BluetoothUUID>());
+ desc_id->uuid);
}
void ArcBluetoothBridge::ReadGattCharacteristic(
@@ -1335,8 +1425,31 @@ void ArcBluetoothBridge::ReadRemoteRssi(
const ReadRemoteRssiCallback& callback) {
BluetoothDevice* device =
bluetooth_adapter_->GetDevice(remote_addr->To<std::string>());
- int rssi = device->GetInquiryRSSI();
- callback.Run(rssi);
+ base::Optional<int8_t> rssi = device->GetInquiryRSSI();
+ callback.Run(rssi.value_or(mojom::kUnknownPower));
+}
+
+void ArcBluetoothBridge::OpenBluetoothSocket(
+ const OpenBluetoothSocketCallback& callback) {
+ base::ScopedFD sock(socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM));
+ if (!sock.is_valid()) {
+ LOG(ERROR) << "Failed to open socket.";
+ callback.Run(mojo::ScopedHandle());
+ return;
+ }
+ mojo::edk::ScopedPlatformHandle platform_handle{
+ mojo::edk::PlatformHandle(sock.release())};
+ MojoHandle wrapped_handle;
+ MojoResult wrap_result = mojo::edk::CreatePlatformHandleWrapper(
+ std::move(platform_handle), &wrapped_handle);
+ if (wrap_result != MOJO_RESULT_OK) {
+ LOG(ERROR) << "Failed to wrap handles. Closing: " << wrap_result;
+ callback.Run(mojo::ScopedHandle());
+ return;
+ }
+ mojo::ScopedHandle scoped_handle{mojo::Handle(wrapped_handle)};
+
+ callback.Run(std::move(scoped_handle));
}
bool ArcBluetoothBridge::IsGattServerAttributeHandleAvailable(int need) {
@@ -1373,7 +1486,7 @@ void ArcBluetoothBridge::AddService(mojom::BluetoothGattServiceIDPtr service_id,
}
base::WeakPtr<BluetoothLocalGattService> service =
BluetoothLocalGattService::Create(
- bluetooth_adapter_.get(), service_id->id->uuid.To<BluetoothUUID>(),
+ bluetooth_adapter_.get(), service_id->id->uuid,
service_id->is_primary, nullptr /* included_service */,
this /* delegate */);
callback.Run(CreateGattAttributeHandle(service.get()));
@@ -1381,7 +1494,7 @@ void ArcBluetoothBridge::AddService(mojom::BluetoothGattServiceIDPtr service_id,
void ArcBluetoothBridge::AddCharacteristic(
int32_t service_handle,
- mojom::BluetoothUUIDPtr uuid,
+ const BluetoothUUID& uuid,
int32_t properties,
int32_t permissions,
const AddCharacteristicCallback& callback) {
@@ -1393,7 +1506,7 @@ void ArcBluetoothBridge::AddCharacteristic(
}
base::WeakPtr<BluetoothLocalGattCharacteristic> characteristic =
BluetoothLocalGattCharacteristic::Create(
- uuid.To<BluetoothUUID>(), properties, permissions,
+ uuid, properties, permissions,
bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle]));
int32_t characteristic_handle =
CreateGattAttributeHandle(characteristic.get());
@@ -1402,7 +1515,7 @@ void ArcBluetoothBridge::AddCharacteristic(
}
void ArcBluetoothBridge::AddDescriptor(int32_t service_handle,
- mojom::BluetoothUUIDPtr uuid,
+ const BluetoothUUID& uuid,
int32_t permissions,
const AddDescriptorCallback& callback) {
DCHECK(CalledOnValidThread());
@@ -1412,7 +1525,7 @@ void ArcBluetoothBridge::AddDescriptor(int32_t service_handle,
}
// Chrome automatically adds a CCC Descriptor to a characteristic when needed.
// We will generate a bogus handle for Android.
- if (uuid.To<BluetoothUUID>() ==
+ if (uuid ==
BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid()) {
int32_t handle = GetNextGattServerAttributeHandle();
callback.Run(handle);
@@ -1439,8 +1552,7 @@ void ArcBluetoothBridge::AddDescriptor(int32_t service_handle,
DCHECK(characteristic);
base::WeakPtr<BluetoothLocalGattDescriptor> descriptor =
- BluetoothLocalGattDescriptor::Create(uuid.To<BluetoothUUID>(),
- permissions, characteristic);
+ BluetoothLocalGattDescriptor::Create(uuid, permissions, characteristic);
callback.Run(CreateGattAttributeHandle(descriptor.get()));
}
@@ -1486,31 +1598,8 @@ void ArcBluetoothBridge::SendIndication(
mojo::Array<uint8_t> value,
const SendIndicationCallback& callback) {}
-void ArcBluetoothBridge::OpenBluetoothSocket(
- const OpenBluetoothSocketCallback& callback) {
- base::ScopedFD sock(socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM));
- if (!sock.is_valid()) {
- LOG(ERROR) << "Failed to open socket.";
- callback.Run(mojo::ScopedHandle());
- return;
- }
- mojo::edk::ScopedPlatformHandle platform_handle{
- mojo::edk::PlatformHandle(sock.release())};
- MojoHandle wrapped_handle;
- MojoResult wrap_result = mojo::edk::CreatePlatformHandleWrapper(
- std::move(platform_handle), &wrapped_handle);
- if (wrap_result != MOJO_RESULT_OK) {
- LOG(ERROR) << "Failed to wrap handles. Closing: " << wrap_result;
- callback.Run(mojo::ScopedHandle());
- return;
- }
- mojo::ScopedHandle scoped_handle{mojo::Handle(wrapped_handle)};
-
- callback.Run(std::move(scoped_handle));
-}
-
void ArcBluetoothBridge::GetSdpRecords(mojom::BluetoothAddressPtr remote_addr,
- mojom::BluetoothUUIDPtr target_uuid) {
+ const BluetoothUUID& target_uuid) {
BluetoothDevice* device =
bluetooth_adapter_->GetDevice(remote_addr->To<std::string>());
@@ -1518,15 +1607,14 @@ void ArcBluetoothBridge::GetSdpRecords(mojom::BluetoothAddressPtr remote_addr,
static_cast<bluez::BluetoothDeviceBlueZ*>(device);
mojom::BluetoothAddressPtr remote_addr_clone = remote_addr.Clone();
- mojom::BluetoothUUIDPtr target_uuid_clone = target_uuid.Clone();
device_bluez->GetServiceRecords(
base::Bind(&ArcBluetoothBridge::OnGetServiceRecordsDone,
weak_factory_.GetWeakPtr(), base::Passed(&remote_addr),
- base::Passed(&target_uuid)),
+ target_uuid),
base::Bind(&ArcBluetoothBridge::OnGetServiceRecordsError,
weak_factory_.GetWeakPtr(), base::Passed(&remote_addr_clone),
- base::Passed(&target_uuid_clone)));
+ target_uuid));
}
void ArcBluetoothBridge::CreateSdpRecord(
@@ -1557,50 +1645,193 @@ void ArcBluetoothBridge::RemoveSdpRecord(
base::Bind(&OnRemoveServiceRecordError, callback));
}
+bool ArcBluetoothBridge::GetAdvertisementHandle(int32_t* adv_handle) {
+ for (int i = 0; i < kMaxAdvertisements; i++) {
+ if (advertisements_.find(i) == advertisements_.end()) {
+ *adv_handle = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+void ArcBluetoothBridge::ReserveAdvertisementHandle(
+ const ReserveAdvertisementHandleCallback& callback) {
+ DCHECK(CalledOnValidThread());
+ // Find an empty advertisement slot.
+ int32_t adv_handle;
+ if (!GetAdvertisementHandle(&adv_handle)) {
+ LOG(WARNING) << "Out of space for advertisement data";
+ callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE,
+ kInvalidAdvertisementHandle);
+ return;
+ }
+
+ // We have a handle. Put an entry in the map to reserve it.
+ advertisements_[adv_handle] = nullptr;
+
+ // The advertisement will be registered when we get the call
+ // to SetAdvertisingData. For now, just return the adv_handle.
+ callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS, adv_handle);
+}
+
+void ArcBluetoothBridge::BroadcastAdvertisement(
+ int32_t adv_handle,
+ std::unique_ptr<device::BluetoothAdvertisement::Data> advertisement,
+ const BroadcastAdvertisementCallback& callback) {
+ DCHECK(CalledOnValidThread());
+ if (advertisements_.find(adv_handle) == advertisements_.end()) {
+ callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE);
+ return;
+ }
+
+ if (!advertisements_[adv_handle]) {
+ OnReadyToRegisterAdvertisement(callback, adv_handle,
+ std::move(advertisement));
+ return;
+ }
+
+ advertisements_[adv_handle]->Unregister(
+ base::Bind(&ArcBluetoothBridge::OnReadyToRegisterAdvertisement,
+ weak_factory_.GetWeakPtr(), callback, adv_handle,
+ base::Passed(std::move(advertisement))),
+ base::Bind(&ArcBluetoothBridge::OnRegisterAdvertisementError,
+ weak_factory_.GetWeakPtr(), callback, adv_handle));
+}
+
+void ArcBluetoothBridge::ReleaseAdvertisementHandle(
+ int32_t adv_handle,
+ const ReleaseAdvertisementHandleCallback& callback) {
+ DCHECK(CalledOnValidThread());
+ if (advertisements_.find(adv_handle) == advertisements_.end()) {
+ callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE);
+ return;
+ }
+
+ if (!advertisements_[adv_handle]) {
+ advertisements_.erase(adv_handle);
+ callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS);
+ return;
+ }
+
+ advertisements_[adv_handle]->Unregister(
+ base::Bind(&ArcBluetoothBridge::OnUnregisterAdvertisementDone,
+ weak_factory_.GetWeakPtr(), callback, adv_handle),
+ base::Bind(&ArcBluetoothBridge::OnUnregisterAdvertisementError,
+ weak_factory_.GetWeakPtr(), callback, adv_handle));
+}
+
+void ArcBluetoothBridge::OnReadyToRegisterAdvertisement(
+ const BroadcastAdvertisementCallback& callback,
+ int32_t adv_handle,
+ std::unique_ptr<device::BluetoothAdvertisement::Data> data) {
+ DCHECK(CalledOnValidThread());
+ bluetooth_adapter_->RegisterAdvertisement(
+ std::move(data),
+ base::Bind(&ArcBluetoothBridge::OnRegisterAdvertisementDone,
+ weak_factory_.GetWeakPtr(), callback, adv_handle),
+ base::Bind(&ArcBluetoothBridge::OnRegisterAdvertisementError,
+ weak_factory_.GetWeakPtr(), callback, adv_handle));
+}
+
+void ArcBluetoothBridge::OnRegisterAdvertisementDone(
+ const BroadcastAdvertisementCallback& callback,
+ int32_t adv_handle,
+ scoped_refptr<BluetoothAdvertisement> advertisement) {
+ DCHECK(CalledOnValidThread());
+ advertisements_[adv_handle] = std::move(advertisement);
+ callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS);
+}
+
+void ArcBluetoothBridge::OnRegisterAdvertisementError(
+ const BroadcastAdvertisementCallback& callback,
+ int32_t adv_handle,
+ BluetoothAdvertisement::ErrorCode error_code) {
+ DCHECK(CalledOnValidThread());
+ LOG(WARNING) << "Failed to register advertisement for handle " << adv_handle
+ << ", error code = " << error_code;
+ advertisements_[adv_handle] = nullptr;
+ callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE);
+}
+
+void ArcBluetoothBridge::OnUnregisterAdvertisementDone(
+ const ReleaseAdvertisementHandleCallback& callback,
+ int32_t adv_handle) {
+ DCHECK(CalledOnValidThread());
+ advertisements_.erase(adv_handle);
+ callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS);
+}
+
+void ArcBluetoothBridge::OnUnregisterAdvertisementError(
+ const ReleaseAdvertisementHandleCallback& callback,
+ int32_t adv_handle,
+ BluetoothAdvertisement::ErrorCode error_code) {
+ DCHECK(CalledOnValidThread());
+ LOG(WARNING) << "Failed to unregister advertisement for handle " << adv_handle
+ << ", error code = " << error_code;
+ advertisements_.erase(adv_handle);
+ callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE);
+}
+
void ArcBluetoothBridge::OnDiscoveryError() {
LOG(WARNING) << "failed to change discovery state";
}
void ArcBluetoothBridge::OnPairing(mojom::BluetoothAddressPtr addr) const {
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnBondStateChanged");
+ if (!bluetooth_instance)
return;
- arc_bridge_service()->bluetooth()->instance()->OnBondStateChanged(
- mojom::BluetoothStatus::SUCCESS, std::move(addr),
- mojom::BluetoothBondState::BONDING);
+ bluetooth_instance->OnBondStateChanged(mojom::BluetoothStatus::SUCCESS,
+ std::move(addr),
+ mojom::BluetoothBondState::BONDING);
}
void ArcBluetoothBridge::OnPairedDone(mojom::BluetoothAddressPtr addr) const {
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnBondStateChanged");
+ if (!bluetooth_instance)
return;
- arc_bridge_service()->bluetooth()->instance()->OnBondStateChanged(
- mojom::BluetoothStatus::SUCCESS, std::move(addr),
- mojom::BluetoothBondState::BONDED);
+ bluetooth_instance->OnBondStateChanged(mojom::BluetoothStatus::SUCCESS,
+ std::move(addr),
+ mojom::BluetoothBondState::BONDED);
}
void ArcBluetoothBridge::OnPairedError(
mojom::BluetoothAddressPtr addr,
BluetoothDevice::ConnectErrorCode error_code) const {
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnBondStateChanged");
+ if (!bluetooth_instance)
return;
- arc_bridge_service()->bluetooth()->instance()->OnBondStateChanged(
- mojom::BluetoothStatus::FAIL, std::move(addr),
- mojom::BluetoothBondState::NONE);
+ bluetooth_instance->OnBondStateChanged(mojom::BluetoothStatus::FAIL,
+ std::move(addr),
+ mojom::BluetoothBondState::NONE);
}
void ArcBluetoothBridge::OnForgetDone(mojom::BluetoothAddressPtr addr) const {
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnBondStateChanged");
+ if (!bluetooth_instance)
return;
- arc_bridge_service()->bluetooth()->instance()->OnBondStateChanged(
- mojom::BluetoothStatus::SUCCESS, std::move(addr),
- mojom::BluetoothBondState::NONE);
+ bluetooth_instance->OnBondStateChanged(mojom::BluetoothStatus::SUCCESS,
+ std::move(addr),
+ mojom::BluetoothBondState::NONE);
}
void ArcBluetoothBridge::OnForgetError(mojom::BluetoothAddressPtr addr) const {
- if (!HasBluetoothInstance())
+ auto* bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnBondStateChanged");
+ if (!bluetooth_instance)
return;
BluetoothDevice* device =
@@ -1609,13 +1840,13 @@ void ArcBluetoothBridge::OnForgetError(mojom::BluetoothAddressPtr addr) const {
if (device && device->IsPaired()) {
bond_state = mojom::BluetoothBondState::BONDED;
}
- arc_bridge_service()->bluetooth()->instance()->OnBondStateChanged(
- mojom::BluetoothStatus::FAIL, std::move(addr), bond_state);
+ bluetooth_instance->OnBondStateChanged(mojom::BluetoothStatus::FAIL,
+ std::move(addr), bond_state);
}
mojo::Array<mojom::BluetoothPropertyPtr>
ArcBluetoothBridge::GetDeviceProperties(mojom::BluetoothPropertyType type,
- BluetoothDevice* device) const {
+ const BluetoothDevice* device) const {
mojo::Array<mojom::BluetoothPropertyPtr> properties;
if (!device) {
@@ -1625,9 +1856,7 @@ ArcBluetoothBridge::GetDeviceProperties(mojom::BluetoothPropertyType type,
if (type == mojom::BluetoothPropertyType::ALL ||
type == mojom::BluetoothPropertyType::BDNAME) {
mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New();
- // TODO(615720): Use the upcoming GetName (was GetDeviceName).
- btp->set_bdname(
- mojo::String::From(base::UTF16ToUTF8(device->GetNameForDisplay())));
+ btp->set_bdname(device->GetName() ? device->GetName().value() : nullptr);
properties.push_back(std::move(btp));
}
if (type == mojom::BluetoothPropertyType::ALL ||
@@ -1638,17 +1867,12 @@ ArcBluetoothBridge::GetDeviceProperties(mojom::BluetoothPropertyType type,
}
if (type == mojom::BluetoothPropertyType::ALL ||
type == mojom::BluetoothPropertyType::UUIDS) {
- mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New();
- std::vector<BluetoothUUID> uuids = device->GetUUIDs();
- mojo::Array<mojom::BluetoothUUIDPtr> uuid_results =
- mojo::Array<mojom::BluetoothUUIDPtr>::New(0);
-
- for (auto& uuid : uuids) {
- uuid_results.push_back(mojom::BluetoothUUID::From(uuid));
+ BluetoothDevice::UUIDSet uuids = device->GetUUIDs();
+ if (uuids.size() > 0) {
+ mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New();
+ btp->set_uuids(std::vector<BluetoothUUID>(uuids.begin(), uuids.end()));
+ properties.push_back(std::move(btp));
}
-
- btp->set_uuids(std::move(uuid_results));
- properties.push_back(std::move(btp));
}
if (type == mojom::BluetoothPropertyType::ALL ||
type == mojom::BluetoothPropertyType::CLASS_OF_DEVICE) {
@@ -1665,16 +1889,18 @@ ArcBluetoothBridge::GetDeviceProperties(mojom::BluetoothPropertyType type,
if (type == mojom::BluetoothPropertyType::ALL ||
type == mojom::BluetoothPropertyType::REMOTE_FRIENDLY_NAME) {
mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New();
- // TODO(615720): Use the upcoming GetName (was GetDeviceName).
btp->set_remote_friendly_name(
mojo::String::From(base::UTF16ToUTF8(device->GetNameForDisplay())));
properties.push_back(std::move(btp));
}
if (type == mojom::BluetoothPropertyType::ALL ||
type == mojom::BluetoothPropertyType::REMOTE_RSSI) {
- mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New();
- btp->set_remote_rssi(device->GetInquiryRSSI());
- properties.push_back(std::move(btp));
+ base::Optional<int8_t> rssi = device->GetInquiryRSSI();
+ if (rssi.has_value()) {
+ mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New();
+ btp->set_remote_rssi(rssi.value());
+ properties.push_back(std::move(btp));
+ }
}
// TODO(smbarber): Add remote version info
@@ -1702,18 +1928,20 @@ ArcBluetoothBridge::GetAdapterProperties(
}
if (type == mojom::BluetoothPropertyType::ALL ||
type == mojom::BluetoothPropertyType::UUIDS) {
- // TODO(smbarber): Fill in once GetUUIDs is available for the adapter.
+ mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New();
+ btp->set_uuids(
+ mojo::Array<BluetoothUUID>::From(bluetooth_adapter_->GetUUIDs()));
+ properties.push_back(std::move(btp));
}
if (type == mojom::BluetoothPropertyType::ALL ||
type == mojom::BluetoothPropertyType::CLASS_OF_DEVICE) {
- // TODO(smbarber): Populate with the actual adapter class
mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New();
- btp->set_device_class(0);
+ btp->set_device_class(kBluetoothComputerClass);
properties.push_back(std::move(btp));
}
if (type == mojom::BluetoothPropertyType::ALL ||
type == mojom::BluetoothPropertyType::TYPE_OF_DEVICE) {
- // TODO(smbarber): Populate with the actual adapter type
+ // Assume that all ChromeOS devices are dual mode Bluetooth device.
mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New();
btp->set_device_type(device::BLUETOOTH_TRANSPORT_DUAL);
properties.push_back(std::move(btp));
@@ -1737,7 +1965,7 @@ ArcBluetoothBridge::GetAdapterProperties(
mojo::Array<mojom::BluetoothAddressPtr> bonded_devices =
mojo::Array<mojom::BluetoothAddressPtr>::New(0);
- for (auto device : devices) {
+ for (auto* device : devices) {
if (device->IsPaired())
continue;
@@ -1755,6 +1983,26 @@ ArcBluetoothBridge::GetAdapterProperties(
btp->set_discovery_timeout(bluetooth_adapter_->GetDiscoverableTimeout());
properties.push_back(std::move(btp));
}
+ if (type == mojom::BluetoothPropertyType::ALL ||
+ type == mojom::BluetoothPropertyType::LOCAL_LE_FEATURES) {
+ // TODO(crbug.com/637171) Investigate all the le_features.
+ mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New();
+ mojom::BluetoothLocalLEFeaturesPtr le_features =
+ mojom::BluetoothLocalLEFeatures::New();
+ le_features->version_supported = kAndroidMBluetoothVersionNumber;
+ le_features->local_privacy_enabled = 0;
+ le_features->max_adv_instance = kMaxAdvertisements;
+ le_features->rpa_offload_supported = 0;
+ le_features->max_irk_list_size = 0;
+ le_features->max_adv_filter_supported = 0;
+ le_features->activity_energy_info_supported = 0;
+ le_features->scan_result_storage_size = 0;
+ le_features->total_trackable_advertisers = 0;
+ le_features->extended_scan_support = false;
+ le_features->debug_logging_supported = false;
+ btp->set_local_le_features(std::move(le_features));
+ properties.push_back(std::move(btp));
+ }
return properties;
}
@@ -1762,50 +2010,46 @@ ArcBluetoothBridge::GetAdapterProperties(
// Android support 5 types of Advertising Data.
// However Chrome didn't expose AdvertiseFlag and ManufacturerData.
// So we will only expose local_name, service_uuids and service_data.
-// Note that we need to use UUID 16 bits because Android does not support
-// UUID 128 bits.
+// Note that we need to use UUID 16 bits in service_data section
+// because Android does not support UUID 128 bits there.
// TODO(crbug.com/618442) Make Chrome expose missing data.
mojo::Array<mojom::BluetoothAdvertisingDataPtr>
-ArcBluetoothBridge::GetAdvertisingData(BluetoothDevice* device) const {
+ArcBluetoothBridge::GetAdvertisingData(const BluetoothDevice* device) const {
mojo::Array<mojom::BluetoothAdvertisingDataPtr> advertising_data;
// LocalName
mojom::BluetoothAdvertisingDataPtr local_name =
mojom::BluetoothAdvertisingData::New();
- local_name->set_local_name(base::UTF16ToUTF8(device->GetNameForDisplay()));
+ local_name->set_local_name(device->GetName() ? device->GetName().value()
+ : nullptr);
advertising_data.push_back(std::move(local_name));
// ServiceUuid
- BluetoothDevice::UUIDList uuid_list = device->GetUUIDs();
- if (uuid_list.size() > 0) {
- mojom::BluetoothAdvertisingDataPtr service_uuids_16 =
+ const BluetoothDevice::UUIDSet& uuid_set = device->GetUUIDs();
+ if (uuid_set.size() > 0) {
+ mojom::BluetoothAdvertisingDataPtr service_uuids =
mojom::BluetoothAdvertisingData::New();
- mojo::Array<uint16_t> uuid16s;
- for (auto& uuid : uuid_list) {
- uuid16s.push_back(GetUUID16(uuid));
- }
- service_uuids_16->set_service_uuids_16(std::move(uuid16s));
- advertising_data.push_back(std::move(service_uuids_16));
+ service_uuids->set_service_uuids(mojo::Array<BluetoothUUID>::From(
+ std::vector<BluetoothUUID>(uuid_set.begin(), uuid_set.end())));
+ advertising_data.push_back(std::move(service_uuids));
}
// Service data
- for (auto& uuid : device->GetServiceDataUUIDs()) {
- base::BinaryValue* data = device->GetServiceData(uuid);
- if (data->GetSize() == 0)
- continue;
- std::string data_str;
- if (!data->GetAsString(&data_str))
- continue;
-
+ for (const BluetoothUUID& uuid : device->GetServiceDataUUIDs()) {
mojom::BluetoothAdvertisingDataPtr service_data_element =
mojom::BluetoothAdvertisingData::New();
mojom::BluetoothServiceDataPtr service_data =
mojom::BluetoothServiceData::New();
+ // Android only supports UUID 16 bit here.
service_data->uuid_16bit = GetUUID16(uuid);
- for (auto& c : data_str) {
- service_data->data.push_back(c);
- }
+
+ const std::vector<uint8_t>* data = device->GetServiceDataForUUID(uuid);
+ DCHECK(data != nullptr);
+
+ std::vector<uint8_t> data_copy = *data;
+ service_data->data.Swap(&data_copy);
+
service_data_element->set_service_data(std::move(service_data));
advertising_data.push_back(std::move(service_data_element));
}
@@ -1814,73 +2058,34 @@ ArcBluetoothBridge::GetAdvertisingData(BluetoothDevice* device) const {
}
void ArcBluetoothBridge::SendCachedDevicesFound() const {
- // Send devices that have already been discovered, but aren't connected.
- if (!HasBluetoothInstance())
- return;
+ DCHECK(bluetooth_adapter_);
+ // Send devices that have already been discovered, but aren't connected.
BluetoothAdapter::DeviceList devices = bluetooth_adapter_->GetDevices();
- for (auto device : devices) {
+ for (auto* device : devices) {
if (device->IsPaired())
continue;
- mojo::Array<mojom::BluetoothPropertyPtr> properties =
- GetDeviceProperties(mojom::BluetoothPropertyType::ALL, device);
-
- arc_bridge_service()->bluetooth()->instance()->OnDeviceFound(
- std::move(properties));
-
- if (arc_bridge_service()->bluetooth()->version() >= kMinBtleVersion) {
- mojom::BluetoothAddressPtr addr =
- mojom::BluetoothAddress::From(device->GetAddress());
- int rssi = device->GetInquiryRSSI();
- mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data =
- GetAdvertisingData(device);
- arc_bridge_service()->bluetooth()->instance()->OnLEDeviceFound(
- std::move(addr), rssi, std::move(adv_data));
- }
+ SendDevice(device);
}
}
-bool ArcBluetoothBridge::HasBluetoothInstance() const {
- if (!arc_bridge_service()->bluetooth()->instance()) {
- LOG(WARNING) << "no Bluetooth instance available";
- return false;
- }
-
- return true;
-}
-
void ArcBluetoothBridge::SendCachedPairedDevices() const {
DCHECK(bluetooth_adapter_);
- if (!HasBluetoothInstance())
- return;
BluetoothAdapter::DeviceList devices = bluetooth_adapter_->GetDevices();
- for (auto device : devices) {
+ for (auto* device : devices) {
if (!device->IsPaired())
continue;
- mojo::Array<mojom::BluetoothPropertyPtr> properties =
- GetDeviceProperties(mojom::BluetoothPropertyType::ALL, device);
-
- arc_bridge_service()->bluetooth()->instance()->OnDeviceFound(
- std::move(properties));
-
- mojom::BluetoothAddressPtr addr =
- mojom::BluetoothAddress::From(device->GetAddress());
-
- if (arc_bridge_service()->bluetooth()->version() >= kMinBtleVersion) {
- int rssi = device->GetInquiryRSSI();
- mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data =
- GetAdvertisingData(device);
- arc_bridge_service()->bluetooth()->instance()->OnLEDeviceFound(
- addr->Clone(), rssi, std::move(adv_data));
- }
+ SendDevice(device);
// OnBondStateChanged must be called with mojom::BluetoothBondState::BONDING
// to make sure the bond state machine on Android is ready to take the
// pair-done event. Otherwise the pair-done event will be dropped as an
// invalid change of paired status.
+ mojom::BluetoothAddressPtr addr =
+ mojom::BluetoothAddress::From(device->GetAddress());
OnPairing(addr->Clone());
OnPairedDone(std::move(addr));
}
@@ -1888,28 +2093,27 @@ void ArcBluetoothBridge::SendCachedPairedDevices() const {
void ArcBluetoothBridge::OnGetServiceRecordsDone(
mojom::BluetoothAddressPtr remote_addr,
- mojom::BluetoothUUIDPtr target_uuid,
+ const BluetoothUUID& target_uuid,
const std::vector<bluez::BluetoothServiceRecordBlueZ>& records_bluez) {
- if (!CheckBluetoothInstanceVersion(kMinSdpSupportVersion))
- return;
-
- if (!HasBluetoothInstance())
+ auto* sdp_bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnGetSdpRecords", kMinSdpSupportVersion);
+ if (!sdp_bluetooth_instance)
return;
- arc_bridge_service()->bluetooth()->instance()->OnGetSdpRecords(
- mojom::BluetoothStatus::SUCCESS, std::move(remote_addr),
- std::move(target_uuid),
+ sdp_bluetooth_instance->OnGetSdpRecords(
+ mojom::BluetoothStatus::SUCCESS, std::move(remote_addr), target_uuid,
mojo::Array<mojom::BluetoothSdpRecordPtr>::From(records_bluez));
}
void ArcBluetoothBridge::OnGetServiceRecordsError(
mojom::BluetoothAddressPtr remote_addr,
- mojom::BluetoothUUIDPtr target_uuid,
+ const BluetoothUUID& target_uuid,
bluez::BluetoothServiceRecordBlueZ::ErrorCode error_code) {
- if (!HasBluetoothInstance())
- return;
-
- if (!CheckBluetoothInstanceVersion(kMinSdpSupportVersion))
+ auto* sdp_bluetooth_instance =
+ arc_bridge_service()->bluetooth()->GetInstanceForMethod(
+ "OnGetSdpRecords", kMinSdpSupportVersion);
+ if (!sdp_bluetooth_instance)
return;
mojom::BluetoothStatus status;
@@ -1927,21 +2131,11 @@ void ArcBluetoothBridge::OnGetServiceRecordsError(
break;
}
- arc_bridge_service()->bluetooth()->instance()->OnGetSdpRecords(
- status, std::move(remote_addr), std::move(target_uuid),
+ sdp_bluetooth_instance->OnGetSdpRecords(
+ status, std::move(remote_addr), target_uuid,
mojo::Array<mojom::BluetoothSdpRecordPtr>::New(0));
}
-bool ArcBluetoothBridge::CheckBluetoothInstanceVersion(
- uint32_t version_need) const {
- uint32_t version = arc_bridge_service()->bluetooth()->version();
- if (version >= version_need)
- return true;
- LOG(WARNING) << "Bluetooth instance is too old (version " << version
- << ") need version " << version_need;
- return false;
-}
-
bool ArcBluetoothBridge::CalledOnValidThread() {
return thread_checker_.CalledOnValidThread();
}
diff --git a/chromium/components/arc/bluetooth/arc_bluetooth_bridge.h b/chromium/components/arc/bluetooth/arc_bluetooth_bridge.h
index 704acfcf1e0..87ba1142bd0 100644
--- a/chromium/components/arc/bluetooth/arc_bluetooth_bridge.h
+++ b/chromium/components/arc/bluetooth/arc_bluetooth_bridge.h
@@ -21,6 +21,7 @@
#include "components/arc/instance_holder.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/bluetooth_advertisement.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "device/bluetooth/bluetooth_local_gatt_service.h"
@@ -47,13 +48,11 @@ class ArcBluetoothBridge
// Overridden from InstanceHolder<mojom::BluetoothInstance>::Observer:
void OnInstanceReady() override;
+ void OnInstanceClosed() override;
void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter);
// Overridden from device::BluetoothAdadpter::Observer
- void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
- bool powered) override;
-
void DeviceAdded(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override;
@@ -166,7 +165,7 @@ class ArcBluetoothBridge
void SetRemoteDeviceProperty(mojom::BluetoothAddressPtr remote_addr,
mojom::BluetoothPropertyPtr property) override;
void GetRemoteServiceRecord(mojom::BluetoothAddressPtr remote_addr,
- mojom::BluetoothUUIDPtr uuid) override;
+ const device::BluetoothUUID& uuid) override;
void GetRemoteServices(mojom::BluetoothAddressPtr remote_addr) override;
@@ -226,6 +225,9 @@ class ArcBluetoothBridge
void ReadRemoteRssi(mojom::BluetoothAddressPtr remote_addr,
const ReadRemoteRssiCallback& callback) override;
+ void OpenBluetoothSocket(
+ const OpenBluetoothSocketCallback& callback) override;
+
// Bluetooth Mojo host interface - Bluetooth Gatt Server functions
// Android counterpart link:
// https://source.android.com/devices/halref/bt__gatt__server_8h.html
@@ -238,14 +240,14 @@ class ArcBluetoothBridge
const AddServiceCallback& callback) override;
// Add a characteristic to a service and pass the characteristic handle back.
void AddCharacteristic(int32_t service_handle,
- mojom::BluetoothUUIDPtr uuid,
+ const device::BluetoothUUID& uuid,
int32_t properties,
int32_t permissions,
const AddCharacteristicCallback& callback) override;
// Add a descriptor to the last characteristic added to the given service
// and pass the descriptor handle back.
void AddDescriptor(int32_t service_handle,
- mojom::BluetoothUUIDPtr uuid,
+ const device::BluetoothUUID& uuid,
int32_t permissions,
const AddDescriptorCallback& callback) override;
// Start a local service.
@@ -264,17 +266,25 @@ class ArcBluetoothBridge
mojo::Array<uint8_t> value,
const SendIndicationCallback& callback) override;
- void OpenBluetoothSocket(
- const OpenBluetoothSocketCallback& callback) override;
-
// Bluetooth Mojo host interface - Bluetooth SDP functions
void GetSdpRecords(mojom::BluetoothAddressPtr remote_addr,
- mojom::BluetoothUUIDPtr target_uuid) override;
+ const device::BluetoothUUID& target_uuid) override;
void CreateSdpRecord(mojom::BluetoothSdpRecordPtr record_mojo,
const CreateSdpRecordCallback& callback) override;
void RemoveSdpRecord(uint32_t service_handle,
const RemoveSdpRecordCallback& callback) override;
+ // Set up or disable multiple advertising.
+ void ReserveAdvertisementHandle(
+ const ReserveAdvertisementHandleCallback& callback) override;
+ void BroadcastAdvertisement(
+ int32_t adv_handle,
+ std::unique_ptr<device::BluetoothAdvertisement::Data> advertisement,
+ const BroadcastAdvertisementCallback& callback) override;
+ void ReleaseAdvertisementHandle(
+ int32_t adv_handle,
+ const ReleaseAdvertisementHandleCallback& callback) override;
+
// Chrome observer callbacks
void OnPoweredOn(
const base::Callback<void(mojom::BluetoothAdapterState)>& callback) const;
@@ -323,15 +333,13 @@ class ArcBluetoothBridge
private:
mojo::Array<mojom::BluetoothPropertyPtr> GetDeviceProperties(
mojom::BluetoothPropertyType type,
- device::BluetoothDevice* device) const;
+ const device::BluetoothDevice* device) const;
mojo::Array<mojom::BluetoothPropertyPtr> GetAdapterProperties(
mojom::BluetoothPropertyType type) const;
mojo::Array<mojom::BluetoothAdvertisingDataPtr> GetAdvertisingData(
- device::BluetoothDevice* device) const;
+ const device::BluetoothDevice* device) const;
void SendCachedDevicesFound() const;
- bool HasBluetoothInstance() const;
- bool CheckBluetoothInstanceVersion(uint32_t version_need) const;
device::BluetoothRemoteGattCharacteristic* FindGattCharacteristic(
mojom::BluetoothAddressPtr remote_addr,
@@ -374,13 +382,54 @@ class ArcBluetoothBridge
void OnGetServiceRecordsDone(
mojom::BluetoothAddressPtr remote_addr,
- mojom::BluetoothUUIDPtr target_uuid,
+ const device::BluetoothUUID& target_uuid,
const std::vector<bluez::BluetoothServiceRecordBlueZ>& records_bluez);
void OnGetServiceRecordsError(
mojom::BluetoothAddressPtr remote_addr,
- mojom::BluetoothUUIDPtr target_uuid,
+ const device::BluetoothUUID& target_uuid,
bluez::BluetoothServiceRecordBlueZ::ErrorCode error_code);
+ void OnSetAdapterProperty(mojom::BluetoothStatus success,
+ mojom::BluetoothPropertyPtr property);
+
+ // Callbacks for managing advertisements registered from the instance.
+
+ // Called when we have an open slot in the advertisement map and want to
+ // register the advertisement given by |data| for handle |adv_handle|.
+ void OnReadyToRegisterAdvertisement(
+ const BroadcastAdvertisementCallback& callback,
+ int32_t adv_handle,
+ std::unique_ptr<device::BluetoothAdvertisement::Data> data);
+ // Called when we've successfully registered a new advertisement for
+ // handle |adv_handle|.
+ void OnRegisterAdvertisementDone(
+ const BroadcastAdvertisementCallback& callback,
+ int32_t adv_handle,
+ scoped_refptr<device::BluetoothAdvertisement> advertisement);
+ // Called when the attempt to register an advertisement for handle
+ // |adv_handle| has failed. |adv_handle| remains reserved, but no
+ // advertisement is associated with it.
+ void OnRegisterAdvertisementError(
+ const BroadcastAdvertisementCallback& callback,
+ int32_t adv_handle,
+ device::BluetoothAdvertisement::ErrorCode error_code);
+ // Both of the following are called after we've tried to unregister
+ // the advertisement for |adv_handle|. Either way, we will no
+ // longer be broadcasting this advertisement, so in either case, the
+ // handle can be released.
+ void OnUnregisterAdvertisementDone(
+ const ReleaseAdvertisementHandleCallback& callback,
+ int32_t adv_handle);
+ void OnUnregisterAdvertisementError(
+ const ReleaseAdvertisementHandleCallback& callback,
+ int32_t adv_handle,
+ device::BluetoothAdvertisement::ErrorCode error_code);
+ // Find the next free advertisement handle and put it in *adv_handle,
+ // or return false if the advertisement map is full.
+ bool GetAdvertisementHandle(int32_t* adv_handle);
+
+ void SendDevice(const device::BluetoothDevice* device) const;
+
bool CalledOnValidThread();
mojo::Binding<mojom::BluetoothHost> binding_;
@@ -407,9 +456,28 @@ class ArcBluetoothBridge
std::unordered_map<std::string,
std::unique_ptr<device::BluetoothGattConnection>>
gatt_connections_;
+ // Timer to turn discovery off.
+ base::OneShotTimer discovery_off_timer_;
// Timer to turn adapter discoverable off.
base::OneShotTimer discoverable_off_timer_;
+ // Holds advertising data registered by the instance.
+ //
+ // When a handle is reserved, an entry is placed into the advertisements_
+ // map. This entry is not yet associated with a device::BluetoothAdvertisement
+ // because the instance hasn't sent us any advertising data yet, so its
+ // mapped value is nullptr until that happens. Thus we have three states for a
+ // handle:
+ // * unmapped -> free
+ // * mapped to nullptr -> reserved, awaiting data
+ // * mapped to a device::BluetoothAdvertisement -> in use, and the mapped
+ // BluetoothAdvertisement is currently registered with the adapter.
+ // TODO(crbug.com/658385) Change back to 5 when we support setting signal
+ // strength per each advertisement slot.
+ enum { kMaxAdvertisements = 1 };
+ std::map<int32_t, scoped_refptr<device::BluetoothAdvertisement>>
+ advertisements_;
+
base::ThreadChecker thread_checker_;
// WeakPtrFactory to use for callbacks.
diff --git a/chromium/components/arc/bluetooth/arc_bluetooth_bridge_unittest.cc b/chromium/components/arc/bluetooth/arc_bluetooth_bridge_unittest.cc
new file mode 100644
index 00000000000..31c2003f11b
--- /dev/null
+++ b/chromium/components/arc/bluetooth/arc_bluetooth_bridge_unittest.cc
@@ -0,0 +1,331 @@
+// 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 "components/arc/bluetooth/arc_bluetooth_bridge.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "components/arc/bluetooth/bluetooth_type_converters.h"
+#include "components/arc/common/bluetooth.mojom.h"
+#include "components/arc/test/fake_arc_bridge_service.h"
+#include "components/arc/test/fake_bluetooth_instance.h"
+#include "device/bluetooth/dbus/bluez_dbus_manager.h"
+#include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_device_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_gatt_service_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_le_advertising_manager_client.h"
+#include "mojo/public/cpp/bindings/array.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+constexpr int16_t kTestRssi = -50;
+constexpr int16_t kTestRssi2 = -70;
+}
+
+namespace arc {
+
+constexpr int kFailureAdvHandle = -1;
+
+class ArcBluetoothBridgeTest : public testing::Test {
+ protected:
+ void AddTestDevice() {
+ bluez::BluezDBusManager* dbus_manager = bluez::BluezDBusManager::Get();
+ auto* fake_bluetooth_device_client =
+ static_cast<bluez::FakeBluetoothDeviceClient*>(
+ dbus_manager->GetBluetoothDeviceClient());
+ auto* fake_bluetooth_gatt_service_client =
+ static_cast<bluez::FakeBluetoothGattServiceClient*>(
+ dbus_manager->GetBluetoothGattServiceClient());
+ auto* fake_bluetooth_gatt_characteristic_client =
+ static_cast<bluez::FakeBluetoothGattCharacteristicClient*>(
+ dbus_manager->GetBluetoothGattCharacteristicClient());
+
+ fake_bluetooth_device_client->CreateDevice(
+ dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
+ fake_bluetooth_gatt_service_client->ExposeHeartRateService(
+ dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
+ fake_bluetooth_gatt_characteristic_client->ExposeHeartRateCharacteristics(
+ fake_bluetooth_gatt_service_client->GetHeartRateServicePath());
+
+ ChangeTestDeviceRssi(kTestRssi);
+ }
+
+ void ChangeTestDeviceRssi(uint16_t rssi) {
+ bluez::BluezDBusManager* dbus_manager = bluez::BluezDBusManager::Get();
+ auto* fake_bluetooth_device_client =
+ static_cast<bluez::FakeBluetoothDeviceClient*>(
+ dbus_manager->GetBluetoothDeviceClient());
+ fake_bluetooth_device_client->UpdateDeviceRSSI(
+ dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath),
+ rssi);
+ }
+
+ void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter) {
+ adapter_ = adapter;
+ get_adapter_run_loop_.Quit();
+ }
+
+ void SetUp() override {
+ std::unique_ptr<bluez::BluezDBusManagerSetter> dbus_setter =
+ bluez::BluezDBusManager::GetSetterForTesting();
+ auto fake_bluetooth_device_client =
+ base::MakeUnique<bluez::FakeBluetoothDeviceClient>();
+ fake_bluetooth_device_client->RemoveAllDevices();
+ dbus_setter->SetBluetoothDeviceClient(
+ std::move(fake_bluetooth_device_client));
+ dbus_setter->SetBluetoothGattServiceClient(
+ base::MakeUnique<bluez::FakeBluetoothGattServiceClient>());
+ dbus_setter->SetBluetoothGattCharacteristicClient(
+ base::MakeUnique<bluez::FakeBluetoothGattCharacteristicClient>());
+ dbus_setter->SetBluetoothGattDescriptorClient(
+ base::MakeUnique<bluez::FakeBluetoothGattDescriptorClient>());
+
+ fake_arc_bridge_service_.reset(new FakeArcBridgeService());
+ fake_bluetooth_instance_.reset(new FakeBluetoothInstance());
+ fake_arc_bridge_service_->bluetooth()->SetInstance(
+ fake_bluetooth_instance_.get(), 2);
+ arc_bluetooth_bridge_.reset(
+ new ArcBluetoothBridge(fake_arc_bridge_service_.get()));
+
+ device::BluetoothAdapterFactory::GetAdapter(base::Bind(
+ &ArcBluetoothBridgeTest::OnAdapterInitialized, base::Unretained(this)));
+ // We will quit the loop once we get the adapter.
+ get_adapter_run_loop_.Run();
+ }
+
+ // Helper methods for multi advertisement tests.
+ int32_t ReserveAdvertisementHandle() {
+ constexpr int kSentinelHandle = -2;
+ last_adv_handle_ = kSentinelHandle;
+ arc_bluetooth_bridge_->ReserveAdvertisementHandle(
+ base::Bind(&ArcBluetoothBridgeTest::ReserveAdvertisementHandleCallback,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+ // Make sure the callback was called.
+ EXPECT_NE(kSentinelHandle, last_adv_handle_);
+ return last_adv_handle_;
+ }
+
+ mojom::BluetoothGattStatus BroadcastAdvertisement(
+ int adv_handle,
+ std::unique_ptr<device::BluetoothAdvertisement::Data> data) {
+ last_status_ = mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED;
+ arc_bluetooth_bridge_->BroadcastAdvertisement(
+ adv_handle, std::move(data),
+ base::Bind(&ArcBluetoothBridgeTest::StatusSetterCallback,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_NE(mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED,
+ last_status_);
+ return last_status_;
+ }
+
+ mojom::BluetoothGattStatus ReleaseAdvertisementHandle(int adv_handle) {
+ last_status_ = mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED;
+ arc_bluetooth_bridge_->ReleaseAdvertisementHandle(
+ adv_handle, base::Bind(&ArcBluetoothBridgeTest::StatusSetterCallback,
+ base::Unretained(this)));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_NE(mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED,
+ last_status_);
+ return last_status_;
+ }
+
+ void ReserveAdvertisementHandleCallback(mojom::BluetoothGattStatus status,
+ int32_t adv_handle) {
+ if (status == mojom::BluetoothGattStatus::GATT_FAILURE)
+ last_adv_handle_ = kFailureAdvHandle;
+ else
+ last_adv_handle_ = adv_handle;
+ }
+
+ void StatusSetterCallback(mojom::BluetoothGattStatus status) {
+ last_status_ = status;
+ }
+
+ int NumActiveAdvertisements() {
+ bluez::FakeBluetoothLEAdvertisingManagerClient* adv_client =
+ static_cast<bluez::FakeBluetoothLEAdvertisingManagerClient*>(
+ bluez::BluezDBusManager::Get()
+ ->GetBluetoothLEAdvertisingManagerClient());
+ return adv_client->currently_registered();
+ }
+
+ int last_adv_handle_;
+ mojom::BluetoothGattStatus last_status_;
+
+ std::unique_ptr<FakeArcBridgeService> fake_arc_bridge_service_;
+ std::unique_ptr<FakeBluetoothInstance> fake_bluetooth_instance_;
+ std::unique_ptr<ArcBluetoothBridge> arc_bluetooth_bridge_;
+ scoped_refptr<device::BluetoothAdapter> adapter_;
+ base::MessageLoop message_loop_;
+ base::RunLoop get_adapter_run_loop_;
+};
+
+// When we add device to bluez::FakeBluetoothDeviceClient, ArcBluetoothBridge
+// should send new device data to Android. This test will then check
+// the correctness of the device properties sent via arc bridge.
+TEST_F(ArcBluetoothBridgeTest, DeviceFound) {
+ EXPECT_EQ(0u, fake_bluetooth_instance_->device_found_data().size());
+ AddTestDevice();
+ EXPECT_EQ(2u, fake_bluetooth_instance_->device_found_data().size());
+ const mojo::Array<mojom::BluetoothPropertyPtr>& prop =
+ fake_bluetooth_instance_->device_found_data().back();
+
+ EXPECT_EQ(7u, prop.size());
+ EXPECT_TRUE(prop[0]->is_bdname());
+ EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyName),
+ prop[0]->get_bdname());
+ EXPECT_TRUE(prop[1]->is_bdaddr());
+ EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
+ prop[1]->get_bdaddr()->To<std::string>());
+ EXPECT_TRUE(prop[2]->is_uuids());
+ EXPECT_EQ(1u, prop[2]->get_uuids().size());
+ EXPECT_EQ(bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID,
+ prop[2]->get_uuids()[0].value());
+ EXPECT_TRUE(prop[3]->is_device_class());
+ EXPECT_EQ(bluez::FakeBluetoothDeviceClient::kLowEnergyClass,
+ prop[3]->get_device_class());
+ EXPECT_TRUE(prop[4]->is_device_type());
+ // bluez::FakeBluetoothDeviceClient does not return proper device type.
+ EXPECT_TRUE(prop[5]->is_remote_friendly_name());
+ EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyName),
+ prop[5]->get_remote_friendly_name());
+ EXPECT_TRUE(prop[6]->is_remote_rssi());
+ EXPECT_EQ(kTestRssi, prop[6]->get_remote_rssi());
+
+ ChangeTestDeviceRssi(kTestRssi2);
+ EXPECT_EQ(3u, fake_bluetooth_instance_->device_found_data().size());
+ const mojo::Array<mojom::BluetoothPropertyPtr>& prop2 =
+ fake_bluetooth_instance_->device_found_data().back();
+ EXPECT_EQ(7u, prop2.size());
+ EXPECT_TRUE(prop2[6]->is_remote_rssi());
+ EXPECT_EQ(kTestRssi2, prop2[6]->get_remote_rssi());
+}
+
+// Invoke OnDiscoveryStarted to send cached device to BT instance,
+// and check correctness of the Advertising data sent via arc bridge.
+TEST_F(ArcBluetoothBridgeTest, LEDeviceFound) {
+ EXPECT_EQ(0u, fake_bluetooth_instance_->le_device_found_data().size());
+ AddTestDevice();
+ EXPECT_EQ(1u, fake_bluetooth_instance_->le_device_found_data().size());
+
+ const auto& le_device_found_data =
+ fake_bluetooth_instance_->le_device_found_data().back();
+ const mojom::BluetoothAddressPtr& addr = le_device_found_data->addr();
+ const mojo::Array<mojom::BluetoothAdvertisingDataPtr>& adv_data =
+ le_device_found_data->adv_data();
+
+ EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
+ addr->To<std::string>());
+ EXPECT_EQ(2u, adv_data.size());
+
+ EXPECT_TRUE(adv_data[0]->is_local_name());
+ EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyName),
+ adv_data[0]->get_local_name().To<std::string>());
+
+ EXPECT_TRUE(adv_data[1]->is_service_uuids());
+ EXPECT_EQ(1u, adv_data[1]->get_service_uuids().size());
+ EXPECT_EQ(bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID,
+ adv_data[1]->get_service_uuids()[0].canonical_value());
+
+ EXPECT_EQ(kTestRssi, le_device_found_data->rssi());
+
+ ChangeTestDeviceRssi(kTestRssi2);
+ EXPECT_EQ(2u, fake_bluetooth_instance_->le_device_found_data().size());
+ EXPECT_EQ(kTestRssi2,
+ fake_bluetooth_instance_->le_device_found_data().back()->rssi());
+}
+
+// Invoke GetGattDB and check correctness of the GattDB sent via arc bridge.
+TEST_F(ArcBluetoothBridgeTest, GetGattDB) {
+ AddTestDevice();
+
+ arc_bluetooth_bridge_->GetGattDB(mojom::BluetoothAddress::From(
+ std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress)));
+ EXPECT_EQ(1u, fake_bluetooth_instance_->gatt_db_result().size());
+
+ const mojom::BluetoothAddressPtr& addr =
+ fake_bluetooth_instance_->gatt_db_result().back()->remote_addr();
+ EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
+ addr->To<std::string>());
+
+ // HeartRateService in bluez::FakeBluetoothDeviceClient consists of
+ // Service: HeartRateService
+ // Characteristic: HeartRateMeasurement
+ // Descriptor: ClientCharacteristicConfiguration
+ // Characteristic: BodySensorLocation
+ // Characteristic: HeartRateControlPoint
+ const mojo::Array<mojom::BluetoothGattDBElementPtr>& db =
+ fake_bluetooth_instance_->gatt_db_result().back()->db();
+ EXPECT_EQ(5u, db.size());
+
+ EXPECT_EQ(device::BluetoothUUID(
+ bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID),
+ db[0]->uuid);
+ EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_PRIMARY_SERVICE,
+ db[0]->type);
+
+ EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient::
+ kHeartRateMeasurementUUID),
+ db[1]->uuid);
+ EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
+ db[1]->type);
+ EXPECT_EQ(device::BluetoothGattCharacteristic::PROPERTY_NOTIFY,
+ db[1]->properties);
+
+ EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattDescriptorClient::
+ kClientCharacteristicConfigurationUUID),
+ db[2]->uuid);
+ EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR,
+ db[2]->type);
+
+ EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient::
+ kBodySensorLocationUUID),
+ db[3]->uuid);
+ EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
+ db[3]->type);
+ EXPECT_EQ(device::BluetoothGattCharacteristic::PROPERTY_READ,
+ db[3]->properties);
+
+ EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient::
+ kHeartRateControlPointUUID),
+ db[4]->uuid);
+ EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
+ db[4]->type);
+ EXPECT_EQ(device::BluetoothGattCharacteristic::PROPERTY_WRITE,
+ db[4]->properties);
+}
+
+// Invoke multi advertisement methods and make sure they are going down to the
+// D-Bus clients.
+TEST_F(ArcBluetoothBridgeTest, SingleAdvertisement) {
+ int32_t handle = ReserveAdvertisementHandle();
+ EXPECT_NE(kFailureAdvHandle, handle);
+ EXPECT_EQ(0, NumActiveAdvertisements());
+
+ auto adv_data = base::MakeUnique<device::BluetoothAdvertisement::Data>(
+ device::BluetoothAdvertisement::ADVERTISEMENT_TYPE_BROADCAST);
+ mojom::BluetoothGattStatus status =
+ BroadcastAdvertisement(handle, std::move(adv_data));
+ EXPECT_EQ(mojom::BluetoothGattStatus::GATT_SUCCESS, status);
+ EXPECT_EQ(1, NumActiveAdvertisements());
+
+ status = ReleaseAdvertisementHandle(handle);
+ EXPECT_EQ(mojom::BluetoothGattStatus::GATT_SUCCESS, status);
+ EXPECT_EQ(0, NumActiveAdvertisements());
+}
+
+} // namespace arc
diff --git a/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc b/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc
new file mode 100644
index 00000000000..716feca08fd
--- /dev/null
+++ b/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc
@@ -0,0 +1,238 @@
+// 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 "components/arc/bluetooth/bluetooth_struct_traits.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "device/bluetooth/bluetooth_advertisement.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+
+namespace {
+
+// BluetoothUUID helpers.
+constexpr size_t kUUIDSize = 16;
+
+bool IsNonHex(char c) {
+ return !isxdigit(c);
+}
+
+std::string StripNonHex(const std::string& str) {
+ std::string result = str;
+ result.erase(std::remove_if(result.begin(), result.end(), IsNonHex),
+ result.end());
+
+ return result;
+}
+
+// BluetoothAdvertisement helpers.
+struct AdvertisementEntry {
+ virtual ~AdvertisementEntry() {}
+ virtual void AddTo(device::BluetoothAdvertisement::Data* data) {}
+};
+
+struct ServiceUUIDEntry : public AdvertisementEntry {
+ std::vector<device::BluetoothUUID> service_uuids;
+
+ ~ServiceUUIDEntry() override {}
+
+ void AddTo(device::BluetoothAdvertisement::Data* data) override {
+ auto string_uuids = base::MakeUnique<std::vector<std::string>>();
+ for (const auto& uuid : service_uuids) {
+ string_uuids->emplace_back(uuid.value());
+ }
+ data->set_service_uuids(std::move(string_uuids));
+ }
+};
+
+struct ServiceDataEntry : public AdvertisementEntry {
+ uint16_t service_uuid;
+ std::vector<uint8_t> service_data;
+
+ ~ServiceDataEntry() override {}
+
+ void AddTo(device::BluetoothAdvertisement::Data* data) override {
+ std::string string_uuid = base::StringPrintf("%04x", service_uuid);
+ data->set_service_data(
+ base::WrapUnique(new std::map<std::string, std::vector<uint8_t>>{
+ {string_uuid, service_data}}));
+ }
+};
+
+struct ManufacturerDataEntry : public AdvertisementEntry {
+ uint16_t company_id_code;
+ std::vector<uint8_t> blob;
+
+ ~ManufacturerDataEntry() override {}
+
+ void AddTo(device::BluetoothAdvertisement::Data* data) override {
+ data->set_manufacturer_data(base::WrapUnique(
+ new std::map<uint16_t, std::vector<uint8_t>>{{company_id_code, blob}}));
+ }
+};
+
+uint16_t ExtractCompanyIdentifierCode(std::vector<uint8_t>* blob) {
+ // The company identifier code is in little-endian.
+ uint16_t company_id_code = (*blob)[1] << 8 | (*blob)[0];
+ blob->erase(blob->begin(), blob->begin() + sizeof(uint16_t));
+ return company_id_code;
+}
+
+} // namespace
+
+namespace mojo {
+
+// static
+std::vector<uint8_t>
+StructTraits<arc::mojom::BluetoothUUIDDataView, device::BluetoothUUID>::uuid(
+ const device::BluetoothUUID& input) {
+ // TODO(dcheng): Figure out what to do here, this is called twice on
+ // serialization. Building a vector is a little inefficient.
+ std::string uuid_str = StripNonHex(input.canonical_value());
+
+ std::vector<uint8_t> address_bytes;
+ base::HexStringToBytes(uuid_str, &address_bytes);
+ return address_bytes;
+}
+
+// static
+bool StructTraits<arc::mojom::BluetoothUUIDDataView,
+ device::BluetoothUUID>::Read(
+ arc::mojom::BluetoothUUIDDataView data,
+ device::BluetoothUUID* output) {
+ std::vector<uint8_t> address_bytes;
+ if (!data.ReadUuid(&address_bytes))
+ return false;
+
+ if (address_bytes.size() != kUUIDSize)
+ return false;
+
+ // BluetoothUUID expects the format below with the dashes inserted.
+ // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+ std::string uuid_str =
+ base::HexEncode(address_bytes.data(), address_bytes.size());
+ constexpr size_t kUuidDashPos[] = {8, 13, 18, 23};
+ for (auto pos : kUuidDashPos)
+ uuid_str = uuid_str.insert(pos, "-");
+
+ device::BluetoothUUID result(uuid_str);
+
+ DCHECK(result.IsValid());
+ *output = result;
+ return true;
+}
+
+template <>
+struct EnumTraits<arc::mojom::BluetoothAdvertisementType,
+ device::BluetoothAdvertisement::AdvertisementType> {
+ static bool FromMojom(
+ arc::mojom::BluetoothAdvertisementType mojom_type,
+ device::BluetoothAdvertisement::AdvertisementType* type) {
+ switch (mojom_type) {
+ case arc::mojom::BluetoothAdvertisementType::ADV_TYPE_CONNECTABLE:
+ case arc::mojom::BluetoothAdvertisementType::ADV_TYPE_SCANNABLE:
+ *type = device::BluetoothAdvertisement::ADVERTISEMENT_TYPE_PERIPHERAL;
+ return true;
+ case arc::mojom::BluetoothAdvertisementType::ADV_TYPE_NON_CONNECTABLE:
+ *type = device::BluetoothAdvertisement::ADVERTISEMENT_TYPE_BROADCAST;
+ return true;
+ }
+ NOTREACHED() << "Invalid type: " << static_cast<uint32_t>(mojom_type);
+ return false;
+ }
+};
+
+template <>
+struct StructTraits<arc::mojom::BluetoothServiceDataDataView,
+ ServiceDataEntry> {
+ static bool Read(arc::mojom::BluetoothServiceDataDataView data,
+ ServiceDataEntry* output) {
+ output->service_uuid = data.uuid_16bit();
+ return data.ReadData(&output->service_data);
+ }
+};
+
+template <>
+struct UnionTraits<arc::mojom::BluetoothAdvertisingDataDataView,
+ std::unique_ptr<AdvertisementEntry>> {
+ static bool Read(arc::mojom::BluetoothAdvertisingDataDataView data,
+ std::unique_ptr<AdvertisementEntry>* output) {
+ switch (data.tag()) {
+ case arc::mojom::BluetoothAdvertisingDataDataView::Tag::SERVICE_UUIDS: {
+ std::unique_ptr<ServiceUUIDEntry> service_uuids =
+ base::MakeUnique<ServiceUUIDEntry>();
+ if (!data.ReadServiceUuids(&service_uuids->service_uuids))
+ return false;
+ *output = std::move(service_uuids);
+ break;
+ }
+ case arc::mojom::BluetoothAdvertisingDataDataView::Tag::SERVICE_DATA: {
+ std::unique_ptr<ServiceDataEntry> service_data =
+ base::MakeUnique<ServiceDataEntry>();
+ if (!data.ReadServiceData(service_data.get()))
+ return false;
+ *output = std::move(service_data);
+ break;
+ }
+ case arc::mojom::BluetoothAdvertisingDataDataView::Tag::
+ MANUFACTURER_DATA: {
+ std::unique_ptr<ManufacturerDataEntry> manufacturer_data =
+ base::MakeUnique<ManufacturerDataEntry>();
+ // We get manufacturer data as a big blob. The first two bytes
+ // should be a company identifier code and the rest is manufacturer-
+ // specific.
+ std::vector<uint8_t> blob;
+ if (!data.ReadManufacturerData(&blob))
+ return false;
+ if (blob.size() < sizeof(uint16_t)) {
+ LOG(WARNING) << "Advertisement had malformed manufacturer data";
+ return false;
+ }
+
+ manufacturer_data->company_id_code =
+ ExtractCompanyIdentifierCode(&blob);
+ manufacturer_data->blob = std::move(blob);
+ *output = std::move(manufacturer_data);
+ break;
+ }
+ default: {
+ LOG(WARNING) << "Bluetooth advertising data case not implemented";
+ // Default AdvertisementEntry does nothing when added to the
+ // device::BluetoothAdvertisement::AdvertisementData, so data we
+ // don't know how to handle yet will be dropped but won't cause a
+ // failure to deserialize.
+ *output = base::MakeUnique<AdvertisementEntry>();
+ break;
+ }
+ }
+ return true;
+ }
+};
+
+// static
+bool StructTraits<arc::mojom::BluetoothAdvertisementDataView,
+ std::unique_ptr<device::BluetoothAdvertisement::Data>>::
+ Read(arc::mojom::BluetoothAdvertisementDataView advertisement,
+ std::unique_ptr<device::BluetoothAdvertisement::Data>* output) {
+ device::BluetoothAdvertisement::AdvertisementType adv_type;
+ if (!advertisement.ReadType(&adv_type))
+ return false;
+ auto data = base::MakeUnique<device::BluetoothAdvertisement::Data>(adv_type);
+
+ std::vector<std::unique_ptr<AdvertisementEntry>> adv_entries;
+ if (!advertisement.ReadData(&adv_entries))
+ return false;
+ for (const auto& adv_entry : adv_entries)
+ adv_entry->AddTo(data.get());
+
+ data->set_include_tx_power(advertisement.include_tx_power());
+
+ *output = std::move(data);
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/components/arc/bluetooth/bluetooth_struct_traits.h b/chromium/components/arc/bluetooth/bluetooth_struct_traits.h
index da75bdd6d52..26ca434aefc 100644
--- a/chromium/components/arc/bluetooth/bluetooth_struct_traits.h
+++ b/chromium/components/arc/bluetooth/bluetooth_struct_traits.h
@@ -2,11 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_ARC_BLUETOOTH_BLUETOOTH_TYPE_TRAITS_H_
-#define COMPONENTS_ARC_BLUETOOTH_BLUETOOTH_TYPE_TRAITS_H_
+#ifndef COMPONENTS_ARC_BLUETOOTH_BLUETOOTH_STRUCT_TRAITS_H_
+#define COMPONENTS_ARC_BLUETOOTH_BLUETOOTH_STRUCT_TRAITS_H_
#include "components/arc/common/bluetooth.mojom.h"
+#include "device/bluetooth/bluetooth_advertisement.h"
#include "device/bluetooth/bluetooth_common.h"
+#include "device/bluetooth/bluetooth_uuid.h"
#include "device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h"
namespace mojo {
@@ -93,6 +95,40 @@ struct EnumTraits<arc::mojom::BluetoothSdpAttributeType,
}
};
+template <>
+struct StructTraits<arc::mojom::BluetoothUUIDDataView, device::BluetoothUUID> {
+ static std::vector<uint8_t> uuid(const device::BluetoothUUID& input);
+ static bool Read(arc::mojom::BluetoothUUIDDataView data,
+ device::BluetoothUUID* output);
+};
+
+template <>
+struct StructTraits<arc::mojom::BluetoothAdvertisementDataView,
+ std::unique_ptr<device::BluetoothAdvertisement::Data>> {
+ static bool Read(
+ arc::mojom::BluetoothAdvertisementDataView advertisement,
+ std::unique_ptr<device::BluetoothAdvertisement::Data>* output);
+
+ // Dummy methods.
+ static arc::mojom::BluetoothAdvertisementType type(
+ std::unique_ptr<device::BluetoothAdvertisement::Data>& input) {
+ NOTREACHED();
+ return arc::mojom::BluetoothAdvertisementType::ADV_TYPE_NON_CONNECTABLE;
+ }
+
+ static bool include_tx_power(
+ std::unique_ptr<device::BluetoothAdvertisement::Data>& input) {
+ NOTREACHED();
+ return false;
+ }
+
+ static mojo::Array<arc::mojom::BluetoothAdvertisingDataPtr> data(
+ std::unique_ptr<device::BluetoothAdvertisement::Data>& input) {
+ NOTREACHED();
+ return mojo::Array<arc::mojom::BluetoothAdvertisingDataPtr>();
+ }
+};
+
} // namespace mojo
-#endif // COMPONENTS_ARC_BLUETOOTH_BLUETOOTH_TYPE_CONVERTERS_H_
+#endif // COMPONENTS_ARC_BLUETOOTH_BLUETOOTH_STRUCT_TRAITS_H_
diff --git a/chromium/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc b/chromium/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc
new file mode 100644
index 00000000000..94adbbb734f
--- /dev/null
+++ b/chromium/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc
@@ -0,0 +1,153 @@
+// 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 "components/arc/bluetooth/bluetooth_struct_traits.h"
+
+#include "base/macros.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+#include "mojo/public/cpp/bindings/array.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+constexpr char kUuidStr[] = "12345678-1234-5678-9abc-def123456789";
+constexpr uint8_t kUuidArray[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34,
+ 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf1,
+ 0x23, 0x45, 0x67, 0x89};
+constexpr size_t kUuidSize = 16;
+
+constexpr char kUuid16Str[] = "1234";
+constexpr uint16_t kUuid16 = 0x1234;
+constexpr uint8_t kServiceData[] = {0x11, 0x22, 0x33, 0x44, 0x55};
+constexpr uint8_t kManufacturerData[] = {0x00, 0xe0};
+
+template <typename MojoType, typename UserType>
+mojo::StructPtr<MojoType> ConvertToMojo(UserType& input) {
+ mojo::Array<uint8_t> data = MojoType::Serialize(&input);
+ mojo::StructPtr<MojoType> output;
+ MojoType::Deserialize(std::move(data), &output);
+ return output;
+}
+
+template <typename MojoType, typename UserType>
+bool ConvertFromMojo(mojo::StructPtr<MojoType> input, UserType* output) {
+ mojo::Array<uint8_t> data = MojoType::Serialize(&input);
+ return MojoType::Deserialize(std::move(data), output);
+}
+
+} // namespace
+
+namespace mojo {
+
+TEST(BluetoothStructTraitsTest, SerializeBluetoothUUID) {
+ device::BluetoothUUID uuid_device(kUuidStr);
+ arc::mojom::BluetoothUUIDPtr uuid_mojo =
+ ConvertToMojo<arc::mojom::BluetoothUUID>(uuid_device);
+ EXPECT_EQ(kUuidSize, uuid_mojo->uuid.size());
+ for (size_t i = 0; i < kUuidSize; i++) {
+ EXPECT_EQ(kUuidArray[i], uuid_mojo->uuid[i]);
+ }
+}
+
+TEST(BluetoothStructTraitsTest, DeserializeBluetoothUUID) {
+ arc::mojom::BluetoothUUIDPtr uuid_mojo = arc::mojom::BluetoothUUID::New();
+ for (size_t i = 0; i < kUuidSize; i++) {
+ uuid_mojo->uuid.push_back(kUuidArray[i]);
+ }
+ uuid_mojo->uuid =
+ std::vector<uint8_t>(std::begin(kUuidArray), std::end(kUuidArray));
+ device::BluetoothUUID uuid_device;
+ EXPECT_TRUE(ConvertFromMojo(std::move(uuid_mojo), &uuid_device));
+ EXPECT_EQ(std::string(kUuidStr), uuid_device.canonical_value());
+
+ // Size checks are performed in serialization code. UUIDs with a length
+ // other than 16 bytes will not make it through the mojo deserialization
+ // code since arc::mojom::BluetoothUUID::uuid is defined as
+ // array<uint8, 16>.
+}
+
+TEST(BluetoothStructTraitsTest, DeserializeBluetoothAdvertisement) {
+ arc::mojom::BluetoothAdvertisementPtr advertisement_mojo =
+ arc::mojom::BluetoothAdvertisement::New();
+ mojo::Array<arc::mojom::BluetoothAdvertisingDataPtr> adv_data;
+
+ // Create service UUIDs.
+ arc::mojom::BluetoothAdvertisingDataPtr data =
+ arc::mojom::BluetoothAdvertisingData::New();
+ std::vector<device::BluetoothUUID> service_uuids;
+ service_uuids.push_back((device::BluetoothUUID(kUuidStr)));
+ data->set_service_uuids(service_uuids);
+ adv_data.push_back(std::move(data));
+
+ // Create service data.
+ data = arc::mojom::BluetoothAdvertisingData::New();
+ arc::mojom::BluetoothServiceDataPtr service_data =
+ arc::mojom::BluetoothServiceData::New();
+ service_data->uuid_16bit = kUuid16;
+ service_data->data =
+ std::vector<uint8_t>(std::begin(kServiceData), std::end(kServiceData));
+ data->set_service_data(std::move(service_data));
+ adv_data.push_back(std::move(data));
+
+ // Create manufacturer data.
+ data = arc::mojom::BluetoothAdvertisingData::New();
+ data->set_manufacturer_data(std::vector<uint8_t>(
+ std::begin(kManufacturerData), std::end(kManufacturerData)));
+ adv_data.push_back(std::move(data));
+
+ advertisement_mojo->type =
+ arc::mojom::BluetoothAdvertisementType::ADV_TYPE_CONNECTABLE;
+ advertisement_mojo->data = std::move(adv_data);
+
+ std::unique_ptr<device::BluetoothAdvertisement::Data> advertisement;
+ EXPECT_TRUE(ConvertFromMojo(std::move(advertisement_mojo), &advertisement));
+
+ EXPECT_EQ(advertisement->type(),
+ device::BluetoothAdvertisement::ADVERTISEMENT_TYPE_PERIPHERAL);
+
+ std::unique_ptr<device::BluetoothAdvertisement::UUIDList> converted_uuids =
+ advertisement->service_uuids();
+ EXPECT_EQ(converted_uuids->size(), 1U);
+ EXPECT_EQ(*converted_uuids->begin(), kUuidStr);
+
+ std::unique_ptr<device::BluetoothAdvertisement::ServiceData>
+ converted_service = advertisement->service_data();
+ EXPECT_EQ(converted_service->size(), 1U);
+ EXPECT_EQ(converted_service->begin()->first, kUuid16Str);
+ for (size_t i = 0; i < arraysize(kServiceData); i++) {
+ EXPECT_EQ(kServiceData[i], converted_service->begin()->second[i]);
+ }
+
+ std::unique_ptr<device::BluetoothAdvertisement::ManufacturerData>
+ converted_manufacturer = advertisement->manufacturer_data();
+ EXPECT_EQ(converted_manufacturer->size(), 1U);
+ uint16_t cic = converted_manufacturer->begin()->first;
+ EXPECT_EQ(cic & 0xff, kManufacturerData[0]);
+ EXPECT_EQ((cic >> 8) & 0xff, kManufacturerData[1]);
+ EXPECT_EQ(converted_manufacturer->begin()->second.size(),
+ static_cast<unsigned long>(arraysize(kManufacturerData) -
+ sizeof(uint16_t)));
+}
+
+TEST(BluetoothStructTraitsTest, DeserializeBluetoothAdvertisementFailure) {
+ arc::mojom::BluetoothAdvertisementPtr advertisement_mojo =
+ arc::mojom::BluetoothAdvertisement::New();
+ mojo::Array<arc::mojom::BluetoothAdvertisingDataPtr> adv_data;
+
+ // Create empty manufacturer data. Manufacturer data must include the CIC
+ // which is 2 bytes long.
+ arc::mojom::BluetoothAdvertisingDataPtr data =
+ arc::mojom::BluetoothAdvertisingData::New();
+ data->set_manufacturer_data((mojo::Array<uint8_t>()));
+ adv_data.push_back(std::move(data));
+
+ advertisement_mojo->type =
+ arc::mojom::BluetoothAdvertisementType::ADV_TYPE_CONNECTABLE;
+ advertisement_mojo->data = std::move(adv_data);
+
+ std::unique_ptr<device::BluetoothAdvertisement::Data> advertisement;
+ EXPECT_FALSE(ConvertFromMojo(std::move(advertisement_mojo), &advertisement));
+}
+
+} // namespace mojo
diff --git a/chromium/components/arc/bluetooth/bluetooth_type_converters.cc b/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
index 3c9ac89f1e5..6acc8c40457 100644
--- a/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
+++ b/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
@@ -20,6 +20,9 @@
namespace {
+constexpr size_t kAddressSize = 6;
+constexpr char kInvalidAddress[] = "00:00:00:00:00:00";
+
// SDP Service attribute IDs.
constexpr uint16_t kServiceClassIDList = 0x0001;
constexpr uint16_t kProtocolDescriptorList = 0x0004;
@@ -43,8 +46,6 @@ std::string StripNonHex(const std::string& str) {
namespace mojo {
-// TODO(smbarber): Add unit tests for Bluetooth type converters.
-
// static
arc::mojom::BluetoothAddressPtr
TypeConverter<arc::mojom::BluetoothAddressPtr, std::string>::Convert(
@@ -69,6 +70,9 @@ std::string TypeConverter<std::string, arc::mojom::BluetoothAddress>::Convert(
const mojo::Array<uint8_t>& bytes = address.address;
+ if (address.address.size() != kAddressSize)
+ return std::string(kInvalidAddress);
+
for (size_t k = 0; k < bytes.size(); k++) {
addr_stream << std::setw(2) << (unsigned int)bytes[k];
addr_stream << ((k == bytes.size() - 1) ? "" : ":");
@@ -78,41 +82,6 @@ std::string TypeConverter<std::string, arc::mojom::BluetoothAddress>::Convert(
}
// static
-arc::mojom::BluetoothUUIDPtr
-TypeConverter<arc::mojom::BluetoothUUIDPtr, device::BluetoothUUID>::Convert(
- const device::BluetoothUUID& uuid) {
- std::string uuid_str = StripNonHex(uuid.canonical_value());
-
- std::vector<uint8_t> address_bytes;
- base::HexStringToBytes(uuid_str, &address_bytes);
-
- arc::mojom::BluetoothUUIDPtr uuidp = arc::mojom::BluetoothUUID::New();
- uuidp->uuid = mojo::Array<uint8_t>::From(address_bytes);
-
- return uuidp;
-}
-
-// static
-device::BluetoothUUID
-TypeConverter<device::BluetoothUUID, arc::mojom::BluetoothUUIDPtr>::Convert(
- const arc::mojom::BluetoothUUIDPtr& uuid) {
- std::vector<uint8_t> address_bytes = uuid->uuid.To<std::vector<uint8_t>>();
-
- // BluetoothUUID expects the format below with the dashes inserted.
- // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- std::string uuid_str =
- base::HexEncode(address_bytes.data(), address_bytes.size());
- const size_t uuid_dash_pos[] = {8, 13, 18, 23};
- for (auto pos : uuid_dash_pos)
- uuid_str = uuid_str.insert(pos, "-");
-
- device::BluetoothUUID result(uuid_str);
-
- DCHECK(result.IsValid());
- return result;
-}
-
-// static
arc::mojom::BluetoothGattStatus
TypeConverter<arc::mojom::BluetoothGattStatus,
device::BluetoothGattService::GattErrorCode>::
diff --git a/chromium/components/arc/bluetooth/bluetooth_type_converters.h b/chromium/components/arc/bluetooth/bluetooth_type_converters.h
index 34618968009..295e3c8ea95 100644
--- a/chromium/components/arc/bluetooth/bluetooth_type_converters.h
+++ b/chromium/components/arc/bluetooth/bluetooth_type_converters.h
@@ -16,10 +16,6 @@
#include "device/bluetooth/bluez/bluetooth_service_record_bluez.h"
#include "mojo/public/cpp/bindings/type_converter.h"
-namespace device {
-class BluetoothUUID;
-}
-
namespace arc {
// The design of SDP attribute allows the attributes in the sequence of an
// attribute to be of sequence type. To prevent a malicious party from sending
@@ -45,18 +41,6 @@ struct TypeConverter<std::string, arc::mojom::BluetoothAddress> {
};
template <>
-struct TypeConverter<arc::mojom::BluetoothUUIDPtr, device::BluetoothUUID> {
- static arc::mojom::BluetoothUUIDPtr Convert(
- const device::BluetoothUUID& uuid);
-};
-
-template <>
-struct TypeConverter<device::BluetoothUUID, arc::mojom::BluetoothUUIDPtr> {
- static device::BluetoothUUID Convert(
- const arc::mojom::BluetoothUUIDPtr& uuid);
-};
-
-template <>
struct TypeConverter<arc::mojom::BluetoothGattStatus,
device::BluetoothGattService::GattErrorCode> {
static arc::mojom::BluetoothGattStatus Convert(
diff --git a/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc b/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
index 0a5f2c25625..6d379839ca3 100644
--- a/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
+++ b/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
@@ -22,11 +22,6 @@ constexpr char kAddressStr[] = "1A:2B:3C:4D:5E:6F";
constexpr char kInvalidAddressStr[] = "00:00:00:00:00:00";
constexpr uint8_t kAddressArray[] = {0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f};
constexpr size_t kAddressSize = 6;
-constexpr char kUuidStr[] = "12345678-1234-5678-9abc-def123456789";
-constexpr uint8_t kUuidArray[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34,
- 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf1,
- 0x23, 0x45, 0x67, 0x89};
-constexpr size_t kUuidSize = 16;
constexpr uint8_t kFillerByte = 0x79;
arc::mojom::BluetoothSdpAttributePtr CreateDeepMojoSequenceAttribute(
@@ -113,33 +108,6 @@ TEST(BluetoothTypeConvertorTest, ConvertMojoBluetoothAddressToString) {
EXPECT_EQ(std::string(kInvalidAddressStr), addressMojo->To<std::string>());
}
-TEST(BluetoothTypeConvertorTest,
- ConvertMojoBluetoothUUIDFromDeviceBluetoothUUID) {
- device::BluetoothUUID uuidDevice((std::string(kUuidStr)));
- arc::mojom::BluetoothUUIDPtr uuidMojo =
- arc::mojom::BluetoothUUID::From(uuidDevice);
- EXPECT_EQ(kUuidSize, uuidMojo->uuid.size());
- for (size_t i = 0; i < kUuidSize; i++) {
- EXPECT_EQ(kUuidArray[i], uuidMojo->uuid[i]);
- }
-}
-
-TEST(BluetoothTypeConvertorTest,
- ConvertMojoBluetoothUUIDToDeviceBluetoothUUID) {
- arc::mojom::BluetoothUUIDPtr uuidMojo = arc::mojom::BluetoothUUID::New();
- for (size_t i = 0; i < kUuidSize - 1; i++) {
- uuidMojo->uuid.push_back(kUuidArray[i]);
- }
- EXPECT_FALSE(uuidMojo.To<device::BluetoothUUID>().IsValid());
-
- uuidMojo->uuid.push_back(kUuidArray[kUuidSize - 1]);
- EXPECT_TRUE(uuidMojo.To<device::BluetoothUUID>().IsValid());
- EXPECT_EQ(std::string(kUuidStr),
- uuidMojo.To<device::BluetoothUUID>().canonical_value());
-
- uuidMojo->uuid.push_back(kFillerByte);
- EXPECT_FALSE(uuidMojo.To<device::BluetoothUUID>().IsValid());
-}
TEST(BluetoothTypeConvertorTest, ConvertMojoValueAttributeToBlueZAttribute) {
// Construct Mojo attribute with NULLTYPE value.
diff --git a/chromium/components/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc b/chromium/components/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc
new file mode 100644
index 00000000000..e4698df7ab6
--- /dev/null
+++ b/chromium/components/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc
@@ -0,0 +1,57 @@
+// 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 "components/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h"
+
+#include "base/logging.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/session_manager_client.h"
+
+namespace arc {
+
+namespace {
+
+void PrioritizeArcInstanceCallback(bool success) {
+ VLOG(2) << "Finished prioritizing the instance: result=" << success;
+ if (!success)
+ LOG(WARNING) << "Failed to prioritize ARC";
+}
+
+} // namespace
+
+ArcBootPhaseMonitorBridge::ArcBootPhaseMonitorBridge(
+ ArcBridgeService* bridge_service)
+ : ArcService(bridge_service), binding_(this) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ arc_bridge_service()->boot_phase_monitor()->AddObserver(this);
+}
+
+ArcBootPhaseMonitorBridge::~ArcBootPhaseMonitorBridge() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ arc_bridge_service()->boot_phase_monitor()->RemoveObserver(this);
+}
+
+void ArcBootPhaseMonitorBridge::OnInstanceReady() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ auto* instance =
+ arc_bridge_service()->boot_phase_monitor()->GetInstanceForMethod("Init");
+ DCHECK(instance);
+ instance->Init(binding_.CreateInterfacePtrAndBind());
+}
+
+void ArcBootPhaseMonitorBridge::OnInstanceClosed() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void ArcBootPhaseMonitorBridge::OnBootCompleted() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ VLOG(2) << "OnBootCompleted";
+ chromeos::SessionManagerClient* session_manager_client =
+ chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
+ session_manager_client->PrioritizeArcInstance(
+ base::Bind(PrioritizeArcInstanceCallback));
+ session_manager_client->EmitArcBooted();
+}
+
+} // namespace arc
diff --git a/chromium/components/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h b/chromium/components/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h
new file mode 100644
index 00000000000..8c783ba2750
--- /dev/null
+++ b/chromium/components/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h
@@ -0,0 +1,44 @@
+// 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 COMPONENTS_ARC_BOOT_PHASE_MONITOR_ARC_BOOT_PHASE_MONITOR_BRIDGE_H_
+#define COMPONENTS_ARC_BOOT_PHASE_MONITOR_ARC_BOOT_PHASE_MONITOR_BRIDGE_H_
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/arc/arc_service.h"
+#include "components/arc/common/boot_phase_monitor.mojom.h"
+#include "components/arc/instance_holder.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace arc {
+
+// Receives boot phase notifications from ARC.
+class ArcBootPhaseMonitorBridge
+ : public ArcService,
+ public InstanceHolder<mojom::BootPhaseMonitorInstance>::Observer,
+ public mojom::BootPhaseMonitorHost {
+ public:
+ explicit ArcBootPhaseMonitorBridge(ArcBridgeService* bridge_service);
+ ~ArcBootPhaseMonitorBridge() override;
+
+ // InstanceHolder<mojom::BootPhaseMonitorInstance>::Observer
+ void OnInstanceReady() override;
+ void OnInstanceClosed() override;
+
+ // arc::mojom::BootPhaseMonitorHost
+ void OnBootCompleted() override;
+
+ private:
+ mojo::Binding<mojom::BootPhaseMonitorHost> binding_;
+
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ArcBootPhaseMonitorBridge);
+};
+
+} // namespace arc
+
+#endif // COMPONENTS_ARC_BOOT_PHASE_MONITOR_ARC_BOOT_PHASE_MONITOR_BRIDGE_H_
diff --git a/chromium/components/arc/clipboard/arc_clipboard_bridge.cc b/chromium/components/arc/clipboard/arc_clipboard_bridge.cc
index 2a6d735d555..029b1adad8a 100644
--- a/chromium/components/arc/clipboard/arc_clipboard_bridge.cc
+++ b/chromium/components/arc/clipboard/arc_clipboard_bridge.cc
@@ -39,12 +39,8 @@ ArcClipboardBridge::~ArcClipboardBridge() {
void ArcClipboardBridge::OnInstanceReady() {
mojom::ClipboardInstance* clipboard_instance =
- arc_bridge_service()->clipboard()->instance();
- if (!clipboard_instance) {
- LOG(ERROR) << "OnClipboardInstanceReady called, "
- << "but no clipboard instance found";
- return;
- }
+ arc_bridge_service()->clipboard()->GetInstanceForMethod("Init");
+ DCHECK(clipboard_instance);
clipboard_instance->Init(binding_.CreateInterfacePtrAndBind());
}
@@ -62,7 +58,10 @@ void ArcClipboardBridge::GetTextContent() {
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &text);
mojom::ClipboardInstance* clipboard_instance =
- arc_bridge_service()->clipboard()->instance();
+ arc_bridge_service()->clipboard()->GetInstanceForMethod(
+ "OnGetTextContent");
+ if (!clipboard_instance)
+ return;
clipboard_instance->OnGetTextContent(ConvertString16ToMojoString(text));
}
diff --git a/chromium/components/arc/common/OWNERS b/chromium/components/arc/common/OWNERS
index 08850f42120..16f082a0ddf 100644
--- a/chromium/components/arc/common/OWNERS
+++ b/chromium/components/arc/common/OWNERS
@@ -1,2 +1,5 @@
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS \ No newline at end of file
diff --git a/chromium/components/arc/common/app_struct_traits.cc b/chromium/components/arc/common/app_struct_traits.cc
index 9cd31a5991c..46c8ac0a22c 100644
--- a/chromium/components/arc/common/app_struct_traits.cc
+++ b/chromium/components/arc/common/app_struct_traits.cc
@@ -6,8 +6,9 @@
namespace mojo {
-bool StructTraits<arc::mojom::ScreenRect, gfx::Rect>::Read(
- arc::mojom::ScreenRectDataView data, gfx::Rect* out) {
+bool StructTraits<arc::mojom::ScreenRectDataView, gfx::Rect>::Read(
+ arc::mojom::ScreenRectDataView data,
+ gfx::Rect* out) {
if (data.right() < data.left() || data.bottom() < data.top())
return false;
diff --git a/chromium/components/arc/common/app_struct_traits.h b/chromium/components/arc/common/app_struct_traits.h
index 86818757472..e0ada3d9e8c 100644
--- a/chromium/components/arc/common/app_struct_traits.h
+++ b/chromium/components/arc/common/app_struct_traits.h
@@ -11,7 +11,7 @@
namespace mojo {
template <>
-struct StructTraits<arc::mojom::ScreenRect, gfx::Rect> {
+struct StructTraits<arc::mojom::ScreenRectDataView, gfx::Rect> {
static int32_t left(const gfx::Rect& p) { return p.x(); }
static int32_t top(const gfx::Rect& p) { return p.y(); }
static int32_t right(const gfx::Rect& p) { return p.right(); }
diff --git a/chromium/components/arc/common/arc_bridge.mojom b/chromium/components/arc/common/arc_bridge.mojom
index 774e0bf1ddd..8247153ef14 100644
--- a/chromium/components/arc/common/arc_bridge.mojom
+++ b/chromium/components/arc/common/arc_bridge.mojom
@@ -8,6 +8,7 @@ import "app.mojom";
import "audio.mojom";
import "auth.mojom";
import "bluetooth.mojom";
+import "boot_phase_monitor.mojom";
import "clipboard.mojom";
import "crash_collector.mojom";
import "enterprise_reporting.mojom";
@@ -20,14 +21,16 @@ import "notifications.mojom";
import "obb_mounter.mojom";
import "policy.mojom";
import "power.mojom";
+import "print.mojom";
import "process.mojom";
import "storage_manager.mojom";
+import "tts.mojom";
import "video.mojom";
-import "window_manager.mojom";
+import "wallpaper.mojom";
-// Next MinVersion: 16
+// Next MinVersion: 20
// Deprecated method IDs: 101, 105
-// Next method ID: 123
+// Next method ID: 126
interface ArcBridgeHost {
// Keep the entries alphabetical. In order to do so without breaking
// compatibility with the ARC instance, explicitly assign each interface a
@@ -45,6 +48,10 @@ interface ArcBridgeHost {
// Notifies Chrome that the BluetoothInstance interface is ready.
[MinVersion=9] OnBluetoothInstanceReady@113(BluetoothInstance instance_ptr);
+ // Notifies Chrome that the BootPhaseMonitorInstance interface is ready.
+ [MinVersion=19] OnBootPhaseMonitorInstanceReady@125(
+ BootPhaseMonitorInstance instance_ptr);
+
// Notifies Chrome that the ClipboardInstance interface is ready.
[MinVersion=2] OnClipboardInstanceReady@109(ClipboardInstance instance_ptr);
@@ -85,17 +92,23 @@ interface ArcBridgeHost {
// Notifies Chrome that the PowerInstance interface is ready.
OnPowerInstanceReady@103(PowerInstance instance_ptr);
+ // Notifies Chrome that the PrintInstance interface is ready.
+ [MinVersion=16] OnPrintInstanceReady@121(PrintInstance instance_ptr);
+
// Notifies Chrome that the ProcessInstance interface is ready.
OnProcessInstanceReady@104(ProcessInstance instance_ptr);
// Notifies Chrome that the StorageManagerInstance interface is ready.
[MinVersion=12] OnStorageManagerInstanceReady@118(StorageManagerInstance instance_ptr);
+ // Notifies Chrome that the TtsInstance interface is ready.
+ [MinVersion=17] OnTtsInstanceReady@123(TtsInstance instance_ptr);
+
// Notifies Chrome that the VideoInstance interface is ready.
[MinVersion=6] OnVideoInstanceReady@107(VideoInstance instance_ptr);
- // Notifies Android of entering / exiting TouchView.
- [MinVersion=11] OnWindowManagerInstanceReady@117(WindowManagerInstance instance_ptr);
+ // Notifies Chrome that the WallpaperInstance interface is ready.
+ [MinVersion=18] OnWallpaperInstanceReady@124(WallpaperInstance instance_ptr);
};
interface ArcBridgeInstance {
diff --git a/chromium/components/arc/common/auth.mojom b/chromium/components/arc/common/auth.mojom
index e4dca7328b3..faa0c0fb2a6 100644
--- a/chromium/components/arc/common/auth.mojom
+++ b/chromium/components/arc/common/auth.mojom
@@ -2,13 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Next MinVersion: 5
+
module arc.mojom;
// These values describe failure reason of sign-in.
[Extensible]
enum ArcSignInFailureReason {
// Negative values are reserved for internal use.
- // The values are shuffled to keep the backward compatibility.
+ // The values are shuffled to keep the backward compatibility and don't match
+ // ProvisioningResult in arc_optin_uma.h
// Next value: 15.
UNKNOWN_ERROR = 0,
@@ -60,12 +63,30 @@ enum ArcSignInFailureReason {
CLOUD_PROVISION_FLOW_INTERNAL_ERROR = 14,
};
+// These values describe the type of the Chrome account to provision.
+[Extensible]
+enum ChromeAccountType {
+ // Next value: 3
+ UNKNOWN = 0,
+
+ // Chrome login account type is a user account.
+ USER_ACCOUNT = 1,
+
+ // Chrome login account type is a robot (service) account.
+ ROBOT_ACCOUNT = 2,
+};
+
interface AuthHost {
+ // Next Method ID: 6.
// Returns an authorization code, which can be used to sign in.
GetAuthCodeDeprecated@0() => (string auth_code);
// Returns an authorization code in case is_enforced is set, which can be used
- // to sign in.
+ // to sign in. By default the ChromeAccountType is USER_ACCOUNT.
[MinVersion=1] GetAuthCode@1() => (string auth_code, bool is_enforced);
+ // Returns an authorization code and its ChromeAccountType in case
+ // is_enforced is set, which can be used to sign in.
+ [MinVersion=4] GetAuthCodeAndAccountType@5() => (
+ string auth_code, bool is_enforced, ChromeAccountType account_type);
// Gets whether the account is managed from Chrome OS.
[MinVersion=3] GetIsAccountManaged@4() => (bool is_managed);
// Notifies Chrome that the sign-in is completed successfully.
diff --git a/chromium/components/arc/common/bitmap.typemap b/chromium/components/arc/common/bitmap.typemap
new file mode 100644
index 00000000000..73529dc3611
--- /dev/null
+++ b/chromium/components/arc/common/bitmap.typemap
@@ -0,0 +1,13 @@
+mojom = "//components/arc/common/bitmap.mojom"
+public_headers = [ "//third_party/skia/include/core/SkBitmap.h" ]
+traits_headers = [ "//components/arc/bitmap/bitmap_struct_traits.h" ]
+sources = [
+ "//components/arc/bitmap/bitmap_struct_traits.cc",
+]
+deps = [
+ "//skia",
+]
+public_deps = [
+ "//skia",
+]
+type_mappings = [ "arc.mojom.ArcBitmap=SkBitmap" ]
diff --git a/chromium/components/arc/common/bluetooth.mojom b/chromium/components/arc/common/bluetooth.mojom
index a3076201d8c..a1f5a0d3d91 100644
--- a/chromium/components/arc/common/bluetooth.mojom
+++ b/chromium/components/arc/common/bluetooth.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Next MinVersion: 6
+// Next MinVersion: 7
module arc.mojom;
@@ -169,6 +169,16 @@ struct BluetoothGattValue {
array<uint8> value;
};
+const int8 kUnknownPower = 127;
+
+// Copied from Android Bluetooth package. See AdvertiseManager$AdvertiseNative
+// http://goo.gl/UnKC5N
+enum BluetoothAdvertisementType {
+ ADV_TYPE_CONNECTABLE = 0,
+ ADV_TYPE_SCANNABLE = 2,
+ ADV_TYPE_NON_CONNECTABLE = 3,
+};
+
// Copy from Bluetooth Assigned Numbers Document, Generic Access Profile
// https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
[Extensible]
@@ -201,6 +211,13 @@ struct BluetoothServiceData {
array<uint8> data;
};
+struct BluetoothAdvertisement {
+ BluetoothAdvertisementType type;
+ bool include_tx_power;
+ array<BluetoothAdvertisingData> data;
+ // Add more here as Chrome supports it.
+};
+
[Extensible]
enum BluetoothGattDBAttributeType {
BTGATT_DB_PRIMARY_SERVICE = 0,
@@ -268,7 +285,7 @@ struct BluetoothCreateSdpRecordResult {
uint32 service_handle;
};
-// Next Method ID: 40
+// Next Method ID: 43
interface BluetoothHost {
EnableAdapter@0() => (BluetoothAdapterState state);
DisableAdapter@1() => (BluetoothAdapterState state);
@@ -331,6 +348,9 @@ interface BluetoothHost {
[MinVersion=1] ReadRemoteRssi@28(BluetoothAddress remote_addr)
=> (int32 rssi);
+ [MinVersion=2] OpenBluetoothSocket@29()
+ => (handle sock);
+
// Bluetooth Gatt Server functions
// Copied from Android API
// https://source.android.com/devices/halref/bt__gatt__server_8h.html
@@ -358,9 +378,6 @@ interface BluetoothHost {
array<uint8> value)
=> (BluetoothGattStatus status);
- [MinVersion=2] OpenBluetoothSocket@29()
- => (handle sock);
-
// Bluetooth SDP functions
[MinVersion=5] GetSdpRecords@37(BluetoothAddress remote_addr,
BluetoothUUID target_uuid);
@@ -368,6 +385,15 @@ interface BluetoothHost {
=> (BluetoothCreateSdpRecordResult result);
[MinVersion=5] RemoveSdpRecord@39(uint32 service_handle)
=> (BluetoothStatus status);
+
+ // Multi-advertisement functions
+ [MinVersion=6] ReserveAdvertisementHandle@40()
+ => (BluetoothGattStatus status, int32 adv_handle);
+ [MinVersion=6] BroadcastAdvertisement@41(int32 adv_handle,
+ BluetoothAdvertisement adv)
+ => (BluetoothGattStatus status);
+ [MinVersion=6] ReleaseAdvertisementHandle@42(int32 adv_handle)
+ => (BluetoothGattStatus status);
};
// Next Method ID: 18
diff --git a/chromium/components/arc/common/bluetooth.typemap b/chromium/components/arc/common/bluetooth.typemap
index 8ce4cc272d4..fc86d17a20e 100644
--- a/chromium/components/arc/common/bluetooth.typemap
+++ b/chromium/components/arc/common/bluetooth.typemap
@@ -1,6 +1,8 @@
mojom = "//components/arc/common/bluetooth.mojom"
public_headers = [
+ "//device/bluetooth/bluetooth_advertisement.h",
"//device/bluetooth/bluetooth_common.h",
+ "//device/bluetooth/bluetooth_uuid.h",
"//device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h",
]
traits_headers = [ "//components/arc/bluetooth/bluetooth_struct_traits.h" ]
@@ -10,4 +12,6 @@ deps = [
type_mappings = [
"arc.mojom.BluetoothDeviceType=device::BluetoothTransport",
"arc.mojom.BluetoothSdpAttributeType=bluez::BluetoothServiceAttributeValueBlueZ::Type",
+ "arc.mojom.BluetoothUUID=device::BluetoothUUID",
+ "arc.mojom.BluetoothAdvertisement=std::unique_ptr<device::BluetoothAdvertisement::Data>[move_only]",
]
diff --git a/chromium/components/arc/common/boot_phase_monitor.mojom b/chromium/components/arc/common/boot_phase_monitor.mojom
new file mode 100644
index 00000000000..e642f2656da
--- /dev/null
+++ b/chromium/components/arc/common/boot_phase_monitor.mojom
@@ -0,0 +1,19 @@
+// 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.
+//
+// Next MinVersion: 1
+
+module arc.mojom;
+
+// Next method ID: 1
+interface BootPhaseMonitorHost {
+ // Called when ARC's system_server reaches SystemService.PHASE_BOOT_COMPLETED.
+ OnBootCompleted@0();
+};
+
+// Next method ID: 1
+interface BootPhaseMonitorInstance {
+ // Establishes full-duplex communication with the host.
+ Init@0(BootPhaseMonitorHost host_ptr);
+};
diff --git a/chromium/components/arc/common/enterprise_reporting.mojom b/chromium/components/arc/common/enterprise_reporting.mojom
index ff1e23833ae..0ad1ffab2a5 100644
--- a/chromium/components/arc/common/enterprise_reporting.mojom
+++ b/chromium/components/arc/common/enterprise_reporting.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Next MinVersion: 1
+// Next MinVersion: 2
module arc.mojom;
// Enumerates the states that management can be in for a user.
@@ -25,8 +25,12 @@ interface EnterpriseReportingHost {
ReportManagementState@0(ManagementState state);
};
-// Next method ID: 1
+// Next method ID: 2
interface EnterpriseReportingInstance {
// Establishes full-duplex communication with the host.
Init@0(EnterpriseReportingHost host_ptr);
+
+ // Requests that a JSON status blob be generated and passed to the
+ // host.
+ [MinVersion=1] GetStatus@1() => (string status, string droid_guard_info);
};
diff --git a/chromium/components/arc/common/intent_helper.mojom b/chromium/components/arc/common/intent_helper.mojom
index 075721d9c72..05bf9ca0a3d 100644
--- a/chromium/components/arc/common/intent_helper.mojom
+++ b/chromium/components/arc/common/intent_helper.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Next MinVersion: 11
+// Next MinVersion: 12
module arc.mojom;
@@ -41,13 +41,14 @@ struct IntentFilter {
[MinVersion=10] array<PatternMatcher>? deprecated_data_scheme_specific_parts;
};
-// Describes a package that can handle a URL.
-struct UrlHandlerInfo {
+// Describes a package that can handle an intent.
+struct IntentHandlerInfo {
string name;
string package_name;
string activity_name; // A hint for retrieving the package's icon.
- [MinVersion=4] ActionType action;
+ [MinVersion=4] ActionType action_type;
[MinVersion=6] bool is_preferred;
+ [MinVersion=11] string? action; // e.g. "android.intent.action.VIEW"
};
// Describes an activity.
@@ -71,6 +72,7 @@ struct UrlWithMimeType {
};
// Handles intents from ARC in Chrome.
+// Deprecated method ID: 4
// Next method ID: 6
interface IntentHelperHost {
// Called when icons associated with the package are no longer up to date.
@@ -91,7 +93,7 @@ interface IntentHelperHost {
// Sets an image as the wallpaper.
// |jpeg_data| is a JPEG encoded wallpaper image.
- [MinVersion=8] SetWallpaper@4(array<uint8> jpeg_data);
+ [MinVersion=8] SetWallpaperDeprecated@4(array<uint8> jpeg_data);
};
// Sends intents to ARC on behalf of Chrome.
@@ -111,12 +113,12 @@ interface IntentHelperInstance {
// Handles the list of URLs by sending a specified intent to the handler.
[MinVersion=5] HandleUrlList@7(array<UrlWithMimeType> urls,
ActivityName activity,
- ActionType action);
+ ActionType action_type);
// Deprecated. Use HandleUrlList.
[MinVersion=4] HandleUrlListDeprecated@5(array<UrlWithMimeType> urls,
string package_name,
- ActionType action);
+ ActionType action_type);
// Establishes full-duplex communication with the host.
Init@0(IntentHelperHost host_ptr);
@@ -129,11 +131,11 @@ interface IntentHelperInstance {
// Requests a list of packages that can handle the URL.
[MinVersion=2] RequestUrlHandlerList@3(string url)
- => (array<UrlHandlerInfo> handlers);
+ => (array<IntentHandlerInfo> handlers);
// Requests a list of packages that can handle the list of files.
[MinVersion=4] RequestUrlListHandlerList@6(array<UrlWithMimeType> urls)
- => (array<UrlHandlerInfo> handlers);
+ => (array<IntentHandlerInfo> handlers);
// Send an Android broadcast message to the Android package and class
// specified. Data can be sent as extras by including a JSON map string which
diff --git a/chromium/components/arc/common/notifications.mojom b/chromium/components/arc/common/notifications.mojom
index 0bba915874e..37268d204b0 100644
--- a/chromium/components/arc/common/notifications.mojom
+++ b/chromium/components/arc/common/notifications.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Next MinVersion: 8
+// Next MinVersion: 9
module arc.mojom;
@@ -82,6 +82,9 @@ struct ArcNotificationData {
ArcBitmap? snapshot_image;
[MinVersion=7]
float snapshot_image_scale;
+ // Accessibility text
+ [MinVersion=8]
+ string? accessible_name;
};
[MinVersion=2]
diff --git a/chromium/components/arc/common/print.mojom b/chromium/components/arc/common/print.mojom
new file mode 100644
index 00000000000..c72a7898726
--- /dev/null
+++ b/chromium/components/arc/common/print.mojom
@@ -0,0 +1,18 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Next MinVersion: 1
+
+module arc.mojom;
+
+// Next method ID: 1
+interface PrintHost {
+ Print@0(handle file);
+};
+
+// Next method ID: 1
+interface PrintInstance {
+ // Establishes full-duplex communication with the host.
+ Init@0(PrintHost host_ptr);
+};
diff --git a/chromium/components/arc/common/process.mojom b/chromium/components/arc/common/process.mojom
index 6dd05d68d51..20c982fbca7 100644
--- a/chromium/components/arc/common/process.mojom
+++ b/chromium/components/arc/common/process.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Next MinVersion: 5
+// Next MinVersion: 6
module arc.mojom;
@@ -87,6 +87,13 @@ struct RunningAppProcessInfo {
// Package names running in the process.
[MinVersion=4] array<string>? packages;
+
+ // Whether this app is focused in ARC++ multi-window environment.
+ [MinVersion=5] bool is_focused;
+
+ // Last time the process was active. Milliseconds since boot.
+ // The clock is monotonic (comes from Android System.uptimeMillis()).
+ [MinVersion=5] int64 last_activity_time;
};
interface ProcessInstance {
@@ -99,13 +106,13 @@ interface ProcessInstance {
// Sets oom_score_adj of a process.
[MinVersion=2]
- SetOomScoreAdj@2(uint32 pid, int32 score);
+ DeprecatedSetOomScoreAdj@2(uint32 pid, int32 score);
// Disables Android built-in oom_adj adjustment.
[MinVersion=2]
- DisableBuiltinOomAdjustment@3();
+ DeprecatedDisableBuiltinOomAdjustment@3();
// Disables Android lowmemorykiller.
[MinVersion=3]
- DisableLowMemoryKiller@4();
+ DeprecatedDisableLowMemoryKiller@4();
};
diff --git a/chromium/components/arc/common/tts.mojom b/chromium/components/arc/common/tts.mojom
new file mode 100644
index 00000000000..4b7f044db11
--- /dev/null
+++ b/chromium/components/arc/common/tts.mojom
@@ -0,0 +1,43 @@
+// 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.
+// Next MinVersion: 1
+
+module arc.mojom;
+
+[Extensible]
+enum TtsEventType {
+ START = 0,
+ END,
+ INTERRUPTED,
+ ERROR
+};
+
+// Represents a tts utterance sent from Chrome to Android.
+struct TtsUtterance {
+ uint32 utteranceId;
+ string text;
+ double rate;
+ double pitch;
+};
+
+// Next Method ID: 1
+interface TtsHost {
+ // Notifies Chrome of Android tts events.
+ OnTtsEvent@0(uint32 utteranceId,
+ TtsEventType event_type,
+ uint32 charIndex,
+ string error_msg);
+};
+
+// Next Method ID: 3
+interface TtsInstance {
+ // Establishes full-duplex communication with the host.
+ Init@0(TtsHost host_ptr);
+
+ // Sends an utterance to Android for synthesis.
+ Speak@1(TtsUtterance utterance);
+
+ // Sends a stop request to Android text to speech.
+ Stop@2();
+};
diff --git a/chromium/components/arc/common/typemaps.gni b/chromium/components/arc/common/typemaps.gni
index edd6aee7a74..4359362fc8c 100644
--- a/chromium/components/arc/common/typemaps.gni
+++ b/chromium/components/arc/common/typemaps.gni
@@ -4,5 +4,6 @@
typemaps = [
"//components/arc/common/app.typemap",
+ "//components/arc/common/bitmap.typemap",
"//components/arc/common/bluetooth.typemap",
]
diff --git a/chromium/components/arc/common/wallpaper.mojom b/chromium/components/arc/common/wallpaper.mojom
new file mode 100644
index 00000000000..6f400742a4b
--- /dev/null
+++ b/chromium/components/arc/common/wallpaper.mojom
@@ -0,0 +1,28 @@
+// 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.
+//
+// Next MinVersion: 2
+
+module arc.mojom;
+
+// Handles wallpaper calls from ARC in Chrome.
+// Next method ID:2
+interface WallpaperHost {
+ // Gets current wallpaper encoded in PNG and send it back to ARC.
+ GetWallpaper@0() => (array<uint8> wallpaper);
+
+ // Sets an image from ARC as the wallpaper.
+ // |png_data| is a PNG encoded wallpaper image.
+ SetWallpaper@1(array<uint8> png_data);
+};
+
+// Connects with container side to publish wallpaper related intents.
+// Next method ID:2
+interface WallpaperInstance {
+ // Establishes communication with the container side.
+ Init@0(WallpaperHost host_ptr);
+
+ // Notifies ArcWallpaperManagerService that wallpaper is changed.
+ [MinVersion=1] OnWallpaperChanged@1();
+}; \ No newline at end of file
diff --git a/chromium/components/arc/common/window_manager.mojom b/chromium/components/arc/common/window_manager.mojom
deleted file mode 100644
index c456b1ae016..00000000000
--- a/chromium/components/arc/common/window_manager.mojom
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module arc.mojom;
-
-[Extensible]
-enum WindowManagerMode {
- MODE_NORMAL = 0,
- MODE_TOUCH_VIEW = 1
-};
-
-interface WindowManagerInstance {
- // Informs of the currently used window mode.
- OnWindowManagerModeChange@0(WindowManagerMode mode);
-};
diff --git a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc
index 8557308a6b8..2336e09bee8 100644
--- a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc
+++ b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc
@@ -14,13 +14,45 @@
#include "mojo/edk/embedder/embedder.h"
namespace {
+
const char kCrashReporterPath[] = "/sbin/crash_reporter";
+
+// Runs crash_reporter to save the crash info provided via the pipe.
+void RunCrashReporter(const std::string& crash_type,
+ const std::string& device,
+ const std::string& board,
+ const std::string& cpu_abi,
+ mojo::edk::ScopedPlatformHandle pipe) {
+ base::FileHandleMappingVector fd_map = {
+ std::make_pair(pipe.get().handle, STDIN_FILENO)};
+
+ base::LaunchOptions options;
+ options.fds_to_remap = &fd_map;
+
+ auto process =
+ base::LaunchProcess({kCrashReporterPath, "--arc_java_crash=" + crash_type,
+ "--arc_device=" + device, "--arc_board=" + board,
+ "--arc_cpu_abi=" + cpu_abi},
+ options);
+
+ int exit_code = 0;
+ if (!process.WaitForExit(&exit_code)) {
+ LOG(ERROR) << "Failed to wait for " << kCrashReporterPath;
+ } else if (exit_code != EX_OK) {
+ LOG(ERROR) << kCrashReporterPath << " failed with exit code " << exit_code;
+ }
}
+} // namespace
+
namespace arc {
-ArcCrashCollectorBridge::ArcCrashCollectorBridge(ArcBridgeService* bridge)
- : ArcService(bridge), binding_(this) {
+ArcCrashCollectorBridge::ArcCrashCollectorBridge(
+ ArcBridgeService* bridge,
+ scoped_refptr<base::TaskRunner> blocking_task_runner)
+ : ArcService(bridge),
+ blocking_task_runner_(blocking_task_runner),
+ binding_(this) {
arc_bridge_service()->crash_collector()->AddObserver(this);
}
@@ -31,33 +63,20 @@ ArcCrashCollectorBridge::~ArcCrashCollectorBridge() {
void ArcCrashCollectorBridge::OnInstanceReady() {
mojom::CrashCollectorHostPtr host_ptr;
binding_.Bind(mojo::GetProxy(&host_ptr));
- arc_bridge_service()->crash_collector()->instance()->Init(
- std::move(host_ptr));
+ auto* instance =
+ arc_bridge_service()->crash_collector()->GetInstanceForMethod("Init");
+ DCHECK(instance);
+ instance->Init(std::move(host_ptr));
}
void ArcCrashCollectorBridge::DumpCrash(const mojo::String& type,
mojo::ScopedHandle pipe) {
- mojo::edk::ScopedPlatformHandle handle;
- mojo::edk::PassWrappedPlatformHandle(pipe.get().value(), &handle);
-
- base::FileHandleMappingVector fd_map = {
- std::make_pair(handle.get().handle, STDIN_FILENO)};
-
- base::LaunchOptions options;
- options.fds_to_remap = &fd_map;
-
- auto process =
- base::LaunchProcess({kCrashReporterPath, "--arc_java_crash=" + type.get(),
- "--arc_device=" + device_, "--arc_board=" + board_,
- "--arc_cpu_abi=" + cpu_abi_},
- options);
+ mojo::edk::ScopedPlatformHandle pipe_handle;
+ mojo::edk::PassWrappedPlatformHandle(pipe.release().value(), &pipe_handle);
- int exit_code;
- if (!process.WaitForExit(&exit_code)) {
- LOG(ERROR) << "Failed to wait for " << kCrashReporterPath;
- } else if (exit_code != EX_OK) {
- LOG(ERROR) << kCrashReporterPath << " failed with exit code " << exit_code;
- }
+ blocking_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&RunCrashReporter, type, device_, board_, cpu_abi_,
+ base::Passed(std::move(pipe_handle))));
}
void ArcCrashCollectorBridge::SetBuildProperties(const mojo::String& device,
diff --git a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.h b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.h
index cb234759a84..0b7ec562f0c 100644
--- a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.h
+++ b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.h
@@ -8,11 +8,16 @@
#include <string>
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service.h"
#include "components/arc/instance_holder.h"
#include "mojo/public/cpp/bindings/binding.h"
+namespace base {
+class TaskRunner;
+}
+
namespace arc {
// Relays dumps for non-native ARC crashes to the crash reporter in Chrome OS.
@@ -21,7 +26,8 @@ class ArcCrashCollectorBridge
public InstanceHolder<mojom::CrashCollectorInstance>::Observer,
public mojom::CrashCollectorHost {
public:
- explicit ArcCrashCollectorBridge(ArcBridgeService* bridge);
+ ArcCrashCollectorBridge(ArcBridgeService* bridge,
+ scoped_refptr<base::TaskRunner> blocking_task_runner);
~ArcCrashCollectorBridge() override;
// InstanceHolder<mojom::CrashCollectorInstance>::Observer overrides.
@@ -35,6 +41,8 @@ class ArcCrashCollectorBridge
const mojo::String& cpu_abi) override;
private:
+ scoped_refptr<base::TaskRunner> blocking_task_runner_;
+
mojo::Binding<mojom::CrashCollectorHost> binding_;
std::string device_;
diff --git a/chromium/components/arc/ime/arc_ime_bridge_impl.cc b/chromium/components/arc/ime/arc_ime_bridge_impl.cc
index 001f26e84ca..224580f342f 100644
--- a/chromium/components/arc/ime/arc_ime_bridge_impl.cc
+++ b/chromium/components/arc/ime/arc_ime_bridge_impl.cc
@@ -4,6 +4,8 @@
#include "components/arc/ime/arc_ime_bridge_impl.h"
+#include <utility>
+
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "components/arc/arc_bridge_service.h"
@@ -14,8 +16,8 @@
namespace arc {
namespace {
-constexpr int kMinVersionForOnKeyboardsBoundsChanging = 3;
-constexpr int kMinVersionForExtendSelectionAndDelete = 4;
+constexpr uint32_t kMinVersionForOnKeyboardsBoundsChanging = 3;
+constexpr uint32_t kMinVersionForExtendSelectionAndDelete = 4;
ui::TextInputType ConvertTextInputType(arc::mojom::TextInputType ipc_type) {
// The two enum types are similar, but intentionally made not identical.
@@ -86,70 +88,56 @@ ArcImeBridgeImpl::~ArcImeBridgeImpl() {
}
void ArcImeBridgeImpl::OnInstanceReady() {
- bridge_service_->ime()->instance()->Init(
- binding_.CreateInterfacePtrAndBind());
+ auto* instance = bridge_service_->ime()->GetInstanceForMethod("Init");
+ DCHECK(instance);
+ instance->Init(binding_.CreateInterfacePtrAndBind());
}
void ArcImeBridgeImpl::SendSetCompositionText(
const ui::CompositionText& composition) {
- mojom::ImeInstance* ime_instance = bridge_service_->ime()->instance();
- if (!ime_instance) {
- LOG(ERROR) << "ArcImeInstance method called before being ready.";
+ auto* ime_instance =
+ bridge_service_->ime()->GetInstanceForMethod("SetCompositionText");
+ if (!ime_instance)
return;
- }
ime_instance->SetCompositionText(base::UTF16ToUTF8(composition.text),
ConvertSegments(composition));
}
void ArcImeBridgeImpl::SendConfirmCompositionText() {
- mojom::ImeInstance* ime_instance = bridge_service_->ime()->instance();
- if (!ime_instance) {
- LOG(ERROR) << "ArcImeInstance method called before being ready.";
+ auto* ime_instance =
+ bridge_service_->ime()->GetInstanceForMethod("ConfirmCompositionText");
+ if (!ime_instance)
return;
- }
ime_instance->ConfirmCompositionText();
}
void ArcImeBridgeImpl::SendInsertText(const base::string16& text) {
- mojom::ImeInstance* ime_instance = bridge_service_->ime()->instance();
- if (!ime_instance) {
- LOG(ERROR) << "ArcImeInstance method called before being ready.";
+ auto* ime_instance =
+ bridge_service_->ime()->GetInstanceForMethod("InsertText");
+ if (!ime_instance)
return;
- }
ime_instance->InsertText(base::UTF16ToUTF8(text));
}
void ArcImeBridgeImpl::SendOnKeyboardBoundsChanging(
const gfx::Rect& new_bounds) {
- mojom::ImeInstance* ime_instance = bridge_service_->ime()->instance();
- if (!ime_instance) {
- LOG(ERROR) << "ArcImeInstance method called before being ready.";
- return;
- }
- if (bridge_service_->ime()->version() <
- kMinVersionForOnKeyboardsBoundsChanging) {
- LOG(ERROR) << "ArcImeInstance is too old for OnKeyboardsBoundsChanging.";
+ auto* ime_instance = bridge_service_->ime()->GetInstanceForMethod(
+ "OnKeyboardBoundsChanging", kMinVersionForOnKeyboardsBoundsChanging);
+ if (!ime_instance)
return;
- }
ime_instance->OnKeyboardBoundsChanging(new_bounds);
}
void ArcImeBridgeImpl::SendExtendSelectionAndDelete(
size_t before, size_t after) {
- mojom::ImeInstance* ime_instance = bridge_service_->ime()->instance();
- if (!ime_instance) {
- LOG(ERROR) << "ArcImeInstance method called before being ready.";
+ auto* ime_instance = bridge_service_->ime()->GetInstanceForMethod(
+ "ExtendSelectionAndDelete", kMinVersionForExtendSelectionAndDelete);
+ if (!ime_instance)
return;
- }
- if (bridge_service_->ime()->version() <
- kMinVersionForExtendSelectionAndDelete) {
- LOG(ERROR) << "ArcImeInstance is too old for ExtendSelectionAndDelete.";
- return;
- }
ime_instance->ExtendSelectionAndDelete(before, after);
}
diff --git a/chromium/components/arc/ime/arc_ime_service.cc b/chromium/components/arc/ime/arc_ime_service.cc
index d17610fe037..e6767ac9b42 100644
--- a/chromium/components/arc/ime/arc_ime_service.cc
+++ b/chromium/components/arc/ime/arc_ime_service.cc
@@ -4,12 +4,13 @@
#include "components/arc/ime/arc_ime_service.h"
+#include <utility>
+
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "components/arc/ime/arc_ime_bridge_impl.h"
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
-#include "ui/aura/client/focus_client.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
@@ -41,7 +42,8 @@ ArcImeService::ArcImeService(ArcBridgeService* bridge_service)
ime_type_(ui::TEXT_INPUT_TYPE_NONE),
has_composition_text_(false),
keyboard_controller_(nullptr),
- test_input_method_(nullptr) {
+ test_input_method_(nullptr),
+ is_focus_observer_installed_(false) {
aura::Env* env = aura::Env::GetInstanceDontCreate();
if (env)
env->AddObserver(this);
@@ -52,10 +54,8 @@ ArcImeService::~ArcImeService() {
if (input_method)
input_method->DetachTextInputClient(this);
- for (aura::Window* window : arc_windows_.windows())
- window->RemoveObserver(this);
- for (aura::Window* root : observing_root_windows_.windows())
- aura::client::GetFocusClient(root)->RemoveObserver(this);
+ if (is_focus_observer_installed_ && exo::WMHelper::GetInstance())
+ exo::WMHelper::GetInstance()->RemoveFocusObserver(this);
aura::Env* env = aura::Env::GetInstanceDontCreate();
if (env)
env->RemoveObserver(this);
@@ -90,8 +90,10 @@ ui::InputMethod* ArcImeService::GetInputMethod() {
void ArcImeService::OnWindowInitialized(aura::Window* new_window) {
if (IsArcWindow(new_window)) {
- arc_windows_.Add(new_window);
- new_window->AddObserver(this);
+ if (!is_focus_observer_installed_) {
+ exo::WMHelper::GetInstance()->AddFocusObserver(this);
+ is_focus_observer_installed_ = true;
+ }
}
keyboard::KeyboardController* keyboard_controller =
keyboard::KeyboardController::GetInstance();
@@ -102,17 +104,8 @@ void ArcImeService::OnWindowInitialized(aura::Window* new_window) {
}
}
-void ArcImeService::OnWindowAddedToRootWindow(aura::Window* window) {
- aura::Window* root = window->GetRootWindow();
- aura::client::FocusClient* focus_client = aura::client::GetFocusClient(root);
- if (focus_client && !observing_root_windows_.Contains(root)) {
- focus_client->AddObserver(this);
- observing_root_windows_.Add(root);
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
-// Overridden from aura::client::FocusChangeObserver:
+// Overridden from exo::WMHelper::FocusChangeObserver:
void ArcImeService::OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) {
@@ -147,15 +140,8 @@ void ArcImeService::OnTextInputTypeChanged(ui::TextInputType type) {
ime_type_ = type;
ui::InputMethod* const input_method = GetInputMethod();
- if (input_method) {
+ if (input_method)
input_method->OnTextInputTypeChanged(this);
- // TODO(crbug.com/581282): Remove this piggyback call when
- // ImeInstance::ShowImeIfNeeded is wired to ARC.
- if (input_method->GetTextInputClient() == this &&
- ime_type_ != ui::TEXT_INPUT_TYPE_NONE) {
- input_method->ShowImeIfNeeded();
- }
- }
}
void ArcImeService::OnCursorRectChanged(const gfx::Rect& rect) {
@@ -193,6 +179,8 @@ void ArcImeService::OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) {
ime_bridge_->SendOnKeyboardBoundsChanging(bounds_in_px);
}
+void ArcImeService::OnKeyboardClosed() {}
+
////////////////////////////////////////////////////////////////////////////////
// Overridden from ui::TextInputClient:
diff --git a/chromium/components/arc/ime/arc_ime_service.h b/chromium/components/arc/ime/arc_ime_service.h
index b29548c1dfa..0db9e2e8023 100644
--- a/chromium/components/arc/ime/arc_ime_service.h
+++ b/chromium/components/arc/ime/arc_ime_service.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "components/arc/arc_service.h"
#include "components/arc/ime/arc_ime_bridge.h"
-#include "ui/aura/client/focus_change_observer.h"
+#include "components/exo/wm_helper.h"
#include "ui/aura/env_observer.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tracker.h"
@@ -38,8 +38,7 @@ class ArcBridgeService;
class ArcImeService : public ArcService,
public ArcImeBridge::Delegate,
public aura::EnvObserver,
- public aura::WindowObserver,
- public aura::client::FocusChangeObserver,
+ public exo::WMHelper::FocusObserver,
public keyboard::KeyboardControllerObserver,
public ui::TextInputClient {
public:
@@ -55,10 +54,7 @@ class ArcImeService : public ArcService,
// Overridden from aura::EnvObserver:
void OnWindowInitialized(aura::Window* new_window) override;
- // Overridden from aura::WindowObserver:
- void OnWindowAddedToRootWindow(aura::Window* window) override;
-
- // Overridden from aura::client::FocusChangeObserver:
+ // Overridden from exo::WMHelper::FocusObserver:
void OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) override;
@@ -70,6 +66,7 @@ class ArcImeService : public ArcService,
// Overridden from keyboard::KeyboardControllerObserver.
void OnKeyboardBoundsChanging(const gfx::Rect& rect) override;
+ void OnKeyboardClosed() override;
// Overridden from ui::TextInputClient:
void SetCompositionText(const ui::CompositionText& composition) override;
@@ -114,13 +111,12 @@ class ArcImeService : public ArcService,
gfx::Rect cursor_rect_;
bool has_composition_text_;
- aura::WindowTracker observing_root_windows_;
- aura::WindowTracker arc_windows_;
aura::WindowTracker focused_arc_window_;
keyboard::KeyboardController* keyboard_controller_;
ui::InputMethod* test_input_method_;
+ bool is_focus_observer_installed_;
DISALLOW_COPY_AND_ASSIGN(ArcImeService);
};
diff --git a/chromium/components/arc/ime/arc_ime_service_unittest.cc b/chromium/components/arc/ime/arc_ime_service_unittest.cc
index 7b38a873dd9..0cbd888452e 100644
--- a/chromium/components/arc/ime/arc_ime_service_unittest.cc
+++ b/chromium/components/arc/ime/arc_ime_service_unittest.cc
@@ -142,19 +142,12 @@ TEST_F(ArcImeServiceTest, ShowImeIfNeeded) {
instance_->OnTextInputTypeChanged(ui::TEXT_INPUT_TYPE_NONE);
ASSERT_EQ(0, fake_input_method_->count_show_ime_if_needed());
+ // Text input type change does not imply the show ime request.
instance_->OnTextInputTypeChanged(ui::TEXT_INPUT_TYPE_TEXT);
- EXPECT_EQ(1, fake_input_method_->count_show_ime_if_needed());
+ EXPECT_EQ(0, fake_input_method_->count_show_ime_if_needed());
- // The type is not changing, hence no call.
- instance_->OnTextInputTypeChanged(ui::TEXT_INPUT_TYPE_TEXT);
+ instance_->ShowImeIfNeeded();
EXPECT_EQ(1, fake_input_method_->count_show_ime_if_needed());
-
- instance_->OnTextInputTypeChanged(ui::TEXT_INPUT_TYPE_SEARCH);
- EXPECT_EQ(2, fake_input_method_->count_show_ime_if_needed());
-
- // Change to NONE should not trigger the showing event.
- instance_->OnTextInputTypeChanged(ui::TEXT_INPUT_TYPE_NONE);
- EXPECT_EQ(2, fake_input_method_->count_show_ime_if_needed());
}
TEST_F(ArcImeServiceTest, CancelComposition) {
diff --git a/chromium/components/arc/instance_holder.h b/chromium/components/arc/instance_holder.h
index bb5b3644d27..0edb0f2c9df 100644
--- a/chromium/components/arc/instance_holder.h
+++ b/chromium/components/arc/instance_holder.h
@@ -5,14 +5,13 @@
#ifndef COMPONENTS_ARC_INSTANCE_HOLDER_H_
#define COMPONENTS_ARC_INSTANCE_HOLDER_H_
+#include <string>
#include <utility>
#include "base/bind.h"
#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
-#include "mojo/public/cpp/bindings/interface_ptr.h"
namespace arc {
@@ -35,14 +34,39 @@ class InstanceHolder {
virtual ~Observer() = default;
};
- InstanceHolder() : weak_factory_(this) {}
+ InstanceHolder() = default;
+
+ // Returns true if the Mojo interface is ready at least for its version 0
+ // interface. Use an Observer if you want to be notified when this is ready.
+ // This can only be called on the thread that this class was created on.
+ bool has_instance() const { return instance_; }
+
+ // Gets the Mojo interface that's intended to call for
+ // |method_name_for_logging|, but only if its reported version is at least
+ // |min_version|. Returns nullptr if the instance is either not ready or does
+ // not have the requested version, and logs appropriately.
+ // TODO(lhchavez): Improve the API. (crbug.com/649782)
+ T* GetInstanceForMethod(const std::string& method_name_for_logging,
+ uint32_t min_version) {
+ if (!instance_) {
+ VLOG(1) << "Instance for " << T::Name_ << "::" << method_name_for_logging
+ << " not available.";
+ return nullptr;
+ }
+ if (version_ < min_version) {
+ LOG(ERROR) << "Instance for " << T::Name_
+ << "::" << method_name_for_logging
+ << " version mismatch. Expected " << min_version << " got "
+ << version_;
+ return nullptr;
+ }
+ return instance_;
+ }
- // Gets the Mojo interface for all the instance services. This will return
- // nullptr if that particular service is not ready yet. Use an Observer if you
- // want to be notified when this is ready. This can only be called on the
- // thread that this class was created on.
- T* instance() const { return raw_ptr_; }
- uint32_t version() const { return version_; }
+ // Same as the above, but for the version zero.
+ T* GetInstanceForMethod(const std::string& method_name_for_logging) {
+ return GetInstanceForMethod(method_name_for_logging, 0u);
+ }
// Adds or removes observers. This can only be called on the thread that this
// class was created on. RemoveObserver does nothing if |observer| is not in
@@ -51,7 +75,7 @@ class InstanceHolder {
DCHECK(thread_checker_.CalledOnValidThread());
observer_list_.AddObserver(observer);
- if (instance())
+ if (instance_)
observer->OnInstanceReady();
}
@@ -60,75 +84,36 @@ class InstanceHolder {
observer_list_.RemoveObserver(observer);
}
- // Called when the channel is closed.
- void CloseChannel() {
- if (!raw_ptr_)
- return;
-
- ptr_.reset();
- raw_ptr_ = nullptr;
- version_ = 0;
- if (observer_list_.might_have_observers()) {
- typename base::ObserverList<Observer>::Iterator it(&observer_list_);
- Observer* obs;
- while ((obs = it.GetNext()) != nullptr)
- obs->OnInstanceClosed();
- }
- }
+ // Sets |instance| with |version|.
+ // This can be called in both case; on ready, and on closed.
+ // Passing nullptr to |instance| means closing.
+ void SetInstance(T* instance, uint32_t version = T::Version_) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(instance == nullptr || instance_ == nullptr);
- // Sets the interface pointer to |ptr|, once the version is determined. This
- // will eventually invoke SetInstance(), which will notify the observers.
- void OnInstanceReady(mojo::InterfacePtr<T> ptr) {
- temporary_ptr_ = std::move(ptr);
- temporary_ptr_.QueryVersion(base::Bind(&InstanceHolder<T>::OnVersionReady,
- weak_factory_.GetWeakPtr()));
- }
+ // Note: This can be called with nullptr even if |instance_| is still
+ // nullptr for just in case clean up purpose. No-op in such a case.
+ if (instance == instance_)
+ return;
- // This method is not intended to be called directly. Normally it is called by
- // OnInstanceReady once the version of the instance is determined, but it is
- // also exposed so that tests can directly inject a raw pointer+version
- // combination.
- void SetInstance(T* raw_ptr, uint32_t raw_version = T::Version_) {
- raw_ptr_ = raw_ptr;
- version_ = raw_version;
- if (observer_list_.might_have_observers()) {
- typename base::ObserverList<Observer>::Iterator it(&observer_list_);
- Observer* obs;
- while ((obs = it.GetNext()) != nullptr)
- obs->OnInstanceReady();
+ instance_ = instance;
+ version_ = version;
+ if (instance_) {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnInstanceReady());
+ } else {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnInstanceClosed());
}
}
private:
- void OnVersionReady(uint32_t version) {
- ptr_ = std::move(temporary_ptr_);
- ptr_.set_connection_error_handler(base::Bind(
- &InstanceHolder<T>::CloseChannel, weak_factory_.GetWeakPtr()));
- SetInstance(ptr_.get(), version);
- }
-
- // These two are copies of the contents of ptr_. They are provided here just
- // so that tests can provide non-mojo implementations.
- T* raw_ptr_ = nullptr;
+ // This class does not have ownership. The pointers should be managed by the
+ // callee.
+ T* instance_ = nullptr;
uint32_t version_ = 0;
- mojo::InterfacePtr<T> ptr_;
-
- // Temporary Mojo interfaces. After a Mojo interface pointer has been
- // received from the other endpoint, we still need to asynchronously query its
- // version. While that is going on, we should still return nullptr on the
- // instance() function.
- // To keep the instance() functions being trivial, store the instance pointer
- // in a temporary variable to avoid losing its reference.
- mojo::InterfacePtr<T> temporary_ptr_;
-
base::ThreadChecker thread_checker_;
base::ObserverList<Observer> observer_list_;
- // This needs to be the last member in order to cancel all inflight callbacks
- // before destroying any other members.
- base::WeakPtrFactory<InstanceHolder<T>> weak_factory_;
-
DISALLOW_COPY_AND_ASSIGN(InstanceHolder<T>);
};
diff --git a/chromium/components/arc/intent_helper/activity_icon_loader.cc b/chromium/components/arc/intent_helper/activity_icon_loader.cc
index 5248f7599cb..de77609e060 100644
--- a/chromium/components/arc/intent_helper/activity_icon_loader.cc
+++ b/chromium/components/arc/intent_helper/activity_icon_loader.cc
@@ -7,6 +7,7 @@
#include <string.h>
#include <tuple>
+#include <utility>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
@@ -27,30 +28,6 @@ const size_t kMaxIconSizeInPx = 200;
const int kMinInstanceVersion = 3; // see intent_helper.mojom
-mojom::IntentHelperInstance* GetIntentHelperInstance(
- ActivityIconLoader::GetResult* out_error_code) {
- DCHECK(out_error_code);
- ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
- if (!bridge_service) {
- VLOG(2) << "ARC bridge is not ready.";
- *out_error_code = ActivityIconLoader::GetResult::FAILED_ARC_NOT_SUPPORTED;
- return nullptr;
- }
- mojom::IntentHelperInstance* intent_helper_instance =
- bridge_service->intent_helper()->instance();
- if (!intent_helper_instance) {
- VLOG(2) << "ARC intent helper instance is not ready.";
- *out_error_code = ActivityIconLoader::GetResult::FAILED_ARC_NOT_READY;
- return nullptr;
- }
- if (bridge_service->intent_helper()->version() < kMinInstanceVersion) {
- VLOG(1) << "ARC intent helper instance is too old.";
- *out_error_code = ActivityIconLoader::GetResult::FAILED_ARC_NOT_SUPPORTED;
- return nullptr;
- }
- return intent_helper_instance;
-}
-
ui::ScaleFactor GetSupportedScaleFactor() {
std::vector<ui::ScaleFactor> scale_factors = ui::GetSupportedScaleFactors();
DCHECK(!scale_factors.empty());
@@ -111,13 +88,20 @@ ActivityIconLoader::GetResult ActivityIconLoader::GetActivityIcons(
return GetResult::SUCCEEDED_SYNC;
}
- GetResult error_code = GetResult::FAILED_ARC_NOT_SUPPORTED;
- mojom::IntentHelperInstance* instance = GetIntentHelperInstance(&error_code);
+ ArcIntentHelperBridge::GetResult error_code;
+ auto* instance = ArcIntentHelperBridge::GetIntentHelperInstanceWithErrorCode(
+ "RequestActivityIcons", kMinInstanceVersion, &error_code);
if (!instance) {
// The mojo channel is not yet ready (or not supported at all). Run the
// callback with |result| that could be empty.
cb.Run(std::move(result));
- return error_code;
+ switch (error_code) {
+ case ArcIntentHelperBridge::GetResult::FAILED_ARC_NOT_READY:
+ return GetResult(GetResult::FAILED_ARC_NOT_READY);
+ case ArcIntentHelperBridge::GetResult::FAILED_ARC_NOT_SUPPORTED:
+ return GetResult(GetResult::FAILED_ARC_NOT_SUPPORTED);
+ }
+ NOTREACHED();
}
// Fetch icons from ARC.
diff --git a/chromium/components/arc/intent_helper/activity_icon_loader.h b/chromium/components/arc/intent_helper/activity_icon_loader.h
index 570d1f7ca90..a03870c0650 100644
--- a/chromium/components/arc/intent_helper/activity_icon_loader.h
+++ b/chromium/components/arc/intent_helper/activity_icon_loader.h
@@ -16,6 +16,7 @@
#include "base/threading/thread_checker.h"
#include "components/arc/arc_service.h"
#include "components/arc/common/intent_helper.mojom.h"
+#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
#include "ui/base/layout.h"
#include "ui/gfx/image/image.h"
diff --git a/chromium/components/arc/intent_helper/activity_icon_loader_unittest.cc b/chromium/components/arc/intent_helper/activity_icon_loader_unittest.cc
index e56d68dee92..650fa8255d0 100644
--- a/chromium/components/arc/intent_helper/activity_icon_loader_unittest.cc
+++ b/chromium/components/arc/intent_helper/activity_icon_loader_unittest.cc
@@ -5,6 +5,7 @@
#include "components/arc/intent_helper/activity_icon_loader.h"
#include <memory>
+#include <utility>
#include <vector>
#include "base/bind.h"
diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
index 6a3fae9f41b..e7af4fa08f7 100644
--- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
+++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
@@ -7,15 +7,16 @@
#include <utility>
#include <vector>
-#include "ash/desktop_background/user_wallpaper_delegate.h"
-#include "ash/new_window_delegate.h"
+#include "ash/common/new_window_delegate.h"
+#include "ash/common/shell_delegate.h"
+#include "ash/common/wallpaper/wallpaper_delegate.h"
+#include "ash/common/wm_shell.h"
#include "ash/shell.h"
-#include "ash/shell_delegate.h"
+#include "base/command_line.h"
#include "base/memory/weak_ptr.h"
#include "components/arc/intent_helper/activity_icon_loader.h"
#include "components/arc/intent_helper/link_handler_model_impl.h"
#include "components/arc/intent_helper/local_activity_resolver.h"
-#include "components/arc/set_wallpaper_delegate.h"
#include "ui/base/layout.h"
#include "url/gurl.h"
@@ -30,12 +31,10 @@ constexpr char kArcIntentHelperPackageName[] = "org.chromium.arc.intent_helper";
ArcIntentHelperBridge::ArcIntentHelperBridge(
ArcBridgeService* bridge_service,
const scoped_refptr<ActivityIconLoader>& icon_loader,
- std::unique_ptr<SetWallpaperDelegate> set_wallpaper_delegate,
const scoped_refptr<LocalActivityResolver>& activity_resolver)
: ArcService(bridge_service),
binding_(this),
icon_loader_(icon_loader),
- set_wallpaper_delegate_(std::move(set_wallpaper_delegate)),
activity_resolver_(activity_resolver) {
DCHECK(thread_checker_.CalledOnValidThread());
arc_bridge_service()->intent_helper()->AddObserver(this);
@@ -49,8 +48,10 @@ ArcIntentHelperBridge::~ArcIntentHelperBridge() {
void ArcIntentHelperBridge::OnInstanceReady() {
DCHECK(thread_checker_.CalledOnValidThread());
ash::Shell::GetInstance()->set_link_handler_model_factory(this);
- arc_bridge_service()->intent_helper()->instance()->Init(
- binding_.CreateInterfacePtrAndBind());
+ auto* instance =
+ arc_bridge_service()->intent_helper()->GetInstanceForMethod("Init");
+ DCHECK(instance);
+ instance->Init(binding_.CreateInterfacePtrAndBind());
}
void ArcIntentHelperBridge::OnInstanceClosed() {
@@ -70,23 +71,24 @@ void ArcIntentHelperBridge::OnOpenDownloads() {
// downloads by default, which is what we want. However if it is open it will
// simply be brought to the forgeground without forcibly being navigated to
// downloads, which is probably not ideal.
- ash::Shell::GetInstance()->new_window_delegate()->OpenFileManager();
+ ash::WmShell::Get()->new_window_delegate()->OpenFileManager();
}
void ArcIntentHelperBridge::OnOpenUrl(const mojo::String& url) {
DCHECK(thread_checker_.CalledOnValidThread());
GURL gurl(url.get());
- ash::Shell::GetInstance()->delegate()->OpenUrlFromArc(gurl);
+ ash::WmShell::Get()->delegate()->OpenUrlFromArc(gurl);
}
void ArcIntentHelperBridge::OpenWallpaperPicker() {
DCHECK(thread_checker_.CalledOnValidThread());
- ash::Shell::GetInstance()->user_wallpaper_delegate()->OpenSetWallpaperPage();
+ ash::WmShell::Get()->wallpaper_delegate()->OpenSetWallpaperPage();
}
-void ArcIntentHelperBridge::SetWallpaper(mojo::Array<uint8_t> jpeg_data) {
+void ArcIntentHelperBridge::SetWallpaperDeprecated(
+ mojo::Array<uint8_t> jpeg_data) {
DCHECK(thread_checker_.CalledOnValidThread());
- set_wallpaper_delegate_->SetWallpaper(jpeg_data.PassStorage());
+ LOG(ERROR) << "IntentHelper.SetWallpaper is deprecated";
}
std::unique_ptr<ash::LinkHandlerModel> ArcIntentHelperBridge::CreateModel(
@@ -106,10 +108,10 @@ bool ArcIntentHelperBridge::IsIntentHelperPackage(
}
// static
-mojo::Array<mojom::UrlHandlerInfoPtr>
+mojo::Array<mojom::IntentHandlerInfoPtr>
ArcIntentHelperBridge::FilterOutIntentHelper(
- mojo::Array<mojom::UrlHandlerInfoPtr> handlers) {
- mojo::Array<mojom::UrlHandlerInfoPtr> handlers_filtered;
+ mojo::Array<mojom::IntentHandlerInfoPtr> handlers) {
+ mojo::Array<mojom::IntentHandlerInfoPtr> handlers_filtered;
for (auto& handler : handlers) {
if (IsIntentHelperPackage(handler->package_name.get()))
continue;
@@ -118,6 +120,51 @@ ArcIntentHelperBridge::FilterOutIntentHelper(
return handlers_filtered;
}
+// static
+mojom::IntentHelperInstance*
+ArcIntentHelperBridge::GetIntentHelperInstanceWithErrorCode(
+ const std::string& method_name_for_logging,
+ uint32_t min_instance_version,
+ GetResult* out_error_code) {
+ ArcBridgeService* bridge_service = ArcBridgeService::Get();
+ if (!bridge_service) {
+ if (!ArcBridgeService::GetEnabled(base::CommandLine::ForCurrentProcess())) {
+ VLOG(2) << "ARC bridge is not supported.";
+ if (out_error_code)
+ *out_error_code = GetResult::FAILED_ARC_NOT_SUPPORTED;
+ } else {
+ VLOG(2) << "ARC bridge is not ready.";
+ if (out_error_code)
+ *out_error_code = GetResult::FAILED_ARC_NOT_READY;
+ }
+ return nullptr;
+ }
+
+ if (!bridge_service->intent_helper()->has_instance()) {
+ VLOG(2) << "ARC intent helper instance is not ready.";
+ if (out_error_code)
+ *out_error_code = GetResult::FAILED_ARC_NOT_READY;
+ return nullptr;
+ }
+
+ auto* instance = bridge_service->intent_helper()->GetInstanceForMethod(
+ method_name_for_logging, min_instance_version);
+ if (!instance) {
+ if (out_error_code)
+ *out_error_code = GetResult::FAILED_ARC_NOT_SUPPORTED;
+ return nullptr;
+ }
+ return instance;
+}
+
+// static
+mojom::IntentHelperInstance* ArcIntentHelperBridge::GetIntentHelperInstance(
+ const std::string& method_name_for_logging,
+ uint32_t min_instance_version) {
+ return GetIntentHelperInstanceWithErrorCode(method_name_for_logging,
+ min_instance_version, nullptr);
+}
+
void ArcIntentHelperBridge::OnIntentFiltersUpdated(
mojo::Array<mojom::IntentFilterPtr> filters) {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h
index a48e90e85da..fbc2f922e2a 100644
--- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h
+++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h
@@ -37,10 +37,18 @@ class ArcIntentHelperBridge
public mojom::IntentHelperHost,
public ash::LinkHandlerModelFactory {
public:
+ enum class GetResult {
+ // Failed. The intent_helper instance is not yet ready. This is a temporary
+ // error.
+ FAILED_ARC_NOT_READY,
+ // Failed. Either ARC is not supported at all or intent_helper instance
+ // version is too old.
+ FAILED_ARC_NOT_SUPPORTED,
+ };
+
ArcIntentHelperBridge(
ArcBridgeService* bridge_service,
const scoped_refptr<ActivityIconLoader>& icon_loader,
- std::unique_ptr<SetWallpaperDelegate> set_wallpaper_delegate,
const scoped_refptr<LocalActivityResolver>& activity_resolver);
~ArcIntentHelperBridge() override;
@@ -55,7 +63,7 @@ class ArcIntentHelperBridge
void OnOpenDownloads() override;
void OnOpenUrl(const mojo::String& url) override;
void OpenWallpaperPicker() override;
- void SetWallpaper(mojo::Array<uint8_t> jpeg_data) override;
+ void SetWallpaperDeprecated(mojo::Array<uint8_t> jpeg_data) override;
// ash::LinkHandlerModelFactory
std::unique_ptr<ash::LinkHandlerModel> CreateModel(const GURL& url) override;
@@ -65,13 +73,24 @@ class ArcIntentHelperBridge
// Filters out handlers that belong to the intent_helper apk and returns
// a new array.
- static mojo::Array<mojom::UrlHandlerInfoPtr> FilterOutIntentHelper(
- mojo::Array<mojom::UrlHandlerInfoPtr> handlers);
+ static mojo::Array<mojom::IntentHandlerInfoPtr> FilterOutIntentHelper(
+ mojo::Array<mojom::IntentHandlerInfoPtr> handlers);
+
+ // Gets the mojo instance if it's available. On failure, returns nullptr and
+ // updates |out_error_code| if it's not nullptr.
+ static mojom::IntentHelperInstance* GetIntentHelperInstanceWithErrorCode(
+ const std::string& method_name_for_logging,
+ uint32_t min_instance_version,
+ GetResult* out_error_code);
+
+ // Does the same as above without asking for the error code.
+ static mojom::IntentHelperInstance* GetIntentHelperInstance(
+ const std::string& method_name_for_logging,
+ uint32_t min_instance_version);
private:
mojo::Binding<mojom::IntentHelperHost> binding_;
scoped_refptr<ActivityIconLoader> icon_loader_;
- std::unique_ptr<SetWallpaperDelegate> set_wallpaper_delegate_;
scoped_refptr<LocalActivityResolver> activity_resolver_;
base::ThreadChecker thread_checker_;
diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc b/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
index c9ae36f4a45..eeae89bf8d3 100644
--- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
+++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
@@ -4,6 +4,8 @@
#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
+#include <utility>
+
#include "components/arc/common/intent_helper.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,38 +32,38 @@ TEST(ArcIntentHelperTest, TestIsIntentHelperPackage) {
// Tests if FilterOutIntentHelper removes handlers as expected.
TEST(ArcIntentHelperTest, TestFilterOutIntentHelper) {
{
- mojo::Array<mojom::UrlHandlerInfoPtr> orig;
- mojo::Array<mojom::UrlHandlerInfoPtr> filtered =
+ mojo::Array<mojom::IntentHandlerInfoPtr> orig;
+ mojo::Array<mojom::IntentHandlerInfoPtr> filtered =
ArcIntentHelperBridge::FilterOutIntentHelper(std::move(orig));
EXPECT_EQ(0U, filtered.size());
}
{
- mojo::Array<mojom::UrlHandlerInfoPtr> orig;
- orig.push_back(mojom::UrlHandlerInfo::New());
+ mojo::Array<mojom::IntentHandlerInfoPtr> orig;
+ orig.push_back(mojom::IntentHandlerInfo::New());
orig[0]->name = "0";
orig[0]->package_name = "package_name0";
- orig.push_back(mojom::UrlHandlerInfo::New());
+ orig.push_back(mojom::IntentHandlerInfo::New());
orig[1]->name = "1";
orig[1]->package_name = "package_name1";
// FilterOutIntentHelper is no-op in this case.
- mojo::Array<mojom::UrlHandlerInfoPtr> filtered =
+ mojo::Array<mojom::IntentHandlerInfoPtr> filtered =
ArcIntentHelperBridge::FilterOutIntentHelper(std::move(orig));
EXPECT_EQ(2U, filtered.size());
}
{
- mojo::Array<mojom::UrlHandlerInfoPtr> orig;
- orig.push_back(mojom::UrlHandlerInfo::New());
+ mojo::Array<mojom::IntentHandlerInfoPtr> orig;
+ orig.push_back(mojom::IntentHandlerInfo::New());
orig[0]->name = "0";
orig[0]->package_name = kArcIntentHelperPackageName;
- orig.push_back(mojom::UrlHandlerInfo::New());
+ orig.push_back(mojom::IntentHandlerInfo::New());
orig[1]->name = "1";
orig[1]->package_name = "package_name1";
// FilterOutIntentHelper should remove the first element.
- mojo::Array<mojom::UrlHandlerInfoPtr> filtered =
+ mojo::Array<mojom::IntentHandlerInfoPtr> filtered =
ArcIntentHelperBridge::FilterOutIntentHelper(std::move(orig));
ASSERT_EQ(1U, filtered.size());
EXPECT_EQ("1", filtered[0]->name);
@@ -69,19 +71,19 @@ TEST(ArcIntentHelperTest, TestFilterOutIntentHelper) {
}
{
- mojo::Array<mojom::UrlHandlerInfoPtr> orig;
- orig.push_back(mojom::UrlHandlerInfo::New());
+ mojo::Array<mojom::IntentHandlerInfoPtr> orig;
+ orig.push_back(mojom::IntentHandlerInfo::New());
orig[0]->name = "0";
orig[0]->package_name = kArcIntentHelperPackageName;
- orig.push_back(mojom::UrlHandlerInfo::New());
+ orig.push_back(mojom::IntentHandlerInfo::New());
orig[1]->name = "1";
orig[1]->package_name = "package_name1";
- orig.push_back(mojom::UrlHandlerInfo::New());
+ orig.push_back(mojom::IntentHandlerInfo::New());
orig[2]->name = "2";
orig[2]->package_name = kArcIntentHelperPackageName;
// FilterOutIntentHelper should remove two elements.
- mojo::Array<mojom::UrlHandlerInfoPtr> filtered =
+ mojo::Array<mojom::IntentHandlerInfoPtr> filtered =
ArcIntentHelperBridge::FilterOutIntentHelper(std::move(orig));
ASSERT_EQ(1U, filtered.size());
EXPECT_EQ("1", filtered[0]->name);
@@ -89,16 +91,16 @@ TEST(ArcIntentHelperTest, TestFilterOutIntentHelper) {
}
{
- mojo::Array<mojom::UrlHandlerInfoPtr> orig;
- orig.push_back(mojom::UrlHandlerInfo::New());
+ mojo::Array<mojom::IntentHandlerInfoPtr> orig;
+ orig.push_back(mojom::IntentHandlerInfo::New());
orig[0]->name = "0";
orig[0]->package_name = kArcIntentHelperPackageName;
- orig.push_back(mojom::UrlHandlerInfo::New());
+ orig.push_back(mojom::IntentHandlerInfo::New());
orig[1]->name = "1";
orig[1]->package_name = kArcIntentHelperPackageName;
// FilterOutIntentHelper should remove all elements.
- mojo::Array<mojom::UrlHandlerInfoPtr> filtered =
+ mojo::Array<mojom::IntentHandlerInfoPtr> filtered =
ArcIntentHelperBridge::FilterOutIntentHelper(std::move(orig));
EXPECT_EQ(0U, filtered.size());
}
diff --git a/chromium/components/arc/intent_helper/intent_filter.cc b/chromium/components/arc/intent_helper/intent_filter.cc
index 4144e95c559..f2772ccc3ab 100644
--- a/chromium/components/arc/intent_helper/intent_filter.cc
+++ b/chromium/components/arc/intent_helper/intent_filter.cc
@@ -74,7 +74,8 @@ IntentFilter::AuthorityEntry::AuthorityEntry(
host_ = host_.substr(1);
}
- // TODO: Not i18n-friendly. Figure out how to correctly deal with IDNs.
+ // TODO(kenobi): Not i18n-friendly. Figure out how to correctly deal with
+ // IDNs.
host_ = base::ToLowerASCII(host_);
}
@@ -103,7 +104,8 @@ bool IntentFilter::AuthorityEntry::match(const GURL& url) const {
return base::EndsWith(url.host_piece(), host_,
base::CompareCase::INSENSITIVE_ASCII);
} else {
- // TODO: Not i18n-friendly. Figure out how to correctly deal with IDNs.
+ // TODO(kenobi): Not i18n-friendly. Figure out how to correctly deal with
+ // IDNs.
return host_ == base::ToLowerASCII(url.host_piece());
}
}
diff --git a/chromium/components/arc/intent_helper/link_handler_model_impl.cc b/chromium/components/arc/intent_helper/link_handler_model_impl.cc
index 957790148b5..4c6f7382f6a 100644
--- a/chromium/components/arc/intent_helper/link_handler_model_impl.cc
+++ b/chromium/components/arc/intent_helper/link_handler_model_impl.cc
@@ -5,6 +5,7 @@
#include "components/arc/intent_helper/link_handler_model_impl.h"
#include <string>
+#include <utility>
#include <vector>
#include "base/bind.h"
@@ -55,8 +56,9 @@ LinkHandlerModelImpl::LinkHandlerModelImpl(
LinkHandlerModelImpl::~LinkHandlerModelImpl() {}
bool LinkHandlerModelImpl::Init(const GURL& url) {
- mojom::IntentHelperInstance* intent_helper_instance = GetIntentHelper();
- if (!intent_helper_instance)
+ auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
+ "RequestUrlHandlerList", kMinInstanceVersion);
+ if (!instance)
return false;
// Check if ARC apps can handle the |url|. Since the information is held in
@@ -64,7 +66,7 @@ bool LinkHandlerModelImpl::Init(const GURL& url) {
// callback function, OnUrlHandlerList, is called within a few milliseconds
// even on the slowest Chromebook we support.
const GURL rewritten(RewriteUrlFromQueryIfAvailable(url));
- intent_helper_instance->RequestUrlHandlerList(
+ instance->RequestUrlHandlerList(
rewritten.spec(), base::Bind(&LinkHandlerModelImpl::OnUrlHandlerList,
weak_ptr_factory_.GetWeakPtr()));
return true;
@@ -76,37 +78,18 @@ void LinkHandlerModelImpl::AddObserver(Observer* observer) {
void LinkHandlerModelImpl::OpenLinkWithHandler(const GURL& url,
uint32_t handler_id) {
- mojom::IntentHelperInstance* intent_helper_instance = GetIntentHelper();
- if (!intent_helper_instance)
+ auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
+ "HandleUrl", kMinInstanceVersion);
+ if (!instance)
return;
if (handler_id >= handlers_.size())
return;
const GURL rewritten(RewriteUrlFromQueryIfAvailable(url));
- intent_helper_instance->HandleUrl(rewritten.spec(),
- handlers_[handler_id]->package_name);
-}
-
-mojom::IntentHelperInstance* LinkHandlerModelImpl::GetIntentHelper() {
- ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
- if (!bridge_service) {
- DLOG(WARNING) << "ARC bridge is not ready.";
- return nullptr;
- }
- mojom::IntentHelperInstance* intent_helper_instance =
- bridge_service->intent_helper()->instance();
- if (!intent_helper_instance) {
- DLOG(WARNING) << "ARC intent helper instance is not ready.";
- return nullptr;
- }
- if (bridge_service->intent_helper()->version() < kMinInstanceVersion) {
- DLOG(WARNING) << "ARC intent helper instance is too old.";
- return nullptr;
- }
- return intent_helper_instance;
+ instance->HandleUrl(rewritten.spec(), handlers_[handler_id]->package_name);
}
void LinkHandlerModelImpl::OnUrlHandlerList(
- mojo::Array<mojom::UrlHandlerInfoPtr> handlers) {
+ mojo::Array<mojom::IntentHandlerInfoPtr> handlers) {
handlers_ = ArcIntentHelperBridge::FilterOutIntentHelper(std::move(handlers));
bool icon_info_notified = false;
diff --git a/chromium/components/arc/intent_helper/link_handler_model_impl.h b/chromium/components/arc/intent_helper/link_handler_model_impl.h
index a2f9cc55516..3322025ba5b 100644
--- a/chromium/components/arc/intent_helper/link_handler_model_impl.h
+++ b/chromium/components/arc/intent_helper/link_handler_model_impl.h
@@ -35,7 +35,7 @@ class LinkHandlerModelImpl : public ash::LinkHandlerModel {
private:
mojom::IntentHelperInstance* GetIntentHelper();
- void OnUrlHandlerList(mojo::Array<mojom::UrlHandlerInfoPtr> handlers);
+ void OnUrlHandlerList(mojo::Array<mojom::IntentHandlerInfoPtr> handlers);
void NotifyObserver(
std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> icons);
@@ -48,7 +48,7 @@ class LinkHandlerModelImpl : public ash::LinkHandlerModel {
base::ObserverList<Observer> observer_list_;
// Url handler info passed from ARC.
- mojo::Array<mojom::UrlHandlerInfoPtr> handlers_;
+ mojo::Array<mojom::IntentHandlerInfoPtr> handlers_;
// Activity icon info passed from ARC.
ActivityIconLoader::ActivityToIconsMap icons_;
diff --git a/chromium/components/arc/intent_helper/link_handler_model_impl_unittest.cc b/chromium/components/arc/intent_helper/link_handler_model_impl_unittest.cc
index 19c52ec98c7..314b1ecbfca 100644
--- a/chromium/components/arc/intent_helper/link_handler_model_impl_unittest.cc
+++ b/chromium/components/arc/intent_helper/link_handler_model_impl_unittest.cc
@@ -4,6 +4,8 @@
#include "components/arc/intent_helper/link_handler_model_impl.h"
+#include <string>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
diff --git a/chromium/components/arc/intent_helper/local_activity_resolver.h b/chromium/components/arc/intent_helper/local_activity_resolver.h
index 2033b7744b5..d3833b367e0 100644
--- a/chromium/components/arc/intent_helper/local_activity_resolver.h
+++ b/chromium/components/arc/intent_helper/local_activity_resolver.h
@@ -36,4 +36,4 @@ class LocalActivityResolver : public base::RefCounted<LocalActivityResolver> {
} // namespace arc
-#endif // COMPONENTS_ARC_INTENT_HELPER_LOCAL_ACTIVITY_HELPER_H_
+#endif // COMPONENTS_ARC_INTENT_HELPER_LOCAL_ACTIVITY_RESOLVER_H_
diff --git a/chromium/components/arc/metrics/arc_metrics_service.cc b/chromium/components/arc/metrics/arc_metrics_service.cc
index 9aca98bd084..bb4cf9d8d40 100644
--- a/chromium/components/arc/metrics/arc_metrics_service.cc
+++ b/chromium/components/arc/metrics/arc_metrics_service.cc
@@ -5,6 +5,7 @@
#include "components/arc/metrics/arc_metrics_service.h"
#include <string>
+#include <utility>
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
@@ -27,10 +28,10 @@ ArcMetricsService::ArcMetricsService(ArcBridgeService* bridge_service)
: ArcService(bridge_service),
binding_(this),
process_observer_(this),
+ oom_kills_monitor_handle_(OomKillsMonitor::StartMonitoring()),
weak_ptr_factory_(this) {
arc_bridge_service()->metrics()->AddObserver(this);
arc_bridge_service()->process()->AddObserver(&process_observer_);
- oom_kills_monitor_.Start();
}
ArcMetricsService::~ArcMetricsService() {
@@ -75,12 +76,10 @@ void ArcMetricsService::OnProcessInstanceClosed() {
void ArcMetricsService::RequestProcessList() {
mojom::ProcessInstance* process_instance =
- arc_bridge_service()->process()->instance();
- if (!process_instance) {
- LOG(ERROR) << "No process instance found before RequestProcessList";
+ arc_bridge_service()->process()->GetInstanceForMethod(
+ "RequestProcessList");
+ if (!process_instance)
return;
- }
-
VLOG(2) << "RequestProcessList";
process_instance->RequestProcessList(base::Bind(
&ArcMetricsService::ParseProcessList, weak_ptr_factory_.GetWeakPtr()));
@@ -120,10 +119,10 @@ void ArcMetricsService::OnArcStartTimeRetrieved(
LOG(ERROR) << "Failed to retrieve ARC start timeticks.";
return;
}
- if (!arc_bridge_service()->metrics()->instance()) {
- LOG(ERROR) << "ARC metrics instance went away while retrieving start time.";
+ auto* instance =
+ arc_bridge_service()->metrics()->GetInstanceForMethod("Init");
+ if (!instance)
return;
- }
// The binding of host interface is deferred until the ARC start time is
// retrieved here because it prevents race condition of the ARC start
@@ -131,7 +130,7 @@ void ArcMetricsService::OnArcStartTimeRetrieved(
if (!binding_.is_bound()) {
mojom::MetricsHostPtr host_ptr;
binding_.Bind(mojo::GetProxy(&host_ptr));
- arc_bridge_service()->metrics()->instance()->Init(std::move(host_ptr));
+ instance->Init(std::move(host_ptr));
}
arc_start_time_ = arc_start_time;
VLOG(2) << "ARC start @" << arc_start_time_;
diff --git a/chromium/components/arc/metrics/arc_metrics_service.h b/chromium/components/arc/metrics/arc_metrics_service.h
index 7b7958be491..06fdf7b85c3 100644
--- a/chromium/components/arc/metrics/arc_metrics_service.h
+++ b/chromium/components/arc/metrics/arc_metrics_service.h
@@ -70,7 +70,7 @@ class ArcMetricsService
base::ThreadChecker thread_checker_;
base::RepeatingTimer timer_;
- OomKillsMonitor oom_kills_monitor_;
+ OomKillsMonitor::Handle oom_kills_monitor_handle_;
base::TimeTicks arc_start_time_;
diff --git a/chromium/components/arc/metrics/oom_kills_monitor.cc b/chromium/components/arc/metrics/oom_kills_monitor.cc
index 7ce7cd24909..719b778eaf9 100644
--- a/chromium/components/arc/metrics/oom_kills_monitor.cc
+++ b/chromium/components/arc/metrics/oom_kills_monitor.cc
@@ -11,10 +11,12 @@
#include <vector>
#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/posix/safe_strerror.h"
#include "base/sequenced_task_runner.h"
@@ -33,25 +35,6 @@ using base::StringPiece;
using base::SequencedWorkerPool;
using base::TimeDelta;
-OomKillsMonitor::OomKillsMonitor()
- : worker_pool_(
- new SequencedWorkerPool(1, "oom_kills_monitor")) {}
-
-OomKillsMonitor::~OomKillsMonitor() {
- Stop();
-}
-
-void OomKillsMonitor::Start() {
- auto task_runner = worker_pool_->GetTaskRunnerWithShutdownBehavior(
- SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
- task_runner->PostTask(
- FROM_HERE, base::Bind(&OomKillsMonitor::Run, worker_pool_));
-}
-
-void OomKillsMonitor::Stop() {
- worker_pool_->Shutdown();
-}
-
namespace {
int64_t GetTimestamp(const StringPiece& line) {
@@ -145,7 +128,7 @@ void LogLowMemoryKill(const StringPiece& line) {
UMA_HISTOGRAM_MEMORY_KB("Arc.LowMemoryKiller.FreedSize", freed_size);
- if(GetTimeDelta(line, &last_timestamp, &time_delta)) {
+ if (GetTimeDelta(line, &last_timestamp, &time_delta)) {
UMA_HISTOGRAM_OOM_KILL_TIME_INTERVAL(
"Arc.LowMemoryKiller.TimeDelta", time_delta);
}
@@ -154,9 +137,48 @@ void LogLowMemoryKill(const StringPiece& line) {
} // namespace
+OomKillsMonitor::Handle::Handle(OomKillsMonitor* outer) : outer_(outer) {
+ DCHECK(outer_);
+}
+
+OomKillsMonitor::Handle::~Handle() {
+ outer_->is_shutting_down_.Set();
+}
+
+OomKillsMonitor::OomKillsMonitor() {
+ base::SimpleThread::Options non_joinable_options;
+ non_joinable_options.joinable = false;
+ non_joinable_worker_thread_ = base::MakeUnique<base::DelegateSimpleThread>(
+ this, "oom_kills_monitor", non_joinable_options);
+ non_joinable_worker_thread_->Start();
+}
+
+OomKillsMonitor::~OomKillsMonitor() {
+ // The instance has to be leaked on shutdown as it is referred to by a
+ // non-joinable thread but ~OomKillsMonitor() can't be explicitly deleted as
+ // it overrides ~SimpleThread(), it should nevertheless never be invoked.
+ NOTREACHED();
+}
+
// static
-void OomKillsMonitor::Run(
- scoped_refptr<base::SequencedWorkerPool> worker_pool) {
+OomKillsMonitor::Handle OomKillsMonitor::StartMonitoring() {
+#if DCHECK_IS_ON()
+ static volatile bool monitoring_active = false;
+ DCHECK(!monitoring_active);
+ monitoring_active = true;
+#endif
+
+ // Instantiate the OomKillsMonitor and its underlying thread. The
+ // OomKillsMonitor itself has to be leaked on shutdown per having a
+ // non-joinable thread associated to its state. The OomKillsMonitor::Handle
+ // will notify the OomKillsMonitor when it is destroyed so that the underlying
+ // thread can at a minimum not do extra work during shutdown.
+ OomKillsMonitor* instance = new OomKillsMonitor;
+ ANNOTATE_LEAKING_OBJECT_PTR(instance);
+ return Handle(instance);
+}
+
+void OomKillsMonitor::Run() {
base::ScopedFILE kmsg_handle(
base::OpenFile(base::FilePath("/dev/kmsg"), "r"));
if (!kmsg_handle) {
@@ -171,7 +193,7 @@ void OomKillsMonitor::Run(
char buf[kMaxBufSize];
while (fgets(buf, kMaxBufSize, kmsg_handle.get())) {
- if (worker_pool->IsShutdownInProgress()) {
+ if (is_shutting_down_.IsSet()) {
DVLOG(1) << "Chrome is shutting down, exit now.";
break;
}
diff --git a/chromium/components/arc/metrics/oom_kills_monitor.h b/chromium/components/arc/metrics/oom_kills_monitor.h
index c6cf7995ae8..f4e188445f0 100644
--- a/chromium/components/arc/metrics/oom_kills_monitor.h
+++ b/chromium/components/arc/metrics/oom_kills_monitor.h
@@ -5,33 +5,58 @@
#ifndef COMPONENTS_ARC_METRICS_OOM_KILLS_MONITOR_H_
#define COMPONENTS_ARC_METRICS_OOM_KILLS_MONITOR_H_
+#include <memory>
+
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/synchronization/atomic_flag.h"
+#include "base/threading/simple_thread.h"
namespace arc {
// Traces kernel OOM kill events and lowmemorykiller (if enabled) events.
//
// OomKillsMonitor listens to kernel messages for both OOM kills and
-// lowmemorykiller kills, then reports to UMA.
+// lowmemorykiller kills, then reports to UMA. It uses a non-joinable thread
+// in order to avoid blocking shutdown.
//
// Note: There should be only one OomKillsMonitor instance globally at any given
// time, otherwise UMA would receive duplicate events.
-class OomKillsMonitor {
+class OomKillsMonitor : public base::DelegateSimpleThread::Delegate {
public:
- OomKillsMonitor();
- ~OomKillsMonitor();
+ // A handle representing the OomKillsMonitor's lifetime (the monitor itself
+ // can't be destroyed per being a non-joinable Thread).
+ class Handle {
+ public:
+ // Constructs a handle that will flag |outer| as shutting down on
+ // destruction.
+ explicit Handle(OomKillsMonitor* outer);
+
+ ~Handle();
+
+ private:
+ OomKillsMonitor* const outer_;
+ };
- void Start();
- void Stop();
+ // Instantiates the OomKillsMonitor instance and starts it. This must only
+ // be invoked once per process.
+ static Handle StartMonitoring();
private:
- // Keeps a reference to worker_pool_ in case |this| is deleted in
- // shutdown process while this thread returns from a blocking read.
- static void Run(scoped_refptr<base::SequencedWorkerPool> worker_pool);
+ OomKillsMonitor();
+ ~OomKillsMonitor() override;
+
+ // Overridden from base::DelegateSimpleThread::Delegate:
+ void Run() override;
+
+ // A flag set when OomKillsMonitor is shutdown so that its thread can poll
+ // it and attempt to wind down from that point (to avoid unecessary work, not
+ // because it blocks shutdown).
+ base::AtomicFlag is_shutting_down_;
- scoped_refptr<base::SequencedWorkerPool> worker_pool_;
+ // The underlying worker thread which is non-joinable to avoid blocking
+ // shutdown.
+ std::unique_ptr<base::DelegateSimpleThread> non_joinable_worker_thread_;
DISALLOW_COPY_AND_ASSIGN(OomKillsMonitor);
};
diff --git a/chromium/components/arc/net/arc_net_host_impl.cc b/chromium/components/arc/net/arc_net_host_impl.cc
index bf20c5c8d4e..a0f3c6cee04 100644
--- a/chromium/components/arc/net/arc_net_host_impl.cc
+++ b/chromium/components/arc/net/arc_net_host_impl.cc
@@ -5,6 +5,7 @@
#include "components/arc/net/arc_net_host_impl.h"
#include <string>
+#include <utility>
#include <vector>
#include "base/bind.h"
@@ -26,7 +27,10 @@
namespace {
-const int kGetNetworksListLimit = 100;
+constexpr int kGetNetworksListLimit = 100;
+constexpr uint32_t kScanCompletedMinInstanceVersion = 1;
+constexpr uint32_t kDefaultNetworkChangedMinInstanceVersion = 2;
+constexpr uint32_t kWifiEnabledStateChanged = 3;
chromeos::NetworkStateHandler* GetStateHandler() {
return chromeos::NetworkHandler::Get()->network_state_handler();
@@ -305,7 +309,9 @@ void ArcNetHostImpl::OnInstanceReady() {
mojom::NetHostPtr host;
binding_.Bind(GetProxy(&host));
- arc_bridge_service()->net()->instance()->Init(std::move(host));
+ auto* instance = arc_bridge_service()->net()->GetInstanceForMethod("Init");
+ DCHECK(instance);
+ instance->Init(std::move(host));
}
void ArcNetHostImpl::GetNetworksDeprecated(
@@ -449,7 +455,8 @@ void ArcNetHostImpl::CreateNetwork(mojom::WifiConfigurationPtr cfg,
properties->SetStringWithoutPathExpansion(onc::network_config::kType,
onc::network_config::kWiFi);
- wifi_dict->SetStringWithoutPathExpansion(onc::wifi::kHexSSID, cfg->hexssid);
+ wifi_dict->SetStringWithoutPathExpansion(onc::wifi::kHexSSID,
+ cfg->hexssid.get());
wifi_dict->SetBooleanWithoutPathExpansion(onc::wifi::kAutoConnect,
details->autoconnect);
if (cfg->security.get().empty()) {
@@ -457,10 +464,10 @@ void ArcNetHostImpl::CreateNetwork(mojom::WifiConfigurationPtr cfg,
onc::wifi::kSecurityNone);
} else {
wifi_dict->SetStringWithoutPathExpansion(onc::wifi::kSecurity,
- cfg->security);
+ cfg->security.get());
if (!details->passphrase.is_null()) {
wifi_dict->SetStringWithoutPathExpansion(onc::wifi::kPassphrase,
- details->passphrase);
+ details->passphrase.get());
}
}
properties->SetWithoutPathExpansion(onc::network_config::kWiFi,
@@ -570,16 +577,12 @@ void ArcNetHostImpl::StartScan() {
}
void ArcNetHostImpl::ScanCompleted(const chromeos::DeviceState* /*unused*/) {
- if (!arc_bridge_service()->net()->instance()) {
- VLOG(2) << "NetInstance not ready yet";
+ auto* net_instance = arc_bridge_service()->net()->GetInstanceForMethod(
+ "ScanCompleted", kScanCompletedMinInstanceVersion);
+ if (!net_instance)
return;
- }
- if (arc_bridge_service()->net()->version() < 1) {
- VLOG(1) << "NetInstance does not support ScanCompleted.";
- return;
- }
- arc_bridge_service()->net()->instance()->ScanCompleted();
+ net_instance->ScanCompleted();
}
void ArcNetHostImpl::GetDefaultNetwork(
@@ -603,26 +606,23 @@ void ArcNetHostImpl::GetDefaultNetwork(
void ArcNetHostImpl::DefaultNetworkSuccessCallback(
const std::string& service_path,
const base::DictionaryValue& dictionary) {
- if (!arc_bridge_service()->net()->instance()) {
- VLOG(2) << "NetInstance is null.";
+ auto* net_instance = arc_bridge_service()->net()->GetInstanceForMethod(
+ "DefaultNetworkChanged", kDefaultNetworkChangedMinInstanceVersion);
+ if (!net_instance)
return;
- }
- arc_bridge_service()->net()->instance()->DefaultNetworkChanged(
- TranslateONCConfiguration(&dictionary),
- TranslateONCConfiguration(&dictionary));
+
+ net_instance->DefaultNetworkChanged(TranslateONCConfiguration(&dictionary),
+ TranslateONCConfiguration(&dictionary));
}
void ArcNetHostImpl::DefaultNetworkChanged(
const chromeos::NetworkState* network) {
- if (arc_bridge_service()->net()->version() < 2) {
- VLOG(1) << "ArcBridgeService does not support DefaultNetworkChanged.";
- return;
- }
-
if (!network) {
VLOG(1) << "No default network";
- arc_bridge_service()->net()->instance()->DefaultNetworkChanged(nullptr,
- nullptr);
+ auto* net_instance = arc_bridge_service()->net()->GetInstanceForMethod(
+ "DefaultNetworkChanged", kDefaultNetworkChangedMinInstanceVersion);
+ if (net_instance)
+ net_instance->DefaultNetworkChanged(nullptr, nullptr);
return;
}
@@ -636,14 +636,14 @@ void ArcNetHostImpl::DefaultNetworkChanged(
}
void ArcNetHostImpl::DeviceListChanged() {
- if (arc_bridge_service()->net()->version() < 3) {
- VLOG(1) << "ArcBridgeService does not support DeviceListChanged.";
+ auto* net_instance = arc_bridge_service()->net()->GetInstanceForMethod(
+ "WifiEnabledStateChanged", kWifiEnabledStateChanged);
+ if (!net_instance)
return;
- }
bool is_enabled = GetStateHandler()->IsTechnologyEnabled(
chromeos::NetworkTypePattern::WiFi());
- arc_bridge_service()->net()->instance()->WifiEnabledStateChanged(is_enabled);
+ net_instance->WifiEnabledStateChanged(is_enabled);
}
void ArcNetHostImpl::OnShuttingDown() {
diff --git a/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc b/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc
index 04362b7cbf9..5d05583bae6 100644
--- a/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc
+++ b/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc
@@ -32,7 +32,8 @@ ArcObbMounterBridge::~ArcObbMounterBridge() {
void ArcObbMounterBridge::OnInstanceReady() {
mojom::ObbMounterInstance* obb_mounter_instance =
- arc_bridge_service()->obb_mounter()->instance();
+ arc_bridge_service()->obb_mounter()->GetInstanceForMethod("Init");
+ DCHECK(obb_mounter_instance);
obb_mounter_instance->Init(binding_.CreateInterfacePtrAndBind());
}
diff --git a/chromium/components/arc/power/arc_power_bridge.cc b/chromium/components/arc/power/arc_power_bridge.cc
index fb8b1fdc7b0..abec9d75b79 100644
--- a/chromium/components/arc/power/arc_power_bridge.cc
+++ b/chromium/components/arc/power/arc_power_bridge.cc
@@ -14,6 +14,12 @@
namespace arc {
+namespace {
+
+constexpr uint32_t kMinVersionForSetInteractive = 1;
+
+} // namespace
+
ArcPowerBridge::ArcPowerBridge(ArcBridgeService* bridge_service)
: ArcService(bridge_service), binding_(this) {
arc_bridge_service()->power()->AddObserver(this);
@@ -26,12 +32,8 @@ ArcPowerBridge::~ArcPowerBridge() {
void ArcPowerBridge::OnInstanceReady() {
mojom::PowerInstance* power_instance =
- arc_bridge_service()->power()->instance();
- if (!power_instance) {
- LOG(ERROR) << "OnPowerInstanceReady called, but no power instance found";
- return;
- }
-
+ arc_bridge_service()->power()->GetInstanceForMethod("Init");
+ DCHECK(power_instance);
power_instance->Init(binding_.CreateInterfacePtrAndBind());
ash::Shell::GetInstance()->display_configurator()->AddObserver(this);
}
@@ -44,11 +46,10 @@ void ArcPowerBridge::OnInstanceClosed() {
void ArcPowerBridge::OnPowerStateChanged(
chromeos::DisplayPowerState power_state) {
mojom::PowerInstance* power_instance =
- arc_bridge_service()->power()->instance();
- if (!power_instance) {
- LOG(ERROR) << "PowerInstance is not available";
+ arc_bridge_service()->power()->GetInstanceForMethod(
+ "SetInteractive", kMinVersionForSetInteractive);
+ if (!power_instance)
return;
- }
bool enabled = (power_state != chromeos::DISPLAY_POWER_ALL_OFF);
power_instance->SetInteractive(enabled);
diff --git a/chromium/components/arc/set_wallpaper_delegate.h b/chromium/components/arc/set_wallpaper_delegate.h
deleted file mode 100644
index 45edd377faf..00000000000
--- a/chromium/components/arc/set_wallpaper_delegate.h
+++ /dev/null
@@ -1,25 +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 COMPONENTS_ARC_SET_WALLPAPER_DELEGATE_H_
-#define COMPONENTS_ARC_SET_WALLPAPER_DELEGATE_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-namespace arc {
-
-// Delegate to allow setting the wallpaper.
-class SetWallpaperDelegate {
- public:
- virtual ~SetWallpaperDelegate() = default;
-
- // Sets an image represented in JPEG format as the wallpaper.
- virtual void SetWallpaper(const std::vector<uint8_t>& jpeg_data) = 0;
-};
-
-} // namespace arc
-
-#endif // COMPONENTS_ARC_SET_WALLPAPER_DELEGATE_H_
diff --git a/chromium/components/arc/standalone/arc_standalone_bridge_main.cc b/chromium/components/arc/standalone/arc_standalone_bridge_main.cc
deleted file mode 100644
index ecf86f095e5..00000000000
--- a/chromium/components/arc/standalone/arc_standalone_bridge_main.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/at_exit.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "components/arc/standalone/arc_standalone_bridge_runner.h"
-#include "components/arc/standalone/service_helper.h"
-#include "mojo/edk/embedder/embedder.h"
-
-// This is experimental only. Do not use in production.
-// All threads in the standalone runner must be I/O threads.
-int main(int argc, char** argv) {
- base::CommandLine::Init(argc, argv);
- base::AtExitManager at_exit_manager;
- mojo::edk::Init();
-
- // Instantiate runner, which instantiates message loop.
- arc::ArcStandaloneBridgeRunner runner;
- arc::ServiceHelper helper;
- helper.Init(base::Bind(&arc::ArcStandaloneBridgeRunner::Stop,
- base::Unretained(&runner),
- 1));
-
- // Spin the message loop.
- int exit_code = runner.Run();
- return exit_code;
-}
diff --git a/chromium/components/arc/standalone/arc_standalone_bridge_runner.cc b/chromium/components/arc/standalone/arc_standalone_bridge_runner.cc
deleted file mode 100644
index 6acfcb5abb6..00000000000
--- a/chromium/components/arc/standalone/arc_standalone_bridge_runner.cc
+++ /dev/null
@@ -1,34 +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 "components/arc/standalone/arc_standalone_bridge_runner.h"
-
-#include "base/bind.h"
-#include "base/run_loop.h"
-
-namespace arc {
-
-ArcStandaloneBridgeRunner::ArcStandaloneBridgeRunner() : exit_code_(0) {
-}
-
-ArcStandaloneBridgeRunner::~ArcStandaloneBridgeRunner() {
-}
-
-int ArcStandaloneBridgeRunner::Run() {
- DCHECK(thread_checker_.CalledOnValidThread());
- run_loop_.reset(new base::RunLoop());
- run_loop_->Run();
- run_loop_.reset(nullptr);
-
- return exit_code_;
-}
-
-void ArcStandaloneBridgeRunner::Stop(int exit_code) {
- DCHECK(thread_checker_.CalledOnValidThread());
- exit_code_ = exit_code;
- CHECK(run_loop_);
- message_loop_.PostTask(FROM_HERE, run_loop_->QuitClosure());
-}
-
-} // namespace arc
diff --git a/chromium/components/arc/standalone/arc_standalone_bridge_runner.h b/chromium/components/arc/standalone/arc_standalone_bridge_runner.h
deleted file mode 100644
index 9edd5f66bdb..00000000000
--- a/chromium/components/arc/standalone/arc_standalone_bridge_runner.h
+++ /dev/null
@@ -1,42 +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 COMPONENTS_ARC_ARC_STANDALONE_BRIDGE_RUNNER_H_
-#define COMPONENTS_ARC_ARC_STANDALONE_BRIDGE_RUNNER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_checker.h"
-
-namespace arc {
-
-// Runner of the standalone ARC++ bridge, which hosts an IO message loop.
-class ArcStandaloneBridgeRunner {
- public:
- ArcStandaloneBridgeRunner();
- ~ArcStandaloneBridgeRunner();
-
- // Starts the message loop. Needs to be run on the thread where this
- // instance is created.
- int Run();
-
- // Stops the message loop. Needs to be called in a message loop.
- void Stop(int exit_code);
-
- private:
- base::MessageLoopForIO message_loop_;
- std::unique_ptr<base::RunLoop> run_loop_;
- base::ThreadChecker thread_checker_;
- int exit_code_;
-
- DISALLOW_COPY_AND_ASSIGN(ArcStandaloneBridgeRunner);
-};
-
-
-} // namespace arc
-
-#endif // COMPONENTS_ARC_ARC_STANDALONE_BRIDGE_RUNNER_H_
diff --git a/chromium/components/arc/standalone/service_helper.cc b/chromium/components/arc/standalone/service_helper.cc
deleted file mode 100644
index 8bfd8212aad..00000000000
--- a/chromium/components/arc/standalone/service_helper.cc
+++ /dev/null
@@ -1,73 +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 "components/arc/standalone/service_helper.h"
-
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/posix/eintr_wrapper.h"
-
-namespace arc {
-
-// static
-ServiceHelper* ServiceHelper::self_ = nullptr;
-
-ServiceHelper::ServiceHelper() {
-}
-
-ServiceHelper::~ServiceHelper() {
- // Best efforts clean up, ignore the return values.
- sigaction(SIGINT, &old_sigint_, NULL);
- sigaction(SIGTERM, &old_sigterm_, NULL);
-}
-
-void ServiceHelper::Init(const base::Closure& closure) {
- CHECK(!ServiceHelper::self_);
- ServiceHelper::self_ = this;
- closure_ = closure;
-
- // Initialize pipe
- int pipe_fd[2];
- CHECK_EQ(0, pipe(pipe_fd));
- read_fd_.reset(pipe_fd[0]);
- write_fd_.reset(pipe_fd[1]);
- CHECK(base::SetNonBlocking(write_fd_.get()));
- CHECK(base::MessageLoopForIO::current()->WatchFileDescriptor(
- read_fd_.get(),
- true, /* persistent */
- base::MessageLoopForIO::WATCH_READ,
- &watcher_,
- this));
-
- struct sigaction action = {};
- CHECK_EQ(0, sigemptyset(&action.sa_mask));
- action.sa_handler = ServiceHelper::TerminationHandler;
- action.sa_flags = 0;
-
- CHECK_EQ(0, sigaction(SIGINT, &action, &old_sigint_));
- CHECK_EQ(0, sigaction(SIGTERM, &action, &old_sigterm_));
-}
-
-// static
-void ServiceHelper::TerminationHandler(int /* signum */) {
- if (HANDLE_EINTR(write(self_->write_fd_.get(), "1", 1)) < 0) {
- _exit(2); // We still need to exit the program, but in a brute force way.
- }
-}
-
-void ServiceHelper::OnFileCanReadWithoutBlocking(int fd) {
- CHECK_EQ(read_fd_.get(), fd);
-
- char c;
- // We don't really care about the return value, since it indicates closing.
- HANDLE_EINTR(read(read_fd_.get(), &c, 1));
- closure_.Run();
-}
-
-void ServiceHelper::OnFileCanWriteWithoutBlocking(int fd) {
- NOTREACHED();
-}
-
-} // namespace arc
diff --git a/chromium/components/arc/standalone/service_helper.h b/chromium/components/arc/standalone/service_helper.h
deleted file mode 100644
index f09a441f11d..00000000000
--- a/chromium/components/arc/standalone/service_helper.h
+++ /dev/null
@@ -1,46 +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 COMPONENTS_ARC_STANDALONE_SERVICE_HELPER_
-#define COMPONENTS_ARC_STANDALONE_SERVICE_HELPER_
-
-#include <signal.h>
-
-#include "base/files/scoped_file.h"
-#include "base/message_loop/message_loop.h"
-
-namespace arc {
-
-// Helper class to set up service-like processes.
-class ServiceHelper : public base::MessageLoopForIO::Watcher {
- public:
- ServiceHelper();
- ~ServiceHelper() override;
-
- // Must be called after message loop instantiation.
- void Init(const base::Closure& closure);
-
- // MessageLoopForIO::Watcher
- void OnFileCanReadWithoutBlocking(int fd) override;
- void OnFileCanWriteWithoutBlocking(int fd) override;
-
- private:
- static void TerminationHandler(int /* signum */);
-
- // Static variable to guarantee instantiated only once per process.
- static ServiceHelper* self_;
-
- base::Closure closure_;
- base::ScopedFD read_fd_;
- base::ScopedFD write_fd_;
- base::MessageLoopForIO::FileDescriptorWatcher watcher_;
- struct sigaction old_sigint_;
- struct sigaction old_sigterm_;
-
- DISALLOW_COPY_AND_ASSIGN(ServiceHelper);
-};
-
-} // namespace arc
-
-#endif // COMPONENTS_ARC_STANDALONE_SERVICE_HELPER_
diff --git a/chromium/components/arc/standalone/service_helper_unittest.cc b/chromium/components/arc/standalone/service_helper_unittest.cc
deleted file mode 100644
index a1da8fc8db4..00000000000
--- a/chromium/components/arc/standalone/service_helper_unittest.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/arc/standalone/service_helper.h"
-
-#include <signal.h>
-#include <unistd.h>
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/test/launcher/unit_test_launcher.h"
-#include "base/test/test_suite.h"
-#include "base/threading/platform_thread.h"
-#include "base/time/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace arc {
-
-class ServiceHelperTest : public ::testing::Test {
- public:
- ServiceHelperTest() {}
- ~ServiceHelperTest() override {}
-
- void Quit() {
- CHECK(base_loop_);
- CHECK(run_loop_);
- base_loop_->PostTask(FROM_HERE, run_loop_->QuitClosure());
- }
-
- void Init() {
- // Dynamically create the message loop to avoid thread check failure of task
- // runner in Debug mode.
- base_loop_.reset(new base::MessageLoopForIO());
- run_loop_.reset(new base::RunLoop());
-
- // This cannot be put inside SetUp() because we need to run it after fork().
- helper_.reset(new ServiceHelper());
- helper_->Init(base::Bind(&ServiceHelperTest::Quit,
- base::Unretained(this)));
- }
-
- protected:
- std::unique_ptr<base::MessageLoopForIO> base_loop_;
- std::unique_ptr<base::RunLoop> run_loop_;
- std::unique_ptr<ServiceHelper> helper_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ServiceHelperTest);
-};
-
-TEST_F(ServiceHelperTest, CheckExternalTerm) {
- // Fork ourselves and run it.
- pid_t child_pid = fork();
- if (child_pid == 0) { // Child process
- Init();
- run_loop_->Run();
- helper_.reset(); // Make sure ServiceHelper dtor does not crash.
- _Exit(EXIT_SUCCESS);
- } else if (child_pid == -1) { // Failed to fork
- FAIL();
- } else { // Parent process
- // Deliberate race. If ServiceHelper had bugs and stalled, the short
- // timeout would kill forked process and stop the test. In that case
- // there will be a crash from improperly terminated message loop
- // and we shall capture the error.
- base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
- kill(child_pid, SIGTERM);
- int status;
- ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
- ASSERT_TRUE(WIFEXITED(status));
- }
-}
-
-} // namespace arc
-
-int main(int argc, char** argv) {
- base::TestSuite test_suite(argc, argv);
- return base::LaunchUnitTestsSerially(
- argc, argv,
- base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
-}
diff --git a/chromium/components/arc/storage_manager/arc_storage_manager.cc b/chromium/components/arc/storage_manager/arc_storage_manager.cc
index 6bc2cf52e25..f8cae30155e 100644
--- a/chromium/components/arc/storage_manager/arc_storage_manager.cc
+++ b/chromium/components/arc/storage_manager/arc_storage_manager.cc
@@ -40,48 +40,35 @@ ArcStorageManager* ArcStorageManager::Get() {
}
bool ArcStorageManager::OpenPrivateVolumeSettings() {
- auto storage_manager_instance = GetStorageManagerInstance();
- if (!storage_manager_instance) {
+ auto* storage_manager_instance =
+ arc_bridge_service()->storage_manager()->GetInstanceForMethod(
+ "OpenPrivateVolumeSettings", kMinInstanceVersion);
+ if (!storage_manager_instance)
return false;
- }
storage_manager_instance->OpenPrivateVolumeSettings();
return true;
}
bool ArcStorageManager::GetApplicationsSize(
const GetApplicationsSizeCallback& callback) {
- auto storage_manager_instance = GetStorageManagerInstance();
- if (!storage_manager_instance) {
+ auto* storage_manager_instance =
+ arc_bridge_service()->storage_manager()->GetInstanceForMethod(
+ "GetApplicationsSize", kMinInstanceVersion);
+ if (!storage_manager_instance)
return false;
- }
storage_manager_instance->GetApplicationsSize(callback);
return true;
}
bool ArcStorageManager::DeleteApplicationsCache(
const base::Callback<void()>& callback) {
- auto storage_manager_instance = GetStorageManagerInstance();
- if (!storage_manager_instance) {
+ auto* storage_manager_instance =
+ arc_bridge_service()->storage_manager()->GetInstanceForMethod(
+ "DeleteApplicationsCache", kMinInstanceVersion);
+ if (!storage_manager_instance)
return false;
- }
storage_manager_instance->DeleteApplicationsCache(callback);
return true;
}
-mojom::StorageManagerInstance* ArcStorageManager::GetStorageManagerInstance() {
- auto bridge_service = arc_bridge_service();
- auto storage_manager_instance = bridge_service->storage_manager()->instance();
- if (!storage_manager_instance) {
- DLOG(WARNING) << "ARC storage manager instance is not ready.";
- return nullptr;
- }
- auto storage_manager_version = bridge_service->storage_manager()->version();
- if (storage_manager_version < kMinInstanceVersion) {
- DLOG(ERROR) << "ARC storage manager instance (version "
- << storage_manager_version << ") is too old.";
- return nullptr;
- }
- return storage_manager_instance;
-}
-
} // namespace arc
diff --git a/chromium/components/arc/storage_manager/arc_storage_manager.h b/chromium/components/arc/storage_manager/arc_storage_manager.h
index 1ca766e73c9..8ea47ccec85 100644
--- a/chromium/components/arc/storage_manager/arc_storage_manager.h
+++ b/chromium/components/arc/storage_manager/arc_storage_manager.h
@@ -39,8 +39,6 @@ class ArcStorageManager : public ArcService {
bool DeleteApplicationsCache(const base::Callback<void()>& callback);
private:
- mojom::StorageManagerInstance* GetStorageManagerInstance();
-
DISALLOW_COPY_AND_ASSIGN(ArcStorageManager);
};
diff --git a/chromium/components/arc/user_data/arc_user_data_service.cc b/chromium/components/arc/user_data/arc_user_data_service.cc
index b1ffb1c93c0..b9b3082f9da 100644
--- a/chromium/components/arc/user_data/arc_user_data_service.cc
+++ b/chromium/components/arc/user_data/arc_user_data_service.cc
@@ -4,6 +4,10 @@
#include "components/arc/user_data/arc_user_data_service.h"
+#include <utility>
+
+#include "base/command_line.h"
+#include "chromeos/chromeos_switches.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "components/prefs/pref_member.h"
@@ -18,8 +22,14 @@ ArcUserDataService::ArcUserDataService(
const AccountId& account_id)
: ArcService(bridge_service),
arc_enabled_pref_(std::move(arc_enabled_pref)),
- primary_user_account_id_(account_id) {
+ primary_user_account_id_(account_id),
+ weak_ptr_factory_(this) {
arc_bridge_service()->AddObserver(this);
+ pref_change_registrar_.Init(arc_enabled_pref_->prefs());
+ pref_change_registrar_.Add(
+ arc_enabled_pref_->GetPrefName(),
+ base::Bind(&ArcUserDataService::OnOptInPreferenceChanged,
+ weak_ptr_factory_.GetWeakPtr()));
WipeIfRequired();
}
@@ -50,12 +60,15 @@ void ArcUserDataService::RequireUserDataWiped(const ArcDataCallback& callback) {
void ArcUserDataService::WipeIfRequired() {
DCHECK(thread_checker_.CalledOnValidThread());
- if (arc_bridge_service()->state() != ArcBridgeService::State::STOPPED) {
+ if (!arc_bridge_service()->stopped()) {
LOG(ERROR) << "ARC instance not stopped, user data can't be wiped";
return;
}
- if (arc_enabled_pref_->GetValue() && !arc_user_data_wipe_required_)
+ if ((arc_enabled_pref_->GetValue() && !arc_user_data_wipe_required_) ||
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ chromeos::switches::kDisableArcDataWipe)) {
return;
+ }
VLOG(1) << "Wipe ARC user data.";
arc_user_data_wipe_required_ = false;
const cryptohome::Identification cryptohome_id(primary_user_account_id_);
@@ -65,4 +78,9 @@ void ArcUserDataService::WipeIfRequired() {
callback_.Reset();
}
+void ArcUserDataService::OnOptInPreferenceChanged() {
+ if (!arc_enabled_pref_->GetValue())
+ arc_user_data_wipe_required_ = true;
+}
+
} // namespace arc
diff --git a/chromium/components/arc/user_data/arc_user_data_service.h b/chromium/components/arc/user_data/arc_user_data_service.h
index 9e15a81e1ea..1ac89a2be75 100644
--- a/chromium/components/arc/user_data/arc_user_data_service.h
+++ b/chromium/components/arc/user_data/arc_user_data_service.h
@@ -2,14 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_ARC_USER_DATA_ARC_USER_DATA_SERVICE
-#define COMPONENTS_ARC_USER_DATA_ARC_USER_DATA_SERVICE
+#ifndef COMPONENTS_ARC_USER_DATA_ARC_USER_DATA_SERVICE_H_
+#define COMPONENTS_ARC_USER_DATA_ARC_USER_DATA_SERVICE_H_
+
+#include <memory>
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "chromeos/dbus/session_manager_client.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service.h"
+#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_member.h"
#include "components/signin/core/account_id/account_id.h"
@@ -46,13 +50,21 @@ class ArcUserDataService : public ArcService,
// required and triggers removal of user data.
void WipeIfRequired();
+ // Callback when the kArcEnabled preference changes. It watches for instances
+ // where the preference is disabled and remembers this so that it can wipe
+ // user data once the bridge has stopped.
+ void OnOptInPreferenceChanged();
+
const std::unique_ptr<BooleanPrefMember> arc_enabled_pref_;
// Account ID for the account for which we currently have opt-in information.
AccountId primary_user_account_id_;
- // Set to true when user data wipe is required and set to false again after
- // user data has been wiped.
+ // Registrar used to monitor ARC enabled state.
+ PrefChangeRegistrar pref_change_registrar_;
+
+ // Set to true when kArcEnabled goes from true to false or user data wipe is
+ // required and set to false again after user data has been wiped.
// This ensures data is wiped even if the user tries to enable ARC before the
// bridge has shut down.
bool arc_user_data_wipe_required_ = false;
@@ -62,9 +74,11 @@ class ArcUserDataService : public ArcService,
// Set when ARC user data wipe is required by RequireUserDataWiped.
ArcDataCallback callback_;
+ base::WeakPtrFactory<ArcUserDataService> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ArcUserDataService);
};
} // namespace arc
-#endif // COMPONENTS_ARC_USER_DATA_ARC_USER_DATA_SERVICE
+#endif // COMPONENTS_ARC_USER_DATA_ARC_USER_DATA_SERVICE_H_
diff --git a/chromium/components/arc/window_manager/arc_window_manager_bridge.cc b/chromium/components/arc/window_manager/arc_window_manager_bridge.cc
index 323def2e058..9ddda4b23a4 100644
--- a/chromium/components/arc/window_manager/arc_window_manager_bridge.cc
+++ b/chromium/components/arc/window_manager/arc_window_manager_bridge.cc
@@ -4,72 +4,18 @@
#include "components/arc/window_manager/arc_window_manager_bridge.h"
-#include "ash/common/wm_shell.h"
-#include "ash/shell.h"
-#include "ash/wm/maximize_mode/maximize_mode_controller.h"
#include "base/logging.h"
-#include "components/arc/arc_bridge_service.h"
namespace arc {
ArcWindowManagerBridge::ArcWindowManagerBridge(ArcBridgeService* bridge_service)
- : ArcService(bridge_service),
- current_mode_(mojom::WindowManagerMode::MODE_NORMAL) {
- arc_bridge_service()->window_manager()->AddObserver(this);
- if (!ash::WmShell::HasInstance()) {
- // The shell gets always loaded before ARC. If there is no shell it can only
- // mean that a unit test is running.
- return;
- }
- // Monitor any mode changes from now on.
- ash::WmShell::Get()->AddShellObserver(this);
+ : ArcService(bridge_service) {
}
void ArcWindowManagerBridge::OnInstanceReady() {
- if (!ash::Shell::HasInstance()) {
- // The shell gets always loaded before ARC. If there is no shell it can only
- // mean that a unit test is running.
- return;
- }
- ash::MaximizeModeController* controller =
- ash::Shell::GetInstance()->maximize_mode_controller();
- if (!controller)
- return;
-
- // Set the initial mode configuration.
- SendWindowManagerModeChange(controller->IsMaximizeModeWindowManagerEnabled());
}
ArcWindowManagerBridge::~ArcWindowManagerBridge() {
- if (ash::WmShell::HasInstance())
- ash::WmShell::Get()->RemoveShellObserver(this);
- arc_bridge_service()->window_manager()->RemoveObserver(this);
-}
-
-void ArcWindowManagerBridge::OnMaximizeModeStarted() {
- SendWindowManagerModeChange(true);
-}
-
-void ArcWindowManagerBridge::OnMaximizeModeEnded() {
- SendWindowManagerModeChange(false);
-}
-
-void ArcWindowManagerBridge::SendWindowManagerModeChange(
- bool touch_view_enabled) {
- // We let the ArcBridgeService check that we are calling on the right thread.
- DCHECK(ArcBridgeService::Get() != nullptr);
- mojom::WindowManagerMode wm_mode =
- touch_view_enabled ? mojom::WindowManagerMode::MODE_TOUCH_VIEW
- : mojom::WindowManagerMode::MODE_NORMAL;
-
- mojom::WindowManagerInstance* wm_instance =
- arc_bridge_service()->window_manager()->instance();
- if (!wm_instance || wm_mode == current_mode_) {
- return;
- }
- VLOG(1) << "Sending window manager mode change to " << wm_mode;
- wm_instance->OnWindowManagerModeChange(wm_mode);
- current_mode_ = wm_mode;
}
} // namespace arc
diff --git a/chromium/components/arc/window_manager/arc_window_manager_bridge.h b/chromium/components/arc/window_manager/arc_window_manager_bridge.h
index 27a346d7c93..6c3a4004f07 100644
--- a/chromium/components/arc/window_manager/arc_window_manager_bridge.h
+++ b/chromium/components/arc/window_manager/arc_window_manager_bridge.h
@@ -7,7 +7,6 @@
#include <string>
-#include "ash/common/shell_observer.h"
#include "base/macros.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_service.h"
@@ -17,8 +16,7 @@ namespace arc {
class ArcWindowManagerBridge
: public ArcService,
- public InstanceHolder<mojom::WindowManagerInstance>::Observer,
- public ash::ShellObserver {
+ public InstanceHolder<mojom::WindowManagerInstance>::Observer {
public:
explicit ArcWindowManagerBridge(ArcBridgeService* bridge_service);
~ArcWindowManagerBridge() override;
@@ -26,15 +24,7 @@ class ArcWindowManagerBridge
// InstanceHolder<mojom::WindowManagerInstance>::Observer
void OnInstanceReady() override;
- // Ash::Shell::ShellObserver
- void OnMaximizeModeStarted() override;
- void OnMaximizeModeEnded() override;
-
private:
- void SendWindowManagerModeChange(bool touch_view_enabled);
-
- // Remembers the currently set mode on the Android side.
- mojom::WindowManagerMode current_mode_;
DISALLOW_COPY_AND_ASSIGN(ArcWindowManagerBridge);
};
diff --git a/chromium/components/audio_modem.gypi b/chromium/components/audio_modem.gypi
deleted file mode 100644
index 58d892883e2..00000000000
--- a/chromium/components/audio_modem.gypi
+++ /dev/null
@@ -1,54 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'audio_modem',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../media/media.gyp:media',
- '../media/media.gyp:shared_memory_support',
- '../third_party/webrtc/common_audio/common_audio.gyp:common_audio',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'audio_modem/audio_player.h',
- 'audio_modem/audio_player_impl.cc',
- 'audio_modem/audio_player_impl.h',
- 'audio_modem/audio_recorder.h',
- 'audio_modem/audio_recorder_impl.cc',
- 'audio_modem/audio_recorder_impl.h',
- 'audio_modem/constants.cc',
- 'audio_modem/modem_impl.cc',
- 'audio_modem/modem_impl.h',
- 'audio_modem/public/modem.h',
- 'audio_modem/public/audio_modem_types.h',
- 'audio_modem/public/whispernet_client.h',
- 'audio_modem/audio_modem_switches.cc',
- 'audio_modem/audio_modem_switches.h',
- ],
- },
- {
- 'target_name': 'audio_modem_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'audio_modem/test/random_samples.cc',
- 'audio_modem/test/random_samples.h',
- 'audio_modem/test/stub_modem.cc',
- 'audio_modem/test/stub_modem.h',
- 'audio_modem/test/stub_whispernet_client.cc',
- 'audio_modem/test/stub_whispernet_client.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/audio_modem/BUILD.gn b/chromium/components/audio_modem/BUILD.gn
deleted file mode 100644
index 83cd882d109..00000000000
--- a/chromium/components/audio_modem/BUILD.gn
+++ /dev/null
@@ -1,72 +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.
-
-source_set("audio_modem") {
- sources = [
- "audio_modem_switches.cc",
- "audio_modem_switches.h",
- "audio_player.h",
- "audio_player_impl.cc",
- "audio_player_impl.h",
- "audio_recorder.h",
- "audio_recorder_impl.cc",
- "audio_recorder_impl.h",
- "constants.cc",
- "modem_impl.cc",
- "modem_impl.h",
- "public/audio_modem_types.h",
- "public/modem.h",
- "public/whispernet_client.h",
- ]
-
- deps = [
- "//base",
- "//content/public/browser",
- "//media",
- "//media:shared_memory_support",
- "//third_party/webrtc/common_audio",
- ]
-}
-
-source_set("test_support") {
- testonly = true
- sources = [
- "test/random_samples.cc",
- "test/random_samples.h",
- "test/stub_modem.cc",
- "test/stub_modem.h",
- "test/stub_whispernet_client.cc",
- "test/stub_whispernet_client.h",
- ]
-
- public_deps = [
- ":audio_modem",
- ]
- deps = [
- "//base",
- "//media",
- "//media:shared_memory_support",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "audio_player_unittest.cc",
- "audio_recorder_unittest.cc",
- "modem_unittest.cc",
- ]
-
- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
- deps = [
- ":test_support",
- "//base",
- "//base/test:test_support",
- "//content/test:test_support",
- "//media",
- "//media:shared_memory_support",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/audio_modem/DEPS b/chromium/components/audio_modem/DEPS
deleted file mode 100644
index 3853989640a..00000000000
--- a/chromium/components/audio_modem/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
- "+content/public",
- "+media",
- "+third_party/webrtc/common_audio",
-]
diff --git a/chromium/components/audio_modem/OWNERS b/chromium/components/audio_modem/OWNERS
deleted file mode 100644
index f9882eb758c..00000000000
--- a/chromium/components/audio_modem/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-ckehoe@chromium.org
-rkc@chromium.org
-xiyuan@chromium.org
diff --git a/chromium/components/audio_modem/audio_modem_switches.cc b/chromium/components/audio_modem/audio_modem_switches.cc
deleted file mode 100644
index 9f559db6561..00000000000
--- a/chromium/components/audio_modem/audio_modem_switches.cc
+++ /dev/null
@@ -1,22 +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 "components/audio_modem/audio_modem_switches.h"
-
-namespace switches {
-
-// Directory to dump encoded tokens to, for debugging.
-// If empty (the default), tokens are not dumped.
-// If invalid (not a writable directory), Chrome will crash!
-const char kAudioModemDumpTokensToDir[] = "audio-modem-dump-tokens-to-dir";
-
-// Allow broadcast of audible audio tokens. Defaults to true.
-const char kAudioModemEnableAudibleBroadcast[] =
- "audio-modem-enable-audible-broadcast";
-
-// Allow broadcast of inaudible audio tokens. Defaults to true.
-const char kAudioModemEnableInaudibleBroadcast[] =
- "audio-modem-enable-inaudible-broadcast";
-
-} // namespace switches
diff --git a/chromium/components/audio_modem/audio_modem_switches.h b/chromium/components/audio_modem/audio_modem_switches.h
deleted file mode 100644
index 6ae44298f0e..00000000000
--- a/chromium/components/audio_modem/audio_modem_switches.h
+++ /dev/null
@@ -1,18 +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 COMPONENTS_AUDIO_MODEM_AUDIO_MODEM_SWITCHES_H_
-#define COMPONENTS_AUDIO_MODEM_AUDIO_MODEM_SWITCHES_H_
-
-namespace switches {
-
-// All switches in alphabetical order. The switches should be documented
-// alongside the definition of their values in the .cc file.
-extern const char kAudioModemDumpTokensToDir[];
-extern const char kAudioModemEnableAudibleBroadcast[];
-extern const char kAudioModemEnableInaudibleBroadcast[];
-
-} // namespace switches
-
-#endif // COMPONENTS_AUDIO_MODEM_AUDIO_MODEM_SWITCHES_H_
diff --git a/chromium/components/audio_modem/audio_player.h b/chromium/components/audio_modem/audio_player.h
deleted file mode 100644
index 53f838d7717..00000000000
--- a/chromium/components/audio_modem/audio_player.h
+++ /dev/null
@@ -1,43 +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 COMPONENTS_AUDIO_MODEM_AUDIO_PLAYER_H_
-#define COMPONENTS_AUDIO_MODEM_AUDIO_PLAYER_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-
-namespace media {
-class AudioBusRefCounted;
-}
-
-namespace audio_modem {
-
-// The AudioPlayerImpl class will play a set of samples till it is told to stop.
-class AudioPlayer {
- public:
- // Initializes the object. Do not use this object before calling this method.
- virtual void Initialize() = 0;
-
- // Play the given samples. These samples will keep on being played in a loop
- // till we explicitly tell the player to stop playing. If we are already
- // playing, this call will be ignored.
- virtual void Play(
- const scoped_refptr<media::AudioBusRefCounted>& samples) = 0;
-
- // Stop playing. If we're already stopped, this call will be ignored.
- virtual void Stop() = 0;
-
- // Cleans up and deletes this object. Do not use object after this call.
- virtual void Finalize() = 0;
-
- protected:
- virtual ~AudioPlayer() {}
-};
-
-} // namespace audio_modem
-
-#endif // COMPONENTS_AUDIO_MODEM_AUDIO_PLAYER_H_
diff --git a/chromium/components/audio_modem/audio_player_impl.cc b/chromium/components/audio_modem/audio_player_impl.cc
deleted file mode 100644
index c968adf40bf..00000000000
--- a/chromium/components/audio_modem/audio_player_impl.cc
+++ /dev/null
@@ -1,163 +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 "components/audio_modem/audio_player_impl.h"
-
-#include <algorithm>
-#include <string>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "components/audio_modem/public/audio_modem_types.h"
-#include "media/audio/audio_manager.h"
-#include "media/base/audio_bus.h"
-#include "media/base/audio_parameters.h"
-
-namespace {
-
-const int kDefaultFrameCount = 1024;
-const double kOutputVolumePercent = 1.0f;
-
-} // namespace
-
-namespace audio_modem {
-
-// Public methods.
-
-AudioPlayerImpl::AudioPlayerImpl()
- : is_playing_(false), stream_(nullptr), frame_index_(0) {
-}
-
-AudioPlayerImpl::~AudioPlayerImpl() {
-}
-
-void AudioPlayerImpl::Initialize() {
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&AudioPlayerImpl::InitializeOnAudioThread,
- base::Unretained(this)));
-}
-
-void AudioPlayerImpl::Play(
- const scoped_refptr<media::AudioBusRefCounted>& samples) {
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&AudioPlayerImpl::PlayOnAudioThread,
- base::Unretained(this),
- samples));
-}
-
-void AudioPlayerImpl::Stop() {
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&AudioPlayerImpl::StopOnAudioThread, base::Unretained(this)));
-}
-
-void AudioPlayerImpl::Finalize() {
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&AudioPlayerImpl::FinalizeOnAudioThread,
- base::Unretained(this)));
-}
-
-// Private methods.
-
-void AudioPlayerImpl::InitializeOnAudioThread() {
- DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
- stream_ = output_stream_for_testing_
- ? output_stream_for_testing_.get()
- : media::AudioManager::Get()->MakeAudioOutputStreamProxy(
- media::AudioParameters(
- media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
- media::CHANNEL_LAYOUT_MONO,
- kDefaultSampleRate,
- kDefaultBitsPerSample,
- kDefaultFrameCount),
- std::string());
-
- if (!stream_ || !stream_->Open()) {
- LOG(ERROR) << "Failed to open an output stream.";
- if (stream_) {
- stream_->Close();
- stream_ = nullptr;
- }
- return;
- }
- stream_->SetVolume(kOutputVolumePercent);
-}
-
-void AudioPlayerImpl::PlayOnAudioThread(
- const scoped_refptr<media::AudioBusRefCounted>& samples) {
- DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
- if (!stream_ || is_playing_)
- return;
-
- {
- base::AutoLock al(state_lock_);
- samples_ = samples;
- frame_index_ = 0;
- }
-
- VLOG(3) << "Starting playback.";
- is_playing_ = true;
- stream_->Start(this);
-}
-
-void AudioPlayerImpl::StopOnAudioThread() {
- DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
- if (!stream_ || !is_playing_)
- return;
-
- VLOG(3) << "Stopping playback.";
- stream_->Stop();
- is_playing_ = false;
-}
-
-void AudioPlayerImpl::StopAndCloseOnAudioThread() {
- DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
- if (!stream_)
- return;
-
- StopOnAudioThread();
- stream_->Close();
- stream_ = nullptr;
-}
-
-void AudioPlayerImpl::FinalizeOnAudioThread() {
- DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
- StopAndCloseOnAudioThread();
- delete this;
-}
-
-int AudioPlayerImpl::OnMoreData(media::AudioBus* dest,
- uint32_t /* total_bytes_delay */,
- uint32_t /* frames_skipped */) {
- base::AutoLock al(state_lock_);
- // Continuously play our samples till explicitly told to stop.
- const int leftover_frames = samples_->frames() - frame_index_;
- const int frames_to_copy = std::min(dest->frames(), leftover_frames);
-
- samples_->CopyPartialFramesTo(frame_index_, frames_to_copy, 0, dest);
- frame_index_ += frames_to_copy;
-
- // If we didn't fill the destination audio bus, wrap around and fill the rest.
- if (leftover_frames <= dest->frames()) {
- samples_->CopyPartialFramesTo(
- 0, dest->frames() - frames_to_copy, frames_to_copy, dest);
- frame_index_ = dest->frames() - frames_to_copy;
- }
-
- return dest->frames();
-}
-
-void AudioPlayerImpl::OnError(media::AudioOutputStream* /* stream */) {
- LOG(ERROR) << "Error during system sound reproduction.";
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&AudioPlayerImpl::StopAndCloseOnAudioThread,
- base::Unretained(this)));
-}
-
-} // namespace audio_modem
diff --git a/chromium/components/audio_modem/audio_player_impl.h b/chromium/components/audio_modem/audio_player_impl.h
deleted file mode 100644
index 3507c699d0a..00000000000
--- a/chromium/components/audio_modem/audio_player_impl.h
+++ /dev/null
@@ -1,89 +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 COMPONENTS_AUDIO_MODEM_AUDIO_PLAYER_IMPL_H_
-#define COMPONENTS_AUDIO_MODEM_AUDIO_PLAYER_IMPL_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "components/audio_modem/audio_player.h"
-#include "media/audio/audio_io.h"
-
-namespace media {
-class AudioBus;
-class AudioBusRefCounted;
-}
-
-namespace audio_modem {
-
-// The AudioPlayerImpl class will play a set of samples till it is told to stop.
-class AudioPlayerImpl final
- : public AudioPlayer,
- public media::AudioOutputStream::AudioSourceCallback {
- public:
- AudioPlayerImpl();
-
- // AudioPlayer overrides:
- void Initialize() override;
- void Play(const scoped_refptr<media::AudioBusRefCounted>& samples) override;
- void Stop() override;
- void Finalize() override;
-
- // Takes ownership of the stream.
- void set_output_stream_for_testing(
- media::AudioOutputStream* output_stream_for_testing) {
- output_stream_for_testing_.reset(output_stream_for_testing);
- }
-
- private:
- friend class AudioPlayerTest;
- FRIEND_TEST_ALL_PREFIXES(AudioPlayerTest, BasicPlayAndStop);
- FRIEND_TEST_ALL_PREFIXES(AudioPlayerTest, OutOfOrderPlayAndStopMultiple);
-
- ~AudioPlayerImpl() override;
-
- // Methods to do our various operations; all of these need to be run on the
- // audio thread.
- void InitializeOnAudioThread();
- void PlayOnAudioThread(
- const scoped_refptr<media::AudioBusRefCounted>& samples);
- void StopOnAudioThread();
- void StopAndCloseOnAudioThread();
- void FinalizeOnAudioThread();
-
- // AudioOutputStream::AudioSourceCallback overrides:
- // Following methods could be called from *ANY* thread.
- int OnMoreData(media::AudioBus* dest,
- uint32_t total_bytes_delay,
- uint32_t frames_skipped) override;
- void OnError(media::AudioOutputStream* stream) override;
-
- bool is_playing_;
-
- // Self-deleting object.
- media::AudioOutputStream* stream_;
-
- std::unique_ptr<media::AudioOutputStream> output_stream_for_testing_;
-
- // All fields below here are protected by this lock.
- base::Lock state_lock_;
-
- scoped_refptr<media::AudioBusRefCounted> samples_;
-
- // Index to the frame in the samples that we need to play next.
- int frame_index_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioPlayerImpl);
-};
-
-} // namespace audio_modem
-
-#endif // COMPONENTS_AUDIO_MODEM_AUDIO_PLAYER_IMPL_H_
diff --git a/chromium/components/audio_modem/audio_player_unittest.cc b/chromium/components/audio_modem/audio_player_unittest.cc
deleted file mode 100644
index ed2c71bc4d0..00000000000
--- a/chromium/components/audio_modem/audio_player_unittest.cc
+++ /dev/null
@@ -1,224 +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 "components/audio_modem/audio_player.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/run_loop.h"
-#include "base/test/test_message_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/audio_modem/audio_player_impl.h"
-#include "components/audio_modem/public/audio_modem_types.h"
-#include "components/audio_modem/test/random_samples.h"
-#include "media/audio/audio_manager_base.h"
-#include "media/base/audio_bus.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-class TestAudioOutputStream : public media::AudioOutputStream {
- public:
- using GatherSamplesCallback =
- base::Callback<void(std::unique_ptr<media::AudioBus>, int frames)>;
- TestAudioOutputStream(int default_frame_count,
- int max_frame_count,
- GatherSamplesCallback gather_callback)
- : default_frame_count_(default_frame_count),
- max_frame_count_(max_frame_count),
- gather_callback_(gather_callback),
- callback_(nullptr) {
- caller_loop_ = base::MessageLoop::current();
- }
-
- ~TestAudioOutputStream() override {}
-
- bool Open() override { return true; }
- void Start(AudioSourceCallback* callback) override {
- callback_ = callback;
- GatherPlayedSamples();
- }
- void Stop() override {}
- void SetVolume(double volume) override {}
- void GetVolume(double* volume) override {}
- void Close() override {}
-
- private:
- void GatherPlayedSamples() {
- int frames = 0, total_frames = 0;
- do {
- // Call back into the player to get samples that it wants us to play.
- std::unique_ptr<media::AudioBus> dest =
- media::AudioBus::Create(1, default_frame_count_);
- frames = callback_->OnMoreData(dest.get(), 0, 0);
- total_frames += frames;
- // Send the samples given to us by the player to the gather callback.
- caller_loop_->task_runner()->PostTask(
- FROM_HERE, base::Bind(gather_callback_, base::Passed(&dest), frames));
- } while (frames && total_frames < max_frame_count_);
- }
-
- int default_frame_count_;
- int max_frame_count_;
- GatherSamplesCallback gather_callback_;
- AudioSourceCallback* callback_;
- base::MessageLoop* caller_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(TestAudioOutputStream);
-};
-
-} // namespace
-
-namespace audio_modem {
-
-class AudioPlayerTest : public testing::Test,
- public base::SupportsWeakPtr<AudioPlayerTest> {
- public:
- AudioPlayerTest() : buffer_index_(0), player_(nullptr) {
- audio_manager_ = media::AudioManager::CreateForTesting(
- base::ThreadTaskRunnerHandle::Get());
- base::RunLoop().RunUntilIdle();
- }
-
- ~AudioPlayerTest() override { DeletePlayer(); }
-
- void CreatePlayer() {
- DeletePlayer();
- player_ = new AudioPlayerImpl();
- player_->set_output_stream_for_testing(new TestAudioOutputStream(
- kDefaultFrameCount,
- kMaxFrameCount,
- base::Bind(&AudioPlayerTest::GatherSamples, AsWeakPtr())));
- player_->Initialize();
- base::RunLoop().RunUntilIdle();
- }
-
- void DeletePlayer() {
- if (!player_)
- return;
- player_->Finalize();
- player_ = nullptr;
- base::RunLoop().RunUntilIdle();
- }
-
- void PlayAndVerifySamples(
- const scoped_refptr<media::AudioBusRefCounted>& samples) {
- DCHECK_LT(samples->frames(), kMaxFrameCount);
-
- buffer_ = media::AudioBus::Create(1, kMaxFrameCount);
- buffer_index_ = 0;
- player_->Play(samples);
- player_->Stop();
- base::RunLoop().RunUntilIdle();
-
- int differences = 0;
- for (int i = 0; i < kMaxFrameCount; ++i) {
- differences += (buffer_->channel(0)[i] !=
- samples->channel(0)[i % samples->frames()]);
- }
- ASSERT_EQ(0, differences);
-
- buffer_.reset();
- }
-
- void GatherSamples(std::unique_ptr<media::AudioBus> bus, int frames) {
- if (!buffer_.get())
- return;
- bus->CopyPartialFramesTo(0, frames, buffer_index_, buffer_.get());
- buffer_index_ += frames;
- }
-
- protected:
- bool IsPlaying() {
- base::RunLoop().RunUntilIdle();
- return player_->is_playing_;
- }
-
- static const int kDefaultFrameCount = 1024;
- static const int kMaxFrameCount = 1024 * 100;
-
- base::TestMessageLoop message_loop_;
- media::ScopedAudioManagerPtr audio_manager_;
- std::unique_ptr<media::AudioBus> buffer_;
- int buffer_index_;
-
- // Deleted by calling Finalize() on the object.
- AudioPlayerImpl* player_;
-};
-
-TEST_F(AudioPlayerTest, BasicPlayAndStop) {
- CreatePlayer();
- scoped_refptr<media::AudioBusRefCounted> samples =
- media::AudioBusRefCounted::Create(1, 7331);
-
- player_->Play(samples);
- EXPECT_TRUE(IsPlaying());
-
- player_->Stop();
- EXPECT_FALSE(IsPlaying());
-
- player_->Play(samples);
- EXPECT_TRUE(IsPlaying());
-
- player_->Stop();
- EXPECT_FALSE(IsPlaying());
-
- player_->Play(samples);
- EXPECT_TRUE(IsPlaying());
-
- player_->Stop();
- EXPECT_FALSE(IsPlaying());
-
- DeletePlayer();
-}
-
-TEST_F(AudioPlayerTest, OutOfOrderPlayAndStopMultiple) {
- CreatePlayer();
- scoped_refptr<media::AudioBusRefCounted> samples =
- media::AudioBusRefCounted::Create(1, 1337);
-
- player_->Stop();
- player_->Stop();
- player_->Stop();
- EXPECT_FALSE(IsPlaying());
-
- player_->Play(samples);
- player_->Play(samples);
- EXPECT_TRUE(IsPlaying());
-
- player_->Stop();
- player_->Stop();
- EXPECT_FALSE(IsPlaying());
-
- DeletePlayer();
-}
-
-TEST_F(AudioPlayerTest, PlayingEndToEnd) {
- const int kNumSamples = kDefaultFrameCount * 7 + 321;
- CreatePlayer();
-
- PlayAndVerifySamples(CreateRandomAudioRefCounted(0x1337, 1, kNumSamples));
-
- DeletePlayer();
-}
-
-TEST_F(AudioPlayerTest, PlayingEndToEndRepeated) {
- const int kNumSamples = kDefaultFrameCount * 7 + 537;
- CreatePlayer();
-
- PlayAndVerifySamples(CreateRandomAudioRefCounted(0x1337, 1, kNumSamples));
-
- PlayAndVerifySamples(
- CreateRandomAudioRefCounted(0x7331, 1, kNumSamples - 3123));
-
- PlayAndVerifySamples(CreateRandomAudioRefCounted(0xf00d, 1, kNumSamples * 2));
-
- DeletePlayer();
-}
-
-} // namespace audio_modem
diff --git a/chromium/components/audio_modem/audio_recorder.h b/chromium/components/audio_modem/audio_recorder.h
deleted file mode 100644
index 259e188b2ad..00000000000
--- a/chromium/components/audio_modem/audio_recorder.h
+++ /dev/null
@@ -1,39 +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 COMPONENTS_AUDIO_MODEM_AUDIO_RECORDER_H_
-#define COMPONENTS_AUDIO_MODEM_AUDIO_RECORDER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "media/audio/audio_io.h"
-#include "media/base/audio_converter.h"
-#include "media/base/audio_parameters.h"
-
-namespace audio_modem {
-
-// The AudioRecorder class will record audio until told to stop.
-class AudioRecorder {
- public:
- using RecordedSamplesCallback = base::Callback<void(const std::string&)>;
-
- // Initializes the object. Do not use this object before calling this method.
- virtual void Initialize(const RecordedSamplesCallback& decode_callback) = 0;
-
- // If we are already recording, this function will do nothing.
- virtual void Record() = 0;
- // If we are already stopped, this function will do nothing.
- virtual void Stop() = 0;
-
- // Cleans up and deletes this object. Do not use object after this call.
- virtual void Finalize() = 0;
-
- protected:
- virtual ~AudioRecorder() {}
-};
-
-} // namespace audio_modem
-
-#endif // COMPONENTS_AUDIO_MODEM_AUDIO_RECORDER_H_
diff --git a/chromium/components/audio_modem/audio_recorder_impl.cc b/chromium/components/audio_modem/audio_recorder_impl.cc
deleted file mode 100644
index 43633fad807..00000000000
--- a/chromium/components/audio_modem/audio_recorder_impl.cc
+++ /dev/null
@@ -1,205 +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 "components/audio_modem/audio_recorder_impl.h"
-
-#include <algorithm>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/logging.h"
-#include "base/run_loop.h"
-#include "base/synchronization/waitable_event.h"
-#include "components/audio_modem/public/audio_modem_types.h"
-#include "content/public/browser/browser_thread.h"
-#include "media/audio/audio_device_description.h"
-#include "media/audio/audio_manager.h"
-#include "media/base/audio_bus.h"
-
-namespace audio_modem {
-
-namespace {
-
-const float kProcessIntervalMs = 500.0f; // milliseconds.
-
-void AudioBusToString(std::unique_ptr<media::AudioBus> source,
- std::string* buffer) {
- buffer->resize(source->frames() * source->channels() * sizeof(float));
- float* buffer_view = reinterpret_cast<float*>(string_as_array(buffer));
-
- const int channels = source->channels();
- for (int ch = 0; ch < channels; ++ch) {
- for (int si = 0, di = ch; si < source->frames(); ++si, di += channels)
- buffer_view[di] = source->channel(ch)[si];
- }
-}
-
-// Called every kProcessIntervalMs to process the recorded audio. This
-// converts our samples to the required sample rate, interleaves the samples
-// and sends them to the whispernet decoder to process.
-void ProcessSamples(
- std::unique_ptr<media::AudioBus> bus,
- const AudioRecorderImpl::RecordedSamplesCallback& callback) {
- std::string samples;
- AudioBusToString(std::move(bus), &samples);
- content::BrowserThread::PostTask(
- content::BrowserThread::UI, FROM_HERE, base::Bind(callback, samples));
-}
-
-void OnLogMessage(const std::string& message) {}
-
-} // namespace
-
-// Public methods.
-
-AudioRecorderImpl::AudioRecorderImpl()
- : is_recording_(false),
- stream_(nullptr),
- total_buffer_frames_(0),
- buffer_frame_index_(0) {
-}
-
-void AudioRecorderImpl::Initialize(
- const RecordedSamplesCallback& decode_callback) {
- decode_callback_ = decode_callback;
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&AudioRecorderImpl::InitializeOnAudioThread,
- base::Unretained(this)));
-}
-
-AudioRecorderImpl::~AudioRecorderImpl() {
-}
-
-void AudioRecorderImpl::Record() {
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&AudioRecorderImpl::RecordOnAudioThread,
- base::Unretained(this)));
-}
-
-void AudioRecorderImpl::Stop() {
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&AudioRecorderImpl::StopOnAudioThread,
- base::Unretained(this)));
-}
-
-void AudioRecorderImpl::Finalize() {
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&AudioRecorderImpl::FinalizeOnAudioThread,
- base::Unretained(this)));
-}
-
-// Private methods.
-
-void AudioRecorderImpl::InitializeOnAudioThread() {
- DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
-
- media::AudioParameters params;
- if (params_for_testing_) {
- params = *params_for_testing_;
- } else {
- params = media::AudioManager::Get()->GetInputStreamParameters(
- media::AudioDeviceDescription::kDefaultDeviceId);
- params.set_effects(media::AudioParameters::NO_EFFECTS);
- }
-
- total_buffer_frames_ = kProcessIntervalMs * params.sample_rate() / 1000;
- buffer_ = media::AudioBus::Create(params.channels(), total_buffer_frames_);
- buffer_frame_index_ = 0;
-
- stream_ = input_stream_for_testing_
- ? input_stream_for_testing_.get()
- : media::AudioManager::Get()->MakeAudioInputStream(
- params, media::AudioDeviceDescription::kDefaultDeviceId,
- base::Bind(&OnLogMessage));
-
- if (!stream_ || !stream_->Open()) {
- LOG(ERROR) << "Failed to open an input stream.";
- if (stream_) {
- stream_->Close();
- stream_ = nullptr;
- }
- return;
- }
- stream_->SetVolume(stream_->GetMaxVolume());
-}
-
-void AudioRecorderImpl::RecordOnAudioThread() {
- DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
- if (!stream_ || is_recording_)
- return;
-
- VLOG(3) << "Starting recording.";
- stream_->Start(this);
- is_recording_ = true;
-}
-
-void AudioRecorderImpl::StopOnAudioThread() {
- DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
- if (!stream_ || !is_recording_)
- return;
-
- VLOG(3) << "Stopping recording.";
- stream_->Stop();
- is_recording_ = false;
-}
-
-void AudioRecorderImpl::StopAndCloseOnAudioThread() {
- DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
- if (!stream_)
- return;
-
- StopOnAudioThread();
- stream_->Close();
- stream_ = nullptr;
-}
-
-void AudioRecorderImpl::FinalizeOnAudioThread() {
- DCHECK(media::AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
- StopAndCloseOnAudioThread();
- delete this;
-}
-
-void AudioRecorderImpl::OnData(media::AudioInputStream* stream,
- const media::AudioBus* source,
- uint32_t /* hardware_delay_bytes */,
- double /* volume */) {
- // source->frames() == source_params.frames_per_buffer(), so we only have
- // one chunk of data in the source; correspondingly set the destination
- // size to one chunk.
-
- int remaining_buffer_frames = buffer_->frames() - buffer_frame_index_;
- int frames_to_copy = std::min(remaining_buffer_frames, source->frames());
- source->CopyPartialFramesTo(0, frames_to_copy, buffer_frame_index_,
- buffer_.get());
- buffer_frame_index_ += frames_to_copy;
-
- // Buffer full, send it for processing.
- if (buffer_->frames() == buffer_frame_index_) {
- ProcessSamples(std::move(buffer_), decode_callback_);
- buffer_ = media::AudioBus::Create(source->channels(), total_buffer_frames_);
- buffer_frame_index_ = 0;
-
- // Copy any remaining frames in the source to our buffer.
- int remaining_source_frames = source->frames() - frames_to_copy;
- source->CopyPartialFramesTo(frames_to_copy, remaining_source_frames,
- buffer_frame_index_, buffer_.get());
- buffer_frame_index_ += remaining_source_frames;
- }
-}
-
-void AudioRecorderImpl::OnError(media::AudioInputStream* /* stream */) {
- LOG(ERROR) << "Error during sound recording.";
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&AudioRecorderImpl::StopAndCloseOnAudioThread,
- base::Unretained(this)));
-}
-
-} // namespace audio_modem
diff --git a/chromium/components/audio_modem/audio_recorder_impl.h b/chromium/components/audio_modem/audio_recorder_impl.h
deleted file mode 100644
index f98a95ff88e..00000000000
--- a/chromium/components/audio_modem/audio_recorder_impl.h
+++ /dev/null
@@ -1,102 +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 COMPONENTS_AUDIO_MODEM_AUDIO_RECORDER_IMPL_H_
-#define COMPONENTS_AUDIO_MODEM_AUDIO_RECORDER_IMPL_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "components/audio_modem/audio_recorder.h"
-#include "media/audio/audio_io.h"
-#include "media/base/audio_parameters.h"
-
-namespace base {
-class MessageLoop;
-}
-
-namespace media {
-class AudioBus;
-}
-
-namespace audio_modem {
-
-// The AudioRecorder class will record audio until told to stop.
-class AudioRecorderImpl final
- : public AudioRecorder,
- public media::AudioInputStream::AudioInputCallback {
- public:
- using RecordedSamplesCallback = base::Callback<void(const std::string&)>;
-
- AudioRecorderImpl();
-
- // AudioRecorder overrides:
- void Initialize(const RecordedSamplesCallback& decode_callback) override;
- void Record() override;
- void Stop() override;
- void Finalize() override;
-
- // Takes ownership of the stream.
- void set_input_stream_for_testing(
- media::AudioInputStream* input_stream_for_testing) {
- input_stream_for_testing_.reset(input_stream_for_testing);
- }
-
- // Takes ownership of the params.
- void set_params_for_testing(media::AudioParameters* params_for_testing) {
- params_for_testing_.reset(params_for_testing);
- }
-
- protected:
- ~AudioRecorderImpl() override;
- void set_is_recording(bool is_recording) { is_recording_ = is_recording; }
-
- private:
- friend class AudioRecorderTest;
- FRIEND_TEST_ALL_PREFIXES(AudioRecorderTest, BasicRecordAndStop);
- FRIEND_TEST_ALL_PREFIXES(AudioRecorderTest, OutOfOrderRecordAndStopMultiple);
-
- // Methods to do our various operations; all of these need to be run on the
- // audio thread.
- void InitializeOnAudioThread();
- void RecordOnAudioThread();
- void StopOnAudioThread();
- void StopAndCloseOnAudioThread();
- void FinalizeOnAudioThread();
-
- // AudioInputStream::AudioInputCallback overrides:
- // Called by the audio recorder when a full packet of audio data is
- // available. This is called from a special audio thread and the
- // implementation should return as soon as possible.
- void OnData(media::AudioInputStream* stream,
- const media::AudioBus* source,
- uint32_t hardware_delay_bytes,
- double volume) override;
- void OnError(media::AudioInputStream* stream) override;
-
- bool is_recording_;
-
- media::AudioInputStream* stream_;
-
- RecordedSamplesCallback decode_callback_;
-
- // Outside of the ctor/Initialize method, only access the next variables on
- // the recording thread.
- std::unique_ptr<media::AudioBus> buffer_;
- int total_buffer_frames_;
- int buffer_frame_index_;
-
- std::unique_ptr<media::AudioInputStream> input_stream_for_testing_;
- std::unique_ptr<media::AudioParameters> params_for_testing_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioRecorderImpl);
-};
-
-} // namespace audio_modem
-
-#endif // COMPONENTS_AUDIO_MODEM_AUDIO_RECORDER_IMPL_H_
diff --git a/chromium/components/audio_modem/audio_recorder_unittest.cc b/chromium/components/audio_modem/audio_recorder_unittest.cc
deleted file mode 100644
index 5d922fc455a..00000000000
--- a/chromium/components/audio_modem/audio_recorder_unittest.cc
+++ /dev/null
@@ -1,282 +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 "components/audio_modem/audio_recorder.h"
-
-#include <stddef.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/memory/aligned_memory.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "components/audio_modem/audio_recorder_impl.h"
-#include "components/audio_modem/public/audio_modem_types.h"
-#include "components/audio_modem/test/random_samples.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "media/audio/audio_device_description.h"
-#include "media/audio/audio_manager.h"
-#include "media/base/audio_bus.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const size_t kSomeNumber = 0x9999;
-
-class TestAudioInputStream : public media::AudioInputStream {
- public:
- TestAudioInputStream(const media::AudioParameters& params,
- const std::vector<float*> channel_data,
- size_t samples)
- : callback_(nullptr), params_(params) {
- buffer_ = media::AudioBus::CreateWrapper(2);
- for (size_t i = 0; i < channel_data.size(); ++i)
- buffer_->SetChannelData(i, channel_data[i]);
- buffer_->set_frames(samples);
- }
-
- ~TestAudioInputStream() override {}
-
- bool Open() override { return true; }
- void Start(AudioInputCallback* callback) override {
- DCHECK(callback);
- callback_ = callback;
- media::AudioManager::Get()->GetTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&TestAudioInputStream::SimulateRecording,
- base::Unretained(this)));
- }
- void Stop() override {}
- void Close() override {}
- double GetMaxVolume() override { return 1.0; }
- void SetVolume(double volume) override {}
- double GetVolume() override { return 1.0; }
- bool SetAutomaticGainControl(bool enabled) override { return false; }
- bool GetAutomaticGainControl() override { return true; }
- bool IsMuted() override { return false; }
-
- private:
- void SimulateRecording() {
- const int fpb = params_.frames_per_buffer();
- for (int i = 0; i < buffer_->frames() / fpb; ++i) {
- std::unique_ptr<media::AudioBus> source = media::AudioBus::Create(2, fpb);
- buffer_->CopyPartialFramesTo(i * fpb, fpb, 0, source.get());
- callback_->OnData(this, source.get(), fpb, 1.0);
- }
- }
-
- AudioInputCallback* callback_;
- media::AudioParameters params_;
- std::unique_ptr<media::AudioBus> buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(TestAudioInputStream);
-};
-
-} // namespace
-
-namespace audio_modem {
-
-class AudioRecorderTest : public testing::Test {
- public:
- AudioRecorderTest() : total_samples_(0), recorder_(nullptr) {
- audio_manager_ = media::AudioManager::CreateForTesting(
- base::ThreadTaskRunnerHandle::Get());
- base::RunLoop().RunUntilIdle();
- }
-
- ~AudioRecorderTest() override {
- DeleteRecorder();
- for (size_t i = 0; i < channel_data_.size(); ++i)
- base::AlignedFree(channel_data_[i]);
- }
-
- void CreateSimpleRecorder() {
- // If we have input devices, we'll create a recorder which uses a real
- // input stream, if not, we'll create a recorder which uses our mock input
- // stream.
- if (media::AudioManager::Get()->HasAudioInputDevices()) {
- DeleteRecorder();
- recorder_ = new AudioRecorderImpl();
- recorder_->Initialize(base::Bind(&AudioRecorderTest::DecodeSamples,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
- } else {
- CreateRecorder(kSomeNumber);
- }
- }
-
- void CreateRecorder(size_t samples) {
- DeleteRecorder();
-
- params_ = media::AudioManager::Get()->GetInputStreamParameters(
- media::AudioDeviceDescription::kDefaultDeviceId);
-
- channel_data_.clear();
- channel_data_.push_back(GenerateSamples(0x1337, samples));
- channel_data_.push_back(GenerateSamples(0x7331, samples));
-
- total_samples_ = samples;
-
- recorder_ = new AudioRecorderImpl();
- recorder_->set_input_stream_for_testing(
- new TestAudioInputStream(params_, channel_data_, samples));
- recorder_->set_params_for_testing(new media::AudioParameters(params_));
- recorder_->Initialize(
- base::Bind(&AudioRecorderTest::DecodeSamples, base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
- }
-
- void DeleteRecorder() {
- if (!recorder_)
- return;
- recorder_->Finalize();
- recorder_ = nullptr;
- base::RunLoop().RunUntilIdle();
- }
-
- void RecordAndVerifySamples() {
- received_samples_.clear();
- run_loop_.reset(new base::RunLoop());
- recorder_->Record();
- run_loop_->Run();
- }
-
- void DecodeSamples(const std::string& samples) {
- received_samples_ += samples;
- // We expect one less decode than our total samples would ideally have
- // triggered since we process data in 4k chunks. So our sample processing
- // will never rarely be perfectly aligned with 0.5s worth of samples, hence
- // we will almost always run with a buffer of leftover samples that will
- // not get sent to this callback since the recorder will be waiting for
- // more data.
- const size_t decode_buffer = params_.sample_rate() / 2; // 0.5s
- const size_t expected_samples =
- (total_samples_ / decode_buffer - 1) * decode_buffer;
- const size_t expected_samples_size =
- expected_samples * sizeof(float) * params_.channels();
- if (received_samples_.size() == expected_samples_size) {
- VerifySamples();
- run_loop_->Quit();
- }
- }
-
- void VerifySamples() {
- int differences = 0;
-
- float* buffer_view =
- reinterpret_cast<float*>(string_as_array(&received_samples_));
- const int channels = params_.channels();
- const int frames =
- received_samples_.size() / sizeof(float) / params_.channels();
- for (int ch = 0; ch < channels; ++ch) {
- for (int si = 0, di = ch; si < frames; ++si, di += channels)
- differences += (buffer_view[di] != channel_data_[ch][si]);
- }
-
- ASSERT_EQ(0, differences);
- }
-
- protected:
- float* GenerateSamples(int random_seed, size_t size) {
- float* samples = static_cast<float*>(base::AlignedAlloc(
- size * sizeof(float), media::AudioBus::kChannelAlignment));
- PopulateSamples(0x1337, size, samples);
- return samples;
- }
- bool IsRecording() {
- base::RunLoop().RunUntilIdle();
- return recorder_->is_recording_;
- }
-
- content::TestBrowserThreadBundle thread_bundle_;
- media::ScopedAudioManagerPtr audio_manager_;
-
- std::vector<float*> channel_data_;
- media::AudioParameters params_;
- size_t total_samples_;
-
- // Deleted by calling Finalize() on the object.
- AudioRecorderImpl* recorder_;
-
- std::string received_samples_;
-
- std::unique_ptr<base::RunLoop> run_loop_;
-};
-
-
-// http://crbug.com/463854
-#if defined(OS_MACOSX)
-#define MAYBE_BasicRecordAndStop DISABLED_BasicRecordAndStop
-#else
-#define MAYBE_BasicRecordAndStop BasicRecordAndStop
-#endif
-
-TEST_F(AudioRecorderTest, MAYBE_BasicRecordAndStop) {
- CreateSimpleRecorder();
-
- recorder_->Record();
- EXPECT_TRUE(IsRecording());
-
- recorder_->Stop();
- EXPECT_FALSE(IsRecording());
-
- recorder_->Record();
- EXPECT_TRUE(IsRecording());
-
- recorder_->Stop();
- EXPECT_FALSE(IsRecording());
-
- recorder_->Record();
- EXPECT_TRUE(IsRecording());
-
- recorder_->Stop();
- EXPECT_FALSE(IsRecording());
-
- DeleteRecorder();
-}
-
-// http://crbug.com/460685
-#if defined(OS_MACOSX)
-#define MAYBE_OutOfOrderRecordAndStopMultiple \
- DISABLED_OutOfOrderRecordAndStopMultiple
-#else
-#define MAYBE_OutOfOrderRecordAndStopMultiple \
- OutOfOrderRecordAndStopMultiple
-#endif
-
-TEST_F(AudioRecorderTest, MAYBE_OutOfOrderRecordAndStopMultiple) {
- CreateSimpleRecorder();
-
- recorder_->Stop();
- recorder_->Stop();
- recorder_->Stop();
- EXPECT_FALSE(IsRecording());
-
- recorder_->Record();
- recorder_->Record();
- EXPECT_TRUE(IsRecording());
-
- recorder_->Stop();
- recorder_->Stop();
- EXPECT_FALSE(IsRecording());
-
- DeleteRecorder();
-}
-
-TEST_F(AudioRecorderTest, RecordingEndToEnd) {
- const int kNumSamples = 48000 * 3;
- CreateRecorder(kNumSamples);
-
- RecordAndVerifySamples();
-
- DeleteRecorder();
-}
-
-// TODO(rkc): Add tests with recording different sample rates.
-
-} // namespace audio_modem
diff --git a/chromium/components/audio_modem/constants.cc b/chromium/components/audio_modem/constants.cc
deleted file mode 100644
index d85da143e0d..00000000000
--- a/chromium/components/audio_modem/constants.cc
+++ /dev/null
@@ -1,15 +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 "components/audio_modem/public/audio_modem_types.h"
-
-namespace audio_modem {
-
-const int kDefaultRepetitions = 5;
-const float kDefaultSampleRate = 48000.0f;
-const int kDefaultBitsPerSample = 16;
-const float kDefaultCarrierFrequency = 18500.0f;
-const media::ChannelLayout kDefaultChannelLayout = media::CHANNEL_LAYOUT_STEREO;
-
-} // namespace audio_modem
diff --git a/chromium/components/audio_modem/modem_impl.cc b/chromium/components/audio_modem/modem_impl.cc
deleted file mode 100644
index 447250cad93..00000000000
--- a/chromium/components/audio_modem/modem_impl.cc
+++ /dev/null
@@ -1,344 +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 "components/audio_modem/modem_impl.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <limits>
-#include <memory>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "components/audio_modem/audio_modem_switches.h"
-#include "components/audio_modem/audio_player_impl.h"
-#include "components/audio_modem/audio_recorder_impl.h"
-#include "components/audio_modem/public/whispernet_client.h"
-#include "content/public/browser/browser_thread.h"
-#include "media/audio/audio_manager.h"
-#include "media/audio/audio_manager_base.h"
-#include "media/base/audio_bus.h"
-#include "third_party/webrtc/common_audio/wav_file.h"
-
-namespace audio_modem {
-
-namespace {
-
-const int kMaxSamples = 10000;
-const int kTokenTimeoutMs = 2000;
-const int kMonoChannelCount = 1;
-
-// UrlSafe is defined as:
-// '/' represented by a '_' and '+' represented by a '-'
-// TODO(ckehoe): Move this to a central place.
-std::string FromUrlSafe(std::string token) {
- base::ReplaceChars(token, "-", "+", &token);
- base::ReplaceChars(token, "_", "/", &token);
- return token;
-}
-std::string ToUrlSafe(std::string token) {
- base::ReplaceChars(token, "+", "-", &token);
- base::ReplaceChars(token, "/", "_", &token);
- return token;
-}
-
-// TODO(ckehoe): Move this to a central place.
-std::string AudioTypeToString(AudioType audio_type) {
- if (audio_type == AUDIBLE)
- return "audible";
- if (audio_type == INAUDIBLE)
- return "inaudible";
-
- NOTREACHED() << "Got unexpected token type " << audio_type;
- return std::string();
-}
-
-bool ReadBooleanFlag(const std::string& flag, bool default_value) {
- const std::string flag_value = base::ToLowerASCII(
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(flag));
- if (flag_value == "true" || flag_value == "1")
- return true;
- if (flag_value == "false" || flag_value == "0")
- return false;
- LOG_IF(ERROR, !flag_value.empty())
- << "Unrecognized value \"" << flag_value << " for flag "
- << flag << ". Defaulting to " << default_value;
- return default_value;
-}
-
-} // namespace
-
-
-// Public functions.
-
-ModemImpl::ModemImpl() : client_(nullptr), recorder_(nullptr) {
- // TODO(rkc): Move all of these into initializer lists once it is allowed.
- should_be_playing_[AUDIBLE] = false;
- should_be_playing_[INAUDIBLE] = false;
- should_be_recording_[AUDIBLE] = false;
- should_be_recording_[INAUDIBLE] = false;
-
- player_enabled_[AUDIBLE] = ReadBooleanFlag(
- switches::kAudioModemEnableAudibleBroadcast, true);
- player_enabled_[INAUDIBLE] = ReadBooleanFlag(
- switches::kAudioModemEnableInaudibleBroadcast, true);
- player_[AUDIBLE] = nullptr;
- player_[INAUDIBLE] = nullptr;
-
- samples_caches_.resize(2);
- samples_caches_[AUDIBLE] = new SamplesMap(kMaxSamples);
- samples_caches_[INAUDIBLE] = new SamplesMap(kMaxSamples);
-}
-
-void ModemImpl::Initialize(WhispernetClient* client,
- const TokensCallback& tokens_cb) {
- DCHECK(client);
- client_ = client;
- tokens_cb_ = tokens_cb;
-
- // These will be unregistered on destruction, so unretained is safe to use.
- client_->RegisterTokensCallback(
- base::Bind(&ModemImpl::OnTokensFound, base::Unretained(this)));
- client_->RegisterSamplesCallback(
- base::Bind(&ModemImpl::OnTokenEncoded, base::Unretained(this)));
-
- if (!player_[AUDIBLE])
- player_[AUDIBLE] = new AudioPlayerImpl();
- player_[AUDIBLE]->Initialize();
-
- if (!player_[INAUDIBLE])
- player_[INAUDIBLE] = new AudioPlayerImpl();
- player_[INAUDIBLE]->Initialize();
-
- decode_cancelable_cb_.Reset(base::Bind(
- &ModemImpl::DecodeSamplesConnector, base::Unretained(this)));
- if (!recorder_)
- recorder_ = new AudioRecorderImpl();
- recorder_->Initialize(decode_cancelable_cb_.callback());
-
- dump_tokens_dir_ = base::FilePath(base::CommandLine::ForCurrentProcess()
- ->GetSwitchValueNative(switches::kAudioModemDumpTokensToDir));
-}
-
-ModemImpl::~ModemImpl() {
- if (player_[AUDIBLE])
- player_[AUDIBLE]->Finalize();
- if (player_[INAUDIBLE])
- player_[INAUDIBLE]->Finalize();
- if (recorder_)
- recorder_->Finalize();
-
- // Whispernet initialization may never have completed.
- if (client_) {
- client_->RegisterTokensCallback(TokensCallback());
- client_->RegisterSamplesCallback(SamplesCallback());
- }
-}
-
-void ModemImpl::StartPlaying(AudioType type) {
- DCHECK(type == AUDIBLE || type == INAUDIBLE);
- should_be_playing_[type] = true;
- // If we don't have our token encoded yet, this check will be false, for now.
- // Once our token is encoded, OnTokenEncoded will call UpdateToken, which
- // will call this code again (if we're still supposed to be playing).
- SamplesMap::iterator samples =
- samples_caches_[type]->Get(playing_token_[type]);
- if (samples != samples_caches_[type]->end()) {
- DCHECK(!playing_token_[type].empty());
- if (player_enabled_[type]) {
- started_playing_[type] = base::Time::Now();
- player_[type]->Play(samples->second);
-
- // If we're playing, we always record to hear what we are playing.
- recorder_->Record();
- } else {
- DVLOG(3) << "Skipping playback for disabled " << AudioTypeToString(type)
- << " player.";
- }
- }
-}
-
-void ModemImpl::StopPlaying(AudioType type) {
- DCHECK(type == AUDIBLE || type == INAUDIBLE);
- should_be_playing_[type] = false;
- player_[type]->Stop();
- // If we were only recording to hear our own played tokens, stop.
- if (!should_be_recording_[AUDIBLE] && !should_be_recording_[INAUDIBLE])
- recorder_->Stop();
- playing_token_[type] = std::string();
-}
-
-void ModemImpl::StartRecording(AudioType type) {
- DCHECK(type == AUDIBLE || type == INAUDIBLE);
- should_be_recording_[type] = true;
- recorder_->Record();
-}
-
-void ModemImpl::StopRecording(AudioType type) {
- DCHECK(type == AUDIBLE || type == INAUDIBLE);
- should_be_recording_[type] = false;
- recorder_->Stop();
-}
-
-void ModemImpl::SetToken(AudioType type,
- const std::string& url_safe_token) {
- DCHECK(type == AUDIBLE || type == INAUDIBLE);
- std::string token = FromUrlSafe(url_safe_token);
- if (samples_caches_[type]->Get(token) == samples_caches_[type]->end()) {
- client_->EncodeToken(token, type, token_params_);
- } else {
- UpdateToken(type, token);
- }
-}
-
-const std::string ModemImpl::GetToken(AudioType type) const {
- return playing_token_[type];
-}
-
-bool ModemImpl::IsPlayingTokenHeard(AudioType type) const {
- base::TimeDelta tokenTimeout =
- base::TimeDelta::FromMilliseconds(kTokenTimeoutMs);
-
- // This is a bit of a hack. If we haven't been playing long enough,
- // return true to avoid tripping an audio fail alarm.
- if (base::Time::Now() - started_playing_[type] < tokenTimeout)
- return true;
-
- return base::Time::Now() - heard_own_token_[type] < tokenTimeout;
-}
-
-void ModemImpl::SetTokenParams(AudioType type, const TokenParameters& params) {
- DCHECK_GT(params.length, 0u);
- token_params_[type] = params;
-
- // TODO(ckehoe): Make whispernet handle different token lengths
- // simultaneously without reinitializing the decoder over and over.
-}
-
-// static
-std::unique_ptr<Modem> Modem::Create() {
- return base::WrapUnique<Modem>(new ModemImpl);
-}
-
-// Private functions.
-
-void ModemImpl::OnTokenEncoded(
- AudioType type,
- const std::string& token,
- const scoped_refptr<media::AudioBusRefCounted>& samples) {
- samples_caches_[type]->Put(token, samples);
- DumpToken(type, token, samples.get());
- UpdateToken(type, token);
-}
-
-void ModemImpl::OnTokensFound(const std::vector<AudioToken>& tokens) {
- std::vector<AudioToken> tokens_to_report;
- for (const auto& token : tokens) {
- AudioType type = token.audible ? AUDIBLE : INAUDIBLE;
- if (playing_token_[type] == token.token)
- heard_own_token_[type] = base::Time::Now();
-
- if (should_be_recording_[AUDIBLE] && token.audible) {
- tokens_to_report.push_back(token);
- } else if (should_be_recording_[INAUDIBLE] && !token.audible) {
- tokens_to_report.push_back(token);
- }
- }
-
- if (!tokens_to_report.empty())
- tokens_cb_.Run(tokens_to_report);
-}
-
-void ModemImpl::UpdateToken(AudioType type, const std::string& token) {
- DCHECK(type == AUDIBLE || type == INAUDIBLE);
- if (playing_token_[type] == token)
- return;
-
- // Update token.
- playing_token_[type] = token;
-
- // If we are supposed to be playing this token type at this moment, switch
- // out playback with the new samples.
- if (should_be_playing_[type])
- RestartPlaying(type);
-}
-
-void ModemImpl::RestartPlaying(AudioType type) {
- DCHECK(type == AUDIBLE || type == INAUDIBLE);
- // We should already have this token in the cache. This function is not
- // called from anywhere except update token and only once we have our samples
- // in the cache.
- DCHECK(samples_caches_[type]->Get(playing_token_[type]) !=
- samples_caches_[type]->end());
-
- player_[type]->Stop();
- StartPlaying(type);
-}
-
-void ModemImpl::DecodeSamplesConnector(const std::string& samples) {
- // If we are either supposed to be recording *or* playing, audible or
- // inaudible, we should be decoding that type. This is so that if we are
- // just playing, we will still decode our recorded token so we can check
- // if we heard our own token. Whether or not we report the token to the
- // server is checked for and handled in OnTokensFound.
-
- bool decode_audible =
- should_be_recording_[AUDIBLE] || should_be_playing_[AUDIBLE];
- bool decode_inaudible =
- should_be_recording_[INAUDIBLE] || should_be_playing_[INAUDIBLE];
-
- if (decode_audible && decode_inaudible) {
- client_->DecodeSamples(BOTH, samples, token_params_);
- } else if (decode_audible) {
- client_->DecodeSamples(AUDIBLE, samples, token_params_);
- } else if (decode_inaudible) {
- client_->DecodeSamples(INAUDIBLE, samples, token_params_);
- }
-}
-
-void ModemImpl::DumpToken(AudioType audio_type,
- const std::string& token,
- const media::AudioBus* samples) {
- if (dump_tokens_dir_.empty())
- return;
-
- // Convert the samples to 16-bit integers.
- std::vector<int16_t> int_samples;
- int_samples.reserve(samples->frames());
- for (int i = 0; i < samples->frames(); i++) {
- int_samples.push_back(round(
- samples->channel(0)[i] * std::numeric_limits<int16_t>::max()));
- }
- DCHECK_EQ(static_cast<int>(int_samples.size()), samples->frames());
- DCHECK_EQ(kMonoChannelCount, samples->channels());
-
- const std::string filename = base::StringPrintf("%s %s.wav",
- AudioTypeToString(audio_type).c_str(), ToUrlSafe(token).c_str());
- DVLOG(3) << "Dumping token " << filename;
-
- std::string file_str;
-#if defined(OS_WIN)
- base::FilePath file_path = dump_tokens_dir_.Append(
- base::SysNativeMBToWide(filename));
- file_str = base::SysWideToNativeMB(file_path.value());
-#else
- file_str = dump_tokens_dir_.Append(filename).value();
-#endif
-
- webrtc::WavWriter writer(file_str, kDefaultSampleRate, kMonoChannelCount);
- writer.WriteSamples(int_samples.data(), int_samples.size());
-}
-
-} // namespace audio_modem
diff --git a/chromium/components/audio_modem/modem_impl.h b/chromium/components/audio_modem/modem_impl.h
deleted file mode 100644
index ec6beb52999..00000000000
--- a/chromium/components/audio_modem/modem_impl.h
+++ /dev/null
@@ -1,127 +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 COMPONENTS_AUDIO_MODEM_MODEM_IMPL_H_
-#define COMPONENTS_AUDIO_MODEM_MODEM_IMPL_H_
-
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/cancelable_callback.h"
-#include "base/containers/mru_cache.h"
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
-#include "components/audio_modem/public/audio_modem_types.h"
-#include "components/audio_modem/public/modem.h"
-#include "media/base/audio_bus.h"
-
-namespace base {
-class Time;
-}
-
-namespace audio_modem {
-
-class AudioPlayer;
-class AudioRecorder;
-class WhispernetClient;
-
-// The ModemImpl class manages the playback and recording of tokens.
-// Clients should not necessary expect the modem to play or record continuously.
-// In the future, it may timeslice multiple tokens, or implement carrier sense.
-class ModemImpl final : public Modem {
- public:
- ModemImpl();
- ~ModemImpl() override;
-
- // Modem overrides:
- void Initialize(WhispernetClient* client,
- const TokensCallback& tokens_cb) override;
- void StartPlaying(AudioType type) override;
- void StopPlaying(AudioType type) override;
- void StartRecording(AudioType type) override;
- void StopRecording(AudioType type) override;
- void SetToken(AudioType type, const std::string& url_safe_token) override;
- const std::string GetToken(AudioType type) const override;
- bool IsPlayingTokenHeard(AudioType type) const override;
- void SetTokenParams(AudioType type, const TokenParameters& params) override;
-
- void set_player_for_testing(AudioType type, AudioPlayer* player) {
- player_[type] = player;
- }
- void set_recorder_for_testing(AudioRecorder* recorder) {
- recorder_ = recorder;
- }
-
- private:
- using SamplesMap = base::MRUCache<std::string,
- scoped_refptr<media::AudioBusRefCounted>>;
-
- // Receives the audio samples from encoding a token.
- void OnTokenEncoded(AudioType type,
- const std::string& token,
- const scoped_refptr<media::AudioBusRefCounted>& samples);
-
- // Receives any tokens found by decoding audio samples.
- void OnTokensFound(const std::vector<AudioToken>& tokens);
-
- // Update our currently playing token with the new token. Change the playing
- // samples if needed. Prerequisite: Samples corresponding to this token
- // should already be in the samples cache.
- void UpdateToken(AudioType type, const std::string& token);
-
- void RestartPlaying(AudioType type);
-
- void DecodeSamplesConnector(const std::string& samples);
-
- void DumpToken(AudioType audio_type,
- const std::string& token,
- const media::AudioBus* samples);
-
- WhispernetClient* client_;
-
- // Callbacks to send tokens back to the client.
- TokensCallback tokens_cb_;
-
- // This cancelable callback is passed to the recorder. The recorder's
- // destruction will happen on the audio thread, so it can outlive us.
- base::CancelableCallback<void(const std::string&)> decode_cancelable_cb_;
-
- // We use the AudioType enum to index into all our data structures that work
- // on values for both audible and inaudible.
- static_assert(AUDIBLE == 0, "AudioType::AUDIBLE should be 0.");
- static_assert(INAUDIBLE == 1, "AudioType::INAUDIBLE should be 1.");
-
- // Indexed using enum AudioType.
- bool player_enabled_[2];
- bool should_be_playing_[2];
- bool should_be_recording_[2];
-
- // AudioPlayer and AudioRecorder objects are self-deleting. When we call
- // Finalize on them, they clean themselves up on the Audio thread.
- // Indexed using enum AudioType.
- AudioPlayer* player_[2];
- AudioRecorder* recorder_;
-
- // Indexed using enum AudioType.
- std::string playing_token_[2];
- TokenParameters token_params_[2];
- base::Time started_playing_[2];
- base::Time heard_own_token_[2];
-
- // Cache that holds the encoded samples. After reaching its limit, the cache
- // expires the oldest samples first.
- // Indexed using enum AudioType.
- ScopedVector<SamplesMap> samples_caches_;
-
- base::FilePath dump_tokens_dir_;
-
- DISALLOW_COPY_AND_ASSIGN(ModemImpl);
-};
-
-} // namespace audio_modem
-
-#endif // COMPONENTS_AUDIO_MODEM_MODEM_IMPL_H_
diff --git a/chromium/components/audio_modem/modem_unittest.cc b/chromium/components/audio_modem/modem_unittest.cc
deleted file mode 100644
index b18c7f85f57..00000000000
--- a/chromium/components/audio_modem/modem_unittest.cc
+++ /dev/null
@@ -1,155 +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 "components/audio_modem/public/modem.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "components/audio_modem/audio_player.h"
-#include "components/audio_modem/audio_recorder.h"
-#include "components/audio_modem/modem_impl.h"
-#include "components/audio_modem/test/random_samples.h"
-#include "components/audio_modem/test/stub_whispernet_client.h"
-#include "media/base/audio_bus.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace audio_modem {
-
-class AudioPlayerStub final : public AudioPlayer {
- public:
- AudioPlayerStub() : is_playing_(false) {}
- ~AudioPlayerStub() override {}
-
- // AudioPlayer overrides:
- void Initialize() override {}
- void Play(const scoped_refptr<media::AudioBusRefCounted>&) override {
- is_playing_ = true;
- }
- void Stop() override { is_playing_ = false; }
- void Finalize() override { delete this; }
-
- bool IsPlaying() { return is_playing_; }
-
- private:
- bool is_playing_;
- DISALLOW_COPY_AND_ASSIGN(AudioPlayerStub);
-};
-
-class AudioRecorderStub final : public AudioRecorder {
- public:
- AudioRecorderStub() : is_recording_(false) {}
- ~AudioRecorderStub() override {}
-
- // AudioRecorder overrides:
- void Initialize(const RecordedSamplesCallback& cb) override { cb_ = cb; }
- void Record() override { is_recording_ = true; }
- void Stop() override { is_recording_ = false; }
- void Finalize() override { delete this; }
-
- bool IsRecording() { return is_recording_; }
-
- void TriggerDecodeRequest() {
- if (!cb_.is_null())
- cb_.Run(std::string(0x1337, 'a'));
- }
-
- private:
- RecordedSamplesCallback cb_;
- bool is_recording_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioRecorderStub);
-};
-
-class ModemTest : public testing::Test {
- public:
- ModemTest()
- : modem_(new ModemImpl),
- audible_player_(new AudioPlayerStub),
- inaudible_player_(new AudioPlayerStub),
- recorder_(new AudioRecorderStub),
- last_received_decode_type_(AUDIO_TYPE_UNKNOWN) {
- std::vector<AudioToken> tokens;
- tokens.push_back(AudioToken("abcdef", true));
- tokens.push_back(AudioToken("123456", false));
- client_.reset(new StubWhispernetClient(
- CreateRandomAudioRefCounted(0x123, 1, 0x321), tokens));
-
- // TODO(ckehoe): Pass these into the Modem constructor instead.
- modem_->set_player_for_testing(AUDIBLE, audible_player_);
- modem_->set_player_for_testing(INAUDIBLE, inaudible_player_);
- modem_->set_recorder_for_testing(recorder_);
- modem_->Initialize(
- client_.get(),
- base::Bind(&ModemTest::GetTokens, base::Unretained(this)));
- }
-
- ~ModemTest() override {}
-
- protected:
- void GetTokens(const std::vector<AudioToken>& tokens) {
- last_received_decode_type_ = AUDIO_TYPE_UNKNOWN;
- for (const auto& token : tokens) {
- if (token.audible && last_received_decode_type_ == INAUDIBLE) {
- last_received_decode_type_ = BOTH;
- } else if (!token.audible && last_received_decode_type_ == AUDIBLE) {
- last_received_decode_type_ = BOTH;
- } else if (token.audible) {
- last_received_decode_type_ = AUDIBLE;
- } else {
- last_received_decode_type_ = INAUDIBLE;
- }
- }
- }
-
- base::MessageLoop message_loop_;
- // This order is important. The WhispernetClient needs to outlive the Modem.
- std::unique_ptr<WhispernetClient> client_;
- std::unique_ptr<ModemImpl> modem_;
-
- // These will be deleted by the Modem's destructor calling finalize on them.
- AudioPlayerStub* audible_player_;
- AudioPlayerStub* inaudible_player_;
- AudioRecorderStub* recorder_;
-
- AudioType last_received_decode_type_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ModemTest);
-};
-
-TEST_F(ModemTest, EncodeToken) {
- modem_->StartPlaying(AUDIBLE);
- // No token yet, player shouldn't be playing.
- EXPECT_FALSE(audible_player_->IsPlaying());
-
- modem_->SetToken(INAUDIBLE, "abcd");
- // No *audible* token yet, so player still shouldn't be playing.
- EXPECT_FALSE(audible_player_->IsPlaying());
-
- modem_->SetToken(AUDIBLE, "abcd");
- EXPECT_TRUE(audible_player_->IsPlaying());
-}
-
-TEST_F(ModemTest, Record) {
- recorder_->TriggerDecodeRequest();
- EXPECT_EQ(AUDIO_TYPE_UNKNOWN, last_received_decode_type_);
-
- modem_->StartRecording(AUDIBLE);
- recorder_->TriggerDecodeRequest();
- EXPECT_EQ(AUDIBLE, last_received_decode_type_);
-
- modem_->StartRecording(INAUDIBLE);
- recorder_->TriggerDecodeRequest();
- EXPECT_EQ(BOTH, last_received_decode_type_);
-
- modem_->StopRecording(AUDIBLE);
- recorder_->TriggerDecodeRequest();
- EXPECT_EQ(INAUDIBLE, last_received_decode_type_);
-}
-
-} // namespace audio_modem
diff --git a/chromium/components/audio_modem/public/audio_modem_types.h b/chromium/components/audio_modem/public/audio_modem_types.h
deleted file mode 100644
index 3ccf6888f04..00000000000
--- a/chromium/components/audio_modem/public/audio_modem_types.h
+++ /dev/null
@@ -1,75 +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 COMPONENTS_AUDIO_MODEM_PUBLIC_AUDIO_MODEM_TYPES_H_
-#define COMPONENTS_AUDIO_MODEM_PUBLIC_AUDIO_MODEM_TYPES_H_
-
-#include <stddef.h>
-
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/ref_counted.h"
-#include "media/base/channel_layout.h"
-
-// Various constants and types used for the audio modem.
-// TODO(ckehoe): Move the constants out into their own header.
-
-namespace audio_modem {
-
-// Number of repetitions of the audio token in one sequence of samples.
-extern const int kDefaultRepetitions;
-
-// Whispernet encoding parameters. These need to be the same on all platforms.
-extern const float kDefaultSampleRate;
-extern const int kDefaultBitsPerSample;
-extern const float kDefaultCarrierFrequency;
-
-// This really needs to be configurable since it doesn't need
-// to be consistent across platforms, or even playing/recording.
-extern const media::ChannelLayout kDefaultChannelLayout;
-
-// Enum to represent the audio band (audible vs. ultrasound).
-// AUDIBLE and INAUDIBLE are used as array indices.
-enum AudioType {
- AUDIBLE = 0,
- INAUDIBLE = 1,
- BOTH = 2,
- AUDIO_TYPE_UNKNOWN = 3,
-};
-
-// Struct representing an audio token.
-// TODO(ckehoe): Make this use the AudioType enum instead of a boolean.
-struct AudioToken final {
- AudioToken(const std::string& token, bool audible)
- : token(token),
- audible(audible) {}
-
- std::string token;
- bool audible;
-};
-
-// Struct to hold the encoding parameters for tokens.
-// Parity is on by default.
-struct TokenParameters {
- TokenParameters() : TokenParameters(0, false, true) {}
-
- explicit TokenParameters(size_t length)
- : TokenParameters(length, false, true) {}
-
- TokenParameters(size_t length, bool crc, bool parity)
- : length(length), crc(crc), parity(parity) {}
-
- size_t length;
- bool crc;
- bool parity;
-};
-
-// Callback to pass around found tokens.
-using TokensCallback = base::Callback<void(const std::vector<AudioToken>&)>;
-
-} // namespace audio_modem
-
-#endif // COMPONENTS_AUDIO_MODEM_PUBLIC_AUDIO_MODEM_TYPES_H_
diff --git a/chromium/components/audio_modem/public/modem.h b/chromium/components/audio_modem/public/modem.h
deleted file mode 100644
index 4dfeeeadb8b..00000000000
--- a/chromium/components/audio_modem/public/modem.h
+++ /dev/null
@@ -1,46 +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 COMPONENTS_AUDIO_MODEM_PUBLIC_MODEM_H_
-#define COMPONENTS_AUDIO_MODEM_PUBLIC_MODEM_H_
-
-#include <memory>
-#include <string>
-
-#include "components/audio_modem/public/audio_modem_types.h"
-
-namespace audio_modem {
-
-class WhispernetClient;
-
-class Modem {
- public:
- virtual ~Modem() {}
-
- // Initializes the object. Do not use this object before calling this method.
- virtual void Initialize(WhispernetClient* client,
- const TokensCallback& tokens_cb) = 0;
-
- virtual void StartPlaying(AudioType type) = 0;
- virtual void StopPlaying(AudioType type) = 0;
-
- virtual void StartRecording(AudioType type) = 0;
- virtual void StopRecording(AudioType type) = 0;
-
- virtual void SetToken(AudioType type,
- const std::string& url_safe_token) = 0;
-
- virtual const std::string GetToken(AudioType type) const = 0;
-
- virtual bool IsPlayingTokenHeard(AudioType type) const = 0;
-
- virtual void SetTokenParams(AudioType type,
- const TokenParameters& params) = 0;
-
- static std::unique_ptr<Modem> Create();
-};
-
-} // namespace audio_modem
-
-#endif // COMPONENTS_AUDIO_MODEM_PUBLIC_MODEM_H_
diff --git a/chromium/components/audio_modem/public/whispernet_client.h b/chromium/components/audio_modem/public/whispernet_client.h
deleted file mode 100644
index 48d1efa9b2b..00000000000
--- a/chromium/components/audio_modem/public/whispernet_client.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUDIO_MODEM_PUBLIC_WHISPERNET_CLIENT_H_
-#define COMPONENTS_AUDIO_MODEM_PUBLIC_WHISPERNET_CLIENT_H_
-
-#include <string>
-
-#include "base/memory/ref_counted.h"
-#include "components/audio_modem/public/audio_modem_types.h"
-#include "media/base/audio_bus.h"
-
-namespace audio_modem {
-
-// Generic callback to indicate a boolean success or failure.
-using SuccessCallback = base::Callback<void(bool)>;
-
-// Callback to receive encoded samples from Whispernet.
-// AudioType type: Type of audio encoding - AUDIBLE or INAUDIBLE.
-// const std::string& token: The token that we encoded.
-// const scoped_refptr<media::AudioBusRefCounted>& samples - Encoded samples.
-using SamplesCallback =
- base::Callback<void(AudioType,
- const std::string&,
- const scoped_refptr<media::AudioBusRefCounted>&)>;
-
-// A client for the Whispernet audio library,
-// responsible for the actual encoding and decoding of tokens.
-class WhispernetClient {
- public:
- // Initialize the whispernet client and call the callback when done. The
- // parameter indicates whether we succeeded or failed.
- virtual void Initialize(const SuccessCallback& init_callback) = 0;
-
- // Fires an event to request a token encode.
- virtual void EncodeToken(const std::string& token,
- AudioType type,
- const TokenParameters token_params[2]) = 0;
- // Fires an event to request a decode for the given samples.
- virtual void DecodeSamples(AudioType type,
- const std::string& samples,
- const TokenParameters token_params[2]) = 0;
-
- // Callback registration methods. The modem will set these to receive data.
- virtual void RegisterTokensCallback(
- const TokensCallback& tokens_callback) = 0;
- virtual void RegisterSamplesCallback(
- const SamplesCallback& samples_callback) = 0;
-
- // Don't cache these callbacks, as they may become invalid at any time.
- // Always invoke callbacks directly through these accessors.
- virtual TokensCallback GetTokensCallback() = 0;
- virtual SamplesCallback GetSamplesCallback() = 0;
- virtual SuccessCallback GetInitializedCallback() = 0;
-
- virtual ~WhispernetClient() {}
-};
-
-} // namespace audio_modem
-
-#endif // COMPONENTS_AUDIO_MODEM_PUBLIC_WHISPERNET_CLIENT_H_
diff --git a/chromium/components/auto_login_parser.gypi b/chromium/components/auto_login_parser.gypi
deleted file mode 100644
index 1dae9360602..00000000000
--- a/chromium/components/auto_login_parser.gypi
+++ /dev/null
@@ -1,23 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'auto_login_parser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'auto_login_parser/auto_login_parser.cc',
- 'auto_login_parser/auto_login_parser.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/auto_login_parser/BUILD.gn b/chromium/components/auto_login_parser/BUILD.gn
deleted file mode 100644
index b59919502b3..00000000000
--- a/chromium/components/auto_login_parser/BUILD.gn
+++ /dev/null
@@ -1,27 +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.
-
-source_set("auto_login_parser") {
- sources = [
- "auto_login_parser.cc",
- "auto_login_parser.h",
- ]
-
- deps = [
- "//base",
- "//net",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "auto_login_parser_unittest.cc",
- ]
-
- deps = [
- ":auto_login_parser",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/auto_login_parser/DEPS b/chromium/components/auto_login_parser/DEPS
deleted file mode 100644
index 8fa9d48d882..00000000000
--- a/chromium/components/auto_login_parser/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+net",
-]
diff --git a/chromium/components/auto_login_parser/OWNERS b/chromium/components/auto_login_parser/OWNERS
deleted file mode 100644
index 57a0c64f500..00000000000
--- a/chromium/components/auto_login_parser/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-boliu@chromium.org
diff --git a/chromium/components/auto_login_parser/auto_login_parser.cc b/chromium/components/auto_login_parser/auto_login_parser.cc
deleted file mode 100644
index 8f3c725d7fe..00000000000
--- a/chromium/components/auto_login_parser/auto_login_parser.cc
+++ /dev/null
@@ -1,86 +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 "components/auto_login_parser/auto_login_parser.h"
-
-#include <utility>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/strings/string_split.h"
-#include "net/base/escape.h"
-#include "net/url_request/url_request.h"
-
-namespace auto_login_parser {
-
-namespace {
-
-const char kHeaderName[] = "X-Auto-Login";
-
-bool MatchRealm(const std::string& realm, RealmRestriction restriction) {
- switch (restriction) {
- case ONLY_GOOGLE_COM:
- return realm == "com.google";
- case ALLOW_ANY_REALM:
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-} // namespace
-
-HeaderData::HeaderData() {}
-HeaderData::~HeaderData() {}
-
-bool ParseHeader(const std::string& header,
- RealmRestriction realm_restriction,
- HeaderData* header_data) {
- // TODO(pliard): Investigate/fix potential internationalization issue. It
- // seems that "account" from the x-auto-login header might contain non-ASCII
- // characters.
- if (header.empty())
- return false;
-
- base::StringPairs pairs;
- if (!base::SplitStringIntoKeyValuePairs(header, '=', '&', &pairs))
- return false;
-
- // Parse the information from the |header| string.
- HeaderData local_params;
- for (base::StringPairs::const_iterator it = pairs.begin(); it != pairs.end();
- ++it) {
- const std::string& key = it->first;
- const std::string& value = it->second;
- std::string unescaped_value(net::UnescapeURLComponent(
- value,
- net::UnescapeRule::PATH_SEPARATORS |
- net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS));
- if (key == "realm") {
- if (!MatchRealm(unescaped_value, realm_restriction))
- return false;
- local_params.realm = unescaped_value;
- } else if (key == "account") {
- local_params.account = unescaped_value;
- } else if (key == "args") {
- local_params.args = unescaped_value;
- }
- }
- if (local_params.realm.empty() || local_params.args.empty())
- return false;
-
- *header_data = local_params;
- return true;
-}
-
-bool ParserHeaderInResponse(net::URLRequest* request,
- RealmRestriction realm_restriction,
- HeaderData* header_data) {
- std::string header_string;
- request->GetResponseHeaderByName(kHeaderName, &header_string);
- return ParseHeader(header_string, realm_restriction, header_data);
-}
-
-} // namespace auto_login_parser
diff --git a/chromium/components/auto_login_parser/auto_login_parser.h b/chromium/components/auto_login_parser/auto_login_parser.h
deleted file mode 100644
index bd2f28f9996..00000000000
--- a/chromium/components/auto_login_parser/auto_login_parser.h
+++ /dev/null
@@ -1,50 +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 COMPONENTS_AUTO_LOGIN_PARSER_AUTO_LOGIN_PARSER_H_
-#define COMPONENTS_AUTO_LOGIN_PARSER_AUTO_LOGIN_PARSER_H_
-
-#include <string>
-
-namespace net {
-class URLRequest;
-}
-
-namespace auto_login_parser {
-
-enum RealmRestriction {
- ONLY_GOOGLE_COM,
- ALLOW_ANY_REALM
-};
-
-struct HeaderData {
- HeaderData();
- ~HeaderData();
-
- // "realm" string from x-auto-login (e.g. "com.google").
- std::string realm;
-
- // "account" string from x-auto-login.
- std::string account;
-
- // "args" string from x-auto-login to be passed to MergeSession. This string
- // should be considered opaque and not be cracked open to look inside.
- std::string args;
-};
-
-// Returns whether parsing succeeded. Parameter |header_data| will not be
-// modified if parsing fails.
-bool ParseHeader(const std::string& header,
- RealmRestriction realm_restriction,
- HeaderData* header_data);
-
-// Helper function that also retrieves the header from the response of the
-// given URLRequest.
-bool ParserHeaderInResponse(net::URLRequest* request,
- RealmRestriction realm_restriction,
- HeaderData* header_data);
-
-} // namespace auto_login_parser
-
-#endif // COMPONENTS_AUTO_LOGIN_PARSER_AUTO_LOGIN_PARSER_H_
diff --git a/chromium/components/auto_login_parser/auto_login_parser_unittest.cc b/chromium/components/auto_login_parser/auto_login_parser_unittest.cc
deleted file mode 100644
index 442784c734f..00000000000
--- a/chromium/components/auto_login_parser/auto_login_parser_unittest.cc
+++ /dev/null
@@ -1,92 +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 "components/auto_login_parser/auto_login_parser.h"
-
-#include <string>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace auto_login_parser {
-
-class AutoLoginParserTest : public testing::Test {
- protected:
- static bool IsHeaderDataEmpty(const HeaderData& header) {
- return header.realm.empty() && header.account.empty() &&
- header.args.empty();
- }
-};
-
-TEST_F(AutoLoginParserTest, ParseHeader) {
- std::string header =
- "realm=com.google&"
- "account=fred.example%40gmail.com&"
- "args=kfdshfwoeriudslkfsdjfhdskjfhsdkr";
-
- HeaderData header_data;
- EXPECT_TRUE(ParseHeader(header, ONLY_GOOGLE_COM, &header_data));
-
- ASSERT_EQ("com.google", header_data.realm);
- ASSERT_EQ("fred.example@gmail.com", header_data.account);
- ASSERT_EQ("kfdshfwoeriudslkfsdjfhdskjfhsdkr", header_data.args);
-}
-
-TEST_F(AutoLoginParserTest, ParseHeaderOnlySupportsComGoogle) {
- std::string header =
- "realm=com.microsoft&"
- "account=fred.example%40gmail.com&"
- "args=kfdshfwoeriudslkfsdjfhdskjfhsdkr";
-
- HeaderData header_data;
- EXPECT_FALSE(ParseHeader(header, ONLY_GOOGLE_COM, &header_data));
- // |header| should not be touched when parsing fails.
- EXPECT_TRUE(IsHeaderDataEmpty(header_data));
-}
-
-TEST_F(AutoLoginParserTest, ParseHeaderWithMissingRealm) {
- std::string header =
- "account=fred.example%40gmail.com&"
- "args=kfdshfwoeriudslkfsdjfhdskjfhsdkr";
-
- HeaderData header_data;
- EXPECT_FALSE(ParseHeader(header, ONLY_GOOGLE_COM, &header_data));
- EXPECT_TRUE(IsHeaderDataEmpty(header_data));
-}
-
-TEST_F(AutoLoginParserTest, ParseHeaderWithMissingArgs) {
- std::string header =
- "realm=com.google&"
- "account=fred.example%40gmail.com&";
-
- HeaderData header_data;
- EXPECT_FALSE(ParseHeader(header, ONLY_GOOGLE_COM, &header_data));
- EXPECT_TRUE(IsHeaderDataEmpty(header_data));
-}
-
-TEST_F(AutoLoginParserTest, ParseHeaderWithoutOptionalAccount) {
- std::string header =
- "realm=com.google&"
- "args=kfdshfwoeriudslkfsdjfhdskjfhsdkr";
-
- HeaderData header_data;
- EXPECT_TRUE(ParseHeader(header, ONLY_GOOGLE_COM, &header_data));
- ASSERT_EQ("com.google", header_data.realm);
- ASSERT_EQ("kfdshfwoeriudslkfsdjfhdskjfhsdkr", header_data.args);
-}
-
-TEST_F(AutoLoginParserTest, ParseHeaderAllowsAnyRealmWithOption) {
- std::string header =
- "realm=com.microsoft&"
- "account=fred.example%40gmail.com&"
- "args=kfdshfwoeriudslkfsdjfhdskjfhsdkr";
-
- HeaderData header_data;
- EXPECT_TRUE(ParseHeader(header, ALLOW_ANY_REALM, &header_data));
-
- ASSERT_EQ("com.microsoft", header_data.realm);
- ASSERT_EQ("fred.example@gmail.com", header_data.account);
- ASSERT_EQ("kfdshfwoeriudslkfsdjfhdskjfhsdkr", header_data.args);
-}
-
-} // namespace auto_login_parser
diff --git a/chromium/components/autofill.gypi b/chromium/components/autofill.gypi
deleted file mode 100644
index 50276063f53..00000000000
--- a/chromium/components/autofill.gypi
+++ /dev/null
@@ -1,639 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/autofill/core/common
- 'target_name': 'autofill_core_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'autofill/core/common/autofill_constants.cc',
- 'autofill/core/common/autofill_constants.h',
- 'autofill/core/common/autofill_data_validation.cc',
- 'autofill/core/common/autofill_data_validation.h',
- 'autofill/core/common/autofill_l10n_util.cc',
- 'autofill/core/common/autofill_l10n_util.h',
- 'autofill/core/common/autofill_pref_names.cc',
- 'autofill/core/common/autofill_pref_names.h',
- 'autofill/core/common/autofill_regexes.cc',
- 'autofill/core/common/autofill_regexes.h',
- 'autofill/core/common/autofill_switches.cc',
- 'autofill/core/common/autofill_switches.h',
- 'autofill/core/common/autofill_util.cc',
- 'autofill/core/common/autofill_util.h',
- 'autofill/core/common/form_data.cc',
- 'autofill/core/common/form_data.h',
- 'autofill/core/common/form_data_predictions.cc',
- 'autofill/core/common/form_data_predictions.h',
- 'autofill/core/common/form_field_data.cc',
- 'autofill/core/common/form_field_data.h',
- 'autofill/core/common/form_field_data_predictions.cc',
- 'autofill/core/common/form_field_data_predictions.h',
- 'autofill/core/common/password_form.cc',
- 'autofill/core/common/password_form.h',
- 'autofill/core/common/password_form_field_prediction_map.h',
- 'autofill/core/common/password_form_fill_data.cc',
- 'autofill/core/common/password_form_fill_data.h',
- 'autofill/core/common/password_form_generation_data.h',
- 'autofill/core/common/password_generation_util.cc',
- 'autofill/core/common/password_generation_util.h',
- 'autofill/core/common/save_password_progress_logger.cc',
- 'autofill/core/common/save_password_progress_logger.h',
- ],
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
-
- {
- # GN version: //components/autofill/core/browser
- 'target_name': 'autofill_core_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../sql/sql.gyp:sql',
- '../sync/sync.gyp:sync',
- '../third_party/fips181/fips181.gyp:fips181',
- '../third_party/icu/icu.gyp:icui18n',
- '../third_party/icu/icu.gyp:icuuc',
- '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_util',
- '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber',
- '../third_party/re2/re2.gyp:re2',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/gfx.gyp:gfx_geometry',
- '../ui/gfx/gfx.gyp:gfx_range',
- '../ui/gfx/gfx.gyp:gfx_vector_icons',
- '../url/url.gyp:url_lib',
- 'autofill_core_common',
- 'autofill_server_proto',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- 'data_use_measurement_core',
- 'infobars_core',
- 'keyed_service_core',
- 'os_crypt',
- 'pref_registry',
- 'prefs/prefs.gyp:prefs',
- 'rappor',
- 'signin_core_browser',
- 'signin_core_common',
- 'sync_driver',
- 'variations_net',
- 'webdata_common',
- ],
- 'sources': [
- 'autofill/core/browser/address.cc',
- 'autofill/core/browser/address.h',
- 'autofill/core/browser/address_field.cc',
- 'autofill/core/browser/address_field.h',
- 'autofill/core/browser/address_i18n.cc',
- 'autofill/core/browser/address_i18n.h',
- 'autofill/core/browser/address_rewriter.cc',
- 'autofill/core/browser/address_rewriter.h',
- 'autofill/core/browser/address_rewriter_rules.cc',
- 'autofill/core/browser/autocomplete_history_manager.cc',
- 'autofill/core/browser/autocomplete_history_manager.h',
- 'autofill/core/browser/autofill-inl.h',
- 'autofill/core/browser/autofill_client.h',
- 'autofill/core/browser/autofill_country.cc',
- 'autofill/core/browser/autofill_country.h',
- 'autofill/core/browser/autofill_data_model.cc',
- 'autofill/core/browser/autofill_data_model.h',
- 'autofill/core/browser/autofill_data_util.cc',
- 'autofill/core/browser/autofill_data_util.h',
- 'autofill/core/browser/autofill_download_manager.cc',
- 'autofill/core/browser/autofill_download_manager.h',
- 'autofill/core/browser/autofill_driver.h',
- 'autofill/core/browser/autofill_experiments.cc',
- 'autofill/core/browser/autofill_experiments.h',
- 'autofill/core/browser/autofill_external_delegate.cc',
- 'autofill/core/browser/autofill_external_delegate.h',
- 'autofill/core/browser/autofill_field.cc',
- 'autofill/core/browser/autofill_field.h',
- 'autofill/core/browser/autofill_ie_toolbar_import_win.cc',
- 'autofill/core/browser/autofill_ie_toolbar_import_win.h',
- 'autofill/core/browser/autofill_manager.cc',
- 'autofill/core/browser/autofill_manager.h',
- 'autofill/core/browser/autofill_manager_test_delegate.h',
- 'autofill/core/browser/autofill_metrics.cc',
- 'autofill/core/browser/autofill_metrics.h',
- 'autofill/core/browser/autofill_popup_delegate.h',
- 'autofill/core/browser/autofill_profile.cc',
- 'autofill/core/browser/autofill_profile.h',
- 'autofill/core/browser/autofill_profile_comparator.cc',
- 'autofill/core/browser/autofill_profile_comparator.h',
- 'autofill/core/browser/autofill_regex_constants.cc',
- 'autofill/core/browser/autofill_regex_constants.h',
- 'autofill/core/browser/autofill_scanner.cc',
- 'autofill/core/browser/autofill_scanner.h',
- 'autofill/core/browser/autofill_sync_constants.cc',
- 'autofill/core/browser/autofill_sync_constants.h',
- 'autofill/core/browser/autofill_type.cc',
- 'autofill/core/browser/autofill_type.h',
- 'autofill/core/browser/autofill_wallet_data_type_controller.cc',
- 'autofill/core/browser/autofill_wallet_data_type_controller.h',
- 'autofill/core/browser/card_unmask_delegate.cc',
- 'autofill/core/browser/card_unmask_delegate.h',
- 'autofill/core/browser/contact_info.cc',
- 'autofill/core/browser/contact_info.h',
- 'autofill/core/browser/country_data.cc',
- 'autofill/core/browser/country_data.h',
- 'autofill/core/browser/country_names.cc',
- 'autofill/core/browser/country_names.h',
- 'autofill/core/browser/credit_card.cc',
- 'autofill/core/browser/credit_card.h',
- 'autofill/core/browser/credit_card_field.cc',
- 'autofill/core/browser/credit_card_field.h',
- 'autofill/core/browser/detail_input.cc',
- 'autofill/core/browser/detail_input.h',
- 'autofill/core/browser/dialog_section.h',
- 'autofill/core/browser/email_field.cc',
- 'autofill/core/browser/email_field.h',
- 'autofill/core/browser/field_candidates.h',
- 'autofill/core/browser/field_candidates.cc',
- 'autofill/core/browser/field_types.h',
- 'autofill/core/browser/form_field.cc',
- 'autofill/core/browser/form_field.h',
- 'autofill/core/browser/form_group.cc',
- 'autofill/core/browser/form_group.h',
- 'autofill/core/browser/form_structure.cc',
- 'autofill/core/browser/form_structure.h',
- 'autofill/core/browser/legal_message_line.cc',
- 'autofill/core/browser/legal_message_line.h',
- 'autofill/core/browser/name_field.cc',
- 'autofill/core/browser/name_field.h',
- 'autofill/core/browser/password_generator.cc',
- 'autofill/core/browser/password_generator.h',
- 'autofill/core/browser/payments/full_card_request.cc',
- 'autofill/core/browser/payments/full_card_request.h',
- 'autofill/core/browser/payments/payments_client.cc',
- 'autofill/core/browser/payments/payments_client.h',
- 'autofill/core/browser/payments/payments_request.h',
- 'autofill/core/browser/payments/payments_service_url.cc',
- 'autofill/core/browser/payments/payments_service_url.h',
- 'autofill/core/browser/personal_data_manager.cc',
- 'autofill/core/browser/personal_data_manager.h',
- 'autofill/core/browser/personal_data_manager_observer.h',
- 'autofill/core/browser/phone_field.cc',
- 'autofill/core/browser/phone_field.h',
- 'autofill/core/browser/phone_number.cc',
- 'autofill/core/browser/phone_number.h',
- 'autofill/core/browser/phone_number_i18n.cc',
- 'autofill/core/browser/phone_number_i18n.h',
- 'autofill/core/browser/popup_item_ids.h',
- 'autofill/core/browser/server_field_types_util.cc',
- 'autofill/core/browser/server_field_types_util.h',
- 'autofill/core/browser/state_names.cc',
- 'autofill/core/browser/state_names.h',
- 'autofill/core/browser/suggestion.cc',
- 'autofill/core/browser/suggestion.h',
- 'autofill/core/browser/ui/card_unmask_prompt_controller.h',
- 'autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc',
- 'autofill/core/browser/ui/card_unmask_prompt_controller_impl.h',
- 'autofill/core/browser/ui/card_unmask_prompt_view.h',
- 'autofill/core/browser/validation.cc',
- 'autofill/core/browser/validation.h',
- 'autofill/core/browser/webdata/autocomplete_syncable_service.cc',
- 'autofill/core/browser/webdata/autocomplete_syncable_service.h',
- 'autofill/core/browser/webdata/autofill_change.cc',
- 'autofill/core/browser/webdata/autofill_change.h',
- 'autofill/core/browser/webdata/autofill_data_type_controller.cc',
- 'autofill/core/browser/webdata/autofill_data_type_controller.h',
- 'autofill/core/browser/webdata/autofill_entry.cc',
- 'autofill/core/browser/webdata/autofill_entry.h',
- 'autofill/core/browser/webdata/autofill_profile_data_type_controller.cc',
- 'autofill/core/browser/webdata/autofill_profile_data_type_controller.h',
- 'autofill/core/browser/webdata/autofill_profile_syncable_service.cc',
- 'autofill/core/browser/webdata/autofill_profile_syncable_service.h',
- 'autofill/core/browser/webdata/autofill_table.cc',
- 'autofill/core/browser/webdata/autofill_table.h',
- 'autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc',
- 'autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h',
- 'autofill/core/browser/webdata/autofill_wallet_syncable_service.cc',
- 'autofill/core/browser/webdata/autofill_wallet_syncable_service.h',
- 'autofill/core/browser/webdata/autofill_webdata.h',
- 'autofill/core/browser/webdata/autofill_webdata_backend.h',
- 'autofill/core/browser/webdata/autofill_webdata_backend_impl.cc',
- 'autofill/core/browser/webdata/autofill_webdata_backend_impl.h',
- 'autofill/core/browser/webdata/autofill_webdata_service.cc',
- 'autofill/core/browser/webdata/autofill_webdata_service.h',
- 'autofill/core/browser/webdata/autofill_webdata_service_observer.h',
- ],
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
-
- # This is needed because GYP's handling of transitive dependencies is
- # not great. See https://goo.gl/QGtlae for details.
- 'export_dependent_settings': [
- 'autofill_server_proto',
- ],
-
- 'conditions': [
- ['OS=="ios"', {
- 'sources': [
- 'autofill/core/browser/autofill_field_trial_ios.cc',
- 'autofill/core/browser/autofill_field_trial_ios.h',
- 'autofill/core/browser/keyboard_accessory_metrics_logger.h',
- 'autofill/core/browser/keyboard_accessory_metrics_logger.mm',
- ],
- }],
- ['OS=="ios" or OS=="android"', {
- 'sources': [
- 'autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc',
- 'autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h',
- 'autofill/core/browser/autofill_save_card_infobar_mobile.h',
- ],
- }]
- ],
- },
-
- {
- # Protobuf compiler / generate rule for Autofill's server proto.
- # GN version: //components/autofill/core/browser/proto
- 'target_name': 'autofill_server_proto',
- 'type': 'static_library',
- 'sources': [
- 'autofill/core/browser/proto/server.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'autofill/core/browser/proto',
- 'proto_out_dir': 'components/autofill/core/browser/proto',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
-
- {
- # GN version: //components/autofill/core/browser:test_support
- 'target_name': 'autofill_core_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../skia/skia.gyp:skia',
- '../testing/gtest.gyp:gtest',
- 'autofill_core_common',
- 'autofill_core_browser',
- 'os_crypt',
- 'pref_registry',
- 'prefs/prefs.gyp:prefs',
- 'rappor',
- 'signin_core_browser_test_support',
- ],
- 'sources': [
- 'autofill/core/browser/autofill_test_utils.cc',
- 'autofill/core/browser/autofill_test_utils.h',
- 'autofill/core/browser/data_driven_test.cc',
- 'autofill/core/browser/data_driven_test.h',
- 'autofill/core/browser/suggestion_test_helpers.h',
- 'autofill/core/browser/test_autofill_client.cc',
- 'autofill/core/browser/test_autofill_client.h',
- 'autofill/core/browser/test_autofill_driver.cc',
- 'autofill/core/browser/test_autofill_driver.h',
- 'autofill/core/browser/test_autofill_external_delegate.cc',
- 'autofill/core/browser/test_autofill_external_delegate.h',
- 'autofill/core/browser/test_personal_data_manager.cc',
- 'autofill/core/browser/test_personal_data_manager.h',
- ],
- },
- ],
- 'conditions': [
- ['OS != "ios"', {
- 'targets': [
- {
- # GN version: //components/autofill/content/public/interfaces:types
- 'target_name': 'autofill_content_types_mojo_bindings_mojom',
- 'type': 'none',
- 'variables': {
- 'mojom_files': [
- 'autofill/content/public/interfaces/autofill_types.mojom',
- ],
- 'mojom_typemaps': [
- 'autofill/content/public/cpp/autofill_types.typemap',
- '<(DEPTH)/url/mojo/gurl.typemap',
- ],
- },
- 'includes': [ '../mojo/mojom_bindings_generator_explicit.gypi' ],
- 'dependencies': [
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
- ],
- },
- {
- # GN version: //components/autofill/content/public/interfaces:types
- 'target_name': 'autofill_content_types_mojo_bindings',
- 'type': 'static_library',
- 'sources': [
- 'autofill/content/public/cpp/autofill_types_struct_traits.cc'
- ],
- 'export_dependent_settings': [
- '../url/url.gyp:url_mojom',
- ],
- 'dependencies': [
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
- '../url/url.gyp:url_mojom',
- 'autofill_content_types_mojo_bindings_mojom',
- ],
- },
- {
- # GN version: //components/autofill/content/public/interfaces:test_types
- 'target_name': 'autofill_content_test_types_mojo_bindings',
- 'type': 'static_library',
- 'variables': {
- 'mojom_typemaps': [
- 'autofill/content/public/cpp/autofill_types.typemap',
- '<(DEPTH)/url/mojo/gurl.typemap',
- ],
- },
- 'sources': [
- 'autofill/content/public/interfaces/test_autofill_types.mojom',
- ],
- 'export_dependent_settings': [
- '../url/url.gyp:url_mojom',
- 'autofill_content_types_mojo_bindings',
- ],
- 'dependencies': [
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
- '../url/url.gyp:url_mojom',
- 'autofill_content_types_mojo_bindings',
- ],
- 'includes': [ '../mojo/mojom_bindings_generator.gypi' ],
- },
- {
- # GN version: //components/autofill/content/public/interfaces
- 'target_name': 'autofill_content_mojo_bindings_mojom',
- 'type': 'none',
- 'variables': {
- 'mojom_files': [
- 'autofill/content/public/interfaces/autofill_agent.mojom',
- 'autofill/content/public/interfaces/autofill_driver.mojom',
- ],
- 'mojom_typemaps': [
- 'autofill/content/public/cpp/autofill_types.typemap',
- ],
- },
- 'include_dirs': [
- '..',
- ],
- 'includes': [
- '../mojo/mojom_bindings_generator_explicit.gypi',
- ],
- },
- {
- # GN version: //components/autofill/content/public/interfaces
- 'target_name': 'autofill_content_mojo_bindings',
- 'type': 'static_library',
- 'export_dependent_settings': [
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
- ],
- 'dependencies': [
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
- 'autofill_content_mojo_bindings_mojom',
- 'autofill_content_types_mojo_bindings',
- ],
- },
- {
- # GN version: //content/autofill/content/common
- 'target_name': 'autofill_content_common',
- 'type': 'static_library',
- 'dependencies': [
- 'autofill_core_common',
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../ipc/ipc.gyp:ipc',
- '../third_party/WebKit/public/blink.gyp:blink_minimal',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/ipc/geometry/gfx_ipc_geometry.gyp:gfx_ipc_geometry',
- '../ui/gfx/ipc/gfx_ipc.gyp:gfx_ipc',
- '../ui/gfx/ipc/skia/gfx_ipc_skia.gyp:gfx_ipc_skia',
- '../url/url.gyp:url_lib',
- '../url/ipc/url_ipc.gyp:url_ipc',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'autofill/content/common/autofill_message_generator.cc',
- 'autofill/content/common/autofill_message_generator.h',
- 'autofill/content/common/autofill_messages.h',
- 'autofill/content/common/autofill_param_traits_macros.h',
- ],
- },
-
- {
- # Protobuf compiler / generate rule for Autofill's risk integration.
- # GN version: //components/autofill/content/browser:risk_proto
- 'target_name': 'autofill_content_risk_proto',
- 'type': 'static_library',
- 'sources': [
- 'autofill/content/browser/risk/proto/fingerprint.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'autofill/content/browser/risk/proto',
- 'proto_out_dir': 'components/autofill/content/browser/risk/proto',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
- {
- # GN version: //components/autofill/content/renderer:test_support
- 'target_name': 'autofill_content_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'autofill_content_browser',
- 'autofill_content_renderer',
- '../base/base.gyp:base',
- '../ipc/ipc.gyp:ipc',
- '../skia/skia.gyp:skia',
- '../testing/gmock.gyp:gmock',
- ],
- 'sources': [
- 'autofill/content/renderer/test_password_autofill_agent.cc',
- 'autofill/content/renderer/test_password_autofill_agent.h',
- 'autofill/content/renderer/test_password_generation_agent.cc',
- 'autofill/content/renderer/test_password_generation_agent.h',
- ],
- 'include_dirs': [ '..' ],
- },
- {
- # GN version: //components/autofill/content/browser
- 'target_name': 'autofill_content_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../google_apis/google_apis.gyp:google_apis',
- '../ipc/ipc.gyp:ipc',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../sql/sql.gyp:sql',
- '../third_party/icu/icu.gyp:icui18n',
- '../third_party/icu/icu.gyp:icuuc',
- '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/display/display.gyp:display',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/gfx.gyp:gfx_geometry',
- '../url/url.gyp:url_lib',
- 'autofill_content_common',
- 'autofill_content_mojo_bindings',
- 'autofill_content_risk_proto',
- 'autofill_core_browser',
- 'autofill_core_common',
- 'autofill_server_proto',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- 'os_crypt',
- 'prefs/prefs.gyp:prefs',
- 'user_prefs',
- 'webdata_common',
- ],
- 'sources': [
- 'autofill/content/browser/content_autofill_driver.cc',
- 'autofill/content/browser/content_autofill_driver.h',
- 'autofill/content/browser/content_autofill_driver_factory.cc',
- 'autofill/content/browser/content_autofill_driver_factory.h',
- 'autofill/content/browser/risk/fingerprint.cc',
- 'autofill/content/browser/risk/fingerprint.h',
- ],
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- # This is needed because GYP's handling of transitive dependencies is
- # not great. See https://goo.gl/QGtlae for details.
- 'export_dependent_settings': [
- 'autofill_server_proto',
- ],
- },
-
- {
- # GN version: //components/autofill/content/renderer
- 'target_name': 'autofill_content_renderer',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../content/content.gyp:content_renderer',
- '../google_apis/google_apis.gyp:google_apis',
- '../ipc/ipc.gyp:ipc',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../third_party/re2/re2.gyp:re2',
- '../third_party/WebKit/public/blink.gyp:blink',
- '../ui/base/ui_base.gyp:ui_base',
- 'autofill_content_common',
- 'autofill_content_mojo_bindings',
- 'autofill_core_common',
- 'components_strings.gyp:components_strings',
- ],
- 'sources': [
- 'autofill/content/renderer/autofill_agent.cc',
- 'autofill/content/renderer/autofill_agent.h',
- 'autofill/content/renderer/form_autofill_util.cc',
- 'autofill/content/renderer/form_autofill_util.h',
- 'autofill/content/renderer/form_cache.cc',
- 'autofill/content/renderer/form_cache.h',
- 'autofill/content/renderer/form_classifier.cc',
- 'autofill/content/renderer/form_classifier.h',
- 'autofill/content/renderer/page_click_listener.h',
- 'autofill/content/renderer/page_click_tracker.cc',
- 'autofill/content/renderer/page_click_tracker.h',
- 'autofill/content/renderer/password_autofill_agent.cc',
- 'autofill/content/renderer/password_autofill_agent.h',
- 'autofill/content/renderer/password_form_conversion_utils.cc',
- 'autofill/content/renderer/password_form_conversion_utils.h',
- 'autofill/content/renderer/password_generation_agent.cc',
- 'autofill/content/renderer/password_generation_agent.h',
- 'autofill/content/renderer/renderer_save_password_progress_logger.cc',
- 'autofill/content/renderer/renderer_save_password_progress_logger.h',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- ],
- }],
- ['OS == "ios"', {
- 'targets': [
- {
- # GN version: //components/autofill/ios/browser
- 'target_name': 'autofill_ios_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'autofill_core_browser',
- 'autofill_core_common',
- 'autofill_ios_injected_js',
- 'autofill_server_proto',
- '../ios/provider/ios_provider_web.gyp:ios_provider_web',
- '../ios/web/ios_web.gyp:ios_web',
- ],
- 'sources': [
- 'autofill/ios/browser/autofill_client_ios_bridge.h',
- 'autofill/ios/browser/autofill_driver_ios.h',
- 'autofill/ios/browser/autofill_driver_ios.mm',
- 'autofill/ios/browser/autofill_driver_ios_bridge.h',
- 'autofill/ios/browser/credit_card_util.h',
- 'autofill/ios/browser/credit_card_util.mm',
- 'autofill/ios/browser/form_suggestion.h',
- 'autofill/ios/browser/form_suggestion.mm',
- 'autofill/ios/browser/js_autofill_manager.h',
- 'autofill/ios/browser/js_autofill_manager.mm',
- 'autofill/ios/browser/js_suggestion_manager.h',
- 'autofill/ios/browser/js_suggestion_manager.mm',
- 'autofill/ios/browser/personal_data_manager_observer_bridge.h',
- 'autofill/ios/browser/personal_data_manager_observer_bridge.mm',
- ],
- # This is needed because GYP's handling of transitive dependencies is
- # not great. See https://goo.gl/QGtlae for details.
- 'export_dependent_settings': [
- 'autofill_server_proto',
- ],
- },
- {
- # GN version: //components/autofill/ios/browser:injected_js
- 'target_name': 'autofill_ios_injected_js',
- 'type': 'none',
- 'sources': [
- 'autofill/ios/browser/resources/autofill_controller.js',
- 'autofill/ios/browser/resources/suggestion_controller.js',
- ],
- 'link_settings': {
- 'mac_bundle_resources': [
- '<(SHARED_INTERMEDIATE_DIR)/autofill_controller.js',
- '<(SHARED_INTERMEDIATE_DIR)/suggestion_controller.js',
- ],
- },
- 'includes': [
- '../ios/web/js_compile_checked.gypi',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/autofill/android/BUILD.gn b/chromium/components/autofill/android/BUILD.gn
new file mode 100644
index 00000000000..54889a8605d
--- /dev/null
+++ b/chromium/components/autofill/android/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+android_resources("autofill_java_resources") {
+ custom_package = "org.chromium.components.autofill"
+ resource_dirs = [ "java/res" ]
+}
+
+android_library("autofill_java") {
+ deps = [
+ ":autofill_java_resources",
+ "//base:base_java",
+ "//ui/android:ui_java",
+ ]
+ java_files = [
+ "java/src/org/chromium/components/autofill/AutofillDelegate.java",
+ "java/src/org/chromium/components/autofill/AutofillKeyboardAccessory.java",
+ "java/src/org/chromium/components/autofill/AutofillPopup.java",
+ "java/src/org/chromium/components/autofill/AutofillSuggestion.java",
+ ]
+}
diff --git a/chromium/components/autofill/android/OWNERS b/chromium/components/autofill/android/OWNERS
new file mode 100644
index 00000000000..fcd1c786a25
--- /dev/null
+++ b/chromium/components/autofill/android/OWNERS
@@ -0,0 +1 @@
+file://ui/android/OWNERS
diff --git a/chromium/components/autofill/android/java/res/drawable/autofill_chip_inset.xml b/chromium/components/autofill/android/java/res/drawable/autofill_chip_inset.xml
new file mode 100644
index 00000000000..9a44f7a5b6c
--- /dev/null
+++ b/chromium/components/autofill/android/java/res/drawable/autofill_chip_inset.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetBottom="@dimen/keyboard_accessory_padding"
+ android:insetLeft="@dimen/keyboard_accessory_half_padding"
+ android:insetRight="@dimen/keyboard_accessory_half_padding"
+ android:insetTop="@dimen/keyboard_accessory_padding">
+ <shape>
+ <solid android:color="#ECEFF1" />
+ <corners android:radius="2dp" />
+ </shape>
+</inset>
diff --git a/chromium/components/autofill/android/java/res/layout/autofill_keyboard_accessory_icon.xml b/chromium/components/autofill/android/java/res/layout/autofill_keyboard_accessory_icon.xml
new file mode 100644
index 00000000000..d06e90d23e4
--- /dev/null
+++ b/chromium/components/autofill/android/java/res/layout/autofill_keyboard_accessory_icon.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_height="@dimen/keyboard_accessory_height"
+ android:layout_width="40dp"
+ android:background="@drawable/autofill_chip_inset"
+ android:padding="12dp"
+ tools:ignore="contentDescription" />
+
diff --git a/chromium/components/autofill/android/java/res/layout/autofill_keyboard_accessory_item.xml b/chromium/components/autofill/android/java/res/layout/autofill_keyboard_accessory_item.xml
new file mode 100644
index 00000000000..dd508f28901
--- /dev/null
+++ b/chromium/components/autofill/android/java/res/layout/autofill_keyboard_accessory_item.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="@dimen/keyboard_accessory_height"
+ android:layout_width="wrap_content"
+ android:background="@drawable/autofill_chip_inset"
+ android:paddingEnd="@dimen/keyboard_accessory_padding"
+ android:paddingStart="@dimen/keyboard_accessory_padding">
+
+ <TextView
+ android:id="@+id/autofill_keyboard_accessory_item_label"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:drawablePadding="@dimen/keyboard_accessory_half_padding"
+ android:ellipsize="end"
+ android:fontFamily="sans-serif-medium"
+ android:gravity="center_vertical"
+ android:minWidth="@dimen/keyboard_accessory_chip_height"
+ android:paddingEnd="@dimen/keyboard_accessory_half_padding"
+ android:paddingStart="@dimen/keyboard_accessory_half_padding"
+ android:singleLine="true"
+ android:textColor="#333"
+ android:textSize="@dimen/keyboard_accessory_text_size" />
+
+ <TextView
+ android:id="@+id/autofill_keyboard_accessory_item_sublabel"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:ellipsize="end"
+ android:gravity="center_vertical"
+ android:paddingEnd="@dimen/keyboard_accessory_half_padding"
+ android:singleLine="true"
+ android:textColor="#646464"
+ android:textSize="@dimen/keyboard_accessory_text_size"
+ android:visibility="gone" />
+
+</LinearLayout>
diff --git a/chromium/components/autofill/android/java/res/values/dimens.xml b/chromium/components/autofill/android/java/res/values/dimens.xml
new file mode 100644
index 00000000000..ee949e47a0f
--- /dev/null
+++ b/chromium/components/autofill/android/java/res/values/dimens.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+ <!--
+ Fallback values if the corresponding com.android.internal.R dimensions
+ cannot be retrieved by name.
+ Note: Constants taken directly from Android's core/res/values/config.xml.
+ -->
+ <dimen name="keyboard_accessory_chip_height">32dp</dimen>
+ <dimen name="keyboard_accessory_half_padding">4dp</dimen>
+ <dimen name="keyboard_accessory_height">48dp</dimen>
+ <dimen name="keyboard_accessory_padding">8dp</dimen>
+ <dimen name="keyboard_accessory_text_size">14sp</dimen>
+</resources>
diff --git a/chromium/components/autofill/content/DEPS b/chromium/components/autofill/content/DEPS
index c3b3bb154c5..bfb7fc18c23 100644
--- a/chromium/components/autofill/content/DEPS
+++ b/chromium/components/autofill/content/DEPS
@@ -3,7 +3,7 @@ include_rules = [
# Allow inclusion of WebKit API files.
"+third_party/WebKit/public/platform",
"+third_party/WebKit/public/web",
- "+ipc",
+ "+mojo/common",
"+mojo/public",
"+services/shell/public/cpp",
]
diff --git a/chromium/components/autofill/content/browser/BUILD.gn b/chromium/components/autofill/content/browser/BUILD.gn
index b2bec8c925b..3b9290e1e6e 100644
--- a/chromium/components/autofill/content/browser/BUILD.gn
+++ b/chromium/components/autofill/content/browser/BUILD.gn
@@ -4,7 +4,6 @@
import("//third_party/protobuf/proto_library.gni")
-# GYP version: components/autofill.gypi:autofill_content_browser
static_library("browser") {
sources = [
"content_autofill_driver.cc",
@@ -17,15 +16,14 @@ static_library("browser") {
public_deps = [
":risk_proto",
+ "//components/autofill/content/public/interfaces",
+ "//components/autofill/core/browser",
+ "//components/autofill/core/common",
"//skia",
]
deps = [
"//base",
"//base:i18n",
- "//components/autofill/content/common",
- "//components/autofill/content/public/interfaces",
- "//components/autofill/core/browser",
- "//components/autofill/core/common",
"//components/os_crypt",
"//components/prefs",
"//components/resources",
@@ -34,9 +32,10 @@ static_library("browser") {
"//components/webdata/common",
"//content/public/browser",
"//content/public/common",
+ "//device/geolocation",
"//google_apis",
"//gpu/config",
- "//ipc",
+ "//mojo/common:common_base",
"//net",
"//services/shell/public/cpp",
"//sql",
@@ -67,7 +66,7 @@ source_set("unit_tests") {
deps = [
":browser",
"//base",
- "//components/autofill/content/common",
+ "//components/autofill/content/public/interfaces",
"//components/autofill/core/browser",
"//components/autofill/core/browser:test_support",
"//components/autofill/core/common",
@@ -76,9 +75,10 @@ source_set("unit_tests") {
"//content/test:test_support",
"//google_apis",
"//google_apis:test_support",
- "//ipc:test_support",
+ "//mojo/common:common_base",
"//net",
"//net:test_support",
+ "//services/shell/public/cpp",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/components/autofill/content/browser/DEPS b/chromium/components/autofill/content/browser/DEPS
index 58131085a11..b9cba252646 100644
--- a/chromium/components/autofill/content/browser/DEPS
+++ b/chromium/components/autofill/content/browser/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+components/webdata/common",
"+content/public/browser",
"+crypto/random.h",
+ "+device/geolocation",
"+google_apis/gaia",
"+google_apis/google_api_keys.h",
"+gpu/config/gpu_info.h",
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc
index 8d091cdcb0e..2821197efa4 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc
@@ -8,7 +8,7 @@
#include "base/command_line.h"
#include "base/threading/sequenced_worker_pool.h"
-#include "components/autofill/content/common/autofill_messages.h"
+#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_manager.h"
@@ -23,7 +23,7 @@
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/storage_partition.h"
-#include "ipc/ipc_message_macros.h"
+#include "content/public/browser/web_contents.h"
#include "services/shell/public/cpp/interface_provider.h"
#include "ui/gfx/geometry/size_f.h"
@@ -40,14 +40,24 @@ ContentAutofillDriver::ContentAutofillDriver(
client,
app_locale,
enable_download_manager)),
- autofill_external_delegate_(autofill_manager_.get(), this) {
+ autofill_external_delegate_(autofill_manager_.get(), this),
+ binding_(this) {
autofill_manager_->SetExternalDelegate(&autofill_external_delegate_);
}
ContentAutofillDriver::~ContentAutofillDriver() {}
+// static
+ContentAutofillDriver* ContentAutofillDriver::GetForRenderFrameHost(
+ content::RenderFrameHost* render_frame_host) {
+ ContentAutofillDriverFactory* factory =
+ ContentAutofillDriverFactory::FromWebContents(
+ content::WebContents::FromRenderFrameHost(render_frame_host));
+ return factory ? factory->DriverForFrame(render_frame_host) : nullptr;
+}
+
void ContentAutofillDriver::BindRequest(mojom::AutofillDriverRequest request) {
- bindings_.AddBinding(this, std::move(request));
+ binding_.Bind(std::move(request));
}
bool ContentAutofillDriver::IsOffTheRecord() const {
@@ -76,14 +86,13 @@ void ContentAutofillDriver::SendFormDataToRenderer(
const FormData& data) {
if (!RendererIsAvailable())
return;
+
switch (action) {
case FORM_DATA_ACTION_FILL:
- render_frame_host_->Send(new AutofillMsg_FillForm(
- render_frame_host_->GetRoutingID(), query_id, data));
+ GetAutofillAgent()->FillForm(query_id, data);
break;
case FORM_DATA_ACTION_PREVIEW:
- render_frame_host_->Send(new AutofillMsg_PreviewForm(
- render_frame_host_->GetRoutingID(), query_id, data));
+ GetAutofillAgent()->PreviewForm(query_id, data);
break;
}
}
@@ -105,46 +114,40 @@ void ContentAutofillDriver::SendAutofillTypePredictionsToRenderer(
std::vector<FormDataPredictions> type_predictions =
FormStructure::GetFieldTypePredictions(forms);
- render_frame_host_->Send(new AutofillMsg_FieldTypePredictionsAvailable(
- render_frame_host_->GetRoutingID(), type_predictions));
+ GetAutofillAgent()->FieldTypePredictionsAvailable(type_predictions);
}
void ContentAutofillDriver::RendererShouldAcceptDataListSuggestion(
const base::string16& value) {
if (!RendererIsAvailable())
return;
- render_frame_host_->Send(new AutofillMsg_AcceptDataListSuggestion(
- render_frame_host_->GetRoutingID(), value));
+ GetAutofillAgent()->AcceptDataListSuggestion(value);
}
void ContentAutofillDriver::RendererShouldClearFilledForm() {
if (!RendererIsAvailable())
return;
- render_frame_host_->Send(
- new AutofillMsg_ClearForm(render_frame_host_->GetRoutingID()));
+ GetAutofillAgent()->ClearForm();
}
void ContentAutofillDriver::RendererShouldClearPreviewedForm() {
if (!RendererIsAvailable())
return;
- render_frame_host_->Send(
- new AutofillMsg_ClearPreviewedForm(render_frame_host_->GetRoutingID()));
+ GetAutofillAgent()->ClearPreviewedForm();
}
void ContentAutofillDriver::RendererShouldFillFieldWithValue(
const base::string16& value) {
if (!RendererIsAvailable())
return;
- render_frame_host_->Send(new AutofillMsg_FillFieldWithValue(
- render_frame_host_->GetRoutingID(), value));
+ GetAutofillAgent()->FillFieldWithValue(value);
}
void ContentAutofillDriver::RendererShouldPreviewFieldWithValue(
const base::string16& value) {
if (!RendererIsAvailable())
return;
- render_frame_host_->Send(new AutofillMsg_PreviewFieldWithValue(
- render_frame_host_->GetRoutingID(), value));
+ GetAutofillAgent()->PreviewFieldWithValue(value);
}
void ContentAutofillDriver::PopupHidden() {
@@ -172,47 +175,63 @@ void ContentAutofillDriver::FirstUserGestureObserved() {
client_->OnFirstUserGestureObserved();
}
-bool ContentAutofillDriver::HandleMessage(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(ContentAutofillDriver, message)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_FormsSeen,
- autofill_manager_.get(),
- AutofillManager::OnFormsSeen)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_WillSubmitForm, autofill_manager_.get(),
- AutofillManager::OnWillSubmitForm)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_FormSubmitted,
- autofill_manager_.get(),
- AutofillManager::OnFormSubmitted)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_TextFieldDidChange,
- autofill_manager_.get(),
- AutofillManager::OnTextFieldDidChange)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_FocusNoLongerOnForm,
- autofill_manager_.get(),
- AutofillManager::OnFocusNoLongerOnForm)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_QueryFormFieldAutofill,
- autofill_manager_.get(),
- AutofillManager::OnQueryFormFieldAutofill)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_DidPreviewAutofillFormData,
- autofill_manager_.get(),
- AutofillManager::OnDidPreviewAutofillFormData)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_PingAck,
- &autofill_external_delegate_,
- AutofillExternalDelegate::OnPingAck)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_DidFillAutofillFormData,
- autofill_manager_.get(),
- AutofillManager::OnDidFillAutofillFormData)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_DidEndTextFieldEditing,
- autofill_manager_.get(),
- AutofillManager::OnDidEndTextFieldEditing)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_HidePopup,
- autofill_manager_.get(),
- AutofillManager::OnHidePopup)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_SetDataList,
- autofill_manager_.get(),
- AutofillManager::OnSetDataList)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
+void ContentAutofillDriver::FormsSeen(const std::vector<FormData>& forms,
+ base::TimeTicks timestamp) {
+ autofill_manager_->OnFormsSeen(forms, timestamp);
+}
+
+void ContentAutofillDriver::WillSubmitForm(const FormData& form,
+ base::TimeTicks timestamp) {
+ autofill_manager_->OnWillSubmitForm(form, timestamp);
+}
+
+void ContentAutofillDriver::FormSubmitted(const FormData& form) {
+ autofill_manager_->OnFormSubmitted(form);
+}
+
+void ContentAutofillDriver::TextFieldDidChange(const FormData& form,
+ const FormFieldData& field,
+ base::TimeTicks timestamp) {
+ autofill_manager_->OnTextFieldDidChange(form, field, timestamp);
+}
+
+void ContentAutofillDriver::QueryFormFieldAutofill(
+ int32_t id,
+ const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box) {
+ autofill_manager_->OnQueryFormFieldAutofill(id, form, field, bounding_box);
+}
+
+void ContentAutofillDriver::HidePopup() {
+ autofill_manager_->OnHidePopup();
+}
+
+void ContentAutofillDriver::PingAck() {
+ autofill_external_delegate_.OnPingAck();
+}
+
+void ContentAutofillDriver::FocusNoLongerOnForm() {
+ autofill_manager_->OnFocusNoLongerOnForm();
+}
+
+void ContentAutofillDriver::DidFillAutofillFormData(const FormData& form,
+ base::TimeTicks timestamp) {
+ autofill_manager_->OnDidFillAutofillFormData(form, timestamp);
+}
+
+void ContentAutofillDriver::DidPreviewAutofillFormData() {
+ autofill_manager_->OnDidPreviewAutofillFormData();
+}
+
+void ContentAutofillDriver::DidEndTextFieldEditing() {
+ autofill_manager_->OnDidEndTextFieldEditing();
+}
+
+void ContentAutofillDriver::SetDataList(
+ const std::vector<base::string16>& values,
+ const std::vector<base::string16>& labels) {
+ autofill_manager_->OnSetDataList(values, labels);
}
void ContentAutofillDriver::DidNavigateFrame(
@@ -229,16 +248,17 @@ void ContentAutofillDriver::SetAutofillManager(
}
void ContentAutofillDriver::NotifyFirstUserGestureObservedInTab() {
- ConnectToMojoAutofillAgentIfNeeded();
- mojo_autofill_agent_->FirstUserGestureObservedInTab();
+ GetAutofillAgent()->FirstUserGestureObservedInTab();
}
-void ContentAutofillDriver::ConnectToMojoAutofillAgentIfNeeded() {
- if (mojo_autofill_agent_)
- return;
+const mojom::AutofillAgentPtr& ContentAutofillDriver::GetAutofillAgent() {
+ // Here is a lazy binding, and will not reconnect after connection error.
+ if (!autofill_agent_) {
+ render_frame_host_->GetRemoteInterfaces()->GetInterface(
+ mojo::GetProxy(&autofill_agent_));
+ }
- render_frame_host_->GetRemoteInterfaces()->GetInterface(
- &mojo_autofill_agent_);
+ return autofill_agent_;
}
} // namespace autofill
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h
index 2a2a9f113f0..0c914977ba5 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.h
@@ -14,7 +14,7 @@
#include "components/autofill/core/browser/autofill_driver.h"
#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_manager.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/binding.h"
namespace content {
class BrowserContext;
@@ -23,10 +23,6 @@ struct FrameNavigateParams;
struct LoadCommittedDetails;
}
-namespace IPC {
-class Message;
-}
-
namespace autofill {
class AutofillClient;
@@ -44,6 +40,10 @@ class ContentAutofillDriver : public AutofillDriver,
AutofillManager::AutofillDownloadManagerState enable_download_manager);
~ContentAutofillDriver() override;
+ // Gets the driver for |render_frame_host|.
+ static ContentAutofillDriver* GetForRenderFrameHost(
+ content::RenderFrameHost* render_frame_host);
+
void BindRequest(mojom::AutofillDriverRequest request);
// AutofillDriver:
@@ -71,9 +71,26 @@ class ContentAutofillDriver : public AutofillDriver,
// mojom::AutofillDriver:
void FirstUserGestureObserved() override;
-
- // Handles a message that came from the associated render frame.
- bool HandleMessage(const IPC::Message& message);
+ void FormsSeen(const std::vector<FormData>& forms,
+ base::TimeTicks timestamp) override;
+ void WillSubmitForm(const FormData& form, base::TimeTicks timestamp) override;
+ void FormSubmitted(const FormData& form) override;
+ void TextFieldDidChange(const FormData& form,
+ const FormFieldData& field,
+ base::TimeTicks timestamp) override;
+ void QueryFormFieldAutofill(int32_t id,
+ const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box) override;
+ void HidePopup() override;
+ void PingAck() override;
+ void FocusNoLongerOnForm() override;
+ void DidFillAutofillFormData(const FormData& form,
+ base::TimeTicks timestamp) override;
+ void DidPreviewAutofillFormData() override;
+ void DidEndTextFieldEditing() override;
+ void SetDataList(const std::vector<base::string16>& values,
+ const std::vector<base::string16>& labels) override;
// Called when the frame has navigated.
void DidNavigateFrame(const content::LoadCommittedDetails& details,
@@ -90,14 +107,14 @@ class ContentAutofillDriver : public AutofillDriver,
AutofillManager* autofill_manager() { return autofill_manager_.get(); }
content::RenderFrameHost* render_frame_host() { return render_frame_host_; }
+ const mojom::AutofillAgentPtr& GetAutofillAgent();
+
protected:
// Sets the manager to |manager| and sets |manager|'s external delegate
// to |autofill_external_delegate_|. Takes ownership of |manager|.
void SetAutofillManager(std::unique_ptr<AutofillManager> manager);
private:
- void ConnectToMojoAutofillAgentIfNeeded();
-
// Weak ref to the RenderFrameHost the driver is associated with. Should
// always be non-NULL and valid for lifetime of |this|.
content::RenderFrameHost* const render_frame_host_;
@@ -113,9 +130,9 @@ class ContentAutofillDriver : public AutofillDriver,
// case where the Autofill native UI is enabled.
AutofillExternalDelegate autofill_external_delegate_;
- mojo::BindingSet<mojom::AutofillDriver> bindings_;
+ mojo::Binding<mojom::AutofillDriver> binding_;
- mojom::AutofillAgentPtr mojo_autofill_agent_;
+ mojom::AutofillAgentPtr autofill_agent_;
};
} // namespace autofill
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
index 3e614dcb94a..32465df8fa4 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -16,7 +16,6 @@
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
-#include "ipc/ipc_message_macros.h"
namespace autofill {
@@ -95,20 +94,14 @@ ContentAutofillDriver* ContentAutofillDriverFactory::DriverForFrame(
return mapping == frame_driver_map_.end() ? nullptr : mapping->second.get();
}
-bool ContentAutofillDriverFactory::OnMessageReceived(
- const IPC::Message& message,
- content::RenderFrameHost* render_frame_host) {
- return frame_driver_map_[render_frame_host]->HandleMessage(message);
-}
-
void ContentAutofillDriverFactory::RenderFrameCreated(
content::RenderFrameHost* render_frame_host) {
auto insertion_result =
frame_driver_map_.insert(std::make_pair(render_frame_host, nullptr));
// This is called twice for the main frame.
if (insertion_result.second) { // This was the first time.
- insertion_result.first->second = base::WrapUnique(new ContentAutofillDriver(
- render_frame_host, client_, app_locale_, enable_download_manager_));
+ insertion_result.first->second = base::MakeUnique<ContentAutofillDriver>(
+ render_frame_host, client_, app_locale_, enable_download_manager_);
}
}
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory.h b/chromium/components/autofill/content/browser/content_autofill_driver_factory.h
index f2a233e72e2..d121269fb8d 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_factory.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory.h
@@ -18,10 +18,6 @@ namespace content {
class RenderFrameHost;
}
-namespace IPC {
-class Message;
-}
-
namespace autofill {
class AutofillDriver;
@@ -50,8 +46,6 @@ class ContentAutofillDriverFactory : public content::WebContentsObserver,
content::RenderFrameHost* render_frame_host);
// content::WebContentsObserver:
- bool OnMessageReceived(const IPC::Message& message,
- content::RenderFrameHost* render_frame_host) override;
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
void DidNavigateAnyFrame(
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
index bc88e12f2ad..2b85105ff7f 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -8,13 +8,12 @@
#include <algorithm>
#include <memory>
-#include <tuple>
#include <utility>
#include <vector>
#include "base/command_line.h"
+#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/content/common/autofill_messages.h"
#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
@@ -26,9 +25,9 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/frame_navigate_params.h"
-#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_renderer_host.h"
-#include "ipc/ipc_test_sink.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/shell/public/cpp/interface_provider.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -40,6 +39,190 @@ const char kAppLocale[] = "en-US";
const AutofillManager::AutofillDownloadManagerState kDownloadState =
AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER;
+class FakeAutofillAgent : public mojom::AutofillAgent {
+ public:
+ FakeAutofillAgent()
+ : fill_form_id_(-1),
+ preview_form_id_(-1),
+ called_clear_form_(false),
+ called_clear_previewed_form_(false) {}
+
+ ~FakeAutofillAgent() override {}
+
+ void BindRequest(mojo::ScopedMessagePipeHandle handle) {
+ bindings_.AddBinding(
+ this, mojo::MakeRequest<mojom::AutofillAgent>(std::move(handle)));
+ }
+
+ void SetQuitLoopClosure(base::Closure closure) { quit_closure_ = closure; }
+
+ // Returns the id and formdata received via
+ // mojo interface method mojom::AutofillAgent::FillForm().
+ bool GetAutofillFillFormMessage(int* page_id, FormData* results) {
+ if (fill_form_id_ == -1)
+ return false;
+ if (!fill_form_form_)
+ return false;
+
+ if (page_id)
+ *page_id = fill_form_id_;
+ if (results)
+ *results = *fill_form_form_;
+ return true;
+ }
+
+ // Returns the id and formdata received via
+ // mojo interface method mojom::AutofillAgent::PreviewForm().
+ bool GetAutofillPreviewFormMessage(int* page_id, FormData* results) {
+ if (preview_form_id_ == -1)
+ return false;
+ if (!preview_form_form_)
+ return false;
+
+ if (page_id)
+ *page_id = preview_form_id_;
+ if (results)
+ *results = *preview_form_form_;
+ return true;
+ }
+
+ // Returns data received via mojo interface method
+ // mojom::AutofillAent::FieldTypePredictionsAvailable().
+ bool GetFieldTypePredictionsAvailable(
+ std::vector<FormDataPredictions>* predictions) {
+ if (!predictions_)
+ return false;
+ if (predictions)
+ *predictions = *predictions_;
+ return true;
+ }
+
+ // Returns whether mojo interface method mojom::AutofillAgent::ClearForm() got
+ // called.
+ bool GetCalledClearForm() { return called_clear_form_; }
+
+ // Returns whether mojo interface method
+ // mojom::AutofillAgent::ClearPreviewedForm() got called.
+ bool GetCalledClearPreviewedForm() { return called_clear_previewed_form_; }
+
+ // Returns data received via mojo interface method
+ // mojom::AutofillAent::FillFieldWithValue().
+ bool GetString16FillFieldWithValue(base::string16* value) {
+ if (!value_fill_field_)
+ return false;
+ if (value)
+ *value = *value_fill_field_;
+ return true;
+ }
+
+ // Returns data received via mojo interface method
+ // mojom::AutofillAent::PreviewFieldWithValue().
+ bool GetString16PreviewFieldWithValue(base::string16* value) {
+ if (!value_preview_field_)
+ return false;
+ if (value)
+ *value = *value_preview_field_;
+ return true;
+ }
+
+ // Returns data received via mojo interface method
+ // mojom::AutofillAent::AcceptDataListSuggestion().
+ bool GetString16AcceptDataListSuggestion(base::string16* value) {
+ if (!value_accept_data_)
+ return false;
+ if (value)
+ *value = *value_accept_data_;
+ return true;
+ }
+
+ private:
+ void CallDone() {
+ if (!quit_closure_.is_null()) {
+ quit_closure_.Run();
+ quit_closure_.Reset();
+ }
+ }
+
+ // mojom::AutofillAgent methods:
+ void FirstUserGestureObservedInTab() override {}
+
+ void FillForm(int32_t id, const FormData& form) override {
+ fill_form_id_ = id;
+ fill_form_form_ = form;
+ CallDone();
+ }
+
+ void PreviewForm(int32_t id, const FormData& form) override {
+ preview_form_id_ = id;
+ preview_form_form_ = form;
+ CallDone();
+ }
+
+ void FieldTypePredictionsAvailable(
+ const std::vector<FormDataPredictions>& forms) override {
+ predictions_ = forms;
+ CallDone();
+ }
+
+ void ClearForm() override {
+ called_clear_form_ = true;
+ CallDone();
+ }
+
+ void ClearPreviewedForm() override {
+ called_clear_previewed_form_ = true;
+ CallDone();
+ }
+
+ void FillFieldWithValue(const base::string16& value) override {
+ value_fill_field_ = value;
+ CallDone();
+ }
+
+ void PreviewFieldWithValue(const base::string16& value) override {
+ value_preview_field_ = value;
+ CallDone();
+ }
+
+ void AcceptDataListSuggestion(const base::string16& value) override {
+ value_accept_data_ = value;
+ CallDone();
+ }
+
+ void FillPasswordSuggestion(const base::string16& username,
+ const base::string16& password) override {}
+
+ void PreviewPasswordSuggestion(const base::string16& username,
+ const base::string16& password) override {}
+
+ void ShowInitialPasswordAccountSuggestions(
+ int32_t key,
+ const PasswordFormFillData& form_data) override {}
+
+ mojo::BindingSet<mojom::AutofillAgent> bindings_;
+
+ base::Closure quit_closure_;
+
+ // Records data received from FillForm() call.
+ int32_t fill_form_id_;
+ base::Optional<FormData> fill_form_form_;
+ // Records data received from PreviewForm() call.
+ int32_t preview_form_id_;
+ base::Optional<FormData> preview_form_form_;
+ // Records data received from FieldTypePredictionsAvailable() call.
+ base::Optional<std::vector<FormDataPredictions>> predictions_;
+ // Records whether ClearForm() got called.
+ bool called_clear_form_;
+ // Records whether ClearPreviewedForm() got called.
+ bool called_clear_previewed_form_;
+ // Records string received from FillFieldWithValue() call.
+ base::Optional<base::string16> value_fill_field_;
+ // Records string received from PreviewFieldWithValue() call.
+ base::Optional<base::string16> value_preview_field_;
+ // Records string received from AcceptDataListSuggestion() call.
+ base::Optional<base::string16> value_accept_data_;
+};
+
} // namespace
class MockAutofillManager : public AutofillManager {
@@ -77,6 +260,13 @@ class ContentAutofillDriverTest : public content::RenderViewHostTestHarness {
test_autofill_client_.reset(new TestAutofillClient());
driver_.reset(new TestContentAutofillDriver(web_contents()->GetMainFrame(),
test_autofill_client_.get()));
+
+ shell::InterfaceProvider* remote_interfaces =
+ web_contents()->GetMainFrame()->GetRemoteInterfaces();
+ shell::InterfaceProvider::TestApi test_api(remote_interfaces);
+ test_api.SetBinderForName(mojom::AutofillAgent::Name_,
+ base::Bind(&FakeAutofillAgent::BindRequest,
+ base::Unretained(&fake_agent_)));
}
void TearDown() override {
@@ -87,118 +277,10 @@ class ContentAutofillDriverTest : public content::RenderViewHostTestHarness {
}
protected:
- // Searches for an |AutofillMsg_FillForm| message in the queue of sent IPC
- // messages. If none is present, returns false. Otherwise, extracts the first
- // |AutofillMsg_FillForm| message, fills the output parameters with the values
- // of the message's parameters, and clears the queue of sent messages.
- bool GetAutofillFillFormMessage(int* page_id, FormData* results) {
- const uint32_t kMsgID = AutofillMsg_FillForm::ID;
- const IPC::Message* message =
- process()->sink().GetFirstMessageMatching(kMsgID);
- if (!message)
- return false;
- std::tuple<int, FormData> autofill_param;
- if (!AutofillMsg_FillForm::Read(message, &autofill_param))
- return false;
- if (page_id)
- *page_id = std::get<0>(autofill_param);
- if (results)
- *results = std::get<1>(autofill_param);
- process()->sink().ClearMessages();
- return true;
- }
-
- // Searches for an |AutofillMsg_PreviewForm| message in the queue of sent IPC
- // messages. If none is present, returns false. Otherwise, extracts the first
- // |AutofillMsg_PreviewForm| message, fills the output parameters with the
- // values of the message's parameters, and clears the queue of sent messages.
- bool GetAutofillPreviewFormMessage(int* page_id, FormData* results) {
- const uint32_t kMsgID = AutofillMsg_PreviewForm::ID;
- const IPC::Message* message =
- process()->sink().GetFirstMessageMatching(kMsgID);
- if (!message)
- return false;
- std::tuple<int, FormData> autofill_param;
- if (!AutofillMsg_PreviewForm::Read(message, &autofill_param))
- return false;
- if (page_id)
- *page_id = std::get<0>(autofill_param);
- if (results)
- *results = std::get<1>(autofill_param);
- process()->sink().ClearMessages();
- return true;
- }
-
- // Searches for an |AutofillMsg_FieldTypePredictionsAvailable| message in the
- // queue of sent IPC messages. If none is present, returns false. Otherwise,
- // extracts the first |AutofillMsg_FieldTypePredictionsAvailable| message,
- // fills the output parameter with the values of the message's parameter, and
- // clears the queue of sent messages.
- bool GetFieldTypePredictionsAvailable(
- std::vector<FormDataPredictions>* predictions) {
- const uint32_t kMsgID = AutofillMsg_FieldTypePredictionsAvailable::ID;
- const IPC::Message* message =
- process()->sink().GetFirstMessageMatching(kMsgID);
- if (!message)
- return false;
- std::tuple<std::vector<FormDataPredictions> > autofill_param;
- if (!AutofillMsg_FieldTypePredictionsAvailable::Read(message,
- &autofill_param))
- return false;
- if (predictions)
- *predictions = std::get<0>(autofill_param);
-
- process()->sink().ClearMessages();
- return true;
- }
-
- // Searches for a message matching |messageID| in the queue of sent IPC
- // messages. If none is present, returns false. Otherwise, extracts the first
- // matching message, fills the output parameter with the string16 from the
- // message's parameter, and clears the queue of sent messages.
- bool GetString16FromMessageWithID(uint32_t messageID, base::string16* value) {
- const IPC::Message* message =
- process()->sink().GetFirstMessageMatching(messageID);
- if (!message)
- return false;
- std::tuple<base::string16> autofill_param;
- switch (messageID) {
- case AutofillMsg_FillFieldWithValue::ID:
- if (!AutofillMsg_FillFieldWithValue::Read(message, &autofill_param))
- return false;
- break;
- case AutofillMsg_PreviewFieldWithValue::ID:
- if (!AutofillMsg_PreviewFieldWithValue::Read(message, &autofill_param))
- return false;
- break;
- case AutofillMsg_AcceptDataListSuggestion::ID:
- if (!AutofillMsg_AcceptDataListSuggestion::Read(message,
- &autofill_param))
- return false;
- break;
- default:
- NOTREACHED();
- }
- if (value)
- *value = std::get<0>(autofill_param);
- process()->sink().ClearMessages();
- return true;
- }
-
- // Searches for a message matching |messageID| in the queue of sent IPC
- // messages. If none is present, returns false. Otherwise, clears the queue
- // of sent messages and returns true.
- bool HasMessageMatchingID(uint32_t messageID) {
- const IPC::Message* message =
- process()->sink().GetFirstMessageMatching(messageID);
- if (!message)
- return false;
- process()->sink().ClearMessages();
- return true;
- }
-
std::unique_ptr<TestAutofillClient> test_autofill_client_;
std::unique_ptr<TestContentAutofillDriver> driver_;
+
+ FakeAutofillAgent fake_agent_;
};
TEST_F(ContentAutofillDriverTest, GetURLRequestContext) {
@@ -233,14 +315,19 @@ TEST_F(ContentAutofillDriverTest, FormDataSentToRenderer_FillForm) {
int input_page_id = 42;
FormData input_form_data;
test::CreateTestAddressFormData(&input_form_data);
+ base::RunLoop run_loop;
+ fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver_->SendFormDataToRenderer(
input_page_id, AutofillDriver::FORM_DATA_ACTION_FILL, input_form_data);
+ run_loop.RunUntilIdle();
+
int output_page_id = 0;
FormData output_form_data;
- EXPECT_FALSE(
- GetAutofillPreviewFormMessage(&output_page_id, &output_form_data));
- EXPECT_TRUE(GetAutofillFillFormMessage(&output_page_id, &output_form_data));
+ EXPECT_FALSE(fake_agent_.GetAutofillPreviewFormMessage(&output_page_id,
+ &output_form_data));
+ EXPECT_TRUE(fake_agent_.GetAutofillFillFormMessage(&output_page_id,
+ &output_form_data));
EXPECT_EQ(input_page_id, output_page_id);
EXPECT_TRUE(input_form_data.SameFormAs(output_form_data));
}
@@ -249,14 +336,19 @@ TEST_F(ContentAutofillDriverTest, FormDataSentToRenderer_PreviewForm) {
int input_page_id = 42;
FormData input_form_data;
test::CreateTestAddressFormData(&input_form_data);
+ base::RunLoop run_loop;
+ fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver_->SendFormDataToRenderer(
input_page_id, AutofillDriver::FORM_DATA_ACTION_PREVIEW, input_form_data);
+ run_loop.RunUntilIdle();
+
int output_page_id = 0;
FormData output_form_data;
- EXPECT_FALSE(GetAutofillFillFormMessage(&output_page_id, &output_form_data));
- EXPECT_TRUE(
- GetAutofillPreviewFormMessage(&output_page_id, &output_form_data));
+ EXPECT_FALSE(fake_agent_.GetAutofillFillFormMessage(&output_page_id,
+ &output_form_data));
+ EXPECT_TRUE(fake_agent_.GetAutofillPreviewFormMessage(&output_page_id,
+ &output_form_data));
EXPECT_EQ(input_page_id, output_page_id);
EXPECT_TRUE(input_form_data.SameFormAs(output_form_data));
}
@@ -267,8 +359,13 @@ TEST_F(ContentAutofillDriverTest,
test::CreateTestAddressFormData(&form);
FormStructure form_structure(form);
std::vector<FormStructure*> forms(1, &form_structure);
+
+ base::RunLoop run_loop;
+ fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver_->SendAutofillTypePredictionsToRenderer(forms);
- EXPECT_FALSE(GetFieldTypePredictionsAvailable(NULL));
+ run_loop.RunUntilIdle();
+
+ EXPECT_FALSE(fake_agent_.GetFieldTypePredictionsAvailable(NULL));
}
TEST_F(ContentAutofillDriverTest, TypePredictionsSentToRendererWhenEnabled) {
@@ -281,49 +378,72 @@ TEST_F(ContentAutofillDriverTest, TypePredictionsSentToRendererWhenEnabled) {
std::vector<FormStructure*> forms(1, &form_structure);
std::vector<FormDataPredictions> expected_type_predictions =
FormStructure::GetFieldTypePredictions(forms);
+
+ base::RunLoop run_loop;
+ fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver_->SendAutofillTypePredictionsToRenderer(forms);
+ run_loop.RunUntilIdle();
std::vector<FormDataPredictions> output_type_predictions;
- EXPECT_TRUE(GetFieldTypePredictionsAvailable(&output_type_predictions));
+ EXPECT_TRUE(
+ fake_agent_.GetFieldTypePredictionsAvailable(&output_type_predictions));
EXPECT_EQ(expected_type_predictions, output_type_predictions);
}
TEST_F(ContentAutofillDriverTest, AcceptDataListSuggestion) {
base::string16 input_value(base::ASCIIToUTF16("barfoo"));
base::string16 output_value;
+
+ base::RunLoop run_loop;
+ fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver_->RendererShouldAcceptDataListSuggestion(input_value);
- EXPECT_TRUE(GetString16FromMessageWithID(
- AutofillMsg_AcceptDataListSuggestion::ID, &output_value));
+ run_loop.RunUntilIdle();
+
+ EXPECT_TRUE(fake_agent_.GetString16AcceptDataListSuggestion(&output_value));
EXPECT_EQ(input_value, output_value);
}
TEST_F(ContentAutofillDriverTest, ClearFilledFormSentToRenderer) {
+ base::RunLoop run_loop;
+ fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver_->RendererShouldClearFilledForm();
- EXPECT_TRUE(HasMessageMatchingID(AutofillMsg_ClearForm::ID));
+ run_loop.RunUntilIdle();
+
+ EXPECT_TRUE(fake_agent_.GetCalledClearForm());
}
TEST_F(ContentAutofillDriverTest, ClearPreviewedFormSentToRenderer) {
+ base::RunLoop run_loop;
+ fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver_->RendererShouldClearPreviewedForm();
- EXPECT_TRUE(HasMessageMatchingID(AutofillMsg_ClearPreviewedForm::ID));
+ run_loop.RunUntilIdle();
+
+ EXPECT_TRUE(fake_agent_.GetCalledClearPreviewedForm());
}
TEST_F(ContentAutofillDriverTest, FillFieldWithValue) {
base::string16 input_value(base::ASCIIToUTF16("barqux"));
base::string16 output_value;
+ base::RunLoop run_loop;
+ fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver_->RendererShouldFillFieldWithValue(input_value);
- EXPECT_TRUE(GetString16FromMessageWithID(AutofillMsg_FillFieldWithValue::ID,
- &output_value));
+ run_loop.RunUntilIdle();
+
+ EXPECT_TRUE(fake_agent_.GetString16FillFieldWithValue(&output_value));
EXPECT_EQ(input_value, output_value);
}
TEST_F(ContentAutofillDriverTest, PreviewFieldWithValue) {
base::string16 input_value(base::ASCIIToUTF16("barqux"));
base::string16 output_value;
+
+ base::RunLoop run_loop;
+ fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
driver_->RendererShouldPreviewFieldWithValue(input_value);
- EXPECT_TRUE(GetString16FromMessageWithID(
- AutofillMsg_PreviewFieldWithValue::ID,
- &output_value));
+ run_loop.RunUntilIdle();
+
+ EXPECT_TRUE(fake_agent_.GetString16PreviewFieldWithValue(&output_value));
EXPECT_EQ(input_value, output_value);
}
diff --git a/chromium/components/autofill/content/browser/payments/payments_client_unittest.cc b/chromium/components/autofill/content/browser/payments/payments_client_unittest.cc
index 055829e9a51..c825367b63b 100644
--- a/chromium/components/autofill/content/browser/payments/payments_client_unittest.cc
+++ b/chromium/components/autofill/content/browser/payments/payments_client_unittest.cc
@@ -3,9 +3,11 @@
// found in the LICENSE file.
#include <utility>
+#include <vector>
#include "base/command_line.h"
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
@@ -82,7 +84,7 @@ class PaymentsClientTest : public testing::Test, public PaymentsClientDelegate {
void StartGettingUploadDetails() {
token_service_->AddAccount("example@gmail.com");
identity_provider_->LogIn("example@gmail.com");
- client_->GetUploadDetails("language-LOCALE");
+ client_->GetUploadDetails(BuildTestProfiles(), "language-LOCALE");
}
void StartUploading() {
@@ -94,9 +96,14 @@ class PaymentsClientTest : public testing::Test, public PaymentsClientDelegate {
request_details.context_token = base::ASCIIToUTF16("context token");
request_details.risk_data = "some risk data";
request_details.app_locale = "language-LOCALE";
+ request_details.profiles = BuildTestProfiles();
client_->UploadCard(request_details);
}
+ const std::string& GetUploadData() {
+ return factory_.GetFetcherByID(0)->upload_data();
+ }
+
void IssueOAuthToken() {
token_service_->IssueAllTokensForAccount(
"example@gmail.com", "totally_real_token",
@@ -135,6 +142,40 @@ class PaymentsClientTest : public testing::Test, public PaymentsClientDelegate {
private:
DISALLOW_COPY_AND_ASSIGN(PaymentsClientTest);
+
+ std::vector<AutofillProfile> BuildTestProfiles() {
+ std::vector<AutofillProfile> profiles;
+ profiles.push_back(BuildProfile("John", "Smith", "1234 Main St.", "Miami",
+ "FL", "32006", "212-555-0162"));
+ profiles.push_back(BuildProfile("Pat", "Jones", "432 Oak Lane", "Lincoln",
+ "OH", "43005", "(834)555-0090"));
+ return profiles;
+ }
+
+ AutofillProfile BuildProfile(base::StringPiece first_name,
+ base::StringPiece last_name,
+ base::StringPiece address_line,
+ base::StringPiece city,
+ base::StringPiece state,
+ base::StringPiece zip,
+ base::StringPiece phone_number) {
+ AutofillProfile profile;
+
+ profile.SetInfo(AutofillType(NAME_FIRST), ASCIIToUTF16(first_name),
+ "en-US");
+ profile.SetInfo(AutofillType(NAME_LAST), ASCIIToUTF16(last_name), "en-US");
+ profile.SetInfo(AutofillType(ADDRESS_HOME_LINE1),
+ ASCIIToUTF16(address_line), "en-US");
+ profile.SetInfo(AutofillType(ADDRESS_HOME_CITY), ASCIIToUTF16(city),
+ "en-US");
+ profile.SetInfo(AutofillType(ADDRESS_HOME_STATE), ASCIIToUTF16(state),
+ "en-US");
+ profile.SetInfo(AutofillType(ADDRESS_HOME_ZIP), ASCIIToUTF16(zip), "en-US");
+ profile.SetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER),
+ ASCIIToUTF16(phone_number), "en-US");
+
+ return profile;
+ }
};
TEST_F(PaymentsClientTest, OAuthError) {
@@ -163,6 +204,29 @@ TEST_F(PaymentsClientTest, GetDetailsSuccess) {
EXPECT_NE(nullptr, legal_message_.get());
}
+TEST_F(PaymentsClientTest, GetDetailsRemovesNonLocationData) {
+ StartGettingUploadDetails();
+
+ // Verify that the recipient name field and test names appear nowhere in the
+ // upload data.
+ EXPECT_TRUE(GetUploadData().find(PaymentsClient::kRecipientName) ==
+ std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("John") == std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("Smith") == std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("Pat") == std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("Jones") == std::string::npos);
+
+ // Verify that the phone number field and test numbers appear nowhere in the
+ // upload data.
+ EXPECT_TRUE(GetUploadData().find(PaymentsClient::kPhoneNumber) ==
+ std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("212") == std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("555") == std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("0162") == std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("834") == std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("0090") == std::string::npos);
+}
+
TEST_F(PaymentsClientTest, UploadSuccess) {
StartUploading();
IssueOAuthToken();
@@ -170,6 +234,29 @@ TEST_F(PaymentsClientTest, UploadSuccess) {
EXPECT_EQ(AutofillClient::SUCCESS, result_);
}
+TEST_F(PaymentsClientTest, UploadIncludesNonLocationData) {
+ StartUploading();
+
+ // Verify that the recipient name field and test names do appear in the upload
+ // data.
+ EXPECT_TRUE(GetUploadData().find(PaymentsClient::kRecipientName) !=
+ std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("John") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("Smith") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("Pat") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("Jones") != std::string::npos);
+
+ // Verify that the phone number field and test numbers do appear in the upload
+ // data.
+ EXPECT_TRUE(GetUploadData().find(PaymentsClient::kPhoneNumber) !=
+ std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("212") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("555") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("0162") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("834") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("0090") != std::string::npos);
+}
+
TEST_F(PaymentsClientTest, GetDetailsFollowedByUploadSuccess) {
StartGettingUploadDetails();
ReturnResponse(
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint.cc b/chromium/components/autofill/content/browser/risk/fingerprint.cc
index 08ed54eb772..acac2f15ad8 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint.cc
@@ -30,24 +30,22 @@
#include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/font_list_async.h"
-#include "content/public/browser/geolocation_provider.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/geoposition.h"
+#include "content/public/common/screen_info.h"
#include "content/public/common/webplugininfo.h"
+#include "device/geolocation/geolocation_provider.h"
+#include "device/geolocation/geoposition.h"
#include "gpu/config/gpu_info.h"
#include "third_party/WebKit/public/platform/WebRect.h"
-#include "third_party/WebKit/public/platform/WebScreenInfo.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
-using blink::WebScreenInfo;
-
namespace autofill {
namespace risk {
@@ -66,7 +64,11 @@ base::TimeDelta GetTimezoneOffset() {
base::Time::Exploded local;
utc.LocalExplode(&local);
- return base::Time::FromUTCExploded(local) - utc;
+ base::Time out_time;
+ bool conversion_success = base::Time::FromUTCExploded(local, &out_time);
+ DCHECK(conversion_success);
+
+ return out_time - utc;
}
// Returns the concatenation of the operating system name and version, e.g.
@@ -125,7 +127,7 @@ void AddAcceptLanguagesToFingerprint(
// (d) the size of the screen unavailable to web page content,
// i.e. the Taskbar size on Windows
// into the |machine|.
-void AddScreenInfoToFingerprint(const WebScreenInfo& screen_info,
+void AddScreenInfoToFingerprint(const content::ScreenInfo& screen_info,
Fingerprint::MachineCharacteristics* machine) {
machine->set_screen_count(display::Screen::GetScreen()->GetNumDisplays());
@@ -137,7 +139,7 @@ void AddScreenInfoToFingerprint(const WebScreenInfo& screen_info,
machine->set_screen_color_depth(screen_info.depth);
const gfx::Rect screen_rect(screen_info.rect);
- const gfx::Rect available_rect(screen_info.availableRect);
+ const gfx::Rect available_rect(screen_info.available_rect);
const gfx::Rect unavailable_rect =
gfx::SubtractRects(screen_rect, available_rect);
machine->mutable_unavailable_screen_size()->set_width(
@@ -177,7 +179,7 @@ class FingerprintDataLoader : public content::GpuDataManagerObserver {
uint64_t obfuscated_gaia_id,
const gfx::Rect& window_bounds,
const gfx::Rect& content_bounds,
- const WebScreenInfo& screen_info,
+ const content::ScreenInfo& screen_info,
const std::string& version,
const std::string& charset,
const std::string& accept_languages,
@@ -196,7 +198,7 @@ class FingerprintDataLoader : public content::GpuDataManagerObserver {
// Callbacks for asynchronously loaded data.
void OnGotFonts(std::unique_ptr<base::ListValue> fonts);
void OnGotPlugins(const std::vector<content::WebPluginInfo>& plugins);
- void OnGotGeoposition(const content::Geoposition& geoposition);
+ void OnGotGeoposition(const device::Geoposition& geoposition);
// If all of the asynchronous data has been loaded, calls |callback_| with
// the fingerprint data.
@@ -218,7 +220,7 @@ class FingerprintDataLoader : public content::GpuDataManagerObserver {
const uint64_t obfuscated_gaia_id_;
const gfx::Rect window_bounds_;
const gfx::Rect content_bounds_;
- const WebScreenInfo screen_info_;
+ const content::ScreenInfo screen_info_;
const std::string version_;
const std::string charset_;
const std::string accept_languages_;
@@ -230,7 +232,7 @@ class FingerprintDataLoader : public content::GpuDataManagerObserver {
std::unique_ptr<base::ListValue> fonts_;
std::vector<content::WebPluginInfo> plugins_;
bool waiting_on_plugins_;
- content::Geoposition geoposition_;
+ device::Geoposition geoposition_;
// Timer to enforce a maximum timeout before the |callback_| is called, even
// if not all asynchronous data has been loaded.
@@ -240,7 +242,7 @@ class FingerprintDataLoader : public content::GpuDataManagerObserver {
base::Callback<void(std::unique_ptr<Fingerprint>)> callback_;
// The callback used as an "observer" of the GeolocationProvider.
- std::unique_ptr<content::GeolocationProvider::Subscription>
+ std::unique_ptr<device::GeolocationProvider::Subscription>
geolocation_subscription_;
// For invalidating asynchronous callbacks that might arrive after |this|
@@ -254,7 +256,7 @@ FingerprintDataLoader::FingerprintDataLoader(
uint64_t obfuscated_gaia_id,
const gfx::Rect& window_bounds,
const gfx::Rect& content_bounds,
- const WebScreenInfo& screen_info,
+ const content::ScreenInfo& screen_info,
const std::string& version,
const std::string& charset,
const std::string& accept_languages,
@@ -306,7 +308,7 @@ FingerprintDataLoader::FingerprintDataLoader(
weak_ptr_factory_.GetWeakPtr()));
// Load geolocation data.
- geolocation_subscription_ = content::GeolocationProvider::GetInstance()->
+ geolocation_subscription_ = device::GeolocationProvider::GetInstance()->
AddLocationUpdateCallback(
base::Bind(&FingerprintDataLoader::OnGotGeoposition,
weak_ptr_factory_.GetWeakPtr()),
@@ -336,12 +338,12 @@ void FingerprintDataLoader::OnGotPlugins(
}
void FingerprintDataLoader::OnGotGeoposition(
- const content::Geoposition& geoposition) {
+ const device::Geoposition& geoposition) {
DCHECK(!geoposition_.Validate());
geoposition_ = geoposition;
DCHECK(geoposition_.Validate() ||
- geoposition_.error_code != content::Geoposition::ERROR_CODE_NONE);
+ geoposition_.error_code != device::Geoposition::ERROR_CODE_NONE);
geolocation_subscription_.reset();
MaybeFillFingerprint();
@@ -356,7 +358,7 @@ void FingerprintDataLoader::MaybeFillFingerprint() {
fonts_ &&
!waiting_on_plugins_ &&
(geoposition_.Validate() ||
- geoposition_.error_code != content::Geoposition::ERROR_CODE_NONE))) {
+ geoposition_.error_code != device::Geoposition::ERROR_CODE_NONE))) {
FillFingerprint();
delete this;
}
@@ -406,7 +408,7 @@ void FingerprintDataLoader::FillFingerprint() {
// TODO(isherman): Record more user behavior data.
if (geoposition_.Validate() &&
- geoposition_.error_code == content::Geoposition::ERROR_CODE_NONE) {
+ geoposition_.error_code == device::Geoposition::ERROR_CODE_NONE) {
Fingerprint::UserCharacteristics::Location* location =
fingerprint->mutable_user_characteristics()->mutable_location();
location->set_altitude(geoposition_.altitude);
@@ -434,7 +436,7 @@ void GetFingerprintInternal(
uint64_t obfuscated_gaia_id,
const gfx::Rect& window_bounds,
const gfx::Rect& content_bounds,
- const blink::WebScreenInfo& screen_info,
+ const content::ScreenInfo& screen_info,
const std::string& version,
const std::string& charset,
const std::string& accept_languages,
@@ -466,11 +468,11 @@ void GetFingerprint(
const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback) {
gfx::Rect content_bounds = web_contents->GetContainerBounds();
- blink::WebScreenInfo screen_info;
+ content::ScreenInfo screen_info;
const content::RenderWidgetHostView* host_view =
web_contents->GetRenderWidgetHostView();
if (host_view)
- host_view->GetRenderWidgetHost()->GetWebScreenInfo(&screen_info);
+ host_view->GetRenderWidgetHost()->GetScreenInfo(&screen_info);
internal::GetFingerprintInternal(
obfuscated_gaia_id, window_bounds, content_bounds, screen_info, version,
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
index cc667d75701..302599f70cf 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
@@ -10,17 +10,18 @@
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "build/build_config.h"
#include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
-#include "content/public/browser/geolocation_provider.h"
#include "content/public/browser/gpu_data_manager.h"
-#include "content/public/common/geoposition.h"
+#include "content/public/common/screen_info.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/test_utils.h"
+#include "device/geolocation/geolocation_provider.h"
+#include "device/geolocation/geoposition.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebRect.h"
-#include "third_party/WebKit/public/platform/WebScreenInfo.h"
#include "ui/gfx/geometry/rect.h"
using testing::ElementsAre;
@@ -35,7 +36,7 @@ void GetFingerprintInternal(
uint64_t obfuscated_gaia_id,
const gfx::Rect& window_bounds,
const gfx::Rect& content_bounds,
- const blink::WebScreenInfo& screen_info,
+ const content::ScreenInfo& screen_info,
const std::string& version,
const std::string& charset,
const std::string& accept_languages,
@@ -186,7 +187,7 @@ class AutofillRiskFingerprintTest : public content::ContentBrowserTest {
// Test that getting a fingerprint works on some basic level.
IN_PROC_BROWSER_TEST_F(AutofillRiskFingerprintTest, GetFingerprint) {
- content::Geoposition position;
+ device::Geoposition position;
position.latitude = kLatitude;
position.longitude = kLongitude;
position.altitude = kAltitude;
@@ -194,13 +195,13 @@ IN_PROC_BROWSER_TEST_F(AutofillRiskFingerprintTest, GetFingerprint) {
position.timestamp =
base::Time::UnixEpoch() +
base::TimeDelta::FromMilliseconds(kGeolocationTime);
- content::GeolocationProvider::GetInstance()->OverrideLocationForTesting(
+ device::GeolocationProvider::GetInstance()->OverrideLocationForTesting(
position);
- blink::WebScreenInfo screen_info;
+ content::ScreenInfo screen_info;
screen_info.depth = kScreenColorDepth;
- screen_info.rect = blink::WebRect(screen_bounds_);
- screen_info.availableRect = blink::WebRect(available_screen_bounds_);
+ screen_info.rect = screen_bounds_;
+ screen_info.available_rect = available_screen_bounds_;
internal::GetFingerprintInternal(
kObfuscatedGaiaId, window_bounds_, content_bounds_, screen_info,
@@ -211,7 +212,7 @@ IN_PROC_BROWSER_TEST_F(AutofillRiskFingerprintTest, GetFingerprint) {
base::Unretained(this)));
// Wait for the callback to be called.
- message_loop_.Run();
+ base::RunLoop().Run();
}
} // namespace risk
diff --git a/chromium/components/autofill/content/common/BUILD.gn b/chromium/components/autofill/content/common/BUILD.gn
index 905fa2226af..fdd3bdeafe1 100644
--- a/chromium/components/autofill/content/common/BUILD.gn
+++ b/chromium/components/autofill/content/common/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components:autofill.gypi:autofill_content_common
static_library("common") {
sources = [
"autofill_message_generator.cc",
@@ -11,22 +10,15 @@ static_library("common") {
"autofill_param_traits_macros.h",
]
- public_deps = [
- # This is indirectly required by autofill_messages because it includes
- # some blink headers that include Skia.
- "//skia",
- ]
deps = [
"//base",
"//components/autofill/core/common",
"//content/public/common",
"//ipc",
- "//third_party/WebKit/public:blink_minimal",
"//ui/gfx",
"//ui/gfx/geometry",
"//ui/gfx/ipc",
"//ui/gfx/ipc/geometry",
- "//ui/gfx/ipc/skia",
"//url",
]
}
diff --git a/chromium/components/autofill/content/common/DEPS b/chromium/components/autofill/content/common/DEPS
index 86be8df50ef..c3505fa54c3 100644
--- a/chromium/components/autofill/content/common/DEPS
+++ b/chromium/components/autofill/content/common/DEPS
@@ -1,4 +1,4 @@
include_rules = [
"+content/public/common",
- "+third_party/WebKit/public/web",
+ "+ipc",
]
diff --git a/chromium/components/autofill/content/common/OWNERS b/chromium/components/autofill/content/common/OWNERS
index 9fbdf6f914e..25497bf408b 100644
--- a/chromium/components/autofill/content/common/OWNERS
+++ b/chromium/components/autofill/content/common/OWNERS
@@ -2,3 +2,5 @@
# new sandbox escapes.
per-file *_messages*.h=set noparent
per-file *_messages*.h=file://ipc/SECURITY_OWNERS
+per-file *_param_traits*.*=set noparent
+per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/autofill/content/common/autofill_messages.h b/chromium/components/autofill/content/common/autofill_messages.h
index e084879b288..704999171cb 100644
--- a/chromium/components/autofill/content/common/autofill_messages.h
+++ b/chromium/components/autofill/content/common/autofill_messages.h
@@ -8,24 +8,14 @@
#include <vector>
#include "base/strings/string16.h"
-#include "base/time/time.h"
#include "components/autofill/content/common/autofill_param_traits_macros.h"
-#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/form_data_predictions.h"
-#include "components/autofill/core/common/form_field_data.h"
-#include "components/autofill/core/common/form_field_data_predictions.h"
#include "components/autofill/core/common/password_form.h"
-#include "components/autofill/core/common/password_form_field_prediction_map.h"
-#include "components/autofill/core/common/password_form_fill_data.h"
-#include "components/autofill/core/common/password_form_generation_data.h"
#include "content/public/common/common_param_traits.h"
#include "content/public/common/common_param_traits_macros.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/ipc/gfx_param_traits.h"
-#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h"
-#include "url/gurl.h"
#define IPC_MESSAGE_START AutofillMsgStart
@@ -35,10 +25,6 @@ IPC_ENUM_TRAITS_MAX_VALUE(autofill::FormFieldData::CheckStatus,
IPC_ENUM_TRAITS_MAX_VALUE(autofill::FormFieldData::RoleAttribute,
autofill::FormFieldData::ROLE_ATTRIBUTE_OTHER)
-IPC_ENUM_TRAITS_MAX_VALUE(
- autofill::PasswordFormFieldPredictionType,
- autofill::PasswordFormFieldPredictionType::PREDICTION_MAX)
-
IPC_ENUM_TRAITS_MAX_VALUE(base::i18n::TextDirection,
base::i18n::TEXT_DIRECTION_NUM_DIRECTIONS - 1)
@@ -58,250 +44,10 @@ IPC_STRUCT_TRAITS_BEGIN(autofill::FormFieldData)
IPC_STRUCT_TRAITS_MEMBER(text_direction)
IPC_STRUCT_TRAITS_MEMBER(option_values)
IPC_STRUCT_TRAITS_MEMBER(option_contents)
+ IPC_STRUCT_TRAITS_MEMBER(css_classes)
+ IPC_STRUCT_TRAITS_MEMBER(properties_mask)
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_TRAITS_BEGIN(autofill::FormFieldDataPredictions)
- IPC_STRUCT_TRAITS_MEMBER(field)
- IPC_STRUCT_TRAITS_MEMBER(signature)
- IPC_STRUCT_TRAITS_MEMBER(heuristic_type)
- IPC_STRUCT_TRAITS_MEMBER(server_type)
- IPC_STRUCT_TRAITS_MEMBER(overall_type)
- IPC_STRUCT_TRAITS_MEMBER(parseable_name)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(autofill::FormDataPredictions)
- IPC_STRUCT_TRAITS_MEMBER(data)
- IPC_STRUCT_TRAITS_MEMBER(signature)
- IPC_STRUCT_TRAITS_MEMBER(fields)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(autofill::PasswordFormGenerationData)
- IPC_STRUCT_TRAITS_MEMBER(name)
- IPC_STRUCT_TRAITS_MEMBER(action)
- IPC_STRUCT_TRAITS_MEMBER(generation_field)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(autofill::UsernamesCollectionKey)
- IPC_STRUCT_TRAITS_MEMBER(username)
- IPC_STRUCT_TRAITS_MEMBER(password)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(autofill::PasswordFormFillData)
- IPC_STRUCT_TRAITS_MEMBER(name)
- IPC_STRUCT_TRAITS_MEMBER(origin)
- IPC_STRUCT_TRAITS_MEMBER(action)
- IPC_STRUCT_TRAITS_MEMBER(username_field)
- IPC_STRUCT_TRAITS_MEMBER(password_field)
- IPC_STRUCT_TRAITS_MEMBER(preferred_realm)
- IPC_STRUCT_TRAITS_MEMBER(additional_logins)
- IPC_STRUCT_TRAITS_MEMBER(other_possible_usernames)
- IPC_STRUCT_TRAITS_MEMBER(wait_for_username)
- IPC_STRUCT_TRAITS_MEMBER(is_possible_change_password_form)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(autofill::PasswordAndRealm)
- IPC_STRUCT_TRAITS_MEMBER(password)
- IPC_STRUCT_TRAITS_MEMBER(realm)
-IPC_STRUCT_TRAITS_END()
-
-// Singly-included section for type definitions.
-#ifndef COMPONENTS_AUTOFILL_CONTENT_COMMON_AUTOFILL_MESSAGES_H_
-#define COMPONENTS_AUTOFILL_CONTENT_COMMON_AUTOFILL_MESSAGES_H_
-
-// IPC_MESSAGE macros fail on the std::map, when expanding. We need to define
-// a type to avoid that.
-using FormsPredictionsMap =
- std::map<autofill::FormData, autofill::PasswordFormFieldPredictionMap>;
-
-#endif // COMPONENTS_AUTOFILL_CONTENT_COMMON_AUTOFILL_MESSAGES_H_
-
-// Autofill messages sent from the browser to the renderer.
-
-// Instructs the renderer to fill the active form with the given form data.
-IPC_MESSAGE_ROUTED2(AutofillMsg_FillForm,
- int /* query_id */,
- autofill::FormData /* form */)
-
-// Instructs the renderer to preview the active form with the given form data.
-IPC_MESSAGE_ROUTED2(AutofillMsg_PreviewForm,
- int /* query_id */,
- autofill::FormData /* form */)
-
-// Fill a password form and prepare field autocomplete for multiple
-// matching logins. Lets the renderer know if it should disable the popup
-// because the browser process will own the popup UI. |key| serves for
-// identifying the fill form data in subsequent
-// AutofillHostMsg_ShowPasswordSuggestions messages to the browser.
-IPC_MESSAGE_ROUTED2(AutofillMsg_FillPasswordForm,
- int /* key */,
- autofill::PasswordFormFillData /* the fill form data*/)
-
-// Notification to start (|active| == true) or stop (|active| == false) logging
-// the decisions made about saving the password.
-IPC_MESSAGE_ROUTED1(AutofillMsg_SetLoggingState, bool /* active */)
-
-// Send the heuristic and server field type predictions to the renderer.
-IPC_MESSAGE_ROUTED1(
- AutofillMsg_FieldTypePredictionsAvailable,
- std::vector<autofill::FormDataPredictions> /* forms */)
-
-// Clears the currently displayed Autofill results.
-IPC_MESSAGE_ROUTED0(AutofillMsg_ClearForm)
-
-// Tells the renderer that the Autofill previewed form should be cleared.
-IPC_MESSAGE_ROUTED0(AutofillMsg_ClearPreviewedForm)
-
-// Sets the currently selected node's value.
-IPC_MESSAGE_ROUTED1(AutofillMsg_FillFieldWithValue,
- base::string16 /* value */)
-
-// Sets the suggested value for the currently previewed node.
-IPC_MESSAGE_ROUTED1(AutofillMsg_PreviewFieldWithValue,
- base::string16 /* value */)
-
-// Sets the currently selected node's value to be the given data list value.
-IPC_MESSAGE_ROUTED1(AutofillMsg_AcceptDataListSuggestion,
- base::string16 /* accepted data list value */)
-
-// Tells the renderer to populate the correct password fields with this
-// generated password.
-IPC_MESSAGE_ROUTED1(AutofillMsg_GeneratedPasswordAccepted,
- base::string16 /* generated_password */)
-
-// Tells the renderer to enable the form classifier.
-IPC_MESSAGE_ROUTED0(AutofillMsg_AllowToRunFormClassifier)
-
-// Tells the renderer to fill the username and password with with given
-// values.
-IPC_MESSAGE_ROUTED2(AutofillMsg_FillPasswordSuggestion,
- base::string16 /* username */,
- base::string16 /* password */)
-
-// Tells the renderer to preview the username and password with the given
-// values.
-IPC_MESSAGE_ROUTED2(AutofillMsg_PreviewPasswordSuggestion,
- base::string16 /* username */,
- base::string16 /* password */)
-
-// Sent when a password form is initially detected and suggestions should be
-// shown. Used by the fill-on-select experiment.
-IPC_MESSAGE_ROUTED2(AutofillMsg_ShowInitialPasswordAccountSuggestions,
- int /* key */,
- autofill::PasswordFormFillData /* the fill form data */)
-
-// Tells the renderer to find the focused password form (assuming it exists).
-// Renderer is expected to respond with the message
-// |AutofillHostMsg_FocusedPasswordFormFound|.
-IPC_MESSAGE_ROUTED0(AutofillMsg_FindFocusedPasswordForm)
-
-// Tells the renderer to find a focused element, and if it is a password field
-// eligible for generation then to trigger generation by responding to the
-// browser with the message |AutofillHostMsg_ShowPasswordGenerationPopup|.
-IPC_MESSAGE_ROUTED0(AutofillMsg_UserTriggeredGeneratePassword)
-
-// Tells the renderer that this password form is not blacklisted. A form can
-// be blacklisted if a user chooses "never save passwords for this site".
-IPC_MESSAGE_ROUTED1(AutofillMsg_FormNotBlacklisted,
- autofill::PasswordForm /* form checked */)
-
-// Sent when Autofill manager gets the query response from the Autofill server
-// and there are fields classified for password generation in the response.
-IPC_MESSAGE_ROUTED1(
- AutofillMsg_FoundFormsEligibleForGeneration,
- std::vector<autofill::PasswordFormGenerationData> /* forms */)
-
-// Sent when Autofill manager gets the query response from the Autofill server
-// which contains information about username and password fields for some forms.
-// |predictions| maps forms to their username fields.
-IPC_MESSAGE_ROUTED1(AutofillMsg_AutofillUsernameAndPasswordDataReceived,
- FormsPredictionsMap /* predictions */)
-
-// Autofill messages sent from the renderer to the browser.
-
-// TODO(creis): check in the browser that the renderer actually has permission
-// for the URL to avoid compromised renderers talking to the browser.
-
-// Notification that forms have been seen that are candidates for
-// filling/submitting by the AutofillManager.
-IPC_MESSAGE_ROUTED2(AutofillHostMsg_FormsSeen,
- std::vector<autofill::FormData> /* forms */,
- base::TimeTicks /* timestamp */)
-
-// Notification that password forms have been seen that are candidates for
-// filling/submitting by the password manager.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordFormsParsed,
- std::vector<autofill::PasswordForm> /* forms */)
-
-// Notification that initial layout has occurred and the following password
-// forms are visible on the page (e.g. not set to display:none.), and whether
-// all frames in the page have been rendered.
-IPC_MESSAGE_ROUTED2(AutofillHostMsg_PasswordFormsRendered,
- std::vector<autofill::PasswordForm> /* forms */,
- bool /* did_stop_loading */)
-
-// A ping to the browser that PasswordAutofillAgent was constructed. As a
-// consequence, the browser sends AutofillMsg_SetLoggingState with the current
-// state of the logging activity.
-IPC_MESSAGE_ROUTED0(AutofillHostMsg_PasswordAutofillAgentConstructed)
-
-// Notification that this password form was submitted by the user.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordFormSubmitted,
- autofill::PasswordForm /* form */)
-
-// Notification that in-page navigation happened and at this moment we have
-// filled password form. We use this as a signal for successful login.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_InPageNavigation,
- autofill::PasswordForm /* form */)
-
-// Sends |log| to browser for displaying to the user. Only strings passed as an
-// argument to methods overriding SavePasswordProgressLogger::SendLog may become
-// |log|, because those are guaranteed to be sanitized. Never pass a free-form
-// string as |log|.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_RecordSavePasswordProgress,
- std::string /* log */)
-
-// Notification that a form is about to be submitted. The user hit the button.
-IPC_MESSAGE_ROUTED2(AutofillHostMsg_WillSubmitForm,
- autofill::FormData /* form */,
- base::TimeTicks /* timestamp */)
-
-// Notification that a form has been submitted.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_FormSubmitted,
- autofill::FormData /* form */)
-
-// Notification that a form field's value has changed.
-IPC_MESSAGE_ROUTED3(AutofillHostMsg_TextFieldDidChange,
- autofill::FormData /* the form */,
- autofill::FormFieldData /* the form field */,
- base::TimeTicks /* timestamp */)
-
-// Queries the browser for Autofill suggestions for a form input field.
-IPC_MESSAGE_ROUTED4(AutofillHostMsg_QueryFormFieldAutofill,
- int /* id of this message */,
- autofill::FormData /* the form */,
- autofill::FormFieldData /* the form field */,
- gfx::RectF /* input field bounds, window-relative */)
-
-// Sent when a form is previewed with Autofill suggestions.
-IPC_MESSAGE_ROUTED0(AutofillHostMsg_DidPreviewAutofillFormData)
-
-// Sent immediately after the renderer receives a ping IPC.
-IPC_MESSAGE_ROUTED0(AutofillHostMsg_PingAck)
-
-// Sent when the current form is no longer focused.
-IPC_MESSAGE_ROUTED0(AutofillHostMsg_FocusNoLongerOnForm)
-
-// Sent when a form is filled with Autofill suggestions.
-IPC_MESSAGE_ROUTED2(AutofillHostMsg_DidFillAutofillFormData,
- autofill::FormData /* the form */,
- base::TimeTicks /* timestamp */)
-
-// Send when a text field is done editing.
-IPC_MESSAGE_ROUTED0(AutofillHostMsg_DidEndTextFieldEditing)
-
-// Instructs the browser to hide the Autofill popup if it is open.
-IPC_MESSAGE_ROUTED0(AutofillHostMsg_HidePopup)
-
// Instructs the browser that generation is available for this particular form.
// This is used for UMA stats.
IPC_MESSAGE_ROUTED1(AutofillHostMsg_GenerationAvailableForForm,
@@ -326,40 +72,3 @@ IPC_MESSAGE_ROUTED2(AutofillHostMsg_ShowPasswordEditingPopup,
// Instructs the browser to hide any password generation popups.
IPC_MESSAGE_ROUTED0(AutofillHostMsg_HidePasswordGenerationPopup)
-
-// Instructs the browser to presave the form with generated password.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_PresaveGeneratedPassword,
- autofill::PasswordForm)
-
-// Instructs the browser that form no longer contains a generated password and
-// the presaved form should be removed.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordNoLongerGenerated,
- autofill::PasswordForm)
-
-// Sends the outcome of HTML parsing based form classifier that detects the
-// forms where password generation should be available.
-IPC_MESSAGE_ROUTED2(AutofillHostMsg_SaveGenerationFieldDetectedByClassifier,
- autofill::PasswordForm,
- base::string16 /* generation field */)
-
-// Instruct the browser to show a popup with suggestions filled from data
-// associated with |key|. The popup will use |text_direction| for displaying
-// text.
-IPC_MESSAGE_ROUTED5(
- AutofillHostMsg_ShowPasswordSuggestions,
- int /* key */,
- base::i18n::TextDirection /* text_direction */,
- base::string16 /* username typed by user */,
- int /* options bitmask of autofill::ShowPasswordSuggestionsOptions */,
- gfx::RectF /* input field bounds, window-relative */)
-
-// Inform browser of data list values for the curent field.
-IPC_MESSAGE_ROUTED2(AutofillHostMsg_SetDataList,
- std::vector<base::string16> /* values */,
- std::vector<base::string16> /* labels */)
-
-// Inform the browser which password form is currently focused, as a response
-// to the |AutofillMsg_FindFocusedPasswordForm| request. If no password form
-// is focused, the response will contain an empty |autofill::PasswordForm|.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_FocusedPasswordFormFound,
- autofill::PasswordForm)
diff --git a/chromium/components/autofill/content/common/autofill_param_traits_macros.h b/chromium/components/autofill/content/common/autofill_param_traits_macros.h
index ed94ab84534..b20ff68848c 100644
--- a/chromium/components/autofill/content/common/autofill_param_traits_macros.h
+++ b/chromium/components/autofill/content/common/autofill_param_traits_macros.h
@@ -43,7 +43,6 @@ IPC_STRUCT_TRAITS_BEGIN(autofill::PasswordForm)
IPC_STRUCT_TRAITS_MEMBER(password_value)
IPC_STRUCT_TRAITS_MEMBER(new_password_element)
IPC_STRUCT_TRAITS_MEMBER(new_password_value)
- IPC_STRUCT_TRAITS_MEMBER(ssl_valid)
IPC_STRUCT_TRAITS_MEMBER(preferred)
IPC_STRUCT_TRAITS_MEMBER(blacklisted_by_user)
IPC_STRUCT_TRAITS_MEMBER(type)
diff --git a/chromium/components/autofill/content/public/cpp/DEPS b/chromium/components/autofill/content/public/cpp/DEPS
new file mode 100644
index 00000000000..1c40d981eb6
--- /dev/null
+++ b/chromium/components/autofill/content/public/cpp/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ipc",
+]
diff --git a/chromium/components/autofill/content/public/cpp/autofill_types.typemap b/chromium/components/autofill/content/public/cpp/autofill_types.typemap
index 6bdf90e1f05..a257f4bd4f5 100644
--- a/chromium/components/autofill/content/public/cpp/autofill_types.typemap
+++ b/chromium/components/autofill/content/public/cpp/autofill_types.typemap
@@ -8,7 +8,10 @@ public_headers = [
"//components/autofill/core/common/form_data_predictions.h",
"//components/autofill/core/common/form_field_data.h",
"//components/autofill/core/common/form_field_data_predictions.h",
+ "//components/autofill/core/common/password_form.h",
+ "//components/autofill/core/common/password_form_field_prediction_map.h",
"//components/autofill/core/common/password_form_fill_data.h",
+ "//components/autofill/core/common/password_form_generation_data.h",
]
traits_headers = [ "//components/autofill/content/public/cpp/autofill_types_struct_traits.h" ]
sources = [
@@ -26,8 +29,17 @@ type_mappings = [
"autofill.mojom.FormDataPredictions=autofill::FormDataPredictions",
"autofill.mojom.FormFieldData=autofill::FormFieldData",
"autofill.mojom.FormFieldDataPredictions=autofill::FormFieldDataPredictions",
+ "autofill.mojom.FormsPredictionsMap=autofill::FormsPredictionsMap",
+ "autofill.mojom.GenerationUploadStatus=autofill::PasswordForm::GenerationUploadStatus",
"autofill.mojom.PasswordAndRealm=autofill::PasswordAndRealm",
+ "autofill.mojom.PasswordForm=autofill::PasswordForm",
+ "autofill.mojom.PasswordFormFieldPredictionMap=autofill::PasswordFormFieldPredictionMap",
+ "autofill.mojom.PasswordFormFieldPredictionType=autofill::PasswordFormFieldPredictionType",
"autofill.mojom.PasswordFormFillData=autofill::PasswordFormFillData",
+ "autofill.mojom.PasswordFormGenerationData=autofill::PasswordFormGenerationData",
+ "autofill.mojom.PasswordFormLayout=autofill::PasswordForm::Layout",
+ "autofill.mojom.PasswordFormScheme=autofill::PasswordForm::Scheme",
+ "autofill.mojom.PasswordFormType=autofill::PasswordForm::Type",
"autofill.mojom.RoleAttribute=autofill::FormFieldData::RoleAttribute",
"autofill.mojom.TextDirection=base::i18n::TextDirection",
"autofill.mojom.UsernamesCollectionKey=autofill::UsernamesCollectionKey",
diff --git a/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits.cc b/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits.cc
index b61c11cb30c..4b020779bdb 100644
--- a/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits.cc
+++ b/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits.cc
@@ -5,12 +5,15 @@
#include "components/autofill/content/public/cpp/autofill_types_struct_traits.h"
#include "base/i18n/rtl.h"
+#include "ipc/ipc_message_utils.h"
+#include "url/mojo/origin_struct_traits.h"
#include "url/mojo/url_gurl_struct_traits.h"
using namespace autofill;
namespace mojo {
+// static
mojom::CheckStatus
EnumTraits<mojom::CheckStatus, FormFieldData::CheckStatus>::ToMojom(
FormFieldData::CheckStatus input) {
@@ -27,6 +30,7 @@ EnumTraits<mojom::CheckStatus, FormFieldData::CheckStatus>::ToMojom(
return mojom::CheckStatus::NOT_CHECKABLE;
}
+// static
bool EnumTraits<mojom::CheckStatus, FormFieldData::CheckStatus>::FromMojom(
mojom::CheckStatus input,
FormFieldData::CheckStatus* output) {
@@ -46,6 +50,7 @@ bool EnumTraits<mojom::CheckStatus, FormFieldData::CheckStatus>::FromMojom(
return false;
}
+// static
mojom::RoleAttribute
EnumTraits<mojom::RoleAttribute, FormFieldData::RoleAttribute>::ToMojom(
FormFieldData::RoleAttribute input) {
@@ -60,6 +65,7 @@ EnumTraits<mojom::RoleAttribute, FormFieldData::RoleAttribute>::ToMojom(
return mojom::RoleAttribute::ROLE_ATTRIBUTE_OTHER;
}
+// static
bool EnumTraits<mojom::RoleAttribute, FormFieldData::RoleAttribute>::FromMojom(
mojom::RoleAttribute input,
FormFieldData::RoleAttribute* output) {
@@ -76,6 +82,7 @@ bool EnumTraits<mojom::RoleAttribute, FormFieldData::RoleAttribute>::FromMojom(
return false;
}
+// static
mojom::TextDirection
EnumTraits<mojom::TextDirection, base::i18n::TextDirection>::ToMojom(
base::i18n::TextDirection input) {
@@ -94,6 +101,7 @@ EnumTraits<mojom::TextDirection, base::i18n::TextDirection>::ToMojom(
return mojom::TextDirection::UNKNOWN_DIRECTION;
}
+// static
bool EnumTraits<mojom::TextDirection, base::i18n::TextDirection>::FromMojom(
mojom::TextDirection input,
base::i18n::TextDirection* output) {
@@ -117,7 +125,211 @@ bool EnumTraits<mojom::TextDirection, base::i18n::TextDirection>::FromMojom(
}
// static
-bool StructTraits<mojom::FormFieldData, FormFieldData>::Read(
+mojom::GenerationUploadStatus EnumTraits<mojom::GenerationUploadStatus,
+ PasswordForm::GenerationUploadStatus>::
+ ToMojom(PasswordForm::GenerationUploadStatus input) {
+ switch (input) {
+ case PasswordForm::GenerationUploadStatus::NO_SIGNAL_SENT:
+ return mojom::GenerationUploadStatus::NO_SIGNAL_SENT;
+ case PasswordForm::GenerationUploadStatus::POSITIVE_SIGNAL_SENT:
+ return mojom::GenerationUploadStatus::POSITIVE_SIGNAL_SENT;
+ case PasswordForm::GenerationUploadStatus::NEGATIVE_SIGNAL_SENT:
+ return mojom::GenerationUploadStatus::NEGATIVE_SIGNAL_SENT;
+ case PasswordForm::GenerationUploadStatus::UNKNOWN_STATUS:
+ return mojom::GenerationUploadStatus::UNKNOWN_STATUS;
+ }
+
+ NOTREACHED();
+ return mojom::GenerationUploadStatus::UNKNOWN_STATUS;
+}
+
+// static
+bool EnumTraits<mojom::GenerationUploadStatus,
+ PasswordForm::GenerationUploadStatus>::
+ FromMojom(mojom::GenerationUploadStatus input,
+ PasswordForm::GenerationUploadStatus* output) {
+ switch (input) {
+ case mojom::GenerationUploadStatus::NO_SIGNAL_SENT:
+ *output = PasswordForm::GenerationUploadStatus::NO_SIGNAL_SENT;
+ return true;
+ case mojom::GenerationUploadStatus::POSITIVE_SIGNAL_SENT:
+ *output = PasswordForm::GenerationUploadStatus::POSITIVE_SIGNAL_SENT;
+ return true;
+ case mojom::GenerationUploadStatus::NEGATIVE_SIGNAL_SENT:
+ *output = PasswordForm::GenerationUploadStatus::NEGATIVE_SIGNAL_SENT;
+ return true;
+ case mojom::GenerationUploadStatus::UNKNOWN_STATUS:
+ *output = PasswordForm::GenerationUploadStatus::UNKNOWN_STATUS;
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+// static
+mojom::PasswordFormLayout
+EnumTraits<mojom::PasswordFormLayout, PasswordForm::Layout>::ToMojom(
+ PasswordForm::Layout input) {
+ switch (input) {
+ case PasswordForm::Layout::LAYOUT_OTHER:
+ return mojom::PasswordFormLayout::LAYOUT_OTHER;
+ case PasswordForm::Layout::LAYOUT_LOGIN_AND_SIGNUP:
+ return mojom::PasswordFormLayout::LAYOUT_LOGIN_AND_SIGNUP;
+ }
+
+ NOTREACHED();
+ return mojom::PasswordFormLayout::LAYOUT_OTHER;
+}
+
+// static
+bool EnumTraits<mojom::PasswordFormLayout, PasswordForm::Layout>::FromMojom(
+ mojom::PasswordFormLayout input,
+ PasswordForm::Layout* output) {
+ switch (input) {
+ case mojom::PasswordFormLayout::LAYOUT_OTHER:
+ *output = PasswordForm::Layout::LAYOUT_OTHER;
+ return true;
+ case mojom::PasswordFormLayout::LAYOUT_LOGIN_AND_SIGNUP:
+ *output = PasswordForm::Layout::LAYOUT_LOGIN_AND_SIGNUP;
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+// static
+mojom::PasswordFormType
+EnumTraits<mojom::PasswordFormType, PasswordForm::Type>::ToMojom(
+ PasswordForm::Type input) {
+ switch (input) {
+ case PasswordForm::Type::TYPE_MANUAL:
+ return mojom::PasswordFormType::TYPE_MANUAL;
+ case PasswordForm::Type::TYPE_GENERATED:
+ return mojom::PasswordFormType::TYPE_GENERATED;
+ case PasswordForm::Type::TYPE_API:
+ return mojom::PasswordFormType::TYPE_API;
+ }
+
+ NOTREACHED();
+ return mojom::PasswordFormType::TYPE_MANUAL;
+}
+
+// static
+bool EnumTraits<mojom::PasswordFormType, PasswordForm::Type>::FromMojom(
+ mojom::PasswordFormType input,
+ PasswordForm::Type* output) {
+ switch (input) {
+ case mojom::PasswordFormType::TYPE_MANUAL:
+ *output = PasswordForm::Type::TYPE_MANUAL;
+ return true;
+ case mojom::PasswordFormType::TYPE_GENERATED:
+ *output = PasswordForm::Type::TYPE_GENERATED;
+ return true;
+ case mojom::PasswordFormType::TYPE_API:
+ *output = PasswordForm::Type::TYPE_API;
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+// static
+mojom::PasswordFormScheme
+EnumTraits<mojom::PasswordFormScheme, PasswordForm::Scheme>::ToMojom(
+ PasswordForm::Scheme input) {
+ switch (input) {
+ case PasswordForm::Scheme::SCHEME_HTML:
+ return mojom::PasswordFormScheme::SCHEME_HTML;
+ case PasswordForm::Scheme::SCHEME_BASIC:
+ return mojom::PasswordFormScheme::SCHEME_BASIC;
+ case PasswordForm::Scheme::SCHEME_DIGEST:
+ return mojom::PasswordFormScheme::SCHEME_DIGEST;
+ case PasswordForm::Scheme::SCHEME_OTHER:
+ return mojom::PasswordFormScheme::SCHEME_OTHER;
+ case PasswordForm::Scheme::SCHEME_USERNAME_ONLY:
+ return mojom::PasswordFormScheme::SCHEME_USERNAME_ONLY;
+ }
+
+ NOTREACHED();
+ return mojom::PasswordFormScheme::SCHEME_OTHER;
+}
+
+// static
+bool EnumTraits<mojom::PasswordFormScheme, PasswordForm::Scheme>::FromMojom(
+ mojom::PasswordFormScheme input,
+ PasswordForm::Scheme* output) {
+ switch (input) {
+ case mojom::PasswordFormScheme::SCHEME_HTML:
+ *output = PasswordForm::Scheme::SCHEME_HTML;
+ return true;
+ case mojom::PasswordFormScheme::SCHEME_BASIC:
+ *output = PasswordForm::Scheme::SCHEME_BASIC;
+ return true;
+ case mojom::PasswordFormScheme::SCHEME_DIGEST:
+ *output = PasswordForm::Scheme::SCHEME_DIGEST;
+ return true;
+ case mojom::PasswordFormScheme::SCHEME_OTHER:
+ *output = PasswordForm::Scheme::SCHEME_OTHER;
+ return true;
+ case mojom::PasswordFormScheme::SCHEME_USERNAME_ONLY:
+ *output = PasswordForm::Scheme::SCHEME_USERNAME_ONLY;
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+// static
+mojom::PasswordFormFieldPredictionType EnumTraits<
+ mojom::PasswordFormFieldPredictionType,
+ PasswordFormFieldPredictionType>::ToMojom(PasswordFormFieldPredictionType
+ input) {
+ switch (input) {
+ case PasswordFormFieldPredictionType::PREDICTION_USERNAME:
+ return mojom::PasswordFormFieldPredictionType::PREDICTION_USERNAME;
+ case PasswordFormFieldPredictionType::PREDICTION_CURRENT_PASSWORD:
+ return mojom::PasswordFormFieldPredictionType::
+ PREDICTION_CURRENT_PASSWORD;
+ case PasswordFormFieldPredictionType::PREDICTION_NEW_PASSWORD:
+ return mojom::PasswordFormFieldPredictionType::PREDICTION_NEW_PASSWORD;
+ case PasswordFormFieldPredictionType::PREDICTION_NOT_PASSWORD:
+ return mojom::PasswordFormFieldPredictionType::PREDICTION_NOT_PASSWORD;
+ }
+
+ NOTREACHED();
+ return mojom::PasswordFormFieldPredictionType::PREDICTION_NOT_PASSWORD;
+}
+
+// static
+bool EnumTraits<mojom::PasswordFormFieldPredictionType,
+ PasswordFormFieldPredictionType>::
+ FromMojom(mojom::PasswordFormFieldPredictionType input,
+ PasswordFormFieldPredictionType* output) {
+ switch (input) {
+ case mojom::PasswordFormFieldPredictionType::PREDICTION_USERNAME:
+ *output = PasswordFormFieldPredictionType::PREDICTION_USERNAME;
+ return true;
+ case mojom::PasswordFormFieldPredictionType::PREDICTION_CURRENT_PASSWORD:
+ *output = PasswordFormFieldPredictionType::PREDICTION_CURRENT_PASSWORD;
+ return true;
+ case mojom::PasswordFormFieldPredictionType::PREDICTION_NEW_PASSWORD:
+ *output = PasswordFormFieldPredictionType::PREDICTION_NEW_PASSWORD;
+ return true;
+ case mojom::PasswordFormFieldPredictionType::PREDICTION_NOT_PASSWORD:
+ *output = PasswordFormFieldPredictionType::PREDICTION_NOT_PASSWORD;
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+// static
+bool StructTraits<mojom::FormFieldDataDataView, FormFieldData>::Read(
mojom::FormFieldDataDataView data,
FormFieldData* out) {
if (!data.ReadLabel(&out->label))
@@ -135,6 +347,11 @@ bool StructTraits<mojom::FormFieldData, FormFieldData>::Read(
if (!data.ReadPlaceholder(&out->placeholder))
return false;
+ if (!data.ReadCssClasses(&out->css_classes))
+ return false;
+
+ out->properties_mask = data.properties_mask();
+
out->max_length = data.max_length();
out->is_autofilled = data.is_autofilled();
@@ -159,8 +376,9 @@ bool StructTraits<mojom::FormFieldData, FormFieldData>::Read(
}
// static
-bool StructTraits<mojom::FormData, FormData>::Read(mojom::FormDataDataView data,
- FormData* out) {
+bool StructTraits<mojom::FormDataDataView, FormData>::Read(
+ mojom::FormDataDataView data,
+ FormData* out) {
if (!data.ReadName(&out->name))
return false;
if (!data.ReadOrigin(&out->origin))
@@ -178,7 +396,8 @@ bool StructTraits<mojom::FormData, FormData>::Read(mojom::FormDataDataView data,
}
// static
-bool StructTraits<mojom::FormFieldDataPredictions, FormFieldDataPredictions>::
+bool StructTraits<mojom::FormFieldDataPredictionsDataView,
+ FormFieldDataPredictions>::
Read(mojom::FormFieldDataPredictionsDataView data,
FormFieldDataPredictions* out) {
if (!data.ReadField(&out->field))
@@ -198,9 +417,10 @@ bool StructTraits<mojom::FormFieldDataPredictions, FormFieldDataPredictions>::
}
// static
-bool StructTraits<mojom::FormDataPredictions, FormDataPredictions>::Read(
- mojom::FormDataPredictionsDataView data,
- FormDataPredictions* out) {
+bool StructTraits<mojom::FormDataPredictionsDataView,
+ FormDataPredictions>::Read(mojom::FormDataPredictionsDataView
+ data,
+ FormDataPredictions* out) {
if (!data.ReadData(&out->data))
return false;
if (!data.ReadSignature(&out->signature))
@@ -212,7 +432,7 @@ bool StructTraits<mojom::FormDataPredictions, FormDataPredictions>::Read(
}
// static
-bool StructTraits<mojom::PasswordAndRealm, PasswordAndRealm>::Read(
+bool StructTraits<mojom::PasswordAndRealmDataView, PasswordAndRealm>::Read(
mojom::PasswordAndRealmDataView data,
PasswordAndRealm* out) {
if (!data.ReadPassword(&out->password))
@@ -224,9 +444,10 @@ bool StructTraits<mojom::PasswordAndRealm, PasswordAndRealm>::Read(
}
// static
-bool StructTraits<mojom::UsernamesCollectionKey, UsernamesCollectionKey>::Read(
- mojom::UsernamesCollectionKeyDataView data,
- UsernamesCollectionKey* out) {
+bool StructTraits<
+ mojom::UsernamesCollectionKeyDataView,
+ UsernamesCollectionKey>::Read(mojom::UsernamesCollectionKeyDataView data,
+ UsernamesCollectionKey* out) {
if (!data.ReadUsername(&out->username))
return false;
if (!data.ReadPassword(&out->password))
@@ -238,7 +459,7 @@ bool StructTraits<mojom::UsernamesCollectionKey, UsernamesCollectionKey>::Read(
}
// static
-void* StructTraits<mojom::PasswordFormFillData, PasswordFormFillData>::
+void* StructTraits<mojom::PasswordFormFillDataDataView, PasswordFormFillData>::
SetUpContext(const PasswordFormFillData& r) {
// Extracts keys vector and values vector from the map, saves them as a pair.
auto* pair = new UsernamesCollectionKeysValuesPair();
@@ -251,15 +472,14 @@ void* StructTraits<mojom::PasswordFormFillData, PasswordFormFillData>::
}
// static
-void StructTraits<mojom::PasswordFormFillData, PasswordFormFillData>::
+void StructTraits<mojom::PasswordFormFillDataDataView, PasswordFormFillData>::
TearDownContext(const PasswordFormFillData& r, void* context) {
delete static_cast<UsernamesCollectionKeysValuesPair*>(context);
}
// static
-bool StructTraits<mojom::PasswordFormFillData, PasswordFormFillData>::Read(
- mojom::PasswordFormFillDataDataView data,
- PasswordFormFillData* out) {
+bool StructTraits<mojom::PasswordFormFillDataDataView, PasswordFormFillData>::
+ Read(mojom::PasswordFormFillDataDataView data, PasswordFormFillData* out) {
if (!data.ReadName(&out->name) || !data.ReadOrigin(&out->origin) ||
!data.ReadAction(&out->action) ||
!data.ReadUsernameField(&out->username_field) ||
@@ -288,4 +508,160 @@ bool StructTraits<mojom::PasswordFormFillData, PasswordFormFillData>::Read(
return true;
}
+// static
+bool StructTraits<mojom::PasswordFormGenerationDataDataView,
+ PasswordFormGenerationData>::
+ Read(mojom::PasswordFormGenerationDataDataView data,
+ PasswordFormGenerationData* out) {
+ out->form_signature = data.form_signature();
+ out->field_signature = data.field_signature();
+ return true;
+}
+
+// static
+bool StructTraits<mojom::PasswordFormDataView, PasswordForm>::Read(
+ mojom::PasswordFormDataView data,
+ PasswordForm* out) {
+ if (!data.ReadScheme(&out->scheme) ||
+ !data.ReadSignonRealm(&out->signon_realm) ||
+ !data.ReadOriginWithPath(&out->origin) ||
+ !data.ReadAction(&out->action) ||
+ !data.ReadAffiliatedWebRealm(&out->affiliated_web_realm) ||
+ !data.ReadSubmitElement(&out->submit_element) ||
+ !data.ReadUsernameElement(&out->username_element))
+ return false;
+
+ out->username_marked_by_site = data.username_marked_by_site();
+
+ if (!data.ReadUsernameValue(&out->username_value) ||
+ !data.ReadOtherPossibleUsernames(&out->other_possible_usernames) ||
+ !data.ReadPasswordElement(&out->password_element) ||
+ !data.ReadPasswordValue(&out->password_value))
+ return false;
+
+ out->password_value_is_default = data.password_value_is_default();
+
+ if (!data.ReadNewPasswordElement(&out->new_password_element) ||
+ !data.ReadNewPasswordValue(&out->new_password_value))
+ return false;
+
+ out->new_password_value_is_default = data.new_password_value_is_default();
+ out->new_password_marked_by_site = data.new_password_marked_by_site();
+ out->preferred = data.preferred();
+
+ if (!data.ReadDateCreated(&out->date_created) ||
+ !data.ReadDateSynced(&out->date_synced))
+ return false;
+
+ out->blacklisted_by_user = data.blacklisted_by_user();
+
+ if (!data.ReadType(&out->type))
+ return false;
+
+ out->times_used = data.times_used();
+
+ if (!data.ReadFormData(&out->form_data) ||
+ !data.ReadGenerationUploadStatus(&out->generation_upload_status) ||
+ !data.ReadDisplayName(&out->display_name) ||
+ !data.ReadIconUrl(&out->icon_url) ||
+ !data.ReadFederationOrigin(&out->federation_origin))
+ return false;
+
+ out->skip_zero_click = data.skip_zero_click();
+
+ if (!data.ReadLayout(&out->layout))
+ return false;
+
+ out->was_parsed_using_autofill_predictions =
+ data.was_parsed_using_autofill_predictions();
+ out->is_public_suffix_match = data.is_public_suffix_match();
+ out->is_affiliation_based_match = data.is_affiliation_based_match();
+ out->does_look_like_signup_form = data.does_look_like_signup_form();
+
+ return true;
+}
+
+// static
+void* StructTraits<mojom::PasswordFormFieldPredictionMapDataView,
+ PasswordFormFieldPredictionMap>::
+ SetUpContext(const PasswordFormFieldPredictionMap& r) {
+ // Extracts keys vector and values vector from the map, saves them as a pair.
+ auto* pair = new KeysValuesPair();
+ for (const auto& i : r) {
+ pair->first.push_back(i.first);
+ pair->second.push_back(i.second);
+ }
+
+ return pair;
+}
+
+// static
+void StructTraits<mojom::PasswordFormFieldPredictionMapDataView,
+ PasswordFormFieldPredictionMap>::
+ TearDownContext(const PasswordFormFieldPredictionMap& r, void* context) {
+ delete static_cast<KeysValuesPair*>(context);
+}
+
+// static
+bool StructTraits<mojom::PasswordFormFieldPredictionMapDataView,
+ PasswordFormFieldPredictionMap>::
+ Read(mojom::PasswordFormFieldPredictionMapDataView data,
+ PasswordFormFieldPredictionMap* out) {
+ // Combines keys vector and values vector to the map.
+ std::vector<FormFieldData> keys;
+ if (!data.ReadKeys(&keys))
+ return false;
+ std::vector<PasswordFormFieldPredictionType> values;
+ if (!data.ReadValues(&values))
+ return false;
+ if (keys.size() != values.size())
+ return false;
+ out->clear();
+ for (size_t i = 0; i < keys.size(); ++i)
+ out->insert({keys[i], values[i]});
+
+ return true;
+}
+
+// static
+void* StructTraits<mojom::FormsPredictionsMapDataView,
+ FormsPredictionsMap>::SetUpContext(const FormsPredictionsMap&
+ r) {
+ // Extracts keys vector and values vector from the map, saves them as a pair.
+ auto* pair = new KeysValuesPair();
+ for (const auto& i : r) {
+ pair->first.push_back(i.first);
+ pair->second.push_back(i.second);
+ }
+
+ return pair;
+}
+
+// static
+void StructTraits<mojom::FormsPredictionsMapDataView, FormsPredictionsMap>::
+ TearDownContext(const FormsPredictionsMap& r, void* context) {
+ delete static_cast<KeysValuesPair*>(context);
+}
+
+// static
+bool StructTraits<mojom::FormsPredictionsMapDataView,
+ FormsPredictionsMap>::Read(mojom::FormsPredictionsMapDataView
+ data,
+ FormsPredictionsMap* out) {
+ // Combines keys vector and values vector to the map.
+ std::vector<FormData> keys;
+ if (!data.ReadKeys(&keys))
+ return false;
+ std::vector<PasswordFormFieldPredictionMap> values;
+ if (!data.ReadValues(&values))
+ return false;
+ if (keys.size() != values.size())
+ return false;
+ out->clear();
+ for (size_t i = 0; i < keys.size(); ++i)
+ out->insert({keys[i], values[i]});
+
+ return true;
+}
+
} // namespace mojo
diff --git a/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits.h b/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits.h
index 7307b00d5e0..e22085f1bbf 100644
--- a/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits.h
+++ b/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits.h
@@ -13,7 +13,10 @@
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/form_field_data_predictions.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/autofill/core/common/password_form_field_prediction_map.h"
#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/autofill/core/common/password_form_generation_data.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
namespace mojo {
@@ -45,7 +48,53 @@ struct EnumTraits<autofill::mojom::TextDirection, base::i18n::TextDirection> {
};
template <>
-struct StructTraits<autofill::mojom::FormFieldData, autofill::FormFieldData> {
+struct EnumTraits<autofill::mojom::GenerationUploadStatus,
+ autofill::PasswordForm::GenerationUploadStatus> {
+ static autofill::mojom::GenerationUploadStatus ToMojom(
+ autofill::PasswordForm::GenerationUploadStatus input);
+ static bool FromMojom(autofill::mojom::GenerationUploadStatus input,
+ autofill::PasswordForm::GenerationUploadStatus* output);
+};
+
+template <>
+struct EnumTraits<autofill::mojom::PasswordFormLayout,
+ autofill::PasswordForm::Layout> {
+ static autofill::mojom::PasswordFormLayout ToMojom(
+ autofill::PasswordForm::Layout input);
+ static bool FromMojom(autofill::mojom::PasswordFormLayout input,
+ autofill::PasswordForm::Layout* output);
+};
+
+template <>
+struct EnumTraits<autofill::mojom::PasswordFormType,
+ autofill::PasswordForm::Type> {
+ static autofill::mojom::PasswordFormType ToMojom(
+ autofill::PasswordForm::Type input);
+ static bool FromMojom(autofill::mojom::PasswordFormType input,
+ autofill::PasswordForm::Type* output);
+};
+
+template <>
+struct EnumTraits<autofill::mojom::PasswordFormScheme,
+ autofill::PasswordForm::Scheme> {
+ static autofill::mojom::PasswordFormScheme ToMojom(
+ autofill::PasswordForm::Scheme input);
+ static bool FromMojom(autofill::mojom::PasswordFormScheme input,
+ autofill::PasswordForm::Scheme* output);
+};
+
+template <>
+struct EnumTraits<autofill::mojom::PasswordFormFieldPredictionType,
+ autofill::PasswordFormFieldPredictionType> {
+ static autofill::mojom::PasswordFormFieldPredictionType ToMojom(
+ autofill::PasswordFormFieldPredictionType input);
+ static bool FromMojom(autofill::mojom::PasswordFormFieldPredictionType input,
+ autofill::PasswordFormFieldPredictionType* output);
+};
+
+template <>
+struct StructTraits<autofill::mojom::FormFieldDataDataView,
+ autofill::FormFieldData> {
static const base::string16& label(const autofill::FormFieldData& r) {
return r.label;
}
@@ -72,6 +121,14 @@ struct StructTraits<autofill::mojom::FormFieldData, autofill::FormFieldData> {
return r.placeholder;
}
+ static const base::string16& css_classes(const autofill::FormFieldData& r) {
+ return r.css_classes;
+ }
+
+ static uint32_t properties_mask(const autofill::FormFieldData& r) {
+ return r.properties_mask;
+ }
+
static uint64_t max_length(const autofill::FormFieldData& r) {
return r.max_length;
}
@@ -118,7 +175,7 @@ struct StructTraits<autofill::mojom::FormFieldData, autofill::FormFieldData> {
};
template <>
-struct StructTraits<autofill::mojom::FormData, autofill::FormData> {
+struct StructTraits<autofill::mojom::FormDataDataView, autofill::FormData> {
static const base::string16& name(const autofill::FormData& r) {
return r.name;
}
@@ -143,7 +200,7 @@ struct StructTraits<autofill::mojom::FormData, autofill::FormData> {
};
template <>
-struct StructTraits<autofill::mojom::FormFieldDataPredictions,
+struct StructTraits<autofill::mojom::FormFieldDataPredictionsDataView,
autofill::FormFieldDataPredictions> {
static const autofill::FormFieldData& field(
const autofill::FormFieldDataPredictions& r) {
@@ -180,7 +237,7 @@ struct StructTraits<autofill::mojom::FormFieldDataPredictions,
};
template <>
-struct StructTraits<autofill::mojom::FormDataPredictions,
+struct StructTraits<autofill::mojom::FormDataPredictionsDataView,
autofill::FormDataPredictions> {
static const autofill::FormData& data(
const autofill::FormDataPredictions& r) {
@@ -201,7 +258,7 @@ struct StructTraits<autofill::mojom::FormDataPredictions,
};
template <>
-struct StructTraits<autofill::mojom::PasswordAndRealm,
+struct StructTraits<autofill::mojom::PasswordAndRealmDataView,
autofill::PasswordAndRealm> {
static const base::string16& password(const autofill::PasswordAndRealm& r) {
return r.password;
@@ -216,7 +273,7 @@ struct StructTraits<autofill::mojom::PasswordAndRealm,
};
template <>
-struct StructTraits<autofill::mojom::UsernamesCollectionKey,
+struct StructTraits<autofill::mojom::UsernamesCollectionKeyDataView,
autofill::UsernamesCollectionKey> {
static const base::string16& username(
const autofill::UsernamesCollectionKey& r) {
@@ -237,7 +294,7 @@ struct StructTraits<autofill::mojom::UsernamesCollectionKey,
};
template <>
-struct StructTraits<autofill::mojom::PasswordFormFillData,
+struct StructTraits<autofill::mojom::PasswordFormFillDataDataView,
autofill::PasswordFormFillData> {
using UsernamesCollectionKeysValuesPair =
std::pair<std::vector<autofill::UsernamesCollectionKey>,
@@ -305,6 +362,230 @@ struct StructTraits<autofill::mojom::PasswordFormFillData,
autofill::PasswordFormFillData* out);
};
+template <>
+struct StructTraits<autofill::mojom::PasswordFormGenerationDataDataView,
+ autofill::PasswordFormGenerationData> {
+ static uint64_t form_signature(
+ const autofill::PasswordFormGenerationData& r) {
+ return r.form_signature;
+ }
+
+ static uint32_t field_signature(
+ const autofill::PasswordFormGenerationData& r) {
+ return r.field_signature;
+ }
+
+ static bool Read(autofill::mojom::PasswordFormGenerationDataDataView data,
+ autofill::PasswordFormGenerationData* out);
+};
+
+template <>
+struct StructTraits<autofill::mojom::PasswordFormDataView,
+ autofill::PasswordForm> {
+ static autofill::PasswordForm::Scheme scheme(
+ const autofill::PasswordForm& r) {
+ return r.scheme;
+ }
+
+ static const std::string& signon_realm(const autofill::PasswordForm& r) {
+ return r.signon_realm;
+ }
+
+ static const GURL& origin_with_path(const autofill::PasswordForm& r) {
+ return r.origin;
+ }
+
+ static const GURL& action(const autofill::PasswordForm& r) {
+ return r.action;
+ }
+
+ static const std::string& affiliated_web_realm(
+ const autofill::PasswordForm& r) {
+ return r.affiliated_web_realm;
+ }
+
+ static const base::string16& submit_element(const autofill::PasswordForm& r) {
+ return r.submit_element;
+ }
+
+ static const base::string16& username_element(
+ const autofill::PasswordForm& r) {
+ return r.username_element;
+ }
+
+ static bool username_marked_by_site(const autofill::PasswordForm& r) {
+ return r.username_marked_by_site;
+ }
+
+ static const base::string16& username_value(const autofill::PasswordForm& r) {
+ return r.username_value;
+ }
+
+ static const std::vector<base::string16>& other_possible_usernames(
+ const autofill::PasswordForm& r) {
+ return r.other_possible_usernames;
+ }
+
+ static const base::string16& password_element(
+ const autofill::PasswordForm& r) {
+ return r.password_element;
+ }
+
+ static const base::string16& password_value(const autofill::PasswordForm& r) {
+ return r.password_value;
+ }
+
+ static bool password_value_is_default(const autofill::PasswordForm& r) {
+ return r.password_value_is_default;
+ }
+
+ static const base::string16& new_password_element(
+ const autofill::PasswordForm& r) {
+ return r.new_password_element;
+ }
+
+ static const base::string16& new_password_value(
+ const autofill::PasswordForm& r) {
+ return r.new_password_value;
+ }
+
+ static bool new_password_value_is_default(const autofill::PasswordForm& r) {
+ return r.new_password_value_is_default;
+ }
+
+ static bool new_password_marked_by_site(const autofill::PasswordForm& r) {
+ return r.new_password_marked_by_site;
+ }
+
+ static bool preferred(const autofill::PasswordForm& r) { return r.preferred; }
+
+ static const base::Time& date_created(const autofill::PasswordForm& r) {
+ return r.date_created;
+ }
+
+ static const base::Time& date_synced(const autofill::PasswordForm& r) {
+ return r.date_synced;
+ }
+
+ static bool blacklisted_by_user(const autofill::PasswordForm& r) {
+ return r.blacklisted_by_user;
+ }
+
+ static autofill::PasswordForm::Type type(const autofill::PasswordForm& r) {
+ return r.type;
+ }
+
+ static int32_t times_used(const autofill::PasswordForm& r) {
+ return r.times_used;
+ }
+
+ static const autofill::FormData& form_data(const autofill::PasswordForm& r) {
+ return r.form_data;
+ }
+
+ static autofill::PasswordForm::GenerationUploadStatus
+ generation_upload_status(const autofill::PasswordForm& r) {
+ return r.generation_upload_status;
+ }
+
+ static const base::string16& display_name(const autofill::PasswordForm& r) {
+ return r.display_name;
+ }
+
+ static const GURL& icon_url(const autofill::PasswordForm& r) {
+ return r.icon_url;
+ }
+
+ static const url::Origin& federation_origin(const autofill::PasswordForm& r) {
+ return r.federation_origin;
+ }
+
+ static bool skip_zero_click(const autofill::PasswordForm& r) {
+ return r.skip_zero_click;
+ }
+
+ static autofill::PasswordForm::Layout layout(
+ const autofill::PasswordForm& r) {
+ return r.layout;
+ }
+
+ static bool was_parsed_using_autofill_predictions(
+ const autofill::PasswordForm& r) {
+ return r.was_parsed_using_autofill_predictions;
+ }
+
+ static bool is_public_suffix_match(const autofill::PasswordForm& r) {
+ return r.is_public_suffix_match;
+ }
+
+ static bool is_affiliation_based_match(const autofill::PasswordForm& r) {
+ return r.is_affiliation_based_match;
+ }
+
+ static bool does_look_like_signup_form(const autofill::PasswordForm& r) {
+ return r.does_look_like_signup_form;
+ }
+
+ static bool Read(autofill::mojom::PasswordFormDataView data,
+ autofill::PasswordForm* out);
+};
+
+template <>
+struct StructTraits<autofill::mojom::PasswordFormFieldPredictionMapDataView,
+ autofill::PasswordFormFieldPredictionMap> {
+ using KeysValuesPair =
+ std::pair<std::vector<autofill::FormFieldData>,
+ std::vector<autofill::PasswordFormFieldPredictionType>>;
+
+ static void* SetUpContext(const autofill::PasswordFormFieldPredictionMap& r);
+
+ static void TearDownContext(const autofill::PasswordFormFieldPredictionMap& r,
+ void* context);
+
+ static const std::vector<autofill::FormFieldData>& keys(
+ const autofill::PasswordFormFieldPredictionMap& r,
+ void* context) {
+ return static_cast<KeysValuesPair*>(context)->first;
+ }
+
+ static const std::vector<autofill::PasswordFormFieldPredictionType>& values(
+ const autofill::PasswordFormFieldPredictionMap& r,
+ void* context) {
+ return static_cast<KeysValuesPair*>(context)->second;
+ }
+
+ static bool Read(autofill::mojom::PasswordFormFieldPredictionMapDataView data,
+ autofill::PasswordFormFieldPredictionMap* out);
+};
+
+template <>
+struct StructTraits<autofill::mojom::FormsPredictionsMapDataView,
+ autofill::FormsPredictionsMap> {
+ using KeysValuesPair =
+ std::pair<std::vector<autofill::FormData>,
+ std::vector<autofill::PasswordFormFieldPredictionMap>>;
+
+ static void* SetUpContext(const autofill::FormsPredictionsMap& r);
+
+ static void TearDownContext(const autofill::FormsPredictionsMap& r,
+ void* context);
+
+ static const std::vector<autofill::FormData>& keys(
+ const autofill::FormsPredictionsMap& r,
+ void* context) {
+ return static_cast<KeysValuesPair*>(context)->first;
+ }
+
+ static const std::vector<autofill::PasswordFormFieldPredictionMap>& values(
+ const autofill::FormsPredictionsMap& r,
+ void* context) {
+ return static_cast<KeysValuesPair*>(context)->second;
+ }
+
+ static bool Read(autofill::mojom::FormsPredictionsMapDataView data,
+ autofill::FormsPredictionsMap* out);
+};
+
} // namespace mojo
#endif // COMPONENTS_AUTOFILL_CONTENT_PUBLIC_INTERFACES_AUTOFILL_TYPES_STRUCT_TRAITS_H_
diff --git a/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits_unittest.cc b/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits_unittest.cc
index 61a44168176..70136683eca 100644
--- a/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits_unittest.cc
+++ b/chromium/components/autofill/content/public/cpp/autofill_types_struct_traits_unittest.cc
@@ -9,6 +9,7 @@
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/signatures_util.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -72,13 +73,88 @@ void CreateTestPasswordFormFillData(PasswordFormFillData* fill_data) {
fill_data->is_possible_change_password_form = false;
}
+void CreateTestPasswordForm(PasswordForm* form) {
+ form->scheme = PasswordForm::Scheme::SCHEME_HTML;
+ form->signon_realm = "https://foo.com/";
+ form->origin = GURL("https://foo.com/");
+ form->action = GURL("https://foo.com/login");
+ form->affiliated_web_realm = "https://foo.com/";
+ form->submit_element = base::ASCIIToUTF16("test_submit");
+ form->username_element = base::ASCIIToUTF16("username");
+ form->username_marked_by_site = true;
+ form->username_value = base::ASCIIToUTF16("test@gmail.com");
+ form->other_possible_usernames.push_back(base::ASCIIToUTF16("Jerry_1"));
+ form->other_possible_usernames.push_back(base::ASCIIToUTF16("Jerry_2"));
+ form->password_element = base::ASCIIToUTF16("password");
+ form->password_value = base::ASCIIToUTF16("test");
+ form->password_value_is_default = true;
+ form->new_password_element = base::ASCIIToUTF16("new_password");
+ form->new_password_value = base::ASCIIToUTF16("new_password_value");
+ form->new_password_value_is_default = false;
+ form->new_password_marked_by_site = false;
+ form->preferred = false;
+ form->date_created = base::Time::Now();
+ form->date_synced = base::Time::Now();
+ form->blacklisted_by_user = false;
+ form->type = PasswordForm::Type::TYPE_GENERATED;
+ form->times_used = 999;
+ test::CreateTestAddressFormData(&form->form_data);
+ form->generation_upload_status =
+ PasswordForm::GenerationUploadStatus::POSITIVE_SIGNAL_SENT;
+ form->display_name = base::ASCIIToUTF16("test display name");
+ form->icon_url = GURL("https://foo.com/icon.png");
+ form->federation_origin =
+ url::Origin::UnsafelyCreateOriginWithoutNormalization(
+ "http", "www.google.com", 80);
+ form->skip_zero_click = false;
+ form->layout = PasswordForm::Layout::LAYOUT_LOGIN_AND_SIGNUP;
+ form->was_parsed_using_autofill_predictions = false;
+ form->is_public_suffix_match = true;
+ form->is_affiliation_based_match = true;
+ form->does_look_like_signup_form = true;
+}
+
+void CreateTestFormsPredictionsMap(FormsPredictionsMap* predictions) {
+ FormsPredictionsMap& result_map = *predictions;
+ // 1st element.
+ FormData form_data;
+ test::CreateTestAddressFormData(&form_data);
+ ASSERT_TRUE(form_data.fields.size() >= 4);
+ result_map[form_data][form_data.fields[0]] =
+ PasswordFormFieldPredictionType::PREDICTION_USERNAME;
+ result_map[form_data][form_data.fields[1]] =
+ PasswordFormFieldPredictionType::PREDICTION_CURRENT_PASSWORD;
+ result_map[form_data][form_data.fields[2]] =
+ PasswordFormFieldPredictionType::PREDICTION_NEW_PASSWORD;
+ result_map[form_data][form_data.fields[3]] =
+ PasswordFormFieldPredictionType::PREDICTION_NOT_PASSWORD;
+
+ // 2nd element.
+ form_data.fields.clear();
+ result_map[form_data] =
+ std::map<FormFieldData, PasswordFormFieldPredictionType>();
+
+ // 3rd element.
+ FormFieldData field_data;
+ test::CreateTestSelectField("TestLabel1", "TestName1", "TestValue1", kOptions,
+ kOptions, 4, &field_data);
+ form_data.fields.push_back(field_data);
+ test::CreateTestSelectField("TestLabel2", "TestName2", "TestValue2", kOptions,
+ kOptions, 4, &field_data);
+ form_data.fields.push_back(field_data);
+ result_map[form_data][form_data.fields[0]] =
+ PasswordFormFieldPredictionType::PREDICTION_NEW_PASSWORD;
+ result_map[form_data][form_data.fields[1]] =
+ PasswordFormFieldPredictionType::PREDICTION_CURRENT_PASSWORD;
+}
+
void CheckEqualPasswordFormFillData(const PasswordFormFillData& expected,
const PasswordFormFillData& actual) {
EXPECT_EQ(expected.name, actual.name);
EXPECT_EQ(expected.origin, actual.origin);
EXPECT_EQ(expected.action, actual.action);
- EXPECT_TRUE(expected.username_field.SameFieldAs(actual.username_field));
- EXPECT_TRUE(expected.password_field.SameFieldAs(actual.password_field));
+ EXPECT_EQ(expected.username_field, actual.username_field);
+ EXPECT_EQ(expected.password_field, actual.password_field);
EXPECT_EQ(expected.preferred_realm, actual.preferred_realm);
{
@@ -119,6 +195,13 @@ void CheckEqualPasswordFormFillData(const PasswordFormFillData& expected,
actual.is_possible_change_password_form);
}
+void CheckEqualPasswordFormGenerationData(
+ const PasswordFormGenerationData& expected,
+ const PasswordFormGenerationData& actual) {
+ EXPECT_EQ(expected.form_signature, actual.form_signature);
+ EXPECT_EQ(expected.field_signature, actual.field_signature);
+}
+
} // namespace
class AutofillTypeTraitsTestImpl : public testing::Test,
@@ -159,6 +242,23 @@ class AutofillTypeTraitsTestImpl : public testing::Test,
callback.Run(s);
}
+ void PassPasswordFormGenerationData(
+ const PasswordFormGenerationData& s,
+ const PassPasswordFormGenerationDataCallback& callback) override {
+ callback.Run(s);
+ }
+
+ void PassPasswordForm(const PasswordForm& s,
+ const PassPasswordFormCallback& callback) override {
+ callback.Run(s);
+ }
+
+ void PassFormsPredictionsMap(
+ const FormsPredictionsMap& s,
+ const PassFormsPredictionsMapCallback& callback) override {
+ callback.Run(s);
+ }
+
private:
base::MessageLoop loop_;
@@ -168,16 +268,14 @@ class AutofillTypeTraitsTestImpl : public testing::Test,
void ExpectFormFieldData(const FormFieldData& expected,
const base::Closure& closure,
const FormFieldData& passed) {
- EXPECT_TRUE(expected.SameFieldAs(passed));
- EXPECT_EQ(expected.option_values, passed.option_values);
- EXPECT_EQ(expected.option_contents, passed.option_contents);
+ EXPECT_EQ(expected, passed);
closure.Run();
}
void ExpectFormData(const FormData& expected,
const base::Closure& closure,
const FormData& passed) {
- EXPECT_TRUE(expected.SameFormAs(passed));
+ EXPECT_EQ(expected, passed);
closure.Run();
}
@@ -202,10 +300,43 @@ void ExpectPasswordFormFillData(const PasswordFormFillData& expected,
closure.Run();
}
+void ExpectPasswordFormGenerationData(
+ const PasswordFormGenerationData& expected,
+ const base::Closure& closure,
+ const PasswordFormGenerationData& passed) {
+ CheckEqualPasswordFormGenerationData(expected, passed);
+ closure.Run();
+}
+
+void ExpectPasswordForm(const PasswordForm& expected,
+ const base::Closure& closure,
+ const PasswordForm& passed) {
+ EXPECT_EQ(expected, passed);
+ closure.Run();
+}
+
+void ExpectFormsPredictionsMap(const FormsPredictionsMap& expected,
+ const base::Closure& closure,
+ const FormsPredictionsMap& passed) {
+ EXPECT_EQ(expected, passed);
+ closure.Run();
+}
+
TEST_F(AutofillTypeTraitsTestImpl, PassFormFieldData) {
FormFieldData input;
test::CreateTestSelectField("TestLabel", "TestName", "TestValue", kOptions,
kOptions, 4, &input);
+ // Set other attributes to check if they are passed correctly.
+ input.autocomplete_attribute = "on";
+ input.placeholder = base::ASCIIToUTF16("placeholder");
+ input.css_classes = base::ASCIIToUTF16("class1");
+ input.max_length = 12345;
+ input.is_autofilled = true;
+ input.check_status = FormFieldData::CHECKED;
+ input.should_autocomplete = true;
+ input.role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION;
+ input.text_direction = base::i18n::RIGHT_TO_LEFT;
+ input.properties_mask = FieldPropertiesFlags::HAD_FOCUS;
base::RunLoop loop;
mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy();
@@ -269,4 +400,42 @@ TEST_F(AutofillTypeTraitsTestImpl, PassPasswordFormFillData) {
loop.Run();
}
+TEST_F(AutofillTypeTraitsTestImpl, PassPasswordFormGenerationData) {
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+ FormSignature form_signature = CalculateFormSignature(form);
+ FieldSignature field_signature =
+ CalculateFieldSignatureForField(form.fields[0]);
+ PasswordFormGenerationData input{form_signature, field_signature};
+
+ base::RunLoop loop;
+ mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy();
+ proxy->PassPasswordFormGenerationData(
+ input,
+ base::Bind(&ExpectPasswordFormGenerationData, input, loop.QuitClosure()));
+ loop.Run();
+}
+
+TEST_F(AutofillTypeTraitsTestImpl, PassPasswordForm) {
+ PasswordForm input;
+ CreateTestPasswordForm(&input);
+
+ base::RunLoop loop;
+ mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy();
+ proxy->PassPasswordForm(
+ input, base::Bind(&ExpectPasswordForm, input, loop.QuitClosure()));
+ loop.Run();
+}
+
+TEST_F(AutofillTypeTraitsTestImpl, PassFormsPredictionsMap) {
+ FormsPredictionsMap input;
+ CreateTestFormsPredictionsMap(&input);
+
+ base::RunLoop loop;
+ mojom::TypeTraitsTestPtr proxy = GetTypeTraitsTestProxy();
+ proxy->PassFormsPredictionsMap(
+ input, base::Bind(&ExpectFormsPredictionsMap, input, loop.QuitClosure()));
+ loop.Run();
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/public/interfaces/BUILD.gn b/chromium/components/autofill/content/public/interfaces/BUILD.gn
index 3a77091da0d..ea583e7bb5d 100644
--- a/chromium/components/autofill/content/public/interfaces/BUILD.gn
+++ b/chromium/components/autofill/content/public/interfaces/BUILD.gn
@@ -12,6 +12,8 @@ mojom("interfaces") {
public_deps = [
":types",
+ "//mojo/common:common_custom_types",
+ "//ui/gfx/geometry/mojo",
]
}
@@ -21,7 +23,9 @@ mojom("types") {
]
public_deps = [
+ "//mojo/common:common_custom_types",
"//url/mojo:url_mojom_gurl",
+ "//url/mojo:url_mojom_origin",
]
}
diff --git a/chromium/components/autofill/content/public/interfaces/autofill_agent.mojom b/chromium/components/autofill/content/public/interfaces/autofill_agent.mojom
index 40c501dd0e0..f94ef04bb37 100644
--- a/chromium/components/autofill/content/public/interfaces/autofill_agent.mojom
+++ b/chromium/components/autofill/content/public/interfaces/autofill_agent.mojom
@@ -4,8 +4,104 @@
module autofill.mojom;
+import "components/autofill/content/public/interfaces/autofill_types.mojom";
+import "mojo/common/common_custom_types.mojom";
+
+// There is one instance of this interface per render frame in the render
+// process.
interface AutofillAgent {
// Tells the render frame that a user gesture was observed
// somewhere in the tab (including in a different frame).
FirstUserGestureObservedInTab();
+
+ // Instructs the renderer to fill the active form with the given form data.
+ // Please refer AutofillDriver.QueryFormFieldAutofill comments about the |id|.
+ FillForm(int32 id, FormData form);
+
+ // Instructs the renderer to preview the active form with the given form data.
+ // Please refer AutofillDriver.QueryFormFieldAutofill comments about the |id|.
+ PreviewForm(int32 id, FormData form);
+
+ // Sends the heuristic and server field type predictions to the renderer.
+ FieldTypePredictionsAvailable(array<FormDataPredictions> forms);
+
+ // Clears the currently displayed Autofill results.
+ ClearForm();
+
+ // Tells the renderer that the Autofill previewed form should be cleared.
+ ClearPreviewedForm();
+
+ // Sets the currently selected node's value.
+ FillFieldWithValue(mojo.common.mojom.String16 value);
+
+ // Sets the suggested value for the currently previewed node.
+ PreviewFieldWithValue(mojo.common.mojom.String16 value);
+
+ // Sets the currently selected node's value to be the given data list value.
+ AcceptDataListSuggestion(mojo.common.mojom.String16 value);
+
+ // Tells the renderer to fill the username and password with with given
+ // values.
+ FillPasswordSuggestion(mojo.common.mojom.String16 username,
+ mojo.common.mojom.String16 password);
+
+ // Tells the renderer to preview the username and password with the given
+ // values.
+ PreviewPasswordSuggestion(mojo.common.mojom.String16 username,
+ mojo.common.mojom.String16 password);
+
+ // Sent when a password form is initially detected and suggestions should be
+ // shown. Used by the fill-on-select experiment.
+ // |key| is the unique id associated with the password form fill data.
+ ShowInitialPasswordAccountSuggestions(int32 key,
+ PasswordFormFillData form_data);
+};
+
+// There is one instance of this interface per render frame in the render
+// process.
+interface PasswordAutofillAgent {
+ // Fills a password form and prepare field autocomplete for multiple
+ // matching logins. Lets the renderer know if it should disable the popup
+ // because the browser process will own the popup UI. |key| serves for
+ // identifying the fill form data in subsequent
+ // ShowPasswordSuggestions messages to the browser.
+ FillPasswordForm(int32 key, PasswordFormFillData form_data);
+
+ // Notification to start (|active| == true) or stop (|active| == false)
+ // logging the decisions made about saving the password.
+ SetLoggingState(bool active);
+
+ // Sent when Autofill manager gets the query response from the Autofill server
+ // which contains information about username and password for some forms.
+ // |predictions| maps forms to their username fields.
+ AutofillUsernameAndPasswordDataReceived(FormsPredictionsMap predictions);
+
+ // Tells the renderer to find the focused password form (assuming it exists).
+ // Renderer is expected to return the found password form. If no password form
+ // is focused, the response will contain an empty |autofill::PasswordForm|.
+ FindFocusedPasswordForm() => (PasswordForm form);
+};
+
+// There is one instance of this interface per render frame in the render
+// process.
+interface PasswordGenerationAgent {
+ // Tells the renderer to populate the correct password fields with this
+ // generated password.
+ GeneratedPasswordAccepted(mojo.common.mojom.String16 generated_password);
+
+ // Tells the renderer to find a focused element, and if it is a password field
+ // eligible for generation then to trigger generation by responding to the
+ // browser with the message |ShowPasswordGenerationPopup|.
+ UserTriggeredGeneratePassword();
+
+ // Tells the renderer that this password form is not blacklisted. A form can
+ // be blacklisted if a user chooses "never save passwords for this site".
+ FormNotBlacklisted(PasswordForm form);
+
+ // Sent when Autofill manager gets the query response from the Autofill server
+ // and there are fields classified for password generation in the response.
+ FoundFormsEligibleForGeneration(array<PasswordFormGenerationData> forms);
+
+ // Tells the renderer to enable the form classifier.
+ AllowToRunFormClassifier();
};
diff --git a/chromium/components/autofill/content/public/interfaces/autofill_driver.mojom b/chromium/components/autofill/content/public/interfaces/autofill_driver.mojom
index 3724043db40..9ce701d72da 100644
--- a/chromium/components/autofill/content/public/interfaces/autofill_driver.mojom
+++ b/chromium/components/autofill/content/public/interfaces/autofill_driver.mojom
@@ -4,7 +4,109 @@
module autofill.mojom;
+import "components/autofill/content/public/interfaces/autofill_types.mojom";
+import "mojo/common/common_custom_types.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
+
+// There is one instance of this interface per render frame host in the browser
+// process.
interface AutofillDriver {
// Notification that there has been a user gesture.
FirstUserGestureObserved();
+
+ // Notification that forms have been seen that are candidates for
+ // filling/submitting by the AutofillManager.
+ FormsSeen(array<FormData> forms, mojo.common.mojom.TimeTicks timestamp);
+
+ // Notification that a form is about to be submitted. The user hit the button.
+ WillSubmitForm(FormData form, mojo.common.mojom.TimeTicks timestamp);
+
+ // Notification that a form has been submitted.
+ FormSubmitted(FormData form);
+
+ // Notification that a form field's value has changed.
+ TextFieldDidChange(FormData form,
+ FormFieldData field,
+ mojo.common.mojom.TimeTicks timestamp);
+
+ // Queries the browser for Autofill suggestions for a form input field.
+ // |id| is the request ID which is used to map responses correctly.
+ QueryFormFieldAutofill(int32 id,
+ FormData form,
+ FormFieldData field,
+ gfx.mojom.RectF bounding_box);
+
+ // Instructs the browser to hide the Autofill popup if it is open.
+ HidePopup();
+
+ // Sent immediately after the renderer receives a ping IPC.
+ PingAck();
+
+ // Sent when the current form is no longer focused.
+ FocusNoLongerOnForm();
+
+ // Sent when a form is filled with Autofill suggestions.
+ DidFillAutofillFormData(FormData form, mojo.common.mojom.TimeTicks timestamp);
+
+ // Sent when a form is previewed with Autofill suggestions.
+ DidPreviewAutofillFormData();
+
+ // Sent when a text field is done editing.
+ DidEndTextFieldEditing();
+
+ // Informs browser of data list values for the current field.
+ SetDataList(array<mojo.common.mojom.String16> values,
+ array<mojo.common.mojom.String16> labels);
+};
+
+// There is one instance of this interface per render frame host in the browser
+// process.
+interface PasswordManagerDriver {
+ // A ping to the browser that PasswordAutofillAgent was constructed. As a
+ // consequence, the browser sends SetLoggingState with the current
+ // state of the logging activity.
+ PasswordAutofillAgentConstructed();
+
+ // Notification that password forms have been seen that are candidates for
+ // filling/submitting by the password manager.
+ PasswordFormsParsed(array<PasswordForm> forms);
+
+ // Notification that initial layout has occurred and the following password
+ // forms are visible on the page (e.g. not set to display:none.), and whether
+ // all frames in the page have been rendered.
+ PasswordFormsRendered(array<PasswordForm> visible_forms,
+ bool did_stop_loading);
+
+ // Notification that this password form was submitted by the user.
+ PasswordFormSubmitted(PasswordForm password_form);
+
+ // Notification that in-page navigation happened and at this moment we have
+ // filled password form. We use this as a signal for successful login.
+ InPageNavigation(PasswordForm password_form);
+
+ // Sends |log| to browser for displaying to the user. Only strings passed as
+ // an argument to methods overriding SavePasswordProgressLogger::SendLog may
+ // become |log|, because those are guaranteed to be sanitized.
+ // Never pass a free-form string as |log|.
+ RecordSavePasswordProgress(string log);
+
+ // Instructs the browser to show a popup with suggestions filled from data
+ // associated with |key|. The popup will use |text_direction| for displaying
+ // text.
+ ShowPasswordSuggestions(int32 key, TextDirection text_direction,
+ mojo.common.mojom.String16 typed_username,
+ int32 options, gfx.mojom.RectF bounds);
+
+
+ // Instructs the browser to presave the form with generated password.
+ PresaveGeneratedPassword(PasswordForm password_form);
+
+ // Instructs the browser that form no longer contains a generated password and
+ // the presaved form should be removed.
+ PasswordNoLongerGenerated(PasswordForm password_form);
+
+ // Sends the outcome of HTML parsing based form classifier that detects the
+ // forms where password generation should be available.
+ SaveGenerationFieldDetectedByClassifier(
+ PasswordForm password_form, mojo.common.mojom.String16 generation_field);
};
diff --git a/chromium/components/autofill/content/public/interfaces/autofill_types.mojom b/chromium/components/autofill/content/public/interfaces/autofill_types.mojom
index 4473f558ee9..91905f2d84d 100644
--- a/chromium/components/autofill/content/public/interfaces/autofill_types.mojom
+++ b/chromium/components/autofill/content/public/interfaces/autofill_types.mojom
@@ -4,6 +4,8 @@
module autofill.mojom;
+import "mojo/common/common_custom_types.mojom";
+import "url/mojo/origin.mojom";
import "url/mojo/url.mojom";
// autofill::FormFieldData::CheckStatus
@@ -27,6 +29,45 @@ enum TextDirection {
TEXT_DIRECTION_NUM_DIRECTIONS = 3
};
+// autofill::PasswordForm::GenerationUploadStatus
+enum GenerationUploadStatus {
+ NO_SIGNAL_SENT,
+ POSITIVE_SIGNAL_SENT,
+ NEGATIVE_SIGNAL_SENT,
+ UNKNOWN_STATUS = 10
+};
+
+// autofill::PasswordForm::Layout
+enum PasswordFormLayout {
+ LAYOUT_OTHER,
+ LAYOUT_LOGIN_AND_SIGNUP
+};
+
+// autofill::PasswordForm::Type
+enum PasswordFormType {
+ TYPE_MANUAL,
+ TYPE_GENERATED,
+ TYPE_API
+};
+
+// autofill::PasswordForm::Scheme
+enum PasswordFormScheme {
+ SCHEME_HTML,
+ SCHEME_BASIC,
+ SCHEME_DIGEST,
+ SCHEME_OTHER,
+ SCHEME_USERNAME_ONLY
+};
+
+// autofill::PasswordFormFieldPredictionType
+enum PasswordFormFieldPredictionType {
+ PREDICTION_USERNAME,
+ PREDICTION_CURRENT_PASSWORD,
+ PREDICTION_NEW_PASSWORD,
+ PREDICTION_NOT_PASSWORD
+};
+
+// autofill::FormFieldData
struct FormFieldData {
string label;
string name;
@@ -34,6 +75,8 @@ struct FormFieldData {
string form_control_type;
string autocomplete_attribute;
string placeholder;
+ string css_classes;
+ uint32 properties_mask;
uint64 max_length;
bool is_autofilled;
@@ -47,6 +90,7 @@ struct FormFieldData {
array<string> option_contents;
};
+// autofill::FormData
struct FormData {
string name;
url.mojom.Url origin;
@@ -56,6 +100,7 @@ struct FormData {
array<FormFieldData> fields;
};
+// autofill::FormFieldDataPredictions
struct FormFieldDataPredictions {
FormFieldData field;
string signature;
@@ -65,23 +110,27 @@ struct FormFieldDataPredictions {
string parseable_name;
};
+// autofill::FormDataPredictions
struct FormDataPredictions {
FormData data;
string signature;
array<FormFieldDataPredictions> fields;
};
+// autofill::PasswordAndRealm
struct PasswordAndRealm {
string password;
string realm;
};
+// autofill::UsernamesCollectionKey
struct UsernamesCollectionKey {
string username;
string password;
string realm;
};
+// autofill::PasswordFormFillData
struct PasswordFormFillData {
string name;
url.mojom.Url origin;
@@ -90,6 +139,7 @@ struct PasswordFormFillData {
FormFieldData password_field;
string preferred_realm;
map<string, PasswordAndRealm> additional_logins;
+ // TODO(leonhsl): Use map directly after http://crbug.com/628104 solved.
// Keys for std::map<UsernamesCollectionKey, std::vector<base::string16>>
array<UsernamesCollectionKey> other_possible_usernames_keys;
// Values for std::map<UsernamesCollectionKey, std::vector<base::string16>>
@@ -97,3 +147,63 @@ struct PasswordFormFillData {
bool wait_for_username;
bool is_possible_change_password_form;
};
+
+// autofill::PasswordFormGenerationData
+struct PasswordFormGenerationData {
+ uint64 form_signature;
+ uint32 field_signature;
+};
+
+// autofill::PasswordForm
+struct PasswordForm {
+ PasswordFormScheme scheme;
+ string signon_realm;
+ url.mojom.Url origin_with_path;
+ url.mojom.Url action;
+ string affiliated_web_realm;
+ string submit_element;
+ string username_element;
+ bool username_marked_by_site;
+ string username_value;
+ array<string> other_possible_usernames;
+ string password_element;
+ string password_value;
+ bool password_value_is_default;
+ string new_password_element;
+ string new_password_value;
+ bool new_password_value_is_default;
+ bool new_password_marked_by_site;
+ bool preferred;
+ mojo.common.mojom.Time date_created;
+ mojo.common.mojom.Time date_synced;
+ bool blacklisted_by_user;
+ PasswordFormType type;
+ int32 times_used;
+ FormData form_data;
+ GenerationUploadStatus generation_upload_status;
+ string display_name;
+ url.mojom.Url icon_url;
+ url.mojom.Origin federation_origin;
+ bool skip_zero_click;
+ PasswordFormLayout layout;
+ bool was_parsed_using_autofill_predictions;
+ bool is_public_suffix_match;
+ bool is_affiliation_based_match;
+ bool does_look_like_signup_form;
+};
+
+// TODO(leonhsl): Use map directly after http://crbug.com/628104 solved.
+// autofill::PasswordFormFieldPredictionMap
+// --> std::map<FormFieldData, PasswordFormFieldPredictionType>
+struct PasswordFormFieldPredictionMap {
+ array<FormFieldData> keys;
+ array<PasswordFormFieldPredictionType> values;
+};
+
+// TODO(leonhsl): Use map directly after http://crbug.com/628104 solved.
+// autofill::FormsPredictionsMap
+// --> std::map<FormData, PasswordFormFieldPredictionMap>
+struct FormsPredictionsMap {
+ array<FormData> keys;
+ array<PasswordFormFieldPredictionMap> values;
+};
diff --git a/chromium/components/autofill/content/public/interfaces/test_autofill_types.mojom b/chromium/components/autofill/content/public/interfaces/test_autofill_types.mojom
index 54b61cc0671..70c18e7f06e 100644
--- a/chromium/components/autofill/content/public/interfaces/test_autofill_types.mojom
+++ b/chromium/components/autofill/content/public/interfaces/test_autofill_types.mojom
@@ -11,5 +11,8 @@ interface TypeTraitsTest {
PassFormFieldData(FormFieldData s) => (FormFieldData passed);
PassFormDataPredictions(FormDataPredictions s) => (FormDataPredictions passed);
PassFormFieldDataPredictions(FormFieldDataPredictions s) => (FormFieldDataPredictions passed);
+ PassPasswordForm(PasswordForm s) => (PasswordForm passed);
PassPasswordFormFillData(PasswordFormFillData s) => (PasswordFormFillData passed);
+ PassFormsPredictionsMap(FormsPredictionsMap s) => (FormsPredictionsMap passed);
+ PassPasswordFormGenerationData(PasswordFormGenerationData s) => (PasswordFormGenerationData passed);
};
diff --git a/chromium/components/autofill/content/renderer/BUILD.gn b/chromium/components/autofill/content/renderer/BUILD.gn
index 866fc7d1921..ade24a61992 100644
--- a/chromium/components/autofill/content/renderer/BUILD.gn
+++ b/chromium/components/autofill/content/renderer/BUILD.gn
@@ -36,6 +36,7 @@ static_library("renderer") {
"//content/public/renderer",
"//google_apis",
"//ipc",
+ "//mojo/common:common_base",
"//net",
"//services/shell/public/cpp",
"//skia",
@@ -48,7 +49,7 @@ static_library("renderer") {
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"test_password_autofill_agent.cc",
@@ -76,8 +77,7 @@ source_set("unit_tests") {
deps = [
":test_support",
- "//components/autofill/content/common",
- "//ipc:test_support",
+ "//components/autofill/content/public/interfaces",
"//testing/gtest",
]
}
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc
index 1254112a0bf..2a20a17c955 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent.cc
@@ -21,7 +21,6 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
-#include "components/autofill/content/common/autofill_messages.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/page_click_tracker.h"
#include "components/autofill/content/renderer/password_autofill_agent.h"
@@ -38,7 +37,6 @@
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/save_password_progress_logger.h"
#include "content/public/common/content_switches.h"
-#include "content/public/common/ssl_status.h"
#include "content/public/common/url_constants.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
@@ -110,31 +108,7 @@ bool IsSingleClickEnabled() {
void GetDataListSuggestions(const WebInputElement& element,
std::vector<base::string16>* values,
std::vector<base::string16>* labels) {
- WebElementCollection options = element.dataListOptions();
- if (options.isNull())
- return;
-
- // If the field accepts multiple email addresses, filter only on the last one.
- base::string16 prefix = element.editingValue();
- if (element.isMultiple() && element.isEmailField()) {
- std::vector<base::string16> parts = base::SplitString(
- prefix, base::ASCIIToUTF16(","), base::TRIM_WHITESPACE,
- base::SPLIT_WANT_ALL);
- if (!parts.empty()) {
- base::TrimWhitespace(parts[parts.size() - 1], base::TRIM_LEADING,
- &prefix);
- }
- }
-
- // Prefix filtering.
- prefix = base::i18n::ToLower(prefix);
- for (WebOptionElement option = options.firstItem().to<WebOptionElement>();
- !option.isNull(); option = options.nextItem().to<WebOptionElement>()) {
- if (!base::StartsWith(base::i18n::ToLower(base::string16(option.value())),
- prefix, base::CompareCase::SENSITIVE) ||
- !element.isValidValue(option.value()))
- continue;
-
+ for (const auto& option : element.filteredDataListOptions()) {
values->push_back(option.value());
if (option.value() != option.label())
labels->push_back(option.label());
@@ -179,8 +153,10 @@ AutofillAgent::AutofillAgent(content::RenderFrame* render_frame,
ignore_text_changes_(false),
is_popup_possibly_visible_(false),
is_generation_popup_possibly_visible_(false),
+ binding_(this),
weak_ptr_factory_(this) {
render_frame->GetWebFrame()->setAutofillClient(this);
+ password_autofill_agent->SetAutofillAgent(this);
// AutofillAgent is guaranteed to outlive |render_frame|.
render_frame->GetInterfaceRegistry()->AddInterface(
@@ -196,7 +172,7 @@ AutofillAgent::AutofillAgent(content::RenderFrame* render_frame,
AutofillAgent::~AutofillAgent() {}
void AutofillAgent::BindRequest(mojom::AutofillAgentRequest request) {
- bindings_.AddBinding(this, std::move(request));
+ binding_.Bind(std::move(request));
}
bool AutofillAgent::FormDataCompare::operator()(const FormData& lhs,
@@ -205,31 +181,6 @@ bool AutofillAgent::FormDataCompare::operator()(const FormData& lhs,
std::tie(rhs.name, rhs.origin, rhs.action, rhs.is_form_tag);
}
-bool AutofillAgent::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message)
- IPC_MESSAGE_HANDLER(AutofillMsg_FillForm, OnFillForm)
- IPC_MESSAGE_HANDLER(AutofillMsg_PreviewForm, OnPreviewForm)
- IPC_MESSAGE_HANDLER(AutofillMsg_FieldTypePredictionsAvailable,
- OnFieldTypePredictionsAvailable)
- IPC_MESSAGE_HANDLER(AutofillMsg_ClearForm, OnClearForm)
- IPC_MESSAGE_HANDLER(AutofillMsg_ClearPreviewedForm, OnClearPreviewedForm)
- IPC_MESSAGE_HANDLER(AutofillMsg_FillFieldWithValue, OnFillFieldWithValue)
- IPC_MESSAGE_HANDLER(AutofillMsg_PreviewFieldWithValue,
- OnPreviewFieldWithValue)
- IPC_MESSAGE_HANDLER(AutofillMsg_AcceptDataListSuggestion,
- OnAcceptDataListSuggestion)
- IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordSuggestion,
- OnFillPasswordSuggestion)
- IPC_MESSAGE_HANDLER(AutofillMsg_PreviewPasswordSuggestion,
- OnPreviewPasswordSuggestion)
- IPC_MESSAGE_HANDLER(AutofillMsg_ShowInitialPasswordAccountSuggestions,
- OnShowInitialPasswordAccountSuggestions);
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
void AutofillAgent::DidCommitProvisionalLoad(bool is_new_navigation,
bool is_same_page_navigation) {
blink::WebFrame* frame = render_frame()->GetWebFrame();
@@ -275,7 +226,7 @@ void AutofillAgent::FocusedNodeChanged(const WebNode& node) {
if (!last_interacted_form_.isNull()) {
// Focus moved away from the last interacted form to somewhere else on
// the page.
- Send(new AutofillHostMsg_FocusNoLongerOnForm(routing_id()));
+ GetAutofillDriver()->FocusNoLongerOnForm();
}
return;
}
@@ -287,7 +238,7 @@ void AutofillAgent::FocusedNodeChanged(const WebNode& node) {
(!element || last_interacted_form_ != element->form())) {
// The focused element is not part of the last interacted form (could be
// in a different form).
- Send(new AutofillHostMsg_FocusNoLongerOnForm(routing_id()));
+ GetAutofillDriver()->FocusNoLongerOnForm();
return;
}
@@ -318,16 +269,17 @@ void AutofillAgent::FireHostSubmitEvents(const FormData& form_data,
// because forms with a submit handler may fire both WillSendSubmitEvent
// and WillSubmitForm, and we don't want duplicate messages.
if (!submitted_forms_.count(form_data)) {
- Send(new AutofillHostMsg_WillSubmitForm(routing_id(), form_data,
- base::TimeTicks::Now()));
+ GetAutofillDriver()->WillSubmitForm(form_data, base::TimeTicks::Now());
submitted_forms_.insert(form_data);
}
- if (form_submitted)
- Send(new AutofillHostMsg_FormSubmitted(routing_id(), form_data));
+ if (form_submitted) {
+ GetAutofillDriver()->FormSubmitted(form_data);
+ }
}
void AutofillAgent::Shutdown() {
+ binding_.Close();
legacy_.Shutdown();
weak_ptr_factory_.InvalidateWeakPtrs();
}
@@ -337,11 +289,14 @@ void AutofillAgent::FocusChangeComplete() {
WebElement focused_element;
if (!doc.isNull())
focused_element = doc.focusedElement();
-
- if (!focused_element.isNull() && password_generation_agent_ &&
- password_generation_agent_->FocusedNodeHasChanged(focused_element)) {
- is_generation_popup_possibly_visible_ = true;
- is_popup_possibly_visible_ = true;
+ if (!focused_element.isNull()) {
+ if (password_generation_agent_ &&
+ password_generation_agent_->FocusedNodeHasChanged(focused_element)) {
+ is_generation_popup_possibly_visible_ = true;
+ is_popup_possibly_visible_ = true;
+ }
+ if (password_autofill_agent_)
+ password_autofill_agent_->FocusedNodeHasChanged(focused_element);
}
}
@@ -375,8 +330,7 @@ void AutofillAgent::FormControlElementClicked(
}
void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) {
- password_autofill_agent_->TextFieldDidEndEditing(element);
- Send(new AutofillHostMsg_DidEndTextFieldEditing(routing_id()));
+ GetAutofillDriver()->DidEndTextFieldEditing();
}
void AutofillAgent::textFieldDidChange(const WebFormControlElement& element) {
@@ -441,8 +395,8 @@ void AutofillAgent::TextFieldDidChangeImpl(
FormFieldData field;
if (form_util::FindFormAndFieldForFormControlElement(element, &form,
&field)) {
- Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field,
- base::TimeTicks::Now()));
+ GetAutofillDriver()->TextFieldDidChange(form, field,
+ base::TimeTicks::Now());
}
}
@@ -473,11 +427,10 @@ void AutofillAgent::dataListOptionsChanged(const WebInputElement& element) {
void AutofillAgent::firstUserGestureObserved() {
password_autofill_agent_->FirstUserGestureObserved();
- ConnectToMojoAutofillDriverIfNeeded();
- mojo_autofill_driver_->FirstUserGestureObserved();
+ GetAutofillDriver()->FirstUserGestureObserved();
}
-void AutofillAgent::AcceptDataListSuggestion(
+void AutofillAgent::DoAcceptDataListSuggestion(
const base::string16& suggested_value) {
WebInputElement* input_element = toWebInputElement(&element_);
DCHECK(input_element);
@@ -500,22 +453,20 @@ void AutofillAgent::AcceptDataListSuggestion(
}
}
last_part.append(suggested_value);
- parts[parts.size() - 1] = last_part;
+ parts.back() = last_part;
new_value = base::JoinString(parts, base::ASCIIToUTF16(","));
}
- FillFieldWithValue(new_value, input_element);
+ DoFillFieldWithValue(new_value, input_element);
}
-void AutofillAgent::OnFieldTypePredictionsAvailable(
- const std::vector<FormDataPredictions>& forms) {
- for (size_t i = 0; i < forms.size(); ++i) {
- form_cache_.ShowPredictions(forms[i]);
- }
+// mojom::AutofillAgent:
+void AutofillAgent::FirstUserGestureObservedInTab() {
+ password_autofill_agent_->FirstUserGestureObserved();
}
-void AutofillAgent::OnFillForm(int query_id, const FormData& form) {
- if (query_id != autofill_query_id_)
+void AutofillAgent::FillForm(int32_t id, const FormData& form) {
+ if (id != autofill_query_id_ && id != kNoQueryId)
return;
was_query_node_autofilled_ = element_.isAutofilled();
@@ -523,33 +474,35 @@ void AutofillAgent::OnFillForm(int query_id, const FormData& form) {
if (!element_.form().isNull())
last_interacted_form_ = element_.form();
- Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id(), form,
- base::TimeTicks::Now()));
+ GetAutofillDriver()->DidFillAutofillFormData(form, base::TimeTicks::Now());
}
-// mojom::AutofillAgent:
-void AutofillAgent::FirstUserGestureObservedInTab() {
- password_autofill_agent_->FirstUserGestureObserved();
+void AutofillAgent::PreviewForm(int32_t id, const FormData& form) {
+ if (id != autofill_query_id_)
+ return;
+
+ was_query_node_autofilled_ = element_.isAutofilled();
+ form_util::PreviewForm(form, element_);
+
+ GetAutofillDriver()->DidPreviewAutofillFormData();
}
void AutofillAgent::OnPing() {
- Send(new AutofillHostMsg_PingAck(routing_id()));
+ GetAutofillDriver()->PingAck();
}
-void AutofillAgent::OnPreviewForm(int query_id, const FormData& form) {
- if (query_id != autofill_query_id_)
- return;
-
- was_query_node_autofilled_ = element_.isAutofilled();
- form_util::PreviewForm(form, element_);
- Send(new AutofillHostMsg_DidPreviewAutofillFormData(routing_id()));
+void AutofillAgent::FieldTypePredictionsAvailable(
+ const std::vector<FormDataPredictions>& forms) {
+ for (const auto& form : forms) {
+ form_cache_.ShowPredictions(form);
+ }
}
-void AutofillAgent::OnClearForm() {
+void AutofillAgent::ClearForm() {
form_cache_.ClearFormWithElement(element_);
}
-void AutofillAgent::OnClearPreviewedForm() {
+void AutofillAgent::ClearPreviewedForm() {
if (!element_.isNull()) {
if (password_autofill_agent_->DidClearAutofillSelection(element_))
return;
@@ -566,50 +519,46 @@ void AutofillAgent::OnClearPreviewedForm() {
}
}
-void AutofillAgent::OnFillFieldWithValue(const base::string16& value) {
+void AutofillAgent::FillFieldWithValue(const base::string16& value) {
WebInputElement* input_element = toWebInputElement(&element_);
if (input_element) {
- FillFieldWithValue(value, input_element);
+ DoFillFieldWithValue(value, input_element);
input_element->setAutofilled(true);
}
}
-void AutofillAgent::OnPreviewFieldWithValue(const base::string16& value) {
+void AutofillAgent::PreviewFieldWithValue(const base::string16& value) {
WebInputElement* input_element = toWebInputElement(&element_);
if (input_element)
- PreviewFieldWithValue(value, input_element);
+ DoPreviewFieldWithValue(value, input_element);
}
-void AutofillAgent::OnAcceptDataListSuggestion(const base::string16& value) {
- AcceptDataListSuggestion(value);
+void AutofillAgent::AcceptDataListSuggestion(const base::string16& value) {
+ DoAcceptDataListSuggestion(value);
}
-void AutofillAgent::OnFillPasswordSuggestion(const base::string16& username,
- const base::string16& password) {
- bool handled = password_autofill_agent_->FillSuggestion(
- element_,
- username,
- password);
+void AutofillAgent::FillPasswordSuggestion(const base::string16& username,
+ const base::string16& password) {
+ bool handled =
+ password_autofill_agent_->FillSuggestion(element_, username, password);
DCHECK(handled);
}
-void AutofillAgent::OnPreviewPasswordSuggestion(
- const base::string16& username,
- const base::string16& password) {
- bool handled = password_autofill_agent_->PreviewSuggestion(
- element_,
- username,
- password);
+void AutofillAgent::PreviewPasswordSuggestion(const base::string16& username,
+ const base::string16& password) {
+ bool handled =
+ password_autofill_agent_->PreviewSuggestion(element_, username, password);
DCHECK(handled);
}
-void AutofillAgent::OnShowInitialPasswordAccountSuggestions(
- int key,
+void AutofillAgent::ShowInitialPasswordAccountSuggestions(
+ int32_t key,
const PasswordFormFillData& form_data) {
std::vector<blink::WebInputElement> elements;
std::unique_ptr<RendererSavePasswordProgressLogger> logger;
if (password_autofill_agent_->logging_state_active()) {
- logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
+ logger.reset(new RendererSavePasswordProgressLogger(
+ GetPasswordManagerDriver().get()));
logger->LogMessage(SavePasswordProgressLogger::
STRING_ON_SHOW_INITIAL_PASSWORD_ACCOUNT_SUGGESTIONS);
}
@@ -748,7 +697,8 @@ void AutofillAgent::QueryAutofillSuggestions(
&field)) {
// If we didn't find the cached form, at least let autocomplete have a shot
// at providing suggestions.
- WebFormControlElementToFormField(element, form_util::EXTRACT_VALUE, &field);
+ WebFormControlElementToFormField(element, nullptr, form_util::EXTRACT_VALUE,
+ &field);
}
std::vector<base::string16> data_list_values;
@@ -764,26 +714,21 @@ void AutofillAgent::QueryAutofillSuggestions(
}
is_popup_possibly_visible_ = true;
- Send(new AutofillHostMsg_SetDataList(routing_id(),
- data_list_values,
- data_list_labels));
- Send(new AutofillHostMsg_QueryFormFieldAutofill(
- routing_id(),
- autofill_query_id_,
- form,
- field,
- render_frame()->GetRenderView()->ElementBoundsInWindow(element_)));
+ GetAutofillDriver()->SetDataList(data_list_values, data_list_labels);
+ GetAutofillDriver()->QueryFormFieldAutofill(
+ autofill_query_id_, form, field,
+ render_frame()->GetRenderView()->ElementBoundsInWindow(element_));
}
-void AutofillAgent::FillFieldWithValue(const base::string16& value,
- WebInputElement* node) {
+void AutofillAgent::DoFillFieldWithValue(const base::string16& value,
+ WebInputElement* node) {
base::AutoReset<bool> auto_reset(&ignore_text_changes_, true);
node->setEditingValue(value.substr(0, node->maxLength()));
}
-void AutofillAgent::PreviewFieldWithValue(const base::string16& value,
- WebInputElement* node) {
+void AutofillAgent::DoPreviewFieldWithValue(const base::string16& value,
+ WebInputElement* node) {
was_query_node_autofilled_ = element_.isAutofilled();
node->setSuggestedValue(value.substr(0, node->maxLength()));
node->setAutofilled(true);
@@ -800,8 +745,7 @@ void AutofillAgent::ProcessForms() {
// Always communicate to browser process for topmost frame.
if (!forms.empty() || !frame->parent()) {
- Send(new AutofillHostMsg_FormsSeen(routing_id(), forms,
- forms_seen_timestamp));
+ GetAutofillDriver()->FormsSeen(forms, forms_seen_timestamp);
}
}
@@ -810,27 +754,24 @@ void AutofillAgent::HidePopup() {
return;
is_popup_possibly_visible_ = false;
is_generation_popup_possibly_visible_ = false;
- Send(new AutofillHostMsg_HidePopup(routing_id()));
+
+ GetAutofillDriver()->HidePopup();
}
bool AutofillAgent::IsUserGesture() const {
return WebUserGestureIndicator::isProcessingUserGesture();
}
-void AutofillAgent::didAssociateFormControls(const WebVector<WebNode>& nodes) {
- for (size_t i = 0; i < nodes.size(); ++i) {
- WebLocalFrame* frame = nodes[i].document().frame();
- // Only monitors dynamic forms created in the top frame. Dynamic forms
- // inserted in iframes are not captured yet. Frame is only processed
- // if it has finished loading, otherwise you can end up with a partially
- // parsed form.
- if (frame && !frame->isLoading()) {
- ProcessForms();
- password_autofill_agent_->OnDynamicFormsSeen();
- if (password_generation_agent_)
- password_generation_agent_->OnDynamicFormsSeen();
- return;
- }
+void AutofillAgent::didAssociateFormControlsDynamically() {
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+
+ // Frame is only processed if it has finished loading, otherwise you can end
+ // up with a partially parsed form.
+ if (frame && !frame->isLoading()) {
+ ProcessForms();
+ password_autofill_agent_->OnDynamicFormsSeen();
+ if (password_generation_agent_)
+ password_generation_agent_->OnDynamicFormsSeen();
}
}
@@ -839,12 +780,19 @@ void AutofillAgent::ajaxSucceeded() {
password_autofill_agent_->AJAXSucceeded();
}
-void AutofillAgent::ConnectToMojoAutofillDriverIfNeeded() {
- if (mojo_autofill_driver_.is_bound() &&
- !mojo_autofill_driver_.encountered_error())
- return;
+const mojom::AutofillDriverPtr& AutofillAgent::GetAutofillDriver() {
+ if (!autofill_driver_) {
+ render_frame()->GetRemoteInterfaces()->GetInterface(
+ mojo::GetProxy(&autofill_driver_));
+ }
+
+ return autofill_driver_;
+}
- render_frame()->GetRemoteInterfaces()->GetInterface(&mojo_autofill_driver_);
+const mojom::PasswordManagerDriverPtr&
+AutofillAgent::GetPasswordManagerDriver() {
+ DCHECK(password_autofill_agent_);
+ return password_autofill_agent_->GetPasswordManagerDriver();
}
// LegacyAutofillAgent ---------------------------------------------------------
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h
index 1fa267a1e7b..c03040f3f9a 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/autofill_agent.h
@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
#include "base/time/time.h"
#include "components/autofill/content/public/interfaces/autofill_agent.mojom.h"
#include "components/autofill/content/public/interfaces/autofill_driver.mojom.h"
@@ -18,7 +19,7 @@
#include "components/autofill/content/renderer/page_click_listener.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/public/renderer/render_view_observer.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/WebKit/public/web/WebAutofillClient.h"
#include "third_party/WebKit/public/web/WebFormControlElement.h"
#include "third_party/WebKit/public/web/WebFormElement.h"
@@ -59,10 +60,32 @@ class AutofillAgent : public content::RenderFrameObserver,
void BindRequest(mojom::AutofillAgentRequest request);
+ const mojom::AutofillDriverPtr& GetAutofillDriver();
+
+ const mojom::PasswordManagerDriverPtr& GetPasswordManagerDriver();
+
+ // mojom::AutofillAgent:
+ void FirstUserGestureObservedInTab() override;
+ void FillForm(int32_t id, const FormData& form) override;
+ void PreviewForm(int32_t id, const FormData& form) override;
+ void FieldTypePredictionsAvailable(
+ const std::vector<FormDataPredictions>& forms) override;
+ void ClearForm() override;
+ void ClearPreviewedForm() override;
+ void FillFieldWithValue(const base::string16& value) override;
+ void PreviewFieldWithValue(const base::string16& value) override;
+ void AcceptDataListSuggestion(const base::string16& value) override;
+ void FillPasswordSuggestion(const base::string16& username,
+ const base::string16& password) override;
+ void PreviewPasswordSuggestion(const base::string16& username,
+ const base::string16& password) override;
+ void ShowInitialPasswordAccountSuggestions(
+ int32_t key,
+ const PasswordFormFillData& form_data) override;
+
protected:
// blink::WebAutofillClient:
- void didAssociateFormControls(
- const blink::WebVector<blink::WebNode>& nodes) override;
+ void didAssociateFormControlsDynamically() override;
private:
// Functor used as a simplified comparison function for FormData. Only
@@ -123,7 +146,6 @@ class AutofillAgent : public content::RenderFrameObserver,
};
// content::RenderFrameObserver:
- bool OnMessageReceived(const IPC::Message& message) override;
void DidCommitProvisionalLoad(bool is_new_navigation,
bool is_same_page_navigation) override;
void DidFinishDocumentLoad() override;
@@ -166,28 +188,7 @@ class AutofillAgent : public content::RenderFrameObserver,
void firstUserGestureObserved() override;
void ajaxSucceeded() override;
- void OnFieldTypePredictionsAvailable(
- const std::vector<FormDataPredictions>& forms);
- void OnFillForm(int query_id, const FormData& form);
void OnPing();
- void OnPreviewForm(int query_id, const FormData& form);
-
- // mojom::AutofillAgent:
- void FirstUserGestureObservedInTab() override;
-
- // For external Autofill selection.
- void OnClearForm();
- void OnClearPreviewedForm();
- void OnFillFieldWithValue(const base::string16& value);
- void OnPreviewFieldWithValue(const base::string16& value);
- void OnAcceptDataListSuggestion(const base::string16& value);
- void OnFillPasswordSuggestion(const base::string16& username,
- const base::string16& password);
- void OnPreviewPasswordSuggestion(const base::string16& username,
- const base::string16& password);
- void OnShowInitialPasswordAccountSuggestions(
- int key,
- const PasswordFormFillData& form_data);
// Called when a same-page navigation is detected.
void OnSamePageNavigationCompleted();
@@ -212,7 +213,7 @@ class AutofillAgent : public content::RenderFrameObserver,
void QueryAutofillSuggestions(const blink::WebFormControlElement& element);
// Sets the element value to reflect the selected |suggested_value|.
- void AcceptDataListSuggestion(const base::string16& suggested_value);
+ void DoAcceptDataListSuggestion(const base::string16& suggested_value);
// Fills |form| and |field| with the FormData and FormField corresponding to
// |node|. Returns true if the data was found; and false otherwise.
@@ -222,14 +223,14 @@ class AutofillAgent : public content::RenderFrameObserver,
FormFieldData* field) WARN_UNUSED_RESULT;
// Set |node| to display the given |value|.
- void FillFieldWithValue(const base::string16& value,
- blink::WebInputElement* node);
+ void DoFillFieldWithValue(const base::string16& value,
+ blink::WebInputElement* node);
// Set |node| to display the given |value| as a preview. The preview is
// visible on screen to the user, but not visible to the page via the DOM or
// JavaScript.
- void PreviewFieldWithValue(const base::string16& value,
- blink::WebInputElement* node);
+ void DoPreviewFieldWithValue(const base::string16& value,
+ blink::WebInputElement* node);
// Notifies browser of new fillable forms in |render_frame|.
void ProcessForms();
@@ -249,8 +250,6 @@ class AutofillAgent : public content::RenderFrameObserver,
// overriden in tests.
virtual bool IsUserGesture() const;
- void ConnectToMojoAutofillDriverIfNeeded();
-
// Formerly cached forms for all frames, now only caches forms for the current
// frame.
FormCache form_cache_;
@@ -301,9 +300,9 @@ class AutofillAgent : public content::RenderFrameObserver,
// for the password manager. TODO(gcasto): Have both UIs show on focus.
bool is_generation_popup_possibly_visible_;
- mojo::BindingSet<mojom::AutofillAgent> bindings_;
+ mojo::Binding<mojom::AutofillAgent> binding_;
- mojom::AutofillDriverPtr mojo_autofill_driver_;
+ mojom::AutofillDriverPtr autofill_driver_;
base::WeakPtrFactory<AutofillAgent> weak_ptr_factory_;
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc
index 69e24c1cfdb..3f31d7495e8 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc
@@ -229,7 +229,7 @@ base::string16 FindChildTextInner(const WebNode& node,
return base::string16();
}
- if (element.hasHTMLTagName("div") && ContainsKey(divs_to_skip, node))
+ if (element.hasHTMLTagName("div") && base::ContainsKey(divs_to_skip, node))
return base::string16();
}
@@ -675,10 +675,11 @@ std::vector<std::string> AncestorTagNames(
bool IsLabelValid(base::StringPiece16 inferred_label,
const std::vector<base::char16>& stop_words) {
// If |inferred_label| has any character other than those in |stop_words|.
- auto first_non_stop_word = std::find_if(inferred_label.begin(),
- inferred_label.end(), [&stop_words](base::char16 c) {
- return !ContainsValue(stop_words, c);
- });
+ auto* first_non_stop_word =
+ std::find_if(inferred_label.begin(), inferred_label.end(),
+ [&stop_words](base::char16 c) {
+ return !base::ContainsValue(stop_words, c);
+ });
return first_non_stop_word != inferred_label.end();
}
@@ -708,7 +709,7 @@ base::string16 InferLabelForElement(const WebFormControlElement& element,
std::vector<std::string> tag_names = AncestorTagNames(element);
std::set<std::string> seen_tag_names;
for (const std::string& tag_name : tag_names) {
- if (ContainsKey(seen_tag_names, tag_name))
+ if (base::ContainsKey(seen_tag_names, tag_name))
continue;
seen_tag_names.insert(tag_name);
@@ -959,6 +960,7 @@ void PreviewFormField(const FormFieldData& data,
// [1, kMaxParseableFields].
bool ExtractFieldsFromControlElements(
const WebVector<WebFormControlElement>& control_elements,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
ExtractMask extract_mask,
ScopedVector<FormFieldData>* form_fields,
std::vector<bool>* fields_extracted,
@@ -975,7 +977,9 @@ bool ExtractFieldsFromControlElements(
// Create a new FormFieldData, fill it out and map it to the field's name.
FormFieldData* form_field = new FormFieldData;
- WebFormControlElementToFormField(control_element, extract_mask, form_field);
+ WebFormControlElementToFormField(control_element,
+ field_value_and_properties_map,
+ extract_mask, form_field);
form_fields->push_back(form_field);
(*element_map)[control_element] = form_field;
(*fields_extracted)[i] = true;
@@ -1062,6 +1066,7 @@ bool FormOrFieldsetsToFormData(
const blink::WebFormControlElement* form_control_element,
const std::vector<blink::WebElement>& fieldsets,
const WebVector<WebFormControlElement>& control_elements,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
ExtractMask extract_mask,
FormData* form,
FormFieldData* field) {
@@ -1083,9 +1088,9 @@ bool FormOrFieldsetsToFormData(
// requirements and thus will be in the resulting |form|.
std::vector<bool> fields_extracted(control_elements.size(), false);
- if (!ExtractFieldsFromControlElements(control_elements, extract_mask,
- &form_fields, &fields_extracted,
- &element_map)) {
+ if (!ExtractFieldsFromControlElements(
+ control_elements, field_value_and_properties_map, extract_mask,
+ &form_fields, &fields_extracted, &element_map)) {
return false;
}
@@ -1146,7 +1151,7 @@ bool FormOrFieldsetsToFormData(
}
// Copy the created FormFields into the resulting FormData object.
- for (const auto& iter : form_fields)
+ for (const auto* iter : form_fields)
form->fields.push_back(*iter);
return true;
}
@@ -1156,25 +1161,16 @@ bool UnownedFormElementsAndFieldSetsToFormData(
const std::vector<blink::WebFormControlElement>& control_elements,
const blink::WebFormControlElement* element,
const blink::WebDocument& document,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
ExtractMask extract_mask,
FormData* form,
FormFieldData* field) {
form->origin = GetCanonicalOriginForDocument(document);
form->is_form_tag = false;
- return FormOrFieldsetsToFormData(nullptr, element, fieldsets,
- control_elements, extract_mask, form, field);
-}
-
-GURL StripAuthAndParams(const GURL& gurl) {
- // We want to keep the path but strip any authentication data, as well as
- // query and ref portions of URL, for the form action and form origin.
- GURL::Replacements rep;
- rep.ClearUsername();
- rep.ClearPassword();
- rep.ClearQuery();
- rep.ClearRef();
- return gurl.ReplaceComponents(rep);
+ return FormOrFieldsetsToFormData(
+ nullptr, element, fieldsets, control_elements,
+ field_value_and_properties_map, extract_mask, form, field);
}
} // namespace
@@ -1191,9 +1187,18 @@ ScopedLayoutPreventer::~ScopedLayoutPreventer() {
g_prevent_layout = false;
}
+GURL StripAuthAndParams(const GURL& gurl) {
+ GURL::Replacements rep;
+ rep.ClearUsername();
+ rep.ClearPassword();
+ rep.ClearQuery();
+ rep.ClearRef();
+ return gurl.ReplaceComponents(rep);
+}
+
bool ExtractFormData(const WebFormElement& form_element, FormData* data) {
return WebFormElementToFormData(
- form_element, WebFormControlElement(),
+ form_element, WebFormControlElement(), nullptr,
static_cast<form_util::ExtractMask>(form_util::EXTRACT_VALUE |
form_util::EXTRACT_OPTION_TEXT |
form_util::EXTRACT_OPTIONS),
@@ -1235,8 +1240,8 @@ bool IsFormVisible(blink::WebFrame* frame,
if (action_is_empty) { // Both actions are empty, compare all fields.
FormData extracted_form_data;
- WebFormElementToFormData(form, WebFormControlElement(), EXTRACT_NONE,
- &extracted_form_data, nullptr);
+ WebFormElementToFormData(form, WebFormControlElement(), nullptr,
+ EXTRACT_NONE, &extracted_form_data, nullptr);
if (form_data.SameFormAs(extracted_form_data)) {
return true; // Form still exists.
}
@@ -1358,9 +1363,11 @@ std::vector<WebFormControlElement> ExtractAutofillableElementsInForm(
return ExtractAutofillableElementsFromSet(control_elements);
}
-void WebFormControlElementToFormField(const WebFormControlElement& element,
- ExtractMask extract_mask,
- FormFieldData* field) {
+void WebFormControlElementToFormField(
+ const WebFormControlElement& element,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
+ ExtractMask extract_mask,
+ FormFieldData* field) {
DCHECK(field);
DCHECK(!element.isNull());
CR_DEFINE_STATIC_LOCAL(WebString, kAutocomplete, ("autocomplete"));
@@ -1388,6 +1395,13 @@ void WebFormControlElementToFormField(const WebFormControlElement& element,
if (element.hasAttribute(kClass))
field->css_classes = element.getAttribute(kClass);
+ if (field_value_and_properties_map) {
+ FieldValueAndPropertiesMaskMap::const_iterator it =
+ field_value_and_properties_map->find(element);
+ if (it != field_value_and_properties_map->end())
+ field->properties_mask = it->second.second;
+ }
+
if (!IsAutofillableElement(element))
return;
@@ -1399,8 +1413,15 @@ void WebFormControlElementToFormField(const WebFormControlElement& element,
if (!g_prevent_layout)
field->is_focusable = element.isFocusable();
field->should_autocomplete = element.autoComplete();
+
+ // Use 'text-align: left|right' if set or 'direction' otherwise.
+ // See crbug.com/482339
field->text_direction = element.directionForFormData() ==
"rtl" ? base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
+ if (element.alignmentForFormData() == "left")
+ field->text_direction = base::i18n::LEFT_TO_RIGHT;
+ else if (element.alignmentForFormData() == "right")
+ field->text_direction = base::i18n::RIGHT_TO_LEFT;
}
if (IsAutofillableInputElement(input_element)) {
@@ -1451,6 +1472,7 @@ void WebFormControlElementToFormField(const WebFormControlElement& element,
bool WebFormElementToFormData(
const blink::WebFormElement& form_element,
const blink::WebFormControlElement& form_control_element,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
ExtractMask extract_mask,
FormData* form,
FormFieldData* field) {
@@ -1471,9 +1493,9 @@ bool WebFormElementToFormData(
form_element.getFormControlElements(control_elements);
std::vector<blink::WebElement> dummy_fieldset;
- return FormOrFieldsetsToFormData(&form_element, &form_control_element,
- dummy_fieldset, control_elements,
- extract_mask, form, field);
+ return FormOrFieldsetsToFormData(
+ &form_element, &form_control_element, dummy_fieldset, control_elements,
+ field_value_and_properties_map, extract_mask, form, field);
}
std::vector<WebFormControlElement> GetUnownedFormFieldElements(
@@ -1526,8 +1548,8 @@ bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
if (!lang.empty() &&
!base::StartsWith(lang, "en", base::CompareCase::INSENSITIVE_ASCII)) {
return UnownedFormElementsAndFieldSetsToFormData(
- fieldsets, control_elements, element, document, extract_mask, form,
- field);
+ fieldsets, control_elements, element, document, nullptr, extract_mask,
+ form, field);
}
// A potential problem is that this only checks document.title(), but should
@@ -1551,7 +1573,7 @@ bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
"wallet"
};
- for (const auto& keyword : kKeywords) {
+ for (const auto* keyword : kKeywords) {
// Compare char16 elements of |title| with char elements of |keyword| using
// operator==.
auto title_pos = std::search(title.begin(), title.end(),
@@ -1561,8 +1583,8 @@ bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
form->is_formless_checkout = true;
// Found a keyword: treat this as an unowned form.
return UnownedFormElementsAndFieldSetsToFormData(
- fieldsets, control_elements, element, document, extract_mask, form,
- field);
+ fieldsets, control_elements, element, document, nullptr, extract_mask,
+ form, field);
}
}
@@ -1580,8 +1602,8 @@ bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
return false;
return UnownedFormElementsAndFieldSetsToFormData(
- fieldsets, elements_with_autocomplete, element, document, extract_mask,
- form, field);
+ fieldsets, elements_with_autocomplete, element, document, nullptr,
+ extract_mask, form, field);
}
bool UnownedPasswordFormElementsAndFieldSetsToFormData(
@@ -1589,12 +1611,13 @@ bool UnownedPasswordFormElementsAndFieldSetsToFormData(
const std::vector<blink::WebFormControlElement>& control_elements,
const blink::WebFormControlElement* element,
const blink::WebDocument& document,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
ExtractMask extract_mask,
FormData* form,
FormFieldData* field) {
return UnownedFormElementsAndFieldSetsToFormData(
- fieldsets, control_elements, element, document, extract_mask, form,
- field);
+ fieldsets, control_elements, element, document,
+ field_value_and_properties_map, extract_mask, form, field);
}
@@ -1618,11 +1641,8 @@ bool FindFormAndFieldForFormControlElement(const WebFormControlElement& element,
form, field);
}
- return WebFormElementToFormData(form_element,
- element,
- extract_mask,
- form,
- field);
+ return WebFormElementToFormData(form_element, element, nullptr, extract_mask,
+ form, field);
}
void FillForm(const FormData& form, const WebFormControlElement& element) {
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.h b/chromium/components/autofill/content/renderer/form_autofill_util.h
index 7f2391dcbf7..89bf5077137 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.h
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/strings/string16.h"
+#include <components/autofill/content/renderer/password_form_conversion_utils.h>
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/password_form_field_prediction_map.h"
#include "third_party/WebKit/public/platform/WebVector.h"
@@ -74,6 +75,10 @@ class ScopedLayoutPreventer {
DISALLOW_COPY_AND_ASSIGN(ScopedLayoutPreventer);
};
+// Helper function that strips any authentication data, as well as query and
+// ref portions of URL
+GURL StripAuthAndParams(const GURL& gurl);
+
// Extract FormData from the form element and return whether the operation was
// successful.
bool ExtractFormData(const blink::WebFormElement& form_element, FormData* data);
@@ -143,9 +148,12 @@ std::vector<blink::WebFormControlElement> ExtractAutofillableElementsInForm(
const blink::WebFormElement& form_element);
// Fills out a FormField object from a given WebFormControlElement.
-// |extract_mask|: See the enum ExtractMask above for details.
+// |extract_mask|: See the enum ExtractMask above for details. Field properties
+// will be copied from |field_value_and_properties_map|, if the argument is not
+// null and has entry for |element| (see properties in FieldPropertiesFlags).
void WebFormControlElementToFormField(
const blink::WebFormControlElement& element,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
ExtractMask extract_mask,
FormFieldData* field);
@@ -153,10 +161,13 @@ void WebFormControlElementToFormField(
// If |field| is non-NULL, also fills |field| with the FormField object
// corresponding to the |form_control_element|. |extract_mask| controls what
// data is extracted. Returns true if |form| is filled out. Also returns false
-// if there are no fields or too many fields in the |form|.
+// if there are no fields or too many fields in the |form|. Field properties
+// will be copied from |field_value_and_properties_map|, if the argument is not
+// null and has entry for |element| (see properties in FieldPropertiesFlags).
bool WebFormElementToFormData(
const blink::WebFormElement& form_element,
const blink::WebFormControlElement& form_control_element,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
ExtractMask extract_mask,
FormData* form,
FormFieldData* field);
@@ -192,12 +203,15 @@ bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
FormFieldData* field);
// Same as above, but without the requirement that the elements only be
-// related to checkout.
+// related to checkout. Field properties of |control_elements| will be copied
+// from |field_value_and_properties_map|, if the argument is not null and has
+// corresponding entries (see properties in FieldPropertiesFlags).
bool UnownedPasswordFormElementsAndFieldSetsToFormData(
const std::vector<blink::WebElement>& fieldsets,
const std::vector<blink::WebFormControlElement>& control_elements,
const blink::WebFormControlElement* element,
const blink::WebDocument& document,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
ExtractMask extract_mask,
FormData* form,
FormFieldData* field);
diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc
index 2d69822a5b0..0ff07229ed6 100644
--- a/chromium/components/autofill/content/renderer/form_cache.cc
+++ b/chromium/components/autofill/content/renderer/form_cache.cc
@@ -123,7 +123,7 @@ std::vector<FormData> FormCache::ExtractNewForms() {
FormData form;
if (!WebFormElementToFormData(form_element, WebFormControlElement(),
- extract_mask, &form, nullptr)) {
+ nullptr, extract_mask, &form, nullptr)) {
continue;
}
@@ -131,7 +131,7 @@ std::vector<FormData> FormCache::ExtractNewForms() {
if (num_fields_seen > form_util::kMaxParseableFields)
return forms;
- if (!ContainsKey(parsed_forms_, form) &&
+ if (!base::ContainsKey(parsed_forms_, form) &&
IsFormInteresting(form, num_editable_elements)) {
for (auto it = parsed_forms_.begin(); it != parsed_forms_.end(); ++it) {
if (it->SameFormAs(form)) {
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
index 19d6562aecb..9fdf40e10a9 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
@@ -13,23 +13,26 @@
#include "base/bind.h"
#include "base/i18n/case_conversion.h"
#include "base/memory/linked_ptr.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
-#include "components/autofill/content/common/autofill_messages.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_field_data.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "content/public/renderer/document_state.h"
#include "content/public/renderer/navigation_state.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
+#include "services/shell/public/cpp/interface_provider.h"
+#include "services/shell/public/cpp/interface_registry.h"
#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/web/WebAutofillClient.h"
@@ -349,19 +352,42 @@ bool CanShowSuggestion(const PasswordFormFillData& fill_data,
return false;
}
+// Updates the value (i.e. the pair of elements's value |value| and field
+// properties |added_flags|) associated with the key |element| in
+// |field_value_and_properties_map|.
+// Flags in |added_flags| are added with bitwise OR operation.
+// If |value| is null, the value is neither updated nor added.
+void UpdateFieldValueAndPropertiesMaskMap(
+ const blink::WebFormControlElement& element,
+ const base::string16* value,
+ FieldPropertiesMask added_flags,
+ FieldValueAndPropertiesMaskMap* field_value_and_properties_map) {
+ FieldValueAndPropertiesMaskMap::iterator it =
+ field_value_and_properties_map->find(element);
+ if (it != field_value_and_properties_map->end()) {
+ if (value)
+ it->second.first.reset(new base::string16(*value));
+ it->second.second |= added_flags;
+ } else {
+ (*field_value_and_properties_map)[element] = std::make_pair(
+ value ? base::MakeUnique<base::string16>(*value) : nullptr,
+ added_flags);
+ }
+}
+
// This function attempts to fill |username_element| and |password_element|
// with values from |fill_data|. The |password_element| will only have the
// suggestedValue set, and will be registered for copying that to the real
// value through |registration_callback|. If a match is found, return true and
-// |nonscript_modified_values| will be modified with the autofilled credentials.
+// |field_value_and_properties_map| will be modified with the autofilled
+// credentials and |FieldPropertiesFlags::AUTOFILLED| flag.
bool FillUserNameAndPassword(
blink::WebInputElement* username_element,
blink::WebInputElement* password_element,
const PasswordFormFillData& fill_data,
bool exact_username_match,
bool set_selection,
- std::map<const blink::WebInputElement, blink::WebString>*
- nonscript_modified_values,
+ FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
base::Callback<void(blink::WebInputElement*)> registration_callback,
RendererSavePasswordProgressLogger* logger) {
if (logger)
@@ -428,7 +454,9 @@ bool FillUserNameAndPassword(
IsElementAutocompletable(*username_element)) {
// TODO(crbug.com/507714): Why not setSuggestedValue?
username_element->setValue(username, true);
- (*nonscript_modified_values)[*username_element] = username;
+ UpdateFieldValueAndPropertiesMaskMap(*username_element, &username,
+ FieldPropertiesFlags::AUTOFILLED,
+ field_value_and_properties_map);
username_element->setAutofilled(true);
if (logger)
logger->LogElementName(Logger::STRING_USERNAME_FILLED, *username_element);
@@ -446,7 +474,9 @@ bool FillUserNameAndPassword(
// sure that we do not fill in the DOM with a password until we believe the
// user is intentionally interacting with the page.
password_element->setSuggestedValue(password);
- (*nonscript_modified_values)[*password_element] = password;
+ UpdateFieldValueAndPropertiesMaskMap(*password_element, &password,
+ FieldPropertiesFlags::AUTOFILLED,
+ field_value_and_properties_map);
registration_callback.Run(password_element);
password_element->setAutofilled(true);
@@ -467,8 +497,7 @@ bool FillFormOnPasswordReceived(
const PasswordFormFillData& fill_data,
blink::WebInputElement username_element,
blink::WebInputElement password_element,
- std::map<const blink::WebInputElement, blink::WebString>*
- nonscript_modified_values,
+ FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
base::Callback<void(blink::WebInputElement*)> registration_callback,
RendererSavePasswordProgressLogger* logger) {
// Do not fill if the password field is in a chain of iframes not having
@@ -527,7 +556,7 @@ bool FillFormOnPasswordReceived(
return FillUserNameAndPassword(
&username_element, &password_element, fill_data,
true /* exact_username_match */, false /* set_selection */,
- nonscript_modified_values, registration_callback, logger);
+ field_value_and_properties_map, registration_callback, logger);
}
// Takes a |map| with pointers as keys and linked_ptr as values, and returns
@@ -552,13 +581,26 @@ PasswordAutofillAgent::PasswordAutofillAgent(content::RenderFrame* render_frame)
: content::RenderFrameObserver(render_frame),
logging_state_active_(false),
was_username_autofilled_(false),
- was_password_autofilled_(false) {
- Send(new AutofillHostMsg_PasswordAutofillAgentConstructed(routing_id()));
+ was_password_autofilled_(false),
+ binding_(this) {
+ // PasswordAutofillAgent is guaranteed to outlive |render_frame|.
+ render_frame->GetInterfaceRegistry()->AddInterface(
+ base::Bind(&PasswordAutofillAgent::BindRequest, base::Unretained(this)));
+ GetPasswordManagerDriver()->PasswordAutofillAgentConstructed();
}
PasswordAutofillAgent::~PasswordAutofillAgent() {
}
+void PasswordAutofillAgent::BindRequest(
+ mojom::PasswordAutofillAgentRequest request) {
+ binding_.Bind(std::move(request));
+}
+
+void PasswordAutofillAgent::SetAutofillAgent(AutofillAgent* autofill_agent) {
+ autofill_agent_ = autofill_agent;
+}
+
PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper()
: was_user_gesture_seen_(false) {
}
@@ -594,40 +636,6 @@ void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue(
element->setValue(element->suggestedValue(), true);
}
-bool PasswordAutofillAgent::TextFieldDidEndEditing(
- const blink::WebInputElement& element) {
- WebInputToPasswordInfoMap::const_iterator iter =
- web_input_to_password_info_.find(element);
- if (iter == web_input_to_password_info_.end())
- return false;
-
- const PasswordInfo& password_info = iter->second;
- // Don't let autofill overwrite an explicit change made by the user.
- if (password_info.password_was_edited_last)
- return false;
-
- const PasswordFormFillData& fill_data = password_info.fill_data;
-
- // If wait_for_username is false, we should have filled when the text changed.
- if (!fill_data.wait_for_username)
- return false;
-
- blink::WebInputElement password = password_info.password_field;
- if (!IsElementEditable(password))
- return false;
-
- blink::WebInputElement username = element; // We need a non-const.
-
- // Do not set selection when ending an editing session, otherwise it can
- // mess with focus.
- FillUserNameAndPassword(&username, &password, fill_data, true, false,
- &nonscript_modified_values_,
- base::Bind(&PasswordValueGatekeeper::RegisterElement,
- base::Unretained(&gatekeeper_)),
- nullptr);
- return true;
-}
-
bool PasswordAutofillAgent::TextDidChangeInTextField(
const blink::WebInputElement& element) {
// TODO(vabr): Get a mutable argument instead. http://crbug.com/397083
@@ -638,9 +646,6 @@ bool PasswordAutofillAgent::TextDidChangeInTextField(
web_input_to_password_info_.find(element);
if (iter != web_input_to_password_info_.end()) {
iter->second.password_was_edited_last = false;
- // If wait_for_username is true we will fill when the username loses focus.
- if (iter->second.fill_data.wait_for_username)
- return false;
}
// Show the popup with the list of available usernames.
@@ -652,8 +657,12 @@ void PasswordAutofillAgent::UpdateStateForTextChange(
// TODO(vabr): Get a mutable argument instead. http://crbug.com/397083
blink::WebInputElement mutable_element = element; // We need a non-const.
- if (element.isTextField())
- nonscript_modified_values_[element] = element.value();
+ if (element.isTextField()) {
+ const base::string16 element_value = element.value();
+ UpdateFieldValueAndPropertiesMaskMap(element, &element_value,
+ FieldPropertiesFlags::USER_TYPED,
+ &field_value_and_properties_map_);
+ }
blink::WebFrame* const element_frame = element.document().frame();
// The element's frame might have been detached in the meantime (see
@@ -673,10 +682,10 @@ void PasswordAutofillAgent::UpdateStateForTextChange(
std::unique_ptr<PasswordForm> password_form;
if (element.form().isNull()) {
password_form = CreatePasswordFormFromUnownedInputElements(
- *element_frame, &nonscript_modified_values_, &form_predictions_);
+ *element_frame, &field_value_and_properties_map_, &form_predictions_);
} else {
password_form = CreatePasswordFormFromWebForm(
- element.form(), &nonscript_modified_values_, &form_predictions_);
+ element.form(), &field_value_and_properties_map_, &form_predictions_);
}
ProvisionallySavePassword(std::move(password_form), RESTRICTION_NONE);
@@ -693,8 +702,8 @@ void PasswordAutofillAgent::UpdateStateForTextChange(
bool PasswordAutofillAgent::FillSuggestion(
const blink::WebFormControlElement& control_element,
- const blink::WebString& username,
- const blink::WebString& password) {
+ const base::string16& username,
+ const base::string16& password) {
// The element in context of the suggestion popup.
const blink::WebInputElement* element = toWebInputElement(&control_element);
if (!element)
@@ -706,8 +715,6 @@ bool PasswordAutofillAgent::FillSuggestion(
if (!FindPasswordInfoForElement(*element, &username_element,
&password_element, &password_info) ||
- (!username_element.isNull() &&
- !IsElementAutocompletable(username_element)) ||
!IsElementAutocompletable(password_element)) {
return false;
}
@@ -716,15 +723,20 @@ bool PasswordAutofillAgent::FillSuggestion(
if (element->isPasswordField()) {
password_info->password_field_suggestion_was_accepted = true;
password_info->password_field = password_element;
- } else if (!username_element.isNull()) {
- username_element.setValue(username, true);
+ } else if (!username_element.isNull() &&
+ IsElementAutocompletable(username_element)) {
+ username_element.setValue(blink::WebString(username), true);
username_element.setAutofilled(true);
- nonscript_modified_values_[username_element] = username;
+ UpdateFieldValueAndPropertiesMaskMap(username_element, &username,
+ FieldPropertiesFlags::AUTOFILLED,
+ &field_value_and_properties_map_);
}
- password_element.setValue(password, true);
+ password_element.setValue(blink::WebString(password), true);
password_element.setAutofilled(true);
- nonscript_modified_values_[password_element] = password;
+ UpdateFieldValueAndPropertiesMaskMap(password_element, &password,
+ FieldPropertiesFlags::AUTOFILLED,
+ &field_value_and_properties_map_);
blink::WebInputElement mutable_filled_element = *element;
mutable_filled_element.setSelectionRange(element->value().length(),
@@ -748,13 +760,12 @@ bool PasswordAutofillAgent::PreviewSuggestion(
if (!FindPasswordInfoForElement(*element, &username_element,
&password_element, &password_info) ||
- (!username_element.isNull() &&
- !IsElementAutocompletable(username_element)) ||
!IsElementAutocompletable(password_element)) {
return false;
}
- if (!element->isPasswordField() && !username_element.isNull()) {
+ if (!element->isPasswordField() && !username_element.isNull() &&
+ IsElementAutocompletable(username_element)) {
if (username_query_prefix_.empty())
username_query_prefix_ = username_element.value();
@@ -918,8 +929,7 @@ void PasswordAutofillAgent::OnSamePageNavigationCompleted() {
return;
}
- Send(new AutofillHostMsg_InPageNavigation(routing_id(),
- *provisionally_saved_form_));
+ GetPasswordManagerDriver()->InPageNavigation(*provisionally_saved_form_);
provisionally_saved_form_.reset();
}
@@ -930,12 +940,18 @@ void PasswordAutofillAgent::FirstUserGestureObserved() {
void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
std::unique_ptr<RendererSavePasswordProgressLogger> logger;
if (logging_state_active_) {
- logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
+ logger.reset(new RendererSavePasswordProgressLogger(
+ GetPasswordManagerDriver().get()));
logger->LogMessage(Logger::STRING_SEND_PASSWORD_FORMS_METHOD);
logger->LogBoolean(Logger::STRING_ONLY_VISIBLE, only_visible);
}
- blink::WebFrame* frame = render_frame()->GetWebFrame();
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ // RenderFrameObserver::DidFinishLoad() can fire when Frame is
+ // detaching. crbug.com/654654
+ if (frame->isFrameDetachedForSpecialOneOffStopTheCrashingHackBug561873())
+ return;
+
// Make sure that this security origin is allowed to use password manager.
blink::WebSecurityOrigin origin = frame->document().getSecurityOrigin();
if (logger) {
@@ -1025,27 +1041,13 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
if (only_visible) {
blink::WebFrame* main_frame = render_frame()->GetWebFrame()->top();
bool did_stop_loading = !main_frame || !main_frame->isLoading();
- Send(new AutofillHostMsg_PasswordFormsRendered(routing_id(), password_forms,
- did_stop_loading));
+ GetPasswordManagerDriver()->PasswordFormsRendered(password_forms,
+ did_stop_loading);
} else {
- Send(new AutofillHostMsg_PasswordFormsParsed(routing_id(), password_forms));
+ GetPasswordManagerDriver()->PasswordFormsParsed(password_forms);
}
}
-bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message)
- IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm)
- IPC_MESSAGE_HANDLER(AutofillMsg_SetLoggingState, OnSetLoggingState)
- IPC_MESSAGE_HANDLER(AutofillMsg_AutofillUsernameAndPasswordDataReceived,
- OnAutofillUsernameAndPasswordDataReceived)
- IPC_MESSAGE_HANDLER(AutofillMsg_FindFocusedPasswordForm,
- OnFindFocusedPasswordForm)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
void PasswordAutofillAgent::DidFinishDocumentLoad() {
// The |frame| contents have been parsed, but not yet rendered. Let the
// PasswordManager know that forms are loaded, even though we can't yet tell
@@ -1062,7 +1064,7 @@ void PasswordAutofillAgent::DidFinishLoad() {
SendPasswordForms(true);
}
-void PasswordAutofillAgent::FrameWillClose() {
+void PasswordAutofillAgent::WillCommitProvisionalLoad() {
FrameClosing();
}
@@ -1079,8 +1081,7 @@ void PasswordAutofillAgent::FrameDetached() {
// for examples of sites that perform login using this technique.
if (render_frame()->GetWebFrame()->parent() &&
ProvisionallySavedPasswordIsValid()) {
- Send(new AutofillHostMsg_InPageNavigation(routing_id(),
- *provisionally_saved_form_));
+ GetPasswordManagerDriver()->InPageNavigation(*provisionally_saved_form_);
}
FrameClosing();
}
@@ -1101,7 +1102,7 @@ void PasswordAutofillAgent::WillSendSubmitEvent(
// Had the user cleared the password, |provisionally_saved_form_| would
// already have been updated in TextDidChangeInTextField.
std::unique_ptr<PasswordForm> password_form = CreatePasswordFormFromWebForm(
- form, &nonscript_modified_values_, &form_predictions_);
+ form, &field_value_and_properties_map_, &form_predictions_);
ProvisionallySavePassword(std::move(password_form),
RESTRICTION_NON_EMPTY_PASSWORD);
}
@@ -1109,13 +1110,14 @@ void PasswordAutofillAgent::WillSendSubmitEvent(
void PasswordAutofillAgent::WillSubmitForm(const blink::WebFormElement& form) {
std::unique_ptr<RendererSavePasswordProgressLogger> logger;
if (logging_state_active_) {
- logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
+ logger.reset(new RendererSavePasswordProgressLogger(
+ GetPasswordManagerDriver().get()));
logger->LogMessage(Logger::STRING_WILL_SUBMIT_FORM_METHOD);
LogHTMLForm(logger.get(), Logger::STRING_HTML_FORM_FOR_SUBMIT, form);
}
std::unique_ptr<PasswordForm> submitted_form = CreatePasswordFormFromWebForm(
- form, &nonscript_modified_values_, &form_predictions_);
+ form, &field_value_and_properties_map_, &form_predictions_);
// If there is a provisionally saved password, copy over the previous
// password value so we get the user's typed password, not the value that
@@ -1143,8 +1145,7 @@ void PasswordAutofillAgent::WillSubmitForm(const blink::WebFormElement& form) {
// the frame starts loading. If there are redirects that cause a new
// RenderView to be instantiated (such as redirects to the WebStore)
// we will never get to finish the load.
- Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
- *submitted_form));
+ GetPasswordManagerDriver()->PasswordFormSubmitted(*submitted_form);
provisionally_saved_form_.reset();
} else if (logger) {
logger->LogMessage(Logger::STRING_FORM_IS_NOT_PASSWORD);
@@ -1152,13 +1153,15 @@ void PasswordAutofillAgent::WillSubmitForm(const blink::WebFormElement& form) {
}
void PasswordAutofillAgent::OnDestruct() {
+ binding_.Close();
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
}
void PasswordAutofillAgent::DidStartProvisionalLoad() {
std::unique_ptr<RendererSavePasswordProgressLogger> logger;
if (logging_state_active_) {
- logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
+ logger.reset(new RendererSavePasswordProgressLogger(
+ GetPasswordManagerDriver().get()));
logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD);
}
@@ -1188,8 +1191,8 @@ void PasswordAutofillAgent::DidStartProvisionalLoad() {
Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME,
*provisionally_saved_form_);
}
- Send(new AutofillHostMsg_PasswordFormSubmitted(
- routing_id(), *provisionally_saved_form_));
+ GetPasswordManagerDriver()->PasswordFormSubmitted(
+ *provisionally_saved_form_);
provisionally_saved_form_.reset();
} else {
ScopedVector<PasswordForm> possible_submitted_forms;
@@ -1206,13 +1209,13 @@ void PasswordAutofillAgent::DidStartProvisionalLoad() {
form_element);
}
possible_submitted_forms.push_back(CreatePasswordFormFromWebForm(
- form_element, &nonscript_modified_values_, &form_predictions_));
+ form_element, &field_value_and_properties_map_,
+ &form_predictions_));
}
possible_submitted_forms.push_back(
CreatePasswordFormFromUnownedInputElements(
- *render_frame()->GetWebFrame(),
- &nonscript_modified_values_,
+ *render_frame()->GetWebFrame(), &field_value_and_properties_map_,
&form_predictions_));
for (const PasswordForm* password_form : possible_submitted_forms) {
@@ -1223,8 +1226,7 @@ void PasswordAutofillAgent::DidStartProvisionalLoad() {
logger->LogPasswordForm(Logger::STRING_PASSWORD_FORM_FOUND_ON_PAGE,
*password_form);
}
- Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
- *password_form));
+ GetPasswordManagerDriver()->PasswordFormSubmitted(*password_form);
break;
}
}
@@ -1239,13 +1241,15 @@ void PasswordAutofillAgent::DidStartProvisionalLoad() {
gatekeeper_.Reset();
}
-void PasswordAutofillAgent::OnFillPasswordForm(
+// mojom::PasswordAutofillAgent:
+void PasswordAutofillAgent::FillPasswordForm(
int key,
const PasswordFormFillData& form_data) {
std::vector<blink::WebInputElement> elements;
std::unique_ptr<RendererSavePasswordProgressLogger> logger;
if (logging_state_active_) {
- logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
+ logger.reset(new RendererSavePasswordProgressLogger(
+ GetPasswordManagerDriver().get()));
logger->LogMessage(Logger::STRING_ON_FILL_PASSWORD_FORM_METHOD);
}
GetFillableElementFromFormData(key, form_data, logger.get(), &elements);
@@ -1264,7 +1268,7 @@ void PasswordAutofillAgent::OnFillPasswordForm(
: web_input_to_password_info_[element].password_field;
FillFormOnPasswordReceived(
form_data, username_element, password_element,
- &nonscript_modified_values_,
+ &field_value_and_properties_map_,
base::Bind(&PasswordValueGatekeeper::RegisterElement,
base::Unretained(&gatekeeper_)),
logger.get());
@@ -1352,16 +1356,31 @@ void PasswordAutofillAgent::GetFillableElementFromFormData(
}
}
-void PasswordAutofillAgent::OnSetLoggingState(bool active) {
+void PasswordAutofillAgent::FocusedNodeHasChanged(const blink::WebNode& node) {
+ if (node.isNull() || !node.isElementNode())
+ return;
+ const blink::WebElement web_element = node.toConst<blink::WebElement>();
+ if (!web_element.isFormControlElement())
+ return;
+ const blink::WebFormControlElement control_element =
+ web_element.toConst<blink::WebFormControlElement>();
+ UpdateFieldValueAndPropertiesMaskMap(control_element, nullptr,
+ FieldPropertiesFlags::HAD_FOCUS,
+ &field_value_and_properties_map_);
+}
+
+// mojom::PasswordAutofillAgent:
+void PasswordAutofillAgent::SetLoggingState(bool active) {
logging_state_active_ = active;
}
-void PasswordAutofillAgent::OnAutofillUsernameAndPasswordDataReceived(
+void PasswordAutofillAgent::AutofillUsernameAndPasswordDataReceived(
const FormsPredictionsMap& predictions) {
form_predictions_.insert(predictions.begin(), predictions.end());
}
-void PasswordAutofillAgent::OnFindFocusedPasswordForm() {
+void PasswordAutofillAgent::FindFocusedPasswordForm(
+ const FindFocusedPasswordFormCallback& callback) {
std::unique_ptr<PasswordForm> password_form;
blink::WebElement element =
@@ -1371,11 +1390,11 @@ void PasswordAutofillAgent::OnFindFocusedPasswordForm() {
if (input.isPasswordField() && !input.form().isNull()) {
if (!input.form().isNull()) {
password_form = CreatePasswordFormFromWebForm(
- input.form(), &nonscript_modified_values_, &form_predictions_);
+ input.form(), &field_value_and_properties_map_, &form_predictions_);
} else {
password_form = CreatePasswordFormFromUnownedInputElements(
- *render_frame()->GetWebFrame(),
- &nonscript_modified_values_, &form_predictions_);
+ *render_frame()->GetWebFrame(), &field_value_and_properties_map_,
+ &form_predictions_);
// Only try to use this form if |input| is one of the password elements
// for |password_form|.
if (password_form->password_element != input.nameForAutofill() &&
@@ -1388,8 +1407,7 @@ void PasswordAutofillAgent::OnFindFocusedPasswordForm() {
if (!password_form)
password_form.reset(new PasswordForm());
- Send(new AutofillHostMsg_FocusedPasswordFormFound(
- routing_id(), *password_form));
+ callback.Run(*password_form);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1411,7 +1429,7 @@ bool PasswordAutofillAgent::ShowSuggestionPopup(
if (user_input.isPasswordField() && !user_input.isAutofilled() &&
!user_input.value().isEmpty()) {
- Send(new AutofillHostMsg_HidePopup(routing_id()));
+ GetAutofillDriver()->HidePopup();
return false;
}
@@ -1430,10 +1448,9 @@ bool PasswordAutofillAgent::ShowSuggestionPopup(
? base::string16()
: static_cast<base::string16>(user_input.value()));
- Send(new AutofillHostMsg_ShowPasswordSuggestions(
- routing_id(), password_info.key, field.text_direction, username_string,
- options,
- render_frame()->GetRenderView()->ElementBoundsInWindow(user_input)));
+ GetPasswordManagerDriver()->ShowPasswordSuggestions(
+ password_info.key, field.text_direction, username_string, options,
+ render_frame()->GetRenderView()->ElementBoundsInWindow(user_input));
username_query_prefix_ = username_string;
return CanShowSuggestion(password_info.fill_data, username_string, show_all);
}
@@ -1444,7 +1461,7 @@ void PasswordAutofillAgent::FrameClosing() {
}
web_input_to_password_info_.clear();
provisionally_saved_form_.reset();
- nonscript_modified_values_.clear();
+ field_value_and_properties_map_.clear();
}
void PasswordAutofillAgent::ClearPreview(
@@ -1480,4 +1497,19 @@ bool PasswordAutofillAgent::ProvisionallySavedPasswordIsValid() {
provisionally_saved_form_->new_password_value.empty());
}
+const mojom::AutofillDriverPtr& PasswordAutofillAgent::GetAutofillDriver() {
+ DCHECK(autofill_agent_);
+ return autofill_agent_->GetAutofillDriver();
+}
+
+const mojom::PasswordManagerDriverPtr&
+PasswordAutofillAgent::GetPasswordManagerDriver() {
+ if (!password_manager_driver_) {
+ render_frame()->GetRemoteInterfaces()->GetInterface(
+ mojo::GetProxy(&password_manager_driver_));
+ }
+
+ return password_manager_driver_;
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.h b/chromium/components/autofill/content/renderer/password_autofill_agent.h
index bc26b4fd763..18874298793 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h
@@ -10,12 +10,17 @@
#include <vector>
#include "base/macros.h"
+#include "components/autofill/content/public/interfaces/autofill_agent.mojom.h"
+#include "components/autofill/content/public/interfaces/autofill_driver.mojom.h"
+#include "components/autofill/content/renderer/autofill_agent.h"
#include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include "components/autofill/core/common/form_data_predictions.h"
+#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_field_prediction_map.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/public/renderer/render_view_observer.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
namespace blink {
@@ -29,15 +34,30 @@ namespace autofill {
class RendererSavePasswordProgressLogger;
// This class is responsible for filling password forms.
-class PasswordAutofillAgent : public content::RenderFrameObserver {
+class PasswordAutofillAgent : public content::RenderFrameObserver,
+ public mojom::PasswordAutofillAgent {
public:
explicit PasswordAutofillAgent(content::RenderFrame* render_frame);
~PasswordAutofillAgent() override;
+ void BindRequest(mojom::PasswordAutofillAgentRequest request);
+
+ void SetAutofillAgent(AutofillAgent* autofill_agent);
+
+ const mojom::PasswordManagerDriverPtr& GetPasswordManagerDriver();
+
+ // mojom::PasswordAutofillAgent:
+ void FillPasswordForm(int key,
+ const PasswordFormFillData& form_data) override;
+ void SetLoggingState(bool active) override;
+ void AutofillUsernameAndPasswordDataReceived(
+ const FormsPredictionsMap& predictions) override;
+ void FindFocusedPasswordForm(
+ const FindFocusedPasswordFormCallback& callback) override;
+
// WebFrameClient editor related calls forwarded by AutofillAgent.
// If they return true, it indicates the event was consumed and should not
// be used for any other autofill activity.
- bool TextFieldDidEndEditing(const blink::WebInputElement& element);
bool TextDidChangeInTextField(const blink::WebInputElement& element);
// Function that should be called whenever the value of |element| changes due
@@ -48,9 +68,9 @@ class PasswordAutofillAgent : public content::RenderFrameObserver {
// Fills the username and password fields of this form with the given values.
// Returns true if the fields were filled, false otherwise.
- bool FillSuggestion(const blink::WebFormControlElement& node,
- const blink::WebString& username,
- const blink::WebString& password);
+ bool FillSuggestion(const blink::WebFormControlElement& control_element,
+ const base::string16& username,
+ const base::string16& password);
// Previews the username and password fields of this form with the given
// values. Returns true if the fields were previewed, false otherwise.
@@ -98,6 +118,9 @@ class PasswordAutofillAgent : public content::RenderFrameObserver {
RendererSavePasswordProgressLogger* logger,
std::vector<blink::WebInputElement>* elements);
+ // Called when the focused node has changed.
+ void FocusedNodeHasChanged(const blink::WebNode& node);
+
bool logging_state_active() const { return logging_state_active_; }
protected:
@@ -158,25 +181,17 @@ class PasswordAutofillAgent : public content::RenderFrameObserver {
};
// RenderFrameObserver:
- bool OnMessageReceived(const IPC::Message& message) override;
void DidFinishDocumentLoad() override;
void DidFinishLoad() override;
void FrameDetached() override;
- void FrameWillClose() override;
void DidStartProvisionalLoad() override;
+ void WillCommitProvisionalLoad() override;
void DidCommitProvisionalLoad(bool is_new_navigation,
bool is_same_page_navigation) override;
void WillSendSubmitEvent(const blink::WebFormElement& form) override;
void WillSubmitForm(const blink::WebFormElement& form) override;
void OnDestruct() override;
- // RenderView IPC handlers:
- void OnFillPasswordForm(int key, const PasswordFormFillData& form_data);
- void OnSetLoggingState(bool active);
- void OnAutofillUsernameAndPasswordDataReceived(
- const FormsPredictionsMap& predictions);
- void OnFindFocusedPasswordForm();
-
// Scans the given frame for password forms and sends them up to the browser.
// If |only_visible| is true, only forms visible in the layout are sent.
void SendPasswordForms(bool only_visible);
@@ -224,6 +239,8 @@ class PasswordAutofillAgent : public content::RenderFrameObserver {
// Helper function called when in-page navigation completed
void OnSamePageNavigationCompleted();
+ const mojom::AutofillDriverPtr& GetAutofillDriver();
+
// The logins we have filled so far with their associated info.
WebInputToPasswordInfoMap web_input_to_password_info_;
// A (sort-of) reverse map to |login_to_password_info_|.
@@ -233,10 +250,13 @@ class PasswordAutofillAgent : public content::RenderFrameObserver {
// but the submit may still fail (i.e. doesn't pass JavaScript validation).
std::unique_ptr<PasswordForm> provisionally_saved_form_;
- // Contains the most recent text that user typed or PasswordManager autofilled
- // in input elements. Used for storing username/password before JavaScript
+ // Map WebFormControlElement to the pair of:
+ // 1) The most recent text that user typed or PasswordManager autofilled in
+ // input elements. Used for storing username/password before JavaScript
// changes them.
- ModifiedValues nonscript_modified_values_;
+ // 2) Field properties mask, i.e. whether the field was autofilled, modified
+ // by user, etc. (see FieldPropertiesMask).
+ FieldValueAndPropertiesMaskMap field_value_and_properties_map_;
PasswordValueGatekeeper gatekeeper_;
@@ -255,6 +275,12 @@ class PasswordAutofillAgent : public content::RenderFrameObserver {
// fields for individual forms.
FormsPredictionsMap form_predictions_;
+ AutofillAgent* autofill_agent_; // Weak reference.
+
+ mojom::PasswordManagerDriverPtr password_manager_driver_;
+
+ mojo::Binding<mojom::PasswordAutofillAgent> binding_;
+
DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgent);
};
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
index 4780a84cbf7..317807fd18e 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -312,6 +312,15 @@ base::string16 FieldName(const WebInputElement& input_field,
return field_name.empty() ? base::ASCIIToUTF16(dummy_name) : field_name;
}
+bool FieldHasNonscriptModifiedValue(
+ const FieldValueAndPropertiesMaskMap* field_map,
+ const blink::WebFormControlElement& element) {
+ if (!field_map)
+ return false;
+ FieldValueAndPropertiesMaskMap::const_iterator it = field_map->find(element);
+ return it != field_map->end() && it->second.first.get();
+}
+
// Helper function that checks the presence of visible password and username
// fields in |form.control_elements|.
// Iff a visible password found, then |*found_visible_password| is set to true.
@@ -350,10 +359,11 @@ void FoundVisiblePasswordAndVisibleUsernameBeforePassword(
// If an element of |form| has an entry in |nonscript_modified_values|, the
// associated string is used instead of the element's value to create
// the PasswordForm.
-bool GetPasswordForm(const SyntheticForm& form,
- PasswordForm* password_form,
- const ModifiedValues* nonscript_modified_values,
- const FormsPredictionsMap* form_predictions) {
+bool GetPasswordForm(
+ const SyntheticForm& form,
+ PasswordForm* password_form,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
+ const FormsPredictionsMap* form_predictions) {
WebInputElement latest_input_element;
WebInputElement username_element;
password_form->username_marked_by_site = false;
@@ -404,9 +414,8 @@ bool GetPasswordForm(const SyntheticForm& form,
continue;
layout_sequence.push_back('P');
} else {
- if (nonscript_modified_values &&
- nonscript_modified_values->find(*input_element) !=
- nonscript_modified_values->end())
+ if (FieldHasNonscriptModifiedValue(field_value_and_properties_map,
+ *input_element))
++number_of_non_empty_text_non_password_fields;
if (element_is_invisible && ignore_invisible_usernames)
continue;
@@ -427,11 +436,9 @@ bool GetPasswordForm(const SyntheticForm& form,
// checking whether password element was updated not from JavaScript.
if (input_element->isPasswordField() &&
(!input_element->isReadOnly() ||
- (nonscript_modified_values &&
- nonscript_modified_values->find(*input_element) !=
- nonscript_modified_values->end()) ||
+ FieldHasNonscriptModifiedValue(field_value_and_properties_map,
+ *input_element) ||
password_marked_by_autocomplete_attribute)) {
-
// We add the field to the list of password fields if it was not flagged
// as a special NOT_PASSWORD prediction by Autofill. The NOT_PASSWORD
// mechanism exists because some webpages use the type "password" for
@@ -534,20 +541,17 @@ bool GetPasswordForm(const SyntheticForm& form,
password_form->username_element =
FieldName(username_element, "anonymous_username");
base::string16 username_value = username_element.value();
- if (nonscript_modified_values != nullptr) {
- auto username_iterator =
- nonscript_modified_values->find(username_element);
- if (username_iterator != nonscript_modified_values->end()) {
- base::string16 typed_username_value = username_iterator->second;
- if (!base::StartsWith(
- base::i18n::ToLower(username_value),
- base::i18n::ToLower(typed_username_value),
- base::CompareCase::SENSITIVE)) {
- // We check that |username_value| was not obtained by autofilling
- // |typed_username_value|. In case when it was, |typed_username_value|
- // is incomplete, so we should leave autofilled value.
- username_value = typed_username_value;
- }
+ if (FieldHasNonscriptModifiedValue(field_value_and_properties_map,
+ username_element)) {
+ base::string16 typed_username_value =
+ *field_value_and_properties_map->at(username_element).first;
+ if (!base::StartsWith(base::i18n::ToLower(username_value),
+ base::i18n::ToLower(typed_username_value),
+ base::CompareCase::SENSITIVE)) {
+ // We check that |username_value| was not obtained by autofilling
+ // |typed_username_value|. In case when it was, |typed_username_value|
+ // is incomplete, so we should leave autofilled value.
+ username_value = typed_username_value;
}
}
password_form->username_value = username_value;
@@ -564,11 +568,9 @@ bool GetPasswordForm(const SyntheticForm& form,
if (!password.isNull()) {
password_form->password_element = FieldName(password, "anonymous_password");
blink::WebString password_value = password.value();
- if (nonscript_modified_values != nullptr) {
- auto password_iterator = nonscript_modified_values->find(password);
- if (password_iterator != nonscript_modified_values->end())
- password_value = password_iterator->second;
- }
+ if (FieldHasNonscriptModifiedValue(field_value_and_properties_map,
+ password))
+ password_value = *field_value_and_properties_map->at(password).first;
password_form->password_value = password_value;
}
if (!new_password.isNull()) {
@@ -594,7 +596,6 @@ bool GetPasswordForm(const SyntheticForm& form,
}
password_form->scheme = PasswordForm::SCHEME_HTML;
- password_form->ssl_valid = false;
password_form->preferred = false;
password_form->blacklisted_by_user = false;
password_form->type = PasswordForm::TYPE_MANUAL;
@@ -647,7 +648,7 @@ bool IsGaiaReauthenticationForm(
std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm(
const WebFormElement& web_form,
- const ModifiedValues* nonscript_modified_values,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
const FormsPredictionsMap* form_predictions) {
if (web_form.isNull())
return std::unique_ptr<PasswordForm>();
@@ -661,11 +662,12 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm(
PopulateSyntheticFormFromWebForm(web_form, &synthetic_form);
WebFormElementToFormData(web_form, blink::WebFormControlElement(),
+ field_value_and_properties_map,
form_util::EXTRACT_NONE, &password_form->form_data,
NULL /* FormFieldData */);
if (!GetPasswordForm(synthetic_form, password_form.get(),
- nonscript_modified_values, form_predictions))
+ field_value_and_properties_map, form_predictions))
return std::unique_ptr<PasswordForm>();
return password_form;
@@ -673,7 +675,7 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm(
std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements(
const WebFrame& frame,
- const ModifiedValues* nonscript_modified_values,
+ const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
const FormsPredictionsMap* form_predictions) {
SyntheticForm synthetic_form;
synthetic_form.control_elements = form_util::GetUnownedFormFieldElements(
@@ -686,10 +688,10 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements(
std::unique_ptr<PasswordForm> password_form(new PasswordForm());
UnownedPasswordFormElementsAndFieldSetsToFormData(
synthetic_form.fieldsets, synthetic_form.control_elements, nullptr,
- frame.document(), form_util::EXTRACT_NONE, &password_form->form_data,
- nullptr /* FormFieldData */);
+ frame.document(), field_value_and_properties_map, form_util::EXTRACT_NONE,
+ &password_form->form_data, nullptr /* FormFieldData */);
if (!GetPasswordForm(synthetic_form, password_form.get(),
- nonscript_modified_values, form_predictions))
+ field_value_and_properties_map, form_predictions))
return std::unique_ptr<PasswordForm>();
// No actual action on the form, so use the the origin as the action.
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
index 2d2847a18a8..235c9b5a7cc 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
@@ -9,6 +9,7 @@
#include <memory>
#include <vector>
+#include <components/autofill/core/common/password_form.h>
#include "components/autofill/core/common/password_form_field_prediction_map.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "url/gurl.h"
@@ -35,8 +36,10 @@ bool IsGaiaReauthenticationForm(
const GURL& origin,
const std::vector<blink::WebFormControlElement>& control_elements);
-typedef std::map<const blink::WebInputElement,
- blink::WebString> ModifiedValues;
+typedef std::map<
+ const blink::WebFormControlElement,
+ std::pair<std::unique_ptr<base::string16>, FieldPropertiesMask>>
+ FieldValueAndPropertiesMaskMap;
// Create a PasswordForm from DOM form. Webkit doesn't allow storing
// custom metadata to DOM nodes, so we have to do this every time an event
@@ -49,14 +52,14 @@ typedef std::map<const blink::WebInputElement,
// overwriting default username element selection.
std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm(
const blink::WebFormElement& form,
- const ModifiedValues* nonscript_modified_values,
+ const FieldValueAndPropertiesMaskMap* nonscript_modified_values,
const FormsPredictionsMap* form_predictions);
// Same as CreatePasswordFormFromWebForm() but for input elements that are not
// enclosed in <form> element.
std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements(
const blink::WebFrame& frame,
- const ModifiedValues* nonscript_modified_values,
+ const FieldValueAndPropertiesMaskMap* nonscript_modified_values,
const FormsPredictionsMap* form_predictions);
// Checks in a case-insensitive way if the autocomplete attribute for the given
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
index dc790c1df82..5169e0bc376 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
@@ -5,6 +5,7 @@
#include <stddef.h>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -179,13 +180,16 @@ class MAYBE_PasswordFormConversionUtilsTest : public content::RenderViewTest {
WebVector<WebFormControlElement> control_elements;
form.getFormControlElements(control_elements);
- ModifiedValues user_input;
+ FieldValueAndPropertiesMaskMap user_input;
for (size_t i = 0; i < control_elements.size(); ++i) {
WebInputElement* input_element = toWebInputElement(&control_elements[i]);
if (input_element->hasAttribute("set-activated-submit"))
input_element->setActivatedSubmit(true);
- if (with_user_input)
- user_input[*input_element] = input_element->value();
+ if (with_user_input) {
+ const base::string16 element_value = input_element->value();
+ user_input[control_elements[i]] =
+ std::make_pair(base::MakeUnique<base::string16>(element_value), 0U);
+ }
}
return CreatePasswordFormFromWebForm(
@@ -203,8 +207,8 @@ class MAYBE_PasswordFormConversionUtilsTest : public content::RenderViewTest {
FormData form_data;
ASSERT_TRUE(form_util::WebFormElementToFormData(
- form, WebFormControlElement(), form_util::EXTRACT_NONE, &form_data,
- nullptr));
+ form, WebFormControlElement(), nullptr, form_util::EXTRACT_NONE,
+ &form_data, nullptr));
FormStructure form_structure(form_data);
@@ -260,7 +264,6 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, BasicFormAttributes) {
EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form->scheme);
- EXPECT_FALSE(password_form->ssl_valid);
EXPECT_FALSE(password_form->preferred);
EXPECT_FALSE(password_form->blacklisted_by_user);
EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type);
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc
index 1264b0ce1cf..bc36e3d0142 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc
@@ -18,9 +18,11 @@
#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_generation_data.h"
#include "components/autofill/core/common/password_generation_util.h"
+#include "components/autofill/core/common/signatures_util.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
#include "google_apis/gaia/gaia_urls.h"
+#include "services/shell/public/cpp/interface_registry.h"
#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/web/WebDocument.h"
@@ -54,38 +56,39 @@ bool ContainsURL(const std::vector<GURL>& urls, const GURL& url) {
return std::find(urls.begin(), urls.end(), url) != urls.end();
}
+// Calculates the signature of |form| and searches it in |forms|.
const PasswordFormGenerationData* FindFormGenerationData(
const std::vector<PasswordFormGenerationData>& forms,
const PasswordForm& form) {
+ FormSignature form_signature = CalculateFormSignature(form.form_data);
for (const auto& form_it : forms) {
- if (form_it.name == form.form_data.name && form_it.action == form.action)
+ if (form_it.form_signature == form_signature)
return &form_it;
}
return nullptr;
}
// This function returns a vector of password fields into which Chrome should
-// fill the generated password. It assumes that |field_data| describes the field
-// where Chrome shows the password generation prompt. It returns no more
+// fill the generated password. It assumes that |field_signature| describes the
+// field where Chrome shows the password generation prompt. It returns no more
// than 2 elements.
std::vector<blink::WebInputElement> FindPasswordElementsForGeneration(
const std::vector<blink::WebInputElement>& all_password_elements,
- const base::string16& field_name) {
- auto iter =
- std::find_if(all_password_elements.begin(), all_password_elements.end(),
- [&field_name](const blink::WebInputElement& input) {
- // Make explicit conversion before comparing with string16.
- base::string16 input_name = input.nameForAutofill();
- return input_name == field_name;
- });
+ const FieldSignature field_signature) {
+ auto iter = std::find_if(
+ all_password_elements.begin(), all_password_elements.end(),
+ [&field_signature](const blink::WebInputElement& input) {
+ FieldSignature signature = CalculateFieldSignatureByNameAndType(
+ input.nameForAutofill(), input.formControlType().utf8());
+ return signature == field_signature;
+ });
std::vector<blink::WebInputElement> passwords;
// We copy not more than 2 fields because occasionally there are forms where
// the security question answers are put in password fields and we don't want
// to fill those.
- for (; iter != all_password_elements.end() && passwords.size() < 2; ++iter) {
+ for (; iter != all_password_elements.end() && passwords.size() < 2; ++iter)
passwords.push_back(*iter);
- }
return passwords;
}
@@ -127,11 +130,20 @@ PasswordGenerationAgent::PasswordGenerationAgent(
editing_popup_shown_(false),
enabled_(password_generation::IsPasswordGenerationEnabled()),
form_classifier_enabled_(false),
- password_agent_(password_agent) {
+ password_agent_(password_agent),
+ binding_(this) {
VLOG(2) << "Password Generation is " << (enabled_ ? "Enabled" : "Disabled");
+ // PasswordGenerationAgent is guaranteed to outlive |render_frame|.
+ render_frame->GetInterfaceRegistry()->AddInterface(base::Bind(
+ &PasswordGenerationAgent::BindRequest, base::Unretained(this)));
}
PasswordGenerationAgent::~PasswordGenerationAgent() {}
+void PasswordGenerationAgent::BindRequest(
+ mojom::PasswordGenerationAgentRequest request) {
+ binding_.Bind(std::move(request));
+}
+
void PasswordGenerationAgent::DidFinishDocumentLoad() {
// Update stats for main frame navigation.
if (!render_frame()->GetWebFrame()->parent()) {
@@ -189,6 +201,7 @@ void PasswordGenerationAgent::DidFinishLoad() {
}
void PasswordGenerationAgent::OnDestruct() {
+ binding_.Close();
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
}
@@ -196,7 +209,7 @@ void PasswordGenerationAgent::OnDynamicFormsSeen() {
FindPossibleGenerationForm();
}
-void PasswordGenerationAgent::OnAllowToRunFormClassifier() {
+void PasswordGenerationAgent::AllowToRunFormClassifier() {
form_classifier_enabled_ = true;
}
@@ -207,8 +220,8 @@ void PasswordGenerationAgent::RunFormClassifierAndSaveVote(
base::string16 generation_field;
ClassifyFormAndFindGenerationField(web_form, &generation_field);
- Send(new AutofillHostMsg_SaveGenerationFieldDetectedByClassifier(
- routing_id(), form, generation_field));
+ GetPasswordManagerDriver()->SaveGenerationFieldDetectedByClassifier(
+ form, generation_field);
}
void PasswordGenerationAgent::FindPossibleGenerationForm() {
@@ -280,30 +293,12 @@ bool PasswordGenerationAgent::ShouldAnalyzeDocument() const {
return true;
}
-bool PasswordGenerationAgent::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PasswordGenerationAgent, message)
- IPC_MESSAGE_HANDLER(AutofillMsg_FormNotBlacklisted,
- OnFormNotBlacklisted)
- IPC_MESSAGE_HANDLER(AutofillMsg_GeneratedPasswordAccepted,
- OnPasswordAccepted)
- IPC_MESSAGE_HANDLER(AutofillMsg_FoundFormsEligibleForGeneration,
- OnFormsEligibleForGenerationFound);
- IPC_MESSAGE_HANDLER(AutofillMsg_UserTriggeredGeneratePassword,
- OnUserTriggeredGeneratePassword);
- IPC_MESSAGE_HANDLER(AutofillMsg_AllowToRunFormClassifier,
- OnAllowToRunFormClassifier);
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void PasswordGenerationAgent::OnFormNotBlacklisted(const PasswordForm& form) {
+void PasswordGenerationAgent::FormNotBlacklisted(const PasswordForm& form) {
not_blacklisted_password_form_origins_.push_back(form.origin);
DetermineGenerationElement();
}
-void PasswordGenerationAgent::OnPasswordAccepted(
+void PasswordGenerationAgent::GeneratedPasswordAccepted(
const base::string16& password) {
password_is_generated_ = true;
password_generation::LogPasswordGenerationEvent(
@@ -325,8 +320,7 @@ void PasswordGenerationAgent::OnPasswordAccepted(
}
std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave());
if (presaved_form) {
- Send(new AutofillHostMsg_PresaveGeneratedPassword(routing_id(),
- *presaved_form));
+ GetPasswordManagerDriver()->PresaveGeneratedPassword(*presaved_form);
}
}
@@ -354,8 +348,8 @@ PasswordGenerationAgent::CreatePasswordFormToPresave() {
return password_form;
}
-void PasswordGenerationAgent::OnFormsEligibleForGenerationFound(
- const std::vector<autofill::PasswordFormGenerationData>& forms) {
+void PasswordGenerationAgent::FoundFormsEligibleForGeneration(
+ const std::vector<PasswordFormGenerationData>& forms) {
generation_enabled_forms_.insert(generation_enabled_forms_.end(),
forms.begin(), forms.end());
DetermineGenerationElement();
@@ -410,7 +404,7 @@ void PasswordGenerationAgent::DetermineGenerationElement() {
std::vector<blink::WebInputElement> password_elements =
generation_data ? FindPasswordElementsForGeneration(
possible_form_data.password_elements,
- generation_data->generation_field.name)
+ generation_data->field_signature)
: possible_form_data.password_elements;
if (password_elements.empty()) {
// It might be if JavaScript changes field names.
@@ -483,8 +477,7 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
std::unique_ptr<PasswordForm> presaved_form(
CreatePasswordFormToPresave());
if (presaved_form) {
- Send(new AutofillHostMsg_PasswordNoLongerGenerated(routing_id(),
- *presaved_form));
+ GetPasswordManagerDriver()->PasswordNoLongerGenerated(*presaved_form);
}
}
@@ -501,8 +494,7 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
&generation_form_data_->password_elements);
std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave());
if (presaved_form) {
- Send(new AutofillHostMsg_PresaveGeneratedPassword(routing_id(),
- *presaved_form));
+ GetPasswordManagerDriver()->PresaveGeneratedPassword(*presaved_form);
}
} else if (element.value().length() > kMaximumOfferSize) {
// User has rejected the feature and has started typing a password.
@@ -546,7 +538,7 @@ void PasswordGenerationAgent::HidePopup() {
Send(new AutofillHostMsg_HidePasswordGenerationPopup(routing_id()));
}
-void PasswordGenerationAgent::OnUserTriggeredGeneratePassword() {
+void PasswordGenerationAgent::UserTriggeredGeneratePassword() {
if (last_focused_password_element_.isNull() || !render_frame())
return;
@@ -574,11 +566,20 @@ void PasswordGenerationAgent::OnUserTriggeredGeneratePassword() {
std::vector<blink::WebInputElement> password_elements;
GetAccountCreationPasswordFields(control_elements, &password_elements);
password_elements = FindPasswordElementsForGeneration(
- password_elements, last_focused_password_element_.nameForAutofill());
+ password_elements,
+ CalculateFieldSignatureByNameAndType(
+ last_focused_password_element_.nameForAutofill(),
+ last_focused_password_element_.formControlType().utf8()));
generation_form_data_.reset(new AccountCreationFormData(
make_linked_ptr(password_form.release()), password_elements));
is_manually_triggered_ = true;
ShowGenerationPopup();
}
+const mojom::PasswordManagerDriverPtr&
+PasswordGenerationAgent::GetPasswordManagerDriver() {
+ DCHECK(password_agent_);
+ return password_agent_->GetPasswordManagerDriver();
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.h b/chromium/components/autofill/content/renderer/password_generation_agent.h
index 47f3a912e3e..df2b9a7a7e7 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.h
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.h
@@ -14,7 +14,10 @@
#include "base/macros.h"
#include "base/memory/linked_ptr.h"
+#include "components/autofill/content/public/interfaces/autofill_agent.mojom.h"
+#include "components/autofill/content/public/interfaces/autofill_driver.mojom.h"
#include "content/public/renderer/render_frame_observer.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
#include "url/gurl.h"
@@ -32,12 +35,26 @@ class PasswordAutofillAgent;
// This class is responsible for controlling communication for password
// generation between the browser (which shows the popup and generates
// passwords) and WebKit (shows the generation icon in the password field).
-class PasswordGenerationAgent : public content::RenderFrameObserver {
+class PasswordGenerationAgent : public content::RenderFrameObserver,
+ public mojom::PasswordGenerationAgent {
public:
PasswordGenerationAgent(content::RenderFrame* render_frame,
PasswordAutofillAgent* password_agent);
~PasswordGenerationAgent() override;
+ void BindRequest(mojom::PasswordGenerationAgentRequest request);
+
+ // mojom::PasswordGenerationAgent:
+ void FormNotBlacklisted(const PasswordForm& form) override;
+ void GeneratedPasswordAccepted(const base::string16& password) override;
+ void FoundFormsEligibleForGeneration(
+ const std::vector<PasswordFormGenerationData>& forms) override;
+ // Sets |generation_element_| to the focused password field and shows a
+ // generation popup at this field.
+ void UserTriggeredGeneratePassword() override;
+ // Enables the form classifier.
+ void AllowToRunFormClassifier() override;
+
// Returns true if the field being changed is one where a generated password
// is being offered. Updates the state of the popup if necessary.
bool TextDidChangeInTextField(const blink::WebInputElement& element);
@@ -74,16 +91,11 @@ class PasswordGenerationAgent : public content::RenderFrameObserver {
typedef std::vector<AccountCreationFormData> AccountCreationFormDataList;
// RenderFrameObserver:
- bool OnMessageReceived(const IPC::Message& message) override;
void DidFinishDocumentLoad() override;
void DidFinishLoad() override;
void OnDestruct() override;
- // Message handlers.
- void OnFormNotBlacklisted(const PasswordForm& form);
- void OnPasswordAccepted(const base::string16& password);
- void OnFormsEligibleForGenerationFound(
- const std::vector<autofill::PasswordFormGenerationData>& forms);
+ const mojom::PasswordManagerDriverPtr& GetPasswordManagerDriver();
// Helper function that will try and populate |password_elements_| and
// |possible_account_creation_form_|.
@@ -103,13 +115,6 @@ class PasswordGenerationAgent : public content::RenderFrameObserver {
// Hides a password generation popup if one exists.
void HidePopup();
- // Sets |generation_element_| to the focused password field and shows a
- // generation popup at this field.
- void OnUserTriggeredGeneratePassword();
-
- // Enables the form classifier.
- void OnAllowToRunFormClassifier();
-
// Runs HTML parsing based classifier and saves its outcome to proto.
// TODO(crbug.com/621442): Remove client-side form classifier when server-side
// classifier is ready.
@@ -177,6 +182,8 @@ class PasswordGenerationAgent : public content::RenderFrameObserver {
// in password fields are updated.
PasswordAutofillAgent* password_agent_;
+ mojo::Binding<mojom::PasswordGenerationAgent> binding_;
+
DISALLOW_COPY_AND_ASSIGN(PasswordGenerationAgent);
};
diff --git a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.cc b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.cc
index 413b5f5d56f..9dd724a22c1 100644
--- a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.cc
+++ b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.cc
@@ -6,24 +6,20 @@
#include "base/strings/string16.h"
#include "base/values.h"
-#include "components/autofill/content/common/autofill_messages.h"
-#include "ipc/ipc_sender.h"
#include "third_party/WebKit/public/web/WebFormControlElement.h"
namespace autofill {
RendererSavePasswordProgressLogger::RendererSavePasswordProgressLogger(
- IPC::Sender* sender,
- int routing_id)
- : sender_(sender), routing_id_(routing_id) {
- DCHECK(sender_);
+ mojom::PasswordManagerDriver* password_manager_driver)
+ : password_manager_driver_(password_manager_driver) {
+ DCHECK(password_manager_driver);
}
RendererSavePasswordProgressLogger::~RendererSavePasswordProgressLogger() {}
void RendererSavePasswordProgressLogger::SendLog(const std::string& log) {
- sender_->Send(
- new AutofillHostMsg_RecordSavePasswordProgress(routing_id_, log));
+ password_manager_driver_->RecordSavePasswordProgress(log);
}
void RendererSavePasswordProgressLogger::LogElementName(
diff --git a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.h b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.h
index bccfd1b0ef5..2ebe2b52900 100644
--- a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.h
+++ b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger.h
@@ -8,28 +8,23 @@
#include <string>
#include "base/macros.h"
+#include "components/autofill/content/public/interfaces/autofill_driver.mojom.h"
#include "components/autofill/core/common/save_password_progress_logger.h"
-class PasswordManagerClient;
-
namespace blink {
class WebFormControlElement;
}
-namespace IPC {
-class Sender;
-}
-
namespace autofill {
// This is the SavePasswordProgressLogger specialization for the renderer code,
// which sends logs to the browser process over IPC.
class RendererSavePasswordProgressLogger : public SavePasswordProgressLogger {
public:
- // The logger will use |sender| and |routing_id| to send a
- // AutofillHostMsg_RecordSavePasswordProgress message with the logs to the
- // browser. The |sender| needs to outlive the constructed logger.
- RendererSavePasswordProgressLogger(IPC::Sender* sender, int routing_id);
+ // The logger will use |password_manager_driver| to send logs to the browser.
+ // The |password_manager_driver| needs to outlive the constructed logger.
+ RendererSavePasswordProgressLogger(
+ mojom::PasswordManagerDriver* password_manager_driver);
~RendererSavePasswordProgressLogger() override;
void LogElementName(StringID label,
@@ -40,10 +35,9 @@ class RendererSavePasswordProgressLogger : public SavePasswordProgressLogger {
void SendLog(const std::string& log) override;
private:
- // Used by SendLog to send the IPC message with logs. |sender_| needs to
- // outlive the logger.
- IPC::Sender* const sender_;
- const int routing_id_;
+ // Used by SendLog to send the logs to the browser.
+ // |password_manager_driver_| needs to outlive the logger.
+ mojom::PasswordManagerDriver* password_manager_driver_;
DISALLOW_COPY_AND_ASSIGN(RendererSavePasswordProgressLogger);
};
diff --git a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
index 73c2bd82ce4..874f534e8ad 100644
--- a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
+++ b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
@@ -2,14 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "components/autofill/content/public/interfaces/autofill_driver.mojom.h"
#include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
+#include "mojo/public/cpp/bindings/binding.h"
-#include <stdint.h>
-
-#include <tuple>
-
-#include "components/autofill/content/common/autofill_messages.h"
-#include "ipc/ipc_test_sink.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
@@ -18,40 +16,91 @@ namespace {
const char kTestText[] = "test";
-class TestLogger : public RendererSavePasswordProgressLogger {
+class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver {
public:
- TestLogger() : RendererSavePasswordProgressLogger(&sink_, 0) {}
+ FakeContentPasswordManagerDriver()
+ : called_record_save_(false), binding_(this) {}
+ ~FakeContentPasswordManagerDriver() override {}
- using RendererSavePasswordProgressLogger::SendLog;
+ mojom::PasswordManagerDriverPtr CreateInterfacePtrAndBind() {
+ return binding_.CreateInterfacePtrAndBind();
+ }
- // Searches for an |AutofillHostMsg_RecordSavePasswordProgress| message in the
- // queue of sent IPC messages. If none is present, returns false. Otherwise,
- // extracts the first |AutofillHostMsg_RecordSavePasswordProgress| message,
- // fills the output parameter with the value of the message's parameter, and
- // clears the queue of sent messages.
bool GetLogMessage(std::string* log) {
- const uint32_t kMsgID = AutofillHostMsg_RecordSavePasswordProgress::ID;
- const IPC::Message* message = sink_.GetFirstMessageMatching(kMsgID);
- if (!message)
+ if (!called_record_save_)
return false;
- std::tuple<std::string> param;
- AutofillHostMsg_RecordSavePasswordProgress::Read(message, &param);
- *log = std::get<0>(param);
- sink_.ClearMessages();
+
+ EXPECT_TRUE(log_);
+ *log = *log_;
return true;
}
private:
- IPC::TestSink sink_;
+ // autofill::mojom::PasswordManagerDriver:
+ void PasswordFormsParsed(
+ const std::vector<autofill::PasswordForm>& forms) override {}
+
+ void PasswordFormsRendered(
+ const std::vector<autofill::PasswordForm>& visible_forms,
+ bool did_stop_loading) override {}
+
+ void PasswordFormSubmitted(
+ const autofill::PasswordForm& password_form) override {}
+
+ void InPageNavigation(const autofill::PasswordForm& password_form) override {}
+
+ void PresaveGeneratedPassword(
+ const autofill::PasswordForm& password_form) override {}
+
+ void PasswordNoLongerGenerated(
+ const autofill::PasswordForm& password_form) override {}
+
+ void ShowPasswordSuggestions(int key,
+ base::i18n::TextDirection text_direction,
+ const base::string16& typed_username,
+ int options,
+ const gfx::RectF& bounds) override {}
+
+ void PasswordAutofillAgentConstructed() override {}
+
+ void RecordSavePasswordProgress(const std::string& log) override {
+ called_record_save_ = true;
+ log_ = log;
+ }
+
+ void SaveGenerationFieldDetectedByClassifier(
+ const autofill::PasswordForm& password_form,
+ const base::string16& generation_field) override {}
+
+ // Records whether RecordSavePasswordProgress() gets called.
+ bool called_record_save_;
+ // Records data received via RecordSavePasswordProgress() call.
+ base::Optional<std::string> log_;
+
+ mojo::Binding<mojom::PasswordManagerDriver> binding_;
+};
+
+class TestLogger : public RendererSavePasswordProgressLogger {
+ public:
+ TestLogger(mojom::PasswordManagerDriver* driver)
+ : RendererSavePasswordProgressLogger(driver) {}
+
+ using RendererSavePasswordProgressLogger::SendLog;
};
} // namespace
TEST(RendererSavePasswordProgressLoggerTest, SendLog) {
- TestLogger logger;
+ base::MessageLoop loop;
+ FakeContentPasswordManagerDriver fake_driver;
+ mojom::PasswordManagerDriverPtr driver_ptr =
+ fake_driver.CreateInterfacePtrAndBind();
+ TestLogger logger(driver_ptr.get());
logger.SendLog(kTestText);
+
+ base::RunLoop().RunUntilIdle();
std::string sent_log;
- EXPECT_TRUE(logger.GetLogMessage(&sent_log));
+ EXPECT_TRUE(fake_driver.GetLogMessage(&sent_log));
EXPECT_EQ(kTestText, sent_log);
}
diff --git a/chromium/components/autofill/content/renderer/test_password_generation_agent.h b/chromium/components/autofill/content/renderer/test_password_generation_agent.h
index c8e81193808..333b4321016 100644
--- a/chromium/components/autofill/content/renderer/test_password_generation_agent.h
+++ b/chromium/components/autofill/content/renderer/test_password_generation_agent.h
@@ -10,7 +10,6 @@
#include "base/macros.h"
#include "base/memory/scoped_vector.h"
#include "components/autofill/content/renderer/password_generation_agent.h"
-#include "ipc/ipc_message.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index b51755e6f88..8e79dc304df 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -4,8 +4,7 @@
import("//build/config/chrome_build.gni")
-# GYP version: components/autofill.gyp:autofill_core_browser
-source_set("browser") {
+static_library("browser") {
sources = [
"address.cc",
"address.h",
@@ -147,8 +146,6 @@ source_set("browser") {
if (is_ios) {
sources += [
- "autofill_field_trial_ios.cc",
- "autofill_field_trial_ios.h",
"keyboard_accessory_metrics_logger.h",
"keyboard_accessory_metrics_logger.mm",
]
@@ -156,6 +153,10 @@ source_set("browser") {
if (is_ios || is_android) {
sources += [
+ "autofill_assistant.cc",
+ "autofill_assistant.h",
+ "autofill_credit_card_filling_infobar_delegate_mobile.cc",
+ "autofill_credit_card_filling_infobar_delegate_mobile.h",
"autofill_save_card_infobar_delegate_mobile.cc",
"autofill_save_card_infobar_delegate_mobile.h",
"autofill_save_card_infobar_mobile.h",
@@ -164,10 +165,13 @@ source_set("browser") {
configs += [ "//build/config:precompiled_headers" ]
+ public_deps = [
+ "//components/autofill/core/browser/proto",
+ "//components/autofill/core/common",
+ ]
deps = [
"//base",
"//base:i18n",
- "//components/autofill/core/common",
"//components/data_use_measurement/core",
"//components/infobars/core",
"//components/keyed_service/core",
@@ -179,7 +183,7 @@ source_set("browser") {
"//components/signin/core/browser",
"//components/signin/core/common",
"//components/strings",
- "//components/sync_driver",
+ "//components/sync",
"//components/variations/net",
"//components/version_info",
"//components/webdata/common",
@@ -187,7 +191,6 @@ source_set("browser") {
"//net",
"//skia",
"//sql",
- "//sync",
"//third_party/fips181",
"//third_party/icu",
"//third_party/libaddressinput:util",
@@ -200,10 +203,6 @@ source_set("browser") {
"//url",
]
- public_deps = [
- "//components/autofill/core/browser/proto",
- ]
-
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
if (is_mac) {
@@ -211,7 +210,7 @@ source_set("browser") {
}
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"autofill_test_utils.cc",
@@ -323,6 +322,10 @@ source_set("unit_tests") {
"webdata/web_data_service_unittest.cc",
]
+ if (is_ios || is_android) {
+ sources += [ "autofill_assistant_unittest.cc" ]
+ }
+
deps = [
":browser",
":test_support",
@@ -339,8 +342,9 @@ source_set("unit_tests") {
"//components/signin/core/browser:test_support",
"//components/signin/core/common",
"//components/strings",
- "//components/sync_driver",
- "//components/sync_driver:test_support",
+ "//components/sync",
+ "//components/sync:test_support_sync_api",
+ "//components/sync:test_support_sync_driver",
"//components/variations",
"//components/webdata/common",
"//components/webdata_services:test_support",
@@ -348,8 +352,6 @@ source_set("unit_tests") {
"//google_apis:test_support",
"//net:test_support",
"//sql",
- "//sync",
- "//sync:test_support_sync_api",
"//testing/gmock",
"//testing/gtest",
"//third_party/libaddressinput:util",
diff --git a/chromium/components/autofill/core/browser/DEPS b/chromium/components/autofill/core/browser/DEPS
index f0d3ea8a3a2..42f1d17a0b7 100644
--- a/chromium/components/autofill/core/browser/DEPS
+++ b/chromium/components/autofill/core/browser/DEPS
@@ -4,7 +4,7 @@ include_rules = [
"+components/keyed_service/core",
"+components/signin/core/browser",
"+components/signin/core/common",
- "+components/sync_driver",
+ "+components/sync",
"+components/variations",
"+components/version_info",
"+components/webdata/common",
@@ -14,7 +14,6 @@ include_rules = [
"+google_apis/google_api_keys.h",
"+net",
"+sql",
- "+sync",
"+third_party/fips181",
"+third_party/libaddressinput", # For address i18n.
"+third_party/libphonenumber", # For phone number i18n.
diff --git a/chromium/components/autofill/core/browser/address_rewriter_rules.cc b/chromium/components/autofill/core/browser/address_rewriter_rules.cc
index 214d293936d..bea463c2a85 100644
--- a/chromium/components/autofill/core/browser/address_rewriter_rules.cc
+++ b/chromium/components/autofill/core/browser/address_rewriter_rules.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.
//
-// Generated 2016-07-06T19:18:28Z
+// Generated 2016-10-20T18:50:22Z
#include "components/autofill/core/browser/address_rewriter.h"
@@ -12,14 +12,14 @@ namespace {
const Rule kRules_AD[] = {
{"\\bparroquia\\s+de\\s+andorra\\s+la\\s+vella\\b", "07"},
- {"\\bprincipat\\s+de\\s+andorra\\b", "07"},
{"\\bprincipal\\s+de\\s+andorra\\b", "07"},
- {"\\bsant\\s+julia\\s+de\\s+loria\\b", "jl"},
+ {"\\bprincipat\\s+de\\s+andorra\\b", "07"},
+ {"\\bsant\\s+julia\\s+de\\s+loria\\b", "06"},
{"\\bescaldes\\s+engordany\\b", "08"},
{"\\bandorra\\s+la\\s+vella\\b", "07"},
{"\\bcarrer\\s+del\\b", ""},
{"\\bla\\s+massana\\b", "04"},
- {"\\bsant\\s+julia\\b", "jl"},
+ {"\\bsant\\s+julia\\b", "06"},
{"\\bcarrer\\s+de\\b", ""},
{"\\bandorra\\b", "07"},
{"\\bcanillo\\b", "02"},
@@ -28,61 +28,61 @@ const Rule kRules_AD[] = {
{"\\bordino\\b", "05"},
{"\\bc\\s+del\\b", ""},
{"\\bc\\s+de\\b", ""},
+ {"\\bad\\b", "07"},
{"\\ban\\b", "07"},
{"\\bca\\b", "02"},
- {"\\ben\\b", "03"},
{"\\bee\\b", "08"},
+ {"\\ben\\b", "03"},
+ {"\\bjl\\b", "06"},
{"\\bma\\b", "04"},
{"\\bor\\b", "05"},
- {"\\b06\\b", "jl"},
- {"\\bad\\b", "07"},
};
const Rule kRules_AR[] = {
{"\\btierra\\s+del\\s+fuego\\s+antartida\\s+e\\s+islas\\s+del\\s+"
- "atlantico\\s+sur\\b",
- "tierra del fuego"},
+ "atlantico\\s+sur\\b",
+ "tierra del fuego"},
{"\\bciudad\\s+autonoma\\s+de\\s+buenos\\s+aires\\b", "caba"},
{"\\bla\\s+ciudad\\s+de\\s+buenos\\s+aires\\b", "caba"},
{"\\bcapital\\s+federal\\b", "caba"},
- {"\\bdiecisiete\\b", "17"},
{"\\bdiecinueve\\b", "19"},
- {"\\bdieciseis\\b", "16"},
- {"\\bdieciocho\\b", "18"},
- {"\\bboulevard\\b", "bv"},
+ {"\\bdiecisiete\\b", "17"},
{"\\bargentina\\b", "ar"},
+ {"\\bboulevard\\b", "bv"},
+ {"\\bdieciocho\\b", "18"},
+ {"\\bdieciseis\\b", "16"},
+ {"\\bavenida\\b", "av"},
+ {"\\bcatorce\\b", "14"},
{"\\bprimera\\b", "1a"},
{"\\bsegunda\\b", "2a"},
- {"\\btercera\\b", "3a"},
{"\\bseptima\\b", "7a"},
- {"\\bcatorce\\b", "14"},
- {"\\bavenida\\b", "av"},
+ {"\\btercera\\b", "3a"},
{"\\bcuarta\\b", "4a"},
- {"\\bquinta\\b", "5a"},
- {"\\boctava\\b", "8a"},
{"\\bcuatro\\b", "4"},
+ {"\\boctava\\b", "8a"},
+ {"\\bpasaje\\b", "pje"},
{"\\bquince\\b", "15"},
+ {"\\bquinta\\b", "5a"},
{"\\bveinte\\b", "20"},
- {"\\bpasaje\\b", "pje"},
- {"\\bsexta\\b", "6a"},
{"\\bcinco\\b", "5"},
- {"\\bsiete\\b", "7"},
{"\\bnueve\\b", "9"},
+ {"\\bsexta\\b", "6a"},
+ {"\\bsiete\\b", "7"},
{"\\btrece\\b", "13"},
- {"\\btres\\b", "3"},
- {"\\bseis\\b", "6"},
- {"\\bocho\\b", "8"},
{"\\bdiez\\b", "10"},
- {"\\bonce\\b", "11"},
{"\\bdoce\\b", "12"},
- {"\\buno\\b", "1"},
+ {"\\bocho\\b", "8"},
+ {"\\bonce\\b", "11"},
+ {"\\bseis\\b", "6"},
+ {"\\btres\\b", "3"},
+ {"\\bdel\\b", ""},
{"\\bdos\\b", "2"},
- {"\\blos\\b", ""},
{"\\blas\\b", ""},
- {"\\bdel\\b", ""},
- {"\\ble\\b", ""},
- {"\\bel\\b", ""},
+ {"\\blos\\b", ""},
+ {"\\buno\\b", "1"},
{"\\bde\\b", ""},
+ {"\\bel\\b", ""},
+ {"\\ble\\b", ""},
};
const Rule kRules_AU[] = {
@@ -93,69 +93,69 @@ const Rule kRules_AU[] = {
{"\\bnew\\s+south\\s+wales\\b", "nsw"},
{"\\bsouth\\s+australia\\b", "sa"},
{"\\bqueensland\\b", "qld"},
- {"\\bboulevard\\b", "blvd"},
{"\\baustralia\\b", "au"},
+ {"\\bboulevard\\b", "blvd"},
{"\\bcrescent\\b", "cres"},
- {"\\bvictoria\\b", "vic"},
{"\\btasmania\\b", "tas"},
- {"\\bparkway\\b", "pkwy"},
+ {"\\bvictoria\\b", "vic"},
{"\\bhighway\\b", "hwy"},
- {"\\bavenue\\b", "ave"},
- {"\\bstreet\\b", "st"},
- {"\\bparade\\b", "pde"},
- {"\\bcommon\\b", "comm"},
- {"\\bau\\-vic\\b", "vic"},
+ {"\\bparkway\\b", "pkwy"},
{"\\ba\\.c\\.t\\.\\b", "act"},
{"\\bau\\-act\\b", "act"},
- {"\\bj\\.b\\.t\\.\\b", "jbt"},
{"\\bau\\-jbt\\b", "jbt"},
- {"\\bn\\.s\\.w\\.\\b", "nsw"},
{"\\bau\\-nsw\\b", "nsw"},
{"\\bau\\-qld\\b", "qld"},
{"\\bau\\-tas\\b", "tas"},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bthree\\b", "3"},
- {"\\bseven\\b", "7"},
- {"\\beight\\b", "8"},
- {"\\bmount\\b", "mt"},
- {"\\bsaint\\b", "st"},
- {"\\bpoint\\b", "pt"},
+ {"\\bau\\-vic\\b", "vic"},
+ {"\\bavenue\\b", "ave"},
+ {"\\bcommon\\b", "comm"},
+ {"\\bj\\.b\\.t\\.\\b", "jbt"},
+ {"\\bn\\.s\\.w\\.\\b", "nsw"},
+ {"\\bparade\\b", "pde"},
+ {"\\bstreet\\b", "st"},
+ {"\\ba\\.c\\.t\\b", "act"},
+ {"\\bau\\-nt\\b", "nt"},
+ {"\\bau\\-sa\\b", "sa"},
+ {"\\bau\\-wa\\b", "wa"},
{"\\bcourt\\b", "ct"},
- {"\\bplace\\b", "pl"},
{"\\bdrive\\b", "dr"},
- {"\\ba\\.c\\.t\\b", "act"},
+ {"\\beight\\b", "8"},
{"\\bj\\.b\\.t\\b", "jbt"},
+ {"\\bmount\\b", "mt"},
{"\\bn\\.s\\.w\\b", "nsw"},
- {"\\bau\\-nt\\b", "nt"},
- {"\\bau\\-wa\\b", "wa"},
- {"\\bau\\-sa\\b", "sa"},
+ {"\\bnorth\\b", "n"},
+ {"\\bplace\\b", "pl"},
+ {"\\bpoint\\b", "pt"},
+ {"\\bsaint\\b", "st"},
+ {"\\bseven\\b", "7"},
+ {"\\bsouth\\b", "s"},
+ {"\\bthree\\b", "3"},
{"\\beast\\b", "e"},
- {"\\bwest\\b", "w"},
- {"\\bfour\\b", "4"},
{"\\bfive\\b", "5"},
- {"\\bnine\\b", "9"},
- {"\\broad\\b", "rd"},
+ {"\\bfour\\b", "4"},
{"\\blane\\b", "ln"},
{"\\bn\\.t\\.\\b", "nt"},
- {"\\bw\\.a\\.\\b", "wa"},
+ {"\\bnine\\b", "9"},
+ {"\\broad\\b", "rd"},
{"\\bs\\.a\\.\\b", "sa"},
+ {"\\bw\\.a\\.\\b", "wa"},
+ {"\\bwest\\b", "w"},
+ {"\\baus\\b", "au"},
+ {"\\bmt\\.\\b", "mt"},
+ {"\\bn\\.t\\b", "nt"},
{"\\bnth\\b", "n"},
- {"\\bsth\\b", "s"},
{"\\bone\\b", "1"},
- {"\\btwo\\b", "2"},
+ {"\\bpt\\.\\b", "pt"},
+ {"\\bs\\.a\\b", "sa"},
{"\\bsix\\b", "6"},
- {"\\bten\\b", "10"},
- {"\\bmt\\.\\b", "mt"},
{"\\bst\\.\\b", "st"},
- {"\\bpt\\.\\b", "pt"},
- {"\\bn\\.t\\b", "nt"},
+ {"\\bsth\\b", "s"},
+ {"\\bten\\b", "10"},
+ {"\\btwo\\b", "2"},
{"\\bw\\.a\\b", "wa"},
- {"\\bs\\.a\\b", "sa"},
- {"\\baus\\b", "au"},
+ {"\\be\\.\\b", "e"},
{"\\bn\\.\\b", "n"},
{"\\bs\\.\\b", "s"},
- {"\\be\\.\\b", "e"},
{"\\bw\\.\\b", "w"},
};
@@ -174,114 +174,114 @@ const Rule kRules_BE[] = {
{"\\bseptieme\\s+d\\s+i\\s+francaise\\b", "7eme division frcse"},
{"\\bwereldtentoonstellings\\b", "wereldtentoonstelings"},
{"\\bberchem\\s+sainte\\s+agathe\\b", "st agatha berchem"},
- {"\\bsaint\\s+josse\\s+ten\\s+noode\\b", "saint josse"},
{"\\bflandres\\s+occidentales\\b", "westflandern"},
+ {"\\bsaint\\s+josse\\s+ten\\s+noode\\b", "saint josse"},
+ {"\\bflandre\\s+occidentales\\b", "westflandern"},
+ {"\\bflandres\\s+occidentale\\b", "westflandern"},
{"\\bhenri\\s+victor\\s+wolvens\\b", "h v wolvens"},
{"\\bjoseph\\s+van\\s+boterdael\\b", "joseph van boterdae"},
{"\\bmarilyn\\s+monroegaarde\\b", "marilyn monroe"},
- {"\\bflandre\\s+occidentales\\b", "westflandern"},
- {"\\bflandres\\s+occidentale\\b", "westflandern"},
- {"\\bwoluwe\\s+saint\\s+pierre\\b", "st pieters woluwe"},
- {"\\bflandres\\s+orientales\\b", "ostflandern"},
{"\\bflandre\\s+occidentale\\b", "westflandern"},
- {"\\bhendrik\\s+conscience\\b", "henri conscience"},
- {"\\bleonoardo\\s+da\\s+vinci\\b", "leonard de vinci"},
+ {"\\bflandres\\s+orientales\\b", "ostflandern"},
+ {"\\bwoluwe\\s+saint\\s+pierre\\b", "st pieters woluwe"},
{"\\bbruxelles\\s+capitale\\b", "brussel"},
- {"\\bwallonische\\s+region\\b", "wallonie"},
{"\\bflandre\\s+orientales\\b", "ostflandern"},
{"\\bflandres\\s+orientale\\b", "ostflandern"},
+ {"\\bhendrik\\s+conscience\\b", "henri conscience"},
+ {"\\bleonoardo\\s+da\\s+vinci\\b", "leonard de vinci"},
{"\\bwallonisch\\s+brabant\\b", "waals brabant"},
+ {"\\bwallonische\\s+region\\b", "wallonie"},
{"\\bbischoffsheimlaan\\b", "bischoffsheim"},
{"\\bbrouck\\s+du\\s+tilleul\\b", "brouck au tilleul"},
- {"\\bleonardo\\s+da\\s+vinci\\b", "leonard de vinci"},
{"\\bflandre\\s+orientale\\b", "ostflandern"},
+ {"\\bleonardo\\s+da\\s+vinci\\b", "leonard de vinci"},
{"\\barmand\\s+scheitler\\b", "armand scheiter"},
+ {"\\bflamisch\\s+brabant\\b", "vlaams brabant"},
+ {"\\bflamische\\s+region\\b", "vlaams gewest"},
{"\\bhenri\\s+wafelaerts\\b", "henri wafelaert"},
- {"\\bpierre\\s+hauwaerts\\b", "pieter hauwaerts"},
- {"\\brennequin\\s+sualem\\b", "renkin sualem"},
+ {"\\bpieter\\s+hauwaerts\\b", "pierre hauwaerts"},
{"\\bregion\\s+wallonien\\b", "wallonie"},
- {"\\bflamische\\s+region\\b", "vlaams gewest"},
- {"\\bflamisch\\s+brabant\\b", "vlaams brabant"},
+ {"\\brennequin\\s+sualem\\b", "renkin sualem"},
{"\\baugust\\s+de\\s+boeck\\b", "a de boeck"},
- {"\\bgodefroid\\s+kurth\\b", "godfroid kurth"},
+ {"\\bbrabant\\s+flamand\\b", "vlaams brabant"},
{"\\bbruxelles\\s+ville\\b", "brussel"},
- {"\\bregion\\s+wallonne\\b", "wallonie"},
- {"\\bregion\\s+flamande\\b", "vlaams gewest"},
{"\\bflamisch\\s+region\\b", "vlaams gewest"},
- {"\\bbrabant\\s+flamand\\b", "vlaams brabant"},
+ {"\\bgodefroid\\s+kurth\\b", "godfroid kurth"},
{"\\boost\\s+vlaanderen\\b", "ostflandern"},
+ {"\\bregion\\s+flamande\\b", "vlaams gewest"},
+ {"\\bregion\\s+wallonne\\b", "wallonie"},
{"\\bwest\\s+vlaanderen\\b", "westflandern"},
- {"\\blimburg\\s+stirum\\b", "limburg strium"},
{"\\barrondissement\\b", ""},
{"\\bbrabant\\s+wallon\\b", "waals brabant"},
+ {"\\blimburg\\s+strium\\b", "limburg stirum"},
+ {"\\bde\\s+ribaucourt\\b", "ribaucourt"},
{"\\bmichel\\s+angelo\\b", "michel ange"},
{"\\bpater\\s+damiaan\\b", "pater damian"},
- {"\\bsualem\\s+renkin\\b", "renkin sualem"},
- {"\\bde\\s+ribaucourt\\b", "ribaucourt"},
{"\\bprofondeville\\b", "profondville"},
- {"\\bsint\\s+lenaarts\\b", "sint lenaerts"},
+ {"\\bsint\\s+lenaerts\\b", "sint lenaarts"},
+ {"\\bsualem\\s+renkin\\b", "renkin sualem"},
{"\\bdendermondse\\b", "dendermonde"},
{"\\bminnezangers\\b", "menestrelen"},
{"\\bvooruitgangs\\b", "vooruitgang"},
{"\\bwaals\\s+gewest\\b", "wallonie"},
- {"\\bjette\\s+jetse\\b", "jette"},
- {"\\bi\\s+urbanisme\\b", "l urbanisme"},
- {"\\bpuits\\s+no\\s+iv\\b", "puits n4"},
- {"\\bterhulpense\\b", "terhulpse"},
{"\\bcortenbergh\\b", "cortenberg"},
+ {"\\bjette\\s+jetse\\b", "jette"},
+ {"\\bl\\s+urbanisme\\b", "i urbanisme"},
{"\\bprovince\\s+de\\b", ""},
{"\\bprovince\\s+du\\b", ""},
+ {"\\bpuits\\s+no\\s+iv\\b", "puits n4"},
+ {"\\bterhulpense\\b", "terhulpse"},
+ {"\\bhenegouwen\\b", "hainaut"},
{"\\blanguesdoc\\b", "languedoc"},
+ {"\\bluxembourg\\b", "luxemburg"},
+ {"\\bprovince\\s+d\\b", ""},
{"\\bpuit\\s+no\\s+iv\\b", "puits n4"},
{"\\bvan\\s+volxem\\b", "volxem"},
- {"\\bprovince\\s+d\\b", ""},
- {"\\bhenegouwen\\b", "hainaut"},
- {"\\bluxembourg\\b", "luxemburg"},
+ {"\\bantwerpen\\b", "anvers"},
{"\\bboulevard\\b", "bd"},
- {"\\bluitenant\\b", "liutenant"},
- {"\\bwestphael\\b", "wesphal"},
{"\\bbruxelles\\b", "brussel"},
+ {"\\bluitenant\\b", "liutenant"},
{"\\bwallonien\\b", "wallonie"},
- {"\\bantwerpen\\b", "anvers"},
+ {"\\bwestphael\\b", "wesphal"},
+ {"\\bbelgique\\b", "be"},
+ {"\\bbrussels\\b", "brussel"},
{"\\bchaussee\\b", "chee"},
+ {"\\bhennegau\\b", "hainaut"},
+ {"\\blimbourg\\b", "limburg"},
{"\\bsteenweg\\b", "stwg"},
{"\\bterrasse\\b", "tsse"},
{"\\bwestphal\\b", "wesphal"},
- {"\\bbrussels\\b", "brussel"},
- {"\\blimbourg\\b", "limburg"},
- {"\\bhennegau\\b", "hainaut"},
- {"\\bbelgique\\b", "be"},
{"\\bavenues\\b", "av"},
+ {"\\bbelgien\\b", "be"},
+ {"\\bbelgium\\b", "be"},
+ {"\\bde\\s+wand\\b", "wand"},
{"\\bimpasse\\b", "imp"},
- {"\\bstrasse\\b", "str"},
{"\\bjettese\\b", "jetse"},
- {"\\bde\\s+wand\\b", "wand"},
- {"\\bprovinz\\b", ""},
{"\\bluttich\\b", "luik"},
- {"\\bbelgium\\b", "be"},
- {"\\bbelgien\\b", "be"},
- {"\\bsainte\\b", "st"},
+ {"\\bprovinz\\b", ""},
+ {"\\bstrasse\\b", "str"},
{"\\ballees\\b", "all"},
{"\\bavenue\\b", "av"},
+ {"\\bbelgie\\b", "be"},
{"\\bcentre\\b", "ctre"},
+ {"\\bsainte\\b", "st"},
{"\\bsquare\\b", "sq"},
{"\\bstraat\\b", "str"},
- {"\\bbelgie\\b", "be"},
- {"\\bsaint\\b", "st"},
- {"\\bsankt\\b", "st"},
{"\\ballee\\b", "all"},
+ {"\\bliege\\b", "luik"},
+ {"\\bnamur\\b", "namen"},
+ {"\\bpiein\\b", "pl"},
{"\\bplace\\b", "pl"},
{"\\bplatz\\b", "pl"},
{"\\bplein\\b", "pl"},
- {"\\bpiein\\b", "pl"},
{"\\broute\\b", "rte"},
+ {"\\bsaint\\b", "st"},
+ {"\\bsankt\\b", "st"},
{"\\bthier\\b", "their"},
- {"\\bnamur\\b", "namen"},
- {"\\bliege\\b", "luik"},
{"\\bsint\\b", "st"},
- {"\\bste\\b", "st"},
{"\\bdes\\b", "d"},
{"\\brue\\b", "r"},
+ {"\\bste\\b", "st"},
{"\\bde\\b", "d"},
{"\\bdu\\b", "d"},
};
@@ -293,227 +293,228 @@ const Rule kRules_BR[] = {
{"\\bdistrito\\s+federal\\b", "df"},
{"\\bdecimo\\s+primeiro\\b", "11"},
{"\\bdecimo\\s+terceiro\\b", "13"},
- {"\\bvinte\\s+e\\s+quatro\\b", "24"},
{"\\bespirito\\s+santo\\b", "es"},
{"\\brio\\s+de\\s+janeiro\\b", "rj"},
{"\\bsanta\\s+catarina\\b", "sc"},
+ {"\\bvinte\\s+e\\s+quatro\\b", "24"},
+ {"\\bdecimo\\s+oitavo\\b", "18"},
{"\\bdecimo\\s+quarto\\b", "14"},
{"\\bdecimo\\s+quinto\\b", "15"},
{"\\bdecimo\\s+setimo\\b", "17"},
- {"\\bdecimo\\s+oitavo\\b", "18"},
{"\\bvinte\\s+e\\s+cinco\\b", "25"},
{"\\bdecimo\\s+sexto\\b", "16"},
+ {"\\bminas\\s+gerais\\b", "mg"},
{"\\bvinte\\s+e\\s+dois\\b", "22"},
- {"\\bvinte\\s+e\\s+tres\\b", "23"},
+ {"\\bvinte\\s+e\\s+nove\\b", "29"},
+ {"\\bvinte\\s+e\\s+oito\\b", "28"},
{"\\bvinte\\s+e\\s+seis\\b", "26"},
{"\\bvinte\\s+e\\s+sete\\b", "27"},
- {"\\bvinte\\s+e\\s+oito\\b", "28"},
- {"\\bvinte\\s+e\\s+nove\\b", "29"},
- {"\\bminas\\s+gerais\\b", "mg"},
+ {"\\bvinte\\s+e\\s+tres\\b", "23"},
{"\\bdecimo\\s+nono\\b", "19"},
{"\\bmato\\s+grosso\\b", "mt"},
- {"\\bvinte\\s+e\\s+um\\b", "21"},
- {"\\bgovernador\\b", "gov"},
- {"\\bpresidente\\b", "pres"},
{"\\bcomandante\\b", "com"},
+ {"\\bgovernador\\b", "gov"},
{"\\bpernambuco\\b", "pe"},
- {"\\bduodecimo\\b", "12"},
+ {"\\bpresidente\\b", "pres"},
+ {"\\bvinte\\s+e\\s+um\\b", "21"},
+ {"\\bcinquenta\\b", "50"},
{"\\bdezesseis\\b", "16"},
{"\\bdezessete\\b", "17"},
- {"\\bcinquenta\\b", "50"},
- {"\\brepublica\\b", "rep"},
+ {"\\bduodecimo\\b", "12"},
{"\\bprofessor\\b", "prof"},
+ {"\\brepublica\\b", "rep"},
{"\\bsao\\s+paulo\\b", "sp"},
{"\\btocantins\\b", "to"},
- {"\\bprimeiro\\b", "i"},
- {"\\bterceiro\\b", "3"},
- {"\\bdezenove\\b", "19"},
- {"\\bvigesimo\\b", "20"},
- {"\\bquarenta\\b", "40"},
- {"\\bsessenta\\b", "60"},
- {"\\bprincesa\\b", "prsa"},
- {"\\bsargento\\b", "sct"},
{"\\bamazonas\\b", "am"},
+ {"\\bdezenove\\b", "19"},
{"\\bmaranhao\\b", "ma"},
+ {"\\bprimeiro\\b", "1"},
+ {"\\bprincesa\\b", "prsa"},
+ {"\\bquarenta\\b", "40"},
{"\\brondonia\\b", "ro"},
- {"\\bsegundo\\b", "2"},
+ {"\\bsargento\\b", "sct"},
+ {"\\bsessenta\\b", "60"},
+ {"\\bterceiro\\b", "3"},
+ {"\\bvigesimo\\b", "20"},
+ {"\\balagoas\\b", "al"},
+ {"\\balameda\\b", "al"},
+ {"\\bavenida\\b", "av"},
{"\\bcatorze\\b", "14"},
- {"\\bdezoito\\b", "18"},
- {"\\bsetenta\\b", "70"},
- {"\\boitenta\\b", "80"},
- {"\\bnoventa\\b", "90"},
- {"\\bsenador\\b", "sen"},
{"\\bcoronel\\b", "cel"},
- {"\\bavenida\\b", "av"},
+ {"\\bdezoito\\b", "18"},
{"\\bestrada\\b", "estr"},
- {"\\balameda\\b", "al"},
- {"\\balagoas\\b", "al"},
+ {"\\bnoventa\\b", "90"},
+ {"\\boitenta\\b", "80"},
{"\\bparaiba\\b", "pb"},
{"\\broraima\\b", "rr"},
+ {"\\bsegundo\\b", "2"},
+ {"\\bsenador\\b", "sen"},
{"\\bsergipe\\b", "se"},
+ {"\\bsetenta\\b", "70"},
+ {"\\bbrasil\\b", "b"},
+ {"\\bbrazil\\b", "b"},
+ {"\\bdecimo\\b", "x"},
+ {"\\bdoutor\\b", "dr"},
+ {"\\boitavo\\b", "8"},
+ {"\\bparana\\b", "pr"},
+ {"\\bprincs\\b", "prsa"},
{"\\bquarto\\b", "4"},
{"\\bquatro\\b", "4"},
{"\\bquinto\\b", "5"},
- {"\\bsetimo\\b", "7"},
- {"\\boitavo\\b", "8"},
- {"\\bdecimo\\b", "x"},
{"\\bquinze\\b", "15"},
+ {"\\bsetimo\\b", "7"},
{"\\btrinta\\b", "30"},
- {"\\bprincs\\b", "prsa"},
- {"\\bdoutor\\b", "dr"},
- {"\\bparana\\b", "pr"},
- {"\\bbrazil\\b", "b"},
- {"\\bbrasil\\b", "b"},
- {"\\bnorte\\b", "n"},
- {"\\boeste\\b", "w"},
- {"\\bcinco\\b", "5"},
- {"\\bsexto\\b", "6"},
- {"\\btreze\\b", "13"},
- {"\\bvinte\\b", "20"},
- {"\\bbarao\\b", "b"},
- {"\\bduque\\b", "dq"},
- {"\\bsanta\\b", "sta"},
- {"\\bconde\\b", "cde"},
- {"\\bpadre\\b", "pe"},
- {"\\bviela\\b", "vl"},
{"\\bamapa\\b", "ap"},
{"\\bbahia\\b", "ba"},
+ {"\\bbarao\\b", "b"},
{"\\bceara\\b", "ce"},
+ {"\\bcinco\\b", "5"},
+ {"\\bconde\\b", "cde"},
+ {"\\bduque\\b", "dq"},
{"\\bgoias\\b", "go"},
+ {"\\bnorte\\b", "n"},
+ {"\\boeste\\b", "w"},
+ {"\\bpadre\\b", "pe"},
{"\\bpiaui\\b", "pi"},
- {"\\beste\\b", "e"},
- {"\\bviii\\b", "8"},
+ {"\\bsanta\\b", "sta"},
+ {"\\bsexto\\b", "6"},
+ {"\\btreze\\b", "13"},
+ {"\\bviela\\b", "ve"},
+ {"\\bvinte\\b", "20"},
+ {"\\bacre\\b", "ac"},
+ {"\\bbaia\\b", "ba"},
{"\\bdois\\b", "2"},
- {"\\btres\\b", "3"},
- {"\\bseis\\b", "6"},
- {"\\bsete\\b", "7"},
- {"\\boito\\b", "8"},
+ {"\\bdoze\\b", "12"},
+ {"\\beste\\b", "e"},
+ {"\\blote\\b", "lt"},
{"\\bnono\\b", "9"},
{"\\bnove\\b", "9"},
+ {"\\boito\\b", "8"},
{"\\bonze\\b", "11"},
- {"\\bdoze\\b", "12"},
- {"\\bacre\\b", "ac"},
- {"\\bbaia\\b", "ba"},
{"\\bpara\\b", "pa"},
{"\\bsala\\b", "s"},
- {"\\blote\\b", "lt"},
- {"\\bsul\\b", "s"},
- {"\\biii\\b", "3"},
- {"\\bvii\\b", "7"},
- {"\\bdez\\b", "x"},
+ {"\\bseis\\b", "6"},
+ {"\\bsete\\b", "7"},
+ {"\\btres\\b", "3"},
+ {"\\bviii\\b", "8"},
{"\\bcem\\b", "100"},
- {"\\bsan\\b", "s"},
- {"\\bsgt\\b", "sct"},
- {"\\bdos\\b", ""},
{"\\bdas\\b", ""},
+ {"\\bdez\\b", "x"},
+ {"\\bdos\\b", ""},
+ {"\\biii\\b", "3"},
{"\\brua\\b", "r"},
- {"\\bii\\b", "2"},
- {"\\biv\\b", "4"},
- {"\\bvi\\b", "6"},
- {"\\bix\\b", "9"},
+ {"\\bsan\\b", "s"},
+ {"\\bsgt\\b", "sct"},
+ {"\\bsul\\b", "s"},
+ {"\\bvii\\b", "7"},
{"\\b10\\b", "x"},
- {"\\bum\\b", "i"},
{"\\bbr\\b", "b"},
- {"\\bdo\\b", ""},
- {"\\bde\\b", ""},
{"\\bda\\b", ""},
+ {"\\bde\\b", ""},
+ {"\\bdo\\b", ""},
{"\\bel\\b", ""},
- {"\\bve\\b", "vl"},
+ {"\\bii\\b", "2"},
+ {"\\biv\\b", "4"},
+ {"\\bix\\b", "9"},
{"\\bsl\\b", "s"},
- {"\\b1\\b", "i"},
+ {"\\bum\\b", "1"},
+ {"\\bvi\\b", "6"},
+ {"\\bvl\\b", "ve"},
+ {"\\bi\\b", "1"},
{"\\bv\\b", "5"},
};
const Rule kRules_CA[] = {
{"\\bdsl\\s+de\\s+grand\\s+sault\\s+falls\\s+grand\\s+sault\\s+grand\\s+"
- "falls\\b",
- "grand falls"},
+ "falls\\b",
+ "grand falls"},
{"\\bsainte\\s+catherine\\s+de\\s+la\\s+jacques\\s+cartier\\b",
- "ste catherine de la j cartier"},
+ "ste catherine de la j cartier"},
{"\\bmadawaska\\s+maliseet\\s+frst\\s+nation\\b", "madawaska"},
{"\\bregional\\s+county\\s+municipality\\b", ""},
{"\\bshediac\\s+bridge\\s+shediac\\s+river\\b", "shediac bridge"},
{"\\bnewfoundland\\s+and\\s+labrador\\b", "nl"},
{"\\bterritoires\\s+du\\s+nord\\s+ouest\\b", "nt"},
- {"\\bregional\\s+municipality\\s+of\\b", ""},
{"\\bdsl\\s+de\\s+grand\\s+sault\\s+falls\\b", "grand falls"},
+ {"\\bregional\\s+municipality\\s+of\\b", ""},
{"\\bgrand\\s+sault\\s+grand\\s+falls\\b", "grand falls"},
{"\\bterre\\s+neuve\\s+et\\s+labrador\\b", "nl"},
{"\\bbay\\s+de\\s+verde\\s+peninsula\\b", "bvd"},
- {"\\bregional\\s+municipality\\b", ""},
- {"\\bnorthwest\\s+territories\\b", "nt"},
{"\\bile\\s+du\\s+prince\\s+edouard\\b", "pe"},
- {"\\bregional\\s+district\\s+of\\b", ""},
+ {"\\bnorthwest\\s+territories\\b", "nt"},
+ {"\\bregional\\s+municipality\\b", ""},
{"\\bcolombie\\s+britannique\\b", "bc"},
{"\\bprince\\s+edward\\s+island\\b", "pe"},
- {"\\bhead\\s+of\\s+bay\\s+despoir\\b", "head bay d\'espoir"},
+ {"\\bregional\\s+district\\s+of\\b", ""},
{"\\bfrench\\s+village\\s+york\\b", "french village"},
+ {"\\bhead\\s+of\\s+bay\\s+despoir\\b", "head bay d\'espoir"},
{"\\bterritoire\\s+du\\s+yukon\\b", "yt"},
- {"\\bregional\\s+district\\b", ""},
{"\\bnouveau\\s+brunswick\\b", "nb"},
+ {"\\bregional\\s+district\\b", ""},
+ {"\\bbritish\\s+columbia\\b", "bc"},
{"\\bcanton\\s+stanstead\\b", "stanstead"},
{"\\bmd\\s+of\\s+bonnyville\\b", "bonnyville"},
- {"\\bbritish\\s+columbia\\b", "bc"},
- {"\\bst\\s+george\\s+brant\\b", "saint george"},
{"\\bnouvelle\\s+ecosse\\b", "ns"},
+ {"\\bst\\s+george\\s+brant\\b", "saint george"},
{"\\byukon\\s+territory\\b", "yt"},
- {"\\bsackville\\s+road\\b", "sackville"},
{"\\bchisholm\\s+mills\\b", "chisholm"},
+ {"\\bsackville\\s+road\\b", "sackville"},
{"\\bnational\\s+park\\b", ""},
- {"\\bplacentia\\s+bay\\b", "pb"},
{"\\bnew\\s+brunswick\\b", "nb"},
- {"\\bmetropolitan\\b", ""},
+ {"\\bplacentia\\s+bay\\b", "pb"},
{"\\bbeaver\\s+brook\\b", "beaverbrook"},
- {"\\brichibouctou\\b", "richibucto"},
+ {"\\bmetropolitan\\b", ""},
{"\\bnewfoundland\\b", "nl"},
+ {"\\brichibouctou\\b", "richibucto"},
{"\\bsaskatchewan\\b", "sk"},
- {"\\bsubdivision\\b", "subdiv"},
- {"\\btownship\\s+of\\b", ""},
- {"\\btrinity\\s+bay\\b", "tb"},
{"\\bfortune\\s+bay\\b", "fb"},
+ {"\\bnova\\s+scotia\\b", "ns"},
+ {"\\bsubdivision\\b", "subdiv"},
{"\\bsutton\\s+west\\b", "sutton"},
{"\\bterre\\s+neuve\\b", "nl"},
- {"\\bnova\\s+scotia\\b", "ns"},
+ {"\\btownship\\s+of\\b", ""},
+ {"\\btrinity\\s+bay\\b", "tb"},
+ {"\\bbelliveaus\\b", "belliveau"},
{"\\bconcession\\b", "conc"},
- {"\\bcul\\-de\\-sac\\b", "cds"},
{"\\bcul\\s+de\\s+sac\\b", "cds"},
+ {"\\bcul\\-de\\-sac\\b", "cds"},
+ {"\\bde\\s+riviere\\b", "riviere"},
{"\\bexpressway\\b", "expy"},
- {"\\brond\\-point\\b", "rdpt"},
- {"\\brond\\s+point\\b", "rdpt"},
- {"\\bnorth\\s+side\\b", "northside"},
- {"\\bbelliveaus\\b", "belliveau"},
{"\\bmackinnons\\b", "mckinnons"},
+ {"\\bnorth\\s+side\\b", "northside"},
{"\\bpine\\s+ridge\\b", "pineridge"},
- {"\\bde\\s+riviere\\b", "riviere"},
+ {"\\brond\\s+point\\b", "rdpt"},
+ {"\\brond\\-point\\b", "rdpt"},
{"\\balternate\\b", "alt"},
{"\\bautoroute\\b", "aut"},
+ {"\\bboulevard\\b", "blvd"},
{"\\bcarrefour\\b", "carref"},
+ {"\\bcounty\\s+of\\b", ""},
{"\\bcroissant\\b", "crois"},
{"\\bdiversion\\b", "divers"},
{"\\bechangeur\\b", "ech"},
{"\\besplanade\\b", "espl"},
{"\\bextension\\b", "exten"},
+ {"\\bhalf\\s+moon\\b", "halfmoon"},
{"\\bhighlands\\b", "hghlds"},
+ {"\\bkuskonook\\b", "kuskanook"},
{"\\bpromenade\\b", "prom"},
{"\\bturnabout\\b", "trnabt"},
- {"\\bboulevard\\b", "blvd"},
- {"\\bcounty\\s+of\\b", ""},
- {"\\bhalf\\s+moon\\b", "halfmoon"},
- {"\\bkuskanook\\b", "kuskonook"},
{"\\bbusiness\\b", "bus"},
{"\\bcrescent\\b", "cres"},
{"\\bcrossing\\b", "cross"},
+ {"\\bjunction\\b", ""},
+ {"\\bmanitoba\\b", "mb"},
{"\\bmountain\\b", "mtn"},
+ {"\\boak\\s+hill\\b", "oakhill"},
+ {"\\bpleasent\\b", "pleasant"},
{"\\bterrasse\\b", "tsse"},
{"\\btownline\\b", "tline"},
- {"\\bjunction\\b", ""},
{"\\btownship\\b", ""},
- {"\\boak\\s+hill\\b", "oakhill"},
- {"\\bpleasent\\b", "pleasant"},
- {"\\bmanitoba\\b", "mb"},
- {"\\bhighway\\b", "hwy"},
+ {"\\balberta\\b", "ab"},
{"\\bby\\s+pass\\b", "bypass"},
{"\\bcircuit\\b", "circt"},
+ {"\\bcity\\s+of\\b", ""},
{"\\bcorners\\b", "crnrs"},
{"\\bestates\\b", "estate"},
{"\\bfreeway\\b", "fwy"},
@@ -521,128 +522,127 @@ const Rule kRules_CA[] = {
{"\\bgrounds\\b", "grnds"},
{"\\bharbour\\b", "harbr"},
{"\\bheights\\b", "hts"},
+ {"\\bherbert\\b", "hebert"},
+ {"\\bhighway\\b", "hwy"},
{"\\bimpasse\\b", "imp"},
+ {"\\bkeenans\\b", "keenan"},
+ {"\\bl\'islet\\b", ""},
+ {"\\bla\\s+have\\b", "lahave"},
{"\\blanding\\b", "landng"},
{"\\blookout\\b", "lkout"},
+ {"\\bnarrows\\b", ""},
+ {"\\bnunavut\\b", "nu"},
+ {"\\bontario\\b", "on"},
{"\\borchard\\b", "orch"},
{"\\bparkway\\b", "pky"},
{"\\bpassage\\b", "pass"},
{"\\bpathway\\b", "ptway"},
{"\\bplateau\\b", "plat"},
+ {"\\breserve\\b", ""},
+ {"\\bsentier\\b", "sent"},
+ {"\\bstation\\b", ""},
{"\\bterrace\\b", "terr"},
{"\\bthicket\\b", "thick"},
- {"\\bvillage\\b", ""},
- {"\\bsentier\\b", "sent"},
- {"\\bcity\\s+of\\b", ""},
{"\\btown\\s+of\\b", ""},
- {"\\bstation\\b", ""},
- {"\\breserve\\b", ""},
- {"\\bnarrows\\b", ""},
- {"\\bl\'islet\\b", ""},
- {"\\bkeenans\\b", "keenan"},
- {"\\bla\\s+have\\b", "lahave"},
- {"\\bherbert\\b", "hebert"},
- {"\\balberta\\b", "ab"},
- {"\\bnunavut\\b", "nu"},
- {"\\bontario\\b", "on"},
- {"\\bsainte\\b", ""},
- {"\\bl\'isle\\b", "isle"},
+ {"\\bvillage\\b", ""},
{"\\bavenue\\b", "av"},
- {"\\bcentre\\b", ""},
+ {"\\bbakers\\b", "baker"},
+ {"\\bcanada\\b", "ca"},
+ {"\\bcanton\\b", ""},
{"\\bcenter\\b", ""},
+ {"\\bcentre\\b", ""},
+ {"\\bchemin\\b", "ch"},
{"\\bcircle\\b", "cir"},
+ {"\\bcounty\\b", ""},
{"\\bharbor\\b", "harbr"},
{"\\bisland\\b", ""},
+ {"\\bl\'isle\\b", "isle"},
{"\\blimits\\b", "lmts"},
+ {"\\bmackay\\b", "mckay"},
+ {"\\bmcgrey\\b", "mcgray"},
{"\\bpointe\\b", "pte"},
+ {"\\bquebec\\b", "qc"},
{"\\bruelle\\b", "rle"},
+ {"\\bsainte\\b", ""},
+ {"\\bsiding\\b", ""},
+ {"\\bsmiths\\b", "smith"},
{"\\bsquare\\b", "sq"},
{"\\bstreet\\b", ""},
- {"\\bchemin\\b", "ch"},
- {"\\bcanton\\b", ""},
- {"\\bsiding\\b", ""},
{"\\bvalley\\b", ""},
- {"\\bcounty\\b", ""},
- {"\\bsmiths\\b", "smith"},
- {"\\bbakers\\b", "baker"},
- {"\\bmackay\\b", "mckay"},
- {"\\bmcgrey\\b", "mcgray"},
- {"\\bquebec\\b", "qc"},
- {"\\bcanada\\b", "ca"},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bouest\\b", "o"},
- {"\\bsaint\\b", ""},
- {"\\bmount\\b", "mt"},
- {"\\bpoint\\b", "pt"},
{"\\bcarre\\b", "car"},
{"\\bclose\\b", "cl"},
{"\\bcourt\\b", "crt"},
{"\\bdrive\\b", "dr"},
+ {"\\bfirst\\b", "fst"},
+ {"\\bforks\\b", ""},
{"\\bgrove\\b", "grv"},
+ {"\\bmanns\\b", "mann"},
+ {"\\bmetro\\b", ""},
+ {"\\bmount\\b", "mt"},
+ {"\\bnorth\\b", "n"},
+ {"\\bouest\\b", "o"},
{"\\bplace\\b", "pl"},
+ {"\\bpoint\\b", "pt"},
{"\\brange\\b", "rg"},
{"\\broute\\b", "rt"},
+ {"\\bsaint\\b", ""},
+ {"\\bsouth\\b", "s"},
{"\\btrail\\b", "trl"},
- {"\\bmetro\\b", ""},
- {"\\bforks\\b", ""},
- {"\\bmanns\\b", "mann"},
- {"\\bfirst\\b", "fst"},
{"\\byukon\\b", "yt"},
- {"\\bnord\\b", "n"},
- {"\\beast\\b", ""},
- {"\\bwest\\b", "o"},
+ {"\\bboul\\b", "blvd"},
+ {"\\bcity\\b", ""},
{"\\bcove\\b", ""},
+ {"\\beast\\b", ""},
+ {"\\bfrst\\b", "fst"},
+ {"\\blake\\b", ""},
{"\\blane\\b", "ln"},
+ {"\\bnord\\b", "n"},
{"\\bpark\\b", ""},
{"\\bpkwy\\b", "pky"},
{"\\broad\\b", ""},
- {"\\bboul\\b", "blvd"},
- {"\\bcity\\b", ""},
- {"\\blake\\b", ""},
- {"\\bfrst\\b", "fst"},
- {"\\bnth\\b", "n"},
- {"\\bsth\\b", "s"},
- {"\\bsud\\b", "s"},
- {"\\best\\b", ""},
- {"\\bere\\b", ""},
- {"\\bste\\b", ""},
+ {"\\bwest\\b", "o"},
{"\\bave\\b", "av"},
{"\\bbay\\b", ""},
+ {"\\bbdv\\b", ""},
+ {"\\bblp\\b", ""},
+ {"\\bcan\\b", "ca"},
+ {"\\bcbd\\b", ""},
{"\\bctr\\b", ""},
- {"\\bile\\b", ""},
- {"\\brte\\b", "rt"},
{"\\bdes\\b", ""},
- {"\\bcbd\\b", ""},
- {"\\bsal\\b", ""},
- {"\\bblp\\b", ""},
- {"\\bbdv\\b", ""},
+ {"\\bere\\b", ""},
+ {"\\best\\b", ""},
+ {"\\bile\\b", ""},
{"\\blab\\b", ""},
{"\\bndb\\b", ""},
- {"\\bsmb\\b", ""},
+ {"\\bnth\\b", "n"},
{"\\bont\\b", "on"},
{"\\bpei\\b", "pe"},
- {"\\bcan\\b", "ca"},
- {"\\bst\\b", ""},
- {"\\bnd\\b", ""},
- {"\\brd\\b", ""},
- {"\\bth\\b", ""},
- {"\\ber\\b", ""},
- {"\\bre\\b", ""},
- {"\\bpk\\b", ""},
+ {"\\brte\\b", "rt"},
+ {"\\bsal\\b", ""},
+ {"\\bsmb\\b", ""},
+ {"\\bste\\b", ""},
+ {"\\bsth\\b", "s"},
+ {"\\bsud\\b", "s"},
+ {"\\bbb\\b", ""},
+ {"\\bcb\\b", ""},
+ {"\\bco\\b", ""},
{"\\bd\'\\b", ""},
{"\\bde\\b", ""},
{"\\bdu\\b", ""},
- {"\\bcb\\b", ""},
- {"\\bbb\\b", ""},
- {"\\bco\\b", ""},
+ {"\\ber\\b", ""},
{"\\bfn\\b", ""},
{"\\bgb\\b", ""},
+ {"\\bnd\\b", ""},
+ {"\\bpk\\b", ""},
+ {"\\brd\\b", ""},
+ {"\\bre\\b", ""},
+ {"\\bst\\b", ""},
+ {"\\bth\\b", ""},
{"\\bwb\\b", ""},
- {"\\be\\b", ""},
- {"\\bw\\b", "o"},
{"\\bc\\b", ""},
{"\\bd\\b", ""},
+ {"\\be\\b", ""},
+ {"\\bw\\b", "o"},
};
const Rule kRules_CH[] = {
@@ -652,199 +652,199 @@ const Rule kRules_CH[] = {
{"\\bjura\\s+north\\s+vaudois\\b", "jura nord vaudois"},
{"\\bprettigovia\\s+davos\\b", "davos"},
{"\\bbasel\\s+landschaft\\b", "bl"},
- {"\\bsankt\\s+silvester\\b", "st silvester"},
{"\\bprattigau\\s+davos\\b", "davos"},
- {"\\bsankt\\s+stephan\\b", "st stephan"},
+ {"\\bsankt\\s+silvester\\b", "st silvester"},
{"\\bbale\\s+campagne\\b", "bl"},
{"\\bbasilea\\s+citta\\b", "bs"},
+ {"\\bsankt\\s+stephan\\b", "st stephan"},
{"\\bwallis\\s+valais\\b", "vs"},
- {"\\bdix\\s+septieme\\b", "17"},
{"\\bdix\\s+huitieme\\b", "18"},
{"\\bdix\\s+neuvieme\\b", "19"},
- {"\\bsankt\\s+gallen\\b", "sg"},
+ {"\\bdix\\s+septieme\\b", "17"},
{"\\bsaint\\s+gallen\\b", "sg"},
+ {"\\bsankt\\s+gallen\\b", "sg"},
{"\\bschaffhausen\\b", "sh"},
+ {"\\bbasel\\s+stadt\\b", "bs"},
+ {"\\bbelinzonese\\b", "bellinzona"},
{"\\bquatorzieme\\b", "14"},
- {"\\bwinterthour\\b", "winterthur"},
+ {"\\bsaint\\s+gallo\\b", "sg"},
{"\\bsan\\s+nazzaro\\b", "s nazzaro"},
{"\\bsan\\s+vittore\\b", "s vittore"},
- {"\\bbelinzonese\\b", "bellinzone"},
{"\\bsankt\\s+gallo\\b", "sg"},
- {"\\bsaint\\s+gallo\\b", "sg"},
- {"\\bbasel\\s+stadt\\b", "bs"},
{"\\bschaffhouse\\b", "sh"},
{"\\bswitzerland\\b", "ch"},
- {"\\benclave\\s+de\\b", ""},
- {"\\bbellinzona\\b", "bellinzone"},
- {"\\bsankt\\s+gall\\b", "sg"},
- {"\\bst\\.\\s+gallen\\b", "sg"},
- {"\\bsaint\\s+gall\\b", "sg"},
- {"\\bsan\\s+gallen\\b", "sg"},
- {"\\bbasel\\s+land\\b", "bl"},
+ {"\\bwinterthour\\b", "winterthur"},
{"\\bbale\\s+ville\\b", "bs"},
- {"\\bbasel\\s+stad\\b", "bs"},
{"\\bbasel\\s+city\\b", "bs"},
+ {"\\bbasel\\s+land\\b", "bl"},
+ {"\\bbasel\\s+stad\\b", "bs"},
{"\\bbazel\\s+stad\\b", "bs"},
+ {"\\bbellinzone\\b", "bellinzona"},
+ {"\\benclave\\s+de\\b", ""},
{"\\bgraubunden\\b", "gr"},
- {"\\bwaadt\\s+vaud\\b", "vd"},
+ {"\\bsaint\\s+gall\\b", "sg"},
+ {"\\bsan\\s+gallen\\b", "sg"},
+ {"\\bsankt\\s+gall\\b", "sg"},
+ {"\\bst\\.\\s+gallen\\b", "sg"},
{"\\bvaud\\s+waadt\\b", "vd"},
- {"\\btroisieme\\b", "3"},
- {"\\bquatrieme\\b", "4"},
+ {"\\bwaadt\\s+vaud\\b", "vd"},
{"\\bcinquieme\\b", "5"},
- {"\\btreizieme\\b", "13"},
- {"\\bquinzieme\\b", "xv"},
- {"\\bvingtieme\\b", "xx"},
- {"\\blaufental\\b", "laufon"},
- {"\\bst\\s+gallen\\b", "sg"},
- {"\\bst\\.\\s+gallo\\b", "sg"},
- {"\\bsan\\s+gallo\\b", "sg"},
- {"\\bneuenburg\\b", "ne"},
+ {"\\blaufental\\b", "laufen"},
{"\\bneuchatel\\b", "ne"},
+ {"\\bneuenburg\\b", "ne"},
{"\\bnidwalden\\b", "nw"},
+ {"\\bquatrieme\\b", "4"},
+ {"\\bquinzieme\\b", "15"},
+ {"\\bsan\\s+gallo\\b", "sg"},
{"\\bsciaffusa\\b", "sh"},
{"\\bsolothurn\\b", "so"},
- {"\\bthurgovie\\b", "tg"},
+ {"\\bst\\s+gallen\\b", "sg"},
+ {"\\bst\\.\\s+gallo\\b", "sg"},
{"\\bthurgovia\\b", "tg"},
- {"\\bpremiere\\b", "i"},
+ {"\\bthurgovie\\b", "tg"},
+ {"\\btreizieme\\b", "13"},
+ {"\\btroisieme\\b", "3"},
+ {"\\bvingtieme\\b", "20"},
+ {"\\bd\\\\\'uster\\b", "uster"},
{"\\bdeuxieme\\b", "2"},
- {"\\bseptieme\\b", "7"},
- {"\\bhuitieme\\b", "8"},
- {"\\bneuvieme\\b", "9"},
{"\\bdouzieme\\b", "12"},
- {"\\bseizieme\\b", "16"},
- {"\\bmaloggia\\b", "maloja"},
- {"\\bgessenay\\b", "saanen"},
- {"\\bst\\s+gallo\\b", "sg"},
- {"\\bst\\.\\s+gall\\b", "sg"},
- {"\\bsan\\s+gall\\b", "sg"},
- {"\\bd\\\\\'uster\\b", "uster"},
- {"\\bzofingen\\b", "zofingue"},
{"\\bfreiburg\\b", "fr"},
{"\\bfribourg\\b", "fr"},
{"\\bfriburgo\\b", "fr"},
+ {"\\bgessenay\\b", "saanen"},
{"\\bgrigioni\\b", "gr"},
+ {"\\bhuitieme\\b", "8"},
+ {"\\bmaloggia\\b", "maloja"},
+ {"\\bneuvieme\\b", "9"},
{"\\bnidvaldo\\b", "nw"},
{"\\bobwalden\\b", "ow"},
+ {"\\bpremiere\\b", "1"},
+ {"\\bsan\\s+gall\\b", "sg"},
+ {"\\bseizieme\\b", "16"},
+ {"\\bseptieme\\b", "7"},
+ {"\\bst\\s+gallo\\b", "sg"},
+ {"\\bst\\.\\s+gall\\b", "sg"},
{"\\bturgovia\\b", "tg"},
- {"\\bsixieme\\b", "6"},
- {"\\bdixieme\\b", "x"},
- {"\\bonzieme\\b", "xi"},
- {"\\bzuerich\\b", "zh"},
- {"\\bturicum\\b", "zh"},
- {"\\blucerne\\b", "lu"},
- {"\\bst\\s+gall\\b", "sg"},
+ {"\\bzofingue\\b", "zofingen"},
{"\\bargovia\\b", "ag"},
{"\\bargovie\\b", "ag"},
+ {"\\bdixieme\\b", "x"},
{"\\bfriburg\\b", "fr"},
{"\\bginevra\\b", "ge"},
{"\\bglarona\\b", "gl"},
{"\\bgrisons\\b", "gr"},
{"\\blucerna\\b", "lu"},
+ {"\\blucerne\\b", "lu"},
{"\\bnidwald\\b", "nw"},
{"\\bobvaldo\\b", "ow"},
- {"\\bsoleure\\b", "so"},
- {"\\bsoletta\\b", "so"},
+ {"\\bonzieme\\b", "11"},
+ {"\\bschweiz\\b", "ch"},
{"\\bschwytz\\b", "sz"},
+ {"\\bsixieme\\b", "6"},
+ {"\\bsoletta\\b", "so"},
+ {"\\bsoleure\\b", "so"},
+ {"\\bst\\s+gall\\b", "sg"},
{"\\bthurgau\\b", "tg"},
- {"\\bvallese\\b", "vs"},
+ {"\\bturicum\\b", "zh"},
{"\\bvallais\\b", "vs"},
- {"\\bschweiz\\b", "ch"},
- {"\\bsainte\\b", ""},
- {"\\bregion\\b", ""},
- {"\\bzurich\\b", "zh"},
- {"\\bbienne\\b", "biel"},
+ {"\\bvallese\\b", "vs"},
+ {"\\bzuerich\\b", "zh"},
+ {"\\baargau\\b", "ag"},
{"\\bbienna\\b", "biel"},
+ {"\\bbienne\\b", "biel"},
{"\\bbrigue\\b", "brig"},
- {"\\blaufen\\b", "laufon"},
- {"\\bthoune\\b", "thun"},
- {"\\bzurigo\\b", "zh"},
- {"\\baargau\\b", "ag"},
- {"\\bgeneve\\b", "ge"},
{"\\bgeneva\\b", "ge"},
- {"\\bglarus\\b", "gl"},
+ {"\\bgeneve\\b", "ge"},
{"\\bglaris\\b", "gl"},
+ {"\\bglarus\\b", "gl"},
+ {"\\blaufon\\b", "laufen"},
{"\\bluzern\\b", "lu"},
{"\\bobwald\\b", "ow"},
+ {"\\bregion\\b", ""},
+ {"\\bsainte\\b", ""},
{"\\bschwyz\\b", "sz"},
{"\\bsvitto\\b", "sz"},
{"\\btessin\\b", "ti"},
+ {"\\bthoune\\b", "thun"},
{"\\bticino\\b", "ti"},
- {"\\bwallis\\b", "vs"},
{"\\bvalais\\b", "vs"},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bouest\\b", "o"},
- {"\\bsaint\\b", ""},
- {"\\bmount\\b", "mt"},
- {"\\bxviii\\b", "18"},
- {"\\bde\\s+la\\b", ""},
- {"\\bde\\s+l\'\\b", ""},
- {"\\bet\\s+du\\b", ""},
- {"\\bstadt\\b", ""},
+ {"\\bwallis\\b", "vs"},
+ {"\\bzurich\\b", "zh"},
+ {"\\bzurigo\\b", "zh"},
{"\\baaray\\b", "aarau"},
{"\\bberna\\b", "be"},
{"\\bberne\\b", "be"},
{"\\bbriga\\b", "brig"},
- {"\\bviege\\b", "visp"},
+ {"\\bde\\s+l\'\\b", ""},
+ {"\\bde\\s+la\\b", ""},
+ {"\\bet\\s+du\\b", ""},
{"\\bgiura\\b", "ju"},
+ {"\\bmount\\b", "mt"},
+ {"\\bnorth\\b", "n"},
+ {"\\bouest\\b", "o"},
+ {"\\bsaint\\b", ""},
+ {"\\bsouth\\b", "s"},
+ {"\\bstadt\\b", ""},
+ {"\\bviege\\b", "visp"},
{"\\bwaadt\\b", "vd"},
- {"\\bnord\\b", "n"},
- {"\\bwest\\b", "o"},
- {"\\bieme\\b", ""},
- {"\\bviii\\b", "8"},
- {"\\bxiii\\b", "13"},
- {"\\bxvii\\b", "17"},
- {"\\bstad\\b", ""},
+ {"\\bxviii\\b", "18"},
{"\\bbern\\b", "be"},
{"\\bgenf\\b", "ge"},
+ {"\\bieme\\b", ""},
{"\\bjura\\b", "ju"},
+ {"\\bnord\\b", "n"},
+ {"\\bstad\\b", ""},
{"\\bvaud\\b", "vd"},
- {"\\bzugo\\b", "zg"},
+ {"\\bviii\\b", "8"},
+ {"\\bwest\\b", "o"},
+ {"\\bxiii\\b", "13"},
+ {"\\bxvii\\b", "17"},
{"\\bzoug\\b", "zg"},
- {"\\bsud\\b", "s"},
- {"\\best\\b", ""},
- {"\\bere\\b", ""},
+ {"\\bzugo\\b", "zg"},
+ {"\\bdes\\b", ""},
{"\\beme\\b", ""},
- {"\\bste\\b", ""},
- {"\\bmte\\b", "mt"},
+ {"\\bere\\b", ""},
+ {"\\best\\b", ""},
{"\\biii\\b", "3"},
+ {"\\bles\\b", ""},
+ {"\\bmte\\b", "mt"},
+ {"\\bste\\b", ""},
+ {"\\bsud\\b", "s"},
+ {"\\bsur\\b", ""},
+ {"\\buri\\b", "ur"},
{"\\bvii\\b", "7"},
{"\\bxii\\b", "12"},
{"\\bxiv\\b", "14"},
- {"\\bxvi\\b", "16"},
{"\\bxix\\b", "19"},
- {"\\bdes\\b", ""},
- {"\\bles\\b", ""},
- {"\\bsur\\b", ""},
- {"\\buri\\b", "ur"},
+ {"\\bxvi\\b", "16"},
{"\\bzug\\b", "zg"},
- {"\\bst\\b", ""},
- {"\\bnd\\b", ""},
- {"\\brd\\b", ""},
- {"\\bth\\b", ""},
+ {"\\b10\\b", "x"},
+ {"\\bd\'\\b", ""},
+ {"\\bde\\b", ""},
+ {"\\bdu\\b", ""},
+ {"\\ben\\b", ""},
{"\\ber\\b", ""},
- {"\\bre\\b", ""},
{"\\bii\\b", "2"},
+ {"\\bin\\b", ""},
{"\\biv\\b", "4"},
- {"\\bvi\\b", "6"},
{"\\bix\\b", "9"},
- {"\\b10\\b", "x"},
- {"\\b11\\b", "xi"},
- {"\\b15\\b", "xv"},
- {"\\b20\\b", "xx"},
- {"\\bdu\\b", ""},
- {"\\bde\\b", ""},
- {"\\bd\'\\b", ""},
+ {"\\bl\'\\b", ""},
{"\\bla\\b", ""},
{"\\ble\\b", ""},
- {"\\bl\'\\b", ""},
+ {"\\bnd\\b", ""},
{"\\bof\\b", ""},
- {"\\ben\\b", ""},
- {"\\bin\\b", ""},
+ {"\\brd\\b", ""},
+ {"\\bre\\b", ""},
+ {"\\bst\\b", ""},
+ {"\\bth\\b", ""},
+ {"\\bvi\\b", "6"},
+ {"\\bxi\\b", "11"},
+ {"\\bxv\\b", "15"},
+ {"\\bxx\\b", "20"},
{"\\be\\b", ""},
- {"\\bw\\b", "o"},
- {"\\b1\\b", "i"},
+ {"\\bi\\b", "1"},
{"\\bv\\b", "5"},
+ {"\\bw\\b", "o"},
};
const Rule kRules_CL[] = {
@@ -853,33 +853,33 @@ const Rule kRules_CL[] = {
{"\\bmetropolitana\\s+de\\s+santiago\\s+de\\s+chile\\b", "rm"},
{"\\bmagallanes\\s+y\\s+la\\s+antartica\\s+chilena\\b", "12"},
{"\\bmetropolitana\\s+de\\s+santiago\\b", "rm"},
- {"\\barica\\s+y\\s+parinacota\\b", "xv"},
+ {"\\barica\\s+y\\s+parinacota\\b", "15"},
{"\\bmetropolitana\\b", "rm"},
{"\\bla\\s+araucania\\b", "9"},
{"\\bantofagasta\\b", "2"},
- {"\\bvalparaiso\\b", "v"},
+ {"\\bvalparaiso\\b", "5"},
{"\\blos\\s+lagos\\b", "x"},
- {"\\btarapaca\\b", "i"},
{"\\bcoquimbo\\b", "4"},
{"\\blos\\s+rios\\b", "14"},
+ {"\\btarapaca\\b", "1"},
{"\\batacama\\b", "3"},
{"\\bbio\\s+bio\\b", "8"},
- {"\\bmaule\\b", "7"},
{"\\bchile\\b", "cl"},
+ {"\\bmaule\\b", "7"},
{"\\bviii\\b", "8"},
{"\\biii\\b", "3"},
{"\\bvii\\b", "7"},
{"\\bxii\\b", "12"},
{"\\bxiv\\b", "14"},
+ {"\\b10\\b", "x"},
{"\\bii\\b", "2"},
{"\\biv\\b", "4"},
- {"\\bvi\\b", "6"},
{"\\bix\\b", "9"},
- {"\\b10\\b", "x"},
+ {"\\bvi\\b", "6"},
{"\\bxi\\b", "11"},
- {"\\b15\\b", "xv"},
- {"\\b1\\b", "i"},
- {"\\b5\\b", "v"},
+ {"\\bxv\\b", "15"},
+ {"\\bi\\b", "1"},
+ {"\\bv\\b", "5"},
};
const Rule kRules_CO[] = {
@@ -902,33 +902,33 @@ const Rule kRules_DE[] = {
{"\\bsachsen\\s+anhalt\\b", "st"},
{"\\bniedersachsen\\b", "ni"},
{"\\bsaxony\\s+anhalt\\b", "st"},
- {"\\bstadtverband\\b", ""},
{"\\blower\\s+saxony\\b", "ni"},
+ {"\\bstadtverband\\b", ""},
{"\\bbrandenburg\\b", "bb"},
{"\\bdeutschland\\b", "de"},
{"\\blandkreis\\b", ""},
- {"\\bthuringia\\b", "th"},
{"\\bthuringen\\b", "th"},
+ {"\\bthuringia\\b", "th"},
{"\\bsaarland\\b", "sl"},
- {"\\bstrasse\\b", "str"},
- {"\\bcologne\\b", "koln"},
{"\\bbavaria\\b", "by"},
+ {"\\bcologne\\b", "koln"},
+ {"\\bgermany\\b", "de"},
{"\\bhamburg\\b", "hh"},
{"\\bsachsen\\b", "sn"},
- {"\\bgermany\\b", "de"},
- {"\\bsudost\\b", "se"},
+ {"\\bstrasse\\b", "str"},
{"\\bbayern\\b", "by"},
{"\\bberlin\\b", "be"},
{"\\bbremen\\b", "hb"},
{"\\bhessen\\b", "he"},
{"\\bsaxony\\b", "sn"},
+ {"\\bsudost\\b", "se"},
+ {"\\bhesse\\b", "he"},
{"\\bsankt\\b", "st"},
{"\\bstadt\\b", ""},
- {"\\bhesse\\b", "he"},
{"\\bnord\\b", "n"},
{"\\bwest\\b", "w"},
- {"\\bsud\\b", "s"},
{"\\bost\\b", "o"},
+ {"\\bsud\\b", "s"},
};
const Rule kRules_DK[] = {
@@ -936,30 +936,30 @@ const Rule kRules_DK[] = {
{"\\barnold\\s+nielsens\\b", "arn nielsens"},
{"\\bhaveforeningen\\b", "haveforening"},
{"\\bmunicipality\\b", ""},
- {"\\btengslemark\\b", "tengslemrk"},
{"\\bbispebjergs\\b", "bispebjerg"},
+ {"\\btengslemark\\b", "tengslemrk"},
{"\\bboulevard\\b", "boul"},
{"\\blillerod\\b", "allerod"},
- {"\\bpladsen\\b", "plads"},
- {"\\bkvarter\\b", "kvater"},
- {"\\bkommune\\b", ""},
- {"\\bdenmark\\b", "dk"},
{"\\bdanmark\\b", "dk"},
- {"\\bsondre\\b", "s"},
- {"\\bnummer\\b", "nr"},
+ {"\\bdenmark\\b", "dk"},
+ {"\\bkommune\\b", ""},
+ {"\\bkvarter\\b", "kvater"},
+ {"\\bpladsen\\b", "plads"},
+ {"\\bboulev\\b", "boul"},
{"\\bgammel\\b", "gl"},
{"\\blokken\\b", "lokke"},
- {"\\bboulev\\b", "boul"},
- {"\\bnorre\\b", "n"},
- {"\\bsankt\\b", "skt"},
+ {"\\bnummer\\b", "nr"},
+ {"\\bsondre\\b", "s"},
{"\\bgamle\\b", "gl"},
+ {"\\bnorre\\b", "n"},
+ {"\\bsankt\\b", "sct"},
{"\\bnord\\b", "n"},
{"\\bvest\\b", "v"},
{"\\bndr\\b", "n"},
- {"\\bsyd\\b", "s"},
- {"\\bsdr\\b", "s"},
{"\\bost\\b", "o"},
- {"\\bsct\\b", "skt"},
+ {"\\bsdr\\b", "s"},
+ {"\\bskt\\b", "sct"},
+ {"\\bsyd\\b", "s"},
};
const Rule kRules_ES[] = {
@@ -974,16 +974,16 @@ const Rule kRules_ES[] = {
{"\\blas\\s+palmas\\b", "gc"},
{"\\bpontevedra\\b", "po"},
{"\\bvalladolid\\b", "va"},
- {"\\besplugues\\b", "esplugas"},
- {"\\bla\\s+coruna\\b", "c"},
{"\\bbarcelona\\b", "b"},
{"\\bcantabria\\b", "s"},
{"\\bcastellon\\b", "cs"},
+ {"\\besplugues\\b", "esplugas"},
{"\\bguipuscoa\\b", "ss"},
{"\\bguipuzcoa\\b", "ss"},
+ {"\\bla\\s+coruna\\b", "c"},
{"\\bsalamanca\\b", "sa"},
- {"\\btarragona\\b", "t"},
{"\\bsaragossa\\b", "z"},
+ {"\\btarragona\\b", "t"},
{"\\ba\\s+coruna\\b", "c"},
{"\\balbacete\\b", "ab"},
{"\\balicante\\b", ""},
@@ -995,71 +995,71 @@ const Rule kRules_ES[] = {
{"\\bpalencia\\b", "p"},
{"\\bvalencia\\b", "v"},
{"\\bzaragoza\\b", "z"},
- {"\\bavenida\\b", "av"},
{"\\balacant\\b", ""},
{"\\balmeria\\b", ""},
+ {"\\bavenida\\b", "av"},
{"\\bbadajoz\\b", "ba"},
- {"\\bvizcaya\\b", "bi"},
{"\\bbizkaia\\b", "bi"},
{"\\bcaceres\\b", "cc"},
{"\\bcordoba\\b", "co"},
{"\\bcordova\\b", "co"},
{"\\bgranada\\b", "gr"},
- {"\\bnavarre\\b", "na"},
{"\\bnavarra\\b", "na"},
+ {"\\bnavarre\\b", "na"},
{"\\bourense\\b", "or"},
{"\\bsegovia\\b", "sg"},
- {"\\bseville\\b", "se"},
{"\\bsevilla\\b", "se"},
- {"\\bmadrid\\b", "m"},
- {"\\bcoruna\\b", "c"},
+ {"\\bseville\\b", "se"},
+ {"\\bvizcaya\\b", "bi"},
{"\\bbiscay\\b", "bi"},
{"\\bburgos\\b", "bu"},
+ {"\\bcoruna\\b", "c"},
{"\\bcuenca\\b", "cu"},
+ {"\\bespana\\b", "es"},
{"\\bgerona\\b", "gi"},
{"\\bgirona\\b", "gi"},
{"\\bhuelva\\b", "h"},
{"\\bhuesca\\b", "hu"},
{"\\blerida\\b", ""},
{"\\blleida\\b", ""},
+ {"\\bmadrid\\b", "m"},
{"\\bmalaga\\b", "ma"},
{"\\bmurcia\\b", "mu"},
{"\\borense\\b", "or"},
{"\\bteruel\\b", "te"},
{"\\btoledo\\b", "to"},
{"\\bzamora\\b", "za"},
- {"\\bespana\\b", "es"},
- {"\\bnorth\\b", "n"},
- {"\\bnorte\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\boeste\\b", "o"},
{"\\balava\\b", "vi"},
{"\\baraba\\b", "vi"},
{"\\bavila\\b", "av"},
{"\\bcadiz\\b", "ca"},
+ {"\\bnorte\\b", "n"},
+ {"\\bnorth\\b", "n"},
+ {"\\boeste\\b", "o"},
{"\\bsoria\\b", "so"},
+ {"\\bsouth\\b", "s"},
{"\\bspain\\b", "es"},
{"\\beast\\b", "e"},
{"\\beste\\b", "e"},
- {"\\bwest\\b", "o"},
{"\\bjaen\\b", "j"},
{"\\bleon\\b", "le"},
{"\\blugo\\b", "lu"},
- {"\\bsur\\b", "s"},
- {"\\bdel\\b", ""},
+ {"\\bwest\\b", "o"},
+ {"\\bc\\.\\/\\b", "c"},
+ {"\\bc\\/\\.\\b", "c"},
{"\\bdal\\b", ""},
- {"\\blos\\b", ""},
+ {"\\bdel\\b", ""},
{"\\blas\\b", ""},
{"\\bles\\b", ""},
- {"\\bc\\/\\.\\b", "c"},
- {"\\bc\\.\\/\\b", "c"},
- {"\\bde\\b", ""},
- {"\\ben\\b", ""},
- {"\\bof\\b", ""},
+ {"\\blos\\b", ""},
+ {"\\bsur\\b", "s"},
{"\\bal\\b", ""},
+ {"\\bc\\/\\b", "c"},
+ {"\\bde\\b", ""},
{"\\bel\\b", ""},
+ {"\\ben\\b", ""},
{"\\bla\\b", ""},
- {"\\bc\\/\\b", "c"},
+ {"\\bof\\b", ""},
{"\\ba\\b", ""},
{"\\bd\\b", ""},
{"\\bl\\b", ""},
@@ -1070,220 +1070,222 @@ const Rule kRules_FR[] = {
{"\\balpes\\s+de\\s+haute\\s+provence\\b", "04"},
{"\\barnouville\\s+les\\s+gonesse\\b", "arnouville"},
{"\\bterritoire\\s+de\\s+belfort\\b", "90"},
- {"\\bpyrenees\\s+atlantiques\\b", "64"},
{"\\blanguedoc\\s+roussillon\\b", "k"},
+ {"\\bpyrenees\\s+atlantiques\\b", "64"},
{"\\bpyrenees\\s+orientales\\b", "66"},
{"\\bmeurthe\\s+et\\s+moselle\\b", "54"},
{"\\bnord\\s+pas\\s+de\\s+calais\\b", "o"},
+ {"\\bchampagne\\s+ardenne\\b", "g"},
{"\\bcharente\\s+maritime\\b", "17"},
{"\\bseine\\s+saint\\s+denis\\b", "93"},
- {"\\bchampagne\\s+ardenne\\b", "g"},
{"\\bbouches\\s+du\\s+rhone\\b", "13"},
{"\\bloire\\s+atlantique\\b", "44"},
{"\\bpays\\s+de\\s+la\\s+loire\\b", "r"},
{"\\bpoitou\\s+charentes\\b", "t"},
{"\\balpes\\s+maritimes\\b", "06"},
- {"\\bille\\s+et\\s+vilaine\\b", "35"},
- {"\\btarn\\s+et\\s+garonne\\b", "82"},
{"\\bbasse\\s+normandie\\b", "p"},
{"\\bhaute\\s+normandie\\b", "q"},
+ {"\\bille\\s+et\\s+vilaine\\b", "35"},
+ {"\\btarn\\s+et\\s+garonne\\b", "82"},
{"\\bdepartementale\\b", "d"},
+ {"\\bhaute\\s+pyrenees\\b", "65"},
+ {"\\bhauts\\s+de\\s+seine\\b", "92"},
{"\\bindre\\s+et\\s+loire\\b", "37"},
{"\\blot\\s+et\\s+garonne\\b", "47"},
+ {"\\blower\\s+normandy\\b", "p"},
{"\\bmaine\\s+et\\s+loire\\b", "49"},
- {"\\bhaute\\s+pyrenees\\b", "65"},
{"\\bsaone\\s+et\\s+loire\\b", "71"},
{"\\bseine\\s+maritime\\b", "76"},
- {"\\bhauts\\s+de\\s+seine\\b", "92"},
- {"\\blower\\s+normandy\\b", "p"},
{"\\bupper\\s+normandy\\b", "q"},
- {"\\bdepartemental\\b", "d"},
{"\\bcotes\\s+d\\s+armor\\b", "22"},
+ {"\\bdepartemental\\b", "d"},
+ {"\\bfranche\\s+comte\\b", "1"},
{"\\bhaute\\s+garonne\\b", "31"},
- {"\\bpas\\s+de\\s+calais\\b", "62"},
- {"\\bseine\\s+et\\s+mame\\b", "77"},
- {"\\bfranche\\s+comte\\b", "i"},
{"\\bile\\s+de\\s+france\\b", "j"},
{"\\bmidi\\s+pyrenees\\b", "n"},
- {"\\bdix\\s+septieme\\b", "17"},
+ {"\\bpas\\s+de\\s+calais\\b", "62"},
+ {"\\bseine\\s+et\\s+mame\\b", "77"},
+ {"\\bcorse\\s+du\\s+sud\\b", "2a"},
{"\\bdix\\s+huitieme\\b", "18"},
{"\\bdix\\s+neuvieme\\b", "19"},
- {"\\bcorse\\s+du\\s+sud\\b", "2a"},
+ {"\\bdix\\s+septieme\\b", "17"},
{"\\beure\\s+et\\s+loir\\b", "28"},
- {"\\bloir\\s+et\\s+cher\\b", "41"},
{"\\bhaute\\s+savoie\\b", "74"},
{"\\bhaute\\s+vienne\\b", "87"},
+ {"\\bloir\\s+et\\s+cher\\b", "41"},
{"\\bval\\s+de\\s+marne\\b", "94"},
- {"\\bquatorzieme\\b", "14"},
{"\\bcouffouleux\\b", "coufouleux"},
+ {"\\bdeux\\s+sevres\\b", "79"},
{"\\bhaute\\s+alpes\\b", "05"},
{"\\bhaute\\s+corse\\b", "2b"},
{"\\bhaute\\s+loire\\b", "43"},
{"\\bhaute\\s+marne\\b", "52"},
- {"\\bpuy\\s+de\\s+dome\\b", "63"},
{"\\bhaute\\s+saone\\b", "70"},
- {"\\bdeux\\s+sevres\\b", "79"},
+ {"\\bpuy\\s+de\\s+dome\\b", "63"},
+ {"\\bquatorzieme\\b", "14"},
{"\\brhone\\s+alpes\\b", "5"},
+ {"\\bacquitaine\\b", "b"},
{"\\benclave\\s+de\\b", ""},
{"\\bval\\s+d\\s+oise\\b", "95"},
- {"\\bacquitaine\\b", "b"},
- {"\\btroisieme\\b", "3"},
- {"\\bquatrieme\\b", "4"},
- {"\\bcinquieme\\b", "5"},
- {"\\btreizieme\\b", "13"},
- {"\\bquinzieme\\b", "xv"},
- {"\\bvingtieme\\b", "20"},
+ {"\\baquitaine\\b", "b"},
{"\\bboulevard\\b", "bd"},
- {"\\bnationale\\b", "n"},
+ {"\\bbourgogne\\b", "d"},
+ {"\\bcinquieme\\b", "5"},
{"\\bcote\\s+d\\s+or\\b", "21"},
{"\\bfinistere\\b", "29"},
- {"\\bmoribihan\\b", "56"},
{"\\bhaut\\s+rhin\\b", "68"},
- {"\\baquitaine\\b", "b"},
- {"\\bbourgogne\\b", "d"},
- {"\\bpremiere\\b", "i"},
- {"\\bdeuxieme\\b", "2"},
- {"\\bseptieme\\b", "7"},
- {"\\bhuitieme\\b", "8"},
- {"\\bneuvieme\\b", "9"},
- {"\\bdouzieme\\b", "12"},
- {"\\bseizieme\\b", "16"},
- {"\\bla\\s+croix\\b", "lacroix"},
+ {"\\bmoribihan\\b", "56"},
+ {"\\bnationale\\b", "n"},
+ {"\\bquatrieme\\b", "4"},
+ {"\\bquinzieme\\b", "15"},
+ {"\\btreizieme\\b", "13"},
+ {"\\btroisieme\\b", "3"},
+ {"\\bvingtieme\\b", "20"},
{"\\ballemont\\b", "allemond"},
{"\\bardennes\\b", "08"},
+ {"\\bauvergne\\b", "c"},
{"\\baveryron\\b", "12"},
- {"\\bcalvados\\b", "14"},
- {"\\bcharente\\b", "16"},
- {"\\bdordogne\\b", "24"},
{"\\bbas\\s+rhin\\b", "67"},
- {"\\byvelines\\b", "78"},
- {"\\bvaucluse\\b", "84"},
- {"\\bauvergne\\b", "c"},
- {"\\bburgundy\\b", "d"},
{"\\bbretagne\\b", ""},
{"\\bbrittany\\b", ""},
+ {"\\bburgundy\\b", "d"},
+ {"\\bcalvados\\b", "14"},
+ {"\\bcharente\\b", "16"},
+ {"\\bdeuxieme\\b", "2"},
+ {"\\bdordogne\\b", "24"},
+ {"\\bdouzieme\\b", "12"},
+ {"\\bhuitieme\\b", "8"},
+ {"\\bla\\s+croix\\b", "lacroix"},
{"\\blimousin\\b", "l"},
{"\\blorraine\\b", "m"},
+ {"\\bneuvieme\\b", "9"},
{"\\bpicardie\\b", "s"},
- {"\\bsixieme\\b", "6"},
- {"\\bdixieme\\b", "x"},
- {"\\bonzieme\\b", "xi"},
- {"\\bpicardy\\b", "s"},
+ {"\\bpremiere\\b", "1"},
+ {"\\bseizieme\\b", "16"},
+ {"\\bseptieme\\b", "7"},
+ {"\\bvaucluse\\b", "84"},
+ {"\\byvelines\\b", "78"},
{"\\bardeche\\b", "07"},
{"\\bcorreze\\b", "19"},
+ {"\\bcorsica\\b", "h"},
+ {"\\bdixieme\\b", "x"},
+ {"\\bessonne\\b", "91"},
{"\\bgironde\\b", "33"},
{"\\bherault\\b", "34"},
{"\\bmayenne\\b", "53"},
{"\\bmoselle\\b", "57"},
- {"\\bessonne\\b", "91"},
- {"\\bcorsica\\b", "h"},
- {"\\bsainte\\b", ""},
- {"\\bgrande\\b", "gr"},
- {"\\bavenue\\b", "ave"},
- {"\\bregion\\b", ""},
+ {"\\bonzieme\\b", "11"},
+ {"\\bpicardy\\b", "s"},
+ {"\\bsixieme\\b", "6"},
{"\\ballier\\b", "03"},
+ {"\\balsace\\b", "a"},
{"\\bariege\\b", "09"},
+ {"\\bavenue\\b", "ave"},
+ {"\\bcantal\\b", "15"},
+ {"\\bcentre\\b", "f"},
{"\\bcreuse\\b", "23"},
+ {"\\bfrance\\b", "fr"},
+ {"\\bgrande\\b", "gd"},
{"\\blandes\\b", "40"},
{"\\bloiret\\b", "45"},
{"\\blozere\\b", "48"},
{"\\bmanche\\b", "50"},
{"\\bnievre\\b", "58"},
+ {"\\bregion\\b", ""},
+ {"\\bsainte\\b", ""},
{"\\bsarthe\\b", "72"},
{"\\bsavoie\\b", "73"},
{"\\bvendee\\b", "85"},
{"\\bvienne\\b", "86"},
{"\\bvosges\\b", "88"},
- {"\\balsace\\b", "a"},
- {"\\bcentre\\b", "f"},
- {"\\bfrance\\b", "fr"},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bouest\\b", "o"},
- {"\\bsaint\\b", ""},
- {"\\bmount\\b", "mt"},
- {"\\bxviii\\b", "18"},
- {"\\bde\\s+la\\b", ""},
- {"\\bde\\s+l\'\\b", ""},
- {"\\bet\\s+du\\b", ""},
- {"\\bgrand\\b", "gr"},
- {"\\bvilla\\b", "vil"},
- {"\\bparis\\b", ""},
{"\\baisne\\b", "02"},
+ {"\\bcorse\\b", "h"},
+ {"\\bde\\s+l\'\\b", ""},
+ {"\\bde\\s+la\\b", ""},
{"\\bdoubs\\b", "25"},
{"\\bdrome\\b", "26"},
+ {"\\bet\\s+du\\b", ""},
+ {"\\bgrand\\b", "gd"},
{"\\bindre\\b", "36"},
{"\\bisere\\b", "38"},
{"\\bloire\\b", "42"},
{"\\bmarne\\b", "51"},
{"\\bmeuse\\b", "55"},
+ {"\\bmount\\b", "mt"},
+ {"\\bnorth\\b", "n"},
+ {"\\bouest\\b", "o"},
+ {"\\bparis\\b", ""},
{"\\brhone\\b", "69"},
+ {"\\bsaint\\b", ""},
{"\\bsomme\\b", "80"},
+ {"\\bsouth\\b", "s"},
+ {"\\bvilla\\b", "vil"},
+ {"\\bxviii\\b", "18"},
{"\\byonne\\b", "89"},
- {"\\bcorse\\b", "h"},
- {"\\bnord\\b", "n"},
- {"\\bwest\\b", "o"},
- {"\\bieme\\b", ""},
- {"\\bviii\\b", "8"},
- {"\\bxiii\\b", "13"},
- {"\\bxvii\\b", "17"},
+ {"\\baude\\b", "11"},
{"\\bcher\\b", "18"},
{"\\beure\\b", "27"},
{"\\bgard\\b", "30"},
{"\\bgers\\b", "32"},
+ {"\\bieme\\b", ""},
{"\\bjura\\b", "39"},
+ {"\\bnord\\b", "n"},
{"\\boise\\b", "60"},
{"\\borne\\b", "61"},
{"\\btarn\\b", "81"},
- {"\\bsud\\b", "s"},
- {"\\best\\b", ""},
- {"\\bere\\b", ""},
+ {"\\bviii\\b", "8"},
+ {"\\bwest\\b", "o"},
+ {"\\bxiii\\b", "13"},
+ {"\\bxvii\\b", "17"},
+ {"\\bain\\b", "01"},
+ {"\\bdes\\b", ""},
{"\\beme\\b", ""},
- {"\\bste\\b", ""},
- {"\\bmte\\b", "mt"},
+ {"\\bere\\b", ""},
+ {"\\best\\b", ""},
+ {"\\bgde\\b", "gd"},
{"\\biii\\b", "3"},
+ {"\\bles\\b", ""},
+ {"\\blot\\b", "46"},
+ {"\\bmte\\b", "mt"},
+ {"\\bste\\b", ""},
+ {"\\bsud\\b", "s"},
+ {"\\bsur\\b", ""},
+ {"\\bvar\\b", "83"},
{"\\bvii\\b", "7"},
{"\\bxii\\b", "12"},
{"\\bxiv\\b", "14"},
- {"\\bxvi\\b", "16"},
{"\\bxix\\b", "19"},
- {"\\bdes\\b", ""},
- {"\\bles\\b", ""},
- {"\\bsur\\b", ""},
- {"\\bgde\\b", "gr"},
- {"\\bain\\b", "01"},
- {"\\blot\\b", "46"},
- {"\\bvar\\b", "83"},
- {"\\bst\\b", ""},
- {"\\bnd\\b", ""},
- {"\\brd\\b", ""},
- {"\\bth\\b", ""},
+ {"\\bxvi\\b", "16"},
+ {"\\b10\\b", "x"},
+ {"\\b59\\b", "n"},
+ {"\\b75\\b", ""},
+ {"\\bd\'\\b", ""},
+ {"\\bde\\b", ""},
+ {"\\bdu\\b", ""},
+ {"\\ben\\b", ""},
{"\\ber\\b", ""},
- {"\\bre\\b", ""},
+ {"\\bgr\\b", "gd"},
{"\\bii\\b", "2"},
+ {"\\bin\\b", ""},
{"\\biv\\b", "4"},
- {"\\bvi\\b", "6"},
{"\\bix\\b", "9"},
- {"\\b10\\b", "x"},
- {"\\b11\\b", "xi"},
- {"\\b15\\b", "xv"},
- {"\\bxx\\b", "20"},
- {"\\bdu\\b", ""},
- {"\\bde\\b", ""},
- {"\\bd\'\\b", ""},
+ {"\\bl\'\\b", ""},
{"\\bla\\b", ""},
{"\\ble\\b", ""},
- {"\\bl\'\\b", ""},
+ {"\\bnd\\b", ""},
{"\\bof\\b", ""},
- {"\\ben\\b", ""},
- {"\\bin\\b", ""},
- {"\\bgd\\b", "gr"},
- {"\\b59\\b", "n"},
- {"\\b75\\b", ""},
+ {"\\brd\\b", ""},
+ {"\\bre\\b", ""},
+ {"\\bst\\b", ""},
+ {"\\bth\\b", ""},
+ {"\\bvi\\b", "6"},
+ {"\\bxi\\b", "11"},
+ {"\\bxv\\b", "15"},
+ {"\\bxx\\b", "20"},
{"\\be\\b", ""},
- {"\\bw\\b", "o"},
- {"\\b1\\b", "i"},
+ {"\\bi\\b", "1"},
{"\\bv\\b", "5"},
+ {"\\bw\\b", "o"},
};
const Rule kRules_GB[] = {
@@ -1298,281 +1300,281 @@ const Rule kRules_GB[] = {
{"\\bkensington\\s+and\\s+chelsea\\b", "gb-kec"},
{"\\bwindsor\\s+and\\s+maidenhead\\b", "gb-wnm"},
{"\\bblackburn\\s+with\\s+darwen\\b", "gb-bbd"},
- {"\\bsouth\\s+gloucestershire\\b", "gb-sgc"},
{"\\bdumfries\\s+and\\s+galloway\\b", "gb-dgy"},
+ {"\\bsouth\\s+gloucestershire\\b", "gb-sgc"},
{"\\bthe\\s+vale\\s+of\\s+glamorgan\\b", "gb-vgl"},
{"\\bbarking\\s+and\\s+dagenham\\b", "gb-bdg"},
- {"\\bkingston\\s+upon\\s+thames\\b", "gb-ktt"},
- {"\\brichmond\\s+upon\\s+thames\\b", "gb-ric"},
{"\\bcentral\\s+bedfordshire\\b", "gb-cbf"},
+ {"\\bkingston\\s+upon\\s+thames\\b", "gb-ktt"},
{"\\bredcar\\s+and\\s+cleveland\\b", "gb-rcc"},
- {"\\bthe\\s+scottish\\s+borders\\b", "gb-scb"},
{"\\brhondda\\,\\s+cynon\\,\\s+taff\\b", "gb-rct"},
- {"\\bnewcastle\\s+upon\\s+tyne\\b", "gb-net"},
+ {"\\brichmond\\s+upon\\s+thames\\b", "gb-ric"},
+ {"\\bthe\\s+scottish\\s+borders\\b", "gb-scb"},
{"\\beast\\s+dunbartonshire\\b", "gb-edu"},
+ {"\\bnewcastle\\s+upon\\s+tyne\\b", "gb-net"},
{"\\bwest\\s+dunbartonshire\\b", "gb-wdu"},
- {"\\bliverpool\\s+district\\b", "gb-liv"},
{"\\bkingston\\s+upon\\s+hull\\b", "gb-khl"},
+ {"\\bliverpool\\s+district\\b", "gb-liv"},
{"\\bnorth\\s+lincolnshire\\b", "gb-nln"},
{"\\btelford\\s+and\\s+wrekin\\b", "gb-tfw"},
- {"\\blondon\\s+borough\\s+of\\b", ""},
- {"\\bkirklees\\s+district\\b", "gb-kir"},
{"\\bbrighton\\s+and\\s+hove\\b", "gb-bnh"},
- {"\\beast\\s+renfrewshire\\b", "gb-erw"},
{"\\bcity\\s+of\\s+edinburgh\\b", "gb-edh"},
+ {"\\beast\\s+renfrewshire\\b", "gb-erw"},
+ {"\\bkirklees\\s+district\\b", "gb-kir"},
+ {"\\blondon\\s+borough\\s+of\\b", ""},
+ {"\\bneath\\s+port\\s+talbot\\b", "gb-ntl"},
{"\\bnorth\\s+lanarkshire\\b", "gb-nlk"},
{"\\bperth\\s+and\\s+kinross\\b", "gb-pkn"},
{"\\bsouth\\s+lanarkshire\\b", "gb-slk"},
- {"\\bneath\\s+port\\s+talbot\\b", "gb-ntl"},
- {"\\bnorthamptonshire\\b", "gb-nth"},
{"\\bbracknell\\s+forest\\b", "gb-brc"},
- {"\\bstockton\\-on\\-tees\\b", "gb-stt"},
{"\\bclackmannanshire\\b", "gb-clk"},
- {"\\bshetland\\s+islands\\b", "gb-zet"},
{"\\bisle\\s+of\\s+anglesey\\b", "gb-agy"},
+ {"\\bnorthamptonshire\\b", "gb-nth"},
{"\\bnorthern\\s+ireland\\b", "n.i."},
+ {"\\bshetland\\s+islands\\b", "gb-zet"},
+ {"\\bstockton\\-on\\-tees\\b", "gb-stt"},
+ {"\\bargyll\\s+and\\s+bute\\b", "gb-agb"},
{"\\bbuckinghamshire\\b", "gb-bkm"},
+ {"\\bcarmarthenshire\\b", "gb-cmn"},
+ {"\\bcity\\s+of\\s+bristol\\b", "gb-bst"},
{"\\bgloucestershire\\b", "gb-gls"},
{"\\bnorth\\s+yorkshire\\b", "gb-nyk"},
{"\\bnottinghamshire\\b", "gb-ntt"},
{"\\bsefton\\s+district\\b", "gb-sft"},
- {"\\bcity\\s+of\\s+bristol\\b", "gb-bst"},
{"\\bsouthend\\-on\\-sea\\b", "gb-sos"},
- {"\\bargyll\\s+and\\s+bute\\b", "gb-agb"},
- {"\\bcarmarthenshire\\b", "gb-cmn"},
{"\\bcambridgeshire\\b", "gb-cam"},
- {"\\bleicestershire\\b", "gb-lec"},
- {"\\bworcestershire\\b", "gb-wor"},
- {"\\bwaltham\\s+forest\\b", "gb-wft"},
+ {"\\bcity\\s+of\\s+london\\b", "gb-lnd"},
{"\\bleeds\\s+district\\b", "gb-lds"},
- {"\\bnorth\\s+tyneside\\b", "gb-nty"},
- {"\\bsouth\\s+tyneside\\b", "gb-sty"},
+ {"\\bleicestershire\\b", "gb-lec"},
+ {"\\bmerthyr\\s+tydfil\\b", "gb-mty"},
+ {"\\bnorth\\s+ayrshire\\b", "gb-nay"},
{"\\bnorth\\s+somerset\\b", "gb-nsm"},
+ {"\\bnorth\\s+tyneside\\b", "gb-nty"},
{"\\bnorthumberland\\b", "gb-nbl"},
- {"\\bstoke\\-on\\-trent\\b", "gb-ste"},
- {"\\bwest\\s+berkshire\\b", "gb-wbk"},
- {"\\bcity\\s+of\\s+london\\b", "gb-lnd"},
- {"\\bnorth\\s+ayrshire\\b", "gb-nay"},
{"\\borkney\\s+islands\\b", "gb-ork"},
{"\\bsouth\\s+ayrshire\\b", "gb-say"},
- {"\\bmerthyr\\s+tydfil\\b", "gb-mty"},
- {"\\bhertfordshire\\b", "gb-hrt"},
- {"\\bstaffordshire\\b", "gb-sts"},
- {"\\btower\\s+hamlets\\b", "gb-twh"},
- {"\\bwolverhampton\\b", "gb-wlv"},
+ {"\\bsouth\\s+tyneside\\b", "gb-sty"},
+ {"\\bstoke\\-on\\-trent\\b", "gb-ste"},
+ {"\\bwaltham\\s+forest\\b", "gb-wft"},
+ {"\\bwest\\s+berkshire\\b", "gb-wbk"},
+ {"\\bworcestershire\\b", "gb-wor"},
+ {"\\baberdeen\\s+city\\b", "gb-abe"},
+ {"\\baberdeenshire\\b", "gb-abd"},
+ {"\\bblaenau\\s+gwent\\b", "gb-bgw"},
+ {"\\bcarrickfergus\\b", "gb-ckf"},
{"\\bcheshire\\s+east\\b", "gb-che"},
{"\\bcounty\\s+durham\\b", "gb-dur"},
+ {"\\beast\\s+ayrshire\\b", "gb-eay"},
{"\\bherefordshire\\b", "gb-hef"},
+ {"\\bhertfordshire\\b", "gb-hrt"},
{"\\bisle\\s+of\\s+wight\\b", "gb-iow"},
{"\\bmiddlesbrough\\b", "gb-mdb"},
{"\\bmilton\\s+keynes\\b", "gb-mik"},
- {"\\bcarrickfergus\\b", "gb-ckf"},
- {"\\baberdeen\\s+city\\b", "gb-abe"},
- {"\\baberdeenshire\\b", "gb-abd"},
- {"\\beast\\s+ayrshire\\b", "gb-eay"},
- {"\\bblaenau\\s+gwent\\b", "gb-bgw"},
{"\\bmonmouthshire\\b", "gb-mon"},
{"\\bpembrokeshire\\b", "gb-pem"},
- {"\\blincolnshire\\b", "gb-lin"},
- {"\\bwarwickshire\\b", "gb-war"},
- {"\\bpeterborough\\b", "gb-pte"},
- {"\\bnewtownabbey\\b", "gb-nta"},
+ {"\\bstaffordshire\\b", "gb-sts"},
+ {"\\btower\\s+hamlets\\b", "gb-twh"},
+ {"\\bwolverhampton\\b", "gb-wlv"},
+ {"\\bdenbighshire\\b", "gb-den"},
{"\\beast\\s+lothian\\b", "gb-eln"},
+ {"\\bfulmodestone\\b", "fulmodeston"},
{"\\bglasgow\\s+city\\b", "gb-glg"},
+ {"\\blincolnshire\\b", "gb-lin"},
+ {"\\bnewtownabbey\\b", "gb-nta"},
+ {"\\bpeterborough\\b", "gb-pte"},
{"\\brenfrewshire\\b", "gb-rfw"},
+ {"\\bwarwickshire\\b", "gb-war"},
{"\\bwest\\s+lothian\\b", "gb-wln"},
- {"\\bdenbighshire\\b", "gb-den"},
- {"\\bfulmodestone\\b", "fulmodeston"},
- {"\\beast\\s+sussex\\b", "gb-esx"},
- {"\\boxfordshire\\b", "gb-oxf"},
- {"\\bwest\\s+sussex\\b", "gb-wsx"},
- {"\\bwestminster\\b", "gb-wsm"},
{"\\bbournemouth\\b", "gb-bmh"},
- {"\\bsouthampton\\b", "gb-sth"},
{"\\bcastlereagh\\b", "gb-csr"},
- {"\\bmagherafelt\\b", "gb-mft"},
{"\\bdundee\\s+city\\b", "gb-dnd"},
- {"\\beilean\\s+siar\\b", "gb-els"},
{"\\bdunnamanagh\\b", "dunamanagh"},
+ {"\\beast\\s+sussex\\b", "gb-esx"},
+ {"\\beilean\\s+siar\\b", "gb-els"},
{"\\bking\'s\\s+stag\\b", "king stag"},
- {"\\bborough\\s+of\\b", ""},
- {"\\bderbyshire\\b", "gb-dby"},
- {"\\blancashire\\b", "gb-lan"},
- {"\\bhillingdon\\b", "gb-hil"},
- {"\\bwandsworth\\b", "gb-wnd"},
+ {"\\bmagherafelt\\b", "gb-mft"},
+ {"\\boxfordshire\\b", "gb-oxf"},
+ {"\\bsouthampton\\b", "gb-sth"},
+ {"\\bwest\\s+sussex\\b", "gb-wsx"},
+ {"\\bwestminster\\b", "gb-wsm"},
+ {"\\bballymoney\\b", "gb-bly"},
{"\\bbirmingham\\b", "gb-bir"},
+ {"\\bborough\\s+of\\b", ""},
+ {"\\bcaerphilly\\b", "gb-cay"},
{"\\bcalderdale\\b", "gb-cld"},
- {"\\bmanchester\\b", "gb-man"},
- {"\\bst\\.\\s+helens\\b", "gb-shn"},
- {"\\bsunderland\\b", "gb-snd"},
+ {"\\bceredigion\\b", "gb-cgn"},
+ {"\\bculnacnock\\b", "culnacnoc"},
{"\\bdarlington\\b", "gb-dal"},
+ {"\\bderbyshire\\b", "gb-dby"},
+ {"\\bflintshire\\b", "gb-fln"},
+ {"\\bgroesllwyd\\b", "groes-lwyd"},
{"\\bhartlepool\\b", "gb-hpl"},
+ {"\\bhillingdon\\b", "gb-hil"},
+ {"\\binverclyde\\b", "gb-ivc"},
+ {"\\blancashire\\b", "gb-lan"},
+ {"\\bmanchester\\b", "gb-man"},
+ {"\\bmidlothian\\b", "gb-mln"},
+ {"\\bn\\.\\s+ireland\\b", "n.i."},
+ {"\\bnorth\\s+down\\b", "gb-ndn"},
{"\\bnottingham\\b", "gb-ngm"},
{"\\bportsmouth\\b", "gb-por"},
{"\\bshropshire\\b", "gb-shr"},
+ {"\\bst\\.\\s+helens\\b", "gb-shn"},
+ {"\\bsunderland\\b", "gb-snd"},
+ {"\\bwandsworth\\b", "gb-wnd"},
{"\\bwarrington\\b", "gb-wrt"},
- {"\\bballymoney\\b", "gb-bly"},
- {"\\bnorth\\s+down\\b", "gb-ndn"},
- {"\\binverclyde\\b", "gb-ivc"},
- {"\\bmidlothian\\b", "gb-mln"},
- {"\\bcaerphilly\\b", "gb-cay"},
- {"\\bceredigion\\b", "gb-cgn"},
- {"\\bflintshire\\b", "gb-fln"},
- {"\\bgroes\\-lwyd\\b", "groesllwyd"},
- {"\\bculnacnock\\b", "culnacnoc"},
- {"\\bn\\.\\s+ireland\\b", "n.i."},
+ {"\\bballymena\\b", "gb-bla"},
+ {"\\bbanbridge\\b", "gb-bnb"},
+ {"\\bblackpool\\b", "gb-bpl"},
{"\\bboulevard\\b", "blvd"},
- {"\\bhampshire\\b", "gb-ham"},
+ {"\\bcoleraine\\b", "gb-clr"},
+ {"\\bcookstown\\b", "gb-ckt"},
+ {"\\bcraigavon\\b", "gb-cgv"},
+ {"\\bdoncaster\\b", "gb-dnc"},
+ {"\\bfermanagh\\b", "gb-fer"},
+ {"\\bgateshead\\b", "gb-gat"},
{"\\bgreenwich\\b", "gb-gre"},
+ {"\\bhampshire\\b", "gb-ham"},
{"\\bislington\\b", "gb-isl"},
+ {"\\bleicester\\b", "gb-lce"},
+ {"\\bn\\s+ireland\\b", "n.i."},
+ {"\\bn\\.ireland\\b", "n.i."},
{"\\bredbridge\\b", "gb-rdb"},
- {"\\bsouthwark\\b", "gb-swk"},
- {"\\bdoncaster\\b", "gb-dnc"},
- {"\\bgateshead\\b", "gb-gat"},
{"\\brotherham\\b", "gb-rot"},
{"\\bsheffield\\b", "gb-shf"},
+ {"\\bsouthwark\\b", "gb-swk"},
{"\\bstockport\\b", "gb-skp"},
{"\\bwakefield\\b", "gb-wkf"},
- {"\\bblackpool\\b", "gb-bpl"},
- {"\\bleicester\\b", "gb-lce"},
{"\\bwiltshire\\b", "gb-wil"},
{"\\bwokingham\\b", "gb-wok"},
- {"\\bballymena\\b", "gb-bla"},
- {"\\bbanbridge\\b", "gb-bnb"},
- {"\\bcoleraine\\b", "gb-clr"},
- {"\\bcookstown\\b", "gb-ckt"},
- {"\\bcraigavon\\b", "gb-cgv"},
- {"\\bfermanagh\\b", "gb-fer"},
- {"\\bn\\.ireland\\b", "n.i."},
- {"\\bn\\s+ireland\\b", "n.i."},
+ {"\\bbarnsley\\b", "gb-bns"},
+ {"\\bbradford\\b", "gb-brd"},
+ {"\\bbridgend\\b", "gb-bge"},
+ {"\\bcheshire\\b", "gb-chs"},
+ {"\\bcornwall\\b", "gb-con"},
+ {"\\bcoventry\\b", "gb-cov"},
{"\\bcrescent\\b", "cres"},
{"\\bdistrict\\b", ""},
- {"\\bsomerset\\b", "gb-som"},
+ {"\\bhare\\s+law\\b", "harelaw"},
{"\\bharingey\\b", "gb-hry"},
{"\\bhavering\\b", "gb-hav"},
+ {"\\bhighland\\b", "gb-hld"},
{"\\bhounslow\\b", "gb-hns"},
- {"\\blewisham\\b", "gb-lew"},
- {"\\bbarnsley\\b", "gb-bns"},
- {"\\bbradford\\b", "gb-brd"},
- {"\\bcoventry\\b", "gb-cov"},
{"\\bknowsley\\b", "gb-kwl"},
+ {"\\blewisham\\b", "gb-lew"},
+ {"\\blimavady\\b", "gb-lmv"},
+ {"\\bplymouth\\b", "gb-ply"},
{"\\brochdale\\b", "gb-rch"},
{"\\bsandwell\\b", "gb-saw"},
+ {"\\bscotland\\b", "gb-sct"},
{"\\bsolihull\\b", "gb-sol"},
+ {"\\bsomerset\\b", "gb-som"},
+ {"\\bstirling\\b", "gb-stg"},
+ {"\\bstrabane\\b", "gb-stb"},
{"\\btameside\\b", "gb-tam"},
- {"\\btrafford\\b", "gb-trf"},
- {"\\bcornwall\\b", "gb-con"},
- {"\\bplymouth\\b", "gb-ply"},
{"\\bthurrock\\b", "gb-thr"},
- {"\\blimavady\\b", "gb-lmv"},
- {"\\bstrabane\\b", "gb-stb"},
- {"\\bhighland\\b", "gb-hld"},
- {"\\bstirling\\b", "gb-stg"},
- {"\\bbridgend\\b", "gb-bge"},
- {"\\bcheshire\\b", "gb-chs"},
- {"\\bhare\\s+law\\b", "harelaw"},
- {"\\bscotland\\b", "gb-sct"},
- {"\\bparkway\\b", "pkwy"},
- {"\\bhighway\\b", "hwy"},
- {"\\bcity\\s+of\\b", ""},
- {"\\bcumbria\\b", "gb-cma"},
- {"\\bnorfolk\\b", "gb-nfk"},
- {"\\bsuffolk\\b", "gb-sfk"},
+ {"\\btrafford\\b", "gb-trf"},
+ {"\\bbedford\\b", "gb-bdf"},
+ {"\\bbelfast\\b", "gb-bfs"},
{"\\bbromley\\b", "gb-bry"},
+ {"\\bcardiff\\b", "gb-crf"},
+ {"\\bcity\\s+of\\b", ""},
{"\\bcroydon\\b", "gb-cry"},
+ {"\\bcumbria\\b", "gb-cma"},
{"\\benfield\\b", "gb-enf"},
+ {"\\bengland\\b", "eng"},
+ {"\\bfalkirk\\b", "gb-fal"},
+ {"\\bgwynedd\\b", "gb-gwn"},
{"\\bhackney\\b", "gb-hck"},
+ {"\\bhighway\\b", "hwy"},
{"\\blambeth\\b", "gb-lbh"},
- {"\\bsalford\\b", "gb-slf"},
- {"\\bwalsall\\b", "gb-wll"},
- {"\\bbedford\\b", "gb-bdf"},
- {"\\breading\\b", "gb-rdg"},
- {"\\brutland\\b", "gb-rut"},
- {"\\bswindon\\b", "gb-swd"},
- {"\\bbelfast\\b", "gb-bfs"},
{"\\blisburn\\b", "gb-lsb"},
- {"\\bfalkirk\\b", "gb-fal"},
- {"\\bcardiff\\b", "gb-crf"},
- {"\\bgwynedd\\b", "gb-gwn"},
{"\\bnewport\\b", "gb-nwp"},
+ {"\\bnorfolk\\b", "gb-nfk"},
+ {"\\bparkway\\b", "pkwy"},
+ {"\\breading\\b", "gb-rdg"},
+ {"\\brutland\\b", "gb-rut"},
+ {"\\bsalford\\b", "gb-slf"},
+ {"\\bsuffolk\\b", "gb-sfk"},
{"\\bswansea\\b", "gb-swa"},
+ {"\\bswindon\\b", "gb-swd"},
{"\\btorfaen\\b", "gb-tof"},
+ {"\\bwalsall\\b", "gb-wll"},
{"\\bwrexham\\b", "gb-wrx"},
- {"\\bengland\\b", "eng"},
{"\\bavenue\\b", "ave"},
- {"\\bstreet\\b", "st"},
- {"\\bparade\\b", "pde"},
{"\\bcommon\\b", "comm"},
- {"\\bgb\\-dev\\b", "devon"},
- {"\\bgb\\-dor\\b", "dorset"},
- {"\\bgb\\-ess\\b", "essex"},
- {"\\bgb\\-ken\\b", "kent"},
- {"\\bsurrey\\b", "gb-sry"},
- {"\\bbarnet\\b", "gb-bne"},
- {"\\bgb\\-bex\\b", "bexley"},
+ {"\\bgb\\-ans\\b", "angus"},
+ {"\\bgb\\-ant\\b", "antrim"},
+ {"\\bgb\\-ard\\b", "ards"},
+ {"\\bgb\\-arm\\b", "armagh"},
{"\\bgb\\-ben\\b", "brent"},
- {"\\bcamden\\b", "gb-cmd"},
- {"\\bealing\\b", "gb-eal"},
- {"\\bgb\\-hrw\\b", "harrow"},
- {"\\bgb\\-mrt\\b", "merton"},
- {"\\bgb\\-nwm\\b", "newham"},
- {"\\bgb\\-stn\\b", "sutton"},
+ {"\\bgb\\-bex\\b", "bexley"},
+ {"\\bgb\\-bne\\b", "barnet"},
{"\\bgb\\-bol\\b", "bolton"},
{"\\bgb\\-bur\\b", "bury"},
- {"\\bdudley\\b", "gb-dud"},
- {"\\bgb\\-old\\b", "oldham"},
- {"\\bgb\\-wgn\\b", "wigan"},
- {"\\bwirral\\b", "gb-wrl"},
+ {"\\bgb\\-cmd\\b", "camden"},
+ {"\\bgb\\-cwy\\b", "conwy"},
{"\\bgb\\-der\\b", "derby"},
- {"\\bgb\\-hal\\b", "halton"},
- {"\\bgb\\-lut\\b", "luton"},
- {"\\bgb\\-mdw\\b", "medway"},
- {"\\bgb\\-pol\\b", "poole"},
- {"\\bslough\\b", "gb-slg"},
- {"\\bgb\\-tob\\b", "torbay"},
- {"\\bgb\\-yor\\b", "york"},
- {"\\bantrim\\b", "gb-ant"},
- {"\\bgb\\-ard\\b", "ards"},
- {"\\bgb\\-arm\\b", "armagh"},
- {"\\bgb\\-dry\\b", "derry"},
+ {"\\bgb\\-dev\\b", "devon"},
+ {"\\bgb\\-dor\\b", "dorset"},
{"\\bgb\\-dow\\b", "down"},
+ {"\\bgb\\-dry\\b", "derry"},
+ {"\\bgb\\-dud\\b", "dudley"},
+ {"\\bgb\\-eal\\b", "ealing"},
+ {"\\bgb\\-eng\\b", "eng"},
+ {"\\bgb\\-ess\\b", "essex"},
+ {"\\bgb\\-fif\\b", "fife"},
+ {"\\bgb\\-ken\\b", "kent"},
{"\\bgb\\-lrn\\b", "larne"},
+ {"\\bgb\\-lut\\b", "luton"},
+ {"\\bgb\\-mry\\b", "moray"},
{"\\bgb\\-myl\\b", "moyle"},
+ {"\\bgb\\-nir\\b", "n.i."},
{"\\bgb\\-omh\\b", "omagh"},
- {"\\bgb\\-ans\\b", "angus"},
- {"\\bgb\\-fif\\b", "fife"},
- {"\\bgb\\-mry\\b", "moray"},
- {"\\bgb\\-cwy\\b", "conwy"},
+ {"\\bgb\\-pol\\b", "poole"},
{"\\bgb\\-pow\\b", "powys"},
- {"\\bgb\\-eng\\b", "eng"},
+ {"\\bgb\\-wgn\\b", "wigan"},
{"\\bgb\\-wls\\b", "wales"},
- {"\\bgb\\-nir\\b", "n.i."},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bmount\\b", "mt"},
- {"\\bsaint\\b", "st"},
- {"\\bpoint\\b", "pt"},
+ {"\\bgb\\-yor\\b", "york"},
+ {"\\bhalton\\b", "gb-hal"},
+ {"\\bharrow\\b", "gb-hrw"},
+ {"\\bmedway\\b", "gb-mdw"},
+ {"\\bmerton\\b", "gb-mrt"},
+ {"\\bnewham\\b", "gb-nwm"},
+ {"\\boldham\\b", "gb-old"},
+ {"\\bparade\\b", "pde"},
+ {"\\bslough\\b", "gb-slg"},
+ {"\\bstreet\\b", "st"},
+ {"\\bsurrey\\b", "gb-sry"},
+ {"\\bsutton\\b", "gb-stn"},
+ {"\\btorbay\\b", "gb-tob"},
+ {"\\bwirral\\b", "gb-wrl"},
{"\\bcourt\\b", "ct"},
- {"\\bplace\\b", "pl"},
{"\\bdrive\\b", "dr"},
+ {"\\bmount\\b", "mt"},
+ {"\\bnorth\\b", "n"},
+ {"\\bplace\\b", "pl"},
+ {"\\bpoint\\b", "pt"},
+ {"\\bsaint\\b", "st"},
+ {"\\bsouth\\b", "s"},
{"\\beast\\b", "e"},
- {"\\bwest\\b", "w"},
- {"\\broad\\b", "rd"},
+ {"\\bg\\.b\\.\\b", "gb"},
{"\\blane\\b", "ln"},
+ {"\\broad\\b", "rd"},
{"\\bu\\.k\\.\\b", "gb"},
- {"\\bg\\.b\\.\\b", "gb"},
- {"\\bnth\\b", "n"},
- {"\\bsth\\b", "s"},
+ {"\\bwest\\b", "w"},
+ {"\\bg\\.b\\b", "gb"},
{"\\bmt\\.\\b", "mt"},
- {"\\bst\\.\\b", "st"},
+ {"\\bnth\\b", "n"},
{"\\bpt\\.\\b", "pt"},
+ {"\\bst\\.\\b", "st"},
+ {"\\bsth\\b", "s"},
{"\\bu\\.k\\b", "gb"},
- {"\\bg\\.b\\b", "gb"},
+ {"\\be\\.\\b", "e"},
{"\\bn\\.\\b", "n"},
{"\\bs\\.\\b", "s"},
- {"\\be\\.\\b", "e"},
- {"\\bw\\.\\b", "w"},
{"\\buk\\b", "gb"},
+ {"\\bw\\.\\b", "w"},
};
const Rule kRules_GR[] = {
@@ -1584,61 +1586,59 @@ const Rule kRules_GR[] = {
{"\\bdytiki\\s+ellada\\b", "g"},
{"\\bsterea\\s+ellada\\b", "h"},
{"\\bvoreio\\s+aigaio\\b", "k"},
+ {"\\bmetamorfossi\\b", "metamorfosi"},
{"\\bnotio\\s+aigaio\\b", "l"},
{"\\bpeloponnisos\\b", "j"},
{"\\bthessaloniki\\b", "54"},
- {"\\bmetamorfossi\\b", "metamorfosi"},
- {"\\bionia\\s+nisia\\b", "f"},
{"\\bdodekanisos\\b", "81"},
+ {"\\bionia\\s+nisia\\b", "f"},
{"\\bkaissariani\\b", "kesariani"},
{"\\banatolikos\\b", "e"},
- {"\\bperifereia\\b", "periphery"},
{"\\bchalkidiki\\b", "64"},
{"\\bkefallonia\\b", "23"},
+ {"\\bperifereia\\b", "periphery"},
{"\\bthesprotia\\b", "32"},
- {"\\bnomarchia\\b", "nomo"},
- {"\\bthessalia\\b", "e"},
+ {"\\bagio\\s+oros\\b", "69"},
+ {"\\bcholargos\\b", "holargos"},
{"\\bevrytania\\b", "05"},
{"\\bfthiotida\\b", "06"},
{"\\bkorinthia\\b", "15"},
+ {"\\bnomarchia\\b", "nomo"},
+ {"\\bthessalia\\b", "e"},
{"\\bzakynthos\\b", "21"},
- {"\\bagio\\s+oros\\b", "69"},
- {"\\bcholargos\\b", "holargos"},
{"\\bargolida\\b", "11"},
+ {"\\bchaidari\\b", "haidari"},
+ {"\\bchalkida\\b", "halkida"},
{"\\bioannina\\b", "33"},
{"\\birakleio\\b", "91"},
{"\\bkarditsa\\b", "41"},
{"\\bkastoria\\b", "56"},
+ {"\\bkifissia\\b", "kifisia"},
{"\\bkyklades\\b", "82"},
{"\\bmagnisia\\b", "43"},
+ {"\\bmaroussi\\b", "marousi"},
{"\\bmessinia\\b", "17"},
- {"\\brethymno\\b", "93"},
{"\\brethymni\\b", "93"},
- {"\\bchaidari\\b", "haidari"},
- {"\\bmaroussi\\b", "marousi"},
- {"\\bkifissia\\b", "kifisia"},
- {"\\bchalkida\\b", "halkida"},
- {"\\bvoreioy\\b", "n"},
+ {"\\brethymno\\b", "93"},
{"\\banatoli\\b", "e"},
- {"\\bdytikos\\b", "w"},
- {"\\bipeiros\\b", "d"},
{"\\barkadia\\b", "12"},
+ {"\\bdytikos\\b", "w"},
{"\\bflorina\\b", "63"},
{"\\bgrevena\\b", "51"},
{"\\bimathia\\b", "53"},
+ {"\\bipeiros\\b", "d"},
{"\\bkerkyra\\b", "22"},
{"\\blakonia\\b", "16"},
{"\\blasithi\\b", "92"},
{"\\blefkada\\b", "24"},
+ {"\\bpapagou\\b", "papagos"},
+ {"\\bpiraeus\\b", "pireas"},
{"\\bpreveza\\b", "34"},
{"\\btrikala\\b", "44"},
{"\\bvoiotia\\b", "03"},
- {"\\bpiraeus\\b", "pireas"},
- {"\\bpapagos\\b", "papagou"},
- {"\\bvoreio\\b", "n"},
- {"\\bnotioy\\b", "s"},
- {"\\battiki\\b", "i"},
+ {"\\bvoreioy\\b", "n"},
{"\\bachaia\\b", "13"},
+ {"\\battiki\\b", "i"},
{"\\bchania\\b", "94"},
{"\\bevvoia\\b", "04"},
{"\\bfokida\\b", "07"},
@@ -1647,64 +1647,90 @@ const Rule kRules_GR[] = {
{"\\bkozani\\b", "58"},
{"\\blarisa\\b", "42"},
{"\\blesvos\\b", "83"},
+ {"\\bnotioy\\b", "s"},
{"\\bpieria\\b", "61"},
{"\\brodopi\\b", "73"},
{"\\bserres\\b", "62"},
+ {"\\bvoreio\\b", "n"},
{"\\bxanthi\\b", "72"},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bnotio\\b", "s"},
- {"\\bkriti\\b", "m"},
{"\\bchios\\b", "85"},
{"\\bdrama\\b", "52"},
{"\\bevros\\b", "71"},
+ {"\\bhania\\b", "94"},
{"\\bileia\\b", "14"},
+ {"\\bkriti\\b", "m"},
+ {"\\bnorth\\b", "n"},
+ {"\\bnotio\\b", "s"},
{"\\bpella\\b", "59"},
{"\\bsamos\\b", "84"},
- {"\\bhania\\b", "94"},
- {"\\bkato\\b", "s"},
- {"\\beast\\b", "e"},
- {"\\bwest\\b", "w"},
- {"\\bdysi\\b", "w"},
+ {"\\bsouth\\b", "s"},
{"\\barta\\b", "31"},
+ {"\\bdysi\\b", "w"},
+ {"\\beast\\b", "e"},
{"\\bhios\\b", "85"},
- {"\\bano\\b", "n"},
+ {"\\bkato\\b", "s"},
+ {"\\bwest\\b", "w"},
{"\\ba\\s+1\\b", "i"},
+ {"\\bano\\b", "n"},
};
const Rule kRules_HK[] = {
- {"\\bboulevard\\b", "blvd"}, {"\\bhong\\s+kong\\b", "hk"},
- {"\\bjunction\\b", "jct"}, {"\\bcrescent\\b", "cres"},
- {"\\bdistrict\\b", ""}, {"\\bhongkong\\b", "hk"},
- {"\\bcentral\\b", "c"}, {"\\bseventh\\b", "7"},
- {"\\bparkway\\b", "pkwy"}, {"\\bhighway\\b", "hwy"},
- {"\\bsecond\\b", "2"}, {"\\bfourth\\b", "4"},
- {"\\beighth\\b", "8"}, {"\\bavenue\\b", "ave"},
- {"\\bstreet\\b", "st"}, {"\\bparade\\b", "pde"},
- {"\\bcommon\\b", "comm"}, {"\\bcenter\\b", "centre"},
- {"\\bnorth\\b", "n"}, {"\\bsouth\\b", "s"},
- {"\\bfirst\\b", "1"}, {"\\bthird\\b", "3"},
- {"\\bthree\\b", "3"}, {"\\bfifth\\b", "5"},
- {"\\bsixth\\b", "6"}, {"\\bseven\\b", "7"},
- {"\\beight\\b", "8"}, {"\\bninth\\b", "9"},
- {"\\btenth\\b", "10"}, {"\\bmount\\b", "mt"},
- {"\\bsaint\\b", "st"}, {"\\bpoint\\b", "pt"},
- {"\\bcourt\\b", "ct"}, {"\\bplace\\b", "pl"},
- {"\\bdrive\\b", "dr"}, {"\\beast\\b", "e"},
- {"\\bwest\\b", "w"}, {"\\bfour\\b", "4"},
- {"\\bfive\\b", "5"}, {"\\bnine\\b", "9"},
- {"\\broad\\b", "rd"}, {"\\blane\\b", "ln"},
- {"\\bnth\\b", "n"}, {"\\bsth\\b", "s"},
- {"\\bone\\b", "1"}, {"\\btwo\\b", "2"},
- {"\\bsix\\b", "6"}, {"\\bten\\b", "10"},
+ {"\\bboulevard\\b", "blvd"},
+ {"\\bhong\\s+kong\\b", "hk"},
+ {"\\bcrescent\\b", "cres"},
+ {"\\bdistrict\\b", ""},
+ {"\\bhongkong\\b", "hk"},
+ {"\\bjunction\\b", "jct"},
+ {"\\bcentral\\b", "c"},
+ {"\\bhighway\\b", "hwy"},
+ {"\\bparkway\\b", "pkwy"},
+ {"\\bseventh\\b", "7"},
+ {"\\bavenue\\b", "ave"},
+ {"\\bcentre\\b", "center"},
+ {"\\bcommon\\b", "comm"},
+ {"\\beighth\\b", "8"},
+ {"\\bfourth\\b", "4"},
+ {"\\bparade\\b", "pde"},
+ {"\\bsecond\\b", "2"},
+ {"\\bstreet\\b", "st"},
+ {"\\bcourt\\b", "ct"},
+ {"\\bdrive\\b", "dr"},
+ {"\\beight\\b", "8"},
+ {"\\bfifth\\b", "5"},
+ {"\\bfirst\\b", "1"},
+ {"\\bmount\\b", "mt"},
+ {"\\bninth\\b", "9"},
+ {"\\bnorth\\b", "n"},
+ {"\\bplace\\b", "pl"},
+ {"\\bpoint\\b", "pt"},
+ {"\\bsaint\\b", "st"},
+ {"\\bseven\\b", "7"},
+ {"\\bsixth\\b", "6"},
+ {"\\bsouth\\b", "s"},
+ {"\\btenth\\b", "10"},
+ {"\\bthird\\b", "3"},
+ {"\\bthree\\b", "3"},
+ {"\\beast\\b", "e"},
+ {"\\bfive\\b", "5"},
+ {"\\bfour\\b", "4"},
+ {"\\blane\\b", "ln"},
+ {"\\bnine\\b", "9"},
+ {"\\broad\\b", "rd"},
+ {"\\bwest\\b", "w"},
{"\\bh\\s+k\\b", "hk"},
+ {"\\bnth\\b", "n"},
+ {"\\bone\\b", "1"},
+ {"\\bsix\\b", "6"},
+ {"\\bsth\\b", "s"},
+ {"\\bten\\b", "10"},
+ {"\\btwo\\b", "2"},
};
const Rule kRules_ID[] = {
{"\\bspecial\\s+region\\s+of\\s+yogyakarta\\b", "yo"},
{"\\bnanggroe\\s+aceh\\s+darussalam\\b", "ac"},
- {"\\bnaggroe\\s+aceh\\s+darussalam\\b", "ac"},
{"\\bbangka\\s+belitung\\s+islands\\b", "bb"},
+ {"\\bnaggroe\\s+aceh\\s+darussalam\\b", "ac"},
{"\\bspecial\\s+region\\s+of\\s+papua\\b", "pa"},
{"\\bspecial\\s+region\\s+of\\s+aceh\\b", "ac"},
{"\\bcentral\\s+kalimantan\\b", "kt"},
@@ -1715,319 +1741,336 @@ const Rule kRules_ID[] = {
{"\\bjakarta\\s+utara\\b", "jk"},
{"\\bcentral\\s+java\\b", "jt"},
{"\\briau\\s+islands\\b", "kr"},
- {"\\bjawa\\s+tengah\\b", "jt"},
{"\\bdki\\s+jakarta\\b", "jk"},
+ {"\\bjawa\\s+tengah\\b", "jt"},
{"\\byogyakarta\\b", "yo"},
{"\\bgorontalo\\b", "go"},
{"\\bindonesia\\b", "id"},
- {"\\bnational\\b", "nasional"},
{"\\bbengkulu\\b", "be"},
- {"\\bselatan\\b", "s"},
+ {"\\bnational\\b", "nasional"},
{"\\bjakarta\\b", "jk"},
{"\\blampung\\b", "la"},
+ {"\\bselatan\\b", "s"},
{"\\bbanten\\b", "bt"},
{"\\bmaluku\\b", "ma"},
{"\\bnumber\\b", "#"},
- {"\\bnorth\\b", "n"},
- {"\\butara\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\btimur\\b", "e"},
{"\\bbarat\\b", "w"},
- {"\\bxviii\\b", "18"},
+ {"\\bblock\\b", "blk"},
{"\\bjalan\\b", "jl"},
{"\\bjambi\\b", "ja"},
+ {"\\bnorth\\b", "n"},
{"\\bpapua\\b", "pa"},
- {"\\bblock\\b", "blk"},
+ {"\\bsouth\\b", "s"},
+ {"\\btimur\\b", "e"},
+ {"\\butara\\b", "n"},
+ {"\\bxviii\\b", "18"},
+ {"\\baceh\\b", "ac"},
+ {"\\bbali\\b", "ba"},
+ {"\\bblk\\.\\b", "blk"},
+ {"\\bblok\\b", "blk"},
{"\\beast\\b", "e"},
- {"\\bwest\\b", "w"},
+ {"\\bjln\\.\\b", "jl"},
+ {"\\briau\\b", "ri"},
+ {"\\broad\\b", "rd"},
{"\\bviii\\b", "8"},
+ {"\\bwest\\b", "w"},
{"\\bxiii\\b", "13"},
{"\\bxvii\\b", "17"},
- {"\\bjln\\.\\b", "jl"},
- {"\\broad\\b", "rd"},
- {"\\baceh\\b", "ac"},
- {"\\bbali\\b", "ba"},
- {"\\briau\\b", "ri"},
- {"\\bblok\\b", "blk"},
- {"\\bblk\\.\\b", "blk"},
{"\\biii\\b", "3"},
+ {"\\bjl\\.\\b", "jl"},
+ {"\\bjln\\b", "jl"},
+ {"\\bno\\.\\b", "#"},
+ {"\\bnum\\b", "#"},
{"\\bvii\\b", "7"},
{"\\bxii\\b", "12"},
{"\\bxiv\\b", "14"},
- {"\\bxvi\\b", "16"},
{"\\bxix\\b", "19"},
- {"\\bjl\\.\\b", "jl"},
- {"\\bjln\\b", "jl"},
- {"\\bnum\\b", "#"},
- {"\\bno\\.\\b", "#"},
+ {"\\bxvi\\b", "16"},
+ {"\\b10\\b", "x"},
{"\\bii\\b", "2"},
{"\\biv\\b", "4"},
- {"\\bvi\\b", "6"},
{"\\bix\\b", "9"},
- {"\\b10\\b", "x"},
- {"\\b11\\b", "xi"},
- {"\\b15\\b", "xv"},
- {"\\b20\\b", "xx"},
{"\\bno\\b", "#"},
+ {"\\bvi\\b", "6"},
+ {"\\bxi\\b", "11"},
+ {"\\bxv\\b", "15"},
+ {"\\bxx\\b", "20"},
{"\\bi\\b", "1"},
{"\\bv\\b", "5"},
};
const Rule kRules_IE[] = {
- {"\\broscommon\\b", "rn"}, {"\\btipperary\\b", "ty"},
- {"\\bwaterford\\b", "wd"}, {"\\bwestmeath\\b", "wh"},
- {"\\bkilkenny\\b", "kk"}, {"\\blimerick\\b", "lk"},
- {"\\blongford\\b", "ld"}, {"\\bmonaghan\\b", "mn"},
- {"\\bterrace\\b", "tce"}, {"\\bdonegal\\b", "dl"},
- {"\\bkildare\\b", "ke"}, {"\\bleitrim\\b", "lm"},
- {"\\bwexford\\b", "wx"}, {"\\bwicklow\\b", "ww"},
- {"\\bireland\\b", "ie"}, {"\\bavenue\\b", "ave"},
- {"\\bcenter\\b", "cntr"}, {"\\bstreet\\b", "st"},
- {"\\bcounty\\b", "co"}, {"\\bcarlow\\b", "cw"},
- {"\\bdublin\\b", "d"}, {"\\bgalway\\b", "g"},
- {"\\blaoise\\b", "ls"}, {"\\boffaly\\b", "oy"},
- {"\\bnorth\\b", "n"}, {"\\bsouth\\b", "s"},
- {"\\bsaint\\b", "st"}, {"\\bcourt\\b", "ct"},
- {"\\bdrive\\b", "dr"}, {"\\bplace\\b", "pl"},
- {"\\bcavan\\b", "cn"}, {"\\bclare\\b", "ce"},
- {"\\bkerry\\b", "ky"}, {"\\blaois\\b", "ls"},
- {"\\blouth\\b", "lh"}, {"\\bmeath\\b", "mh"},
- {"\\bsligo\\b", "so"}, {"\\beast\\b", "e"},
- {"\\bwest\\b", "w"}, {"\\blane\\b", "ln"},
- {"\\broad\\b", "rd"}, {"\\bwalk\\b", "wk"},
- {"\\byard\\b", "yd"}, {"\\bcork\\b", "co"},
- {"\\bmayo\\b", "mo"}, {"\\bway\\b", "wy"},
- {"\\bdn\\b", "d"}, {"\\bta\\b", "ty"},
- {"\\bgy\\b", "g"}, {"\\bck\\b", "co"},
+ {"\\broscommon\\b", "rn"},
+ {"\\btipperary\\b", "ta"},
+ {"\\bwaterford\\b", "wd"},
+ {"\\bwestmeath\\b", "wh"},
+ {"\\bkilkenny\\b", "kk"},
+ {"\\blimerick\\b", "lk"},
+ {"\\blongford\\b", "ld"},
+ {"\\bmonaghan\\b", "mn"},
+ {"\\bdonegal\\b", "dl"},
+ {"\\bireland\\b", "ie"},
+ {"\\bkildare\\b", "ke"},
+ {"\\bleitrim\\b", "lm"},
+ {"\\bterrace\\b", "tce"},
+ {"\\bwexford\\b", "wx"},
+ {"\\bwicklow\\b", "ww"},
+ {"\\bavenue\\b", "ave"},
+ {"\\bcarlow\\b", "cw"},
+ {"\\bcenter\\b", "cntr"},
+ {"\\bcounty\\b", "ck"},
+ {"\\bdublin\\b", "d"},
+ {"\\bgalway\\b", "g"},
+ {"\\blaoise\\b", "ls"},
+ {"\\boffaly\\b", "oy"},
+ {"\\bstreet\\b", "st"},
+ {"\\bcavan\\b", "cn"},
+ {"\\bclare\\b", "ce"},
+ {"\\bcourt\\b", "ct"},
+ {"\\bdrive\\b", "dr"},
+ {"\\bkerry\\b", "ky"},
+ {"\\blaois\\b", "ls"},
+ {"\\blouth\\b", "lh"},
+ {"\\bmeath\\b", "mh"},
+ {"\\bnorth\\b", "n"},
+ {"\\bplace\\b", "pl"},
+ {"\\bsaint\\b", "st"},
+ {"\\bsligo\\b", "so"},
+ {"\\bsouth\\b", "s"},
+ {"\\bcork\\b", "ck"},
+ {"\\beast\\b", "e"},
+ {"\\blane\\b", "ln"},
+ {"\\bmayo\\b", "mo"},
+ {"\\broad\\b", "rd"},
+ {"\\bwalk\\b", "wk"},
+ {"\\bwest\\b", "w"},
+ {"\\byard\\b", "yd"},
+ {"\\bway\\b", "wy"},
+ {"\\bco\\b", "ck"},
+ {"\\bdn\\b", "d"},
+ {"\\bgy\\b", "g"},
+ {"\\bty\\b", "ta"},
};
const Rule kRules_IN[] = {
{"\\bthiruvananthapuram\\b", "tvpm"},
{"\\bazimabad\\s+kusumpur\\b", "patna"},
- {"\\btiruvananthapuram\\b", "tvpm"},
{"\\bjammu\\s+and\\s+kashmir\\b", "j&k"},
+ {"\\btiruvananthapuram\\b", "tvpm"},
{"\\bchandigarh\\s+city\\b", "ch"},
{"\\bjammu\\s+\\&\\s+kashmir\\b", "j&k"},
{"\\bgovt\\s+of\\s+india\\b", "goi"},
{"\\binternational\\b", "intl"},
{"\\bvisakhapatnam\\b", "vskp"},
- {"\\bchikmagaluru\\b", "chicmagalur"},
{"\\bchickmagalur\\b", "chicmagalur"},
- {"\\bpataliputra\\b", "patna"},
+ {"\\bchikmagaluru\\b", "chicmagalur"},
{"\\bchikmagalur\\b", "chicmagalur"},
- {"\\branga\\s+reddy\\b", "rangareddi"},
{"\\bcross\\-roads\\b", "xrd"},
- {"\\bgovernment\\b", "goi"},
- {"\\buniversity\\b", "uni"},
- {"\\bpatliputra\\b", "patna"},
- {"\\bvijayawada\\b", "bza"},
+ {"\\bpataliputra\\b", "patna"},
+ {"\\branga\\s+reddy\\b", "rangareddi"},
{"\\bchandigarh\\b", "ch"},
{"\\bcross\\-road\\b", "xrd"},
{"\\bcrossroads\\b", "xrd"},
- {"\\bcrossroad\\b", "xrd"},
+ {"\\bgovernment\\b", "goi"},
+ {"\\bpatliputra\\b", "patna"},
+ {"\\buniversity\\b", "uni"},
+ {"\\bvijayawada\\b", "bza"},
+ {"\\bahmedabad\\b", "ahd"},
{"\\bbangalore\\b", "blr"},
{"\\bbengaluru\\b", "blr"},
- {"\\bhyderabad\\b", "hyd"},
- {"\\bahmedabad\\b", "ahd"},
- {"\\bvijaywada\\b", "bza"},
{"\\bchar\\-rast\\b", "chaurah"},
{"\\bchaurasta\\b", "chaurah"},
{"\\bchourasta\\b", "chaurah"},
+ {"\\bcrossroad\\b", "xrd"},
+ {"\\bhyderabad\\b", "hyd"},
{"\\bi\\.n\\.d\\.i\\.a\\b", "in"},
- {"\\bcrossrds\\b", "xrd"},
+ {"\\bvijaywada\\b", "bza"},
{"\\bcalcutta\\b", "kol"},
- {"\\bkolkatta\\b", "kol"},
- {"\\bvaranasi\\b", "benaras"},
- {"\\bjunction\\b", "jn."},
- {"\\bcrossing\\b", "xrd"},
- {"\\bchowrast\\b", "chaurah"},
{"\\bchourast\\b", "chaurah"},
- {"\\bseventh\\b", "7"},
+ {"\\bchowrast\\b", "chaurah"},
+ {"\\bcrossing\\b", "xrd"},
+ {"\\bcrossrds\\b", "xrd"},
+ {"\\bjunction\\b", "jn."},
+ {"\\bkolkatta\\b", "kol"},
+ {"\\bvaranasi\\b", "banaras"},
+ {"\\bamdavad\\b", "ahd"},
+ {"\\bbenaras\\b", "banaras"},
+ {"\\bchennai\\b", "che"},
{"\\bcollege\\b", "clg"},
+ {"\\bcrossrd\\b", "xrd"},
{"\\bgateway\\b", "gtwy"},
{"\\bheights\\b", "hts"},
- {"\\bcrossrd\\b", "xrd"},
- {"\\bx\\s+roads\\b", "xrd"},
+ {"\\bkeralam\\b", "kl"},
{"\\bkolkata\\b", "kol"},
{"\\bkolkota\\b", "kol"},
- {"\\bchennai\\b", "che"},
- {"\\bamdavad\\b", "ahd"},
- {"\\bbanaras\\b", "benaras"},
- {"\\bkeralam\\b", "kl"},
+ {"\\bseventh\\b", "7"},
{"\\bvruttha\\b", "cir."},
- {"\\bsecond\\b", "2"},
- {"\\bfourth\\b", "4"},
+ {"\\bx\\s+roads\\b", "xrd"},
+ {"\\bbombay\\b", "bom"},
+ {"\\bcenter\\b", "cen"},
+ {"\\bcentre\\b", "cen"},
+ {"\\bchowdi\\b", "chok"},
+ {"\\bcircle\\b", "cir."},
{"\\beighth\\b", "8"},
- {"\\bcentre\\b", "ctr"},
- {"\\bcenter\\b", "ctr"},
{"\\bforest\\b", "frst"},
+ {"\\bfourth\\b", "4"},
{"\\bgarden\\b", "gdn"},
- {"\\bgatway\\b", "gtwy"},
{"\\bgatewy\\b", "gtwy"},
+ {"\\bgatway\\b", "gtwy"},
{"\\bheight\\b", "hts"},
+ {"\\bkavala\\b", "jn."},
+ {"\\bkerala\\b", "kl"},
+ {"\\bmadras\\b", "che"},
+ {"\\bmumbai\\b", "bom"},
+ {"\\bnumber\\b", "#"},
+ {"\\braasta\\b", "rasta"},
+ {"\\bsecond\\b", "2"},
+ {"\\bstreet\\b", "st"},
{"\\bx\\s+road\\b", "xrd"},
{"\\bxroads\\b", "xrd"},
- {"\\bstreet\\b", "st"},
- {"\\braasta\\b", "rasta"},
- {"\\bnumber\\b", "#"},
- {"\\bmumbai\\b", "bom"},
- {"\\bbombay\\b", "bom"},
- {"\\bmadras\\b", "che"},
- {"\\bkerala\\b", "kl"},
- {"\\bchowdi\\b", "chok"},
- {"\\bcircle\\b", "cir."},
- {"\\bkavala\\b", "jn."},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bfirst\\b", "1"},
- {"\\bthird\\b", "3"},
+ {"\\bcentr\\b", "cen"},
+ {"\\bchauk\\b", "chok"},
+ {"\\bchouk\\b", "chok"},
+ {"\\bchowk\\b", "chok"},
+ {"\\bcnter\\b", "cen"},
+ {"\\bdelhi\\b", "del"},
{"\\bfifth\\b", "5"},
- {"\\bsixth\\b", "6"},
- {"\\bninth\\b", "9"},
- {"\\btenth\\b", "10"},
- {"\\bcnter\\b", "ctr"},
- {"\\bcentr\\b", "ctr"},
+ {"\\bfirst\\b", "1"},
+ {"\\bgalli\\b", "gali"},
{"\\bgardn\\b", "gdn"},
{"\\bgrden\\b", "gdn"},
{"\\bgtway\\b", "gtwy"},
- {"\\bxroad\\b", "xrd"},
- {"\\broute\\b", "rt"},
- {"\\bgalli\\b", "gali"},
- {"\\bpally\\b", "palli"},
- {"\\bdelhi\\b", "del"},
- {"\\bvizag\\b", "vskp"},
+ {"\\bindia\\b", "in"},
{"\\bj\\s+\\&\\s+k\\b", "j&k"},
- {"\\bchowk\\b", "chok"},
- {"\\bchauk\\b", "chok"},
- {"\\bchouk\\b", "chok"},
- {"\\bround\\b", "cir."},
- {"\\bnaaka\\b", "jn."},
{"\\bmukku\\b", "jn."},
- {"\\bindia\\b", "in"},
+ {"\\bnaaka\\b", "jn."},
+ {"\\bninth\\b", "9"},
+ {"\\bnorth\\b", "n"},
+ {"\\bpally\\b", "palli"},
+ {"\\bround\\b", "cir."},
+ {"\\broute\\b", "rt"},
+ {"\\bsixth\\b", "6"},
+ {"\\bsouth\\b", "s"},
+ {"\\btenth\\b", "10"},
+ {"\\bthird\\b", "3"},
+ {"\\bvizag\\b", "vskp"},
+ {"\\bxroad\\b", "xrd"},
+ {"\\bcent\\b", "cen"},
+ {"\\bcntr\\b", "cen"},
{"\\beast\\b", "e"},
- {"\\bwest\\b", "w"},
- {"\\bcntr\\b", "ctr"},
- {"\\bcent\\b", "ctr"},
+ {"\\bgarh\\b", "gad"},
{"\\bgrdn\\b", "gdn"},
- {"\\bhgts\\b", "hts"},
{"\\bhght\\b", "hts"},
- {"\\buniv\\b", "uni"},
- {"\\bxrds\\b", "xrd"},
- {"\\broad\\b", "rd"},
- {"\\bstr\\.\\b", "st"},
- {"\\bgarh\\b", "gad"},
- {"\\bpeth\\b", "pet"},
+ {"\\bhgts\\b", "hts"},
{"\\bj\\s+\\&k\\b", "j&k"},
{"\\bjct\\.\\b", "jn."},
{"\\bjnct\\b", "jn."},
- {"\\bx\\-rd\\b", "xrd"},
+ {"\\bpeth\\b", "pet"},
{"\\brnd\\.\\b", "cir."},
- {"\\bcen\\b", "ctr"},
+ {"\\broad\\b", "rd"},
+ {"\\bstr\\.\\b", "st"},
+ {"\\buniv\\b", "uni"},
+ {"\\bwest\\b", "w"},
+ {"\\bx\\-rd\\b", "xrd"},
+ {"\\bxrds\\b", "xrd"},
+ {"\\bcha\\b", "ch"},
+ {"\\bctr\\b", "cen"},
+ {"\\bmum\\b", "bom"},
+ {"\\bno\\.\\b", "#"},
+ {"\\bnum\\b", "#"},
+ {"\\brte\\b", "rt"},
{"\\bst\\.\\b", "st"},
{"\\bstr\\b", "st"},
- {"\\brte\\b", "rt"},
- {"\\bnum\\b", "#"},
- {"\\bno\\.\\b", "#"},
- {"\\bmum\\b", "bom"},
- {"\\bcha\\b", "ch"},
{"\\bno\\b", "#"},
};
const Rule kRules_IT[] = {
- {"\\bfriuli\\s+venezia\\s+giulia\\b", "36"},
{"\\bbarletta\\s+andria\\s+trani\\b", "bt"},
+ {"\\bfriuli\\s+venezia\\s+giulia\\b", "36"},
{"\\bverbano\\s+cusio\\s+ossola\\b", "vb"},
{"\\btrentino\\s+alto\\s+adige\\b", "32"},
{"\\bstrada\\s+provinciale\\b", "sp"},
- {"\\btrentino\\s+sudtirol\\b", "32"},
{"\\bcarbonia\\s+iglesias\\b", "ci"},
- {"\\bventiquattresimo\\b", "24"},
+ {"\\btrentino\\s+sudtirol\\b", "32"},
{"\\bstrada\\s+regionale\\b", "sr"},
- {"\\bquattordicesimo\\b", "14"},
+ {"\\bventiquattresimo\\b", "24"},
{"\\bdiciassettesimo\\b", "17"},
- {"\\bventicinquesimo\\b", "25"},
- {"\\bstrada\\s+comunale\\b", "sc"},
{"\\bmedio\\s+campidano\\b", "vs"},
{"\\bmonza\\s+e\\s+brianza\\b", "mb"},
{"\\bpesaro\\s+e\\s+urbino\\b", "pu"},
+ {"\\bquattordicesimo\\b", "14"},
{"\\breggio\\s+calabria\\b", "rc"},
+ {"\\bstrada\\s+comunale\\b", "sc"},
+ {"\\bventicinquesimo\\b", "25"},
{"\\bdiciannovesimo\\b", "19"},
- {"\\bventisettesimo\\b", "27"},
- {"\\bstrada\\s+statali\\b", "ss"},
{"\\bemilia\\s+romagna\\b", "45"},
+ {"\\bstrada\\s+statali\\b", "ss"},
{"\\bvallee\\s+d\\s+aoste\\b", "23"},
- {"\\bventitreesimo\\b", "23"},
- {"\\bventinovesimo\\b", "29"},
- {"\\bvalle\\s+d\\s+aosta\\b", "23"},
+ {"\\bventisettesimo\\b", "27"},
{"\\bascoli\\s+piceno\\b", "ap"},
{"\\bcaltanissetta\\b", "cl"},
{"\\bmassa\\s+carrara\\b", "ms"},
{"\\breggio\\s+emilia\\b", "re"},
+ {"\\bvalle\\s+d\\s+aosta\\b", "23"},
+ {"\\bventinovesimo\\b", "29"},
+ {"\\bventitreesimo\\b", "23"},
{"\\bvibo\\s+valentia\\b", "vv"},
- {"\\bventiquattro\\b", "24"},
- {"\\bquindicesimo\\b", "xv"},
{"\\bdiciottesimo\\b", "18"},
- {"\\bventiduesimo\\b", "22"},
- {"\\bventottesimo\\b", "28"},
{"\\bforli\\s+cesena\\b", "fc"},
{"\\bolbia\\s+tempio\\b", "ot"},
- {"\\bquattordici\\b", "14"},
+ {"\\bquindicesimo\\b", "15"},
+ {"\\bventiduesimo\\b", "22"},
+ {"\\bventiquattro\\b", "24"},
+ {"\\bventottesimo\\b", "28"},
+ {"\\balessandria\\b", ""},
{"\\bdiciassette\\b", "17"},
- {"\\bventicinque\\b", "25"},
+ {"\\bquattordici\\b", "14"},
{"\\btredicesimo\\b", "13"},
- {"\\bventunesimo\\b", "21"},
- {"\\bventisesimo\\b", "26"},
{"\\bvalle\\s+aosta\\b", "23"},
- {"\\balessandria\\b", ""},
+ {"\\bventicinque\\b", "25"},
+ {"\\bventisesimo\\b", "26"},
+ {"\\bventunesimo\\b", "21"},
+ {"\\bbasilicata\\b", "77"},
+ {"\\bcampobasso\\b", "cb"},
{"\\bdiciannove\\b", "19"},
- {"\\bventisette\\b", "27"},
- {"\\bundicesimo\\b", "xi"},
{"\\bdodicesimo\\b", "12"},
+ {"\\breggimento\\b", "rgt"},
{"\\bsedicesimo\\b", "16"},
{"\\btrentesimo\\b", "30"},
- {"\\breggimento\\b", "rgt"},
- {"\\bbasilicata\\b", "77"},
- {"\\bcampobasso\\b", "cb"},
- {"\\bventinove\\b", "29"},
- {"\\bventesimo\\b", "20"},
- {"\\blombardia\\b", "25"},
+ {"\\bundicesimo\\b", "11"},
+ {"\\bventisette\\b", "27"},
{"\\bagrigento\\b", "ag"},
{"\\bbenevento\\b", "bn"},
{"\\bcatanzaro\\b", "cz"},
{"\\bfrosinone\\b", "fr"},
{"\\bla\\s+spezia\\b", "sp"},
+ {"\\blombardia\\b", "25"},
{"\\bogliastra\\b", "og"},
{"\\bpordenone\\b", "pn"},
- {"\\bquindici\\b", "xv"},
- {"\\bdiciotto\\b", "18"},
- {"\\bventidue\\b", "22"},
- {"\\bventitre\\b", "23"},
- {"\\bventisei\\b", "26"},
- {"\\bventotto\\b", "28"},
- {"\\btraversa\\b", "trav"},
- {"\\bcalabria\\b", "78"},
- {"\\bcampania\\b", "72"},
- {"\\bpiemonte\\b", "21"},
- {"\\bsardegna\\b", "88"},
+ {"\\bventesimo\\b", "20"},
+ {"\\bventinove\\b", "29"},
{"\\bavellino\\b", "av"},
{"\\bbrindisi\\b", "br"},
{"\\bcagliari\\b", "ca"},
+ {"\\bcalabria\\b", "78"},
+ {"\\bcampania\\b", "72"},
+ {"\\bdiciotto\\b", "18"},
{"\\bgrosseto\\b", "gr"},
{"\\bl\\s+aquila\\b", "aq"},
{"\\bmacerata\\b", "mc"},
{"\\boristano\\b", "or"},
{"\\bpiacenza\\b", "pc"},
+ {"\\bpiemonte\\b", "21"},
+ {"\\bquindici\\b", "15"},
+ {"\\bsardegna\\b", "88"},
{"\\bsiracusa\\b", "sr"},
+ {"\\btraversa\\b", "trav"},
+ {"\\bventidue\\b", "22"},
+ {"\\bventisei\\b", "26"},
+ {"\\bventitre\\b", "23"},
+ {"\\bventotto\\b", "28"},
{"\\bvercelli\\b", "vc"},
- {"\\bquattro\\b", "4"},
- {"\\btredici\\b", "13"},
- {"\\bventuno\\b", "21"},
- {"\\bsecondo\\b", "2"},
- {"\\bsettimo\\b", "7"},
{"\\babruzzo\\b", "65"},
- {"\\bliguria\\b", "42"},
- {"\\bsicilia\\b", "82"},
- {"\\btoscana\\b", "52"},
{"\\bbelluno\\b", "bl"},
{"\\bbergamo\\b", "bg"},
{"\\bbologna\\b", "bo"},
@@ -2043,6 +2086,7 @@ const Rule kRules_IT[] = {
{"\\bgorizia\\b", "go"},
{"\\bimperia\\b", "im"},
{"\\bisernia\\b", "is"},
+ {"\\bliguria\\b", "42"},
{"\\blivorno\\b", "li"},
{"\\bmantova\\b", "mn"},
{"\\bmessina\\b", "me"},
@@ -2051,180 +2095,187 @@ const Rule kRules_IT[] = {
{"\\bpescara\\b", "pe"},
{"\\bpistoia\\b", "pt"},
{"\\bpotenza\\b", "pz"},
+ {"\\bquattro\\b", "4"},
{"\\bravenna\\b", "ra"},
{"\\bsalerno\\b", "sa"},
{"\\bsassari\\b", "ss"},
+ {"\\bsecondo\\b", "2"},
+ {"\\bsettimo\\b", "7"},
+ {"\\bsicilia\\b", "82"},
{"\\bsondrio\\b", "so"},
{"\\btaranto\\b", "ta"},
+ {"\\btoscana\\b", "52"},
{"\\btrapani\\b", "tp"},
+ {"\\btredici\\b", "13"},
{"\\btreviso\\b", "tv"},
{"\\btrieste\\b", "ts"},
{"\\bvenezia\\b", "ve"},
+ {"\\bventuno\\b", "21"},
{"\\bvicenza\\b", "6"},
{"\\bviterbo\\b", "vt"},
- {"\\bxxviii\\b", "28"},
- {"\\bcinque\\b", "5"},
- {"\\bundici\\b", "xi"},
- {"\\bdodici\\b", "12"},
- {"\\bsedici\\b", "16"},
- {"\\btrenta\\b", "30"},
- {"\\bquarto\\b", "4"},
- {"\\bquinto\\b", "5"},
- {"\\bottavo\\b", "8"},
- {"\\bdecimo\\b", "x"},
- {"\\bmarche\\b", "57"},
- {"\\bmolise\\b", "67"},
- {"\\bpuglia\\b", "75"},
- {"\\bumbria\\b", "55"},
- {"\\bveneto\\b", "34"},
{"\\bancona\\b", "an"},
{"\\barezzo\\b", "ar"},
{"\\bbiella\\b", "bi"},
{"\\bchieti\\b", "ch"},
+ {"\\bcinque\\b", "5"},
+ {"\\bdecimo\\b", "x"},
+ {"\\bdodici\\b", "12"},
{"\\bfoggia\\b", "fg"},
{"\\bgenova\\b", "ge"},
+ {"\\bitalia\\b", "it"},
{"\\blatina\\b", "lt"},
+ {"\\bmarche\\b", "57"},
{"\\bmatera\\b", "mt"},
{"\\bmilano\\b", "mi"},
{"\\bmodena\\b", "mo"},
+ {"\\bmolise\\b", "67"},
{"\\bnapoli\\b", "na"},
{"\\bnovara\\b", "no"},
+ {"\\bottavo\\b", "8"},
{"\\bpadova\\b", "pd"},
+ {"\\bpuglia\\b", "75"},
+ {"\\bquarto\\b", "4"},
+ {"\\bquinto\\b", "5"},
{"\\bragusa\\b", "rg"},
{"\\brimini\\b", "rn"},
{"\\brovigo\\b", "ro"},
{"\\bsavona\\b", "sv"},
+ {"\\bsedici\\b", "16"},
{"\\bteramo\\b", "te"},
{"\\btorino\\b", "to"},
+ {"\\btrenta\\b", "30"},
{"\\btrento\\b", "tn"},
+ {"\\bumbria\\b", "55"},
+ {"\\bundici\\b", "11"},
{"\\bvarese\\b", "va"},
+ {"\\bveneto\\b", "34"},
{"\\bverona\\b", "vr"},
- {"\\bitalia\\b", "it"},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bovest\\b", "o"},
- {"\\bxviii\\b", "18"},
- {"\\bxxiii\\b", "23"},
- {"\\bxxvii\\b", "27"},
- {"\\bsette\\b", "7"},
- {"\\bdieci\\b", "x"},
- {"\\bventi\\b", "20"},
- {"\\bprimo\\b", ""},
- {"\\bterzo\\b", "3"},
- {"\\bsesto\\b", "6"},
- {"\\bdallo\\b", ""},
- {"\\bdello\\b", ""},
- {"\\bnello\\b", ""},
- {"\\bsullo\\b", ""},
- {"\\bdagli\\b", ""},
- {"\\bdegli\\b", ""},
- {"\\bnegli\\b", ""},
- {"\\bsugli\\b", ""},
- {"\\bdalla\\b", ""},
- {"\\bdella\\b", ""},
- {"\\bnella\\b", ""},
- {"\\bsulla\\b", ""},
- {"\\bdalle\\b", ""},
- {"\\bdelle\\b", ""},
- {"\\bnelle\\b", ""},
- {"\\bsulle\\b", ""},
- {"\\blazio\\b", "62"},
+ {"\\bxxviii\\b", "28"},
{"\\baosta\\b", "ao"},
{"\\baoste\\b", "ao"},
{"\\bbozen\\b", "bz"},
{"\\bcuneo\\b", "cn"},
+ {"\\bdagli\\b", ""},
+ {"\\bdalla\\b", ""},
+ {"\\bdalle\\b", ""},
+ {"\\bdallo\\b", ""},
+ {"\\bdegli\\b", ""},
+ {"\\bdella\\b", ""},
+ {"\\bdelle\\b", ""},
+ {"\\bdello\\b", ""},
+ {"\\bdieci\\b", "x"},
{"\\bfermo\\b", "fm"},
+ {"\\bitaly\\b", "it"},
+ {"\\blazio\\b", "62"},
{"\\blecce\\b", ""},
{"\\blecco\\b", "lc"},
{"\\blucca\\b", "lu"},
+ {"\\bnegli\\b", ""},
+ {"\\bnella\\b", ""},
+ {"\\bnelle\\b", ""},
+ {"\\bnello\\b", ""},
+ {"\\bnorth\\b", "n"},
{"\\bnuoro\\b", "nu"},
+ {"\\bovest\\b", "o"},
{"\\bparma\\b", "pr"},
{"\\bpavia\\b", "pv"},
{"\\bprato\\b", "po"},
+ {"\\bprimo\\b", ""},
{"\\brieti\\b", "ri"},
+ {"\\bsesto\\b", "6"},
+ {"\\bsette\\b", "7"},
{"\\bsiena\\b", "si"},
+ {"\\bsouth\\b", "s"},
+ {"\\bsugli\\b", ""},
+ {"\\bsulla\\b", ""},
+ {"\\bsulle\\b", ""},
+ {"\\bsullo\\b", ""},
{"\\bterni\\b", "tr"},
+ {"\\bterzo\\b", "3"},
{"\\budine\\b", "ud"},
- {"\\bitaly\\b", "it"},
- {"\\bnord\\b", "n"},
- {"\\beast\\b", "e"},
- {"\\bwest\\b", "o"},
- {"\\bviii\\b", "8"},
- {"\\bxiii\\b", "13"},
- {"\\bxvii\\b", "17"},
- {"\\bxxii\\b", "22"},
- {"\\bxxiv\\b", "24"},
- {"\\bxxvi\\b", "26"},
- {"\\bxxix\\b", "29"},
- {"\\botto\\b", "8"},
- {"\\bnove\\b", "9"},
- {"\\bnono\\b", "9"},
- {"\\ballo\\b", ""},
- {"\\bdall\\b", ""},
- {"\\bdell\\b", ""},
- {"\\bnell\\b", ""},
- {"\\bsull\\b", ""},
+ {"\\bventi\\b", "20"},
+ {"\\bxviii\\b", "18"},
+ {"\\bxxiii\\b", "23"},
+ {"\\bxxvii\\b", "27"},
{"\\bagli\\b", ""},
{"\\balla\\b", ""},
{"\\balle\\b", ""},
+ {"\\ballo\\b", ""},
{"\\basti\\b", "at"},
{"\\bbari\\b", "ba"},
{"\\bcomo\\b", "co"},
+ {"\\bdall\\b", ""},
+ {"\\bdell\\b", ""},
+ {"\\beast\\b", "e"},
{"\\benna\\b", ""},
{"\\blodi\\b", ""},
+ {"\\bnell\\b", ""},
+ {"\\bnono\\b", "9"},
+ {"\\bnord\\b", "n"},
+ {"\\bnove\\b", "9"},
+ {"\\botto\\b", "8"},
{"\\bpisa\\b", "pi"},
{"\\broma\\b", "rm"},
- {"\\bsud\\b", "s"},
+ {"\\bsull\\b", ""},
+ {"\\bviii\\b", "8"},
+ {"\\bwest\\b", "o"},
+ {"\\bxiii\\b", "13"},
+ {"\\bxvii\\b", "17"},
+ {"\\bxxii\\b", "22"},
+ {"\\bxxiv\\b", "24"},
+ {"\\bxxix\\b", "29"},
+ {"\\bxxvi\\b", "26"},
+ {"\\ball\\b", ""},
+ {"\\bdai\\b", ""},
+ {"\\bdal\\b", ""},
+ {"\\bdei\\b", ""},
+ {"\\bdel\\b", ""},
+ {"\\bdue\\b", "2"},
{"\\best\\b", "e"},
+ {"\\bgli\\b", ""},
{"\\biii\\b", "3"},
+ {"\\bles\\b", ""},
+ {"\\bnei\\b", ""},
+ {"\\bnel\\b", ""},
+ {"\\bsei\\b", "6"},
+ {"\\bsud\\b", "s"},
+ {"\\bsui\\b", ""},
+ {"\\bsul\\b", ""},
+ {"\\btre\\b", "3"},
+ {"\\buno\\b", ""},
{"\\bvii\\b", "7"},
{"\\bxii\\b", "12"},
{"\\bxiv\\b", "14"},
- {"\\bxvi\\b", "16"},
{"\\bxix\\b", "19"},
+ {"\\bxvi\\b", "16"},
{"\\bxxi\\b", "21"},
{"\\bxxv\\b", "25"},
{"\\bxxx\\b", "30"},
- {"\\buno\\b", ""},
- {"\\bdue\\b", "2"},
- {"\\btre\\b", "3"},
- {"\\bsei\\b", "6"},
- {"\\bdal\\b", ""},
- {"\\bdel\\b", ""},
- {"\\bnel\\b", ""},
- {"\\bsul\\b", ""},
- {"\\ball\\b", ""},
- {"\\bdai\\b", ""},
- {"\\bdei\\b", ""},
- {"\\bnei\\b", ""},
- {"\\bsui\\b", ""},
- {"\\bgli\\b", ""},
- {"\\bles\\b", ""},
- {"\\bii\\b", "2"},
- {"\\biv\\b", "4"},
- {"\\bvi\\b", "6"},
- {"\\bix\\b", "9"},
{"\\b10\\b", "x"},
- {"\\b11\\b", "xi"},
- {"\\b15\\b", "xv"},
- {"\\bxx\\b", "20"},
+ {"\\bai\\b", ""},
+ {"\\bal\\b", ""},
{"\\bda\\b", ""},
{"\\bdi\\b", ""},
- {"\\bin\\b", ""},
- {"\\bsu\\b", ""},
- {"\\bal\\b", ""},
- {"\\bai\\b", ""},
+ {"\\ben\\b", ""},
+ {"\\bii\\b", "2"},
{"\\bil\\b", ""},
- {"\\blo\\b", ""},
+ {"\\bin\\b", ""},
+ {"\\biv\\b", "4"},
+ {"\\bix\\b", "9"},
{"\\bla\\b", ""},
{"\\ble\\b", ""},
- {"\\ben\\b", ""},
- {"\\bw\\b", "o"},
- {"\\bi\\b", ""},
- {"\\bv\\b", "5"},
+ {"\\blo\\b", ""},
+ {"\\bsu\\b", ""},
+ {"\\bvi\\b", "6"},
+ {"\\bxi\\b", "11"},
+ {"\\bxv\\b", "15"},
+ {"\\bxx\\b", "20"},
{"\\ba\\b", ""},
{"\\bd\\b", ""},
+ {"\\bi\\b", ""},
{"\\bl\\b", ""},
+ {"\\bv\\b", "5"},
+ {"\\bw\\b", "o"},
};
const Rule kRules_LU[] = {
@@ -2234,30 +2285,30 @@ const Rule kRules_LU[] = {
{"\\bbuederscheid\\b", "buderscheid"},
{"\\bschwebsingen\\b", "schwebsange"},
{"\\brammeldange\\b", "rameldange"},
- {"\\blexembourg\\b", "lu"},
- {"\\bcul\\-de\\-sac\\b", "cds"},
{"\\bcul\\s+de\\s+sac\\b", "cds"},
- {"\\brond\\-point\\b", "rdpt"},
+ {"\\bcul\\-de\\-sac\\b", "cds"},
{"\\bgeyershaff\\b", "geyershof"},
+ {"\\blexembourg\\b", "lu"},
{"\\bluxembourg\\b", "lu"},
- {"\\bluxemburg\\b", "lu"},
+ {"\\brond\\-point\\b", "rdpt"},
{"\\bboulevard\\b", "boul"},
{"\\bcarrefour\\b", "carref"},
{"\\bcroissant\\b", "crois"},
{"\\bdiversion\\b", "divers"},
{"\\bechangeur\\b", "ech"},
{"\\besplanade\\b", "esp"},
+ {"\\bluxemburg\\b", "lu"},
{"\\bpromenade\\b", "prom"},
- {"\\bterrasse\\b", "tsse"},
{"\\bcapellen\\b", "cap"},
- {"\\bstrasse\\b", "str"},
+ {"\\bterrasse\\b", "tsse"},
{"\\bcircuit\\b", "circt"},
{"\\bimpasse\\b", "imp"},
{"\\bplateau\\b", "plat"},
{"\\bsentier\\b", "sent"},
+ {"\\bstrasse\\b", "str"},
{"\\bavenue\\b", "av"},
- {"\\bcentre\\b", "c"},
{"\\bcenter\\b", "c"},
+ {"\\bcentre\\b", "c"},
{"\\bchemin\\b", "ch"},
{"\\bpointe\\b", "pte"},
{"\\bruelle\\b", "rle"},
@@ -2269,9 +2320,9 @@ const Rule kRules_LU[] = {
{"\\bespl\\b", "esp"},
{"\\bave\\b", "av"},
{"\\bctr\\b", "c"},
- {"\\brue\\b", "r"},
{"\\bdes\\b", ""},
{"\\blux\\b", "lu"},
+ {"\\brue\\b", "r"},
{"\\bde\\b", ""},
{"\\bdu\\b", ""},
{"\\bd\\b", ""},
@@ -2286,79 +2337,79 @@ const Rule kRules_MX[] = {
{"\\bveracruz\\s+llave\\b", "veracruz"},
{"\\bprolongacion\\b", "prol"},
{"\\bquintana\\s+roo\\b", "qr"},
- {"\\bdiecisiete\\b", "17"},
{"\\bdiecinueve\\b", "19"},
+ {"\\bdiecisiete\\b", "17"},
{"\\bgobernador\\b", "gob"},
+ {"\\bguanajuato\\b", "gt"},
{"\\blicenciado\\b", "lic"},
{"\\bpresbitero\\b", "pbro"},
{"\\bsan\\s+isidro\\b", "s isidro"},
{"\\bseptiembre\\b", "sept"},
- {"\\bguanajuato\\b", "gt"},
- {"\\bdieciseis\\b", "16"},
{"\\bdieciocho\\b", "18"},
+ {"\\bdieciseis\\b", "16"},
{"\\bfrancisco\\b", "fco"},
{"\\bingeniero\\b", "ing"},
{"\\brepublica\\b", "rep"},
- {"\\bponiente\\b", "pte"},
- {"\\bprofesor\\b", "prof"},
{"\\barticulo\\b", "art"},
+ {"\\bguerrero\\b", "gr"},
{"\\bhacienda\\b", "hda"},
+ {"\\bponiente\\b", "pte"},
+ {"\\bprofesor\\b", "prof"},
{"\\bsan\\s+juan\\b", "s juan"},
- {"\\bguerrero\\b", "gr"},
- {"\\boriente\\b", "ote"},
- {"\\bprimera\\b", "1a"},
- {"\\bsegunda\\b", "2a"},
- {"\\btercera\\b", "3a"},
- {"\\bseptima\\b", "7a"},
- {"\\bcatorce\\b", "14"},
+ {"\\bavenida\\b", "av"},
{"\\bcaptain\\b", "cap"},
- {"\\bgeneral\\b", "gral"},
+ {"\\bcatorce\\b", "14"},
{"\\bfebrero\\b", "feb"},
- {"\\bprivada\\b", "priv"},
- {"\\bavenida\\b", "av"},
+ {"\\bgeneral\\b", "gral"},
{"\\bhidalgo\\b", "hg"},
{"\\bjalisco\\b", "ja"},
+ {"\\boriente\\b", "ote"},
+ {"\\bprimera\\b", "1a"},
+ {"\\bprivada\\b", "priv"},
+ {"\\bsegunda\\b", "2a"},
+ {"\\bseptima\\b", "7a"},
{"\\bsinaloa\\b", "si"},
+ {"\\btercera\\b", "3a"},
+ {"\\bciudad\\b", "cd"},
{"\\bcuarta\\b", "4a"},
- {"\\bquinta\\b", "5a"},
- {"\\boctava\\b", "8a"},
{"\\bcuatro\\b", "4"},
- {"\\bquince\\b", "15"},
- {"\\bveinte\\b", "20"},
{"\\bdoctor\\b", "dr"},
- {"\\bciudad\\b", "cd"},
- {"\\bpuerto\\b", "pto"},
{"\\bmexico\\b", "me"},
{"\\bmx\\s+mex\\b", "me"},
{"\\boaxaca\\b", "oa"},
+ {"\\boctava\\b", "8a"},
{"\\bpuebla\\b", "pu"},
+ {"\\bpuerto\\b", "pto"},
+ {"\\bquince\\b", "15"},
+ {"\\bquinta\\b", "5a"},
+ {"\\bveinte\\b", "20"},
+ {"\\bcinco\\b", "5"},
+ {"\\bmaria\\b", "ma"},
{"\\bnorte\\b", "nte"},
+ {"\\bnueve\\b", "9"},
{"\\boeste\\b", "pte"},
+ {"\\bq\\s+roo\\b", "qr"},
+ {"\\bsanta\\b", "sta"},
{"\\bsexta\\b", "6a"},
- {"\\bcinco\\b", "5"},
{"\\bsiete\\b", "7"},
- {"\\bnueve\\b", "9"},
{"\\btrece\\b", "13"},
- {"\\bmaria\\b", "ma"},
- {"\\bsanta\\b", "sta"},
- {"\\bq\\s+roo\\b", "qr"},
+ {"\\bdiez\\b", "10"},
+ {"\\bdoce\\b", "12"},
{"\\beste\\b", "ote"},
- {"\\btres\\b", "3"},
- {"\\bseis\\b", "6"},
{"\\bocho\\b", "8"},
- {"\\bdiez\\b", "10"},
{"\\bonce\\b", "11"},
- {"\\bdoce\\b", "12"},
- {"\\buno\\b", "1"},
+ {"\\bseis\\b", "6"},
+ {"\\btres\\b", "3"},
+ {"\\bags\\b", "ag"},
+ {"\\bdel\\b", ""},
{"\\bdos\\b", "2"},
- {"\\blos\\b", ""},
{"\\blas\\b", ""},
- {"\\bdel\\b", ""},
- {"\\bags\\b", "ag"},
+ {"\\blos\\b", ""},
{"\\bq\\s+r\\b", "qr"},
- {"\\ble\\b", ""},
- {"\\bel\\b", ""},
+ {"\\buno\\b", "1"},
{"\\bde\\b", ""},
+ {"\\bel\\b", ""},
+ {"\\ble\\b", ""},
{"\\bmx\\b", "me"},
};
@@ -2368,75 +2419,75 @@ const Rule kRules_MY[] = {
const Rule kRules_NL[] = {
{"\\bwesterhaar\\s+vriezenveensewijk\\b", "westerhaar-vriezenv wijk"},
- {"\\bnoord\\-brabant\\b", "nb"},
- {"\\bnoord\\-holland\\b", "nh"},
{"\\bnoord\\s+brabant\\b", "nb"},
{"\\bnoord\\s+holland\\b", "nh"},
- {"\\bburgemeester\\b", "burg"},
- {"\\bs\\s+gravenhage\\b", "sgravenhage"},
+ {"\\bnoord\\-brabant\\b", "nb"},
+ {"\\bnoord\\-holland\\b", "nh"},
{"\\balphen\\s+chaam\\b", "ac"},
+ {"\\bburgemeester\\b", "burg"},
{"\\bnoordbrabant\\b", "nb"},
- {"\\bzuid\\-holland\\b", "zh"},
+ {"\\bs\\s+gravenhage\\b", "sgravenhage"},
{"\\bzuid\\s+holland\\b", "zh"},
+ {"\\bzuid\\-holland\\b", "zh"},
{"\\bmonseigneur\\b", "mgr"},
+ {"\\bnetherlands\\b", "nl"},
{"\\bnordholland\\b", "nh"},
{"\\bzuidholland\\b", "zh"},
- {"\\bnetherlands\\b", "nl"},
- {"\\bnoordzijde\\b", "nz"},
{"\\bgelderland\\b", "ge"},
+ {"\\bnoordzijde\\b", "nz"},
{"\\boverijssel\\b", "ov"},
- {"\\bprofessor\\b", "prof"},
- {"\\bzuidzijde\\b", "zz"},
- {"\\boostzijde\\b", "oz"},
- {"\\bwestzijde\\b", "wz"},
- {"\\brotterdam\\b", "rt"},
{"\\bflevoland\\b", "fl"},
{"\\bfriesland\\b", "fr"},
- {"\\bgroningen\\b", "gr"},
+ {"\\bgroningen\\b", "gn"},
{"\\bnederland\\b", "nl"},
- {"\\bdominee\\b", "ds"},
- {"\\bmeester\\b", "mr"},
- {"\\bzevende\\b", "7"},
- {"\\bachtste\\b", "8"},
- {"\\bnegende\\b", "9"},
+ {"\\boostzijde\\b", "oz"},
+ {"\\bprofessor\\b", "prof"},
+ {"\\brotterdam\\b", "rt"},
+ {"\\bwestzijde\\b", "wz"},
+ {"\\bzuidzijde\\b", "zz"},
{"\\baan\\s+den\\b", "ad"},
+ {"\\bachtste\\b", "8"},
+ {"\\bdominee\\b", "ds"},
{"\\bdrenthe\\b", "dr"},
{"\\blimburg\\b", "l"},
+ {"\\bmeester\\b", "mr"},
+ {"\\bnegende\\b", "9"},
{"\\butrecht\\b", "u"},
{"\\bzeeland\\b", "z"},
+ {"\\bzevende\\b", "7"},
+ {"\\baan\\s+de\\b", "ad"},
{"\\bdoctor\\b", "dr"},
{"\\beerste\\b", "1"},
+ {"\\bstraat\\b", "str"},
{"\\btweede\\b", "2"},
{"\\bvierde\\b", "4"},
{"\\bvijfde\\b", "5"},
- {"\\bstraat\\b", "str"},
- {"\\baan\\s+de\\b", "ad"},
{"\\bderde\\b", "3"},
- {"\\bzesde\\b", "6"},
{"\\bnl\\-dr\\b", "dr"},
{"\\bnl\\-fl\\b", "fl"},
{"\\bnl\\-fr\\b", "fr"},
{"\\bnl\\-ge\\b", "ge"},
- {"\\bnl\\-gr\\b", "gr"},
+ {"\\bnl\\-gr\\b", "gn"},
{"\\bnl\\-li\\b", "l"},
{"\\bnl\\-nb\\b", "nb"},
{"\\bnl\\-nh\\b", "nh"},
{"\\bnl\\-ov\\b", "ov"},
- {"\\bnl\\-zh\\b", "zh"},
{"\\bnl\\-ut\\b", "u"},
{"\\bnl\\-ze\\b", "z"},
+ {"\\bnl\\-zh\\b", "zh"},
+ {"\\bzesde\\b", "6"},
{"\\bsint\\b", "st"},
+ {"\\ba\\s+d\\b", "ad"},
+ {"\\bgld\\b", "ge"},
{"\\bn\\s+z\\b", "nz"},
- {"\\bz\\s+z\\b", "zz"},
{"\\bo\\s+z\\b", "oz"},
{"\\bw\\s+z\\b", "wz"},
- {"\\ba\\s+d\\b", "ad"},
- {"\\bgld\\b", "ge"},
+ {"\\bz\\s+z\\b", "zz"},
{"\\bzld\\b", "z"},
{"\\bgl\\b", "ge"},
- {"\\bgn\\b", "gr"},
- {"\\bli\\b", "l"},
+ {"\\bgr\\b", "gn"},
{"\\blb\\b", "l"},
+ {"\\bli\\b", "l"},
{"\\but\\b", "u"},
{"\\bze\\b", "z"},
{"\\bzl\\b", "z"},
@@ -2449,52 +2500,68 @@ const Rule kRules_NZ[] = {
{"\\blong\\s+beach\\b", "longbeach"},
{"\\bboulevard\\b", "blvd"},
{"\\bcrescent\\b", "cres"},
+ {"\\bheights\\b", "hts"},
{"\\bhighway\\b", "hwy"},
{"\\bparkway\\b", "pkwy"},
- {"\\bheights\\b", "hts"},
{"\\bavenue\\b", "ave"},
- {"\\bstreet\\b", "st"},
- {"\\bparade\\b", "pde"},
{"\\bcommon\\b", "comm"},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bmount\\b", "mt"},
- {"\\bsaint\\b", "st"},
- {"\\bpoint\\b", "pt"},
+ {"\\bparade\\b", "pde"},
+ {"\\bstreet\\b", "st"},
{"\\bcourt\\b", "ct"},
- {"\\bplace\\b", "pl"},
{"\\bdrive\\b", "dr"},
+ {"\\bmount\\b", "mt"},
+ {"\\bnorth\\b", "n"},
+ {"\\bplace\\b", "pl"},
+ {"\\bpoint\\b", "pt"},
+ {"\\bsaint\\b", "st"},
+ {"\\bsouth\\b", "s"},
{"\\beast\\b", "e"},
- {"\\bwest\\b", "w"},
- {"\\broad\\b", "rd"},
{"\\blane\\b", "ln"},
{"\\bn\\.z\\.\\b", "nz"},
- {"\\bnth\\b", "n"},
- {"\\bsth\\b", "s"},
+ {"\\broad\\b", "rd"},
+ {"\\bwest\\b", "w"},
{"\\bmt\\.\\b", "mt"},
- {"\\bst\\.\\b", "st"},
- {"\\bpt\\.\\b", "pt"},
{"\\bn\\.z\\b", "nz"},
+ {"\\bnth\\b", "n"},
+ {"\\bpt\\.\\b", "pt"},
+ {"\\bst\\.\\b", "st"},
+ {"\\bsth\\b", "s"},
+ {"\\be\\.\\b", "e"},
{"\\bn\\.\\b", "n"},
{"\\bs\\.\\b", "s"},
- {"\\be\\.\\b", "e"},
{"\\bw\\.\\b", "w"},
};
const Rule kRules_PE[] = {
- {"\\bavenida\\b", "av"}, {"\\bperu\\b", "pe"}, {"\\blos\\b", ""},
- {"\\blas\\b", ""}, {"\\bdel\\b", ""}, {"\\ble\\b", ""},
- {"\\bel\\b", ""}, {"\\bde\\b", ""},
+ {"\\bavenida\\b", "av"},
+ {"\\bperu\\b", "pe"},
+ {"\\bdel\\b", ""},
+ {"\\blas\\b", ""},
+ {"\\blos\\b", ""},
+ {"\\bde\\b", ""},
+ {"\\bel\\b", ""},
+ {"\\ble\\b", ""},
};
const Rule kRules_PH[] = {
- {"\\bphilippines\\b", "ph"}, {"\\bboulevard\\b", "blvd"},
- {"\\bcaptain\\b", "cap"}, {"\\bgeneral\\b", "gen"},
- {"\\bstreet\\b", "st"}, {"\\bavenue\\b", "av"},
- {"\\bdoctor\\b", "dr"}, {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"}, {"\\beast\\b", "e"},
- {"\\bwest\\b", "w"}, {"\\broad\\b", "rd"},
+ {"\\bphilippines\\b", "ph"},
+ {"\\bboulevard\\b", "blvd"},
+ {"\\bextension\\b", "ext"},
+ {"\\bbarangay\\b", ""},
+ {"\\bcaptain\\b", "cap"},
+ {"\\bgeneral\\b", "gen"},
+ {"\\bavenue\\b", "av"},
+ {"\\bdoctor\\b", "dr"},
+ {"\\bstreet\\b", "st"},
+ {"\\bnorth\\b", "n"},
+ {"\\bsouth\\b", "s"},
+ {"\\bbrgy\\b", ""},
+ {"\\beast\\b", "e"},
+ {"\\bextn\\b", "ext"},
+ {"\\broad\\b", "rd"},
+ {"\\bwest\\b", "w"},
{"\\bave\\b", "av"},
+ {"\\bbgy\\b", ""},
};
const Rule kRules_PL[] = {
@@ -2513,33 +2580,33 @@ const Rule kRules_PL[] = {
{"\\bmalopolskie\\b", "mp"},
{"\\bmazowieckie\\b", "ma"},
{"\\bpomeranian\\b", "pm"},
+ {"\\blubelskie\\b", "lu"},
{"\\bmarszalek\\b", "marsz"},
{"\\bpodlaskie\\b", "pd"},
- {"\\blubelskie\\b", "lu"},
{"\\bpomorskie\\b", "pm"},
{"\\bwarminsko\\b", "wn"},
- {"\\bpoludnie\\b", "south"},
- {"\\bwschodni\\b", "w"},
- {"\\bzachodni\\b", "z"},
- {"\\bmasovian\\b", "ma"},
- {"\\bsilesian\\b", "sl"},
{"\\bkujawsko\\b", "kp"},
{"\\blubuskie\\b", "lb"},
+ {"\\bmasovian\\b", "ma"},
{"\\bopolskie\\b", "op"},
+ {"\\bpoludnie\\b", "south"},
+ {"\\bsilesian\\b", "sl"},
+ {"\\bwschodni\\b", "w"},
+ {"\\bzachodni\\b", "z"},
+ {"\\blodzkie\\b", "ld"},
{"\\bosiedle\\b", "os"},
{"\\bsilesia\\b", "sl"},
- {"\\blodzkie\\b", "ld"},
{"\\bslaskie\\b", "sl"},
- {"\\bpolnoc\\b", "north"},
- {"\\bwschod\\b", "w"},
- {"\\bzachod\\b", "z"},
{"\\blublin\\b", "lu"},
{"\\blubusz\\b", "lb"},
{"\\bpoland\\b", "pl"},
+ {"\\bpolnoc\\b", "north"},
+ {"\\bwschod\\b", "w"},
+ {"\\bzachod\\b", "z"},
{"\\bopole\\b", "op"},
{"\\beast\\b", "w"},
- {"\\bwest\\b", "z"},
{"\\blodz\\b", "ld"},
+ {"\\bwest\\b", "z"},
{"\\bwlkp\\b", "wp"},
};
@@ -2551,28 +2618,28 @@ const Rule kRules_PR[] = {
{"\\bavenida\\b", "av"},
{"\\bbulevar\\b", "blvd"},
{"\\bcamino\\b", "cm"},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bsaint\\b", "st"},
{"\\bcalle\\b", "cll"},
- {"\\bplaza\\b", "plz"},
- {"\\bpaseo\\b", "pso"},
{"\\bcourt\\b", "ct"},
- {"\\beast\\b", "e"},
- {"\\bwest\\b", "w"},
+ {"\\bnorth\\b", "n"},
+ {"\\bpaseo\\b", "pso"},
+ {"\\bplaza\\b", "plz"},
+ {"\\bsaint\\b", "st"},
+ {"\\bsouth\\b", "s"},
{"\\bave\\.\\b", "av"},
+ {"\\beast\\b", "e"},
{"\\blane\\b", "ln"},
- {"\\broad\\b", "rd"},
{"\\bp\\.r\\.\\b", "pr"},
- {"\\bnth\\b", "n"},
- {"\\bsth\\b", "s"},
- {"\\bst\\.\\b", "st"},
+ {"\\broad\\b", "rd"},
+ {"\\bwest\\b", "w"},
{"\\bave\\b", "av"},
{"\\bcam\\b", "cm"},
+ {"\\bnth\\b", "n"},
{"\\bp\\.r\\b", "pr"},
+ {"\\bst\\.\\b", "st"},
+ {"\\bsth\\b", "s"},
+ {"\\be\\.\\b", "e"},
{"\\bn\\.\\b", "n"},
{"\\bs\\.\\b", "s"},
- {"\\be\\.\\b", "e"},
{"\\bw\\.\\b", "w"},
};
@@ -2583,33 +2650,33 @@ const Rule kRules_PT[] = {
{"\\bportalegre\\b", "08"},
{"\\bvila\\s+real\\b", "15"},
{"\\bbraganca\\b", "14"},
- {"\\bsantarem\\b", "03"},
{"\\bportugal\\b", "pt"},
+ {"\\bsantarem\\b", "03"},
{"\\bcoimbra\\b", "11"},
{"\\bsetubal\\b", "04"},
+ {"\\baveiro\\b", "12"},
{"\\bdoctor\\b", "dr"},
{"\\bdoutor\\b", "dr"},
- {"\\baveiro\\b", "12"},
{"\\bguarda\\b", "10"},
{"\\bleiria\\b", "02"},
{"\\blisbon\\b", "01"},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
{"\\bbraga\\b", "17"},
{"\\bevora\\b", "07"},
+ {"\\bnorth\\b", "n"},
{"\\bporto\\b", "16"},
+ {"\\bsouth\\b", "s"},
{"\\bviseu\\b", "13"},
- {"\\bwest\\b", "w"},
{"\\bbeja\\b", "05"},
{"\\bfaro\\b", "06"},
- {"\\bsao\\b", "s"},
- {"\\bdos\\b", ""},
+ {"\\bwest\\b", "w"},
{"\\bdas\\b", ""},
- {"\\bdo\\b", ""},
- {"\\bde\\b", ""},
+ {"\\bdos\\b", ""},
+ {"\\bsao\\b", "s"},
{"\\bda\\b", ""},
- {"\\ben\\b", "n"},
+ {"\\bde\\b", ""},
+ {"\\bdo\\b", ""},
{"\\bem\\b", "m"},
+ {"\\ben\\b", "n"},
{"\\be\\b", ""},
};
@@ -2618,27 +2685,37 @@ const Rule kRules_RO[] = {
};
const Rule kRules_RU[] = {
- {"\\bĐ½Đ°Đ±ĐµÑ€ĐµĐ¶Đ½Đ°Ñ\\b", "Đ½Đ°Đ±"}, {"\\bÑ‚ĐµÑ€Ñ€Đ¸Ñ‚Đ¾Ñ€Đ¸Ñ\\b", "Ñ‚ĐµÑ€"},
- {"\\bĐ°Đ²Ñ‚Đ¾Đ´Đ¾Ñ€Đ¾Đ³Đ°\\b", "Đ°/Đ´"}, {"\\bĐ¿ĐµÑ€ĐµÑƒĐ»Đ¾Đº\\b", "Đ¿ĐµÑ€"},
- {"\\bĐ¿Ñ€Đ¾ÑĐ¿ĐµĐºÑ‚\\b", "Đ¿Ñ€"}, {"\\bĐ±ÑƒĐ»ÑŒĐ²Đ°Ñ€\\b", "б-Ñ€"},
- {"\\bĐºĐ²Đ°Ñ€Ñ‚Đ°Đ»\\b", "ĐºĐ²-Đ»"}, {"\\bĐ¿Đ»Đ¾Ñ‰Đ°Đ´ÑŒ\\b", "Đ¿Đ»"},
- {"\\bÑ€Đ¾ÑÑиÑ\\b", "ru"}, {"\\brussia\\b", "ru"},
- {"\\bĐ¿Ñ€Đ¾ĐµĐ·Đ´\\b", "Đ¿Ñ€-Đ´"}, {"\\bĐ´Đ¾Ñ€Đ¾Đ³Đ°\\b", "Đ´Đ¾Ñ€"},
- {"\\bÑˆĐ¾ÑÑе\\b", "ш"}, {"\\bĐ»Đ¸Đ½Đ¸Ñ\\b", "Đ»Đ¸Đ½"},
- {"\\bÑƒĐ»Đ¸Ñ†Đ°\\b", "ÑƒĐ»"}, {"\\bĐ±ÑƒĐ»ÑŒĐ²\\b", "б-Ñ€"},
- {"\\bĐ¿Ñ€Đ¾ÑĐ¿\\b", "Đ¿Ñ€"}, {"\\bĐ¿Ñ€\\-ĐºÑ‚\\b", "Đ¿Ñ€"},
- {"\\bÑ‚ÑƒĐ¿Đ¸Đº\\b", "Ñ‚ÑƒĐ¿"}, {"\\bĐ¿Ñ€Đ¾Ñ‚\\b", "Đ¿Ñ€"},
+ {"\\bĐ°Đ²Ñ‚Đ¾Đ´Đ¾Ñ€Đ¾Đ³Đ°\\b", "Đ°/Đ´"},
+ {"\\bĐ½Đ°Đ±ĐµÑ€ĐµĐ¶Đ½Đ°Ñ\\b", "Đ½Đ°Đ±"},
+ {"\\bÑ‚ĐµÑ€Ñ€Đ¸Ñ‚Đ¾Ñ€Đ¸Ñ\\b", "Ñ‚ĐµÑ€"},
+ {"\\bĐ¿ĐµÑ€ĐµÑƒĐ»Đ¾Đº\\b", "Đ¿ĐµÑ€"},
+ {"\\bĐ¿Ñ€Đ¾ÑĐ¿ĐµĐºÑ‚\\b", "Đ¿Ñ€"},
+ {"\\bĐ±ÑƒĐ»ÑŒĐ²Đ°Ñ€\\b", "б-Ñ€"},
+ {"\\bĐºĐ²Đ°Ñ€Ñ‚Đ°Đ»\\b", "ĐºĐ²-Đ»"},
+ {"\\bĐ¿Đ»Đ¾Ñ‰Đ°Đ´ÑŒ\\b", "Đ¿Đ»"},
+ {"\\brussia\\b", "ru"},
+ {"\\bĐ´Đ¾Ñ€Đ¾Đ³Đ°\\b", "Đ´Đ¾Ñ€"},
+ {"\\bĐ¿Ñ€Đ¾ĐµĐ·Đ´\\b", "Đ¿Ñ€-Đ´"},
+ {"\\bÑ€Đ¾ÑÑиÑ\\b", "ru"},
+ {"\\bĐ±ÑƒĐ»ÑŒĐ²\\b", "б-Ñ€"},
+ {"\\bĐ»Đ¸Đ½Đ¸Ñ\\b", "Đ»Đ¸Đ½"},
+ {"\\bĐ¿Ñ€\\-ĐºÑ‚\\b", "Đ¿Ñ€"},
+ {"\\bĐ¿Ñ€Đ¾ÑĐ¿\\b", "Đ¿Ñ€"},
+ {"\\bÑ‚ÑƒĐ¿Đ¸Đº\\b", "Ñ‚ÑƒĐ¿"},
+ {"\\bÑƒĐ»Đ¸Ñ†Đ°\\b", "ÑƒĐ»"},
+ {"\\bÑˆĐ¾ÑÑе\\b", "ш"},
+ {"\\bĐ¿Ñ€Đ¾Ñ‚\\b", "Đ¿Ñ€"},
{"\\bĐ±ÑƒĐ»\\b", "б-Ñ€"},
};
const Rule kRules_SE[] = {
{"\\bvastra\\s+goetalands\\b", "o"},
{"\\bvastra\\s+goetaland\\b", "o"},
- {"\\bvasternorrlands\\b", "y"},
{"\\boestergoetlands\\b", "e"},
- {"\\bvasternorrland\\b", "y"},
+ {"\\bvasternorrlands\\b", "y"},
{"\\boestergoetland\\b", "e"},
{"\\bvastergoetland\\b", "e"},
+ {"\\bvasternorrland\\b", "y"},
{"\\bsodermanlands\\b", "d"},
{"\\bvasterbottens\\b", "ac"},
{"\\bjoenkoepings\\b", "f"},
@@ -2662,16 +2739,16 @@ const Rule kRules_SE[] = {
{"\\bgotlands\\b", "i"},
{"\\bhallands\\b", "n"},
{"\\bjamtland\\b", "z"},
- {"\\bvarmland\\b", "s"},
{"\\boerebros\\b", "t"},
+ {"\\bvarmland\\b", "s"},
{"\\bdalarna\\b", "w"},
{"\\bgotland\\b", "i"},
{"\\bhalland\\b", "n"},
- {"\\buppsala\\b", "c"},
{"\\boerebro\\b", "t"},
{"\\bsverige\\b", "se"},
- {"\\bsoeder\\b", "s"},
+ {"\\buppsala\\b", "c"},
{"\\bkalmar\\b", "h"},
+ {"\\bsoeder\\b", "s"},
{"\\bsweden\\b", "se"},
{"\\bskane\\b", "m"},
{"\\bnorr\\b", "n"},
@@ -2692,286 +2769,305 @@ const Rule kRules_TR[] = {
const Rule kRules_US[] = {
{"\\bjoint\\s+base\\s+elmendorf\\s+richardson\\b", "jber"},
{"\\bwashington\\s+district\\s+of\\s+columbia\\b", "dc"},
- {"\\bjoint\\s+base\\s+pearl\\s+harbor\\s+hickam\\b", "jbphh"},
{"\\bfederated\\s+states\\s+of\\s+micronesia\\b", "fm"},
+ {"\\bjoint\\s+base\\s+pearl\\s+harbor\\s+hickam\\b", "jbphh"},
{"\\bnational\\s+forest\\s+development\\b", "nat for dev"},
{"\\bmartin\\s+luther\\s+king\\s+junior\\b", "mlk"},
- {"\\bnational\\s+for\\s+development\\b", "nat for dev"},
+ {"\\barmed\\s+forces\\s+middle\\s+east\\b", "ae"},
{"\\bmarine\\s+corps\\s+base\\s+hawaii\\b", "mcbh kanehoe bay"},
+ {"\\bnational\\s+for\\s+development\\b", "nat for dev"},
{"\\bnorthern\\s+mariana\\s+islands\\b", "mp"},
- {"\\barmed\\s+forces\\s+middle\\s+east\\b", "ae"},
{"\\bunited\\s+states\\s+of\\s+america\\b", "us"},
- {"\\bnat\\s+forest\\s+development\\b", "nat for dev"},
{"\\bmartin\\s+luther\\s+king\\s+jnr\\b", "mlk"},
- {"\\bmartin\\s+luther\\s+king\\s+jr\\b", "mlk"},
+ {"\\bnat\\s+forest\\s+development\\b", "nat for dev"},
{"\\barmed\\s+forces\\s+americas\\b", "aa"},
- {"\\bdistrict\\s+of\\s+columbia\\b", "dc"},
+ {"\\bmartin\\s+luther\\s+king\\s+jr\\b", "mlk"},
{"\\barmed\\s+forces\\s+pacific\\b", "ap"},
- {"\\bnat\\s+for\\s+development\\b", "nat for dev"},
- {"\\bnational\\s+forest\\s+dev\\b", "nat for dev"},
+ {"\\bdistrict\\s+of\\s+columbia\\b", "dc"},
{"\\barmed\\s+forces\\s+africa\\b", "ae"},
{"\\barmed\\s+forces\\s+canada\\b", "ae"},
{"\\barmed\\s+forces\\s+europe\\b", "ae"},
- {"\\bmartin\\s+luther\\s+king\\b", "mlk"},
+ {"\\bnat\\s+for\\s+development\\b", "nat for dev"},
+ {"\\bnational\\s+forest\\s+dev\\b", "nat for dev"},
{"\\bjoint\\s+reserve\\s+base\\b", "jrb"},
{"\\blincolns\\s+new\\s+salem\\b", "lincoln nw sl"},
+ {"\\bmartin\\s+luther\\s+king\\b", "mlk"},
{"\\bmetropolitan\\s+area\\b", ""},
{"\\bnational\\s+monument\\b", "national mo"},
- {"\\bnational\\s+for\\s+dev\\b", "nat for dev"},
- {"\\bfrancis\\s+e\\s+warren\\b", "fe warren"},
{"\\bcolorado\\s+springs\\b", "co spgs"},
{"\\bdist\\s+of\\s+columbia\\b", "dc"},
- {"\\bwashington\\s+state\\b", "wa"},
+ {"\\bfrancis\\s+e\\s+warren\\b", "fe warren"},
{"\\bmarshall\\s+islands\\b", "mh"},
+ {"\\bnational\\s+for\\s+dev\\b", "nat for dev"},
+ {"\\bwashington\\s+state\\b", "wa"},
{"\\bcharlottesville\\b", "charlottesvle"},
{"\\badministration\\b", "admn"},
- {"\\bfarm\\s+to\\s+market\\b", "fm"},
- {"\\bnat\\s+forest\\s+dev\\b", "nat for dev"},
- {"\\bforest\\s+service\\b", "frst srvc"},
- {"\\bjohn\\s+f\\s+kennedy\\b", "jfk"},
{"\\bair\\s+force\\s+base\\b", "afb"},
+ {"\\bamerican\\s+samoa\\b", "as"},
{"\\bbradford\\s+woods\\b", "bradfordwoods"},
+ {"\\bchristiansberg\\b", "christiansbrg"},
{"\\bcrawfordsville\\b", "crawfordsvlle"},
+ {"\\bfarm\\s+to\\s+market\\b", "fm"},
+ {"\\bforest\\s+service\\b", "frst srvc"},
{"\\bfredericksburg\\b", "fredericksbrg"},
{"\\bhendersonville\\b", "hendersonvlle"},
{"\\bjeffersonville\\b", "jeffersonvlle"},
- {"\\bmechanicsville\\b", "mechanicsvlle"},
- {"\\bnorthumberland\\b", "northumberlnd"},
- {"\\bsalt\\s+lake\\s+city\\b", "slc"},
- {"\\bchristiansberg\\b", "christiansbrg"},
+ {"\\bjohn\\s+f\\s+kennedy\\b", "jfk"},
{"\\blittle\\s+diomede\\b", "diomede"},
- {"\\bwashington\\s+d\\s+c\\b", "dc"},
+ {"\\bmechanicsville\\b", "mechanicsvlle"},
+ {"\\bnat\\s+forest\\s+dev\\b", "nat for dev"},
{"\\bnew\\s+york\\s+state\\b", "ny"},
{"\\bnorth\\s+carolina\\b", "nc"},
+ {"\\bnorthumberland\\b", "northumberlnd"},
+ {"\\bsalt\\s+lake\\s+city\\b", "slc"},
{"\\bsouth\\s+carolina\\b", "sc"},
{"\\bvirgin\\s+islands\\b", "vi"},
- {"\\bamerican\\s+samoa\\b", "as"},
- {"\\binternational\\b", "intl"},
+ {"\\bwashington\\s+d\\s+c\\b", "dc"},
{"\\barmy\\s+airfield\\b", "army af"},
- {"\\bnew\\s+york\\s+city\\b", "ny"},
+ {"\\binternational\\b", "intl"},
{"\\bjf\\s+kennedy\\s+ap\\b", "jfk airport"},
+ {"\\bmassachusetts\\b", "ma"},
{"\\bnational\\s+park\\b", "ntpk"},
- {"\\bwashington\\s+dc\\b", "dc"},
{"\\bnew\\s+hampshire\\b", "nh"},
- {"\\bwest\\s+virginia\\b", "wv"},
- {"\\bmassachusetts\\b", "ma"},
+ {"\\bnew\\s+york\\s+city\\b", "ny"},
{"\\bunited\\s+states\\b", "us"},
- {"\\bfrst\\s+service\\b", "frst srvc"},
- {"\\bservice\\s+road\\b", "service rd"},
+ {"\\bwashington\\s+dc\\b", "dc"},
+ {"\\bwest\\s+virginia\\b", "wv"},
{"\\bbristle\\s+cone\\b", "bristlecone"},
- {"\\bswan\\s+quarter\\b", "swanquarter"},
+ {"\\bfrst\\s+service\\b", "frst srvc"},
{"\\bminers\\s+mills\\b", "miners mill"},
{"\\bnorth\\s+dakota\\b", "nd"},
+ {"\\bpennsylvania\\b", "pa"},
{"\\brhode\\s+island\\b", "ri"},
+ {"\\bservice\\s+road\\b", "service rd"},
{"\\bsouth\\s+dakota\\b", "sd"},
- {"\\bpennsylvania\\b", "pa"},
- {"\\brural\\s+route\\b", "rr"},
- {"\\bforest\\s+srvc\\b", "frst srvc"},
+ {"\\bswan\\s+quarter\\b", "swanquarter"},
{"\\bbloomington\\b", "blmngtn"},
+ {"\\bchevy\\s+chase\\b", "chevy chs"},
+ {"\\bclutch\\s+city\\b", "houston"},
+ {"\\bconnecticut\\b", "ct"},
+ {"\\bforest\\s+srvc\\b", "frst srvc"},
{"\\bfrenchville\\b", "frnchvl"},
{"\\bgood\\s+fellow\\b", "goodfellow"},
- {"\\bclutch\\s+city\\b", "houston"},
+ {"\\bhigh\\s+bridge\\b", "highbridge"},
{"\\blos\\s+angeles\\b", "la"},
{"\\bloxahatchee\\b", "lox"},
+ {"\\bmississippi\\b", "ms"},
{"\\bobservatory\\b", "obs"},
+ {"\\bpuerto\\s+rico\\b", "pr"},
+ {"\\brural\\s+route\\b", "rr"},
{"\\bspringfield\\b", "spfld"},
{"\\byellowstone\\b", "yelwstn"},
- {"\\bchevy\\s+chase\\b", "chevy chs"},
- {"\\bhigh\\s+bridge\\b", "highbridge"},
- {"\\bpuerto\\s+rico\\b", "pr"},
- {"\\bconnecticut\\b", "ct"},
- {"\\bmississippi\\b", "ms"},
- {"\\bcrossroads\\b", "xrds"},
- {"\\bextensions\\b", "exts"},
- {"\\bplantation\\b", "plt"},
- {"\\buniversity\\b", "univ"},
- {"\\bexpressway\\b", "exp"},
- {"\\bthroughway\\b", "trwy"},
- {"\\btrafficway\\b", "trfy"},
{"\\balpen\\s+glow\\b", "alpenglow"},
{"\\bambassador\\b", "amb"},
{"\\bbernardino\\b", "bernrdno"},
{"\\bbloomfield\\b", "bloomfld"},
+ {"\\bbrownstown\\b", "brownstwn"},
+ {"\\bburlington\\b", "burlngtn"},
+ {"\\bcalifornia\\b", "ca"},
{"\\bcapistrano\\b", "capo"},
+ {"\\bchristmass\\b", "chirstmas"},
{"\\bcincinnati\\b", "cin"},
{"\\bcottonwood\\b", "ctwd"},
+ {"\\bcrossroads\\b", "xrds"},
+ {"\\bexpressway\\b", "exp"},
+ {"\\bextensions\\b", "exts"},
{"\\bfarmington\\b", "farmingtn"},
+ {"\\bnew\\s+jersey\\b", "nj"},
+ {"\\bnew\\s+mexico\\b", "nm"},
{"\\bpittsburgh\\b", "pgh"},
+ {"\\bplantation\\b", "plt"},
{"\\bprovidence\\b", "providnce"},
{"\\bsouth\\s+lake\\b", "southlake"},
- {"\\bwest\\s+point\\b", "westpoint"},
- {"\\bbrownstown\\b", "brownstwn"},
- {"\\bburlington\\b", "burlngtn"},
- {"\\bchristmass\\b", "chirstmas"},
- {"\\bnew\\s+jersey\\b", "nj"},
- {"\\bnew\\s+mexico\\b", "nm"},
- {"\\bcalifornia\\b", "ca"},
+ {"\\bthroughway\\b", "trwy"},
+ {"\\btrafficway\\b", "trfy"},
+ {"\\buniversity\\b", "univ"},
{"\\bwashington\\b", "wa"},
- {"\\bcrossroad\\b", "xrd"},
- {"\\bhighlands\\b", "hlds"},
- {"\\bjunctions\\b", "jcts"},
- {"\\bmountains\\b", "mtns"},
- {"\\bboulevard\\b", "boul"},
- {"\\bextension\\b", "ext"},
- {"\\bstravenue\\b", "stra"},
- {"\\bunderpass\\b", "upas"},
- {"\\bchair\\s+bar\\b", "chairbar"},
- {"\\btown\\s+line\\b", "t l"},
- {"\\bterritory\\b", ""},
+ {"\\bwest\\s+point\\b", "westpoint"},
{"\\bbellerose\\b", "bellrs"},
+ {"\\bboulevard\\b", "blvd"},
+ {"\\bburlingtn\\b", "burlngtn"},
+ {"\\bchair\\s+bar\\b", "chairbar"},
{"\\bchicester\\b", "chicstr"},
{"\\bcity\\s+base\\b", "cb"},
{"\\bcleveland\\b", "cleve"},
{"\\bcommunity\\b", "cmnty"},
+ {"\\bcrossroad\\b", "xrd"},
+ {"\\bextension\\b", "ext"},
{"\\bfairmount\\b", "fairmt"},
{"\\bfernandez\\b", "fdez"},
{"\\bfrancisco\\b", "fran"},
+ {"\\bhighlands\\b", "hlds"},
{"\\bho\'olehua\\b", "hoolehua"},
- {"\\blexington\\b", "lxngtn"},
- {"\\bmilwaukee\\b", "milw"},
- {"\\brichfield\\b", "richfld"},
- {"\\bwashingtn\\b", "wa"},
- {"\\bburlingtn\\b", "burlngtn"},
{"\\bhomestead\\b", "hmstd"},
+ {"\\bjunctions\\b", "jcts"},
+ {"\\blexington\\b", "lxngtn"},
{"\\blouisiana\\b", "la"},
+ {"\\bmilwaukee\\b", "milw"},
{"\\bminnesota\\b", "mn"},
+ {"\\bmountains\\b", "mtns"},
+ {"\\brichfield\\b", "richfld"},
+ {"\\bstravenue\\b", "stra"},
{"\\btennessee\\b", ""},
+ {"\\bterritory\\b", ""},
+ {"\\btown\\s+line\\b", "t l"},
+ {"\\bunderpass\\b", "upas"},
+ {"\\bwashingtn\\b", "wa"},
{"\\bwisconsin\\b", "wi"},
+ {"\\barkansas\\b", "ar"},
+ {"\\bbig\\s+bend\\b", "bg bnd"},
+ {"\\bblooming\\b", "blmng"},
+ {"\\bbullrush\\b", "bulrush"},
{"\\bcauseway\\b", "cswy"},
- {"\\bcrossrds\\b", "xrds"},
- {"\\bjunction\\b", "jt"},
- {"\\bmountain\\b", "mnt"},
- {"\\bnational\\b", "nl"},
- {"\\bparkways\\b", "pkwys"},
- {"\\bvilliage\\b", "vil"},
- {"\\bvillages\\b", "vlgs"},
+ {"\\bcolorado\\b", "co"},
+ {"\\bcottonwd\\b", "ctwd"},
{"\\bcrescent\\b", "cres"},
- {"\\bmotorway\\b", "mtwy"},
- {"\\boverpass\\b", "opas"},
- {"\\bturnpike\\b", "tpk"},
{"\\bcrossing\\b", "xing"},
- {"\\bbullrush\\b", "bulrush"},
- {"\\bmichelle\\b", "michele"},
- {"\\btownline\\b", "t l"},
+ {"\\bcrossrds\\b", "xrds"},
+ {"\\bdelaware\\b", "de"},
{"\\bdowntown\\b", ""},
- {"\\btownship\\b", "tw"},
- {"\\bcottonwd\\b", "ctwd"},
{"\\bhartford\\b", "hartfrd"},
- {"\\bla\\s+salle\\b", "lasalle"},
- {"\\bnew\\s+york\\b", "ny"},
- {"\\brichland\\b", "richlnd"},
- {"\\bbig\\s+bend\\b", "bg bnd"},
- {"\\bblooming\\b", "blmng"},
- {"\\barkansas\\b", "ar"},
- {"\\bcolorado\\b", "co"},
- {"\\bdelaware\\b", "de"},
{"\\billinois\\b", "il"},
+ {"\\bjunction\\b", "jt"},
{"\\bkentucky\\b", "ky"},
+ {"\\bla\\s+salle\\b", "lasalle"},
{"\\bmaryland\\b", "md"},
+ {"\\bmichelle\\b", "michele"},
{"\\bmichigan\\b", "mi"},
{"\\bmissouri\\b", "mo"},
+ {"\\bmotorway\\b", "mtwy"},
+ {"\\bmountain\\b", "mnt"},
+ {"\\bnational\\b", "nl"},
{"\\bnebraska\\b", "ne"},
+ {"\\bnew\\s+york\\b", "ny"},
{"\\boklahoma\\b", "ok"},
+ {"\\boverpass\\b", "opas"},
+ {"\\bparkways\\b", "pkwys"},
+ {"\\brichland\\b", "richlnd"},
+ {"\\btownline\\b", "t l"},
+ {"\\btownship\\b", "tp"},
+ {"\\bturnpike\\b", "tpk"},
+ {"\\bvillages\\b", "vlgs"},
+ {"\\bvilliage\\b", "vil"},
{"\\bvirginia\\b", "va"},
- {"\\bseventh\\b", "7"},
+ {"\\balabama\\b", "al"},
+ {"\\bamerica\\b", "us"},
+ {"\\barizona\\b", "az"},
+ {"\\bavenida\\b", "av"},
+ {"\\bcapitol\\b", "capital"},
{"\\bcausway\\b", "cswy"},
{"\\bcenters\\b", "ctrs"},
+ {"\\bcentral\\b", ""},
+ {"\\bchicago\\b", "chgo"},
{"\\bcircles\\b", "cirs"},
{"\\bcollege\\b", "clg"},
+ {"\\bcolonel\\b", "col"},
{"\\bcorners\\b", "cors"},
{"\\bcountry\\b", "cntry"},
+ {"\\bcrecent\\b", "cres"},
+ {"\\bcresent\\b", "cres"},
{"\\bcrossrd\\b", "xrd"},
+ {"\\bcrssing\\b", "xing"},
{"\\bestates\\b", "ests"},
+ {"\\bexpress\\b", "exp"},
+ {"\\bflorida\\b", "fl"},
+ {"\\bfreeway\\b", "fwy"},
{"\\bgardens\\b", "gdns"},
{"\\bgateway\\b", "gtwy"},
+ {"\\bgeorgia\\b", "ga"},
{"\\bharbors\\b", "hbrs"},
{"\\bheights\\b", "ht"},
+ {"\\bhighway\\b", "hwy"},
{"\\bhollows\\b", "hllw"},
+ {"\\bindiana\\b", "in"},
{"\\bislands\\b", "is"},
+ {"\\bjohnson\\b", "jhnsn"},
+ {"\\bjuncton\\b", "jt"},
{"\\blanding\\b", "lndg"},
{"\\bmeadows\\b", "mdws"},
{"\\bmission\\b", "msn"},
+ {"\\bmontana\\b", "mt"},
{"\\bmountin\\b", "mnt"},
{"\\borchard\\b", "orch"},
+ {"\\bparkway\\b", "pky"},
+ {"\\bpassage\\b", "psge"},
+ {"\\bphoenix\\b", "phx"},
{"\\bplaines\\b", "plns"},
+ {"\\bpotsdam\\b", "potsdm"},
{"\\bprairie\\b", "pr"},
{"\\branches\\b", "rnchs"},
{"\\branchos\\b", "rnchs"},
+ {"\\bseventh\\b", "7"},
{"\\bsprings\\b", "spg"},
{"\\bsquares\\b", "sqs"},
{"\\bstation\\b", "sta"},
- {"\\bstreets\\b", "sts"},
- {"\\bterrace\\b", "ter"},
- {"\\bvalleys\\b", "vlys"},
- {"\\bvillage\\b", "vil"},
- {"\\bhighway\\b", "hwy"},
- {"\\bexpress\\b", "exp"},
- {"\\bcrecent\\b", "cres"},
- {"\\bcresent\\b", "cres"},
- {"\\bfreeway\\b", "fwy"},
- {"\\bjuncton\\b", "jt"},
- {"\\bparkway\\b", "pky"},
- {"\\bpassage\\b", "psge"},
{"\\bstraven\\b", "stra"},
+ {"\\bstreets\\b", "sts"},
{"\\bstrvnue\\b", "stra"},
+ {"\\bterrace\\b", "ter"},
+ {"\\btownshp\\b", "tp"},
{"\\btunnels\\b", "tunl"},
+ {"\\bvalleys\\b", "vlys"},
+ {"\\bvermont\\b", "vt"},
{"\\bviaduct\\b", "via"},
- {"\\bcrssing\\b", "xing"},
- {"\\bavenida\\b", "av"},
- {"\\bcapital\\b", "capitol"},
- {"\\bcolonel\\b", "col"},
- {"\\bcentral\\b", ""},
- {"\\btownshp\\b", "tw"},
- {"\\bchicago\\b", "chgo"},
- {"\\bjohnson\\b", "jhnsn"},
- {"\\bphoenix\\b", "phx"},
- {"\\bwshngtn\\b", "wa"},
+ {"\\bvillage\\b", "vil"},
{"\\bwilliam\\b", "wm"},
- {"\\bpotsdam\\b", "potsdm"},
- {"\\balabama\\b", "al"},
- {"\\barizona\\b", "az"},
- {"\\bflorida\\b", "fl"},
- {"\\bgeorgia\\b", "ga"},
- {"\\bindiana\\b", "in"},
- {"\\bmontana\\b", "mt"},
- {"\\bvermont\\b", "vt"},
+ {"\\bwshngtn\\b", "wa"},
{"\\bwyoming\\b", "wy"},
- {"\\bamerica\\b", "us"},
- {"\\bsecond\\b", "2"},
- {"\\bfourth\\b", "4"},
- {"\\beighth\\b", "8"},
+ {"\\balaska\\b", "ak"},
+ {"\\barcade\\b", "arc"},
+ {"\\bavenue\\b", "av"},
{"\\bbarrio\\b", "bo"},
{"\\bbluffs\\b", "blfs"},
{"\\bbottom\\b", "bot"},
{"\\bbranch\\b", "br"},
{"\\bbridge\\b", "brg"},
{"\\bbrooks\\b", "brks"},
+ {"\\bbypass\\b", "byp"},
+ {"\\bcamino\\b", "cm"},
{"\\bcanyon\\b", "cyn"},
- {"\\bcentre\\b", "ctr"},
- {"\\bcenter\\b", "ctr"},
+ {"\\bcarlin\\b", "carlan"},
+ {"\\bcenter\\b", "cen"},
+ {"\\bcentre\\b", "cen"},
+ {"\\bcircle\\b", "cir"},
{"\\bcliffs\\b", "clfs"},
{"\\bcommon\\b", "cmn"},
{"\\bcorner\\b", "cor"},
+ {"\\bcorpus\\b", "crp"},
+ {"\\bcounty\\b", ""},
{"\\bcourse\\b", "crse"},
{"\\bcourts\\b", "cts"},
- {"\\bxroads\\b", "xrds"},
+ {"\\bcrscnt\\b", "cres"},
+ {"\\bcrsent\\b", "cres"},
+ {"\\bcrssng\\b", "xing"},
+ {"\\bdesert\\b", "dsrt"},
{"\\bdivide\\b", "dv"},
{"\\bdrives\\b", "drs"},
+ {"\\beighth\\b", "8"},
{"\\bestate\\b", "est"},
+ {"\\bextnsn\\b", "ext"},
{"\\bfields\\b", "flds"},
{"\\bforest\\b", "frst"},
{"\\bforges\\b", "frgs"},
+ {"\\bfourth\\b", "4"},
+ {"\\bfreewy\\b", "fwy"},
{"\\bgarden\\b", "gdn"},
- {"\\bgatway\\b", "gtwy"},
{"\\bgatewy\\b", "gtwy"},
+ {"\\bgatway\\b", "gtwy"},
{"\\bgreens\\b", "grns"},
{"\\bgroves\\b", "grvs"},
{"\\bharbor\\b", "hbr"},
+ {"\\bhawaii\\b", "hi"},
{"\\bheight\\b", "ht"},
+ {"\\bhighwy\\b", "hwy"},
{"\\bhollow\\b", "hllw"},
{"\\bisland\\b", "is"},
{"\\bislnds\\b", "is"},
+ {"\\bjction\\b", "jt"},
+ {"\\bjunctn\\b", "jt"},
+ {"\\bkansas\\b", "ks"},
{"\\bknolls\\b", "knls"},
+ {"\\blagoon\\b", "lagn"},
{"\\blights\\b", "lgts"},
{"\\blittle\\b", "ltl"},
{"\\bmanors\\b", "mnrs"},
@@ -2979,415 +3075,396 @@ const Rule kRules_US[] = {
{"\\bmedows\\b", "mdws"},
{"\\bmiddle\\b", "mid"},
{"\\bmntain\\b", "mnt"},
+ {"\\bnevada\\b", "nv"},
+ {"\\bobispo\\b", "obisp"},
{"\\borchrd\\b", "orch"},
+ {"\\boregon\\b", "or"},
+ {"\\bparish\\b", ""},
+ {"\\bparkwy\\b", "pky"},
{"\\bplains\\b", "plns"},
{"\\bpoints\\b", "pts"},
{"\\bpuerto\\b", "pto"},
{"\\bquarry\\b", "qry"},
- {"\\branchs\\b", "rnchs"},
+ {"\\bradial\\b", "rad"},
+ {"\\bradiel\\b", "rad"},
{"\\brancho\\b", "rncho"},
+ {"\\branchs\\b", "rnchs"},
{"\\brapids\\b", "rpds"},
{"\\bridges\\b", "rdgs"},
+ {"\\bschool\\b", "sch"},
+ {"\\bsecond\\b", "2"},
+ {"\\bsenior\\b", "sr"},
{"\\bshoals\\b", "shls"},
- {"\\bshores\\b", "shrs"},
{"\\bshoars\\b", "shrs"},
+ {"\\bshores\\b", "shrs"},
+ {"\\bskyway\\b", "skwy"},
{"\\bspring\\b", "spg"},
{"\\bsprngs\\b", "spg"},
{"\\bsquare\\b", "sq"},
+ {"\\bstrave\\b", "stra"},
+ {"\\bstravn\\b", "stra"},
{"\\bstream\\b", "strm"},
+ {"\\bstreet\\b", "st"},
{"\\bstreme\\b", "strm"},
{"\\bsumitt\\b", "smt"},
{"\\bsummit\\b", "smt"},
+ {"\\bsydney\\b", "sidney"},
+ {"\\btraces\\b", "trce"},
+ {"\\btracks\\b", "trk"},
{"\\btrails\\b", "tr"},
+ {"\\btunnel\\b", "tunl"},
+ {"\\bturnpk\\b", "tpk"},
+ {"\\btwnshp\\b", "tp"},
{"\\bunions\\b", "uns"},
{"\\bvalley\\b", "vl"},
+ {"\\bviadct\\b", "via"},
{"\\bvillag\\b", "vil"},
{"\\bwaters\\b", "wtr"},
- {"\\bschool\\b", "sch"},
- {"\\blagoon\\b", "lagn"},
- {"\\bavenue\\b", "av"},
- {"\\bhighwy\\b", "hwy"},
- {"\\bcircle\\b", "cir"},
- {"\\barcade\\b", "arc"},
- {"\\bbypass\\b", "byp"},
- {"\\bcrscnt\\b", "cres"},
- {"\\bcrsent\\b", "cres"},
- {"\\bextnsn\\b", "ext"},
- {"\\bfreewy\\b", "fwy"},
- {"\\bjunctn\\b", "jt"},
- {"\\bjction\\b", "jt"},
- {"\\bparkwy\\b", "pky"},
- {"\\bradial\\b", "rad"},
- {"\\bradiel\\b", "rad"},
- {"\\bskyway\\b", "skwy"},
- {"\\bstrave\\b", "stra"},
- {"\\bstravn\\b", "stra"},
- {"\\bstreet\\b", "st"},
- {"\\btraces\\b", "trce"},
- {"\\btracks\\b", "trk"},
- {"\\bturnpk\\b", "tpk"},
- {"\\btunnel\\b", "tunl"},
- {"\\bviadct\\b", "via"},
- {"\\bcrssng\\b", "xing"},
- {"\\bcamino\\b", "cm"},
- {"\\bcarlan\\b", "carlin"},
- {"\\bsenior\\b", "sr"},
- {"\\bsydney\\b", "sidney"},
- {"\\bcounty\\b", ""},
- {"\\bparish\\b", ""},
- {"\\btwnshp\\b", "tw"},
- {"\\bcorpus\\b", "crp"},
- {"\\bobispo\\b", "obisp"},
- {"\\bdesert\\b", "dsrt"},
- {"\\balaska\\b", "ak"},
- {"\\bhawaii\\b", "hi"},
- {"\\bkansas\\b", "ks"},
- {"\\bnevada\\b", "nv"},
- {"\\boregon\\b", "or"},
- {"\\bnorth\\b", "n"},
- {"\\bsouth\\b", "s"},
- {"\\bfirst\\b", "1"},
- {"\\bthird\\b", "3"},
- {"\\bthree\\b", "3"},
- {"\\bfifth\\b", "5"},
- {"\\bsixth\\b", "6"},
- {"\\bseven\\b", "7"},
- {"\\beight\\b", "8"},
- {"\\bninth\\b", "9"},
- {"\\btenth\\b", "10"},
- {"\\bmount\\b", "mt"},
- {"\\bsaint\\b", "st"},
+ {"\\bxroads\\b", "xrds"},
+ {"\\ba\\s+f\\s+b\\b", "afb"},
+ {"\\ballee\\b", "aly"},
+ {"\\balley\\b", "aly"},
{"\\bannex\\b", "anx"},
+ {"\\bavenu\\b", "av"},
+ {"\\bavnue\\b", "av"},
{"\\bbayoo\\b", "byu"},
{"\\bbayou\\b", "byu"},
{"\\bbeach\\b", "bch"},
{"\\bblack\\b", "blk"},
{"\\bbluff\\b", "blf"},
{"\\bbottm\\b", "bot"},
- {"\\bbrnch\\b", "br"},
+ {"\\bboulv\\b", "blvd"},
{"\\bbrdge\\b", "brg"},
+ {"\\bbrnch\\b", "br"},
{"\\bbrook\\b", "brk"},
{"\\bburgs\\b", "bgs"},
+ {"\\bbypas\\b", "byp"},
+ {"\\bcalif\\b", "ca"},
+ {"\\bcalle\\b", "cll"},
{"\\bcanyn\\b", "cyn"},
- {"\\bcnter\\b", "ctr"},
- {"\\bcentr\\b", "ctr"},
+ {"\\bcentr\\b", "cen"},
+ {"\\bcircl\\b", "cir"},
{"\\bcliff\\b", "clf"},
+ {"\\bcnter\\b", "cen"},
+ {"\\bcourt\\b", "ct"},
{"\\bcoves\\b", "cvs"},
+ {"\\bcrcle\\b", "cir"},
{"\\bcreek\\b", "ck"},
{"\\bcrest\\b", "crst"},
- {"\\bxroad\\b", "xrd"},
+ {"\\bcrsnt\\b", "cres"},
{"\\bcurve\\b", "curv"},
+ {"\\bdepot\\b", "dep"},
+ {"\\bdrive\\b", "dr"},
+ {"\\beight\\b", "8"},
{"\\bfalls\\b", "fls"},
+ {"\\bferry\\b", "fry"},
{"\\bfield\\b", "fld"},
+ {"\\bfifth\\b", "5"},
+ {"\\bfirst\\b", "1"},
{"\\bflats\\b", "flts"},
{"\\bfords\\b", "frds"},
{"\\bforge\\b", "frg"},
{"\\bforks\\b", "fks"},
+ {"\\bfrway\\b", "fwy"},
{"\\bgardn\\b", "gdn"},
- {"\\bgrden\\b", "gdn"},
- {"\\bgrdns\\b", "gdns"},
- {"\\bgtway\\b", "gtwy"},
{"\\bglens\\b", "glns"},
{"\\bgrand\\b", "grnd"},
+ {"\\bgrden\\b", "gdn"},
+ {"\\bgrdns\\b", "gdns"},
{"\\bgreen\\b", "grn"},
{"\\bgrove\\b", "grv"},
+ {"\\bgtway\\b", "gtwy"},
{"\\bharbr\\b", "hbr"},
- {"\\bhrbor\\b", "hbr"},
{"\\bhaven\\b", "hvn"},
{"\\bhills\\b", "hl"},
+ {"\\bhiway\\b", "hwy"},
{"\\bholws\\b", "hllw"},
{"\\bhouse\\b", "hse"},
+ {"\\bhrbor\\b", "hbr"},
+ {"\\bidaho\\b", "id"},
{"\\binlet\\b", "inlt"},
- {"\\bislnd\\b", "is"},
{"\\bisles\\b", "isle"},
+ {"\\bislnd\\b", "is"},
{"\\bjctns\\b", "jcts"},
{"\\bknoll\\b", "knl"},
{"\\blakes\\b", "lks"},
- {"\\blndng\\b", "lndg"},
+ {"\\blanes\\b", "la"},
{"\\blight\\b", "lgt"},
+ {"\\blndng\\b", "lndg"},
{"\\blocks\\b", "lcks"},
{"\\blodge\\b", "ldg"},
+ {"\\bloops\\b", "loop"},
{"\\blower\\b", "lo"},
+ {"\\bm\\s+l\\s+k\\b", "mlk"},
+ {"\\bmaine\\b", "me"},
{"\\bmanor\\b", "mnr"},
{"\\bmills\\b", "mls"},
{"\\bmissn\\b", "msn"},
{"\\bmntns\\b", "mtns"},
- {"\\bplace\\b", "pl"},
+ {"\\bmount\\b", "mt"},
+ {"\\bn\\s+y\\s+c\\b", "ny"},
+ {"\\bninth\\b", "9"},
+ {"\\bnorth\\b", "n"},
+ {"\\bpalau\\b", "pw"},
{"\\bpalms\\b", "plms"},
+ {"\\bpaseo\\b", "pso"},
+ {"\\bpaths\\b", "path"},
+ {"\\bpikes\\b", "pike"},
{"\\bpines\\b", "pnes"},
+ {"\\bpkway\\b", "pky"},
+ {"\\bplace\\b", "pl"},
{"\\bplain\\b", "pln"},
+ {"\\bplaza\\b", "plz"},
{"\\bpoint\\b", "pt"},
- {"\\bports\\b", "prts"},
{"\\bponds\\b", "pnds"},
+ {"\\bports\\b", "prts"},
{"\\branch\\b", "rch"},
{"\\brapid\\b", "rpd"},
{"\\bridge\\b", "rdg"},
- {"\\briver\\b", "rvr"},
+ {"\\briver\\b", "riv"},
{"\\broads\\b", "rds"},
+ {"\\broute\\b", "rt"},
+ {"\\bsaint\\b", "st"},
+ {"\\bseven\\b", "7"},
{"\\bshoal\\b", "shl"},
- {"\\bshore\\b", "shr"},
{"\\bshoar\\b", "shr"},
+ {"\\bshore\\b", "shr"},
+ {"\\bsixth\\b", "6"},
+ {"\\bsouth\\b", "s"},
{"\\bspace\\b", "sp"},
- {"\\bsprng\\b", "spg"},
{"\\bspngs\\b", "spg"},
{"\\bsprgs\\b", "spg"},
+ {"\\bsprng\\b", "spg"},
{"\\bstatn\\b", "sta"},
+ {"\\bstrav\\b", "stra"},
+ {"\\bstrvn\\b", "stra"},
{"\\bsumit\\b", "smt"},
+ {"\\btenth\\b", "10"},
+ {"\\btexas\\b", "tx"},
+ {"\\bthird\\b", "3"},
+ {"\\bthree\\b", "3"},
+ {"\\btrace\\b", "trce"},
+ {"\\btrack\\b", "trk"},
{"\\btrail\\b", "tr"},
+ {"\\btrnpk\\b", "tpk"},
+ {"\\btunel\\b", "tunl"},
+ {"\\btunls\\b", "tunl"},
+ {"\\btunnl\\b", "tunl"},
+ {"\\bu\\s+s\\s+a\\b", "us"},
{"\\bunion\\b", "un"},
{"\\bvally\\b", "vl"},
+ {"\\bverdi\\b", "verde"},
{"\\bviews\\b", "vws"},
- {"\\bvillg\\b", "vil"},
{"\\bville\\b", "vl"},
+ {"\\bvillg\\b", "vil"},
{"\\bvista\\b", "vis"},
{"\\bwells\\b", "wls"},
{"\\bwoods\\b", "wds"},
{"\\bworks\\b", "wks"},
- {"\\broute\\b", "rt"},
- {"\\bavnue\\b", "av"},
- {"\\bavenu\\b", "av"},
- {"\\bhiway\\b", "hwy"},
- {"\\bcrcle\\b", "cir"},
- {"\\bcircl\\b", "cir"},
- {"\\balley\\b", "aly"},
- {"\\ballee\\b", "aly"},
- {"\\bboulv\\b", "boul"},
- {"\\bbypas\\b", "byp"},
- {"\\bcourt\\b", "ct"},
- {"\\bcrsnt\\b", "cres"},
- {"\\bdrive\\b", "dr"},
- {"\\bfrway\\b", "fwy"},
- {"\\bferry\\b", "fry"},
- {"\\blanes\\b", "la"},
- {"\\bloops\\b", "loop"},
- {"\\bpkway\\b", "pky"},
- {"\\bpaths\\b", "path"},
- {"\\bpikes\\b", "pike"},
- {"\\bplaza\\b", "plz"},
- {"\\bstrvn\\b", "stra"},
- {"\\bstrav\\b", "stra"},
- {"\\btrace\\b", "trce"},
- {"\\btrack\\b", "trk"},
- {"\\btrnpk\\b", "tpk"},
- {"\\btunls\\b", "tunl"},
- {"\\btunel\\b", "tunl"},
- {"\\btunnl\\b", "tunl"},
- {"\\bcalle\\b", "cll"},
- {"\\bpaseo\\b", "pso"},
- {"\\bm\\s+l\\s+k\\b", "mlk"},
- {"\\bverdi\\b", "verde"},
- {"\\ba\\s+f\\s+b\\b", "afb"},
- {"\\bcalif\\b", "ca"},
- {"\\bdepot\\b", "dep"},
- {"\\bn\\s+y\\s+c\\b", "ny"},
- {"\\bidaho\\b", "id"},
- {"\\bmaine\\b", "me"},
- {"\\btexas\\b", "tx"},
- {"\\bpalau\\b", "pw"},
- {"\\bu\\s+s\\s+a\\b", "us"},
- {"\\beast\\b", "e"},
- {"\\bwest\\b", "w"},
- {"\\bfour\\b", "4"},
- {"\\bfive\\b", "5"},
- {"\\bnine\\b", "9"},
+ {"\\bxroad\\b", "xrd"},
+ {"\\bally\\b", "aly"},
{"\\banex\\b", "anx"},
+ {"\\bariz\\b", "az"},
+ {"\\baven\\b", "av"},
{"\\bbend\\b", "bnd"},
{"\\bbluf\\b", "blf"},
+ {"\\bboul\\b", "blvd"},
{"\\bburg\\b", "bg"},
+ {"\\bbyng\\b", "bing"},
+ {"\\bbypa\\b", "byp"},
+ {"\\bbyps\\b", "byp"},
{"\\bcamp\\b", "cp"},
- {"\\bcnyn\\b", "cyn"},
{"\\bcape\\b", "cpe"},
- {"\\bcntr\\b", "ctr"},
- {"\\bcent\\b", "ctr"},
+ {"\\bcent\\b", "cen"},
+ {"\\bcirc\\b", "cir"},
+ {"\\bcity\\b", "cy"},
{"\\bclub\\b", "clb"},
+ {"\\bcntr\\b", "cen"},
+ {"\\bcnyn\\b", "cyn"},
+ {"\\bcolo\\b", "co"},
+ {"\\bconn\\b", "ct"},
{"\\bcove\\b", "cv"},
+ {"\\bcrcl\\b", "cir"},
{"\\bdale\\b", "dl"},
+ {"\\bdriv\\b", "dr"},
+ {"\\beast\\b", "e"},
+ {"\\bexpr\\b", "exp"},
+ {"\\bexpw\\b", "exp"},
+ {"\\bexpy\\b", "exp"},
+ {"\\bextn\\b", "ext"},
+ {"\\bfarm\\b", "frm"},
+ {"\\bfive\\b", "5"},
{"\\bflat\\b", "flt"},
{"\\bford\\b", "frd"},
- {"\\bfarm\\b", "frm"},
{"\\bforg\\b", "frg"},
{"\\bfork\\b", "frk"},
- {"\\bfrks\\b", "fks"},
{"\\bfort\\b", "ft"},
- {"\\bgrdn\\b", "gdn"},
+ {"\\bfour\\b", "4"},
+ {"\\bfrks\\b", "fks"},
+ {"\\bfrry\\b", "fry"},
+ {"\\bfrwy\\b", "fwy"},
{"\\bglen\\b", "gln"},
+ {"\\bgrdn\\b", "gdn"},
+ {"\\bgrov\\b", "grv"},
+ {"\\bguam\\b", "gu"},
{"\\bharb\\b", "hbr"},
{"\\bhavn\\b", "hvn"},
- {"\\bhgts\\b", "ht"},
{"\\bhght\\b", "ht"},
+ {"\\bhgts\\b", "ht"},
{"\\bhill\\b", "hl"},
+ {"\\bhiwy\\b", "hwy"},
{"\\bholw\\b", "hllw"},
+ {"\\bhway\\b", "hwy"},
+ {"\\biowa\\b", "ia"},
+ {"\\bjctn\\b", "jt"},
{"\\bjnct\\b", "jt"},
+ {"\\bkans\\b", "ks"},
{"\\bkeys\\b", "kys"},
{"\\bknol\\b", "knl"},
{"\\blake\\b", "lk"},
+ {"\\blane\\b", "la"},
+ {"\\bldge\\b", "ldg"},
{"\\blitl\\b", "ltl"},
{"\\bloaf\\b", "lf"},
{"\\block\\b", "lck"},
- {"\\bldge\\b", "ldg"},
{"\\blodg\\b", "ldg"},
+ {"\\bmass\\b", "ma"},
+ {"\\bmich\\b", "mi"},
{"\\bmile\\b", "mle"},
{"\\bmill\\b", "ml"},
- {"\\bmssn\\b", "msn"},
+ {"\\bminn\\b", "mn"},
+ {"\\bmiss\\b", "ms"},
{"\\bmntn\\b", "mnt"},
+ {"\\bmssn\\b", "msn"},
{"\\bmtin\\b", "mnt"},
+ {"\\bnebr\\b", "ne"},
{"\\bneck\\b", "nck"},
+ {"\\bnine\\b", "9"},
+ {"\\bohio\\b", "oh"},
+ {"\\bokla\\b", "ok"},
+ {"\\boreg\\b", "or"},
{"\\boval\\b", "ovl"},
{"\\bpalm\\b", "plm"},
{"\\bpark\\b", "pk"},
{"\\bpass\\b", "ps"},
{"\\bpine\\b", "pne"},
+ {"\\bpkwy\\b", "pky"},
+ {"\\bplza\\b", "plz"},
{"\\bport\\b", "prt"},
- {"\\brnch\\b", "rch"},
- {"\\brest\\b", "rst"},
+ {"\\bradl\\b", "rad"},
{"\\brdge\\b", "rdg"},
- {"\\brivr\\b", "rvr"},
+ {"\\brest\\b", "rst"},
+ {"\\brivr\\b", "riv"},
+ {"\\brnch\\b", "rch"},
+ {"\\broad\\b", "rd"},
+ {"\\bspgs\\b", "spg"},
{"\\bspng\\b", "spg"},
{"\\bsprg\\b", "spg"},
- {"\\bspgs\\b", "spg"},
{"\\bsqre\\b", "sq"},
{"\\bsqrs\\b", "sqs"},
- {"\\btrls\\b", "tr"},
- {"\\bvlly\\b", "vl"},
- {"\\bview\\b", "vw"},
- {"\\bvill\\b", "vil"},
- {"\\bvist\\b", "vis"},
- {"\\bvsta\\b", "vis"},
- {"\\bwell\\b", "wl"},
- {"\\broad\\b", "rd"},
- {"\\baven\\b", "av"},
- {"\\bhiwy\\b", "hwy"},
- {"\\bhway\\b", "hwy"},
- {"\\bexpr\\b", "exp"},
- {"\\bexpw\\b", "exp"},
- {"\\bexpy\\b", "exp"},
- {"\\bcirc\\b", "cir"},
- {"\\bcrcl\\b", "cir"},
- {"\\bally\\b", "aly"},
- {"\\bblvd\\b", "boul"},
- {"\\bbypa\\b", "byp"},
- {"\\bbyps\\b", "byp"},
- {"\\bdriv\\b", "dr"},
- {"\\bextn\\b", "ext"},
- {"\\bfrwy\\b", "fwy"},
- {"\\bfrry\\b", "fry"},
- {"\\bgrov\\b", "grv"},
- {"\\bjctn\\b", "jt"},
- {"\\blane\\b", "la"},
- {"\\bpkwy\\b", "pky"},
- {"\\bplza\\b", "plz"},
- {"\\bradl\\b", "rad"},
{"\\bstrt\\b", "st"},
+ {"\\btenn\\b", ""},
{"\\bterr\\b", "ter"},
- {"\\btrks\\b", "trk"},
+ {"\\btown\\b", ""},
+ {"\\btpke\\b", "tpk"},
{"\\btrak\\b", "trk"},
+ {"\\btrks\\b", "trk"},
+ {"\\btrls\\b", "tr"},
{"\\btrpk\\b", "tpk"},
- {"\\btpke\\b", "tpk"},
- {"\\bvdct\\b", "via"},
- {"\\bx\\s+rd\\b", "xrd"},
{"\\btwln\\b", "t l"},
- {"\\btown\\b", ""},
- {"\\btwsp\\b", "tw"},
- {"\\bcity\\b", "cy"},
- {"\\bbing\\b", "byng"},
- {"\\bcolo\\b", "co"},
- {"\\bariz\\b", "az"},
- {"\\bconn\\b", "ct"},
- {"\\biowa\\b", "ia"},
- {"\\bkans\\b", "ks"},
- {"\\bmass\\b", "ma"},
- {"\\bmich\\b", "mi"},
- {"\\bminn\\b", "mn"},
- {"\\bmiss\\b", "ms"},
- {"\\bnebr\\b", "ne"},
- {"\\bohio\\b", "oh"},
- {"\\bokla\\b", "ok"},
- {"\\boreg\\b", "or"},
- {"\\btenn\\b", ""},
+ {"\\btwsp\\b", "tp"},
{"\\butah\\b", "ut"},
+ {"\\bvdct\\b", "via"},
+ {"\\bview\\b", "vw"},
+ {"\\bvill\\b", "vil"},
+ {"\\bvist\\b", "vis"},
+ {"\\bvlly\\b", "vl"},
+ {"\\bvsta\\b", "vis"},
{"\\bwash\\b", "wa"},
- {"\\bguam\\b", "gu"},
- {"\\bnth\\b", "n"},
- {"\\bsth\\b", "s"},
- {"\\bone\\b", "1"},
- {"\\btwo\\b", "2"},
- {"\\bsix\\b", "6"},
- {"\\bten\\b", "10"},
+ {"\\bwell\\b", "wl"},
+ {"\\bwest\\b", "w"},
+ {"\\bx\\s+rd\\b", "xrd"},
+ {"\\bala\\b", "al"},
+ {"\\bave\\b", "av"},
+ {"\\bavn\\b", "av"},
{"\\bbtm\\b", "bot"},
+ {"\\bcam\\b", "cm"},
{"\\bcmp\\b", "cp"},
- {"\\bcen\\b", "ctr"},
{"\\bcrk\\b", "ck"},
+ {"\\bcrt\\b", "ct"},
+ {"\\bctr\\b", "cen"},
+ {"\\bcty\\b", "cy"},
+ {"\\bd\\s+c\\b", "dc"},
{"\\bdam\\b", "dm"},
{"\\bdiv\\b", "dv"},
+ {"\\bdpt\\b", "dep"},
+ {"\\bdrv\\b", "dr"},
{"\\bdvd\\b", "dv"},
+ {"\\bfla\\b", "fl"},
{"\\bfrt\\b", "ft"},
{"\\bhei\\b", "ht"},
- {"\\bhts\\b", "ht"},
{"\\bhls\\b", "hl"},
+ {"\\bhts\\b", "ht"},
+ {"\\bill\\b", "il"},
+ {"\\bind\\b", "in"},
{"\\bisl\\b", "is"},
{"\\biss\\b", "is"},
{"\\bjct\\b", "jt"},
+ {"\\bkan\\b", "ks"},
{"\\bkey\\b", "ky"},
+ {"\\bl\\s+a\\b", "la"},
{"\\blke\\b", "lk"},
{"\\blwr\\b", "lo"},
{"\\bmtn\\b", "mnt"},
+ {"\\bn\\s+c\\b", "nc"},
+ {"\\bn\\s+d\\b", "nd"},
+ {"\\bn\\s+h\\b", "nh"},
+ {"\\bn\\s+j\\b", "nj"},
+ {"\\bn\\s+m\\b", "nm"},
+ {"\\bn\\s+y\\b", "ny"},
+ {"\\bneb\\b", "ne"},
+ {"\\bnev\\b", "nv"},
+ {"\\bnth\\b", "n"},
{"\\bntl\\b", "nl"},
+ {"\\bnyc\\b", "ny"},
+ {"\\bnys\\b", "ny"},
+ {"\\bone\\b", "1"},
+ {"\\bore\\b", "or"},
+ {"\\bp\\s+r\\b", "pr"},
{"\\bprk\\b", "pk"},
{"\\bprr\\b", "pr"},
- {"\\briv\\b", "rvr"},
+ {"\\br\\s+i\\b", "ri"},
+ {"\\brte\\b", "rt"},
+ {"\\brvr\\b", "riv"},
+ {"\\bs\\s+c\\b", "sc"},
+ {"\\bs\\s+d\\b", "sd"},
{"\\bsan\\b", "sn"},
+ {"\\bsix\\b", "6"},
{"\\bspr\\b", "spg"},
{"\\bsqr\\b", "sq"},
{"\\bsqu\\b", "sq"},
+ {"\\bsth\\b", "s"},
{"\\bstn\\b", "sta"},
+ {"\\bstr\\b", "st"},
+ {"\\bten\\b", "10"},
{"\\btrl\\b", "tr"},
- {"\\bvly\\b", "vl"},
+ {"\\btwo\\b", "2"},
+ {"\\btwp\\b", "tp"},
+ {"\\bu\\s+s\\b", "us"},
+ {"\\busa\\b", "us"},
+ {"\\bv\\s+i\\b", "vi"},
{"\\bvlg\\b", "vil"},
+ {"\\bvly\\b", "vl"},
{"\\bvst\\b", "vis"},
- {"\\brte\\b", "rt"},
- {"\\bave\\b", "av"},
- {"\\bavn\\b", "av"},
- {"\\bcrt\\b", "ct"},
- {"\\bdrv\\b", "dr"},
- {"\\bstr\\b", "st"},
- {"\\bway\\b", "wy"},
- {"\\bcam\\b", "cm"},
- {"\\btwp\\b", "tw"},
- {"\\bcty\\b", "cy"},
- {"\\bdpt\\b", "dep"},
- {"\\bl\\s+a\\b", "la"},
- {"\\bnyc\\b", "ny"},
- {"\\bd\\s+c\\b", "dc"},
- {"\\bn\\s+h\\b", "nh"},
- {"\\bn\\s+j\\b", "nj"},
- {"\\bn\\s+m\\b", "nm"},
- {"\\bnys\\b", "ny"},
- {"\\bn\\s+y\\b", "ny"},
- {"\\bn\\s+c\\b", "nc"},
- {"\\bn\\s+d\\b", "nd"},
- {"\\bp\\s+r\\b", "pr"},
- {"\\br\\s+i\\b", "ri"},
- {"\\bs\\s+c\\b", "sc"},
- {"\\bs\\s+d\\b", "sd"},
- {"\\bv\\s+i\\b", "vi"},
{"\\bw\\s+v\\b", "wv"},
- {"\\bala\\b", "al"},
- {"\\bfla\\b", "fl"},
- {"\\bill\\b", "il"},
- {"\\bind\\b", "in"},
- {"\\bkan\\b", "ks"},
- {"\\bneb\\b", "ne"},
- {"\\bnev\\b", "nv"},
- {"\\bore\\b", "or"},
+ {"\\bway\\b", "wy"},
{"\\bwis\\b", "wi"},
{"\\bwva\\b", "wv"},
- {"\\busa\\b", "us"},
- {"\\bu\\s+s\\b", "us"},
{"\\bcr\\b", "ck"},
- {"\\bvy\\b", "vl"},
{"\\bln\\b", "la"},
- {"\\btp\\b", "tw"},
{"\\btn\\b", ""},
+ {"\\btw\\b", "tp"},
+ {"\\bvy\\b", "vl"},
{"\\b\\#\\b", ""},
};
@@ -3396,103 +3473,97 @@ const Rule kRules_VN[] = {
{"\\bho\\s+chi\\s+minh\\s+city\\b", "hcm"},
{"\\bho\\s+chi\\s+minh\\b", "hcm"},
{"\\bthanh\\s+pho\\b", "tp"},
- {"\\btpha\\s+noi\\b", "ha noi"},
{"\\bthi\\s+tran\\b", "tt"},
+ {"\\btpha\\s+noi\\b", "ha noi"},
{"\\bviet\\s+nam\\b", "vn"},
{"\\bvietnam\\b", "vn"},
{"\\bphuong\\b", "p"},
{"\\bthi\\s+xa\\b", "tx"},
- {"\\bhuyen\\b", "h"},
+ {"\\bhuyen\\b", "h."},
{"\\bhcmc\\b", "hcm"},
- {"\\bquan\\b", "q"},
- {"\\bt\\.p\\.\\b", "tp"},
- {"\\btinh\\b", "t"},
+ {"\\bquan\\b", "q."},
{"\\bph\\.\\b", "p"},
{"\\btp\\.\\b", "tp"},
{"\\btt\\.\\b", "tt"},
{"\\btx\\.\\b", "tx"},
- {"\\bh\\.\\b", "h"},
{"\\bp\\.\\b", "p"},
- {"\\bq\\.\\b", "q"},
- {"\\bt\\.\\b", "t"},
- {"\\bx\\.\\b", "x"},
- {"\\bxa\\b", "x"},
+ {"\\bxa\\b", "x."},
};
const Rule kRules_ZA[] = {
- {"\\brepublic\\s+of\\s+south\\s+africa\\b", "za"},
- {"\\bkwazulu\\s+natal\\b", "zn"},
+ {"\\brepublic\\s+of\\s+south\\s+africa\\b", "sa"},
+ {"\\bkwazulu\\s+natal\\b", "nl"},
{"\\bnorthern\\s+cape\\b", "nc"},
{"\\beastern\\s+cape\\b", "ec"},
- {"\\bkwazulunatal\\b", "zn"},
+ {"\\bkwazulunatal\\b", "nl"},
+ {"\\bsouth\\s+africa\\b", "sa"},
{"\\bwestern\\s+cape\\b", "wc"},
- {"\\bsouth\\s+africa\\b", "za"},
{"\\bfree\\s+state\\b", "fs"},
{"\\bmpumalanga\\b", "mp"},
- {"\\bnorth\\s+west\\b", "nw"},
{"\\bnoord\\s+kaap\\b", "nc"},
+ {"\\bnorth\\s+west\\b", "nw"},
{"\\bboulevard\\b", "blvd"},
{"\\bfreestate\\b", "fs"},
+ {"\\bnoordwes\\b", "nw"},
{"\\boos\\s+kaap\\b", "ec"},
{"\\bvrystaat\\b", "fs"},
- {"\\bnoordwes\\b", "nw"},
{"\\bwes\\s+kaap\\b", "wc"},
- {"\\bhighway\\b", "hwy"},
{"\\bgauteng\\b", "gp"},
+ {"\\bhighway\\b", "hwy"},
{"\\blimpopo\\b", "lp"},
- {"\\bstreet\\b", "st"},
{"\\bavenue\\b", "ave"},
- {"\\bsaint\\b", "st"},
+ {"\\bstreet\\b", "st"},
{"\\bdrive\\b", "dr"},
- {"\\bnatal\\b", "zn"},
+ {"\\bnatal\\b", "nl"},
+ {"\\bsaint\\b", "st"},
{"\\broad\\b", "rd"},
- {"\\bkzn\\b", "zn"},
+ {"\\bkzn\\b", "nl"},
{"\\bgt\\b", "gp"},
- {"\\bnl\\b", "zn"},
- {"\\bsa\\b", "za"},
+ {"\\bza\\b", "sa"},
+ {"\\bzn\\b", "nl"},
};
} // namespace
const RegionInfo kRuleTable[] = {
- {"AD", kRules_AD, sizeof(kRules_AD) / sizeof(kRules_AD[0])},
- {"AR", kRules_AR, sizeof(kRules_AR) / sizeof(kRules_AR[0])},
- {"AU", kRules_AU, sizeof(kRules_AU) / sizeof(kRules_AU[0])},
- {"BE", kRules_BE, sizeof(kRules_BE) / sizeof(kRules_BE[0])},
- {"BR", kRules_BR, sizeof(kRules_BR) / sizeof(kRules_BR[0])},
- {"CA", kRules_CA, sizeof(kRules_CA) / sizeof(kRules_CA[0])},
- {"CH", kRules_CH, sizeof(kRules_CH) / sizeof(kRules_CH[0])},
- {"CL", kRules_CL, sizeof(kRules_CL) / sizeof(kRules_CL[0])},
- {"CO", kRules_CO, sizeof(kRules_CO) / sizeof(kRules_CO[0])},
- {"DE", kRules_DE, sizeof(kRules_DE) / sizeof(kRules_DE[0])},
- {"DK", kRules_DK, sizeof(kRules_DK) / sizeof(kRules_DK[0])},
- {"ES", kRules_ES, sizeof(kRules_ES) / sizeof(kRules_ES[0])},
- {"FR", kRules_FR, sizeof(kRules_FR) / sizeof(kRules_FR[0])},
- {"GB", kRules_GB, sizeof(kRules_GB) / sizeof(kRules_GB[0])},
- {"GR", kRules_GR, sizeof(kRules_GR) / sizeof(kRules_GR[0])},
- {"HK", kRules_HK, sizeof(kRules_HK) / sizeof(kRules_HK[0])},
- {"ID", kRules_ID, sizeof(kRules_ID) / sizeof(kRules_ID[0])},
- {"IE", kRules_IE, sizeof(kRules_IE) / sizeof(kRules_IE[0])},
- {"IN", kRules_IN, sizeof(kRules_IN) / sizeof(kRules_IN[0])},
- {"IT", kRules_IT, sizeof(kRules_IT) / sizeof(kRules_IT[0])},
- {"LU", kRules_LU, sizeof(kRules_LU) / sizeof(kRules_LU[0])},
- {"MX", kRules_MX, sizeof(kRules_MX) / sizeof(kRules_MX[0])},
- {"MY", kRules_MY, sizeof(kRules_MY) / sizeof(kRules_MY[0])},
- {"NL", kRules_NL, sizeof(kRules_NL) / sizeof(kRules_NL[0])},
- {"NZ", kRules_NZ, sizeof(kRules_NZ) / sizeof(kRules_NZ[0])},
- {"PE", kRules_PE, sizeof(kRules_PE) / sizeof(kRules_PE[0])},
- {"PH", kRules_PH, sizeof(kRules_PH) / sizeof(kRules_PH[0])},
- {"PL", kRules_PL, sizeof(kRules_PL) / sizeof(kRules_PL[0])},
- {"PR", kRules_PR, sizeof(kRules_PR) / sizeof(kRules_PR[0])},
- {"PT", kRules_PT, sizeof(kRules_PT) / sizeof(kRules_PT[0])},
- {"RO", kRules_RO, sizeof(kRules_RO) / sizeof(kRules_RO[0])},
- {"RU", kRules_RU, sizeof(kRules_RU) / sizeof(kRules_RU[0])},
- {"SE", kRules_SE, sizeof(kRules_SE) / sizeof(kRules_SE[0])},
- {"TH", kRules_TH, sizeof(kRules_TH) / sizeof(kRules_TH[0])},
- {"TR", kRules_TR, sizeof(kRules_TR) / sizeof(kRules_TR[0])},
- {"US", kRules_US, sizeof(kRules_US) / sizeof(kRules_US[0])},
- {"VN", kRules_VN, sizeof(kRules_VN) / sizeof(kRules_VN[0])},
- {"ZA", kRules_ZA, sizeof(kRules_ZA) / sizeof(kRules_ZA[0])},
+ {"AD", kRules_AD, sizeof(kRules_AD)/sizeof(kRules_AD[0])},
+ {"AR", kRules_AR, sizeof(kRules_AR)/sizeof(kRules_AR[0])},
+ {"AU", kRules_AU, sizeof(kRules_AU)/sizeof(kRules_AU[0])},
+ {"BE", kRules_BE, sizeof(kRules_BE)/sizeof(kRules_BE[0])},
+ {"BR", kRules_BR, sizeof(kRules_BR)/sizeof(kRules_BR[0])},
+ {"CA", kRules_CA, sizeof(kRules_CA)/sizeof(kRules_CA[0])},
+ {"CH", kRules_CH, sizeof(kRules_CH)/sizeof(kRules_CH[0])},
+ {"CL", kRules_CL, sizeof(kRules_CL)/sizeof(kRules_CL[0])},
+ {"CO", kRules_CO, sizeof(kRules_CO)/sizeof(kRules_CO[0])},
+ {"DE", kRules_DE, sizeof(kRules_DE)/sizeof(kRules_DE[0])},
+ {"DK", kRules_DK, sizeof(kRules_DK)/sizeof(kRules_DK[0])},
+ {"ES", kRules_ES, sizeof(kRules_ES)/sizeof(kRules_ES[0])},
+ {"FR", kRules_FR, sizeof(kRules_FR)/sizeof(kRules_FR[0])},
+ {"GB", kRules_GB, sizeof(kRules_GB)/sizeof(kRules_GB[0])},
+ {"GR", kRules_GR, sizeof(kRules_GR)/sizeof(kRules_GR[0])},
+ {"HK", kRules_HK, sizeof(kRules_HK)/sizeof(kRules_HK[0])},
+ {"ID", kRules_ID, sizeof(kRules_ID)/sizeof(kRules_ID[0])},
+ {"IE", kRules_IE, sizeof(kRules_IE)/sizeof(kRules_IE[0])},
+ {"IN", kRules_IN, sizeof(kRules_IN)/sizeof(kRules_IN[0])},
+ {"IT", kRules_IT, sizeof(kRules_IT)/sizeof(kRules_IT[0])},
+ {"LU", kRules_LU, sizeof(kRules_LU)/sizeof(kRules_LU[0])},
+ {"MX", kRules_MX, sizeof(kRules_MX)/sizeof(kRules_MX[0])},
+ {"MY", kRules_MY, sizeof(kRules_MY)/sizeof(kRules_MY[0])},
+ {"NL", kRules_NL, sizeof(kRules_NL)/sizeof(kRules_NL[0])},
+ {"NZ", kRules_NZ, sizeof(kRules_NZ)/sizeof(kRules_NZ[0])},
+ {"PE", kRules_PE, sizeof(kRules_PE)/sizeof(kRules_PE[0])},
+ {"PH", kRules_PH, sizeof(kRules_PH)/sizeof(kRules_PH[0])},
+ {"PL", kRules_PL, sizeof(kRules_PL)/sizeof(kRules_PL[0])},
+ {"PR", kRules_PR, sizeof(kRules_PR)/sizeof(kRules_PR[0])},
+ {"PT", kRules_PT, sizeof(kRules_PT)/sizeof(kRules_PT[0])},
+ {"RO", kRules_RO, sizeof(kRules_RO)/sizeof(kRules_RO[0])},
+ {"RU", kRules_RU, sizeof(kRules_RU)/sizeof(kRules_RU[0])},
+ {"SE", kRules_SE, sizeof(kRules_SE)/sizeof(kRules_SE[0])},
+ {"TH", kRules_TH, sizeof(kRules_TH)/sizeof(kRules_TH[0])},
+ {"TR", kRules_TR, sizeof(kRules_TR)/sizeof(kRules_TR[0])},
+ {"US", kRules_US, sizeof(kRules_US)/sizeof(kRules_US[0])},
+ {"VN", kRules_VN, sizeof(kRules_VN)/sizeof(kRules_VN[0])},
+ {"ZA", kRules_ZA, sizeof(kRules_ZA)/sizeof(kRules_ZA[0])},
};
const size_t kRuleTableSize = sizeof(kRuleTable)/sizeof(kRuleTable[0]);
diff --git a/chromium/components/autofill/core/browser/autofill_assistant.cc b/chromium/components/autofill/core/browser/autofill_assistant.cc
new file mode 100644
index 00000000000..b7f00b5a30c
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_assistant.cc
@@ -0,0 +1,68 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_assistant.h"
+
+#include "base/containers/adapters.h"
+#include "base/strings/string16.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/common/autofill_constants.h"
+
+namespace autofill {
+
+AutofillAssistant::AutofillAssistant(AutofillManager* autofill_manager)
+ : credit_card_form_data_(nullptr),
+ autofill_manager_(autofill_manager),
+ weak_ptr_factory_(this) {}
+
+AutofillAssistant::~AutofillAssistant() {}
+
+void AutofillAssistant::Reset() {
+ credit_card_form_data_.reset();
+}
+
+bool AutofillAssistant::CanShowCreditCardAssist(
+ const std::vector<FormStructure*>& form_structures) {
+ if (form_structures.empty() || credit_card_form_data_ != nullptr ||
+ !IsAutofillCreditCardAssistEnabled() ||
+ !autofill_manager_->client()->IsContextSecure(
+ form_structures.front()->source_url())) {
+ return false;
+ }
+
+ for (FormStructure* cur_form : base::Reversed(form_structures)) {
+ if (cur_form->IsCompleteCreditCardForm()) {
+ credit_card_form_data_.reset(new FormData(cur_form->ToFormData()));
+ break;
+ }
+ }
+ return credit_card_form_data_ != nullptr;
+}
+
+void AutofillAssistant::ShowAssistForCreditCard(const CreditCard& card) {
+ DCHECK(credit_card_form_data_);
+ autofill_manager_->client()->ConfirmCreditCardFillAssist(
+ card, base::Bind(&AutofillAssistant::OnUserDidAcceptCreditCardFill,
+ weak_ptr_factory_.GetWeakPtr(), card));
+}
+
+void AutofillAssistant::OnUserDidAcceptCreditCardFill(const CreditCard& card) {
+ autofill_manager_->GetOrCreateFullCardRequest()->GetFullCard(
+ card, AutofillClient::UNMASK_FOR_AUTOFILL,
+ weak_ptr_factory_.GetWeakPtr());
+}
+
+void AutofillAssistant::OnFullCardRequestSucceeded(const CreditCard& card,
+ const base::string16& cvc) {
+ autofill_manager_->FillCreditCardForm(kNoQueryId, *credit_card_form_data_,
+ credit_card_form_data_->fields[0], card,
+ cvc);
+}
+
+void AutofillAssistant::OnFullCardRequestFailed() {}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_assistant.h b/chromium/components/autofill/core/browser/autofill_assistant.h
new file mode 100644
index 00000000000..d546601d60d
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_assistant.h
@@ -0,0 +1,65 @@
+// 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 COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ASSISTANT_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ASSISTANT_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/payments/full_card_request.h"
+#include "components/autofill/core/common/form_data.h"
+
+namespace autofill {
+
+class AutofillManager;
+class CreditCard;
+class FormStructure;
+
+// This class encompasses the triggering rules and the logic for the autofill
+// assisted filling mechanisms.
+class AutofillAssistant : public payments::FullCardRequest::Delegate {
+ public:
+ explicit AutofillAssistant(AutofillManager* autofill_manager);
+ ~AutofillAssistant();
+
+ // Should be called at every page navigation to clear state.
+ void Reset();
+
+ // Returns whether a credit card assist can be shown. Will go through the
+ // forms in |form_structures| and extract the credit card form.
+ bool CanShowCreditCardAssist(
+ const std::vector<FormStructure*>& form_structures);
+
+ // Will show an assist infobar for the previously extracted form proposing to
+ // autofill it. Should only be called if CanShowCreditCardAssist() returned
+ // true.
+ void ShowAssistForCreditCard(const CreditCard& card);
+
+ private:
+ // Called by the infobar delegate when the user accepts the infobar.
+ void OnUserDidAcceptCreditCardFill(const CreditCard& card);
+
+ // payments::FullCardRequest::Delegate:
+ void OnFullCardRequestSucceeded(const CreditCard& card,
+ const base::string16& cvc) override;
+ void OnFullCardRequestFailed() override;
+
+ // Holds the FormData to be filled with a credit card.
+ std::unique_ptr<FormData> credit_card_form_data_;
+
+ // Weak reference to the AutofillManager that created and maintains this
+ // AutofillAssistant.
+ AutofillManager* autofill_manager_;
+
+ base::WeakPtrFactory<AutofillAssistant> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillAssistant);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ASSISTANT_H_
diff --git a/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
new file mode 100644
index 00000000000..16176f2af8f
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_assistant_unittest.cc
@@ -0,0 +1,207 @@
+// 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 "components/autofill/core/browser/autofill_assistant.h"
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/feature_list.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/browser/autofill_driver.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+#include "components/autofill/core/browser/test_autofill_driver.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+
+namespace autofill {
+namespace {
+
+class MockAutofillManager : public AutofillManager {
+ public:
+ MockAutofillManager(TestAutofillDriver* driver,
+ TestAutofillClient* client,
+ PersonalDataManager* pdm)
+ // Force to use the constructor designated for unit test.
+ : AutofillManager(driver, client, pdm) {}
+ virtual ~MockAutofillManager() {}
+
+ MOCK_METHOD5(FillCreditCardForm,
+ void(int query_id,
+ const FormData& form,
+ const FormFieldData& field,
+ const CreditCard& credit_card,
+ const base::string16& cvc));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAutofillManager);
+};
+
+} // namespace
+
+class AutofillAssistantTest : public testing::Test {
+ protected:
+ AutofillAssistantTest()
+ : message_loop_(),
+ autofill_client_(),
+ autofill_driver_(),
+ pdm_(),
+ autofill_manager_(&autofill_driver_, &autofill_client_, &pdm_),
+ autofill_assistant_(&autofill_manager_) {}
+
+ void EnableAutofillCreditCardAssist() {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillCreditCardAssist);
+ autofill_client_.set_is_context_secure(true);
+ }
+
+ // Returns an initialized FormStructure with credit card form data. To be
+ // owned by the caller.
+ std::unique_ptr<FormStructure> CreateValidCreditCardForm() {
+ std::unique_ptr<FormStructure> form_structure;
+ FormData form;
+
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = base::ASCIIToUTF16("Name on Card");
+ field.name = base::ASCIIToUTF16("name_on_card");
+ form.fields.push_back(field);
+
+ field.label = base::ASCIIToUTF16("Card Number");
+ field.name = base::ASCIIToUTF16("card_number");
+ form.fields.push_back(field);
+
+ field.label = base::ASCIIToUTF16("Exp Month");
+ field.name = base::ASCIIToUTF16("ccmonth");
+ form.fields.push_back(field);
+
+ field.label = base::ASCIIToUTF16("Exp Year");
+ field.name = base::ASCIIToUTF16("ccyear");
+ form.fields.push_back(field);
+
+ field.label = base::ASCIIToUTF16("Verification");
+ field.name = base::ASCIIToUTF16("verification");
+ form.fields.push_back(field);
+
+ form_structure.reset(new FormStructure(form));
+ form_structure->DetermineHeuristicTypes();
+
+ return form_structure;
+ }
+
+ base::MessageLoop message_loop_;
+ TestAutofillClient autofill_client_;
+ testing::NiceMock<TestAutofillDriver> autofill_driver_;
+ TestPersonalDataManager pdm_;
+ MockAutofillManager autofill_manager_;
+ AutofillAssistant autofill_assistant_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+MATCHER_P(CreditCardMatches, guid, "") {
+ return arg.guid() == guid;
+}
+
+// If the feature is turned off, CanShowCreditCardAssist() always returns
+// false.
+TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOff) {
+ std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm();
+
+ std::vector<FormStructure*> form_structures{form_structure.get()};
+ EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+}
+
+// Tests that with the feature enabled and proper input,
+// CanShowCreditCardAssist() behaves as expected.
+TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn) {
+ EnableAutofillCreditCardAssist();
+ std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm();
+
+ std::vector<FormStructure*> form_structures;
+ EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+
+ // With valid input, the function extracts the credit card form properly.
+ form_structures.push_back(form_structure.get());
+ EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+}
+
+// Tests that with the feature enabled and proper input,
+// CanShowCreditCardAssist() behaves as expected for secure vs insecure
+// contexts.
+TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn_NotSecure) {
+ EnableAutofillCreditCardAssist();
+ std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm();
+ std::vector<FormStructure*> form_structures;
+ form_structures.push_back(form_structure.get());
+
+ // Cannot be shown if the context is not secure.
+ autofill_client_.set_is_context_secure(false);
+ EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+
+ // Can be shown if the context is secure.
+ autofill_client_.set_is_context_secure(true);
+ EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+}
+
+TEST_F(AutofillAssistantTest, ShowAssistForCreditCard_ValidCard_CancelCvc) {
+ EnableAutofillCreditCardAssist();
+ std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm();
+
+ // Will extract the credit card form data.
+ std::vector<FormStructure*> form_structures{form_structure.get()};
+ EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+
+ // Create a valid card for the assist.
+ CreditCard card;
+ test::SetCreditCardInfo(&card, "John Doe", "4111111111111111", "05", "2999");
+
+ // FillCreditCardForm should not be called if the user cancelled the CVC.
+ EXPECT_CALL(autofill_manager_, FillCreditCardForm(_, _, _, _, _)).Times(0);
+
+ autofill_assistant_.ShowAssistForCreditCard(card);
+ static_cast<CardUnmaskDelegate*>(
+ autofill_manager_.GetOrCreateFullCardRequest())
+ ->OnUnmaskPromptClosed();
+}
+
+TEST_F(AutofillAssistantTest, ShowAssistForCreditCard_ValidCard_SubmitCvc) {
+ EnableAutofillCreditCardAssist();
+ std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm();
+
+ // Will extract the credit card form data.
+ std::vector<FormStructure*> form_structures{form_structure.get()};
+ EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+
+ // Create a valid card for the assist.
+ CreditCard card;
+ test::SetCreditCardInfo(&card, "John Doe", "4111111111111111", "05", "2999");
+
+ // FillCreditCardForm ends up being called after user has accepted the
+ // prompt.
+ EXPECT_CALL(
+ autofill_manager_,
+ FillCreditCardForm(kNoQueryId, _, _, CreditCardMatches(card.guid()),
+ base::ASCIIToUTF16("123")));
+
+ autofill_assistant_.ShowAssistForCreditCard(card);
+
+ CardUnmaskDelegate::UnmaskResponse unmask_response;
+ unmask_response.cvc = base::ASCIIToUTF16("123");
+ static_cast<CardUnmaskDelegate*>(
+ autofill_manager_.GetOrCreateFullCardRequest())
+ ->OnUnmaskResponse(unmask_response);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h
index b83d6efb087..61b10177c41 100644
--- a/chromium/components/autofill/core/browser/autofill_client.h
+++ b/chromium/components/autofill/core/browser/autofill_client.h
@@ -6,6 +6,7 @@
#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CLIENT_H_
#include <memory>
+#include <string>
#include <vector>
#include "base/callback_forward.h"
@@ -16,7 +17,9 @@
#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"
+class GURL;
class IdentityProvider;
+class PrefService;
namespace content {
class RenderFrameHost;
@@ -31,13 +34,10 @@ namespace rappor {
class RapporService;
}
-namespace sync_driver {
+namespace syncer {
class SyncService;
}
-class GURL;
-class PrefService;
-
namespace autofill {
class AutofillPopupDelegate;
@@ -86,9 +86,7 @@ class AutofillClient {
UNMASK_FOR_AUTOFILL,
};
- typedef base::Callback<void(const base::string16& /* card number */,
- int /* exp month */,
- int /* exp year */)> CreditCardScanCallback;
+ typedef base::Callback<void(const CreditCard&)> CreditCardScanCallback;
virtual ~AutofillClient() {}
@@ -102,7 +100,7 @@ class AutofillClient {
virtual PrefService* GetPrefs() = 0;
// Gets the sync service associated with the client.
- virtual sync_driver::SyncService* GetSyncService() = 0;
+ virtual syncer::SyncService* GetSyncService() = 0;
// Gets the IdentityProvider associated with the client (for OAuth2).
virtual IdentityProvider* GetIdentityProvider() = 0;
@@ -132,6 +130,11 @@ class AutofillClient {
std::unique_ptr<base::DictionaryValue> legal_message,
const base::Closure& callback) = 0;
+ // Will show an infobar to get user consent for Credit Card assistive filling.
+ // Will run |callback| on success.
+ virtual void ConfirmCreditCardFillAssist(const CreditCard& card,
+ const base::Closure& callback) = 0;
+
// Gathers risk data and provides it to |callback|.
virtual void LoadRiskData(
const base::Callback<void(const std::string&)>& callback) = 0;
@@ -181,6 +184,13 @@ class AutofillClient {
// If the context is secure.
virtual bool IsContextSecure(const GURL& form_origin) = 0;
+
+ // Whether it is appropriate to show a signin promo for this user.
+ virtual bool ShouldShowSigninPromo() = 0;
+
+ // Starts the signin flow. Should not be called if ShouldShowSigninPromo()
+ // returns false.
+ virtual void StartSigninFlow() = 0;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_country.cc b/chromium/components/autofill/core/browser/autofill_country.cc
index f89e4c1dc04..412783b48b1 100644
--- a/chromium/components/autofill/core/browser/autofill_country.cc
+++ b/chromium/components/autofill/core/browser/autofill_country.cc
@@ -56,8 +56,8 @@ const std::string AutofillCountry::CountryCodeForLocale(
std::string country_code = icu::Locale(likely_locale.c_str()).getCountry();
// Default to the United States if we have no better guess.
- if (!ContainsValue(CountryDataMap::GetInstance()->country_codes(),
- country_code)) {
+ if (!base::ContainsValue(CountryDataMap::GetInstance()->country_codes(),
+ country_code)) {
return "US";
}
diff --git a/chromium/components/autofill/core/browser/autofill_country_unittest.cc b/chromium/components/autofill/core/browser/autofill_country_unittest.cc
index 855cda269ad..d6b3cfc0b60 100644
--- a/chromium/components/autofill/core/browser/autofill_country_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_country_unittest.cc
@@ -2,12 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <set>
#include <string>
+#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_country.h"
#include "components/autofill/core/browser/country_data.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(ANDROID)
+#include "base/android/build_info.h"
+#endif
using base::ASCIIToUTF16;
@@ -49,9 +54,20 @@ TEST(AutofillCountryTest, CountryCodeForLocale) {
// Test mapping all country codes to country names.
TEST(AutofillCountryTest, AllCountryCodesHaveCountryName) {
+ std::set<std::string> expected_failures;
+#if defined(ANDROID)
+ if (base::android::BuildInfo::GetInstance()->sdk_int() <
+ base::android::SDK_VERSION_KITKAT) {
+ expected_failures.insert("BQ");
+ expected_failures.insert("SS");
+ expected_failures.insert("XK");
+ }
+#endif
const std::vector<std::string>& country_codes =
CountryDataMap::GetInstance()->country_codes();
for (const std::string& country_code : country_codes) {
+ if (base::ContainsKey(expected_failures, country_code))
+ continue;
SCOPED_TRACE("Country code '" + country_code + "' should have a name.");
EXPECT_NE(ASCIIToUTF16(country_code),
AutofillCountry(country_code, "en").name());
diff --git a/chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.cc
new file mode 100644
index 00000000000..c79d465c41d
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.cc
@@ -0,0 +1,100 @@
+// 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 "components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "components/infobars/core/infobar_delegate.h"
+#include "grit/components_scaled_resources.h"
+#include "grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace autofill {
+
+AutofillCreditCardFillingInfoBarDelegateMobile::
+ AutofillCreditCardFillingInfoBarDelegateMobile(
+ const CreditCard& card,
+ const base::Closure& card_filling_callback)
+ : ConfirmInfoBarDelegate(),
+ card_filling_callback_(card_filling_callback),
+ had_user_interaction_(false),
+ was_shown_(false),
+ issuer_icon_id_(CreditCard::IconResourceId(card.type())),
+#if defined(OS_IOS)
+ card_label_(card.TypeAndLastFourDigits()),
+#else
+ card_label_(base::string16(kMidlineEllipsis) + card.LastFourDigits()),
+#endif
+ card_sub_label_(card.AbbreviatedExpirationDateForDisplay()) {
+}
+
+AutofillCreditCardFillingInfoBarDelegateMobile::
+ ~AutofillCreditCardFillingInfoBarDelegateMobile() {
+ if (was_shown_) {
+ AutofillMetrics::LogCreditCardFillingInfoBarMetric(
+ AutofillMetrics::INFOBAR_SHOWN);
+ if (!had_user_interaction_)
+ LogUserAction(AutofillMetrics::INFOBAR_IGNORED);
+ }
+}
+
+int AutofillCreditCardFillingInfoBarDelegateMobile::GetIconId() const {
+ return IDR_INFOBAR_AUTOFILL_CC;
+}
+
+base::string16 AutofillCreditCardFillingInfoBarDelegateMobile::GetMessageText()
+ const {
+#if defined(OS_ANDROID)
+ return l10n_util::GetStringUTF16(
+ IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_TITLE);
+#elif defined(OS_IOS)
+ // On iOS the card details are in the title of the infobar.
+ return l10n_util::GetStringFUTF16(
+ IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_FORMATTED_TITLE, card_label_);
+#endif
+}
+
+void AutofillCreditCardFillingInfoBarDelegateMobile::InfoBarDismissed() {
+ LogUserAction(AutofillMetrics::INFOBAR_DENIED);
+}
+
+bool AutofillCreditCardFillingInfoBarDelegateMobile::Accept() {
+ card_filling_callback_.Run();
+ LogUserAction(AutofillMetrics::INFOBAR_ACCEPTED);
+ return true;
+}
+
+bool AutofillCreditCardFillingInfoBarDelegateMobile::Cancel() {
+ LogUserAction(AutofillMetrics::INFOBAR_DENIED);
+ return true;
+}
+
+infobars::InfoBarDelegate::Type
+AutofillCreditCardFillingInfoBarDelegateMobile::GetInfoBarType() const {
+ return PAGE_ACTION_TYPE;
+}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+AutofillCreditCardFillingInfoBarDelegateMobile::GetIdentifier() const {
+ return AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_ANDROID;
+}
+
+base::string16 AutofillCreditCardFillingInfoBarDelegateMobile::GetButtonLabel(
+ InfoBarButton button) const {
+ return l10n_util::GetStringUTF16(
+ button == BUTTON_OK ? IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_ACCEPT
+ : IDS_NO_THANKS);
+}
+
+void AutofillCreditCardFillingInfoBarDelegateMobile::LogUserAction(
+ AutofillMetrics::InfoBarMetric user_action) {
+ DCHECK(!had_user_interaction_);
+
+ AutofillMetrics::LogCreditCardFillingInfoBarMetric(user_action);
+ had_user_interaction_ = true;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h
new file mode 100644
index 00000000000..fe1cc199e0e
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h
@@ -0,0 +1,75 @@
+// 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 COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+
+namespace infobars {
+class InfoBarManager;
+}
+
+namespace autofill {
+
+class CreditCard;
+
+// An InfoBarDelegate that enables the user to allow or deny filling credit
+// card information on a website form. Only used on mobile.
+class AutofillCreditCardFillingInfoBarDelegateMobile
+ : public ConfirmInfoBarDelegate {
+ public:
+ AutofillCreditCardFillingInfoBarDelegateMobile(
+ const CreditCard& card,
+ const base::Closure& card_filling_callback);
+ ~AutofillCreditCardFillingInfoBarDelegateMobile() override;
+
+ int issuer_icon_id() const { return issuer_icon_id_; }
+ const base::string16& card_label() const { return card_label_; }
+ const base::string16& card_sub_label() const { return card_sub_label_; }
+ void set_was_shown() { was_shown_ = true; }
+
+ // ConfirmInfoBarDelegate (publicly exposed):
+ int GetIconId() const override;
+ base::string16 GetMessageText() const override;
+ void InfoBarDismissed() override;
+ bool Accept() override;
+ bool Cancel() override;
+
+ private:
+ // ConfirmInfoBarDelegate (continued):
+ Type GetInfoBarType() const override;
+ infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+ base::string16 GetButtonLabel(InfoBarButton button) const override;
+
+ void LogUserAction(AutofillMetrics::InfoBarMetric user_action);
+
+ // The callback after having accepted the infobar; will initiate filling the
+ // credit card information.
+ base::Closure card_filling_callback_;
+
+ // Did the user ever explicitly accept or dismiss this infobar?
+ bool had_user_interaction_;
+
+ // Tracks whether the infobar was shown.
+ bool was_shown_;
+
+ // The resource ID for the icon that identifies the issuer of the card.
+ int issuer_icon_id_;
+
+ base::string16 card_label_;
+ base::string16 card_sub_label_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillCreditCardFillingInfoBarDelegateMobile);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_
diff --git a/chromium/components/autofill/core/browser/autofill_data_util.cc b/chromium/components/autofill/core/browser/autofill_data_util.cc
index 7387ed737ee..3d4c48d2463 100644
--- a/chromium/components/autofill/core/browser/autofill_data_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_data_util.cc
@@ -4,17 +4,35 @@
#include "components/autofill/core/browser/autofill_data_util.h"
+#include <algorithm>
#include <vector>
+#include "base/i18n/char_iterator.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/field_types.h"
+#include "third_party/icu/source/common/unicode/uscript.h"
namespace autofill {
namespace data_util {
namespace {
+// Mappings from Chrome card types to Payment Request API basic card payment
+// spec types and icons. Note that "generic" is not in the spec.
+// https://w3c.github.io/webpayments-methods-card/#method-id
+const PaymentRequestData kPaymentRequestData[]{
+ {"americanExpressCC", "amex", IDR_AUTOFILL_PR_AMEX},
+ {"dinersCC", "diners", IDR_AUTOFILL_PR_DINERS},
+ {"discoverCC", "discover", IDR_AUTOFILL_PR_DISCOVER},
+ {"jcbCC", "jcb", IDR_AUTOFILL_PR_JCB},
+ {"masterCardCC", "mastercard", IDR_AUTOFILL_PR_MASTERCARD},
+ {"unionPayCC", "unionpay", IDR_AUTOFILL_PR_UNIONPAY},
+ {"visaCC", "visa", IDR_AUTOFILL_PR_VISA},
+};
+const PaymentRequestData kGenericPaymentRequestData = {"genericCC", "generic",
+ IDR_AUTOFILL_PR_GENERIC};
+
const char* const name_prefixes[] = {
"1lt", "1st", "2lt", "2nd", "3rd", "admiral", "capt",
"captain", "col", "cpt", "dr", "gen", "general", "lcdr",
@@ -31,6 +49,28 @@ const char* const family_name_prefixes[] = {"d'", "de", "del", "der", "di",
"la", "le", "mc", "san", "st",
"ter", "van", "von"};
+// The common and non-ambiguous CJK surnames (last names) that have more than
+// one character.
+const char* common_cjk_multi_char_surnames[] = {
+ // Korean, taken from the list of surnames:
+ // https://ko.wikipedia.org/wiki/%ED%95%9C%EA%B5%AD%EC%9D%98_%EC%84%B1%EC%94%A8_%EB%AA%A9%EB%A1%9D
+ "남ê¶", "́‚¬ê³µ", "́„œë¬¸", "́„ ́°", "́ œê°ˆ", "황보", "ë…ê³ ", "ë§́ ˆ",
+
+ // Chinese, taken from the top 10 Chinese 2-character surnames:
+ // https://zh.wikipedia.org/wiki/%E8%A4%87%E5%A7%93#.E5.B8.B8.E8.A6.8B.E7.9A.84.E8.A4.87.E5.A7.93
+ // Simplified Chinese (mostly mainland China)
+ "欧阳", "令ç‹", "ç‡ç”«", "ä¸å®˜", "å¸å¾’", "诸葛", "å¸é©¬", "宇文", "呼延", "端木",
+ // Traditional Chinese (mostly Taiwan)
+ "張簡", "æ­é™½", "諸葛", "申屠", "å°‰é²", "å¸é¦¬", "è»’è½…", "å¤ä¾¯"
+};
+
+// All Korean surnames that have more than one character, even the
+// rare/ambiguous ones.
+const char* korean_multi_char_surnames[] = {
+ "ê°•́ „", "남ê¶", "ë…ê³ ", "ë™ë°©", "ë§́ ˆ", "́‚¬ê³µ", "́„œë¬¸", "́„ ́°",
+ "́†Œë´‰", "́–´ê¸ˆ", "́¥ê³¡", "́ œê°ˆ", "황목", "황보"
+};
+
// Returns true if |set| contains |element|, modulo a final period.
bool ContainsString(const char* const set[],
size_t set_size,
@@ -74,20 +114,173 @@ void StripSuffixes(std::vector<base::string16>* name_tokens) {
}
}
+// Find whether |name| starts with any of the strings from the array
+// |prefixes|. The returned value is the length of the prefix found, or 0 if
+// none is found.
+size_t StartsWithAny(base::StringPiece16 name, const char** prefixes,
+ size_t prefix_count) {
+ base::string16 buffer;
+ for (size_t i = 0; i < prefix_count; i++) {
+ buffer.clear();
+ base::UTF8ToUTF16(prefixes[i], strlen(prefixes[i]), &buffer);
+ if (base::StartsWith(name, buffer, base::CompareCase::SENSITIVE)) {
+ return buffer.size();
+ }
+ }
+ return 0;
+}
+
+// Returns true if |c| is a CJK (Chinese, Japanese, Korean) character, for any
+// of the CJK alphabets.
+bool IsCJKCharacter(UChar32 c) {
+ UErrorCode error = U_ZERO_ERROR;
+ switch (uscript_getScript(c, &error)) {
+ case USCRIPT_HAN: // CJK logographs, used by all 3 (but rarely for Korean)
+ case USCRIPT_HANGUL: // Korean alphabet
+ case USCRIPT_KATAKANA: // A Japanese syllabary
+ case USCRIPT_HIRAGANA: // A Japanese syllabary
+ case USCRIPT_BOPOMOFO: // Chinese semisyllabary, rarely used
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true if |c| is a Korean Hangul character.
+bool IsHangulCharacter(UChar32 c) {
+ UErrorCode error = U_ZERO_ERROR;
+ return uscript_getScript(c, &error) == USCRIPT_HANGUL;
+}
+
+// Returns true if |name| looks like a Korean name, made up entirely of Hangul
+// characters or spaces. |name| should already be confirmed to be a CJK name, as
+// per |IsCJKName()|.
+bool IsHangulName(const base::string16& name) {
+ for (base::i18n::UTF16CharIterator iter(name.data(), name.length());
+ !iter.end(); iter.Advance()) {
+ UChar32 c = iter.get();
+ if (!IsHangulCharacter(c) && !base::IsUnicodeWhitespace(c)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Tries to split a Chinese, Japanese, or Korean name into its given name &
+// surname parts, and puts the result in |parts|. If splitting did not work for
+// whatever reason, returns false.
+bool SplitCJKName(const std::vector<base::string16>& name_tokens,
+ NameParts* parts) {
+ // The convention for CJK languages is to put the surname (last name) first,
+ // and the given name (first name) second. In a continuous text, there is
+ // normally no space between the two parts of the name. When entering their
+ // name into a field, though, some people add a space to disambiguate. CJK
+ // names (almost) never have a middle name.
+ if (name_tokens.size() == 1) {
+ // There is no space between the surname and given name. Try to infer where
+ // to separate between the two. Most Chinese and Korean surnames have only
+ // one character, but there are a few that have 2. If the name does not
+ // start with a surname from a known list, default to 1 character.
+ //
+ // TODO(crbug.com/89111): Japanese names with no space will be mis-split,
+ // since we don't have a list of Japanese last names. In the Han alphabet,
+ // it might also be difficult for us to differentiate between Chinese &
+ // Japanese names.
+ const base::string16& name = name_tokens.front();
+ const bool is_korean = IsHangulName(name);
+ size_t surname_length = 0;
+ if (is_korean && name.size() > 3) {
+ // 4-character Korean names are more likely to be 2/2 than 1/3, so use
+ // the full list of Korean 2-char surnames. (instead of only the common
+ // ones)
+ surname_length = std::max<size_t>(
+ 1, StartsWithAny(name, korean_multi_char_surnames,
+ arraysize(korean_multi_char_surnames)));
+ } else {
+ // Default to 1 character if the surname is not in
+ // |common_cjk_multi_char_surnames|.
+ surname_length = std::max<size_t>(
+ 1, StartsWithAny(name, common_cjk_multi_char_surnames,
+ arraysize(common_cjk_multi_char_surnames)));
+ }
+ parts->family = name.substr(0, surname_length);
+ parts->given = name.substr(surname_length);
+ return true;
+ }
+ if (name_tokens.size() == 2) {
+ // The user entered a space between the two name parts. This makes our job
+ // easier. Family name first, given name second.
+ parts->family = name_tokens[0];
+ parts->given = name_tokens[1];
+ return true;
+ }
+ // We don't know what to do if there are more than 2 tokens.
+ return false;
+}
+
} // namespace
+bool IsCJKName(const base::string16& name) {
+ // The name is considered to be a CJK name if it is only CJK characters,
+ // spaces, and "middle dot" separators, with at least one CJK character, and
+ // no more than 2 words.
+ //
+ // Chinese and Japanese names are usually spelled out using the Han characters
+ // (logographs), which constitute the "CJK Unified Ideographs" block in
+ // Unicode, also referred to as Unihan. Korean names are usually spelled out
+ // in the Korean alphabet (Hangul), although they do have a Han equivalent as
+ // well.
+ //
+ // The middle dot is used as a separator for foreign names in Japanese.
+ static const base::char16 kKatakanaMiddleDot = u'\u30FB';
+ // A (common?) typo for 'KATAKANA MIDDLE DOT' (U+30FB).
+ static const base::char16 kMiddleDot = u'\u00B7';
+ bool previous_was_cjk = false;
+ size_t word_count = 0;
+ for (base::i18n::UTF16CharIterator iter(name.data(), name.length());
+ !iter.end(); iter.Advance()) {
+ UChar32 c = iter.get();
+ const bool is_cjk = IsCJKCharacter(c);
+ if (!is_cjk && !base::IsUnicodeWhitespace(c) && c != kKatakanaMiddleDot &&
+ c != kMiddleDot) {
+ return false;
+ }
+ if (is_cjk && !previous_was_cjk) {
+ word_count++;
+ }
+ previous_was_cjk = is_cjk;
+ }
+ return word_count > 0 && word_count < 3;
+}
+
NameParts SplitName(const base::string16& name) {
- std::vector<base::string16> name_tokens =
- base::SplitString(name, base::ASCIIToUTF16(" ,"), base::KEEP_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY);
+ static const base::char16 kWordSeparators[] = {
+ u' ', // ASCII space.
+ u',', // ASCII comma.
+ u'\u3000', // 'IDEOGRAPHIC SPACE' (U+3000).
+ u'\u30FB', // 'KATAKANA MIDDLE DOT' (U+30FB).
+ u'\u00B7', // 'MIDDLE DOT' (U+00B7).
+ u'\0' // End of string.
+ };
+ std::vector<base::string16> name_tokens = base::SplitString(
+ name, kWordSeparators, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
StripPrefixes(&name_tokens);
+ NameParts parts;
+
+ // TODO(crbug.com/89111): Hungarian, Tamil, Telugu, and Vietnamese also have
+ // the given name before the surname, and should be treated as special cases
+ // too.
+
+ // Treat CJK names differently.
+ if (IsCJKName(name) && SplitCJKName(name_tokens, &parts)) {
+ return parts;
+ }
+
// Don't assume "Ma" is a suffix in John Ma.
if (name_tokens.size() > 2)
StripSuffixes(&name_tokens);
- NameParts parts;
-
if (name_tokens.empty()) {
// Bad things have happened; just assume the whole thing is a given name.
parts.given = name;
@@ -129,6 +322,30 @@ NameParts SplitName(const base::string16& name) {
return parts;
}
+base::string16 JoinNameParts(const base::string16& given,
+ const base::string16& middle,
+ const base::string16& family) {
+ // First Middle Last
+ std::vector<base::string16> full_name;
+ if (!given.empty())
+ full_name.push_back(given);
+
+ if (!middle.empty())
+ full_name.push_back(middle);
+
+ if (!family.empty())
+ full_name.push_back(family);
+
+ const char* separator = " ";
+ if (IsCJKName(given) && IsCJKName(family) && middle.empty()) {
+ // LastFirst
+ std::reverse(full_name.begin(), full_name.end());
+ separator = "";
+ }
+
+ return base::JoinString(full_name, base::ASCIIToUTF16(separator));
+}
+
bool ProfileMatchesFullName(const base::string16 full_name,
const autofill::AutofillProfile& profile) {
const base::string16 kSpace = base::ASCIIToUTF16(" ");
@@ -165,8 +382,41 @@ bool ProfileMatchesFullName(const base::string16 full_name,
return true;
}
+ // Last First
+ candidate = profile.GetRawInfo(autofill::NAME_LAST) + kSpace +
+ profile.GetRawInfo(autofill::NAME_FIRST);
+ if (!full_name.compare(candidate)) {
+ return true;
+ }
+
+ // LastFirst
+ candidate = profile.GetRawInfo(autofill::NAME_LAST) +
+ profile.GetRawInfo(autofill::NAME_FIRST);
+ if (!full_name.compare(candidate)) {
+ return true;
+ }
+
return false;
}
+const PaymentRequestData& GetPaymentRequestData(const std::string& type) {
+ for (size_t i = 0; i < arraysize(kPaymentRequestData); ++i) {
+ if (type == kPaymentRequestData[i].card_type)
+ return kPaymentRequestData[i];
+ }
+ return kGenericPaymentRequestData;
+}
+
+const char* GetCardTypeForBasicCardPaymentType(
+ const std::string& basic_card_payment_type) {
+ for (size_t i = 0; i < arraysize(kPaymentRequestData); ++i) {
+ if (basic_card_payment_type ==
+ kPaymentRequestData[i].basic_card_payment_type) {
+ return kPaymentRequestData[i].card_type;
+ }
+ }
+ return kGenericPaymentRequestData.card_type;
+}
+
} // namespace data_util
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_data_util.h b/chromium/components/autofill/core/browser/autofill_data_util.h
index 1c1e1353af3..d398e476b68 100644
--- a/chromium/components/autofill/core/browser/autofill_data_util.h
+++ b/chromium/components/autofill/core/browser/autofill_data_util.h
@@ -7,6 +7,7 @@
#include "base/strings/string16.h"
#include "components/autofill/core/browser/autofill_profile.h"
+#include "grit/components_scaled_resources.h"
namespace autofill {
namespace data_util {
@@ -17,17 +18,44 @@ struct NameParts {
base::string16 family;
};
+// Used to map Chrome card types to Payment Request API basic card payment spec
+// types and icons. https://w3c.github.io/webpayments-methods-card/#method-id
+struct PaymentRequestData {
+ const char* card_type;
+ const char* basic_card_payment_type;
+ const int icon_resource_id;
+};
+
+// Returns true if |name| looks like a CJK name (or some kind of mish-mash of
+// the three, at least).
+bool IsCJKName(const base::string16& name);
+
// TODO(crbug.com/586510): Investigate the use of app_locale to do better name
// splitting.
// Returns the different name parts (given, middle and family names) of the full
// |name| passed as a parameter.
NameParts SplitName(const base::string16& name);
+// Concatenates the name parts together in the correct order (based on script),
+// and returns the result.
+base::string16 JoinNameParts(const base::string16& given,
+ const base::string16& middle,
+ const base::string16& family);
+
// Returns true iff |full_name| is a concatenation of some combination of the
// first/middle/last (incl. middle initial) in |profile|.
bool ProfileMatchesFullName(const base::string16 full_name,
const autofill::AutofillProfile& profile);
+// Returns the Payment Request API basic card payment spec data for the provided
+// autofill credit card |type|. Will set the type and the icon to "generic" for
+// any unrecognized type.
+const PaymentRequestData& GetPaymentRequestData(const std::string& type);
+
+// Returns the autofill credit card type string for the provided Payment Request
+// API basic card payment spec |type|.
+const char* GetCardTypeForBasicCardPaymentType(const std::string& type);
+
} // namespace data_util
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc b/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
index 707ac4925f1..584690d7871 100644
--- a/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_data_util_unittest.cc
@@ -11,6 +11,46 @@
namespace autofill {
namespace data_util {
+TEST(AutofillDataUtilTest, IsCJKName) {
+ typedef struct {
+ const char* full_name;
+ bool is_cjk;
+ } TestCase;
+
+ TestCase test_cases[] = {
+ // Non-CJK language with only ASCII characters.
+ {"Homer Jay Simpson", false},
+ // Non-CJK language with some ASCII characters.
+ {"ÉloĂ¯se ParĂ©", false},
+ // Non-CJK language with no ASCII characters.
+ {"ΣωκÏάτης", false},
+
+ // (Simplified) Chinese name, Unihan.
+ {"刘翔", true},
+ // (Simplified) Chinese name, Unihan, with an ASCII space.
+ {"æˆ é¾™", true},
+ // Korean name, Hangul.
+ {"́†¡́§€í¨", true},
+ // Korean name, Hangul, with an 'IDEOGRAPHIC SPACE' (U+3000).
+ {"ê¹€ă€€́¢…êµ­", true},
+ // Japanese name, Unihan.
+ {"山田貴洋", true},
+ // Japanese name, Katakana, with a 'KATAKANA MIDDLE DOT' (U+30FB).
+ {"ăƒ“ăƒ«ăƒ»ă‚²ă‚¤ăƒ„", true},
+ // Japanese name, Katakana, with a 'MIDDLE DOT' (U+00B7) (likely a typo).
+ {"ăƒ“ăƒ«Â·ă‚²ă‚¤ăƒ„", true},
+
+ // CJK names don't have a middle name, so a 3-part name is bogus to us.
+ {"반 기 문", false}
+ };
+
+ for (const TestCase& test_case : test_cases) {
+ EXPECT_EQ(test_case.is_cjk,
+ IsCJKName(base::UTF8ToUTF16(test_case.full_name)))
+ << "Failed for: " << test_case.full_name;
+ }
+}
+
TEST(AutofillDataUtilTest, SplitName) {
typedef struct {
std::string full_name;
@@ -20,7 +60,7 @@ TEST(AutofillDataUtilTest, SplitName) {
} TestCase;
- TestCase test_cases[] = {
+ const TestCase test_cases[] = {
// Full name including given, middle and family names.
{"Homer Jay Simpson", "Homer", "Jay", "Simpson"},
// No middle name.
@@ -32,7 +72,45 @@ TEST(AutofillDataUtilTest, SplitName) {
// Exception to the name suffix removal.
{"John Ma", "John", "", "Ma"},
// Common family name prefixes not considered a middle name.
- {"Milhouse Van Houten", "Milhouse", "", "Van Houten"}};
+ {"Milhouse Van Houten", "Milhouse", "", "Van Houten"},
+
+ // CJK names have reverse order (surname goes first, given name goes
+ // second).
+ {"å­« å¾·æ˜", "å¾·æ˜", "", "å­«"}, // Chinese name, Unihan
+ {"å­«ă€€å¾·æ˜", "å¾·æ˜", "", "å­«"}, // Chinese name, Unihan, 'IDEOGRAPHIC SPACE'
+ {"í™ ê¸¸ë™", "길ë™", "", "í™"}, // Korean name, Hangul
+ {"山田 貴洋", "貴洋", "", "山田"}, // Japanese name, Unihan
+
+ // In Japanese, foreign names use 'KATAKANA MIDDLE DOT' (U+30FB) as a
+ // separator. There is no consensus for the ordering. For now, we use the
+ // same ordering as regular Japanese names ("lastăƒ»first").
+ {"ă‚²ă‚¤ăƒ„ăƒ»ăƒ“ăƒ«", "ăƒ“ăƒ«", "", "ă‚²ă‚¤ăƒ„"}, // Foreign name in Japanese, Katakana
+ // 'KATAKANA MIDDLE DOT' is occasionally typoed as 'MIDDLE DOT' (U+00B7).
+ {"ă‚²ă‚¤ăƒ„Â·ăƒ“ăƒ«", "ăƒ“ăƒ«", "", "ă‚²ă‚¤ăƒ„"}, // Foreign name in Japanese, Katakana
+
+ // CJK names don't usually have a space in the middle, but most of the
+ // time, the surname is only one character (in Chinese & Korean).
+ {"́µœ́„±í›ˆ", "́„±í›ˆ", "", "́µœ"}, // Korean name, Hangul
+ {"刘翔", "翔", "", "刘"}, // (Simplified) Chinese name, Unihan
+ {"å‰ç¿”", "ç¿”", "", "å‰"}, // (Traditional) Chinese name, Unihan
+
+ // There are a few exceptions. Occasionally, the surname has two
+ // characters.
+ {"남ê¶ë„", "ë„", "", "남ê¶"}, // Korean name, Hangul
+ {"황보혜́ •", "혜́ •", "", "황보"}, // Korean name, Hangul
+ {"æ­é™½é–", "é–", "", "æ­é™½"}, // (Traditional) Chinese name, Unihan
+
+ // In Korean, some 2-character surnames are rare/ambiguous, like "ê°•́ „":
+ // "ê°•" is a common surname, and "́ „" can be part of a given name. In
+ // those cases, we assume it's 1/2 for 3-character names, or 2/2 for
+ // 4-character names.
+ {"ê°•́ „í¬", "́ „í¬", "", "ê°•"}, // Korean name, Hangul
+ {"황목́¹˜́¹", "́¹˜́¹", "", "황목"}, // Korean name, Hangul
+
+ // It occasionally happens that a full name is 2 characters, 1/1.
+ {"́´ë„", "ë„", "", "́´"}, // Korean name, Hangul
+ {"å­«æ–‡", "æ–‡", "", "å­«"} // Chinese name, Unihan
+ };
for (TestCase test_case : test_cases) {
NameParts name_parts = SplitName(base::UTF8ToUTF16(test_case.full_name));
@@ -43,6 +121,41 @@ TEST(AutofillDataUtilTest, SplitName) {
}
}
+TEST(AutofillDataUtilTest, JoinNameParts) {
+ typedef struct {
+ std::string given_name;
+ std::string middle_name;
+ std::string family_name;
+ std::string full_name;
+ } TestCase;
+
+ TestCase test_cases[] = {
+ // Full name including given, middle and family names.
+ {"Homer", "Jay", "Simpson", "Homer Jay Simpson"},
+ // No middle name.
+ {"Moe", "", "Szyslak", "Moe Szyslak"},
+
+ // CJK names have reversed order, no space.
+ {"å¾·æ˜", "", "å­«", "å­«å¾·æ˜"}, // Chinese name, Unihan
+ {"길ë™", "", "í™", "í™ê¸¸ë™"}, // Korean name, Hangul
+ {"貴洋", "", "山田", "山田貴洋"}, // Japanese name, Unihan
+
+ // These are no CJK names for us, they're just bogus.
+ {"Homer", "", "ă‚·ăƒ³ăƒ—ă‚½ăƒ³", "Homer ă‚·ăƒ³ăƒ—ă‚½ăƒ³"},
+ {"ăƒ›ăƒ¼ăƒăƒ¼", "", "Simpson", "ăƒ›ăƒ¼ăƒăƒ¼ Simpson"},
+ {"반", "기", "문", "반 기 문"} // Has a middle-name, too unusual
+ };
+
+ for (const TestCase& test_case : test_cases) {
+ base::string16 joined = JoinNameParts(
+ base::UTF8ToUTF16(test_case.given_name),
+ base::UTF8ToUTF16(test_case.middle_name),
+ base::UTF8ToUTF16(test_case.family_name));
+
+ EXPECT_EQ(base::UTF8ToUTF16(test_case.full_name), joined);
+ }
+}
+
TEST(AutofillDataUtilTest, ProfileMatchesFullName) {
autofill::AutofillProfile profile;
autofill::test::SetProfileInfo(
@@ -60,6 +173,12 @@ TEST(AutofillDataUtilTest, ProfileMatchesFullName) {
EXPECT_TRUE(
ProfileMatchesFullName(base::UTF8ToUTF16("First M. Last"), profile));
+ EXPECT_TRUE(
+ ProfileMatchesFullName(base::UTF8ToUTF16("Last First"), profile));
+
+ EXPECT_TRUE(
+ ProfileMatchesFullName(base::UTF8ToUTF16("LastFirst"), profile));
+
EXPECT_FALSE(
ProfileMatchesFullName(base::UTF8ToUTF16("Kirby Puckett"), profile));
}
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc
index c22c2d5c480..021a85024ea 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc
@@ -11,7 +11,6 @@
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/rand_util.h"
-#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/autofill_driver.h"
@@ -101,8 +100,6 @@ std::ostream& operator<<(std::ostream& out,
out << "\n name: " << field.name();
if (!field.type().empty())
out << "\n type: " << field.type();
- if (!field.label().empty())
- out << "\n label: " << field.label();
}
}
return out;
@@ -131,8 +128,6 @@ std::ostream& operator<<(std::ostream& out,
out << "\n autocomplete: " << field.autocomplete();
if (!field.type().empty())
out << "\n type: " << field.type();
- if (!field.label().empty())
- out << "\n label: " << field.label();
if (field.generation_type())
out << "\n generation_type: " << field.generation_type();
}
@@ -158,10 +153,7 @@ AutofillDownloadManager::AutofillDownloadManager(AutofillDriver* driver,
DCHECK(observer_);
}
-AutofillDownloadManager::~AutofillDownloadManager() {
- STLDeleteContainerPairFirstPointers(url_fetchers_.begin(),
- url_fetchers_.end());
-}
+AutofillDownloadManager::~AutofillDownloadManager() = default;
bool AutofillDownloadManager::StartQueryRequest(
const std::vector<FormStructure*>& forms) {
@@ -223,7 +215,7 @@ bool AutofillDownloadManager::StartUploadRequest(
}
FormRequestData request_data;
- request_data.form_signatures.push_back(form.FormSignature());
+ request_data.form_signatures.push_back(form.FormSignatureAsStr());
request_data.request_type = AutofillDownloadManager::REQUEST_UPLOAD;
request_data.payload = payload;
@@ -241,12 +233,13 @@ bool AutofillDownloadManager::StartRequest(
// Id is ignored for regular chrome, in unit test id's for fake fetcher
// factory will be 0, 1, 2, ...
- net::URLFetcher* fetcher =
- net::URLFetcher::Create(fetcher_id_for_unittest_++, request_url,
- net::URLFetcher::POST, this).release();
+ std::unique_ptr<net::URLFetcher> owned_fetcher = net::URLFetcher::Create(
+ fetcher_id_for_unittest_++, request_url, net::URLFetcher::POST, this);
+ net::URLFetcher* fetcher = owned_fetcher.get();
data_use_measurement::DataUseUserData::AttachToFetcher(
fetcher, data_use_measurement::DataUseUserData::AUTOFILL);
- url_fetchers_[fetcher] = request_data;
+ url_fetchers_[fetcher] =
+ std::make_pair(std::move(owned_fetcher), request_data);
fetcher->SetAutomaticallyRetryOn5xx(false);
fetcher->SetRequestContext(request_context);
fetcher->SetUploadData("text/proto", request_data.payload);
@@ -316,16 +309,15 @@ std::string AutofillDownloadManager::GetCombinedSignature(
void AutofillDownloadManager::OnURLFetchComplete(
const net::URLFetcher* source) {
- std::map<net::URLFetcher *, FormRequestData>::iterator it =
- url_fetchers_.find(const_cast<net::URLFetcher*>(source));
+ auto it = url_fetchers_.find(const_cast<net::URLFetcher*>(source));
if (it == url_fetchers_.end()) {
// Looks like crash on Mac is possibly caused with callback entering here
// with unknown fetcher when network is refreshed.
return;
}
- std::string request_type(RequestTypeToString(it->second.request_type));
+ std::string request_type(RequestTypeToString(it->second.second.request_type));
- CHECK(it->second.form_signatures.size());
+ CHECK(it->second.second.form_signatures.size());
bool success = source->GetResponseCode() == net::HTTP_OK;
fetcher_backoff_.InformOfRequest(success);
@@ -335,28 +327,28 @@ void AutofillDownloadManager::OnURLFetchComplete(
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(base::IgnoreResult(&AutofillDownloadManager::StartRequest),
- weak_factory_.GetWeakPtr(), it->second),
+ weak_factory_.GetWeakPtr(), it->second.second),
fetcher_backoff_.GetTimeUntilRelease());
VLOG(1) << "AutofillDownloadManager: " << request_type
<< " request has failed with response "
<< source->GetResponseCode();
- observer_->OnServerRequestError(it->second.form_signatures[0],
- it->second.request_type,
+ observer_->OnServerRequestError(it->second.second.form_signatures[0],
+ it->second.second.request_type,
source->GetResponseCode());
} else {
std::string response_body;
source->GetResponseAsString(&response_body);
- if (it->second.request_type == AutofillDownloadManager::REQUEST_QUERY) {
- CacheQueryRequest(it->second.form_signatures, response_body);
+ if (it->second.second.request_type ==
+ AutofillDownloadManager::REQUEST_QUERY) {
+ CacheQueryRequest(it->second.second.form_signatures, response_body);
observer_->OnLoadedServerPredictions(std::move(response_body),
- it->second.form_signatures);
+ it->second.second.form_signatures);
} else {
VLOG(1) << "AutofillDownloadManager: upload request has succeeded.";
observer_->OnUploadedPossibleFieldTypes();
}
}
- delete it->first;
url_fetchers_.erase(it);
}
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.h b/chromium/components/autofill/core/browser/autofill_download_manager.h
index c470614f187..c1b39b1d58b 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.h
@@ -8,6 +8,7 @@
#include <stddef.h>
#include <list>
#include <map>
+#include <memory>
#include <string>
#include <utility>
#include <vector>
@@ -135,8 +136,11 @@ class AutofillDownloadManager : public net::URLFetcherDelegate {
// For each requested form for both query and upload we create a separate
// request and save its info. As url fetcher is identified by its address
- // we use a map between fetchers and info.
- std::map<net::URLFetcher*, FormRequestData> url_fetchers_;
+ // we use a map between fetchers and info. The value type is a pair of an
+ // owning pointer to the key and the actual FormRequestData.
+ std::map<net::URLFetcher*,
+ std::pair<std::unique_ptr<net::URLFetcher>, FormRequestData>>
+ url_fetchers_;
// Cached QUERY requests.
QueryRequestCache cached_forms_;
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
index 1a359d04b13..e9bfcb30cc9 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -277,7 +277,7 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) {
EXPECT_EQ(AutofillDownloadManagerTest::REQUEST_UPLOAD_FAILED,
responses_.front().type_of_response);
EXPECT_EQ(net::HTTP_NOT_FOUND, responses_.front().error);
- EXPECT_EQ(form_structures[1]->FormSignature(),
+ EXPECT_EQ(form_structures[1]->FormSignatureAsStr(),
responses_.front().signature);
// Expected response on non-query request is an empty string.
EXPECT_EQ(std::string(), responses_.front().response);
@@ -426,7 +426,7 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Upload) {
EXPECT_EQ(AutofillDownloadManagerTest::REQUEST_UPLOAD_FAILED,
responses_.front().type_of_response);
EXPECT_EQ(net::HTTP_NOT_FOUND, responses_.front().error);
- EXPECT_EQ(form_structure->FormSignature(), responses_.front().signature);
+ EXPECT_EQ(form_structure->FormSignatureAsStr(), responses_.front().signature);
// Expected response on non-query request is an empty string.
EXPECT_EQ(std::string(), responses_.front().response);
responses_.pop_front();
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc
index 364b8c622c9..5d22b24a684 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments.cc
@@ -7,18 +7,27 @@
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/prefs/pref_service.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_service.h"
+#include "components/variations/variations_associated_data.h"
#include "google_apis/gaia/gaia_auth_util.h"
namespace autofill {
+const base::Feature kAutofillCreditCardAssist{
+ "AutofillCreditCardAssist", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillCreditCardSigninPromo{
+ "AutofillCreditCardSigninPromo", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kAutofillProfileCleanup{"AutofillProfileCleanup",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillScanCardholderName{
+ "AutofillScanCardholderName", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kCreditCardSigninPromoImpressionLimitParamKey[] = "impression_limit";
bool IsAutofillEnabled(const PrefService* pref_service) {
return pref_service->GetBoolean(prefs::kAutofillEnabled);
@@ -34,6 +43,29 @@ bool IsAutofillProfileCleanupEnabled() {
return base::FeatureList::IsEnabled(kAutofillProfileCleanup);
}
+bool IsAutofillCreditCardSigninPromoEnabled() {
+ return base::FeatureList::IsEnabled(kAutofillCreditCardSigninPromo);
+}
+
+bool IsAutofillCreditCardAssistEnabled() {
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+ return false;
+#else
+ return base::FeatureList::IsEnabled(kAutofillCreditCardAssist);
+#endif
+}
+
+int GetCreditCardSigninPromoImpressionLimit() {
+ int impression_limit;
+ std::string param_value = variations::GetVariationParamValueByFeature(
+ kAutofillCreditCardSigninPromo,
+ kCreditCardSigninPromoImpressionLimitParamKey);
+ if (!param_value.empty() && base::StringToInt(param_value, &impression_limit))
+ return impression_limit;
+
+ return 0;
+}
+
bool OfferStoreUnmaskedCards() {
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// The checkbox can be forced on with a flag, but by default we don't store
@@ -60,7 +92,7 @@ bool OfferStoreUnmaskedCards() {
}
bool IsCreditCardUploadEnabled(const PrefService* pref_service,
- const sync_driver::SyncService* sync_service,
+ const syncer::SyncService* sync_service,
const std::string& user_email) {
// Query the field trial first to ensure UMA always reports the correct group.
std::string group_name =
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.h b/chromium/components/autofill/core/browser/autofill_experiments.h
index 390ed55a49d..d4ae183cf20 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.h
+++ b/chromium/components/autofill/core/browser/autofill_experiments.h
@@ -7,19 +7,23 @@
#include <string>
+class PrefService;
+
namespace base {
struct Feature;
}
-namespace sync_driver {
+namespace syncer {
class SyncService;
}
-class PrefService;
-
namespace autofill {
+extern const base::Feature kAutofillCreditCardAssist;
+extern const base::Feature kAutofillCreditCardSigninPromo;
extern const base::Feature kAutofillProfileCleanup;
+extern const base::Feature kAutofillScanCardholderName;
+extern const char kCreditCardSigninPromoImpressionLimitParamKey[];
// Returns true if autofill should be enabled. See also
// IsInAutofillSuggestionsDisabledExperiment below.
@@ -34,6 +38,16 @@ bool IsInAutofillSuggestionsDisabledExperiment();
// Returns whether the Autofill profile cleanup feature is enabled.
bool IsAutofillProfileCleanupEnabled();
+// Returns whether the Autofill credit card signin promo should be shown.
+bool IsAutofillCreditCardSigninPromoEnabled();
+
+// Returns whether the Autofill credit card assist infobar should be shown.
+bool IsAutofillCreditCardAssistEnabled();
+
+// Returns the maximum number of impressions of the credit card signin promo, or
+// 0 if there are no limits.
+int GetCreditCardSigninPromoImpressionLimit();
+
// Returns true if the user should be offered to locally store unmasked cards.
// This controls whether the option is presented at all rather than the default
// response of the option.
@@ -43,7 +57,7 @@ bool OfferStoreUnmaskedCards();
// requires the appropriate flags and user settings to be true and the user to
// be a member of a supported domain.
bool IsCreditCardUploadEnabled(const PrefService* pref_service,
- const sync_driver::SyncService* sync_service,
+ const syncer::SyncService* sync_service,
const std::string& user_email);
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
index eaa1fd547ea..6b04aa5b573 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
@@ -12,6 +12,7 @@
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/user_metrics.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -32,9 +33,10 @@ AutofillExternalDelegate::AutofillExternalDelegate(AutofillManager* manager,
: manager_(manager),
driver_(driver),
query_id_(0),
- has_suggestion_(false),
+ has_autofill_suggestions_(false),
has_shown_popup_for_current_edit_(false),
should_show_scan_credit_card_(false),
+ should_show_cc_signin_promo_(false),
has_shown_address_book_prompt(false),
weak_ptr_factory_(this) {
DCHECK(manager);
@@ -55,6 +57,8 @@ void AutofillExternalDelegate::OnQuery(int query_id,
element_bounds_ = element_bounds;
should_show_scan_credit_card_ =
manager_->ShouldShowScanCreditCard(query_form_, query_field_);
+ should_show_cc_signin_promo_ =
+ manager_->ShouldShowCreditCardSigninPromo(query_form_, query_field_);
}
void AutofillExternalDelegate::OnSuggestionsReturned(
@@ -63,15 +67,19 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
if (query_id != query_id_)
return;
+ // The suggestions and warnings are "above the fold" and are separated from
+ // other menu items with a separator.
std::vector<Suggestion> suggestions(input_suggestions);
-
// Add or hide warnings as appropriate.
ApplyAutofillWarnings(&suggestions);
#if !defined(OS_ANDROID)
- // Add a separator to go between the values and menu items.
- suggestions.push_back(Suggestion());
- suggestions.back().frontend_id = POPUP_ITEM_ID_SEPARATOR;
+ // If there are above the fold suggestions at this point, add a separator to
+ // go between the values and menu items.
+ if (!suggestions.empty()) {
+ suggestions.push_back(Suggestion());
+ suggestions.back().frontend_id = POPUP_ITEM_ID_SEPARATOR;
+ }
#endif
if (should_show_scan_credit_card_) {
@@ -89,22 +97,45 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
// Only include "Autofill Options" special menu item if we have Autofill
// suggestions.
- has_suggestion_ = false;
+ has_autofill_suggestions_ = false;
for (size_t i = 0; i < suggestions.size(); ++i) {
if (suggestions[i].frontend_id > 0) {
- has_suggestion_ = true;
+ has_autofill_suggestions_ = true;
break;
}
}
- if (has_suggestion_)
+ if (has_autofill_suggestions_)
ApplyAutofillOptions(&suggestions);
+ // Append the credit card signin promo, if appropriate (there are no other
+ // suggestions).
+ if (suggestions.empty() && should_show_cc_signin_promo_) {
+// No separator on Android.
#if !defined(OS_ANDROID)
- // Remove the separator if it is the last element.
- DCHECK_GT(suggestions.size(), 0U);
- if (suggestions.back().frontend_id == POPUP_ITEM_ID_SEPARATOR)
+ // If there are autofill suggestions, the "Autofill options" row was added
+ // above. Add a separator between it and the signin promo.
+ if (has_autofill_suggestions_) {
+ suggestions.push_back(Suggestion());
+ suggestions.back().frontend_id = POPUP_ITEM_ID_SEPARATOR;
+ }
+#endif
+
+ Suggestion signin_promo_suggestion(
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_CREDIT_CARD_SIGNIN_PROMO));
+ signin_promo_suggestion.frontend_id =
+ POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO;
+ suggestions.push_back(signin_promo_suggestion);
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Impression_FromAutofillDropdown"));
+ }
+
+#if !defined(OS_ANDROID)
+ // Remove the separator if there is one, and if it is the last element.
+ if (!suggestions.empty() &&
+ suggestions.back().frontend_id == POPUP_ITEM_ID_SEPARATOR) {
suggestions.pop_back();
+ }
#endif
// If anything else is added to modify the values after inserting the data
@@ -139,10 +170,9 @@ void AutofillExternalDelegate::SetCurrentDataListValues(
void AutofillExternalDelegate::OnPopupShown() {
manager_->DidShowSuggestions(
- has_suggestion_ && !has_shown_popup_for_current_edit_,
- query_form_,
- query_field_);
- has_shown_popup_for_current_edit_ |= has_suggestion_;
+ has_autofill_suggestions_ && !has_shown_popup_for_current_edit_,
+ query_form_, query_field_);
+ has_shown_popup_for_current_edit_ |= has_autofill_suggestions_;
}
void AutofillExternalDelegate::OnPopupHidden() {
@@ -181,6 +211,8 @@ void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
} else if (identifier == POPUP_ITEM_ID_SCAN_CREDIT_CARD) {
manager_->client()->ScanCreditCard(base::Bind(
&AutofillExternalDelegate::OnCreditCardScanned, GetWeakPtr()));
+ } else if (identifier == POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO) {
+ manager_->client()->StartSigninFlow();
} else {
if (identifier > 0) // Denotes an Autofill suggestion.
AutofillMetrics::LogAutofillSuggestionAcceptedIndex(position);
@@ -243,14 +275,9 @@ base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
-void AutofillExternalDelegate::OnCreditCardScanned(
- const base::string16& card_number,
- int expiration_month,
- int expiration_year) {
- manager_->FillCreditCardForm(
- query_id_, query_form_, query_field_,
- CreditCard(card_number, expiration_month, expiration_year),
- base::string16());
+void AutofillExternalDelegate::OnCreditCardScanned(const CreditCard& card) {
+ manager_->FillCreditCardForm(query_id_, query_form_, query_field_, card,
+ base::string16());
}
void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
@@ -319,12 +346,12 @@ void AutofillExternalDelegate::InsertDataListValues(
std::set<base::string16> data_list_set(data_list_values_.begin(),
data_list_values_.end());
suggestions->erase(
- std::remove_if(suggestions->begin(), suggestions->end(),
- [&data_list_set](const Suggestion& suggestion) {
- return suggestion.frontend_id ==
- POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY &&
- ContainsKey(data_list_set, suggestion.value);
- }),
+ std::remove_if(
+ suggestions->begin(), suggestions->end(),
+ [&data_list_set](const Suggestion& suggestion) {
+ return suggestion.frontend_id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY &&
+ base::ContainsKey(data_list_set, suggestion.value);
+ }),
suggestions->end());
#if !defined(OS_ANDROID)
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.h b/chromium/components/autofill/core/browser/autofill_external_delegate.h
index f880c750d6c..22a002f7e0d 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.h
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.h
@@ -22,6 +22,7 @@ namespace autofill {
class AutofillDriver;
class AutofillManager;
+class CreditCard;
// TODO(csharp): A lot of the logic in this class is copied from autofillagent.
// Once Autofill is moved out of WebKit this class should be the only home for
@@ -91,9 +92,7 @@ class AutofillExternalDelegate : public AutofillPopupDelegate {
FillCreditCardForm);
// Called when a credit card is scanned using device camera.
- void OnCreditCardScanned(const base::string16& card_number,
- int expiration_month,
- int expiration_year);
+ void OnCreditCardScanned(const CreditCard& card);
// Fills the form with the Autofill data corresponding to |unique_id|.
// If |is_preview| is true then this is just a preview to show the user what
@@ -133,7 +132,7 @@ class AutofillExternalDelegate : public AutofillPopupDelegate {
gfx::RectF element_bounds_;
// Does the popup include any Autofill profile or credit card suggestions?
- bool has_suggestion_;
+ bool has_autofill_suggestions_;
// Have we already shown Autofill suggestions for the field the user is
// currently editing? Used to keep track of state for metrics logging.
@@ -142,6 +141,9 @@ class AutofillExternalDelegate : public AutofillPopupDelegate {
// FIXME
bool should_show_scan_credit_card_;
+ // Whether the credit card signin promo should be shown to the user.
+ bool should_show_cc_signin_promo_;
+
// Whether the access Address Book prompt has ever been shown for the current
// |query_form_|. This variable is only used on OSX.
bool has_shown_address_book_prompt;
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
index fab6c933fb7..59add4d8584 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -12,9 +12,11 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
+#include "base/test/user_action_tester.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/popup_item_ids.h"
#include "components/autofill/core/browser/suggestion_test_helpers.h"
#include "components/autofill/core/browser/test_autofill_client.h"
@@ -76,6 +78,8 @@ class MockAutofillClient : public TestAutofillClient {
MOCK_METHOD0(HideAutofillPopup, void());
+ MOCK_METHOD0(StartSigninFlow, void());
+
private:
DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
};
@@ -91,6 +95,9 @@ class MockAutofillManager : public AutofillManager {
MOCK_METHOD2(ShouldShowScanCreditCard,
bool(const FormData& form, const FormFieldData& field));
+ MOCK_METHOD2(ShouldShowCreditCardSigninPromo,
+ bool(const FormData& form, const FormFieldData& field));
+
MOCK_METHOD5(FillOrPreviewForm,
void(AutofillDriver::RendererFormDataAction action,
int query_id,
@@ -188,6 +195,80 @@ TEST_F(AutofillExternalDelegateUnitTest, TestExternalDelegateVirtualCalls) {
0);
}
+// Test that our external delegate does not add the signin promo and its
+// separator in the popup items when there are suggestions.
+TEST_F(AutofillExternalDelegateUnitTest,
+ TestSigninPromoIsNotAdded_WithSuggestions) {
+ EXPECT_CALL(*autofill_manager_, ShouldShowCreditCardSigninPromo(_, _))
+ .WillOnce(testing::Return(true));
+
+ IssueOnQuery(kQueryId);
+
+ // The enums must be cast to ints to prevent compile errors on linux_rel.
+ auto element_ids =
+ testing::ElementsAre(kAutofillProfileId,
+#if !defined(OS_ANDROID)
+ static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
+#endif
+ static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
+
+ EXPECT_CALL(autofill_client_,
+ ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids), _));
+
+ base::UserActionTester user_action_tester;
+
+ // This should call ShowAutofillPopup.
+ std::vector<Suggestion> autofill_item;
+ autofill_item.push_back(Suggestion());
+ autofill_item[0].frontend_id = kAutofillProfileId;
+ external_delegate_->OnSuggestionsReturned(kQueryId, autofill_item);
+ EXPECT_EQ(0, user_action_tester.GetActionCount(
+ "Signin_Impression_FromAutofillDropdown"));
+
+ EXPECT_CALL(
+ *autofill_manager_,
+ FillOrPreviewForm(AutofillDriver::FORM_DATA_ACTION_FILL, _, _, _, _));
+ EXPECT_CALL(autofill_client_, HideAutofillPopup());
+
+ // This should trigger a call to hide the popup since we've selected an
+ // option.
+ external_delegate_->DidAcceptSuggestion(autofill_item[0].value,
+ autofill_item[0].frontend_id, 0);
+}
+
+// Test that our external delegate properly adds the signin promo and no
+// separator in the dropdown, when there are no suggestions.
+TEST_F(AutofillExternalDelegateUnitTest,
+ TestSigninPromoIsAdded_WithNoSuggestions) {
+ EXPECT_CALL(*autofill_manager_, ShouldShowCreditCardSigninPromo(_, _))
+ .WillOnce(testing::Return(true));
+
+ IssueOnQuery(kQueryId);
+
+ // The enums must be cast to ints to prevent compile errors on linux_rel.
+ auto element_ids = testing::ElementsAre(
+ static_cast<int>(POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO));
+
+ EXPECT_CALL(autofill_client_,
+ ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids), _));
+
+ base::UserActionTester user_action_tester;
+
+ // This should call ShowAutofillPopup.
+ std::vector<Suggestion> items;
+ external_delegate_->OnSuggestionsReturned(kQueryId, items);
+ EXPECT_EQ(1, user_action_tester.GetActionCount(
+ "Signin_Impression_FromAutofillDropdown"));
+
+ EXPECT_CALL(autofill_client_, StartSigninFlow());
+ EXPECT_CALL(autofill_client_, HideAutofillPopup());
+
+ // This should trigger a call to start the signin flow and hide the popup
+ // since we've selected the sign-in promo option.
+ external_delegate_->DidAcceptSuggestion(
+ base::string16(), POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO, 0);
+}
+
// Test that data list elements for a node will appear in the Autofill popup.
TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateDataList) {
IssueOnQuery(kQueryId);
@@ -555,28 +636,27 @@ TEST_F(AutofillExternalDelegateUnitTest, ScanCreditCardPromptMetricsTest) {
}
}
-MATCHER_P3(CreditCardMatches,
- card_number,
- expiration_month,
- expiration_year,
- "") {
- return !arg.Compare(
- CreditCard(card_number, expiration_month, expiration_year));
+// Test that autofill client will start the signin flow after the user accepted
+// the suggestion to sign in.
+TEST_F(AutofillExternalDelegateUnitTest, SigninPromoMenuItem) {
+ EXPECT_CALL(autofill_client_, StartSigninFlow());
+ EXPECT_CALL(autofill_client_, HideAutofillPopup());
+ external_delegate_->DidAcceptSuggestion(
+ base::string16(), POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO, 0);
+}
+
+MATCHER_P(CreditCardMatches, card, "") {
+ return !arg.Compare(card);
}
// Test that autofill manager will fill the credit card form after user scans a
// credit card.
TEST_F(AutofillExternalDelegateUnitTest, FillCreditCardForm) {
- base::string16 card_number = base::ASCIIToUTF16("test");
- int expiration_month = 1;
- int expiration_year = 3000;
+ CreditCard card;
+ test::SetCreditCardInfo(&card, "Alice", "4111", "1", "3000");
EXPECT_CALL(*autofill_manager_,
- FillCreditCardForm(
- _, _, _, CreditCardMatches(card_number, expiration_month,
- expiration_year),
- base::string16()));
- external_delegate_->OnCreditCardScanned(card_number, expiration_month,
- expiration_year);
+ FillCreditCardForm(_, _, _, CreditCardMatches(card), base::string16()));
+ external_delegate_->OnCreditCardScanned(card);
}
TEST_F(AutofillExternalDelegateUnitTest, IgnoreAutocompleteOffForAutofill) {
diff --git a/chromium/components/autofill/core/browser/autofill_field.cc b/chromium/components/autofill/core/browser/autofill_field.cc
index ae484d79437..bf57caec2f6 100644
--- a/chromium/components/autofill/core/browser/autofill_field.cc
+++ b/chromium/components/autofill/core/browser/autofill_field.cc
@@ -11,7 +11,6 @@
#include "base/i18n/string_search.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
-#include "base/sha1.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -527,17 +526,6 @@ bool FillExpirationDateInput(const base::string16 &value,
return true;
}
-std::string Hash32Bit(const std::string& str) {
- std::string hash_bin = base::SHA1HashString(str);
- DCHECK_EQ(base::kSHA1Length, hash_bin.length());
-
- uint32_t hash32 = ((hash_bin[0] & 0xFF) << 24) |
- ((hash_bin[1] & 0xFF) << 16) | ((hash_bin[2] & 0xFF) << 8) |
- (hash_bin[3] & 0xFF);
-
- return base::UintToString(hash32);
-}
-
base::string16 RemoveWhitespace(const base::string16& value) {
base::string16 stripped_value;
base::RemoveChars(value, base::kWhitespaceUTF16, &stripped_value);
@@ -554,7 +542,8 @@ AutofillField::AutofillField()
phone_part_(IGNORED),
credit_card_number_offset_(0),
previously_autofilled_(false),
- generation_type_(AutofillUploadContents::Field::NO_GENERATION) {}
+ generation_type_(AutofillUploadContents::Field::NO_GENERATION),
+ form_classifier_outcome_(AutofillUploadContents::Field::NO_OUTCOME) {}
AutofillField::AutofillField(const FormFieldData& field,
const base::string16& unique_name)
@@ -568,7 +557,8 @@ AutofillField::AutofillField(const FormFieldData& field,
credit_card_number_offset_(0),
previously_autofilled_(false),
parseable_name_(field.name),
- generation_type_(AutofillUploadContents::Field::NO_GENERATION) {}
+ generation_type_(AutofillUploadContents::Field::NO_GENERATION),
+ form_classifier_outcome_(AutofillUploadContents::Field::NO_OUTCOME) {}
AutofillField::~AutofillField() {}
@@ -641,10 +631,12 @@ bool AutofillField::IsEmpty() const {
return value.empty();
}
-std::string AutofillField::FieldSignature() const {
- std::string field_name = base::UTF16ToUTF8(name);
- std::string field_string = field_name + "&" + form_control_type;
- return Hash32Bit(field_string);
+FieldSignature AutofillField::GetFieldSignature() const {
+ return CalculateFieldSignatureByNameAndType(name, form_control_type);
+}
+
+std::string AutofillField::FieldSignatureAsStr() const {
+ return base::UintToString(GetFieldSignature());
}
bool AutofillField::IsFieldFillable() const {
diff --git a/chromium/components/autofill/core/browser/autofill_field.h b/chromium/components/autofill/core/browser/autofill_field.h
index d2db76e5fda..ed74fdfe239 100644
--- a/chromium/components/autofill/core/browser/autofill_field.h
+++ b/chromium/components/autofill/core/browser/autofill_field.h
@@ -14,6 +14,7 @@
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/proto/server.pb.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/signatures_util.h"
namespace autofill {
@@ -67,7 +68,10 @@ class AutofillField : public FormFieldData {
// The unique signature of this field, composed of the field name and the html
// input type in a 32-bit hash.
- std::string FieldSignature() const;
+ FieldSignature GetFieldSignature() const;
+
+ // Returns the field signature as string.
+ std::string FieldSignatureAsStr() const;
// Returns true if the field type has been determined (without the text in the
// field).
@@ -175,9 +179,6 @@ class AutofillField : public FormFieldData {
// The outcome of HTML parsing based form classifier.
AutofillUploadContents::Field::FormClassifierOutcome form_classifier_outcome_;
- // The value of the class attribute on the field, if present.
- base::string16 css_classes_;
-
DISALLOW_COPY_AND_ASSIGN(AutofillField);
};
diff --git a/chromium/components/autofill/core/browser/autofill_field_trial_ios.cc b/chromium/components/autofill/core/browser/autofill_field_trial_ios.cc
deleted file mode 100644
index 95290e046fc..00000000000
--- a/chromium/components/autofill/core/browser/autofill_field_trial_ios.cc
+++ /dev/null
@@ -1,33 +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 "components/autofill/core/browser/autofill_field_trial_ios.h"
-
-#include "base/command_line.h"
-#include "base/metrics/field_trial.h"
-#include "components/autofill/core/common/autofill_switches.h"
-
-namespace autofill {
-
-// The full-form Autofill field trial name.
-const char kFullFormFieldTrialName[] = "FullFormAutofill";
-
-// static
-bool AutofillFieldTrialIOS::IsFullFormAutofillEnabled() {
- // Query the field trial state first to ensure that UMA reports the correct
- // group.
- std::string field_trial_state =
- base::FieldTrialList::FindFullName(kFullFormFieldTrialName);
-
- const base::CommandLine* command_line =
- base::CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kDisableFullFormAutofillIOS))
- return false;
- if (command_line->HasSwitch(switches::kEnableFullFormAutofillIOS))
- return true;
-
- return !field_trial_state.empty() && field_trial_state != "Disabled";
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_field_trial_ios.h b/chromium/components/autofill/core/browser/autofill_field_trial_ios.h
deleted file mode 100644
index 9750b7135d9..00000000000
--- a/chromium/components/autofill/core/browser/autofill_field_trial_ios.h
+++ /dev/null
@@ -1,28 +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 COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_FIELD_TRIAL_IOS_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_FIELD_TRIAL_IOS_H_
-
-#include "base/macros.h"
-
-namespace autofill {
-
-// This class manages the iOS Autofill field trials.
-class AutofillFieldTrialIOS {
- public:
- // Returns whether the user is in a full-form Autofill field trial. Full-form
- // Autofill fills all fields of the form at once, similar to the desktop and
- // Clank Autofill implementations. Previous iOS implementation requires user
- // to select an Autofill value for each field individually, automatically
- // advancing focus to the next field after each selection.
- static bool IsFullFormAutofillEnabled();
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(AutofillFieldTrialIOS);
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_FIELD_TRIAL_IOS_H_
diff --git a/chromium/components/autofill/core/browser/autofill_field_unittest.cc b/chromium/components/autofill/core/browser/autofill_field_unittest.cc
index aa88edc3ec6..ef4c0473f9a 100644
--- a/chromium/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_field_unittest.cc
@@ -198,29 +198,29 @@ TEST_F(AutofillFieldTest, IsEmpty) {
EXPECT_FALSE(field.IsEmpty());
}
-TEST_F(AutofillFieldTest, FieldSignature) {
+TEST_F(AutofillFieldTest, FieldSignatureAsStr) {
AutofillField field;
ASSERT_EQ(base::string16(), field.name);
ASSERT_EQ(std::string(), field.form_control_type);
// Signature is empty.
- EXPECT_EQ("2085434232", field.FieldSignature());
+ EXPECT_EQ("2085434232", field.FieldSignatureAsStr());
// Field name is set.
field.name = ASCIIToUTF16("Name");
- EXPECT_EQ("1606968241", field.FieldSignature());
+ EXPECT_EQ("1606968241", field.FieldSignatureAsStr());
// Field form control type is set.
field.form_control_type = "text";
- EXPECT_EQ("502192749", field.FieldSignature());
+ EXPECT_EQ("502192749", field.FieldSignatureAsStr());
// Heuristic type does not affect FieldSignature.
field.set_heuristic_type(NAME_FIRST);
- EXPECT_EQ("502192749", field.FieldSignature());
+ EXPECT_EQ("502192749", field.FieldSignatureAsStr());
// Server type does not affect FieldSignature.
field.set_server_type(NAME_LAST);
- EXPECT_EQ("502192749", field.FieldSignature());
+ EXPECT_EQ("502192749", field.FieldSignatureAsStr());
}
TEST_F(AutofillFieldTest, IsFieldFillable) {
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index 95febfc04b7..bfe70109bdf 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -12,10 +12,12 @@
#include <map>
#include <set>
#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/containers/adapters.h"
+#include "base/feature_list.h"
#include "base/files/file_util.h"
#include "base/guid.h"
#include "base/logging.h"
@@ -50,7 +52,6 @@
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_data_validation.h"
#include "components/autofill/core/common/autofill_pref_names.h"
-#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_predictions.h"
@@ -66,7 +67,6 @@
#include "url/gurl.h"
#if defined(OS_IOS)
-#include "components/autofill/core/browser/autofill_field_trial_ios.h"
#include "components/autofill/core/browser/keyboard_accessory_metrics_logger.h"
#endif
@@ -210,6 +210,9 @@ AutofillManager::AutofillManager(
user_did_accept_upload_prompt_(false),
external_delegate_(NULL),
test_delegate_(NULL),
+#if defined(OS_ANDROID) || defined(OS_IOS)
+ autofill_assistant_(this),
+#endif
weak_ptr_factory_(this) {
if (enable_download_manager == ENABLE_AUTOFILL_DOWNLOAD_MANAGER) {
download_manager_.reset(new AutofillDownloadManager(driver, this));
@@ -217,6 +220,11 @@ AutofillManager::AutofillManager(
CountryNames::SetLocaleString(app_locale_);
if (personal_data_ && client_)
personal_data_->OnSyncServiceInitialized(client_->GetSyncService());
+
+#if defined(OS_ANDROID)
+ if (personal_data_ && driver_)
+ personal_data_->SetURLRequestContextGetter(driver_->GetURLRequestContext());
+#endif
}
AutofillManager::~AutofillManager() {}
@@ -224,6 +232,10 @@ AutofillManager::~AutofillManager() {}
// static
void AutofillManager::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
+ // This pref is not synced because it's for a signin promo, which by
+ // definition will not be synced.
+ registry->RegisterIntegerPref(
+ prefs::kAutofillCreditCardSigninPromoImpressionCount, 0);
registry->RegisterBooleanPref(
prefs::kAutofillEnabled,
true,
@@ -254,24 +266,56 @@ void AutofillManager::ShowAutofillSettings() {
bool AutofillManager::ShouldShowScanCreditCard(const FormData& form,
const FormFieldData& field) {
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableCreditCardScan)) {
+ if (!client_->HasCreditCardScanFeature())
return false;
- }
- if (!client_->HasCreditCardScanFeature())
+ AutofillField* autofill_field = GetAutofillField(form, field);
+ if (!autofill_field)
+ return false;
+
+ bool is_card_number_field =
+ autofill_field->Type().GetStorableType() == CREDIT_CARD_NUMBER &&
+ base::ContainsOnlyChars(CreditCard::StripSeparators(field.value),
+ base::ASCIIToUTF16("0123456789"));
+
+ bool is_scannable_name_on_card_field =
+ autofill_field->Type().GetStorableType() == CREDIT_CARD_NAME_FULL &&
+ base::FeatureList::IsEnabled(kAutofillScanCardholderName);
+
+ if (!is_card_number_field && !is_scannable_name_on_card_field)
+ return false;
+
+ static const int kShowScanCreditCardMaxValueLength = 6;
+ return field.value.size() <= kShowScanCreditCardMaxValueLength;
+}
+
+bool AutofillManager::ShouldShowCreditCardSigninPromo(
+ const FormData& form,
+ const FormFieldData& field) {
+ if (!IsAutofillCreditCardSigninPromoEnabled())
return false;
+ // Check whether we are dealing with a credit card field and whether it's
+ // appropriate to show the promo (e.g. the platform is supported).
AutofillField* autofill_field = GetAutofillField(form, field);
- if (!autofill_field ||
- autofill_field->Type().GetStorableType() != CREDIT_CARD_NUMBER) {
+ if (!autofill_field || autofill_field->Type().group() != CREDIT_CARD ||
+ !client_->ShouldShowSigninPromo())
return false;
+
+ // The last step is checking if we are under the limit of impressions (a limit
+ // of 0 means there is no limit);
+ int impression_limit = GetCreditCardSigninPromoImpressionLimit();
+ int impression_count = client_->GetPrefs()->GetInteger(
+ prefs::kAutofillCreditCardSigninPromoImpressionCount);
+ if (impression_limit == 0 || impression_count < impression_limit) {
+ // The promo will be shown. Increment the impression count.
+ client_->GetPrefs()->SetInteger(
+ prefs::kAutofillCreditCardSigninPromoImpressionCount,
+ impression_count + 1);
+ return true;
}
- static const int kShowScanCreditCardMaxValueLength = 6;
- return field.value.size() <= kShowScanCreditCardMaxValueLength &&
- base::ContainsOnlyChars(CreditCard::StripSeparators(field.value),
- base::ASCIIToUTF16("0123456789"));
+ return false;
}
void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms,
@@ -507,11 +551,15 @@ void AutofillManager::OnQueryFormFieldAutofill(int query_id,
GetProfileSuggestions(*form_structure, field, *autofill_field);
}
if (!suggestions.empty()) {
+ bool is_context_secure =
+ client_->IsContextSecure(form_structure->source_url());
+ if (is_filling_credit_card)
+ AutofillMetrics::LogIsQueriedCreditCardFormSecure(is_context_secure);
+
// Don't provide credit card suggestions for non-secure pages, but do
// provide them for secure pages with passive mixed content (see impl. of
// IsContextSecure).
- if (is_filling_credit_card &&
- !client_->IsContextSecure(form_structure->source_url())) {
+ if (is_filling_credit_card && !is_context_secure) {
Suggestion warning_suggestion(l10n_util::GetStringUTF16(
IDS_AUTOFILL_WARNING_INSECURE_CONNECTION));
warning_suggestion.frontend_id = POPUP_ITEM_ID_WARNING_MESSAGE;
@@ -553,11 +601,14 @@ void AutofillManager::OnQueryFormFieldAutofill(int query_id,
// If there are no Autofill suggestions, consider showing Autocomplete
// suggestions. We will not show Autocomplete suggestions for a field that
- // specifies autocomplete=off or a field that we think is a credit card
- // expiration, cvc or number.
- if (suggestions.empty() && field.should_autocomplete &&
+ // specifies autocomplete=off (or an unrecognized type), a field for which we
+ // will show the credit card signin promo, or a field that we think is a
+ // credit card expiration, cvc or number.
+ if (suggestions.empty() && !ShouldShowCreditCardSigninPromo(form, field) &&
+ field.should_autocomplete &&
!(autofill_field &&
(IsCreditCardExpirationType(autofill_field->Type().GetStorableType()) ||
+ autofill_field->Type().html_type() == HTML_TYPE_UNRECOGNIZED ||
autofill_field->Type().GetStorableType() == CREDIT_CARD_NUMBER ||
autofill_field->Type().GetStorableType() ==
CREDIT_CARD_VERIFICATION_CODE))) {
@@ -583,13 +634,6 @@ bool AutofillManager::WillFillCreditCardNumber(const FormData& form,
if (autofill_field->Type().GetStorableType() == CREDIT_CARD_NUMBER)
return true;
-#if defined(OS_IOS)
- // On iOS, we only fill out one field at a time (assuming the new full-form
- // feature isn't enabled). So we only need to check the current field.
- if (!AutofillFieldTrialIOS::IsFullFormAutofillEnabled())
- return false;
-#endif
-
// If the relevant section is already autofilled, the new fill operation will
// only fill |autofill_field|.
if (SectionIsAutofilled(*form_structure, form, autofill_field->section()))
@@ -870,7 +914,7 @@ void AutofillManager::OnLoadedServerPredictions(
std::vector<FormStructure*> queried_forms;
for (const std::string& signature : base::Reversed(form_signatures)) {
for (FormStructure* cur_form : base::Reversed(form_structures_)) {
- if (cur_form->FormSignature() == signature) {
+ if (cur_form->FormSignatureAsStr() == signature) {
queried_forms.push_back(cur_form);
break;
}
@@ -956,15 +1000,15 @@ void AutofillManager::OnDidUploadCard(
// TODO(jdonnelly): Log duration.
}
-void AutofillManager::OnFullCardDetails(const CreditCard& card,
- const base::string16& cvc) {
+void AutofillManager::OnFullCardRequestSucceeded(const CreditCard& card,
+ const base::string16& cvc) {
credit_card_form_event_logger_->OnDidFillSuggestion(masked_card_);
FillCreditCardForm(unmasking_query_id_, unmasking_form_, unmasking_field_,
card, cvc);
masked_card_ = CreditCard();
}
-void AutofillManager::OnFullCardError() {
+void AutofillManager::OnFullCardRequestFailed() {
driver_->RendererShouldClearPreviewedForm();
}
@@ -1028,7 +1072,7 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
recently_autofilled_forms_.push_back(
std::map<std::string, base::string16>());
auto& map = recently_autofilled_forms_.back();
- for (const auto& field : submitted_form) {
+ for (const auto* field : submitted_form) {
AutofillType type = field->Type();
// Even though this is for development only, mask full credit card #'s.
if (type.GetStorableType() == CREDIT_CARD_NUMBER &&
@@ -1093,7 +1137,7 @@ void AutofillManager::ImportFormData(const FormStructure& submitted_form) {
}
// All required data is available, start the upload process.
- payments_client_->GetUploadDetails(app_locale_);
+ payments_client_->GetUploadDetails(upload_request_.profiles, app_locale_);
}
}
@@ -1236,7 +1280,7 @@ void AutofillManager::UploadFormData(const FormStructure& submitted_form,
// Check if the form is among the forms that were recently auto-filled.
bool was_autofilled = false;
- std::string form_signature = submitted_form.FormSignature();
+ std::string form_signature = submitted_form.FormSignatureAsStr();
for (const std::string& cur_sig : autofilled_form_signatures_) {
if (cur_sig == form_signature) {
was_autofilled = true;
@@ -1262,6 +1306,9 @@ void AutofillManager::Reset() {
new AutofillMetrics::FormEventLogger(false /* is_for_credit_card */));
credit_card_form_event_logger_.reset(
new AutofillMetrics::FormEventLogger(true /* is_for_credit_card */));
+#if defined(OS_ANDROID) || defined(OS_IOS)
+ autofill_assistant_.Reset();
+#endif
has_logged_autofill_enabled_ = false;
has_logged_address_suggestions_count_ = false;
did_show_suggestions_ = false;
@@ -1301,6 +1348,9 @@ AutofillManager::AutofillManager(AutofillDriver* driver,
unmasking_query_id_(-1),
external_delegate_(NULL),
test_delegate_(NULL),
+#if defined(OS_ANDROID) || defined(OS_IOS)
+ autofill_assistant_(this),
+#endif
weak_ptr_factory_(this) {
DCHECK(driver_);
DCHECK(client_);
@@ -1497,7 +1547,7 @@ void AutofillManager::FillOrPreviewDataModelForm(
}
}
- autofilled_form_signatures_.push_front(form_structure->FormSignature());
+ autofilled_form_signatures_.push_front(form_structure->FormSignatureAsStr());
// Only remember the last few forms that we've seen, both to avoid false
// positives and to avoid wasting memory.
if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember)
@@ -1749,6 +1799,21 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
#endif
}
+#if defined(OS_ANDROID) || defined(OS_IOS)
+ // When a credit card form is parsed and conditions are met, show an infobar
+ // prompt for credit card assisted filling. Upon accepting the infobar, the
+ // form will automatically be filled with the user's information through this
+ // class' FillCreditCardForm().
+ if (autofill_assistant_.CanShowCreditCardAssist(form_structures_.get())) {
+ const std::vector<CreditCard*> cards =
+ personal_data_->GetCreditCardsToSuggest();
+ // Expired cards are last in the sorted order, so if the first one is
+ // expired, they all are.
+ if (!cards.empty() && !cards.front()->IsExpired(base::Time::Now()))
+ autofill_assistant_.ShowAssistForCreditCard(*cards.front());
+ }
+#endif
+
// For the |non_queryable_forms|, we have all the field type info we're ever
// going to get about them. For the other forms, we'll wait until we get a
// response from the server.
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index 2a37e9af4ee..c93d0247631 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -32,6 +32,10 @@
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/common/form_data.h"
+#if defined(OS_ANDROID) || defined(OS_IOS)
+#include "components/autofill/core/browser/autofill_assistant.h"
+#endif
+
// This define protects some debugging code (see DumpAutofillData). This
// is here to make it easier to delete this code when the test is complete,
// and to prevent adding the code on mobile where there is no desktop (the
@@ -94,6 +98,11 @@ class AutofillManager : public AutofillDownloadManager::Observer,
virtual bool ShouldShowScanCreditCard(const FormData& form,
const FormFieldData& field);
+ // Whether we should show the signin promo, based on the triggered |field|
+ // inside the |form|.
+ virtual bool ShouldShowCreditCardSigninPromo(const FormData& form,
+ const FormFieldData& field);
+
// Called from our external delegate so they cannot be private.
virtual void FillOrPreviewForm(AutofillDriver::RendererFormDataAction action,
int query_id,
@@ -246,7 +255,6 @@ class AutofillManager : public AutofillDownloadManager::Observer,
ScopedVector<FormStructure>* form_structures() { return &form_structures_; }
- protected:
// Exposed for testing.
AutofillExternalDelegate* external_delegate() {
return external_delegate_;
@@ -279,9 +287,9 @@ class AutofillManager : public AutofillDownloadManager::Observer,
void OnDidUploadCard(AutofillClient::PaymentsRpcResult result) override;
// FullCardRequest::Delegate:
- void OnFullCardDetails(const CreditCard& card,
- const base::string16& cvc) override;
- void OnFullCardError() override;
+ void OnFullCardRequestSucceeded(const CreditCard& card,
+ const base::string16& cvc) override;
+ void OnFullCardRequestFailed() override;
// Sets |user_did_accept_upload_prompt_| and calls UploadCard if the risk data
// is available.
@@ -530,6 +538,10 @@ class AutofillManager : public AutofillDownloadManager::Observer,
// Delegate used in test to get notifications on certain events.
AutofillManagerTestDelegate* test_delegate_;
+#if defined(OS_ANDROID) || defined(OS_IOS)
+ AutofillAssistant autofill_assistant_;
+#endif
+
base::WeakPtrFactory<AutofillManager> weak_ptr_factory_;
friend class AutofillManagerTest;
@@ -569,33 +581,9 @@ class AutofillManager : public AutofillDownloadManager::Observer,
UserHappinessFormLoadAndSubmission);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, UserHappinessFormInteraction);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
- FormSubmittedAutocompleteEnabled);
- FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
OnLoadedServerPredictions);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
OnLoadedServerPredictions_ResetManager);
- FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
- AutocompleteSuggestions_SomeWhenAutofillDisabled);
- FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
- AutocompleteSuggestions_SomeWhenAutofillEmpty);
- FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
- AutocompleteSuggestions_NoneWhenAutofillPresent);
- FRIEND_TEST_ALL_PREFIXES(
- AutofillManagerTest,
- AutocompleteSuggestions_CreditCardNameFieldShouldAutocomplete);
- FRIEND_TEST_ALL_PREFIXES(
- AutofillManagerTest,
- AutocompleteSuggestions_CreditCardNumberShouldNotAutocomplete);
- FRIEND_TEST_ALL_PREFIXES(
- AutofillManagerTest,
- AutocompleteSuggestions_AutofillDisabledAndFieldShouldNotAutocomplete);
- FRIEND_TEST_ALL_PREFIXES(
- AutofillManagerTest,
- AutocompleteSuggestions_NoneWhenAutofillEmptyFieldShouldNotAutocomplete);
- FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
- AutocompleteOffRespectedForAutocomplete);
- FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
- DontSaveCvcInAutocompleteHistory);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DontOfferToSavePaymentsCard);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, FillInUpdatedExpirationDate);
DISALLOW_COPY_AND_ASSIGN(AutofillManager);
diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
index 179985d31e6..6495573cdba 100644
--- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -11,10 +11,12 @@
#include <vector>
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/format_macros.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
+#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
@@ -22,11 +24,13 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autocomplete_history_manager.h"
#include "components/autofill/core/browser/autofill_download_manager.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/credit_card.h"
@@ -44,6 +48,7 @@
#include "components/autofill/core/common/form_field_data.h"
#include "components/prefs/pref_service.h"
#include "components/rappor/test_rappor_service.h"
+#include "components/variations/variations_associated_data.h"
#include "grit/components_strings.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -56,6 +61,7 @@ using base::ASCIIToUTF16;
using base::UTF8ToUTF16;
using testing::_;
using testing::AtLeast;
+using testing::Return;
using testing::SaveArg;
namespace autofill {
@@ -73,6 +79,8 @@ class MockAutofillClient : public TestAutofillClient {
MOCK_METHOD2(ConfirmSaveCreditCardLocally,
void(const CreditCard& card, const base::Closure& callback));
+ MOCK_METHOD0(ShouldShowSigninPromo, bool());
+
private:
DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
};
@@ -85,7 +93,8 @@ class TestPaymentsClient : public payments::PaymentsClient {
~TestPaymentsClient() override {}
- void GetUploadDetails(const std::string& app_locale) override {
+ void GetUploadDetails(const std::vector<AutofillProfile>& addresses,
+ const std::string& app_locale) override {
delegate_->OnDidGetUploadDetails(
app_locale == "en-US" ? AutofillClient::SUCCESS
: AutofillClient::PERMANENT_FAILURE,
@@ -567,7 +576,7 @@ class TestAutofillManager : public AutofillManager {
void UploadFormData(const FormStructure& submitted_form,
bool observed_submission) override {
- submitted_form_signature_ = submitted_form.FormSignature();
+ submitted_form_signature_ = submitted_form.FormSignatureAsStr();
}
const std::string GetSubmittedFormSignature() {
@@ -695,10 +704,21 @@ class TestAutofillExternalDelegate : public AutofillExternalDelegate {
suggestion_vector.push_back(suggestion2);
CheckSuggestions(expected_page_id, 3, &suggestion_vector[0]);
}
+ // Check that the autofill suggestions were sent, and that they match a page
+ // but contain no results.
void CheckNoSuggestions(int expected_page_id) {
- EXPECT_TRUE(on_suggestions_returned_seen());
CheckSuggestions(expected_page_id, 0, nullptr);
}
+ // Check that the autofill suggestions were sent, and that they match a page
+ // and contain a specific number of suggestions.
+ void CheckSuggestionCount(int expected_page_id,
+ size_t expected_num_suggestions) {
+ // Ensure that these results are from the most recent query.
+ EXPECT_TRUE(on_suggestions_returned_seen_);
+
+ EXPECT_EQ(expected_page_id, query_id_);
+ ASSERT_EQ(expected_num_suggestions, suggestions_.size());
+ }
bool on_query_seen() const {
return on_query_seen_;
@@ -729,6 +749,8 @@ class TestAutofillExternalDelegate : public AutofillExternalDelegate {
class AutofillManagerTest : public testing::Test {
public:
+ AutofillManagerTest() : field_trial_list_(nullptr) {}
+
void SetUp() override {
autofill_client_.SetPrefs(test::PrefServiceForTesting());
personal_data_.set_database(autofill_client_.GetDatabase());
@@ -747,6 +769,9 @@ class AutofillManagerTest : public testing::Test {
autofill_manager_.get(),
autofill_driver_.get()));
autofill_manager_->SetExternalDelegate(external_delegate_.get());
+
+ // Clear all the things.
+ variations::testing::ClearAllVariationParams();
}
void TearDown() override {
@@ -763,6 +788,32 @@ class AutofillManagerTest : public testing::Test {
request_context_ = nullptr;
}
+ void EnableCreditCardSigninPromoFeatureWithLimit(int impression_limit) {
+ const std::string kTrialName = "MyTrial";
+ const std::string kGroupName = "Group1";
+
+ scoped_refptr<base::FieldTrial> trial(
+ base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName));
+ std::map<std::string, std::string> params;
+ params[kCreditCardSigninPromoImpressionLimitParamKey] =
+ base::IntToString(impression_limit);
+ ASSERT_TRUE(
+ variations::AssociateVariationParams(kTrialName, kGroupName, params));
+
+ // Enable the feature.
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->RegisterFieldTrialOverride(
+ kAutofillCreditCardSigninPromo.name,
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
+ scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
+
+ // Double-checking our params made it.
+ std::map<std::string, std::string> actualParams;
+ EXPECT_TRUE(variations::GetVariationParamsByFeature(
+ kAutofillCreditCardSigninPromo, &actualParams));
+ EXPECT_EQ(params, actualParams);
+ }
+
void GetAutofillSuggestions(int query_id,
const FormData& form,
const FormFieldData& field) {
@@ -921,20 +972,16 @@ class AutofillManagerTest : public testing::Test {
autofill_manager_->FillOrPreviewCreditCardForm(
AutofillDriver::FORM_DATA_ACTION_FILL, kDefaultPageID, *form,
form->fields[0], *card);
+ }
-#if defined(OS_IOS)
- // Filling out the entire form on iOS requires requesting autofill on each
- // of the form fields.
- autofill_manager_->FillOrPreviewCreditCardForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, kDefaultPageID, *form,
- form->fields[1], *card);
- autofill_manager_->FillOrPreviewCreditCardForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, kDefaultPageID, *form,
- form->fields[2], *card);
- autofill_manager_->FillOrPreviewCreditCardForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, kDefaultPageID, *form,
- form->fields[3], *card);
-#endif // defined(OS_IOS)
+ // Convenience method for using and retrieving a mock autocomplete history
+ // manager.
+ MockAutocompleteHistoryManager* RecreateMockAutocompleteHistoryManager() {
+ MockAutocompleteHistoryManager* manager = new
+ MockAutocompleteHistoryManager(autofill_driver_.get(),
+ autofill_manager_->client());
+ autofill_manager_->autocomplete_history_manager_.reset(manager);
+ return manager;
}
// Convenience method to cast the FullCardRequest into a CardUnmaskDelegate.
@@ -954,6 +1001,8 @@ class AutofillManagerTest : public testing::Test {
TestPaymentsClient* payments_client_;
TestAutofillDownloadManager* download_manager_;
TestPersonalDataManager personal_data_;
+ base::FieldTrialList field_trial_list_;
+ base::test::ScopedFeatureList scoped_feature_list_;
};
class TestFormStructure : public FormStructure {
@@ -1037,9 +1086,10 @@ TEST_F(AutofillManagerTest, OnFormsSeen_DifferentFormStructures) {
download_manager_->VerifyLastQueriedForms(forms);
}
-// Test that no suggestions are returned for a field with an unrecognized
-// autocomplete attribute.
+// Test that no autofill suggestions are returned for a field with an
+// unrecognized autocomplete attribute.
TEST_F(AutofillManagerTest, GetProfileSuggestions_UnrecognizedAttribute) {
+ // Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.origin = GURL("https://myform.com/form.html");
@@ -1060,21 +1110,26 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_UnrecognizedAttribute) {
std::vector<FormData> forms(1, form);
FormsSeen(forms);
- // Suggestions should be returned for the first two fields
+ // Ensure that autocomplete manager is not called for suggestions either.
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+ EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
+
+ // Suggestions should be returned for the first two fields.
GetAutofillSuggestions(form, form.fields[0]);
- EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+ external_delegate_->CheckSuggestionCount(kDefaultPageID, 2);
GetAutofillSuggestions(form, form.fields[1]);
- EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+ external_delegate_->CheckSuggestionCount(kDefaultPageID, 2);
- // Suggestions should not be returned for the third field because of its
+ // No suggestions should not be provided for the third field because of its
// unrecognized autocomplete attribute.
GetAutofillSuggestions(form, form.fields[2]);
- EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
+ external_delegate_->CheckNoSuggestions(kDefaultPageID);
}
// Test that no suggestions are returned when there are less than three fields
// and none of them have an autocomplete attribute.
TEST_F(AutofillManagerTest, GetProfileSuggestions_SmallFormNoAutocomplete) {
+ // Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.origin = GURL("https://myform.com/form.html");
@@ -1088,6 +1143,10 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_SmallFormNoAutocomplete) {
std::vector<FormData> forms(1, form);
FormsSeen(forms);
+ // Ensure that autocomplete manager is called for both fields.
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+ EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(2);
+
GetAutofillSuggestions(form, form.fields[0]);
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
@@ -1099,6 +1158,7 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_SmallFormNoAutocomplete) {
// attribute, suggestions are only made for the one that has the attribute.
TEST_F(AutofillManagerTest,
GetProfileSuggestions_SmallFormWithOneAutocomplete) {
+ // Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.origin = GURL("https://myform.com/form.html");
@@ -1131,6 +1191,7 @@ TEST_F(AutofillManagerTest,
// suggestions are made for both fields.
TEST_F(AutofillManagerTest,
GetProfileSuggestions_SmallFormWithTwoAutocomplete) {
+ // Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.origin = GURL("https://myform.com/form.html");
@@ -1159,7 +1220,7 @@ TEST_F(AutofillManagerTest,
// Test that we return all address profile suggestions when all form fields are
// empty.
-TEST_F(AutofillManagerTest, GetProfileSuggestionsEmptyValue) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_EmptyValue) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
@@ -1179,7 +1240,7 @@ TEST_F(AutofillManagerTest, GetProfileSuggestionsEmptyValue) {
// Test that we return only matching address profile suggestions when the
// selected form field has been partially filled out.
-TEST_F(AutofillManagerTest, GetProfileSuggestionsMatchCharacter) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_MatchCharacter) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
@@ -1271,7 +1332,7 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_AlreadyAutofilledNoLabels) {
}
// Test that we return no suggestions when the form has no relevant fields.
-TEST_F(AutofillManagerTest, GetProfileSuggestionsUnknownFields) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_UnknownFields) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -1296,7 +1357,7 @@ TEST_F(AutofillManagerTest, GetProfileSuggestionsUnknownFields) {
}
// Test that we cull duplicate profile suggestions.
-TEST_F(AutofillManagerTest, GetProfileSuggestionsWithDuplicates) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_WithDuplicates) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
@@ -1320,7 +1381,7 @@ TEST_F(AutofillManagerTest, GetProfileSuggestionsWithDuplicates) {
}
// Test that we return no suggestions when autofill is disabled.
-TEST_F(AutofillManagerTest, GetProfileSuggestionsAutofillDisabledByUser) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_AutofillDisabledByUser) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
@@ -1441,7 +1502,7 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_StopCharsWithInput) {
// Test that we return only matching credit card profile suggestions when the
// selected form field has been partially filled out.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestionsMatchCharacter) {
+TEST_F(AutofillManagerTest, GetCreditCardSuggestions_MatchCharacter) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
@@ -1462,7 +1523,7 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestionsMatchCharacter) {
// Test that we return credit card profile suggestions when the selected form
// field is not the credit card number field.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestionsNonCCNumber) {
+TEST_F(AutofillManagerTest, GetCreditCardSuggestions_NonCCNumber) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
@@ -1495,7 +1556,7 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestionsNonCCNumber) {
// Test that we return a warning explaining that credit card profile suggestions
// are unavailable when the form is not secure.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestionsNonHTTPS) {
+TEST_F(AutofillManagerTest, GetCreditCardSuggestions_NonHTTPS) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, false, false);
@@ -1519,9 +1580,44 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestionsNonHTTPS) {
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
+// Test that we will eventually return the credit card signin promo when there
+// are no credit card suggestions and the promo is active. See the tests in
+// AutofillExternalDelegateTest that test whether the promo is added.
+TEST_F(AutofillManagerTest, GetCreditCardSuggestions_OnlySigninPromo) {
+ // Enable the signin promo feature with no impression limit.
+ EnableCreditCardSigninPromoFeatureWithLimit(0);
+
+ // Make sure there are no credit cards.
+ personal_data_.ClearCreditCards();
+
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+ FormFieldData field = form.fields[1];
+
+ ON_CALL(autofill_client_, ShouldShowSigninPromo())
+ .WillByDefault(Return(true));
+ EXPECT_CALL(autofill_client_, ShouldShowSigninPromo()).Times(2);
+ EXPECT_TRUE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
+
+ // Autocomplete suggestions are not queried.
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+ EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
+
+ GetAutofillSuggestions(form, field);
+
+ // Test that we sent no values to the external delegate. It will add the promo
+ // before passing along the results.
+ external_delegate_->CheckNoSuggestions(kDefaultPageID);
+
+ EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+}
+
// Test that we return all credit card suggestions in the case that two cards
// have the same obfuscated number.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestionsRepeatedObfuscatedNumber) {
+TEST_F(AutofillManagerTest, GetCreditCardSuggestions_RepeatedObfuscatedNumber) {
// Add a credit card with the same obfuscated number as Elvis's.
// |credit_card| will be owned by the mock PersonalDataManager.
CreditCard* credit_card = new CreditCard;
@@ -1702,7 +1798,7 @@ TEST_F(AutofillManagerTest, GetFieldSuggestionsWithDuplicateValues) {
Suggestion("Elvis", "", "", 1));
}
-TEST_F(AutofillManagerTest, GetProfileSuggestionsFancyPhone) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_FancyPhone) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
@@ -1729,7 +1825,7 @@ TEST_F(AutofillManagerTest, GetProfileSuggestionsFancyPhone) {
Suggestion("12345678901", "3734 Elvis Presley Blvd.", "", 3));
}
-TEST_F(AutofillManagerTest, GetProfileSuggestionsForPhonePrefixOrSuffix) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_ForPhonePrefixOrSuffix) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -1825,26 +1921,18 @@ TEST_F(AutofillManagerTest, WillFillCreditCardNumber) {
month_field = &form.fields[i];
}
- // Empty form - whole form is Autofilled (except on iOS).
+ // Empty form - whole form is Autofilled.
EXPECT_TRUE(WillFillCreditCardNumber(form, *number_field));
-#if defined(OS_IOS)
- EXPECT_FALSE(WillFillCreditCardNumber(form, *name_field));
-#else
EXPECT_TRUE(WillFillCreditCardNumber(form, *name_field));
-#endif // defined(OS_IOS)
// If the user has entered a value, it won't be overridden.
number_field->value = ASCIIToUTF16("gibberish");
EXPECT_TRUE(WillFillCreditCardNumber(form, *number_field));
EXPECT_FALSE(WillFillCreditCardNumber(form, *name_field));
- // But if that value is removed, it will be Autofilled (except on iOS).
+ // But if that value is removed, it will be Autofilled.
number_field->value.clear();
-#if defined(OS_IOS)
- EXPECT_FALSE(WillFillCreditCardNumber(form, *name_field));
-#else
EXPECT_TRUE(WillFillCreditCardNumber(form, *name_field));
-#endif // defined(OS_IOS)
// When part of the section is Autofilled, only fill the initiating field.
month_field->is_autofilled = true;
@@ -1853,7 +1941,7 @@ TEST_F(AutofillManagerTest, WillFillCreditCardNumber) {
}
// Test that we correctly fill a credit card form.
-TEST_F(AutofillManagerTest, FillCreditCardForm) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_Simple) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
@@ -1871,7 +1959,7 @@ TEST_F(AutofillManagerTest, FillCreditCardForm) {
}
// Test that whitespace is stripped from the credit card number.
-TEST_F(AutofillManagerTest, FillCreditCardFormStripCardNumberWhitespace) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_StripCardNumberWhitespace) {
// Same as the SetUp(), but generate Elvis card with whitespace in credit
// card number.
personal_data_.CreateTestCreditCardWithWhitespace();
@@ -1892,7 +1980,7 @@ TEST_F(AutofillManagerTest, FillCreditCardFormStripCardNumberWhitespace) {
}
// Test that separator characters are stripped from the credit card number.
-TEST_F(AutofillManagerTest, FillCreditCardFormStripCardNumberSeparators) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_StripCardNumberSeparators) {
// Same as the SetUp(), but generate Elvis card with separator characters in
// credit card number.
personal_data_.CreateTestCreditCardWithSeparators();
@@ -1914,7 +2002,7 @@ TEST_F(AutofillManagerTest, FillCreditCardFormStripCardNumberSeparators) {
// Test that we correctly fill a credit card form with month input type.
// 1. year empty, month empty
-TEST_F(AutofillManagerTest, FillCreditCardFormNoYearNoMonth) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_NoYearNoMonth) {
// Same as the SetUp(), but generate 4 credit cards with year month
// combination.
personal_data_.CreateTestCreditCardsYearAndMonth("", "");
@@ -1937,7 +2025,7 @@ TEST_F(AutofillManagerTest, FillCreditCardFormNoYearNoMonth) {
// Test that we correctly fill a credit card form with month input type.
// 2. year empty, month non-empty
-TEST_F(AutofillManagerTest, FillCreditCardFormNoYearMonth) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_NoYearMonth) {
// Same as the SetUp(), but generate 4 credit cards with year month
// combination.
personal_data_.CreateTestCreditCardsYearAndMonth("", "04");
@@ -1959,7 +2047,7 @@ TEST_F(AutofillManagerTest, FillCreditCardFormNoYearMonth) {
// Test that we correctly fill a credit card form with month input type.
// 3. year non-empty, month empty
-TEST_F(AutofillManagerTest, FillCreditCardFormYearNoMonth) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_YearNoMonth) {
// Same as the SetUp(), but generate 4 credit cards with year month
// combination.
personal_data_.CreateTestCreditCardsYearAndMonth("2999", "");
@@ -1981,7 +2069,7 @@ TEST_F(AutofillManagerTest, FillCreditCardFormYearNoMonth) {
// Test that we correctly fill a credit card form with month input type.
// 4. year non-empty, month empty
-TEST_F(AutofillManagerTest, FillCreditCardFormYearMonth) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_YearMonth) {
// Same as the SetUp(), but generate 4 credit cards with year month
// combination.
personal_data_.ClearCreditCards();
@@ -2004,7 +2092,7 @@ TEST_F(AutofillManagerTest, FillCreditCardFormYearMonth) {
// Test that we correctly fill a credit card form with first and last cardholder
// name.
-TEST_F(AutofillManagerTest, FillCreditCardFormSplitName) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_SplitName) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -2949,15 +3037,12 @@ TEST_F(AutofillManagerTest, FormSubmittedAutocompleteEnabled) {
autofill_manager_.reset(
new TestAutofillManager(autofill_driver_.get(), &client, NULL));
autofill_manager_->set_autofill_enabled(false);
- autofill_manager_->autocomplete_history_manager_.reset(
- new MockAutocompleteHistoryManager(autofill_driver_.get(), &client));
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
- MockAutocompleteHistoryManager* m = static_cast<
- MockAutocompleteHistoryManager*>(
- autofill_manager_->autocomplete_history_manager_.get());
+
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
EXPECT_CALL(*m, OnWillSubmitForm(_));
FormSubmitted(form);
}
@@ -2979,13 +3064,8 @@ TEST_F(AutofillManagerTest, AutocompleteSuggestions_SomeWhenAutofillDisabled) {
const FormFieldData& field = form.fields[0];
// Expect Autocomplete manager to be called for suggestions.
- autofill_manager_->autocomplete_history_manager_.reset(
- new MockAutocompleteHistoryManager(autofill_driver_.get(), &client));
- MockAutocompleteHistoryManager* m = static_cast<
- MockAutocompleteHistoryManager*>(
- autofill_manager_->autocomplete_history_manager_.get());
- EXPECT_CALL(*m,
- OnGetAutocompleteSuggestions(_, _, _, _));
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+ EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _));
GetAutofillSuggestions(form, field);
}
@@ -3009,13 +3089,9 @@ TEST_F(AutofillManagerTest,
field.should_autocomplete = false;
// Autocomplete manager is not called for suggestions.
- autofill_manager_->autocomplete_history_manager_.reset(
- new MockAutocompleteHistoryManager(autofill_driver_.get(), &client));
- MockAutocompleteHistoryManager* m = static_cast<
- MockAutocompleteHistoryManager*>(
- autofill_manager_->autocomplete_history_manager_.get());
- EXPECT_CALL(*m,
- OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
+
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+ EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
GetAutofillSuggestions(form, field);
}
@@ -3032,14 +3108,8 @@ TEST_F(AutofillManagerTest, AutocompleteSuggestions_NoneWhenAutofillPresent) {
const FormFieldData& field = form.fields[0];
// Autocomplete manager is not called for suggestions.
- autofill_manager_->autocomplete_history_manager_.reset(
- new MockAutocompleteHistoryManager(autofill_driver_.get(),
- autofill_manager_->client()));
- MockAutocompleteHistoryManager* m = static_cast<
- MockAutocompleteHistoryManager*>(
- autofill_manager_->autocomplete_history_manager_.get());
- EXPECT_CALL(*m,
- OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+ EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
GetAutofillSuggestions(form, field);
@@ -3065,14 +3135,8 @@ TEST_F(AutofillManagerTest, AutocompleteSuggestions_SomeWhenAutofillEmpty) {
test::CreateTestFormField("Email", "email", "donkey", "email", &field);
// Autocomplete manager is called for suggestions because Autofill is empty.
- autofill_manager_->autocomplete_history_manager_.reset(
- new MockAutocompleteHistoryManager(autofill_driver_.get(),
- autofill_manager_->client()));
- MockAutocompleteHistoryManager* m = static_cast<
- MockAutocompleteHistoryManager*>(
- autofill_manager_->autocomplete_history_manager_.get());
- EXPECT_CALL(*m,
- OnGetAutocompleteSuggestions(_, _, _, _));
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+ EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _));
GetAutofillSuggestions(form, field);
}
@@ -3098,12 +3162,7 @@ TEST_F(AutofillManagerTest,
field.should_autocomplete = true;
// Autocomplete manager is not called for suggestions.
- autofill_manager_->autocomplete_history_manager_.reset(
- new MockAutocompleteHistoryManager(autofill_driver_.get(),
- autofill_manager_->client()));
- MockAutocompleteHistoryManager* m =
- static_cast<MockAutocompleteHistoryManager*>(
- autofill_manager_->autocomplete_history_manager_.get());
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _));
GetAutofillSuggestions(form, field);
@@ -3129,11 +3188,7 @@ TEST_F(AutofillManagerTest,
field.should_autocomplete = true;
// Autocomplete manager is not called for suggestions.
- autofill_manager_->autocomplete_history_manager_.reset(
- new MockAutocompleteHistoryManager(autofill_driver_.get(), &client));
- MockAutocompleteHistoryManager* m =
- static_cast<MockAutocompleteHistoryManager*>(
- autofill_manager_->autocomplete_history_manager_.get());
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
GetAutofillSuggestions(form, field);
@@ -3156,14 +3211,8 @@ TEST_F(
test::CreateTestFormField("Email", "email", "donkey", "email", &field);
// Autocomplete manager is not called for suggestions.
- autofill_manager_->autocomplete_history_manager_.reset(
- new MockAutocompleteHistoryManager(autofill_driver_.get(),
- autofill_manager_->client()));
- MockAutocompleteHistoryManager* m = static_cast<
- MockAutocompleteHistoryManager*>(
- autofill_manager_->autocomplete_history_manager_.get());
- EXPECT_CALL(*m,
- OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+ EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
GetAutofillSuggestions(form, field);
}
@@ -3175,13 +3224,8 @@ TEST_F(AutofillManagerTest, AutocompleteOffRespectedForAutocomplete) {
autofill_manager_->set_autofill_enabled(false);
autofill_manager_->SetExternalDelegate(external_delegate_.get());
- autofill_manager_->autocomplete_history_manager_.reset(
- new MockAutocompleteHistoryManager(autofill_driver_.get(), &client));
- MockAutocompleteHistoryManager* m = static_cast<
- MockAutocompleteHistoryManager*>(
- autofill_manager_->autocomplete_history_manager_.get());
- EXPECT_CALL(*m,
- OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+ EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
// Set up our form data.
FormData form;
@@ -3242,8 +3286,8 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions) {
ASSERT_TRUE(response.SerializeToString(&response_string));
std::vector<std::string> signatures;
- signatures.push_back(form_structure->FormSignature());
- signatures.push_back(form_structure2->FormSignature());
+ signatures.push_back(form_structure->FormSignatureAsStr());
+ signatures.push_back(form_structure2->FormSignatureAsStr());
base::HistogramTester histogram_tester;
autofill_manager_->OnLoadedServerPredictions(response_string, signatures);
@@ -3292,7 +3336,7 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions_ResetManager) {
ASSERT_TRUE(response.SerializeToString(&response_string));
std::vector<std::string> signatures;
- signatures.push_back(form_structure->FormSignature());
+ signatures.push_back(form_structure->FormSignatureAsStr());
// Reset the manager (such as during a navigation).
autofill_manager_->Reset();
@@ -3394,7 +3438,7 @@ TEST_F(AutofillManagerTest, FormSubmittedWithDifferentFields) {
FormsSeen(forms);
// Cache the expected form signature.
- std::string signature = FormStructure(form).FormSignature();
+ std::string signature = FormStructure(form).FormSignatureAsStr();
// Change the structure of the form prior to submission.
// Websites would typically invoke JavaScript either on page load or on form
@@ -4108,7 +4152,8 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_UnrecognizedAttribute) {
// Test to verify suggestions appears for forms having credit card number split
// across fields.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestionsForNumberSpitAcrossFields) {
+TEST_F(AutofillManagerTest,
+ GetCreditCardSuggestions_ForNumberSpitAcrossFields) {
// Set up our form data with credit card number split across fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -4165,15 +4210,9 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestionsForNumberSpitAcrossFields) {
// Test that inputs detected to be CVC inputs are forced to
// !should_autocomplete for AutocompleteHistoryManager::OnWillSubmitForm.
TEST_F(AutofillManagerTest, DontSaveCvcInAutocompleteHistory) {
- autofill_manager_->autocomplete_history_manager_.reset(
- new MockAutocompleteHistoryManager(autofill_driver_.get(),
- &autofill_client_));
FormData form_seen_by_ahm;
- MockAutocompleteHistoryManager* mock_ahm =
- static_cast<MockAutocompleteHistoryManager*>(
- autofill_manager_->autocomplete_history_manager_.get());
- EXPECT_CALL(*mock_ahm, OnWillSubmitForm(_))
- .WillOnce(SaveArg<0>(&form_seen_by_ahm));
+ MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+ EXPECT_CALL(*m, OnWillSubmitForm(_)).WillOnce(SaveArg<0>(&form_seen_by_ahm));
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -4907,6 +4946,141 @@ TEST_F(AutofillManagerTest, NoCreditCardSuggestionsForNonPrefixTokenMatch) {
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
+// Test that ShouldShowCreditCardSigninPromo behaves as expected for a credit
+// card form, with no impression limit and the feature enabled.
+TEST_F(AutofillManagerTest,
+ ShouldShowCreditCardSigninPromo_CreditCardField_NoLimit) {
+ // Enable the feature with no impression limit.
+ EnableCreditCardSigninPromoFeatureWithLimit(0);
+
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ FormFieldData field;
+ test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
+
+ // The result will depend on what ShouldShowSigninPromo(). We control its
+ // output and verify that both cases behave as expected.
+ EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
+ .WillOnce(testing::Return(true));
+ EXPECT_TRUE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
+
+ EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
+ .WillOnce(testing::Return(false));
+ EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
+}
+
+// Test that ShouldShowCreditCardSigninPromo doesn't show for a credit card form
+// when the feature is off.
+TEST_F(AutofillManagerTest,
+ ShouldShowCreditCardSigninPromo_CreditCardField_FeatureOff) {
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ FormFieldData field;
+ test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
+
+ // Returns false without calling ShouldShowSigninPromo().
+ EXPECT_CALL(autofill_client_, ShouldShowSigninPromo()).Times(0);
+ EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
+}
+
+// Test that ShouldShowCreditCardSigninPromo behaves as expected for a credit
+// card form with an impression limit and no impressions yet.
+TEST_F(AutofillManagerTest,
+ ShouldShowCreditCardSigninPromo_CreditCardField_UnmetLimit) {
+ // Enable the feature with an impression limit.
+ EnableCreditCardSigninPromoFeatureWithLimit(10);
+ // No impressions yet.
+ ASSERT_EQ(0, autofill_client_.GetPrefs()->GetInteger(
+ prefs::kAutofillCreditCardSigninPromoImpressionCount));
+
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ FormFieldData field;
+ test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
+
+ // The mock implementation of ShouldShowSigninPromo() will return true here,
+ // creating an impression, and false below, preventing an impression.
+ EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
+ .WillOnce(testing::Return(true));
+ EXPECT_TRUE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
+
+ // Expect to now have an impression.
+ EXPECT_EQ(1, autofill_client_.GetPrefs()->GetInteger(
+ prefs::kAutofillCreditCardSigninPromoImpressionCount));
+
+ EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
+ .WillOnce(testing::Return(false));
+ EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
+
+ // No additional impression.
+ EXPECT_EQ(1, autofill_client_.GetPrefs()->GetInteger(
+ prefs::kAutofillCreditCardSigninPromoImpressionCount));
+}
+
+// Test that ShouldShowCreditCardSigninPromo behaves as expected for a credit
+// card form with an impression limit that has been attained already.
+TEST_F(AutofillManagerTest,
+ ShouldShowCreditCardSigninPromo_CreditCardField_WithAttainedLimit) {
+ // Enable the feature with an impression limit.
+ EnableCreditCardSigninPromoFeatureWithLimit(10);
+
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ FormFieldData field;
+ test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
+
+ // Set the impression count to the same value as the limit.
+ autofill_client_.GetPrefs()->SetInteger(
+ prefs::kAutofillCreditCardSigninPromoImpressionCount, 10);
+
+ // Both calls will now return false, regardless of the mock implementation of
+ // ShouldShowSigninPromo().
+ EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
+ .WillOnce(testing::Return(true));
+ EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
+
+ EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
+ .WillOnce(testing::Return(false));
+ EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
+
+ // Number of impressions stay the same.
+ EXPECT_EQ(10, autofill_client_.GetPrefs()->GetInteger(
+ prefs::kAutofillCreditCardSigninPromoImpressionCount));
+}
+
+// Test that ShouldShowCreditCardSigninPromo behaves as expected for an address
+// form.
+TEST_F(AutofillManagerTest, ShouldShowCreditCardSigninPromo_AddressField) {
+ // Set up our form data.
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ FormFieldData field;
+ test::CreateTestFormField("First Name", "firstname", "", "text", &field);
+
+ // Call will now return false, because it is initiated from an address field.
+ EXPECT_CALL(autofill_client_, ShouldShowSigninPromo()).Times(0);
+ EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
+}
+
// Verify that typing "S" into the middle name field will match and order middle
// names "Shawn Smith" followed by "Adam Smith" i.e. prefix matched followed by
// substring matched.
diff --git a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
index 3baf43244ec..dfa93142527 100644
--- a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
@@ -16,6 +16,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/autofill_type.h"
@@ -183,6 +184,7 @@ class AutofillMergeTest : public DataDrivenTest,
PersonalDataManagerMock personal_data_;
private:
+ base::test::ScopedFeatureList scoped_feature_list_;
std::map<std::string, ServerFieldType> string_to_field_type_map_;
DISALLOW_COPY_AND_ASSIGN(AutofillMergeTest);
@@ -201,12 +203,7 @@ AutofillMergeTest::~AutofillMergeTest() {
void AutofillMergeTest::SetUp() {
test::DisableSystemServices(nullptr);
-
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(kAutofillProfileCleanup.name,
- std::string());
- base::FeatureList::SetInstance(std::move(feature_list));
+ scoped_feature_list_.InitAndEnableFeature(kAutofillProfileCleanup);
}
void AutofillMergeTest::TearDown() {
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc
index ff13a655a9c..54a927a430b 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics.cc
@@ -265,6 +265,13 @@ void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric) {
}
// static
+void AutofillMetrics::LogCreditCardFillingInfoBarMetric(InfoBarMetric metric) {
+ DCHECK_LT(metric, NUM_INFO_BAR_METRICS);
+ UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardFillingInfoBar", metric,
+ NUM_INFO_BAR_METRICS);
+}
+
+// static
void AutofillMetrics::LogSaveCardPromptMetric(SaveCardPromptMetric metric,
bool is_uploading,
bool is_reshow) {
@@ -522,6 +529,16 @@ void AutofillMetrics::LogStoredLocalCreditCardCount(size_t num_local_cards) {
}
// static
+void AutofillMetrics::LogStoredServerCreditCardCounts(
+ size_t num_masked_cards,
+ size_t num_unmasked_cards) {
+ UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredServerCreditCardCount.Masked",
+ num_masked_cards);
+ UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredServerCreditCardCount.Unmasked",
+ num_unmasked_cards);
+}
+
+// static
void AutofillMetrics::LogNumberOfProfilesAtAutofillableFormSubmission(
size_t num_profiles) {
UMA_HISTOGRAM_COUNTS(
@@ -641,6 +658,11 @@ void AutofillMetrics::LogNumberOfProfilesRemovedDuringDedupe(
std::min(int(num_removed), 50));
}
+// static
+void AutofillMetrics::LogIsQueriedCreditCardFormSecure(bool is_secure) {
+ UMA_HISTOGRAM_BOOLEAN("Autofill.QueriedCreditCardFormIsSecure", is_secure);
+}
+
AutofillMetrics::FormEventLogger::FormEventLogger(bool is_for_credit_card)
: is_for_credit_card_(is_for_credit_card),
is_server_data_available_(false),
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h
index de9b8ff5480..fa0aaa35de2 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.h
+++ b/chromium/components/autofill/core/browser/autofill_metrics.h
@@ -513,6 +513,7 @@ class AutofillMetrics {
static void LogCardUploadDecisionMetric(CardUploadDecisionMetric metric);
static void LogCreditCardInfoBarMetric(InfoBarMetric metric);
+ static void LogCreditCardFillingInfoBarMetric(InfoBarMetric metric);
static void LogSaveCardPromptMetric(SaveCardPromptMetric metric,
bool is_uploading,
bool is_reshow);
@@ -600,6 +601,10 @@ class AutofillMetrics {
// This should be called each time a new profile is launched.
static void LogStoredLocalCreditCardCount(size_t num_local_cards);
+ // This should be called each time a new profile is launched.
+ static void LogStoredServerCreditCardCounts(size_t num_masked_cards,
+ size_t num_unmasked_cards);
+
// Log the number of profiles available when an autofillable form is
// submitted.
static void LogNumberOfProfilesAtAutofillableFormSubmission(
@@ -646,6 +651,10 @@ class AutofillMetrics {
// Log how many profiles were removed as part of the deduplication process.
static void LogNumberOfProfilesRemovedDuringDedupe(size_t num_removed);
+ // Log whether the Autofill query on a credit card form is made in a secure
+ // context.
+ static void LogIsQueriedCreditCardFormSecure(bool is_secure);
+
// Utility to autofill form events in the relevant histograms depending on
// the presence of server and/or local data.
class FormEventLogger {
diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
index 1d5c5168f54..73c9ae8fd4a 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -155,22 +155,24 @@ class TestPersonalDataManager : public PersonalDataManager {
local_credit_cards_.clear();
server_credit_cards_.clear();
if (include_local_credit_card) {
- CreditCard* credit_card = new CreditCard;
- credit_card->set_guid("10000000-0000-0000-0000-000000000001");
- local_credit_cards_.push_back(credit_card);
+ std::unique_ptr<CreditCard> credit_card(new CreditCard(
+ "10000000-0000-0000-0000-000000000001", std::string()));
+ test::SetCreditCardInfo(credit_card.get(), nullptr, "4111111111111111",
+ "12", "24");
+ local_credit_cards_.push_back(credit_card.release());
}
if (include_masked_server_credit_card) {
- CreditCard* credit_card = new CreditCard(
- CreditCard::MASKED_SERVER_CARD, "server_id");
+ std::unique_ptr<CreditCard> credit_card(new CreditCard(
+ CreditCard::MASKED_SERVER_CARD, "server_id"));
credit_card->set_guid("10000000-0000-0000-0000-000000000002");
credit_card->SetTypeForMaskedCard(kDiscoverCard);
- server_credit_cards_.push_back(credit_card);
+ server_credit_cards_.push_back(credit_card.release());
}
if (include_full_server_credit_card) {
- CreditCard* credit_card = new CreditCard(
- CreditCard::FULL_SERVER_CARD, "server_id");
+ std::unique_ptr<CreditCard> credit_card(new CreditCard(
+ CreditCard::FULL_SERVER_CARD, "server_id"));
credit_card->set_guid("10000000-0000-0000-0000-000000000003");
- server_credit_cards_.push_back(credit_card);
+ server_credit_cards_.push_back(credit_card.release());
}
Refresh();
}
@@ -753,7 +755,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
ASSERT_TRUE(response.SerializeToString(&response_string));
std::vector<std::string> signatures;
- signatures.push_back(form_structure->FormSignature());
+ signatures.push_back(form_structure->FormSignatureAsStr());
base::HistogramTester histogram_tester;
autofill_manager_->OnLoadedServerPredictions(response_string, signatures);
@@ -1511,6 +1513,56 @@ TEST_F(AutofillMetricsTest, StoredLocalCreditCardCount) {
}
}
+// Test that the masked server credit card counts are logged correctly.
+TEST_F(AutofillMetricsTest, StoredServerCreditCardCounts_Masked) {
+ // The metrics should be logged when the credit cards are first loaded.
+ {
+ base::HistogramTester histogram_tester;
+ personal_data_->RecreateCreditCards(
+ false /* include_local_credit_card */,
+ true /* include_masked_server_credit_card */,
+ false /* include_full_server_credit_card */);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.StoredServerCreditCardCount.Masked", 1, 1);
+ }
+
+ // The metrics should only be logged once.
+ {
+ base::HistogramTester histogram_tester;
+ personal_data_->RecreateCreditCards(
+ false /* include_local_credit_card */,
+ true /* include_masked_server_credit_card */,
+ true /* include_full_server_credit_card */);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.StoredServerCreditCardCount.Masked", 0);
+ }
+}
+
+// Test that the unmasked (full) server credit card counts are logged correctly.
+TEST_F(AutofillMetricsTest, StoredServerCreditCardCounts_Unmasked) {
+ // The metrics should be logged when the credit cards are first loaded.
+ {
+ base::HistogramTester histogram_tester;
+ personal_data_->RecreateCreditCards(
+ false /* include_local_credit_card */,
+ false /* include_masked_server_credit_card */,
+ true /* include_full_server_credit_card */);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.StoredServerCreditCardCount.Unmasked", 1, 1);
+ }
+
+ // The metrics should only be logged once.
+ {
+ base::HistogramTester histogram_tester;
+ personal_data_->RecreateCreditCards(
+ false /* include_local_credit_card */,
+ false /* include_masked_server_credit_card */,
+ true /* include_full_server_credit_card */);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.StoredServerCreditCardCount.Unmasked", 0);
+ }
+}
+
// Test that we correctly log when Autofill is enabled.
TEST_F(AutofillMetricsTest, AutofillIsEnabledAtStartup) {
base::HistogramTester histogram_tester;
@@ -1812,6 +1864,56 @@ TEST_F(AutofillMetricsTest, PolledCreditCardSuggestions_DebounceLogs) {
"Autofill_PolledCreditCardSuggestions"));
}
+// Tests that the Autofill.QueriedCreditCardFormIsSecure histogram is logged
+// properly.
+TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) {
+ personal_data_->RecreateCreditCards(
+ true /* include_local_credit_card */,
+ false /* include_masked_server_credit_card */,
+ false /* include_full_server_credit_card */);
+
+ // Set up the form data.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+
+ FormFieldData field;
+ std::vector<ServerFieldType> field_types;
+ test::CreateTestFormField("Month", "card_month", "", "text", &field);
+ form.fields.push_back(field);
+ field_types.push_back(CREDIT_CARD_EXP_MONTH);
+ test::CreateTestFormField("Year", "card_year", "", "text", &field);
+ form.fields.push_back(field);
+ field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
+ test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ form.fields.push_back(field);
+ field_types.push_back(CREDIT_CARD_NUMBER);
+
+ // Simulate having seen this form on page load.
+ autofill_manager_->AddSeenForm(form, field_types, field_types);
+
+ {
+ // Simulate an Autofill query on a credit card field.
+ autofill_client_.set_is_context_secure(true);
+ base::HistogramTester histogram_tester;
+ autofill_manager_->OnQueryFormFieldAutofill(0, form, form.fields[1],
+ gfx::RectF());
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.QueriedCreditCardFormIsSecure", true, 1);
+ }
+
+ {
+ // Simulate an Autofill query on a credit card field.
+ autofill_client_.set_is_context_secure(false);
+ base::HistogramTester histogram_tester;
+ autofill_manager_->OnQueryFormFieldAutofill(0, form, form.fields[1],
+ gfx::RectF());
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.QueriedCreditCardFormIsSecure", false, 1);
+ }
+}
+
// Tests that the Autofill_PolledProfileSuggestions user action is only logged
// once if the field is queried repeatedly.
TEST_F(AutofillMetricsTest, PolledProfileSuggestions_DebounceLogs) {
diff --git a/chromium/components/autofill/core/browser/autofill_profile.cc b/chromium/components/autofill/core/browser/autofill_profile.cc
index f73fe5eece0..602cf1bf7bb 100644
--- a/chromium/components/autofill/core/browser/autofill_profile.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile.cc
@@ -253,8 +253,8 @@ void AutofillProfile::GetMatchingTypes(
const std::string& app_locale,
ServerFieldTypeSet* matching_types) const {
FormGroupList info = FormGroups();
- for (const auto& it : info) {
- it->GetMatchingTypes(text, app_locale, matching_types);
+ for (const auto* form_group : info) {
+ form_group->GetMatchingTypes(text, app_locale, matching_types);
}
}
@@ -449,10 +449,11 @@ bool AutofillProfile::MergeDataFrom(const AutofillProfile& profile,
DVLOG(1) << "Merging profiles:\nSource = " << profile << "\nDest = " << *this;
// The comparator's merge operations are biased to prefer the data in the
- // first profile parameter when the data is the same modulo case. We pass the
- // incoming profile in this position to prefer accepting updates instead of
- // preserving the original data. I.e., passing the incoming profile first
- // accepts case changes, the other ways does not.
+ // first profile parameter when the data is the same modulo case. We expect
+ // the caller to pass the incoming profile in this position to prefer
+ // accepting updates instead of preserving the original data. I.e., passing
+ // the incoming profile first accepts case and diacritic changes, for example,
+ // the other ways does not.
if (!comparator.MergeNames(profile, *this, &name) ||
!comparator.MergeEmailAddresses(profile, *this, &email) ||
!comparator.MergeCompanyNames(profile, *this, &company) ||
@@ -462,16 +463,24 @@ bool AutofillProfile::MergeDataFrom(const AutofillProfile& profile,
return false;
}
+ // TODO(rogerm): As implemented, "origin" really denotes "domain of last use".
+ // Find a better merge heuristic. Ditto for language code.
set_origin(profile.origin());
set_language_code(profile.language_code());
- set_use_count(profile.use_count() + use_count());
- if (profile.use_date() > use_date())
- set_use_date(profile.use_date());
- // Now that the preferred values have been obtained, update the fields which
- // need to be modified, if any. Note: that we're comparing the fields for
- // representational equality below (i.e., are the values byte for byte the
- // same).
+ // Update the use-count to be the max of the two merge-counts. Alternatively,
+ // we could have summed the two merge-counts. We don't sum because it skews
+ // the frecency value on merge and double counts usage on profile reuse.
+ // Profile reuse is accounted for on RecordUseOf() on selection of a profile
+ // in the autofill drop-down; we don't need to account for that here. Further,
+ // a similar, fully-typed submission that merges to an existing profile should
+ // not be counted as a re-use of that profile.
+ set_use_count(std::max(profile.use_count(), use_count()));
+ set_use_date(std::max(profile.use_date(), use_date()));
+
+ // Update the fields which need to be modified, if any. Note: that we're
+ // comparing the fields for representational equality below (i.e., are the
+ // values byte for byte the same).
bool modified = false;
@@ -698,8 +707,8 @@ void AutofillProfile::RecordAndLogUse() {
void AutofillProfile::GetSupportedTypes(
ServerFieldTypeSet* supported_types) const {
FormGroupList info = FormGroups();
- for (const auto& it : info) {
- it->GetSupportedTypes(supported_types);
+ for (const auto* form_group : info) {
+ form_group->GetSupportedTypes(supported_types);
}
}
diff --git a/chromium/components/autofill/core/browser/autofill_profile_comparator.cc b/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
index 42890407284..edfe2450d67 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_comparator.cc
@@ -174,6 +174,7 @@ bool AutofillProfileComparator::MergeNames(const AutofillProfile& p1,
const AutofillType kFullName(NAME_FULL);
const base::string16& full_name_1 = p1.GetInfo(kFullName, app_locale_);
const base::string16& full_name_2 = p2.GetInfo(kFullName, app_locale_);
+
const base::string16& normalized_full_name_1 =
NormalizeForComparison(full_name_1);
const base::string16& normalized_full_name_2 =
@@ -186,6 +187,10 @@ bool AutofillProfileComparator::MergeNames(const AutofillProfile& p1,
} else if (normalized_full_name_2.empty()) {
// p2 has no name, so use the name from p1.
best_name = &full_name_1;
+ } else if (data_util::IsCJKName(full_name_1) &&
+ data_util::IsCJKName(full_name_2)) {
+ // Use a separate logic for CJK names.
+ return MergeCJKNames(p1, p2, name_info);
} else if (IsNameVariantOf(normalized_full_name_1, normalized_full_name_2)) {
// full_name_2 is a variant of full_name_1.
best_name = &full_name_1;
@@ -199,6 +204,78 @@ bool AutofillProfileComparator::MergeNames(const AutofillProfile& p1,
return true;
}
+bool AutofillProfileComparator::MergeCJKNames(
+ const AutofillProfile& p1,
+ const AutofillProfile& p2,
+ NameInfo* info) const {
+ DCHECK(data_util::IsCJKName(p1.GetInfo(AutofillType(NAME_FULL),
+ app_locale_)));
+ DCHECK(data_util::IsCJKName(p2.GetInfo(AutofillType(NAME_FULL),
+ app_locale_)));
+
+ struct Name {
+ base::string16 given;
+ base::string16 surname;
+ base::string16 full;
+ };
+
+ Name name1 = {
+ p1.GetRawInfo(NAME_FIRST),
+ p1.GetRawInfo(NAME_LAST),
+ p1.GetRawInfo(NAME_FULL)
+ };
+ Name name2 = {
+ p2.GetRawInfo(NAME_FIRST),
+ p2.GetRawInfo(NAME_LAST),
+ p2.GetRawInfo(NAME_FULL)
+ };
+
+ const Name* most_recent_name =
+ p2.use_date() >= p1.use_date() ? &name2 : &name1;
+
+ // The two |NameInfo| objects might disagree about what the full name looks
+ // like. If only one of the two has an explicit (user-entered) full name, use
+ // that as ground truth. Otherwise, use the most recent profile.
+ const Name* full_name_candidate;
+ if (name1.full.empty()) {
+ full_name_candidate = &name2;
+ } else if (name2.full.empty()) {
+ full_name_candidate = &name1;
+ } else {
+ full_name_candidate = most_recent_name;
+ }
+
+ // The two |NameInfo| objects might disagree about how the name is split into
+ // given/surname. If only one of the two has an explicit (user-entered)
+ // given/surname pair, use that as ground truth. Otherwise, use the most
+ // recent profile.
+ const Name* name_parts_candidate;
+ if (name1.given.empty() || name1.surname.empty()) {
+ name_parts_candidate = &name2;
+ } else if (name2.given.empty() || name2.surname.empty()) {
+ name_parts_candidate = &name1;
+ } else {
+ name_parts_candidate = most_recent_name;
+ }
+
+ if (name_parts_candidate->given.empty() ||
+ name_parts_candidate->surname.empty()) {
+ // The name was not split correctly into a given/surname, so use the logic
+ // from |SplitName()|.
+ info->SetInfo(AutofillType(NAME_FULL), full_name_candidate->full,
+ app_locale_);
+ } else {
+ // The name was already split into a given/surname, so keep those intact.
+ if (!full_name_candidate->full.empty()) {
+ info->SetRawInfo(NAME_FULL, full_name_candidate->full);
+ }
+ info->SetRawInfo(NAME_FIRST, name_parts_candidate->given);
+ info->SetRawInfo(NAME_LAST, name_parts_candidate->surname);
+ }
+
+ return true;
+}
+
bool AutofillProfileComparator::MergeEmailAddresses(
const AutofillProfile& p1,
const AutofillProfile& p2,
@@ -334,7 +411,7 @@ bool AutofillProfileComparator::MergePhoneNumbers(
// include the country code prefix.
if (merged_number.country_code() == 1 &&
merged_number.national_number() <= 9999999 &&
- new_number.find("+1") == 0) {
+ base::StartsWith(new_number, "+1", base::CompareCase::SENSITIVE)) {
size_t offset = 2; // The char just after "+1".
while (offset < new_number.size() &&
base::IsAsciiWhitespace(new_number[offset])) {
@@ -471,7 +548,7 @@ bool AutofillProfileComparator::MergeAddresses(const AutofillProfile& p1,
break;
case S2_CONTAINS_S1:
// address2 has more unique tokens than address1.
- address->SetInfo(kStreetAddress, address1, app_locale_);
+ address->SetInfo(kStreetAddress, address2, app_locale_);
break;
case DIFFERENT_TOKENS:
default:
@@ -621,13 +698,32 @@ bool AutofillProfileComparator::HaveMergeableNames(
base::string16 full_name_2 =
NormalizeForComparison(p2.GetInfo(AutofillType(NAME_FULL), app_locale_));
+ if (full_name_1.empty() || full_name_2.empty() ||
+ full_name_1 == full_name_2) {
+ return true;
+ }
+
+ if (data_util::IsCJKName(full_name_1) && data_util::IsCJKName(full_name_2)) {
+ return HaveMergeableCJKNames(p1, p2);
+ }
+
// Is it reasonable to merge the names from p1 and p2.
- return full_name_1.empty() || full_name_2.empty() ||
- (full_name_1 == full_name_2) ||
- IsNameVariantOf(full_name_1, full_name_2) ||
+ return IsNameVariantOf(full_name_1, full_name_2) ||
IsNameVariantOf(full_name_2, full_name_1);
}
+bool AutofillProfileComparator::HaveMergeableCJKNames(
+ const AutofillProfile& p1,
+ const AutofillProfile& p2) const {
+ base::string16 name_1 =
+ NormalizeForComparison(p1.GetInfo(AutofillType(NAME_FULL), app_locale_),
+ DISCARD_WHITESPACE);
+ base::string16 name_2 =
+ NormalizeForComparison(p2.GetInfo(AutofillType(NAME_FULL), app_locale_),
+ DISCARD_WHITESPACE);
+ return name_1 == name_2;
+}
+
bool AutofillProfileComparator::HaveMergeableEmailAddresses(
const AutofillProfile& p1,
const AutofillProfile& p2) const {
diff --git a/chromium/components/autofill/core/browser/autofill_profile_comparator.h b/chromium/components/autofill/core/browser/autofill_profile_comparator.h
index d594dec3f62..4b69d184112 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_comparator.h
+++ b/chromium/components/autofill/core/browser/autofill_profile_comparator.h
@@ -160,6 +160,14 @@ class AutofillProfileComparator {
bool HaveMergeableNames(const AutofillProfile& p1,
const AutofillProfile& p2) const;
+ // Returns true if |p1| and |p2| have Chinese, Japanese, or Korean names that
+ // are equivalent for the purpose of merging profiles.
+ //
+ // This method is used internally by |HaveMergeableNames()| when CJK names are
+ // detected.
+ bool HaveMergeableCJKNames(const AutofillProfile& p1,
+ const AutofillProfile& p2) const;
+
// Returns true if |p1| and |p2| have email addresses which are equivalent for
// the purposes of merging the two profiles. This means one of the email
// addresses is empty, or the email addresses are the same (modulo case).
@@ -200,6 +208,13 @@ class AutofillProfileComparator {
bool HaveMergeableAddresses(const AutofillProfile& p1,
const AutofillProfile& p2) const;
+ // Populates |name_info| with the result of merging the Chinese, Japanese or
+ // Korean names in |p1| and |p2|. Returns true if successful. Expects that
+ // |p1| and |p2| have already been found to be mergeable, and have CJK names.
+ bool MergeCJKNames(const AutofillProfile& p1,
+ const AutofillProfile& p2,
+ NameInfo* info) const;
+
private:
l10n::CaseInsensitiveCompare case_insensitive_compare_;
std::unique_ptr<icu::Transliterator> transliterator_;
diff --git a/chromium/components/autofill/core/browser/autofill_profile_comparator_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_comparator_unittest.cc
index ff4727f0fe1..bcd0274eb66 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_comparator_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_comparator_unittest.cc
@@ -79,6 +79,18 @@ class AutofillProfileComparatorTest : public ::testing::Test {
autofill::CountryNames::SetLocaleString(kLocale);
}
+ NameInfo CreateNameInfo(const char* first,
+ const char* middle,
+ const char* last,
+ const char* full) {
+ NameInfo name;
+ name.SetRawInfo(NAME_FIRST, base::UTF8ToUTF16(first));
+ name.SetRawInfo(NAME_MIDDLE, base::UTF8ToUTF16(middle));
+ name.SetRawInfo(NAME_LAST, base::UTF8ToUTF16(last));
+ name.SetRawInfo(NAME_FULL, base::UTF8ToUTF16(full));
+ return name;
+ }
+
AutofillProfile CreateProfileWithName(const char* first,
const char* middle,
const char* last) {
@@ -311,6 +323,16 @@ TEST_F(AutofillProfileComparatorTest, NormalizeForComparison) {
// Diacritics removed.
EXPECT_EQ(UTF8ToUTF16("ă¾eoá •"),
comparator_.NormalizeForComparison(UTF8ToUTF16("ă¾Ă©Ă–ä́ •")));
+
+ // Spaces removed.
+ EXPECT_EQ(UTF8ToUTF16("́œ ́¬́„"), comparator_.NormalizeForComparison(
+ UTF8ToUTF16("́œ  ́¬́„"),
+ AutofillProfileComparator::DISCARD_WHITESPACE));
+
+ // Punctuation removed, Japanese kana normalized.
+ EXPECT_EQ(UTF8ToUTF16("ăƒ’ăƒ«ă‚±ă‚¤ăƒ„"), comparator_.NormalizeForComparison(
+ UTF8ToUTF16("ăƒ“ăƒ«ăƒ»ă‚²ă‚¤ăƒ„"),
+ AutofillProfileComparator::DISCARD_WHITESPACE));
}
TEST_F(AutofillProfileComparatorTest, GetNamePartVariants) {
@@ -640,6 +662,62 @@ TEST_F(AutofillProfileComparatorTest, MergeNames) {
MergeNamesAndExpect(p5, p5, synthesized); // We flesh out missing data.
}
+TEST_F(AutofillProfileComparatorTest, MergeCJKNames) {
+ // Korean names that are all mergeable, but constructed differently.
+ NameInfo name1 = CreateNameInfo("호", "", "́´́˜", "́´́˜ 호");
+ NameInfo name2 = CreateNameInfo("́´́˜í˜¸", "", "", "́´́˜í˜¸");
+ NameInfo name3 = CreateNameInfo("́˜í˜¸", "", "́´", "́´́˜í˜¸");
+ NameInfo name4 = CreateNameInfo("́˜í˜¸", "", "́´", "");
+ NameInfo name5 = CreateNameInfo("́˜í˜¸", "", "́´", "́´ ́˜í˜¸");
+
+
+ // Mergeable foreign name in Japanese with a 'KATAKANA MIDDLE DOT'.
+ NameInfo name6 = CreateNameInfo("", "", "", "ă‚²ă‚¤ăƒ„ăƒ»ăƒ“ăƒ«");
+ NameInfo name7 = CreateNameInfo("ăƒ“ăƒ«", "", "ă‚²ă‚¤ăƒ„", "");
+
+ // Set the use dates for the profiles, because |MergeCJKNames()| tries to use
+ // the most recent profile if there is a conflict. The ordering is
+ // p1 > p2 > p3 > p4 > p5, with p1 being the most recent.
+ AutofillProfile p1 = CreateProfileWithName(name1);
+ p1.set_use_date(base::Time::Now());
+ AutofillProfile p2 = CreateProfileWithName(name2);
+ p2.set_use_date(base::Time::Now() - base::TimeDelta::FromHours(1));
+ AutofillProfile p3 = CreateProfileWithName(name3);
+ p3.set_use_date(base::Time::Now() - base::TimeDelta::FromHours(2));
+ AutofillProfile p4 = CreateProfileWithName(name4);
+ p4.set_use_date(base::Time::Now() - base::TimeDelta::FromHours(3));
+ AutofillProfile p5 = CreateProfileWithName(name5);
+ p5.set_use_date(base::Time::Now() - base::TimeDelta::FromHours(4));
+
+ AutofillProfile p6 = CreateProfileWithName(name6);
+ AutofillProfile p7 = CreateProfileWithName(name7);
+
+ // Because |p1| is the most recent, it always wins over others.
+ MergeNamesAndExpect(p1, p2, CreateNameInfo("호", "", "́´́˜", "́´́˜ 호"));
+ MergeNamesAndExpect(p1, p3, CreateNameInfo("호", "", "́´́˜", "́´́˜ 호"));
+ MergeNamesAndExpect(p1, p4, CreateNameInfo("호", "", "́´́˜", "́´́˜ 호"));
+ MergeNamesAndExpect(p1, p5, CreateNameInfo("호", "", "́´́˜", "́´́˜ 호"));
+
+ // |p2| is more recent than |p3|, |p4|, and |p5|. However, it does not have a
+ // surname entry (it was probably parsed with the old logic), so the other
+ // profiles are used as the source for given/surname.
+ MergeNamesAndExpect(p2, p3, CreateNameInfo("́˜í˜¸", "", "́´", "́´́˜í˜¸"));
+ MergeNamesAndExpect(p2, p4, CreateNameInfo("́˜í˜¸", "", "́´", "́´́˜í˜¸"));
+ MergeNamesAndExpect(p2, p5, CreateNameInfo("́˜í˜¸", "", "́´", "́´́˜í˜¸"));
+
+ // |p3| is more recent than |p4| and |p5|.
+ MergeNamesAndExpect(p3, p4, CreateNameInfo("́˜í˜¸", "", "́´", "́´́˜í˜¸"));
+ MergeNamesAndExpect(p3, p5, CreateNameInfo("́˜í˜¸", "", "́´", "́´́˜í˜¸"));
+
+ // |p4| is more recent than |p5|. However, it does not have an explicit full
+ // name, so use the one from |p5|.
+ MergeNamesAndExpect(p4, p5, CreateNameInfo("́˜í˜¸", "", "́´", "́´ ́˜í˜¸"));
+
+ // There is no conflict between |p6| and |p7|, so use the parts from both.
+ MergeNamesAndExpect(p6, p7,
+ CreateNameInfo("ăƒ“ăƒ«", "", "ă‚²ă‚¤ăƒ„", "ă‚²ă‚¤ăƒ„ăƒ»ăƒ“ăƒ«"));
+}
+
TEST_F(AutofillProfileComparatorTest, MergeEmailAddresses) {
static const char kEmailA[] = "testaccount@domain.net";
static const char kEmailB[] = "TestAccount@Domain.Net";
diff --git a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
index b3c1c8cc8f3..d50ddecf7ee 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -547,17 +547,17 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_ja) {
profiles.back()->set_language_code("ja_JP");
static const char* kExpectedLabels[] = {
"",
- "ăƒŸă‚¯ åˆéŸ³",
- "å…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼ăƒŸă‚¯ åˆéŸ³",
- "å…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1ăƒŸă‚¯ åˆéŸ³",
- "æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1ăƒŸă‚¯ åˆéŸ³",
- "æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1ăƒŸă‚¯ åˆéŸ³",
- "〒106-6126æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1ăƒŸă‚¯ åˆéŸ³",
- "〒106-6126æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1ä¾‹ăƒŸă‚¯ åˆéŸ³",
- "〒106-6126æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1ä¾‹ăƒŸă‚¯ åˆéŸ³, Japan",
- "〒106-6126æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1ä¾‹ăƒŸă‚¯ åˆéŸ³, Japan, "
+ "åˆéŸ³ăƒŸă‚¯",
+ "å…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼åˆéŸ³ăƒŸă‚¯",
+ "å…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1åˆéŸ³ăƒŸă‚¯",
+ "æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1åˆéŸ³ăƒŸă‚¯",
+ "æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1åˆéŸ³ăƒŸă‚¯",
+ "〒106-6126æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1åˆéŸ³ăƒŸă‚¯",
+ "〒106-6126æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1例åˆéŸ³ăƒŸă‚¯",
+ "〒106-6126æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1例åˆéŸ³ăƒŸă‚¯, Japan",
+ "〒106-6126æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1例åˆéŸ³ăƒŸă‚¯, Japan, "
"miku@rei.com",
- "〒106-6126æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1ä¾‹ăƒŸă‚¯ åˆéŸ³, Japan, "
+ "〒106-6126æ±äº¬éƒ½æ¸¯åŒºå…­æœ¬æœ¨ăƒ’ăƒ«ă‚ºæ£®ă‚¿ăƒ¯ăƒ¼å…­æœ¬æœ¨ 6-10-1例åˆéŸ³ăƒŸă‚¯, Japan, "
"miku@rei.com, 03-6384-9000",
};
@@ -880,7 +880,7 @@ TEST(AutofillProfileTest, MergeDataFrom_SameProfile) {
AutofillProfile b = a;
b.set_guid(base::GenerateGUID());
EXPECT_TRUE(a.MergeDataFrom(b, "en-US"));
- EXPECT_EQ(2u, a.use_count());
+ EXPECT_EQ(1u, a.use_count());
// Now the profile is fully populated. Merging it again has no effect (except
// for usage statistics).
@@ -888,7 +888,7 @@ TEST(AutofillProfileTest, MergeDataFrom_SameProfile) {
c.set_guid(base::GenerateGUID());
c.set_use_count(3);
EXPECT_FALSE(a.MergeDataFrom(c, "en-US"));
- EXPECT_EQ(5u, a.use_count());
+ EXPECT_EQ(3u, a.use_count());
}
TEST(AutofillProfileTest, OverwriteName_AddNameFull) {
diff --git a/chromium/components/autofill/core/browser/autofill_regex_constants.cc b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
index 4c153b315f8..e5587bea511 100644
--- a/chromium/components/autofill/core/browser/autofill_regex_constants.cc
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
@@ -274,7 +274,7 @@ const char kLastNameRe[] =
"|姓" // ja-JP
"|morada|apelidos|surename|sobrenome" // pt-BR, pt-PT
"|Đ¤Đ°Đ¼Đ¸Đ»Đ¸Ñ" // ru
- "|́„±[^명]?"; // ko-KR
+ "|\\b́„±(?:[^명]|\\b)"; // ko-KR
/////////////////////////////////////////////////////////////////////////////
// phone_field.cc
diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
index 471e0d2fbf3..020d5e0df6b 100644
--- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
+++ b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -54,7 +54,7 @@ AutofillSaveCardInfoBarDelegateMobile::
void AutofillSaveCardInfoBarDelegateMobile::OnLegalMessageLinkClicked(
GURL url) {
- infobar()->owner()->OpenURL(url, NEW_FOREGROUND_TAB);
+ infobar()->owner()->OpenURL(url, WindowOpenDisposition::NEW_FOREGROUND_TAB);
}
int AutofillSaveCardInfoBarDelegateMobile::GetIconId() const {
@@ -97,7 +97,7 @@ base::string16 AutofillSaveCardInfoBarDelegateMobile::GetButtonLabel(
InfoBarButton button) const {
return l10n_util::GetStringUTF16(button == BUTTON_OK
? IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT
- : IDS_AUTOFILL_SAVE_CARD_PROMPT_DENY);
+ : IDS_NO_THANKS);
}
bool AutofillSaveCardInfoBarDelegateMobile::Accept() {
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc
index a27d8332db8..6994b6faa76 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc
@@ -340,7 +340,6 @@ void FillUploadField(AutofillUploadContents::Field* field,
unsigned signature,
const char* name,
const char* control_type,
- const char* label,
const char* autocomplete,
unsigned autofill_type,
const char* css_classes) {
@@ -349,8 +348,6 @@ void FillUploadField(AutofillUploadContents::Field* field,
field->set_name(name);
if (control_type)
field->set_type(control_type);
- if (label)
- field->set_label(label);
if (autocomplete)
field->set_autocomplete(autocomplete);
field->set_autofill_type(autofill_type);
@@ -361,15 +358,12 @@ void FillUploadField(AutofillUploadContents::Field* field,
void FillQueryField(AutofillQueryContents::Form::Field* field,
unsigned signature,
const char* name,
- const char* control_type,
- const char* label) {
+ const char* control_type) {
field->set_signature(signature);
if (name)
field->set_name(name);
if (control_type)
field->set_type(control_type);
- if (label)
- field->set_label(label);
}
} // namespace test
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h
index 677ab6c8e7f..4912732cb9e 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.h
@@ -131,7 +131,6 @@ void FillUploadField(AutofillUploadContents::Field* field,
unsigned signature,
const char* name,
const char* control_type,
- const char* label,
const char* autocomplete,
unsigned autofill_type,
const char* css_classes);
@@ -142,8 +141,7 @@ void FillUploadField(AutofillUploadContents::Field* field,
void FillQueryField(AutofillQueryContents::Form::Field* field,
unsigned signature,
const char* name,
- const char* control_type,
- const char* label);
+ const char* control_type);
} // namespace test
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc
index 0e4d0fbbcfc..119c492ca93 100644
--- a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc
+++ b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.cc
@@ -9,44 +9,36 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/prefs/pref_service.h"
-#include "components/sync_driver/sync_client.h"
-#include "components/sync_driver/sync_service.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/syncable_service.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/syncable_service.h"
+#include "components/sync/driver/sync_client.h"
+#include "components/sync/driver/sync_service.h"
namespace browser_sync {
AutofillWalletDataTypeController::AutofillWalletDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
+ syncer::ModelType type,
const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
- syncer::ModelType model_type,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
const scoped_refptr<autofill::AutofillWebDataService>& web_data_service)
- : NonUIDataTypeController(ui_thread, error_callback, sync_client),
- ui_thread_(ui_thread),
+ : NonUIDataTypeController(type, dump_stack, sync_client),
db_thread_(db_thread),
sync_client_(sync_client),
callback_registered_(false),
- model_type_(model_type),
web_data_service_(web_data_service),
currently_enabled_(IsEnabled()) {
- DCHECK(ui_thread_->BelongsToCurrentThread());
- DCHECK(model_type_ == syncer::AUTOFILL_WALLET_DATA ||
- model_type_ == syncer::AUTOFILL_WALLET_METADATA);
+ DCHECK(type == syncer::AUTOFILL_WALLET_DATA ||
+ type == syncer::AUTOFILL_WALLET_METADATA);
pref_registrar_.Init(sync_client_->GetPrefService());
pref_registrar_.Add(
autofill::prefs::kAutofillWalletImportEnabled,
base::Bind(&AutofillWalletDataTypeController::OnUserPrefChanged,
- base::Unretained(this)));
+ base::AsWeakPtr(this)));
}
AutofillWalletDataTypeController::~AutofillWalletDataTypeController() {}
-syncer::ModelType AutofillWalletDataTypeController::type() const {
- return model_type_;
-}
-
syncer::ModelSafeGroup AutofillWalletDataTypeController::model_safe_group()
const {
return syncer::GROUP_DB;
@@ -55,12 +47,12 @@ syncer::ModelSafeGroup AutofillWalletDataTypeController::model_safe_group()
bool AutofillWalletDataTypeController::PostTaskOnBackendThread(
const tracked_objects::Location& from_here,
const base::Closure& task) {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
return db_thread_->PostTask(from_here, task);
}
bool AutofillWalletDataTypeController::StartModels() {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
DCHECK_EQ(state(), MODEL_STARTING);
if (!web_data_service_)
@@ -71,7 +63,8 @@ bool AutofillWalletDataTypeController::StartModels() {
if (!callback_registered_) {
web_data_service_->RegisterDBLoadedCallback(
- base::Bind(&AutofillWalletDataTypeController::OnModelLoaded, this));
+ base::Bind(&AutofillWalletDataTypeController::OnModelLoaded,
+ base::AsWeakPtr(this)));
callback_registered_ = true;
}
@@ -79,7 +72,7 @@ bool AutofillWalletDataTypeController::StartModels() {
}
void AutofillWalletDataTypeController::StopModels() {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
// This function is called when shutting down (nothing is changing), when
// sync is disabled completely, or when wallet sync is disabled. In the
@@ -87,7 +80,7 @@ void AutofillWalletDataTypeController::StopModels() {
// and addresses copied from the server. This is different than other sync
// cases since this type of data reflects what's on the server rather than
// syncing local data between clients, so this extra step is required.
- sync_driver::SyncService* service = sync_client_->GetSyncService();
+ syncer::SyncService* service = sync_client_->GetSyncService();
// CanSyncStart indicates if sync is currently enabled at all. The preferred
// data type indicates if wallet sync data/metadata is enabled, and
@@ -102,12 +95,12 @@ void AutofillWalletDataTypeController::StopModels() {
}
bool AutofillWalletDataTypeController::ReadyForStart() const {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
return currently_enabled_;
}
void AutofillWalletDataTypeController::OnUserPrefChanged() {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
bool new_enabled = IsEnabled();
if (currently_enabled_ == new_enabled)
@@ -117,24 +110,20 @@ void AutofillWalletDataTypeController::OnUserPrefChanged() {
if (currently_enabled_) {
// The preference was just enabled. Trigger a reconfiguration. This will do
// nothing if the type isn't preferred.
- sync_driver::SyncService* sync_service = sync_client_->GetSyncService();
+ syncer::SyncService* sync_service = sync_client_->GetSyncService();
sync_service->ReenableDatatype(type());
} else {
- // Post a task to the backend thread to stop the datatype.
+ // Report the error (which will stop the datatype asynchronously).
if (state() != NOT_RUNNING && state() != STOPPING) {
- PostTaskOnBackendThread(
- FROM_HERE,
- base::Bind(&DataTypeController::OnSingleDataTypeUnrecoverableError,
- this,
- syncer::SyncError(
- FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR,
- "Wallet syncing is disabled by policy.", type())));
+ CreateErrorHandler()->OnUnrecoverableError(
+ syncer::SyncError(FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR,
+ "Wallet syncing is disabled by policy.", type()));
}
}
}
bool AutofillWalletDataTypeController::IsEnabled() {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
// Require the user-visible pref to be enabled to sync Wallet data/metadata.
PrefService* ps = sync_client_->GetPrefService();
diff --git a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h
index 84ed7b6baae..e483e0b304f 100644
--- a/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h
+++ b/chromium/components/autofill/core/browser/autofill_wallet_data_type_controller.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_SYNC_DRIVER_GLUE_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
-#define COMPONENTS_SYNC_DRIVER_GLUE_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
#include "base/macros.h"
#include "components/prefs/pref_change_registrar.h"
-#include "components/sync_driver/non_ui_data_type_controller.h"
+#include "components/sync/driver/non_ui_data_type_controller.h"
namespace autofill {
class AutofillWebDataService;
@@ -17,24 +17,21 @@ namespace browser_sync {
// Controls syncing of either AUTOFILL_WALLET or AUTOFILL_WALLET_METADATA.
class AutofillWalletDataTypeController
- : public sync_driver::NonUIDataTypeController {
+ : public syncer::NonUIDataTypeController {
public:
- // |model_type| should be either AUTOFILL_WALLET or AUTOFILL_WALLET_METADATA.
+ // |type| should be either AUTOFILL_WALLET or AUTOFILL_WALLET_METADATA.
+ // |dump_stack| is called when an unrecoverable error occurs.
AutofillWalletDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
+ syncer::ModelType type,
const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
- syncer::ModelType model_type,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
const scoped_refptr<autofill::AutofillWebDataService>& web_data_service);
+ ~AutofillWalletDataTypeController() override;
// NonUIDataTypeController implementation.
- syncer::ModelType type() const override;
syncer::ModelSafeGroup model_safe_group() const override;
- protected:
- ~AutofillWalletDataTypeController() override;
-
private:
// NonUIDataTypeController implementation.
bool PostTaskOnBackendThread(const tracked_objects::Location& from_here,
@@ -49,21 +46,15 @@ class AutofillWalletDataTypeController
// Returns true if the prefs are set such that wallet sync should be enabled.
bool IsEnabled();
- // A reference to the UI thread's task runner.
- const scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
-
// A reference to the DB thread's task runner.
const scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
// A pointer to the sync client.
- sync_driver::SyncClient* const sync_client_;
+ syncer::SyncClient* const sync_client_;
// Whether the database loaded callback has been registered.
bool callback_registered_;
- // The model type for this DTC; can be AUTOFILL_WALLET_DATA or _METADATA.
- syncer::ModelType model_type_;
-
// A reference to the AutofillWebDataService for this controller.
scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
@@ -79,4 +70,4 @@ class AutofillWalletDataTypeController
} // namespace browser_sync
-#endif // COMPONENTS_SYNC_DRIVER_GLUE_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
diff --git a/chromium/components/autofill/core/browser/contact_info.cc b/chromium/components/autofill/core/browser/contact_info.cc
index 352933661db..ec4399495be 100644
--- a/chromium/components/autofill/core/browser/contact_info.cc
+++ b/chromium/components/autofill/core/browser/contact_info.cc
@@ -153,17 +153,7 @@ base::string16 NameInfo::FullName() const {
if (!full_.empty())
return full_;
- std::vector<base::string16> full_name;
- if (!given_.empty())
- full_name.push_back(given_);
-
- if (!middle_.empty())
- full_name.push_back(middle_);
-
- if (!family_.empty())
- full_name.push_back(family_);
-
- return base::JoinString(full_name, base::ASCIIToUTF16(" "));
+ return data_util::JoinNameParts(given_, middle_, family_);
}
base::string16 NameInfo::MiddleInitial() const {
diff --git a/chromium/components/autofill/core/browser/country_data.cc b/chromium/components/autofill/core/browser/country_data.cc
index 4d066245b20..443b2f60b90 100644
--- a/chromium/components/autofill/core/browser/country_data.cc
+++ b/chromium/components/autofill/core/browser/country_data.cc
@@ -20,8 +20,11 @@ struct StaticCountryData {
// Maps country codes to localized label string identifiers. Keep this sorted
// by country code.
+// This list is comprized of countries appearing in both
+// //third_party/icu/source/data/region/en.txt and
+// //third_party/libaddressinput/src/cpp/src/region_data_constants.cc.
const StaticCountryData kCountryData[] = {
- // clang-format off
+ // clang-format off
{ "AC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIRES_CITY } },
@@ -112,6 +115,9 @@ const StaticCountryData kCountryData[] = {
{ "BO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIREMENTS_UNKNOWN } },
+ { "BQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
+ IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
+ ADDRESS_REQUIREMENTS_UNKNOWN } },
{ "BR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_STATE,
ADDRESS_REQUIRES_CITY_STATE_ZIP } },
@@ -178,6 +184,9 @@ const StaticCountryData kCountryData[] = {
{ "CV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_ISLAND,
ADDRESS_REQUIREMENTS_UNKNOWN } },
+ { "CW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
+ IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
+ ADDRESS_REQUIREMENTS_UNKNOWN } },
{ "CX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIREMENTS_UNKNOWN } },
@@ -340,6 +349,9 @@ const StaticCountryData kCountryData[] = {
{ "IQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIRES_CITY_STATE } },
+ { "IR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
+ IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
+ ADDRESS_REQUIREMENTS_UNKNOWN } },
{ "IS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIREMENTS_UNKNOWN } },
@@ -451,6 +463,9 @@ const StaticCountryData kCountryData[] = {
{ "ML", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIREMENTS_UNKNOWN } },
+ { "MM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
+ IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
+ ADDRESS_REQUIREMENTS_UNKNOWN } },
{ "MN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIREMENTS_UNKNOWN } },
@@ -631,12 +646,18 @@ const StaticCountryData kCountryData[] = {
{ "SR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIREMENTS_UNKNOWN } },
+ { "SS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
+ IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
+ ADDRESS_REQUIREMENTS_UNKNOWN } },
{ "ST", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIREMENTS_UNKNOWN } },
{ "SV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIRES_CITY_STATE } },
+ { "SX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
+ IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
+ ADDRESS_REQUIREMENTS_UNKNOWN } },
{ "SZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIREMENTS_UNKNOWN } },
@@ -754,7 +775,7 @@ const StaticCountryData kCountryData[] = {
{ "ZW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
ADDRESS_REQUIREMENTS_UNKNOWN } },
- // clang-format on
+ // clang-format on
};
// GetCountryCodes and GetCountryData compute the data for CountryDataMap
diff --git a/chromium/components/autofill/core/browser/credit_card.cc b/chromium/components/autofill/core/browser/credit_card.cc
index a37f16fba01..27700bed98a 100644
--- a/chromium/components/autofill/core/browser/credit_card.cc
+++ b/chromium/components/autofill/core/browser/credit_card.cc
@@ -93,15 +93,6 @@ CreditCard::CreditCard(const std::string& guid, const std::string& origin)
expiration_year_(0),
server_status_(OK) {}
-CreditCard::CreditCard(const base::string16& card_number,
- int expiration_month,
- int expiration_year)
- : CreditCard() {
- SetNumber(card_number);
- SetExpirationMonth(expiration_month);
- SetExpirationYear(expiration_year);
-}
-
CreditCard::CreditCard(RecordType type, const std::string& server_id)
: CreditCard() {
DCHECK(type == MASKED_SERVER_CARD || type == FULL_SERVER_CARD);
@@ -134,9 +125,6 @@ base::string16 CreditCard::TypeForDisplay(const std::string& type) {
return ::autofill::TypeForFill(type);
}
-// This method is not compiled on iOS because the resources are not used and
-// should not be shipped.
-#if !defined(OS_IOS)
// static
int CreditCard::IconResourceId(const std::string& type) {
if (type == kAmericanExpressCard)
@@ -159,7 +147,6 @@ int CreditCard::IconResourceId(const std::string& type) {
DCHECK_EQ(kGenericCard, type);
return IDR_AUTOFILL_CC_GENERIC;
}
-#endif // #if !defined(OS_IOS)
// static
const char* CreditCard::GetCreditCardType(const base::string16& number) {
diff --git a/chromium/components/autofill/core/browser/credit_card.h b/chromium/components/autofill/core/browser/credit_card.h
index 3a73533e594..1e4efd12f37 100644
--- a/chromium/components/autofill/core/browser/credit_card.h
+++ b/chromium/components/autofill/core/browser/credit_card.h
@@ -46,9 +46,6 @@ class CreditCard : public AutofillDataModel {
};
CreditCard(const std::string& guid, const std::string& origin);
- CreditCard(const base::string16& card_number,
- int expiration_month,
- int expiration_year);
// Creates a server card. The type must be MASKED_SERVER_CARD or
// FULL_SERVER_CARD.
@@ -65,14 +62,8 @@ class CreditCard : public AutofillDataModel {
// The user-visible type of the card, e.g. 'Mastercard'.
static base::string16 TypeForDisplay(const std::string& type);
-// This method is not compiled on iOS because the resources are not used and
-// should not be shipped.
-// TODO(jdonnelly): Use credit card issuer images on iOS.
-// http://crbug.com/535784
-#if !defined(OS_IOS)
// The ResourceBundle ID for the appropriate credit card image.
static int IconResourceId(const std::string& type);
-#endif // #if !defined(OS_IOS)
// Returns the internal representation of credit card type corresponding to
// the given |number|. The credit card type is determined purely according to
diff --git a/chromium/components/autofill/core/browser/credit_card_unittest.cc b/chromium/components/autofill/core/browser/credit_card_unittest.cc
index 52a23ba8605..d61bbe3fa73 100644
--- a/chromium/components/autofill/core/browser/credit_card_unittest.cc
+++ b/chromium/components/autofill/core/browser/credit_card_unittest.cc
@@ -50,9 +50,7 @@ const char* const kValidNumbers[] = {
"4222-2222-2222-2",
"5019717010103742",
"6331101999990016",
-
- // A UnionPay card that doesn't pass the Luhn checksum
- "6200000000000000",
+ "6247130048162403",
};
const char* const kInvalidNumbers[] = {
"4111 1111 112", /* too short */
@@ -642,7 +640,7 @@ TEST(CreditCardTest, GetCreditCardType) {
{ "4222222222222", kVisaCard, true },
// The relevant sample numbers from
- // http://auricsystems.com/support-center/sample-credit-card-numbers/
+ // https://www.auricsystems.com/sample-credit-card-numbers/
{ "343434343434343", kAmericanExpressCard, true },
{ "371144371144376", kAmericanExpressCard, true },
{ "341134113411347", kAmericanExpressCard, true },
@@ -665,9 +663,9 @@ TEST(CreditCardTest, GetCreditCardType) {
{ "5111005111051128", kMasterCard, true },
{ "5112345112345114", kMasterCard, true },
{ "5115915115915118", kMasterCard, true },
-
- // A UnionPay card that doesn't pass the Luhn checksum
- { "6200000000000000", kUnionPay, true },
+ { "6247130048162403", kUnionPay, true },
+ { "6247130048162403", kUnionPay, true },
+ { "622384452162063648", kUnionPay, true },
// Empty string
{ std::string(), kGenericCard, false },
@@ -678,6 +676,7 @@ TEST(CreditCardTest, GetCreditCardType) {
// Fails Luhn check.
{ "4111111111111112", kVisaCard, false },
+ { "6247130048162413", kUnionPay, false },
// Invalid length.
{ "3434343434343434", kAmericanExpressCard, false },
@@ -797,16 +796,6 @@ TEST(CreditCardTest, LastFourDigits) {
ASSERT_EQ(base::ASCIIToUTF16("489"), card.LastFourDigits());
}
-TEST(CreditCardTest, CanBuildFromCardNumberAndExpirationDate) {
- base::string16 card_number = base::ASCIIToUTF16("test");
- int month = 1;
- int year = 2999;
- CreditCard card(card_number, month, year);
- EXPECT_EQ(card_number, card.number());
- EXPECT_EQ(month, card.expiration_month());
- EXPECT_EQ(year, card.expiration_year());
-}
-
// Verifies that a credit card should be updated.
TEST(CreditCardTest, ShouldUpdateExpiration) {
base::Time now = base::Time::Now();
@@ -894,8 +883,9 @@ TEST(CreditCardTest, ShouldUpdateExpiration) {
};
for (size_t i = 0; i < arraysize(kTestCases); ++i) {
- CreditCard card(base::ASCIIToUTF16("1234"), kTestCases[i].month,
- kTestCases[i].year);
+ CreditCard card;
+ card.SetExpirationMonth(kTestCases[i].month);
+ card.SetExpirationYear(kTestCases[i].year);
card.set_record_type(kTestCases[i].record_type);
if (card.record_type() != CreditCard::LOCAL_CARD)
card.SetServerStatus(kTestCases[i].server_status);
diff --git a/chromium/components/autofill/core/browser/form_field.cc b/chromium/components/autofill/core/browser/form_field.cc
index a63634cca72..3d31c0bd59f 100644
--- a/chromium/components/autofill/core/browser/form_field.cc
+++ b/chromium/components/autofill/core/browser/form_field.cc
@@ -24,6 +24,7 @@
#include "components/autofill/core/browser/name_field.h"
#include "components/autofill/core/browser/phone_field.h"
#include "components/autofill/core/common/autofill_regexes.h"
+#include "components/autofill/core/common/autofill_util.h"
namespace autofill {
namespace {
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index 61bcd71a5ce..fb0c4954a47 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -27,13 +27,14 @@
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_field.h"
#include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/form_field_data_predictions.h"
+#include "components/autofill/core/common/signatures_util.h"
#include "components/rappor/rappor_service.h"
#include "components/rappor/rappor_utils.h"
-#include "third_party/re2/src/re2/re2.h"
namespace autofill {
namespace {
@@ -42,9 +43,6 @@ const char kClientVersion[] = "6.1.1715.1442/en (GGLL)";
const char kBillingMode[] = "billing";
const char kShippingMode[] = "shipping";
-// Strip away >= 5 consecutive digits.
-const char kIgnorePatternInFieldName[] = "\\d{5,}";
-
// A form is considered to have a high prediction mismatch rate if the number of
// mismatches exceeds this threshold.
const int kNumberOfMismatchesThreshold = 3;
@@ -57,9 +55,6 @@ const int kNumberOfMismatchesThreshold = 3;
const int kCommonNamePrefixRemovalFieldThreshold = 3;
const int kMinCommonNamePrefixLength = 16;
-// Maximum number of characters in the field label to be encoded in a proto.
-const int kMaxFieldLabelNumChars = 200;
-
// Helper for |EncodeUploadRequest()| that creates a bit field corresponding to
// |available_field_types| and returns the hex representation as a string.
std::string EncodeFieldTypes(const ServerFieldTypeSet& available_field_types) {
@@ -275,14 +270,6 @@ HtmlFieldType FieldTypeFromAutocompleteAttributeValue(
return HTML_TYPE_UNRECOGNIZED;
}
-std::string StripDigitsIfRequired(const base::string16& input) {
- std::string return_string = base::UTF16ToUTF8(input);
-
- re2::RE2::GlobalReplace(&return_string, re2::RE2(kIgnorePatternInFieldName),
- std::string());
- return return_string;
-}
-
std::ostream& operator<<(
std::ostream& out,
const autofill::AutofillQueryResponseContents& response) {
@@ -293,6 +280,14 @@ std::ostream& operator<<(
return out;
}
+bool IsCreditCardExpirationType(ServerFieldType type) {
+ return type == CREDIT_CARD_EXP_MONTH ||
+ type == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
+ type == CREDIT_CARD_EXP_4_DIGIT_YEAR ||
+ type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR ||
+ type == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR;
+}
+
} // namespace
FormStructure::FormStructure(const FormData& form)
@@ -312,14 +307,8 @@ FormStructure::FormStructure(const FormData& form)
// Copy the form fields.
std::map<base::string16, size_t> unique_names;
for (const FormFieldData& field : form.fields) {
- if (!ShouldSkipField(field)) {
- // Add all supported form fields (including with empty names) to the
- // signature. This is a requirement for Autofill servers.
- form_signature_field_names_.append("&");
- form_signature_field_names_.append(StripDigitsIfRequired(field.name));
-
+ if (!ShouldSkipField(field))
++active_field_count_;
- }
if (field.form_control_type == "password")
has_password_field_ = true;
@@ -335,6 +324,7 @@ FormStructure::FormStructure(const FormData& form)
fields_.push_back(new AutofillField(field, unique_name));
}
+ form_signature_ = autofill::CalculateFormSignature(form);
// Do further processing on the fields, as needed.
ProcessExtractedFields();
}
@@ -398,12 +388,12 @@ bool FormStructure::EncodeUploadRequest(
upload->set_submission(observed_submission);
upload->set_client_version(kClientVersion);
- upload->set_form_signature(FormSignature64Bit());
+ upload->set_form_signature(form_signature());
upload->set_autofill_used(form_was_autofilled);
upload->set_data_present(EncodeFieldTypes(available_field_types));
if (IsAutofillFieldMetadataEnabled()) {
- upload->set_action_signature(Hash64Bit(target_url_.host()));
+ upload->set_action_signature(StrToHash64Bit(target_url_.host()));
if (!form_name().empty())
upload->set_form_name(base::UTF16ToUTF8(form_name()));
}
@@ -435,8 +425,8 @@ bool FormStructure::EncodeQueryRequest(
// Some badly formatted web sites repeat forms - detect that and encode only
// one form as returned data would be the same for all the repeated forms.
std::set<std::string> processed_forms;
- for (const auto& form : forms) {
- std::string signature(form->FormSignature());
+ for (const auto* form : forms) {
+ std::string signature(form->FormSignatureAsStr());
if (processed_forms.find(signature) != processed_forms.end())
continue;
processed_forms.insert(signature);
@@ -448,10 +438,7 @@ bool FormStructure::EncodeQueryRequest(
encoded_signatures->push_back(signature);
}
- if (!encoded_signatures->size())
- return false;
-
- return true;
+ return !encoded_signatures->empty();
}
// static
@@ -543,13 +530,13 @@ std::vector<FormDataPredictions> FormStructure::GetFieldTypePredictions(
form.data.origin = form_structure->source_url_;
form.data.action = form_structure->target_url_;
form.data.is_form_tag = form_structure->is_form_tag_;
- form.signature = form_structure->FormSignature();
+ form.signature = form_structure->FormSignatureAsStr();
for (const AutofillField* field : form_structure->fields_) {
form.data.fields.push_back(FormFieldData(*field));
FormFieldDataPredictions annotated_field;
- annotated_field.signature = field->FieldSignature();
+ annotated_field.signature = field->FieldSignatureAsStr();
annotated_field.heuristic_type =
AutofillType(field->heuristic_type()).ToString();
annotated_field.server_type =
@@ -572,8 +559,8 @@ bool FormStructure::IsAutofillFieldMetadataEnabled() {
return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
}
-std::string FormStructure::FormSignature() const {
- return base::Uint64ToString(FormSignature64Bit());
+std::string FormStructure::FormSignatureAsStr() const {
+ return base::Uint64ToString(form_signature());
}
bool FormStructure::IsAutofillable() const {
@@ -583,6 +570,22 @@ bool FormStructure::IsAutofillable() const {
return ShouldBeParsed();
}
+bool FormStructure::IsCompleteCreditCardForm() const {
+ bool found_cc_number = false;
+ bool found_cc_expiration = false;
+ for (const AutofillField* field : fields_) {
+ ServerFieldType type = field->Type().GetStorableType();
+ if (!found_cc_expiration && IsCreditCardExpirationType(type)) {
+ found_cc_expiration = true;
+ } else if (!found_cc_number && type == CREDIT_CARD_NUMBER) {
+ found_cc_number = true;
+ }
+ if (found_cc_expiration && found_cc_number)
+ return true;
+ }
+ return false;
+}
+
void FormStructure::UpdateAutofillCount() {
autofill_count_ = 0;
for (const AutofillField* field : *this) {
@@ -624,12 +627,12 @@ void FormStructure::UpdateFromCache(const FormStructure& cached_form) {
std::map<std::string, const AutofillField*> cached_fields;
for (size_t i = 0; i < cached_form.field_count(); ++i) {
const AutofillField* field = cached_form.field(i);
- cached_fields[field->FieldSignature()] = field;
+ cached_fields[field->FieldSignatureAsStr()] = field;
}
for (AutofillField* field : *this) {
- std::map<std::string, const AutofillField*>::const_iterator
- cached_field = cached_fields.find(field->FieldSignature());
+ std::map<std::string, const AutofillField*>::const_iterator cached_field =
+ cached_fields.find(field->FieldSignatureAsStr());
if (cached_field != cached_fields.end()) {
if (field->form_control_type != "select-one" &&
field->value == cached_field->second->value) {
@@ -660,7 +663,7 @@ void FormStructure::UpdateFromCache(const FormStructure& cached_form) {
DCHECK_EQ(cached_form.form_name_, form_name_);
DCHECK_EQ(cached_form.source_url_, source_url_);
DCHECK_EQ(cached_form.target_url_, target_url_);
- form_signature_field_names_ = cached_form.form_signature_field_names_;
+ form_signature_ = cached_form.form_signature_;
}
void FormStructure::LogQualityMetrics(const base::TimeTicks& load_time,
@@ -1110,19 +1113,14 @@ void FormStructure::EncodeFormForQuery(
AutofillQueryContents::Form* query_form) const {
DCHECK(!IsMalformed());
- query_form->set_signature(FormSignature64Bit());
+ query_form->set_signature(form_signature());
for (const AutofillField* field : fields_) {
if (ShouldSkipField(*field))
continue;
AutofillQueryContents::Form::Field* added_field = query_form->add_field();
- unsigned sig = 0;
- // The signature is a required field. If it can't be parsed, the proto would
- // not serialize.
- if (!base::StringToUint(field->FieldSignature(), &sig))
- continue;
- added_field->set_signature(sig);
+ added_field->set_signature(field->GetFieldSignature());
if (IsAutofillFieldMetadataEnabled()) {
added_field->set_type(field->form_control_type);
@@ -1130,12 +1128,6 @@ void FormStructure::EncodeFormForQuery(
if (!field->name.empty())
added_field->set_name(base::UTF16ToUTF8(field->name));
- if (!field->label.empty()) {
- std::string truncated;
- base::TruncateUTF8ToByteSize(base::UTF16ToUTF8(field->label),
- kMaxFieldLabelNumChars, &truncated);
- added_field->set_label(truncated);
- }
}
}
}
@@ -1159,12 +1151,12 @@ void FormStructure::EncodeFormForUpload(AutofillUploadContents* upload) const {
if (field->generation_type())
added_field->set_generation_type(field->generation_type());
- unsigned sig = 0;
- // The signature is a required field. If it can't be parsed, the proto
- // would not serialize.
- if (!base::StringToUint(field->FieldSignature(), &sig))
- continue;
- added_field->set_signature(sig);
+ if (field->form_classifier_outcome()) {
+ added_field->set_form_classifier_outcome(
+ field->form_classifier_outcome());
+ }
+
+ added_field->set_signature(field->GetFieldSignature());
if (IsAutofillFieldMetadataEnabled()) {
added_field->set_type(field->form_control_type);
@@ -1172,57 +1164,19 @@ void FormStructure::EncodeFormForUpload(AutofillUploadContents* upload) const {
if (!field->name.empty())
added_field->set_name(base::UTF16ToUTF8(field->name));
- if (!field->label.empty()) {
- std::string truncated;
- base::TruncateUTF8ToByteSize(base::UTF16ToUTF8(field->label),
- kMaxFieldLabelNumChars, &truncated);
- added_field->set_label(truncated);
- }
-
if (!field->autocomplete_attribute.empty())
added_field->set_autocomplete(field->autocomplete_attribute);
if (!field->css_classes.empty())
added_field->set_css_classes(base::UTF16ToUTF8(field->css_classes));
+
+ if (field->properties_mask)
+ added_field->set_properties_mask(field->properties_mask);
}
}
}
}
-uint64_t FormStructure::Hash64Bit(const std::string& str) {
- std::string hash_bin = base::SHA1HashString(str);
- DCHECK_EQ(base::kSHA1Length, hash_bin.length());
-
- uint64_t hash64 = (((static_cast<uint64_t>(hash_bin[0])) & 0xFF) << 56) |
- (((static_cast<uint64_t>(hash_bin[1])) & 0xFF) << 48) |
- (((static_cast<uint64_t>(hash_bin[2])) & 0xFF) << 40) |
- (((static_cast<uint64_t>(hash_bin[3])) & 0xFF) << 32) |
- (((static_cast<uint64_t>(hash_bin[4])) & 0xFF) << 24) |
- (((static_cast<uint64_t>(hash_bin[5])) & 0xFF) << 16) |
- (((static_cast<uint64_t>(hash_bin[6])) & 0xFF) << 8) |
- ((static_cast<uint64_t>(hash_bin[7])) & 0xFF);
-
- return hash64;
-}
-
-uint64_t FormStructure::FormSignature64Bit() const {
- std::string scheme(target_url_.scheme());
- std::string host(target_url_.host());
-
- // If target host or scheme is empty, set scheme and host of source url.
- // This is done to match the Toolbar's behavior.
- if (scheme.empty() || host.empty()) {
- scheme = source_url_.scheme();
- host = source_url_.host();
- }
-
- std::string form_string = scheme + "://" + host + "&" +
- base::UTF16ToUTF8(form_name_) +
- form_signature_field_names_;
-
- return Hash64Bit(form_string);
-}
-
bool FormStructure::IsMalformed() const {
if (!field_count()) // Nothing to add.
return true;
diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h
index aab2a664be8..e359a8f1f93 100644
--- a/chromium/components/autofill/core/browser/form_structure.h
+++ b/chromium/components/autofill/core/browser/form_structure.h
@@ -91,14 +91,18 @@ class FormStructure {
// Returns whether sending autofill field metadata to the server is enabled.
static bool IsAutofillFieldMetadataEnabled();
- // The unique signature for this form, composed of the target url domain,
- // the form name, and the form field names in a 64-bit hash.
- std::string FormSignature() const;
+ // Return the form signature as string.
+ std::string FormSignatureAsStr() const;
// Runs a quick heuristic to rule out forms that are obviously not
// auto-fillable, like google/yahoo/msn search, etc.
bool IsAutofillable() const;
+ // Returns whether |this| form represents a complete Credit Card form, which
+ // consists in having at least a credit card number field and an expiration
+ // field.
+ bool IsCompleteCreditCardForm() const;
+
// Resets |autofill_count_| and counts the number of auto-fillable fields.
// This is used when we receive server data for form fields. At that time,
// we may have more known fields than just the number of fields we matched
@@ -216,6 +220,8 @@ class FormStructure {
bool all_fields_are_passwords() const { return all_fields_are_passwords_; }
+ FormSignature form_signature() const { return form_signature_; }
+
// Returns a FormData containing the data this form structure knows about.
FormData ToFormData() const;
@@ -235,11 +241,6 @@ class FormStructure {
// Encodes information about this form and its fields into |upload|.
void EncodeFormForUpload(autofill::AutofillUploadContents* upload) const;
- // 64-bit hash of the string - used in FormSignature and unit-tests.
- static uint64_t Hash64Bit(const std::string& str);
-
- uint64_t FormSignature64Bit() const;
-
// Returns true if the form has no fields, or too many.
bool IsMalformed() const;
@@ -285,11 +286,6 @@ class FormStructure {
// included in queries to the Autofill server.
size_t active_field_count_;
- // The names of the form input elements, that are part of the form signature.
- // The string starts with "&" and the names are also separated by the "&"
- // character. E.g.: "&form_input1_name&form_input2_name&...&form_inputN_name"
- std::string form_signature_field_names_;
-
// Whether the server expects us to always upload, never upload, or default
// to the stored upload rates.
UploadRequired upload_required_;
@@ -319,6 +315,10 @@ class FormStructure {
// True if all form fields are password fields.
bool all_fields_are_passwords_;
+ // The unique signature for this form, composed of the target url domain,
+ // the form name, and the form field names in a 64-bit hash.
+ FormSignature form_signature_;
+
DISALLOW_COPY_AND_ASSIGN(FormStructure);
};
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index 4038d567ceb..fba95adf86c 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -9,6 +9,7 @@
#include <memory>
#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -17,6 +18,7 @@
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/signatures_util.h"
#include "components/variations/entropy_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -50,7 +52,7 @@ std::ostream& operator<<(std::ostream& os, const FormData& form) {
class FormStructureTest : public testing::Test {
public:
static std::string Hash64Bit(const std::string& str) {
- return base::Uint64ToString(FormStructure::Hash64Bit(str));
+ return base::Uint64ToString(StrToHash64Bit(str));
}
void SetUp() override {
@@ -67,7 +69,8 @@ class FormStructureTest : public testing::Test {
void EnableAutofillMetadataFieldTrial() {
field_trial_list_.reset();
field_trial_list_.reset(
- new base::FieldTrialList(new metrics::SHA1EntropyProvider("foo")));
+ new base::FieldTrialList(
+ base::MakeUnique<metrics::SHA1EntropyProvider>("foo")));
field_trial_ = base::FieldTrialList::CreateFieldTrial(
"AutofillFieldMetadata", "Enabled");
field_trial_->group();
@@ -605,6 +608,129 @@ TEST_F(FormStructureTest, StripCommonNamePrefix_SmallPrefix) {
EXPECT_EQ(ADDRESS_HOME_LINE3, form_structure->field(2)->heuristic_type());
}
+TEST_F(FormStructureTest, IsCompleteCreditCardForm_Minimal) {
+ std::unique_ptr<FormStructure> form_structure;
+ FormData form;
+
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("Card Number");
+ field.name = ASCIIToUTF16("card_number");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Expiration");
+ field.name = ASCIIToUTF16("cc_exp");
+ form.fields.push_back(field);
+
+ // Another field to reach the minimum 3.
+ field.label = ASCIIToUTF16("Zip");
+ field.name = ASCIIToUTF16("zip");
+ form.fields.push_back(field);
+
+ form_structure.reset(new FormStructure(form));
+ form_structure->DetermineHeuristicTypes();
+
+ EXPECT_TRUE(form_structure->IsCompleteCreditCardForm());
+}
+
+TEST_F(FormStructureTest, IsCompleteCreditCardForm_Full) {
+ std::unique_ptr<FormStructure> form_structure;
+ FormData form;
+
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("Name on Card");
+ field.name = ASCIIToUTF16("name_on_card");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Card Number");
+ field.name = ASCIIToUTF16("card_number");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Exp Month");
+ field.name = ASCIIToUTF16("ccmonth");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Exp Year");
+ field.name = ASCIIToUTF16("ccyear");
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Verification");
+ field.name = ASCIIToUTF16("verification");
+ form.fields.push_back(field);
+
+ field.label = base::string16();
+ field.name = ASCIIToUTF16("Submit");
+ field.form_control_type = "submit";
+ form.fields.push_back(field);
+
+ form_structure.reset(new FormStructure(form));
+ form_structure->DetermineHeuristicTypes();
+
+ EXPECT_TRUE(form_structure->IsCompleteCreditCardForm());
+}
+
+// A form with only the credit card number is not considered sufficient.
+TEST_F(FormStructureTest, IsCompleteCreditCardForm_OnlyCCNumber) {
+ std::unique_ptr<FormStructure> form_structure;
+ FormData form;
+
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("Card Number");
+ field.name = ASCIIToUTF16("card_number");
+ form.fields.push_back(field);
+
+ form_structure.reset(new FormStructure(form));
+ form_structure->DetermineHeuristicTypes();
+
+ EXPECT_FALSE(form_structure->IsCompleteCreditCardForm());
+}
+
+// A form with only the credit card number is not considered sufficient.
+TEST_F(FormStructureTest, IsCompleteCreditCardForm_AddressForm) {
+ std::unique_ptr<FormStructure> form_structure;
+ FormData form;
+
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("First Name");
+ field.name = base::string16();
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Last Name");
+ field.name = base::string16();
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Email");
+ field.name = base::string16();
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Phone");
+ field.name = base::string16();
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Address");
+ field.name = base::string16();
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Address");
+ field.name = base::string16();
+ form.fields.push_back(field);
+
+ field.label = ASCIIToUTF16("Zip code");
+ field.name = base::string16();
+ form.fields.push_back(field);
+ form_structure.reset(new FormStructure(form));
+ form_structure->DetermineHeuristicTypes();
+
+ EXPECT_FALSE(form_structure->IsCompleteCreditCardForm());
+}
+
// Verify that we can correctly process the 'autocomplete' attribute for phone
// number types (especially phone prefixes and suffixes).
TEST_F(FormStructureTest, HeuristicsAutocompleteAttributePhoneTypes) {
@@ -1875,15 +2001,15 @@ TEST_F(FormStructureTest, EncodeQueryRequest) {
query_form->set_signature(11337937696949187602U);
test::FillQueryField(query_form->add_field(), 412125936U, "name_on_card",
- "text", "Name on Card");
+ "text");
test::FillQueryField(query_form->add_field(), 1917667676U, "billing_address",
- "text", "Address");
+ "text");
test::FillQueryField(query_form->add_field(), 2226358947U, "card_number",
- "text", "Card Number");
+ "text");
test::FillQueryField(query_form->add_field(), 747221617U, "expiration_month",
- "text", "Expiration Date");
+ "text");
test::FillQueryField(query_form->add_field(), 4108155786U, "expiration_year",
- "text", "Expiration Year");
+ "text");
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -1927,18 +2053,18 @@ TEST_F(FormStructureTest, EncodeQueryRequest) {
query_form->set_signature(8308881815906226214U);
test::FillQueryField(query_form->add_field(), 412125936U, "name_on_card",
- "text", "Name on Card");
+ "text");
test::FillQueryField(query_form->add_field(), 1917667676U, "billing_address",
- "text", "Address");
+ "text");
test::FillQueryField(query_form->add_field(), 2226358947U, "card_number",
- "text", "Card Number");
+ "text");
test::FillQueryField(query_form->add_field(), 747221617U, "expiration_month",
- "text", "Expiration Date");
+ "text");
test::FillQueryField(query_form->add_field(), 4108155786U, "expiration_year",
- "text", "Expiration Year");
+ "text");
for (int i = 0; i < 5; ++i) {
- test::FillQueryField(query_form->add_field(), 509334676U, "address", "text",
- "Address");
+ test::FillQueryField(query_form->add_field(), 509334676U, "address",
+ "text");
}
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -2061,15 +2187,15 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text",
- "First Name", nullptr, 3U, nullptr);
+ nullptr, 3U, nullptr);
test::FillUploadField(upload.add_field(), 3494530716U, "lastname", "text",
- "Last Name", nullptr, 5U, nullptr);
+ nullptr, 5U, nullptr);
test::FillUploadField(upload.add_field(), 1029417091U, "email", "email",
- "Email", nullptr, 9U, nullptr);
+ nullptr, 9U, nullptr);
test::FillUploadField(upload.add_field(), 466116101U, "phone", "number",
- "Phone", nullptr, 14U, nullptr);
+ nullptr, 14U, nullptr);
test::FillUploadField(upload.add_field(), 2799270304U, "country",
- "select-one", "Country", nullptr, 36U, nullptr);
+ "select-one", nullptr, 36U, nullptr);
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -2117,7 +2243,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
// Create an additonal 8 fields (total of 13).
for (int i = 0; i < 8; ++i) {
test::FillUploadField(upload.add_field(), 509334676U, "address", "text",
- "Address", nullptr, 30U, nullptr);
+ nullptr, 30U, nullptr);
}
// Put the appropriate autofill type on the different address fields.
upload.mutable_field(6)->set_autofill_type(31U);
@@ -2207,10 +2333,23 @@ TEST_F(FormStructureTest,
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
for (size_t i = 0; i < form_structure->field_count(); ++i) {
form_structure->field(i)->set_possible_types(possible_field_types[i]);
- if (form_structure->field(i)->name == ASCIIToUTF16("password"))
+ if (form_structure->field(i)->name == ASCIIToUTF16("password")) {
form_structure->field(i)->set_generation_type(
- autofill::AutofillUploadContents::Field::
+ AutofillUploadContents::Field::
MANUALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM);
+ form_structure->field(i)->set_form_classifier_outcome(
+ AutofillUploadContents::Field::GENERATION_ELEMENT);
+ } else {
+ form_structure->field(i)->set_form_classifier_outcome(
+ AutofillUploadContents::Field::NON_GENERATION_ELEMENT);
+ }
+ if (form_structure->field(i)->name == ASCIIToUTF16("firstname")) {
+ form_structure->field(i)->properties_mask =
+ FieldPropertiesFlags::HAD_FOCUS;
+ } else {
+ form_structure->field(i)->properties_mask =
+ FieldPropertiesFlags::HAD_FOCUS | FieldPropertiesFlags::USER_TYPED;
+ }
}
ServerFieldTypeSet available_field_types;
@@ -2230,20 +2369,47 @@ TEST_F(FormStructureTest,
upload.set_action_signature(15724779818122431245U);
upload.set_login_form_signature(42);
- test::FillUploadField(upload.add_field(), 4224610201U, "firstname", "",
- "First Name", "given-name", 3U, nullptr);
- test::FillUploadField(upload.add_field(), 2786066110U, "lastname", "",
- "Last Name", "family-name", 5U, nullptr);
- test::FillUploadField(upload.add_field(), 1029417091U, "email", "email",
- "Email", "email", 9U, nullptr);
- test::FillUploadField(upload.add_field(), 239111655U, "username", "text",
- "username", "email", 86U, nullptr);
- auto* upload_password_field = upload.add_field();
+ AutofillUploadContents::Field* upload_firstname_field = upload.add_field();
+ test::FillUploadField(upload_firstname_field, 4224610201U, "firstname", "",
+ "given-name", 3U, nullptr);
+ upload_firstname_field->set_form_classifier_outcome(
+ AutofillUploadContents::Field::NON_GENERATION_ELEMENT);
+ upload_firstname_field->set_properties_mask(FieldPropertiesFlags::HAD_FOCUS);
+
+ AutofillUploadContents::Field* upload_lastname_field = upload.add_field();
+ test::FillUploadField(upload_lastname_field, 2786066110U, "lastname", "",
+ "family-name", 5U, nullptr);
+ upload_lastname_field->set_form_classifier_outcome(
+ AutofillUploadContents::Field::NON_GENERATION_ELEMENT);
+ upload_lastname_field->set_properties_mask(FieldPropertiesFlags::HAD_FOCUS |
+ FieldPropertiesFlags::USER_TYPED);
+
+ AutofillUploadContents::Field* upload_email_field = upload.add_field();
+ test::FillUploadField(upload_email_field, 1029417091U, "email", "email",
+ "email", 9U, nullptr);
+ upload_email_field->set_form_classifier_outcome(
+ AutofillUploadContents::Field::NON_GENERATION_ELEMENT);
+ upload_email_field->set_properties_mask(FieldPropertiesFlags::HAD_FOCUS |
+ FieldPropertiesFlags::USER_TYPED);
+
+ AutofillUploadContents::Field* upload_username_field = upload.add_field();
+ test::FillUploadField(upload_username_field, 239111655U, "username", "text",
+ "email", 86U, nullptr);
+ upload_username_field->set_form_classifier_outcome(
+ AutofillUploadContents::Field::NON_GENERATION_ELEMENT);
+ upload_username_field->set_properties_mask(FieldPropertiesFlags::HAD_FOCUS |
+ FieldPropertiesFlags::USER_TYPED);
+
+ AutofillUploadContents::Field* upload_password_field = upload.add_field();
test::FillUploadField(upload_password_field, 2051817934U, "password",
- "password", "password", "email", 76U, nullptr);
+ "password", "email", 76U, nullptr);
+ upload_password_field->set_form_classifier_outcome(
+ AutofillUploadContents::Field::GENERATION_ELEMENT);
upload_password_field->set_generation_type(
- autofill::AutofillUploadContents::Field::
+ AutofillUploadContents::Field::
MANUALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM);
+ upload_password_field->set_properties_mask(FieldPropertiesFlags::HAD_FOCUS |
+ FieldPropertiesFlags::USER_TYPED);
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -2310,11 +2476,11 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithAutocomplete) {
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text",
- "First Name", "given-name", 3U, nullptr);
+ "given-name", 3U, nullptr);
test::FillUploadField(upload.add_field(), 3494530716U, "lastname", "text",
- "Last Name", "family-name", 5U, nullptr);
+ "family-name", 5U, nullptr);
test::FillUploadField(upload.add_field(), 1029417091U, "email", "email",
- "Email", "email", 9U, nullptr);
+ "email", 9U, nullptr);
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -2378,11 +2544,11 @@ TEST_F(FormStructureTest, EncodeUploadRequest_ObservedSubmissionFalse) {
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text",
- "First Name", nullptr, 3U, nullptr);
+ nullptr, 3U, nullptr);
test::FillUploadField(upload.add_field(), 3494530716U, "lastname", "text",
- "Last Name", nullptr, 5U, nullptr);
+ nullptr, 5U, nullptr);
test::FillUploadField(upload.add_field(), 1029417091U, "email", "email",
- "Email", nullptr, 9U, nullptr);
+ nullptr, 9U, nullptr);
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -2443,11 +2609,11 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithLabels) {
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
- nullptr, nullptr, 3U, nullptr);
+ nullptr, 3U, nullptr);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
- "Last Name", nullptr, 5U, nullptr);
+ nullptr, 5U, nullptr);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
- "Email", nullptr, 9U, nullptr);
+ nullptr, 9U, nullptr);
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -2503,11 +2669,11 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithCssClasses) {
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
- nullptr, nullptr, 3U, nullptr);
+ nullptr, 3U, nullptr);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
- nullptr, nullptr, 5U, "last_name_field");
+ nullptr, 5U, "last_name_field");
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
- nullptr, nullptr, 9U, "email_field required_field");
+ nullptr, 9U, "email_field required_field");
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -2568,11 +2734,11 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithFormName) {
upload.set_form_name("myform");
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
- nullptr, nullptr, 3U, nullptr);
+ nullptr, 3U, nullptr);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
- nullptr, nullptr, 5U, nullptr);
+ nullptr, 5U, nullptr);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
- nullptr, nullptr, 9U, nullptr);
+ nullptr, 9U, nullptr);
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -2638,11 +2804,11 @@ TEST_F(FormStructureTest, EncodeUploadRequestPartialMetadata) {
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
- nullptr, nullptr, 3U, nullptr);
+ nullptr, 3U, nullptr);
test::FillUploadField(upload.add_field(), 3494530716U, "lastname", "text",
- "Last Name", "family-name", 5U, nullptr);
+ "family-name", 5U, nullptr);
test::FillUploadField(upload.add_field(), 1545468175U, "lastname", "email",
- "Email", "email", 9U, nullptr);
+ "email", 9U, nullptr);
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -2714,11 +2880,11 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) {
upload.set_data_present("1440");
test::FillUploadField(upload.add_field(), 3763331450U, nullptr, nullptr,
- nullptr, nullptr, 3U, nullptr);
+ nullptr, 3U, nullptr);
test::FillUploadField(upload.add_field(), 3494530716U, nullptr, nullptr,
- nullptr, nullptr, 5U, nullptr);
+ nullptr, 5U, nullptr);
test::FillUploadField(upload.add_field(), 1029417091U, nullptr, nullptr,
- nullptr, nullptr, 9U, nullptr);
+ nullptr, 9U, nullptr);
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -2774,11 +2940,11 @@ TEST_F(FormStructureTest, CheckDataPresence) {
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 1089846351U, "first", "text",
- "First Name", nullptr, 1U, nullptr);
+ nullptr, 1U, nullptr);
test::FillUploadField(upload.add_field(), 2404144663U, "last", "text",
- "Last Name", nullptr, 1U, nullptr);
+ nullptr, 1U, nullptr);
test::FillUploadField(upload.add_field(), 420638584U, "email", "text",
- "Email", nullptr, 1U, nullptr);
+ nullptr, 1U, nullptr);
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -3042,13 +3208,13 @@ TEST_F(FormStructureTest, CheckMultipleTypes) {
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 420638584U, "email", "text",
- "email", nullptr, 9U, nullptr);
+ nullptr, 9U, nullptr);
test::FillUploadField(upload.add_field(), 1089846351U, "first", "text",
- "First Name", nullptr, 3U, nullptr);
+ nullptr, 3U, nullptr);
test::FillUploadField(upload.add_field(), 2404144663U, "last", "text",
- "Last Name", nullptr, 5U, nullptr);
+ nullptr, 5U, nullptr);
test::FillUploadField(upload.add_field(), 509334676U, "address", "text",
- "Address", nullptr, 30U, nullptr);
+ nullptr, 30U, nullptr);
std::string expected_upload_string;
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -3070,10 +3236,10 @@ TEST_F(FormStructureTest, CheckMultipleTypes) {
upload.mutable_field(2)->set_autofill_type(3);
// Replace the fourth field by the old third field.
test::FillUploadField(upload.mutable_field(3), 2404144663U, "last", "text",
- "Last Name", nullptr, 5U, nullptr);
+ nullptr, 5U, nullptr);
// Re-add the old fourth field.
test::FillUploadField(upload.add_field(), 509334676U, "address", "text",
- "Address", nullptr, 30U, nullptr);
+ nullptr, 30U, nullptr);
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
@@ -3091,7 +3257,7 @@ TEST_F(FormStructureTest, CheckMultipleTypes) {
// Adjust the expected upload proto.
test::FillUploadField(upload.add_field(), 509334676U, "address", "text",
- "Address", nullptr, 31U, nullptr);
+ nullptr, 31U, nullptr);
ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
AutofillUploadContents encoded_upload3;
@@ -3145,27 +3311,26 @@ TEST_F(FormStructureTest, CheckFormSignature) {
form_structure.reset(new FormStructure(form));
- EXPECT_EQ(FormStructureTest::Hash64Bit(
- std::string("://&&email&first")),
- form_structure->FormSignature());
+ EXPECT_EQ(FormStructureTest::Hash64Bit(std::string("://&&email&first")),
+ form_structure->FormSignatureAsStr());
form.origin = GURL(std::string("http://www.facebook.com"));
form_structure.reset(new FormStructure(form));
EXPECT_EQ(FormStructureTest::Hash64Bit(
- std::string("http://www.facebook.com&&email&first")),
- form_structure->FormSignature());
+ std::string("http://www.facebook.com&&email&first")),
+ form_structure->FormSignatureAsStr());
form.action = GURL(std::string("https://login.facebook.com/path"));
form_structure.reset(new FormStructure(form));
EXPECT_EQ(FormStructureTest::Hash64Bit(
- std::string("https://login.facebook.com&&email&first")),
- form_structure->FormSignature());
+ std::string("https://login.facebook.com&&email&first")),
+ form_structure->FormSignatureAsStr());
form.name = ASCIIToUTF16("login_form");
form_structure.reset(new FormStructure(form));
- EXPECT_EQ(FormStructureTest::Hash64Bit(
- std::string("https://login.facebook.com&login_form&email&first")),
- form_structure->FormSignature());
+ EXPECT_EQ(FormStructureTest::Hash64Bit(std::string(
+ "https://login.facebook.com&login_form&email&first")),
+ form_structure->FormSignatureAsStr());
field.check_status = FormFieldData::NOT_CHECKABLE;
field.label = ASCIIToUTF16("Random Field label");
@@ -3183,9 +3348,9 @@ TEST_F(FormStructureTest, CheckFormSignature) {
form.fields.push_back(field);
form_structure.reset(new FormStructure(form));
EXPECT_EQ(FormStructureTest::Hash64Bit(
- std::string("https://login.facebook.com&login_form&email&first&"
- "random1234&random&1random&random")),
- form_structure->FormSignature());
+ std::string("https://login.facebook.com&login_form&email&first&"
+ "random1234&random&1random&random")),
+ form_structure->FormSignatureAsStr());
}
TEST_F(FormStructureTest, ToFormData) {
@@ -3248,10 +3413,8 @@ TEST_F(FormStructureTest, SkipFieldTest) {
AutofillQueryContents::Form* query_form = query.add_form();
query_form->set_signature(18006745212084723782U);
- test::FillQueryField(query_form->add_field(), 239111655U, "username", "text",
- "username");
- test::FillQueryField(query_form->add_field(), 420638584U, "email", "text",
- nullptr);
+ test::FillQueryField(query_form->add_field(), 239111655U, "username", "text");
+ test::FillQueryField(query_form->add_field(), 420638584U, "email", "text");
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -3301,12 +3464,10 @@ TEST_F(FormStructureTest, EncodeQueryRequest_WithLabels) {
AutofillQueryContents::Form* query_form = query.add_form();
query_form->set_signature(13906559713264665730U);
- test::FillQueryField(query_form->add_field(), 239111655U, "username", "text",
- nullptr);
- test::FillQueryField(query_form->add_field(), 420638584U, "email", "text",
- "Enter your Email address");
+ test::FillQueryField(query_form->add_field(), 239111655U, "username", "text");
+ test::FillQueryField(query_form->add_field(), 420638584U, "email", "text");
test::FillQueryField(query_form->add_field(), 2051817934U, "password",
- "password", "Enter your Password");
+ "password");
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -3357,16 +3518,10 @@ TEST_F(FormStructureTest, EncodeQueryRequest_WithLongLabels) {
AutofillQueryContents::Form* query_form = query.add_form();
query_form->set_signature(13906559713264665730U);
- test::FillQueryField(query_form->add_field(), 239111655U, "username", "text",
- nullptr);
- test::FillQueryField(
- query_form->add_field(), 420638584U, "email", "text",
- "Enter Your Really Really Really (Really!) Long Email Address"
- " Which We Hope To Get In Order To Send You Unwanted Publicity Because"
- " That's What Marketers Do! We Know That Your Email Address Has The"
- " Poss");
+ test::FillQueryField(query_form->add_field(), 239111655U, "username", "text");
+ test::FillQueryField(query_form->add_field(), 420638584U, "email", "text");
test::FillQueryField(query_form->add_field(), 2051817934U, "password",
- "password", "Enter your Password");
+ "password");
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -3410,10 +3565,8 @@ TEST_F(FormStructureTest, EncodeQueryRequest_MissingNames) {
AutofillQueryContents::Form* query_form = query.add_form();
query_form->set_signature(16416961345885087496U);
- test::FillQueryField(query_form->add_field(), 239111655U, "username", "text",
- "username");
- test::FillQueryField(query_form->add_field(), 1318412689U, nullptr, "text",
- nullptr);
+ test::FillQueryField(query_form->add_field(), 239111655U, "username", "text");
+ test::FillQueryField(query_form->add_field(), 1318412689U, nullptr, "text");
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
@@ -3462,10 +3615,8 @@ TEST_F(FormStructureTest, EncodeQueryRequest_DisabledMetadataTrial) {
AutofillQueryContents::Form* query_form = query.add_form();
query_form->set_signature(7635954436925888745U);
- test::FillQueryField(query_form->add_field(), 239111655U, nullptr, nullptr,
- nullptr);
- test::FillQueryField(query_form->add_field(), 3654076265U, nullptr, nullptr,
- nullptr);
+ test::FillQueryField(query_form->add_field(), 239111655U, nullptr, nullptr);
+ test::FillQueryField(query_form->add_field(), 3654076265U, nullptr, nullptr);
std::string expected_query_string;
ASSERT_TRUE(query.SerializeToString(&expected_query_string));
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.cc b/chromium/components/autofill/core/browser/payments/full_card_request.cc
index d16715ee713..f2f63805e58 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.cc
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.cc
@@ -41,7 +41,7 @@ void FullCardRequest::GetFullCard(const CreditCard& card,
// already set, then immediately reject the new request through the method
// parameter |delegate|.
if (delegate_) {
- delegate->OnFullCardError();
+ delegate->OnFullCardRequestFailed();
return;
}
@@ -83,7 +83,7 @@ void FullCardRequest::OnUnmaskResponse(const UnmaskResponse& response) {
if (!should_unmask_card_) {
if (delegate_)
- delegate_->OnFullCardDetails(request_->card, response.cvc);
+ delegate_->OnFullCardRequestSucceeded(request_->card, response.cvc);
Reset();
autofill_client_->OnUnmaskVerificationResult(AutofillClient::SUCCESS);
return;
@@ -98,7 +98,7 @@ void FullCardRequest::OnUnmaskResponse(const UnmaskResponse& response) {
void FullCardRequest::OnUnmaskPromptClosed() {
if (delegate_)
- delegate_->OnFullCardError();
+ delegate_->OnFullCardRequestFailed();
Reset();
}
@@ -126,7 +126,7 @@ void FullCardRequest::OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
// Intentional fall through.
case AutofillClient::NETWORK_ERROR: {
if (delegate_)
- delegate_->OnFullCardError();
+ delegate_->OnFullCardRequestFailed();
Reset();
break;
}
@@ -141,8 +141,8 @@ void FullCardRequest::OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
personal_data_manager_->UpdateServerCreditCard(request_->card);
if (delegate_)
- delegate_->OnFullCardDetails(request_->card,
- request_->user_response.cvc);
+ delegate_->OnFullCardRequestSucceeded(request_->card,
+ request_->user_response.cvc);
Reset();
break;
}
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.h b/chromium/components/autofill/core/browser/payments/full_card_request.h
index 7f0d2f34209..6fd06ae5250 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.h
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.h
@@ -29,9 +29,9 @@ class FullCardRequest : public CardUnmaskDelegate {
// The interface for receiving the full card details.
class Delegate {
public:
- virtual void OnFullCardDetails(const CreditCard& card,
- const base::string16& cvc) = 0;
- virtual void OnFullCardError() = 0;
+ virtual void OnFullCardRequestSucceeded(const CreditCard& card,
+ const base::string16& cvc) = 0;
+ virtual void OnFullCardRequestFailed() = 0;
};
// The parameters should outlive the FullCardRequest.
@@ -41,8 +41,9 @@ class FullCardRequest : public CardUnmaskDelegate {
~FullCardRequest();
// Retrieves the pan and cvc for |card| and invokes
- // Delegate::OnFullCardDetails() or Delegate::OnFullCardError(). Only one
- // request should be active at a time.
+ // Delegate::OnFullCardRequestSucceeded() or
+ // Delegate::OnFullCardRequestFailed(). Only one request should be active at a
+ // time.
//
// If the card is local, has a non-empty GUID, and the user has updated its
// expiration date, then this function will write the new information to
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
index 8f93cd765f8..6fa6a66d947 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
@@ -8,7 +8,9 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/personal_data_manager.h"
@@ -27,9 +29,9 @@ using testing::_;
class MockDelegate : public FullCardRequest::Delegate,
public base::SupportsWeakPtr<MockDelegate> {
public:
- MOCK_METHOD2(OnFullCardDetails,
+ MOCK_METHOD2(OnFullCardRequestSucceeded,
void(const CreditCard&, const base::string16&));
- MOCK_METHOD0(OnFullCardError, void());
+ MOCK_METHOD0(OnFullCardRequestFailed, void());
};
// The personal data manager.
@@ -131,10 +133,10 @@ MATCHER_P4(CardMatches, record_type, number, month, year, "") {
// Verify getting the full PAN and the CVC for a masked server card.
TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForMaskedServerCard) {
- EXPECT_CALL(
- *delegate(),
- OnFullCardDetails(CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(),
+ OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS));
@@ -150,14 +152,15 @@ TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForMaskedServerCard) {
// Verify getting the CVC for a local card.
TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForLocalCard) {
- EXPECT_CALL(*delegate(),
- OnFullCardDetails(CardMatches(CreditCard::LOCAL_CARD, "4111"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(), OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::LOCAL_CARD, "4111"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS));
- request()->GetFullCard(CreditCard(base::ASCIIToUTF16("4111"), 12, 2050),
- AutofillClient::UNMASK_FOR_AUTOFILL,
+ CreditCard card;
+ test::SetCreditCardInfo(&card, nullptr, "4111", "12", "2050");
+ request()->GetFullCard(card, AutofillClient::UNMASK_FOR_AUTOFILL,
delegate()->AsWeakPtr());
CardUnmaskDelegate::UnmaskResponse response;
response.cvc = base::ASCIIToUTF16("123");
@@ -167,15 +170,15 @@ TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForLocalCard) {
// Verify getting the CVC for an unmasked server card.
TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForFullServerCard) {
- EXPECT_CALL(
- *delegate(),
- OnFullCardDetails(CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(),
+ OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS));
- CreditCard full_server_card(base::ASCIIToUTF16("4111"), 12, 2050);
- full_server_card.set_record_type(CreditCard::FULL_SERVER_CARD);
+ CreditCard full_server_card(CreditCard::FULL_SERVER_CARD, "server_id");
+ test::SetCreditCardInfo(&full_server_card, nullptr, "4111", "12", "2050");
request()->GetFullCard(full_server_card, AutofillClient::UNMASK_FOR_AUTOFILL,
delegate()->AsWeakPtr());
CardUnmaskDelegate::UnmaskResponse response;
@@ -188,16 +191,16 @@ TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForFullServerCard) {
// status.
TEST_F(FullCardRequestTest,
GetFullCardPanAndCvcForFullServerCardInExpiredStatus) {
- EXPECT_CALL(*delegate(),
- OnFullCardDetails(CardMatches(CreditCard::FULL_SERVER_CARD,
- "4111", "12", "2051"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(), OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::FULL_SERVER_CARD, "4111",
+ "12", "2051"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*personal_data(), UpdateServerCreditCard(_)).Times(0);
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS));
- CreditCard full_server_card(base::ASCIIToUTF16("4111"), 12, 2050);
- full_server_card.set_record_type(CreditCard::FULL_SERVER_CARD);
+ CreditCard full_server_card(CreditCard::FULL_SERVER_CARD, "server_id");
+ test::SetCreditCardInfo(&full_server_card, nullptr, "4111", "12", "2050");
full_server_card.SetServerStatus(CreditCard::EXPIRED);
request()->GetFullCard(full_server_card, AutofillClient::UNMASK_FOR_AUTOFILL,
delegate()->AsWeakPtr());
@@ -213,18 +216,19 @@ TEST_F(FullCardRequestTest,
// Verify getting the CVC for an unmasked server card with OK status, but
// expiration date in the past.
TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForExpiredFullServerCard) {
- EXPECT_CALL(*delegate(),
- OnFullCardDetails(CardMatches(CreditCard::FULL_SERVER_CARD,
- "4111", "12", "2051"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(), OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::FULL_SERVER_CARD, "4111",
+ "12", "2051"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*personal_data(), UpdateServerCreditCard(_)).Times(0);
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS));
base::Time::Exploded today;
base::Time::Now().LocalExplode(&today);
- CreditCard full_server_card(base::ASCIIToUTF16("4111"), 12, today.year - 1);
- full_server_card.set_record_type(CreditCard::FULL_SERVER_CARD);
+ CreditCard full_server_card(CreditCard::FULL_SERVER_CARD, "server_id");
+ test::SetCreditCardInfo(&full_server_card, nullptr, "4111", "12",
+ base::StringPrintf("%d", today.year - 1).c_str());
full_server_card.SetServerStatus(CreditCard::OK);
request()->GetFullCard(full_server_card, AutofillClient::UNMASK_FOR_AUTOFILL,
delegate()->AsWeakPtr());
@@ -239,7 +243,7 @@ TEST_F(FullCardRequestTest, GetFullCardPanAndCvcForExpiredFullServerCard) {
// Only one request at a time should be allowed.
TEST_F(FullCardRequestTest, OneRequestAtATime) {
- EXPECT_CALL(*delegate(), OnFullCardError());
+ EXPECT_CALL(*delegate(), OnFullCardRequestFailed());
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(), OnUnmaskVerificationResult(_)).Times(0);
@@ -253,34 +257,34 @@ TEST_F(FullCardRequestTest, OneRequestAtATime) {
// After the first request completes, it's OK to start the second request.
TEST_F(FullCardRequestTest, SecondRequestOkAfterFirstFinished) {
- EXPECT_CALL(*delegate(), OnFullCardError()).Times(0);
- EXPECT_CALL(*delegate(),
- OnFullCardDetails(CardMatches(CreditCard::LOCAL_CARD, "4111"),
- base::ASCIIToUTF16("123")))
+ EXPECT_CALL(*delegate(), OnFullCardRequestFailed()).Times(0);
+ EXPECT_CALL(*delegate(), OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::LOCAL_CARD, "4111"),
+ base::ASCIIToUTF16("123")))
.Times(2);
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _)).Times(2);
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS))
.Times(2);
- request()->GetFullCard(CreditCard(base::ASCIIToUTF16("4111"), 12, 2050),
- AutofillClient::UNMASK_FOR_AUTOFILL,
+ CreditCard card;
+ test::SetCreditCardInfo(&card, nullptr, "4111", "12", "2050");
+ request()->GetFullCard(card, AutofillClient::UNMASK_FOR_AUTOFILL,
delegate()->AsWeakPtr());
CardUnmaskDelegate::UnmaskResponse response;
response.cvc = base::ASCIIToUTF16("123");
ui_delegate()->OnUnmaskResponse(response);
ui_delegate()->OnUnmaskPromptClosed();
- request()->GetFullCard(CreditCard(base::ASCIIToUTF16("4111"), 12, 2050),
- AutofillClient::UNMASK_FOR_AUTOFILL,
+ request()->GetFullCard(card, AutofillClient::UNMASK_FOR_AUTOFILL,
delegate()->AsWeakPtr());
ui_delegate()->OnUnmaskResponse(response);
ui_delegate()->OnUnmaskPromptClosed();
}
// If the user cancels the CVC prompt,
-// FullCardRequest::Delegate::OnFullCardError() should be invoked.
+// FullCardRequest::Delegate::OnFullCardRequestFailed() should be invoked.
TEST_F(FullCardRequestTest, ClosePromptWithoutUserInput) {
- EXPECT_CALL(*delegate(), OnFullCardError());
+ EXPECT_CALL(*delegate(), OnFullCardRequestFailed());
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(), OnUnmaskVerificationResult(_)).Times(0);
@@ -291,9 +295,9 @@ TEST_F(FullCardRequestTest, ClosePromptWithoutUserInput) {
}
// If the server provides an empty PAN with PERMANENT_FAILURE error,
-// FullCardRequest::Delegate::OnFullCardError() should be invoked.
+// FullCardRequest::Delegate::OnFullCardRequestFailed() should be invoked.
TEST_F(FullCardRequestTest, PermanentFailure) {
- EXPECT_CALL(*delegate(), OnFullCardError());
+ EXPECT_CALL(*delegate(), OnFullCardRequestFailed());
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(),
OnUnmaskVerificationResult(AutofillClient::PERMANENT_FAILURE));
@@ -309,9 +313,9 @@ TEST_F(FullCardRequestTest, PermanentFailure) {
}
// If the server provides an empty PAN with NETWORK_ERROR error,
-// FullCardRequest::Delegate::OnFullCardError() should be invoked.
+// FullCardRequest::Delegate::OnFullCardRequestFailed() should be invoked.
TEST_F(FullCardRequestTest, NetworkError) {
- EXPECT_CALL(*delegate(), OnFullCardError());
+ EXPECT_CALL(*delegate(), OnFullCardRequestFailed());
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(),
OnUnmaskVerificationResult(AutofillClient::NETWORK_ERROR));
@@ -329,7 +333,7 @@ TEST_F(FullCardRequestTest, NetworkError) {
// If the server provides an empty PAN with TRY_AGAIN_FAILURE, the user can
// manually cancel out of the dialog.
TEST_F(FullCardRequestTest, TryAgainFailureGiveUp) {
- EXPECT_CALL(*delegate(), OnFullCardError());
+ EXPECT_CALL(*delegate(), OnFullCardRequestFailed());
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(),
OnUnmaskVerificationResult(AutofillClient::TRY_AGAIN_FAILURE));
@@ -347,11 +351,11 @@ TEST_F(FullCardRequestTest, TryAgainFailureGiveUp) {
// If the server provides an empty PAN with TRY_AGAIN_FAILURE, the user can
// correct their mistake and resubmit.
TEST_F(FullCardRequestTest, TryAgainFailureRetry) {
- EXPECT_CALL(*delegate(), OnFullCardError()).Times(0);
- EXPECT_CALL(
- *delegate(),
- OnFullCardDetails(CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(), OnFullCardRequestFailed()).Times(0);
+ EXPECT_CALL(*delegate(),
+ OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(),
OnUnmaskVerificationResult(AutofillClient::TRY_AGAIN_FAILURE));
@@ -372,10 +376,10 @@ TEST_F(FullCardRequestTest, TryAgainFailureRetry) {
// Verify updating expiration date for a masked server card.
TEST_F(FullCardRequestTest, UpdateExpDateForMaskedServerCard) {
- EXPECT_CALL(*delegate(),
- OnFullCardDetails(CardMatches(CreditCard::FULL_SERVER_CARD,
- "4111", "12", "2050"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(), OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::FULL_SERVER_CARD, "4111",
+ "12", "2050"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS));
@@ -393,15 +397,15 @@ TEST_F(FullCardRequestTest, UpdateExpDateForMaskedServerCard) {
// Verify updating expiration date for an unmasked server card.
TEST_F(FullCardRequestTest, UpdateExpDateForFullServerCard) {
- EXPECT_CALL(*delegate(),
- OnFullCardDetails(CardMatches(CreditCard::FULL_SERVER_CARD,
- "4111", "12", "2050"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(), OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::FULL_SERVER_CARD, "4111",
+ "12", "2050"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS));
- CreditCard full_server_card(base::ASCIIToUTF16("4111"), 10, 2000);
- full_server_card.set_record_type(CreditCard::FULL_SERVER_CARD);
+ CreditCard full_server_card(CreditCard::FULL_SERVER_CARD, "server_id");
+ test::SetCreditCardInfo(&full_server_card, nullptr, "4111", "10", "2000");
request()->GetFullCard(full_server_card, AutofillClient::UNMASK_FOR_AUTOFILL,
delegate()->AsWeakPtr());
CardUnmaskDelegate::UnmaskResponse response;
@@ -415,9 +419,10 @@ TEST_F(FullCardRequestTest, UpdateExpDateForFullServerCard) {
// Verify updating expiration date for a local card.
TEST_F(FullCardRequestTest, UpdateExpDateForLocalCard) {
- EXPECT_CALL(*delegate(), OnFullCardDetails(CardMatches(CreditCard::LOCAL_CARD,
- "4111", "12", "2051"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(),
+ OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::LOCAL_CARD, "4111", "12", "2051"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*personal_data(),
UpdateCreditCard(
@@ -426,9 +431,11 @@ TEST_F(FullCardRequestTest, UpdateExpDateForLocalCard) {
base::Time::Exploded today;
base::Time::Now().LocalExplode(&today);
- request()->GetFullCard(
- CreditCard(base::ASCIIToUTF16("4111"), 12, today.year - 1),
- AutofillClient::UNMASK_FOR_AUTOFILL, delegate()->AsWeakPtr());
+ CreditCard card;
+ test::SetCreditCardInfo(&card, nullptr, "4111", "10",
+ base::StringPrintf("%d", today.year - 1).c_str());
+ request()->GetFullCard(card, AutofillClient::UNMASK_FOR_AUTOFILL,
+ delegate()->AsWeakPtr());
CardUnmaskDelegate::UnmaskResponse response;
response.cvc = base::ASCIIToUTF16("123");
response.exp_month = base::ASCIIToUTF16("12");
@@ -439,10 +446,10 @@ TEST_F(FullCardRequestTest, UpdateExpDateForLocalCard) {
// Verify saving full PAN on disk.
TEST_F(FullCardRequestTest, SaveRealPan) {
- EXPECT_CALL(*delegate(),
- OnFullCardDetails(CardMatches(CreditCard::FULL_SERVER_CARD,
- "4111", "12", "2050"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(), OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::FULL_SERVER_CARD, "4111",
+ "12", "2050"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*personal_data(),
UpdateServerCreditCard(CardMatches(CreditCard::FULL_SERVER_CARD,
@@ -464,10 +471,10 @@ TEST_F(FullCardRequestTest, SaveRealPan) {
// Verify getting full PAN and CVC for PaymentRequest.
TEST_F(FullCardRequestTest, UnmaskForPaymentRequest) {
- EXPECT_CALL(
- *delegate(),
- OnFullCardDetails(CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(),
+ OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS));
@@ -484,10 +491,10 @@ TEST_F(FullCardRequestTest, UnmaskForPaymentRequest) {
// Verify that FullCardRequest::IsGettingFullCard() is true until the server
// returns the full PAN for a masked card.
TEST_F(FullCardRequestTest, IsGettingFullCardForMaskedServerCard) {
- EXPECT_CALL(
- *delegate(),
- OnFullCardDetails(CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(),
+ OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::FULL_SERVER_CARD, "4111"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS));
@@ -517,16 +524,17 @@ TEST_F(FullCardRequestTest, IsGettingFullCardForMaskedServerCard) {
// Verify that FullCardRequest::IsGettingFullCard() is true until the user types
// in the CVC for a card that is not masked.
TEST_F(FullCardRequestTest, IsGettingFullCardForLocalCard) {
- EXPECT_CALL(*delegate(),
- OnFullCardDetails(CardMatches(CreditCard::LOCAL_CARD, "4111"),
- base::ASCIIToUTF16("123")));
+ EXPECT_CALL(*delegate(), OnFullCardRequestSucceeded(
+ CardMatches(CreditCard::LOCAL_CARD, "4111"),
+ base::ASCIIToUTF16("123")));
EXPECT_CALL(*client(), ShowUnmaskPrompt(_, _, _));
EXPECT_CALL(*client(), OnUnmaskVerificationResult(AutofillClient::SUCCESS));
EXPECT_FALSE(request()->IsGettingFullCard());
- request()->GetFullCard(CreditCard(base::ASCIIToUTF16("4111"), 12, 2050),
- AutofillClient::UNMASK_FOR_AUTOFILL,
+ CreditCard card;
+ test::SetCreditCardInfo(&card, nullptr, "4111", "12", "2050");
+ request()->GetFullCard(card, AutofillClient::UNMASK_FOR_AUTOFILL,
delegate()->AsWeakPtr());
EXPECT_TRUE(request()->IsGettingFullCard());
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc
index 7c7d75b3ce3..32b2cca0857 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client.cc
@@ -6,6 +6,7 @@
#include <memory>
#include <utility>
+#include <vector>
#include "base/command_line.h"
#include "base/json/json_reader.h"
@@ -110,14 +111,21 @@ void AppendStringIfNotEmpty(const AutofillProfile& profile,
list->AppendString(value);
}
+// Returns a dictionary with the structure expected by Payments RPCs, containing
+// each of the fields in |profile|, formatted according to |app_locale|. If
+// |include_non_location_data| is false, the name and phone number in |profile|
+// are not included.
std::unique_ptr<base::DictionaryValue> BuildAddressDictionary(
const AutofillProfile& profile,
- const std::string& app_locale) {
+ const std::string& app_locale,
+ bool include_non_location_data) {
std::unique_ptr<base::DictionaryValue> postal_address(
new base::DictionaryValue());
- SetStringIfNotEmpty(profile, NAME_FULL, app_locale, "recipient_name",
- postal_address.get());
+ if (include_non_location_data) {
+ SetStringIfNotEmpty(profile, NAME_FULL, app_locale,
+ PaymentsClient::kRecipientName, postal_address.get());
+ }
std::unique_ptr<base::ListValue> address_lines(new base::ListValue());
AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE1, app_locale,
@@ -143,8 +151,11 @@ std::unique_ptr<base::DictionaryValue> BuildAddressDictionary(
std::unique_ptr<base::DictionaryValue> address(new base::DictionaryValue());
address->Set("postal_address", std::move(postal_address));
- SetStringIfNotEmpty(profile, PHONE_HOME_WHOLE_NUMBER, app_locale,
- "phone_number", address.get());
+
+ if (include_non_location_data) {
+ SetStringIfNotEmpty(profile, PHONE_HOME_WHOLE_NUMBER, app_locale,
+ PaymentsClient::kPhoneNumber, address.get());
+ }
return address;
}
@@ -171,7 +182,7 @@ class UnmaskCardRequest : public PaymentsRequest {
request_dict.SetString("credit_card_id", request_details_.card.server_id());
request_dict.Set("risk_data_encoded",
BuildRiskDictionary(request_details_.risk_data));
- request_dict.Set("context", base::WrapUnique(new base::DictionaryValue()));
+ request_dict.Set("context", base::MakeUnique<base::DictionaryValue>());
int value = 0;
if (base::StringToInt(request_details_.user_response.exp_month, &value))
@@ -209,8 +220,9 @@ class UnmaskCardRequest : public PaymentsRequest {
class GetUploadDetailsRequest : public PaymentsRequest {
public:
- GetUploadDetailsRequest(const std::string& app_locale)
- : app_locale_(app_locale) {}
+ GetUploadDetailsRequest(const std::vector<AutofillProfile>& addresses,
+ const std::string& app_locale)
+ : addresses_(addresses), app_locale_(app_locale) {}
~GetUploadDetailsRequest() override {}
std::string GetRequestUrlPath() override {
@@ -225,6 +237,18 @@ class GetUploadDetailsRequest : public PaymentsRequest {
context->SetString("language_code", app_locale_);
request_dict.Set("context", std::move(context));
+ std::unique_ptr<base::ListValue> addresses(new base::ListValue());
+ for (const AutofillProfile& profile : addresses_) {
+ // These addresses are used by Payments to (1) accurately determine the
+ // user's country in order to show the correct legal documents and (2) to
+ // verify that the addresses are valid for their purposes so that we don't
+ // offer save in a case where it would definitely fail (e.g. P.O. boxes).
+ // The final parameter directs BuildAddressDictionary to omit names and
+ // phone numbers, which aren't useful for these purposes.
+ addresses->Append(BuildAddressDictionary(profile, app_locale_, false));
+ }
+ request_dict.Set("address", std::move(addresses));
+
std::string request_content;
base::JSONWriter::Write(request_dict, &request_content);
VLOG(3) << "getdetailsforsavecard request body: " << request_content;
@@ -249,6 +273,7 @@ class GetUploadDetailsRequest : public PaymentsRequest {
}
private:
+ std::vector<AutofillProfile> addresses_;
std::string app_locale_;
base::string16 context_token_;
std::unique_ptr<base::DictionaryValue> legal_message_;
@@ -283,7 +308,7 @@ class UploadCardRequest : public PaymentsRequest {
std::unique_ptr<base::ListValue> addresses(new base::ListValue());
for (const AutofillProfile& profile : request_details_.profiles) {
- addresses->Append(BuildAddressDictionary(profile, app_locale));
+ addresses->Append(BuildAddressDictionary(profile, app_locale, true));
}
request_dict.Set("address", std::move(addresses));
@@ -330,6 +355,9 @@ class UploadCardRequest : public PaymentsRequest {
} // namespace
+const char PaymentsClient::kRecipientName[] = "recipient_name";
+const char PaymentsClient::kPhoneNumber[] = "phone_number";
+
PaymentsClient::UnmaskRequestDetails::UnmaskRequestDetails() {}
PaymentsClient::UnmaskRequestDetails::~UnmaskRequestDetails() {}
@@ -357,17 +385,19 @@ void PaymentsClient::Prepare() {
void PaymentsClient::UnmaskCard(
const PaymentsClient::UnmaskRequestDetails& request_details) {
- IssueRequest(base::WrapUnique(new UnmaskCardRequest(request_details)), true);
+ IssueRequest(base::MakeUnique<UnmaskCardRequest>(request_details), true);
}
-void PaymentsClient::GetUploadDetails(const std::string& app_locale) {
- IssueRequest(base::WrapUnique(new GetUploadDetailsRequest(app_locale)),
+void PaymentsClient::GetUploadDetails(
+ const std::vector<AutofillProfile>& addresses,
+ const std::string& app_locale) {
+ IssueRequest(base::MakeUnique<GetUploadDetailsRequest>(addresses, app_locale),
false);
}
void PaymentsClient::UploadCard(
const PaymentsClient::UploadRequestDetails& request_details) {
- IssueRequest(base::WrapUnique(new UploadCardRequest(request_details)), true);
+ IssueRequest(base::MakeUnique<UploadCardRequest>(request_details), true);
}
void PaymentsClient::IssueRequest(std::unique_ptr<PaymentsRequest> request,
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.h b/chromium/components/autofill/core/browser/payments/payments_client.h
index 2af8bb7b7cf..40fb7d1590c 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.h
+++ b/chromium/components/autofill/core/browser/payments/payments_client.h
@@ -58,6 +58,12 @@ class PaymentsClientDelegate {
class PaymentsClient : public net::URLFetcherDelegate,
public OAuth2TokenService::Consumer {
public:
+ // The names of the fields used to send non-location elements as part of an
+ // address. Used in the implementation and in tests which verify that these
+ // values are set or not at appropriate times.
+ static const char kRecipientName[];
+ static const char kPhoneNumber[];
+
// A collection of the information required to make a credit card unmask
// request.
struct UnmaskRequestDetails {
@@ -103,9 +109,12 @@ class PaymentsClient : public net::URLFetcherDelegate,
void UnmaskCard(const UnmaskRequestDetails& request_details);
// Determine if the user meets the Payments service's conditions for upload.
- // If so, the required legal message for display will be returned via
+ // The service uses |addresses| (from which names and phone numbers are
+ // removed) and |app_locale| to determine which legal message to display. If
+ // the conditions are met, the legal message will be returned via
// OnDidGetUploadDetails.
- virtual void GetUploadDetails(const std::string& app_locale);
+ virtual void GetUploadDetails(const std::vector<AutofillProfile>& addresses,
+ const std::string& app_locale);
// The user has indicated that they would like to upload a card with the given
// cvc. This request will fail server-side if a successful call to
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index d8679fb71db..7efb5d7be13 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -5,6 +5,7 @@
#include "components/autofill/core/browser/personal_data_manager.h"
#include <stddef.h>
+
#include <algorithm>
#include <list>
#include <map>
@@ -39,7 +40,7 @@
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/common/signin_pref_names.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_service.h"
#include "components/variations/variations_associated_data.h"
#include "components/version_info/version_info.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
@@ -262,7 +263,8 @@ PersonalDataManager::PersonalDataManager(const std::string& app_locale)
account_tracker_(NULL),
is_off_the_record_(false),
has_logged_profile_count_(false),
- has_logged_credit_card_count_(false) {}
+ has_logged_local_credit_card_count_(false),
+ has_logged_server_credit_card_counts_(false) {}
void PersonalDataManager::Init(scoped_refptr<AutofillWebDataService> database,
PrefService* pref_service,
@@ -302,7 +304,7 @@ PersonalDataManager::~PersonalDataManager() {
}
void PersonalDataManager::OnSyncServiceInitialized(
- sync_driver::SyncService* sync_service) {
+ syncer::SyncService* sync_service) {
// We want to know when, if at all, we need to run autofill profile de-
// duplication: now or after waiting until sync has started.
if (!is_autofill_profile_dedupe_pending_) {
@@ -387,6 +389,8 @@ void PersonalDataManager::OnWebDataServiceRequestDone(
// disabled, force mask all cards back to the unsaved state.
if (!OfferStoreUnmaskedCards())
ResetFullServerCards();
+
+ LogServerCreditCardCounts();
}
break;
default:
@@ -600,10 +604,10 @@ void PersonalDataManager::UpdateServerCreditCard(
return;
// Look up by server id, not GUID.
- CreditCard* existing_credit_card = nullptr;
- for (auto it : server_credit_cards_) {
- if (credit_card.server_id() == it->server_id()) {
- existing_credit_card = it;
+ const CreditCard* existing_credit_card = nullptr;
+ for (const auto* server_card : server_credit_cards_) {
+ if (credit_card.server_id() == server_card->server_id()) {
+ existing_credit_card = server_card;
break;
}
}
@@ -630,9 +634,9 @@ void PersonalDataManager::UpdateServerCardBillingAddress(
return;
CreditCard* existing_credit_card = nullptr;
- for (auto it : server_credit_cards_) {
- if (credit_card.server_id() == it->server_id()) {
- existing_credit_card = it;
+ for (auto* server_card : server_credit_cards_) {
+ if (credit_card.server_id() == server_card->server_id()) {
+ existing_credit_card = server_card;
break;
}
}
@@ -1283,9 +1287,25 @@ void PersonalDataManager::LogProfileCount() const {
}
void PersonalDataManager::LogLocalCreditCardCount() const {
- if (!has_logged_credit_card_count_) {
+ if (!has_logged_local_credit_card_count_) {
AutofillMetrics::LogStoredLocalCreditCardCount(local_credit_cards_.size());
- has_logged_credit_card_count_ = true;
+ has_logged_local_credit_card_count_ = true;
+ }
+}
+
+void PersonalDataManager::LogServerCreditCardCounts() const {
+ if (!has_logged_server_credit_card_counts_) {
+ size_t unmasked_cards = 0, masked_cards = 0;
+ for (CreditCard* card : server_credit_cards_) {
+ if (card->record_type() == CreditCard::MASKED_SERVER_CARD) {
+ masked_cards++;
+ } else if (card->record_type() == CreditCard::FULL_SERVER_CARD) {
+ unmasked_cards++;
+ }
+ }
+ AutofillMetrics::LogStoredServerCreditCardCounts(masked_cards,
+ unmasked_cards);
+ has_logged_server_credit_card_counts_ = true;
}
}
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h
index b32e130b3dc..ac558756e00 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/personal_data_manager.h
@@ -5,8 +5,11 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PERSONAL_DATA_MANAGER_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_PERSONAL_DATA_MANAGER_H_
+#include <list>
#include <memory>
#include <set>
+#include <string>
+#include <unordered_set>
#include <vector>
#include "base/gtest_prod_util.h"
@@ -24,6 +27,9 @@
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_member.h"
#include "components/webdata/common/web_data_service_consumer.h"
+#if defined(OS_ANDROID)
+#include "net/url_request/url_request_context_getter.h"
+#endif
class AccountTrackerService;
class Browser;
@@ -31,15 +37,6 @@ class PrefService;
class RemoveAutofillTester;
class SigninManagerBase;
-#if defined(OS_IOS)
-// TODO(crbug.com/513344): Remove this once Chrome on iOS is unforked.
-class PersonalDataManagerFactory;
-#endif
-
-namespace sync_driver {
-class SyncService;
-}
-
namespace autofill {
class AutofillInteractiveTest;
class AutofillTest;
@@ -53,6 +50,10 @@ void SetProfiles(int, std::vector<autofill::AutofillProfile>*);
void SetCreditCards(int, std::vector<autofill::CreditCard>*);
} // namespace autofill_helper
+namespace syncer {
+class SyncService;
+} // namespace syncer
+
namespace autofill {
extern const char kFrecencyFieldTrialName[];
@@ -81,7 +82,7 @@ class PersonalDataManager : public KeyedService,
// Called once the sync service is known to be instantiated. Note that it may
// not be started, but it's preferences can be queried.
- void OnSyncServiceInitialized(sync_driver::SyncService* sync_service);
+ void OnSyncServiceInitialized(syncer::SyncService* sync_service);
// WebDataServiceConsumer:
void OnWebDataServiceRequestDone(WebDataServiceBase::Handle h,
@@ -265,6 +266,20 @@ class PersonalDataManager : public KeyedService,
NotifyPersonalDataChanged();
}
+#if defined(OS_ANDROID)
+ // Sets the URL request context getter to be used when normalizing addresses
+ // with libaddressinput's address validator.
+ void SetURLRequestContextGetter(
+ net::URLRequestContextGetter* context_getter) {
+ context_getter_ = context_getter;
+ }
+
+ // Returns the class used to fetch the address validation rules.
+ net::URLRequestContextGetter* GetURLRequestContextGetter() const {
+ return context_getter_.get();
+ }
+#endif
+
protected:
// Only PersonalDataManagerFactory and certain tests can create instances of
// PersonalDataManager.
@@ -293,10 +308,6 @@ class PersonalDataManager : public KeyedService,
friend class autofill::AutofillTest;
friend class autofill::PersonalDataManagerFactory;
friend class PersonalDataManagerTest;
-#if defined(OS_IOS)
- // TODO(crbug.com/513344): Remove this once Chrome on iOS is unforked.
- friend class ::PersonalDataManagerFactory;
-#endif
friend class ProfileSyncServiceAutofillTest;
friend class ::RemoveAutofillTester;
friend std::default_delete<PersonalDataManager>;
@@ -344,6 +355,11 @@ class PersonalDataManager : public KeyedService,
// credit cards the user has. On subsequent calls, does nothing.
void LogLocalCreditCardCount() const;
+ // The first time this is called, logs an UMA metric for the number of server
+ // credit cards the user has (both masked and unmasked). On subsequent calls,
+ // does nothing.
+ void LogServerCreditCardCounts() const;
+
// Returns the value of the AutofillEnabled pref.
virtual bool IsAutofillEnabled() const;
@@ -490,7 +506,11 @@ class PersonalDataManager : public KeyedService,
// Whether we have already logged the number of local credit cards this
// session.
- mutable bool has_logged_credit_card_count_;
+ mutable bool has_logged_local_credit_card_count_;
+
+ // Whether we have already logged the number of server credit cards this
+ // session.
+ mutable bool has_logged_server_credit_card_counts_;
// An observer to listen for changes to prefs::kAutofillEnabled.
std::unique_ptr<BooleanPrefMember> enabled_pref_;
@@ -502,6 +522,12 @@ class PersonalDataManager : public KeyedService,
// performed on the next data refresh.
bool is_autofill_profile_dedupe_pending_ = false;
+#if defined(OS_ANDROID)
+ // The context for the request to be used to fetch libaddressinput's address
+ // validation rules.
+ scoped_refptr<net::URLRequestContextGetter> context_getter_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(PersonalDataManager);
};
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
index 06eed20241a..06776f10ef6 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -18,11 +18,13 @@
#include "base/feature_list.h"
#include "base/files/scoped_temp_dir.h"
#include "base/guid.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -113,7 +115,7 @@ class PersonalDataManagerTest : public testing::Test {
OSCryptMocker::SetUpWithSingleton();
prefs_ = test::PrefServiceForTesting();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- base::FilePath path = temp_dir_.path().AppendASCII("TestWebDB");
+ base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
web_database_ =
new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
base::ThreadTaskRunnerHandle::Get());
@@ -141,11 +143,7 @@ class PersonalDataManagerTest : public testing::Test {
// There are no field trials enabled by default.
field_trial_list_.reset();
-
- // There are no features enabled by default.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- base::FeatureList::SetInstance(std::move(feature_list));
+ scoped_feature_list_.reset();
// Reset the deduping pref to its default value.
personal_data_->pref_service_->SetInteger(
@@ -199,11 +197,8 @@ class PersonalDataManagerTest : public testing::Test {
}
void EnableAutofillProfileCleanup() {
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(kAutofillProfileCleanup.name,
- std::string());
- base::FeatureList::SetInstance(std::move(feature_list));
+ scoped_feature_list_.reset(new base::test::ScopedFeatureList);
+ scoped_feature_list_->InitAndEnableFeature(kAutofillProfileCleanup);
personal_data_->is_autofill_profile_dedupe_pending_ = true;
}
@@ -314,7 +309,8 @@ class PersonalDataManagerTest : public testing::Test {
// Clear the existing |field_trial_list_| and variation parameters.
field_trial_list_.reset(NULL);
field_trial_list_.reset(
- new base::FieldTrialList(new metrics::SHA1EntropyProvider("foo")));
+ new base::FieldTrialList(
+ base::MakeUnique<metrics::SHA1EntropyProvider>("foo")));
variations::testing::ClearAllVariationParams();
std::map<std::string, std::string> params;
@@ -342,7 +338,7 @@ class PersonalDataManagerTest : public testing::Test {
// Verify that the web database has been updated and the notification sent.
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
.WillOnce(QuitMainMessageLoop());
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
CreditCard expected(base::GenerateGUID(), "https://www.example.com");
test::SetCreditCardInfo(&expected, exp_name, exp_cc_num, exp_cc_month,
@@ -368,6 +364,7 @@ class PersonalDataManagerTest : public testing::Test {
std::unique_ptr<base::FieldTrialList> field_trial_list_;
scoped_refptr<base::FieldTrial> field_trial_;
+ std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
};
TEST_F(PersonalDataManagerTest, AddProfile) {
@@ -2052,6 +2049,136 @@ TEST_F(PersonalDataManagerTest,
EXPECT_EQ(0, profile.Compare(*results2[0]));
}
+// Tests that no profile is inferred if the country is not recognized.
+TEST_F(PersonalDataManagerTest, ImportAddressProfiles_UnrecognizedCountry) {
+ FormData form;
+ FormFieldData field;
+ test::CreateTestFormField("First name:", "first_name", "George", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name:", "last_name", "Washington", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "California", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Country:", "country", "Notacountry", "text",
+ &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes();
+ EXPECT_FALSE(ImportAddressProfiles(form_structure));
+
+ // Since no refresh is expected, reload the data from the database to make
+ // sure no changes were written out.
+ ResetPersonalDataManager(USER_MODE_NORMAL);
+
+ const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
+ ASSERT_EQ(0U, profiles.size());
+ const std::vector<CreditCard*>& cards = personal_data_->GetCreditCards();
+ ASSERT_EQ(0U, cards.size());
+}
+
+// Tests that a profile is created for countries with composed names.
+TEST_F(PersonalDataManagerTest,
+ ImportAddressProfiles_CompleteComposedCountryName) {
+ FormData form;
+ FormFieldData field;
+ test::CreateTestFormField("First name:", "first_name", "George", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name:", "last_name", "Washington", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "California", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Country:", "country", "Myanmar [Burma]", "text",
+ &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes();
+ EXPECT_TRUE(ImportAddressProfiles(form_structure));
+
+ // Verify that the web database has been updated and the notification sent.
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+ .WillOnce(QuitMainMessageLoop());
+ base::RunLoop().Run();
+
+ AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ test::SetProfileInfo(&expected, "George", nullptr, "Washington",
+ "theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
+ "San Francisco", "California", "94102", "MM", nullptr);
+ const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
+ ASSERT_EQ(1U, results.size());
+ EXPECT_EQ(0, expected.Compare(*results[0]));
+}
+
+// TODO(crbug.com/634131): Create profiles if part of a standalone part of a
+// composed country name is present.
+// Tests that a profile is created if a standalone part of a composed country
+// name is present.
+TEST_F(PersonalDataManagerTest,
+ ImportAddressProfiles_IncompleteComposedCountryName) {
+ FormData form;
+ FormFieldData field;
+ test::CreateTestFormField("First name:", "first_name", "George", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name:", "last_name", "Washington", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "California", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "94102", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Country:", "country",
+ "Myanmar", // Missing the [Burma] part
+ "text", &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes();
+ EXPECT_FALSE(ImportAddressProfiles(form_structure));
+
+ // Since no refresh is expected, reload the data from the database to make
+ // sure no changes were written out.
+ ResetPersonalDataManager(USER_MODE_NORMAL);
+
+ const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles();
+ ASSERT_EQ(0U, profiles.size());
+ const std::vector<CreditCard*>& cards = personal_data_->GetCreditCards();
+ ASSERT_EQ(0U, cards.size());
+}
+
// ImportCreditCard tests.
// Tests that a valid credit card is extracted.
@@ -4390,8 +4517,8 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfile) {
saved_profiles.front()->GetRawInfo(changed_field.field_type));
}
// Verify that the merged profile's use count, use date and modification
- // date were updated.
- EXPECT_EQ(2U, saved_profiles.front()->use_count());
+ // date were properly updated.
+ EXPECT_EQ(1U, saved_profiles.front()->use_count());
EXPECT_GT(base::TimeDelta::FromMilliseconds(500),
base::Time::Now() - saved_profiles.front()->use_date());
EXPECT_GT(
@@ -4473,8 +4600,8 @@ TEST_F(PersonalDataManagerTest, MergeProfile_UsageStats) {
// The new profile should be merged into the existing profile.
EXPECT_EQ(profile.guid(), guid);
- // The use count should have been incremented by one.
- EXPECT_EQ(5U, profile.use_count());
+ // The use count should have be max(4, 1) => 4.
+ EXPECT_EQ(4U, profile.use_count());
// The use date and modification dates should have been set to less than 500
// milliseconds ago.
EXPECT_GT(base::TimeDelta::FromMilliseconds(500),
@@ -4644,10 +4771,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
// The specified country from the imported profile shoudl be kept (no loss of
// information).
EXPECT_EQ(UTF8ToUTF16("US"), profiles[0]->GetRawInfo(ADDRESS_HOME_COUNTRY));
- // The use count that results from the merge should be the sum of the two
- // saved profiles plus 1 (imported profile count).
- EXPECT_EQ(profile1.use_count() + profile2.use_count() + profile3.use_count(),
- profiles[0]->use_count());
+ // The use count that results from the merge should be the max of all the
+ // profiles use counts.
+ EXPECT_EQ(10U, profiles[0]->use_count());
// The use date that results from the merge should be the one from the
// profile1 since it was the most recently used profile.
EXPECT_LT(profile1.use_date() - base::TimeDelta::FromSeconds(10),
@@ -5057,7 +5183,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
personal_data_->AddProfile(Barney);
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
.WillOnce(QuitMainMessageLoop());
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
// Make sure the 7 profiles were saved;
EXPECT_EQ(7U, personal_data_->GetProfiles().size());
@@ -5074,7 +5200,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
.WillOnce(QuitMainMessageLoop());
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
// Get the profiles, sorted by frecency to have a deterministic order.
std::vector<AutofillProfile*> profiles =
@@ -5111,10 +5237,9 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
EXPECT_EQ(UTF8ToUTF16("Fox"), profiles[0]->GetRawInfo(COMPANY_NAME));
// The country from |Homer1| profile should be kept (no loss of information).
EXPECT_EQ(UTF8ToUTF16("US"), profiles[0]->GetRawInfo(ADDRESS_HOME_COUNTRY));
- // The use count that results from the merge should be the sum of Homer 1, 2
+ // The use count that results from the merge should be the max of Homer 1, 2
// and 3's respective use counts.
- EXPECT_EQ(Homer1.use_count() + Homer2.use_count() + Homer3.use_count(),
- profiles[0]->use_count());
+ EXPECT_EQ(10U, profiles[0]->use_count());
// The use date that results from the merge should be the one from the
// |Homer1| since it was the most recently used profile.
EXPECT_LT(Homer1.use_date() - base::TimeDelta::FromSeconds(5),
@@ -5147,7 +5272,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_FeatureDisabled) {
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
.WillOnce(QuitMainMessageLoop());
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
// Make sure both profiles were saved.
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -5178,7 +5303,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
personal_data_->AddProfile(profile2);
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
.WillOnce(QuitMainMessageLoop());
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
@@ -5190,7 +5315,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
EXPECT_TRUE(personal_data_->ApplyDedupingRoutine());
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
.WillOnce(QuitMainMessageLoop());
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
@@ -5204,14 +5329,12 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
"", "Springfield", "IL", "91601", "", "");
// Disable the profile cleanup before adding |profile3|.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- base::FeatureList::SetInstance(std::move(feature_list));
+ scoped_feature_list_.reset();
personal_data_->AddProfile(profile3);
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
.WillOnce(QuitMainMessageLoop());
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
// Make sure |profile3| was saved.
EXPECT_EQ(2U, personal_data_->GetProfiles().size());
diff --git a/chromium/components/autofill/core/browser/phone_field_unittest.cc b/chromium/components/autofill/core/browser/phone_field_unittest.cc
index b32bbdc996d..14c0b2c9d39 100644
--- a/chromium/components/autofill/core/browser/phone_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/phone_field_unittest.cc
@@ -158,7 +158,7 @@ TEST_F(PhoneFieldTest, ThreePartPhoneNumber) {
CheckField("areacode1", PHONE_HOME_CITY_CODE);
CheckField("prefix2", PHONE_HOME_NUMBER);
CheckField("suffix3", PHONE_HOME_NUMBER);
- EXPECT_TRUE(ContainsKey(field_candidates_map_, ASCIIToUTF16("ext4")));
+ EXPECT_TRUE(base::ContainsKey(field_candidates_map_, ASCIIToUTF16("ext4")));
}
}
diff --git a/chromium/components/autofill/core/browser/popup_item_ids.h b/chromium/components/autofill/core/browser/popup_item_ids.h
index e22ec5fff31..29be19cb622 100644
--- a/chromium/components/autofill/core/browser/popup_item_ids.h
+++ b/chromium/components/autofill/core/browser/popup_item_ids.h
@@ -19,6 +19,7 @@ enum PopupItemId {
POPUP_ITEM_ID_DATALIST_ENTRY = -6,
POPUP_ITEM_ID_SCAN_CREDIT_CARD = -7,
POPUP_ITEM_ID_TITLE = -8,
+ POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO = -9,
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto
index 5e6a9b7e2af..75451977735 100644
--- a/chromium/components/autofill/core/browser/proto/server.proto
+++ b/chromium/components/autofill/core/browser/proto/server.proto
@@ -18,8 +18,7 @@ message AutofillQueryContents {
repeated group Field = 4 {
required fixed32 signature = 5;
optional string name = 8;
- optional string type = 9; // Control type.
- optional string label = 10; // Truncated at 200 characters.
+ optional string type = 9; // Control type.
}
}
}
@@ -34,7 +33,7 @@ message AutofillQueryResponseContents {
// This message contains information about the field types in a single form.
// It is sent by the toolbar to contribute to the field type statistics.
-// Next available id: 20
+// Next available id: 21
message AutofillUploadContents {
required string client_version = 1;
required fixed64 form_signature = 2;
@@ -69,10 +68,6 @@ message AutofillUploadContents {
// The type of input control for this field (e.g. text, textarea, email).
optional string type = 10;
- // The label that is used alongside the field. Its value is truncated at
- // 200 characters.
- optional string label = 11;
-
enum PasswordGenerationType {
NO_GENERATION = 0;
AUTOMATICALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM = 1;
@@ -94,6 +89,10 @@ message AutofillUploadContents {
// The value of the class attribute on the field, if present.
optional string css_classes = 19;
+
+ // The properties mask (i.e. whether the field was autofilled, user
+ // modified, etc.) See FieldPropertiesFlags.
+ optional uint32 properties_mask = 20;
}
// Signature of the form action host (e.g. Hash64Bit("example.com")).
optional fixed64 action_signature = 13;
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc
index 0063e00cc7b..c97e95c6551 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_client.cc
@@ -30,7 +30,7 @@ PrefService* TestAutofillClient::GetPrefs() {
return prefs_.get();
}
-sync_driver::SyncService* TestAutofillClient::GetSyncService() {
+syncer::SyncService* TestAutofillClient::GetSyncService() {
return nullptr;
}
@@ -66,6 +66,12 @@ void TestAutofillClient::ConfirmSaveCreditCardToCloud(
callback.Run();
}
+void TestAutofillClient::ConfirmCreditCardFillAssist(
+ const CreditCard& card,
+ const base::Closure& callback) {
+ callback.Run();
+}
+
void TestAutofillClient::LoadRiskData(
const base::Callback<void(const std::string&)>& callback) {
callback.Run("some risk data");
@@ -115,4 +121,10 @@ bool TestAutofillClient::IsContextSecure(const GURL& form_origin) {
return is_context_secure_;
}
+bool TestAutofillClient::ShouldShowSigninPromo() {
+ return false;
+}
+
+void TestAutofillClient::StartSigninFlow() {}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h
index 0cca2eff50c..a9f2a86b33d 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.h
+++ b/chromium/components/autofill/core/browser/test_autofill_client.h
@@ -6,7 +6,9 @@
#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_CLIENT_H_
#include <memory>
+#include <string>
#include <utility>
+#include <vector>
#include "base/compiler_specific.h"
#include "base/i18n/rtl.h"
@@ -29,7 +31,7 @@ class TestAutofillClient : public AutofillClient {
PersonalDataManager* GetPersonalDataManager() override;
scoped_refptr<AutofillWebDataService> GetDatabase() override;
PrefService* GetPrefs() override;
- sync_driver::SyncService* GetSyncService() override;
+ syncer::SyncService* GetSyncService() override;
IdentityProvider* GetIdentityProvider() override;
rappor::RapporService* GetRapporService() override;
void ShowAutofillSettings() override;
@@ -43,6 +45,8 @@ class TestAutofillClient : public AutofillClient {
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
const base::Closure& callback) override;
+ void ConfirmCreditCardFillAssist(const CreditCard& card,
+ const base::Closure& callback) override;
void LoadRiskData(
const base::Callback<void(const std::string&)>& callback) override;
bool HasCreditCardScanFeature() override;
@@ -64,10 +68,12 @@ class TestAutofillClient : public AutofillClient {
const base::string16& profile_full_name) override;
void OnFirstUserGestureObserved() override;
bool IsContextSecure(const GURL& form_origin) override;
+ bool ShouldShowSigninPromo() override;
+ void StartSigninFlow() override;
void set_is_context_secure(bool is_context_secure) {
is_context_secure_ = is_context_secure;
- };
+ }
void SetPrefs(std::unique_ptr<PrefService> prefs) {
prefs_ = std::move(prefs);
diff --git a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
index a7fdb320234..a922b5a2c75 100644
--- a/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
+++ b/chromium/components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.cc
@@ -269,6 +269,8 @@ bool CardUnmaskPromptControllerImpl::CanStoreLocally() const {
return false;
if (reason_ == AutofillClient::UNMASK_FOR_PAYMENT_REQUEST)
return false;
+ if (card_.record_type() == CreditCard::LOCAL_CARD)
+ return false;
return OfferStoreUnmaskedCards();
}
@@ -322,7 +324,10 @@ bool CardUnmaskPromptControllerImpl::InputExpirationIsValid(
base::TimeDelta CardUnmaskPromptControllerImpl::GetSuccessMessageDuration()
const {
- return base::TimeDelta::FromMilliseconds(500);
+ return base::TimeDelta::FromMilliseconds(
+ card_.record_type() == CreditCard::LOCAL_CARD ||
+ reason_ == AutofillClient::UNMASK_FOR_PAYMENT_REQUEST
+ ? 0 : 500);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/validation.cc b/chromium/components/autofill/core/browser/validation.cc
index a063ab2fa00..b0f0a2a72bc 100644
--- a/chromium/components/autofill/core/browser/validation.cc
+++ b/chromium/components/autofill/core/browser/validation.cc
@@ -61,11 +61,6 @@ bool IsValidCreditCardNumber(const base::string16& text) {
if (type == kGenericCard && (number.size() < 12 || number.size() > 19))
return false;
- // Unlike all the other supported types, UnionPay cards lack Luhn checksum
- // validation.
- if (type == kUnionPay)
- return true;
-
// Use the Luhn formula [3] to validate the number.
// [3] http://en.wikipedia.org/wiki/Luhn_algorithm
int sum = 0;
diff --git a/chromium/components/autofill/core/browser/validation_unittest.cc b/chromium/components/autofill/core/browser/validation_unittest.cc
index 11dc379d7f9..9f8840dcdad 100644
--- a/chromium/components/autofill/core/browser/validation_unittest.cc
+++ b/chromium/components/autofill/core/browser/validation_unittest.cc
@@ -44,9 +44,7 @@ const char* const kValidNumbers[] = {
"4222-2222-2222-2",
"5019717010103742",
"6331101999990016",
-
- // A UnionPay card that doesn't pass the Luhn checksum
- "6200000000000000",
+ "6247130048162403",
};
const char* const kInvalidNumbers[] = {
"4111 1111 112", /* too short */
diff --git a/chromium/components/autofill/core/browser/webdata/DEPS b/chromium/components/autofill/core/browser/webdata/DEPS
index 05b9658453f..5fb592e596f 100644
--- a/chromium/components/autofill/core/browser/webdata/DEPS
+++ b/chromium/components/autofill/core/browser/webdata/DEPS
@@ -1,3 +1,3 @@
include_rules = [
- "+sync",
+ "+components/sync",
]
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc
index 843fe9c9731..cb23f73e4ed 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc
@@ -5,6 +5,7 @@
#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
#include <stdint.h>
+
#include <utility>
#include "base/location.h"
@@ -12,12 +13,12 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
#include "components/webdata/common/web_database.h"
#include "net/base/escape.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/protocol/autofill_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
namespace autofill {
namespace {
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h
index 75f2aa15f12..8f5949ca664 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_syncable_service.h
@@ -20,21 +20,23 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/syncable_service.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/syncable_service.h"
+namespace browser_sync {
class FakeServerUpdater;
class ProfileSyncServiceAutofillTest;
+} // namespace browser_sync
namespace syncer {
class SyncErrorFactory;
-}
+} // namespace syncer
namespace sync_pb {
class AutofillSpecifics;
-}
+} // namespace sync_pb
namespace autofill {
@@ -98,8 +100,8 @@ class AutocompleteSyncableService
virtual bool SaveChangesToWebData(const std::vector<AutofillEntry>& entries);
private:
- friend class ::FakeServerUpdater;
- friend class ::ProfileSyncServiceAutofillTest;
+ friend class browser_sync::FakeServerUpdater;
+ friend class browser_sync::ProfileSyncServiceAutofillTest;
// This is a helper map used only in Merge/Process* functions. The lifetime
// of the iterator is longer than the map object. The bool in the pair is used
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.cc b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.cc
index a4f4a2218e0..67af5fd7180 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.cc
@@ -8,49 +8,44 @@
#include "base/metrics/histogram.h"
#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "sync/api/sync_error.h"
-#include "sync/internal_api/public/util/experiments.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/base/experiments.h"
namespace browser_sync {
AutofillDataTypeController::AutofillDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
const scoped_refptr<autofill::AutofillWebDataService>& web_data_service)
- : NonUIDataTypeController(ui_thread, error_callback, sync_client),
+ : NonUIDataTypeController(syncer::AUTOFILL, dump_stack, sync_client),
db_thread_(db_thread),
web_data_service_(web_data_service) {}
-syncer::ModelType AutofillDataTypeController::type() const {
- return syncer::AUTOFILL;
-}
-
syncer::ModelSafeGroup AutofillDataTypeController::model_safe_group() const {
return syncer::GROUP_DB;
}
void AutofillDataTypeController::WebDatabaseLoaded() {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
DCHECK_EQ(MODEL_STARTING, state());
OnModelLoaded();
}
AutofillDataTypeController::~AutofillDataTypeController() {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
}
bool AutofillDataTypeController::PostTaskOnBackendThread(
const tracked_objects::Location& from_here,
const base::Closure& task) {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
return db_thread_->PostTask(from_here, task);
}
bool AutofillDataTypeController::StartModels() {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
DCHECK_EQ(MODEL_STARTING, state());
if (!web_data_service_)
@@ -59,8 +54,8 @@ bool AutofillDataTypeController::StartModels() {
if (web_data_service_->IsDatabaseLoaded()) {
return true;
} else {
- web_data_service_->RegisterDBLoadedCallback(
- base::Bind(&AutofillDataTypeController::WebDatabaseLoaded, this));
+ web_data_service_->RegisterDBLoadedCallback(base::Bind(
+ &AutofillDataTypeController::WebDatabaseLoaded, base::AsWeakPtr(this)));
return false;
}
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.h b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.h
index ed7a83308bb..90559399957 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.h
@@ -11,7 +11,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "components/sync_driver/non_ui_data_type_controller.h"
+#include "components/sync/driver/non_ui_data_type_controller.h"
namespace autofill {
class AutofillWebDataService;
@@ -20,22 +20,20 @@ class AutofillWebDataService;
namespace browser_sync {
// A class that manages the startup and shutdown of autofill sync.
-class AutofillDataTypeController : public sync_driver::NonUIDataTypeController {
+class AutofillDataTypeController : public syncer::NonUIDataTypeController {
public:
+ // |dump_stack| is called when an unrecoverable error occurs.
AutofillDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
const scoped_refptr<autofill::AutofillWebDataService>& web_data_service);
+ ~AutofillDataTypeController() override;
// NonUIDataTypeController implementation.
- syncer::ModelType type() const override;
syncer::ModelSafeGroup model_safe_group() const override;
protected:
- ~AutofillDataTypeController() override;
-
// NonUIDataTypeController implementation.
bool PostTaskOnBackendThread(const tracked_objects::Location& from_here,
const base::Closure& task) override;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc
index 401d84f628d..1d2df0a6809 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc
@@ -4,6 +4,8 @@
#include "components/autofill/core/browser/webdata/autofill_data_type_controller.h"
+#include <memory>
+
#include "base/bind.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
@@ -16,10 +18,10 @@
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/sync_driver/data_type_controller_mock.h"
-#include "components/sync_driver/fake_sync_client.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/driver/data_type_controller_mock.h"
+#include "components/sync/driver/fake_sync_client.h"
#include "components/webdata_services/web_data_service_test_util.h"
-#include "sync/api/sync_error.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -111,7 +113,7 @@ class SyncAutofillDataTypeControllerTest : public testing::Test {
public:
SyncAutofillDataTypeControllerTest()
: db_thread_("DB_Thread"),
- last_start_result_(sync_driver::DataTypeController::OK),
+ last_start_result_(syncer::DataTypeController::OK),
weak_ptr_factory_(this) {}
~SyncAutofillDataTypeControllerTest() override {}
@@ -119,9 +121,9 @@ class SyncAutofillDataTypeControllerTest : public testing::Test {
db_thread_.Start();
web_data_service_ = new FakeWebDataService(
base::ThreadTaskRunnerHandle::Get(), db_thread_.task_runner());
- autofill_dtc_ = new AutofillDataTypeController(
- base::ThreadTaskRunnerHandle::Get(), db_thread_.task_runner(),
- base::Bind(&base::DoNothing), &sync_client_, web_data_service_);
+ autofill_dtc_ = base::MakeUnique<AutofillDataTypeController>(
+ db_thread_.task_runner(), base::Bind(&base::DoNothing), &sync_client_,
+ web_data_service_);
}
void TearDown() override {
@@ -136,14 +138,14 @@ class SyncAutofillDataTypeControllerTest : public testing::Test {
}
// Passed to AutofillDTC::Start().
- void OnStartFinished(sync_driver::DataTypeController::ConfigureResult result,
+ void OnStartFinished(syncer::DataTypeController::ConfigureResult result,
const syncer::SyncMergeResult& local_merge_result,
const syncer::SyncMergeResult& syncer_merge_result) {
last_start_result_ = result;
last_start_error_ = local_merge_result.error();
}
- void OnLoadFinished(syncer::ModelType type, syncer::SyncError error) {
+ void OnLoadFinished(syncer::ModelType type, const syncer::SyncError& error) {
EXPECT_FALSE(error.IsSet());
EXPECT_EQ(type, syncer::AUTOFILL);
}
@@ -158,12 +160,12 @@ class SyncAutofillDataTypeControllerTest : public testing::Test {
protected:
base::MessageLoop message_loop_;
base::Thread db_thread_;
- sync_driver::FakeSyncClient sync_client_;
- scoped_refptr<AutofillDataTypeController> autofill_dtc_;
+ syncer::FakeSyncClient sync_client_;
+ std::unique_ptr<AutofillDataTypeController> autofill_dtc_;
scoped_refptr<FakeWebDataService> web_data_service_;
// Stores arguments of most recent call of OnStartFinished().
- sync_driver::DataTypeController::ConfigureResult last_start_result_;
+ syncer::DataTypeController::ConfigureResult last_start_result_;
syncer::SyncError last_start_error_;
base::WeakPtrFactory<SyncAutofillDataTypeControllerTest> weak_ptr_factory_;
};
@@ -182,10 +184,9 @@ TEST_F(SyncAutofillDataTypeControllerTest, StartWDSReady) {
weak_ptr_factory_.GetWeakPtr()));
BlockForDBThread();
- EXPECT_EQ(sync_driver::DataTypeController::ASSOCIATION_FAILED,
- last_start_result_);
+ EXPECT_EQ(syncer::DataTypeController::ASSOCIATION_FAILED, last_start_result_);
EXPECT_TRUE(last_start_error_.IsSet());
- EXPECT_EQ(sync_driver::DataTypeController::DISABLED, autofill_dtc_->state());
+ EXPECT_EQ(syncer::DataTypeController::DISABLED, autofill_dtc_->state());
}
// Start the autofill DTC without the WDS's database loaded, then
@@ -197,10 +198,9 @@ TEST_F(SyncAutofillDataTypeControllerTest, StartWDSNotReady) {
base::Bind(&SyncAutofillDataTypeControllerTest::OnLoadFinished,
weak_ptr_factory_.GetWeakPtr()));
- EXPECT_EQ(sync_driver::DataTypeController::OK, last_start_result_);
+ EXPECT_EQ(syncer::DataTypeController::OK, last_start_result_);
EXPECT_FALSE(last_start_error_.IsSet());
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_STARTING,
- autofill_dtc_->state());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING, autofill_dtc_->state());
web_data_service_->LoadDatabase();
@@ -209,11 +209,10 @@ TEST_F(SyncAutofillDataTypeControllerTest, StartWDSNotReady) {
weak_ptr_factory_.GetWeakPtr()));
BlockForDBThread();
- EXPECT_EQ(sync_driver::DataTypeController::ASSOCIATION_FAILED,
- last_start_result_);
+ EXPECT_EQ(syncer::DataTypeController::ASSOCIATION_FAILED, last_start_result_);
EXPECT_TRUE(last_start_error_.IsSet());
- EXPECT_EQ(sync_driver::DataTypeController::DISABLED, autofill_dtc_->state());
+ EXPECT_EQ(syncer::DataTypeController::DISABLED, autofill_dtc_->state());
}
} // namespace
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc
index ce15cdeffc8..447e0623f42 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc
@@ -8,43 +8,39 @@
#include "base/metrics/histogram.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/sync_driver/sync_client.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/syncable_service.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/syncable_service.h"
+#include "components/sync/driver/sync_client.h"
using autofill::AutofillWebDataService;
namespace browser_sync {
AutofillProfileDataTypeController::AutofillProfileDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
const scoped_refptr<autofill::AutofillWebDataService>& web_data_service)
- : NonUIDataTypeController(ui_thread, error_callback, sync_client),
- ui_thread_(ui_thread),
+ : NonUIDataTypeController(syncer::AUTOFILL_PROFILE,
+ dump_stack,
+ sync_client),
db_thread_(db_thread),
sync_client_(sync_client),
web_data_service_(web_data_service),
callback_registered_(false) {}
-syncer::ModelType AutofillProfileDataTypeController::type() const {
- return syncer::AUTOFILL_PROFILE;
-}
-
syncer::ModelSafeGroup AutofillProfileDataTypeController::model_safe_group()
const {
return syncer::GROUP_DB;
}
void AutofillProfileDataTypeController::WebDatabaseLoaded() {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
OnModelLoaded();
}
void AutofillProfileDataTypeController::OnPersonalDataChanged() {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
DCHECK_EQ(state(), MODEL_STARTING);
sync_client_->GetPersonalDataManager()->RemoveObserver(this);
@@ -55,8 +51,9 @@ void AutofillProfileDataTypeController::OnPersonalDataChanged() {
if (web_data_service_->IsDatabaseLoaded()) {
OnModelLoaded();
} else if (!callback_registered_) {
- web_data_service_->RegisterDBLoadedCallback(base::Bind(
- &AutofillProfileDataTypeController::WebDatabaseLoaded, this));
+ web_data_service_->RegisterDBLoadedCallback(
+ base::Bind(&AutofillProfileDataTypeController::WebDatabaseLoaded,
+ base::AsWeakPtr(this)));
callback_registered_ = true;
}
}
@@ -66,12 +63,12 @@ AutofillProfileDataTypeController::~AutofillProfileDataTypeController() {}
bool AutofillProfileDataTypeController::PostTaskOnBackendThread(
const tracked_objects::Location& from_here,
const base::Closure& task) {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
return db_thread_->PostTask(from_here, task);
}
bool AutofillProfileDataTypeController::StartModels() {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
DCHECK_EQ(state(), MODEL_STARTING);
// Waiting for the personal data is subtle: we do this as the PDM resets
// its cache of unique IDs once it gets loaded. If we were to proceed with
@@ -90,8 +87,9 @@ bool AutofillProfileDataTypeController::StartModels() {
return true;
if (!callback_registered_) {
- web_data_service_->RegisterDBLoadedCallback(base::Bind(
- &AutofillProfileDataTypeController::WebDatabaseLoaded, this));
+ web_data_service_->RegisterDBLoadedCallback(
+ base::Bind(&AutofillProfileDataTypeController::WebDatabaseLoaded,
+ base::AsWeakPtr(this)));
callback_registered_ = true;
}
@@ -99,7 +97,7 @@ bool AutofillProfileDataTypeController::StartModels() {
}
void AutofillProfileDataTypeController::StopModels() {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
sync_client_->GetPersonalDataManager()->RemoveObserver(this);
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h
index 5e13080de1c..cf68f4af67d 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h
@@ -10,7 +10,7 @@
#include "base/memory/ref_counted.h"
#include "base/scoped_observer.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
-#include "components/sync_driver/non_ui_data_type_controller.h"
+#include "components/sync/driver/non_ui_data_type_controller.h"
namespace autofill {
class AutofillWebDataService;
@@ -21,26 +21,24 @@ namespace browser_sync {
// Controls syncing of the AUTOFILL_PROFILE data type.
class AutofillProfileDataTypeController
- : public sync_driver::NonUIDataTypeController,
+ : public syncer::NonUIDataTypeController,
public autofill::PersonalDataManagerObserver {
public:
+ // |dump_stack| is called when an unrecoverable error occurs.
AutofillProfileDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
const scoped_refptr<autofill::AutofillWebDataService>& web_data_service);
+ ~AutofillProfileDataTypeController() override;
// NonUIDataTypeController:
- syncer::ModelType type() const override;
syncer::ModelSafeGroup model_safe_group() const override;
// PersonalDataManagerObserver:
void OnPersonalDataChanged() override;
protected:
- ~AutofillProfileDataTypeController() override;
-
// NonUIDataTypeController:
bool PostTaskOnBackendThread(const tracked_objects::Location& from_here,
const base::Closure& task) override;
@@ -51,14 +49,11 @@ class AutofillProfileDataTypeController
// Callback to notify that WebDatabase has loaded.
void WebDatabaseLoaded();
- // A reference to the UI thread's task runner.
- const scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
-
// A reference to the DB thread's task runner.
const scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
// A pointer to the sync client.
- sync_driver::SyncClient* const sync_client_;
+ syncer::SyncClient* const sync_client_;
// A reference to the AutofillWebDataService for this controller.
scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
index cd99e11a2aa..8d628f33dfe 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
@@ -5,6 +5,7 @@
#include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
#include <stddef.h>
+
#include <utility>
#include "base/guid.h"
@@ -18,10 +19,10 @@
#include "components/autofill/core/browser/form_group.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/protocol/sync.pb.h"
#include "components/webdata/common/web_database.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/protocol/sync.pb.h"
using base::ASCIIToUTF16;
using base::UTF8ToUTF16;
@@ -111,7 +112,7 @@ AutofillProfileSyncableService::MergeDataAndStartSyncing(
DVLOG(2) << "[AUTOFILL MIGRATION]"
<< "Printing profiles from web db";
- for (const auto& p : profiles_) {
+ for (const auto* p : profiles_) {
DVLOG(2) << "[AUTOFILL MIGRATION] "
<< UTF16ToUTF8(p->GetRawInfo(NAME_FIRST))
<< UTF16ToUTF8(p->GetRawInfo(NAME_LAST))
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
index 743cf795008..fa0aa81706b 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
@@ -21,13 +21,15 @@
#include "components/autofill/core/browser/webdata/autofill_entry.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/syncable_service.h"
-#include "sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/syncable_service.h"
+#include "components/sync/protocol/autofill_specifics.pb.h"
+namespace browser_sync {
class ProfileSyncServiceAutofillTest;
+} // namespace browser_sync
namespace autofill {
@@ -117,7 +119,7 @@ class AutofillProfileSyncableService
static syncer::SyncData CreateData(const AutofillProfile& profile);
private:
- friend class ::ProfileSyncServiceAutofillTest;
+ friend class browser_sync::ProfileSyncServiceAutofillTest;
FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
UpdateField);
FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
index cc4d442e612..a8ef61cb911 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
@@ -16,9 +16,9 @@
#include "components/autofill/core/browser/country_names.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
#include "components/autofill/core/common/autofill_constants.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/api/sync_error_factory_mock.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/api/sync_error_factory_mock.h"
+#include "components/sync/protocol/sync.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -377,6 +377,7 @@ TEST_F(AutofillProfileSyncableServiceTest, MergeSimilarProfiles) {
profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1,
ASCIIToUTF16("1 1st st"));
+ profiles_from_web_db.back()->set_use_count(27);
profiles_from_web_db.push_back(
new AutofillProfile(guid_present2, origin_present2));
profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
@@ -384,17 +385,19 @@ TEST_F(AutofillProfileSyncableServiceTest, MergeSimilarProfiles) {
ASCIIToUTF16("2 2nd st"));
// The synced profiles are identical to the local ones, except that the guids
- // are different.
+ // and use_count values are different.
syncer::SyncDataList data_list;
AutofillProfile profile1(guid_synced1, origin_synced1);
profile1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
profile1.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 1st st"));
profile1.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
+ profile1.set_use_count(13);
data_list.push_back(autofill_syncable_service_.CreateData(profile1));
AutofillProfile profile2(guid_synced2, origin_synced2);
profile2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
profile2.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("2 2nd st"));
profile2.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Fizzbang, LLC."));
+ profile1.set_use_count(4);
data_list.push_back(autofill_syncable_service_.CreateData(profile2));
// The first profile should have its origin updated.
@@ -403,8 +406,8 @@ TEST_F(AutofillProfileSyncableServiceTest, MergeSimilarProfiles) {
AutofillProfile expected_profile(profile1);
expected_profile.set_origin(origin_present1);
expected_profile.SetRawInfo(NAME_FULL, ASCIIToUTF16("John"));
- // Merging two profile adds their user count.
- expected_profile.set_use_count(2);
+ // Merging two profile takes their max use count.
+ expected_profile.set_use_count(27);
syncer::SyncChangeList expected_change_list;
expected_change_list.push_back(
syncer::SyncChange(FROM_HERE,
@@ -670,7 +673,7 @@ TEST_F(AutofillProfileSyncableServiceTest,
EXPECT_EQ(base::Time::FromTimeT(35), into_profile.use_date());
}
-// Tests that MergeSimilarProfiles saves the sum of the use counts of the two
+// Tests that MergeSimilarProfiles saves the max of the use counts of the two
// profiles in |into_profile|.
TEST_F(AutofillProfileSyncableServiceTest,
MergeSimilarProfiles_NonZeroUseCounts) {
@@ -680,14 +683,14 @@ TEST_F(AutofillProfileSyncableServiceTest,
from_profile.set_use_date(base::Time::FromTimeT(1234));
into_profile.set_use_date(base::Time::FromTimeT(1234));
- from_profile.set_use_count(5);
- into_profile.set_use_count(12);
+ from_profile.set_use_count(12);
+ into_profile.set_use_count(5);
// Expect true because the use count of |from_profile| was added to the use
// count of |into_profile|.
EXPECT_TRUE(AutofillProfileSyncableService::MergeSimilarProfiles(
from_profile, &into_profile, "en-US"));
- EXPECT_EQ(17U, into_profile.use_count());
+ EXPECT_EQ(12U, into_profile.use_count());
}
// Ensure that all profile fields are able to be synced up from the client to
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
index 98ebfafce36..20bdea877a6 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
@@ -702,7 +702,7 @@ bool AutofillTable::AddFormFieldValuesTime(
for (const FormFieldData& element : elements) {
if (seen_names.size() >= kMaximumUniqueNames)
break;
- if (ContainsKey(seen_names, element.name))
+ if (base::ContainsKey(seen_names, element.name))
continue;
result = result && AddFormFieldValueTime(element, changes, time);
seen_names.insert(element.name);
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index df40d8bb8b9..dbef60bbf97 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -128,7 +128,7 @@ class AutofillTableTest : public testing::Test {
void SetUp() override {
OSCryptMocker::SetUpWithSingleton();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- file_ = temp_dir_.path().AppendASCII("TestWebDatabase");
+ file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
table_.reset(new AutofillTable);
db_.reset(new WebDatabase);
@@ -1608,7 +1608,7 @@ TEST_F(AutofillTableTest, SetGetServerCards) {
EXPECT_EQ(CreditCard::OK, outputs[0]->GetServerStatus());
EXPECT_EQ(CreditCard::EXPIRED, outputs[1]->GetServerStatus());
- STLDeleteContainerPointers(outputs.begin(), outputs.end());
+ base::STLDeleteContainerPointers(outputs.begin(), outputs.end());
}
TEST_F(AutofillTableTest, MaskUnmaskServerCards) {
@@ -1633,7 +1633,7 @@ TEST_F(AutofillTableTest, MaskUnmaskServerCards) {
EXPECT_TRUE(CreditCard::FULL_SERVER_CARD == outputs[0]->record_type());
EXPECT_EQ(full_number, outputs[0]->GetRawInfo(CREDIT_CARD_NUMBER));
- STLDeleteContainerPointers(outputs.begin(), outputs.end());
+ base::STLDeleteContainerPointers(outputs.begin(), outputs.end());
outputs.clear();
// Re-mask the number, we should only get the last 4 digits out.
@@ -1643,7 +1643,7 @@ TEST_F(AutofillTableTest, MaskUnmaskServerCards) {
EXPECT_TRUE(CreditCard::MASKED_SERVER_CARD == outputs[0]->record_type());
EXPECT_EQ(masked_number, outputs[0]->GetRawInfo(CREDIT_CARD_NUMBER));
- STLDeleteContainerPointers(outputs.begin(), outputs.end());
+ base::STLDeleteContainerPointers(outputs.begin(), outputs.end());
outputs.clear();
}
@@ -1674,7 +1674,7 @@ TEST_F(AutofillTableTest, SetServerCardModify) {
EXPECT_TRUE(outputs[0]->record_type() == CreditCard::FULL_SERVER_CARD);
EXPECT_EQ(full_number, outputs[0]->GetRawInfo(CREDIT_CARD_NUMBER));
- STLDeleteContainerPointers(outputs.begin(), outputs.end());
+ base::STLDeleteContainerPointers(outputs.begin(), outputs.end());
outputs.clear();
// Call set again with the masked number.
@@ -1687,7 +1687,7 @@ TEST_F(AutofillTableTest, SetServerCardModify) {
EXPECT_TRUE(outputs[0]->record_type() == CreditCard::FULL_SERVER_CARD);
EXPECT_EQ(full_number, outputs[0]->GetRawInfo(CREDIT_CARD_NUMBER));
- STLDeleteContainerPointers(outputs.begin(), outputs.end());
+ base::STLDeleteContainerPointers(outputs.begin(), outputs.end());
outputs.clear();
// Set inputs that do not include our old card.
@@ -1707,7 +1707,7 @@ TEST_F(AutofillTableTest, SetServerCardModify) {
EXPECT_EQ(random_card.server_id(), outputs[0]->server_id());
EXPECT_EQ(ASCIIToUTF16("2222"), outputs[0]->GetRawInfo(CREDIT_CARD_NUMBER));
- STLDeleteContainerPointers(outputs.begin(), outputs.end());
+ base::STLDeleteContainerPointers(outputs.begin(), outputs.end());
outputs.clear();
// Putting back the original card masked should make it masked (this tests
@@ -1720,7 +1720,7 @@ TEST_F(AutofillTableTest, SetServerCardModify) {
EXPECT_EQ(masked_card.server_id(), outputs[0]->server_id());
EXPECT_EQ(ASCIIToUTF16("1111"), outputs[0]->GetRawInfo(CREDIT_CARD_NUMBER));
- STLDeleteContainerPointers(outputs.begin(), outputs.end());
+ base::STLDeleteContainerPointers(outputs.begin(), outputs.end());
outputs.clear();
}
@@ -1826,7 +1826,7 @@ TEST_F(AutofillTableTest, SetServerProfile) {
ASSERT_EQ(1u, outputs.size());
EXPECT_EQ(one.server_id(), outputs[0]->server_id());
- STLDeleteContainerPointers(outputs.begin(), outputs.end());
+ base::STLDeleteContainerPointers(outputs.begin(), outputs.end());
outputs.clear();
// Set a different profile.
@@ -1839,7 +1839,7 @@ TEST_F(AutofillTableTest, SetServerProfile) {
ASSERT_EQ(1u, outputs.size());
EXPECT_EQ(two.server_id(), outputs[0]->server_id());
- STLDeleteContainerPointers(outputs.begin(), outputs.end());
+ base::STLDeleteContainerPointers(outputs.begin(), outputs.end());
outputs.clear();
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
index 7541787ea04..a1f94586e8b 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
@@ -24,11 +24,11 @@
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_change_processor.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_change_processor.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/protocol/sync.pb.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
index 55b44345e55..53807de06fc 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
@@ -15,10 +15,10 @@
#include "base/threading/thread_checker.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_merge_result.h"
-#include "sync/api/syncable_service.h"
-#include "sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_merge_result.h"
+#include "components/sync/api/syncable_service.h"
+#include "components/sync/protocol/autofill_specifics.pb.h"
namespace base {
template <typename, typename>
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
index 504a319c524..e4655d53ae4 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
@@ -20,11 +20,11 @@
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_change_processor_wrapper_for_test.h"
-#include "sync/api/sync_error_factory_mock.h"
-#include "sync/protocol/autofill_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_change_processor_wrapper_for_test.h"
+#include "components/sync/api/sync_error_factory_mock.h"
+#include "components/sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
index 08cb1d36fb3..de73b809704 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
@@ -5,6 +5,7 @@
#include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
#include <stddef.h>
+
#include <set>
#include <utility>
@@ -16,8 +17,8 @@
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/protocol/sync.pb.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h
index 7042baa41b8..8daa34b769f 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h
@@ -8,7 +8,7 @@
#include "base/macros.h"
#include "base/supports_user_data.h"
#include "base/threading/thread_checker.h"
-#include "sync/api/syncable_service.h"
+#include "components/sync/api/syncable_service.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h
index 5b913054bfd..8885a58f224 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend.h
@@ -5,7 +5,7 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WEBDATA_BACKEND_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WEBDATA_BACKEND_H_
-#include "sync/internal_api/public/base/model_type.h"
+#include "components/sync/base/model_type.h"
class WebDatabase;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
index 1bc55bbda26..d4117a0aa11 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
@@ -525,7 +525,7 @@ void AutofillWebDataBackendImpl::DestroyAutofillProfileResult(
const WDResult<std::vector<AutofillProfile*> >* r =
static_cast<const WDResult<std::vector<AutofillProfile*> >*>(result);
std::vector<AutofillProfile*> profiles = r->GetValue();
- STLDeleteElements(&profiles);
+ base::STLDeleteElements(&profiles);
}
void AutofillWebDataBackendImpl::DestroyAutofillCreditCardResult(
@@ -535,7 +535,7 @@ void AutofillWebDataBackendImpl::DestroyAutofillCreditCardResult(
static_cast<const WDResult<std::vector<CreditCard*> >*>(result);
std::vector<CreditCard*> credit_cards = r->GetValue();
- STLDeleteElements(&credit_cards);
+ base::STLDeleteElements(&credit_cards);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
index f1e9c823b6f..ab0ac2c86e5 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
@@ -14,11 +14,11 @@
#include "base/supports_user_data.h"
#include "components/autofill/core/browser/webdata/autofill_webdata.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/sync/base/model_type.h"
#include "components/webdata/common/web_data_results.h"
#include "components/webdata/common/web_data_service_base.h"
#include "components/webdata/common/web_data_service_consumer.h"
#include "components/webdata/common/web_database.h"
-#include "sync/internal_api/public/base/model_type.h"
class WebDatabaseService;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
index 7c83330d84d..f5d0605ebb0 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
@@ -6,7 +6,7 @@
#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WEBDATA_SERVICE_OBSERVER_H_
#include "components/autofill/core/browser/webdata/autofill_change.h"
-#include "sync/internal_api/public/base/model_type.h"
+#include "components/sync/base/model_type.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
index ff255507e94..0a62a262be3 100644
--- a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
@@ -101,7 +101,7 @@ class WebDataServiceTest : public testing::Test {
db_thread_.Start();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- base::FilePath path = temp_dir_.path().AppendASCII("TestWebDB");
+ base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
wdbs_ = new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
db_thread_.task_runner());
@@ -308,7 +308,7 @@ TEST_F(WebDataServiceAutofillTest, ProfileAdd) {
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(profile, *consumer.result()[0]);
- STLDeleteElements(&consumer.result());
+ base::STLDeleteElements(&consumer.result());
}
TEST_F(WebDataServiceAutofillTest, ProfileRemove) {
@@ -327,7 +327,7 @@ TEST_F(WebDataServiceAutofillTest, ProfileRemove) {
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(profile, *consumer.result()[0]);
- STLDeleteElements(&consumer.result());
+ base::STLDeleteElements(&consumer.result());
// Check that GUID-based notification was sent.
const AutofillProfileChange expected_change(
@@ -372,7 +372,7 @@ TEST_F(WebDataServiceAutofillTest, ProfileUpdate) {
ASSERT_EQ(2U, consumer.result().size());
EXPECT_EQ(profile2, *consumer.result()[0]);
EXPECT_EQ(profile1, *consumer.result()[1]);
- STLDeleteElements(&consumer.result());
+ base::STLDeleteElements(&consumer.result());
AutofillProfile profile2_changed(profile2);
profile2_changed.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Bill"));
@@ -395,7 +395,7 @@ TEST_F(WebDataServiceAutofillTest, ProfileUpdate) {
EXPECT_EQ(profile2_changed, *consumer2.result()[0]);
EXPECT_NE(profile2, *consumer2.result()[0]);
EXPECT_EQ(profile1, *consumer2.result()[1]);
- STLDeleteElements(&consumer2.result());
+ base::STLDeleteElements(&consumer2.result());
}
TEST_F(WebDataServiceAutofillTest, CreditAdd) {
@@ -410,7 +410,7 @@ TEST_F(WebDataServiceAutofillTest, CreditAdd) {
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(card, *consumer.result()[0]);
- STLDeleteElements(&consumer.result());
+ base::STLDeleteElements(&consumer.result());
}
TEST_F(WebDataServiceAutofillTest, CreditCardRemove) {
@@ -427,7 +427,7 @@ TEST_F(WebDataServiceAutofillTest, CreditCardRemove) {
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(credit_card, *consumer.result()[0]);
- STLDeleteElements(&consumer.result());
+ base::STLDeleteElements(&consumer.result());
// Remove the credit card.
wds_->RemoveCreditCard(credit_card.guid());
@@ -461,7 +461,7 @@ TEST_F(WebDataServiceAutofillTest, CreditUpdate) {
ASSERT_EQ(2U, consumer.result().size());
EXPECT_EQ(card2, *consumer.result()[0]);
EXPECT_EQ(card1, *consumer.result()[1]);
- STLDeleteElements(&consumer.result());
+ base::STLDeleteElements(&consumer.result());
CreditCard card2_changed(card2);
card2_changed.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Bill"));
@@ -478,7 +478,7 @@ TEST_F(WebDataServiceAutofillTest, CreditUpdate) {
EXPECT_NE(card2, *consumer2.result()[0]);
EXPECT_EQ(card2_changed, *consumer2.result()[0]);
EXPECT_EQ(card1, *consumer2.result()[1]);
- STLDeleteElements(&consumer2.result());
+ base::STLDeleteElements(&consumer2.result());
}
TEST_F(WebDataServiceAutofillTest, AutofillRemoveModifiedBetween) {
@@ -498,7 +498,7 @@ TEST_F(WebDataServiceAutofillTest, AutofillRemoveModifiedBetween) {
EXPECT_EQ(handle, profile_consumer.handle());
ASSERT_EQ(1U, profile_consumer.result().size());
EXPECT_EQ(profile, *profile_consumer.result()[0]);
- STLDeleteElements(&profile_consumer.result());
+ base::STLDeleteElements(&profile_consumer.result());
// Add a credit card.
CreditCard credit_card;
@@ -512,7 +512,7 @@ TEST_F(WebDataServiceAutofillTest, AutofillRemoveModifiedBetween) {
EXPECT_EQ(handle, card_consumer.handle());
ASSERT_EQ(1U, card_consumer.result().size());
EXPECT_EQ(credit_card, *card_consumer.result()[0]);
- STLDeleteElements(&card_consumer.result());
+ base::STLDeleteElements(&card_consumer.result());
// Check that GUID-based notification was sent for the profile.
const AutofillProfileChange expected_profile_change(
diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn
index d6213b21ef8..d01d18e3b28 100644
--- a/chromium/components/autofill/core/common/BUILD.gn
+++ b/chromium/components/autofill/core/common/BUILD.gn
@@ -28,17 +28,22 @@ static_library("common") {
"form_field_data_predictions.h",
"password_form.cc",
"password_form.h",
+ "password_form_field_prediction_map.h",
"password_form_fill_data.cc",
"password_form_fill_data.h",
+ "password_form_generation_data.h",
"password_generation_util.cc",
"password_generation_util.h",
"save_password_progress_logger.cc",
"save_password_progress_logger.h",
+ "signatures_util.cc",
+ "signatures_util.h",
]
deps = [
"//base",
"//base:i18n",
+ "//third_party/re2",
"//url",
]
diff --git a/chromium/components/autofill/core/common/DEPS b/chromium/components/autofill/core/common/DEPS
new file mode 100644
index 00000000000..0de07bbaf08
--- /dev/null
+++ b/chromium/components/autofill/core/common/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+third_party/re2",
+]
diff --git a/chromium/components/autofill/core/common/autofill_constants.h b/chromium/components/autofill/core/common/autofill_constants.h
index ab092908f89..872f697491b 100644
--- a/chromium/components/autofill/core/common/autofill_constants.h
+++ b/chromium/components/autofill/core/common/autofill_constants.h
@@ -32,6 +32,10 @@ const size_t kRequiredFieldsForUpload = 3;
// upload the form to and request predictions from the Autofill servers.
const size_t kRequiredFieldsForFormsWithOnlyPasswordFields = 2;
+// Special query id used between the browser and the renderer when the action
+// is initiated from the browser.
+const int kNoQueryId = -1;
+
// Options bitmask values for AutofillHostMsg_ShowPasswordSuggestions IPC
enum ShowPasswordSuggestionsOptions {
SHOW_ALL = 1 << 0 /* show all credentials, not just ones matching username */,
diff --git a/chromium/components/autofill/core/common/autofill_pref_names.cc b/chromium/components/autofill/core/common/autofill_pref_names.cc
index 526b93a063f..1dc5b59116d 100644
--- a/chromium/components/autofill/core/common/autofill_pref_names.cc
+++ b/chromium/components/autofill/core/common/autofill_pref_names.cc
@@ -7,6 +7,10 @@
namespace autofill {
namespace prefs {
+// Number of times the credit card signin promo has been shown.
+const char kAutofillCreditCardSigninPromoImpressionCount[] =
+ "autofill.credit_card_signin_promo_impression_count";
+
// Boolean that is true if Autofill is enabled and allowed to save profile data.
const char kAutofillEnabled[] = "autofill.enabled";
diff --git a/chromium/components/autofill/core/common/autofill_pref_names.h b/chromium/components/autofill/core/common/autofill_pref_names.h
index bdcf0fa4bd2..cab272d6cb6 100644
--- a/chromium/components/autofill/core/common/autofill_pref_names.h
+++ b/chromium/components/autofill/core/common/autofill_pref_names.h
@@ -11,6 +11,7 @@ namespace prefs {
// Alphabetical list of preference names specific to the Autofill
// component. Keep alphabetized, and document each in the .cc file.
+extern const char kAutofillCreditCardSigninPromoImpressionCount[];
extern const char kAutofillEnabled[];
extern const char kAutofillProfileUseDatesFixed[];
extern const char kAutofillLastVersionDeduped[];
diff --git a/chromium/components/autofill/core/common/autofill_switches.cc b/chromium/components/autofill/core/common/autofill_switches.cc
index 42276f83932..8aadec54c62 100644
--- a/chromium/components/autofill/core/common/autofill_switches.cc
+++ b/chromium/components/autofill/core/common/autofill_switches.cc
@@ -8,13 +8,6 @@
namespace autofill {
namespace switches {
-// Disables using device's camera to scan a new credit card when filling out a
-// credit card form.
-const char kDisableCreditCardScan[] = "disable-credit-card-scan";
-
-// Disables the experimental Full Form Autofill on iOS feature.
-const char kDisableFullFormAutofillIOS[] = "disable-full-form-autofill-ios";
-
// Force hiding the local save checkbox in the autofill dialog box for getting
// the full credit card number for a wallet card. The card will never be stored
// locally.
@@ -32,13 +25,6 @@ const char kDisablePasswordGeneration[] = "disable-password-generation";
// The "disable" flag for kEnableSingleClickAutofill.
const char kDisableSingleClickAutofill[] = "disable-single-click-autofill";
-// Enables using device's camera to scan a new credit card when filling out a
-// credit card form.
-const char kEnableCreditCardScan[] = "enable-credit-card-scan";
-
-// Enables the experimental Full Form Autofill on iOS feature.
-const char kEnableFullFormAutofillIOS[] = "enable-full-form-autofill-ios";
-
// Force showing the local save checkbox in the autofill dialog box for getting
// the full credit card number for a wallet card.
const char kEnableOfferStoreUnmaskedWalletCards[] =
diff --git a/chromium/components/autofill/core/common/autofill_switches.h b/chromium/components/autofill/core/common/autofill_switches.h
index 75c7a93fcf2..e423cca352b 100644
--- a/chromium/components/autofill/core/common/autofill_switches.h
+++ b/chromium/components/autofill/core/common/autofill_switches.h
@@ -12,14 +12,10 @@ namespace switches {
// All switches in alphabetical order. The switches should be documented
// alongside the definition of their values in the .cc file.
-extern const char kDisableCreditCardScan[];
-extern const char kDisableFullFormAutofillIOS[];
extern const char kDisableOfferStoreUnmaskedWalletCards[];
extern const char kDisableOfferUploadCreditCards[];
extern const char kDisablePasswordGeneration[];
extern const char kDisableSingleClickAutofill[];
-extern const char kEnableCreditCardScan[];
-extern const char kEnableFullFormAutofillIOS[];
extern const char kEnableOfferStoreUnmaskedWalletCards[];
extern const char kEnableOfferUploadCreditCards[];
extern const char kEnablePasswordGeneration[];
diff --git a/chromium/components/autofill/core/common/autofill_util.cc b/chromium/components/autofill/core/common/autofill_util.cc
index 28fc6c5e37c..faf019e8cdb 100644
--- a/chromium/components/autofill/core/common/autofill_util.cc
+++ b/chromium/components/autofill/core/common/autofill_util.cc
@@ -105,4 +105,31 @@ bool IsDesktopPlatform() {
#endif
}
+bool ShouldSkipField(const FormFieldData& field) {
+ return IsCheckable(field.check_status);
+}
+
+bool IsCheckable(const FormFieldData::CheckStatus& check_status) {
+ return check_status != FormFieldData::CheckStatus::NOT_CHECKABLE;
+}
+
+bool IsChecked(const FormFieldData::CheckStatus& check_status) {
+ return check_status == FormFieldData::CheckStatus::CHECKED;
+}
+
+void SetCheckStatus(FormFieldData* form_field_data,
+ bool isCheckable,
+ bool isChecked) {
+ if (isChecked) {
+ form_field_data->check_status = FormFieldData::CheckStatus::CHECKED;
+ } else {
+ if (isCheckable) {
+ form_field_data->check_status =
+ FormFieldData::CheckStatus::CHECKABLE_BUT_UNCHECKED;
+ } else {
+ form_field_data->check_status = FormFieldData::CheckStatus::NOT_CHECKABLE;
+ }
+ }
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_util.h b/chromium/components/autofill/core/common/autofill_util.h
index 34a2b0223f7..519b3cbe4f3 100644
--- a/chromium/components/autofill/core/common/autofill_util.h
+++ b/chromium/components/autofill/core/common/autofill_util.h
@@ -8,6 +8,7 @@
#include <stddef.h>
#include "base/strings/string16.h"
+#include "components/autofill/core/common/form_field_data.h"
namespace autofill {
@@ -42,6 +43,14 @@ size_t GetTextSelectionStart(const base::string16& suggestion,
// Android or iOS is considered desktop.
bool IsDesktopPlatform();
+bool ShouldSkipField(const FormFieldData& field);
+
+bool IsCheckable(const FormFieldData::CheckStatus& check_status);
+bool IsChecked(const FormFieldData::CheckStatus& check_status);
+void SetCheckStatus(FormFieldData* form_field_data,
+ bool isCheckable,
+ bool isChecked);
+
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_UTIL_H_
diff --git a/chromium/components/autofill/core/common/form_data.cc b/chromium/components/autofill/core/common/form_data.cc
index a1a5e822939..47137bb7f3b 100644
--- a/chromium/components/autofill/core/common/form_data.cc
+++ b/chromium/components/autofill/core/common/form_data.cc
@@ -86,6 +86,17 @@ bool FormData::SameFormAs(const FormData& form) const {
return true;
}
+bool FormData::operator==(const FormData& form) const {
+ return name == form.name && origin == form.origin && action == form.action &&
+ is_form_tag == form.is_form_tag &&
+ is_formless_checkout == form.is_formless_checkout &&
+ fields == form.fields;
+}
+
+bool FormData::operator!=(const FormData& form) const {
+ return !(*this == form);
+}
+
bool FormData::operator<(const FormData& form) const {
return std::tie(name, origin, action, is_form_tag, is_formless_checkout,
fields) < std::tie(form.name, form.origin, form.action,
diff --git a/chromium/components/autofill/core/common/form_data.h b/chromium/components/autofill/core/common/form_data.h
index 6014c14fcd0..a4397fc2a23 100644
--- a/chromium/components/autofill/core/common/form_data.h
+++ b/chromium/components/autofill/core/common/form_data.h
@@ -23,6 +23,11 @@ struct FormData {
// form elements.
bool SameFormAs(const FormData& other) const;
+ // Note: operator==() performs a full-field-comparison(byte by byte), this is
+ // different from SameFormAs(), which ignores comparison for those "values" of
+ // all form fields, just like what FormFieldData::SameFieldAs() ignores.
+ bool operator==(const FormData& form) const;
+ bool operator!=(const FormData& form) const;
// Allow FormData to be a key in STL containers.
bool operator<(const FormData& form) const;
diff --git a/chromium/components/autofill/core/common/form_field_data.cc b/chromium/components/autofill/core/common/form_field_data.cc
index 561ec4e9b77..6e19116ad9a 100644
--- a/chromium/components/autofill/core/common/form_field_data.cc
+++ b/chromium/components/autofill/core/common/form_field_data.cc
@@ -7,6 +7,7 @@
#include "base/pickle.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/autofill_util.h"
namespace autofill {
@@ -14,7 +15,7 @@ namespace {
// Increment this anytime pickle format is modified as well as provide
// deserialization routine from previous kPickleVersion format.
-const int kPickleVersion = 5;
+const int kPickleVersion = 6;
void AddVectorToPickle(std::vector<base::string16> strings,
base::Pickle* pickle) {
@@ -108,6 +109,11 @@ bool DeserializeSection8(base::PickleIterator* iter,
return iter->ReadString16(&field_data->css_classes);
}
+bool DeserializeSection9(base::PickleIterator* iter,
+ FormFieldData* field_data) {
+ return iter->ReadUInt32(&field_data->properties_mask);
+}
+
} // namespace
FormFieldData::FormFieldData()
@@ -117,7 +123,8 @@ FormFieldData::FormFieldData()
is_focusable(false),
should_autocomplete(true),
role(ROLE_ATTRIBUTE_OTHER),
- text_direction(base::i18n::UNKNOWN_DIRECTION) {}
+ text_direction(base::i18n::UNKNOWN_DIRECTION),
+ properties_mask(0) {}
FormFieldData::FormFieldData(const FormFieldData& other) = default;
@@ -147,13 +154,25 @@ bool FormFieldData::SameFieldAs(const FormFieldData& field) const {
// should not be considered changes in the structure of the form.
}
+bool FormFieldData::operator==(const FormFieldData& field) const {
+ return SameFieldAs(field) && is_autofilled == field.is_autofilled &&
+ check_status == field.check_status &&
+ option_values == field.option_values &&
+ option_contents == field.option_contents &&
+ properties_mask == field.properties_mask;
+}
+
+bool FormFieldData::operator!=(const FormFieldData& field) const {
+ return !(*this == field);
+}
+
bool FormFieldData::operator<(const FormFieldData& field) const {
// This does not use std::tie() as that generates more implicit variables
// than the max-vartrack-size for var-tracking-assignments when compiling
// for Android, producing build warnings. (See https://crbug.com/555171 for
// context.)
- // Like operator==, this ignores the value.
+ // Like SameFieldAs this ignores the value.
if (label < field.label) return true;
if (label > field.label) return false;
if (name < field.name) return true;
@@ -179,7 +198,7 @@ bool FormFieldData::operator<(const FormFieldData& field) const {
if (role > field.role) return false;
if (text_direction < field.text_direction) return true;
if (text_direction > field.text_direction) return false;
- // See operator== above for why we don't check option_values/contents.
+ // See SameFieldAs above for why we don't check option_values/contents.
return false;
}
@@ -202,6 +221,7 @@ void SerializeFormFieldData(const FormFieldData& field_data,
AddVectorToPickle(field_data.option_contents, pickle);
pickle->WriteString16(field_data.placeholder);
pickle->WriteString16(field_data.css_classes);
+ pickle->WriteUInt32(field_data.properties_mask);
}
bool DeserializeFormFieldData(base::PickleIterator* iter,
@@ -272,6 +292,20 @@ bool DeserializeFormFieldData(base::PickleIterator* iter,
}
break;
}
+ case 6: {
+ if (!DeserializeSection1(iter, &temp_form_field_data) ||
+ !DeserializeSection6(iter, &temp_form_field_data) ||
+ !DeserializeSection7(iter, &temp_form_field_data) ||
+ !DeserializeSection2(iter, &temp_form_field_data) ||
+ !DeserializeSection3(iter, &temp_form_field_data) ||
+ !DeserializeSection4(iter, &temp_form_field_data) ||
+ !DeserializeSection8(iter, &temp_form_field_data) ||
+ !DeserializeSection9(iter, &temp_form_field_data)) {
+ LOG(ERROR) << "Could not deserialize FormFieldData from pickle";
+ return false;
+ }
+ break;
+ }
default: {
LOG(ERROR) << "Unknown FormFieldData pickle version " << version;
return false;
@@ -313,30 +347,8 @@ std::ostream& operator<<(std::ostream& os, const FormFieldData& field) {
<< (field.is_autofilled ? "true" : "false") << " "
<< check_status_str << (field.is_focusable ? "true" : "false")
<< " " << (field.should_autocomplete ? "true" : "false") << " "
- << role_str << " " << field.text_direction;
-}
-
-bool IsCheckable(const FormFieldData::CheckStatus& check_status) {
- return check_status != FormFieldData::CheckStatus::NOT_CHECKABLE;
-}
-
-bool IsChecked(const FormFieldData::CheckStatus& check_status) {
- return check_status == FormFieldData::CheckStatus::CHECKED;
-}
-
-void SetCheckStatus(FormFieldData* form_field_data,
- bool isCheckable,
- bool isChecked) {
- if (isChecked) {
- form_field_data->check_status = FormFieldData::CheckStatus::CHECKED;
- } else {
- if (isCheckable) {
- form_field_data->check_status =
- FormFieldData::CheckStatus::CHECKABLE_BUT_UNCHECKED;
- } else {
- form_field_data->check_status = FormFieldData::CheckStatus::NOT_CHECKABLE;
- }
- }
+ << role_str << " " << field.text_direction << " "
+ << field.properties_mask;
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/form_field_data.h b/chromium/components/autofill/core/common/form_field_data.h
index 689657c0811..dbcb3ea445e 100644
--- a/chromium/components/autofill/core/common/form_field_data.h
+++ b/chromium/components/autofill/core/common/form_field_data.h
@@ -19,6 +19,20 @@ class PickleIterator;
namespace autofill {
+// The flags describing form field properties.
+enum FieldPropertiesFlags {
+ NO_FLAGS = 0u,
+ USER_TYPED = 1u << 0,
+ AUTOFILLED = 1u << 1,
+ HAD_FOCUS = 1u << 2,
+ // Use this flag, if some error occurred in flags processing.
+ ERROR_OCCURRED = 1u << 3
+};
+
+// FieldPropertiesMask is used to contain combinations of FieldPropertiesFlags
+// values.
+typedef uint32_t FieldPropertiesMask;
+
// Stores information about a field in a form.
struct FormFieldData {
// Copied to components/autofill/ios/browser/resources/autofill_controller.js.
@@ -42,10 +56,16 @@ struct FormFieldData {
// Returns true if two form fields are the same, not counting the value.
bool SameFieldAs(const FormFieldData& field) const;
+ // Note: operator==() performs a full-field-comparison(byte by byte), this is
+ // different from SameFieldAs(), which ignores comparison for those "values"
+ // not regarded as part of identity of the field, such as is_autofilled and
+ // the option_values/contents etc.
+ bool operator==(const FormFieldData& field) const;
+ bool operator!=(const FormFieldData& field) const;
// Comparison operator exposed for STL map. Uses label, then name to sort.
bool operator<(const FormFieldData& field) const;
- // If you add more, be sure to update the comparison operator, SameFieldAs,
+ // If you add more, be sure to update the comparison operators, SameFieldAs,
// serializing functions (in the .cc file) and the constructor.
base::string16 label;
base::string16 name;
@@ -65,6 +85,7 @@ struct FormFieldData {
bool should_autocomplete;
RoleAttribute role;
base::i18n::TextDirection text_direction;
+ FieldPropertiesMask properties_mask;
// For the HTML snippet |<option value="US">United States</option>|, the
// value is "US" and the contents are "United States".
@@ -82,12 +103,6 @@ bool DeserializeFormFieldData(base::PickleIterator* pickle_iterator,
// So we can compare FormFieldDatas with EXPECT_EQ().
std::ostream& operator<<(std::ostream& os, const FormFieldData& field);
-bool IsCheckable(const FormFieldData::CheckStatus& check_status);
-bool IsChecked(const FormFieldData::CheckStatus& check_status);
-void SetCheckStatus(FormFieldData* form_field_data,
- bool isCheckable,
- bool isChecked);
-
// Prefer to use this macro in place of |EXPECT_EQ()| for comparing
// |FormFieldData|s in test code.
#define EXPECT_FORM_FIELD_DATA_EQUALS(expected, actual) \
@@ -102,6 +117,7 @@ void SetCheckStatus(FormFieldData* form_field_data,
EXPECT_EQ(expected.css_classes, actual.css_classes); \
EXPECT_EQ(expected.is_autofilled, actual.is_autofilled); \
EXPECT_EQ(expected.check_status, actual.check_status); \
+ EXPECT_EQ(expected.properties_mask, actual.properties_mask); \
} while (0)
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/form_field_data_unittest.cc b/chromium/components/autofill/core/common/form_field_data_unittest.cc
index a2e55c77185..cae49ecb4df 100644
--- a/chromium/components/autofill/core/common/form_field_data_unittest.cc
+++ b/chromium/components/autofill/core/common/form_field_data_unittest.cc
@@ -7,6 +7,7 @@
#include "base/i18n/rtl.h"
#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/autofill_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
@@ -43,6 +44,11 @@ void FillVersion5Fields(FormFieldData* data) {
data->css_classes = base::ASCIIToUTF16("class1 class2");
}
+void FillVersion6Fields(FormFieldData* data) {
+ data->properties_mask =
+ FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::HAD_FOCUS;
+}
+
void WriteSection1(const FormFieldData& data, base::Pickle* pickle) {
pickle->WriteString16(data.label);
pickle->WriteString16(data.name);
@@ -89,6 +95,10 @@ void WriteVersion5Specific(const FormFieldData& data, base::Pickle* pickle) {
pickle->WriteString16(data.css_classes);
}
+void WriteVersion6Specific(const FormFieldData& data, base::Pickle* pickle) {
+ pickle->WriteUInt32(data.properties_mask);
+}
+
void SerializeInVersion1Format(const FormFieldData& data,
base::Pickle* pickle) {
WriteSection1(data, pickle);
@@ -137,6 +147,18 @@ void SerializeInVersion5Format(const FormFieldData& data,
WriteVersion5Specific(data, pickle);
}
+void SerializeInVersion6Format(const FormFieldData& data,
+ base::Pickle* pickle) {
+ WriteSection1(data, pickle);
+ WriteSection4(data, pickle);
+ WriteSection5(data, pickle);
+ WriteVersion2Specific(data, pickle);
+ WriteSection2(data, pickle);
+ WriteVersion3Specific(data, pickle);
+ WriteVersion5Specific(data, pickle);
+ WriteVersion6Specific(data, pickle);
+}
+
} // namespace
TEST(FormFieldDataTest, SerializeAndDeserialize) {
@@ -145,6 +167,7 @@ TEST(FormFieldDataTest, SerializeAndDeserialize) {
FillVersion2Fields(&data);
FillVersion3Fields(&data);
FillVersion5Fields(&data);
+ FillVersion6Fields(&data);
base::Pickle pickle;
SerializeFormFieldData(data, &pickle);
@@ -239,6 +262,25 @@ TEST(FormFieldDataTest, DeserializeVersion5) {
EXPECT_TRUE(actual.SameFieldAs(data));
}
+TEST(FormFieldDataTest, DeserializeVersion6) {
+ FormFieldData data;
+ FillCommonFields(&data);
+ FillVersion2Fields(&data);
+ FillVersion3Fields(&data);
+ FillVersion5Fields(&data);
+ FillVersion6Fields(&data);
+
+ base::Pickle pickle;
+ pickle.WriteInt(6);
+ SerializeInVersion6Format(data, &pickle);
+
+ base::PickleIterator iter(pickle);
+ FormFieldData actual;
+ EXPECT_TRUE(DeserializeFormFieldData(&iter, &actual));
+
+ EXPECT_TRUE(actual.SameFieldAs(data));
+}
+
// Verify that if the data isn't valid, the FormFieldData isn't populated
// during deserialization.
TEST(FormFieldDataTest, DeserializeBadData) {
diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc
index c4bcc588f76..17db56672b2 100644
--- a/chromium/components/autofill/core/common/password_form.cc
+++ b/chromium/components/autofill/core/common/password_form.cc
@@ -45,7 +45,6 @@ void PasswordFormToJSON(const PasswordForm& form,
base::ASCIIToUTF16("|")));
target->SetBoolean("blacklisted", form.blacklisted_by_user);
target->SetBoolean("preferred", form.preferred);
- target->SetBoolean("ssl_valid", form.ssl_valid);
target->SetDouble("date_created", form.date_created.ToDoubleT());
target->SetDouble("date_synced", form.date_synced.ToDoubleT());
target->SetInteger("type", form.type);
@@ -76,13 +75,12 @@ PasswordForm::PasswordForm()
password_value_is_default(false),
new_password_value_is_default(false),
new_password_marked_by_site(false),
- ssl_valid(false),
preferred(false),
blacklisted_by_user(false),
type(TYPE_MANUAL),
times_used(0),
generation_upload_status(NO_SIGNAL_SENT),
- skip_zero_click(true),
+ skip_zero_click(false),
layout(Layout::LAYOUT_OTHER),
was_parsed_using_autofill_predictions(false),
is_public_suffix_match(false),
@@ -91,8 +89,7 @@ PasswordForm::PasswordForm()
PasswordForm::PasswordForm(const PasswordForm& other) = default;
-PasswordForm::~PasswordForm() {
-}
+PasswordForm::~PasswordForm() = default;
bool PasswordForm::IsPossibleChangePasswordForm() const {
return !new_password_element.empty() &&
@@ -116,8 +113,8 @@ bool PasswordForm::operator==(const PasswordForm& form) const {
new_password_element == form.new_password_element &&
new_password_marked_by_site == form.new_password_marked_by_site &&
new_password_value == form.new_password_value &&
- ssl_valid == form.ssl_valid && preferred == form.preferred &&
- date_created == form.date_created && date_synced == form.date_synced &&
+ preferred == form.preferred && date_created == form.date_created &&
+ date_synced == form.date_synced &&
blacklisted_by_user == form.blacklisted_by_user && type == form.type &&
times_used == form.times_used &&
form_data.SameFormAs(form.form_data) &&
diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h
index 41dcef40767..c70da901fc9 100644
--- a/chromium/components/autofill/core/common/password_form.h
+++ b/chromium/components/autofill/core/common/password_form.h
@@ -176,15 +176,6 @@ struct PasswordForm {
// attribute. This is only used in parsed HTML forms.
bool new_password_marked_by_site;
- // Whether or not this login was saved under an HTTPS session with a valid
- // SSL cert. We will never match or autofill a PasswordForm where
- // ssl_valid == true with a PasswordForm where ssl_valid == false. This means
- // passwords saved under HTTPS will never get autofilled onto an HTTP page.
- // When importing, this should be set to true if the page URL is HTTPS, thus
- // giving it "the benefit of the doubt" that the SSL cert was valid when it
- // was saved. Default to false.
- bool ssl_valid;
-
// True if this PasswordForm represents the last username/password login the
// user selected to log in to the site. If there is only one saved entry for
// the site, this will always be true, but when there are multiple entries
@@ -305,12 +296,6 @@ struct LessThanUniqueKey {
bool operator()(const PasswordForm* left, const PasswordForm* right) const;
};
-// Map username to PasswordForm* for convenience. See password_form_manager.h.
-using PasswordFormMap = std::map<base::string16, std::unique_ptr<PasswordForm>>;
-
-// Like PasswordFormMap, but with weak (not owned) pointers.
-using ConstPasswordFormMap = std::map<base::string16, const PasswordForm*>;
-
// For testing.
std::ostream& operator<<(std::ostream& os, PasswordForm::Layout layout);
std::ostream& operator<<(std::ostream& os, const PasswordForm& form);
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.cc b/chromium/components/autofill/core/common/password_form_fill_data.cc
index 3ffa1811600..b4d5fd047bc 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.cc
+++ b/chromium/components/autofill/core/common/password_form_fill_data.cc
@@ -34,7 +34,7 @@ PasswordFormFillData::~PasswordFormFillData() {
void InitPasswordFormFillData(
const PasswordForm& form_on_page,
- const PasswordFormMap& matches,
+ const std::map<base::string16, const PasswordForm*>& matches,
const PasswordForm* const preferred_match,
bool wait_for_username_before_autofill,
bool enable_other_possible_usernames,
@@ -66,7 +66,7 @@ void InitPasswordFormFillData(
// Copy additional username/value pairs.
for (const auto& it : matches) {
- if (it.second.get() != preferred_match) {
+ if (it.second != preferred_match) {
PasswordAndRealm value;
value.password = it.second->password_value;
if (it.second->is_public_suffix_match ||
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.h b/chromium/components/autofill/core/common/password_form_fill_data.h
index 9c7819a4843..fd0f64fe84a 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.h
+++ b/chromium/components/autofill/core/common/password_form_fill_data.h
@@ -90,7 +90,7 @@ struct PasswordFormFillData {
// in |result|.
void InitPasswordFormFillData(
const PasswordForm& form_on_page,
- const PasswordFormMap& matches,
+ const std::map<base::string16, const PasswordForm*>& matches,
const PasswordForm* const preferred_match,
bool wait_for_username_before_autofill,
bool enable_other_possible_usernames,
diff --git a/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc b/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc
index e4734cc37d1..fd08e4f691e 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc
+++ b/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc
@@ -4,9 +4,11 @@
#include "components/autofill/core/common/password_form_fill_data.h"
+#include <map>
#include <memory>
#include <utility>
+#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/common/password_form.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -29,7 +31,6 @@ TEST(PasswordFormFillDataTest, TestSinglePreferredMatch) {
form_on_page.password_value = ASCIIToUTF16("test");
form_on_page.submit_element = ASCIIToUTF16("");
form_on_page.signon_realm = "https://foo.com/";
- form_on_page.ssl_valid = true;
form_on_page.preferred = false;
form_on_page.scheme = PasswordForm::SCHEME_HTML;
@@ -43,11 +44,10 @@ TEST(PasswordFormFillDataTest, TestSinglePreferredMatch) {
preferred_match.password_value = ASCIIToUTF16("test");
preferred_match.submit_element = ASCIIToUTF16("");
preferred_match.signon_realm = "https://foo.com/";
- preferred_match.ssl_valid = true;
preferred_match.preferred = true;
preferred_match.scheme = PasswordForm::SCHEME_HTML;
- PasswordFormMap matches;
+ std::map<base::string16, const PasswordForm*> matches;
PasswordFormFillData result;
InitPasswordFormFillData(form_on_page,
@@ -92,7 +92,6 @@ TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) {
form_on_page.password_value = ASCIIToUTF16("test");
form_on_page.submit_element = ASCIIToUTF16("");
form_on_page.signon_realm = "https://foo.com/";
- form_on_page.ssl_valid = true;
form_on_page.preferred = false;
form_on_page.scheme = PasswordForm::SCHEME_HTML;
@@ -107,14 +106,12 @@ TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) {
preferred_match.submit_element = ASCIIToUTF16("");
preferred_match.signon_realm = "https://foo.com/";
preferred_match.is_public_suffix_match = true;
- preferred_match.ssl_valid = true;
preferred_match.preferred = true;
preferred_match.scheme = PasswordForm::SCHEME_HTML;
// Create a match that matches exactly, so |is_public_suffix_match| has a
// default value false.
- std::unique_ptr<PasswordForm> scoped_exact_match(new PasswordForm);
- PasswordForm& exact_match = *scoped_exact_match;
+ PasswordForm exact_match;
exact_match.origin = GURL("https://foo.com/");
exact_match.action = GURL("https://foo.com/login");
exact_match.username_element = ASCIIToUTF16("username");
@@ -123,14 +120,12 @@ TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) {
exact_match.password_value = ASCIIToUTF16("test");
exact_match.submit_element = ASCIIToUTF16("");
exact_match.signon_realm = "https://foo.com/";
- exact_match.ssl_valid = true;
exact_match.preferred = false;
exact_match.scheme = PasswordForm::SCHEME_HTML;
// Create a match that was matched using public suffix, so
// |is_public_suffix_match| == true.
- std::unique_ptr<PasswordForm> scoped_public_suffix_match(new PasswordForm);
- PasswordForm& public_suffix_match = *scoped_public_suffix_match;
+ PasswordForm public_suffix_match;
public_suffix_match.origin = GURL("https://foo.com/");
public_suffix_match.action = GURL("https://foo.com/login");
public_suffix_match.username_element = ASCIIToUTF16("username");
@@ -140,16 +135,14 @@ TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) {
public_suffix_match.submit_element = ASCIIToUTF16("");
public_suffix_match.is_public_suffix_match = true;
public_suffix_match.signon_realm = "https://foo.com/";
- public_suffix_match.ssl_valid = true;
public_suffix_match.preferred = false;
public_suffix_match.scheme = PasswordForm::SCHEME_HTML;
// Add one exact match and one public suffix match.
- PasswordFormMap matches;
- matches.insert(std::make_pair(exact_match.username_value,
- std::move(scoped_exact_match)));
- matches.insert(std::make_pair(public_suffix_match.username_value,
- std::move(scoped_public_suffix_match)));
+ std::map<base::string16, const PasswordForm*> matches;
+ matches.insert(std::make_pair(exact_match.username_value, &exact_match));
+ matches.insert(
+ std::make_pair(public_suffix_match.username_value, &public_suffix_match));
PasswordFormFillData result;
InitPasswordFormFillData(form_on_page,
@@ -189,7 +182,6 @@ TEST(PasswordFormFillDataTest, TestAffiliationMatch) {
form_on_page.password_value = ASCIIToUTF16("test");
form_on_page.submit_element = ASCIIToUTF16("");
form_on_page.signon_realm = "https://foo.com/";
- form_on_page.ssl_valid = true;
form_on_page.preferred = false;
form_on_page.scheme = PasswordForm::SCHEME_HTML;
@@ -200,13 +192,11 @@ TEST(PasswordFormFillDataTest, TestAffiliationMatch) {
preferred_match.password_value = ASCIIToUTF16("test");
preferred_match.signon_realm = "android://hash@foo.com/";
preferred_match.is_affiliation_based_match = true;
- preferred_match.ssl_valid = true;
preferred_match.preferred = true;
// Create a match that matches exactly, so |is_affiliation_based_match| has a
// default value false.
- std::unique_ptr<PasswordForm> scoped_exact_match(new PasswordForm);
- PasswordForm& exact_match = *scoped_exact_match;
+ PasswordForm exact_match;
exact_match.origin = GURL("https://foo.com/");
exact_match.action = GURL("https://foo.com/login");
exact_match.username_element = ASCIIToUTF16("username");
@@ -215,29 +205,25 @@ TEST(PasswordFormFillDataTest, TestAffiliationMatch) {
exact_match.password_value = ASCIIToUTF16("test");
exact_match.submit_element = ASCIIToUTF16("");
exact_match.signon_realm = "https://foo.com/";
- exact_match.ssl_valid = true;
exact_match.preferred = false;
exact_match.scheme = PasswordForm::SCHEME_HTML;
// Create a match that was matched using public suffix, so
// |is_public_suffix_match| == true.
- std::unique_ptr<PasswordForm> scoped_affiliated_match(new PasswordForm);
- PasswordForm& affiliated_match = *scoped_affiliated_match;
+ PasswordForm affiliated_match;
affiliated_match.origin = GURL("android://hash@foo1.com/");
affiliated_match.username_value = ASCIIToUTF16("test2@gmail.com");
affiliated_match.password_value = ASCIIToUTF16("test");
affiliated_match.is_affiliation_based_match = true;
affiliated_match.signon_realm = "https://foo1.com/";
- affiliated_match.ssl_valid = true;
affiliated_match.preferred = false;
affiliated_match.scheme = PasswordForm::SCHEME_HTML;
// Add one exact match and one affiliation based match.
- PasswordFormMap matches;
- matches.insert(std::make_pair(exact_match.username_value,
- std::move(scoped_exact_match)));
- matches.insert(std::make_pair(affiliated_match.username_value,
- std::move(scoped_affiliated_match)));
+ std::map<base::string16, const PasswordForm*> matches;
+ matches.insert(std::make_pair(exact_match.username_value, &exact_match));
+ matches.insert(
+ std::make_pair(affiliated_match.username_value, &affiliated_match));
PasswordFormFillData result;
InitPasswordFormFillData(form_on_page, matches, &preferred_match, false,
diff --git a/chromium/components/autofill/core/common/password_form_generation_data.h b/chromium/components/autofill/core/common/password_form_generation_data.h
index 38910c904f3..d010d9a8ddb 100644
--- a/chromium/components/autofill/core/common/password_form_generation_data.h
+++ b/chromium/components/autofill/core/common/password_form_generation_data.h
@@ -5,8 +5,11 @@
#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_GENERATION_DATA_H_
#define COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_GENERATION_DATA_H_
+#include <stdint.h>
+
#include "base/strings/string16.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/signatures_util.h"
#include "url/gurl.h"
namespace autofill {
@@ -14,15 +17,13 @@ namespace autofill {
// Structure used for sending information from browser to renderer about on
// which fields password should be generated.
struct PasswordFormGenerationData {
- // The name of the form.
- base::string16 name;
-
- // The action target of the form; this URL consists of the scheme, host, port
- // and path; the rest is stripped.
- GURL action;
+ // The unique signature of form where password should be generated
+ // (see components/autofill/core/browser/form_structure.h).
+ FormSignature form_signature;
- // Field in which password should be generated.
- FormFieldData generation_field;
+ // The unique signature of field where password should be generated
+ // (see components/autofill/core/browser/autofill_field.h).
+ FieldSignature field_signature;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.cc b/chromium/components/autofill/core/common/save_password_progress_logger.cc
index 1c13e464e66..5a5fe7681c2 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.cc
@@ -25,25 +25,11 @@ namespace autofill {
namespace {
-// Removes privacy sensitive parts of |url| (currently all but host and scheme).
-std::string ScrubURL(const GURL& url) {
- if (url.is_valid())
- return url.GetWithEmptyPath().spec();
- return std::string();
-}
-
// Returns true for all characters which we don't want to see in the logged IDs
// or names of HTML elements.
bool IsUnwantedInElementID(char c) {
- return !(c == '_' || c == '-' ||
- base::IsAsciiAlpha(c) || base::IsAsciiDigit(c));
-}
-
-// The UTF-8 version of SavePasswordProgressLogger::ScrubElementID.
-std::string ScrubElementID8Bit(std::string element_id) {
- std::replace_if(
- element_id.begin(), element_id.end(), IsUnwantedInElementID, ' ');
- return base::ToLowerASCII(element_id);
+ return !(c == '_' || c == '-' || base::IsAsciiAlpha(c) ||
+ base::IsAsciiDigit(c));
}
SavePasswordProgressLogger::StringID FormSchemeToStringID(
@@ -66,11 +52,9 @@ SavePasswordProgressLogger::StringID FormSchemeToStringID(
} // namespace
-SavePasswordProgressLogger::SavePasswordProgressLogger() {
-}
+SavePasswordProgressLogger::SavePasswordProgressLogger() {}
-SavePasswordProgressLogger::~SavePasswordProgressLogger() {
-}
+SavePasswordProgressLogger::~SavePasswordProgressLogger() {}
void SavePasswordProgressLogger::LogPasswordForm(
SavePasswordProgressLogger::StringID label,
@@ -90,7 +74,6 @@ void SavePasswordProgressLogger::LogPasswordForm(
ScrubElementID(form.password_element));
log.SetString(GetStringFromID(STRING_NEW_PASSWORD_ELEMENT),
ScrubElementID(form.new_password_element));
- log.SetBoolean(GetStringFromID(STRING_SSL_VALID), form.ssl_valid);
log.SetBoolean(GetStringFromID(STRING_PASSWORD_GENERATED),
form.type == PasswordForm::TYPE_GENERATED);
log.SetInteger(GetStringFromID(STRING_TIMES_USED), form.times_used);
@@ -104,8 +87,7 @@ void SavePasswordProgressLogger::LogHTMLForm(
const std::string& name_or_id,
const GURL& action) {
DictionaryValue log;
- log.SetString(GetStringFromID(STRING_NAME_OR_ID),
- ScrubElementID8Bit(name_or_id));
+ log.SetString(GetStringFromID(STRING_NAME_OR_ID), ScrubElementID(name_or_id));
log.SetString(GetStringFromID(STRING_ACTION), ScrubURL(action));
LogValue(label, log);
}
@@ -140,6 +122,13 @@ void SavePasswordProgressLogger::LogMessage(
LogValue(STRING_MESSAGE, StringValue(GetStringFromID(message)));
}
+// static
+std::string SavePasswordProgressLogger::ScrubURL(const GURL& url) {
+ if (url.is_valid())
+ return url.GetWithEmptyPath().spec();
+ return std::string();
+}
+
void SavePasswordProgressLogger::LogValue(StringID label, const Value& log) {
std::string log_string;
bool conversion_to_string_successful = base::JSONWriter::WriteWithOptions(
@@ -151,7 +140,14 @@ void SavePasswordProgressLogger::LogValue(StringID label, const Value& log) {
// static
std::string SavePasswordProgressLogger::ScrubElementID(
const base::string16& element_id) {
- return ScrubElementID8Bit(base::UTF16ToUTF8(element_id));
+ return ScrubElementID(base::UTF16ToUTF8(element_id));
+}
+
+// static
+std::string SavePasswordProgressLogger::ScrubElementID(std::string element_id) {
+ std::replace_if(element_id.begin(), element_id.end(), IsUnwantedInElementID,
+ ' ');
+ return element_id;
}
// Note 1: Caching the ID->string map in an array would be probably faster, but
@@ -197,8 +193,6 @@ std::string SavePasswordProgressLogger::GetStringFromID(
return "Password element";
case SavePasswordProgressLogger::STRING_NEW_PASSWORD_ELEMENT:
return "New password element";
- case SavePasswordProgressLogger::STRING_SSL_VALID:
- return "SSL valid";
case SavePasswordProgressLogger::STRING_PASSWORD_GENERATED:
return "Password generated";
case SavePasswordProgressLogger::STRING_TIMES_USED:
@@ -312,16 +306,16 @@ std::string SavePasswordProgressLogger::GetStringFromID(
return "wait_for_username";
case SavePasswordProgressLogger::STRING_LOGINMODELOBSERVER_PRESENT:
return "Instances of LoginModelObserver may be present";
- case
- SavePasswordProgressLogger::STRING_WAS_LAST_NAVIGATION_HTTP_ERROR_METHOD:
+ case SavePasswordProgressLogger::
+ STRING_WAS_LAST_NAVIGATION_HTTP_ERROR_METHOD:
return "ChromePasswordManagerClient::WasLastNavigationHTTPError";
case SavePasswordProgressLogger::STRING_HTTP_STATUS_CODE:
return "HTTP status code for landing page";
- case
- SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVED_FORM_IS_NOT_HTML:
+ case SavePasswordProgressLogger::
+ STRING_PROVISIONALLY_SAVED_FORM_IS_NOT_HTML:
return "Provisionally saved form is not HTML";
- case SavePasswordProgressLogger::STRING_ON_REQUEST_DONE_METHOD:
- return "PasswordFormManager::OnRequestDone";
+ case SavePasswordProgressLogger::STRING_PROCESS_MATCHES_METHOD:
+ return "PasswordFormManager::ProcessMatches";
case SavePasswordProgressLogger::STRING_BEST_SCORE:
return "best_score";
case SavePasswordProgressLogger::STRING_ON_GET_STORE_RESULTS_METHOD:
@@ -352,11 +346,11 @@ std::string SavePasswordProgressLogger::GetStringFromID(
case SavePasswordProgressLogger::STRING_PROCESS_FRAME_METHOD:
return "PasswordFormManager::ProcessFrame";
case SavePasswordProgressLogger::STRING_FORM_SIGNATURE:
- return "Signature of form, followed by field signatures";
+ return "Signature of form";
case SavePasswordProgressLogger::STRING_FORM_MANAGER_STATE:
return "PasswordFormManager::state_";
case SavePasswordProgressLogger::STRING_ADDING_SIGNATURE:
- return "Adding manager for form with this signature";
+ return "Adding manager for form";
case SavePasswordProgressLogger::STRING_UNOWNED_INPUTS_VISIBLE:
return "Some control elements not associated to a form element are "
"visible";
@@ -387,6 +381,10 @@ std::string SavePasswordProgressLogger::GetStringFromID(
return "Filled username element named";
case SavePasswordProgressLogger::STRING_PASSWORD_FILLED:
return "Filled password element named";
+ case SavePasswordProgressLogger::STRING_FORM_NAME:
+ return "Form name";
+ case SavePasswordProgressLogger::STRING_FIELDS:
+ return "Form fields";
case SavePasswordProgressLogger::STRING_INVALID:
return "INVALID";
// Intentionally no default: clause here -- all IDs need to get covered.
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.h b/chromium/components/autofill/core/common/save_password_progress_logger.h
index 4407c11dd22..f31bf6dbdac 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.h
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.h
@@ -53,7 +53,6 @@ class SavePasswordProgressLogger {
STRING_USERNAME_ELEMENT,
STRING_PASSWORD_ELEMENT,
STRING_NEW_PASSWORD_ELEMENT,
- STRING_SSL_VALID,
STRING_PASSWORD_GENERATED,
STRING_TIMES_USED,
STRING_PSL_MATCH,
@@ -113,7 +112,7 @@ class SavePasswordProgressLogger {
STRING_WAS_LAST_NAVIGATION_HTTP_ERROR_METHOD,
STRING_HTTP_STATUS_CODE,
STRING_PROVISIONALLY_SAVED_FORM_IS_NOT_HTML,
- STRING_ON_REQUEST_DONE_METHOD,
+ STRING_PROCESS_MATCHES_METHOD,
STRING_BEST_SCORE,
STRING_ON_GET_STORE_RESULTS_METHOD,
STRING_NUMBER_RESULTS,
@@ -145,6 +144,8 @@ class SavePasswordProgressLogger {
STRING_MATCH_IN_ADDITIONAL,
STRING_USERNAME_FILLED,
STRING_PASSWORD_FILLED,
+ STRING_FORM_NAME,
+ STRING_FIELDS,
STRING_INVALID, // Represents a string returned in a case of an error.
STRING_MAX = STRING_INVALID
};
@@ -164,6 +165,10 @@ class SavePasswordProgressLogger {
void LogNumber(StringID label, size_t unsigned_number);
void LogMessage(StringID message);
+ // Removes privacy sensitive parts of |url| (currently all but host and
+ // scheme).
+ static std::string ScrubURL(const GURL& url);
+
protected:
// Sends |log| immediately for display.
virtual void SendLog(const std::string& log) = 0;
@@ -171,13 +176,16 @@ class SavePasswordProgressLogger {
// Converts |log| and its |label| to a string and calls SendLog on the result.
void LogValue(StringID label, const base::Value& log);
- // Replaces all characters satisfying IsUnwantedInElementID with a ' ', and
- // lowercases all characters. This damages some valid HTML element IDs
- // or names, but it is likely that it will be still possible to match the
- // scrubbed string to the original ID or name in the HTML doc. That's good
- // enough for the logging purposes, and provides some security benefits.
+ // Replaces all characters satisfying IsUnwantedInElementID with a ' '.
+ // This damages some valid HTML element IDs or names, but it is likely that it
+ // will be still possible to match the scrubbed string to the original ID or
+ // name in the HTML doc. That's good enough for the logging purposes, and
+ // provides some security benefits.
static std::string ScrubElementID(const base::string16& element_id);
+ // The UTF-8 version of the function above.
+ static std::string ScrubElementID(std::string element_id);
+
// Translates the StringID values into the corresponding strings.
static std::string GetStringFromID(SavePasswordProgressLogger::StringID id);
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc b/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
index 96f2b4ca7c5..f047183d414 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
@@ -63,11 +63,11 @@ TEST(SavePasswordProgressLoggerTest, LogPasswordFormElementID) {
TestLogger logger;
PasswordForm form;
const std::string kHTMLInside("Username <script> element");
- const std::string kHTMLInsideExpected("username script element");
+ const std::string kHTMLInsideExpected("Username script element");
const std::string kIPAddressInside("y128.0.0.1Y");
- const std::string kIPAddressInsideExpected("y128 0 0 1y");
+ const std::string kIPAddressInsideExpected("y128 0 0 1Y");
const std::string kSpecialCharsInside("X@#a$%B&*c()D;:e+!x");
- const std::string kSpecialCharsInsideExpected("x a b c d e x");
+ const std::string kSpecialCharsInsideExpected("X a B c D e x");
form.username_element = UTF8ToUTF16(kHTMLInside);
form.password_element = UTF8ToUTF16(kIPAddressInside);
form.new_password_element = UTF8ToUTF16(kSpecialCharsInside);
diff --git a/chromium/components/autofill/core/common/signatures_util.cc b/chromium/components/autofill/core/common/signatures_util.cc
new file mode 100644
index 00000000000..8e7695eac75
--- /dev/null
+++ b/chromium/components/autofill/core/common/signatures_util.cc
@@ -0,0 +1,107 @@
+// 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 "components/autofill/core/common/signatures_util.h"
+
+#include "base/sha1.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/autofill_util.h"
+#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/form_field_data.h"
+#include "third_party/re2/src/re2/re2.h"
+#include "third_party/re2/src/re2/stringpiece.h"
+#include "url/gurl.h"
+
+namespace autofill {
+
+namespace {
+
+// Strip away >= 5 consecutive digits.
+const char kIgnorePatternInFieldName[] = "\\d{5,}";
+
+// Returns a copy of |input| without all occurrences of
+// |kIgnorePatternInFieldName|
+std::string StripDigitsIfRequired(const base::string16& input) {
+ std::string return_string = base::UTF16ToUTF8(input);
+ re2::RE2::GlobalReplace(&return_string, re2::RE2(kIgnorePatternInFieldName),
+ re2::StringPiece());
+ return return_string;
+}
+
+} // namespace
+
+FormSignature CalculateFormSignature(const FormData& form_data) {
+ const GURL& target_url = form_data.action;
+ const GURL& source_url = form_data.origin;
+ std::string scheme(target_url.scheme());
+ std::string host(target_url.host());
+
+ // If target host or scheme is empty, set scheme and host of source url.
+ // This is done to match the Toolbar's behavior.
+ if (scheme.empty() || host.empty()) {
+ scheme = source_url.scheme();
+ host = source_url.host();
+ }
+
+ std::string form_signature_field_names;
+
+ for (const FormFieldData& field : form_data.fields) {
+ if (!ShouldSkipField(field)) {
+ // Add all supported form fields (including with empty names) to the
+ // signature. This is a requirement for Autofill servers.
+ form_signature_field_names.append("&");
+ form_signature_field_names.append(StripDigitsIfRequired(field.name));
+ }
+ }
+
+ std::string form_string = scheme + "://" + host + "&" +
+ base::UTF16ToUTF8(form_data.name) +
+ form_signature_field_names;
+
+ return StrToHash64Bit(form_string);
+}
+
+FieldSignature CalculateFieldSignatureByNameAndType(
+ const base::string16& field_name,
+ const std::string& field_type) {
+ std::string name = base::UTF16ToUTF8(field_name);
+ std::string field_string = name + "&" + field_type;
+ return StrToHash32Bit(field_string);
+}
+
+FieldSignature CalculateFieldSignatureForField(
+ const FormFieldData& field_data) {
+ return CalculateFieldSignatureByNameAndType(field_data.name,
+ field_data.form_control_type);
+}
+
+uint64_t StrToHash64Bit(const std::string& str) {
+ std::string hash_bin = base::SHA1HashString(str);
+ DCHECK_EQ(base::kSHA1Length, hash_bin.length());
+
+ uint64_t hash64 = (((static_cast<uint64_t>(hash_bin[0])) & 0xFF) << 56) |
+ (((static_cast<uint64_t>(hash_bin[1])) & 0xFF) << 48) |
+ (((static_cast<uint64_t>(hash_bin[2])) & 0xFF) << 40) |
+ (((static_cast<uint64_t>(hash_bin[3])) & 0xFF) << 32) |
+ (((static_cast<uint64_t>(hash_bin[4])) & 0xFF) << 24) |
+ (((static_cast<uint64_t>(hash_bin[5])) & 0xFF) << 16) |
+ (((static_cast<uint64_t>(hash_bin[6])) & 0xFF) << 8) |
+ ((static_cast<uint64_t>(hash_bin[7])) & 0xFF);
+
+ return hash64;
+}
+
+uint32_t StrToHash32Bit(const std::string& str) {
+ std::string hash_bin = base::SHA1HashString(str);
+ DCHECK_EQ(base::kSHA1Length, hash_bin.length());
+
+ uint32_t hash32 = ((hash_bin[0] & 0xFF) << 24) |
+ ((hash_bin[1] & 0xFF) << 16) | ((hash_bin[2] & 0xFF) << 8) |
+ (hash_bin[3] & 0xFF);
+
+ return hash32;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/common/signatures_util.h b/chromium/components/autofill/core/common/signatures_util.h
new file mode 100644
index 00000000000..15be6ae2107
--- /dev/null
+++ b/chromium/components/autofill/core/common/signatures_util.h
@@ -0,0 +1,43 @@
+// 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 COMPONENTS_AUTOFILL_CORE_COMMON_SIGNATURES_UTIL_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_SIGNATURES_UTIL_H_
+
+#include <stddef.h>
+
+#include <stdint.h>
+#include <string>
+
+#include "base/strings/string16.h"
+
+namespace autofill {
+
+struct FormData;
+struct FormFieldData;
+
+using FormSignature = uint64_t;
+using FieldSignature = uint32_t;
+
+// Calculates form signature based on |form_data|.
+FormSignature CalculateFormSignature(const FormData& form_data);
+
+// Calculates field signature based on |field_name| and |field_type|.
+FieldSignature CalculateFieldSignatureByNameAndType(
+ const base::string16& field_name,
+ const std::string& field_type);
+
+// Calculates field signature based on |field_data|. This function is a proxy to
+// |CalculateFieldSignatureByNameAndType|.
+FieldSignature CalculateFieldSignatureForField(const FormFieldData& field_data);
+
+// Returns 64-bit hash of the string.
+uint64_t StrToHash64Bit(const std::string& str);
+
+// Returns 32-bit hash of the string.
+uint32_t StrToHash32Bit(const std::string& str);
+
+}
+
+#endif // COMPONENTS_AUTOFILL_CORE_COMMON_SIGNATURES_UTIL_H_
diff --git a/chromium/components/autofill/ios/browser/js_autofill_manager.h b/chromium/components/autofill/ios/browser/js_autofill_manager.h
index a1a797a941f..6b957ca71e8 100644
--- a/chromium/components/autofill/ios/browser/js_autofill_manager.h
+++ b/chromium/components/autofill/ios/browser/js_autofill_manager.h
@@ -23,17 +23,8 @@
completionHandler:
(void (^)(NSString*))completionHandler;
-// Stores the current active element. This is used to make the element active
-// again in case the web view loses focus when a dialog is presented over it.
-- (void)storeActiveElement;
-
-// Clears the current active element.
-- (void)clearActiveElement;
-
// Fills the data in JSON string |dataString| into the active form field, then
-// executes the |completionHandler|. The active form field is either
-// document.activeElement or the field stored by a call to storeActiveElement.
-// non-null.
+// executes the |completionHandler|.
- (void)fillActiveFormField:(NSString*)dataString
completionHandler:(ProceduralBlock)completionHandler;
diff --git a/chromium/components/autofill/ios/browser/js_autofill_manager.mm b/chromium/components/autofill/ios/browser/js_autofill_manager.mm
index 84d5a7235d8..96e15c90734 100644
--- a/chromium/components/autofill/ios/browser/js_autofill_manager.mm
+++ b/chromium/components/autofill/ios/browser/js_autofill_manager.mm
@@ -7,6 +7,7 @@
#include "base/format_macros.h"
#include "base/json/string_escape.h"
#include "base/logging.h"
+#include "base/mac/foundation_util.h"
@implementation JsAutofillManager
@@ -17,10 +18,10 @@
NSString* extractFormsJS = [NSString
stringWithFormat:@"__gCrWeb.autofill.extractForms(%" PRIuNS ");",
requiredFieldsCount];
- [self evaluate:extractFormsJS
- stringResultHandler:^(NSString* result, NSError*) {
- completionHandler(result);
- }];
+ [self executeJavaScript:extractFormsJS
+ completionHandler:^(id result, NSError*) {
+ completionHandler(base::mac::ObjCCastStrict<NSString>(result));
+ }];
}
#pragma mark -
@@ -30,30 +31,14 @@
return @"autofill_controller";
}
-- (NSString*)presenceBeacon {
- return @"__gCrWeb.autofill";
-}
-
-- (void)storeActiveElement {
- NSString* js = @"__gCrWeb.autofill.storeActiveElement()";
- [self evaluate:js stringResultHandler:nil];
-}
-
-- (void)clearActiveElement {
- NSString* js = @"__gCrWeb.autofill.clearActiveElement()";
- [self evaluate:js stringResultHandler:nil];
-}
-
- (void)fillActiveFormField:(NSString*)dataString
completionHandler:(ProceduralBlock)completionHandler {
- web::JavaScriptCompletion resultHandler = ^void(NSString*, NSError*) {
- completionHandler();
- };
-
- NSString* js =
+ NSString* script =
[NSString stringWithFormat:@"__gCrWeb.autofill.fillActiveFormField(%@);",
dataString];
- [self evaluate:js stringResultHandler:resultHandler];
+ [self executeJavaScript:script completionHandler:^(id, NSError*) {
+ completionHandler();
+ }];
}
- (void)fillForm:(NSString*)dataString
@@ -67,31 +52,28 @@
NSString* fillFormJS =
[NSString stringWithFormat:@"__gCrWeb.autofill.fillForm(%@, %s);",
dataString, fieldName.c_str()];
- id stringResultHandler = ^(NSString*, NSError*) {
+ [self executeJavaScript:fillFormJS completionHandler:^(id, NSError*) {
completionHandler();
- };
- return [self evaluate:fillFormJS stringResultHandler:stringResultHandler];
+ }];
}
- (void)clearAutofilledFieldsForFormNamed:(NSString*)formName
completionHandler:(ProceduralBlock)completionHandler {
DCHECK(completionHandler);
- web::JavaScriptCompletion resultHandler = ^void(NSString*, NSError*) {
- completionHandler();
- };
-
- NSString* js =
+ NSString* script =
[NSString stringWithFormat:
@"__gCrWeb.autofill.clearAutofilledFields(%s);",
base::GetQuotedJSONString([formName UTF8String]).c_str()];
- [self evaluate:js stringResultHandler:resultHandler];
+ [self executeJavaScript:script completionHandler:^(id, NSError*) {
+ completionHandler();
+ }];
}
- (void)fillPredictionData:(NSString*)dataString {
- [self deferredEvaluate:
- [NSString
- stringWithFormat:@"__gCrWeb.autofill.fillPredictionData(%@);",
- dataString]];
+ NSString* script =
+ [NSString stringWithFormat:@"__gCrWeb.autofill.fillPredictionData(%@);",
+ dataString];
+ [self executeJavaScript:script completionHandler:nil];
}
@end
diff --git a/chromium/components/autofill/ios/browser/js_suggestion_manager.mm b/chromium/components/autofill/ios/browser/js_suggestion_manager.mm
index 829df6952a7..1d415ce1a49 100644
--- a/chromium/components/autofill/ios/browser/js_suggestion_manager.mm
+++ b/chromium/components/autofill/ios/browser/js_suggestion_manager.mm
@@ -27,10 +27,6 @@ NSString* JSONEscape(NSString* str) {
return @"suggestion_controller";
}
-- (NSString*)presenceBeacon {
- return @"__gCrWeb.suggestion";
-}
-
- (void)selectNextElement {
[self selectElementAfterForm:@"" field:@""];
}
@@ -39,7 +35,7 @@ NSString* JSONEscape(NSString* str) {
NSString* selectNextElementJS = [NSString
stringWithFormat:@"__gCrWeb.suggestion.selectNextElement(%@, %@)",
JSONEscape(formName), JSONEscape(fieldName)];
- [self evaluate:selectNextElementJS stringResultHandler:nil];
+ [self executeJavaScript:selectNextElementJS completionHandler:nil];
}
- (void)selectPreviousElement {
@@ -50,7 +46,7 @@ NSString* JSONEscape(NSString* str) {
NSString* selectPreviousElementJS = [NSString
stringWithFormat:@"__gCrWeb.suggestion.selectPreviousElement(%@, %@)",
JSONEscape(formName), JSONEscape(fieldName)];
- [self evaluate:selectPreviousElementJS stringResultHandler:nil];
+ [self executeJavaScript:selectPreviousElementJS completionHandler:nil];
}
- (void)fetchPreviousAndNextElementsPresenceWithCompletionHandler:
@@ -66,7 +62,15 @@ NSString* JSONEscape(NSString* str) {
(void (^)(BOOL, BOOL))completionHandler {
DCHECK(completionHandler);
DCHECK([self hasBeenInjected]);
- id stringResultHandler = ^(NSString* result, NSError* error) {
+ NSString* escapedFormName = JSONEscape(formName);
+ NSString* escapedFieldName = JSONEscape(fieldName);
+ NSString* JS = [NSString
+ stringWithFormat:@"[__gCrWeb.suggestion.hasPreviousElement(%@, %@),"
+ @"__gCrWeb.suggestion.hasNextElement(%@, %@)]"
+ @".toString()",
+ escapedFormName, escapedFieldName, escapedFormName,
+ escapedFieldName];
+ [self executeJavaScript:JS completionHandler:^(id result, NSError* error) {
// The result maybe an empty string here due to 2 reasons:
// 1) When there is an exception running the JS
// 2) There is a race when the page is changing due to which
@@ -89,22 +93,12 @@ NSString* JSONEscape(NSString* str) {
[components[1] isEqualToString:@"false"]);
BOOL hasNextElement = [components[1] isEqualToString:@"true"];
completionHandler(hasPreviousElement, hasNextElement);
- };
- NSString* escapedFormName = JSONEscape(formName);
- NSString* escapedFieldName = JSONEscape(fieldName);
- NSString* js = [NSString
- stringWithFormat:@"[__gCrWeb.suggestion.hasPreviousElement(%@, %@),"
- @"__gCrWeb.suggestion.hasNextElement(%@, %@)]"
- @".toString()",
- escapedFormName, escapedFieldName, escapedFormName,
- escapedFieldName];
- [self evaluate:js stringResultHandler:stringResultHandler];
+ }];
}
- (void)closeKeyboard {
- // Deferred execution used because of a risk of crwebinvoke:// triggered
- // immediately by the loss of focus.
- [self deferredEvaluate:@"document.activeElement.blur()"];
+ [self executeJavaScript:@"document.activeElement.blur()"
+ completionHandler:nil];
}
@end
diff --git a/chromium/components/autofill/ios/browser/resources/autofill_controller.js b/chromium/components/autofill/ios/browser/resources/autofill_controller.js
index a7600892fa6..510a9309cbd 100644
--- a/chromium/components/autofill/ios/browser/resources/autofill_controller.js
+++ b/chromium/components/autofill/ios/browser/resources/autofill_controller.js
@@ -43,6 +43,9 @@ var AutofillFormFieldData;
*/
var AutofillFormData;
+/* Beginning of anonymous object. */
+(function() {
+
/**
* Namespace for this file. It depends on |__gCrWeb| having already been
* injected.
@@ -71,7 +74,7 @@ __gCrWeb.autofill.MAX_DATA_LENGTH = 1024;
*
* @const {number}
*/
-__gCrWeb.autofill.MAX_PARSEABLE_FIELDS = 100;
+__gCrWeb.autofill.MAX_PARSEABLE_FIELDS = 200;
/**
* A bit field mask to extract data from WebFormControlElement for
@@ -137,13 +140,6 @@ __gCrWeb.autofill.ROLE_ATTRIBUTE_PRESENTATION = 0;
__gCrWeb.autofill.lastAutoFilledElement = null;
/**
- * The last element that was active (used to restore focus if necessary).
- *
- * @type {Element}
- */
-__gCrWeb.autofill.lastActiveElement = null;
-
-/**
* Whether CSS for autofilled elements has been injected into the page.
*
* @type {boolean}
@@ -269,7 +265,7 @@ function getUnownedAutofillableFormFieldElements_(elements, fieldsets) {
if (__gCrWeb.autofill.hasTagName(elements[i], 'fieldset') &&
!isElementInsideFormOrFieldSet(elements[i])) {
- fieldset.push(elements[i]);
+ fieldsets.push(elements[i]);
}
}
return __gCrWeb.autofill.extractAutofillableElementsFromSet(
@@ -556,34 +552,12 @@ __gCrWeb.autofill['extractForms'] = function(requiredFields) {
};
/**
- * Stores the current active element. This is used to make the element active
- * again in case the web view loses focus when a dialog is presented over it.
- */
-__gCrWeb.autofill['storeActiveElement'] = function() {
- __gCrWeb.autofill.lastActiveElement = document.activeElement;
-}
-
-/**
- * Clears the current active element by setting it to null.
- */
-__gCrWeb.autofill['clearActiveElement'] = function() {
- __gCrWeb.autofill.lastActiveElement = null;
-}
-
-/**
- * Fills data into the active form field. The active form field is either
- * document.activeElement or the value of lastActiveElement if that value is
- * non-null.
+ * Fills data into the active form field.
*
* @param {AutofillFormFieldData} data The data to fill in.
*/
__gCrWeb.autofill['fillActiveFormField'] = function(data) {
var activeElement = document.activeElement;
- if (__gCrWeb.autofill.lastActiveElement) {
- activeElement = __gCrWeb.autofill.lastActiveElement;
- activeElement.focus();
- __gCrWeb.autofill.lastActiveElement = null;
- }
if (data['name'] !== __gCrWeb['common'].nameForAutofill(activeElement)) {
return;
}
@@ -2091,3 +2065,5 @@ __gCrWeb.autofill['fillPredictionData'] = function(data) {
}
}
};
+
+}()); // End of anonymous object
diff --git a/chromium/components/autofill/ios/browser/resources/suggestion_controller.js b/chromium/components/autofill/ios/browser/resources/suggestion_controller.js
index abc088af5d1..69b830143a0 100644
--- a/chromium/components/autofill/ios/browser/resources/suggestion_controller.js
+++ b/chromium/components/autofill/ios/browser/resources/suggestion_controller.js
@@ -4,6 +4,9 @@
// Installs suggestion management functions on the |__gCrWeb| object.
+/* Beginning of anonymous object. */
+(function() {
+
/**
* Namespace for this file. It depends on |__gCrWeb| having already been
* injected.
@@ -313,3 +316,5 @@ __gCrWeb.suggestion['hasPreviousElement'] = function(formName, fieldName) {
return __gCrWeb.suggestion.getPreviousElementInTabOrder(
currentElement, document.all) !== null;
};
+
+}()); // End of anonymous object
diff --git a/chromium/components/autofill_strings.grdp b/chromium/components/autofill_strings.grdp
index 6b8da3c1ae6..ab8667f35e7 100644
--- a/chromium/components/autofill_strings.grdp
+++ b/chromium/components/autofill_strings.grdp
@@ -20,6 +20,9 @@
<message name="IDS_AUTOFILL_WARNING_INSECURE_CONNECTION" desc="Warning text to show when credit card autofill is disabled because the website is not using a secure connection.">
Automatic credit card filling is disabled because this form does not use a secure connection.
</message>
+ <message name="IDS_AUTOFILL_CREDIT_CARD_SIGNIN_PROMO" desc="Promo text shown alongside credit card suggestions to get people to sign in.">
+ To use cards from your Google Account, sign in to Chrome
+ </message>
<if expr="_google_chrome">
<message name="IDS_AUTOFILL_DELETE_AUTOCOMPLETE_SUGGESTION_CONFIRMATION_BODY" desc="Text in a dialog to confirm that the user wants to delete an autocomplete form history suggestion.">
Remove form suggestion from Chrome?
@@ -163,7 +166,7 @@
</message>
</if>
- <message name="IDS_AUTOFILL_SCAN_CREDIT_CARD" desc="An item in the autofill popup that triggers a new credit card to be scanned using the camera on the device.">
+ <message name="IDS_AUTOFILL_SCAN_CREDIT_CARD" desc="An item in the autofill popup that triggers a new credit card to be scanned using the camera on the device." formatter_data="android_java">
Scan new card
</message>
@@ -171,13 +174,27 @@
Use password for:
</message>
+ <!-- Autofill Credit Card Assisted Filling Infobar -->
+ <if expr="is_android">
+ <message name="IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_TITLE" desc="Title text for the Autofill Credit Card Assisted Filling Infobar">
+ Do you want to fill in your card info?
+ </message>
+ </if>
+ <if expr="is_ios">
+ <message name="IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_FORMATTED_TITLE" desc="Title text for the Autofill Credit Card Assisted Filling Infobar, which contains the card description in it.">
+ Do you want to fill in your <ph name="CARD_DETAIL">$1<ex>Visa - 1234</ex></ph>?
+ </message>
+ </if>
+ <if expr="is_android or is_ios">
+ <message name="IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_ACCEPT" desc="Text to show for the Autofill credit card Assisted Filling infobar accept button.">
+ Fill in
+ </message>
+ </if>
+
<!-- Autofill save credit card bubble or infobar prompt -->
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT" desc="Text to show for the Autofill save credit card prompt accept button. The prompt can be either a bubble or an infobar.">
Save
</message>
- <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_DENY" desc="Text to show for the Autofill save credit card prompt deny button. The prompt can be either a bubble or an infobar.">
- No thanks
- </message>
<if expr="_google_chrome">
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save card prompt when the card is to be saved locally. The prompt can be either a bubble or an infobar.">
Do you want Chrome to save this card?
diff --git a/chromium/components/base32.gypi b/chromium/components/base32.gypi
deleted file mode 100644
index 1e26737cf76..00000000000
--- a/chromium/components/base32.gypi
+++ /dev/null
@@ -1,23 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/base32
- 'target_name': 'base32',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'base32/base32.h',
- 'base32/base32.cc',
- ],
- }
- ],
-}
diff --git a/chromium/components/base32/BUILD.gn b/chromium/components/base32/BUILD.gn
index 78136044798..3e53a3f72fd 100644
--- a/chromium/components/base32/BUILD.gn
+++ b/chromium/components/base32/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("base32") {
+static_library("base32") {
sources = [
"base32.cc",
"base32.h",
diff --git a/chromium/components/bitmap_uploader/BUILD.gn b/chromium/components/bitmap_uploader/BUILD.gn
deleted file mode 100644
index 8a0b80425c8..00000000000
--- a/chromium/components/bitmap_uploader/BUILD.gn
+++ /dev/null
@@ -1,21 +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.
-
-component("bitmap_uploader") {
- sources = [
- "bitmap_uploader.cc",
- "bitmap_uploader.h",
- ]
-
- defines = [
- "BITMAP_UPLOADER_IMPLEMENTATION",
- "GL_GLEXT_PROTOTYPES",
- ]
-
- deps = [
- "//base",
- "//components/mus/public/cpp",
- "//components/mus/public/interfaces",
- ]
-}
diff --git a/chromium/components/bitmap_uploader/DEPS b/chromium/components/bitmap_uploader/DEPS
deleted file mode 100644
index f9f9262a07c..00000000000
--- a/chromium/components/bitmap_uploader/DEPS
+++ /dev/null
@@ -1,9 +0,0 @@
-include_rules = [
- "+cc/ipc",
- "+cc/quads",
- "+components/mus/public",
- "+gpu/GLES2",
- "+mojo/common",
- "+mojo/public",
- "+ui/gfx/geometry",
-]
diff --git a/chromium/components/bitmap_uploader/OWNERS b/chromium/components/bitmap_uploader/OWNERS
deleted file mode 100644
index bb698f32fbb..00000000000
--- a/chromium/components/bitmap_uploader/OWNERS
+++ /dev/null
@@ -1,11 +0,0 @@
-ben@chromium.org
-erg@chromium.org
-fsamuel@chromium.org
-jam@chromium.org
-jochen@chromium.org
-msw@chromium.org
-penghuang@chromium.org
-rjkroege@chromium.org
-sadrul@chromium.org
-sky@chromium.org
-yzshen@chromium.org
diff --git a/chromium/components/bitmap_uploader/bitmap_uploader.cc b/chromium/components/bitmap_uploader/bitmap_uploader.cc
deleted file mode 100644
index 8650a9547be..00000000000
--- a/chromium/components/bitmap_uploader/bitmap_uploader.cc
+++ /dev/null
@@ -1,210 +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 "components/bitmap_uploader/bitmap_uploader.h"
-
-#include <stddef.h>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "cc/ipc/compositor_frame.mojom.h"
-#include "cc/quads/render_pass.h"
-#include "cc/quads/solid_color_draw_quad.h"
-#include "cc/quads/texture_draw_quad.h"
-#include "components/mus/public/cpp/gles2_context.h"
-#include "components/mus/public/cpp/window.h"
-#include "components/mus/public/cpp/window_surface.h"
-
-namespace bitmap_uploader {
-namespace {
-
-const uint32_t g_transparent_color = 0x00000000;
-
-} // namespace
-
-const char kBitmapUploaderForAcceleratedWidget[] =
- "__BITMAP_UPLOADER_ACCELERATED_WIDGET__";
-
-BitmapUploader::BitmapUploader(mus::Window* window)
- : window_(window),
- color_(g_transparent_color),
- width_(0),
- height_(0),
- format_(BGRA),
- next_resource_id_(1u),
- id_namespace_(0u) {}
-
-BitmapUploader::~BitmapUploader() {
-}
-
-void BitmapUploader::Init(shell::Connector* connector) {
- surface_ = window_->RequestSurface(mus::mojom::SurfaceType::DEFAULT);
- surface_->BindToThread();
- surface_->set_client(this);
-
- gles2_context_ = mus::GLES2Context::CreateOffscreenContext(
- std::vector<int32_t>(), connector);
- // CreateOffscreenContext() may return null.
-}
-
-// Sets the color which is RGBA.
-void BitmapUploader::SetColor(uint32_t color) {
- if (color_ == color)
- return;
- color_ = color;
- if (surface_)
- Upload();
-}
-
-// Sets a bitmap.
-void BitmapUploader::SetBitmap(int width,
- int height,
- std::unique_ptr<std::vector<unsigned char>> data,
- Format format) {
- width_ = width;
- height_ = height;
- bitmap_ = std::move(data);
- format_ = format;
- if (surface_)
- Upload();
-}
-
-void BitmapUploader::Upload() {
- if (!gles2_context_)
- return;
-
- const gfx::Rect bounds(window_->bounds().size());
-
- cc::CompositorFrame frame;
- // TODO(rjkroege): Support device scale factors other than 1.
- frame.metadata.device_scale_factor = 1.0f;
- frame.delegated_frame_data.reset(new cc::DelegatedFrameData());
- frame.delegated_frame_data->resource_list.resize(0u);
-
- const cc::RenderPassId render_pass_id(1, 1);
- std::unique_ptr<cc::RenderPass> pass = cc::RenderPass::Create();
- pass->SetAll(render_pass_id, bounds, bounds, gfx::Transform(),
- true /* has_transparent_background */);
-
- // The SharedQuadState is owned by the SharedQuadStateList
- // shared_quad_state_list.
- cc::SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
- sqs->SetAll(gfx::Transform(), bounds.size(), bounds, bounds,
- false /* is_clipped */, 1.f /* opacity */, SkXfermode::kSrc_Mode,
- 0 /* sorting_context_id */);
-
- if (bitmap_.get()) {
- gpu::gles2::GLES2Interface* gl = gles2_context_->interface();
- gfx::Size bitmap_size(width_, height_);
- GLuint texture_id = BindTextureForSize(bitmap_size);
- gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap_size.width(),
- bitmap_size.height(), TextureFormat(), GL_UNSIGNED_BYTE,
- &((*bitmap_)[0]));
-
- gpu::Mailbox mailbox;
- gl->GenMailboxCHROMIUM(mailbox.name);
- gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
-
- const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM();
- gl->ShallowFlushCHROMIUM();
-
- gpu::SyncToken sync_token;
- gl->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
-
- cc::TransferableResource resource;
- resource.id = next_resource_id_++;
- resource_to_texture_id_map_[resource.id] = texture_id;
- resource.format = cc::ResourceFormat::RGBA_8888;
- resource.filter = GL_LINEAR;
- resource.size = bitmap_size;
- resource.mailbox_holder =
- gpu::MailboxHolder(mailbox, sync_token, GL_TEXTURE_2D);
- resource.read_lock_fences_enabled = false;
- resource.is_software = false;
- resource.is_overlay_candidate = false;
- frame.delegated_frame_data->resource_list.push_back(std::move(resource));
-
- cc::TextureDrawQuad* quad =
- pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
-
- gfx::Size rect_size;
- if (width_ <= bounds.width() && height_ <= bounds.height()) {
- rect_size.SetSize(width_, height_);
- } else {
- // The source bitmap is larger than the viewport. Resize it while
- // maintaining the aspect ratio.
- float width_ratio = static_cast<float>(width_) / bounds.width();
- float height_ratio = static_cast<float>(height_) / bounds.height();
- if (width_ratio > height_ratio) {
- rect_size.SetSize(bounds.width(), height_ / width_ratio);
- } else {
- rect_size.SetSize(width_ / height_ratio, bounds.height());
- }
- }
- gfx::Rect rect(rect_size);
- const bool needs_blending = true;
- const bool premultiplied_alpha = true;
- const gfx::PointF uv_top_left(0.f, 0.f);
- const gfx::PointF uv_bottom_right(1.f, 1.f);
- float vertex_opacity[4] = {1.f, 1.f, 1.f, 1.f};
- const bool y_flipped = false;
- const bool nearest_neighbor = false;
- quad->SetAll(sqs, rect, rect, rect, needs_blending, resource.id,
- gfx::Size(), premultiplied_alpha, uv_top_left, uv_bottom_right,
- g_transparent_color, vertex_opacity, y_flipped,
- nearest_neighbor, false);
- }
-
- if (color_ != g_transparent_color) {
- cc::SolidColorDrawQuad* quad =
- pass->CreateAndAppendDrawQuad<cc::SolidColorDrawQuad>();
- const bool force_antialiasing_off = false;
- const gfx::Rect opaque_rect(0, 0, 0, 0);
- const bool needs_blending = true;
- quad->SetAll(sqs, bounds, opaque_rect, bounds, needs_blending, color_,
- force_antialiasing_off);
- }
-
- frame.delegated_frame_data->render_pass_list.push_back(std::move(pass));
-
- // TODO(rjkroege, fsamuel): We should throttle frames.
- surface_->SubmitCompositorFrame(std::move(frame), base::Closure());
-}
-
-uint32_t BitmapUploader::BindTextureForSize(const gfx::Size& size) {
- gpu::gles2::GLES2Interface* gl = gles2_context_->interface();
- // TODO(jamesr): Recycle textures.
- GLuint texture = 0u;
- gl->GenTextures(1, &texture);
- gl->BindTexture(GL_TEXTURE_2D, texture);
- gl->TexImage2D(GL_TEXTURE_2D, 0, TextureFormat(), size.width(), size.height(),
- 0, TextureFormat(), GL_UNSIGNED_BYTE, 0);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- return texture;
-}
-
-void BitmapUploader::SetIdNamespace(uint32_t id_namespace) {
- id_namespace_ = id_namespace;
- if (color_ != g_transparent_color || bitmap_.get())
- Upload();
-}
-
-void BitmapUploader::OnResourcesReturned(
- mus::WindowSurface* surface,
- mojo::Array<cc::ReturnedResource> resources) {
- gpu::gles2::GLES2Interface* gl = gles2_context_->interface();
- // TODO(jamesr): Recycle.
- for (size_t i = 0; i < resources.size(); ++i) {
- cc::ReturnedResource resource = std::move(resources[i]);
- DCHECK_EQ(1, resource.count);
- gl->WaitSyncTokenCHROMIUM(resource.sync_token.GetConstData());
- uint32_t texture_id = resource_to_texture_id_map_[resource.id];
- DCHECK_NE(0u, texture_id);
- resource_to_texture_id_map_.erase(resource.id);
- gl->DeleteTextures(1, &texture_id);
- }
-}
-
-} // namespace bitmap_uploader
diff --git a/chromium/components/bitmap_uploader/bitmap_uploader.h b/chromium/components/bitmap_uploader/bitmap_uploader.h
deleted file mode 100644
index d33bc834045..00000000000
--- a/chromium/components/bitmap_uploader/bitmap_uploader.h
+++ /dev/null
@@ -1,94 +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 COMPONENTS_BITMAP_UPLOADER_BITMAP_UPLOADER_H_
-#define COMPONENTS_BITMAP_UPLOADER_BITMAP_UPLOADER_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/compiler_specific.h"
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "components/bitmap_uploader/bitmap_uploader_export.h"
-#include "components/mus/public/cpp/window_surface.h"
-#include "components/mus/public/cpp/window_surface_client.h"
-#include "components/mus/public/interfaces/surface.mojom.h"
-#include "gpu/GLES2/gl2chromium.h"
-#include "gpu/GLES2/gl2extchromium.h"
-
-namespace mus {
-class GLES2Context;
-}
-
-namespace shell {
-class Connector;
-}
-
-namespace bitmap_uploader {
-
-BITMAP_UPLOADER_EXPORT extern const char kBitmapUploaderForAcceleratedWidget[];
-
-// BitmapUploader is useful if you want to draw a bitmap or color in a
-// mus::Window.
-class BITMAP_UPLOADER_EXPORT BitmapUploader
- : public NON_EXPORTED_BASE(mus::WindowSurfaceClient) {
- public:
- explicit BitmapUploader(mus::Window* window);
- ~BitmapUploader() override;
-
- void Init(shell::Connector* connector);
-
- // Sets the color which is RGBA.
- void SetColor(uint32_t color);
-
- enum Format {
- RGBA, // Pixel layout on Android.
- BGRA, // Pixel layout everywhere else.
- };
-
- // Sets a bitmap.
- void SetBitmap(int width,
- int height,
- std::unique_ptr<std::vector<unsigned char>> data,
- Format format);
-
- private:
- void Upload();
-
- uint32_t BindTextureForSize(const gfx::Size& size);
-
- uint32_t TextureFormat() const {
- return format_ == BGRA ? GL_BGRA_EXT : GL_RGBA;
- }
-
- void SetIdNamespace(uint32_t id_namespace);
-
- // WindowSurfaceClient implementation.
- void OnResourcesReturned(
- mus::WindowSurface* surface,
- mojo::Array<cc::ReturnedResource> resources) override;
-
- mus::Window* window_;
- std::unique_ptr<mus::WindowSurface> surface_;
- // This may be null if there is an error contacting mus/initializing. We
- // assume we'll be shutting down soon and do nothing in this case.
- std::unique_ptr<mus::GLES2Context> gles2_context_;
-
- uint32_t color_;
- int width_;
- int height_;
- Format format_;
- std::unique_ptr<std::vector<unsigned char>> bitmap_;
- uint32_t next_resource_id_;
- uint32_t id_namespace_;
- base::hash_map<uint32_t, uint32_t> resource_to_texture_id_map_;
-
- DISALLOW_COPY_AND_ASSIGN(BitmapUploader);
-};
-
-} // namespace bitmap_uploader
-
-#endif // COMPONENTS_BITMAP_UPLOADER_BITMAP_UPLAODER_H_
diff --git a/chromium/components/bitmap_uploader/bitmap_uploader_export.h b/chromium/components/bitmap_uploader/bitmap_uploader_export.h
deleted file mode 100644
index e3642119673..00000000000
--- a/chromium/components/bitmap_uploader/bitmap_uploader_export.h
+++ /dev/null
@@ -1,32 +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 COMPONENTS_BITMAP_UPLOADER_BITMAP_UPLOADER_EXPORT_H_
-#define COMPONENTS_BITMAP_UPLOADER_BITMAP_UPLOADER_EXPORT_H_
-
-// Defines BITMAP_UPLOADER_EXPORT so that functionality implemented by the
-// bitmap_uploader module can be exported to consumers.
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(BITMAP_UPLOADER_IMPLEMENTATION)
-#define BITMAP_UPLOADER_EXPORT __declspec(dllexport)
-#else
-#define BITMAP_UPLOADER_EXPORT __declspec(dllimport)
-#endif // defined(BITMAP_UPLOADER_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(BITMAP_UPLOADER_IMPLEMENTATION)
-#define BITMAP_UPLOADER_EXPORT __attribute__((visibility("default")))
-#else
-#define BITMAP_UPLOADER_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define BITMAP_UPLOADER_EXPORT
-#endif
-
-#endif // COMPONENTS_BITMAP_UPLOADER_BITMAP_UPLOADER_EXPORT_H_
diff --git a/chromium/components/bookmarks.gypi b/chromium/components/bookmarks.gypi
deleted file mode 100644
index bea253f0e15..00000000000
--- a/chromium/components/bookmarks.gypi
+++ /dev/null
@@ -1,205 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/bookmarks/browser
- 'target_name': 'bookmarks_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../net/net.gyp:net',
- '../third_party/icu/icu.gyp:icui18n',
- '../third_party/icu/icu.gyp:icuuc',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx',
- '../url/url.gyp:url_lib',
- 'bookmarks_common',
- 'components_strings.gyp:components_strings',
- 'favicon_base',
- 'keyed_service_core',
- 'pref_registry',
- 'query_parser',
- 'url_formatter/url_formatter.gyp:url_formatter',
- ],
- 'sources': [
- 'bookmarks/browser/base_bookmark_model_observer.cc',
- 'bookmarks/browser/base_bookmark_model_observer.h',
- 'bookmarks/browser/bookmark_client.cc',
- 'bookmarks/browser/bookmark_client.h',
- 'bookmarks/browser/bookmark_codec.cc',
- 'bookmarks/browser/bookmark_codec.h',
- 'bookmarks/browser/bookmark_expanded_state_tracker.cc',
- 'bookmarks/browser/bookmark_expanded_state_tracker.h',
- 'bookmarks/browser/bookmark_index.cc',
- 'bookmarks/browser/bookmark_index.h',
- 'bookmarks/browser/bookmark_match.cc',
- 'bookmarks/browser/bookmark_match.h',
- 'bookmarks/browser/bookmark_model.cc',
- 'bookmarks/browser/bookmark_model.h',
- 'bookmarks/browser/bookmark_model_observer.h',
- 'bookmarks/browser/bookmark_node.cc',
- 'bookmarks/browser/bookmark_node.h',
- 'bookmarks/browser/bookmark_node_data.cc',
- 'bookmarks/browser/bookmark_node_data.h',
- 'bookmarks/browser/bookmark_node_data_ios.cc',
- 'bookmarks/browser/bookmark_node_data_mac.cc',
- 'bookmarks/browser/bookmark_node_data_views.cc',
- 'bookmarks/browser/bookmark_pasteboard_helper_mac.h',
- 'bookmarks/browser/bookmark_pasteboard_helper_mac.mm',
- 'bookmarks/browser/bookmark_storage.cc',
- 'bookmarks/browser/bookmark_storage.h',
- 'bookmarks/browser/bookmark_undo_delegate.h',
- 'bookmarks/browser/bookmark_undo_provider.h',
- 'bookmarks/browser/bookmark_utils.cc',
- 'bookmarks/browser/bookmark_utils.h',
- 'bookmarks/browser/scoped_group_bookmark_actions.cc',
- 'bookmarks/browser/scoped_group_bookmark_actions.h',
- 'bookmarks/browser/startup_task_runner_service.cc',
- 'bookmarks/browser/startup_task_runner_service.h',
- ],
- 'conditions': [
- ['OS == "android"', {
- # In GN, this android-specific stuff is its own target at
- # //components/bookmarks/common/android
- # TODO(cjhopman): This should be its own target in Gyp, too.
- 'dependencies': [
- 'bookmarks_jni_headers',
- ],
- 'sources' : [
- 'bookmarks/common/android/bookmark_id.cc',
- 'bookmarks/common/android/bookmark_id.h',
- 'bookmarks/common/android/bookmark_type_list.h',
- 'bookmarks/common/android/component_jni_registrar.cc',
- 'bookmarks/common/android/component_jni_registrar.h',
- ],
- }],
- ['toolkit_views==1', {
- 'dependencies': [
- '<(DEPTH)/ui/views/views.gyp:views',
- ],
- }],
- ['use_x11==1', {
- 'dependencies': [
- '../ui/events/platform/x11/x11_events_platform.gyp:x11_events_platform',
- '../ui/gfx/x/gfx_x11.gyp:gfx_x11',
- ],
- }],
- ],
- },
- {
- # GN version: //components/bookmarks/common
- 'target_name': 'bookmarks_common',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'bookmarks/common/bookmark_constants.cc',
- 'bookmarks/common/bookmark_constants.h',
- 'bookmarks/common/bookmark_pref_names.cc',
- 'bookmarks/common/bookmark_pref_names.h',
- ],
- },
- {
- # GN version: //components/bookmarks/managed
- 'target_name': 'bookmarks_managed',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'bookmarks_browser',
- 'components_strings.gyp:components_strings',
- 'keyed_service_core',
- ],
- 'sources': [
- 'bookmarks/managed/managed_bookmark_service.cc',
- 'bookmarks/managed/managed_bookmark_service.h',
- 'bookmarks/managed/managed_bookmark_util.cc',
- 'bookmarks/managed/managed_bookmark_util.h',
- 'bookmarks/managed/managed_bookmarks_tracker.cc',
- 'bookmarks/managed/managed_bookmarks_tracker.h',
- ],
- },
- {
- # GN version: //components/bookmarks/test
- 'target_name': 'bookmarks_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../testing/gmock.gyp:gmock',
- '../ui/events/platform/events_platform.gyp:events_platform',
- '../url/url.gyp:url_lib',
- 'bookmarks_browser',
- ],
- 'sources': [
- 'bookmarks/test/bookmark_test_helpers.cc',
- 'bookmarks/test/bookmark_test_helpers.h',
- 'bookmarks/test/mock_bookmark_model_observer.cc',
- 'bookmarks/test/mock_bookmark_model_observer.h',
- 'bookmarks/test/test_bookmark_client.cc',
- 'bookmarks/test/test_bookmark_client.h',
- ],
- 'conditions': [
- ['use_x11==1', {
- 'dependencies': [
- '../ui/events/platform/x11/x11_events_platform.gyp:x11_events_platform',
- ],
- }],
- ],
- },
- ],
- 'conditions' : [
- ['OS=="android"', {
- 'targets': [
- {
- # GN: //components/bookmarks/common/android:bookmarks_java
- 'target_name': 'bookmarks_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base_java',
- 'bookmark_type_java',
- ],
- 'variables': {
- 'java_in_dir': 'bookmarks/common/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN: //components/bookmarks/common/android:bookmarks_jni_headers
- 'target_name': 'bookmarks_jni_headers',
- 'type': 'none',
- 'sources': [
- 'bookmarks/common/android/java/src/org/chromium/components/bookmarks/BookmarkId.java',
- ],
- 'variables': {
- 'jni_gen_package': 'components/bookmarks',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- # GN: //components/bookmarks/common/android:bookmarks_type_javagen
- 'target_name': 'bookmark_type_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'bookmarks/common/android/bookmark_type.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- ],
- }]
- ],
-}
diff --git a/chromium/components/bookmarks/browser/BUILD.gn b/chromium/components/bookmarks/browser/BUILD.gn
index 3ac521297d1..05e81256e48 100644
--- a/chromium/components/bookmarks/browser/BUILD.gn
+++ b/chromium/components/bookmarks/browser/BUILD.gn
@@ -4,7 +4,7 @@
import("//build/config/ui.gni")
-source_set("browser") {
+static_library("browser") {
sources = [
"base_bookmark_model_observer.cc",
"base_bookmark_model_observer.h",
@@ -117,11 +117,4 @@ source_set("unit_tests") {
"//ui/base",
"//url",
]
-
- if (use_x11) {
- deps += [
- "//ui/events/platform/x11",
- "//ui/gfx/x",
- ]
- }
}
diff --git a/chromium/components/bookmarks/browser/bookmark_codec.cc b/chromium/components/bookmarks/browser/bookmark_codec.cc
index 8bda69bf388..1d6ff890bb6 100644
--- a/chromium/components/bookmarks/browser/bookmark_codec.cc
+++ b/chromium/components/bookmarks/browser/bookmark_codec.cc
@@ -7,8 +7,10 @@
#include <stddef.h>
#include <algorithm>
+#include <utility>
#include "base/json/json_string_value_serializer.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/values.h"
@@ -114,8 +116,9 @@ bool BookmarkCodec::Decode(BookmarkNode* bb_node,
return success;
}
-base::Value* BookmarkCodec::EncodeNode(const BookmarkNode* node) {
- base::DictionaryValue* value = new base::DictionaryValue();
+std::unique_ptr<base::Value> BookmarkCodec::EncodeNode(
+ const BookmarkNode* node) {
+ std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue());
std::string id = base::Int64ToString(node->id());
value->SetString(kIdKey, id);
const base::string16& title = node->GetTitle();
@@ -147,7 +150,7 @@ base::Value* BookmarkCodec::EncodeNode(const BookmarkNode* node) {
value->SetString(kSyncTransactionVersion,
base::Int64ToString(node->sync_transaction_version()));
}
- return value;
+ return std::move(value);
}
base::Value* BookmarkCodec::EncodeMetaInfo(
@@ -270,6 +273,12 @@ bool BookmarkCodec::DecodeNode(const base::DictionaryValue& value,
return false;
}
+ // It's not valid to have both a node and a specified parent.
+ if (node && parent) {
+ NOTREACHED();
+ return false;
+ }
+
std::string id_string;
int64_t id = 0;
if (ids_valid_) {
@@ -312,7 +321,7 @@ bool BookmarkCodec::DecodeNode(const base::DictionaryValue& value,
return false; // Node invalid.
if (parent)
- parent->Add(node, parent->child_count());
+ parent->Add(base::WrapUnique(node), parent->child_count());
node->set_type(BookmarkNode::URL);
UpdateChecksumWithUrlNode(id_string, title, url_string);
} else {
@@ -340,7 +349,7 @@ bool BookmarkCodec::DecodeNode(const base::DictionaryValue& value,
node->set_date_folder_modified(Time::FromInternalValue(internal_time));
if (parent)
- parent->Add(node, parent->child_count());
+ parent->Add(base::WrapUnique(node), parent->child_count());
UpdateChecksumWithFolderNode(id_string, title);
diff --git a/chromium/components/bookmarks/browser/bookmark_codec.h b/chromium/components/bookmarks/browser/bookmark_codec.h
index 8b42d3940bb..7760826e4f6 100644
--- a/chromium/components/bookmarks/browser/bookmark_codec.h
+++ b/chromium/components/bookmarks/browser/bookmark_codec.h
@@ -6,6 +6,8 @@
#define COMPONENTS_BOOKMARKS_BROWSER_BOOKMARK_CODEC_H_
#include <stdint.h>
+
+#include <memory>
#include <set>
#include <string>
@@ -108,8 +110,7 @@ class BookmarkCodec {
private:
// Encodes node and all its children into a Value object and returns it.
- // The caller takes ownership of the returned object.
- base::Value* EncodeNode(const BookmarkNode* node);
+ std::unique_ptr<base::Value> EncodeNode(const BookmarkNode* node);
// Encodes the given meta info into a Value object and returns it. The caller
// takes ownership of the returned object.
diff --git a/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc b/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc
index 9890f27af0f..10534745e5b 100644
--- a/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc
@@ -46,7 +46,7 @@ void BookmarkExpandedStateTrackerTest::SetUp() {
prefs_.registry()->RegisterListPref(prefs::kBookmarkEditorExpandedNodes,
new base::ListValue);
prefs_.registry()->RegisterListPref(prefs::kManagedBookmarks);
- model_.reset(new BookmarkModel(base::WrapUnique(new TestBookmarkClient())));
+ model_.reset(new BookmarkModel(base::MakeUnique<TestBookmarkClient>()));
model_->Load(&prefs_, base::FilePath(),
base::ThreadTaskRunnerHandle::Get(),
base::ThreadTaskRunnerHandle::Get());
diff --git a/chromium/components/bookmarks/browser/bookmark_index.cc b/chromium/components/bookmarks/browser/bookmark_index.cc
index f054022abe4..1704f3a27d1 100644
--- a/chromium/components/bookmarks/browser/bookmark_index.cc
+++ b/chromium/components/bookmarks/browser/bookmark_index.cc
@@ -13,6 +13,7 @@
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
#include "base/stl_util.h"
#include "base/strings/utf_offset_string_conversions.h"
#include "build/build_config.h"
diff --git a/chromium/components/bookmarks/browser/bookmark_index_unittest.cc b/chromium/components/bookmarks/browser/bookmark_index_unittest.cc
index 8b56b40e680..3e23cc38080 100644
--- a/chromium/components/bookmarks/browser/bookmark_index_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_index_unittest.cc
@@ -529,7 +529,7 @@ TEST_F(BookmarkIndexTest, GetResultsSortedByTypedCount) {
std::unique_ptr<BookmarkModel> model =
TestBookmarkClient::CreateModelWithClient(
- base::WrapUnique(new BookmarkClientMock(typed_count_map)));
+ base::MakeUnique<BookmarkClientMock>(typed_count_map));
for (size_t i = 0; i < arraysize(data); ++i)
// Populate the BookmarkIndex.
diff --git a/chromium/components/bookmarks/browser/bookmark_model.cc b/chromium/components/bookmarks/browser/bookmark_model.cc
index 8d5b238a0c9..45ea8ee9b43 100644
--- a/chromium/components/bookmarks/browser/bookmark_model.cc
+++ b/chromium/components/bookmarks/browser/bookmark_model.cc
@@ -13,6 +13,7 @@
#include "base/i18n/string_compare.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/profiler/scoped_tracker.h"
#include "base/strings/string_util.h"
@@ -51,11 +52,11 @@ class VisibilityComparator {
public:
explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
- // Returns true if |n1| preceeds |n2|.
- bool operator()(const BookmarkPermanentNode* n1,
- const BookmarkPermanentNode* n2) {
- bool n1_visible = client_->IsPermanentNodeVisible(n1);
- bool n2_visible = client_->IsPermanentNodeVisible(n2);
+ // Returns true if |n1| precedes |n2|.
+ bool operator()(const std::unique_ptr<BookmarkPermanentNode>& n1,
+ const std::unique_ptr<BookmarkPermanentNode>& n2) {
+ bool n1_visible = client_->IsPermanentNodeVisible(n1.get());
+ bool n2_visible = client_->IsPermanentNodeVisible(n2.get());
return n1_visible != n2_visible && n1_visible;
}
@@ -69,8 +70,9 @@ class SortComparator {
public:
explicit SortComparator(icu::Collator* collator) : collator_(collator) {}
- // Returns true if |n1| preceeds |n2|.
- bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) {
+ // Returns true if |n1| precedes |n2|.
+ bool operator()(const std::unique_ptr<BookmarkNode>& n1,
+ const std::unique_ptr<BookmarkNode>& n2) {
if (n1->type() == n2->type()) {
// Types are the same, compare the names.
if (!collator_)
@@ -217,12 +219,9 @@ void BookmarkModel::Remove(const BookmarkNode* node) {
void BookmarkModel::RemoveAllUserBookmarks() {
std::set<GURL> removed_urls;
struct RemoveNodeData {
- RemoveNodeData(const BookmarkNode* parent, int index, BookmarkNode* node)
- : parent(parent), index(index), node(node) {}
-
const BookmarkNode* parent;
int index;
- BookmarkNode* node;
+ std::unique_ptr<BookmarkNode> node;
};
std::vector<RemoveNodeData> removed_node_data_list;
@@ -242,10 +241,9 @@ void BookmarkModel::RemoveAllUserBookmarks() {
continue;
for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
- BookmarkNode* child_node = AsMutable(permanent_node->GetChild(j));
- RemoveNodeAndGetRemovedUrls(child_node, &removed_urls);
- removed_node_data_list.push_back(
- RemoveNodeData(permanent_node, j, child_node));
+ std::unique_ptr<BookmarkNode> node = RemoveNodeAndGetRemovedUrls(
+ AsMutable(permanent_node->GetChild(j)), &removed_urls);
+ removed_node_data_list.push_back({permanent_node, j, std::move(node)});
}
}
}
@@ -257,10 +255,10 @@ void BookmarkModel::RemoveAllUserBookmarks() {
BookmarkAllUserNodesRemoved(this, removed_urls));
BeginGroupedChanges();
- for (const auto& removed_node_data : removed_node_data_list) {
- undo_delegate()->OnBookmarkNodeRemoved(
- this, removed_node_data.parent, removed_node_data.index,
- std::unique_ptr<BookmarkNode>(removed_node_data.node));
+ for (auto& removed_node_data : removed_node_data_list) {
+ undo_delegate()->OnBookmarkNodeRemoved(this, removed_node_data.parent,
+ removed_node_data.index,
+ std::move(removed_node_data.node));
}
EndGroupedChanges();
}
@@ -293,8 +291,12 @@ void BookmarkModel::Move(const BookmarkNode* node,
if (old_parent == new_parent && index > old_index)
index--;
+
+ BookmarkNode* mutable_old_parent = AsMutable(old_parent);
+ std::unique_ptr<BookmarkNode> owned_node =
+ mutable_old_parent->Remove(AsMutable(node));
BookmarkNode* mutable_new_parent = AsMutable(new_parent);
- mutable_new_parent->Add(AsMutable(node), index);
+ mutable_new_parent->Add(std::move(owned_node), index);
if (store_.get())
store_->ScheduleSave();
@@ -594,7 +596,8 @@ const BookmarkNode* BookmarkModel::AddFolderWithMetaInfo(
return NULL;
}
- BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), GURL());
+ std::unique_ptr<BookmarkNode> new_node =
+ base::MakeUnique<BookmarkNode>(generate_next_node_id(), GURL());
new_node->set_date_folder_modified(Time::Now());
// Folders shouldn't have line breaks in their titles.
new_node->SetTitle(title);
@@ -602,7 +605,7 @@ const BookmarkNode* BookmarkModel::AddFolderWithMetaInfo(
if (meta_info)
new_node->SetMetaInfoMap(*meta_info);
- return AddNode(AsMutable(parent), index, new_node);
+ return AddNode(AsMutable(parent), index, std::move(new_node));
}
const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
@@ -635,14 +638,15 @@ const BookmarkNode* BookmarkModel::AddURLWithCreationTimeAndMetaInfo(
if (creation_time > parent->date_folder_modified())
SetDateFolderModified(parent, creation_time);
- BookmarkNode* new_node = new BookmarkNode(generate_next_node_id(), url);
+ std::unique_ptr<BookmarkNode> new_node =
+ base::MakeUnique<BookmarkNode>(generate_next_node_id(), url);
new_node->SetTitle(title);
new_node->set_date_added(creation_time);
new_node->set_type(BookmarkNode::URL);
if (meta_info)
new_node->SetMetaInfoMap(*meta_info);
- return AddNode(AsMutable(parent), index, new_node);
+ return AddNode(AsMutable(parent), index, std::move(new_node));
}
void BookmarkModel::SortChildren(const BookmarkNode* parent) {
@@ -679,17 +683,29 @@ void BookmarkModel::ReorderChildren(
// Ensure that all children in |parent| are in |ordered_nodes|.
DCHECK_EQ(static_cast<size_t>(parent->child_count()), ordered_nodes.size());
- for (size_t i = 0; i < ordered_nodes.size(); ++i)
- DCHECK_EQ(parent, ordered_nodes[i]->parent());
+ for (const BookmarkNode* node : ordered_nodes)
+ DCHECK_EQ(parent, node->parent());
FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
OnWillReorderBookmarkNode(this, parent));
- AsMutable(parent)->SetChildren(
- *(reinterpret_cast<const std::vector<BookmarkNode*>*>(&ordered_nodes)));
+ if (ordered_nodes.size() > 1) {
+ std::map<const BookmarkNode*, int> order;
+ for (size_t i = 0; i < ordered_nodes.size(); ++i)
+ order[ordered_nodes[i]] = i;
+
+ std::vector<std::unique_ptr<BookmarkNode>> new_children(
+ ordered_nodes.size());
+ BookmarkNode* mutable_parent = AsMutable(parent);
+ for (auto& child : mutable_parent->children()) {
+ size_t new_location = order[child.get()];
+ new_children[new_location] = std::move(child);
+ }
+ mutable_parent->children().swap(new_children);
- if (store_.get())
- store_->ScheduleSave();
+ if (store_.get())
+ store_->ScheduleSave();
+ }
FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
BookmarkNodeChildrenReordered(this, parent));
@@ -752,16 +768,15 @@ const BookmarkPermanentNode* BookmarkModel::PermanentNode(
}
}
-void BookmarkModel::RestoreRemovedNode(
- const BookmarkNode* parent,
- int index,
- std::unique_ptr<BookmarkNode> scoped_node) {
- BookmarkNode* node = scoped_node.release();
- AddNode(AsMutable(parent), index, node);
+void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent,
+ int index,
+ std::unique_ptr<BookmarkNode> node) {
+ BookmarkNode* node_ptr = node.get();
+ AddNode(AsMutable(parent), index, std::move(node));
// We might be restoring a folder node that have already contained a set of
// child nodes. We need to notify all of them.
- NotifyNodeAddedForAllDescendents(node);
+ NotifyNodeAddedForAllDescendents(node_ptr);
}
void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) {
@@ -826,14 +841,21 @@ void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
if (store_.get())
store_->ScheduleSave();
}
- bookmark_bar_node_ = details->release_bb_node();
- other_node_ = details->release_other_folder_node();
- mobile_node_ = details->release_mobile_folder_node();
- index_.reset(details->release_index());
+ std::unique_ptr<BookmarkPermanentNode> owned_bb_node =
+ details->owned_bb_node();
+ std::unique_ptr<BookmarkPermanentNode> owned_other_folder_node =
+ details->owned_other_folder_node();
+ std::unique_ptr<BookmarkPermanentNode> owned_mobile_folder_node =
+ details->owned_mobile_folder_node();
+ index_ = details->owned_index();
+
+ bookmark_bar_node_ = owned_bb_node.get();
+ other_node_ = owned_other_folder_node.get();
+ mobile_node_ = owned_mobile_folder_node.get();
// Get any extra nodes and take ownership of them at the |root_|.
- std::vector<BookmarkPermanentNode*> extra_nodes;
- details->release_extra_nodes(&extra_nodes);
+ std::vector<std::unique_ptr<BookmarkPermanentNode>> extra_nodes =
+ details->owned_extra_nodes();
// TODO(robliao): Remove ScopedTracker below once https://crbug.com/467179
// is fixed.
@@ -843,12 +865,12 @@ void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
// WARNING: order is important here, various places assume the order is
// constant (but can vary between embedders with the initial visibility
// of permanent nodes).
- std::vector<BookmarkPermanentNode*> root_children;
- root_children.push_back(bookmark_bar_node_);
- root_children.push_back(other_node_);
- root_children.push_back(mobile_node_);
- for (size_t i = 0; i < extra_nodes.size(); ++i)
- root_children.push_back(extra_nodes[i]);
+ std::vector<std::unique_ptr<BookmarkPermanentNode>> root_children;
+ root_children.push_back(std::move(owned_bb_node));
+ root_children.push_back(std::move(owned_other_folder_node));
+ root_children.push_back(std::move(owned_mobile_folder_node));
+ std::move(extra_nodes.begin(), extra_nodes.end(),
+ std::back_inserter(root_children));
// TODO(robliao): Remove ScopedTracker below once https://crbug.com/467179
// is fixed.
@@ -859,7 +881,7 @@ void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
root_children.end(),
VisibilityComparator(client_.get()));
for (size_t i = 0; i < root_children.size(); ++i)
- root_.Add(root_children[i], static_cast<int>(i));
+ root_.Add(std::move(root_children[i]), static_cast<int>(i));
root_.SetMetaInfoMap(details->model_meta_info_map());
root_.set_sync_transaction_version(details->model_sync_transaction_version());
@@ -889,21 +911,21 @@ void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
BookmarkModelLoaded(this, details->ids_reassigned()));
}
-void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* delete_me) {
- std::unique_ptr<BookmarkNode> node(delete_me);
+void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* node_ptr) {
+ std::unique_ptr<BookmarkNode> node;
- const BookmarkNode* parent = node->parent();
+ const BookmarkNode* parent = node_ptr->parent();
DCHECK(parent);
- int index = parent->GetIndexOf(node.get());
+ int index = parent->GetIndexOf(node_ptr);
DCHECK_NE(-1, index);
FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
- OnWillRemoveBookmarks(this, parent, index, node.get()));
+ OnWillRemoveBookmarks(this, parent, index, node_ptr));
std::set<GURL> removed_urls;
{
base::AutoLock url_lock(url_lock_);
- RemoveNodeAndGetRemovedUrls(node.get(), &removed_urls);
+ node = RemoveNodeAndGetRemovedUrls(node_ptr, &removed_urls);
}
if (store_.get())
@@ -931,16 +953,17 @@ void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) {
nodes_ordered_by_url_set_.erase(i);
}
-void BookmarkModel::RemoveNodeAndGetRemovedUrls(BookmarkNode* node,
- std::set<GURL>* removed_urls) {
+std::unique_ptr<BookmarkNode> BookmarkModel::RemoveNodeAndGetRemovedUrls(
+ BookmarkNode* node_ptr,
+ std::set<GURL>* removed_urls) {
// NOTE: this method should be always called with |url_lock_| held.
// This method does not explicitly acquires a lock.
url_lock_.AssertAcquired();
DCHECK(removed_urls);
- BookmarkNode* parent = node->parent();
+ BookmarkNode* parent = node_ptr->parent();
DCHECK(parent);
- parent->Remove(node);
- RemoveNode(node, removed_urls);
+ std::unique_ptr<BookmarkNode> node = parent->Remove(node_ptr);
+ RemoveNode(node_ptr, removed_urls);
// RemoveNode adds an entry to removed_urls for each node of type URL. As we
// allow duplicates we need to remove any entries that are still bookmarked.
for (std::set<GURL>::iterator i = removed_urls->begin();
@@ -955,25 +978,28 @@ void BookmarkModel::RemoveNodeAndGetRemovedUrls(BookmarkNode* node,
++i;
}
}
+
+ return node;
}
BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
int index,
- BookmarkNode* node) {
- parent->Add(node, index);
+ std::unique_ptr<BookmarkNode> node) {
+ BookmarkNode* node_ptr = node.get();
+ parent->Add(std::move(node), index);
if (store_.get())
store_->ScheduleSave();
{
base::AutoLock url_lock(url_lock_);
- AddNodeToInternalMaps(node);
+ AddNodeToInternalMaps(node_ptr);
}
FOR_EACH_OBSERVER(BookmarkModelObserver, observers_,
BookmarkNodeAdded(this, parent, index));
- return node;
+ return node_ptr;
}
void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) {
diff --git a/chromium/components/bookmarks/browser/bookmark_model.h b/chromium/components/bookmarks/browser/bookmark_model.h
index 61cdfa48bc4..2dd64c58c8f 100644
--- a/chromium/components/bookmarks/browser/bookmark_model.h
+++ b/chromium/components/bookmarks/browser/bookmark_model.h
@@ -354,12 +354,13 @@ class BookmarkModel : public BookmarkUndoProvider,
// Populates |nodes_ordered_by_url_set_| from root.
void PopulateNodesByURL(BookmarkNode* node);
- // Removes the node from its parent, but does not delete it. No notifications
+ // Removes the node from its parent and returns it. No notifications
// are sent. |removed_urls| is populated with the urls which no longer have
// any bookmarks associated with them.
// This method should be called after acquiring |url_lock_|.
- void RemoveNodeAndGetRemovedUrls(BookmarkNode* node,
- std::set<GURL>* removed_urls);
+ std::unique_ptr<BookmarkNode> RemoveNodeAndGetRemovedUrls(
+ BookmarkNode* node,
+ std::set<GURL>* removed_urls);
// Removes the node from its parent, sends notification, and deletes it.
// type specifies how the node should be removed.
@@ -372,7 +373,7 @@ class BookmarkModel : public BookmarkUndoProvider,
// observers.
BookmarkNode* AddNode(BookmarkNode* parent,
int index,
- BookmarkNode* node);
+ std::unique_ptr<BookmarkNode> node);
// Adds the |node| to |nodes_ordered_by_url_set_| and |index_|.
void AddNodeToInternalMaps(BookmarkNode* node);
diff --git a/chromium/components/bookmarks/browser/bookmark_model_unittest.cc b/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
index 55927dd1def..f5b8af8fe5b 100644
--- a/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -15,6 +15,7 @@
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -129,9 +130,10 @@ void PopulateNodeImpl(const std::vector<std::string>& description,
// value. The folders need not have a name, but one is assigned to help
// in debugging.
static int next_folder_id = 1;
- TestNode* new_node = new TestNode(base::IntToString16(next_folder_id++),
- BookmarkNode::FOLDER);
- parent->Add(new_node, parent->child_count());
+ TestNode* new_node = parent->Add(
+ base::MakeUnique<TestNode>(base::IntToString16(next_folder_id++),
+ BookmarkNode::FOLDER),
+ parent->child_count());
PopulateNodeImpl(description, index, new_node);
} else if (element == "]") {
// End the current folder.
@@ -143,7 +145,8 @@ void PopulateNodeImpl(const std::vector<std::string>& description,
// likely means a space was forgotten.
DCHECK(element.find('[') == std::string::npos);
DCHECK(element.find(']') == std::string::npos);
- parent->Add(new TestNode(base::UTF8ToUTF16(element), BookmarkNode::URL),
+ parent->Add(base::MakeUnique<TestNode>(base::UTF8ToUTF16(element),
+ BookmarkNode::URL),
parent->child_count());
}
}
@@ -425,9 +428,9 @@ class BookmarkModelTest : public testing::Test,
BookmarkPermanentNode* ReloadModelWithExtraNode() {
model_->RemoveObserver(this);
- BookmarkPermanentNode* extra_node = new BookmarkPermanentNode(100);
BookmarkPermanentNodeList extra_nodes;
- extra_nodes.push_back(extra_node);
+ extra_nodes.push_back(base::MakeUnique<BookmarkPermanentNode>(100));
+ BookmarkPermanentNode* extra_node = extra_nodes.back().get();
std::unique_ptr<TestBookmarkClient> client(new TestBookmarkClient);
client->SetExtraNodesToLoad(std::move(extra_nodes));
@@ -1017,10 +1020,10 @@ TEST_F(BookmarkModelTest, DISABLED_Sort) {
BookmarkNode* child1 = AsMutable(parent->GetChild(1));
child1->SetTitle(ASCIIToUTF16("a"));
- delete child1->Remove(child1->GetChild(0));
+ child1->Remove(child1->GetChild(0));
BookmarkNode* child3 = AsMutable(parent->GetChild(3));
child3->SetTitle(ASCIIToUTF16("C"));
- delete child3->Remove(child3->GetChild(0));
+ child3->Remove(child3->GetChild(0));
ClearCounts();
diff --git a/chromium/components/bookmarks/browser/bookmark_node_data_unittest.cc b/chromium/components/bookmarks/browser/bookmark_node_data_unittest.cc
index 24bd39a4537..881fa7bffab 100644
--- a/chromium/components/bookmarks/browser/bookmark_node_data_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_node_data_unittest.cc
@@ -17,7 +17,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/dragdrop/os_exchange_data.h"
-#include "ui/events/platform/platform_event_source.h"
#include "url/gurl.h"
using base::ASCIIToUTF16;
@@ -29,7 +28,6 @@ class BookmarkNodeDataTest : public testing::Test {
BookmarkNodeDataTest() {}
void SetUp() override {
- event_source_ = ui::PlatformEventSource::CreateDefault();
model_ = TestBookmarkClient::CreateModel();
test::WaitForBookmarkModelToLoad(model_.get());
bool success = profile_dir_.CreateUniqueTempDir();
@@ -38,13 +36,14 @@ class BookmarkNodeDataTest : public testing::Test {
void TearDown() override {
model_.reset();
- event_source_.reset();
bool success = profile_dir_.Delete();
ASSERT_TRUE(success);
ui::Clipboard::DestroyClipboardForCurrentThread();
}
- const base::FilePath& GetProfilePath() const { return profile_dir_.path(); }
+ const base::FilePath& GetProfilePath() const {
+ return profile_dir_.GetPath();
+ }
BookmarkModel* model() { return model_.get(); }
@@ -54,7 +53,6 @@ class BookmarkNodeDataTest : public testing::Test {
private:
base::ScopedTempDir profile_dir_;
std::unique_ptr<BookmarkModel> model_;
- std::unique_ptr<ui::PlatformEventSource> event_source_;
base::MessageLoopForUI loop_;
DISALLOW_COPY_AND_ASSIGN(BookmarkNodeDataTest);
@@ -62,7 +60,8 @@ class BookmarkNodeDataTest : public testing::Test {
namespace {
-ui::OSExchangeData::Provider* CloneProvider(const ui::OSExchangeData& data) {
+std::unique_ptr<ui::OSExchangeData::Provider> CloneProvider(
+ const ui::OSExchangeData& data) {
return data.provider().Clone();
}
@@ -137,7 +136,7 @@ TEST_F(BookmarkNodeDataTest, URL) {
// Make sure asking for the node with a different profile returns NULL.
base::ScopedTempDir other_profile_dir;
EXPECT_TRUE(other_profile_dir.CreateUniqueTempDir());
- EXPECT_TRUE(read_data.GetFirstNode(model(), other_profile_dir.path()) ==
+ EXPECT_TRUE(read_data.GetFirstNode(model(), other_profile_dir.GetPath()) ==
NULL);
// Writing should also put the URL and title on the clipboard.
@@ -186,7 +185,7 @@ TEST_F(BookmarkNodeDataTest, Folder) {
// A different profile should return NULL for the node.
base::ScopedTempDir other_profile_dir;
EXPECT_TRUE(other_profile_dir.CreateUniqueTempDir());
- EXPECT_TRUE(read_data.GetFirstNode(model(), other_profile_dir.path()) ==
+ EXPECT_TRUE(read_data.GetFirstNode(model(), other_profile_dir.GetPath()) ==
NULL);
}
diff --git a/chromium/components/bookmarks/browser/bookmark_storage.cc b/chromium/components/bookmarks/browser/bookmark_storage.cc
index 4acd103a2c7..b3f424f5779 100644
--- a/chromium/components/bookmarks/browser/bookmark_storage.cc
+++ b/chromium/components/bookmarks/browser/bookmark_storage.cc
@@ -101,7 +101,7 @@ void LoadCallback(const base::FilePath& path,
AddBookmarksToIndex(details.get(), details->other_folder_node());
AddBookmarksToIndex(details.get(), details->mobile_folder_node());
for (size_t i = 0; i < extra_nodes.size(); ++i)
- AddBookmarksToIndex(details.get(), extra_nodes[i]);
+ AddBookmarksToIndex(details.get(), extra_nodes[i].get());
UMA_HISTOGRAM_TIMES("Bookmarks.CreateBookmarkIndexTime",
TimeTicks::Now() - start_time);
}
diff --git a/chromium/components/bookmarks/browser/bookmark_storage.h b/chromium/components/bookmarks/browser/bookmark_storage.h
index d5bb9e56540..2496e42c34f 100644
--- a/chromium/components/bookmarks/browser/bookmark_storage.h
+++ b/chromium/components/bookmarks/browser/bookmark_storage.h
@@ -16,8 +16,8 @@
#include "base/files/important_file_writer.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
+#include "components/bookmarks/browser/bookmark_index.h"
#include "components/bookmarks/browser/bookmark_node.h"
namespace base {
@@ -26,16 +26,16 @@ class SequencedTaskRunner;
namespace bookmarks {
-class BookmarkIndex;
class BookmarkModel;
// A list of BookmarkPermanentNodes that owns them.
-typedef ScopedVector<BookmarkPermanentNode> BookmarkPermanentNodeList;
+using BookmarkPermanentNodeList =
+ std::vector<std::unique_ptr<BookmarkPermanentNode>>;
// A callback that generates a BookmarkPermanentNodeList, given a max ID to
// use. The max ID argument will be updated after any new nodes have been
// created and assigned IDs.
-typedef base::Callback<BookmarkPermanentNodeList(int64_t*)> LoadExtraCallback;
+using LoadExtraCallback = base::Callback<BookmarkPermanentNodeList(int64_t*)>;
// BookmarkLoadDetails is used by BookmarkStorage when loading bookmarks.
// BookmarkModel creates a BookmarkLoadDetails and passes it (including
@@ -58,27 +58,29 @@ class BookmarkLoadDetails {
void LoadExtraNodes();
BookmarkPermanentNode* bb_node() { return bb_node_.get(); }
- BookmarkPermanentNode* release_bb_node() { return bb_node_.release(); }
+ std::unique_ptr<BookmarkPermanentNode> owned_bb_node() {
+ return std::move(bb_node_);
+ }
BookmarkPermanentNode* mobile_folder_node() {
return mobile_folder_node_.get();
}
- BookmarkPermanentNode* release_mobile_folder_node() {
- return mobile_folder_node_.release();
+ std::unique_ptr<BookmarkPermanentNode> owned_mobile_folder_node() {
+ return std::move(mobile_folder_node_);
}
BookmarkPermanentNode* other_folder_node() {
return other_folder_node_.get();
}
- BookmarkPermanentNode* release_other_folder_node() {
- return other_folder_node_.release();
+ std::unique_ptr<BookmarkPermanentNode> owned_other_folder_node() {
+ return std::move(other_folder_node_);
}
const BookmarkPermanentNodeList& extra_nodes() {
return extra_nodes_;
}
- void release_extra_nodes(std::vector<BookmarkPermanentNode*>* extra_nodes) {
- extra_nodes_.release(extra_nodes);
+ BookmarkPermanentNodeList owned_extra_nodes() {
+ return std::move(extra_nodes_);
}
BookmarkIndex* index() { return index_.get(); }
- BookmarkIndex* release_index() { return index_.release(); }
+ std::unique_ptr<BookmarkIndex> owned_index() { return std::move(index_); }
const BookmarkNode::MetaInfoMap& model_meta_info_map() const {
return model_meta_info_map_;
diff --git a/chromium/components/bookmarks/browser/bookmark_utils_unittest.cc b/chromium/components/bookmarks/browser/bookmark_utils_unittest.cc
index 54d89d780ba..d78e9fcebed 100644
--- a/chromium/components/bookmarks/browser/bookmark_utils_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_utils_unittest.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
@@ -20,15 +21,6 @@
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
-#if defined(USE_GLIB) && defined(USE_X11)
-
-#include <memory>
-
-#include "ui/events/platform/x11/x11_event_source_glib.h" // nogncheck
-#include "ui/gfx/x/x11_types.h" // nogncheck
-
-#endif // defined(USE_GLIB) && defined(USE_X11)
-
using base::ASCIIToUTF16;
using std::string;
@@ -39,11 +31,7 @@ class BookmarkUtilsTest : public testing::Test,
public BaseBookmarkModelObserver {
public:
BookmarkUtilsTest()
- : grouped_changes_beginning_count_(0), grouped_changes_ended_count_(0) {
-#if defined(USE_GLIB) && defined(USE_X11)
- event_source_.reset(new ui::X11EventSourceGlib(gfx::GetXDisplay()));
-#endif // defined(USE_GLIB) && defined(USE_X11)
- }
+ : grouped_changes_beginning_count_(0), grouped_changes_ended_count_(0) {}
~BookmarkUtilsTest() override {}
@@ -86,11 +74,6 @@ class BookmarkUtilsTest : public testing::Test,
// Clipboard requires a message loop.
base::MessageLoopForUI loop_;
-#if defined(USE_GLIB) && defined(USE_X11)
- // On Linux, Clipboard also depends on an event source being present, to get
- // the timestamp.
- std::unique_ptr<ui::X11EventSourceGlib> event_source_;
-#endif // defined(USE_GLIB) && defined(USE_X11)
DISALLOW_COPY_AND_ASSIGN(BookmarkUtilsTest);
};
@@ -435,9 +418,9 @@ TEST_F(BookmarkUtilsTest, MAYBE_CutToClipboard) {
TEST_F(BookmarkUtilsTest, PasteNonEditableNodes) {
// Load a model with an extra node that is not editable.
std::unique_ptr<TestBookmarkClient> client(new TestBookmarkClient());
- BookmarkPermanentNode* extra_node = new BookmarkPermanentNode(100);
BookmarkPermanentNodeList extra_nodes;
- extra_nodes.push_back(extra_node);
+ extra_nodes.push_back(base::MakeUnique<BookmarkPermanentNode>(100));
+ BookmarkPermanentNode* extra_node = extra_nodes.back().get();
client->SetExtraNodesToLoad(std::move(extra_nodes));
std::unique_ptr<BookmarkModel> model(
@@ -586,9 +569,9 @@ TEST_F(BookmarkUtilsTest, CloneFolderResetsNonClonedKey) {
TEST_F(BookmarkUtilsTest, RemoveAllBookmarks) {
// Load a model with an extra node that is not editable.
std::unique_ptr<TestBookmarkClient> client(new TestBookmarkClient());
- BookmarkPermanentNode* extra_node = new BookmarkPermanentNode(100);
BookmarkPermanentNodeList extra_nodes;
- extra_nodes.push_back(extra_node);
+ extra_nodes.push_back(base::MakeUnique<BookmarkPermanentNode>(100));
+ BookmarkPermanentNode* extra_node = extra_nodes.back().get();
client->SetExtraNodesToLoad(std::move(extra_nodes));
std::unique_ptr<BookmarkModel> model(
diff --git a/chromium/components/bookmarks/common/BUILD.gn b/chromium/components/bookmarks/common/BUILD.gn
index 2ba1bd9c411..8ce4153e57b 100644
--- a/chromium/components/bookmarks/common/BUILD.gn
+++ b/chromium/components/bookmarks/common/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("common") {
+static_library("common") {
sources = [
"bookmark_constants.cc",
"bookmark_constants.h",
diff --git a/chromium/components/bookmarks/common/android/BUILD.gn b/chromium/components/bookmarks/common/android/BUILD.gn
index 69bb7f9ea68..b09869a3be9 100644
--- a/chromium/components/bookmarks/common/android/BUILD.gn
+++ b/chromium/components/bookmarks/common/android/BUILD.gn
@@ -4,14 +4,11 @@
import("//build/config/android/rules.gni")
-# GYP: //components/bookmarks.gyp:bookmarks_browser (android part)
source_set("android") {
sources = [
"bookmark_id.cc",
"bookmark_id.h",
"bookmark_type.h",
- "component_jni_registrar.cc",
- "component_jni_registrar.h",
]
deps = [
":bookmarks_jni_headers",
@@ -19,16 +16,15 @@ source_set("android") {
]
}
-# GYP: //components/bookmarks.gyp:bookmarks_java
android_library("bookmarks_java") {
deps = [
"//base:base_java",
+ "//third_party/android_tools:android_support_annotations_java",
]
srcjar_deps = [ ":bookmark_type_javagen" ]
java_files = [ "java/src/org/chromium/components/bookmarks/BookmarkId.java" ]
}
-# GYP: //components/bookmarks.gyp:bookmarks_jni_headers
generate_jni("bookmarks_jni_headers") {
jni_package = "components/bookmarks"
sources = [
@@ -36,7 +32,6 @@ generate_jni("bookmarks_jni_headers") {
]
}
-# GYP: //components/bookmarks.gyp:bookmarks_type_java
java_cpp_enum("bookmark_type_javagen") {
sources = [
"bookmark_type.h",
diff --git a/chromium/components/bookmarks/common/android/bookmark_id.cc b/chromium/components/bookmarks/common/android/bookmark_id.cc
index 5cac9eeaff4..2f00de64afa 100644
--- a/chromium/components/bookmarks/common/android/bookmark_id.cc
+++ b/chromium/components/bookmarks/common/android/bookmark_id.cc
@@ -22,9 +22,5 @@ base::android::ScopedJavaLocalRef<jobject> JavaBookmarkIdCreateBookmarkId(
return Java_BookmarkId_createBookmarkId(env, id, type);
}
-bool RegisterBookmarkId(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace android
} // namespace bookmarks
diff --git a/chromium/components/bookmarks/common/android/bookmark_id.h b/chromium/components/bookmarks/common/android/bookmark_id.h
index af7ae721d5b..dc9bada7f41 100644
--- a/chromium/components/bookmarks/common/android/bookmark_id.h
+++ b/chromium/components/bookmarks/common/android/bookmark_id.h
@@ -22,8 +22,6 @@ int JavaBookmarkIdGetType(JNIEnv* env, jobject obj);
base::android::ScopedJavaLocalRef<jobject> JavaBookmarkIdCreateBookmarkId(
JNIEnv* env, jlong id, jint type);
-bool RegisterBookmarkId(JNIEnv* env);
-
} // namespace android
} // namespace bookmarks
diff --git a/chromium/components/bookmarks/managed/BUILD.gn b/chromium/components/bookmarks/managed/BUILD.gn
index f2f27659a61..2ad1a0cea30 100644
--- a/chromium/components/bookmarks/managed/BUILD.gn
+++ b/chromium/components/bookmarks/managed/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("managed") {
+static_library("managed") {
sources = [
"managed_bookmark_service.cc",
"managed_bookmark_service.h",
diff --git a/chromium/components/bookmarks/managed/managed_bookmark_service.cc b/chromium/components/bookmarks/managed/managed_bookmark_service.cc
index 9e47b9c6488..b6f9cc76c10 100644
--- a/chromium/components/bookmarks/managed/managed_bookmark_service.cc
+++ b/chromium/components/bookmarks/managed/managed_bookmark_service.cc
@@ -6,6 +6,7 @@
#include <stdint.h>
#include <stdlib.h>
+
#include <utility>
#include <vector>
@@ -68,8 +69,8 @@ BookmarkPermanentNodeList LoadExtraNodes(
ScopedVector<BookmarkPermanentNodeLoader> loaders,
int64_t* next_node_id) {
BookmarkPermanentNodeList extra_nodes;
- for (const auto& loader : loaders)
- extra_nodes.push_back(loader->Load(next_node_id).release());
+ for (auto* loader : loaders)
+ extra_nodes.push_back(loader->Load(next_node_id));
return extra_nodes;
}
diff --git a/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc b/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc
index b72a3c5db94..7ff6f2b0cae 100644
--- a/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc
+++ b/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc
@@ -60,9 +60,10 @@ int64_t ManagedBookmarksTracker::LoadInitial(BookmarkNode* folder,
if (!LoadBookmark(list, i, &title, &url, &children))
continue;
- BookmarkNode* child = new BookmarkNode(next_node_id++, url);
+ BookmarkNode* child =
+ folder->Add(base::MakeUnique<BookmarkNode>(next_node_id++, url),
+ folder->child_count());
child->SetTitle(title);
- folder->Add(child, folder->child_count());
if (children) {
child->set_type(BookmarkNode::FOLDER);
child->set_date_folder_modified(base::Time::Now());
diff --git a/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc b/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
index a3d3bb256ae..837f1e639c6 100644
--- a/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
+++ b/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/files/file_path.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
@@ -62,7 +63,7 @@ class ManagedBookmarksTrackerTest : public testing::Test {
: IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME));
BookmarkPermanentNodeList extra_nodes;
- extra_nodes.push_back(managed_node);
+ extra_nodes.push_back(base::WrapUnique(managed_node));
std::unique_ptr<TestBookmarkClient> client(new TestBookmarkClient);
client->SetExtraNodesToLoad(std::move(extra_nodes));
@@ -98,18 +99,20 @@ class ManagedBookmarksTrackerTest : public testing::Test {
return node && node->HasAncestor(managed_node_);
}
- static base::DictionaryValue* CreateBookmark(const std::string& title,
- const std::string& url) {
+ static std::unique_ptr<base::DictionaryValue> CreateBookmark(
+ const std::string& title,
+ const std::string& url) {
EXPECT_TRUE(GURL(url).is_valid());
- base::DictionaryValue* dict = new base::DictionaryValue();
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("name", title);
dict->SetString("url", GURL(url).spec());
return dict;
}
- static base::DictionaryValue* CreateFolder(const std::string& title,
- base::ListValue* children) {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ static std::unique_ptr<base::DictionaryValue> CreateFolder(
+ const std::string& title,
+ base::ListValue* children) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("name", title);
dict->Set("children", children);
return dict;
@@ -137,7 +140,7 @@ class ManagedBookmarksTrackerTest : public testing::Test {
IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME);
}
- static base::DictionaryValue* CreateExpectedTree() {
+ static std::unique_ptr<base::DictionaryValue> CreateExpectedTree() {
return CreateFolder(GetManagedFolderTitle(), CreateTestTree());
}
diff --git a/chromium/components/browser_sync.gypi b/chromium/components/browser_sync.gypi
deleted file mode 100644
index 50c974a91ef..00000000000
--- a/chromium/components/browser_sync.gypi
+++ /dev/null
@@ -1,111 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/browser_sync_browser
- 'target_name': 'browser_sync_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../sync/sync.gyp:sync',
- '../ui/base/ui_base.gyp:ui_base',
- 'autofill_core_browser',
- 'autofill_core_common',
- 'browser_sync_common',
- 'components_strings.gyp:components_strings',
- 'dom_distiller_core',
- 'generate_version_info',
- 'history_core_browser',
- 'invalidation_impl',
- 'invalidation_public',
- 'keyed_service_core',
- 'password_manager_core_browser',
- 'password_manager_sync_browser',
- 'pref_registry',
- 'signin_core_browser',
- 'syncable_prefs',
- 'sync_bookmarks',
- 'sync_driver',
- 'sync_sessions',
- 'variations',
- 'version_info',
- ],
- 'include_dirs': [
- '..',
- ],
- 'export_dependent_settings': [
- 'sync_driver',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'browser_sync/browser/profile_sync_components_factory_impl.cc',
- 'browser_sync/browser/profile_sync_components_factory_impl.h',
- 'browser_sync/browser/profile_sync_service.cc',
- 'browser_sync/browser/profile_sync_service.h',
- 'browser_sync/browser/signin_confirmation_helper.cc',
- 'browser_sync/browser/signin_confirmation_helper.h',
- ],
- },
- {
- # GN version: //components/browser_sync_common
- 'target_name': 'browser_sync_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'browser_sync/common/browser_sync_switches.cc',
- 'browser_sync/common/browser_sync_switches.h',
- ],
- },
- {
- # GN version: //components/browser_sync/browser:test_support
- 'target_name': 'browser_sync_browser_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../google_apis/google_apis.gyp:google_apis',
- '../sync/sync.gyp:sync',
- '../testing/gmock.gyp:gmock',
- 'bookmarks_browser',
- 'browser_sync_browser',
- 'history_core_browser',
- 'invalidation_impl',
- 'invalidation_test_support',
- 'pref_registry',
- 'signin_core_browser',
- 'signin_core_browser_test_support',
- 'sync_driver',
- 'sync_driver_test_support',
- 'sync_sessions_test_support',
- 'syncable_prefs_test_support',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'browser_sync/browser/abstract_profile_sync_service_test.cc',
- 'browser_sync/browser/abstract_profile_sync_service_test.h',
- 'browser_sync/browser/profile_sync_service_mock.cc',
- 'browser_sync/browser/profile_sync_service_mock.h',
- 'browser_sync/browser/profile_sync_test_util.cc',
- 'browser_sync/browser/profile_sync_test_util.h',
- 'browser_sync/browser/test_http_bridge_factory.cc',
- 'browser_sync/browser/test_http_bridge_factory.h',
- 'browser_sync/browser/test_profile_sync_service.cc',
- 'browser_sync/browser/test_profile_sync_service.h',
- ],
- }
- ],
-}
diff --git a/chromium/components/browser_sync/BUILD.gn b/chromium/components/browser_sync/BUILD.gn
new file mode 100644
index 00000000000..7a42726915e
--- /dev/null
+++ b/chromium/components/browser_sync/BUILD.gn
@@ -0,0 +1,135 @@
+# 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.
+
+import("//build/config/features.gni")
+
+static_library("browser_sync") {
+ sources = [
+ "browser_sync_switches.cc",
+ "browser_sync_switches.h",
+ "profile_sync_components_factory_impl.cc",
+ "profile_sync_components_factory_impl.h",
+ "profile_sync_service.cc",
+ "profile_sync_service.h",
+ "signin_confirmation_helper.cc",
+ "signin_confirmation_helper.h",
+ ]
+
+ public_deps = [
+ "//components/sync",
+ ]
+
+ deps = [
+ "//base",
+ "//components/autofill/core/browser",
+ "//components/autofill/core/common",
+ "//components/dom_distiller/core",
+ "//components/history/core/browser",
+ "//components/invalidation/impl",
+ "//components/invalidation/public",
+ "//components/keyed_service/core",
+ "//components/password_manager/core/browser",
+ "//components/password_manager/sync/browser",
+ "//components/pref_registry",
+ "//components/prefs",
+ "//components/signin/core/browser",
+ "//components/strings",
+ "//components/sync_bookmarks",
+ "//components/sync_sessions",
+ "//components/syncable_prefs",
+ "//components/variations",
+ "//components/version_info",
+ "//components/version_info:generate_version_info",
+ "//google_apis",
+ "//net",
+ "//ui/base",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+
+ sources = [
+ "profile_sync_service_autofill_unittest.cc",
+ "profile_sync_service_bookmark_unittest.cc",
+ "profile_sync_service_startup_unittest.cc",
+ "profile_sync_service_typed_url_unittest.cc",
+ "profile_sync_service_unittest.cc",
+ ]
+
+ deps = [
+ ":browser_sync",
+ ":test_support",
+ "//base",
+ "//base/test:test_support",
+ "//components/autofill/core/browser:test_support",
+ "//components/autofill/core/common:common",
+ "//components/bookmarks/browser:browser",
+ "//components/bookmarks/managed:managed",
+ "//components/bookmarks/test:test",
+ "//components/dom_distiller/core",
+ "//components/history/core/browser:browser",
+ "//components/invalidation/impl",
+ "//components/invalidation/public",
+ "//components/prefs",
+ "//components/signin/core/browser",
+ "//components/signin/core/browser:test_support",
+ "//components/signin/core/common:common",
+ "//components/strings",
+ "//components/sync",
+ "//components/sync:test_support_sync_core_impl",
+ "//components/sync:test_support_sync_driver",
+ "//components/sync_bookmarks:sync_bookmarks",
+ "//components/sync_sessions",
+ "//components/sync_sessions:test_support",
+ "//components/syncable_prefs",
+ "//components/syncable_prefs:test_support",
+ "//components/version_info",
+ "//components/version_info:generate_version_info",
+ "//components/webdata_services:test_support",
+ "//google_apis",
+ "//net",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//ui/base",
+ ]
+}
+
+static_library("test_support") {
+ testonly = true
+ sources = [
+ "abstract_profile_sync_service_test.cc",
+ "abstract_profile_sync_service_test.h",
+ "profile_sync_service_mock.cc",
+ "profile_sync_service_mock.h",
+ "profile_sync_test_util.cc",
+ "profile_sync_test_util.h",
+ "test_http_bridge_factory.cc",
+ "test_http_bridge_factory.h",
+ "test_profile_sync_service.cc",
+ "test_profile_sync_service.h",
+ ]
+
+ deps = [
+ ":browser_sync",
+ "//base",
+ "//base/test:test_support",
+ "//components/bookmarks/browser:browser",
+ "//components/history/core/browser:browser",
+ "//components/invalidation/impl",
+ "//components/invalidation/impl:test_support",
+ "//components/pref_registry",
+ "//components/signin/core/browser:browser",
+ "//components/signin/core/browser:test_support",
+ "//components/sync",
+ "//components/sync:test_support_sync_core",
+ "//components/sync:test_support_sync_core_impl",
+ "//components/sync:test_support_sync_driver",
+ "//components/sync_sessions:test_support",
+ "//components/syncable_prefs:test_support",
+ "//google_apis",
+ "//net:test_support",
+ "//testing/gmock",
+ ]
+}
diff --git a/chromium/components/browser_sync/DEPS b/chromium/components/browser_sync/DEPS
new file mode 100644
index 00000000000..ed67f1144df
--- /dev/null
+++ b/chromium/components/browser_sync/DEPS
@@ -0,0 +1,28 @@
+include_rules = [
+ "+components/autofill/core",
+ "+components/bookmarks/browser",
+ "+components/bookmarks/managed",
+ "+components/bookmarks/test",
+ "+components/dom_distiller/core",
+ "+components/history/core/browser",
+ "+components/invalidation",
+ "+components/keyed_service/core",
+ "+components/password_manager/core/browser",
+ "+components/password_manager/sync/browser",
+ "+components/pref_registry",
+ "+components/prefs",
+ "+components/signin/core/browser",
+ "+components/signin/core/common",
+ "+components/sync",
+ "+components/syncable_prefs",
+ "+components/sync_bookmarks",
+ "+components/sync_sessions",
+ "+components/strings",
+ "+components/variations",
+ "+components/version_info",
+ "+components/webdata/common",
+ "+components/webdata_services",
+ "+google_apis",
+ "+net",
+ "+ui/base/l10n",
+]
diff --git a/chromium/components/browser_sync/abstract_profile_sync_service_test.cc b/chromium/components/browser_sync/abstract_profile_sync_service_test.cc
new file mode 100644
index 00000000000..c1def134bb6
--- /dev/null
+++ b/chromium/components/browser_sync/abstract_profile_sync_service_test.cc
@@ -0,0 +1,239 @@
+// 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 "components/browser_sync/abstract_profile_sync_service_test.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_path.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "components/browser_sync/test_http_bridge_factory.h"
+#include "components/browser_sync/test_profile_sync_service.h"
+#include "components/sync/core/test/sync_manager_factory_for_profile_sync_test.h"
+#include "components/sync/core/test/test_internal_components_factory.h"
+#include "components/sync/core/test/test_user_share.h"
+#include "components/sync/driver/glue/sync_backend_host_core.h"
+#include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "google_apis/gaia/gaia_constants.h"
+
+using syncer::SyncBackendHostImpl;
+using syncer::ModelType;
+using testing::_;
+using testing::Return;
+
+namespace browser_sync {
+
+namespace {
+
+class SyncBackendHostForProfileSyncTest : public SyncBackendHostImpl {
+ public:
+ SyncBackendHostForProfileSyncTest(
+ const base::FilePath& temp_dir,
+ syncer::SyncClient* sync_client,
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
+ invalidation::InvalidationService* invalidator,
+ const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
+ const base::Closure& callback);
+ ~SyncBackendHostForProfileSyncTest() override;
+
+ void RequestConfigureSyncer(
+ syncer::ConfigureReason reason,
+ syncer::ModelTypeSet to_download,
+ syncer::ModelTypeSet to_purge,
+ syncer::ModelTypeSet to_journal,
+ syncer::ModelTypeSet to_unapply,
+ syncer::ModelTypeSet to_ignore,
+ const syncer::ModelSafeRoutingInfo& routing_info,
+ const base::Callback<void(syncer::ModelTypeSet, syncer::ModelTypeSet)>&
+ ready_task,
+ const base::Closure& retry_callback) override;
+
+ protected:
+ void InitCore(std::unique_ptr<syncer::DoInitializeOptions> options) override;
+
+ private:
+ // Invoked at the start of HandleSyncManagerInitializationOnFrontendLoop.
+ // Allows extra initialization work to be performed before the backend comes
+ // up.
+ base::Closure callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncBackendHostForProfileSyncTest);
+};
+
+SyncBackendHostForProfileSyncTest::SyncBackendHostForProfileSyncTest(
+ const base::FilePath& temp_dir,
+ syncer::SyncClient* sync_client,
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
+ invalidation::InvalidationService* invalidator,
+ const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
+ const base::Closure& callback)
+ : SyncBackendHostImpl(
+ "dummy_debug_name",
+ sync_client,
+ ui_thread,
+ invalidator,
+ sync_prefs,
+ temp_dir.Append(base::FilePath(FILE_PATH_LITERAL("test")))),
+ callback_(callback) {}
+
+SyncBackendHostForProfileSyncTest::~SyncBackendHostForProfileSyncTest() {}
+
+void SyncBackendHostForProfileSyncTest::InitCore(
+ std::unique_ptr<syncer::DoInitializeOptions> options) {
+ options->http_bridge_factory =
+ std::unique_ptr<syncer::HttpPostProviderFactory>(
+ new TestHttpBridgeFactory());
+ options->sync_manager_factory.reset(
+ new syncer::SyncManagerFactoryForProfileSyncTest(callback_));
+ options->credentials.email = "testuser@gmail.com";
+ options->credentials.sync_token = "token";
+ options->credentials.scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope);
+ options->restored_key_for_bootstrapping.clear();
+
+ // It'd be nice if we avoided creating the InternalComponentsFactory in the
+ // first place, but SyncBackendHost will have created one by now so we must
+ // free it. Grab the switches to pass on first.
+ syncer::InternalComponentsFactory::Switches factory_switches =
+ options->internal_components_factory->GetSwitches();
+ options->internal_components_factory.reset(
+ new syncer::TestInternalComponentsFactory(
+ factory_switches,
+ syncer::InternalComponentsFactory::STORAGE_IN_MEMORY, nullptr));
+
+ SyncBackendHostImpl::InitCore(std::move(options));
+}
+
+void SyncBackendHostForProfileSyncTest::RequestConfigureSyncer(
+ syncer::ConfigureReason reason,
+ syncer::ModelTypeSet to_download,
+ syncer::ModelTypeSet to_purge,
+ syncer::ModelTypeSet to_journal,
+ syncer::ModelTypeSet to_unapply,
+ syncer::ModelTypeSet to_ignore,
+ const syncer::ModelSafeRoutingInfo& routing_info,
+ const base::Callback<void(syncer::ModelTypeSet, syncer::ModelTypeSet)>&
+ ready_task,
+ const base::Closure& retry_callback) {
+ syncer::ModelTypeSet failed_configuration_types;
+
+ // The first parameter there should be the set of enabled types. That's not
+ // something we have access to from this strange test harness. We'll just
+ // send back the list of newly configured types instead and hope it doesn't
+ // break anything.
+ // Posted to avoid re-entrancy issues.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&SyncBackendHostForProfileSyncTest::
+ FinishConfigureDataTypesOnFrontendLoop,
+ base::Unretained(this),
+ syncer::Difference(to_download, failed_configuration_types),
+ syncer::Difference(to_download, failed_configuration_types),
+ failed_configuration_types, ready_task));
+}
+
+// Helper function for return-type-upcasting of the callback.
+syncer::SyncService* GetSyncService(
+ base::Callback<TestProfileSyncService*(void)> get_sync_service_callback) {
+ return get_sync_service_callback.Run();
+}
+
+} // namespace
+
+/* static */
+syncer::ImmutableChangeRecordList
+ProfileSyncServiceTestHelper::MakeSingletonChangeRecordList(
+ int64_t node_id,
+ syncer::ChangeRecord::Action action) {
+ syncer::ChangeRecord record;
+ record.action = action;
+ record.id = node_id;
+ syncer::ChangeRecordList records(1, record);
+ return syncer::ImmutableChangeRecordList(&records);
+}
+
+/* static */
+syncer::ImmutableChangeRecordList
+ProfileSyncServiceTestHelper::MakeSingletonDeletionChangeRecordList(
+ int64_t node_id,
+ const sync_pb::EntitySpecifics& specifics) {
+ syncer::ChangeRecord record;
+ record.action = syncer::ChangeRecord::ACTION_DELETE;
+ record.id = node_id;
+ record.specifics = specifics;
+ syncer::ChangeRecordList records(1, record);
+ return syncer::ImmutableChangeRecordList(&records);
+}
+
+AbstractProfileSyncServiceTest::AbstractProfileSyncServiceTest()
+ : data_type_thread_("Extra thread") {
+ CHECK(temp_dir_.CreateUniqueTempDir());
+}
+
+AbstractProfileSyncServiceTest::~AbstractProfileSyncServiceTest() {
+ sync_service_->Shutdown();
+}
+
+bool AbstractProfileSyncServiceTest::CreateRoot(ModelType model_type) {
+ return syncer::TestUserShare::CreateRoot(model_type,
+ sync_service_->GetUserShare());
+}
+
+void AbstractProfileSyncServiceTest::CreateSyncService(
+ std::unique_ptr<syncer::SyncClient> sync_client,
+ const base::Closure& initialization_success_callback) {
+ DCHECK(sync_client);
+ ProfileSyncService::InitParams init_params =
+ profile_sync_service_bundle_.CreateBasicInitParams(
+ ProfileSyncService::AUTO_START, std::move(sync_client));
+ sync_service_ =
+ base::MakeUnique<TestProfileSyncService>(std::move(init_params));
+
+ syncer::SyncApiComponentFactoryMock* components =
+ profile_sync_service_bundle_.component_factory();
+ EXPECT_CALL(*components, CreateSyncBackendHost(_, _, _, _))
+ .WillOnce(Return(new SyncBackendHostForProfileSyncTest(
+ temp_dir_.GetPath(), sync_service_->GetSyncClient(),
+ base::ThreadTaskRunnerHandle::Get(),
+ profile_sync_service_bundle_.fake_invalidation_service(),
+ sync_service_->sync_prefs()->AsWeakPtr(),
+ initialization_success_callback)));
+
+ sync_service_->SetFirstSetupComplete();
+}
+
+base::Callback<syncer::SyncService*(void)>
+AbstractProfileSyncServiceTest::GetSyncServiceCallback() {
+ return base::Bind(GetSyncService,
+ base::Bind(&AbstractProfileSyncServiceTest::sync_service,
+ base::Unretained(this)));
+}
+
+CreateRootHelper::CreateRootHelper(AbstractProfileSyncServiceTest* test,
+ ModelType model_type)
+ : callback_(base::Bind(&CreateRootHelper::CreateRootCallback,
+ base::Unretained(this))),
+ test_(test),
+ model_type_(model_type),
+ success_(false) {}
+
+CreateRootHelper::~CreateRootHelper() {}
+
+const base::Closure& CreateRootHelper::callback() const {
+ return callback_;
+}
+
+bool CreateRootHelper::success() {
+ return success_;
+}
+
+void CreateRootHelper::CreateRootCallback() {
+ success_ = test_->CreateRoot(model_type_);
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/abstract_profile_sync_service_test.h b/chromium/components/browser_sync/abstract_profile_sync_service_test.h
new file mode 100644
index 00000000000..4fc8cd3c746
--- /dev/null
+++ b/chromium/components/browser_sync/abstract_profile_sync_service_test.h
@@ -0,0 +1,110 @@
+// 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 COMPONENTS_BROWSER_SYNC_ABSTRACT_PROFILE_SYNC_SERVICE_TEST_H_
+#define COMPONENTS_BROWSER_SYNC_ABSTRACT_PROFILE_SYNC_SERVICE_TEST_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/test/test_message_loop.h"
+#include "components/browser_sync/profile_sync_test_util.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/core/change_record.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+struct UserShare;
+} // namespace syncer
+
+namespace browser_sync {
+
+class TestProfileSyncService;
+
+class ProfileSyncServiceTestHelper {
+ public:
+ static syncer::ImmutableChangeRecordList MakeSingletonChangeRecordList(
+ int64_t node_id,
+ syncer::ChangeRecord::Action action);
+
+ // Deletions must provide an EntitySpecifics for the deleted data.
+ static syncer::ImmutableChangeRecordList
+ MakeSingletonDeletionChangeRecordList(
+ int64_t node_id,
+ const sync_pb::EntitySpecifics& specifics);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceTestHelper);
+};
+
+class AbstractProfileSyncServiceTest : public testing::Test {
+ public:
+ AbstractProfileSyncServiceTest();
+ ~AbstractProfileSyncServiceTest() override;
+
+ bool CreateRoot(syncer::ModelType model_type);
+
+ protected:
+ // Creates a TestProfileSyncService instance based on
+ // |profile_sync_service_bundle_|, with start behavior AUTO_START. Passes
+ // |callback| down to SyncManagerForProfileSyncTest to be used by
+ // NotifyInitializationSuccess. |sync_client| is passed to the service. The
+ // created service is stored in |sync_service_|.
+ void CreateSyncService(std::unique_ptr<syncer::SyncClient> sync_client,
+ const base::Closure& initialization_success_callback);
+
+ base::Thread* data_type_thread() { return &data_type_thread_; }
+
+ TestProfileSyncService* sync_service() { return sync_service_.get(); }
+
+ // Returns the callback for the FakeSyncClient builder. It is not possible to
+ // just Bind() sync_service(), because of Callback not understanding the
+ // inheritance of its template arguments.
+ base::Callback<syncer::SyncService*(void)> GetSyncServiceCallback();
+
+ ProfileSyncServiceBundle* profile_sync_service_bundle() {
+ return &profile_sync_service_bundle_;
+ }
+
+ private:
+ // Use |data_type_thread_| for code disallowed on the UI thread.
+ base::Thread data_type_thread_;
+
+ base::TestMessageLoop message_loop_;
+ ProfileSyncServiceBundle profile_sync_service_bundle_;
+ std::unique_ptr<TestProfileSyncService> sync_service_;
+
+ base::ScopedTempDir temp_dir_; // To pass to the backend host.
+
+ DISALLOW_COPY_AND_ASSIGN(AbstractProfileSyncServiceTest);
+};
+
+class CreateRootHelper {
+ public:
+ CreateRootHelper(AbstractProfileSyncServiceTest* test,
+ syncer::ModelType model_type);
+ virtual ~CreateRootHelper();
+
+ const base::Closure& callback() const;
+ bool success();
+
+ private:
+ void CreateRootCallback();
+
+ base::Closure callback_;
+ AbstractProfileSyncServiceTest* test_;
+ syncer::ModelType model_type_;
+ bool success_;
+
+ DISALLOW_COPY_AND_ASSIGN(CreateRootHelper);
+};
+
+} // namespace browser_sync
+
+#endif // COMPONENTS_BROWSER_SYNC_ABSTRACT_PROFILE_SYNC_SERVICE_TEST_H_
diff --git a/chromium/components/browser_sync/browser/BUILD.gn b/chromium/components/browser_sync/browser/BUILD.gn
deleted file mode 100644
index b44150cfe40..00000000000
--- a/chromium/components/browser_sync/browser/BUILD.gn
+++ /dev/null
@@ -1,136 +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.
-
-import("//build/config/features.gni")
-
-source_set("browser") {
- sources = [
- "profile_sync_components_factory_impl.cc",
- "profile_sync_components_factory_impl.h",
- "profile_sync_service.cc",
- "profile_sync_service.h",
- "signin_confirmation_helper.cc",
- "signin_confirmation_helper.h",
- ]
-
- public_deps = [
- "//components/sync_driver",
- ]
-
- deps = [
- "//base",
- "//components/autofill/core/browser",
- "//components/autofill/core/common",
- "//components/browser_sync/common",
- "//components/dom_distiller/core",
- "//components/history/core/browser",
- "//components/invalidation/impl",
- "//components/invalidation/public",
- "//components/keyed_service/core",
- "//components/password_manager/core/browser",
- "//components/password_manager/sync/browser",
- "//components/pref_registry",
- "//components/prefs",
- "//components/signin/core/browser",
- "//components/strings",
- "//components/sync_bookmarks",
- "//components/sync_sessions",
- "//components/syncable_prefs",
- "//components/variations",
- "//components/version_info",
- "//components/version_info:generate_version_info",
- "//google_apis",
- "//net",
- "//sync",
- "//ui/base",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
-
- sources = [
- "profile_sync_service_autofill_unittest.cc",
- "profile_sync_service_bookmark_unittest.cc",
- "profile_sync_service_startup_unittest.cc",
- "profile_sync_service_typed_url_unittest.cc",
- "profile_sync_service_unittest.cc",
- ]
-
- deps = [
- ":browser",
- ":test_support",
- "//base",
- "//base/test:test_support",
- "//components/autofill/core/browser:test_support",
- "//components/autofill/core/common:common",
- "//components/bookmarks/browser:browser",
- "//components/bookmarks/managed:managed",
- "//components/bookmarks/test:test",
- "//components/browser_sync/common",
- "//components/dom_distiller/core",
- "//components/history/core/browser:browser",
- "//components/invalidation/impl",
- "//components/invalidation/public",
- "//components/prefs",
- "//components/signin/core/browser",
- "//components/signin/core/browser:test_support",
- "//components/signin/core/common:common",
- "//components/strings",
- "//components/sync_bookmarks:sync_bookmarks",
- "//components/sync_driver",
- "//components/sync_driver:test_support",
- "//components/sync_sessions",
- "//components/sync_sessions:test_support",
- "//components/syncable_prefs",
- "//components/syncable_prefs:test_support",
- "//components/version_info",
- "//components/version_info:generate_version_info",
- "//components/webdata_services:test_support",
- "//google_apis",
- "//net",
- "//sync:test_support_sync_internal_api",
- "//testing/gmock",
- "//testing/gtest",
- "//ui/base",
- ]
-}
-
-source_set("test_support") {
- testonly = true
- sources = [
- "abstract_profile_sync_service_test.cc",
- "abstract_profile_sync_service_test.h",
- "profile_sync_service_mock.cc",
- "profile_sync_service_mock.h",
- "profile_sync_test_util.cc",
- "profile_sync_test_util.h",
- "test_http_bridge_factory.cc",
- "test_http_bridge_factory.h",
- "test_profile_sync_service.cc",
- "test_profile_sync_service.h",
- ]
-
- deps = [
- ":browser",
- "//base",
- "//base/test:test_support",
- "//components/bookmarks/browser:browser",
- "//components/history/core/browser:browser",
- "//components/invalidation/impl",
- "//components/invalidation/impl:test_support",
- "//components/pref_registry",
- "//components/signin/core/browser:browser",
- "//components/signin/core/browser:test_support",
- "//components/sync_driver",
- "//components/sync_driver:test_support",
- "//components/sync_sessions:test_support",
- "//components/syncable_prefs:test_support",
- "//google_apis",
- "//net:test_support",
- "//sync:test_support_sync_core",
- "//sync:test_support_sync_internal_api",
- "//testing/gmock",
- ]
-}
diff --git a/chromium/components/browser_sync/browser/DEPS b/chromium/components/browser_sync/browser/DEPS
deleted file mode 100644
index 7b3e9c32752..00000000000
--- a/chromium/components/browser_sync/browser/DEPS
+++ /dev/null
@@ -1,29 +0,0 @@
-include_rules = [
- "+components/autofill/core",
- "+components/bookmarks/browser",
- "+components/bookmarks/managed",
- "+components/bookmarks/test",
- "+components/dom_distiller/core",
- "+components/history/core/browser",
- "+components/invalidation",
- "+components/keyed_service/core",
- "+components/password_manager/core/browser",
- "+components/password_manager/sync/browser",
- "+components/pref_registry",
- "+components/prefs",
- "+components/signin/core/browser",
- "+components/signin/core/common",
- "+components/syncable_prefs",
- "+components/sync_bookmarks",
- "+components/sync_driver",
- "+components/sync_sessions",
- "+components/strings",
- "+components/variations",
- "+components/version_info",
- "+components/webdata/common",
- "+components/webdata_services",
- "+google_apis",
- "+net",
- "+sync",
- "+ui/base/l10n",
-]
diff --git a/chromium/components/browser_sync/browser/abstract_profile_sync_service_test.cc b/chromium/components/browser_sync/browser/abstract_profile_sync_service_test.cc
deleted file mode 100644
index dba623d53df..00000000000
--- a/chromium/components/browser_sync/browser/abstract_profile_sync_service_test.cc
+++ /dev/null
@@ -1,238 +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 "components/browser_sync/browser/abstract_profile_sync_service_test.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/files/file_path.h"
-#include "base/location.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "components/browser_sync/browser/test_http_bridge_factory.h"
-#include "components/browser_sync/browser/test_profile_sync_service.h"
-#include "components/sync_driver/glue/sync_backend_host_core.h"
-#include "components/sync_driver/sync_api_component_factory_mock.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "sync/internal_api/public/test/sync_manager_factory_for_profile_sync_test.h"
-#include "sync/internal_api/public/test/test_internal_components_factory.h"
-#include "sync/internal_api/public/test/test_user_share.h"
-#include "sync/protocol/sync.pb.h"
-
-using syncer::ModelType;
-using testing::_;
-using testing::Return;
-
-namespace {
-
-class SyncBackendHostForProfileSyncTest
- : public browser_sync::SyncBackendHostImpl {
- public:
- SyncBackendHostForProfileSyncTest(
- const base::FilePath& temp_dir,
- sync_driver::SyncClient* sync_client,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- invalidation::InvalidationService* invalidator,
- const base::WeakPtr<sync_driver::SyncPrefs>& sync_prefs,
- const base::Closure& callback);
- ~SyncBackendHostForProfileSyncTest() override;
-
- void RequestConfigureSyncer(
- syncer::ConfigureReason reason,
- syncer::ModelTypeSet to_download,
- syncer::ModelTypeSet to_purge,
- syncer::ModelTypeSet to_journal,
- syncer::ModelTypeSet to_unapply,
- syncer::ModelTypeSet to_ignore,
- const syncer::ModelSafeRoutingInfo& routing_info,
- const base::Callback<void(syncer::ModelTypeSet, syncer::ModelTypeSet)>&
- ready_task,
- const base::Closure& retry_callback) override;
-
- protected:
- void InitCore(
- std::unique_ptr<browser_sync::DoInitializeOptions> options) override;
-
- private:
- // Invoked at the start of HandleSyncManagerInitializationOnFrontendLoop.
- // Allows extra initialization work to be performed before the backend comes
- // up.
- base::Closure callback_;
-
- DISALLOW_COPY_AND_ASSIGN(SyncBackendHostForProfileSyncTest);
-};
-
-SyncBackendHostForProfileSyncTest::SyncBackendHostForProfileSyncTest(
- const base::FilePath& temp_dir,
- sync_driver::SyncClient* sync_client,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- invalidation::InvalidationService* invalidator,
- const base::WeakPtr<sync_driver::SyncPrefs>& sync_prefs,
- const base::Closure& callback)
- : browser_sync::SyncBackendHostImpl(
- "dummy_debug_name",
- sync_client,
- ui_thread,
- invalidator,
- sync_prefs,
- temp_dir.Append(base::FilePath(FILE_PATH_LITERAL("test")))),
- callback_(callback) {}
-
-SyncBackendHostForProfileSyncTest::~SyncBackendHostForProfileSyncTest() {}
-
-void SyncBackendHostForProfileSyncTest::InitCore(
- std::unique_ptr<browser_sync::DoInitializeOptions> options) {
- options->http_bridge_factory =
- std::unique_ptr<syncer::HttpPostProviderFactory>(
- new browser_sync::TestHttpBridgeFactory());
- options->sync_manager_factory.reset(
- new syncer::SyncManagerFactoryForProfileSyncTest(callback_));
- options->credentials.email = "testuser@gmail.com";
- options->credentials.sync_token = "token";
- options->credentials.scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope);
- options->restored_key_for_bootstrapping.clear();
-
- // It'd be nice if we avoided creating the InternalComponentsFactory in the
- // first place, but SyncBackendHost will have created one by now so we must
- // free it. Grab the switches to pass on first.
- syncer::InternalComponentsFactory::Switches factory_switches =
- options->internal_components_factory->GetSwitches();
- options->internal_components_factory.reset(
- new syncer::TestInternalComponentsFactory(
- factory_switches,
- syncer::InternalComponentsFactory::STORAGE_IN_MEMORY, nullptr));
-
- browser_sync::SyncBackendHostImpl::InitCore(std::move(options));
-}
-
-void SyncBackendHostForProfileSyncTest::RequestConfigureSyncer(
- syncer::ConfigureReason reason,
- syncer::ModelTypeSet to_download,
- syncer::ModelTypeSet to_purge,
- syncer::ModelTypeSet to_journal,
- syncer::ModelTypeSet to_unapply,
- syncer::ModelTypeSet to_ignore,
- const syncer::ModelSafeRoutingInfo& routing_info,
- const base::Callback<void(syncer::ModelTypeSet, syncer::ModelTypeSet)>&
- ready_task,
- const base::Closure& retry_callback) {
- syncer::ModelTypeSet failed_configuration_types;
-
- // The first parameter there should be the set of enabled types. That's not
- // something we have access to from this strange test harness. We'll just
- // send back the list of newly configured types instead and hope it doesn't
- // break anything.
- // Posted to avoid re-entrancy issues.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&SyncBackendHostForProfileSyncTest::
- FinishConfigureDataTypesOnFrontendLoop,
- base::Unretained(this),
- syncer::Difference(to_download, failed_configuration_types),
- syncer::Difference(to_download, failed_configuration_types),
- failed_configuration_types, ready_task));
-}
-
-// Helper function for return-type-upcasting of the callback.
-sync_driver::SyncService* GetSyncService(
- base::Callback<TestProfileSyncService*(void)> get_sync_service_callback) {
- return get_sync_service_callback.Run();
-}
-
-} // namespace
-
-/* static */
-syncer::ImmutableChangeRecordList
-ProfileSyncServiceTestHelper::MakeSingletonChangeRecordList(
- int64_t node_id,
- syncer::ChangeRecord::Action action) {
- syncer::ChangeRecord record;
- record.action = action;
- record.id = node_id;
- syncer::ChangeRecordList records(1, record);
- return syncer::ImmutableChangeRecordList(&records);
-}
-
-/* static */
-syncer::ImmutableChangeRecordList
-ProfileSyncServiceTestHelper::MakeSingletonDeletionChangeRecordList(
- int64_t node_id,
- const sync_pb::EntitySpecifics& specifics) {
- syncer::ChangeRecord record;
- record.action = syncer::ChangeRecord::ACTION_DELETE;
- record.id = node_id;
- record.specifics = specifics;
- syncer::ChangeRecordList records(1, record);
- return syncer::ImmutableChangeRecordList(&records);
-}
-
-AbstractProfileSyncServiceTest::AbstractProfileSyncServiceTest()
- : data_type_thread_("Extra thread") {
- CHECK(temp_dir_.CreateUniqueTempDir());
-}
-
-AbstractProfileSyncServiceTest::~AbstractProfileSyncServiceTest() {
- sync_service_->Shutdown();
-}
-
-bool AbstractProfileSyncServiceTest::CreateRoot(ModelType model_type) {
- return syncer::TestUserShare::CreateRoot(model_type,
- sync_service_->GetUserShare());
-}
-
-void AbstractProfileSyncServiceTest::CreateSyncService(
- std::unique_ptr<sync_driver::SyncClient> sync_client,
- const base::Closure& initialization_success_callback) {
- DCHECK(sync_client);
- ProfileSyncService::InitParams init_params =
- profile_sync_service_bundle_.CreateBasicInitParams(
- ProfileSyncService::AUTO_START, std::move(sync_client));
- sync_service_ =
- base::WrapUnique(new TestProfileSyncService(std::move(init_params)));
-
- SyncApiComponentFactoryMock* components =
- profile_sync_service_bundle_.component_factory();
- EXPECT_CALL(*components, CreateSyncBackendHost(_, _, _, _))
- .WillOnce(Return(new SyncBackendHostForProfileSyncTest(
- temp_dir_.path(), sync_service_->GetSyncClient(),
- base::ThreadTaskRunnerHandle::Get(),
- profile_sync_service_bundle_.fake_invalidation_service(),
- sync_service_->sync_prefs()->AsWeakPtr(),
- initialization_success_callback)));
-
- sync_service_->SetFirstSetupComplete();
-}
-
-base::Callback<sync_driver::SyncService*(void)>
-AbstractProfileSyncServiceTest::GetSyncServiceCallback() {
- return base::Bind(GetSyncService,
- base::Bind(&AbstractProfileSyncServiceTest::sync_service,
- base::Unretained(this)));
-}
-
-CreateRootHelper::CreateRootHelper(AbstractProfileSyncServiceTest* test,
- ModelType model_type)
- : callback_(base::Bind(&CreateRootHelper::CreateRootCallback,
- base::Unretained(this))),
- test_(test),
- model_type_(model_type),
- success_(false) {
-}
-
-CreateRootHelper::~CreateRootHelper() {
-}
-
-const base::Closure& CreateRootHelper::callback() const {
- return callback_;
-}
-
-bool CreateRootHelper::success() {
- return success_;
-}
-
-void CreateRootHelper::CreateRootCallback() {
- success_ = test_->CreateRoot(model_type_);
-}
diff --git a/chromium/components/browser_sync/browser/abstract_profile_sync_service_test.h b/chromium/components/browser_sync/browser/abstract_profile_sync_service_test.h
deleted file mode 100644
index adce5e9bf28..00000000000
--- a/chromium/components/browser_sync/browser/abstract_profile_sync_service_test.h
+++ /dev/null
@@ -1,107 +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 COMPONENTS_BROWSER_SYNC_BROWSER_ABSTRACT_PROFILE_SYNC_SERVICE_TEST_H_
-#define COMPONENTS_BROWSER_SYNC_BROWSER_ABSTRACT_PROFILE_SYNC_SERVICE_TEST_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/macros.h"
-#include "base/test/test_message_loop.h"
-#include "components/browser_sync/browser/profile_sync_test_util.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/internal_api/public/change_record.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class TestProfileSyncService;
-
-namespace syncer {
-struct UserShare;
-} // namespace syncer
-
-class ProfileSyncServiceTestHelper {
- public:
- static syncer::ImmutableChangeRecordList MakeSingletonChangeRecordList(
- int64_t node_id,
- syncer::ChangeRecord::Action action);
-
- // Deletions must provide an EntitySpecifics for the deleted data.
- static syncer::ImmutableChangeRecordList
- MakeSingletonDeletionChangeRecordList(
- int64_t node_id,
- const sync_pb::EntitySpecifics& specifics);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceTestHelper);
-};
-
-class AbstractProfileSyncServiceTest : public testing::Test {
- public:
- AbstractProfileSyncServiceTest();
- ~AbstractProfileSyncServiceTest() override;
-
- bool CreateRoot(syncer::ModelType model_type);
-
- protected:
- // Creates a TestProfileSyncService instance based on
- // |profile_sync_service_bundle_|, with start behavior
- // browser_sync::AUTO_START. Passes |callback| down to
- // SyncManagerForProfileSyncTest to be used by NotifyInitializationSuccess.
- // |sync_client| is passed to the service. The created service is stored in
- // |sync_service_|.
- void CreateSyncService(std::unique_ptr<sync_driver::SyncClient> sync_client,
- const base::Closure& initialization_success_callback);
-
- base::Thread* data_type_thread() { return &data_type_thread_; }
-
- TestProfileSyncService* sync_service() { return sync_service_.get(); }
-
- // Returns the callback for the FakeSyncClient builder. It is not possible to
- // just Bind() sync_service(), because of Callback not understanding the
- // inheritance of its template arguments.
- base::Callback<sync_driver::SyncService*(void)> GetSyncServiceCallback();
-
- browser_sync::ProfileSyncServiceBundle* profile_sync_service_bundle() {
- return &profile_sync_service_bundle_;
- }
-
- private:
- // Use |data_type_thread_| for code disallowed on the UI thread.
- base::Thread data_type_thread_;
-
- base::TestMessageLoop message_loop_;
- browser_sync::ProfileSyncServiceBundle profile_sync_service_bundle_;
- std::unique_ptr<TestProfileSyncService> sync_service_;
-
- base::ScopedTempDir temp_dir_; // To pass to the backend host.
-
- DISALLOW_COPY_AND_ASSIGN(AbstractProfileSyncServiceTest);
-};
-
-class CreateRootHelper {
- public:
- CreateRootHelper(AbstractProfileSyncServiceTest* test,
- syncer::ModelType model_type);
- virtual ~CreateRootHelper();
-
- const base::Closure& callback() const;
- bool success();
-
- private:
- void CreateRootCallback();
-
- base::Closure callback_;
- AbstractProfileSyncServiceTest* test_;
- syncer::ModelType model_type_;
- bool success_;
-
- DISALLOW_COPY_AND_ASSIGN(CreateRootHelper);
-};
-
-#endif // COMPONENTS_BROWSER_SYNC_BROWSER_ABSTRACT_PROFILE_SYNC_SERVICE_TEST_H_
diff --git a/chromium/components/browser_sync/browser/profile_sync_components_factory_impl.cc b/chromium/components/browser_sync/browser/profile_sync_components_factory_impl.cc
deleted file mode 100644
index c15a8797e15..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_components_factory_impl.cc
+++ /dev/null
@@ -1,392 +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 "components/browser_sync/browser/profile_sync_components_factory_impl.h"
-
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "build/build_config.h"
-#include "components/autofill/core/browser/autofill_wallet_data_type_controller.h"
-#include "components/autofill/core/browser/webdata/autofill_data_type_controller.h"
-#include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/core/common/autofill_pref_names.h"
-#include "components/autofill/core/common/autofill_switches.h"
-#include "components/browser_sync/browser/profile_sync_service.h"
-#include "components/browser_sync/common/browser_sync_switches.h"
-#include "components/dom_distiller/core/dom_distiller_features.h"
-#include "components/history/core/browser/history_delete_directives_data_type_controller.h"
-#include "components/history/core/browser/typed_url_data_type_controller.h"
-#include "components/password_manager/core/browser/password_store.h"
-#include "components/password_manager/sync/browser/password_data_type_controller.h"
-#include "components/prefs/pref_service.h"
-#include "components/sync_bookmarks/bookmark_change_processor.h"
-#include "components/sync_bookmarks/bookmark_data_type_controller.h"
-#include "components/sync_bookmarks/bookmark_model_associator.h"
-#include "components/sync_driver/data_type_manager_impl.h"
-#include "components/sync_driver/device_info_data_type_controller.h"
-#include "components/sync_driver/glue/chrome_report_unrecoverable_error.h"
-#include "components/sync_driver/glue/sync_backend_host.h"
-#include "components/sync_driver/glue/sync_backend_host_impl.h"
-#include "components/sync_driver/local_device_info_provider_impl.h"
-#include "components/sync_driver/proxy_data_type_controller.h"
-#include "components/sync_driver/sync_client.h"
-#include "components/sync_driver/sync_driver_switches.h"
-#include "components/sync_driver/ui_data_type_controller.h"
-#include "components/sync_driver/ui_model_type_controller.h"
-#include "components/sync_sessions/session_data_type_controller.h"
-#include "google_apis/gaia/oauth2_token_service.h"
-#include "google_apis/gaia/oauth2_token_service_request.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "sync/internal_api/public/attachments/attachment_downloader.h"
-#include "sync/internal_api/public/attachments/attachment_service.h"
-#include "sync/internal_api/public/attachments/attachment_service_impl.h"
-#include "sync/internal_api/public/attachments/attachment_uploader_impl.h"
-
-using bookmarks::BookmarkModel;
-using browser_sync::AutofillDataTypeController;
-using browser_sync::AutofillProfileDataTypeController;
-using browser_sync::BookmarkChangeProcessor;
-using browser_sync::BookmarkDataTypeController;
-using browser_sync::BookmarkModelAssociator;
-using browser_sync::ChromeReportUnrecoverableError;
-using browser_sync::HistoryDeleteDirectivesDataTypeController;
-using browser_sync::PasswordDataTypeController;
-using browser_sync::SessionDataTypeController;
-using browser_sync::SyncBackendHost;
-using browser_sync::TypedUrlDataTypeController;
-using sync_driver::DataTypeController;
-using syncer::DataTypeErrorHandler;
-using sync_driver::DataTypeManager;
-using sync_driver::DataTypeManagerImpl;
-using sync_driver::DataTypeManagerObserver;
-using sync_driver::DeviceInfoDataTypeController;
-using sync_driver::ProxyDataTypeController;
-using sync_driver::UIDataTypeController;
-using sync_driver_v2::UIModelTypeController;
-
-namespace {
-
-syncer::ModelTypeSet GetDisabledTypesFromCommandLine(
- const base::CommandLine& command_line) {
- syncer::ModelTypeSet disabled_types;
- std::string disabled_types_str =
- command_line.GetSwitchValueASCII(switches::kDisableSyncTypes);
-
- disabled_types = syncer::ModelTypeSetFromString(disabled_types_str);
- return disabled_types;
-}
-
-syncer::ModelTypeSet GetEnabledTypesFromCommandLine(
- const base::CommandLine& command_line) {
- return syncer::ModelTypeSet();
-}
-
-} // namespace
-
-ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl(
- sync_driver::SyncClient* sync_client,
- version_info::Channel channel,
- const std::string& version,
- bool is_tablet,
- const base::CommandLine& command_line,
- const char* history_disabled_pref,
- const GURL& sync_service_url,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
- OAuth2TokenService* token_service,
- net::URLRequestContextGetter* url_request_context_getter,
- const scoped_refptr<autofill::AutofillWebDataService>& web_data_service,
- const scoped_refptr<password_manager::PasswordStore>& password_store)
- : sync_client_(sync_client),
- channel_(channel),
- version_(version),
- is_tablet_(is_tablet),
- command_line_(command_line),
- history_disabled_pref_(history_disabled_pref),
- sync_service_url_(sync_service_url),
- ui_thread_(ui_thread),
- db_thread_(db_thread),
- token_service_(token_service),
- url_request_context_getter_(url_request_context_getter),
- web_data_service_(web_data_service),
- password_store_(password_store),
- weak_factory_(this) {
- DCHECK(token_service_);
- DCHECK(url_request_context_getter_);
-}
-
-ProfileSyncComponentsFactoryImpl::~ProfileSyncComponentsFactoryImpl() {}
-
-void ProfileSyncComponentsFactoryImpl::RegisterDataTypes(
- sync_driver::SyncService* sync_service,
- const RegisterDataTypesMethod& register_platform_types_method) {
- syncer::ModelTypeSet disabled_types =
- GetDisabledTypesFromCommandLine(command_line_);
- syncer::ModelTypeSet enabled_types =
- GetEnabledTypesFromCommandLine(command_line_);
- RegisterCommonDataTypes(sync_service, disabled_types, enabled_types);
- if (!register_platform_types_method.is_null())
- register_platform_types_method.Run(sync_service, disabled_types,
- enabled_types);
-}
-
-void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
- sync_driver::SyncService* sync_service,
- syncer::ModelTypeSet disabled_types,
- syncer::ModelTypeSet enabled_types) {
- base::Closure error_callback =
- base::Bind(&ChromeReportUnrecoverableError, channel_);
-
- // TODO(stanisc): can DEVICE_INFO be one of disabled datatypes?
- if (channel_ == version_info::Channel::UNKNOWN &&
- command_line_.HasSwitch(switches::kSyncEnableUSSDeviceInfo)) {
- sync_service->RegisterDataTypeController(new UIModelTypeController(
- ui_thread_, error_callback, syncer::DEVICE_INFO, sync_client_));
- } else {
- sync_service->RegisterDataTypeController(new DeviceInfoDataTypeController(
- ui_thread_, error_callback, sync_client_,
- sync_service->GetLocalDeviceInfoProvider()));
- }
-
- // Autofill sync is enabled by default. Register unless explicitly
- // disabled.
- if (!disabled_types.Has(syncer::AUTOFILL)) {
- sync_service->RegisterDataTypeController(
- new AutofillDataTypeController(ui_thread_, db_thread_, error_callback,
- sync_client_, web_data_service_));
- }
-
- // Autofill profile sync is enabled by default. Register unless explicitly
- // disabled.
- if (!disabled_types.Has(syncer::AUTOFILL_PROFILE)) {
- sync_service->RegisterDataTypeController(
- new AutofillProfileDataTypeController(ui_thread_, db_thread_,
- error_callback, sync_client_,
- web_data_service_));
- }
-
- // Wallet data sync is enabled by default, but behind a syncer experiment
- // enforced by the datatype controller. Register unless explicitly disabled.
- bool wallet_disabled = disabled_types.Has(syncer::AUTOFILL_WALLET_DATA);
- if (!wallet_disabled) {
- sync_service->RegisterDataTypeController(
- new browser_sync::AutofillWalletDataTypeController(
- ui_thread_, db_thread_, error_callback, sync_client_,
- syncer::AUTOFILL_WALLET_DATA, web_data_service_));
- }
-
- // Wallet metadata sync depends on Wallet data sync. Register if Wallet data
- // is syncing and metadata sync is not explicitly disabled.
- if (!wallet_disabled &&
- !disabled_types.Has(syncer::AUTOFILL_WALLET_METADATA)) {
- sync_service->RegisterDataTypeController(
- new browser_sync::AutofillWalletDataTypeController(
- ui_thread_, db_thread_, error_callback, sync_client_,
- syncer::AUTOFILL_WALLET_METADATA, web_data_service_));
- }
-
- // Bookmark sync is enabled by default. Register unless explicitly
- // disabled.
- if (!disabled_types.Has(syncer::BOOKMARKS)) {
- sync_service->RegisterDataTypeController(new BookmarkDataTypeController(
- ui_thread_, error_callback, sync_client_));
- }
-
- const bool history_disabled =
- sync_client_->GetPrefService()->GetBoolean(history_disabled_pref_);
- // TypedUrl sync is enabled by default. Register unless explicitly disabled,
- // or if saving history is disabled.
- if (!disabled_types.Has(syncer::TYPED_URLS) && !history_disabled) {
- sync_service->RegisterDataTypeController(new TypedUrlDataTypeController(
- ui_thread_, error_callback, sync_client_, history_disabled_pref_));
- }
-
- // Delete directive sync is enabled by default. Register unless full history
- // sync is disabled.
- if (!disabled_types.Has(syncer::HISTORY_DELETE_DIRECTIVES) &&
- !history_disabled) {
- sync_service->RegisterDataTypeController(
- new HistoryDeleteDirectivesDataTypeController(
- ui_thread_, error_callback, sync_client_));
- }
-
- // Session sync is enabled by default. Register unless explicitly disabled.
- // This is also disabled if the browser history is disabled, because the
- // tab sync data is added to the web history on the server.
- if (!disabled_types.Has(syncer::PROXY_TABS) && !history_disabled) {
- sync_service->RegisterDataTypeController(
- new ProxyDataTypeController(ui_thread_, syncer::PROXY_TABS));
- sync_service->RegisterDataTypeController(new SessionDataTypeController(
- ui_thread_, error_callback, sync_client_,
- sync_service->GetLocalDeviceInfoProvider(), history_disabled_pref_));
- }
-
- // Favicon sync is enabled by default. Register unless explicitly disabled.
- if (!disabled_types.Has(syncer::FAVICON_IMAGES) &&
- !disabled_types.Has(syncer::FAVICON_TRACKING) && !history_disabled) {
- // crbug/384552. We disable error uploading for this data types for now.
- sync_service->RegisterDataTypeController(new UIDataTypeController(
- ui_thread_, base::Closure(), syncer::FAVICON_IMAGES, sync_client_));
- sync_service->RegisterDataTypeController(new UIDataTypeController(
- ui_thread_, base::Closure(), syncer::FAVICON_TRACKING, sync_client_));
- }
-
- // Password sync is enabled by default. Register unless explicitly
- // disabled.
- if (!disabled_types.Has(syncer::PASSWORDS)) {
- sync_service->RegisterDataTypeController(new PasswordDataTypeController(
- ui_thread_, error_callback, sync_client_,
- sync_client_->GetPasswordStateChangedCallback(), password_store_));
- }
-
- if (!disabled_types.Has(syncer::PRIORITY_PREFERENCES)) {
- sync_service->RegisterDataTypeController(
- new UIDataTypeController(ui_thread_, error_callback,
- syncer::PRIORITY_PREFERENCES, sync_client_));
- }
-
- // Article sync is disabled by default. Register only if explicitly enabled.
- if (dom_distiller::IsEnableSyncArticlesSet()) {
- sync_service->RegisterDataTypeController(new UIDataTypeController(
- ui_thread_, error_callback, syncer::ARTICLES, sync_client_));
- }
-}
-
-DataTypeManager* ProfileSyncComponentsFactoryImpl::CreateDataTypeManager(
- const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
- debug_info_listener,
- const DataTypeController::TypeMap* controllers,
- const sync_driver::DataTypeEncryptionHandler* encryption_handler,
- SyncBackendHost* backend,
- DataTypeManagerObserver* observer) {
- return new DataTypeManagerImpl(debug_info_listener, controllers,
- encryption_handler, backend, observer);
-}
-
-browser_sync::SyncBackendHost*
-ProfileSyncComponentsFactoryImpl::CreateSyncBackendHost(
- const std::string& name,
- invalidation::InvalidationService* invalidator,
- const base::WeakPtr<sync_driver::SyncPrefs>& sync_prefs,
- const base::FilePath& sync_folder) {
- return new browser_sync::SyncBackendHostImpl(
- name, sync_client_, ui_thread_, invalidator, sync_prefs, sync_folder);
-}
-
-std::unique_ptr<sync_driver::LocalDeviceInfoProvider>
-ProfileSyncComponentsFactoryImpl::CreateLocalDeviceInfoProvider() {
- return base::WrapUnique(
- new browser_sync::LocalDeviceInfoProviderImpl(channel_, version_,
- is_tablet_));
-}
-
-class TokenServiceProvider
- : public OAuth2TokenServiceRequest::TokenServiceProvider {
- public:
- TokenServiceProvider(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- OAuth2TokenService* token_service);
-
- // OAuth2TokenServiceRequest::TokenServiceProvider implementation.
- scoped_refptr<base::SingleThreadTaskRunner> GetTokenServiceTaskRunner()
- override;
- OAuth2TokenService* GetTokenService() override;
-
- private:
- ~TokenServiceProvider() override;
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- OAuth2TokenService* token_service_;
-};
-
-TokenServiceProvider::TokenServiceProvider(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- OAuth2TokenService* token_service)
- : task_runner_(task_runner), token_service_(token_service) {}
-
-TokenServiceProvider::~TokenServiceProvider() {}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-TokenServiceProvider::GetTokenServiceTaskRunner() {
- return task_runner_;
-}
-
-OAuth2TokenService* TokenServiceProvider::GetTokenService() {
- return token_service_;
-}
-
-std::unique_ptr<syncer::AttachmentService>
-ProfileSyncComponentsFactoryImpl::CreateAttachmentService(
- std::unique_ptr<syncer::AttachmentStoreForSync> attachment_store,
- const syncer::UserShare& user_share,
- const std::string& store_birthday,
- syncer::ModelType model_type,
- syncer::AttachmentService::Delegate* delegate) {
- std::unique_ptr<syncer::AttachmentUploader> attachment_uploader;
- std::unique_ptr<syncer::AttachmentDownloader> attachment_downloader;
- // Only construct an AttachmentUploader and AttachmentDownload if we have sync
- // credentials. We may not have sync credentials because there may not be a
- // signed in sync user.
- if (!user_share.sync_credentials.account_id.empty() &&
- !user_share.sync_credentials.scope_set.empty()) {
- scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>
- token_service_provider(
- new TokenServiceProvider(ui_thread_, token_service_));
- // TODO(maniscalco): Use shared (one per profile) thread-safe instances of
- // AttachmentUploader and AttachmentDownloader instead of creating a new one
- // per AttachmentService (bug 369536).
- attachment_uploader.reset(new syncer::AttachmentUploaderImpl(
- sync_service_url_, url_request_context_getter_,
- user_share.sync_credentials.account_id,
- user_share.sync_credentials.scope_set, token_service_provider,
- store_birthday, model_type));
-
- token_service_provider =
- new TokenServiceProvider(ui_thread_, token_service_);
- attachment_downloader = syncer::AttachmentDownloader::Create(
- sync_service_url_, url_request_context_getter_,
- user_share.sync_credentials.account_id,
- user_share.sync_credentials.scope_set, token_service_provider,
- store_birthday, model_type);
- }
-
- // It is important that the initial backoff delay is relatively large. For
- // whatever reason, the server may fail all requests for a short period of
- // time. When this happens we don't want to overwhelm the server with
- // requests so we use a large initial backoff.
- const base::TimeDelta initial_backoff_delay =
- base::TimeDelta::FromMinutes(30);
- const base::TimeDelta max_backoff_delay = base::TimeDelta::FromHours(4);
- std::unique_ptr<syncer::AttachmentService> attachment_service(
- new syncer::AttachmentServiceImpl(
- std::move(attachment_store), std::move(attachment_uploader),
- std::move(attachment_downloader), delegate, initial_backoff_delay,
- max_backoff_delay));
- return attachment_service;
-}
-
-sync_driver::SyncApiComponentFactory::SyncComponents
-ProfileSyncComponentsFactoryImpl::CreateBookmarkSyncComponents(
- sync_driver::SyncService* sync_service,
- syncer::DataTypeErrorHandler* error_handler) {
- BookmarkModel* bookmark_model =
- sync_service->GetSyncClient()->GetBookmarkModel();
- syncer::UserShare* user_share = sync_service->GetUserShare();
-// TODO(akalin): We may want to propagate this switch up eventually.
-#if defined(OS_ANDROID) || defined(OS_IOS)
- const bool kExpectMobileBookmarksFolder = true;
-#else
- const bool kExpectMobileBookmarksFolder = false;
-#endif
- BookmarkModelAssociator* model_associator = new BookmarkModelAssociator(
- bookmark_model, sync_service->GetSyncClient(), user_share, error_handler,
- kExpectMobileBookmarksFolder);
- BookmarkChangeProcessor* change_processor = new BookmarkChangeProcessor(
- sync_service->GetSyncClient(), model_associator, error_handler);
- return SyncComponents(model_associator, change_processor);
-}
diff --git a/chromium/components/browser_sync/browser/profile_sync_components_factory_impl.h b/chromium/components/browser_sync/browser/profile_sync_components_factory_impl.h
deleted file mode 100644
index 4e7232d46d8..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_components_factory_impl.h
+++ /dev/null
@@ -1,122 +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 COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_COMPONENTS_FACTORY_IMPL_H__
-#define COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_COMPONENTS_FACTORY_IMPL_H__
-
-#include <string>
-
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/sync_driver/sync_api_component_factory.h"
-#include "components/version_info/version_info.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "url/gurl.h"
-
-class OAuth2TokenService;
-class Profile;
-
-namespace autofill {
-class AutofillWebDataService;
-}
-
-namespace password_manager {
-class PasswordStore;
-}
-
-namespace net {
-class URLRequestContextGetter;
-}
-
-class ProfileSyncComponentsFactoryImpl
- : public sync_driver::SyncApiComponentFactory {
- public:
- // Constructs a ProfileSyncComponentsFactoryImpl.
- //
- // |sync_service_url| is the base URL of the sync server.
- //
- // |token_service| must outlive the ProfileSyncComponentsFactoryImpl.
- //
- // |url_request_context_getter| must outlive the
- // ProfileSyncComponentsFactoryImpl.
- ProfileSyncComponentsFactoryImpl(
- sync_driver::SyncClient* sync_client,
- version_info::Channel channel,
- const std::string& version,
- bool is_tablet,
- const base::CommandLine& command_line,
- const char* history_disabled_pref,
- const GURL& sync_service_url,
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
- OAuth2TokenService* token_service,
- net::URLRequestContextGetter* url_request_context_getter,
- const scoped_refptr<autofill::AutofillWebDataService>& web_data_service,
- const scoped_refptr<password_manager::PasswordStore>& password_store);
- ~ProfileSyncComponentsFactoryImpl() override;
-
- // SyncApiComponentFactory implementation:
- void RegisterDataTypes(
- sync_driver::SyncService* sync_service,
- const RegisterDataTypesMethod& register_platform_types_method) override;
- sync_driver::DataTypeManager* CreateDataTypeManager(
- const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
- debug_info_listener,
- const sync_driver::DataTypeController::TypeMap* controllers,
- const sync_driver::DataTypeEncryptionHandler* encryption_handler,
- browser_sync::SyncBackendHost* backend,
- sync_driver::DataTypeManagerObserver* observer) override;
- browser_sync::SyncBackendHost* CreateSyncBackendHost(
- const std::string& name,
- invalidation::InvalidationService* invalidator,
- const base::WeakPtr<sync_driver::SyncPrefs>& sync_prefs,
- const base::FilePath& sync_folder) override;
- std::unique_ptr<sync_driver::LocalDeviceInfoProvider>
- CreateLocalDeviceInfoProvider() override;
- std::unique_ptr<syncer::AttachmentService> CreateAttachmentService(
- std::unique_ptr<syncer::AttachmentStoreForSync> attachment_store,
- const syncer::UserShare& user_share,
- const std::string& store_birthday,
- syncer::ModelType model_type,
- syncer::AttachmentService::Delegate* delegate) override;
- sync_driver::SyncApiComponentFactory::SyncComponents
- CreateBookmarkSyncComponents(
- sync_driver::SyncService* sync_service,
- syncer::DataTypeErrorHandler* error_handler) override;
-
- private:
- // Register data types which are enabled on both desktop and mobile.
- // |disabled_types| and |enabled_types| correspond only to those types
- // being explicitly enabled/disabled by the command line.
- void RegisterCommonDataTypes(sync_driver::SyncService* sync_service,
- syncer::ModelTypeSet disabled_types,
- syncer::ModelTypeSet enabled_types);
-
- void DisableBrokenType(syncer::ModelType type,
- const tracked_objects::Location& from_here,
- const std::string& message);
-
- // Client/platform specific members.
- sync_driver::SyncClient* const sync_client_;
- const version_info::Channel channel_;
- const std::string version_;
- const bool is_tablet_;
- const base::CommandLine command_line_;
- const char* history_disabled_pref_;
- const GURL sync_service_url_;
- const scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
- const scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
- OAuth2TokenService* const token_service_;
- net::URLRequestContextGetter* const url_request_context_getter_;
- const scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
- const scoped_refptr<password_manager::PasswordStore> password_store_;
-
- base::WeakPtrFactory<ProfileSyncComponentsFactoryImpl> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ProfileSyncComponentsFactoryImpl);
-};
-
-#endif // COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_COMPONENTS_FACTORY_IMPL_H__
diff --git a/chromium/components/browser_sync/browser/profile_sync_service.cc b/chromium/components/browser_sync/browser/profile_sync_service.cc
deleted file mode 100644
index 13f89836142..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_service.cc
+++ /dev/null
@@ -1,2543 +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 "components/browser_sync/browser/profile_sync_service.h"
-
-#include <stddef.h>
-#include <cstddef>
-#include <map>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/feature_list.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/metrics/histogram.h"
-#include "base/profiler/scoped_tracker.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string16.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "components/autofill/core/common/autofill_pref_names.h"
-#include "components/browser_sync/common/browser_sync_switches.h"
-#include "components/history/core/browser/typed_url_data_type_controller.h"
-#include "components/invalidation/impl/invalidation_prefs.h"
-#include "components/invalidation/public/invalidation_service.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "components/prefs/json_pref_store.h"
-#include "components/signin/core/browser/about_signin_internals.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "components/signin/core/browser/signin_metrics.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/sync_driver/backend_migrator.h"
-#include "components/sync_driver/change_processor.h"
-#include "components/sync_driver/data_type_controller.h"
-#include "components/sync_driver/device_info.h"
-#include "components/sync_driver/device_info_service.h"
-#include "components/sync_driver/device_info_sync_service.h"
-#include "components/sync_driver/device_info_tracker.h"
-#include "components/sync_driver/glue/chrome_report_unrecoverable_error.h"
-#include "components/sync_driver/glue/sync_backend_host.h"
-#include "components/sync_driver/glue/sync_backend_host_impl.h"
-#include "components/sync_driver/pref_names.h"
-#include "components/sync_driver/signin_manager_wrapper.h"
-#include "components/sync_driver/sync_api_component_factory.h"
-#include "components/sync_driver/sync_client.h"
-#include "components/sync_driver/sync_driver_switches.h"
-#include "components/sync_driver/sync_error_controller.h"
-#include "components/sync_driver/sync_stopped_reporter.h"
-#include "components/sync_driver/sync_type_preference_provider.h"
-#include "components/sync_driver/sync_util.h"
-#include "components/sync_driver/system_encryptor.h"
-#include "components/sync_driver/user_selectable_sync_type.h"
-#include "components/sync_sessions/favicon_cache.h"
-#include "components/sync_sessions/session_data_type_controller.h"
-#include "components/sync_sessions/sessions_sync_manager.h"
-#include "components/sync_sessions/sync_sessions_client.h"
-#include "components/syncable_prefs/pref_service_syncable.h"
-#include "components/version_info/version_info_values.h"
-#include "net/cookies/cookie_monster.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "sync/api/model_type_store.h"
-#include "sync/api/sync_error.h"
-#include "sync/internal_api/public/base/stop_source.h"
-#include "sync/internal_api/public/configure_reason.h"
-#include "sync/internal_api/public/http_bridge_network_resources.h"
-#include "sync/internal_api/public/network_resources.h"
-#include "sync/internal_api/public/sessions/model_neutral_state.h"
-#include "sync/internal_api/public/sessions/type_debug_info_observer.h"
-#include "sync/internal_api/public/shared_model_type_processor.h"
-#include "sync/internal_api/public/shutdown_reason.h"
-#include "sync/internal_api/public/sync_encryption_handler.h"
-#include "sync/internal_api/public/util/experiments.h"
-#include "sync/internal_api/public/util/sync_db_util.h"
-#include "sync/internal_api/public/util/sync_string_conversions.h"
-#include "sync/js/js_event_details.h"
-#include "sync/protocol/sync.pb.h"
-#include "sync/syncable/directory.h"
-#include "sync/util/cryptographer.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/time_format.h"
-
-#if defined(OS_ANDROID)
-#include "sync/internal_api/public/read_transaction.h"
-#endif
-
-using browser_sync::SessionsSyncManager;
-using browser_sync::SyncBackendHost;
-using sync_driver::ChangeProcessor;
-using sync_driver::DataTypeController;
-using sync_driver::DataTypeManager;
-using sync_driver::DataTypeStatusTable;
-using sync_driver::DeviceInfoSyncService;
-using sync_driver_v2::DeviceInfoService;
-using syncer::ModelType;
-using syncer::ModelTypeSet;
-using syncer::JsBackend;
-using syncer::JsController;
-using syncer::JsEventDetails;
-using syncer::JsEventHandler;
-using syncer::ModelSafeRoutingInfo;
-using syncer::SyncCredentials;
-using syncer::SyncProtocolError;
-using syncer::WeakHandle;
-using syncer_v2::ModelTypeStore;
-using syncer_v2::SharedModelTypeProcessor;
-
-typedef GoogleServiceAuthError AuthError;
-
-const char kSyncUnrecoverableErrorHistogram[] =
- "Sync.UnrecoverableErrors";
-
-const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
- // Number of initial errors (in sequence) to ignore before applying
- // exponential back-off rules.
- 0,
-
- // Initial delay for exponential back-off in ms.
- 2000,
-
- // Factor by which the waiting time will be multiplied.
- 2,
-
- // Fuzzing percentage. ex: 10% will spread requests randomly
- // between 90%-100% of the calculated time.
- 0.2, // 20%
-
- // Maximum amount of time we are willing to delay our request in ms.
- // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
- // RequestAccessToken on connection state change after backoff
- 1000 * 3600 * 4, // 4 hours.
-
- // Time to keep an entry from being discarded even when it
- // has no significant state, -1 to never discard.
- -1,
-
- // Don't use initial delay unless the last request was an error.
- false,
-};
-
-static const base::FilePath::CharType kSyncDataFolderName[] =
- FILE_PATH_LITERAL("Sync Data");
-static const base::FilePath::CharType kLevelDBFolderName[] =
- FILE_PATH_LITERAL("LevelDB");
-
-namespace {
-
-// Perform the actual sync data folder deletion.
-// This should only be called on the sync thread.
-void DeleteSyncDataFolder(const base::FilePath& directory_path) {
- if (base::DirectoryExists(directory_path)) {
- if (!base::DeleteFile(directory_path, true))
- LOG(DFATAL) << "Could not delete the Sync Data folder.";
- }
-}
-
-} // namespace
-
-bool ShouldShowActionOnUI(
- const syncer::SyncProtocolError& error) {
- return (error.action != syncer::UNKNOWN_ACTION &&
- error.action != syncer::DISABLE_SYNC_ON_CLIENT &&
- error.action != syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT &&
- error.action != syncer::RESET_LOCAL_SYNC_DATA);
-}
-
-ProfileSyncService::InitParams::InitParams() = default;
-ProfileSyncService::InitParams::~InitParams() = default;
-ProfileSyncService::InitParams::InitParams(InitParams&& other) // NOLINT
- : sync_client(std::move(other.sync_client)),
- signin_wrapper(std::move(other.signin_wrapper)),
- oauth2_token_service(other.oauth2_token_service),
- gaia_cookie_manager_service(other.gaia_cookie_manager_service),
- start_behavior(other.start_behavior),
- network_time_update_callback(
- std::move(other.network_time_update_callback)),
- base_directory(std::move(other.base_directory)),
- url_request_context(std::move(other.url_request_context)),
- debug_identifier(std::move(other.debug_identifier)),
- channel(other.channel),
- db_thread(std::move(other.db_thread)),
- file_thread(std::move(other.file_thread)),
- blocking_pool(other.blocking_pool) {}
-
-ProfileSyncService::ProfileSyncService(InitParams init_params)
- : OAuth2TokenService::Consumer("sync"),
- last_auth_error_(AuthError::AuthErrorNone()),
- passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED),
- sync_client_(std::move(init_params.sync_client)),
- sync_prefs_(sync_client_->GetPrefService()),
- sync_service_url_(
- GetSyncServiceURL(*base::CommandLine::ForCurrentProcess(),
- init_params.channel)),
- network_time_update_callback_(
- std::move(init_params.network_time_update_callback)),
- base_directory_(init_params.base_directory),
- url_request_context_(init_params.url_request_context),
- debug_identifier_(std::move(init_params.debug_identifier)),
- channel_(init_params.channel),
- db_thread_(init_params.db_thread),
- file_thread_(init_params.file_thread),
- blocking_pool_(init_params.blocking_pool),
- is_first_time_sync_configure_(false),
- backend_initialized_(false),
- sync_disabled_by_admin_(false),
- is_auth_in_progress_(false),
- signin_(std::move(init_params.signin_wrapper)),
- unrecoverable_error_reason_(ERROR_REASON_UNSET),
- expect_sync_configuration_aborted_(false),
- encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()),
- encrypt_everything_allowed_(true),
- encrypt_everything_(false),
- encryption_pending_(false),
- configure_status_(DataTypeManager::UNKNOWN),
- oauth2_token_service_(init_params.oauth2_token_service),
- request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy),
- connection_status_(syncer::CONNECTION_NOT_ATTEMPTED),
- last_get_token_error_(GoogleServiceAuthError::AuthErrorNone()),
- gaia_cookie_manager_service_(init_params.gaia_cookie_manager_service),
- network_resources_(new syncer::HttpBridgeNetworkResources),
- start_behavior_(init_params.start_behavior),
- directory_path_(
- base_directory_.Append(base::FilePath(kSyncDataFolderName))),
- catch_up_configure_in_progress_(false),
- passphrase_prompt_triggered_by_version_(false),
- sync_enabled_weak_factory_(this),
- weak_factory_(this) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(sync_client_);
- std::string last_version = sync_prefs_.GetLastRunVersion();
- std::string current_version = PRODUCT_VERSION;
- sync_prefs_.SetLastRunVersion(current_version);
-
- // Check for a major version change. Note that the versions have format
- // MAJOR.MINOR.BUILD.PATCH.
- if (last_version.substr(0, last_version.find('.')) !=
- current_version.substr(0, current_version.find('.'))) {
- passphrase_prompt_triggered_by_version_ = true;
- }
-}
-
-ProfileSyncService::~ProfileSyncService() {
- if (gaia_cookie_manager_service_)
- gaia_cookie_manager_service_->RemoveObserver(this);
- sync_prefs_.RemoveSyncPrefObserver(this);
- // Shutdown() should have been called before destruction.
- CHECK(!backend_initialized_);
-}
-
-bool ProfileSyncService::CanSyncStart() const {
- return IsSyncAllowed() && IsSyncRequested() && IsSignedIn();
-}
-
-void ProfileSyncService::Initialize() {
- sync_client_->Initialize();
-
- // We don't pass StartupController an Unretained reference to future-proof
- // against the controller impl changing to post tasks.
- startup_controller_.reset(new browser_sync::StartupController(
- &sync_prefs_,
- base::Bind(&ProfileSyncService::CanBackendStart, base::Unretained(this)),
- base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
- weak_factory_.GetWeakPtr())));
- std::unique_ptr<browser_sync::LocalSessionEventRouter> router(
- sync_client_->GetSyncSessionsClient()->GetLocalSessionEventRouter());
- local_device_ = sync_client_->GetSyncApiComponentFactory()
- ->CreateLocalDeviceInfoProvider();
- sync_stopped_reporter_.reset(new browser_sync::SyncStoppedReporter(
- sync_service_url_, local_device_->GetSyncUserAgent(),
- url_request_context_,
- browser_sync::SyncStoppedReporter::ResultCallback()));
- sessions_sync_manager_.reset(new SessionsSyncManager(
- sync_client_->GetSyncSessionsClient(), &sync_prefs_, local_device_.get(),
- std::move(router),
- base::Bind(&ProfileSyncService::NotifyForeignSessionUpdated,
- sync_enabled_weak_factory_.GetWeakPtr()),
- base::Bind(&ProfileSyncService::TriggerRefresh,
- sync_enabled_weak_factory_.GetWeakPtr(),
- syncer::ModelTypeSet(syncer::SESSIONS))));
-
- if (channel_ == version_info::Channel::UNKNOWN &&
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kSyncEnableUSSDeviceInfo)) {
- scoped_refptr<base::SequencedTaskRunner> blocking_task_runner(
- blocking_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
- blocking_pool_->GetSequenceToken(),
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
- // TODO(skym): Stop creating leveldb files when signed out.
- // TODO(skym): Verify using AsUTF8Unsafe is okay here. Should work as long
- // as the Local State file is guaranteed to be UTF-8.
- device_info_service_.reset(new DeviceInfoService(
- local_device_.get(),
- base::Bind(&ModelTypeStore::CreateStore, syncer::DEVICE_INFO,
- directory_path_.Append(base::FilePath(kLevelDBFolderName))
- .AsUTF8Unsafe(),
- blocking_task_runner),
- base::Bind(&SharedModelTypeProcessor::CreateAsChangeProcessor)));
- } else {
- device_info_sync_service_.reset(
- new DeviceInfoSyncService(local_device_.get()));
- }
-
- sync_driver::SyncApiComponentFactory::RegisterDataTypesMethod
- register_platform_types_callback =
- sync_client_->GetRegisterPlatformTypesCallback();
- sync_client_->GetSyncApiComponentFactory()->RegisterDataTypes(
- this, register_platform_types_callback);
-
- if (gaia_cookie_manager_service_)
- gaia_cookie_manager_service_->AddObserver(this);
-
- // We clear this here (vs Shutdown) because we want to remember that an error
- // happened on shutdown so we can display details (message, location) about it
- // in about:sync.
- ClearStaleErrors();
-
- sync_prefs_.AddSyncPrefObserver(this);
-
- SyncInitialState sync_state = CAN_START;
- if (!IsSignedIn()) {
- sync_state = NOT_SIGNED_IN;
- } else if (IsManaged()) {
- sync_state = IS_MANAGED;
- } else if (!IsSyncAllowedByPlatform()) {
- // This case should currently never be hit, as Android's master sync isn't
- // plumbed into PSS until after this function. See http://crbug.com/568771.
- sync_state = NOT_ALLOWED_BY_PLATFORM;
- } else if (!IsSyncRequested()) {
- if (IsFirstSetupComplete()) {
- sync_state = NOT_REQUESTED;
- } else {
- sync_state = NOT_REQUESTED_NOT_SETUP;
- }
- } else if (!IsFirstSetupComplete()) {
- sync_state = NEEDS_CONFIRMATION;
- }
- UMA_HISTOGRAM_ENUMERATION("Sync.InitialState", sync_state,
- SYNC_INITIAL_STATE_LIMIT);
-
- // If sync isn't allowed, the only thing to do is to turn it off.
- if (!IsSyncAllowed()) {
- // Only clear data if disallowed by policy.
- RequestStop(IsManaged() ? CLEAR_DATA : KEEP_DATA);
- return;
- }
-
- RegisterAuthNotifications();
-
- if (!IsSignedIn()) {
- // Clean up in case of previous crash during signout.
- StopImpl(CLEAR_DATA);
- }
-
-#if defined(OS_CHROMEOS)
- std::string bootstrap_token = sync_prefs_.GetEncryptionBootstrapToken();
- if (bootstrap_token.empty()) {
- sync_prefs_.SetEncryptionBootstrapToken(
- sync_prefs_.GetSpareBootstrapToken());
- }
-#endif
-
-#if !defined(OS_ANDROID)
- DCHECK(sync_error_controller_ == NULL)
- << "Initialize() called more than once.";
- sync_error_controller_.reset(new SyncErrorController(this));
- AddObserver(sync_error_controller_.get());
-#endif
-
- memory_pressure_listener_.reset(new base::MemoryPressureListener(
- base::Bind(&ProfileSyncService::OnMemoryPressure,
- sync_enabled_weak_factory_.GetWeakPtr())));
- startup_controller_->Reset(GetRegisteredDataTypes());
-
- // Auto-start means means the first time the profile starts up, sync should
- // start up immediately.
- if (start_behavior_ == AUTO_START && IsSyncRequested() &&
- !IsFirstSetupComplete()) {
- startup_controller_->TryStartImmediately();
- } else {
- startup_controller_->TryStart();
- }
-}
-
-void ProfileSyncService::StartSyncingWithServer() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (base::FeatureList::IsEnabled(
- switches::kSyncClearDataOnPassphraseEncryption) &&
- sync_prefs_.GetPassphraseEncryptionTransitionInProgress()) {
- BeginConfigureCatchUpBeforeClear();
- return;
- }
-
- if (backend_)
- backend_->StartSyncingWithServer();
-}
-
-void ProfileSyncService::RegisterAuthNotifications() {
- oauth2_token_service_->AddObserver(this);
- if (signin())
- signin()->AddObserver(this);
-}
-
-void ProfileSyncService::UnregisterAuthNotifications() {
- if (signin())
- signin()->RemoveObserver(this);
- oauth2_token_service_->RemoveObserver(this);
-}
-
-void ProfileSyncService::RegisterDataTypeController(
- sync_driver::DataTypeController* data_type_controller) {
- DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U);
- data_type_controllers_[data_type_controller->type()] = data_type_controller;
-}
-
-bool ProfileSyncService::IsDataTypeControllerRunning(
- syncer::ModelType type) const {
- DataTypeController::TypeMap::const_iterator iter =
- data_type_controllers_.find(type);
- if (iter == data_type_controllers_.end()) {
- return false;
- }
- return iter->second->state() == DataTypeController::RUNNING;
-}
-
-sync_driver::OpenTabsUIDelegate* ProfileSyncService::GetOpenTabsUIDelegate() {
- if (!IsDataTypeControllerRunning(syncer::SESSIONS))
- return NULL;
- return sessions_sync_manager_.get();
-}
-
-browser_sync::FaviconCache* ProfileSyncService::GetFaviconCache() {
- return sessions_sync_manager_->GetFaviconCache();
-}
-
-sync_driver::DeviceInfoTracker* ProfileSyncService::GetDeviceInfoTracker()
- const {
- // One of the two should always be non-null after initialization is done.
- if (device_info_service_) {
- return device_info_service_.get();
- } else {
- return device_info_sync_service_.get();
- }
-}
-
-sync_driver::LocalDeviceInfoProvider*
-ProfileSyncService::GetLocalDeviceInfoProvider() const {
- return local_device_.get();
-}
-
-void ProfileSyncService::GetDataTypeControllerStates(
- DataTypeController::StateMap* state_map) const {
- for (DataTypeController::TypeMap::const_iterator iter =
- data_type_controllers_.begin();
- iter != data_type_controllers_.end(); ++iter)
- (*state_map)[iter->first] = iter->second.get()->state();
-}
-
-void ProfileSyncService::OnSessionRestoreComplete() {
- DataTypeController::TypeMap::const_iterator iter =
- data_type_controllers_.find(syncer::SESSIONS);
- if (iter == data_type_controllers_.end()) {
- return;
- }
- DCHECK(iter->second);
-
- static_cast<browser_sync::SessionDataTypeController*>(iter->second.get())
- ->OnSessionRestoreComplete();
-}
-
-SyncCredentials ProfileSyncService::GetCredentials() {
- SyncCredentials credentials;
- credentials.account_id = signin_->GetAccountIdToUse();
- DCHECK(!credentials.account_id.empty());
- credentials.email = signin_->GetEffectiveUsername();
- credentials.sync_token = access_token_;
-
- if (credentials.sync_token.empty())
- credentials.sync_token = "credentials_lost";
-
- credentials.scope_set.insert(signin_->GetSyncScopeToUse());
-
- return credentials;
-}
-
-bool ProfileSyncService::ShouldDeleteSyncFolder() {
- return !IsFirstSetupComplete();
-}
-
-void ProfileSyncService::InitializeBackend(bool delete_stale_data) {
- if (!backend_) {
- NOTREACHED();
- return;
- }
-
- SyncCredentials credentials = GetCredentials();
-
- if (delete_stale_data)
- ClearStaleErrors();
-
- SyncBackendHost::HttpPostProviderFactoryGetter
- http_post_provider_factory_getter =
- base::Bind(&syncer::NetworkResources::GetHttpPostProviderFactory,
- base::Unretained(network_resources_.get()),
- url_request_context_,
- network_time_update_callback_);
-
- backend_->Initialize(
- this, std::move(sync_thread_), db_thread_, file_thread_,
- GetJsEventHandler(), sync_service_url_, local_device_->GetSyncUserAgent(),
- credentials, delete_stale_data,
- std::unique_ptr<syncer::SyncManagerFactory>(
- new syncer::SyncManagerFactory()),
- MakeWeakHandle(sync_enabled_weak_factory_.GetWeakPtr()),
- base::Bind(browser_sync::ChromeReportUnrecoverableError, channel_),
- http_post_provider_factory_getter, std::move(saved_nigori_state_));
-}
-
-bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
- if (encryption_pending())
- return true;
- const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
- const syncer::ModelTypeSet encrypted_types = GetEncryptedDataTypes();
- DCHECK(encrypted_types.Has(syncer::PASSWORDS));
- return !Intersection(preferred_types, encrypted_types).Empty();
-}
-
-void ProfileSyncService::OnProtocolEvent(
- const syncer::ProtocolEvent& event) {
- FOR_EACH_OBSERVER(browser_sync::ProtocolEventObserver,
- protocol_event_observers_,
- OnProtocolEvent(event));
-}
-
-void ProfileSyncService::OnDirectoryTypeCommitCounterUpdated(
- syncer::ModelType type,
- const syncer::CommitCounters& counters) {
- FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver,
- type_debug_info_observers_,
- OnCommitCountersUpdated(type, counters));
-}
-
-void ProfileSyncService::OnDirectoryTypeUpdateCounterUpdated(
- syncer::ModelType type,
- const syncer::UpdateCounters& counters) {
- FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver,
- type_debug_info_observers_,
- OnUpdateCountersUpdated(type, counters));
-}
-
-void ProfileSyncService::OnDirectoryTypeStatusCounterUpdated(
- syncer::ModelType type,
- const syncer::StatusCounters& counters) {
- FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver,
- type_debug_info_observers_,
- OnStatusCountersUpdated(type, counters));
-}
-
-void ProfileSyncService::OnDataTypeRequestsSyncStartup(
- syncer::ModelType type) {
- DCHECK(syncer::UserTypes().Has(type));
-
- if (!GetPreferredDataTypes().Has(type)) {
- // We can get here as datatype SyncableServices are typically wired up
- // to the native datatype even if sync isn't enabled.
- DVLOG(1) << "Dropping sync startup request because type "
- << syncer::ModelTypeToString(type) << "not enabled.";
- return;
- }
-
- // If this is a data type change after a major version update, reset the
- // passphrase prompted state and notify observers.
- if (IsPassphraseRequired() && passphrase_prompt_triggered_by_version_) {
- // The major version has changed and a local syncable change was made.
- // Reset the passphrase prompt state.
- passphrase_prompt_triggered_by_version_ = false;
- sync_prefs_.SetPassphrasePrompted(false);
- NotifyObservers();
- }
-
- if (backend_.get()) {
- DVLOG(1) << "A data type requested sync startup, but it looks like "
- "something else beat it to the punch.";
- return;
- }
-
- startup_controller_->OnDataTypeRequestsSyncStartup(type);
-}
-
-void ProfileSyncService::StartUpSlowBackendComponents() {
- invalidation::InvalidationService* invalidator =
- sync_client_->GetInvalidationService();
-
- backend_.reset(
- sync_client_->GetSyncApiComponentFactory()->CreateSyncBackendHost(
- debug_identifier_, invalidator, sync_prefs_.AsWeakPtr(),
- directory_path_));
-
- // Initialize the backend. Every time we start up a new SyncBackendHost,
- // we'll want to start from a fresh SyncDB, so delete any old one that might
- // be there.
- InitializeBackend(ShouldDeleteSyncFolder());
-
- UpdateFirstSyncTimePref();
-
- ReportPreviousSessionMemoryWarningCount();
-}
-
-void ProfileSyncService::OnGetTokenSuccess(
- const OAuth2TokenService::Request* request,
- const std::string& access_token,
- const base::Time& expiration_time) {
- DCHECK_EQ(access_token_request_.get(), request);
- access_token_request_.reset();
- access_token_ = access_token;
- token_receive_time_ = base::Time::Now();
- last_get_token_error_ = GoogleServiceAuthError::AuthErrorNone();
-
- if (sync_prefs_.SyncHasAuthError()) {
- sync_prefs_.SetSyncAuthError(false);
- }
-
- if (HasSyncingBackend())
- backend_->UpdateCredentials(GetCredentials());
- else
- startup_controller_->TryStart();
-}
-
-void ProfileSyncService::OnGetTokenFailure(
- const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) {
- DCHECK_EQ(access_token_request_.get(), request);
- DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
- access_token_request_.reset();
- last_get_token_error_ = error;
- switch (error.state()) {
- case GoogleServiceAuthError::CONNECTION_FAILED:
- case GoogleServiceAuthError::REQUEST_CANCELED:
- case GoogleServiceAuthError::SERVICE_ERROR:
- case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
- // Transient error. Retry after some time.
- request_access_token_backoff_.InformOfRequest(false);
- next_token_request_time_ = base::Time::Now() +
- request_access_token_backoff_.GetTimeUntilRelease();
- request_access_token_retry_timer_.Start(
- FROM_HERE, request_access_token_backoff_.GetTimeUntilRelease(),
- base::Bind(&ProfileSyncService::RequestAccessToken,
- sync_enabled_weak_factory_.GetWeakPtr()));
- NotifyObservers();
- break;
- }
- case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
- if (!sync_prefs_.SyncHasAuthError()) {
- sync_prefs_.SetSyncAuthError(true);
- UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError",
- AUTH_ERROR_ENCOUNTERED,
- AUTH_ERROR_LIMIT);
- }
- // Fallthrough.
- }
- default: {
- if (error.state() != GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
- LOG(ERROR) << "Unexpected persistent error: " << error.ToString();
- }
- // Show error to user.
- UpdateAuthErrorState(error);
- }
- }
-}
-
-void ProfileSyncService::OnRefreshTokenAvailable(
- const std::string& account_id) {
- // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422460 ProfileSyncService::OnRefreshTokenAvailable"));
-
- if (account_id == signin_->GetAccountIdToUse())
- OnRefreshTokensLoaded();
-}
-
-void ProfileSyncService::OnRefreshTokenRevoked(
- const std::string& account_id) {
- if (account_id == signin_->GetAccountIdToUse()) {
- access_token_.clear();
- UpdateAuthErrorState(
- GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
- }
-}
-
-void ProfileSyncService::OnRefreshTokensLoaded() {
- // This notification gets fired when OAuth2TokenService loads the tokens
- // from storage.
- // Initialize the backend if sync is enabled. If the sync token was
- // not loaded, GetCredentials() will generate invalid credentials to
- // cause the backend to generate an auth error (crbug.com/121755).
- if (HasSyncingBackend()) {
- RequestAccessToken();
- } else {
- startup_controller_->TryStart();
- }
-}
-
-void ProfileSyncService::Shutdown() {
- UnregisterAuthNotifications();
-
- ShutdownImpl(syncer::BROWSER_SHUTDOWN);
- if (sync_error_controller_) {
- // Destroy the SyncErrorController when the service shuts down for good.
- RemoveObserver(sync_error_controller_.get());
- sync_error_controller_.reset();
- }
-
- if (sync_thread_)
- sync_thread_->Stop();
-}
-
-void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) {
- if (!backend_) {
- if (reason == syncer::ShutdownReason::DISABLE_SYNC && sync_thread_) {
- // If the backend is already shut down when a DISABLE_SYNC happens,
- // the data directory needs to be cleaned up here.
- sync_thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&DeleteSyncDataFolder, directory_path_));
- }
- return;
- }
-
- if (reason == syncer::ShutdownReason::STOP_SYNC
- || reason == syncer::ShutdownReason::DISABLE_SYNC) {
- RemoveClientFromServer();
- }
-
- // First, we spin down the backend to stop change processing as soon as
- // possible.
- base::Time shutdown_start_time = base::Time::Now();
- backend_->StopSyncingForShutdown();
-
- // Stop all data type controllers, if needed. Note that until Stop
- // completes, it is possible in theory to have a ChangeProcessor apply a
- // change from a native model. In that case, it will get applied to the sync
- // database (which doesn't get destroyed until we destroy the backend below)
- // as an unsynced change. That will be persisted, and committed on restart.
- if (data_type_manager_) {
- if (data_type_manager_->state() != DataTypeManager::STOPPED) {
- // When aborting as part of shutdown, we should expect an aborted sync
- // configure result, else we'll dcheck when we try to read the sync error.
- expect_sync_configuration_aborted_ = true;
- data_type_manager_->Stop();
- }
- data_type_manager_.reset();
- }
-
- // Shutdown the migrator before the backend to ensure it doesn't pull a null
- // snapshot.
- migrator_.reset();
- sync_js_controller_.AttachJsBackend(WeakHandle<syncer::JsBackend>());
-
- // Move aside the backend so nobody else tries to use it while we are
- // shutting it down.
- std::unique_ptr<SyncBackendHost> doomed_backend(backend_.release());
- if (doomed_backend) {
- sync_thread_ = doomed_backend->Shutdown(reason);
- doomed_backend.reset();
- }
- base::TimeDelta shutdown_time = base::Time::Now() - shutdown_start_time;
- UMA_HISTOGRAM_TIMES("Sync.Shutdown.BackendDestroyedTime", shutdown_time);
-
- sync_enabled_weak_factory_.InvalidateWeakPtrs();
-
- startup_controller_->Reset(GetRegisteredDataTypes());
-
- // If the sync DB is getting destroyed, the local DeviceInfo is no longer
- // valid and should be cleared from the cache.
- if (reason == syncer::ShutdownReason::DISABLE_SYNC) {
- local_device_->Clear();
- }
-
- // Clear various flags.
- expect_sync_configuration_aborted_ = false;
- is_auth_in_progress_ = false;
- backend_initialized_ = false;
- cached_passphrase_.clear();
- encryption_pending_ = false;
- encrypt_everything_ = false;
- encrypted_types_ = syncer::SyncEncryptionHandler::SensitiveTypes();
- passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
- catch_up_configure_in_progress_ = false;
- access_token_.clear();
- request_access_token_retry_timer_.Stop();
- // Revert to "no auth error".
- if (last_auth_error_.state() != GoogleServiceAuthError::NONE)
- UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone());
-
- NotifyObservers();
-
- // Mark this as a clean shutdown(without crash).
- sync_prefs_.SetCleanShutdown(true);
-}
-
-void ProfileSyncService::StopImpl(SyncStopDataFate data_fate) {
- switch (data_fate) {
- case KEEP_DATA:
- // TODO(maxbogue): Investigate whether this logic can/should be moved
- // into ShutdownImpl or SyncBackendHost itself.
- if (HasSyncingBackend()) {
- backend_->UnregisterInvalidationIds();
- }
- ShutdownImpl(syncer::STOP_SYNC);
- break;
- case CLEAR_DATA:
- // Clear prefs (including SyncSetupHasCompleted) before shutting down so
- // PSS clients don't think we're set up while we're shutting down.
- sync_prefs_.ClearPreferences();
- ClearUnrecoverableError();
- ShutdownImpl(syncer::DISABLE_SYNC);
- break;
- }
-}
-
-bool ProfileSyncService::IsFirstSetupComplete() const {
- return sync_prefs_.IsFirstSetupComplete();
-}
-
-void ProfileSyncService::SetFirstSetupComplete() {
- sync_prefs_.SetFirstSetupComplete();
- if (IsBackendInitialized()) {
- ReconfigureDatatypeManager();
- }
-}
-
-void ProfileSyncService::UpdateLastSyncedTime() {
- sync_prefs_.SetLastSyncedTime(base::Time::Now());
-}
-
-void ProfileSyncService::NotifyObservers() {
- FOR_EACH_OBSERVER(sync_driver::SyncServiceObserver, observers_,
- OnStateChanged());
-}
-
-void ProfileSyncService::NotifySyncCycleCompleted() {
- FOR_EACH_OBSERVER(sync_driver::SyncServiceObserver, observers_,
- OnSyncCycleCompleted());
-}
-
-void ProfileSyncService::NotifyForeignSessionUpdated() {
- FOR_EACH_OBSERVER(sync_driver::SyncServiceObserver, observers_,
- OnForeignSessionUpdated());
-}
-
-void ProfileSyncService::ClearStaleErrors() {
- ClearUnrecoverableError();
- last_actionable_error_ = SyncProtocolError();
- // Clear the data type errors as well.
- if (data_type_manager_.get())
- data_type_manager_->ResetDataTypeErrors();
-}
-
-void ProfileSyncService::ClearUnrecoverableError() {
- unrecoverable_error_reason_ = ERROR_REASON_UNSET;
- unrecoverable_error_message_.clear();
- unrecoverable_error_location_ = tracked_objects::Location();
-}
-
-// An invariant has been violated. Transition to an error state where we try
-// to do as little work as possible, to avoid further corruption or crashes.
-void ProfileSyncService::OnUnrecoverableError(
- const tracked_objects::Location& from_here,
- const std::string& message) {
- // Unrecoverable errors that arrive via the syncer::UnrecoverableErrorHandler
- // interface are assumed to originate within the syncer.
- unrecoverable_error_reason_ = ERROR_REASON_SYNCER;
- OnUnrecoverableErrorImpl(from_here, message, true);
-}
-
-void ProfileSyncService::OnUnrecoverableErrorImpl(
- const tracked_objects::Location& from_here,
- const std::string& message,
- bool delete_sync_database) {
- DCHECK(HasUnrecoverableError());
- unrecoverable_error_message_ = message;
- unrecoverable_error_location_ = from_here;
-
- UMA_HISTOGRAM_ENUMERATION(kSyncUnrecoverableErrorHistogram,
- unrecoverable_error_reason_,
- ERROR_REASON_LIMIT);
- std::string location;
- from_here.Write(true, true, &location);
- LOG(ERROR)
- << "Unrecoverable error detected at " << location
- << " -- ProfileSyncService unusable: " << message;
-
- // Shut all data types down.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&ProfileSyncService::ShutdownImpl,
- sync_enabled_weak_factory_.GetWeakPtr(),
- delete_sync_database ? syncer::DISABLE_SYNC
- : syncer::STOP_SYNC));
-}
-
-void ProfileSyncService::ReenableDatatype(syncer::ModelType type) {
- if (!backend_initialized_ || !data_type_manager_)
- return;
- data_type_manager_->ReenableType(type);
-}
-
-void ProfileSyncService::UpdateBackendInitUMA(bool success) {
- is_first_time_sync_configure_ = !IsFirstSetupComplete();
-
- if (is_first_time_sync_configure_) {
- UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeFirstTimeSuccess", success);
- } else {
- UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeRestoreSuccess", success);
- }
-
- base::Time on_backend_initialized_time = base::Time::Now();
- base::TimeDelta delta = on_backend_initialized_time -
- startup_controller_->start_backend_time();
- if (is_first_time_sync_configure_) {
- UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeFirstTime", delta);
- } else {
- UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeRestoreTime", delta);
- }
-}
-
-void ProfileSyncService::PostBackendInitialization() {
- if (protocol_event_observers_.might_have_observers()) {
- backend_->RequestBufferedProtocolEventsAndEnableForwarding();
- }
-
- if (type_debug_info_observers_.might_have_observers()) {
- backend_->EnableDirectoryTypeDebugInfoForwarding();
- }
-
- // If we have a cached passphrase use it to decrypt/encrypt data now that the
- // backend is initialized. We want to call this before notifying observers in
- // case this operation affects the "passphrase required" status.
- ConsumeCachedPassphraseIfPossible();
-
- // The very first time the backend initializes is effectively the first time
- // we can say we successfully "synced". LastSyncedTime will only be null in
- // this case, because the pref wasn't restored on StartUp.
- if (sync_prefs_.GetLastSyncedTime().is_null()) {
- UpdateLastSyncedTime();
- }
-
- // Auto-start means IsFirstSetupComplete gets set automatically.
- if (start_behavior_ == AUTO_START && !IsFirstSetupComplete()) {
- // This will trigger a configure if it completes setup.
- SetFirstSetupComplete();
- } else if (CanConfigureDataTypes()) {
- ConfigureDataTypeManager();
- }
-
- // Check for a cookie jar mismatch.
- std::vector<gaia::ListedAccount> accounts;
- std::vector<gaia::ListedAccount> signed_out_accounts;
- GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
- if (gaia_cookie_manager_service_ &&
- gaia_cookie_manager_service_->ListAccounts(
- &accounts, &signed_out_accounts)) {
- OnGaiaAccountsInCookieUpdated(accounts, signed_out_accounts, error);
- }
-
- NotifyObservers();
-}
-
-void ProfileSyncService::OnBackendInitialized(
- const syncer::WeakHandle<syncer::JsBackend>& js_backend,
- const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
- debug_info_listener,
- const std::string& cache_guid,
- bool success) {
- UpdateBackendInitUMA(success);
-
- if (!success) {
- // Something went unexpectedly wrong. Play it safe: stop syncing at once
- // and surface error UI to alert the user sync has stopped.
- // Keep the directory around for now so that on restart we will retry
- // again and potentially succeed in presence of transient file IO failures
- // or permissions issues, etc.
- //
- // TODO(rlarocque): Consider making this UnrecoverableError less special.
- // Unlike every other UnrecoverableError, it does not delete our sync data.
- // This exception made sense at the time it was implemented, but our new
- // directory corruption recovery mechanism makes it obsolete. By the time
- // we get here, we will have already tried and failed to delete the
- // directory. It would be no big deal if we tried to delete it again.
- OnInternalUnrecoverableError(FROM_HERE,
- "BackendInitialize failure",
- false,
- ERROR_REASON_BACKEND_INIT_FAILURE);
- return;
- }
-
- backend_initialized_ = true;
-
- sync_js_controller_.AttachJsBackend(js_backend);
- debug_info_listener_ = debug_info_listener;
-
- SigninClient* signin_client = signin_->GetOriginal()->signin_client();
- DCHECK(signin_client);
- std::string signin_scoped_device_id =
- signin_client->GetSigninScopedDeviceId();
-
- // Initialize local device info.
- local_device_->Initialize(cache_guid, signin_scoped_device_id,
- blocking_pool_);
-
- PostBackendInitialization();
-}
-
-void ProfileSyncService::OnSyncCycleCompleted() {
- UpdateLastSyncedTime();
- const syncer::sessions::SyncSessionSnapshot snapshot =
- GetLastSessionSnapshot();
- if (IsDataTypeControllerRunning(syncer::SESSIONS) &&
- snapshot.model_neutral_state().get_updates_request_types.Has(
- syncer::SESSIONS) &&
- !syncer::sessions::HasSyncerError(snapshot.model_neutral_state())) {
- // Trigger garbage collection of old sessions now that we've downloaded
- // any new session data.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&SessionsSyncManager::DoGarbageCollection,
- base::AsWeakPtr(sessions_sync_manager_.get())));
- }
- DVLOG(2) << "Notifying observers sync cycle completed";
- NotifySyncCycleCompleted();
-}
-
-void ProfileSyncService::OnExperimentsChanged(
- const syncer::Experiments& experiments) {
- if (current_experiments_.Matches(experiments))
- return;
-
- current_experiments_ = experiments;
-
- sync_client_->GetPrefService()->SetBoolean(
- invalidation::prefs::kInvalidationServiceUseGCMChannel,
- experiments.gcm_invalidations_enabled);
-}
-
-void ProfileSyncService::UpdateAuthErrorState(const AuthError& error) {
- is_auth_in_progress_ = false;
- last_auth_error_ = error;
-
- NotifyObservers();
-}
-
-namespace {
-
-AuthError ConnectionStatusToAuthError(
- syncer::ConnectionStatus status) {
- switch (status) {
- case syncer::CONNECTION_OK:
- return AuthError::AuthErrorNone();
- break;
- case syncer::CONNECTION_AUTH_ERROR:
- return AuthError(AuthError::INVALID_GAIA_CREDENTIALS);
- break;
- case syncer::CONNECTION_SERVER_ERROR:
- return AuthError(AuthError::CONNECTION_FAILED);
- break;
- default:
- NOTREACHED();
- return AuthError(AuthError::CONNECTION_FAILED);
- }
-}
-
-} // namespace
-
-void ProfileSyncService::OnConnectionStatusChange(
- syncer::ConnectionStatus status) {
- connection_status_update_time_ = base::Time::Now();
- connection_status_ = status;
- if (status == syncer::CONNECTION_AUTH_ERROR) {
- // Sync server returned error indicating that access token is invalid. It
- // could be either expired or access is revoked. Let's request another
- // access token and if access is revoked then request for token will fail
- // with corresponding error. If access token is repeatedly reported
- // invalid, there may be some issues with server, e.g. authentication
- // state is inconsistent on sync and token server. In that case, we
- // backoff token requests exponentially to avoid hammering token server
- // too much and to avoid getting same token due to token server's caching
- // policy. |request_access_token_retry_timer_| is used to backoff request
- // triggered by both auth error and failure talking to GAIA server.
- // Therefore, we're likely to reach the backoff ceiling more quickly than
- // you would expect from looking at the BackoffPolicy if both types of
- // errors happen. We shouldn't receive two errors back-to-back without
- // attempting a token/sync request in between, thus crank up request delay
- // unnecessary. This is because we won't make a sync request if we hit an
- // error until GAIA succeeds at sending a new token, and we won't request
- // a new token unless sync reports a token failure. But to be safe, don't
- // schedule request if this happens.
- if (request_access_token_retry_timer_.IsRunning()) {
- // The timer to perform a request later is already running; nothing
- // further needs to be done at this point.
- } else if (request_access_token_backoff_.failure_count() == 0) {
- // First time request without delay. Currently invalid token is used
- // to initialize sync backend and we'll always end up here. We don't
- // want to delay initialization.
- request_access_token_backoff_.InformOfRequest(false);
- RequestAccessToken();
- } else {
- request_access_token_backoff_.InformOfRequest(false);
- request_access_token_retry_timer_.Start(
- FROM_HERE, request_access_token_backoff_.GetTimeUntilRelease(),
- base::Bind(&ProfileSyncService::RequestAccessToken,
- sync_enabled_weak_factory_.GetWeakPtr()));
- }
- } else {
- // Reset backoff time after successful connection.
- if (status == syncer::CONNECTION_OK) {
- // Request shouldn't be scheduled at this time. But if it is, it's
- // possible that sync flips between OK and auth error states rapidly,
- // thus hammers token server. To be safe, only reset backoff delay when
- // no scheduled request.
- if (!request_access_token_retry_timer_.IsRunning()) {
- request_access_token_backoff_.Reset();
- }
- }
-
- const GoogleServiceAuthError auth_error =
- ConnectionStatusToAuthError(status);
- DVLOG(1) << "Connection status change: " << auth_error.ToString();
- UpdateAuthErrorState(auth_error);
- }
-}
-
-void ProfileSyncService::OnPassphraseRequired(
- syncer::PassphraseRequiredReason reason,
- const sync_pb::EncryptedData& pending_keys) {
- DCHECK(backend_.get());
- DCHECK(backend_->IsNigoriEnabled());
-
- // TODO(lipalani) : add this check to other locations as well.
- if (HasUnrecoverableError()) {
- // When unrecoverable error is detected we post a task to shutdown the
- // backend. The task might not have executed yet.
- return;
- }
-
- DVLOG(1) << "Passphrase required with reason: "
- << syncer::PassphraseRequiredReasonToString(reason);
- passphrase_required_reason_ = reason;
-
- // TODO(stanisc): http://crbug.com/351005: Does this support USS types?
- const syncer::ModelTypeSet types = GetPreferredDataTypes();
- if (data_type_manager_) {
- // Reconfigure without the encrypted types (excluded implicitly via the
- // failed datatypes handler).
- data_type_manager_->Configure(types, syncer::CONFIGURE_REASON_CRYPTO);
- }
-
- // Notify observers that the passphrase status may have changed.
- NotifyObservers();
-}
-
-void ProfileSyncService::OnPassphraseAccepted() {
- DVLOG(1) << "Received OnPassphraseAccepted.";
-
- // If the pending keys were resolved via keystore, it's possible we never
- // consumed our cached passphrase. Clear it now.
- if (!cached_passphrase_.empty())
- cached_passphrase_.clear();
-
- // Reset passphrase_required_reason_ since we know we no longer require the
- // passphrase. We do this here rather than down in ResolvePassphraseRequired()
- // because that can be called by OnPassphraseRequired() if no encrypted data
- // types are enabled, and we don't want to clobber the true passphrase error.
- passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
-
- // Make sure the data types that depend on the passphrase are started at
- // this time.
- // TODO(stanisc): http://crbug.com/351005: Does this support USS types?
- const syncer::ModelTypeSet types = GetPreferredDataTypes();
- if (data_type_manager_) {
- // Re-enable any encrypted types if necessary.
- data_type_manager_->Configure(types, syncer::CONFIGURE_REASON_CRYPTO);
- }
-
- NotifyObservers();
-}
-
-void ProfileSyncService::OnEncryptedTypesChanged(
- syncer::ModelTypeSet encrypted_types,
- bool encrypt_everything) {
- encrypted_types_ = encrypted_types;
- encrypt_everything_ = encrypt_everything;
- DCHECK(encrypt_everything_allowed_ || !encrypt_everything_);
- DVLOG(1) << "Encrypted types changed to "
- << syncer::ModelTypeSetToString(encrypted_types_)
- << " (encrypt everything is set to "
- << (encrypt_everything_ ? "true" : "false") << ")";
- DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
-
- NotifyObservers();
-}
-
-void ProfileSyncService::OnEncryptionComplete() {
- DVLOG(1) << "Encryption complete";
- if (encryption_pending_ && encrypt_everything_) {
- encryption_pending_ = false;
- // This is to nudge the integration tests when encryption is
- // finished.
- NotifyObservers();
- }
-}
-
-void ProfileSyncService::OnMigrationNeededForTypes(
- syncer::ModelTypeSet types) {
- DCHECK(backend_initialized_);
- DCHECK(data_type_manager_.get());
-
- // Migrator must be valid, because we don't sync until it is created and this
- // callback originates from a sync cycle.
- migrator_->MigrateTypes(types);
-}
-
-void ProfileSyncService::OnActionableError(const SyncProtocolError& error) {
- last_actionable_error_ = error;
- DCHECK_NE(last_actionable_error_.action,
- syncer::UNKNOWN_ACTION);
- switch (error.action) {
- case syncer::UPGRADE_CLIENT:
- case syncer::CLEAR_USER_DATA_AND_RESYNC:
- case syncer::ENABLE_SYNC_ON_ACCOUNT:
- case syncer::STOP_AND_RESTART_SYNC:
- // TODO(lipalani) : if setup in progress we want to display these
- // actions in the popup. The current experience might not be optimal for
- // the user. We just dismiss the dialog.
- if (startup_controller_->IsSetupInProgress()) {
- RequestStop(CLEAR_DATA);
- expect_sync_configuration_aborted_ = true;
- }
- // Trigger an unrecoverable error to stop syncing.
- OnInternalUnrecoverableError(FROM_HERE,
- last_actionable_error_.error_description,
- true,
- ERROR_REASON_ACTIONABLE_ERROR);
- break;
- case syncer::DISABLE_SYNC_ON_CLIENT:
- if (error.error_type == syncer::NOT_MY_BIRTHDAY) {
- UMA_HISTOGRAM_ENUMERATION("Sync.StopSource", syncer::BIRTHDAY_ERROR,
- syncer::STOP_SOURCE_LIMIT);
- }
- RequestStop(CLEAR_DATA);
-#if !defined(OS_CHROMEOS)
- // On every platform except ChromeOS, sign out the user after a dashboard
- // clear.
- static_cast<SigninManager*>(signin_->GetOriginal())
- ->SignOut(signin_metrics::SERVER_FORCED_DISABLE,
- signin_metrics::SignoutDelete::IGNORE_METRIC);
-#endif
- break;
- case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
- // Sync disabled by domain admin. we should stop syncing until next
- // restart.
- sync_disabled_by_admin_ = true;
- ShutdownImpl(syncer::DISABLE_SYNC);
- break;
- case syncer::RESET_LOCAL_SYNC_DATA:
- ShutdownImpl(syncer::DISABLE_SYNC);
- startup_controller_->TryStart();
- break;
- default:
- NOTREACHED();
- }
- NotifyObservers();
-}
-
-void ProfileSyncService::OnLocalSetPassphraseEncryption(
- const syncer::SyncEncryptionHandler::NigoriState& nigori_state) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::FeatureList::IsEnabled(
- switches::kSyncClearDataOnPassphraseEncryption))
- return;
-
- // At this point the user has set a custom passphrase and we have received the
- // updated nigori state. Time to cache the nigori state, and catch up the
- // active data types.
- sync_prefs_.SetSavedNigoriStateForPassphraseEncryptionTransition(
- nigori_state);
- sync_prefs_.SetPassphraseEncryptionTransitionInProgress(true);
- BeginConfigureCatchUpBeforeClear();
-}
-
-void ProfileSyncService::BeginConfigureCatchUpBeforeClear() {
- DCHECK(data_type_manager_);
- DCHECK(!saved_nigori_state_);
- saved_nigori_state_ =
- sync_prefs_.GetSavedNigoriStateForPassphraseEncryptionTransition();
- const syncer::ModelTypeSet types = GetActiveDataTypes();
- catch_up_configure_in_progress_ = true;
- data_type_manager_->Configure(types, syncer::CONFIGURE_REASON_CATCH_UP);
-}
-
-void ProfileSyncService::ClearAndRestartSyncForPassphraseEncryption() {
- DCHECK(thread_checker_.CalledOnValidThread());
- backend_->ClearServerData(
- base::Bind(&ProfileSyncService::OnClearServerDataDone,
- sync_enabled_weak_factory_.GetWeakPtr()));
-}
-
-void ProfileSyncService::OnClearServerDataDone() {
- DCHECK(sync_prefs_.GetPassphraseEncryptionTransitionInProgress());
- sync_prefs_.SetPassphraseEncryptionTransitionInProgress(false);
-
- // Call to ClearServerData generates new keystore key on the server. This
- // makes keystore bootstrap token invalid. Let's clear it from preferences.
- sync_prefs_.SetKeystoreEncryptionBootstrapToken(std::string());
-
- // Shutdown sync, delete the Directory, then restart, restoring the cached
- // nigori state.
- ShutdownImpl(syncer::DISABLE_SYNC);
- startup_controller_->TryStart();
-}
-
-void ProfileSyncService::OnConfigureDone(
- const DataTypeManager::ConfigureResult& result) {
- configure_status_ = result.status;
- data_type_status_table_ = result.data_type_status_table;
-
- // We should have cleared our cached passphrase before we get here (in
- // OnBackendInitialized()).
- DCHECK(cached_passphrase_.empty());
-
- if (!sync_configure_start_time_.is_null()) {
- if (result.status == DataTypeManager::OK) {
- base::Time sync_configure_stop_time = base::Time::Now();
- base::TimeDelta delta = sync_configure_stop_time -
- sync_configure_start_time_;
- if (is_first_time_sync_configure_) {
- UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceInitialConfigureTime", delta);
- } else {
- UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceSubsequentConfigureTime",
- delta);
- }
- }
- sync_configure_start_time_ = base::Time();
- }
-
- // Notify listeners that configuration is done.
- FOR_EACH_OBSERVER(sync_driver::SyncServiceObserver, observers_,
- OnSyncConfigurationCompleted());
-
- DVLOG(1) << "PSS OnConfigureDone called with status: " << configure_status_;
- // The possible status values:
- // ABORT - Configuration was aborted. This is not an error, if
- // initiated by user.
- // OK - Some or all types succeeded.
- // Everything else is an UnrecoverableError. So treat it as such.
-
- // First handle the abort case.
- if (configure_status_ == DataTypeManager::ABORTED &&
- expect_sync_configuration_aborted_) {
- DVLOG(0) << "ProfileSyncService::Observe Sync Configure aborted";
- expect_sync_configuration_aborted_ = false;
- return;
- }
-
- // Handle unrecoverable error.
- if (configure_status_ != DataTypeManager::OK) {
- // Something catastrophic had happened. We should only have one
- // error representing it.
- syncer::SyncError error =
- data_type_status_table_.GetUnrecoverableError();
- DCHECK(error.IsSet());
- std::string message =
- "Sync configuration failed with status " +
- DataTypeManager::ConfigureStatusToString(configure_status_) +
- " caused by " +
- syncer::ModelTypeSetToString(
- data_type_status_table_.GetUnrecoverableErrorTypes()) +
- ": " + error.message();
- LOG(ERROR) << "ProfileSyncService error: " << message;
- OnInternalUnrecoverableError(error.location(),
- message,
- true,
- ERROR_REASON_CONFIGURATION_FAILURE);
- return;
- }
-
- DCHECK_EQ(DataTypeManager::OK, configure_status_);
-
- // We should never get in a state where we have no encrypted datatypes
- // enabled, and yet we still think we require a passphrase for decryption.
- DCHECK(!(IsPassphraseRequiredForDecryption() &&
- !IsEncryptedDatatypeEnabled()));
-
- // This must be done before we start syncing with the server to avoid
- // sending unencrypted data up on a first time sync.
- if (encryption_pending_)
- backend_->EnableEncryptEverything();
- NotifyObservers();
-
- if (migrator_.get() &&
- migrator_->state() != browser_sync::BackendMigrator::IDLE) {
- // Migration in progress. Let the migrator know we just finished
- // configuring something. It will be up to the migrator to call
- // StartSyncingWithServer() if migration is now finished.
- migrator_->OnConfigureDone(result);
- return;
- }
-
- if (catch_up_configure_in_progress_) {
- catch_up_configure_in_progress_ = false;
- ClearAndRestartSyncForPassphraseEncryption();
- return;
- }
-
- StartSyncingWithServer();
-}
-
-void ProfileSyncService::OnConfigureStart() {
- sync_configure_start_time_ = base::Time::Now();
- NotifyObservers();
-}
-
-ProfileSyncService::SyncStatusSummary
- ProfileSyncService::QuerySyncStatusSummary() {
- if (HasUnrecoverableError()) {
- return UNRECOVERABLE_ERROR;
- } else if (!backend_) {
- return NOT_ENABLED;
- } else if (backend_.get() && !IsFirstSetupComplete()) {
- return SETUP_INCOMPLETE;
- } else if (backend_ && IsFirstSetupComplete() && data_type_manager_ &&
- data_type_manager_->state() == DataTypeManager::STOPPED) {
- return DATATYPES_NOT_INITIALIZED;
- } else if (IsSyncActive()) {
- return INITIALIZED;
- }
- return UNKNOWN_ERROR;
-}
-
-std::string ProfileSyncService::QuerySyncStatusSummaryString() {
- SyncStatusSummary status = QuerySyncStatusSummary();
-
- std::string config_status_str =
- configure_status_ != DataTypeManager::UNKNOWN ?
- DataTypeManager::ConfigureStatusToString(configure_status_) : "";
-
- switch (status) {
- case UNRECOVERABLE_ERROR:
- return "Unrecoverable error detected";
- case NOT_ENABLED:
- return "Syncing not enabled";
- case SETUP_INCOMPLETE:
- return "First time sync setup incomplete";
- case DATATYPES_NOT_INITIALIZED:
- return "Datatypes not fully initialized";
- case INITIALIZED:
- return "Sync service initialized";
- default:
- return "Status unknown: Internal error?";
- }
-}
-
-std::string ProfileSyncService::GetBackendInitializationStateString() const {
- return startup_controller_->GetBackendInitializationStateString();
-}
-
-bool ProfileSyncService::IsSetupInProgress() const {
- return startup_controller_->IsSetupInProgress();
-}
-
-bool ProfileSyncService::QueryDetailedSyncStatus(
- SyncBackendHost::Status* result) {
- if (backend_.get() && backend_initialized_) {
- *result = backend_->GetDetailedStatus();
- return true;
- } else {
- SyncBackendHost::Status status;
- status.sync_protocol_error = last_actionable_error_;
- *result = status;
- return false;
- }
-}
-
-const AuthError& ProfileSyncService::GetAuthError() const {
- return last_auth_error_;
-}
-
-bool ProfileSyncService::CanConfigureDataTypes() const {
- return IsFirstSetupComplete() && !IsSetupInProgress();
-}
-
-bool ProfileSyncService::IsFirstSetupInProgress() const {
- return !IsFirstSetupComplete() && startup_controller_->IsSetupInProgress();
-}
-
-std::unique_ptr<sync_driver::SyncSetupInProgressHandle>
-ProfileSyncService::GetSetupInProgressHandle() {
- if (++outstanding_setup_in_progress_handles_ == 1) {
- DCHECK(!startup_controller_->IsSetupInProgress());
- startup_controller_->SetSetupInProgress(true);
-
- NotifyObservers();
- }
-
- return std::unique_ptr<sync_driver::SyncSetupInProgressHandle>(
- new sync_driver::SyncSetupInProgressHandle(
- base::Bind(&ProfileSyncService::OnSetupInProgressHandleDestroyed,
- weak_factory_.GetWeakPtr())));
-}
-
-bool ProfileSyncService::IsSyncAllowed() const {
- return IsSyncAllowedByFlag() && !IsManaged() && IsSyncAllowedByPlatform();
-}
-
-bool ProfileSyncService::IsSyncActive() const {
- return backend_initialized_ && data_type_manager_ &&
- data_type_manager_->state() != DataTypeManager::STOPPED;
-}
-
-void ProfileSyncService::TriggerRefresh(const syncer::ModelTypeSet& types) {
- if (backend_initialized_)
- backend_->TriggerRefresh(types);
-}
-
-bool ProfileSyncService::IsSignedIn() const {
- // Sync is logged in if there is a non-empty effective account id.
- return !signin_->GetAccountIdToUse().empty();
-}
-
-bool ProfileSyncService::CanBackendStart() const {
- return CanSyncStart() && oauth2_token_service_ &&
- oauth2_token_service_->RefreshTokenIsAvailable(
- signin_->GetAccountIdToUse());
-}
-
-bool ProfileSyncService::IsBackendInitialized() const {
- return backend_initialized_;
-}
-
-bool ProfileSyncService::ConfigurationDone() const {
- return data_type_manager_ &&
- data_type_manager_->state() == DataTypeManager::CONFIGURED;
-}
-
-bool ProfileSyncService::waiting_for_auth() const {
- return is_auth_in_progress_;
-}
-
-const syncer::Experiments& ProfileSyncService::current_experiments() const {
- return current_experiments_;
-}
-
-bool ProfileSyncService::HasUnrecoverableError() const {
- return unrecoverable_error_reason_ != ERROR_REASON_UNSET;
-}
-
-bool ProfileSyncService::IsPassphraseRequired() const {
- return passphrase_required_reason_ !=
- syncer::REASON_PASSPHRASE_NOT_REQUIRED;
-}
-
-bool ProfileSyncService::IsPassphraseRequiredForDecryption() const {
- // If there is an encrypted datatype enabled and we don't have the proper
- // passphrase, we must prompt the user for a passphrase. The only way for the
- // user to avoid entering their passphrase is to disable the encrypted types.
- return IsEncryptedDatatypeEnabled() && IsPassphraseRequired();
-}
-
-base::string16 ProfileSyncService::GetLastSyncedTimeString() const {
- const base::Time last_synced_time = sync_prefs_.GetLastSyncedTime();
- if (last_synced_time.is_null())
- return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
-
- base::TimeDelta time_since_last_sync = base::Time::Now() - last_synced_time;
-
- if (time_since_last_sync < base::TimeDelta::FromMinutes(1))
- return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
-
- return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED,
- ui::TimeFormat::LENGTH_SHORT,
- time_since_last_sync);
-}
-
-void ProfileSyncService::UpdateSelectedTypesHistogram(
- bool sync_everything, const syncer::ModelTypeSet chosen_types) const {
- if (!IsFirstSetupComplete() ||
- sync_everything != sync_prefs_.HasKeepEverythingSynced()) {
- UMA_HISTOGRAM_BOOLEAN("Sync.SyncEverything", sync_everything);
- }
-
- // Only log the data types that are shown in the sync settings ui.
- // Note: the order of these types must match the ordering of
- // the respective types in ModelType
- const sync_driver::user_selectable_type::UserSelectableSyncType
- user_selectable_types[] = {
- sync_driver::user_selectable_type::BOOKMARKS,
- sync_driver::user_selectable_type::PREFERENCES,
- sync_driver::user_selectable_type::PASSWORDS,
- sync_driver::user_selectable_type::AUTOFILL,
- sync_driver::user_selectable_type::THEMES,
- sync_driver::user_selectable_type::TYPED_URLS,
- sync_driver::user_selectable_type::EXTENSIONS,
- sync_driver::user_selectable_type::APPS,
- sync_driver::user_selectable_type::PROXY_TABS,
- };
-
- static_assert(37 == syncer::MODEL_TYPE_COUNT,
- "custom config histogram must be updated");
-
- if (!sync_everything) {
- const syncer::ModelTypeSet current_types = GetPreferredDataTypes();
-
- syncer::ModelTypeSet type_set = syncer::UserSelectableTypes();
- syncer::ModelTypeSet::Iterator it = type_set.First();
-
- DCHECK_EQ(arraysize(user_selectable_types), type_set.Size());
-
- for (size_t i = 0; i < arraysize(user_selectable_types) && it.Good();
- ++i, it.Inc()) {
- const syncer::ModelType type = it.Get();
- if (chosen_types.Has(type) &&
- (!IsFirstSetupComplete() || !current_types.Has(type))) {
- // Selected type has changed - log it.
- UMA_HISTOGRAM_ENUMERATION(
- "Sync.CustomSync",
- user_selectable_types[i],
- sync_driver::user_selectable_type::SELECTABLE_DATATYPE_COUNT + 1);
- }
- }
- }
-}
-
-#if defined(OS_CHROMEOS)
-void ProfileSyncService::RefreshSpareBootstrapToken(
- const std::string& passphrase) {
- sync_driver::SystemEncryptor encryptor;
- syncer::Cryptographer temp_cryptographer(&encryptor);
- // The first 2 params (hostname and username) doesn't have any effect here.
- syncer::KeyParams key_params = {"localhost", "dummy", passphrase};
-
- std::string bootstrap_token;
- if (!temp_cryptographer.AddKey(key_params)) {
- NOTREACHED() << "Failed to add key to cryptographer.";
- }
- temp_cryptographer.GetBootstrapToken(&bootstrap_token);
- sync_prefs_.SetSpareBootstrapToken(bootstrap_token);
-}
-#endif
-
-void ProfileSyncService::OnUserChoseDatatypes(
- bool sync_everything,
- syncer::ModelTypeSet chosen_types) {
- DCHECK(syncer::UserSelectableTypes().HasAll(chosen_types));
-
- if (!backend_.get() && !HasUnrecoverableError()) {
- NOTREACHED();
- return;
- }
-
- UpdateSelectedTypesHistogram(sync_everything, chosen_types);
- sync_prefs_.SetKeepEverythingSynced(sync_everything);
-
- if (data_type_manager_)
- data_type_manager_->ResetDataTypeErrors();
- ChangePreferredDataTypes(chosen_types);
-}
-
-void ProfileSyncService::ChangePreferredDataTypes(
- syncer::ModelTypeSet preferred_types) {
-
- DVLOG(1) << "ChangePreferredDataTypes invoked";
- const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
- // Will only enable those types that are registered and preferred.
- sync_prefs_.SetPreferredDataTypes(registered_types, preferred_types);
-
- // Now reconfigure the DTM.
- ReconfigureDatatypeManager();
-}
-
-syncer::ModelTypeSet ProfileSyncService::GetActiveDataTypes() const {
- if (!IsSyncActive() || !ConfigurationDone())
- return syncer::ModelTypeSet();
- const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
- const syncer::ModelTypeSet failed_types =
- data_type_status_table_.GetFailedTypes();
- return Difference(preferred_types, failed_types);
-}
-
-sync_driver::SyncClient* ProfileSyncService::GetSyncClient() const {
- return sync_client_.get();
-}
-
-syncer::ModelTypeSet ProfileSyncService::GetPreferredDataTypes() const {
- const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
- const syncer::ModelTypeSet preferred_types =
- Union(sync_prefs_.GetPreferredDataTypes(registered_types),
- syncer::ControlTypes());
- const syncer::ModelTypeSet enforced_types =
- Intersection(GetDataTypesFromPreferenceProviders(), registered_types);
- return Union(preferred_types, enforced_types);
-}
-
-syncer::ModelTypeSet ProfileSyncService::GetForcedDataTypes() const {
- // TODO(treib,zea): When SyncPrefs also implements SyncTypePreferenceProvider,
- // we'll need another way to distinguish user-choosable types from
- // programmatically-enabled types.
- return GetDataTypesFromPreferenceProviders();
-}
-
-syncer::ModelTypeSet ProfileSyncService::GetRegisteredDataTypes() const {
- syncer::ModelTypeSet registered_types;
- // The data_type_controllers_ are determined by command-line flags;
- // that's effectively what controls the values returned here.
- for (DataTypeController::TypeMap::const_iterator it =
- data_type_controllers_.begin();
- it != data_type_controllers_.end(); ++it) {
- registered_types.Put(it->first);
- }
- return registered_types;
-}
-
-bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
- syncer::PassphraseType passphrase_type = GetPassphraseType();
- return passphrase_type == syncer::FROZEN_IMPLICIT_PASSPHRASE ||
- passphrase_type == syncer::CUSTOM_PASSPHRASE;
-}
-
-std::string ProfileSyncService::GetCustomPassphraseKey() const {
- sync_driver::SystemEncryptor encryptor;
- syncer::Cryptographer cryptographer(&encryptor);
- cryptographer.Bootstrap(sync_prefs_.GetEncryptionBootstrapToken());
- return cryptographer.GetDefaultNigoriKeyData();
-}
-
-syncer::PassphraseType ProfileSyncService::GetPassphraseType() const {
- return backend_->GetPassphraseType();
-}
-
-base::Time ProfileSyncService::GetExplicitPassphraseTime() const {
- return backend_->GetExplicitPassphraseTime();
-}
-
-bool ProfileSyncService::IsCryptographerReady(
- const syncer::BaseTransaction* trans) const {
- return backend_.get() && backend_->IsCryptographerReady(trans);
-}
-
-void ProfileSyncService::SetPlatformSyncAllowedProvider(
- const PlatformSyncAllowedProvider& platform_sync_allowed_provider) {
- platform_sync_allowed_provider_ = platform_sync_allowed_provider;
-}
-
-void ProfileSyncService::ConfigureDataTypeManager() {
- // Don't configure datatypes if the setup UI is still on the screen - this
- // is to help multi-screen setting UIs (like iOS) where they don't want to
- // start syncing data until the user is done configuring encryption options,
- // etc. ReconfigureDatatypeManager() will get called again once the UI calls
- // SetSetupInProgress(false).
- if (!CanConfigureDataTypes()) {
- // If we can't configure the data type manager yet, we should still notify
- // observers. This is to support multiple setup UIs being open at once.
- NotifyObservers();
- return;
- }
-
- bool restart = false;
- if (!data_type_manager_) {
- restart = true;
- data_type_manager_.reset(
- sync_client_->GetSyncApiComponentFactory()->CreateDataTypeManager(
- debug_info_listener_, &data_type_controllers_, this, backend_.get(),
- this));
-
- // We create the migrator at the same time.
- migrator_.reset(new browser_sync::BackendMigrator(
- debug_identifier_, GetUserShare(), this, data_type_manager_.get(),
- base::Bind(&ProfileSyncService::StartSyncingWithServer,
- base::Unretained(this))));
- }
-
- syncer::ModelTypeSet types;
- syncer::ConfigureReason reason = syncer::CONFIGURE_REASON_UNKNOWN;
- types = GetPreferredDataTypes();
- if (restart) {
- // Datatype downloads on restart are generally due to newly supported
- // datatypes (although it's also possible we're picking up where a failed
- // previous configuration left off).
- // TODO(sync): consider detecting configuration recovery and setting
- // the reason here appropriately.
- reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
- } else {
- // The user initiated a reconfiguration (either to add or remove types).
- reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
- }
-
- data_type_manager_->Configure(types, reason);
-}
-
-syncer::UserShare* ProfileSyncService::GetUserShare() const {
- if (backend_.get() && backend_initialized_) {
- return backend_->GetUserShare();
- }
- NOTREACHED();
- return NULL;
-}
-
-syncer::sessions::SyncSessionSnapshot
-ProfileSyncService::GetLastSessionSnapshot() const {
- if (backend_)
- return backend_->GetLastSessionSnapshot();
- return syncer::sessions::SyncSessionSnapshot();
-}
-
-bool ProfileSyncService::HasUnsyncedItems() const {
- if (HasSyncingBackend() && backend_initialized_) {
- return backend_->HasUnsyncedItems();
- }
- NOTREACHED();
- return false;
-}
-
-browser_sync::BackendMigrator*
-ProfileSyncService::GetBackendMigratorForTest() {
- return migrator_.get();
-}
-
-void ProfileSyncService::GetModelSafeRoutingInfo(
- syncer::ModelSafeRoutingInfo* out) const {
- if (backend_.get() && backend_initialized_) {
- backend_->GetModelSafeRoutingInfo(out);
- } else {
- NOTREACHED();
- }
-}
-
-base::Value* ProfileSyncService::GetTypeStatusMap() const {
- std::unique_ptr<base::ListValue> result(new base::ListValue());
-
- if (!backend_.get() || !backend_initialized_) {
- return result.release();
- }
-
- DataTypeStatusTable::TypeErrorMap error_map =
- data_type_status_table_.GetAllErrors();
- ModelTypeSet active_types;
- ModelTypeSet passive_types;
- ModelSafeRoutingInfo routing_info;
- backend_->GetModelSafeRoutingInfo(&routing_info);
- for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
- it != routing_info.end(); ++it) {
- if (it->second == syncer::GROUP_PASSIVE) {
- passive_types.Put(it->first);
- } else {
- active_types.Put(it->first);
- }
- }
-
- SyncBackendHost::Status detailed_status = backend_->GetDetailedStatus();
- ModelTypeSet& throttled_types(detailed_status.throttled_types);
- ModelTypeSet registered = GetRegisteredDataTypes();
- std::unique_ptr<base::DictionaryValue> type_status_header(
- new base::DictionaryValue());
-
- type_status_header->SetString("name", "Model Type");
- type_status_header->SetString("status", "header");
- type_status_header->SetString("value", "Group Type");
- type_status_header->SetString("num_entries", "Total Entries");
- type_status_header->SetString("num_live", "Live Entries");
- result->Append(std::move(type_status_header));
-
- std::unique_ptr<base::DictionaryValue> type_status;
- for (ModelTypeSet::Iterator it = registered.First(); it.Good(); it.Inc()) {
- ModelType type = it.Get();
-
- type_status.reset(new base::DictionaryValue());
- type_status->SetString("name", ModelTypeToString(type));
-
- if (error_map.find(type) != error_map.end()) {
- const syncer::SyncError &error = error_map.find(type)->second;
- DCHECK(error.IsSet());
- switch (error.GetSeverity()) {
- case syncer::SyncError::SYNC_ERROR_SEVERITY_ERROR: {
- std::string error_text = "Error: " + error.location().ToString() +
- ", " + error.GetMessagePrefix() + error.message();
- type_status->SetString("status", "error");
- type_status->SetString("value", error_text);
- }
- break;
- case syncer::SyncError::SYNC_ERROR_SEVERITY_INFO:
- type_status->SetString("status", "disabled");
- type_status->SetString("value", error.message());
- break;
- default:
- NOTREACHED() << "Unexpected error severity.";
- break;
- }
- } else if (syncer::IsProxyType(type) && passive_types.Has(type)) {
- // Show a proxy type in "ok" state unless it is disabled by user.
- DCHECK(!throttled_types.Has(type));
- type_status->SetString("status", "ok");
- type_status->SetString("value", "Passive");
- } else if (throttled_types.Has(type) && passive_types.Has(type)) {
- type_status->SetString("status", "warning");
- type_status->SetString("value", "Passive, Throttled");
- } else if (passive_types.Has(type)) {
- type_status->SetString("status", "warning");
- type_status->SetString("value", "Passive");
- } else if (throttled_types.Has(type)) {
- type_status->SetString("status", "warning");
- type_status->SetString("value", "Throttled");
- } else if (active_types.Has(type)) {
- type_status->SetString("status", "ok");
- type_status->SetString("value", "Active: " +
- ModelSafeGroupToString(routing_info[type]));
- } else {
- type_status->SetString("status", "warning");
- type_status->SetString("value", "Disabled by User");
- }
-
- int live_count = detailed_status.num_entries_by_type[type] -
- detailed_status.num_to_delete_entries_by_type[type];
- type_status->SetInteger("num_entries",
- detailed_status.num_entries_by_type[type]);
- type_status->SetInteger("num_live", live_count);
-
- result->Append(std::move(type_status));
- }
- return result.release();
-}
-
-void ProfileSyncService::ConsumeCachedPassphraseIfPossible() {
- // If no cached passphrase, or sync backend hasn't started up yet, just exit.
- // If the backend isn't running yet, OnBackendInitialized() will call this
- // method again after the backend starts up.
- if (cached_passphrase_.empty() || !IsBackendInitialized())
- return;
-
- // Backend is up and running, so we can consume the cached passphrase.
- std::string passphrase = cached_passphrase_;
- cached_passphrase_.clear();
-
- // If we need a passphrase to decrypt data, try the cached passphrase.
- if (passphrase_required_reason() == syncer::REASON_DECRYPTION) {
- if (SetDecryptionPassphrase(passphrase)) {
- DVLOG(1) << "Cached passphrase successfully decrypted pending keys";
- return;
- }
- }
-
- // If we get here, we don't have pending keys (or at least, the passphrase
- // doesn't decrypt them) - just try to re-encrypt using the encryption
- // passphrase.
- if (!IsUsingSecondaryPassphrase())
- SetEncryptionPassphrase(passphrase, IMPLICIT);
-}
-
-void ProfileSyncService::RequestAccessToken() {
- // Only one active request at a time.
- if (access_token_request_ != NULL)
- return;
- request_access_token_retry_timer_.Stop();
- OAuth2TokenService::ScopeSet oauth2_scopes;
- oauth2_scopes.insert(signin_->GetSyncScopeToUse());
-
- // Invalidate previous token, otherwise token service will return the same
- // token again.
- const std::string& account_id = signin_->GetAccountIdToUse();
- if (!access_token_.empty()) {
- oauth2_token_service_->InvalidateAccessToken(account_id, oauth2_scopes,
- access_token_);
- }
-
- access_token_.clear();
-
- token_request_time_ = base::Time::Now();
- token_receive_time_ = base::Time();
- next_token_request_time_ = base::Time();
- access_token_request_ =
- oauth2_token_service_->StartRequest(account_id, oauth2_scopes, this);
-}
-
-void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase,
- PassphraseType type) {
- // This should only be called when the backend has been initialized.
- DCHECK(IsBackendInitialized());
- DCHECK(!(type == IMPLICIT && IsUsingSecondaryPassphrase())) <<
- "Data is already encrypted using an explicit passphrase";
- DCHECK(!(type == EXPLICIT &&
- passphrase_required_reason_ == syncer::REASON_DECRYPTION)) <<
- "Can not set explicit passphrase when decryption is needed.";
-
- DVLOG(1) << "Setting " << (type == EXPLICIT ? "explicit" : "implicit")
- << " passphrase for encryption.";
- if (passphrase_required_reason_ == syncer::REASON_ENCRYPTION) {
- // REASON_ENCRYPTION implies that the cryptographer does not have pending
- // keys. Hence, as long as we're not trying to do an invalid passphrase
- // change (e.g. explicit -> explicit or explicit -> implicit), we know this
- // will succeed. If for some reason a new encryption key arrives via
- // sync later, the SBH will trigger another OnPassphraseRequired().
- passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
- NotifyObservers();
- }
- backend_->SetEncryptionPassphrase(passphrase, type == EXPLICIT);
-}
-
-bool ProfileSyncService::SetDecryptionPassphrase(
- const std::string& passphrase) {
- if (IsPassphraseRequired()) {
- DVLOG(1) << "Setting passphrase for decryption.";
- bool result = backend_->SetDecryptionPassphrase(passphrase);
- UMA_HISTOGRAM_BOOLEAN("Sync.PassphraseDecryptionSucceeded", result);
- return result;
- } else {
- NOTREACHED() << "SetDecryptionPassphrase must not be called when "
- "IsPassphraseRequired() is false.";
- return false;
- }
-}
-
-bool ProfileSyncService::IsEncryptEverythingAllowed() const {
- return encrypt_everything_allowed_;
-}
-
-void ProfileSyncService::SetEncryptEverythingAllowed(bool allowed) {
- DCHECK(allowed || !IsBackendInitialized() || !IsEncryptEverythingEnabled());
- encrypt_everything_allowed_ = allowed;
-}
-
-void ProfileSyncService::EnableEncryptEverything() {
- DCHECK(IsEncryptEverythingAllowed());
-
- // Tests override IsBackendInitialized() to always return true, so we
- // must check that instead of |backend_initialized_|.
- // TODO(akalin): Fix the above. :/
- DCHECK(IsBackendInitialized());
- // TODO(atwilson): Persist the encryption_pending_ flag to address the various
- // problems around cancelling encryption in the background (crbug.com/119649).
- if (!encrypt_everything_)
- encryption_pending_ = true;
-}
-
-bool ProfileSyncService::encryption_pending() const {
- // We may be called during the setup process before we're
- // initialized (via IsEncryptedDatatypeEnabled and
- // IsPassphraseRequiredForDecryption).
- return encryption_pending_;
-}
-
-bool ProfileSyncService::IsEncryptEverythingEnabled() const {
- DCHECK(backend_initialized_);
- return encrypt_everything_ || encryption_pending_;
-}
-
-syncer::ModelTypeSet ProfileSyncService::GetEncryptedDataTypes() const {
- DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
- // We may be called during the setup process before we're
- // initialized. In this case, we default to the sensitive types.
- return encrypted_types_;
-}
-
-void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) {
- if (is_sync_managed) {
- StopImpl(CLEAR_DATA);
- } else {
- // Sync is no longer disabled by policy. Try starting it up if appropriate.
- startup_controller_->TryStart();
- }
-}
-
-void ProfileSyncService::GoogleSigninSucceeded(const std::string& account_id,
- const std::string& username,
- const std::string& password) {
- if (IsSyncRequested() && !password.empty()) {
- cached_passphrase_ = password;
- // Try to consume the passphrase we just cached. If the sync backend
- // is not running yet, the passphrase will remain cached until the
- // backend starts up.
- ConsumeCachedPassphraseIfPossible();
- }
-#if defined(OS_CHROMEOS)
- RefreshSpareBootstrapToken(password);
-#endif
- if (!IsBackendInitialized() || GetAuthError().state() != AuthError::NONE) {
- // Track the fact that we're still waiting for auth to complete.
- is_auth_in_progress_ = true;
- }
-}
-
-void ProfileSyncService::GoogleSignedOut(const std::string& account_id,
- const std::string& username) {
- sync_disabled_by_admin_ = false;
- UMA_HISTOGRAM_ENUMERATION("Sync.StopSource", syncer::SIGN_OUT,
- syncer::STOP_SOURCE_LIMIT);
- RequestStop(CLEAR_DATA);
-}
-
-void ProfileSyncService::OnGaiaAccountsInCookieUpdated(
- const std::vector<gaia::ListedAccount>& accounts,
- const std::vector<gaia::ListedAccount>& signed_out_accounts,
- const GoogleServiceAuthError& error) {
- if (!IsBackendInitialized())
- return;
-
- bool cookie_jar_mismatch = true;
- bool cookie_jar_empty = accounts.size() == 0;
- std::string account_id = signin_->GetAccountIdToUse();
-
- // Iterate through list of accounts, looking for current sync account.
- for (const auto& account : accounts) {
- if (account.id == account_id) {
- cookie_jar_mismatch = false;
- break;
- }
- }
-
- DVLOG(1) << "Cookie jar mismatch: " << cookie_jar_mismatch;
- DVLOG(1) << "Cookie jar empty: " << cookie_jar_empty;
- backend_->OnCookieJarChanged(cookie_jar_mismatch, cookie_jar_empty);
-}
-
-void ProfileSyncService::AddObserver(
- sync_driver::SyncServiceObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void ProfileSyncService::RemoveObserver(
- sync_driver::SyncServiceObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void ProfileSyncService::AddProtocolEventObserver(
- browser_sync::ProtocolEventObserver* observer) {
- protocol_event_observers_.AddObserver(observer);
- if (HasSyncingBackend()) {
- backend_->RequestBufferedProtocolEventsAndEnableForwarding();
- }
-}
-
-void ProfileSyncService::RemoveProtocolEventObserver(
- browser_sync::ProtocolEventObserver* observer) {
- protocol_event_observers_.RemoveObserver(observer);
- if (HasSyncingBackend() &&
- !protocol_event_observers_.might_have_observers()) {
- backend_->DisableProtocolEventForwarding();
- }
-}
-
-void ProfileSyncService::AddTypeDebugInfoObserver(
- syncer::TypeDebugInfoObserver* type_debug_info_observer) {
- type_debug_info_observers_.AddObserver(type_debug_info_observer);
- if (type_debug_info_observers_.might_have_observers() &&
- backend_initialized_) {
- backend_->EnableDirectoryTypeDebugInfoForwarding();
- }
-}
-
-void ProfileSyncService::RemoveTypeDebugInfoObserver(
- syncer::TypeDebugInfoObserver* type_debug_info_observer) {
- type_debug_info_observers_.RemoveObserver(type_debug_info_observer);
- if (!type_debug_info_observers_.might_have_observers() &&
- backend_initialized_) {
- backend_->DisableDirectoryTypeDebugInfoForwarding();
- }
-}
-
-void ProfileSyncService::AddPreferenceProvider(
- SyncTypePreferenceProvider* provider) {
- DCHECK(!HasPreferenceProvider(provider))
- << "Providers may only be added once!";
- preference_providers_.insert(provider);
-}
-
-void ProfileSyncService::RemovePreferenceProvider(
- SyncTypePreferenceProvider* provider) {
- DCHECK(HasPreferenceProvider(provider))
- << "Only providers that have been added before can be removed!";
- preference_providers_.erase(provider);
-}
-
-bool ProfileSyncService::HasPreferenceProvider(
- SyncTypePreferenceProvider* provider) const {
- return preference_providers_.count(provider) > 0;
-}
-
-namespace {
-
-class GetAllNodesRequestHelper
- : public base::RefCountedThreadSafe<GetAllNodesRequestHelper> {
- public:
- GetAllNodesRequestHelper(
- syncer::ModelTypeSet requested_types,
- const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback);
-
- void OnReceivedNodesForTypes(
- const std::vector<syncer::ModelType>& types,
- ScopedVector<base::ListValue> scoped_node_lists);
-
- private:
- friend class base::RefCountedThreadSafe<GetAllNodesRequestHelper>;
- virtual ~GetAllNodesRequestHelper();
-
- std::unique_ptr<base::ListValue> result_accumulator_;
-
- syncer::ModelTypeSet awaiting_types_;
- base::Callback<void(std::unique_ptr<base::ListValue>)> callback_;
-};
-
-GetAllNodesRequestHelper::GetAllNodesRequestHelper(
- syncer::ModelTypeSet requested_types,
- const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback)
- : result_accumulator_(new base::ListValue()),
- awaiting_types_(requested_types),
- callback_(callback) {}
-
-GetAllNodesRequestHelper::~GetAllNodesRequestHelper() {
- if (!awaiting_types_.Empty()) {
- DLOG(WARNING)
- << "GetAllNodesRequest deleted before request was fulfilled. "
- << "Missing types are: " << ModelTypeSetToString(awaiting_types_);
- }
-}
-
-// Called when the set of nodes for a type or set of types has been returned.
-//
-// The nodes for several types can be returned at the same time by specifying
-// their types in the |types| array, and putting their results at the
-// correspnding indices in the |scoped_node_lists|.
-void GetAllNodesRequestHelper::OnReceivedNodesForTypes(
- const std::vector<syncer::ModelType>& types,
- ScopedVector<base::ListValue> scoped_node_lists) {
- DCHECK_EQ(types.size(), scoped_node_lists.size());
-
- // Take unsafe ownership of the node list.
- std::vector<base::ListValue*> node_lists;
- scoped_node_lists.release(&node_lists);
-
- for (size_t i = 0; i < node_lists.size() && i < types.size(); ++i) {
- const ModelType type = types[i];
- base::ListValue* node_list = node_lists[i];
-
- // Add these results to our list.
- std::unique_ptr<base::DictionaryValue> type_dict(
- new base::DictionaryValue());
- type_dict->SetString("type", ModelTypeToString(type));
- type_dict->Set("nodes", node_list);
- result_accumulator_->Append(std::move(type_dict));
-
- // Remember that this part of the request is satisfied.
- awaiting_types_.Remove(type);
- }
-
- if (awaiting_types_.Empty()) {
- callback_.Run(std::move(result_accumulator_));
- callback_.Reset();
- }
-}
-
-} // namespace
-
-void ProfileSyncService::GetAllNodes(
- const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback) {
- // TODO(stanisc): crbug.com/328606: Make this work for USS datatypes.
- ModelTypeSet all_types = GetRegisteredDataTypes();
- all_types.PutAll(syncer::ControlTypes());
- scoped_refptr<GetAllNodesRequestHelper> helper =
- new GetAllNodesRequestHelper(all_types, callback);
-
- if (!backend_initialized_) {
- // If there's no backend available to fulfill the request, handle it here.
- ScopedVector<base::ListValue> empty_results;
- std::vector<ModelType> type_vector;
- for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
- type_vector.push_back(it.Get());
- empty_results.push_back(new base::ListValue());
- }
- helper->OnReceivedNodesForTypes(type_vector, std::move(empty_results));
- } else {
- backend_->GetAllNodesForTypes(
- all_types,
- base::Bind(&GetAllNodesRequestHelper::OnReceivedNodesForTypes, helper));
- }
-}
-
-bool ProfileSyncService::HasObserver(
- const sync_driver::SyncServiceObserver* observer) const {
- return observers_.HasObserver(observer);
-}
-
-base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() {
- return sync_js_controller_.AsWeakPtr();
-}
-
-void ProfileSyncService::SyncEvent(SyncEventCodes code) {
- UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code, MAX_SYNC_EVENT_CODE);
-}
-
-// static
-bool ProfileSyncService::IsSyncAllowedByFlag() {
- return !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableSync);
-}
-
-bool ProfileSyncService::IsSyncAllowedByPlatform() const {
- return platform_sync_allowed_provider_.is_null() ||
- platform_sync_allowed_provider_.Run();
-}
-
-bool ProfileSyncService::IsManaged() const {
- return sync_prefs_.IsManaged() || sync_disabled_by_admin_;
-}
-
-void ProfileSyncService::RequestStop(SyncStopDataFate data_fate) {
- sync_prefs_.SetSyncRequested(false);
- StopImpl(data_fate);
-}
-
-bool ProfileSyncService::IsSyncRequested() const {
- return sync_prefs_.IsSyncRequested();
-}
-
-SigninManagerBase* ProfileSyncService::signin() const {
- if (!signin_)
- return NULL;
- return signin_->GetOriginal();
-}
-
-void ProfileSyncService::RequestStart() {
- if (!IsSyncAllowed()) {
- // Sync cannot be requested if it's not allowed.
- return;
- }
- DCHECK(sync_client_);
- if (!IsSyncRequested()) {
- sync_prefs_.SetSyncRequested(true);
- NotifyObservers();
- }
- startup_controller_->TryStartImmediately();
-}
-
-void ProfileSyncService::ReconfigureDatatypeManager() {
- // If we haven't initialized yet, don't configure the DTM as it could cause
- // association to start before a Directory has even been created.
- if (backend_initialized_) {
- DCHECK(backend_.get());
- ConfigureDataTypeManager();
- } else if (HasUnrecoverableError()) {
- // There is nothing more to configure. So inform the listeners,
- NotifyObservers();
-
- DVLOG(1) << "ConfigureDataTypeManager not invoked because of an "
- << "Unrecoverable error.";
- } else {
- DVLOG(0) << "ConfigureDataTypeManager not invoked because backend is not "
- << "initialized";
- }
-}
-
-syncer::ModelTypeSet ProfileSyncService::GetDataTypesFromPreferenceProviders()
- const {
- syncer::ModelTypeSet types;
- for (std::set<SyncTypePreferenceProvider*>::const_iterator it =
- preference_providers_.begin();
- it != preference_providers_.end();
- ++it) {
- types.PutAll((*it)->GetPreferredDataTypes());
- }
- return types;
-}
-
-const DataTypeStatusTable& ProfileSyncService::data_type_status_table()
- const {
- return data_type_status_table_;
-}
-
-void ProfileSyncService::OnInternalUnrecoverableError(
- const tracked_objects::Location& from_here,
- const std::string& message,
- bool delete_sync_database,
- UnrecoverableErrorReason reason) {
- DCHECK(!HasUnrecoverableError());
- unrecoverable_error_reason_ = reason;
- OnUnrecoverableErrorImpl(from_here, message, delete_sync_database);
-}
-
-bool ProfileSyncService::IsRetryingAccessTokenFetchForTest() const {
- return request_access_token_retry_timer_.IsRunning();
-}
-
-std::string ProfileSyncService::GetAccessTokenForTest() const {
- return access_token_;
-}
-
-WeakHandle<syncer::JsEventHandler> ProfileSyncService::GetJsEventHandler() {
- return MakeWeakHandle(sync_js_controller_.AsWeakPtr());
-}
-
-syncer::SyncableService* ProfileSyncService::GetSessionsSyncableService() {
- return sessions_sync_manager_.get();
-}
-
-syncer::SyncableService* ProfileSyncService::GetDeviceInfoSyncableService() {
- return device_info_sync_service_.get();
-}
-
-syncer_v2::ModelTypeService* ProfileSyncService::GetDeviceInfoService() {
- return device_info_service_.get();
-}
-
-sync_driver::SyncService::SyncTokenStatus
-ProfileSyncService::GetSyncTokenStatus() const {
- SyncTokenStatus status;
- status.connection_status_update_time = connection_status_update_time_;
- status.connection_status = connection_status_;
- status.token_request_time = token_request_time_;
- status.token_receive_time = token_receive_time_;
- status.last_get_token_error = last_get_token_error_;
- if (request_access_token_retry_timer_.IsRunning())
- status.next_token_request_time = next_token_request_time_;
- return status;
-}
-
-void ProfileSyncService::OverrideNetworkResourcesForTest(
- std::unique_ptr<syncer::NetworkResources> network_resources) {
- network_resources_ = std::move(network_resources);
-}
-
-bool ProfileSyncService::HasSyncingBackend() const {
- return backend_ != NULL;
-}
-
-void ProfileSyncService::UpdateFirstSyncTimePref() {
- if (!IsSignedIn()) {
- sync_prefs_.ClearFirstSyncTime();
- } else if (sync_prefs_.GetFirstSyncTime().is_null()) {
- // Set if not set before and it's syncing now.
- sync_prefs_.SetFirstSyncTime(base::Time::Now());
- }
-}
-
-void ProfileSyncService::FlushDirectory() const {
- // backend_initialized_ implies backend_ isn't NULL and the manager exists.
- // If sync is not initialized yet, we fail silently.
- if (backend_initialized_)
- backend_->FlushDirectory();
-}
-
-base::FilePath ProfileSyncService::GetDirectoryPathForTest() const {
- return directory_path_;
-}
-
-base::MessageLoop* ProfileSyncService::GetSyncLoopForTest() const {
- if (sync_thread_) {
- return sync_thread_->message_loop();
- } else if (backend_) {
- return backend_->GetSyncLoopForTesting();
- } else {
- return NULL;
- }
-}
-
-void ProfileSyncService::RefreshTypesForTest(syncer::ModelTypeSet types) {
- if (backend_initialized_)
- backend_->RefreshTypesForTest(types);
-}
-
-void ProfileSyncService::RemoveClientFromServer() const {
- if (!backend_initialized_) return;
- const std::string cache_guid = local_device_->GetLocalSyncCacheGUID();
- std::string birthday;
- syncer::UserShare* user_share = GetUserShare();
- if (user_share && user_share->directory.get()) {
- birthday = user_share->directory->store_birthday();
- }
- if (!access_token_.empty() && !cache_guid.empty() && !birthday.empty()) {
- sync_stopped_reporter_->ReportSyncStopped(
- access_token_, cache_guid, birthday);
- }
-}
-
-void ProfileSyncService::OnMemoryPressure(
- base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
- if (memory_pressure_level ==
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
- sync_prefs_.SetMemoryPressureWarningCount(
- sync_prefs_.GetMemoryPressureWarningCount() + 1);
- }
-}
-
-void ProfileSyncService::ReportPreviousSessionMemoryWarningCount() {
- int warning_received = sync_prefs_.GetMemoryPressureWarningCount();
-
- if (-1 != warning_received) {
- // -1 means it is new client.
- if (!sync_prefs_.DidSyncShutdownCleanly()) {
- UMA_HISTOGRAM_COUNTS("Sync.MemoryPressureWarningBeforeUncleanShutdown",
- warning_received);
- } else {
- UMA_HISTOGRAM_COUNTS("Sync.MemoryPressureWarningBeforeCleanShutdown",
- warning_received);
- }
- }
- sync_prefs_.SetMemoryPressureWarningCount(0);
- // Will set to true during a clean shutdown, so crash or something else will
- // remain this as false.
- sync_prefs_.SetCleanShutdown(false);
-}
-
-const GURL& ProfileSyncService::sync_service_url() const {
- return sync_service_url_;
-}
-
-std::string ProfileSyncService::unrecoverable_error_message() const {
- return unrecoverable_error_message_;
-}
-
-tracked_objects::Location ProfileSyncService::unrecoverable_error_location()
- const {
- return unrecoverable_error_location_;
-}
-
-void ProfileSyncService::OnSetupInProgressHandleDestroyed() {
- DCHECK_GT(outstanding_setup_in_progress_handles_, 0);
-
- // Don't re-start Sync until all outstanding handles are destroyed.
- if (--outstanding_setup_in_progress_handles_ != 0)
- return;
-
- DCHECK(startup_controller_->IsSetupInProgress());
- startup_controller_->SetSetupInProgress(false);
-
- if (IsBackendInitialized())
- ReconfigureDatatypeManager();
- NotifyObservers();
-}
diff --git a/chromium/components/browser_sync/browser/profile_sync_service.h b/chromium/components/browser_sync/browser/profile_sync_service.h
deleted file mode 100644
index 201e3030e22..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_service.h
+++ /dev/null
@@ -1,1029 +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 COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_SERVICE_H_
-#define COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_SERVICE_H_
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/gtest_prod_util.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/memory_pressure_listener.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/strings/string16.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "build/build_config.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/signin/core/browser/gaia_cookie_manager_service.h"
-#include "components/signin/core/browser/signin_manager_base.h"
-#include "components/sync_driver/data_type_controller.h"
-#include "components/sync_driver/data_type_manager.h"
-#include "components/sync_driver/data_type_manager_observer.h"
-#include "components/sync_driver/data_type_status_table.h"
-#include "components/sync_driver/glue/sync_backend_host.h"
-#include "components/sync_driver/local_device_info_provider.h"
-#include "components/sync_driver/protocol_event_observer.h"
-#include "components/sync_driver/startup_controller.h"
-#include "components/sync_driver/sync_client.h"
-#include "components/sync_driver/sync_frontend.h"
-#include "components/sync_driver/sync_prefs.h"
-#include "components/sync_driver/sync_service.h"
-#include "components/sync_driver/sync_stopped_reporter.h"
-#include "components/version_info/version_info.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "google_apis/gaia/oauth2_token_service.h"
-#include "net/base/backoff_entry.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/internal_api/public/engine/model_safe_worker.h"
-#include "sync/internal_api/public/network_time_update_callback.h"
-#include "sync/internal_api/public/shutdown_reason.h"
-#include "sync/internal_api/public/sync_manager_factory.h"
-#include "sync/internal_api/public/user_share.h"
-#include "sync/internal_api/public/util/experiments.h"
-#include "sync/internal_api/public/util/unrecoverable_error_handler.h"
-#include "sync/js/sync_js_controller.h"
-#include "url/gurl.h"
-
-class Profile;
-class ProfileOAuth2TokenService;
-class SigninManagerWrapper;
-class SyncErrorController;
-class SyncTypePreferenceProvider;
-
-namespace browser_sync {
-class BackendMigrator;
-class FaviconCache;
-class SessionsSyncManager;
-} // namespace browser_sync
-
-namespace sync_driver {
-class DataTypeManager;
-class DeviceInfoSyncService;
-class DeviceInfoTracker;
-class LocalDeviceInfoProvider;
-class OpenTabsUIDelegate;
-class SyncApiComponentFactory;
-class SyncClient;
-} // namespace sync_driver
-
-namespace sync_driver_v2 {
-class DeviceInfoService;
-}
-
-namespace syncer {
-class BaseTransaction;
-class NetworkResources;
-class TypeDebugInfoObserver;
-struct CommitCounters;
-struct StatusCounters;
-struct SyncCredentials;
-struct UpdateCounters;
-struct UserShare;
-} // namespace syncer
-
-namespace sync_pb {
-class EncryptedData;
-} // namespace sync_pb
-
-// ProfileSyncService is the layer between browser subsystems like bookmarks,
-// and the sync backend. Each subsystem is logically thought of as being
-// a sync datatype.
-//
-// Individual datatypes can, at any point, be in a variety of stages of being
-// "enabled". Here are some specific terms for concepts used in this class:
-//
-// 'Registered' (feature suppression for a datatype)
-//
-// When a datatype is registered, the user has the option of syncing it.
-// The sync opt-in UI will show only registered types; a checkbox should
-// never be shown for an unregistered type, and nor should it ever be
-// synced.
-//
-// A datatype is considered registered once RegisterDataTypeController
-// has been called with that datatype's DataTypeController.
-//
-// 'Preferred' (user preferences and opt-out for a datatype)
-//
-// This means the user's opt-in or opt-out preference on a per-datatype
-// basis. The sync service will try to make active exactly these types.
-// If a user has opted out of syncing a particular datatype, it will
-// be registered, but not preferred.
-//
-// This state is controlled by the ConfigurePreferredDataTypes and
-// GetPreferredDataTypes. They are stored in the preferences system,
-// and persist; though if a datatype is not registered, it cannot
-// be a preferred datatype.
-//
-// 'Active' (run-time initialization of sync system for a datatype)
-//
-// An active datatype is a preferred datatype that is actively being
-// synchronized: the syncer has been instructed to querying the server
-// for this datatype, first-time merges have finished, and there is an
-// actively installed ChangeProcessor that listens for changes to this
-// datatype, propagating such changes into and out of the sync backend
-// as necessary.
-//
-// When a datatype is in the process of becoming active, it may be
-// in some intermediate state. Those finer-grained intermediate states
-// are differentiated by the DataTypeController state.
-//
-// Sync Configuration:
-//
-// Sync configuration is accomplished via the following APIs:
-// * OnUserChoseDatatypes(): Set the data types the user wants to sync.
-// * SetDecryptionPassphrase(): Attempt to decrypt the user's encrypted data
-// using the passed passphrase.
-// * SetEncryptionPassphrase(): Re-encrypt the user's data using the passed
-// passphrase.
-//
-// Additionally, the current sync configuration can be fetched by calling
-// * GetRegisteredDataTypes()
-// * GetPreferredDataTypes()
-// * GetActiveDataTypes()
-// * IsUsingSecondaryPassphrase()
-// * IsEncryptEverythingEnabled()
-// * IsPassphraseRequired()/IsPassphraseRequiredForDecryption()
-//
-// The "sync everything" state cannot be read from ProfileSyncService, but
-// is instead pulled from SyncPrefs.HasKeepEverythingSynced().
-//
-// Initial sync setup:
-//
-// For privacy reasons, it is usually desirable to avoid syncing any data
-// types until the user has finished setting up sync. There are two APIs
-// that control the initial sync download:
-//
-// * SetFirstSetupComplete()
-// * GetSetupInProgressHandle()
-//
-// SetFirstSetupComplete() should be called once the user has finished setting
-// up sync at least once on their account. GetSetupInProgressHandle() should
-// be called while the user is actively configuring their account. The handle
-// should be deleted once configuration is complete.
-//
-// Once first setup has completed and there are no outstanding
-// setup-in-progress handles, CanConfigureDataTypes() will return true and
-// datatype configuration can begin.
-class ProfileSyncService : public sync_driver::SyncService,
- public sync_driver::SyncFrontend,
- public sync_driver::SyncPrefObserver,
- public sync_driver::DataTypeManagerObserver,
- public syncer::UnrecoverableErrorHandler,
- public KeyedService,
- public OAuth2TokenService::Consumer,
- public OAuth2TokenService::Observer,
- public SigninManagerBase::Observer,
- public GaiaCookieManagerService::Observer {
- public:
- typedef browser_sync::SyncBackendHost::Status Status;
- typedef base::Callback<bool(void)> PlatformSyncAllowedProvider;
-
- enum SyncEventCodes {
- MIN_SYNC_EVENT_CODE = 0,
-
- // Events starting the sync service.
- START_FROM_NTP = 1, // Sync was started from the ad in NTP
- START_FROM_WRENCH = 2, // Sync was started from the Wrench menu.
- START_FROM_OPTIONS = 3, // Sync was started from Wrench->Options.
- START_FROM_BOOKMARK_MANAGER = 4, // Sync was started from Bookmark manager.
- START_FROM_PROFILE_MENU = 5, // Sync was started from multiprofile menu.
- START_FROM_URL = 6, // Sync was started from a typed URL.
-
- // Events regarding cancellation of the signon process of sync.
- CANCEL_FROM_SIGNON_WITHOUT_AUTH = 10, // Cancelled before submitting
- // username and password.
- CANCEL_DURING_SIGNON = 11, // Cancelled after auth.
- CANCEL_DURING_CONFIGURE = 12, // Cancelled before choosing data
- // types and clicking OK.
- // Events resulting in the stoppage of sync service.
- STOP_FROM_OPTIONS = 20, // Sync was stopped from Wrench->Options.
- STOP_FROM_ADVANCED_DIALOG = 21, // Sync was stopped via advanced settings.
-
- // Miscellaneous events caused by sync service.
-
- MAX_SYNC_EVENT_CODE
- };
-
- enum SyncStatusSummary {
- UNRECOVERABLE_ERROR,
- NOT_ENABLED,
- SETUP_INCOMPLETE,
- DATATYPES_NOT_INITIALIZED,
- INITIALIZED,
- UNKNOWN_ERROR,
- };
-
- // If AUTO_START, sync will set IsFirstSetupComplete() automatically and sync
- // will begin syncing without the user needing to confirm sync settings.
- enum StartBehavior {
- AUTO_START,
- MANUAL_START,
- };
-
- // Bundles the arguments for ProfileSyncService construction. This is a
- // movable struct. Because of the non-POD data members, it needs out-of-line
- // constructors, so in particular the move constructor needs to be
- // explicitly defined.
- struct InitParams {
- InitParams();
- ~InitParams();
- InitParams(InitParams&& other); // NOLINT
-
- std::unique_ptr<sync_driver::SyncClient> sync_client;
- std::unique_ptr<SigninManagerWrapper> signin_wrapper;
- ProfileOAuth2TokenService* oauth2_token_service = nullptr;
- GaiaCookieManagerService* gaia_cookie_manager_service = nullptr;
- StartBehavior start_behavior = MANUAL_START;
- syncer::NetworkTimeUpdateCallback network_time_update_callback;
- base::FilePath base_directory;
- scoped_refptr<net::URLRequestContextGetter> url_request_context;
- std::string debug_identifier;
- version_info::Channel channel = version_info::Channel::UNKNOWN;
- scoped_refptr<base::SingleThreadTaskRunner> db_thread;
- scoped_refptr<base::SingleThreadTaskRunner> file_thread;
- base::SequencedWorkerPool* blocking_pool = nullptr;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InitParams);
- };
-
- explicit ProfileSyncService(InitParams init_params);
-
- ~ProfileSyncService() override;
-
- // Initializes the object. This must be called at most once, and
- // immediately after an object of this class is constructed.
- void Initialize();
-
- // sync_driver::SyncService implementation
- bool IsFirstSetupComplete() const override;
- bool IsSyncAllowed() const override;
- bool IsSyncActive() const override;
- void TriggerRefresh(const syncer::ModelTypeSet& types) override;
- void OnDataTypeRequestsSyncStartup(syncer::ModelType type) override;
- bool CanSyncStart() const override;
- void RequestStop(SyncStopDataFate data_fate) override;
- void RequestStart() override;
- syncer::ModelTypeSet GetActiveDataTypes() const override;
- sync_driver::SyncClient* GetSyncClient() const override;
- syncer::ModelTypeSet GetPreferredDataTypes() const override;
- void OnUserChoseDatatypes(bool sync_everything,
- syncer::ModelTypeSet chosen_types) override;
- void SetFirstSetupComplete() override;
- bool IsFirstSetupInProgress() const override;
- std::unique_ptr<sync_driver::SyncSetupInProgressHandle>
- GetSetupInProgressHandle() override;
- bool IsSetupInProgress() const override;
- bool ConfigurationDone() const override;
- const GoogleServiceAuthError& GetAuthError() const override;
- bool HasUnrecoverableError() const override;
- bool IsBackendInitialized() const override;
- sync_driver::OpenTabsUIDelegate* GetOpenTabsUIDelegate() override;
- bool IsPassphraseRequiredForDecryption() const override;
- base::Time GetExplicitPassphraseTime() const override;
- bool IsUsingSecondaryPassphrase() const override;
- void EnableEncryptEverything() override;
- bool IsEncryptEverythingEnabled() const override;
- void SetEncryptionPassphrase(const std::string& passphrase,
- PassphraseType type) override;
- bool SetDecryptionPassphrase(const std::string& passphrase) override
- WARN_UNUSED_RESULT;
- bool IsCryptographerReady(
- const syncer::BaseTransaction* trans) const override;
- syncer::UserShare* GetUserShare() const override;
- sync_driver::LocalDeviceInfoProvider* GetLocalDeviceInfoProvider()
- const override;
- void AddObserver(sync_driver::SyncServiceObserver* observer) override;
- void RemoveObserver(sync_driver::SyncServiceObserver* observer) override;
- bool HasObserver(
- const sync_driver::SyncServiceObserver* observer) const override;
- void RegisterDataTypeController(
- sync_driver::DataTypeController* data_type_controller) override;
- void ReenableDatatype(syncer::ModelType type) override;
- SyncTokenStatus GetSyncTokenStatus() const override;
- std::string QuerySyncStatusSummaryString() override;
- bool QueryDetailedSyncStatus(syncer::SyncStatus* result) override;
- base::string16 GetLastSyncedTimeString() const override;
- std::string GetBackendInitializationStateString() const override;
- syncer::sessions::SyncSessionSnapshot GetLastSessionSnapshot() const override;
- base::Value* GetTypeStatusMap() const override;
- const GURL& sync_service_url() const override;
- std::string unrecoverable_error_message() const override;
- tracked_objects::Location unrecoverable_error_location() const override;
- void AddProtocolEventObserver(
- browser_sync::ProtocolEventObserver* observer) override;
- void RemoveProtocolEventObserver(
- browser_sync::ProtocolEventObserver* observer) override;
- void AddTypeDebugInfoObserver(
- syncer::TypeDebugInfoObserver* observer) override;
- void RemoveTypeDebugInfoObserver(
- syncer::TypeDebugInfoObserver* observer) override;
- base::WeakPtr<syncer::JsController> GetJsController() override;
- void GetAllNodes(const base::Callback<void(std::unique_ptr<base::ListValue>)>&
- callback) override;
-
- // Add a sync type preference provider. Each provider may only be added once.
- void AddPreferenceProvider(SyncTypePreferenceProvider* provider);
- // Remove a sync type preference provider. May only be called for providers
- // that have been added. Providers must not remove themselves while being
- // called back.
- void RemovePreferenceProvider(SyncTypePreferenceProvider* provider);
- // Check whether a given sync type preference provider has been added.
- bool HasPreferenceProvider(SyncTypePreferenceProvider* provider) const;
-
- void RegisterAuthNotifications();
- void UnregisterAuthNotifications();
-
- // Returns the SyncableService for syncer::SESSIONS.
- virtual syncer::SyncableService* GetSessionsSyncableService();
-
- // Returns the SyncableService for syncer::DEVICE_INFO.
- virtual syncer::SyncableService* GetDeviceInfoSyncableService();
-
- // Returns the ModelTypeService for syncer::DEVICE_INFO.
- virtual syncer_v2::ModelTypeService* GetDeviceInfoService();
-
- // Returns synced devices tracker.
- virtual sync_driver::DeviceInfoTracker* GetDeviceInfoTracker() const;
-
- // Fills state_map with a map of current data types that are possible to
- // sync, as well as their states.
- void GetDataTypeControllerStates(
- sync_driver::DataTypeController::StateMap* state_map) const;
-
- // Called when asynchronous session restore has completed.
- void OnSessionRestoreComplete();
-
- // SyncFrontend implementation.
- void OnBackendInitialized(
- const syncer::WeakHandle<syncer::JsBackend>& js_backend,
- const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
- debug_info_listener,
- const std::string& cache_guid,
- bool success) override;
- void OnSyncCycleCompleted() override;
- void OnProtocolEvent(const syncer::ProtocolEvent& event) override;
- void OnDirectoryTypeCommitCounterUpdated(
- syncer::ModelType type,
- const syncer::CommitCounters& counters) override;
- void OnDirectoryTypeUpdateCounterUpdated(
- syncer::ModelType type,
- const syncer::UpdateCounters& counters) override;
- void OnDirectoryTypeStatusCounterUpdated(
- syncer::ModelType type,
- const syncer::StatusCounters& counters) override;
- void OnConnectionStatusChange(syncer::ConnectionStatus status) override;
- void OnPassphraseRequired(
- syncer::PassphraseRequiredReason reason,
- const sync_pb::EncryptedData& pending_keys) override;
- void OnPassphraseAccepted() override;
- void OnEncryptedTypesChanged(syncer::ModelTypeSet encrypted_types,
- bool encrypt_everything) override;
- void OnEncryptionComplete() override;
- void OnMigrationNeededForTypes(syncer::ModelTypeSet types) override;
- void OnExperimentsChanged(const syncer::Experiments& experiments) override;
- void OnActionableError(const syncer::SyncProtocolError& error) override;
- void OnLocalSetPassphraseEncryption(
- const syncer::SyncEncryptionHandler::NigoriState& nigori_state) override;
-
- // DataTypeManagerObserver implementation.
- void OnConfigureDone(
- const sync_driver::DataTypeManager::ConfigureResult& result) override;
- void OnConfigureStart() override;
-
- // DataTypeEncryptionHandler implementation.
- bool IsPassphraseRequired() const override;
- syncer::ModelTypeSet GetEncryptedDataTypes() const override;
-
- // SigninManagerBase::Observer implementation.
- void GoogleSigninSucceeded(const std::string& account_id,
- const std::string& username,
- const std::string& password) override;
- void GoogleSignedOut(const std::string& account_id,
- const std::string& username) override;
-
- // GaiaCookieManagerService::Observer implementation.
- void OnGaiaAccountsInCookieUpdated(
- const std::vector<gaia::ListedAccount>& accounts,
- const std::vector<gaia::ListedAccount>& signed_out_accounts,
- const GoogleServiceAuthError& error) override;
-
- // Get the sync status code.
- SyncStatusSummary QuerySyncStatusSummary();
-
- // Reconfigures the data type manager with the latest enabled types.
- // Note: Does not initialize the backend if it is not already initialized.
- // This function needs to be called only after sync has been initialized
- // (i.e.,only for reconfigurations). The reason we don't initialize the
- // backend is because if we had encountered an unrecoverable error we don't
- // want to startup once more.
- // This function is called by |SetSetupInProgress|.
- virtual void ReconfigureDatatypeManager();
-
- syncer::PassphraseRequiredReason passphrase_required_reason() const {
- return passphrase_required_reason_;
- }
-
- // Returns true if sync is requested to be running by the user.
- // Note that this does not mean that sync WILL be running; e.g. if
- // IsSyncAllowed() is false then sync won't start, and if the user
- // doesn't confirm their settings (IsFirstSetupComplete), sync will
- // never become active. Use IsSyncActive to see if sync is running.
- virtual bool IsSyncRequested() const;
-
- // Record stats on various events.
- static void SyncEvent(SyncEventCodes code);
-
- // Returns whether sync is allowed to run based on command-line switches.
- // Profile::IsSyncAllowed() is probably a better signal than this function.
- // This function can be called from any thread, and the implementation doesn't
- // assume it's running on the UI thread.
- static bool IsSyncAllowedByFlag();
-
- // Returns whether sync is currently allowed on this platform.
- bool IsSyncAllowedByPlatform() const;
-
- // Returns whether sync is managed, i.e. controlled by configuration
- // management. If so, the user is not allowed to configure sync.
- virtual bool IsManaged() const;
-
- // syncer::UnrecoverableErrorHandler implementation.
- void OnUnrecoverableError(const tracked_objects::Location& from_here,
- const std::string& message) override;
-
- // The functions below (until ActivateDataType()) should only be
- // called if IsBackendInitialized() is true.
-
- // TODO(akalin): These two functions are used only by
- // ProfileSyncServiceHarness. Figure out a different way to expose
- // this info to that class, and remove these functions.
-
- // Returns whether or not the underlying sync engine has made any
- // local changes to items that have not yet been synced with the
- // server.
- bool HasUnsyncedItems() const;
-
- // Used by ProfileSyncServiceHarness. May return NULL.
- browser_sync::BackendMigrator* GetBackendMigratorForTest();
-
- // Used by tests to inspect interaction with OAuth2TokenService.
- bool IsRetryingAccessTokenFetchForTest() const;
-
- // Used by tests to inspect the OAuth2 access tokens used by PSS.
- std::string GetAccessTokenForTest() const;
-
- // TODO(sync): This is only used in tests. Can we remove it?
- void GetModelSafeRoutingInfo(syncer::ModelSafeRoutingInfo* out) const;
-
- // SyncPrefObserver implementation.
- void OnSyncManagedPrefChange(bool is_sync_managed) override;
-
- // Changes which data types we're going to be syncing to |preferred_types|.
- // If it is running, the DataTypeManager will be instructed to reconfigure
- // the sync backend so that exactly these datatypes are actively synced. See
- // class comment for more on what it means for a datatype to be Preferred.
- virtual void ChangePreferredDataTypes(
- syncer::ModelTypeSet preferred_types);
-
- // Returns the set of types which are enforced programmatically and can not
- // be disabled by the user.
- virtual syncer::ModelTypeSet GetForcedDataTypes() const;
-
- // Gets the set of all data types that could be allowed (the set that
- // should be advertised to the user). These will typically only change
- // via a command-line option. See class comment for more on what it means
- // for a datatype to be Registered.
- virtual syncer::ModelTypeSet GetRegisteredDataTypes() const;
-
- // Returns the actual passphrase type being used for encryption.
- virtual syncer::PassphraseType GetPassphraseType() const;
-
- // Note about setting passphrases: There are different scenarios under which
- // we might want to apply a passphrase. It could be for first-time encryption,
- // re-encryption, or for decryption by clients that sign in at a later time.
- // In addition, encryption can either be done using a custom passphrase, or by
- // reusing the GAIA password. Depending on what is happening in the system,
- // callers should determine which of the two methods below must be used.
-
- // Returns true if encrypting all the sync data is allowed. If this method
- // returns false, EnableEncryptEverything() should not be called.
- virtual bool IsEncryptEverythingAllowed() const;
-
- // Sets whether encrypting all the sync data is allowed or not.
- virtual void SetEncryptEverythingAllowed(bool allowed);
-
- // Returns true if the syncer is waiting for new datatypes to be encrypted.
- virtual bool encryption_pending() const;
-
- SigninManagerBase* signin() const;
-
- SyncErrorController* sync_error_controller() {
- return sync_error_controller_.get();
- }
-
- // TODO(sync): This is only used in tests. Can we remove it?
- const sync_driver::DataTypeStatusTable& data_type_status_table() const;
-
- sync_driver::DataTypeManager::ConfigureStatus configure_status() {
- return configure_status_;
- }
-
- // If true, the ProfileSyncService has detected that a new GAIA signin has
- // succeeded, and is waiting for initialization to complete. This is used by
- // the UI to differentiate between a new auth error (encountered as part of
- // the initialization process) and a pre-existing auth error that just hasn't
- // been cleared yet. Virtual for testing purposes.
- virtual bool waiting_for_auth() const;
-
- // The set of currently enabled sync experiments.
- const syncer::Experiments& current_experiments() const;
-
- // OAuth2TokenService::Consumer implementation.
- void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
- const std::string& access_token,
- const base::Time& expiration_time) override;
- void OnGetTokenFailure(const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) override;
-
- // OAuth2TokenService::Observer implementation.
- void OnRefreshTokenAvailable(const std::string& account_id) override;
- void OnRefreshTokenRevoked(const std::string& account_id) override;
- void OnRefreshTokensLoaded() override;
-
- // KeyedService implementation. This must be called exactly
- // once (before this object is destroyed).
- void Shutdown() override;
-
- browser_sync::FaviconCache* GetFaviconCache();
-
- // Overrides the NetworkResources used for Sync connections.
- // This function takes ownership of |network_resources|.
- void OverrideNetworkResourcesForTest(
- std::unique_ptr<syncer::NetworkResources> network_resources);
-
- virtual bool IsDataTypeControllerRunning(syncer::ModelType type) const;
-
- // This triggers a Directory::SaveChanges() call on the sync thread.
- // It should be used to persist data to disk when the process might be
- // killed in the near future.
- void FlushDirectory() const;
-
- // Returns a serialized NigoriKey proto generated from the bootstrap token in
- // SyncPrefs. Will return the empty string if no bootstrap token exists.
- std::string GetCustomPassphraseKey() const;
-
- // Set the provider for whether sync is currently allowed by the platform.
- void SetPlatformSyncAllowedProvider(
- const PlatformSyncAllowedProvider& platform_sync_allowed_provider);
-
- // Needed to test whether the directory is deleted properly.
- base::FilePath GetDirectoryPathForTest() const;
-
- // Sometimes we need to wait for tasks on the sync thread in tests.
- base::MessageLoop* GetSyncLoopForTest() const;
-
- // Triggers sync cycle with request to update specified |types|.
- void RefreshTypesForTest(syncer::ModelTypeSet types);
-
- protected:
- // Helper to install and configure a data type manager.
- void ConfigureDataTypeManager();
-
- // Shuts down the backend sync components.
- // |reason| dictates if syncing is being disabled or not, and whether
- // to claim ownership of sync thread from backend.
- void ShutdownImpl(syncer::ShutdownReason reason);
-
- // Return SyncCredentials from the OAuth2TokenService.
- syncer::SyncCredentials GetCredentials();
-
- virtual syncer::WeakHandle<syncer::JsEventHandler> GetJsEventHandler();
-
- // Helper method for managing encryption UI.
- bool IsEncryptedDatatypeEnabled() const;
-
- // Helper for OnUnrecoverableError.
- // TODO(tim): Use an enum for |delete_sync_database| here, in ShutdownImpl,
- // and in SyncBackendHost::Shutdown.
- void OnUnrecoverableErrorImpl(
- const tracked_objects::Location& from_here,
- const std::string& message,
- bool delete_sync_database);
-
- // This is a cache of the last authentication response we received from the
- // sync server. The UI queries this to display appropriate messaging to the
- // user.
- GoogleServiceAuthError last_auth_error_;
-
- // Our asynchronous backend to communicate with sync components living on
- // other threads.
- std::unique_ptr<browser_sync::SyncBackendHost> backend_;
-
- // Was the last SYNC_PASSPHRASE_REQUIRED notification sent because it
- // was required for encryption, decryption with a cached passphrase, or
- // because a new passphrase is required?
- syncer::PassphraseRequiredReason passphrase_required_reason_;
-
- private:
- enum UnrecoverableErrorReason {
- ERROR_REASON_UNSET,
- ERROR_REASON_SYNCER,
- ERROR_REASON_BACKEND_INIT_FAILURE,
- ERROR_REASON_CONFIGURATION_RETRY,
- ERROR_REASON_CONFIGURATION_FAILURE,
- ERROR_REASON_ACTIONABLE_ERROR,
- ERROR_REASON_LIMIT
- };
-
- enum AuthErrorMetric {
- AUTH_ERROR_ENCOUNTERED,
- AUTH_ERROR_FIXED,
- AUTH_ERROR_LIMIT
- };
-
- // The initial state of sync, for the Sync.InitialState histogram. Even if
- // this value is CAN_START, sync startup might fail for reasons that we may
- // want to consider logging in the future, such as a passphrase needed for
- // decryption, or the version of Chrome being too old. This enum is used to
- // back a UMA histogram, and should therefore be treated as append-only.
- enum SyncInitialState {
- CAN_START, // Sync can attempt to start up.
- NOT_SIGNED_IN, // There is no signed in user.
- NOT_REQUESTED, // The user turned off sync.
- NOT_REQUESTED_NOT_SETUP, // The user turned off sync and setup completed
- // is false. Might indicate a stop-and-clear.
- NEEDS_CONFIRMATION, // The user must confirm sync settings.
- IS_MANAGED, // Sync is disallowed by enterprise policy.
- NOT_ALLOWED_BY_PLATFORM, // Sync is disallowed by the platform.
- SYNC_INITIAL_STATE_LIMIT
- };
-
- friend class ProfileSyncServicePasswordTest;
- friend class SyncTest;
- friend class TestProfileSyncService;
- FRIEND_TEST_ALL_PREFIXES(ProfileSyncServiceTest, InitialState);
-
- // Stops the sync engine. Does NOT set IsSyncRequested to false. Use
- // RequestStop for that. |data_fate| controls whether the local sync data is
- // deleted or kept when the engine shuts down.
- void StopImpl(SyncStopDataFate data_fate);
-
- // Update the last auth error and notify observers of error state.
- void UpdateAuthErrorState(const GoogleServiceAuthError& error);
-
- // Puts the backend's sync scheduler into NORMAL mode.
- // Called when configuration is complete.
- void StartSyncingWithServer();
-
- // Called when we've determined that we don't need a passphrase (either
- // because OnPassphraseAccepted() was called, or because we've gotten a
- // OnPassphraseRequired() but no data types are enabled).
- void ResolvePassphraseRequired();
-
- // During initial signin, ProfileSyncService caches the user's signin
- // passphrase so it can be used to encrypt/decrypt data after sync starts up.
- // This routine is invoked once the backend has started up to use the
- // cached passphrase and clear it out when it is done.
- void ConsumeCachedPassphraseIfPossible();
-
- // RequestAccessToken initiates RPC to request downscoped access token from
- // refresh token. This happens when a new OAuth2 login token is loaded and
- // when sync server returns AUTH_ERROR which indicates it is time to refresh
- // token.
- virtual void RequestAccessToken();
-
- // Return true if backend should start from a fresh sync DB.
- bool ShouldDeleteSyncFolder();
-
- // If |delete_sync_data_folder| is true, then this method will delete all
- // previous "Sync Data" folders. (useful if the folder is partial/corrupt).
- void InitializeBackend(bool delete_sync_data_folder);
-
- // Initializes the various settings from the command line.
- void InitSettings();
-
- // Sets the last synced time to the current time.
- void UpdateLastSyncedTime();
-
- void NotifyObservers();
- void NotifySyncCycleCompleted();
- void NotifyForeignSessionUpdated();
-
- void ClearStaleErrors();
-
- void ClearUnrecoverableError();
-
- // Starts up the backend sync components.
- virtual void StartUpSlowBackendComponents();
-
- // Collects preferred sync data types from |preference_providers_|.
- syncer::ModelTypeSet GetDataTypesFromPreferenceProviders() const;
-
- // Called when the user changes the sync configuration, to update the UMA
- // stats.
- void UpdateSelectedTypesHistogram(
- bool sync_everything,
- const syncer::ModelTypeSet chosen_types) const;
-
-#if defined(OS_CHROMEOS)
- // Refresh spare sync bootstrap token for re-enabling the sync service.
- // Called on successful sign-in notifications.
- void RefreshSpareBootstrapToken(const std::string& passphrase);
-#endif
-
- // Internal unrecoverable error handler. Used to track error reason via
- // Sync.UnrecoverableErrors histogram.
- void OnInternalUnrecoverableError(const tracked_objects::Location& from_here,
- const std::string& message,
- bool delete_sync_database,
- UnrecoverableErrorReason reason);
-
- // Update UMA for syncing backend.
- void UpdateBackendInitUMA(bool success);
-
- // Various setup following backend initialization, mostly for syncing backend.
- void PostBackendInitialization();
-
- // Whether sync has been authenticated with an account ID.
- bool IsSignedIn() const;
-
- // The backend can only start if sync can start and has an auth token. This is
- // different fron CanSyncStart because it represents whether the backend can
- // be started at this moment, whereas CanSyncStart represents whether sync can
- // conceptually start without further user action (acquiring a token is an
- // automatic process).
- bool CanBackendStart() const;
-
- // True if a syncing backend exists.
- bool HasSyncingBackend() const;
-
- // Update first sync time stored in preferences
- void UpdateFirstSyncTimePref();
-
- // Tell the sync server that this client has disabled sync.
- void RemoveClientFromServer() const;
-
- // Called when the system is under memory pressure.
- void OnMemoryPressure(
- base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
-
- // Check if previous shutdown is shutdown cleanly.
- void ReportPreviousSessionMemoryWarningCount();
-
- // After user switches to custom passphrase encryption a set of steps needs to
- // be performed:
- // - Download all latest updates from server (catch up configure).
- // - Clear user data on server.
- // - Clear directory so that data is merged from model types and encrypted.
- // Following three functions perform these steps.
-
- // Calls data type manager to start catch up configure.
- void BeginConfigureCatchUpBeforeClear();
-
- // Calls sync backend to send ClearServerDataMessage to server.
- void ClearAndRestartSyncForPassphraseEncryption();
-
- // Restarts sync clearing directory in the process.
- void OnClearServerDataDone();
-
- // True if setup has been completed at least once and is not in progress.
- bool CanConfigureDataTypes() const;
-
- // Called when a SetupInProgressHandle issued by this instance is destroyed.
- virtual void OnSetupInProgressHandleDestroyed();
-
- // This profile's SyncClient, which abstracts away non-Sync dependencies and
- // the Sync API component factory.
- std::unique_ptr<sync_driver::SyncClient> sync_client_;
-
- // The class that handles getting, setting, and persisting sync
- // preferences.
- sync_driver::SyncPrefs sync_prefs_;
-
- // TODO(ncarter): Put this in a profile, once there is UI for it.
- // This specifies where to find the sync server.
- const GURL sync_service_url_;
-
- // The time that OnConfigureStart is called. This member is zero if
- // OnConfigureStart has not yet been called, and is reset to zero once
- // OnConfigureDone is called.
- base::Time sync_configure_start_time_;
-
- // Callback to update the network time; used for initializing the backend.
- syncer::NetworkTimeUpdateCallback network_time_update_callback_;
-
- // The path to the base directory under which sync should store its
- // information.
- base::FilePath base_directory_;
-
- // The request context in which sync should operate.
- scoped_refptr<net::URLRequestContextGetter> url_request_context_;
-
- // An identifier representing this instance for debugging purposes.
- std::string debug_identifier_;
-
- // The product channel of the embedder.
- version_info::Channel channel_;
-
- // Threading context.
- scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
- scoped_refptr<base::SingleThreadTaskRunner> file_thread_;
- base::SequencedWorkerPool* blocking_pool_;
-
- // Indicates if this is the first time sync is being configured. This value
- // is equal to !IsFirstSetupComplete() at the time of OnBackendInitialized().
- bool is_first_time_sync_configure_;
-
- // Number of UIs currently configuring the Sync service. When this number
- // is decremented back to zero, Sync setup is marked no longer in progress.
- int outstanding_setup_in_progress_handles_ = 0;
-
- // List of available data type controllers.
- sync_driver::DataTypeController::TypeMap data_type_controllers_;
-
- // Whether the SyncBackendHost has been initialized.
- bool backend_initialized_;
-
- // Set when sync receives DISABLED_BY_ADMIN error from server. Prevents
- // ProfileSyncService from starting backend till browser restarted or user
- // signed out.
- bool sync_disabled_by_admin_;
-
- // Set to true if a signin has completed but we're still waiting for the
- // backend to refresh its credentials.
- bool is_auth_in_progress_;
-
- // Encapsulates user signin - used to set/get the user's authenticated
- // email address.
- const std::unique_ptr<SigninManagerWrapper> signin_;
-
- // Information describing an unrecoverable error.
- UnrecoverableErrorReason unrecoverable_error_reason_;
- std::string unrecoverable_error_message_;
- tracked_objects::Location unrecoverable_error_location_;
-
- // Manages the start and stop of the data types.
- std::unique_ptr<sync_driver::DataTypeManager> data_type_manager_;
-
- base::ObserverList<sync_driver::SyncServiceObserver> observers_;
- base::ObserverList<browser_sync::ProtocolEventObserver>
- protocol_event_observers_;
- base::ObserverList<syncer::TypeDebugInfoObserver> type_debug_info_observers_;
-
- std::set<SyncTypePreferenceProvider*> preference_providers_;
-
- syncer::SyncJsController sync_js_controller_;
-
- // This allows us to gracefully handle an ABORTED return code from the
- // DataTypeManager in the event that the server informed us to cease and
- // desist syncing immediately.
- bool expect_sync_configuration_aborted_;
-
- // Sometimes we need to temporarily hold on to a passphrase because we don't
- // yet have a backend to send it to. This happens during initialization as
- // we don't StartUp until we have a valid token, which happens after valid
- // credentials were provided.
- std::string cached_passphrase_;
-
- // The current set of encrypted types. Always a superset of
- // syncer::Cryptographer::SensitiveTypes().
- syncer::ModelTypeSet encrypted_types_;
-
- // Whether encrypting everything is allowed.
- bool encrypt_everything_allowed_;
-
- // Whether we want to encrypt everything.
- bool encrypt_everything_;
-
- // Whether we're waiting for an attempt to encryption all sync data to
- // complete. We track this at this layer in order to allow the user to cancel
- // if they e.g. don't remember their explicit passphrase.
- bool encryption_pending_;
-
- std::unique_ptr<browser_sync::BackendMigrator> migrator_;
-
- // This is the last |SyncProtocolError| we received from the server that had
- // an action set on it.
- syncer::SyncProtocolError last_actionable_error_;
-
- // Exposes sync errors to the UI.
- std::unique_ptr<SyncErrorController> sync_error_controller_;
-
- // Tracks the set of failed data types (those that encounter an error
- // or must delay loading for some reason).
- sync_driver::DataTypeStatusTable data_type_status_table_;
-
- sync_driver::DataTypeManager::ConfigureStatus configure_status_;
-
- // The set of currently enabled sync experiments.
- syncer::Experiments current_experiments_;
-
- // Sync's internal debug info listener. Used to record datatype configuration
- // and association information.
- syncer::WeakHandle<syncer::DataTypeDebugInfoListener> debug_info_listener_;
-
- // A thread where all the sync operations happen.
- // OWNERSHIP Notes:
- // * Created when backend starts for the first time.
- // * If sync is disabled, PSS claims ownership from backend.
- // * If sync is reenabled, PSS passes ownership to new backend.
- std::unique_ptr<base::Thread> sync_thread_;
-
- // ProfileSyncService uses this service to get access tokens.
- ProfileOAuth2TokenService* const oauth2_token_service_;
-
- // ProfileSyncService needs to remember access token in order to invalidate it
- // with OAuth2TokenService.
- std::string access_token_;
-
- // ProfileSyncService needs to hold reference to access_token_request_ for
- // the duration of request in order to receive callbacks.
- std::unique_ptr<OAuth2TokenService::Request> access_token_request_;
-
- // If RequestAccessToken fails with transient error then retry requesting
- // access token with exponential backoff.
- base::OneShotTimer request_access_token_retry_timer_;
- net::BackoffEntry request_access_token_backoff_;
-
- // States related to sync token and connection.
- base::Time connection_status_update_time_;
- syncer::ConnectionStatus connection_status_;
- base::Time token_request_time_;
- base::Time token_receive_time_;
- GoogleServiceAuthError last_get_token_error_;
- base::Time next_token_request_time_;
-
- // The gaia cookie manager. Used for monitoring cookie jar changes to detect
- // when the user signs out of the content area.
- GaiaCookieManagerService* const gaia_cookie_manager_service_;
-
- std::unique_ptr<sync_driver::LocalDeviceInfoProvider> local_device_;
-
- // Locally owned SyncableService and ModelTypeService implementations.
- std::unique_ptr<browser_sync::SessionsSyncManager> sessions_sync_manager_;
- std::unique_ptr<sync_driver::DeviceInfoSyncService> device_info_sync_service_;
- std::unique_ptr<sync_driver_v2::DeviceInfoService> device_info_service_;
-
- std::unique_ptr<syncer::NetworkResources> network_resources_;
-
- StartBehavior start_behavior_;
- std::unique_ptr<browser_sync::StartupController> startup_controller_;
-
- // The full path to the sync data directory.
- base::FilePath directory_path_;
-
- std::unique_ptr<browser_sync::SyncStoppedReporter> sync_stopped_reporter_;
-
- // Listens for the system being under memory pressure.
- std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
-
- // Nigori state after user switching to custom passphrase, saved until
- // transition steps complete. It will be injected into new backend after sync
- // restart.
- std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState>
- saved_nigori_state_;
-
- // When BeginConfigureCatchUpBeforeClear is called it will set
- // catch_up_configure_in_progress_ to true. This is needed to detect that call
- // to OnConfigureDone originated from BeginConfigureCatchUpBeforeClear and
- // needs to be followed by ClearAndRestartSyncForPassphraseEncryption().
- bool catch_up_configure_in_progress_;
-
- // Whether the major version has changed since the last time Chrome ran,
- // and therefore a passphrase required state should result in prompting
- // the user. This logic is only enabled on platforms that consume the
- // IsPassphrasePrompted sync preference.
- bool passphrase_prompt_triggered_by_version_;
-
- // An object that lets us check whether sync is currently allowed on this
- // platform.
- PlatformSyncAllowedProvider platform_sync_allowed_provider_;
-
- // Used to ensure that certain operations are performed on the thread that
- // this object was created on.
- base::ThreadChecker thread_checker_;
-
- // This weak factory invalidates its issued pointers when Sync is disabled.
- base::WeakPtrFactory<ProfileSyncService> sync_enabled_weak_factory_;
-
- base::WeakPtrFactory<ProfileSyncService> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ProfileSyncService);
-};
-
-bool ShouldShowActionOnUI(
- const syncer::SyncProtocolError& error);
-
-
-#endif // COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_SERVICE_H_
diff --git a/chromium/components/browser_sync/browser/profile_sync_service_autofill_unittest.cc b/chromium/components/browser_sync/browser/profile_sync_service_autofill_unittest.cc
deleted file mode 100644
index b883cc3a8da..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_service_autofill_unittest.cc
+++ /dev/null
@@ -1,1489 +0,0 @@
-// Copyright 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 <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/run_loop.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/autofill/core/browser/country_names.h"
-#include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
-#include "components/autofill/core/browser/webdata/autofill_change.h"
-#include "components/autofill/core/browser/webdata/autofill_data_type_controller.h"
-#include "components/autofill/core/browser/webdata/autofill_entry.h"
-#include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
-#include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
-#include "components/autofill/core/browser/webdata/autofill_table.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/core/common/autofill_pref_names.h"
-#include "components/browser_sync/browser/abstract_profile_sync_service_test.h"
-#include "components/browser_sync/browser/profile_sync_service.h"
-#include "components/browser_sync/browser/test_profile_sync_service.h"
-#include "components/sync_driver/data_type_controller.h"
-#include "components/sync_driver/data_type_manager_impl.h"
-#include "components/sync_driver/sync_api_component_factory_mock.h"
-#include "components/syncable_prefs/pref_service_syncable.h"
-#include "components/version_info/version_info.h"
-#include "components/webdata/common/web_database.h"
-#include "components/webdata_services/web_data_service_test_util.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/internal_api/public/data_type_debug_info_listener.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/write_node.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/protocol/autofill_specifics.pb.h"
-#include "sync/syncable/mutable_entry.h"
-#include "sync/syncable/syncable_write_transaction.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using autofill::AutocompleteSyncableService;
-using autofill::AutofillChange;
-using autofill::AutofillChangeList;
-using autofill::AutofillEntry;
-using autofill::AutofillKey;
-using autofill::AutofillProfile;
-using autofill::AutofillProfileChange;
-using autofill::AutofillProfileSyncableService;
-using autofill::AutofillTable;
-using autofill::AutofillWebDataService;
-using autofill::NAME_FULL;
-using autofill::PersonalDataManager;
-using autofill::ServerFieldType;
-using base::ASCIIToUTF16;
-using base::Time;
-using base::TimeDelta;
-using base::WaitableEvent;
-using browser_sync::AutofillDataTypeController;
-using browser_sync::AutofillProfileDataTypeController;
-using syncer::AUTOFILL;
-using syncer::AUTOFILL_PROFILE;
-using syncer::BaseNode;
-using syncer::syncable::CREATE;
-using syncer::syncable::GET_TYPE_ROOT;
-using syncer::syncable::MutableEntry;
-using syncer::syncable::UNITTEST;
-using syncer::syncable::WriterTag;
-using syncer::syncable::WriteTransaction;
-using testing::_;
-using testing::DoAll;
-using testing::ElementsAre;
-using testing::Not;
-using testing::SetArgumentPointee;
-using testing::Return;
-
-namespace {
-
-void RegisterAutofillPrefs(user_prefs::PrefRegistrySyncable* registry) {
- registry->RegisterBooleanPref(autofill::prefs::kAutofillEnabled, true);
- registry->RegisterBooleanPref(autofill::prefs::kAutofillWalletImportEnabled,
- true);
- registry->RegisterBooleanPref(autofill::prefs::kAutofillProfileUseDatesFixed,
- true);
- registry->RegisterIntegerPref(autofill::prefs::kAutofillLastVersionDeduped,
- atoi(version_info::GetVersionNumber().c_str()));
-}
-
-void RunAndSignal(const base::Closure& cb, WaitableEvent* event) {
- cb.Run();
- event->Signal();
-}
-
-AutofillEntry MakeAutofillEntry(const char* name,
- const char* value,
- int time_shift0,
- int time_shift1) {
- // Time deep in the past would cause Autocomplete sync to discard the
- // entries.
- static Time base_time = Time::Now().LocalMidnight();
-
- Time date_created = base_time + TimeDelta::FromSeconds(time_shift0);
- Time date_last_used = date_created;
- if (time_shift1 >= 0)
- date_last_used = base_time + TimeDelta::FromSeconds(time_shift1);
- return AutofillEntry(AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)),
- date_created, date_last_used);
-}
-
-AutofillEntry MakeAutofillEntry(const char* name,
- const char* value,
- int time_shift) {
- return MakeAutofillEntry(name, value, time_shift, -1);
-}
-
-} // namespace
-
-class AutofillTableMock : public AutofillTable {
- public:
- AutofillTableMock() {}
- MOCK_METHOD2(RemoveFormElement,
- bool(const base::string16& name,
- const base::string16& value)); // NOLINT
- MOCK_METHOD1(GetAllAutofillEntries,
- bool(std::vector<AutofillEntry>* entries)); // NOLINT
- MOCK_METHOD4(GetAutofillTimestamps,
- bool(const base::string16& name, // NOLINT
- const base::string16& value,
- Time* date_created,
- Time* date_last_used));
- MOCK_METHOD1(UpdateAutofillEntries,
- bool(const std::vector<AutofillEntry>&)); // NOLINT
- MOCK_METHOD1(GetAutofillProfiles,
- bool(std::vector<AutofillProfile*>*)); // NOLINT
- MOCK_METHOD1(UpdateAutofillProfile,
- bool(const AutofillProfile&)); // NOLINT
- MOCK_METHOD1(AddAutofillProfile,
- bool(const AutofillProfile&)); // NOLINT
- MOCK_METHOD1(RemoveAutofillProfile,
- bool(const std::string&)); // NOLINT
-};
-
-MATCHER_P(MatchProfiles, profile, "") {
- return (profile.Compare(arg) == 0);
-}
-
-class WebDatabaseFake : public WebDatabase {
- public:
- explicit WebDatabaseFake(AutofillTable* autofill_table) {
- AddTable(autofill_table);
- }
-};
-
-class MockAutofillBackend : public autofill::AutofillWebDataBackend {
- public:
- MockAutofillBackend(
- WebDatabase* web_database,
- const base::Closure& on_changed,
- const base::Callback<void(syncer::ModelType)>& on_sync_started,
- const scoped_refptr<base::SequencedTaskRunner>& ui_thread)
- : web_database_(web_database),
- on_changed_(on_changed),
- on_sync_started_(on_sync_started),
- ui_thread_(ui_thread) {}
-
- ~MockAutofillBackend() override {}
- WebDatabase* GetDatabase() override { return web_database_; }
- void AddObserver(
- autofill::AutofillWebDataServiceObserverOnDBThread* observer) override {}
- void RemoveObserver(
- autofill::AutofillWebDataServiceObserverOnDBThread* observer) override {}
- void RemoveExpiredFormElements() override {}
- void NotifyOfMultipleAutofillChanges() override {
- DCHECK(!ui_thread_->RunsTasksOnCurrentThread());
- ui_thread_->PostTask(FROM_HERE, on_changed_);
- }
- void NotifyThatSyncHasStarted(syncer::ModelType model_type) override {
- DCHECK(!ui_thread_->RunsTasksOnCurrentThread());
- ui_thread_->PostTask(FROM_HERE, base::Bind(on_sync_started_, model_type));
- }
-
- private:
- WebDatabase* web_database_;
- base::Closure on_changed_;
- base::Callback<void(syncer::ModelType)> on_sync_started_;
- const scoped_refptr<base::SequencedTaskRunner> ui_thread_;
-};
-
-class ProfileSyncServiceAutofillTest;
-
-template<class AutofillProfile>
-syncer::ModelType GetModelType() {
- return syncer::UNSPECIFIED;
-}
-
-template<>
-syncer::ModelType GetModelType<AutofillEntry>() {
- return AUTOFILL;
-}
-
-template<>
-syncer::ModelType GetModelType<AutofillProfile>() {
- return AUTOFILL_PROFILE;
-}
-
-class TokenWebDataServiceFake : public TokenWebData {
- public:
- TokenWebDataServiceFake(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread)
- : TokenWebData(ui_thread, db_thread) {}
-
- bool IsDatabaseLoaded() override { return true; }
-
- AutofillWebDataService::Handle GetAllTokens(
- WebDataServiceConsumer* consumer) override {
- // TODO(tim): It would be nice if WebDataService was injected on
- // construction of ProfileOAuth2TokenService rather than fetched by
- // Initialize so that this isn't necessary (we could pass a NULL service).
- // We currently do return it via EXPECT_CALLs, but without depending on
- // order-of-initialization (which seems way more fragile) we can't tell
- // which component is asking at what time, and some components in these
- // Autofill tests require a WebDataService.
- return 0;
- }
-
- private:
- ~TokenWebDataServiceFake() override {}
-
- DISALLOW_COPY_AND_ASSIGN(TokenWebDataServiceFake);
-};
-
-class WebDataServiceFake : public AutofillWebDataService {
- public:
- WebDataServiceFake(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread)
- : AutofillWebDataService(ui_thread, db_thread),
- web_database_(NULL),
- autocomplete_syncable_service_(NULL),
- autofill_profile_syncable_service_(NULL),
- syncable_service_created_or_destroyed_(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED),
- db_thread_(db_thread),
- ui_thread_(ui_thread) {}
-
- void SetDatabase(WebDatabase* web_database) {
- web_database_ = web_database;
- }
-
- void StartSyncableService() {
- // The |autofill_profile_syncable_service_| must be constructed on the DB
- // thread.
- const base::Closure& on_changed_callback = base::Bind(
- &WebDataServiceFake::NotifyAutofillMultipleChangedOnUIThread,
- AsWeakPtr());
- const base::Callback<void(syncer::ModelType)> on_sync_started_callback =
- base::Bind(&WebDataServiceFake::NotifySyncStartedOnUIThread,
- AsWeakPtr());
-
- db_thread_->PostTask(FROM_HERE,
- base::Bind(&WebDataServiceFake::CreateSyncableService,
- base::Unretained(this), on_changed_callback,
- on_sync_started_callback));
- syncable_service_created_or_destroyed_.Wait();
- }
-
- void ShutdownSyncableService() {
- // The |autofill_profile_syncable_service_| must be destructed on the DB
- // thread.
- db_thread_->PostTask(FROM_HERE,
- base::Bind(&WebDataServiceFake::DestroySyncableService,
- base::Unretained(this)));
- syncable_service_created_or_destroyed_.Wait();
- }
-
- bool IsDatabaseLoaded() override { return true; }
-
- WebDatabase* GetDatabase() override { return web_database_; }
-
- void OnAutofillEntriesChanged(const AutofillChangeList& changes) {
- WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- base::Closure notify_cb =
- base::Bind(&AutocompleteSyncableService::AutofillEntriesChanged,
- base::Unretained(autocomplete_syncable_service_),
- changes);
- db_thread_->PostTask(FROM_HERE,
- base::Bind(&RunAndSignal, notify_cb, &event));
- event.Wait();
- }
-
- void OnAutofillProfileChanged(const AutofillProfileChange& changes) {
- WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- base::Closure notify_cb =
- base::Bind(&AutocompleteSyncableService::AutofillProfileChanged,
- base::Unretained(autofill_profile_syncable_service_),
- changes);
- db_thread_->PostTask(FROM_HERE,
- base::Bind(&RunAndSignal, notify_cb, &event));
- event.Wait();
- }
-
- private:
- ~WebDataServiceFake() override {}
-
- void CreateSyncableService(
- const base::Closure& on_changed_callback,
- const base::Callback<void(syncer::ModelType)>& on_sync_started) {
- ASSERT_TRUE(db_thread_->RunsTasksOnCurrentThread());
- // These services are deleted in DestroySyncableService().
- backend_.reset(new MockAutofillBackend(GetDatabase(), on_changed_callback,
- on_sync_started, ui_thread_.get()));
- AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
- this, backend_.get());
- AutofillProfileSyncableService::CreateForWebDataServiceAndBackend(
- this, backend_.get(), "en-US");
-
- autocomplete_syncable_service_ =
- AutocompleteSyncableService::FromWebDataService(this);
- autofill_profile_syncable_service_ =
- AutofillProfileSyncableService::FromWebDataService(this);
-
- syncable_service_created_or_destroyed_.Signal();
- }
-
- void DestroySyncableService() {
- ASSERT_TRUE(db_thread_->RunsTasksOnCurrentThread());
- autocomplete_syncable_service_ = NULL;
- autofill_profile_syncable_service_ = NULL;
- backend_.reset();
- syncable_service_created_or_destroyed_.Signal();
- }
-
- WebDatabase* web_database_;
- AutocompleteSyncableService* autocomplete_syncable_service_;
- AutofillProfileSyncableService* autofill_profile_syncable_service_;
- std::unique_ptr<autofill::AutofillWebDataBackend> backend_;
-
- WaitableEvent syncable_service_created_or_destroyed_;
-
- const scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
- const scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
-
- DISALLOW_COPY_AND_ASSIGN(WebDataServiceFake);
-};
-
-ACTION_P(ReturnNewDataTypeManagerWithDebugListener, debug_listener) {
- return new sync_driver::DataTypeManagerImpl(
- debug_listener,
- arg1,
- arg2,
- arg3,
- arg4);
-}
-
-class MockPersonalDataManager : public PersonalDataManager {
- public:
- MockPersonalDataManager() : PersonalDataManager("en-US") {}
- MOCK_CONST_METHOD0(IsDataLoaded, bool());
- MOCK_METHOD0(LoadProfiles, void());
- MOCK_METHOD0(LoadCreditCards, void());
- MOCK_METHOD0(Refresh, void());
-};
-
-template <class T> class AddAutofillHelper;
-
-class ProfileSyncServiceAutofillTest
- : public AbstractProfileSyncServiceTest,
- public syncer::DataTypeDebugInfoListener {
- public:
- // DataTypeDebugInfoListener implementation.
- void OnDataTypeConfigureComplete(const std::vector<
- syncer::DataTypeConfigurationStats>& configuration_stats) override {
- ASSERT_EQ(1u, configuration_stats.size());
- association_stats_ = configuration_stats[0].association_stats;
- }
-
- protected:
- ProfileSyncServiceAutofillTest() : debug_ptr_factory_(this) {
- autofill::CountryNames::SetLocaleString("en-US");
- RegisterAutofillPrefs(
- profile_sync_service_bundle()->pref_service()->registry());
-
- data_type_thread()->Start();
- profile_sync_service_bundle()->set_db_thread(
- data_type_thread()->task_runner());
-
- web_database_.reset(new WebDatabaseFake(&autofill_table_));
- web_data_wrapper_ = base::WrapUnique(new MockWebDataServiceWrapper(
- new WebDataServiceFake(base::ThreadTaskRunnerHandle::Get(),
- data_type_thread()->task_runner()),
- new TokenWebDataServiceFake(base::ThreadTaskRunnerHandle::Get(),
- data_type_thread()->task_runner())));
- web_data_service_ = static_cast<WebDataServiceFake*>(
- web_data_wrapper_->GetAutofillWebData().get());
- web_data_service_->SetDatabase(web_database_.get());
-
- personal_data_manager_ = base::WrapUnique(new MockPersonalDataManager());
-
- EXPECT_CALL(personal_data_manager(), LoadProfiles());
- EXPECT_CALL(personal_data_manager(), LoadCreditCards());
-
- personal_data_manager_->Init(
- web_data_service_, profile_sync_service_bundle()->pref_service(),
- profile_sync_service_bundle()->account_tracker(),
- profile_sync_service_bundle()->signin_manager(), false);
-
- web_data_service_->StartSyncableService();
-
- browser_sync::ProfileSyncServiceBundle::SyncClientBuilder builder(
- profile_sync_service_bundle());
- builder.SetPersonalDataManager(personal_data_manager_.get());
- builder.SetSyncServiceCallback(GetSyncServiceCallback());
- builder.SetSyncableServiceCallback(
- base::Bind(&ProfileSyncServiceAutofillTest::GetSyncableServiceForType,
- base::Unretained(this)));
- builder.set_activate_model_creation();
- sync_client_owned_ = builder.Build();
- sync_client_ = sync_client_owned_.get();
-
- // When UpdateAutofillEntries() is called with an empty list, the return
- // value should be |true|, rather than the default of |false|.
- std::vector<AutofillEntry> empty;
- EXPECT_CALL(autofill_table_, UpdateAutofillEntries(empty))
- .WillRepeatedly(Return(true));
- }
-
- ~ProfileSyncServiceAutofillTest() override {
- web_data_service_->ShutdownOnUIThread();
- web_data_service_->ShutdownSyncableService();
- web_data_wrapper_->Shutdown();
- web_data_service_ = nullptr;
- web_data_wrapper_.reset();
- web_database_.reset();
- // Shut down the service explicitly before some data members from this
- // test it needs will be deleted.
- sync_service()->Shutdown();
- }
-
- int GetSyncCount(syncer::ModelType type) {
- syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
- syncer::ReadNode node(&trans);
- if (node.InitTypeRoot(type) != BaseNode::INIT_OK)
- return 0;
- return node.GetTotalNodeCount() - 1;
- }
-
- void StartSyncService(const base::Closure& callback,
- bool will_fail_association,
- syncer::ModelType type) {
- SigninManagerBase* signin = profile_sync_service_bundle()->signin_manager();
- signin->SetAuthenticatedAccountInfo("12345", "test_user@gmail.com");
- CreateSyncService(std::move(sync_client_owned_), callback);
-
- EXPECT_CALL(*profile_sync_service_bundle()->component_factory(),
- CreateDataTypeManager(_, _, _, _, _))
- .WillOnce(ReturnNewDataTypeManagerWithDebugListener(
- syncer::MakeWeakHandle(debug_ptr_factory_.GetWeakPtr())));
-
- EXPECT_CALL(personal_data_manager(), IsDataLoaded())
- .WillRepeatedly(Return(true));
-
- // We need tokens to get the tests going
- profile_sync_service_bundle()->auth_service()->UpdateCredentials(
- signin->GetAuthenticatedAccountId(), "oauth2_login_token");
-
- sync_service()->RegisterDataTypeController(CreateDataTypeController(type));
- sync_service()->Initialize();
- base::RunLoop().Run();
-
- // It's possible this test triggered an unrecoverable error, in which case
- // we can't get the sync count.
- if (sync_service()->IsSyncActive()) {
- EXPECT_EQ(GetSyncCount(type),
- association_stats_.num_sync_items_after_association);
- }
- EXPECT_EQ(association_stats_.num_sync_items_after_association,
- association_stats_.num_sync_items_before_association +
- association_stats_.num_sync_items_added -
- association_stats_.num_sync_items_deleted);
- }
-
- bool AddAutofillSyncNode(const AutofillEntry& entry) {
- syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare());
- syncer::WriteNode node(&trans);
- std::string tag = AutocompleteSyncableService::KeyToTag(
- base::UTF16ToUTF8(entry.key().name()),
- base::UTF16ToUTF8(entry.key().value()));
- syncer::WriteNode::InitUniqueByCreationResult result =
- node.InitUniqueByCreation(AUTOFILL, tag);
- if (result != syncer::WriteNode::INIT_SUCCESS)
- return false;
-
- sync_pb::EntitySpecifics specifics;
- AutocompleteSyncableService::WriteAutofillEntry(entry, &specifics);
- node.SetEntitySpecifics(specifics);
- return true;
- }
-
- bool AddAutofillSyncNode(const AutofillProfile& profile) {
- syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare());
- syncer::WriteNode node(&trans);
- std::string tag = profile.guid();
- syncer::WriteNode::InitUniqueByCreationResult result =
- node.InitUniqueByCreation(AUTOFILL_PROFILE, tag);
- if (result != syncer::WriteNode::INIT_SUCCESS)
- return false;
-
- sync_pb::EntitySpecifics specifics;
- AutofillProfileSyncableService::WriteAutofillProfile(profile, &specifics);
- node.SetEntitySpecifics(specifics);
- return true;
- }
-
- bool GetAutofillEntriesFromSyncDB(std::vector<AutofillEntry>* entries,
- std::vector<AutofillProfile>* profiles) {
- syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
- syncer::ReadNode autofill_root(&trans);
- if (autofill_root.InitTypeRoot(AUTOFILL) != BaseNode::INIT_OK) {
- return false;
- }
-
- int64_t child_id = autofill_root.GetFirstChildId();
- while (child_id != syncer::kInvalidId) {
- syncer::ReadNode child_node(&trans);
- if (child_node.InitByIdLookup(child_id) != BaseNode::INIT_OK)
- return false;
-
- const sync_pb::AutofillSpecifics& autofill(
- child_node.GetEntitySpecifics().autofill());
- if (autofill.has_value()) {
- AutofillKey key(base::UTF8ToUTF16(autofill.name()),
- base::UTF8ToUTF16(autofill.value()));
- std::vector<Time> timestamps;
- int timestamps_count = autofill.usage_timestamp_size();
- for (int i = 0; i < timestamps_count; ++i) {
- timestamps.push_back(Time::FromInternalValue(
- autofill.usage_timestamp(i)));
- }
- entries->push_back(
- AutofillEntry(key, timestamps.front(), timestamps.back()));
- } else if (autofill.has_profile()) {
- AutofillProfile p;
- p.set_guid(autofill.profile().guid());
- AutofillProfileSyncableService::OverwriteProfileWithServerData(
- autofill.profile(), &p);
- profiles->push_back(p);
- }
- child_id = child_node.GetSuccessorId();
- }
- return true;
- }
-
- bool GetAutofillProfilesFromSyncDBUnderProfileNode(
- std::vector<AutofillProfile>* profiles) {
- syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
- syncer::ReadNode autofill_root(&trans);
- if (autofill_root.InitTypeRoot(AUTOFILL_PROFILE) != BaseNode::INIT_OK) {
- return false;
- }
-
- int64_t child_id = autofill_root.GetFirstChildId();
- while (child_id != syncer::kInvalidId) {
- syncer::ReadNode child_node(&trans);
- if (child_node.InitByIdLookup(child_id) != BaseNode::INIT_OK)
- return false;
-
- const sync_pb::AutofillProfileSpecifics& autofill(
- child_node.GetEntitySpecifics().autofill_profile());
- AutofillProfile p;
- p.set_guid(autofill.guid());
- AutofillProfileSyncableService::OverwriteProfileWithServerData(autofill,
- &p);
- profiles->push_back(p);
- child_id = child_node.GetSuccessorId();
- }
- return true;
- }
-
- void SetIdleChangeProcessorExpectations() {
- EXPECT_CALL(autofill_table_, RemoveFormElement(_, _)).Times(0);
- EXPECT_CALL(autofill_table_, GetAutofillTimestamps(_, _, _, _)).Times(0);
-
- // Only permit UpdateAutofillEntries() to be called with an empty list.
- std::vector<AutofillEntry> empty;
- EXPECT_CALL(autofill_table_, UpdateAutofillEntries(Not(empty))).Times(0);
- }
-
- sync_driver::DataTypeController* CreateDataTypeController(
- syncer::ModelType type) {
- DCHECK(type == AUTOFILL || type == AUTOFILL_PROFILE);
- if (type == AUTOFILL) {
- return new AutofillDataTypeController(base::ThreadTaskRunnerHandle::Get(),
- data_type_thread()->task_runner(),
- base::Bind(&base::DoNothing),
- sync_client_, web_data_service_);
- } else {
- return new AutofillProfileDataTypeController(
- base::ThreadTaskRunnerHandle::Get(),
- data_type_thread()->task_runner(), base::Bind(&base::DoNothing),
- sync_client_, web_data_service_);
- }
- }
-
- AutofillTableMock& autofill_table() { return autofill_table_; }
-
- MockPersonalDataManager& personal_data_manager() {
- return *personal_data_manager_;
- }
-
- WebDataServiceFake* web_data_service() { return web_data_service_.get(); }
-
- private:
- friend class AddAutofillHelper<AutofillEntry>;
- friend class AddAutofillHelper<AutofillProfile>;
-
- base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
- syncer::ModelType type) {
- DCHECK(type == AUTOFILL || type == AUTOFILL_PROFILE);
- if (type == AUTOFILL) {
- return AutocompleteSyncableService::FromWebDataService(
- web_data_service_.get())
- ->AsWeakPtr();
- } else {
- return AutofillProfileSyncableService::FromWebDataService(
- web_data_service_.get())
- ->AsWeakPtr();
- }
- }
-
- AutofillTableMock autofill_table_;
- std::unique_ptr<WebDatabaseFake> web_database_;
- std::unique_ptr<MockWebDataServiceWrapper> web_data_wrapper_;
- scoped_refptr<WebDataServiceFake> web_data_service_;
- std::unique_ptr<MockPersonalDataManager> personal_data_manager_;
- syncer::DataTypeAssociationStats association_stats_;
- base::WeakPtrFactory<DataTypeDebugInfoListener> debug_ptr_factory_;
- // |sync_client_owned_| keeps the created client until it is passed to the
- // created ProfileSyncService. |sync_client_| just keeps a weak reference to
- // the client the whole time.
- std::unique_ptr<sync_driver::FakeSyncClient> sync_client_owned_;
- sync_driver::FakeSyncClient* sync_client_;
-
- DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceAutofillTest);
-};
-
-template <class T>
-class AddAutofillHelper {
- public:
- AddAutofillHelper(ProfileSyncServiceAutofillTest* test,
- const std::vector<T>& entries)
- : callback_(base::Bind(&AddAutofillHelper::AddAutofillCallback,
- base::Unretained(this), test, entries)),
- success_(false) {
- }
-
- const base::Closure& callback() const { return callback_; }
- bool success() { return success_; }
-
- private:
- void AddAutofillCallback(ProfileSyncServiceAutofillTest* test,
- const std::vector<T>& entries) {
- if (!test->CreateRoot(GetModelType<T>()))
- return;
-
- for (size_t i = 0; i < entries.size(); ++i) {
- if (!test->AddAutofillSyncNode(entries[i]))
- return;
- }
- success_ = true;
- }
-
- base::Closure callback_;
- bool success_;
-};
-
-// Overload write transaction to use custom NotifyTransactionComplete
-class WriteTransactionTest: public WriteTransaction {
- public:
- WriteTransactionTest(const tracked_objects::Location& from_here,
- WriterTag writer,
- syncer::syncable::Directory* directory,
- WaitableEvent* wait_for_syncapi)
- : WriteTransaction(from_here, writer, directory),
- wait_for_syncapi_(wait_for_syncapi) {}
-
- void NotifyTransactionComplete(syncer::ModelTypeSet types) override {
- // This is where we differ. Force a thread change here, giving another
- // thread a chance to create a WriteTransaction
- wait_for_syncapi_->Wait();
-
- WriteTransaction::NotifyTransactionComplete(types);
- }
-
- private:
- WaitableEvent* const wait_for_syncapi_;
-};
-
-// Our fake server updater. Needs the RefCountedThreadSafe inheritance so we can
-// post tasks with it.
-class FakeServerUpdater : public base::RefCountedThreadSafe<FakeServerUpdater> {
- public:
- FakeServerUpdater(TestProfileSyncService* service,
- WaitableEvent* wait_for_start,
- WaitableEvent* wait_for_syncapi,
- scoped_refptr<base::SequencedTaskRunner> db_thread)
- : entry_(MakeAutofillEntry("0", "0", 0)),
- service_(service),
- wait_for_start_(wait_for_start),
- wait_for_syncapi_(wait_for_syncapi),
- is_finished_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED),
- db_thread_(db_thread) {}
-
- void Update() {
- // This gets called in a modelsafeworker thread.
- ASSERT_TRUE(db_thread_->RunsTasksOnCurrentThread());
-
- syncer::UserShare* user_share = service_->GetUserShare();
- syncer::syncable::Directory* directory = user_share->directory.get();
-
- // Create autofill protobuf.
- std::string tag = AutocompleteSyncableService::KeyToTag(
- base::UTF16ToUTF8(entry_.key().name()),
- base::UTF16ToUTF8(entry_.key().value()));
- sync_pb::AutofillSpecifics new_autofill;
- new_autofill.set_name(base::UTF16ToUTF8(entry_.key().name()));
- new_autofill.set_value(base::UTF16ToUTF8(entry_.key().value()));
- new_autofill.add_usage_timestamp(entry_.date_created().ToInternalValue());
- if (entry_.date_created() != entry_.date_last_used()) {
- new_autofill.add_usage_timestamp(
- entry_.date_last_used().ToInternalValue());
- }
-
- sync_pb::EntitySpecifics entity_specifics;
- entity_specifics.mutable_autofill()->CopyFrom(new_autofill);
-
- {
- // Tell main thread we've started
- wait_for_start_->Signal();
-
- // Create write transaction.
- WriteTransactionTest trans(FROM_HERE, UNITTEST, directory,
- wait_for_syncapi_);
-
- // Create actual entry based on autofill protobuf information.
- // Simulates effects of UpdateLocalDataFromServerData
- MutableEntry parent(&trans, GET_TYPE_ROOT, AUTOFILL);
- MutableEntry item(&trans, CREATE, AUTOFILL, parent.GetId(), tag);
- ASSERT_TRUE(item.good());
- item.PutSpecifics(entity_specifics);
- item.PutServerSpecifics(entity_specifics);
- item.PutBaseVersion(1);
- syncer::syncable::Id server_item_id =
- service_->id_factory()->NewServerId();
- item.PutId(server_item_id);
- syncer::syncable::Id new_predecessor;
- ASSERT_TRUE(item.PutPredecessor(new_predecessor));
- }
- DVLOG(1) << "FakeServerUpdater finishing.";
- is_finished_.Signal();
- }
-
- void CreateNewEntry(const AutofillEntry& entry) {
- entry_ = entry;
- ASSERT_FALSE(db_thread_->RunsTasksOnCurrentThread());
- if (!db_thread_->PostTask(FROM_HERE,
- base::Bind(&FakeServerUpdater::Update, this))) {
- NOTREACHED() << "Failed to post task to the db thread.";
- return;
- }
- }
-
- void WaitForUpdateCompletion() {
- is_finished_.Wait();
- }
-
- private:
- friend class base::RefCountedThreadSafe<FakeServerUpdater>;
- ~FakeServerUpdater() { }
-
- AutofillEntry entry_;
- TestProfileSyncService* service_;
- WaitableEvent* const wait_for_start_;
- WaitableEvent* const wait_for_syncapi_;
- WaitableEvent is_finished_;
- syncer::syncable::Id parent_id_;
- scoped_refptr<base::SequencedTaskRunner> db_thread_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeServerUpdater);
-};
-
-// TODO(skrul): Test abort startup.
-// TODO(skrul): Test processing of cloud changes.
-// TODO(tim): Add autofill data type controller test, and a case to cover
-// waiting for the PersonalDataManager.
-TEST_F(ProfileSyncServiceAutofillTest, FailModelAssociation) {
- // Don't create the root autofill node so startup fails.
- StartSyncService(base::Closure(), true, AUTOFILL);
- EXPECT_TRUE(sync_service()->HasUnrecoverableError());
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, EmptyNativeEmptySync) {
- EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
- .WillOnce(Return(true));
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, AUTOFILL);
- EXPECT_CALL(personal_data_manager(), Refresh());
- StartSyncService(create_root.callback(), false, AUTOFILL);
- EXPECT_TRUE(create_root.success());
- std::vector<AutofillEntry> sync_entries;
- std::vector<AutofillProfile> sync_profiles;
- ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
- EXPECT_EQ(0U, sync_entries.size());
- EXPECT_EQ(0U, sync_profiles.size());
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeEntriesEmptySync) {
- std::vector<AutofillEntry> entries;
- entries.push_back(MakeAutofillEntry("foo", "bar", 1));
- EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, AUTOFILL);
- EXPECT_CALL(personal_data_manager(), Refresh());
- StartSyncService(create_root.callback(), false, AUTOFILL);
- ASSERT_TRUE(create_root.success());
- std::vector<AutofillEntry> sync_entries;
- std::vector<AutofillProfile> sync_profiles;
- ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
- ASSERT_EQ(1U, entries.size());
- EXPECT_TRUE(entries[0] == sync_entries[0]);
- EXPECT_EQ(0U, sync_profiles.size());
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, HasProfileEmptySync) {
- std::vector<AutofillProfile*> profiles;
- std::vector<AutofillProfile> expected_profiles;
- // Owned by GetAutofillProfiles caller.
- AutofillProfile* profile0 = new AutofillProfile;
- autofill::test::SetProfileInfoWithGuid(profile0,
- "54B3F9AA-335E-4F71-A27D-719C41564230", "Billing",
- "Mitchell", "Morrison",
- "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
- "91601", "US", "12345678910");
- profiles.push_back(profile0);
- expected_profiles.push_back(*profile0);
- EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(profiles), Return(true)));
- EXPECT_CALL(personal_data_manager(), Refresh());
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, AUTOFILL_PROFILE);
- StartSyncService(create_root.callback(), false, AUTOFILL_PROFILE);
- ASSERT_TRUE(create_root.success());
- std::vector<AutofillProfile> sync_profiles;
- ASSERT_TRUE(GetAutofillProfilesFromSyncDBUnderProfileNode(&sync_profiles));
- EXPECT_EQ(1U, sync_profiles.size());
- EXPECT_EQ(0, expected_profiles[0].Compare(sync_profiles[0]));
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeWithDuplicatesEmptySync) {
- // There is buggy autofill code that allows duplicate name/value
- // pairs to exist in the database with separate pair_ids.
- std::vector<AutofillEntry> entries;
- entries.push_back(MakeAutofillEntry("foo", "bar", 1));
- entries.push_back(MakeAutofillEntry("dup", "", 2));
- entries.push_back(MakeAutofillEntry("dup", "", 3));
- EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, AUTOFILL);
- EXPECT_CALL(personal_data_manager(), Refresh());
- StartSyncService(create_root.callback(), false, AUTOFILL);
- ASSERT_TRUE(create_root.success());
- std::vector<AutofillEntry> sync_entries;
- std::vector<AutofillProfile> sync_profiles;
- ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
- EXPECT_EQ(2U, sync_entries.size());
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncNoMerge) {
- AutofillEntry native_entry(MakeAutofillEntry("native", "entry", 1));
- AutofillEntry sync_entry(MakeAutofillEntry("sync", "entry", 2));
-
- std::vector<AutofillEntry> native_entries;
- native_entries.push_back(native_entry);
-
- EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
-
- std::vector<AutofillEntry> sync_entries;
- sync_entries.push_back(sync_entry);
-
- AddAutofillHelper<AutofillEntry> add_autofill(this, sync_entries);
-
- EXPECT_CALL(autofill_table(), UpdateAutofillEntries(ElementsAre(sync_entry)))
- .WillOnce(Return(true));
-
- EXPECT_CALL(personal_data_manager(), Refresh());
- StartSyncService(add_autofill.callback(), false, AUTOFILL);
- ASSERT_TRUE(add_autofill.success());
-
- std::set<AutofillEntry> expected_entries;
- expected_entries.insert(native_entry);
- expected_entries.insert(sync_entry);
-
- std::vector<AutofillEntry> new_sync_entries;
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&new_sync_entries,
- &new_sync_profiles));
- std::set<AutofillEntry> new_sync_entries_set(new_sync_entries.begin(),
- new_sync_entries.end());
-
- EXPECT_TRUE(expected_entries == new_sync_entries_set);
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncMergeEntry) {
- AutofillEntry native_entry(MakeAutofillEntry("merge", "entry", 1));
- AutofillEntry sync_entry(MakeAutofillEntry("merge", "entry", 2));
- AutofillEntry merged_entry(MakeAutofillEntry("merge", "entry", 1, 2));
-
- std::vector<AutofillEntry> native_entries;
- native_entries.push_back(native_entry);
- EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
-
- std::vector<AutofillEntry> sync_entries;
- sync_entries.push_back(sync_entry);
- AddAutofillHelper<AutofillEntry> add_autofill(this, sync_entries);
-
- EXPECT_CALL(autofill_table(),
- UpdateAutofillEntries(ElementsAre(merged_entry)))
- .WillOnce(Return(true));
- EXPECT_CALL(personal_data_manager(), Refresh());
- StartSyncService(add_autofill.callback(), false, AUTOFILL);
- ASSERT_TRUE(add_autofill.success());
-
- std::vector<AutofillEntry> new_sync_entries;
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&new_sync_entries,
- &new_sync_profiles));
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(merged_entry == new_sync_entries[0]);
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncMergeProfile) {
- AutofillProfile sync_profile;
- autofill::test::SetProfileInfoWithGuid(&sync_profile,
- "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
- "Mitchell", "Morrison",
- "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
- "91601", "US", "12345678910");
-
- AutofillProfile* native_profile = new AutofillProfile;
- autofill::test::SetProfileInfoWithGuid(native_profile,
- "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing", "Alicia", "Saenz",
- "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL",
- "32801", "US", "19482937549");
-
- std::vector<AutofillProfile*> native_profiles;
- native_profiles.push_back(native_profile);
- EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
-
- std::vector<AutofillProfile> sync_profiles;
- sync_profiles.push_back(sync_profile);
- AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
-
- EXPECT_CALL(autofill_table(),
- UpdateAutofillProfile(MatchProfiles(sync_profile)))
- .WillOnce(Return(true));
- EXPECT_CALL(personal_data_manager(), Refresh());
- StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
- ASSERT_TRUE(add_autofill.success());
-
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(GetAutofillProfilesFromSyncDBUnderProfileNode(
- &new_sync_profiles));
- ASSERT_EQ(1U, new_sync_profiles.size());
- EXPECT_EQ(0, sync_profile.Compare(new_sync_profiles[0]));
-}
-
-// Tests that a sync with a new native profile that matches a more recent new
-// sync profile but with less information results in the native profile being
-// deleted and replaced by the sync profile with merged usage stats.
-TEST_F(
- ProfileSyncServiceAutofillTest,
- HasNativeHasSyncMergeSimilarProfileCombine_SyncHasMoreInfoAndMoreRecent) {
- // Create two almost identical profiles. The GUIDs are different and the
- // native profile has no value for company name.
- AutofillProfile sync_profile;
- autofill::test::SetProfileInfoWithGuid(
- &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
- "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
- "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
- sync_profile.set_use_date(base::Time::FromTimeT(4321));
-
- AutofillProfile* native_profile = new AutofillProfile;
- autofill::test::SetProfileInfoWithGuid(
- native_profile, "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
- "Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
- "Hollywood", "CA", "91601", "US", "12345678910");
- native_profile->set_use_date(base::Time::FromTimeT(1234));
-
- AutofillProfile expected_profile(sync_profile);
- expected_profile.SetRawInfo(NAME_FULL,
- ASCIIToUTF16("Billing Mitchell Morrison"));
- expected_profile.set_use_count(2);
-
- std::vector<AutofillProfile*> native_profiles;
- native_profiles.push_back(native_profile);
- EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
- EXPECT_CALL(autofill_table(),
- AddAutofillProfile(MatchProfiles(expected_profile)))
- .WillOnce(Return(true));
- EXPECT_CALL(autofill_table(),
- RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
- .WillOnce(Return(true));
- std::vector<AutofillProfile> sync_profiles;
- sync_profiles.push_back(sync_profile);
- AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
-
- EXPECT_CALL(personal_data_manager(), Refresh());
- // Adds all entries in |sync_profiles| to sync.
- StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
- ASSERT_TRUE(add_autofill.success());
-
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(
- GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
- ASSERT_EQ(1U, new_sync_profiles.size());
- // Check that key fields are the same.
- EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(sync_profile, "en-US"));
- // Make sure the additional information from the sync profile was kept.
- EXPECT_EQ(ASCIIToUTF16("Fox"),
- new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
- // Check that the latest use date is saved.
- EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
- // Check that the use counts were added (default value is 1).
- EXPECT_EQ(2U, new_sync_profiles[0].use_count());
-}
-
-// Tests that a sync with a new native profile that matches an older new sync
-// profile but with less information results in the native profile being deleted
-// and replaced by the sync profile with merged usage stats.
-TEST_F(ProfileSyncServiceAutofillTest,
- HasNativeHasSyncMergeSimilarProfileCombine_SyncHasMoreInfoAndOlder) {
- // Create two almost identical profiles. The GUIDs are different and the
- // native profile has no value for company name.
- AutofillProfile sync_profile;
- autofill::test::SetProfileInfoWithGuid(
- &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
- "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
- "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
- sync_profile.set_use_date(base::Time::FromTimeT(1234));
-
- AutofillProfile* native_profile = new AutofillProfile;
- autofill::test::SetProfileInfoWithGuid(
- native_profile, "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
- "Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
- "Hollywood", "CA", "91601", "US", "12345678910");
- native_profile->set_use_date(base::Time::FromTimeT(4321));
-
- AutofillProfile expected_profile(sync_profile);
- expected_profile.SetRawInfo(NAME_FULL,
- ASCIIToUTF16("Billing Mitchell Morrison"));
- expected_profile.set_use_count(2);
- expected_profile.set_use_date(native_profile->use_date());
-
- std::vector<AutofillProfile*> native_profiles;
- native_profiles.push_back(native_profile);
- EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
- EXPECT_CALL(autofill_table(),
- AddAutofillProfile(MatchProfiles(expected_profile)))
- .WillOnce(Return(true));
- EXPECT_CALL(autofill_table(),
- RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
- .WillOnce(Return(true));
- std::vector<AutofillProfile> sync_profiles;
- sync_profiles.push_back(sync_profile);
- AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
-
- EXPECT_CALL(personal_data_manager(), Refresh());
- // Adds all entries in |sync_profiles| to sync.
- StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
- ASSERT_TRUE(add_autofill.success());
-
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(
- GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
- ASSERT_EQ(1U, new_sync_profiles.size());
- // Check that key fields are the same.
- EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(sync_profile, "en-US"));
- // Make sure the additional information from the sync profile was kept.
- EXPECT_EQ(ASCIIToUTF16("Fox"),
- new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
- // Check that the latest use date is saved.
- EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
- // Check that the use counts were added (default value is 1).
- EXPECT_EQ(2U, new_sync_profiles[0].use_count());
-}
-
-// Tests that a sync with a new native profile that matches an a new sync
-// profile but with more information results in the native profile being deleted
-// and replaced by the sync profile with the native profiles additional
-// information merged in. The merge should happen even if the sync profile is
-// more recent.
-TEST_F(ProfileSyncServiceAutofillTest,
- HasNativeHasSyncMergeSimilarProfileCombine_NativeHasMoreInfo) {
- // Create two almost identical profiles. The GUIDs are different and the
- // sync profile has no value for company name.
- AutofillProfile sync_profile;
- autofill::test::SetProfileInfoWithGuid(
- &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
- "Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
- "Hollywood", "CA", "91601", "US", "12345678910");
- sync_profile.set_use_date(base::Time::FromTimeT(4321));
-
- AutofillProfile* native_profile = new AutofillProfile;
- autofill::test::SetProfileInfoWithGuid(
- native_profile, "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
- "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
- "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
- native_profile->set_use_date(base::Time::FromTimeT(1234));
-
- AutofillProfile expected_profile(*native_profile);
- expected_profile.SetRawInfo(NAME_FULL,
- ASCIIToUTF16("Billing Mitchell Morrison"));
- expected_profile.set_use_date(sync_profile.use_date());
- expected_profile.set_use_count(2);
-
- std::vector<AutofillProfile*> native_profiles;
- native_profiles.push_back(native_profile);
- EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
- EXPECT_CALL(autofill_table(),
- AddAutofillProfile(MatchProfiles(expected_profile)))
- .WillOnce(Return(true));
- EXPECT_CALL(autofill_table(),
- RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
- .WillOnce(Return(true));
- std::vector<AutofillProfile> sync_profiles;
- sync_profiles.push_back(sync_profile);
- AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
-
- EXPECT_CALL(personal_data_manager(), Refresh());
- // Adds all entries in |sync_profiles| to sync.
- StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
- ASSERT_TRUE(add_autofill.success());
-
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(
- GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
- ASSERT_EQ(1U, new_sync_profiles.size());
- // Check that key fields are the same.
- EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(expected_profile, "en-US"));
- // Make sure the addtional information of the native profile was saved into
- // the sync profile.
- EXPECT_EQ(ASCIIToUTF16("Fox"),
- new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
- // Check that the latest use date is saved.
- EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
- // Check that the use counts were added (default value is 1).
- EXPECT_EQ(2U, new_sync_profiles[0].use_count());
-}
-
-// Tests that a sync with a new native profile that differ only by name a new
-// sync profile results in keeping both profiles.
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSync_DifferentPrimaryInfo) {
- AutofillProfile sync_profile;
- autofill::test::SetProfileInfoWithGuid(
- &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
- "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
- "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
- sync_profile.set_use_date(base::Time::FromTimeT(4321));
-
- AutofillProfile* native_profile = new AutofillProfile;
- autofill::test::SetProfileInfoWithGuid(
- native_profile, "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing", "John",
- "Smith", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood",
- "CA", "91601", "US", "12345678910");
- native_profile->set_use_date(base::Time::FromTimeT(1234));
-
- std::vector<AutofillProfile*> native_profiles;
- native_profiles.push_back(native_profile);
- EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
- EXPECT_CALL(autofill_table(), AddAutofillProfile(MatchProfiles(sync_profile)))
- .WillOnce(Return(true));
- std::vector<AutofillProfile> sync_profiles;
- sync_profiles.push_back(sync_profile);
- AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
-
- EXPECT_CALL(personal_data_manager(), Refresh());
- // Adds all entries in |sync_profiles| to sync.
- StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
- ASSERT_TRUE(add_autofill.success());
-
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(
- GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
- // The two profiles should be kept.
- ASSERT_EQ(2U, new_sync_profiles.size());
-}
-
-// Tests that a new native profile that is the same as a new sync profile except
-// with different GUIDs results in the native profile being deleted and replaced
-// by the sync profile.
-TEST_F(ProfileSyncServiceAutofillTest, MergeProfileWithDifferentGuid) {
- AutofillProfile sync_profile;
-
- autofill::test::SetProfileInfoWithGuid(&sync_profile,
- "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
- "Mitchell", "Morrison",
- "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
- "91601", "US", "12345678910");
- sync_profile.set_use_count(20);
- sync_profile.set_use_date(base::Time::FromTimeT(1234));
-
- std::string native_guid = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
- AutofillProfile* native_profile = new AutofillProfile;
- autofill::test::SetProfileInfoWithGuid(native_profile,
- native_guid.c_str(), "Billing",
- "Mitchell", "Morrison",
- "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
- "91601", "US", "12345678910");
- native_profile->set_use_count(5);
- native_profile->set_use_date(base::Time::FromTimeT(4321));
-
- std::vector<AutofillProfile*> native_profiles;
- native_profiles.push_back(native_profile);
- EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
-
- std::vector<AutofillProfile> sync_profiles;
- sync_profiles.push_back(sync_profile);
- AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
-
- EXPECT_CALL(autofill_table(), AddAutofillProfile(_)).WillOnce(Return(true));
- EXPECT_CALL(autofill_table(), RemoveAutofillProfile(native_guid))
- .WillOnce(Return(true));
- EXPECT_CALL(personal_data_manager(), Refresh());
- StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
- ASSERT_TRUE(add_autofill.success());
-
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(GetAutofillProfilesFromSyncDBUnderProfileNode(
- &new_sync_profiles));
- // Check that the profiles were merged.
- ASSERT_EQ(1U, new_sync_profiles.size());
- EXPECT_EQ(0, sync_profile.Compare(new_sync_profiles[0]));
- // Check that the sync guid was kept.
- EXPECT_EQ(sync_profile.guid(), new_sync_profiles[0].guid());
- // Check that the sync profile use count was kept.
- EXPECT_EQ(20U, new_sync_profiles[0].use_count());
- // Check that the sync profile use date was kept.
- EXPECT_EQ(base::Time::FromTimeT(1234), new_sync_profiles[0].use_date());
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeAddEntry) {
- EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
- .WillOnce(Return(true));
- EXPECT_CALL(personal_data_manager(), Refresh());
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, AUTOFILL);
- StartSyncService(create_root.callback(), false, AUTOFILL);
- ASSERT_TRUE(create_root.success());
-
- AutofillEntry added_entry(MakeAutofillEntry("added", "entry", 1));
-
- EXPECT_CALL(autofill_table(), GetAutofillTimestamps(_, _, _, _))
- .WillOnce(DoAll(SetArgumentPointee<2>(added_entry.date_created()),
- SetArgumentPointee<3>(added_entry.date_last_used()),
- Return(true)));
-
- AutofillChangeList changes;
- changes.push_back(AutofillChange(AutofillChange::ADD, added_entry.key()));
-
- web_data_service()->OnAutofillEntriesChanged(changes);
-
- std::vector<AutofillEntry> new_sync_entries;
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&new_sync_entries,
- &new_sync_profiles));
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(added_entry == new_sync_entries[0]);
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeAddProfile) {
- EXPECT_CALL(autofill_table(), GetAutofillProfiles(_)).WillOnce(Return(true));
- EXPECT_CALL(personal_data_manager(), Refresh());
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, AUTOFILL_PROFILE);
- StartSyncService(create_root.callback(), false, AUTOFILL_PROFILE);
- ASSERT_TRUE(create_root.success());
-
- AutofillProfile added_profile;
- autofill::test::SetProfileInfoWithGuid(&added_profile,
- "D6ADA912-D374-4C0A-917D-F5C8EBE43011", "Josephine", "Alicia", "Saenz",
- "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL",
- "32801", "US", "19482937549");
-
- AutofillProfileChange change(
- AutofillProfileChange::ADD, added_profile.guid(), &added_profile);
- web_data_service()->OnAutofillProfileChanged(change);
-
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(GetAutofillProfilesFromSyncDBUnderProfileNode(
- &new_sync_profiles));
- ASSERT_EQ(1U, new_sync_profiles.size());
- EXPECT_EQ(0, added_profile.Compare(new_sync_profiles[0]));
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeUpdateEntry) {
- AutofillEntry original_entry(MakeAutofillEntry("my", "entry", 1));
- std::vector<AutofillEntry> original_entries;
- original_entries.push_back(original_entry);
-
- EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
- EXPECT_CALL(personal_data_manager(), Refresh());
- CreateRootHelper create_root(this, AUTOFILL);
- StartSyncService(create_root.callback(), false, AUTOFILL);
- ASSERT_TRUE(create_root.success());
-
- AutofillEntry updated_entry(MakeAutofillEntry("my", "entry", 1, 2));
-
- EXPECT_CALL(autofill_table(), GetAutofillTimestamps(_, _, _, _))
- .WillOnce(DoAll(SetArgumentPointee<2>(updated_entry.date_created()),
- SetArgumentPointee<3>(updated_entry.date_last_used()),
- Return(true)));
-
- AutofillChangeList changes;
- changes.push_back(AutofillChange(AutofillChange::UPDATE,
- updated_entry.key()));
- web_data_service()->OnAutofillEntriesChanged(changes);
-
- std::vector<AutofillEntry> new_sync_entries;
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&new_sync_entries,
- &new_sync_profiles));
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(updated_entry == new_sync_entries[0]);
-}
-
-
-TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveEntry) {
- AutofillEntry original_entry(MakeAutofillEntry("my", "entry", 1));
- std::vector<AutofillEntry> original_entries;
- original_entries.push_back(original_entry);
-
- EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
- EXPECT_CALL(personal_data_manager(), Refresh());
- CreateRootHelper create_root(this, AUTOFILL);
- StartSyncService(create_root.callback(), false, AUTOFILL);
- ASSERT_TRUE(create_root.success());
-
- AutofillChangeList changes;
- changes.push_back(AutofillChange(AutofillChange::REMOVE,
- original_entry.key()));
- web_data_service()->OnAutofillEntriesChanged(changes);
-
- std::vector<AutofillEntry> new_sync_entries;
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&new_sync_entries,
- &new_sync_profiles));
- ASSERT_EQ(0U, new_sync_entries.size());
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveProfile) {
- AutofillProfile sync_profile;
- autofill::test::SetProfileInfoWithGuid(&sync_profile,
- "3BA5FA1B-1EC4-4BB3-9B57-EC92BE3C1A09", "Josephine", "Alicia", "Saenz",
- "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL",
- "32801", "US", "19482937549");
- AutofillProfile* native_profile = new AutofillProfile;
- autofill::test::SetProfileInfoWithGuid(native_profile,
- "3BA5FA1B-1EC4-4BB3-9B57-EC92BE3C1A09", "Josephine", "Alicia", "Saenz",
- "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL",
- "32801", "US", "19482937549");
-
- std::vector<AutofillProfile*> native_profiles;
- native_profiles.push_back(native_profile);
- EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
-
- std::vector<AutofillProfile> sync_profiles;
- sync_profiles.push_back(sync_profile);
- AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
- EXPECT_CALL(personal_data_manager(), Refresh());
- StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
- ASSERT_TRUE(add_autofill.success());
-
- AutofillProfileChange change(
- AutofillProfileChange::REMOVE, sync_profile.guid(), NULL);
- web_data_service()->OnAutofillProfileChanged(change);
-
- std::vector<AutofillProfile> new_sync_profiles;
- ASSERT_TRUE(GetAutofillProfilesFromSyncDBUnderProfileNode(
- &new_sync_profiles));
- ASSERT_EQ(0U, new_sync_profiles.size());
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, ServerChangeRace) {
- // Once for MergeDataAndStartSyncing() and twice for ProcessSyncChanges(), via
- // LoadAutofillData().
- EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
- .Times(3)
- .WillRepeatedly(Return(true));
- // On the other hand Autofill and Autocomplete are separated now, so
- // GetAutofillProfiles() should not be called.
- EXPECT_CALL(autofill_table(), GetAutofillProfiles(_)).Times(0);
- EXPECT_CALL(autofill_table(), UpdateAutofillEntries(_))
- .WillRepeatedly(Return(true));
- EXPECT_CALL(personal_data_manager(), Refresh()).Times(3);
- CreateRootHelper create_root(this, AUTOFILL);
- StartSyncService(create_root.callback(), false, AUTOFILL);
- ASSERT_TRUE(create_root.success());
-
- std::unique_ptr<WaitableEvent> wait_for_start(
- new WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED));
- std::unique_ptr<WaitableEvent> wait_for_syncapi(
- new WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED));
- scoped_refptr<FakeServerUpdater> updater(new FakeServerUpdater(
- sync_service(), wait_for_start.get(), wait_for_syncapi.get(),
- data_type_thread()->task_runner()));
-
- // This server side update will stall waiting for CommitWaiter.
- updater->CreateNewEntry(MakeAutofillEntry("server", "entry", 1));
- wait_for_start->Wait();
-
- AutofillEntry syncapi_entry(MakeAutofillEntry("syncapi", "entry", 2));
- ASSERT_TRUE(AddAutofillSyncNode(syncapi_entry));
- DVLOG(1) << "Syncapi update finished.";
-
- // If we reach here, it means syncapi succeeded and we didn't deadlock. Yay!
- // Signal FakeServerUpdater that it can complete.
- wait_for_syncapi->Signal();
-
- // Make another entry to ensure nothing broke afterwards and wait for finish
- // to clean up.
- updater->WaitForUpdateCompletion();
- updater->CreateNewEntry(MakeAutofillEntry("server2", "entry2", 3));
- updater->WaitForUpdateCompletion();
-
- // Let callbacks posted on UI thread execute.
- base::RunLoop().RunUntilIdle();
-
- std::vector<AutofillEntry> sync_entries;
- std::vector<AutofillProfile> sync_profiles;
- ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
- EXPECT_EQ(3U, sync_entries.size());
- EXPECT_EQ(0U, sync_profiles.size());
- for (size_t i = 0; i < sync_entries.size(); i++) {
- DVLOG(1) << "Entry " << i << ": " << sync_entries[i].key().name()
- << ", " << sync_entries[i].key().value();
- }
-}
diff --git a/chromium/components/browser_sync/browser/profile_sync_service_bookmark_unittest.cc b/chromium/components/browser_sync/browser/profile_sync_service_bookmark_unittest.cc
deleted file mode 100644
index 91d18cf4470..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_service_bookmark_unittest.cc
+++ /dev/null
@@ -1,2594 +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.
-
-// TODO(akalin): This file is basically just a unit test for
-// BookmarkChangeProcessor. Write unit tests for
-// BookmarkModelAssociator separately.
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <queue>
-#include <stack>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/files/file_util.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "components/bookmarks/browser/base_bookmark_model_observer.h"
-#include "components/bookmarks/browser/bookmark_model.h"
-#include "components/bookmarks/browser/bookmark_utils.h"
-#include "components/bookmarks/managed/managed_bookmark_service.h"
-#include "components/bookmarks/test/bookmark_test_helpers.h"
-#include "components/bookmarks/test/test_bookmark_client.h"
-#include "components/browser_sync/browser/profile_sync_test_util.h"
-#include "components/sync_bookmarks/bookmark_change_processor.h"
-#include "components/sync_bookmarks/bookmark_model_associator.h"
-#include "components/sync_driver/fake_sync_client.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_merge_result.h"
-#include "sync/internal_api/public/change_record.h"
-#include "sync/internal_api/public/data_type_error_handler.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/test/data_type_error_handler_mock.h"
-#include "sync/internal_api/public/test/test_user_share.h"
-#include "sync/internal_api/public/write_node.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/internal_api/syncapi_internal.h"
-#include "sync/syncable/mutable_entry.h"
-#include "sync/syncable/syncable_id.h"
-#include "sync/syncable/syncable_util.h"
-#include "sync/syncable/syncable_write_transaction.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using bookmarks::BookmarkModel;
-using bookmarks::BookmarkNode;
-using syncer::BaseNode;
-using testing::_;
-using testing::Return;
-using testing::StrictMock;
-
-namespace browser_sync {
-
-namespace {
-
-#if defined(OS_ANDROID) || defined(OS_IOS)
-static const bool kExpectMobileBookmarks = true;
-#else
-static const bool kExpectMobileBookmarks = false;
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
-
-std::string ReturnEmptyString() {
- return std::string();
-}
-
-void MakeServerUpdate(syncer::WriteTransaction* trans,
- syncer::WriteNode* node) {
- syncer::syncable::ChangeEntryIDAndUpdateChildren(
- trans->GetWrappedWriteTrans(), node->GetMutableEntryForTest(),
- syncer::syncable::Id::CreateFromServerId(
- base::Int64ToString(node->GetId())));
- node->GetMutableEntryForTest()->PutBaseVersion(10);
- node->GetMutableEntryForTest()->PutIsUnappliedUpdate(true);
-}
-
-void MakeServerUpdate(syncer::WriteTransaction* trans, int64_t id) {
- syncer::WriteNode node(trans);
- EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
- MakeServerUpdate(trans, &node);
-}
-
-// FakeServerChange constructs a list of syncer::ChangeRecords while modifying
-// the sync model, and can pass the ChangeRecord list to a
-// syncer::SyncObserver (i.e., the ProfileSyncService) to test the client
-// change-application behavior.
-// Tests using FakeServerChange should be careful to avoid back-references,
-// since FakeServerChange will send the edits in the order specified.
-class FakeServerChange {
- public:
- explicit FakeServerChange(syncer::WriteTransaction* trans) : trans_(trans) {}
-
- // Pretend that the server told the syncer to add a bookmark object.
- int64_t AddWithMetaInfo(const std::string& title,
- const std::string& url,
- const BookmarkNode::MetaInfoMap* meta_info_map,
- bool is_folder,
- int64_t parent_id,
- int64_t predecessor_id) {
- syncer::ReadNode parent(trans_);
- EXPECT_EQ(BaseNode::INIT_OK, parent.InitByIdLookup(parent_id));
- syncer::WriteNode node(trans_);
- if (predecessor_id == 0) {
- EXPECT_TRUE(node.InitBookmarkByCreation(parent, NULL));
- } else {
- syncer::ReadNode predecessor(trans_);
- EXPECT_EQ(BaseNode::INIT_OK, predecessor.InitByIdLookup(predecessor_id));
- EXPECT_EQ(predecessor.GetParentId(), parent.GetId());
- EXPECT_TRUE(node.InitBookmarkByCreation(parent, &predecessor));
- }
- EXPECT_EQ(node.GetPredecessorId(), predecessor_id);
- EXPECT_EQ(node.GetParentId(), parent_id);
- node.SetIsFolder(is_folder);
- node.SetTitle(title);
-
- sync_pb::BookmarkSpecifics specifics(node.GetBookmarkSpecifics());
- const base::Time creation_time(base::Time::Now());
- specifics.set_creation_time_us(creation_time.ToInternalValue());
- if (!is_folder)
- specifics.set_url(url);
- if (meta_info_map)
- SetNodeMetaInfo(*meta_info_map, &specifics);
- node.SetBookmarkSpecifics(specifics);
-
- syncer::ChangeRecord record;
- record.action = syncer::ChangeRecord::ACTION_ADD;
- record.id = node.GetId();
- changes_.push_back(record);
- return node.GetId();
- }
-
- int64_t Add(const std::string& title,
- const std::string& url,
- bool is_folder,
- int64_t parent_id,
- int64_t predecessor_id) {
- return AddWithMetaInfo(title, url, NULL, is_folder, parent_id,
- predecessor_id);
- }
-
- // Add a bookmark folder.
- int64_t AddFolder(const std::string& title,
- int64_t parent_id,
- int64_t predecessor_id) {
- return Add(title, std::string(), true, parent_id, predecessor_id);
- }
- int64_t AddFolderWithMetaInfo(const std::string& title,
- const BookmarkNode::MetaInfoMap* meta_info_map,
- int64_t parent_id,
- int64_t predecessor_id) {
- return AddWithMetaInfo(title, std::string(), meta_info_map, true, parent_id,
- predecessor_id);
- }
-
- // Add a bookmark.
- int64_t AddURL(const std::string& title,
- const std::string& url,
- int64_t parent_id,
- int64_t predecessor_id) {
- return Add(title, url, false, parent_id, predecessor_id);
- }
- int64_t AddURLWithMetaInfo(const std::string& title,
- const std::string& url,
- const BookmarkNode::MetaInfoMap* meta_info_map,
- int64_t parent_id,
- int64_t predecessor_id) {
- return AddWithMetaInfo(title, url, meta_info_map, false, parent_id,
- predecessor_id);
- }
-
- // Pretend that the server told the syncer to delete an object.
- void Delete(int64_t id) {
- {
- // Delete the sync node.
- syncer::WriteNode node(trans_);
- EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
- if (node.GetIsFolder())
- EXPECT_FALSE(node.GetFirstChildId());
- node.GetMutableEntryForTest()->PutServerIsDel(true);
- node.Tombstone();
- }
- {
- // Verify the deletion.
- syncer::ReadNode node(trans_);
- EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_IS_DEL, node.InitByIdLookup(id));
- }
-
- syncer::ChangeRecord record;
- record.action = syncer::ChangeRecord::ACTION_DELETE;
- record.id = id;
- // Deletions are always first in the changelist, but we can't actually do
- // WriteNode::Remove() on the node until its children are moved. So, as
- // a practical matter, users of FakeServerChange must move or delete
- // children before parents. Thus, we must insert the deletion record
- // at the front of the vector.
- changes_.insert(changes_.begin(), record);
- }
-
- // Set a new title value, and return the old value.
- std::string ModifyTitle(int64_t id, const std::string& new_title) {
- syncer::WriteNode node(trans_);
- EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
- std::string old_title = node.GetTitle();
- node.SetTitle(new_title);
- SetModified(id);
- return old_title;
- }
-
- // Set a new parent and predecessor value. Return the old parent id.
- // We could return the old predecessor id, but it turns out not to be
- // very useful for assertions.
- int64_t ModifyPosition(int64_t id,
- int64_t parent_id,
- int64_t predecessor_id) {
- syncer::ReadNode parent(trans_);
- EXPECT_EQ(BaseNode::INIT_OK, parent.InitByIdLookup(parent_id));
- syncer::WriteNode node(trans_);
- EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
- int64_t old_parent_id = node.GetParentId();
- if (predecessor_id == 0) {
- EXPECT_TRUE(node.SetPosition(parent, NULL));
- } else {
- syncer::ReadNode predecessor(trans_);
- EXPECT_EQ(BaseNode::INIT_OK, predecessor.InitByIdLookup(predecessor_id));
- EXPECT_EQ(predecessor.GetParentId(), parent.GetId());
- EXPECT_TRUE(node.SetPosition(parent, &predecessor));
- }
- SetModified(id);
- return old_parent_id;
- }
-
- void ModifyCreationTime(int64_t id, int64_t creation_time_us) {
- syncer::WriteNode node(trans_);
- ASSERT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
- sync_pb::BookmarkSpecifics specifics = node.GetBookmarkSpecifics();
- specifics.set_creation_time_us(creation_time_us);
- node.SetBookmarkSpecifics(specifics);
- SetModified(id);
- }
-
- void ModifyMetaInfo(int64_t id,
- const BookmarkNode::MetaInfoMap& meta_info_map) {
- syncer::WriteNode node(trans_);
- ASSERT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
- sync_pb::BookmarkSpecifics specifics = node.GetBookmarkSpecifics();
- SetNodeMetaInfo(meta_info_map, &specifics);
- node.SetBookmarkSpecifics(specifics);
- SetModified(id);
- }
-
- // Pass the fake change list to |service|.
- void ApplyPendingChanges(sync_driver::ChangeProcessor* processor) {
- processor->ApplyChangesFromSyncModel(
- trans_, 0, syncer::ImmutableChangeRecordList(&changes_));
- }
-
- const syncer::ChangeRecordList& changes() { return changes_; }
-
- private:
- // Helper function to push an ACTION_UPDATE record onto the back
- // of the changelist.
- void SetModified(int64_t id) {
- // Coalesce multi-property edits.
- if (!changes_.empty() && changes_.back().id == id &&
- changes_.back().action == syncer::ChangeRecord::ACTION_UPDATE)
- return;
- syncer::ChangeRecord record;
- record.action = syncer::ChangeRecord::ACTION_UPDATE;
- record.id = id;
- changes_.push_back(record);
- }
-
- void SetNodeMetaInfo(const BookmarkNode::MetaInfoMap& meta_info_map,
- sync_pb::BookmarkSpecifics* specifics) {
- specifics->clear_meta_info();
- // Deliberatly set MetaInfoMap entries in opposite order (compared
- // to the implementation in BookmarkChangeProcessor) to ensure that
- // (a) the implementation isn't sensitive to the order and
- // (b) the original meta info isn't blindly overwritten by
- // BookmarkChangeProcessor unless there is a real change.
- BookmarkNode::MetaInfoMap::const_iterator it = meta_info_map.end();
- while (it != meta_info_map.begin()) {
- --it;
- sync_pb::MetaInfo* meta_info = specifics->add_meta_info();
- meta_info->set_key(it->first);
- meta_info->set_value(it->second);
- }
- }
-
- // The transaction on which everything happens.
- syncer::WriteTransaction* trans_;
-
- // The change list we construct.
- syncer::ChangeRecordList changes_;
- DISALLOW_COPY_AND_ASSIGN(FakeServerChange);
-};
-
-class ExtensiveChangesBookmarkModelObserver
- : public bookmarks::BaseBookmarkModelObserver {
- public:
- ExtensiveChangesBookmarkModelObserver()
- : started_count_(0),
- completed_count_at_started_(0),
- completed_count_(0) {}
-
- void ExtensiveBookmarkChangesBeginning(BookmarkModel* model) override {
- ++started_count_;
- completed_count_at_started_ = completed_count_;
- }
-
- void ExtensiveBookmarkChangesEnded(BookmarkModel* model) override {
- ++completed_count_;
- }
-
- void BookmarkModelChanged() override {}
-
- int get_started() const { return started_count_; }
-
- int get_completed_count_at_started() const {
- return completed_count_at_started_;
- }
-
- int get_completed() const { return completed_count_; }
-
- private:
- int started_count_;
- int completed_count_at_started_;
- int completed_count_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensiveChangesBookmarkModelObserver);
-};
-
-class ProfileSyncServiceBookmarkTest : public testing::Test {
- protected:
- enum LoadOption { LOAD_FROM_STORAGE, DELETE_EXISTING_STORAGE };
- enum SaveOption { SAVE_TO_STORAGE, DONT_SAVE_TO_STORAGE };
-
- ProfileSyncServiceBookmarkTest()
- : managed_bookmark_service_(new bookmarks::ManagedBookmarkService(
- profile_sync_service_bundle_.pref_service(),
- base::Bind(ReturnEmptyString))),
- local_merge_result_(syncer::BOOKMARKS),
- syncer_merge_result_(syncer::BOOKMARKS) {
- CHECK(data_dir_.CreateUniqueTempDir());
- browser_sync::ProfileSyncServiceBundle::SyncClientBuilder builder(
- &profile_sync_service_bundle_);
- builder.SetBookmarkModelCallback(base::Bind(
- &ProfileSyncServiceBookmarkTest::model, base::Unretained(this)));
- sync_client_ = builder.Build();
- bookmarks::RegisterProfilePrefs(
- profile_sync_service_bundle_.pref_service()->registry());
- }
-
- ~ProfileSyncServiceBookmarkTest() override {
- static_cast<KeyedService*>(managed_bookmark_service_.get())->Shutdown();
- StopSync();
- }
-
- void SetUp() override { test_user_share_.SetUp(); }
-
- void TearDown() override { test_user_share_.TearDown(); }
-
- bool CanSyncNode(const BookmarkNode* node) {
- return model_->client()->CanSyncNode(node);
- }
-
- // Inserts a folder directly to the share.
- // Do not use this after model association is complete.
- //
- // This function differs from the AddFolder() function declared elsewhere in
- // this file in that it only affects the sync model. It would be invalid to
- // change the sync model directly after ModelAssociation. This function can
- // be invoked prior to model association to set up first-time sync model
- // association scenarios.
- int64_t AddFolderToShare(syncer::WriteTransaction* trans,
- const std::string& title) {
- EXPECT_FALSE(model_associator_);
-
- // Be sure to call CreatePermanentBookmarkNodes(), otherwise this will fail.
- syncer::ReadNode bookmark_bar(trans);
- EXPECT_EQ(BaseNode::INIT_OK,
- bookmark_bar.InitByTagLookupForBookmarks("bookmark_bar"));
-
- syncer::WriteNode node(trans);
- EXPECT_TRUE(node.InitBookmarkByCreation(bookmark_bar, NULL));
- node.SetIsFolder(true);
- node.SetTitle(title);
-
- return node.GetId();
- }
-
- // Inserts a bookmark directly to the share.
- // Do not use this after model association is complete.
- //
- // This function differs from the AddURL() function declared elsewhere in this
- // file in that it only affects the sync model. It would be invalid to change
- // the sync model directly after ModelAssociation. This function can be
- // invoked prior to model association to set up first-time sync model
- // association scenarios.
- int64_t AddBookmarkToShare(syncer::WriteTransaction* trans,
- int64_t parent_id,
- const std::string& title,
- const std::string& url) {
- EXPECT_FALSE(model_associator_);
-
- syncer::ReadNode parent(trans);
- EXPECT_EQ(BaseNode::INIT_OK, parent.InitByIdLookup(parent_id));
-
- sync_pb::BookmarkSpecifics specifics;
- specifics.set_url(url);
- specifics.set_title(title);
-
- syncer::WriteNode node(trans);
- EXPECT_TRUE(node.InitBookmarkByCreation(parent, NULL));
- node.SetIsFolder(false);
- node.SetTitle(title);
- node.SetBookmarkSpecifics(specifics);
-
- return node.GetId();
- }
-
- // Create a BookmarkModel. If |delete_bookmarks| is true, the bookmarks file
- // will be deleted before starting up the BookmarkModel.
- std::unique_ptr<BookmarkModel> CreateBookmarkModel(bool delete_bookmarks) {
- const base::FilePath& data_path = data_dir_.path();
- auto model = base::WrapUnique(new BookmarkModel(
- base::WrapUnique(new bookmarks::TestBookmarkClient())));
- managed_bookmark_service_->BookmarkModelCreated(model.get());
- int64_t next_id = 0;
- static_cast<bookmarks::TestBookmarkClient*>(model->client())
- ->SetExtraNodesToLoad(
- managed_bookmark_service_->GetLoadExtraNodesCallback().Run(
- &next_id));
- if (delete_bookmarks) {
- base::DeleteFile(data_path.Append(FILE_PATH_LITERAL("dummy_bookmarks")),
- false);
- }
-
- model->Load(profile_sync_service_bundle_.pref_service(), data_path,
- base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get());
- bookmarks::test::WaitForBookmarkModelToLoad(model.get());
- return model;
- }
-
- // Load (or re-load) the bookmark model. |load| controls use of the
- // bookmarks file on disk. |save| controls whether the newly loaded
- // bookmark model will write out a bookmark file as it goes.
- void LoadBookmarkModel(LoadOption load, SaveOption save) {
- bool delete_bookmarks = load == DELETE_EXISTING_STORAGE;
- model_.reset();
- model_ = CreateBookmarkModel(delete_bookmarks);
- // This noticeably speeds up the unit tests that request it.
- if (save == DONT_SAVE_TO_STORAGE)
- model_->ClearStore();
- base::RunLoop().RunUntilIdle();
- }
-
- int GetSyncBookmarkCount() {
- syncer::ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
- syncer::ReadNode node(&trans);
- if (node.InitTypeRoot(syncer::BOOKMARKS) != BaseNode::INIT_OK)
- return 0;
- return node.GetTotalNodeCount();
- }
-
- // Creates the bookmark root node and the permanent nodes if they don't
- // already exist.
- bool CreatePermanentBookmarkNodes() {
- bool root_exists = false;
- syncer::ModelType type = syncer::BOOKMARKS;
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
- syncer::ReadNode uber_root(&trans);
- uber_root.InitByRootLookup();
-
- syncer::ReadNode root(&trans);
- root_exists = (root.InitTypeRoot(type) == BaseNode::INIT_OK);
- }
-
- if (!root_exists) {
- if (!syncer::TestUserShare::CreateRoot(type,
- test_user_share_.user_share()))
- return false;
- }
-
- const int kNumPermanentNodes = 3;
- const std::string permanent_tags[kNumPermanentNodes] = {
- "bookmark_bar", "other_bookmarks", "synced_bookmarks",
- };
- syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
- syncer::ReadNode root(&trans);
- EXPECT_EQ(BaseNode::INIT_OK, root.InitTypeRoot(type));
-
- // Loop through creating permanent nodes as necessary.
- int64_t last_child_id = syncer::kInvalidId;
- for (int i = 0; i < kNumPermanentNodes; ++i) {
- // First check if the node already exists. This is for tests that involve
- // persistence and set up sync more than once.
- syncer::ReadNode lookup(&trans);
- if (lookup.InitByTagLookupForBookmarks(permanent_tags[i]) ==
- syncer::ReadNode::INIT_OK) {
- last_child_id = lookup.GetId();
- continue;
- }
-
- // If it doesn't exist, create the permanent node at the end of the
- // ordering.
- syncer::ReadNode predecessor_node(&trans);
- syncer::ReadNode* predecessor = NULL;
- if (last_child_id != syncer::kInvalidId) {
- EXPECT_EQ(BaseNode::INIT_OK,
- predecessor_node.InitByIdLookup(last_child_id));
- predecessor = &predecessor_node;
- }
- syncer::WriteNode node(&trans);
- if (!node.InitBookmarkByCreation(root, predecessor))
- return false;
- node.SetIsFolder(true);
- node.GetMutableEntryForTest()->PutUniqueServerTag(permanent_tags[i]);
- node.SetTitle(permanent_tags[i]);
- node.SetExternalId(0);
- last_child_id = node.GetId();
- }
- return true;
- }
-
- bool AssociateModels() {
- DCHECK(!model_associator_);
-
- // Set up model associator.
- model_associator_.reset(new BookmarkModelAssociator(
- model_.get(), sync_client_.get(), test_user_share_.user_share(),
- &mock_error_handler_, kExpectMobileBookmarks));
-
- local_merge_result_ = syncer::SyncMergeResult(syncer::BOOKMARKS);
- syncer_merge_result_ = syncer::SyncMergeResult(syncer::BOOKMARKS);
- int local_count_before = model_->root_node()->GetTotalNodeCount();
- int syncer_count_before = GetSyncBookmarkCount();
-
- syncer::SyncError error = model_associator_->AssociateModels(
- &local_merge_result_, &syncer_merge_result_);
- if (error.IsSet())
- return false;
-
- base::RunLoop().RunUntilIdle();
-
- // Verify the merge results were calculated properly.
- EXPECT_EQ(local_count_before,
- local_merge_result_.num_items_before_association());
- EXPECT_EQ(syncer_count_before,
- syncer_merge_result_.num_items_before_association());
- EXPECT_EQ(local_merge_result_.num_items_after_association(),
- local_merge_result_.num_items_before_association() +
- local_merge_result_.num_items_added() -
- local_merge_result_.num_items_deleted());
- EXPECT_EQ(syncer_merge_result_.num_items_after_association(),
- syncer_merge_result_.num_items_before_association() +
- syncer_merge_result_.num_items_added() -
- syncer_merge_result_.num_items_deleted());
- EXPECT_EQ(model_->root_node()->GetTotalNodeCount(),
- local_merge_result_.num_items_after_association());
- EXPECT_EQ(GetSyncBookmarkCount(),
- syncer_merge_result_.num_items_after_association());
- return true;
- }
-
- void StartSync() {
- test_user_share_.Reload();
-
- ASSERT_TRUE(CreatePermanentBookmarkNodes());
- ASSERT_TRUE(AssociateModels());
-
- // Set up change processor.
- ResetChangeProcessor();
- change_processor_->Start(test_user_share_.user_share());
- }
-
- void StopSync() {
- change_processor_.reset();
- if (model_associator_) {
- syncer::SyncError error = model_associator_->DisassociateModels();
- EXPECT_FALSE(error.IsSet());
- }
- model_associator_.reset();
-
- base::RunLoop().RunUntilIdle();
-
- // TODO(akalin): Actually close the database and flush it to disk
- // (and make StartSync reload from disk). This would require
- // refactoring TestUserShare.
- }
-
- bool InitSyncNodeFromChromeNode(const BookmarkNode* bnode,
- BaseNode* sync_node) {
- return model_associator_->InitSyncNodeFromChromeId(bnode->id(), sync_node);
- }
-
- void ExpectSyncerNodeMatching(syncer::BaseTransaction* trans,
- const BookmarkNode* bnode) {
- std::string truncated_title = base::UTF16ToUTF8(bnode->GetTitle());
- syncer::SyncAPINameToServerName(truncated_title, &truncated_title);
- base::TruncateUTF8ToByteSize(truncated_title, 255, &truncated_title);
- syncer::ServerNameToSyncAPIName(truncated_title, &truncated_title);
-
- syncer::ReadNode gnode(trans);
- ASSERT_TRUE(InitSyncNodeFromChromeNode(bnode, &gnode));
- // Non-root node titles and parents must match.
- if (!model_->is_permanent_node(bnode)) {
- EXPECT_EQ(truncated_title, gnode.GetTitle());
- EXPECT_EQ(model_associator_->GetChromeNodeFromSyncId(gnode.GetParentId()),
- bnode->parent());
- }
- EXPECT_EQ(bnode->is_folder(), gnode.GetIsFolder());
- if (bnode->is_url())
- EXPECT_EQ(bnode->url(), GURL(gnode.GetBookmarkSpecifics().url()));
-
- // Check that meta info matches.
- const BookmarkNode::MetaInfoMap* meta_info_map = bnode->GetMetaInfoMap();
- sync_pb::BookmarkSpecifics specifics = gnode.GetBookmarkSpecifics();
- if (!meta_info_map) {
- EXPECT_EQ(0, specifics.meta_info_size());
- } else {
- EXPECT_EQ(meta_info_map->size(),
- static_cast<size_t>(specifics.meta_info_size()));
- for (int i = 0; i < specifics.meta_info_size(); i++) {
- BookmarkNode::MetaInfoMap::const_iterator it =
- meta_info_map->find(specifics.meta_info(i).key());
- EXPECT_TRUE(it != meta_info_map->end());
- EXPECT_EQ(it->second, specifics.meta_info(i).value());
- }
- }
-
- // Check for position matches.
- int browser_index = bnode->parent()->GetIndexOf(bnode);
- if (browser_index == 0) {
- EXPECT_EQ(gnode.GetPredecessorId(), 0);
- } else {
- const BookmarkNode* bprev = bnode->parent()->GetChild(browser_index - 1);
- syncer::ReadNode gprev(trans);
- ASSERT_TRUE(InitSyncNodeFromChromeNode(bprev, &gprev));
- EXPECT_EQ(gnode.GetPredecessorId(), gprev.GetId());
- EXPECT_EQ(gnode.GetParentId(), gprev.GetParentId());
- }
- // Note: the managed node is the last child of the root_node but isn't
- // synced; if CanSyncNode() is false then there is no next node to sync.
- const BookmarkNode* bnext = NULL;
- if (browser_index + 1 < bnode->parent()->child_count())
- bnext = bnode->parent()->GetChild(browser_index + 1);
- if (!bnext || !CanSyncNode(bnext)) {
- EXPECT_EQ(gnode.GetSuccessorId(), 0);
- } else {
- syncer::ReadNode gnext(trans);
- ASSERT_TRUE(InitSyncNodeFromChromeNode(bnext, &gnext));
- EXPECT_EQ(gnode.GetSuccessorId(), gnext.GetId());
- EXPECT_EQ(gnode.GetParentId(), gnext.GetParentId());
- }
- if (!bnode->empty())
- EXPECT_TRUE(gnode.GetFirstChildId());
- }
-
- void ExpectSyncerNodeMatching(const BookmarkNode* bnode) {
- syncer::ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
- ExpectSyncerNodeMatching(&trans, bnode);
- }
-
- void ExpectBrowserNodeMatching(syncer::BaseTransaction* trans,
- int64_t sync_id) {
- EXPECT_TRUE(sync_id);
- const BookmarkNode* bnode =
- model_associator_->GetChromeNodeFromSyncId(sync_id);
- ASSERT_TRUE(bnode);
- ASSERT_TRUE(CanSyncNode(bnode));
-
- int64_t id = model_associator_->GetSyncIdFromChromeId(bnode->id());
- EXPECT_EQ(id, sync_id);
- ExpectSyncerNodeMatching(trans, bnode);
- }
-
- void ExpectBrowserNodeUnknown(int64_t sync_id) {
- EXPECT_FALSE(model_associator_->GetChromeNodeFromSyncId(sync_id));
- }
-
- void ExpectBrowserNodeKnown(int64_t sync_id) {
- EXPECT_TRUE(model_associator_->GetChromeNodeFromSyncId(sync_id));
- }
-
- void ExpectSyncerNodeKnown(const BookmarkNode* node) {
- int64_t sync_id = model_associator_->GetSyncIdFromChromeId(node->id());
- EXPECT_NE(sync_id, syncer::kInvalidId);
- }
-
- void ExpectSyncerNodeUnknown(const BookmarkNode* node) {
- int64_t sync_id = model_associator_->GetSyncIdFromChromeId(node->id());
- EXPECT_EQ(sync_id, syncer::kInvalidId);
- }
-
- void ExpectBrowserNodeTitle(int64_t sync_id, const std::string& title) {
- const BookmarkNode* bnode =
- model_associator_->GetChromeNodeFromSyncId(sync_id);
- ASSERT_TRUE(bnode);
- EXPECT_EQ(bnode->GetTitle(), base::UTF8ToUTF16(title));
- }
-
- void ExpectBrowserNodeURL(int64_t sync_id, const std::string& url) {
- const BookmarkNode* bnode =
- model_associator_->GetChromeNodeFromSyncId(sync_id);
- ASSERT_TRUE(bnode);
- EXPECT_EQ(GURL(url), bnode->url());
- }
-
- void ExpectBrowserNodeParent(int64_t sync_id, int64_t parent_sync_id) {
- const BookmarkNode* node =
- model_associator_->GetChromeNodeFromSyncId(sync_id);
- ASSERT_TRUE(node);
- const BookmarkNode* parent =
- model_associator_->GetChromeNodeFromSyncId(parent_sync_id);
- EXPECT_TRUE(parent);
- EXPECT_EQ(node->parent(), parent);
- }
-
- void ExpectModelMatch(syncer::BaseTransaction* trans) {
- const BookmarkNode* root = model_->root_node();
- EXPECT_EQ(root->GetIndexOf(model_->bookmark_bar_node()), 0);
- EXPECT_EQ(root->GetIndexOf(model_->other_node()), 1);
- EXPECT_EQ(root->GetIndexOf(model_->mobile_node()), 2);
-
- std::stack<int64_t> stack;
- stack.push(bookmark_bar_id());
- while (!stack.empty()) {
- int64_t id = stack.top();
- stack.pop();
- if (!id)
- continue;
-
- ExpectBrowserNodeMatching(trans, id);
-
- syncer::ReadNode gnode(trans);
- ASSERT_EQ(BaseNode::INIT_OK, gnode.InitByIdLookup(id));
- stack.push(gnode.GetSuccessorId());
- if (gnode.GetIsFolder())
- stack.push(gnode.GetFirstChildId());
- }
- }
-
- void ExpectModelMatch() {
- syncer::ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
- ExpectModelMatch(&trans);
- }
-
- int64_t mobile_bookmarks_id() {
- return model_associator_->GetSyncIdFromChromeId(
- model_->mobile_node()->id());
- }
-
- int64_t other_bookmarks_id() {
- return model_associator_->GetSyncIdFromChromeId(model_->other_node()->id());
- }
-
- int64_t bookmark_bar_id() {
- return model_associator_->GetSyncIdFromChromeId(
- model_->bookmark_bar_node()->id());
- }
-
- BookmarkModel* model() { return model_.get(); }
-
- syncer::TestUserShare* test_user_share() { return &test_user_share_; }
-
- BookmarkChangeProcessor* change_processor() {
- return change_processor_.get();
- }
-
- void delete_change_processor() { change_processor_.reset(); }
-
- void ResetChangeProcessor() {
- change_processor_ = base::WrapUnique(new BookmarkChangeProcessor(
- sync_client_.get(), model_associator_.get(), &mock_error_handler_));
- }
-
- syncer::DataTypeErrorHandlerMock* mock_error_handler() {
- return &mock_error_handler_;
- }
-
- void delete_model_associator() { model_associator_.reset(); }
-
- BookmarkModelAssociator* model_associator() {
- return model_associator_.get();
- }
-
- bookmarks::ManagedBookmarkService* managed_bookmark_service() {
- return managed_bookmark_service_.get();
- }
-
- private:
- base::ScopedTempDir data_dir_;
- base::MessageLoop message_loop_;
- browser_sync::ProfileSyncServiceBundle profile_sync_service_bundle_;
-
- std::unique_ptr<sync_driver::FakeSyncClient> sync_client_;
- std::unique_ptr<BookmarkModel> model_;
- syncer::TestUserShare test_user_share_;
- std::unique_ptr<BookmarkChangeProcessor> change_processor_;
- StrictMock<syncer::DataTypeErrorHandlerMock> mock_error_handler_;
- std::unique_ptr<BookmarkModelAssociator> model_associator_;
- std::unique_ptr<bookmarks::ManagedBookmarkService> managed_bookmark_service_;
-
- syncer::SyncMergeResult local_merge_result_;
- syncer::SyncMergeResult syncer_merge_result_;
-
- DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceBookmarkTest);
-};
-
-TEST_F(ProfileSyncServiceBookmarkTest, InitialState) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- EXPECT_TRUE(other_bookmarks_id());
- EXPECT_TRUE(bookmark_bar_id());
- EXPECT_TRUE(mobile_bookmarks_id());
-
- ExpectModelMatch();
-}
-
-// Populate the sync database then start model association. Sync's bookmarks
-// should end up being copied into the native model, resulting in a successful
-// "ExpectModelMatch()".
-//
-// This code has some use for verifying correctness. It's also a very useful
-// for profiling bookmark ModelAssociation, an important part of some first-time
-// sync scenarios. Simply increase the kNumFolders and kNumBookmarksPerFolder
-// as desired, then run the test under a profiler to find hot spots in the model
-// association code.
-TEST_F(ProfileSyncServiceBookmarkTest, InitialModelAssociate) {
- const int kNumBookmarksPerFolder = 10;
- const int kNumFolders = 10;
-
- CreatePermanentBookmarkNodes();
-
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- for (int i = 0; i < kNumFolders; ++i) {
- int64_t folder_id =
- AddFolderToShare(&trans, base::StringPrintf("folder%05d", i));
- for (int j = 0; j < kNumBookmarksPerFolder; ++j) {
- AddBookmarkToShare(
- &trans, folder_id, base::StringPrintf("bookmark%05d", j),
- base::StringPrintf("http://www.google.com/search?q=%05d", j));
- }
- }
- }
-
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- ExpectModelMatch();
-}
-
-// Tests bookmark association when nodes exists in the native model only.
-// These entries should be copied to Sync directory during association process.
-TEST_F(ProfileSyncServiceBookmarkTest,
- InitialModelAssociateWithBookmarkModelNodes) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- const BookmarkNode* folder = model()->AddFolder(model()->other_node(), 0,
- base::ASCIIToUTF16("foobar"));
- model()->AddFolder(folder, 0, base::ASCIIToUTF16("nested"));
- model()->AddURL(folder, 0, base::ASCIIToUTF16("Internets #1 Pies Site"),
- GURL("http://www.easypie.com/"));
- model()->AddURL(folder, 1, base::ASCIIToUTF16("Airplanes"),
- GURL("http://www.easyjet.com/"));
-
- StartSync();
- ExpectModelMatch();
-}
-
-// Tests bookmark association case when there is an entry in the delete journal
-// that matches one of native bookmarks.
-TEST_F(ProfileSyncServiceBookmarkTest, InitialModelAssociateWithDeleteJournal) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- const BookmarkNode* folder = model()->AddFolder(
- model()->bookmark_bar_node(), 0, base::ASCIIToUTF16("foobar"));
- const BookmarkNode* bookmark =
- model()->AddURL(folder, 0, base::ASCIIToUTF16("Airplanes"),
- GURL("http://www.easyjet.com/"));
-
- CreatePermanentBookmarkNodes();
-
- // Create entries matching the folder and the bookmark above.
- int64_t folder_id, bookmark_id;
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- folder_id = AddFolderToShare(&trans, "foobar");
- bookmark_id = AddBookmarkToShare(&trans, folder_id, "Airplanes",
- "http://www.easyjet.com/");
- }
-
- // Associate the bookmark sync node with the native model one and make
- // it look like it was deleted by a server update.
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- syncer::WriteNode node(&trans);
- EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(bookmark_id));
-
- node.GetMutableEntryForTest()->PutLocalExternalId(bookmark->id());
-
- MakeServerUpdate(&trans, &node);
- node.GetMutableEntryForTest()->PutServerIsDel(true);
- node.GetMutableEntryForTest()->PutIsDel(true);
- }
-
- ASSERT_TRUE(AssociateModels());
- ExpectModelMatch();
-
- // The bookmark node should be deleted.
- EXPECT_EQ(0, folder->child_count());
-}
-
-// Tests that the external ID is used to match the right folder amoung
-// multiple folders with the same name during the native model traversal.
-// Also tests that the external ID is used to match the right bookmark
-// among multiple identical bookmarks when dealing with the delete journal.
-TEST_F(ProfileSyncServiceBookmarkTest,
- InitialModelAssociateVerifyExternalIdMatch) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- const int kNumFolders = 10;
- const int kNumBookmarks = 10;
- const int kFolderToIncludeBookmarks = 7;
- const int kBookmarkToDelete = 4;
-
- int64_t folder_ids[kNumFolders];
- int64_t bookmark_ids[kNumBookmarks];
-
- // Create native folders and bookmarks with identical names. Only
- // one of the folders contains bookmarks and others are empty. Here is the
- // expected tree shape:
- // Bookmarks bar
- // +- folder (#0)
- // +- folder (#1)
- // ...
- // +- folder (#7) <-- Only this folder contains bookmarks.
- // +- bookmark (#0)
- // +- bookmark (#1)
- // ...
- // +- bookmark (#4) <-- Only this one bookmark should be removed later.
- // ...
- // +- bookmark (#9)
- // ...
- // +- folder (#9)
-
- const BookmarkNode* parent_folder = nullptr;
- for (int i = 0; i < kNumFolders; i++) {
- const BookmarkNode* folder = model()->AddFolder(
- model()->bookmark_bar_node(), i, base::ASCIIToUTF16("folder"));
- folder_ids[i] = folder->id();
- if (i == kFolderToIncludeBookmarks) {
- parent_folder = folder;
- }
- }
-
- for (int i = 0; i < kNumBookmarks; i++) {
- const BookmarkNode* bookmark =
- model()->AddURL(parent_folder, i, base::ASCIIToUTF16("bookmark"),
- GURL("http://www.google.com/"));
- bookmark_ids[i] = bookmark->id();
- }
-
- // Number of nodes in bookmark bar before association.
- int total_node_count = model()->bookmark_bar_node()->GetTotalNodeCount();
-
- CreatePermanentBookmarkNodes();
-
- int64_t sync_bookmark_id_to_delete = 0;
- {
- // Create sync folders matching native folders above.
- int64_t parent_id = 0;
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- // Create in reverse order because AddFolderToShare passes NULL for
- // |predecessor| argument.
- for (int i = kNumFolders - 1; i >= 0; i--) {
- int64_t id = AddFolderToShare(&trans, "folder");
-
- // Pre-map sync folders to native folders by setting
- // external ID. This will verify that the association algorithm picks
- // the right ones despite all of them having identical names.
- // More specifically this will help to avoid cloning bookmarks from
- // a wrong folder.
- syncer::WriteNode node(&trans);
- EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
- node.GetMutableEntryForTest()->PutLocalExternalId(folder_ids[i]);
-
- if (i == kFolderToIncludeBookmarks) {
- parent_id = id;
- }
- }
-
- // Create sync bookmark matching native bookmarks above in reverse order
- // because AddBookmarkToShare passes NULL for |predecessor| argument.
- for (int i = kNumBookmarks - 1; i >= 0; i--) {
- int id = AddBookmarkToShare(&trans, parent_id, "bookmark",
- "http://www.google.com/");
-
- // Pre-map sync bookmarks to native bookmarks by setting
- // external ID. This will verify that the association algorithm picks
- // the right ones despite all of them having identical names and URLs.
- syncer::WriteNode node(&trans);
- EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
- node.GetMutableEntryForTest()->PutLocalExternalId(bookmark_ids[i]);
-
- if (i == kBookmarkToDelete) {
- sync_bookmark_id_to_delete = id;
- }
- }
- }
-
- // Make one bookmark deleted.
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- syncer::WriteNode node(&trans);
- EXPECT_EQ(BaseNode::INIT_OK,
- node.InitByIdLookup(sync_bookmark_id_to_delete));
-
- MakeServerUpdate(&trans, &node);
- node.GetMutableEntryForTest()->PutServerIsDel(true);
- node.GetMutableEntryForTest()->PutIsDel(true);
- }
-
- // Perform association.
- ASSERT_TRUE(AssociateModels());
- ExpectModelMatch();
-
- // Only one native node should have been deleted and no nodes cloned due to
- // matching folder names.
- EXPECT_EQ(kNumFolders, model()->bookmark_bar_node()->child_count());
- EXPECT_EQ(kNumBookmarks - 1, parent_folder->child_count());
- EXPECT_EQ(total_node_count - 1,
- model()->bookmark_bar_node()->GetTotalNodeCount());
-
- // Verify that the right bookmark got deleted and no bookmarks reordered.
- for (int i = 0; i < parent_folder->child_count(); i++) {
- int index_in_bookmark_ids = (i < kBookmarkToDelete) ? i : i + 1;
- EXPECT_EQ(bookmark_ids[index_in_bookmark_ids],
- parent_folder->GetChild(i)->id());
- }
-}
-
-// Verifies that the bookmark association skips sync nodes with invalid URLs.
-TEST_F(ProfileSyncServiceBookmarkTest, InitialModelAssociateWithInvalidUrl) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- // On the local side create a folder and two nodes.
- const BookmarkNode* folder = model()->AddFolder(
- model()->bookmark_bar_node(), 0, base::ASCIIToUTF16("folder"));
- model()->AddURL(folder, 0, base::ASCIIToUTF16("node1"),
- GURL("http://www.node1.com/"));
- model()->AddURL(folder, 1, base::ASCIIToUTF16("node2"),
- GURL("http://www.node2.com/"));
-
- // On the sync side create a matching folder, one matching node, one
- // unmatching node, and one node with an invalid URL.
- CreatePermanentBookmarkNodes();
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- int64_t folder_id = AddFolderToShare(&trans, "folder");
- // Please note that each AddBookmarkToShare inserts the node at the front
- // so the actual order of children in the directory will be opposite.
- AddBookmarkToShare(&trans, folder_id, "node2", "http://www.node2.com/");
- AddBookmarkToShare(&trans, folder_id, "node3", "");
- AddBookmarkToShare(&trans, folder_id, "node4", "http://www.node4.com/");
- }
-
- // Perform association.
- StartSync();
-
- // Concatenate resulting titles of native nodes.
- std::string native_titles;
- for (int i = 0; i < folder->child_count(); i++) {
- if (!native_titles.empty())
- native_titles += ",";
- const BookmarkNode* child = folder->GetChild(i);
- native_titles += base::UTF16ToUTF8(child->GetTitle());
- }
-
- // Expect the order of nodes to follow the sync order (see note above), the
- // node with the invalid URL to be skipped, and the extra native node to be
- // at the end.
- EXPECT_EQ("node4,node2,node1", native_titles);
-}
-
-TEST_F(ProfileSyncServiceBookmarkTest, BookmarkModelOperations) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- // Test addition.
- const BookmarkNode* folder = model()->AddFolder(model()->other_node(), 0,
- base::ASCIIToUTF16("foobar"));
- ExpectSyncerNodeMatching(folder);
- ExpectModelMatch();
- const BookmarkNode* folder2 =
- model()->AddFolder(folder, 0, base::ASCIIToUTF16("nested"));
- ExpectSyncerNodeMatching(folder2);
- ExpectModelMatch();
- const BookmarkNode* url1 =
- model()->AddURL(folder, 0, base::ASCIIToUTF16("Internets #1 Pies Site"),
- GURL("http://www.easypie.com/"));
- ExpectSyncerNodeMatching(url1);
- ExpectModelMatch();
- const BookmarkNode* url2 =
- model()->AddURL(folder, 1, base::ASCIIToUTF16("Airplanes"),
- GURL("http://www.easyjet.com/"));
- ExpectSyncerNodeMatching(url2);
- ExpectModelMatch();
- // Test addition.
- const BookmarkNode* mobile_folder =
- model()->AddFolder(model()->mobile_node(), 0, base::ASCIIToUTF16("pie"));
- ExpectSyncerNodeMatching(mobile_folder);
- ExpectModelMatch();
-
- // Test modification.
- model()->SetTitle(url2, base::ASCIIToUTF16("EasyJet"));
- ExpectModelMatch();
- model()->Move(url1, folder2, 0);
- ExpectModelMatch();
- model()->Move(folder2, model()->bookmark_bar_node(), 0);
- ExpectModelMatch();
- model()->SetTitle(folder2, base::ASCIIToUTF16("Not Nested"));
- ExpectModelMatch();
- model()->Move(folder, folder2, 0);
- ExpectModelMatch();
- model()->SetTitle(folder, base::ASCIIToUTF16("who's nested now?"));
- ExpectModelMatch();
- model()->Copy(url2, model()->bookmark_bar_node(), 0);
- ExpectModelMatch();
- model()->SetTitle(mobile_folder, base::ASCIIToUTF16("strawberry"));
- ExpectModelMatch();
-
- // Test deletion.
- // Delete a single item.
- model()->Remove(url2);
- ExpectModelMatch();
- // Delete an item with several children.
- model()->Remove(folder2);
- ExpectModelMatch();
- model()->Remove(model()->mobile_node()->GetChild(0));
- ExpectModelMatch();
-}
-
-TEST_F(ProfileSyncServiceBookmarkTest, ServerChangeProcessing) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
-
- FakeServerChange adds(&trans);
- int64_t f1 = adds.AddFolder("Server Folder B", bookmark_bar_id(), 0);
- int64_t f2 = adds.AddFolder("Server Folder A", bookmark_bar_id(), f1);
- int64_t u1 = adds.AddURL("Some old site", "ftp://nifty.andrew.cmu.edu/",
- bookmark_bar_id(), f2);
- int64_t u2 = adds.AddURL("Nifty", "ftp://nifty.andrew.cmu.edu/", f1, 0);
- // u3 is a duplicate URL
- int64_t u3 = adds.AddURL("Nifty2", "ftp://nifty.andrew.cmu.edu/", f1, u2);
- // u4 is a duplicate title, different URL.
- adds.AddURL("Some old site", "http://slog.thestranger.com/",
- bookmark_bar_id(), u1);
- // u5 tests an empty-string title.
- std::string javascript_url(
- "javascript:(function(){var w=window.open("
- "'about:blank','gnotesWin','location=0,menubar=0,"
- "scrollbars=0,status=0,toolbar=0,width=300,"
- "height=300,resizable');});");
- adds.AddURL(std::string(), javascript_url, other_bookmarks_id(), 0);
- int64_t u6 = adds.AddURL("Sync1", "http://www.syncable.edu/",
- mobile_bookmarks_id(), 0);
-
- syncer::ChangeRecordList::const_iterator it;
- // The bookmark model shouldn't yet have seen any of the nodes of |adds|.
- for (it = adds.changes().begin(); it != adds.changes().end(); ++it)
- ExpectBrowserNodeUnknown(it->id);
-
- adds.ApplyPendingChanges(change_processor());
-
- // Make sure the bookmark model received all of the nodes in |adds|.
- for (it = adds.changes().begin(); it != adds.changes().end(); ++it)
- ExpectBrowserNodeMatching(&trans, it->id);
- ExpectModelMatch(&trans);
-
- // Part two: test modifications.
- FakeServerChange mods(&trans);
- // Mess with u2, and move it into empty folder f2
- // TODO(ncarter): Determine if we allow ModifyURL ops or not.
- /* std::string u2_old_url = mods.ModifyURL(u2, "http://www.google.com"); */
- std::string u2_old_title = mods.ModifyTitle(u2, "The Google");
- int64_t u2_old_parent = mods.ModifyPosition(u2, f2, 0);
-
- // Now move f1 after u2.
- std::string f1_old_title = mods.ModifyTitle(f1, "Server Folder C");
- int64_t f1_old_parent = mods.ModifyPosition(f1, f2, u2);
-
- // Then add u3 after f1.
- int64_t u3_old_parent = mods.ModifyPosition(u3, f2, f1);
-
- std::string u6_old_title = mods.ModifyTitle(u6, "Mobile Folder A");
-
- // Test that the property changes have not yet taken effect.
- ExpectBrowserNodeTitle(u2, u2_old_title);
- /* ExpectBrowserNodeURL(u2, u2_old_url); */
- ExpectBrowserNodeParent(u2, u2_old_parent);
-
- ExpectBrowserNodeTitle(f1, f1_old_title);
- ExpectBrowserNodeParent(f1, f1_old_parent);
-
- ExpectBrowserNodeParent(u3, u3_old_parent);
-
- ExpectBrowserNodeTitle(u6, u6_old_title);
-
- // Apply the changes.
- mods.ApplyPendingChanges(change_processor());
-
- // Check for successful application.
- for (it = mods.changes().begin(); it != mods.changes().end(); ++it)
- ExpectBrowserNodeMatching(&trans, it->id);
- ExpectModelMatch(&trans);
-
- // Part 3: Test URL deletion.
- FakeServerChange dels(&trans);
- dels.Delete(u2);
- dels.Delete(u3);
- dels.Delete(u6);
-
- ExpectBrowserNodeKnown(u2);
- ExpectBrowserNodeKnown(u3);
-
- dels.ApplyPendingChanges(change_processor());
-
- ExpectBrowserNodeUnknown(u2);
- ExpectBrowserNodeUnknown(u3);
- ExpectBrowserNodeUnknown(u6);
- ExpectModelMatch(&trans);
-}
-
-// Tests a specific case in ApplyModelChanges where we move the
-// children out from under a parent, and then delete the parent
-// in the same changelist. The delete shows up first in the changelist,
-// requiring the children to be moved to a temporary location.
-TEST_F(ProfileSyncServiceBookmarkTest, ServerChangeRequiringFosterParent) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
-
- // Stress the immediate children of other_node because that's where
- // ApplyModelChanges puts a temporary foster parent node.
- std::string url("http://dev.chromium.org/");
- FakeServerChange adds(&trans);
- int64_t f0 = other_bookmarks_id(); // + other_node
- int64_t f1 = adds.AddFolder("f1", f0, 0); // + f1
- int64_t f2 = adds.AddFolder("f2", f1, 0); // + f2
- int64_t u3 = adds.AddURL("u3", url, f2, 0); // + u3 NOLINT
- int64_t u4 = adds.AddURL("u4", url, f2, u3); // + u4 NOLINT
- int64_t u5 = adds.AddURL("u5", url, f1, f2); // + u5 NOLINT
- int64_t f6 = adds.AddFolder("f6", f1, u5); // + f6
- int64_t u7 = adds.AddURL("u7", url, f0, f1); // + u7 NOLINT
-
- syncer::ChangeRecordList::const_iterator it;
- // The bookmark model shouldn't yet have seen any of the nodes of |adds|.
- for (it = adds.changes().begin(); it != adds.changes().end(); ++it)
- ExpectBrowserNodeUnknown(it->id);
-
- adds.ApplyPendingChanges(change_processor());
-
- // Make sure the bookmark model received all of the nodes in |adds|.
- for (it = adds.changes().begin(); it != adds.changes().end(); ++it)
- ExpectBrowserNodeMatching(&trans, it->id);
- ExpectModelMatch(&trans);
-
- // We have to do the moves before the deletions, but FakeServerChange will
- // put the deletion at the front of the changelist.
- FakeServerChange ops(&trans);
- ops.ModifyPosition(f6, other_bookmarks_id(), 0);
- ops.ModifyPosition(u3, other_bookmarks_id(), f1); // Prev == f1 is OK here.
- ops.ModifyPosition(f2, other_bookmarks_id(), u7);
- ops.ModifyPosition(u7, f2, 0);
- ops.ModifyPosition(u4, other_bookmarks_id(), f2);
- ops.ModifyPosition(u5, f6, 0);
- ops.Delete(f1);
-
- ops.ApplyPendingChanges(change_processor());
-
- ExpectModelMatch(&trans);
-}
-
-// Simulate a server change record containing a valid but non-canonical URL.
-TEST_F(ProfileSyncServiceBookmarkTest, ServerChangeWithNonCanonicalURL) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
- StartSync();
-
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
-
- FakeServerChange adds(&trans);
- std::string url("http://dev.chromium.org");
- EXPECT_NE(GURL(url).spec(), url);
- adds.AddURL("u1", url, other_bookmarks_id(), 0);
-
- adds.ApplyPendingChanges(change_processor());
-
- EXPECT_EQ(1, model()->other_node()->child_count());
- ExpectModelMatch(&trans);
- }
-
- // Now reboot the sync service, forcing a merge step.
- StopSync();
- LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE);
- StartSync();
-
- // There should still be just the one bookmark.
- EXPECT_EQ(1, model()->other_node()->child_count());
- ExpectModelMatch();
-}
-
-// Simulate a server change record containing an invalid URL (per GURL).
-// TODO(ncarter): Disabled due to crashes. Fix bug 1677563.
-TEST_F(ProfileSyncServiceBookmarkTest, DISABLED_ServerChangeWithInvalidURL) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
- StartSync();
-
- int child_count = 0;
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
-
- FakeServerChange adds(&trans);
- std::string url("x");
- EXPECT_FALSE(GURL(url).is_valid());
- adds.AddURL("u1", url, other_bookmarks_id(), 0);
-
- adds.ApplyPendingChanges(change_processor());
-
- // We're lenient about what should happen -- the model could wind up with
- // the node or without it; but things should be consistent, and we
- // shouldn't crash.
- child_count = model()->other_node()->child_count();
- EXPECT_TRUE(child_count == 0 || child_count == 1);
- ExpectModelMatch(&trans);
- }
-
- // Now reboot the sync service, forcing a merge step.
- StopSync();
- LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE);
- StartSync();
-
- // Things ought not to have changed.
- EXPECT_EQ(model()->other_node()->child_count(), child_count);
- ExpectModelMatch();
-}
-
-// Test strings that might pose a problem if the titles ever became used as
-// file names in the sync backend.
-TEST_F(ProfileSyncServiceBookmarkTest, CornerCaseNames) {
- // TODO(ncarter): Bug 1570238 explains the failure of this test.
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
- StartSync();
-
- const char* names[] = {
- // The empty string.
- "",
- // Illegal Windows filenames.
- "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5",
- "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5",
- "LPT6", "LPT7", "LPT8", "LPT9",
- // Current/parent directory markers.
- ".", "..", "...",
- // Files created automatically by the Windows shell.
- "Thumbs.db", ".DS_Store",
- // Names including Win32-illegal characters, and path separators.
- "foo/bar", "foo\\bar", "foo?bar", "foo:bar", "foo|bar", "foo\"bar",
- "foo'bar", "foo<bar", "foo>bar", "foo%bar", "foo*bar", "foo]bar",
- "foo[bar",
- // A name with title > 255 characters
- "012345678901234567890123456789012345678901234567890123456789012345678901"
- "234567890123456789012345678901234567890123456789012345678901234567890123"
- "456789012345678901234567890123456789012345678901234567890123456789012345"
- "678901234567890123456789012345678901234567890123456789012345678901234567"
- "890123456789"};
- // Create both folders and bookmarks using each name.
- GURL url("http://www.doublemint.com");
- for (size_t i = 0; i < arraysize(names); ++i) {
- model()->AddFolder(model()->other_node(), 0, base::ASCIIToUTF16(names[i]));
- model()->AddURL(model()->other_node(), 0, base::ASCIIToUTF16(names[i]),
- url);
- }
-
- // Verify that the browser model matches the sync model.
- EXPECT_EQ(static_cast<size_t>(model()->other_node()->child_count()),
- 2 * arraysize(names));
- ExpectModelMatch();
-
- // Restart and re-associate. Verify things still match.
- StopSync();
- LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE);
- StartSync();
- EXPECT_EQ(static_cast<size_t>(model()->other_node()->child_count()),
- 2 * arraysize(names));
- ExpectModelMatch();
-}
-
-// Stress the internal representation of position by sparse numbers. We want
-// to repeatedly bisect the range of available positions, to force the
-// syncer code to renumber its ranges. Pick a number big enough so that it
-// would exhaust 32bits of room between items a couple of times.
-TEST_F(ProfileSyncServiceBookmarkTest, RepeatedMiddleInsertion) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- static const int kTimesToInsert = 256;
-
- // Create two book-end nodes to insert between.
- model()->AddFolder(model()->other_node(), 0, base::ASCIIToUTF16("Alpha"));
- model()->AddFolder(model()->other_node(), 1, base::ASCIIToUTF16("Omega"));
- int count = 2;
-
- // Test insertion in first half of range by repeatedly inserting in second
- // position.
- for (int i = 0; i < kTimesToInsert; ++i) {
- base::string16 title =
- base::ASCIIToUTF16("Pre-insertion ") + base::IntToString16(i);
- model()->AddFolder(model()->other_node(), 1, title);
- count++;
- }
-
- // Test insertion in second half of range by repeatedly inserting in
- // second-to-last position.
- for (int i = 0; i < kTimesToInsert; ++i) {
- base::string16 title =
- base::ASCIIToUTF16("Post-insertion ") + base::IntToString16(i);
- model()->AddFolder(model()->other_node(), count - 1, title);
- count++;
- }
-
- // Verify that the browser model matches the sync model.
- EXPECT_EQ(model()->other_node()->child_count(), count);
- ExpectModelMatch();
-}
-
-// Introduce a consistency violation into the model, and see that it
-// puts itself into a lame, error state.
-TEST_F(ProfileSyncServiceBookmarkTest, UnrecoverableErrorSuspendsService) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- // Add a node which will be the target of the consistency violation.
- const BookmarkNode* node =
- model()->AddFolder(model()->other_node(), 0, base::ASCIIToUTF16("node"));
- ExpectSyncerNodeMatching(node);
-
- // Now destroy the syncer node as if we were the ProfileSyncService without
- // updating the ProfileSyncService state. This should introduce
- // inconsistency between the two models.
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- syncer::WriteNode sync_node(&trans);
- ASSERT_TRUE(InitSyncNodeFromChromeNode(node, &sync_node));
- sync_node.Tombstone();
- }
- // The models don't match at this point, but the ProfileSyncService
- // doesn't know it yet.
- ExpectSyncerNodeKnown(node);
-
- mock_error_handler()->ExpectError(syncer::SyncError::DATATYPE_ERROR);
-
- // Add a child to the inconsistent node. This should cause detection of the
- // problem and the syncer should stop processing changes.
- model()->AddFolder(node, 0, base::ASCIIToUTF16("nested"));
-}
-
-// See what happens if we run model association when there are two exact URL
-// duplicate bookmarks. The BookmarkModelAssociator should not fall over when
-// this happens.
-TEST_F(ProfileSyncServiceBookmarkTest, MergeDuplicates) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
- StartSync();
-
- model()->AddURL(model()->other_node(), 0, base::ASCIIToUTF16("Dup"),
- GURL("http://dup.com/"));
- model()->AddURL(model()->other_node(), 0, base::ASCIIToUTF16("Dup"),
- GURL("http://dup.com/"));
-
- EXPECT_EQ(2, model()->other_node()->child_count());
-
- // Restart the sync service to trigger model association.
- StopSync();
- StartSync();
-
- EXPECT_EQ(2, model()->other_node()->child_count());
- ExpectModelMatch();
-}
-
-TEST_F(ProfileSyncServiceBookmarkTest, ApplySyncDeletesFromJournal) {
- // Initialize sync model and bookmark model as:
- // URL 0
- // Folder 1
- // |-- URL 1
- // +-- Folder 2
- // +-- URL 2
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
- int64_t u0 = 0;
- int64_t f1 = 0;
- int64_t u1 = 0;
- int64_t f2 = 0;
- int64_t u2 = 0;
- StartSync();
- int fixed_sync_bk_count = GetSyncBookmarkCount();
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- FakeServerChange adds(&trans);
- u0 = adds.AddURL("URL 0", "http://plus.google.com/", bookmark_bar_id(), 0);
- f1 = adds.AddFolder("Folder 1", bookmark_bar_id(), u0);
- u1 = adds.AddURL("URL 1", "http://www.google.com/", f1, 0);
- f2 = adds.AddFolder("Folder 2", f1, u1);
- u2 = adds.AddURL("URL 2", "http://mail.google.com/", f2, 0);
- adds.ApplyPendingChanges(change_processor());
- }
- StopSync();
-
- // Reload bookmark model and disable model saving to make sync changes not
- // persisted.
- LoadBookmarkModel(LOAD_FROM_STORAGE, DONT_SAVE_TO_STORAGE);
- EXPECT_EQ(6, model()->bookmark_bar_node()->GetTotalNodeCount());
- EXPECT_EQ(fixed_sync_bk_count + 5, GetSyncBookmarkCount());
- StartSync();
- {
- // Remove all folders/bookmarks except u3 added above.
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- MakeServerUpdate(&trans, f1);
- MakeServerUpdate(&trans, u1);
- MakeServerUpdate(&trans, f2);
- MakeServerUpdate(&trans, u2);
- FakeServerChange dels(&trans);
- dels.Delete(u2);
- dels.Delete(f2);
- dels.Delete(u1);
- dels.Delete(f1);
- dels.ApplyPendingChanges(change_processor());
- }
- StopSync();
- // Bookmark bar itself and u0 remain.
- EXPECT_EQ(2, model()->bookmark_bar_node()->GetTotalNodeCount());
-
- // Reload bookmarks including ones deleted in sync model from storage.
- LoadBookmarkModel(LOAD_FROM_STORAGE, DONT_SAVE_TO_STORAGE);
- EXPECT_EQ(6, model()->bookmark_bar_node()->GetTotalNodeCount());
- // Add a bookmark under f1 when sync is off so that f1 will not be
- // deleted even when f1 matches delete journal because it's not empty.
- model()->AddURL(model()->bookmark_bar_node()->GetChild(1), 0,
- base::UTF8ToUTF16("local"), GURL("http://www.youtube.com"));
- // Sync model has fixed bookmarks nodes and u3.
- EXPECT_EQ(fixed_sync_bk_count + 1, GetSyncBookmarkCount());
- StartSync();
- // Expect 4 bookmarks after model association because u2, f2, u1 are removed
- // by delete journal, f1 is not removed by delete journal because it's
- // not empty due to www.youtube.com added above.
- EXPECT_EQ(4, model()->bookmark_bar_node()->GetTotalNodeCount());
- EXPECT_EQ(base::UTF8ToUTF16("URL 0"),
- model()->bookmark_bar_node()->GetChild(0)->GetTitle());
- EXPECT_EQ(base::UTF8ToUTF16("Folder 1"),
- model()->bookmark_bar_node()->GetChild(1)->GetTitle());
- EXPECT_EQ(base::UTF8ToUTF16("local"),
- model()->bookmark_bar_node()->GetChild(1)->GetChild(0)->GetTitle());
- StopSync();
-
- // Verify purging of delete journals.
- // Delete journals for u2, f2, u1 remains because they are used in last
- // association.
- EXPECT_EQ(3u, test_user_share()->GetDeleteJournalSize());
- StartSync();
- StopSync();
- // Reload again and all delete journals should be gone because none is used
- // in last association.
- ASSERT_TRUE(test_user_share()->Reload());
- EXPECT_EQ(0u, test_user_share()->GetDeleteJournalSize());
-}
-
-struct TestData {
- const char* title;
- const char* url;
-};
-
-// Map from bookmark node ID to its version.
-typedef std::map<int64_t, int64_t> BookmarkNodeVersionMap;
-
-// TODO(ncarter): Integrate the existing TestNode/PopulateNodeFromString code
-// in the bookmark model unittest, to make it simpler to set up test data
-// here (and reduce the amount of duplication among tests), and to reduce the
-// duplication.
-class ProfileSyncServiceBookmarkTestWithData
- : public ProfileSyncServiceBookmarkTest {
- public:
- ProfileSyncServiceBookmarkTestWithData();
-
- protected:
- // Populates or compares children of the given bookmark node from/with the
- // given test data array with the given size. |running_count| is updated as
- // urls are added. It is used to set the creation date (or test the creation
- // date for CompareWithTestData()).
- void PopulateFromTestData(const BookmarkNode* node,
- const TestData* data,
- int size,
- int* running_count);
- void CompareWithTestData(const BookmarkNode* node,
- const TestData* data,
- int size,
- int* running_count);
-
- void ExpectBookmarkModelMatchesTestData();
- void WriteTestDataToBookmarkModel();
-
- // Output transaction versions of |node| and nodes under it to
- // |node_versions|.
- void GetTransactionVersions(const BookmarkNode* root,
- BookmarkNodeVersionMap* node_versions);
-
- // Verify transaction versions of bookmark nodes and sync nodes are equal
- // recursively. If node is in |version_expected|, versions should match
- // there, too.
- void ExpectTransactionVersionMatch(
- const BookmarkNode* node,
- const BookmarkNodeVersionMap& version_expected);
-
- private:
- const base::Time start_time_;
-
- DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceBookmarkTestWithData);
-};
-
-namespace {
-
-// Constants for bookmark model that looks like:
-// |-- Bookmark bar
-// | |-- u2, http://www.u2.com/
-// | |-- f1
-// | | |-- f1u4, http://www.f1u4.com/
-// | | |-- f1u2, http://www.f1u2.com/
-// | | |-- f1u3, http://www.f1u3.com/
-// | | +-- f1u1, http://www.f1u1.com/
-// | |-- u1, http://www.u1.com/
-// | +-- f2
-// | |-- f2u2, http://www.f2u2.com/
-// | |-- f2u4, http://www.f2u4.com/
-// | |-- f2u3, http://www.f2u3.com/
-// | +-- f2u1, http://www.f2u1.com/
-// +-- Other bookmarks
-// | |-- f3
-// | | |-- f3u4, http://www.f3u4.com/
-// | | |-- f3u2, http://www.f3u2.com/
-// | | |-- f3u3, http://www.f3u3.com/
-// | | +-- f3u1, http://www.f3u1.com/
-// | |-- u4, http://www.u4.com/
-// | |-- u3, http://www.u3.com/
-// | --- f4
-// | | |-- f4u1, http://www.f4u1.com/
-// | | |-- f4u2, http://www.f4u2.com/
-// | | |-- f4u3, http://www.f4u3.com/
-// | | +-- f4u4, http://www.f4u4.com/
-// | |-- dup
-// | | +-- dupu1, http://www.dupu1.com/
-// | +-- dup
-// | | +-- dupu2, http://www.dupu1.com/
-// | +-- ls , http://www.ls.com/
-// |
-// +-- Mobile bookmarks
-// |-- f5
-// | |-- f5u1, http://www.f5u1.com/
-// |-- f6
-// | |-- f6u1, http://www.f6u1.com/
-// | |-- f6u2, http://www.f6u2.com/
-// +-- u5, http://www.u5.com/
-
-static TestData kBookmarkBarChildren[] = {
- {"u2", "http://www.u2.com/"},
- {"f1", NULL},
- {"u1", "http://www.u1.com/"},
- {"f2", NULL},
-};
-static TestData kF1Children[] = {
- {"f1u4", "http://www.f1u4.com/"},
- {"f1u2", "http://www.f1u2.com/"},
- {"f1u3", "http://www.f1u3.com/"},
- {"f1u1", "http://www.f1u1.com/"},
-};
-static TestData kF2Children[] = {
- {"f2u2", "http://www.f2u2.com/"},
- {"f2u4", "http://www.f2u4.com/"},
- {"f2u3", "http://www.f2u3.com/"},
- {"f2u1", "http://www.f2u1.com/"},
-};
-
-static TestData kOtherBookmarkChildren[] = {{"f3", NULL},
- {"u4", "http://www.u4.com/"},
- {"u3", "http://www.u3.com/"},
- {"f4", NULL},
- {"dup", NULL},
- {"dup", NULL},
- {" ls ", "http://www.ls.com/"}};
-static TestData kF3Children[] = {
- {"f3u4", "http://www.f3u4.com/"},
- {"f3u2", "http://www.f3u2.com/"},
- {"f3u3", "http://www.f3u3.com/"},
- {"f3u1", "http://www.f3u1.com/"},
-};
-static TestData kF4Children[] = {
- {"f4u1", "http://www.f4u1.com/"},
- {"f4u2", "http://www.f4u2.com/"},
- {"f4u3", "http://www.f4u3.com/"},
- {"f4u4", "http://www.f4u4.com/"},
-};
-static TestData kDup1Children[] = {
- {"dupu1", "http://www.dupu1.com/"},
-};
-static TestData kDup2Children[] = {
- {"dupu2", "http://www.dupu2.com/"},
-};
-
-static TestData kMobileBookmarkChildren[] = {
- {"f5", NULL},
- {"f6", NULL},
- {"u5", "http://www.u5.com/"},
-};
-static TestData kF5Children[] = {
- {"f5u1", "http://www.f5u1.com/"},
- {"f5u2", "http://www.f5u2.com/"},
-};
-static TestData kF6Children[] = {
- {"f6u1", "http://www.f6u1.com/"},
- {"f6u2", "http://www.f6u2.com/"},
-};
-
-} // anonymous namespace.
-
-ProfileSyncServiceBookmarkTestWithData::ProfileSyncServiceBookmarkTestWithData()
- : start_time_(base::Time::Now()) {}
-
-void ProfileSyncServiceBookmarkTestWithData::PopulateFromTestData(
- const BookmarkNode* node,
- const TestData* data,
- int size,
- int* running_count) {
- DCHECK(node);
- DCHECK(data);
- DCHECK(node->is_folder());
- for (int i = 0; i < size; ++i) {
- const TestData& item = data[i];
- if (item.url) {
- const base::Time add_time =
- start_time_ + base::TimeDelta::FromMinutes(*running_count);
- model()->AddURLWithCreationTimeAndMetaInfo(
- node, i, base::UTF8ToUTF16(item.title), GURL(item.url), add_time,
- NULL);
- } else {
- model()->AddFolder(node, i, base::UTF8ToUTF16(item.title));
- }
- (*running_count)++;
- }
-}
-
-void ProfileSyncServiceBookmarkTestWithData::CompareWithTestData(
- const BookmarkNode* node,
- const TestData* data,
- int size,
- int* running_count) {
- DCHECK(node);
- DCHECK(data);
- DCHECK(node->is_folder());
- ASSERT_EQ(size, node->child_count());
- for (int i = 0; i < size; ++i) {
- const BookmarkNode* child_node = node->GetChild(i);
- const TestData& item = data[i];
- GURL url = GURL(item.url == NULL ? "" : item.url);
- BookmarkNode test_node(url);
- test_node.SetTitle(base::UTF8ToUTF16(item.title));
- EXPECT_EQ(child_node->GetTitle(), test_node.GetTitle());
- if (item.url) {
- EXPECT_FALSE(child_node->is_folder());
- EXPECT_TRUE(child_node->is_url());
- EXPECT_EQ(child_node->url(), test_node.url());
- const base::Time expected_time =
- start_time_ + base::TimeDelta::FromMinutes(*running_count);
- EXPECT_EQ(expected_time.ToInternalValue(),
- child_node->date_added().ToInternalValue());
- } else {
- EXPECT_TRUE(child_node->is_folder());
- EXPECT_FALSE(child_node->is_url());
- }
- (*running_count)++;
- }
-}
-
-// TODO(munjal): We should implement some way of generating random data and can
-// use the same seed to generate the same sequence.
-void ProfileSyncServiceBookmarkTestWithData::WriteTestDataToBookmarkModel() {
- const BookmarkNode* bookmarks_bar_node = model()->bookmark_bar_node();
- int count = 0;
- PopulateFromTestData(bookmarks_bar_node, kBookmarkBarChildren,
- arraysize(kBookmarkBarChildren), &count);
-
- ASSERT_GE(bookmarks_bar_node->child_count(), 4);
- const BookmarkNode* f1_node = bookmarks_bar_node->GetChild(1);
- PopulateFromTestData(f1_node, kF1Children, arraysize(kF1Children), &count);
- const BookmarkNode* f2_node = bookmarks_bar_node->GetChild(3);
- PopulateFromTestData(f2_node, kF2Children, arraysize(kF2Children), &count);
-
- const BookmarkNode* other_bookmarks_node = model()->other_node();
- PopulateFromTestData(other_bookmarks_node, kOtherBookmarkChildren,
- arraysize(kOtherBookmarkChildren), &count);
-
- ASSERT_GE(other_bookmarks_node->child_count(), 6);
- const BookmarkNode* f3_node = other_bookmarks_node->GetChild(0);
- PopulateFromTestData(f3_node, kF3Children, arraysize(kF3Children), &count);
- const BookmarkNode* f4_node = other_bookmarks_node->GetChild(3);
- PopulateFromTestData(f4_node, kF4Children, arraysize(kF4Children), &count);
- const BookmarkNode* dup_node = other_bookmarks_node->GetChild(4);
- PopulateFromTestData(dup_node, kDup1Children, arraysize(kDup1Children),
- &count);
- dup_node = other_bookmarks_node->GetChild(5);
- PopulateFromTestData(dup_node, kDup2Children, arraysize(kDup2Children),
- &count);
-
- const BookmarkNode* mobile_bookmarks_node = model()->mobile_node();
- PopulateFromTestData(mobile_bookmarks_node, kMobileBookmarkChildren,
- arraysize(kMobileBookmarkChildren), &count);
-
- ASSERT_GE(mobile_bookmarks_node->child_count(), 3);
- const BookmarkNode* f5_node = mobile_bookmarks_node->GetChild(0);
- PopulateFromTestData(f5_node, kF5Children, arraysize(kF5Children), &count);
- const BookmarkNode* f6_node = mobile_bookmarks_node->GetChild(1);
- PopulateFromTestData(f6_node, kF6Children, arraysize(kF6Children), &count);
-
- ExpectBookmarkModelMatchesTestData();
-}
-
-void ProfileSyncServiceBookmarkTestWithData::
- ExpectBookmarkModelMatchesTestData() {
- const BookmarkNode* bookmark_bar_node = model()->bookmark_bar_node();
- int count = 0;
- CompareWithTestData(bookmark_bar_node, kBookmarkBarChildren,
- arraysize(kBookmarkBarChildren), &count);
-
- ASSERT_GE(bookmark_bar_node->child_count(), 4);
- const BookmarkNode* f1_node = bookmark_bar_node->GetChild(1);
- CompareWithTestData(f1_node, kF1Children, arraysize(kF1Children), &count);
- const BookmarkNode* f2_node = bookmark_bar_node->GetChild(3);
- CompareWithTestData(f2_node, kF2Children, arraysize(kF2Children), &count);
-
- const BookmarkNode* other_bookmarks_node = model()->other_node();
- CompareWithTestData(other_bookmarks_node, kOtherBookmarkChildren,
- arraysize(kOtherBookmarkChildren), &count);
-
- ASSERT_GE(other_bookmarks_node->child_count(), 6);
- const BookmarkNode* f3_node = other_bookmarks_node->GetChild(0);
- CompareWithTestData(f3_node, kF3Children, arraysize(kF3Children), &count);
- const BookmarkNode* f4_node = other_bookmarks_node->GetChild(3);
- CompareWithTestData(f4_node, kF4Children, arraysize(kF4Children), &count);
- const BookmarkNode* dup_node = other_bookmarks_node->GetChild(4);
- CompareWithTestData(dup_node, kDup1Children, arraysize(kDup1Children),
- &count);
- dup_node = other_bookmarks_node->GetChild(5);
- CompareWithTestData(dup_node, kDup2Children, arraysize(kDup2Children),
- &count);
-
- const BookmarkNode* mobile_bookmarks_node = model()->mobile_node();
- CompareWithTestData(mobile_bookmarks_node, kMobileBookmarkChildren,
- arraysize(kMobileBookmarkChildren), &count);
-
- ASSERT_GE(mobile_bookmarks_node->child_count(), 3);
- const BookmarkNode* f5_node = mobile_bookmarks_node->GetChild(0);
- CompareWithTestData(f5_node, kF5Children, arraysize(kF5Children), &count);
- const BookmarkNode* f6_node = mobile_bookmarks_node->GetChild(1);
- CompareWithTestData(f6_node, kF6Children, arraysize(kF6Children), &count);
-}
-
-// Tests persistence of the profile sync service by unloading the
-// database and then reloading it from disk.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, Persistence) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
- StartSync();
-
- WriteTestDataToBookmarkModel();
-
- ExpectModelMatch();
-
- // Force both models to discard their data and reload from disk. This
- // simulates what would happen if the browser were to shutdown normally,
- // and then relaunch.
- StopSync();
- LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE);
- StartSync();
-
- ExpectBookmarkModelMatchesTestData();
-
- // With the BookmarkModel contents verified, ExpectModelMatch will
- // verify the contents of the sync model.
- ExpectModelMatch();
-}
-
-// Tests the merge case when the BookmarkModel is non-empty but the
-// sync model is empty. This corresponds to uploading browser
-// bookmarks to an initially empty, new account.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, MergeWithEmptySyncModel) {
- // Don't start the sync service until we've populated the bookmark model.
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
-
- WriteTestDataToBookmarkModel();
-
- // Restart sync. This should trigger a merge step during
- // initialization -- we expect the browser bookmarks to be written
- // to the sync service during this call.
- StartSync();
-
- // Verify that the bookmark model hasn't changed, and that the sync model
- // matches it exactly.
- ExpectBookmarkModelMatchesTestData();
- ExpectModelMatch();
-}
-
-// Tests the merge case when the BookmarkModel is empty but the sync model is
-// non-empty. This corresponds (somewhat) to a clean install of the browser,
-// with no bookmarks, connecting to a sync account that has some bookmarks.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, MergeWithEmptyBookmarkModel) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- WriteTestDataToBookmarkModel();
-
- ExpectModelMatch();
-
- // Force the databse to unload and write itself to disk.
- StopSync();
-
- // Blow away the bookmark model -- it should be empty afterwards.
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- EXPECT_EQ(model()->bookmark_bar_node()->child_count(), 0);
- EXPECT_EQ(model()->other_node()->child_count(), 0);
- EXPECT_EQ(model()->mobile_node()->child_count(), 0);
-
- // Now restart the sync service. Starting it should populate the bookmark
- // model -- test for consistency.
- StartSync();
- ExpectBookmarkModelMatchesTestData();
- ExpectModelMatch();
-}
-
-// Tests the merge cases when both the models are expected to be identical
-// after the merge.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, MergeExpectedIdenticalModels) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
- StartSync();
- WriteTestDataToBookmarkModel();
- ExpectModelMatch();
- StopSync();
-
- // At this point both the bookmark model and the server should have the
- // exact same data and it should match the test data.
- LoadBookmarkModel(LOAD_FROM_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
- ExpectBookmarkModelMatchesTestData();
- ExpectModelMatch();
- StopSync();
-
- // Now reorder some bookmarks in the bookmark model and then merge. Make
- // sure we get the order of the server after merge.
- LoadBookmarkModel(LOAD_FROM_STORAGE, DONT_SAVE_TO_STORAGE);
- ExpectBookmarkModelMatchesTestData();
- const BookmarkNode* bookmark_bar = model()->bookmark_bar_node();
- ASSERT_TRUE(bookmark_bar);
- ASSERT_GT(bookmark_bar->child_count(), 1);
- model()->Move(bookmark_bar->GetChild(0), bookmark_bar, 1);
- StartSync();
- ExpectModelMatch();
- ExpectBookmarkModelMatchesTestData();
-}
-
-// Tests the merge cases when both the models are expected to be identical
-// after the merge.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, MergeModelsWithSomeExtras) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- WriteTestDataToBookmarkModel();
- ExpectBookmarkModelMatchesTestData();
-
- // Remove some nodes and reorder some nodes.
- const BookmarkNode* bookmark_bar_node = model()->bookmark_bar_node();
- int remove_index = 2;
- ASSERT_GT(bookmark_bar_node->child_count(), remove_index);
- const BookmarkNode* child_node = bookmark_bar_node->GetChild(remove_index);
- ASSERT_TRUE(child_node);
- ASSERT_TRUE(child_node->is_url());
- model()->Remove(bookmark_bar_node->GetChild(remove_index));
- ASSERT_GT(bookmark_bar_node->child_count(), remove_index);
- child_node = bookmark_bar_node->GetChild(remove_index);
- ASSERT_TRUE(child_node);
- ASSERT_TRUE(child_node->is_folder());
- model()->Remove(bookmark_bar_node->GetChild(remove_index));
-
- const BookmarkNode* other_node = model()->other_node();
- ASSERT_GE(other_node->child_count(), 1);
- const BookmarkNode* f3_node = other_node->GetChild(0);
- ASSERT_TRUE(f3_node);
- ASSERT_TRUE(f3_node->is_folder());
- remove_index = 2;
- ASSERT_GT(f3_node->child_count(), remove_index);
- model()->Remove(f3_node->GetChild(remove_index));
- ASSERT_GT(f3_node->child_count(), remove_index);
- model()->Remove(f3_node->GetChild(remove_index));
-
- StartSync();
- ExpectModelMatch();
- StopSync();
-
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- WriteTestDataToBookmarkModel();
- ExpectBookmarkModelMatchesTestData();
-
- // Remove some nodes and reorder some nodes.
- bookmark_bar_node = model()->bookmark_bar_node();
- remove_index = 0;
- ASSERT_GT(bookmark_bar_node->child_count(), remove_index);
- child_node = bookmark_bar_node->GetChild(remove_index);
- ASSERT_TRUE(child_node);
- ASSERT_TRUE(child_node->is_url());
- model()->Remove(bookmark_bar_node->GetChild(remove_index));
- ASSERT_GT(bookmark_bar_node->child_count(), remove_index);
- child_node = bookmark_bar_node->GetChild(remove_index);
- ASSERT_TRUE(child_node);
- ASSERT_TRUE(child_node->is_folder());
- model()->Remove(bookmark_bar_node->GetChild(remove_index));
-
- ASSERT_GE(bookmark_bar_node->child_count(), 2);
- model()->Move(bookmark_bar_node->GetChild(0), bookmark_bar_node, 1);
-
- other_node = model()->other_node();
- ASSERT_GE(other_node->child_count(), 1);
- f3_node = other_node->GetChild(0);
- ASSERT_TRUE(f3_node);
- ASSERT_TRUE(f3_node->is_folder());
- remove_index = 0;
- ASSERT_GT(f3_node->child_count(), remove_index);
- model()->Remove(f3_node->GetChild(remove_index));
- ASSERT_GT(f3_node->child_count(), remove_index);
- model()->Remove(f3_node->GetChild(remove_index));
-
- ASSERT_GE(other_node->child_count(), 4);
- model()->Move(other_node->GetChild(0), other_node, 1);
- model()->Move(other_node->GetChild(2), other_node, 3);
-
- StartSync();
- ExpectModelMatch();
-
- // After the merge, the model should match the test data.
- ExpectBookmarkModelMatchesTestData();
-}
-
-// Tests that when persisted model associations are used, things work fine.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, ModelAssociationPersistence) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- WriteTestDataToBookmarkModel();
- StartSync();
- ExpectModelMatch();
- // Force sync to shut down and write itself to disk.
- StopSync();
- // Now restart sync. This time it should use the persistent
- // associations.
- StartSync();
- ExpectModelMatch();
-}
-
-// Tests that when persisted model associations are used, things work fine.
-TEST_F(ProfileSyncServiceBookmarkTestWithData,
- ModelAssociationInvalidPersistence) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- WriteTestDataToBookmarkModel();
- StartSync();
- ExpectModelMatch();
- // Force sync to shut down and write itself to disk.
- StopSync();
- // Change the bookmark model before restarting sync service to simulate
- // the situation where bookmark model is different from sync model and
- // make sure model associator correctly rebuilds associations.
- const BookmarkNode* bookmark_bar_node = model()->bookmark_bar_node();
- model()->AddURL(bookmark_bar_node, 0, base::ASCIIToUTF16("xtra"),
- GURL("http://www.xtra.com"));
- // Now restart sync. This time it will try to use the persistent
- // associations and realize that they are invalid and hence will rebuild
- // associations.
- StartSync();
- ExpectModelMatch();
-}
-
-TEST_F(ProfileSyncServiceBookmarkTestWithData, SortChildren) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- // Write test data to bookmark model and verify that the models match.
- WriteTestDataToBookmarkModel();
- const BookmarkNode* folder_added = model()->other_node()->GetChild(0);
- ASSERT_TRUE(folder_added);
- ASSERT_TRUE(folder_added->is_folder());
-
- ExpectModelMatch();
-
- // Sort the other-bookmarks children and expect that the models match.
- model()->SortChildren(folder_added);
- ExpectModelMatch();
-}
-
-// See what happens if we enable sync but then delete the "Sync Data"
-// folder.
-TEST_F(ProfileSyncServiceBookmarkTestWithData,
- RecoverAfterDeletingSyncDataDirectory) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
- StartSync();
-
- WriteTestDataToBookmarkModel();
-
- StopSync();
-
- // Nuke the sync DB and reload.
- TearDown();
- SetUp();
-
- // First attempt fails due to a persistence error.
- EXPECT_TRUE(CreatePermanentBookmarkNodes());
- EXPECT_FALSE(AssociateModels());
-
- // Second attempt succeeds due to the previous error resetting the native
- // transaction version.
- delete_model_associator();
- EXPECT_TRUE(CreatePermanentBookmarkNodes());
- EXPECT_TRUE(AssociateModels());
-
- // Make sure we're back in sync. In real life, the user would need
- // to reauthenticate before this happens, but in the test, authentication
- // is sidestepped.
- ExpectBookmarkModelMatchesTestData();
- ExpectModelMatch();
-}
-
-// Verify that the bookmark model is updated about whether the
-// associator is currently running.
-TEST_F(ProfileSyncServiceBookmarkTest, AssociationState) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
-
- ExtensiveChangesBookmarkModelObserver observer;
- model()->AddObserver(&observer);
-
- StartSync();
-
- EXPECT_EQ(1, observer.get_started());
- EXPECT_EQ(0, observer.get_completed_count_at_started());
- EXPECT_EQ(1, observer.get_completed());
-
- model()->RemoveObserver(&observer);
-}
-
-// Verify that the creation_time_us changes are applied in the local model at
-// association time and update time.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, UpdateDateAdded) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- WriteTestDataToBookmarkModel();
-
- // Start and stop sync in order to create bookmark nodes in the sync db.
- StartSync();
- StopSync();
-
- // Modify the date_added field of a bookmark so it doesn't match with
- // the sync data.
- const BookmarkNode* bookmark_bar_node = model()->bookmark_bar_node();
- int modified_index = 2;
- ASSERT_GT(bookmark_bar_node->child_count(), modified_index);
- const BookmarkNode* child_node = bookmark_bar_node->GetChild(modified_index);
- ASSERT_TRUE(child_node);
- EXPECT_TRUE(child_node->is_url());
- model()->SetDateAdded(child_node, base::Time::FromInternalValue(10));
-
- StartSync();
- StopSync();
-
- // Verify that transaction versions are in sync between the native model
- // and Sync.
- {
- syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
- int64_t sync_version = trans.GetModelVersion(syncer::BOOKMARKS);
- int64_t native_version = model()->root_node()->sync_transaction_version();
- EXPECT_EQ(native_version, sync_version);
- }
-
- // Since the version is in sync the association above should have skipped
- // updating the native node above. That is expected optimization (see
- // crbug/464907.
- EXPECT_EQ(child_node->date_added(), base::Time::FromInternalValue(10));
-
- // Reset transaction version on the native model to trigger updating data
- // for all bookmark nodes.
- model()->SetNodeSyncTransactionVersion(
- model()->root_node(), syncer::syncable::kInvalidTransactionVersion);
-
- StartSync();
-
- // Everything should be back in sync after model association.
- ExpectBookmarkModelMatchesTestData();
- ExpectModelMatch();
-
- // Now trigger a change while syncing. We add a new bookmark, sync it, then
- // updates it's creation time.
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- FakeServerChange adds(&trans);
- const std::string kTitle = "Some site";
- const std::string kUrl = "http://www.whatwhat.yeah/";
- const int kCreationTime = 30;
- int64_t id = adds.AddURL(kTitle, kUrl, bookmark_bar_id(), 0);
- adds.ApplyPendingChanges(change_processor());
- FakeServerChange updates(&trans);
- updates.ModifyCreationTime(id, kCreationTime);
- updates.ApplyPendingChanges(change_processor());
-
- const BookmarkNode* node = model()->bookmark_bar_node()->GetChild(0);
- ASSERT_TRUE(node);
- EXPECT_TRUE(node->is_url());
- EXPECT_EQ(base::UTF8ToUTF16(kTitle), node->GetTitle());
- EXPECT_EQ(kUrl, node->url().possibly_invalid_spec());
- EXPECT_EQ(node->date_added(), base::Time::FromInternalValue(30));
-}
-
-// Verifies that the transaction version in the native bookmark model gets
-// updated and synced with the sync transaction version even when the
-// association doesn't modify any sync nodes. This is necessary to ensure
-// that the native transaction doesn't get stuck at "unset" version and skips
-// any further consistency checks.
-TEST_F(ProfileSyncServiceBookmarkTestWithData,
- NativeTransactionVersionUpdated) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- WriteTestDataToBookmarkModel();
-
- // Start sync in order to create bookmark nodes in the sync db.
- StartSync();
- StopSync();
-
- // Reset transaction version on the native mode to "unset".
- model()->SetNodeSyncTransactionVersion(
- model()->root_node(), syncer::syncable::kInvalidTransactionVersion);
-
- // Restart sync.
- StartSync();
- StopSync();
-
- // Verify that the native transaction version has been updated and is now
- // in sync with the sync version.
- {
- syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
- int64_t sync_version = trans.GetModelVersion(syncer::BOOKMARKS);
- int64_t native_version = model()->root_node()->sync_transaction_version();
- EXPECT_EQ(native_version, sync_version);
- }
-}
-
-// Tests that changes to the sync nodes meta info gets reflected in the local
-// bookmark model.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, UpdateMetaInfoFromSync) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- WriteTestDataToBookmarkModel();
- StartSync();
-
- // Create bookmark nodes containing meta info.
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- FakeServerChange adds(&trans);
- BookmarkNode::MetaInfoMap folder_meta_info;
- folder_meta_info["folder"] = "foldervalue";
- int64_t folder_id = adds.AddFolderWithMetaInfo(
- "folder title", &folder_meta_info, bookmark_bar_id(), 0);
- BookmarkNode::MetaInfoMap node_meta_info;
- node_meta_info["node"] = "nodevalue";
- node_meta_info["other"] = "othervalue";
- int64_t id = adds.AddURLWithMetaInfo("node title", "http://www.foo.com",
- &node_meta_info, folder_id, 0);
- adds.ApplyPendingChanges(change_processor());
-
- // Verify that the nodes are created with the correct meta info.
- ASSERT_LT(0, model()->bookmark_bar_node()->child_count());
- const BookmarkNode* folder_node = model()->bookmark_bar_node()->GetChild(0);
- ASSERT_TRUE(folder_node->GetMetaInfoMap());
- EXPECT_EQ(folder_meta_info, *folder_node->GetMetaInfoMap());
- ASSERT_LT(0, folder_node->child_count());
- const BookmarkNode* node = folder_node->GetChild(0);
- ASSERT_TRUE(node->GetMetaInfoMap());
- EXPECT_EQ(node_meta_info, *node->GetMetaInfoMap());
-
- // Update meta info on nodes on server
- FakeServerChange updates(&trans);
- folder_meta_info.erase("folder");
- updates.ModifyMetaInfo(folder_id, folder_meta_info);
- node_meta_info["node"] = "changednodevalue";
- node_meta_info.erase("other");
- node_meta_info["newkey"] = "newkeyvalue";
- updates.ModifyMetaInfo(id, node_meta_info);
- updates.ApplyPendingChanges(change_processor());
-
- // Confirm that the updated values are reflected in the bookmark nodes.
- EXPECT_FALSE(folder_node->GetMetaInfoMap());
- ASSERT_TRUE(node->GetMetaInfoMap());
- EXPECT_EQ(node_meta_info, *node->GetMetaInfoMap());
-}
-
-// Tests that changes to the local bookmark nodes meta info gets reflected in
-// the sync nodes.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, UpdateMetaInfoFromModel) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- WriteTestDataToBookmarkModel();
- StartSync();
- ExpectBookmarkModelMatchesTestData();
-
- const BookmarkNode* folder_node = model()->AddFolder(
- model()->bookmark_bar_node(), 0, base::ASCIIToUTF16("folder title"));
- const BookmarkNode* node =
- model()->AddURL(folder_node, 0, base::ASCIIToUTF16("node title"),
- GURL("http://www.foo.com"));
- ExpectModelMatch();
-
- // Add some meta info and verify sync model matches the changes.
- model()->SetNodeMetaInfo(folder_node, "folder", "foldervalue");
- model()->SetNodeMetaInfo(node, "node", "nodevalue");
- model()->SetNodeMetaInfo(node, "other", "othervalue");
- ExpectModelMatch();
-
- // Change/delete existing meta info and verify.
- model()->DeleteNodeMetaInfo(folder_node, "folder");
- model()->SetNodeMetaInfo(node, "node", "changednodevalue");
- model()->DeleteNodeMetaInfo(node, "other");
- model()->SetNodeMetaInfo(node, "newkey", "newkeyvalue");
- ExpectModelMatch();
-}
-
-// Tests that node's specifics doesn't get unnecessarily overwritten (causing
-// a subsequent commit) when BookmarkChangeProcessor handles a notification
-// (such as BookmarkMetaInfoChanged) without an actual data change.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, MetaInfoPreservedOnNonChange) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- WriteTestDataToBookmarkModel();
- StartSync();
-
- std::string orig_specifics;
- int64_t sync_id;
- const BookmarkNode* bookmark;
-
- // Create bookmark folder node containing meta info.
- {
- syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
- FakeServerChange adds(&trans);
-
- int64_t folder_id = adds.AddFolder("folder title", bookmark_bar_id(), 0);
-
- BookmarkNode::MetaInfoMap node_meta_info;
- node_meta_info["one"] = "1";
- node_meta_info["two"] = "2";
- node_meta_info["three"] = "3";
-
- sync_id = adds.AddURLWithMetaInfo("node title", "http://www.foo.com/",
- &node_meta_info, folder_id, 0);
-
- // Verify that the node propagates to the bookmark model
- adds.ApplyPendingChanges(change_processor());
-
- bookmark = model()->bookmark_bar_node()->GetChild(0)->GetChild(0);
- EXPECT_EQ(node_meta_info, *bookmark->GetMetaInfoMap());
-
- syncer::ReadNode sync_node(&trans);
- EXPECT_EQ(BaseNode::INIT_OK, sync_node.InitByIdLookup(sync_id));
- orig_specifics = sync_node.GetBookmarkSpecifics().SerializeAsString();
- }
-
- // Force change processor to update the sync node.
- change_processor()->BookmarkMetaInfoChanged(model(), bookmark);
-
- // Read bookmark specifics again and verify that there is no change.
- {
- syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
- syncer::ReadNode sync_node(&trans);
- EXPECT_EQ(BaseNode::INIT_OK, sync_node.InitByIdLookup(sync_id));
- std::string new_specifics =
- sync_node.GetBookmarkSpecifics().SerializeAsString();
- ASSERT_EQ(orig_specifics, new_specifics);
- }
-}
-
-void ProfileSyncServiceBookmarkTestWithData::GetTransactionVersions(
- const BookmarkNode* root,
- BookmarkNodeVersionMap* node_versions) {
- node_versions->clear();
- std::queue<const BookmarkNode*> nodes;
- nodes.push(root);
- while (!nodes.empty()) {
- const BookmarkNode* n = nodes.front();
- nodes.pop();
-
- int64_t version = n->sync_transaction_version();
- EXPECT_NE(BookmarkNode::kInvalidSyncTransactionVersion, version);
-
- (*node_versions)[n->id()] = version;
- for (int i = 0; i < n->child_count(); ++i) {
- if (!CanSyncNode(n->GetChild(i)))
- continue;
- nodes.push(n->GetChild(i));
- }
- }
-}
-
-void ProfileSyncServiceBookmarkTestWithData::ExpectTransactionVersionMatch(
- const BookmarkNode* node,
- const BookmarkNodeVersionMap& version_expected) {
- syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
-
- BookmarkNodeVersionMap bnodes_versions;
- GetTransactionVersions(node, &bnodes_versions);
- for (BookmarkNodeVersionMap::const_iterator it = bnodes_versions.begin();
- it != bnodes_versions.end(); ++it) {
- syncer::ReadNode sync_node(&trans);
- ASSERT_TRUE(
- model_associator()->InitSyncNodeFromChromeId(it->first, &sync_node));
- EXPECT_EQ(sync_node.GetTransactionVersion(), it->second);
- BookmarkNodeVersionMap::const_iterator expected_ver_it =
- version_expected.find(it->first);
- if (expected_ver_it != version_expected.end())
- EXPECT_EQ(expected_ver_it->second, it->second);
- }
-}
-
-// Test transaction versions of model and nodes are incremented after changes
-// are applied.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, UpdateTransactionVersion) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
- WriteTestDataToBookmarkModel();
- base::RunLoop().RunUntilIdle();
-
- BookmarkNodeVersionMap initial_versions;
-
- // Verify transaction versions in sync model and bookmark model (saved as
- // transaction version of root node) are equal after
- // WriteTestDataToBookmarkModel() created bookmarks.
- {
- syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
- EXPECT_GT(trans.GetModelVersion(syncer::BOOKMARKS), 0);
- GetTransactionVersions(model()->root_node(), &initial_versions);
- EXPECT_EQ(trans.GetModelVersion(syncer::BOOKMARKS),
- initial_versions[model()->root_node()->id()]);
- }
- ExpectTransactionVersionMatch(model()->bookmark_bar_node(),
- BookmarkNodeVersionMap());
- ExpectTransactionVersionMatch(model()->other_node(),
- BookmarkNodeVersionMap());
- ExpectTransactionVersionMatch(model()->mobile_node(),
- BookmarkNodeVersionMap());
-
- // Verify model version is incremented and bookmark node versions remain
- // the same.
- const BookmarkNode* bookmark_bar = model()->bookmark_bar_node();
- model()->Remove(bookmark_bar->GetChild(0));
- base::RunLoop().RunUntilIdle();
- BookmarkNodeVersionMap new_versions;
- GetTransactionVersions(model()->root_node(), &new_versions);
- EXPECT_EQ(initial_versions[model()->root_node()->id()] + 1,
- new_versions[model()->root_node()->id()]);
- ExpectTransactionVersionMatch(model()->bookmark_bar_node(), initial_versions);
- ExpectTransactionVersionMatch(model()->other_node(), initial_versions);
- ExpectTransactionVersionMatch(model()->mobile_node(), initial_versions);
-
- // Verify model version and version of changed bookmark are incremented and
- // versions of others remain same.
- const BookmarkNode* changed_bookmark =
- model()->bookmark_bar_node()->GetChild(0);
- model()->SetTitle(changed_bookmark, base::ASCIIToUTF16("test"));
- base::RunLoop().RunUntilIdle();
- GetTransactionVersions(model()->root_node(), &new_versions);
- EXPECT_EQ(initial_versions[model()->root_node()->id()] + 2,
- new_versions[model()->root_node()->id()]);
- EXPECT_LT(initial_versions[changed_bookmark->id()],
- new_versions[changed_bookmark->id()]);
- initial_versions.erase(changed_bookmark->id());
- ExpectTransactionVersionMatch(model()->bookmark_bar_node(), initial_versions);
- ExpectTransactionVersionMatch(model()->other_node(), initial_versions);
- ExpectTransactionVersionMatch(model()->mobile_node(), initial_versions);
-}
-
-// Test that sync persistence errors are detected and trigger a failed
-// association.
-TEST_F(ProfileSyncServiceBookmarkTestWithData, PersistenceError) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
- WriteTestDataToBookmarkModel();
- base::RunLoop().RunUntilIdle();
-
- BookmarkNodeVersionMap initial_versions;
-
- // Verify transaction versions in sync model and bookmark model (saved as
- // transaction version of root node) are equal after
- // WriteTestDataToBookmarkModel() created bookmarks.
- {
- syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
- EXPECT_GT(trans.GetModelVersion(syncer::BOOKMARKS), 0);
- GetTransactionVersions(model()->root_node(), &initial_versions);
- EXPECT_EQ(trans.GetModelVersion(syncer::BOOKMARKS),
- initial_versions[model()->root_node()->id()]);
- }
- ExpectTransactionVersionMatch(model()->bookmark_bar_node(),
- BookmarkNodeVersionMap());
- ExpectTransactionVersionMatch(model()->other_node(),
- BookmarkNodeVersionMap());
- ExpectTransactionVersionMatch(model()->mobile_node(),
- BookmarkNodeVersionMap());
-
- // Now shut down sync and artificially increment the native model's version.
- StopSync();
- int64_t root_version = initial_versions[model()->root_node()->id()];
- model()->SetNodeSyncTransactionVersion(model()->root_node(),
- root_version + 1);
-
- // Upon association, bookmarks should fail to associate.
- EXPECT_FALSE(AssociateModels());
-}
-
-// It's possible for update/add calls from the bookmark model to be out of
-// order, or asynchronous. Handle that without triggering an error.
-TEST_F(ProfileSyncServiceBookmarkTest, UpdateThenAdd) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- EXPECT_TRUE(other_bookmarks_id());
- EXPECT_TRUE(bookmark_bar_id());
- EXPECT_TRUE(mobile_bookmarks_id());
-
- ExpectModelMatch();
-
- // Now destroy the change processor then add a bookmark, to simulate
- // missing the Update call.
- delete_change_processor();
- const BookmarkNode* node =
- model()->AddURL(model()->bookmark_bar_node(), 0,
- base::ASCIIToUTF16("title"), GURL("http://www.url.com"));
-
- // Recreate the change processor then update that bookmark. Sync should
- // receive the update call and gracefully treat that as if it were an add.
- ResetChangeProcessor();
- change_processor()->Start(test_user_share()->user_share());
- model()->SetTitle(node, base::ASCIIToUTF16("title2"));
- ExpectModelMatch();
-
- // Then simulate the add call arriving late.
- change_processor()->BookmarkNodeAdded(model(), model()->bookmark_bar_node(),
- 0);
- ExpectModelMatch();
-}
-
-// Verify operations on native nodes that shouldn't be propagated to Sync.
-TEST_F(ProfileSyncServiceBookmarkTest, TestUnsupportedNodes) {
- LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
- StartSync();
-
- // Initial number of bookmarks on the sync side.
- int sync_bookmark_count = GetSyncBookmarkCount();
-
- // Create a bookmark under managed_node() permanent folder.
- const BookmarkNode* folder = managed_bookmark_service()->managed_node();
- const BookmarkNode* node = model()->AddURL(
- folder, 0, base::ASCIIToUTF16("node"), GURL("http://www.node.com/"));
-
- // Verify that these changes are ignored by Sync.
- EXPECT_EQ(sync_bookmark_count, GetSyncBookmarkCount());
- int64_t sync_id = model_associator()->GetSyncIdFromChromeId(node->id());
- EXPECT_EQ(syncer::kInvalidId, sync_id);
-
- // Verify that Sync ignores deleting this node.
- model()->Remove(node);
- EXPECT_EQ(sync_bookmark_count, GetSyncBookmarkCount());
-}
-
-} // namespace
-
-} // namespace browser_sync
diff --git a/chromium/components/browser_sync/browser/profile_sync_service_mock.cc b/chromium/components/browser_sync/browser/profile_sync_service_mock.cc
deleted file mode 100644
index 494ba7754ca..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_service_mock.cc
+++ /dev/null
@@ -1,17 +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 "components/browser_sync/browser/profile_sync_service_mock.h"
-
-#include <utility>
-
-ProfileSyncServiceMock::ProfileSyncServiceMock(InitParams init_params)
- : ProfileSyncService(std::move(init_params)) {
- ON_CALL(*this, IsSyncRequested()).WillByDefault(testing::Return(true));
-}
-
-ProfileSyncServiceMock::ProfileSyncServiceMock(InitParams* init_params)
- : ProfileSyncServiceMock(std::move(*init_params)) {}
-
-ProfileSyncServiceMock::~ProfileSyncServiceMock() {}
diff --git a/chromium/components/browser_sync/browser/profile_sync_service_mock.h b/chromium/components/browser_sync/browser/profile_sync_service_mock.h
deleted file mode 100644
index 5985c7e5c41..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_service_mock.h
+++ /dev/null
@@ -1,102 +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 COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_SERVICE_MOCK_H_
-#define COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_SERVICE_MOCK_H_
-
-#include <string>
-#include <vector>
-
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "components/browser_sync/browser/profile_sync_service.h"
-#include "components/sync_driver/change_processor.h"
-#include "components/sync_driver/data_type_controller.h"
-#include "components/sync_driver/device_info.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/protocol/sync_protocol_error.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-class ProfileSyncServiceMock : public ProfileSyncService {
- public:
- explicit ProfileSyncServiceMock(InitParams init_params);
- // The second constructor defers to the first one. Use it when you need to
- // create a StrictMock or NiceMock of ProfileSyncServiceMock, because those
- // template classes cannot handle the input class having constructors with
- // arguments passed by value. Otherwise use the constructor above for cleaner
- // code.
- explicit ProfileSyncServiceMock(InitParams* init_params);
-
- virtual ~ProfileSyncServiceMock();
-
- MOCK_METHOD4(OnBackendInitialized,
- void(const syncer::WeakHandle<syncer::JsBackend>&,
- const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&,
- const std::string&,
- bool));
- MOCK_METHOD0(OnSyncCycleCompleted, void());
- MOCK_METHOD2(OnUserChoseDatatypes,
- void(bool sync_everything,
- syncer::ModelTypeSet chosen_types));
-
- MOCK_METHOD2(OnUnrecoverableError,
- void(const tracked_objects::Location& location,
- const std::string& message));
- MOCK_CONST_METHOD0(GetUserShare, syncer::UserShare*());
- MOCK_METHOD0(RequestStart, void());
- MOCK_METHOD1(RequestStop, void(ProfileSyncService::SyncStopDataFate));
-
- MOCK_METHOD1(AddObserver, void(sync_driver::SyncServiceObserver*));
- MOCK_METHOD1(RemoveObserver, void(sync_driver::SyncServiceObserver*));
- MOCK_METHOD0(GetJsController, base::WeakPtr<syncer::JsController>());
- MOCK_CONST_METHOD0(IsFirstSetupComplete, bool());
-
- MOCK_CONST_METHOD0(IsEncryptEverythingAllowed, bool());
- MOCK_CONST_METHOD0(IsEncryptEverythingEnabled, bool());
- MOCK_METHOD0(EnableEncryptEverything, void());
-
- MOCK_METHOD1(ChangePreferredDataTypes,
- void(syncer::ModelTypeSet preferred_types));
- MOCK_CONST_METHOD0(GetActiveDataTypes, syncer::ModelTypeSet());
- MOCK_CONST_METHOD0(GetPreferredDataTypes, syncer::ModelTypeSet());
- MOCK_CONST_METHOD0(GetRegisteredDataTypes, syncer::ModelTypeSet());
- MOCK_CONST_METHOD0(GetLastSessionSnapshot,
- syncer::sessions::SyncSessionSnapshot());
-
- MOCK_METHOD1(QueryDetailedSyncStatus,
- bool(browser_sync::SyncBackendHost::Status* result));
- MOCK_CONST_METHOD0(GetAuthError, const GoogleServiceAuthError&());
- MOCK_CONST_METHOD0(IsFirstSetupInProgress, bool());
- MOCK_CONST_METHOD0(GetLastSyncedTimeString, base::string16());
- MOCK_CONST_METHOD0(HasUnrecoverableError, bool());
- MOCK_CONST_METHOD0(IsSyncActive, bool());
- MOCK_CONST_METHOD0(IsBackendInitialized, bool());
- MOCK_CONST_METHOD0(IsSyncRequested, bool());
- MOCK_CONST_METHOD0(waiting_for_auth, bool());
- MOCK_METHOD1(OnActionableError, void(const syncer::SyncProtocolError&));
- MOCK_CONST_METHOD1(IsDataTypeControllerRunning, bool(syncer::ModelType));
-
- // DataTypeManagerObserver mocks.
- MOCK_METHOD1(OnConfigureDone,
- void(const sync_driver::DataTypeManager::ConfigureResult&));
- MOCK_METHOD0(OnConfigureStart, void());
-
- MOCK_CONST_METHOD0(CanSyncStart, bool());
- MOCK_CONST_METHOD0(IsManaged, bool());
-
- MOCK_CONST_METHOD0(IsPassphraseRequired, bool());
- MOCK_CONST_METHOD0(IsPassphraseRequiredForDecryption, bool());
- MOCK_CONST_METHOD0(IsUsingSecondaryPassphrase, bool());
- MOCK_CONST_METHOD0(GetPassphraseType, syncer::PassphraseType());
- MOCK_CONST_METHOD0(GetExplicitPassphraseTime, base::Time());
-
- MOCK_METHOD1(SetDecryptionPassphrase, bool(const std::string& passphrase));
- MOCK_METHOD2(SetEncryptionPassphrase, void(const std::string& passphrase,
- PassphraseType type));
-
- MOCK_METHOD0(OnSetupInProgressHandleDestroyed, void());
-};
-
-#endif // COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_SERVICE_MOCK_H_
diff --git a/chromium/components/browser_sync/browser/profile_sync_service_startup_unittest.cc b/chromium/components/browser_sync/browser/profile_sync_service_startup_unittest.cc
deleted file mode 100644
index b67f8e2a8b5..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_service_startup_unittest.cc
+++ /dev/null
@@ -1,485 +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 <memory>
-#include <utility>
-
-#include "base/files/file_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "components/browser_sync/browser/profile_sync_service.h"
-#include "components/browser_sync/browser/profile_sync_test_util.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "components/signin/core/common/signin_pref_names.h"
-#include "components/sync_driver/data_type_manager.h"
-#include "components/sync_driver/data_type_manager_mock.h"
-#include "components/sync_driver/fake_data_type_controller.h"
-#include "components/sync_driver/glue/sync_backend_host_mock.h"
-#include "components/sync_driver/pref_names.h"
-#include "components/sync_driver/sync_api_component_factory_mock.h"
-#include "components/sync_driver/sync_prefs.h"
-#include "components/sync_driver/sync_service_observer.h"
-#include "components/syncable_prefs/pref_service_syncable.h"
-#include "google_apis/gaia/gaia_auth_consumer.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "google_apis/gaia/oauth2_token_service.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 browser_sync::SyncBackendHostMock;
-using sync_driver::DataTypeManager;
-using sync_driver::DataTypeManagerMock;
-using testing::_;
-using testing::AnyNumber;
-using testing::DoAll;
-using testing::Mock;
-using testing::Return;
-
-namespace {
-
-const char kGaiaId[] = "12345";
-const char kEmail[] = "test_user@gmail.com";
-const char kDummyPassword[] = "";
-
-class SyncServiceObserverMock : public sync_driver::SyncServiceObserver {
- public:
- SyncServiceObserverMock();
- virtual ~SyncServiceObserverMock();
-
- MOCK_METHOD0(OnStateChanged, void());
-};
-
-SyncServiceObserverMock::SyncServiceObserverMock() {}
-
-SyncServiceObserverMock::~SyncServiceObserverMock() {}
-
-} // namespace
-
-ACTION_P(InvokeOnConfigureStart, sync_service) {
- sync_service->OnConfigureStart();
-}
-
-ACTION_P3(InvokeOnConfigureDone, sync_service, error_callback, result) {
- DataTypeManager::ConfigureResult configure_result =
- static_cast<DataTypeManager::ConfigureResult>(result);
- if (result.status == sync_driver::DataTypeManager::ABORTED)
- error_callback.Run(&configure_result);
- sync_service->OnConfigureDone(configure_result);
-}
-
-class ProfileSyncServiceStartupTest : public testing::Test {
- public:
- ProfileSyncServiceStartupTest() {
- profile_sync_service_bundle_.auth_service()
- ->set_auto_post_fetch_response_on_message_loop(true);
- }
-
- ~ProfileSyncServiceStartupTest() override {
- sync_service_->RemoveObserver(&observer_);
- sync_service_->Shutdown();
- }
-
- void CreateSyncService(
- ProfileSyncService::StartBehavior start_behavior) {
- component_factory_ = profile_sync_service_bundle_.component_factory();
- browser_sync::ProfileSyncServiceBundle::SyncClientBuilder builder(
- &profile_sync_service_bundle_);
- ProfileSyncService::InitParams init_params =
- profile_sync_service_bundle_.CreateBasicInitParams(start_behavior,
- builder.Build());
-
- sync_service_.reset(new ProfileSyncService(std::move(init_params)));
- sync_service_->RegisterDataTypeController(
- new sync_driver::FakeDataTypeController(syncer::BOOKMARKS));
- sync_service_->AddObserver(&observer_);
- }
-
- void IssueTestTokens(const std::string& account_id) {
- profile_sync_service_bundle_.auth_service()->UpdateCredentials(
- account_id, "oauth2_login_token");
- }
-
- void SetError(DataTypeManager::ConfigureResult* result) {
- sync_driver::DataTypeStatusTable::TypeErrorMap errors;
- errors[syncer::BOOKMARKS] =
- syncer::SyncError(FROM_HERE,
- syncer::SyncError::UNRECOVERABLE_ERROR,
- "Error",
- syncer::BOOKMARKS);
- result->data_type_status_table.UpdateFailedDataTypes(errors);
- }
-
- protected:
- std::string SimulateTestUserSignin(ProfileSyncService* sync_service) {
- std::string account_id =
- profile_sync_service_bundle_.account_tracker()->SeedAccountInfo(kGaiaId,
- kEmail);
- pref_service()->SetString(prefs::kGoogleServicesAccountId, account_id);
-#if !defined(OS_CHROMEOS)
- profile_sync_service_bundle_.signin_manager()->SignIn(kGaiaId, kEmail,
- kDummyPassword);
-#else
- profile_sync_service_bundle_.signin_manager()->SetAuthenticatedAccountInfo(
- kGaiaId, kEmail);
- if (sync_service)
- sync_service->GoogleSigninSucceeded(account_id, kEmail, kDummyPassword);
-#endif
- return account_id;
- }
-
- DataTypeManagerMock* SetUpDataTypeManager() {
- DataTypeManagerMock* data_type_manager = new DataTypeManagerMock();
- EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
- .WillOnce(Return(data_type_manager));
- return data_type_manager;
- }
-
- browser_sync::SyncBackendHostMock* SetUpSyncBackendHost() {
- browser_sync::SyncBackendHostMock* sync_backend_host =
- new browser_sync::SyncBackendHostMock();
- EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
- .WillOnce(Return(sync_backend_host));
- return sync_backend_host;
- }
-
- PrefService* pref_service() {
- return profile_sync_service_bundle_.pref_service();
- }
-
- base::MessageLoop message_loop_;
- browser_sync::ProfileSyncServiceBundle profile_sync_service_bundle_;
- std::unique_ptr<ProfileSyncService> sync_service_;
- SyncServiceObserverMock observer_;
- sync_driver::DataTypeStatusTable data_type_status_table_;
- SyncApiComponentFactoryMock* component_factory_ = nullptr;
-};
-
-class ProfileSyncServiceStartupCrosTest : public ProfileSyncServiceStartupTest {
- public:
- ProfileSyncServiceStartupCrosTest() {
- CreateSyncService(ProfileSyncService::AUTO_START);
- SimulateTestUserSignin(nullptr);
- EXPECT_TRUE(
- profile_sync_service_bundle_.signin_manager()->IsAuthenticated());
- }
-};
-
-TEST_F(ProfileSyncServiceStartupTest, StartFirstTime) {
- // We've never completed startup.
- pref_service()->ClearPref(sync_driver::prefs::kSyncFirstSetupComplete);
- CreateSyncService(ProfileSyncService::MANUAL_START);
- SetUpSyncBackendHost();
- DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
- EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(0);
-
- // Should not actually start, rather just clean things up and wait
- // to be enabled.
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
- sync_service_->Initialize();
-
- // Preferences should be back to defaults.
- EXPECT_EQ(0,
- pref_service()->GetInt64(sync_driver::prefs::kSyncLastSyncedTime));
- EXPECT_FALSE(
- pref_service()->GetBoolean(sync_driver::prefs::kSyncFirstSetupComplete));
- Mock::VerifyAndClearExpectations(data_type_manager);
-
- // Then start things up.
- EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(1);
- EXPECT_CALL(*data_type_manager, state()).
- WillOnce(Return(DataTypeManager::CONFIGURED)).
- WillOnce(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*data_type_manager, Stop()).Times(1);
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
-
- auto sync_blocker = sync_service_->GetSetupInProgressHandle();
-
- // Simulate successful signin as test_user.
- std::string account_id = SimulateTestUserSignin(sync_service_.get());
- // Create some tokens in the token service.
- IssueTestTokens(account_id);
-
- // Simulate the UI telling sync it has finished setting up.
- sync_blocker.reset();
- sync_service_->SetFirstSetupComplete();
- EXPECT_TRUE(sync_service_->IsSyncActive());
-}
-
-// TODO(pavely): Reenable test once android is switched to oauth2.
-TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartNoCredentials) {
- // We've never completed startup.
- pref_service()->ClearPref(sync_driver::prefs::kSyncFirstSetupComplete);
- CreateSyncService(ProfileSyncService::MANUAL_START);
-
- // Should not actually start, rather just clean things up and wait
- // to be enabled.
- EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
- .Times(0);
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
- sync_service_->Initialize();
-
- // Preferences should be back to defaults.
- EXPECT_EQ(0,
- pref_service()->GetInt64(sync_driver::prefs::kSyncLastSyncedTime));
- EXPECT_FALSE(
- pref_service()->GetBoolean(sync_driver::prefs::kSyncFirstSetupComplete));
-
- // Then start things up.
- auto sync_blocker = sync_service_->GetSetupInProgressHandle();
-
- // Simulate successful signin as test_user.
- std::string account_id = SimulateTestUserSignin(sync_service_.get());
-
- profile_sync_service_bundle_.auth_service()->LoadCredentials(account_id);
-
- sync_blocker.reset();
- // ProfileSyncService should try to start by requesting access token.
- // This request should fail as login token was not issued.
- EXPECT_FALSE(sync_service_->IsSyncActive());
- EXPECT_EQ(GoogleServiceAuthError::USER_NOT_SIGNED_UP,
- sync_service_->GetAuthError().state());
-}
-
-// TODO(pavely): Reenable test once android is switched to oauth2.
-TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartInvalidCredentials) {
- CreateSyncService(ProfileSyncService::MANUAL_START);
- std::string account_id = SimulateTestUserSignin(sync_service_.get());
- SyncBackendHostMock* mock_sbh = SetUpSyncBackendHost();
-
- // Tell the backend to stall while downloading control types (simulating an
- // auth error).
- mock_sbh->set_fail_initial_download(true);
-
- DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
- EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(0);
-
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
- sync_service_->Initialize();
- EXPECT_FALSE(sync_service_->IsSyncActive());
- Mock::VerifyAndClearExpectations(data_type_manager);
-
- // Update the credentials, unstalling the backend.
- EXPECT_CALL(*data_type_manager, Configure(_, _));
- EXPECT_CALL(*data_type_manager, state()).
- WillRepeatedly(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*data_type_manager, Stop()).Times(1);
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
- auto sync_blocker = sync_service_->GetSetupInProgressHandle();
-
- // Simulate successful signin.
- SimulateTestUserSignin(sync_service_.get());
-
- sync_blocker.reset();
-
- // Verify we successfully finish startup and configuration.
- EXPECT_TRUE(sync_service_->IsSyncActive());
-}
-
-TEST_F(ProfileSyncServiceStartupCrosTest, StartCrosNoCredentials) {
- EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
- .Times(0);
- EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _)).Times(0);
- pref_service()->ClearPref(sync_driver::prefs::kSyncFirstSetupComplete);
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
-
- sync_service_->Initialize();
- // Sync should not start because there are no tokens yet.
- EXPECT_FALSE(sync_service_->IsSyncActive());
- sync_service_->SetFirstSetupComplete();
-
- // Sync should not start because there are still no tokens.
- EXPECT_FALSE(sync_service_->IsSyncActive());
-}
-
-TEST_F(ProfileSyncServiceStartupCrosTest, StartFirstTime) {
- SetUpSyncBackendHost();
- DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
- pref_service()->ClearPref(sync_driver::prefs::kSyncFirstSetupComplete);
- EXPECT_CALL(*data_type_manager, Configure(_, _));
- EXPECT_CALL(*data_type_manager, state()).
- WillRepeatedly(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*data_type_manager, Stop());
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
-
- IssueTestTokens(
- profile_sync_service_bundle_.account_tracker()->PickAccountIdForAccount(
- "12345", kEmail));
- sync_service_->Initialize();
- EXPECT_TRUE(sync_service_->IsSyncActive());
-}
-
-TEST_F(ProfileSyncServiceStartupTest, StartNormal) {
- // Pre load the tokens
- CreateSyncService(ProfileSyncService::MANUAL_START);
- std::string account_id = SimulateTestUserSignin(sync_service_.get());
- sync_service_->SetFirstSetupComplete();
- SetUpSyncBackendHost();
- DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
- EXPECT_CALL(*data_type_manager, Configure(_, _));
- EXPECT_CALL(*data_type_manager, state()).
- WillRepeatedly(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*data_type_manager, Stop()).Times(1);
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
-
- IssueTestTokens(account_id);
-
- sync_service_->Initialize();
-}
-
-// Test that we can recover from a case where a bug in the code resulted in
-// OnUserChoseDatatypes not being properly called and datatype preferences
-// therefore being left unset.
-TEST_F(ProfileSyncServiceStartupTest, StartRecoverDatatypePrefs) {
- // Clear the datatype preference fields (simulating bug 154940).
- pref_service()->ClearPref(sync_driver::prefs::kSyncKeepEverythingSynced);
- syncer::ModelTypeSet user_types = syncer::UserTypes();
- for (syncer::ModelTypeSet::Iterator iter = user_types.First();
- iter.Good(); iter.Inc()) {
- pref_service()->ClearPref(
- sync_driver::SyncPrefs::GetPrefNameForDataType(iter.Get()));
- }
-
- // Pre load the tokens
- CreateSyncService(ProfileSyncService::MANUAL_START);
- std::string account_id = SimulateTestUserSignin(sync_service_.get());
- sync_service_->SetFirstSetupComplete();
- SetUpSyncBackendHost();
- DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
- EXPECT_CALL(*data_type_manager, Configure(_, _));
- EXPECT_CALL(*data_type_manager, state()).
- WillRepeatedly(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*data_type_manager, Stop()).Times(1);
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
-
- IssueTestTokens(account_id);
- sync_service_->Initialize();
-
- EXPECT_TRUE(pref_service()->GetBoolean(
- sync_driver::prefs::kSyncKeepEverythingSynced));
-}
-
-// Verify that the recovery of datatype preferences doesn't overwrite a valid
-// case where only bookmarks are enabled.
-TEST_F(ProfileSyncServiceStartupTest, StartDontRecoverDatatypePrefs) {
- // Explicitly set Keep Everything Synced to false and have only bookmarks
- // enabled.
- pref_service()->SetBoolean(sync_driver::prefs::kSyncKeepEverythingSynced,
- false);
-
- // Pre load the tokens
- CreateSyncService(ProfileSyncService::MANUAL_START);
- std::string account_id = SimulateTestUserSignin(sync_service_.get());
- sync_service_->SetFirstSetupComplete();
- SetUpSyncBackendHost();
- DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
- EXPECT_CALL(*data_type_manager, Configure(_, _));
- EXPECT_CALL(*data_type_manager, state()).
- WillRepeatedly(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*data_type_manager, Stop()).Times(1);
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
- IssueTestTokens(account_id);
- sync_service_->Initialize();
-
- EXPECT_FALSE(pref_service()->GetBoolean(
- sync_driver::prefs::kSyncKeepEverythingSynced));
-}
-
-TEST_F(ProfileSyncServiceStartupTest, ManagedStartup) {
- // Service should not be started by Initialize() since it's managed.
- pref_service()->SetString(prefs::kGoogleServicesAccountId, kEmail);
- CreateSyncService(ProfileSyncService::MANUAL_START);
-
- // Disable sync through policy.
- pref_service()->SetBoolean(sync_driver::prefs::kSyncManaged, true);
- EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
- .Times(0);
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
-
- sync_service_->Initialize();
-}
-
-TEST_F(ProfileSyncServiceStartupTest, SwitchManaged) {
- CreateSyncService(ProfileSyncService::MANUAL_START);
- std::string account_id = SimulateTestUserSignin(sync_service_.get());
- sync_service_->SetFirstSetupComplete();
- SetUpSyncBackendHost();
- DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
- EXPECT_CALL(*data_type_manager, Configure(_, _));
- EXPECT_CALL(*data_type_manager, state())
- .WillRepeatedly(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
- IssueTestTokens(account_id);
- sync_service_->Initialize();
- EXPECT_TRUE(sync_service_->IsBackendInitialized());
- EXPECT_TRUE(sync_service_->IsSyncActive());
-
- // The service should stop when switching to managed mode.
- Mock::VerifyAndClearExpectations(data_type_manager);
- EXPECT_CALL(*data_type_manager, state()).
- WillOnce(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*data_type_manager, Stop()).Times(1);
- pref_service()->SetBoolean(sync_driver::prefs::kSyncManaged, true);
- EXPECT_FALSE(sync_service_->IsBackendInitialized());
- // Note that PSS no longer references |data_type_manager| after stopping.
-
- // When switching back to unmanaged, the state should change but sync should
- // not start automatically because IsFirstSetupComplete() will be false.
- // A new DataTypeManager should not be created.
- Mock::VerifyAndClearExpectations(data_type_manager);
- EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
- .Times(0);
- pref_service()->ClearPref(sync_driver::prefs::kSyncManaged);
- EXPECT_FALSE(sync_service_->IsBackendInitialized());
- EXPECT_FALSE(sync_service_->IsSyncActive());
-}
-
-TEST_F(ProfileSyncServiceStartupTest, StartFailure) {
- CreateSyncService(ProfileSyncService::MANUAL_START);
- std::string account_id = SimulateTestUserSignin(sync_service_.get());
- sync_service_->SetFirstSetupComplete();
- SetUpSyncBackendHost();
- DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
- DataTypeManager::ConfigureStatus status = DataTypeManager::ABORTED;
- DataTypeManager::ConfigureResult result(
- status,
- syncer::ModelTypeSet());
- EXPECT_CALL(*data_type_manager, Configure(_, _))
- .WillRepeatedly(
- DoAll(InvokeOnConfigureStart(sync_service_.get()),
- InvokeOnConfigureDone(
- sync_service_.get(),
- base::Bind(&ProfileSyncServiceStartupTest::SetError,
- base::Unretained(this)),
- result)));
- EXPECT_CALL(*data_type_manager, state()).
- WillOnce(Return(DataTypeManager::STOPPED));
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
- IssueTestTokens(account_id);
- sync_service_->Initialize();
- EXPECT_TRUE(sync_service_->HasUnrecoverableError());
-}
-
-TEST_F(ProfileSyncServiceStartupTest, StartDownloadFailed) {
- // Pre load the tokens
- CreateSyncService(ProfileSyncService::MANUAL_START);
- std::string account_id = SimulateTestUserSignin(sync_service_.get());
- SyncBackendHostMock* mock_sbh = SetUpSyncBackendHost();
- mock_sbh->set_fail_initial_download(true);
-
- pref_service()->ClearPref(sync_driver::prefs::kSyncFirstSetupComplete);
-
- EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
- sync_service_->Initialize();
-
- auto sync_blocker = sync_service_->GetSetupInProgressHandle();
- IssueTestTokens(account_id);
- sync_blocker.reset();
- EXPECT_FALSE(sync_service_->IsSyncActive());
-}
diff --git a/chromium/components/browser_sync/browser/profile_sync_service_typed_url_unittest.cc b/chromium/components/browser_sync/browser/profile_sync_service_typed_url_unittest.cc
deleted file mode 100644
index e77507b297a..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_service_typed_url_unittest.cc
+++ /dev/null
@@ -1,1089 +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 <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/run_loop.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/browser_sync/browser/abstract_profile_sync_service_test.h"
-#include "components/browser_sync/browser/test_profile_sync_service.h"
-#include "components/history/core/browser/history_backend.h"
-#include "components/history/core/browser/history_backend_client.h"
-#include "components/history/core/browser/history_backend_notifier.h"
-#include "components/history/core/browser/history_db_task.h"
-#include "components/history/core/browser/history_service.h"
-#include "components/history/core/browser/typed_url_data_type_controller.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "components/sync_driver/data_type_manager_impl.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/test/data_type_error_handler_mock.h"
-#include "sync/internal_api/public/write_node.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/protocol/typed_url_specifics.pb.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using browser_sync::TypedUrlDataTypeController;
-using history::HistoryBackend;
-using history::HistoryBackendNotifier;
-using history::TypedUrlSyncableService;
-using testing::DoAll;
-using testing::Return;
-using testing::SetArgumentPointee;
-using testing::_;
-
-namespace {
-
-const char kDummySavingBrowserHistoryDisabled[] = "dummyPref";
-
-// Visits with this timestamp are treated as expired.
-static const int EXPIRED_VISIT = -1;
-
-ACTION(ReturnNewDataTypeManager) {
- return new sync_driver::DataTypeManagerImpl(arg0, arg1, arg2, arg3, arg4);
-}
-
-class HistoryBackendMock : public HistoryBackend {
- public:
- HistoryBackendMock()
- : HistoryBackend(nullptr, nullptr, base::ThreadTaskRunnerHandle::Get()) {}
- bool IsExpiredVisitTime(const base::Time& time) override {
- return time.ToInternalValue() == EXPIRED_VISIT;
- }
- MOCK_METHOD1(GetAllTypedURLs, bool(history::URLRows* entries));
- MOCK_METHOD3(GetMostRecentVisitsForURL, bool(history::URLID id,
- int max_visits,
- history::VisitVector* visits));
- MOCK_METHOD2(UpdateURL, bool(history::URLID id, const history::URLRow& url));
- MOCK_METHOD3(AddVisits, bool(const GURL& url,
- const std::vector<history::VisitInfo>& visits,
- history::VisitSource visit_source));
- MOCK_METHOD2(GetURL, bool(const GURL& url_id, history::URLRow* url_row));
- MOCK_METHOD2(SetPageTitle, void(const GURL& url,
- const base::string16& title));
- MOCK_METHOD1(DeleteURL, void(const GURL& url));
-
- private:
- friend class ProfileSyncServiceTypedUrlTest;
-
- virtual ~HistoryBackendMock() {}
-};
-
-class HistoryServiceMock : public history::HistoryService {
- public:
- HistoryServiceMock() : history::HistoryService(), backend_(nullptr) {}
-
- base::CancelableTaskTracker::TaskId ScheduleDBTask(
- std::unique_ptr<history::HistoryDBTask> task,
- base::CancelableTaskTracker* tracker) override {
- // Explicitly copy out the raw pointer -- compilers might decide to
- // evaluate task.release() before the arguments for the first Bind().
- history::HistoryDBTask* task_raw = task.get();
- task_runner_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&HistoryServiceMock::RunTaskOnDBThread,
- base::Unretained(this), task_raw),
- base::Bind(&base::DeletePointer<history::HistoryDBTask>,
- task.release()));
- return base::CancelableTaskTracker::kBadTaskId; // unused
- }
-
- ~HistoryServiceMock() override {}
-
- void set_task_runner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- DCHECK(task_runner.get());
- task_runner_ = task_runner;
- }
-
- void set_backend(scoped_refptr<history::HistoryBackend> backend) {
- backend_ = backend;
- }
-
- private:
- void RunTaskOnDBThread(history::HistoryDBTask* task) {
- EXPECT_TRUE(task->RunOnDBThread(backend_.get(), NULL));
- }
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- scoped_refptr<history::HistoryBackend> backend_;
-};
-
-class TestTypedUrlSyncableService : public TypedUrlSyncableService {
- // TODO(gangwu): remove TestProfileSyncService or even remove whole test
- // suite, and make sure typed_url_syncable_service_unittest.cc and the various
- // typed url integration tests.
- public:
- explicit TestTypedUrlSyncableService(history::HistoryBackend* history_backend)
- : TypedUrlSyncableService(history_backend) {}
-
- static void WriteToSyncNode(const history::URLRow& url,
- const history::VisitVector& visits,
- syncer::WriteNode* node) {
- sync_pb::TypedUrlSpecifics typed_url;
- WriteToTypedUrlSpecifics(url, visits, &typed_url);
- node->SetTypedUrlSpecifics(typed_url);
- }
-
- protected:
- // Don't clear error stats - that way we can verify their values in our
- // tests.
- void ClearErrorStats() override {}
-};
-
-class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
- public:
- void AddTypedUrlSyncNode(const history::URLRow& url,
- const history::VisitVector& visits) {
- syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare());
-
- syncer::WriteNode node(&trans);
- std::string tag = url.url().spec();
- syncer::WriteNode::InitUniqueByCreationResult result =
- node.InitUniqueByCreation(syncer::TYPED_URLS, tag);
- ASSERT_EQ(syncer::WriteNode::INIT_SUCCESS, result);
- TestTypedUrlSyncableService::WriteToSyncNode(url, visits, &node);
- }
-
- protected:
- ProfileSyncServiceTypedUrlTest() {
- profile_sync_service_bundle()
- ->pref_service()
- ->registry()
- ->RegisterBooleanPref(kDummySavingBrowserHistoryDisabled, false);
-
- data_type_thread()->Start();
- base::RunLoop run_loop;
- data_type_thread()->task_runner()->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&ProfileSyncServiceTypedUrlTest::CreateHistoryService,
- base::Unretained(this)),
- run_loop.QuitClosure());
- run_loop.Run();
- history_service_ = base::WrapUnique(new HistoryServiceMock);
- history_service_->set_task_runner(data_type_thread()->task_runner());
- history_service_->set_backend(history_backend_);
-
- browser_sync::ProfileSyncServiceBundle::SyncClientBuilder builder(
- profile_sync_service_bundle());
- builder.SetHistoryService(history_service_.get());
- builder.SetSyncServiceCallback(GetSyncServiceCallback());
- builder.SetSyncableServiceCallback(
- base::Bind(&ProfileSyncServiceTypedUrlTest::GetSyncableServiceForType,
- base::Unretained(this)));
- builder.set_activate_model_creation();
- sync_client_ = builder.Build();
- }
-
- void CreateHistoryService() {
- history_backend_ = new HistoryBackendMock();
- syncable_service_ = base::WrapUnique(
- new TestTypedUrlSyncableService(history_backend_.get()));
- }
-
- void DeleteSyncableService() {
- syncable_service_.reset();
- history_backend_ = nullptr;
- }
-
- ~ProfileSyncServiceTypedUrlTest() override {
- history_service_->Shutdown();
-
- // Request stop to get deletion tasks related to the HistoryService posted
- // on the Sync thread. It is important to not Shutdown at this moment,
- // because after shutdown the Sync thread is not returned to the sync
- // service, so we could not get the thread's message loop to wait for the
- // deletions to be finished.
- sync_service()->RequestStop(sync_driver::SyncService::CLEAR_DATA);
- // Spin the sync thread.
- {
- base::RunLoop run_loop;
- sync_service()->GetSyncLoopForTest()->task_runner()->PostTaskAndReply(
- FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure());
- run_loop.Run();
- }
-
- // Spin the loop again for deletion tasks posted from the Sync thread.
- base::RunLoop().RunUntilIdle();
-
- {
- base::RunLoop run_loop;
- data_type_thread()->task_runner()->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&ProfileSyncServiceTypedUrlTest::DeleteSyncableService,
- base::Unretained(this)),
- run_loop.QuitClosure());
- run_loop.Run();
- }
- }
-
- TypedUrlSyncableService* StartSyncService(const base::Closure& callback) {
- if (!sync_service()) {
- std::string account_id =
- profile_sync_service_bundle()->account_tracker()->SeedAccountInfo(
- "gaia_id", "test");
- SigninManagerBase* signin =
- profile_sync_service_bundle()->signin_manager();
- signin->SetAuthenticatedAccountInfo("gaia_id", "test");
- CreateSyncService(std::move(sync_client_), callback);
- data_type_controller = new TypedUrlDataTypeController(
- base::ThreadTaskRunnerHandle::Get(), base::Bind(&base::DoNothing),
- sync_service()->GetSyncClient(), kDummySavingBrowserHistoryDisabled);
- EXPECT_CALL(*profile_sync_service_bundle()->component_factory(),
- CreateDataTypeManager(_, _, _, _, _))
- .WillOnce(ReturnNewDataTypeManager());
-
- profile_sync_service_bundle()->auth_service()->UpdateCredentials(
- account_id, "oauth2_login_token");
-
- sync_service()->RegisterDataTypeController(data_type_controller);
-
- sync_service()->Initialize();
- base::RunLoop().Run();
- }
- return syncable_service_.get();
- }
-
- void GetTypedUrlsFromSyncDB(history::URLRows* urls) {
- urls->clear();
- syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
- syncer::ReadNode typed_url_root(&trans);
- if (typed_url_root.InitTypeRoot(syncer::TYPED_URLS) !=
- syncer::BaseNode::INIT_OK)
- return;
-
- int64_t child_id = typed_url_root.GetFirstChildId();
- while (child_id != syncer::kInvalidId) {
- syncer::ReadNode child_node(&trans);
- if (child_node.InitByIdLookup(child_id) != syncer::BaseNode::INIT_OK)
- return;
-
- const sync_pb::TypedUrlSpecifics& typed_url(
- child_node.GetTypedUrlSpecifics());
- history::URLRow new_url(GURL(typed_url.url()));
-
- new_url.set_title(base::UTF8ToUTF16(typed_url.title()));
- DCHECK(typed_url.visits_size());
- DCHECK_EQ(typed_url.visits_size(), typed_url.visit_transitions_size());
- new_url.set_last_visit(base::Time::FromInternalValue(
- typed_url.visits(typed_url.visits_size() - 1)));
- new_url.set_hidden(typed_url.hidden());
-
- urls->push_back(new_url);
- child_id = child_node.GetSuccessorId();
- }
- }
-
- void SetIdleChangeProcessorExpectations() {
- EXPECT_CALL((history_backend()), SetPageTitle(_, _)).Times(0);
- EXPECT_CALL((history_backend()), UpdateURL(_, _)).Times(0);
- EXPECT_CALL((history_backend()), GetURL(_, _)).Times(0);
- EXPECT_CALL((history_backend()), DeleteURL(_)).Times(0);
- }
-
- void SendNotification(const base::Closure& task) {
- data_type_thread()->task_runner()->PostTaskAndReply(
- FROM_HERE, task,
- base::Bind(&base::MessageLoop::QuitNow,
- base::Unretained(base::MessageLoop::current())));
- base::RunLoop().Run();
- }
-
- void SendNotificationURLVisited(ui::PageTransition transition,
- const history::URLRow& row) {
- base::Time visit_time;
- history::RedirectList redirects;
- SendNotification(
- base::Bind(&HistoryBackendNotifier::NotifyURLVisited,
- base::Unretained(history_backend_.get()),
- transition,
- row,
- redirects,
- visit_time));
- }
-
- void SendNotificationURLsModified(const history::URLRows& rows) {
- SendNotification(base::Bind(&HistoryBackendNotifier::NotifyURLsModified,
- base::Unretained(history_backend_.get()),
- rows));
- }
-
- void SendNotificationURLsDeleted(bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
- SendNotification(base::Bind(&HistoryBackendNotifier::NotifyURLsDeleted,
- base::Unretained(history_backend_.get()),
- all_history, expired, deleted_rows,
- favicon_urls));
- }
-
- static bool URLsEqual(const history::URLRow& lhs,
- const history::URLRow& rhs) {
- // Only verify the fields we explicitly sync (i.e. don't verify typed_count
- // or visit_count because we rely on the history DB to manage those values
- // and they are left unchanged by HistoryBackendMock).
- return (lhs.url().spec().compare(rhs.url().spec()) == 0) &&
- (lhs.title().compare(rhs.title()) == 0) &&
- (lhs.last_visit() == rhs.last_visit()) &&
- (lhs.hidden() == rhs.hidden());
- }
-
- static history::URLRow MakeTypedUrlEntry(const char* url,
- const char* title,
- int typed_count,
- int64_t last_visit,
- bool hidden,
- history::VisitVector* visits) {
- // Give each URL a unique ID, to mimic the behavior of the real database.
- static int unique_url_id = 0;
- GURL gurl(url);
- history::URLRow history_url(gurl, ++unique_url_id);
- history_url.set_title(base::UTF8ToUTF16(title));
- history_url.set_typed_count(typed_count);
- history_url.set_last_visit(
- base::Time::FromInternalValue(last_visit));
- history_url.set_hidden(hidden);
- visits->push_back(history::VisitRow(
- history_url.id(), history_url.last_visit(), 0,
- ui::PAGE_TRANSITION_TYPED, 0));
- history_url.set_visit_count(visits->size());
- return history_url;
- }
-
- base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
- syncer::ModelType type) {
- DCHECK_EQ(syncer::TYPED_URLS, type);
- return syncable_service_->AsWeakPtr();
- }
-
- HistoryBackendMock& history_backend() { return *history_backend_.get(); }
-
- private:
- scoped_refptr<HistoryBackendMock> history_backend_;
- std::unique_ptr<HistoryServiceMock> history_service_;
- syncer::DataTypeErrorHandlerMock error_handler_;
- TypedUrlDataTypeController* data_type_controller;
- std::unique_ptr<TestTypedUrlSyncableService> syncable_service_;
- std::unique_ptr<sync_driver::FakeSyncClient> sync_client_;
-
- DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceTypedUrlTest);
-};
-
-void AddTypedUrlEntries(ProfileSyncServiceTypedUrlTest* test,
- const history::URLRows& entries) {
- test->CreateRoot(syncer::TYPED_URLS);
- for (size_t i = 0; i < entries.size(); ++i) {
- history::VisitVector visits;
- visits.push_back(history::VisitRow(
- entries[i].id(), entries[i].last_visit(), 0,
- ui::PageTransitionFromInt(0), 0));
- test->AddTypedUrlSyncNode(entries[i], visits);
- }
-}
-
-} // namespace
-
-TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeEmptySync) {
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true));
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- TypedUrlSyncableService* syncable_service =
- StartSyncService(create_root.callback());
- history::URLRows sync_entries;
- GetTypedUrlsFromSyncDB(&sync_entries);
- EXPECT_EQ(0U, sync_entries.size());
- ASSERT_EQ(0, syncable_service->GetErrorPercentage());
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeEmptySync) {
- history::URLRows entries;
- history::VisitVector visits;
- entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar",
- 2, 15, false, &visits));
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true)));
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- TypedUrlSyncableService* syncable_service =
- StartSyncService(create_root.callback());
- history::URLRows sync_entries;
- GetTypedUrlsFromSyncDB(&sync_entries);
- ASSERT_EQ(1U, sync_entries.size());
- EXPECT_TRUE(URLsEqual(entries[0], sync_entries[0]));
- ASSERT_EQ(0, syncable_service->GetErrorPercentage());
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeErrorReadingVisits) {
- history::URLRows entries;
- history::VisitVector visits;
- history::URLRow native_entry1(MakeTypedUrlEntry("http://foo.com", "bar",
- 2, 15, false, &visits));
- history::URLRow native_entry2(MakeTypedUrlEntry("http://foo2.com", "bar",
- 3, 15, false, &visits));
- entries.push_back(native_entry1);
- entries.push_back(native_entry2);
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
- // Return an error from GetMostRecentVisitsForURL() for the second URL.
- EXPECT_CALL((history_backend()),
- GetMostRecentVisitsForURL(native_entry1.id(), _, _))
- .WillRepeatedly(Return(true));
- EXPECT_CALL((history_backend()),
- GetMostRecentVisitsForURL(native_entry2.id(), _, _))
- .WillRepeatedly(Return(false));
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
- history::URLRows sync_entries;
- GetTypedUrlsFromSyncDB(&sync_entries);
- ASSERT_EQ(1U, sync_entries.size());
- EXPECT_TRUE(URLsEqual(native_entry1, sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithBlankEmptySync) {
- std::vector<history::URLRow> entries;
- history::VisitVector visits;
- // Add an empty URL.
- entries.push_back(MakeTypedUrlEntry("", "bar",
- 2, 15, false, &visits));
- entries.push_back(MakeTypedUrlEntry("http://foo.com", "bar",
- 2, 15, false, &visits));
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true)));
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
- std::vector<history::URLRow> sync_entries;
- GetTypedUrlsFromSyncDB(&sync_entries);
- // The empty URL should be ignored.
- ASSERT_EQ(1U, sync_entries.size());
- EXPECT_TRUE(URLsEqual(entries[1], sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncNoMerge) {
- history::VisitVector native_visits;
- history::VisitVector sync_visits;
- history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
- 2, 15, false, &native_visits));
- history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
- 3, 16, false, &sync_visits));
-
- history::URLRows native_entries;
- native_entries.push_back(native_entry);
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
- EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED))
- .WillRepeatedly(Return(true));
-
- history::URLRows sync_entries;
- sync_entries.push_back(sync_entry);
-
- EXPECT_CALL((history_backend()), UpdateURL(_, _))
- .WillRepeatedly(Return(true));
- StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
-
- std::map<std::string, history::URLRow> expected;
- expected[native_entry.url().spec()] = native_entry;
- expected[sync_entry.url().spec()] = sync_entry;
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
-
- EXPECT_TRUE(new_sync_entries.size() == expected.size());
- for (history::URLRows::iterator entry = new_sync_entries.begin();
- entry != new_sync_entries.end(); ++entry) {
- EXPECT_TRUE(URLsEqual(expected[entry->url().spec()], *entry));
- }
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeExpiredSync) {
- history::VisitVector sync_visits;
- history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
- 3, EXPIRED_VISIT, false,
- &sync_visits));
- history::URLRows sync_entries;
- sync_entries.push_back(sync_entry);
-
- // Since all our URLs are expired, no backend calls to add new URLs will be
- // made.
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true));
- SetIdleChangeProcessorExpectations();
-
- StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncMerge) {
- history::VisitVector native_visits;
- history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
- 2, 15, false, &native_visits));
- history::VisitVector sync_visits;
- history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "name",
- 1, 17, false, &sync_visits));
- history::VisitVector merged_visits;
- merged_visits.push_back(history::VisitRow(
- sync_entry.id(), base::Time::FromInternalValue(15), 0,
- ui::PageTransitionFromInt(0), 0));
-
- history::URLRow merged_entry(MakeTypedUrlEntry("http://native.com", "name",
- 2, 17, false, &merged_visits));
-
- history::URLRows native_entries;
- native_entries.push_back(native_entry);
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
- EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED))
- .WillRepeatedly(Return(true));
-
- history::URLRows sync_entries;
- sync_entries.push_back(sync_entry);
-
- EXPECT_CALL((history_backend()), UpdateURL(_, _))
- .WillRepeatedly(Return(true));
- EXPECT_CALL((history_backend()), SetPageTitle(_, _)).WillRepeatedly(Return());
- StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(merged_entry, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithErrorHasSyncMerge) {
- history::VisitVector native_visits;
- history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "native",
- 2, 15, false, &native_visits));
- history::VisitVector sync_visits;
- history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "sync",
- 1, 17, false, &sync_visits));
-
- history::URLRows native_entries;
- native_entries.push_back(native_entry);
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
- // Return an error getting the visits for the native URL.
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL((history_backend()), GetURL(_, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<1>(native_entry), Return(true)));
- EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED))
- .WillRepeatedly(Return(true));
-
- history::URLRows sync_entries;
- sync_entries.push_back(sync_entry);
-
- EXPECT_CALL((history_backend()), UpdateURL(_, _))
- .WillRepeatedly(Return(true));
- EXPECT_CALL((history_backend()), SetPageTitle(_, _)).WillRepeatedly(Return());
- StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(sync_entry, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAdd) {
- history::VisitVector added_visits;
- history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
- 2, 15, false, &added_visits));
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
-
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- history::URLRows changed_urls;
- changed_urls.push_back(added_entry);
- SendNotificationURLsModified(changed_urls);
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddWithBlank) {
- history::VisitVector added_visits;
- history::URLRow empty_entry(MakeTypedUrlEntry("", "entry",
- 2, 15, false, &added_visits));
- history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
- 2, 15, false, &added_visits));
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
-
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- history::URLRows changed_urls;
- changed_urls.push_back(empty_entry);
- changed_urls.push_back(added_entry);
- SendNotificationURLsModified(changed_urls);
-
- std::vector<history::URLRow> new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdate) {
- history::VisitVector original_visits;
- history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
- 2, 15, false,
- &original_visits));
- history::URLRows original_entries;
- original_entries.push_back(original_entry);
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillOnce(DoAll(SetArgumentPointee<2>(original_visits), Return(true)));
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- history::VisitVector updated_visits;
- history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
- 7, 17, false,
- &updated_visits));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillOnce(DoAll(SetArgumentPointee<2>(updated_visits), Return(true)));
-
- history::URLRows changed_urls;
- changed_urls.push_back(updated_entry);
- SendNotificationURLsModified(changed_urls);
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddFromVisit) {
- history::VisitVector added_visits;
- history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry",
- 2, 15, false, &added_visits));
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
-
- SetIdleChangeProcessorExpectations();
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, added_entry);
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdateFromVisit) {
- history::VisitVector original_visits;
- history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
- 2, 15, false,
- &original_visits));
- history::URLRows original_entries;
- original_entries.push_back(original_entry);
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillOnce(DoAll(SetArgumentPointee<2>(original_visits), Return(true)));
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- history::VisitVector updated_visits;
- history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
- 7, 17, false,
- &updated_visits));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillOnce(DoAll(SetArgumentPointee<2>(updated_visits), Return(true)));
-
- SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, updated_entry);
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserIgnoreChangeUpdateFromVisit) {
- history::VisitVector original_visits;
- history::URLRow original_entry(MakeTypedUrlEntry("http://mine.com", "entry",
- 2, 15, false,
- &original_visits));
- history::URLRows original_entries;
- original_entries.push_back(original_entry);
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<2>(original_visits), Return(true)));
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
-
- history::VisitVector updated_visits;
- history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry",
- 7, 15, false,
- &updated_visits));
-
- // Should ignore this change because it's not TYPED.
- SendNotificationURLVisited(ui::PAGE_TRANSITION_RELOAD, updated_entry);
- GetTypedUrlsFromSyncDB(&new_sync_entries);
-
- // Should be no changes to the sync DB from this notification.
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
-
- // Now, try updating it with a large number of visits not divisible by 10
- // (should ignore this visit).
- history::URLRow twelve_visits(MakeTypedUrlEntry("http://mine.com", "entry",
- 12, 15, false,
- &updated_visits));
- SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, twelve_visits);
- GetTypedUrlsFromSyncDB(&new_sync_entries);
-
- // Should be no changes to the sync DB from this notification.
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
-
- // Now, try updating it with a large number of visits that is divisible by 10
- // (should *not* be ignored).
- history::URLRow twenty_visits(MakeTypedUrlEntry("http://mine.com", "entry",
- 20, 15, false,
- &updated_visits));
- SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, twenty_visits);
- GetTypedUrlsFromSyncDB(&new_sync_entries);
-
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(twenty_visits, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemove) {
- history::VisitVector original_visits1;
- history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
- 2, 15, false,
- &original_visits1));
- history::VisitVector original_visits2;
- history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
- "entry2",
- 3, 15, false,
- &original_visits2));
- history::URLRows original_entries;
- original_entries.push_back(original_entry1);
- original_entries.push_back(original_entry2);
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<2>(original_visits1), Return(true)));
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- history::URLRows rows;
- rows.push_back(history::URLRow(GURL("http://mine.com")));
- SendNotificationURLsDeleted(false, false, rows, std::set<GURL>());
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(original_entry2, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveExpired) {
- history::VisitVector original_visits1;
- history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
- 2, 15, false,
- &original_visits1));
- history::VisitVector original_visits2;
- history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
- "entry2",
- 3, 15, false,
- &original_visits2));
- history::URLRows original_entries;
- original_entries.push_back(original_entry1);
- original_entries.push_back(original_entry2);
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<2>(original_visits1), Return(true)));
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- // Setting expired=true should cause the sync code to ignore this deletion.
- history::URLRows rows;
- rows.push_back(history::URLRow(GURL("http://mine.com")));
- SendNotificationURLsDeleted(false, true, rows, std::set<GURL>());
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- // Both URLs should still be there.
- ASSERT_EQ(2U, new_sync_entries.size());
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveAll) {
- history::VisitVector original_visits1;
- history::URLRow original_entry1(MakeTypedUrlEntry("http://mine.com", "entry",
- 2, 15, false,
- &original_visits1));
- history::VisitVector original_visits2;
- history::URLRow original_entry2(MakeTypedUrlEntry("http://mine2.com",
- "entry2",
- 3, 15, false,
- &original_visits2));
- history::URLRows original_entries;
- original_entries.push_back(original_entry1);
- original_entries.push_back(original_entry2);
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<2>(original_visits1), Return(true)));
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(2U, new_sync_entries.size());
-
- SendNotificationURLsDeleted(true, false, history::URLRows(),
- std::set<GURL>());
-
- GetTypedUrlsFromSyncDB(&new_sync_entries);
- ASSERT_EQ(0U, new_sync_entries.size());
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, FailWriteToHistoryBackend) {
- history::VisitVector native_visits;
- history::VisitVector sync_visits;
- history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
- 2, 15, false, &native_visits));
- history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
- 3, 16, false, &sync_visits));
-
- history::URLRows native_entries;
- native_entries.push_back(native_entry);
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetURL(_, _))
- .WillOnce(DoAll(SetArgumentPointee<1>(native_entry), Return(false)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
- EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED))
- .WillRepeatedly(Return(false));
-
- history::URLRows sync_entries;
- sync_entries.push_back(sync_entry);
-
- EXPECT_CALL((history_backend()), UpdateURL(_, _))
- .WillRepeatedly(Return(false));
- TypedUrlSyncableService* syncable_service =
- StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
- // Errors writing to the DB should be recorded, but should not cause an
- // unrecoverable error.
- ASSERT_FALSE(sync_service()->data_type_status_table().GetFailedTypes().Has(
- syncer::TYPED_URLS));
- // Some calls should have succeeded, so the error percentage should be
- // somewhere > 0 and < 100.
- ASSERT_NE(0, syncable_service->GetErrorPercentage());
- ASSERT_NE(100, syncable_service->GetErrorPercentage());
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, FailToGetTypedURLs) {
- history::VisitVector native_visits;
- history::VisitVector sync_visits;
- history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
- 2, 15, false, &native_visits));
- history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry",
- 3, 16, false, &sync_visits));
-
- history::URLRows native_entries;
- native_entries.push_back(native_entry);
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(false)));
-
- history::URLRows sync_entries;
- sync_entries.push_back(sync_entry);
-
- StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
- // Errors getting typed URLs will cause an unrecoverable error (since we can
- // do *nothing* in that case).
- ASSERT_TRUE(sync_service()->data_type_status_table().GetFailedTypes().Has(
- syncer::TYPED_URLS));
- ASSERT_EQ(1u,
- sync_service()->data_type_status_table().GetFailedTypes().Size());
- // Can't check GetErrorPercentage(), because generating an unrecoverable
- // error will free the model associator.
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalFileURL) {
- history::VisitVector original_visits;
- // Create http and file url.
- history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com",
- "yey", 12, 15, false,
- &original_visits));
- history::URLRow file_entry(MakeTypedUrlEntry("file:///kitty.jpg",
- "kitteh", 12, 15, false,
- &original_visits));
-
- history::URLRows original_entries;
- original_entries.push_back(url_entry);
- original_entries.push_back(file_entry);
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<2>(original_visits), Return(true)));
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- history::VisitVector updated_visits;
- // Create updates for the previous urls + a new file one.
- history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com",
- "yey", 20, 15, false,
- &updated_visits));
- history::URLRow updated_file_entry(MakeTypedUrlEntry("file:///cat.jpg",
- "cat", 20, 15, false,
- &updated_visits));
- history::URLRow new_file_entry(MakeTypedUrlEntry("file:///dog.jpg",
- "dog", 20, 15, false,
- &updated_visits));
-
- history::URLRows changed_urls;
- changed_urls.push_back(updated_url_entry);
- changed_urls.push_back(updated_file_entry);
- changed_urls.push_back(new_file_entry);
- SendNotificationURLsModified(changed_urls);
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
-
- // We should ignore the local file urls (existing and updated),
- // and only be left with the updated http url.
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalhostURL) {
- history::VisitVector original_visits;
- // Create http and localhost url.
- history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com",
- "yey", 12, 15, false,
- &original_visits));
- history::URLRow localhost_entry(MakeTypedUrlEntry("http://localhost",
- "localhost", 12, 15, false,
- &original_visits));
-
- history::URLRows original_entries;
- original_entries.push_back(url_entry);
- original_entries.push_back(localhost_entry);
-
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(
- DoAll(SetArgumentPointee<2>(original_visits), Return(true)));
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- history::VisitVector updated_visits;
- // Update the previous entries and add a new localhost.
- history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com",
- "yey", 20, 15, false,
- &updated_visits));
- history::URLRow updated_localhost_entry(MakeTypedUrlEntry(
- "http://localhost:80",
- "localhost", 20, 15, false,
- &original_visits));
- history::URLRow localhost_ip_entry(MakeTypedUrlEntry("http://127.0.0.1",
- "localhost", 12, 15, false,
- &original_visits));
-
- history::URLRows changed_urls;
- changed_urls.push_back(updated_url_entry);
- changed_urls.push_back(updated_localhost_entry);
- changed_urls.push_back(localhost_ip_entry);
- SendNotificationURLsModified(changed_urls);
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
-
- // We should ignore the localhost urls and left only with http url.
- ASSERT_EQ(1U, new_sync_entries.size());
- EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0]));
-}
-
-TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreModificationWithoutValidVisit) {
- EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
- .WillRepeatedly(Return(true));
- EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
- .WillRepeatedly(Return(true));
-
- CreateRootHelper create_root(this, syncer::TYPED_URLS);
- StartSyncService(create_root.callback());
-
- history::VisitVector updated_visits;
- history::URLRow updated_url_entry(MakeTypedUrlEntry("http://yey.com",
- "yey", 20, 0, false,
- &updated_visits));
-
- history::URLRows changed_urls;
- changed_urls.push_back(updated_url_entry);
- SendNotificationURLsModified(changed_urls);
-
- history::URLRows new_sync_entries;
- GetTypedUrlsFromSyncDB(&new_sync_entries);
-
- // The change should be ignored.
- ASSERT_EQ(0U, new_sync_entries.size());
-}
diff --git a/chromium/components/browser_sync/browser/profile_sync_service_unittest.cc b/chromium/components/browser_sync/browser/profile_sync_service_unittest.cc
deleted file mode 100644
index e53e159d1df..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_service_unittest.cc
+++ /dev/null
@@ -1,973 +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 "components/browser_sync/browser/profile_sync_service.h"
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/feature_list.h"
-#include "base/location.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/sequenced_worker_pool_owner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "components/browser_sync/browser/profile_sync_test_util.h"
-#include "components/browser_sync/common/browser_sync_switches.h"
-#include "components/invalidation/impl/profile_invalidation_provider.h"
-#include "components/invalidation/public/invalidation_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/sync_driver/data_type_manager.h"
-#include "components/sync_driver/data_type_manager_observer.h"
-#include "components/sync_driver/fake_data_type_controller.h"
-#include "components/sync_driver/glue/sync_backend_host_mock.h"
-#include "components/sync_driver/pref_names.h"
-#include "components/sync_driver/sync_api_component_factory_mock.h"
-#include "components/sync_driver/sync_driver_switches.h"
-#include "components/sync_driver/sync_prefs.h"
-#include "components/sync_driver/sync_service_observer.h"
-#include "components/sync_driver/sync_util.h"
-#include "components/syncable_prefs/testing_pref_service_syncable.h"
-#include "components/version_info/version_info.h"
-#include "components/version_info/version_info_values.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/l10n/l10n_util.h"
-
-using testing::Return;
-
-namespace browser_sync {
-
-namespace {
-
-const char kGaiaId[] = "12345";
-const char kEmail[] = "test_user@gmail.com";
-
-class FakeDataTypeManager : public sync_driver::DataTypeManager {
- public:
- typedef base::Callback<void(syncer::ConfigureReason)> ConfigureCalled;
-
- explicit FakeDataTypeManager(const ConfigureCalled& configure_called)
- : configure_called_(configure_called) {}
-
- ~FakeDataTypeManager() override{};
-
- void Configure(syncer::ModelTypeSet desired_types,
- syncer::ConfigureReason reason) override {
- DCHECK(!configure_called_.is_null());
- configure_called_.Run(reason);
- }
-
- void ReenableType(syncer::ModelType type) override {}
- void ResetDataTypeErrors() override {}
- void PurgeForMigration(syncer::ModelTypeSet undesired_types,
- syncer::ConfigureReason reason) override {}
- void Stop() override{};
- State state() const override {
- return sync_driver::DataTypeManager::CONFIGURED;
- };
-
- private:
- ConfigureCalled configure_called_;
-};
-
-ACTION_P(ReturnNewDataTypeManager, configure_called) {
- return new FakeDataTypeManager(configure_called);
-}
-
-using testing::Return;
-using testing::StrictMock;
-using testing::_;
-
-class TestSyncServiceObserver : public sync_driver::SyncServiceObserver {
- public:
- explicit TestSyncServiceObserver(ProfileSyncService* service)
- : service_(service), setup_in_progress_(false) {}
- void OnStateChanged() override {
- setup_in_progress_ = service_->IsSetupInProgress();
- }
- bool setup_in_progress() const { return setup_in_progress_; }
-
- private:
- ProfileSyncService* service_;
- bool setup_in_progress_;
-};
-
-// A variant of the SyncBackendHostMock that won't automatically
-// call back when asked to initialized. Allows us to test things
-// that could happen while backend init is in progress.
-class SyncBackendHostNoReturn : public SyncBackendHostMock {
- void Initialize(
- sync_driver::SyncFrontend* frontend,
- std::unique_ptr<base::Thread> sync_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& file_thread,
- const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
- const GURL& service_url,
- const std::string& sync_user_agent,
- const syncer::SyncCredentials& credentials,
- bool delete_sync_data_folder,
- std::unique_ptr<syncer::SyncManagerFactory> sync_manager_factory,
- const syncer::WeakHandle<syncer::UnrecoverableErrorHandler>&
- unrecoverable_error_handler,
- const base::Closure& report_unrecoverable_error_function,
- const HttpPostProviderFactoryGetter& http_post_provider_factory_getter,
- std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState>
- saved_nigori_state) override {}
-};
-
-class SyncBackendHostMockCollectDeleteDirParam : public SyncBackendHostMock {
- public:
- explicit SyncBackendHostMockCollectDeleteDirParam(
- std::vector<bool>* delete_dir_param)
- : delete_dir_param_(delete_dir_param) {}
-
- void Initialize(
- sync_driver::SyncFrontend* frontend,
- std::unique_ptr<base::Thread> sync_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
- const scoped_refptr<base::SingleThreadTaskRunner>& file_thread,
- const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
- const GURL& service_url,
- const std::string& sync_user_agent,
- const syncer::SyncCredentials& credentials,
- bool delete_sync_data_folder,
- std::unique_ptr<syncer::SyncManagerFactory> sync_manager_factory,
- const syncer::WeakHandle<syncer::UnrecoverableErrorHandler>&
- unrecoverable_error_handler,
- const base::Closure& report_unrecoverable_error_function,
- const HttpPostProviderFactoryGetter& http_post_provider_factory_getter,
- std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState>
- saved_nigori_state) override {
- delete_dir_param_->push_back(delete_sync_data_folder);
- SyncBackendHostMock::Initialize(
- frontend, std::move(sync_thread), db_thread, file_thread, event_handler,
- service_url, sync_user_agent, credentials, delete_sync_data_folder,
- std::move(sync_manager_factory), unrecoverable_error_handler,
- report_unrecoverable_error_function, http_post_provider_factory_getter,
- std::move(saved_nigori_state));
- }
-
- private:
- std::vector<bool>* delete_dir_param_;
-};
-
-// SyncBackendHostMock that calls an external callback when ClearServerData is
-// called.
-class SyncBackendHostCaptureClearServerData : public SyncBackendHostMock {
- public:
- typedef base::Callback<void(
- const syncer::SyncManager::ClearServerDataCallback&)>
- ClearServerDataCalled;
- explicit SyncBackendHostCaptureClearServerData(
- const ClearServerDataCalled& clear_server_data_called)
- : clear_server_data_called_(clear_server_data_called) {}
-
- void ClearServerData(
- const syncer::SyncManager::ClearServerDataCallback& callback) override {
- clear_server_data_called_.Run(callback);
- }
-
- private:
- ClearServerDataCalled clear_server_data_called_;
-};
-
-ACTION(ReturnNewSyncBackendHostMock) {
- return new browser_sync::SyncBackendHostMock();
-}
-
-ACTION(ReturnNewSyncBackendHostNoReturn) {
- return new browser_sync::SyncBackendHostNoReturn();
-}
-
-ACTION_P(ReturnNewMockHostCollectDeleteDirParam, delete_dir_param) {
- return new browser_sync::SyncBackendHostMockCollectDeleteDirParam(
- delete_dir_param);
-}
-
-void OnClearServerDataCalled(
- syncer::SyncManager::ClearServerDataCallback* captured_callback,
- const syncer::SyncManager::ClearServerDataCallback& callback) {
- *captured_callback = callback;
-}
-
-ACTION_P(ReturnNewMockHostCaptureClearServerData, captured_callback) {
- return new SyncBackendHostCaptureClearServerData(base::Bind(
- &OnClearServerDataCalled, base::Unretained(captured_callback)));
-}
-
-// A test harness that uses a real ProfileSyncService and in most cases a
-// MockSyncBackendHost.
-//
-// This is useful if we want to test the ProfileSyncService and don't care about
-// testing the SyncBackendHost.
-class ProfileSyncServiceTest : public ::testing::Test {
- protected:
- ProfileSyncServiceTest() : component_factory_(nullptr) {}
- ~ProfileSyncServiceTest() override {}
-
- void SetUp() override {
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kSyncDeferredStartupTimeoutSeconds, "0");
- }
-
- void TearDown() override {
- // Kill the service before the profile.
- if (service_)
- service_->Shutdown();
-
- service_.reset();
- }
-
- void IssueTestTokens() {
- std::string account_id =
- account_tracker()->SeedAccountInfo(kGaiaId, kEmail);
- auth_service()->UpdateCredentials(account_id, "oauth2_login_token");
- }
-
- void CreateService(ProfileSyncService::StartBehavior behavior) {
- signin_manager()->SetAuthenticatedAccountInfo(kGaiaId, kEmail);
- component_factory_ = profile_sync_service_bundle_.component_factory();
- ProfileSyncServiceBundle::SyncClientBuilder builder(
- &profile_sync_service_bundle_);
- ProfileSyncService::InitParams init_params =
- profile_sync_service_bundle_.CreateBasicInitParams(behavior,
- builder.Build());
-
- service_.reset(new ProfileSyncService(std::move(init_params)));
- service_->RegisterDataTypeController(
- new sync_driver::FakeDataTypeController(syncer::BOOKMARKS));
- }
-
-#if defined(OS_WIN) || defined(OS_MACOSX) || \
- (defined(OS_LINUX) && !defined(OS_CHROMEOS))
- void CreateServiceWithoutSignIn() {
- CreateService(ProfileSyncService::AUTO_START);
- signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
- signin_metrics::SignoutDelete::IGNORE_METRIC);
- }
-#endif
-
- void ShutdownAndDeleteService() {
- if (service_)
- service_->Shutdown();
- service_.reset();
- }
-
- void InitializeForNthSync() {
- // Set first sync time before initialize to simulate a complete sync setup.
- sync_driver::SyncPrefs sync_prefs(prefs());
- sync_prefs.SetFirstSyncTime(base::Time::Now());
- sync_prefs.SetFirstSetupComplete();
- sync_prefs.SetKeepEverythingSynced(true);
- service_->Initialize();
- }
-
- void InitializeForFirstSync() {
- service_->Initialize();
- }
-
- void TriggerPassphraseRequired() {
- service_->OnPassphraseRequired(syncer::REASON_DECRYPTION,
- sync_pb::EncryptedData());
- }
-
- void TriggerDataTypeStartRequest() {
- service_->OnDataTypeRequestsSyncStartup(syncer::BOOKMARKS);
- }
-
- void OnConfigureCalled(syncer::ConfigureReason configure_reason) {
- sync_driver::DataTypeManager::ConfigureResult result;
- result.status = sync_driver::DataTypeManager::OK;
- service()->OnConfigureDone(result);
- }
-
- FakeDataTypeManager::ConfigureCalled GetDefaultConfigureCalledCallback() {
- return base::Bind(&ProfileSyncServiceTest::OnConfigureCalled,
- base::Unretained(this));
- }
-
- void OnConfigureCalledRecordReason(syncer::ConfigureReason* reason_dest,
- syncer::ConfigureReason reason) {
- DCHECK(reason_dest);
- *reason_dest = reason;
- }
-
- FakeDataTypeManager::ConfigureCalled GetRecordingConfigureCalledCallback(
- syncer::ConfigureReason* reason) {
- return base::Bind(&ProfileSyncServiceTest::OnConfigureCalledRecordReason,
- base::Unretained(this), reason);
- }
-
- void ExpectDataTypeManagerCreation(
- int times,
- const FakeDataTypeManager::ConfigureCalled& callback) {
- EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
- .Times(times)
- .WillRepeatedly(ReturnNewDataTypeManager(callback));
- }
-
- void ExpectSyncBackendHostCreation(int times) {
- EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
- .Times(times)
- .WillRepeatedly(ReturnNewSyncBackendHostMock());
- }
-
- void ExpectSyncBackendHostCreationCollectDeleteDir(
- int times, std::vector<bool> *delete_dir_param) {
- EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
- .Times(times)
- .WillRepeatedly(
- ReturnNewMockHostCollectDeleteDirParam(delete_dir_param));
- }
-
- void ExpectSyncBackendHostCreationCaptureClearServerData(
- syncer::SyncManager::ClearServerDataCallback* captured_callback) {
- EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
- .Times(1)
- .WillOnce(ReturnNewMockHostCaptureClearServerData(captured_callback));
- }
-
- void PrepareDelayedInitSyncBackendHost() {
- EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
- .WillOnce(ReturnNewSyncBackendHostNoReturn());
- }
-
- AccountTrackerService* account_tracker() {
- return profile_sync_service_bundle_.account_tracker();
- }
-
-#if defined(OS_CHROMEOS)
- SigninManagerBase* signin_manager()
-#else
- SigninManager* signin_manager()
-#endif
- // Opening brace is outside of macro to avoid confusing lint.
- {
- return profile_sync_service_bundle_.signin_manager();
- }
-
- ProfileOAuth2TokenService* auth_service() {
- return profile_sync_service_bundle_.auth_service();
- }
-
- ProfileSyncService* service() {
- return service_.get();
- }
-
- syncable_prefs::TestingPrefServiceSyncable* prefs() {
- return profile_sync_service_bundle_.pref_service();
- }
-
- SyncApiComponentFactoryMock* component_factory() {
- return component_factory_;
- }
-
- protected:
- void PumpLoop() {
- base::RunLoop run_loop;
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- run_loop.QuitClosure());
- run_loop.Run();
- }
-
- private:
- base::MessageLoop message_loop_;
- browser_sync::ProfileSyncServiceBundle profile_sync_service_bundle_;
- std::unique_ptr<ProfileSyncService> service_;
-
- // The current component factory used by sync. May be null if the server
- // hasn't been created yet.
- SyncApiComponentFactoryMock* component_factory_;
-};
-
-// Verify that the server URLs are sane.
-TEST_F(ProfileSyncServiceTest, InitialState) {
- CreateService(ProfileSyncService::AUTO_START);
- InitializeForNthSync();
- const std::string& url = service()->sync_service_url().spec();
- EXPECT_TRUE(url == internal::kSyncServerUrl ||
- url == internal::kSyncDevServerUrl);
-}
-
-// Verify a successful initialization.
-TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
- prefs()->SetManagedPref(sync_driver::prefs::kSyncManaged,
- new base::FundamentalValue(false));
- IssueTestTokens();
- CreateService(ProfileSyncService::AUTO_START);
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- InitializeForNthSync();
- EXPECT_FALSE(service()->IsManaged());
- EXPECT_TRUE(service()->IsSyncActive());
-}
-
-// Verify that an initialization where first setup is not complete does not
-// start up the backend.
-TEST_F(ProfileSyncServiceTest, NeedsConfirmation) {
- prefs()->SetManagedPref(sync_driver::prefs::kSyncManaged,
- new base::FundamentalValue(false));
- IssueTestTokens();
- CreateService(ProfileSyncService::MANUAL_START);
- sync_driver::SyncPrefs sync_prefs(prefs());
- base::Time now = base::Time::Now();
- sync_prefs.SetLastSyncedTime(now);
- sync_prefs.SetKeepEverythingSynced(true);
- service()->Initialize();
- EXPECT_FALSE(service()->IsSyncActive());
-
- // The last sync time shouldn't be cleared.
- // TODO(zea): figure out a way to check that the directory itself wasn't
- // cleared.
- EXPECT_EQ(now, sync_prefs.GetLastSyncedTime());
-}
-
-// Verify that the SetSetupInProgress function call updates state
-// and notifies observers.
-TEST_F(ProfileSyncServiceTest, SetupInProgress) {
- CreateService(ProfileSyncService::AUTO_START);
- InitializeForFirstSync();
-
- TestSyncServiceObserver observer(service());
- service()->AddObserver(&observer);
-
- auto sync_blocker = service()->GetSetupInProgressHandle();
- EXPECT_TRUE(observer.setup_in_progress());
- sync_blocker.reset();
- EXPECT_FALSE(observer.setup_in_progress());
-
- service()->RemoveObserver(&observer);
-}
-
-// Verify that disable by enterprise policy works.
-TEST_F(ProfileSyncServiceTest, DisabledByPolicyBeforeInit) {
- prefs()->SetManagedPref(sync_driver::prefs::kSyncManaged,
- new base::FundamentalValue(true));
- IssueTestTokens();
- CreateService(ProfileSyncService::AUTO_START);
- InitializeForNthSync();
- EXPECT_TRUE(service()->IsManaged());
- EXPECT_FALSE(service()->IsSyncActive());
-}
-
-// Verify that disable by enterprise policy works even after the backend has
-// been initialized.
-TEST_F(ProfileSyncServiceTest, DisabledByPolicyAfterInit) {
- IssueTestTokens();
- CreateService(ProfileSyncService::AUTO_START);
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- InitializeForNthSync();
-
- EXPECT_FALSE(service()->IsManaged());
- EXPECT_TRUE(service()->IsSyncActive());
-
- prefs()->SetManagedPref(sync_driver::prefs::kSyncManaged,
- new base::FundamentalValue(true));
-
- EXPECT_TRUE(service()->IsManaged());
- EXPECT_FALSE(service()->IsSyncActive());
-}
-
-// Exercies the ProfileSyncService's code paths related to getting shut down
-// before the backend initialize call returns.
-TEST_F(ProfileSyncServiceTest, AbortedByShutdown) {
- CreateService(ProfileSyncService::AUTO_START);
- PrepareDelayedInitSyncBackendHost();
-
- IssueTestTokens();
- InitializeForNthSync();
- EXPECT_FALSE(service()->IsSyncActive());
-
- ShutdownAndDeleteService();
-}
-
-// Test RequestStop() before we've initialized the backend.
-TEST_F(ProfileSyncServiceTest, EarlyRequestStop) {
- CreateService(ProfileSyncService::AUTO_START);
- IssueTestTokens();
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
-
- service()->RequestStop(ProfileSyncService::KEEP_DATA);
- EXPECT_FALSE(service()->IsSyncRequested());
-
- // Because sync is not requested, this should fail.
- InitializeForNthSync();
- EXPECT_FALSE(service()->IsSyncRequested());
- EXPECT_FALSE(service()->IsSyncActive());
-
- // Request start. This should be enough to allow init to happen.
- service()->RequestStart();
- EXPECT_TRUE(service()->IsSyncRequested());
- EXPECT_TRUE(service()->IsSyncActive());
-}
-
-// Test RequestStop() after we've initialized the backend.
-TEST_F(ProfileSyncServiceTest, DisableAndEnableSyncTemporarily) {
- CreateService(ProfileSyncService::AUTO_START);
- IssueTestTokens();
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- InitializeForNthSync();
-
- EXPECT_TRUE(service()->IsSyncActive());
- EXPECT_FALSE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
-
- testing::Mock::VerifyAndClearExpectations(component_factory());
-
- service()->RequestStop(ProfileSyncService::KEEP_DATA);
- EXPECT_FALSE(service()->IsSyncActive());
- EXPECT_TRUE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
-
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
-
- service()->RequestStart();
- EXPECT_TRUE(service()->IsSyncActive());
- EXPECT_FALSE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
-}
-
-// Certain ProfileSyncService tests don't apply to Chrome OS, for example
-// things that deal with concepts like "signing out" and policy.
-#if !defined (OS_CHROMEOS)
-TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOut) {
- CreateService(ProfileSyncService::AUTO_START);
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- IssueTestTokens();
- InitializeForNthSync();
-
- EXPECT_TRUE(service()->IsSyncActive());
- EXPECT_FALSE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
-
- signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
- signin_metrics::SignoutDelete::IGNORE_METRIC);
- EXPECT_FALSE(service()->IsSyncActive());
-}
-#endif // !defined(OS_CHROMEOS)
-
-TEST_F(ProfileSyncServiceTest, GetSyncTokenStatus) {
- CreateService(ProfileSyncService::AUTO_START);
- IssueTestTokens();
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- InitializeForNthSync();
-
- // Initial status.
- ProfileSyncService::SyncTokenStatus token_status =
- service()->GetSyncTokenStatus();
- EXPECT_EQ(syncer::CONNECTION_NOT_ATTEMPTED, token_status.connection_status);
- EXPECT_TRUE(token_status.connection_status_update_time.is_null());
- EXPECT_TRUE(token_status.token_request_time.is_null());
- EXPECT_TRUE(token_status.token_receive_time.is_null());
-
- // Simulate an auth error.
- service()->OnConnectionStatusChange(syncer::CONNECTION_AUTH_ERROR);
-
- // The token request will take the form of a posted task. Run it.
- base::RunLoop loop;
- loop.RunUntilIdle();
-
- token_status = service()->GetSyncTokenStatus();
- EXPECT_EQ(syncer::CONNECTION_AUTH_ERROR, token_status.connection_status);
- EXPECT_FALSE(token_status.connection_status_update_time.is_null());
- EXPECT_FALSE(token_status.token_request_time.is_null());
- EXPECT_FALSE(token_status.token_receive_time.is_null());
- EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
- token_status.last_get_token_error);
- EXPECT_TRUE(token_status.next_token_request_time.is_null());
-
- // Simulate successful connection.
- service()->OnConnectionStatusChange(syncer::CONNECTION_OK);
- token_status = service()->GetSyncTokenStatus();
- EXPECT_EQ(syncer::CONNECTION_OK, token_status.connection_status);
-}
-
-TEST_F(ProfileSyncServiceTest, RevokeAccessTokenFromTokenService) {
- CreateService(ProfileSyncService::AUTO_START);
- IssueTestTokens();
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- InitializeForNthSync();
- EXPECT_TRUE(service()->IsSyncActive());
-
- std::string primary_account_id =
- signin_manager()->GetAuthenticatedAccountId();
- auth_service()->LoadCredentials(primary_account_id);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
-
- std::string secondary_account_gaiaid = "1234567";
- std::string secondary_account_name = "test_user2@gmail.com";
- std::string secondary_account_id = account_tracker()->SeedAccountInfo(
- secondary_account_gaiaid, secondary_account_name);
- auth_service()->UpdateCredentials(secondary_account_id,
- "second_account_refresh_token");
- auth_service()->RevokeCredentials(secondary_account_id);
- EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
-
- auth_service()->RevokeCredentials(primary_account_id);
- EXPECT_TRUE(service()->GetAccessTokenForTest().empty());
-}
-
-// CrOS does not support signout.
-#if !defined(OS_CHROMEOS)
-TEST_F(ProfileSyncServiceTest, SignOutRevokeAccessToken) {
- CreateService(ProfileSyncService::AUTO_START);
- IssueTestTokens();
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- InitializeForNthSync();
- EXPECT_TRUE(service()->IsSyncActive());
-
- std::string primary_account_id =
- signin_manager()->GetAuthenticatedAccountId();
- auth_service()->LoadCredentials(primary_account_id);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
-
- signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
- signin_metrics::SignoutDelete::IGNORE_METRIC);
- EXPECT_TRUE(service()->GetAccessTokenForTest().empty());
-}
-#endif
-
-// Verify that LastSyncedTime and local DeviceInfo is cleared on sign out.
-TEST_F(ProfileSyncServiceTest, ClearDataOnSignOut) {
- IssueTestTokens();
- CreateService(ProfileSyncService::AUTO_START);
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- InitializeForNthSync();
- EXPECT_TRUE(service()->IsSyncActive());
- EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW),
- service()->GetLastSyncedTimeString());
- EXPECT_TRUE(service()->GetLocalDeviceInfoProvider()->GetLocalDeviceInfo());
-
- // Sign out.
- service()->RequestStop(ProfileSyncService::CLEAR_DATA);
- PumpLoop();
-
- EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER),
- service()->GetLastSyncedTimeString());
- EXPECT_FALSE(service()->GetLocalDeviceInfoProvider()->GetLocalDeviceInfo());
-}
-
-// Verify that the disable sync flag disables sync.
-TEST_F(ProfileSyncServiceTest, DisableSyncFlag) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableSync);
- EXPECT_FALSE(ProfileSyncService::IsSyncAllowedByFlag());
-}
-
-// Verify that no disable sync flag enables sync.
-TEST_F(ProfileSyncServiceTest, NoDisableSyncFlag) {
- EXPECT_TRUE(ProfileSyncService::IsSyncAllowedByFlag());
-}
-
-// Test Sync will stop after receive memory pressure
-TEST_F(ProfileSyncServiceTest, MemoryPressureRecording) {
- CreateService(ProfileSyncService::AUTO_START);
- IssueTestTokens();
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- InitializeForNthSync();
-
- EXPECT_TRUE(service()->IsSyncActive());
- EXPECT_FALSE(prefs()->GetBoolean(sync_driver::prefs::kSyncSuppressStart));
-
- testing::Mock::VerifyAndClearExpectations(component_factory());
-
- sync_driver::SyncPrefs sync_prefs(
- service()->GetSyncClient()->GetPrefService());
-
- EXPECT_EQ(
- prefs()->GetInteger(sync_driver::prefs::kSyncMemoryPressureWarningCount),
- 0);
- EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly());
-
- // Simulate memory pressure notification.
- base::MemoryPressureListener::NotifyMemoryPressure(
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
- base::RunLoop().RunUntilIdle();
-
- // Verify memory pressure recorded.
- EXPECT_EQ(
- prefs()->GetInteger(sync_driver::prefs::kSyncMemoryPressureWarningCount),
- 1);
- EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly());
-
- // Simulate memory pressure notification.
- base::MemoryPressureListener::NotifyMemoryPressure(
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
- base::RunLoop().RunUntilIdle();
- ShutdownAndDeleteService();
-
- // Verify memory pressure and shutdown recorded.
- EXPECT_EQ(
- prefs()->GetInteger(sync_driver::prefs::kSyncMemoryPressureWarningCount),
- 2);
- EXPECT_TRUE(sync_prefs.DidSyncShutdownCleanly());
-}
-
-// Verify that OnLocalSetPassphraseEncryption triggers catch up configure sync
-// cycle, calls ClearServerData, shuts down and restarts sync.
-TEST_F(ProfileSyncServiceTest, OnLocalSetPassphraseEncryption) {
- base::FeatureList::ClearInstanceForTesting();
- ASSERT_TRUE(base::FeatureList::InitializeInstance(
- switches::kSyncClearDataOnPassphraseEncryption.name, std::string()));
- IssueTestTokens();
- CreateService(ProfileSyncService::AUTO_START);
-
- syncer::SyncManager::ClearServerDataCallback captured_callback;
- syncer::ConfigureReason configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
-
- // Initialize sync, ensure that both DataTypeManager and SyncBackendHost are
- // initialized and DTM::Configure is called with
- // CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE.
- ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
- ExpectDataTypeManagerCreation(
- 1, GetRecordingConfigureCalledCallback(&configure_reason));
- InitializeForNthSync();
- EXPECT_TRUE(service()->IsSyncActive());
- testing::Mock::VerifyAndClearExpectations(component_factory());
- EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
- sync_driver::DataTypeManager::ConfigureResult result;
- result.status = sync_driver::DataTypeManager::OK;
- service()->OnConfigureDone(result);
-
- // Simulate user entering encryption passphrase. Ensure that catch up
- // configure cycle is started (DTM::Configure is called with
- // CONFIGURE_REASON_CATCH_UP).
- const syncer::SyncEncryptionHandler::NigoriState nigori_state;
- service()->OnLocalSetPassphraseEncryption(nigori_state);
- EXPECT_EQ(syncer::CONFIGURE_REASON_CATCH_UP, configure_reason);
- EXPECT_TRUE(captured_callback.is_null());
-
- // Simulate configure successful. Ensure that SBH::ClearServerData is called.
- service()->OnConfigureDone(result);
- EXPECT_FALSE(captured_callback.is_null());
-
- // Once SBH::ClearServerData finishes successfully ensure that sync is
- // restarted.
- configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
- ExpectSyncBackendHostCreation(1);
- ExpectDataTypeManagerCreation(
- 1, GetRecordingConfigureCalledCallback(&configure_reason));
- captured_callback.Run();
- testing::Mock::VerifyAndClearExpectations(component_factory());
- EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
- service()->OnConfigureDone(result);
-}
-
-// Verify that if after OnLocalSetPassphraseEncryption catch up configure sync
-// cycle gets interrupted, it starts again after browser restart.
-TEST_F(ProfileSyncServiceTest,
- OnLocalSetPassphraseEncryption_RestartDuringCatchUp) {
- syncer::ConfigureReason configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
- base::FeatureList::ClearInstanceForTesting();
- ASSERT_TRUE(base::FeatureList::InitializeInstance(
- switches::kSyncClearDataOnPassphraseEncryption.name, std::string()));
- IssueTestTokens();
- CreateService(ProfileSyncService::AUTO_START);
- ExpectSyncBackendHostCreation(1);
- ExpectDataTypeManagerCreation(
- 1, GetRecordingConfigureCalledCallback(&configure_reason));
- InitializeForNthSync();
- testing::Mock::VerifyAndClearExpectations(component_factory());
- EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
- sync_driver::DataTypeManager::ConfigureResult result;
- result.status = sync_driver::DataTypeManager::OK;
- service()->OnConfigureDone(result);
-
- // Simulate user entering encryption passphrase. Ensure Configure was called
- // but don't let it continue.
- const syncer::SyncEncryptionHandler::NigoriState nigori_state;
- service()->OnLocalSetPassphraseEncryption(nigori_state);
- EXPECT_EQ(syncer::CONFIGURE_REASON_CATCH_UP, configure_reason);
-
- // Simulate browser restart. First configuration is a regular one.
- service()->Shutdown();
- syncer::SyncManager::ClearServerDataCallback captured_callback;
- ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
- ExpectDataTypeManagerCreation(
- 1, GetRecordingConfigureCalledCallback(&configure_reason));
- service()->RequestStart();
- testing::Mock::VerifyAndClearExpectations(component_factory());
- EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
- EXPECT_TRUE(captured_callback.is_null());
-
- // Simulate configure successful. This time it should be catch up.
- service()->OnConfigureDone(result);
- EXPECT_EQ(syncer::CONFIGURE_REASON_CATCH_UP, configure_reason);
- EXPECT_TRUE(captured_callback.is_null());
-
- // Simulate catch up configure successful. Ensure that SBH::ClearServerData is
- // called.
- service()->OnConfigureDone(result);
- EXPECT_FALSE(captured_callback.is_null());
-
- ExpectSyncBackendHostCreation(1);
- ExpectDataTypeManagerCreation(
- 1, GetRecordingConfigureCalledCallback(&configure_reason));
- captured_callback.Run();
- testing::Mock::VerifyAndClearExpectations(component_factory());
- EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
-}
-
-// Verify that if after OnLocalSetPassphraseEncryption ClearServerData gets
-// interrupted, transition again from catch up sync cycle after browser restart.
-TEST_F(ProfileSyncServiceTest,
- OnLocalSetPassphraseEncryption_RestartDuringClearServerData) {
- syncer::SyncManager::ClearServerDataCallback captured_callback;
- syncer::ConfigureReason configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
- base::FeatureList::ClearInstanceForTesting();
- ASSERT_TRUE(base::FeatureList::InitializeInstance(
- switches::kSyncClearDataOnPassphraseEncryption.name, std::string()));
- IssueTestTokens();
- CreateService(ProfileSyncService::AUTO_START);
- ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- InitializeForNthSync();
- testing::Mock::VerifyAndClearExpectations(component_factory());
-
- // Simulate user entering encryption passphrase.
- const syncer::SyncEncryptionHandler::NigoriState nigori_state;
- service()->OnLocalSetPassphraseEncryption(nigori_state);
- EXPECT_FALSE(captured_callback.is_null());
- captured_callback.Reset();
-
- // Simulate browser restart. First configuration is a regular one.
- service()->Shutdown();
- ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
- ExpectDataTypeManagerCreation(
- 1, GetRecordingConfigureCalledCallback(&configure_reason));
- service()->RequestStart();
- testing::Mock::VerifyAndClearExpectations(component_factory());
- EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
- EXPECT_TRUE(captured_callback.is_null());
-
- // Simulate configure successful. This time it should be catch up.
- sync_driver::DataTypeManager::ConfigureResult result;
- result.status = sync_driver::DataTypeManager::OK;
- service()->OnConfigureDone(result);
- EXPECT_EQ(syncer::CONFIGURE_REASON_CATCH_UP, configure_reason);
- EXPECT_TRUE(captured_callback.is_null());
-
- // Simulate catch up configure successful. Ensure that SBH::ClearServerData is
- // called.
- service()->OnConfigureDone(result);
- EXPECT_FALSE(captured_callback.is_null());
-
- ExpectSyncBackendHostCreation(1);
- ExpectDataTypeManagerCreation(
- 1, GetRecordingConfigureCalledCallback(&configure_reason));
- captured_callback.Run();
- testing::Mock::VerifyAndClearExpectations(component_factory());
- EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
-}
-
-// Test that the passphrase prompt due to version change logic gets triggered
-// on a datatype type requesting startup, but only happens once.
-TEST_F(ProfileSyncServiceTest, PassphrasePromptDueToVersion) {
- IssueTestTokens();
- CreateService(ProfileSyncService::AUTO_START);
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- InitializeForNthSync();
-
- sync_driver::SyncPrefs sync_prefs(
- service()->GetSyncClient()->GetPrefService());
- EXPECT_EQ(PRODUCT_VERSION, sync_prefs.GetLastRunVersion());
-
- sync_prefs.SetPassphrasePrompted(true);
-
- // Until a datatype requests startup while a passphrase is required the
- // passphrase prompt bit should remain set.
- EXPECT_TRUE(sync_prefs.IsPassphrasePrompted());
- TriggerPassphraseRequired();
- EXPECT_TRUE(sync_prefs.IsPassphrasePrompted());
-
- // Because the last version was unset, this run should be treated as a new
- // version and force a prompt.
- TriggerDataTypeStartRequest();
- EXPECT_FALSE(sync_prefs.IsPassphrasePrompted());
-
- // At this point further datatype startup request should have no effect.
- sync_prefs.SetPassphrasePrompted(true);
- TriggerDataTypeStartRequest();
- EXPECT_TRUE(sync_prefs.IsPassphrasePrompted());
-}
-
-// Test that when ProfileSyncService receives actionable error
-// RESET_LOCAL_SYNC_DATA it restarts sync.
-TEST_F(ProfileSyncServiceTest, ResetSyncData) {
- IssueTestTokens();
- CreateService(ProfileSyncService::AUTO_START);
- // Backend should get initialized two times: once during initialization and
- // once when handling actionable error.
- ExpectDataTypeManagerCreation(2, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(2);
- InitializeForNthSync();
-
- syncer::SyncProtocolError client_cmd;
- client_cmd.action = syncer::RESET_LOCAL_SYNC_DATA;
- service()->OnActionableError(client_cmd);
-}
-
-// Test that when ProfileSyncService receives actionable error
-// DISABLE_SYNC_ON_CLIENT it disables sync and signs out.
-TEST_F(ProfileSyncServiceTest, DisableSyncOnClient) {
- IssueTestTokens();
- CreateService(ProfileSyncService::AUTO_START);
- ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
- ExpectSyncBackendHostCreation(1);
- InitializeForNthSync();
-
- EXPECT_TRUE(service()->IsSyncActive());
- EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW),
- service()->GetLastSyncedTimeString());
- EXPECT_TRUE(service()->GetLocalDeviceInfoProvider()->GetLocalDeviceInfo());
-
- syncer::SyncProtocolError client_cmd;
- client_cmd.action = syncer::DISABLE_SYNC_ON_CLIENT;
- service()->OnActionableError(client_cmd);
-
-// CrOS does not support signout.
-#if !defined(OS_CHROMEOS)
- EXPECT_TRUE(signin_manager()->GetAuthenticatedAccountId().empty());
-#else
- EXPECT_FALSE(signin_manager()->GetAuthenticatedAccountId().empty());
-#endif
-
- EXPECT_FALSE(service()->IsSyncActive());
- EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER),
- service()->GetLastSyncedTimeString());
- EXPECT_FALSE(service()->GetLocalDeviceInfoProvider()->GetLocalDeviceInfo());
-}
-
-// Regression test for crbug/555434. The issue is that check for sessions DTC in
-// OnSessionRestoreComplete was creating map entry with nullptr which later was
-// dereferenced in OnSyncCycleCompleted. The fix is to use find() to check if
-// entry for sessions exists in map.
-TEST_F(ProfileSyncServiceTest, ValidPointersInDTCMap) {
- CreateService(ProfileSyncService::AUTO_START);
- service()->OnSessionRestoreComplete();
- service()->OnSyncCycleCompleted();
-}
-
-} // namespace
-} // namespace browser_sync
diff --git a/chromium/components/browser_sync/browser/profile_sync_test_util.cc b/chromium/components/browser_sync/browser/profile_sync_test_util.cc
deleted file mode 100644
index 3290db5b785..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_test_util.cc
+++ /dev/null
@@ -1,275 +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 "components/browser_sync/browser/profile_sync_test_util.h"
-
-#include "base/memory/ptr_util.h"
-#include "components/bookmarks/browser/bookmark_model.h"
-#include "components/history/core/browser/history_model_worker.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "components/signin/core/browser/signin_manager_base.h"
-#include "components/sync_driver/glue/browser_thread_model_worker.h"
-#include "components/sync_driver/glue/ui_model_worker.h"
-#include "components/sync_driver/signin_manager_wrapper.h"
-#include "components/sync_driver/sync_prefs.h"
-#include "net/url_request/url_request_test_util.h"
-#include "sync/internal_api/public/engine/passive_model_worker.h"
-
-namespace browser_sync {
-
-namespace {
-
-class BundleSyncClient : public sync_driver::FakeSyncClient {
- public:
- BundleSyncClient(
- sync_driver::SyncApiComponentFactory* factory,
- PrefService* pref_service,
- sync_sessions::SyncSessionsClient* sync_sessions_client,
- autofill::PersonalDataManager* personal_data_manager,
- const base::Callback<base::WeakPtr<syncer::SyncableService>(
- syncer::ModelType type)>& get_syncable_service_callback,
- const base::Callback<sync_driver::SyncService*(void)>&
- get_sync_service_callback,
- const base::Callback<bookmarks::BookmarkModel*(void)>&
- get_bookmark_model_callback,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
- scoped_refptr<base::SingleThreadTaskRunner> file_thread,
- history::HistoryService* history_service);
-
- ~BundleSyncClient() override;
-
- PrefService* GetPrefService() override;
- sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override;
- autofill::PersonalDataManager* GetPersonalDataManager() override;
- base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
- syncer::ModelType type) override;
- sync_driver::SyncService* GetSyncService() override;
- scoped_refptr<syncer::ModelSafeWorker> CreateModelWorkerForGroup(
- syncer::ModelSafeGroup group,
- syncer::WorkerLoopDestructionObserver* observer) override;
- history::HistoryService* GetHistoryService() override;
- bookmarks::BookmarkModel* GetBookmarkModel() override;
-
- private:
- PrefService* const pref_service_;
- sync_sessions::SyncSessionsClient* const sync_sessions_client_;
- autofill::PersonalDataManager* const personal_data_manager_;
- const base::Callback<base::WeakPtr<syncer::SyncableService>(
- syncer::ModelType type)>
- get_syncable_service_callback_;
- const base::Callback<sync_driver::SyncService*(void)>
- get_sync_service_callback_;
- const base::Callback<bookmarks::BookmarkModel*(void)>
- get_bookmark_model_callback_;
- // These task runners, if not null, are used in CreateModelWorkerForGroup.
- const scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
- const scoped_refptr<base::SingleThreadTaskRunner> file_thread_;
- history::HistoryService* history_service_;
-};
-
-BundleSyncClient::BundleSyncClient(
- sync_driver::SyncApiComponentFactory* factory,
- PrefService* pref_service,
- sync_sessions::SyncSessionsClient* sync_sessions_client,
- autofill::PersonalDataManager* personal_data_manager,
- const base::Callback<base::WeakPtr<syncer::SyncableService>(
- syncer::ModelType type)>& get_syncable_service_callback,
- const base::Callback<sync_driver::SyncService*(void)>&
- get_sync_service_callback,
- const base::Callback<bookmarks::BookmarkModel*(void)>&
- get_bookmark_model_callback,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
- scoped_refptr<base::SingleThreadTaskRunner> file_thread,
- history::HistoryService* history_service)
- : sync_driver::FakeSyncClient(factory),
- pref_service_(pref_service),
- sync_sessions_client_(sync_sessions_client),
- personal_data_manager_(personal_data_manager),
- get_syncable_service_callback_(get_syncable_service_callback),
- get_sync_service_callback_(get_sync_service_callback),
- get_bookmark_model_callback_(get_bookmark_model_callback),
- db_thread_(db_thread),
- file_thread_(file_thread),
- history_service_(history_service) {
- DCHECK_EQ(!!db_thread_, !!file_thread_);
-}
-
-BundleSyncClient::~BundleSyncClient() = default;
-
-PrefService* BundleSyncClient::GetPrefService() {
- return pref_service_;
-}
-
-sync_sessions::SyncSessionsClient* BundleSyncClient::GetSyncSessionsClient() {
- return sync_sessions_client_;
-}
-
-autofill::PersonalDataManager* BundleSyncClient::GetPersonalDataManager() {
- return personal_data_manager_;
-}
-
-base::WeakPtr<syncer::SyncableService>
-BundleSyncClient::GetSyncableServiceForType(syncer::ModelType type) {
- if (get_syncable_service_callback_.is_null())
- return sync_driver::FakeSyncClient::GetSyncableServiceForType(type);
- return get_syncable_service_callback_.Run(type);
-}
-
-sync_driver::SyncService* BundleSyncClient::GetSyncService() {
- if (get_sync_service_callback_.is_null())
- return sync_driver::FakeSyncClient::GetSyncService();
- return get_sync_service_callback_.Run();
-}
-
-scoped_refptr<syncer::ModelSafeWorker>
-BundleSyncClient::CreateModelWorkerForGroup(
- syncer::ModelSafeGroup group,
- syncer::WorkerLoopDestructionObserver* observer) {
- if (!db_thread_)
- return FakeSyncClient::CreateModelWorkerForGroup(group, observer);
- DCHECK(file_thread_) << "DB thread was specified but FILE thread was not.";
- switch (group) {
- case syncer::GROUP_DB:
- return new BrowserThreadModelWorker(db_thread_, syncer::GROUP_DB,
- observer);
- case syncer::GROUP_FILE:
- return new BrowserThreadModelWorker(file_thread_, syncer::GROUP_FILE,
- observer);
- case syncer::GROUP_UI:
- return new UIModelWorker(base::ThreadTaskRunnerHandle::Get(), observer);
- case syncer::GROUP_PASSIVE:
- return new syncer::PassiveModelWorker(observer);
- case syncer::GROUP_HISTORY: {
- history::HistoryService* history_service = GetHistoryService();
- if (!history_service)
- return nullptr;
- return new HistoryModelWorker(history_service->AsWeakPtr(),
- base::ThreadTaskRunnerHandle::Get(),
- observer);
- }
- default:
- return nullptr;
- }
-}
-
-history::HistoryService* BundleSyncClient::GetHistoryService() {
- if (history_service_)
- return history_service_;
- return FakeSyncClient::GetHistoryService();
-}
-
-bookmarks::BookmarkModel* BundleSyncClient::GetBookmarkModel() {
- if (get_bookmark_model_callback_.is_null())
- return FakeSyncClient::GetBookmarkModel();
- return get_bookmark_model_callback_.Run();
-}
-
-} // namespace
-
-void EmptyNetworkTimeUpdate(const base::Time&,
- const base::TimeDelta&,
- const base::TimeDelta&) {}
-
-void RegisterPrefsForProfileSyncService(
- user_prefs::PrefRegistrySyncable* registry) {
- sync_driver::SyncPrefs::RegisterProfilePrefs(registry);
- AccountTrackerService::RegisterPrefs(registry);
- SigninManagerBase::RegisterProfilePrefs(registry);
- SigninManagerBase::RegisterPrefs(registry);
-}
-
-ProfileSyncServiceBundle::SyncClientBuilder::~SyncClientBuilder() = default;
-
-ProfileSyncServiceBundle::SyncClientBuilder::SyncClientBuilder(
- ProfileSyncServiceBundle* bundle)
- : bundle_(bundle) {}
-
-void ProfileSyncServiceBundle::SyncClientBuilder::SetPersonalDataManager(
- autofill::PersonalDataManager* personal_data_manager) {
- personal_data_manager_ = personal_data_manager;
-}
-
-// The client will call this callback to produce the service.
-void ProfileSyncServiceBundle::SyncClientBuilder::SetSyncableServiceCallback(
- const base::Callback<base::WeakPtr<syncer::SyncableService>(
- syncer::ModelType type)>& get_syncable_service_callback) {
- get_syncable_service_callback_ = get_syncable_service_callback;
-}
-
-// The client will call this callback to produce the service.
-void ProfileSyncServiceBundle::SyncClientBuilder::SetSyncServiceCallback(
- const base::Callback<sync_driver::SyncService*(void)>&
- get_sync_service_callback) {
- get_sync_service_callback_ = get_sync_service_callback;
-}
-
-void ProfileSyncServiceBundle::SyncClientBuilder::SetHistoryService(
- history::HistoryService* history_service) {
- history_service_ = history_service;
-}
-
-void ProfileSyncServiceBundle::SyncClientBuilder::SetBookmarkModelCallback(
- const base::Callback<bookmarks::BookmarkModel*(void)>&
- get_bookmark_model_callback) {
- get_bookmark_model_callback_ = get_bookmark_model_callback;
-}
-
-std::unique_ptr<sync_driver::FakeSyncClient>
-ProfileSyncServiceBundle::SyncClientBuilder::Build() {
- return base::WrapUnique(new BundleSyncClient(
- bundle_->component_factory(), bundle_->pref_service(),
- bundle_->sync_sessions_client(), personal_data_manager_,
- get_syncable_service_callback_, get_sync_service_callback_,
- get_bookmark_model_callback_,
- activate_model_creation_ ? bundle_->db_thread() : nullptr,
- activate_model_creation_ ? base::ThreadTaskRunnerHandle::Get() : nullptr,
- history_service_));
-}
-
-ProfileSyncServiceBundle::ProfileSyncServiceBundle()
- : db_thread_(base::ThreadTaskRunnerHandle::Get()),
- worker_pool_owner_(2, "sync test worker pool"),
- signin_client_(&pref_service_),
-#if defined(OS_CHROMEOS)
- signin_manager_(&signin_client_, &account_tracker_),
-#else
- signin_manager_(&signin_client_,
- &auth_service_,
- &account_tracker_,
- nullptr),
-#endif
- url_request_context_(new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get())) {
- browser_sync::RegisterPrefsForProfileSyncService(pref_service_.registry());
- auth_service_.set_auto_post_fetch_response_on_message_loop(true);
- account_tracker_.Initialize(&signin_client_);
- signin_manager_.Initialize(&pref_service_);
-}
-
-ProfileSyncServiceBundle::~ProfileSyncServiceBundle() {}
-
-ProfileSyncService::InitParams ProfileSyncServiceBundle::CreateBasicInitParams(
- ProfileSyncService::StartBehavior start_behavior,
- std::unique_ptr<sync_driver::SyncClient> sync_client) {
- ProfileSyncService::InitParams init_params;
-
- init_params.start_behavior = start_behavior;
- init_params.sync_client = std::move(sync_client);
- init_params.signin_wrapper =
- base::WrapUnique(new SigninManagerWrapper(signin_manager()));
- init_params.oauth2_token_service = auth_service();
- init_params.network_time_update_callback =
- base::Bind(&EmptyNetworkTimeUpdate);
- init_params.base_directory = base::FilePath(FILE_PATH_LITERAL("dummyPath"));
- init_params.url_request_context = url_request_context();
- init_params.debug_identifier = "dummyDebugName";
- init_params.channel = version_info::Channel::UNKNOWN;
- init_params.db_thread = db_thread_;
- init_params.file_thread = base::ThreadTaskRunnerHandle::Get();
- init_params.blocking_pool = worker_pool_owner_.pool().get();
-
- return init_params;
-}
-
-} // namespace browser_sync
diff --git a/chromium/components/browser_sync/browser/profile_sync_test_util.h b/chromium/components/browser_sync/browser/profile_sync_test_util.h
deleted file mode 100644
index ae554e2837b..00000000000
--- a/chromium/components/browser_sync/browser/profile_sync_test_util.h
+++ /dev/null
@@ -1,186 +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 COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_TEST_UTIL_H_
-#define COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_TEST_UTIL_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/test/sequenced_worker_pool_owner.h"
-#include "base/time/time.h"
-#include "components/browser_sync/browser/profile_sync_service.h"
-#include "components/invalidation/impl/fake_invalidation_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
-#include "components/signin/core/browser/test_signin_client.h"
-#include "components/sync_driver/fake_sync_client.h"
-#include "components/sync_driver/sync_api_component_factory_mock.h"
-#include "components/sync_sessions/fake_sync_sessions_client.h"
-#include "components/syncable_prefs/testing_pref_service_syncable.h"
-
-namespace base {
-class Time;
-class TimeDelta;
-}
-
-namespace history {
-class HistoryService;
-}
-
-namespace net {
-class URLRequestContextGetter;
-}
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-}
-
-namespace browser_sync {
-
-// An empty syncer::NetworkTimeUpdateCallback. Used in various tests to
-// instantiate ProfileSyncService.
-void EmptyNetworkTimeUpdate(const base::Time&,
- const base::TimeDelta&,
- const base::TimeDelta&);
-
-// Call this to register preferences needed for ProfileSyncService creation.
-void RegisterPrefsForProfileSyncService(
- user_prefs::PrefRegistrySyncable* registry);
-
-// Aggregate this class to get all necessary support for creating a
-// ProfileSyncService in tests. The test still needs to have its own
-// MessageLoop, though.
-class ProfileSyncServiceBundle {
- public:
-#if defined(OS_CHROMEOS)
- typedef FakeSigninManagerBase FakeSigninManagerType;
-#else
- typedef FakeSigninManager FakeSigninManagerType;
-#endif
-
- ProfileSyncServiceBundle();
-
- ~ProfileSyncServiceBundle();
-
- // Builders
-
- // Builds a child of FakeSyncClient which overrides some of the client's
- // accessors to return objects from the bundle.
- class SyncClientBuilder {
- public:
- // Construct the builder and associate with the |bundle| to source objects
- // from.
- explicit SyncClientBuilder(ProfileSyncServiceBundle* bundle);
-
- ~SyncClientBuilder();
-
- void SetPersonalDataManager(
- autofill::PersonalDataManager* personal_data_manager);
-
- // The client will call this callback to produce the SyncableService
- // specific to |type|.
- void SetSyncableServiceCallback(
- const base::Callback<base::WeakPtr<syncer::SyncableService>(
- syncer::ModelType type)>& get_syncable_service_callback);
-
- // The client will call this callback to produce the SyncService for the
- // current Profile.
- void SetSyncServiceCallback(const base::Callback<sync_driver::SyncService*(
- void)>& get_sync_service_callback);
-
- void SetHistoryService(history::HistoryService* history_service);
-
- void SetBookmarkModelCallback(
- const base::Callback<bookmarks::BookmarkModel*(void)>&
- get_bookmark_model_callback);
-
- void set_activate_model_creation() { activate_model_creation_ = true; }
-
- std::unique_ptr<sync_driver::FakeSyncClient> Build();
-
- private:
- // Associated bundle to source objects from.
- ProfileSyncServiceBundle* const bundle_;
-
- autofill::PersonalDataManager* personal_data_manager_;
- base::Callback<base::WeakPtr<syncer::SyncableService>(
- syncer::ModelType type)>
- get_syncable_service_callback_;
- base::Callback<sync_driver::SyncService*(void)> get_sync_service_callback_;
- history::HistoryService* history_service_ = nullptr;
- base::Callback<bookmarks::BookmarkModel*(void)>
- get_bookmark_model_callback_;
- // If set, the built client will be able to build some ModelSafeWorker
- // instances.
- bool activate_model_creation_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(SyncClientBuilder);
- };
-
- // Creates an InitParams instance with the specified |start_behavior| and
- // |sync_client|, and fills the rest with dummy values and objects owned by
- // the bundle.
- ProfileSyncService::InitParams CreateBasicInitParams(
- ProfileSyncService::StartBehavior start_behavior,
- std::unique_ptr<sync_driver::SyncClient> sync_client);
-
- // Accessors
-
- net::URLRequestContextGetter* url_request_context() {
- return url_request_context_.get();
- }
-
- syncable_prefs::TestingPrefServiceSyncable* pref_service() {
- return &pref_service_;
- }
-
- FakeProfileOAuth2TokenService* auth_service() { return &auth_service_; }
-
- FakeSigninManagerType* signin_manager() { return &signin_manager_; }
-
- AccountTrackerService* account_tracker() { return &account_tracker_; }
-
- SyncApiComponentFactoryMock* component_factory() {
- return &component_factory_;
- }
-
- sync_sessions::FakeSyncSessionsClient* sync_sessions_client() {
- return &sync_sessions_client_;
- }
-
- invalidation::FakeInvalidationService* fake_invalidation_service() {
- return &fake_invalidation_service_;
- }
-
- base::SingleThreadTaskRunner* db_thread() { return db_thread_.get(); }
-
- void set_db_thread(
- const scoped_refptr<base::SingleThreadTaskRunner>& db_thread) {
- db_thread_ = db_thread;
- }
-
- private:
- scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
- base::SequencedWorkerPoolOwner worker_pool_owner_;
- syncable_prefs::TestingPrefServiceSyncable pref_service_;
- TestSigninClient signin_client_;
- AccountTrackerService account_tracker_;
- FakeSigninManagerType signin_manager_;
- FakeProfileOAuth2TokenService auth_service_;
- SyncApiComponentFactoryMock component_factory_;
- sync_sessions::FakeSyncSessionsClient sync_sessions_client_;
- invalidation::FakeInvalidationService fake_invalidation_service_;
- scoped_refptr<net::URLRequestContextGetter> url_request_context_;
-
- DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceBundle);
-};
-
-} // namespace browser_sync
-
-#endif // COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_TEST_UTIL_H_
diff --git a/chromium/components/browser_sync/browser/signin_confirmation_helper.cc b/chromium/components/browser_sync/browser/signin_confirmation_helper.cc
deleted file mode 100644
index 096231a9b87..00000000000
--- a/chromium/components/browser_sync/browser/signin_confirmation_helper.cc
+++ /dev/null
@@ -1,118 +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 "components/browser_sync/browser/signin_confirmation_helper.h"
-
-#include "base/strings/string16.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/history/core/browser/history_backend.h"
-#include "components/history/core/browser/history_db_task.h"
-#include "components/history/core/browser/history_service.h"
-#include "components/history/core/browser/history_types.h"
-
-namespace {
-
-// Determines whether there are any typed URLs in a history backend.
-class HasTypedURLsTask : public history::HistoryDBTask {
- public:
- explicit HasTypedURLsTask(const base::Callback<void(bool)>& cb)
- : has_typed_urls_(false), cb_(cb) {}
-
- bool RunOnDBThread(history::HistoryBackend* backend,
- history::HistoryDatabase* db) override {
- history::URLRows rows;
- backend->GetAllTypedURLs(&rows);
- if (!rows.empty()) {
- DVLOG(1) << "SigninConfirmationHelper: history contains " << rows.size()
- << " typed URLs";
- has_typed_urls_ = true;
- }
- return true;
- }
-
- void DoneRunOnMainThread() override { cb_.Run(has_typed_urls_); }
-
- private:
- ~HasTypedURLsTask() override {}
-
- bool has_typed_urls_;
- base::Callback<void(bool)> cb_;
-};
-
-} // namespace
-
-namespace sync_driver {
-
-SigninConfirmationHelper::SigninConfirmationHelper(
- history::HistoryService* history_service,
- const base::Callback<void(bool)>& return_result)
- : origin_thread_(base::ThreadTaskRunnerHandle::Get()),
- history_service_(history_service),
- pending_requests_(0),
- return_result_(return_result) {}
-
-SigninConfirmationHelper::~SigninConfirmationHelper() {
- DCHECK(origin_thread_->BelongsToCurrentThread());
-}
-
-void SigninConfirmationHelper::OnHistoryQueryResults(
- size_t max_entries,
- history::QueryResults* results) {
- history::QueryResults owned_results;
- results->Swap(&owned_results);
- bool too_much_history = owned_results.size() >= max_entries;
- if (too_much_history) {
- DVLOG(1) << "SigninConfirmationHelper: profile contains "
- << owned_results.size() << " history entries";
- }
- ReturnResult(too_much_history);
-}
-
-void SigninConfirmationHelper::CheckHasHistory(int max_entries) {
- pending_requests_++;
- if (!history_service_) {
- PostResult(false);
- return;
- }
- history::QueryOptions opts;
- opts.max_count = max_entries;
- history_service_->QueryHistory(
- base::string16(), opts,
- base::Bind(&SigninConfirmationHelper::OnHistoryQueryResults,
- base::Unretained(this), max_entries),
- &task_tracker_);
-}
-
-void SigninConfirmationHelper::CheckHasTypedURLs() {
- pending_requests_++;
- if (!history_service_) {
- PostResult(false);
- return;
- }
- history_service_->ScheduleDBTask(
- std::unique_ptr<history::HistoryDBTask>(new HasTypedURLsTask(base::Bind(
- &SigninConfirmationHelper::ReturnResult, base::Unretained(this)))),
- &task_tracker_);
-}
-
-void SigninConfirmationHelper::PostResult(bool result) {
- origin_thread_->PostTask(FROM_HERE,
- base::Bind(&SigninConfirmationHelper::ReturnResult,
- base::Unretained(this), result));
-}
-
-void SigninConfirmationHelper::ReturnResult(bool result) {
- DCHECK(origin_thread_->BelongsToCurrentThread());
- // Pass |true| into the callback as soon as one of the tasks passes a
- // result of |true|, otherwise pass the last returned result.
- if (--pending_requests_ == 0 || result) {
- return_result_.Run(result);
-
- // This leaks at shutdown if the HistoryService is destroyed, but
- // the process is going to die anyway.
- delete this;
- }
-}
-
-} // namespace sync_driver
diff --git a/chromium/components/browser_sync/browser/signin_confirmation_helper.h b/chromium/components/browser_sync/browser/signin_confirmation_helper.h
deleted file mode 100644
index fd0e7d4393c..00000000000
--- a/chromium/components/browser_sync/browser/signin_confirmation_helper.h
+++ /dev/null
@@ -1,70 +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 COMPONENTS_BROWSER_SYNC_BROWSER_SIGNIN_CONFIRMATION_HELPER_
-#define COMPONENTS_BROWSER_SYNC_BROWSER_SIGNIN_CONFIRMATION_HELPER_
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/task/cancelable_task_tracker.h"
-
-namespace history {
-class HistoryService;
-class QueryResults;
-}
-
-namespace sync_driver {
-
-// Helper class for sync signin to check some asynchronous conditions. Call
-// either CheckHasHistory or CheckHasTypedUrls or both, and |return_result|
-// will be called with true if either returns true, otherwise false.
-class SigninConfirmationHelper {
- public:
- SigninConfirmationHelper(history::HistoryService* history_service,
- const base::Callback<void(bool)>& return_result);
-
- // This helper checks if there are history entries in the history service.
- void CheckHasHistory(int max_entries);
-
- // This helper checks if there are typed URLs in the history service.
- void CheckHasTypedURLs();
-
- private:
- // Deletes itself.
- ~SigninConfirmationHelper();
-
- // Callback helper function for CheckHasHistory.
- void OnHistoryQueryResults(size_t max_entries,
- history::QueryResults* results);
-
- // Posts the given result to the origin thread.
- void PostResult(bool result);
-
- // Calls |return_result_| if |result| == true or if it's the result of the
- // last pending check.
- void ReturnResult(bool result);
-
- // The task runner for the thread this object was constructed on.
- const scoped_refptr<base::SingleThreadTaskRunner> origin_thread_;
-
- // Pointer to the history service.
- history::HistoryService* history_service_;
-
- // Used for async tasks.
- base::CancelableTaskTracker task_tracker_;
-
- // Keep track of how many async requests are pending.
- int pending_requests_;
-
- // Callback to pass the result back to the caller.
- const base::Callback<void(bool)> return_result_;
-
- DISALLOW_COPY_AND_ASSIGN(SigninConfirmationHelper);
-};
-
-} // namespace sync_driver
-
-#endif // COMPONENTS_BROWSER_SYNC_BROWSER_SIGNIN_CONFIRMATION_HELPER_
diff --git a/chromium/components/browser_sync/browser/test_http_bridge_factory.cc b/chromium/components/browser_sync/browser/test_http_bridge_factory.cc
deleted file mode 100644
index b38bb6e7ee9..00000000000
--- a/chromium/components/browser_sync/browser/test_http_bridge_factory.cc
+++ /dev/null
@@ -1,46 +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 "components/browser_sync/browser/test_http_bridge_factory.h"
-
-namespace browser_sync {
-
-bool TestHttpBridge::MakeSynchronousPost(int* error_code,
- int* response_code) {
- return false;
-}
-
-int TestHttpBridge::GetResponseContentLength() const {
- return 0;
-}
-
-const char* TestHttpBridge::GetResponseContent() const {
- return 0;
-}
-
-const std::string TestHttpBridge::GetResponseHeaderValue(
- const std::string &) const {
- return std::string();
-}
-
-void TestHttpBridge::Abort() {
-}
-
-TestHttpBridgeFactory::TestHttpBridgeFactory() {}
-
-TestHttpBridgeFactory::~TestHttpBridgeFactory() {}
-
-void TestHttpBridgeFactory::Init(
- const std::string& user_agent,
- const syncer::BindToTrackerCallback& bind_to_tracker_callback) {}
-
-syncer::HttpPostProviderInterface* TestHttpBridgeFactory::Create() {
- return new TestHttpBridge();
-}
-
-void TestHttpBridgeFactory::Destroy(syncer::HttpPostProviderInterface* http) {
- delete static_cast<TestHttpBridge*>(http);
-}
-
-} // namespace browser_sync
diff --git a/chromium/components/browser_sync/browser/test_http_bridge_factory.h b/chromium/components/browser_sync/browser/test_http_bridge_factory.h
deleted file mode 100644
index b4c26082037..00000000000
--- a/chromium/components/browser_sync/browser/test_http_bridge_factory.h
+++ /dev/null
@@ -1,52 +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 COMPONENTS_BROWSER_SYNC_BROWSER_TEST_HTTP_BRIDGE_FACTORY_H_
-#define COMPONENTS_BROWSER_SYNC_BROWSER_TEST_HTTP_BRIDGE_FACTORY_H_
-
-#include "base/compiler_specific.h"
-#include "sync/internal_api/public/http_post_provider_factory.h"
-#include "sync/internal_api/public/http_post_provider_interface.h"
-
-namespace browser_sync {
-
-class TestHttpBridge : public syncer::HttpPostProviderInterface {
- public:
- // Begin syncer::HttpPostProviderInterface implementation:
- void SetExtraRequestHeaders(const char* headers) override {}
-
- void SetURL(const char* url, int port) override {}
-
- void SetPostPayload(const char* content_type,
- int content_length,
- const char* content) override {}
-
- bool MakeSynchronousPost(int* error_code, int* response_code) override;
-
- int GetResponseContentLength() const override;
-
- const char* GetResponseContent() const override;
-
- const std::string GetResponseHeaderValue(const std::string&) const override;
-
- void Abort() override;
- // End syncer::HttpPostProviderInterface implementation.
-};
-
-class TestHttpBridgeFactory : public syncer::HttpPostProviderFactory {
- public:
- TestHttpBridgeFactory();
- ~TestHttpBridgeFactory() override;
-
- // syncer::HttpPostProviderFactory:
- void Init(
- const std::string& user_agent,
- const syncer::BindToTrackerCallback& bind_to_tracker_callback) override;
- syncer::HttpPostProviderInterface* Create() override;
- void Destroy(syncer::HttpPostProviderInterface* http) override;
-};
-
-} // namespace browser_sync
-
-#endif // COMPONENTS_BROWSER_SYNC_BROWSER_TEST_HTTP_BRIDGE_FACTORY_H_
diff --git a/chromium/components/browser_sync/browser/test_profile_sync_service.cc b/chromium/components/browser_sync/browser/test_profile_sync_service.cc
deleted file mode 100644
index 48ede525fde..00000000000
--- a/chromium/components/browser_sync/browser/test_profile_sync_service.cc
+++ /dev/null
@@ -1,32 +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 "components/browser_sync/browser/test_profile_sync_service.h"
-
-#include <utility>
-
-syncer::TestIdFactory* TestProfileSyncService::id_factory() {
- return &id_factory_;
-}
-
-syncer::WeakHandle<syncer::JsEventHandler>
-TestProfileSyncService::GetJsEventHandler() {
- return syncer::WeakHandle<syncer::JsEventHandler>();
-}
-
-TestProfileSyncService::TestProfileSyncService(
- ProfileSyncService::InitParams init_params)
- : ProfileSyncService(std::move(init_params)) {}
-
-TestProfileSyncService::~TestProfileSyncService() {}
-
-void TestProfileSyncService::OnConfigureDone(
- const sync_driver::DataTypeManager::ConfigureResult& result) {
- ProfileSyncService::OnConfigureDone(result);
- base::MessageLoop::current()->QuitWhenIdle();
-}
-
-syncer::UserShare* TestProfileSyncService::GetUserShare() const {
- return backend_->GetUserShare();
-}
diff --git a/chromium/components/browser_sync/browser/test_profile_sync_service.h b/chromium/components/browser_sync/browser/test_profile_sync_service.h
deleted file mode 100644
index abd82aa5cff..00000000000
--- a/chromium/components/browser_sync/browser/test_profile_sync_service.h
+++ /dev/null
@@ -1,50 +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 COMPONENTS_BROWSER_SYNC_BROWSER_TEST_PROFILE_SYNC_SERVICE_H_
-#define COMPONENTS_BROWSER_SYNC_BROWSER_TEST_PROFILE_SYNC_SERVICE_H_
-
-#include "base/macros.h"
-#include "components/browser_sync/browser/profile_sync_service.h"
-#include "components/sync_driver/data_type_manager.h"
-#include "sync/internal_api/public/util/weak_handle.h"
-#include "sync/js/js_event_handler.h"
-#include "sync/test/engine/test_id_factory.h"
-
-namespace sync_driver {
-class SyncPrefs;
-} // namespace sync_driver
-
-class TestProfileSyncService : public ProfileSyncService {
- public:
- explicit TestProfileSyncService(InitParams init_params);
-
- ~TestProfileSyncService() override;
-
- void OnConfigureDone(
- const sync_driver::DataTypeManager::ConfigureResult& result) override;
-
- // We implement our own version to avoid some DCHECKs.
- syncer::UserShare* GetUserShare() const override;
-
- syncer::TestIdFactory* id_factory();
-
- // Raise visibility to ease testing.
- using ProfileSyncService::NotifyObservers;
-
- sync_driver::SyncPrefs* sync_prefs() { return &sync_prefs_; }
-
- protected:
- // Return NULL handle to use in backend initialization to avoid receiving
- // js messages on UI loop when it's being destroyed, which are not deleted
- // and cause memory leak in test.
- syncer::WeakHandle<syncer::JsEventHandler> GetJsEventHandler() override;
-
- private:
- syncer::TestIdFactory id_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(TestProfileSyncService);
-};
-
-#endif // COMPONENTS_BROWSER_SYNC_BROWSER_TEST_PROFILE_SYNC_SERVICE_H_
diff --git a/chromium/components/browser_sync/browser_sync_switches.cc b/chromium/components/browser_sync/browser_sync_switches.cc
new file mode 100644
index 00000000000..b354cdb91c3
--- /dev/null
+++ b/chromium/components/browser_sync/browser_sync_switches.cc
@@ -0,0 +1,22 @@
+// 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 "components/browser_sync/browser_sync_switches.h"
+
+namespace switches {
+
+// Disables syncing browser data to a Google Account.
+const char kDisableSync[] = "disable-sync";
+
+// Disables syncing one or more sync data types that are on by default.
+// See sync/base/model_type.h for possible types. Types
+// should be comma separated, and follow the naming convention for string
+// representation of model types, e.g.:
+// --disable-synctypes='Typed URLs, Bookmarks, Autofill Profiles'
+const char kDisableSyncTypes[] = "disable-sync-types";
+
+// Enables synchronizing WiFi credentials across devices, using Chrome Sync.
+const char kEnableWifiCredentialSync[] = "enable-wifi-credential-sync";
+
+} // namespace switches
diff --git a/chromium/components/browser_sync/browser_sync_switches.h b/chromium/components/browser_sync/browser_sync_switches.h
new file mode 100644
index 00000000000..d2376a42e96
--- /dev/null
+++ b/chromium/components/browser_sync/browser_sync_switches.h
@@ -0,0 +1,18 @@
+// 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.
+
+// Defines all the command-line switches used by //components/browser_sync.
+
+#ifndef COMPONENTS_BROWSER_SYNC_BROWSER_SYNC_SWITCHES_H_
+#define COMPONENTS_BROWSER_SYNC_BROWSER_SYNC_SWITCHES_H_
+
+namespace switches {
+
+extern const char kDisableSync[];
+extern const char kDisableSyncTypes[];
+extern const char kEnableWifiCredentialSync[];
+
+} // namespace switches
+
+#endif // COMPONENTS_BROWSER_SYNC_BROWSER_SYNC_SWITCHES_H_
diff --git a/chromium/components/browser_sync/common/BUILD.gn b/chromium/components/browser_sync/common/BUILD.gn
deleted file mode 100644
index 8fcae92bbf0..00000000000
--- a/chromium/components/browser_sync/common/BUILD.gn
+++ /dev/null
@@ -1,16 +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.
-
-import("//build/config/features.gni")
-
-source_set("common") {
- sources = [
- "browser_sync_switches.cc",
- "browser_sync_switches.h",
- ]
-
- deps = [
- "//base",
- ]
-}
diff --git a/chromium/components/browser_sync/common/browser_sync_switches.cc b/chromium/components/browser_sync/common/browser_sync_switches.cc
deleted file mode 100644
index 927d31c328d..00000000000
--- a/chromium/components/browser_sync/common/browser_sync_switches.cc
+++ /dev/null
@@ -1,22 +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 "components/browser_sync/common/browser_sync_switches.h"
-
-namespace switches {
-
-// Disables syncing browser data to a Google Account.
-const char kDisableSync[] = "disable-sync";
-
-// Disables syncing one or more sync data types that are on by default.
-// See sync/internal_api/public/base/model_type.h for possible types. Types
-// should be comma separated, and follow the naming convention for string
-// representation of model types, e.g.:
-// --disable-synctypes='Typed URLs, Bookmarks, Autofill Profiles'
-const char kDisableSyncTypes[] = "disable-sync-types";
-
-// Enables synchronizing WiFi credentials across devices, using Chrome Sync.
-const char kEnableWifiCredentialSync[] = "enable-wifi-credential-sync";
-
-} // namespace switches
diff --git a/chromium/components/browser_sync/common/browser_sync_switches.h b/chromium/components/browser_sync/common/browser_sync_switches.h
deleted file mode 100644
index e8d02358fa0..00000000000
--- a/chromium/components/browser_sync/common/browser_sync_switches.h
+++ /dev/null
@@ -1,18 +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.
-
-// Defines all the command-line switches used by //components/browser_sync.
-
-#ifndef COMPONENTS_BROWSER_SYNC_COMMON_BROWSER_SYNC_SWITCHES_H_
-#define COMPONENTS_BROWSER_SYNC_COMMON_BROWSER_SYNC_SWITCHES_H_
-
-namespace switches {
-
-extern const char kDisableSync[];
-extern const char kDisableSyncTypes[];
-extern const char kEnableWifiCredentialSync[];
-
-} // namespace switches
-
-#endif // COMPONENTS_BROWSER_SYNC_COMMON_BROWSER_SYNC_SWITCHES_H_
diff --git a/chromium/components/browser_sync/profile_sync_components_factory_impl.cc b/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
new file mode 100644
index 00000000000..7aab9bc8a91
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -0,0 +1,430 @@
+// 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 "components/browser_sync/profile_sync_components_factory_impl.h"
+
+#include <utility>
+
+#include "base/debug/dump_without_crashing.h"
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_wallet_data_type_controller.h"
+#include "components/autofill/core/browser/webdata/autofill_data_type_controller.h"
+#include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/common/autofill_pref_names.h"
+#include "components/autofill/core/common/autofill_switches.h"
+#include "components/browser_sync/browser_sync_switches.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/dom_distiller/core/dom_distiller_features.h"
+#include "components/history/core/browser/history_delete_directives_data_type_controller.h"
+#include "components/history/core/browser/typed_url_data_type_controller.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/sync/browser/password_data_type_controller.h"
+#include "components/prefs/pref_service.h"
+#include "components/sync/core/attachments/attachment_downloader.h"
+#include "components/sync/core/attachments/attachment_service.h"
+#include "components/sync/core/attachments/attachment_service_impl.h"
+#include "components/sync/core/attachments/attachment_uploader_impl.h"
+#include "components/sync/device_info/device_info_data_type_controller.h"
+#include "components/sync/device_info/local_device_info_provider_impl.h"
+#include "components/sync/driver/data_type_manager_impl.h"
+#include "components/sync/driver/glue/chrome_report_unrecoverable_error.h"
+#include "components/sync/driver/glue/sync_backend_host.h"
+#include "components/sync/driver/glue/sync_backend_host_impl.h"
+#include "components/sync/driver/model_type_controller.h"
+#include "components/sync/driver/proxy_data_type_controller.h"
+#include "components/sync/driver/sync_client.h"
+#include "components/sync/driver/sync_driver_switches.h"
+#include "components/sync/driver/ui_data_type_controller.h"
+#include "components/sync_bookmarks/bookmark_change_processor.h"
+#include "components/sync_bookmarks/bookmark_data_type_controller.h"
+#include "components/sync_bookmarks/bookmark_model_associator.h"
+#include "components/sync_sessions/session_data_type_controller.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "google_apis/gaia/oauth2_token_service_request.h"
+#include "net/url_request/url_request_context_getter.h"
+
+using bookmarks::BookmarkModel;
+using sync_bookmarks::BookmarkChangeProcessor;
+using sync_bookmarks::BookmarkDataTypeController;
+using sync_bookmarks::BookmarkModelAssociator;
+using syncer::DataTypeController;
+using syncer::DataTypeManager;
+using syncer::DataTypeManagerImpl;
+using syncer::DataTypeManagerObserver;
+using syncer::DeviceInfoDataTypeController;
+using syncer::ProxyDataTypeController;
+using syncer::UIDataTypeController;
+using syncer::ModelTypeController;
+using sync_sessions::SessionDataTypeController;
+
+namespace browser_sync {
+
+namespace {
+
+syncer::ModelTypeSet GetDisabledTypesFromCommandLine(
+ const base::CommandLine& command_line) {
+ syncer::ModelTypeSet disabled_types;
+ std::string disabled_types_str =
+ command_line.GetSwitchValueASCII(switches::kDisableSyncTypes);
+
+ disabled_types = syncer::ModelTypeSetFromString(disabled_types_str);
+ return disabled_types;
+}
+
+syncer::ModelTypeSet GetEnabledTypesFromCommandLine(
+ const base::CommandLine& command_line) {
+ return syncer::ModelTypeSet();
+}
+
+// Used to gate syncing preferences, see crbug.com/374865 for more information.
+// Has always been on for desktop/ChromeOS, so default to on. This feature is
+// mainly to give us a kill switch should something go wrong with starting to
+// sync prefs on mobile.
+const base::Feature kSyncPreferencesFeature{"SyncPreferences",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+} // namespace
+
+ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl(
+ syncer::SyncClient* sync_client,
+ version_info::Channel channel,
+ const std::string& version,
+ bool is_tablet,
+ const base::CommandLine& command_line,
+ const char* history_disabled_pref,
+ const GURL& sync_service_url,
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+ OAuth2TokenService* token_service,
+ net::URLRequestContextGetter* url_request_context_getter,
+ const scoped_refptr<autofill::AutofillWebDataService>& web_data_service,
+ const scoped_refptr<password_manager::PasswordStore>& password_store)
+ : sync_client_(sync_client),
+ channel_(channel),
+ version_(version),
+ is_tablet_(is_tablet),
+ command_line_(command_line),
+ history_disabled_pref_(history_disabled_pref),
+ sync_service_url_(sync_service_url),
+ ui_thread_(ui_thread),
+ db_thread_(db_thread),
+ token_service_(token_service),
+ url_request_context_getter_(url_request_context_getter),
+ web_data_service_(web_data_service),
+ password_store_(password_store),
+ weak_factory_(this) {
+ DCHECK(token_service_);
+ DCHECK(url_request_context_getter_);
+}
+
+ProfileSyncComponentsFactoryImpl::~ProfileSyncComponentsFactoryImpl() {}
+
+void ProfileSyncComponentsFactoryImpl::RegisterDataTypes(
+ syncer::SyncService* sync_service,
+ const RegisterDataTypesMethod& register_platform_types_method) {
+ syncer::ModelTypeSet disabled_types =
+ GetDisabledTypesFromCommandLine(command_line_);
+ syncer::ModelTypeSet enabled_types =
+ GetEnabledTypesFromCommandLine(command_line_);
+ RegisterCommonDataTypes(sync_service, disabled_types, enabled_types);
+ if (!register_platform_types_method.is_null())
+ register_platform_types_method.Run(sync_service, disabled_types,
+ enabled_types);
+}
+
+void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
+ syncer::SyncService* sync_service,
+ syncer::ModelTypeSet disabled_types,
+ syncer::ModelTypeSet enabled_types) {
+ base::Closure error_callback =
+ base::Bind(&syncer::ChromeReportUnrecoverableError, channel_);
+
+ // TODO(stanisc): can DEVICE_INFO be one of disabled datatypes?
+ if (base::FeatureList::IsEnabled(switches::kSyncUSSDeviceInfo)) {
+ // Use an error callback that always uploads a stacktrace if it can to help
+ // get USS as stable as possible.
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<ModelTypeController>(
+ syncer::DEVICE_INFO, base::Bind(&base::debug::DumpWithoutCrashing),
+ sync_client_, base::ThreadTaskRunnerHandle::Get()));
+ } else {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<DeviceInfoDataTypeController>(
+ error_callback, sync_client_,
+ sync_service->GetLocalDeviceInfoProvider()));
+ }
+
+ // Autofill sync is enabled by default. Register unless explicitly
+ // disabled.
+ if (!disabled_types.Has(syncer::AUTOFILL)) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<AutofillDataTypeController>(
+ db_thread_, error_callback, sync_client_, web_data_service_));
+ }
+
+ // Autofill profile sync is enabled by default. Register unless explicitly
+ // disabled.
+ if (!disabled_types.Has(syncer::AUTOFILL_PROFILE)) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<AutofillProfileDataTypeController>(
+ db_thread_, error_callback, sync_client_, web_data_service_));
+ }
+
+ // Wallet data sync is enabled by default, but behind a syncer experiment
+ // enforced by the datatype controller. Register unless explicitly disabled.
+ bool wallet_disabled = disabled_types.Has(syncer::AUTOFILL_WALLET_DATA);
+ if (!wallet_disabled) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<AutofillWalletDataTypeController>(
+ syncer::AUTOFILL_WALLET_DATA, db_thread_, error_callback,
+ sync_client_, web_data_service_));
+ }
+
+ // Wallet metadata sync depends on Wallet data sync. Register if Wallet data
+ // is syncing and metadata sync is not explicitly disabled.
+ if (!wallet_disabled &&
+ !disabled_types.Has(syncer::AUTOFILL_WALLET_METADATA)) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<AutofillWalletDataTypeController>(
+ syncer::AUTOFILL_WALLET_METADATA, db_thread_, error_callback,
+ sync_client_, web_data_service_));
+ }
+
+ // Bookmark sync is enabled by default. Register unless explicitly
+ // disabled.
+ if (!disabled_types.Has(syncer::BOOKMARKS)) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<BookmarkDataTypeController>(error_callback,
+ sync_client_));
+ }
+
+ const bool history_disabled =
+ sync_client_->GetPrefService()->GetBoolean(history_disabled_pref_);
+ // TypedUrl sync is enabled by default. Register unless explicitly disabled,
+ // or if saving history is disabled.
+ if (!disabled_types.Has(syncer::TYPED_URLS) && !history_disabled) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<TypedUrlDataTypeController>(
+ error_callback, sync_client_, history_disabled_pref_));
+ }
+
+ // Delete directive sync is enabled by default. Register unless full history
+ // sync is disabled.
+ if (!disabled_types.Has(syncer::HISTORY_DELETE_DIRECTIVES) &&
+ !history_disabled) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<HistoryDeleteDirectivesDataTypeController>(
+ error_callback, sync_client_));
+ }
+
+ // Session sync is enabled by default. Register unless explicitly disabled.
+ // This is also disabled if the browser history is disabled, because the
+ // tab sync data is added to the web history on the server.
+ if (!disabled_types.Has(syncer::PROXY_TABS) && !history_disabled) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<ProxyDataTypeController>(syncer::PROXY_TABS));
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<SessionDataTypeController>(
+ error_callback, sync_client_,
+ sync_service->GetLocalDeviceInfoProvider(),
+ history_disabled_pref_));
+ }
+
+ // Favicon sync is enabled by default. Register unless explicitly disabled.
+ if (!disabled_types.Has(syncer::FAVICON_IMAGES) &&
+ !disabled_types.Has(syncer::FAVICON_TRACKING) && !history_disabled) {
+ // crbug/384552. We disable error uploading for this data types for now.
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<UIDataTypeController>(syncer::FAVICON_IMAGES,
+ base::Closure(), sync_client_));
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<UIDataTypeController>(syncer::FAVICON_TRACKING,
+ base::Closure(), sync_client_));
+ }
+
+ // Password sync is enabled by default. Register unless explicitly
+ // disabled.
+ if (!disabled_types.Has(syncer::PASSWORDS)) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<PasswordDataTypeController>(
+ error_callback, sync_client_,
+ sync_client_->GetPasswordStateChangedCallback(), password_store_));
+ }
+
+ if (!disabled_types.Has(syncer::PREFERENCES) &&
+ base::FeatureList::IsEnabled(kSyncPreferencesFeature)) {
+ if (!override_prefs_controller_to_uss_for_test_) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<UIDataTypeController>(syncer::PREFERENCES,
+ error_callback, sync_client_));
+ } else {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<ModelTypeController>(
+ syncer::PREFERENCES, error_callback, sync_client_,
+ base::ThreadTaskRunnerHandle::Get()));
+ }
+ }
+
+ if (!disabled_types.Has(syncer::PRIORITY_PREFERENCES)) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<UIDataTypeController>(syncer::PRIORITY_PREFERENCES,
+ error_callback, sync_client_));
+ }
+
+ // Article sync is disabled by default. Register only if explicitly enabled.
+ if (dom_distiller::IsEnableSyncArticlesSet()) {
+ sync_service->RegisterDataTypeController(
+ base::MakeUnique<UIDataTypeController>(syncer::ARTICLES, error_callback,
+ sync_client_));
+ }
+}
+
+DataTypeManager* ProfileSyncComponentsFactoryImpl::CreateDataTypeManager(
+ const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
+ debug_info_listener,
+ const DataTypeController::TypeMap* controllers,
+ const syncer::DataTypeEncryptionHandler* encryption_handler,
+ syncer::SyncBackendHost* backend,
+ DataTypeManagerObserver* observer) {
+ return new DataTypeManagerImpl(debug_info_listener, controllers,
+ encryption_handler, backend, observer);
+}
+
+syncer::SyncBackendHost*
+ProfileSyncComponentsFactoryImpl::CreateSyncBackendHost(
+ const std::string& name,
+ invalidation::InvalidationService* invalidator,
+ const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
+ const base::FilePath& sync_folder) {
+ return new syncer::SyncBackendHostImpl(name, sync_client_, ui_thread_,
+ invalidator, sync_prefs, sync_folder);
+}
+
+std::unique_ptr<syncer::LocalDeviceInfoProvider>
+ProfileSyncComponentsFactoryImpl::CreateLocalDeviceInfoProvider() {
+ return base::MakeUnique<syncer::LocalDeviceInfoProviderImpl>(
+ channel_, version_, is_tablet_);
+}
+
+class TokenServiceProvider
+ : public OAuth2TokenServiceRequest::TokenServiceProvider {
+ public:
+ TokenServiceProvider(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ OAuth2TokenService* token_service);
+
+ // OAuth2TokenServiceRequest::TokenServiceProvider implementation.
+ scoped_refptr<base::SingleThreadTaskRunner> GetTokenServiceTaskRunner()
+ override;
+ OAuth2TokenService* GetTokenService() override;
+
+ private:
+ ~TokenServiceProvider() override;
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ OAuth2TokenService* token_service_;
+};
+
+TokenServiceProvider::TokenServiceProvider(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ OAuth2TokenService* token_service)
+ : task_runner_(task_runner), token_service_(token_service) {}
+
+TokenServiceProvider::~TokenServiceProvider() {}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+TokenServiceProvider::GetTokenServiceTaskRunner() {
+ return task_runner_;
+}
+
+OAuth2TokenService* TokenServiceProvider::GetTokenService() {
+ return token_service_;
+}
+
+std::unique_ptr<syncer::AttachmentService>
+ProfileSyncComponentsFactoryImpl::CreateAttachmentService(
+ std::unique_ptr<syncer::AttachmentStoreForSync> attachment_store,
+ const syncer::UserShare& user_share,
+ const std::string& store_birthday,
+ syncer::ModelType model_type,
+ syncer::AttachmentService::Delegate* delegate) {
+ std::unique_ptr<syncer::AttachmentUploader> attachment_uploader;
+ std::unique_ptr<syncer::AttachmentDownloader> attachment_downloader;
+ // Only construct an AttachmentUploader and AttachmentDownload if we have sync
+ // credentials. We may not have sync credentials because there may not be a
+ // signed in sync user.
+ if (!user_share.sync_credentials.account_id.empty() &&
+ !user_share.sync_credentials.scope_set.empty()) {
+ scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>
+ token_service_provider(
+ new TokenServiceProvider(ui_thread_, token_service_));
+ // TODO(maniscalco): Use shared (one per profile) thread-safe instances of
+ // AttachmentUploader and AttachmentDownloader instead of creating a new one
+ // per AttachmentService (bug 369536).
+ attachment_uploader.reset(new syncer::AttachmentUploaderImpl(
+ sync_service_url_, url_request_context_getter_,
+ user_share.sync_credentials.account_id,
+ user_share.sync_credentials.scope_set, token_service_provider,
+ store_birthday, model_type));
+
+ token_service_provider =
+ new TokenServiceProvider(ui_thread_, token_service_);
+ attachment_downloader = syncer::AttachmentDownloader::Create(
+ sync_service_url_, url_request_context_getter_,
+ user_share.sync_credentials.account_id,
+ user_share.sync_credentials.scope_set, token_service_provider,
+ store_birthday, model_type);
+ }
+
+ // It is important that the initial backoff delay is relatively large. For
+ // whatever reason, the server may fail all requests for a short period of
+ // time. When this happens we don't want to overwhelm the server with
+ // requests so we use a large initial backoff.
+ const base::TimeDelta initial_backoff_delay =
+ base::TimeDelta::FromMinutes(30);
+ const base::TimeDelta max_backoff_delay = base::TimeDelta::FromHours(4);
+ std::unique_ptr<syncer::AttachmentService> attachment_service(
+ new syncer::AttachmentServiceImpl(
+ std::move(attachment_store), std::move(attachment_uploader),
+ std::move(attachment_downloader), delegate, initial_backoff_delay,
+ max_backoff_delay));
+ return attachment_service;
+}
+
+syncer::SyncApiComponentFactory::SyncComponents
+ProfileSyncComponentsFactoryImpl::CreateBookmarkSyncComponents(
+ syncer::SyncService* sync_service,
+ std::unique_ptr<syncer::DataTypeErrorHandler> error_handler) {
+ BookmarkModel* bookmark_model =
+ sync_service->GetSyncClient()->GetBookmarkModel();
+ syncer::UserShare* user_share = sync_service->GetUserShare();
+// TODO(akalin): We may want to propagate this switch up eventually.
+#if defined(OS_ANDROID) || defined(OS_IOS)
+ const bool kExpectMobileBookmarksFolder = true;
+#else
+ const bool kExpectMobileBookmarksFolder = false;
+#endif
+ BookmarkModelAssociator* model_associator = new BookmarkModelAssociator(
+ bookmark_model, sync_service->GetSyncClient(), user_share,
+ error_handler->Copy(), kExpectMobileBookmarksFolder);
+ BookmarkChangeProcessor* change_processor =
+ new BookmarkChangeProcessor(sync_service->GetSyncClient(),
+ model_associator, std::move(error_handler));
+ return SyncComponents(model_associator, change_processor);
+}
+
+// static
+void ProfileSyncComponentsFactoryImpl::OverridePrefsForUssTest(bool use_uss) {
+ override_prefs_controller_to_uss_for_test_ = use_uss;
+}
+
+bool ProfileSyncComponentsFactoryImpl::
+ override_prefs_controller_to_uss_for_test_ = false;
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_components_factory_impl.h b/chromium/components/browser_sync/profile_sync_components_factory_impl.h
new file mode 100644
index 00000000000..de43525d415
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_components_factory_impl.h
@@ -0,0 +1,133 @@
+// 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 COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_COMPONENTS_FACTORY_IMPL_H__
+#define COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_COMPONENTS_FACTORY_IMPL_H__
+
+#include <memory>
+#include <string>
+
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/driver/sync_api_component_factory.h"
+#include "components/version_info/version_info.h"
+#include "url/gurl.h"
+
+class OAuth2TokenService;
+class Profile;
+
+namespace autofill {
+class AutofillWebDataService;
+}
+
+namespace password_manager {
+class PasswordStore;
+}
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace browser_sync {
+
+class ProfileSyncComponentsFactoryImpl
+ : public syncer::SyncApiComponentFactory {
+ public:
+ // Constructs a ProfileSyncComponentsFactoryImpl.
+ //
+ // |sync_service_url| is the base URL of the sync server.
+ //
+ // |token_service| must outlive the ProfileSyncComponentsFactoryImpl.
+ //
+ // |url_request_context_getter| must outlive the
+ // ProfileSyncComponentsFactoryImpl.
+ ProfileSyncComponentsFactoryImpl(
+ syncer::SyncClient* sync_client,
+ version_info::Channel channel,
+ const std::string& version,
+ bool is_tablet,
+ const base::CommandLine& command_line,
+ const char* history_disabled_pref,
+ const GURL& sync_service_url,
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+ OAuth2TokenService* token_service,
+ net::URLRequestContextGetter* url_request_context_getter,
+ const scoped_refptr<autofill::AutofillWebDataService>& web_data_service,
+ const scoped_refptr<password_manager::PasswordStore>& password_store);
+ ~ProfileSyncComponentsFactoryImpl() override;
+
+ // SyncApiComponentFactory implementation:
+ void RegisterDataTypes(
+ syncer::SyncService* sync_service,
+ const RegisterDataTypesMethod& register_platform_types_method) override;
+ syncer::DataTypeManager* CreateDataTypeManager(
+ const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
+ debug_info_listener,
+ const syncer::DataTypeController::TypeMap* controllers,
+ const syncer::DataTypeEncryptionHandler* encryption_handler,
+ syncer::SyncBackendHost* backend,
+ syncer::DataTypeManagerObserver* observer) override;
+ syncer::SyncBackendHost* CreateSyncBackendHost(
+ const std::string& name,
+ invalidation::InvalidationService* invalidator,
+ const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
+ const base::FilePath& sync_folder) override;
+ std::unique_ptr<syncer::LocalDeviceInfoProvider>
+ CreateLocalDeviceInfoProvider() override;
+ std::unique_ptr<syncer::AttachmentService> CreateAttachmentService(
+ std::unique_ptr<syncer::AttachmentStoreForSync> attachment_store,
+ const syncer::UserShare& user_share,
+ const std::string& store_birthday,
+ syncer::ModelType model_type,
+ syncer::AttachmentService::Delegate* delegate) override;
+ syncer::SyncApiComponentFactory::SyncComponents CreateBookmarkSyncComponents(
+ syncer::SyncService* sync_service,
+ std::unique_ptr<syncer::DataTypeErrorHandler> error_handler) override;
+
+ // Sets a bit that determines whether PREFERENCES should be registered with a
+ // ModelTypeController for testing purposes.
+ static void OverridePrefsForUssTest(bool use_uss);
+
+ private:
+ // Register data types which are enabled on both desktop and mobile.
+ // |disabled_types| and |enabled_types| correspond only to those types
+ // being explicitly enabled/disabled by the command line.
+ void RegisterCommonDataTypes(syncer::SyncService* sync_service,
+ syncer::ModelTypeSet disabled_types,
+ syncer::ModelTypeSet enabled_types);
+
+ void DisableBrokenType(syncer::ModelType type,
+ const tracked_objects::Location& from_here,
+ const std::string& message);
+
+ // Client/platform specific members.
+ syncer::SyncClient* const sync_client_;
+ const version_info::Channel channel_;
+ const std::string version_;
+ const bool is_tablet_;
+ const base::CommandLine command_line_;
+ const char* history_disabled_pref_;
+ const GURL sync_service_url_;
+ const scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
+ const scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+ OAuth2TokenService* const token_service_;
+ net::URLRequestContextGetter* const url_request_context_getter_;
+ const scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
+ const scoped_refptr<password_manager::PasswordStore> password_store_;
+
+ base::WeakPtrFactory<ProfileSyncComponentsFactoryImpl> weak_factory_;
+
+ // Whether to override PREFERENCES to use USS.
+ static bool override_prefs_controller_to_uss_for_test_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileSyncComponentsFactoryImpl);
+};
+
+} // namespace browser_sync
+
+#endif // COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_COMPONENTS_FACTORY_IMPL_H__
diff --git a/chromium/components/browser_sync/profile_sync_service.cc b/chromium/components/browser_sync/profile_sync_service.cc
new file mode 100644
index 00000000000..ab636d3a00a
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_service.cc
@@ -0,0 +1,2500 @@
+// 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 "components/browser_sync/profile_sync_service.h"
+
+#include <stddef.h>
+
+#include <cstddef>
+#include <map>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/autofill/core/common/autofill_pref_names.h"
+#include "components/browser_sync/browser_sync_switches.h"
+#include "components/history/core/browser/typed_url_data_type_controller.h"
+#include "components/invalidation/impl/invalidation_prefs.h"
+#include "components/invalidation/public/invalidation_service.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/json_pref_store.h"
+#include "components/signin/core/browser/about_signin_internals.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/browser/signin_metrics.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/sync/api/model_type_store.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/base/cryptographer.h"
+#include "components/sync/base/passphrase_type.h"
+#include "components/sync/base/stop_source.h"
+#include "components/sync/base/sync_db_util.h"
+#include "components/sync/core/configure_reason.h"
+#include "components/sync/core/http_bridge_network_resources.h"
+#include "components/sync/core/network_resources.h"
+#include "components/sync/core/shared_model_type_processor.h"
+#include "components/sync/core/sync_encryption_handler.h"
+#include "components/sync/device_info/device_info.h"
+#include "components/sync/device_info/device_info_service.h"
+#include "components/sync/device_info/device_info_sync_service.h"
+#include "components/sync/device_info/device_info_tracker.h"
+#include "components/sync/driver/backend_migrator.h"
+#include "components/sync/driver/change_processor.h"
+#include "components/sync/driver/directory_data_type_controller.h"
+#include "components/sync/driver/glue/chrome_report_unrecoverable_error.h"
+#include "components/sync/driver/glue/sync_backend_host_impl.h"
+#include "components/sync/driver/pref_names.h"
+#include "components/sync/driver/signin_manager_wrapper.h"
+#include "components/sync/driver/sync_api_component_factory.h"
+#include "components/sync/driver/sync_driver_switches.h"
+#include "components/sync/driver/sync_error_controller.h"
+#include "components/sync/driver/sync_type_preference_provider.h"
+#include "components/sync/driver/sync_util.h"
+#include "components/sync/driver/system_encryptor.h"
+#include "components/sync/driver/user_selectable_sync_type.h"
+#include "components/sync/engine/cycle/model_neutral_state.h"
+#include "components/sync/engine/cycle/type_debug_info_observer.h"
+#include "components/sync/engine/sync_string_conversions.h"
+#include "components/sync/js/js_event_details.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/syncable/directory.h"
+#include "components/sync/syncable/syncable_read_transaction.h"
+#include "components/sync_sessions/favicon_cache.h"
+#include "components/sync_sessions/session_data_type_controller.h"
+#include "components/sync_sessions/sessions_sync_manager.h"
+#include "components/sync_sessions/sync_sessions_client.h"
+#include "components/syncable_prefs/pref_service_syncable.h"
+#include "components/version_info/version_info_values.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
+
+#if defined(OS_ANDROID)
+#include "components/sync/core/read_transaction.h"
+#endif
+
+using sync_sessions::SessionsSyncManager;
+using syncer::BackendMigrator;
+using syncer::ChangeProcessor;
+using syncer::DataTypeController;
+using syncer::DataTypeManager;
+using syncer::DataTypeStatusTable;
+using syncer::DeviceInfoService;
+using syncer::DeviceInfoSyncService;
+using syncer::JsBackend;
+using syncer::JsController;
+using syncer::JsEventDetails;
+using syncer::JsEventHandler;
+using syncer::ModelSafeRoutingInfo;
+using syncer::ModelType;
+using syncer::ModelTypeSet;
+using syncer::ModelTypeStore;
+using syncer::ProtocolEventObserver;
+using syncer::SharedModelTypeProcessor;
+using syncer::SyncBackendHost;
+using syncer::SyncCredentials;
+using syncer::SyncProtocolError;
+using syncer::WeakHandle;
+
+namespace browser_sync {
+
+typedef GoogleServiceAuthError AuthError;
+
+const char kSyncUnrecoverableErrorHistogram[] = "Sync.UnrecoverableErrors";
+
+const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
+ // Number of initial errors (in sequence) to ignore before applying
+ // exponential back-off rules.
+ 0,
+
+ // Initial delay for exponential back-off in ms.
+ 2000,
+
+ // Factor by which the waiting time will be multiplied.
+ 2,
+
+ // Fuzzing percentage. ex: 10% will spread requests randomly
+ // between 90%-100% of the calculated time.
+ 0.2, // 20%
+
+ // Maximum amount of time we are willing to delay our request in ms.
+ // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
+ // RequestAccessToken on connection state change after backoff
+ 1000 * 3600 * 4, // 4 hours.
+
+ // Time to keep an entry from being discarded even when it
+ // has no significant state, -1 to never discard.
+ -1,
+
+ // Don't use initial delay unless the last request was an error.
+ false,
+};
+
+static const base::FilePath::CharType kSyncDataFolderName[] =
+ FILE_PATH_LITERAL("Sync Data");
+static const base::FilePath::CharType kLevelDBFolderName[] =
+ FILE_PATH_LITERAL("LevelDB");
+
+namespace {
+
+// Perform the actual sync data folder deletion.
+// This should only be called on the sync thread.
+void DeleteSyncDataFolder(const base::FilePath& directory_path) {
+ if (base::DirectoryExists(directory_path)) {
+ if (!base::DeleteFile(directory_path, true))
+ LOG(DFATAL) << "Could not delete the Sync Data folder.";
+ }
+}
+
+} // namespace
+
+bool ShouldShowActionOnUI(const syncer::SyncProtocolError& error) {
+ return (error.action != syncer::UNKNOWN_ACTION &&
+ error.action != syncer::DISABLE_SYNC_ON_CLIENT &&
+ error.action != syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT &&
+ error.action != syncer::RESET_LOCAL_SYNC_DATA);
+}
+
+ProfileSyncService::InitParams::InitParams() = default;
+ProfileSyncService::InitParams::~InitParams() = default;
+ProfileSyncService::InitParams::InitParams(InitParams&& other) // NOLINT
+ : sync_client(std::move(other.sync_client)),
+ signin_wrapper(std::move(other.signin_wrapper)),
+ oauth2_token_service(other.oauth2_token_service),
+ gaia_cookie_manager_service(other.gaia_cookie_manager_service),
+ start_behavior(other.start_behavior),
+ network_time_update_callback(
+ std::move(other.network_time_update_callback)),
+ base_directory(std::move(other.base_directory)),
+ url_request_context(std::move(other.url_request_context)),
+ debug_identifier(std::move(other.debug_identifier)),
+ channel(other.channel),
+ db_thread(std::move(other.db_thread)),
+ file_thread(std::move(other.file_thread)),
+ blocking_pool(other.blocking_pool) {}
+
+ProfileSyncService::ProfileSyncService(InitParams init_params)
+ : OAuth2TokenService::Consumer("sync"),
+ last_auth_error_(AuthError::AuthErrorNone()),
+ passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED),
+ sync_client_(std::move(init_params.sync_client)),
+ sync_prefs_(sync_client_->GetPrefService()),
+ sync_service_url_(
+ syncer::GetSyncServiceURL(*base::CommandLine::ForCurrentProcess(),
+ init_params.channel)),
+ network_time_update_callback_(
+ std::move(init_params.network_time_update_callback)),
+ base_directory_(init_params.base_directory),
+ url_request_context_(init_params.url_request_context),
+ debug_identifier_(std::move(init_params.debug_identifier)),
+ channel_(init_params.channel),
+ db_thread_(init_params.db_thread),
+ file_thread_(init_params.file_thread),
+ blocking_pool_(init_params.blocking_pool),
+ is_first_time_sync_configure_(false),
+ backend_initialized_(false),
+ sync_disabled_by_admin_(false),
+ is_auth_in_progress_(false),
+ signin_(std::move(init_params.signin_wrapper)),
+ unrecoverable_error_reason_(ERROR_REASON_UNSET),
+ expect_sync_configuration_aborted_(false),
+ encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()),
+ encrypt_everything_allowed_(true),
+ encrypt_everything_(false),
+ encryption_pending_(false),
+ configure_status_(DataTypeManager::UNKNOWN),
+ oauth2_token_service_(init_params.oauth2_token_service),
+ request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy),
+ connection_status_(syncer::CONNECTION_NOT_ATTEMPTED),
+ last_get_token_error_(GoogleServiceAuthError::AuthErrorNone()),
+ gaia_cookie_manager_service_(init_params.gaia_cookie_manager_service),
+ network_resources_(new syncer::HttpBridgeNetworkResources),
+ start_behavior_(init_params.start_behavior),
+ directory_path_(
+ base_directory_.Append(base::FilePath(kSyncDataFolderName))),
+ catch_up_configure_in_progress_(false),
+ passphrase_prompt_triggered_by_version_(false),
+ sync_enabled_weak_factory_(this),
+ weak_factory_(this) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sync_client_);
+ std::string last_version = sync_prefs_.GetLastRunVersion();
+ std::string current_version = PRODUCT_VERSION;
+ sync_prefs_.SetLastRunVersion(current_version);
+
+ // Check for a major version change. Note that the versions have format
+ // MAJOR.MINOR.BUILD.PATCH.
+ if (last_version.substr(0, last_version.find('.')) !=
+ current_version.substr(0, current_version.find('.'))) {
+ passphrase_prompt_triggered_by_version_ = true;
+ }
+}
+
+ProfileSyncService::~ProfileSyncService() {
+ if (gaia_cookie_manager_service_)
+ gaia_cookie_manager_service_->RemoveObserver(this);
+ sync_prefs_.RemoveSyncPrefObserver(this);
+ // Shutdown() should have been called before destruction.
+ CHECK(!backend_initialized_);
+}
+
+bool ProfileSyncService::CanSyncStart() const {
+ return IsSyncAllowed() && IsSyncRequested() && IsSignedIn();
+}
+
+void ProfileSyncService::Initialize() {
+ sync_client_->Initialize();
+
+ // We don't pass StartupController an Unretained reference to future-proof
+ // against the controller impl changing to post tasks.
+ startup_controller_.reset(new syncer::StartupController(
+ &sync_prefs_,
+ base::Bind(&ProfileSyncService::CanBackendStart, base::Unretained(this)),
+ base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
+ weak_factory_.GetWeakPtr())));
+ std::unique_ptr<sync_sessions::LocalSessionEventRouter> router(
+ sync_client_->GetSyncSessionsClient()->GetLocalSessionEventRouter());
+ local_device_ = sync_client_->GetSyncApiComponentFactory()
+ ->CreateLocalDeviceInfoProvider();
+ sync_stopped_reporter_.reset(new syncer::SyncStoppedReporter(
+ sync_service_url_, local_device_->GetSyncUserAgent(),
+ url_request_context_, syncer::SyncStoppedReporter::ResultCallback()));
+ sessions_sync_manager_.reset(new SessionsSyncManager(
+ sync_client_->GetSyncSessionsClient(), &sync_prefs_, local_device_.get(),
+ std::move(router),
+ base::Bind(&ProfileSyncService::NotifyForeignSessionUpdated,
+ sync_enabled_weak_factory_.GetWeakPtr()),
+ base::Bind(&ProfileSyncService::TriggerRefresh,
+ sync_enabled_weak_factory_.GetWeakPtr(),
+ syncer::ModelTypeSet(syncer::SESSIONS))));
+
+ if (base::FeatureList::IsEnabled(switches::kSyncUSSDeviceInfo)) {
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner(
+ blocking_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
+ blocking_pool_->GetSequenceToken(),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+ // TODO(skym): Stop creating leveldb files when signed out.
+ // TODO(skym): Verify using AsUTF8Unsafe is okay here. Should work as long
+ // as the Local State file is guaranteed to be UTF-8.
+ device_info_service_.reset(new DeviceInfoService(
+ local_device_.get(),
+ base::Bind(&ModelTypeStore::CreateStore, syncer::DEVICE_INFO,
+ directory_path_.Append(base::FilePath(kLevelDBFolderName))
+ .AsUTF8Unsafe(),
+ blocking_task_runner),
+ base::Bind(&SharedModelTypeProcessor::CreateAsChangeProcessor)));
+ } else {
+ device_info_sync_service_.reset(
+ new DeviceInfoSyncService(local_device_.get()));
+ }
+
+ syncer::SyncApiComponentFactory::RegisterDataTypesMethod
+ register_platform_types_callback =
+ sync_client_->GetRegisterPlatformTypesCallback();
+ sync_client_->GetSyncApiComponentFactory()->RegisterDataTypes(
+ this, register_platform_types_callback);
+
+ if (gaia_cookie_manager_service_)
+ gaia_cookie_manager_service_->AddObserver(this);
+
+ // We clear this here (vs Shutdown) because we want to remember that an error
+ // happened on shutdown so we can display details (message, location) about it
+ // in about:sync.
+ ClearStaleErrors();
+
+ sync_prefs_.AddSyncPrefObserver(this);
+
+ SyncInitialState sync_state = CAN_START;
+ if (!IsSignedIn()) {
+ sync_state = NOT_SIGNED_IN;
+ } else if (IsManaged()) {
+ sync_state = IS_MANAGED;
+ } else if (!IsSyncAllowedByPlatform()) {
+ // This case should currently never be hit, as Android's master sync isn't
+ // plumbed into PSS until after this function. See http://crbug.com/568771.
+ sync_state = NOT_ALLOWED_BY_PLATFORM;
+ } else if (!IsSyncRequested()) {
+ if (IsFirstSetupComplete()) {
+ sync_state = NOT_REQUESTED;
+ } else {
+ sync_state = NOT_REQUESTED_NOT_SETUP;
+ }
+ } else if (!IsFirstSetupComplete()) {
+ sync_state = NEEDS_CONFIRMATION;
+ }
+ UMA_HISTOGRAM_ENUMERATION("Sync.InitialState", sync_state,
+ SYNC_INITIAL_STATE_LIMIT);
+
+ // If sync isn't allowed, the only thing to do is to turn it off.
+ if (!IsSyncAllowed()) {
+ // Only clear data if disallowed by policy.
+ RequestStop(IsManaged() ? CLEAR_DATA : KEEP_DATA);
+ return;
+ }
+
+ RegisterAuthNotifications();
+
+ if (!IsSignedIn()) {
+ // Clean up in case of previous crash during signout.
+ StopImpl(CLEAR_DATA);
+ }
+
+#if defined(OS_CHROMEOS)
+ std::string bootstrap_token = sync_prefs_.GetEncryptionBootstrapToken();
+ if (bootstrap_token.empty()) {
+ sync_prefs_.SetEncryptionBootstrapToken(
+ sync_prefs_.GetSpareBootstrapToken());
+ }
+#endif
+
+#if !defined(OS_ANDROID)
+ DCHECK(sync_error_controller_ == NULL)
+ << "Initialize() called more than once.";
+ sync_error_controller_.reset(new syncer::SyncErrorController(this));
+ AddObserver(sync_error_controller_.get());
+#endif
+
+ memory_pressure_listener_.reset(new base::MemoryPressureListener(
+ base::Bind(&ProfileSyncService::OnMemoryPressure,
+ sync_enabled_weak_factory_.GetWeakPtr())));
+ startup_controller_->Reset(GetRegisteredDataTypes());
+
+ // Auto-start means means the first time the profile starts up, sync should
+ // start up immediately.
+ if (start_behavior_ == AUTO_START && IsSyncRequested() &&
+ !IsFirstSetupComplete()) {
+ startup_controller_->TryStartImmediately();
+ } else {
+ startup_controller_->TryStart();
+ }
+}
+
+void ProfileSyncService::StartSyncingWithServer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (base::FeatureList::IsEnabled(
+ switches::kSyncClearDataOnPassphraseEncryption) &&
+ sync_prefs_.GetPassphraseEncryptionTransitionInProgress()) {
+ BeginConfigureCatchUpBeforeClear();
+ return;
+ }
+
+ if (backend_)
+ backend_->StartSyncingWithServer();
+}
+
+void ProfileSyncService::RegisterAuthNotifications() {
+ oauth2_token_service_->AddObserver(this);
+ if (signin())
+ signin()->AddObserver(this);
+}
+
+void ProfileSyncService::UnregisterAuthNotifications() {
+ if (signin())
+ signin()->RemoveObserver(this);
+ oauth2_token_service_->RemoveObserver(this);
+}
+
+void ProfileSyncService::RegisterDataTypeController(
+ std::unique_ptr<syncer::DataTypeController> data_type_controller) {
+ DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U);
+ data_type_controllers_[data_type_controller->type()] =
+ std::move(data_type_controller);
+}
+
+bool ProfileSyncService::IsDataTypeControllerRunning(
+ syncer::ModelType type) const {
+ DataTypeController::TypeMap::const_iterator iter =
+ data_type_controllers_.find(type);
+ if (iter == data_type_controllers_.end()) {
+ return false;
+ }
+ return iter->second->state() == DataTypeController::RUNNING;
+}
+
+sync_sessions::OpenTabsUIDelegate* ProfileSyncService::GetOpenTabsUIDelegate() {
+ if (!IsDataTypeControllerRunning(syncer::SESSIONS))
+ return NULL;
+ return sessions_sync_manager_.get();
+}
+
+sync_sessions::FaviconCache* ProfileSyncService::GetFaviconCache() {
+ return sessions_sync_manager_->GetFaviconCache();
+}
+
+syncer::DeviceInfoTracker* ProfileSyncService::GetDeviceInfoTracker() const {
+ // One of the two should always be non-null after initialization is done.
+ if (device_info_service_) {
+ return device_info_service_.get();
+ } else {
+ return device_info_sync_service_.get();
+ }
+}
+
+syncer::LocalDeviceInfoProvider*
+ProfileSyncService::GetLocalDeviceInfoProvider() const {
+ return local_device_.get();
+}
+
+void ProfileSyncService::GetDataTypeControllerStates(
+ DataTypeController::StateMap* state_map) const {
+ for (DataTypeController::TypeMap::const_iterator iter =
+ data_type_controllers_.begin();
+ iter != data_type_controllers_.end(); ++iter)
+ (*state_map)[iter->first] = iter->second.get()->state();
+}
+
+void ProfileSyncService::OnSessionRestoreComplete() {
+ DataTypeController::TypeMap::const_iterator iter =
+ data_type_controllers_.find(syncer::SESSIONS);
+ if (iter == data_type_controllers_.end()) {
+ return;
+ }
+ DCHECK(iter->second);
+
+ static_cast<sync_sessions::SessionDataTypeController*>(iter->second.get())
+ ->OnSessionRestoreComplete();
+}
+
+SyncCredentials ProfileSyncService::GetCredentials() {
+ SyncCredentials credentials;
+ credentials.account_id = signin_->GetAccountIdToUse();
+ DCHECK(!credentials.account_id.empty());
+ credentials.email = signin_->GetEffectiveUsername();
+ credentials.sync_token = access_token_;
+
+ if (credentials.sync_token.empty())
+ credentials.sync_token = "credentials_lost";
+
+ credentials.scope_set.insert(signin_->GetSyncScopeToUse());
+
+ return credentials;
+}
+
+bool ProfileSyncService::ShouldDeleteSyncFolder() {
+ return !IsFirstSetupComplete();
+}
+
+void ProfileSyncService::InitializeBackend(bool delete_stale_data) {
+ if (!backend_) {
+ NOTREACHED();
+ return;
+ }
+
+ SyncCredentials credentials = GetCredentials();
+
+ if (delete_stale_data)
+ ClearStaleErrors();
+
+ SyncBackendHost::HttpPostProviderFactoryGetter
+ http_post_provider_factory_getter =
+ base::Bind(&syncer::NetworkResources::GetHttpPostProviderFactory,
+ base::Unretained(network_resources_.get()),
+ url_request_context_, network_time_update_callback_);
+
+ backend_->Initialize(
+ this, std::move(sync_thread_), db_thread_, file_thread_,
+ GetJsEventHandler(), sync_service_url_, local_device_->GetSyncUserAgent(),
+ credentials, delete_stale_data,
+ std::unique_ptr<syncer::SyncManagerFactory>(
+ new syncer::SyncManagerFactory()),
+ MakeWeakHandle(sync_enabled_weak_factory_.GetWeakPtr()),
+ base::Bind(syncer::ChromeReportUnrecoverableError, channel_),
+ http_post_provider_factory_getter, std::move(saved_nigori_state_));
+}
+
+bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
+ if (encryption_pending())
+ return true;
+ const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
+ const syncer::ModelTypeSet encrypted_types = GetEncryptedDataTypes();
+ DCHECK(encrypted_types.Has(syncer::PASSWORDS));
+ return !Intersection(preferred_types, encrypted_types).Empty();
+}
+
+void ProfileSyncService::OnProtocolEvent(const syncer::ProtocolEvent& event) {
+ FOR_EACH_OBSERVER(ProtocolEventObserver, protocol_event_observers_,
+ OnProtocolEvent(event));
+}
+
+void ProfileSyncService::OnDirectoryTypeCommitCounterUpdated(
+ syncer::ModelType type,
+ const syncer::CommitCounters& counters) {
+ FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver, type_debug_info_observers_,
+ OnCommitCountersUpdated(type, counters));
+}
+
+void ProfileSyncService::OnDirectoryTypeUpdateCounterUpdated(
+ syncer::ModelType type,
+ const syncer::UpdateCounters& counters) {
+ FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver, type_debug_info_observers_,
+ OnUpdateCountersUpdated(type, counters));
+}
+
+void ProfileSyncService::OnDirectoryTypeStatusCounterUpdated(
+ syncer::ModelType type,
+ const syncer::StatusCounters& counters) {
+ FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver, type_debug_info_observers_,
+ OnStatusCountersUpdated(type, counters));
+}
+
+void ProfileSyncService::OnDataTypeRequestsSyncStartup(syncer::ModelType type) {
+ DCHECK(syncer::UserTypes().Has(type));
+
+ if (!GetPreferredDataTypes().Has(type)) {
+ // We can get here as datatype SyncableServices are typically wired up
+ // to the native datatype even if sync isn't enabled.
+ DVLOG(1) << "Dropping sync startup request because type "
+ << syncer::ModelTypeToString(type) << "not enabled.";
+ return;
+ }
+
+ // If this is a data type change after a major version update, reset the
+ // passphrase prompted state and notify observers.
+ if (IsPassphraseRequired() && passphrase_prompt_triggered_by_version_) {
+ // The major version has changed and a local syncable change was made.
+ // Reset the passphrase prompt state.
+ passphrase_prompt_triggered_by_version_ = false;
+ sync_prefs_.SetPassphrasePrompted(false);
+ NotifyObservers();
+ }
+
+ if (backend_.get()) {
+ DVLOG(1) << "A data type requested sync startup, but it looks like "
+ "something else beat it to the punch.";
+ return;
+ }
+
+ startup_controller_->OnDataTypeRequestsSyncStartup(type);
+}
+
+void ProfileSyncService::StartUpSlowBackendComponents() {
+ invalidation::InvalidationService* invalidator =
+ sync_client_->GetInvalidationService();
+
+ backend_.reset(
+ sync_client_->GetSyncApiComponentFactory()->CreateSyncBackendHost(
+ debug_identifier_, invalidator, sync_prefs_.AsWeakPtr(),
+ directory_path_));
+
+ // Initialize the backend. Every time we start up a new SyncBackendHost,
+ // we'll want to start from a fresh SyncDB, so delete any old one that might
+ // be there.
+ InitializeBackend(ShouldDeleteSyncFolder());
+
+ UpdateFirstSyncTimePref();
+
+ ReportPreviousSessionMemoryWarningCount();
+}
+
+void ProfileSyncService::OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) {
+ DCHECK_EQ(access_token_request_.get(), request);
+ access_token_request_.reset();
+ access_token_ = access_token;
+ token_receive_time_ = base::Time::Now();
+ last_get_token_error_ = GoogleServiceAuthError::AuthErrorNone();
+
+ if (sync_prefs_.SyncHasAuthError()) {
+ sync_prefs_.SetSyncAuthError(false);
+ }
+
+ if (HasSyncingBackend())
+ backend_->UpdateCredentials(GetCredentials());
+ else
+ startup_controller_->TryStart();
+}
+
+void ProfileSyncService::OnGetTokenFailure(
+ const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ DCHECK_EQ(access_token_request_.get(), request);
+ DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
+ access_token_request_.reset();
+ last_get_token_error_ = error;
+ switch (error.state()) {
+ case GoogleServiceAuthError::CONNECTION_FAILED:
+ case GoogleServiceAuthError::REQUEST_CANCELED:
+ case GoogleServiceAuthError::SERVICE_ERROR:
+ case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
+ // Transient error. Retry after some time.
+ request_access_token_backoff_.InformOfRequest(false);
+ next_token_request_time_ =
+ base::Time::Now() +
+ request_access_token_backoff_.GetTimeUntilRelease();
+ request_access_token_retry_timer_.Start(
+ FROM_HERE, request_access_token_backoff_.GetTimeUntilRelease(),
+ base::Bind(&ProfileSyncService::RequestAccessToken,
+ sync_enabled_weak_factory_.GetWeakPtr()));
+ NotifyObservers();
+ break;
+ }
+ case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
+ if (!sync_prefs_.SyncHasAuthError()) {
+ sync_prefs_.SetSyncAuthError(true);
+ UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError", AUTH_ERROR_ENCOUNTERED,
+ AUTH_ERROR_LIMIT);
+ }
+ // Fallthrough.
+ }
+ default: {
+ if (error.state() != GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
+ LOG(ERROR) << "Unexpected persistent error: " << error.ToString();
+ }
+ // Show error to user.
+ UpdateAuthErrorState(error);
+ }
+ }
+}
+
+void ProfileSyncService::OnRefreshTokenAvailable(
+ const std::string& account_id) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "422460 ProfileSyncService::OnRefreshTokenAvailable"));
+
+ if (account_id == signin_->GetAccountIdToUse())
+ OnRefreshTokensLoaded();
+}
+
+void ProfileSyncService::OnRefreshTokenRevoked(const std::string& account_id) {
+ if (account_id == signin_->GetAccountIdToUse()) {
+ access_token_.clear();
+ UpdateAuthErrorState(
+ GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
+ }
+}
+
+void ProfileSyncService::OnRefreshTokensLoaded() {
+ // This notification gets fired when OAuth2TokenService loads the tokens
+ // from storage.
+ // Initialize the backend if sync is enabled. If the sync token was
+ // not loaded, GetCredentials() will generate invalid credentials to
+ // cause the backend to generate an auth error (crbug.com/121755).
+ if (HasSyncingBackend()) {
+ RequestAccessToken();
+ } else {
+ startup_controller_->TryStart();
+ }
+}
+
+void ProfileSyncService::Shutdown() {
+ UnregisterAuthNotifications();
+
+ ShutdownImpl(syncer::BROWSER_SHUTDOWN);
+ if (sync_error_controller_) {
+ // Destroy the SyncErrorController when the service shuts down for good.
+ RemoveObserver(sync_error_controller_.get());
+ sync_error_controller_.reset();
+ }
+
+ if (sync_thread_)
+ sync_thread_->Stop();
+}
+
+void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) {
+ if (!backend_) {
+ if (reason == syncer::ShutdownReason::DISABLE_SYNC && sync_thread_) {
+ // If the backend is already shut down when a DISABLE_SYNC happens,
+ // the data directory needs to be cleaned up here.
+ sync_thread_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&DeleteSyncDataFolder, directory_path_));
+ }
+ return;
+ }
+
+ if (reason == syncer::ShutdownReason::STOP_SYNC ||
+ reason == syncer::ShutdownReason::DISABLE_SYNC) {
+ RemoveClientFromServer();
+ }
+
+ // First, we spin down the backend to stop change processing as soon as
+ // possible.
+ base::Time shutdown_start_time = base::Time::Now();
+ backend_->StopSyncingForShutdown();
+
+ // Stop all data type controllers, if needed. Note that until Stop
+ // completes, it is possible in theory to have a ChangeProcessor apply a
+ // change from a native model. In that case, it will get applied to the sync
+ // database (which doesn't get destroyed until we destroy the backend below)
+ // as an unsynced change. That will be persisted, and committed on restart.
+ if (data_type_manager_) {
+ if (data_type_manager_->state() != DataTypeManager::STOPPED) {
+ // When aborting as part of shutdown, we should expect an aborted sync
+ // configure result, else we'll dcheck when we try to read the sync error.
+ expect_sync_configuration_aborted_ = true;
+ data_type_manager_->Stop();
+ }
+ data_type_manager_.reset();
+ }
+
+ // Shutdown the migrator before the backend to ensure it doesn't pull a null
+ // snapshot.
+ migrator_.reset();
+ sync_js_controller_.AttachJsBackend(WeakHandle<syncer::JsBackend>());
+
+ // Move aside the backend so nobody else tries to use it while we are
+ // shutting it down.
+ std::unique_ptr<SyncBackendHost> doomed_backend(backend_.release());
+ if (doomed_backend) {
+ sync_thread_ = doomed_backend->Shutdown(reason);
+ doomed_backend.reset();
+ }
+ base::TimeDelta shutdown_time = base::Time::Now() - shutdown_start_time;
+ UMA_HISTOGRAM_TIMES("Sync.Shutdown.BackendDestroyedTime", shutdown_time);
+
+ sync_enabled_weak_factory_.InvalidateWeakPtrs();
+
+ startup_controller_->Reset(GetRegisteredDataTypes());
+
+ // If the sync DB is getting destroyed, the local DeviceInfo is no longer
+ // valid and should be cleared from the cache.
+ if (reason == syncer::ShutdownReason::DISABLE_SYNC) {
+ local_device_->Clear();
+ }
+
+ // Clear various flags.
+ expect_sync_configuration_aborted_ = false;
+ is_auth_in_progress_ = false;
+ backend_initialized_ = false;
+ cached_passphrase_.clear();
+ encryption_pending_ = false;
+ encrypt_everything_ = false;
+ encrypted_types_ = syncer::SyncEncryptionHandler::SensitiveTypes();
+ passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
+ catch_up_configure_in_progress_ = false;
+ access_token_.clear();
+ request_access_token_retry_timer_.Stop();
+ // Revert to "no auth error".
+ if (last_auth_error_.state() != GoogleServiceAuthError::NONE)
+ UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone());
+
+ NotifyObservers();
+
+ // Mark this as a clean shutdown(without crash).
+ sync_prefs_.SetCleanShutdown(true);
+}
+
+void ProfileSyncService::StopImpl(SyncStopDataFate data_fate) {
+ switch (data_fate) {
+ case KEEP_DATA:
+ // TODO(maxbogue): Investigate whether this logic can/should be moved
+ // into ShutdownImpl or SyncBackendHost itself.
+ if (HasSyncingBackend()) {
+ backend_->UnregisterInvalidationIds();
+ }
+ ShutdownImpl(syncer::STOP_SYNC);
+ break;
+ case CLEAR_DATA:
+ // Clear prefs (including SyncSetupHasCompleted) before shutting down so
+ // PSS clients don't think we're set up while we're shutting down.
+ sync_prefs_.ClearPreferences();
+ ClearUnrecoverableError();
+ ShutdownImpl(syncer::DISABLE_SYNC);
+ break;
+ }
+}
+
+bool ProfileSyncService::IsFirstSetupComplete() const {
+ return sync_prefs_.IsFirstSetupComplete();
+}
+
+void ProfileSyncService::SetFirstSetupComplete() {
+ sync_prefs_.SetFirstSetupComplete();
+ if (IsBackendInitialized()) {
+ ReconfigureDatatypeManager();
+ }
+}
+
+void ProfileSyncService::UpdateLastSyncedTime() {
+ sync_prefs_.SetLastSyncedTime(base::Time::Now());
+}
+
+void ProfileSyncService::NotifyObservers() {
+ FOR_EACH_OBSERVER(syncer::SyncServiceObserver, observers_, OnStateChanged());
+}
+
+void ProfileSyncService::NotifySyncCycleCompleted() {
+ FOR_EACH_OBSERVER(syncer::SyncServiceObserver, observers_,
+ OnSyncCycleCompleted());
+}
+
+void ProfileSyncService::NotifyForeignSessionUpdated() {
+ FOR_EACH_OBSERVER(syncer::SyncServiceObserver, observers_,
+ OnForeignSessionUpdated());
+}
+
+void ProfileSyncService::ClearStaleErrors() {
+ ClearUnrecoverableError();
+ last_actionable_error_ = SyncProtocolError();
+ // Clear the data type errors as well.
+ if (data_type_manager_.get())
+ data_type_manager_->ResetDataTypeErrors();
+}
+
+void ProfileSyncService::ClearUnrecoverableError() {
+ unrecoverable_error_reason_ = ERROR_REASON_UNSET;
+ unrecoverable_error_message_.clear();
+ unrecoverable_error_location_ = tracked_objects::Location();
+}
+
+// An invariant has been violated. Transition to an error state where we try
+// to do as little work as possible, to avoid further corruption or crashes.
+void ProfileSyncService::OnUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message) {
+ // Unrecoverable errors that arrive via the syncer::UnrecoverableErrorHandler
+ // interface are assumed to originate within the syncer.
+ unrecoverable_error_reason_ = ERROR_REASON_SYNCER;
+ OnUnrecoverableErrorImpl(from_here, message, true);
+}
+
+void ProfileSyncService::OnUnrecoverableErrorImpl(
+ const tracked_objects::Location& from_here,
+ const std::string& message,
+ bool delete_sync_database) {
+ DCHECK(HasUnrecoverableError());
+ unrecoverable_error_message_ = message;
+ unrecoverable_error_location_ = from_here;
+
+ UMA_HISTOGRAM_ENUMERATION(kSyncUnrecoverableErrorHistogram,
+ unrecoverable_error_reason_, ERROR_REASON_LIMIT);
+ std::string location;
+ from_here.Write(true, true, &location);
+ LOG(ERROR) << "Unrecoverable error detected at " << location
+ << " -- ProfileSyncService unusable: " << message;
+
+ // Shut all data types down.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&ProfileSyncService::ShutdownImpl,
+ sync_enabled_weak_factory_.GetWeakPtr(),
+ delete_sync_database ? syncer::DISABLE_SYNC
+ : syncer::STOP_SYNC));
+}
+
+void ProfileSyncService::ReenableDatatype(syncer::ModelType type) {
+ if (!backend_initialized_ || !data_type_manager_)
+ return;
+ data_type_manager_->ReenableType(type);
+}
+
+void ProfileSyncService::UpdateBackendInitUMA(bool success) {
+ is_first_time_sync_configure_ = !IsFirstSetupComplete();
+
+ if (is_first_time_sync_configure_) {
+ UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeFirstTimeSuccess", success);
+ } else {
+ UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeRestoreSuccess", success);
+ }
+
+ base::Time on_backend_initialized_time = base::Time::Now();
+ base::TimeDelta delta =
+ on_backend_initialized_time - startup_controller_->start_backend_time();
+ if (is_first_time_sync_configure_) {
+ UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeFirstTime", delta);
+ } else {
+ UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeRestoreTime", delta);
+ }
+}
+
+void ProfileSyncService::PostBackendInitialization() {
+ if (protocol_event_observers_.might_have_observers()) {
+ backend_->RequestBufferedProtocolEventsAndEnableForwarding();
+ }
+
+ if (type_debug_info_observers_.might_have_observers()) {
+ backend_->EnableDirectoryTypeDebugInfoForwarding();
+ }
+
+ // If we have a cached passphrase use it to decrypt/encrypt data now that the
+ // backend is initialized. We want to call this before notifying observers in
+ // case this operation affects the "passphrase required" status.
+ ConsumeCachedPassphraseIfPossible();
+
+ // The very first time the backend initializes is effectively the first time
+ // we can say we successfully "synced". LastSyncedTime will only be null in
+ // this case, because the pref wasn't restored on StartUp.
+ if (sync_prefs_.GetLastSyncedTime().is_null()) {
+ UpdateLastSyncedTime();
+ }
+
+ // Auto-start means IsFirstSetupComplete gets set automatically.
+ if (start_behavior_ == AUTO_START && !IsFirstSetupComplete()) {
+ // This will trigger a configure if it completes setup.
+ SetFirstSetupComplete();
+ } else if (CanConfigureDataTypes()) {
+ ConfigureDataTypeManager();
+ }
+
+ // Check for a cookie jar mismatch.
+ std::vector<gaia::ListedAccount> accounts;
+ std::vector<gaia::ListedAccount> signed_out_accounts;
+ GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
+ if (gaia_cookie_manager_service_ &&
+ gaia_cookie_manager_service_->ListAccounts(
+ &accounts, &signed_out_accounts, "ChromiumProfileSyncService")) {
+ OnGaiaAccountsInCookieUpdated(accounts, signed_out_accounts, error);
+ }
+
+ NotifyObservers();
+}
+
+void ProfileSyncService::OnBackendInitialized(
+ const syncer::WeakHandle<syncer::JsBackend>& js_backend,
+ const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
+ debug_info_listener,
+ const std::string& cache_guid,
+ bool success) {
+ UpdateBackendInitUMA(success);
+
+ if (!success) {
+ // Something went unexpectedly wrong. Play it safe: stop syncing at once
+ // and surface error UI to alert the user sync has stopped.
+ // Keep the directory around for now so that on restart we will retry
+ // again and potentially succeed in presence of transient file IO failures
+ // or permissions issues, etc.
+ //
+ // TODO(rlarocque): Consider making this UnrecoverableError less special.
+ // Unlike every other UnrecoverableError, it does not delete our sync data.
+ // This exception made sense at the time it was implemented, but our new
+ // directory corruption recovery mechanism makes it obsolete. By the time
+ // we get here, we will have already tried and failed to delete the
+ // directory. It would be no big deal if we tried to delete it again.
+ OnInternalUnrecoverableError(FROM_HERE, "BackendInitialize failure", false,
+ ERROR_REASON_BACKEND_INIT_FAILURE);
+ return;
+ }
+
+ backend_initialized_ = true;
+
+ sync_js_controller_.AttachJsBackend(js_backend);
+ debug_info_listener_ = debug_info_listener;
+
+ SigninClient* signin_client = signin_->GetOriginal()->signin_client();
+ DCHECK(signin_client);
+ std::string signin_scoped_device_id =
+ signin_client->GetSigninScopedDeviceId();
+
+ // Initialize local device info.
+ local_device_->Initialize(cache_guid, signin_scoped_device_id,
+ blocking_pool_);
+
+ PostBackendInitialization();
+}
+
+void ProfileSyncService::OnSyncCycleCompleted() {
+ UpdateLastSyncedTime();
+ const syncer::SyncCycleSnapshot snapshot = GetLastCycleSnapshot();
+ if (IsDataTypeControllerRunning(syncer::SESSIONS) &&
+ snapshot.model_neutral_state().get_updates_request_types.Has(
+ syncer::SESSIONS) &&
+ !syncer::HasSyncerError(snapshot.model_neutral_state())) {
+ // Trigger garbage collection of old sessions now that we've downloaded
+ // any new session data.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&SessionsSyncManager::DoGarbageCollection,
+ base::AsWeakPtr(sessions_sync_manager_.get())));
+ }
+ DVLOG(2) << "Notifying observers sync cycle completed";
+ NotifySyncCycleCompleted();
+}
+
+void ProfileSyncService::OnExperimentsChanged(
+ const syncer::Experiments& experiments) {
+ if (current_experiments_.Matches(experiments))
+ return;
+
+ current_experiments_ = experiments;
+
+ sync_client_->GetPrefService()->SetBoolean(
+ invalidation::prefs::kInvalidationServiceUseGCMChannel,
+ experiments.gcm_invalidations_enabled);
+}
+
+void ProfileSyncService::UpdateAuthErrorState(const AuthError& error) {
+ is_auth_in_progress_ = false;
+ last_auth_error_ = error;
+
+ NotifyObservers();
+}
+
+namespace {
+
+AuthError ConnectionStatusToAuthError(syncer::ConnectionStatus status) {
+ switch (status) {
+ case syncer::CONNECTION_OK:
+ return AuthError::AuthErrorNone();
+ break;
+ case syncer::CONNECTION_AUTH_ERROR:
+ return AuthError(AuthError::INVALID_GAIA_CREDENTIALS);
+ break;
+ case syncer::CONNECTION_SERVER_ERROR:
+ return AuthError(AuthError::CONNECTION_FAILED);
+ break;
+ default:
+ NOTREACHED();
+ return AuthError(AuthError::CONNECTION_FAILED);
+ }
+}
+
+} // namespace
+
+void ProfileSyncService::OnConnectionStatusChange(
+ syncer::ConnectionStatus status) {
+ connection_status_update_time_ = base::Time::Now();
+ connection_status_ = status;
+ if (status == syncer::CONNECTION_AUTH_ERROR) {
+ // Sync server returned error indicating that access token is invalid. It
+ // could be either expired or access is revoked. Let's request another
+ // access token and if access is revoked then request for token will fail
+ // with corresponding error. If access token is repeatedly reported
+ // invalid, there may be some issues with server, e.g. authentication
+ // state is inconsistent on sync and token server. In that case, we
+ // backoff token requests exponentially to avoid hammering token server
+ // too much and to avoid getting same token due to token server's caching
+ // policy. |request_access_token_retry_timer_| is used to backoff request
+ // triggered by both auth error and failure talking to GAIA server.
+ // Therefore, we're likely to reach the backoff ceiling more quickly than
+ // you would expect from looking at the BackoffPolicy if both types of
+ // errors happen. We shouldn't receive two errors back-to-back without
+ // attempting a token/sync request in between, thus crank up request delay
+ // unnecessary. This is because we won't make a sync request if we hit an
+ // error until GAIA succeeds at sending a new token, and we won't request
+ // a new token unless sync reports a token failure. But to be safe, don't
+ // schedule request if this happens.
+ if (request_access_token_retry_timer_.IsRunning()) {
+ // The timer to perform a request later is already running; nothing
+ // further needs to be done at this point.
+ } else if (request_access_token_backoff_.failure_count() == 0) {
+ // First time request without delay. Currently invalid token is used
+ // to initialize sync backend and we'll always end up here. We don't
+ // want to delay initialization.
+ request_access_token_backoff_.InformOfRequest(false);
+ RequestAccessToken();
+ } else {
+ request_access_token_backoff_.InformOfRequest(false);
+ request_access_token_retry_timer_.Start(
+ FROM_HERE, request_access_token_backoff_.GetTimeUntilRelease(),
+ base::Bind(&ProfileSyncService::RequestAccessToken,
+ sync_enabled_weak_factory_.GetWeakPtr()));
+ }
+ } else {
+ // Reset backoff time after successful connection.
+ if (status == syncer::CONNECTION_OK) {
+ // Request shouldn't be scheduled at this time. But if it is, it's
+ // possible that sync flips between OK and auth error states rapidly,
+ // thus hammers token server. To be safe, only reset backoff delay when
+ // no scheduled request.
+ if (!request_access_token_retry_timer_.IsRunning()) {
+ request_access_token_backoff_.Reset();
+ }
+ }
+
+ const GoogleServiceAuthError auth_error =
+ ConnectionStatusToAuthError(status);
+ DVLOG(1) << "Connection status change: " << auth_error.ToString();
+ UpdateAuthErrorState(auth_error);
+ }
+}
+
+void ProfileSyncService::OnPassphraseRequired(
+ syncer::PassphraseRequiredReason reason,
+ const sync_pb::EncryptedData& pending_keys) {
+ DCHECK(backend_.get());
+ DCHECK(backend_->IsNigoriEnabled());
+
+ // TODO(lipalani) : add this check to other locations as well.
+ if (HasUnrecoverableError()) {
+ // When unrecoverable error is detected we post a task to shutdown the
+ // backend. The task might not have executed yet.
+ return;
+ }
+
+ DVLOG(1) << "Passphrase required with reason: "
+ << syncer::PassphraseRequiredReasonToString(reason);
+ passphrase_required_reason_ = reason;
+
+ // TODO(stanisc): http://crbug.com/351005: Does this support USS types?
+ const syncer::ModelTypeSet types = GetPreferredDataTypes();
+ if (data_type_manager_) {
+ // Reconfigure without the encrypted types (excluded implicitly via the
+ // failed datatypes handler).
+ data_type_manager_->Configure(types, syncer::CONFIGURE_REASON_CRYPTO);
+ }
+
+ // Notify observers that the passphrase status may have changed.
+ NotifyObservers();
+}
+
+void ProfileSyncService::OnPassphraseAccepted() {
+ DVLOG(1) << "Received OnPassphraseAccepted.";
+
+ // If the pending keys were resolved via keystore, it's possible we never
+ // consumed our cached passphrase. Clear it now.
+ if (!cached_passphrase_.empty())
+ cached_passphrase_.clear();
+
+ // Reset passphrase_required_reason_ since we know we no longer require the
+ // passphrase. We do this here rather than down in ResolvePassphraseRequired()
+ // because that can be called by OnPassphraseRequired() if no encrypted data
+ // types are enabled, and we don't want to clobber the true passphrase error.
+ passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
+
+ // Make sure the data types that depend on the passphrase are started at
+ // this time.
+ // TODO(stanisc): http://crbug.com/351005: Does this support USS types?
+ const syncer::ModelTypeSet types = GetPreferredDataTypes();
+ if (data_type_manager_) {
+ // Re-enable any encrypted types if necessary.
+ data_type_manager_->Configure(types, syncer::CONFIGURE_REASON_CRYPTO);
+ }
+
+ NotifyObservers();
+}
+
+void ProfileSyncService::OnEncryptedTypesChanged(
+ syncer::ModelTypeSet encrypted_types,
+ bool encrypt_everything) {
+ encrypted_types_ = encrypted_types;
+ encrypt_everything_ = encrypt_everything;
+ DCHECK(encrypt_everything_allowed_ || !encrypt_everything_);
+ DVLOG(1) << "Encrypted types changed to "
+ << syncer::ModelTypeSetToString(encrypted_types_)
+ << " (encrypt everything is set to "
+ << (encrypt_everything_ ? "true" : "false") << ")";
+ DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
+
+ NotifyObservers();
+}
+
+void ProfileSyncService::OnEncryptionComplete() {
+ DVLOG(1) << "Encryption complete";
+ if (encryption_pending_ && encrypt_everything_) {
+ encryption_pending_ = false;
+ // This is to nudge the integration tests when encryption is
+ // finished.
+ NotifyObservers();
+ }
+}
+
+void ProfileSyncService::OnMigrationNeededForTypes(syncer::ModelTypeSet types) {
+ DCHECK(backend_initialized_);
+ DCHECK(data_type_manager_.get());
+
+ // Migrator must be valid, because we don't sync until it is created and this
+ // callback originates from a sync cycle.
+ migrator_->MigrateTypes(types);
+}
+
+void ProfileSyncService::OnActionableError(const SyncProtocolError& error) {
+ last_actionable_error_ = error;
+ DCHECK_NE(last_actionable_error_.action, syncer::UNKNOWN_ACTION);
+ switch (error.action) {
+ case syncer::UPGRADE_CLIENT:
+ case syncer::CLEAR_USER_DATA_AND_RESYNC:
+ case syncer::ENABLE_SYNC_ON_ACCOUNT:
+ case syncer::STOP_AND_RESTART_SYNC:
+ // TODO(lipalani) : if setup in progress we want to display these
+ // actions in the popup. The current experience might not be optimal for
+ // the user. We just dismiss the dialog.
+ if (startup_controller_->IsSetupInProgress()) {
+ RequestStop(CLEAR_DATA);
+ expect_sync_configuration_aborted_ = true;
+ }
+ // Trigger an unrecoverable error to stop syncing.
+ OnInternalUnrecoverableError(FROM_HERE,
+ last_actionable_error_.error_description,
+ true, ERROR_REASON_ACTIONABLE_ERROR);
+ break;
+ case syncer::DISABLE_SYNC_ON_CLIENT:
+ if (error.error_type == syncer::NOT_MY_BIRTHDAY) {
+ UMA_HISTOGRAM_ENUMERATION("Sync.StopSource", syncer::BIRTHDAY_ERROR,
+ syncer::STOP_SOURCE_LIMIT);
+ }
+ RequestStop(CLEAR_DATA);
+#if !defined(OS_CHROMEOS)
+ // On every platform except ChromeOS, sign out the user after a dashboard
+ // clear.
+ static_cast<SigninManager*>(signin_->GetOriginal())
+ ->SignOut(signin_metrics::SERVER_FORCED_DISABLE,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
+#endif
+ break;
+ case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
+ // Sync disabled by domain admin. we should stop syncing until next
+ // restart.
+ sync_disabled_by_admin_ = true;
+ ShutdownImpl(syncer::DISABLE_SYNC);
+ break;
+ case syncer::RESET_LOCAL_SYNC_DATA:
+ ShutdownImpl(syncer::DISABLE_SYNC);
+ startup_controller_->TryStart();
+ break;
+ default:
+ NOTREACHED();
+ }
+ NotifyObservers();
+}
+
+void ProfileSyncService::OnLocalSetPassphraseEncryption(
+ const syncer::SyncEncryptionHandler::NigoriState& nigori_state) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!base::FeatureList::IsEnabled(
+ switches::kSyncClearDataOnPassphraseEncryption))
+ return;
+
+ // At this point the user has set a custom passphrase and we have received the
+ // updated nigori state. Time to cache the nigori state, and catch up the
+ // active data types.
+ sync_prefs_.SetSavedNigoriStateForPassphraseEncryptionTransition(
+ nigori_state);
+ sync_prefs_.SetPassphraseEncryptionTransitionInProgress(true);
+ BeginConfigureCatchUpBeforeClear();
+}
+
+void ProfileSyncService::BeginConfigureCatchUpBeforeClear() {
+ DCHECK(data_type_manager_);
+ DCHECK(!saved_nigori_state_);
+ saved_nigori_state_ =
+ sync_prefs_.GetSavedNigoriStateForPassphraseEncryptionTransition();
+ const syncer::ModelTypeSet types = GetActiveDataTypes();
+ catch_up_configure_in_progress_ = true;
+ data_type_manager_->Configure(types, syncer::CONFIGURE_REASON_CATCH_UP);
+}
+
+void ProfileSyncService::ClearAndRestartSyncForPassphraseEncryption() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ backend_->ClearServerData(
+ base::Bind(&ProfileSyncService::OnClearServerDataDone,
+ sync_enabled_weak_factory_.GetWeakPtr()));
+}
+
+void ProfileSyncService::OnClearServerDataDone() {
+ DCHECK(sync_prefs_.GetPassphraseEncryptionTransitionInProgress());
+ sync_prefs_.SetPassphraseEncryptionTransitionInProgress(false);
+
+ // Call to ClearServerData generates new keystore key on the server. This
+ // makes keystore bootstrap token invalid. Let's clear it from preferences.
+ sync_prefs_.SetKeystoreEncryptionBootstrapToken(std::string());
+
+ // Shutdown sync, delete the Directory, then restart, restoring the cached
+ // nigori state.
+ ShutdownImpl(syncer::DISABLE_SYNC);
+ startup_controller_->TryStart();
+}
+
+void ProfileSyncService::OnConfigureDone(
+ const DataTypeManager::ConfigureResult& result) {
+ configure_status_ = result.status;
+ data_type_status_table_ = result.data_type_status_table;
+
+ // We should have cleared our cached passphrase before we get here (in
+ // OnBackendInitialized()).
+ DCHECK(cached_passphrase_.empty());
+
+ if (!sync_configure_start_time_.is_null()) {
+ if (result.status == DataTypeManager::OK) {
+ base::Time sync_configure_stop_time = base::Time::Now();
+ base::TimeDelta delta =
+ sync_configure_stop_time - sync_configure_start_time_;
+ if (is_first_time_sync_configure_) {
+ UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceInitialConfigureTime", delta);
+ } else {
+ UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceSubsequentConfigureTime", delta);
+ }
+ }
+ sync_configure_start_time_ = base::Time();
+ }
+
+ // Notify listeners that configuration is done.
+ FOR_EACH_OBSERVER(syncer::SyncServiceObserver, observers_,
+ OnSyncConfigurationCompleted());
+
+ DVLOG(1) << "PSS OnConfigureDone called with status: " << configure_status_;
+ // The possible status values:
+ // ABORT - Configuration was aborted. This is not an error, if
+ // initiated by user.
+ // OK - Some or all types succeeded.
+ // Everything else is an UnrecoverableError. So treat it as such.
+
+ // First handle the abort case.
+ if (configure_status_ == DataTypeManager::ABORTED &&
+ expect_sync_configuration_aborted_) {
+ DVLOG(0) << "ProfileSyncService::Observe Sync Configure aborted";
+ expect_sync_configuration_aborted_ = false;
+ return;
+ }
+
+ // Handle unrecoverable error.
+ if (configure_status_ != DataTypeManager::OK) {
+ // Something catastrophic had happened. We should only have one
+ // error representing it.
+ syncer::SyncError error = data_type_status_table_.GetUnrecoverableError();
+ DCHECK(error.IsSet());
+ std::string message =
+ "Sync configuration failed with status " +
+ DataTypeManager::ConfigureStatusToString(configure_status_) +
+ " caused by " +
+ syncer::ModelTypeSetToString(
+ data_type_status_table_.GetUnrecoverableErrorTypes()) +
+ ": " + error.message();
+ LOG(ERROR) << "ProfileSyncService error: " << message;
+ OnInternalUnrecoverableError(error.location(), message, true,
+ ERROR_REASON_CONFIGURATION_FAILURE);
+ return;
+ }
+
+ DCHECK_EQ(DataTypeManager::OK, configure_status_);
+
+ // We should never get in a state where we have no encrypted datatypes
+ // enabled, and yet we still think we require a passphrase for decryption.
+ DCHECK(
+ !(IsPassphraseRequiredForDecryption() && !IsEncryptedDatatypeEnabled()));
+
+ // This must be done before we start syncing with the server to avoid
+ // sending unencrypted data up on a first time sync.
+ if (encryption_pending_)
+ backend_->EnableEncryptEverything();
+ NotifyObservers();
+
+ if (migrator_.get() && migrator_->state() != BackendMigrator::IDLE) {
+ // Migration in progress. Let the migrator know we just finished
+ // configuring something. It will be up to the migrator to call
+ // StartSyncingWithServer() if migration is now finished.
+ migrator_->OnConfigureDone(result);
+ return;
+ }
+
+ if (catch_up_configure_in_progress_) {
+ catch_up_configure_in_progress_ = false;
+ ClearAndRestartSyncForPassphraseEncryption();
+ return;
+ }
+
+ StartSyncingWithServer();
+}
+
+void ProfileSyncService::OnConfigureStart() {
+ sync_configure_start_time_ = base::Time::Now();
+ NotifyObservers();
+}
+
+ProfileSyncService::SyncStatusSummary
+ProfileSyncService::QuerySyncStatusSummary() {
+ if (HasUnrecoverableError()) {
+ return UNRECOVERABLE_ERROR;
+ } else if (!backend_) {
+ return NOT_ENABLED;
+ } else if (backend_.get() && !IsFirstSetupComplete()) {
+ return SETUP_INCOMPLETE;
+ } else if (backend_ && IsFirstSetupComplete() && data_type_manager_ &&
+ data_type_manager_->state() == DataTypeManager::STOPPED) {
+ return DATATYPES_NOT_INITIALIZED;
+ } else if (IsSyncActive()) {
+ return INITIALIZED;
+ }
+ return UNKNOWN_ERROR;
+}
+
+std::string ProfileSyncService::QuerySyncStatusSummaryString() {
+ SyncStatusSummary status = QuerySyncStatusSummary();
+
+ std::string config_status_str =
+ configure_status_ != DataTypeManager::UNKNOWN
+ ? DataTypeManager::ConfigureStatusToString(configure_status_)
+ : "";
+
+ switch (status) {
+ case UNRECOVERABLE_ERROR:
+ return "Unrecoverable error detected";
+ case NOT_ENABLED:
+ return "Syncing not enabled";
+ case SETUP_INCOMPLETE:
+ return "First time sync setup incomplete";
+ case DATATYPES_NOT_INITIALIZED:
+ return "Datatypes not fully initialized";
+ case INITIALIZED:
+ return "Sync service initialized";
+ default:
+ return "Status unknown: Internal error?";
+ }
+}
+
+std::string ProfileSyncService::GetBackendInitializationStateString() const {
+ return startup_controller_->GetBackendInitializationStateString();
+}
+
+bool ProfileSyncService::IsSetupInProgress() const {
+ return startup_controller_->IsSetupInProgress();
+}
+
+bool ProfileSyncService::QueryDetailedSyncStatus(
+ SyncBackendHost::Status* result) {
+ if (backend_.get() && backend_initialized_) {
+ *result = backend_->GetDetailedStatus();
+ return true;
+ } else {
+ SyncBackendHost::Status status;
+ status.sync_protocol_error = last_actionable_error_;
+ *result = status;
+ return false;
+ }
+}
+
+const AuthError& ProfileSyncService::GetAuthError() const {
+ return last_auth_error_;
+}
+
+bool ProfileSyncService::CanConfigureDataTypes() const {
+ return IsFirstSetupComplete() && !IsSetupInProgress();
+}
+
+bool ProfileSyncService::IsFirstSetupInProgress() const {
+ return !IsFirstSetupComplete() && startup_controller_->IsSetupInProgress();
+}
+
+std::unique_ptr<syncer::SyncSetupInProgressHandle>
+ProfileSyncService::GetSetupInProgressHandle() {
+ if (++outstanding_setup_in_progress_handles_ == 1) {
+ DCHECK(!startup_controller_->IsSetupInProgress());
+ startup_controller_->SetSetupInProgress(true);
+
+ NotifyObservers();
+ }
+
+ return std::unique_ptr<syncer::SyncSetupInProgressHandle>(
+ new syncer::SyncSetupInProgressHandle(
+ base::Bind(&ProfileSyncService::OnSetupInProgressHandleDestroyed,
+ weak_factory_.GetWeakPtr())));
+}
+
+bool ProfileSyncService::IsSyncAllowed() const {
+ return IsSyncAllowedByFlag() && !IsManaged() && IsSyncAllowedByPlatform();
+}
+
+bool ProfileSyncService::IsSyncActive() const {
+ return backend_initialized_ && data_type_manager_ &&
+ data_type_manager_->state() != DataTypeManager::STOPPED;
+}
+
+void ProfileSyncService::TriggerRefresh(const syncer::ModelTypeSet& types) {
+ if (backend_initialized_)
+ backend_->TriggerRefresh(types);
+}
+
+bool ProfileSyncService::IsSignedIn() const {
+ // Sync is logged in if there is a non-empty effective account id.
+ return !signin_->GetAccountIdToUse().empty();
+}
+
+bool ProfileSyncService::CanBackendStart() const {
+ return CanSyncStart() && oauth2_token_service_ &&
+ oauth2_token_service_->RefreshTokenIsAvailable(
+ signin_->GetAccountIdToUse());
+}
+
+bool ProfileSyncService::IsBackendInitialized() const {
+ return backend_initialized_;
+}
+
+bool ProfileSyncService::ConfigurationDone() const {
+ return data_type_manager_ &&
+ data_type_manager_->state() == DataTypeManager::CONFIGURED;
+}
+
+bool ProfileSyncService::waiting_for_auth() const {
+ return is_auth_in_progress_;
+}
+
+const syncer::Experiments& ProfileSyncService::current_experiments() const {
+ return current_experiments_;
+}
+
+bool ProfileSyncService::HasUnrecoverableError() const {
+ return unrecoverable_error_reason_ != ERROR_REASON_UNSET;
+}
+
+bool ProfileSyncService::IsPassphraseRequired() const {
+ return passphrase_required_reason_ != syncer::REASON_PASSPHRASE_NOT_REQUIRED;
+}
+
+bool ProfileSyncService::IsPassphraseRequiredForDecryption() const {
+ // If there is an encrypted datatype enabled and we don't have the proper
+ // passphrase, we must prompt the user for a passphrase. The only way for the
+ // user to avoid entering their passphrase is to disable the encrypted types.
+ return IsEncryptedDatatypeEnabled() && IsPassphraseRequired();
+}
+
+base::string16 ProfileSyncService::GetLastSyncedTimeString() const {
+ const base::Time last_synced_time = sync_prefs_.GetLastSyncedTime();
+ if (last_synced_time.is_null())
+ return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
+
+ base::TimeDelta time_since_last_sync = base::Time::Now() - last_synced_time;
+
+ if (time_since_last_sync < base::TimeDelta::FromMinutes(1))
+ return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
+
+ return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED,
+ ui::TimeFormat::LENGTH_SHORT,
+ time_since_last_sync);
+}
+
+void ProfileSyncService::UpdateSelectedTypesHistogram(
+ bool sync_everything,
+ const syncer::ModelTypeSet chosen_types) const {
+ if (!IsFirstSetupComplete() ||
+ sync_everything != sync_prefs_.HasKeepEverythingSynced()) {
+ UMA_HISTOGRAM_BOOLEAN("Sync.SyncEverything", sync_everything);
+ }
+
+ // Only log the data types that are shown in the sync settings ui.
+ // Note: the order of these types must match the ordering of
+ // the respective types in ModelType
+ const syncer::user_selectable_type::UserSelectableSyncType
+ user_selectable_types[] = {
+ syncer::user_selectable_type::BOOKMARKS,
+ syncer::user_selectable_type::PREFERENCES,
+ syncer::user_selectable_type::PASSWORDS,
+ syncer::user_selectable_type::AUTOFILL,
+ syncer::user_selectable_type::THEMES,
+ syncer::user_selectable_type::TYPED_URLS,
+ syncer::user_selectable_type::EXTENSIONS,
+ syncer::user_selectable_type::APPS,
+ syncer::user_selectable_type::PROXY_TABS,
+ };
+
+ static_assert(39 == syncer::MODEL_TYPE_COUNT,
+ "custom config histogram must be updated");
+
+ if (!sync_everything) {
+ const syncer::ModelTypeSet current_types = GetPreferredDataTypes();
+
+ syncer::ModelTypeSet type_set = syncer::UserSelectableTypes();
+ syncer::ModelTypeSet::Iterator it = type_set.First();
+
+ DCHECK_EQ(arraysize(user_selectable_types), type_set.Size());
+
+ for (size_t i = 0; i < arraysize(user_selectable_types) && it.Good();
+ ++i, it.Inc()) {
+ const syncer::ModelType type = it.Get();
+ if (chosen_types.Has(type) &&
+ (!IsFirstSetupComplete() || !current_types.Has(type))) {
+ // Selected type has changed - log it.
+ UMA_HISTOGRAM_ENUMERATION(
+ "Sync.CustomSync", user_selectable_types[i],
+ syncer::user_selectable_type::SELECTABLE_DATATYPE_COUNT + 1);
+ }
+ }
+ }
+}
+
+#if defined(OS_CHROMEOS)
+void ProfileSyncService::RefreshSpareBootstrapToken(
+ const std::string& passphrase) {
+ syncer::SystemEncryptor encryptor;
+ syncer::Cryptographer temp_cryptographer(&encryptor);
+ // The first 2 params (hostname and username) doesn't have any effect here.
+ syncer::KeyParams key_params = {"localhost", "dummy", passphrase};
+
+ std::string bootstrap_token;
+ if (!temp_cryptographer.AddKey(key_params)) {
+ NOTREACHED() << "Failed to add key to cryptographer.";
+ }
+ temp_cryptographer.GetBootstrapToken(&bootstrap_token);
+ sync_prefs_.SetSpareBootstrapToken(bootstrap_token);
+}
+#endif
+
+void ProfileSyncService::OnUserChoseDatatypes(
+ bool sync_everything,
+ syncer::ModelTypeSet chosen_types) {
+ DCHECK(syncer::UserSelectableTypes().HasAll(chosen_types));
+
+ if (!backend_.get() && !HasUnrecoverableError()) {
+ NOTREACHED();
+ return;
+ }
+
+ UpdateSelectedTypesHistogram(sync_everything, chosen_types);
+ sync_prefs_.SetKeepEverythingSynced(sync_everything);
+
+ if (data_type_manager_)
+ data_type_manager_->ResetDataTypeErrors();
+ ChangePreferredDataTypes(chosen_types);
+}
+
+void ProfileSyncService::ChangePreferredDataTypes(
+ syncer::ModelTypeSet preferred_types) {
+ DVLOG(1) << "ChangePreferredDataTypes invoked";
+ const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
+ // Will only enable those types that are registered and preferred.
+ sync_prefs_.SetPreferredDataTypes(registered_types, preferred_types);
+
+ // Now reconfigure the DTM.
+ ReconfigureDatatypeManager();
+}
+
+syncer::ModelTypeSet ProfileSyncService::GetActiveDataTypes() const {
+ if (!IsSyncActive() || !ConfigurationDone())
+ return syncer::ModelTypeSet();
+ const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
+ const syncer::ModelTypeSet failed_types =
+ data_type_status_table_.GetFailedTypes();
+ return Difference(preferred_types, failed_types);
+}
+
+syncer::SyncClient* ProfileSyncService::GetSyncClient() const {
+ return sync_client_.get();
+}
+
+syncer::ModelTypeSet ProfileSyncService::GetPreferredDataTypes() const {
+ const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
+ const syncer::ModelTypeSet preferred_types =
+ Union(sync_prefs_.GetPreferredDataTypes(registered_types),
+ syncer::ControlTypes());
+ const syncer::ModelTypeSet enforced_types =
+ Intersection(GetDataTypesFromPreferenceProviders(), registered_types);
+ return Union(preferred_types, enforced_types);
+}
+
+syncer::ModelTypeSet ProfileSyncService::GetForcedDataTypes() const {
+ // TODO(treib,zea): When SyncPrefs also implements SyncTypePreferenceProvider,
+ // we'll need another way to distinguish user-choosable types from
+ // programmatically-enabled types.
+ return GetDataTypesFromPreferenceProviders();
+}
+
+syncer::ModelTypeSet ProfileSyncService::GetRegisteredDataTypes() const {
+ syncer::ModelTypeSet registered_types;
+ // The data_type_controllers_ are determined by command-line flags;
+ // that's effectively what controls the values returned here.
+ for (DataTypeController::TypeMap::const_iterator it =
+ data_type_controllers_.begin();
+ it != data_type_controllers_.end(); ++it) {
+ registered_types.Put(it->first);
+ }
+ return registered_types;
+}
+
+bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
+ syncer::PassphraseType passphrase_type = GetPassphraseType();
+ return passphrase_type ==
+ syncer::PassphraseType::FROZEN_IMPLICIT_PASSPHRASE ||
+ passphrase_type == syncer::PassphraseType::CUSTOM_PASSPHRASE;
+}
+
+std::string ProfileSyncService::GetCustomPassphraseKey() const {
+ syncer::SystemEncryptor encryptor;
+ syncer::Cryptographer cryptographer(&encryptor);
+ cryptographer.Bootstrap(sync_prefs_.GetEncryptionBootstrapToken());
+ return cryptographer.GetDefaultNigoriKeyData();
+}
+
+syncer::PassphraseType ProfileSyncService::GetPassphraseType() const {
+ return backend_->GetPassphraseType();
+}
+
+base::Time ProfileSyncService::GetExplicitPassphraseTime() const {
+ return backend_->GetExplicitPassphraseTime();
+}
+
+bool ProfileSyncService::IsCryptographerReady(
+ const syncer::BaseTransaction* trans) const {
+ return backend_.get() && backend_->IsCryptographerReady(trans);
+}
+
+void ProfileSyncService::SetPlatformSyncAllowedProvider(
+ const PlatformSyncAllowedProvider& platform_sync_allowed_provider) {
+ platform_sync_allowed_provider_ = platform_sync_allowed_provider;
+}
+
+void ProfileSyncService::ConfigureDataTypeManager() {
+ // Don't configure datatypes if the setup UI is still on the screen - this
+ // is to help multi-screen setting UIs (like iOS) where they don't want to
+ // start syncing data until the user is done configuring encryption options,
+ // etc. ReconfigureDatatypeManager() will get called again once the UI calls
+ // SetSetupInProgress(false).
+ if (!CanConfigureDataTypes()) {
+ // If we can't configure the data type manager yet, we should still notify
+ // observers. This is to support multiple setup UIs being open at once.
+ NotifyObservers();
+ return;
+ }
+
+ bool restart = false;
+ if (!data_type_manager_) {
+ restart = true;
+ data_type_manager_.reset(
+ sync_client_->GetSyncApiComponentFactory()->CreateDataTypeManager(
+ debug_info_listener_, &data_type_controllers_, this, backend_.get(),
+ this));
+
+ // We create the migrator at the same time.
+ migrator_.reset(new BackendMigrator(
+ debug_identifier_, GetUserShare(), this, data_type_manager_.get(),
+ base::Bind(&ProfileSyncService::StartSyncingWithServer,
+ base::Unretained(this))));
+ }
+
+ syncer::ModelTypeSet types;
+ syncer::ConfigureReason reason = syncer::CONFIGURE_REASON_UNKNOWN;
+ types = GetPreferredDataTypes();
+ if (restart) {
+ // Datatype downloads on restart are generally due to newly supported
+ // datatypes (although it's also possible we're picking up where a failed
+ // previous configuration left off).
+ // TODO(sync): consider detecting configuration recovery and setting
+ // the reason here appropriately.
+ reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
+ } else {
+ // The user initiated a reconfiguration (either to add or remove types).
+ reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
+ }
+
+ data_type_manager_->Configure(types, reason);
+}
+
+syncer::UserShare* ProfileSyncService::GetUserShare() const {
+ if (backend_.get() && backend_initialized_) {
+ return backend_->GetUserShare();
+ }
+ NOTREACHED();
+ return NULL;
+}
+
+syncer::SyncCycleSnapshot ProfileSyncService::GetLastCycleSnapshot() const {
+ if (backend_)
+ return backend_->GetLastCycleSnapshot();
+ return syncer::SyncCycleSnapshot();
+}
+
+bool ProfileSyncService::HasUnsyncedItems() const {
+ if (HasSyncingBackend() && backend_initialized_) {
+ return backend_->HasUnsyncedItems();
+ }
+ NOTREACHED();
+ return false;
+}
+
+BackendMigrator* ProfileSyncService::GetBackendMigratorForTest() {
+ return migrator_.get();
+}
+
+void ProfileSyncService::GetModelSafeRoutingInfo(
+ syncer::ModelSafeRoutingInfo* out) const {
+ if (backend_.get() && backend_initialized_) {
+ backend_->GetModelSafeRoutingInfo(out);
+ } else {
+ NOTREACHED();
+ }
+}
+
+base::Value* ProfileSyncService::GetTypeStatusMap() const {
+ std::unique_ptr<base::ListValue> result(new base::ListValue());
+
+ if (!backend_.get() || !backend_initialized_) {
+ return result.release();
+ }
+
+ DataTypeStatusTable::TypeErrorMap error_map =
+ data_type_status_table_.GetAllErrors();
+ ModelTypeSet active_types;
+ ModelTypeSet passive_types;
+ ModelSafeRoutingInfo routing_info;
+ backend_->GetModelSafeRoutingInfo(&routing_info);
+ for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
+ it != routing_info.end(); ++it) {
+ if (it->second == syncer::GROUP_PASSIVE) {
+ passive_types.Put(it->first);
+ } else {
+ active_types.Put(it->first);
+ }
+ }
+
+ SyncBackendHost::Status detailed_status = backend_->GetDetailedStatus();
+ ModelTypeSet& throttled_types(detailed_status.throttled_types);
+ ModelTypeSet registered = GetRegisteredDataTypes();
+ std::unique_ptr<base::DictionaryValue> type_status_header(
+ new base::DictionaryValue());
+
+ type_status_header->SetString("name", "Model Type");
+ type_status_header->SetString("status", "header");
+ type_status_header->SetString("value", "Group Type");
+ type_status_header->SetString("num_entries", "Total Entries");
+ type_status_header->SetString("num_live", "Live Entries");
+ result->Append(std::move(type_status_header));
+
+ std::unique_ptr<base::DictionaryValue> type_status;
+ for (ModelTypeSet::Iterator it = registered.First(); it.Good(); it.Inc()) {
+ ModelType type = it.Get();
+
+ type_status.reset(new base::DictionaryValue());
+ type_status->SetString("name", ModelTypeToString(type));
+
+ if (error_map.find(type) != error_map.end()) {
+ const syncer::SyncError& error = error_map.find(type)->second;
+ DCHECK(error.IsSet());
+ switch (error.GetSeverity()) {
+ case syncer::SyncError::SYNC_ERROR_SEVERITY_ERROR:
+ type_status->SetString("status", "error");
+ type_status->SetString(
+ "value", "Error: " + error.location().ToString() + ", " +
+ error.GetMessagePrefix() + error.message());
+ break;
+ case syncer::SyncError::SYNC_ERROR_SEVERITY_INFO:
+ type_status->SetString("status", "disabled");
+ type_status->SetString("value", error.message());
+ break;
+ default:
+ NOTREACHED() << "Unexpected error severity.";
+ break;
+ }
+ } else if (syncer::IsProxyType(type) && passive_types.Has(type)) {
+ // Show a proxy type in "ok" state unless it is disabled by user.
+ DCHECK(!throttled_types.Has(type));
+ type_status->SetString("status", "ok");
+ type_status->SetString("value", "Passive");
+ } else if (throttled_types.Has(type) && passive_types.Has(type)) {
+ type_status->SetString("status", "warning");
+ type_status->SetString("value", "Passive, Throttled");
+ } else if (passive_types.Has(type)) {
+ type_status->SetString("status", "warning");
+ type_status->SetString("value", "Passive");
+ } else if (throttled_types.Has(type)) {
+ type_status->SetString("status", "warning");
+ type_status->SetString("value", "Throttled");
+ } else if (active_types.Has(type)) {
+ type_status->SetString("status", "ok");
+ type_status->SetString(
+ "value", "Active: " + ModelSafeGroupToString(routing_info[type]));
+ } else {
+ type_status->SetString("status", "warning");
+ type_status->SetString("value", "Disabled by User");
+ }
+
+ int live_count = detailed_status.num_entries_by_type[type] -
+ detailed_status.num_to_delete_entries_by_type[type];
+ type_status->SetInteger("num_entries",
+ detailed_status.num_entries_by_type[type]);
+ type_status->SetInteger("num_live", live_count);
+
+ result->Append(std::move(type_status));
+ }
+ return result.release();
+}
+
+void ProfileSyncService::ConsumeCachedPassphraseIfPossible() {
+ // If no cached passphrase, or sync backend hasn't started up yet, just exit.
+ // If the backend isn't running yet, OnBackendInitialized() will call this
+ // method again after the backend starts up.
+ if (cached_passphrase_.empty() || !IsBackendInitialized())
+ return;
+
+ // Backend is up and running, so we can consume the cached passphrase.
+ std::string passphrase = cached_passphrase_;
+ cached_passphrase_.clear();
+
+ // If we need a passphrase to decrypt data, try the cached passphrase.
+ if (passphrase_required_reason() == syncer::REASON_DECRYPTION) {
+ if (SetDecryptionPassphrase(passphrase)) {
+ DVLOG(1) << "Cached passphrase successfully decrypted pending keys";
+ return;
+ }
+ }
+
+ // If we get here, we don't have pending keys (or at least, the passphrase
+ // doesn't decrypt them) - just try to re-encrypt using the encryption
+ // passphrase.
+ if (!IsUsingSecondaryPassphrase())
+ SetEncryptionPassphrase(passphrase, IMPLICIT);
+}
+
+void ProfileSyncService::RequestAccessToken() {
+ // Only one active request at a time.
+ if (access_token_request_ != NULL)
+ return;
+ request_access_token_retry_timer_.Stop();
+ OAuth2TokenService::ScopeSet oauth2_scopes;
+ oauth2_scopes.insert(signin_->GetSyncScopeToUse());
+
+ // Invalidate previous token, otherwise token service will return the same
+ // token again.
+ const std::string& account_id = signin_->GetAccountIdToUse();
+ if (!access_token_.empty()) {
+ oauth2_token_service_->InvalidateAccessToken(account_id, oauth2_scopes,
+ access_token_);
+ }
+
+ access_token_.clear();
+
+ token_request_time_ = base::Time::Now();
+ token_receive_time_ = base::Time();
+ next_token_request_time_ = base::Time();
+ access_token_request_ =
+ oauth2_token_service_->StartRequest(account_id, oauth2_scopes, this);
+}
+
+void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase,
+ PassphraseType type) {
+ // This should only be called when the backend has been initialized.
+ DCHECK(IsBackendInitialized());
+ DCHECK(!(type == IMPLICIT && IsUsingSecondaryPassphrase()))
+ << "Data is already encrypted using an explicit passphrase";
+ DCHECK(!(type == EXPLICIT &&
+ passphrase_required_reason_ == syncer::REASON_DECRYPTION))
+ << "Can not set explicit passphrase when decryption is needed.";
+
+ DVLOG(1) << "Setting " << (type == EXPLICIT ? "explicit" : "implicit")
+ << " passphrase for encryption.";
+ if (passphrase_required_reason_ == syncer::REASON_ENCRYPTION) {
+ // REASON_ENCRYPTION implies that the cryptographer does not have pending
+ // keys. Hence, as long as we're not trying to do an invalid passphrase
+ // change (e.g. explicit -> explicit or explicit -> implicit), we know this
+ // will succeed. If for some reason a new encryption key arrives via
+ // sync later, the SBH will trigger another OnPassphraseRequired().
+ passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
+ NotifyObservers();
+ }
+ backend_->SetEncryptionPassphrase(passphrase, type == EXPLICIT);
+}
+
+bool ProfileSyncService::SetDecryptionPassphrase(
+ const std::string& passphrase) {
+ if (IsPassphraseRequired()) {
+ DVLOG(1) << "Setting passphrase for decryption.";
+ bool result = backend_->SetDecryptionPassphrase(passphrase);
+ UMA_HISTOGRAM_BOOLEAN("Sync.PassphraseDecryptionSucceeded", result);
+ return result;
+ } else {
+ NOTREACHED() << "SetDecryptionPassphrase must not be called when "
+ "IsPassphraseRequired() is false.";
+ return false;
+ }
+}
+
+bool ProfileSyncService::IsEncryptEverythingAllowed() const {
+ return encrypt_everything_allowed_;
+}
+
+void ProfileSyncService::SetEncryptEverythingAllowed(bool allowed) {
+ DCHECK(allowed || !IsBackendInitialized() || !IsEncryptEverythingEnabled());
+ encrypt_everything_allowed_ = allowed;
+}
+
+void ProfileSyncService::EnableEncryptEverything() {
+ DCHECK(IsEncryptEverythingAllowed());
+
+ // Tests override IsBackendInitialized() to always return true, so we
+ // must check that instead of |backend_initialized_|.
+ // TODO(akalin): Fix the above. :/
+ DCHECK(IsBackendInitialized());
+ // TODO(atwilson): Persist the encryption_pending_ flag to address the various
+ // problems around cancelling encryption in the background (crbug.com/119649).
+ if (!encrypt_everything_)
+ encryption_pending_ = true;
+}
+
+bool ProfileSyncService::encryption_pending() const {
+ // We may be called during the setup process before we're
+ // initialized (via IsEncryptedDatatypeEnabled and
+ // IsPassphraseRequiredForDecryption).
+ return encryption_pending_;
+}
+
+bool ProfileSyncService::IsEncryptEverythingEnabled() const {
+ DCHECK(backend_initialized_);
+ return encrypt_everything_ || encryption_pending_;
+}
+
+syncer::ModelTypeSet ProfileSyncService::GetEncryptedDataTypes() const {
+ DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
+ // We may be called during the setup process before we're
+ // initialized. In this case, we default to the sensitive types.
+ return encrypted_types_;
+}
+
+void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) {
+ if (is_sync_managed) {
+ StopImpl(CLEAR_DATA);
+ } else {
+ // Sync is no longer disabled by policy. Try starting it up if appropriate.
+ startup_controller_->TryStart();
+ }
+}
+
+void ProfileSyncService::GoogleSigninSucceeded(const std::string& account_id,
+ const std::string& username,
+ const std::string& password) {
+ if (IsSyncRequested() && !password.empty()) {
+ cached_passphrase_ = password;
+ // Try to consume the passphrase we just cached. If the sync backend
+ // is not running yet, the passphrase will remain cached until the
+ // backend starts up.
+ ConsumeCachedPassphraseIfPossible();
+ }
+#if defined(OS_CHROMEOS)
+ RefreshSpareBootstrapToken(password);
+#endif
+ if (!IsBackendInitialized() || GetAuthError().state() != AuthError::NONE) {
+ // Track the fact that we're still waiting for auth to complete.
+ is_auth_in_progress_ = true;
+ }
+}
+
+void ProfileSyncService::GoogleSignedOut(const std::string& account_id,
+ const std::string& username) {
+ sync_disabled_by_admin_ = false;
+ UMA_HISTOGRAM_ENUMERATION("Sync.StopSource", syncer::SIGN_OUT,
+ syncer::STOP_SOURCE_LIMIT);
+ RequestStop(CLEAR_DATA);
+}
+
+void ProfileSyncService::OnGaiaAccountsInCookieUpdated(
+ const std::vector<gaia::ListedAccount>& accounts,
+ const std::vector<gaia::ListedAccount>& signed_out_accounts,
+ const GoogleServiceAuthError& error) {
+ if (!IsBackendInitialized())
+ return;
+
+ bool cookie_jar_mismatch = true;
+ bool cookie_jar_empty = accounts.size() == 0;
+ std::string account_id = signin_->GetAccountIdToUse();
+
+ // Iterate through list of accounts, looking for current sync account.
+ for (const auto& account : accounts) {
+ if (account.id == account_id) {
+ cookie_jar_mismatch = false;
+ break;
+ }
+ }
+
+ DVLOG(1) << "Cookie jar mismatch: " << cookie_jar_mismatch;
+ DVLOG(1) << "Cookie jar empty: " << cookie_jar_empty;
+ backend_->OnCookieJarChanged(cookie_jar_mismatch, cookie_jar_empty);
+}
+
+void ProfileSyncService::AddObserver(syncer::SyncServiceObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ProfileSyncService::RemoveObserver(syncer::SyncServiceObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void ProfileSyncService::AddProtocolEventObserver(
+ ProtocolEventObserver* observer) {
+ protocol_event_observers_.AddObserver(observer);
+ if (HasSyncingBackend()) {
+ backend_->RequestBufferedProtocolEventsAndEnableForwarding();
+ }
+}
+
+void ProfileSyncService::RemoveProtocolEventObserver(
+ ProtocolEventObserver* observer) {
+ protocol_event_observers_.RemoveObserver(observer);
+ if (HasSyncingBackend() &&
+ !protocol_event_observers_.might_have_observers()) {
+ backend_->DisableProtocolEventForwarding();
+ }
+}
+
+void ProfileSyncService::AddTypeDebugInfoObserver(
+ syncer::TypeDebugInfoObserver* type_debug_info_observer) {
+ type_debug_info_observers_.AddObserver(type_debug_info_observer);
+ if (type_debug_info_observers_.might_have_observers() &&
+ backend_initialized_) {
+ backend_->EnableDirectoryTypeDebugInfoForwarding();
+ }
+}
+
+void ProfileSyncService::RemoveTypeDebugInfoObserver(
+ syncer::TypeDebugInfoObserver* type_debug_info_observer) {
+ type_debug_info_observers_.RemoveObserver(type_debug_info_observer);
+ if (!type_debug_info_observers_.might_have_observers() &&
+ backend_initialized_) {
+ backend_->DisableDirectoryTypeDebugInfoForwarding();
+ }
+}
+
+void ProfileSyncService::AddPreferenceProvider(
+ syncer::SyncTypePreferenceProvider* provider) {
+ DCHECK(!HasPreferenceProvider(provider))
+ << "Providers may only be added once!";
+ preference_providers_.insert(provider);
+}
+
+void ProfileSyncService::RemovePreferenceProvider(
+ syncer::SyncTypePreferenceProvider* provider) {
+ DCHECK(HasPreferenceProvider(provider))
+ << "Only providers that have been added before can be removed!";
+ preference_providers_.erase(provider);
+}
+
+bool ProfileSyncService::HasPreferenceProvider(
+ syncer::SyncTypePreferenceProvider* provider) const {
+ return preference_providers_.count(provider) > 0;
+}
+
+namespace {
+
+class GetAllNodesRequestHelper
+ : public base::RefCountedThreadSafe<GetAllNodesRequestHelper> {
+ public:
+ GetAllNodesRequestHelper(
+ syncer::ModelTypeSet requested_types,
+ const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback);
+
+ void OnReceivedNodesForType(const syncer::ModelType type,
+ std::unique_ptr<base::ListValue> node_list);
+
+ private:
+ friend class base::RefCountedThreadSafe<GetAllNodesRequestHelper>;
+ virtual ~GetAllNodesRequestHelper();
+
+ std::unique_ptr<base::ListValue> result_accumulator_;
+
+ syncer::ModelTypeSet awaiting_types_;
+ base::Callback<void(std::unique_ptr<base::ListValue>)> callback_;
+};
+
+GetAllNodesRequestHelper::GetAllNodesRequestHelper(
+ syncer::ModelTypeSet requested_types,
+ const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback)
+ : result_accumulator_(new base::ListValue()),
+ awaiting_types_(requested_types),
+ callback_(callback) {}
+
+GetAllNodesRequestHelper::~GetAllNodesRequestHelper() {
+ if (!awaiting_types_.Empty()) {
+ DLOG(WARNING)
+ << "GetAllNodesRequest deleted before request was fulfilled. "
+ << "Missing types are: " << ModelTypeSetToString(awaiting_types_);
+ }
+}
+
+// Called when the set of nodes for a type has been returned.
+// Only return one type of nodes each time.
+void GetAllNodesRequestHelper::OnReceivedNodesForType(
+ const syncer::ModelType type,
+ std::unique_ptr<base::ListValue> node_list) {
+ // Add these results to our list.
+ std::unique_ptr<base::DictionaryValue> type_dict(new base::DictionaryValue());
+ type_dict->SetString("type", ModelTypeToString(type));
+ type_dict->Set("nodes", std::move(node_list));
+ result_accumulator_->Append(std::move(type_dict));
+
+ // Remember that this part of the request is satisfied.
+ awaiting_types_.Remove(type);
+
+ if (awaiting_types_.Empty()) {
+ callback_.Run(std::move(result_accumulator_));
+ callback_.Reset();
+ }
+}
+
+} // namespace
+
+void ProfileSyncService::GetAllNodes(
+ const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback) {
+ // TODO(stanisc): crbug.com/328606: Make this work for USS datatypes.
+ ModelTypeSet all_types = GetActiveDataTypes();
+ all_types.PutAll(syncer::ControlTypes());
+ scoped_refptr<GetAllNodesRequestHelper> helper =
+ new GetAllNodesRequestHelper(all_types, callback);
+
+ if (!backend_initialized_) {
+ // If there's no backend available to fulfill the request, handle it here.
+ for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
+ helper->OnReceivedNodesForType(it.Get(),
+ base::MakeUnique<base::ListValue>());
+ }
+ return;
+ }
+
+ for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
+ const auto& dtc_iter = data_type_controllers_.find(it.Get());
+ if (dtc_iter != data_type_controllers_.end()) {
+ dtc_iter->second->GetAllNodes(base::Bind(
+ &GetAllNodesRequestHelper::OnReceivedNodesForType, helper));
+ } else {
+ // Control Types
+ helper->OnReceivedNodesForType(
+ it.Get(),
+ syncer::DirectoryDataTypeController::GetAllNodesForTypeFromDirectory(
+ it.Get(), GetUserShare()->directory.get()));
+ }
+ }
+}
+
+bool ProfileSyncService::HasObserver(
+ const syncer::SyncServiceObserver* observer) const {
+ return observers_.HasObserver(observer);
+}
+
+base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() {
+ return sync_js_controller_.AsWeakPtr();
+}
+
+void ProfileSyncService::SyncEvent(SyncEventCodes code) {
+ UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code, MAX_SYNC_EVENT_CODE);
+}
+
+// static
+bool ProfileSyncService::IsSyncAllowedByFlag() {
+ return !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableSync);
+}
+
+bool ProfileSyncService::IsSyncAllowedByPlatform() const {
+ return platform_sync_allowed_provider_.is_null() ||
+ platform_sync_allowed_provider_.Run();
+}
+
+bool ProfileSyncService::IsManaged() const {
+ return sync_prefs_.IsManaged() || sync_disabled_by_admin_;
+}
+
+void ProfileSyncService::RequestStop(SyncStopDataFate data_fate) {
+ sync_prefs_.SetSyncRequested(false);
+ StopImpl(data_fate);
+}
+
+bool ProfileSyncService::IsSyncRequested() const {
+ return sync_prefs_.IsSyncRequested();
+}
+
+SigninManagerBase* ProfileSyncService::signin() const {
+ if (!signin_)
+ return NULL;
+ return signin_->GetOriginal();
+}
+
+void ProfileSyncService::RequestStart() {
+ if (!IsSyncAllowed()) {
+ // Sync cannot be requested if it's not allowed.
+ return;
+ }
+ DCHECK(sync_client_);
+ if (!IsSyncRequested()) {
+ sync_prefs_.SetSyncRequested(true);
+ NotifyObservers();
+ }
+ startup_controller_->TryStartImmediately();
+}
+
+void ProfileSyncService::ReconfigureDatatypeManager() {
+ // If we haven't initialized yet, don't configure the DTM as it could cause
+ // association to start before a Directory has even been created.
+ if (backend_initialized_) {
+ DCHECK(backend_.get());
+ ConfigureDataTypeManager();
+ } else if (HasUnrecoverableError()) {
+ // There is nothing more to configure. So inform the listeners,
+ NotifyObservers();
+
+ DVLOG(1) << "ConfigureDataTypeManager not invoked because of an "
+ << "Unrecoverable error.";
+ } else {
+ DVLOG(0) << "ConfigureDataTypeManager not invoked because backend is not "
+ << "initialized";
+ }
+}
+
+syncer::ModelTypeSet ProfileSyncService::GetDataTypesFromPreferenceProviders()
+ const {
+ syncer::ModelTypeSet types;
+ for (std::set<syncer::SyncTypePreferenceProvider*>::const_iterator it =
+ preference_providers_.begin();
+ it != preference_providers_.end(); ++it) {
+ types.PutAll((*it)->GetPreferredDataTypes());
+ }
+ return types;
+}
+
+const DataTypeStatusTable& ProfileSyncService::data_type_status_table() const {
+ return data_type_status_table_;
+}
+
+void ProfileSyncService::OnInternalUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message,
+ bool delete_sync_database,
+ UnrecoverableErrorReason reason) {
+ DCHECK(!HasUnrecoverableError());
+ unrecoverable_error_reason_ = reason;
+ OnUnrecoverableErrorImpl(from_here, message, delete_sync_database);
+}
+
+bool ProfileSyncService::IsRetryingAccessTokenFetchForTest() const {
+ return request_access_token_retry_timer_.IsRunning();
+}
+
+std::string ProfileSyncService::GetAccessTokenForTest() const {
+ return access_token_;
+}
+
+WeakHandle<syncer::JsEventHandler> ProfileSyncService::GetJsEventHandler() {
+ return MakeWeakHandle(sync_js_controller_.AsWeakPtr());
+}
+
+syncer::SyncableService* ProfileSyncService::GetSessionsSyncableService() {
+ return sessions_sync_manager_.get();
+}
+
+syncer::SyncableService* ProfileSyncService::GetDeviceInfoSyncableService() {
+ return device_info_sync_service_.get();
+}
+
+syncer::ModelTypeService* ProfileSyncService::GetDeviceInfoService() {
+ return device_info_service_.get();
+}
+
+syncer::SyncService::SyncTokenStatus ProfileSyncService::GetSyncTokenStatus()
+ const {
+ SyncTokenStatus status;
+ status.connection_status_update_time = connection_status_update_time_;
+ status.connection_status = connection_status_;
+ status.token_request_time = token_request_time_;
+ status.token_receive_time = token_receive_time_;
+ status.last_get_token_error = last_get_token_error_;
+ if (request_access_token_retry_timer_.IsRunning())
+ status.next_token_request_time = next_token_request_time_;
+ return status;
+}
+
+void ProfileSyncService::OverrideNetworkResourcesForTest(
+ std::unique_ptr<syncer::NetworkResources> network_resources) {
+ network_resources_ = std::move(network_resources);
+}
+
+bool ProfileSyncService::HasSyncingBackend() const {
+ return backend_ != NULL;
+}
+
+void ProfileSyncService::UpdateFirstSyncTimePref() {
+ if (!IsSignedIn()) {
+ sync_prefs_.ClearFirstSyncTime();
+ } else if (sync_prefs_.GetFirstSyncTime().is_null()) {
+ // Set if not set before and it's syncing now.
+ sync_prefs_.SetFirstSyncTime(base::Time::Now());
+ }
+}
+
+void ProfileSyncService::FlushDirectory() const {
+ // backend_initialized_ implies backend_ isn't NULL and the manager exists.
+ // If sync is not initialized yet, we fail silently.
+ if (backend_initialized_)
+ backend_->FlushDirectory();
+}
+
+base::FilePath ProfileSyncService::GetDirectoryPathForTest() const {
+ return directory_path_;
+}
+
+base::MessageLoop* ProfileSyncService::GetSyncLoopForTest() const {
+ if (sync_thread_) {
+ return sync_thread_->message_loop();
+ } else if (backend_) {
+ return backend_->GetSyncLoopForTesting();
+ } else {
+ return NULL;
+ }
+}
+
+void ProfileSyncService::RefreshTypesForTest(syncer::ModelTypeSet types) {
+ if (backend_initialized_)
+ backend_->RefreshTypesForTest(types);
+}
+
+void ProfileSyncService::RemoveClientFromServer() const {
+ if (!backend_initialized_)
+ return;
+ const std::string cache_guid = local_device_->GetLocalSyncCacheGUID();
+ std::string birthday;
+ syncer::UserShare* user_share = GetUserShare();
+ if (user_share && user_share->directory.get()) {
+ birthday = user_share->directory->store_birthday();
+ }
+ if (!access_token_.empty() && !cache_guid.empty() && !birthday.empty()) {
+ sync_stopped_reporter_->ReportSyncStopped(access_token_, cache_guid,
+ birthday);
+ }
+}
+
+void ProfileSyncService::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ if (memory_pressure_level ==
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+ sync_prefs_.SetMemoryPressureWarningCount(
+ sync_prefs_.GetMemoryPressureWarningCount() + 1);
+ }
+}
+
+void ProfileSyncService::ReportPreviousSessionMemoryWarningCount() {
+ int warning_received = sync_prefs_.GetMemoryPressureWarningCount();
+
+ if (-1 != warning_received) {
+ // -1 means it is new client.
+ if (!sync_prefs_.DidSyncShutdownCleanly()) {
+ UMA_HISTOGRAM_COUNTS("Sync.MemoryPressureWarningBeforeUncleanShutdown",
+ warning_received);
+ } else {
+ UMA_HISTOGRAM_COUNTS("Sync.MemoryPressureWarningBeforeCleanShutdown",
+ warning_received);
+ }
+ }
+ sync_prefs_.SetMemoryPressureWarningCount(0);
+ // Will set to true during a clean shutdown, so crash or something else will
+ // remain this as false.
+ sync_prefs_.SetCleanShutdown(false);
+}
+
+const GURL& ProfileSyncService::sync_service_url() const {
+ return sync_service_url_;
+}
+
+std::string ProfileSyncService::unrecoverable_error_message() const {
+ return unrecoverable_error_message_;
+}
+
+tracked_objects::Location ProfileSyncService::unrecoverable_error_location()
+ const {
+ return unrecoverable_error_location_;
+}
+
+void ProfileSyncService::OnSetupInProgressHandleDestroyed() {
+ DCHECK_GT(outstanding_setup_in_progress_handles_, 0);
+
+ // Don't re-start Sync until all outstanding handles are destroyed.
+ if (--outstanding_setup_in_progress_handles_ != 0)
+ return;
+
+ DCHECK(startup_controller_->IsSetupInProgress());
+ startup_controller_->SetSetupInProgress(false);
+
+ if (IsBackendInitialized())
+ ReconfigureDatatypeManager();
+ NotifyObservers();
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_service.h b/chromium/components/browser_sync/profile_sync_service.h
new file mode 100644
index 00000000000..f0fb9945b8d
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_service.h
@@ -0,0 +1,1017 @@
+// 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 COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_
+#define COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/strings/string16.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "build/build_config.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/signin/core/browser/gaia_cookie_manager_service.h"
+#include "components/signin/core/browser/signin_manager_base.h"
+#include "components/sync/base/experiments.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/base/unrecoverable_error_handler.h"
+#include "components/sync/core/network_time_update_callback.h"
+#include "components/sync/core/shutdown_reason.h"
+#include "components/sync/core/sync_manager_factory.h"
+#include "components/sync/core/user_share.h"
+#include "components/sync/device_info/local_device_info_provider.h"
+#include "components/sync/driver/data_type_controller.h"
+#include "components/sync/driver/data_type_manager.h"
+#include "components/sync/driver/data_type_manager_observer.h"
+#include "components/sync/driver/data_type_status_table.h"
+#include "components/sync/driver/glue/sync_backend_host.h"
+#include "components/sync/driver/protocol_event_observer.h"
+#include "components/sync/driver/startup_controller.h"
+#include "components/sync/driver/sync_client.h"
+#include "components/sync/driver/sync_frontend.h"
+#include "components/sync/driver/sync_prefs.h"
+#include "components/sync/driver/sync_service.h"
+#include "components/sync/driver/sync_stopped_reporter.h"
+#include "components/sync/engine/model_safe_worker.h"
+#include "components/sync/js/sync_js_controller.h"
+#include "components/version_info/version_info.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "net/base/backoff_entry.h"
+#include "url/gurl.h"
+
+class Profile;
+class ProfileOAuth2TokenService;
+class SigninManagerWrapper;
+
+namespace sync_pb {
+class EncryptedData;
+} // namespace sync_pb
+
+namespace sync_sessions {
+class FaviconCache;
+class OpenTabsUIDelegate;
+class SessionsSyncManager;
+} // namespace sync_sessions
+
+namespace syncer {
+class BackendMigrator;
+class BaseTransaction;
+class DataTypeManager;
+class DeviceInfoService;
+class DeviceInfoSyncService;
+class DeviceInfoTracker;
+class LocalDeviceInfoProvider;
+class NetworkResources;
+class SyncApiComponentFactory;
+class SyncClient;
+class SyncErrorController;
+class SyncTypePreferenceProvider;
+class TypeDebugInfoObserver;
+struct CommitCounters;
+struct StatusCounters;
+struct SyncCredentials;
+struct UpdateCounters;
+struct UserShare;
+} // namespace syncer
+
+namespace browser_sync {
+
+// ProfileSyncService is the layer between browser subsystems like bookmarks,
+// and the sync backend. Each subsystem is logically thought of as being
+// a sync datatype.
+//
+// Individual datatypes can, at any point, be in a variety of stages of being
+// "enabled". Here are some specific terms for concepts used in this class:
+//
+// 'Registered' (feature suppression for a datatype)
+//
+// When a datatype is registered, the user has the option of syncing it.
+// The sync opt-in UI will show only registered types; a checkbox should
+// never be shown for an unregistered type, and nor should it ever be
+// synced.
+//
+// A datatype is considered registered once RegisterDataTypeController
+// has been called with that datatype's DataTypeController.
+//
+// 'Preferred' (user preferences and opt-out for a datatype)
+//
+// This means the user's opt-in or opt-out preference on a per-datatype
+// basis. The sync service will try to make active exactly these types.
+// If a user has opted out of syncing a particular datatype, it will
+// be registered, but not preferred.
+//
+// This state is controlled by the ConfigurePreferredDataTypes and
+// GetPreferredDataTypes. They are stored in the preferences system,
+// and persist; though if a datatype is not registered, it cannot
+// be a preferred datatype.
+//
+// 'Active' (run-time initialization of sync system for a datatype)
+//
+// An active datatype is a preferred datatype that is actively being
+// synchronized: the syncer has been instructed to querying the server
+// for this datatype, first-time merges have finished, and there is an
+// actively installed ChangeProcessor that listens for changes to this
+// datatype, propagating such changes into and out of the sync backend
+// as necessary.
+//
+// When a datatype is in the process of becoming active, it may be
+// in some intermediate state. Those finer-grained intermediate states
+// are differentiated by the DataTypeController state.
+//
+// Sync Configuration:
+//
+// Sync configuration is accomplished via the following APIs:
+// * OnUserChoseDatatypes(): Set the data types the user wants to sync.
+// * SetDecryptionPassphrase(): Attempt to decrypt the user's encrypted data
+// using the passed passphrase.
+// * SetEncryptionPassphrase(): Re-encrypt the user's data using the passed
+// passphrase.
+//
+// Additionally, the current sync configuration can be fetched by calling
+// * GetRegisteredDataTypes()
+// * GetPreferredDataTypes()
+// * GetActiveDataTypes()
+// * IsUsingSecondaryPassphrase()
+// * IsEncryptEverythingEnabled()
+// * IsPassphraseRequired()/IsPassphraseRequiredForDecryption()
+//
+// The "sync everything" state cannot be read from ProfileSyncService, but
+// is instead pulled from SyncPrefs.HasKeepEverythingSynced().
+//
+// Initial sync setup:
+//
+// For privacy reasons, it is usually desirable to avoid syncing any data
+// types until the user has finished setting up sync. There are two APIs
+// that control the initial sync download:
+//
+// * SetFirstSetupComplete()
+// * GetSetupInProgressHandle()
+//
+// SetFirstSetupComplete() should be called once the user has finished setting
+// up sync at least once on their account. GetSetupInProgressHandle() should
+// be called while the user is actively configuring their account. The handle
+// should be deleted once configuration is complete.
+//
+// Once first setup has completed and there are no outstanding
+// setup-in-progress handles, CanConfigureDataTypes() will return true and
+// datatype configuration can begin.
+class ProfileSyncService : public syncer::SyncService,
+ public syncer::SyncFrontend,
+ public syncer::SyncPrefObserver,
+ public syncer::DataTypeManagerObserver,
+ public syncer::UnrecoverableErrorHandler,
+ public KeyedService,
+ public OAuth2TokenService::Consumer,
+ public OAuth2TokenService::Observer,
+ public SigninManagerBase::Observer,
+ public GaiaCookieManagerService::Observer {
+ public:
+ typedef syncer::SyncBackendHost::Status Status;
+ typedef base::Callback<bool(void)> PlatformSyncAllowedProvider;
+
+ enum SyncEventCodes {
+ MIN_SYNC_EVENT_CODE = 0,
+
+ // Events starting the sync service.
+ START_FROM_NTP = 1, // Sync was started from the ad in NTP
+ START_FROM_WRENCH = 2, // Sync was started from the Wrench menu.
+ START_FROM_OPTIONS = 3, // Sync was started from Wrench->Options.
+ START_FROM_BOOKMARK_MANAGER = 4, // Sync was started from Bookmark manager.
+ START_FROM_PROFILE_MENU = 5, // Sync was started from multiprofile menu.
+ START_FROM_URL = 6, // Sync was started from a typed URL.
+
+ // Events regarding cancellation of the signon process of sync.
+ CANCEL_FROM_SIGNON_WITHOUT_AUTH = 10, // Cancelled before submitting
+ // username and password.
+ CANCEL_DURING_SIGNON = 11, // Cancelled after auth.
+ CANCEL_DURING_CONFIGURE = 12, // Cancelled before choosing data
+ // types and clicking OK.
+ // Events resulting in the stoppage of sync service.
+ STOP_FROM_OPTIONS = 20, // Sync was stopped from Wrench->Options.
+ STOP_FROM_ADVANCED_DIALOG = 21, // Sync was stopped via advanced settings.
+
+ // Miscellaneous events caused by sync service.
+
+ MAX_SYNC_EVENT_CODE
+ };
+
+ enum SyncStatusSummary {
+ UNRECOVERABLE_ERROR,
+ NOT_ENABLED,
+ SETUP_INCOMPLETE,
+ DATATYPES_NOT_INITIALIZED,
+ INITIALIZED,
+ UNKNOWN_ERROR,
+ };
+
+ // If AUTO_START, sync will set IsFirstSetupComplete() automatically and sync
+ // will begin syncing without the user needing to confirm sync settings.
+ enum StartBehavior {
+ AUTO_START,
+ MANUAL_START,
+ };
+
+ // Bundles the arguments for ProfileSyncService construction. This is a
+ // movable struct. Because of the non-POD data members, it needs out-of-line
+ // constructors, so in particular the move constructor needs to be
+ // explicitly defined.
+ struct InitParams {
+ InitParams();
+ ~InitParams();
+ InitParams(InitParams&& other); // NOLINT
+
+ std::unique_ptr<syncer::SyncClient> sync_client;
+ std::unique_ptr<SigninManagerWrapper> signin_wrapper;
+ ProfileOAuth2TokenService* oauth2_token_service = nullptr;
+ GaiaCookieManagerService* gaia_cookie_manager_service = nullptr;
+ StartBehavior start_behavior = MANUAL_START;
+ syncer::NetworkTimeUpdateCallback network_time_update_callback;
+ base::FilePath base_directory;
+ scoped_refptr<net::URLRequestContextGetter> url_request_context;
+ std::string debug_identifier;
+ version_info::Channel channel = version_info::Channel::UNKNOWN;
+ scoped_refptr<base::SingleThreadTaskRunner> db_thread;
+ scoped_refptr<base::SingleThreadTaskRunner> file_thread;
+ base::SequencedWorkerPool* blocking_pool = nullptr;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InitParams);
+ };
+
+ explicit ProfileSyncService(InitParams init_params);
+
+ ~ProfileSyncService() override;
+
+ // Initializes the object. This must be called at most once, and
+ // immediately after an object of this class is constructed.
+ void Initialize();
+
+ // syncer::SyncService implementation
+ bool IsFirstSetupComplete() const override;
+ bool IsSyncAllowed() const override;
+ bool IsSyncActive() const override;
+ void TriggerRefresh(const syncer::ModelTypeSet& types) override;
+ void OnDataTypeRequestsSyncStartup(syncer::ModelType type) override;
+ bool CanSyncStart() const override;
+ void RequestStop(SyncStopDataFate data_fate) override;
+ void RequestStart() override;
+ syncer::ModelTypeSet GetActiveDataTypes() const override;
+ syncer::SyncClient* GetSyncClient() const override;
+ syncer::ModelTypeSet GetPreferredDataTypes() const override;
+ void OnUserChoseDatatypes(bool sync_everything,
+ syncer::ModelTypeSet chosen_types) override;
+ void SetFirstSetupComplete() override;
+ bool IsFirstSetupInProgress() const override;
+ std::unique_ptr<syncer::SyncSetupInProgressHandle> GetSetupInProgressHandle()
+ override;
+ bool IsSetupInProgress() const override;
+ bool ConfigurationDone() const override;
+ const GoogleServiceAuthError& GetAuthError() const override;
+ bool HasUnrecoverableError() const override;
+ bool IsBackendInitialized() const override;
+ sync_sessions::OpenTabsUIDelegate* GetOpenTabsUIDelegate() override;
+ bool IsPassphraseRequiredForDecryption() const override;
+ base::Time GetExplicitPassphraseTime() const override;
+ bool IsUsingSecondaryPassphrase() const override;
+ void EnableEncryptEverything() override;
+ bool IsEncryptEverythingEnabled() const override;
+ void SetEncryptionPassphrase(const std::string& passphrase,
+ PassphraseType type) override;
+ bool SetDecryptionPassphrase(const std::string& passphrase) override
+ WARN_UNUSED_RESULT;
+ bool IsCryptographerReady(
+ const syncer::BaseTransaction* trans) const override;
+ syncer::UserShare* GetUserShare() const override;
+ syncer::LocalDeviceInfoProvider* GetLocalDeviceInfoProvider() const override;
+ void AddObserver(syncer::SyncServiceObserver* observer) override;
+ void RemoveObserver(syncer::SyncServiceObserver* observer) override;
+ bool HasObserver(const syncer::SyncServiceObserver* observer) const override;
+ void RegisterDataTypeController(std::unique_ptr<syncer::DataTypeController>
+ data_type_controller) override;
+ void ReenableDatatype(syncer::ModelType type) override;
+ SyncTokenStatus GetSyncTokenStatus() const override;
+ std::string QuerySyncStatusSummaryString() override;
+ bool QueryDetailedSyncStatus(syncer::SyncStatus* result) override;
+ base::string16 GetLastSyncedTimeString() const override;
+ std::string GetBackendInitializationStateString() const override;
+ syncer::SyncCycleSnapshot GetLastCycleSnapshot() const override;
+ base::Value* GetTypeStatusMap() const override;
+ const GURL& sync_service_url() const override;
+ std::string unrecoverable_error_message() const override;
+ tracked_objects::Location unrecoverable_error_location() const override;
+ void AddProtocolEventObserver(
+ syncer::ProtocolEventObserver* observer) override;
+ void RemoveProtocolEventObserver(
+ syncer::ProtocolEventObserver* observer) override;
+ void AddTypeDebugInfoObserver(
+ syncer::TypeDebugInfoObserver* observer) override;
+ void RemoveTypeDebugInfoObserver(
+ syncer::TypeDebugInfoObserver* observer) override;
+ base::WeakPtr<syncer::JsController> GetJsController() override;
+ void GetAllNodes(const base::Callback<void(std::unique_ptr<base::ListValue>)>&
+ callback) override;
+
+ // Add a sync type preference provider. Each provider may only be added once.
+ void AddPreferenceProvider(syncer::SyncTypePreferenceProvider* provider);
+ // Remove a sync type preference provider. May only be called for providers
+ // that have been added. Providers must not remove themselves while being
+ // called back.
+ void RemovePreferenceProvider(syncer::SyncTypePreferenceProvider* provider);
+ // Check whether a given sync type preference provider has been added.
+ bool HasPreferenceProvider(
+ syncer::SyncTypePreferenceProvider* provider) const;
+
+ void RegisterAuthNotifications();
+ void UnregisterAuthNotifications();
+
+ // Returns the SyncableService for syncer::SESSIONS.
+ virtual syncer::SyncableService* GetSessionsSyncableService();
+
+ // Returns the SyncableService for syncer::DEVICE_INFO.
+ virtual syncer::SyncableService* GetDeviceInfoSyncableService();
+
+ // Returns the ModelTypeService for syncer::DEVICE_INFO.
+ virtual syncer::ModelTypeService* GetDeviceInfoService();
+
+ // Returns synced devices tracker.
+ virtual syncer::DeviceInfoTracker* GetDeviceInfoTracker() const;
+
+ // Fills state_map with a map of current data types that are possible to
+ // sync, as well as their states.
+ void GetDataTypeControllerStates(
+ syncer::DataTypeController::StateMap* state_map) const;
+
+ // Called when asynchronous session restore has completed.
+ void OnSessionRestoreComplete();
+
+ // SyncFrontend implementation.
+ void OnBackendInitialized(
+ const syncer::WeakHandle<syncer::JsBackend>& js_backend,
+ const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
+ debug_info_listener,
+ const std::string& cache_guid,
+ bool success) override;
+ void OnSyncCycleCompleted() override;
+ void OnProtocolEvent(const syncer::ProtocolEvent& event) override;
+ void OnDirectoryTypeCommitCounterUpdated(
+ syncer::ModelType type,
+ const syncer::CommitCounters& counters) override;
+ void OnDirectoryTypeUpdateCounterUpdated(
+ syncer::ModelType type,
+ const syncer::UpdateCounters& counters) override;
+ void OnDirectoryTypeStatusCounterUpdated(
+ syncer::ModelType type,
+ const syncer::StatusCounters& counters) override;
+ void OnConnectionStatusChange(syncer::ConnectionStatus status) override;
+ void OnPassphraseRequired(
+ syncer::PassphraseRequiredReason reason,
+ const sync_pb::EncryptedData& pending_keys) override;
+ void OnPassphraseAccepted() override;
+ void OnEncryptedTypesChanged(syncer::ModelTypeSet encrypted_types,
+ bool encrypt_everything) override;
+ void OnEncryptionComplete() override;
+ void OnMigrationNeededForTypes(syncer::ModelTypeSet types) override;
+ void OnExperimentsChanged(const syncer::Experiments& experiments) override;
+ void OnActionableError(const syncer::SyncProtocolError& error) override;
+ void OnLocalSetPassphraseEncryption(
+ const syncer::SyncEncryptionHandler::NigoriState& nigori_state) override;
+
+ // DataTypeManagerObserver implementation.
+ void OnConfigureDone(
+ const syncer::DataTypeManager::ConfigureResult& result) override;
+ void OnConfigureStart() override;
+
+ // DataTypeEncryptionHandler implementation.
+ bool IsPassphraseRequired() const override;
+ syncer::ModelTypeSet GetEncryptedDataTypes() const override;
+
+ // SigninManagerBase::Observer implementation.
+ void GoogleSigninSucceeded(const std::string& account_id,
+ const std::string& username,
+ const std::string& password) override;
+ void GoogleSignedOut(const std::string& account_id,
+ const std::string& username) override;
+
+ // GaiaCookieManagerService::Observer implementation.
+ void OnGaiaAccountsInCookieUpdated(
+ const std::vector<gaia::ListedAccount>& accounts,
+ const std::vector<gaia::ListedAccount>& signed_out_accounts,
+ const GoogleServiceAuthError& error) override;
+
+ // Get the sync status code.
+ SyncStatusSummary QuerySyncStatusSummary();
+
+ // Reconfigures the data type manager with the latest enabled types.
+ // Note: Does not initialize the backend if it is not already initialized.
+ // This function needs to be called only after sync has been initialized
+ // (i.e.,only for reconfigurations). The reason we don't initialize the
+ // backend is because if we had encountered an unrecoverable error we don't
+ // want to startup once more.
+ // This function is called by |SetSetupInProgress|.
+ virtual void ReconfigureDatatypeManager();
+
+ syncer::PassphraseRequiredReason passphrase_required_reason() const {
+ return passphrase_required_reason_;
+ }
+
+ // Returns true if sync is requested to be running by the user.
+ // Note that this does not mean that sync WILL be running; e.g. if
+ // IsSyncAllowed() is false then sync won't start, and if the user
+ // doesn't confirm their settings (IsFirstSetupComplete), sync will
+ // never become active. Use IsSyncActive to see if sync is running.
+ virtual bool IsSyncRequested() const;
+
+ // Record stats on various events.
+ static void SyncEvent(SyncEventCodes code);
+
+ // Returns whether sync is allowed to run based on command-line switches.
+ // Profile::IsSyncAllowed() is probably a better signal than this function.
+ // This function can be called from any thread, and the implementation doesn't
+ // assume it's running on the UI thread.
+ static bool IsSyncAllowedByFlag();
+
+ // Returns whether sync is currently allowed on this platform.
+ bool IsSyncAllowedByPlatform() const;
+
+ // Returns whether sync is managed, i.e. controlled by configuration
+ // management. If so, the user is not allowed to configure sync.
+ virtual bool IsManaged() const;
+
+ // syncer::UnrecoverableErrorHandler implementation.
+ void OnUnrecoverableError(const tracked_objects::Location& from_here,
+ const std::string& message) override;
+
+ // The functions below (until ActivateDataType()) should only be
+ // called if IsBackendInitialized() is true.
+
+ // TODO(akalin): These two functions are used only by
+ // ProfileSyncServiceHarness. Figure out a different way to expose
+ // this info to that class, and remove these functions.
+
+ // Returns whether or not the underlying sync engine has made any
+ // local changes to items that have not yet been synced with the
+ // server.
+ bool HasUnsyncedItems() const;
+
+ // Used by ProfileSyncServiceHarness. May return NULL.
+ syncer::BackendMigrator* GetBackendMigratorForTest();
+
+ // Used by tests to inspect interaction with OAuth2TokenService.
+ bool IsRetryingAccessTokenFetchForTest() const;
+
+ // Used by tests to inspect the OAuth2 access tokens used by PSS.
+ std::string GetAccessTokenForTest() const;
+
+ // TODO(sync): This is only used in tests. Can we remove it?
+ void GetModelSafeRoutingInfo(syncer::ModelSafeRoutingInfo* out) const;
+
+ // SyncPrefObserver implementation.
+ void OnSyncManagedPrefChange(bool is_sync_managed) override;
+
+ // Changes which data types we're going to be syncing to |preferred_types|.
+ // If it is running, the DataTypeManager will be instructed to reconfigure
+ // the sync backend so that exactly these datatypes are actively synced. See
+ // class comment for more on what it means for a datatype to be Preferred.
+ virtual void ChangePreferredDataTypes(syncer::ModelTypeSet preferred_types);
+
+ // Returns the set of types which are enforced programmatically and can not
+ // be disabled by the user.
+ virtual syncer::ModelTypeSet GetForcedDataTypes() const;
+
+ // Gets the set of all data types that could be allowed (the set that
+ // should be advertised to the user). These will typically only change
+ // via a command-line option. See class comment for more on what it means
+ // for a datatype to be Registered.
+ virtual syncer::ModelTypeSet GetRegisteredDataTypes() const;
+
+ // Returns the actual passphrase type being used for encryption.
+ virtual syncer::PassphraseType GetPassphraseType() const;
+
+ // Note about setting passphrases: There are different scenarios under which
+ // we might want to apply a passphrase. It could be for first-time encryption,
+ // re-encryption, or for decryption by clients that sign in at a later time.
+ // In addition, encryption can either be done using a custom passphrase, or by
+ // reusing the GAIA password. Depending on what is happening in the system,
+ // callers should determine which of the two methods below must be used.
+
+ // Returns true if encrypting all the sync data is allowed. If this method
+ // returns false, EnableEncryptEverything() should not be called.
+ virtual bool IsEncryptEverythingAllowed() const;
+
+ // Sets whether encrypting all the sync data is allowed or not.
+ virtual void SetEncryptEverythingAllowed(bool allowed);
+
+ // Returns true if the syncer is waiting for new datatypes to be encrypted.
+ virtual bool encryption_pending() const;
+
+ SigninManagerBase* signin() const;
+
+ syncer::SyncErrorController* sync_error_controller() {
+ return sync_error_controller_.get();
+ }
+
+ // TODO(sync): This is only used in tests. Can we remove it?
+ const syncer::DataTypeStatusTable& data_type_status_table() const;
+
+ syncer::DataTypeManager::ConfigureStatus configure_status() {
+ return configure_status_;
+ }
+
+ // If true, the ProfileSyncService has detected that a new GAIA signin has
+ // succeeded, and is waiting for initialization to complete. This is used by
+ // the UI to differentiate between a new auth error (encountered as part of
+ // the initialization process) and a pre-existing auth error that just hasn't
+ // been cleared yet. Virtual for testing purposes.
+ virtual bool waiting_for_auth() const;
+
+ // The set of currently enabled sync experiments.
+ const syncer::Experiments& current_experiments() const;
+
+ // OAuth2TokenService::Consumer implementation.
+ void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) override;
+ void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) override;
+
+ // OAuth2TokenService::Observer implementation.
+ void OnRefreshTokenAvailable(const std::string& account_id) override;
+ void OnRefreshTokenRevoked(const std::string& account_id) override;
+ void OnRefreshTokensLoaded() override;
+
+ // KeyedService implementation. This must be called exactly
+ // once (before this object is destroyed).
+ void Shutdown() override;
+
+ sync_sessions::FaviconCache* GetFaviconCache();
+
+ // Overrides the NetworkResources used for Sync connections.
+ // This function takes ownership of |network_resources|.
+ void OverrideNetworkResourcesForTest(
+ std::unique_ptr<syncer::NetworkResources> network_resources);
+
+ virtual bool IsDataTypeControllerRunning(syncer::ModelType type) const;
+
+ // This triggers a Directory::SaveChanges() call on the sync thread.
+ // It should be used to persist data to disk when the process might be
+ // killed in the near future.
+ void FlushDirectory() const;
+
+ // Returns a serialized NigoriKey proto generated from the bootstrap token in
+ // SyncPrefs. Will return the empty string if no bootstrap token exists.
+ std::string GetCustomPassphraseKey() const;
+
+ // Set the provider for whether sync is currently allowed by the platform.
+ void SetPlatformSyncAllowedProvider(
+ const PlatformSyncAllowedProvider& platform_sync_allowed_provider);
+
+ // Needed to test whether the directory is deleted properly.
+ base::FilePath GetDirectoryPathForTest() const;
+
+ // Sometimes we need to wait for tasks on the sync thread in tests.
+ base::MessageLoop* GetSyncLoopForTest() const;
+
+ // Triggers sync cycle with request to update specified |types|.
+ void RefreshTypesForTest(syncer::ModelTypeSet types);
+
+ protected:
+ // Helper to install and configure a data type manager.
+ void ConfigureDataTypeManager();
+
+ // Shuts down the backend sync components.
+ // |reason| dictates if syncing is being disabled or not, and whether
+ // to claim ownership of sync thread from backend.
+ void ShutdownImpl(syncer::ShutdownReason reason);
+
+ // Return SyncCredentials from the OAuth2TokenService.
+ syncer::SyncCredentials GetCredentials();
+
+ virtual syncer::WeakHandle<syncer::JsEventHandler> GetJsEventHandler();
+
+ // Helper method for managing encryption UI.
+ bool IsEncryptedDatatypeEnabled() const;
+
+ // Helper for OnUnrecoverableError.
+ // TODO(tim): Use an enum for |delete_sync_database| here, in ShutdownImpl,
+ // and in SyncBackendHost::Shutdown.
+ void OnUnrecoverableErrorImpl(const tracked_objects::Location& from_here,
+ const std::string& message,
+ bool delete_sync_database);
+
+ // This is a cache of the last authentication response we received from the
+ // sync server. The UI queries this to display appropriate messaging to the
+ // user.
+ GoogleServiceAuthError last_auth_error_;
+
+ // Our asynchronous backend to communicate with sync components living on
+ // other threads.
+ std::unique_ptr<syncer::SyncBackendHost> backend_;
+
+ // Was the last SYNC_PASSPHRASE_REQUIRED notification sent because it
+ // was required for encryption, decryption with a cached passphrase, or
+ // because a new passphrase is required?
+ syncer::PassphraseRequiredReason passphrase_required_reason_;
+
+ private:
+ enum UnrecoverableErrorReason {
+ ERROR_REASON_UNSET,
+ ERROR_REASON_SYNCER,
+ ERROR_REASON_BACKEND_INIT_FAILURE,
+ ERROR_REASON_CONFIGURATION_RETRY,
+ ERROR_REASON_CONFIGURATION_FAILURE,
+ ERROR_REASON_ACTIONABLE_ERROR,
+ ERROR_REASON_LIMIT
+ };
+
+ enum AuthErrorMetric {
+ AUTH_ERROR_ENCOUNTERED,
+ AUTH_ERROR_FIXED,
+ AUTH_ERROR_LIMIT
+ };
+
+ // The initial state of sync, for the Sync.InitialState histogram. Even if
+ // this value is CAN_START, sync startup might fail for reasons that we may
+ // want to consider logging in the future, such as a passphrase needed for
+ // decryption, or the version of Chrome being too old. This enum is used to
+ // back a UMA histogram, and should therefore be treated as append-only.
+ enum SyncInitialState {
+ CAN_START, // Sync can attempt to start up.
+ NOT_SIGNED_IN, // There is no signed in user.
+ NOT_REQUESTED, // The user turned off sync.
+ NOT_REQUESTED_NOT_SETUP, // The user turned off sync and setup completed
+ // is false. Might indicate a stop-and-clear.
+ NEEDS_CONFIRMATION, // The user must confirm sync settings.
+ IS_MANAGED, // Sync is disallowed by enterprise policy.
+ NOT_ALLOWED_BY_PLATFORM, // Sync is disallowed by the platform.
+ SYNC_INITIAL_STATE_LIMIT
+ };
+
+ friend class TestProfileSyncService;
+
+ // Stops the sync engine. Does NOT set IsSyncRequested to false. Use
+ // RequestStop for that. |data_fate| controls whether the local sync data is
+ // deleted or kept when the engine shuts down.
+ void StopImpl(SyncStopDataFate data_fate);
+
+ // Update the last auth error and notify observers of error state.
+ void UpdateAuthErrorState(const GoogleServiceAuthError& error);
+
+ // Puts the backend's sync scheduler into NORMAL mode.
+ // Called when configuration is complete.
+ void StartSyncingWithServer();
+
+ // Called when we've determined that we don't need a passphrase (either
+ // because OnPassphraseAccepted() was called, or because we've gotten a
+ // OnPassphraseRequired() but no data types are enabled).
+ void ResolvePassphraseRequired();
+
+ // During initial signin, ProfileSyncService caches the user's signin
+ // passphrase so it can be used to encrypt/decrypt data after sync starts up.
+ // This routine is invoked once the backend has started up to use the
+ // cached passphrase and clear it out when it is done.
+ void ConsumeCachedPassphraseIfPossible();
+
+ // RequestAccessToken initiates RPC to request downscoped access token from
+ // refresh token. This happens when a new OAuth2 login token is loaded and
+ // when sync server returns AUTH_ERROR which indicates it is time to refresh
+ // token.
+ virtual void RequestAccessToken();
+
+ // Return true if backend should start from a fresh sync DB.
+ bool ShouldDeleteSyncFolder();
+
+ // If |delete_sync_data_folder| is true, then this method will delete all
+ // previous "Sync Data" folders. (useful if the folder is partial/corrupt).
+ void InitializeBackend(bool delete_sync_data_folder);
+
+ // Initializes the various settings from the command line.
+ void InitSettings();
+
+ // Sets the last synced time to the current time.
+ void UpdateLastSyncedTime();
+
+ void NotifyObservers();
+ void NotifySyncCycleCompleted();
+ void NotifyForeignSessionUpdated();
+
+ void ClearStaleErrors();
+
+ void ClearUnrecoverableError();
+
+ // Starts up the backend sync components.
+ virtual void StartUpSlowBackendComponents();
+
+ // Collects preferred sync data types from |preference_providers_|.
+ syncer::ModelTypeSet GetDataTypesFromPreferenceProviders() const;
+
+ // Called when the user changes the sync configuration, to update the UMA
+ // stats.
+ void UpdateSelectedTypesHistogram(
+ bool sync_everything,
+ const syncer::ModelTypeSet chosen_types) const;
+
+#if defined(OS_CHROMEOS)
+ // Refresh spare sync bootstrap token for re-enabling the sync service.
+ // Called on successful sign-in notifications.
+ void RefreshSpareBootstrapToken(const std::string& passphrase);
+#endif
+
+ // Internal unrecoverable error handler. Used to track error reason via
+ // Sync.UnrecoverableErrors histogram.
+ void OnInternalUnrecoverableError(const tracked_objects::Location& from_here,
+ const std::string& message,
+ bool delete_sync_database,
+ UnrecoverableErrorReason reason);
+
+ // Update UMA for syncing backend.
+ void UpdateBackendInitUMA(bool success);
+
+ // Various setup following backend initialization, mostly for syncing backend.
+ void PostBackendInitialization();
+
+ // Whether sync has been authenticated with an account ID.
+ bool IsSignedIn() const;
+
+ // The backend can only start if sync can start and has an auth token. This is
+ // different fron CanSyncStart because it represents whether the backend can
+ // be started at this moment, whereas CanSyncStart represents whether sync can
+ // conceptually start without further user action (acquiring a token is an
+ // automatic process).
+ bool CanBackendStart() const;
+
+ // True if a syncing backend exists.
+ bool HasSyncingBackend() const;
+
+ // Update first sync time stored in preferences
+ void UpdateFirstSyncTimePref();
+
+ // Tell the sync server that this client has disabled sync.
+ void RemoveClientFromServer() const;
+
+ // Called when the system is under memory pressure.
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
+
+ // Check if previous shutdown is shutdown cleanly.
+ void ReportPreviousSessionMemoryWarningCount();
+
+ // After user switches to custom passphrase encryption a set of steps needs to
+ // be performed:
+ // - Download all latest updates from server (catch up configure).
+ // - Clear user data on server.
+ // - Clear directory so that data is merged from model types and encrypted.
+ // Following three functions perform these steps.
+
+ // Calls data type manager to start catch up configure.
+ void BeginConfigureCatchUpBeforeClear();
+
+ // Calls sync backend to send ClearServerDataMessage to server.
+ void ClearAndRestartSyncForPassphraseEncryption();
+
+ // Restarts sync clearing directory in the process.
+ void OnClearServerDataDone();
+
+ // True if setup has been completed at least once and is not in progress.
+ bool CanConfigureDataTypes() const;
+
+ // Called when a SetupInProgressHandle issued by this instance is destroyed.
+ virtual void OnSetupInProgressHandleDestroyed();
+
+ // This profile's SyncClient, which abstracts away non-Sync dependencies and
+ // the Sync API component factory.
+ std::unique_ptr<syncer::SyncClient> sync_client_;
+
+ // The class that handles getting, setting, and persisting sync
+ // preferences.
+ syncer::SyncPrefs sync_prefs_;
+
+ // TODO(ncarter): Put this in a profile, once there is UI for it.
+ // This specifies where to find the sync server.
+ const GURL sync_service_url_;
+
+ // The time that OnConfigureStart is called. This member is zero if
+ // OnConfigureStart has not yet been called, and is reset to zero once
+ // OnConfigureDone is called.
+ base::Time sync_configure_start_time_;
+
+ // Callback to update the network time; used for initializing the backend.
+ syncer::NetworkTimeUpdateCallback network_time_update_callback_;
+
+ // The path to the base directory under which sync should store its
+ // information.
+ base::FilePath base_directory_;
+
+ // The request context in which sync should operate.
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_;
+
+ // An identifier representing this instance for debugging purposes.
+ std::string debug_identifier_;
+
+ // The product channel of the embedder.
+ version_info::Channel channel_;
+
+ // Threading context.
+ scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> file_thread_;
+ base::SequencedWorkerPool* blocking_pool_;
+
+ // Indicates if this is the first time sync is being configured. This value
+ // is equal to !IsFirstSetupComplete() at the time of OnBackendInitialized().
+ bool is_first_time_sync_configure_;
+
+ // Number of UIs currently configuring the Sync service. When this number
+ // is decremented back to zero, Sync setup is marked no longer in progress.
+ int outstanding_setup_in_progress_handles_ = 0;
+
+ // List of available data type controllers.
+ syncer::DataTypeController::TypeMap data_type_controllers_;
+
+ // Whether the SyncBackendHost has been initialized.
+ bool backend_initialized_;
+
+ // Set when sync receives DISABLED_BY_ADMIN error from server. Prevents
+ // ProfileSyncService from starting backend till browser restarted or user
+ // signed out.
+ bool sync_disabled_by_admin_;
+
+ // Set to true if a signin has completed but we're still waiting for the
+ // backend to refresh its credentials.
+ bool is_auth_in_progress_;
+
+ // Encapsulates user signin - used to set/get the user's authenticated
+ // email address.
+ const std::unique_ptr<SigninManagerWrapper> signin_;
+
+ // Information describing an unrecoverable error.
+ UnrecoverableErrorReason unrecoverable_error_reason_;
+ std::string unrecoverable_error_message_;
+ tracked_objects::Location unrecoverable_error_location_;
+
+ // Manages the start and stop of the data types.
+ std::unique_ptr<syncer::DataTypeManager> data_type_manager_;
+
+ base::ObserverList<syncer::SyncServiceObserver> observers_;
+ base::ObserverList<syncer::ProtocolEventObserver> protocol_event_observers_;
+ base::ObserverList<syncer::TypeDebugInfoObserver> type_debug_info_observers_;
+
+ std::set<syncer::SyncTypePreferenceProvider*> preference_providers_;
+
+ syncer::SyncJsController sync_js_controller_;
+
+ // This allows us to gracefully handle an ABORTED return code from the
+ // DataTypeManager in the event that the server informed us to cease and
+ // desist syncing immediately.
+ bool expect_sync_configuration_aborted_;
+
+ // Sometimes we need to temporarily hold on to a passphrase because we don't
+ // yet have a backend to send it to. This happens during initialization as
+ // we don't StartUp until we have a valid token, which happens after valid
+ // credentials were provided.
+ std::string cached_passphrase_;
+
+ // The current set of encrypted types. Always a superset of
+ // syncer::Cryptographer::SensitiveTypes().
+ syncer::ModelTypeSet encrypted_types_;
+
+ // Whether encrypting everything is allowed.
+ bool encrypt_everything_allowed_;
+
+ // Whether we want to encrypt everything.
+ bool encrypt_everything_;
+
+ // Whether we're waiting for an attempt to encryption all sync data to
+ // complete. We track this at this layer in order to allow the user to cancel
+ // if they e.g. don't remember their explicit passphrase.
+ bool encryption_pending_;
+
+ std::unique_ptr<syncer::BackendMigrator> migrator_;
+
+ // This is the last |SyncProtocolError| we received from the server that had
+ // an action set on it.
+ syncer::SyncProtocolError last_actionable_error_;
+
+ // Exposes sync errors to the UI.
+ std::unique_ptr<syncer::SyncErrorController> sync_error_controller_;
+
+ // Tracks the set of failed data types (those that encounter an error
+ // or must delay loading for some reason).
+ syncer::DataTypeStatusTable data_type_status_table_;
+
+ syncer::DataTypeManager::ConfigureStatus configure_status_;
+
+ // The set of currently enabled sync experiments.
+ syncer::Experiments current_experiments_;
+
+ // Sync's internal debug info listener. Used to record datatype configuration
+ // and association information.
+ syncer::WeakHandle<syncer::DataTypeDebugInfoListener> debug_info_listener_;
+
+ // A thread where all the sync operations happen.
+ // OWNERSHIP Notes:
+ // * Created when backend starts for the first time.
+ // * If sync is disabled, PSS claims ownership from backend.
+ // * If sync is reenabled, PSS passes ownership to new backend.
+ std::unique_ptr<base::Thread> sync_thread_;
+
+ // ProfileSyncService uses this service to get access tokens.
+ ProfileOAuth2TokenService* const oauth2_token_service_;
+
+ // ProfileSyncService needs to remember access token in order to invalidate it
+ // with OAuth2TokenService.
+ std::string access_token_;
+
+ // ProfileSyncService needs to hold reference to access_token_request_ for
+ // the duration of request in order to receive callbacks.
+ std::unique_ptr<OAuth2TokenService::Request> access_token_request_;
+
+ // If RequestAccessToken fails with transient error then retry requesting
+ // access token with exponential backoff.
+ base::OneShotTimer request_access_token_retry_timer_;
+ net::BackoffEntry request_access_token_backoff_;
+
+ // States related to sync token and connection.
+ base::Time connection_status_update_time_;
+ syncer::ConnectionStatus connection_status_;
+ base::Time token_request_time_;
+ base::Time token_receive_time_;
+ GoogleServiceAuthError last_get_token_error_;
+ base::Time next_token_request_time_;
+
+ // The gaia cookie manager. Used for monitoring cookie jar changes to detect
+ // when the user signs out of the content area.
+ GaiaCookieManagerService* const gaia_cookie_manager_service_;
+
+ std::unique_ptr<syncer::LocalDeviceInfoProvider> local_device_;
+
+ // Locally owned SyncableService and ModelTypeService implementations.
+ std::unique_ptr<sync_sessions::SessionsSyncManager> sessions_sync_manager_;
+ std::unique_ptr<syncer::DeviceInfoSyncService> device_info_sync_service_;
+ std::unique_ptr<syncer::DeviceInfoService> device_info_service_;
+
+ std::unique_ptr<syncer::NetworkResources> network_resources_;
+
+ StartBehavior start_behavior_;
+ std::unique_ptr<syncer::StartupController> startup_controller_;
+
+ // The full path to the sync data directory.
+ base::FilePath directory_path_;
+
+ std::unique_ptr<syncer::SyncStoppedReporter> sync_stopped_reporter_;
+
+ // Listens for the system being under memory pressure.
+ std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
+ // Nigori state after user switching to custom passphrase, saved until
+ // transition steps complete. It will be injected into new backend after sync
+ // restart.
+ std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState>
+ saved_nigori_state_;
+
+ // When BeginConfigureCatchUpBeforeClear is called it will set
+ // catch_up_configure_in_progress_ to true. This is needed to detect that call
+ // to OnConfigureDone originated from BeginConfigureCatchUpBeforeClear and
+ // needs to be followed by ClearAndRestartSyncForPassphraseEncryption().
+ bool catch_up_configure_in_progress_;
+
+ // Whether the major version has changed since the last time Chrome ran,
+ // and therefore a passphrase required state should result in prompting
+ // the user. This logic is only enabled on platforms that consume the
+ // IsPassphrasePrompted sync preference.
+ bool passphrase_prompt_triggered_by_version_;
+
+ // An object that lets us check whether sync is currently allowed on this
+ // platform.
+ PlatformSyncAllowedProvider platform_sync_allowed_provider_;
+
+ // Used to ensure that certain operations are performed on the thread that
+ // this object was created on.
+ base::ThreadChecker thread_checker_;
+
+ // This weak factory invalidates its issued pointers when Sync is disabled.
+ base::WeakPtrFactory<ProfileSyncService> sync_enabled_weak_factory_;
+
+ base::WeakPtrFactory<ProfileSyncService> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileSyncService);
+};
+
+bool ShouldShowActionOnUI(const syncer::SyncProtocolError& error);
+
+} // namespace browser_sync
+
+#endif // COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_
diff --git a/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc b/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc
new file mode 100644
index 00000000000..3b322cc2681
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc
@@ -0,0 +1,1474 @@
+// Copyright 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 <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/country_names.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
+#include "components/autofill/core/browser/webdata/autofill_change.h"
+#include "components/autofill/core/browser/webdata/autofill_data_type_controller.h"
+#include "components/autofill/core/browser/webdata/autofill_entry.h"
+#include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
+#include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/common/autofill_pref_names.h"
+#include "components/browser_sync/abstract_profile_sync_service_test.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/browser_sync/test_profile_sync_service.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/core/data_type_debug_info_listener.h"
+#include "components/sync/core/read_node.h"
+#include "components/sync/core/read_transaction.h"
+#include "components/sync/core/write_node.h"
+#include "components/sync/core/write_transaction.h"
+#include "components/sync/driver/data_type_controller.h"
+#include "components/sync/driver/data_type_manager_impl.h"
+#include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/syncable/mutable_entry.h"
+#include "components/sync/syncable/syncable_write_transaction.h"
+#include "components/syncable_prefs/pref_service_syncable.h"
+#include "components/version_info/version_info.h"
+#include "components/webdata/common/web_database.h"
+#include "components/webdata_services/web_data_service_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using autofill::AutocompleteSyncableService;
+using autofill::AutofillChange;
+using autofill::AutofillChangeList;
+using autofill::AutofillEntry;
+using autofill::AutofillKey;
+using autofill::AutofillProfile;
+using autofill::AutofillProfileChange;
+using autofill::AutofillProfileSyncableService;
+using autofill::AutofillTable;
+using autofill::AutofillWebDataService;
+using autofill::NAME_FULL;
+using autofill::PersonalDataManager;
+using autofill::ServerFieldType;
+using base::ASCIIToUTF16;
+using base::Time;
+using base::TimeDelta;
+using base::WaitableEvent;
+using syncer::AUTOFILL;
+using syncer::AUTOFILL_PROFILE;
+using syncer::BaseNode;
+using syncer::syncable::CREATE;
+using syncer::syncable::GET_TYPE_ROOT;
+using syncer::syncable::MutableEntry;
+using syncer::syncable::UNITTEST;
+using syncer::syncable::WriterTag;
+using syncer::syncable::WriteTransaction;
+using testing::_;
+using testing::DoAll;
+using testing::ElementsAre;
+using testing::Not;
+using testing::SetArgumentPointee;
+using testing::Return;
+
+namespace browser_sync {
+
+namespace {
+
+void RegisterAutofillPrefs(user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterBooleanPref(autofill::prefs::kAutofillEnabled, true);
+ registry->RegisterBooleanPref(autofill::prefs::kAutofillWalletImportEnabled,
+ true);
+ registry->RegisterBooleanPref(autofill::prefs::kAutofillProfileUseDatesFixed,
+ true);
+ registry->RegisterIntegerPref(autofill::prefs::kAutofillLastVersionDeduped,
+ atoi(version_info::GetVersionNumber().c_str()));
+}
+
+void RunAndSignal(const base::Closure& cb, WaitableEvent* event) {
+ cb.Run();
+ event->Signal();
+}
+
+AutofillEntry MakeAutofillEntry(const char* name,
+ const char* value,
+ int time_shift0,
+ int time_shift1) {
+ // Time deep in the past would cause Autocomplete sync to discard the
+ // entries.
+ static Time base_time = Time::Now().LocalMidnight();
+
+ Time date_created = base_time + TimeDelta::FromSeconds(time_shift0);
+ Time date_last_used = date_created;
+ if (time_shift1 >= 0)
+ date_last_used = base_time + TimeDelta::FromSeconds(time_shift1);
+ return AutofillEntry(AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)),
+ date_created, date_last_used);
+}
+
+AutofillEntry MakeAutofillEntry(const char* name,
+ const char* value,
+ int time_shift) {
+ return MakeAutofillEntry(name, value, time_shift, -1);
+}
+
+} // namespace
+
+class AutofillTableMock : public AutofillTable {
+ public:
+ AutofillTableMock() {}
+ MOCK_METHOD2(RemoveFormElement,
+ bool(const base::string16& name,
+ const base::string16& value)); // NOLINT
+ MOCK_METHOD1(GetAllAutofillEntries,
+ bool(std::vector<AutofillEntry>* entries)); // NOLINT
+ MOCK_METHOD4(GetAutofillTimestamps,
+ bool(const base::string16& name, // NOLINT
+ const base::string16& value,
+ Time* date_created,
+ Time* date_last_used));
+ MOCK_METHOD1(UpdateAutofillEntries,
+ bool(const std::vector<AutofillEntry>&)); // NOLINT
+ MOCK_METHOD1(GetAutofillProfiles,
+ bool(std::vector<AutofillProfile*>*)); // NOLINT
+ MOCK_METHOD1(UpdateAutofillProfile, bool(const AutofillProfile&)); // NOLINT
+ MOCK_METHOD1(AddAutofillProfile, bool(const AutofillProfile&)); // NOLINT
+ MOCK_METHOD1(RemoveAutofillProfile, bool(const std::string&)); // NOLINT
+};
+
+MATCHER_P(MatchProfiles, profile, "") {
+ return (profile.Compare(arg) == 0);
+}
+
+class WebDatabaseFake : public WebDatabase {
+ public:
+ explicit WebDatabaseFake(AutofillTable* autofill_table) {
+ AddTable(autofill_table);
+ }
+};
+
+class MockAutofillBackend : public autofill::AutofillWebDataBackend {
+ public:
+ MockAutofillBackend(
+ WebDatabase* web_database,
+ const base::Closure& on_changed,
+ const base::Callback<void(syncer::ModelType)>& on_sync_started,
+ const scoped_refptr<base::SequencedTaskRunner>& ui_thread)
+ : web_database_(web_database),
+ on_changed_(on_changed),
+ on_sync_started_(on_sync_started),
+ ui_thread_(ui_thread) {}
+
+ ~MockAutofillBackend() override {}
+ WebDatabase* GetDatabase() override { return web_database_; }
+ void AddObserver(
+ autofill::AutofillWebDataServiceObserverOnDBThread* observer) override {}
+ void RemoveObserver(
+ autofill::AutofillWebDataServiceObserverOnDBThread* observer) override {}
+ void RemoveExpiredFormElements() override {}
+ void NotifyOfMultipleAutofillChanges() override {
+ DCHECK(!ui_thread_->RunsTasksOnCurrentThread());
+ ui_thread_->PostTask(FROM_HERE, on_changed_);
+ }
+ void NotifyThatSyncHasStarted(syncer::ModelType model_type) override {
+ DCHECK(!ui_thread_->RunsTasksOnCurrentThread());
+ ui_thread_->PostTask(FROM_HERE, base::Bind(on_sync_started_, model_type));
+ }
+
+ private:
+ WebDatabase* web_database_;
+ base::Closure on_changed_;
+ base::Callback<void(syncer::ModelType)> on_sync_started_;
+ const scoped_refptr<base::SequencedTaskRunner> ui_thread_;
+};
+
+class ProfileSyncServiceAutofillTest;
+
+template <class AutofillProfile>
+syncer::ModelType GetModelType() {
+ return syncer::UNSPECIFIED;
+}
+
+template <>
+syncer::ModelType GetModelType<AutofillEntry>() {
+ return AUTOFILL;
+}
+
+template <>
+syncer::ModelType GetModelType<AutofillProfile>() {
+ return AUTOFILL_PROFILE;
+}
+
+class TokenWebDataServiceFake : public TokenWebData {
+ public:
+ TokenWebDataServiceFake(
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread)
+ : TokenWebData(ui_thread, db_thread) {}
+
+ bool IsDatabaseLoaded() override { return true; }
+
+ AutofillWebDataService::Handle GetAllTokens(
+ WebDataServiceConsumer* consumer) override {
+ // TODO(tim): It would be nice if WebDataService was injected on
+ // construction of ProfileOAuth2TokenService rather than fetched by
+ // Initialize so that this isn't necessary (we could pass a NULL service).
+ // We currently do return it via EXPECT_CALLs, but without depending on
+ // order-of-initialization (which seems way more fragile) we can't tell
+ // which component is asking at what time, and some components in these
+ // Autofill tests require a WebDataService.
+ return 0;
+ }
+
+ private:
+ ~TokenWebDataServiceFake() override {}
+
+ DISALLOW_COPY_AND_ASSIGN(TokenWebDataServiceFake);
+};
+
+class WebDataServiceFake : public AutofillWebDataService {
+ public:
+ WebDataServiceFake(
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread)
+ : AutofillWebDataService(ui_thread, db_thread),
+ web_database_(NULL),
+ autocomplete_syncable_service_(NULL),
+ autofill_profile_syncable_service_(NULL),
+ syncable_service_created_or_destroyed_(
+ base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED),
+ db_thread_(db_thread),
+ ui_thread_(ui_thread) {}
+
+ void SetDatabase(WebDatabase* web_database) { web_database_ = web_database; }
+
+ void StartSyncableService() {
+ // The |autofill_profile_syncable_service_| must be constructed on the DB
+ // thread.
+ const base::Closure& on_changed_callback =
+ base::Bind(&WebDataServiceFake::NotifyAutofillMultipleChangedOnUIThread,
+ AsWeakPtr());
+ const base::Callback<void(syncer::ModelType)> on_sync_started_callback =
+ base::Bind(&WebDataServiceFake::NotifySyncStartedOnUIThread,
+ AsWeakPtr());
+
+ db_thread_->PostTask(FROM_HERE,
+ base::Bind(&WebDataServiceFake::CreateSyncableService,
+ base::Unretained(this), on_changed_callback,
+ on_sync_started_callback));
+ syncable_service_created_or_destroyed_.Wait();
+ }
+
+ void ShutdownSyncableService() {
+ // The |autofill_profile_syncable_service_| must be destructed on the DB
+ // thread.
+ db_thread_->PostTask(FROM_HERE,
+ base::Bind(&WebDataServiceFake::DestroySyncableService,
+ base::Unretained(this)));
+ syncable_service_created_or_destroyed_.Wait();
+ }
+
+ bool IsDatabaseLoaded() override { return true; }
+
+ WebDatabase* GetDatabase() override { return web_database_; }
+
+ void OnAutofillEntriesChanged(const AutofillChangeList& changes) {
+ WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+
+ base::Closure notify_cb =
+ base::Bind(&AutocompleteSyncableService::AutofillEntriesChanged,
+ base::Unretained(autocomplete_syncable_service_), changes);
+ db_thread_->PostTask(FROM_HERE,
+ base::Bind(&RunAndSignal, notify_cb, &event));
+ event.Wait();
+ }
+
+ void OnAutofillProfileChanged(const AutofillProfileChange& changes) {
+ WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+
+ base::Closure notify_cb = base::Bind(
+ &AutocompleteSyncableService::AutofillProfileChanged,
+ base::Unretained(autofill_profile_syncable_service_), changes);
+ db_thread_->PostTask(FROM_HERE,
+ base::Bind(&RunAndSignal, notify_cb, &event));
+ event.Wait();
+ }
+
+ private:
+ ~WebDataServiceFake() override {}
+
+ void CreateSyncableService(
+ const base::Closure& on_changed_callback,
+ const base::Callback<void(syncer::ModelType)>& on_sync_started) {
+ ASSERT_TRUE(db_thread_->RunsTasksOnCurrentThread());
+ // These services are deleted in DestroySyncableService().
+ backend_.reset(new MockAutofillBackend(GetDatabase(), on_changed_callback,
+ on_sync_started, ui_thread_.get()));
+ AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
+ this, backend_.get());
+ AutofillProfileSyncableService::CreateForWebDataServiceAndBackend(
+ this, backend_.get(), "en-US");
+
+ autocomplete_syncable_service_ =
+ AutocompleteSyncableService::FromWebDataService(this);
+ autofill_profile_syncable_service_ =
+ AutofillProfileSyncableService::FromWebDataService(this);
+
+ syncable_service_created_or_destroyed_.Signal();
+ }
+
+ void DestroySyncableService() {
+ ASSERT_TRUE(db_thread_->RunsTasksOnCurrentThread());
+ autocomplete_syncable_service_ = NULL;
+ autofill_profile_syncable_service_ = NULL;
+ backend_.reset();
+ syncable_service_created_or_destroyed_.Signal();
+ }
+
+ WebDatabase* web_database_;
+ AutocompleteSyncableService* autocomplete_syncable_service_;
+ AutofillProfileSyncableService* autofill_profile_syncable_service_;
+ std::unique_ptr<autofill::AutofillWebDataBackend> backend_;
+
+ WaitableEvent syncable_service_created_or_destroyed_;
+
+ const scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+ const scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebDataServiceFake);
+};
+
+ACTION_P(ReturnNewDataTypeManagerWithDebugListener, debug_listener) {
+ return new syncer::DataTypeManagerImpl(debug_listener, arg1, arg2, arg3,
+ arg4);
+}
+
+class MockPersonalDataManager : public PersonalDataManager {
+ public:
+ MockPersonalDataManager() : PersonalDataManager("en-US") {}
+ MOCK_CONST_METHOD0(IsDataLoaded, bool());
+ MOCK_METHOD0(LoadProfiles, void());
+ MOCK_METHOD0(LoadCreditCards, void());
+ MOCK_METHOD0(Refresh, void());
+};
+
+template <class T>
+class AddAutofillHelper;
+
+class ProfileSyncServiceAutofillTest
+ : public AbstractProfileSyncServiceTest,
+ public syncer::DataTypeDebugInfoListener {
+ public:
+ // DataTypeDebugInfoListener implementation.
+ void OnDataTypeConfigureComplete(
+ const std::vector<syncer::DataTypeConfigurationStats>&
+ configuration_stats) override {
+ ASSERT_EQ(1u, configuration_stats.size());
+ association_stats_ = configuration_stats[0].association_stats;
+ }
+
+ protected:
+ ProfileSyncServiceAutofillTest() : debug_ptr_factory_(this) {
+ autofill::CountryNames::SetLocaleString("en-US");
+ RegisterAutofillPrefs(
+ profile_sync_service_bundle()->pref_service()->registry());
+
+ data_type_thread()->Start();
+ profile_sync_service_bundle()->set_db_thread(
+ data_type_thread()->task_runner());
+
+ web_database_.reset(new WebDatabaseFake(&autofill_table_));
+ web_data_wrapper_ = base::MakeUnique<MockWebDataServiceWrapper>(
+ new WebDataServiceFake(base::ThreadTaskRunnerHandle::Get(),
+ data_type_thread()->task_runner()),
+ new TokenWebDataServiceFake(base::ThreadTaskRunnerHandle::Get(),
+ data_type_thread()->task_runner()));
+ web_data_service_ = static_cast<WebDataServiceFake*>(
+ web_data_wrapper_->GetAutofillWebData().get());
+ web_data_service_->SetDatabase(web_database_.get());
+
+ personal_data_manager_ = base::MakeUnique<MockPersonalDataManager>();
+
+ EXPECT_CALL(personal_data_manager(), LoadProfiles());
+ EXPECT_CALL(personal_data_manager(), LoadCreditCards());
+
+ personal_data_manager_->Init(
+ web_data_service_, profile_sync_service_bundle()->pref_service(),
+ profile_sync_service_bundle()->account_tracker(),
+ profile_sync_service_bundle()->signin_manager(), false);
+
+ web_data_service_->StartSyncableService();
+
+ ProfileSyncServiceBundle::SyncClientBuilder builder(
+ profile_sync_service_bundle());
+ builder.SetPersonalDataManager(personal_data_manager_.get());
+ builder.SetSyncServiceCallback(GetSyncServiceCallback());
+ builder.SetSyncableServiceCallback(
+ base::Bind(&ProfileSyncServiceAutofillTest::GetSyncableServiceForType,
+ base::Unretained(this)));
+ builder.set_activate_model_creation();
+ sync_client_owned_ = builder.Build();
+ sync_client_ = sync_client_owned_.get();
+
+ // When UpdateAutofillEntries() is called with an empty list, the return
+ // value should be |true|, rather than the default of |false|.
+ std::vector<AutofillEntry> empty;
+ EXPECT_CALL(autofill_table_, UpdateAutofillEntries(empty))
+ .WillRepeatedly(Return(true));
+ }
+
+ ~ProfileSyncServiceAutofillTest() override {
+ web_data_service_->ShutdownOnUIThread();
+ web_data_service_->ShutdownSyncableService();
+ web_data_wrapper_->Shutdown();
+ web_data_service_ = nullptr;
+ web_data_wrapper_.reset();
+ web_database_.reset();
+ // Shut down the service explicitly before some data members from this
+ // test it needs will be deleted.
+ sync_service()->Shutdown();
+ }
+
+ int GetSyncCount(syncer::ModelType type) {
+ syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
+ syncer::ReadNode node(&trans);
+ if (node.InitTypeRoot(type) != BaseNode::INIT_OK)
+ return 0;
+ return node.GetTotalNodeCount() - 1;
+ }
+
+ void StartSyncService(const base::Closure& callback,
+ bool will_fail_association,
+ syncer::ModelType type) {
+ SigninManagerBase* signin = profile_sync_service_bundle()->signin_manager();
+ signin->SetAuthenticatedAccountInfo("12345", "test_user@gmail.com");
+ CreateSyncService(std::move(sync_client_owned_), callback);
+
+ EXPECT_CALL(*profile_sync_service_bundle()->component_factory(),
+ CreateDataTypeManager(_, _, _, _, _))
+ .WillOnce(ReturnNewDataTypeManagerWithDebugListener(
+ syncer::MakeWeakHandle(debug_ptr_factory_.GetWeakPtr())));
+
+ EXPECT_CALL(personal_data_manager(), IsDataLoaded())
+ .WillRepeatedly(Return(true));
+
+ // We need tokens to get the tests going
+ profile_sync_service_bundle()->auth_service()->UpdateCredentials(
+ signin->GetAuthenticatedAccountId(), "oauth2_login_token");
+
+ sync_service()->RegisterDataTypeController(CreateDataTypeController(type));
+ sync_service()->Initialize();
+ base::RunLoop().Run();
+
+ // It's possible this test triggered an unrecoverable error, in which case
+ // we can't get the sync count.
+ if (sync_service()->IsSyncActive()) {
+ EXPECT_EQ(GetSyncCount(type),
+ association_stats_.num_sync_items_after_association);
+ }
+ EXPECT_EQ(association_stats_.num_sync_items_after_association,
+ association_stats_.num_sync_items_before_association +
+ association_stats_.num_sync_items_added -
+ association_stats_.num_sync_items_deleted);
+ }
+
+ bool AddAutofillSyncNode(const AutofillEntry& entry) {
+ syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare());
+ syncer::WriteNode node(&trans);
+ std::string tag = AutocompleteSyncableService::KeyToTag(
+ base::UTF16ToUTF8(entry.key().name()),
+ base::UTF16ToUTF8(entry.key().value()));
+ syncer::WriteNode::InitUniqueByCreationResult result =
+ node.InitUniqueByCreation(AUTOFILL, tag);
+ if (result != syncer::WriteNode::INIT_SUCCESS)
+ return false;
+
+ sync_pb::EntitySpecifics specifics;
+ AutocompleteSyncableService::WriteAutofillEntry(entry, &specifics);
+ node.SetEntitySpecifics(specifics);
+ return true;
+ }
+
+ bool AddAutofillSyncNode(const AutofillProfile& profile) {
+ syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare());
+ syncer::WriteNode node(&trans);
+ std::string tag = profile.guid();
+ syncer::WriteNode::InitUniqueByCreationResult result =
+ node.InitUniqueByCreation(AUTOFILL_PROFILE, tag);
+ if (result != syncer::WriteNode::INIT_SUCCESS)
+ return false;
+
+ sync_pb::EntitySpecifics specifics;
+ AutofillProfileSyncableService::WriteAutofillProfile(profile, &specifics);
+ node.SetEntitySpecifics(specifics);
+ return true;
+ }
+
+ bool GetAutofillEntriesFromSyncDB(std::vector<AutofillEntry>* entries,
+ std::vector<AutofillProfile>* profiles) {
+ syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
+ syncer::ReadNode autofill_root(&trans);
+ if (autofill_root.InitTypeRoot(AUTOFILL) != BaseNode::INIT_OK) {
+ return false;
+ }
+
+ int64_t child_id = autofill_root.GetFirstChildId();
+ while (child_id != syncer::kInvalidId) {
+ syncer::ReadNode child_node(&trans);
+ if (child_node.InitByIdLookup(child_id) != BaseNode::INIT_OK)
+ return false;
+
+ const sync_pb::AutofillSpecifics& autofill(
+ child_node.GetEntitySpecifics().autofill());
+ if (autofill.has_value()) {
+ AutofillKey key(base::UTF8ToUTF16(autofill.name()),
+ base::UTF8ToUTF16(autofill.value()));
+ std::vector<Time> timestamps;
+ int timestamps_count = autofill.usage_timestamp_size();
+ for (int i = 0; i < timestamps_count; ++i) {
+ timestamps.push_back(
+ Time::FromInternalValue(autofill.usage_timestamp(i)));
+ }
+ entries->push_back(
+ AutofillEntry(key, timestamps.front(), timestamps.back()));
+ } else if (autofill.has_profile()) {
+ AutofillProfile p;
+ p.set_guid(autofill.profile().guid());
+ AutofillProfileSyncableService::OverwriteProfileWithServerData(
+ autofill.profile(), &p);
+ profiles->push_back(p);
+ }
+ child_id = child_node.GetSuccessorId();
+ }
+ return true;
+ }
+
+ bool GetAutofillProfilesFromSyncDBUnderProfileNode(
+ std::vector<AutofillProfile>* profiles) {
+ syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
+ syncer::ReadNode autofill_root(&trans);
+ if (autofill_root.InitTypeRoot(AUTOFILL_PROFILE) != BaseNode::INIT_OK) {
+ return false;
+ }
+
+ int64_t child_id = autofill_root.GetFirstChildId();
+ while (child_id != syncer::kInvalidId) {
+ syncer::ReadNode child_node(&trans);
+ if (child_node.InitByIdLookup(child_id) != BaseNode::INIT_OK)
+ return false;
+
+ const sync_pb::AutofillProfileSpecifics& autofill(
+ child_node.GetEntitySpecifics().autofill_profile());
+ AutofillProfile p;
+ p.set_guid(autofill.guid());
+ AutofillProfileSyncableService::OverwriteProfileWithServerData(autofill,
+ &p);
+ profiles->push_back(p);
+ child_id = child_node.GetSuccessorId();
+ }
+ return true;
+ }
+
+ void SetIdleChangeProcessorExpectations() {
+ EXPECT_CALL(autofill_table_, RemoveFormElement(_, _)).Times(0);
+ EXPECT_CALL(autofill_table_, GetAutofillTimestamps(_, _, _, _)).Times(0);
+
+ // Only permit UpdateAutofillEntries() to be called with an empty list.
+ std::vector<AutofillEntry> empty;
+ EXPECT_CALL(autofill_table_, UpdateAutofillEntries(Not(empty))).Times(0);
+ }
+
+ std::unique_ptr<syncer::DataTypeController> CreateDataTypeController(
+ syncer::ModelType type) {
+ DCHECK(type == AUTOFILL || type == AUTOFILL_PROFILE);
+ if (type == AUTOFILL) {
+ return base::MakeUnique<AutofillDataTypeController>(
+ data_type_thread()->task_runner(), base::Bind(&base::DoNothing),
+ sync_client_, web_data_service_);
+ } else {
+ return base::MakeUnique<AutofillProfileDataTypeController>(
+ data_type_thread()->task_runner(), base::Bind(&base::DoNothing),
+ sync_client_, web_data_service_);
+ }
+ }
+
+ AutofillTableMock& autofill_table() { return autofill_table_; }
+
+ MockPersonalDataManager& personal_data_manager() {
+ return *personal_data_manager_;
+ }
+
+ WebDataServiceFake* web_data_service() { return web_data_service_.get(); }
+
+ private:
+ friend class AddAutofillHelper<AutofillEntry>;
+ friend class AddAutofillHelper<AutofillProfile>;
+
+ base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
+ syncer::ModelType type) {
+ DCHECK(type == AUTOFILL || type == AUTOFILL_PROFILE);
+ if (type == AUTOFILL) {
+ return AutocompleteSyncableService::FromWebDataService(
+ web_data_service_.get())
+ ->AsWeakPtr();
+ } else {
+ return AutofillProfileSyncableService::FromWebDataService(
+ web_data_service_.get())
+ ->AsWeakPtr();
+ }
+ }
+
+ AutofillTableMock autofill_table_;
+ std::unique_ptr<WebDatabaseFake> web_database_;
+ std::unique_ptr<MockWebDataServiceWrapper> web_data_wrapper_;
+ scoped_refptr<WebDataServiceFake> web_data_service_;
+ std::unique_ptr<MockPersonalDataManager> personal_data_manager_;
+ syncer::DataTypeAssociationStats association_stats_;
+ base::WeakPtrFactory<DataTypeDebugInfoListener> debug_ptr_factory_;
+ // |sync_client_owned_| keeps the created client until it is passed to the
+ // created ProfileSyncService. |sync_client_| just keeps a weak reference to
+ // the client the whole time.
+ std::unique_ptr<syncer::FakeSyncClient> sync_client_owned_;
+ syncer::FakeSyncClient* sync_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceAutofillTest);
+};
+
+template <class T>
+class AddAutofillHelper {
+ public:
+ AddAutofillHelper(ProfileSyncServiceAutofillTest* test,
+ const std::vector<T>& entries)
+ : callback_(base::Bind(&AddAutofillHelper::AddAutofillCallback,
+ base::Unretained(this),
+ test,
+ entries)),
+ success_(false) {}
+
+ const base::Closure& callback() const { return callback_; }
+ bool success() { return success_; }
+
+ private:
+ void AddAutofillCallback(ProfileSyncServiceAutofillTest* test,
+ const std::vector<T>& entries) {
+ if (!test->CreateRoot(GetModelType<T>()))
+ return;
+
+ for (size_t i = 0; i < entries.size(); ++i) {
+ if (!test->AddAutofillSyncNode(entries[i]))
+ return;
+ }
+ success_ = true;
+ }
+
+ base::Closure callback_;
+ bool success_;
+};
+
+// Overload write transaction to use custom NotifyTransactionComplete
+class WriteTransactionTest : public WriteTransaction {
+ public:
+ WriteTransactionTest(const tracked_objects::Location& from_here,
+ WriterTag writer,
+ syncer::syncable::Directory* directory,
+ WaitableEvent* wait_for_syncapi)
+ : WriteTransaction(from_here, writer, directory),
+ wait_for_syncapi_(wait_for_syncapi) {}
+
+ void NotifyTransactionComplete(syncer::ModelTypeSet types) override {
+ // This is where we differ. Force a thread change here, giving another
+ // thread a chance to create a WriteTransaction
+ wait_for_syncapi_->Wait();
+
+ WriteTransaction::NotifyTransactionComplete(types);
+ }
+
+ private:
+ WaitableEvent* const wait_for_syncapi_;
+};
+
+// Our fake server updater. Needs the RefCountedThreadSafe inheritance so we can
+// post tasks with it.
+class FakeServerUpdater : public base::RefCountedThreadSafe<FakeServerUpdater> {
+ public:
+ FakeServerUpdater(TestProfileSyncService* service,
+ WaitableEvent* wait_for_start,
+ WaitableEvent* wait_for_syncapi,
+ scoped_refptr<base::SequencedTaskRunner> db_thread)
+ : entry_(MakeAutofillEntry("0", "0", 0)),
+ service_(service),
+ wait_for_start_(wait_for_start),
+ wait_for_syncapi_(wait_for_syncapi),
+ is_finished_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED),
+ db_thread_(db_thread) {}
+
+ void Update() {
+ // This gets called in a modelsafeworker thread.
+ ASSERT_TRUE(db_thread_->RunsTasksOnCurrentThread());
+
+ syncer::UserShare* user_share = service_->GetUserShare();
+ syncer::syncable::Directory* directory = user_share->directory.get();
+
+ // Create autofill protobuf.
+ std::string tag = AutocompleteSyncableService::KeyToTag(
+ base::UTF16ToUTF8(entry_.key().name()),
+ base::UTF16ToUTF8(entry_.key().value()));
+ sync_pb::AutofillSpecifics new_autofill;
+ new_autofill.set_name(base::UTF16ToUTF8(entry_.key().name()));
+ new_autofill.set_value(base::UTF16ToUTF8(entry_.key().value()));
+ new_autofill.add_usage_timestamp(entry_.date_created().ToInternalValue());
+ if (entry_.date_created() != entry_.date_last_used()) {
+ new_autofill.add_usage_timestamp(
+ entry_.date_last_used().ToInternalValue());
+ }
+
+ sync_pb::EntitySpecifics entity_specifics;
+ entity_specifics.mutable_autofill()->CopyFrom(new_autofill);
+
+ {
+ // Tell main thread we've started
+ wait_for_start_->Signal();
+
+ // Create write transaction.
+ WriteTransactionTest trans(FROM_HERE, UNITTEST, directory,
+ wait_for_syncapi_);
+
+ // Create actual entry based on autofill protobuf information.
+ // Simulates effects of UpdateLocalDataFromServerData
+ MutableEntry parent(&trans, GET_TYPE_ROOT, AUTOFILL);
+ MutableEntry item(&trans, CREATE, AUTOFILL, parent.GetId(), tag);
+ ASSERT_TRUE(item.good());
+ item.PutSpecifics(entity_specifics);
+ item.PutServerSpecifics(entity_specifics);
+ item.PutBaseVersion(1);
+ syncer::syncable::Id server_item_id =
+ service_->id_factory()->NewServerId();
+ item.PutId(server_item_id);
+ syncer::syncable::Id new_predecessor;
+ ASSERT_TRUE(item.PutPredecessor(new_predecessor));
+ }
+ DVLOG(1) << "FakeServerUpdater finishing.";
+ is_finished_.Signal();
+ }
+
+ void CreateNewEntry(const AutofillEntry& entry) {
+ entry_ = entry;
+ ASSERT_FALSE(db_thread_->RunsTasksOnCurrentThread());
+ if (!db_thread_->PostTask(FROM_HERE,
+ base::Bind(&FakeServerUpdater::Update, this))) {
+ NOTREACHED() << "Failed to post task to the db thread.";
+ return;
+ }
+ }
+
+ void WaitForUpdateCompletion() { is_finished_.Wait(); }
+
+ private:
+ friend class base::RefCountedThreadSafe<FakeServerUpdater>;
+ ~FakeServerUpdater() {}
+
+ AutofillEntry entry_;
+ TestProfileSyncService* service_;
+ WaitableEvent* const wait_for_start_;
+ WaitableEvent* const wait_for_syncapi_;
+ WaitableEvent is_finished_;
+ syncer::syncable::Id parent_id_;
+ scoped_refptr<base::SequencedTaskRunner> db_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeServerUpdater);
+};
+
+// TODO(skrul): Test abort startup.
+// TODO(skrul): Test processing of cloud changes.
+// TODO(tim): Add autofill data type controller test, and a case to cover
+// waiting for the PersonalDataManager.
+TEST_F(ProfileSyncServiceAutofillTest, FailModelAssociation) {
+ // Don't create the root autofill node so startup fails.
+ StartSyncService(base::Closure(), true, AUTOFILL);
+ EXPECT_TRUE(sync_service()->HasUnrecoverableError());
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, EmptyNativeEmptySync) {
+ EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
+ .WillOnce(Return(true));
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, AUTOFILL);
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ StartSyncService(create_root.callback(), false, AUTOFILL);
+ EXPECT_TRUE(create_root.success());
+ std::vector<AutofillEntry> sync_entries;
+ std::vector<AutofillProfile> sync_profiles;
+ ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
+ EXPECT_EQ(0U, sync_entries.size());
+ EXPECT_EQ(0U, sync_profiles.size());
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, HasNativeEntriesEmptySync) {
+ std::vector<AutofillEntry> entries;
+ entries.push_back(MakeAutofillEntry("foo", "bar", 1));
+ EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, AUTOFILL);
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ StartSyncService(create_root.callback(), false, AUTOFILL);
+ ASSERT_TRUE(create_root.success());
+ std::vector<AutofillEntry> sync_entries;
+ std::vector<AutofillProfile> sync_profiles;
+ ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
+ ASSERT_EQ(1U, entries.size());
+ EXPECT_TRUE(entries[0] == sync_entries[0]);
+ EXPECT_EQ(0U, sync_profiles.size());
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, HasProfileEmptySync) {
+ std::vector<AutofillProfile*> profiles;
+ std::vector<AutofillProfile> expected_profiles;
+ // Owned by GetAutofillProfiles caller.
+ AutofillProfile* profile0 = new AutofillProfile;
+ autofill::test::SetProfileInfoWithGuid(
+ profile0, "54B3F9AA-335E-4F71-A27D-719C41564230", "Billing", "Mitchell",
+ "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ profiles.push_back(profile0);
+ expected_profiles.push_back(*profile0);
+ EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(profiles), Return(true)));
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, AUTOFILL_PROFILE);
+ StartSyncService(create_root.callback(), false, AUTOFILL_PROFILE);
+ ASSERT_TRUE(create_root.success());
+ std::vector<AutofillProfile> sync_profiles;
+ ASSERT_TRUE(GetAutofillProfilesFromSyncDBUnderProfileNode(&sync_profiles));
+ EXPECT_EQ(1U, sync_profiles.size());
+ EXPECT_EQ(0, expected_profiles[0].Compare(sync_profiles[0]));
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, HasNativeWithDuplicatesEmptySync) {
+ // There is buggy autofill code that allows duplicate name/value
+ // pairs to exist in the database with separate pair_ids.
+ std::vector<AutofillEntry> entries;
+ entries.push_back(MakeAutofillEntry("foo", "bar", 1));
+ entries.push_back(MakeAutofillEntry("dup", "", 2));
+ entries.push_back(MakeAutofillEntry("dup", "", 3));
+ EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, AUTOFILL);
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ StartSyncService(create_root.callback(), false, AUTOFILL);
+ ASSERT_TRUE(create_root.success());
+ std::vector<AutofillEntry> sync_entries;
+ std::vector<AutofillProfile> sync_profiles;
+ ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
+ EXPECT_EQ(2U, sync_entries.size());
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncNoMerge) {
+ AutofillEntry native_entry(MakeAutofillEntry("native", "entry", 1));
+ AutofillEntry sync_entry(MakeAutofillEntry("sync", "entry", 2));
+
+ std::vector<AutofillEntry> native_entries;
+ native_entries.push_back(native_entry);
+
+ EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
+
+ std::vector<AutofillEntry> sync_entries;
+ sync_entries.push_back(sync_entry);
+
+ AddAutofillHelper<AutofillEntry> add_autofill(this, sync_entries);
+
+ EXPECT_CALL(autofill_table(), UpdateAutofillEntries(ElementsAre(sync_entry)))
+ .WillOnce(Return(true));
+
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ StartSyncService(add_autofill.callback(), false, AUTOFILL);
+ ASSERT_TRUE(add_autofill.success());
+
+ std::set<AutofillEntry> expected_entries;
+ expected_entries.insert(native_entry);
+ expected_entries.insert(sync_entry);
+
+ std::vector<AutofillEntry> new_sync_entries;
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
+ std::set<AutofillEntry> new_sync_entries_set(new_sync_entries.begin(),
+ new_sync_entries.end());
+
+ EXPECT_TRUE(expected_entries == new_sync_entries_set);
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncMergeEntry) {
+ AutofillEntry native_entry(MakeAutofillEntry("merge", "entry", 1));
+ AutofillEntry sync_entry(MakeAutofillEntry("merge", "entry", 2));
+ AutofillEntry merged_entry(MakeAutofillEntry("merge", "entry", 1, 2));
+
+ std::vector<AutofillEntry> native_entries;
+ native_entries.push_back(native_entry);
+ EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
+
+ std::vector<AutofillEntry> sync_entries;
+ sync_entries.push_back(sync_entry);
+ AddAutofillHelper<AutofillEntry> add_autofill(this, sync_entries);
+
+ EXPECT_CALL(autofill_table(),
+ UpdateAutofillEntries(ElementsAre(merged_entry)))
+ .WillOnce(Return(true));
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ StartSyncService(add_autofill.callback(), false, AUTOFILL);
+ ASSERT_TRUE(add_autofill.success());
+
+ std::vector<AutofillEntry> new_sync_entries;
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(merged_entry == new_sync_entries[0]);
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncMergeProfile) {
+ AutofillProfile sync_profile;
+ autofill::test::SetProfileInfoWithGuid(
+ &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
+ "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
+ "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
+
+ AutofillProfile* native_profile = new AutofillProfile;
+ autofill::test::SetProfileInfoWithGuid(
+ native_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
+ "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
+ "Orlando", "FL", "32801", "US", "19482937549");
+
+ std::vector<AutofillProfile*> native_profiles;
+ native_profiles.push_back(native_profile);
+ EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
+
+ std::vector<AutofillProfile> sync_profiles;
+ sync_profiles.push_back(sync_profile);
+ AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+
+ EXPECT_CALL(autofill_table(),
+ UpdateAutofillProfile(MatchProfiles(sync_profile)))
+ .WillOnce(Return(true));
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+ ASSERT_TRUE(add_autofill.success());
+
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
+ ASSERT_EQ(1U, new_sync_profiles.size());
+ EXPECT_EQ(0, sync_profile.Compare(new_sync_profiles[0]));
+}
+
+// Tests that a sync with a new native profile that matches a more recent new
+// sync profile but with less information results in the native profile being
+// deleted and replaced by the sync profile with merged usage stats.
+TEST_F(
+ ProfileSyncServiceAutofillTest,
+ HasNativeHasSyncMergeSimilarProfileCombine_SyncHasMoreInfoAndMoreRecent) {
+ // Create two almost identical profiles. The GUIDs are different and the
+ // native profile has no value for company name.
+ AutofillProfile sync_profile;
+ autofill::test::SetProfileInfoWithGuid(
+ &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
+ "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
+ "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
+ sync_profile.set_use_date(base::Time::FromTimeT(4321));
+
+ AutofillProfile* native_profile = new AutofillProfile;
+ autofill::test::SetProfileInfoWithGuid(
+ native_profile, "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
+ "Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ native_profile->set_use_date(base::Time::FromTimeT(1234));
+
+ AutofillProfile expected_profile(sync_profile);
+ expected_profile.SetRawInfo(NAME_FULL,
+ ASCIIToUTF16("Billing Mitchell Morrison"));
+ expected_profile.set_use_count(1);
+
+ std::vector<AutofillProfile*> native_profiles;
+ native_profiles.push_back(native_profile);
+ EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
+ EXPECT_CALL(autofill_table(),
+ AddAutofillProfile(MatchProfiles(expected_profile)))
+ .WillOnce(Return(true));
+ EXPECT_CALL(autofill_table(),
+ RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
+ .WillOnce(Return(true));
+ std::vector<AutofillProfile> sync_profiles;
+ sync_profiles.push_back(sync_profile);
+ AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ // Adds all entries in |sync_profiles| to sync.
+ StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+ ASSERT_TRUE(add_autofill.success());
+
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
+ ASSERT_EQ(1U, new_sync_profiles.size());
+ // Check that key fields are the same.
+ EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(sync_profile, "en-US"));
+ // Make sure the additional information from the sync profile was kept.
+ EXPECT_EQ(ASCIIToUTF16("Fox"),
+ new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
+ // Check that the latest use date is saved.
+ EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
+ // Check that the use counts were added (default value is 1).
+ EXPECT_EQ(1U, new_sync_profiles[0].use_count());
+}
+
+// Tests that a sync with a new native profile that matches an older new sync
+// profile but with less information results in the native profile being deleted
+// and replaced by the sync profile with merged usage stats.
+TEST_F(ProfileSyncServiceAutofillTest,
+ HasNativeHasSyncMergeSimilarProfileCombine_SyncHasMoreInfoAndOlder) {
+ // Create two almost identical profiles. The GUIDs are different and the
+ // native profile has no value for company name.
+ AutofillProfile sync_profile;
+ autofill::test::SetProfileInfoWithGuid(
+ &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
+ "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
+ "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
+ sync_profile.set_use_date(base::Time::FromTimeT(1234));
+
+ AutofillProfile* native_profile = new AutofillProfile;
+ autofill::test::SetProfileInfoWithGuid(
+ native_profile, "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
+ "Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ native_profile->set_use_date(base::Time::FromTimeT(4321));
+
+ AutofillProfile expected_profile(sync_profile);
+ expected_profile.SetRawInfo(NAME_FULL,
+ ASCIIToUTF16("Billing Mitchell Morrison"));
+ expected_profile.set_use_count(1);
+ expected_profile.set_use_date(native_profile->use_date());
+
+ std::vector<AutofillProfile*> native_profiles;
+ native_profiles.push_back(native_profile);
+ EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
+ EXPECT_CALL(autofill_table(),
+ AddAutofillProfile(MatchProfiles(expected_profile)))
+ .WillOnce(Return(true));
+ EXPECT_CALL(autofill_table(),
+ RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
+ .WillOnce(Return(true));
+ std::vector<AutofillProfile> sync_profiles;
+ sync_profiles.push_back(sync_profile);
+ AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ // Adds all entries in |sync_profiles| to sync.
+ StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+ ASSERT_TRUE(add_autofill.success());
+
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
+ ASSERT_EQ(1U, new_sync_profiles.size());
+ // Check that key fields are the same.
+ EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(sync_profile, "en-US"));
+ // Make sure the additional information from the sync profile was kept.
+ EXPECT_EQ(ASCIIToUTF16("Fox"),
+ new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
+ // Check that the latest use date is saved.
+ EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
+ // Check that the use counts were added (default value is 1).
+ EXPECT_EQ(1U, new_sync_profiles[0].use_count());
+}
+
+// Tests that a sync with a new native profile that matches an a new sync
+// profile but with more information results in the native profile being deleted
+// and replaced by the sync profile with the native profiles additional
+// information merged in. The merge should happen even if the sync profile is
+// more recent.
+TEST_F(ProfileSyncServiceAutofillTest,
+ HasNativeHasSyncMergeSimilarProfileCombine_NativeHasMoreInfo) {
+ // Create two almost identical profiles. The GUIDs are different and the
+ // sync profile has no value for company name.
+ AutofillProfile sync_profile;
+ autofill::test::SetProfileInfoWithGuid(
+ &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
+ "Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ sync_profile.set_use_date(base::Time::FromTimeT(4321));
+
+ AutofillProfile* native_profile = new AutofillProfile;
+ autofill::test::SetProfileInfoWithGuid(
+ native_profile, "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
+ "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
+ "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
+ native_profile->set_use_date(base::Time::FromTimeT(1234));
+
+ AutofillProfile expected_profile(*native_profile);
+ expected_profile.SetRawInfo(NAME_FULL,
+ ASCIIToUTF16("Billing Mitchell Morrison"));
+ expected_profile.set_use_date(sync_profile.use_date());
+ expected_profile.set_use_count(1);
+
+ std::vector<AutofillProfile*> native_profiles;
+ native_profiles.push_back(native_profile);
+ EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
+ EXPECT_CALL(autofill_table(),
+ AddAutofillProfile(MatchProfiles(expected_profile)))
+ .WillOnce(Return(true));
+ EXPECT_CALL(autofill_table(),
+ RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
+ .WillOnce(Return(true));
+ std::vector<AutofillProfile> sync_profiles;
+ sync_profiles.push_back(sync_profile);
+ AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ // Adds all entries in |sync_profiles| to sync.
+ StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+ ASSERT_TRUE(add_autofill.success());
+
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
+ ASSERT_EQ(1U, new_sync_profiles.size());
+ // Check that key fields are the same.
+ EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(expected_profile, "en-US"));
+ // Make sure the addtional information of the native profile was saved into
+ // the sync profile.
+ EXPECT_EQ(ASCIIToUTF16("Fox"),
+ new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
+ // Check that the latest use date is saved.
+ EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
+ // Check that the use counts were added (default value is 1).
+ EXPECT_EQ(1U, new_sync_profiles[0].use_count());
+}
+
+// Tests that a sync with a new native profile that differ only by name a new
+// sync profile results in keeping both profiles.
+TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSync_DifferentPrimaryInfo) {
+ AutofillProfile sync_profile;
+ autofill::test::SetProfileInfoWithGuid(
+ &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
+ "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
+ "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
+ sync_profile.set_use_date(base::Time::FromTimeT(4321));
+
+ AutofillProfile* native_profile = new AutofillProfile;
+ autofill::test::SetProfileInfoWithGuid(
+ native_profile, "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing", "John",
+ "Smith", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood",
+ "CA", "91601", "US", "12345678910");
+ native_profile->set_use_date(base::Time::FromTimeT(1234));
+
+ std::vector<AutofillProfile*> native_profiles;
+ native_profiles.push_back(native_profile);
+ EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
+ EXPECT_CALL(autofill_table(), AddAutofillProfile(MatchProfiles(sync_profile)))
+ .WillOnce(Return(true));
+ std::vector<AutofillProfile> sync_profiles;
+ sync_profiles.push_back(sync_profile);
+ AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ // Adds all entries in |sync_profiles| to sync.
+ StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+ ASSERT_TRUE(add_autofill.success());
+
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
+ // The two profiles should be kept.
+ ASSERT_EQ(2U, new_sync_profiles.size());
+}
+
+// Tests that a new native profile that is the same as a new sync profile except
+// with different GUIDs results in the native profile being deleted and replaced
+// by the sync profile.
+TEST_F(ProfileSyncServiceAutofillTest, MergeProfileWithDifferentGuid) {
+ AutofillProfile sync_profile;
+
+ autofill::test::SetProfileInfoWithGuid(
+ &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
+ "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
+ "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
+ sync_profile.set_use_count(20);
+ sync_profile.set_use_date(base::Time::FromTimeT(1234));
+
+ std::string native_guid = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
+ AutofillProfile* native_profile = new AutofillProfile;
+ autofill::test::SetProfileInfoWithGuid(
+ native_profile, native_guid.c_str(), "Billing", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
+ "91601", "US", "12345678910");
+ native_profile->set_use_count(5);
+ native_profile->set_use_date(base::Time::FromTimeT(4321));
+
+ std::vector<AutofillProfile*> native_profiles;
+ native_profiles.push_back(native_profile);
+ EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
+
+ std::vector<AutofillProfile> sync_profiles;
+ sync_profiles.push_back(sync_profile);
+ AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+
+ EXPECT_CALL(autofill_table(), AddAutofillProfile(_)).WillOnce(Return(true));
+ EXPECT_CALL(autofill_table(), RemoveAutofillProfile(native_guid))
+ .WillOnce(Return(true));
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+ ASSERT_TRUE(add_autofill.success());
+
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
+ // Check that the profiles were merged.
+ ASSERT_EQ(1U, new_sync_profiles.size());
+ EXPECT_EQ(0, sync_profile.Compare(new_sync_profiles[0]));
+ // Check that the sync guid was kept.
+ EXPECT_EQ(sync_profile.guid(), new_sync_profiles[0].guid());
+ // Check that the sync profile use count was kept.
+ EXPECT_EQ(20U, new_sync_profiles[0].use_count());
+ // Check that the sync profile use date was kept.
+ EXPECT_EQ(base::Time::FromTimeT(1234), new_sync_profiles[0].use_date());
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeAddEntry) {
+ EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
+ .WillOnce(Return(true));
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, AUTOFILL);
+ StartSyncService(create_root.callback(), false, AUTOFILL);
+ ASSERT_TRUE(create_root.success());
+
+ AutofillEntry added_entry(MakeAutofillEntry("added", "entry", 1));
+
+ EXPECT_CALL(autofill_table(), GetAutofillTimestamps(_, _, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(added_entry.date_created()),
+ SetArgumentPointee<3>(added_entry.date_last_used()),
+ Return(true)));
+
+ AutofillChangeList changes;
+ changes.push_back(AutofillChange(AutofillChange::ADD, added_entry.key()));
+
+ web_data_service()->OnAutofillEntriesChanged(changes);
+
+ std::vector<AutofillEntry> new_sync_entries;
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(added_entry == new_sync_entries[0]);
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeAddProfile) {
+ EXPECT_CALL(autofill_table(), GetAutofillProfiles(_)).WillOnce(Return(true));
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, AUTOFILL_PROFILE);
+ StartSyncService(create_root.callback(), false, AUTOFILL_PROFILE);
+ ASSERT_TRUE(create_root.success());
+
+ AutofillProfile added_profile;
+ autofill::test::SetProfileInfoWithGuid(
+ &added_profile, "D6ADA912-D374-4C0A-917D-F5C8EBE43011", "Josephine",
+ "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
+ "Orlando", "FL", "32801", "US", "19482937549");
+
+ AutofillProfileChange change(AutofillProfileChange::ADD, added_profile.guid(),
+ &added_profile);
+ web_data_service()->OnAutofillProfileChanged(change);
+
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
+ ASSERT_EQ(1U, new_sync_profiles.size());
+ EXPECT_EQ(0, added_profile.Compare(new_sync_profiles[0]));
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeUpdateEntry) {
+ AutofillEntry original_entry(MakeAutofillEntry("my", "entry", 1));
+ std::vector<AutofillEntry> original_entries;
+ original_entries.push_back(original_entry);
+
+ EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ CreateRootHelper create_root(this, AUTOFILL);
+ StartSyncService(create_root.callback(), false, AUTOFILL);
+ ASSERT_TRUE(create_root.success());
+
+ AutofillEntry updated_entry(MakeAutofillEntry("my", "entry", 1, 2));
+
+ EXPECT_CALL(autofill_table(), GetAutofillTimestamps(_, _, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(updated_entry.date_created()),
+ SetArgumentPointee<3>(updated_entry.date_last_used()),
+ Return(true)));
+
+ AutofillChangeList changes;
+ changes.push_back(
+ AutofillChange(AutofillChange::UPDATE, updated_entry.key()));
+ web_data_service()->OnAutofillEntriesChanged(changes);
+
+ std::vector<AutofillEntry> new_sync_entries;
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(updated_entry == new_sync_entries[0]);
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveEntry) {
+ AutofillEntry original_entry(MakeAutofillEntry("my", "entry", 1));
+ std::vector<AutofillEntry> original_entries;
+ original_entries.push_back(original_entry);
+
+ EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ CreateRootHelper create_root(this, AUTOFILL);
+ StartSyncService(create_root.callback(), false, AUTOFILL);
+ ASSERT_TRUE(create_root.success());
+
+ AutofillChangeList changes;
+ changes.push_back(
+ AutofillChange(AutofillChange::REMOVE, original_entry.key()));
+ web_data_service()->OnAutofillEntriesChanged(changes);
+
+ std::vector<AutofillEntry> new_sync_entries;
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
+ ASSERT_EQ(0U, new_sync_entries.size());
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveProfile) {
+ AutofillProfile sync_profile;
+ autofill::test::SetProfileInfoWithGuid(
+ &sync_profile, "3BA5FA1B-1EC4-4BB3-9B57-EC92BE3C1A09", "Josephine",
+ "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
+ "Orlando", "FL", "32801", "US", "19482937549");
+ AutofillProfile* native_profile = new AutofillProfile;
+ autofill::test::SetProfileInfoWithGuid(
+ native_profile, "3BA5FA1B-1EC4-4BB3-9B57-EC92BE3C1A09", "Josephine",
+ "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
+ "Orlando", "FL", "32801", "US", "19482937549");
+
+ std::vector<AutofillProfile*> native_profiles;
+ native_profiles.push_back(native_profile);
+ EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_profiles), Return(true)));
+
+ std::vector<AutofillProfile> sync_profiles;
+ sync_profiles.push_back(sync_profile);
+ AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+ EXPECT_CALL(personal_data_manager(), Refresh());
+ StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+ ASSERT_TRUE(add_autofill.success());
+
+ AutofillProfileChange change(AutofillProfileChange::REMOVE,
+ sync_profile.guid(), NULL);
+ web_data_service()->OnAutofillProfileChanged(change);
+
+ std::vector<AutofillProfile> new_sync_profiles;
+ ASSERT_TRUE(
+ GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
+ ASSERT_EQ(0U, new_sync_profiles.size());
+}
+
+TEST_F(ProfileSyncServiceAutofillTest, ServerChangeRace) {
+ // Once for MergeDataAndStartSyncing() and twice for ProcessSyncChanges(), via
+ // LoadAutofillData().
+ EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
+ .Times(3)
+ .WillRepeatedly(Return(true));
+ // On the other hand Autofill and Autocomplete are separated now, so
+ // GetAutofillProfiles() should not be called.
+ EXPECT_CALL(autofill_table(), GetAutofillProfiles(_)).Times(0);
+ EXPECT_CALL(autofill_table(), UpdateAutofillEntries(_))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(personal_data_manager(), Refresh()).Times(3);
+ CreateRootHelper create_root(this, AUTOFILL);
+ StartSyncService(create_root.callback(), false, AUTOFILL);
+ ASSERT_TRUE(create_root.success());
+
+ std::unique_ptr<WaitableEvent> wait_for_start(
+ new WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED));
+ std::unique_ptr<WaitableEvent> wait_for_syncapi(
+ new WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED));
+ scoped_refptr<FakeServerUpdater> updater(new FakeServerUpdater(
+ sync_service(), wait_for_start.get(), wait_for_syncapi.get(),
+ data_type_thread()->task_runner()));
+
+ // This server side update will stall waiting for CommitWaiter.
+ updater->CreateNewEntry(MakeAutofillEntry("server", "entry", 1));
+ wait_for_start->Wait();
+
+ AutofillEntry syncapi_entry(MakeAutofillEntry("syncapi", "entry", 2));
+ ASSERT_TRUE(AddAutofillSyncNode(syncapi_entry));
+ DVLOG(1) << "Syncapi update finished.";
+
+ // If we reach here, it means syncapi succeeded and we didn't deadlock. Yay!
+ // Signal FakeServerUpdater that it can complete.
+ wait_for_syncapi->Signal();
+
+ // Make another entry to ensure nothing broke afterwards and wait for finish
+ // to clean up.
+ updater->WaitForUpdateCompletion();
+ updater->CreateNewEntry(MakeAutofillEntry("server2", "entry2", 3));
+ updater->WaitForUpdateCompletion();
+
+ // Let callbacks posted on UI thread execute.
+ base::RunLoop().RunUntilIdle();
+
+ std::vector<AutofillEntry> sync_entries;
+ std::vector<AutofillProfile> sync_profiles;
+ ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
+ EXPECT_EQ(3U, sync_entries.size());
+ EXPECT_EQ(0U, sync_profiles.size());
+ for (size_t i = 0; i < sync_entries.size(); i++) {
+ DVLOG(1) << "Entry " << i << ": " << sync_entries[i].key().name() << ", "
+ << sync_entries[i].key().value();
+ }
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_service_bookmark_unittest.cc b/chromium/components/browser_sync/profile_sync_service_bookmark_unittest.cc
new file mode 100644
index 00000000000..ff90423810f
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_service_bookmark_unittest.cc
@@ -0,0 +1,2601 @@
+// 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.
+
+// TODO(akalin): This file is basically just a unit test for
+// BookmarkChangeProcessor. Write unit tests for
+// BookmarkModelAssociator separately.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <queue>
+#include <stack>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_message_loop.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/bookmarks/browser/base_bookmark_model_observer.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/bookmark_utils.h"
+#include "components/bookmarks/managed/managed_bookmark_service.h"
+#include "components/bookmarks/test/bookmark_test_helpers.h"
+#include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/browser_sync/profile_sync_test_util.h"
+#include "components/sync/api/data_type_error_handler.h"
+#include "components/sync/api/data_type_error_handler_mock.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_merge_result.h"
+#include "components/sync/core/change_record.h"
+#include "components/sync/core/read_node.h"
+#include "components/sync/core/read_transaction.h"
+#include "components/sync/core/test/test_user_share.h"
+#include "components/sync/core/write_node.h"
+#include "components/sync/core/write_transaction.h"
+#include "components/sync/core_impl/syncapi_internal.h"
+#include "components/sync/driver/fake_sync_client.h"
+#include "components/sync/syncable/mutable_entry.h"
+#include "components/sync/syncable/syncable_id.h"
+#include "components/sync/syncable/syncable_util.h"
+#include "components/sync/syncable/syncable_write_transaction.h"
+#include "components/sync_bookmarks/bookmark_change_processor.h"
+#include "components/sync_bookmarks/bookmark_model_associator.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using bookmarks::BookmarkModel;
+using bookmarks::BookmarkNode;
+using sync_bookmarks::BookmarkChangeProcessor;
+using sync_bookmarks::BookmarkModelAssociator;
+using syncer::BaseNode;
+using testing::_;
+using testing::Return;
+using testing::StrictMock;
+
+namespace browser_sync {
+
+namespace {
+
+#if defined(OS_ANDROID) || defined(OS_IOS)
+static const bool kExpectMobileBookmarks = true;
+#else
+static const bool kExpectMobileBookmarks = false;
+#endif // defined(OS_ANDROID) || defined(OS_IOS)
+
+std::string ReturnEmptyString() {
+ return std::string();
+}
+
+void MakeServerUpdate(syncer::WriteTransaction* trans,
+ syncer::WriteNode* node) {
+ syncer::syncable::ChangeEntryIDAndUpdateChildren(
+ trans->GetWrappedWriteTrans(), node->GetMutableEntryForTest(),
+ syncer::syncable::Id::CreateFromServerId(
+ base::Int64ToString(node->GetId())));
+ node->GetMutableEntryForTest()->PutBaseVersion(10);
+ node->GetMutableEntryForTest()->PutIsUnappliedUpdate(true);
+}
+
+void MakeServerUpdate(syncer::WriteTransaction* trans, int64_t id) {
+ syncer::WriteNode node(trans);
+ EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
+ MakeServerUpdate(trans, &node);
+}
+
+// FakeServerChange constructs a list of syncer::ChangeRecords while modifying
+// the sync model, and can pass the ChangeRecord list to a
+// syncer::SyncObserver (i.e., the ProfileSyncService) to test the client
+// change-application behavior.
+// Tests using FakeServerChange should be careful to avoid back-references,
+// since FakeServerChange will send the edits in the order specified.
+class FakeServerChange {
+ public:
+ explicit FakeServerChange(syncer::WriteTransaction* trans) : trans_(trans) {}
+
+ // Pretend that the server told the syncer to add a bookmark object.
+ int64_t AddWithMetaInfo(const std::string& title,
+ const std::string& url,
+ const BookmarkNode::MetaInfoMap* meta_info_map,
+ bool is_folder,
+ int64_t parent_id,
+ int64_t predecessor_id) {
+ syncer::ReadNode parent(trans_);
+ EXPECT_EQ(BaseNode::INIT_OK, parent.InitByIdLookup(parent_id));
+ syncer::WriteNode node(trans_);
+ if (predecessor_id == 0) {
+ EXPECT_TRUE(node.InitBookmarkByCreation(parent, NULL));
+ } else {
+ syncer::ReadNode predecessor(trans_);
+ EXPECT_EQ(BaseNode::INIT_OK, predecessor.InitByIdLookup(predecessor_id));
+ EXPECT_EQ(predecessor.GetParentId(), parent.GetId());
+ EXPECT_TRUE(node.InitBookmarkByCreation(parent, &predecessor));
+ }
+ EXPECT_EQ(node.GetPredecessorId(), predecessor_id);
+ EXPECT_EQ(node.GetParentId(), parent_id);
+ node.SetIsFolder(is_folder);
+ node.SetTitle(title);
+
+ sync_pb::BookmarkSpecifics specifics(node.GetBookmarkSpecifics());
+ const base::Time creation_time(base::Time::Now());
+ specifics.set_creation_time_us(creation_time.ToInternalValue());
+ if (!is_folder)
+ specifics.set_url(url);
+ if (meta_info_map)
+ SetNodeMetaInfo(*meta_info_map, &specifics);
+ node.SetBookmarkSpecifics(specifics);
+
+ syncer::ChangeRecord record;
+ record.action = syncer::ChangeRecord::ACTION_ADD;
+ record.id = node.GetId();
+ changes_.push_back(record);
+ return node.GetId();
+ }
+
+ int64_t Add(const std::string& title,
+ const std::string& url,
+ bool is_folder,
+ int64_t parent_id,
+ int64_t predecessor_id) {
+ return AddWithMetaInfo(title, url, NULL, is_folder, parent_id,
+ predecessor_id);
+ }
+
+ // Add a bookmark folder.
+ int64_t AddFolder(const std::string& title,
+ int64_t parent_id,
+ int64_t predecessor_id) {
+ return Add(title, std::string(), true, parent_id, predecessor_id);
+ }
+ int64_t AddFolderWithMetaInfo(const std::string& title,
+ const BookmarkNode::MetaInfoMap* meta_info_map,
+ int64_t parent_id,
+ int64_t predecessor_id) {
+ return AddWithMetaInfo(title, std::string(), meta_info_map, true, parent_id,
+ predecessor_id);
+ }
+
+ // Add a bookmark.
+ int64_t AddURL(const std::string& title,
+ const std::string& url,
+ int64_t parent_id,
+ int64_t predecessor_id) {
+ return Add(title, url, false, parent_id, predecessor_id);
+ }
+ int64_t AddURLWithMetaInfo(const std::string& title,
+ const std::string& url,
+ const BookmarkNode::MetaInfoMap* meta_info_map,
+ int64_t parent_id,
+ int64_t predecessor_id) {
+ return AddWithMetaInfo(title, url, meta_info_map, false, parent_id,
+ predecessor_id);
+ }
+
+ // Pretend that the server told the syncer to delete an object.
+ void Delete(int64_t id) {
+ {
+ // Delete the sync node.
+ syncer::WriteNode node(trans_);
+ EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
+ if (node.GetIsFolder())
+ EXPECT_FALSE(node.GetFirstChildId());
+ node.GetMutableEntryForTest()->PutServerIsDel(true);
+ node.Tombstone();
+ }
+ {
+ // Verify the deletion.
+ syncer::ReadNode node(trans_);
+ EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_IS_DEL, node.InitByIdLookup(id));
+ }
+
+ syncer::ChangeRecord record;
+ record.action = syncer::ChangeRecord::ACTION_DELETE;
+ record.id = id;
+ // Deletions are always first in the changelist, but we can't actually do
+ // WriteNode::Remove() on the node until its children are moved. So, as
+ // a practical matter, users of FakeServerChange must move or delete
+ // children before parents. Thus, we must insert the deletion record
+ // at the front of the vector.
+ changes_.insert(changes_.begin(), record);
+ }
+
+ // Set a new title value, and return the old value.
+ std::string ModifyTitle(int64_t id, const std::string& new_title) {
+ syncer::WriteNode node(trans_);
+ EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
+ std::string old_title = node.GetTitle();
+ node.SetTitle(new_title);
+ SetModified(id);
+ return old_title;
+ }
+
+ // Set a new parent and predecessor value. Return the old parent id.
+ // We could return the old predecessor id, but it turns out not to be
+ // very useful for assertions.
+ int64_t ModifyPosition(int64_t id,
+ int64_t parent_id,
+ int64_t predecessor_id) {
+ syncer::ReadNode parent(trans_);
+ EXPECT_EQ(BaseNode::INIT_OK, parent.InitByIdLookup(parent_id));
+ syncer::WriteNode node(trans_);
+ EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
+ int64_t old_parent_id = node.GetParentId();
+ if (predecessor_id == 0) {
+ EXPECT_TRUE(node.SetPosition(parent, NULL));
+ } else {
+ syncer::ReadNode predecessor(trans_);
+ EXPECT_EQ(BaseNode::INIT_OK, predecessor.InitByIdLookup(predecessor_id));
+ EXPECT_EQ(predecessor.GetParentId(), parent.GetId());
+ EXPECT_TRUE(node.SetPosition(parent, &predecessor));
+ }
+ SetModified(id);
+ return old_parent_id;
+ }
+
+ void ModifyCreationTime(int64_t id, int64_t creation_time_us) {
+ syncer::WriteNode node(trans_);
+ ASSERT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
+ sync_pb::BookmarkSpecifics specifics = node.GetBookmarkSpecifics();
+ specifics.set_creation_time_us(creation_time_us);
+ node.SetBookmarkSpecifics(specifics);
+ SetModified(id);
+ }
+
+ void ModifyMetaInfo(int64_t id,
+ const BookmarkNode::MetaInfoMap& meta_info_map) {
+ syncer::WriteNode node(trans_);
+ ASSERT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
+ sync_pb::BookmarkSpecifics specifics = node.GetBookmarkSpecifics();
+ SetNodeMetaInfo(meta_info_map, &specifics);
+ node.SetBookmarkSpecifics(specifics);
+ SetModified(id);
+ }
+
+ // Pass the fake change list to |service|.
+ void ApplyPendingChanges(syncer::ChangeProcessor* processor) {
+ processor->ApplyChangesFromSyncModel(
+ trans_, 0, syncer::ImmutableChangeRecordList(&changes_));
+ }
+
+ const syncer::ChangeRecordList& changes() { return changes_; }
+
+ private:
+ // Helper function to push an ACTION_UPDATE record onto the back
+ // of the changelist.
+ void SetModified(int64_t id) {
+ // Coalesce multi-property edits.
+ if (!changes_.empty() && changes_.back().id == id &&
+ changes_.back().action == syncer::ChangeRecord::ACTION_UPDATE)
+ return;
+ syncer::ChangeRecord record;
+ record.action = syncer::ChangeRecord::ACTION_UPDATE;
+ record.id = id;
+ changes_.push_back(record);
+ }
+
+ void SetNodeMetaInfo(const BookmarkNode::MetaInfoMap& meta_info_map,
+ sync_pb::BookmarkSpecifics* specifics) {
+ specifics->clear_meta_info();
+ // Deliberatly set MetaInfoMap entries in opposite order (compared
+ // to the implementation in BookmarkChangeProcessor) to ensure that
+ // (a) the implementation isn't sensitive to the order and
+ // (b) the original meta info isn't blindly overwritten by
+ // BookmarkChangeProcessor unless there is a real change.
+ BookmarkNode::MetaInfoMap::const_iterator it = meta_info_map.end();
+ while (it != meta_info_map.begin()) {
+ --it;
+ sync_pb::MetaInfo* meta_info = specifics->add_meta_info();
+ meta_info->set_key(it->first);
+ meta_info->set_value(it->second);
+ }
+ }
+
+ // The transaction on which everything happens.
+ syncer::WriteTransaction* trans_;
+
+ // The change list we construct.
+ syncer::ChangeRecordList changes_;
+ DISALLOW_COPY_AND_ASSIGN(FakeServerChange);
+};
+
+class ExtensiveChangesBookmarkModelObserver
+ : public bookmarks::BaseBookmarkModelObserver {
+ public:
+ ExtensiveChangesBookmarkModelObserver()
+ : started_count_(0),
+ completed_count_at_started_(0),
+ completed_count_(0) {}
+
+ void ExtensiveBookmarkChangesBeginning(BookmarkModel* model) override {
+ ++started_count_;
+ completed_count_at_started_ = completed_count_;
+ }
+
+ void ExtensiveBookmarkChangesEnded(BookmarkModel* model) override {
+ ++completed_count_;
+ }
+
+ void BookmarkModelChanged() override {}
+
+ int get_started() const { return started_count_; }
+
+ int get_completed_count_at_started() const {
+ return completed_count_at_started_;
+ }
+
+ int get_completed() const { return completed_count_; }
+
+ private:
+ int started_count_;
+ int completed_count_at_started_;
+ int completed_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensiveChangesBookmarkModelObserver);
+};
+
+class ProfileSyncServiceBookmarkTest : public testing::Test {
+ protected:
+ enum LoadOption { LOAD_FROM_STORAGE, DELETE_EXISTING_STORAGE };
+ enum SaveOption { SAVE_TO_STORAGE, DONT_SAVE_TO_STORAGE };
+
+ ProfileSyncServiceBookmarkTest()
+ : managed_bookmark_service_(new bookmarks::ManagedBookmarkService(
+ profile_sync_service_bundle_.pref_service(),
+ base::Bind(ReturnEmptyString))),
+ local_merge_result_(syncer::BOOKMARKS),
+ syncer_merge_result_(syncer::BOOKMARKS) {
+ CHECK(data_dir_.CreateUniqueTempDir());
+ ProfileSyncServiceBundle::SyncClientBuilder builder(
+ &profile_sync_service_bundle_);
+ builder.SetBookmarkModelCallback(base::Bind(
+ &ProfileSyncServiceBookmarkTest::model, base::Unretained(this)));
+ sync_client_ = builder.Build();
+ bookmarks::RegisterProfilePrefs(
+ profile_sync_service_bundle_.pref_service()->registry());
+ }
+
+ ~ProfileSyncServiceBookmarkTest() override {
+ static_cast<KeyedService*>(managed_bookmark_service_.get())->Shutdown();
+ StopSync();
+ }
+
+ void SetUp() override { test_user_share_.SetUp(); }
+
+ void TearDown() override { test_user_share_.TearDown(); }
+
+ bool CanSyncNode(const BookmarkNode* node) {
+ return model_->client()->CanSyncNode(node);
+ }
+
+ // Inserts a folder directly to the share.
+ // Do not use this after model association is complete.
+ //
+ // This function differs from the AddFolder() function declared elsewhere in
+ // this file in that it only affects the sync model. It would be invalid to
+ // change the sync model directly after ModelAssociation. This function can
+ // be invoked prior to model association to set up first-time sync model
+ // association scenarios.
+ int64_t AddFolderToShare(syncer::WriteTransaction* trans,
+ const std::string& title) {
+ EXPECT_FALSE(model_associator_);
+
+ // Be sure to call CreatePermanentBookmarkNodes(), otherwise this will fail.
+ syncer::ReadNode bookmark_bar(trans);
+ EXPECT_EQ(BaseNode::INIT_OK,
+ bookmark_bar.InitByTagLookupForBookmarks("bookmark_bar"));
+
+ syncer::WriteNode node(trans);
+ EXPECT_TRUE(node.InitBookmarkByCreation(bookmark_bar, NULL));
+ node.SetIsFolder(true);
+ node.SetTitle(title);
+
+ return node.GetId();
+ }
+
+ // Inserts a bookmark directly to the share.
+ // Do not use this after model association is complete.
+ //
+ // This function differs from the AddURL() function declared elsewhere in this
+ // file in that it only affects the sync model. It would be invalid to change
+ // the sync model directly after ModelAssociation. This function can be
+ // invoked prior to model association to set up first-time sync model
+ // association scenarios.
+ int64_t AddBookmarkToShare(syncer::WriteTransaction* trans,
+ int64_t parent_id,
+ const std::string& title,
+ const std::string& url) {
+ EXPECT_FALSE(model_associator_);
+
+ syncer::ReadNode parent(trans);
+ EXPECT_EQ(BaseNode::INIT_OK, parent.InitByIdLookup(parent_id));
+
+ sync_pb::BookmarkSpecifics specifics;
+ specifics.set_url(url);
+ specifics.set_title(title);
+
+ syncer::WriteNode node(trans);
+ EXPECT_TRUE(node.InitBookmarkByCreation(parent, NULL));
+ node.SetIsFolder(false);
+ node.SetTitle(title);
+ node.SetBookmarkSpecifics(specifics);
+
+ return node.GetId();
+ }
+
+ // Create a BookmarkModel. If |delete_bookmarks| is true, the bookmarks file
+ // will be deleted before starting up the BookmarkModel.
+ std::unique_ptr<BookmarkModel> CreateBookmarkModel(bool delete_bookmarks) {
+ const base::FilePath& data_path = data_dir_.GetPath();
+ auto model = base::MakeUnique<BookmarkModel>(
+ base::WrapUnique(new bookmarks::TestBookmarkClient()));
+ managed_bookmark_service_->BookmarkModelCreated(model.get());
+ int64_t next_id = 0;
+ static_cast<bookmarks::TestBookmarkClient*>(model->client())
+ ->SetExtraNodesToLoad(
+ managed_bookmark_service_->GetLoadExtraNodesCallback().Run(
+ &next_id));
+ if (delete_bookmarks) {
+ base::DeleteFile(data_path.Append(FILE_PATH_LITERAL("dummy_bookmarks")),
+ false);
+ }
+
+ model->Load(profile_sync_service_bundle_.pref_service(), data_path,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+ bookmarks::test::WaitForBookmarkModelToLoad(model.get());
+ return model;
+ }
+
+ // Load (or re-load) the bookmark model. |load| controls use of the
+ // bookmarks file on disk. |save| controls whether the newly loaded
+ // bookmark model will write out a bookmark file as it goes.
+ void LoadBookmarkModel(LoadOption load, SaveOption save) {
+ bool delete_bookmarks = load == DELETE_EXISTING_STORAGE;
+ model_.reset();
+ model_ = CreateBookmarkModel(delete_bookmarks);
+ // This noticeably speeds up the unit tests that request it.
+ if (save == DONT_SAVE_TO_STORAGE)
+ model_->ClearStore();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ int GetSyncBookmarkCount() {
+ syncer::ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
+ syncer::ReadNode node(&trans);
+ if (node.InitTypeRoot(syncer::BOOKMARKS) != BaseNode::INIT_OK)
+ return 0;
+ return node.GetTotalNodeCount();
+ }
+
+ // Creates the bookmark root node and the permanent nodes if they don't
+ // already exist.
+ bool CreatePermanentBookmarkNodes() {
+ bool root_exists = false;
+ syncer::ModelType type = syncer::BOOKMARKS;
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
+ syncer::ReadNode uber_root(&trans);
+ uber_root.InitByRootLookup();
+
+ syncer::ReadNode root(&trans);
+ root_exists = (root.InitTypeRoot(type) == BaseNode::INIT_OK);
+ }
+
+ if (!root_exists) {
+ if (!syncer::TestUserShare::CreateRoot(type,
+ test_user_share_.user_share()))
+ return false;
+ }
+
+ const int kNumPermanentNodes = 3;
+ const std::string permanent_tags[kNumPermanentNodes] = {
+ "bookmark_bar", "other_bookmarks", "synced_bookmarks",
+ };
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
+ syncer::ReadNode root(&trans);
+ EXPECT_EQ(BaseNode::INIT_OK, root.InitTypeRoot(type));
+
+ // Loop through creating permanent nodes as necessary.
+ int64_t last_child_id = syncer::kInvalidId;
+ for (int i = 0; i < kNumPermanentNodes; ++i) {
+ // First check if the node already exists. This is for tests that involve
+ // persistence and set up sync more than once.
+ syncer::ReadNode lookup(&trans);
+ if (lookup.InitByTagLookupForBookmarks(permanent_tags[i]) ==
+ syncer::ReadNode::INIT_OK) {
+ last_child_id = lookup.GetId();
+ continue;
+ }
+
+ // If it doesn't exist, create the permanent node at the end of the
+ // ordering.
+ syncer::ReadNode predecessor_node(&trans);
+ syncer::ReadNode* predecessor = NULL;
+ if (last_child_id != syncer::kInvalidId) {
+ EXPECT_EQ(BaseNode::INIT_OK,
+ predecessor_node.InitByIdLookup(last_child_id));
+ predecessor = &predecessor_node;
+ }
+ syncer::WriteNode node(&trans);
+ if (!node.InitBookmarkByCreation(root, predecessor))
+ return false;
+ node.SetIsFolder(true);
+ node.GetMutableEntryForTest()->PutUniqueServerTag(permanent_tags[i]);
+ node.SetTitle(permanent_tags[i]);
+ node.SetExternalId(0);
+ last_child_id = node.GetId();
+ }
+ return true;
+ }
+
+ bool AssociateModels() {
+ DCHECK(!model_associator_);
+
+ // Set up model associator.
+ model_associator_.reset(new BookmarkModelAssociator(
+ model_.get(), sync_client_.get(), test_user_share_.user_share(),
+ base::MakeUnique<syncer::DataTypeErrorHandlerMock>(),
+ kExpectMobileBookmarks));
+
+ local_merge_result_ = syncer::SyncMergeResult(syncer::BOOKMARKS);
+ syncer_merge_result_ = syncer::SyncMergeResult(syncer::BOOKMARKS);
+ int local_count_before = model_->root_node()->GetTotalNodeCount();
+ int syncer_count_before = GetSyncBookmarkCount();
+
+ syncer::SyncError error = model_associator_->AssociateModels(
+ &local_merge_result_, &syncer_merge_result_);
+ if (error.IsSet())
+ return false;
+
+ base::RunLoop().RunUntilIdle();
+
+ // Verify the merge results were calculated properly.
+ EXPECT_EQ(local_count_before,
+ local_merge_result_.num_items_before_association());
+ EXPECT_EQ(syncer_count_before,
+ syncer_merge_result_.num_items_before_association());
+ EXPECT_EQ(local_merge_result_.num_items_after_association(),
+ local_merge_result_.num_items_before_association() +
+ local_merge_result_.num_items_added() -
+ local_merge_result_.num_items_deleted());
+ EXPECT_EQ(syncer_merge_result_.num_items_after_association(),
+ syncer_merge_result_.num_items_before_association() +
+ syncer_merge_result_.num_items_added() -
+ syncer_merge_result_.num_items_deleted());
+ EXPECT_EQ(model_->root_node()->GetTotalNodeCount(),
+ local_merge_result_.num_items_after_association());
+ EXPECT_EQ(GetSyncBookmarkCount(),
+ syncer_merge_result_.num_items_after_association());
+ return true;
+ }
+
+ void StartSync() {
+ test_user_share_.Reload();
+
+ ASSERT_TRUE(CreatePermanentBookmarkNodes());
+ ASSERT_TRUE(AssociateModels());
+
+ // Set up change processor.
+ ResetChangeProcessor();
+ change_processor_->Start(test_user_share_.user_share());
+ }
+
+ void StopSync() {
+ change_processor_.reset();
+ if (model_associator_) {
+ syncer::SyncError error = model_associator_->DisassociateModels();
+ EXPECT_FALSE(error.IsSet());
+ }
+ model_associator_.reset();
+
+ base::RunLoop().RunUntilIdle();
+
+ // TODO(akalin): Actually close the database and flush it to disk
+ // (and make StartSync reload from disk). This would require
+ // refactoring TestUserShare.
+ }
+
+ bool InitSyncNodeFromChromeNode(const BookmarkNode* bnode,
+ BaseNode* sync_node) {
+ return model_associator_->InitSyncNodeFromChromeId(bnode->id(), sync_node);
+ }
+
+ void ExpectSyncerNodeMatching(syncer::BaseTransaction* trans,
+ const BookmarkNode* bnode) {
+ std::string truncated_title = base::UTF16ToUTF8(bnode->GetTitle());
+ syncer::SyncAPINameToServerName(truncated_title, &truncated_title);
+ base::TruncateUTF8ToByteSize(truncated_title, 255, &truncated_title);
+ syncer::ServerNameToSyncAPIName(truncated_title, &truncated_title);
+
+ syncer::ReadNode gnode(trans);
+ ASSERT_TRUE(InitSyncNodeFromChromeNode(bnode, &gnode));
+ // Non-root node titles and parents must match.
+ if (!model_->is_permanent_node(bnode)) {
+ EXPECT_EQ(truncated_title, gnode.GetTitle());
+ EXPECT_EQ(model_associator_->GetChromeNodeFromSyncId(gnode.GetParentId()),
+ bnode->parent());
+ }
+ EXPECT_EQ(bnode->is_folder(), gnode.GetIsFolder());
+ if (bnode->is_url())
+ EXPECT_EQ(bnode->url(), GURL(gnode.GetBookmarkSpecifics().url()));
+
+ // Check that meta info matches.
+ const BookmarkNode::MetaInfoMap* meta_info_map = bnode->GetMetaInfoMap();
+ sync_pb::BookmarkSpecifics specifics = gnode.GetBookmarkSpecifics();
+ if (!meta_info_map) {
+ EXPECT_EQ(0, specifics.meta_info_size());
+ } else {
+ EXPECT_EQ(meta_info_map->size(),
+ static_cast<size_t>(specifics.meta_info_size()));
+ for (int i = 0; i < specifics.meta_info_size(); i++) {
+ BookmarkNode::MetaInfoMap::const_iterator it =
+ meta_info_map->find(specifics.meta_info(i).key());
+ EXPECT_TRUE(it != meta_info_map->end());
+ EXPECT_EQ(it->second, specifics.meta_info(i).value());
+ }
+ }
+
+ // Check for position matches.
+ int browser_index = bnode->parent()->GetIndexOf(bnode);
+ if (browser_index == 0) {
+ EXPECT_EQ(gnode.GetPredecessorId(), 0);
+ } else {
+ const BookmarkNode* bprev = bnode->parent()->GetChild(browser_index - 1);
+ syncer::ReadNode gprev(trans);
+ ASSERT_TRUE(InitSyncNodeFromChromeNode(bprev, &gprev));
+ EXPECT_EQ(gnode.GetPredecessorId(), gprev.GetId());
+ EXPECT_EQ(gnode.GetParentId(), gprev.GetParentId());
+ }
+ // Note: the managed node is the last child of the root_node but isn't
+ // synced; if CanSyncNode() is false then there is no next node to sync.
+ const BookmarkNode* bnext = NULL;
+ if (browser_index + 1 < bnode->parent()->child_count())
+ bnext = bnode->parent()->GetChild(browser_index + 1);
+ if (!bnext || !CanSyncNode(bnext)) {
+ EXPECT_EQ(gnode.GetSuccessorId(), 0);
+ } else {
+ syncer::ReadNode gnext(trans);
+ ASSERT_TRUE(InitSyncNodeFromChromeNode(bnext, &gnext));
+ EXPECT_EQ(gnode.GetSuccessorId(), gnext.GetId());
+ EXPECT_EQ(gnode.GetParentId(), gnext.GetParentId());
+ }
+ if (!bnode->empty())
+ EXPECT_TRUE(gnode.GetFirstChildId());
+ }
+
+ void ExpectSyncerNodeMatching(const BookmarkNode* bnode) {
+ syncer::ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
+ ExpectSyncerNodeMatching(&trans, bnode);
+ }
+
+ void ExpectBrowserNodeMatching(syncer::BaseTransaction* trans,
+ int64_t sync_id) {
+ EXPECT_TRUE(sync_id);
+ const BookmarkNode* bnode =
+ model_associator_->GetChromeNodeFromSyncId(sync_id);
+ ASSERT_TRUE(bnode);
+ ASSERT_TRUE(CanSyncNode(bnode));
+
+ int64_t id = model_associator_->GetSyncIdFromChromeId(bnode->id());
+ EXPECT_EQ(id, sync_id);
+ ExpectSyncerNodeMatching(trans, bnode);
+ }
+
+ void ExpectBrowserNodeUnknown(int64_t sync_id) {
+ EXPECT_FALSE(model_associator_->GetChromeNodeFromSyncId(sync_id));
+ }
+
+ void ExpectBrowserNodeKnown(int64_t sync_id) {
+ EXPECT_TRUE(model_associator_->GetChromeNodeFromSyncId(sync_id));
+ }
+
+ void ExpectSyncerNodeKnown(const BookmarkNode* node) {
+ int64_t sync_id = model_associator_->GetSyncIdFromChromeId(node->id());
+ EXPECT_NE(sync_id, syncer::kInvalidId);
+ }
+
+ void ExpectSyncerNodeUnknown(const BookmarkNode* node) {
+ int64_t sync_id = model_associator_->GetSyncIdFromChromeId(node->id());
+ EXPECT_EQ(sync_id, syncer::kInvalidId);
+ }
+
+ void ExpectBrowserNodeTitle(int64_t sync_id, const std::string& title) {
+ const BookmarkNode* bnode =
+ model_associator_->GetChromeNodeFromSyncId(sync_id);
+ ASSERT_TRUE(bnode);
+ EXPECT_EQ(bnode->GetTitle(), base::UTF8ToUTF16(title));
+ }
+
+ void ExpectBrowserNodeURL(int64_t sync_id, const std::string& url) {
+ const BookmarkNode* bnode =
+ model_associator_->GetChromeNodeFromSyncId(sync_id);
+ ASSERT_TRUE(bnode);
+ EXPECT_EQ(GURL(url), bnode->url());
+ }
+
+ void ExpectBrowserNodeParent(int64_t sync_id, int64_t parent_sync_id) {
+ const BookmarkNode* node =
+ model_associator_->GetChromeNodeFromSyncId(sync_id);
+ ASSERT_TRUE(node);
+ const BookmarkNode* parent =
+ model_associator_->GetChromeNodeFromSyncId(parent_sync_id);
+ EXPECT_TRUE(parent);
+ EXPECT_EQ(node->parent(), parent);
+ }
+
+ void ExpectModelMatch(syncer::BaseTransaction* trans) {
+ const BookmarkNode* root = model_->root_node();
+ EXPECT_EQ(root->GetIndexOf(model_->bookmark_bar_node()), 0);
+ EXPECT_EQ(root->GetIndexOf(model_->other_node()), 1);
+ EXPECT_EQ(root->GetIndexOf(model_->mobile_node()), 2);
+
+ std::stack<int64_t> stack;
+ stack.push(bookmark_bar_id());
+ while (!stack.empty()) {
+ int64_t id = stack.top();
+ stack.pop();
+ if (!id)
+ continue;
+
+ ExpectBrowserNodeMatching(trans, id);
+
+ syncer::ReadNode gnode(trans);
+ ASSERT_EQ(BaseNode::INIT_OK, gnode.InitByIdLookup(id));
+ stack.push(gnode.GetSuccessorId());
+ if (gnode.GetIsFolder())
+ stack.push(gnode.GetFirstChildId());
+ }
+ }
+
+ void ExpectModelMatch() {
+ syncer::ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
+ ExpectModelMatch(&trans);
+ }
+
+ int64_t mobile_bookmarks_id() {
+ return model_associator_->GetSyncIdFromChromeId(
+ model_->mobile_node()->id());
+ }
+
+ int64_t other_bookmarks_id() {
+ return model_associator_->GetSyncIdFromChromeId(model_->other_node()->id());
+ }
+
+ int64_t bookmark_bar_id() {
+ return model_associator_->GetSyncIdFromChromeId(
+ model_->bookmark_bar_node()->id());
+ }
+
+ BookmarkModel* model() { return model_.get(); }
+
+ syncer::TestUserShare* test_user_share() { return &test_user_share_; }
+
+ BookmarkChangeProcessor* change_processor() {
+ return change_processor_.get();
+ }
+
+ void delete_change_processor() { change_processor_.reset(); }
+
+ void ResetChangeProcessor() {
+ std::unique_ptr<syncer::DataTypeErrorHandlerMock> error_handler =
+ base::MakeUnique<syncer::DataTypeErrorHandlerMock>();
+ mock_error_handler_ = error_handler.get();
+ change_processor_ = base::MakeUnique<BookmarkChangeProcessor>(
+ sync_client_.get(), model_associator_.get(), std::move(error_handler));
+ }
+
+ syncer::DataTypeErrorHandlerMock* mock_error_handler() {
+ return mock_error_handler_;
+ }
+
+ void delete_model_associator() { model_associator_.reset(); }
+
+ BookmarkModelAssociator* model_associator() {
+ return model_associator_.get();
+ }
+
+ bookmarks::ManagedBookmarkService* managed_bookmark_service() {
+ return managed_bookmark_service_.get();
+ }
+
+ private:
+ base::TestMessageLoop message_loop_;
+ base::ScopedTempDir data_dir_;
+ ProfileSyncServiceBundle profile_sync_service_bundle_;
+
+ std::unique_ptr<syncer::FakeSyncClient> sync_client_;
+ std::unique_ptr<BookmarkModel> model_;
+ syncer::TestUserShare test_user_share_;
+ std::unique_ptr<BookmarkChangeProcessor> change_processor_;
+ syncer::DataTypeErrorHandlerMock* mock_error_handler_;
+ std::unique_ptr<BookmarkModelAssociator> model_associator_;
+ std::unique_ptr<bookmarks::ManagedBookmarkService> managed_bookmark_service_;
+
+ syncer::SyncMergeResult local_merge_result_;
+ syncer::SyncMergeResult syncer_merge_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceBookmarkTest);
+};
+
+TEST_F(ProfileSyncServiceBookmarkTest, InitialState) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ EXPECT_TRUE(other_bookmarks_id());
+ EXPECT_TRUE(bookmark_bar_id());
+ EXPECT_TRUE(mobile_bookmarks_id());
+
+ ExpectModelMatch();
+}
+
+// Populate the sync database then start model association. Sync's bookmarks
+// should end up being copied into the native model, resulting in a successful
+// "ExpectModelMatch()".
+//
+// This code has some use for verifying correctness. It's also a very useful
+// for profiling bookmark ModelAssociation, an important part of some first-time
+// sync scenarios. Simply increase the kNumFolders and kNumBookmarksPerFolder
+// as desired, then run the test under a profiler to find hot spots in the model
+// association code.
+TEST_F(ProfileSyncServiceBookmarkTest, InitialModelAssociate) {
+ const int kNumBookmarksPerFolder = 10;
+ const int kNumFolders = 10;
+
+ CreatePermanentBookmarkNodes();
+
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ for (int i = 0; i < kNumFolders; ++i) {
+ int64_t folder_id =
+ AddFolderToShare(&trans, base::StringPrintf("folder%05d", i));
+ for (int j = 0; j < kNumBookmarksPerFolder; ++j) {
+ AddBookmarkToShare(
+ &trans, folder_id, base::StringPrintf("bookmark%05d", j),
+ base::StringPrintf("http://www.google.com/search?q=%05d", j));
+ }
+ }
+ }
+
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ ExpectModelMatch();
+}
+
+// Tests bookmark association when nodes exists in the native model only.
+// These entries should be copied to Sync directory during association process.
+TEST_F(ProfileSyncServiceBookmarkTest,
+ InitialModelAssociateWithBookmarkModelNodes) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ const BookmarkNode* folder = model()->AddFolder(model()->other_node(), 0,
+ base::ASCIIToUTF16("foobar"));
+ model()->AddFolder(folder, 0, base::ASCIIToUTF16("nested"));
+ model()->AddURL(folder, 0, base::ASCIIToUTF16("Internets #1 Pies Site"),
+ GURL("http://www.easypie.com/"));
+ model()->AddURL(folder, 1, base::ASCIIToUTF16("Airplanes"),
+ GURL("http://www.easyjet.com/"));
+
+ StartSync();
+ ExpectModelMatch();
+}
+
+// Tests bookmark association case when there is an entry in the delete journal
+// that matches one of native bookmarks.
+TEST_F(ProfileSyncServiceBookmarkTest, InitialModelAssociateWithDeleteJournal) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ const BookmarkNode* folder = model()->AddFolder(
+ model()->bookmark_bar_node(), 0, base::ASCIIToUTF16("foobar"));
+ const BookmarkNode* bookmark =
+ model()->AddURL(folder, 0, base::ASCIIToUTF16("Airplanes"),
+ GURL("http://www.easyjet.com/"));
+
+ CreatePermanentBookmarkNodes();
+
+ // Create entries matching the folder and the bookmark above.
+ int64_t folder_id, bookmark_id;
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ folder_id = AddFolderToShare(&trans, "foobar");
+ bookmark_id = AddBookmarkToShare(&trans, folder_id, "Airplanes",
+ "http://www.easyjet.com/");
+ }
+
+ // Associate the bookmark sync node with the native model one and make
+ // it look like it was deleted by a server update.
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ syncer::WriteNode node(&trans);
+ EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(bookmark_id));
+
+ node.GetMutableEntryForTest()->PutLocalExternalId(bookmark->id());
+
+ MakeServerUpdate(&trans, &node);
+ node.GetMutableEntryForTest()->PutServerIsDel(true);
+ node.GetMutableEntryForTest()->PutIsDel(true);
+ }
+
+ ASSERT_TRUE(AssociateModels());
+ ExpectModelMatch();
+
+ // The bookmark node should be deleted.
+ EXPECT_EQ(0, folder->child_count());
+}
+
+// Tests that the external ID is used to match the right folder amoung
+// multiple folders with the same name during the native model traversal.
+// Also tests that the external ID is used to match the right bookmark
+// among multiple identical bookmarks when dealing with the delete journal.
+TEST_F(ProfileSyncServiceBookmarkTest,
+ InitialModelAssociateVerifyExternalIdMatch) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ const int kNumFolders = 10;
+ const int kNumBookmarks = 10;
+ const int kFolderToIncludeBookmarks = 7;
+ const int kBookmarkToDelete = 4;
+
+ int64_t folder_ids[kNumFolders];
+ int64_t bookmark_ids[kNumBookmarks];
+
+ // Create native folders and bookmarks with identical names. Only
+ // one of the folders contains bookmarks and others are empty. Here is the
+ // expected tree shape:
+ // Bookmarks bar
+ // +- folder (#0)
+ // +- folder (#1)
+ // ...
+ // +- folder (#7) <-- Only this folder contains bookmarks.
+ // +- bookmark (#0)
+ // +- bookmark (#1)
+ // ...
+ // +- bookmark (#4) <-- Only this one bookmark should be removed later.
+ // ...
+ // +- bookmark (#9)
+ // ...
+ // +- folder (#9)
+
+ const BookmarkNode* parent_folder = nullptr;
+ for (int i = 0; i < kNumFolders; i++) {
+ const BookmarkNode* folder = model()->AddFolder(
+ model()->bookmark_bar_node(), i, base::ASCIIToUTF16("folder"));
+ folder_ids[i] = folder->id();
+ if (i == kFolderToIncludeBookmarks) {
+ parent_folder = folder;
+ }
+ }
+
+ for (int i = 0; i < kNumBookmarks; i++) {
+ const BookmarkNode* bookmark =
+ model()->AddURL(parent_folder, i, base::ASCIIToUTF16("bookmark"),
+ GURL("http://www.google.com/"));
+ bookmark_ids[i] = bookmark->id();
+ }
+
+ // Number of nodes in bookmark bar before association.
+ int total_node_count = model()->bookmark_bar_node()->GetTotalNodeCount();
+
+ CreatePermanentBookmarkNodes();
+
+ int64_t sync_bookmark_id_to_delete = 0;
+ {
+ // Create sync folders matching native folders above.
+ int64_t parent_id = 0;
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ // Create in reverse order because AddFolderToShare passes NULL for
+ // |predecessor| argument.
+ for (int i = kNumFolders - 1; i >= 0; i--) {
+ int64_t id = AddFolderToShare(&trans, "folder");
+
+ // Pre-map sync folders to native folders by setting
+ // external ID. This will verify that the association algorithm picks
+ // the right ones despite all of them having identical names.
+ // More specifically this will help to avoid cloning bookmarks from
+ // a wrong folder.
+ syncer::WriteNode node(&trans);
+ EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
+ node.GetMutableEntryForTest()->PutLocalExternalId(folder_ids[i]);
+
+ if (i == kFolderToIncludeBookmarks) {
+ parent_id = id;
+ }
+ }
+
+ // Create sync bookmark matching native bookmarks above in reverse order
+ // because AddBookmarkToShare passes NULL for |predecessor| argument.
+ for (int i = kNumBookmarks - 1; i >= 0; i--) {
+ int id = AddBookmarkToShare(&trans, parent_id, "bookmark",
+ "http://www.google.com/");
+
+ // Pre-map sync bookmarks to native bookmarks by setting
+ // external ID. This will verify that the association algorithm picks
+ // the right ones despite all of them having identical names and URLs.
+ syncer::WriteNode node(&trans);
+ EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
+ node.GetMutableEntryForTest()->PutLocalExternalId(bookmark_ids[i]);
+
+ if (i == kBookmarkToDelete) {
+ sync_bookmark_id_to_delete = id;
+ }
+ }
+ }
+
+ // Make one bookmark deleted.
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ syncer::WriteNode node(&trans);
+ EXPECT_EQ(BaseNode::INIT_OK,
+ node.InitByIdLookup(sync_bookmark_id_to_delete));
+
+ MakeServerUpdate(&trans, &node);
+ node.GetMutableEntryForTest()->PutServerIsDel(true);
+ node.GetMutableEntryForTest()->PutIsDel(true);
+ }
+
+ // Perform association.
+ ASSERT_TRUE(AssociateModels());
+ ExpectModelMatch();
+
+ // Only one native node should have been deleted and no nodes cloned due to
+ // matching folder names.
+ EXPECT_EQ(kNumFolders, model()->bookmark_bar_node()->child_count());
+ EXPECT_EQ(kNumBookmarks - 1, parent_folder->child_count());
+ EXPECT_EQ(total_node_count - 1,
+ model()->bookmark_bar_node()->GetTotalNodeCount());
+
+ // Verify that the right bookmark got deleted and no bookmarks reordered.
+ for (int i = 0; i < parent_folder->child_count(); i++) {
+ int index_in_bookmark_ids = (i < kBookmarkToDelete) ? i : i + 1;
+ EXPECT_EQ(bookmark_ids[index_in_bookmark_ids],
+ parent_folder->GetChild(i)->id());
+ }
+}
+
+// Verifies that the bookmark association skips sync nodes with invalid URLs.
+TEST_F(ProfileSyncServiceBookmarkTest, InitialModelAssociateWithInvalidUrl) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ // On the local side create a folder and two nodes.
+ const BookmarkNode* folder = model()->AddFolder(
+ model()->bookmark_bar_node(), 0, base::ASCIIToUTF16("folder"));
+ model()->AddURL(folder, 0, base::ASCIIToUTF16("node1"),
+ GURL("http://www.node1.com/"));
+ model()->AddURL(folder, 1, base::ASCIIToUTF16("node2"),
+ GURL("http://www.node2.com/"));
+
+ // On the sync side create a matching folder, one matching node, one
+ // unmatching node, and one node with an invalid URL.
+ CreatePermanentBookmarkNodes();
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ int64_t folder_id = AddFolderToShare(&trans, "folder");
+ // Please note that each AddBookmarkToShare inserts the node at the front
+ // so the actual order of children in the directory will be opposite.
+ AddBookmarkToShare(&trans, folder_id, "node2", "http://www.node2.com/");
+ AddBookmarkToShare(&trans, folder_id, "node3", "");
+ AddBookmarkToShare(&trans, folder_id, "node4", "http://www.node4.com/");
+ }
+
+ // Perform association.
+ StartSync();
+
+ // Concatenate resulting titles of native nodes.
+ std::string native_titles;
+ for (int i = 0; i < folder->child_count(); i++) {
+ if (!native_titles.empty())
+ native_titles += ",";
+ const BookmarkNode* child = folder->GetChild(i);
+ native_titles += base::UTF16ToUTF8(child->GetTitle());
+ }
+
+ // Expect the order of nodes to follow the sync order (see note above), the
+ // node with the invalid URL to be skipped, and the extra native node to be
+ // at the end.
+ EXPECT_EQ("node4,node2,node1", native_titles);
+}
+
+TEST_F(ProfileSyncServiceBookmarkTest, BookmarkModelOperations) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ // Test addition.
+ const BookmarkNode* folder = model()->AddFolder(model()->other_node(), 0,
+ base::ASCIIToUTF16("foobar"));
+ ExpectSyncerNodeMatching(folder);
+ ExpectModelMatch();
+ const BookmarkNode* folder2 =
+ model()->AddFolder(folder, 0, base::ASCIIToUTF16("nested"));
+ ExpectSyncerNodeMatching(folder2);
+ ExpectModelMatch();
+ const BookmarkNode* url1 =
+ model()->AddURL(folder, 0, base::ASCIIToUTF16("Internets #1 Pies Site"),
+ GURL("http://www.easypie.com/"));
+ ExpectSyncerNodeMatching(url1);
+ ExpectModelMatch();
+ const BookmarkNode* url2 =
+ model()->AddURL(folder, 1, base::ASCIIToUTF16("Airplanes"),
+ GURL("http://www.easyjet.com/"));
+ ExpectSyncerNodeMatching(url2);
+ ExpectModelMatch();
+ // Test addition.
+ const BookmarkNode* mobile_folder =
+ model()->AddFolder(model()->mobile_node(), 0, base::ASCIIToUTF16("pie"));
+ ExpectSyncerNodeMatching(mobile_folder);
+ ExpectModelMatch();
+
+ // Test modification.
+ model()->SetTitle(url2, base::ASCIIToUTF16("EasyJet"));
+ ExpectModelMatch();
+ model()->Move(url1, folder2, 0);
+ ExpectModelMatch();
+ model()->Move(folder2, model()->bookmark_bar_node(), 0);
+ ExpectModelMatch();
+ model()->SetTitle(folder2, base::ASCIIToUTF16("Not Nested"));
+ ExpectModelMatch();
+ model()->Move(folder, folder2, 0);
+ ExpectModelMatch();
+ model()->SetTitle(folder, base::ASCIIToUTF16("who's nested now?"));
+ ExpectModelMatch();
+ model()->Copy(url2, model()->bookmark_bar_node(), 0);
+ ExpectModelMatch();
+ model()->SetTitle(mobile_folder, base::ASCIIToUTF16("strawberry"));
+ ExpectModelMatch();
+
+ // Test deletion.
+ // Delete a single item.
+ model()->Remove(url2);
+ ExpectModelMatch();
+ // Delete an item with several children.
+ model()->Remove(folder2);
+ ExpectModelMatch();
+ model()->Remove(model()->mobile_node()->GetChild(0));
+ ExpectModelMatch();
+}
+
+TEST_F(ProfileSyncServiceBookmarkTest, ServerChangeProcessing) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+
+ FakeServerChange adds(&trans);
+ int64_t f1 = adds.AddFolder("Server Folder B", bookmark_bar_id(), 0);
+ int64_t f2 = adds.AddFolder("Server Folder A", bookmark_bar_id(), f1);
+ int64_t u1 = adds.AddURL("Some old site", "ftp://nifty.andrew.cmu.edu/",
+ bookmark_bar_id(), f2);
+ int64_t u2 = adds.AddURL("Nifty", "ftp://nifty.andrew.cmu.edu/", f1, 0);
+ // u3 is a duplicate URL
+ int64_t u3 = adds.AddURL("Nifty2", "ftp://nifty.andrew.cmu.edu/", f1, u2);
+ // u4 is a duplicate title, different URL.
+ adds.AddURL("Some old site", "http://slog.thestranger.com/",
+ bookmark_bar_id(), u1);
+ // u5 tests an empty-string title.
+ std::string javascript_url(
+ "javascript:(function(){var w=window.open("
+ "'about:blank','gnotesWin','location=0,menubar=0,"
+ "scrollbars=0,status=0,toolbar=0,width=300,"
+ "height=300,resizable');});");
+ adds.AddURL(std::string(), javascript_url, other_bookmarks_id(), 0);
+ int64_t u6 = adds.AddURL("Sync1", "http://www.syncable.edu/",
+ mobile_bookmarks_id(), 0);
+
+ syncer::ChangeRecordList::const_iterator it;
+ // The bookmark model shouldn't yet have seen any of the nodes of |adds|.
+ for (it = adds.changes().begin(); it != adds.changes().end(); ++it)
+ ExpectBrowserNodeUnknown(it->id);
+
+ adds.ApplyPendingChanges(change_processor());
+
+ // Make sure the bookmark model received all of the nodes in |adds|.
+ for (it = adds.changes().begin(); it != adds.changes().end(); ++it)
+ ExpectBrowserNodeMatching(&trans, it->id);
+ ExpectModelMatch(&trans);
+
+ // Part two: test modifications.
+ FakeServerChange mods(&trans);
+ // Mess with u2, and move it into empty folder f2
+ // TODO(ncarter): Determine if we allow ModifyURL ops or not.
+ /* std::string u2_old_url = mods.ModifyURL(u2, "http://www.google.com"); */
+ std::string u2_old_title = mods.ModifyTitle(u2, "The Google");
+ int64_t u2_old_parent = mods.ModifyPosition(u2, f2, 0);
+
+ // Now move f1 after u2.
+ std::string f1_old_title = mods.ModifyTitle(f1, "Server Folder C");
+ int64_t f1_old_parent = mods.ModifyPosition(f1, f2, u2);
+
+ // Then add u3 after f1.
+ int64_t u3_old_parent = mods.ModifyPosition(u3, f2, f1);
+
+ std::string u6_old_title = mods.ModifyTitle(u6, "Mobile Folder A");
+
+ // Test that the property changes have not yet taken effect.
+ ExpectBrowserNodeTitle(u2, u2_old_title);
+ /* ExpectBrowserNodeURL(u2, u2_old_url); */
+ ExpectBrowserNodeParent(u2, u2_old_parent);
+
+ ExpectBrowserNodeTitle(f1, f1_old_title);
+ ExpectBrowserNodeParent(f1, f1_old_parent);
+
+ ExpectBrowserNodeParent(u3, u3_old_parent);
+
+ ExpectBrowserNodeTitle(u6, u6_old_title);
+
+ // Apply the changes.
+ mods.ApplyPendingChanges(change_processor());
+
+ // Check for successful application.
+ for (it = mods.changes().begin(); it != mods.changes().end(); ++it)
+ ExpectBrowserNodeMatching(&trans, it->id);
+ ExpectModelMatch(&trans);
+
+ // Part 3: Test URL deletion.
+ FakeServerChange dels(&trans);
+ dels.Delete(u2);
+ dels.Delete(u3);
+ dels.Delete(u6);
+
+ ExpectBrowserNodeKnown(u2);
+ ExpectBrowserNodeKnown(u3);
+
+ dels.ApplyPendingChanges(change_processor());
+
+ ExpectBrowserNodeUnknown(u2);
+ ExpectBrowserNodeUnknown(u3);
+ ExpectBrowserNodeUnknown(u6);
+ ExpectModelMatch(&trans);
+}
+
+// Tests a specific case in ApplyModelChanges where we move the
+// children out from under a parent, and then delete the parent
+// in the same changelist. The delete shows up first in the changelist,
+// requiring the children to be moved to a temporary location.
+TEST_F(ProfileSyncServiceBookmarkTest, ServerChangeRequiringFosterParent) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+
+ // Stress the immediate children of other_node because that's where
+ // ApplyModelChanges puts a temporary foster parent node.
+ std::string url("http://dev.chromium.org/");
+ FakeServerChange adds(&trans);
+ int64_t f0 = other_bookmarks_id(); // + other_node
+ int64_t f1 = adds.AddFolder("f1", f0, 0); // + f1
+ int64_t f2 = adds.AddFolder("f2", f1, 0); // + f2
+ int64_t u3 = adds.AddURL("u3", url, f2, 0); // + u3 NOLINT
+ int64_t u4 = adds.AddURL("u4", url, f2, u3); // + u4 NOLINT
+ int64_t u5 = adds.AddURL("u5", url, f1, f2); // + u5 NOLINT
+ int64_t f6 = adds.AddFolder("f6", f1, u5); // + f6
+ int64_t u7 = adds.AddURL("u7", url, f0, f1); // + u7 NOLINT
+
+ syncer::ChangeRecordList::const_iterator it;
+ // The bookmark model shouldn't yet have seen any of the nodes of |adds|.
+ for (it = adds.changes().begin(); it != adds.changes().end(); ++it)
+ ExpectBrowserNodeUnknown(it->id);
+
+ adds.ApplyPendingChanges(change_processor());
+
+ // Make sure the bookmark model received all of the nodes in |adds|.
+ for (it = adds.changes().begin(); it != adds.changes().end(); ++it)
+ ExpectBrowserNodeMatching(&trans, it->id);
+ ExpectModelMatch(&trans);
+
+ // We have to do the moves before the deletions, but FakeServerChange will
+ // put the deletion at the front of the changelist.
+ FakeServerChange ops(&trans);
+ ops.ModifyPosition(f6, other_bookmarks_id(), 0);
+ ops.ModifyPosition(u3, other_bookmarks_id(), f1); // Prev == f1 is OK here.
+ ops.ModifyPosition(f2, other_bookmarks_id(), u7);
+ ops.ModifyPosition(u7, f2, 0);
+ ops.ModifyPosition(u4, other_bookmarks_id(), f2);
+ ops.ModifyPosition(u5, f6, 0);
+ ops.Delete(f1);
+
+ ops.ApplyPendingChanges(change_processor());
+
+ ExpectModelMatch(&trans);
+}
+
+// Simulate a server change record containing a valid but non-canonical URL.
+TEST_F(ProfileSyncServiceBookmarkTest, ServerChangeWithNonCanonicalURL) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+
+ FakeServerChange adds(&trans);
+ std::string url("http://dev.chromium.org");
+ EXPECT_NE(GURL(url).spec(), url);
+ adds.AddURL("u1", url, other_bookmarks_id(), 0);
+
+ adds.ApplyPendingChanges(change_processor());
+
+ EXPECT_EQ(1, model()->other_node()->child_count());
+ ExpectModelMatch(&trans);
+ }
+
+ // Now reboot the sync service, forcing a merge step.
+ StopSync();
+ LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+
+ // There should still be just the one bookmark.
+ EXPECT_EQ(1, model()->other_node()->child_count());
+ ExpectModelMatch();
+}
+
+// Simulate a server change record containing an invalid URL (per GURL).
+// TODO(ncarter): Disabled due to crashes. Fix bug 1677563.
+TEST_F(ProfileSyncServiceBookmarkTest, DISABLED_ServerChangeWithInvalidURL) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+
+ int child_count = 0;
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+
+ FakeServerChange adds(&trans);
+ std::string url("x");
+ EXPECT_FALSE(GURL(url).is_valid());
+ adds.AddURL("u1", url, other_bookmarks_id(), 0);
+
+ adds.ApplyPendingChanges(change_processor());
+
+ // We're lenient about what should happen -- the model could wind up with
+ // the node or without it; but things should be consistent, and we
+ // shouldn't crash.
+ child_count = model()->other_node()->child_count();
+ EXPECT_TRUE(child_count == 0 || child_count == 1);
+ ExpectModelMatch(&trans);
+ }
+
+ // Now reboot the sync service, forcing a merge step.
+ StopSync();
+ LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+
+ // Things ought not to have changed.
+ EXPECT_EQ(model()->other_node()->child_count(), child_count);
+ ExpectModelMatch();
+}
+
+// Test strings that might pose a problem if the titles ever became used as
+// file names in the sync backend.
+TEST_F(ProfileSyncServiceBookmarkTest, CornerCaseNames) {
+ // TODO(ncarter): Bug 1570238 explains the failure of this test.
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+
+ const char* names[] = {
+ // The empty string.
+ "",
+ // Illegal Windows filenames.
+ "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5",
+ "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5",
+ "LPT6", "LPT7", "LPT8", "LPT9",
+ // Current/parent directory markers.
+ ".", "..", "...",
+ // Files created automatically by the Windows shell.
+ "Thumbs.db", ".DS_Store",
+ // Names including Win32-illegal characters, and path separators.
+ "foo/bar", "foo\\bar", "foo?bar", "foo:bar", "foo|bar", "foo\"bar",
+ "foo'bar", "foo<bar", "foo>bar", "foo%bar", "foo*bar", "foo]bar",
+ "foo[bar",
+ // A name with title > 255 characters
+ "012345678901234567890123456789012345678901234567890123456789012345678901"
+ "234567890123456789012345678901234567890123456789012345678901234567890123"
+ "456789012345678901234567890123456789012345678901234567890123456789012345"
+ "678901234567890123456789012345678901234567890123456789012345678901234567"
+ "890123456789"};
+ // Create both folders and bookmarks using each name.
+ GURL url("http://www.doublemint.com");
+ for (size_t i = 0; i < arraysize(names); ++i) {
+ model()->AddFolder(model()->other_node(), 0, base::ASCIIToUTF16(names[i]));
+ model()->AddURL(model()->other_node(), 0, base::ASCIIToUTF16(names[i]),
+ url);
+ }
+
+ // Verify that the browser model matches the sync model.
+ EXPECT_EQ(static_cast<size_t>(model()->other_node()->child_count()),
+ 2 * arraysize(names));
+ ExpectModelMatch();
+
+ // Restart and re-associate. Verify things still match.
+ StopSync();
+ LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+ EXPECT_EQ(static_cast<size_t>(model()->other_node()->child_count()),
+ 2 * arraysize(names));
+ ExpectModelMatch();
+}
+
+// Stress the internal representation of position by sparse numbers. We want
+// to repeatedly bisect the range of available positions, to force the
+// syncer code to renumber its ranges. Pick a number big enough so that it
+// would exhaust 32bits of room between items a couple of times.
+TEST_F(ProfileSyncServiceBookmarkTest, RepeatedMiddleInsertion) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ static const int kTimesToInsert = 256;
+
+ // Create two book-end nodes to insert between.
+ model()->AddFolder(model()->other_node(), 0, base::ASCIIToUTF16("Alpha"));
+ model()->AddFolder(model()->other_node(), 1, base::ASCIIToUTF16("Omega"));
+ int count = 2;
+
+ // Test insertion in first half of range by repeatedly inserting in second
+ // position.
+ for (int i = 0; i < kTimesToInsert; ++i) {
+ base::string16 title =
+ base::ASCIIToUTF16("Pre-insertion ") + base::IntToString16(i);
+ model()->AddFolder(model()->other_node(), 1, title);
+ count++;
+ }
+
+ // Test insertion in second half of range by repeatedly inserting in
+ // second-to-last position.
+ for (int i = 0; i < kTimesToInsert; ++i) {
+ base::string16 title =
+ base::ASCIIToUTF16("Post-insertion ") + base::IntToString16(i);
+ model()->AddFolder(model()->other_node(), count - 1, title);
+ count++;
+ }
+
+ // Verify that the browser model matches the sync model.
+ EXPECT_EQ(model()->other_node()->child_count(), count);
+ ExpectModelMatch();
+}
+
+// Introduce a consistency violation into the model, and see that it
+// puts itself into a lame, error state.
+TEST_F(ProfileSyncServiceBookmarkTest, UnrecoverableErrorSuspendsService) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ // Add a node which will be the target of the consistency violation.
+ const BookmarkNode* node =
+ model()->AddFolder(model()->other_node(), 0, base::ASCIIToUTF16("node"));
+ ExpectSyncerNodeMatching(node);
+
+ // Now destroy the syncer node as if we were the ProfileSyncService without
+ // updating the ProfileSyncService state. This should introduce
+ // inconsistency between the two models.
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ syncer::WriteNode sync_node(&trans);
+ ASSERT_TRUE(InitSyncNodeFromChromeNode(node, &sync_node));
+ sync_node.Tombstone();
+ }
+ // The models don't match at this point, but the ProfileSyncService
+ // doesn't know it yet.
+ ExpectSyncerNodeKnown(node);
+
+ mock_error_handler()->ExpectError(syncer::SyncError::DATATYPE_ERROR);
+
+ // Add a child to the inconsistent node. This should cause detection of the
+ // problem and the syncer should stop processing changes.
+ model()->AddFolder(node, 0, base::ASCIIToUTF16("nested"));
+}
+
+// See what happens if we run model association when there are two exact URL
+// duplicate bookmarks. The BookmarkModelAssociator should not fall over when
+// this happens.
+TEST_F(ProfileSyncServiceBookmarkTest, MergeDuplicates) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+
+ model()->AddURL(model()->other_node(), 0, base::ASCIIToUTF16("Dup"),
+ GURL("http://dup.com/"));
+ model()->AddURL(model()->other_node(), 0, base::ASCIIToUTF16("Dup"),
+ GURL("http://dup.com/"));
+
+ EXPECT_EQ(2, model()->other_node()->child_count());
+
+ // Restart the sync service to trigger model association.
+ StopSync();
+ StartSync();
+
+ EXPECT_EQ(2, model()->other_node()->child_count());
+ ExpectModelMatch();
+}
+
+TEST_F(ProfileSyncServiceBookmarkTest, ApplySyncDeletesFromJournal) {
+ // Initialize sync model and bookmark model as:
+ // URL 0
+ // Folder 1
+ // |-- URL 1
+ // +-- Folder 2
+ // +-- URL 2
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
+ int64_t u0 = 0;
+ int64_t f1 = 0;
+ int64_t u1 = 0;
+ int64_t f2 = 0;
+ int64_t u2 = 0;
+ StartSync();
+ int fixed_sync_bk_count = GetSyncBookmarkCount();
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ FakeServerChange adds(&trans);
+ u0 = adds.AddURL("URL 0", "http://plus.google.com/", bookmark_bar_id(), 0);
+ f1 = adds.AddFolder("Folder 1", bookmark_bar_id(), u0);
+ u1 = adds.AddURL("URL 1", "http://www.google.com/", f1, 0);
+ f2 = adds.AddFolder("Folder 2", f1, u1);
+ u2 = adds.AddURL("URL 2", "http://mail.google.com/", f2, 0);
+ adds.ApplyPendingChanges(change_processor());
+ }
+ StopSync();
+
+ // Reload bookmark model and disable model saving to make sync changes not
+ // persisted.
+ LoadBookmarkModel(LOAD_FROM_STORAGE, DONT_SAVE_TO_STORAGE);
+ EXPECT_EQ(6, model()->bookmark_bar_node()->GetTotalNodeCount());
+ EXPECT_EQ(fixed_sync_bk_count + 5, GetSyncBookmarkCount());
+ StartSync();
+ {
+ // Remove all folders/bookmarks except u3 added above.
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ MakeServerUpdate(&trans, f1);
+ MakeServerUpdate(&trans, u1);
+ MakeServerUpdate(&trans, f2);
+ MakeServerUpdate(&trans, u2);
+ FakeServerChange dels(&trans);
+ dels.Delete(u2);
+ dels.Delete(f2);
+ dels.Delete(u1);
+ dels.Delete(f1);
+ dels.ApplyPendingChanges(change_processor());
+ }
+ StopSync();
+ // Bookmark bar itself and u0 remain.
+ EXPECT_EQ(2, model()->bookmark_bar_node()->GetTotalNodeCount());
+
+ // Reload bookmarks including ones deleted in sync model from storage.
+ LoadBookmarkModel(LOAD_FROM_STORAGE, DONT_SAVE_TO_STORAGE);
+ EXPECT_EQ(6, model()->bookmark_bar_node()->GetTotalNodeCount());
+ // Add a bookmark under f1 when sync is off so that f1 will not be
+ // deleted even when f1 matches delete journal because it's not empty.
+ model()->AddURL(model()->bookmark_bar_node()->GetChild(1), 0,
+ base::UTF8ToUTF16("local"), GURL("http://www.youtube.com"));
+ // Sync model has fixed bookmarks nodes and u3.
+ EXPECT_EQ(fixed_sync_bk_count + 1, GetSyncBookmarkCount());
+ StartSync();
+ // Expect 4 bookmarks after model association because u2, f2, u1 are removed
+ // by delete journal, f1 is not removed by delete journal because it's
+ // not empty due to www.youtube.com added above.
+ EXPECT_EQ(4, model()->bookmark_bar_node()->GetTotalNodeCount());
+ EXPECT_EQ(base::UTF8ToUTF16("URL 0"),
+ model()->bookmark_bar_node()->GetChild(0)->GetTitle());
+ EXPECT_EQ(base::UTF8ToUTF16("Folder 1"),
+ model()->bookmark_bar_node()->GetChild(1)->GetTitle());
+ EXPECT_EQ(base::UTF8ToUTF16("local"),
+ model()->bookmark_bar_node()->GetChild(1)->GetChild(0)->GetTitle());
+ StopSync();
+
+ // Verify purging of delete journals.
+ // Delete journals for u2, f2, u1 remains because they are used in last
+ // association.
+ EXPECT_EQ(3u, test_user_share()->GetDeleteJournalSize());
+ StartSync();
+ StopSync();
+ // Reload again and all delete journals should be gone because none is used
+ // in last association.
+ ASSERT_TRUE(test_user_share()->Reload());
+ EXPECT_EQ(0u, test_user_share()->GetDeleteJournalSize());
+}
+
+struct TestData {
+ const char* title;
+ const char* url;
+};
+
+// Map from bookmark node ID to its version.
+typedef std::map<int64_t, int64_t> BookmarkNodeVersionMap;
+
+// TODO(ncarter): Integrate the existing TestNode/PopulateNodeFromString code
+// in the bookmark model unittest, to make it simpler to set up test data
+// here (and reduce the amount of duplication among tests), and to reduce the
+// duplication.
+class ProfileSyncServiceBookmarkTestWithData
+ : public ProfileSyncServiceBookmarkTest {
+ public:
+ ProfileSyncServiceBookmarkTestWithData();
+
+ protected:
+ // Populates or compares children of the given bookmark node from/with the
+ // given test data array with the given size. |running_count| is updated as
+ // urls are added. It is used to set the creation date (or test the creation
+ // date for CompareWithTestData()).
+ void PopulateFromTestData(const BookmarkNode* node,
+ const TestData* data,
+ int size,
+ int* running_count);
+ void CompareWithTestData(const BookmarkNode* node,
+ const TestData* data,
+ int size,
+ int* running_count);
+
+ void ExpectBookmarkModelMatchesTestData();
+ void WriteTestDataToBookmarkModel();
+
+ // Output transaction versions of |node| and nodes under it to
+ // |node_versions|.
+ void GetTransactionVersions(const BookmarkNode* root,
+ BookmarkNodeVersionMap* node_versions);
+
+ // Verify transaction versions of bookmark nodes and sync nodes are equal
+ // recursively. If node is in |version_expected|, versions should match
+ // there, too.
+ void ExpectTransactionVersionMatch(
+ const BookmarkNode* node,
+ const BookmarkNodeVersionMap& version_expected);
+
+ private:
+ const base::Time start_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceBookmarkTestWithData);
+};
+
+namespace {
+
+// Constants for bookmark model that looks like:
+// |-- Bookmark bar
+// | |-- u2, http://www.u2.com/
+// | |-- f1
+// | | |-- f1u4, http://www.f1u4.com/
+// | | |-- f1u2, http://www.f1u2.com/
+// | | |-- f1u3, http://www.f1u3.com/
+// | | +-- f1u1, http://www.f1u1.com/
+// | |-- u1, http://www.u1.com/
+// | +-- f2
+// | |-- f2u2, http://www.f2u2.com/
+// | |-- f2u4, http://www.f2u4.com/
+// | |-- f2u3, http://www.f2u3.com/
+// | +-- f2u1, http://www.f2u1.com/
+// +-- Other bookmarks
+// | |-- f3
+// | | |-- f3u4, http://www.f3u4.com/
+// | | |-- f3u2, http://www.f3u2.com/
+// | | |-- f3u3, http://www.f3u3.com/
+// | | +-- f3u1, http://www.f3u1.com/
+// | |-- u4, http://www.u4.com/
+// | |-- u3, http://www.u3.com/
+// | --- f4
+// | | |-- f4u1, http://www.f4u1.com/
+// | | |-- f4u2, http://www.f4u2.com/
+// | | |-- f4u3, http://www.f4u3.com/
+// | | +-- f4u4, http://www.f4u4.com/
+// | |-- dup
+// | | +-- dupu1, http://www.dupu1.com/
+// | +-- dup
+// | | +-- dupu2, http://www.dupu1.com/
+// | +-- ls , http://www.ls.com/
+// |
+// +-- Mobile bookmarks
+// |-- f5
+// | |-- f5u1, http://www.f5u1.com/
+// |-- f6
+// | |-- f6u1, http://www.f6u1.com/
+// | |-- f6u2, http://www.f6u2.com/
+// +-- u5, http://www.u5.com/
+
+static TestData kBookmarkBarChildren[] = {
+ {"u2", "http://www.u2.com/"},
+ {"f1", NULL},
+ {"u1", "http://www.u1.com/"},
+ {"f2", NULL},
+};
+static TestData kF1Children[] = {
+ {"f1u4", "http://www.f1u4.com/"},
+ {"f1u2", "http://www.f1u2.com/"},
+ {"f1u3", "http://www.f1u3.com/"},
+ {"f1u1", "http://www.f1u1.com/"},
+};
+static TestData kF2Children[] = {
+ {"f2u2", "http://www.f2u2.com/"},
+ {"f2u4", "http://www.f2u4.com/"},
+ {"f2u3", "http://www.f2u3.com/"},
+ {"f2u1", "http://www.f2u1.com/"},
+};
+
+static TestData kOtherBookmarkChildren[] = {{"f3", NULL},
+ {"u4", "http://www.u4.com/"},
+ {"u3", "http://www.u3.com/"},
+ {"f4", NULL},
+ {"dup", NULL},
+ {"dup", NULL},
+ {" ls ", "http://www.ls.com/"}};
+static TestData kF3Children[] = {
+ {"f3u4", "http://www.f3u4.com/"},
+ {"f3u2", "http://www.f3u2.com/"},
+ {"f3u3", "http://www.f3u3.com/"},
+ {"f3u1", "http://www.f3u1.com/"},
+};
+static TestData kF4Children[] = {
+ {"f4u1", "http://www.f4u1.com/"},
+ {"f4u2", "http://www.f4u2.com/"},
+ {"f4u3", "http://www.f4u3.com/"},
+ {"f4u4", "http://www.f4u4.com/"},
+};
+static TestData kDup1Children[] = {
+ {"dupu1", "http://www.dupu1.com/"},
+};
+static TestData kDup2Children[] = {
+ {"dupu2", "http://www.dupu2.com/"},
+};
+
+static TestData kMobileBookmarkChildren[] = {
+ {"f5", NULL},
+ {"f6", NULL},
+ {"u5", "http://www.u5.com/"},
+};
+static TestData kF5Children[] = {
+ {"f5u1", "http://www.f5u1.com/"},
+ {"f5u2", "http://www.f5u2.com/"},
+};
+static TestData kF6Children[] = {
+ {"f6u1", "http://www.f6u1.com/"},
+ {"f6u2", "http://www.f6u2.com/"},
+};
+
+} // anonymous namespace.
+
+ProfileSyncServiceBookmarkTestWithData::ProfileSyncServiceBookmarkTestWithData()
+ : start_time_(base::Time::Now()) {}
+
+void ProfileSyncServiceBookmarkTestWithData::PopulateFromTestData(
+ const BookmarkNode* node,
+ const TestData* data,
+ int size,
+ int* running_count) {
+ DCHECK(node);
+ DCHECK(data);
+ DCHECK(node->is_folder());
+ for (int i = 0; i < size; ++i) {
+ const TestData& item = data[i];
+ if (item.url) {
+ const base::Time add_time =
+ start_time_ + base::TimeDelta::FromMinutes(*running_count);
+ model()->AddURLWithCreationTimeAndMetaInfo(
+ node, i, base::UTF8ToUTF16(item.title), GURL(item.url), add_time,
+ NULL);
+ } else {
+ model()->AddFolder(node, i, base::UTF8ToUTF16(item.title));
+ }
+ (*running_count)++;
+ }
+}
+
+void ProfileSyncServiceBookmarkTestWithData::CompareWithTestData(
+ const BookmarkNode* node,
+ const TestData* data,
+ int size,
+ int* running_count) {
+ DCHECK(node);
+ DCHECK(data);
+ DCHECK(node->is_folder());
+ ASSERT_EQ(size, node->child_count());
+ for (int i = 0; i < size; ++i) {
+ const BookmarkNode* child_node = node->GetChild(i);
+ const TestData& item = data[i];
+ GURL url = GURL(item.url == NULL ? "" : item.url);
+ BookmarkNode test_node(url);
+ test_node.SetTitle(base::UTF8ToUTF16(item.title));
+ EXPECT_EQ(child_node->GetTitle(), test_node.GetTitle());
+ if (item.url) {
+ EXPECT_FALSE(child_node->is_folder());
+ EXPECT_TRUE(child_node->is_url());
+ EXPECT_EQ(child_node->url(), test_node.url());
+ const base::Time expected_time =
+ start_time_ + base::TimeDelta::FromMinutes(*running_count);
+ EXPECT_EQ(expected_time.ToInternalValue(),
+ child_node->date_added().ToInternalValue());
+ } else {
+ EXPECT_TRUE(child_node->is_folder());
+ EXPECT_FALSE(child_node->is_url());
+ }
+ (*running_count)++;
+ }
+}
+
+// TODO(munjal): We should implement some way of generating random data and can
+// use the same seed to generate the same sequence.
+void ProfileSyncServiceBookmarkTestWithData::WriteTestDataToBookmarkModel() {
+ const BookmarkNode* bookmarks_bar_node = model()->bookmark_bar_node();
+ int count = 0;
+ PopulateFromTestData(bookmarks_bar_node, kBookmarkBarChildren,
+ arraysize(kBookmarkBarChildren), &count);
+
+ ASSERT_GE(bookmarks_bar_node->child_count(), 4);
+ const BookmarkNode* f1_node = bookmarks_bar_node->GetChild(1);
+ PopulateFromTestData(f1_node, kF1Children, arraysize(kF1Children), &count);
+ const BookmarkNode* f2_node = bookmarks_bar_node->GetChild(3);
+ PopulateFromTestData(f2_node, kF2Children, arraysize(kF2Children), &count);
+
+ const BookmarkNode* other_bookmarks_node = model()->other_node();
+ PopulateFromTestData(other_bookmarks_node, kOtherBookmarkChildren,
+ arraysize(kOtherBookmarkChildren), &count);
+
+ ASSERT_GE(other_bookmarks_node->child_count(), 6);
+ const BookmarkNode* f3_node = other_bookmarks_node->GetChild(0);
+ PopulateFromTestData(f3_node, kF3Children, arraysize(kF3Children), &count);
+ const BookmarkNode* f4_node = other_bookmarks_node->GetChild(3);
+ PopulateFromTestData(f4_node, kF4Children, arraysize(kF4Children), &count);
+ const BookmarkNode* dup_node = other_bookmarks_node->GetChild(4);
+ PopulateFromTestData(dup_node, kDup1Children, arraysize(kDup1Children),
+ &count);
+ dup_node = other_bookmarks_node->GetChild(5);
+ PopulateFromTestData(dup_node, kDup2Children, arraysize(kDup2Children),
+ &count);
+
+ const BookmarkNode* mobile_bookmarks_node = model()->mobile_node();
+ PopulateFromTestData(mobile_bookmarks_node, kMobileBookmarkChildren,
+ arraysize(kMobileBookmarkChildren), &count);
+
+ ASSERT_GE(mobile_bookmarks_node->child_count(), 3);
+ const BookmarkNode* f5_node = mobile_bookmarks_node->GetChild(0);
+ PopulateFromTestData(f5_node, kF5Children, arraysize(kF5Children), &count);
+ const BookmarkNode* f6_node = mobile_bookmarks_node->GetChild(1);
+ PopulateFromTestData(f6_node, kF6Children, arraysize(kF6Children), &count);
+
+ ExpectBookmarkModelMatchesTestData();
+}
+
+void ProfileSyncServiceBookmarkTestWithData::
+ ExpectBookmarkModelMatchesTestData() {
+ const BookmarkNode* bookmark_bar_node = model()->bookmark_bar_node();
+ int count = 0;
+ CompareWithTestData(bookmark_bar_node, kBookmarkBarChildren,
+ arraysize(kBookmarkBarChildren), &count);
+
+ ASSERT_GE(bookmark_bar_node->child_count(), 4);
+ const BookmarkNode* f1_node = bookmark_bar_node->GetChild(1);
+ CompareWithTestData(f1_node, kF1Children, arraysize(kF1Children), &count);
+ const BookmarkNode* f2_node = bookmark_bar_node->GetChild(3);
+ CompareWithTestData(f2_node, kF2Children, arraysize(kF2Children), &count);
+
+ const BookmarkNode* other_bookmarks_node = model()->other_node();
+ CompareWithTestData(other_bookmarks_node, kOtherBookmarkChildren,
+ arraysize(kOtherBookmarkChildren), &count);
+
+ ASSERT_GE(other_bookmarks_node->child_count(), 6);
+ const BookmarkNode* f3_node = other_bookmarks_node->GetChild(0);
+ CompareWithTestData(f3_node, kF3Children, arraysize(kF3Children), &count);
+ const BookmarkNode* f4_node = other_bookmarks_node->GetChild(3);
+ CompareWithTestData(f4_node, kF4Children, arraysize(kF4Children), &count);
+ const BookmarkNode* dup_node = other_bookmarks_node->GetChild(4);
+ CompareWithTestData(dup_node, kDup1Children, arraysize(kDup1Children),
+ &count);
+ dup_node = other_bookmarks_node->GetChild(5);
+ CompareWithTestData(dup_node, kDup2Children, arraysize(kDup2Children),
+ &count);
+
+ const BookmarkNode* mobile_bookmarks_node = model()->mobile_node();
+ CompareWithTestData(mobile_bookmarks_node, kMobileBookmarkChildren,
+ arraysize(kMobileBookmarkChildren), &count);
+
+ ASSERT_GE(mobile_bookmarks_node->child_count(), 3);
+ const BookmarkNode* f5_node = mobile_bookmarks_node->GetChild(0);
+ CompareWithTestData(f5_node, kF5Children, arraysize(kF5Children), &count);
+ const BookmarkNode* f6_node = mobile_bookmarks_node->GetChild(1);
+ CompareWithTestData(f6_node, kF6Children, arraysize(kF6Children), &count);
+}
+
+// Tests persistence of the profile sync service by unloading the
+// database and then reloading it from disk.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, Persistence) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+
+ WriteTestDataToBookmarkModel();
+
+ ExpectModelMatch();
+
+ // Force both models to discard their data and reload from disk. This
+ // simulates what would happen if the browser were to shutdown normally,
+ // and then relaunch.
+ StopSync();
+ LoadBookmarkModel(LOAD_FROM_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+
+ ExpectBookmarkModelMatchesTestData();
+
+ // With the BookmarkModel contents verified, ExpectModelMatch will
+ // verify the contents of the sync model.
+ ExpectModelMatch();
+}
+
+// Tests the merge case when the BookmarkModel is non-empty but the
+// sync model is empty. This corresponds to uploading browser
+// bookmarks to an initially empty, new account.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, MergeWithEmptySyncModel) {
+ // Don't start the sync service until we've populated the bookmark model.
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
+
+ WriteTestDataToBookmarkModel();
+
+ // Restart sync. This should trigger a merge step during
+ // initialization -- we expect the browser bookmarks to be written
+ // to the sync service during this call.
+ StartSync();
+
+ // Verify that the bookmark model hasn't changed, and that the sync model
+ // matches it exactly.
+ ExpectBookmarkModelMatchesTestData();
+ ExpectModelMatch();
+}
+
+// Tests the merge case when the BookmarkModel is empty but the sync model is
+// non-empty. This corresponds (somewhat) to a clean install of the browser,
+// with no bookmarks, connecting to a sync account that has some bookmarks.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, MergeWithEmptyBookmarkModel) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ WriteTestDataToBookmarkModel();
+
+ ExpectModelMatch();
+
+ // Force the databse to unload and write itself to disk.
+ StopSync();
+
+ // Blow away the bookmark model -- it should be empty afterwards.
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ EXPECT_EQ(model()->bookmark_bar_node()->child_count(), 0);
+ EXPECT_EQ(model()->other_node()->child_count(), 0);
+ EXPECT_EQ(model()->mobile_node()->child_count(), 0);
+
+ // Now restart the sync service. Starting it should populate the bookmark
+ // model -- test for consistency.
+ StartSync();
+ ExpectBookmarkModelMatchesTestData();
+ ExpectModelMatch();
+}
+
+// Tests the merge cases when both the models are expected to be identical
+// after the merge.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, MergeExpectedIdenticalModels) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+ WriteTestDataToBookmarkModel();
+ ExpectModelMatch();
+ StopSync();
+
+ // At this point both the bookmark model and the server should have the
+ // exact same data and it should match the test data.
+ LoadBookmarkModel(LOAD_FROM_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+ ExpectBookmarkModelMatchesTestData();
+ ExpectModelMatch();
+ StopSync();
+
+ // Now reorder some bookmarks in the bookmark model and then merge. Make
+ // sure we get the order of the server after merge.
+ LoadBookmarkModel(LOAD_FROM_STORAGE, DONT_SAVE_TO_STORAGE);
+ ExpectBookmarkModelMatchesTestData();
+ const BookmarkNode* bookmark_bar = model()->bookmark_bar_node();
+ ASSERT_TRUE(bookmark_bar);
+ ASSERT_GT(bookmark_bar->child_count(), 1);
+ model()->Move(bookmark_bar->GetChild(0), bookmark_bar, 1);
+ StartSync();
+ ExpectModelMatch();
+ ExpectBookmarkModelMatchesTestData();
+}
+
+// Tests the merge cases when both the models are expected to be identical
+// after the merge.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, MergeModelsWithSomeExtras) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ WriteTestDataToBookmarkModel();
+ ExpectBookmarkModelMatchesTestData();
+
+ // Remove some nodes and reorder some nodes.
+ const BookmarkNode* bookmark_bar_node = model()->bookmark_bar_node();
+ int remove_index = 2;
+ ASSERT_GT(bookmark_bar_node->child_count(), remove_index);
+ const BookmarkNode* child_node = bookmark_bar_node->GetChild(remove_index);
+ ASSERT_TRUE(child_node);
+ ASSERT_TRUE(child_node->is_url());
+ model()->Remove(bookmark_bar_node->GetChild(remove_index));
+ ASSERT_GT(bookmark_bar_node->child_count(), remove_index);
+ child_node = bookmark_bar_node->GetChild(remove_index);
+ ASSERT_TRUE(child_node);
+ ASSERT_TRUE(child_node->is_folder());
+ model()->Remove(bookmark_bar_node->GetChild(remove_index));
+
+ const BookmarkNode* other_node = model()->other_node();
+ ASSERT_GE(other_node->child_count(), 1);
+ const BookmarkNode* f3_node = other_node->GetChild(0);
+ ASSERT_TRUE(f3_node);
+ ASSERT_TRUE(f3_node->is_folder());
+ remove_index = 2;
+ ASSERT_GT(f3_node->child_count(), remove_index);
+ model()->Remove(f3_node->GetChild(remove_index));
+ ASSERT_GT(f3_node->child_count(), remove_index);
+ model()->Remove(f3_node->GetChild(remove_index));
+
+ StartSync();
+ ExpectModelMatch();
+ StopSync();
+
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ WriteTestDataToBookmarkModel();
+ ExpectBookmarkModelMatchesTestData();
+
+ // Remove some nodes and reorder some nodes.
+ bookmark_bar_node = model()->bookmark_bar_node();
+ remove_index = 0;
+ ASSERT_GT(bookmark_bar_node->child_count(), remove_index);
+ child_node = bookmark_bar_node->GetChild(remove_index);
+ ASSERT_TRUE(child_node);
+ ASSERT_TRUE(child_node->is_url());
+ model()->Remove(bookmark_bar_node->GetChild(remove_index));
+ ASSERT_GT(bookmark_bar_node->child_count(), remove_index);
+ child_node = bookmark_bar_node->GetChild(remove_index);
+ ASSERT_TRUE(child_node);
+ ASSERT_TRUE(child_node->is_folder());
+ model()->Remove(bookmark_bar_node->GetChild(remove_index));
+
+ ASSERT_GE(bookmark_bar_node->child_count(), 2);
+ model()->Move(bookmark_bar_node->GetChild(0), bookmark_bar_node, 1);
+
+ other_node = model()->other_node();
+ ASSERT_GE(other_node->child_count(), 1);
+ f3_node = other_node->GetChild(0);
+ ASSERT_TRUE(f3_node);
+ ASSERT_TRUE(f3_node->is_folder());
+ remove_index = 0;
+ ASSERT_GT(f3_node->child_count(), remove_index);
+ model()->Remove(f3_node->GetChild(remove_index));
+ ASSERT_GT(f3_node->child_count(), remove_index);
+ model()->Remove(f3_node->GetChild(remove_index));
+
+ ASSERT_GE(other_node->child_count(), 4);
+ model()->Move(other_node->GetChild(0), other_node, 1);
+ model()->Move(other_node->GetChild(2), other_node, 3);
+
+ StartSync();
+ ExpectModelMatch();
+
+ // After the merge, the model should match the test data.
+ ExpectBookmarkModelMatchesTestData();
+}
+
+// Tests that when persisted model associations are used, things work fine.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, ModelAssociationPersistence) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ WriteTestDataToBookmarkModel();
+ StartSync();
+ ExpectModelMatch();
+ // Force sync to shut down and write itself to disk.
+ StopSync();
+ // Now restart sync. This time it should use the persistent
+ // associations.
+ StartSync();
+ ExpectModelMatch();
+}
+
+// Tests that when persisted model associations are used, things work fine.
+TEST_F(ProfileSyncServiceBookmarkTestWithData,
+ ModelAssociationInvalidPersistence) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ WriteTestDataToBookmarkModel();
+ StartSync();
+ ExpectModelMatch();
+ // Force sync to shut down and write itself to disk.
+ StopSync();
+ // Change the bookmark model before restarting sync service to simulate
+ // the situation where bookmark model is different from sync model and
+ // make sure model associator correctly rebuilds associations.
+ const BookmarkNode* bookmark_bar_node = model()->bookmark_bar_node();
+ model()->AddURL(bookmark_bar_node, 0, base::ASCIIToUTF16("xtra"),
+ GURL("http://www.xtra.com"));
+ // Now restart sync. This time it will try to use the persistent
+ // associations and realize that they are invalid and hence will rebuild
+ // associations.
+ StartSync();
+ ExpectModelMatch();
+}
+
+TEST_F(ProfileSyncServiceBookmarkTestWithData, SortChildren) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ // Write test data to bookmark model and verify that the models match.
+ WriteTestDataToBookmarkModel();
+ const BookmarkNode* folder_added = model()->other_node()->GetChild(0);
+ ASSERT_TRUE(folder_added);
+ ASSERT_TRUE(folder_added->is_folder());
+
+ ExpectModelMatch();
+
+ // Sort the other-bookmarks children and expect that the models match.
+ model()->SortChildren(folder_added);
+ ExpectModelMatch();
+}
+
+// See what happens if we enable sync but then delete the "Sync Data"
+// folder.
+TEST_F(ProfileSyncServiceBookmarkTestWithData,
+ RecoverAfterDeletingSyncDataDirectory) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
+ StartSync();
+
+ WriteTestDataToBookmarkModel();
+
+ StopSync();
+
+ // Nuke the sync DB and reload.
+ TearDown();
+ SetUp();
+
+ // First attempt fails due to a persistence error.
+ EXPECT_TRUE(CreatePermanentBookmarkNodes());
+ EXPECT_FALSE(AssociateModels());
+
+ // Second attempt succeeds due to the previous error resetting the native
+ // transaction version.
+ delete_model_associator();
+ EXPECT_TRUE(CreatePermanentBookmarkNodes());
+ EXPECT_TRUE(AssociateModels());
+
+ // Make sure we're back in sync. In real life, the user would need
+ // to reauthenticate before this happens, but in the test, authentication
+ // is sidestepped.
+ ExpectBookmarkModelMatchesTestData();
+ ExpectModelMatch();
+}
+
+// Verify that the bookmark model is updated about whether the
+// associator is currently running.
+TEST_F(ProfileSyncServiceBookmarkTest, AssociationState) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+
+ ExtensiveChangesBookmarkModelObserver observer;
+ model()->AddObserver(&observer);
+
+ StartSync();
+
+ EXPECT_EQ(1, observer.get_started());
+ EXPECT_EQ(0, observer.get_completed_count_at_started());
+ EXPECT_EQ(1, observer.get_completed());
+
+ model()->RemoveObserver(&observer);
+}
+
+// Verify that the creation_time_us changes are applied in the local model at
+// association time and update time.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, UpdateDateAdded) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ WriteTestDataToBookmarkModel();
+
+ // Start and stop sync in order to create bookmark nodes in the sync db.
+ StartSync();
+ StopSync();
+
+ // Modify the date_added field of a bookmark so it doesn't match with
+ // the sync data.
+ const BookmarkNode* bookmark_bar_node = model()->bookmark_bar_node();
+ int modified_index = 2;
+ ASSERT_GT(bookmark_bar_node->child_count(), modified_index);
+ const BookmarkNode* child_node = bookmark_bar_node->GetChild(modified_index);
+ ASSERT_TRUE(child_node);
+ EXPECT_TRUE(child_node->is_url());
+ model()->SetDateAdded(child_node, base::Time::FromInternalValue(10));
+
+ StartSync();
+ StopSync();
+
+ // Verify that transaction versions are in sync between the native model
+ // and Sync.
+ {
+ syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
+ int64_t sync_version = trans.GetModelVersion(syncer::BOOKMARKS);
+ int64_t native_version = model()->root_node()->sync_transaction_version();
+ EXPECT_EQ(native_version, sync_version);
+ }
+
+ // Since the version is in sync the association above should have skipped
+ // updating the native node above. That is expected optimization (see
+ // crbug/464907.
+ EXPECT_EQ(child_node->date_added(), base::Time::FromInternalValue(10));
+
+ // Reset transaction version on the native model to trigger updating data
+ // for all bookmark nodes.
+ model()->SetNodeSyncTransactionVersion(
+ model()->root_node(), syncer::syncable::kInvalidTransactionVersion);
+
+ StartSync();
+
+ // Everything should be back in sync after model association.
+ ExpectBookmarkModelMatchesTestData();
+ ExpectModelMatch();
+
+ // Now trigger a change while syncing. We add a new bookmark, sync it, then
+ // updates it's creation time.
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ FakeServerChange adds(&trans);
+ const std::string kTitle = "Some site";
+ const std::string kUrl = "http://www.whatwhat.yeah/";
+ const int kCreationTime = 30;
+ int64_t id = adds.AddURL(kTitle, kUrl, bookmark_bar_id(), 0);
+ adds.ApplyPendingChanges(change_processor());
+ FakeServerChange updates(&trans);
+ updates.ModifyCreationTime(id, kCreationTime);
+ updates.ApplyPendingChanges(change_processor());
+
+ const BookmarkNode* node = model()->bookmark_bar_node()->GetChild(0);
+ ASSERT_TRUE(node);
+ EXPECT_TRUE(node->is_url());
+ EXPECT_EQ(base::UTF8ToUTF16(kTitle), node->GetTitle());
+ EXPECT_EQ(kUrl, node->url().possibly_invalid_spec());
+ EXPECT_EQ(node->date_added(), base::Time::FromInternalValue(30));
+}
+
+// Verifies that the transaction version in the native bookmark model gets
+// updated and synced with the sync transaction version even when the
+// association doesn't modify any sync nodes. This is necessary to ensure
+// that the native transaction doesn't get stuck at "unset" version and skips
+// any further consistency checks.
+TEST_F(ProfileSyncServiceBookmarkTestWithData,
+ NativeTransactionVersionUpdated) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ WriteTestDataToBookmarkModel();
+
+ // Start sync in order to create bookmark nodes in the sync db.
+ StartSync();
+ StopSync();
+
+ // Reset transaction version on the native mode to "unset".
+ model()->SetNodeSyncTransactionVersion(
+ model()->root_node(), syncer::syncable::kInvalidTransactionVersion);
+
+ // Restart sync.
+ StartSync();
+ StopSync();
+
+ // Verify that the native transaction version has been updated and is now
+ // in sync with the sync version.
+ {
+ syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
+ int64_t sync_version = trans.GetModelVersion(syncer::BOOKMARKS);
+ int64_t native_version = model()->root_node()->sync_transaction_version();
+ EXPECT_EQ(native_version, sync_version);
+ }
+}
+
+// Tests that changes to the sync nodes meta info gets reflected in the local
+// bookmark model.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, UpdateMetaInfoFromSync) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ WriteTestDataToBookmarkModel();
+ StartSync();
+
+ // Create bookmark nodes containing meta info.
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ FakeServerChange adds(&trans);
+ BookmarkNode::MetaInfoMap folder_meta_info;
+ folder_meta_info["folder"] = "foldervalue";
+ int64_t folder_id = adds.AddFolderWithMetaInfo(
+ "folder title", &folder_meta_info, bookmark_bar_id(), 0);
+ BookmarkNode::MetaInfoMap node_meta_info;
+ node_meta_info["node"] = "nodevalue";
+ node_meta_info["other"] = "othervalue";
+ int64_t id = adds.AddURLWithMetaInfo("node title", "http://www.foo.com",
+ &node_meta_info, folder_id, 0);
+ adds.ApplyPendingChanges(change_processor());
+
+ // Verify that the nodes are created with the correct meta info.
+ ASSERT_LT(0, model()->bookmark_bar_node()->child_count());
+ const BookmarkNode* folder_node = model()->bookmark_bar_node()->GetChild(0);
+ ASSERT_TRUE(folder_node->GetMetaInfoMap());
+ EXPECT_EQ(folder_meta_info, *folder_node->GetMetaInfoMap());
+ ASSERT_LT(0, folder_node->child_count());
+ const BookmarkNode* node = folder_node->GetChild(0);
+ ASSERT_TRUE(node->GetMetaInfoMap());
+ EXPECT_EQ(node_meta_info, *node->GetMetaInfoMap());
+
+ // Update meta info on nodes on server
+ FakeServerChange updates(&trans);
+ folder_meta_info.erase("folder");
+ updates.ModifyMetaInfo(folder_id, folder_meta_info);
+ node_meta_info["node"] = "changednodevalue";
+ node_meta_info.erase("other");
+ node_meta_info["newkey"] = "newkeyvalue";
+ updates.ModifyMetaInfo(id, node_meta_info);
+ updates.ApplyPendingChanges(change_processor());
+
+ // Confirm that the updated values are reflected in the bookmark nodes.
+ EXPECT_FALSE(folder_node->GetMetaInfoMap());
+ ASSERT_TRUE(node->GetMetaInfoMap());
+ EXPECT_EQ(node_meta_info, *node->GetMetaInfoMap());
+}
+
+// Tests that changes to the local bookmark nodes meta info gets reflected in
+// the sync nodes.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, UpdateMetaInfoFromModel) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ WriteTestDataToBookmarkModel();
+ StartSync();
+ ExpectBookmarkModelMatchesTestData();
+
+ const BookmarkNode* folder_node = model()->AddFolder(
+ model()->bookmark_bar_node(), 0, base::ASCIIToUTF16("folder title"));
+ const BookmarkNode* node =
+ model()->AddURL(folder_node, 0, base::ASCIIToUTF16("node title"),
+ GURL("http://www.foo.com"));
+ ExpectModelMatch();
+
+ // Add some meta info and verify sync model matches the changes.
+ model()->SetNodeMetaInfo(folder_node, "folder", "foldervalue");
+ model()->SetNodeMetaInfo(node, "node", "nodevalue");
+ model()->SetNodeMetaInfo(node, "other", "othervalue");
+ ExpectModelMatch();
+
+ // Change/delete existing meta info and verify.
+ model()->DeleteNodeMetaInfo(folder_node, "folder");
+ model()->SetNodeMetaInfo(node, "node", "changednodevalue");
+ model()->DeleteNodeMetaInfo(node, "other");
+ model()->SetNodeMetaInfo(node, "newkey", "newkeyvalue");
+ ExpectModelMatch();
+}
+
+// Tests that node's specifics doesn't get unnecessarily overwritten (causing
+// a subsequent commit) when BookmarkChangeProcessor handles a notification
+// (such as BookmarkMetaInfoChanged) without an actual data change.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, MetaInfoPreservedOnNonChange) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ WriteTestDataToBookmarkModel();
+ StartSync();
+
+ std::string orig_specifics;
+ int64_t sync_id;
+ const BookmarkNode* bookmark;
+
+ // Create bookmark folder node containing meta info.
+ {
+ syncer::WriteTransaction trans(FROM_HERE, test_user_share()->user_share());
+ FakeServerChange adds(&trans);
+
+ int64_t folder_id = adds.AddFolder("folder title", bookmark_bar_id(), 0);
+
+ BookmarkNode::MetaInfoMap node_meta_info;
+ node_meta_info["one"] = "1";
+ node_meta_info["two"] = "2";
+ node_meta_info["three"] = "3";
+
+ sync_id = adds.AddURLWithMetaInfo("node title", "http://www.foo.com/",
+ &node_meta_info, folder_id, 0);
+
+ // Verify that the node propagates to the bookmark model
+ adds.ApplyPendingChanges(change_processor());
+
+ bookmark = model()->bookmark_bar_node()->GetChild(0)->GetChild(0);
+ EXPECT_EQ(node_meta_info, *bookmark->GetMetaInfoMap());
+
+ syncer::ReadNode sync_node(&trans);
+ EXPECT_EQ(BaseNode::INIT_OK, sync_node.InitByIdLookup(sync_id));
+ orig_specifics = sync_node.GetBookmarkSpecifics().SerializeAsString();
+ }
+
+ // Force change processor to update the sync node.
+ change_processor()->BookmarkMetaInfoChanged(model(), bookmark);
+
+ // Read bookmark specifics again and verify that there is no change.
+ {
+ syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
+ syncer::ReadNode sync_node(&trans);
+ EXPECT_EQ(BaseNode::INIT_OK, sync_node.InitByIdLookup(sync_id));
+ std::string new_specifics =
+ sync_node.GetBookmarkSpecifics().SerializeAsString();
+ ASSERT_EQ(orig_specifics, new_specifics);
+ }
+}
+
+void ProfileSyncServiceBookmarkTestWithData::GetTransactionVersions(
+ const BookmarkNode* root,
+ BookmarkNodeVersionMap* node_versions) {
+ node_versions->clear();
+ std::queue<const BookmarkNode*> nodes;
+ nodes.push(root);
+ while (!nodes.empty()) {
+ const BookmarkNode* n = nodes.front();
+ nodes.pop();
+
+ int64_t version = n->sync_transaction_version();
+ EXPECT_NE(BookmarkNode::kInvalidSyncTransactionVersion, version);
+
+ (*node_versions)[n->id()] = version;
+ for (int i = 0; i < n->child_count(); ++i) {
+ if (!CanSyncNode(n->GetChild(i)))
+ continue;
+ nodes.push(n->GetChild(i));
+ }
+ }
+}
+
+void ProfileSyncServiceBookmarkTestWithData::ExpectTransactionVersionMatch(
+ const BookmarkNode* node,
+ const BookmarkNodeVersionMap& version_expected) {
+ syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
+
+ BookmarkNodeVersionMap bnodes_versions;
+ GetTransactionVersions(node, &bnodes_versions);
+ for (BookmarkNodeVersionMap::const_iterator it = bnodes_versions.begin();
+ it != bnodes_versions.end(); ++it) {
+ syncer::ReadNode sync_node(&trans);
+ ASSERT_TRUE(
+ model_associator()->InitSyncNodeFromChromeId(it->first, &sync_node));
+ EXPECT_EQ(sync_node.GetTransactionVersion(), it->second);
+ BookmarkNodeVersionMap::const_iterator expected_ver_it =
+ version_expected.find(it->first);
+ if (expected_ver_it != version_expected.end())
+ EXPECT_EQ(expected_ver_it->second, it->second);
+ }
+}
+
+// Test transaction versions of model and nodes are incremented after changes
+// are applied.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, UpdateTransactionVersion) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+ WriteTestDataToBookmarkModel();
+ base::RunLoop().RunUntilIdle();
+
+ BookmarkNodeVersionMap initial_versions;
+
+ // Verify transaction versions in sync model and bookmark model (saved as
+ // transaction version of root node) are equal after
+ // WriteTestDataToBookmarkModel() created bookmarks.
+ {
+ syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
+ EXPECT_GT(trans.GetModelVersion(syncer::BOOKMARKS), 0);
+ GetTransactionVersions(model()->root_node(), &initial_versions);
+ EXPECT_EQ(trans.GetModelVersion(syncer::BOOKMARKS),
+ initial_versions[model()->root_node()->id()]);
+ }
+ ExpectTransactionVersionMatch(model()->bookmark_bar_node(),
+ BookmarkNodeVersionMap());
+ ExpectTransactionVersionMatch(model()->other_node(),
+ BookmarkNodeVersionMap());
+ ExpectTransactionVersionMatch(model()->mobile_node(),
+ BookmarkNodeVersionMap());
+
+ // Verify model version is incremented and bookmark node versions remain
+ // the same.
+ const BookmarkNode* bookmark_bar = model()->bookmark_bar_node();
+ model()->Remove(bookmark_bar->GetChild(0));
+ base::RunLoop().RunUntilIdle();
+ BookmarkNodeVersionMap new_versions;
+ GetTransactionVersions(model()->root_node(), &new_versions);
+ EXPECT_EQ(initial_versions[model()->root_node()->id()] + 1,
+ new_versions[model()->root_node()->id()]);
+ ExpectTransactionVersionMatch(model()->bookmark_bar_node(), initial_versions);
+ ExpectTransactionVersionMatch(model()->other_node(), initial_versions);
+ ExpectTransactionVersionMatch(model()->mobile_node(), initial_versions);
+
+ // Verify model version and version of changed bookmark are incremented and
+ // versions of others remain same.
+ const BookmarkNode* changed_bookmark =
+ model()->bookmark_bar_node()->GetChild(0);
+ model()->SetTitle(changed_bookmark, base::ASCIIToUTF16("test"));
+ base::RunLoop().RunUntilIdle();
+ GetTransactionVersions(model()->root_node(), &new_versions);
+ EXPECT_EQ(initial_versions[model()->root_node()->id()] + 2,
+ new_versions[model()->root_node()->id()]);
+ EXPECT_LT(initial_versions[changed_bookmark->id()],
+ new_versions[changed_bookmark->id()]);
+ initial_versions.erase(changed_bookmark->id());
+ ExpectTransactionVersionMatch(model()->bookmark_bar_node(), initial_versions);
+ ExpectTransactionVersionMatch(model()->other_node(), initial_versions);
+ ExpectTransactionVersionMatch(model()->mobile_node(), initial_versions);
+}
+
+// Test that sync persistence errors are detected and trigger a failed
+// association.
+TEST_F(ProfileSyncServiceBookmarkTestWithData, PersistenceError) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+ WriteTestDataToBookmarkModel();
+ base::RunLoop().RunUntilIdle();
+
+ BookmarkNodeVersionMap initial_versions;
+
+ // Verify transaction versions in sync model and bookmark model (saved as
+ // transaction version of root node) are equal after
+ // WriteTestDataToBookmarkModel() created bookmarks.
+ {
+ syncer::ReadTransaction trans(FROM_HERE, test_user_share()->user_share());
+ EXPECT_GT(trans.GetModelVersion(syncer::BOOKMARKS), 0);
+ GetTransactionVersions(model()->root_node(), &initial_versions);
+ EXPECT_EQ(trans.GetModelVersion(syncer::BOOKMARKS),
+ initial_versions[model()->root_node()->id()]);
+ }
+ ExpectTransactionVersionMatch(model()->bookmark_bar_node(),
+ BookmarkNodeVersionMap());
+ ExpectTransactionVersionMatch(model()->other_node(),
+ BookmarkNodeVersionMap());
+ ExpectTransactionVersionMatch(model()->mobile_node(),
+ BookmarkNodeVersionMap());
+
+ // Now shut down sync and artificially increment the native model's version.
+ StopSync();
+ int64_t root_version = initial_versions[model()->root_node()->id()];
+ model()->SetNodeSyncTransactionVersion(model()->root_node(),
+ root_version + 1);
+
+ // Upon association, bookmarks should fail to associate.
+ EXPECT_FALSE(AssociateModels());
+}
+
+// It's possible for update/add calls from the bookmark model to be out of
+// order, or asynchronous. Handle that without triggering an error.
+TEST_F(ProfileSyncServiceBookmarkTest, UpdateThenAdd) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ EXPECT_TRUE(other_bookmarks_id());
+ EXPECT_TRUE(bookmark_bar_id());
+ EXPECT_TRUE(mobile_bookmarks_id());
+
+ ExpectModelMatch();
+
+ // Now destroy the change processor then add a bookmark, to simulate
+ // missing the Update call.
+ delete_change_processor();
+ const BookmarkNode* node =
+ model()->AddURL(model()->bookmark_bar_node(), 0,
+ base::ASCIIToUTF16("title"), GURL("http://www.url.com"));
+
+ // Recreate the change processor then update that bookmark. Sync should
+ // receive the update call and gracefully treat that as if it were an add.
+ ResetChangeProcessor();
+ change_processor()->Start(test_user_share()->user_share());
+ model()->SetTitle(node, base::ASCIIToUTF16("title2"));
+ ExpectModelMatch();
+
+ // Then simulate the add call arriving late.
+ change_processor()->BookmarkNodeAdded(model(), model()->bookmark_bar_node(),
+ 0);
+ ExpectModelMatch();
+}
+
+// Verify operations on native nodes that shouldn't be propagated to Sync.
+TEST_F(ProfileSyncServiceBookmarkTest, TestUnsupportedNodes) {
+ LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
+ StartSync();
+
+ // Initial number of bookmarks on the sync side.
+ int sync_bookmark_count = GetSyncBookmarkCount();
+
+ // Create a bookmark under managed_node() permanent folder.
+ const BookmarkNode* folder = managed_bookmark_service()->managed_node();
+ const BookmarkNode* node = model()->AddURL(
+ folder, 0, base::ASCIIToUTF16("node"), GURL("http://www.node.com/"));
+
+ // Verify that these changes are ignored by Sync.
+ EXPECT_EQ(sync_bookmark_count, GetSyncBookmarkCount());
+ int64_t sync_id = model_associator()->GetSyncIdFromChromeId(node->id());
+ EXPECT_EQ(syncer::kInvalidId, sync_id);
+
+ // Verify that Sync ignores deleting this node.
+ model()->Remove(node);
+ EXPECT_EQ(sync_bookmark_count, GetSyncBookmarkCount());
+}
+
+} // namespace
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_service_mock.cc b/chromium/components/browser_sync/profile_sync_service_mock.cc
new file mode 100644
index 00000000000..d2dd85c1d21
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_service_mock.cc
@@ -0,0 +1,21 @@
+// 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 "components/browser_sync/profile_sync_service_mock.h"
+
+#include <utility>
+
+namespace browser_sync {
+
+ProfileSyncServiceMock::ProfileSyncServiceMock(InitParams init_params)
+ : ProfileSyncService(std::move(init_params)) {
+ ON_CALL(*this, IsSyncRequested()).WillByDefault(testing::Return(true));
+}
+
+ProfileSyncServiceMock::ProfileSyncServiceMock(InitParams* init_params)
+ : ProfileSyncServiceMock(std::move(*init_params)) {}
+
+ProfileSyncServiceMock::~ProfileSyncServiceMock() {}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_service_mock.h b/chromium/components/browser_sync/profile_sync_service_mock.h
new file mode 100644
index 00000000000..3ddb30f54e9
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_service_mock.h
@@ -0,0 +1,105 @@
+// 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 COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_SERVICE_MOCK_H_
+#define COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_SERVICE_MOCK_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/device_info/device_info.h"
+#include "components/sync/driver/change_processor.h"
+#include "components/sync/driver/data_type_controller.h"
+#include "components/sync/protocol/sync_protocol_error.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace browser_sync {
+
+class ProfileSyncServiceMock : public ProfileSyncService {
+ public:
+ explicit ProfileSyncServiceMock(InitParams init_params);
+ // The second constructor defers to the first one. Use it when you need to
+ // create a StrictMock or NiceMock of ProfileSyncServiceMock, because those
+ // template classes cannot handle the input class having constructors with
+ // arguments passed by value. Otherwise use the constructor above for cleaner
+ // code.
+ explicit ProfileSyncServiceMock(InitParams* init_params);
+
+ virtual ~ProfileSyncServiceMock();
+
+ MOCK_METHOD4(
+ OnBackendInitialized,
+ void(const syncer::WeakHandle<syncer::JsBackend>&,
+ const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&,
+ const std::string&,
+ bool));
+ MOCK_METHOD0(OnSyncCycleCompleted, void());
+ MOCK_METHOD2(OnUserChoseDatatypes,
+ void(bool sync_everything, syncer::ModelTypeSet chosen_types));
+
+ MOCK_METHOD2(OnUnrecoverableError,
+ void(const tracked_objects::Location& location,
+ const std::string& message));
+ MOCK_CONST_METHOD0(GetUserShare, syncer::UserShare*());
+ MOCK_METHOD0(RequestStart, void());
+ MOCK_METHOD1(RequestStop, void(ProfileSyncService::SyncStopDataFate));
+
+ MOCK_METHOD1(AddObserver, void(syncer::SyncServiceObserver*));
+ MOCK_METHOD1(RemoveObserver, void(syncer::SyncServiceObserver*));
+ MOCK_METHOD0(GetJsController, base::WeakPtr<syncer::JsController>());
+ MOCK_CONST_METHOD0(IsFirstSetupComplete, bool());
+
+ MOCK_CONST_METHOD0(IsEncryptEverythingAllowed, bool());
+ MOCK_CONST_METHOD0(IsEncryptEverythingEnabled, bool());
+ MOCK_METHOD0(EnableEncryptEverything, void());
+
+ MOCK_METHOD1(ChangePreferredDataTypes,
+ void(syncer::ModelTypeSet preferred_types));
+ MOCK_CONST_METHOD0(GetActiveDataTypes, syncer::ModelTypeSet());
+ MOCK_CONST_METHOD0(GetPreferredDataTypes, syncer::ModelTypeSet());
+ MOCK_CONST_METHOD0(GetRegisteredDataTypes, syncer::ModelTypeSet());
+ MOCK_CONST_METHOD0(GetLastCycleSnapshot, syncer::SyncCycleSnapshot());
+
+ MOCK_METHOD1(QueryDetailedSyncStatus,
+ bool(syncer::SyncBackendHost::Status* result));
+ MOCK_CONST_METHOD0(GetAuthError, const GoogleServiceAuthError&());
+ MOCK_CONST_METHOD0(IsFirstSetupInProgress, bool());
+ MOCK_CONST_METHOD0(GetLastSyncedTimeString, base::string16());
+ MOCK_CONST_METHOD0(HasUnrecoverableError, bool());
+ MOCK_CONST_METHOD0(IsSyncActive, bool());
+ MOCK_CONST_METHOD0(IsBackendInitialized, bool());
+ MOCK_CONST_METHOD0(IsSyncRequested, bool());
+ MOCK_CONST_METHOD0(waiting_for_auth, bool());
+ MOCK_METHOD1(OnActionableError, void(const syncer::SyncProtocolError&));
+ MOCK_CONST_METHOD1(IsDataTypeControllerRunning, bool(syncer::ModelType));
+
+ // DataTypeManagerObserver mocks.
+ MOCK_METHOD1(OnConfigureDone,
+ void(const syncer::DataTypeManager::ConfigureResult&));
+ MOCK_METHOD0(OnConfigureStart, void());
+
+ MOCK_CONST_METHOD0(CanSyncStart, bool());
+ MOCK_CONST_METHOD0(IsManaged, bool());
+
+ MOCK_CONST_METHOD0(IsPassphraseRequired, bool());
+ MOCK_CONST_METHOD0(IsPassphraseRequiredForDecryption, bool());
+ MOCK_CONST_METHOD0(IsUsingSecondaryPassphrase, bool());
+ MOCK_CONST_METHOD0(GetPassphraseType, syncer::PassphraseType());
+ MOCK_CONST_METHOD0(GetExplicitPassphraseTime, base::Time());
+
+ MOCK_METHOD1(SetDecryptionPassphrase, bool(const std::string& passphrase));
+ MOCK_METHOD2(SetEncryptionPassphrase,
+ void(const std::string& passphrase, PassphraseType type));
+
+ MOCK_METHOD0(OnSetupInProgressHandleDestroyed, void());
+};
+
+} // namespace browser_sync
+
+#endif // COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_SERVICE_MOCK_H_
diff --git a/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc b/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc
new file mode 100644
index 00000000000..a608d123c4b
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc
@@ -0,0 +1,474 @@
+// 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 "components/browser_sync/profile_sync_service.h"
+
+#include "base/files/file_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/browser_sync/profile_sync_test_util.h"
+#include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/common/signin_pref_names.h"
+#include "components/sync/driver/data_type_manager_mock.h"
+#include "components/sync/driver/fake_data_type_controller.h"
+#include "components/sync/driver/glue/sync_backend_host_mock.h"
+#include "components/sync/driver/pref_names.h"
+#include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/driver/sync_service_observer.h"
+#include "components/syncable_prefs/pref_service_syncable.h"
+#include "google_apis/gaia/gaia_auth_consumer.h"
+#include "google_apis/gaia/gaia_constants.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 syncer::DataTypeManager;
+using syncer::DataTypeManagerMock;
+using syncer::SyncBackendHostMock;
+using testing::_;
+using testing::AnyNumber;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+
+namespace browser_sync {
+
+namespace {
+
+const char kGaiaId[] = "12345";
+const char kEmail[] = "test_user@gmail.com";
+const char kDummyPassword[] = "";
+
+class SyncServiceObserverMock : public syncer::SyncServiceObserver {
+ public:
+ SyncServiceObserverMock();
+ virtual ~SyncServiceObserverMock();
+
+ MOCK_METHOD0(OnStateChanged, void());
+};
+
+SyncServiceObserverMock::SyncServiceObserverMock() {}
+
+SyncServiceObserverMock::~SyncServiceObserverMock() {}
+
+} // namespace
+
+ACTION_P(InvokeOnConfigureStart, sync_service) {
+ sync_service->OnConfigureStart();
+}
+
+ACTION_P3(InvokeOnConfigureDone, sync_service, error_callback, result) {
+ DataTypeManager::ConfigureResult configure_result =
+ static_cast<DataTypeManager::ConfigureResult>(result);
+ if (result.status == syncer::DataTypeManager::ABORTED)
+ error_callback.Run(&configure_result);
+ sync_service->OnConfigureDone(configure_result);
+}
+
+class ProfileSyncServiceStartupTest : public testing::Test {
+ public:
+ ProfileSyncServiceStartupTest() {
+ profile_sync_service_bundle_.auth_service()
+ ->set_auto_post_fetch_response_on_message_loop(true);
+ }
+
+ ~ProfileSyncServiceStartupTest() override {
+ sync_service_->RemoveObserver(&observer_);
+ sync_service_->Shutdown();
+ }
+
+ void CreateSyncService(ProfileSyncService::StartBehavior start_behavior) {
+ component_factory_ = profile_sync_service_bundle_.component_factory();
+ ProfileSyncServiceBundle::SyncClientBuilder builder(
+ &profile_sync_service_bundle_);
+ ProfileSyncService::InitParams init_params =
+ profile_sync_service_bundle_.CreateBasicInitParams(start_behavior,
+ builder.Build());
+
+ sync_service_.reset(new ProfileSyncService(std::move(init_params)));
+ sync_service_->RegisterDataTypeController(
+ base::MakeUnique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
+ sync_service_->AddObserver(&observer_);
+ }
+
+ void IssueTestTokens(const std::string& account_id) {
+ profile_sync_service_bundle_.auth_service()->UpdateCredentials(
+ account_id, "oauth2_login_token");
+ }
+
+ void SetError(DataTypeManager::ConfigureResult* result) {
+ syncer::DataTypeStatusTable::TypeErrorMap errors;
+ errors[syncer::BOOKMARKS] =
+ syncer::SyncError(FROM_HERE, syncer::SyncError::UNRECOVERABLE_ERROR,
+ "Error", syncer::BOOKMARKS);
+ result->data_type_status_table.UpdateFailedDataTypes(errors);
+ }
+
+ protected:
+ std::string SimulateTestUserSignin(ProfileSyncService* sync_service) {
+ std::string account_id =
+ profile_sync_service_bundle_.account_tracker()->SeedAccountInfo(kGaiaId,
+ kEmail);
+ pref_service()->SetString(prefs::kGoogleServicesAccountId, account_id);
+#if !defined(OS_CHROMEOS)
+ profile_sync_service_bundle_.signin_manager()->SignIn(kGaiaId, kEmail,
+ kDummyPassword);
+#else
+ profile_sync_service_bundle_.signin_manager()->SetAuthenticatedAccountInfo(
+ kGaiaId, kEmail);
+ if (sync_service)
+ sync_service->GoogleSigninSucceeded(account_id, kEmail, kDummyPassword);
+#endif
+ return account_id;
+ }
+
+ DataTypeManagerMock* SetUpDataTypeManager() {
+ DataTypeManagerMock* data_type_manager = new DataTypeManagerMock();
+ EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
+ .WillOnce(Return(data_type_manager));
+ return data_type_manager;
+ }
+
+ SyncBackendHostMock* SetUpSyncBackendHost() {
+ SyncBackendHostMock* sync_backend_host = new SyncBackendHostMock();
+ EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
+ .WillOnce(Return(sync_backend_host));
+ return sync_backend_host;
+ }
+
+ PrefService* pref_service() {
+ return profile_sync_service_bundle_.pref_service();
+ }
+
+ base::MessageLoop message_loop_;
+ ProfileSyncServiceBundle profile_sync_service_bundle_;
+ std::unique_ptr<ProfileSyncService> sync_service_;
+ SyncServiceObserverMock observer_;
+ syncer::DataTypeStatusTable data_type_status_table_;
+ syncer::SyncApiComponentFactoryMock* component_factory_ = nullptr;
+};
+
+class ProfileSyncServiceStartupCrosTest : public ProfileSyncServiceStartupTest {
+ public:
+ ProfileSyncServiceStartupCrosTest() {
+ CreateSyncService(ProfileSyncService::AUTO_START);
+ SimulateTestUserSignin(nullptr);
+ EXPECT_TRUE(
+ profile_sync_service_bundle_.signin_manager()->IsAuthenticated());
+ }
+};
+
+TEST_F(ProfileSyncServiceStartupTest, StartFirstTime) {
+ // We've never completed startup.
+ pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
+ CreateSyncService(ProfileSyncService::MANUAL_START);
+ SetUpSyncBackendHost();
+ DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
+ EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(0);
+
+ // Should not actually start, rather just clean things up and wait
+ // to be enabled.
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+ sync_service_->Initialize();
+
+ // Preferences should be back to defaults.
+ EXPECT_EQ(0, pref_service()->GetInt64(syncer::prefs::kSyncLastSyncedTime));
+ EXPECT_FALSE(
+ pref_service()->GetBoolean(syncer::prefs::kSyncFirstSetupComplete));
+ Mock::VerifyAndClearExpectations(data_type_manager);
+
+ // Then start things up.
+ EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(1);
+ EXPECT_CALL(*data_type_manager, state())
+ .WillOnce(Return(DataTypeManager::CONFIGURED))
+ .WillOnce(Return(DataTypeManager::CONFIGURED));
+ EXPECT_CALL(*data_type_manager, Stop()).Times(1);
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+
+ auto sync_blocker = sync_service_->GetSetupInProgressHandle();
+
+ // Simulate successful signin as test_user.
+ std::string account_id = SimulateTestUserSignin(sync_service_.get());
+ // Create some tokens in the token service.
+ IssueTestTokens(account_id);
+
+ // Simulate the UI telling sync it has finished setting up.
+ sync_blocker.reset();
+ sync_service_->SetFirstSetupComplete();
+ EXPECT_TRUE(sync_service_->IsSyncActive());
+}
+
+// TODO(pavely): Reenable test once android is switched to oauth2.
+TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartNoCredentials) {
+ // We've never completed startup.
+ pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
+ CreateSyncService(ProfileSyncService::MANUAL_START);
+
+ // Should not actually start, rather just clean things up and wait
+ // to be enabled.
+ EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+ sync_service_->Initialize();
+
+ // Preferences should be back to defaults.
+ EXPECT_EQ(0, pref_service()->GetInt64(syncer::prefs::kSyncLastSyncedTime));
+ EXPECT_FALSE(
+ pref_service()->GetBoolean(syncer::prefs::kSyncFirstSetupComplete));
+
+ // Then start things up.
+ auto sync_blocker = sync_service_->GetSetupInProgressHandle();
+
+ // Simulate successful signin as test_user.
+ std::string account_id = SimulateTestUserSignin(sync_service_.get());
+
+ profile_sync_service_bundle_.auth_service()->LoadCredentials(account_id);
+
+ sync_blocker.reset();
+ // ProfileSyncService should try to start by requesting access token.
+ // This request should fail as login token was not issued.
+ EXPECT_FALSE(sync_service_->IsSyncActive());
+ EXPECT_EQ(GoogleServiceAuthError::USER_NOT_SIGNED_UP,
+ sync_service_->GetAuthError().state());
+}
+
+// TODO(pavely): Reenable test once android is switched to oauth2.
+TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartInvalidCredentials) {
+ CreateSyncService(ProfileSyncService::MANUAL_START);
+ std::string account_id = SimulateTestUserSignin(sync_service_.get());
+ SyncBackendHostMock* mock_sbh = SetUpSyncBackendHost();
+
+ // Tell the backend to stall while downloading control types (simulating an
+ // auth error).
+ mock_sbh->set_fail_initial_download(true);
+
+ DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
+ EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(0);
+
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+ sync_service_->Initialize();
+ EXPECT_FALSE(sync_service_->IsSyncActive());
+ Mock::VerifyAndClearExpectations(data_type_manager);
+
+ // Update the credentials, unstalling the backend.
+ EXPECT_CALL(*data_type_manager, Configure(_, _));
+ EXPECT_CALL(*data_type_manager, state())
+ .WillRepeatedly(Return(DataTypeManager::CONFIGURED));
+ EXPECT_CALL(*data_type_manager, Stop()).Times(1);
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+ auto sync_blocker = sync_service_->GetSetupInProgressHandle();
+
+ // Simulate successful signin.
+ SimulateTestUserSignin(sync_service_.get());
+
+ sync_blocker.reset();
+
+ // Verify we successfully finish startup and configuration.
+ EXPECT_TRUE(sync_service_->IsSyncActive());
+}
+
+TEST_F(ProfileSyncServiceStartupCrosTest, StartCrosNoCredentials) {
+ EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _)).Times(0);
+ pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+
+ sync_service_->Initialize();
+ // Sync should not start because there are no tokens yet.
+ EXPECT_FALSE(sync_service_->IsSyncActive());
+ sync_service_->SetFirstSetupComplete();
+
+ // Sync should not start because there are still no tokens.
+ EXPECT_FALSE(sync_service_->IsSyncActive());
+}
+
+TEST_F(ProfileSyncServiceStartupCrosTest, StartFirstTime) {
+ SetUpSyncBackendHost();
+ DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
+ pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
+ EXPECT_CALL(*data_type_manager, Configure(_, _));
+ EXPECT_CALL(*data_type_manager, state())
+ .WillRepeatedly(Return(DataTypeManager::CONFIGURED));
+ EXPECT_CALL(*data_type_manager, Stop());
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+
+ IssueTestTokens(
+ profile_sync_service_bundle_.account_tracker()->PickAccountIdForAccount(
+ "12345", kEmail));
+ sync_service_->Initialize();
+ EXPECT_TRUE(sync_service_->IsSyncActive());
+}
+
+TEST_F(ProfileSyncServiceStartupTest, StartNormal) {
+ // Pre load the tokens
+ CreateSyncService(ProfileSyncService::MANUAL_START);
+ std::string account_id = SimulateTestUserSignin(sync_service_.get());
+ sync_service_->SetFirstSetupComplete();
+ SetUpSyncBackendHost();
+ DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
+ EXPECT_CALL(*data_type_manager, Configure(_, _));
+ EXPECT_CALL(*data_type_manager, state())
+ .WillRepeatedly(Return(DataTypeManager::CONFIGURED));
+ EXPECT_CALL(*data_type_manager, Stop()).Times(1);
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+
+ IssueTestTokens(account_id);
+
+ sync_service_->Initialize();
+}
+
+// Test that we can recover from a case where a bug in the code resulted in
+// OnUserChoseDatatypes not being properly called and datatype preferences
+// therefore being left unset.
+TEST_F(ProfileSyncServiceStartupTest, StartRecoverDatatypePrefs) {
+ // Clear the datatype preference fields (simulating bug 154940).
+ pref_service()->ClearPref(syncer::prefs::kSyncKeepEverythingSynced);
+ syncer::ModelTypeSet user_types = syncer::UserTypes();
+ for (syncer::ModelTypeSet::Iterator iter = user_types.First(); iter.Good();
+ iter.Inc()) {
+ pref_service()->ClearPref(
+ syncer::SyncPrefs::GetPrefNameForDataType(iter.Get()));
+ }
+
+ // Pre load the tokens
+ CreateSyncService(ProfileSyncService::MANUAL_START);
+ std::string account_id = SimulateTestUserSignin(sync_service_.get());
+ sync_service_->SetFirstSetupComplete();
+ SetUpSyncBackendHost();
+ DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
+ EXPECT_CALL(*data_type_manager, Configure(_, _));
+ EXPECT_CALL(*data_type_manager, state())
+ .WillRepeatedly(Return(DataTypeManager::CONFIGURED));
+ EXPECT_CALL(*data_type_manager, Stop()).Times(1);
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+
+ IssueTestTokens(account_id);
+ sync_service_->Initialize();
+
+ EXPECT_TRUE(
+ pref_service()->GetBoolean(syncer::prefs::kSyncKeepEverythingSynced));
+}
+
+// Verify that the recovery of datatype preferences doesn't overwrite a valid
+// case where only bookmarks are enabled.
+TEST_F(ProfileSyncServiceStartupTest, StartDontRecoverDatatypePrefs) {
+ // Explicitly set Keep Everything Synced to false and have only bookmarks
+ // enabled.
+ pref_service()->SetBoolean(syncer::prefs::kSyncKeepEverythingSynced, false);
+
+ // Pre load the tokens
+ CreateSyncService(ProfileSyncService::MANUAL_START);
+ std::string account_id = SimulateTestUserSignin(sync_service_.get());
+ sync_service_->SetFirstSetupComplete();
+ SetUpSyncBackendHost();
+ DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
+ EXPECT_CALL(*data_type_manager, Configure(_, _));
+ EXPECT_CALL(*data_type_manager, state())
+ .WillRepeatedly(Return(DataTypeManager::CONFIGURED));
+ EXPECT_CALL(*data_type_manager, Stop()).Times(1);
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+ IssueTestTokens(account_id);
+ sync_service_->Initialize();
+
+ EXPECT_FALSE(
+ pref_service()->GetBoolean(syncer::prefs::kSyncKeepEverythingSynced));
+}
+
+TEST_F(ProfileSyncServiceStartupTest, ManagedStartup) {
+ // Service should not be started by Initialize() since it's managed.
+ pref_service()->SetString(prefs::kGoogleServicesAccountId, kEmail);
+ CreateSyncService(ProfileSyncService::MANUAL_START);
+
+ // Disable sync through policy.
+ pref_service()->SetBoolean(syncer::prefs::kSyncManaged, true);
+ EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+
+ sync_service_->Initialize();
+}
+
+TEST_F(ProfileSyncServiceStartupTest, SwitchManaged) {
+ CreateSyncService(ProfileSyncService::MANUAL_START);
+ std::string account_id = SimulateTestUserSignin(sync_service_.get());
+ sync_service_->SetFirstSetupComplete();
+ SetUpSyncBackendHost();
+ DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
+ EXPECT_CALL(*data_type_manager, Configure(_, _));
+ EXPECT_CALL(*data_type_manager, state())
+ .WillRepeatedly(Return(DataTypeManager::CONFIGURED));
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+ IssueTestTokens(account_id);
+ sync_service_->Initialize();
+ EXPECT_TRUE(sync_service_->IsBackendInitialized());
+ EXPECT_TRUE(sync_service_->IsSyncActive());
+
+ // The service should stop when switching to managed mode.
+ Mock::VerifyAndClearExpectations(data_type_manager);
+ EXPECT_CALL(*data_type_manager, state())
+ .WillOnce(Return(DataTypeManager::CONFIGURED));
+ EXPECT_CALL(*data_type_manager, Stop()).Times(1);
+ pref_service()->SetBoolean(syncer::prefs::kSyncManaged, true);
+ EXPECT_FALSE(sync_service_->IsBackendInitialized());
+ // Note that PSS no longer references |data_type_manager| after stopping.
+
+ // When switching back to unmanaged, the state should change but sync should
+ // not start automatically because IsFirstSetupComplete() will be false.
+ // A new DataTypeManager should not be created.
+ Mock::VerifyAndClearExpectations(data_type_manager);
+ EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
+ .Times(0);
+ pref_service()->ClearPref(syncer::prefs::kSyncManaged);
+ EXPECT_FALSE(sync_service_->IsBackendInitialized());
+ EXPECT_FALSE(sync_service_->IsSyncActive());
+}
+
+TEST_F(ProfileSyncServiceStartupTest, StartFailure) {
+ CreateSyncService(ProfileSyncService::MANUAL_START);
+ std::string account_id = SimulateTestUserSignin(sync_service_.get());
+ sync_service_->SetFirstSetupComplete();
+ SetUpSyncBackendHost();
+ DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
+ DataTypeManager::ConfigureStatus status = DataTypeManager::ABORTED;
+ DataTypeManager::ConfigureResult result(status, syncer::ModelTypeSet());
+ EXPECT_CALL(*data_type_manager, Configure(_, _))
+ .WillRepeatedly(
+ DoAll(InvokeOnConfigureStart(sync_service_.get()),
+ InvokeOnConfigureDone(
+ sync_service_.get(),
+ base::Bind(&ProfileSyncServiceStartupTest::SetError,
+ base::Unretained(this)),
+ result)));
+ EXPECT_CALL(*data_type_manager, state())
+ .WillOnce(Return(DataTypeManager::STOPPED));
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+ IssueTestTokens(account_id);
+ sync_service_->Initialize();
+ EXPECT_TRUE(sync_service_->HasUnrecoverableError());
+}
+
+TEST_F(ProfileSyncServiceStartupTest, StartDownloadFailed) {
+ // Pre load the tokens
+ CreateSyncService(ProfileSyncService::MANUAL_START);
+ std::string account_id = SimulateTestUserSignin(sync_service_.get());
+ SyncBackendHostMock* mock_sbh = SetUpSyncBackendHost();
+ mock_sbh->set_fail_initial_download(true);
+
+ pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
+
+ EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
+ sync_service_->Initialize();
+
+ auto sync_blocker = sync_service_->GetSetupInProgressHandle();
+ IssueTestTokens(account_id);
+ sync_blocker.reset();
+ EXPECT_FALSE(sync_service_->IsSyncActive());
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc b/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc
new file mode 100644
index 00000000000..cded15d4c9c
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_service_typed_url_unittest.cc
@@ -0,0 +1,1055 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/browser_sync/abstract_profile_sync_service_test.h"
+#include "components/browser_sync/test_profile_sync_service.h"
+#include "components/history/core/browser/history_backend.h"
+#include "components/history/core/browser/history_backend_client.h"
+#include "components/history/core/browser/history_backend_notifier.h"
+#include "components/history/core/browser/history_db_task.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/typed_url_data_type_controller.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/sync/api/data_type_error_handler_mock.h"
+#include "components/sync/core/read_node.h"
+#include "components/sync/core/read_transaction.h"
+#include "components/sync/core/write_node.h"
+#include "components/sync/core/write_transaction.h"
+#include "components/sync/driver/data_type_manager_impl.h"
+#include "components/sync/protocol/typed_url_specifics.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using history::HistoryBackend;
+using history::HistoryBackendNotifier;
+using history::TypedUrlSyncableService;
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::_;
+
+namespace browser_sync {
+
+namespace {
+
+const char kDummySavingBrowserHistoryDisabled[] = "dummyPref";
+
+// Visits with this timestamp are treated as expired.
+static const int EXPIRED_VISIT = -1;
+
+ACTION(ReturnNewDataTypeManager) {
+ return new syncer::DataTypeManagerImpl(arg0, arg1, arg2, arg3, arg4);
+}
+
+class HistoryBackendMock : public HistoryBackend {
+ public:
+ HistoryBackendMock()
+ : HistoryBackend(nullptr, nullptr, base::ThreadTaskRunnerHandle::Get()) {}
+ bool IsExpiredVisitTime(const base::Time& time) override {
+ return time.ToInternalValue() == EXPIRED_VISIT;
+ }
+ MOCK_METHOD1(GetAllTypedURLs, bool(history::URLRows* entries));
+ MOCK_METHOD3(GetMostRecentVisitsForURL,
+ bool(history::URLID id,
+ int max_visits,
+ history::VisitVector* visits));
+ MOCK_METHOD2(UpdateURL, bool(history::URLID id, const history::URLRow& url));
+ MOCK_METHOD3(AddVisits,
+ bool(const GURL& url,
+ const std::vector<history::VisitInfo>& visits,
+ history::VisitSource visit_source));
+ MOCK_METHOD2(GetURL, bool(const GURL& url_id, history::URLRow* url_row));
+ MOCK_METHOD2(SetPageTitle,
+ void(const GURL& url, const base::string16& title));
+ MOCK_METHOD1(DeleteURL, void(const GURL& url));
+
+ private:
+ friend class ProfileSyncServiceTypedUrlTest;
+
+ virtual ~HistoryBackendMock() {}
+};
+
+class HistoryServiceMock : public history::HistoryService {
+ public:
+ HistoryServiceMock() : history::HistoryService(), backend_(nullptr) {}
+
+ base::CancelableTaskTracker::TaskId ScheduleDBTask(
+ std::unique_ptr<history::HistoryDBTask> task,
+ base::CancelableTaskTracker* tracker) override {
+ // Explicitly copy out the raw pointer -- compilers might decide to
+ // evaluate task.release() before the arguments for the first Bind().
+ history::HistoryDBTask* task_raw = task.get();
+ task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind(&HistoryServiceMock::RunTaskOnDBThread,
+ base::Unretained(this), task_raw),
+ base::Bind(&base::DeletePointer<history::HistoryDBTask>,
+ task.release()));
+ return base::CancelableTaskTracker::kBadTaskId; // unused
+ }
+
+ ~HistoryServiceMock() override {}
+
+ void set_task_runner(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ DCHECK(task_runner.get());
+ task_runner_ = task_runner;
+ }
+
+ void set_backend(scoped_refptr<history::HistoryBackend> backend) {
+ backend_ = backend;
+ }
+
+ private:
+ void RunTaskOnDBThread(history::HistoryDBTask* task) {
+ EXPECT_TRUE(task->RunOnDBThread(backend_.get(), NULL));
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ scoped_refptr<history::HistoryBackend> backend_;
+};
+
+class TestTypedUrlSyncableService : public TypedUrlSyncableService {
+ // TODO(gangwu): remove TestProfileSyncService or even remove whole test
+ // suite, and make sure typed_url_syncable_service_unittest.cc and the various
+ // typed url integration tests.
+ public:
+ explicit TestTypedUrlSyncableService(history::HistoryBackend* history_backend)
+ : TypedUrlSyncableService(history_backend) {}
+
+ static void WriteToSyncNode(const history::URLRow& url,
+ const history::VisitVector& visits,
+ syncer::WriteNode* node) {
+ sync_pb::TypedUrlSpecifics typed_url;
+ WriteToTypedUrlSpecifics(url, visits, &typed_url);
+ node->SetTypedUrlSpecifics(typed_url);
+ }
+
+ protected:
+ // Don't clear error stats - that way we can verify their values in our
+ // tests.
+ void ClearErrorStats() override {}
+};
+
+class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
+ public:
+ void AddTypedUrlSyncNode(const history::URLRow& url,
+ const history::VisitVector& visits) {
+ syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare());
+
+ syncer::WriteNode node(&trans);
+ std::string tag = url.url().spec();
+ syncer::WriteNode::InitUniqueByCreationResult result =
+ node.InitUniqueByCreation(syncer::TYPED_URLS, tag);
+ ASSERT_EQ(syncer::WriteNode::INIT_SUCCESS, result);
+ TestTypedUrlSyncableService::WriteToSyncNode(url, visits, &node);
+ }
+
+ protected:
+ ProfileSyncServiceTypedUrlTest() {
+ profile_sync_service_bundle()
+ ->pref_service()
+ ->registry()
+ ->RegisterBooleanPref(kDummySavingBrowserHistoryDisabled, false);
+
+ data_type_thread()->Start();
+ base::RunLoop run_loop;
+ data_type_thread()->task_runner()->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&ProfileSyncServiceTypedUrlTest::CreateHistoryService,
+ base::Unretained(this)),
+ run_loop.QuitClosure());
+ run_loop.Run();
+ history_service_ = base::WrapUnique(new HistoryServiceMock);
+ history_service_->set_task_runner(data_type_thread()->task_runner());
+ history_service_->set_backend(history_backend_);
+
+ ProfileSyncServiceBundle::SyncClientBuilder builder(
+ profile_sync_service_bundle());
+ builder.SetHistoryService(history_service_.get());
+ builder.SetSyncServiceCallback(GetSyncServiceCallback());
+ builder.SetSyncableServiceCallback(
+ base::Bind(&ProfileSyncServiceTypedUrlTest::GetSyncableServiceForType,
+ base::Unretained(this)));
+ builder.set_activate_model_creation();
+ sync_client_ = builder.Build();
+ }
+
+ void CreateHistoryService() {
+ history_backend_ = new HistoryBackendMock();
+ syncable_service_ =
+ base::MakeUnique<TestTypedUrlSyncableService>(history_backend_.get());
+ }
+
+ void DeleteSyncableService() {
+ syncable_service_.reset();
+ history_backend_ = nullptr;
+ }
+
+ ~ProfileSyncServiceTypedUrlTest() override {
+ history_service_->Shutdown();
+
+ // Request stop to get deletion tasks related to the HistoryService posted
+ // on the Sync thread. It is important to not Shutdown at this moment,
+ // because after shutdown the Sync thread is not returned to the sync
+ // service, so we could not get the thread's message loop to wait for the
+ // deletions to be finished.
+ sync_service()->RequestStop(syncer::SyncService::CLEAR_DATA);
+ // Spin the sync thread.
+ {
+ base::RunLoop run_loop;
+ sync_service()->GetSyncLoopForTest()->task_runner()->PostTaskAndReply(
+ FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
+ // Spin the loop again for deletion tasks posted from the Sync thread.
+ base::RunLoop().RunUntilIdle();
+
+ {
+ base::RunLoop run_loop;
+ data_type_thread()->task_runner()->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&ProfileSyncServiceTypedUrlTest::DeleteSyncableService,
+ base::Unretained(this)),
+ run_loop.QuitClosure());
+ run_loop.Run();
+ }
+ }
+
+ TypedUrlSyncableService* StartSyncService(const base::Closure& callback) {
+ if (!sync_service()) {
+ std::string account_id =
+ profile_sync_service_bundle()->account_tracker()->SeedAccountInfo(
+ "gaia_id", "test");
+ SigninManagerBase* signin =
+ profile_sync_service_bundle()->signin_manager();
+ signin->SetAuthenticatedAccountInfo("gaia_id", "test");
+ CreateSyncService(std::move(sync_client_), callback);
+ EXPECT_CALL(*profile_sync_service_bundle()->component_factory(),
+ CreateDataTypeManager(_, _, _, _, _))
+ .WillOnce(ReturnNewDataTypeManager());
+
+ profile_sync_service_bundle()->auth_service()->UpdateCredentials(
+ account_id, "oauth2_login_token");
+
+ sync_service()->RegisterDataTypeController(
+ base::MakeUnique<TypedUrlDataTypeController>(
+ base::Bind(&base::DoNothing), sync_service()->GetSyncClient(),
+ kDummySavingBrowserHistoryDisabled));
+
+ sync_service()->Initialize();
+ base::RunLoop().Run();
+ }
+ return syncable_service_.get();
+ }
+
+ void GetTypedUrlsFromSyncDB(history::URLRows* urls) {
+ urls->clear();
+ syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
+ syncer::ReadNode typed_url_root(&trans);
+ if (typed_url_root.InitTypeRoot(syncer::TYPED_URLS) !=
+ syncer::BaseNode::INIT_OK)
+ return;
+
+ int64_t child_id = typed_url_root.GetFirstChildId();
+ while (child_id != syncer::kInvalidId) {
+ syncer::ReadNode child_node(&trans);
+ if (child_node.InitByIdLookup(child_id) != syncer::BaseNode::INIT_OK)
+ return;
+
+ const sync_pb::TypedUrlSpecifics& typed_url(
+ child_node.GetTypedUrlSpecifics());
+ history::URLRow new_url(GURL(typed_url.url()));
+
+ new_url.set_title(base::UTF8ToUTF16(typed_url.title()));
+ DCHECK(typed_url.visits_size());
+ DCHECK_EQ(typed_url.visits_size(), typed_url.visit_transitions_size());
+ new_url.set_last_visit(base::Time::FromInternalValue(
+ typed_url.visits(typed_url.visits_size() - 1)));
+ new_url.set_hidden(typed_url.hidden());
+
+ urls->push_back(new_url);
+ child_id = child_node.GetSuccessorId();
+ }
+ }
+
+ void SetIdleChangeProcessorExpectations() {
+ EXPECT_CALL((history_backend()), SetPageTitle(_, _)).Times(0);
+ EXPECT_CALL((history_backend()), UpdateURL(_, _)).Times(0);
+ EXPECT_CALL((history_backend()), GetURL(_, _)).Times(0);
+ EXPECT_CALL((history_backend()), DeleteURL(_)).Times(0);
+ }
+
+ void SendNotification(const base::Closure& task) {
+ data_type_thread()->task_runner()->PostTaskAndReply(
+ FROM_HERE, task,
+ base::Bind(&base::MessageLoop::QuitNow,
+ base::Unretained(base::MessageLoop::current())));
+ base::RunLoop().Run();
+ }
+
+ void SendNotificationURLVisited(ui::PageTransition transition,
+ const history::URLRow& row) {
+ base::Time visit_time;
+ history::RedirectList redirects;
+ SendNotification(base::Bind(&HistoryBackendNotifier::NotifyURLVisited,
+ base::Unretained(history_backend_.get()),
+ transition, row, redirects, visit_time));
+ }
+
+ void SendNotificationURLsModified(const history::URLRows& rows) {
+ SendNotification(base::Bind(&HistoryBackendNotifier::NotifyURLsModified,
+ base::Unretained(history_backend_.get()),
+ rows));
+ }
+
+ void SendNotificationURLsDeleted(bool all_history,
+ bool expired,
+ const history::URLRows& deleted_rows,
+ const std::set<GURL>& favicon_urls) {
+ SendNotification(base::Bind(&HistoryBackendNotifier::NotifyURLsDeleted,
+ base::Unretained(history_backend_.get()),
+ all_history, expired, deleted_rows,
+ favicon_urls));
+ }
+
+ static bool URLsEqual(const history::URLRow& lhs,
+ const history::URLRow& rhs) {
+ // Only verify the fields we explicitly sync (i.e. don't verify typed_count
+ // or visit_count because we rely on the history DB to manage those values
+ // and they are left unchanged by HistoryBackendMock).
+ return (lhs.url().spec().compare(rhs.url().spec()) == 0) &&
+ (lhs.title().compare(rhs.title()) == 0) &&
+ (lhs.last_visit() == rhs.last_visit()) &&
+ (lhs.hidden() == rhs.hidden());
+ }
+
+ static history::URLRow MakeTypedUrlEntry(const char* url,
+ const char* title,
+ int typed_count,
+ int64_t last_visit,
+ bool hidden,
+ history::VisitVector* visits) {
+ // Give each URL a unique ID, to mimic the behavior of the real database.
+ static int unique_url_id = 0;
+ GURL gurl(url);
+ history::URLRow history_url(gurl, ++unique_url_id);
+ history_url.set_title(base::UTF8ToUTF16(title));
+ history_url.set_typed_count(typed_count);
+ history_url.set_last_visit(base::Time::FromInternalValue(last_visit));
+ history_url.set_hidden(hidden);
+ visits->push_back(history::VisitRow(history_url.id(),
+ history_url.last_visit(), 0,
+ ui::PAGE_TRANSITION_TYPED, 0));
+ history_url.set_visit_count(visits->size());
+ return history_url;
+ }
+
+ base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
+ syncer::ModelType type) {
+ DCHECK_EQ(syncer::TYPED_URLS, type);
+ return syncable_service_->AsWeakPtr();
+ }
+
+ HistoryBackendMock& history_backend() { return *history_backend_.get(); }
+
+ private:
+ scoped_refptr<HistoryBackendMock> history_backend_;
+ std::unique_ptr<HistoryServiceMock> history_service_;
+ syncer::DataTypeErrorHandlerMock error_handler_;
+ std::unique_ptr<TestTypedUrlSyncableService> syncable_service_;
+ std::unique_ptr<syncer::FakeSyncClient> sync_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceTypedUrlTest);
+};
+
+void AddTypedUrlEntries(ProfileSyncServiceTypedUrlTest* test,
+ const history::URLRows& entries) {
+ test->CreateRoot(syncer::TYPED_URLS);
+ for (size_t i = 0; i < entries.size(); ++i) {
+ history::VisitVector visits;
+ visits.push_back(history::VisitRow(entries[i].id(), entries[i].last_visit(),
+ 0, ui::PageTransitionFromInt(0), 0));
+ test->AddTypedUrlSyncNode(entries[i], visits);
+ }
+}
+
+} // namespace
+
+TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeEmptySync) {
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true));
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ TypedUrlSyncableService* syncable_service =
+ StartSyncService(create_root.callback());
+ history::URLRows sync_entries;
+ GetTypedUrlsFromSyncDB(&sync_entries);
+ EXPECT_EQ(0U, sync_entries.size());
+ ASSERT_EQ(0, syncable_service->GetErrorPercentage());
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeEmptySync) {
+ history::URLRows entries;
+ history::VisitVector visits;
+ entries.push_back(
+ MakeTypedUrlEntry("http://foo.com", "bar", 2, 15, false, &visits));
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true)));
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ TypedUrlSyncableService* syncable_service =
+ StartSyncService(create_root.callback());
+ history::URLRows sync_entries;
+ GetTypedUrlsFromSyncDB(&sync_entries);
+ ASSERT_EQ(1U, sync_entries.size());
+ EXPECT_TRUE(URLsEqual(entries[0], sync_entries[0]));
+ ASSERT_EQ(0, syncable_service->GetErrorPercentage());
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeErrorReadingVisits) {
+ history::URLRows entries;
+ history::VisitVector visits;
+ history::URLRow native_entry1(
+ MakeTypedUrlEntry("http://foo.com", "bar", 2, 15, false, &visits));
+ history::URLRow native_entry2(
+ MakeTypedUrlEntry("http://foo2.com", "bar", 3, 15, false, &visits));
+ entries.push_back(native_entry1);
+ entries.push_back(native_entry2);
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
+ // Return an error from GetMostRecentVisitsForURL() for the second URL.
+ EXPECT_CALL((history_backend()),
+ GetMostRecentVisitsForURL(native_entry1.id(), _, _))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL((history_backend()),
+ GetMostRecentVisitsForURL(native_entry2.id(), _, _))
+ .WillRepeatedly(Return(false));
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+ history::URLRows sync_entries;
+ GetTypedUrlsFromSyncDB(&sync_entries);
+ ASSERT_EQ(1U, sync_entries.size());
+ EXPECT_TRUE(URLsEqual(native_entry1, sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithBlankEmptySync) {
+ std::vector<history::URLRow> entries;
+ history::VisitVector visits;
+ // Add an empty URL.
+ entries.push_back(MakeTypedUrlEntry("", "bar", 2, 15, false, &visits));
+ entries.push_back(
+ MakeTypedUrlEntry("http://foo.com", "bar", 2, 15, false, &visits));
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(DoAll(SetArgumentPointee<2>(visits), Return(true)));
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+ std::vector<history::URLRow> sync_entries;
+ GetTypedUrlsFromSyncDB(&sync_entries);
+ // The empty URL should be ignored.
+ ASSERT_EQ(1U, sync_entries.size());
+ EXPECT_TRUE(URLsEqual(entries[1], sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncNoMerge) {
+ history::VisitVector native_visits;
+ history::VisitVector sync_visits;
+ history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
+ 2, 15, false, &native_visits));
+ history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry", 3,
+ 16, false, &sync_visits));
+
+ history::URLRows native_entries;
+ native_entries.push_back(native_entry);
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
+ EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED))
+ .WillRepeatedly(Return(true));
+
+ history::URLRows sync_entries;
+ sync_entries.push_back(sync_entry);
+
+ EXPECT_CALL((history_backend()), UpdateURL(_, _))
+ .WillRepeatedly(Return(true));
+ StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
+
+ std::map<std::string, history::URLRow> expected;
+ expected[native_entry.url().spec()] = native_entry;
+ expected[sync_entry.url().spec()] = sync_entry;
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+
+ EXPECT_TRUE(new_sync_entries.size() == expected.size());
+ for (history::URLRows::iterator entry = new_sync_entries.begin();
+ entry != new_sync_entries.end(); ++entry) {
+ EXPECT_TRUE(URLsEqual(expected[entry->url().spec()], *entry));
+ }
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeExpiredSync) {
+ history::VisitVector sync_visits;
+ history::URLRow sync_entry(MakeTypedUrlEntry(
+ "http://sync.com", "entry", 3, EXPIRED_VISIT, false, &sync_visits));
+ history::URLRows sync_entries;
+ sync_entries.push_back(sync_entry);
+
+ // Since all our URLs are expired, no backend calls to add new URLs will be
+ // made.
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true));
+ SetIdleChangeProcessorExpectations();
+
+ StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncMerge) {
+ history::VisitVector native_visits;
+ history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
+ 2, 15, false, &native_visits));
+ history::VisitVector sync_visits;
+ history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "name", 1,
+ 17, false, &sync_visits));
+ history::VisitVector merged_visits;
+ merged_visits.push_back(
+ history::VisitRow(sync_entry.id(), base::Time::FromInternalValue(15), 0,
+ ui::PageTransitionFromInt(0), 0));
+
+ history::URLRow merged_entry(MakeTypedUrlEntry("http://native.com", "name", 2,
+ 17, false, &merged_visits));
+
+ history::URLRows native_entries;
+ native_entries.push_back(native_entry);
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
+ EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED))
+ .WillRepeatedly(Return(true));
+
+ history::URLRows sync_entries;
+ sync_entries.push_back(sync_entry);
+
+ EXPECT_CALL((history_backend()), UpdateURL(_, _))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL((history_backend()), SetPageTitle(_, _)).WillRepeatedly(Return());
+ StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(merged_entry, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeWithErrorHasSyncMerge) {
+ history::VisitVector native_visits;
+ history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "native",
+ 2, 15, false, &native_visits));
+ history::VisitVector sync_visits;
+ history::URLRow sync_entry(MakeTypedUrlEntry("http://native.com", "sync", 1,
+ 17, false, &sync_visits));
+
+ history::URLRows native_entries;
+ native_entries.push_back(native_entry);
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
+ // Return an error getting the visits for the native URL.
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL((history_backend()), GetURL(_, _))
+ .WillRepeatedly(DoAll(SetArgumentPointee<1>(native_entry), Return(true)));
+ EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED))
+ .WillRepeatedly(Return(true));
+
+ history::URLRows sync_entries;
+ sync_entries.push_back(sync_entry);
+
+ EXPECT_CALL((history_backend()), UpdateURL(_, _))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL((history_backend()), SetPageTitle(_, _)).WillRepeatedly(Return());
+ StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(sync_entry, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAdd) {
+ history::VisitVector added_visits;
+ history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry", 2,
+ 15, false, &added_visits));
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
+
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ history::URLRows changed_urls;
+ changed_urls.push_back(added_entry);
+ SendNotificationURLsModified(changed_urls);
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddWithBlank) {
+ history::VisitVector added_visits;
+ history::URLRow empty_entry(
+ MakeTypedUrlEntry("", "entry", 2, 15, false, &added_visits));
+ history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry", 2,
+ 15, false, &added_visits));
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
+
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ history::URLRows changed_urls;
+ changed_urls.push_back(empty_entry);
+ changed_urls.push_back(added_entry);
+ SendNotificationURLsModified(changed_urls);
+
+ std::vector<history::URLRow> new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdate) {
+ history::VisitVector original_visits;
+ history::URLRow original_entry(MakeTypedUrlEntry(
+ "http://mine.com", "entry", 2, 15, false, &original_visits));
+ history::URLRows original_entries;
+ original_entries.push_back(original_entry);
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(original_visits), Return(true)));
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ history::VisitVector updated_visits;
+ history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry", 7,
+ 17, false, &updated_visits));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(updated_visits), Return(true)));
+
+ history::URLRows changed_urls;
+ changed_urls.push_back(updated_entry);
+ SendNotificationURLsModified(changed_urls);
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeAddFromVisit) {
+ history::VisitVector added_visits;
+ history::URLRow added_entry(MakeTypedUrlEntry("http://added.com", "entry", 2,
+ 15, false, &added_visits));
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_)).WillOnce(Return(true));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(added_visits), Return(true)));
+
+ SetIdleChangeProcessorExpectations();
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, added_entry);
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(added_entry, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeUpdateFromVisit) {
+ history::VisitVector original_visits;
+ history::URLRow original_entry(MakeTypedUrlEntry(
+ "http://mine.com", "entry", 2, 15, false, &original_visits));
+ history::URLRows original_entries;
+ original_entries.push_back(original_entry);
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(original_visits), Return(true)));
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ history::VisitVector updated_visits;
+ history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry", 7,
+ 17, false, &updated_visits));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(updated_visits), Return(true)));
+
+ SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, updated_entry);
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(updated_entry, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserIgnoreChangeUpdateFromVisit) {
+ history::VisitVector original_visits;
+ history::URLRow original_entry(MakeTypedUrlEntry(
+ "http://mine.com", "entry", 2, 15, false, &original_visits));
+ history::URLRows original_entries;
+ original_entries.push_back(original_entry);
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<2>(original_visits), Return(true)));
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
+
+ history::VisitVector updated_visits;
+ history::URLRow updated_entry(MakeTypedUrlEntry("http://mine.com", "entry", 7,
+ 15, false, &updated_visits));
+
+ // Should ignore this change because it's not TYPED.
+ SendNotificationURLVisited(ui::PAGE_TRANSITION_RELOAD, updated_entry);
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+
+ // Should be no changes to the sync DB from this notification.
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
+
+ // Now, try updating it with a large number of visits not divisible by 10
+ // (should ignore this visit).
+ history::URLRow twelve_visits(MakeTypedUrlEntry(
+ "http://mine.com", "entry", 12, 15, false, &updated_visits));
+ SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, twelve_visits);
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+
+ // Should be no changes to the sync DB from this notification.
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(original_entry, new_sync_entries[0]));
+
+ // Now, try updating it with a large number of visits that is divisible by 10
+ // (should *not* be ignored).
+ history::URLRow twenty_visits(MakeTypedUrlEntry(
+ "http://mine.com", "entry", 20, 15, false, &updated_visits));
+ SendNotificationURLVisited(ui::PAGE_TRANSITION_TYPED, twenty_visits);
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(twenty_visits, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemove) {
+ history::VisitVector original_visits1;
+ history::URLRow original_entry1(MakeTypedUrlEntry(
+ "http://mine.com", "entry", 2, 15, false, &original_visits1));
+ history::VisitVector original_visits2;
+ history::URLRow original_entry2(MakeTypedUrlEntry(
+ "http://mine2.com", "entry2", 3, 15, false, &original_visits2));
+ history::URLRows original_entries;
+ original_entries.push_back(original_entry1);
+ original_entries.push_back(original_entry2);
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<2>(original_visits1), Return(true)));
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ history::URLRows rows;
+ rows.push_back(history::URLRow(GURL("http://mine.com")));
+ SendNotificationURLsDeleted(false, false, rows, std::set<GURL>());
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(original_entry2, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveExpired) {
+ history::VisitVector original_visits1;
+ history::URLRow original_entry1(MakeTypedUrlEntry(
+ "http://mine.com", "entry", 2, 15, false, &original_visits1));
+ history::VisitVector original_visits2;
+ history::URLRow original_entry2(MakeTypedUrlEntry(
+ "http://mine2.com", "entry2", 3, 15, false, &original_visits2));
+ history::URLRows original_entries;
+ original_entries.push_back(original_entry1);
+ original_entries.push_back(original_entry2);
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<2>(original_visits1), Return(true)));
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ // Setting expired=true should cause the sync code to ignore this deletion.
+ history::URLRows rows;
+ rows.push_back(history::URLRow(GURL("http://mine.com")));
+ SendNotificationURLsDeleted(false, true, rows, std::set<GURL>());
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ // Both URLs should still be there.
+ ASSERT_EQ(2U, new_sync_entries.size());
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, ProcessUserChangeRemoveAll) {
+ history::VisitVector original_visits1;
+ history::URLRow original_entry1(MakeTypedUrlEntry(
+ "http://mine.com", "entry", 2, 15, false, &original_visits1));
+ history::VisitVector original_visits2;
+ history::URLRow original_entry2(MakeTypedUrlEntry(
+ "http://mine2.com", "entry2", 3, 15, false, &original_visits2));
+ history::URLRows original_entries;
+ original_entries.push_back(original_entry1);
+ original_entries.push_back(original_entry2);
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<2>(original_visits1), Return(true)));
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(2U, new_sync_entries.size());
+
+ SendNotificationURLsDeleted(true, false, history::URLRows(),
+ std::set<GURL>());
+
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+ ASSERT_EQ(0U, new_sync_entries.size());
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, FailWriteToHistoryBackend) {
+ history::VisitVector native_visits;
+ history::VisitVector sync_visits;
+ history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
+ 2, 15, false, &native_visits));
+ history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry", 3,
+ 16, false, &sync_visits));
+
+ history::URLRows native_entries;
+ native_entries.push_back(native_entry);
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetURL(_, _))
+ .WillOnce(DoAll(SetArgumentPointee<1>(native_entry), Return(false)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<2>(native_visits), Return(true)));
+ EXPECT_CALL((history_backend()), AddVisits(_, _, history::SOURCE_SYNCED))
+ .WillRepeatedly(Return(false));
+
+ history::URLRows sync_entries;
+ sync_entries.push_back(sync_entry);
+
+ EXPECT_CALL((history_backend()), UpdateURL(_, _))
+ .WillRepeatedly(Return(false));
+ TypedUrlSyncableService* syncable_service =
+ StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
+ // Errors writing to the DB should be recorded, but should not cause an
+ // unrecoverable error.
+ ASSERT_FALSE(sync_service()->data_type_status_table().GetFailedTypes().Has(
+ syncer::TYPED_URLS));
+ // Some calls should have succeeded, so the error percentage should be
+ // somewhere > 0 and < 100.
+ ASSERT_NE(0, syncable_service->GetErrorPercentage());
+ ASSERT_NE(100, syncable_service->GetErrorPercentage());
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, FailToGetTypedURLs) {
+ history::VisitVector native_visits;
+ history::VisitVector sync_visits;
+ history::URLRow native_entry(MakeTypedUrlEntry("http://native.com", "entry",
+ 2, 15, false, &native_visits));
+ history::URLRow sync_entry(MakeTypedUrlEntry("http://sync.com", "entry", 3,
+ 16, false, &sync_visits));
+
+ history::URLRows native_entries;
+ native_entries.push_back(native_entry);
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(false)));
+
+ history::URLRows sync_entries;
+ sync_entries.push_back(sync_entry);
+
+ StartSyncService(base::Bind(&AddTypedUrlEntries, this, sync_entries));
+ // Errors getting typed URLs will cause an unrecoverable error (since we can
+ // do *nothing* in that case).
+ ASSERT_TRUE(sync_service()->data_type_status_table().GetFailedTypes().Has(
+ syncer::TYPED_URLS));
+ ASSERT_EQ(1u,
+ sync_service()->data_type_status_table().GetFailedTypes().Size());
+ // Can't check GetErrorPercentage(), because generating an unrecoverable
+ // error will free the model associator.
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalFileURL) {
+ history::VisitVector original_visits;
+ // Create http and file url.
+ history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com", "yey", 12, 15,
+ false, &original_visits));
+ history::URLRow file_entry(MakeTypedUrlEntry(
+ "file:///kitty.jpg", "kitteh", 12, 15, false, &original_visits));
+
+ history::URLRows original_entries;
+ original_entries.push_back(url_entry);
+ original_entries.push_back(file_entry);
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<2>(original_visits), Return(true)));
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ history::VisitVector updated_visits;
+ // Create updates for the previous urls + a new file one.
+ history::URLRow updated_url_entry(MakeTypedUrlEntry(
+ "http://yey.com", "yey", 20, 15, false, &updated_visits));
+ history::URLRow updated_file_entry(MakeTypedUrlEntry(
+ "file:///cat.jpg", "cat", 20, 15, false, &updated_visits));
+ history::URLRow new_file_entry(MakeTypedUrlEntry("file:///dog.jpg", "dog", 20,
+ 15, false, &updated_visits));
+
+ history::URLRows changed_urls;
+ changed_urls.push_back(updated_url_entry);
+ changed_urls.push_back(updated_file_entry);
+ changed_urls.push_back(new_file_entry);
+ SendNotificationURLsModified(changed_urls);
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+
+ // We should ignore the local file urls (existing and updated),
+ // and only be left with the updated http url.
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreLocalhostURL) {
+ history::VisitVector original_visits;
+ // Create http and localhost url.
+ history::URLRow url_entry(MakeTypedUrlEntry("http://yey.com", "yey", 12, 15,
+ false, &original_visits));
+ history::URLRow localhost_entry(MakeTypedUrlEntry(
+ "http://localhost", "localhost", 12, 15, false, &original_visits));
+
+ history::URLRows original_entries;
+ original_entries.push_back(url_entry);
+ original_entries.push_back(localhost_entry);
+
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<0>(original_entries), Return(true)));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(
+ DoAll(SetArgumentPointee<2>(original_visits), Return(true)));
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ history::VisitVector updated_visits;
+ // Update the previous entries and add a new localhost.
+ history::URLRow updated_url_entry(MakeTypedUrlEntry(
+ "http://yey.com", "yey", 20, 15, false, &updated_visits));
+ history::URLRow updated_localhost_entry(MakeTypedUrlEntry(
+ "http://localhost:80", "localhost", 20, 15, false, &original_visits));
+ history::URLRow localhost_ip_entry(MakeTypedUrlEntry(
+ "http://127.0.0.1", "localhost", 12, 15, false, &original_visits));
+
+ history::URLRows changed_urls;
+ changed_urls.push_back(updated_url_entry);
+ changed_urls.push_back(updated_localhost_entry);
+ changed_urls.push_back(localhost_ip_entry);
+ SendNotificationURLsModified(changed_urls);
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+
+ // We should ignore the localhost urls and left only with http url.
+ ASSERT_EQ(1U, new_sync_entries.size());
+ EXPECT_TRUE(URLsEqual(updated_url_entry, new_sync_entries[0]));
+}
+
+TEST_F(ProfileSyncServiceTypedUrlTest, IgnoreModificationWithoutValidVisit) {
+ EXPECT_CALL((history_backend()), GetAllTypedURLs(_))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL((history_backend()), GetMostRecentVisitsForURL(_, _, _))
+ .WillRepeatedly(Return(true));
+
+ CreateRootHelper create_root(this, syncer::TYPED_URLS);
+ StartSyncService(create_root.callback());
+
+ history::VisitVector updated_visits;
+ history::URLRow updated_url_entry(MakeTypedUrlEntry(
+ "http://yey.com", "yey", 20, 0, false, &updated_visits));
+
+ history::URLRows changed_urls;
+ changed_urls.push_back(updated_url_entry);
+ SendNotificationURLsModified(changed_urls);
+
+ history::URLRows new_sync_entries;
+ GetTypedUrlsFromSyncDB(&new_sync_entries);
+
+ // The change should be ignored.
+ ASSERT_EQ(0U, new_sync_entries.size());
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_service_unittest.cc b/chromium/components/browser_sync/profile_sync_service_unittest.cc
new file mode 100644
index 00000000000..86368bd3ad1
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_service_unittest.cc
@@ -0,0 +1,955 @@
+// 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 "components/browser_sync/profile_sync_service.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/values.h"
+#include "components/browser_sync/browser_sync_switches.h"
+#include "components/browser_sync/profile_sync_test_util.h"
+#include "components/invalidation/impl/profile_invalidation_provider.h"
+#include "components/invalidation/public/invalidation_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/sync/driver/fake_data_type_controller.h"
+#include "components/sync/driver/glue/sync_backend_host_mock.h"
+#include "components/sync/driver/pref_names.h"
+#include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync/driver/sync_driver_switches.h"
+#include "components/sync/driver/sync_service_observer.h"
+#include "components/sync/driver/sync_util.h"
+#include "components/syncable_prefs/testing_pref_service_syncable.h"
+#include "components/version_info/version_info_values.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+
+using syncer::SyncBackendHostMock;
+using testing::Return;
+
+namespace browser_sync {
+
+namespace {
+
+const char kGaiaId[] = "12345";
+const char kEmail[] = "test_user@gmail.com";
+
+class FakeDataTypeManager : public syncer::DataTypeManager {
+ public:
+ typedef base::Callback<void(syncer::ConfigureReason)> ConfigureCalled;
+
+ explicit FakeDataTypeManager(const ConfigureCalled& configure_called)
+ : configure_called_(configure_called) {}
+
+ ~FakeDataTypeManager() override{};
+
+ void Configure(syncer::ModelTypeSet desired_types,
+ syncer::ConfigureReason reason) override {
+ DCHECK(!configure_called_.is_null());
+ configure_called_.Run(reason);
+ }
+
+ void ReenableType(syncer::ModelType type) override {}
+ void ResetDataTypeErrors() override {}
+ void PurgeForMigration(syncer::ModelTypeSet undesired_types,
+ syncer::ConfigureReason reason) override {}
+ void Stop() override{};
+ State state() const override { return syncer::DataTypeManager::CONFIGURED; };
+
+ private:
+ ConfigureCalled configure_called_;
+};
+
+ACTION_P(ReturnNewDataTypeManager, configure_called) {
+ return new FakeDataTypeManager(configure_called);
+}
+
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+class TestSyncServiceObserver : public syncer::SyncServiceObserver {
+ public:
+ explicit TestSyncServiceObserver(ProfileSyncService* service)
+ : service_(service), setup_in_progress_(false) {}
+ void OnStateChanged() override {
+ setup_in_progress_ = service_->IsSetupInProgress();
+ }
+ bool setup_in_progress() const { return setup_in_progress_; }
+
+ private:
+ ProfileSyncService* service_;
+ bool setup_in_progress_;
+};
+
+// A variant of the SyncBackendHostMock that won't automatically
+// call back when asked to initialized. Allows us to test things
+// that could happen while backend init is in progress.
+class SyncBackendHostNoReturn : public SyncBackendHostMock {
+ void Initialize(
+ syncer::SyncFrontend* frontend,
+ std::unique_ptr<base::Thread> sync_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& file_thread,
+ const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
+ const GURL& service_url,
+ const std::string& sync_user_agent,
+ const syncer::SyncCredentials& credentials,
+ bool delete_sync_data_folder,
+ std::unique_ptr<syncer::SyncManagerFactory> sync_manager_factory,
+ const syncer::WeakHandle<syncer::UnrecoverableErrorHandler>&
+ unrecoverable_error_handler,
+ const base::Closure& report_unrecoverable_error_function,
+ const HttpPostProviderFactoryGetter& http_post_provider_factory_getter,
+ std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState>
+ saved_nigori_state) override {}
+};
+
+class SyncBackendHostMockCollectDeleteDirParam : public SyncBackendHostMock {
+ public:
+ explicit SyncBackendHostMockCollectDeleteDirParam(
+ std::vector<bool>* delete_dir_param)
+ : delete_dir_param_(delete_dir_param) {}
+
+ void Initialize(
+ syncer::SyncFrontend* frontend,
+ std::unique_ptr<base::Thread> sync_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& file_thread,
+ const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
+ const GURL& service_url,
+ const std::string& sync_user_agent,
+ const syncer::SyncCredentials& credentials,
+ bool delete_sync_data_folder,
+ std::unique_ptr<syncer::SyncManagerFactory> sync_manager_factory,
+ const syncer::WeakHandle<syncer::UnrecoverableErrorHandler>&
+ unrecoverable_error_handler,
+ const base::Closure& report_unrecoverable_error_function,
+ const HttpPostProviderFactoryGetter& http_post_provider_factory_getter,
+ std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState>
+ saved_nigori_state) override {
+ delete_dir_param_->push_back(delete_sync_data_folder);
+ SyncBackendHostMock::Initialize(
+ frontend, std::move(sync_thread), db_thread, file_thread, event_handler,
+ service_url, sync_user_agent, credentials, delete_sync_data_folder,
+ std::move(sync_manager_factory), unrecoverable_error_handler,
+ report_unrecoverable_error_function, http_post_provider_factory_getter,
+ std::move(saved_nigori_state));
+ }
+
+ private:
+ std::vector<bool>* delete_dir_param_;
+};
+
+// SyncBackendHostMock that calls an external callback when ClearServerData is
+// called.
+class SyncBackendHostCaptureClearServerData : public SyncBackendHostMock {
+ public:
+ typedef base::Callback<void(
+ const syncer::SyncManager::ClearServerDataCallback&)>
+ ClearServerDataCalled;
+ explicit SyncBackendHostCaptureClearServerData(
+ const ClearServerDataCalled& clear_server_data_called)
+ : clear_server_data_called_(clear_server_data_called) {}
+
+ void ClearServerData(
+ const syncer::SyncManager::ClearServerDataCallback& callback) override {
+ clear_server_data_called_.Run(callback);
+ }
+
+ private:
+ ClearServerDataCalled clear_server_data_called_;
+};
+
+ACTION(ReturnNewSyncBackendHostMock) {
+ return new SyncBackendHostMock();
+}
+
+ACTION(ReturnNewSyncBackendHostNoReturn) {
+ return new SyncBackendHostNoReturn();
+}
+
+ACTION_P(ReturnNewMockHostCollectDeleteDirParam, delete_dir_param) {
+ return new SyncBackendHostMockCollectDeleteDirParam(delete_dir_param);
+}
+
+void OnClearServerDataCalled(
+ syncer::SyncManager::ClearServerDataCallback* captured_callback,
+ const syncer::SyncManager::ClearServerDataCallback& callback) {
+ *captured_callback = callback;
+}
+
+ACTION_P(ReturnNewMockHostCaptureClearServerData, captured_callback) {
+ return new SyncBackendHostCaptureClearServerData(base::Bind(
+ &OnClearServerDataCalled, base::Unretained(captured_callback)));
+}
+
+// A test harness that uses a real ProfileSyncService and in most cases a
+// MockSyncBackendHost.
+//
+// This is useful if we want to test the ProfileSyncService and don't care about
+// testing the SyncBackendHost.
+class ProfileSyncServiceTest : public ::testing::Test {
+ protected:
+ ProfileSyncServiceTest() : component_factory_(nullptr) {}
+ ~ProfileSyncServiceTest() override {}
+
+ void SetUp() override {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kSyncDeferredStartupTimeoutSeconds, "0");
+ }
+
+ void TearDown() override {
+ // Kill the service before the profile.
+ if (service_)
+ service_->Shutdown();
+
+ service_.reset();
+ }
+
+ void IssueTestTokens() {
+ std::string account_id =
+ account_tracker()->SeedAccountInfo(kGaiaId, kEmail);
+ auth_service()->UpdateCredentials(account_id, "oauth2_login_token");
+ }
+
+ void CreateService(ProfileSyncService::StartBehavior behavior) {
+ signin_manager()->SetAuthenticatedAccountInfo(kGaiaId, kEmail);
+ component_factory_ = profile_sync_service_bundle_.component_factory();
+ ProfileSyncServiceBundle::SyncClientBuilder builder(
+ &profile_sync_service_bundle_);
+ ProfileSyncService::InitParams init_params =
+ profile_sync_service_bundle_.CreateBasicInitParams(behavior,
+ builder.Build());
+
+ service_.reset(new ProfileSyncService(std::move(init_params)));
+ service_->RegisterDataTypeController(
+ base::MakeUnique<syncer::FakeDataTypeController>(syncer::BOOKMARKS));
+ }
+
+#if defined(OS_WIN) || defined(OS_MACOSX) || \
+ (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+ void CreateServiceWithoutSignIn() {
+ CreateService(ProfileSyncService::AUTO_START);
+ signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
+ }
+#endif
+
+ void ShutdownAndDeleteService() {
+ if (service_)
+ service_->Shutdown();
+ service_.reset();
+ }
+
+ void InitializeForNthSync() {
+ // Set first sync time before initialize to simulate a complete sync setup.
+ syncer::SyncPrefs sync_prefs(prefs());
+ sync_prefs.SetFirstSyncTime(base::Time::Now());
+ sync_prefs.SetFirstSetupComplete();
+ sync_prefs.SetKeepEverythingSynced(true);
+ service_->Initialize();
+ }
+
+ void InitializeForFirstSync() { service_->Initialize(); }
+
+ void TriggerPassphraseRequired() {
+ service_->OnPassphraseRequired(syncer::REASON_DECRYPTION,
+ sync_pb::EncryptedData());
+ }
+
+ void TriggerDataTypeStartRequest() {
+ service_->OnDataTypeRequestsSyncStartup(syncer::BOOKMARKS);
+ }
+
+ void OnConfigureCalled(syncer::ConfigureReason configure_reason) {
+ syncer::DataTypeManager::ConfigureResult result;
+ result.status = syncer::DataTypeManager::OK;
+ service()->OnConfigureDone(result);
+ }
+
+ FakeDataTypeManager::ConfigureCalled GetDefaultConfigureCalledCallback() {
+ return base::Bind(&ProfileSyncServiceTest::OnConfigureCalled,
+ base::Unretained(this));
+ }
+
+ void OnConfigureCalledRecordReason(syncer::ConfigureReason* reason_dest,
+ syncer::ConfigureReason reason) {
+ DCHECK(reason_dest);
+ *reason_dest = reason;
+ }
+
+ FakeDataTypeManager::ConfigureCalled GetRecordingConfigureCalledCallback(
+ syncer::ConfigureReason* reason) {
+ return base::Bind(&ProfileSyncServiceTest::OnConfigureCalledRecordReason,
+ base::Unretained(this), reason);
+ }
+
+ void ExpectDataTypeManagerCreation(
+ int times,
+ const FakeDataTypeManager::ConfigureCalled& callback) {
+ EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
+ .Times(times)
+ .WillRepeatedly(ReturnNewDataTypeManager(callback));
+ }
+
+ void ExpectSyncBackendHostCreation(int times) {
+ EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
+ .Times(times)
+ .WillRepeatedly(ReturnNewSyncBackendHostMock());
+ }
+
+ void ExpectSyncBackendHostCreationCollectDeleteDir(
+ int times,
+ std::vector<bool>* delete_dir_param) {
+ EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
+ .Times(times)
+ .WillRepeatedly(
+ ReturnNewMockHostCollectDeleteDirParam(delete_dir_param));
+ }
+
+ void ExpectSyncBackendHostCreationCaptureClearServerData(
+ syncer::SyncManager::ClearServerDataCallback* captured_callback) {
+ EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
+ .Times(1)
+ .WillOnce(ReturnNewMockHostCaptureClearServerData(captured_callback));
+ }
+
+ void PrepareDelayedInitSyncBackendHost() {
+ EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
+ .WillOnce(ReturnNewSyncBackendHostNoReturn());
+ }
+
+ AccountTrackerService* account_tracker() {
+ return profile_sync_service_bundle_.account_tracker();
+ }
+
+#if defined(OS_CHROMEOS)
+ SigninManagerBase* signin_manager()
+#else
+ SigninManager* signin_manager()
+#endif
+ // Opening brace is outside of macro to avoid confusing lint.
+ {
+ return profile_sync_service_bundle_.signin_manager();
+ }
+
+ ProfileOAuth2TokenService* auth_service() {
+ return profile_sync_service_bundle_.auth_service();
+ }
+
+ ProfileSyncService* service() { return service_.get(); }
+
+ syncable_prefs::TestingPrefServiceSyncable* prefs() {
+ return profile_sync_service_bundle_.pref_service();
+ }
+
+ syncer::SyncApiComponentFactoryMock* component_factory() {
+ return component_factory_;
+ }
+
+ protected:
+ void PumpLoop() {
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
+ private:
+ base::MessageLoop message_loop_;
+ ProfileSyncServiceBundle profile_sync_service_bundle_;
+ std::unique_ptr<ProfileSyncService> service_;
+
+ // The current component factory used by sync. May be null if the server
+ // hasn't been created yet.
+ syncer::SyncApiComponentFactoryMock* component_factory_;
+};
+
+// Verify that the server URLs are sane.
+TEST_F(ProfileSyncServiceTest, InitialState) {
+ CreateService(ProfileSyncService::AUTO_START);
+ InitializeForNthSync();
+ const std::string& url = service()->sync_service_url().spec();
+ EXPECT_TRUE(url == syncer::internal::kSyncServerUrl ||
+ url == syncer::internal::kSyncDevServerUrl);
+}
+
+// Verify a successful initialization.
+TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
+ prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
+ new base::FundamentalValue(false));
+ IssueTestTokens();
+ CreateService(ProfileSyncService::AUTO_START);
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ InitializeForNthSync();
+ EXPECT_FALSE(service()->IsManaged());
+ EXPECT_TRUE(service()->IsSyncActive());
+}
+
+// Verify that an initialization where first setup is not complete does not
+// start up the backend.
+TEST_F(ProfileSyncServiceTest, NeedsConfirmation) {
+ prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
+ new base::FundamentalValue(false));
+ IssueTestTokens();
+ CreateService(ProfileSyncService::MANUAL_START);
+ syncer::SyncPrefs sync_prefs(prefs());
+ base::Time now = base::Time::Now();
+ sync_prefs.SetLastSyncedTime(now);
+ sync_prefs.SetKeepEverythingSynced(true);
+ service()->Initialize();
+ EXPECT_FALSE(service()->IsSyncActive());
+
+ // The last sync time shouldn't be cleared.
+ // TODO(zea): figure out a way to check that the directory itself wasn't
+ // cleared.
+ EXPECT_EQ(now, sync_prefs.GetLastSyncedTime());
+}
+
+// Verify that the SetSetupInProgress function call updates state
+// and notifies observers.
+TEST_F(ProfileSyncServiceTest, SetupInProgress) {
+ CreateService(ProfileSyncService::AUTO_START);
+ InitializeForFirstSync();
+
+ TestSyncServiceObserver observer(service());
+ service()->AddObserver(&observer);
+
+ auto sync_blocker = service()->GetSetupInProgressHandle();
+ EXPECT_TRUE(observer.setup_in_progress());
+ sync_blocker.reset();
+ EXPECT_FALSE(observer.setup_in_progress());
+
+ service()->RemoveObserver(&observer);
+}
+
+// Verify that disable by enterprise policy works.
+TEST_F(ProfileSyncServiceTest, DisabledByPolicyBeforeInit) {
+ prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
+ new base::FundamentalValue(true));
+ IssueTestTokens();
+ CreateService(ProfileSyncService::AUTO_START);
+ InitializeForNthSync();
+ EXPECT_TRUE(service()->IsManaged());
+ EXPECT_FALSE(service()->IsSyncActive());
+}
+
+// Verify that disable by enterprise policy works even after the backend has
+// been initialized.
+TEST_F(ProfileSyncServiceTest, DisabledByPolicyAfterInit) {
+ IssueTestTokens();
+ CreateService(ProfileSyncService::AUTO_START);
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ InitializeForNthSync();
+
+ EXPECT_FALSE(service()->IsManaged());
+ EXPECT_TRUE(service()->IsSyncActive());
+
+ prefs()->SetManagedPref(syncer::prefs::kSyncManaged,
+ new base::FundamentalValue(true));
+
+ EXPECT_TRUE(service()->IsManaged());
+ EXPECT_FALSE(service()->IsSyncActive());
+}
+
+// Exercies the ProfileSyncService's code paths related to getting shut down
+// before the backend initialize call returns.
+TEST_F(ProfileSyncServiceTest, AbortedByShutdown) {
+ CreateService(ProfileSyncService::AUTO_START);
+ PrepareDelayedInitSyncBackendHost();
+
+ IssueTestTokens();
+ InitializeForNthSync();
+ EXPECT_FALSE(service()->IsSyncActive());
+
+ ShutdownAndDeleteService();
+}
+
+// Test RequestStop() before we've initialized the backend.
+TEST_F(ProfileSyncServiceTest, EarlyRequestStop) {
+ CreateService(ProfileSyncService::AUTO_START);
+ IssueTestTokens();
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+
+ service()->RequestStop(ProfileSyncService::KEEP_DATA);
+ EXPECT_FALSE(service()->IsSyncRequested());
+
+ // Because sync is not requested, this should fail.
+ InitializeForNthSync();
+ EXPECT_FALSE(service()->IsSyncRequested());
+ EXPECT_FALSE(service()->IsSyncActive());
+
+ // Request start. This should be enough to allow init to happen.
+ service()->RequestStart();
+ EXPECT_TRUE(service()->IsSyncRequested());
+ EXPECT_TRUE(service()->IsSyncActive());
+}
+
+// Test RequestStop() after we've initialized the backend.
+TEST_F(ProfileSyncServiceTest, DisableAndEnableSyncTemporarily) {
+ CreateService(ProfileSyncService::AUTO_START);
+ IssueTestTokens();
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ InitializeForNthSync();
+
+ EXPECT_TRUE(service()->IsSyncActive());
+ EXPECT_FALSE(prefs()->GetBoolean(syncer::prefs::kSyncSuppressStart));
+
+ testing::Mock::VerifyAndClearExpectations(component_factory());
+
+ service()->RequestStop(ProfileSyncService::KEEP_DATA);
+ EXPECT_FALSE(service()->IsSyncActive());
+ EXPECT_TRUE(prefs()->GetBoolean(syncer::prefs::kSyncSuppressStart));
+
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+
+ service()->RequestStart();
+ EXPECT_TRUE(service()->IsSyncActive());
+ EXPECT_FALSE(prefs()->GetBoolean(syncer::prefs::kSyncSuppressStart));
+}
+
+// Certain ProfileSyncService tests don't apply to Chrome OS, for example
+// things that deal with concepts like "signing out" and policy.
+#if !defined(OS_CHROMEOS)
+TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOut) {
+ CreateService(ProfileSyncService::AUTO_START);
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ IssueTestTokens();
+ InitializeForNthSync();
+
+ EXPECT_TRUE(service()->IsSyncActive());
+ EXPECT_FALSE(prefs()->GetBoolean(syncer::prefs::kSyncSuppressStart));
+
+ signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
+ EXPECT_FALSE(service()->IsSyncActive());
+}
+#endif // !defined(OS_CHROMEOS)
+
+TEST_F(ProfileSyncServiceTest, GetSyncTokenStatus) {
+ CreateService(ProfileSyncService::AUTO_START);
+ IssueTestTokens();
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ InitializeForNthSync();
+
+ // Initial status.
+ ProfileSyncService::SyncTokenStatus token_status =
+ service()->GetSyncTokenStatus();
+ EXPECT_EQ(syncer::CONNECTION_NOT_ATTEMPTED, token_status.connection_status);
+ EXPECT_TRUE(token_status.connection_status_update_time.is_null());
+ EXPECT_TRUE(token_status.token_request_time.is_null());
+ EXPECT_TRUE(token_status.token_receive_time.is_null());
+
+ // Simulate an auth error.
+ service()->OnConnectionStatusChange(syncer::CONNECTION_AUTH_ERROR);
+
+ // The token request will take the form of a posted task. Run it.
+ base::RunLoop loop;
+ loop.RunUntilIdle();
+
+ token_status = service()->GetSyncTokenStatus();
+ EXPECT_EQ(syncer::CONNECTION_AUTH_ERROR, token_status.connection_status);
+ EXPECT_FALSE(token_status.connection_status_update_time.is_null());
+ EXPECT_FALSE(token_status.token_request_time.is_null());
+ EXPECT_FALSE(token_status.token_receive_time.is_null());
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ token_status.last_get_token_error);
+ EXPECT_TRUE(token_status.next_token_request_time.is_null());
+
+ // Simulate successful connection.
+ service()->OnConnectionStatusChange(syncer::CONNECTION_OK);
+ token_status = service()->GetSyncTokenStatus();
+ EXPECT_EQ(syncer::CONNECTION_OK, token_status.connection_status);
+}
+
+TEST_F(ProfileSyncServiceTest, RevokeAccessTokenFromTokenService) {
+ CreateService(ProfileSyncService::AUTO_START);
+ IssueTestTokens();
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ InitializeForNthSync();
+ EXPECT_TRUE(service()->IsSyncActive());
+
+ std::string primary_account_id =
+ signin_manager()->GetAuthenticatedAccountId();
+ auth_service()->LoadCredentials(primary_account_id);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
+
+ std::string secondary_account_gaiaid = "1234567";
+ std::string secondary_account_name = "test_user2@gmail.com";
+ std::string secondary_account_id = account_tracker()->SeedAccountInfo(
+ secondary_account_gaiaid, secondary_account_name);
+ auth_service()->UpdateCredentials(secondary_account_id,
+ "second_account_refresh_token");
+ auth_service()->RevokeCredentials(secondary_account_id);
+ EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
+
+ auth_service()->RevokeCredentials(primary_account_id);
+ EXPECT_TRUE(service()->GetAccessTokenForTest().empty());
+}
+
+// CrOS does not support signout.
+#if !defined(OS_CHROMEOS)
+TEST_F(ProfileSyncServiceTest, SignOutRevokeAccessToken) {
+ CreateService(ProfileSyncService::AUTO_START);
+ IssueTestTokens();
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ InitializeForNthSync();
+ EXPECT_TRUE(service()->IsSyncActive());
+
+ std::string primary_account_id =
+ signin_manager()->GetAuthenticatedAccountId();
+ auth_service()->LoadCredentials(primary_account_id);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
+
+ signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
+ EXPECT_TRUE(service()->GetAccessTokenForTest().empty());
+}
+#endif
+
+// Verify that LastSyncedTime and local DeviceInfo is cleared on sign out.
+TEST_F(ProfileSyncServiceTest, ClearDataOnSignOut) {
+ IssueTestTokens();
+ CreateService(ProfileSyncService::AUTO_START);
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ InitializeForNthSync();
+ EXPECT_TRUE(service()->IsSyncActive());
+ EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW),
+ service()->GetLastSyncedTimeString());
+ EXPECT_TRUE(service()->GetLocalDeviceInfoProvider()->GetLocalDeviceInfo());
+
+ // Sign out.
+ service()->RequestStop(ProfileSyncService::CLEAR_DATA);
+ PumpLoop();
+
+ EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER),
+ service()->GetLastSyncedTimeString());
+ EXPECT_FALSE(service()->GetLocalDeviceInfoProvider()->GetLocalDeviceInfo());
+}
+
+// Verify that the disable sync flag disables sync.
+TEST_F(ProfileSyncServiceTest, DisableSyncFlag) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableSync);
+ EXPECT_FALSE(ProfileSyncService::IsSyncAllowedByFlag());
+}
+
+// Verify that no disable sync flag enables sync.
+TEST_F(ProfileSyncServiceTest, NoDisableSyncFlag) {
+ EXPECT_TRUE(ProfileSyncService::IsSyncAllowedByFlag());
+}
+
+// Test Sync will stop after receive memory pressure
+TEST_F(ProfileSyncServiceTest, MemoryPressureRecording) {
+ CreateService(ProfileSyncService::AUTO_START);
+ IssueTestTokens();
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ InitializeForNthSync();
+
+ EXPECT_TRUE(service()->IsSyncActive());
+ EXPECT_FALSE(prefs()->GetBoolean(syncer::prefs::kSyncSuppressStart));
+
+ testing::Mock::VerifyAndClearExpectations(component_factory());
+
+ syncer::SyncPrefs sync_prefs(service()->GetSyncClient()->GetPrefService());
+
+ EXPECT_EQ(prefs()->GetInteger(syncer::prefs::kSyncMemoryPressureWarningCount),
+ 0);
+ EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly());
+
+ // Simulate memory pressure notification.
+ base::MemoryPressureListener::NotifyMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+ base::RunLoop().RunUntilIdle();
+
+ // Verify memory pressure recorded.
+ EXPECT_EQ(prefs()->GetInteger(syncer::prefs::kSyncMemoryPressureWarningCount),
+ 1);
+ EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly());
+
+ // Simulate memory pressure notification.
+ base::MemoryPressureListener::NotifyMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+ base::RunLoop().RunUntilIdle();
+ ShutdownAndDeleteService();
+
+ // Verify memory pressure and shutdown recorded.
+ EXPECT_EQ(prefs()->GetInteger(syncer::prefs::kSyncMemoryPressureWarningCount),
+ 2);
+ EXPECT_TRUE(sync_prefs.DidSyncShutdownCleanly());
+}
+
+// Verify that OnLocalSetPassphraseEncryption triggers catch up configure sync
+// cycle, calls ClearServerData, shuts down and restarts sync.
+TEST_F(ProfileSyncServiceTest, OnLocalSetPassphraseEncryption) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ switches::kSyncClearDataOnPassphraseEncryption);
+ IssueTestTokens();
+ CreateService(ProfileSyncService::AUTO_START);
+
+ syncer::SyncManager::ClearServerDataCallback captured_callback;
+ syncer::ConfigureReason configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
+
+ // Initialize sync, ensure that both DataTypeManager and SyncBackendHost are
+ // initialized and DTM::Configure is called with
+ // CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE.
+ ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
+ ExpectDataTypeManagerCreation(
+ 1, GetRecordingConfigureCalledCallback(&configure_reason));
+ InitializeForNthSync();
+ EXPECT_TRUE(service()->IsSyncActive());
+ testing::Mock::VerifyAndClearExpectations(component_factory());
+ EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
+ syncer::DataTypeManager::ConfigureResult result;
+ result.status = syncer::DataTypeManager::OK;
+ service()->OnConfigureDone(result);
+
+ // Simulate user entering encryption passphrase. Ensure that catch up
+ // configure cycle is started (DTM::Configure is called with
+ // CONFIGURE_REASON_CATCH_UP).
+ const syncer::SyncEncryptionHandler::NigoriState nigori_state;
+ service()->OnLocalSetPassphraseEncryption(nigori_state);
+ EXPECT_EQ(syncer::CONFIGURE_REASON_CATCH_UP, configure_reason);
+ EXPECT_TRUE(captured_callback.is_null());
+
+ // Simulate configure successful. Ensure that SBH::ClearServerData is called.
+ service()->OnConfigureDone(result);
+ EXPECT_FALSE(captured_callback.is_null());
+
+ // Once SBH::ClearServerData finishes successfully ensure that sync is
+ // restarted.
+ configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
+ ExpectSyncBackendHostCreation(1);
+ ExpectDataTypeManagerCreation(
+ 1, GetRecordingConfigureCalledCallback(&configure_reason));
+ captured_callback.Run();
+ testing::Mock::VerifyAndClearExpectations(component_factory());
+ EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
+ service()->OnConfigureDone(result);
+}
+
+// Verify that if after OnLocalSetPassphraseEncryption catch up configure sync
+// cycle gets interrupted, it starts again after browser restart.
+TEST_F(ProfileSyncServiceTest,
+ OnLocalSetPassphraseEncryption_RestartDuringCatchUp) {
+ syncer::ConfigureReason configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ switches::kSyncClearDataOnPassphraseEncryption);
+ IssueTestTokens();
+ CreateService(ProfileSyncService::AUTO_START);
+ ExpectSyncBackendHostCreation(1);
+ ExpectDataTypeManagerCreation(
+ 1, GetRecordingConfigureCalledCallback(&configure_reason));
+ InitializeForNthSync();
+ testing::Mock::VerifyAndClearExpectations(component_factory());
+ EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
+ syncer::DataTypeManager::ConfigureResult result;
+ result.status = syncer::DataTypeManager::OK;
+ service()->OnConfigureDone(result);
+
+ // Simulate user entering encryption passphrase. Ensure Configure was called
+ // but don't let it continue.
+ const syncer::SyncEncryptionHandler::NigoriState nigori_state;
+ service()->OnLocalSetPassphraseEncryption(nigori_state);
+ EXPECT_EQ(syncer::CONFIGURE_REASON_CATCH_UP, configure_reason);
+
+ // Simulate browser restart. First configuration is a regular one.
+ service()->Shutdown();
+ syncer::SyncManager::ClearServerDataCallback captured_callback;
+ ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
+ ExpectDataTypeManagerCreation(
+ 1, GetRecordingConfigureCalledCallback(&configure_reason));
+ service()->RequestStart();
+ testing::Mock::VerifyAndClearExpectations(component_factory());
+ EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
+ EXPECT_TRUE(captured_callback.is_null());
+
+ // Simulate configure successful. This time it should be catch up.
+ service()->OnConfigureDone(result);
+ EXPECT_EQ(syncer::CONFIGURE_REASON_CATCH_UP, configure_reason);
+ EXPECT_TRUE(captured_callback.is_null());
+
+ // Simulate catch up configure successful. Ensure that SBH::ClearServerData is
+ // called.
+ service()->OnConfigureDone(result);
+ EXPECT_FALSE(captured_callback.is_null());
+
+ ExpectSyncBackendHostCreation(1);
+ ExpectDataTypeManagerCreation(
+ 1, GetRecordingConfigureCalledCallback(&configure_reason));
+ captured_callback.Run();
+ testing::Mock::VerifyAndClearExpectations(component_factory());
+ EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
+}
+
+// Verify that if after OnLocalSetPassphraseEncryption ClearServerData gets
+// interrupted, transition again from catch up sync cycle after browser restart.
+TEST_F(ProfileSyncServiceTest,
+ OnLocalSetPassphraseEncryption_RestartDuringClearServerData) {
+ syncer::SyncManager::ClearServerDataCallback captured_callback;
+ syncer::ConfigureReason configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ switches::kSyncClearDataOnPassphraseEncryption);
+ IssueTestTokens();
+ CreateService(ProfileSyncService::AUTO_START);
+ ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ InitializeForNthSync();
+ testing::Mock::VerifyAndClearExpectations(component_factory());
+
+ // Simulate user entering encryption passphrase.
+ const syncer::SyncEncryptionHandler::NigoriState nigori_state;
+ service()->OnLocalSetPassphraseEncryption(nigori_state);
+ EXPECT_FALSE(captured_callback.is_null());
+ captured_callback.Reset();
+
+ // Simulate browser restart. First configuration is a regular one.
+ service()->Shutdown();
+ ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
+ ExpectDataTypeManagerCreation(
+ 1, GetRecordingConfigureCalledCallback(&configure_reason));
+ service()->RequestStart();
+ testing::Mock::VerifyAndClearExpectations(component_factory());
+ EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
+ EXPECT_TRUE(captured_callback.is_null());
+
+ // Simulate configure successful. This time it should be catch up.
+ syncer::DataTypeManager::ConfigureResult result;
+ result.status = syncer::DataTypeManager::OK;
+ service()->OnConfigureDone(result);
+ EXPECT_EQ(syncer::CONFIGURE_REASON_CATCH_UP, configure_reason);
+ EXPECT_TRUE(captured_callback.is_null());
+
+ // Simulate catch up configure successful. Ensure that SBH::ClearServerData is
+ // called.
+ service()->OnConfigureDone(result);
+ EXPECT_FALSE(captured_callback.is_null());
+
+ ExpectSyncBackendHostCreation(1);
+ ExpectDataTypeManagerCreation(
+ 1, GetRecordingConfigureCalledCallback(&configure_reason));
+ captured_callback.Run();
+ testing::Mock::VerifyAndClearExpectations(component_factory());
+ EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
+}
+
+// Test that the passphrase prompt due to version change logic gets triggered
+// on a datatype type requesting startup, but only happens once.
+TEST_F(ProfileSyncServiceTest, PassphrasePromptDueToVersion) {
+ IssueTestTokens();
+ CreateService(ProfileSyncService::AUTO_START);
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ InitializeForNthSync();
+
+ syncer::SyncPrefs sync_prefs(service()->GetSyncClient()->GetPrefService());
+ EXPECT_EQ(PRODUCT_VERSION, sync_prefs.GetLastRunVersion());
+
+ sync_prefs.SetPassphrasePrompted(true);
+
+ // Until a datatype requests startup while a passphrase is required the
+ // passphrase prompt bit should remain set.
+ EXPECT_TRUE(sync_prefs.IsPassphrasePrompted());
+ TriggerPassphraseRequired();
+ EXPECT_TRUE(sync_prefs.IsPassphrasePrompted());
+
+ // Because the last version was unset, this run should be treated as a new
+ // version and force a prompt.
+ TriggerDataTypeStartRequest();
+ EXPECT_FALSE(sync_prefs.IsPassphrasePrompted());
+
+ // At this point further datatype startup request should have no effect.
+ sync_prefs.SetPassphrasePrompted(true);
+ TriggerDataTypeStartRequest();
+ EXPECT_TRUE(sync_prefs.IsPassphrasePrompted());
+}
+
+// Test that when ProfileSyncService receives actionable error
+// RESET_LOCAL_SYNC_DATA it restarts sync.
+TEST_F(ProfileSyncServiceTest, ResetSyncData) {
+ IssueTestTokens();
+ CreateService(ProfileSyncService::AUTO_START);
+ // Backend should get initialized two times: once during initialization and
+ // once when handling actionable error.
+ ExpectDataTypeManagerCreation(2, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(2);
+ InitializeForNthSync();
+
+ syncer::SyncProtocolError client_cmd;
+ client_cmd.action = syncer::RESET_LOCAL_SYNC_DATA;
+ service()->OnActionableError(client_cmd);
+}
+
+// Test that when ProfileSyncService receives actionable error
+// DISABLE_SYNC_ON_CLIENT it disables sync and signs out.
+TEST_F(ProfileSyncServiceTest, DisableSyncOnClient) {
+ IssueTestTokens();
+ CreateService(ProfileSyncService::AUTO_START);
+ ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
+ ExpectSyncBackendHostCreation(1);
+ InitializeForNthSync();
+
+ EXPECT_TRUE(service()->IsSyncActive());
+ EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW),
+ service()->GetLastSyncedTimeString());
+ EXPECT_TRUE(service()->GetLocalDeviceInfoProvider()->GetLocalDeviceInfo());
+
+ syncer::SyncProtocolError client_cmd;
+ client_cmd.action = syncer::DISABLE_SYNC_ON_CLIENT;
+ service()->OnActionableError(client_cmd);
+
+// CrOS does not support signout.
+#if !defined(OS_CHROMEOS)
+ EXPECT_TRUE(signin_manager()->GetAuthenticatedAccountId().empty());
+#else
+ EXPECT_FALSE(signin_manager()->GetAuthenticatedAccountId().empty());
+#endif
+
+ EXPECT_FALSE(service()->IsSyncActive());
+ EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER),
+ service()->GetLastSyncedTimeString());
+ EXPECT_FALSE(service()->GetLocalDeviceInfoProvider()->GetLocalDeviceInfo());
+}
+
+// Regression test for crbug/555434. The issue is that check for sessions DTC in
+// OnSessionRestoreComplete was creating map entry with nullptr which later was
+// dereferenced in OnSyncCycleCompleted. The fix is to use find() to check if
+// entry for sessions exists in map.
+TEST_F(ProfileSyncServiceTest, ValidPointersInDTCMap) {
+ CreateService(ProfileSyncService::AUTO_START);
+ service()->OnSessionRestoreComplete();
+ service()->OnSyncCycleCompleted();
+}
+
+} // namespace
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_test_util.cc b/chromium/components/browser_sync/profile_sync_test_util.cc
new file mode 100644
index 00000000000..1732fcda728
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_test_util.cc
@@ -0,0 +1,275 @@
+// 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 "components/browser_sync/profile_sync_test_util.h"
+
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/history/core/browser/history_model_worker.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/signin/core/browser/signin_manager_base.h"
+#include "components/sync/driver/glue/browser_thread_model_worker.h"
+#include "components/sync/driver/glue/ui_model_worker.h"
+#include "components/sync/driver/signin_manager_wrapper.h"
+#include "components/sync/driver/sync_prefs.h"
+#include "components/sync/engine/passive_model_worker.h"
+#include "net/url_request/url_request_test_util.h"
+
+namespace browser_sync {
+
+namespace {
+
+class BundleSyncClient : public syncer::FakeSyncClient {
+ public:
+ BundleSyncClient(syncer::SyncApiComponentFactory* factory,
+ PrefService* pref_service,
+ sync_sessions::SyncSessionsClient* sync_sessions_client,
+ autofill::PersonalDataManager* personal_data_manager,
+ const base::Callback<base::WeakPtr<syncer::SyncableService>(
+ syncer::ModelType type)>& get_syncable_service_callback,
+ const base::Callback<syncer::SyncService*(void)>&
+ get_sync_service_callback,
+ const base::Callback<bookmarks::BookmarkModel*(void)>&
+ get_bookmark_model_callback,
+ scoped_refptr<base::SingleThreadTaskRunner> db_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> file_thread,
+ history::HistoryService* history_service);
+
+ ~BundleSyncClient() override;
+
+ PrefService* GetPrefService() override;
+ sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override;
+ autofill::PersonalDataManager* GetPersonalDataManager() override;
+ base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
+ syncer::ModelType type) override;
+ syncer::SyncService* GetSyncService() override;
+ scoped_refptr<syncer::ModelSafeWorker> CreateModelWorkerForGroup(
+ syncer::ModelSafeGroup group,
+ syncer::WorkerLoopDestructionObserver* observer) override;
+ history::HistoryService* GetHistoryService() override;
+ bookmarks::BookmarkModel* GetBookmarkModel() override;
+
+ private:
+ PrefService* const pref_service_;
+ sync_sessions::SyncSessionsClient* const sync_sessions_client_;
+ autofill::PersonalDataManager* const personal_data_manager_;
+ const base::Callback<base::WeakPtr<syncer::SyncableService>(
+ syncer::ModelType type)>
+ get_syncable_service_callback_;
+ const base::Callback<syncer::SyncService*(void)> get_sync_service_callback_;
+ const base::Callback<bookmarks::BookmarkModel*(void)>
+ get_bookmark_model_callback_;
+ // These task runners, if not null, are used in CreateModelWorkerForGroup.
+ const scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+ const scoped_refptr<base::SingleThreadTaskRunner> file_thread_;
+ history::HistoryService* history_service_;
+};
+
+BundleSyncClient::BundleSyncClient(
+ syncer::SyncApiComponentFactory* factory,
+ PrefService* pref_service,
+ sync_sessions::SyncSessionsClient* sync_sessions_client,
+ autofill::PersonalDataManager* personal_data_manager,
+ const base::Callback<base::WeakPtr<syncer::SyncableService>(
+ syncer::ModelType type)>& get_syncable_service_callback,
+ const base::Callback<syncer::SyncService*(void)>& get_sync_service_callback,
+ const base::Callback<bookmarks::BookmarkModel*(void)>&
+ get_bookmark_model_callback,
+ scoped_refptr<base::SingleThreadTaskRunner> db_thread,
+ scoped_refptr<base::SingleThreadTaskRunner> file_thread,
+ history::HistoryService* history_service)
+ : syncer::FakeSyncClient(factory),
+ pref_service_(pref_service),
+ sync_sessions_client_(sync_sessions_client),
+ personal_data_manager_(personal_data_manager),
+ get_syncable_service_callback_(get_syncable_service_callback),
+ get_sync_service_callback_(get_sync_service_callback),
+ get_bookmark_model_callback_(get_bookmark_model_callback),
+ db_thread_(db_thread),
+ file_thread_(file_thread),
+ history_service_(history_service) {
+ DCHECK_EQ(!!db_thread_, !!file_thread_);
+}
+
+BundleSyncClient::~BundleSyncClient() = default;
+
+PrefService* BundleSyncClient::GetPrefService() {
+ return pref_service_;
+}
+
+sync_sessions::SyncSessionsClient* BundleSyncClient::GetSyncSessionsClient() {
+ return sync_sessions_client_;
+}
+
+autofill::PersonalDataManager* BundleSyncClient::GetPersonalDataManager() {
+ return personal_data_manager_;
+}
+
+base::WeakPtr<syncer::SyncableService>
+BundleSyncClient::GetSyncableServiceForType(syncer::ModelType type) {
+ if (get_syncable_service_callback_.is_null())
+ return syncer::FakeSyncClient::GetSyncableServiceForType(type);
+ return get_syncable_service_callback_.Run(type);
+}
+
+syncer::SyncService* BundleSyncClient::GetSyncService() {
+ if (get_sync_service_callback_.is_null())
+ return syncer::FakeSyncClient::GetSyncService();
+ return get_sync_service_callback_.Run();
+}
+
+scoped_refptr<syncer::ModelSafeWorker>
+BundleSyncClient::CreateModelWorkerForGroup(
+ syncer::ModelSafeGroup group,
+ syncer::WorkerLoopDestructionObserver* observer) {
+ if (!db_thread_)
+ return FakeSyncClient::CreateModelWorkerForGroup(group, observer);
+ DCHECK(file_thread_) << "DB thread was specified but FILE thread was not.";
+ switch (group) {
+ case syncer::GROUP_DB:
+ return new syncer::BrowserThreadModelWorker(db_thread_, syncer::GROUP_DB,
+ observer);
+ case syncer::GROUP_FILE:
+ return new syncer::BrowserThreadModelWorker(file_thread_,
+ syncer::GROUP_FILE, observer);
+ case syncer::GROUP_UI:
+ return new syncer::UIModelWorker(base::ThreadTaskRunnerHandle::Get(),
+ observer);
+ case syncer::GROUP_PASSIVE:
+ return new syncer::PassiveModelWorker(observer);
+ case syncer::GROUP_HISTORY: {
+ history::HistoryService* history_service = GetHistoryService();
+ if (!history_service)
+ return nullptr;
+ return new HistoryModelWorker(history_service->AsWeakPtr(),
+ base::ThreadTaskRunnerHandle::Get(),
+ observer);
+ }
+ default:
+ return nullptr;
+ }
+}
+
+history::HistoryService* BundleSyncClient::GetHistoryService() {
+ if (history_service_)
+ return history_service_;
+ return FakeSyncClient::GetHistoryService();
+}
+
+bookmarks::BookmarkModel* BundleSyncClient::GetBookmarkModel() {
+ if (get_bookmark_model_callback_.is_null())
+ return FakeSyncClient::GetBookmarkModel();
+ return get_bookmark_model_callback_.Run();
+}
+
+} // namespace
+
+void EmptyNetworkTimeUpdate(const base::Time&,
+ const base::TimeDelta&,
+ const base::TimeDelta&) {}
+
+void RegisterPrefsForProfileSyncService(
+ user_prefs::PrefRegistrySyncable* registry) {
+ syncer::SyncPrefs::RegisterProfilePrefs(registry);
+ AccountTrackerService::RegisterPrefs(registry);
+ SigninManagerBase::RegisterProfilePrefs(registry);
+ SigninManagerBase::RegisterPrefs(registry);
+}
+
+ProfileSyncServiceBundle::SyncClientBuilder::~SyncClientBuilder() = default;
+
+ProfileSyncServiceBundle::SyncClientBuilder::SyncClientBuilder(
+ ProfileSyncServiceBundle* bundle)
+ : bundle_(bundle) {}
+
+void ProfileSyncServiceBundle::SyncClientBuilder::SetPersonalDataManager(
+ autofill::PersonalDataManager* personal_data_manager) {
+ personal_data_manager_ = personal_data_manager;
+}
+
+// The client will call this callback to produce the service.
+void ProfileSyncServiceBundle::SyncClientBuilder::SetSyncableServiceCallback(
+ const base::Callback<base::WeakPtr<syncer::SyncableService>(
+ syncer::ModelType type)>& get_syncable_service_callback) {
+ get_syncable_service_callback_ = get_syncable_service_callback;
+}
+
+// The client will call this callback to produce the service.
+void ProfileSyncServiceBundle::SyncClientBuilder::SetSyncServiceCallback(
+ const base::Callback<syncer::SyncService*(void)>&
+ get_sync_service_callback) {
+ get_sync_service_callback_ = get_sync_service_callback;
+}
+
+void ProfileSyncServiceBundle::SyncClientBuilder::SetHistoryService(
+ history::HistoryService* history_service) {
+ history_service_ = history_service;
+}
+
+void ProfileSyncServiceBundle::SyncClientBuilder::SetBookmarkModelCallback(
+ const base::Callback<bookmarks::BookmarkModel*(void)>&
+ get_bookmark_model_callback) {
+ get_bookmark_model_callback_ = get_bookmark_model_callback;
+}
+
+std::unique_ptr<syncer::FakeSyncClient>
+ProfileSyncServiceBundle::SyncClientBuilder::Build() {
+ return base::MakeUnique<BundleSyncClient>(
+ bundle_->component_factory(), bundle_->pref_service(),
+ bundle_->sync_sessions_client(), personal_data_manager_,
+ get_syncable_service_callback_, get_sync_service_callback_,
+ get_bookmark_model_callback_,
+ activate_model_creation_ ? bundle_->db_thread() : nullptr,
+ activate_model_creation_ ? base::ThreadTaskRunnerHandle::Get() : nullptr,
+ history_service_);
+}
+
+ProfileSyncServiceBundle::ProfileSyncServiceBundle()
+ : db_thread_(base::ThreadTaskRunnerHandle::Get()),
+ worker_pool_owner_(2, "sync test worker pool"),
+ signin_client_(&pref_service_),
+#if defined(OS_CHROMEOS)
+ signin_manager_(&signin_client_, &account_tracker_),
+#else
+ signin_manager_(&signin_client_,
+ &auth_service_,
+ &account_tracker_,
+ nullptr),
+#endif
+ url_request_context_(new net::TestURLRequestContextGetter(
+ base::ThreadTaskRunnerHandle::Get())) {
+ RegisterPrefsForProfileSyncService(pref_service_.registry());
+ auth_service_.set_auto_post_fetch_response_on_message_loop(true);
+ account_tracker_.Initialize(&signin_client_);
+ signin_manager_.Initialize(&pref_service_);
+}
+
+ProfileSyncServiceBundle::~ProfileSyncServiceBundle() {}
+
+ProfileSyncService::InitParams ProfileSyncServiceBundle::CreateBasicInitParams(
+ ProfileSyncService::StartBehavior start_behavior,
+ std::unique_ptr<syncer::SyncClient> sync_client) {
+ ProfileSyncService::InitParams init_params;
+
+ init_params.start_behavior = start_behavior;
+ init_params.sync_client = std::move(sync_client);
+ init_params.signin_wrapper =
+ base::MakeUnique<SigninManagerWrapper>(signin_manager());
+ init_params.oauth2_token_service = auth_service();
+ init_params.network_time_update_callback =
+ base::Bind(&EmptyNetworkTimeUpdate);
+ init_params.base_directory = base::FilePath(FILE_PATH_LITERAL("dummyPath"));
+ init_params.url_request_context = url_request_context();
+ init_params.debug_identifier = "dummyDebugName";
+ init_params.channel = version_info::Channel::UNKNOWN;
+ init_params.db_thread = db_thread_;
+ init_params.file_thread = base::ThreadTaskRunnerHandle::Get();
+ init_params.blocking_pool = worker_pool_owner_.pool().get();
+
+ return init_params;
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/profile_sync_test_util.h b/chromium/components/browser_sync/profile_sync_test_util.h
new file mode 100644
index 00000000000..1c573a74abc
--- /dev/null
+++ b/chromium/components/browser_sync/profile_sync_test_util.h
@@ -0,0 +1,187 @@
+// 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 COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_TEST_UTIL_H_
+#define COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_TEST_UTIL_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/time/time.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/invalidation/impl/fake_invalidation_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/signin/core/browser/test_signin_client.h"
+#include "components/sync/driver/fake_sync_client.h"
+#include "components/sync/driver/sync_api_component_factory_mock.h"
+#include "components/sync_sessions/fake_sync_sessions_client.h"
+#include "components/syncable_prefs/testing_pref_service_syncable.h"
+
+namespace base {
+class Time;
+class TimeDelta;
+}
+
+namespace history {
+class HistoryService;
+}
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+namespace browser_sync {
+
+// An empty syncer::NetworkTimeUpdateCallback. Used in various tests to
+// instantiate ProfileSyncService.
+void EmptyNetworkTimeUpdate(const base::Time&,
+ const base::TimeDelta&,
+ const base::TimeDelta&);
+
+// Call this to register preferences needed for ProfileSyncService creation.
+void RegisterPrefsForProfileSyncService(
+ user_prefs::PrefRegistrySyncable* registry);
+
+// Aggregate this class to get all necessary support for creating a
+// ProfileSyncService in tests. The test still needs to have its own
+// MessageLoop, though.
+class ProfileSyncServiceBundle {
+ public:
+#if defined(OS_CHROMEOS)
+ typedef FakeSigninManagerBase FakeSigninManagerType;
+#else
+ typedef FakeSigninManager FakeSigninManagerType;
+#endif
+
+ ProfileSyncServiceBundle();
+
+ ~ProfileSyncServiceBundle();
+
+ // Builders
+
+ // Builds a child of FakeSyncClient which overrides some of the client's
+ // accessors to return objects from the bundle.
+ class SyncClientBuilder {
+ public:
+ // Construct the builder and associate with the |bundle| to source objects
+ // from.
+ explicit SyncClientBuilder(ProfileSyncServiceBundle* bundle);
+
+ ~SyncClientBuilder();
+
+ void SetPersonalDataManager(
+ autofill::PersonalDataManager* personal_data_manager);
+
+ // The client will call this callback to produce the SyncableService
+ // specific to |type|.
+ void SetSyncableServiceCallback(
+ const base::Callback<base::WeakPtr<syncer::SyncableService>(
+ syncer::ModelType type)>& get_syncable_service_callback);
+
+ // The client will call this callback to produce the SyncService for the
+ // current Profile.
+ void SetSyncServiceCallback(
+ const base::Callback<syncer::SyncService*(void)>&
+ get_sync_service_callback);
+
+ void SetHistoryService(history::HistoryService* history_service);
+
+ void SetBookmarkModelCallback(
+ const base::Callback<bookmarks::BookmarkModel*(void)>&
+ get_bookmark_model_callback);
+
+ void set_activate_model_creation() { activate_model_creation_ = true; }
+
+ std::unique_ptr<syncer::FakeSyncClient> Build();
+
+ private:
+ // Associated bundle to source objects from.
+ ProfileSyncServiceBundle* const bundle_;
+
+ autofill::PersonalDataManager* personal_data_manager_;
+ base::Callback<base::WeakPtr<syncer::SyncableService>(
+ syncer::ModelType type)>
+ get_syncable_service_callback_;
+ base::Callback<syncer::SyncService*(void)> get_sync_service_callback_;
+ history::HistoryService* history_service_ = nullptr;
+ base::Callback<bookmarks::BookmarkModel*(void)>
+ get_bookmark_model_callback_;
+ // If set, the built client will be able to build some ModelSafeWorker
+ // instances.
+ bool activate_model_creation_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncClientBuilder);
+ };
+
+ // Creates an InitParams instance with the specified |start_behavior| and
+ // |sync_client|, and fills the rest with dummy values and objects owned by
+ // the bundle.
+ ProfileSyncService::InitParams CreateBasicInitParams(
+ ProfileSyncService::StartBehavior start_behavior,
+ std::unique_ptr<syncer::SyncClient> sync_client);
+
+ // Accessors
+
+ net::URLRequestContextGetter* url_request_context() {
+ return url_request_context_.get();
+ }
+
+ syncable_prefs::TestingPrefServiceSyncable* pref_service() {
+ return &pref_service_;
+ }
+
+ FakeProfileOAuth2TokenService* auth_service() { return &auth_service_; }
+
+ FakeSigninManagerType* signin_manager() { return &signin_manager_; }
+
+ AccountTrackerService* account_tracker() { return &account_tracker_; }
+
+ syncer::SyncApiComponentFactoryMock* component_factory() {
+ return &component_factory_;
+ }
+
+ sync_sessions::FakeSyncSessionsClient* sync_sessions_client() {
+ return &sync_sessions_client_;
+ }
+
+ invalidation::FakeInvalidationService* fake_invalidation_service() {
+ return &fake_invalidation_service_;
+ }
+
+ base::SingleThreadTaskRunner* db_thread() { return db_thread_.get(); }
+
+ void set_db_thread(
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread) {
+ db_thread_ = db_thread;
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+ base::SequencedWorkerPoolOwner worker_pool_owner_;
+ syncable_prefs::TestingPrefServiceSyncable pref_service_;
+ TestSigninClient signin_client_;
+ AccountTrackerService account_tracker_;
+ FakeSigninManagerType signin_manager_;
+ FakeProfileOAuth2TokenService auth_service_;
+ syncer::SyncApiComponentFactoryMock component_factory_;
+ sync_sessions::FakeSyncSessionsClient sync_sessions_client_;
+ invalidation::FakeInvalidationService fake_invalidation_service_;
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceBundle);
+};
+
+} // namespace browser_sync
+
+#endif // COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_TEST_UTIL_H_
diff --git a/chromium/components/browser_sync/signin_confirmation_helper.cc b/chromium/components/browser_sync/signin_confirmation_helper.cc
new file mode 100644
index 00000000000..0a59831753c
--- /dev/null
+++ b/chromium/components/browser_sync/signin_confirmation_helper.cc
@@ -0,0 +1,120 @@
+// 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 "components/browser_sync/signin_confirmation_helper.h"
+
+#include <memory>
+
+#include "base/strings/string16.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/history/core/browser/history_backend.h"
+#include "components/history/core/browser/history_db_task.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/history_types.h"
+
+namespace browser_sync {
+
+namespace {
+
+// Determines whether there are any typed URLs in a history backend.
+class HasTypedURLsTask : public history::HistoryDBTask {
+ public:
+ explicit HasTypedURLsTask(const base::Callback<void(bool)>& cb)
+ : has_typed_urls_(false), cb_(cb) {}
+
+ bool RunOnDBThread(history::HistoryBackend* backend,
+ history::HistoryDatabase* db) override {
+ history::URLRows rows;
+ backend->GetAllTypedURLs(&rows);
+ if (!rows.empty()) {
+ DVLOG(1) << "SigninConfirmationHelper: history contains " << rows.size()
+ << " typed URLs";
+ has_typed_urls_ = true;
+ }
+ return true;
+ }
+
+ void DoneRunOnMainThread() override { cb_.Run(has_typed_urls_); }
+
+ private:
+ ~HasTypedURLsTask() override {}
+
+ bool has_typed_urls_;
+ base::Callback<void(bool)> cb_;
+};
+
+} // namespace
+
+SigninConfirmationHelper::SigninConfirmationHelper(
+ history::HistoryService* history_service,
+ const base::Callback<void(bool)>& return_result)
+ : origin_thread_(base::ThreadTaskRunnerHandle::Get()),
+ history_service_(history_service),
+ pending_requests_(0),
+ return_result_(return_result) {}
+
+SigninConfirmationHelper::~SigninConfirmationHelper() {
+ DCHECK(origin_thread_->BelongsToCurrentThread());
+}
+
+void SigninConfirmationHelper::OnHistoryQueryResults(
+ size_t max_entries,
+ history::QueryResults* results) {
+ history::QueryResults owned_results;
+ results->Swap(&owned_results);
+ bool too_much_history = owned_results.size() >= max_entries;
+ if (too_much_history) {
+ DVLOG(1) << "SigninConfirmationHelper: profile contains "
+ << owned_results.size() << " history entries";
+ }
+ ReturnResult(too_much_history);
+}
+
+void SigninConfirmationHelper::CheckHasHistory(int max_entries) {
+ pending_requests_++;
+ if (!history_service_) {
+ PostResult(false);
+ return;
+ }
+ history::QueryOptions opts;
+ opts.max_count = max_entries;
+ history_service_->QueryHistory(
+ base::string16(), opts,
+ base::Bind(&SigninConfirmationHelper::OnHistoryQueryResults,
+ base::Unretained(this), max_entries),
+ &task_tracker_);
+}
+
+void SigninConfirmationHelper::CheckHasTypedURLs() {
+ pending_requests_++;
+ if (!history_service_) {
+ PostResult(false);
+ return;
+ }
+ history_service_->ScheduleDBTask(
+ std::unique_ptr<history::HistoryDBTask>(new HasTypedURLsTask(base::Bind(
+ &SigninConfirmationHelper::ReturnResult, base::Unretained(this)))),
+ &task_tracker_);
+}
+
+void SigninConfirmationHelper::PostResult(bool result) {
+ origin_thread_->PostTask(FROM_HERE,
+ base::Bind(&SigninConfirmationHelper::ReturnResult,
+ base::Unretained(this), result));
+}
+
+void SigninConfirmationHelper::ReturnResult(bool result) {
+ DCHECK(origin_thread_->BelongsToCurrentThread());
+ // Pass |true| into the callback as soon as one of the tasks passes a
+ // result of |true|, otherwise pass the last returned result.
+ if (--pending_requests_ == 0 || result) {
+ return_result_.Run(result);
+
+ // This leaks at shutdown if the HistoryService is destroyed, but
+ // the process is going to die anyway.
+ delete this;
+ }
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/signin_confirmation_helper.h b/chromium/components/browser_sync/signin_confirmation_helper.h
new file mode 100644
index 00000000000..27bd62ef1bf
--- /dev/null
+++ b/chromium/components/browser_sync/signin_confirmation_helper.h
@@ -0,0 +1,70 @@
+// 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 COMPONENTS_BROWSER_SYNC_SIGNIN_CONFIRMATION_HELPER_H_
+#define COMPONENTS_BROWSER_SYNC_SIGNIN_CONFIRMATION_HELPER_H_
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/task/cancelable_task_tracker.h"
+
+namespace history {
+class HistoryService;
+class QueryResults;
+}
+
+namespace browser_sync {
+
+// Helper class for sync signin to check some asynchronous conditions. Call
+// either CheckHasHistory or CheckHasTypedUrls or both, and |return_result|
+// will be called with true if either returns true, otherwise false.
+class SigninConfirmationHelper {
+ public:
+ SigninConfirmationHelper(history::HistoryService* history_service,
+ const base::Callback<void(bool)>& return_result);
+
+ // This helper checks if there are history entries in the history service.
+ void CheckHasHistory(int max_entries);
+
+ // This helper checks if there are typed URLs in the history service.
+ void CheckHasTypedURLs();
+
+ private:
+ // Deletes itself.
+ ~SigninConfirmationHelper();
+
+ // Callback helper function for CheckHasHistory.
+ void OnHistoryQueryResults(size_t max_entries,
+ history::QueryResults* results);
+
+ // Posts the given result to the origin thread.
+ void PostResult(bool result);
+
+ // Calls |return_result_| if |result| == true or if it's the result of the
+ // last pending check.
+ void ReturnResult(bool result);
+
+ // The task runner for the thread this object was constructed on.
+ const scoped_refptr<base::SingleThreadTaskRunner> origin_thread_;
+
+ // Pointer to the history service.
+ history::HistoryService* history_service_;
+
+ // Used for async tasks.
+ base::CancelableTaskTracker task_tracker_;
+
+ // Keep track of how many async requests are pending.
+ int pending_requests_;
+
+ // Callback to pass the result back to the caller.
+ const base::Callback<void(bool)> return_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(SigninConfirmationHelper);
+};
+
+} // namespace browser_sync
+
+#endif // COMPONENTS_BROWSER_SYNC_SIGNIN_CONFIRMATION_HELPER_H_
diff --git a/chromium/components/browser_sync/test_http_bridge_factory.cc b/chromium/components/browser_sync/test_http_bridge_factory.cc
new file mode 100644
index 00000000000..e20bdc77439
--- /dev/null
+++ b/chromium/components/browser_sync/test_http_bridge_factory.cc
@@ -0,0 +1,44 @@
+// 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 "components/browser_sync/test_http_bridge_factory.h"
+
+namespace browser_sync {
+
+bool TestHttpBridge::MakeSynchronousPost(int* error_code, int* response_code) {
+ return false;
+}
+
+int TestHttpBridge::GetResponseContentLength() const {
+ return 0;
+}
+
+const char* TestHttpBridge::GetResponseContent() const {
+ return 0;
+}
+
+const std::string TestHttpBridge::GetResponseHeaderValue(
+ const std::string&) const {
+ return std::string();
+}
+
+void TestHttpBridge::Abort() {}
+
+TestHttpBridgeFactory::TestHttpBridgeFactory() {}
+
+TestHttpBridgeFactory::~TestHttpBridgeFactory() {}
+
+void TestHttpBridgeFactory::Init(
+ const std::string& user_agent,
+ const syncer::BindToTrackerCallback& bind_to_tracker_callback) {}
+
+syncer::HttpPostProviderInterface* TestHttpBridgeFactory::Create() {
+ return new TestHttpBridge();
+}
+
+void TestHttpBridgeFactory::Destroy(syncer::HttpPostProviderInterface* http) {
+ delete static_cast<TestHttpBridge*>(http);
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/test_http_bridge_factory.h b/chromium/components/browser_sync/test_http_bridge_factory.h
new file mode 100644
index 00000000000..e2c229a3bda
--- /dev/null
+++ b/chromium/components/browser_sync/test_http_bridge_factory.h
@@ -0,0 +1,54 @@
+// 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 COMPONENTS_BROWSER_SYNC_TEST_HTTP_BRIDGE_FACTORY_H_
+#define COMPONENTS_BROWSER_SYNC_TEST_HTTP_BRIDGE_FACTORY_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "components/sync/core/http_post_provider_factory.h"
+#include "components/sync/core/http_post_provider_interface.h"
+
+namespace browser_sync {
+
+class TestHttpBridge : public syncer::HttpPostProviderInterface {
+ public:
+ // Begin syncer::HttpPostProviderInterface implementation:
+ void SetExtraRequestHeaders(const char* headers) override {}
+
+ void SetURL(const char* url, int port) override {}
+
+ void SetPostPayload(const char* content_type,
+ int content_length,
+ const char* content) override {}
+
+ bool MakeSynchronousPost(int* error_code, int* response_code) override;
+
+ int GetResponseContentLength() const override;
+
+ const char* GetResponseContent() const override;
+
+ const std::string GetResponseHeaderValue(const std::string&) const override;
+
+ void Abort() override;
+ // End syncer::HttpPostProviderInterface implementation.
+};
+
+class TestHttpBridgeFactory : public syncer::HttpPostProviderFactory {
+ public:
+ TestHttpBridgeFactory();
+ ~TestHttpBridgeFactory() override;
+
+ // syncer::HttpPostProviderFactory:
+ void Init(
+ const std::string& user_agent,
+ const syncer::BindToTrackerCallback& bind_to_tracker_callback) override;
+ syncer::HttpPostProviderInterface* Create() override;
+ void Destroy(syncer::HttpPostProviderInterface* http) override;
+};
+
+} // namespace browser_sync
+
+#endif // COMPONENTS_BROWSER_SYNC_TEST_HTTP_BRIDGE_FACTORY_H_
diff --git a/chromium/components/browser_sync/test_profile_sync_service.cc b/chromium/components/browser_sync/test_profile_sync_service.cc
new file mode 100644
index 00000000000..c7222ae5ea0
--- /dev/null
+++ b/chromium/components/browser_sync/test_profile_sync_service.cc
@@ -0,0 +1,36 @@
+// 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 "components/browser_sync/test_profile_sync_service.h"
+
+#include <utility>
+
+namespace browser_sync {
+
+syncer::TestIdFactory* TestProfileSyncService::id_factory() {
+ return &id_factory_;
+}
+
+syncer::WeakHandle<syncer::JsEventHandler>
+TestProfileSyncService::GetJsEventHandler() {
+ return syncer::WeakHandle<syncer::JsEventHandler>();
+}
+
+TestProfileSyncService::TestProfileSyncService(
+ ProfileSyncService::InitParams init_params)
+ : ProfileSyncService(std::move(init_params)) {}
+
+TestProfileSyncService::~TestProfileSyncService() {}
+
+void TestProfileSyncService::OnConfigureDone(
+ const syncer::DataTypeManager::ConfigureResult& result) {
+ ProfileSyncService::OnConfigureDone(result);
+ base::MessageLoop::current()->QuitWhenIdle();
+}
+
+syncer::UserShare* TestProfileSyncService::GetUserShare() const {
+ return backend_->GetUserShare();
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/test_profile_sync_service.h b/chromium/components/browser_sync/test_profile_sync_service.h
new file mode 100644
index 00000000000..c1f8dc27708
--- /dev/null
+++ b/chromium/components/browser_sync/test_profile_sync_service.h
@@ -0,0 +1,54 @@
+// 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 COMPONENTS_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
+#define COMPONENTS_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
+
+#include "base/macros.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/sync/base/weak_handle.h"
+#include "components/sync/driver/data_type_manager.h"
+#include "components/sync/js/js_event_handler.h"
+#include "components/sync/test/engine/test_id_factory.h"
+
+namespace syncer {
+class SyncPrefs;
+} // namespace syncer
+
+namespace browser_sync {
+
+class TestProfileSyncService : public ProfileSyncService {
+ public:
+ explicit TestProfileSyncService(InitParams init_params);
+
+ ~TestProfileSyncService() override;
+
+ void OnConfigureDone(
+ const syncer::DataTypeManager::ConfigureResult& result) override;
+
+ // We implement our own version to avoid some DCHECKs.
+ syncer::UserShare* GetUserShare() const override;
+
+ syncer::TestIdFactory* id_factory();
+
+ // Raise visibility to ease testing.
+ using ProfileSyncService::NotifyObservers;
+
+ syncer::SyncPrefs* sync_prefs() { return &sync_prefs_; }
+
+ protected:
+ // Return NULL handle to use in backend initialization to avoid receiving
+ // js messages on UI loop when it's being destroyed, which are not deleted
+ // and cause memory leak in test.
+ syncer::WeakHandle<syncer::JsEventHandler> GetJsEventHandler() override;
+
+ private:
+ syncer::TestIdFactory id_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestProfileSyncService);
+};
+
+} // namespace browser_sync
+
+#endif // COMPONENTS_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
diff --git a/chromium/components/browser_watcher.gypi b/chromium/components/browser_watcher.gypi
deleted file mode 100644
index b65d4631a7c..00000000000
--- a/chromium/components/browser_watcher.gypi
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'conditions': [
- ['OS=="win"', {
- 'targets': [
- {
- # This is a separate lib to minimize the dependencies for its
- # hosting binary "chrome_watcher.dll".
- 'target_name': 'browser_watcher',
- 'type': 'static_library',
- 'sources': [
- 'browser_watcher/endsession_watcher_window_win.cc',
- 'browser_watcher/endsession_watcher_window_win.h',
- 'browser_watcher/exit_code_watcher_win.cc',
- 'browser_watcher/exit_code_watcher_win.h',
- 'browser_watcher/exit_funnel_win.cc',
- 'browser_watcher/exit_funnel_win.h',
- 'browser_watcher/window_hang_monitor_win.cc',
- 'browser_watcher/window_hang_monitor_win.h',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- },
- {
- # Users of the watcher link this target.
- 'target_name': 'browser_watcher_client',
- 'type': 'static_library',
- 'sources': [
- 'browser_watcher/watcher_client_win.cc',
- 'browser_watcher/watcher_client_win.h',
- 'browser_watcher/watcher_metrics_provider_win.cc',
- 'browser_watcher/watcher_metrics_provider_win.h',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- },
- ],
- }
- ],
- ],
-} \ No newline at end of file
diff --git a/chromium/components/browser_watcher/BUILD.gn b/chromium/components/browser_watcher/BUILD.gn
index 8b95bcd060a..f024ed5d549 100644
--- a/chromium/components/browser_watcher/BUILD.gn
+++ b/chromium/components/browser_watcher/BUILD.gn
@@ -2,7 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser_watcher") {
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("stability_report_proto") {
+ sources = [
+ "stability_report.proto",
+ ]
+}
+
+static_library("browser_watcher") {
# This is a separate lib to minimize the dependencies for its
# hosting binary "chrome_watcher.dll".
sources = [
@@ -20,7 +28,7 @@ source_set("browser_watcher") {
]
}
-source_set("browser_watcher_client") {
+static_library("browser_watcher_client") {
sources = [
"watcher_client_win.cc",
"watcher_client_win.h",
@@ -28,8 +36,52 @@ source_set("browser_watcher_client") {
"watcher_metrics_provider_win.h",
]
deps = [
+ ":postmortem_report_collector",
+ ":stability",
"//base",
"//components/metrics",
+ "//third_party/crashpad/crashpad/client",
+ ]
+}
+
+static_library("postmortem_minidump_writer") {
+ # TODO(manzagop): remove this lib once Crashpad writes the minidumps.
+ sources = [
+ "postmortem_minidump_writer.h",
+ "postmortem_minidump_writer_win.cc",
+ ]
+ deps = [
+ ":stability_report_proto",
+ "//base",
+ "//third_party/crashpad/crashpad/client",
+ "//third_party/crashpad/crashpad/minidump",
+ "//third_party/crashpad/crashpad/util",
+ ]
+}
+
+static_library("postmortem_report_collector") {
+ sources = [
+ "postmortem_report_collector.cc",
+ "postmortem_report_collector.h",
+ ]
+ deps = [
+ ":postmortem_minidump_writer",
+ ":stability_report_proto",
+ "//base",
+ "//third_party/crashpad/crashpad/client",
+ "//third_party/crashpad/crashpad/util",
+ ]
+}
+
+static_library("stability") {
+ sources = [
+ "features.cc",
+ "features.h",
+ "stability_debugging_win.cc",
+ "stability_debugging_win.h",
+ ]
+ deps = [
+ "//base",
]
}
@@ -39,6 +91,8 @@ source_set("unit_tests") {
"endsession_watcher_window_win_unittest.cc",
"exit_code_watcher_win_unittest.cc",
"exit_funnel_win_unittest.cc",
+ "postmortem_minidump_writer_win_unittest.cc",
+ "postmortem_report_collector_unittest.cc",
"watcher_client_win_unittest.cc",
"watcher_metrics_provider_win_unittest.cc",
"window_hang_monitor_win_unittest.cc",
@@ -47,8 +101,29 @@ source_set("unit_tests") {
deps = [
":browser_watcher",
":browser_watcher_client",
+ ":postmortem_minidump_writer",
+ ":postmortem_report_collector",
+ ":stability_report_proto",
"//base",
"//base/test:test_support",
+ "//testing/gmock",
"//testing/gtest",
+ "//third_party/crashpad/crashpad/client",
+
+ # TODO(manzagop): remove this lib once Crashpad writes the minidumps.
+ "//third_party/crashpad/crashpad/compat",
+ "//third_party/crashpad/crashpad/minidump",
+ "//third_party/crashpad/crashpad/snapshot",
+ "//third_party/crashpad/crashpad/util",
+ ]
+}
+
+executable("dump_postmortem") {
+ sources = [
+ "dump_postmortem_minidump_main_win.cc",
+ ]
+ deps = [
+ ":stability_report_proto",
+ "//base",
]
}
diff --git a/chromium/components/browser_watcher/DEPS b/chromium/components/browser_watcher/DEPS
index 5ea95eaf28b..1d59b5cc9d2 100644
--- a/chromium/components/browser_watcher/DEPS
+++ b/chromium/components/browser_watcher/DEPS
@@ -1,3 +1,4 @@
include_rules = [
- "+components/metrics"
+ "+components/metrics",
+ "+third_party/crashpad/crashpad",
]
diff --git a/chromium/components/browser_watcher/OWNERS b/chromium/components/browser_watcher/OWNERS
index 147afd99170..a2ea389cf4e 100644
--- a/chromium/components/browser_watcher/OWNERS
+++ b/chromium/components/browser_watcher/OWNERS
@@ -1 +1,2 @@
siggi@chromium.org
+manzagop@chromium.org
diff --git a/chromium/components/browser_watcher/dump_postmortem_minidump_main_win.cc b/chromium/components/browser_watcher/dump_postmortem_minidump_main_win.cc
new file mode 100644
index 00000000000..1b9aabe4d99
--- /dev/null
+++ b/chromium/components/browser_watcher/dump_postmortem_minidump_main_win.cc
@@ -0,0 +1,105 @@
+// 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.
+
+// A utility for printing the contents of a postmortem stability minidump.
+
+#include <windows.h> // NOLINT
+#include <dbghelp.h>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "components/browser_watcher/stability_report.pb.h"
+
+namespace {
+
+const char kUsage[] =
+ "Usage: %ls --minidump=<minidump file>\n"
+ "\n"
+ " Dumps the contents of a postmortem minidump in a human readable way.\n";
+
+bool ParseCommandLine(const base::CommandLine* cmd,
+ base::FilePath* minidump_path) {
+ *minidump_path = cmd->GetSwitchValuePath("minidump");
+ if (minidump_path->empty()) {
+ LOG(ERROR) << "Missing minidump file.\n";
+ LOG(ERROR) << base::StringPrintf(kUsage, cmd->GetProgram().value().c_str());
+ return false;
+ }
+ return true;
+}
+
+void PrintProcessState(FILE* out,
+ const browser_watcher::ProcessState& process) {
+ fprintf(out, "%s", "Process:\n");
+ for (int i = 0; i < process.threads_size(); ++i) {
+ const browser_watcher::ThreadState thread = process.threads(i);
+ fprintf(out, "%s\n", thread.thread_name().c_str());
+ }
+}
+
+// TODO(manzagop): flesh out as StabilityReport gets fleshed out.
+void PrintReport(FILE* out, const browser_watcher::StabilityReport& report) {
+ for (int i = 0; i < report.process_states_size(); ++i) {
+ const browser_watcher::ProcessState process = report.process_states(i);
+ PrintProcessState(out, process);
+ }
+}
+
+int Main(int argc, char** argv) {
+ base::CommandLine::Init(argc, argv);
+
+ // Get the dump.
+ base::FilePath minidump_path;
+ if (!ParseCommandLine(base::CommandLine::ForCurrentProcess(), &minidump_path))
+ return 1;
+
+ // Read the minidump to extract the proto.
+ base::ScopedFILE minidump_file;
+ minidump_file.reset(base::OpenFile(minidump_path, "rb"));
+ CHECK(minidump_file.get());
+
+ // Read the header.
+ // TODO(manzagop): leverage Crashpad to do this.
+ MINIDUMP_HEADER header = {};
+ CHECK_EQ(1U, fread(&header, sizeof(header), 1U, minidump_file.get()));
+ CHECK_EQ(static_cast<ULONG32>(MINIDUMP_SIGNATURE), header.Signature);
+ CHECK_EQ(2U, header.NumberOfStreams);
+ RVA directory_rva = header.StreamDirectoryRva;
+
+ // Read the directory entry for the stability report's stream.
+ // Note: this hardcodes an expectation that the stability report is the first
+ // encountered stream. This is acceptable for a debug tool.
+ MINIDUMP_DIRECTORY directory = {};
+ CHECK_EQ(0, fseek(minidump_file.get(), directory_rva, SEEK_SET));
+ CHECK_EQ(1U, fread(&directory, sizeof(directory), 1U, minidump_file.get()));
+ CHECK_EQ(static_cast<ULONG32>(0x4B6B0002), directory.StreamType);
+ RVA report_rva = directory.Location.Rva;
+ ULONG32 report_size_bytes = directory.Location.DataSize;
+
+ // Read the serialized stability report.
+ std::string serialized_report;
+ serialized_report.resize(report_size_bytes);
+ CHECK_EQ(0, fseek(minidump_file.get(), report_rva, SEEK_SET));
+ CHECK_EQ(report_size_bytes, fread(&serialized_report.at(0), 1,
+ report_size_bytes, minidump_file.get()));
+
+ browser_watcher::StabilityReport report;
+ CHECK(report.ParseFromString(serialized_report));
+
+ // Note: we can't use the usual protocol buffer human readable API due to
+ // the use of optimize_for = LITE_RUNTIME.
+ PrintReport(stdout, report);
+
+ return 0;
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ return Main(argc, argv);
+}
diff --git a/chromium/components/browser_watcher/features.cc b/chromium/components/browser_watcher/features.cc
new file mode 100644
index 00000000000..87b65aa661e
--- /dev/null
+++ b/chromium/components/browser_watcher/features.cc
@@ -0,0 +1,13 @@
+// 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 "components/browser_watcher/features.h"
+
+namespace browser_watcher {
+
+// Additional stability instrumentation.
+const base::Feature kStabilityDebuggingFeature{
+ "StabilityDebugging", base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/features.h b/chromium/components/browser_watcher/features.h
new file mode 100644
index 00000000000..26ab23f353f
--- /dev/null
+++ b/chromium/components/browser_watcher/features.h
@@ -0,0 +1,16 @@
+// 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 COMPONENTS_BROWSER_WATCHER_FEATURES_H_
+#define COMPONENTS_BROWSER_WATCHER_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace browser_watcher {
+
+extern const base::Feature kStabilityDebuggingFeature;
+
+} // namespace browser_watcher
+
+#endif // COMPONENTS_BROWSER_WATCHER_FEATURES_H_
diff --git a/chromium/components/browser_watcher/postmortem_minidump_writer.h b/chromium/components/browser_watcher/postmortem_minidump_writer.h
new file mode 100644
index 00000000000..28758f84a68
--- /dev/null
+++ b/chromium/components/browser_watcher/postmortem_minidump_writer.h
@@ -0,0 +1,48 @@
+// 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 COMPONENTS_BROWSER_WATCHER_POSTMORTEM_MINIDUMP_WRITER_H_
+#define COMPONENTS_BROWSER_WATCHER_POSTMORTEM_MINIDUMP_WRITER_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/files/file.h"
+#include "components/browser_watcher/stability_report.pb.h"
+#include "third_party/crashpad/crashpad/util/misc/uuid.h"
+
+namespace browser_watcher {
+
+// Minidump information required by the Crashpad reporter.
+struct MinidumpInfo {
+ MinidumpInfo();
+ ~MinidumpInfo();
+
+ // Client and report identifiers, from the Crashpad database.
+ crashpad::UUID client_id;
+ crashpad::UUID report_id;
+
+ // Product name, version number and channel name from the executable's version
+ // resource.
+ std::string product_name;
+ std::string version_number;
+ std::string channel_name;
+
+ // The platform identifier (e.g. "Win32" or "Win64").
+ std::string platform;
+};
+
+// Write to |minidump_file| a minimal minidump that wraps |report|. Returns
+// true on success, false otherwise.
+// Note: the caller owns |minidump_file| and is responsible for keeping it valid
+// for this function's duration. |minidump_file| is expected to be empty
+// and a binary stream.
+bool WritePostmortemDump(base::PlatformFile minidump_file,
+ const StabilityReport& report,
+ const MinidumpInfo& minidump_info);
+
+} // namespace browser_watcher
+
+#endif // COMPONENTS_BROWSER_WATCHER_POSTMORTEM_MINIDUMP_WRITER_H_
diff --git a/chromium/components/browser_watcher/postmortem_minidump_writer_win.cc b/chromium/components/browser_watcher/postmortem_minidump_writer_win.cc
new file mode 100644
index 00000000000..4a61f1efb2f
--- /dev/null
+++ b/chromium/components/browser_watcher/postmortem_minidump_writer_win.cc
@@ -0,0 +1,419 @@
+// 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.
+//
+// Note: aside from using windows headers to obtain the definitions of minidump
+// structures, nothing here is windows specific. This seems like the best
+// approach given this code is for temporary experimentation on Windows.
+// Longer term, Crashpad will take over the minidump writing in this case as
+// well.
+
+#include "components/browser_watcher/postmortem_minidump_writer.h"
+
+#include <windows.h> // NOLINT
+#include <dbghelp.h>
+
+#include <map>
+#include <type_traits>
+#include <vector>
+
+#include "base/files/file_util.h"
+#include "base/macros.h"
+#include "base/numerics/safe_math.h"
+#include "base/strings/string_piece.h"
+#include "third_party/crashpad/crashpad/minidump/minidump_extensions.h"
+
+namespace browser_watcher {
+
+namespace {
+
+// The stream type assigned to the minidump stream that holds the serialized
+// stability report.
+// Note: the value was obtained by adding 1 to the stream type used for holding
+// the SyzyAsan proto.
+// TODO(manzagop): centralize the stream type definitions to avoid issues.
+const uint32_t kStabilityReportStreamType = 0x4B6B0002;
+
+int64_t GetFileOffset(base::File* file) {
+ DCHECK(file);
+ return file->Seek(base::File::FROM_CURRENT, 0LL);
+}
+
+// Returns true if the file is empty, and false if the file is not empty or if
+// there is an error.
+bool IsFileEmpty(base::File* file) {
+ DCHECK(file);
+ int64_t end = file->Seek(base::File::FROM_END, 0LL);
+ return end == 0LL;
+}
+
+// A class with functionality for writing minimal minidump containers to wrap
+// postmortem stability reports.
+// TODO(manzagop): remove this class once Crashpad takes over writing postmortem
+// minidumps.
+// TODO(manzagop): revisit where the module information should be transported,
+// in the protocol buffer or in a module stream.
+class PostmortemMinidumpWriter {
+ public:
+ PostmortemMinidumpWriter();
+ ~PostmortemMinidumpWriter();
+
+ // Write to |minidump_file| a minimal minidump that wraps |report|. Returns
+ // true on success, false otherwise.
+ // Note: the caller owns |minidump_file| and is responsible for keeping it
+ // valid for this object's lifetime. |minidump_file| is expected to be empty
+ // and a binary stream.
+ bool WriteDump(base::PlatformFile minidump_file,
+ const StabilityReport& report,
+ const MinidumpInfo& minidump_info);
+
+ private:
+ // An offset within a minidump file. Note: using this type to avoid including
+ // windows.h and relying on the RVA type.
+ using FilePosition = uint32_t;
+
+ // The minidump header is always located at the head.
+ static const FilePosition kHeaderPos = 0U;
+
+ bool WriteDumpImpl(const StabilityReport& report,
+ const MinidumpInfo& minidump_info);
+
+ bool AppendCrashpadInfo(const crashpad::UUID& client_id,
+ const crashpad::UUID& report_id,
+ const std::map<std::string, std::string>& crash_keys);
+
+ bool AppendCrashpadDictionaryEntry(
+ const std::string& key,
+ const std::string& value,
+ std::vector<crashpad::MinidumpSimpleStringDictionaryEntry>* entries);
+
+ // Allocate |size_bytes| within the minidump. On success, |pos| contains the
+ // location of the allocation. Returns true on success, false otherwise.
+ bool Allocate(size_t size_bytes, FilePosition* pos);
+
+ // Seeks |cursor_|. The seek operation is kept separate from the write in
+ // order to make the call explicit. Seek operations can be costly and should
+ // be avoided.
+ bool SeekCursor(FilePosition destination);
+
+ // Write to pre-allocated space.
+ // Note: |pos| must match |cursor_|.
+ template <class DataType>
+ bool Write(FilePosition pos, const DataType& data);
+ bool WriteBytes(FilePosition pos, size_t size_bytes, const char* data);
+
+ // Allocate space for and write the contents of |data|. On success, |pos|
+ // contains the location of the write. Returns true on success, false
+ // otherwise.
+ template <class DataType>
+ bool Append(const DataType& data, FilePosition* pos);
+ template <class DataType>
+ bool AppendVec(const std::vector<DataType>& data, FilePosition* pos);
+ bool AppendUtf8String(base::StringPiece data, FilePosition* pos);
+ bool AppendBytes(base::StringPiece data, FilePosition* pos);
+
+ void RegisterDirectoryEntry(uint32_t stream_type,
+ FilePosition pos,
+ uint32_t size);
+
+ // The next allocatable FilePosition.
+ FilePosition next_available_byte_;
+
+ // Storage for the directory during writes.
+ std::vector<MINIDUMP_DIRECTORY> directory_;
+
+ // The file to write to. Only valid within the scope of a call to WriteDump.
+ base::File* minidump_file_;
+
+ DISALLOW_COPY_AND_ASSIGN(PostmortemMinidumpWriter);
+};
+
+PostmortemMinidumpWriter::PostmortemMinidumpWriter()
+ : next_available_byte_(0U), minidump_file_(nullptr) {}
+
+PostmortemMinidumpWriter::~PostmortemMinidumpWriter() {
+ DCHECK_EQ(nullptr, minidump_file_);
+}
+
+bool PostmortemMinidumpWriter::WriteDump(
+ base::PlatformFile minidump_platform_file,
+ const StabilityReport& report,
+ const MinidumpInfo& minidump_info) {
+ DCHECK_NE(base::kInvalidPlatformFile, minidump_platform_file);
+
+ DCHECK_EQ(0U, next_available_byte_);
+ DCHECK(directory_.empty());
+ DCHECK_EQ(nullptr, minidump_file_);
+
+ // We do not own |minidump_platform_file|, but we want to rely on base::File's
+ // API, and so we need to duplicate it.
+ HANDLE duplicated_handle;
+ BOOL duplicate_success = ::DuplicateHandle(
+ ::GetCurrentProcess(), minidump_platform_file, ::GetCurrentProcess(),
+ &duplicated_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ if (!duplicate_success)
+ return false;
+ base::File minidump_file(duplicated_handle);
+ DCHECK(minidump_file.IsValid());
+ minidump_file_ = &minidump_file;
+ DCHECK_EQ(0LL, GetFileOffset(minidump_file_));
+ DCHECK(IsFileEmpty(minidump_file_));
+
+ // Write the minidump, then reset members.
+ bool success = WriteDumpImpl(report, minidump_info);
+ next_available_byte_ = 0U;
+ directory_.clear();
+ minidump_file_ = nullptr;
+
+ return success;
+}
+
+bool PostmortemMinidumpWriter::WriteDumpImpl(
+ const StabilityReport& report,
+ const MinidumpInfo& minidump_info) {
+ // Allocate space for the header and seek the cursor.
+ FilePosition pos = 0U;
+ if (!Allocate(sizeof(MINIDUMP_HEADER), &pos))
+ return false;
+ if (!SeekCursor(sizeof(MINIDUMP_HEADER)))
+ return false;
+ DCHECK_EQ(kHeaderPos, pos);
+
+ // Write the proto to the file.
+ std::string serialized_report;
+ if (!report.SerializeToString(&serialized_report))
+ return false;
+ FilePosition report_pos = 0U;
+ if (!AppendBytes(serialized_report, &report_pos))
+ return false;
+
+ // The directory entry for the stability report's stream.
+ RegisterDirectoryEntry(kStabilityReportStreamType, report_pos,
+ serialized_report.length());
+
+ // Write mandatory crash keys. These will be read by crashpad and used as
+ // http request parameters for the upload. Keys and values should match
+ // server side configuration.
+ // TODO(manzagop): use product and version from the stability report. The
+ // current executable's values are an (imperfect) proxy.
+ std::map<std::string, std::string> crash_keys = {
+ {"prod", minidump_info.product_name + "_Postmortem"},
+ {"ver", minidump_info.version_number},
+ {"channel", minidump_info.channel_name},
+ {"plat", minidump_info.platform}};
+ if (!AppendCrashpadInfo(minidump_info.client_id, minidump_info.report_id,
+ crash_keys))
+ return false;
+
+ // Write the directory.
+ FilePosition directory_pos = 0U;
+ if (!AppendVec(directory_, &directory_pos))
+ return false;
+
+ // Write the header.
+ MINIDUMP_HEADER header;
+ header.Signature = MINIDUMP_SIGNATURE;
+ header.Version = MINIDUMP_VERSION;
+ header.NumberOfStreams = directory_.size();
+ header.StreamDirectoryRva = directory_pos;
+ if (!SeekCursor(0U))
+ return false;
+ return Write(kHeaderPos, header);
+}
+
+bool PostmortemMinidumpWriter::AppendCrashpadInfo(
+ const crashpad::UUID& client_id,
+ const crashpad::UUID& report_id,
+ const std::map<std::string, std::string>& crash_keys) {
+ // Write the crash keys as the contents of a crashpad dictionary.
+ std::vector<crashpad::MinidumpSimpleStringDictionaryEntry> entries;
+ for (const auto& crash_key : crash_keys) {
+ if (!AppendCrashpadDictionaryEntry(crash_key.first, crash_key.second,
+ &entries)) {
+ return false;
+ }
+ }
+
+ // Write the dictionary's index.
+ FilePosition dict_pos = 0U;
+ uint32_t entry_count = entries.size();
+ if (entry_count > 0) {
+ if (!Append(entry_count, &dict_pos))
+ return false;
+ FilePosition unused_pos = 0U;
+ if (!AppendVec(entries, &unused_pos))
+ return false;
+ }
+
+ MINIDUMP_LOCATION_DESCRIPTOR simple_annotations = {0};
+ simple_annotations.DataSize = 0U;
+ if (entry_count > 0)
+ simple_annotations.DataSize = next_available_byte_ - dict_pos;
+ // Note: an RVA of 0 indicates the absence of a dictionary.
+ simple_annotations.Rva = dict_pos;
+
+ // Write the crashpad info.
+ crashpad::MinidumpCrashpadInfo crashpad_info;
+ crashpad_info.version = crashpad::MinidumpCrashpadInfo::kVersion;
+ crashpad_info.report_id = report_id;
+ crashpad_info.client_id = client_id;
+ crashpad_info.simple_annotations = simple_annotations;
+ // Note: module_list is left at 0, which means none.
+
+ FilePosition crashpad_pos = 0U;
+ if (!Append(crashpad_info, &crashpad_pos))
+ return false;
+
+ // Append a directory entry for the crashpad info stream.
+ RegisterDirectoryEntry(crashpad::kMinidumpStreamTypeCrashpadInfo,
+ crashpad_pos, sizeof(crashpad::MinidumpCrashpadInfo));
+
+ return true;
+}
+
+bool PostmortemMinidumpWriter::AppendCrashpadDictionaryEntry(
+ const std::string& key,
+ const std::string& value,
+ std::vector<crashpad::MinidumpSimpleStringDictionaryEntry>* entries) {
+ DCHECK_NE(nullptr, entries);
+
+ FilePosition key_pos = 0U;
+ if (!AppendUtf8String(key, &key_pos))
+ return false;
+ FilePosition value_pos = 0U;
+ if (!AppendUtf8String(value, &value_pos))
+ return false;
+
+ crashpad::MinidumpSimpleStringDictionaryEntry entry = {0};
+ entry.key = key_pos;
+ entry.value = value_pos;
+ entries->push_back(entry);
+
+ return true;
+}
+
+bool PostmortemMinidumpWriter::Allocate(size_t size_bytes, FilePosition* pos) {
+ DCHECK(pos);
+ *pos = next_available_byte_;
+
+ base::CheckedNumeric<FilePosition> next = next_available_byte_;
+ next += size_bytes;
+ if (!next.IsValid())
+ return false;
+
+ next_available_byte_ += size_bytes;
+ return true;
+}
+
+bool PostmortemMinidumpWriter::SeekCursor(FilePosition destination) {
+ DCHECK_NE(nullptr, minidump_file_);
+ DCHECK(minidump_file_->IsValid());
+
+ // Validate the write does not extend past the allocated space.
+ if (destination > next_available_byte_)
+ return false;
+
+ int64_t new_pos = minidump_file_->Seek(base::File::FROM_BEGIN,
+ static_cast<int64_t>(destination));
+ return new_pos != -1;
+}
+
+template <class DataType>
+bool PostmortemMinidumpWriter::Write(FilePosition pos, const DataType& data) {
+ static_assert(std::is_trivially_copyable<DataType>::value,
+ "restricted to trivially copyable");
+ return WriteBytes(pos, sizeof(data), reinterpret_cast<const char*>(&data));
+}
+
+bool PostmortemMinidumpWriter::WriteBytes(FilePosition pos,
+ size_t size_bytes,
+ const char* data) {
+ DCHECK(data);
+ DCHECK_NE(nullptr, minidump_file_);
+ DCHECK(minidump_file_->IsValid());
+ DCHECK_EQ(static_cast<int64_t>(pos), GetFileOffset(minidump_file_));
+
+ // Validate the write does not extend past the next available byte.
+ base::CheckedNumeric<FilePosition> pos_end = pos;
+ pos_end += size_bytes;
+ if (!pos_end.IsValid() || pos_end.ValueOrDie() > next_available_byte_)
+ return false;
+
+ int size_bytes_signed = static_cast<int>(size_bytes);
+ CHECK_LE(0, size_bytes_signed);
+
+ int written_bytes =
+ minidump_file_->WriteAtCurrentPos(data, size_bytes_signed);
+ if (written_bytes < 0)
+ return false;
+ return static_cast<size_t>(written_bytes) == size_bytes;
+}
+
+template <class DataType>
+bool PostmortemMinidumpWriter::Append(const DataType& data, FilePosition* pos) {
+ static_assert(std::is_trivially_copyable<DataType>::value,
+ "restricted to trivially copyable");
+ DCHECK(pos);
+ if (!Allocate(sizeof(data), pos))
+ return false;
+ return Write(*pos, data);
+}
+
+template <class DataType>
+bool PostmortemMinidumpWriter::AppendVec(const std::vector<DataType>& data,
+ FilePosition* pos) {
+ static_assert(std::is_trivially_copyable<DataType>::value,
+ "restricted to trivially copyable");
+ DCHECK(!data.empty());
+ DCHECK(pos);
+
+ size_t size_bytes = sizeof(DataType) * data.size();
+ if (!Allocate(size_bytes, pos))
+ return false;
+ return WriteBytes(*pos, size_bytes,
+ reinterpret_cast<const char*>(&data.at(0)));
+}
+
+bool PostmortemMinidumpWriter::AppendUtf8String(base::StringPiece data,
+ FilePosition* pos) {
+ DCHECK(pos);
+ uint32_t string_size = data.size();
+ if (!Append(string_size, pos))
+ return false;
+
+ FilePosition unused_pos = 0U;
+ return AppendBytes(data, &unused_pos);
+}
+
+bool PostmortemMinidumpWriter::AppendBytes(base::StringPiece data,
+ FilePosition* pos) {
+ DCHECK(pos);
+ if (!Allocate(data.length(), pos))
+ return false;
+ return WriteBytes(*pos, data.length(), data.data());
+}
+
+void PostmortemMinidumpWriter::RegisterDirectoryEntry(uint32_t stream_type,
+ FilePosition pos,
+ uint32_t size) {
+ MINIDUMP_DIRECTORY entry = {0};
+ entry.StreamType = stream_type;
+ entry.Location.Rva = pos;
+ entry.Location.DataSize = size;
+ directory_.push_back(entry);
+}
+
+} // namespace
+
+MinidumpInfo::MinidumpInfo() {}
+
+MinidumpInfo::~MinidumpInfo() {}
+
+bool WritePostmortemDump(base::PlatformFile minidump_file,
+ const StabilityReport& report,
+ const MinidumpInfo& minidump_info) {
+ PostmortemMinidumpWriter writer;
+ return writer.WriteDump(minidump_file, report, minidump_info);
+}
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/postmortem_minidump_writer_win_unittest.cc b/chromium/components/browser_watcher/postmortem_minidump_writer_win_unittest.cc
new file mode 100644
index 00000000000..7acbfb1b3fc
--- /dev/null
+++ b/chromium/components/browser_watcher/postmortem_minidump_writer_win_unittest.cc
@@ -0,0 +1,160 @@
+// 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 "components/browser_watcher/postmortem_minidump_writer.h"
+
+#include <windows.h> // NOLINT
+#include <dbghelp.h>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/win/scoped_handle.h"
+#include "components/browser_watcher/stability_report.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h"
+#include "third_party/crashpad/crashpad/util/file/file_reader.h"
+#include "third_party/crashpad/crashpad/util/misc/uuid.h"
+
+namespace browser_watcher {
+
+using crashpad::UUID;
+
+const char kProductName[] = "some-product";
+const char kExpectedProductName[] = "some-product_Postmortem";
+const char kVersion[] = "51.0.2704.106";
+const char kChannel[] = "some-channel";
+const char kPlatform[] = "some-platform";
+
+class WritePostmortemDumpTest : public testing::Test {
+ public:
+ void SetUp() override {
+ testing::Test::SetUp();
+
+ expected_client_id_ = UUID(UUID::InitializeWithNewTag{});
+ expected_report_id_ = UUID(UUID::InitializeWithNewTag{});
+
+ // Create a stability report.
+ // TODO(manzagop): flesh out the report once proto is more detailed.
+ ProcessState* process_state = expected_report_.add_process_states();
+ CodeModule* module = process_state->add_modules();
+ module->set_base_address(1024);
+ module->set_code_file("some_code_file.dll");
+
+ // Write the minidump.
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ minidump_path_ = temp_dir_.GetPath().AppendASCII("minidump.dmp");
+ }
+
+ bool WriteDump() {
+ base::win::ScopedHandle file_handle(::CreateFile(
+ minidump_path_.value().c_str(), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL, nullptr));
+ if (!file_handle.IsValid())
+ return false;
+
+ MinidumpInfo minidump_info;
+ minidump_info.client_id = expected_client_id_;
+ minidump_info.report_id = expected_report_id_;
+ minidump_info.product_name = kProductName;
+ minidump_info.version_number = kVersion;
+ minidump_info.channel_name = kChannel;
+ minidump_info.platform = kPlatform;
+
+ return WritePostmortemDump(file_handle.Get(), expected_report_,
+ minidump_info);
+ }
+
+ const base::FilePath& minidump_path() { return minidump_path_; }
+ const UUID& expected_client_id() { return expected_client_id_; }
+ const UUID& expected_report_id() { return expected_report_id_; }
+ const StabilityReport& expected_report() { return expected_report_; }
+
+ private:
+ base::ScopedTempDir temp_dir_;
+ base::FilePath minidump_path_;
+ UUID expected_client_id_;
+ UUID expected_report_id_;
+ StabilityReport expected_report_;
+};
+
+TEST_F(WritePostmortemDumpTest, ValidateStabilityReportTest) {
+ ASSERT_TRUE(WriteDump());
+
+ // Read back the minidump to extract the proto.
+ // TODO(manzagop): rely on crashpad for reading the proto once crashpad
+ // supports it (https://crashpad.chromium.org/bug/10).
+ base::ScopedFILE minidump_file;
+ minidump_file.reset(base::OpenFile(minidump_path(), "rb"));
+ ASSERT_TRUE(minidump_file.get());
+
+ MINIDUMP_HEADER header = {};
+ ASSERT_EQ(1U, fread(&header, sizeof(header), 1, minidump_file.get()));
+ ASSERT_EQ(static_cast<ULONG32>(MINIDUMP_SIGNATURE), header.Signature);
+ ASSERT_EQ(2U, header.NumberOfStreams);
+ RVA directory_rva = header.StreamDirectoryRva;
+
+ MINIDUMP_DIRECTORY directory = {};
+ ASSERT_EQ(0, fseek(minidump_file.get(), directory_rva, SEEK_SET));
+ ASSERT_EQ(1U, fread(&directory, sizeof(directory), 1, minidump_file.get()));
+ ASSERT_EQ(0x4B6B0002U, directory.StreamType);
+ RVA report_rva = directory.Location.Rva;
+ ULONG32 report_size_bytes = directory.Location.DataSize;
+
+ std::string recovered_serialized_report;
+ recovered_serialized_report.resize(report_size_bytes);
+ ASSERT_EQ(0, fseek(minidump_file.get(), report_rva, SEEK_SET));
+ ASSERT_EQ(report_size_bytes, fread(&recovered_serialized_report.at(0), 1,
+ report_size_bytes, minidump_file.get()));
+
+ // Validate the recovered report.
+ std::string expected_serialized_report;
+ expected_report().SerializeToString(&expected_serialized_report);
+ ASSERT_EQ(expected_serialized_report, recovered_serialized_report);
+
+ StabilityReport recovered_report;
+ ASSERT_TRUE(recovered_report.ParseFromString(recovered_serialized_report));
+}
+
+TEST_F(WritePostmortemDumpTest, CrashpadCanReadTest) {
+ ASSERT_TRUE(WriteDump());
+
+ // Validate crashpad can read the produced minidump.
+ crashpad::FileReader minidump_file_reader;
+ ASSERT_TRUE(minidump_file_reader.Open(minidump_path()));
+
+ crashpad::ProcessSnapshotMinidump minidump_process_snapshot;
+ ASSERT_TRUE(minidump_process_snapshot.Initialize(&minidump_file_reader));
+
+ // Validate the crashpadinfo.
+ UUID client_id;
+ minidump_process_snapshot.ClientID(&client_id);
+ ASSERT_EQ(expected_client_id(), client_id);
+
+ UUID report_id;
+ minidump_process_snapshot.ReportID(&report_id);
+ ASSERT_EQ(expected_report_id(), report_id);
+
+ std::map<std::string, std::string> parameters =
+ minidump_process_snapshot.AnnotationsSimpleMap();
+ auto it = parameters.find("prod");
+ ASSERT_NE(parameters.end(), it);
+ ASSERT_EQ(kExpectedProductName, it->second);
+
+ it = parameters.find("ver");
+ ASSERT_NE(parameters.end(), it);
+ ASSERT_EQ(kVersion, it->second);
+
+ it = parameters.find("channel");
+ ASSERT_NE(parameters.end(), it);
+ ASSERT_EQ(kChannel, it->second);
+
+ it = parameters.find("plat");
+ ASSERT_NE(parameters.end(), it);
+ ASSERT_EQ(kPlatform, it->second);
+}
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/postmortem_report_collector.cc b/chromium/components/browser_watcher/postmortem_report_collector.cc
new file mode 100644
index 00000000000..ffca970ba40
--- /dev/null
+++ b/chromium/components/browser_watcher/postmortem_report_collector.cc
@@ -0,0 +1,217 @@
+// 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 "components/browser_watcher/postmortem_report_collector.h"
+
+#include <utility>
+
+#include "base/debug/activity_analyzer.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/browser_watcher/postmortem_minidump_writer.h"
+#include "third_party/crashpad/crashpad/client/settings.h"
+#include "third_party/crashpad/crashpad/util/misc/uuid.h"
+
+using base::FilePath;
+
+namespace browser_watcher {
+
+using base::debug::GlobalActivityAnalyzer;
+using base::debug::ThreadActivityAnalyzer;
+using crashpad::CrashReportDatabase;
+
+PostmortemReportCollector::PostmortemReportCollector(
+ const std::string& product_name,
+ const std::string& version_number,
+ const std::string& channel_name)
+ : product_name_(product_name),
+ version_number_(version_number),
+ channel_name_(channel_name) {}
+
+int PostmortemReportCollector::CollectAndSubmitForUpload(
+ const base::FilePath& debug_info_dir,
+ const base::FilePath::StringType& debug_file_pattern,
+ const std::set<base::FilePath>& excluded_debug_files,
+ crashpad::CrashReportDatabase* report_database) {
+ DCHECK_NE(true, debug_info_dir.empty());
+ DCHECK_NE(true, debug_file_pattern.empty());
+ DCHECK_NE(nullptr, report_database);
+
+ // Collect the list of files to harvest.
+ std::vector<FilePath> debug_files = GetDebugStateFilePaths(
+ debug_info_dir, debug_file_pattern, excluded_debug_files);
+
+ // Determine the crashpad client id.
+ crashpad::UUID client_id;
+ crashpad::Settings* settings = report_database->GetSettings();
+ if (settings) {
+ // If GetSettings() or GetClientID() fails client_id will be left at its
+ // default value, all zeroes, which is appropriate.
+ settings->GetClientID(&client_id);
+ }
+
+ // Process each stability file.
+ int success_cnt = 0;
+ for (const FilePath& file : debug_files) {
+ CollectionStatus status =
+ CollectAndSubmit(client_id, file, report_database);
+ // TODO(manzagop): consider making this a stability metric.
+ UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.Status", status,
+ COLLECTION_STATUS_MAX);
+ if (status == SUCCESS)
+ ++success_cnt;
+ }
+
+ return success_cnt;
+}
+
+std::vector<FilePath> PostmortemReportCollector::GetDebugStateFilePaths(
+ const base::FilePath& debug_info_dir,
+ const base::FilePath::StringType& debug_file_pattern,
+ const std::set<FilePath>& excluded_debug_files) {
+ DCHECK_NE(true, debug_info_dir.empty());
+ DCHECK_NE(true, debug_file_pattern.empty());
+
+ std::vector<FilePath> paths;
+ base::FileEnumerator enumerator(debug_info_dir, false /* recursive */,
+ base::FileEnumerator::FILES,
+ debug_file_pattern);
+ FilePath path;
+ for (path = enumerator.Next(); !path.empty(); path = enumerator.Next()) {
+ if (excluded_debug_files.find(path) == excluded_debug_files.end())
+ paths.push_back(path);
+ }
+ return paths;
+}
+
+PostmortemReportCollector::CollectionStatus
+PostmortemReportCollector::CollectAndSubmit(
+ const crashpad::UUID& client_id,
+ const FilePath& file,
+ crashpad::CrashReportDatabase* report_database) {
+ DCHECK_NE(nullptr, report_database);
+
+ // Note: the code below involves two notions of report: chrome internal state
+ // reports and the crashpad reports they get wrapped into.
+
+ // Collect the data from the debug file to a proto.
+ std::unique_ptr<StabilityReport> report_proto;
+ CollectionStatus status = Collect(file, &report_proto);
+ if (status != SUCCESS) {
+ // The file was empty, or there was an error collecting the data. Detailed
+ // logging happens within the Collect function.
+ if (!base::DeleteFile(file, false))
+ LOG(ERROR) << "Failed to delete " << file.value();
+ return status;
+ }
+ DCHECK_NE(nullptr, report_proto.get());
+
+ // Prepare a crashpad report.
+ CrashReportDatabase::NewReport* new_report = nullptr;
+ CrashReportDatabase::OperationStatus database_status =
+ report_database->PrepareNewCrashReport(&new_report);
+ if (database_status != CrashReportDatabase::kNoError) {
+ LOG(ERROR) << "PrepareNewCrashReport failed";
+ return PREPARE_NEW_CRASH_REPORT_FAILED;
+ }
+ CrashReportDatabase::CallErrorWritingCrashReport
+ call_error_writing_crash_report(report_database, new_report);
+
+ // Write the report to a minidump.
+ if (!WriteReportToMinidump(*report_proto, client_id, new_report->uuid,
+ reinterpret_cast<FILE*>(new_report->handle))) {
+ return WRITE_TO_MINIDUMP_FAILED;
+ }
+
+ // If the file cannot be deleted, do not report its contents. Note this can
+ // lead to under reporting and retries. However, under reporting is
+ // preferable to the over reporting that would happen with a file that
+ // cannot be deleted.
+ // TODO(manzagop): metrics for the number of non-deletable files.
+ if (!base::DeleteFile(file, false)) {
+ LOG(ERROR) << "Failed to delete " << file.value();
+ return DEBUG_FILE_DELETION_FAILED;
+ }
+
+ // Finalize the report wrt the report database. Note that this doesn't trigger
+ // an immediate upload, but Crashpad will eventually upload the report (as of
+ // writing, the delay is on the order of up to 15 minutes).
+ call_error_writing_crash_report.Disarm();
+ crashpad::UUID unused_report_id;
+ database_status = report_database->FinishedWritingCrashReport(
+ new_report, &unused_report_id);
+ if (database_status != CrashReportDatabase::kNoError) {
+ LOG(ERROR) << "FinishedWritingCrashReport failed";
+ return FINISHED_WRITING_CRASH_REPORT_FAILED;
+ }
+
+ return SUCCESS;
+}
+
+PostmortemReportCollector::CollectionStatus PostmortemReportCollector::Collect(
+ const base::FilePath& debug_state_file,
+ std::unique_ptr<StabilityReport>* report) {
+ DCHECK_NE(nullptr, report);
+ report->reset();
+
+ // Create a global analyzer.
+ std::unique_ptr<GlobalActivityAnalyzer> global_analyzer =
+ GlobalActivityAnalyzer::CreateWithFile(debug_state_file);
+ if (!global_analyzer)
+ return ANALYZER_CREATION_FAILED;
+
+ // Early exit if there is no data.
+ ThreadActivityAnalyzer* thread_analyzer = global_analyzer->GetFirstAnalyzer();
+ if (!thread_analyzer) {
+ // No data. This case happens in the case of a clean exit.
+ return DEBUG_FILE_NO_DATA;
+ }
+
+ // Iterate through the thread analyzers, fleshing out the report.
+ report->reset(new StabilityReport());
+ ProcessState* process_state = (*report)->add_process_states();
+
+ for (; thread_analyzer != nullptr;
+ thread_analyzer = global_analyzer->GetNextAnalyzer()) {
+ // Only valid analyzers are expected per contract of GetFirstAnalyzer /
+ // GetNextAnalyzer.
+ DCHECK(thread_analyzer->IsValid());
+
+ ThreadState* thread_state = process_state->add_threads();
+ thread_state->set_thread_name(thread_analyzer->GetThreadName());
+ // TODO(manzagop): flesh this out.
+ }
+
+ return SUCCESS;
+}
+
+bool PostmortemReportCollector::WriteReportToMinidump(
+ const StabilityReport& report,
+ const crashpad::UUID& client_id,
+ const crashpad::UUID& report_id,
+ base::PlatformFile minidump_file) {
+ MinidumpInfo minidump_info;
+ minidump_info.client_id = client_id;
+ minidump_info.report_id = report_id;
+ // TODO(manzagop): replace this information, i.e. the reporter's attributes,
+ // by that of the reportee. Doing so requires adding this information to the
+ // stability report. In the meantime, there is a tolerable information
+ // mismatch after upgrades.
+ minidump_info.product_name = product_name();
+ minidump_info.version_number = version_number();
+ minidump_info.channel_name = channel_name();
+#if defined(ARCH_CPU_X86)
+ minidump_info.platform = std::string("Win32");
+#elif defined(ARCH_CPU_X86_64)
+ minidump_info.platform = std::string("Win64");
+#endif
+
+ return WritePostmortemDump(minidump_file, report, minidump_info);
+}
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/postmortem_report_collector.h b/chromium/components/browser_watcher/postmortem_report_collector.h
new file mode 100644
index 00000000000..dffdc6e3214
--- /dev/null
+++ b/chromium/components/browser_watcher/postmortem_report_collector.h
@@ -0,0 +1,105 @@
+// 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.
+//
+// Following an unclean shutdown, a stability report can be collected and
+// submitted for upload to a reporter.
+
+#ifndef COMPONENTS_BROWSER_WATCHER_POSTMORTEM_REPORT_COLLECTOR_H_
+#define COMPONENTS_BROWSER_WATCHER_POSTMORTEM_REPORT_COLLECTOR_H_
+
+#include <stdio.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/browser_watcher/stability_report.pb.h"
+#include "third_party/crashpad/crashpad/client/crash_report_database.h"
+
+namespace browser_watcher {
+
+// Collects unclean shutdown information and creates Crashpad minidumps.
+// TODO(manzagop): throttling, graceful handling of accumulating data.
+// TODO(manzagop): UMA metrics and some error logging.
+class PostmortemReportCollector {
+ public:
+ // DO NOT CHANGE VALUES. This is logged persistently in a histogram.
+ enum CollectionStatus {
+ NONE = 0,
+ SUCCESS = 1, // Successfully registered a report with Crashpad.
+ ANALYZER_CREATION_FAILED = 2,
+ DEBUG_FILE_NO_DATA = 3,
+ PREPARE_NEW_CRASH_REPORT_FAILED = 4,
+ WRITE_TO_MINIDUMP_FAILED = 5,
+ DEBUG_FILE_DELETION_FAILED = 6,
+ FINISHED_WRITING_CRASH_REPORT_FAILED = 7,
+ COLLECTION_STATUS_MAX = 8
+ };
+
+ PostmortemReportCollector(const std::string& product_name,
+ const std::string& version_number,
+ const std::string& channel_name);
+ virtual ~PostmortemReportCollector() = default;
+
+ // Collects postmortem stability reports from files found in |debug_info_dir|,
+ // relying on |debug_file_pattern| and |excluded_debug_files|. Reports are
+ // then wrapped in Crashpad reports, manufactured via |report_database|.
+ // Returns the number crash reports successfully registered with the reporter.
+ // TODO(manzagop): consider mechanisms for partial collection if this is to be
+ // used on a critical path.
+ int CollectAndSubmitForUpload(
+ const base::FilePath& debug_info_dir,
+ const base::FilePath::StringType& debug_file_pattern,
+ const std::set<base::FilePath>& excluded_debug_files,
+ crashpad::CrashReportDatabase* report_database);
+
+ const std::string& product_name() const { return product_name_; }
+ const std::string& version_number() const { return version_number_; }
+ const std::string& channel_name() const { return channel_name_; }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(PostmortemReportCollectorTest,
+ GetDebugStateFilePaths);
+ FRIEND_TEST_ALL_PREFIXES(PostmortemReportCollectorTest, CollectEmptyFile);
+ FRIEND_TEST_ALL_PREFIXES(PostmortemReportCollectorTest, CollectRandomFile);
+ FRIEND_TEST_ALL_PREFIXES(PostmortemReportCollectorCollectionTest,
+ CollectSuccess);
+
+ // Virtual for unittesting.
+ virtual std::vector<base::FilePath> GetDebugStateFilePaths(
+ const base::FilePath& debug_info_dir,
+ const base::FilePath::StringType& debug_file_pattern,
+ const std::set<base::FilePath>& excluded_debug_files);
+
+ CollectionStatus CollectAndSubmit(
+ const crashpad::UUID& client_id,
+ const base::FilePath& file,
+ crashpad::CrashReportDatabase* report_database);
+
+ // Virtual for unittesting.
+ // TODO(manzagop): move this for reuse in live scenario.
+ virtual CollectionStatus Collect(const base::FilePath& debug_state_file,
+ std::unique_ptr<StabilityReport>* report);
+
+ virtual bool WriteReportToMinidump(const StabilityReport& report,
+ const crashpad::UUID& client_id,
+ const crashpad::UUID& report_id,
+ base::PlatformFile minidump_file);
+
+ std::string product_name_;
+ std::string version_number_;
+ std::string channel_name_;
+
+ DISALLOW_COPY_AND_ASSIGN(PostmortemReportCollector);
+};
+
+} // namespace browser_watcher
+
+#endif // COMPONENTS_BROWSER_WATCHER_POSTMORTEM_REPORT_COLLECTOR_H_
diff --git a/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc b/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc
new file mode 100644
index 00000000000..6049189f3d1
--- /dev/null
+++ b/chromium/components/browser_watcher/postmortem_report_collector_unittest.cc
@@ -0,0 +1,429 @@
+// 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 "components/browser_watcher/postmortem_report_collector.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/debug/activity_tracker.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/files/scoped_file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/persistent_memory_allocator.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/crashpad/crashpad/client/crash_report_database.h"
+
+namespace browser_watcher {
+
+using base::debug::Activity;
+using base::debug::ActivityData;
+using base::debug::GlobalActivityTracker;
+using base::debug::ThreadActivityTracker;
+using base::File;
+using base::FilePersistentMemoryAllocator;
+using base::MemoryMappedFile;
+using base::PersistentMemoryAllocator;
+using base::WrapUnique;
+using crashpad::CrashReportDatabase;
+using crashpad::Settings;
+using crashpad::UUID;
+using testing::_;
+using testing::Return;
+using testing::SetArgPointee;
+
+namespace {
+
+const char kProductName[] = "TestProduct";
+const char kVersionNumber[] = "TestVersionNumber";
+const char kChannelName[] = "TestChannel";
+
+// Exposes a public constructor in order to create a dummy database.
+class MockCrashReportDatabase : public CrashReportDatabase {
+ public:
+ MockCrashReportDatabase() {}
+ MOCK_METHOD0(GetSettings, Settings*());
+ MOCK_METHOD1(PrepareNewCrashReport,
+ CrashReportDatabase::CrashReportDatabase::OperationStatus(
+ NewReport** report));
+ MOCK_METHOD2(FinishedWritingCrashReport,
+ CrashReportDatabase::CrashReportDatabase::OperationStatus(
+ CrashReportDatabase::NewReport* report,
+ crashpad::UUID* uuid));
+ MOCK_METHOD1(ErrorWritingCrashReport,
+ CrashReportDatabase::CrashReportDatabase::OperationStatus(
+ NewReport* report));
+ MOCK_METHOD2(LookUpCrashReport,
+ CrashReportDatabase::CrashReportDatabase::OperationStatus(
+ const UUID& uuid,
+ Report* report));
+ MOCK_METHOD1(
+ GetPendingReports,
+ CrashReportDatabase::OperationStatus(std::vector<Report>* reports));
+ MOCK_METHOD1(
+ GetCompletedReports,
+ CrashReportDatabase::OperationStatus(std::vector<Report>* reports));
+ MOCK_METHOD2(GetReportForUploading,
+ CrashReportDatabase::OperationStatus(const UUID& uuid,
+ const Report** report));
+ MOCK_METHOD3(RecordUploadAttempt,
+ CrashReportDatabase::OperationStatus(const Report* report,
+ bool successful,
+ const std::string& id));
+ MOCK_METHOD2(SkipReportUpload,
+ CrashReportDatabase::OperationStatus(
+ const UUID& uuid,
+ crashpad::Metrics::CrashSkippedReason reason));
+ MOCK_METHOD1(DeleteReport,
+ CrashReportDatabase::OperationStatus(const UUID& uuid));
+ MOCK_METHOD1(RequestUpload,
+ CrashReportDatabase::OperationStatus(const UUID& uuid));
+};
+
+// Used for testing CollectAndSubmitForUpload.
+class MockPostmortemReportCollector : public PostmortemReportCollector {
+ public:
+ MockPostmortemReportCollector()
+ : PostmortemReportCollector(kProductName, kVersionNumber, kChannelName) {}
+
+ // A function that returns a unique_ptr cannot be mocked, so mock a function
+ // that returns a raw pointer instead.
+ CollectionStatus Collect(const base::FilePath& debug_state_file,
+ std::unique_ptr<StabilityReport>* report) override {
+ DCHECK_NE(nullptr, report);
+ report->reset(CollectRaw(debug_state_file));
+ return SUCCESS;
+ }
+
+ MOCK_METHOD3(GetDebugStateFilePaths,
+ std::vector<base::FilePath>(
+ const base::FilePath& debug_info_dir,
+ const base::FilePath::StringType& debug_file_pattern,
+ const std::set<base::FilePath>&));
+ MOCK_METHOD1(CollectRaw, StabilityReport*(const base::FilePath&));
+ MOCK_METHOD4(WriteReportToMinidump,
+ bool(const StabilityReport& report,
+ const crashpad::UUID& client_id,
+ const crashpad::UUID& report_id,
+ base::PlatformFile minidump_file));
+};
+
+// Checks if two proto messages are the same based on their serializations. Note
+// this only works if serialization is deterministic, which is not guaranteed.
+// In practice, serialization is deterministic (even for protocol buffers with
+// maps) and such matchers are common in the Chromium code base. Also note that
+// in the context of this test, false positive matches are the problem and these
+// are not possible (otherwise serialization would be ambiguous). False
+// negatives would lead to test failure and developer action. Alternatives are:
+// 1) a generic matcher (likely not possible without reflections, missing from
+// lite runtime), 2) a specialized matcher or 3) implementing deterministic
+// serialization.
+// TODO(manzagop): switch a matcher with guarantees.
+MATCHER_P(EqualsProto, message, "") {
+ std::string expected_serialized;
+ std::string actual_serialized;
+ message.SerializeToString(&expected_serialized);
+ arg.SerializeToString(&actual_serialized);
+ return expected_serialized == actual_serialized;
+}
+
+} // namespace
+
+class PostmortemReportCollectorCollectAndSubmitTest : public testing::Test {
+ public:
+ void SetUp() override {
+ testing::Test::SetUp();
+ // Create a dummy debug file.
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ debug_file_ = temp_dir_.GetPath().AppendASCII("foo-1.pma");
+ {
+ base::ScopedFILE file(base::OpenFile(debug_file_, "w"));
+ ASSERT_NE(file.get(), nullptr);
+ }
+ ASSERT_TRUE(base::PathExists(debug_file_));
+
+ // Expect collection of the debug file paths.
+ debug_file_pattern_ = FILE_PATH_LITERAL("foo-*.pma");
+ std::vector<base::FilePath> debug_files{debug_file_};
+ EXPECT_CALL(collector_,
+ GetDebugStateFilePaths(debug_file_.DirName(),
+ debug_file_pattern_, no_excluded_files_))
+ .Times(1)
+ .WillOnce(Return(debug_files));
+
+ EXPECT_CALL(database_, GetSettings()).Times(1).WillOnce(Return(nullptr));
+
+ // Expect collection to a proto of a single debug file.
+ // Note: caller takes ownership.
+ StabilityReport* stability_report = new StabilityReport();
+ EXPECT_CALL(collector_, CollectRaw(debug_file_))
+ .Times(1)
+ .WillOnce(Return(stability_report));
+
+ // Expect the call to write the proto to a minidump. This involves
+ // requesting a report from the crashpad database, writing the report, then
+ // finalizing it with the database.
+ base::FilePath minidump_path = temp_dir_.GetPath().AppendASCII("foo-1.dmp");
+ base::File minidump_file(
+ minidump_path, base::File::FLAG_CREATE | base::File::File::FLAG_WRITE);
+ crashpad_report_ = {minidump_file.GetPlatformFile(),
+ crashpad::UUID(UUID::InitializeWithNewTag{}),
+ minidump_path};
+ EXPECT_CALL(database_, PrepareNewCrashReport(_))
+ .Times(1)
+ .WillOnce(DoAll(SetArgPointee<0>(&crashpad_report_),
+ Return(CrashReportDatabase::kNoError)));
+
+ EXPECT_CALL(collector_,
+ WriteReportToMinidump(EqualsProto(*stability_report), _, _,
+ minidump_file.GetPlatformFile()))
+ .Times(1)
+ .WillOnce(Return(true));
+ }
+
+ protected:
+ base::ScopedTempDir temp_dir_;
+ base::FilePath debug_file_;
+ MockCrashReportDatabase database_;
+ MockPostmortemReportCollector collector_;
+ base::FilePath::StringType debug_file_pattern_;
+ std::set<base::FilePath> no_excluded_files_;
+ CrashReportDatabase::NewReport crashpad_report_;
+};
+
+TEST_F(PostmortemReportCollectorCollectAndSubmitTest,
+ CollectAndSubmitForUpload) {
+ EXPECT_CALL(database_, FinishedWritingCrashReport(&crashpad_report_, _))
+ .Times(1)
+ .WillOnce(Return(CrashReportDatabase::kNoError));
+
+ // Run the test.
+ int success_cnt = collector_.CollectAndSubmitForUpload(
+ debug_file_.DirName(), debug_file_pattern_, no_excluded_files_,
+ &database_);
+ ASSERT_EQ(1, success_cnt);
+ ASSERT_FALSE(base::PathExists(debug_file_));
+}
+
+TEST_F(PostmortemReportCollectorCollectAndSubmitTest,
+ CollectAndSubmitForUploadStuckFile) {
+ // Open the stability debug file to prevent its deletion.
+ base::ScopedFILE file(base::OpenFile(debug_file_, "w"));
+ ASSERT_NE(file.get(), nullptr);
+
+ // Expect Crashpad is notified of an error writing the crash report.
+ EXPECT_CALL(database_, ErrorWritingCrashReport(&crashpad_report_))
+ .Times(1)
+ .WillOnce(Return(CrashReportDatabase::kNoError));
+
+ // Run the test.
+ int success_cnt = collector_.CollectAndSubmitForUpload(
+ debug_file_.DirName(), debug_file_pattern_, no_excluded_files_,
+ &database_);
+ ASSERT_EQ(0, success_cnt);
+ ASSERT_TRUE(base::PathExists(debug_file_));
+}
+
+TEST(PostmortemReportCollectorTest, GetDebugStateFilePaths) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ // Create files.
+ std::vector<base::FilePath> expected_paths;
+ std::set<base::FilePath> excluded_paths;
+ {
+ // Matches the pattern.
+ base::FilePath path = temp_dir.GetPath().AppendASCII("foo1.pma");
+ base::ScopedFILE file(base::OpenFile(path, "w"));
+ ASSERT_NE(file.get(), nullptr);
+ expected_paths.push_back(path);
+
+ // Matches the pattern, but is excluded.
+ path = temp_dir.GetPath().AppendASCII("foo2.pma");
+ file.reset(base::OpenFile(path, "w"));
+ ASSERT_NE(file.get(), nullptr);
+ ASSERT_TRUE(excluded_paths.insert(path).second);
+
+ // Matches the pattern.
+ path = temp_dir.GetPath().AppendASCII("foo3.pma");
+ file.reset(base::OpenFile(path, "w"));
+ ASSERT_NE(file.get(), nullptr);
+ expected_paths.push_back(path);
+
+ // Does not match the pattern.
+ path = temp_dir.GetPath().AppendASCII("bar.baz");
+ file.reset(base::OpenFile(path, "w"));
+ ASSERT_NE(file.get(), nullptr);
+ }
+
+ PostmortemReportCollector collector(kProductName, kVersionNumber,
+ kChannelName);
+ EXPECT_THAT(
+ collector.GetDebugStateFilePaths(
+ temp_dir.GetPath(), FILE_PATH_LITERAL("foo*.pma"), excluded_paths),
+ testing::UnorderedElementsAreArray(expected_paths));
+}
+
+TEST(PostmortemReportCollectorTest, CollectEmptyFile) {
+ // Create an empty file.
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath file_path = temp_dir.GetPath().AppendASCII("empty.pma");
+ {
+ base::ScopedFILE file(base::OpenFile(file_path, "w"));
+ ASSERT_NE(file.get(), nullptr);
+ }
+ ASSERT_TRUE(PathExists(file_path));
+
+ // Validate collection: an empty file cannot suppport an analyzer.
+ PostmortemReportCollector collector(kProductName, kVersionNumber,
+ kChannelName);
+ std::unique_ptr<StabilityReport> report;
+ ASSERT_EQ(PostmortemReportCollector::ANALYZER_CREATION_FAILED,
+ collector.Collect(file_path, &report));
+}
+
+TEST(PostmortemReportCollectorTest, CollectRandomFile) {
+ // Create a file with content we don't expect to be valid for a debug file.
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath file_path =
+ temp_dir.GetPath().AppendASCII("invalid_content.pma");
+ {
+ base::ScopedFILE file(base::OpenFile(file_path, "w"));
+ ASSERT_NE(file.get(), nullptr);
+ // Assuming this size is greater than the minimum size of a debug file.
+ std::vector<uint8_t> data(1024);
+ for (size_t i = 0; i < data.size(); ++i)
+ data[i] = i % UINT8_MAX;
+ ASSERT_EQ(data.size(),
+ fwrite(&data.at(0), sizeof(uint8_t), data.size(), file.get()));
+ }
+ ASSERT_TRUE(PathExists(file_path));
+
+ // Validate collection: random content appears as though there is not
+ // stability data.
+ PostmortemReportCollector collector(kProductName, kVersionNumber,
+ kChannelName);
+ std::unique_ptr<StabilityReport> report;
+ ASSERT_EQ(PostmortemReportCollector::DEBUG_FILE_NO_DATA,
+ collector.Collect(file_path, &report));
+}
+
+namespace {
+
+// Parameters for the activity tracking.
+const size_t kFileSize = 2 * 1024;
+const int kStackDepth = 4;
+const uint64_t kAllocatorId = 0;
+const char kAllocatorName[] = "PostmortemReportCollectorCollectionTest";
+
+} // namespace
+
+class PostmortemReportCollectorCollectionTest : public testing::Test {
+ public:
+ // Create a proper debug file.
+ void SetUp() override {
+ testing::Test::SetUp();
+
+ // Create a file backed allocator.
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug_file.pma");
+ std::unique_ptr<PersistentMemoryAllocator> allocator = CreateAllocator();
+ ASSERT_NE(nullptr, allocator);
+
+ size_t tracker_mem_size =
+ ThreadActivityTracker::SizeForStackDepth(kStackDepth);
+ ASSERT_GT(kFileSize, tracker_mem_size);
+
+ // Create some debug data using trackers.
+ std::unique_ptr<ThreadActivityTracker> tracker =
+ CreateTracker(allocator.get(), tracker_mem_size);
+ ASSERT_NE(nullptr, tracker);
+ ASSERT_TRUE(tracker->IsValid());
+
+ const void* dummy_task_origin = reinterpret_cast<void*>(0xCAFE);
+ const int dummy_task_sequence_num = 42;
+ tracker->PushActivity(dummy_task_origin, Activity::ACT_TASK_RUN,
+ ActivityData::ForTask(dummy_task_sequence_num));
+
+ // TODO(manzagop): flesh out the data (more trackers and content).
+ }
+
+ std::unique_ptr<PersistentMemoryAllocator> CreateAllocator() {
+ // Create the memory mapped file.
+ std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
+ bool success = mmfile->Initialize(
+ File(debug_file_path_, File::FLAG_CREATE | File::FLAG_READ |
+ File::FLAG_WRITE | File::FLAG_SHARE_DELETE),
+ {0, static_cast<int64_t>(kFileSize)},
+ MemoryMappedFile::READ_WRITE_EXTEND);
+ if (!success || !mmfile->IsValid())
+ return nullptr;
+
+ // Create a persistent memory allocator.
+ if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true))
+ return nullptr;
+ return WrapUnique(new FilePersistentMemoryAllocator(
+ std::move(mmfile), kFileSize, kAllocatorId, kAllocatorName, false));
+ }
+
+ std::unique_ptr<ThreadActivityTracker> CreateTracker(
+ PersistentMemoryAllocator* allocator,
+ size_t tracker_mem_size) {
+ // Allocate a block of memory for the tracker to use.
+ PersistentMemoryAllocator::Reference mem_reference = allocator->Allocate(
+ tracker_mem_size, GlobalActivityTracker::kTypeIdActivityTracker);
+ if (mem_reference == 0U)
+ return nullptr;
+
+ // Get the memory's base address.
+ void* mem_base = allocator->GetAsObject<char>(
+ mem_reference, GlobalActivityTracker::kTypeIdActivityTracker);
+ if (mem_base == nullptr)
+ return nullptr;
+
+ // Make the allocation iterable so it can be found by other processes.
+ allocator->MakeIterable(mem_reference);
+
+ return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size));
+ }
+
+ const base::FilePath& debug_file_path() const { return debug_file_path_; }
+
+ private:
+ base::ScopedTempDir temp_dir_;
+ base::FilePath debug_file_path_;
+};
+
+TEST_F(PostmortemReportCollectorCollectionTest, CollectSuccess) {
+ // Validate collection returns the expected report.
+ PostmortemReportCollector collector(kProductName, kVersionNumber,
+ kChannelName);
+ std::unique_ptr<StabilityReport> report;
+ ASSERT_EQ(PostmortemReportCollector::SUCCESS,
+ collector.Collect(debug_file_path(), &report));
+ ASSERT_NE(nullptr, report);
+
+ // Build the expected report.
+ StabilityReport expected_report;
+ ProcessState* process_state = expected_report.add_process_states();
+ ThreadState* thread_state = process_state->add_threads();
+ thread_state->set_thread_name(base::PlatformThread::GetName());
+
+ ASSERT_EQ(expected_report.SerializeAsString(), report->SerializeAsString());
+}
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/stability_debugging_win.cc b/chromium/components/browser_watcher/stability_debugging_win.cc
new file mode 100644
index 00000000000..804bf88d5da
--- /dev/null
+++ b/chromium/components/browser_watcher/stability_debugging_win.cc
@@ -0,0 +1,63 @@
+// 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 "components/browser_watcher/stability_debugging_win.h"
+
+#include <string>
+
+#include "base/metrics/persistent_memory_allocator.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+
+namespace browser_watcher {
+
+namespace {
+
+bool GetCreationTime(const base::Process& process, base::Time* time) {
+ DCHECK(time);
+
+ FILETIME creation_time = {};
+ FILETIME ignore1 = {};
+ FILETIME ignore2 = {};
+ FILETIME ignore3 = {};
+ if (!::GetProcessTimes(process.Handle(), &creation_time, &ignore1, &ignore2,
+ &ignore3)) {
+ return false;
+ }
+ *time = base::Time::FromFileTime(creation_time);
+ return true;
+}
+
+} // namespace
+
+base::FilePath GetStabilityDir(const base::FilePath& user_data_dir) {
+ return user_data_dir.AppendASCII("Stability");
+}
+
+bool GetStabilityFileForProcess(const base::Process& process,
+ const base::FilePath& user_data_dir,
+ base::FilePath* file_path) {
+ DCHECK(file_path);
+ base::FilePath stability_dir = GetStabilityDir(user_data_dir);
+
+ // Build the name using the pid and creation time. On windows, this is unique
+ // even after the process exits.
+ base::Time creation_time;
+ if (!GetCreationTime(process, &creation_time))
+ return false;
+
+ std::string file_name =
+ base::StringPrintf("%u-%llu", process.Pid(), creation_time.ToJavaTime());
+ *file_path = stability_dir.AppendASCII(file_name).AddExtension(
+ base::PersistentMemoryAllocator::kFileExtension);
+ return true;
+}
+
+base::FilePath::StringType GetStabilityFilePattern() {
+ return base::FilePath::StringType(FILE_PATH_LITERAL("*-*")) +
+ base::PersistentMemoryAllocator::kFileExtension;
+}
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/stability_debugging_win.h b/chromium/components/browser_watcher/stability_debugging_win.h
new file mode 100644
index 00000000000..08edd48b386
--- /dev/null
+++ b/chromium/components/browser_watcher/stability_debugging_win.h
@@ -0,0 +1,28 @@
+// 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 COMPONENTS_BROWSER_WATCHER_STABILITY_DEBUGGING_WIN_H_
+#define COMPONENTS_BROWSER_WATCHER_STABILITY_DEBUGGING_WIN_H_
+
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/process/process.h"
+
+namespace browser_watcher {
+
+// Returns the the stability debugging directory.
+base::FilePath GetStabilityDir(const base::FilePath& user_data_dir);
+
+// On success, |path| contains the path to the stability debugging information
+// file for |process|.
+bool GetStabilityFileForProcess(const base::Process& process,
+ const base::FilePath& user_data_dir,
+ base::FilePath* path);
+
+// Returns a pattern that matches file names returned by GetFileForProcess.
+base::FilePath::StringType GetStabilityFilePattern();
+
+} // namespace browser_watcher
+
+#endif // COMPONENTS_BROWSER_WATCHER_STABILITY_DEBUGGING_WIN_H_
diff --git a/chromium/components/browser_watcher/stability_debugging_win_unittest.cc b/chromium/components/browser_watcher/stability_debugging_win_unittest.cc
new file mode 100644
index 00000000000..d1920109a06
--- /dev/null
+++ b/chromium/components/browser_watcher/stability_debugging_win_unittest.cc
@@ -0,0 +1,85 @@
+// 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 "components/browser_watcher/stability_debugging_win.h"
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/process/process.h"
+#include "base/test/multiprocess_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace browser_watcher {
+
+class StabilityDebuggingWinMultiProcTest : public base::MultiProcessTest {};
+
+MULTIPROCESS_TEST_MAIN(DummyProcess) {
+ return 0;
+}
+
+TEST_F(StabilityDebuggingWinMultiProcTest, GetStabilityFileForProcessTest) {
+ const base::FilePath empty_path;
+
+ // Get the path for the current process.
+ base::FilePath stability_path;
+ ASSERT_TRUE(GetStabilityFileForProcess(base::Process::Current(), empty_path,
+ &stability_path));
+
+ // Ensure requesting a second time produces the same.
+ base::FilePath stability_path_two;
+ ASSERT_TRUE(GetStabilityFileForProcess(base::Process::Current(), empty_path,
+ &stability_path_two));
+ EXPECT_EQ(stability_path, stability_path_two);
+
+ // Ensure a different process has a different stability path.
+ base::FilePath stability_path_other;
+ ASSERT_TRUE(GetStabilityFileForProcess(SpawnChild("DummyProcess"), empty_path,
+ &stability_path_other));
+ EXPECT_NE(stability_path, stability_path_other);
+}
+
+TEST(StabilityDebuggingWinTest,
+ GetStabilityFilePatternMatchesGetStabilityFileForProcessResult) {
+ // GetStabilityFileForProcess file names must match GetStabilityFilePattern
+ // according to
+ // FileEnumerator's algorithm. We test this by writing out some files and
+ // validating what is matched.
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath user_data_dir = temp_dir.path();
+
+ // Create the stability directory.
+ base::FilePath stability_dir = GetStabilityDir(user_data_dir);
+ ASSERT_TRUE(base::CreateDirectory(stability_dir));
+
+ // Write a stability file.
+ base::FilePath stability_file;
+ ASSERT_TRUE(GetStabilityFileForProcess(base::Process::Current(),
+ user_data_dir, &stability_file));
+ {
+ base::ScopedFILE file(base::OpenFile(stability_file, "w"));
+ ASSERT_TRUE(file.get());
+ }
+
+ // Write a file that shouldn't match.
+ base::FilePath non_matching_file =
+ stability_dir.AppendASCII("non_matching.foo");
+ {
+ base::ScopedFILE file(base::OpenFile(non_matching_file, "w"));
+ ASSERT_TRUE(file.get());
+ }
+
+ // Validate only the stability file matches.
+ base::FileEnumerator enumerator(stability_dir, false /* recursive */,
+ base::FileEnumerator::FILES,
+ GetStabilityFilePattern());
+ ASSERT_EQ(stability_file, enumerator.Next());
+ ASSERT_TRUE(enumerator.Next().empty());
+}
+
+} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/stability_report.proto b/chromium/components/browser_watcher/stability_report.proto
new file mode 100644
index 00000000000..0943be3db4e
--- /dev/null
+++ b/chromium/components/browser_watcher/stability_report.proto
@@ -0,0 +1,78 @@
+// 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package browser_watcher;
+
+// The state of the system on which Chrome is running (shutting down, battery
+// level, load, etc.).
+message SystemState {
+ // TODO(manzagop): flesh out.
+}
+
+message CodeModule {
+ // The base address of this code module as it was loaded by the process.
+ optional int64 base_address = 1;
+
+ // The size of the code module.
+ optional int64 size = 2;
+
+ // The path or file name that the code module was loaded from.
+ optional string code_file = 3;
+
+ // An identifying string used to discriminate between multiple versions and
+ // builds of the same code module. This may contain a uuid, timestamp,
+ // version number, or any combination of this or other information, in an
+ // implementation-defined format.
+ optional string code_identifier = 4;
+
+ // The filename containing debugging information associated with the code
+ // module. If debugging information is stored in a file separate from the
+ // code module itself (as is the case when .pdb or .dSYM files are used),
+ // this will be different from code_file. If debugging information is
+ // stored in the code module itself (possibly prior to stripping), this
+ // will be the same as code_file.
+ optional string debug_file = 5;
+
+ // An identifying string similar to code_identifier, but identifies a
+ // specific version and build of the associated debug file. This may be
+ // the same as code_identifier when the debug_file and code_file are
+ // identical or when the same identifier is used to identify distinct
+ // debug and code files.
+ optional string debug_identifier = 6;
+
+ // A human-readable representation of the code module's version.
+ optional string version = 7;
+}
+
+// The state of a thread.
+message ThreadState {
+ optional string thread_name = 1;
+ // TODO(manzagop): flesh out.
+}
+
+// The state of a process.
+message ProcessState {
+ // Note: likely only a subset of modules of interest (e.g. Chromium's own
+ // modules).
+ repeated CodeModule modules = 1;
+ repeated ThreadState threads = 2;
+ // TODO(manzagop): add experiment state.
+}
+
+// A stability report contains information pertaining to the execution of a
+// single logical instance of a "chrome browser". It is comprised of information
+// about the system state and about the chrome browser's processes.
+message StabilityReport {
+ optional SystemState system_state = 1;
+ // TODO(manzagop): revisit whether a single repeated field should contain all
+ // processes, or whether it's preferable to have separate fields per type.
+ // TODO(manzagop): add information about the type of process, pid, process
+ // times (e.g. start time), hierarchical relationships (e.g. parent pid),
+ // command line, etc.
+ repeated ProcessState process_states = 2;
+}
diff --git a/chromium/components/browser_watcher/watcher_metrics_provider_win.cc b/chromium/components/browser_watcher/watcher_metrics_provider_win.cc
index efe177bb998..5ed372d07e2 100644
--- a/chromium/components/browser_watcher/watcher_metrics_provider_win.cc
+++ b/chromium/components/browser_watcher/watcher_metrics_provider_win.cc
@@ -7,15 +7,25 @@
#include <stddef.h>
#include <limits>
+#include <memory>
+#include <set>
#include <vector>
#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/process/process.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
+#include "components/browser_watcher/features.h"
+#include "components/browser_watcher/postmortem_report_collector.h"
+#include "components/browser_watcher/stability_debugging_win.h"
+#include "third_party/crashpad/crashpad/client/crash_report_database.h"
namespace browser_watcher {
@@ -185,6 +195,19 @@ void DeleteExitCodeRegistryKey(const base::string16& registry_path) {
DVLOG(1) << "Failed to delete exit code key " << registry_path;
}
+enum CollectionInitializationStatus {
+ INIT_SUCCESS = 0,
+ UNKNOWN_DIR = 1,
+ GET_STABILITY_FILE_PATH_FAILED = 2,
+ CRASHPAD_DATABASE_INIT_FAILED = 3,
+ INIT_STATUS_MAX = 4
+};
+
+void LogCollectionInitStatus(CollectionInitializationStatus status) {
+ UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.InitStatus", status,
+ INIT_STATUS_MAX);
+}
+
} // namespace
const char WatcherMetricsProviderWin::kBrowserExitCodeHistogramName[] =
@@ -192,12 +215,19 @@ const char WatcherMetricsProviderWin::kBrowserExitCodeHistogramName[] =
WatcherMetricsProviderWin::WatcherMetricsProviderWin(
const base::string16& registry_path,
- base::TaskRunner* cleanup_io_task_runner)
+ const base::FilePath& user_data_dir,
+ const base::FilePath& crash_dir,
+ const GetExecutableDetailsCallback& exe_details_cb,
+ base::TaskRunner* io_task_runner)
: recording_enabled_(false),
cleanup_scheduled_(false),
registry_path_(registry_path),
- cleanup_io_task_runner_(cleanup_io_task_runner) {
- DCHECK(cleanup_io_task_runner_);
+ user_data_dir_(user_data_dir),
+ crash_dir_(crash_dir),
+ exe_details_cb_(exe_details_cb),
+ io_task_runner_(io_task_runner),
+ weak_ptr_factory_(this) {
+ DCHECK(io_task_runner_);
}
WatcherMetricsProviderWin::~WatcherMetricsProviderWin() {
@@ -212,7 +242,7 @@ void WatcherMetricsProviderWin::OnRecordingDisabled() {
// When metrics reporting is disabled, the providers get an
// OnRecordingDisabled notification at startup. Use that first notification
// to issue the cleanup task.
- cleanup_io_task_runner_->PostTask(
+ io_task_runner_->PostTask(
FROM_HERE, base::Bind(&DeleteExitCodeRegistryKey, registry_path_));
cleanup_scheduled_ = true;
@@ -231,4 +261,67 @@ void WatcherMetricsProviderWin::ProvideStabilityMetrics(
DeleteExitFunnels(registry_path_);
}
+void WatcherMetricsProviderWin::CollectPostmortemReports(
+ const base::Closure& done_callback) {
+ io_task_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(
+ &WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool,
+ weak_ptr_factory_.GetWeakPtr()),
+ done_callback);
+}
+
+void WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool() {
+ // Note: the feature controls both instrumentation and collection.
+ bool is_stability_debugging_on =
+ base::FeatureList::IsEnabled(browser_watcher::kStabilityDebuggingFeature);
+ if (!is_stability_debugging_on) {
+ // TODO(manzagop): delete possible leftover data.
+ return;
+ }
+
+ SCOPED_UMA_HISTOGRAM_TIMER("ActivityTracker.Collect.TotalTime");
+
+ if (user_data_dir_.empty() || crash_dir_.empty()) {
+ LOG(ERROR) << "User data directory or crash directory is unknown.";
+ LogCollectionInitStatus(UNKNOWN_DIR);
+ return;
+ }
+
+ // Determine the stability directory and the stability file for the current
+ // process.
+ base::FilePath stability_dir = GetStabilityDir(user_data_dir_);
+ base::FilePath current_stability_file;
+ if (!GetStabilityFileForProcess(base::Process::Current(), user_data_dir_,
+ &current_stability_file)) {
+ LOG(ERROR) << "Failed to get the current stability file.";
+ LogCollectionInitStatus(GET_STABILITY_FILE_PATH_FAILED);
+ return;
+ }
+ const std::set<base::FilePath>& excluded_debug_files = {
+ current_stability_file};
+
+ // Create a database. Note: Chrome already has a g_database in crashpad.cc but
+ // it has internal linkage. Create a new one.
+ std::unique_ptr<crashpad::CrashReportDatabase> crashpad_database =
+ crashpad::CrashReportDatabase::InitializeWithoutCreating(crash_dir_);
+ if (!crashpad_database) {
+ LOG(ERROR) << "Failed to initialize a CrashPad database.";
+ LogCollectionInitStatus(CRASHPAD_DATABASE_INIT_FAILED);
+ return;
+ }
+
+ LogCollectionInitStatus(INIT_SUCCESS);
+
+ // TODO(manzagop): fix incorrect version attribution on update.
+ base::string16 product_name, version_number, channel_name;
+ exe_details_cb_.Run(&product_name, &version_number, &channel_name);
+ PostmortemReportCollector collector(base::UTF16ToUTF8(product_name),
+ base::UTF16ToUTF8(version_number),
+ base::UTF16ToUTF8(channel_name));
+ collector.CollectAndSubmitForUpload(stability_dir, GetStabilityFilePattern(),
+ excluded_debug_files,
+ crashpad_database.get());
+}
+
} // namespace browser_watcher
diff --git a/chromium/components/browser_watcher/watcher_metrics_provider_win.h b/chromium/components/browser_watcher/watcher_metrics_provider_win.h
index 48ec7faebba..65c5307d301 100644
--- a/chromium/components/browser_watcher/watcher_metrics_provider_win.h
+++ b/chromium/components/browser_watcher/watcher_metrics_provider_win.h
@@ -5,9 +5,13 @@
#ifndef COMPONENTS_BROWSER_WATCHER_WATCHER_METRICS_PROVIDER_WIN_H_
#define COMPONENTS_BROWSER_WATCHER_WATCHER_METRICS_PROVIDER_WIN_H_
+#include "base/callback.h"
+#include "base/files/file_path.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/task_runner.h"
+#include "base/threading/thread_checker.h"
#include "components/metrics/metrics_provider.h"
namespace browser_watcher {
@@ -16,25 +20,55 @@ namespace browser_watcher {
// process exit codes.
class WatcherMetricsProviderWin : public metrics::MetricsProvider {
public:
+ // A callback that provides product name, version number and channel name.
+ using GetExecutableDetailsCallback =
+ base::Callback<void(base::string16*, base::string16*, base::string16*)>;
+
static const char kBrowserExitCodeHistogramName[];
- // Initializes the reporter. |cleanup_io_task_runner| is used to clear
- // leftover data in registry if metrics reporting is disabled.
+ // Initializes the reporter. |io_task_runner| is used for collecting
+ // postmortem reports and clearing leftover data in registry if metrics
+ // reporting is disabled.
WatcherMetricsProviderWin(const base::string16& registry_path,
- base::TaskRunner* cleanup_io_task_runner);
+ const base::FilePath& user_data_dir,
+ const base::FilePath& crash_dir,
+ const GetExecutableDetailsCallback& exe_details_cb,
+ base::TaskRunner* io_task_runner);
~WatcherMetricsProviderWin() override;
// metrics::MetricsProvider implementation.
void OnRecordingEnabled() override;
void OnRecordingDisabled() override;
+ // Note: this function collects metrics, some of which are related to the
+ // previous run's version and some to the current version. Doing the correct
+ // attribution on upgrade is difficult, and currently ignored. Metrics
+ // clearing is one mechanism to avoid misattribution, but is not used in this
+ // case (ClearSavedStabilityMetrics is not overridden) as version
+ // misattribution is preferred to data loss. Metrics will likely be attributed
+ // to the previous run's version, unless no initial log is sent, in which case
+ // they should be attributed to the current version (though they may actually
+ // be attributed to still another following version).
+ // TODO(manzagop): proper metric version attribution on upgrade.
void ProvideStabilityMetrics(
metrics::SystemProfileProto* system_profile_proto) override;
+ // Collects postmortem reports asynchronously and calls |done_callback| when
+ // done.
+ void CollectPostmortemReports(const base::Closure& done_callback);
+
private:
+ // TODO(manzagop): avoid collecting reports for clean exits from the fast exit
+ // path.
+ void CollectPostmortemReportsOnBlockingPool();
+
bool recording_enabled_;
bool cleanup_scheduled_;
const base::string16 registry_path_;
- scoped_refptr<base::TaskRunner> cleanup_io_task_runner_;
+ const base::FilePath user_data_dir_;
+ const base::FilePath crash_dir_;
+ GetExecutableDetailsCallback exe_details_cb_;
+ scoped_refptr<base::TaskRunner> io_task_runner_;
+ base::WeakPtrFactory<WatcherMetricsProviderWin> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(WatcherMetricsProviderWin);
};
diff --git a/chromium/components/browser_watcher/watcher_metrics_provider_win_unittest.cc b/chromium/components/browser_watcher/watcher_metrics_provider_win_unittest.cc
index 456a48778e4..5f2554679c6 100644
--- a/chromium/components/browser_watcher/watcher_metrics_provider_win_unittest.cc
+++ b/chromium/components/browser_watcher/watcher_metrics_provider_win_unittest.cc
@@ -23,6 +23,9 @@ namespace browser_watcher {
namespace {
+using GetExecutableDetailsCallback =
+ WatcherMetricsProviderWin::GetExecutableDetailsCallback;
+
const wchar_t kRegistryPath[] = L"Software\\WatcherMetricsProviderWinTest";
class WatcherMetricsProviderWinTest : public testing::Test {
@@ -87,7 +90,9 @@ TEST_F(WatcherMetricsProviderWinTest, RecordsStabilityHistogram) {
// Record a single failure.
AddProcessExitCode(false, 100);
- WatcherMetricsProviderWin provider(kRegistryPath, test_task_runner_.get());
+ WatcherMetricsProviderWin provider(
+ kRegistryPath, base::FilePath(), base::FilePath(),
+ GetExecutableDetailsCallback(), test_task_runner_.get());
provider.ProvideStabilityMetrics(NULL);
histogram_tester_.ExpectBucketCount(
@@ -109,7 +114,9 @@ TEST_F(WatcherMetricsProviderWinTest, DoesNotReportOwnProcessId) {
// Record own process as STILL_ACTIVE.
AddProcessExitCode(true, STILL_ACTIVE);
- WatcherMetricsProviderWin provider(kRegistryPath, test_task_runner_.get());
+ WatcherMetricsProviderWin provider(
+ kRegistryPath, base::FilePath(), base::FilePath(),
+ GetExecutableDetailsCallback(), test_task_runner_.get());
provider.ProvideStabilityMetrics(NULL);
histogram_tester_.ExpectUniqueSample(
@@ -129,7 +136,9 @@ TEST_F(WatcherMetricsProviderWinTest, DeletesRecordedExitFunnelEvents) {
base::win::RegistryKeyIterator it(HKEY_CURRENT_USER, kRegistryPath);
EXPECT_EQ(3u, it.SubkeyCount());
- WatcherMetricsProviderWin provider(kRegistryPath, test_task_runner_.get());
+ WatcherMetricsProviderWin provider(
+ kRegistryPath, base::FilePath(), base::FilePath(),
+ GetExecutableDetailsCallback(), test_task_runner_.get());
provider.ProvideStabilityMetrics(NULL);
// Make sure the exit funnel events are no longer recorded in histograms.
@@ -163,7 +172,9 @@ TEST_F(WatcherMetricsProviderWinTest, DeletesExitcodeKeyWhenNotReporting) {
AddExitFunnelEvent(102, L"Three", 990 * 1000);
// Make like the user is opted out of reporting.
- WatcherMetricsProviderWin provider(kRegistryPath, test_task_runner_.get());
+ WatcherMetricsProviderWin provider(
+ kRegistryPath, base::FilePath(), base::FilePath(),
+ GetExecutableDetailsCallback(), test_task_runner_.get());
provider.OnRecordingDisabled();
base::win::RegKey key;
@@ -194,7 +205,9 @@ TEST_F(WatcherMetricsProviderWinTest, DeletesOnly100FunnelsAtATime) {
{
// Make like the user is opted out of reporting.
- WatcherMetricsProviderWin provider(kRegistryPath, test_task_runner_.get());
+ WatcherMetricsProviderWin provider(
+ kRegistryPath, base::FilePath(), base::FilePath(),
+ GetExecutableDetailsCallback(), test_task_runner_.get());
provider.OnRecordingDisabled();
// Flush the task(s).
test_task_runner_->RunPendingTasks();
diff --git a/chromium/components/browser_watcher/window_hang_monitor_win.cc b/chromium/components/browser_watcher/window_hang_monitor_win.cc
index e3966f8c500..96cadb62ca3 100644
--- a/chromium/components/browser_watcher/window_hang_monitor_win.cc
+++ b/chromium/components/browser_watcher/window_hang_monitor_win.cc
@@ -9,9 +9,9 @@
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/win/message_window.h"
namespace browser_watcher {
@@ -75,7 +75,7 @@ WindowHangMonitor::~WindowHangMonitor() {
void WindowHangMonitor::Initialize(base::Process process) {
window_process_ = std::move(process);
- timer_.SetTaskRunner(base::MessageLoop::current()->task_runner());
+ timer_.SetTaskRunner(base::ThreadTaskRunnerHandle::Get());
ScheduleFindWindow();
}
diff --git a/chromium/components/browsing_data.gypi b/chromium/components/browsing_data.gypi
deleted file mode 100644
index aa71bfc2447..00000000000
--- a/chromium/components/browsing_data.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'browsing_data',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../net/net.gyp:net',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'browsing_data/conditional_cache_deletion_helper.cc',
- 'browsing_data/conditional_cache_deletion_helper.h',
- 'browsing_data/storage_partition_http_cache_data_remover.cc',
- 'browsing_data/storage_partition_http_cache_data_remover.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/browsing_data/BUILD.gn b/chromium/components/browsing_data/BUILD.gn
deleted file mode 100644
index 7b964e54960..00000000000
--- a/chromium/components/browsing_data/BUILD.gn
+++ /dev/null
@@ -1,21 +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.
-
-static_library("browsing_data") {
- output_name = "browsing_data"
- sources = [
- "conditional_cache_deletion_helper.cc",
- "conditional_cache_deletion_helper.h",
- "storage_partition_http_cache_data_remover.cc",
- "storage_partition_http_cache_data_remover.h",
- ]
-
- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
- deps = [
- "//base",
- "//content/public/browser",
- "//net",
- ]
-}
diff --git a/chromium/components/browsing_data/conditional_cache_deletion_helper.cc b/chromium/components/browsing_data/conditional_cache_deletion_helper.cc
deleted file mode 100644
index 3d1e0f9b865..00000000000
--- a/chromium/components/browsing_data/conditional_cache_deletion_helper.cc
+++ /dev/null
@@ -1,96 +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 "components/browsing_data/conditional_cache_deletion_helper.h"
-
-#include "base/callback.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace {
-
-bool EntryPredicateFromURLsAndTime(
- const base::Callback<bool(const GURL&)>& url_predicate,
- const base::Time& begin_time,
- const base::Time& end_time,
- const disk_cache::Entry* entry) {
- return (entry->GetLastModified() >= begin_time &&
- entry->GetLastModified() < end_time &&
- url_predicate.Run(GURL(entry->GetKey())));
-}
-
-} // namespace
-
-namespace browsing_data {
-
-ConditionalCacheDeletionHelper::ConditionalCacheDeletionHelper(
- disk_cache::Backend* cache,
- const base::Callback<bool(const disk_cache::Entry*)>& condition)
- : cache_(cache),
- condition_(condition),
- current_entry_(nullptr),
- previous_entry_(nullptr) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-}
-
-// static
-base::Callback<bool(const disk_cache::Entry*)>
-ConditionalCacheDeletionHelper::CreateURLAndTimeCondition(
- const base::Callback<bool(const GURL&)>& url_predicate,
- const base::Time& begin_time,
- const base::Time& end_time) {
- return base::Bind(
- &EntryPredicateFromURLsAndTime,
- url_predicate,
- begin_time.is_null() ? base::Time() : begin_time,
- end_time.is_null() ? base::Time::Max() : end_time);
-}
-
-int ConditionalCacheDeletionHelper::DeleteAndDestroySelfWhenFinished(
- const net::CompletionCallback& completion_callback) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
- completion_callback_ = completion_callback;
- iterator_ = cache_->CreateIterator();
-
- IterateOverEntries(net::OK);
- return net::ERR_IO_PENDING;
-}
-
-ConditionalCacheDeletionHelper::~ConditionalCacheDeletionHelper() {
-}
-
-void ConditionalCacheDeletionHelper::IterateOverEntries(int error) {
- while (error != net::ERR_IO_PENDING) {
- // If the entry obtained in the previous iteration matches the condition,
- // mark it for deletion. The iterator is already one step forward, so it
- // won't be invalidated. Always close the previous entry so it does not
- // leak.
- if (previous_entry_) {
- if (condition_.Run(previous_entry_))
- previous_entry_->Doom();
- previous_entry_->Close();
- }
-
- if (error == net::ERR_FAILED) {
- // The iteration finished successfuly or we can no longer iterate
- // (e.g. the cache was destroyed). We cannot distinguish between the two,
- // but we know that there is nothing more that we can do, so we return OK.
- base::MessageLoop::current()->task_runner()->PostTask(
- FROM_HERE, base::Bind(completion_callback_, net::OK));
- base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
- return;
- }
-
- previous_entry_ = current_entry_;
- error = iterator_->OpenNextEntry(
- &current_entry_,
- base::Bind(&ConditionalCacheDeletionHelper::IterateOverEntries,
- base::Unretained(this)));
- }
-}
-
-} // namespace browsing_data
diff --git a/chromium/components/browsing_data/conditional_cache_deletion_helper.h b/chromium/components/browsing_data/conditional_cache_deletion_helper.h
deleted file mode 100644
index b4376b3463e..00000000000
--- a/chromium/components/browsing_data/conditional_cache_deletion_helper.h
+++ /dev/null
@@ -1,73 +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 COMPONENTS_BROWSING_DATA_CONDITIONAL_CACHE_DELETION_HELPER_H_
-#define COMPONENTS_BROWSING_DATA_CONDITIONAL_CACHE_DELETION_HELPER_H_
-
-#include <memory>
-
-#include "base/callback_forward.h"
-#include "base/message_loop/message_loop.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_errors.h"
-#include "net/disk_cache/disk_cache.h"
-#include "url/gurl.h"
-
-namespace disk_cache {
-class Entry;
-}
-
-namespace browsing_data {
-
-// Helper to remove http cache data from a StoragePartition.
-class ConditionalCacheDeletionHelper {
- public:
- // Creates a helper to delete |cache| entries that match the |condition|.
- // Must be created on the IO thread!
- ConditionalCacheDeletionHelper(
- disk_cache::Backend* cache,
- const base::Callback<bool(const disk_cache::Entry*)>& condition);
-
- // A convenience method to create a condition matching cache entries whose
- // last modified time is between |begin_time| (inclusively), |end_time|
- // (exclusively) and whose URL is matched by the |url_predicate|. Note that
- // |begin_time| and |end_time| can be null to indicate unbounded time interval
- // in their respective direction.
- static base::Callback<bool(const disk_cache::Entry*)>
- CreateURLAndTimeCondition(
- const base::Callback<bool(const GURL&)>& url_predicate,
- const base::Time& begin_time,
- const base::Time& end_time);
-
- // Deletes the cache entries according to the specified condition. Destroys
- // this instance of ConditionalCacheDeletionHelper when finished.
- // Must be called on the IO thread!
- //
- // The return value is a net error code. If this method returns
- // ERR_IO_PENDING, the |completion_callback| will be invoked when the
- // operation completes.
- int DeleteAndDestroySelfWhenFinished(
- const net::CompletionCallback& completion_callback);
-
- private:
- friend class base::DeleteHelper<ConditionalCacheDeletionHelper>;
- ~ConditionalCacheDeletionHelper();
-
- void IterateOverEntries(int error);
-
- disk_cache::Backend* cache_;
- const base::Callback<bool(const disk_cache::Entry*)> condition_;
-
- net::CompletionCallback completion_callback_;
-
- std::unique_ptr<disk_cache::Backend::Iterator> iterator_;
- disk_cache::Entry* current_entry_;
- disk_cache::Entry* previous_entry_;
-
- DISALLOW_COPY_AND_ASSIGN(ConditionalCacheDeletionHelper);
-};
-
-} // namespace browsing_data
-
-#endif // COMPONENTS_BROWSING_DATA_CONDITIONAL_CACHE_DELETION_HELPER_H_
diff --git a/chromium/components/browsing_data/content/BUILD.gn b/chromium/components/browsing_data/content/BUILD.gn
new file mode 100644
index 00000000000..6229e1b59fb
--- /dev/null
+++ b/chromium/components/browsing_data/content/BUILD.gn
@@ -0,0 +1,20 @@
+# 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.
+
+static_library("content") {
+ sources = [
+ "conditional_cache_deletion_helper.cc",
+ "conditional_cache_deletion_helper.h",
+ "storage_partition_http_cache_data_remover.cc",
+ "storage_partition_http_cache_data_remover.h",
+ ]
+
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+ deps = [
+ "//base",
+ "//content/public/browser",
+ "//net",
+ ]
+}
diff --git a/chromium/components/browsing_data/DEPS b/chromium/components/browsing_data/content/DEPS
index 8c57389c3be..8c57389c3be 100644
--- a/chromium/components/browsing_data/DEPS
+++ b/chromium/components/browsing_data/content/DEPS
diff --git a/chromium/components/browsing_data/content/conditional_cache_deletion_helper.cc b/chromium/components/browsing_data/content/conditional_cache_deletion_helper.cc
new file mode 100644
index 00000000000..416ad0ce8e7
--- /dev/null
+++ b/chromium/components/browsing_data/content/conditional_cache_deletion_helper.cc
@@ -0,0 +1,96 @@
+// 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 "components/browsing_data/content/conditional_cache_deletion_helper.h"
+
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace {
+
+bool EntryPredicateFromURLsAndTime(
+ const base::Callback<bool(const GURL&)>& url_predicate,
+ const base::Time& begin_time,
+ const base::Time& end_time,
+ const disk_cache::Entry* entry) {
+ return (entry->GetLastModified() >= begin_time &&
+ entry->GetLastModified() < end_time &&
+ url_predicate.Run(GURL(entry->GetKey())));
+}
+
+} // namespace
+
+namespace browsing_data {
+
+ConditionalCacheDeletionHelper::ConditionalCacheDeletionHelper(
+ disk_cache::Backend* cache,
+ const base::Callback<bool(const disk_cache::Entry*)>& condition)
+ : cache_(cache),
+ condition_(condition),
+ current_entry_(nullptr),
+ previous_entry_(nullptr) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+}
+
+// static
+base::Callback<bool(const disk_cache::Entry*)>
+ConditionalCacheDeletionHelper::CreateURLAndTimeCondition(
+ const base::Callback<bool(const GURL&)>& url_predicate,
+ const base::Time& begin_time,
+ const base::Time& end_time) {
+ return base::Bind(
+ &EntryPredicateFromURLsAndTime,
+ url_predicate,
+ begin_time.is_null() ? base::Time() : begin_time,
+ end_time.is_null() ? base::Time::Max() : end_time);
+}
+
+int ConditionalCacheDeletionHelper::DeleteAndDestroySelfWhenFinished(
+ const net::CompletionCallback& completion_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ completion_callback_ = completion_callback;
+ iterator_ = cache_->CreateIterator();
+
+ IterateOverEntries(net::OK);
+ return net::ERR_IO_PENDING;
+}
+
+ConditionalCacheDeletionHelper::~ConditionalCacheDeletionHelper() {
+}
+
+void ConditionalCacheDeletionHelper::IterateOverEntries(int error) {
+ while (error != net::ERR_IO_PENDING) {
+ // If the entry obtained in the previous iteration matches the condition,
+ // mark it for deletion. The iterator is already one step forward, so it
+ // won't be invalidated. Always close the previous entry so it does not
+ // leak.
+ if (previous_entry_) {
+ if (condition_.Run(previous_entry_))
+ previous_entry_->Doom();
+ previous_entry_->Close();
+ }
+
+ if (error == net::ERR_FAILED) {
+ // The iteration finished successfuly or we can no longer iterate
+ // (e.g. the cache was destroyed). We cannot distinguish between the two,
+ // but we know that there is nothing more that we can do, so we return OK.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(completion_callback_, net::OK));
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+ return;
+ }
+
+ previous_entry_ = current_entry_;
+ error = iterator_->OpenNextEntry(
+ &current_entry_,
+ base::Bind(&ConditionalCacheDeletionHelper::IterateOverEntries,
+ base::Unretained(this)));
+ }
+}
+
+} // namespace browsing_data
diff --git a/chromium/components/browsing_data/content/conditional_cache_deletion_helper.h b/chromium/components/browsing_data/content/conditional_cache_deletion_helper.h
new file mode 100644
index 00000000000..c46d8bed820
--- /dev/null
+++ b/chromium/components/browsing_data/content/conditional_cache_deletion_helper.h
@@ -0,0 +1,73 @@
+// 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 COMPONENTS_BROWSING_DATA_CONTENT_CONDITIONAL_CACHE_DELETION_HELPER_H_
+#define COMPONENTS_BROWSING_DATA_CONTENT_CONDITIONAL_CACHE_DELETION_HELPER_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/message_loop/message_loop.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
+#include "net/disk_cache/disk_cache.h"
+#include "url/gurl.h"
+
+namespace disk_cache {
+class Entry;
+}
+
+namespace browsing_data {
+
+// Helper to remove http cache data from a StoragePartition.
+class ConditionalCacheDeletionHelper {
+ public:
+ // Creates a helper to delete |cache| entries that match the |condition|.
+ // Must be created on the IO thread!
+ ConditionalCacheDeletionHelper(
+ disk_cache::Backend* cache,
+ const base::Callback<bool(const disk_cache::Entry*)>& condition);
+
+ // A convenience method to create a condition matching cache entries whose
+ // last modified time is between |begin_time| (inclusively), |end_time|
+ // (exclusively) and whose URL is matched by the |url_predicate|. Note that
+ // |begin_time| and |end_time| can be null to indicate unbounded time interval
+ // in their respective direction.
+ static base::Callback<bool(const disk_cache::Entry*)>
+ CreateURLAndTimeCondition(
+ const base::Callback<bool(const GURL&)>& url_predicate,
+ const base::Time& begin_time,
+ const base::Time& end_time);
+
+ // Deletes the cache entries according to the specified condition. Destroys
+ // this instance of ConditionalCacheDeletionHelper when finished.
+ // Must be called on the IO thread!
+ //
+ // The return value is a net error code. If this method returns
+ // ERR_IO_PENDING, the |completion_callback| will be invoked when the
+ // operation completes.
+ int DeleteAndDestroySelfWhenFinished(
+ const net::CompletionCallback& completion_callback);
+
+ private:
+ friend class base::DeleteHelper<ConditionalCacheDeletionHelper>;
+ ~ConditionalCacheDeletionHelper();
+
+ void IterateOverEntries(int error);
+
+ disk_cache::Backend* cache_;
+ const base::Callback<bool(const disk_cache::Entry*)> condition_;
+
+ net::CompletionCallback completion_callback_;
+
+ std::unique_ptr<disk_cache::Backend::Iterator> iterator_;
+ disk_cache::Entry* current_entry_;
+ disk_cache::Entry* previous_entry_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConditionalCacheDeletionHelper);
+};
+
+} // namespace browsing_data
+
+#endif // COMPONENTS_BROWSING_DATA_CONTENT_CONDITIONAL_CACHE_DELETION_HELPER_H_
diff --git a/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.cc b/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.cc
new file mode 100644
index 00000000000..c0f20519de2
--- /dev/null
+++ b/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.cc
@@ -0,0 +1,310 @@
+// 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 "components/browsing_data/content/storage_partition_http_cache_data_remover.h"
+
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/browsing_data/content/conditional_cache_deletion_helper.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+#include "net/base/sdch_manager.h"
+#include "net/disk_cache/blockfile/backend_impl.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/disk_cache/memory/mem_backend_impl.h"
+#include "net/disk_cache/simple/simple_backend_impl.h"
+#include "net/http/http_cache.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
+
+using content::BrowserThread;
+
+namespace browsing_data {
+
+StoragePartitionHttpCacheDataRemover::StoragePartitionHttpCacheDataRemover(
+ base::Callback<bool(const GURL&)> url_predicate,
+ base::Time delete_begin,
+ base::Time delete_end,
+ net::URLRequestContextGetter* main_context_getter,
+ net::URLRequestContextGetter* media_context_getter)
+ : url_predicate_(url_predicate),
+ delete_begin_(delete_begin),
+ delete_end_(delete_end),
+ main_context_getter_(main_context_getter),
+ media_context_getter_(media_context_getter),
+ next_cache_state_(STATE_NONE),
+ cache_(nullptr),
+ calculation_result_(0) {
+}
+
+StoragePartitionHttpCacheDataRemover::~StoragePartitionHttpCacheDataRemover() {
+}
+
+// static.
+StoragePartitionHttpCacheDataRemover*
+StoragePartitionHttpCacheDataRemover::CreateForRange(
+ content::StoragePartition* storage_partition,
+ base::Time delete_begin,
+ base::Time delete_end) {
+ return new StoragePartitionHttpCacheDataRemover(
+ base::Callback<bool(const GURL&)>(), // Null callback.
+ delete_begin, delete_end,
+ storage_partition->GetURLRequestContext(),
+ storage_partition->GetMediaURLRequestContext());
+}
+
+// static.
+StoragePartitionHttpCacheDataRemover*
+StoragePartitionHttpCacheDataRemover::CreateForURLsAndRange(
+ content::StoragePartition* storage_partition,
+ const base::Callback<bool(const GURL&)>& url_predicate,
+ base::Time delete_begin,
+ base::Time delete_end) {
+ return new StoragePartitionHttpCacheDataRemover(
+ url_predicate, delete_begin, delete_end,
+ storage_partition->GetURLRequestContext(),
+ storage_partition->GetMediaURLRequestContext());
+}
+
+void StoragePartitionHttpCacheDataRemover::Remove(
+ const base::Closure& done_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!done_callback.is_null());
+ done_callback_ = done_callback;
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(
+ &StoragePartitionHttpCacheDataRemover::ClearHttpCacheOnIOThread,
+ base::Unretained(this)));
+}
+
+void StoragePartitionHttpCacheDataRemover::Count(
+ const net::Int64CompletionCallback& result_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!result_callback.is_null());
+ result_callback_ = result_callback;
+ calculation_result_ = 0;
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(
+ &StoragePartitionHttpCacheDataRemover::CountHttpCacheOnIOThread,
+ base::Unretained(this)));
+}
+
+void StoragePartitionHttpCacheDataRemover::ClearHttpCacheOnIOThread() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ next_cache_state_ = STATE_NONE;
+ DCHECK_EQ(STATE_NONE, next_cache_state_);
+ DCHECK(main_context_getter_.get());
+ DCHECK(media_context_getter_.get());
+
+ next_cache_state_ = STATE_CREATE_MAIN;
+ DoClearCache(net::OK);
+}
+
+void StoragePartitionHttpCacheDataRemover::CountHttpCacheOnIOThread() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ next_cache_state_ = STATE_NONE;
+ DCHECK_EQ(STATE_NONE, next_cache_state_);
+ DCHECK(main_context_getter_.get());
+ DCHECK(media_context_getter_.get());
+
+ next_cache_state_ = STATE_CREATE_MAIN;
+ DoCountCache(net::OK);
+}
+
+void StoragePartitionHttpCacheDataRemover::ClearedHttpCache() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ done_callback_.Run();
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+}
+
+void StoragePartitionHttpCacheDataRemover::CountedHttpCache() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ result_callback_.Run(calculation_result_);
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+}
+
+// The expected state sequence is STATE_NONE --> STATE_CREATE_MAIN -->
+// STATE_PROCESS_MAIN --> STATE_CREATE_MEDIA --> STATE_PROCESS_MEDIA -->
+// STATE_DONE, and any errors are ignored.
+void StoragePartitionHttpCacheDataRemover::DoClearCache(int rv) {
+ DCHECK_NE(STATE_NONE, next_cache_state_);
+
+ while (rv != net::ERR_IO_PENDING && next_cache_state_ != STATE_NONE) {
+ switch (next_cache_state_) {
+ case STATE_CREATE_MAIN:
+ case STATE_CREATE_MEDIA: {
+ // Get a pointer to the cache.
+ net::URLRequestContextGetter* getter =
+ (next_cache_state_ == STATE_CREATE_MAIN)
+ ? main_context_getter_.get()
+ : media_context_getter_.get();
+ net::HttpCache* http_cache = getter->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetCache();
+
+ next_cache_state_ = (next_cache_state_ == STATE_CREATE_MAIN)
+ ? STATE_PROCESS_MAIN
+ : STATE_PROCESS_MEDIA;
+
+ // Clear QUIC server information from memory and the disk cache.
+ http_cache->GetSession()
+ ->quic_stream_factory()
+ ->ClearCachedStatesInCryptoConfig(url_predicate_);
+
+ // Clear SDCH dictionary state.
+ net::SdchManager* sdch_manager =
+ getter->GetURLRequestContext()->sdch_manager();
+ // The test is probably overkill, since chrome should always have an
+ // SdchManager. But in general the URLRequestContext is *not*
+ // guaranteed to have an SdchManager, so checking is wise.
+ if (sdch_manager)
+ sdch_manager->ClearData();
+
+ rv = http_cache->GetBackend(
+ &cache_,
+ base::Bind(&StoragePartitionHttpCacheDataRemover::DoClearCache,
+ base::Unretained(this)));
+ break;
+ }
+ case STATE_PROCESS_MAIN:
+ case STATE_PROCESS_MEDIA: {
+ next_cache_state_ = (next_cache_state_ == STATE_PROCESS_MAIN)
+ ? STATE_CREATE_MEDIA
+ : STATE_DONE;
+
+ // |cache_| can be null if it cannot be initialized.
+ if (cache_) {
+ if (!url_predicate_.is_null()) {
+ rv = (new ConditionalCacheDeletionHelper(
+ cache_,
+ ConditionalCacheDeletionHelper::CreateURLAndTimeCondition(
+ url_predicate_,
+ delete_begin_,
+ delete_end_)))->DeleteAndDestroySelfWhenFinished(
+ base::Bind(
+ &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)));
+ } else {
+ rv = cache_->DoomEntriesBetween(
+ delete_begin_, delete_end_,
+ base::Bind(
+ &StoragePartitionHttpCacheDataRemover::DoClearCache,
+ base::Unretained(this)));
+ }
+ cache_ = NULL;
+ }
+ break;
+ }
+ case STATE_DONE: {
+ cache_ = NULL;
+ next_cache_state_ = STATE_NONE;
+
+ // Notify the UI thread that we are done.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&StoragePartitionHttpCacheDataRemover::ClearedHttpCache,
+ base::Unretained(this)));
+ return;
+ }
+ default: {
+ NOTREACHED() << "bad state";
+ next_cache_state_ = STATE_NONE; // Stop looping.
+ return;
+ }
+ }
+ }
+}
+
+// The expected state sequence is STATE_NONE --> STATE_CREATE_MAIN -->
+// STATE_PROCESS_MAIN --> STATE_CREATE_MEDIA --> STATE_PROCESS_MEDIA -->
+// STATE_DONE. On error, we jump directly to STATE_DONE.
+void StoragePartitionHttpCacheDataRemover::DoCountCache(int rv) {
+ DCHECK_NE(STATE_NONE, next_cache_state_);
+
+ while (rv != net::ERR_IO_PENDING && next_cache_state_ != STATE_NONE) {
+ // On error, finish and return the error code. A valid result value might
+ // be of two types - either net::OK from the CREATE states, or the result
+ // of calculation from the PROCESS states. Since net::OK == 0, it is valid
+ // to simply add the value to the final calculation result.
+ if (rv < 0) {
+ calculation_result_ = rv;
+ next_cache_state_ = STATE_DONE;
+ } else {
+ DCHECK_EQ(0, net::OK);
+ calculation_result_ += rv;
+ }
+
+ switch (next_cache_state_) {
+ case STATE_CREATE_MAIN:
+ case STATE_CREATE_MEDIA: {
+ // Get a pointer to the cache.
+ net::URLRequestContextGetter* getter =
+ (next_cache_state_ == STATE_CREATE_MAIN)
+ ? main_context_getter_.get()
+ : media_context_getter_.get();
+ net::HttpCache* http_cache = getter->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetCache();
+
+ next_cache_state_ = (next_cache_state_ == STATE_CREATE_MAIN)
+ ? STATE_PROCESS_MAIN
+ : STATE_PROCESS_MEDIA;
+
+ rv = http_cache->GetBackend(
+ &cache_,
+ base::Bind(&StoragePartitionHttpCacheDataRemover::DoCountCache,
+ base::Unretained(this)));
+ break;
+ }
+ case STATE_PROCESS_MAIN:
+ case STATE_PROCESS_MEDIA: {
+ next_cache_state_ = (next_cache_state_ == STATE_PROCESS_MAIN)
+ ? STATE_CREATE_MEDIA
+ : STATE_DONE;
+
+ // |cache_| can be null if it cannot be initialized.
+ if (cache_) {
+ if (delete_begin_.is_null() && delete_end_.is_max()) {
+ rv = cache_->CalculateSizeOfAllEntries(
+ base::Bind(
+ &StoragePartitionHttpCacheDataRemover::DoCountCache,
+ base::Unretained(this)));
+ } else {
+ // TODO(msramek): Implement this when we need it.
+ DoCountCache(net::ERR_NOT_IMPLEMENTED);
+ }
+ cache_ = NULL;
+ }
+ break;
+ }
+ case STATE_DONE: {
+ cache_ = NULL;
+ next_cache_state_ = STATE_NONE;
+
+ // Notify the UI thread that we are done.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&StoragePartitionHttpCacheDataRemover::CountedHttpCache,
+ base::Unretained(this)));
+ return;
+ }
+ default: {
+ NOTREACHED() << "bad state";
+ next_cache_state_ = STATE_NONE; // Stop looping.
+ return;
+ }
+ }
+ }
+}
+
+} // namespace browsing_data
diff --git a/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.h b/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.h
new file mode 100644
index 00000000000..ee4d581fbb7
--- /dev/null
+++ b/chromium/components/browsing_data/content/storage_partition_http_cache_data_remover.h
@@ -0,0 +1,116 @@
+// 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 COMPONENTS_BROWSING_DATA_CONTENT_STORAGE_PARTITION_HTTP_CACHE_DATA_REMOVER_H_
+#define COMPONENTS_BROWSING_DATA_CONTENT_STORAGE_PARTITION_HTTP_CACHE_DATA_REMOVER_H_
+
+#include <stdint.h>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "base/time/time.h"
+#include "net/base/completion_callback.h"
+#include "url/gurl.h"
+
+namespace content {
+class StoragePartition;
+}
+
+namespace disk_cache {
+class Backend;
+}
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace browsing_data {
+
+// Helper to remove http cache data from a StoragePartition.
+class StoragePartitionHttpCacheDataRemover {
+ public:
+ // Creates a StoragePartitionHttpCacheDataRemover that deletes cache entries
+ // in the time range between |delete_begin| (inclusively) and |delete_end|
+ // (exclusively).
+ static StoragePartitionHttpCacheDataRemover* CreateForRange(
+ content::StoragePartition* storage_partition,
+ base::Time delete_begin,
+ base::Time delete_end);
+
+ // Similar to CreateForRange(), but only deletes URLs that are matched by
+ // |url_predicate|. Note that the deletion with URL filtering is not built in
+ // to the cache interface and might be slower.
+ static StoragePartitionHttpCacheDataRemover* CreateForURLsAndRange(
+ content::StoragePartition* storage_partition,
+ const base::Callback<bool(const GURL&)>& url_predicate,
+ base::Time delete_begin,
+ base::Time delete_end);
+
+ // Calls |done_callback| upon completion and also destroys itself.
+ void Remove(const base::Closure& done_callback);
+
+ // Counts the total size of entries that would be removed by calling |Remove|.
+ // Reports it via |result_callback| and then destroys itself.
+ void Count(const net::Int64CompletionCallback& result_callback);
+
+ private:
+ enum CacheState {
+ STATE_NONE,
+ STATE_CREATE_MAIN,
+ STATE_CREATE_MEDIA,
+ STATE_PROCESS_MAIN,
+ STATE_PROCESS_MEDIA,
+ STATE_DONE
+ };
+
+ StoragePartitionHttpCacheDataRemover(
+ base::Callback<bool(const GURL&)> url_predicate,
+ base::Time delete_begin,
+ base::Time delete_end,
+ net::URLRequestContextGetter* main_context_getter,
+ net::URLRequestContextGetter* media_context_getter);
+
+ // StoragePartitionHttpCacheDataRemover deletes itself (using DeleteHelper)
+ // and is not supposed to be deleted by other objects so make destructor
+ // private and DeleteHelper a friend.
+ friend class base::DeleteHelper<StoragePartitionHttpCacheDataRemover>;
+
+ ~StoragePartitionHttpCacheDataRemover();
+
+ void ClearHttpCacheOnIOThread();
+ void CountHttpCacheOnIOThread();
+
+ void ClearedHttpCache();
+ void CountedHttpCache();
+
+ // Performs the actual work to delete or count the cache.
+ void DoClearCache(int rv);
+ void DoCountCache(int rv);
+
+ base::Callback<bool(const GURL&)> url_predicate_;
+ const base::Time delete_begin_;
+ const base::Time delete_end_;
+
+ const scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
+ const scoped_refptr<net::URLRequestContextGetter> media_context_getter_;
+
+ base::Closure done_callback_;
+ net::Int64CompletionCallback result_callback_;
+
+ // IO.
+ int next_cache_state_;
+ disk_cache::Backend* cache_;
+
+ // Stores the cache size computation result before it can be returned
+ // via a callback. This is either the sum of size of the the two cache
+ // backends, or an error code if the calculation failed.
+ int64_t calculation_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(StoragePartitionHttpCacheDataRemover);
+};
+
+} // namespace browsing_data
+
+#endif // COMPONENTS_BROWSING_DATA_CONTENT_STORAGE_PARTITION_HTTP_CACHE_DATA_REMOVER_H_
diff --git a/chromium/components/browsing_data/core/BUILD.gn b/chromium/components/browsing_data/core/BUILD.gn
new file mode 100644
index 00000000000..35fd34f4305
--- /dev/null
+++ b/chromium/components/browsing_data/core/BUILD.gn
@@ -0,0 +1,69 @@
+# 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.
+
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
+static_library("core") {
+ sources = [
+ "browsing_data_utils.cc",
+ "browsing_data_utils.h",
+ "counters/autofill_counter.cc",
+ "counters/autofill_counter.h",
+ "counters/browsing_data_counter.cc",
+ "counters/browsing_data_counter.h",
+ "counters/history_counter.cc",
+ "counters/history_counter.h",
+ "counters/passwords_counter.cc",
+ "counters/passwords_counter.h",
+ "history_notice_utils.cc",
+ "history_notice_utils.h",
+ "pref_names.cc",
+ "pref_names.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/autofill/core/browser",
+ "//components/history/core/browser",
+ "//components/password_manager/core/browser",
+ "//components/pref_registry:pref_registry",
+ "//components/prefs:prefs",
+ "//components/strings",
+ "//components/sync",
+ "//components/version_info",
+ "//components/webdata/common",
+ "//ui/base",
+ ]
+}
+
+if (is_android) {
+ java_cpp_enum("browsing_data_utils_java") {
+ sources = [
+ "browsing_data_utils.h",
+ ]
+ }
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "browsing_data_utils_unittest.cc",
+ "history_notice_utils_unittest.cc",
+ ]
+
+ deps = [
+ ":core",
+ "//base",
+ "//components/autofill/core/browser:browser",
+ "//components/history/core/test:test",
+ "//components/signin/core/browser:test_support",
+ "//components/sync:test_support_sync_driver",
+ "//components/sync/protocol:protocol",
+ "//components/version_info:version_info",
+ "//net",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/browsing_data/core/DEPS b/chromium/components/browsing_data/core/DEPS
new file mode 100644
index 00000000000..c559bcd5b7a
--- /dev/null
+++ b/chromium/components/browsing_data/core/DEPS
@@ -0,0 +1,18 @@
+include_rules = [
+ "+components/autofill/core/browser",
+ "+components/browser_sync",
+ "+components/history/core/browser",
+ "+components/history/core/test",
+ "+components/password_manager/core/browser",
+ "+components/pref_registry",
+ "+components/prefs",
+ "+components/signin",
+ "+components/sync/base",
+ "+components/sync/core",
+ "+components/sync/driver",
+ "+components/version_info",
+ "+components/webdata/common",
+ "+grit",
+ "+net",
+ "+ui/base",
+]
diff --git a/chromium/components/browsing_data/core/OWNERS b/chromium/components/browsing_data/core/OWNERS
new file mode 100644
index 00000000000..b4ccfe82ffe
--- /dev/null
+++ b/chromium/components/browsing_data/core/OWNERS
@@ -0,0 +1 @@
+per-file history_notice_utils*=msarda@chromium.org
diff --git a/chromium/components/browsing_data/core/browsing_data_utils.cc b/chromium/components/browsing_data/core/browsing_data_utils.cc
new file mode 100644
index 00000000000..b5b472bc19c
--- /dev/null
+++ b/chromium/components/browsing_data/core/browsing_data_utils.cc
@@ -0,0 +1,176 @@
+// 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 "components/browsing_data/core/browsing_data_utils.h"
+
+#include "components/browsing_data/core/counters/autofill_counter.h"
+#include "components/browsing_data/core/counters/history_counter.h"
+#include "components/browsing_data/core/counters/passwords_counter.h"
+#include "components/browsing_data/core/pref_names.h"
+#include "grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace browsing_data {
+
+base::Time CalculateBeginDeleteTime(TimePeriod time_period) {
+ base::TimeDelta diff;
+ base::Time delete_begin_time = base::Time::Now();
+ switch (time_period) {
+ case LAST_HOUR:
+ diff = base::TimeDelta::FromHours(1);
+ break;
+ case LAST_DAY:
+ diff = base::TimeDelta::FromHours(24);
+ break;
+ case LAST_WEEK:
+ diff = base::TimeDelta::FromHours(7 * 24);
+ break;
+ case FOUR_WEEKS:
+ diff = base::TimeDelta::FromHours(4 * 7 * 24);
+ break;
+ case ALL_TIME:
+ delete_begin_time = base::Time();
+ break;
+ }
+ return delete_begin_time - diff;
+}
+
+base::string16 GetCounterTextFromResult(
+ const browsing_data::BrowsingDataCounter::Result* result) {
+ base::string16 text;
+ std::string pref_name = result->source()->GetPrefName();
+
+ if (!result->Finished()) {
+ // The counter is still counting.
+ text = l10n_util::GetStringUTF16(IDS_CLEAR_BROWSING_DATA_CALCULATING);
+
+ } else if (pref_name == browsing_data::prefs::kDeletePasswords ||
+ pref_name == browsing_data::prefs::kDeleteDownloadHistory) {
+ // Counters with trivially formatted result: passwords and downloads.
+ browsing_data::BrowsingDataCounter::ResultInt count =
+ static_cast<const browsing_data::BrowsingDataCounter::FinishedResult*>(
+ result)
+ ->Value();
+ text = l10n_util::GetPluralStringFUTF16(
+ pref_name == browsing_data::prefs::kDeletePasswords
+ ? IDS_DEL_PASSWORDS_COUNTER
+ : IDS_DEL_DOWNLOADS_COUNTER,
+ count);
+ } else if (pref_name == browsing_data::prefs::kDeleteBrowsingHistory) {
+ // History counter.
+ const browsing_data::HistoryCounter::HistoryResult* history_result =
+ static_cast<const browsing_data::HistoryCounter::HistoryResult*>(
+ result);
+ browsing_data::BrowsingDataCounter::ResultInt local_item_count =
+ history_result->Value();
+ bool has_synced_visits = history_result->has_synced_visits();
+
+ text = has_synced_visits
+ ? l10n_util::GetPluralStringFUTF16(
+ IDS_DEL_BROWSING_HISTORY_COUNTER_SYNCED, local_item_count)
+ : l10n_util::GetPluralStringFUTF16(
+ IDS_DEL_BROWSING_HISTORY_COUNTER, local_item_count);
+
+ } else if (pref_name == browsing_data::prefs::kDeleteFormData) {
+ // Autofill counter.
+ const browsing_data::AutofillCounter::AutofillResult* autofill_result =
+ static_cast<const browsing_data::AutofillCounter::AutofillResult*>(
+ result);
+ browsing_data::AutofillCounter::ResultInt num_suggestions =
+ autofill_result->Value();
+ browsing_data::AutofillCounter::ResultInt num_credit_cards =
+ autofill_result->num_credit_cards();
+ browsing_data::AutofillCounter::ResultInt num_addresses =
+ autofill_result->num_addresses();
+
+ std::vector<base::string16> displayed_strings;
+
+ if (num_credit_cards) {
+ displayed_strings.push_back(l10n_util::GetPluralStringFUTF16(
+ IDS_DEL_AUTOFILL_COUNTER_CREDIT_CARDS, num_credit_cards));
+ }
+ if (num_addresses) {
+ displayed_strings.push_back(l10n_util::GetPluralStringFUTF16(
+ IDS_DEL_AUTOFILL_COUNTER_ADDRESSES, num_addresses));
+ }
+ if (num_suggestions) {
+ // We use a different wording for autocomplete suggestions based on the
+ // length of the entire string.
+ switch (displayed_strings.size()) {
+ case 0:
+ displayed_strings.push_back(l10n_util::GetPluralStringFUTF16(
+ IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS, num_suggestions));
+ break;
+ case 1:
+ displayed_strings.push_back(l10n_util::GetPluralStringFUTF16(
+ IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS_LONG, num_suggestions));
+ break;
+ case 2:
+ displayed_strings.push_back(l10n_util::GetPluralStringFUTF16(
+ IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS_SHORT, num_suggestions));
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ // Construct the resulting string from the sections in |displayed_strings|.
+ switch (displayed_strings.size()) {
+ case 0:
+ text = l10n_util::GetStringUTF16(IDS_DEL_AUTOFILL_COUNTER_EMPTY);
+ break;
+ case 1:
+ text = displayed_strings[0];
+ break;
+ case 2:
+ text = l10n_util::GetStringFUTF16(IDS_DEL_AUTOFILL_COUNTER_TWO_TYPES,
+ displayed_strings[0],
+ displayed_strings[1]);
+ break;
+ case 3:
+ text = l10n_util::GetStringFUTF16(
+ IDS_DEL_AUTOFILL_COUNTER_THREE_TYPES, displayed_strings[0],
+ displayed_strings[1], displayed_strings[2]);
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ return text;
+}
+
+bool GetDeletionPreferenceFromDataType(
+ BrowsingDataType data_type,
+ std::string* out_pref) {
+ switch (data_type) {
+ case HISTORY:
+ *out_pref = prefs::kDeleteBrowsingHistory;
+ return true;
+ case CACHE:
+ *out_pref = prefs::kDeleteCache;
+ return true;
+ case COOKIES:
+ *out_pref = prefs::kDeleteCookies;
+ return true;
+ case PASSWORDS:
+ *out_pref = prefs::kDeletePasswords;
+ return true;
+ case FORM_DATA:
+ *out_pref = prefs::kDeleteFormData;
+ return true;
+ case BOOKMARKS:
+ // Bookmarks are deleted on the Android side. No corresponding deletion
+ // preference.
+ return false;
+ case NUM_TYPES:
+ // This is not an actual type.
+ NOTREACHED();
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/browsing_data_utils.h b/chromium/components/browsing_data/core/browsing_data_utils.h
new file mode 100644
index 00000000000..368dc60c84b
--- /dev/null
+++ b/chromium/components/browsing_data/core/browsing_data_utils.h
@@ -0,0 +1,60 @@
+// 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 COMPONENTS_BROWSING_DATA_CORE_BROWSING_DATA_UTILS_H_
+#define COMPONENTS_BROWSING_DATA_CORE_BROWSING_DATA_UTILS_H_
+
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "components/browsing_data/core/counters/browsing_data_counter.h"
+
+namespace browsing_data {
+
+// Browsing data types as seen in the Android UI.
+// TODO(msramek): Reuse this enum as the canonical representation of the
+// user-facing browsing data types in the Desktop UI as well.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.browsing_data
+enum BrowsingDataType {
+ HISTORY,
+ CACHE,
+ COOKIES,
+ PASSWORDS,
+ FORM_DATA,
+ BOOKMARKS,
+ NUM_TYPES
+};
+
+// Time period ranges available when doing browsing data removals.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.browsing_data
+enum TimePeriod {
+ LAST_HOUR = 0,
+ LAST_DAY,
+ LAST_WEEK,
+ FOUR_WEEKS,
+ ALL_TIME,
+ TIME_PERIOD_LAST = ALL_TIME
+};
+
+// Calculate the begin time for the deletion range specified by |time_period|.
+base::Time CalculateBeginDeleteTime(TimePeriod time_period);
+
+// Constructs the text to be displayed by a counter from the given |result|.
+// Currently this can only be used for counters for which the Result is defined
+// in components/browsing_data/core/counters.
+base::string16 GetCounterTextFromResult(
+ const browsing_data::BrowsingDataCounter::Result* result);
+
+// Copies the name of the deletion preference corresponding to the given
+// |data_type| to |out_pref|. Returns false if no such preference exists.
+bool GetDeletionPreferenceFromDataType(
+ BrowsingDataType data_type,
+ std::string* out_pref);
+
+} // namespace browsing_data
+
+#endif // COMPONENTS_BROWSING_DATA_CORE_BROWSING_DATA_UTILS_H_
diff --git a/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc b/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
new file mode 100644
index 00000000000..eaad13b4b84
--- /dev/null
+++ b/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
@@ -0,0 +1,79 @@
+// 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 "components/browsing_data/core/browsing_data_utils.h"
+
+#include <string>
+
+#include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/browsing_data/core/counters/autofill_counter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class FakeWebDataService : public autofill::AutofillWebDataService {
+ public:
+ FakeWebDataService()
+ : AutofillWebDataService(base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get()) {}
+
+ protected:
+ ~FakeWebDataService() override {}
+};
+
+} // namespace
+
+class BrowsingDataUtilsTest : public testing::Test {
+ public:
+ BrowsingDataUtilsTest() {}
+ ~BrowsingDataUtilsTest() override {}
+
+ private:
+ base::MessageLoop loop_;
+};
+
+// Tests the complex output of the Autofill counter.
+TEST_F(BrowsingDataUtilsTest, AutofillCounterResult) {
+ browsing_data::AutofillCounter counter(
+ scoped_refptr<FakeWebDataService>(new FakeWebDataService()));
+
+ // Test all configurations of zero and nonzero partial results for datatypes.
+ // Test singular and plural for each datatype.
+ const struct TestCase {
+ int num_credit_cards;
+ int num_addresses;
+ int num_suggestions;
+ std::string expected_output;
+ } kTestCases[] = {
+ {0, 0, 0, "none"},
+ {1, 0, 0, "1 credit card"},
+ {0, 5, 0, "5 addresses"},
+ {0, 0, 1, "1 suggestion"},
+ {0, 0, 2, "2 suggestions"},
+ {4, 7, 0, "4 credit cards, 7 addresses"},
+ {3, 0, 9, "3 credit cards, 9 other suggestions"},
+ {0, 1, 1, "1 address, 1 other suggestion"},
+ {9, 6, 3, "9 credit cards, 6 addresses, 3 others"},
+ {4, 2, 1, "4 credit cards, 2 addresses, 1 other"},
+ };
+
+ for (const TestCase& test_case : kTestCases) {
+ browsing_data::AutofillCounter::AutofillResult result(
+ &counter, test_case.num_suggestions, test_case.num_credit_cards,
+ test_case.num_addresses);
+
+ SCOPED_TRACE(
+ base::StringPrintf("Test params: %d credit card(s), "
+ "%d address(es), %d suggestion(s).",
+ test_case.num_credit_cards, test_case.num_addresses,
+ test_case.num_suggestions));
+
+ base::string16 output = browsing_data::GetCounterTextFromResult(&result);
+ EXPECT_EQ(output, base::ASCIIToUTF16(test_case.expected_output));
+ }
+}
diff --git a/chromium/components/browsing_data/core/counters/autofill_counter.cc b/chromium/components/browsing_data/core/counters/autofill_counter.cc
new file mode 100644
index 00000000000..1d520016bff
--- /dev/null
+++ b/chromium/components/browsing_data/core/counters/autofill_counter.cc
@@ -0,0 +1,172 @@
+// 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 "components/browsing_data/core/counters/autofill_counter.h"
+
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+#include "base/memory/scoped_vector.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/browsing_data/core/pref_names.h"
+
+namespace browsing_data {
+
+AutofillCounter::AutofillCounter(
+ scoped_refptr<autofill::AutofillWebDataService> web_data_service)
+ : web_data_service_(web_data_service),
+ suggestions_query_(0),
+ credit_cards_query_(0),
+ addresses_query_(0),
+ num_suggestions_(0),
+ num_credit_cards_(0),
+ num_addresses_(0) {}
+
+AutofillCounter::~AutofillCounter() {
+ CancelAllRequests();
+}
+
+void AutofillCounter::OnInitialized() {
+ DCHECK(web_data_service_);
+}
+
+const char* AutofillCounter::GetPrefName() const {
+ return browsing_data::prefs::kDeleteFormData;
+}
+
+void AutofillCounter::SetPeriodStartForTesting(
+ const base::Time& period_start_for_testing) {
+ period_start_for_testing_ = period_start_for_testing;
+}
+
+void AutofillCounter::Count() {
+ const base::Time start = period_start_for_testing_.is_null()
+ ? GetPeriodStart()
+ : period_start_for_testing_;
+
+ CancelAllRequests();
+
+ // Count the autocomplete suggestions (also called form elements in Autofill).
+ // Note that |AutofillTable::RemoveFormElementsAddedBetween| only deletes
+ // those whose entire existence (i.e. the interval between creation time
+ // and last modified time) lies within the deletion time range. Otherwise,
+ // it only decreases the count property, but always to a nonzero value,
+ // and the suggestion is retained. Therefore here as well, we must only count
+ // the entries that are entirely contained in [start, base::Time::Max()).
+ // Further, many of these entries may contain the same values, as they are
+ // simply the same data point entered on different forms. For example,
+ // [name, value] pairs such as:
+ // ["mail", "example@example.com"]
+ // ["email", "example@example.com"]
+ // ["e-mail", "example@example.com"]
+ // are stored as three separate entries, but from the user's perspective,
+ // they constitute the same suggestion - "my email". Therefore, for the final
+ // output, we will consider all entries with the same value as one suggestion,
+ // and increment the counter only if all entries with the given value are
+ // contained in the interval [start, base::Time::Max()).
+ suggestions_query_ = web_data_service_->GetCountOfValuesContainedBetween(
+ start, base::Time::Max(), this);
+
+ // Count the credit cards.
+ credit_cards_query_ = web_data_service_->GetCreditCards(this);
+
+ // Count the addresses.
+ addresses_query_ = web_data_service_->GetAutofillProfiles(this);
+}
+
+void AutofillCounter::OnWebDataServiceRequestDone(
+ WebDataServiceBase::Handle handle,
+ const WDTypedResult* result) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!result) {
+ CancelAllRequests();
+ return;
+ }
+
+ const base::Time start = period_start_for_testing_.is_null()
+ ? GetPeriodStart()
+ : period_start_for_testing_;
+
+ if (handle == suggestions_query_) {
+ // Autocomplete suggestions.
+ DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType());
+ num_suggestions_ = static_cast<const WDResult<int>*>(result)->GetValue();
+ suggestions_query_ = 0;
+
+ } else if (handle == credit_cards_query_) {
+ // Credit cards.
+ DCHECK_EQ(AUTOFILL_CREDITCARDS_RESULT, result->GetType());
+ const std::vector<autofill::CreditCard*> credit_cards =
+ static_cast<const WDResult<std::vector<autofill::CreditCard*>>*>(result)
+ ->GetValue();
+
+ // We own the result from this query. Make sure it will be deleted.
+ ScopedVector<const autofill::CreditCard> owned_result;
+ owned_result.assign(credit_cards.begin(), credit_cards.end());
+
+ num_credit_cards_ = std::count_if(
+ credit_cards.begin(),
+ credit_cards.end(),
+ [start](const autofill::CreditCard* card) {
+ return card->modification_date() >= start;
+ });
+ credit_cards_query_ = 0;
+
+ } else if (handle == addresses_query_) {
+ // Addresses.
+ DCHECK_EQ(AUTOFILL_PROFILES_RESULT, result->GetType());
+ const std::vector<autofill::AutofillProfile*> addresses =
+ static_cast<const WDResult<std::vector<autofill::AutofillProfile*>>*>(
+ result)
+ ->GetValue();
+
+ // We own the result from this query. Make sure it will be deleted.
+ ScopedVector<const autofill::AutofillProfile> owned_result;
+ owned_result.assign(addresses.begin(), addresses.end());
+
+ num_addresses_ =
+ std::count_if(addresses.begin(), addresses.end(),
+ [start](const autofill::AutofillProfile* address) {
+ return address->modification_date() >= start;
+ });
+ addresses_query_ = 0;
+
+ } else {
+ NOTREACHED() << "No such query: " << handle;
+ }
+
+ // If we still have pending queries, do not report data yet.
+ if (HasPendingQuery())
+ return;
+
+ std::unique_ptr<Result> reported_result(new AutofillResult(
+ this, num_suggestions_, num_credit_cards_, num_addresses_));
+ ReportResult(std::move(reported_result));
+}
+
+void AutofillCounter::CancelAllRequests() {
+ if (suggestions_query_)
+ web_data_service_->CancelRequest(suggestions_query_);
+ if (credit_cards_query_)
+ web_data_service_->CancelRequest(credit_cards_query_);
+ if (addresses_query_)
+ web_data_service_->CancelRequest(addresses_query_);
+}
+
+// AutofillCounter::AutofillResult ---------------------------------------------
+
+AutofillCounter::AutofillResult::AutofillResult(const AutofillCounter* source,
+ ResultInt num_suggestions,
+ ResultInt num_credit_cards,
+ ResultInt num_addresses)
+ : FinishedResult(source, num_suggestions),
+ num_credit_cards_(num_credit_cards),
+ num_addresses_(num_addresses) {}
+
+AutofillCounter::AutofillResult::~AutofillResult() {}
+
+} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/counters/autofill_counter.h b/chromium/components/browsing_data/core/counters/autofill_counter.h
new file mode 100644
index 00000000000..f1833049c20
--- /dev/null
+++ b/chromium/components/browsing_data/core/counters/autofill_counter.h
@@ -0,0 +1,93 @@
+// 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 COMPONENTS_BROWSING_DATA_CORE_COUNTERS_AUTOFILL_COUNTER_H_
+#define COMPONENTS_BROWSING_DATA_CORE_COUNTERS_AUTOFILL_COUNTER_H_
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/browsing_data/core/counters/browsing_data_counter.h"
+#include "components/webdata/common/web_data_service_consumer.h"
+
+namespace autofill {
+class AutofillWebDataService;
+}
+
+namespace browsing_data {
+
+class AutofillCounter : public browsing_data::BrowsingDataCounter,
+ public WebDataServiceConsumer {
+ public:
+ class AutofillResult : public FinishedResult {
+ public:
+ AutofillResult(const AutofillCounter* source,
+ ResultInt num_suggestions,
+ ResultInt num_credit_cards,
+ ResultInt num_addresses);
+ ~AutofillResult() override;
+
+ ResultInt num_credit_cards() const { return num_credit_cards_; }
+ ResultInt num_addresses() const { return num_addresses_; }
+
+ private:
+ ResultInt num_credit_cards_;
+ ResultInt num_addresses_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillResult);
+ };
+
+ explicit AutofillCounter(
+ scoped_refptr<autofill::AutofillWebDataService> web_data_service);
+ ~AutofillCounter() override;
+
+ // BrowsingDataCounter implementation.
+ void OnInitialized() override;
+
+ // Whether the counting is in progress.
+ bool HasPendingQuery() {
+ return suggestions_query_ || credit_cards_query_ || addresses_query_;
+ }
+
+ const char* GetPrefName() const override;
+
+ // Set the beginning of the time period for testing. AutofillTable does not
+ // allow us to set time explicitly, and BrowsingDataCounter recognizes
+ // only predefined time periods, out of which the lowest one is one hour.
+ // Obviously, the test cannot run that long.
+ // TODO(msramek): Consider changing BrowsingDataCounter to use arbitrary
+ // time periods instead of BrowsingDataRemover::TimePeriod.
+ void SetPeriodStartForTesting(const base::Time& period_start_for_testing);
+
+ private:
+ void Count() override;
+
+ // WebDataServiceConsumer implementation.
+ void OnWebDataServiceRequestDone(WebDataServiceBase::Handle handle,
+ const WDTypedResult* result) override;
+
+ // Cancel all pending requests to AutofillWebdataService.
+ void CancelAllRequests();
+
+ base::ThreadChecker thread_checker_;
+
+ scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
+
+ WebDataServiceBase::Handle suggestions_query_;
+ WebDataServiceBase::Handle credit_cards_query_;
+ WebDataServiceBase::Handle addresses_query_;
+
+ ResultInt num_suggestions_;
+ ResultInt num_credit_cards_;
+ ResultInt num_addresses_;
+
+ base::Time period_start_for_testing_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutofillCounter);
+};
+
+} // namespace browsing_data
+
+#endif // COMPONENTS_BROWSING_DATA_CORE_COUNTERS_AUTOFILL_COUNTER_H_
diff --git a/chromium/components/browsing_data/core/counters/browsing_data_counter.cc b/chromium/components/browsing_data/core/counters/browsing_data_counter.cc
new file mode 100644
index 00000000000..1af879c6576
--- /dev/null
+++ b/chromium/components/browsing_data/core/counters/browsing_data_counter.cc
@@ -0,0 +1,96 @@
+// 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 "components/browsing_data/core/counters/browsing_data_counter.h"
+
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "components/browsing_data/core/browsing_data_utils.h"
+#include "components/browsing_data/core/pref_names.h"
+#include "components/prefs/pref_service.h"
+
+namespace browsing_data {
+
+BrowsingDataCounter::BrowsingDataCounter() {}
+
+BrowsingDataCounter::~BrowsingDataCounter() {}
+
+void BrowsingDataCounter::Init(PrefService* pref_service,
+ const Callback& callback) {
+ DCHECK(!initialized_);
+ callback_ = callback;
+ pref_service_ = pref_service;
+ pref_.Init(GetPrefName(), pref_service_,
+ base::Bind(&BrowsingDataCounter::Restart, base::Unretained(this)));
+ period_.Init(
+ browsing_data::prefs::kDeleteTimePeriod, pref_service_,
+ base::Bind(&BrowsingDataCounter::Restart, base::Unretained(this)));
+
+ initialized_ = true;
+ OnInitialized();
+}
+
+void BrowsingDataCounter::OnInitialized() {}
+
+base::Time BrowsingDataCounter::GetPeriodStart() {
+ return CalculateBeginDeleteTime(static_cast<TimePeriod>(*period_));
+}
+
+void BrowsingDataCounter::Restart() {
+ DCHECK(initialized_);
+
+ // If this data type was unchecked for deletion, we do not need to count it.
+ if (!pref_service_->GetBoolean(GetPrefName()))
+ return;
+
+ callback_.Run(base::MakeUnique<Result>(this));
+
+ Count();
+}
+
+void BrowsingDataCounter::ReportResult(ResultInt value) {
+ DCHECK(initialized_);
+ callback_.Run(base::MakeUnique<FinishedResult>(this, value));
+}
+
+void BrowsingDataCounter::ReportResult(std::unique_ptr<Result> result) {
+ DCHECK(initialized_);
+ callback_.Run(std::move(result));
+}
+
+PrefService* BrowsingDataCounter::GetPrefs() const {
+ return pref_service_;
+}
+
+// BrowsingDataCounter::Result -------------------------------------------------
+
+BrowsingDataCounter::Result::Result(const BrowsingDataCounter* source)
+ : source_(source) {}
+
+BrowsingDataCounter::Result::~Result() {}
+
+bool BrowsingDataCounter::Result::Finished() const {
+ return false;
+}
+
+// BrowsingDataCounter::FinishedResult -----------------------------------------
+
+BrowsingDataCounter::FinishedResult::FinishedResult(
+ const BrowsingDataCounter* source,
+ ResultInt value)
+ : Result(source), value_(value) {}
+
+BrowsingDataCounter::FinishedResult::~FinishedResult() {}
+
+bool BrowsingDataCounter::FinishedResult::Finished() const {
+ return true;
+}
+
+BrowsingDataCounter::ResultInt BrowsingDataCounter::FinishedResult::Value()
+ const {
+ return value_;
+}
+
+} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/counters/browsing_data_counter.h b/chromium/components/browsing_data/core/counters/browsing_data_counter.h
new file mode 100644
index 00000000000..c2749364f53
--- /dev/null
+++ b/chromium/components/browsing_data/core/counters/browsing_data_counter.h
@@ -0,0 +1,120 @@
+// 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 COMPONENTS_BROWSING_DATA_CORE_COUNTERS_BROWSING_DATA_COUNTER_H_
+#define COMPONENTS_BROWSING_DATA_CORE_COUNTERS_BROWSING_DATA_COUNTER_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "components/prefs/pref_member.h"
+
+class PrefService;
+
+namespace browsing_data {
+
+class BrowsingDataCounter {
+ public:
+ typedef int64_t ResultInt;
+
+ // Base class of results returned by BrowsingDataCounter. When the computation
+ // has started, an instance is returned to represent a pending result.
+ class Result {
+ public:
+ explicit Result(const BrowsingDataCounter* source);
+ virtual ~Result();
+
+ const BrowsingDataCounter* source() const { return source_; }
+ virtual bool Finished() const;
+
+ private:
+ const BrowsingDataCounter* source_;
+
+ DISALLOW_COPY_AND_ASSIGN(Result);
+ };
+
+ // A subclass of Result returned when the computation has finished. The result
+ // value can be retrieved by calling |Value()|. Some BrowsingDataCounter
+ // subclasses might use a subclass of FinishedResult to provide more complex
+ // results.
+ class FinishedResult : public Result {
+ public:
+ FinishedResult(const BrowsingDataCounter* source, ResultInt value);
+ ~FinishedResult() override;
+
+ // Result:
+ bool Finished() const override;
+
+ ResultInt Value() const;
+
+ private:
+ ResultInt value_;
+
+ DISALLOW_COPY_AND_ASSIGN(FinishedResult);
+ };
+
+ typedef base::Callback<void(std::unique_ptr<Result>)> Callback;
+
+ BrowsingDataCounter();
+ virtual ~BrowsingDataCounter();
+
+ // Should be called once to initialize this class.
+ void Init(PrefService* pref_service, const Callback& callback);
+
+ // Name of the preference associated with this counter.
+ virtual const char* GetPrefName() const = 0;
+
+ // PrefService that manages the preferences for the user profile
+ // associated with this counter.
+ PrefService* GetPrefs() const;
+
+ // Restarts the counter. Will be called automatically if the counting needs
+ // to be restarted, e.g. when the deletion preference changes state or when
+ // we are notified of data changes.
+ void Restart();
+
+ protected:
+ // Should be called from |Count| by any overriding class to indicate that
+ // counting is finished and report |value| as the result.
+ void ReportResult(ResultInt value);
+
+ // A convenience overload of the previous method that allows subclasses to
+ // provide a custom |result|.
+ void ReportResult(std::unique_ptr<Result> result);
+
+ // Calculates the beginning of the counting period as |period_| before now.
+ base::Time GetPeriodStart();
+
+ private:
+ // Called after the class is initialized by calling |Init|.
+ virtual void OnInitialized();
+
+ // Count the data.
+ virtual void Count() = 0;
+
+ // Pointer to the PrefService that manages the preferences for the user
+ // profile associated with this counter.
+ PrefService* pref_service_;
+
+ // The callback that will be called when the UI should be updated with a new
+ // counter value.
+ Callback callback_;
+
+ // The boolean preference indicating whether this data type is to be deleted.
+ // If false, we will not count it.
+ BooleanPrefMember pref_;
+
+ // The integer preference describing the time period for which this data type
+ // is to be deleted.
+ IntegerPrefMember period_;
+
+ // Whether this class was properly initialized by calling |Init|.
+ bool initialized_ = false;
+};
+
+} // namespace browsing_data
+
+#endif // COMPONENTS_BROWSING_DATA_CORE_COUNTERS_BROWSING_DATA_COUNTER_H_
diff --git a/chromium/components/browsing_data/core/counters/history_counter.cc b/chromium/components/browsing_data/core/counters/history_counter.cc
new file mode 100644
index 00000000000..c1c44512ba0
--- /dev/null
+++ b/chromium/components/browsing_data/core/counters/history_counter.cc
@@ -0,0 +1,172 @@
+// 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 "components/browsing_data/core/counters/history_counter.h"
+
+#include <limits.h>
+#include <stdint.h>
+
+#include "base/memory/ptr_util.h"
+#include "base/timer/timer.h"
+#include "components/browsing_data/core/pref_names.h"
+
+namespace {
+static const int64_t kWebHistoryTimeoutSeconds = 10;
+}
+
+namespace browsing_data {
+
+HistoryCounter::HistoryCounter(
+ history::HistoryService* history_service,
+ const GetUpdatedWebHistoryServiceCallback& callback,
+ syncer::SyncService* sync_service)
+ : history_service_(history_service),
+ web_history_service_callback_(callback),
+ sync_service_(sync_service),
+ has_synced_visits_(false),
+ local_counting_finished_(false),
+ web_counting_finished_(false),
+ history_sync_enabled_(false),
+ weak_ptr_factory_(this) {}
+
+HistoryCounter::~HistoryCounter() {
+ if (sync_service_)
+ sync_service_->RemoveObserver(this);
+}
+
+void HistoryCounter::OnInitialized() {
+ if (sync_service_)
+ sync_service_->AddObserver(this);
+ history_sync_enabled_ = !!web_history_service_callback_.Run();
+}
+
+bool HistoryCounter::HasTrackedTasks() {
+ return cancelable_task_tracker_.HasTrackedTasks();
+}
+
+const char* HistoryCounter::GetPrefName() const {
+ return browsing_data::prefs::kDeleteBrowsingHistory;
+}
+
+void HistoryCounter::Count() {
+ // Reset the state.
+ cancelable_task_tracker_.TryCancelAll();
+ web_history_request_.reset();
+ has_synced_visits_ = false;
+
+ // Count the locally stored items.
+ local_counting_finished_ = false;
+
+ history_service_->GetHistoryCount(
+ GetPeriodStart(), base::Time::Max(),
+ base::Bind(&HistoryCounter::OnGetLocalHistoryCount,
+ weak_ptr_factory_.GetWeakPtr()),
+ &cancelable_task_tracker_);
+
+ // If the history sync is enabled, test if there is at least one synced item.
+ history::WebHistoryService* web_history =
+ web_history_service_callback_.Run();
+
+ if (!web_history) {
+ web_counting_finished_ = true;
+ return;
+ }
+
+ web_counting_finished_ = false;
+
+ web_history_timeout_.Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(kWebHistoryTimeoutSeconds), this,
+ &HistoryCounter::OnWebHistoryTimeout);
+
+ history::QueryOptions options;
+ options.max_count = 1;
+ options.begin_time = GetPeriodStart();
+ options.end_time = base::Time::Max();
+ web_history_request_ = web_history->QueryHistory(
+ base::string16(), options,
+ base::Bind(&HistoryCounter::OnGetWebHistoryCount,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // TODO(msramek): Include web history count when there is an API for it.
+}
+
+void HistoryCounter::OnGetLocalHistoryCount(
+ history::HistoryCountResult result) {
+ // Ensure that all callbacks are on the same thread, so that we do not need
+ // a mutex for |MergeResults|.
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!result.success) {
+ LOG(ERROR) << "Failed to count the local history.";
+ return;
+ }
+
+ local_result_ = result.count;
+ local_counting_finished_ = true;
+ MergeResults();
+}
+
+void HistoryCounter::OnGetWebHistoryCount(
+ history::WebHistoryService::Request* request,
+ const base::DictionaryValue* result) {
+ // Ensure that all callbacks are on the same thread, so that we do not need
+ // a mutex for |MergeResults|.
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // If the timeout for this request already fired, ignore the result.
+ if (!web_history_timeout_.IsRunning())
+ return;
+
+ web_history_timeout_.Stop();
+
+ // If the query failed, err on the safe side and inform the user that they
+ // may have history items stored in Sync. Otherwise, we expect at least one
+ // entry in the "event" list.
+ const base::ListValue* events;
+ has_synced_visits_ =
+ !result || (result->GetList("event", &events) && !events->empty());
+ web_counting_finished_ = true;
+ MergeResults();
+}
+
+void HistoryCounter::OnWebHistoryTimeout() {
+ // Ensure that all callbacks are on the same thread, so that we do not need
+ // a mutex for |MergeResults|.
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // If the query timed out, err on the safe side and inform the user that they
+ // may have history items stored in Sync.
+ web_history_request_.reset();
+ has_synced_visits_ = true;
+ web_counting_finished_ = true;
+ MergeResults();
+}
+
+void HistoryCounter::MergeResults() {
+ if (!local_counting_finished_ || !web_counting_finished_)
+ return;
+
+ ReportResult(
+ base::MakeUnique<HistoryResult>(this, local_result_, has_synced_visits_));
+}
+
+HistoryCounter::HistoryResult::HistoryResult(const HistoryCounter* source,
+ ResultInt value,
+ bool has_synced_visits)
+ : FinishedResult(source, value), has_synced_visits_(has_synced_visits) {}
+
+HistoryCounter::HistoryResult::~HistoryResult() {}
+
+void HistoryCounter::OnStateChanged() {
+ bool history_sync_enabled_new_state = !!web_history_service_callback_.Run();
+
+ // If the history sync was just enabled or disabled, restart the counter
+ // so that we update the result accordingly.
+ if (history_sync_enabled_ != history_sync_enabled_new_state) {
+ history_sync_enabled_ = history_sync_enabled_new_state;
+ Restart();
+ }
+}
+
+} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/counters/history_counter.h b/chromium/components/browsing_data/core/counters/history_counter.h
new file mode 100644
index 00000000000..dd3db2f85e8
--- /dev/null
+++ b/chromium/components/browsing_data/core/counters/history_counter.h
@@ -0,0 +1,89 @@
+// 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 COMPONENTS_BROWSING_DATA_CORE_COUNTERS_HISTORY_COUNTER_H_
+#define COMPONENTS_BROWSING_DATA_CORE_COUNTERS_HISTORY_COUNTER_H_
+
+#include <memory>
+
+#include "base/task/cancelable_task_tracker.h"
+#include "base/timer/timer.h"
+#include "components/browsing_data/core/counters/browsing_data_counter.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/web_history_service.h"
+#include "components/sync/driver/sync_service.h"
+#include "components/sync/driver/sync_service_observer.h"
+
+namespace browsing_data {
+
+class HistoryCounter : public browsing_data::BrowsingDataCounter,
+ public syncer::SyncServiceObserver {
+ public:
+ typedef base::Callback<history::WebHistoryService*()>
+ GetUpdatedWebHistoryServiceCallback;
+
+ class HistoryResult : public FinishedResult {
+ public:
+ HistoryResult(const HistoryCounter* source,
+ ResultInt value,
+ bool has_synced_visits);
+ ~HistoryResult() override;
+
+ bool has_synced_visits() const { return has_synced_visits_; }
+
+ private:
+ bool has_synced_visits_;
+ };
+
+ explicit HistoryCounter(history::HistoryService* history_service,
+ const GetUpdatedWebHistoryServiceCallback& callback,
+ syncer::SyncService* sync_service);
+ ~HistoryCounter() override;
+
+ void OnInitialized() override;
+
+ // Whether there are counting tasks in progress. Only used for testing.
+ bool HasTrackedTasks();
+
+ const char* GetPrefName() const override;
+
+ private:
+ void Count() override;
+
+ void OnGetLocalHistoryCount(history::HistoryCountResult result);
+ void OnGetWebHistoryCount(history::WebHistoryService::Request* request,
+ const base::DictionaryValue* result);
+ void OnWebHistoryTimeout();
+ void MergeResults();
+
+ // SyncServiceObserver implementation.
+ void OnStateChanged() override;
+
+ history::HistoryService* history_service_;
+
+ GetUpdatedWebHistoryServiceCallback web_history_service_callback_;
+
+ syncer::SyncService* sync_service_;
+
+ bool has_synced_visits_;
+
+ bool local_counting_finished_;
+ bool web_counting_finished_;
+
+ base::CancelableTaskTracker cancelable_task_tracker_;
+ std::unique_ptr<history::WebHistoryService::Request> web_history_request_;
+ base::OneShotTimer web_history_timeout_;
+
+ base::ThreadChecker thread_checker_;
+
+ BrowsingDataCounter::ResultInt local_result_;
+
+ bool history_sync_enabled_;
+
+ base::WeakPtrFactory<HistoryCounter> weak_ptr_factory_;
+};
+
+} // namespace browsing_data
+
+#endif // COMPONENTS_BROWSING_DATA_CORE_COUNTERS_HISTORY_COUNTER_H_
diff --git a/chromium/components/browsing_data/core/counters/passwords_counter.cc b/chromium/components/browsing_data/core/counters/passwords_counter.cc
new file mode 100644
index 00000000000..8585158b839
--- /dev/null
+++ b/chromium/components/browsing_data/core/counters/passwords_counter.cc
@@ -0,0 +1,52 @@
+// 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 "components/browsing_data/core/counters/passwords_counter.h"
+
+#include "components/browsing_data/core/pref_names.h"
+#include "components/password_manager/core/browser/password_store.h"
+
+namespace browsing_data {
+
+PasswordsCounter::PasswordsCounter(
+ scoped_refptr<password_manager::PasswordStore> store) : store_(store) {}
+
+PasswordsCounter::~PasswordsCounter() {
+ store_->RemoveObserver(this);
+}
+
+void PasswordsCounter::OnInitialized() {
+ DCHECK(store_);
+ store_->AddObserver(this);
+}
+
+const char* PasswordsCounter::GetPrefName() const {
+ return browsing_data::prefs::kDeletePasswords;
+}
+
+void PasswordsCounter::Count() {
+ cancelable_task_tracker()->TryCancelAll();
+ // TODO(msramek): We don't actually need the logins themselves, just their
+ // count. Consider implementing |PasswordStore::CountAutofillableLogins|.
+ // This custom request should also allow us to specify the time range, so that
+ // we can use it to filter the login creation date in the database.
+ store_->GetAutofillableLogins(this);
+}
+
+void PasswordsCounter::OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+ base::Time start = GetPeriodStart();
+ ReportResult(std::count_if(
+ results.begin(), results.end(),
+ [start](const std::unique_ptr<autofill::PasswordForm>& form) {
+ return form->date_created >= start;
+ }));
+}
+
+void PasswordsCounter::OnLoginsChanged(
+ const password_manager::PasswordStoreChangeList& changes) {
+ Restart();
+}
+
+} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/counters/passwords_counter.h b/chromium/components/browsing_data/core/counters/passwords_counter.h
new file mode 100644
index 00000000000..dd69536393f
--- /dev/null
+++ b/chromium/components/browsing_data/core/counters/passwords_counter.h
@@ -0,0 +1,48 @@
+// 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 COMPONENTS_BROWSING_DATA_CORE_COUNTERS_PASSWORDS_COUNTER_H_
+#define COMPONENTS_BROWSING_DATA_CORE_COUNTERS_PASSWORDS_COUNTER_H_
+
+#include <memory>
+#include <vector>
+
+#include "components/browsing_data/core/counters/browsing_data_counter.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/browser/password_store_consumer.h"
+
+namespace browsing_data {
+
+class PasswordsCounter : public browsing_data::BrowsingDataCounter,
+ public password_manager::PasswordStoreConsumer,
+ public password_manager::PasswordStore::Observer {
+ public:
+ explicit PasswordsCounter(
+ scoped_refptr<password_manager::PasswordStore> store);
+ ~PasswordsCounter() override;
+
+ const char* GetPrefName() const override;
+
+ private:
+ void OnInitialized() override;
+
+ // Counting is done asynchronously in a request to PasswordStore.
+ // This callback returns the results, which are subsequently reported.
+ void OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
+
+ // Called when the contents of the password store change. Triggers new
+ // counting.
+ void OnLoginsChanged(
+ const password_manager::PasswordStoreChangeList& changes) override;
+
+ void Count() override;
+
+ base::CancelableTaskTracker cancelable_task_tracker_;
+ scoped_refptr<password_manager::PasswordStore> store_;
+};
+
+} // namespace browsing_data
+
+#endif // COMPONENTS_BROWSING_DATA_CORE_COUNTERS_PASSWORDS_COUNTER_H_
diff --git a/chromium/components/browsing_data/core/history_notice_utils.cc b/chromium/components/browsing_data/core/history_notice_utils.cc
new file mode 100644
index 00000000000..4c3612352e4
--- /dev/null
+++ b/chromium/components/browsing_data/core/history_notice_utils.cc
@@ -0,0 +1,115 @@
+// 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 "components/browsing_data/core/history_notice_utils.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/history/core/browser/web_history_service.h"
+#include "components/sync/driver/sync_service.h"
+#include "components/version_info/version_info.h"
+
+namespace {
+
+// Merges several asynchronous boolean callbacks into one that returns a boolean
+// product of their responses. Deletes itself when done.
+class MergeBooleanCallbacks {
+ public:
+ // Constructor. Upon receiving |expected_call_count| calls to |RunCallback|,
+ // |target_callback| will be run with the boolean product of their results.
+ MergeBooleanCallbacks(
+ int expected_call_count,
+ const base::Callback<void(bool)>& target_callback)
+ : expected_call_count_(expected_call_count),
+ target_callback_(target_callback),
+ final_response_(true),
+ call_count_(0) {}
+
+ // This method is to be bound to all asynchronous callbacks which we want
+ // to merge.
+ void RunCallback(bool response) {
+ final_response_ &= response;
+
+ if (++call_count_ < expected_call_count_)
+ return;
+
+ target_callback_.Run(final_response_);
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+ }
+
+ private:
+ int expected_call_count_;
+ base::Callback<void(bool)> target_callback_;
+ bool final_response_;
+ int call_count_;
+};
+
+} // namespace
+
+namespace browsing_data {
+
+namespace testing {
+
+bool g_override_other_forms_of_browsing_history_query = false;
+
+} // namespace testing
+
+void ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
+ const syncer::SyncService* sync_service,
+ history::WebHistoryService* history_service,
+ base::Callback<void(bool)> callback) {
+ if (!sync_service ||
+ !sync_service->IsSyncActive() ||
+ !sync_service->GetActiveDataTypes().Has(
+ syncer::HISTORY_DELETE_DIRECTIVES) ||
+ sync_service->IsUsingSecondaryPassphrase() ||
+ !history_service) {
+ callback.Run(false);
+ return;
+ }
+
+ history_service->QueryWebAndAppActivity(callback);
+}
+
+void ShouldPopupDialogAboutOtherFormsOfBrowsingHistory(
+ const syncer::SyncService* sync_service,
+ history::WebHistoryService* history_service,
+ version_info::Channel channel,
+ base::Callback<void(bool)> callback) {
+ // If the query for other forms of browsing history is overriden for testing,
+ // the conditions are identical with
+ // ShouldShowNoticeAboutOtherFormsOfBrowsingHistory.
+ if (testing::g_override_other_forms_of_browsing_history_query) {
+ ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
+ sync_service, history_service, callback);
+ return;
+ }
+
+ if (!sync_service ||
+ !sync_service->IsSyncActive() ||
+ !sync_service->GetActiveDataTypes().Has(
+ syncer::HISTORY_DELETE_DIRECTIVES) ||
+ sync_service->IsUsingSecondaryPassphrase() ||
+ !history_service) {
+ callback.Run(false);
+ return;
+ }
+
+ // Return the boolean product of QueryWebAndAppActivity and
+ // QueryOtherFormsOfBrowsingHistory. MergeBooleanCallbacks deletes itself
+ // after processing both callbacks.
+ MergeBooleanCallbacks* merger = new MergeBooleanCallbacks(2, callback);
+ history_service->QueryWebAndAppActivity(base::Bind(
+ &MergeBooleanCallbacks::RunCallback, base::Unretained(merger)));
+ history_service->QueryOtherFormsOfBrowsingHistory(
+ channel,
+ base::Bind(
+ &MergeBooleanCallbacks::RunCallback, base::Unretained(merger)));
+}
+
+} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/history_notice_utils.h b/chromium/components/browsing_data/core/history_notice_utils.h
new file mode 100644
index 00000000000..5f454c95939
--- /dev/null
+++ b/chromium/components/browsing_data/core/history_notice_utils.h
@@ -0,0 +1,58 @@
+// 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 COMPONENTS_BROWSING_DATA_CORE_HISTORY_NOTICE_UTILS_H_
+#define COMPONENTS_BROWSING_DATA_CORE_HISTORY_NOTICE_UTILS_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+
+namespace history {
+class WebHistoryService;
+}
+
+namespace syncer {
+class SyncService;
+}
+
+namespace version_info {
+enum class Channel;
+}
+
+namespace browsing_data {
+
+namespace testing {
+
+// TODO(crbug.com/595332): A boolean flag indicating that
+// ShouldShowNoticeAboutOtherFormsOfBrowsingHistory() should skip the query
+// for other forms of browsing history and just assume some such forms were
+// found. Used only for testing. The default is false.
+extern bool g_override_other_forms_of_browsing_history_query;
+
+} // testing
+
+// Whether the Clear Browsing Data UI should show a notice about the existence
+// of other forms of browsing history stored in user's account. The response
+// is returned in a |callback|.
+void ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
+ const syncer::SyncService* sync_service,
+ history::WebHistoryService* history_service,
+ base::Callback<void(bool)> callback);
+
+// Whether the Clear Browsing Data UI should popup a dialog with information
+// about the existence of other forms of browsing history stored in user's
+// account when the user deletes their browsing history for the first time.
+// The response is returned in a |callback|. The |channel| parameter
+// must be provided for successful communication with the Sync server, but
+// the result does not depend on it.
+void ShouldPopupDialogAboutOtherFormsOfBrowsingHistory(
+ const syncer::SyncService* sync_service,
+ history::WebHistoryService* history_service,
+ version_info::Channel channel,
+ base::Callback<void(bool)> callback);
+
+} // namespace browsing_data
+
+#endif // COMPONENTS_BROWSING_DATA_CORE_HISTORY_NOTICE_UTILS_H_
diff --git a/chromium/components/browsing_data/core/history_notice_utils_unittest.cc b/chromium/components/browsing_data/core/history_notice_utils_unittest.cc
new file mode 100644
index 00000000000..6c4363c02d1
--- /dev/null
+++ b/chromium/components/browsing_data/core/history_notice_utils_unittest.cc
@@ -0,0 +1,187 @@
+// 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 "components/browsing_data/core/history_notice_utils.h"
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "components/history/core/test/fake_web_history_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/signin/core/browser/test_signin_client.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/driver/fake_sync_service.h"
+#include "components/version_info/version_info.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace browsing_data {
+
+namespace {
+
+class TestSyncService : public syncer::FakeSyncService {
+ public:
+ // Getters (FakeSyncService implementation). ---------------------------------
+ bool IsSyncActive() const override {
+ return sync_active_;
+ }
+
+ syncer::ModelTypeSet GetActiveDataTypes() const override {
+ return active_data_types_;
+ }
+
+ bool IsUsingSecondaryPassphrase() const override {
+ return using_secondary_passphrase_;
+ }
+
+ // Setters. ------------------------------------------------------------------
+ void set_sync_active(bool active) {
+ sync_active_ = active;
+ }
+
+ void set_active_data_types(syncer::ModelTypeSet data_types) {
+ active_data_types_ = data_types;
+ }
+
+ void set_using_secondary_passphrase(bool passphrase) {
+ using_secondary_passphrase_ = passphrase;
+ }
+
+ private:
+ syncer::ModelTypeSet active_data_types_;
+ bool using_secondary_passphrase_ = false;
+ bool sync_active_ = false;
+};
+
+} // namespace
+
+
+class HistoryNoticeUtilsTest : public ::testing::Test {
+ public:
+ HistoryNoticeUtilsTest()
+ : signin_client_(nullptr),
+ signin_manager_(&signin_client_, &account_tracker_) {
+ }
+
+ void SetUp() override {
+ sync_service_.reset(new TestSyncService());
+ history_service_.reset(new history::FakeWebHistoryService(
+ &oauth2_token_service_,
+ &signin_manager_,
+ url_request_context_));
+ history_service_->SetupFakeResponse(true /* success */, net::HTTP_OK);
+ }
+
+ TestSyncService* sync_service() {
+ return sync_service_.get();
+ }
+
+ history::FakeWebHistoryService* history_service() {
+ return history_service_.get();
+ }
+
+ void ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(
+ bool expected_test_case_result) {
+ bool got_result = false;
+
+ ShouldPopupDialogAboutOtherFormsOfBrowsingHistory(
+ sync_service_.get(),
+ history_service_.get(),
+ version_info::Channel::STABLE,
+ base::Bind(
+ &HistoryNoticeUtilsTest::Callback,
+ base::Unretained(this),
+ base::Unretained(&got_result)));
+
+ if (!got_result) {
+ run_loop_.reset(new base::RunLoop());
+ run_loop_->Run();
+ }
+
+ // Process the DeleteSoon() called on MergeBooleanCallbacks, otherwise
+ // this it will be considered to be leaked.
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(expected_test_case_result, result_);
+ }
+
+ private:
+ void Callback(bool* got_result, bool result) {
+ *got_result = true;
+ result_ = result;
+
+ if (run_loop_)
+ run_loop_->Quit();
+ }
+
+ FakeProfileOAuth2TokenService oauth2_token_service_;
+ AccountTrackerService account_tracker_;
+ TestSigninClient signin_client_;
+ FakeSigninManagerBase signin_manager_;
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_;
+ std::unique_ptr<TestSyncService> sync_service_;
+ std::unique_ptr<history::FakeWebHistoryService> history_service_;
+
+ std::unique_ptr<base::RunLoop> run_loop_;
+ bool result_;
+
+ base::MessageLoop message_loop_;
+};
+
+TEST_F(HistoryNoticeUtilsTest, NotSyncing) {
+ ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
+}
+
+TEST_F(HistoryNoticeUtilsTest, SyncingWithWrongParameters) {
+ sync_service()->set_sync_active(true);
+
+ // Regardless of the state of the web history...
+ history_service()->SetWebAndAppActivityEnabled(true);
+ history_service()->SetOtherFormsOfBrowsingHistoryPresent(true);
+
+ // ...the response is false if there's custom passphrase...
+ sync_service()->set_active_data_types(syncer::ModelTypeSet::All());
+ sync_service()->set_using_secondary_passphrase(true);
+ ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
+
+ // ...or even if there's no custom passphrase, but we're not syncing history.
+ syncer::ModelTypeSet only_passwords(syncer::PASSWORDS);
+ sync_service()->set_active_data_types(only_passwords);
+ sync_service()->set_using_secondary_passphrase(false);
+ ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
+}
+
+TEST_F(HistoryNoticeUtilsTest, WebHistoryStates) {
+ // If history Sync is active...
+ sync_service()->set_sync_active(true);
+ sync_service()->set_active_data_types(syncer::ModelTypeSet::All());
+
+ // ...the result is true if both web history queries return true...
+ history_service()->SetWebAndAppActivityEnabled(true);
+ history_service()->SetOtherFormsOfBrowsingHistoryPresent(true);
+ ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(true);
+
+ // ...but not otherwise.
+ history_service()->SetOtherFormsOfBrowsingHistoryPresent(false);
+ ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
+ history_service()->SetWebAndAppActivityEnabled(false);
+ ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
+ history_service()->SetOtherFormsOfBrowsingHistoryPresent(true);
+ ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
+
+ // Invalid responses from the web history are interpreted as false.
+ history_service()->SetWebAndAppActivityEnabled(true);
+ history_service()->SetOtherFormsOfBrowsingHistoryPresent(true);
+ history_service()->SetupFakeResponse(true, net::HTTP_INTERNAL_SERVER_ERROR);
+ ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
+ history_service()->SetupFakeResponse(false, net::HTTP_OK);
+ ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
+}
+
+} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/pref_names.cc b/chromium/components/browsing_data/core/pref_names.cc
new file mode 100644
index 00000000000..4ff2416aed8
--- /dev/null
+++ b/chromium/components/browsing_data/core/pref_names.cc
@@ -0,0 +1,70 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/browsing_data/core/pref_names.h"
+
+#include "components/pref_registry/pref_registry_syncable.h"
+
+namespace browsing_data {
+
+namespace prefs {
+
+// Clear browsing data deletion time period.
+const char kDeleteTimePeriod[] = "browser.clear_data.time_period";
+
+// Clear Browsing Data dialog datatype preferences.
+const char kDeleteBrowsingHistory[] = "browser.clear_data.browsing_history";
+const char kDeleteDownloadHistory[] = "browser.clear_data.download_history";
+const char kDeleteCache[] = "browser.clear_data.cache";
+const char kDeleteCookies[] = "browser.clear_data.cookies";
+const char kDeletePasswords[] = "browser.clear_data.passwords";
+const char kDeleteFormData[] = "browser.clear_data.form_data";
+const char kDeleteHostedAppsData[] = "browser.clear_data.hosted_apps_data";
+const char kDeleteMediaLicenses[] = "browser.clear_data.media_licenses";
+
+// Other Clear Browsing Data preferences.
+const char kLastClearBrowsingDataTime[] =
+ "browser.last_clear_browsing_data_time";
+const char kClearBrowsingDataHistoryNoticeShownTimes[] =
+ "browser.clear_data.history_notice_shown_times";
+
+void RegisterBrowserUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterIntegerPref(
+ kDeleteTimePeriod, 0,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ kDeleteBrowsingHistory, true,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ kDeleteCache, true,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ kDeleteCookies, true,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ kDeletePasswords, false,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ kDeleteFormData, false,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterIntegerPref(
+ kClearBrowsingDataHistoryNoticeShownTimes, 0);
+
+#if !defined(OS_IOS)
+ registry->RegisterBooleanPref(
+ kDeleteDownloadHistory, true,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ kDeleteHostedAppsData, false,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ kDeleteMediaLicenses, false,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterInt64Pref(prefs::kLastClearBrowsingDataTime, 0);
+#endif // !defined(OS_IOS)
+}
+
+} // namespace prefs
+
+} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/pref_names.h b/chromium/components/browsing_data/core/pref_names.h
new file mode 100644
index 00000000000..8325ab4a76c
--- /dev/null
+++ b/chromium/components/browsing_data/core/pref_names.h
@@ -0,0 +1,37 @@
+// 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 COMPONENTS_BROWSING_DATA_CORE_PREF_NAMES_H_
+#define COMPONENTS_BROWSING_DATA_CORE_PREF_NAMES_H_
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+namespace browsing_data {
+
+namespace prefs {
+
+extern const char kDeleteTimePeriod[];
+
+extern const char kDeleteBrowsingHistory[];
+extern const char kDeleteDownloadHistory[];
+extern const char kDeleteCache[];
+extern const char kDeleteCookies[];
+extern const char kDeletePasswords[];
+extern const char kDeleteFormData[];
+extern const char kDeleteHostedAppsData[];
+extern const char kDeleteMediaLicenses[];
+
+extern const char kLastClearBrowsingDataTime[];
+extern const char kClearBrowsingDataHistoryNoticeShownTimes[];
+
+// Registers the Clear Browsing Data UI prefs.
+void RegisterBrowserUserPrefs(user_prefs::PrefRegistrySyncable* registry);
+
+} // namespace prefs
+
+} // namespace browsing_data
+
+#endif // COMPONENTS_BROWSING_DATA_CORE_PREF_NAMES_H_
diff --git a/chromium/components/browsing_data/storage_partition_http_cache_data_remover.cc b/chromium/components/browsing_data/storage_partition_http_cache_data_remover.cc
deleted file mode 100644
index fabde8efbcf..00000000000
--- a/chromium/components/browsing_data/storage_partition_http_cache_data_remover.cc
+++ /dev/null
@@ -1,310 +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 "components/browsing_data/storage_partition_http_cache_data_remover.h"
-
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/browsing_data/conditional_cache_deletion_helper.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
-#include "net/base/sdch_manager.h"
-#include "net/disk_cache/blockfile/backend_impl.h"
-#include "net/disk_cache/disk_cache.h"
-#include "net/disk_cache/memory/mem_backend_impl.h"
-#include "net/disk_cache/simple/simple_backend_impl.h"
-#include "net/http/http_cache.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-
-using content::BrowserThread;
-
-namespace browsing_data {
-
-StoragePartitionHttpCacheDataRemover::StoragePartitionHttpCacheDataRemover(
- base::Callback<bool(const GURL&)> url_predicate,
- base::Time delete_begin,
- base::Time delete_end,
- net::URLRequestContextGetter* main_context_getter,
- net::URLRequestContextGetter* media_context_getter)
- : url_predicate_(url_predicate),
- delete_begin_(delete_begin),
- delete_end_(delete_end),
- main_context_getter_(main_context_getter),
- media_context_getter_(media_context_getter),
- next_cache_state_(STATE_NONE),
- cache_(nullptr),
- calculation_result_(0) {
-}
-
-StoragePartitionHttpCacheDataRemover::~StoragePartitionHttpCacheDataRemover() {
-}
-
-// static.
-StoragePartitionHttpCacheDataRemover*
-StoragePartitionHttpCacheDataRemover::CreateForRange(
- content::StoragePartition* storage_partition,
- base::Time delete_begin,
- base::Time delete_end) {
- return new StoragePartitionHttpCacheDataRemover(
- base::Callback<bool(const GURL&)>(), // Null callback.
- delete_begin, delete_end,
- storage_partition->GetURLRequestContext(),
- storage_partition->GetMediaURLRequestContext());
-}
-
-// static.
-StoragePartitionHttpCacheDataRemover*
-StoragePartitionHttpCacheDataRemover::CreateForURLsAndRange(
- content::StoragePartition* storage_partition,
- const base::Callback<bool(const GURL&)>& url_predicate,
- base::Time delete_begin,
- base::Time delete_end) {
- return new StoragePartitionHttpCacheDataRemover(
- url_predicate, delete_begin, delete_end,
- storage_partition->GetURLRequestContext(),
- storage_partition->GetMediaURLRequestContext());
-}
-
-void StoragePartitionHttpCacheDataRemover::Remove(
- const base::Closure& done_callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(!done_callback.is_null());
- done_callback_ = done_callback;
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(
- &StoragePartitionHttpCacheDataRemover::ClearHttpCacheOnIOThread,
- base::Unretained(this)));
-}
-
-void StoragePartitionHttpCacheDataRemover::Count(
- const net::Int64CompletionCallback& result_callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(!result_callback.is_null());
- result_callback_ = result_callback;
- calculation_result_ = 0;
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(
- &StoragePartitionHttpCacheDataRemover::CountHttpCacheOnIOThread,
- base::Unretained(this)));
-}
-
-void StoragePartitionHttpCacheDataRemover::ClearHttpCacheOnIOThread() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- next_cache_state_ = STATE_NONE;
- DCHECK_EQ(STATE_NONE, next_cache_state_);
- DCHECK(main_context_getter_.get());
- DCHECK(media_context_getter_.get());
-
- next_cache_state_ = STATE_CREATE_MAIN;
- DoClearCache(net::OK);
-}
-
-void StoragePartitionHttpCacheDataRemover::CountHttpCacheOnIOThread() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- next_cache_state_ = STATE_NONE;
- DCHECK_EQ(STATE_NONE, next_cache_state_);
- DCHECK(main_context_getter_.get());
- DCHECK(media_context_getter_.get());
-
- next_cache_state_ = STATE_CREATE_MAIN;
- DoCountCache(net::OK);
-}
-
-void StoragePartitionHttpCacheDataRemover::ClearedHttpCache() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- done_callback_.Run();
- base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
-}
-
-void StoragePartitionHttpCacheDataRemover::CountedHttpCache() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- result_callback_.Run(calculation_result_);
- base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
-}
-
-// The expected state sequence is STATE_NONE --> STATE_CREATE_MAIN -->
-// STATE_PROCESS_MAIN --> STATE_CREATE_MEDIA --> STATE_PROCESS_MEDIA -->
-// STATE_DONE, and any errors are ignored.
-void StoragePartitionHttpCacheDataRemover::DoClearCache(int rv) {
- DCHECK_NE(STATE_NONE, next_cache_state_);
-
- while (rv != net::ERR_IO_PENDING && next_cache_state_ != STATE_NONE) {
- switch (next_cache_state_) {
- case STATE_CREATE_MAIN:
- case STATE_CREATE_MEDIA: {
- // Get a pointer to the cache.
- net::URLRequestContextGetter* getter =
- (next_cache_state_ == STATE_CREATE_MAIN)
- ? main_context_getter_.get()
- : media_context_getter_.get();
- net::HttpCache* http_cache = getter->GetURLRequestContext()
- ->http_transaction_factory()
- ->GetCache();
-
- next_cache_state_ = (next_cache_state_ == STATE_CREATE_MAIN)
- ? STATE_PROCESS_MAIN
- : STATE_PROCESS_MEDIA;
-
- // Clear QUIC server information from memory and the disk cache.
- http_cache->GetSession()
- ->quic_stream_factory()
- ->ClearCachedStatesInCryptoConfig();
-
- // Clear SDCH dictionary state.
- net::SdchManager* sdch_manager =
- getter->GetURLRequestContext()->sdch_manager();
- // The test is probably overkill, since chrome should always have an
- // SdchManager. But in general the URLRequestContext is *not*
- // guaranteed to have an SdchManager, so checking is wise.
- if (sdch_manager)
- sdch_manager->ClearData();
-
- rv = http_cache->GetBackend(
- &cache_,
- base::Bind(&StoragePartitionHttpCacheDataRemover::DoClearCache,
- base::Unretained(this)));
- break;
- }
- case STATE_PROCESS_MAIN:
- case STATE_PROCESS_MEDIA: {
- next_cache_state_ = (next_cache_state_ == STATE_PROCESS_MAIN)
- ? STATE_CREATE_MEDIA
- : STATE_DONE;
-
- // |cache_| can be null if it cannot be initialized.
- if (cache_) {
- if (!url_predicate_.is_null()) {
- rv = (new ConditionalCacheDeletionHelper(
- cache_,
- ConditionalCacheDeletionHelper::CreateURLAndTimeCondition(
- url_predicate_,
- delete_begin_,
- delete_end_)))->DeleteAndDestroySelfWhenFinished(
- base::Bind(
- &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)));
- } else {
- rv = cache_->DoomEntriesBetween(
- delete_begin_, delete_end_,
- base::Bind(
- &StoragePartitionHttpCacheDataRemover::DoClearCache,
- base::Unretained(this)));
- }
- cache_ = NULL;
- }
- break;
- }
- case STATE_DONE: {
- cache_ = NULL;
- next_cache_state_ = STATE_NONE;
-
- // Notify the UI thread that we are done.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&StoragePartitionHttpCacheDataRemover::ClearedHttpCache,
- base::Unretained(this)));
- return;
- }
- default: {
- NOTREACHED() << "bad state";
- next_cache_state_ = STATE_NONE; // Stop looping.
- return;
- }
- }
- }
-}
-
-// The expected state sequence is STATE_NONE --> STATE_CREATE_MAIN -->
-// STATE_PROCESS_MAIN --> STATE_CREATE_MEDIA --> STATE_PROCESS_MEDIA -->
-// STATE_DONE. On error, we jump directly to STATE_DONE.
-void StoragePartitionHttpCacheDataRemover::DoCountCache(int rv) {
- DCHECK_NE(STATE_NONE, next_cache_state_);
-
- while (rv != net::ERR_IO_PENDING && next_cache_state_ != STATE_NONE) {
- // On error, finish and return the error code. A valid result value might
- // be of two types - either net::OK from the CREATE states, or the result
- // of calculation from the PROCESS states. Since net::OK == 0, it is valid
- // to simply add the value to the final calculation result.
- if (rv < 0) {
- calculation_result_ = rv;
- next_cache_state_ = STATE_DONE;
- } else {
- DCHECK_EQ(0, net::OK);
- calculation_result_ += rv;
- }
-
- switch (next_cache_state_) {
- case STATE_CREATE_MAIN:
- case STATE_CREATE_MEDIA: {
- // Get a pointer to the cache.
- net::URLRequestContextGetter* getter =
- (next_cache_state_ == STATE_CREATE_MAIN)
- ? main_context_getter_.get()
- : media_context_getter_.get();
- net::HttpCache* http_cache = getter->GetURLRequestContext()
- ->http_transaction_factory()
- ->GetCache();
-
- next_cache_state_ = (next_cache_state_ == STATE_CREATE_MAIN)
- ? STATE_PROCESS_MAIN
- : STATE_PROCESS_MEDIA;
-
- rv = http_cache->GetBackend(
- &cache_,
- base::Bind(&StoragePartitionHttpCacheDataRemover::DoCountCache,
- base::Unretained(this)));
- break;
- }
- case STATE_PROCESS_MAIN:
- case STATE_PROCESS_MEDIA: {
- next_cache_state_ = (next_cache_state_ == STATE_PROCESS_MAIN)
- ? STATE_CREATE_MEDIA
- : STATE_DONE;
-
- // |cache_| can be null if it cannot be initialized.
- if (cache_) {
- if (delete_begin_.is_null() && delete_end_.is_max()) {
- rv = cache_->CalculateSizeOfAllEntries(
- base::Bind(
- &StoragePartitionHttpCacheDataRemover::DoCountCache,
- base::Unretained(this)));
- } else {
- // TODO(msramek): Implement this when we need it.
- DoCountCache(net::ERR_NOT_IMPLEMENTED);
- }
- cache_ = NULL;
- }
- break;
- }
- case STATE_DONE: {
- cache_ = NULL;
- next_cache_state_ = STATE_NONE;
-
- // Notify the UI thread that we are done.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&StoragePartitionHttpCacheDataRemover::CountedHttpCache,
- base::Unretained(this)));
- return;
- }
- default: {
- NOTREACHED() << "bad state";
- next_cache_state_ = STATE_NONE; // Stop looping.
- return;
- }
- }
- }
-}
-
-} // namespace browsing_data
diff --git a/chromium/components/browsing_data/storage_partition_http_cache_data_remover.h b/chromium/components/browsing_data/storage_partition_http_cache_data_remover.h
deleted file mode 100644
index 41e0bcd7956..00000000000
--- a/chromium/components/browsing_data/storage_partition_http_cache_data_remover.h
+++ /dev/null
@@ -1,116 +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 COMPONENTS_BROWSING_DATA_STORAGE_PARTITION_HTTP_CACHE_DATA_REMOVER_H_
-#define COMPONENTS_BROWSING_DATA_STORAGE_PARTITION_HTTP_CACHE_DATA_REMOVER_H_
-
-#include <stdint.h>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/sequenced_task_runner_helpers.h"
-#include "base/time/time.h"
-#include "net/base/completion_callback.h"
-#include "url/gurl.h"
-
-namespace content {
-class StoragePartition;
-}
-
-namespace disk_cache {
-class Backend;
-}
-
-namespace net {
-class URLRequestContextGetter;
-}
-
-namespace browsing_data {
-
-// Helper to remove http cache data from a StoragePartition.
-class StoragePartitionHttpCacheDataRemover {
- public:
- // Creates a StoragePartitionHttpCacheDataRemover that deletes cache entries
- // in the time range between |delete_begin| (inclusively) and |delete_end|
- // (exclusively).
- static StoragePartitionHttpCacheDataRemover* CreateForRange(
- content::StoragePartition* storage_partition,
- base::Time delete_begin,
- base::Time delete_end);
-
- // Similar to CreateForRange(), but only deletes URLs that are matched by
- // |url_predicate|. Note that the deletion with URL filtering is not built in
- // to the cache interface and might be slower.
- static StoragePartitionHttpCacheDataRemover* CreateForURLsAndRange(
- content::StoragePartition* storage_partition,
- const base::Callback<bool(const GURL&)>& url_predicate,
- base::Time delete_begin,
- base::Time delete_end);
-
- // Calls |done_callback| upon completion and also destroys itself.
- void Remove(const base::Closure& done_callback);
-
- // Counts the total size of entries that would be removed by calling |Remove|.
- // Reports it via |result_callback| and then destroys itself.
- void Count(const net::Int64CompletionCallback& result_callback);
-
- private:
- enum CacheState {
- STATE_NONE,
- STATE_CREATE_MAIN,
- STATE_CREATE_MEDIA,
- STATE_PROCESS_MAIN,
- STATE_PROCESS_MEDIA,
- STATE_DONE
- };
-
- StoragePartitionHttpCacheDataRemover(
- base::Callback<bool(const GURL&)> url_predicate,
- base::Time delete_begin,
- base::Time delete_end,
- net::URLRequestContextGetter* main_context_getter,
- net::URLRequestContextGetter* media_context_getter);
-
- // StoragePartitionHttpCacheDataRemover deletes itself (using DeleteHelper)
- // and is not supposed to be deleted by other objects so make destructor
- // private and DeleteHelper a friend.
- friend class base::DeleteHelper<StoragePartitionHttpCacheDataRemover>;
-
- ~StoragePartitionHttpCacheDataRemover();
-
- void ClearHttpCacheOnIOThread();
- void CountHttpCacheOnIOThread();
-
- void ClearedHttpCache();
- void CountedHttpCache();
-
- // Performs the actual work to delete or count the cache.
- void DoClearCache(int rv);
- void DoCountCache(int rv);
-
- base::Callback<bool(const GURL&)> url_predicate_;
- const base::Time delete_begin_;
- const base::Time delete_end_;
-
- const scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
- const scoped_refptr<net::URLRequestContextGetter> media_context_getter_;
-
- base::Closure done_callback_;
- net::Int64CompletionCallback result_callback_;
-
- // IO.
- int next_cache_state_;
- disk_cache::Backend* cache_;
-
- // Stores the cache size computation result before it can be returned
- // via a callback. This is either the sum of size of the the two cache
- // backends, or an error code if the calculation failed.
- int64_t calculation_result_;
-
- DISALLOW_COPY_AND_ASSIGN(StoragePartitionHttpCacheDataRemover);
-};
-
-} // namespace browsing_data
-
-#endif // COMPONENTS_BROWSING_DATA_STORAGE_PARTITION_HTTP_CACHE_DATA_REMOVER_H_
diff --git a/chromium/components/browsing_data_strings.grdp b/chromium/components/browsing_data_strings.grdp
new file mode 100644
index 00000000000..ae7085509a0
--- /dev/null
+++ b/chromium/components/browsing_data_strings.grdp
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+
+ <!-- Clear Browsing Data counters-->
+ <message name="IDS_CLEAR_BROWSING_DATA_CALCULATING" desc="A text that is shown while the data volume is being counted.">
+ Calculating...
+ </message>
+ <message name="IDS_CLEAR_BROWSING_DATA_UNKNOWN_SIZE" desc="A text that is shown when the data volume could not be calculated. This string refers to uncountable objects, such as cache.">
+ unknown size
+ </message>
+ <message name="IDS_CLEAR_BROWSING_DATA_UNKNOWN_AMOUNT" desc="A text that is shown when the data volume could not be calculated. This string refers to countable objects, such as history entries or passwords.">
+ unknown amount
+ </message>
+ <message name="IDS_DEL_BROWSING_HISTORY_COUNTER" desc="A counter showing how many items of browsing history the user has.">
+ {COUNT, plural,
+ =0 {none}
+ =1 {1 item}
+ other {# items}}
+ </message>
+ <message name="IDS_DEL_BROWSING_HISTORY_COUNTER_SYNCED" desc="A counter showing the user how many local items of browsing history they have, and informing them that more items might be synced. In the case when COUNT is zero, the counter only mentions existence of synced items.">
+ {COUNT, plural,
+ =0 {at least 1 item on synced devices}
+ =1 {1 item (and more on synced devices)}
+ other {# items (and more on synced devices)}}
+ </message>
+ <message name="IDS_DEL_CACHE_COUNTER_UPPER_ESTIMATE" desc="A counter showing that the user has less than X megabytes of cache. The value X will be substituted.">
+ less than <ph name="UPPER_ESTIMATE">$1<ex>328 MB</ex></ph>
+ </message>
+ <message name="IDS_DEL_CACHE_COUNTER_ALMOST_EMPTY" desc="A counter showing that the user's cache is almost empty, having less than 1 MB of data.">
+ less than 1 MB
+ </message>
+ <message name="IDS_DEL_PASSWORDS_COUNTER" desc="A counter showing how many passwords the user has.">
+ {COUNT, plural,
+ =0 {none}
+ =1 {1}
+ other {#}}
+ </message>
+ <message name="IDS_DEL_AUTOFILL_COUNTER_EMPTY" desc="A counter showing that the user has no form data stored.">
+ none
+ </message>
+ <message name="IDS_DEL_AUTOFILL_COUNTER_CREDIT_CARDS" desc="A counter showing how many credit cards the user has.">
+ {COUNT, plural,
+ =1 {1 credit card}
+ other {# credit cards}}
+ </message>
+ <message name="IDS_DEL_AUTOFILL_COUNTER_ADDRESSES" desc="A counter showing how many addresses the user has.">
+ {COUNT, plural,
+ =1 {1 address}
+ other {# addresses}}
+ </message>
+ <message name="IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS" desc="A counter showing how many form autocompletion suggestions the user has.">
+ {COUNT, plural,
+ =1 {1 suggestion}
+ other {# suggestions}}
+ </message>
+ <message name="IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS_LONG" desc="A counter showing how many other form autocompletion suggestions the user has. Note that this message is shown at the end of an enumeration of form data types, such as '2 addresses, 5 others suggestions'.">
+ {COUNT, plural,
+ =1 {1 other suggestion}
+ other {# other suggestions}}
+ </message>
+ <message name="IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS_SHORT" desc="A counter showing how many other items of form data the user has. Note that this message is shown at the end of an enumeration of form data types, such as '3 credit cards, 2 addresses, 5 others'.">
+ {COUNT, plural,
+ =1 {1 other}
+ other {# others}}
+ </message>
+ <message name="IDS_DEL_AUTOFILL_COUNTER_TWO_TYPES" desc="A counter showing that the user has two types of form data. The types and their counts will be substituted, this message only provides the comma separator.">
+ <ph name="TYPE_1">$1<ex>2 credit cards</ex></ph>, <ph name="TYPE_2">$2<ex>1 address</ex></ph>
+ </message>
+ <message name="IDS_DEL_AUTOFILL_COUNTER_THREE_TYPES" desc="A counter showing that the user has three types of form data. The types and their counts will be substituted, this message only provides the comma separators.">
+ <ph name="TYPE_1">$1<ex>2 credit cards</ex></ph>, <ph name="TYPE_2">$2<ex>1 address</ex></ph>, <ph name="TYPE_3">$3<ex>5 others</ex></ph>
+ </message>
+ <message name="IDS_DEL_COOKIES_COUNTER" desc="A static message shown in the Clear Browsing Data dialog explaining to the user that deleting cookies and site data will result in the user being signed out of most websites.">
+ This will sign you out of most websites.
+ </message>
+ <message name="IDS_DEL_DOWNLOADS_COUNTER" desc="A counter showing how many items of downloads history the user has.">
+ {COUNT, plural,
+ =0 {none}
+ =1 {1 item}
+ other {# items}}
+ </message>
+ <message name="IDS_DEL_HOSTED_APPS_COUNTER" desc="A counter showing how many hosted apps the user has. We show the number of apps, and in the cases where there is one or two apps, we will also give two example app names, denoted as placeholders $1 and $2. If there are more than two apps, we will give two examples and say 'and X more'. The 'and X more' string, denoted by the placeholder $3, will be supplied from another message.">
+ {COUNT, plural,
+ =0 {none}
+ =1 {1 app ($1)}
+ =2 {2 apps ($1, $2)}
+ other {# apps ($1, $2, $3)}}
+ </message>
+ <message name="IDS_DEL_HOSTED_APPS_COUNTER_AND_X_MORE" desc="This message stands at the end of a sentence enumerating hosted apps the user has installed, e.g.: 'App1, App2, and 5 more'">
+ {COUNT, plural,
+ =1 {and 1 more}
+ other {and # more}}
+ </message>
+ <message name="IDS_DEL_MEDIA_LICENSES_COUNTER_GENERAL_COMMENT" desc="A static message shown in the Clear Browsing Data dialog explaining to the user that clearing media licenses will result in the user being unable to play some premium content">
+ You may lose access to premium content from some sites.
+ </message>
+ <message name="IDS_DEL_MEDIA_LICENSES_COUNTER_SITE_COMMENT" desc="A message shown in the Clear Browsing Data dialog explaining to the user that clearing media licenses will result in the user being unable to play some premium content from at least one specific web site">
+ You may lose access to premium content from <ph name="SITE">$1<ex>youtube.com</ex></ph> and some other sites.
+ </message>
+</grit-part> \ No newline at end of file
diff --git a/chromium/components/browsing_data_ui.gypi b/chromium/components/browsing_data_ui.gypi
deleted file mode 100644
index f7d10e0f6c3..00000000000
--- a/chromium/components/browsing_data_ui.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/browsing_data_ui
- 'target_name': 'browsing_data_ui',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- 'history_core_browser',
- 'sync_driver',
- 'version_info',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'browsing_data_ui/history_notice_utils.cc',
- 'browsing_data_ui/history_notice_utils.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/browsing_data_ui/BUILD.gn b/chromium/components/browsing_data_ui/BUILD.gn
deleted file mode 100644
index 241e32dfefc..00000000000
--- a/chromium/components/browsing_data_ui/BUILD.gn
+++ /dev/null
@@ -1,36 +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.
-
-static_library("browsing_data_ui") {
- sources = [
- "history_notice_utils.cc",
- "history_notice_utils.h",
- ]
-
- deps = [
- "//base",
- "//components/history/core/browser",
- "//components/sync_driver:sync_driver",
- "//components/version_info",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "history_notice_utils_unittest.cc",
- ]
-
- deps = [
- ":browsing_data_ui",
- "//base",
- "//components/history/core/test:test",
- "//components/signin/core/browser:test_support",
- "//components/sync_driver:test_support",
- "//components/version_info:version_info",
- "//net",
- "//sync/protocol:protocol",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/browsing_data_ui/DEPS b/chromium/components/browsing_data_ui/DEPS
deleted file mode 100644
index b798afdcd19..00000000000
--- a/chromium/components/browsing_data_ui/DEPS
+++ /dev/null
@@ -1,10 +0,0 @@
-include_rules = [
- "+components/browser_sync/browser",
- "+components/history/core/browser",
- "+components/history/core/test",
- "+components/signin",
- "+components/sync_driver",
- "+components/version_info",
- "+sync/internal_api/public",
- "+net",
-]
diff --git a/chromium/components/browsing_data_ui/OWNERS b/chromium/components/browsing_data_ui/OWNERS
deleted file mode 100644
index 9e7d1117d38..00000000000
--- a/chromium/components/browsing_data_ui/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-msarda@chromium.org
-msramek@chromium.org
diff --git a/chromium/components/browsing_data_ui/history_notice_utils.cc b/chromium/components/browsing_data_ui/history_notice_utils.cc
deleted file mode 100644
index dca2c14e15f..00000000000
--- a/chromium/components/browsing_data_ui/history_notice_utils.cc
+++ /dev/null
@@ -1,115 +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 "components/browsing_data_ui/history_notice_utils.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/history/core/browser/web_history_service.h"
-#include "components/sync_driver/sync_service.h"
-#include "components/version_info/version_info.h"
-
-namespace {
-
-// Merges several asynchronous boolean callbacks into one that returns a boolean
-// product of their responses. Deletes itself when done.
-class MergeBooleanCallbacks {
- public:
- // Constructor. Upon receiving |expected_call_count| calls to |RunCallback|,
- // |target_callback| will be run with the boolean product of their results.
- MergeBooleanCallbacks(
- int expected_call_count,
- const base::Callback<void(bool)>& target_callback)
- : expected_call_count_(expected_call_count),
- target_callback_(target_callback),
- final_response_(true),
- call_count_(0) {}
-
- // This method is to be bound to all asynchronous callbacks which we want
- // to merge.
- void RunCallback(bool response) {
- final_response_ &= response;
-
- if (++call_count_ < expected_call_count_)
- return;
-
- target_callback_.Run(final_response_);
- base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
- }
-
- private:
- int expected_call_count_;
- base::Callback<void(bool)> target_callback_;
- bool final_response_;
- int call_count_;
-};
-
-} // namespace
-
-namespace browsing_data_ui {
-
-namespace testing {
-
-bool g_override_other_forms_of_browsing_history_query = false;
-
-} // namespace testing
-
-void ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
- const sync_driver::SyncService* sync_service,
- history::WebHistoryService* history_service,
- base::Callback<void(bool)> callback) {
- if (!sync_service ||
- !sync_service->IsSyncActive() ||
- !sync_service->GetActiveDataTypes().Has(
- syncer::HISTORY_DELETE_DIRECTIVES) ||
- sync_service->IsUsingSecondaryPassphrase() ||
- !history_service) {
- callback.Run(false);
- return;
- }
-
- history_service->QueryWebAndAppActivity(callback);
-}
-
-void ShouldPopupDialogAboutOtherFormsOfBrowsingHistory(
- const sync_driver::SyncService* sync_service,
- history::WebHistoryService* history_service,
- version_info::Channel channel,
- base::Callback<void(bool)> callback) {
- // If the query for other forms of browsing history is overriden for testing,
- // the conditions are identical with
- // ShouldShowNoticeAboutOtherFormsOfBrowsingHistory.
- if (testing::g_override_other_forms_of_browsing_history_query) {
- ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
- sync_service, history_service, callback);
- return;
- }
-
- if (!sync_service ||
- !sync_service->IsSyncActive() ||
- !sync_service->GetActiveDataTypes().Has(
- syncer::HISTORY_DELETE_DIRECTIVES) ||
- sync_service->IsUsingSecondaryPassphrase() ||
- !history_service) {
- callback.Run(false);
- return;
- }
-
- // Return the boolean product of QueryWebAndAppActivity and
- // QueryOtherFormsOfBrowsingHistory. MergeBooleanCallbacks deletes itself
- // after processing both callbacks.
- MergeBooleanCallbacks* merger = new MergeBooleanCallbacks(2, callback);
- history_service->QueryWebAndAppActivity(base::Bind(
- &MergeBooleanCallbacks::RunCallback, base::Unretained(merger)));
- history_service->QueryOtherFormsOfBrowsingHistory(
- channel,
- base::Bind(
- &MergeBooleanCallbacks::RunCallback, base::Unretained(merger)));
-}
-
-} // namespace browsing_data_ui
diff --git a/chromium/components/browsing_data_ui/history_notice_utils.h b/chromium/components/browsing_data_ui/history_notice_utils.h
deleted file mode 100644
index bd3242e4477..00000000000
--- a/chromium/components/browsing_data_ui/history_notice_utils.h
+++ /dev/null
@@ -1,58 +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 COMPONENTS_BROWSING_DATA_UI_HISTORY_NOTICE_UTILS_H_
-#define COMPONENTS_BROWSING_DATA_UI_HISTORY_NOTICE_UTILS_H_
-
-#include <string>
-
-#include "base/callback_forward.h"
-
-namespace history {
-class WebHistoryService;
-}
-
-namespace sync_driver {
-class SyncService;
-}
-
-namespace version_info {
-enum class Channel;
-}
-
-namespace browsing_data_ui {
-
-namespace testing {
-
-// TODO(crbug.com/595332): A boolean flag indicating that
-// ShouldShowNoticeAboutOtherFormsOfBrowsingHistory() should skip the query
-// for other forms of browsing history and just assume some such forms were
-// found. Used only for testing. The default is false.
-extern bool g_override_other_forms_of_browsing_history_query;
-
-} // testing
-
-// Whether the Clear Browsing Data UI should show a notice about the existence
-// of other forms of browsing history stored in user's account. The response
-// is returned in a |callback|.
-void ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
- const sync_driver::SyncService* sync_service,
- history::WebHistoryService* history_service,
- base::Callback<void(bool)> callback);
-
-// Whether the Clear Browsing Data UI should popup a dialog with information
-// about the existence of other forms of browsing history stored in user's
-// account when the user deletes their browsing history for the first time.
-// The response is returned in a |callback|. The |channel| parameter
-// must be provided for successful communication with the Sync server, but
-// the result does not depend on it.
-void ShouldPopupDialogAboutOtherFormsOfBrowsingHistory(
- const sync_driver::SyncService* sync_service,
- history::WebHistoryService* history_service,
- version_info::Channel channel,
- base::Callback<void(bool)> callback);
-
-} // namespace browsing_data_ui
-
-#endif // COMPONENTS_BROWSING_DATA_UI_HISTORY_NOTICE_UTILS_H_
diff --git a/chromium/components/browsing_data_ui/history_notice_utils_unittest.cc b/chromium/components/browsing_data_ui/history_notice_utils_unittest.cc
deleted file mode 100644
index 725a308029f..00000000000
--- a/chromium/components/browsing_data_ui/history_notice_utils_unittest.cc
+++ /dev/null
@@ -1,187 +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 "components/browsing_data_ui/history_notice_utils.h"
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "components/history/core/test/fake_web_history_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
-#include "components/signin/core/browser/test_signin_client.h"
-#include "components/sync_driver/fake_sync_service.h"
-#include "components/version_info/version_info.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/url_request_test_util.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace browsing_data_ui {
-
-namespace {
-
-class TestSyncService : public sync_driver::FakeSyncService {
- public:
- // Getters (FakeSyncService implementation). ---------------------------------
- bool IsSyncActive() const override {
- return sync_active_;
- }
-
- syncer::ModelTypeSet GetActiveDataTypes() const override {
- return active_data_types_;
- }
-
- bool IsUsingSecondaryPassphrase() const override {
- return using_secondary_passphrase_;
- }
-
- // Setters. ------------------------------------------------------------------
- void set_sync_active(bool active) {
- sync_active_ = active;
- }
-
- void set_active_data_types(syncer::ModelTypeSet data_types) {
- active_data_types_ = data_types;
- }
-
- void set_using_secondary_passphrase(bool passphrase) {
- using_secondary_passphrase_ = passphrase;
- }
-
- private:
- syncer::ModelTypeSet active_data_types_;
- bool using_secondary_passphrase_ = false;
- bool sync_active_ = false;
-};
-
-} // namespace
-
-
-class HistoryNoticeUtilsTest : public ::testing::Test {
- public:
- HistoryNoticeUtilsTest()
- : signin_client_(nullptr),
- signin_manager_(&signin_client_, &account_tracker_) {
- }
-
- void SetUp() override {
- sync_service_.reset(new TestSyncService());
- history_service_.reset(new history::FakeWebHistoryService(
- &oauth2_token_service_,
- &signin_manager_,
- url_request_context_));
- history_service_->SetupFakeResponse(true /* success */, net::HTTP_OK);
- }
-
- TestSyncService* sync_service() {
- return sync_service_.get();
- }
-
- history::FakeWebHistoryService* history_service() {
- return history_service_.get();
- }
-
- void ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(
- bool expected_test_case_result) {
- bool got_result = false;
-
- ShouldPopupDialogAboutOtherFormsOfBrowsingHistory(
- sync_service_.get(),
- history_service_.get(),
- version_info::Channel::STABLE,
- base::Bind(
- &HistoryNoticeUtilsTest::Callback,
- base::Unretained(this),
- base::Unretained(&got_result)));
-
- if (!got_result) {
- run_loop_.reset(new base::RunLoop());
- run_loop_->Run();
- }
-
- // Process the DeleteSoon() called on MergeBooleanCallbacks, otherwise
- // this it will be considered to be leaked.
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(expected_test_case_result, result_);
- }
-
- private:
- void Callback(bool* got_result, bool result) {
- *got_result = true;
- result_ = result;
-
- if (run_loop_)
- run_loop_->Quit();
- }
-
- FakeProfileOAuth2TokenService oauth2_token_service_;
- AccountTrackerService account_tracker_;
- TestSigninClient signin_client_;
- FakeSigninManagerBase signin_manager_;
- scoped_refptr<net::URLRequestContextGetter> url_request_context_;
- std::unique_ptr<TestSyncService> sync_service_;
- std::unique_ptr<history::FakeWebHistoryService> history_service_;
-
- std::unique_ptr<base::RunLoop> run_loop_;
- bool result_;
-
- base::MessageLoop message_loop_;
-};
-
-TEST_F(HistoryNoticeUtilsTest, NotSyncing) {
- ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
-}
-
-TEST_F(HistoryNoticeUtilsTest, SyncingWithWrongParameters) {
- sync_service()->set_sync_active(true);
-
- // Regardless of the state of the web history...
- history_service()->SetWebAndAppActivityEnabled(true);
- history_service()->SetOtherFormsOfBrowsingHistoryPresent(true);
-
- // ...the response is false if there's custom passphrase...
- sync_service()->set_active_data_types(syncer::ModelTypeSet::All());
- sync_service()->set_using_secondary_passphrase(true);
- ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
-
- // ...or even if there's no custom passphrase, but we're not syncing history.
- syncer::ModelTypeSet only_passwords(syncer::PASSWORDS);
- sync_service()->set_active_data_types(only_passwords);
- sync_service()->set_using_secondary_passphrase(false);
- ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
-}
-
-TEST_F(HistoryNoticeUtilsTest, WebHistoryStates) {
- // If history Sync is active...
- sync_service()->set_sync_active(true);
- sync_service()->set_active_data_types(syncer::ModelTypeSet::All());
-
- // ...the result is true if both web history queries return true...
- history_service()->SetWebAndAppActivityEnabled(true);
- history_service()->SetOtherFormsOfBrowsingHistoryPresent(true);
- ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(true);
-
- // ...but not otherwise.
- history_service()->SetOtherFormsOfBrowsingHistoryPresent(false);
- ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
- history_service()->SetWebAndAppActivityEnabled(false);
- ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
- history_service()->SetOtherFormsOfBrowsingHistoryPresent(true);
- ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
-
- // Invalid responses from the web history are interpreted as false.
- history_service()->SetWebAndAppActivityEnabled(true);
- history_service()->SetOtherFormsOfBrowsingHistoryPresent(true);
- history_service()->SetupFakeResponse(true, net::HTTP_INTERNAL_SERVER_ERROR);
- ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
- history_service()->SetupFakeResponse(false, net::HTTP_OK);
- ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(false);
-}
-
-} // namespace browsing_data_ui
diff --git a/chromium/components/bubble.gypi b/chromium/components/bubble.gypi
deleted file mode 100644
index 76cf9370a60..00000000000
--- a/chromium/components/bubble.gypi
+++ /dev/null
@@ -1,43 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/bubble
- 'target_name': 'bubble',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'bubble/bubble_close_reason.h',
- 'bubble/bubble_controller.cc',
- 'bubble/bubble_controller.h',
- 'bubble/bubble_delegate.cc',
- 'bubble/bubble_delegate.h',
- 'bubble/bubble_manager.cc',
- 'bubble/bubble_manager.h',
- 'bubble/bubble_reference.h',
- 'bubble/bubble_ui.h',
- ],
- },
- {
- 'target_name': 'bubble_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../testing/gmock.gyp:gmock',
- 'bubble',
- ],
- 'sources': [
- 'bubble/bubble_manager_mocks.cc',
- 'bubble/bubble_manager_mocks.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/bubble/BUILD.gn b/chromium/components/bubble/BUILD.gn
index 912dbad71a0..b9e66327d06 100644
--- a/chromium/components/bubble/BUILD.gn
+++ b/chromium/components/bubble/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("bubble") {
+static_library("bubble") {
sources = [
"bubble_close_reason.h",
"bubble_controller.cc",
@@ -20,7 +20,7 @@ source_set("bubble") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
diff --git a/chromium/components/bubble/bubble_manager.cc b/chromium/components/bubble/bubble_manager.cc
index a4b48351a06..dc94dc25fb7 100644
--- a/chromium/components/bubble/bubble_manager.cc
+++ b/chromium/components/bubble/bubble_manager.cc
@@ -67,7 +67,7 @@ void BubbleManager::UpdateAllBubbleAnchors() {
// Guard against bubbles being added or removed while iterating the bubbles.
ManagerState original_state = manager_state_;
manager_state_ = ITERATING_BUBBLES;
- for (auto controller : controllers_)
+ for (auto* controller : controllers_)
controller->UpdateAnchorPosition();
manager_state_ = original_state;
}
@@ -122,7 +122,7 @@ bool BubbleManager::CloseAllMatchingBubbles(
}
manager_state_ = original_state;
- for (auto controller : close_queue) {
+ for (auto* controller : close_queue) {
controller->DoClose(reason);
FOR_EACH_OBSERVER(BubbleManagerObserver, observers_,
diff --git a/chromium/components/captive_portal.gypi b/chromium/components/captive_portal.gypi
deleted file mode 100644
index 5525bb00bc2..00000000000
--- a/chromium/components/captive_portal.gypi
+++ /dev/null
@@ -1,48 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/captive_portal
- 'target_name': 'captive_portal',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'CAPTIVE_PORTAL_IMPLEMENTATION',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'captive_portal/captive_portal_detector.cc',
- 'captive_portal/captive_portal_detector.h',
- 'captive_portal/captive_portal_export.h',
- 'captive_portal/captive_portal_types.cc',
- 'captive_portal/captive_portal_types.h',
- ],
- },
- {
- # GN version: //components/captive_portal:test_support
- 'target_name': 'captive_portal_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'captive_portal',
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'captive_portal/captive_portal_testing_utils.cc',
- 'captive_portal/captive_portal_testing_utils.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/captive_portal/BUILD.gn b/chromium/components/captive_portal/BUILD.gn
index 3d77291c697..c534db82a07 100644
--- a/chromium/components/captive_portal/BUILD.gn
+++ b/chromium/components/captive_portal/BUILD.gn
@@ -20,7 +20,7 @@ component("captive_portal") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"captive_portal_testing_utils.cc",
diff --git a/chromium/components/cast_certificate.gypi b/chromium/components/cast_certificate.gypi
deleted file mode 100644
index dc5f8e6d1fe..00000000000
--- a/chromium/components/cast_certificate.gypi
+++ /dev/null
@@ -1,42 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'cast_certificate',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- ],
- 'sources': [
- 'cast_certificate/cast_cert_validator.cc',
- 'cast_certificate/cast_cert_validator.h',
- 'cast_certificate/cast_root_ca_cert_der-inc.h',
- 'cast_certificate/eureka_root_ca_der-inc.h',
- ],
- },
- {
- 'target_name': 'cast_certificate_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../testing/gtest.gyp:gtest',
- 'cast_certificate',
- ],
- 'sources': [
- 'cast_certificate/cast_cert_validator_test_helpers.cc',
- 'cast_certificate/cast_cert_validator_test_helpers.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/cast_certificate/BUILD.gn b/chromium/components/cast_certificate/BUILD.gn
index 7e53f203f68..19ac0d72d2e 100644
--- a/chromium/components/cast_certificate/BUILD.gn
+++ b/chromium/components/cast_certificate/BUILD.gn
@@ -2,20 +2,23 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("cast_certificate") {
+static_library("cast_certificate") {
sources = [
"cast_cert_validator.cc",
"cast_cert_validator.h",
+ "cast_crl.cc",
+ "cast_crl.h",
"cast_root_ca_cert_der-inc.h",
"eureka_root_ca_der-inc.h",
]
deps = [
"//base",
+ "//components/cast_certificate/proto",
"//net",
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"cast_cert_validator_test_helpers.cc",
@@ -33,11 +36,13 @@ source_set("unit_tests") {
testonly = true
sources = [
"cast_cert_validator_unittest.cc",
+ "cast_crl_unittest.cc",
]
deps = [
":cast_certificate",
":test_support",
"//base",
+ "//components/cast_certificate/proto:unittest_proto",
"//net",
"//testing/gtest",
]
diff --git a/chromium/components/cast_certificate/DEPS b/chromium/components/cast_certificate/DEPS
index 8fa9d48d882..12af900d0c5 100644
--- a/chromium/components/cast_certificate/DEPS
+++ b/chromium/components/cast_certificate/DEPS
@@ -1,3 +1,4 @@
include_rules = [
+ "+crypto",
"+net",
]
diff --git a/chromium/components/cast_certificate/cast_cert_validator.cc b/chromium/components/cast_certificate/cast_cert_validator.cc
index 6a81c84d562..5cbf9bf896f 100644
--- a/chromium/components/cast_certificate/cast_cert_validator.cc
+++ b/chromium/components/cast_certificate/cast_cert_validator.cc
@@ -13,16 +13,19 @@
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
+#include "net/cert/internal/cert_issuer_source_static.h"
+#include "components/cast_certificate/cast_crl.h"
#include "net/cert/internal/certificate_policies.h"
#include "net/cert/internal/extended_key_usage.h"
#include "net/cert/internal/parse_certificate.h"
#include "net/cert/internal/parse_name.h"
#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/path_builder.h"
#include "net/cert/internal/signature_algorithm.h"
#include "net/cert/internal/signature_policy.h"
-#include "net/cert/internal/trust_store.h"
-#include "net/cert/internal/verify_certificate_chain.h"
+#include "net/cert/internal/trust_store_in_memory.h"
#include "net/cert/internal/verify_signed_data.h"
+#include "net/der/encode_values.h"
#include "net/der/input.h"
namespace cast_certificate {
@@ -64,15 +67,18 @@ class CastTrustStore {
// storage.
template <size_t N>
void AddAnchor(const uint8_t (&data)[N]) {
- scoped_refptr<net::ParsedCertificate> root =
- net::ParsedCertificate::CreateFromCertificateData(
- data, N, net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE,
- {});
- CHECK(root);
- store_.AddTrustedCertificate(std::move(root));
+ net::CertErrors errors;
+ scoped_refptr<net::ParsedCertificate> cert =
+ net::ParsedCertificate::CreateWithoutCopyingUnsafe(data, N, {},
+ &errors);
+ CHECK(cert) << errors.ToDebugString();
+ // Enforce pathlen constraints and policies defined on the root certificate.
+ scoped_refptr<net::TrustAnchor> anchor =
+ net::TrustAnchor::CreateFromCertificateWithConstraints(std::move(cert));
+ store_.AddTrustAnchor(std::move(anchor));
}
- net::TrustStore store_;
+ net::TrustStoreInMemory store_;
DISALLOW_COPY_AND_ASSIGN(CastTrustStore);
};
@@ -110,7 +116,7 @@ net::der::Input AudioOnlyPolicyOid() {
// * Hashes: All SHA hashes including SHA-1 (despite being known weak).
// * RSA keys must have a modulus at least 2048-bits long.
std::unique_ptr<net::SignaturePolicy> CreateCastSignaturePolicy() {
- return base::WrapUnique(new net::SimpleSignaturePolicy(2048));
+ return base::MakeUnique<net::SimpleSignaturePolicy>(2048);
}
class CertVerificationContextImpl : public CertVerificationContext {
@@ -133,10 +139,11 @@ class CertVerificationContextImpl : public CertVerificationContext {
// least 2048-bits long.
auto signature_policy = CreateCastSignaturePolicy();
+ net::CertErrors errors;
return net::VerifySignedData(
*signature_algorithm, net::der::Input(data),
net::der::BitString(net::der::Input(signature), 0),
- net::der::Input(&spki_), signature_policy.get());
+ net::der::Input(&spki_), signature_policy.get(), &errors);
}
std::string GetCommonName() const override { return common_name_; }
@@ -232,33 +239,6 @@ WARN_UNUSED_RESULT bool CheckTargetCertificate(
return true;
}
-// Converts a base::Time::Exploded to a net::der::GeneralizedTime.
-net::der::GeneralizedTime ConvertExplodedTime(
- const base::Time::Exploded& exploded) {
- net::der::GeneralizedTime result;
- result.year = exploded.year;
- result.month = exploded.month;
- result.day = exploded.day_of_month;
- result.hours = exploded.hour;
- result.minutes = exploded.minute;
- result.seconds = exploded.second;
- return result;
-}
-
-class ScopedCheckUnreferencedCerts {
- public:
- explicit ScopedCheckUnreferencedCerts(
- std::vector<scoped_refptr<net::ParsedCertificate>>* certs)
- : certs_(certs) {}
- ~ScopedCheckUnreferencedCerts() {
- for (const auto& cert : *certs_)
- DCHECK(cert->HasOneRef());
- }
-
- private:
- std::vector<scoped_refptr<net::ParsedCertificate>>* certs_;
-};
-
// Returns the parsing options used for Cast certificates.
net::ParseCertificateOptions GetCertParsingOptions() {
net::ParseCertificateOptions options;
@@ -275,63 +255,100 @@ net::ParseCertificateOptions GetCertParsingOptions() {
return options;
}
-} // namespace
-
+// Verifies a cast device certificate given a chain of DER-encoded certificates.
bool VerifyDeviceCert(const std::vector<std::string>& certs,
- const base::Time::Exploded& time,
+ const base::Time& time,
std::unique_ptr<CertVerificationContext>* context,
- CastDeviceCertPolicy* policy) {
- // The underlying verification function expects a sequence of
- // ParsedCertificate.
- std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
- // Verify that nothing saves a reference to the input certs, since the backing
- // data will go out of scope when the function finishes.
- ScopedCheckUnreferencedCerts ref_checker(&input_chain);
-
- for (const auto& cert_der : certs) {
- // No reference to the ParsedCertificate is kept past the end of this
- // function, so using EXTERNAL_REFERENCE here is safe.
- if (!net::ParsedCertificate::CreateAndAddToVector(
- reinterpret_cast<const uint8_t*>(cert_der.data()), cert_der.size(),
- net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE,
- GetCertParsingOptions(), &input_chain)) {
+ CastDeviceCertPolicy* policy,
+ const CastCRL* crl,
+ CRLPolicy crl_policy,
+ net::TrustStore* trust_store) {
+ if (certs.empty())
+ return false;
+
+ net::CertErrors errors;
+ scoped_refptr<net::ParsedCertificate> target_cert;
+ net::CertIssuerSourceStatic intermediate_cert_issuer_source;
+ for (size_t i = 0; i < certs.size(); ++i) {
+ scoped_refptr<net::ParsedCertificate> cert(net::ParsedCertificate::Create(
+ certs[i], GetCertParsingOptions(), &errors));
+ // TODO(eroman): Propagate/log these parsing errors.
+ if (!cert)
return false;
- }
+
+ if (i == 0)
+ target_cert = std::move(cert);
+ else
+ intermediate_cert_issuer_source.AddCert(std::move(cert));
}
// Use a signature policy compatible with Cast's PKI.
auto signature_policy = CreateCastSignaturePolicy();
- // Do RFC 5280 compatible certificate verification using the two Cast
- // trust anchors and Cast signature policy.
- if (!net::VerifyCertificateChain(input_chain, CastTrustStore::Get(),
- signature_policy.get(),
- ConvertExplodedTime(time), nullptr)) {
+ // Do path building and RFC 5280 compatible certificate verification using the
+ // two Cast trust anchors and Cast signature policy.
+ net::der::GeneralizedTime verification_time;
+ if (!net::der::EncodeTimeAsGeneralizedTime(time, &verification_time))
+ return false;
+ net::CertPathBuilder::Result result;
+ net::CertPathBuilder path_builder(target_cert.get(), trust_store,
+ signature_policy.get(), verification_time,
+ &result);
+ path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
+ net::CompletionStatus rv = path_builder.Run(base::Closure());
+ DCHECK_EQ(rv, net::CompletionStatus::SYNC);
+ if (!result.HasValidPath()) {
+ // TODO(crbug.com/634443): Log error information.
return false;
}
// Check properties of the leaf certificate (key usage, policy), and construct
// a CertVerificationContext that uses its public key.
- return CheckTargetCertificate(input_chain[0].get(), context, policy);
+ if (!CheckTargetCertificate(target_cert.get(), context, policy))
+ return false;
+
+ // Check if a CRL is available.
+ if (!crl) {
+ if (crl_policy == CRLPolicy::CRL_REQUIRED) {
+ return false;
+ }
+ } else {
+ if (!crl->CheckRevocation(result.GetBestValidPath()->path, time)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+bool VerifyDeviceCert(const std::vector<std::string>& certs,
+ const base::Time& time,
+ std::unique_ptr<CertVerificationContext>* context,
+ CastDeviceCertPolicy* policy,
+ const CastCRL* crl,
+ CRLPolicy crl_policy) {
+ return VerifyDeviceCert(certs, time, context, policy, crl, crl_policy,
+ &CastTrustStore::Get());
+}
+
+bool VerifyDeviceCertForTest(const std::vector<std::string>& certs,
+ const base::Time& time,
+ std::unique_ptr<CertVerificationContext>* context,
+ CastDeviceCertPolicy* policy,
+ const CastCRL* crl,
+ CRLPolicy crl_policy,
+ net::TrustStore* trust_store) {
+ return VerifyDeviceCert(certs, time, context, policy, crl, crl_policy,
+ trust_store);
}
std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest(
const base::StringPiece& spki) {
// Use a bogus CommonName, since this is just exposed for testing signature
// verification by unittests.
- return base::WrapUnique(
- new CertVerificationContextImpl(net::der::Input(spki), "CommonName"));
-}
-
-bool AddTrustAnchorForTest(const uint8_t* data, size_t length) {
- scoped_refptr<net::ParsedCertificate> anchor(
- net::ParsedCertificate::CreateFromCertificateData(
- data, length, net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE,
- GetCertParsingOptions()));
- if (!anchor)
- return false;
- CastTrustStore::Get().AddTrustedCertificate(std::move(anchor));
- return true;
+ return base::MakeUnique<CertVerificationContextImpl>(net::der::Input(spki),
+ "CommonName");
}
} // namespace cast_certificate
diff --git a/chromium/components/cast_certificate/cast_cert_validator.h b/chromium/components/cast_certificate/cast_cert_validator.h
index 1c335ae6530..a918dd58207 100644
--- a/chromium/components/cast_certificate/cast_cert_validator.h
+++ b/chromium/components/cast_certificate/cast_cert_validator.h
@@ -14,8 +14,13 @@
#include "base/strings/string_piece.h"
#include "base/time/time.h"
+namespace net {
+class TrustStore;
+}
namespace cast_certificate {
+class CastCRL;
+
// Describes the policy for a Device certificate.
enum class CastDeviceCertPolicy {
// The device certificate is unrestricted.
@@ -25,6 +30,14 @@ enum class CastDeviceCertPolicy {
AUDIO_ONLY,
};
+enum class CRLPolicy {
+ // Revocation is only checked if a CRL is provided.
+ CRL_OPTIONAL,
+
+ // Revocation is always checked. A missing CRL results in failure.
+ CRL_REQUIRED,
+};
+
// An object of this type is returned by the VerifyDeviceCert function, and can
// be used for additional certificate-related operations, using the verified
// certificate.
@@ -49,18 +62,26 @@ class CertVerificationContext {
DISALLOW_COPY_AND_ASSIGN(CertVerificationContext);
};
-// Verifies a cast device certficate given a chain of DER-encoded certificates.
+// Verifies a cast device certficate given a chain of DER-encoded certificates,
+// using the built-in Cast trust anchors.
//
// Inputs:
//
// * |certs| is a chain of DER-encoded certificates:
-// * |certs[0]| is the target certificate (i.e. the device certificate)
-// * |certs[i]| is the certificate that issued certs[i-1]
-// * |certs.back()| must be signed by a trust anchor
+// * |certs[0]| is the target certificate (i.e. the device certificate).
+// * |certs[1..n-1]| are intermediates certificates to use in path building.
+// Their ordering does not matter.
//
-// * |time| is the UTC time to use for determining if the certificate
+// * |time| is the unix timestamp to use for determining if the certificate
// is expired.
//
+// * |crl| is the CRL to check for certificate revocation status.
+// If this is a nullptr, then revocation checking is currently disabled.
+//
+// * |crl_options| is for choosing how to handle the absence of a CRL.
+// If crl_required is set to true, then an empty |crl| input would result
+// in a failed verification. Otherwise, |crl| is ignored if it is absent.
+//
// Outputs:
//
// Returns true on success, false on failure. On success the output
@@ -72,9 +93,23 @@ class CertVerificationContext {
// * |policy| is filled with an indication of the device certificate's policy
// (i.e. is it for audio-only devices or is it unrestricted?)
bool VerifyDeviceCert(const std::vector<std::string>& certs,
- const base::Time::Exploded& time,
+ const base::Time& time,
std::unique_ptr<CertVerificationContext>* context,
- CastDeviceCertPolicy* policy) WARN_UNUSED_RESULT;
+ CastDeviceCertPolicy* policy,
+ const CastCRL* crl,
+ CRLPolicy crl_policy) WARN_UNUSED_RESULT;
+
+// Exposed only for testing, not for use in production code.
+//
+// This is an overloaded version of VerifyDeviceCert that allows
+// the input of a custom TrustStore.
+bool VerifyDeviceCertForTest(const std::vector<std::string>& certs,
+ const base::Time& time,
+ std::unique_ptr<CertVerificationContext>* context,
+ CastDeviceCertPolicy* policy,
+ const CastCRL* crl,
+ CRLPolicy crl_policy,
+ net::TrustStore* trust_store) WARN_UNUSED_RESULT;
// Exposed only for unit-tests, not for use in production code.
// Production code would get a context from VerifyDeviceCert().
@@ -84,16 +119,6 @@ bool VerifyDeviceCert(const std::vector<std::string>& certs,
std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest(
const base::StringPiece& spki);
-// Exposed only for testing, not for use in production code.
-//
-// Injects trusted root certificates into the CastTrustStore.
-// |data| must remain valid and not be mutated throughout the lifetime of
-// the program.
-// Warning: Using this function concurrently with VerifyDeviceCert()
-// is not thread safe.
-bool AddTrustAnchorForTest(const uint8_t* data,
- size_t length) WARN_UNUSED_RESULT;
-
} // namespace cast_certificate
#endif // COMPONENTS_CAST_CERTIFICATE_CAST_CERT_VALIDATOR_H_
diff --git a/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc b/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc
index 78c092b1e6e..a854abd8c18 100644
--- a/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc
+++ b/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc
@@ -13,10 +13,6 @@ namespace cast_certificate {
namespace testing {
-namespace {
-
-// Reads a file from the test data directory
-// (//src/components/test/data/cast_certificate)
std::string ReadTestFileToString(const base::StringPiece& file_name) {
base::FilePath filepath;
PathService::Get(base::DIR_SOURCE_ROOT, &filepath);
@@ -36,8 +32,6 @@ std::string ReadTestFileToString(const base::StringPiece& file_name) {
return file_data;
}
-} // namespace
-
std::vector<std::string> ReadCertificateChainFromFile(
const base::StringPiece& file_name) {
std::string file_data = ReadTestFileToString(file_name);
diff --git a/chromium/components/cast_certificate/cast_cert_validator_test_helpers.h b/chromium/components/cast_certificate/cast_cert_validator_test_helpers.h
index d5281a70707..72cb5034a19 100644
--- a/chromium/components/cast_certificate/cast_cert_validator_test_helpers.h
+++ b/chromium/components/cast_certificate/cast_cert_validator_test_helpers.h
@@ -35,6 +35,10 @@ struct SignatureTestData {
// |file_name| should be relative to //components/test/data/cast_certificate
SignatureTestData ReadSignatureTestData(const base::StringPiece& file_name);
+// Reads a file from the test data directory
+// (//src/components/test/data/cast_certificate)
+std::string ReadTestFileToString(const base::StringPiece& file_name);
+
} // namespace testing
} // namespace cast_certificate
diff --git a/chromium/components/cast_certificate/cast_cert_validator_unittest.cc b/chromium/components/cast_certificate/cast_cert_validator_unittest.cc
index e363a1d47c8..a12f6da571d 100644
--- a/chromium/components/cast_certificate/cast_cert_validator_unittest.cc
+++ b/chromium/components/cast_certificate/cast_cert_validator_unittest.cc
@@ -5,6 +5,9 @@
#include "components/cast_certificate/cast_cert_validator.h"
#include "components/cast_certificate/cast_cert_validator_test_helpers.h"
+#include "net/cert/internal/cert_errors.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/trust_store_in_memory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cast_certificate {
@@ -23,6 +26,24 @@ enum TestResult {
RESULT_FAIL,
};
+enum TrustStoreDependency {
+ // Uses the built-in trust store for Cast. This is how certificates are
+ // verified in production.
+ TRUST_STORE_BUILTIN,
+
+ // Instead of using the built-in trust store, use root certificate in the
+ // provided test chain as the trust anchor.
+ //
+ // This trust anchor is initialized with anchor constraints, similar to how
+ // TrustAnchors in the built-in store are setup.
+ TRUST_STORE_FROM_TEST_FILE,
+
+ // This is the same as TRUST_STORE_FROM_TEST_FILE except the TrustAnchor is
+ // setup to NOT enforce anchor constraints. This mode is useful for
+ // verifying control groups. It is not how code works in production.
+ TRUST_STORE_FROM_TEST_FILE_UNCONSTRAINED,
+};
+
// Reads a test chain from |certs_file_name|, and asserts that verifying it as
// a Cast device certificate yields |expected_result|.
//
@@ -32,6 +53,8 @@ enum TestResult {
// * |expected_policy| - The policy that should have been identified for the
// device certificate.
// * |time| - The timestamp to use when verifying the certificate.
+// * |trust_store_dependency| - Which trust store to use when verifying (see
+// enum's definition).
// * |optional_signed_data_file_name| - optional path to a PEM file containing
// a valid signature generated by the device certificate.
//
@@ -39,14 +62,62 @@ void RunTest(TestResult expected_result,
const std::string& expected_common_name,
CastDeviceCertPolicy expected_policy,
const std::string& certs_file_name,
- const base::Time::Exploded& time,
+ const base::Time& time,
+ TrustStoreDependency trust_store_dependency,
const std::string& optional_signed_data_file_name) {
auto certs =
cast_certificate::testing::ReadCertificateChainFromFile(certs_file_name);
+ std::unique_ptr<net::TrustStoreInMemory> trust_store;
+
+ switch (trust_store_dependency) {
+ case TRUST_STORE_BUILTIN:
+ // Leave trust_store as nullptr.
+ break;
+
+ case TRUST_STORE_FROM_TEST_FILE:
+ case TRUST_STORE_FROM_TEST_FILE_UNCONSTRAINED: {
+ ASSERT_FALSE(certs.empty());
+
+ // Parse the root certificate of the chain.
+ net::CertErrors errors;
+ scoped_refptr<net::ParsedCertificate> root =
+ net::ParsedCertificate::Create(certs.back(), {}, &errors);
+ ASSERT_TRUE(root) << errors.ToDebugString();
+
+ // Remove it from the chain.
+ certs.pop_back();
+
+ // Add it to the trust store as a trust anchor
+ trust_store.reset(new net::TrustStoreInMemory);
+
+ if (trust_store_dependency == TRUST_STORE_FROM_TEST_FILE_UNCONSTRAINED) {
+ // This is a test-only mode where anchor constraints are not enforced.
+ trust_store->AddTrustAnchor(
+ net::TrustAnchor::CreateFromCertificateNoConstraints(
+ std::move(root)));
+ } else {
+ // This is the regular mode used by the TrustAnchors for the built-in
+ // Cast store.
+ trust_store->AddTrustAnchor(
+ net::TrustAnchor::CreateFromCertificateWithConstraints(
+ std::move(root)));
+ }
+ }
+ }
+
std::unique_ptr<CertVerificationContext> context;
CastDeviceCertPolicy policy;
- bool result = VerifyDeviceCert(certs, time, &context, &policy);
+
+ bool result;
+ if (trust_store.get()) {
+ result =
+ VerifyDeviceCertForTest(certs, time, &context, &policy, nullptr,
+ CRLPolicy::CRL_OPTIONAL, trust_store.get());
+ } else {
+ result = VerifyDeviceCert(certs, time, &context, &policy, nullptr,
+ CRLPolicy::CRL_OPTIONAL);
+ }
if (expected_result == RESULT_FAIL) {
ASSERT_FALSE(result);
@@ -89,33 +160,39 @@ void RunTest(TestResult expected_result,
}
// Creates a time in UTC at midnight.
-base::Time::Exploded CreateDate(int year, int month, int day) {
+//
+// The maximum date usable here is limited to year 2038 on 32 bit systems due to
+// base::Time::FromExploded clamping the range to what is supported by mktime
+// and timegm.
+base::Time CreateDate(int year, int month, int day) {
base::Time::Exploded time = {0};
time.year = year;
time.month = month;
time.day_of_month = day;
- return time;
+ base::Time result;
+ EXPECT_TRUE(base::Time::FromUTCExploded(time, &result));
+ return result;
}
// Returns 2016-04-01 00:00:00 UTC.
//
// This is a time when most of the test certificate paths are
// valid.
-base::Time::Exploded AprilFirst2016() {
+base::Time AprilFirst2016() {
return CreateDate(2016, 4, 1);
}
// Returns 2015-01-01 00:00:00 UTC.
-base::Time::Exploded JanuaryFirst2015() {
+base::Time JanuaryFirst2015() {
return CreateDate(2015, 1, 1);
}
-// Returns 2040-03-01 00:00:00 UTC.
+// Returns 2037-03-01 00:00:00 UTC.
//
// This is so far in the future that the test chains in this unit-test
// should all be invalid.
-base::Time::Exploded MarchFirst2040() {
- return CreateDate(2040, 3, 1);
+base::Time MarchFirst2037() {
+ return CreateDate(2037, 3, 1);
}
// Tests verifying a valid certificate chain of length 2:
@@ -124,11 +201,11 @@ base::Time::Exploded MarchFirst2040() {
// 1: Eureka Gen1 ICA
//
// Chains to trust anchor:
-// Eureka Root CA (not included)
+// Eureka Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen1) {
RunTest(RESULT_SUCCESS, "2ZZBG9 FA8FCA3EF91A", CastDeviceCertPolicy::NONE,
"certificates/chromecast_gen1.pem", AprilFirst2016(),
- "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
+ TRUST_STORE_BUILTIN, "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
}
// Tests verifying a valid certificate chain of length 2:
@@ -137,11 +214,11 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen1) {
// 1: Eureka Gen1 ICA
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen1Reissue) {
RunTest(RESULT_SUCCESS, "2ZZBG9 FA8FCA3EF91A", CastDeviceCertPolicy::NONE,
"certificates/chromecast_gen1_reissue.pem", AprilFirst2016(),
- "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
+ TRUST_STORE_BUILTIN, "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
}
// Tests verifying a valid certificate chain of length 2:
@@ -150,10 +227,11 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen1Reissue) {
// 1: Chromecast ICA 3
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen2) {
RunTest(RESULT_SUCCESS, "3ZZAK6 FA8FCA3F0D35", CastDeviceCertPolicy::NONE,
- "certificates/chromecast_gen2.pem", AprilFirst2016(), "");
+ "certificates/chromecast_gen2.pem", AprilFirst2016(),
+ TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 3:
@@ -163,10 +241,10 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2) {
// 2: Widevine Cast Subroot
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, Fugu) {
RunTest(RESULT_SUCCESS, "-6394818897508095075", CastDeviceCertPolicy::NONE,
- "certificates/fugu.pem", AprilFirst2016(), "");
+ "certificates/fugu.pem", AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying an invalid certificate chain of length 1:
@@ -174,12 +252,13 @@ TEST(VerifyCastDeviceCertTest, Fugu) {
// 0: Cast Test Untrusted Device
//
// Chains to:
-// Cast Test Untrusted ICA (not included)
+// Cast Test Untrusted ICA (Not part of trust store)
//
// This is invalid because it does not chain to a trust anchor.
TEST(VerifyCastDeviceCertTest, Unchained) {
RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE,
- "certificates/unchained.pem", AprilFirst2016(), "");
+ "certificates/unchained.pem", AprilFirst2016(), TRUST_STORE_BUILTIN,
+ "");
}
// Tests verifying one of the self-signed trust anchors (chain of length 1):
@@ -187,14 +266,15 @@ TEST(VerifyCastDeviceCertTest, Unchained) {
// 0: Cast Root CA
//
// Chains to trust anchor:
-// Cast Root CA
+// Cast Root CA (built-in trust store)
//
// Although this is a valid and trusted certificate (it is one of the
// trust anchors after all) it fails the test as it is not a *device
// certificate*.
TEST(VerifyCastDeviceCertTest, CastRootCa) {
RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE,
- "certificates/cast_root_ca.pem", AprilFirst2016(), "");
+ "certificates/cast_root_ca.pem", AprilFirst2016(),
+ TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2:
@@ -203,14 +283,14 @@ TEST(VerifyCastDeviceCertTest, CastRootCa) {
// 1: Chromecast ICA 4 (Audio)
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
//
// This device certificate has a policy that means it is valid only for audio
// devices.
TEST(VerifyCastDeviceCertTest, ChromecastAudio) {
RunTest(RESULT_SUCCESS, "4ZZDZJ FA8FCA7EFE3C",
CastDeviceCertPolicy::AUDIO_ONLY, "certificates/chromecast_audio.pem",
- AprilFirst2016(), "");
+ AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 3:
@@ -220,14 +300,14 @@ TEST(VerifyCastDeviceCertTest, ChromecastAudio) {
// 2: Cast Audio Dev Root CA
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
//
// This device certificate has a policy that means it is valid only for audio
// devices.
TEST(VerifyCastDeviceCertTest, MtkAudioDev) {
RunTest(RESULT_SUCCESS, "MediaTek Audio Dev Test",
CastDeviceCertPolicy::AUDIO_ONLY, "certificates/mtk_audio_dev.pem",
- JanuaryFirst2015(), "");
+ JanuaryFirst2015(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2:
@@ -236,10 +316,10 @@ TEST(VerifyCastDeviceCertTest, MtkAudioDev) {
// 1: Cast TV ICA (Vizio)
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, Vizio) {
RunTest(RESULT_SUCCESS, "9V0000VB FA8FCA784D01", CastDeviceCertPolicy::NONE,
- "certificates/vizio.pem", AprilFirst2016(), "");
+ "certificates/vizio.pem", AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2 using expired
@@ -250,15 +330,15 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2InvalidTime) {
// Control test - certificate should be valid at some time otherwise
// this test is pointless.
RunTest(RESULT_SUCCESS, "3ZZAK6 FA8FCA3F0D35", CastDeviceCertPolicy::NONE,
- kCertsFile, AprilFirst2016(), "");
+ kCertsFile, AprilFirst2016(), TRUST_STORE_BUILTIN, "");
// Use a time before notBefore.
RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE, kCertsFile,
- JanuaryFirst2015(), "");
+ JanuaryFirst2015(), TRUST_STORE_BUILTIN, "");
// Use a time after notAfter.
RunTest(RESULT_FAIL, "", CastDeviceCertPolicy::NONE, kCertsFile,
- MarchFirst2040(), "");
+ MarchFirst2037(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 3:
@@ -268,7 +348,7 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2InvalidTime) {
// 2: Cast Audio Dev Root CA
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
//
// This device certificate has a policy that means it is valid only for audio
// devices.
@@ -276,7 +356,7 @@ TEST(VerifyCastDeviceCertTest, AudioRefDevTestChain3) {
RunTest(RESULT_SUCCESS, "Audio Reference Dev Test",
CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/audio_ref_dev_test_chain_3.pem", AprilFirst2016(),
- "signeddata/AudioReferenceDevTest.pem");
+ TRUST_STORE_BUILTIN, "signeddata/AudioReferenceDevTest.pem");
}
// Tests verifying a valid certificate chain of length 3. Note that the first
@@ -289,7 +369,7 @@ TEST(VerifyCastDeviceCertTest, AudioRefDevTestChain3) {
// 2: Cast Audio Sony CA
//
// Chains to trust anchor:
-// Cast Root CA (not included)
+// Cast Root CA (built-in trust store)
//
// This device certificate has a policy that means it is valid only for audio
// devices.
@@ -297,7 +377,51 @@ TEST(VerifyCastDeviceCertTest, IntermediateSerialNumberTooLong) {
RunTest(RESULT_SUCCESS, "8C579B806FFC8A9DFFFF F8:8F:CA:6B:E6:DA",
CastDeviceCertPolicy::AUDIO_ONLY,
"certificates/intermediate_serialnumber_toolong.pem",
- AprilFirst2016(), "");
+ AprilFirst2016(), TRUST_STORE_BUILTIN, "");
+}
+
+// Tests verifying a valid certificate chain of length 2 when the trust anchor
+// is "expired". This is expected to work since expiration is not an enforced
+// anchor constraint, even though it may appear in the root certificate.
+//
+// 0: CastDevice
+// 1: CastIntermediate
+//
+// Chains to trust anchor:
+// Expired CastRoot (provided by test data)
+TEST(VerifyCastDeviceCertTest, ExpiredTrustAnchor) {
+ // The root certificate is only valid in 2015, so validating with a time in
+ // 2016 means it is expired.
+ RunTest(RESULT_SUCCESS, "CastDevice", CastDeviceCertPolicy::NONE,
+ "certificates/expired_root.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE, "");
+}
+
+// Tests verifying a certificate chain where the root certificate has a pathlen
+// constraint which is violated by the chain. In this case Root has a pathlen=1
+// constraint, however neither intermediate is constrained.
+//
+// The expectation is for pathlen constraints on trust anchors to be enforced,
+// so this validation must fail.
+//
+// 0: Target
+// 1: Intermediate2
+// 2: Intermediate1
+//
+// Chains to trust anchor:
+// Root (provided by test data; has pathlen=1 constraint)
+TEST(VerifyCastDeviceCertTest, ViolatesPathlenTrustAnchorConstraint) {
+ // First do a control test -- when anchor constraints are NOT enforced this
+ // chain should validate just fine.
+ RunTest(RESULT_SUCCESS, "Target", CastDeviceCertPolicy::NONE,
+ "certificates/violates_root_pathlen_constraint.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE_UNCONSTRAINED, "");
+
+ // Now do the real test and verify validation fails when using a TrustAncho
+ // with pathlen constraint.
+ RunTest(RESULT_FAIL, "Target", CastDeviceCertPolicy::NONE,
+ "certificates/violates_root_pathlen_constraint.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE, "");
}
// ------------------------------------------------------
diff --git a/chromium/components/cast_certificate/cast_crl.cc b/chromium/components/cast_certificate/cast_crl.cc
new file mode 100644
index 00000000000..9defacf370d
--- /dev/null
+++ b/chromium/components/cast_certificate/cast_crl.cc
@@ -0,0 +1,363 @@
+// 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 "components/cast_certificate/cast_crl.h"
+
+#include <unordered_map>
+#include <unordered_set>
+
+#include "base/base64.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/singleton.h"
+#include "components/cast_certificate/proto/revocation.pb.h"
+#include "crypto/sha2.h"
+#include "net/cert/internal/cert_errors.h"
+#include "net/cert/internal/parse_certificate.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/path_builder.h"
+#include "net/cert/internal/signature_algorithm.h"
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/trust_store_in_memory.h"
+#include "net/cert/internal/verify_certificate_chain.h"
+#include "net/cert/internal/verify_signed_data.h"
+#include "net/cert/x509_certificate.h"
+#include "net/der/encode_values.h"
+#include "net/der/input.h"
+#include "net/der/parse_values.h"
+#include "net/der/parser.h"
+
+namespace cast_certificate {
+namespace {
+
+enum CrlVersion {
+ // version 0: Spki Hash Algorithm = SHA-256
+ // Signature Algorithm = RSA-PKCS1 V1.5 with SHA-256
+ CRL_VERSION_0 = 0,
+};
+
+// -------------------------------------------------------------------------
+// Cast CRL trust anchors.
+// -------------------------------------------------------------------------
+
+// There is one trusted root for Cast CRL certificate chains:
+//
+// (1) CN=Cast CRL Root CA (kCastCRLRootCaDer)
+//
+// These constants are defined by the file included next:
+
+#include "components/cast_certificate/cast_crl_root_ca_cert_der-inc.h"
+
+// Singleton for the Cast CRL trust store.
+class CastCRLTrustStore {
+ public:
+ static CastCRLTrustStore* GetInstance() {
+ return base::Singleton<CastCRLTrustStore, base::LeakySingletonTraits<
+ CastCRLTrustStore>>::get();
+ }
+
+ static net::TrustStore& Get() { return GetInstance()->store_; }
+
+ private:
+ friend struct base::DefaultSingletonTraits<CastCRLTrustStore>;
+
+ CastCRLTrustStore() {
+ // Initialize the trust store with the root certificate.
+ net::CertErrors errors;
+ scoped_refptr<net::ParsedCertificate> cert =
+ net::ParsedCertificate::CreateWithoutCopyingUnsafe(
+ kCastCRLRootCaDer, sizeof(kCastCRLRootCaDer), {}, &errors);
+ CHECK(cert) << errors.ToDebugString();
+ // Enforce pathlen constraints and policies defined on the root certificate.
+ scoped_refptr<net::TrustAnchor> anchor =
+ net::TrustAnchor::CreateFromCertificateWithConstraints(std::move(cert));
+ CHECK(anchor);
+ store_.AddTrustAnchor(std::move(anchor));
+ }
+
+ net::TrustStoreInMemory store_;
+ DISALLOW_COPY_AND_ASSIGN(CastCRLTrustStore);
+};
+
+// Converts a uint64_t unix timestamp to net::der::GeneralizedTime.
+bool ConvertTimeSeconds(uint64_t seconds,
+ net::der::GeneralizedTime* generalized_time) {
+ base::Time unix_timestamp =
+ base::Time::UnixEpoch() +
+ base::TimeDelta::FromSeconds(base::saturated_cast<int64_t>(seconds));
+ return net::der::EncodeTimeAsGeneralizedTime(unix_timestamp,
+ generalized_time);
+}
+
+// Specifies the signature verification policy.
+// The required algorithms are:
+// RSASSA PKCS#1 v1.5 with SHA-256, using RSA keys 2048-bits or longer.
+std::unique_ptr<net::SignaturePolicy> CreateCastSignaturePolicy() {
+ return base::MakeUnique<net::SimpleSignaturePolicy>(2048);
+}
+
+// Verifies the CRL is signed by a trusted CRL authority at the time the CRL
+// was issued. Verifies the signature of |tbs_crl| is valid based on the
+// certificate and signature in |crl|. The validity of |tbs_crl| is verified
+// at |time|. The validity period of the CRL is adjusted to be the earliest
+// of the issuer certificate chain's expiration and the CRL's expiration and
+// the result is stored in |overall_not_after|.
+bool VerifyCRL(const Crl& crl,
+ const TbsCrl& tbs_crl,
+ const base::Time& time,
+ net::TrustStore* trust_store,
+ net::der::GeneralizedTime* overall_not_after) {
+ // Verify the trust of the CRL authority.
+ net::CertErrors parse_errors;
+ scoped_refptr<net::ParsedCertificate> parsed_cert =
+ net::ParsedCertificate::Create(crl.signer_cert(), {}, &parse_errors);
+ if (parsed_cert == nullptr) {
+ VLOG(2) << "CRL - Issuer certificate parsing failed:\n"
+ << parse_errors.ToDebugString();
+ return false;
+ }
+
+ // Wrap the signature in a BitString.
+ net::der::BitString signature_value_bit_string = net::der::BitString(
+ net::der::Input(base::StringPiece(crl.signature())), 0);
+
+ // Verify the signature.
+ auto signature_policy = CreateCastSignaturePolicy();
+ std::unique_ptr<net::SignatureAlgorithm> signature_algorithm_type =
+ net::SignatureAlgorithm::CreateRsaPkcs1(net::DigestAlgorithm::Sha256);
+ net::CertErrors verify_errors;
+ if (!VerifySignedData(*signature_algorithm_type,
+ net::der::Input(&crl.tbs_crl()),
+ signature_value_bit_string, parsed_cert->tbs().spki_tlv,
+ signature_policy.get(), &verify_errors)) {
+ VLOG(2) << "CRL - Signature verification failed:\n"
+ << verify_errors.ToDebugString();
+ return false;
+ }
+
+ // Verify the issuer certificate.
+ net::der::GeneralizedTime verification_time;
+ if (!net::der::EncodeTimeAsGeneralizedTime(time, &verification_time)) {
+ VLOG(2) << "CRL - Unable to parse verification time.";
+ return false;
+ }
+ net::CertPathBuilder::Result result;
+ net::CertPathBuilder path_builder(parsed_cert.get(), trust_store,
+ signature_policy.get(), verification_time,
+ &result);
+ net::CompletionStatus rv = path_builder.Run(base::Closure());
+ DCHECK_EQ(rv, net::CompletionStatus::SYNC);
+ if (!result.HasValidPath()) {
+ VLOG(2) << "CRL - Issuer certificate verification failed.";
+ // TODO(crbug.com/634443): Log the error information.
+ return false;
+ }
+ // There are no requirements placed on the leaf certificate having any
+ // particular KeyUsages. Leaf certificate checks are bypassed.
+
+ // Verify the CRL is still valid.
+ net::der::GeneralizedTime not_before;
+ if (!ConvertTimeSeconds(tbs_crl.not_before_seconds(), &not_before)) {
+ VLOG(2) << "CRL - Unable to parse not_before.";
+ return false;
+ }
+ net::der::GeneralizedTime not_after;
+ if (!ConvertTimeSeconds(tbs_crl.not_after_seconds(), &not_after)) {
+ VLOG(2) << "CRL - Unable to parse not_after.";
+ return false;
+ }
+ if ((verification_time < not_before) || (verification_time > not_after)) {
+ VLOG(2) << "CRL - Not time-valid.";
+ return false;
+ }
+
+ // Set CRL expiry to the earliest of the cert chain expiry and CRL expiry.
+ // Note that the trust anchor is not part of this loop.
+ // "expiration" of the trust anchor is handled instead by its
+ // presence in the trust store.
+ *overall_not_after = not_after;
+ for (const auto& cert : result.GetBestValidPath()->path.certs) {
+ net::der::GeneralizedTime cert_not_after = cert->tbs().validity_not_after;
+ if (cert_not_after < *overall_not_after)
+ *overall_not_after = cert_not_after;
+ }
+
+ // Perform sanity check on serial numbers.
+ for (const auto& range : tbs_crl.revoked_serial_number_ranges()) {
+ uint64_t first_serial_number = range.first_serial_number();
+ uint64_t last_serial_number = range.last_serial_number();
+ if (last_serial_number < first_serial_number) {
+ VLOG(2) << "CRL - Malformed serial number range.";
+ return false;
+ }
+ }
+ return true;
+}
+
+class CastCRLImpl : public CastCRL {
+ public:
+ CastCRLImpl(const TbsCrl& tbs_crl,
+ const net::der::GeneralizedTime& overall_not_after);
+ ~CastCRLImpl() override;
+
+ bool CheckRevocation(const net::CertPath& trusted_chain,
+ const base::Time& time) const override;
+
+ private:
+ struct SerialNumberRange {
+ uint64_t first_serial;
+ uint64_t last_serial;
+ };
+
+ net::der::GeneralizedTime not_before_;
+ net::der::GeneralizedTime not_after_;
+
+ // Revoked public key hashes.
+ // The values consist of the SHA256 hash of the SubjectPublicKeyInfo.
+ std::unordered_set<std::string> revoked_hashes_;
+
+ // Revoked serial number ranges indexed by issuer public key hash.
+ // The key is the SHA256 hash of issuer's SubjectPublicKeyInfo.
+ // The value is a list of revoked serial number ranges.
+ std::unordered_map<std::string, std::vector<SerialNumberRange>>
+ revoked_serial_numbers_;
+ DISALLOW_COPY_AND_ASSIGN(CastCRLImpl);
+};
+
+CastCRLImpl::CastCRLImpl(const TbsCrl& tbs_crl,
+ const net::der::GeneralizedTime& overall_not_after) {
+ // Parse the validity information.
+ // Assume ConvertTimeSeconds will succeed. Successful call to VerifyCRL
+ // means that these calls were successful.
+ ConvertTimeSeconds(tbs_crl.not_before_seconds(), &not_before_);
+ ConvertTimeSeconds(tbs_crl.not_after_seconds(), &not_after_);
+ if (overall_not_after < not_after_)
+ not_after_ = overall_not_after;
+
+ // Parse the revoked hashes.
+ for (const auto& hash : tbs_crl.revoked_public_key_hashes()) {
+ revoked_hashes_.insert(hash);
+ }
+
+ // Parse the revoked serial ranges.
+ for (const auto& range : tbs_crl.revoked_serial_number_ranges()) {
+ std::string issuer_hash = range.issuer_public_key_hash();
+
+ uint64_t first_serial_number = range.first_serial_number();
+ uint64_t last_serial_number = range.last_serial_number();
+ auto& serial_number_range = revoked_serial_numbers_[issuer_hash];
+ serial_number_range.push_back({first_serial_number, last_serial_number});
+ }
+}
+
+CastCRLImpl::~CastCRLImpl() {}
+
+// Verifies the revocation status of the certificate chain, at the specified
+// time.
+bool CastCRLImpl::CheckRevocation(const net::CertPath& trusted_chain,
+ const base::Time& time) const {
+ if (trusted_chain.IsEmpty())
+ return false;
+
+ DCHECK(trusted_chain.trust_anchor);
+
+ // Check the validity of the CRL at the specified time.
+ net::der::GeneralizedTime verification_time;
+ if (!net::der::EncodeTimeAsGeneralizedTime(time, &verification_time)) {
+ VLOG(2) << "CRL verification time malformed.";
+ return false;
+ }
+ if ((verification_time < not_before_) || (verification_time > not_after_)) {
+ VLOG(2) << "CRL not time-valid. Perform hard fail.";
+ return false;
+ }
+
+ // Check revocation. Note that this loop has "+ 1" in order to also loop
+ // over the trust anchor (which is treated specially).
+ for (size_t i = 0; i < trusted_chain.certs.size() + 1; ++i) {
+ // This loop iterates over both certificates AND then the trust
+ // anchor after exhausing the certs.
+ net::der::Input spki_tlv;
+ if (i == trusted_chain.certs.size()) {
+ spki_tlv = trusted_chain.trust_anchor->spki();
+ } else {
+ spki_tlv = trusted_chain.certs[i]->tbs().spki_tlv;
+ }
+
+ // Calculate the public key's hash to check for revocation.
+ std::string spki_hash = crypto::SHA256HashString(spki_tlv.AsString());
+ if (revoked_hashes_.find(spki_hash) != revoked_hashes_.end()) {
+ VLOG(2) << "Public key is revoked.";
+ return false;
+ }
+
+ // Check if the subordinate certificate was revoked by serial number.
+ if (i > 0) {
+ auto issuer_iter = revoked_serial_numbers_.find(spki_hash);
+ if (issuer_iter != revoked_serial_numbers_.end()) {
+ const auto& subordinate = trusted_chain.certs[i - 1];
+ uint64_t serial_number;
+ // Only Google generated device certificates will be revoked by range.
+ // These will always be less than 64 bits in length.
+ if (!net::der::ParseUint64(subordinate->tbs().serial_number,
+ &serial_number)) {
+ continue;
+ }
+ for (const auto& revoked_serial : issuer_iter->second) {
+ if (revoked_serial.first_serial <= serial_number &&
+ revoked_serial.last_serial >= serial_number) {
+ VLOG(2) << "Serial number is revoked";
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+// Parses and verifies the CRL used to verify the revocation status of
+// Cast device certificates.
+std::unique_ptr<CastCRL> ParseAndVerifyCRL(const std::string& crl_proto,
+ const base::Time& time,
+ net::TrustStore* trust_store) {
+ CrlBundle crl_bundle;
+ if (!crl_bundle.ParseFromString(crl_proto)) {
+ LOG(ERROR) << "CRL - Binary could not be parsed.";
+ return nullptr;
+ }
+ for (auto const& crl : crl_bundle.crls()) {
+ TbsCrl tbs_crl;
+ if (!tbs_crl.ParseFromString(crl.tbs_crl())) {
+ LOG(WARNING) << "Binary TBS CRL could not be parsed.";
+ continue;
+ }
+ if (tbs_crl.version() != CRL_VERSION_0) {
+ continue;
+ }
+ net::der::GeneralizedTime overall_not_after;
+ if (!VerifyCRL(crl, tbs_crl, time, trust_store, &overall_not_after)) {
+ LOG(ERROR) << "CRL - Verification failed.";
+ return nullptr;
+ }
+ return base::MakeUnique<CastCRLImpl>(tbs_crl, overall_not_after);
+ }
+ LOG(ERROR) << "No supported version of revocation data.";
+ return nullptr;
+}
+
+} // namespace
+
+std::unique_ptr<CastCRL> ParseAndVerifyCRL(const std::string& crl_proto,
+ const base::Time& time) {
+ return ParseAndVerifyCRL(crl_proto, time, &CastCRLTrustStore::Get());
+}
+
+std::unique_ptr<CastCRL> ParseAndVerifyCRLForTest(
+ const std::string& crl_proto,
+ const base::Time& time,
+ net::TrustStore* trust_store) {
+ return ParseAndVerifyCRL(crl_proto, time, trust_store);
+}
+
+} // namespace cast_certificate
diff --git a/chromium/components/cast_certificate/cast_crl.h b/chromium/components/cast_certificate/cast_crl.h
new file mode 100644
index 00000000000..0ab6964fa03
--- /dev/null
+++ b/chromium/components/cast_certificate/cast_crl.h
@@ -0,0 +1,66 @@
+// 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 COMPONENTS_CAST_CERTIFICATE_CAST_CRL_H_
+#define COMPONENTS_CAST_CERTIFICATE_CAST_CRL_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "net/cert/internal/parsed_certificate.h"
+
+namespace net {
+class TrustStore;
+struct CertPath;
+}
+
+namespace cast_certificate {
+
+// This class represents the CRL information parsed from the binary proto.
+class CastCRL {
+ public:
+ virtual ~CastCRL(){};
+
+ // Verifies the revocation status of a cast device certificate given a chain
+ // of X.509 certificates.
+ //
+ // Inputs:
+ // * |chain| the chain of verified certificates, including trust anchor.
+ //
+ // * |time| is the unix timestamp to use for determining if the certificate
+ // is revoked.
+ //
+ // Output:
+ // Returns true if no certificate in the chain was revoked.
+ virtual bool CheckRevocation(const net::CertPath& chain,
+ const base::Time& time) const = 0;
+};
+
+// Parses and verifies the CRL used to verify the revocation status of
+// Cast device certificates, using the built-in Cast CRL trust anchors.
+//
+// Inputs:
+// * |crl_proto| is a serialized cast_certificate.CrlBundle proto.
+// * |time| is the unix timestamp to use for determining if the CRL is valid.
+//
+// Output:
+// Returns the CRL object if success, nullptr otherwise.
+std::unique_ptr<CastCRL> ParseAndVerifyCRL(const std::string& crl_proto,
+ const base::Time& time);
+
+// Exposed only for testing, not for use in production code.
+//
+// This is an overloaded version of ParseAndVerifyCRL that allows
+// the input of a custom TrustStore.
+std::unique_ptr<CastCRL> ParseAndVerifyCRLForTest(const std::string& crl_proto,
+ const base::Time& time,
+ net::TrustStore* trust_store);
+
+} // namespace cast_certificate
+
+#endif // COMPONENTS_CAST_CERTIFICATE_CAST_CRL_H_
diff --git a/chromium/components/cast_certificate/cast_crl_root_ca_cert_der-inc.h b/chromium/components/cast_certificate/cast_crl_root_ca_cert_der-inc.h
new file mode 100644
index 00000000000..75380151564
--- /dev/null
+++ b/chromium/components/cast_certificate/cast_crl_root_ca_cert_der-inc.h
@@ -0,0 +1,150 @@
+// 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.
+
+// Certificate:
+// Data:
+// Version: 3 (0x2)
+// Serial Number: 153 (0x99)
+// Signature Algorithm: sha256WithRSAEncryption
+// Issuer: C=US, ST=California, L=Mountain View, O=Google Inc,
+// OU=Cast, CN=Cast CRL Root CA
+// Validity
+// Not Before: Aug 1 21:47:47 2016 GMT
+// Not After : Jul 27 21:47:47 2036 GMT
+// Subject: C=US, ST=California, L=Mountain View, O=Google Inc, OU=Cast,
+// CN=Cast CRL Root CA
+// Subject Public Key Info:
+// Public Key Algorithm: rsaEncryption
+// Public-Key: (2048 bit)
+// Modulus:
+// 00:c2:7f:c0:09:21:d3:60:89:28:b5:96:6e:fe:a6:
+// ad:fe:ae:e0:66:35:bd:99:6e:e8:93:85:29:ba:de:
+// 44:5d:a8:6b:fc:e6:cc:37:dd:1d:0f:cf:1e:3a:32:
+// 2c:7f:e0:1b:c9:bb:4c:34:a9:1c:97:b5:f8:6d:42:
+// 9c:4d:06:6a:a0:2d:95:55:3f:78:1d:5c:ab:e9:3a:
+// a6:08:3b:5a:af:f4:ab:53:77:14:9a:6b:b2:37:2e:
+// cd:6e:ea:bc:22:5d:56:55:73:fd:bd:03:2f:54:5e:
+// 7f:8b:c1:74:36:1a:18:1f:64:de:bf:08:80:4a:12:
+// 0c:49:53:b8:c7:3b:db:5f:dc:59:77:2f:b8:3a:05:
+// 8a:f6:b7:47:2a:9b:74:63:08:31:12:e6:7b:44:d1:
+// c1:7c:c8:87:b8:50:63:6d:9f:d7:ba:36:53:72:47:
+// 5f:dc:43:43:eb:d7:2e:11:d1:8a:7a:a4:03:f2:6a:
+// d3:88:e6:a7:b8:9d:81:b2:b0:88:24:c8:a1:fa:b0:
+// aa:db:08:64:3e:8b:2a:07:5c:5a:82:05:99:c2:d5:
+// ca:52:75:21:a7:fa:c5:a1:da:ac:f7:fe:d0:c7:44:
+// 76:9a:eb:6b:d3:bd:f4:7a:31:a6:ad:2f:5a:c4:31:
+// 3a:6d:f1:dd:7b:44:81:37:cf:13:85:5d:96:ae:7b:
+// 96:2b
+// Exponent: 65537 (0x10001)
+// X509v3 extensions:
+// X509v3 Basic Constraints:
+// CA:TRUE, pathlen:1
+// X509v3 Subject Key Identifier:
+// 1A:65:12:B4:A9:B9:B4:FC:91:0C:9E:67:E0:5B:D9:C9:AD:44:1C:B9
+// X509v3 Authority Key Identifier:
+// keyid:1A:65:12:B4:A9:B9:B4:FC:91:0C:9E:67:E0:5B:D9:C9:AD:44
+// :1C:B9
+//
+// X509v3 Key Usage:
+// Certificate Sign
+// Signature Algorithm: sha256WithRSAEncryption
+// af:5f:8b:c0:f7:c5:26:88:b9:ac:f7:ec:4d:0f:76:ab:e2:74:
+// 9a:44:3c:33:f6:74:3d:04:2a:59:76:a2:05:27:c4:e3:a2:c8:
+// c2:af:7e:fd:be:b9:ca:e9:5b:a8:2a:cd:a7:1e:0e:37:f1:6f:
+// 84:5e:aa:42:1f:ba:f0:44:ba:db:87:61:68:91:bb:1d:5c:3a:
+// f0:8e:02:20:76:aa:47:99:c7:73:0d:90:32:4a:b9:e3:fd:11:
+// 8b:5d:bd:22:4d:05:75:17:61:a2:a6:4f:b0:3d:52:8e:aa:c9:
+// b4:8d:05:5a:1c:36:c1:7b:87:f7:f8:e4:81:36:27:ec:35:ae:
+// b9:ce:15:47:e1:10:c9:16:69:3a:22:8e:63:18:31:cc:3b:56:
+// 69:c6:d4:24:dd:95:25:cf:34:e6:00:ae:e1:87:1e:ee:0c:14:
+// dc:0d:82:81:31:1f:8f:6d:d2:c0:e1:7c:12:f7:9d:ca:02:e3:
+// 76:36:44:53:3a:87:71:7d:ed:32:4c:a4:96:e6:e5:2c:c7:0d:
+// b7:96:c0:f3:7d:e5:58:32:f7:25:25:c0:13:76:d0:76:6c:73:
+// ab:3d:15:cd:c5:e8:85:15:9a:02:52:e9:61:41:e2:66:01:c5:
+// 71:e5:db:c0:a5:b3:4c:1e:ac:93:8a:35:4c:4d:da:57:22:24:
+// 1d:3a:f6:bd
+const unsigned char kCastCRLRootCaDer[] = {
+ 0x30, 0x82, 0x03, 0xce, 0x30, 0x82, 0x02, 0xb6, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x02, 0x00, 0x99, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x79, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61,
+ 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14,
+ 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55,
+ 0x04, 0x0b, 0x0c, 0x04, 0x43, 0x61, 0x73, 0x74, 0x31, 0x19, 0x30, 0x17,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x10, 0x43, 0x61, 0x73, 0x74, 0x20,
+ 0x43, 0x52, 0x4c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30,
+ 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x38, 0x30, 0x31, 0x32, 0x31, 0x34,
+ 0x37, 0x34, 0x37, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x37, 0x32, 0x37,
+ 0x32, 0x31, 0x34, 0x37, 0x34, 0x37, 0x5a, 0x30, 0x79, 0x31, 0x0b, 0x30,
+ 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c,
+ 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06,
+ 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61,
+ 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x20, 0x49, 0x6e, 0x63, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04,
+ 0x0b, 0x0c, 0x04, 0x43, 0x61, 0x73, 0x74, 0x31, 0x19, 0x30, 0x17, 0x06,
+ 0x03, 0x55, 0x04, 0x03, 0x0c, 0x10, 0x43, 0x61, 0x73, 0x74, 0x20, 0x43,
+ 0x52, 0x4c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82,
+ 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
+ 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc2, 0x7f, 0xc0, 0x09, 0x21,
+ 0xd3, 0x60, 0x89, 0x28, 0xb5, 0x96, 0x6e, 0xfe, 0xa6, 0xad, 0xfe, 0xae,
+ 0xe0, 0x66, 0x35, 0xbd, 0x99, 0x6e, 0xe8, 0x93, 0x85, 0x29, 0xba, 0xde,
+ 0x44, 0x5d, 0xa8, 0x6b, 0xfc, 0xe6, 0xcc, 0x37, 0xdd, 0x1d, 0x0f, 0xcf,
+ 0x1e, 0x3a, 0x32, 0x2c, 0x7f, 0xe0, 0x1b, 0xc9, 0xbb, 0x4c, 0x34, 0xa9,
+ 0x1c, 0x97, 0xb5, 0xf8, 0x6d, 0x42, 0x9c, 0x4d, 0x06, 0x6a, 0xa0, 0x2d,
+ 0x95, 0x55, 0x3f, 0x78, 0x1d, 0x5c, 0xab, 0xe9, 0x3a, 0xa6, 0x08, 0x3b,
+ 0x5a, 0xaf, 0xf4, 0xab, 0x53, 0x77, 0x14, 0x9a, 0x6b, 0xb2, 0x37, 0x2e,
+ 0xcd, 0x6e, 0xea, 0xbc, 0x22, 0x5d, 0x56, 0x55, 0x73, 0xfd, 0xbd, 0x03,
+ 0x2f, 0x54, 0x5e, 0x7f, 0x8b, 0xc1, 0x74, 0x36, 0x1a, 0x18, 0x1f, 0x64,
+ 0xde, 0xbf, 0x08, 0x80, 0x4a, 0x12, 0x0c, 0x49, 0x53, 0xb8, 0xc7, 0x3b,
+ 0xdb, 0x5f, 0xdc, 0x59, 0x77, 0x2f, 0xb8, 0x3a, 0x05, 0x8a, 0xf6, 0xb7,
+ 0x47, 0x2a, 0x9b, 0x74, 0x63, 0x08, 0x31, 0x12, 0xe6, 0x7b, 0x44, 0xd1,
+ 0xc1, 0x7c, 0xc8, 0x87, 0xb8, 0x50, 0x63, 0x6d, 0x9f, 0xd7, 0xba, 0x36,
+ 0x53, 0x72, 0x47, 0x5f, 0xdc, 0x43, 0x43, 0xeb, 0xd7, 0x2e, 0x11, 0xd1,
+ 0x8a, 0x7a, 0xa4, 0x03, 0xf2, 0x6a, 0xd3, 0x88, 0xe6, 0xa7, 0xb8, 0x9d,
+ 0x81, 0xb2, 0xb0, 0x88, 0x24, 0xc8, 0xa1, 0xfa, 0xb0, 0xaa, 0xdb, 0x08,
+ 0x64, 0x3e, 0x8b, 0x2a, 0x07, 0x5c, 0x5a, 0x82, 0x05, 0x99, 0xc2, 0xd5,
+ 0xca, 0x52, 0x75, 0x21, 0xa7, 0xfa, 0xc5, 0xa1, 0xda, 0xac, 0xf7, 0xfe,
+ 0xd0, 0xc7, 0x44, 0x76, 0x9a, 0xeb, 0x6b, 0xd3, 0xbd, 0xf4, 0x7a, 0x31,
+ 0xa6, 0xad, 0x2f, 0x5a, 0xc4, 0x31, 0x3a, 0x6d, 0xf1, 0xdd, 0x7b, 0x44,
+ 0x81, 0x37, 0xcf, 0x13, 0x85, 0x5d, 0x96, 0xae, 0x7b, 0x96, 0x2b, 0x02,
+ 0x03, 0x01, 0x00, 0x01, 0xa3, 0x60, 0x30, 0x5e, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x1d, 0x13, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01,
+ 0x01, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+ 0x1a, 0x65, 0x12, 0xb4, 0xa9, 0xb9, 0xb4, 0xfc, 0x91, 0x0c, 0x9e, 0x67,
+ 0xe0, 0x5b, 0xd9, 0xc9, 0xad, 0x44, 0x1c, 0xb9, 0x30, 0x1f, 0x06, 0x03,
+ 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x1a, 0x65, 0x12,
+ 0xb4, 0xa9, 0xb9, 0xb4, 0xfc, 0x91, 0x0c, 0x9e, 0x67, 0xe0, 0x5b, 0xd9,
+ 0xc9, 0xad, 0x44, 0x1c, 0xb9, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+ 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01,
+ 0x01, 0x00, 0xaf, 0x5f, 0x8b, 0xc0, 0xf7, 0xc5, 0x26, 0x88, 0xb9, 0xac,
+ 0xf7, 0xec, 0x4d, 0x0f, 0x76, 0xab, 0xe2, 0x74, 0x9a, 0x44, 0x3c, 0x33,
+ 0xf6, 0x74, 0x3d, 0x04, 0x2a, 0x59, 0x76, 0xa2, 0x05, 0x27, 0xc4, 0xe3,
+ 0xa2, 0xc8, 0xc2, 0xaf, 0x7e, 0xfd, 0xbe, 0xb9, 0xca, 0xe9, 0x5b, 0xa8,
+ 0x2a, 0xcd, 0xa7, 0x1e, 0x0e, 0x37, 0xf1, 0x6f, 0x84, 0x5e, 0xaa, 0x42,
+ 0x1f, 0xba, 0xf0, 0x44, 0xba, 0xdb, 0x87, 0x61, 0x68, 0x91, 0xbb, 0x1d,
+ 0x5c, 0x3a, 0xf0, 0x8e, 0x02, 0x20, 0x76, 0xaa, 0x47, 0x99, 0xc7, 0x73,
+ 0x0d, 0x90, 0x32, 0x4a, 0xb9, 0xe3, 0xfd, 0x11, 0x8b, 0x5d, 0xbd, 0x22,
+ 0x4d, 0x05, 0x75, 0x17, 0x61, 0xa2, 0xa6, 0x4f, 0xb0, 0x3d, 0x52, 0x8e,
+ 0xaa, 0xc9, 0xb4, 0x8d, 0x05, 0x5a, 0x1c, 0x36, 0xc1, 0x7b, 0x87, 0xf7,
+ 0xf8, 0xe4, 0x81, 0x36, 0x27, 0xec, 0x35, 0xae, 0xb9, 0xce, 0x15, 0x47,
+ 0xe1, 0x10, 0xc9, 0x16, 0x69, 0x3a, 0x22, 0x8e, 0x63, 0x18, 0x31, 0xcc,
+ 0x3b, 0x56, 0x69, 0xc6, 0xd4, 0x24, 0xdd, 0x95, 0x25, 0xcf, 0x34, 0xe6,
+ 0x00, 0xae, 0xe1, 0x87, 0x1e, 0xee, 0x0c, 0x14, 0xdc, 0x0d, 0x82, 0x81,
+ 0x31, 0x1f, 0x8f, 0x6d, 0xd2, 0xc0, 0xe1, 0x7c, 0x12, 0xf7, 0x9d, 0xca,
+ 0x02, 0xe3, 0x76, 0x36, 0x44, 0x53, 0x3a, 0x87, 0x71, 0x7d, 0xed, 0x32,
+ 0x4c, 0xa4, 0x96, 0xe6, 0xe5, 0x2c, 0xc7, 0x0d, 0xb7, 0x96, 0xc0, 0xf3,
+ 0x7d, 0xe5, 0x58, 0x32, 0xf7, 0x25, 0x25, 0xc0, 0x13, 0x76, 0xd0, 0x76,
+ 0x6c, 0x73, 0xab, 0x3d, 0x15, 0xcd, 0xc5, 0xe8, 0x85, 0x15, 0x9a, 0x02,
+ 0x52, 0xe9, 0x61, 0x41, 0xe2, 0x66, 0x01, 0xc5, 0x71, 0xe5, 0xdb, 0xc0,
+ 0xa5, 0xb3, 0x4c, 0x1e, 0xac, 0x93, 0x8a, 0x35, 0x4c, 0x4d, 0xda, 0x57,
+ 0x22, 0x24, 0x1d, 0x3a, 0xf6, 0xbd,
+};
diff --git a/chromium/components/cast_certificate/cast_crl_unittest.cc b/chromium/components/cast_certificate/cast_crl_unittest.cc
new file mode 100644
index 00000000000..b108b5fc1d7
--- /dev/null
+++ b/chromium/components/cast_certificate/cast_crl_unittest.cc
@@ -0,0 +1,260 @@
+// 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 "base/time/time.h"
+#include "components/cast_certificate/cast_cert_validator.h"
+#include "components/cast_certificate/cast_cert_validator_test_helpers.h"
+#include "components/cast_certificate/cast_crl.h"
+#include "components/cast_certificate/proto/test_suite.pb.h"
+#include "net/cert/internal/cert_errors.h"
+#include "net/cert/internal/trust_store_in_memory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cast_certificate {
+namespace {
+
+// Creates a trust store using the test roots encoded in the PEM file at |path|.
+std::unique_ptr<net::TrustStoreInMemory> CreateTrustStoreFromFile(
+ const std::string& path) {
+ std::unique_ptr<net::TrustStoreInMemory> trust_store(
+ new net::TrustStoreInMemory());
+ const auto trusted_test_roots =
+ cast_certificate::testing::ReadCertificateChainFromFile(path);
+ for (const auto& trusted_root : trusted_test_roots) {
+ net::CertErrors errors;
+ scoped_refptr<net::ParsedCertificate> cert(
+ net::ParsedCertificate::Create(trusted_root, {}, &errors));
+ EXPECT_TRUE(cert) << errors.ToDebugString();
+ scoped_refptr<net::TrustAnchor> anchor =
+ net::TrustAnchor::CreateFromCertificateWithConstraints(std::move(cert));
+ trust_store->AddTrustAnchor(std::move(anchor));
+ }
+ return trust_store;
+}
+
+// Converts uint64_t unix timestamp in seconds to base::Time.
+base::Time ConvertUnixTimestampSeconds(uint64_t time) {
+ return base::Time::UnixEpoch() +
+ base::TimeDelta::FromMilliseconds(time * 1000);
+}
+
+// Indicates the expected result of test step's verification.
+enum TestStepResult {
+ RESULT_SUCCESS,
+ RESULT_FAIL,
+};
+
+// Verifies that the provided certificate chain is valid at the specified time
+// and chains up to a trust anchor.
+bool TestVerifyCertificate(TestStepResult expected_result,
+ const std::vector<std::string>& certificate_chain,
+ const base::Time& time,
+ net::TrustStore* cast_trust_store) {
+ std::unique_ptr<CertVerificationContext> context;
+ CastDeviceCertPolicy policy;
+ int result;
+ if (cast_trust_store != nullptr) {
+ result = VerifyDeviceCertForTest(certificate_chain, time, &context, &policy,
+ nullptr, CRLPolicy::CRL_OPTIONAL,
+ cast_trust_store);
+ } else {
+ result = VerifyDeviceCert(certificate_chain, time, &context, &policy,
+ nullptr, CRLPolicy::CRL_OPTIONAL);
+ }
+ if (expected_result != RESULT_SUCCESS) {
+ EXPECT_FALSE(result);
+ return !result;
+ }
+ EXPECT_TRUE(result);
+ return result;
+}
+
+// Verifies that the provided Cast CRL is signed by a trusted issuer
+// and that the CRL can be parsed successfully.
+// The validity of the CRL is also checked at the specified time.
+bool TestVerifyCRL(TestStepResult expected_result,
+ const std::string& crl_bundle,
+ const base::Time& time,
+ net::TrustStore* crl_trust_store) {
+ std::unique_ptr<CastCRL> crl;
+ if (crl_trust_store != nullptr) {
+ crl = ParseAndVerifyCRLForTest(crl_bundle, time, crl_trust_store);
+ } else {
+ crl = ParseAndVerifyCRL(crl_bundle, time);
+ }
+ if (expected_result != RESULT_SUCCESS) {
+ EXPECT_EQ(crl, nullptr);
+ return crl == nullptr;
+ }
+ EXPECT_NE(crl, nullptr);
+ return crl != nullptr;
+}
+
+// Verifies that the certificate chain provided is not revoked according to
+// the provided Cast CRL at |cert_time|.
+// The provided CRL is verified at |crl_time|.
+// If |crl_required| is set, then a valid Cast CRL must be provided.
+// Otherwise, a missing CRL is be ignored.
+bool TestVerifyRevocation(TestStepResult expected_result,
+ const std::vector<std::string>& certificate_chain,
+ const std::string& crl_bundle,
+ const base::Time& crl_time,
+ const base::Time& cert_time,
+ bool crl_required,
+ net::TrustStore* cast_trust_store,
+ net::TrustStore* crl_trust_store) {
+ std::unique_ptr<CastCRL> crl;
+ if (!crl_bundle.empty()) {
+ if (crl_trust_store != nullptr) {
+ crl = ParseAndVerifyCRLForTest(crl_bundle, crl_time, crl_trust_store);
+ } else {
+ crl = ParseAndVerifyCRL(crl_bundle, crl_time);
+ }
+ EXPECT_NE(crl.get(), nullptr);
+ }
+
+ std::unique_ptr<CertVerificationContext> context;
+ CastDeviceCertPolicy policy;
+ CRLPolicy crl_policy = CRLPolicy::CRL_REQUIRED;
+ if (!crl_required)
+ crl_policy = CRLPolicy::CRL_OPTIONAL;
+ int result;
+ if (cast_trust_store != nullptr) {
+ result =
+ VerifyDeviceCertForTest(certificate_chain, cert_time, &context, &policy,
+ crl.get(), crl_policy, cast_trust_store);
+ } else {
+ result = VerifyDeviceCert(certificate_chain, cert_time, &context, &policy,
+ crl.get(), crl_policy);
+ }
+ if (expected_result != RESULT_SUCCESS) {
+ EXPECT_FALSE(result);
+ return !result;
+ }
+ EXPECT_TRUE(result);
+ return result;
+}
+
+// Runs a single test case.
+bool RunTest(const DeviceCertTest& test_case) {
+ std::unique_ptr<net::TrustStoreInMemory> crl_trust_store;
+ std::unique_ptr<net::TrustStoreInMemory> cast_trust_store;
+ if (test_case.use_test_trust_anchors()) {
+ crl_trust_store =
+ CreateTrustStoreFromFile("certificates/cast_crl_test_root_ca.pem");
+ cast_trust_store =
+ CreateTrustStoreFromFile("certificates/cast_test_root_ca.pem");
+
+ EXPECT_TRUE(crl_trust_store.get());
+ EXPECT_TRUE(cast_trust_store.get());
+ }
+
+ std::vector<std::string> certificate_chain;
+ for (auto const& cert : test_case.der_cert_path()) {
+ certificate_chain.push_back(cert);
+ }
+
+ base::Time cert_verification_time =
+ ConvertUnixTimestampSeconds(test_case.cert_verification_time_seconds());
+
+ uint64_t crl_verify_time = test_case.crl_verification_time_seconds();
+ base::Time crl_verification_time =
+ ConvertUnixTimestampSeconds(crl_verify_time);
+ if (crl_verify_time == 0)
+ crl_verification_time = cert_verification_time;
+
+ std::string crl_bundle = test_case.crl_bundle();
+ switch (test_case.expected_result()) {
+ case PATH_VERIFICATION_FAILED:
+ return TestVerifyCertificate(RESULT_FAIL, certificate_chain,
+ cert_verification_time,
+ cast_trust_store.get());
+ break;
+ case CRL_VERIFICATION_FAILED:
+ return TestVerifyCRL(RESULT_FAIL, crl_bundle, crl_verification_time,
+ crl_trust_store.get());
+ break;
+ case REVOCATION_CHECK_FAILED_WITHOUT_CRL:
+ return TestVerifyCertificate(RESULT_SUCCESS, certificate_chain,
+ cert_verification_time,
+ cast_trust_store.get()) &&
+ TestVerifyCRL(RESULT_FAIL, crl_bundle, crl_verification_time,
+ crl_trust_store.get()) &&
+ TestVerifyRevocation(RESULT_FAIL, certificate_chain, crl_bundle,
+ crl_verification_time, cert_verification_time,
+ true, cast_trust_store.get(),
+ crl_trust_store.get());
+ break;
+ case REVOCATION_CHECK_FAILED:
+ return TestVerifyCertificate(RESULT_SUCCESS, certificate_chain,
+ cert_verification_time,
+ cast_trust_store.get()) &&
+ TestVerifyCRL(RESULT_SUCCESS, crl_bundle, crl_verification_time,
+ crl_trust_store.get()) &&
+ TestVerifyRevocation(RESULT_FAIL, certificate_chain, crl_bundle,
+ crl_verification_time, cert_verification_time,
+ false, cast_trust_store.get(),
+ crl_trust_store.get());
+ break;
+ case SUCCESS:
+ return (crl_bundle.empty() ||
+ TestVerifyCRL(RESULT_SUCCESS, crl_bundle, crl_verification_time,
+ crl_trust_store.get())) &&
+ TestVerifyCertificate(RESULT_SUCCESS, certificate_chain,
+ cert_verification_time,
+ cast_trust_store.get()) &&
+ TestVerifyRevocation(RESULT_SUCCESS, certificate_chain, crl_bundle,
+ crl_verification_time, cert_verification_time,
+ !crl_bundle.empty(), cast_trust_store.get(),
+ crl_trust_store.get());
+ break;
+ case UNSPECIFIED:
+ return false;
+ break;
+ }
+ return false;
+}
+
+// Parses the provided test suite provided in wire-format proto.
+// Each test contains the inputs and the expected output.
+// To see the description of the test, execute the test.
+// These tests are generated by a test generator in google3.
+void RunTestSuite(const std::string& test_suite_file_name) {
+ std::string testsuite_raw =
+ cast_certificate::testing::ReadTestFileToString(test_suite_file_name);
+ DeviceCertTestSuite test_suite;
+ EXPECT_TRUE(test_suite.ParseFromString(testsuite_raw));
+ uint16_t success = 0;
+ uint16_t failed = 0;
+ std::vector<std::string> failed_tests;
+
+ for (auto const& test_case : test_suite.tests()) {
+ LOG(INFO) << "[ RUN ] " << test_case.description();
+ bool result = RunTest(test_case);
+ EXPECT_TRUE(result);
+ if (!result) {
+ LOG(INFO) << "[ FAILED ] " << test_case.description();
+ ++failed;
+ failed_tests.push_back(test_case.description());
+ } else {
+ LOG(INFO) << "[ PASSED ] " << test_case.description();
+ ++success;
+ }
+ }
+ LOG(INFO) << "[ PASSED ] " << success << " test(s).";
+ if (failed) {
+ LOG(INFO) << "[ FAILED ] " << failed << " test(s), listed below:";
+ for (const auto& failed_test : failed_tests) {
+ LOG(INFO) << "[ FAILED ] " << failed_test;
+ }
+ }
+}
+
+TEST(CastCertificateTest, TestSuite1) {
+ RunTestSuite("testsuite/testsuite1.pb");
+}
+
+} // namespace
+
+} // namespace cast_certificate
diff --git a/chromium/components/cast_certificate/proto/BUILD.gn b/chromium/components/cast_certificate/proto/BUILD.gn
new file mode 100644
index 00000000000..96949971bc0
--- /dev/null
+++ b/chromium/components/cast_certificate/proto/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
+proto_library("proto") {
+ sources = [
+ "revocation.proto",
+ ]
+}
+
+proto_library("unittest_proto") {
+ sources = [
+ "test_suite.proto",
+ ]
+}
+
+if (is_android) {
+ proto_java_library("proto_java") {
+ proto_path = "//components/cast_certificate/proto"
+
+ sources = [
+ "revocation.proto",
+ ]
+ }
+ proto_java_library("unittest_proto_java") {
+ proto_path = "//components/cast_certificate/proto"
+
+ sources = [
+ "test_suite.proto",
+ ]
+ }
+}
diff --git a/chromium/components/cast_certificate/proto/revocation.proto b/chromium/components/cast_certificate/proto/revocation.proto
new file mode 100644
index 00000000000..d3f9d7f7f32
--- /dev/null
+++ b/chromium/components/cast_certificate/proto/revocation.proto
@@ -0,0 +1,60 @@
+// 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.
+//
+// Data structures related to Cast device certificate revocation infrastructure.
+
+// This proto must be kept in sync with google3.
+
+syntax = "proto2";
+
+package cast_certificate;
+
+option optimize_for = LITE_RUNTIME;
+
+message CrlBundle {
+ // List of supported versions of the same revocation list.
+ repeated Crl crls = 1;
+}
+
+message Crl {
+ // Octet string of serialized TbsCrl protobuf.
+ optional bytes tbs_crl = 1;
+
+ // Binary ASN.1 DER encoding of the signer's certificate.
+ optional bytes signer_cert = 2;
+
+ // Signature calculated over the contents of the tbs_crl field. Signature
+ // algorithm is implied by TbsCrl.version.
+ optional bytes signature = 3;
+}
+
+message TbsCrl {
+ // Version 0 algorithms:
+ // revoked_public_key_hashes: SHA-256
+ // SerialNumberRange.issuer_public_key_hash: SHA-256
+ // Crl.signature: RSA-PKCS1 V1.5 with SHA-256
+ optional uint64 version = 1 [default = 0];
+
+ // Inclusive validity range of the CRL in Unix time.
+ optional uint64 not_before_seconds = 2;
+ optional uint64 not_after_seconds = 3;
+
+ // SPKI hashes of revoked credentials. Hashing algorithm is implied by
+ // TbsCrl.version.
+ repeated bytes revoked_public_key_hashes = 4;
+
+ repeated SerialNumberRange revoked_serial_number_ranges = 5;
+}
+
+message SerialNumberRange {
+ // SPKI hash of the certificate issuer. Hashing algorithm is implied by the
+ // enclosing TbsCrl.version.
+ optional bytes issuer_public_key_hash = 1;
+
+ // Inclusive range of revoked certificate serial numbers. Only certificates
+ // with positive serial numbers that fit within 64 bits can be revoked through
+ // this mechanism.
+ optional uint64 first_serial_number = 2;
+ optional uint64 last_serial_number = 3;
+}
diff --git a/chromium/components/cast_certificate/proto/test_suite.proto b/chromium/components/cast_certificate/proto/test_suite.proto
new file mode 100644
index 00000000000..d6b9a365cba
--- /dev/null
+++ b/chromium/components/cast_certificate/proto/test_suite.proto
@@ -0,0 +1,56 @@
+// 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.
+
+syntax = "proto2";
+
+package cast_certificate;
+
+option optimize_for = LITE_RUNTIME;
+
+// A suite of test data to exercise Cast device certificate verification and
+// revocation logic.
+message DeviceCertTestSuite {
+ repeated DeviceCertTest tests = 1;
+}
+
+enum VerificationResult {
+ // This should never be encountered in a valid test.
+ UNSPECIFIED = 0;
+ // The device certificate is valid.
+ SUCCESS = 1;
+ // Problem with device certificate or its path.
+ PATH_VERIFICATION_FAILED = 2;
+ // Problem with the CRL.
+ CRL_VERIFICATION_FAILED = 3;
+ // Device certificate or one of the certificates in its path did not pass the
+ // revocation check.
+ REVOCATION_CHECK_FAILED = 4;
+ // No CRL was provided, but revocation check is required, and therefore fails.
+ REVOCATION_CHECK_FAILED_WITHOUT_CRL = 5;
+}
+
+message DeviceCertTest {
+ // Human-readable description of the test.
+ optional string description = 1;
+
+ // Expected result of the certificate verification.
+ optional VerificationResult expected_result = 4;
+
+ // Device certiticate path up to a trusted root. Root is not included.
+ repeated bytes der_cert_path = 2;
+
+ // Serialized cast.CrlBundle proto if revocation check is required.
+ optional bytes crl_bundle = 3;
+
+ // Time at which to verify the device certificate.
+ optional uint64 cert_verification_time_seconds = 5;
+
+ // Time at which to verify the CRL. It this field is omitted, the CRL is
+ // verified at cert_verification_time_seconds.
+ optional uint64 crl_verification_time_seconds = 6;
+
+ // Chooses between test and production trust anchors for device certificates
+ // and CRLs. Defaults to using the test trust anchors.
+ optional bool use_test_trust_anchors = 7 [default = true];
+}
diff --git a/chromium/components/cdm.gypi b/chromium/components/cdm.gypi
deleted file mode 100644
index 3698f34bdae..00000000000
--- a/chromium/components/cdm.gypi
+++ /dev/null
@@ -1,80 +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.
-
-{
- 'targets': [
- {
- # GN verison: //components/cdm/common
- 'target_name': 'cdm_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../ipc/ipc.gyp:ipc',
- ],
- 'sources': [
- 'cdm/common/cdm_message_generator.cc',
- 'cdm/common/cdm_message_generator.h',
- 'cdm/common/cdm_messages_android.h',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'sources': [
- 'cdm/common/widevine_drm_delegate_android.cc',
- 'cdm/common/widevine_drm_delegate_android.h',
- ],
- }],
- ],
- },
- {
- # GN version: //components/cdm/renderer
- 'target_name': 'cdm_renderer',
- 'type': 'static_library',
- 'dependencies': [
- 'cdm_common',
- '../base/base.gyp:base',
- '../content/content.gyp:content_renderer',
- '../third_party/widevine/cdm/widevine_cdm.gyp:widevine_cdm_version_h',
- ],
- 'include_dirs': [
- # Needed by widevine_key_system_properties.cc.
- '<(SHARED_INTERMEDIATE_DIR)',
- ],
- 'sources': [
- 'cdm/renderer/widevine_key_system_properties.cc',
- 'cdm/renderer/widevine_key_system_properties.h',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'sources': [
- 'cdm/renderer/android_key_systems.cc',
- 'cdm/renderer/android_key_systems.h',
- ],
- }],
- ],
- },
- ],
- 'conditions': [
- ['OS == "android"', {
- 'targets': [
- {
- # GN version: //components/cdm/browser
- 'target_name': 'cdm_browser',
- 'type': 'static_library',
- 'dependencies': [
- 'cdm_common',
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../media/media.gyp:media',
- ],
- 'sources': [
- 'cdm/browser/cdm_message_filter_android.cc',
- 'cdm/browser/cdm_message_filter_android.h',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/cdm/common/BUILD.gn b/chromium/components/cdm/common/BUILD.gn
index fc43c7e2a70..03e672cc5d3 100644
--- a/chromium/components/cdm/common/BUILD.gn
+++ b/chromium/components/cdm/common/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("common") {
+static_library("common") {
sources = [
"cdm_message_generator.cc",
"cdm_message_generator.h",
diff --git a/chromium/components/cdm/renderer/BUILD.gn b/chromium/components/cdm/renderer/BUILD.gn
index f364f89c829..9ec8fd05be4 100644
--- a/chromium/components/cdm/renderer/BUILD.gn
+++ b/chromium/components/cdm/renderer/BUILD.gn
@@ -4,6 +4,8 @@
static_library("renderer") {
sources = [
+ "external_clear_key_key_system_properties.cc",
+ "external_clear_key_key_system_properties.h",
"widevine_key_system_properties.cc",
"widevine_key_system_properties.h",
]
diff --git a/chromium/components/cdm/renderer/android_key_systems.cc b/chromium/components/cdm/renderer/android_key_systems.cc
index 22ca175eaa4..7953dd61f19 100644
--- a/chromium/components/cdm/renderer/android_key_systems.cc
+++ b/chromium/components/cdm/renderer/android_key_systems.cc
@@ -91,9 +91,7 @@ class AndroidPlatformKeySystemProperties : public KeySystemProperties {
const SupportedCodecs supported_codecs_;
};
-} // namespace
-
-static SupportedKeySystemResponse QueryKeySystemSupport(
+SupportedKeySystemResponse QueryKeySystemSupport(
const std::string& key_system) {
SupportedKeySystemRequest request;
SupportedKeySystemResponse response;
@@ -109,6 +107,8 @@ static SupportedKeySystemResponse QueryKeySystemSupport(
return response;
}
+} // namespace
+
void AddAndroidWidevine(
std::vector<std::unique_ptr<KeySystemProperties>>* concrete_key_systems) {
SupportedKeySystemResponse response = QueryKeySystemSupport(
diff --git a/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc
new file mode 100644
index 00000000000..5771ec2af55
--- /dev/null
+++ b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc
@@ -0,0 +1,89 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cdm/renderer/external_clear_key_key_system_properties.h"
+
+#include "base/logging.h"
+#include "media/base/eme_constants.h"
+
+namespace cdm {
+
+#if defined(ENABLE_PEPPER_CDMS)
+const char kExternalClearKeyPepperType[] = "application/x-ppapi-clearkey-cdm";
+#endif
+
+ExternalClearKeyProperties::ExternalClearKeyProperties(
+ const std::string& key_system_name)
+ : key_system_name_(key_system_name) {}
+
+ExternalClearKeyProperties::~ExternalClearKeyProperties() {}
+
+std::string ExternalClearKeyProperties::GetKeySystemName() const {
+ return key_system_name_;
+}
+
+bool ExternalClearKeyProperties::IsSupportedInitDataType(
+ media::EmeInitDataType init_data_type) const {
+ switch (init_data_type) {
+ case media::EmeInitDataType::WEBM:
+ case media::EmeInitDataType::KEYIDS:
+ return true;
+
+ case media::EmeInitDataType::CENC:
+#if defined(USE_PROPRIETARY_CODECS)
+ return true;
+#else
+ return false;
+#endif // defined(USE_PROPRIETARY_CODECS)
+
+ case media::EmeInitDataType::UNKNOWN:
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+media::SupportedCodecs ExternalClearKeyProperties::GetSupportedCodecs() const {
+#if defined(USE_PROPRIETARY_CODECS)
+ return media::EME_CODEC_MP4_ALL | media::EME_CODEC_WEBM_ALL;
+#else
+ return media::EME_CODEC_WEBM_ALL;
+#endif
+}
+
+media::EmeConfigRule ExternalClearKeyProperties::GetRobustnessConfigRule(
+ media::EmeMediaType media_type,
+ const std::string& requested_robustness) const {
+ return requested_robustness.empty() ? media::EmeConfigRule::SUPPORTED
+ : media::EmeConfigRule::NOT_SUPPORTED;
+}
+
+// Persistent license sessions are faked.
+media::EmeSessionTypeSupport
+ExternalClearKeyProperties::GetPersistentLicenseSessionSupport() const {
+ return media::EmeSessionTypeSupport::SUPPORTED;
+}
+
+media::EmeSessionTypeSupport
+ExternalClearKeyProperties::GetPersistentReleaseMessageSessionSupport() const {
+ return media::EmeSessionTypeSupport::NOT_SUPPORTED;
+}
+
+media::EmeFeatureSupport ExternalClearKeyProperties::GetPersistentStateSupport()
+ const {
+ return media::EmeFeatureSupport::REQUESTABLE;
+}
+
+media::EmeFeatureSupport
+ExternalClearKeyProperties::GetDistinctiveIdentifierSupport() const {
+ return media::EmeFeatureSupport::NOT_SUPPORTED;
+}
+
+#if defined(ENABLE_PEPPER_CDMS)
+std::string ExternalClearKeyProperties::GetPepperType() const {
+ return kExternalClearKeyPepperType;
+}
+#endif
+
+} // namespace cdm
diff --git a/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h
new file mode 100644
index 00000000000..d0ed06fd875
--- /dev/null
+++ b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h
@@ -0,0 +1,48 @@
+// 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 COMPONENTS_CDM_RENDERER_EXTERNAL_CLEAR_KEY_KEY_SYSTEM_PROPERTIES_H_
+#define COMPONENTS_CDM_RENDERER_EXTERNAL_CLEAR_KEY_KEY_SYSTEM_PROPERTIES_H_
+
+#include <string>
+
+#include "build/build_config.h"
+#include "media/base/key_system_properties.h"
+
+namespace cdm {
+
+#if defined(ENABLE_PEPPER_CDMS)
+extern const char kExternalClearKeyPepperType[];
+#endif
+
+// KeySystemProperties implementation for external Clear Key key systems.
+class ExternalClearKeyProperties : public media::KeySystemProperties {
+ public:
+ explicit ExternalClearKeyProperties(const std::string& key_system_name);
+ ~ExternalClearKeyProperties() override;
+
+ std::string GetKeySystemName() const override;
+ bool IsSupportedInitDataType(
+ media::EmeInitDataType init_data_type) const override;
+ media::SupportedCodecs GetSupportedCodecs() const override;
+ media::EmeConfigRule GetRobustnessConfigRule(
+ media::EmeMediaType media_type,
+ const std::string& requested_robustness) const override;
+ media::EmeSessionTypeSupport GetPersistentLicenseSessionSupport()
+ const override;
+ media::EmeSessionTypeSupport GetPersistentReleaseMessageSessionSupport()
+ const override;
+ media::EmeFeatureSupport GetPersistentStateSupport() const override;
+ media::EmeFeatureSupport GetDistinctiveIdentifierSupport() const override;
+#if defined(ENABLE_PEPPER_CDMS)
+ std::string GetPepperType() const override;
+#endif
+
+ private:
+ const std::string key_system_name_;
+};
+
+} // namespace cdm
+
+#endif // COMPONENTS_CDM_RENDERER_EXTERNAL_CLEAR_KEY_KEY_SYSTEM_PROPERTIES_H_
diff --git a/chromium/components/certificate_reporting.gypi b/chromium/components/certificate_reporting.gypi
deleted file mode 100644
index 87f9f50fdd6..00000000000
--- a/chromium/components/certificate_reporting.gypi
+++ /dev/null
@@ -1,57 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/certificate_reporting
- 'target_name': 'certificate_reporting',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- 'cert_logger_proto',
- 'encrypted_cert_logger_proto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- "certificate_reporting/error_report.cc",
- "certificate_reporting/error_report.h",
- "certificate_reporting/error_reporter.cc",
- "certificate_reporting/error_reporter.h",
- ]
- },
- {
- # Protobuf compiler / generator for the certificate error reporting
- # protocol buffer.
- # GN version: //components/certificate_reporting:cert_logger_proto
- 'target_name': 'cert_logger_proto',
- 'type': 'static_library',
- 'sources': [ 'certificate_reporting/cert_logger.proto', ],
- 'variables': {
- 'proto_in_dir': 'certificate_reporting/',
- 'proto_out_dir': 'components/certificate_reporting/',
- },
- 'includes': [ '../build/protoc.gypi', ],
- },
- {
- # Protobuf compiler / generator for the encrypted certificate
- # reports protocol buffer.
- # GN version: //components/certificate_reporting:encrypted_cert_logger_proto
- 'target_name': 'encrypted_cert_logger_proto',
- 'type': 'static_library',
- 'sources': [ 'certificate_reporting/encrypted_cert_logger.proto', ],
- 'variables': {
- 'proto_in_dir': 'certificate_reporting/',
- 'proto_out_dir': 'components/certificate_reporting/',
- },
- 'includes': [ '../build/protoc.gypi', ],
- },
- ]
-}
diff --git a/chromium/components/certificate_reporting/BUILD.gn b/chromium/components/certificate_reporting/BUILD.gn
index d54b2916ccb..eee31993b70 100644
--- a/chromium/components/certificate_reporting/BUILD.gn
+++ b/chromium/components/certificate_reporting/BUILD.gn
@@ -4,7 +4,6 @@
import("//third_party/protobuf/proto_library.gni")
-# GYP version: components/certificate_reporting.gyp:certificate_reporting
static_library("certificate_reporting") {
sources = [
"cert_logger.proto",
@@ -27,14 +26,12 @@ static_library("certificate_reporting") {
]
}
-# GYP version: components/certificate_reporting.gypi:cert_logger_proto
proto_library("cert_logger_proto") {
sources = [
"cert_logger.proto",
]
}
-# GYP version: components/certificate_reporting.gypi:encrypted_cert_logger_proto
proto_library("encrypted_cert_logger_proto") {
sources = [
"encrypted_cert_logger.proto",
diff --git a/chromium/components/certificate_reporting/error_reporter.cc b/chromium/components/certificate_reporting/error_reporter.cc
index a4beff826a7..3e639ea5d70 100644
--- a/chromium/components/certificate_reporting/error_reporter.cc
+++ b/chromium/components/certificate_reporting/error_reporter.cc
@@ -11,6 +11,8 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
#include "components/certificate_reporting/encrypted_cert_logger.pb.h"
#include "crypto/aead.h"
#include "crypto/curve25519.h"
@@ -98,6 +100,12 @@ bool EncryptSerializedReport(const uint8_t* server_public_key,
return true;
}
+// Records an UMA histogram of the net errors when certificate reports
+// fail to send.
+void RecordUMAOnFailure(const GURL& report_uri, int net_error) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("SSL.CertificateErrorReportFailure", -net_error);
+}
+
} // namespace
ErrorReporter::ErrorReporter(
@@ -108,8 +116,10 @@ ErrorReporter::ErrorReporter(
upload_url,
kServerPublicKey,
kServerPublicKeyVersion,
- base::WrapUnique(
- new net::ReportSender(request_context, cookies_preference))) {}
+ base::MakeUnique<net::ReportSender>(request_context,
+ cookies_preference,
+ base::Bind(RecordUMAOnFailure))) {
+}
ErrorReporter::ErrorReporter(
const GURL& upload_url,
@@ -129,9 +139,9 @@ ErrorReporter::~ErrorReporter() {}
void ErrorReporter::SendExtendedReportingReport(
const std::string& serialized_report) {
if (upload_url_.SchemeIsCryptographic()) {
- certificate_report_sender_->Send(upload_url_, serialized_report);
+ certificate_report_sender_->Send(upload_url_, "application/octet-stream",
+ serialized_report);
} else {
- DCHECK(IsHttpUploadUrlSupported());
EncryptedCertLoggerRequest encrypted_report;
if (!EncryptSerializedReport(server_public_key_, server_public_key_version_,
serialized_report, &encrypted_report)) {
@@ -140,14 +150,11 @@ void ErrorReporter::SendExtendedReportingReport(
}
std::string serialized_encrypted_report;
encrypted_report.SerializeToString(&serialized_encrypted_report);
- certificate_report_sender_->Send(upload_url_, serialized_encrypted_report);
+ certificate_report_sender_->Send(upload_url_, "application/octet-stream",
+ serialized_encrypted_report);
}
}
-bool ErrorReporter::IsHttpUploadUrlSupported() {
- return true;
-}
-
// Used only by tests.
bool ErrorReporter::DecryptErrorReport(
const uint8_t server_private_key[32],
diff --git a/chromium/components/certificate_reporting/error_reporter.h b/chromium/components/certificate_reporting/error_reporter.h
index ed4a1ee98ac..c4a15d6ef6b 100644
--- a/chromium/components/certificate_reporting/error_reporter.h
+++ b/chromium/components/certificate_reporting/error_reporter.h
@@ -63,9 +63,6 @@ class ErrorReporter {
virtual void SendExtendedReportingReport(
const std::string& serialized_report);
- // Whether sending reports over HTTP is supported.
- static bool IsHttpUploadUrlSupported();
-
// Used by tests.
static bool DecryptErrorReport(
const uint8_t server_private_key[32],
diff --git a/chromium/components/certificate_reporting/error_reporter_unittest.cc b/chromium/components/certificate_reporting/error_reporter_unittest.cc
index 5de9737c07a..6e83ca165be 100644
--- a/chromium/components/certificate_reporting/error_reporter_unittest.cc
+++ b/chromium/components/certificate_reporting/error_reporter_unittest.cc
@@ -14,9 +14,14 @@
#include "base/bind_helpers.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/histogram_tester.h"
#include "components/certificate_reporting/encrypted_cert_logger.pb.h"
#include "crypto/curve25519.h"
+#include "net/test/url_request/url_request_failed_job.h"
#include "net/url_request/report_sender.h"
+#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace certificate_reporting {
@@ -27,6 +32,7 @@ const char kDummyHttpReportUri[] = "http://example.test";
const char kDummyHttpsReportUri[] = "https://example.test";
const char kDummyReport[] = "a dummy report";
const uint32_t kServerPublicKeyTestVersion = 16;
+const char kFailureHistogramName[] = "SSL.CertificateErrorReportFailure";
// A mock ReportSender that keeps track of the last report
// sent.
@@ -36,22 +42,50 @@ class MockCertificateReportSender : public net::ReportSender {
: net::ReportSender(nullptr, DO_NOT_SEND_COOKIES) {}
~MockCertificateReportSender() override {}
- void Send(const GURL& report_uri, const std::string& report) override {
+ void Send(const GURL& report_uri,
+ base::StringPiece content_type,
+ base::StringPiece report) override {
latest_report_uri_ = report_uri;
- latest_report_ = report;
+ report.CopyToString(&latest_report_);
+ content_type.CopyToString(&latest_content_type_);
}
const GURL& latest_report_uri() { return latest_report_uri_; }
const std::string& latest_report() { return latest_report_; }
+ const std::string& latest_content_type() { return latest_content_type_; }
+
private:
GURL latest_report_uri_;
std::string latest_report_;
+ std::string latest_content_type_;
DISALLOW_COPY_AND_ASSIGN(MockCertificateReportSender);
};
+// A test network delegate that allows the user to specify a callback to
+// be run whenever a net::URLRequest is destroyed.
+class TestCertificateReporterNetworkDelegate : public net::NetworkDelegateImpl {
+ public:
+ TestCertificateReporterNetworkDelegate()
+ : url_request_destroyed_callback_(base::Bind(&base::DoNothing)) {}
+
+ void set_url_request_destroyed_callback(const base::Closure& callback) {
+ url_request_destroyed_callback_ = callback;
+ }
+
+ // net::NetworkDelegateImpl:
+ void OnURLRequestDestroyed(net::URLRequest* request) override {
+ url_request_destroyed_callback_.Run();
+ }
+
+ private:
+ base::Closure url_request_destroyed_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestCertificateReporterNetworkDelegate);
+};
+
class ErrorReporterTest : public ::testing::Test {
public:
ErrorReporterTest() {
@@ -62,8 +96,11 @@ class ErrorReporterTest : public ::testing::Test {
~ErrorReporterTest() override {}
protected:
+ base::MessageLoopForIO loop_;
uint8_t server_public_key_[32];
uint8_t server_private_key_[32];
+
+ DISALLOW_COPY_AND_ASSIGN(ErrorReporterTest);
};
// Test that ErrorReporter::SendExtendedReportingReport sends
@@ -81,30 +118,56 @@ TEST_F(ErrorReporterTest, ExtendedReportingSendReport) {
EXPECT_EQ(mock_report_sender->latest_report(), kDummyReport);
// Data should be encrypted when sent to an HTTP URL.
- if (ErrorReporter::IsHttpUploadUrlSupported()) {
- MockCertificateReportSender* http_mock_report_sender =
- new MockCertificateReportSender();
- GURL http_url(kDummyHttpReportUri);
- ErrorReporter http_reporter(http_url, server_public_key_,
- kServerPublicKeyTestVersion,
- base::WrapUnique(http_mock_report_sender));
- http_reporter.SendExtendedReportingReport(kDummyReport);
-
- EXPECT_EQ(http_mock_report_sender->latest_report_uri(), http_url);
-
- std::string uploaded_report;
- EncryptedCertLoggerRequest encrypted_request;
- ASSERT_TRUE(encrypted_request.ParseFromString(
- http_mock_report_sender->latest_report()));
- EXPECT_EQ(kServerPublicKeyTestVersion,
- encrypted_request.server_public_key_version());
- EXPECT_EQ(EncryptedCertLoggerRequest::AEAD_ECDH_AES_128_CTR_HMAC_SHA256,
- encrypted_request.algorithm());
- ASSERT_TRUE(ErrorReporter::DecryptErrorReport(
- server_private_key_, encrypted_request, &uploaded_report));
-
- EXPECT_EQ(kDummyReport, uploaded_report);
- }
+ MockCertificateReportSender* http_mock_report_sender =
+ new MockCertificateReportSender();
+ GURL http_url(kDummyHttpReportUri);
+ ErrorReporter http_reporter(http_url, server_public_key_,
+ kServerPublicKeyTestVersion,
+ base::WrapUnique(http_mock_report_sender));
+ http_reporter.SendExtendedReportingReport(kDummyReport);
+
+ EXPECT_EQ(http_mock_report_sender->latest_report_uri(), http_url);
+ EXPECT_EQ("application/octet-stream",
+ http_mock_report_sender->latest_content_type());
+
+ std::string uploaded_report;
+ EncryptedCertLoggerRequest encrypted_request;
+ ASSERT_TRUE(encrypted_request.ParseFromString(
+ http_mock_report_sender->latest_report()));
+ EXPECT_EQ(kServerPublicKeyTestVersion,
+ encrypted_request.server_public_key_version());
+ EXPECT_EQ(EncryptedCertLoggerRequest::AEAD_ECDH_AES_128_CTR_HMAC_SHA256,
+ encrypted_request.algorithm());
+ ASSERT_TRUE(ErrorReporter::DecryptErrorReport(
+ server_private_key_, encrypted_request, &uploaded_report));
+
+ EXPECT_EQ(kDummyReport, uploaded_report);
+}
+
+// Tests that an UMA histogram is recorded if a report fails to send.
+TEST_F(ErrorReporterTest, UMAOnFailure) {
+ net::URLRequestFailedJob::AddUrlHandler();
+
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kFailureHistogramName, 0);
+
+ base::RunLoop run_loop;
+ net::TestURLRequestContext context(true);
+ TestCertificateReporterNetworkDelegate test_delegate;
+ test_delegate.set_url_request_destroyed_callback(run_loop.QuitClosure());
+ context.set_network_delegate(&test_delegate);
+ context.Init();
+
+ GURL report_uri(
+ net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_FAILED));
+ ErrorReporter reporter(&context, report_uri,
+ net::ReportSender::DO_NOT_SEND_COOKIES);
+ reporter.SendExtendedReportingReport(kDummyReport);
+ run_loop.Run();
+
+ histograms.ExpectTotalCount(kFailureHistogramName, 1);
+ histograms.ExpectBucketCount(kFailureHistogramName,
+ -net::ERR_CONNECTION_FAILED, 1);
}
// This test decrypts a "known gold" report. It's intentionally brittle
diff --git a/chromium/components/certificate_transparency.gypi b/chromium/components/certificate_transparency.gypi
deleted file mode 100644
index 00a6e960d8d..00000000000
--- a/chromium/components/certificate_transparency.gypi
+++ /dev/null
@@ -1,37 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/certificate_transparency
- 'target_name': 'certificate_transparency',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../components/components.gyp:safe_json',
- '../components/components.gyp:url_matcher',
- '../components/prefs/prefs.gyp:prefs',
- '../components/url_formatter/url_formatter.gyp:url_formatter',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'certificate_transparency/ct_policy_manager.cc',
- 'certificate_transparency/ct_policy_manager.h',
- 'certificate_transparency/log_proof_fetcher.h',
- 'certificate_transparency/log_proof_fetcher.cc',
- 'certificate_transparency/pref_names.cc',
- 'certificate_transparency/pref_names.h',
- 'certificate_transparency/single_tree_tracker.cc',
- 'certificate_transparency/single_tree_tracker.h',
- 'certificate_transparency/tree_state_tracker.h',
- 'certificate_transparency/tree_state_tracker.cc',
- ],
- }
- ],
-}
diff --git a/chromium/components/certificate_transparency/BUILD.gn b/chromium/components/certificate_transparency/BUILD.gn
index 15cb99f3bec..ec807604be1 100644
--- a/chromium/components/certificate_transparency/BUILD.gn
+++ b/chromium/components/certificate_transparency/BUILD.gn
@@ -2,10 +2,12 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("certificate_transparency") {
+static_library("certificate_transparency") {
sources = [
"ct_policy_manager.cc",
"ct_policy_manager.h",
+ "log_dns_client.cc",
+ "log_dns_client.h",
"log_proof_fetcher.cc",
"log_proof_fetcher.h",
"pref_names.cc",
@@ -18,6 +20,7 @@ source_set("certificate_transparency") {
deps = [
"//base",
+ "//components/base32",
"//components/prefs",
"//components/safe_json",
"//components/url_formatter",
@@ -31,16 +34,19 @@ source_set("unit_tests") {
testonly = true
sources = [
"ct_policy_manager_unittest.cc",
+ "log_dns_client_unittest.cc",
"log_proof_fetcher_unittest.cc",
+ "mock_log_dns_traffic.cc",
+ "mock_log_dns_traffic.h",
"single_tree_tracker_unittest.cc",
]
-
deps = [
":certificate_transparency",
"//base/test:test_support",
"//components/prefs:test_support",
"//components/safe_json:test_support",
"//net:test_support",
+ "//testing/gmock",
"//testing/gtest",
]
}
diff --git a/chromium/components/certificate_transparency/DEPS b/chromium/components/certificate_transparency/DEPS
index b3d5f275485..575b1501408 100644
--- a/chromium/components/certificate_transparency/DEPS
+++ b/chromium/components/certificate_transparency/DEPS
@@ -1,7 +1,9 @@
include_rules = [
+ "+components/base32",
"+components/prefs",
"+components/safe_json",
"+components/url_formatter",
"+components/url_matcher",
+ "+crypto",
"+net",
]
diff --git a/chromium/components/certificate_transparency/log_dns_client.cc b/chromium/components/certificate_transparency/log_dns_client.cc
new file mode 100644
index 00000000000..ce7e8627a70
--- /dev/null
+++ b/chromium/components/certificate_transparency/log_dns_client.cc
@@ -0,0 +1,330 @@
+// 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 "components/certificate_transparency/log_dns_client.h"
+
+#include <sstream>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/base32/base32.h"
+#include "crypto/sha2.h"
+#include "net/base/net_errors.h"
+#include "net/cert/merkle_audit_proof.h"
+#include "net/dns/dns_client.h"
+#include "net/dns/dns_config_service.h"
+#include "net/dns/dns_protocol.h"
+#include "net/dns/dns_response.h"
+#include "net/dns/dns_transaction.h"
+#include "net/dns/record_parsed.h"
+#include "net/dns/record_rdata.h"
+
+namespace certificate_transparency {
+
+namespace {
+
+// Parses the DNS response and extracts a single string from the TXT RDATA.
+// If the response is malformed, not a TXT record, or contains any number of
+// strings other than 1, this returns false and extracts nothing.
+// Otherwise, it returns true and the extracted string is assigned to |*txt|.
+bool ParseTxtResponse(const net::DnsResponse& response, std::string* txt) {
+ DCHECK(txt);
+
+ net::DnsRecordParser parser = response.Parser();
+ // We don't care about the creation time, since we're going to throw
+ // |parsed_record| away as soon as we've extracted the payload, so provide
+ // the "null" time.
+ auto parsed_record = net::RecordParsed::CreateFrom(&parser, base::Time());
+ if (parsed_record == nullptr)
+ return false;
+
+ auto* txt_record = parsed_record->rdata<net::TxtRecordRdata>();
+ if (txt_record == nullptr)
+ return false;
+
+ // The draft CT-over-DNS RFC says that there MUST be exactly one string in the
+ // TXT record.
+ if (txt_record->texts().size() != 1)
+ return false;
+
+ *txt = txt_record->texts().front();
+ return true;
+}
+
+// Extracts a leaf index value from a DNS response's TXT RDATA.
+// Returns true on success, false otherwise.
+bool ParseLeafIndex(const net::DnsResponse& response, uint64_t* index) {
+ DCHECK(index);
+
+ std::string index_str;
+ if (!ParseTxtResponse(response, &index_str))
+ return false;
+
+ return base::StringToUint64(index_str, index);
+}
+
+// Extracts audit proof nodes from a DNS response's TXT RDATA.
+// Returns true on success, false otherwise.
+// It will fail if there is not a whole number of nodes present > 0.
+// There must only be one string in the TXT RDATA.
+// The nodes will be appended to |proof->nodes|
+bool ParseAuditPath(const net::DnsResponse& response,
+ net::ct::MerkleAuditProof* proof) {
+ DCHECK(proof);
+
+ std::string audit_path;
+ if (!ParseTxtResponse(response, &audit_path))
+ return false;
+ // If empty or not a multiple of the node size, it is considered invalid.
+ // It's important to consider empty audit paths as invalid, as otherwise an
+ // infinite loop could occur if the server consistently returned empty
+ // responses.
+ if (audit_path.empty() || audit_path.size() % crypto::kSHA256Length != 0)
+ return false;
+
+ for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) {
+ proof->nodes.push_back(audit_path.substr(i, crypto::kSHA256Length));
+ }
+
+ return true;
+}
+
+} // namespace
+
+LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
+ const net::NetLogWithSource& net_log)
+ : dns_client_(std::move(dns_client)),
+ net_log_(net_log),
+ weak_ptr_factory_(this) {
+ CHECK(dns_client_);
+ net::NetworkChangeNotifier::AddDNSObserver(this);
+ UpdateDnsConfig();
+}
+
+LogDnsClient::~LogDnsClient() {
+ net::NetworkChangeNotifier::RemoveDNSObserver(this);
+}
+
+void LogDnsClient::OnDNSChanged() {
+ UpdateDnsConfig();
+}
+
+void LogDnsClient::OnInitialDNSConfigRead() {
+ UpdateDnsConfig();
+}
+
+void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log,
+ base::StringPiece leaf_hash,
+ const LeafIndexCallback& callback) {
+ if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, 0));
+ return;
+ }
+
+ std::string encoded_leaf_hash =
+ base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING);
+ DCHECK_EQ(encoded_leaf_hash.size(), 52u);
+
+ net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
+ if (factory == nullptr) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, 0));
+ return;
+ }
+
+ std::ostringstream qname;
+ qname << encoded_leaf_hash << ".hash." << domain_for_log << ".";
+
+ net::DnsTransactionFactory::CallbackType transaction_callback = base::Bind(
+ &LogDnsClient::QueryLeafIndexComplete, weak_ptr_factory_.GetWeakPtr());
+
+ std::unique_ptr<net::DnsTransaction> dns_transaction =
+ factory->CreateTransaction(qname.str(), net::dns_protocol::kTypeTXT,
+ transaction_callback, net_log_);
+
+ dns_transaction->Start();
+ leaf_index_queries_.push_back({std::move(dns_transaction), callback});
+}
+
+// The performance of this could be improved by sending all of the expected
+// queries up front. Each response can contain a maximum of 7 audit path nodes,
+// so for an audit proof of size 20, it could send 3 queries (for nodes 0-6,
+// 7-13 and 14-19) immediately. Currently, it sends only the first and then,
+// based on the number of nodes received, sends the next query. The complexity
+// of the code would increase though, as it would need to detect gaps in the
+// audit proof caused by the server not responding with the anticipated number
+// of nodes. Ownership of the proof would need to change, as it would be shared
+// between simultaneous DNS transactions.
+void LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log,
+ uint64_t leaf_index,
+ uint64_t tree_size,
+ const AuditProofCallback& callback) {
+ if (domain_for_log.empty() || leaf_index >= tree_size) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr));
+ return;
+ }
+
+ std::unique_ptr<net::ct::MerkleAuditProof> proof(
+ new net::ct::MerkleAuditProof);
+ proof->leaf_index = leaf_index;
+ // TODO(robpercival): Once a "tree_size" field is added to MerkleAuditProof,
+ // pass |tree_size| to QueryAuditProofNodes using that.
+
+ // Query for the first batch of audit proof nodes (i.e. starting from 0).
+ QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, 0,
+ callback);
+}
+
+void LogDnsClient::QueryLeafIndexComplete(net::DnsTransaction* transaction,
+ int net_error,
+ const net::DnsResponse* response) {
+ auto query_iterator =
+ std::find_if(leaf_index_queries_.begin(), leaf_index_queries_.end(),
+ [transaction](const Query<LeafIndexCallback>& query) {
+ return query.transaction.get() == transaction;
+ });
+ if (query_iterator == leaf_index_queries_.end()) {
+ NOTREACHED();
+ return;
+ }
+ const Query<LeafIndexCallback> query = std::move(*query_iterator);
+ leaf_index_queries_.erase(query_iterator);
+
+ // If we've received no response but no net::error either (shouldn't happen),
+ // report the response as invalid.
+ if (response == nullptr && net_error == net::OK) {
+ net_error = net::ERR_INVALID_RESPONSE;
+ }
+
+ if (net_error != net::OK) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(query.callback, net_error, 0));
+ return;
+ }
+
+ uint64_t leaf_index;
+ if (!ParseLeafIndex(*response, &leaf_index)) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, 0));
+ return;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(query.callback, net::OK, leaf_index));
+}
+
+void LogDnsClient::QueryAuditProofNodes(
+ std::unique_ptr<net::ct::MerkleAuditProof> proof,
+ base::StringPiece domain_for_log,
+ uint64_t tree_size,
+ uint64_t node_index,
+ const AuditProofCallback& callback) {
+ // Preconditions that should be guaranteed internally by this class.
+ DCHECK(proof);
+ DCHECK(!domain_for_log.empty());
+ DCHECK_LT(proof->leaf_index, tree_size);
+ DCHECK_LT(node_index,
+ net::ct::CalculateAuditPathLength(proof->leaf_index, tree_size));
+
+ net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
+ if (factory == nullptr) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, nullptr));
+ return;
+ }
+
+ std::ostringstream qname;
+ qname << node_index << "." << proof->leaf_index << "." << tree_size
+ << ".tree." << domain_for_log << ".";
+
+ net::DnsTransactionFactory::CallbackType transaction_callback =
+ base::Bind(&LogDnsClient::QueryAuditProofNodesComplete,
+ weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(proof)),
+ domain_for_log, tree_size);
+
+ std::unique_ptr<net::DnsTransaction> dns_transaction =
+ factory->CreateTransaction(qname.str(), net::dns_protocol::kTypeTXT,
+ transaction_callback, net_log_);
+ dns_transaction->Start();
+ audit_proof_queries_.push_back({std::move(dns_transaction), callback});
+}
+
+void LogDnsClient::QueryAuditProofNodesComplete(
+ std::unique_ptr<net::ct::MerkleAuditProof> proof,
+ base::StringPiece domain_for_log,
+ uint64_t tree_size,
+ net::DnsTransaction* transaction,
+ int net_error,
+ const net::DnsResponse* response) {
+ // Preconditions that should be guaranteed internally by this class.
+ DCHECK(proof);
+ DCHECK(!domain_for_log.empty());
+
+ auto query_iterator =
+ std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(),
+ [transaction](const Query<AuditProofCallback>& query) {
+ return query.transaction.get() == transaction;
+ });
+
+ if (query_iterator == audit_proof_queries_.end()) {
+ NOTREACHED();
+ return;
+ }
+ const Query<AuditProofCallback> query = std::move(*query_iterator);
+ audit_proof_queries_.erase(query_iterator);
+
+ // If we've received no response but no net::error either (shouldn't happen),
+ // report the response as invalid.
+ if (response == nullptr && net_error == net::OK) {
+ net_error = net::ERR_INVALID_RESPONSE;
+ }
+
+ if (net_error != net::OK) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(query.callback, net_error, nullptr));
+ return;
+ }
+
+ const uint64_t audit_path_length =
+ net::ct::CalculateAuditPathLength(proof->leaf_index, tree_size);
+ proof->nodes.reserve(audit_path_length);
+
+ if (!ParseAuditPath(*response, proof.get())) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, nullptr));
+ return;
+ }
+
+ const uint64_t audit_path_nodes_received = proof->nodes.size();
+ if (audit_path_nodes_received < audit_path_length) {
+ QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size,
+ audit_path_nodes_received, query.callback);
+ return;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(query.callback, net::OK, base::Passed(std::move(proof))));
+}
+
+void LogDnsClient::UpdateDnsConfig() {
+ net::DnsConfig config;
+ net::NetworkChangeNotifier::GetDnsConfig(&config);
+ if (config.IsValid())
+ dns_client_->SetConfig(config);
+}
+
+} // namespace certificate_transparency
diff --git a/chromium/components/certificate_transparency/log_dns_client.h b/chromium/components/certificate_transparency/log_dns_client.h
new file mode 100644
index 00000000000..11b99990e2b
--- /dev/null
+++ b/chromium/components/certificate_transparency/log_dns_client.h
@@ -0,0 +1,136 @@
+// 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 COMPONENTS_CERTIFICATE_TRANSPARENCY_LOG_DNS_CLIENT_H_
+#define COMPONENTS_CERTIFICATE_TRANSPARENCY_LOG_DNS_CLIENT_H_
+
+#include <stdint.h>
+
+#include <list>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/network_change_notifier.h"
+#include "net/log/net_log_with_source.h"
+
+namespace net {
+class DnsClient;
+class DnsResponse;
+class DnsTransaction;
+namespace ct {
+struct MerkleAuditProof;
+} // namespace ct
+} // namespace net
+
+namespace certificate_transparency {
+
+// Queries Certificate Transparency (CT) log servers via DNS.
+// All queries are performed asynchronously.
+// For more information, see
+// https://github.com/google/certificate-transparency-rfcs/blob/master/dns/draft-ct-over-dns.md.
+// It must be created and deleted on the same thread. It is not thread-safe.
+class LogDnsClient : public net::NetworkChangeNotifier::DNSObserver {
+ public:
+ // Invoked when a leaf index query completes.
+ // If an error occured, |net_error| will be a net::Error code, otherwise it
+ // will be net::OK and |leaf_index| will be the leaf index that was received.
+ using LeafIndexCallback =
+ base::Callback<void(int net_error, uint64_t leaf_index)>;
+ // Invoked when an audit proof query completes.
+ // If an error occurred, |net_error| will be a net::Error code, otherwise it
+ // will be net::OK and |proof| will be the audit proof that was received.
+ // The log ID of |proof| will not be set, as that is not known by this class,
+ // but the leaf index will be set.
+ using AuditProofCallback =
+ base::Callback<void(int net_error,
+ std::unique_ptr<net::ct::MerkleAuditProof> proof)>;
+
+ // Creates a log client that will take ownership of |dns_client| and use it
+ // to perform DNS queries. Queries will be logged to |net_log|.
+ // The |dns_client| does not need to be configured first - this will be done
+ // automatically as needed.
+ LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
+ const net::NetLogWithSource& net_log);
+ // Must be deleted on the same thread that it was created on.
+ ~LogDnsClient() override;
+
+ // Called by NetworkChangeNotifier when the DNS config changes.
+ // The DnsClient's config will be updated in response.
+ void OnDNSChanged() override;
+
+ // Called by NetworkChangeNotifier when the DNS config is first read.
+ // The DnsClient's config will be updated in response.
+ void OnInitialDNSConfigRead() override;
+
+ // Queries a CT log to discover the index of the leaf with |leaf_hash|.
+ // The log is identified by |domain_for_log|, which is the DNS name used as a
+ // suffix for all queries.
+ // The |leaf_hash| is the SHA-256 hash of a Merkle tree leaf in that log.
+ // The |callback| is invoked when the query is complete, or an error occurs.
+ void QueryLeafIndex(base::StringPiece domain_for_log,
+ base::StringPiece leaf_hash,
+ const LeafIndexCallback& callback);
+
+ // Queries a CT log to retrieve an audit proof for the leaf at |leaf_index|.
+ // The size of the CT log tree must be provided in |tree_size|.
+ // The log is identified by |domain_for_log|, which is the DNS name used as a
+ // suffix for all queries.
+ // The |callback| is invoked when the query is complete, or an error occurs.
+ void QueryAuditProof(base::StringPiece domain_for_log,
+ uint64_t leaf_index,
+ uint64_t tree_size,
+ const AuditProofCallback& callback);
+
+ private:
+ void QueryLeafIndexComplete(net::DnsTransaction* transaction,
+ int neterror,
+ const net::DnsResponse* response);
+
+ // Queries a CT log to retrieve part of an audit |proof|. The |node_index|
+ // indicates which node of the audit proof/ should be requested. The CT log
+ // may return up to 7 nodes, starting from |node_index| (this is the maximum
+ // that will fit in a DNS UDP packet). The nodes will be appended to
+ // |proof->nodes|.
+ void QueryAuditProofNodes(std::unique_ptr<net::ct::MerkleAuditProof> proof,
+ base::StringPiece domain_for_log,
+ uint64_t tree_size,
+ uint64_t node_index,
+ const AuditProofCallback& callback);
+
+ void QueryAuditProofNodesComplete(
+ std::unique_ptr<net::ct::MerkleAuditProof> proof,
+ base::StringPiece domain_for_log,
+ uint64_t tree_size,
+ net::DnsTransaction* transaction,
+ int net_error,
+ const net::DnsResponse* response);
+
+ // Updates the |dns_client_| config using NetworkChangeNotifier.
+ void UpdateDnsConfig();
+
+ // A DNS query that is in flight.
+ template <typename CallbackType>
+ struct Query {
+ std::unique_ptr<net::DnsTransaction> transaction;
+ CallbackType callback;
+ };
+
+ // Used to perform DNS queries.
+ std::unique_ptr<net::DnsClient> dns_client_;
+ // Passed to the DNS client for logging.
+ net::NetLogWithSource net_log_;
+ // Leaf index queries that haven't completed yet.
+ std::list<Query<LeafIndexCallback>> leaf_index_queries_;
+ // Audit proof queries that haven't completed yet.
+ std::list<Query<AuditProofCallback>> audit_proof_queries_;
+ // Creates weak_ptrs to this, for callback purposes.
+ base::WeakPtrFactory<LogDnsClient> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(LogDnsClient);
+};
+
+} // namespace certificate_transparency
+#endif // COMPONENTS_CERTIFICATE_TRANSPARENCY_LOG_DNS_CLIENT_H_
diff --git a/chromium/components/certificate_transparency/log_dns_client_unittest.cc b/chromium/components/certificate_transparency/log_dns_client_unittest.cc
new file mode 100644
index 00000000000..5f7a0240273
--- /dev/null
+++ b/chromium/components/certificate_transparency/log_dns_client_unittest.cc
@@ -0,0 +1,615 @@
+// 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 "components/certificate_transparency/log_dns_client.h"
+
+#include <memory>
+#include <numeric>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "components/certificate_transparency/mock_log_dns_traffic.h"
+#include "crypto/sha2.h"
+#include "net/base/net_errors.h"
+#include "net/cert/merkle_audit_proof.h"
+#include "net/cert/signed_certificate_timestamp.h"
+#include "net/dns/dns_client.h"
+#include "net/dns/dns_config_service.h"
+#include "net/dns/dns_protocol.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace certificate_transparency {
+namespace {
+
+using ::testing::IsEmpty;
+using ::testing::IsNull;
+using ::testing::Not;
+using ::testing::NotNull;
+using net::test::IsError;
+using net::test::IsOk;
+
+constexpr char kLeafHash[] =
+ "\x1f\x25\xe1\xca\xba\x4f\xf9\xb8\x27\x24\x83\x0f\xca\x60\xe4\xc2\xbe\xa8"
+ "\xc3\xa9\x44\x1c\x27\xb0\xb4\x3e\x6a\x96\x94\xc7\xb8\x04";
+
+std::vector<std::string> GetSampleAuditProof(size_t length) {
+ std::vector<std::string> audit_proof(length);
+ // Makes each node of the audit proof different, so that tests are able to
+ // confirm that the audit proof is reconstructed in the correct order.
+ for (size_t i = 0; i < length; ++i) {
+ std::string node(crypto::kSHA256Length, '\0');
+ // Each node is 32 bytes, with each byte having a different value.
+ for (size_t j = 0; j < crypto::kSHA256Length; ++j) {
+ node[j] = static_cast<char>((-127 + i + j) % 128);
+ }
+ audit_proof[i].assign(std::move(node));
+ }
+
+ return audit_proof;
+}
+
+class MockLeafIndexCallback {
+ public:
+ MockLeafIndexCallback() : called_(false) {}
+
+ bool called() const { return called_; }
+ int net_error() const { return net_error_; }
+ uint64_t leaf_index() const { return leaf_index_; }
+
+ void Run(int net_error, uint64_t leaf_index) {
+ EXPECT_TRUE(!called_);
+ called_ = true;
+ net_error_ = net_error;
+ leaf_index_ = leaf_index;
+ run_loop_.Quit();
+ }
+
+ LogDnsClient::LeafIndexCallback AsCallback() {
+ return base::Bind(&MockLeafIndexCallback::Run, base::Unretained(this));
+ }
+
+ void WaitUntilRun() { run_loop_.Run(); }
+
+ private:
+ bool called_;
+ int net_error_;
+ uint64_t leaf_index_;
+ base::RunLoop run_loop_;
+};
+
+class MockAuditProofCallback {
+ public:
+ MockAuditProofCallback() : called_(false) {}
+
+ bool called() const { return called_; }
+ int net_error() const { return net_error_; }
+ const net::ct::MerkleAuditProof* proof() const { return proof_.get(); }
+
+ void Run(int net_error, std::unique_ptr<net::ct::MerkleAuditProof> proof) {
+ EXPECT_TRUE(!called_);
+ called_ = true;
+ net_error_ = net_error;
+ proof_ = std::move(proof);
+ run_loop_.Quit();
+ }
+
+ LogDnsClient::AuditProofCallback AsCallback() {
+ return base::Bind(&MockAuditProofCallback::Run, base::Unretained(this));
+ }
+
+ void WaitUntilRun() { run_loop_.Run(); }
+
+ private:
+ bool called_;
+ int net_error_;
+ std::unique_ptr<net::ct::MerkleAuditProof> proof_;
+ base::RunLoop run_loop_;
+};
+
+class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> {
+ protected:
+ LogDnsClientTest()
+ : network_change_notifier_(net::NetworkChangeNotifier::CreateMock()) {
+ mock_dns_.SetSocketReadMode(GetParam());
+ mock_dns_.InitializeDnsConfig();
+ }
+
+ void QueryLeafIndex(base::StringPiece log_domain,
+ base::StringPiece leaf_hash,
+ MockLeafIndexCallback* callback) {
+ LogDnsClient log_client(mock_dns_.CreateDnsClient(),
+ net::NetLogWithSource());
+ log_client.QueryLeafIndex(log_domain, leaf_hash, callback->AsCallback());
+ callback->WaitUntilRun();
+ }
+
+ void QueryAuditProof(base::StringPiece log_domain,
+ uint64_t leaf_index,
+ uint64_t tree_size,
+ MockAuditProofCallback* callback) {
+ LogDnsClient log_client(mock_dns_.CreateDnsClient(),
+ net::NetLogWithSource());
+ log_client.QueryAuditProof(log_domain, leaf_index, tree_size,
+ callback->AsCallback());
+ callback->WaitUntilRun();
+ }
+
+ // This will be the NetworkChangeNotifier singleton for the duration of the
+ // test. It is accessed statically by LogDnsClient.
+ std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
+ // Queues and handles asynchronous DNS tasks. Indirectly used by LogDnsClient,
+ // the underlying net::DnsClient, and NetworkChangeNotifier.
+ base::MessageLoopForIO message_loop_;
+ // Allows mock DNS sockets to be setup.
+ MockLogDnsTraffic mock_dns_;
+};
+
+TEST_P(LogDnsClientTest, QueryLeafIndex) {
+ mock_dns_.ExpectLeafIndexRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ 123456);
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsOk());
+ EXPECT_THAT(callback.leaf_index(), 123456);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsThatLogDomainDoesNotExist) {
+ mock_dns_.ExpectRequestAndErrorResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ net::dns_protocol::kRcodeNXDOMAIN);
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_NAME_NOT_RESOLVED));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsServerFailure) {
+ mock_dns_.ExpectRequestAndErrorResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ net::dns_protocol::kRcodeSERVFAIL);
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_SERVER_FAILED));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsServerRefusal) {
+ mock_dns_.ExpectRequestAndErrorResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ net::dns_protocol::kRcodeREFUSED);
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_SERVER_FAILED));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+ QueryLeafIndexReportsMalformedResponseIfContainsNoStrings) {
+ mock_dns_.ExpectRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ std::vector<base::StringPiece>());
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+ QueryLeafIndexReportsMalformedResponseIfContainsMoreThanOneString) {
+ mock_dns_.ExpectRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ {"123456", "7"});
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+ QueryLeafIndexReportsMalformedResponseIfLeafIndexIsNotNumeric) {
+ mock_dns_.ExpectRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ {"foo"});
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+ QueryLeafIndexReportsMalformedResponseIfLeafIndexIsFloatingPoint) {
+ mock_dns_.ExpectRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ {"123456.0"});
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+ QueryLeafIndexReportsMalformedResponseIfLeafIndexIsEmpty) {
+ mock_dns_.ExpectRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ {""});
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+ QueryLeafIndexReportsMalformedResponseIfLeafIndexHasNonNumericPrefix) {
+ mock_dns_.ExpectRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ {"foo123456"});
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+ QueryLeafIndexReportsMalformedResponseIfLeafIndexHasNonNumericSuffix) {
+ mock_dns_.ExpectRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ {"123456foo"});
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsEmpty) {
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsNull) {
+ MockLeafIndexCallback callback;
+ QueryLeafIndex(nullptr, kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsInvalid) {
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", "foo", &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsEmpty) {
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", "", &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsNull) {
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", nullptr, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsSocketError) {
+ mock_dns_.ExpectRequestAndSocketError(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ net::ERR_CONNECTION_REFUSED);
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_CONNECTION_REFUSED));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsTimeout) {
+ mock_dns_.ExpectRequestAndTimeout(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.");
+
+ MockLeafIndexCallback callback;
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_TIMED_OUT));
+ EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProof) {
+ const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
+
+ // It should require 3 queries to collect the entire audit proof, as there is
+ // only space for 7 nodes per UDP packet.
+ mock_dns_.ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+ audit_proof.begin(),
+ audit_proof.begin() + 7);
+ mock_dns_.ExpectAuditProofRequestAndResponse("7.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 7,
+ audit_proof.begin() + 14);
+ mock_dns_.ExpectAuditProofRequestAndResponse("14.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 14,
+ audit_proof.end());
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsOk());
+ ASSERT_THAT(callback.proof(), NotNull());
+ EXPECT_THAT(callback.proof()->leaf_index, 123456);
+ // EXPECT_THAT(callback.proof()->tree_size, 999999);
+ EXPECT_THAT(callback.proof()->nodes, audit_proof);
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofHandlesResponsesWithShortAuditPaths) {
+ const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
+
+ // Make some of the responses contain fewer proof nodes than they can hold.
+ mock_dns_.ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+ audit_proof.begin(),
+ audit_proof.begin() + 1);
+ mock_dns_.ExpectAuditProofRequestAndResponse("1.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 1,
+ audit_proof.begin() + 3);
+ mock_dns_.ExpectAuditProofRequestAndResponse("3.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 3,
+ audit_proof.begin() + 6);
+ mock_dns_.ExpectAuditProofRequestAndResponse("6.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 6,
+ audit_proof.begin() + 10);
+ mock_dns_.ExpectAuditProofRequestAndResponse("10.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 10,
+ audit_proof.begin() + 13);
+ mock_dns_.ExpectAuditProofRequestAndResponse("13.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 13,
+ audit_proof.end());
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsOk());
+ ASSERT_THAT(callback.proof(), NotNull());
+ EXPECT_THAT(callback.proof()->leaf_index, 123456);
+ // EXPECT_THAT(callback.proof()->tree_size, 999999);
+ EXPECT_THAT(callback.proof()->nodes, audit_proof);
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsThatLogDomainDoesNotExist) {
+ mock_dns_.ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
+ net::dns_protocol::kRcodeNXDOMAIN);
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_NAME_NOT_RESOLVED));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsServerFailure) {
+ mock_dns_.ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
+ net::dns_protocol::kRcodeSERVFAIL);
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_SERVER_FAILED));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsServerRefusal) {
+ mock_dns_.ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
+ net::dns_protocol::kRcodeREFUSED);
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_SERVER_FAILED));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest,
+ QueryAuditProofReportsResponseMalformedIfContainsNoStrings) {
+ mock_dns_.ExpectRequestAndResponse("0.123456.999999.tree.ct.test.",
+ std::vector<base::StringPiece>());
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest,
+ QueryAuditProofReportsResponseMalformedIfContainsMoreThanOneString) {
+ // The CT-over-DNS draft RFC states that the response will contain "exactly
+ // one character-string."
+ const std::vector<std::string> audit_proof = GetSampleAuditProof(10);
+
+ std::string first_chunk_of_proof = std::accumulate(
+ audit_proof.begin(), audit_proof.begin() + 7, std::string());
+ std::string second_chunk_of_proof = std::accumulate(
+ audit_proof.begin() + 7, audit_proof.end(), std::string());
+
+ mock_dns_.ExpectRequestAndResponse(
+ "0.123456.999999.tree.ct.test.",
+ {first_chunk_of_proof, second_chunk_of_proof});
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest,
+ QueryAuditProofReportsResponseMalformedIfNodeTooShort) {
+ // node is shorter than a SHA-256 hash (31 vs 32 bytes)
+ const std::vector<std::string> audit_proof(1, std::string(31, 'a'));
+
+ mock_dns_.ExpectAuditProofRequestAndResponse(
+ "0.123456.999999.tree.ct.test.", audit_proof.begin(), audit_proof.end());
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsResponseMalformedIfNodeTooLong) {
+ // node is longer than a SHA-256 hash (33 vs 32 bytes)
+ const std::vector<std::string> audit_proof(1, std::string(33, 'a'));
+
+ mock_dns_.ExpectAuditProofRequestAndResponse(
+ "0.123456.999999.tree.ct.test.", audit_proof.begin(), audit_proof.end());
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsResponseMalformedIfEmpty) {
+ const std::vector<std::string> audit_proof;
+
+ mock_dns_.ExpectAuditProofRequestAndResponse(
+ "0.123456.999999.tree.ct.test.", audit_proof.begin(), audit_proof.end());
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsInvalidArgIfLogDomainIsEmpty) {
+ MockAuditProofCallback callback;
+ QueryAuditProof("", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsInvalidArgIfLogDomainIsNull) {
+ MockAuditProofCallback callback;
+ QueryAuditProof(nullptr, 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest,
+ QueryAuditProofReportsInvalidArgIfLeafIndexEqualToTreeSize) {
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 123456, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest,
+ QueryAuditProofReportsInvalidArgIfLeafIndexGreaterThanTreeSize) {
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 999999, 123456, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsSocketError) {
+ mock_dns_.ExpectRequestAndSocketError("0.123456.999999.tree.ct.test.",
+ net::ERR_CONNECTION_REFUSED);
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_CONNECTION_REFUSED));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsTimeout) {
+ mock_dns_.ExpectRequestAndTimeout("0.123456.999999.tree.ct.test.");
+
+ MockAuditProofCallback callback;
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+ ASSERT_TRUE(callback.called());
+ EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_TIMED_OUT));
+ EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, AdoptsLatestDnsConfigIfValid) {
+ std::unique_ptr<net::DnsClient> tmp = mock_dns_.CreateDnsClient();
+ net::DnsClient* dns_client = tmp.get();
+ LogDnsClient log_client(std::move(tmp), net::NetLogWithSource());
+
+ // Get the current DNS config, modify it and broadcast the update.
+ net::DnsConfig config(*dns_client->GetConfig());
+ ASSERT_NE(123, config.attempts);
+ config.attempts = 123;
+ mock_dns_.SetDnsConfig(config);
+
+ // Let the DNS config change propogate.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(123, dns_client->GetConfig()->attempts);
+}
+
+TEST_P(LogDnsClientTest, IgnoresLatestDnsConfigIfInvalid) {
+ std::unique_ptr<net::DnsClient> tmp = mock_dns_.CreateDnsClient();
+ net::DnsClient* dns_client = tmp.get();
+ LogDnsClient log_client(std::move(tmp), net::NetLogWithSource());
+
+ // Get the current DNS config, modify it and broadcast the update.
+ net::DnsConfig config(*dns_client->GetConfig());
+ ASSERT_THAT(config.nameservers, Not(IsEmpty()));
+ config.nameservers.clear(); // Makes config invalid
+ mock_dns_.SetDnsConfig(config);
+
+ // Let the DNS config change propogate.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(dns_client->GetConfig()->nameservers, Not(IsEmpty()));
+}
+
+INSTANTIATE_TEST_CASE_P(ReadMode,
+ LogDnsClientTest,
+ ::testing::Values(net::IoMode::ASYNC,
+ net::IoMode::SYNCHRONOUS));
+
+} // namespace
+} // namespace certificate_transparency
diff --git a/chromium/components/certificate_transparency/log_proof_fetcher.cc b/chromium/components/certificate_transparency/log_proof_fetcher.cc
index 0cfcc39a5e0..4a1a3902d0b 100644
--- a/chromium/components/certificate_transparency/log_proof_fetcher.cc
+++ b/chromium/components/certificate_transparency/log_proof_fetcher.cc
@@ -10,9 +10,9 @@
#include "base/callback_helpers.h"
#include "base/format_macros.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/numerics/safe_conversions.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "components/safe_json/safe_json_parser.h"
@@ -47,7 +47,7 @@ class LogFetcher : public net::URLRequest::Delegate {
~LogFetcher() override {}
// net::URLRequest::Delegate
- void OnResponseStarted(net::URLRequest* request) override;
+ void OnResponseStarted(net::URLRequest* request, int net_error) override;
void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
const std::string& assembled_response() const { return assembled_response_; }
@@ -57,7 +57,7 @@ class LogFetcher : public net::URLRequest::Delegate {
// Returns true if another read should be started, false if the read
// failed completely or we have to wait for OnResponseStarted to
// be called.
- bool HandleReadResult(int bytes_read);
+ bool HandleReadResult(int result);
// Calls URLRequest::Read on |request| repeatedly, until HandleReadResult
// indicates it should no longer be called. Usually this would be when there
@@ -102,12 +102,13 @@ LogFetcher::LogFetcher(net::URLRequestContext* request_context,
url_request_->Start();
}
-void LogFetcher::OnResponseStarted(net::URLRequest* request) {
+void LogFetcher::OnResponseStarted(net::URLRequest* request, int net_error) {
+ DCHECK_NE(net::ERR_IO_PENDING, net_error);
DCHECK_EQ(url_request_.get(), request);
int http_response_code = request->GetResponseCode();
- if (!request->status().is_success()) {
- InvokeFailureCallback(request->status().error(), http_response_code);
+ if (net_error != net::OK) {
+ InvokeFailureCallback(net_error, http_response_code);
return;
}
@@ -133,53 +134,43 @@ void LogFetcher::OnReadCompleted(net::URLRequest* request, int bytes_read) {
StartNextReadLoop();
}
-bool LogFetcher::HandleReadResult(int bytes_read) {
- // Start by checking for an error condition.
- // If there are errors, invoke the failure callback and clean up the
- // request.
- if (!url_request_->status().is_success() || bytes_read < 0) {
- int net_error = url_request_->status().error();
- if (net_error == net::OK)
- net_error = net::URLRequestStatus::FAILED;
-
- InvokeFailureCallback(net_error, net::HTTP_OK);
+bool LogFetcher::HandleReadResult(int result) {
+ if (result == net::ERR_IO_PENDING)
return false;
- }
- // Not an error, but no data available, so wait for OnReadCompleted
- // callback.
- if (url_request_->status().is_io_pending())
+ if (result < 0) {
+ InvokeFailureCallback(result, net::HTTP_OK);
return false;
+ }
// Nothing more to read from the stream - finish handling the response.
- if (bytes_read == 0) {
+ if (result == 0) {
RequestComplete();
return false;
}
// Data is available, collect it and indicate another read is needed.
- DCHECK_GE(bytes_read, 0);
- // |bytes_read| is non-negative at this point, casting to size_t should be
+ DCHECK_GE(result, 0);
+ // |result| is non-negative at this point, casting to size_t should be
// safe.
- if (base::checked_cast<size_t>(bytes_read) >
+ if (base::checked_cast<size_t>(result) >
LogProofFetcher::kMaxLogResponseSizeInBytes ||
LogProofFetcher::kMaxLogResponseSizeInBytes <
- (assembled_response_.size() + bytes_read)) {
+ (assembled_response_.size() + result)) {
// Log response is too big, invoke the failure callback.
InvokeFailureCallback(net::ERR_FILE_TOO_BIG, net::HTTP_OK);
return false;
}
- assembled_response_.append(response_buffer_->data(), bytes_read);
+ assembled_response_.append(response_buffer_->data(), result);
return true;
}
void LogFetcher::StartNextReadLoop() {
bool continue_reading = true;
while (continue_reading) {
- int read_bytes = 0;
- url_request_->Read(response_buffer_.get(), response_buffer_->size(),
- &read_bytes);
+ int read_bytes =
+ url_request_->Read(response_buffer_.get(), response_buffer_->size());
continue_reading = HandleReadResult(read_bytes);
}
}
@@ -397,8 +388,6 @@ LogProofFetcher::LogProofFetcher(net::URLRequestContext* request_context)
}
LogProofFetcher::~LogProofFetcher() {
- STLDeleteContainerPointers(inflight_fetches_.begin(),
- inflight_fetches_.end());
}
void LogProofFetcher::FetchSignedTreeHead(
@@ -407,8 +396,8 @@ void LogProofFetcher::FetchSignedTreeHead(
const SignedTreeHeadFetchedCallback& fetched_callback,
const FetchFailedCallback& failed_callback) {
GURL request_url = base_log_url.Resolve("ct/v1/get-sth");
- StartFetch(request_url, new GetSTHLogResponseHandler(log_id, fetched_callback,
- failed_callback));
+ StartFetch(request_url, base::MakeUnique<GetSTHLogResponseHandler>(
+ log_id, fetched_callback, failed_callback));
}
void LogProofFetcher::FetchConsistencyProof(
@@ -421,24 +410,30 @@ void LogProofFetcher::FetchConsistencyProof(
GURL request_url = base_log_url.Resolve(base::StringPrintf(
"ct/v1/get-sth-consistency?first=%" PRIu64 "&second=%" PRIu64,
old_tree_size, new_tree_size));
- StartFetch(request_url, new GetConsistencyProofLogResponseHandler(
- log_id, fetched_callback, failed_callback));
+ StartFetch(request_url,
+ base::MakeUnique<GetConsistencyProofLogResponseHandler>(
+ log_id, fetched_callback, failed_callback));
}
-void LogProofFetcher::StartFetch(const GURL& request_url,
- LogResponseHandler* log_request) {
- log_request->StartFetch(request_context_, request_url,
- base::Bind(&LogProofFetcher::OnFetchDone,
- weak_factory_.GetWeakPtr(), log_request));
- inflight_fetches_.insert(log_request);
+void LogProofFetcher::StartFetch(
+ const GURL& request_url,
+ std::unique_ptr<LogResponseHandler> log_request) {
+ log_request->StartFetch(
+ request_context_, request_url,
+ base::Bind(&LogProofFetcher::OnFetchDone, weak_factory_.GetWeakPtr(),
+ log_request.get()));
+ inflight_fetches_.insert(std::move(log_request));
}
void LogProofFetcher::OnFetchDone(LogResponseHandler* log_handler,
const base::Closure& requestor_callback) {
- auto it = inflight_fetches_.find(log_handler);
+ auto it = std::find_if(
+ inflight_fetches_.begin(), inflight_fetches_.end(),
+ [log_handler](const std::unique_ptr<LogResponseHandler>& ptr) {
+ return ptr.get() == log_handler;
+ });
DCHECK(it != inflight_fetches_.end());
- delete *it;
inflight_fetches_.erase(it);
requestor_callback.Run();
}
diff --git a/chromium/components/certificate_transparency/log_proof_fetcher.h b/chromium/components/certificate_transparency/log_proof_fetcher.h
index 7a0c82fbeb1..7c760a330a8 100644
--- a/chromium/components/certificate_transparency/log_proof_fetcher.h
+++ b/chromium/components/certificate_transparency/log_proof_fetcher.h
@@ -108,7 +108,8 @@ class LogProofFetcher {
// Starts the fetch (by delegating to the LogResponseHandler)
// and stores the |log_handler| in |inflight_fetches_| for later
// cleanup.
- void StartFetch(const GURL& request_url, LogResponseHandler* log_handler);
+ void StartFetch(const GURL& request_url,
+ std::unique_ptr<LogResponseHandler> log_request);
// Callback for when the fetch was done (successfully or not).
// Deletes, and removes, the |log_handler| from the |inflight_fetches_|.
@@ -120,7 +121,7 @@ class LogProofFetcher {
net::URLRequestContext* const request_context_;
- std::set<LogResponseHandler*> inflight_fetches_;
+ std::set<std::unique_ptr<LogResponseHandler>> inflight_fetches_;
base::WeakPtrFactory<LogProofFetcher> weak_factory_;
diff --git a/chromium/components/certificate_transparency/mock_log_dns_traffic.cc b/chromium/components/certificate_transparency/mock_log_dns_traffic.cc
new file mode 100644
index 00000000000..22599950dd7
--- /dev/null
+++ b/chromium/components/certificate_transparency/mock_log_dns_traffic.cc
@@ -0,0 +1,271 @@
+// 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 "components/certificate_transparency/mock_log_dns_traffic.h"
+
+#include <algorithm>
+#include <numeric>
+#include <vector>
+
+#include "base/big_endian.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/sys_byteorder.h"
+#include "base/test/test_timeouts.h"
+#include "net/dns/dns_client.h"
+#include "net/dns/dns_protocol.h"
+#include "net/dns/dns_util.h"
+#include "net/socket/socket_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace certificate_transparency {
+
+namespace {
+
+// Necessary to expose SetDnsConfig for testing.
+class DnsChangeNotifier : public net::NetworkChangeNotifier {
+ public:
+ static void SetInitialDnsConfig(const net::DnsConfig& config) {
+ net::NetworkChangeNotifier::SetInitialDnsConfig(config);
+ }
+
+ static void SetDnsConfig(const net::DnsConfig& config) {
+ net::NetworkChangeNotifier::SetDnsConfig(config);
+ }
+};
+
+// Always return min, to simplify testing.
+// This should result in the DNS query ID always being 0.
+int FakeRandInt(int min, int max) {
+ return min;
+}
+
+std::vector<char> CreateDnsTxtRequest(base::StringPiece qname) {
+ std::string encoded_qname;
+ EXPECT_TRUE(net::DNSDomainFromDot(qname, &encoded_qname));
+
+ // DNS query section:
+ // N bytes - qname
+ // 2 bytes - record type
+ // 2 bytes - record class
+ // Total = N + 4 bytes
+ const size_t query_section_size = encoded_qname.size() + 4;
+
+ std::vector<char> request(sizeof(net::dns_protocol::Header) +
+ query_section_size);
+ base::BigEndianWriter writer(request.data(), request.size());
+
+ // Header
+ net::dns_protocol::Header header = {};
+ header.flags = base::HostToNet16(net::dns_protocol::kFlagRD);
+ header.qdcount = base::HostToNet16(1);
+ EXPECT_TRUE(writer.WriteBytes(&header, sizeof(header)));
+ // Query section
+ EXPECT_TRUE(writer.WriteBytes(encoded_qname.data(), encoded_qname.size()));
+ EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kTypeTXT));
+ EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kClassIN));
+ EXPECT_EQ(0, writer.remaining());
+
+ return request;
+}
+
+std::vector<char> CreateDnsTxtResponse(const std::vector<char>& request,
+ base::StringPiece answer) {
+ // DNS answers section:
+ // 2 bytes - qname pointer
+ // 2 bytes - record type
+ // 2 bytes - record class
+ // 4 bytes - time-to-live
+ // 2 bytes - size of answer (N)
+ // N bytes - answer
+ // Total = 12 + N bytes
+ const size_t answers_section_size = 12 + answer.size();
+ constexpr uint32_t ttl = 86400; // seconds
+
+ std::vector<char> response(request.size() + answers_section_size);
+ std::copy(request.begin(), request.end(), response.begin());
+ // Modify the header
+ net::dns_protocol::Header* header =
+ reinterpret_cast<net::dns_protocol::Header*>(response.data());
+ header->ancount = base::HostToNet16(1);
+ header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse);
+
+ // Write the answer section
+ base::BigEndianWriter writer(response.data() + request.size(),
+ response.size() - request.size());
+ EXPECT_TRUE(writer.WriteU8(0xc0)); // qname is a pointer
+ EXPECT_TRUE(writer.WriteU8(
+ sizeof(*header))); // address of qname (start of query section)
+ EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kTypeTXT));
+ EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kClassIN));
+ EXPECT_TRUE(writer.WriteU32(ttl));
+ EXPECT_TRUE(writer.WriteU16(answer.size()));
+ EXPECT_TRUE(writer.WriteBytes(answer.data(), answer.size()));
+ EXPECT_EQ(0, writer.remaining());
+
+ return response;
+}
+
+std::vector<char> CreateDnsErrorResponse(const std::vector<char>& request,
+ uint8_t rcode) {
+ std::vector<char> response(request);
+ // Modify the header
+ net::dns_protocol::Header* header =
+ reinterpret_cast<net::dns_protocol::Header*>(response.data());
+ header->ancount = base::HostToNet16(1);
+ header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse | rcode);
+
+ return response;
+}
+
+} // namespace
+
+namespace internal {
+
+MockSocketData::MockSocketData(const std::vector<char>& write,
+ const std::vector<char>& read)
+ : expected_write_payload_(write),
+ expected_read_payload_(read),
+ expected_write_(net::SYNCHRONOUS,
+ expected_write_payload_.data(),
+ expected_write_payload_.size(),
+ 0),
+ expected_reads_{net::MockRead(net::ASYNC,
+ expected_read_payload_.data(),
+ expected_read_payload_.size(),
+ 1),
+ no_more_data_},
+ socket_data_(expected_reads_, 2, &expected_write_, 1) {}
+
+MockSocketData::MockSocketData(const std::vector<char>& write, int net_error)
+ : expected_write_payload_(write),
+ expected_write_(net::SYNCHRONOUS,
+ expected_write_payload_.data(),
+ expected_write_payload_.size(),
+ 0),
+ expected_reads_{net::MockRead(net::ASYNC, net_error, 1), no_more_data_},
+ socket_data_(expected_reads_, 2, &expected_write_, 1) {}
+
+MockSocketData::MockSocketData(const std::vector<char>& write)
+ : expected_write_payload_(write),
+ expected_write_(net::SYNCHRONOUS,
+ expected_write_payload_.data(),
+ expected_write_payload_.size(),
+ 0),
+ expected_reads_{net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING, 1),
+ no_more_data_},
+ socket_data_(expected_reads_, 2, &expected_write_, 1) {}
+
+MockSocketData::~MockSocketData() {}
+
+void MockSocketData::AddToFactory(
+ net::MockClientSocketFactory* socket_factory) {
+ socket_factory->AddSocketDataProvider(&socket_data_);
+}
+
+const net::MockRead MockSocketData::no_more_data_(net::SYNCHRONOUS,
+ net::ERR_IO_PENDING,
+ 2);
+
+} // namespace internal
+
+using internal::MockSocketData;
+
+MockLogDnsTraffic::MockLogDnsTraffic() : socket_read_mode_(net::ASYNC) {}
+
+MockLogDnsTraffic::~MockLogDnsTraffic() {}
+
+void MockLogDnsTraffic::ExpectRequestAndErrorResponse(base::StringPiece qname,
+ uint8_t rcode) {
+ std::vector<char> request = CreateDnsTxtRequest(qname);
+ EmplaceMockSocketData(CreateDnsTxtRequest(qname),
+ CreateDnsErrorResponse(request, rcode));
+}
+
+void MockLogDnsTraffic::ExpectRequestAndSocketError(base::StringPiece qname,
+ int net_error) {
+ EmplaceMockSocketData(CreateDnsTxtRequest(qname), net_error);
+}
+
+void MockLogDnsTraffic::ExpectRequestAndTimeout(base::StringPiece qname) {
+ EmplaceMockSocketData(CreateDnsTxtRequest(qname));
+
+ // Speed up timeout tests.
+ SetDnsTimeout(TestTimeouts::tiny_timeout());
+}
+
+void MockLogDnsTraffic::ExpectRequestAndResponse(
+ base::StringPiece qname,
+ const std::vector<base::StringPiece>& txt_strings) {
+ std::string answer;
+ for (base::StringPiece str : txt_strings) {
+ // The size of the string must precede it. The size must fit into 1 byte.
+ answer.insert(answer.end(), base::checked_cast<uint8_t>(str.size()));
+ str.AppendToString(&answer);
+ }
+
+ std::vector<char> request = CreateDnsTxtRequest(qname);
+ EmplaceMockSocketData(request, CreateDnsTxtResponse(request, answer));
+}
+
+void MockLogDnsTraffic::ExpectLeafIndexRequestAndResponse(
+ base::StringPiece qname,
+ uint64_t leaf_index) {
+ ExpectRequestAndResponse(qname, { base::Uint64ToString(leaf_index) });
+}
+
+void MockLogDnsTraffic::ExpectAuditProofRequestAndResponse(
+ base::StringPiece qname,
+ std::vector<std::string>::const_iterator audit_path_start,
+ std::vector<std::string>::const_iterator audit_path_end) {
+ // Join nodes in the audit path into a single string.
+ std::string proof =
+ std::accumulate(audit_path_start, audit_path_end, std::string());
+
+ ExpectRequestAndResponse(qname, { proof });
+}
+
+void MockLogDnsTraffic::InitializeDnsConfig() {
+ net::DnsConfig dns_config;
+ // Use an invalid nameserver address. This prevents the tests accidentally
+ // sending real DNS queries. The mock sockets don't care that the address
+ // is invalid.
+ dns_config.nameservers.push_back(net::IPEndPoint());
+ // Don't attempt retransmissions - just fail.
+ dns_config.attempts = 1;
+ // This ensures timeouts are long enough for memory tests.
+ dns_config.timeout = TestTimeouts::action_timeout();
+ // Simplify testing - don't require random numbers for the source port.
+ // This means our FakeRandInt function should only be called to get query
+ // IDs.
+ dns_config.randomize_ports = false;
+
+ DnsChangeNotifier::SetInitialDnsConfig(dns_config);
+}
+
+void MockLogDnsTraffic::SetDnsConfig(const net::DnsConfig& config) {
+ DnsChangeNotifier::SetDnsConfig(config);
+}
+
+std::unique_ptr<net::DnsClient> MockLogDnsTraffic::CreateDnsClient() {
+ return net::DnsClient::CreateClientForTesting(nullptr, &socket_factory_,
+ base::Bind(&FakeRandInt));
+}
+
+template <typename... Args>
+void MockLogDnsTraffic::EmplaceMockSocketData(Args&&... args) {
+ mock_socket_data_.emplace_back(
+ new MockSocketData(std::forward<Args>(args)...));
+ mock_socket_data_.back()->SetReadMode(socket_read_mode_);
+ mock_socket_data_.back()->AddToFactory(&socket_factory_);
+}
+
+void MockLogDnsTraffic::SetDnsTimeout(const base::TimeDelta& timeout) {
+ net::DnsConfig dns_config;
+ DnsChangeNotifier::GetDnsConfig(&dns_config);
+ dns_config.timeout = timeout;
+ DnsChangeNotifier::SetDnsConfig(dns_config);
+}
+
+} // namespace certificate_transparency
diff --git a/chromium/components/certificate_transparency/mock_log_dns_traffic.h b/chromium/components/certificate_transparency/mock_log_dns_traffic.h
new file mode 100644
index 00000000000..2496737f864
--- /dev/null
+++ b/chromium/components/certificate_transparency/mock_log_dns_traffic.h
@@ -0,0 +1,162 @@
+// 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 COMPONENTS_CERTIFICATE_TRANSPARENCY_MOCK_LOG_DNS_TRAFFIC_H_
+#define COMPONENTS_CERTIFICATE_TRANSPARENCY_MOCK_LOG_DNS_TRAFFIC_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/dns/dns_client.h"
+#include "net/dns/dns_config_service.h"
+#include "net/socket/socket_test_util.h"
+
+namespace certificate_transparency {
+
+namespace internal {
+
+// A container for all of the data we need to keep alive for a mock socket.
+// This is useful because Mock{Read,Write}, SequencedSocketData and
+// MockClientSocketFactory all do not take ownership of or copy their arguments,
+// so we have to manage the lifetime of those arguments ourselves. Wrapping all
+// of that up in a single class simplifies this.
+// This cannot be forward declared because MockLogDnsTraffic has a
+// vector<unique_ptr<MockSocketData>> member, which requires MockSocketData be
+// defined.
+class MockSocketData {
+ public:
+ // A socket that expects one write and one read operation.
+ MockSocketData(const std::vector<char>& write, const std::vector<char>& read);
+ // A socket that expects one write and a read error.
+ MockSocketData(const std::vector<char>& write, int net_error);
+ // A socket that expects one write and no response.
+ explicit MockSocketData(const std::vector<char>& write);
+
+ ~MockSocketData();
+
+ void SetWriteMode(net::IoMode mode) { expected_write_.mode = mode; }
+ void SetReadMode(net::IoMode mode) { expected_reads_[0].mode = mode; }
+
+ void AddToFactory(net::MockClientSocketFactory* socket_factory);
+
+ private:
+ // Prevents read overruns and makes a socket timeout the default behaviour.
+ static const net::MockRead no_more_data_;
+
+ // This class only supports one write and one read, so just need to store one
+ // payload each.
+ const std::vector<char> expected_write_payload_;
+ const std::vector<char> expected_read_payload_;
+ // Encapsulates the data that is expected to be written to a socket.
+ net::MockWrite expected_write_;
+ // Encapsulates the data/error that should be returned when reading from a
+ // socket. The second "expected" read is always |no_more_data_|, which
+ // causes the socket read to hang until it times out. This results in better
+ // test failure messages (rather than a CHECK-fail due to a socket read
+ // overrunning the MockRead array) and behaviour more like a real socket when
+ // an unexpected second socket read occurs.
+ net::MockRead expected_reads_[2];
+ // Holds pointers to |expected_write_| and |expected_reads_|. This is what is
+ // added to net::MockClientSocketFactory to prepare a mock socket.
+ net::SequencedSocketData socket_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockSocketData);
+};
+
+} // namespace internal
+
+// Mocks DNS requests and responses for a Certificate Transparency (CT) log.
+// This is implemented using mock sockets. Call the CreateDnsClient() method to
+// get a net::DnsClient wired up to these mock sockets.
+// The Expect*() methods must be called from within a GTest test case.
+class MockLogDnsTraffic {
+ public:
+ MockLogDnsTraffic();
+ ~MockLogDnsTraffic();
+
+ // Expect a CT DNS request for the domain |qname|.
+ // Such a request will receive a DNS response indicating that the error
+ // specified by |rcode| occurred. See RFC1035, Section 4.1.1 for |rcode|
+ // values.
+ void ExpectRequestAndErrorResponse(base::StringPiece qname, uint8_t rcode);
+ // Expect a CT DNS request for the domain |qname|.
+ // Such a request will trigger a socket error of type |net_error|.
+ // |net_error| can be any net:Error value.
+ void ExpectRequestAndSocketError(base::StringPiece qname, int net_error);
+ // Expect a CT DNS request for the domain |qname|.
+ // Such a request will timeout.
+ // This will reduce the DNS timeout to minimize test duration.
+ void ExpectRequestAndTimeout(base::StringPiece qname);
+ // Expect a CT DNS request for the domain |qname|.
+ // Such a request will receive a DNS TXT response containing |txt_strings|.
+ void ExpectRequestAndResponse(
+ base::StringPiece qname,
+ const std::vector<base::StringPiece>& txt_strings);
+ // Expect a CT DNS request for the domain |qname|.
+ // Such a request will receive a DNS response containing |leaf_index|.
+ // A description of such a request and response can be seen here:
+ // https://github.com/google/certificate-transparency-rfcs/blob/c8844de6bd0b5d3d16bac79865e6edef533d760b/dns/draft-ct-over-dns.md#hash-query-hashquery
+ void ExpectLeafIndexRequestAndResponse(base::StringPiece qname,
+ uint64_t leaf_index);
+ // Expect a CT DNS request for the domain |qname|.
+ // Such a request will receive a DNS response containing the inclusion proof
+ // nodes between |audit_path_start| and |audit_path_end|.
+ // A description of such a request and response can be seen here:
+ // https://github.com/google/certificate-transparency-rfcs/blob/c8844de6bd0b5d3d16bac79865e6edef533d760b/dns/draft-ct-over-dns.md#tree-query-treequery
+ void ExpectAuditProofRequestAndResponse(
+ base::StringPiece qname,
+ std::vector<std::string>::const_iterator audit_path_start,
+ std::vector<std::string>::const_iterator audit_path_end);
+
+ // Sets the initial DNS config appropriate for testing.
+ // Requires that net::NetworkChangeNotifier is initialized first.
+ // The DNS config is propogated to NetworkChangeNotifier::DNSObservers
+ // asynchronously.
+ void InitializeDnsConfig();
+
+ // Sets the DNS config to |config|.
+ // Requires that net::NetworkChangeNotifier is initialized first.
+ // The DNS config is propogated to NetworkChangeNotifier::DNSObservers
+ // asynchronously.
+ void SetDnsConfig(const net::DnsConfig& config);
+
+ // Creates a DNS client that uses mock sockets.
+ // It is this DNS client that the expectations will be tested against.
+ std::unique_ptr<net::DnsClient> CreateDnsClient();
+
+ // Sets whether mock reads should complete synchronously or asynchronously.
+ void SetSocketReadMode(net::IoMode read_mode) {
+ socket_read_mode_ = read_mode;
+ }
+
+ private:
+ // Constructs MockSocketData from |args| and adds it to |socket_factory_|.
+ template <typename... Args>
+ void EmplaceMockSocketData(Args&&... args);
+
+ // Sets the timeout used for DNS queries.
+ // Requires that net::NetworkChangeNotifier is initialized first.
+ // The new timeout is propogated to NetworkChangeNotifier::DNSObservers
+ // asynchronously.
+ void SetDnsTimeout(const base::TimeDelta& timeout);
+
+ // One MockSocketData for each socket that is created. This corresponds to one
+ // for each DNS request sent.
+ std::vector<std::unique_ptr<internal::MockSocketData>> mock_socket_data_;
+ // Provides as many mock sockets as there are entries in |mock_socket_data_|.
+ net::MockClientSocketFactory socket_factory_;
+ // Controls whether mock socket reads are asynchronous.
+ net::IoMode socket_read_mode_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockLogDnsTraffic);
+};
+
+} // namespace certificate_transparency
+
+#endif // COMPONENTS_CERTIFICATE_TRANSPARENCY_MOCK_LOG_DNS_TRAFFIC_H_
diff --git a/chromium/components/certificate_transparency/single_tree_tracker.cc b/chromium/components/certificate_transparency/single_tree_tracker.cc
index 7946208ca75..adaf04d4e1d 100644
--- a/chromium/components/certificate_transparency/single_tree_tracker.cc
+++ b/chromium/components/certificate_transparency/single_tree_tracker.cc
@@ -6,12 +6,45 @@
#include <utility>
+#include "base/metrics/histogram_macros.h"
#include "net/cert/ct_log_verifier.h"
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/x509_certificate.h"
using net::ct::SignedTreeHead;
+namespace {
+
+// Enum indicating whether an SCT can be checked for inclusion and if not,
+// the reason it cannot.
+//
+// Note: The numeric values are used within a histogram and should not change
+// or be re-assigned.
+enum SCTCanBeCheckedForInclusion {
+ // If the SingleTreeTracker does not have a valid STH, then a valid STH is
+ // first required to evaluate whether the SCT can be checked for inclusion
+ // or not.
+ VALID_STH_REQUIRED = 0,
+ // If the STH does not cover the SCT (the timestamp in the SCT is greater than
+ // MMD + timestamp in the STH), then a newer STH is needed.
+ NEWER_STH_REQUIRED = 1,
+ // When an SCT is observed, if the SingleTreeTracker instance has a valid STH
+ // and the STH covers the SCT (the timestamp in the SCT is less than MMD +
+ // timestamp in the STH), then it can be checked for inclusion.
+ CAN_BE_CHECKED = 2,
+ SCT_CAN_BE_CHECKED_MAX
+};
+
+// Measure how often clients encounter very new SCTs, by measuring whether an
+// SCT can be checked for inclusion upon first observation.
+void LogCanBeCheckedForInclusionToUMA(
+ SCTCanBeCheckedForInclusion can_be_checked) {
+ UMA_HISTOGRAM_ENUMERATION("Net.CertificateTransparency.CanInclusionCheckSCT",
+ can_be_checked, SCT_CAN_BE_CHECKED_MAX);
+}
+
+} // namespace
+
namespace certificate_transparency {
SingleTreeTracker::SingleTreeTracker(
@@ -34,15 +67,20 @@ void SingleTreeTracker::OnSCTVerified(
if (verified_sth_.timestamp.is_null() ||
(verified_sth_.timestamp <
(sct->timestamp + base::TimeDelta::FromHours(24)))) {
- // TODO(eranm): UMA - how often SCTs have to wait for a newer STH for
- // inclusion check.
entries_status_.insert(
std::make_pair(sct->timestamp, SCT_PENDING_NEWER_STH));
+
+ if (!verified_sth_.timestamp.is_null()) {
+ LogCanBeCheckedForInclusionToUMA(NEWER_STH_REQUIRED);
+ } else {
+ LogCanBeCheckedForInclusionToUMA(VALID_STH_REQUIRED);
+ }
+
return;
}
+ LogCanBeCheckedForInclusionToUMA(CAN_BE_CHECKED);
// TODO(eranm): Check inclusion here.
- // TODO(eranm): UMA - how often inclusion can be checked immediately.
entries_status_.insert(
std::make_pair(sct->timestamp, SCT_PENDING_INCLUSION_CHECK));
}
diff --git a/chromium/components/certificate_transparency/single_tree_tracker_unittest.cc b/chromium/components/certificate_transparency/single_tree_tracker_unittest.cc
index cbdfe6175b8..43ea4fd446a 100644
--- a/chromium/components/certificate_transparency/single_tree_tracker_unittest.cc
+++ b/chromium/components/certificate_transparency/single_tree_tracker_unittest.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/strings/string_piece.h"
+#include "base/test/histogram_tester.h"
#include "net/cert/ct_log_verifier.h"
#include "net/cert/ct_serialization.h"
#include "net/cert/signed_certificate_timestamp.h"
@@ -20,6 +21,9 @@ namespace certificate_transparency {
namespace {
+const char kCanCheckForInclusionHistogramName[] =
+ "Net.CertificateTransparency.CanInclusionCheckSCT";
+
bool GetOldSignedTreeHead(net::ct::SignedTreeHead* sth) {
sth->version = net::ct::SignedTreeHead::V1;
sth->timestamp = base::Time::UnixEpoch() +
@@ -51,8 +55,9 @@ bool GetOldSignedTreeHead(net::ct::SignedTreeHead* sth) {
class SingleTreeTrackerTest : public ::testing::Test {
void SetUp() override {
- log_ = net::CTLogVerifier::Create(net::ct::GetTestPublicKey(), "testlog",
- "https://ct.example.com");
+ log_ =
+ net::CTLogVerifier::Create(net::ct::GetTestPublicKey(), "testlog",
+ "https://ct.example.com", "dns.example.com");
ASSERT_TRUE(log_);
ASSERT_EQ(log_->key_id(), net::ct::GetTestPublicKeyId());
@@ -75,6 +80,7 @@ class SingleTreeTrackerTest : public ::testing::Test {
// Test that an SCT is classified as pending for a newer STH if the
// SingleTreeTracker has not seen any STHs so far.
TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTNoSTH) {
+ base::HistogramTester histograms;
// First make sure the SCT has not been observed at all.
EXPECT_EQ(
SingleTreeTracker::SCT_NOT_OBSERVED,
@@ -87,11 +93,16 @@ TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTNoSTH) {
EXPECT_EQ(
SingleTreeTracker::SCT_PENDING_NEWER_STH,
tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get()));
+
+ // Expect logging of a value indicating a valid STH is required.
+ histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1);
+ histograms.ExpectBucketCount(kCanCheckForInclusionHistogramName, 0, 1);
}
// Test that an SCT is classified as pending an inclusion check if the
// SingleTreeTracker has a fresh-enough STH to check inclusion against.
TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTWithRecentSTH) {
+ base::HistogramTester histograms;
// Provide an STH to the tree_tracker_.
net::ct::SignedTreeHead sth;
net::ct::GetSampleSignedTreeHead(&sth);
@@ -110,18 +121,26 @@ TEST_F(SingleTreeTrackerTest, CorrectlyClassifiesUnobservedSCTWithRecentSTH) {
EXPECT_EQ(
SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK,
tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get()));
+
+ // Exactly one value should be logged, indicating the SCT can be checked for
+ // inclusion, as |tree_tracker_| did have a valid STH when it was notified
+ // of a new SCT.
+ histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1);
+ histograms.ExpectBucketCount(kCanCheckForInclusionHistogramName, 2, 1);
}
// Test that the SingleTreeTracker correctly queues verified SCTs for inclusion
// checking such that, upon receiving a fresh STH, it changes the SCT's status
// from pending newer STH to pending inclusion check.
TEST_F(SingleTreeTrackerTest, CorrectlyUpdatesSCTStatusOnNewSTH) {
+ base::HistogramTester histograms;
// Report an observed SCT and make sure it's in the pending newer STH
// state.
tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get());
EXPECT_EQ(
SingleTreeTracker::SCT_PENDING_NEWER_STH,
tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get()));
+ histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1);
// Provide with a fresh STH
net::ct::SignedTreeHead sth;
@@ -132,6 +151,10 @@ TEST_F(SingleTreeTrackerTest, CorrectlyUpdatesSCTStatusOnNewSTH) {
EXPECT_EQ(
SingleTreeTracker::SCT_PENDING_INCLUSION_CHECK,
tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get()));
+ // Check that no additional UMA was logged for this case as the histogram is
+ // only supposed to measure the state of newly-observed SCTs, not pending
+ // ones.
+ histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1);
}
// Test that the SingleTreeTracker does not change an SCT's status if an STH
@@ -155,4 +178,25 @@ TEST_F(SingleTreeTrackerTest, DoesNotUpdatesSCTStatusOnOldSTH) {
tree_tracker_->GetLogEntryInclusionStatus(chain_.get(), cert_sct_.get()));
}
+// Test that the SingleTreeTracker correctly logs that an SCT is pending a new
+// STH, when it has a valid STH, but the observed SCT is not covered by the
+// STH.
+TEST_F(SingleTreeTrackerTest, LogsUMAForNewSCTAndOldSTH) {
+ base::HistogramTester histograms;
+ // Provide an old STH for the same log.
+ net::ct::SignedTreeHead sth;
+ GetOldSignedTreeHead(&sth);
+ tree_tracker_->NewSTHObserved(sth);
+
+ histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 0);
+
+ // Notify of an SCT and make sure it's in the 'pending newer STH' state.
+ tree_tracker_->OnSCTVerified(chain_.get(), cert_sct_.get());
+
+ // Exactly one value should be logged, indicating the SCT cannot be checked
+ // for inclusion as the STH is too old.
+ histograms.ExpectTotalCount(kCanCheckForInclusionHistogramName, 1);
+ histograms.ExpectBucketCount(kCanCheckForInclusionHistogramName, 1, 1);
+}
+
} // namespace certificate_transparency
diff --git a/chromium/components/chooser_controller.gypi b/chromium/components/chooser_controller.gypi
deleted file mode 100644
index 98d0cd308bf..00000000000
--- a/chromium/components/chooser_controller.gypi
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'targets': [
- {
- # GN version: //components/chooser_controller
- 'target_name': 'chooser_controller',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'chooser_controller/chooser_controller.cc',
- 'chooser_controller/chooser_controller.h',
- ],
- },
- {
- 'target_name': 'chooser_controller_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../testing/gmock.gyp:gmock',
- 'chooser_controller',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'chooser_controller/mock_chooser_controller.cc',
- 'chooser_controller/mock_chooser_controller.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/chooser_controller/BUILD.gn b/chromium/components/chooser_controller/BUILD.gn
deleted file mode 100644
index 5e8b8e166a1..00000000000
--- a/chromium/components/chooser_controller/BUILD.gn
+++ /dev/null
@@ -1,34 +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.
-
-source_set("chooser_controller") {
- sources = [
- "chooser_controller.cc",
- "chooser_controller.h",
- ]
-
- deps = [
- "//base",
- "//content/public/browser",
- "//url",
- ]
-}
-
-source_set("test_support") {
- testonly = true
-
- sources = [
- "mock_chooser_controller.cc",
- "mock_chooser_controller.h",
- ]
-
- deps = [
- ":chooser_controller",
- "//base",
- ]
-
- public_deps = [
- "//testing/gmock",
- ]
-}
diff --git a/chromium/components/chooser_controller/DEPS b/chromium/components/chooser_controller/DEPS
deleted file mode 100644
index 1c35d9ca694..00000000000
--- a/chromium/components/chooser_controller/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+content/public/browser",
-]
diff --git a/chromium/components/chooser_controller/OWNERS b/chromium/components/chooser_controller/OWNERS
deleted file mode 100644
index 298cd1c35f0..00000000000
--- a/chromium/components/chooser_controller/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-juncai@chromium.org
-reillyg@chromium.org
diff --git a/chromium/components/chooser_controller/README b/chromium/components/chooser_controller/README
deleted file mode 100644
index 7981b8829c1..00000000000
--- a/chromium/components/chooser_controller/README
+++ /dev/null
@@ -1,2 +0,0 @@
-This directory contains an interface for a chooser controller which has
-a list of options that users can pick one of.
diff --git a/chromium/components/chooser_controller/chooser_controller.cc b/chromium/components/chooser_controller/chooser_controller.cc
deleted file mode 100644
index 3099cef5b8b..00000000000
--- a/chromium/components/chooser_controller/chooser_controller.cc
+++ /dev/null
@@ -1,18 +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 "components/chooser_controller/chooser_controller.h"
-
-#include "content/public/browser/render_frame_host.h"
-#include "url/origin.h"
-
-ChooserController::ChooserController(content::RenderFrameHost* owner)
- : owning_frame_(owner) {}
-
-ChooserController::~ChooserController() {}
-
-url::Origin ChooserController::GetOrigin() const {
- return owning_frame_ ? owning_frame_->GetLastCommittedOrigin()
- : url::Origin();
-}
diff --git a/chromium/components/chooser_controller/chooser_controller.h b/chromium/components/chooser_controller/chooser_controller.h
deleted file mode 100644
index 24af5d545bc..00000000000
--- a/chromium/components/chooser_controller/chooser_controller.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CHOOSER_CONTROLLER_CHOOSER_CONTROLLER_H_
-#define COMPONENTS_CHOOSER_CONTROLLER_CHOOSER_CONTROLLER_H_
-
-#include "base/macros.h"
-#include "base/strings/string16.h"
-
-namespace content {
-class RenderFrameHost;
-}
-
-namespace url {
-class Origin;
-}
-
-// Subclass ChooserController to implement a chooser, which has some
-// introductory text and a list of options that users can pick one of.
-// Your subclass must define the set of options users can pick from;
-// the actions taken after users select an item or press the 'Cancel'
-// button or the chooser is closed.
-// After Select/Cancel/Close is called, this object is destroyed and
-// calls back into it are not allowed.
-class ChooserController {
- public:
- explicit ChooserController(content::RenderFrameHost* owner);
- virtual ~ChooserController();
-
- // Since the set of options can change while the UI is visible an
- // implementation should register an observer.
- class Observer {
- public:
- // Called after the options list is initialized for the first time.
- // OnOptionsInitialized should only be called once.
- virtual void OnOptionsInitialized() = 0;
-
- // Called after GetOption(index) has been added to the options and the
- // newly added option is the last element in the options list. Calling
- // GetOption(index) from inside a call to OnOptionAdded will see the
- // added string since the options have already been updated.
- virtual void OnOptionAdded(size_t index) = 0;
-
- // Called when GetOption(index) is no longer present, and all later
- // options have been moved earlier by 1 slot. Calling GetOption(index)
- // from inside a call to OnOptionRemoved will NOT see the removed string
- // since the options have already been updated.
- virtual void OnOptionRemoved(size_t index) = 0;
-
- protected:
- virtual ~Observer() {}
- };
-
- // Return the origin URL to be displayed on the chooser title.
- url::Origin GetOrigin() const;
-
- // The number of options users can pick from. For example, it can be
- // the number of USB/Bluetooth device names which are listed in the
- // chooser so that users can grant permission.
- virtual size_t NumOptions() const = 0;
-
- // The |index|th option string which is listed in the chooser.
- virtual const base::string16& GetOption(size_t index) const = 0;
-
- // These three functions are called just before this object is destroyed:
-
- // Called when the user selects the |index|th element from the dialog.
- virtual void Select(size_t index) = 0;
-
- // Called when the user presses the 'Cancel' button in the dialog.
- virtual void Cancel() = 0;
-
- // Called when the user clicks outside the dialog or the dialog otherwise
- // closes without the user taking an explicit action.
- virtual void Close() = 0;
-
- // Open help center URL.
- virtual void OpenHelpCenterUrl() const = 0;
-
- // Only one observer may be registered at a time.
- void set_observer(Observer* observer) { observer_ = observer; }
- Observer* observer() const { return observer_; }
-
- private:
- content::RenderFrameHost* owning_frame_;
- Observer* observer_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(ChooserController);
-};
-
-#endif // COMPONENTS_CHOOSER_CONTROLLER_CHOOSER_CONTROLLER_H_
diff --git a/chromium/components/chooser_controller/mock_chooser_controller.cc b/chromium/components/chooser_controller/mock_chooser_controller.cc
deleted file mode 100644
index bc40544f170..00000000000
--- a/chromium/components/chooser_controller/mock_chooser_controller.cc
+++ /dev/null
@@ -1,36 +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 "components/chooser_controller/mock_chooser_controller.h"
-
-MockChooserController::MockChooserController(content::RenderFrameHost* owner)
- : ChooserController(owner) {}
-
-MockChooserController::~MockChooserController() {}
-
-size_t MockChooserController::NumOptions() const {
- return option_names_.size();
-}
-
-const base::string16& MockChooserController::GetOption(size_t index) const {
- return option_names_[index];
-}
-
-void MockChooserController::OptionAdded(const base::string16 option_name) {
- option_names_.push_back(option_name);
- if (observer())
- observer()->OnOptionAdded(option_names_.size() - 1);
-}
-
-void MockChooserController::OptionRemoved(const base::string16 option_name) {
- for (auto it = option_names_.begin(); it != option_names_.end(); ++it) {
- if (*it == option_name) {
- size_t index = it - option_names_.begin();
- option_names_.erase(it);
- if (observer())
- observer()->OnOptionRemoved(index);
- return;
- }
- }
-}
diff --git a/chromium/components/chooser_controller/mock_chooser_controller.h b/chromium/components/chooser_controller/mock_chooser_controller.h
deleted file mode 100644
index c0875582395..00000000000
--- a/chromium/components/chooser_controller/mock_chooser_controller.h
+++ /dev/null
@@ -1,36 +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 COMPONENTS_CHOOSER_CONTROLLER_MOCK_CHOOSER_CONTROLLER_H_
-#define COMPONENTS_CHOOSER_CONTROLLER_MOCK_CHOOSER_CONTROLLER_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "components/chooser_controller/chooser_controller.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-class MockChooserController : public ChooserController {
- public:
- explicit MockChooserController(content::RenderFrameHost* owner);
- ~MockChooserController() override;
-
- // ChooserController:
- size_t NumOptions() const override;
- const base::string16& GetOption(size_t index) const override;
- MOCK_METHOD1(Select, void(size_t index));
- MOCK_METHOD0(Cancel, void());
- MOCK_METHOD0(Close, void());
- MOCK_CONST_METHOD0(OpenHelpCenterUrl, void());
-
- void OptionAdded(const base::string16 option_name);
- void OptionRemoved(const base::string16 option_name);
-
- private:
- std::vector<base::string16> option_names_;
-
- DISALLOW_COPY_AND_ASSIGN(MockChooserController);
-};
-
-#endif // COMPONENTS_CHOOSER_CONTROLLER_MOCK_CHOOSER_CONTROLLER_H_
diff --git a/chromium/components/chrome_apps.gypi b/chromium/components/chrome_apps.gypi
deleted file mode 100644
index 4d01ece34f3..00000000000
--- a/chromium/components/chrome_apps.gypi
+++ /dev/null
@@ -1,51 +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.
-{
- 'variables': {
- 'chromium_code': 1,
- 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/components/chrome_apps',
- },
- 'targets': [
- {
- 'target_name': 'chrome_apps_resources',
- 'type': 'none',
- 'actions': [
- {
- 'action_name': 'chrome_apps_resources',
- 'variables': {
- 'grit_grd_file': 'chrome_apps/chrome_apps_resources.grd',
- },
- 'includes': [ '../build/grit_action.gypi' ],
- },
- ],
- 'includes': [ '../build/grit_target.gypi' ],
- 'copies': [
- {
- 'destination': '<(PRODUCT_DIR)',
- 'files': [
- '<(SHARED_INTERMEDIATE_DIR)/components/chrome_apps/chrome_apps_resources.pak',
- ],
- },
- ],
- },
- {
- 'target_name': 'chrome_apps',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- 'chrome_apps_resources',
- ],
- 'defines': [
- 'CHROME_APPS_IMPLEMENTATION',
- ],
- 'sources': [
- '<(grit_out_dir)/grit/chrome_apps_resources_map.cc',
- '<(grit_out_dir)/grit/chrome_apps_resources_map.h',
- 'chrome_apps/chrome_apps_export.h',
- 'chrome_apps/chrome_apps_resource_util.cc',
- 'chrome_apps/chrome_apps_resource_util.h',
- ]
- }
- ]
-}
diff --git a/chromium/components/chrome_apps/BUILD.gn b/chromium/components/chrome_apps/BUILD.gn
index 6b7b67ae175..74f27a9efd3 100644
--- a/chromium/components/chrome_apps/BUILD.gn
+++ b/chromium/components/chrome_apps/BUILD.gn
@@ -21,9 +21,11 @@ component("chrome_apps") {
"chrome_apps_resource_util.cc",
"chrome_apps_resource_util.h",
]
- deps = [
+
+ defines = [ "CHROME_APPS_IMPLEMENTATION" ]
+
+ public_deps = [
":resources",
"//base",
]
- defines = [ "CHROME_APPS_IMPLEMENTATION" ]
}
diff --git a/chromium/components/client_update_protocol.gypi b/chromium/components/client_update_protocol.gypi
deleted file mode 100644
index ba395d06f96..00000000000
--- a/chromium/components/client_update_protocol.gypi
+++ /dev/null
@@ -1,41 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/client_update_protocol
- 'target_name': 'client_update_protocol',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- ],
-
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'client_update_protocol/ecdsa.h',
- 'client_update_protocol/ecdsa.cc',
- ],
- },
- {
- # GN version: //components/client_update_protocol:test_support
- 'target_name': 'client_update_protocol_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'update_client',
- '../testing/gtest.gyp:gtest',
- ],
-
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'client_update_protocol/ecdsa_unittest.cc',
- ],
- },
- ],
-}
diff --git a/chromium/components/client_update_protocol/BUILD.gn b/chromium/components/client_update_protocol/BUILD.gn
index e3af8836de7..e22ee24d20e 100644
--- a/chromium/components/client_update_protocol/BUILD.gn
+++ b/chromium/components/client_update_protocol/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("client_update_protocol") {
+static_library("client_update_protocol") {
sources = [
"ecdsa.cc",
"ecdsa.h",
diff --git a/chromium/components/cloud_devices.gypi b/chromium/components/cloud_devices.gypi
deleted file mode 100644
index 8edf24d17d9..00000000000
--- a/chromium/components/cloud_devices.gypi
+++ /dev/null
@@ -1,35 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'cloud_devices_common',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'cloud_devices/common/cloud_device_description.cc',
- 'cloud_devices/common/cloud_device_description.h',
- 'cloud_devices/common/cloud_device_description_consts.cc',
- 'cloud_devices/common/cloud_device_description_consts.h',
- 'cloud_devices/common/cloud_devices_switches.cc',
- 'cloud_devices/common/cloud_devices_switches.h',
- 'cloud_devices/common/cloud_devices_urls.cc',
- 'cloud_devices/common/cloud_devices_urls.h',
- 'cloud_devices/common/description_items.h',
- 'cloud_devices/common/description_items_inl.h',
- 'cloud_devices/common/printer_description.cc',
- 'cloud_devices/common/printer_description.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/cloud_devices/common/description_items_inl.h b/chromium/components/cloud_devices/common/description_items_inl.h
index f36a595ce84..3c303105328 100644
--- a/chromium/components/cloud_devices/common/description_items_inl.h
+++ b/chromium/components/cloud_devices/common/description_items_inl.h
@@ -7,6 +7,8 @@
#include <stddef.h>
+#include <memory>
+#include <utility>
#include <vector>
#include "base/numerics/safe_conversions.h"
@@ -65,9 +67,10 @@ void ListCapability<Option, Traits>::SaveTo(
base::ListValue* options_list =
description->CreateListItem(Traits::GetCapabilityPath());
for (size_t i = 0; i < options_.size(); ++i) {
- base::DictionaryValue* option_value = new base::DictionaryValue;
- options_list->Append(option_value);
- Traits::Save(options_[i], option_value);
+ std::unique_ptr<base::DictionaryValue> option_value(
+ new base::DictionaryValue);
+ Traits::Save(options_[i], option_value.get());
+ options_list->Append(std::move(option_value));
}
}
@@ -127,11 +130,12 @@ void SelectionCapability<Option, Traits>::SaveTo(
description->CreateItem(Traits::GetCapabilityPath())
->Set(json::kKeyOption, options_list);
for (size_t i = 0; i < options_.size(); ++i) {
- base::DictionaryValue* option_value = new base::DictionaryValue;
- options_list->Append(option_value);
+ std::unique_ptr<base::DictionaryValue> option_value(
+ new base::DictionaryValue);
if (base::checked_cast<int>(i) == default_idx_)
option_value->SetBoolean(json::kKeyIsDefault, true);
- Traits::Save(options_[i], option_value);
+ Traits::Save(options_[i], option_value.get());
+ options_list->Append(std::move(option_value));
}
}
diff --git a/chromium/components/cloud_devices/common/printer_description.cc b/chromium/components/cloud_devices/common/printer_description.cc
index a5e03a0999e..aa7fa38d517 100644
--- a/chromium/components/cloud_devices/common/printer_description.cc
+++ b/chromium/components/cloud_devices/common/printer_description.cc
@@ -7,6 +7,8 @@
#include <stddef.h>
#include <algorithm>
+#include <memory>
+#include <utility>
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
@@ -734,11 +736,12 @@ class PageRangeTraits : public ItemsTraits<kOptionPageRange> {
base::ListValue* list = new base::ListValue;
dict->Set(kPageRangeInterval, list);
for (size_t i = 0; i < option.size(); ++i) {
- base::DictionaryValue* interval = new base::DictionaryValue;
- list->Append(interval);
+ std::unique_ptr<base::DictionaryValue> interval(
+ new base::DictionaryValue);
interval->SetInteger(kPageRangeStart, option[i].start);
if (option[i].end < kMaxPageNumber)
interval->SetInteger(kPageRangeEnd, option[i].end);
+ list->Append(std::move(interval));
}
}
}
diff --git a/chromium/components/component_updater.gypi b/chromium/components/component_updater.gypi
deleted file mode 100644
index 3baecca0272..00000000000
--- a/chromium/components/component_updater.gypi
+++ /dev/null
@@ -1,59 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/component_updater
- 'target_name': 'component_updater',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../ui/base/ui_base.gyp:ui_base',
- '../url/url.gyp:url_lib',
- 'update_client',
- 'version_info',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'component_updater/component_updater_paths.cc',
- 'component_updater/component_updater_paths.h',
- 'component_updater/component_updater_service.cc',
- 'component_updater/component_updater_service.h',
- 'component_updater/component_updater_service_internal.h',
- 'component_updater/component_updater_switches.cc',
- 'component_updater/component_updater_switches.h',
- 'component_updater/component_updater_url_constants.cc',
- 'component_updater/component_updater_url_constants.h',
- 'component_updater/configurator_impl.cc',
- 'component_updater/configurator_impl.h',
- 'component_updater/default_component_installer.cc',
- 'component_updater/default_component_installer.h',
- 'component_updater/pref_names.cc',
- 'component_updater/pref_names.h',
- 'component_updater/timer.cc',
- 'component_updater/timer.h',
- ],
- },
- {
- # GN version: //components/component_updater:test_support
- 'target_name': 'component_updater_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../testing/gmock.gyp:gmock',
- 'component_updater',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'component_updater/mock_component_updater_service.cc',
- 'component_updater/mock_component_updater_service.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/component_updater/BUILD.gn b/chromium/components/component_updater/BUILD.gn
index d01c1ade498..1b5b142a84f 100644
--- a/chromium/components/component_updater/BUILD.gn
+++ b/chromium/components/component_updater/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("component_updater") {
+static_library("component_updater") {
sources = [
"component_updater_paths.cc",
"component_updater_paths.h",
@@ -21,6 +21,8 @@ source_set("component_updater") {
"pref_names.h",
"timer.cc",
"timer.h",
+ "updater_state_win.cc",
+ "updater_state_win.h",
]
deps = [
@@ -32,7 +34,7 @@ source_set("component_updater") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"mock_component_updater_service.cc",
@@ -50,8 +52,10 @@ source_set("unit_tests") {
testonly = true
sources = [
"component_updater_service_unittest.cc",
+ "configurator_impl_unittest.cc",
"default_component_installer_unittest.cc",
"timer_unittest.cc",
+ "updater_state_unittest_win.cc",
]
deps = [
diff --git a/chromium/components/component_updater/README.md b/chromium/components/component_updater/README.md
new file mode 100644
index 00000000000..53ce47c7399
--- /dev/null
+++ b/chromium/components/component_updater/README.md
@@ -0,0 +1,80 @@
+# Component Updater
+
+## Overview
+The Component Updater is a piece of Chrome responsible for updating other pieces
+of Chrome. It runs in the browser process and communicates with a set of servers
+using the [Omaha](https://github.com/google/omaha) protocol to find the latest
+versions of components, download them, and register them with the rest of
+Chrome.
+
+The primary benefit of components is that they can be updated without an update
+to Chrome itself, which allows them to have faster (or desynchronized) release
+cadences, lower bandwidth consumption, and avoids bloat in the (already sizable)
+Chrome installer. The primary drawback is that they require Chrome to tolerate
+their absence in a sane way.
+
+In the normal configuration, the component updater registers all components
+during (or close to) browser start-up, and then begins checking for updates six
+minutes later, with substantial pauses between successive update application.
+
+## Terminology
+For the purposes of this document:
+
+ * A `component` is any element of Chrome's core functionality that is sometimes
+ delivered by the component updater separately from the browser itself,
+ usually as a dynamically-linked library or data file.
+ * A `crx file` is any file in the
+ [CRX package format](https://developer.chrome.com/extensions/crx).
+
+## Adding New Components
+This document covers the work that must be done on the client side. Additional
+work is necessary to integrate with the Omaha servers, and is covered in
+[Google-internal documentation](http://go/newchromecomponent).
+
+This assumes you've already done the hard work of splitting your functionality
+out into a dynamically-linked library or data file.
+
+### Create a CRX Package Signing Key & Manifest (Non-Google)
+All components are delivered as CRX files (signed ZIP archives). You need to
+create a signing key. If you are a Googler, follow the instructions at
+http://go/newchromecomponents for maximum key security. Otherwise, you can
+create an RSA key pair using `openssl` or a similar tool.
+
+You will additionally need to create a manifest.json file. If nothing else, the
+manifest file must specify the component's version and name. If you plan to
+release the component using Google infrastructure, this file can be generated
+for you automatically.
+
+### Writing an Installer
+The "installer" is a piece of Chrome code that the component updater will run to
+install or update the component. Installers live at
+`src/chrome/browser/component_updater`.
+
+You will need the SHA256 hash of the public key generated in the previous step,
+as well as the CRX ID, which consists of the first half (128 bits) of that hash,
+rendered as hexadecimal using the characters `a-p` (rather than `0-9a-f`).
+
+New components should use
+[`default_component_installer`](default_component_installer.h)
+if possible, as this provides you with transparent differential updates, version
+management, and more. You must provide a `ComponentInstallerTraits` object to
+a new `DefaultComponentInstaller`.
+[file\_type\_policies\_component\_installer.cc](../../chrome/browser/component_updater/file_type_policies_component_installer.cc)
+is a good example to work from.
+
+Components need to be registered with the component updater. This is done in
+[RegisterComponentsForUpdate](https://cs.chromium.org/chromium/src/chrome/browser/chrome_browser_main.cc).
+
+### Bundle with the Chrome Installer (Optional)
+If you need the guarantee that some implementation of your component is always
+available, you must bundle a component implementation with the browser itself.
+If you are using `DefaultComponentInstaller`, you simply need to make sure that
+your component implementation (and a corresponding manifest.json file) are
+written to DIR\_COMPONENTS as part of the build. The manifest.json file must
+state the version of this component implementation, and the files must be
+bitwise identical to the contents of any update CRX with that version for that
+platform, as the system will attempt to apply differential updates over these
+files.
+
+### Implement On-Demand or Just-In-Time Updates (Optional)
+Contact the component\_updater OWNERS.
diff --git a/chromium/components/component_updater/component_updater_service.cc b/chromium/components/component_updater/component_updater_service.cc
index 5ef5a3f54d1..33680d13eb6 100644
--- a/chromium/components/component_updater/component_updater_service.cc
+++ b/chromium/components/component_updater/component_updater_service.cc
@@ -21,6 +21,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_checker.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -28,6 +29,9 @@
#include "base/timer/timer.h"
#include "components/component_updater/component_updater_service_internal.h"
#include "components/component_updater/timer.h"
+#if defined(OS_WIN)
+#include "components/component_updater/updater_state_win.h"
+#endif
#include "components/update_client/configurator.h"
#include "components/update_client/crx_update_item.h"
#include "components/update_client/update_client.h"
@@ -45,10 +49,16 @@ enum UpdateType {
UPDATE_TYPE_COUNT,
};
+const char kRecoveryComponentId[] = "npdjjkjlcidkjlamlmmdelcjbcpdjocm";
+
} // namespace
namespace component_updater {
+ComponentInfo::ComponentInfo(const std::string& id, const base::string16& name)
+ : id(id), name(name) {}
+ComponentInfo::~ComponentInfo() {}
+
CrxUpdateService::CrxUpdateService(
const scoped_refptr<Configurator>& config,
const scoped_refptr<UpdateClient>& update_client)
@@ -122,6 +132,8 @@ bool CrxUpdateService::RegisterComponent(const CrxComponent& component) {
components_.insert(std::make_pair(id, component));
components_order_.push_back(id);
+ for (const auto& mime_type : component.handled_mime_types)
+ component_ids_by_mime_type_[mime_type] = id;
// Create an initial state for this component. The state is mutated in
// response to events from the UpdateClient instance.
@@ -185,6 +197,19 @@ std::vector<std::string> CrxUpdateService::GetComponentIDs() const {
return ids;
}
+std::unique_ptr<ComponentInfo> CrxUpdateService::GetComponentForMimeType(
+ const std::string& mime_type) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ const auto it = component_ids_by_mime_type_.find(mime_type);
+ if (it == component_ids_by_mime_type_.end())
+ return nullptr;
+ const auto component = GetComponent(it->second);
+ if (!component)
+ return nullptr;
+ return base::MakeUnique<ComponentInfo>(GetCrxComponentID(*component),
+ base::UTF8ToUTF16(component->name));
+}
+
OnDemandUpdater& CrxUpdateService::GetOnDemandUpdater() {
DCHECK(thread_checker_.CalledOnValidThread());
return *this;
@@ -219,13 +244,19 @@ void CrxUpdateService::MaybeThrottle(const std::string& id,
callback.Run(); // Unblock the request if the request can't be throttled.
}
-bool CrxUpdateService::OnDemandUpdate(const std::string& id) {
+void CrxUpdateService::OnDemandUpdate(const std::string& id,
+ CompletionCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!GetComponent(id))
- return false;
+ if (!GetComponent(id)) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(callback,
+ update_client::Error::ERROR_UPDATE_INVALID_ARGUMENT));
+ return;
+ }
- return OnDemandUpdateInternal(id);
+ OnDemandUpdateInternal(id, callback);
}
bool CrxUpdateService::OnDemandUpdateWithCooldown(const std::string& id) {
@@ -234,28 +265,28 @@ bool CrxUpdateService::OnDemandUpdateWithCooldown(const std::string& id) {
DCHECK(GetComponent(id));
// Check if the request is too soon.
- const auto component_state(GetComponentState(id));
+ const auto* component_state(GetComponentState(id));
if (component_state) {
- base::TimeDelta delta = base::Time::Now() - component_state->last_check;
+ base::TimeDelta delta =
+ base::TimeTicks::Now() - component_state->last_check;
if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
return false;
}
- return OnDemandUpdateInternal(id);
+ OnDemandUpdateInternal(id, CompletionCallback());
+ return true;
}
-bool CrxUpdateService::OnDemandUpdateInternal(const std::string& id) {
+void CrxUpdateService::OnDemandUpdateInternal(const std::string& id,
+ CompletionCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.Calls", UPDATE_TYPE_MANUAL,
UPDATE_TYPE_COUNT);
-
update_client_->Install(
id, base::Bind(&CrxUpdateService::OnUpdate, base::Unretained(this)),
base::Bind(&CrxUpdateService::OnUpdateComplete, base::Unretained(this),
- base::TimeTicks::Now()));
-
- return true;
+ callback, base::TimeTicks::Now()));
}
bool CrxUpdateService::CheckForUpdates() {
@@ -269,7 +300,7 @@ bool CrxUpdateService::CheckForUpdates() {
for (const auto id : components_order_) {
DCHECK(components_.find(id) != components_.end());
- auto component(GetComponent(id));
+ auto* component(GetComponent(id));
if (!component || component->requires_network_encryption)
secure_ids.push_back(id);
else
@@ -281,7 +312,7 @@ bool CrxUpdateService::CheckForUpdates() {
unsecure_ids,
base::Bind(&CrxUpdateService::OnUpdate, base::Unretained(this)),
base::Bind(&CrxUpdateService::OnUpdateComplete, base::Unretained(this),
- base::TimeTicks::Now()));
+ CompletionCallback(), base::TimeTicks::Now()));
}
if (!secure_ids.empty()) {
@@ -289,7 +320,7 @@ bool CrxUpdateService::CheckForUpdates() {
secure_ids,
base::Bind(&CrxUpdateService::OnUpdate, base::Unretained(this)),
base::Bind(&CrxUpdateService::OnUpdateComplete, base::Unretained(this),
- base::TimeTicks::Now()));
+ CompletionCallback(), base::TimeTicks::Now()));
}
return true;
@@ -327,14 +358,23 @@ void CrxUpdateService::OnUpdate(const std::vector<std::string>& ids,
DCHECK(components->empty());
for (const auto& id : ids) {
- const auto registered_component(GetComponent(id));
+ const update_client::CrxComponent* registered_component(GetComponent(id));
if (registered_component) {
components->push_back(*registered_component);
+ if (id == kRecoveryComponentId) {
+ // Override the installer attributes for the recovery component in the
+ // components which will be checked for updates.
+ update_client::CrxComponent& recovery_component(components->back());
+ recovery_component.installer_attributes =
+ GetInstallerAttributesForRecoveryComponentInstaller(
+ recovery_component);
+ }
}
}
}
-void CrxUpdateService::OnUpdateComplete(const base::TimeTicks& start_time,
+void CrxUpdateService::OnUpdateComplete(CompletionCallback callback,
+ const base::TimeTicks& start_time,
int error) {
DCHECK(thread_checker_.CalledOnValidThread());
VLOG(1) << "Update completed with error " << error;
@@ -345,11 +385,16 @@ void CrxUpdateService::OnUpdateComplete(const base::TimeTicks& start_time,
for (const auto id : components_pending_unregistration_) {
if (!update_client_->IsUpdating(id)) {
- const auto component = GetComponent(id);
+ const auto* component = GetComponent(id);
if (component)
DoUnregisterComponent(*component);
}
}
+
+ if (!callback.is_null()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, error));
+ }
}
void CrxUpdateService::OnEvent(Events event, const std::string& id) {
@@ -376,7 +421,7 @@ void CrxUpdateService::OnEvent(Events event, const std::string& id) {
// Update the component registration with the new version.
if (event == Observer::Events::COMPONENT_UPDATED) {
- auto component(const_cast<CrxComponent*>(GetComponent(id)));
+ auto* component(const_cast<CrxComponent*>(GetComponent(id)));
if (component) {
component->version = update_item.next_version;
component->fingerprint = update_item.next_fp;
@@ -384,6 +429,25 @@ void CrxUpdateService::OnEvent(Events event, const std::string& id) {
}
}
+update_client::InstallerAttributes
+CrxUpdateService::GetInstallerAttributesForRecoveryComponentInstaller(
+ const CrxComponent& crx_component) const {
+ update_client::InstallerAttributes installer_attributes;
+#if defined(OS_WIN)
+ DCHECK_EQ("recovery", crx_component.name);
+
+ const bool is_machine =
+ crx_component.installer_attributes.count("ismachine") &&
+ crx_component.installer_attributes.at("ismachine") == "1";
+
+ auto updater_state(UpdaterState::Create(is_machine));
+ if (updater_state) {
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ }
+#endif
+ return installer_attributes;
+}
+
///////////////////////////////////////////////////////////////////////////////
// The component update factory. Using the component updater as a singleton
@@ -393,8 +457,7 @@ std::unique_ptr<ComponentUpdateService> ComponentUpdateServiceFactory(
const scoped_refptr<Configurator>& config) {
DCHECK(config);
auto update_client = update_client::UpdateClientFactory(config);
- return base::WrapUnique(
- new CrxUpdateService(config, std::move(update_client)));
+ return base::MakeUnique<CrxUpdateService>(config, std::move(update_client));
}
} // namespace component_updater
diff --git a/chromium/components/component_updater/component_updater_service.h b/chromium/components/component_updater/component_updater_service.h
index 7abf4d6bc95..48b12a1a8e9 100644
--- a/chromium/components/component_updater/component_updater_service.h
+++ b/chromium/components/component_updater/component_updater_service.h
@@ -19,6 +19,7 @@
#include "url/gurl.h"
class ComponentsUI;
+class PluginObserver;
class SupervisedUserWhitelistService;
namespace base {
@@ -36,6 +37,10 @@ class URLRequestContextGetter;
class URLRequest;
}
+namespace policy {
+class ComponentUpdaterPolicyTest;
+}
+
namespace update_client {
class ComponentInstaller;
class Configurator;
@@ -51,6 +56,14 @@ using Configurator = update_client::Configurator;
using CrxComponent = update_client::CrxComponent;
using CrxUpdateItem = update_client::CrxUpdateItem;
+struct ComponentInfo {
+ ComponentInfo(const std::string& id, const base::string16& name);
+ ~ComponentInfo();
+
+ const std::string id;
+ const base::string16 name;
+};
+
// The component update service is in charge of installing or upgrading
// select parts of chrome. Each part is called a component and managed by
// instances of CrxComponent registered using RegisterComponent(). On the
@@ -68,6 +81,7 @@ using CrxUpdateItem = update_client::CrxUpdateItem;
// All methods are safe to call ONLY from the browser's main thread.
class ComponentUpdateService {
public:
+ using CompletionCallback = update_client::UpdateClient::CompletionCallback;
using Observer = update_client::UpdateClient::Observer;
// Adds an observer for this class. An observer should not be added more
@@ -96,6 +110,13 @@ class ComponentUpdateService {
// Returns a list of registered components.
virtual std::vector<std::string> GetComponentIDs() const = 0;
+ // Returns a ComponentInfo describing a registered component that implements a
+ // handler for the specified |mime_type|. If multiple such components exist,
+ // returns information for the one that was most recently registered. If no
+ // such components exist, returns nullptr.
+ virtual std::unique_ptr<ComponentInfo> GetComponentForMimeType(
+ const std::string& mime_type) const = 0;
+
// Returns an interface for on-demand updates. On-demand updates are
// proactively triggered outside the normal component update service schedule.
virtual OnDemandUpdater& GetOnDemandUpdater() = 0;
@@ -138,18 +159,20 @@ class OnDemandUpdater {
private:
friend class OnDemandTester;
+ friend class policy::ComponentUpdaterPolicyTest;
friend class SupervisedUserWhitelistInstaller;
friend class ::ComponentsUI;
+ friend class ::PluginObserver;
// Triggers an update check for a component. |id| is a value
// returned by GetCrxComponentID(). If an update for this component is already
// in progress, the function returns |kInProgress|. If an update is available,
// the update will be applied. The caller can subscribe to component update
- // service notifications to get an indication about the outcome of the
- // on-demand update. The function does not implement any cooldown interval.
- // TODO(sorin): improve this API so that the result of this non-blocking
- // call is provided by a callback.
- virtual bool OnDemandUpdate(const std::string& id) = 0;
+ // service notifications and provide an optional callback to get the result
+ // of the call. The function does not implement any cooldown interval.
+ virtual void OnDemandUpdate(
+ const std::string& id,
+ ComponentUpdateService::CompletionCallback callback) = 0;
};
// Creates the component updater.
diff --git a/chromium/components/component_updater/component_updater_service_internal.h b/chromium/components/component_updater/component_updater_service_internal.h
index e20a3156fad..08963bbb94e 100644
--- a/chromium/components/component_updater/component_updater_service_internal.h
+++ b/chromium/components/component_updater/component_updater_service_internal.h
@@ -6,6 +6,7 @@
#define COMPONENTS_COMPONENT_UPDATER_COMPONENT_UPDATER_SERVICE_INTERNAL_H_
#include <map>
+#include <memory>
#include <string>
#include <vector>
@@ -43,6 +44,8 @@ class CrxUpdateService : public ComponentUpdateService,
bool RegisterComponent(const CrxComponent& component) override;
bool UnregisterComponent(const std::string& id) override;
std::vector<std::string> GetComponentIDs() const override;
+ std::unique_ptr<ComponentInfo> GetComponentForMimeType(
+ const std::string& id) const override;
OnDemandUpdater& GetOnDemandUpdater() override;
void MaybeThrottle(const std::string& id,
const base::Closure& callback) override;
@@ -54,7 +57,8 @@ class CrxUpdateService : public ComponentUpdateService,
void OnEvent(Events event, const std::string& id) override;
// Overrides for OnDemandUpdater.
- bool OnDemandUpdate(const std::string& id) override;
+ void OnDemandUpdate(const std::string& id,
+ CompletionCallback callback) override;
private:
void Start();
@@ -62,7 +66,8 @@ class CrxUpdateService : public ComponentUpdateService,
bool CheckForUpdates();
- bool OnDemandUpdateInternal(const std::string& id);
+ void OnDemandUpdateInternal(const std::string& id,
+ CompletionCallback callback);
bool OnDemandUpdateWithCooldown(const std::string& id);
bool DoUnregisterComponent(const CrxComponent& component);
@@ -73,8 +78,16 @@ class CrxUpdateService : public ComponentUpdateService,
void OnUpdate(const std::vector<std::string>& ids,
std::vector<CrxComponent>* components);
- void OnUpdateComplete(const base::TimeTicks& start_time, int error);
-
+ void OnUpdateComplete(CompletionCallback callback,
+ const base::TimeTicks& start_time,
+ int error);
+
+ // Returns the map of installer attributes for the recovery component
+ // installer. This data corresponds to the Omaha updater state and it is
+ // serialized as part of the update check for the recovery component.
+ update_client::InstallerAttributes
+ GetInstallerAttributesForRecoveryComponentInstaller(
+ const CrxComponent& crx_component) const;
base::ThreadChecker thread_checker_;
scoped_refptr<Configurator> config_;
@@ -107,6 +120,11 @@ class CrxUpdateService : public ComponentUpdateService,
using ComponentStates = std::map<std::string, CrxUpdateItem>;
ComponentStates component_states_;
+ // Contains a map of media types to the component that implements a handler
+ // for that media type. Only the most recently-registered component is
+ // tracked. May include the IDs of un-registered components.
+ std::map<std::string, std::string> component_ids_by_mime_type_;
+
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
DISALLOW_COPY_AND_ASSIGN(CrxUpdateService);
diff --git a/chromium/components/component_updater/component_updater_service_unittest.cc b/chromium/components/component_updater/component_updater_service_unittest.cc
index 73c5f83b14c..caac5add681 100644
--- a/chromium/components/component_updater/component_updater_service_unittest.cc
+++ b/chromium/components/component_updater/component_updater_service_unittest.cc
@@ -73,8 +73,9 @@ class MockUpdateClient : public UpdateClient {
bool(const std::string& id, CrxUpdateItem* update_item));
MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
MOCK_METHOD0(Stop, void());
- MOCK_METHOD3(SendUninstallPing,
- void(const std::string& id, const Version& version, int reason));
+ MOCK_METHOD3(
+ SendUninstallPing,
+ void(const std::string& id, const base::Version& version, int reason));
private:
~MockUpdateClient() override;
@@ -127,7 +128,13 @@ class ComponentUpdaterTest : public testing::Test {
class OnDemandTester {
public:
- static bool OnDemand(ComponentUpdateService* cus, const std::string& id);
+ void OnDemand(ComponentUpdateService* cus, const std::string& id);
+ int error() const { return error_; }
+
+ private:
+ void OnDemandComplete(int error);
+
+ int error_ = 0;
};
MockInstaller::MockInstaller() {
@@ -148,15 +155,21 @@ MockServiceObserver::MockServiceObserver() {
MockServiceObserver::~MockServiceObserver() {
}
-bool OnDemandTester::OnDemand(ComponentUpdateService* cus,
+void OnDemandTester::OnDemand(ComponentUpdateService* cus,
const std::string& id) {
- return cus->GetOnDemandUpdater().OnDemandUpdate(id);
+ cus->GetOnDemandUpdater().OnDemandUpdate(
+ id,
+ base::Bind(&OnDemandTester::OnDemandComplete, base::Unretained(this)));
+}
+
+void OnDemandTester::OnDemandComplete(int error) {
+ error_ = error;
}
std::unique_ptr<ComponentUpdateService> TestComponentUpdateServiceFactory(
const scoped_refptr<Configurator>& config) {
DCHECK(config);
- return base::WrapUnique(new CrxUpdateService(config, new MockUpdateClient()));
+ return base::MakeUnique<CrxUpdateService>(config, new MockUpdateClient());
}
ComponentUpdaterTest::ComponentUpdaterTest()
@@ -243,12 +256,12 @@ TEST_F(ComponentUpdaterTest, RegisterComponent) {
CrxComponent crx_component1;
crx_component1.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
- crx_component1.version = Version("1.0");
+ crx_component1.version = base::Version("1.0");
crx_component1.installer = installer;
CrxComponent crx_component2;
crx_component2.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx_component2.version = Version("0.9");
+ crx_component2.version = base::Version("0.9");
crx_component2.installer = installer;
// Quit after two update checks have fired.
@@ -274,8 +287,7 @@ TEST_F(ComponentUpdaterTest, RegisterComponent) {
TEST_F(ComponentUpdaterTest, OnDemandUpdate) {
class LoopHandler {
public:
- LoopHandler(int max_cnt, const base::Closure& quit_closure)
- : max_cnt_(max_cnt), quit_closure_(quit_closure) {}
+ LoopHandler(int max_cnt) : max_cnt_(max_cnt) {}
void OnInstall(
const std::string& ids,
@@ -284,13 +296,16 @@ TEST_F(ComponentUpdaterTest, OnDemandUpdate) {
completion_callback.Run(0);
static int cnt = 0;
++cnt;
- if (cnt >= max_cnt_)
- quit_closure_.Run();
+ if (cnt >= max_cnt_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&LoopHandler::Quit, base::Unretained(this)));
+ }
}
private:
+ void Quit() { base::MessageLoop::current()->QuitWhenIdle(); }
+
const int max_cnt_;
- base::Closure quit_closure_;
};
base::HistogramTester ht;
@@ -300,27 +315,37 @@ TEST_F(ComponentUpdaterTest, OnDemandUpdate) {
auto& cus = component_updater();
- const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
- EXPECT_FALSE(OnDemandTester::OnDemand(&cus, id));
+ // Tests calling OnDemand for an unregistered component. This call results in
+ // an error, which is recorded by the OnDemandTester instance. Since the
+ // component was not registered, the call is ignored for UMA metrics.
+ OnDemandTester ondemand_tester_component_not_registered;
+ ondemand_tester_component_not_registered.OnDemand(
+ &cus, "ihfokbkgjpifnbbojhneepfflplebdkc");
- scoped_refptr<MockInstaller> installer(new MockInstaller());
+ const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
using update_client::jebg_hash;
CrxComponent crx_component;
crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx_component.version = Version("0.9");
- crx_component.installer = installer;
+ crx_component.version = base::Version("0.9");
+ crx_component.installer = new MockInstaller();
- LoopHandler loop_handler(1, quit_closure());
+ LoopHandler loop_handler(1);
EXPECT_CALL(update_client(),
Install("jebgalgnebhfojomionfpkfelancnnkf", _, _))
.WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
EXPECT_CALL(update_client(), Stop()).Times(1);
EXPECT_TRUE(cus.RegisterComponent(crx_component));
- EXPECT_TRUE(OnDemandTester::OnDemand(&cus, id));
+ OnDemandTester ondemand_tester;
+ ondemand_tester.OnDemand(&cus, id);
- RunThreads();
+ base::RunLoop().Run();
+
+ EXPECT_EQ(
+ static_cast<int>(update_client::Error::ERROR_UPDATE_INVALID_ARGUMENT),
+ ondemand_tester_component_not_registered.error());
+ EXPECT_EQ(0, ondemand_tester.error());
ht.ExpectUniqueSample("ComponentUpdater.Calls", 0, 1);
ht.ExpectUniqueSample("ComponentUpdater.UpdateCompleteResult", 0, 1);
@@ -360,7 +385,7 @@ TEST_F(ComponentUpdaterTest, MaybeThrottle) {
using update_client::jebg_hash;
CrxComponent crx_component;
crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx_component.version = Version("0.9");
+ crx_component.version = base::Version("0.9");
crx_component.installer = installer;
LoopHandler loop_handler(1, quit_closure());
diff --git a/chromium/components/component_updater/configurator_impl.cc b/chromium/components/component_updater/configurator_impl.cc
index 8da26fd6f74..2f702574855 100644
--- a/chromium/components/component_updater/configurator_impl.cc
+++ b/chromium/components/component_updater/configurator_impl.cc
@@ -25,12 +25,15 @@
namespace component_updater {
namespace {
+
// Default time constants.
const int kDelayOneMinute = 60;
const int kDelayOneHour = kDelayOneMinute * 60;
-// Debug values you can pass to --component-updater=value1,value2.
-// Speed up component checking.
+// Debug values you can pass to --component-updater=value1,value2. Do not
+// use these values in production code.
+
+// Speed up the initial component checking.
const char kSwitchFastUpdate[] = "fast-update";
// Add "testrequest=1" attribute to the update check request.
@@ -123,7 +126,7 @@ int ConfiguratorImpl::InitialDelay() const {
}
int ConfiguratorImpl::NextCheckDelay() const {
- return fast_update_ ? 60 : (6 * kDelayOneHour);
+ return 6 * kDelayOneHour;
}
int ConfiguratorImpl::StepDelay() const {
@@ -177,15 +180,19 @@ net::URLRequestContextGetter* ConfiguratorImpl::RequestContext() const {
return url_request_getter_;
}
-bool ConfiguratorImpl::DeltasEnabled() const {
+bool ConfiguratorImpl::EnabledDeltas() const {
return deltas_enabled_;
}
-bool ConfiguratorImpl::UseBackgroundDownloader() const {
+bool ConfiguratorImpl::EnabledComponentUpdates() const {
+ return true;
+}
+
+bool ConfiguratorImpl::EnabledBackgroundDownloader() const {
return background_downloads_enabled_;
}
-bool ConfiguratorImpl::UseCupSigning() const {
+bool ConfiguratorImpl::EnabledCupSigning() const {
return true;
}
diff --git a/chromium/components/component_updater/configurator_impl.h b/chromium/components/component_updater/configurator_impl.h
index 1fa95f17751..870dc860f16 100644
--- a/chromium/components/component_updater/configurator_impl.h
+++ b/chromium/components/component_updater/configurator_impl.h
@@ -76,14 +76,17 @@ class ConfiguratorImpl {
net::URLRequestContextGetter* RequestContext() const;
// True means that this client can handle delta updates.
- bool DeltasEnabled() const;
+ bool EnabledDeltas() const;
+
+ // True is the component updates are enabled.
+ bool EnabledComponentUpdates() const;
// True means that the background downloader can be used for downloading
// non on-demand components.
- bool UseBackgroundDownloader() const;
+ bool EnabledBackgroundDownloader() const;
// True if signing of update checks is enabled.
- bool UseCupSigning() const;
+ bool EnabledCupSigning() const;
private:
net::URLRequestContextGetter* url_request_getter_;
diff --git a/chromium/components/component_updater/configurator_impl_unittest.cc b/chromium/components/component_updater/configurator_impl_unittest.cc
new file mode 100644
index 00000000000..ec0c1cdffed
--- /dev/null
+++ b/chromium/components/component_updater/configurator_impl_unittest.cc
@@ -0,0 +1,53 @@
+// 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 <memory>
+
+#include "base/command_line.h"
+#include "base/macros.h"
+#include "components/component_updater/configurator_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace component_updater {
+
+namespace {
+
+const int kDelayOneMinute = 60;
+const int kDelayOneHour = kDelayOneMinute * 60;
+
+} // namespace
+
+using base::CommandLine;
+
+class ComponentUpdaterConfiguratorImplTest : public testing::Test {
+ public:
+ ComponentUpdaterConfiguratorImplTest() {}
+ ~ComponentUpdaterConfiguratorImplTest() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ComponentUpdaterConfiguratorImplTest);
+};
+
+TEST_F(ComponentUpdaterConfiguratorImplTest, FastUpdate) {
+ // Test the default timing values when no command line argument is present.
+ base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
+ std::unique_ptr<ConfiguratorImpl> config(
+ new ConfiguratorImpl(&cmdline, nullptr, false));
+ CHECK_EQ(6 * kDelayOneMinute, config->InitialDelay());
+ CHECK_EQ(6 * kDelayOneHour, config->NextCheckDelay());
+ CHECK_EQ(1, config->StepDelay());
+ CHECK_EQ(30 * kDelayOneMinute, config->OnDemandDelay());
+ CHECK_EQ(15 * kDelayOneMinute, config->UpdateDelay());
+
+ // Test the fast-update timings.
+ cmdline.AppendSwitchASCII("--component-updater", "fast-update");
+ config.reset(new ConfiguratorImpl(&cmdline, nullptr, false));
+ CHECK_EQ(10, config->InitialDelay());
+ CHECK_EQ(6 * kDelayOneHour, config->NextCheckDelay());
+ CHECK_EQ(1, config->StepDelay());
+ CHECK_EQ(2, config->OnDemandDelay());
+ CHECK_EQ(10, config->UpdateDelay());
+}
+
+} // namespace component_updater
diff --git a/chromium/components/component_updater/default_component_installer.cc b/chromium/components/component_updater/default_component_installer.cc
index fa071a20036..b9bcaa9e92d 100644
--- a/chromium/components/component_updater/default_component_installer.cc
+++ b/chromium/components/component_updater/default_component_installer.cc
@@ -195,7 +195,7 @@ bool DefaultComponentInstaller::FindPreinstallation(
}
void DefaultComponentInstaller::StartRegistration(ComponentUpdateService* cus) {
- VLOG(1) << __FUNCTION__ << " for " << installer_traits_->GetName();
+ VLOG(1) << __func__ << " for " << installer_traits_->GetName();
DCHECK(task_runner_.get());
DCHECK(task_runner_->RunsTasksOnCurrentThread());
@@ -322,29 +322,31 @@ void DefaultComponentInstaller::UninstallOnTaskRunner() {
void DefaultComponentInstaller::FinishRegistration(
ComponentUpdateService* cus,
const base::Closure& callback) {
- VLOG(1) << __FUNCTION__ << " for " << installer_traits_->GetName();
+ VLOG(1) << __func__ << " for " << installer_traits_->GetName();
DCHECK(thread_checker_.CalledOnValidThread());
- if (installer_traits_->CanAutoUpdate()) {
- CrxComponent crx;
- installer_traits_->GetHash(&crx.pk_hash);
- crx.installer = this;
- crx.version = current_version_;
- crx.fingerprint = current_fingerprint_;
- crx.name = installer_traits_->GetName();
- crx.installer_attributes = installer_traits_->GetInstallerAttributes();
- crx.requires_network_encryption =
- installer_traits_->RequiresNetworkEncryption();
- if (!cus->RegisterComponent(crx)) {
- LOG(ERROR) << "Component registration failed for "
- << installer_traits_->GetName();
- return;
- }
-
- if (!callback.is_null())
- callback.Run();
+ CrxComponent crx;
+ installer_traits_->GetHash(&crx.pk_hash);
+ crx.installer = this;
+ crx.version = current_version_;
+ crx.fingerprint = current_fingerprint_;
+ crx.name = installer_traits_->GetName();
+ crx.installer_attributes = installer_traits_->GetInstallerAttributes();
+ crx.requires_network_encryption =
+ installer_traits_->RequiresNetworkEncryption();
+ crx.handled_mime_types = installer_traits_->GetMimeTypes();
+ crx.supports_group_policy_enable_component_updates =
+ installer_traits_->SupportsGroupPolicyEnabledComponentUpdates();
+
+ if (!cus->RegisterComponent(crx)) {
+ LOG(ERROR) << "Component registration failed for "
+ << installer_traits_->GetName();
+ return;
}
+ if (!callback.is_null())
+ callback.Run();
+
if (!current_manifest_) {
DVLOG(1) << "No component found for " << installer_traits_->GetName();
return;
diff --git a/chromium/components/component_updater/default_component_installer.h b/chromium/components/component_updater/default_component_installer.h
index 8819c29053b..18a87c543f8 100644
--- a/chromium/components/component_updater/default_component_installer.h
+++ b/chromium/components/component_updater/default_component_installer.h
@@ -46,9 +46,9 @@ class ComponentInstallerTraits {
virtual bool VerifyInstallation(const base::DictionaryValue& manifest,
const base::FilePath& install_dir) const = 0;
- // Returns true if the component can be automatically updated. Called once
- // during component registration from the UI thread.
- virtual bool CanAutoUpdate() const = 0;
+ // Returns true if the component supports a group policy to enable updates.
+ // Called once during component registration from the UI thread.
+ virtual bool SupportsGroupPolicyEnabledComponentUpdates() const = 0;
// Returns true if the network communication related to this component
// must be encrypted.
@@ -86,6 +86,9 @@ class ComponentInstallerTraits {
// Returns the human-readable name of the component.
virtual std::string GetName() const = 0;
+ // If this component is a plugin, returns the media types it can handle.
+ virtual std::vector<std::string> GetMimeTypes() const = 0;
+
// Returns a container of name-value pairs representing arbitrary,
// installer-defined metadata.
// The installer metadata may be used in the update checks for this component.
diff --git a/chromium/components/component_updater/default_component_installer_unittest.cc b/chromium/components/component_updater/default_component_installer_unittest.cc
index 184ef2b8445..d235714610c 100644
--- a/chromium/components/component_updater/default_component_installer_unittest.cc
+++ b/chromium/components/component_updater/default_component_installer_unittest.cc
@@ -4,6 +4,7 @@
#include <iterator>
#include <string>
+#include <utility>
#include <vector>
#include "base/callback.h"
@@ -57,8 +58,9 @@ class MockUpdateClient : public UpdateClient {
bool(const std::string& id, CrxUpdateItem* update_item));
MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
MOCK_METHOD0(Stop, void());
- MOCK_METHOD3(SendUninstallPing,
- void(const std::string& id, const Version& version, int reason));
+ MOCK_METHOD3(
+ SendUninstallPing,
+ void(const std::string& id, const base::Version& version, int reason));
private:
~MockUpdateClient() override {}
@@ -73,7 +75,9 @@ class FakeInstallerTraits : public ComponentInstallerTraits {
return true;
}
- bool CanAutoUpdate() const override { return true; }
+ bool SupportsGroupPolicyEnabledComponentUpdates() const override {
+ return true;
+ }
bool RequiresNetworkEncryption() const override { return true; }
@@ -102,6 +106,10 @@ class FakeInstallerTraits : public ComponentInstallerTraits {
return installer_attributes;
}
+ std::vector<std::string> GetMimeTypes() const override {
+ return std::vector<std::string>();
+ }
+
private:
static void GetPkHash(std::vector<uint8_t>* hash) {
hash->assign(std::begin(kSha256Hash), std::end(kSha256Hash));
@@ -124,7 +132,7 @@ class DefaultComponentInstallerTest : public testing::Test {
void RunThreads();
private:
- static const int kNumWorkerThreads_ = 1;
+ static const int kNumWorkerThreads_ = 2;
base::MessageLoopForUI message_loop_;
base::RunLoop runloop_;
@@ -221,6 +229,7 @@ TEST_F(DefaultComponentInstallerTest, RegisterComponent) {
EXPECT_STREQ("fake name", component.name.c_str());
EXPECT_EQ(expected_attrs, component.installer_attributes);
EXPECT_TRUE(component.requires_network_encryption);
+ EXPECT_TRUE(component.supports_group_policy_enable_component_updates);
}
} // namespace component_updater
diff --git a/chromium/components/component_updater/mock_component_updater_service.h b/chromium/components/component_updater/mock_component_updater_service.h
index f8d1447cc96..7d1ad245256 100644
--- a/chromium/components/component_updater/mock_component_updater_service.h
+++ b/chromium/components/component_updater/mock_component_updater_service.h
@@ -11,6 +11,9 @@
#ifndef COMPONENTS_COMPONENT_UPDATER_MOCK_COMPONENT_UPDATER_SERVICE_H_
#define COMPONENTS_COMPONENT_UPDATER_MOCK_COMPONENT_UPDATER_SERVICE_H_
+#include <string>
+#include <vector>
+
#include "base/callback.h"
#include "base/sequenced_task_runner.h"
#include "components/component_updater/component_updater_service.h"
@@ -33,6 +36,9 @@ class MockComponentUpdateService : public ComponentUpdateService {
bool(const std::string& id));
MOCK_CONST_METHOD0(GetComponentIDs,
std::vector<std::string>());
+ MOCK_CONST_METHOD1(
+ GetComponentForMimeType,
+ std::unique_ptr<ComponentInfo>(const std::string& mime_type));
MOCK_METHOD0(GetOnDemandUpdater,
OnDemandUpdater&());
MOCK_METHOD2(MaybeThrottle,
diff --git a/chromium/components/component_updater/pref_names.cc b/chromium/components/component_updater/pref_names.cc
index 98e9fcab91d..861ee447d1c 100644
--- a/chromium/components/component_updater/pref_names.cc
+++ b/chromium/components/component_updater/pref_names.cc
@@ -23,6 +23,10 @@ const char kSwReporterLastExitCode[] = "software_reporter.last_exit_code";
const char kSwReporterLastTimeTriggered[] =
"software_reporter.last_time_triggered";
+// The last time SwReporter ran in send report mode. Saved in local state.
+const char kSwReporterLastTimeSentReport[] =
+ "software_reporter.last_time_sent_report";
+
// Identify whether there is a pending prompt to be added to the Chrome menu.
const char kSwReporterPendingPrompt[] = "software_reporter.pending_prompt";
diff --git a/chromium/components/component_updater/pref_names.h b/chromium/components/component_updater/pref_names.h
index 347c1df3301..7ac5147825d 100644
--- a/chromium/components/component_updater/pref_names.h
+++ b/chromium/components/component_updater/pref_names.h
@@ -17,6 +17,7 @@ extern const char kRecoveryComponentUnpackPath[];
extern const char kSwReporterLastExitCode[];
extern const char kSwReporterLastTimeTriggered[];
extern const char kSwReporterPendingPrompt[];
+extern const char kSwReporterLastTimeSentReport[];
// Profile prefs.
extern const char kSwReporterPromptReason[];
diff --git a/chromium/components/component_updater/updater_state_unittest_win.cc b/chromium/components/component_updater/updater_state_unittest_win.cc
new file mode 100644
index 00000000000..bda3094254c
--- /dev/null
+++ b/chromium/components/component_updater/updater_state_unittest_win.cc
@@ -0,0 +1,103 @@
+// 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 "base/macros.h"
+#include "base/time/time.h"
+#include "base/version.h"
+#include "components/component_updater/updater_state_win.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace component_updater {
+
+class UpdaterStateTest : public testing::Test {
+ public:
+ UpdaterStateTest() {}
+ ~UpdaterStateTest() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UpdaterStateTest);
+};
+
+TEST_F(UpdaterStateTest, MakeInstallerAttributes) {
+ // is_machine argument does not make a difference in this test as, the
+ // values of the |updater_state| are fake.
+ auto updater_state = UpdaterState::Create(false);
+
+ // Sanity check all members.
+ updater_state->google_update_version_ = base::Version("1.0");
+ updater_state->last_autoupdate_started_ = base::Time::NowFromSystemTime();
+ updater_state->last_checked_ = base::Time::NowFromSystemTime();
+ updater_state->is_joined_to_domain_ = false;
+ updater_state->is_autoupdate_check_enabled_ = true;
+ updater_state->chrome_update_policy_ = 1;
+
+ auto installer_attributes = updater_state->MakeInstallerAttributes();
+
+ EXPECT_STREQ("1.0", installer_attributes.at("googleupdatever").c_str());
+ EXPECT_STREQ("0", installer_attributes.at("laststarted").c_str());
+ EXPECT_STREQ("0", installer_attributes.at("lastchecked").c_str());
+ EXPECT_STREQ("0", installer_attributes.at("domainjoined").c_str());
+ EXPECT_STREQ("1", installer_attributes.at("autoupdatecheckenabled").c_str());
+ EXPECT_STREQ("1", installer_attributes.at("chromeupdatepolicy").c_str());
+
+ // Tests some of the remaining values.
+ updater_state = UpdaterState::Create(false);
+
+ // Don't serialize an invalid version if it could not be read.
+ updater_state->google_update_version_ = base::Version();
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_EQ(0u, installer_attributes.count("googleupdatever"));
+
+ updater_state->google_update_version_ = base::Version("0.0.0.0");
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_STREQ("0.0.0.0", installer_attributes.at("googleupdatever").c_str());
+
+ updater_state->last_autoupdate_started_ =
+ base::Time::NowFromSystemTime() - base::TimeDelta::FromDays(15);
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_STREQ("408", installer_attributes.at("laststarted").c_str());
+
+ updater_state->last_autoupdate_started_ =
+ base::Time::NowFromSystemTime() - base::TimeDelta::FromDays(90);
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_STREQ("1344", installer_attributes.at("laststarted").c_str());
+
+ // Don't serialize the time if it could not be read.
+ updater_state->last_autoupdate_started_ = base::Time();
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_EQ(0u, installer_attributes.count("laststarted"));
+
+ updater_state->last_checked_ =
+ base::Time::NowFromSystemTime() - base::TimeDelta::FromDays(15);
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_STREQ("408", installer_attributes.at("lastchecked").c_str());
+
+ updater_state->last_checked_ =
+ base::Time::NowFromSystemTime() - base::TimeDelta::FromDays(90);
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_STREQ("1344", installer_attributes.at("lastchecked").c_str());
+
+ // Don't serialize the time if it could not be read.
+ updater_state->last_checked_ = base::Time();
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_EQ(0u, installer_attributes.count("lastchecked"));
+
+ updater_state->is_joined_to_domain_ = true;
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_STREQ("1", installer_attributes.at("domainjoined").c_str());
+
+ updater_state->is_autoupdate_check_enabled_ = false;
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_STREQ("0", installer_attributes.at("autoupdatecheckenabled").c_str());
+
+ updater_state->chrome_update_policy_ = 0;
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_STREQ("0", installer_attributes.at("chromeupdatepolicy").c_str());
+
+ updater_state->chrome_update_policy_ = -1;
+ installer_attributes = updater_state->MakeInstallerAttributes();
+ EXPECT_STREQ("-1", installer_attributes.at("chromeupdatepolicy").c_str());
+}
+
+} // namespace component_updater
diff --git a/chromium/components/component_updater/updater_state_win.cc b/chromium/components/component_updater/updater_state_win.cc
new file mode 100644
index 00000000000..b7fd10f7f75
--- /dev/null
+++ b/chromium/components/component_updater/updater_state_win.cc
@@ -0,0 +1,195 @@
+
+// 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 "components/component_updater/updater_state_win.h"
+
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+
+#include "base/win/registry.h"
+#include "base/win/win_util.h"
+
+namespace component_updater {
+
+namespace {
+
+// Google Update group policy settings.
+const wchar_t kGoogleUpdatePoliciesKey[] =
+ L"SOFTWARE\\Policies\\Google\\Update";
+const wchar_t kCheckPeriodOverrideMinutes[] = L"AutoUpdateCheckPeriodMinutes";
+const wchar_t kUpdatePolicyValue[] = L"UpdateDefault";
+const wchar_t kChromeUpdatePolicyOverride[] =
+ L"Update{8A69D345-D564-463C-AFF1-A69D9E530F96}";
+
+// Don't allow update periods longer than six weeks (Chrome release cadence).
+const int kCheckPeriodOverrideMinutesMax = 60 * 24 * 7 * 6;
+
+// Google Update registry settings.
+const wchar_t kRegPathGoogleUpdate[] = L"Software\\Google\\Update";
+const wchar_t kRegPathClientsGoogleUpdate[] =
+ L"Software\\Google\\Update\\Clients\\"
+ L"{430FD4D0-B729-4F61-AA34-91526481799D}";
+const wchar_t kRegValueGoogleUpdatePv[] = L"pv";
+const wchar_t kRegValueLastStartedAU[] = L"LastStartedAU";
+const wchar_t kRegValueLastChecked[] = L"LastChecked";
+
+} // namespace
+
+UpdaterState::UpdaterState(bool is_machine) : is_machine_(is_machine) {}
+
+std::unique_ptr<UpdaterState> UpdaterState::Create(bool is_machine) {
+ std::unique_ptr<UpdaterState> updater_state(new UpdaterState(is_machine));
+ updater_state->ReadState();
+ return updater_state;
+}
+
+void UpdaterState::ReadState() {
+ google_update_version_ = GetGoogleUpdateVersion(is_machine_);
+ last_autoupdate_started_ = GetGoogleUpdateLastStartedAU(is_machine_);
+ last_checked_ = GetGoogleUpdateLastChecked(is_machine_);
+ is_joined_to_domain_ = IsJoinedToDomain();
+ is_autoupdate_check_enabled_ = IsAutoupdateCheckEnabled();
+ chrome_update_policy_ = GetChromeUpdatePolicy();
+}
+
+update_client::InstallerAttributes UpdaterState::MakeInstallerAttributes()
+ const {
+ update_client::InstallerAttributes installer_attributes;
+
+ if (google_update_version_.IsValid())
+ installer_attributes["googleupdatever"] =
+ google_update_version_.GetString();
+
+ const base::Time now = base::Time::NowFromSystemTime();
+ if (!last_autoupdate_started_.is_null())
+ installer_attributes["laststarted"] =
+ NormalizeTimeDelta(now - last_autoupdate_started_);
+ if (!last_checked_.is_null())
+ installer_attributes["lastchecked"] =
+ NormalizeTimeDelta(now - last_checked_);
+
+ installer_attributes["domainjoined"] = is_joined_to_domain_ ? "1" : "0";
+ installer_attributes["autoupdatecheckenabled"] =
+ is_autoupdate_check_enabled_ ? "1" : "0";
+
+ DCHECK(chrome_update_policy_ >= 0 && chrome_update_policy_ <= 3 ||
+ chrome_update_policy_ == -1);
+ installer_attributes["chromeupdatepolicy"] =
+ base::IntToString(chrome_update_policy_);
+
+ return installer_attributes;
+}
+
+std::string UpdaterState::NormalizeTimeDelta(const base::TimeDelta& delta) {
+ const base::TimeDelta two_weeks = base::TimeDelta::FromDays(14);
+ const base::TimeDelta two_months = base::TimeDelta::FromDays(60);
+
+ std::string val; // Contains the value to return in hours.
+ if (delta <= two_weeks) {
+ val = "0";
+ } else if (two_weeks < delta && delta <= two_months) {
+ val = "408"; // 2 weeks in hours.
+ } else {
+ val = "1344"; // 2*28 days in hours.
+ }
+
+ DCHECK(!val.empty());
+ return val;
+}
+
+base::Version UpdaterState::GetGoogleUpdateVersion(bool is_machine) {
+ const HKEY root_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ base::string16 version;
+ base::win::RegKey key;
+
+ if (key.Open(root_key, kRegPathClientsGoogleUpdate,
+ KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS &&
+ key.ReadValue(kRegValueGoogleUpdatePv, &version) == ERROR_SUCCESS) {
+ return base::Version(base::UTF16ToUTF8(version));
+ }
+
+ return base::Version();
+}
+
+base::Time UpdaterState::GetGoogleUpdateLastStartedAU(bool is_machine) {
+ return GetGoogleUpdateTimeValue(is_machine, kRegValueLastStartedAU);
+}
+
+base::Time UpdaterState::GetGoogleUpdateLastChecked(bool is_machine) {
+ return GetGoogleUpdateTimeValue(is_machine, kRegValueLastChecked);
+}
+
+base::Time UpdaterState::GetGoogleUpdateTimeValue(bool is_machine,
+ const wchar_t* value_name) {
+ const HKEY root_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ base::win::RegKey update_key;
+
+ if (update_key.Open(root_key, kRegPathGoogleUpdate,
+ KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ DWORD value(0);
+ if (update_key.ReadValueDW(value_name, &value) == ERROR_SUCCESS) {
+ return base::Time::FromTimeT(value);
+ }
+ }
+
+ return base::Time();
+}
+
+bool UpdaterState::IsAutoupdateCheckEnabled() {
+ // Check the auto-update check period override. If it is 0 or exceeds the
+ // maximum timeout, then for all intents and purposes auto updates are
+ // disabled.
+ base::win::RegKey policy_key;
+ DWORD value = 0;
+ if (policy_key.Open(HKEY_LOCAL_MACHINE, kGoogleUpdatePoliciesKey,
+ KEY_QUERY_VALUE) == ERROR_SUCCESS &&
+ policy_key.ReadValueDW(kCheckPeriodOverrideMinutes, &value) ==
+ ERROR_SUCCESS &&
+ (value == 0 || value > kCheckPeriodOverrideMinutesMax)) {
+ return false;
+ }
+
+ return true;
+}
+
+// Returns -1 if the policy is not found or the value was invalid. Otherwise,
+// returns a value in the [0, 3] range, representing the value of the
+// Chrome update group policy.
+int UpdaterState::GetChromeUpdatePolicy() {
+ const int kMaxUpdatePolicyValue = 3;
+
+ base::win::RegKey policy_key;
+
+ if (policy_key.Open(HKEY_LOCAL_MACHINE, kGoogleUpdatePoliciesKey,
+ KEY_QUERY_VALUE) != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ DWORD value = 0;
+ // First try to read the Chrome-specific override.
+ if (policy_key.ReadValueDW(kChromeUpdatePolicyOverride, &value) ==
+ ERROR_SUCCESS &&
+ value <= kMaxUpdatePolicyValue) {
+ return value;
+ }
+
+ // Try to read default override.
+ if (policy_key.ReadValueDW(kUpdatePolicyValue, &value) == ERROR_SUCCESS &&
+ value <= kMaxUpdatePolicyValue) {
+ return value;
+ }
+
+ return -1;
+}
+
+bool UpdaterState::IsJoinedToDomain() {
+ return base::win::IsEnrolledToDomain();
+}
+
+} // namespace component_updater
diff --git a/chromium/components/component_updater/updater_state_win.h b/chromium/components/component_updater/updater_state_win.h
new file mode 100644
index 00000000000..f09f7d8ce6f
--- /dev/null
+++ b/chromium/components/component_updater/updater_state_win.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef COMPONENTS_COMPONENT_UPDATER_UPDATER_STATE_WIN_H_
+#define COMPONENTS_COMPONENT_UPDATER_UPDATER_STATE_WIN_H_
+
+#include <memory>
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/time/time.h"
+#include "base/version.h"
+#include "components/update_client/update_client.h"
+
+namespace component_updater {
+
+// TODO(sorin): implement this in terms of
+// chrome/installer/util/google_update_settings (crbug.com/615187).
+class UpdaterState {
+ public:
+ static std::unique_ptr<UpdaterState> Create(bool is_machine);
+
+ update_client::InstallerAttributes MakeInstallerAttributes() const;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(UpdaterStateTest, MakeInstallerAttributes);
+
+ explicit UpdaterState(bool is_machine);
+
+ // This function is best-effort. It updates the class members with
+ // the relevant values that could be retrieved.
+ void ReadState();
+
+ static base::Version GetGoogleUpdateVersion(bool is_machine);
+ static bool IsAutoupdateCheckEnabled();
+ static bool IsJoinedToDomain();
+ static base::Time GetGoogleUpdateLastStartedAU(bool is_machine);
+ static base::Time GetGoogleUpdateLastChecked(bool is_machine);
+ static base::Time GetGoogleUpdateTimeValue(bool is_machine,
+ const wchar_t* value_name);
+ static int GetChromeUpdatePolicy();
+
+ static std::string NormalizeTimeDelta(const base::TimeDelta& delta);
+
+ bool is_machine_;
+ base::Version google_update_version_;
+ base::Time last_autoupdate_started_;
+ base::Time last_checked_;
+ bool is_joined_to_domain_ = false;
+ bool is_autoupdate_check_enabled_ = false;
+ int chrome_update_policy_ = 0;
+};
+
+} // namespace component_updater
+
+#endif // COMPONENTS_COMPONENT_UPDATER_UPDATER_STATE_WIN_H_
diff --git a/chromium/components/components.gyp b/chromium/components/components.gyp
deleted file mode 100644
index bbf57795ca7..00000000000
--- a/chromium/components/components.gyp
+++ /dev/null
@@ -1,221 +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.
-
-{
- 'variables': {
- # This turns on e.g. the filename-based detection of which
- # platforms to include source files on (e.g. files ending in
- # _mac.h or _mac.cc are only compiled on MacOSX).
- 'chromium_code': 1,
- },
- 'includes': [
- 'about_handler.gypi',
- 'auto_login_parser.gypi',
- 'autofill.gypi',
- 'base32.gypi',
- 'bookmarks.gypi',
- 'browser_sync.gypi',
- 'browsing_data_ui.gypi',
- 'bubble.gypi',
- 'captive_portal.gypi',
- 'cast_certificate.gypi',
- 'certificate_reporting.gypi',
- 'client_update_protocol.gypi',
- 'cloud_devices.gypi',
- 'component_updater.gypi',
- 'content_settings.gypi',
- 'cookie_config.gypi',
- 'crash.gypi',
- 'cronet.gypi',
- 'crx_file.gypi',
- 'data_reduction_proxy.gypi',
- 'data_usage.gypi',
- 'data_use_measurement.gypi',
- 'device_event_log.gypi',
- 'dom_distiller.gypi',
- 'error_page.gypi',
- 'favicon.gypi',
- 'favicon_base.gypi',
- 'flags_ui.gypi',
- 'gcm_driver.gypi',
- 'google.gypi',
- 'guest_view.gypi',
- 'handoff.gypi',
- 'history.gypi',
- 'image_fetcher.gypi',
- 'infobars.gypi',
- 'invalidation.gypi',
- 'json_schema.gypi',
- 'keyed_service.gypi',
- 'language_usage_metrics.gypi',
- 'leveldb_proto.gypi',
- 'login.gypi',
- 'memory_pressure.gypi',
- 'metrics.gypi',
- 'metrics_services_manager.gypi',
- 'navigation_metrics.gypi',
- 'net_log.gypi',
- 'network_session_configurator.gypi',
- 'network_time.gypi',
- 'ntp_snippets.gypi',
- 'ntp_tiles.gypi',
- 'offline_pages.gypi',
- 'omnibox.gypi',
- 'onc.gypi',
- 'open_from_clipboard.gypi',
- 'os_crypt.gypi',
- 'ownership.gypi',
- 'password_manager.gypi',
- 'plugins.gypi',
- 'policy.gypi',
- 'precache.gypi',
- 'pref_registry.gypi',
- 'profile_metrics.gypi',
- 'proxy_config.gypi',
- 'query_parser.gypi',
- 'rappor.gypi',
- 'search.gypi',
- 'search_engines.gypi',
- 'search_provider_logos.gypi',
- 'security_interstitials.gypi',
- 'security_state.gypi',
- 'sessions.gypi',
- 'signin.gypi',
- 'ssl_config.gypi',
- 'ssl_errors.gypi',
- 'subresource_filter.gypi',
- 'suggestions.gypi',
- 'supervised_user_error_page.gypi',
- 'sync_bookmarks.gypi',
- 'sync_driver.gypi',
- 'sync_sessions.gypi',
- 'syncable_prefs.gypi',
- 'toolbar.gypi',
- 'translate.gypi',
- 'undo.gypi',
- 'update_client.gypi',
- 'upload_list.gypi',
- 'url_matcher.gypi',
- 'user_prefs.gypi',
- 'variations.gypi',
- 'version_info.gypi',
- 'version_ui.gypi',
- 'web_resource.gypi',
- 'web_restrictions.gypi',
- 'webdata.gypi',
- 'webdata_services.gypi',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'includes': [
- 'external_video_surface.gypi',
- 'service_tab_launcher.gypi',
- ],
- }],
- ['OS != "ios"', {
- 'includes': [
- 'app_modal.gypi',
- 'browsing_data.gypi',
- 'cdm.gypi',
- 'certificate_transparency.gypi',
- 'contextual_search.gypi',
- 'devtools_discovery.gypi',
- 'devtools_http_handler.gypi',
- 'display_compositor.gypi',
- 'domain_reliability.gypi',
- 'drive.gypi',
- 'memory_coordinator.gypi',
- 'navigation_interception.gypi',
- 'network_hints.gypi',
- 'packed_ct_ev_whitelist.gypi',
- 'page_load_metrics.gypi',
- 'power.gypi',
- 'renderer_context_menu.gypi',
- 'safe_browsing_db.gypi',
- 'safe_json.gypi',
- 'startup_metric_utils.gypi',
- 'visitedlink.gypi',
- 'wallpaper.gypi',
- 'web_cache.gypi',
- 'web_contents_delegate_android.gypi',
- 'web_modal.gypi',
- 'webmessaging.gypi',
- 'webusb.gypi',
- 'zoom.gypi',
- ],
- }],
- ['OS == "ios"', {
- 'includes': [
- 'webp_transcode.gypi',
- ],
- }],
- ['OS != "ios" and OS != "android"', {
- 'includes': [
- 'audio_modem.gypi',
- 'chooser_controller.gypi',
- 'copresence.gypi',
- 'feedback.gypi',
- 'proximity_auth.gypi',
- 'storage_monitor.gypi',
- ]
- }],
- ['chromeos == 1', {
- 'includes': [
- 'arc.gypi',
- 'pairing.gypi',
- 'quirks.gypi',
- 'timers.gypi',
- 'wifi_sync.gypi',
- ],
- }],
- ['OS == "win" or OS == "mac"', {
- 'includes': [
- 'wifi.gypi',
- ],
- }],
- ['OS == "win"', {
- 'includes': [
- 'browser_watcher.gypi',
- ],
- }],
- ['chromeos == 1 or use_aura == 1', {
- 'includes': [
- 'session_manager.gypi',
- 'user_manager.gypi',
- ],
- }],
- ['toolkit_views==1', {
- 'includes': [
- 'constrained_window.gypi',
- ],
- }],
- ['enable_basic_printing==1 or enable_print_preview==1', {
- 'includes': [
- 'printing.gypi',
- ],
- }],
- ['enable_plugins==1', {
- 'includes': [
- 'pdf.gypi',
- ],
- }],
- # TODO(tbarzic): Remove chromeos condition when there are non-chromeos apps
- # in components/apps.
- ['enable_extensions == 1 and chromeos == 1', {
- 'includes': [
- 'chrome_apps.gypi',
- ],
- }],
- ['enable_rlz_support==1', {
- 'includes': [
- 'rlz.gypi',
- ],
- }],
- ['use_ash==1', {
- 'includes': [
- 'exo.gypi',
- ],
- }],
- ],
-}
diff --git a/chromium/components/components_browsertests.isolate b/chromium/components/components_browsertests.isolate
deleted file mode 100644
index c3a8b561e6b..00000000000
--- a/chromium/components/components_browsertests.isolate
+++ /dev/null
@@ -1,85 +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.
-{
- 'conditions': [
- ['use_x11==0', {
- 'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/components_browsertests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--msan=<(msan)',
- '--tsan=<(tsan)',
- ],
- },
- }],
- ['use_x11==1', {
- 'variables': {
- 'command': [
- '../testing/xvfb.py',
- '<(PRODUCT_DIR)',
- '<(PRODUCT_DIR)/components_browsertests',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--msan=<(msan)',
- '--tsan=<(tsan)',
- ],
- 'files': [
- '../testing/xvfb.py',
- '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
- ],
- },
- }],
- ['OS=="linux" or OS=="mac" or OS=="win"', {
- 'variables': {
- 'files': [
- '../testing/test_env.py',
- ],
- },
- }],
- ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', {
- 'variables': {
- 'files': [
- 'test/data/',
- 'dom_distiller/core/javascript/',
- '../third_party/dom_distiller_js/dist/test/data/',
- '<(PRODUCT_DIR)/components_tests_resources.pak',
- '<(PRODUCT_DIR)/content_shell.pak',
- ],
- },
- }],
- ['OS=="linux"', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/libosmesa.so',
- ],
- },
- }],
- ['OS=="mac"', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/Content Shell.app/',
- ],
- },
- }],
- ['OS=="mac" and asan==1 and fastbuild==0', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/Content Shell Framework.framework.dSYM/',
- '<(PRODUCT_DIR)/Content Shell Helper.app.dSYM/',
- '<(PRODUCT_DIR)/Content Shell.app.dSYM/',
- '<(PRODUCT_DIR)/components_browsertests.dSYM/',
- ],
- },
- }],
- ],
- 'includes': [
- '../base/base.isolate',
- '../gin/v8.isolate',
- '../ui/gl/gl.isolate',
- ],
-}
diff --git a/chromium/components/components_browsertests_apk.isolate b/chromium/components/components_browsertests_apk.isolate
deleted file mode 100644
index ed188bc0639..00000000000
--- a/chromium/components/components_browsertests_apk.isolate
+++ /dev/null
@@ -1,28 +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.
-{
- 'includes': [
- '../build/android/android.isolate',
- '../net/tools/testserver/testserver.isolate',
- 'components_browsertests.isolate',
- ],
- 'variables': {
- 'command': [
- '<(PRODUCT_DIR)/bin/run_components_browsertests',
- '--logcat-output-dir', '${ISOLATED_OUTDIR}/logcats',
- ],
- 'files': [
- '../base/base.isolate',
- '../build/config/',
- '../gin/v8.isolate',
- '../third_party/angle/angle.isolate',
- '../third_party/icu/icu.isolate',
- '../third_party/instrumented_libraries/instrumented_libraries.isolate',
- '../ui/gl/gl.isolate',
- '<(PRODUCT_DIR)/bin/run_components_browsertests',
- '<(PRODUCT_DIR)/components_browsertests_apk/',
- 'components_browsertests.isolate',
- ]
- },
-}
diff --git a/chromium/components/components_chromium_strings.grd b/chromium/components/components_chromium_strings.grd
index ff021d2ae84..e3019ed5b4b 100644
--- a/chromium/components/components_chromium_strings.grd
+++ b/chromium/components/components_chromium_strings.grd
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<grit latest_public_release="0" current_release="1"
- source_lang_id="en" enc_check="möl">
+ output_all_resource_defines="false" source_lang_id="en" enc_check="möl">
<outputs>
<output filename="grit/components_chromium_strings.h" type="rc_header">
<emit emit_type='prepend'></emit>
diff --git a/chromium/components/components_google_chrome_strings.grd b/chromium/components/components_google_chrome_strings.grd
index 548cbcbbd5f..3aef0e53828 100644
--- a/chromium/components/components_google_chrome_strings.grd
+++ b/chromium/components/components_google_chrome_strings.grd
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<grit latest_public_release="0" current_release="1"
- source_lang_id="en" enc_check="möl">
+ output_all_resource_defines="false" source_lang_id="en" enc_check="möl">
<outputs>
<output filename="grit/components_google_chrome_strings.h" type="rc_header">
<emit emit_type='prepend'></emit>
diff --git a/chromium/components/components_locale_settings.grd b/chromium/components/components_locale_settings.grd
index 0b94b300cb1..1db75317168 100644
--- a/chromium/components/components_locale_settings.grd
+++ b/chromium/components/components_locale_settings.grd
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1">
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
<outputs>
<output filename="grit/components_locale_settings.h" type="rc_header">
<emit emit_type='prepend'></emit>
diff --git a/chromium/components/components_resources.gyp b/chromium/components/components_resources.gyp
deleted file mode 100644
index 9e092c27631..00000000000
--- a/chromium/components/components_resources.gyp
+++ /dev/null
@@ -1,93 +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.
-
-{
- 'variables': {
- 'about_credits_file': '<(SHARED_INTERMEDIATE_DIR)/about_credits.html',
- 'about_credits_file_bro': '<(SHARED_INTERMEDIATE_DIR)/about_credits.bro',
- },
- 'targets': [
- {
- # GN version: //components/resources
- 'target_name': 'components_resources',
- 'type': 'none',
- 'dependencies': [
- 'compressed_about_credits',
- ],
- 'hard_dependency': 1,
- 'variables': {
- 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/components',
- },
- 'actions': [
- {
- # GN version: //components/resources:components_resources
- 'action_name': 'generate_components_resources',
- 'variables': {
- 'grit_grd_file': 'resources/components_resources.grd',
- 'grit_additional_defines': [
- '-E', 'about_credits_file=<(about_credits_file_bro)',
- ],
- },
- 'includes': [ '../build/grit_action.gypi' ],
- },
- {
- # GN version: //components/resources:components_scaled_resources
- 'action_name': 'generate_components_scaled_resources',
- 'variables': {
- 'grit_grd_file': 'resources/components_scaled_resources.grd',
- },
- 'includes': [ '../build/grit_action.gypi' ],
- },
- ],
- 'includes': [ '../build/grit_target.gypi' ],
- },
- {
- 'target_name': 'compressed_about_credits',
- 'type': 'none',
- 'actions': [
- {
- 'variables': {
- 'input_file': '<(about_credits_file)',
- 'output_file': '<(about_credits_file_bro)',
- },
- 'includes': ['../third_party/brotli/bro.gypi'],
- }
- ],
- 'dependencies': [
- 'about_credits'
- ],
- },
- {
- # GN version: //components/resources:about_credits
- 'target_name': 'about_credits',
- 'type': 'none',
- 'hard_dependency': 1,
- 'actions': [
- {
- 'variables': {
- 'generator_path': '../tools/licenses.py',
- },
- 'action_name': 'generate_about_credits',
- 'inputs': [
- # TODO(phajdan.jr): make licenses.py print license input files so
- # about:credits gets rebuilt when one changes.
- '<(generator_path)',
- 'about_ui/resources/about_credits.tmpl',
- 'about_ui/resources/about_credits_entry.tmpl',
- ],
- 'outputs': [
- '<(about_credits_file)',
- ],
- 'action': ['python',
- '<(generator_path)',
- '--target-os=<(OS)',
- 'credits',
- '<(about_credits_file)',
- ],
- 'message': 'Generating about:credits',
- },
- ],
- },
- ],
-}
diff --git a/chromium/components/components_strings.grd b/chromium/components/components_strings.grd
index d8e82d30ee3..95920283b2c 100644
--- a/chromium/components/components_strings.grd
+++ b/chromium/components/components_strings.grd
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<grit latest_public_release="0" current_release="1"
- source_lang_id="en" enc_check="möl">
+ output_all_resource_defines="false" source_lang_id="en" enc_check="möl">
<outputs>
<output filename="grit/components_strings.h" type="rc_header">
<emit emit_type='prepend'></emit>
@@ -187,6 +187,7 @@
<part file="bookmark_bar_strings.grdp" />
<part file="bookmark_component_strings.grdp" />
<part file="browser_sync_strings.grdp" />
+ <part file="browsing_data_strings.grdp" />
<part file="components_settings_strings.grdp" />
<part file="crash_strings.grdp" />
<part file="dialog_strings.grdp" />
@@ -202,6 +203,7 @@
<part file="pageinfo_strings.grdp" />
<part file="password_manager_strings.grdp" />
<part file="pdf_strings.grdp" />
+ <part file="physical_web_ui_strings.grdp" />
<part file="policy_strings.grdp" />
<part file="security_interstitials_strings.grdp" />
<part file="ssl_errors_strings.grdp" />
@@ -227,8 +229,22 @@
<message name="IDS_OK" desc="Used for OK on buttons">
OK
</message>
+ <message name="IDS_NO_THANKS" desc="Used to dismiss various prompts.">
+ No thanks
+ </message>
+ <if expr="not use_titlecase">
+ <message name="IDS_NOT_NOW" desc="Used on a button that avoids taking a suggested action. The action will likely be suggested again or automatically taken later.">
+ Not now
+ </message>
+ </if>
+ <if expr="use_titlecase">
+ <message name="IDS_NOT_NOW" desc="In Title Case: Used on a button that avoids taking a suggested action. The action will likely be suggested again or automatically taken later.">
+ Not Now
+ </message>
+ </if>
+
<message name="IDS_PLUGIN_NOT_SUPPORTED" desc="The placeholder text for an unsupported plugin.">
- This plugin is not supported.
+ This plugin is not supported
</message>
<if expr="not is_android">
<if expr="not use_titlecase">
diff --git a/chromium/components/components_strings.gyp b/chromium/components/components_strings.gyp
deleted file mode 100644
index e73a24b40cc..00000000000
--- a/chromium/components/components_strings.gyp
+++ /dev/null
@@ -1,51 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'components_strings',
- 'type': 'none',
- 'hard_dependency': 1,
- 'variables': {
- 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/components/strings',
- },
- 'actions': [
- {
- # GN version: //components/strings:components_strings
- 'action_name': 'generate_components_strings',
- 'variables': {
- 'grit_grd_file': 'components_strings.grd',
- },
- 'includes': [ '../build/grit_action.gypi' ],
- },
- {
- # GN version: //components/strings:components_chromium_strings
- 'action_name': 'generate_components_chromium_strings',
- 'variables': {
- 'grit_grd_file': 'components_chromium_strings.grd',
- },
- 'includes': [ '../build/grit_action.gypi' ],
- },
- {
- # GN version: //components/strings:components_google_chrome_strings
- 'action_name': 'generate_components_google_chrome_strings',
- 'variables': {
- 'grit_grd_file': 'components_google_chrome_strings.grd',
- },
- 'includes': [ '../build/grit_action.gypi' ],
- },
- {
- # GN version: //components/strings:components_locale_settings
- 'action_name': 'generate_components_locale_settings',
- 'variables': {
- 'grit_grd_file': 'components_locale_settings.grd',
- },
- 'includes': [ '../build/grit_action.gypi' ],
- },
- ],
- 'includes': [ '../build/grit_target.gypi' ],
- },
- ],
-}
diff --git a/chromium/components/components_tests.gyp b/chromium/components/components_tests.gyp
deleted file mode 100644
index 83b8c6eff96..00000000000
--- a/chromium/components/components_tests.gyp
+++ /dev/null
@@ -1,2058 +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.
-
-{
- 'variables': {
- # This turns on e.g. the filename-based detection of which
- # platforms to include source files on (e.g. files ending in
- # _mac.h or _mac.cc are only compiled on MacOSX).
- 'chromium_code': 1,
-
- # Note: sources list duplicated in GN build. In the GN build,
- # each component has its own unit tests target defined in its
- # directory that are then linked into the final components_unittests.
- 'auto_login_parser_unittest_sources': [
- 'auto_login_parser/auto_login_parser_unittest.cc',
- ],
- 'autofill_unittest_sources': [
- 'autofill/content/browser/content_autofill_driver_unittest.cc',
- 'autofill/content/browser/payments/payments_client_unittest.cc',
- 'autofill/content/public/cpp/autofill_types_struct_traits_unittest.cc',
- 'autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc',
- 'autofill/core/browser/address_field_unittest.cc',
- 'autofill/core/browser/address_i18n_unittest.cc',
- 'autofill/core/browser/address_unittest.cc',
- 'autofill/core/browser/address_rewriter_unittest.cc',
- 'autofill/core/browser/autocomplete_history_manager_unittest.cc',
- 'autofill/core/browser/autofill_country_unittest.cc',
- 'autofill/core/browser/autofill_data_model_unittest.cc',
- 'autofill/core/browser/autofill_data_util_unittest.cc',
- 'autofill/core/browser/autofill_download_manager_unittest.cc',
- 'autofill/core/browser/autofill_external_delegate_unittest.cc',
- 'autofill/core/browser/autofill_field_unittest.cc',
- 'autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc',
- 'autofill/core/browser/autofill_manager_unittest.cc',
- 'autofill/core/browser/autofill_merge_unittest.cc',
- 'autofill/core/browser/autofill_metrics_unittest.cc',
- 'autofill/core/browser/autofill_profile_comparator_unittest.cc',
- 'autofill/core/browser/autofill_profile_unittest.cc',
- 'autofill/core/browser/autofill_type_unittest.cc',
- 'autofill/core/browser/contact_info_unittest.cc',
- 'autofill/core/browser/country_names_unittest.cc',
- 'autofill/core/browser/credit_card_field_unittest.cc',
- 'autofill/core/browser/credit_card_unittest.cc',
- 'autofill/core/browser/field_candidates_unittest.cc',
- 'autofill/core/browser/form_field_unittest.cc',
- 'autofill/core/browser/form_structure_unittest.cc',
- 'autofill/core/browser/legal_message_line_unittest.cc',
- 'autofill/core/browser/name_field_unittest.cc',
- 'autofill/core/browser/password_generator_unittest.cc',
- 'autofill/core/browser/payments/full_card_request_unittest.cc',
- 'autofill/core/browser/payments/payments_service_url_unittest.cc',
- 'autofill/core/browser/personal_data_manager_unittest.cc',
- 'autofill/core/browser/phone_field_unittest.cc',
- 'autofill/core/browser/phone_number_i18n_unittest.cc',
- 'autofill/core/browser/phone_number_unittest.cc',
- 'autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc',
- 'autofill/core/browser/validation_unittest.cc',
- 'autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc',
- 'autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc',
- 'autofill/core/browser/webdata/autofill_table_unittest.cc',
- 'autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc',
- 'autofill/core/browser/webdata/web_data_service_unittest.cc',
- 'autofill/core/common/autofill_l10n_util_unittest.cc',
- 'autofill/core/common/autofill_regexes_unittest.cc',
- 'autofill/core/common/autofill_util_unittest.cc',
- 'autofill/core/common/form_data_unittest.cc',
- 'autofill/core/common/form_field_data_unittest.cc',
- 'autofill/core/common/password_form_fill_data_unittest.cc',
- 'autofill/core/common/save_password_progress_logger_unittest.cc',
- ],
- 'base32_unittest_sources': [
- 'base32/base32_unittest.cc',
- ],
- 'bookmarks_unittest_sources': [
- 'bookmarks/browser/bookmark_codec_unittest.cc',
- 'bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc',
- 'bookmarks/browser/bookmark_index_unittest.cc',
- 'bookmarks/browser/bookmark_model_unittest.cc',
- 'bookmarks/browser/bookmark_utils_unittest.cc',
- 'bookmarks/managed/managed_bookmarks_tracker_unittest.cc',
- ],
- 'browser_sync_unittest_sources': [
- 'browser_sync/browser/profile_sync_service_autofill_unittest.cc',
- 'browser_sync/browser/profile_sync_service_bookmark_unittest.cc',
- 'browser_sync/browser/profile_sync_service_startup_unittest.cc',
- 'browser_sync/browser/profile_sync_service_typed_url_unittest.cc',
- 'browser_sync/browser/profile_sync_service_unittest.cc',
- ],
- 'browser_watcher_unittest_sources': [
- 'browser_watcher/endsession_watcher_window_win_unittest.cc',
- 'browser_watcher/exit_code_watcher_win_unittest.cc',
- 'browser_watcher/exit_funnel_win_unittest.cc',
- 'browser_watcher/watcher_client_win_unittest.cc',
- 'browser_watcher/watcher_metrics_provider_win_unittest.cc',
- 'browser_watcher/window_hang_monitor_win_unittest.cc',
- ],
- 'browsing_data_ui_unittest_sources': [
- 'browsing_data_ui/history_notice_utils_unittest.cc'
- ],
- 'bubble_unittest_sources': [
- 'bubble/bubble_manager_mocks.cc',
- 'bubble/bubble_manager_mocks.h',
- 'bubble/bubble_manager_unittest.cc',
- ],
- 'captive_portal_unittest_sources': [
- 'captive_portal/captive_portal_detector_unittest.cc',
- ],
- 'cast_certificate_unittest_sources': [
- 'cast_certificate/cast_cert_validator_test_helpers.cc',
- 'cast_certificate/cast_cert_validator_test_helpers.h',
- 'cast_certificate/cast_cert_validator_unittest.cc',
- ],
- 'certificate_reporting_unittest_sources': [
- 'certificate_reporting/error_report_unittest.cc',
- 'certificate_reporting/error_reporter_unittest.cc',
- ],
- 'certificate_transparency_unittest_sources': [
- 'certificate_transparency/ct_policy_manager_unittest.cc',
- 'certificate_transparency/log_proof_fetcher_unittest.cc',
- 'certificate_transparency/single_tree_tracker_unittest.cc',
- ],
- 'child_trace_message_filter_unittest_sources': [
- 'tracing/child/child_trace_message_filter_unittest.cc',
- ],
- 'client_update_protocol_unittest_sources': [
- 'client_update_protocol/ecdsa_unittest.cc',
- ],
- 'cloud_devices_unittest_sources': [
- 'cloud_devices/common/cloud_devices_urls_unittest.cc',
- 'cloud_devices/common/printer_description_unittest.cc',
- ],
- 'component_updater_unittest_sources': [
- 'component_updater/component_updater_service_unittest.cc',
- 'component_updater/default_component_installer_unittest.cc',
- 'component_updater/timer_unittest.cc',
- ],
- 'content_settings_unittest_sources': [
- 'content_settings/core/browser/content_settings_mock_provider.cc',
- 'content_settings/core/browser/content_settings_mock_provider.h',
- 'content_settings/core/browser/content_settings_registry_unittest.cc',
- 'content_settings/core/browser/content_settings_rule_unittest.cc',
- 'content_settings/core/browser/content_settings_utils_unittest.cc',
- 'content_settings/core/browser/cookie_settings_unittest.cc',
- 'content_settings/core/browser/website_settings_registry_unittest.cc',
- 'content_settings/core/common/content_settings_pattern_parser_unittest.cc',
- 'content_settings/core/common/content_settings_pattern_unittest.cc',
- ],
- 'crash_unittest_sources': [
- 'crash/content/app/crash_keys_win_unittest.cc',
- 'crash/core/common/crash_keys_unittest.cc',
- 'crash/core/common/objc_zombie_unittest.mm',
- ],
- 'crx_file_unittest_sources': [
- 'crx_file/id_util_unittest.cc',
- ],
- 'data_reduction_proxy_unittest_sources': [
- 'data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc',
- 'data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc',
- 'data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_prefs_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc',
- 'data_reduction_proxy/core/browser/data_usage_store_unittest.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_util_unittest.cc',
- ],
- 'data_usage_unittest_sources': [
- 'data_usage/core/data_use_aggregator_unittest.cc',
- ],
- 'device_event_log_unittest_sources': [
- 'device_event_log/device_event_log_impl_unittest.cc',
- ],
- 'devtools_http_handler_unittest_sources': [
- 'devtools_http_handler/devtools_http_handler_unittest.cc',
- ],
- 'display_compositor_unittest_sources': [
- 'display_compositor/buffer_queue_unittest.cc',
- ],
- 'dom_distiller_unittest_sources': [
- 'dom_distiller/content/browser/dom_distiller_viewer_source_unittest.cc',
- 'dom_distiller/content/browser/web_contents_main_frame_observer_unittest.cc',
- 'dom_distiller/core/article_entry_unittest.cc',
- 'dom_distiller/core/distillable_page_detector_unittest.cc',
- 'dom_distiller/core/distilled_content_store_unittest.cc',
- 'dom_distiller/core/distilled_page_prefs_unittests.cc',
- 'dom_distiller/core/distiller_unittest.cc',
- 'dom_distiller/core/distiller_url_fetcher_unittest.cc',
- 'dom_distiller/core/dom_distiller_model_unittest.cc',
- 'dom_distiller/core/dom_distiller_request_view_base_unittest.cc',
- 'dom_distiller/core/dom_distiller_service_unittest.cc',
- 'dom_distiller/core/dom_distiller_store_unittest.cc',
- 'dom_distiller/core/page_features_unittest.cc',
- 'dom_distiller/core/task_tracker_unittest.cc',
- 'dom_distiller/core/url_utils_unittest.cc',
- 'dom_distiller/core/viewer_unittest.cc',
- ],
- 'domain_reliability_unittest_sources': [
- 'domain_reliability/config_unittest.cc',
- 'domain_reliability/context_unittest.cc',
- 'domain_reliability/dispatcher_unittest.cc',
- 'domain_reliability/google_configs_unittest.cc',
- 'domain_reliability/header_unittest.cc',
- 'domain_reliability/monitor_unittest.cc',
- 'domain_reliability/scheduler_unittest.cc',
- 'domain_reliability/test_util.cc',
- 'domain_reliability/test_util.h',
- 'domain_reliability/uploader_unittest.cc',
- 'domain_reliability/util_unittest.cc',
- ],
- 'favicon_base_unittest_sources': [
- 'favicon_base/fallback_icon_url_parser_unittest.cc',
- 'favicon_base/favicon_url_parser_unittest.cc',
- 'favicon_base/large_icon_url_parser_unittest.cc',
- 'favicon_base/select_favicon_frames_unittest.cc',
- ],
- 'favicon_unittest_sources': [
- 'favicon/content/content_favicon_driver_unittest.cc',
- 'favicon/core/fallback_url_util_unittest.cc',
- 'favicon/core/favicon_handler_unittest.cc',
- 'favicon/core/large_icon_service_unittest.cc',
- ],
- 'flags_ui_unittest_sources': [
- 'flags_ui/flags_state_unittest.cc',
- ],
- 'undo_unittest_sources': [
- 'undo/bookmark_undo_service_test.cc',
- 'undo/undo_manager_test.cc',
- ],
-
- 'audio_modem_unittest_sources': [
- 'audio_modem/audio_player_unittest.cc',
- 'audio_modem/audio_recorder_unittest.cc',
- 'audio_modem/modem_unittest.cc',
- ],
- 'copresence_unittest_sources': [
- 'copresence/copresence_state_unittest.cc',
- 'copresence/handlers/audio/audio_directive_handler_unittest.cc',
- 'copresence/handlers/audio/audio_directive_list_unittest.cc',
- 'copresence/handlers/directive_handler_unittest.cc',
- 'copresence/handlers/gcm_handler_unittest.cc',
- 'copresence/rpc/http_post_unittest.cc',
- 'copresence/rpc/rpc_handler_unittest.cc',
- 'copresence/timed_map_unittest.cc',
- ],
- 'data_use_measurement_unittest_sources': [
- 'data_use_measurement/content/data_use_measurement_unittest.cc',
- ],
- 'error_page_unittest_sources': [
- 'error_page/renderer/net_error_helper_core_unittest.cc',
- ],
- 'feedback_unittest_sources': [
- 'feedback/anonymizer_tool_unittest.cc',
- 'feedback/feedback_common_unittest.cc',
- 'feedback/feedback_data_unittest.cc',
- 'feedback/feedback_uploader_chrome_unittest.cc',
- 'feedback/feedback_uploader_unittest.cc',
- ],
- 'gcm_driver_unittest_sources': [
- 'gcm_driver/gcm_account_mapper_unittest.cc',
- 'gcm_driver/gcm_account_tracker_unittest.cc',
- 'gcm_driver/gcm_channel_status_request_unittest.cc',
- 'gcm_driver/gcm_client_impl_unittest.cc',
- 'gcm_driver/gcm_delayed_task_controller_unittest.cc',
- 'gcm_driver/gcm_driver_desktop_unittest.cc',
- 'gcm_driver/gcm_stats_recorder_android_unittest.cc',
- 'gcm_driver/gcm_stats_recorder_impl_unittest.cc',
- ],
- 'gcm_driver_crypto_unittest_sources': [
- 'gcm_driver/crypto/encryption_header_parsers_unittest.cc',
- 'gcm_driver/crypto/gcm_encryption_provider_unittest.cc',
- 'gcm_driver/crypto/gcm_key_store_unittest.cc',
- 'gcm_driver/crypto/gcm_message_cryptographer_unittest.cc',
- 'gcm_driver/crypto/p256_key_util_unittest.cc',
- ],
- 'google_unittest_sources': [
- 'google/core/browser/google_url_tracker_unittest.cc',
- 'google/core/browser/google_util_unittest.cc',
- ],
- 'guest_view_unittest_sources': [
- 'guest_view/browser/guest_view_manager_unittest.cc'
- ],
- 'history_unittest_sources': [
- 'history/content/browser/content_history_backend_db_unittest.cc',
- 'history/core/browser/android/android_history_types_unittest.cc',
- 'history/core/browser/expire_history_backend_unittest.cc',
- 'history/core/browser/history_backend_db_unittest.cc',
- 'history/core/browser/history_backend_unittest.cc',
- 'history/core/browser/history_database_unittest.cc',
- 'history/core/browser/history_querying_unittest.cc',
- 'history/core/browser/history_service_unittest.cc',
- 'history/core/browser/history_types_unittest.cc',
- 'history/core/browser/thumbnail_database_unittest.cc',
- 'history/core/browser/top_sites_cache_unittest.cc',
- 'history/core/browser/top_sites_database_unittest.cc',
- 'history/core/browser/top_sites_impl_unittest.cc',
- 'history/core/browser/typed_url_syncable_service_unittest.cc',
- 'history/core/browser/url_database_unittest.cc',
- 'history/core/browser/url_utils_unittest.cc',
- 'history/core/browser/visit_database_unittest.cc',
- 'history/core/browser/visit_tracker_unittest.cc',
- 'history/core/browser/web_history_service_unittest.cc',
- 'history/core/common/thumbnail_score_unittest.cc',
- ],
- 'image_fetcher_unittest_sources': [
- 'image_fetcher/image_data_fetcher_unittest.cc',
- ],
- 'instance_id_unittest_sources': [
- 'gcm_driver/instance_id/instance_id_driver_unittest.cc',
- ],
- 'invalidation_unittest_sources': [
- 'invalidation/impl/fake_invalidator_unittest.cc',
- 'invalidation/impl/gcm_invalidation_bridge_unittest.cc',
- 'invalidation/impl/gcm_network_channel_unittest.cc',
- 'invalidation/impl/invalidation_logger_unittest.cc',
- 'invalidation/impl/invalidation_notifier_unittest.cc',
- 'invalidation/impl/invalidator_registrar_unittest.cc',
- 'invalidation/impl/invalidator_storage_unittest.cc',
- 'invalidation/impl/non_blocking_invalidator_unittest.cc',
- 'invalidation/impl/object_id_invalidation_map_unittest.cc',
- 'invalidation/impl/p2p_invalidator_unittest.cc',
- 'invalidation/impl/push_client_channel_unittest.cc',
- 'invalidation/impl/registration_manager_unittest.cc',
- 'invalidation/impl/single_object_invalidation_set_unittest.cc',
- 'invalidation/impl/sync_invalidation_listener_unittest.cc',
- 'invalidation/impl/sync_system_resources_unittest.cc',
- 'invalidation/impl/ticl_invalidation_service_unittest.cc',
- 'invalidation/impl/ticl_profile_settings_provider_unittest.cc',
- 'invalidation/impl/unacked_invalidation_set_unittest.cc',
- ],
- 'json_schema_unittest_sources': [
- 'json_schema/json_schema_validator_unittest.cc',
- 'json_schema/json_schema_validator_unittest_base.cc',
- 'json_schema/json_schema_validator_unittest_base.h',
- ],
- 'keyed_service_unittest_sources': [
- 'keyed_service/content/browser_context_dependency_manager_unittest.cc',
- 'keyed_service/core/dependency_graph_unittest.cc',
- ],
- 'language_usage_metrics_unittest_sources': [
- 'language_usage_metrics/language_usage_metrics_unittest.cc',
- ],
- 'leveldb_proto_unittest_sources': [
- 'leveldb_proto/proto_database_impl_unittest.cc',
- ],
- 'link_header_util_unittest_sources': [
- 'link_header_util/link_header_util_unittest.cc',
- ],
- 'login_unittest_sources': [
- 'login/screens/screen_context_unittest.cc',
- ],
- 'memory_coordinator_unittest_sources': [
- 'memory_coordinator/child/child_memory_coordinator_impl_unittest.cc',
- ],
- 'memory_pressure_unittest_sources': [
- 'memory_pressure/direct_memory_pressure_calculator_linux_unittest.cc',
- 'memory_pressure/direct_memory_pressure_calculator_win_unittest.cc',
- 'memory_pressure/filtered_memory_pressure_calculator_unittest.cc',
- 'memory_pressure/memory_pressure_monitor_unittest.cc',
- 'memory_pressure/memory_pressure_stats_collector_unittest.cc',
- 'memory_pressure/test_memory_pressure_calculator.cc',
- 'memory_pressure/test_memory_pressure_calculator.h',
- ],
- 'metrics_unittest_sources': [
- 'metrics/call_stack_profile_metrics_provider_unittest.cc',
- 'metrics/cloned_install_detector_unittest.cc',
- 'metrics/daily_event_unittest.cc',
- 'metrics/data_use_tracker_unittest.cc',
- 'metrics/drive_metrics_provider_unittest.cc',
- 'metrics/file_metrics_provider_unittest.cc',
- 'metrics/histogram_encoder_unittest.cc',
- 'metrics/machine_id_provider_win_unittest.cc',
- 'metrics/metrics_log_manager_unittest.cc',
- 'metrics/metrics_log_unittest.cc',
- 'metrics/metrics_reporting_scheduler_unittest.cc',
- 'metrics/metrics_service_unittest.cc',
- 'metrics/metrics_state_manager_unittest.cc',
- 'metrics/net/net_metrics_log_uploader_unittest.cc',
- 'metrics/persisted_logs_unittest.cc',
- 'metrics/profiler/profiler_metrics_provider_unittest.cc',
- 'metrics/profiler/tracking_synchronizer_unittest.cc',
- 'metrics/stability_metrics_helper_unittest.cc',
- 'metrics/ui/screen_info_metrics_provider_unittest.cc',
- ],
- 'metrics_leak_detector_unittest_sources': [
- 'metrics/leak_detector/call_stack_manager_unittest.cc',
- 'metrics/leak_detector/call_stack_table_unittest.cc',
- 'metrics/leak_detector/leak_analyzer_unittest.cc',
- 'metrics/leak_detector/leak_detector_impl_unittest.cc',
- 'metrics/leak_detector/leak_detector_unittest.cc',
- 'metrics/leak_detector/ranked_set_unittest.cc',
- ],
- 'mime_util_unittest_sources': [
- 'mime_util/mime_util_unittest.cc',
- ],
- 'nacl_unittest_sources': [
- 'nacl/browser/nacl_file_host_unittest.cc',
- 'nacl/browser/nacl_process_host_unittest.cc',
- 'nacl/browser/nacl_validation_cache_unittest.cc',
- 'nacl/browser/pnacl_host_unittest.cc',
- 'nacl/browser/pnacl_translation_cache_unittest.cc',
- 'nacl/browser/test_nacl_browser_delegate.cc',
- 'nacl/zygote/nacl_fork_delegate_linux_unittest.cc',
- ],
- 'navigation_interception_unittest_sources': [
- 'navigation_interception/intercept_navigation_throttle_unittest.cc',
- ],
- 'network_hints_unittest_sources': [
- 'network_hints/renderer/dns_prefetch_queue_unittest.cc',
- 'network_hints/renderer/renderer_dns_prefetch_unittest.cc',
- ],
- 'network_session_configurator_unittest_sources': [
- 'network_session_configurator/network_session_configurator_unittest.cc',
- ],
- 'network_time_unittest_sources': [
- 'network_time/network_time_tracker_unittest.cc',
- ],
- 'ntp_snippets_unittest_sources': [
- 'ntp_snippets/ntp_snippet_unittest.cc',
- 'ntp_snippets/ntp_snippets_database_unittest.cc',
- 'ntp_snippets/ntp_snippets_fetcher_unittest.cc',
- 'ntp_snippets/ntp_snippets_service_unittest.cc',
- 'ntp_snippets/ntp_snippets_status_service_unittest.cc',
- 'ntp_snippets/ntp_snippets_test_utils.cc',
- 'ntp_snippets/ntp_snippets_test_utils.h',
- ],
- 'ntp_tiles_unittest_sources': [
- 'ntp_tiles/most_visited_sites_unittest.cc',
- ],
- 'offline_pages_background_unittest_sources': [
- 'offline_pages/background/request_coordinator_event_logger_unittest.cc',
- 'offline_pages/background/request_coordinator_unittest.cc',
- 'offline_pages/background/request_picker_unittest.cc',
- 'offline_pages/background/request_queue_store_unittest.cc',
- 'offline_pages/background/request_queue_unittest.cc',
- 'offline_pages/background/save_page_request_unittest.cc',
- ],
- 'offline_pages_unittest_sources': [
- 'offline_pages/archive_manager_unittest.cc',
- 'offline_pages/client_policy_controller_unittest.cc',
- 'offline_pages/offline_page_metadata_store_impl_unittest.cc',
- 'offline_pages/offline_page_model_event_logger_unittest.cc',
- 'offline_pages/offline_page_model_impl_unittest.cc',
- 'offline_pages/offline_page_storage_manager_unittest.cc',
- 'offline_pages/snapshot_controller_unittest.cc',
- ],
- 'omnibox_unittest_sources': [
- 'omnibox/browser/answers_cache_unittest.cc',
- 'omnibox/browser/autocomplete_input_unittest.cc',
- 'omnibox/browser/autocomplete_match_unittest.cc',
- 'omnibox/browser/autocomplete_provider_unittest.cc',
- 'omnibox/browser/autocomplete_result_unittest.cc',
- 'omnibox/browser/base_search_provider_unittest.cc',
- 'omnibox/browser/bookmark_provider_unittest.cc',
- 'omnibox/browser/builtin_provider_unittest.cc',
- 'omnibox/browser/clipboard_url_provider_unittest.cc',
- 'omnibox/browser/history_quick_provider_unittest.cc',
- 'omnibox/browser/history_url_provider_unittest.cc',
- 'omnibox/browser/in_memory_url_index_types_unittest.cc',
- 'omnibox/browser/in_memory_url_index_unittest.cc',
- 'omnibox/browser/keyword_provider_unittest.cc',
- 'omnibox/browser/omnibox_edit_unittest.cc',
- 'omnibox/browser/omnibox_field_trial_unittest.cc',
- 'omnibox/browser/omnibox_popup_model_unittest.cc',
- 'omnibox/browser/omnibox_view_unittest.cc',
- 'omnibox/browser/scored_history_match_unittest.cc',
- 'omnibox/browser/shortcuts_backend_unittest.cc',
- 'omnibox/browser/shortcuts_database_unittest.cc',
- 'omnibox/browser/shortcuts_provider_unittest.cc',
- 'omnibox/browser/suggestion_answer_unittest.cc',
- 'omnibox/browser/url_prefix_unittest.cc',
- 'omnibox/browser/zero_suggest_provider_unittest.cc',
- ],
- 'open_from_clipboard_unittest_sources': [
- 'open_from_clipboard/clipboard_recent_content_ios_unittest.mm',
- ],
- 'os_crypt_unittest_sources': [
- 'os_crypt/ie7_password_win_unittest.cc',
- 'os_crypt/keychain_password_mac_unittest.mm',
- 'os_crypt/os_crypt_unittest.cc',
- ],
- 'ownership_unittest_sources': [
- 'ownership/owner_key_util_impl_unittest.cc',
- ],
- 'packed_ct_ev_whitelist_unittest_sources': [
- 'packed_ct_ev_whitelist/bit_stream_reader_unittest.cc',
- 'packed_ct_ev_whitelist/packed_ct_ev_whitelist_unittest.cc',
- ],
- 'page_load_metrics_unittest_sources': [
- 'page_load_metrics/browser/metrics_web_contents_observer_unittest.cc',
- 'page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.cc',
- 'page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.h',
- 'page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc',
- 'page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc',
- ],
- 'password_manager_unittest_sources': [
- 'password_manager/content/browser/content_password_manager_driver_unittest.cc',
- 'password_manager/content/browser/credential_manager_impl_unittest.cc',
- 'password_manager/core/browser/affiliated_match_helper_unittest.cc',
- 'password_manager/core/browser/affiliation_backend_unittest.cc',
- 'password_manager/core/browser/affiliation_database_unittest.cc',
- 'password_manager/core/browser/affiliation_fetch_throttler_unittest.cc',
- 'password_manager/core/browser/affiliation_fetcher_unittest.cc',
- 'password_manager/core/browser/affiliation_service_unittest.cc',
- 'password_manager/core/browser/affiliation_utils_unittest.cc',
- 'password_manager/core/browser/browser_save_password_progress_logger_unittest.cc',
- 'password_manager/core/browser/export/csv_writer_unittest.cc',
- 'password_manager/core/browser/export/password_csv_writer_unittest.cc',
- 'password_manager/core/browser/export/password_exporter_unittest.cc',
- 'password_manager/core/browser/facet_manager_unittest.cc',
- 'password_manager/core/browser/form_saver_impl_unittest.cc',
- 'password_manager/core/browser/import/csv_reader_unittest.cc',
- 'password_manager/core/browser/import/password_csv_reader_unittest.cc',
- 'password_manager/core/browser/import/password_importer_unittest.cc',
- 'password_manager/core/browser/log_manager_unittest.cc',
- 'password_manager/core/browser/log_router_unittest.cc',
- 'password_manager/core/browser/login_database_ios_unittest.cc',
- 'password_manager/core/browser/login_database_unittest.cc',
- 'password_manager/core/browser/login_model_unittest.cc',
- 'password_manager/core/browser/mock_affiliated_match_helper.cc',
- 'password_manager/core/browser/mock_affiliated_match_helper.h',
- 'password_manager/core/browser/password_autofill_manager_unittest.cc',
- 'password_manager/core/browser/password_bubble_experiment_unittest.cc',
- 'password_manager/core/browser/password_form_manager_unittest.cc',
- 'password_manager/core/browser/password_generation_manager_unittest.cc',
- 'password_manager/core/browser/password_manager_settings_migration_experiment_unittest.cc',
- 'password_manager/core/browser/password_manager_unittest.cc',
- 'password_manager/core/browser/password_manager_util_unittest.cc',
- 'password_manager/core/browser/password_store_default_unittest.cc',
- 'password_manager/core/browser/password_store_origin_unittest.h',
- 'password_manager/core/browser/password_store_unittest.cc',
- 'password_manager/core/browser/password_syncable_service_unittest.cc',
- 'password_manager/core/browser/password_ui_utils_unittest.cc',
- 'password_manager/core/browser/psl_matching_helper_unittest.cc',
- 'password_manager/core/browser/statistics_table_unittest.cc',
- 'password_manager/core/common/credential_manager_types_unittest.cc',
- 'password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc',
- 'password_manager/sync/browser/password_sync_util_unittest.cc',
- 'password_manager/sync/browser/sync_credentials_filter_unittest.cc',
- 'password_manager/sync/browser/sync_username_test_base.cc',
- 'password_manager/sync/browser/sync_username_test_base.h',
- ],
- 'policy_unittest_sources': [
- 'policy/core/browser/android/android_combined_policy_provider_unittest.cc',
- 'policy/core/browser/android/policy_converter_unittest.cc',
- 'policy/core/browser/autofill_policy_handler_unittest.cc',
- 'policy/core/browser/browser_policy_connector_unittest.cc',
- 'policy/core/browser/configuration_policy_handler_unittest.cc',
- 'policy/core/browser/configuration_policy_pref_store_unittest.cc',
- 'policy/core/browser/proxy_policy_handler_unittest.cc',
- 'policy/core/browser/url_blacklist_manager_unittest.cc',
- 'policy/core/browser/url_blacklist_policy_handler_unittest.cc',
- 'policy/core/common/async_policy_provider_unittest.cc',
- 'policy/core/common/cloud/cloud_policy_client_unittest.cc',
- 'policy/core/common/cloud/cloud_policy_constants_unittest.cc',
- 'policy/core/common/cloud/cloud_policy_core_unittest.cc',
- 'policy/core/common/cloud/cloud_policy_manager_unittest.cc',
- 'policy/core/common/cloud/cloud_policy_refresh_scheduler_unittest.cc',
- 'policy/core/common/cloud/cloud_policy_service_unittest.cc',
- 'policy/core/common/cloud/cloud_policy_validator_unittest.cc',
- 'policy/core/common/cloud/component_cloud_policy_service_unittest.cc',
- 'policy/core/common/cloud/component_cloud_policy_store_unittest.cc',
- 'policy/core/common/cloud/component_cloud_policy_updater_unittest.cc',
- 'policy/core/common/cloud/device_management_service_unittest.cc',
- 'policy/core/common/cloud/external_policy_data_fetcher_unittest.cc',
- 'policy/core/common/cloud/external_policy_data_updater_unittest.cc',
- 'policy/core/common/cloud/policy_header_io_helper_unittest.cc',
- 'policy/core/common/cloud/policy_header_service_unittest.cc',
- 'policy/core/common/cloud/resource_cache_unittest.cc',
- 'policy/core/common/cloud/user_cloud_policy_manager_unittest.cc',
- 'policy/core/common/cloud/user_cloud_policy_store_unittest.cc',
- 'policy/core/common/cloud/user_info_fetcher_unittest.cc',
- 'policy/core/common/config_dir_policy_loader_unittest.cc',
- 'policy/core/common/generate_policy_source_unittest.cc',
- 'policy/core/common/policy_bundle_unittest.cc',
- 'policy/core/common/policy_loader_ios_unittest.mm',
- 'policy/core/common/policy_loader_mac_unittest.cc',
- 'policy/core/common/policy_loader_win_unittest.cc',
- 'policy/core/common/policy_map_unittest.cc',
- 'policy/core/common/policy_service_impl_unittest.cc',
- 'policy/core/common/policy_statistics_collector_unittest.cc',
- 'policy/core/common/preg_parser_win_unittest.cc',
- 'policy/core/common/registry_dict_win_unittest.cc',
- 'policy/core/common/remote_commands/remote_commands_queue_unittest.cc',
- 'policy/core/common/remote_commands/remote_commands_service_unittest.cc',
- 'policy/core/common/schema_map_unittest.cc',
- 'policy/core/common/schema_registry_tracking_policy_provider_unittest.cc',
- 'policy/core/common/schema_registry_unittest.cc',
- 'policy/core/common/schema_unittest.cc',
- ],
- 'power_unittest_sources': [
- 'power/origin_power_map_unittest.cc',
- ],
- 'precache_unittest_sources': [
- 'precache/content/precache_manager_unittest.cc',
- 'precache/core/fetcher_pool_unittest.cc',
- 'precache/core/precache_database_unittest.cc',
- 'precache/core/precache_fetcher_unittest.cc',
- 'precache/core/precache_session_table_unittest.cc',
- 'precache/core/precache_url_table_unittest.cc',
- ],
- 'user_prefs_unittest_sources': [
- 'user_prefs/tracked/device_id_unittest.cc',
- 'user_prefs/tracked/pref_hash_calculator_unittest.cc',
- 'user_prefs/tracked/pref_hash_filter_unittest.cc',
- 'user_prefs/tracked/pref_hash_store_impl_unittest.cc',
- 'user_prefs/tracked/pref_service_hash_store_contents_unittest.cc',
- 'user_prefs/tracked/segregated_pref_store_unittest.cc',
- 'user_prefs/tracked/tracked_preferences_migration_unittest.cc',
- ],
- 'proximity_auth_unittest_sources': [
- 'proximity_auth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc',
- 'proximity_auth/ble/bluetooth_low_energy_connection_finder_unittest.cc',
- 'proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc',
- 'proximity_auth/ble/bluetooth_low_energy_device_whitelist_unittest.cc',
- 'proximity_auth/ble/bluetooth_low_energy_weave_packet_generator_unittest.cc',
- 'proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver_unittest.cc',
- 'proximity_auth/bluetooth_connection_finder_unittest.cc',
- 'proximity_auth/bluetooth_connection_unittest.cc',
- 'proximity_auth/bluetooth_throttler_impl_unittest.cc',
- 'proximity_auth/connection_unittest.cc',
- 'proximity_auth/cryptauth/cryptauth_access_token_fetcher_impl_unittest.cc',
- 'proximity_auth/cryptauth/cryptauth_api_call_flow_unittest.cc',
- 'proximity_auth/cryptauth/cryptauth_client_impl_unittest.cc',
- 'proximity_auth/cryptauth/cryptauth_device_manager_unittest.cc',
- 'proximity_auth/cryptauth/cryptauth_enroller_impl_unittest.cc',
- 'proximity_auth/cryptauth/cryptauth_enrollment_manager_unittest.cc',
- 'proximity_auth/cryptauth/cryptauth_gcm_manager_impl_unittest.cc',
- 'proximity_auth/cryptauth/fake_secure_message_delegate_unittest.cc',
- 'proximity_auth/cryptauth/sync_scheduler_impl_unittest.cc',
- 'proximity_auth/device_to_device_authenticator_unittest.cc',
- 'proximity_auth/device_to_device_operations_unittest.cc',
- 'proximity_auth/device_to_device_operations_unittest.cc',
- 'proximity_auth/device_to_device_secure_context_unittest.cc',
- 'proximity_auth/logging/logging_unittest.cc',
- 'proximity_auth/messenger_impl_unittest.cc',
- 'proximity_auth/proximity_auth_pref_manager_unittest.cc',
- 'proximity_auth/proximity_auth_system_unittest.cc',
- 'proximity_auth/proximity_monitor_impl_unittest.cc',
- 'proximity_auth/remote_device_life_cycle_impl_unittest.cc',
- 'proximity_auth/remote_device_loader_unittest.cc',
- 'proximity_auth/remote_status_update_unittest.cc',
- 'proximity_auth/throttled_bluetooth_connection_finder_unittest.cc',
- 'proximity_auth/unlock_manager_unittest.cc',
- 'proximity_auth/wire_message_unittest.cc',
- ],
- 'proxy_config_unittest_sources': [
- 'proxy_config/pref_proxy_config_tracker_impl_unittest.cc',
- 'proxy_config/proxy_config_dictionary_unittest.cc',
- 'proxy_config/proxy_prefs_unittest.cc',
- ],
- 'prefs_unittest_sources': [
- 'prefs/default_pref_store_unittest.cc',
- 'prefs/in_memory_pref_store_unittest.cc',
- 'prefs/json_pref_store_unittest.cc',
- 'prefs/overlay_user_pref_store_unittest.cc',
- 'prefs/pref_change_registrar_unittest.cc',
- 'prefs/pref_member_unittest.cc',
- 'prefs/pref_notifier_impl_unittest.cc',
- 'prefs/pref_service_unittest.cc',
- 'prefs/pref_value_map_unittest.cc',
- 'prefs/pref_value_store_unittest.cc',
- 'prefs/scoped_user_pref_update_unittest.cc',
- ],
- 'query_parser_unittest_sources': [
- 'query_parser/query_parser_unittest.cc',
- 'query_parser/snippet_unittest.cc',
- ],
- 'rappor_unittest_sources': [
- 'rappor/bloom_filter_unittest.cc',
- 'rappor/byte_vector_utils_unittest.cc',
- 'rappor/log_uploader_unittest.cc',
- 'rappor/rappor_metric_unittest.cc',
- 'rappor/rappor_prefs_unittest.cc',
- 'rappor/rappor_service_unittest.cc',
- 'rappor/rappor_utils_unittest.cc',
- 'rappor/reports_unittest.cc',
- 'rappor/sampler_unittest.cc',
- ],
- 'rlz_unittest_sources': [
- 'rlz/rlz_tracker_unittest.cc',
- ],
- 'safe_browsing_db_mobile_unittest_sources': [
- 'safe_browsing_db/remote_database_manager_unittest.cc',
- 'safe_browsing_db/safe_browsing_api_handler_unittest.cc',
- ],
- 'safe_browsing_db_unittest_sources': [
- 'safe_browsing_db/database_manager_unittest.cc',
- 'safe_browsing_db/prefix_set_unittest.cc',
- 'safe_browsing_db/testing_util.h',
- 'safe_browsing_db/util_unittest.cc',
- 'safe_browsing_db/v4_database_unittest.cc',
- 'safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc',
- 'safe_browsing_db/v4_protocol_manager_util_unittest.cc',
- 'safe_browsing_db/v4_store_unittest.cc',
- 'safe_browsing_db/v4_update_protocol_manager_unittest.cc',
- ],
- 'safe_json_unittest_sources': [
- 'safe_json/json_sanitizer_unittest.cc',
- 'safe_json/testing_json_parser_unittest.cc',
- ],
- 'scheduler_unittest_sources': [
- 'scheduler/base/task_queue_manager_delegate_for_test.cc',
- 'scheduler/base/task_queue_manager_delegate_for_test.h',
- 'scheduler/base/task_queue_manager_unittest.cc',
- 'scheduler/base/task_queue_selector_unittest.cc',
- 'scheduler/base/test_always_fail_time_source.cc',
- 'scheduler/base/test_always_fail_time_source.h',
- 'scheduler/base/test_time_source.cc',
- 'scheduler/base/test_time_source.h',
- 'scheduler/base/time_domain_unittest.cc',
- 'scheduler/base/work_queue_sets_unittest.cc',
- 'scheduler/child/idle_helper_unittest.cc',
- 'scheduler/child/scheduler_helper_unittest.cc',
- 'scheduler/child/scheduler_tqm_delegate_for_test.cc',
- 'scheduler/child/scheduler_tqm_delegate_for_test.h',
- 'scheduler/child/scheduler_tqm_delegate_impl_unittest.cc',
- 'scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc',
- 'scheduler/child/worker_scheduler_impl_unittest.cc',
- 'scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc',
- 'scheduler/renderer/deadline_task_runner_unittest.cc',
- 'scheduler/renderer/idle_time_estimator_unittest.cc',
- 'scheduler/renderer/render_widget_signals_unittest.cpp',
- 'scheduler/renderer/renderer_scheduler_impl_unittest.cc',
- 'scheduler/renderer/task_cost_estimator_unittest.cc',
- 'scheduler/renderer/throttling_helper_unittest.cc',
- 'scheduler/renderer/user_model_unittest.cc',
- 'scheduler/renderer/web_view_scheduler_impl_unittest.cc',
- 'scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc',
- ],
- 'search_unittest_sources': [
- 'search/search_android_unittest.cc',
- 'search/search_unittest.cc',
- ],
- 'search_engines_unittest_sources': [
- 'search_engines/default_search_manager_unittest.cc',
- 'search_engines/default_search_policy_handler_unittest.cc',
- 'search_engines/default_search_pref_migration_unittest.cc',
- 'search_engines/keyword_table_unittest.cc',
- 'search_engines/search_engine_data_type_controller_unittest.cc',
- 'search_engines/search_host_to_urls_map_unittest.cc',
- 'search_engines/template_url_prepopulate_data_unittest.cc',
- 'search_engines/template_url_service_util_unittest.cc',
- 'search_engines/template_url_unittest.cc',
- ],
- 'search_provider_logos_unittest_sources': [
- 'search_provider_logos/logo_cache_unittest.cc',
- 'search_provider_logos/logo_tracker_unittest.cc',
- ],
- 'security_state_unittest_sources': [
- 'security_state/security_state_model_unittest.cc',
- ],
- 'sessions_unittest_sources': [
- 'sessions/content/content_serialized_navigation_builder_unittest.cc',
- 'sessions/content/content_serialized_navigation_driver_unittest.cc',
- 'sessions/core/serialized_navigation_entry_unittest.cc',
- 'sessions/core/session_backend_unittest.cc',
- 'sessions/core/session_types_unittest.cc',
- 'sessions/ios/ios_serialized_navigation_builder_unittest.mm',
- 'sessions/ios/ios_serialized_navigation_driver_unittest.cc',
- ],
- 'signin_unittest_sources': [
- 'signin/core/browser/account_info_unittest.cc',
- 'signin/core/browser/account_investigator_unittest.cc',
- 'signin/core/browser/account_tracker_service_unittest.cc',
- 'signin/core/browser/gaia_cookie_manager_service_unittest.cc',
- 'signin/core/browser/refresh_token_annotation_request_unittest.cc',
- 'signin/core/browser/signin_error_controller_unittest.cc',
- 'signin/core/browser/signin_investigator_unittest.cc',
- 'signin/core/browser/signin_status_metrics_provider_unittest.cc',
- 'signin/core/browser/webdata/token_service_table_unittest.cc',
- 'signin/ios/browser/account_consistency_service_unittest.mm',
- 'signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm',
- ],
- 'ssl_config_unittest_sources': [
- 'ssl_config/ssl_config_service_manager_pref_unittest.cc',
- ],
- 'ssl_errors_unittest_sources': [
- 'ssl_errors/error_classification_unittest.cc'
- ],
- 'storage_monitor_unittest_sources': [
- 'storage_monitor/image_capture_device_manager_unittest.mm',
- 'storage_monitor/media_storage_util_unittest.cc',
- 'storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc',
- 'storage_monitor/storage_info_unittest.cc',
- 'storage_monitor/storage_monitor_chromeos_unittest.cc',
- 'storage_monitor/storage_monitor_linux_unittest.cc',
- 'storage_monitor/storage_monitor_mac_unittest.mm',
- 'storage_monitor/storage_monitor_unittest.cc',
- 'storage_monitor/storage_monitor_win_unittest.cc',
- ],
- 'subresource_filter_content_browser_unittest_sources': [
- 'subresource_filter/content/browser/content_ruleset_distributor_unittest.cc',
- 'subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc',
- ],
- 'subresource_filter_core_browser_unittest_sources': [
- 'subresource_filter/core/browser/ruleset_service_unittest.cc',
- 'subresource_filter/core/browser/subresource_filter_features_unittest.cc',
- ],
- 'subresource_filter_core_common_unittest_sources': [
- 'subresource_filter/core/common/closed_hash_map_unittest.cc',
- 'subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc',
- 'subresource_filter/core/common/knuth_morris_pratt_unittest.cc',
- 'subresource_filter/core/common/ngram_extractor_unittest.cc',
- 'subresource_filter/core/common/string_splitter_unittest.cc',
- ],
- 'suggestions_unittest_sources': [
- 'suggestions/blacklist_store_unittest.cc',
- 'suggestions/image_manager_unittest.cc',
- 'suggestions/suggestions_service_unittest.cc',
- 'suggestions/suggestions_store_unittest.cc',
- ],
- 'supervised_user_error_page_unittest_sources': [
- 'supervised_user_error_page/supervised_user_error_page_unittest.cc',
- ],
- 'sync_bookmarks_unittest_sources': [
- 'sync_bookmarks/bookmark_data_type_controller_unittest.cc',
- ],
- 'sync_driver_unittest_sources': [
- 'sync_driver/about_sync_util_unittest.cc',
- 'sync_driver/backend_migrator_unittest.cc',
- 'sync_driver/data_type_manager_impl_unittest.cc',
- 'sync_driver/device_count_metrics_provider_unittest.cc',
- 'sync_driver/device_info_data_type_controller_unittest.cc',
- 'sync_driver/device_info_service_unittest.cc',
- 'sync_driver/device_info_sync_service_unittest.cc',
- 'sync_driver/device_info_util_unittest.cc',
- 'sync_driver/frontend_data_type_controller_unittest.cc',
- 'sync_driver/generic_change_processor_unittest.cc',
- 'sync_driver/glue/browser_thread_model_worker_unittest.cc',
- 'sync_driver/glue/sync_backend_host_impl_unittest.cc',
- 'sync_driver/glue/sync_backend_registrar_unittest.cc',
- 'sync_driver/glue/ui_model_worker_unittest.cc',
- 'sync_driver/local_device_info_provider_unittest.cc',
- 'sync_driver/model_association_manager_unittest.cc',
- 'sync_driver/non_blocking_data_type_controller_unittest.cc',
- 'sync_driver/non_ui_data_type_controller_unittest.cc',
- 'sync_driver/non_ui_model_type_controller_unittest.cc',
- 'sync_driver/profile_sync_auth_provider_unittest.cc',
- 'sync_driver/shared_change_processor_unittest.cc',
- 'sync_driver/startup_controller_unittest.cc',
- 'sync_driver/sync_prefs_unittest.cc',
- 'sync_driver/sync_stopped_reporter_unittest.cc',
- 'sync_driver/sync_util_unittest.cc',
- 'sync_driver/system_encryptor_unittest.cc',
- 'sync_driver/ui_data_type_controller_unittest.cc',
- 'sync_driver/ui_model_type_controller_unittest.cc',
- ],
- 'sync_sessions_unittest_sources': [
- 'sync_sessions/favicon_cache_unittest.cc',
- 'sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc',
- 'sync_sessions/revisit/current_tab_matcher_unittest.cc',
- 'sync_sessions/revisit/offset_tab_matcher_unittest.cc',
- 'sync_sessions/revisit/page_revisit_broadcaster_unittest.cc',
- 'sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc',
- 'sync_sessions/revisit/typed_url_page_revisit_task_unittest.cc',
- 'sync_sessions/session_data_type_controller_unittest.cc',
- 'sync_sessions/sync_sessions_metrics_unittest.cc',
- 'sync_sessions/synced_session_tracker_unittest.cc',
- 'sync_sessions/tab_node_pool_unittest.cc',
- ],
- 'syncable_prefs_unittest_sources': [
- 'syncable_prefs/pref_model_associator_unittest.cc',
- 'syncable_prefs/pref_service_syncable_unittest.cc',
- ],
- 'tracing_unittest_sources': [
- 'tracing/browser/trace_config_file_unittest.cc',
- 'tracing/common/graphics_memory_dump_provider_android_unittest.cc',
- 'tracing/common/process_metrics_memory_dump_provider_unittest.cc',
- 'tracing/core/trace_ring_buffer_unittest.cc',
- 'tracing/core/scattered_stream_writer_unittest.cc',
- ],
- 'translate_unittest_sources': [
- 'translate/core/browser/language_state_unittest.cc',
- 'translate/core/browser/mock_translate_driver.cc',
- 'translate/core/browser/translate_browser_metrics_unittest.cc',
- 'translate/core/browser/translate_language_list_unittest.cc',
- 'translate/core/browser/translate_manager_unittest.cc',
- 'translate/core/browser/translate_prefs_unittest.cc',
- 'translate/core/browser/translate_script_unittest.cc',
- 'translate/core/browser/translate_ui_delegate_unittest.cc',
- 'translate/core/common/translate_metrics_unittest.cc',
- 'translate/core/common/translate_util_unittest.cc',
- 'translate/core/language_detection/language_detection_util_unittest.cc',
- 'translate/ios/browser/js_translate_manager_unittest.mm',
- 'translate/ios/browser/language_detection_controller_unittest.mm',
- 'translate/ios/browser/translate_controller_unittest.mm',
- ],
- 'zoom_unittest_sources': [
- 'zoom/page_zoom_unittests.cc',
- ],
- 'update_client_unittest_sources': [
- 'update_client/component_patcher_unittest.cc',
- 'update_client/crx_downloader_unittest.cc',
- 'update_client/persisted_data_unittest.cc',
- 'update_client/ping_manager_unittest.cc',
- 'update_client/request_sender_unittest.cc',
- 'update_client/update_checker_unittest.cc',
- 'update_client/update_client_unittest.cc',
- 'update_client/update_query_params_unittest.cc',
- 'update_client/update_response_unittest.cc',
- 'update_client/utils_unittest.cc',
- ],
- 'upload_list_unittest_sources': [
- 'upload_list/upload_list_unittest.cc',
- ],
- 'url_formatter_unittest_sources': [
- 'url_formatter/elide_url_unittest.cc',
- 'url_formatter/url_fixer_unittest.cc',
- 'url_formatter/url_formatter_unittest.cc',
- ],
- 'url_matcher_unittest_sources': [
- 'url_matcher/regex_set_matcher_unittest.cc',
- 'url_matcher/string_pattern_unittest.cc',
- 'url_matcher/substring_set_matcher_unittest.cc',
- 'url_matcher/url_matcher_factory_unittest.cc',
- 'url_matcher/url_matcher_unittest.cc',
- ],
- 'user_manager_unittest_sources': [
- 'user_manager/user_unittest.cc',
- ],
- 'variations_unittest_sources': [
- 'variations/active_field_trials_unittest.cc',
- 'variations/caching_permuted_entropy_provider_unittest.cc',
- 'variations/entropy_provider_unittest.cc',
- 'variations/experiment_labels_unittest.cc',
- 'variations/metrics_util_unittest.cc',
- 'variations/net/variations_http_headers_unittest.cc',
- 'variations/service/ui_string_overrider_unittest.cc',
- 'variations/service/variations_service_unittest.cc',
- 'variations/study_filtering_unittest.cc',
- 'variations/variations_associated_data_unittest.cc',
- 'variations/variations_http_header_provider_unittest.cc',
- 'variations/variations_request_scheduler_mobile_unittest.cc',
- 'variations/variations_request_scheduler_unittest.cc',
- 'variations/variations_seed_processor_unittest.cc',
- 'variations/variations_seed_simulator_unittest.cc',
- 'variations/variations_seed_store_unittest.cc',
- ],
- 'visitedlink_unittest_sources': [
- 'visitedlink/test/visitedlink_unittest.cc',
- ],
- 'wallpaper_unittest_sources': [
- 'wallpaper/wallpaper_resizer_unittest.cc',
- ],
- 'web_cache_unittest_sources': [
- 'web_cache/browser/web_cache_manager_unittest.cc',
- ],
- 'web_modal_unittest_sources': [
- 'web_modal/web_contents_modal_dialog_manager_unittest.cc',
- ],
- 'web_resource_unittest_sources': [
- 'web_resource/eula_accepted_notifier_unittest.cc',
- 'web_resource/resource_request_allowed_notifier_unittest.cc',
- ],
- 'web_restrictions_unittest_sources' : [
- 'web_restrictions/browser/web_restrictions_client_unittest.cc',
- 'web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc',
- ],
- 'webcrypto_unittest_sources': [
- 'webcrypto/algorithms/aes_cbc_unittest.cc',
- 'webcrypto/algorithms/aes_ctr_unittest.cc',
- 'webcrypto/algorithms/aes_gcm_unittest.cc',
- 'webcrypto/algorithms/aes_kw_unittest.cc',
- 'webcrypto/algorithms/ecdh_unittest.cc',
- 'webcrypto/algorithms/ecdsa_unittest.cc',
- 'webcrypto/algorithms/hmac_unittest.cc',
- 'webcrypto/algorithms/rsa_oaep_unittest.cc',
- 'webcrypto/algorithms/rsa_pss_unittest.cc',
- 'webcrypto/algorithms/rsa_ssa_unittest.cc',
- 'webcrypto/algorithms/sha_unittest.cc',
- 'webcrypto/algorithms/test_helpers.cc',
- 'webcrypto/algorithms/test_helpers.h',
- 'webcrypto/status_unittest.cc',
- ],
- 'webdata_unittest_sources': [
- 'webdata/common/web_database_migration_unittest.cc',
- ],
- 'webusb_detector_unittest_sources': [
- 'webusb/webusb_detector_unittest.cc',
- ],
- },
- 'targets': [
- {
- # GN version: //components:components_tests_pak
- 'target_name': 'components_tests_pak',
- 'type': 'none',
- 'dependencies': [
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- ],
- 'actions': [
- {
- 'action_name': 'repack_components_tests_pak',
- 'variables': {
- 'pak_inputs': [
- '<(SHARED_INTERMEDIATE_DIR)/components/components_resources.pak',
- '<(SHARED_INTERMEDIATE_DIR)/components/strings/components_strings_en-US.pak',
- ],
- 'pak_output': '<(PRODUCT_DIR)/components_tests_resources.pak',
- },
- 'includes': [ '../build/repack_action.gypi' ],
- },
- ],
- 'direct_dependent_settings': {
- 'mac_bundle_resources': [
- '<(PRODUCT_DIR)/components_tests_resources.pak',
- ],
- },
- },
- {
- # GN version: //components:components_unittests
- 'target_name': 'components_unittests',
- 'type': '<(gtest_target_type)',
- 'sources': [
- 'test/run_all_unittests.cc',
-
- '<@(auto_login_parser_unittest_sources)',
- '<@(autofill_unittest_sources)',
- '<@(base32_unittest_sources)',
- '<@(bookmarks_unittest_sources)',
- '<@(browser_sync_unittest_sources)',
- '<@(browser_watcher_unittest_sources)',
- '<@(browsing_data_ui_unittest_sources)',
- '<@(bubble_unittest_sources)',
- '<@(captive_portal_unittest_sources)',
- '<@(cast_certificate_unittest_sources)',
- '<@(certificate_reporting_unittest_sources)',
- '<@(client_update_protocol_unittest_sources)',
- '<@(cloud_devices_unittest_sources)',
- '<@(component_updater_unittest_sources)',
- '<@(content_settings_unittest_sources)',
- '<@(crash_unittest_sources)',
- '<@(crx_file_unittest_sources)',
- '<@(data_reduction_proxy_unittest_sources)',
- '<@(data_usage_unittest_sources)',
- '<@(data_use_measurement_unittest_sources)',
- '<@(device_event_log_unittest_sources)',
- '<@(dom_distiller_unittest_sources)',
- '<@(favicon_base_unittest_sources)',
- '<@(favicon_unittest_sources)',
- '<@(flags_ui_unittest_sources)',
- '<@(gcm_driver_crypto_unittest_sources)',
- '<@(gcm_driver_unittest_sources)',
- '<@(google_unittest_sources)',
- '<@(history_unittest_sources)',
- '<@(image_fetcher_unittest_sources)',
- '<@(instance_id_unittest_sources)',
- '<@(json_schema_unittest_sources)',
- '<@(keyed_service_unittest_sources)',
- '<@(language_usage_metrics_unittest_sources)',
- '<@(leveldb_proto_unittest_sources)',
- '<@(link_header_util_unittest_sources)',
- '<@(login_unittest_sources)',
- '<@(memory_pressure_unittest_sources)',
- '<@(metrics_unittest_sources)',
- '<@(mime_util_unittest_sources)',
- '<@(network_session_configurator_unittest_sources)',
- '<@(network_time_unittest_sources)',
- '<@(ntp_snippets_unittest_sources)',
- '<@(offline_pages_background_unittest_sources)',
- '<@(offline_pages_unittest_sources)',
- '<@(omnibox_unittest_sources)',
- '<@(open_from_clipboard_unittest_sources)',
- '<@(os_crypt_unittest_sources)',
- '<@(password_manager_unittest_sources)',
- '<@(precache_unittest_sources)',
- '<@(proxy_config_unittest_sources)',
- '<@(prefs_unittest_sources)',
- '<@(query_parser_unittest_sources)',
- '<@(rappor_unittest_sources)',
- '<@(search_engines_unittest_sources)',
- '<@(search_provider_logos_unittest_sources)',
- '<@(search_unittest_sources)',
- '<@(security_state_unittest_sources)',
- '<@(sessions_unittest_sources)',
- '<@(signin_unittest_sources)',
- '<@(ssl_config_unittest_sources)',
- '<@(ssl_errors_unittest_sources)',
- '<@(subresource_filter_core_browser_unittest_sources)',
- '<@(subresource_filter_core_common_unittest_sources)',
- '<@(suggestions_unittest_sources)',
- '<@(supervised_user_error_page_unittest_sources)',
- '<@(sync_bookmarks_unittest_sources)',
- '<@(sync_driver_unittest_sources)',
- '<@(sync_sessions_unittest_sources)',
- '<@(syncable_prefs_unittest_sources)',
- '<@(translate_unittest_sources)',
- '<@(undo_unittest_sources)',
- '<@(update_client_unittest_sources)',
- '<@(upload_list_unittest_sources)',
- '<@(url_formatter_unittest_sources)',
- '<@(url_matcher_unittest_sources)',
- '<@(user_prefs_unittest_sources)',
- '<@(variations_unittest_sources)',
- '<@(web_resource_unittest_sources)',
- '<@(webdata_unittest_sources)',
- 'net_log/net_log_temp_file_unittest.cc',
- ],
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../google_apis/google_apis.gyp:google_apis_test_support',
- '../jingle/jingle.gyp:notifier_test_util',
- '../net/net.gyp:net_test_support',
- '../sql/sql.gyp:test_support_sql',
- '../sync/sync.gyp:sync',
- '../sync/sync.gyp:test_support_sync_api',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- '../third_party/icu/icu.gyp:icui18n',
- '../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
- '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_util',
- '../third_party/libjingle/libjingle.gyp:libjingle',
- '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- '../third_party/re2/re2.gyp:re2',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/gfx.gyp:gfx_test_support',
- '../ui/resources/ui_resources.gyp:ui_resources',
- '../ui/resources/ui_resources.gyp:ui_test_pak',
- '../ui/strings/ui_strings.gyp:ui_strings',
- '../url/url.gyp:url_lib',
- 'components.gyp:auto_login_parser',
- 'components.gyp:autofill_core_browser',
- 'components.gyp:autofill_core_common',
- 'components.gyp:autofill_core_test_support',
- 'components.gyp:base32',
- 'components.gyp:bookmarks_browser',
- 'components.gyp:bookmarks_managed',
- 'components.gyp:bookmarks_test_support',
- 'components.gyp:browser_sync_browser',
- 'components.gyp:browser_sync_browser_test_support',
- 'components.gyp:browsing_data_ui',
- 'components.gyp:bubble',
- 'components.gyp:captive_portal_test_support',
- 'components.gyp:cast_certificate',
- 'components.gyp:certificate_reporting',
- 'components.gyp:cloud_devices_common',
- 'components.gyp:component_updater',
- 'components.gyp:component_updater_test_support',
- 'components.gyp:content_settings_core_browser',
- 'components.gyp:content_settings_core_common',
- 'components.gyp:content_settings_core_test_support',
- 'components.gyp:crash_core_common',
- 'components.gyp:crx_file',
- 'components.gyp:data_reduction_proxy_core_browser',
- 'components.gyp:data_reduction_proxy_core_common',
- 'components.gyp:data_reduction_proxy_test_support',
- 'components.gyp:data_usage_core',
- 'components.gyp:data_use_measurement_core',
- 'components.gyp:device_event_log_component',
- 'components.gyp:dom_distiller_core',
- 'components.gyp:dom_distiller_protos',
- 'components.gyp:dom_distiller_test_support',
- 'components.gyp:favicon_base',
- 'components.gyp:favicon_core',
- 'components.gyp:flags_ui',
- 'components.gyp:gcm_driver',
- 'components.gyp:gcm_driver_test_support',
- 'components.gyp:google_core_browser',
- 'components.gyp:history_core_browser',
- 'components.gyp:history_core_common',
- 'components.gyp:history_core_test_support',
- 'components.gyp:image_fetcher',
- 'components.gyp:instance_id_test_support',
- 'components.gyp:invalidation_impl',
- 'components.gyp:invalidation_test_support',
- 'components.gyp:json_schema',
- 'components.gyp:keyed_service_core',
- 'components.gyp:language_usage_metrics',
- 'components.gyp:leveldb_proto',
- 'components.gyp:leveldb_proto_test_support',
- 'components.gyp:login',
- 'components.gyp:memory_pressure',
- 'components.gyp:metrics',
- 'components.gyp:metrics_net',
- 'components.gyp:metrics_profiler',
- 'components.gyp:metrics_test_support',
- 'components.gyp:metrics_ui',
- 'components.gyp:net_log',
- 'components.gyp:network_session_configurator',
- 'components.gyp:network_time',
- 'components.gyp:ntp_snippets',
- 'components.gyp:offline_pages',
- 'components.gyp:offline_pages_background_offliner',
- 'components.gyp:offline_pages_test_support',
- 'components.gyp:omnibox_browser',
- 'components.gyp:omnibox_test_support',
- 'components.gyp:open_from_clipboard',
- 'components.gyp:open_from_clipboard_test_support',
- 'components.gyp:os_crypt',
- 'components.gyp:os_crypt_test_support',
- 'components.gyp:password_manager_core_browser',
- 'components.gyp:password_manager_core_browser_test_support',
- 'components.gyp:password_manager_sync_browser',
- 'components.gyp:precache_core',
- 'components.gyp:pref_registry_test_support',
- 'components.gyp:proxy_config',
- 'components.gyp:query_parser',
- 'components.gyp:rappor',
- 'components.gyp:rappor_test_support',
- 'components.gyp:search',
- 'components.gyp:search_engines',
- 'components.gyp:search_engines_test_support',
- 'components.gyp:search_provider_logos',
- 'components.gyp:security_state',
- 'components.gyp:sessions_test_support',
- 'components.gyp:signin_core_browser',
- 'components.gyp:signin_core_browser_test_support',
- 'components.gyp:ssl_config',
- 'components.gyp:ssl_errors',
- 'components.gyp:subresource_filter_core_browser_test_support',
- 'components.gyp:subresource_filter_core_browser',
- 'components.gyp:subresource_filter_core_common',
- 'components.gyp:suggestions',
- 'components.gyp:supervised_user_error_page',
- 'components.gyp:sync_bookmarks',
- 'components.gyp:sync_driver',
- 'components.gyp:sync_driver_test_support',
- 'components.gyp:sync_sessions',
- 'components.gyp:sync_sessions_test_support',
- 'components.gyp:syncable_prefs_test_support',
- 'components.gyp:toolbar_test_support',
- 'components.gyp:translate_core_browser',
- 'components.gyp:translate_core_common',
- 'components.gyp:translate_core_language_detection',
- 'components.gyp:undo_component',
- 'components.gyp:update_client',
- 'components.gyp:update_client_test_support',
- 'components.gyp:upload_list',
- 'components.gyp:url_matcher',
- 'components.gyp:user_prefs_tracked',
- 'components.gyp:user_prefs_tracked_test_support',
- 'components.gyp:variations',
- 'components.gyp:variations_net',
- 'components.gyp:variations_service',
- 'components.gyp:version_info',
- 'components.gyp:webdata_services_test_support',
- 'components.gyp:web_resource',
- 'components.gyp:web_resource_test_support',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- 'components_tests_pak',
- 'link_header_util/link_header_util.gyp:link_header_util',
- 'mime_util/mime_util.gyp:mime_util',
- 'prefs/prefs.gyp:prefs',
- 'prefs/prefs.gyp:prefs_test_support',
- 'url_formatter/url_formatter.gyp:url_formatter',
- ],
- 'conditions': [
- ['OS!="mac" and OS!="ios"', {
- 'sources!': [
- 'crash/core/common/objc_zombie_unittest.mm',
- ],
- }],
- ['enable_rlz_support==1', {
- 'sources': [
- '<@(rlz_unittest_sources)',
- ],
- 'dependencies': [
- '../net/net.gyp:net_test_support',
- '../rlz/rlz.gyp:test_support_rlz',
- 'components.gyp:rlz',
- ],
- 'conditions': [
- ['OS == "ios"', {
- 'dependencies': [
- '../ui/base/ui_base.gyp:ui_base',
- ],
- }],
- ],
- }],
- ['toolkit_views == 1', {
- 'sources': [
- 'bookmarks/browser/bookmark_node_data_unittest.cc',
- 'constrained_window/constrained_window_views_unittest.cc',
- ],
- 'dependencies': [
- '<(DEPTH)/ui/views/views.gyp:views',
- '<(DEPTH)/ui/views/views.gyp:views_test_support',
- 'components.gyp:constrained_window',
- ]
- }],
- ['OS=="win"', {
- 'dependencies': [
- 'components.gyp:browser_watcher',
- 'components.gyp:browser_watcher_client',
- ]
- }],
- ['OS != "ios"', {
- 'sources': [
- '<@(certificate_transparency_unittest_sources)',
- '<@(child_trace_message_filter_unittest_sources)',
- '<@(devtools_http_handler_unittest_sources)',
- '<@(display_compositor_unittest_sources)',
- '<@(domain_reliability_unittest_sources)',
- '<@(error_page_unittest_sources)',
- '<@(guest_view_unittest_sources)',
- '<@(memory_coordinator_unittest_sources)',
- '<@(navigation_interception_unittest_sources)',
- '<@(network_hints_unittest_sources)',
- '<@(ntp_tiles_unittest_sources)',
- '<@(packed_ct_ev_whitelist_unittest_sources)',
- '<@(page_load_metrics_unittest_sources)',
- '<@(power_unittest_sources)',
- '<@(safe_browsing_db_unittest_sources)',
- '<@(safe_json_unittest_sources)',
- '<@(scheduler_unittest_sources)',
- '<@(storage_monitor_unittest_sources)',
- '<@(subresource_filter_content_browser_unittest_sources)',
- '<@(tracing_unittest_sources)',
- '<@(visitedlink_unittest_sources)',
- '<@(wallpaper_unittest_sources)',
- '<@(web_cache_unittest_sources)',
- '<@(webcrypto_unittest_sources)',
- '<@(web_modal_unittest_sources)',
- '<@(zoom_unittest_sources)',
- ],
- 'dependencies': [
- '../content/content_shell_and_tests.gyp:test_support_content',
- '../skia/skia.gyp:skia',
- 'components.gyp:autofill_content_browser',
- 'components.gyp:autofill_content_renderer',
- 'components.gyp:autofill_content_test_support',
- 'components.gyp:autofill_content_test_types_mojo_bindings',
- 'components.gyp:certificate_transparency',
- 'components.gyp:crash_test_support',
- 'components.gyp:data_reduction_proxy_content_browser',
- 'components.gyp:data_use_measurement_content',
- 'components.gyp:devtools_http_handler',
- 'components.gyp:display_compositor',
- 'components.gyp:dom_distiller_content_browser',
- 'components.gyp:dom_distiller_content_renderer',
- 'components.gyp:domain_reliability',
- 'components.gyp:error_page_renderer',
- 'components.gyp:favicon_content',
- 'components.gyp:guest_view_browser',
- 'components.gyp:guest_view_common',
- 'components.gyp:guest_view_test_support',
- 'components.gyp:history_content_browser',
- 'components.gyp:keyed_service_content',
- 'components.gyp:memory_coordinator_child',
- 'components.gyp:metrics_gpu',
- 'components.gyp:navigation_interception',
- 'components.gyp:network_hints_renderer',
- 'components.gyp:ntp_tiles',
- 'components.gyp:packed_ct_ev_whitelist',
- 'components.gyp:page_load_metrics_browser',
- 'components.gyp:page_load_metrics_renderer',
- 'components.gyp:password_manager_content_browser',
- 'components.gyp:power',
- 'components.gyp:precache_content',
- 'components.gyp:safe_browsing_db',
- 'components.gyp:safe_json',
- 'components.gyp:safe_json_test_support',
- 'components.gyp:sessions_content',
- 'components.gyp:storage_monitor',
- 'components.gyp:storage_monitor_test_support',
- 'components.gyp:subresource_filter_content_browser',
- 'components.gyp:subresource_filter_content_common',
- 'components.gyp:test_database_manager',
- 'components.gyp:url_matcher',
- 'components.gyp:visitedlink_browser',
- 'components.gyp:visitedlink_renderer',
- 'components.gyp:wallpaper',
- 'components.gyp:web_cache_browser',
- 'components.gyp:web_modal',
- 'components.gyp:web_modal_test_support',
- 'components.gyp:zoom',
- 'scheduler/scheduler.gyp:scheduler',
- 'test_runner/test_runner.gyp:test_runner',
- 'tracing.gyp:tracing',
- 'webcrypto/webcrypto.gyp:webcrypto',
- '../third_party/boringssl/boringssl.gyp:boringssl',
- '../third_party/re2/re2.gyp:re2',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'sources' : [
- '<@(web_restrictions_unittest_sources)',
- ],
- 'dependencies': [
- 'components.gyp:web_restrictions_browser',
- 'components.gyp:web_restrictions_test_support',
- '../build/android/ndk.gyp:cpu_features',
- ],
- }],
- ['OS=="android" and configuration_policy == 1', {
- 'dependencies': [
- 'components.gyp:policy_java',
- ],
- }],
- ['safe_browsing == 2 and OS != "ios"', {
- 'dependencies': [
- 'components.gyp:safe_browsing_db_mobile',
- ],
- 'sources': [
- '<@(safe_browsing_db_mobile_unittest_sources)',
- ],
- }],
- ['OS != "mac" and use_aura == 0', {
- 'sources!': [
- 'display_compositor/buffer_queue_unittest.cc',
- ],
- }],
- ],
- }, { # 'OS == "ios"'
- 'sources': [
- 'webp_transcode/webp_decoder_unittest.mm',
- ],
- 'sources/': [
- # Exclude all tests that depends on //content (based on layered-
- # component directory structure).
- ['exclude', '^[^/]*/content/'],
- ],
- 'mac_bundle_resources': [
- '<(PRODUCT_DIR)/ui_test.pak',
- ],
- 'dependencies': [
- '../ios/web/ios_web.gyp:ios_web_test_support',
- '../third_party/ocmock/ocmock.gyp:ocmock',
- 'components.gyp:autofill_ios_browser',
- 'components.gyp:sessions_ios',
- 'components.gyp:signin_ios_browser',
- 'components.gyp:signin_ios_browser_test_support',
- 'components.gyp:translate_ios_browser',
- 'components.gyp:webp_transcode',
- ],
- 'actions': [
- {
- 'action_name': 'copy_test_data',
- 'variables': {
- 'test_data_files': [
- '../net/data/ssl/certificates',
- 'test/data',
- ],
- 'test_data_prefix': 'components',
- },
- 'includes': [ '../build/copy_test_data_ios.gypi' ],
- },
- ],
- 'conditions': [
- ['configuration_policy==1', {
- 'sources/': [
- ['include', '^policy/'],
- ],
- }],
- ],
- }],
- ['disable_nacl==0', {
- 'sources': [
- '<@(nacl_unittest_sources)',
- ],
- 'dependencies': [
- 'nacl.gyp:nacl_browser',
- 'nacl.gyp:nacl_common',
- ],
- }],
- ['OS == "mac"', {
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/AddressBook.framework',
- '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
- '$(SDKROOT)/System/Library/Frameworks/ImageCaptureCore.framework',
- ],
- },
- 'sources!': [
- 'password_manager/core/browser/password_store_default_unittest.cc',
- ],
- }],
- ['OS == "android"', {
- 'sources': [
- 'data_usage/android/traffic_stats_amortizer_unittest.cc',
- 'invalidation/impl/invalidation_logger_unittest.cc',
- 'invalidation/impl/invalidation_service_android_unittest.cc',
- ],
- 'sources!': [
- 'gcm_driver/gcm_account_mapper_unittest.cc',
- 'gcm_driver/gcm_channel_status_request_unittest.cc',
- 'gcm_driver/gcm_client_impl_unittest.cc',
- 'gcm_driver/gcm_driver_desktop_unittest.cc',
- 'gcm_driver/gcm_stats_recorder_impl_unittest.cc',
- 'sessions/core/session_backend_unittest.cc',
- 'storage_monitor/media_storage_util_unittest.cc',
- 'storage_monitor/storage_info_unittest.cc',
- 'storage_monitor/storage_monitor_unittest.cc',
- 'web_modal/web_contents_modal_dialog_manager_unittest.cc',
- ],
- 'dependencies': [
- 'components.gyp:data_usage_android',
- 'components.gyp:safe_json_java',
- 'components.gyp:variations_java',
- '../content/content.gyp:content_java',
- '../testing/android/native_test.gyp:native_test_native_code',
- ],
- 'dependencies!': [
- 'components.gyp:storage_monitor',
- 'components.gyp:storage_monitor_test_support',
- 'components.gyp:web_modal',
- 'components.gyp:web_modal_test_support',
- ],
- }, {
- 'sources': [
- '<@(invalidation_unittest_sources)',
- ],
- }],
- ['OS != "ios" and OS != "android"', {
- 'sources': [
- '<@(audio_modem_unittest_sources)',
- '<@(copresence_unittest_sources)',
- '<@(feedback_unittest_sources)',
- '<@(proximity_auth_unittest_sources)',
- '<@(webusb_detector_unittest_sources)',
- ],
- 'sources!': [
- 'variations/variations_request_scheduler_mobile_unittest.cc',
- 'web_resource/promo_resource_service_mobile_ntp_unittest.cc',
- ],
- 'dependencies': [
- '../device/bluetooth/bluetooth.gyp:device_bluetooth_mocks',
- '../device/core/core.gyp:device_core',
- '../device/core/core.gyp:device_core_mocks',
- '../device/hid/hid.gyp:device_hid_mocks',
- '../device/usb/usb.gyp:device_usb',
- '../device/usb/usb.gyp:device_usb_mocks',
- '../google_apis/google_apis.gyp:google_apis_test_support',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- 'components.gyp:audio_modem',
- 'components.gyp:audio_modem_test_support',
- 'components.gyp:copresence',
- 'components.gyp:copresence_test_support',
- 'components.gyp:cryptauth',
- 'components.gyp:cryptauth_proto',
- 'components.gyp:cryptauth_test_support',
- 'components.gyp:feedback_component',
- 'components.gyp:pref_registry_test_support',
- 'components.gyp:proximity_auth',
- 'components.gyp:proximity_auth_test_support',
- 'components.gyp:webusb',
- ],
- }],
- ['chromeos==1', {
- 'sources': [
- 'arc/arc_bridge_service_unittest.cc',
- 'arc/ime/arc_ime_service_unittest.cc',
- 'arc/intent_helper/activity_icon_loader_unittest.cc',
- 'arc/intent_helper/arc_intent_helper_bridge_unittest.cc',
- 'arc/intent_helper/font_size_util_unittest.cc',
- 'arc/intent_helper/intent_filter_unittest.cc',
- 'arc/intent_helper/link_handler_model_impl_unittest.cc',
- 'pairing/message_buffer_unittest.cc',
- 'timers/alarm_timer_unittest.cc',
- 'wifi_sync/wifi_config_delegate_chromeos_unittest.cc',
- 'wifi_sync/wifi_credential_syncable_service_unittest.cc',
- 'wifi_sync/wifi_credential_unittest.cc',
- 'wifi_sync/wifi_security_class_chromeos_unittest.cc',
- 'wifi_sync/wifi_security_class_unittest.cc',
- '<@(metrics_leak_detector_unittest_sources)',
- '<@(ownership_unittest_sources)',
- '<@(user_manager_unittest_sources)',
- ],
- 'sources!': [
- 'signin/core/browser/account_investigator_unittest.cc',
- 'signin/core/browser/signin_status_metrics_provider_unittest.cc',
- 'storage_monitor/storage_monitor_linux_unittest.cc',
- ],
- 'dependencies': [
- '../chromeos/chromeos.gyp:chromeos_test_support',
- 'components.gyp:arc',
- 'components.gyp:arc_test_support',
- 'components.gyp:metrics_leak_detector',
- 'components.gyp:ownership',
- 'components.gyp:pairing',
- 'components.gyp:user_manager_test_support',
- 'components.gyp:wifi_sync',
- ],
- }],
- ['OS=="linux"', {
- 'sources': [
- 'metrics/serialization/serialization_utils_unittest.cc',
- ],
- 'dependencies': [
- 'components.gyp:metrics_serialization',
- '../dbus/dbus.gyp:dbus',
- '../device/media_transfer_protocol/media_transfer_protocol.gyp:device_media_transfer_protocol',
- ],
- }],
- ['OS=="linux" and chromeos!=1', {
- 'sources': [
- 'os_crypt/kwallet_dbus_unittest.cc',
- 'os_crypt/os_crypt_linux_unittest.cc',
- 'os_crypt/os_crypt_util_linux_unittest.cc',
- ],
- 'defines': [
- 'USE_KWALLET',
- 'USE_LIBSECRET',
- ],
- 'include_dirs': [
- '../third_party/libsecret'
- ],
- 'dependencies' : [
- '../build/linux/system.gyp:dbus',
- '../dbus/dbus.gyp:dbus',
- '../dbus/dbus.gyp:dbus_test_support',
- ]
- }],
- ['OS=="linux" and use_udev==0', {
- 'dependencies!': [
- 'components.gyp:storage_monitor',
- 'components.gyp:storage_monitor_test_support',
- ],
- 'sources/': [
- ['exclude', '^storage_monitor/'],
- ],
- }],
- ['configuration_policy==1', {
- 'dependencies': [
- 'components.gyp:policy_component',
- 'components.gyp:policy_component_test_support',
- 'components.gyp:policy_test_support',
- ],
- 'sources': [
- '<@(policy_unittest_sources)',
- 'sync_driver/sync_policy_handler_unittest.cc',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'sources/': [
- ['exclude', '^policy/core/common/async_policy_provider_unittest\\.cc'],
- ['exclude', '^tracing/browser/trace_config_file_unittest\\.cc'],
- ],
- }],
- ['OS=="android" or OS=="ios"', {
- # Note: 'sources!' is processed before any 'sources/', so the
- # ['include', '^policy/'] on iOS above will include all of the
- # policy source files again. Using 'source/' here too will get
- # these files excluded as expected.
- 'sources/': [
- ['exclude', '^policy/core/common/cloud/component_cloud_policy_service_unittest\\.cc'],
- ['exclude', '^policy/core/common/cloud/component_cloud_policy_store_unittest\\.cc'],
- ['exclude', '^policy/core/common/cloud/component_cloud_policy_updater_unittest\\.cc'],
- ['exclude', '^policy/core/common/cloud/external_policy_data_fetcher_unittest\\.cc'],
- ['exclude', '^policy/core/common/cloud/external_policy_data_updater_unittest\\.cc'],
- ['exclude', '^policy/core/common/cloud/resource_cache_unittest\\.cc'],
- ['exclude', '^policy/core/common/config_dir_policy_loader_unittest\\.cc'],
- ],
- }],
- ['chromeos==1', {
- 'sources': [
- 'policy/core/common/proxy_policy_provider_unittest.cc',
- ],
- 'sources!': [
- 'policy/core/common/cloud/user_cloud_policy_manager_unittest.cc',
- 'policy/core/common/cloud/user_cloud_policy_store_unittest.cc',
- ],
- }],
- ['OS=="ios" or OS=="mac"', {
- 'sources': [
- 'policy/core/common/mac_util_unittest.cc',
- ],
- }],
- ],
- }, { # configuration_policy!=1
- 'sources!': [
- 'search_engines/default_search_policy_handler_unittest.cc',
- 'sync_driver/sync_policy_handler_unittest.cc',
- ],
- }],
- ['enable_plugins == 1', {
- 'sources': [
- 'content_settings/core/browser/content_settings_provider_unittest.cc',
- ],
- }],
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- ],
- 'conditions': [
- ['OS == "android"', {
- 'variables': {
- 'components_browsertests_pak_input_resources': [
- '<(PRODUCT_DIR)/components_tests_resources.pak',
- '<(PRODUCT_DIR)/content_shell/assets/content_shell.pak',
- ],
- 'conditions': [
- ['icu_use_data_file_flag==1', {
- 'components_browsertests_pak_input_resources': [
- '<(PRODUCT_DIR)/icudtl.dat',
- ],
- }],
- ],
- },
- 'includes': ['../build/android/v8_external_startup_data_arch_suffix.gypi'],
- 'targets': [
- {
- 'target_name': 'components_browsertests_paks_copy',
- 'type': 'none',
- 'dependencies': [
- 'components_browsertests',
- ],
- 'variables': {
- 'dest_path': '<(PRODUCT_DIR)/components_browsertests_apk_shell/assets',
- 'src_files': [
- '<@(components_browsertests_pak_input_resources)',
- ],
- 'clear': 1,
- 'conditions': [
- ['v8_use_external_startup_data==1', {
- 'renaming_sources': [
- '<(PRODUCT_DIR)/natives_blob.bin',
- '<(PRODUCT_DIR)/snapshot_blob.bin',
- ],
- 'renaming_destinations': [
- 'natives_blob_<(arch_suffix).bin',
- 'snapshot_blob_<(arch_suffix).bin',
- ],
- }],
- ],
- },
- 'includes': ['../build/android/copy_ex.gypi'],
- },
- {
- 'target_name': 'components_browsertests_manifest',
- 'type': 'none',
- 'variables': {
- 'jinja_inputs': ['test/android/browsertests_apk/AndroidManifest.xml.jinja2'],
- 'jinja_output': '<(SHARED_INTERMEDIATE_DIR)/components_browsertests_manifest/AndroidManifest.xml',
- },
- 'includes': [ '../build/android/jinja_template.gypi' ],
- },
- {
- # GN: //components:components_browsertests_apk
- 'target_name': 'components_browsertests_apk',
- 'type': 'none',
- 'dependencies': [
- '../content/content.gyp:content_java',
- '../content/content_shell_and_tests.gyp:content_java_test_support',
- '../content/content_shell_and_tests.gyp:content_shell_browsertests_java',
- '../content/content_shell_and_tests.gyp:content_shell_java',
- 'components_browsertests_paks_copy',
- 'components_browsertests',
- ],
- 'variables': {
- 'test_suite_name': 'components_browsertests',
- 'isolate_file': 'components_browsertests.isolate',
- 'java_in_dir': 'test/android/browsertests_apk',
- 'android_manifest_path': '<(SHARED_INTERMEDIATE_DIR)/components_browsertests_manifest/AndroidManifest.xml',
- 'resource_dir': 'test/android/browsertests_apk/res',
- 'asset_location': '<(PRODUCT_DIR)/components_browsertests_apk_shell/assets',
- 'conditions': [
- ['icu_use_data_file_flag==1', {
- 'additional_input_paths': [
- '<(asset_location)/icudtl.dat',
- ],
- }],
- ['v8_use_external_startup_data==1', {
- 'additional_input_paths': [
- '<(asset_location)/natives_blob_<(arch_suffix).bin',
- '<(asset_location)/snapshot_blob_<(arch_suffix).bin',
- ],
- }],
- ],
- },
- 'includes': [ '../build/apk_browsertest.gypi' ],
- },
- {
- 'target_name': 'components_unittests_apk',
- 'isolate_file': 'components_unittests.isolate',
- 'type': 'none',
- 'dependencies': [
- 'components_unittests',
- 'components.gyp:instance_id_driver_java',
- 'components.gyp:instance_id_driver_test_support_java',
- 'components.gyp:invalidation_java',
- 'components.gyp:signin_core_browser_java',
- 'components.gyp:web_restrictions_test_support_java',
- ],
- 'variables': {
- 'test_suite_name': 'components_unittests',
- },
- 'includes': [ '../build/apk_test.gypi' ],
- },
- {
- 'target_name': 'components_junit_tests',
- 'type': 'none',
- 'dependencies': [
- 'components.gyp:invalidation_java',
- 'components.gyp:policy_java',
- 'components.gyp:policy_java_test_support',
- 'components.gyp:web_restrictions_java',
- '../base/base.gyp:base_java',
- '../base/base.gyp:base_java_test_support',
- '../testing/android/junit/junit_test.gyp:junit_test_support',
- ],
- 'variables': {
- 'main_class': 'org.chromium.testing.local.JunitTestMain',
- 'src_paths': [
- 'invalidation/impl/android/junit/',
- 'policy/android/junit/',
- 'web_restrictions/browser/junit/'
- ],
- 'wrapper_script_name': 'helper/<(_target_name)',
- },
- 'includes': [ '../build/host_jar.gypi' ],
- },
- ],
- 'conditions': [
- ['test_isolation_mode != "noop"',
- {
- 'targets': [
- {
- 'target_name': 'components_browsertests_apk_run',
- 'type': 'none',
- 'dependencies': [
- 'components_browsertests_apk',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'components_browsertests_apk.isolate',
- ],
- },
- {
- 'target_name': 'components_unittests_apk_run',
- 'type': 'none',
- 'dependencies': [
- 'components_unittests_apk',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'components_unittests_apk.isolate',
- ],
- },
- ],
- },
- ],
- ],
- }],
- ['OS != "ios"', {
- 'targets': [
- {
- # GN: //components:components_perftests
- 'target_name': 'components_perftests',
- 'type': '<(gtest_target_type)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_perf',
- '../content/content_shell_and_tests.gyp:test_support_content',
- '../testing/gtest.gyp:gtest',
- '../testing/perf/perf_test.gyp:perf_test',
- 'components.gyp:visitedlink_browser',
- 'scheduler/scheduler.gyp:scheduler',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'scheduler/base/task_queue_manager_delegate_for_test.cc',
- 'scheduler/base/task_queue_manager_delegate_for_test.h',
- 'scheduler/base/task_queue_manager_perftest.cc',
- 'visitedlink/test/visitedlink_perftest.cc',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'dependencies': [
- '../testing/android/native_test.gyp:native_test_native_code',
- ],
- }],
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- },
- {
- 'target_name': 'components_browsertests',
- 'type': '<(gtest_target_type)',
- 'defines!': ['CONTENT_IMPLEMENTATION'],
- 'dependencies': [
- '../content/content.gyp:content_common',
- '../content/content.gyp:content_gpu',
- '../content/content.gyp:content_renderer',
- '../content/content_shell_and_tests.gyp:content_browser_test_base',
- '../content/content_shell_and_tests.gyp:content_browser_test_support',
- '../content/content_shell_and_tests.gyp:content_shell_lib',
- '../content/content_shell_and_tests.gyp:content_shell_pak',
- '../content/content_shell_and_tests.gyp:test_support_content',
- '../skia/skia.gyp:skia',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- 'components.gyp:autofill_content_browser',
- 'components.gyp:autofill_content_renderer',
- 'components.gyp:content_settings_core_browser',
- 'components.gyp:content_settings_core_common',
- 'components.gyp:dom_distiller_content_browser',
- 'components.gyp:dom_distiller_content_renderer',
- 'components.gyp:dom_distiller_core',
- 'components.gyp:password_manager_content_renderer',
- 'components.gyp:pref_registry_test_support',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- 'components_tests_pak',
- 'tracing.gyp:tracing',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'HAS_OUT_OF_PROC_TEST_RUNNER',
- ],
- 'sources': [
- # Note: test list duplicated in GN build.
- 'autofill/content/browser/risk/fingerprint_browsertest.cc',
- 'autofill/content/renderer/password_form_conversion_utils_browsertest.cc',
- 'dom_distiller/content/browser/distillable_page_utils_browsertest.cc',
- 'dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc',
- 'dom_distiller/content/browser/test/dom_distiller_js_browsertest.cc',
- 'password_manager/content/renderer/credential_manager_client_browsertest.cc',
- 'tracing/child/child_trace_message_filter_browsertest.cc',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'sources' : [
- 'test/android/browsertests_apk/components_browser_tests_jni_onload.cc',
- ],
- 'sources!': [
- 'autofill/content/browser/risk/fingerprint_browsertest.cc',
- ],
- 'dependencies': [
- '../testing/android/native_test.gyp:native_test_support',
- ],
- }],
- ['OS == "linux"', {
- 'sources': [
- # content_extractor_browsertest is a standalone content extraction tool built as
- # a MANUAL component_browsertest.
- 'dom_distiller/standalone/content_extractor_browsertest.cc',
- ],
- }],
- ['OS=="win"', {
- 'resource_include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/content/app/resources',
- ],
- 'sources': [
- '../content/shell/app/resource.h',
- '../content/shell/app/shell.rc',
- ],
- 'dependencies': [
- '<(DEPTH)/content/app/resources/content_resources.gyp:content_resources',
- '<(DEPTH)/content/app/strings/content_strings.gyp:content_strings',
- '<(DEPTH)/net/net.gyp:net_resources',
- '<(DEPTH)/third_party/WebKit/public/blink_resources.gyp:blink_resources',
- '<(DEPTH)/third_party/iaccessible2/iaccessible2.gyp:iaccessible2',
- '<(DEPTH)/third_party/isimpledom/isimpledom.gyp:isimpledom',
- ],
- 'configurations': {
- 'Debug_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'LinkIncremental': '<(msvs_large_module_debug_link_mode)',
- },
- },
- },
- },
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- }],
- ['OS=="mac"', {
- 'dependencies': [
- '../content/content_shell_and_tests.gyp:content_shell', # Needed for Content Shell.app's Helper.
- ],
- }],
- ['enable_basic_printing==1 or enable_print_preview==1', {
- 'dependencies': [
- 'components.gyp:printing_test_support',
- ],
- 'sources' : [
- 'printing/test/print_web_view_helper_browsertest.cc',
- ],
- }]
- ],
- },
- ],
- 'conditions': [
- ['test_isolation_mode != "noop"', {
- 'targets': [
- {
- 'target_name': 'components_browsertests_run',
- 'type': 'none',
- 'dependencies': [ 'components_browsertests' ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'components_browsertests.isolate',
- ],
- 'conditions': [
- ['use_x11==1', {
- 'dependencies': [
- '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
- ],
- }],
- ],
- },
- ],
- }],
- ],
- }],
- ['test_isolation_mode != "noop"', {
- 'targets': [
- {
- 'target_name': 'components_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'components_unittests',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'components_unittests.isolate',
- ],
- 'conditions': [
- ['use_x11==1', {
- 'dependencies': [
- '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
- ],
- }],
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/components_unittests.isolate b/chromium/components/components_unittests.isolate
deleted file mode 100644
index 4befb23f286..00000000000
--- a/chromium/components/components_unittests.isolate
+++ /dev/null
@@ -1,96 +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.
-{
- 'conditions': [
- ['use_x11==0', {
- 'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/components_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--msan=<(msan)',
- '--tsan=<(tsan)',
- ],
- },
- }],
- ['use_x11==1', {
- 'variables': {
- 'command': [
- '../testing/xvfb.py',
- '<(PRODUCT_DIR)',
- '<(PRODUCT_DIR)/components_unittests',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--msan=<(msan)',
- '--tsan=<(tsan)',
- ],
- 'files': [
- '../testing/xvfb.py',
- '<(PRODUCT_DIR)/xdisplaycheck',
- ],
- },
- }],
- ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', {
- 'variables': {
- 'files': [
- '../net/data/',
- 'test/data/',
- '<(PRODUCT_DIR)/components_tests_resources.pak',
- '<(PRODUCT_DIR)/ui_test.pak',
- ],
- },
- }],
- ['OS=="linux" or OS=="mac" or OS=="win"', {
- 'variables': {
- 'files': [
- '../testing/test_env.py',
- ],
- },
- }],
- ['OS=="linux"', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/libosmesa.so',
- ],
- },
- }],
- ['OS=="mac"', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/osmesa.so',
- ],
- },
- }],
- ['OS=="win"', {
- 'variables': {
- 'files': [
- '../chrome/test/data/policy/',
- '<(PRODUCT_DIR)/osmesa.dll',
- ],
- },
- }],
- ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/components_unittests.exe.pdb',
- ],
- },
- }],
- ['OS=="mac" and asan==1 and fastbuild==0', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/components_unittests.dSYM/',
- '<(PRODUCT_DIR)/osmesa.so.dSYM/',
- ],
- },
- }],
- ],
- 'includes': [
- '../base/base.isolate',
- '../ui/gl/gl.isolate',
- ],
-}
diff --git a/chromium/components/components_unittests_apk.isolate b/chromium/components/components_unittests_apk.isolate
deleted file mode 100644
index e21059f524e..00000000000
--- a/chromium/components/components_unittests_apk.isolate
+++ /dev/null
@@ -1,26 +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.
-{
- 'includes': [
- '../build/android/android.isolate',
- 'components_unittests.isolate',
- ],
- 'variables': {
- 'command': [
- '<(PRODUCT_DIR)/bin/run_components_unittests',
- '--logcat-output-dir', '${ISOLATED_OUTDIR}/logcats',
- ],
- 'files': [
- '../base/base.isolate',
- '../build/config/',
- '../third_party/angle/angle.isolate',
- '../third_party/icu/icu.isolate',
- '../third_party/instrumented_libraries/instrumented_libraries.isolate',
- '../ui/gl/gl.isolate',
- '<(PRODUCT_DIR)/bin/run_components_unittests',
- '<(PRODUCT_DIR)/components_unittests_apk/',
- 'components_unittests.isolate',
- ]
- },
-}
diff --git a/chromium/components/constrained_window.gypi b/chromium/components/constrained_window.gypi
deleted file mode 100644
index 9abba05d18b..00000000000
--- a/chromium/components/constrained_window.gypi
+++ /dev/null
@@ -1,24 +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.
-{
- 'targets': [
- {
- 'target_name': 'constrained_window',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/components/components.gyp:web_modal',
- '<(DEPTH)/ui/views/views.gyp:views',
- '<(DEPTH)/skia/skia.gyp:skia',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'constrained_window/constrained_window_views.cc',
- 'constrained_window/constrained_window_views.h',
- 'constrained_window/constrained_window_views_client.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/constrained_window/BUILD.gn b/chromium/components/constrained_window/BUILD.gn
index 8e0952e0763..8cff9755f0c 100644
--- a/chromium/components/constrained_window/BUILD.gn
+++ b/chromium/components/constrained_window/BUILD.gn
@@ -2,19 +2,41 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("constrained_window") {
+import("//build/config/ui.gni")
+
+static_library("constrained_window") {
sources = [
"constrained_window_views.cc",
"constrained_window_views.h",
"constrained_window_views_client.h",
+ "native_web_contents_modal_dialog_manager_views.cc",
+ "native_web_contents_modal_dialog_manager_views.h",
+ "native_web_contents_modal_dialog_manager_views_mac.mm",
]
+ if (is_mac && !mac_views_browser) {
+ sources += [ "show_modal_dialog_cocoa.cc" ]
+ } else {
+ sources += [ "show_modal_dialog_views.cc" ]
+ }
+
deps = [
"//components/guest_view/browser",
"//components/web_modal",
- "//skia",
+ "//content/public/browser",
"//ui/views",
]
+ public_deps = [
+ # Skia headers are exposed in the public API.
+ "//skia",
+ ]
+
+ if (use_aura) {
+ deps += [
+ "//ui/aura",
+ "//ui/wm",
+ ]
+ }
}
source_set("unit_tests") {
@@ -23,6 +45,10 @@ source_set("unit_tests") {
"constrained_window_views_unittest.cc",
]
+ if (is_mac && !mac_views_browser) {
+ sources += [ "test_create_native_web_modal_manager_cocoa.cc" ]
+ }
+
deps = [
":constrained_window",
"//components/web_modal:test_support",
diff --git a/chromium/components/constrained_window/DEPS b/chromium/components/constrained_window/DEPS
index 9ddd155ac03..4950d97c958 100644
--- a/chromium/components/constrained_window/DEPS
+++ b/chromium/components/constrained_window/DEPS
@@ -1,7 +1,10 @@
include_rules = [
"+components/guest_view",
"+components/web_modal",
+ "+content/public/browser",
+ "+ui/aura",
"+ui/base",
"+ui/gfx",
"+ui/views",
+ "+ui/wm",
]
diff --git a/chromium/components/constrained_window/constrained_window_views.cc b/chromium/components/constrained_window/constrained_window_views.cc
index def5232fc97..ccdfdd16067 100644
--- a/chromium/components/constrained_window/constrained_window_views.cc
+++ b/chromium/components/constrained_window/constrained_window_views.cc
@@ -18,6 +18,10 @@
#include "ui/views/widget/widget_observer.h"
#include "ui/views/window/dialog_delegate.h"
+#if defined(OS_MACOSX)
+#import "components/constrained_window/native_web_contents_modal_dialog_manager_views_mac.h"
+#endif
+
using web_modal::ModalDialogHost;
using web_modal::ModalDialogHostObserver;
@@ -83,6 +87,18 @@ void UpdateModalDialogPosition(views::Widget* widget,
if (widget->HasCapture())
return;
+ views::Widget* host_widget =
+ views::Widget::GetWidgetForNativeView(dialog_host->GetHostView());
+
+ // If the host view is not backed by a Views::Widget, just update the widget
+ // size. This can happen on MacViews under the Cocoa browser where the window
+ // modal dialogs are displayed as sheets, and their position is managed by a
+ // ConstrainedWindowSheetController instance.
+ if (!host_widget) {
+ widget->SetSize(size);
+ return;
+ }
+
gfx::Point position = dialog_host->GetDialogPosition(size);
views::Border* border = widget->non_client_view()->frame_view()->border();
// Border may be null during widget initialization.
@@ -92,11 +108,8 @@ void UpdateModalDialogPosition(views::Widget* widget,
position.set_y(position.y() - border->GetInsets().top());
}
- if (widget->is_top_level()) {
- position +=
- views::Widget::GetWidgetForNativeView(dialog_host->GetHostView())->
- GetClientAreaBoundsInScreen().OffsetFromOrigin();
- }
+ if (widget->is_top_level())
+ position += host_widget->GetClientAreaBoundsInScreen().OffsetFromOrigin();
widget->SetBounds(gfx::Rect(position, size));
}
@@ -132,6 +145,12 @@ void UpdateWidgetModalDialogPosition(views::Widget* widget,
widget->GetRootView()->GetPreferredSize());
}
+content::WebContents* GetTopLevelWebContents(
+ content::WebContents* initiator_web_contents) {
+ return guest_view::GuestViewBase::GetTopLevelWebContents(
+ initiator_web_contents);
+}
+
views::Widget* ShowWebModalDialogViews(
views::WidgetDelegate* dialog,
content::WebContents* initiator_web_contents) {
@@ -139,13 +158,33 @@ views::Widget* ShowWebModalDialogViews(
// For embedded WebContents, use the embedder's WebContents for constrained
// window.
content::WebContents* web_contents =
- guest_view::GuestViewBase::GetTopLevelWebContents(initiator_web_contents);
+ GetTopLevelWebContents(initiator_web_contents);
views::Widget* widget = CreateWebModalDialogViews(dialog, web_contents);
- web_modal::WebContentsModalDialogManager::FromWebContents(web_contents)
- ->ShowModalDialog(widget->GetNativeWindow());
+ ShowModalDialog(widget->GetNativeWindow(), web_contents);
return widget;
}
+#if defined(OS_MACOSX)
+views::Widget* ShowWebModalDialogWithOverlayViews(
+ views::WidgetDelegate* dialog,
+ content::WebContents* initiator_web_contents) {
+ DCHECK(constrained_window_views_client);
+ // For embedded WebContents, use the embedder's WebContents for constrained
+ // window.
+ content::WebContents* web_contents =
+ GetTopLevelWebContents(initiator_web_contents);
+ views::Widget* widget = CreateWebModalDialogViews(dialog, web_contents);
+ web_modal::WebContentsModalDialogManager* manager =
+ web_modal::WebContentsModalDialogManager::FromWebContents(web_contents);
+ std::unique_ptr<web_modal::SingleWebContentsDialogManager> dialog_manager(
+ new NativeWebContentsModalDialogManagerViewsMac(widget->GetNativeWindow(),
+ manager));
+ manager->ShowDialogWithManager(widget->GetNativeWindow(),
+ std::move(dialog_manager));
+ return widget;
+}
+#endif
+
views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog,
content::WebContents* web_contents) {
DCHECK_EQ(ui::MODAL_TYPE_CHILD, dialog->GetModalType());
diff --git a/chromium/components/constrained_window/constrained_window_views.h b/chromium/components/constrained_window/constrained_window_views.h
index fd44fe77d3a..9a8b3e95f5f 100644
--- a/chromium/components/constrained_window/constrained_window_views.h
+++ b/chromium/components/constrained_window/constrained_window_views.h
@@ -42,11 +42,30 @@ void UpdateWidgetModalDialogPosition(
views::Widget* widget,
web_modal::ModalDialogHost* dialog_host);
+// Returns the top level WebContents of |initiator_web_contents|.
+content::WebContents* GetTopLevelWebContents(
+ content::WebContents* initiator_web_contents);
+
+// Shows the dialog with a new SingleWebContentsDialogManager. The dialog will
+// notify via WillClose() when it is being destroyed.
+void ShowModalDialog(gfx::NativeWindow dialog,
+ content::WebContents* web_contents);
+
// Calls CreateWebModalDialogViews, shows the dialog, and returns its widget.
views::Widget* ShowWebModalDialogViews(
views::WidgetDelegate* dialog,
content::WebContents* initiator_web_contents);
+#if defined(OS_MACOSX)
+// Like ShowWebModalDialogViews, but used to show a native dialog "sheet" on
+// Mac. Sheets are always modal to their parent window. To make them tab-modal,
+// this provides an invisible tab-modal overlay window managed by
+// WebContentsModalDialogManager, which can host a dialog sheet.
+views::Widget* ShowWebModalDialogWithOverlayViews(
+ views::WidgetDelegate* dialog,
+ content::WebContents* initiator_web_contents);
+#endif
+
// Create a widget for |dialog| that is modal to |web_contents|.
// The modal type of |dialog->GetModalType()| must be ui::MODAL_TYPE_CHILD.
views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog,
@@ -59,6 +78,6 @@ views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog,
views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog,
gfx::NativeWindow parent);
-} // namespace constrained window
+} // namespace constrained_window
#endif // COMPONENTS_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_VIEWS_H_
diff --git a/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views.cc b/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views.cc
new file mode 100644
index 00000000000..45e3a43e490
--- /dev/null
+++ b/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views.cc
@@ -0,0 +1,233 @@
+// 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 "components/constrained_window/native_web_contents_modal_dialog_manager_views.h"
+
+#include <memory>
+
+#include "components/constrained_window/constrained_window_views.h"
+#include "components/web_modal/web_contents_modal_dialog_host.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/border.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/window/dialog_delegate.h"
+#include "ui/views/window/non_client_view.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
+#include "ui/wm/core/visibility_controller.h"
+#include "ui/wm/core/window_animations.h"
+#include "ui/wm/core/window_modality_controller.h"
+#endif
+
+using web_modal::SingleWebContentsDialogManager;
+using web_modal::SingleWebContentsDialogManagerDelegate;
+using web_modal::WebContentsModalDialogHost;
+using web_modal::ModalDialogHostObserver;
+
+namespace constrained_window {
+
+NativeWebContentsModalDialogManagerViews::
+ NativeWebContentsModalDialogManagerViews(
+ gfx::NativeWindow dialog,
+ SingleWebContentsDialogManagerDelegate* native_delegate)
+ : native_delegate_(native_delegate),
+ dialog_(dialog),
+ host_(NULL),
+ host_destroying_(false) {
+ ManageDialog();
+}
+
+NativeWebContentsModalDialogManagerViews::
+ ~NativeWebContentsModalDialogManagerViews() {
+ if (host_)
+ host_->RemoveObserver(this);
+
+ for (std::set<views::Widget*>::iterator it = observed_widgets_.begin();
+ it != observed_widgets_.end(); ++it) {
+ (*it)->RemoveObserver(this);
+ }
+}
+
+void NativeWebContentsModalDialogManagerViews::ManageDialog() {
+ views::Widget* widget = GetWidget(dialog());
+ widget->AddObserver(this);
+ observed_widgets_.insert(widget);
+ widget->set_movement_disabled(true);
+
+#if defined(USE_AURA)
+ // TODO(wittman): remove once the new visual style is complete
+ widget->GetNativeWindow()->SetProperty(aura::client::kConstrainedWindowKey,
+ true);
+
+ wm::SetWindowVisibilityAnimationType(
+ widget->GetNativeWindow(), wm::WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE);
+
+ gfx::NativeView parent = widget->GetNativeView()->parent();
+ wm::SetChildWindowVisibilityChangesAnimated(parent);
+ // No animations should get performed on the window since that will re-order
+ // the window stack which will then cause many problems.
+ if (parent && parent->parent()) {
+ parent->parent()->SetProperty(aura::client::kAnimationsDisabledKey, true);
+ }
+
+ wm::SetModalParent(widget->GetNativeWindow(),
+ native_delegate_->GetWebContents()->GetNativeView());
+#endif
+}
+
+// SingleWebContentsDialogManager:
+
+void NativeWebContentsModalDialogManagerViews::Show() {
+ // The host destroying means the dialogs will be destroyed in short order.
+ // Avoid showing dialogs at this point as the necessary native window
+ // services may not be present.
+ if (host_destroying_)
+ return;
+
+ views::Widget* widget = GetWidget(dialog());
+#if defined(USE_AURA)
+ std::unique_ptr<wm::SuspendChildWindowVisibilityAnimations> suspend;
+ if (shown_widgets_.find(widget) != shown_widgets_.end()) {
+ suspend.reset(new wm::SuspendChildWindowVisibilityAnimations(
+ widget->GetNativeWindow()->parent()));
+ }
+#endif
+ ShowWidget(widget);
+ Focus();
+
+#if defined(USE_AURA)
+ // TODO(pkotwicz): Control the z-order of the constrained dialog via
+ // views::kHostViewKey. We will need to ensure that the parent window's
+ // shadows are below the constrained dialog in z-order when we do this.
+ shown_widgets_.insert(widget);
+#endif
+}
+
+void NativeWebContentsModalDialogManagerViews::Hide() {
+ views::Widget* widget = GetWidget(dialog());
+#if defined(USE_AURA)
+ std::unique_ptr<wm::SuspendChildWindowVisibilityAnimations> suspend;
+ suspend.reset(new wm::SuspendChildWindowVisibilityAnimations(
+ widget->GetNativeWindow()->parent()));
+#endif
+ HideWidget(widget);
+}
+
+void NativeWebContentsModalDialogManagerViews::Close() {
+ GetWidget(dialog())->Close();
+}
+
+void NativeWebContentsModalDialogManagerViews::Focus() {
+ views::Widget* widget = GetWidget(dialog());
+ if (widget->widget_delegate() &&
+ widget->widget_delegate()->GetInitiallyFocusedView())
+ widget->widget_delegate()->GetInitiallyFocusedView()->RequestFocus();
+#if defined(USE_AURA)
+ // We don't necessarily have a RootWindow yet.
+ if (widget->GetNativeView()->GetRootWindow())
+ widget->GetNativeView()->Focus();
+#endif
+}
+
+void NativeWebContentsModalDialogManagerViews::Pulse() {}
+
+// web_modal::ModalDialogHostObserver:
+
+void NativeWebContentsModalDialogManagerViews::OnPositionRequiresUpdate() {
+ DCHECK(host_);
+
+ for (std::set<views::Widget*>::iterator it = observed_widgets_.begin();
+ it != observed_widgets_.end(); ++it) {
+ constrained_window::UpdateWebContentsModalDialogPosition(*it, host_);
+ }
+}
+
+void NativeWebContentsModalDialogManagerViews::OnHostDestroying() {
+ host_->RemoveObserver(this);
+ host_ = NULL;
+ host_destroying_ = true;
+}
+
+// views::WidgetObserver:
+
+void NativeWebContentsModalDialogManagerViews::OnWidgetClosing(
+ views::Widget* widget) {
+ WidgetClosing(widget);
+}
+
+void NativeWebContentsModalDialogManagerViews::OnWidgetDestroying(
+ views::Widget* widget) {
+ WidgetClosing(widget);
+}
+
+void NativeWebContentsModalDialogManagerViews::HostChanged(
+ WebContentsModalDialogHost* new_host) {
+ if (host_)
+ host_->RemoveObserver(this);
+
+ host_ = new_host;
+
+ // |host_| may be null during WebContents destruction or Win32 tab dragging.
+ if (host_) {
+ host_->AddObserver(this);
+
+ for (std::set<views::Widget*>::iterator it = observed_widgets_.begin();
+ it != observed_widgets_.end(); ++it) {
+ views::Widget::ReparentNativeView((*it)->GetNativeView(),
+ host_->GetHostView());
+ }
+
+ OnPositionRequiresUpdate();
+ }
+}
+
+gfx::NativeWindow NativeWebContentsModalDialogManagerViews::dialog() {
+ return dialog_;
+}
+
+void NativeWebContentsModalDialogManagerViews::ShowWidget(
+ views::Widget* widget) {
+ // |host_| may be NULL during tab drag on Views/Win32.
+ if (host_)
+ constrained_window::UpdateWebContentsModalDialogPosition(widget, host_);
+ widget->Show();
+}
+
+void NativeWebContentsModalDialogManagerViews::HideWidget(
+ views::Widget* widget) {
+ widget->Hide();
+}
+
+views::Widget* NativeWebContentsModalDialogManagerViews::GetWidget(
+ gfx::NativeWindow dialog) {
+ views::Widget* widget = views::Widget::GetWidgetForNativeWindow(dialog);
+ DCHECK(widget);
+ return widget;
+}
+
+void NativeWebContentsModalDialogManagerViews::WidgetClosing(
+ views::Widget* widget) {
+#if defined(USE_AURA)
+ gfx::NativeView view = widget->GetNativeView()->parent();
+ // Allow the parent to animate again.
+ if (view && view->parent())
+ view->parent()->ClearProperty(aura::client::kAnimationsDisabledKey);
+#endif
+ widget->RemoveObserver(this);
+ observed_widgets_.erase(widget);
+
+#if defined(USE_AURA)
+ shown_widgets_.erase(widget);
+#endif
+
+ // Will cause this object to be deleted.
+ native_delegate_->WillClose(widget->GetNativeWindow());
+}
+
+} // namespace constrained_window
diff --git a/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views.h b/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views.h
new file mode 100644
index 00000000000..382b9ce8cad
--- /dev/null
+++ b/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views.h
@@ -0,0 +1,92 @@
+// 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 COMPONENTS_CONSTRAINED_WINDOW_NATIVE_WEB_CONTENTS_MODAL_DIALOG_MANAGER_VIEWS_H_
+#define COMPONENTS_CONSTRAINED_WINDOW_NATIVE_WEB_CONTENTS_MODAL_DIALOG_MANAGER_VIEWS_H_
+
+#include <set>
+
+#include "base/macros.h"
+#include "components/web_modal/modal_dialog_host.h"
+#include "components/web_modal/single_web_contents_dialog_manager.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/widget/widget_observer.h"
+
+namespace views {
+class Widget;
+}
+
+namespace constrained_window {
+
+// Class for parenting a tab-modal views dialog off of a views browser.
+class NativeWebContentsModalDialogManagerViews
+ : public web_modal::SingleWebContentsDialogManager,
+ public web_modal::ModalDialogHostObserver,
+ public views::WidgetObserver {
+ public:
+ NativeWebContentsModalDialogManagerViews(
+ gfx::NativeWindow dialog,
+ web_modal::SingleWebContentsDialogManagerDelegate* native_delegate);
+
+ ~NativeWebContentsModalDialogManagerViews() override;
+
+ // Sets up this object to manage the |dialog_|. Registers for closing events
+ // in order to notify the delegate.
+ void ManageDialog();
+
+ // web_modal::SingleWebContentsDialogManager:
+ void Show() override;
+ void Hide() override;
+ void Close() override;
+ void Focus() override;
+ void Pulse() override;
+
+ // web_modal::ModalDialogHostObserver:
+ void OnPositionRequiresUpdate() override;
+ void OnHostDestroying() override;
+
+ // views::WidgetObserver:
+
+ // NOTE(wittman): OnWidgetClosing is overriden to ensure that, when the widget
+ // is explicitly closed, the destruction occurs within the same call
+ // stack. This avoids event races that lead to non-deterministic destruction
+ // ordering in e.g. the print preview dialog. OnWidgetDestroying is overridden
+ // because OnWidgetClosing is *only* invoked on explicit close, not when the
+ // widget is implicitly destroyed due to its parent being closed. This
+ // situation occurs with app windows. WidgetClosing removes the observer, so
+ // only one of these two functions is ever invoked for a given widget.
+ void OnWidgetClosing(views::Widget* widget) override;
+ void OnWidgetDestroying(views::Widget* widget) override;
+ void HostChanged(web_modal::WebContentsModalDialogHost* new_host) override;
+ gfx::NativeWindow dialog() override;
+
+ protected:
+ web_modal::SingleWebContentsDialogManagerDelegate* native_delegate() {
+ return native_delegate_;
+ }
+
+ // By default just calls widget->Show() or Hide(), but allows a derived class
+ // to override in order to hide an alternate way (e.g. if the default hide
+ // would tear down attached dialogs too early).
+ virtual void ShowWidget(views::Widget* widget);
+ virtual void HideWidget(views::Widget* widget);
+
+ static views::Widget* GetWidget(gfx::NativeWindow dialog);
+
+ private:
+ void WidgetClosing(views::Widget* widget);
+
+ web_modal::SingleWebContentsDialogManagerDelegate* native_delegate_;
+ gfx::NativeWindow dialog_;
+ web_modal::WebContentsModalDialogHost* host_;
+ bool host_destroying_;
+ std::set<views::Widget*> observed_widgets_;
+ std::set<views::Widget*> shown_widgets_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWebContentsModalDialogManagerViews);
+};
+
+} // namespace constrained_window
+
+#endif // COMPONENTS_CONSTRAINED_WINDOW_NATIVE_WEB_CONTENTS_MODAL_DIALOG_MANAGER_VIEWS_H_
diff --git a/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views_mac.h b/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views_mac.h
new file mode 100644
index 00000000000..deb28bc3f07
--- /dev/null
+++ b/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views_mac.h
@@ -0,0 +1,33 @@
+// 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 "components/constrained_window/native_web_contents_modal_dialog_manager_views.h"
+
+namespace web_modal {
+class SingleWebContentsDialogManagerDelegate;
+}
+
+namespace constrained_window {
+
+// Class for parenting a Mac Cocoa sheet on a views tab modal dialog off of a
+// views browser, e.g. for tab-modal Cocoa sheets. Since Cocoa sheets are modal
+// to the parent window, the sheet is instead parented to an invisible views
+// overlay window which is tab-modal.
+class NativeWebContentsModalDialogManagerViewsMac
+ : public NativeWebContentsModalDialogManagerViews {
+ public:
+ NativeWebContentsModalDialogManagerViewsMac(
+ gfx::NativeWindow dialog,
+ web_modal::SingleWebContentsDialogManagerDelegate* native_delegate);
+
+ // NativeWebContentsModalDialogManagerViews:
+ void OnPositionRequiresUpdate() override;
+ void ShowWidget(views::Widget* widget) override;
+ void HideWidget(views::Widget* widget) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NativeWebContentsModalDialogManagerViewsMac);
+};
+
+} // namespace constrained_window
diff --git a/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views_mac.mm b/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views_mac.mm
new file mode 100644
index 00000000000..5df747e7ece
--- /dev/null
+++ b/chromium/components/constrained_window/native_web_contents_modal_dialog_manager_views_mac.mm
@@ -0,0 +1,98 @@
+// 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 "components/constrained_window/native_web_contents_modal_dialog_manager_views_mac.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "components/constrained_window/constrained_window_views.h"
+#include "components/guest_view/browser/guest_view_base.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "content/public/browser/web_contents.h"
+#import "ui/gfx/mac/coordinate_conversion.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+
+using web_modal::WebContentsModalDialogManager;
+using web_modal::SingleWebContentsDialogManager;
+
+namespace {
+
+// Sets visibility and mouse events for a Cocoa NSWindow* and an attached sheet.
+void SetSheetVisible(gfx::NativeWindow overlay, bool visible) {
+ CGFloat alpha = visible ? 1.0 : 0.0;
+ BOOL ignore_events = visible ? NO : YES;
+
+ // Don't allow interaction with the tab underneath the overlay.
+ [overlay setIgnoresMouseEvents:ignore_events];
+
+ [[overlay attachedSheet] setAlphaValue:alpha];
+ [[overlay attachedSheet] setIgnoresMouseEvents:ignore_events];
+}
+
+} // namespace
+
+namespace constrained_window {
+
+NativeWebContentsModalDialogManagerViewsMac::
+ NativeWebContentsModalDialogManagerViewsMac(
+ gfx::NativeWindow dialog,
+ web_modal::SingleWebContentsDialogManagerDelegate* native_delegate)
+ : NativeWebContentsModalDialogManagerViews(dialog, native_delegate) {}
+
+// NativeWebContentsModalDialogManagerViews:
+void NativeWebContentsModalDialogManagerViewsMac::OnPositionRequiresUpdate() {
+ NativeWebContentsModalDialogManagerViews::OnPositionRequiresUpdate();
+
+ views::Widget* widget = GetWidget(dialog());
+ // Because the animation of SFCertificatePanel will change depending on the
+ // size of the parent, i.e. |widget|, make sure its size is the same as the
+ // area under the Chrome UI. The origin of the dialog then also needs to be
+ // updated to position the certificate viewer in the middle horizontally.
+ content::WebContents* web_contents = native_delegate()->GetWebContents();
+ // Note: Can't use WebContents container bounds here because it doesn't
+ // include the DevTool panel width.
+ CGFloat window_width =
+ NSWidth([web_contents->GetTopLevelNativeWindow() frame]);
+ gfx::Rect tab_view_size = web_contents->GetContainerBounds();
+ widget->SetBounds(gfx::Rect(tab_view_size.x(),
+ widget->GetWindowBoundsInScreen().y(),
+ window_width, tab_view_size.height()));
+}
+
+void NativeWebContentsModalDialogManagerViewsMac::ShowWidget(
+ views::Widget* widget) {
+ NSWindow* dialog_window = widget->GetNativeWindow();
+ [dialog_window setAlphaValue:0.0];
+ // Because |dialog_window| is transparent, it won't accept mouse events until
+ // ignoresMouseEvents is set. NSWindows start off accepting mouse events only
+ // in non-transparent areas - setting this explicitly will make the NSWindow
+ // accept mouse events everywhere regardless of window transparency.
+ [dialog_window setIgnoresMouseEvents:NO];
+
+ // Detect whether this is the first call to open the dialog. If yes, do this
+ // via the normal views method. If not, overlay and sheet are both already
+ // opened, and should be invisible, so return the sheet to full opacity.
+ if (![dialog_window attachedSheet]) {
+ NativeWebContentsModalDialogManagerViews::ShowWidget(widget);
+ // Make sure the dialog is sized correctly for the correct animations.
+ OnPositionRequiresUpdate();
+ return;
+ }
+
+ // Account for window resizes that happen while another tab is open.
+ OnPositionRequiresUpdate();
+ SetSheetVisible(dialog_window, true);
+}
+
+void NativeWebContentsModalDialogManagerViewsMac::HideWidget(
+ views::Widget* widget) {
+ NSWindow* dialog_window = widget->GetNativeWindow();
+ // Avoid views::Widget::Hide(), as a call to orderOut: on a NSWindow with an
+ // attached sheet will close the sheet. Instead, just set the sheet to 0
+ // opacity and don't accept click events.
+ SetSheetVisible(dialog_window, false);
+}
+
+} // namespace constrained_window
diff --git a/chromium/components/constrained_window/show_modal_dialog_cocoa.cc b/chromium/components/constrained_window/show_modal_dialog_cocoa.cc
new file mode 100644
index 00000000000..bcb8a5ca4db
--- /dev/null
+++ b/chromium/components/constrained_window/show_modal_dialog_cocoa.cc
@@ -0,0 +1,34 @@
+// 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 <memory>
+
+#include "components/constrained_window/constrained_window_views.h"
+#include "components/web_modal/single_web_contents_dialog_manager.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/gfx/native_widget_types.h"
+
+// TODO(patricialor): This is a layering violation and should be deleted.
+// Currently it's needed because on Cocoa, the dialog needs to be shown with a
+// SingleWebContentsDialogManagerViewsMac, which depends on things inside
+// chrome/browser/ui/cocoa/constrained_window/* and thus can't be moved out into
+// components/constrained_window/*. Instead, to get this to work, the
+// CreateNativeWebModalManager() method is declared in the web_modal component,
+// but defined outside of that in c/b/u/cocoa/.
+
+namespace constrained_window {
+
+void ShowModalDialog(gfx::NativeWindow dialog,
+ content::WebContents* initiator_web_contents) {
+ web_modal::WebContentsModalDialogManager* manager =
+ web_modal::WebContentsModalDialogManager::FromWebContents(
+ initiator_web_contents);
+ std::unique_ptr<web_modal::SingleWebContentsDialogManager> dialog_manager(
+ web_modal::WebContentsModalDialogManager::CreateNativeWebModalManager(
+ dialog, manager));
+ manager->ShowDialogWithManager(dialog, std::move(dialog_manager));
+}
+
+} // namespace constrained_window
diff --git a/chromium/components/constrained_window/show_modal_dialog_views.cc b/chromium/components/constrained_window/show_modal_dialog_views.cc
new file mode 100644
index 00000000000..78af596c001
--- /dev/null
+++ b/chromium/components/constrained_window/show_modal_dialog_views.cc
@@ -0,0 +1,27 @@
+// 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 <memory>
+
+#include "components/constrained_window/constrained_window_views.h"
+#include "components/constrained_window/native_web_contents_modal_dialog_manager_views.h"
+#include "components/web_modal/single_web_contents_dialog_manager.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace constrained_window {
+
+void ShowModalDialog(gfx::NativeWindow dialog,
+ content::WebContents* web_contents) {
+ web_modal::WebContentsModalDialogManager* manager =
+ web_modal::WebContentsModalDialogManager::FromWebContents(web_contents);
+ DCHECK(manager);
+ std::unique_ptr<web_modal::SingleWebContentsDialogManager> dialog_manager(
+ new constrained_window::NativeWebContentsModalDialogManagerViews(
+ dialog, manager));
+ manager->ShowDialogWithManager(dialog, std::move(dialog_manager));
+}
+
+} // namespace constrained_window
diff --git a/chromium/components/constrained_window/test_create_native_web_modal_manager_cocoa.cc b/chromium/components/constrained_window/test_create_native_web_modal_manager_cocoa.cc
new file mode 100644
index 00000000000..931dfe45c39
--- /dev/null
+++ b/chromium/components/constrained_window/test_create_native_web_modal_manager_cocoa.cc
@@ -0,0 +1,16 @@
+// 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 "components/web_modal/web_contents_modal_dialog_manager.h"
+
+namespace web_modal {
+
+SingleWebContentsDialogManager*
+WebContentsModalDialogManager::CreateNativeWebModalManager(
+ gfx::NativeWindow dialog,
+ web_modal::SingleWebContentsDialogManagerDelegate* delegate) {
+ return nullptr;
+}
+
+} // namespace web_modal
diff --git a/chromium/components/content_settings.gypi b/chromium/components/content_settings.gypi
deleted file mode 100644
index 243fcce8226..00000000000
--- a/chromium/components/content_settings.gypi
+++ /dev/null
@@ -1,148 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/content_settings/core/browser
- 'target_name': 'content_settings_core_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- 'content_settings_core_common',
- 'pref_registry',
- 'prefs/prefs.gyp:prefs',
- 'url_formatter/url_formatter.gyp:url_formatter',
- ],
- 'variables': { 'enable_wexit_time_destructors': 1, },
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'content_settings/core/browser/content_settings_binary_value_map.cc',
- 'content_settings/core/browser/content_settings_binary_value_map.h',
- 'content_settings/core/browser/content_settings_client.h',
- 'content_settings/core/browser/content_settings_default_provider.cc',
- 'content_settings/core/browser/content_settings_default_provider.h',
- 'content_settings/core/browser/content_settings_details.cc',
- 'content_settings/core/browser/content_settings_details.h',
- 'content_settings/core/browser/content_settings_info.cc',
- 'content_settings/core/browser/content_settings_info.h',
- 'content_settings/core/browser/content_settings_observable_provider.cc',
- 'content_settings/core/browser/content_settings_observable_provider.h',
- 'content_settings/core/browser/content_settings_observer.h',
- 'content_settings/core/browser/content_settings_origin_identifier_value_map.cc',
- 'content_settings/core/browser/content_settings_origin_identifier_value_map.h',
- 'content_settings/core/browser/content_settings_policy_provider.cc',
- 'content_settings/core/browser/content_settings_policy_provider.h',
- 'content_settings/core/browser/content_settings_pref.cc',
- 'content_settings/core/browser/content_settings_pref.h',
- 'content_settings/core/browser/content_settings_pref_provider.cc',
- 'content_settings/core/browser/content_settings_pref_provider.h',
- 'content_settings/core/browser/content_settings_provider.h',
- 'content_settings/core/browser/content_settings_registry.cc',
- 'content_settings/core/browser/content_settings_registry.h',
- 'content_settings/core/browser/content_settings_rule.cc',
- 'content_settings/core/browser/content_settings_rule.h',
- 'content_settings/core/browser/content_settings_usages_state.cc',
- 'content_settings/core/browser/content_settings_usages_state.h',
- 'content_settings/core/browser/content_settings_utils.cc',
- 'content_settings/core/browser/content_settings_utils.h',
- 'content_settings/core/browser/cookie_settings.cc',
- 'content_settings/core/browser/cookie_settings.h',
- 'content_settings/core/browser/host_content_settings_map.cc',
- 'content_settings/core/browser/host_content_settings_map.h',
- 'content_settings/core/browser/local_shared_objects_counter.h',
- 'content_settings/core/browser/website_settings_info.cc',
- 'content_settings/core/browser/website_settings_info.h',
- 'content_settings/core/browser/website_settings_registry.cc',
- 'content_settings/core/browser/website_settings_registry.h',
- ],
- 'conditions': [
- ['enable_plugins == 1', {
- 'sources': [
- 'content_settings/core/browser/plugins_field_trial.cc',
- 'content_settings/core/browser/plugins_field_trial.h',
- ],
- }],
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- # GN version: //components/content_settings/core/common
- 'target_name': 'content_settings_core_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'variables': { 'enable_wexit_time_destructors': 1, },
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'content_settings/core/common/content_settings.cc',
- 'content_settings/core/common/content_settings.h',
- 'content_settings/core/common/content_settings_pattern.cc',
- 'content_settings/core/common/content_settings_pattern.h',
- 'content_settings/core/common/content_settings_pattern_parser.cc',
- 'content_settings/core/common/content_settings_pattern_parser.h',
- 'content_settings/core/common/content_settings_types.h',
- 'content_settings/core/common/pref_names.cc',
- 'content_settings/core/common/pref_names.h',
- ],
- },
- {
- # GN version: //components/content_settings/core/test:test_support
- 'target_name': 'content_settings_core_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'content_settings_core_browser',
- 'content_settings_core_common',
- '../base/base.gyp:base',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'content_settings/core/test/content_settings_test_utils.cc',
- 'content_settings/core/test/content_settings_test_utils.h',
- ],
- },
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'targets': [
- {
- # GN version: //components/content_settings/content/common
- 'target_name': 'content_settings_content_common',
- 'type': 'static_library',
- 'dependencies': [
- 'content_settings_core_common',
- '../base/base.gyp:base',
- '../ipc/ipc.gyp:ipc',
- '../url/url.gyp:url_lib',
- '../url/ipc/url_ipc.gyp:url_ipc',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'content_settings/content/common/content_settings_message_generator.cc',
- 'content_settings/content/common/content_settings_message_generator.h',
- 'content_settings/content/common/content_settings_messages.h',
- ],
- },
- ],
- }]
- ],
-}
diff --git a/chromium/components/content_settings/DEPS b/chromium/components/content_settings/DEPS
index 3a4400fde88..eac076192dc 100644
--- a/chromium/components/content_settings/DEPS
+++ b/chromium/components/content_settings/DEPS
@@ -1,6 +1,3 @@
include_rules = [
- # Content settings is a layered component; subdirectories must explicitly
- # introduce the ability to use the content layer as appropriate.
- "-components/content_settings/content",
"+components/prefs",
]
diff --git a/chromium/components/content_settings/content/DEPS b/chromium/components/content_settings/content/DEPS
deleted file mode 100644
index 09645ae41e7..00000000000
--- a/chromium/components/content_settings/content/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+components/content_settings/content/common",
- "+ipc",
-]
diff --git a/chromium/components/content_settings/content/common/BUILD.gn b/chromium/components/content_settings/content/common/BUILD.gn
deleted file mode 100644
index 5da2f62693b..00000000000
--- a/chromium/components/content_settings/content/common/BUILD.gn
+++ /dev/null
@@ -1,19 +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.
-
-source_set("common") {
- sources = [
- "content_settings_message_generator.cc",
- "content_settings_message_generator.h",
- "content_settings_messages.h",
- ]
-
- deps = [
- "//base",
- "//components/content_settings/core/common",
- "//content/public/common",
- "//ipc",
- "//url",
- ]
-}
diff --git a/chromium/components/content_settings/content/common/DEPS b/chromium/components/content_settings/content/common/DEPS
deleted file mode 100644
index d5923ee96cb..00000000000
--- a/chromium/components/content_settings/content/common/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+content/public/common",
-]
diff --git a/chromium/components/content_settings/content/common/content_settings_message_generator.cc b/chromium/components/content_settings/content/common/content_settings_message_generator.cc
deleted file mode 100644
index 0156c49723b..00000000000
--- a/chromium/components/content_settings/content/common/content_settings_message_generator.cc
+++ /dev/null
@@ -1,39 +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.
-
-// Get basic type definitions.
-#define IPC_MESSAGE_IMPL
-#include "components/content_settings/content/common/content_settings_message_generator.h"
-
-// Generate constructors.
-#include "ipc/struct_constructor_macros.h"
-#include "components/content_settings/content/common/content_settings_message_generator.h"
-
-// Generate destructors.
-#include "ipc/struct_destructor_macros.h"
-#include "components/content_settings/content/common/content_settings_message_generator.h"
-
-// Generate param traits size methods.
-#include "ipc/param_traits_size_macros.h"
-namespace IPC {
-#include "components/content_settings/content/common/content_settings_message_generator.h"
-} // namespace IPC
-
-// Generate param traits write methods.
-#include "ipc/param_traits_write_macros.h"
-namespace IPC {
-#include "components/content_settings/content/common/content_settings_message_generator.h"
-} // namespace IPC
-
-// Generate param traits read methods.
-#include "ipc/param_traits_read_macros.h"
-namespace IPC {
-#include "components/content_settings/content/common/content_settings_message_generator.h"
-} // namespace IPC
-
-// Generate param traits log methods.
-#include "ipc/param_traits_log_macros.h"
-namespace IPC {
-#include "components/content_settings/content/common/content_settings_message_generator.h"
-} // namespace IPC
diff --git a/chromium/components/content_settings/content/common/content_settings_message_generator.h b/chromium/components/content_settings/content/common/content_settings_message_generator.h
deleted file mode 100644
index 322fbaecaa9..00000000000
--- a/chromium/components/content_settings/content/common/content_settings_message_generator.h
+++ /dev/null
@@ -1,7 +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.
-
-// Multiply-included file, hence no include guard.
-
-#include "components/content_settings/content/common/content_settings_messages.h"
diff --git a/chromium/components/content_settings/content/common/content_settings_messages.h b/chromium/components/content_settings/content/common/content_settings_messages.h
deleted file mode 100644
index 6d969472da6..00000000000
--- a/chromium/components/content_settings/content/common/content_settings_messages.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Multiply-included file, no traditional include guard.
-#include "base/strings/string16.h"
-#include "components/content_settings/core/common/content_settings_types.h"
-#include "ipc/ipc_message_macros.h"
-#include "url/gurl.h"
-#include "url/ipc/url_param_traits.h"
-
-#define IPC_MESSAGE_START ContentSettingsMsgStart
-
-IPC_ENUM_TRAITS_MAX_VALUE(ContentSettingsType,
- CONTENT_SETTINGS_NUM_TYPES_DO_NOT_USE - 1)
-
-//-----------------------------------------------------------------------------
-// These are messages sent from the browser to the renderer process.
-
-// Sent in response to FrameHostMsg_DidBlockDisplayingInsecureContent.
-IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetAllowDisplayingInsecureContent,
- bool /* allowed */)
-
-// Sent in response to FrameHostMsg_DidBlockRunningInsecureContent.
-IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetAllowRunningInsecureContent,
- bool /* allowed */)
-
-IPC_MESSAGE_ROUTED0(ChromeViewMsg_ReloadFrame)
-
-// Tells the renderer whether or not a file system access has been allowed.
-IPC_MESSAGE_ROUTED2(ChromeViewMsg_RequestFileSystemAccessAsyncResponse,
- int /* request_id */,
- bool /* allowed */)
-
-// Tells the render frame to load all blocked plugins with the given identifier.
-IPC_MESSAGE_ROUTED1(ChromeViewMsg_LoadBlockedPlugins,
- std::string /* identifier */)
-
-// JavaScript related messages -----------------------------------------------
-
-// Tells the frame it is displaying an interstitial page.
-IPC_MESSAGE_ROUTED0(ChromeViewMsg_SetAsInterstitial)
-
-//-----------------------------------------------------------------------------
-// These are messages sent from the renderer to the browser process.
-
-// Tells the browser that content in the current page was blocked due to the
-// user's content settings.
-IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_ContentBlocked,
- ContentSettingsType /* type of blocked content */,
- base::string16 /* details on blocked content */)
-
-// Sent by the renderer process to check whether access to web databases is
-// granted by content settings.
-IPC_SYNC_MESSAGE_CONTROL5_1(ChromeViewHostMsg_AllowDatabase,
- int /* render_frame_id */,
- GURL /* origin_url */,
- GURL /* top origin url */,
- base::string16 /* database name */,
- base::string16 /* database display name */,
- bool /* allowed */)
-
-// Sent by the renderer process to check whether access to DOM Storage is
-// granted by content settings.
-IPC_SYNC_MESSAGE_CONTROL4_1(ChromeViewHostMsg_AllowDOMStorage,
- int /* render_frame_id */,
- GURL /* origin_url */,
- GURL /* top origin url */,
- bool /* if true local storage, otherwise session */,
- bool /* allowed */)
-
-// Sent by the renderer process when a keygen element is rendered onto the
-// current page.
-IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_DidUseKeygen,
- GURL /* origin_url */)
-
-// Sent by the renderer process to check whether access to FileSystem is
-// granted by content settings.
-IPC_MESSAGE_CONTROL4(ChromeViewHostMsg_RequestFileSystemAccessAsync,
- int /* render_frame_id */,
- int /* request_id */,
- GURL /* origin_url */,
- GURL /* top origin url */)
-
-// Sent by the renderer process to check whether access to Indexed DBis
-// granted by content settings.
-IPC_SYNC_MESSAGE_CONTROL4_1(ChromeViewHostMsg_AllowIndexedDB,
- int /* render_frame_id */,
- GURL /* origin_url */,
- GURL /* top origin url */,
- base::string16 /* database name */,
- bool /* allowed */)
-
-// Sent when the renderer was prevented from displaying insecure content in
-// a secure page by a security policy. The page may appear incomplete.
-IPC_MESSAGE_ROUTED0(ChromeViewHostMsg_DidBlockDisplayingInsecureContent)
diff --git a/chromium/components/content_settings/core/browser/BUILD.gn b/chromium/components/content_settings/core/browser/BUILD.gn
index 12e50f4f42a..536cd3d7288 100644
--- a/chromium/components/content_settings/core/browser/BUILD.gn
+++ b/chromium/components/content_settings/core/browser/BUILD.gn
@@ -4,11 +4,10 @@
import("//build/config/features.gni")
-source_set("browser") {
+static_library("browser") {
sources = [
"content_settings_binary_value_map.cc",
"content_settings_binary_value_map.h",
- "content_settings_client.h",
"content_settings_default_provider.cc",
"content_settings_default_provider.h",
"content_settings_details.cc",
@@ -39,20 +38,12 @@ source_set("browser") {
"cookie_settings.h",
"host_content_settings_map.cc",
"host_content_settings_map.h",
- "local_shared_objects_counter.h",
"website_settings_info.cc",
"website_settings_info.h",
"website_settings_registry.cc",
"website_settings_registry.h",
]
- if (enable_plugins) {
- sources += [
- "plugins_field_trial.cc",
- "plugins_field_trial.h",
- ]
- }
-
deps = [
"//base",
"//components/content_settings/core/common",
diff --git a/chromium/components/content_settings/core/browser/content_settings_binary_value_map.cc b/chromium/components/content_settings/core/browser/content_settings_binary_value_map.cc
index cd030bd65dd..ddfb7326c12 100644
--- a/chromium/components/content_settings/core/browser/content_settings_binary_value_map.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_binary_value_map.cc
@@ -16,14 +16,13 @@ namespace {
class RuleIteratorBinary : public RuleIterator {
public:
- explicit RuleIteratorBinary(bool is_enabled,
- std::unique_ptr<base::AutoLock> auto_lock)
+ RuleIteratorBinary(bool is_enabled, std::unique_ptr<base::AutoLock> auto_lock)
: is_done_(is_enabled), auto_lock_(std::move(auto_lock)) {}
bool HasNext() const override { return !is_done_; }
Rule Next() override {
- DCHECK(!is_done_);
+ DCHECK(HasNext());
is_done_ = true;
return Rule(ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
@@ -45,11 +44,10 @@ std::unique_ptr<RuleIterator> BinaryValueMap::GetRuleIterator(
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
std::unique_ptr<base::AutoLock> auto_lock) const {
- if (resource_identifier.empty()) {
- return std::unique_ptr<RuleIterator>(new RuleIteratorBinary(
- IsContentSettingEnabled(content_type), std::move(auto_lock)));
- }
- return std::unique_ptr<RuleIterator>(new EmptyRuleIterator());
+ if (!resource_identifier.empty())
+ return nullptr;
+ return std::unique_ptr<RuleIterator>(new RuleIteratorBinary(
+ IsContentSettingEnabled(content_type), std::move(auto_lock)));
}
void BinaryValueMap::SetContentSettingDisabled(ContentSettingsType content_type,
@@ -60,9 +58,7 @@ void BinaryValueMap::SetContentSettingDisabled(ContentSettingsType content_type,
bool BinaryValueMap::IsContentSettingEnabled(
ContentSettingsType content_type) const {
auto it = is_enabled_.find(content_type);
- if (it == is_enabled_.end())
- return true;
- return it->second;
+ return it == is_enabled_.end() || it->second;
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/content_settings_binary_value_map.h b/chromium/components/content_settings/core/browser/content_settings_binary_value_map.h
index 2fba9126371..dbce8982bc1 100644
--- a/chromium/components/content_settings/core/browser/content_settings_binary_value_map.h
+++ b/chromium/components/content_settings/core/browser/content_settings_binary_value_map.h
@@ -26,6 +26,7 @@ class BinaryValueMap {
BinaryValueMap();
~BinaryValueMap();
+ // Returns nullptr to indicate the RuleIterator is empty.
std::unique_ptr<RuleIterator> GetRuleIterator(
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
diff --git a/chromium/components/content_settings/core/browser/content_settings_client.h b/chromium/components/content_settings/core/browser/content_settings_client.h
deleted file mode 100644
index 2ba347c6d45..00000000000
--- a/chromium/components/content_settings/core/browser/content_settings_client.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_CLIENT_H_
-#define COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_CLIENT_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "net/cookies/canonical_cookie.h"
-
-class GURL;
-class LocalSharedObjectsCounter;
-
-namespace net {
-class CookieOptions;
-}
-
-namespace content_settings {
-
-// An abstraction of operations that depend on the embedder (e.g. Chrome).
-class ContentSettingsClient {
- public:
- enum AccessType { BLOCKED, ALLOWED };
-
- ContentSettingsClient() {}
- virtual ~ContentSettingsClient() {}
-
- // Methods to notify the client about access to local shared objects.
- virtual void OnCookiesRead(const GURL& url,
- const GURL& first_party_url,
- const net::CookieList& cookie_list,
- bool blocked_by_policy) = 0;
-
- virtual void OnCookieChanged(const GURL& url,
- const GURL& first_party_url,
- const std::string& cookie_line,
- const net::CookieOptions& options,
- bool blocked_by_policy) = 0;
-
- virtual void OnFileSystemAccessed(const GURL& url,
- bool blocked_by_policy) = 0;
-
- virtual void OnIndexedDBAccessed(const GURL& url,
- const base::string16& description,
- bool blocked_by_policy) = 0;
-
- virtual void OnLocalStorageAccessed(const GURL& url,
- bool local,
- bool blocked_by_policy) = 0;
-
- virtual void OnWebDatabaseAccessed(const GURL& url,
- const base::string16& name,
- const base::string16& display_name,
- bool blocked_by_policy) = 0;
-
- // Returns the |LocalSharedObjectsCounter| instances corresponding to all
- // allowed (or blocked, depending on |type|) local shared objects.
- virtual const LocalSharedObjectsCounter& local_shared_objects(
- AccessType type) const = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ContentSettingsClient);
-};
-
-} // namespace content_settings
-
-#endif // COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_CLIENT_H_
diff --git a/chromium/components/content_settings/core/browser/content_settings_default_provider.cc b/chromium/components/content_settings/core/browser/content_settings_default_provider.cc
index 1d4af86fdca..f1ca103e3b6 100644
--- a/chromium/components/content_settings/core/browser/content_settings_default_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_default_provider.cc
@@ -9,7 +9,6 @@
#include "base/auto_reset.h"
#include "base/bind.h"
-#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "components/content_settings/core/browser/content_settings_rule.h"
@@ -29,15 +28,6 @@ namespace content_settings {
namespace {
-// Obsolete prefs to be removed from the pref file.
-// TODO(msramek): Remove this cleanup code after two releases (i.e. in M50).
-const char kObsoleteMetroSwitchToDesktopSetting[] =
- "profile.default_content_setting_values.metro_switch_to_desktop";
-
-// TODO(msramek): Remove this cleanup code after two releases (i.e. in M51).
-const char kObsoleteMediaStreamSetting[] =
- "profile.default_content_setting_values.media_stream";
-
ContentSetting GetDefaultValue(const WebsiteSettingsInfo* info) {
const base::Value* initial_default = info->initial_default_value();
if (!initial_default)
@@ -65,10 +55,10 @@ class DefaultRuleIterator : public RuleIterator {
value_.reset(value->DeepCopy());
}
- bool HasNext() const override { return value_.get() != NULL; }
+ bool HasNext() const override { return !!value_; }
Rule Next() override {
- DCHECK(value_.get());
+ DCHECK(HasNext());
return Rule(ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
value_.release());
@@ -91,17 +81,6 @@ void DefaultProvider::RegisterProfilePrefs(
GetDefaultValue(info),
info->GetPrefRegistrationFlags());
}
-
- // Obsolete prefs -------------------------------------------------------
-
- // The removed content settings type METRO_SWITCH_TO_DESKTOP.
- registry->RegisterIntegerPref(
- kObsoleteMetroSwitchToDesktopSetting,
- 0,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-
- // The removed content settings type MEDIASTREAM.
- registry->RegisterIntegerPref(kObsoleteMediaStreamSetting, 0);
}
DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito)
@@ -110,9 +89,6 @@ DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito)
updating_preferences_(false) {
DCHECK(prefs_);
- // Remove the obsolete preferences from the pref file.
- DiscardObsoletePreferences();
-
// Read global defaults.
ReadDefaultSettings();
@@ -178,11 +154,6 @@ DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito)
GetPrefName(CONTENT_SETTINGS_TYPE_MIDI_SYSEX))),
CONTENT_SETTING_NUM_SETTINGS);
UMA_HISTOGRAM_ENUMERATION(
- "ContentSettings.DefaultPushMessagingSetting",
- IntToContentSetting(prefs_->GetInteger(
- GetPrefName(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING))),
- CONTENT_SETTING_NUM_SETTINGS);
- UMA_HISTOGRAM_ENUMERATION(
"ContentSettings.DefaultKeygenSetting",
IntToContentSetting(prefs_->GetInteger(
GetPrefName(CONTENT_SETTINGS_TYPE_KEYGEN))),
@@ -261,17 +232,18 @@ std::unique_ptr<RuleIterator> DefaultProvider::GetRuleIterator(
bool incognito) const {
// The default provider never has incognito-specific settings.
if (incognito)
- return std::unique_ptr<RuleIterator>(new EmptyRuleIterator());
+ return nullptr;
base::AutoLock lock(lock_);
- if (resource_identifier.empty()) {
- auto it(default_settings_.find(content_type));
- if (it != default_settings_.end())
- return std::unique_ptr<RuleIterator>(
- new DefaultRuleIterator(it->second.get()));
+ if (!resource_identifier.empty())
+ return nullptr;
+
+ auto it = default_settings_.find(content_type);
+ if (it == default_settings_.end()) {
NOTREACHED();
+ return nullptr;
}
- return std::unique_ptr<RuleIterator>(new EmptyRuleIterator());
+ return base::MakeUnique<DefaultRuleIterator>(it->second.get());
}
void DefaultProvider::ClearAllContentSettingsRules(
@@ -300,8 +272,8 @@ void DefaultProvider::ReadDefaultSettings() {
bool DefaultProvider::IsValueEmptyOrDefault(ContentSettingsType content_type,
base::Value* value) {
- if (!value) return true;
- return ValueToContentSetting(value) == GetDefaultValue(content_type);
+ return !value ||
+ ValueToContentSetting(value) == GetDefaultValue(content_type);
}
void DefaultProvider::ChangeSetting(ContentSettingsType content_type,
@@ -372,9 +344,4 @@ std::unique_ptr<base::Value> DefaultProvider::ReadFromPref(
return ContentSettingToValue(IntToContentSetting(int_value));
}
-void DefaultProvider::DiscardObsoletePreferences() {
- prefs_->ClearPref(kObsoleteMetroSwitchToDesktopSetting);
- prefs_->ClearPref(kObsoleteMediaStreamSetting);
-}
-
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/content_settings_default_provider.h b/chromium/components/content_settings/core/browser/content_settings_default_provider.h
index 5691a188ce4..f4f234695ca 100644
--- a/chromium/components/content_settings/core/browser/content_settings_default_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_default_provider.h
@@ -72,16 +72,13 @@ class DefaultProvider : public ObservableProvider {
// Called on prefs change.
void OnPreferenceChanged(const std::string& pref_name);
- // Clean up the obsolete preferences from the user's profile.
- void DiscardObsoletePreferences();
-
// Copies of the pref data, so that we can read it on the IO thread.
std::map<ContentSettingsType, std::unique_ptr<base::Value>> default_settings_;
PrefService* prefs_;
// Whether this settings map is for an Incognito session.
- bool is_incognito_;
+ const bool is_incognito_;
// Used around accesses to the |default_settings_| object to guarantee
// thread safety.
diff --git a/chromium/components/content_settings/core/browser/content_settings_info.cc b/chromium/components/content_settings/core/browser/content_settings_info.cc
index 62e5c685c4f..c111944e286 100644
--- a/chromium/components/content_settings/core/browser/content_settings_info.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_info.cc
@@ -21,7 +21,7 @@ ContentSettingsInfo::ContentSettingsInfo(
ContentSettingsInfo::~ContentSettingsInfo() {}
bool ContentSettingsInfo::IsSettingValid(ContentSetting setting) const {
- return ContainsKey(valid_settings_, setting);
+ return base::ContainsKey(valid_settings_, setting);
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc b/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
index 42bc2512b5f..3f6133b67a8 100644
--- a/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
@@ -37,7 +37,7 @@ class RuleIteratorImpl : public RuleIterator {
bool HasNext() const override { return (current_rule_ != rule_end_); }
Rule Next() override {
- DCHECK(current_rule_ != rule_end_);
+ DCHECK(HasNext());
DCHECK(current_rule_->second.get());
Rule to_return(current_rule_->first.primary_pattern,
current_rule_->first.secondary_pattern,
@@ -97,16 +97,15 @@ std::unique_ptr<RuleIterator> OriginIdentifierValueMap::GetRuleIterator(
auto_lock.reset(new base::AutoLock(*lock));
EntryMap::const_iterator it = entries_.find(key);
if (it == entries_.end())
- return std::unique_ptr<RuleIterator>(new EmptyRuleIterator());
+ return nullptr;
return std::unique_ptr<RuleIterator>(new RuleIteratorImpl(
it->second.begin(), it->second.end(), auto_lock.release()));
}
size_t OriginIdentifierValueMap::size() const {
size_t size = 0;
- EntryMap::const_iterator it;
- for (it = entries_.begin(); it != entries_.end(); ++it)
- size += it->second.size();
+ for (const auto& entry : entries_)
+ size += entry.second.size();
return size;
}
@@ -122,19 +121,18 @@ base::Value* OriginIdentifierValueMap::GetValue(
EntryMapKey key(content_type, resource_identifier);
EntryMap::const_iterator it = entries_.find(key);
if (it == entries_.end())
- return NULL;
+ return nullptr;
// Iterate the entries in until a match is found. Since the rules are stored
// in the order of decreasing precedence, the most specific match is found
// first.
- Rules::const_iterator entry;
- for (entry = it->second.begin(); entry != it->second.end(); ++entry) {
- if (entry->first.primary_pattern.Matches(primary_url) &&
- entry->first.secondary_pattern.Matches(secondary_url)) {
- return entry->second.get();
+ for (const auto& entry : it->second) {
+ if (entry.first.primary_pattern.Matches(primary_url) &&
+ entry.first.secondary_pattern.Matches(secondary_url)) {
+ return entry.second.get();
}
}
- return NULL;
+ return nullptr;
}
void OriginIdentifierValueMap::SetValue(
diff --git a/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h b/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h
index 62c984c59de..1ac2fe56bed 100644
--- a/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h
+++ b/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h
@@ -74,6 +74,7 @@ class OriginIdentifierValueMap {
// |OriginIdentifierValueMap| (also |GetRuleIterator|) before the iterator
// has been destroyed. If |lock| is non-NULL, the returned |RuleIterator|
// locks it and releases it when it is destroyed.
+ // Returns nullptr to indicate the RuleIterator is empty.
std::unique_ptr<RuleIterator> GetRuleIterator(
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
diff --git a/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc b/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
index 3e1245b9ad4..78a12a27a91 100644
--- a/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
@@ -9,6 +9,7 @@
#include <string>
#include "base/bind.h"
+#include "base/feature_list.h"
#include "base/json/json_reader.h"
#include "base/macros.h"
#include "base/values.h"
@@ -354,8 +355,14 @@ void PolicyProvider::UpdateManagedDefaultSetting(
DCHECK(!prefs_->HasPrefPath(entry.pref_name) ||
prefs_->IsManagedPreference(entry.pref_name));
base::AutoLock auto_lock(lock_);
-
int setting = prefs_->GetInteger(entry.pref_name);
+ // TODO(wfh): Remove once HDB is enabled by default.
+ if (entry.pref_name == prefs::kManagedDefaultPluginsSetting) {
+ static constexpr base::Feature kIgnoreDefaultPluginsSetting = {
+ "IgnoreDefaultPluginsSetting", base::FEATURE_DISABLED_BY_DEFAULT};
+ if (base::FeatureList::IsEnabled(kIgnoreDefaultPluginsSetting))
+ setting = CONTENT_SETTING_DEFAULT;
+ }
if (setting == CONTENT_SETTING_DEFAULT) {
value_map_.DeleteValue(ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref.h b/chromium/components/content_settings/core/browser/content_settings_pref.h
index 1a600d6c156..aa2ab178e3d 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref.h
+++ b/chromium/components/content_settings/core/browser/content_settings_pref.h
@@ -51,6 +51,7 @@ class ContentSettingsPref {
NotifyObserversCallback notify_callback);
~ContentSettingsPref();
+ // Returns nullptr to indicate the RuleIterator is empty.
std::unique_ptr<RuleIterator> GetRuleIterator(
const ResourceIdentifier& resource_identifier,
bool incognito) const;
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc b/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc
index c544e186aa2..8d451633e2c 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc
@@ -15,7 +15,6 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_split.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "components/content_settings/core/browser/content_settings_pref.h"
@@ -32,18 +31,6 @@
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
-namespace {
-
-// Obsolete prefs.
-// TODO(msramek): Remove the cleanup code after two releases (i.e. in M50).
-const char kObsoleteMetroSwitchToDesktopExceptions[] =
- "profile.content_settings.exceptions.metro_switch_to_desktop";
-
-const char kObsoleteMediaStreamExceptions[] =
- "profile.content_settings.exceptions.media_stream";
-
-} // namespace
-
namespace content_settings {
// ////////////////////////////////////////////////////////////////////////////
@@ -63,14 +50,6 @@ void PrefProvider::RegisterProfilePrefs(
registry->RegisterDictionaryPref(info->pref_name(),
info->GetPrefRegistrationFlags());
}
-
- // Obsolete prefs ----------------------------------------------------------
-
- registry->RegisterDictionaryPref(
- kObsoleteMetroSwitchToDesktopExceptions,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-
- registry->RegisterDictionaryPref(kObsoleteMediaStreamExceptions);
}
PrefProvider::PrefProvider(PrefService* prefs, bool incognito)
@@ -95,10 +74,10 @@ PrefProvider::PrefProvider(PrefService* prefs, bool incognito)
for (const WebsiteSettingsInfo* info : *website_settings) {
content_settings_prefs_.insert(std::make_pair(
info->type(),
- base::WrapUnique(new ContentSettingsPref(
+ base::MakeUnique<ContentSettingsPref>(
info->type(), prefs_, &pref_change_registrar_, info->pref_name(),
is_incognito_,
- base::Bind(&PrefProvider::Notify, base::Unretained(this))))));
+ base::Bind(&PrefProvider::Notify, base::Unretained(this)))));
}
if (!is_incognito_) {
@@ -109,8 +88,6 @@ PrefProvider::PrefProvider(PrefService* prefs, bool incognito)
UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfExceptions",
num_exceptions);
}
-
- DiscardObsoletePreferences();
}
PrefProvider::~PrefProvider() {
@@ -210,9 +187,4 @@ void PrefProvider::Notify(
resource_identifier);
}
-void PrefProvider::DiscardObsoletePreferences() {
- prefs_->ClearPref(kObsoleteMetroSwitchToDesktopExceptions);
- prefs_->ClearPref(kObsoleteMediaStreamExceptions);
-}
-
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref_provider.h b/chromium/components/content_settings/core/browser/content_settings_pref_provider.h
index fd7bb42635f..65be16d049f 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_pref_provider.h
@@ -80,16 +80,13 @@ class PrefProvider : public ObservableProvider {
ContentSettingsType content_type,
const std::string& resource_identifier);
- // Clean up the obsolete preferences from the user's profile.
- void DiscardObsoletePreferences();
-
// Weak; owned by the Profile and reset in ShutdownOnUIThread.
PrefService* prefs_;
// Can be set for testing.
std::unique_ptr<base::Clock> clock_;
- bool is_incognito_;
+ const bool is_incognito_;
PrefChangeRegistrar pref_change_registrar_;
diff --git a/chromium/components/content_settings/core/browser/content_settings_provider.h b/chromium/components/content_settings/core/browser/content_settings_provider.h
index 8c1852e5ece..057ed81ba7e 100644
--- a/chromium/components/content_settings/core/browser/content_settings_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_provider.h
@@ -32,6 +32,7 @@ class ProviderInterface {
// mode. It is not allowed to call other |ProviderInterface| functions
// (including |GetRuleIterator|) for the same provider until the
// |RuleIterator| is destroyed.
+ // Returns nullptr to indicate the RuleIterator is empty.
virtual std::unique_ptr<RuleIterator> GetRuleIterator(
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
diff --git a/chromium/components/content_settings/core/browser/content_settings_registry.cc b/chromium/components/content_settings/core/browser/content_settings_registry.cc
index 240243d1961..6f71249d2be 100644
--- a/chromium/components/content_settings/core/browser/content_settings_registry.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_registry.cc
@@ -132,7 +132,7 @@ void ContentSettingsRegistry::Init() {
WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
kExtensionScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP,
ContentSettingsInfo::INHERIT_IN_INCOGNITO);
@@ -141,7 +141,7 @@ void ContentSettingsRegistry::Init() {
WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
kExtensionScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
WebsiteSettingsRegistry::PLATFORM_ANDROID,
ContentSettingsInfo::INHERIT_IN_INCOGNITO);
@@ -153,7 +153,7 @@ void ContentSettingsRegistry::Init() {
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK,
CONTENT_SETTING_DETECT_IMPORTANT_CONTENT),
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP,
ContentSettingsInfo::INHERIT_IN_INCOGNITO);
@@ -162,7 +162,7 @@ void ContentSettingsRegistry::Init() {
WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
kExtensionScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::ALL_PLATFORMS,
ContentSettingsInfo::INHERIT_IN_INCOGNITO);
@@ -202,7 +202,7 @@ void ContentSettingsRegistry::Init() {
WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP,
ContentSettingsInfo::INHERIT_IN_INCOGNITO);
@@ -241,7 +241,7 @@ void ContentSettingsRegistry::Init() {
kExtensionScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
WebsiteSettingsRegistry::PLATFORM_ANDROID,
ContentSettingsInfo::INHERIT_IN_INCOGNITO);
@@ -255,16 +255,6 @@ void ContentSettingsRegistry::Init() {
WebsiteSettingsRegistry::PLATFORM_ANDROID,
ContentSettingsInfo::INHERIT_IN_INCOGNITO);
- Register(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, "push-messaging",
- CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
- ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
- CONTENT_SETTING_ASK),
- WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE,
- WebsiteSettingsRegistry::DESKTOP |
- WebsiteSettingsRegistry::PLATFORM_ANDROID,
- ContentSettingsInfo::INHERIT_IN_INCOGNITO_EXCEPT_ALLOW);
-
Register(CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
"protected-media-identifier", CONTENT_SETTING_ASK,
WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
@@ -316,14 +306,14 @@ void ContentSettingsRegistry::Init() {
Register(CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, "protocol-handler",
CONTENT_SETTING_DEFAULT, WebsiteSettingsInfo::UNSYNCABLE,
WhitelistedSchemes(), ValidSettings(),
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP,
ContentSettingsInfo::INHERIT_IN_INCOGNITO);
Register(CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, "mixed-script",
CONTENT_SETTING_DEFAULT, WebsiteSettingsInfo::UNSYNCABLE,
WhitelistedSchemes(), ValidSettings(),
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP,
ContentSettingsInfo::INHERIT_IN_INCOGNITO);
@@ -349,9 +339,9 @@ void ContentSettingsRegistry::Register(
ContentSettingsInfo::IncognitoBehavior incognito_behavior) {
// Ensure that nothing has been registered yet for the given type.
DCHECK(!website_settings_registry_->Get(type));
- DCHECK(incognito_behavior
- != ContentSettingsInfo::INHERIT_IN_INCOGNITO_EXCEPT_ALLOW
- || ContainsKey(valid_settings, CONTENT_SETTING_ASK))
+ DCHECK(incognito_behavior !=
+ ContentSettingsInfo::INHERIT_IN_INCOGNITO_EXCEPT_ALLOW ||
+ base::ContainsKey(valid_settings, CONTENT_SETTING_ASK))
<< "If INHERIT_IN_INCOGNITO_EXCEPT_ALLOW is set, ASK must be listed as a "
"valid setting.";
std::unique_ptr<base::Value> default_value(
@@ -367,10 +357,10 @@ void ContentSettingsRegistry::Register(
if (!website_settings_info)
return;
- DCHECK(!ContainsKey(content_settings_info_, type));
- content_settings_info_[type] = base::WrapUnique(
- new ContentSettingsInfo(website_settings_info, whitelisted_schemes,
- valid_settings, incognito_behavior));
+ DCHECK(!base::ContainsKey(content_settings_info_, type));
+ content_settings_info_[type] = base::MakeUnique<ContentSettingsInfo>(
+ website_settings_info, whitelisted_schemes, valid_settings,
+ incognito_behavior);
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc b/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc
index 7b8d66203ce..bf595c44e03 100644
--- a/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc
@@ -86,7 +86,7 @@ TEST_F(ContentSettingsRegistryTest, Properties) {
ASSERT_TRUE(
website_settings_info->initial_default_value()->GetAsInteger(&setting));
EXPECT_EQ(CONTENT_SETTING_ALLOW, setting);
-#if defined(OS_IOS)
+#if defined(OS_ANDROID) || defined(OS_IOS)
EXPECT_EQ(PrefRegistry::NO_REGISTRATION_FLAGS,
website_settings_info->GetPrefRegistrationFlags());
#else
diff --git a/chromium/components/content_settings/core/browser/content_settings_rule.cc b/chromium/components/content_settings/core/browser/content_settings_rule.cc
index 540231337ee..13d6a0aeed9 100644
--- a/chromium/components/content_settings/core/browser/content_settings_rule.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_rule.cc
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/logging.h"
#include "components/content_settings/core/browser/content_settings_rule.h"
+#include <utility>
+
+#include "base/logging.h"
+
namespace content_settings {
Rule::Rule() {}
@@ -25,17 +28,6 @@ Rule::~Rule() {}
RuleIterator::~RuleIterator() {}
-EmptyRuleIterator::~EmptyRuleIterator() {}
-
-bool EmptyRuleIterator::HasNext() const {
- return false;
-}
-
-Rule EmptyRuleIterator::Next() {
- NOTREACHED();
- return Rule();
-}
-
ConcatenationIterator::ConcatenationIterator(
std::vector<std::unique_ptr<RuleIterator>> iterators,
base::AutoLock* auto_lock)
@@ -52,7 +44,7 @@ ConcatenationIterator::ConcatenationIterator(
ConcatenationIterator::~ConcatenationIterator() {}
bool ConcatenationIterator::HasNext() const {
- return (!iterators_.empty());
+ return !iterators_.empty();
}
Rule ConcatenationIterator::Next() {
diff --git a/chromium/components/content_settings/core/browser/content_settings_rule.h b/chromium/components/content_settings/core/browser/content_settings_rule.h
index af7b450a8f9..8c24e60ccaf 100644
--- a/chromium/components/content_settings/core/browser/content_settings_rule.h
+++ b/chromium/components/content_settings/core/browser/content_settings_rule.h
@@ -39,13 +39,6 @@ class RuleIterator {
virtual Rule Next() = 0;
};
-class EmptyRuleIterator : public RuleIterator {
- public:
- ~EmptyRuleIterator() override;
- bool HasNext() const override;
- Rule Next() override;
-};
-
class ConcatenationIterator : public RuleIterator {
public:
// ConcatenationIterator takes ownership of the pointers in the |iterators|
diff --git a/chromium/components/content_settings/core/browser/content_settings_usages_state.cc b/chromium/components/content_settings/core/browser/content_settings_usages_state.cc
index b0486a90758..0619ff3ffc6 100644
--- a/chromium/components/content_settings/core/browser/content_settings_usages_state.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_usages_state.cc
@@ -10,12 +10,6 @@
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/url_formatter/url_formatter.h"
-ContentSettingsUsagesState::CommittedDetails::CommittedDetails()
- : current_url_valid(false) {
-}
-
-ContentSettingsUsagesState::CommittedDetails::~CommittedDetails() {}
-
ContentSettingsUsagesState::ContentSettingsUsagesState(
HostContentSettingsMap* host_content_settings_map,
ContentSettingsType type)
@@ -33,12 +27,10 @@ void ContentSettingsUsagesState::OnPermissionSet(
}
void ContentSettingsUsagesState::DidNavigate(const CommittedDetails& details) {
- if (details.current_url_valid)
- embedder_url_ = details.current_url;
+ embedder_url_ = details.current_url;
if (state_map_.empty())
return;
- if (!details.current_url_valid ||
- details.previous_url.GetOrigin() != details.current_url.GetOrigin()) {
+ if (details.previous_url.GetOrigin() != details.current_url.GetOrigin()) {
state_map_.clear();
return;
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_usages_state.h b/chromium/components/content_settings/core/browser/content_settings_usages_state.h
index 770483eed6d..f00e1702ee1 100644
--- a/chromium/components/content_settings/core/browser/content_settings_usages_state.h
+++ b/chromium/components/content_settings/core/browser/content_settings_usages_state.h
@@ -22,10 +22,6 @@ class ContentSettingsUsagesState {
public:
// Information about navigation.
struct CommittedDetails {
- CommittedDetails();
- ~CommittedDetails();
-
- bool current_url_valid;
GURL current_url;
GURL previous_url;
};
diff --git a/chromium/components/content_settings/core/browser/content_settings_utils.cc b/chromium/components/content_settings/core/browser/content_settings_utils.cc
index c58163250c1..ed0a256f0ae 100644
--- a/chromium/components/content_settings/core/browser/content_settings_utils.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_utils.cc
@@ -128,7 +128,7 @@ std::unique_ptr<base::Value> ContentSettingToValue(ContentSetting setting) {
setting >= CONTENT_SETTING_NUM_SETTINGS) {
return nullptr;
}
- return base::WrapUnique(new base::FundamentalValue(setting));
+ return base::MakeUnique<base::FundamentalValue>(setting);
}
void GetRendererContentSettingRules(const HostContentSettingsMap* map,
diff --git a/chromium/components/content_settings/core/browser/host_content_settings_map.cc b/chromium/components/content_settings/core/browser/host_content_settings_map.cc
index f5a47a8b15b..0e3f49fea1b 100644
--- a/chromium/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/chromium/components/content_settings/core/browser/host_content_settings_map.cc
@@ -11,7 +11,7 @@
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -58,6 +58,23 @@ const ProviderNamesSourceMapEntry kProviderNamesSourceMap[] = {
{"default", content_settings::SETTING_SOURCE_USER},
};
+// Enum describing the status of domain to origin migration of content settings.
+// Migration will be done twice: once upon construction of the
+// HostContentSettingsMap (before syncing any content settings) and once after
+// sync has finished. We always migrate before sync to ensure that settings will
+// get migrated even if a user doesn't have sync enabled. We migrate after sync
+// to ensure that any sync'd settings will be migrated. Once these events have
+// occurred, we won't perform migration again.
+enum DomainToOriginMigrationStatus {
+ // Haven't been migrated at all.
+ NOT_MIGRATED,
+ // Have done migration in the constructor of HostContentSettingsMap.
+ MIGRATED_BEFORE_SYNC,
+ // Have done migration both in HostContentSettingsMap construction and and
+ // after sync is finished. No migration will happen after this point.
+ MIGRATED_AFTER_SYNC,
+};
+
static_assert(
arraysize(kProviderNamesSourceMap) ==
HostContentSettingsMap::NUM_PROVIDER_TYPES,
@@ -118,11 +135,11 @@ content_settings::PatternPair GetPatternsFromScopingType(
content_settings::PatternPair patterns;
switch (scoping_type) {
- case WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE:
case WebsiteSettingsInfo::REQUESTING_DOMAIN_ONLY_SCOPE:
patterns.first = ContentSettingsPattern::FromURL(primary_url);
patterns.second = ContentSettingsPattern::Wildcard();
break;
+ case WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE:
case WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE:
patterns.first = ContentSettingsPattern::FromURLNoWildcard(primary_url);
patterns.second = ContentSettingsPattern::Wildcard();
@@ -147,7 +164,8 @@ HostContentSettingsMap::HostContentSettingsMap(PrefService* prefs,
used_from_thread_id_(base::PlatformThread::CurrentId()),
#endif
prefs_(prefs),
- is_off_the_record_(is_incognito_profile || is_guest_profile) {
+ is_off_the_record_(is_incognito_profile || is_guest_profile),
+ weak_ptr_factory_(this) {
DCHECK(!(is_incognito_profile && is_guest_profile));
content_settings::PolicyProvider* policy_provider =
@@ -172,7 +190,7 @@ HostContentSettingsMap::HostContentSettingsMap(PrefService* prefs,
content_settings_providers_[DEFAULT_PROVIDER] = default_provider;
MigrateKeygenSettings();
-
+ MigrateDomainScopedSettings(false);
RecordExceptionMetrics();
}
@@ -183,6 +201,8 @@ void HostContentSettingsMap::RegisterProfilePrefs(
content_settings::ContentSettingsRegistry::GetInstance();
registry->RegisterIntegerPref(prefs::kContentSettingsWindowLastTabIndex, 0);
+ registry->RegisterIntegerPref(prefs::kDomainToOriginMigrationStatus,
+ NOT_MIGRATED);
// Register the prefs for the content settings providers.
content_settings::DefaultProvider::RegisterProfilePrefs(registry);
@@ -214,12 +234,14 @@ ContentSetting HostContentSettingsMap::GetDefaultContentSettingFromProvider(
std::unique_ptr<content_settings::RuleIterator> rule_iterator(
provider->GetRuleIterator(content_type, std::string(), false));
- ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard();
- while (rule_iterator->HasNext()) {
- content_settings::Rule rule = rule_iterator->Next();
- if (rule.primary_pattern == wildcard &&
- rule.secondary_pattern == wildcard) {
- return content_settings::ValueToContentSetting(rule.value.get());
+ if (rule_iterator) {
+ ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard();
+ while (rule_iterator->HasNext()) {
+ content_settings::Rule rule = rule_iterator->Next();
+ if (rule.primary_pattern == wildcard &&
+ rule.secondary_pattern == wildcard) {
+ return content_settings::ValueToContentSetting(rule.value.get());
+ }
}
}
return CONTENT_SETTING_DEFAULT;
@@ -497,6 +519,93 @@ void HostContentSettingsMap::MigrateKeygenSettings() {
}
}
+void HostContentSettingsMap::MigrateDomainScopedSettings(bool after_sync) {
+ DomainToOriginMigrationStatus status =
+ static_cast<DomainToOriginMigrationStatus>(
+ prefs_->GetInteger(prefs::kDomainToOriginMigrationStatus));
+ if (status == MIGRATED_AFTER_SYNC)
+ return;
+ if (status == MIGRATED_BEFORE_SYNC && !after_sync)
+ return;
+ DCHECK(status != NOT_MIGRATED || !after_sync);
+
+ const ContentSettingsType kDomainScopedTypes[] = {
+ CONTENT_SETTINGS_TYPE_IMAGES,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT,
+ CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+ CONTENT_SETTINGS_TYPE_POPUPS};
+ for (const ContentSettingsType& type : kDomainScopedTypes) {
+ if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(type))
+ continue;
+ ContentSettingsForOneType settings;
+ GetSettingsForOneType(type, std::string(), &settings);
+
+ for (const ContentSettingPatternSource& setting_entry : settings) {
+ // Migrate user preference settings only.
+ if (setting_entry.source != "preference")
+ continue;
+ // Migrate ALLOW settings only.
+ if (setting_entry.setting != CONTENT_SETTING_ALLOW)
+ continue;
+ // Skip default settings.
+ if (setting_entry.primary_pattern == ContentSettingsPattern::Wildcard())
+ continue;
+
+ if (setting_entry.secondary_pattern !=
+ ContentSettingsPattern::Wildcard()) {
+ NOTREACHED();
+ continue;
+ }
+
+ ContentSettingsPattern origin_pattern;
+ if (!ContentSettingsPattern::MigrateFromDomainToOrigin(
+ setting_entry.primary_pattern, &origin_pattern)) {
+ continue;
+ }
+
+ if (!origin_pattern.IsValid())
+ continue;
+
+ GURL origin(origin_pattern.ToString());
+ DCHECK(origin.is_valid());
+
+ // Ensure that the current resolved content setting for this origin is
+ // allowed. Otherwise we may be overriding some narrower setting which is
+ // set to block.
+ ContentSetting origin_setting =
+ GetContentSetting(origin, origin, type, std::string());
+
+ // Remove the domain scoped pattern. If |origin_setting| is not
+ // CONTENT_SETTING_ALLOW it implies there is some narrower pattern in
+ // effect, so it's still safe to remove the domain-scoped pattern.
+ SetContentSettingCustomScope(setting_entry.primary_pattern,
+ setting_entry.secondary_pattern, type,
+ std::string(), CONTENT_SETTING_DEFAULT);
+
+ // If the current resolved content setting is allowed it's safe to set the
+ // origin-scoped pattern.
+ if (origin_setting == CONTENT_SETTING_ALLOW)
+ SetContentSettingCustomScope(
+ ContentSettingsPattern::FromURLNoWildcard(origin),
+ ContentSettingsPattern::Wildcard(), type, std::string(),
+ CONTENT_SETTING_ALLOW);
+ }
+ }
+
+ if (status == NOT_MIGRATED) {
+ prefs_->SetInteger(prefs::kDomainToOriginMigrationStatus,
+ MIGRATED_BEFORE_SYNC);
+ } else if (status == MIGRATED_BEFORE_SYNC) {
+ prefs_->SetInteger(prefs::kDomainToOriginMigrationStatus,
+ MIGRATED_AFTER_SYNC);
+ }
+}
+
+base::WeakPtr<HostContentSettingsMap> HostContentSettingsMap::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
void HostContentSettingsMap::RecordExceptionMetrics() {
for (const content_settings::WebsiteSettingsInfo* info :
*content_settings::WebsiteSettingsRegistry::GetInstance()) {
@@ -514,10 +623,28 @@ void HostContentSettingsMap::RecordExceptionMetrics() {
continue;
}
- UMA_HISTOGRAM_ENUMERATION("ContentSettings.ExceptionScheme",
- setting_entry.primary_pattern.GetScheme(),
+ ContentSettingsPattern::SchemeType scheme =
+ setting_entry.primary_pattern.GetScheme();
+ UMA_HISTOGRAM_ENUMERATION("ContentSettings.ExceptionScheme", scheme,
ContentSettingsPattern::SCHEME_MAX);
+ if (scheme == ContentSettingsPattern::SCHEME_FILE) {
+ UMA_HISTOGRAM_BOOLEAN("ContentSettings.ExceptionSchemeFile.HasPath",
+ setting_entry.primary_pattern.HasPath());
+ size_t num_values;
+ int histogram_value =
+ ContentSettingTypeToHistogramValue(content_type, &num_values);
+ if (setting_entry.primary_pattern.HasPath()) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "ContentSettings.ExceptionSchemeFile.Type.WithPath",
+ histogram_value, num_values);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION(
+ "ContentSettings.ExceptionSchemeFile.Type.WithoutPath",
+ histogram_value, num_values);
+ }
+ }
+
if (setting_entry.source == "preference")
++num_exceptions;
}
@@ -620,6 +747,28 @@ void HostContentSettingsMap::ClearSettingsForOneType(
FlushLossyWebsiteSettings();
}
+void HostContentSettingsMap::ClearSettingsForOneTypeWithPredicate(
+ ContentSettingsType content_type,
+ const base::Callback<bool(const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern)>&
+ pattern_predicate) {
+ if (pattern_predicate.is_null()) {
+ ClearSettingsForOneType(content_type);
+ return;
+ }
+
+ ContentSettingsForOneType settings;
+ GetSettingsForOneType(content_type, std::string(), &settings);
+ for (const ContentSettingPatternSource& setting : settings) {
+ if (pattern_predicate.Run(setting.primary_pattern,
+ setting.secondary_pattern)) {
+ SetWebsiteSettingCustomScope(setting.primary_pattern,
+ setting.secondary_pattern, content_type,
+ std::string(), nullptr);
+ }
+ }
+}
+
// TODO(raymes): Remove this function. Consider making it a property of
// ContentSettingsInfo or removing it altogether (it's unclear whether we should
// be restricting allowed default values at this layer).
@@ -664,7 +813,7 @@ void HostContentSettingsMap::OnContentSettingChanged(
HostContentSettingsMap::~HostContentSettingsMap() {
DCHECK(!prefs_);
- STLDeleteValues(&content_settings_providers_);
+ base::STLDeleteValues(&content_settings_providers_);
}
void HostContentSettingsMap::ShutdownOnUIThread() {
@@ -687,6 +836,9 @@ void HostContentSettingsMap::AddSettingsForOneType(
bool incognito) const {
std::unique_ptr<content_settings::RuleIterator> rule_iterator(
provider->GetRuleIterator(content_type, resource_identifier, incognito));
+ if (!rule_iterator)
+ return;
+
while (rule_iterator->HasNext()) {
const content_settings::Rule& rule = rule_iterator->Next();
ContentSetting setting_value = CONTENT_SETTING_DEFAULT;
@@ -851,15 +1003,17 @@ HostContentSettingsMap::GetContentSettingValueAndPatterns(
const GURL& secondary_url,
ContentSettingsPattern* primary_pattern,
ContentSettingsPattern* secondary_pattern) {
- while (rule_iterator->HasNext()) {
- const content_settings::Rule& rule = rule_iterator->Next();
- if (rule.primary_pattern.Matches(primary_url) &&
- rule.secondary_pattern.Matches(secondary_url)) {
- if (primary_pattern)
- *primary_pattern = rule.primary_pattern;
- if (secondary_pattern)
- *secondary_pattern = rule.secondary_pattern;
- return base::WrapUnique(rule.value.get()->DeepCopy());
+ if (rule_iterator) {
+ while (rule_iterator->HasNext()) {
+ const content_settings::Rule& rule = rule_iterator->Next();
+ if (rule.primary_pattern.Matches(primary_url) &&
+ rule.secondary_pattern.Matches(secondary_url)) {
+ if (primary_pattern)
+ *primary_pattern = rule.primary_pattern;
+ if (secondary_pattern)
+ *secondary_pattern = rule.secondary_pattern;
+ return base::WrapUnique(rule.value.get()->DeepCopy());
+ }
}
}
return std::unique_ptr<base::Value>();
diff --git a/chromium/components/content_settings/core/browser/host_content_settings_map.h b/chromium/components/content_settings/core/browser/host_content_settings_map.h
index 2a958d33b87..29af9c7c669 100644
--- a/chromium/components/content_settings/core/browser/host_content_settings_map.h
+++ b/chromium/components/content_settings/core/browser/host_content_settings_map.h
@@ -210,6 +210,14 @@ class HostContentSettingsMap : public content_settings::Observer,
// This should only be called on the UI thread.
void ClearSettingsForOneType(ContentSettingsType content_type);
+ // If |pattern_predicate| is null, this method is equivalent to the above.
+ // Otherwise, it only deletes exceptions matched by |pattern_predicate|.
+ void ClearSettingsForOneTypeWithPredicate(
+ ContentSettingsType content_type,
+ const base::Callback<bool(
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern)>& pattern_predicate);
+
static bool IsDefaultSettingAllowedForType(ContentSetting setting,
ContentSettingsType content_type);
@@ -278,9 +286,27 @@ class HostContentSettingsMap : public content_settings::Observer,
// Passes ownership of |clock|.
void SetPrefClockForTesting(std::unique_ptr<base::Clock> clock);
+ // Migrate old domain scoped ALLOW settings to be origin scoped for
+ // ContentSettingsTypes which are domain scoped. Only narrow down ALLOW
+ // domain settings to origins so that this will not cause privacy/security
+ // issues.
+ //
+ // |after_sync| will be false when called upon construction of this object and
+ // true when called by the sync layer after sync is completed.
+ // TODO(lshang): https://crbug.com/621398 Remove this when clients have
+ // migrated (~M56).
+ void MigrateDomainScopedSettings(bool after_sync);
+
+ base::WeakPtr<HostContentSettingsMap> GetWeakPtr();
+
private:
friend class base::RefCountedThreadSafe<HostContentSettingsMap>;
- friend class HostContentSettingsMapTest_MigrateKeygenSettings_Test;
+
+ FRIEND_TEST_ALL_PREFIXES(HostContentSettingsMapTest,
+ DomainToOriginMigrationStatus);
+ FRIEND_TEST_ALL_PREFIXES(HostContentSettingsMapTest,
+ MigrateDomainScopedSettings);
+ FRIEND_TEST_ALL_PREFIXES(HostContentSettingsMapTest, MigrateKeygenSettings);
friend class content_settings::TestUtils;
@@ -387,6 +413,8 @@ class HostContentSettingsMap : public content_settings::Observer,
base::ObserverList<content_settings::Observer> observers_;
+ base::WeakPtrFactory<HostContentSettingsMap> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(HostContentSettingsMap);
};
diff --git a/chromium/components/content_settings/core/browser/local_shared_objects_counter.h b/chromium/components/content_settings/core/browser/local_shared_objects_counter.h
deleted file mode 100644
index 800b5e39e44..00000000000
--- a/chromium/components/content_settings/core/browser/local_shared_objects_counter.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_LOCAL_SHARED_OBJECTS_COUNTER_H_
-#define COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_LOCAL_SHARED_OBJECTS_COUNTER_H_
-
-#include <stddef.h>
-
-#include "base/macros.h"
-
-class GURL;
-
-// An interface to retrieve counts of browser data objects.
-class LocalSharedObjectsCounter {
- public:
- LocalSharedObjectsCounter() {}
- virtual ~LocalSharedObjectsCounter() {}
-
- virtual size_t GetObjectCount() const = 0;
-
- virtual size_t GetObjectCountForDomain(const GURL& url) const = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LocalSharedObjectsCounter);
-};
-
-#endif // COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_LOCAL_SHARED_OBJECTS_COUNTER_H_
diff --git a/chromium/components/content_settings/core/browser/plugins_field_trial.cc b/chromium/components/content_settings/core/browser/plugins_field_trial.cc
deleted file mode 100644
index 874002ddbe1..00000000000
--- a/chromium/components/content_settings/core/browser/plugins_field_trial.cc
+++ /dev/null
@@ -1,23 +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 "components/content_settings/core/browser/plugins_field_trial.h"
-
-namespace content_settings {
-
-// static
-ContentSetting PluginsFieldTrial::EffectiveContentSetting(
- ContentSettingsType type,
- ContentSetting setting) {
- if (type != CONTENT_SETTINGS_TYPE_PLUGINS)
- return setting;
-
- // For Plugins, ASK is obsolete. Show as BLOCK to reflect actual behavior.
- if (setting == ContentSetting::CONTENT_SETTING_ASK)
- return ContentSetting::CONTENT_SETTING_BLOCK;
-
- return setting;
-}
-
-} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/plugins_field_trial.h b/chromium/components/content_settings/core/browser/plugins_field_trial.h
deleted file mode 100644
index f486ee09d7a..00000000000
--- a/chromium/components/content_settings/core/browser/plugins_field_trial.h
+++ /dev/null
@@ -1,28 +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 COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_H_
-#define COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_H_
-
-#include "base/macros.h"
-#include "components/content_settings/core/common/content_settings.h"
-#include "components/content_settings/core/common/content_settings_types.h"
-
-namespace content_settings {
-
-// This class manages the Plugins field trials.
-class PluginsFieldTrial {
- public:
- // Returns the effective content setting for plugins. Passes non-plugin
- // content settings through without modification.
- static ContentSetting EffectiveContentSetting(ContentSettingsType type,
- ContentSetting setting);
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(PluginsFieldTrial);
-};
-
-} // namespace content_settings
-
-#endif // COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_H_
diff --git a/chromium/components/content_settings/core/browser/website_settings_info.h b/chromium/components/content_settings/core/browser/website_settings_info.h
index 762e32e828c..1f8176ad7b3 100644
--- a/chromium/components/content_settings/core/browser/website_settings_info.h
+++ b/chromium/components/content_settings/core/browser/website_settings_info.h
@@ -27,13 +27,13 @@ class WebsiteSettingsInfo {
enum LossyStatus { LOSSY, NOT_LOSSY };
enum ScopingType {
- // Settings scoped to the domain of the main frame only.
- TOP_LEVEL_DOMAIN_ONLY_SCOPE,
-
// Settings scoped to the domain of the requesting frame only. This should
// not generally be used.
REQUESTING_DOMAIN_ONLY_SCOPE,
+ // Settings scoped to the origin of the main frame only.
+ TOP_LEVEL_ORIGIN_ONLY_SCOPE,
+
// Settings scoped to the origin of the requesting frame only.
REQUESTING_ORIGIN_ONLY_SCOPE,
diff --git a/chromium/components/content_settings/core/browser/website_settings_registry.cc b/chromium/components/content_settings/core/browser/website_settings_registry.cc
index 553a0c72dd4..7fd4f40ab21 100644
--- a/chromium/components/content_settings/core/browser/website_settings_registry.cc
+++ b/chromium/components/content_settings/core/browser/website_settings_registry.cc
@@ -77,13 +77,16 @@ const WebsiteSettingsInfo* WebsiteSettingsRegistry::Register(
#elif defined(OS_ANDROID)
if (!(platform & PLATFORM_ANDROID))
return nullptr;
+ // Don't sync settings to mobile platforms. The UI is different to desktop and
+ // doesn't allow the settings to be managed in the same way. See
+ // crbug.com/642184.
+ sync_status = WebsiteSettingsInfo::UNSYNCABLE;
#elif defined(OS_IOS)
if (!(platform & PLATFORM_IOS))
return nullptr;
- // Only default settings for Cookies and Popups are used in iOS. Exceptions
- // and all the other content setting types are not used in iOS currently. So
- // make content settings unsyncable on iOS for now.
- // TODO(lshang): address this once we have proper content settings on iOS.
+ // Don't sync settings to mobile platforms. The UI is different to desktop and
+ // doesn't allow the settings to be managed in the same way. See
+ // crbug.com/642184.
sync_status = WebsiteSettingsInfo::UNSYNCABLE;
#else
#error "Unsupported platform"
@@ -116,7 +119,7 @@ void WebsiteSettingsRegistry::Init() {
Register(CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE,
"auto-select-certificate", nullptr, WebsiteSettingsInfo::UNSYNCABLE,
WebsiteSettingsInfo::NOT_LOSSY,
- WebsiteSettingsInfo::REQUESTING_DOMAIN_ONLY_SCOPE, ALL_PLATFORMS,
+ WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE, ALL_PLATFORMS,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
Register(CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS,
"ssl-cert-decisions", nullptr, WebsiteSettingsInfo::UNSYNCABLE,
@@ -126,7 +129,7 @@ void WebsiteSettingsRegistry::Init() {
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
Register(CONTENT_SETTINGS_TYPE_APP_BANNER, "app-banner", nullptr,
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
- WebsiteSettingsInfo::REQUESTING_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
Register(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, "site-engagement", nullptr,
@@ -139,6 +142,17 @@ void WebsiteSettingsRegistry::Init() {
WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
+ Register(CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT,
+ "prompt-no-decision-count", nullptr, WebsiteSettingsInfo::UNSYNCABLE,
+ WebsiteSettingsInfo::NOT_LOSSY,
+ WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
+ DESKTOP | PLATFORM_ANDROID,
+ WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
+ Register(CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "important-site-info",
+ nullptr, WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
+ WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
+ DESKTOP | PLATFORM_ANDROID,
+ WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/website_settings_registry_unittest.cc b/chromium/components/content_settings/core/browser/website_settings_registry_unittest.cc
index 223d810774f..aeb0a803c97 100644
--- a/chromium/components/content_settings/core/browser/website_settings_registry_unittest.cc
+++ b/chromium/components/content_settings/core/browser/website_settings_registry_unittest.cc
@@ -50,7 +50,7 @@ TEST_F(WebsiteSettingsRegistryTest, GetByName) {
registry()->Register(static_cast<ContentSettingsType>(10), "test", nullptr,
WebsiteSettingsInfo::UNSYNCABLE,
WebsiteSettingsInfo::LOSSY,
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::ALL_PLATFORMS,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
info = registry()->GetByName("test");
@@ -88,10 +88,10 @@ TEST_F(WebsiteSettingsRegistryTest, Properties) {
// Register a new setting.
registry()->Register(static_cast<ContentSettingsType>(10), "test",
- base::WrapUnique(new base::FundamentalValue(999)),
+ base::MakeUnique<base::FundamentalValue>(999),
WebsiteSettingsInfo::SYNCABLE,
WebsiteSettingsInfo::LOSSY,
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::ALL_PLATFORMS,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
info = registry()->Get(static_cast<ContentSettingsType>(10));
@@ -102,14 +102,14 @@ TEST_F(WebsiteSettingsRegistryTest, Properties) {
int setting;
ASSERT_TRUE(info->initial_default_value()->GetAsInteger(&setting));
EXPECT_EQ(999, setting);
-#if defined(OS_IOS)
+#if defined(OS_ANDROID) || defined(OS_IOS)
EXPECT_EQ(PrefRegistry::LOSSY_PREF, info->GetPrefRegistrationFlags());
#else
EXPECT_EQ(PrefRegistry::LOSSY_PREF |
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF,
info->GetPrefRegistrationFlags());
#endif
- EXPECT_EQ(WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ EXPECT_EQ(WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
info->scoping_type());
EXPECT_EQ(WebsiteSettingsInfo::INHERIT_IN_INCOGNITO,
info->incognito_behavior());
@@ -117,10 +117,10 @@ TEST_F(WebsiteSettingsRegistryTest, Properties) {
TEST_F(WebsiteSettingsRegistryTest, Iteration) {
registry()->Register(static_cast<ContentSettingsType>(10), "test",
- base::WrapUnique(new base::FundamentalValue(999)),
+ base::MakeUnique<base::FundamentalValue>(999),
WebsiteSettingsInfo::SYNCABLE,
WebsiteSettingsInfo::LOSSY,
- WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+ WebsiteSettingsInfo::TOP_LEVEL_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::ALL_PLATFORMS,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
diff --git a/chromium/components/content_settings/core/common/content_settings.cc b/chromium/components/content_settings/core/common/content_settings.cc
index e7a8dea8fb8..3a245e0133f 100644
--- a/chromium/components/content_settings/core/common/content_settings.cc
+++ b/chromium/components/content_settings/core/common/content_settings.cc
@@ -41,7 +41,7 @@ ContentSettingsType kHistogramOrder[] = {
CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
- CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
+ CONTENT_SETTINGS_TYPE_DEFAULT, // PUSH_MESSAGING (removed).
CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS,
CONTENT_SETTINGS_TYPE_DEFAULT, // METRO_SWITCH_TO_DESKTOP (deprecated).
#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
@@ -56,6 +56,8 @@ ContentSettingsType kHistogramOrder[] = {
CONTENT_SETTINGS_TYPE_BLUETOOTH_GUARD,
CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC,
CONTENT_SETTINGS_TYPE_AUTOPLAY,
+ CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT,
+ CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO,
};
int ContentSettingTypeToHistogramValue(ContentSettingsType content_setting,
@@ -70,7 +72,7 @@ int ContentSettingTypeToHistogramValue(ContentSettingsType content_setting,
}
}
- DCHECK(ContainsKey(kMap, content_setting));
+ DCHECK(base::ContainsKey(kMap, content_setting));
*num_values = arraysize(kHistogramOrder);
return kMap[content_setting];
}
diff --git a/chromium/components/content_settings/core/common/content_settings_pattern.cc b/chromium/components/content_settings/core/common/content_settings_pattern.cc
index 6eeab8bc9a9..c86044ef639 100644
--- a/chromium/components/content_settings/core/common/content_settings_pattern.cc
+++ b/chromium/components/content_settings/core/common/content_settings_pattern.cc
@@ -42,7 +42,7 @@ std::string GetDefaultPort(const std::string& scheme) {
return std::string();
}
-// Returns true if |sub_domain| is a sub domain or equls |domain|. E.g.
+// Returns true if |sub_domain| is a sub domain or equals |domain|. E.g.
// "mail.google.com" is a sub domain of "google.com" but "evilhost.com" is not a
// subdomain of "host.com".
bool IsSubDomainOrEqual(const std::string& sub_domain,
@@ -452,6 +452,60 @@ ContentSettingsPattern ContentSettingsPattern::FromString(
}
// static
+bool ContentSettingsPattern::MigrateFromDomainToOrigin(
+ const ContentSettingsPattern& domain_pattern,
+ ContentSettingsPattern* origin_pattern) {
+ DCHECK(origin_pattern);
+
+ // Generated patterns with ::FromURL (which we want to migrate) must either
+ // have a scheme wildcard or be https.
+ if (domain_pattern.parts_.scheme != url::kHttpsScheme &&
+ !domain_pattern.parts_.is_scheme_wildcard) {
+ return false;
+ }
+
+ // Generated patterns using ::FromURL with the HTTPs scheme can not have a
+ // port wildcard.
+ if (domain_pattern.parts_.is_port_wildcard &&
+ domain_pattern.parts_.scheme == url::kHttpsScheme) {
+ return false;
+ }
+
+ // Patterns generated with ::FromURL will always have a domain wildcard. Those
+ // generated with ::FromURLNoWildcard don't.
+ if (!domain_pattern.parts_.has_domain_wildcard)
+ return false;
+
+ // Generated patterns with ::FromURL will always have a host.
+ if (domain_pattern.parts_.host.empty())
+ return false;
+
+ std::unique_ptr<ContentSettingsPattern::BuilderInterface> builder(
+ ContentSettingsPattern::CreateBuilder(false));
+
+ if (domain_pattern.parts_.is_scheme_wildcard)
+ builder->WithScheme(url::kHttpScheme);
+ else
+ builder->WithScheme(domain_pattern.parts_.scheme);
+
+ builder->WithHost(domain_pattern.parts_.host);
+
+ if (domain_pattern.parts_.is_port_wildcard) {
+ if (domain_pattern.parts_.scheme == url::kHttpsScheme) {
+ builder->WithPort(GetDefaultPort(url::kHttpsScheme));
+ } else {
+ builder->WithPort(GetDefaultPort(url::kHttpScheme));
+ }
+ } else {
+ builder->WithPort(domain_pattern.parts_.port);
+ }
+
+ *origin_pattern = builder->Build();
+
+ return true;
+}
+
+// static
void ContentSettingsPattern::SetNonWildcardDomainNonPortScheme(
const char* scheme) {
DCHECK(scheme);
@@ -560,6 +614,11 @@ ContentSettingsPattern::SchemeType ContentSettingsPattern::GetScheme() const {
return SCHEME_OTHER;
}
+bool ContentSettingsPattern::HasPath() const {
+ DCHECK_EQ(GetScheme(), SCHEME_FILE);
+ return !parts_.is_path_wildcard && !parts_.path.empty();
+}
+
ContentSettingsPattern::Relation ContentSettingsPattern::Compare(
const ContentSettingsPattern& other) const {
// Two invalid patterns are identical in the way they behave. They don't match
diff --git a/chromium/components/content_settings/core/common/content_settings_pattern.h b/chromium/components/content_settings/core/common/content_settings_pattern.h
index d0c59db530e..f0432f59930 100644
--- a/chromium/components/content_settings/core/common/content_settings_pattern.h
+++ b/chromium/components/content_settings/core/common/content_settings_pattern.h
@@ -142,6 +142,7 @@ class ContentSettingsPattern {
// Returns a pattern that matches the scheme and host of this URL, as well as
// all subdomains and ports.
+ // TODO(lshang): Remove this when crbug.com/604612 is done.
static ContentSettingsPattern FromURL(const GURL& url);
// Returns a pattern that matches exactly this URL.
@@ -158,6 +159,13 @@ class ContentSettingsPattern {
// - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip)
static ContentSettingsPattern FromString(const std::string& pattern_spec);
+ // Migrate domain scoped settings generated using FromURL() to be origin
+ // scoped. Return false if domain_pattern is not generated using FromURL().
+ // TODO(lshang): Remove this when migration is done. https://crbug.com/604612
+ static bool MigrateFromDomainToOrigin(
+ const ContentSettingsPattern& domain_pattern,
+ ContentSettingsPattern* origin_pattern);
+
// Sets the scheme that doesn't support domain wildcard and port.
// Needs to be called by the embedder before using ContentSettingsPattern.
// |scheme| can't be NULL, and the pointed string must remain alive until the
@@ -186,6 +194,10 @@ class ContentSettingsPattern {
// Returns scheme type of pattern.
ContentSettingsPattern::SchemeType GetScheme() const;
+ // True if this pattern has a non-empty path. Can only be used for patterns
+ // with file: schemes.
+ bool HasPath() const;
+
// Compares the pattern with a given |other| pattern and returns the
// |Relation| of the two patterns.
Relation Compare(const ContentSettingsPattern& other) const;
diff --git a/chromium/components/content_settings/core/common/content_settings_pattern_unittest.cc b/chromium/components/content_settings/core/common/content_settings_pattern_unittest.cc
index c8280b8fcfa..c2480858445 100644
--- a/chromium/components/content_settings/core/common/content_settings_pattern_unittest.cc
+++ b/chromium/components/content_settings/core/common/content_settings_pattern_unittest.cc
@@ -721,6 +721,95 @@ TEST(ContentSettingsPatternTest, CanonicalizePattern_Legacy) {
EXPECT_STREQ("", Pattern("\xC4\x87ira.*").ToString().c_str());
}
+TEST(ContentSettingsPatternTest, MigrateFromDomainToOrigin) {
+ ContentSettingsPattern origin_pattern;
+ // Http scheme patterns.
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("http://[*.]example.com"),
+ &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("http://[*.]example.com:80"),
+ &origin_pattern));
+
+ // Https patterns with port wildcard.
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("https://www.google.com"),
+ &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("https://[*.]google.com"),
+ &origin_pattern));
+
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("www.google.com"), &origin_pattern));
+
+ // Patterns with no domain wildcard.
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("*://www.google.com:8080"),
+ &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("www.example.com:8080"),
+ &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("www.google.com/*"), &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("google"), &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("https://www.google.com:443"),
+ &origin_pattern));
+
+ // Patterns with empty host.
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("*"), &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("[*.]"), &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("http://*"), &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("http://*:8080"), &origin_pattern));
+
+ // Other schemes and IP address patterns won't be migrated.
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("192.168.0.1"), &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("https://127.0.0.1"),
+ &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("http://[::1]"), &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("[::1]"), &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("file:///foo/bar.html"),
+ &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString(
+ "filesystem:http://www.google.com/temporary/"),
+ &origin_pattern));
+ EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString(
+ "chrome-extension://peoadpeiejnhkmpaakpnompolbglelel/"),
+ &origin_pattern));
+
+ // These are pattern styles which might be generated using FromURL().
+ EXPECT_TRUE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("[*.]example.com"), &origin_pattern));
+ EXPECT_EQ("http://example.com:80", origin_pattern.ToString());
+
+ EXPECT_TRUE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("[*.]google.com:80"),
+ &origin_pattern));
+ EXPECT_EQ("http://google.com:80", origin_pattern.ToString());
+
+ EXPECT_TRUE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("[*.]example.com:123"),
+ &origin_pattern));
+ EXPECT_EQ("http://example.com:123", origin_pattern.ToString());
+
+ EXPECT_TRUE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+ ContentSettingsPattern::FromString("https://[*.]google.com:443"),
+ &origin_pattern));
+ EXPECT_EQ("https://google.com:443", origin_pattern.ToString());
+}
+
TEST(ContentSettingsPatternTest, Schemes) {
EXPECT_EQ(ContentSettingsPattern::SCHEME_HTTP,
Pattern("http://www.example.com").GetScheme());
@@ -738,3 +827,10 @@ TEST(ContentSettingsPatternTest, Schemes) {
EXPECT_EQ(ContentSettingsPattern::SCHEME_OTHER,
Pattern("filesystem:http://www.google.com/temporary/").GetScheme());
}
+
+TEST(ContentSettingsPatternTest, FileSchemeHasPath) {
+ EXPECT_FALSE(Pattern("file:///*").HasPath());
+ EXPECT_TRUE(Pattern("file:///foo").HasPath());
+ EXPECT_TRUE(Pattern("file:///foo/bar/").HasPath());
+ EXPECT_TRUE(Pattern("file:///foo/bar/test.html").HasPath());
+} \ No newline at end of file
diff --git a/chromium/components/content_settings/core/common/content_settings_types.h b/chromium/components/content_settings/core/common/content_settings_types.h
index dc8cf6f5b82..724297e4c32 100644
--- a/chromium/components/content_settings/core/common/content_settings_types.h
+++ b/chromium/components/content_settings/core/common/content_settings_types.h
@@ -35,7 +35,6 @@ enum ContentSettingsType {
CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
- CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS,
CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
CONTENT_SETTINGS_TYPE_APP_BANNER,
@@ -46,6 +45,8 @@ enum ContentSettingsType {
CONTENT_SETTINGS_TYPE_KEYGEN,
CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC,
CONTENT_SETTINGS_TYPE_AUTOPLAY,
+ CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT,
+ CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO,
// WARNING: This enum is going to be removed soon. Do not depend on NUM_TYPES.
CONTENT_SETTINGS_NUM_TYPES_DO_NOT_USE,
diff --git a/chromium/components/content_settings/core/common/pref_names.cc b/chromium/components/content_settings/core/common/pref_names.cc
index ebcf7f0608e..36a7e628b32 100644
--- a/chromium/components/content_settings/core/common/pref_names.cc
+++ b/chromium/components/content_settings/core/common/pref_names.cc
@@ -18,6 +18,12 @@ const char kContentSettingsVersion[] = "profile.content_settings.pref_version";
const char kContentSettingsWindowLastTabIndex[] =
"content_settings_window.last_tab_index";
+// Integer that indicates the status of migrating domain scoped settings to
+// origin scoped settings.
+// TODO(lshang): Remove this when all migration is done. See crbug.com/621398.
+const char kDomainToOriginMigrationStatus[] =
+ "profile.content_settings.domain_to_origin_migration_status";
+
// Preferences that are exclusively used to store managed values for default
// content settings.
const char kManagedDefaultCookiesSetting[] =
diff --git a/chromium/components/content_settings/core/common/pref_names.h b/chromium/components/content_settings/core/common/pref_names.h
index aa1af1cf226..9ddbd4c882d 100644
--- a/chromium/components/content_settings/core/common/pref_names.h
+++ b/chromium/components/content_settings/core/common/pref_names.h
@@ -16,6 +16,7 @@ namespace prefs {
extern const char kBlockThirdPartyCookies[];
extern const char kContentSettingsVersion[];
extern const char kContentSettingsWindowLastTabIndex[];
+extern const char kDomainToOriginMigrationStatus[];
extern const char kManagedDefaultCookiesSetting[];
extern const char kManagedDefaultImagesSetting[];
diff --git a/chromium/components/contextual_search.gypi b/chromium/components/contextual_search.gypi
deleted file mode 100644
index 7d769a7e358..00000000000
--- a/chromium/components/contextual_search.gypi
+++ /dev/null
@@ -1,59 +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.
-
-{
- 'targets': [
- {
- # GN: //components/contextual_search:browser
- 'target_name': 'contextual_search_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'contextual_search_mojo_bindings',
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'contextual_search/browser/contextual_search_js_api_service_impl.cc',
- 'contextual_search/browser/contextual_search_js_api_service_impl.h',
- ],
- },
- {
- # GN: //components/contextual_search:renderer
- 'target_name': 'contextual_search_renderer',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- '../third_party/WebKit',
- ],
- 'dependencies': [
- 'contextual_search_mojo_bindings',
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../third_party/WebKit/public/blink.gyp:blink',
- ],
- 'sources': [
- 'contextual_search/renderer/contextual_search_wrapper.cc',
- 'contextual_search/renderer/contextual_search_wrapper.h',
- 'contextual_search/renderer/overlay_js_render_frame_observer.cc',
- 'contextual_search/renderer/overlay_js_render_frame_observer.h',
- 'contextual_search/renderer/overlay_page_notifier_service_impl.cc',
- 'contextual_search/renderer/overlay_page_notifier_service_impl.h',
- ],
- },
- {
- # GN version: //components/contextual_search:mojo_bindings
- 'target_name': 'contextual_search_mojo_bindings',
- 'type': 'static_library',
- 'sources': [
- 'contextual_search/common/contextual_search_js_api_service.mojom',
- 'contextual_search/common/overlay_page_notifier_service.mojom',
- ],
- 'includes': [
- '../mojo/mojom_bindings_generator.gypi',
- ],
- },
- ],
-}
diff --git a/chromium/components/contextual_search/BUILD.gn b/chromium/components/contextual_search/BUILD.gn
index b82522bbc33..dea8e600cbd 100644
--- a/chromium/components/contextual_search/BUILD.gn
+++ b/chromium/components/contextual_search/BUILD.gn
@@ -4,19 +4,23 @@
import("//mojo/public/tools/bindings/mojom.gni")
-# GYP version: components/contextual_search.gypi:contextual_search_mojo_bindings
mojom("mojo_bindings") {
sources = [
"common/contextual_search_js_api_service.mojom",
"common/overlay_page_notifier_service.mojom",
]
+
+ use_new_wrapper_types = false
}
-# GYP version: components/contextual_search.gypi:contextual_search_browser
static_library("browser") {
sources = [
"browser/contextual_search_js_api_service_impl.cc",
"browser/contextual_search_js_api_service_impl.h",
+ "browser/ctr_aggregator.cc",
+ "browser/ctr_aggregator.h",
+ "browser/weekly_activity_storage.cc",
+ "browser/weekly_activity_storage.h",
]
deps = [
":mojo_bindings",
@@ -24,7 +28,19 @@ static_library("browser") {
]
}
-# GYP version: components/contextual_search.gypi:contextual_search_renderer
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "browser/ctr_aggregator_unittest.cc",
+ ]
+
+ deps = [
+ ":browser",
+ "//base",
+ "//testing/gtest",
+ ]
+}
+
static_library("renderer") {
sources = [
"renderer/contextual_search_wrapper.cc",
diff --git a/chromium/components/contextual_search/OWNERS b/chromium/components/contextual_search/OWNERS
index 602de403961..1ae3bf181ac 100644
--- a/chromium/components/contextual_search/OWNERS
+++ b/chromium/components/contextual_search/OWNERS
@@ -1,5 +1,4 @@
donnd@chromium.org
-pedrosimonetti@chromium.org
twellington@chromium.org
per-file *.mojom=set noparent
diff --git a/chromium/components/contextual_search/browser/contextual_search_js_api_service_impl.cc b/chromium/components/contextual_search/browser/contextual_search_js_api_service_impl.cc
index c664593b180..12aed8ed2d4 100644
--- a/chromium/components/contextual_search/browser/contextual_search_js_api_service_impl.cc
+++ b/chromium/components/contextual_search/browser/contextual_search_js_api_service_impl.cc
@@ -7,14 +7,13 @@
#include <utility>
#include "components/contextual_search/browser/contextual_search_js_api_handler.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
namespace contextual_search {
ContextualSearchJsApiServiceImpl::ContextualSearchJsApiServiceImpl(
- ContextualSearchJsApiHandler* contextual_search_js_api_handler,
- mojo::InterfaceRequest<mojom::ContextualSearchJsApiService> request)
- : binding_(this, std::move(request)),
- contextual_search_js_api_handler_(contextual_search_js_api_handler) {}
+ ContextualSearchJsApiHandler* contextual_search_js_api_handler)
+ : contextual_search_js_api_handler_(contextual_search_js_api_handler) {}
ContextualSearchJsApiServiceImpl::~ContextualSearchJsApiServiceImpl() {}
@@ -28,9 +27,9 @@ void ContextualSearchJsApiServiceImpl::HandleSetCaption(
void CreateContextualSearchJsApiService(
ContextualSearchJsApiHandler* contextual_search_js_api_handler,
mojo::InterfaceRequest<mojom::ContextualSearchJsApiService> request) {
- // This is strongly bound and owned by the pipe.
- new ContextualSearchJsApiServiceImpl(contextual_search_js_api_handler,
- std::move(request));
+ mojo::MakeStrongBinding(base::MakeUnique<ContextualSearchJsApiServiceImpl>(
+ contextual_search_js_api_handler),
+ std::move(request));
}
} // namespace contextual_search
diff --git a/chromium/components/contextual_search/browser/contextual_search_js_api_service_impl.h b/chromium/components/contextual_search/browser/contextual_search_js_api_service_impl.h
index 218e938423f..0b5c8b19c47 100644
--- a/chromium/components/contextual_search/browser/contextual_search_js_api_service_impl.h
+++ b/chromium/components/contextual_search/browser/contextual_search_js_api_service_impl.h
@@ -9,7 +9,6 @@
#include "components/contextual_search/browser/contextual_search_js_api_handler.h"
#include "components/contextual_search/common/contextual_search_js_api_service.mojom.h"
#include "mojo/public/cpp/bindings/string.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
namespace contextual_search {
@@ -17,17 +16,14 @@ namespace contextual_search {
class ContextualSearchJsApiServiceImpl
: public mojom::ContextualSearchJsApiService {
public:
- ContextualSearchJsApiServiceImpl(
- ContextualSearchJsApiHandler* contextual_search_js_api_handler,
- mojo::InterfaceRequest<mojom::ContextualSearchJsApiService> request);
+ explicit ContextualSearchJsApiServiceImpl(
+ ContextualSearchJsApiHandler* contextual_search_js_api_handler);
~ContextualSearchJsApiServiceImpl() override;
// Mojo ContextualSearchApiService implementation.
void HandleSetCaption(const mojo::String& message, bool does_answer) override;
private:
- mojo::StrongBinding<mojom::ContextualSearchJsApiService> binding_;
-
// The UI handler for calls through the JavaScript API.
ContextualSearchJsApiHandler* contextual_search_js_api_handler_;
diff --git a/chromium/components/contextual_search/browser/ctr_aggregator.cc b/chromium/components/contextual_search/browser/ctr_aggregator.cc
new file mode 100644
index 00000000000..637b4c2be97
--- /dev/null
+++ b/chromium/components/contextual_search/browser/ctr_aggregator.cc
@@ -0,0 +1,118 @@
+// 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 "components/contextual_search/browser/ctr_aggregator.h"
+
+#include "base/numerics/safe_conversions.h"
+#include "base/time/time.h"
+
+namespace {
+
+const double kSecondsPerWeek =
+ base::Time::kMicrosecondsPerWeek / base::Time::kMicrosecondsPerSecond;
+// Used for validation in debug build. Week numbers are > 2300 as of year 2016.
+const int kReasonableMinWeek = 2000;
+
+} // namespace
+
+namespace contextual_search {
+
+CtrAggregator::CtrAggregator(WeeklyActivityStorage& storage)
+ : storage_(storage) {
+ base::Time now = base::Time::NowFromSystemTime();
+ double now_in_seconds = now.ToDoubleT();
+ week_number_ = now_in_seconds / kSecondsPerWeek;
+ DCHECK(week_number_ >= kReasonableMinWeek);
+ // NOTE: This initialization may callback into the storage implementation so
+ // that needs to be fully initialized when constructing this aggregator.
+ storage_.AdvanceToWeek(week_number_);
+}
+
+// Testing only
+CtrAggregator::CtrAggregator(WeeklyActivityStorage& storage, int week_number)
+ : storage_(storage), week_number_(week_number) {
+ storage_.AdvanceToWeek(week_number_);
+}
+
+CtrAggregator::~CtrAggregator() {}
+
+void CtrAggregator::RecordImpression(bool did_click) {
+ storage_.WriteImpressions(week_number_,
+ 1 + storage_.ReadImpressions(week_number_));
+ if (did_click)
+ storage_.WriteClicks(week_number_, 1 + storage_.ReadClicks(week_number_));
+}
+
+int CtrAggregator::GetCurrentWeekNumber() {
+ return week_number_;
+}
+
+bool CtrAggregator::HasPreviousWeekData() {
+ return storage_.HasData(week_number_ - 1);
+}
+
+int CtrAggregator::GetPreviousWeekImpressions() {
+ return storage_.ReadImpressions(week_number_ - 1);
+}
+
+float CtrAggregator::GetPreviousWeekCtr() {
+ if (!HasPreviousWeekData())
+ return NAN;
+
+ int clicks = GetPreviousWeekClicks();
+ int impressions = GetPreviousWeekImpressions();
+ if (impressions == 0)
+ return 0.0;
+ return base::saturated_cast<float>(clicks) / impressions;
+}
+
+bool CtrAggregator::HasPrevious28DayData() {
+ for (int previous = 1; previous <= kNumWeeksNeededFor28DayData; previous++) {
+ if (!storage_.HasData(week_number_ - previous))
+ return false;
+ }
+ return true;
+}
+
+float CtrAggregator::GetPrevious28DayCtr() {
+ if (!HasPrevious28DayData())
+ return NAN;
+
+ int clicks = GetPrevious28DayClicks();
+ int impressions = GetPrevious28DayImpressions();
+ if (impressions == 0)
+ return 0.0;
+ return base::saturated_cast<float>(clicks) / impressions;
+}
+
+int CtrAggregator::GetPrevious28DayImpressions() {
+ int impressions = 0;
+ for (int previous = 1; previous <= kNumWeeksNeededFor28DayData; previous++) {
+ impressions += storage_.ReadImpressions(week_number_ - previous);
+ }
+ return impressions;
+}
+
+// private
+
+int CtrAggregator::GetPreviousWeekClicks() {
+ return storage_.ReadClicks(week_number_ - 1);
+}
+
+int CtrAggregator::GetPrevious28DayClicks() {
+ int clicks = 0;
+ for (int previous = 1; previous <= kNumWeeksNeededFor28DayData; previous++) {
+ clicks += storage_.ReadClicks(week_number_ - previous);
+ }
+ return clicks;
+}
+
+// Testing only
+
+void CtrAggregator::IncrementWeek(int weeks) {
+ week_number_ += weeks;
+ storage_.AdvanceToWeek(week_number_);
+}
+
+} // namespace contextual_search
diff --git a/chromium/components/contextual_search/browser/ctr_aggregator.h b/chromium/components/contextual_search/browser/ctr_aggregator.h
new file mode 100644
index 00000000000..a7c5807af93
--- /dev/null
+++ b/chromium/components/contextual_search/browser/ctr_aggregator.h
@@ -0,0 +1,118 @@
+// 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.
+
+// Provides aggregation of feature usage by tracking impressions and clicks
+// over 1-week and 28-day intervals. Impressions are views of some UX and
+// clicks are any measured interaction with that UX, yielding CTR -- Click
+// Through Rate.
+// Used by Contextual Search to record impressions of the Bar and CTR of
+// panel opens to use as signals for Tap triggering.
+
+#ifndef COMPONENTS_CONTEXTUAL_SEARCH_BROWSER_CTR_AGGREGATOR_H_
+#define COMPONENTS_CONTEXTUAL_SEARCH_BROWSER_CTR_AGGREGATOR_H_
+
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "components/contextual_search/browser/weekly_activity_storage.h"
+
+namespace contextual_search {
+
+// Number of weeks of data needed for 28 days.
+const int kNumWeeksNeededFor28DayData = 4;
+
+// Usage: Create a CtrAggregator and start recording impressions or reading
+// aggregated data. Get data from the previous week or previous 4-week period
+// that ended with the previous week.
+// A new week starts at an arbitrary time based on seconds since the Epoch.
+// The data from the previous week and previous 28-day period are guaranteed to
+// be complete only if the HasPrevious method returns true. If one of the data
+// accessors is called when the data is not complete invalid data may be
+// returned.
+class CtrAggregator {
+ public:
+ // Constructs a CtrAggregator using the given |storage| mechanism.
+ // Data is stored by |storage| typically on persistent device-local storage.
+ // A callback through the storage interface may occur at construction time,
+ // so the |storage| must be fully initialized when this constructor is
+ // called.
+ CtrAggregator(WeeklyActivityStorage& storage);
+ ~CtrAggregator();
+
+ // Records an impression. Records a click if |did_click| is true.
+ void RecordImpression(bool did_click);
+
+ // Returns the number for the current week. Useful for checking when the
+ // current week changes.
+ int GetCurrentWeekNumber();
+
+ // Returns whether we have the previous week's data for this user.
+ bool HasPreviousWeekData();
+
+ // Gets the number of impressions from the previous week.
+ // Callers must check if there is previous week's data for this user, or
+ // invalid data may be returned.
+ int GetPreviousWeekImpressions();
+
+ // Gets the CTR from the previous week.
+ // Callers must check if there is previous week's data for this user, or
+ // invalid data may be returned.
+ float GetPreviousWeekCtr();
+
+ // Returns whether we have data from a 28 day period ending in the previous
+ // week.
+ bool HasPrevious28DayData();
+
+ // Gets the number of impressions from a 28 day period ending in the previous
+ // week.
+ // Callers must check if there is previous 28 day data for this user, or
+ // invalid data may be returned.
+ int GetPrevious28DayImpressions();
+
+ // Gets the CTR from a 28 day period ending in the previous week.
+ // Callers must check if there is previous 28 day data for this user, or
+ // invalid data may be returned.
+ float GetPrevious28DayCtr();
+
+ private:
+ // This implementation uses a fixed number of bins to store integer impression
+ // and click data for the most recent N weeks, where N = 5 (in order to keep 4
+ // complete weeks). Another bin keeps track of the current week being
+ // written. Yet another bin records when data was first stored or accessed so
+ // we can know when a time period has complete data.
+ friend class CtrAggregatorTest;
+ FRIEND_TEST_ALL_PREFIXES(CtrAggregatorTest, SimpleOperationTest);
+ FRIEND_TEST_ALL_PREFIXES(CtrAggregatorTest, MultiWeekTest);
+ FRIEND_TEST_ALL_PREFIXES(CtrAggregatorTest, SkipOneWeekTest);
+ FRIEND_TEST_ALL_PREFIXES(CtrAggregatorTest, SkipThreeWeeksTest);
+ FRIEND_TEST_ALL_PREFIXES(CtrAggregatorTest, SkipFourWeeksTest);
+
+ // Constructs an instance for testing; sets the week.
+ CtrAggregator(WeeklyActivityStorage& storage, int week_number);
+ // For testing, increments the current week number by |weeks|.
+ void IncrementWeek(int weeks);
+
+ // Gets the number of clicks from the previous week.
+ // Callers must check if there is previous week's data for this user, or
+ // invalid data may be returned.
+ int GetPreviousWeekClicks();
+ // Gets the number of clicks from a 28 day period ending in the previous
+ // week.
+ // Callers must check if there is previous 28 day data for this user, or
+ // invalid data may be returned.
+ int GetPrevious28DayClicks();
+
+ // Stores the weekly activity data.
+ WeeklyActivityStorage& storage_;
+
+ // The current week number, expressed as the number of weeks since Epoch.
+ int week_number_;
+
+ DISALLOW_COPY_AND_ASSIGN(CtrAggregator);
+};
+
+} // namespace contextual_search
+
+#endif // COMPONENTS_CONTEXTUAL_SEARCH_BROWSER_CTR_AGGREGATOR_H_
diff --git a/chromium/components/contextual_search/browser/ctr_aggregator_unittest.cc b/chromium/components/contextual_search/browser/ctr_aggregator_unittest.cc
new file mode 100644
index 00000000000..9e3d7912643
--- /dev/null
+++ b/chromium/components/contextual_search/browser/ctr_aggregator_unittest.cc
@@ -0,0 +1,138 @@
+// 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 "components/contextual_search/browser/ctr_aggregator.h"
+
+#include <unordered_map>
+
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Value;
+
+namespace {
+const int kTestWeek = 2500;
+}
+
+namespace contextual_search {
+
+class CtrAggregatorTest : public testing::Test {
+ public:
+ CtrAggregatorTest() {}
+ ~CtrAggregatorTest() override {}
+
+ class WeeklyActivityStorageStub : public WeeklyActivityStorage {
+ public:
+ WeeklyActivityStorageStub();
+
+ private:
+ int ReadStorage(std::string storage_bucket) override;
+ void WriteStorage(std::string storage_key, int value) override;
+
+ typedef std::unordered_map<std::string, int> hashmap;
+ hashmap weeks_;
+ };
+
+ // Test helpers
+ void Fill4Weeks(); // Fill 4 weeks with 2 impressions, 1 click.
+
+ // The class under test.
+ std::unique_ptr<CtrAggregator> aggregator_;
+
+ protected:
+ // The storage stub.
+ std::unique_ptr<WeeklyActivityStorage> storage_;
+
+ void SetUp() override {
+ storage_.reset(new WeeklyActivityStorageStub());
+ aggregator_.reset(new CtrAggregator(*storage_.get(), kTestWeek));
+ }
+
+ void TearDown() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CtrAggregatorTest);
+};
+
+CtrAggregatorTest::WeeklyActivityStorageStub::WeeklyActivityStorageStub()
+ : WeeklyActivityStorage(4) {}
+
+int CtrAggregatorTest::WeeklyActivityStorageStub::ReadStorage(
+ std::string storage_bucket) {
+ return weeks_[storage_bucket];
+}
+
+void CtrAggregatorTest::WeeklyActivityStorageStub::WriteStorage(
+ std::string storage_bucket,
+ int value) {
+ weeks_[storage_bucket] = value;
+}
+
+void CtrAggregatorTest::Fill4Weeks() {
+ int weeks_to_record = 4;
+ for (int i = 0; i < weeks_to_record; i++) {
+ aggregator_->RecordImpression(true);
+ aggregator_->RecordImpression(false);
+ EXPECT_FALSE(aggregator_->HasPrevious28DayData());
+ aggregator_->IncrementWeek(1);
+ }
+ EXPECT_TRUE(aggregator_->HasPrevious28DayData());
+}
+
+// NaN has the property that it is not equal to itself.
+#define EXPECT_NAN(x) EXPECT_NE(x, x)
+
+TEST_F(CtrAggregatorTest, SimpleOperationTest) {
+ aggregator_->RecordImpression(true);
+ aggregator_->RecordImpression(false);
+ EXPECT_FALSE(aggregator_->HasPreviousWeekData());
+ EXPECT_EQ(0, aggregator_->GetPreviousWeekImpressions());
+ EXPECT_NAN(aggregator_->GetPreviousWeekCtr());
+
+ aggregator_->IncrementWeek(1);
+ EXPECT_TRUE(aggregator_->HasPreviousWeekData());
+ EXPECT_EQ(2, aggregator_->GetPreviousWeekImpressions());
+ EXPECT_FLOAT_EQ(0.5f, aggregator_->GetPreviousWeekCtr());
+}
+
+TEST_F(CtrAggregatorTest, MultiWeekTest) {
+ Fill4Weeks();
+ aggregator_->RecordImpression(false);
+ aggregator_->IncrementWeek(1);
+ EXPECT_TRUE(aggregator_->HasPrevious28DayData());
+ EXPECT_FLOAT_EQ(static_cast<float>(3.0 / 7),
+ aggregator_->GetPrevious28DayCtr());
+ aggregator_->RecordImpression(false);
+ aggregator_->IncrementWeek(1);
+ EXPECT_TRUE(aggregator_->HasPrevious28DayData());
+ EXPECT_FLOAT_EQ(static_cast<float>(2.0 / 6),
+ aggregator_->GetPrevious28DayCtr());
+}
+
+TEST_F(CtrAggregatorTest, SkipOneWeekTest) {
+ Fill4Weeks();
+ aggregator_->IncrementWeek(1);
+ EXPECT_EQ(0, aggregator_->GetPreviousWeekCtr());
+ EXPECT_FLOAT_EQ(static_cast<float>(3.0 / 6),
+ aggregator_->GetPrevious28DayCtr());
+}
+
+TEST_F(CtrAggregatorTest, SkipThreeWeeksTest) {
+ Fill4Weeks();
+ aggregator_->IncrementWeek(3);
+ EXPECT_EQ(0, aggregator_->GetPreviousWeekCtr());
+ EXPECT_FLOAT_EQ(static_cast<float>(1.0 / 2),
+ aggregator_->GetPrevious28DayCtr());
+}
+
+TEST_F(CtrAggregatorTest, SkipFourWeeksTest) {
+ Fill4Weeks();
+ aggregator_->IncrementWeek(4);
+ EXPECT_EQ(0, aggregator_->GetPreviousWeekCtr());
+ EXPECT_EQ(0, aggregator_->GetPrevious28DayCtr());
+}
+
+} // namespace contextual_search
diff --git a/chromium/components/contextual_search/browser/weekly_activity_storage.cc b/chromium/components/contextual_search/browser/weekly_activity_storage.cc
new file mode 100644
index 00000000000..485a4b989bb
--- /dev/null
+++ b/chromium/components/contextual_search/browser/weekly_activity_storage.cc
@@ -0,0 +1,129 @@
+// 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 "components/contextual_search/browser/weekly_activity_storage.h"
+
+#include <algorithm> // std::min
+
+#include "base/logging.h"
+
+namespace {
+
+// Keys for ChromePreferenceManager storage of oldest and newest week written.
+const char kOldestWeekWrittenKey[] = "contextual_search_oldest_week";
+const char kNewestWeekWrittenKey[] = "contextual_search_newest_week";
+// Prefixes for ChromePreferenceManager storage keyed by week.
+const char kClicksWeekKeyPrefix[] = "contextual_search_clicks_week_";
+const char kImpressionsWeekKeyPrefix[] = "contextual_search_impressions_week_";
+
+// Used for validation in debug build. Week numbers are > 2300 as of year 2016.
+const int kReasonableMinWeek = 2000;
+
+} // namespace
+
+namespace contextual_search {
+
+WeeklyActivityStorage::WeeklyActivityStorage(int weeks_needed) {
+ weeks_needed_ = weeks_needed;
+}
+
+WeeklyActivityStorage::~WeeklyActivityStorage() {}
+
+int WeeklyActivityStorage::ReadClicks(int week_number) {
+ std::string key = GetWeekClicksKey(week_number);
+ return ReadInt(key);
+}
+
+void WeeklyActivityStorage::WriteClicks(int week_number, int value) {
+ std::string key = GetWeekClicksKey(week_number);
+ WriteInt(key, value);
+}
+
+int WeeklyActivityStorage::ReadImpressions(int week_number) {
+ std::string key = GetWeekImpressionsKey(week_number);
+ return ReadInt(key);
+}
+
+void WeeklyActivityStorage::WriteImpressions(int week_number, int value) {
+ std::string key = GetWeekImpressionsKey(week_number);
+ WriteInt(key, value);
+}
+
+bool WeeklyActivityStorage::HasData(int week_number) {
+ return ReadInt(kOldestWeekWrittenKey) <= week_number &&
+ ReadInt(kNewestWeekWrittenKey) >= week_number;
+}
+
+void WeeklyActivityStorage::ClearData(int week_number) {
+ WriteImpressions(week_number, 0);
+ WriteClicks(week_number, 0);
+}
+
+void WeeklyActivityStorage::AdvanceToWeek(int week_number) {
+ EnsureHasActivity(week_number);
+}
+
+// private
+
+std::string WeeklyActivityStorage::GetWeekImpressionsKey(int which_week) {
+ return kImpressionsWeekKeyPrefix + GetWeekKey(which_week);
+}
+
+std::string WeeklyActivityStorage::GetWeekClicksKey(int which_week) {
+ return kClicksWeekKeyPrefix + GetWeekKey(which_week);
+}
+
+// Round-robin implementation:
+// GetWeekKey and EnsureHasActivity are implemented with a round-robin
+// implementation that simply recycles usage of the last N weeks, where N is
+// less than weeks_needed_.
+
+std::string WeeklyActivityStorage::GetWeekKey(int which_week) {
+ return std::to_string(which_week % (weeks_needed_ + 1));
+}
+
+void WeeklyActivityStorage::EnsureHasActivity(int which_week) {
+ DCHECK(which_week > kReasonableMinWeek);
+
+ // If still on the newest week we're done!
+ int newest_week = ReadInt(kNewestWeekWrittenKey);
+ if (newest_week == which_week)
+ return;
+
+ // Update the newest and oldest week written.
+ if (which_week > newest_week) {
+ WriteInt(kNewestWeekWrittenKey, which_week);
+ }
+ int oldest_week = ReadInt(kOldestWeekWrittenKey);
+ if (oldest_week == 0 || oldest_week > which_week)
+ WriteInt(kOldestWeekWrittenKey, which_week);
+
+ // Any stale weeks to update?
+ if (newest_week == 0)
+ return;
+
+ // Moved to some new week beyond the newest previously recorded.
+ // Since we recycle storage we must clear the new week and all that we
+ // may have skipped since our last access.
+ int weeks_to_clear = std::min(which_week - newest_week, weeks_needed_);
+ int week = which_week;
+ while (weeks_to_clear > 0) {
+ WriteInt(GetWeekImpressionsKey(week), 0);
+ WriteInt(GetWeekClicksKey(week), 0);
+ week--;
+ weeks_to_clear--;
+ }
+}
+
+// Storage access bottlenecks
+
+int WeeklyActivityStorage::ReadInt(std::string storage_bucket) {
+ return ReadStorage(storage_bucket);
+}
+
+void WeeklyActivityStorage::WriteInt(std::string storage_bucket, int value) {
+ WriteStorage(storage_bucket, value);
+}
+
+} // namespace contextual_search
diff --git a/chromium/components/contextual_search/browser/weekly_activity_storage.h b/chromium/components/contextual_search/browser/weekly_activity_storage.h
new file mode 100644
index 00000000000..15cf9284db7
--- /dev/null
+++ b/chromium/components/contextual_search/browser/weekly_activity_storage.h
@@ -0,0 +1,88 @@
+// 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 COMPONENTS_CONTEXTUAL_SEARCH_BROWSER_WEEKLY_ACTIVITY_STORAGE_H_
+#define COMPONENTS_CONTEXTUAL_SEARCH_BROWSER_WEEKLY_ACTIVITY_STORAGE_H_
+
+#include <string>
+#include <unordered_map>
+
+#include "base/macros.h"
+
+namespace contextual_search {
+
+// An abstract class that stores weekly user interaction data in device-specific
+// integer storage. Only a limited storage window is supported, set through the
+// constructor. Allows callers to read and write user actions to persistent
+// storage on the device by overriding the ReadStorage and WriteStorage calls.
+// A user view of some UX is an "Impression", and user interaction is considered
+// a "Click" even if the triggering gesture was something else. Together they
+// produce the Click-Through-Rate, or CTR.
+class WeeklyActivityStorage {
+ public:
+ // Constructs an instance that will manage at least |weeks_needed| weeks of
+ // data.
+ WeeklyActivityStorage(int weeks_needed);
+ virtual ~WeeklyActivityStorage();
+
+ // Advances the accessible storage range to end at the given |week_number|.
+ // Since only a limited number of storage weeks are supported, advancing to
+ // a different week makes data from weeks than the range size inaccessible.
+ // This must be called for each week before reading or writing any data
+ // for that week.
+ // HasData will return true for all the weeks that still have accessible data.
+ void AdvanceToWeek(int week_number);
+
+ // Returns the number of clicks for the given week.
+ int ReadClicks(int week_number);
+ // Writes |value| into the number of clicks for the given |week_number|.
+ void WriteClicks(int week_number, int value);
+
+ // Returns the number of impressions for the given week.
+ int ReadImpressions(int week_number);
+ // Writes |value| into the number of impressions for the given |week_number|.
+ void WriteImpressions(int week_number, int value);
+
+ // Returns whether the given |week_number| has data, based on whether
+ // InitData has ever been called for that week.
+ bool HasData(int week_number);
+ // Clears the click and impression counters for the given |week_number|.
+ void ClearData(int week_number);
+
+ // Reads and returns the value keyed by |storage_bucket|.
+ // If there is no stored value associated with the given bucket then 0 is
+ // returned.
+ virtual int ReadStorage(std::string storage_bucket) = 0;
+ // Overwrites the |value| to the storage bucket keyed by |storage_bucket|,
+ // regardless of whether there is an existing value in the given bucket.
+ virtual void WriteStorage(std::string storage_bucket, int value) = 0;
+
+ private:
+ // Returns the string key of the storage bin for the given week |which_week|.
+ std::string GetWeekKey(int which_week);
+ // Returns the string key for the "clicks" storage bin for the given week
+ // |which_week|.
+ std::string GetWeekClicksKey(int which_week);
+ // Returns the string key for the "impressions" storage bin for the given week
+ // |which_week|.
+ std::string GetWeekImpressionsKey(int which_week);
+
+ // Reads and returns the integer keyed by |storage_key|.
+ // If there is no value for the given key then 0 is returned.
+ int ReadInt(std::string storage_key);
+ // Writes the integer |value| to the storage bucket keyed by |storage_key|.
+ void WriteInt(std::string storage_key, int value);
+
+ // Ensures that activity data is initialized for the given week |which_week|.
+ void EnsureHasActivity(int which_week);
+
+ // The number of weeks of data that this instance needs to support.
+ int weeks_needed_;
+
+ DISALLOW_COPY_AND_ASSIGN(WeeklyActivityStorage);
+};
+
+} // namespace contextual_search
+
+#endif // COMPONENTS_CONTEXTUAL_SEARCH_BROWSER_WEEKLY_ACTIVITY_STORAGE_H_
diff --git a/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.cc b/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.cc
index 2991d2f1d54..9214a7772b5 100644
--- a/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.cc
+++ b/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.cc
@@ -10,6 +10,7 @@
#include "components/contextual_search/renderer/contextual_search_wrapper.h"
#include "components/contextual_search/renderer/overlay_page_notifier_service_impl.h"
#include "content/public/renderer/render_frame.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/shell/public/cpp/interface_registry.h"
#include "v8/include/v8.h"
@@ -35,8 +36,10 @@ void OverlayJsRenderFrameObserver::RegisterMojoInterface() {
void OverlayJsRenderFrameObserver::CreateOverlayPageNotifierService(
mojo::InterfaceRequest<mojom::OverlayPageNotifierService> request) {
- // This is strongly bound to and owned by the pipe.
- new OverlayPageNotifierServiceImpl(this, std::move(request));
+ mojo::MakeStrongBinding(
+ base::MakeUnique<OverlayPageNotifierServiceImpl>(
+ weak_factory_.GetWeakPtr()),
+ std::move(request));
}
void OverlayJsRenderFrameObserver::SetIsContextualSearchOverlay() {
@@ -53,12 +56,19 @@ void OverlayJsRenderFrameObserver::DidFinishLoad() {
// If no message about the Contextual Search overlay was received at this
// point, there will not be one; remove the OverlayPageNotifierService
// from the registry.
- render_frame()
- ->GetInterfaceRegistry()
- ->RemoveInterface<mojom::OverlayPageNotifierService>();
+ DestroyOverlayPageNotifierService();
+}
+
+void OverlayJsRenderFrameObserver::DestroyOverlayPageNotifierService() {
+ if (render_frame()) {
+ render_frame()
+ ->GetInterfaceRegistry()
+ ->RemoveInterface<mojom::OverlayPageNotifierService>();
+ }
}
void OverlayJsRenderFrameObserver::OnDestruct() {
+ DestroyOverlayPageNotifierService();
delete this;
}
diff --git a/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.h b/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.h
index da88b520bb9..cbde3c290be 100644
--- a/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.h
+++ b/chromium/components/contextual_search/renderer/overlay_js_render_frame_observer.h
@@ -38,8 +38,12 @@ class OverlayJsRenderFrameObserver : public content::RenderFrameObserver {
// Add the mojo interface to a RenderFrame's shell::InterfaceRegistry.
void RegisterMojoInterface();
+ // Creates the OverlayPageNotifierService connecting the browser to this
+ // observer.
void CreateOverlayPageNotifierService(
mojo::InterfaceRequest<mojom::OverlayPageNotifierService> request);
+ // Destroys the OverlayPageNotifierService.
+ void DestroyOverlayPageNotifierService();
// Track if the current page is presented in the contextual search overlay.
bool is_contextual_search_overlay_;
diff --git a/chromium/components/contextual_search/renderer/overlay_page_notifier_service_impl.cc b/chromium/components/contextual_search/renderer/overlay_page_notifier_service_impl.cc
index bbe06f4087c..c0ebfc4c607 100644
--- a/chromium/components/contextual_search/renderer/overlay_page_notifier_service_impl.cc
+++ b/chromium/components/contextual_search/renderer/overlay_page_notifier_service_impl.cc
@@ -11,14 +11,14 @@
namespace contextual_search {
OverlayPageNotifierServiceImpl::OverlayPageNotifierServiceImpl(
- OverlayJsRenderFrameObserver* observer,
- mojo::InterfaceRequest<mojom::OverlayPageNotifierService> request)
- : binding_(this, std::move(request)), overlay_js_observer_(observer) {}
+ base::WeakPtr<OverlayJsRenderFrameObserver> observer)
+ : overlay_js_observer_(observer) {}
OverlayPageNotifierServiceImpl::~OverlayPageNotifierServiceImpl() {}
void OverlayPageNotifierServiceImpl::NotifyIsContextualSearchOverlay() {
- overlay_js_observer_->SetIsContextualSearchOverlay();
+ if (overlay_js_observer_ != nullptr)
+ overlay_js_observer_->SetIsContextualSearchOverlay();
}
} // namespace contextual_search
diff --git a/chromium/components/contextual_search/renderer/overlay_page_notifier_service_impl.h b/chromium/components/contextual_search/renderer/overlay_page_notifier_service_impl.h
index 48de3dffecb..b38264430be 100644
--- a/chromium/components/contextual_search/renderer/overlay_page_notifier_service_impl.h
+++ b/chromium/components/contextual_search/renderer/overlay_page_notifier_service_impl.h
@@ -6,17 +6,16 @@
#define COMPONENTS_CONTEXTUAL_SEARCH_RENDERER_OVERLAY_PAGE_NOTIFIER_SERVICE_IMPL_H_
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "components/contextual_search/common/overlay_page_notifier_service.mojom.h"
#include "components/contextual_search/renderer/overlay_js_render_frame_observer.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
namespace contextual_search {
class OverlayJsRenderFrameObserver;
// mojom::OverlayPageNotifierService is responsible for listening to the browser
-// for
-// messages about whether a page is presented in an overlay panel.
+// for messages about whether a page is presented in an overlay panel.
// No message is received if the page is not presented in an overlay panel.
// This service should be removed from the registry once the page is done
// loading.
@@ -24,16 +23,14 @@ class OverlayPageNotifierServiceImpl
: public mojom::OverlayPageNotifierService {
public:
explicit OverlayPageNotifierServiceImpl(
- OverlayJsRenderFrameObserver* observer,
- mojo::InterfaceRequest<mojom::OverlayPageNotifierService> request);
+ base::WeakPtr<OverlayJsRenderFrameObserver> observer);
~OverlayPageNotifierServiceImpl() override;
// Implementation of mojo interface OverlayPageNotifierService.
void NotifyIsContextualSearchOverlay() override;
private:
- mojo::StrongBinding<mojom::OverlayPageNotifierService> binding_;
- OverlayJsRenderFrameObserver* overlay_js_observer_;
+ base::WeakPtr<OverlayJsRenderFrameObserver> overlay_js_observer_;
DISALLOW_COPY_AND_ASSIGN(OverlayPageNotifierServiceImpl);
};
diff --git a/chromium/components/cookie_config.gypi b/chromium/components/cookie_config.gypi
deleted file mode 100644
index 4c3e8f7ec00..00000000000
--- a/chromium/components/cookie_config.gypi
+++ /dev/null
@@ -1,26 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/cookie_config
- 'target_name': 'cookie_config',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- 'os_crypt',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'cookie_config/cookie_store_util.cc',
- 'cookie_config/cookie_store_util.h',
- ],
- },
- ],
-}
-
diff --git a/chromium/components/cookie_config/BUILD.gn b/chromium/components/cookie_config/BUILD.gn
index be3bb12497b..d5ed75dc330 100644
--- a/chromium/components/cookie_config/BUILD.gn
+++ b/chromium/components/cookie_config/BUILD.gn
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/cookie_config.gypi:cookie_config
-source_set("cookie_config") {
+static_library("cookie_config") {
sources = [
"cookie_store_util.cc",
"cookie_store_util.h",
diff --git a/chromium/components/copresence.gypi b/chromium/components/copresence.gypi
deleted file mode 100644
index 2aaf6f72256..00000000000
--- a/chromium/components/copresence.gypi
+++ /dev/null
@@ -1,98 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'copresence',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../third_party/webrtc/common_audio/common_audio.gyp:common_audio',
- 'audio_modem',
- 'copresence_proto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'copresence/copresence_manager_impl.cc',
- 'copresence/copresence_state_impl.cc',
- 'copresence/copresence_state_impl.h',
- 'copresence/copresence_switches.cc',
- 'copresence/copresence_switches.h',
- 'copresence/handlers/audio/audio_directive_handler.h',
- 'copresence/handlers/audio/audio_directive_handler_impl.cc',
- 'copresence/handlers/audio/audio_directive_handler_impl.h',
- 'copresence/handlers/audio/audio_directive_list.cc',
- 'copresence/handlers/audio/audio_directive_list.h',
- 'copresence/handlers/audio/tick_clock_ref_counted.cc',
- 'copresence/handlers/audio/tick_clock_ref_counted.h',
- 'copresence/handlers/directive_handler.h',
- 'copresence/handlers/directive_handler_impl.cc',
- 'copresence/handlers/directive_handler_impl.h',
- 'copresence/handlers/gcm_handler.h',
- 'copresence/handlers/gcm_handler_impl.cc',
- 'copresence/handlers/gcm_handler_impl.h',
- 'copresence/public/copresence_constants.h',
- 'copresence/public/copresence_delegate.h',
- 'copresence/public/copresence_manager.h',
- 'copresence/public/copresence_observer.h',
- 'copresence/public/copresence_state.h',
- 'copresence/rpc/http_post.cc',
- 'copresence/rpc/http_post.h',
- 'copresence/rpc/rpc_handler.cc',
- 'copresence/rpc/rpc_handler.h',
- 'copresence/timed_map.h',
- 'copresence/tokens.cc',
- 'copresence/tokens.h',
- ],
- 'export_dependent_settings': [
- 'copresence_proto',
- ],
- },
- {
- 'target_name': 'copresence_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'copresence_proto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'copresence/test/fake_directive_handler.cc',
- 'copresence/test/fake_directive_handler.h',
- ],
- 'export_dependent_settings': [
- 'copresence_proto',
- ],
- },
- {
- # Protobuf compiler / generate rule for copresence.
- # GN version: //components/copresence/proto
- # Note: These protos are auto-generated from the protos of the
- # Copresence server. Currently this strips all formatting and comments
- # but makes sure that we are always using up to date protos.
- 'target_name': 'copresence_proto',
- 'type': 'static_library',
- 'sources': [
- 'copresence/proto/codes.proto',
- 'copresence/proto/config_data.proto',
- 'copresence/proto/data.proto',
- 'copresence/proto/enums.proto',
- 'copresence/proto/identity.proto',
- 'copresence/proto/push_message.proto',
- 'copresence/proto/rpcs.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'copresence/proto',
- 'proto_out_dir': 'components/copresence/proto',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
- ],
-}
diff --git a/chromium/components/copresence/BUILD.gn b/chromium/components/copresence/BUILD.gn
deleted file mode 100644
index 4f697fc7bbe..00000000000
--- a/chromium/components/copresence/BUILD.gn
+++ /dev/null
@@ -1,87 +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.
-
-source_set("copresence") {
- sources = [
- "copresence_manager_impl.cc",
- "copresence_state_impl.cc",
- "copresence_state_impl.h",
- "copresence_switches.cc",
- "copresence_switches.h",
- "handlers/audio/audio_directive_handler.h",
- "handlers/audio/audio_directive_handler_impl.cc",
- "handlers/audio/audio_directive_handler_impl.h",
- "handlers/audio/audio_directive_list.cc",
- "handlers/audio/audio_directive_list.h",
- "handlers/audio/tick_clock_ref_counted.cc",
- "handlers/audio/tick_clock_ref_counted.h",
- "handlers/directive_handler.h",
- "handlers/directive_handler_impl.cc",
- "handlers/directive_handler_impl.h",
- "handlers/gcm_handler.h",
- "handlers/gcm_handler_impl.cc",
- "handlers/gcm_handler_impl.h",
- "public/copresence_constants.h",
- "public/copresence_delegate.h",
- "public/copresence_manager.h",
- "public/copresence_observer.h",
- "public/copresence_state.h",
- "rpc/http_post.cc",
- "rpc/http_post.h",
- "rpc/rpc_handler.cc",
- "rpc/rpc_handler.h",
- "timed_map.h",
- "tokens.cc",
- "tokens.h",
- ]
-
- deps = [
- "//base",
- "//components/audio_modem",
- "//components/copresence/proto",
- "//components/gcm_driver",
- "//google_apis",
- "//media",
- "//media:shared_memory_support",
- "//net",
- ]
-}
-
-source_set("test_support") {
- testonly = true
- sources = [
- "test/fake_directive_handler.cc",
- "test/fake_directive_handler.h",
- ]
- public_deps = [
- ":copresence",
- "//base",
- "//components/copresence/proto",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "copresence_state_unittest.cc",
- "handlers/audio/audio_directive_handler_unittest.cc",
- "handlers/audio/audio_directive_list_unittest.cc",
- "handlers/directive_handler_unittest.cc",
- "handlers/gcm_handler_unittest.cc",
- "rpc/http_post_unittest.cc",
- "rpc/rpc_handler_unittest.cc",
- "timed_map_unittest.cc",
- ]
- deps = [
- ":test_support",
- "//base",
- "//base/test:test_support",
- "//components/audio_modem:test_support",
- "//components/copresence/proto",
- "//components/gcm_driver:test_support",
- "//net:test_support",
- "//testing/gmock",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/copresence/DEPS b/chromium/components/copresence/DEPS
deleted file mode 100644
index 9a1a6d084dd..00000000000
--- a/chromium/components/copresence/DEPS
+++ /dev/null
@@ -1,8 +0,0 @@
-include_rules = [
- "+components/audio_modem/public",
- "+components/audio_modem/test",
- "+components/gcm_driver",
- "+google_apis",
- "+media/base",
- "+net",
-]
diff --git a/chromium/components/copresence/OWNERS b/chromium/components/copresence/OWNERS
deleted file mode 100644
index 38d2b19b7c7..00000000000
--- a/chromium/components/copresence/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-rkc@chromium.org
-ckehoe@chromium.org
-xiyuan@chromium.org
-derat@chromium.org
diff --git a/chromium/components/copresence/copresence_manager_impl.cc b/chromium/components/copresence/copresence_manager_impl.cc
deleted file mode 100644
index 956391f39c6..00000000000
--- a/chromium/components/copresence/copresence_manager_impl.cc
+++ /dev/null
@@ -1,270 +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 "components/copresence/copresence_manager_impl.h"
-
-#include <map>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "components/audio_modem/public/whispernet_client.h"
-#include "components/copresence/copresence_state_impl.h"
-#include "components/copresence/handlers/directive_handler_impl.h"
-#include "components/copresence/handlers/gcm_handler_impl.h"
-#include "components/copresence/proto/rpcs.pb.h"
-#include "components/copresence/rpc/rpc_handler.h"
-
-using google::protobuf::RepeatedPtrField;
-
-using audio_modem::AUDIBLE;
-using audio_modem::AudioToken;
-using audio_modem::INAUDIBLE;
-
-namespace {
-
-const int kPollTimerIntervalMs = 3000; // milliseconds.
-const int kAudioCheckIntervalMs = 1000; // milliseconds.
-
-const int kQueuedMessageTimeout = 10; // seconds.
-const int kMaxQueuedMessages = 1000;
-
-} // namespace
-
-namespace copresence {
-
-bool SupportedTokenMedium(const TokenObservation& token) {
- for (const TokenSignals& signals : token.signals()) {
- if (signals.medium() == AUDIO_ULTRASOUND_PASSBAND ||
- signals.medium() == AUDIO_AUDIBLE_DTMF)
- return true;
- }
- return false;
-}
-
-
-// Public functions.
-
-CopresenceManagerImpl::CopresenceManagerImpl(CopresenceDelegate* delegate)
- : delegate_(delegate),
- whispernet_init_callback_(
- base::Bind(&CopresenceManagerImpl::WhispernetInitComplete,
- // This callback gets cancelled when we are destroyed.
- base::Unretained(this))),
- init_failed_(false),
- state_(new CopresenceStateImpl),
- directive_handler_(new DirectiveHandlerImpl(
- // The directive handler and its descendants
- // will be destructed before the CopresenceState instance.
- base::Bind(&CopresenceStateImpl::UpdateDirectives,
- base::Unretained(state_.get())))),
- poll_timer_(new base::RepeatingTimer),
- audio_check_timer_(new base::RepeatingTimer),
- queued_messages_by_token_(
- base::TimeDelta::FromSeconds(kQueuedMessageTimeout),
- kMaxQueuedMessages) {
- DCHECK(delegate_);
- DCHECK(delegate_->GetWhispernetClient());
- // TODO(ckehoe): Handle whispernet initialization in the whispernet component.
- delegate_->GetWhispernetClient()->Initialize(
- whispernet_init_callback_.callback());
-
- MessagesCallback messages_callback = base::Bind(
- &CopresenceManagerImpl::DispatchMessages,
- // This will only be passed to objects that we own.
- base::Unretained(this));
-
- if (delegate->GetGCMDriver())
- gcm_handler_.reset(new GCMHandlerImpl(delegate->GetGCMDriver(),
- directive_handler_.get(),
- messages_callback));
-
- rpc_handler_.reset(new RpcHandler(delegate,
- directive_handler_.get(),
- state_.get(),
- gcm_handler_.get(),
- messages_callback));
-
- directive_handler_->Start(delegate_->GetWhispernetClient(),
- base::Bind(&CopresenceManagerImpl::ReceivedTokens,
- base::Unretained(this)));
-}
-
-CopresenceManagerImpl::~CopresenceManagerImpl() {
- whispernet_init_callback_.Cancel();
-}
-
-CopresenceState* CopresenceManagerImpl::state() {
- return state_.get();
-}
-
-// Returns false if any operations were malformed.
-void CopresenceManagerImpl::ExecuteReportRequest(
- const ReportRequest& request,
- const std::string& app_id,
- const std::string& auth_token,
- const StatusCallback& callback) {
- // If initialization has failed, reject all requests.
- if (init_failed_) {
- callback.Run(FAIL);
- return;
- }
-
- // We'll need to modify the ReportRequest, so we make our own copy to send.
- std::unique_ptr<ReportRequest> request_copy(new ReportRequest(request));
- rpc_handler_->SendReportRequest(std::move(request_copy), app_id, auth_token,
- callback);
-}
-
-
-// Private functions.
-
-void CopresenceManagerImpl::WhispernetInitComplete(bool success) {
- if (success) {
- DVLOG(3) << "Whispernet initialized successfully.";
- poll_timer_->Start(FROM_HERE,
- base::TimeDelta::FromMilliseconds(kPollTimerIntervalMs),
- base::Bind(&CopresenceManagerImpl::PollForMessages,
- base::Unretained(this)));
- audio_check_timer_->Start(
- FROM_HERE, base::TimeDelta::FromMilliseconds(kAudioCheckIntervalMs),
- base::Bind(&CopresenceManagerImpl::AudioCheck, base::Unretained(this)));
- } else {
- LOG(ERROR) << "Whispernet initialization failed!";
- init_failed_ = true;
- }
-}
-
-void CopresenceManagerImpl::ReceivedTokens(
- const std::vector<AudioToken>& tokens) {
- rpc_handler_->ReportTokens(tokens);
-
- for (const AudioToken audio_token : tokens) {
- const std::string& token_id = audio_token.token;
- DVLOG(3) << "Heard token: " << token_id;
-
- // Update the CopresenceState.
- ReceivedToken token(
- token_id,
- audio_token.audible ? AUDIO_AUDIBLE_DTMF : AUDIO_ULTRASOUND_PASSBAND,
- base::Time::Now());
- state_->UpdateReceivedToken(token);
-
- // Deliver messages that were pre-sent on this token.
- if (queued_messages_by_token_.HasKey(token_id)) {
- // Not const because we have to remove the required tokens for delivery.
- // We're going to delete this whole vector at the end anyway.
- RepeatedPtrField<SubscribedMessage>* messages =
- queued_messages_by_token_.GetMutableValue(token_id);
- DCHECK_GT(messages->size(), 0)
- << "Empty entry in queued_messages_by_token_";
-
- // These messages still have their required tokens stored, and
- // DispatchMessages() will still check for them. If we don't remove
- // the tokens before delivery, we'll just end up re-queuing the message.
- for (SubscribedMessage& message : *messages)
- message.mutable_required_token()->Clear();
-
- DVLOG(3) << "Delivering " << messages->size()
- << " message(s) pre-sent on token " << token_id;
- DispatchMessages(*messages);
-
- // The messages have been delivered, so we don't need to keep them
- // in the queue. Note that the token will still be reported
- // to the server (above), so we'll keep getting the message.
- // But we can now drop our local copy of it.
- int erase_count = queued_messages_by_token_.Erase(token_id);
- DCHECK_GT(erase_count, 0);
- }
- }
-}
-
-void CopresenceManagerImpl::AudioCheck() {
- if (!directive_handler_->GetCurrentAudioToken(AUDIBLE).empty() &&
- !directive_handler_->IsAudioTokenHeard(AUDIBLE)) {
- delegate_->HandleStatusUpdate(AUDIO_FAIL);
- } else if (!directive_handler_->GetCurrentAudioToken(INAUDIBLE).empty() &&
- !directive_handler_->IsAudioTokenHeard(INAUDIBLE)) {
- delegate_->HandleStatusUpdate(AUDIO_FAIL);
- }
-}
-
-// Report our currently playing tokens to the server.
-void CopresenceManagerImpl::PollForMessages() {
- const std::string& audible_token =
- directive_handler_->GetCurrentAudioToken(AUDIBLE);
- const std::string& inaudible_token =
- directive_handler_->GetCurrentAudioToken(INAUDIBLE);
-
- std::vector<AudioToken> tokens;
- if (!audible_token.empty())
- tokens.push_back(AudioToken(audible_token, true));
- if (!inaudible_token.empty())
- tokens.push_back(AudioToken(inaudible_token, false));
-
- if (!tokens.empty())
- rpc_handler_->ReportTokens(tokens);
-}
-
-void CopresenceManagerImpl::DispatchMessages(
- const RepeatedPtrField<SubscribedMessage>& messages) {
- if (messages.size() == 0)
- return;
-
- // Index the messages by subscription id.
- std::map<std::string, std::vector<Message>> messages_by_subscription;
- DVLOG(3) << "Processing " << messages.size() << " received message(s).";
- int immediate_message_count = 0;
- for (const SubscribedMessage& message : messages) {
- // If tokens are required for this message, queue it.
- // Otherwise stage it for delivery.
- if (message.required_token_size() > 0) {
- int supported_token_count = 0;
- for (const TokenObservation& token : message.required_token()) {
- if (SupportedTokenMedium(token)) {
- if (!queued_messages_by_token_.HasKey(token.token_id())) {
- queued_messages_by_token_.Add(
- token.token_id(), RepeatedPtrField<SubscribedMessage>());
- }
- RepeatedPtrField<SubscribedMessage>* queued_messages =
- queued_messages_by_token_.GetMutableValue(token.token_id());
- DCHECK(queued_messages);
- queued_messages->Add()->CopyFrom(message);
- supported_token_count++;
- }
- }
-
- if (supported_token_count > 0) {
- DVLOG(3) << "Queued message under " << supported_token_count
- << "token(s).";
- } else {
- VLOG(2) << "Discarded message that requires one of "
- << message.required_token_size()
- << " token(s), all on unsupported mediums.";
- }
- } else {
- immediate_message_count++;
- for (const std::string& subscription_id : message.subscription_id()) {
- messages_by_subscription[subscription_id].push_back(
- message.published_message());
- }
- }
- }
-
- // Send the messages for each subscription.
- DVLOG(3) << "Dispatching " << immediate_message_count << "message(s) for "
- << messages_by_subscription.size() << " subscription(s).";
- for (const auto& map_entry : messages_by_subscription) {
- // TODO(ckehoe): Once we have the app ID from the server, we need to pass
- // it in here and get rid of the app id registry from the main API class.
- const std::string& subscription = map_entry.first;
- const std::vector<Message>& messages = map_entry.second;
- delegate_->HandleMessages(std::string(), subscription, messages);
- }
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/copresence_manager_impl.h b/chromium/components/copresence/copresence_manager_impl.h
deleted file mode 100644
index 63cac4b2883..00000000000
--- a/chromium/components/copresence/copresence_manager_impl.h
+++ /dev/null
@@ -1,105 +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 COMPONENTS_COPRESENCE_COPRESENCE_MANAGER_IMPL_H_
-#define COMPONENTS_COPRESENCE_COPRESENCE_MANAGER_IMPL_H_
-
-#include <google/protobuf/repeated_field.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/cancelable_callback.h"
-#include "base/macros.h"
-#include "components/copresence/copresence_state_impl.h"
-#include "components/copresence/public/copresence_manager.h"
-#include "components/copresence/timed_map.h"
-
-namespace audio_modem {
-struct AudioToken;
-}
-
-namespace base {
-class Timer;
-}
-
-namespace net {
-class URLContextGetter;
-}
-
-namespace copresence {
-
-class DirectiveHandler;
-class GCMHandler;
-class ReportRequest;
-class RpcHandler;
-class SubscribedMessage;
-
-// The implementation for CopresenceManager. Responsible primarily for
-// client-side initialization. The RpcHandler handles all the details
-// of interacting with the server.
-// TODO(ckehoe, rkc): Add tests for this class.
-class CopresenceManagerImpl : public CopresenceManager {
- public:
- // The delegate is owned by the caller, and must outlive the manager.
- explicit CopresenceManagerImpl(CopresenceDelegate* delegate);
-
- ~CopresenceManagerImpl() override;
-
- // CopresenceManager overrides.
- CopresenceState* state() override;
- void ExecuteReportRequest(const ReportRequest& request,
- const std::string& app_id,
- const std::string& auth_token,
- const StatusCallback& callback) override;
-
- private:
- // Complete initialization when Whispernet is available.
- void WhispernetInitComplete(bool success);
-
- // Handle tokens decoded by Whispernet.
- // TODO(ckehoe): Replace AudioToken with ReceivedToken.
- void ReceivedTokens(const std::vector<audio_modem::AudioToken>& tokens);
-
- // Verifies that we can hear the audio we're playing.
- // This gets called every kAudioCheckIntervalMs milliseconds.
- void AudioCheck();
-
- // This gets called every kPollTimerIntervalMs milliseconds
- // to poll the server for new messages.
- void PollForMessages();
-
- // Send SubscribedMessages to the appropriate clients.
- void DispatchMessages(
- const google::protobuf::RepeatedPtrField<SubscribedMessage>&
- subscribed_messages);
-
- // Belongs to the caller.
- CopresenceDelegate* const delegate_;
-
- // We use a CancelableCallback here because Whispernet
- // does not provide a way to unregister its init callback.
- base::CancelableCallback<void(bool)> whispernet_init_callback_;
-
- bool init_failed_;
-
- // The RpcHandler makes calls to the other objects here, so it must come last.
- std::unique_ptr<CopresenceStateImpl> state_;
- std::unique_ptr<DirectiveHandler> directive_handler_;
- std::unique_ptr<GCMHandler> gcm_handler_;
- std::unique_ptr<RpcHandler> rpc_handler_;
-
- std::unique_ptr<base::Timer> poll_timer_;
- std::unique_ptr<base::Timer> audio_check_timer_;
-
- TimedMap<std::string, google::protobuf::RepeatedPtrField<SubscribedMessage>>
- queued_messages_by_token_;
-
- DISALLOW_COPY_AND_ASSIGN(CopresenceManagerImpl);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_COPRESENCE_MANAGER_IMPL_H_
diff --git a/chromium/components/copresence/copresence_state_impl.cc b/chromium/components/copresence/copresence_state_impl.cc
deleted file mode 100644
index 9a873d32e82..00000000000
--- a/chromium/components/copresence/copresence_state_impl.cc
+++ /dev/null
@@ -1,179 +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 <set>
-
-#include "base/logging.h"
-#include "base/time/time.h"
-#include "components/copresence/copresence_state_impl.h"
-#include "components/copresence/proto/data.pb.h"
-#include "components/copresence/public/copresence_constants.h"
-#include "components/copresence/public/copresence_observer.h"
-
-namespace copresence {
-
-namespace {
-
-template<typename TokenType>
-void HandleCommonFields(const TokenType& new_token, TokenType* current_token) {
- if (current_token->id.empty()) {
- current_token->id = new_token.id;
- current_token->medium = new_token.medium;
- current_token->start_time = new_token.start_time;
- } else {
- DCHECK_EQ(new_token.id, current_token->id);
- DCHECK_EQ(new_token.medium, current_token->medium);
- DCHECK(new_token.start_time.is_null() ||
- new_token.start_time == current_token->start_time);
- }
-}
-
-void UpdateToken(const TransmittedToken& new_token,
- TransmittedToken* current_token) {
- HandleCommonFields(new_token, current_token);
-
- current_token->stop_time = new_token.stop_time;
- current_token->broadcast_confirmed = new_token.broadcast_confirmed;
-}
-
-void UpdateToken(const ReceivedToken& new_token,
- ReceivedToken* current_token) {
- HandleCommonFields(new_token, current_token);
-
- current_token->last_time = new_token.last_time;
- if (new_token.valid != ReceivedToken::UNKNOWN)
- current_token->valid = new_token.valid;
-}
-
-} // namespace
-
-
-// Public functions.
-
-CopresenceStateImpl::CopresenceStateImpl() {}
-
-CopresenceStateImpl::~CopresenceStateImpl() {}
-
-void CopresenceStateImpl::AddObserver(CopresenceObserver* observer) {
- DCHECK(observer);
- observers_.AddObserver(observer);
-}
-
-void CopresenceStateImpl::RemoveObserver(CopresenceObserver* observer) {
- DCHECK(observer);
- observers_.RemoveObserver(observer);
-}
-
-const std::vector<Directive>& CopresenceStateImpl::active_directives() const {
- return active_directives_;
-}
-
-const std::map<std::string, TransmittedToken>&
-CopresenceStateImpl::transmitted_tokens() const {
- return transmitted_tokens_;
-}
-
-const std::map<std::string, ReceivedToken>&
-CopresenceStateImpl::received_tokens() const {
- return received_tokens_;
-}
-
-// TODO(ckehoe): Only send updates if the directives have really changed.
-void CopresenceStateImpl::UpdateDirectives(
- const std::vector<Directive>& directives) {
- active_directives_ = directives;
- UpdateTransmittingTokens();
- FOR_EACH_OBSERVER(CopresenceObserver, observers_, DirectivesUpdated());
-}
-
-void CopresenceStateImpl::UpdateTransmittedToken(
- const TransmittedToken& token) {
- UpdateToken(token, &transmitted_tokens_[token.id]);
- FOR_EACH_OBSERVER(CopresenceObserver,
- observers_,
- TokenTransmitted(transmitted_tokens_[token.id]));
-}
-
-// TODO(ckehoe): Check which tokens are no longer heard and report them lost.
-void CopresenceStateImpl::UpdateReceivedToken(const ReceivedToken& token) {
- DCHECK(!token.id.empty());
-
- // TODO(ckehoe): Have CopresenceManagerImpl::AudioCheck() use this to check
- // if we can hear our token, and delete the logic from the AudioManager.
- if (transmitted_tokens_.count(token.id) > 0) {
- transmitted_tokens_[token.id].broadcast_confirmed = true;
- FOR_EACH_OBSERVER(CopresenceObserver,
- observers_,
- TokenTransmitted(transmitted_tokens_[token.id]));
- } else {
- ReceivedToken& stored_token = received_tokens_[token.id];
- UpdateToken(token, &stored_token);
-
- // The decoder doesn't track when this token was heard before,
- // so it should just fill in the last_time.
- // If we've never seen this token, we populate the start time too.
- if (stored_token.start_time.is_null())
- stored_token.start_time = token.last_time;
-
- FOR_EACH_OBSERVER(CopresenceObserver,
- observers_,
- TokenReceived(stored_token));
- }
-}
-
-void CopresenceStateImpl::UpdateTokenStatus(const std::string& token_id,
- TokenStatus status) {
- if (transmitted_tokens_.count(token_id) > 0) {
- LOG_IF(ERROR, status != VALID)
- << "Broadcast token " << token_id << " is invalid";
- } else if (received_tokens_.count(token_id) > 0) {
- received_tokens_[token_id].valid = status == VALID ?
- ReceivedToken::VALID : ReceivedToken::INVALID;
- FOR_EACH_OBSERVER(CopresenceObserver,
- observers_,
- TokenReceived(received_tokens_[token_id]));
- } else {
- LOG(ERROR) << "Got status update for unrecognized token " << token_id;
- }
-}
-
-
-// Private functions.
-
-void CopresenceStateImpl::UpdateTransmittingTokens() {
- std::set<std::string> tokens_to_update;
- for (const auto& token_entry : transmitted_tokens_)
- tokens_to_update.insert(token_entry.first);
-
- for (const Directive& directive : active_directives_) {
- const TokenInstruction& instruction = directive.token_instruction();
- if (instruction.token_instruction_type() == TRANSMIT) {
- tokens_to_update.erase(instruction.token_id());
-
- TransmittedToken& token = transmitted_tokens_[instruction.token_id()];
- token.id = instruction.token_id();
- token.medium = instruction.medium();
- token.start_time = base::Time::Now();
- token.stop_time = base::Time::Now() +
- base::TimeDelta::FromMilliseconds(directive.ttl_millis());
-
- FOR_EACH_OBSERVER(CopresenceObserver,
- observers_,
- TokenTransmitted(token));
- }
- }
-
- // Tokens not updated above are no longer transmitting.
- base::Time now = base::Time::Now();
- for (const std::string& token : tokens_to_update) {
- if (transmitted_tokens_[token].stop_time > now)
- transmitted_tokens_[token].stop_time = now;
-
- FOR_EACH_OBSERVER(CopresenceObserver,
- observers_,
- TokenTransmitted(transmitted_tokens_[token]));
- }
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/copresence_state_impl.h b/chromium/components/copresence/copresence_state_impl.h
deleted file mode 100644
index 4b9bf7684db..00000000000
--- a/chromium/components/copresence/copresence_state_impl.h
+++ /dev/null
@@ -1,71 +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 COMPONENTS_COPRESENCE_COPRESENCE_STATE_IMPL_H_
-#define COMPONENTS_COPRESENCE_COPRESENCE_STATE_IMPL_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/copresence/proto/enums.pb.h"
-#include "components/copresence/public/copresence_state.h"
-
-namespace copresence {
-
-class Directive;
-struct ReceivedToken;
-struct TransmittedToken;
-
-// This class tracks the internal state of the copresence component
-// for debugging purposes. CopresenceState only allows observation,
-// but this class accepts updates from elsewhere in the component.
-class CopresenceStateImpl final : public CopresenceState {
- public:
- CopresenceStateImpl();
- ~CopresenceStateImpl() override;
-
- // CopresenceState overrides.
- void AddObserver(CopresenceObserver* observer) override;
- void RemoveObserver(CopresenceObserver* observer) override;
- const std::vector<Directive>& active_directives() const override;
- const std::map<std::string, TransmittedToken>&
- transmitted_tokens() const override;
- const std::map<std::string, ReceivedToken>&
- received_tokens() const override;
-
- // Update the current active directives.
- void UpdateDirectives(const std::vector<Directive>& directives);
-
- // Report transmitting a token.
- void UpdateTransmittedToken(const TransmittedToken& token);
-
- // Report receiving a token.
- void UpdateReceivedToken(const ReceivedToken& token);
-
- // Report the token state from the server.
- void UpdateTokenStatus(const std::string& token_id, TokenStatus status);
-
- private:
- // Reconcile the |active_directives_| against |transmitted_tokens_|.
- void UpdateTransmittingTokens();
-
- std::vector<Directive> active_directives_;
-
- // TODO(ckehoe): When we support more mediums, separate tokens by medium.
- // Otherwise tokens from different mediums could overwrite each other.
- // TODO(ckehoe): Limit the number of tokens stored.
- std::map<std::string, TransmittedToken> transmitted_tokens_;
- std::map<std::string, ReceivedToken> received_tokens_;
-
- base::ObserverList<CopresenceObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(CopresenceStateImpl);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_COPRESENCE_STATE_IMPL_H_
diff --git a/chromium/components/copresence/copresence_state_unittest.cc b/chromium/components/copresence/copresence_state_unittest.cc
deleted file mode 100644
index 4817e7e426b..00000000000
--- a/chromium/components/copresence/copresence_state_unittest.cc
+++ /dev/null
@@ -1,149 +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 <string>
-#include <vector>
-
-#include "base/time/time.h"
-#include "components/copresence/copresence_state_impl.h"
-#include "components/copresence/proto/data.pb.h"
-#include "components/copresence/public/copresence_observer.h"
-#include "components/copresence/tokens.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using testing::ElementsAre;
-using testing::Key;
-using testing::SizeIs;
-using testing::UnorderedElementsAre;
-
-// TODO(ckehoe): Test start and end time tracking.
-
-namespace google {
-namespace protobuf {
-
-bool operator==(const MessageLite& A, const MessageLite& B) {
- std::string serializedA;
- CHECK(A.SerializeToString(&serializedA));
-
- std::string serializedB;
- CHECK(B.SerializeToString(&serializedB));
-
- return serializedA == serializedB;
-}
-
-} // namespace protobuf
-} // namespace google
-
-namespace copresence {
-
-namespace {
-
-const base::Time kStartTime = base::Time::FromDoubleT(10);
-const base::Time kStopTime = base::Time::FromDoubleT(20);
-
-Directive CreateDirective(const std::string& token, bool transmit) {
- Directive directive;
- TokenInstruction* instruction = directive.mutable_token_instruction();
- instruction->set_token_id(token);
- instruction->set_medium(AUDIO_ULTRASOUND_PASSBAND);
- if (transmit)
- instruction->set_token_instruction_type(TRANSMIT);
- return directive;
-}
-
-template<typename TokenType>
-TokenType CreateToken(const std::string& id) {
- TokenType token;
- token.id = id;
- token.medium = AUDIO_ULTRASOUND_PASSBAND;
- token.start_time = kStartTime;
- return token;
-}
-
-} // namespace
-
-class CopresenceStateTest : public CopresenceObserver,
- public testing::Test {
- public:
- CopresenceStateTest() : directive_notifications_(0) {
- state_.AddObserver(this);
- }
-
- protected:
- CopresenceStateImpl state_;
-
- int directive_notifications_;
- std::vector<std::string> transmitted_updates_;
- std::vector<std::string> received_updates_;
-
- private:
- // CopresenceObserver implementation.
- void DirectivesUpdated() override {
- directive_notifications_++;
- }
- void TokenTransmitted(const TransmittedToken& token) override {
- transmitted_updates_.push_back(token.id);
- }
- void TokenReceived(const ReceivedToken& token) override {
- received_updates_.push_back(token.id);
- }
-};
-
-TEST_F(CopresenceStateTest, Directives) {
- std::vector<Directive> directives;
- directives.push_back(CreateDirective("transmit 1", true));
- directives.push_back(CreateDirective("transmit 2", true));
- directives.push_back(CreateDirective("receive", false));
- state_.UpdateDirectives(directives);
-
- EXPECT_EQ(1, directive_notifications_);
- EXPECT_EQ(directives, state_.active_directives());
- EXPECT_THAT(transmitted_updates_, ElementsAre("transmit 1", "transmit 2"));
- EXPECT_THAT(state_.transmitted_tokens(),
- UnorderedElementsAre(Key("transmit 1"), Key("transmit 2")));
-
- directives.clear();
- directives.push_back(CreateDirective("transmit 1", true));
- state_.UpdateDirectives(directives);
- EXPECT_EQ(2, directive_notifications_);
- EXPECT_EQ(directives, state_.active_directives());
- EXPECT_THAT(state_.transmitted_tokens(), SizeIs(2));
-}
-
-TEST_F(CopresenceStateTest, TransmittedTokens) {
- state_.UpdateTransmittedToken(CreateToken<TransmittedToken>("A"));
- state_.UpdateTransmittedToken(CreateToken<TransmittedToken>("B"));
-
- EXPECT_THAT(transmitted_updates_, ElementsAre("A", "B"));
- EXPECT_THAT(state_.transmitted_tokens(),
- UnorderedElementsAre(Key("A"), Key("B")));
-
- TransmittedToken tokenA = CreateToken<TransmittedToken>("A");
- tokenA.stop_time = kStopTime;
- state_.UpdateTransmittedToken(tokenA);
-
- EXPECT_THAT(transmitted_updates_, ElementsAre("A", "B", "A"));
- EXPECT_EQ(kStopTime, state_.transmitted_tokens().find("A")->second.stop_time);
-
- state_.UpdateReceivedToken(CreateToken<ReceivedToken>("B"));
- EXPECT_THAT(transmitted_updates_, ElementsAre("A", "B", "A", "B"));
- EXPECT_TRUE(state_.transmitted_tokens().find("B")
- ->second.broadcast_confirmed);
-}
-
-TEST_F(CopresenceStateTest, ReceivedTokens) {
- state_.UpdateReceivedToken(CreateToken<ReceivedToken>("A"));
- state_.UpdateReceivedToken(CreateToken<ReceivedToken>("B"));
-
- EXPECT_THAT(received_updates_, ElementsAre("A", "B"));
- EXPECT_THAT(state_.received_tokens(),
- UnorderedElementsAre(Key("A"), Key("B")));
-
- state_.UpdateTokenStatus("A", copresence::VALID);
- EXPECT_THAT(received_updates_, ElementsAre("A", "B", "A"));
- EXPECT_EQ(ReceivedToken::VALID,
- state_.received_tokens().find("A")->second.valid);
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/copresence_switches.cc b/chromium/components/copresence/copresence_switches.cc
deleted file mode 100644
index 026e7a25b89..00000000000
--- a/chromium/components/copresence/copresence_switches.cc
+++ /dev/null
@@ -1,18 +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 "components/copresence/copresence_switches.h"
-
-// TODO(ckehoe): Move these flags to the chrome://copresence page.
-
-namespace switches {
-
-// Address for calls to the Copresence server (via Apiary).
-// Defaults to https://www.googleapis.com/copresence/v2/copresence.
-const char kCopresenceServer[] = "copresence-server";
-
-// Apiary tracing token for calls to the Copresence server.
-const char kCopresenceTracingToken[] = "copresence-tracing-token";
-
-} // namespace switches
diff --git a/chromium/components/copresence/copresence_switches.h b/chromium/components/copresence/copresence_switches.h
deleted file mode 100644
index d60a589ffab..00000000000
--- a/chromium/components/copresence/copresence_switches.h
+++ /dev/null
@@ -1,17 +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 COMPONENTS_COPRESENCE_COPRESENCE_SWITCHES_H_
-#define COMPONENTS_COPRESENCE_COPRESENCE_SWITCHES_H_
-
-namespace switches {
-
-// All switches in alphabetical order. The switches should be documented
-// alongside the definition of their values in the .cc file.
-extern const char kCopresenceServer[];
-extern const char kCopresenceTracingToken[];
-
-} // namespace switches
-
-#endif // COMPONENTS_COPRESENCE_COPRESENCE_SWITCHES_H_
diff --git a/chromium/components/copresence/handlers/audio/audio_directive_handler.h b/chromium/components/copresence/handlers/audio/audio_directive_handler.h
deleted file mode 100644
index 91213c917a6..00000000000
--- a/chromium/components/copresence/handlers/audio/audio_directive_handler.h
+++ /dev/null
@@ -1,42 +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 COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_HANDLER_H_
-#define COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_HANDLER_H_
-
-#include <string>
-
-#include "components/audio_modem/public/whispernet_client.h"
-
-namespace copresence {
-
-class Directive;
-
-// The AudioDirectiveHandler handles audio transmit and receive instructions.
-class AudioDirectiveHandler {
- public:
- virtual ~AudioDirectiveHandler() {}
-
- // Do not use this class before calling this.
- virtual void Initialize(audio_modem::WhispernetClient* whispernet_client,
- const audio_modem::TokensCallback& tokens_cb) = 0;
-
- // Adds an instruction to our handler. The instruction will execute and be
- // removed after the ttl expires.
- virtual void AddInstruction(const Directive& directive,
- const std::string& op_id) = 0;
-
- // Removes all instructions associated with this operation id.
- virtual void RemoveInstructions(const std::string& op_id) = 0;
-
- // Returns the currently playing token.
- virtual const std::string PlayingToken(audio_modem::AudioType type) const = 0;
-
- // Returns if we have heard the currently playing audio token.
- virtual bool IsPlayingTokenHeard(audio_modem::AudioType type) const = 0;
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_HANDLER_H_
diff --git a/chromium/components/copresence/handlers/audio/audio_directive_handler_impl.cc b/chromium/components/copresence/handlers/audio/audio_directive_handler_impl.cc
deleted file mode 100644
index 5e73009cc67..00000000000
--- a/chromium/components/copresence/handlers/audio/audio_directive_handler_impl.cc
+++ /dev/null
@@ -1,241 +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 "components/copresence/handlers/audio/audio_directive_handler_impl.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/time/default_tick_clock.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "components/audio_modem/public/modem.h"
-#include "components/copresence/handlers/audio/audio_directive_list.h"
-#include "components/copresence/handlers/audio/tick_clock_ref_counted.h"
-#include "components/copresence/proto/data.pb.h"
-#include "components/copresence/public/copresence_constants.h"
-#include "media/base/audio_bus.h"
-
-using audio_modem::AUDIBLE;
-using audio_modem::INAUDIBLE;
-using audio_modem::TokenParameters;
-
-namespace copresence {
-
-namespace {
-
-base::TimeTicks GetEarliestEventTime(AudioDirectiveList* list,
- base::TimeTicks event_time) {
- std::unique_ptr<AudioDirective> active_directive = list->GetActiveDirective();
-
- if (!active_directive)
- return event_time;
- if (event_time.is_null())
- return active_directive->end_time;
-
- return std::min(active_directive->end_time, event_time);
-}
-
-void ConvertDirectives(const std::vector<AudioDirective>& in_directives,
- std::vector<Directive>* out_directives) {
- for (const AudioDirective& in_directive : in_directives)
- out_directives->push_back(in_directive.server_directive);
-}
-
-} // namespace
-
-
-// Public functions.
-
-AudioDirectiveHandlerImpl::AudioDirectiveHandlerImpl(
- const DirectivesCallback& update_directives_callback)
- : update_directives_callback_(update_directives_callback),
- audio_modem_(audio_modem::Modem::Create()),
- audio_event_timer_(new base::OneShotTimer),
- clock_(new TickClockRefCounted(new base::DefaultTickClock)) {}
-
-AudioDirectiveHandlerImpl::AudioDirectiveHandlerImpl(
- const DirectivesCallback& update_directives_callback,
- std::unique_ptr<audio_modem::Modem> audio_modem,
- std::unique_ptr<base::Timer> timer,
- const scoped_refptr<TickClockRefCounted>& clock)
- : update_directives_callback_(update_directives_callback),
- audio_modem_(std::move(audio_modem)),
- audio_event_timer_(std::move(timer)),
- clock_(clock) {}
-
-AudioDirectiveHandlerImpl::~AudioDirectiveHandlerImpl() {}
-
-void AudioDirectiveHandlerImpl::Initialize(
- audio_modem::WhispernetClient* whispernet_client,
- const audio_modem::TokensCallback& tokens_cb) {
- DCHECK(audio_modem_);
- audio_modem_->Initialize(whispernet_client, tokens_cb);
-
- DCHECK(transmits_lists_.empty());
- transmits_lists_.push_back(new AudioDirectiveList(clock_));
- transmits_lists_.push_back(new AudioDirectiveList(clock_));
-
- DCHECK(receives_lists_.empty());
- receives_lists_.push_back(new AudioDirectiveList(clock_));
- receives_lists_.push_back(new AudioDirectiveList(clock_));
-}
-
-void AudioDirectiveHandlerImpl::AddInstruction(
- const Directive& directive,
- const std::string& op_id) {
- DCHECK(transmits_lists_.size() == 2u && receives_lists_.size() == 2u)
- << "Call Initialize() before other AudioDirectiveHandler methods";
-
- const TokenInstruction& instruction = directive.token_instruction();
- base::TimeDelta ttl =
- base::TimeDelta::FromMilliseconds(directive.ttl_millis());
- const size_t token_length = directive.configuration().token_params().length();
-
- switch (instruction.token_instruction_type()) {
- case TRANSMIT:
- DVLOG(2) << "Audio Transmit Directive received. Token: "
- << instruction.token_id()
- << " with medium=" << instruction.medium()
- << " with TTL=" << ttl.InMilliseconds();
- DCHECK_GT(token_length, 0u);
- switch (instruction.medium()) {
- case AUDIO_ULTRASOUND_PASSBAND:
- audio_modem_->SetTokenParams(INAUDIBLE,
- TokenParameters(token_length));
- transmits_lists_[INAUDIBLE]->AddDirective(op_id, directive);
- audio_modem_->SetToken(INAUDIBLE, instruction.token_id());
- break;
- case AUDIO_AUDIBLE_DTMF:
- audio_modem_->SetTokenParams(AUDIBLE, TokenParameters(token_length));
- transmits_lists_[AUDIBLE]->AddDirective(op_id, directive);
- audio_modem_->SetToken(AUDIBLE, instruction.token_id());
- break;
- default:
- NOTREACHED();
- }
- break;
-
- case RECEIVE:
- DVLOG(2) << "Audio Receive Directive received."
- << " with medium=" << instruction.medium()
- << " with TTL=" << ttl.InMilliseconds();
- DCHECK_GT(token_length, 0u);
- switch (instruction.medium()) {
- case AUDIO_ULTRASOUND_PASSBAND:
- audio_modem_->SetTokenParams(INAUDIBLE,
- TokenParameters(token_length));
- receives_lists_[INAUDIBLE]->AddDirective(op_id, directive);
- break;
- case AUDIO_AUDIBLE_DTMF:
- audio_modem_->SetTokenParams(AUDIBLE, TokenParameters(token_length));
- receives_lists_[AUDIBLE]->AddDirective(op_id, directive);
- break;
- default:
- NOTREACHED();
- }
- break;
-
- case UNKNOWN_TOKEN_INSTRUCTION_TYPE:
- default:
- LOG(WARNING) << "Unknown Audio Transmit Directive received. type = "
- << instruction.token_instruction_type();
- }
-
- ProcessNextInstruction();
-}
-
-void AudioDirectiveHandlerImpl::RemoveInstructions(const std::string& op_id) {
- DCHECK(transmits_lists_.size() == 2u && receives_lists_.size() == 2u)
- << "Call Initialize() before other AudioDirectiveHandler methods";
-
- transmits_lists_[AUDIBLE]->RemoveDirective(op_id);
- transmits_lists_[INAUDIBLE]->RemoveDirective(op_id);
- receives_lists_[AUDIBLE]->RemoveDirective(op_id);
- receives_lists_[INAUDIBLE]->RemoveDirective(op_id);
-
- ProcessNextInstruction();
-}
-
-const std::string AudioDirectiveHandlerImpl::PlayingToken(
- audio_modem::AudioType type) const {
- return audio_modem_->GetToken(type);
-}
-
-bool AudioDirectiveHandlerImpl::IsPlayingTokenHeard(
- audio_modem::AudioType type) const {
- return audio_modem_->IsPlayingTokenHeard(type);
-}
-
-
-// Private functions.
-
-void AudioDirectiveHandlerImpl::ProcessNextInstruction() {
- DCHECK(audio_event_timer_);
- audio_event_timer_->Stop();
-
- // Change |audio_modem_| state for audible transmits.
- if (transmits_lists_[AUDIBLE]->GetActiveDirective())
- audio_modem_->StartPlaying(AUDIBLE);
- else
- audio_modem_->StopPlaying(AUDIBLE);
-
- // Change audio_modem_ state for inaudible transmits.
- if (transmits_lists_[INAUDIBLE]->GetActiveDirective())
- audio_modem_->StartPlaying(INAUDIBLE);
- else
- audio_modem_->StopPlaying(INAUDIBLE);
-
- // Change audio_modem_ state for audible receives.
- if (receives_lists_[AUDIBLE]->GetActiveDirective())
- audio_modem_->StartRecording(AUDIBLE);
- else
- audio_modem_->StopRecording(AUDIBLE);
-
- // Change audio_modem_ state for inaudible receives.
- if (receives_lists_[INAUDIBLE]->GetActiveDirective())
- audio_modem_->StartRecording(INAUDIBLE);
- else
- audio_modem_->StopRecording(INAUDIBLE);
-
- base::TimeTicks next_event_time;
- if (GetNextInstructionExpiry(&next_event_time)) {
- audio_event_timer_->Start(
- FROM_HERE,
- next_event_time - clock_->NowTicks(),
- base::Bind(&AudioDirectiveHandlerImpl::ProcessNextInstruction,
- base::Unretained(this)));
- }
-
- // TODO(crbug.com/436584): Instead of this, store the directives
- // in a single list, and prune them when expired.
- if (!update_directives_callback_.is_null()) {
- std::vector<Directive> directives;
- ConvertDirectives(transmits_lists_[AUDIBLE]->directives(), &directives);
- ConvertDirectives(transmits_lists_[INAUDIBLE]->directives(), &directives);
- ConvertDirectives(receives_lists_[AUDIBLE]->directives(), &directives);
- ConvertDirectives(receives_lists_[INAUDIBLE]->directives(), &directives);
- update_directives_callback_.Run(directives);
- }
-}
-
-bool AudioDirectiveHandlerImpl::GetNextInstructionExpiry(
- base::TimeTicks* expiry) {
- DCHECK(expiry);
-
- *expiry = GetEarliestEventTime(transmits_lists_[AUDIBLE], base::TimeTicks());
- *expiry = GetEarliestEventTime(transmits_lists_[INAUDIBLE], *expiry);
- *expiry = GetEarliestEventTime(receives_lists_[AUDIBLE], *expiry);
- *expiry = GetEarliestEventTime(receives_lists_[INAUDIBLE], *expiry);
-
- return !expiry->is_null();
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/handlers/audio/audio_directive_handler_impl.h b/chromium/components/copresence/handlers/audio/audio_directive_handler_impl.h
deleted file mode 100644
index 875f9941e2e..00000000000
--- a/chromium/components/copresence/handlers/audio/audio_directive_handler_impl.h
+++ /dev/null
@@ -1,86 +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 COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_HANDLER_IMPL_H_
-#define COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_HANDLER_IMPL_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
-#include "components/audio_modem/public/modem.h"
-#include "components/copresence/handlers/audio/audio_directive_handler.h"
-#include "components/copresence/public/copresence_constants.h"
-
-namespace base {
-class TimeTicks;
-class Timer;
-}
-
-namespace media {
-class AudioBusRefCounted;
-}
-
-namespace copresence {
-
-class AudioDirectiveList;
-class TickClockRefCounted;
-
-// The AudioDirectiveHandler handles audio transmit and receive instructions.
-// TODO(rkc): Currently since WhispernetClient can only have one token encoded
-// callback at a time, we need to have both the audible and inaudible in this
-// class. Investigate a better way to do this; a few options are abstracting
-// out token encoding to a separate class, or allowing whispernet to have
-// multiple callbacks for encoded tokens being sent back and have two versions
-// of this class.
-class AudioDirectiveHandlerImpl final : public AudioDirectiveHandler {
- public:
- explicit AudioDirectiveHandlerImpl(
- const DirectivesCallback& update_directives_callback);
- AudioDirectiveHandlerImpl(
- const DirectivesCallback& update_directives_callback,
- std::unique_ptr<audio_modem::Modem> audio_modem,
- std::unique_ptr<base::Timer> timer,
- const scoped_refptr<TickClockRefCounted>& clock);
-
- ~AudioDirectiveHandlerImpl() override;
-
- // AudioDirectiveHandler overrides:
- void Initialize(audio_modem::WhispernetClient* whispernet_client,
- const audio_modem::TokensCallback& tokens_cb) override;
- void AddInstruction(const Directive& directive,
- const std::string& op_id) override;
- void RemoveInstructions(const std::string& op_id) override;
- const std::string PlayingToken(audio_modem::AudioType type) const override;
- bool IsPlayingTokenHeard(audio_modem::AudioType type) const override;
-
- private:
- // Processes the next active instruction,
- // updating our audio manager state accordingly.
- void ProcessNextInstruction();
-
- // Returns the time that an instruction expires at. This will always return
- // the earliest expiry time among all the active receive and transmit
- // instructions. If we don't have any active instructions, returns false.
- bool GetNextInstructionExpiry(base::TimeTicks* next_event);
-
- DirectivesCallback update_directives_callback_;
- std::unique_ptr<audio_modem::Modem> audio_modem_;
- std::unique_ptr<base::Timer> audio_event_timer_;
- scoped_refptr<TickClockRefCounted> clock_;
-
- // Lists of transmits and receives, for both audible and inaudible tokens.
- // AUDIBLE = element 0, INAUDIBLE = element 1 (see copresence_constants.h).
- ScopedVector<AudioDirectiveList> transmits_lists_;
- ScopedVector<AudioDirectiveList> receives_lists_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioDirectiveHandlerImpl);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_HANDLER_IMPL_H_
diff --git a/chromium/components/copresence/handlers/audio/audio_directive_handler_unittest.cc b/chromium/components/copresence/handlers/audio/audio_directive_handler_unittest.cc
deleted file mode 100644
index d0de08affda..00000000000
--- a/chromium/components/copresence/handlers/audio/audio_directive_handler_unittest.cc
+++ /dev/null
@@ -1,179 +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 <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "base/timer/mock_timer.h"
-#include "components/audio_modem/public/modem.h"
-#include "components/audio_modem/test/random_samples.h"
-#include "components/audio_modem/test/stub_modem.h"
-#include "components/copresence/handlers/audio/audio_directive_handler_impl.h"
-#include "components/copresence/handlers/audio/tick_clock_ref_counted.h"
-#include "components/copresence/proto/data.pb.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using audio_modem::AUDIBLE;
-using audio_modem::AudioType;
-using audio_modem::INAUDIBLE;
-using audio_modem::StubModem;
-
-namespace copresence {
-
-namespace {
-
-const Directive CreateDirective(TokenInstructionType type,
- bool audible,
- int64_t ttl) {
- Directive directive;
- directive.mutable_token_instruction()->set_token_instruction_type(type);
- directive.mutable_token_instruction()->set_token_id("token");
- directive.mutable_token_instruction()->set_medium(audible ?
- AUDIO_AUDIBLE_DTMF : AUDIO_ULTRASOUND_PASSBAND);
- directive.set_ttl_millis(ttl);
- return directive;
-}
-
-} // namespace
-
-class AudioDirectiveHandlerTest : public testing::Test {
- public:
- AudioDirectiveHandlerTest() {
- modem_ptr_ = new StubModem;
- timer_ptr_ = new base::MockTimer(false, false);
- clock_ptr_ = new base::SimpleTestTickClock;
-
- directive_handler_.reset(new AudioDirectiveHandlerImpl(
- base::Bind(&AudioDirectiveHandlerTest::GetDirectiveUpdates,
- base::Unretained(this)),
- base::WrapUnique<audio_modem::Modem>(modem_ptr_),
- base::WrapUnique<base::Timer>(timer_ptr_),
- make_scoped_refptr(new TickClockRefCounted(clock_ptr_))));
- directive_handler_->Initialize(nullptr, audio_modem::TokensCallback());
- }
- ~AudioDirectiveHandlerTest() override {}
-
- protected:
- const std::vector<Directive>& current_directives() {
- return current_directives_;
- }
-
- bool IsPlaying(AudioType type) { return modem_ptr_->IsPlaying(type); }
-
- bool IsRecording(AudioType type) { return modem_ptr_->IsRecording(type); }
-
- // This order is important. We want the message loop to get created before
- // our the audio directive handler since the directive list ctor (invoked
- // from the directive handler ctor) will post tasks.
- base::MessageLoop message_loop_;
- std::unique_ptr<AudioDirectiveHandler> directive_handler_;
-
- std::vector<Directive> current_directives_;
-
- // Unowned.
- StubModem* modem_ptr_;
- base::MockTimer* timer_ptr_;
- base::SimpleTestTickClock* clock_ptr_;
-
- private:
- void GetDirectiveUpdates(const std::vector<Directive>& current_directives) {
- current_directives_ = current_directives;
- }
-
- DISALLOW_COPY_AND_ASSIGN(AudioDirectiveHandlerTest);
-};
-
-TEST_F(AudioDirectiveHandlerTest, Basic) {
- const int64_t kTtl = 10;
- directive_handler_->AddInstruction(CreateDirective(TRANSMIT, true, kTtl),
- "op_id1");
- directive_handler_->AddInstruction(CreateDirective(TRANSMIT, false, kTtl),
- "op_id1");
- directive_handler_->AddInstruction(CreateDirective(TRANSMIT, false, kTtl),
- "op_id2");
- directive_handler_->AddInstruction(CreateDirective(RECEIVE, false, kTtl),
- "op_id1");
- directive_handler_->AddInstruction(CreateDirective(RECEIVE, true, kTtl),
- "op_id2");
- directive_handler_->AddInstruction(CreateDirective(RECEIVE, false, kTtl),
- "op_id3");
-
- EXPECT_TRUE(IsPlaying(AUDIBLE));
- EXPECT_TRUE(IsPlaying(INAUDIBLE));
- EXPECT_TRUE(IsRecording(AUDIBLE));
- EXPECT_TRUE(IsRecording(INAUDIBLE));
-
- directive_handler_->RemoveInstructions("op_id1");
- EXPECT_FALSE(IsPlaying(AUDIBLE));
- EXPECT_TRUE(IsPlaying(INAUDIBLE));
- EXPECT_TRUE(IsRecording(AUDIBLE));
- EXPECT_TRUE(IsRecording(INAUDIBLE));
-
- directive_handler_->RemoveInstructions("op_id2");
- EXPECT_FALSE(IsPlaying(INAUDIBLE));
- EXPECT_FALSE(IsRecording(AUDIBLE));
- EXPECT_TRUE(IsRecording(INAUDIBLE));
-
- directive_handler_->RemoveInstructions("op_id3");
- EXPECT_FALSE(IsRecording(INAUDIBLE));
-}
-
-TEST_F(AudioDirectiveHandlerTest, Timed) {
- directive_handler_->AddInstruction(CreateDirective(TRANSMIT, true, 6),
- "op_id1");
- directive_handler_->AddInstruction(CreateDirective(TRANSMIT, false, 8),
- "op_id1");
- directive_handler_->AddInstruction(CreateDirective(RECEIVE, false, 4),
- "op_id3");
-
- EXPECT_TRUE(IsPlaying(AUDIBLE));
- EXPECT_TRUE(IsPlaying(INAUDIBLE));
- EXPECT_FALSE(IsRecording(AUDIBLE));
- EXPECT_TRUE(IsRecording(INAUDIBLE));
-
- // Every time we advance and a directive expires, the timer should fire also.
- clock_ptr_->Advance(base::TimeDelta::FromMilliseconds(5));
- timer_ptr_->Fire();
-
- // We are now at +5ms. This instruction expires at +10ms.
- directive_handler_->AddInstruction(CreateDirective(RECEIVE, true, 5),
- "op_id4");
- EXPECT_TRUE(IsPlaying(AUDIBLE));
- EXPECT_TRUE(IsPlaying(INAUDIBLE));
- EXPECT_TRUE(IsRecording(AUDIBLE));
- EXPECT_FALSE(IsRecording(INAUDIBLE));
-
- // Advance to +7ms.
- const base::TimeDelta twoMs = base::TimeDelta::FromMilliseconds(2);
- clock_ptr_->Advance(twoMs);
- timer_ptr_->Fire();
-
- EXPECT_FALSE(IsPlaying(AUDIBLE));
- EXPECT_TRUE(IsPlaying(INAUDIBLE));
- EXPECT_TRUE(IsRecording(AUDIBLE));
-
- // Advance to +9ms.
- clock_ptr_->Advance(twoMs);
- timer_ptr_->Fire();
- EXPECT_FALSE(IsPlaying(INAUDIBLE));
- EXPECT_TRUE(IsRecording(AUDIBLE));
-
- // Advance to +11ms.
- clock_ptr_->Advance(twoMs);
- timer_ptr_->Fire();
- EXPECT_FALSE(IsRecording(AUDIBLE));
-}
-
-// TODO(rkc): Write more tests that check more convoluted sequences of
-// transmits/receives.
-
-} // namespace copresence
diff --git a/chromium/components/copresence/handlers/audio/audio_directive_list.cc b/chromium/components/copresence/handlers/audio/audio_directive_list.cc
deleted file mode 100644
index c66b06809ad..00000000000
--- a/chromium/components/copresence/handlers/audio/audio_directive_list.cc
+++ /dev/null
@@ -1,93 +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 "components/copresence/handlers/audio/audio_directive_list.h"
-
-#include <algorithm>
-
-#include "base/memory/ptr_util.h"
-
-namespace copresence {
-
-// Public functions.
-
-AudioDirective::AudioDirective() {}
-
-AudioDirective::AudioDirective(const std::string& op_id,
- base::TimeTicks end_time,
- const Directive& server_directive)
- : op_id(op_id),
- end_time(end_time),
- server_directive(server_directive) {}
-
-AudioDirectiveList::AudioDirectiveList(
- const scoped_refptr<TickClockRefCounted>& clock)
- : clock_(clock) {}
-
-AudioDirectiveList::~AudioDirectiveList() {}
-
-void AudioDirectiveList::AddDirective(const std::string& op_id,
- const Directive& server_directive) {
- base::TimeTicks end_time = clock_->NowTicks() +
- base::TimeDelta::FromMilliseconds(server_directive.ttl_millis());
-
- // If this op is already in the list, update it instead of adding it again.
- auto it = FindDirectiveByOpId(op_id);
- if (it != active_directives_.end()) {
- it->end_time = end_time;
- std::make_heap(active_directives_.begin(),
- active_directives_.end(),
- LatestFirstComparator());
- return;
- }
-
- active_directives_.push_back(
- AudioDirective(op_id, end_time, server_directive));
- std::push_heap(active_directives_.begin(),
- active_directives_.end(),
- LatestFirstComparator());
-}
-
-void AudioDirectiveList::RemoveDirective(const std::string& op_id) {
- auto it = FindDirectiveByOpId(op_id);
- if (it != active_directives_.end())
- active_directives_.erase(it);
-
- std::make_heap(active_directives_.begin(),
- active_directives_.end(),
- LatestFirstComparator());
-}
-
-std::unique_ptr<AudioDirective> AudioDirectiveList::GetActiveDirective() {
- // The top is always the instruction that is ending the latest.
- // If that time has passed, all our previous instructions have expired too.
- // So we clear the list.
- if (active_directives_.empty() ||
- active_directives_.front().end_time < clock_->NowTicks()) {
- active_directives_.clear();
- return std::unique_ptr<AudioDirective>();
- }
-
- return base::WrapUnique(new AudioDirective(active_directives_.front()));
-}
-
-const std::vector<AudioDirective>& AudioDirectiveList::directives() const {
- return active_directives_;
-}
-
-
-// Private functions.
-
-std::vector<AudioDirective>::iterator AudioDirectiveList::FindDirectiveByOpId(
- const std::string& op_id) {
- for (auto it = active_directives_.begin();
- it != active_directives_.end();
- ++it) {
- if (it->op_id == op_id)
- return it;
- }
- return active_directives_.end();
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/handlers/audio/audio_directive_list.h b/chromium/components/copresence/handlers/audio/audio_directive_list.h
deleted file mode 100644
index b6438522385..00000000000
--- a/chromium/components/copresence/handlers/audio/audio_directive_list.h
+++ /dev/null
@@ -1,88 +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 COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_LIST_H_
-#define COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_LIST_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/time/default_tick_clock.h"
-#include "base/time/time.h"
-#include "components/copresence/handlers/audio/tick_clock_ref_counted.h"
-#include "components/copresence/proto/data.pb.h"
-
-namespace media {
-class AudioBusRefCounted;
-}
-
-namespace copresence {
-
-class TickClockRefCounted;
-
-struct AudioDirective final {
- // Default ctor, required by the priority queue.
- AudioDirective();
- AudioDirective(const std::string& op_id,
- base::TimeTicks end_time,
- const Directive& server_directive);
-
- std::string op_id;
-
- // We're currently using TimeTicks to track time. This may not work for cases
- // where your machine suspends. See crbug.com/426136
- base::TimeTicks end_time;
-
- Directive server_directive;
-};
-
-// This class maintains a list of active audio directives. It fetches the audio
-// samples associated with a audio transmit directives and expires directives
-// that have outlived their TTL.
-// TODO(rkc): Once we implement more token technologies, move reusable code
-// from here to a base class and inherit various XxxxDirectiveList
-// classes from it.
-class AudioDirectiveList final {
- public:
- explicit AudioDirectiveList(const scoped_refptr<TickClockRefCounted>& clock =
- make_scoped_refptr(new TickClockRefCounted(new base::DefaultTickClock)));
- ~AudioDirectiveList();
-
- void AddDirective(const std::string& op_id, const Directive& directive);
- void RemoveDirective(const std::string& op_id);
-
- std::unique_ptr<AudioDirective> GetActiveDirective();
-
- const std::vector<AudioDirective>& directives() const;
-
- private:
- // Comparator for comparing end_times on audio tokens.
- class LatestFirstComparator {
- public:
- // This will sort our queue with the 'latest' time being the top.
- bool operator()(const AudioDirective& left,
- const AudioDirective& right) const {
- return left.end_time < right.end_time;
- }
- };
-
- std::vector<AudioDirective>::iterator FindDirectiveByOpId(
- const std::string& op_id);
-
- // This vector will be organized as a heap with the latest time as the first
- // element. Only currently active directives will exist in this list.
- std::vector<AudioDirective> active_directives_;
-
- scoped_refptr<TickClockRefCounted> clock_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioDirectiveList);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_LIST_H_
diff --git a/chromium/components/copresence/handlers/audio/audio_directive_list_unittest.cc b/chromium/components/copresence/handlers/audio/audio_directive_list_unittest.cc
deleted file mode 100644
index e0da75543a4..00000000000
--- a/chromium/components/copresence/handlers/audio/audio_directive_list_unittest.cc
+++ /dev/null
@@ -1,84 +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 "components/copresence/handlers/audio/audio_directive_list.h"
-
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/message_loop/message_loop.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using testing::IsNull;
-
-namespace copresence {
-
-static const int64_t kTtl = 10;
-
-const Directive CreateDirective(int64_t ttl) {
- Directive directive;
- directive.set_ttl_millis(ttl);
- return directive;
-}
-
-class AudioDirectiveListTest : public testing::Test {
- public:
- AudioDirectiveListTest() : directive_list_(new AudioDirectiveList) {}
-
- protected:
- base::MessageLoop message_loop_;
- std::unique_ptr<AudioDirectiveList> directive_list_;
-};
-
-TEST_F(AudioDirectiveListTest, Basic) {
- EXPECT_THAT(directive_list_->GetActiveDirective(), IsNull());
-
- directive_list_->AddDirective("op_id1", CreateDirective(kTtl));
- directive_list_->AddDirective("op_id2", CreateDirective(kTtl * 3));
- directive_list_->AddDirective("op_id3", CreateDirective(kTtl * 2));
- EXPECT_EQ("op_id2", directive_list_->GetActiveDirective()->op_id);
-
- directive_list_->RemoveDirective("op_id2");
- EXPECT_EQ("op_id3", directive_list_->GetActiveDirective()->op_id);
-}
-
-TEST_F(AudioDirectiveListTest, AddDirectiveMultiple) {
- directive_list_->AddDirective("op_id1", CreateDirective(kTtl));
- directive_list_->AddDirective("op_id2", CreateDirective(kTtl * 2));
- directive_list_->AddDirective("op_id3", CreateDirective(kTtl * 3 * 2));
- directive_list_->AddDirective("op_id3", CreateDirective(kTtl * 3 * 3));
- directive_list_->AddDirective("op_id4", CreateDirective(kTtl * 4));
-
- EXPECT_EQ("op_id3", directive_list_->GetActiveDirective()->op_id);
- directive_list_->RemoveDirective("op_id3");
- EXPECT_EQ("op_id4", directive_list_->GetActiveDirective()->op_id);
- directive_list_->RemoveDirective("op_id4");
- EXPECT_EQ("op_id2", directive_list_->GetActiveDirective()->op_id);
- directive_list_->RemoveDirective("op_id2");
- EXPECT_EQ("op_id1", directive_list_->GetActiveDirective()->op_id);
- directive_list_->RemoveDirective("op_id1");
- EXPECT_THAT(directive_list_->GetActiveDirective(), IsNull());
-}
-
-TEST_F(AudioDirectiveListTest, RemoveDirectiveMultiple) {
- directive_list_->AddDirective("op_id1", CreateDirective(kTtl));
- directive_list_->AddDirective("op_id2", CreateDirective(kTtl * 2));
- directive_list_->AddDirective("op_id3", CreateDirective(kTtl * 3));
- directive_list_->AddDirective("op_id4", CreateDirective(kTtl * 4));
-
- EXPECT_EQ("op_id4", directive_list_->GetActiveDirective()->op_id);
- directive_list_->RemoveDirective("op_id4");
- EXPECT_EQ("op_id3", directive_list_->GetActiveDirective()->op_id);
- directive_list_->RemoveDirective("op_id3");
- directive_list_->RemoveDirective("op_id3");
- directive_list_->RemoveDirective("op_id3");
- EXPECT_EQ("op_id2", directive_list_->GetActiveDirective()->op_id);
- directive_list_->RemoveDirective("op_id2");
- EXPECT_EQ("op_id1", directive_list_->GetActiveDirective()->op_id);
- directive_list_->RemoveDirective("op_id1");
- EXPECT_THAT(directive_list_->GetActiveDirective(), IsNull());
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/handlers/audio/tick_clock_ref_counted.cc b/chromium/components/copresence/handlers/audio/tick_clock_ref_counted.cc
deleted file mode 100644
index 1d052eb6362..00000000000
--- a/chromium/components/copresence/handlers/audio/tick_clock_ref_counted.cc
+++ /dev/null
@@ -1,26 +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 "components/copresence/handlers/audio/tick_clock_ref_counted.h"
-
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "base/time/tick_clock.h"
-
-namespace copresence {
-
-TickClockRefCounted::TickClockRefCounted(std::unique_ptr<base::TickClock> clock)
- : clock_(std::move(clock)) {}
-
-TickClockRefCounted::TickClockRefCounted(base::TickClock* clock)
- : clock_(base::WrapUnique(clock)) {}
-
-base::TimeTicks TickClockRefCounted::NowTicks() const {
- return clock_->NowTicks();
-}
-
-TickClockRefCounted::~TickClockRefCounted() {}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/handlers/audio/tick_clock_ref_counted.h b/chromium/components/copresence/handlers/audio/tick_clock_ref_counted.h
deleted file mode 100644
index 45f8bcfe803..00000000000
--- a/chromium/components/copresence/handlers/audio/tick_clock_ref_counted.h
+++ /dev/null
@@ -1,41 +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 COMPONENTS_COPRESENCE_HANDLERS_AUDIO_TICK_CLOCK_REF_COUNTED_H_
-#define COMPONENTS_COPRESENCE_HANDLERS_AUDIO_TICK_CLOCK_REF_COUNTED_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-
-namespace base {
-class TickClock;
-class TimeTicks;
-}
-
-namespace copresence {
-
-class TickClockRefCounted
- : public base::RefCountedThreadSafe<TickClockRefCounted> {
- public:
- explicit TickClockRefCounted(std::unique_ptr<base::TickClock> clock);
-
- // Takes ownership of the clock.
- explicit TickClockRefCounted(base::TickClock* clock);
-
- base::TimeTicks NowTicks() const;
-
- private:
- friend class base::RefCountedThreadSafe<TickClockRefCounted>;
- virtual ~TickClockRefCounted();
-
- std::unique_ptr<base::TickClock> clock_;
-
- DISALLOW_COPY_AND_ASSIGN(TickClockRefCounted);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_HANDLERS_AUDIO_TICK_CLOCK_REF_COUNTED_H_
diff --git a/chromium/components/copresence/handlers/directive_handler.h b/chromium/components/copresence/handlers/directive_handler.h
deleted file mode 100644
index 6221a35154a..00000000000
--- a/chromium/components/copresence/handlers/directive_handler.h
+++ /dev/null
@@ -1,50 +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 COMPONENTS_COPRESENCE_HANDLERS_DIRECTIVE_HANDLER_H_
-#define COMPONENTS_COPRESENCE_HANDLERS_DIRECTIVE_HANDLER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "components/audio_modem/public/whispernet_client.h"
-
-namespace copresence {
-
-class Directive;
-
-// The directive handler manages transmit and receive directives.
-class DirectiveHandler {
- public:
- DirectiveHandler() {}
- virtual ~DirectiveHandler() {}
-
- // Starts processing directives with the provided Whispernet delegate.
- // Directives will be queued until this function is called.
- // |whispernet_client| is owned by the caller and must outlive the
- // DirectiveHandler.
- // |tokens_cb| is called for all audio tokens found in recorded audio.
- // TODO(ckehoe): This is no longer needed. Merge into the constructor.
- virtual void Start(audio_modem::WhispernetClient* whispernet_client,
- const audio_modem::TokensCallback& tokens_cb) = 0;
-
- // Adds a directive to handle.
- virtual void AddDirective(const Directive& directive) = 0;
-
- // Removes any directives associated with the given operation id.
- virtual void RemoveDirectives(const std::string& op_id) = 0;
-
- // TODO(ckehoe): Move the Modem to be owned by CopresenceManager.
- // Then this will not need to be passed all the way down the tree.
- virtual const std::string
- GetCurrentAudioToken(audio_modem::AudioType type) const = 0;
- virtual bool IsAudioTokenHeard(audio_modem::AudioType type) const = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DirectiveHandler);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_HANDLERS_DIRECTIVE_HANDLER_H_
diff --git a/chromium/components/copresence/handlers/directive_handler_impl.cc b/chromium/components/copresence/handlers/directive_handler_impl.cc
deleted file mode 100644
index 62b4f61926f..00000000000
--- a/chromium/components/copresence/handlers/directive_handler_impl.cc
+++ /dev/null
@@ -1,126 +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 "components/copresence/handlers/directive_handler_impl.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/guid.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/time/time.h"
-#include "components/copresence/handlers/audio/audio_directive_handler_impl.h"
-#include "components/copresence/proto/data.pb.h"
-
-namespace {
-
-const int kMaxUnlabeledDirectiveTtl = 60000; // 1 minute
-
-} // namespace
-
-namespace copresence {
-
-// Public functions.
-
-DirectiveHandlerImpl::DirectiveHandlerImpl()
- : DirectiveHandlerImpl(base::WrapUnique(
- new AudioDirectiveHandlerImpl(DirectivesCallback()))) {}
-
-DirectiveHandlerImpl::DirectiveHandlerImpl(
- const DirectivesCallback& update_directives_callback)
- : DirectiveHandlerImpl(base::WrapUnique(
- new AudioDirectiveHandlerImpl(update_directives_callback))) {}
-
-DirectiveHandlerImpl::DirectiveHandlerImpl(
- std::unique_ptr<AudioDirectiveHandler> audio_handler)
- : audio_handler_(std::move(audio_handler)), is_started_(false) {}
-
-DirectiveHandlerImpl::~DirectiveHandlerImpl() {}
-
-void DirectiveHandlerImpl::Start(
- audio_modem::WhispernetClient* whispernet_client,
- const audio_modem::TokensCallback& tokens_cb) {
- audio_handler_->Initialize(whispernet_client, tokens_cb);
- DVLOG(2) << "Directive handler starting";
-
- is_started_ = true;
-
- // Run all the queued directives.
- for (const auto& op_id : pending_directives_) {
- for (const Directive& directive : op_id.second)
- StartDirective(op_id.first, directive);
- }
- pending_directives_.clear();
-}
-
-void DirectiveHandlerImpl::AddDirective(const Directive& original_directive) {
- // We may need to modify the directive's TTL.
- Directive directive(original_directive);
-
- // We only handle transmit and receive directives.
- // WiFi and BLE scans aren't implemented.
- DCHECK_EQ(directive.instruction_type(), TOKEN);
-
- std::string op_id = directive.published_message_id();
- if (op_id.empty())
- op_id = directive.subscription_id();
-
- // GCM directives will not have a publish or subscribe ID populated.
- if (op_id.empty()) {
- op_id = base::GenerateGUID();
- DVLOG(3) << "No operation associated with directive. Setting op id to "
- << op_id;
-
- // The app can't cancel these directives, so make sure they're not too long.
- if (directive.ttl_millis() > kMaxUnlabeledDirectiveTtl) {
- DVLOG(2) << "Cutting TTL of unlabeled directive from "
- << directive.ttl_millis() << " down to "
- << kMaxUnlabeledDirectiveTtl << " milliseconds";
- directive.set_ttl_millis(kMaxUnlabeledDirectiveTtl);
- }
- }
-
- if (!is_started_) {
- pending_directives_[op_id].push_back(directive);
- } else {
- StartDirective(op_id, directive);
- }
-}
-
-void DirectiveHandlerImpl::RemoveDirectives(const std::string& op_id) {
- // If whispernet_client_ is null, audio_handler_ hasn't been Initialized.
- if (is_started_) {
- audio_handler_->RemoveInstructions(op_id);
- } else {
- pending_directives_.erase(op_id);
- }
-}
-
-const std::string DirectiveHandlerImpl::GetCurrentAudioToken(
- audio_modem::AudioType type) const {
- // If whispernet_client_ is null, audio_handler_ hasn't been Initialized.
- return is_started_ ? audio_handler_->PlayingToken(type) : "";
-}
-
-bool DirectiveHandlerImpl::IsAudioTokenHeard(
- audio_modem::AudioType type) const {
- return is_started_ ? audio_handler_->IsPlayingTokenHeard(type) : false;
-}
-
-
-// Private functions.
-
-void DirectiveHandlerImpl::StartDirective(const std::string& op_id,
- const Directive& directive) {
- DCHECK(is_started_);
- DLOG_IF(WARNING, directive.delay_millis() > 0)
- << "Ignoring " << directive.delay_millis() << " delay for directive";
- const TokenMedium& medium = directive.token_instruction().medium();
- DCHECK(medium == AUDIO_ULTRASOUND_PASSBAND || medium == AUDIO_AUDIBLE_DTMF)
- << "Received directive for unimplemented medium " << medium;
- audio_handler_->AddInstruction(directive, op_id);
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/handlers/directive_handler_impl.h b/chromium/components/copresence/handlers/directive_handler_impl.h
deleted file mode 100644
index cfee1c7504d..00000000000
--- a/chromium/components/copresence/handlers/directive_handler_impl.h
+++ /dev/null
@@ -1,52 +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 COMPONENTS_COPRESENCE_HANDLERS_DIRECTIVE_HANDLER_IMPL_H_
-#define COMPONENTS_COPRESENCE_HANDLERS_DIRECTIVE_HANDLER_IMPL_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "components/copresence/handlers/audio/audio_directive_handler_impl.h"
-#include "components/copresence/handlers/directive_handler.h"
-#include "components/copresence/public/copresence_constants.h"
-
-namespace copresence {
-
-// The directive handler manages transmit and receive directives.
-class DirectiveHandlerImpl final : public DirectiveHandler {
- public:
- DirectiveHandlerImpl();
- explicit DirectiveHandlerImpl(
- const DirectivesCallback& update_directives_callback);
- DirectiveHandlerImpl(std::unique_ptr<AudioDirectiveHandler> audio_handler);
- ~DirectiveHandlerImpl() override;
-
- // DirectiveHandler overrides.
- void Start(audio_modem::WhispernetClient* whispernet_client,
- const audio_modem::TokensCallback& tokens_cb) override;
- void AddDirective(const Directive& directive) override;
- void RemoveDirectives(const std::string& op_id) override;
- const std::string
- GetCurrentAudioToken(audio_modem::AudioType type) const override;
- bool IsAudioTokenHeard(audio_modem::AudioType type) const override;
-
- private:
- // Starts actually running a directive.
- void StartDirective(const std::string& op_id, const Directive& directive);
-
- std::unique_ptr<AudioDirectiveHandler> audio_handler_;
- std::map<std::string, std::vector<Directive>> pending_directives_;
-
- bool is_started_;
-
- DISALLOW_COPY_AND_ASSIGN(DirectiveHandlerImpl);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_HANDLERS_DIRECTIVE_HANDLER_IMPL_H_
diff --git a/chromium/components/copresence/handlers/directive_handler_unittest.cc b/chromium/components/copresence/handlers/directive_handler_unittest.cc
deleted file mode 100644
index 5eae8615760..00000000000
--- a/chromium/components/copresence/handlers/directive_handler_unittest.cc
+++ /dev/null
@@ -1,147 +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 <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/time/time.h"
-#include "components/audio_modem/test/stub_whispernet_client.h"
-#include "components/copresence/handlers/audio/audio_directive_handler.h"
-#include "components/copresence/handlers/directive_handler_impl.h"
-#include "components/copresence/proto/data.pb.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using testing::ElementsAre;
-using testing::IsEmpty;
-
-namespace {
-
-const int64_t kMaxUnlabeledTtl = 60000; // 1 minute
-const int64_t kExcessiveUnlabeledTtl = 120000; // 2 minutes
-const int64_t kDefaultTtl = 600000; // 10 minutes
-
-} // namespace
-
-namespace copresence {
-
-const Directive CreateDirective(const std::string& publish_id,
- const std::string& subscribe_id,
- const std::string& token,
- int64_t ttl_ms) {
- Directive directive;
- directive.set_instruction_type(TOKEN);
- directive.set_published_message_id(publish_id);
- directive.set_subscription_id(subscribe_id);
- directive.set_ttl_millis(ttl_ms);
-
- TokenInstruction* instruction = new TokenInstruction;
- instruction->set_token_id(token);
- instruction->set_medium(AUDIO_ULTRASOUND_PASSBAND);
- directive.set_allocated_token_instruction(instruction);
-
- return directive;
-}
-
-const Directive CreateDirective(const std::string& publish_id,
- const std::string& subscribe_id,
- const std::string& token) {
- return CreateDirective(publish_id, subscribe_id, token, kDefaultTtl);
-}
-
-class FakeAudioDirectiveHandler final : public AudioDirectiveHandler {
- public:
- FakeAudioDirectiveHandler() {}
-
- void Initialize(
- audio_modem::WhispernetClient* /* whispernet_client */,
- const audio_modem::TokensCallback& /* tokens_cb */) override {}
-
- void AddInstruction(const Directive& directive,
- const std::string& /* op_id */) override {
- added_tokens_.push_back(directive.token_instruction().token_id());
- added_ttls_.push_back(directive.ttl_millis());
- }
-
- void RemoveInstructions(const std::string& op_id) override {
- removed_operations_.push_back(op_id);
- }
-
- const std::string
- PlayingToken(audio_modem::AudioType /* type */) const override {
- NOTREACHED();
- return "";
- }
-
- bool IsPlayingTokenHeard(audio_modem::AudioType /* type */) const override {
- NOTREACHED();
- return false;
- }
-
- const std::vector<std::string>& added_tokens() const {
- return added_tokens_;
- }
-
- const std::vector<int64_t>& added_ttls() const { return added_ttls_; }
-
- const std::vector<std::string>& removed_operations() const {
- return removed_operations_;
- }
-
- private:
- std::vector<std::string> added_tokens_;
- std::vector<int64_t> added_ttls_;
- std::vector<std::string> removed_operations_;
-};
-
-class DirectiveHandlerTest : public testing::Test {
- public:
- DirectiveHandlerTest()
- : whispernet_client_(new audio_modem::StubWhispernetClient),
- audio_handler_(new FakeAudioDirectiveHandler),
- directive_handler_(
- base::WrapUnique<AudioDirectiveHandler>(audio_handler_)) {}
-
- protected:
- void StartDirectiveHandler() {
- directive_handler_.Start(whispernet_client_.get(),
- audio_modem::TokensCallback());
- }
-
- std::unique_ptr<audio_modem::WhispernetClient> whispernet_client_;
- FakeAudioDirectiveHandler* audio_handler_;
- DirectiveHandlerImpl directive_handler_;
-};
-
-TEST_F(DirectiveHandlerTest, DirectiveTtl) {
- StartDirectiveHandler();
- directive_handler_.AddDirective(
- CreateDirective("", "", "token 1", kMaxUnlabeledTtl));
- directive_handler_.AddDirective(
- CreateDirective("", "", "token 2", kExcessiveUnlabeledTtl));
- EXPECT_THAT(audio_handler_->added_ttls(),
- ElementsAre(kMaxUnlabeledTtl, kMaxUnlabeledTtl));
-}
-
-TEST_F(DirectiveHandlerTest, Queuing) {
- directive_handler_.AddDirective(CreateDirective("id 1", "", "token 1"));
- directive_handler_.AddDirective(CreateDirective("", "id 1", "token 2"));
- directive_handler_.AddDirective(CreateDirective("id 2", "", "token 3"));
- directive_handler_.RemoveDirectives("id 1");
-
- EXPECT_THAT(audio_handler_->added_tokens(), IsEmpty());
- EXPECT_THAT(audio_handler_->removed_operations(), IsEmpty());
-
- StartDirectiveHandler();
- directive_handler_.RemoveDirectives("id 3");
-
- EXPECT_THAT(audio_handler_->added_tokens(), ElementsAre("token 3"));
- EXPECT_THAT(audio_handler_->added_ttls(), ElementsAre(kDefaultTtl));
- EXPECT_THAT(audio_handler_->removed_operations(), ElementsAre("id 3"));
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/handlers/gcm_handler.h b/chromium/components/copresence/handlers/gcm_handler.h
deleted file mode 100644
index 341a7d8ca69..00000000000
--- a/chromium/components/copresence/handlers/gcm_handler.h
+++ /dev/null
@@ -1,40 +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 COMPONENTS_COPRESENCE_HANDLERS_GCM_HANDLER_H_
-#define COMPONENTS_COPRESENCE_HANDLERS_GCM_HANDLER_H_
-
-#include <string>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-
-namespace gcm {
-class GCMDriver;
-}
-
-namespace copresence {
-
-// A class to handle GCM messages from the Copresence server. As far as the
-// rest of the system is concerned, it simply provides the registered GCM ID.
-// The implementation will call other classes to enact the message contents.
-class GCMHandler {
- public:
- // Callback to report that registration has completed.
- // Returns an empty ID if registration failed.
- using RegistrationCallback = base::Callback<void(const std::string&)>;
-
- GCMHandler() {}
- virtual ~GCMHandler() {}
-
- // Request the GCM ID. It may be returned now or later, via the callback.
- virtual void GetGcmId(const RegistrationCallback& callback) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GCMHandler);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_HANDLERS_GCM_HANDLER_H_
diff --git a/chromium/components/copresence/handlers/gcm_handler_impl.cc b/chromium/components/copresence/handlers/gcm_handler_impl.cc
deleted file mode 100644
index 362b53550e3..00000000000
--- a/chromium/components/copresence/handlers/gcm_handler_impl.cc
+++ /dev/null
@@ -1,158 +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 "components/copresence/handlers/gcm_handler_impl.h"
-
-#include "base/base64.h"
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "components/copresence/handlers/directive_handler.h"
-#include "components/copresence/proto/push_message.pb.h"
-#include "components/gcm_driver/gcm_driver.h"
-
-using gcm::GCMClient;
-
-namespace {
-
-// TODO(ckehoe): Move this to a common library.
-bool Base64Decode(std::string data, std::string* out) {
- // Convert from URL-safe.
- base::ReplaceChars(data, "-", "+", &data);
- base::ReplaceChars(data, "_", "/", &data);
-
- // Add padding if needed.
- while (data.size() % 4)
- data.push_back('=');
-
- // Decode.
- return base::Base64Decode(data, out);
-}
-
-} // namespace
-
-namespace copresence {
-
-const char GCMHandlerImpl::kCopresenceAppId[] =
- "com.google.android.gms.location.copresence";
-const char GCMHandlerImpl::kCopresenceSenderId[] = "745476177629";
-const char GCMHandlerImpl::kGcmMessageKey[] = "PUSH_MESSAGE";
-
-
-// Public functions.
-
-GCMHandlerImpl::GCMHandlerImpl(gcm::GCMDriver* gcm_driver,
- DirectiveHandler* directive_handler,
- const MessagesCallback& new_messages_callback)
- : driver_(gcm_driver),
- directive_handler_(directive_handler),
- new_messages_callback_(new_messages_callback),
- registration_callback_(base::Bind(&GCMHandlerImpl::RegistrationComplete,
- base::Unretained(this))) {
- DCHECK(driver_);
- DCHECK(directive_handler_);
-
- driver_->AddAppHandler(kCopresenceAppId, this);
- driver_->Register(kCopresenceAppId,
- std::vector<std::string>(1, kCopresenceSenderId),
- registration_callback_.callback());
-}
-
-GCMHandlerImpl::~GCMHandlerImpl() {
- if (driver_)
- driver_->RemoveAppHandler(kCopresenceAppId);
-}
-
-void GCMHandlerImpl::GetGcmId(const RegistrationCallback& callback) {
- if (gcm_id_.empty()) {
- pending_id_requests_.push_back(callback);
- } else {
- callback.Run(gcm_id_);
- }
-}
-
-void GCMHandlerImpl::ShutdownHandler() {
- // The GCMDriver is going away. Make sure we don't try to contact it.
- driver_ = nullptr;
-}
-
-void GCMHandlerImpl::OnMessage(const std::string& app_id,
- const gcm::IncomingMessage& message) {
- DCHECK_EQ(kCopresenceAppId, app_id);
- DVLOG(2) << "Incoming GCM message";
-
- const auto& content = message.data.find(kGcmMessageKey);
- if (content == message.data.end()) {
- LOG(ERROR) << "GCM message missing data key";
- return;
- }
-
- std::string serialized_message;
- if (!Base64Decode(content->second, &serialized_message)) {
- LOG(ERROR) << "Couldn't decode GCM message";
- return;
- }
-
- PushMessage push_message;
- if (!push_message.ParseFromString(serialized_message)) {
- LOG(ERROR) << "GCM message contained invalid proto";
- return;
- }
-
- if (push_message.type() != PushMessage::REPORT) {
- DVLOG(2) << "Discarding non-report GCM message";
- return;
- }
-
- DVLOG(3) << "Processing " << push_message.report().directive_size()
- << " directive(s) from GCM message";
- for (const Directive& directive : push_message.report().directive()) {
- // TODO(ckehoe): Use a callback here so GCMHandler
- // is decoupled from DirectiveHandler.
- directive_handler_->AddDirective(directive);
- }
-
- new_messages_callback_.Run(push_message.report().subscribed_message());
-}
-
-void GCMHandlerImpl::OnMessagesDeleted(const std::string& app_id) {
- DCHECK_EQ(kCopresenceAppId, app_id);
- DVLOG(2) << "GCM message overflow reported";
-}
-
-void GCMHandlerImpl::OnSendError(
- const std::string& /* app_id */,
- const GCMClient::SendErrorDetails& /* send_error_details */) {
- NOTREACHED() << "Copresence clients should not be sending GCM messages";
-}
-
-void GCMHandlerImpl::OnSendAcknowledged(const std::string& /* app_id */,
- const std::string& /* message_id */) {
- NOTREACHED() << "Copresence clients should not be sending GCM messages";
-}
-
-bool GCMHandlerImpl::CanHandle(const std::string& app_id) const {
- return app_id == kCopresenceAppId;
-}
-
-
-// Private functions.
-
-void GCMHandlerImpl::RegistrationComplete(const std::string& registration_id,
- GCMClient::Result result) {
- if (result == GCMClient::SUCCESS) {
- DVLOG(2) << "GCM registration successful. ID: " << registration_id;
- gcm_id_ = registration_id;
- } else {
- LOG(ERROR) << "GCM registration failed with error " << result;
- }
-
- for (const RegistrationCallback& callback : pending_id_requests_) {
- callback.Run(result == GCMClient::SUCCESS ?
- registration_id : std::string());
- }
- pending_id_requests_.clear();
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/handlers/gcm_handler_impl.h b/chromium/components/copresence/handlers/gcm_handler_impl.h
deleted file mode 100644
index 69cd085bdca..00000000000
--- a/chromium/components/copresence/handlers/gcm_handler_impl.h
+++ /dev/null
@@ -1,84 +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 COMPONENTS_COPRESENCE_HANDLERS_GCM_HANDLER_IMPL_H_
-#define COMPONENTS_COPRESENCE_HANDLERS_GCM_HANDLER_IMPL_H_
-
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/cancelable_callback.h"
-#include "base/macros.h"
-#include "components/copresence/handlers/gcm_handler.h"
-#include "components/copresence/public/copresence_constants.h"
-#include "components/gcm_driver/gcm_app_handler.h"
-#include "components/gcm_driver/gcm_client.h"
-
-namespace gcm {
-class GCMDriver;
-}
-
-namespace copresence {
-
-class DirectiveHandler;
-
-// This class handles GCM messages from the Copresence server.
-class GCMHandlerImpl final : public GCMHandler,
- public gcm::GCMAppHandler {
- public:
- // Callback to report that registration has completed.
- // Returns an empty ID if registration failed.
- using RegistrationCallback = base::Callback<void(const std::string&)>;
-
- static const char kCopresenceAppId[];
- static const char kCopresenceSenderId[];
- static const char kGcmMessageKey[];
-
- // |gcm_driver| is required, but may disappear if we get a ShutdownHandler()
- // call first. |directive_handler| must outlive us. The caller owns both.
- GCMHandlerImpl(gcm::GCMDriver* gcm_driver,
- DirectiveHandler* directive_handler,
- const MessagesCallback& new_messages_callback);
- ~GCMHandlerImpl() override;
-
- // GCMHandler override.
- void GetGcmId(const RegistrationCallback& callback) override;
-
- private:
- friend class GCMHandlerTest;
-
- // GCMAppHandler overrides
- void ShutdownHandler() override;
- void OnMessage(const std::string& app_id,
- const gcm::IncomingMessage& message) override;
- void OnMessagesDeleted(const std::string& app_id) override;
- void OnSendError(
- const std::string& /* app_id */,
- const gcm::GCMClient::SendErrorDetails& /* send_error_details */)
- override;
- void OnSendAcknowledged(const std::string& /* app_id */,
- const std::string& /* message_id */) override;
- bool CanHandle(const std::string& app_id) const override;
-
- // GCM Registration has finished. Notify clients as appropriate.
- void RegistrationComplete(const std::string& registration_id,
- gcm::GCMClient::Result result);
-
- gcm::GCMDriver* driver_;
- DirectiveHandler* const directive_handler_;
- MessagesCallback new_messages_callback_;
-
- std::string gcm_id_;
- std::vector<RegistrationCallback> pending_id_requests_;
-
- base::CancelableCallback<void(const std::string&,
- gcm::GCMClient::Result)> registration_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(GCMHandlerImpl);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_HANDLERS_GCM_HANDLER_IMPL_H_
diff --git a/chromium/components/copresence/handlers/gcm_handler_unittest.cc b/chromium/components/copresence/handlers/gcm_handler_unittest.cc
deleted file mode 100644
index 2e45ff1333e..00000000000
--- a/chromium/components/copresence/handlers/gcm_handler_unittest.cc
+++ /dev/null
@@ -1,72 +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 <memory>
-
-#include "base/base64url.h"
-#include "components/copresence/handlers/gcm_handler_impl.h"
-#include "components/copresence/proto/push_message.pb.h"
-#include "components/copresence/test/fake_directive_handler.h"
-#include "components/gcm_driver/fake_gcm_driver.h"
-#include "components/gcm_driver/gcm_client.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace copresence {
-
-namespace {
-
-using google::protobuf::RepeatedPtrField;
-void IgnoreMessages(
- const RepeatedPtrField<SubscribedMessage>& /* messages */) {}
-
-} // namespace
-
-
-class GCMHandlerTest : public testing::Test {
- public:
- GCMHandlerTest()
- : driver_(new gcm::FakeGCMDriver),
- directive_handler_(new FakeDirectiveHandler),
- gcm_handler_(driver_.get(),
- directive_handler_.get(),
- base::Bind(&IgnoreMessages)) {
- }
-
- protected:
- void ProcessMessage(const gcm::IncomingMessage& message) {
- gcm_handler_.OnMessage(GCMHandlerImpl::kCopresenceAppId, message);
- }
-
- std::unique_ptr<gcm::GCMDriver> driver_;
- std::unique_ptr<FakeDirectiveHandler> directive_handler_;
- GCMHandlerImpl gcm_handler_;
-};
-
-TEST_F(GCMHandlerTest, OnMessage) {
- // Create a PushMessage.
- PushMessage push_message;
- push_message.set_type(PushMessage::REPORT);
- Report* report = push_message.mutable_report();
- report->add_directive()->set_subscription_id("subscription 1");
- report->add_directive()->set_subscription_id("subscription 2");
-
- // Encode it.
- std::string serialized_proto;
- std::string encoded_proto;
- push_message.SerializeToString(&serialized_proto);
- base::Base64UrlEncode(serialized_proto,
- base::Base64UrlEncodePolicy::INCLUDE_PADDING,
- &encoded_proto);
-
- // Send it in a GCM message.
- gcm::IncomingMessage gcm_message;
- gcm_message.data[GCMHandlerImpl::kGcmMessageKey] = encoded_proto;
- ProcessMessage(gcm_message);
-
- // Check that the correct directives were passed along.
- EXPECT_THAT(directive_handler_->added_directives(),
- testing::ElementsAre("subscription 1", "subscription 2"));
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/proto/BUILD.gn b/chromium/components/copresence/proto/BUILD.gn
deleted file mode 100644
index cdffe4bb6f4..00000000000
--- a/chromium/components/copresence/proto/BUILD.gn
+++ /dev/null
@@ -1,18 +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("//third_party/protobuf/proto_library.gni")
-
-# GYP version: components/copresence.gypi:copresence_proto
-proto_library("proto") {
- sources = [
- "codes.proto",
- "config_data.proto",
- "data.proto",
- "enums.proto",
- "identity.proto",
- "push_message.proto",
- "rpcs.proto",
- ]
-}
diff --git a/chromium/components/copresence/proto/codes.proto b/chromium/components/copresence/proto/codes.proto
deleted file mode 100644
index 3459f269395..00000000000
--- a/chromium/components/copresence/proto/codes.proto
+++ /dev/null
@@ -1,23 +0,0 @@
-syntax = "proto2";
-package util.error;
-option optimize_for = LITE_RUNTIME;
-enum Code {
- OK = 0;
- CANCELLED = 1;
- UNKNOWN = 2;
- INVALID_ARGUMENT = 3;
- DEADLINE_EXCEEDED = 4;
- NOT_FOUND = 5;
- ALREADY_EXISTS = 6;
- PERMISSION_DENIED = 7;
- UNAUTHENTICATED = 16;
- RESOURCE_EXHAUSTED = 8;
- FAILED_PRECONDITION = 9;
- ABORTED = 10;
- OUT_OF_RANGE = 11;
- UNIMPLEMENTED = 12;
- INTERNAL = 13;
- UNAVAILABLE = 14;
- DATA_LOSS = 15;
- DO_NOT_USE_RESERVED_FOR_FUTURE_EXPANSION_USE_DEFAULT_IN_SWITCH_INSTEAD_ = 20;
-}
diff --git a/chromium/components/copresence/proto/config_data.proto b/chromium/components/copresence/proto/config_data.proto
deleted file mode 100644
index a59a8d04a97..00000000000
--- a/chromium/components/copresence/proto/config_data.proto
+++ /dev/null
@@ -1,91 +0,0 @@
-syntax = "proto2";
-package copresence;
-option optimize_for = LITE_RUNTIME;
-message Configuration {
- optional string etag = 3 [default = ""];
- optional SystemParams system = 5;
- optional CarrierSenseParams carrier_sense = 6;
- optional AudioDsssParams audio_dsss = 7;
- optional LoggerParam logger = 13;
- optional ClientDirectiveParams client_directive = 14;
- optional AudioDtmfParams audio_dtmf = 15;
-}
-message DirectiveConfiguration {
- optional TokenParams token_params = 1;
-}
-message TokenParams {
- optional int32 length = 1 [default = 6];
- optional string prefix = 2 [default = "GCS"];
-}
-message ClientDirectiveParams {
- optional TokenParams audio_ultrasound_passband = 1;
- optional TokenParams audio_audible_dtmf = 7;
-}
-message SystemParams {
- optional bool enable_copresence_support = 1 [default = true];
- optional bool enable_listen_ultrasound_audio = 2 [default = true];
- optional bool enable_advertise_ultrasound_audio = 3 [default = true];
- optional int64 kick_scheduler_timeout_millis = 16 [default = 30000];
- optional int64 copresence_state_pruning_millis = 17 [default = 604800000];
- optional int32 num_oauth_retries = 18 [default = 3];
- optional int64 default_state_transition_timeout_millis = 19 [default = 1000];
- optional int64 sync_adapter_period_seconds = 20 [default = 86400]; // 1 day
- optional int64 heartbeat_interval_millis = 21 [default = 5000];
- optional int64 transmit_directive_max_ttl_millis = 22 [default = 600000];
- optional string experiment_override = 23 [default = ""];
- optional int64 poll_delay_on_token_heard_in_millis = 24 [default = 2000];
- optional bool enable_listen_audible_audio = 27 [default = true];
- optional bool enable_advertise_audible_audio = 28 [default = true];
- optional int64 duty_cycler_notify_timeout_millis = 30 [default = 5000];
- optional bool enable_client_message_etag = 31 [default=false];
- optional int64 max_duration_to_reserve_tokens_millis = 32 [default = 3600000];
- optional int64 max_unauth_ttl_millis = 33 [default = 86400000];
- optional bool enable_preseeded_tokens = 34 [default = false];
-}
-message CarrierSenseParams {
- optional int64 max_additional_broadcast_time_millis = 1 [default = 0];
- optional int64 max_additional_pause_broadcast_time_millis = 2 [default = 300];
- optional int64 min_pause_broadcast_time_millis = 4 [default = 500];
- optional int64 min_wait_time_when_broadcasting_millis = 5 [default = 1100];
- optional int64 max_additional_wait_time_when_broadcasting_millis = 6
- [default = 1500];
- optional int64 min_wait_time_when_listening_millis = 7 [default = 4000];
- optional int64 step_size_millis = 8 [default = 300];
- optional int64 estimated_stop_playback_latency_millis = 9 [default = 150];
- optional int64 min_broadcast_time_per_byte_millis = 10 [default = 400];
-}
-message AudioDsssParams {
- optional int32 broadcaster_volume = 1 [default = 5];
- optional bool include_parity_symbol = 2 [default = true];
- optional bool use_single_sideband = 3 [default = true];
- optional double desired_carrier_frequency = 4 [default = 18500.0];
- optional bool use_crc_16 = 5 [default = false];
- optional int32 number_of_taps_lfsr = 6 [default = 7];
- optional int32 code_number = 7 [default = 0];
- optional double coder_sample_rate = 8 [default = 48000.0];
- optional int32 bits_per_symbol = 9 [default = 4];
- optional int32 min_cycles_per_frame = 10 [default = 4];
- optional int32 baseband_decimation_factor = 11 [default = 4];
- optional int32 upsampling_factor = 12 [default = 16];
-}
-message AudioDtmfParams {
- optional bool include_parity_symbol = 1 [default = true];
- optional bool use_crc_16 = 2 [default = false];
- optional double coder_sample_rate = 3 [default = 44100.0];
- optional int32 baseband_decimation_factor = 4 [default = 16];
- optional int32 frequencies_per_symbol = 5 [default = 2];
- optional int32 window_duration_millis = 6 [default = 125];
- optional AdsrParams adsr_params = 7;
- optional double num_repetitions_to_play = 8 [default = 1];
-}
-message AdsrParams {
- optional int64 attack_time_millis = 1 [default = 8];
- optional int64 decay_time_millis = 2 [default = 0];
- optional int64 sustain_time_millis = 3 [default = 0];
- optional int64 release_time_millis = 4 [default = 40];
- optional double sustain_amplitude = 5 [default = 1.0];
-}
-message LoggerParam {
- optional int64 clear_cached_request_duration_millis = 1 [default = 172800000];
- optional int32 request_buffer_limit = 3 [default = 200];
-}
diff --git a/chromium/components/copresence/proto/data.proto b/chromium/components/copresence/proto/data.proto
deleted file mode 100644
index f862e9b8842..00000000000
--- a/chromium/components/copresence/proto/data.proto
+++ /dev/null
@@ -1,138 +0,0 @@
-syntax = "proto2";
-package copresence;
-option optimize_for = LITE_RUNTIME;
-import "config_data.proto";
-import "enums.proto";
-import "identity.proto";
-message ClientVersion {
- optional string client = 1;
- optional string version_name = 2;
- optional int64 version_code = 3;
- optional string certificate_fingerprint = 4;
-}
-message Status {
- optional StatusCode code = 1;
- optional string message = 2;
-}
-message PushServiceRegistration {
- optional PushService service = 1;
- optional GcmRegistration gcm_registration = 2;
-}
-message GcmRegistration {
- optional string device_token = 1;
-}
-message DeviceIdentifiers {
- optional int32 ulr_device_id = 1;
- optional DeviceIdentity device_identity = 2;
- optional Identity registrant = 3;
-}
-message Token {
- message Debug {
- repeated string email = 2;
- }
- optional string id = 1;
- optional TokenStatus status = 3;
- optional Debug debug = 4;
-}
-message DeviceFingerprint {
- optional string manufacturer = 1;
- optional string model = 2;
- optional PlatformType type = 3;
- optional string platform_version = 4;
-}
-message TokenTechnology {
- optional TokenMedium medium = 1;
- repeated TokenInstructionType instruction_type = 2;
-}
-message DeviceCapabilities {
- repeated TokenTechnology token_technology = 2;
-}
-message TokenInstruction {
- optional TokenInstructionType token_instruction_type = 1;
- optional TokenMedium medium = 2;
- optional string token_id = 4;
-}
-message Directive {
- optional InstructionType instruction_type = 1;
- optional TokenInstruction token_instruction = 2;
- optional int64 delay_millis = 3;
- optional int64 ttl_millis = 4;
- optional string published_message_id = 5;
- optional string subscription_id = 6;
- optional DirectiveConfiguration configuration = 7;
-}
-message DeviceState {
- optional DeviceCapabilities capabilities = 1;
- repeated Directive active_directive = 2;
-}
-message DebugInfo {
- optional string served_by_task = 1;
- repeated string token_id = 3;
- optional int64 request_time_millis = 4;
-}
-message TokenObservation {
- optional string token_id = 1;
- repeated TokenSignals signals = 2;
-}
-message TokenSignals {
- optional TokenMedium medium = 1;
- optional int32 rssi = 2;
- optional int64 observed_time_millis = 3;
-}
-message AccessPolicy {
- optional int64 ttl_millis = 1;
- optional Acl acl = 2;
-}
-message Acl {
- optional AclType acl_type = 1;
- optional string named_acl_name = 2;
- optional bytes referenced_acl_consistency_token = 5;
-}
-message PublishedMessage {
- optional string id = 1;
- optional AccessPolicy access_policy = 2;
- optional Message message = 3;
- optional TokenExchangeStrategy token_exchange_strategy = 5;
- optional OptInStateFilter opt_in_state_filter = 6;
-}
-message TokenExchangeStrategy {
- optional AudioConfiguration audio_configuration = 1;
- optional BroadcastScanConfiguration broadcast_scan_configuration = 2;
-}
-message SubscribedMessage {
- message Debug {
- optional string published_message_id = 1;
- optional string publisher_identity_id = 2;
- optional string publisher_device_id = 3;
- optional int64 creation_timestamp_millis = 4;
- optional int64 ttl_millis = 5;
- optional TokenExchangeStrategy token_exchange_strategy = 7;
- }
- repeated string subscription_id = 1;
- optional Message published_message = 2;
- optional Debug debug = 3;
- repeated TokenObservation required_token = 5;
-}
-message Message {
- optional MessageType type = 2;
- optional bytes payload = 3;
-}
-message MessageType {
- optional string type = 2;
-}
-message Subscription {
- optional string id = 1;
- optional int64 ttl_millis = 3;
- optional MessageType message_type = 4;
- optional TokenExchangeStrategy token_exchange_strategy = 7;
- optional OptInStateFilter opt_in_state_filter = 8;
-}
-message MessageResult {
- optional string published_message_id = 1;
-}
-message SubscriptionResult {
- optional string subscription_id = 1;
-}
-message OptInStateFilter {
- repeated OptInState allowed_opt_in_state = 1;
-}
diff --git a/chromium/components/copresence/proto/enums.proto b/chromium/components/copresence/proto/enums.proto
deleted file mode 100644
index 6570e4bd047..00000000000
--- a/chromium/components/copresence/proto/enums.proto
+++ /dev/null
@@ -1,91 +0,0 @@
-syntax = "proto2";
-package copresence;
-option optimize_for = LITE_RUNTIME;
-enum IdentityType {
- IDENTITY_TYPE_UNKNOWN = 0;
- GAIA_USER = 1;
- CHROMECAST = 2;
- ANDROIDOS = 3;
- CHROME = 4;
- UNREGISTERED = 5;
-}
-enum PushService {
- PUSH_SERVICE_UNKNOWN = 0;
- GCM = 1;
- APNS = 2;
- PUSH_SERVICE_NONE = 3;
-}
-enum ErrorType {
- ERROR_TYPE_UNKNOWN = 0;
- TOKEN_EXPIRED = 1;
- MAC_ADDRESS_UNAVAILABLE = 2;
- MAC_ADDRESS_NEEDS_PERMISSION = 3;
-}
-enum TokenStatus {
- TOKEN_STATUS_UNKNOWN = 0;
- VALID = 1;
- INVALID = 2;
- TRANSITIVE = 3;
-}
-enum TokenMedium {
- TOKEN_MEDIUM_UNKNOWN = 0;
- AUDIO_ULTRASOUND_PASSBAND = 1;
- BLUETOOTH_CLASSIC_NAME = 2;
- BLE_ADVERTISING_PACKET = 3;
- WIFI_DIRECT_SSID = 4;
- LOCAL_DEVICE = 5;
- BLE_GATT_SERVICE = 6;
- WIFI_AP_SSID = 7;
- AUDIO_AUDIBLE_DTMF = 8;
-}
-enum AclType {
- UNKNOWN_ACL_TYPE = 0;
- NO_ACL_CHECK = 1;
- OWNER_ONLY = 2;
- NAMED_ACL = 4;
- MESSAGE_ACL = 5;
- REFERENCED_ACL = 6;
- OPTED_OUT_MESSAGE_ACL = 7;
-}
-enum TokenInstructionType {
- UNKNOWN_TOKEN_INSTRUCTION_TYPE = 0;
- TRANSMIT = 1;
- RECEIVE = 2;
-}
-enum PlatformType {
- UNKNOWN_PLATFORM_TYPE = 0;
- CHROMECAST_PLATFORM_TYPE = 5;
- ANDROID_PLATFORM_TYPE = 6;
- IOS_PLATFORM_TYPE = 7;
- CHROME_PLATFORM_TYPE = 8;
-}
-enum InstructionType {
- UNKNOWN_INSTRUCTION_TYPE = 0;
- TOKEN = 1;
- SCAN_WIFI = 2;
- SCAN_BLE = 3;
-}
-enum StatusCode {
- STATUS_CODE_UNKNOWN = -1;
- OK = 0;
- COPRESENCE_DISABLED = 201;
- LOCATION_HISTORY_DISABLED = 202;
- UNDERAGED = 203;
- DEVICE_RE_REGISTRATION_REQUIRED = 204;
- RATE_LIMITED = 301;
-}
-enum OptInState {
- UNKNOWN_OPT_IN_STATE = 0;
- OPTED_IN = 1;
- OPTED_OUT = 2;
-}
-enum AudioConfiguration {
- AUDIO_CONFIGURATION_UNKNOWN = 0;
- AUDIO_CONFIGURATION_AUDIBLE = 1;
-}
-enum BroadcastScanConfiguration {
- BROADCAST_SCAN_CONFIGURATION_UNKNOWN = 0;
- BROADCAST_AND_SCAN = 1;
- BROADCAST_ONLY = 2;
- SCAN_ONLY = 3;
-}
diff --git a/chromium/components/copresence/proto/identity.proto b/chromium/components/copresence/proto/identity.proto
deleted file mode 100644
index 6c104edd2e0..00000000000
--- a/chromium/components/copresence/proto/identity.proto
+++ /dev/null
@@ -1,20 +0,0 @@
-syntax = "proto2";
-package copresence;
-option optimize_for = LITE_RUNTIME;
-import "enums.proto";
-message Identity {
- optional IdentityType type = 1;
- optional string chromecast_id = 3;
- optional string android_id = 4;
- optional string chrome_id = 5;
- optional int64 gaia_id = 6;
-}
-message DeviceIdentity {
- optional Identity identity = 1;
- optional DeviceVersion version = 2;
-}
-message DeviceVersion {
- optional string brand = 1;
- optional string product = 2;
- optional string version = 3;
-}
diff --git a/chromium/components/copresence/proto/push_message.proto b/chromium/components/copresence/proto/push_message.proto
deleted file mode 100644
index 239e88525b1..00000000000
--- a/chromium/components/copresence/proto/push_message.proto
+++ /dev/null
@@ -1,20 +0,0 @@
-syntax = "proto2";
-package copresence;
-option optimize_for = LITE_RUNTIME;
-import "data.proto";
-message PushMessage {
- enum Type {
- TYPE_UNKNOWN = 0;
- SYNC_SETTINGS = 3;
- OBTAIN_MAC = 5;
- NOTIFY_MAC = 6;
- TEST = 7;
- REPORT = 8;
- };
- optional Type type = 1;
- optional Report report = 9;
-}
-message Report {
- repeated Directive directive = 1;
- repeated SubscribedMessage subscribed_message = 2;
-}
diff --git a/chromium/components/copresence/proto/rpcs.proto b/chromium/components/copresence/proto/rpcs.proto
deleted file mode 100644
index 0d090e59ab3..00000000000
--- a/chromium/components/copresence/proto/rpcs.proto
+++ /dev/null
@@ -1,67 +0,0 @@
-syntax = "proto2";
-package copresence;
-option optimize_for = LITE_RUNTIME;
-import "codes.proto";
-import "config_data.proto";
-import "data.proto";
-message RequestHeader {
- optional ClientVersion client_version = 4;
- optional ClientVersion framework_version = 5;
- optional int64 current_time_millis = 6;
- optional string registered_device_id = 7;
- repeated string experiment_override = 8;
- optional DeviceFingerprint device_fingerprint = 10;
- optional string configuration_etag = 11;
-}
-message ResponseHeader {
- optional DebugInfo debug_info = 2;
- optional Status status = 3;
- optional Configuration configuration = 4;
-}
-message RegisterDeviceRequest {
- optional RequestHeader header = 1;
- optional PushServiceRegistration push_service = 5;
- optional DeviceIdentifiers device_identifiers = 6;
-}
-message RegisterDeviceResponse {
- optional ResponseHeader header = 1;
- optional string registered_device_id = 2;
-}
-message ReportRequest {
- optional RequestHeader header = 1;
- optional ManageMessagesRequest manage_messages_request = 2;
- optional ManageSubscriptionsRequest manage_subscriptions_request = 3;
- optional UpdateSignalsRequest update_signals_request = 4;
-}
-message UpdateSignalsRequest {
- repeated TokenObservation token_observation = 1;
- optional DeviceState state = 3;
-}
-message ManageMessagesRequest {
- repeated PublishedMessage message_to_publish = 1;
- repeated string id_to_unpublish = 2;
-}
-message ManageSubscriptionsRequest {
- repeated Subscription subscription = 1;
- repeated string id_to_unsubscribe = 2;
-}
-message ReportResponse {
- optional ResponseHeader header = 1;
- optional ManageMessagesResponse manage_messages_response = 2;
- optional ManageSubscriptionsResponse manage_subscriptions_response = 3;
- optional UpdateSignalsResponse update_signals_response = 4;
-}
-message UpdateSignalsResponse {
- optional util.error.Code status = 1;
- repeated Token token = 2;
- repeated SubscribedMessage message = 3;
- repeated Directive directive = 4;
-}
-message ManageMessagesResponse {
- optional util.error.Code status = 1;
- repeated MessageResult published_message_result = 3;
-}
-message ManageSubscriptionsResponse {
- optional util.error.Code status = 1;
- repeated SubscriptionResult subscription_result = 3;
-}
diff --git a/chromium/components/copresence/public/copresence_constants.h b/chromium/components/copresence/public/copresence_constants.h
deleted file mode 100644
index e4c43907b1e..00000000000
--- a/chromium/components/copresence/public/copresence_constants.h
+++ /dev/null
@@ -1,36 +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 COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_CONSTANTS_H_
-#define COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_CONSTANTS_H_
-
-#include <google/protobuf/repeated_field.h>
-
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/ref_counted.h"
-#include "components/copresence/tokens.h"
-#include "media/base/channel_layout.h"
-
-namespace media {
-class AudioBusRefCounted;
-}
-
-namespace copresence {
-
-class Directive;
-class SubscribedMessage;
-
-// Callback to pass a list of directives back to CopresenceState.
-using DirectivesCallback = base::Callback<void(const std::vector<Directive>&)>;
-
-// Callback to pass around a list of SubscribedMessages.
-using MessagesCallback = base::Callback<void(
- const google::protobuf::RepeatedPtrField<SubscribedMessage>&)>;
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_CONSTANTS_H_
diff --git a/chromium/components/copresence/public/copresence_delegate.h b/chromium/components/copresence/public/copresence_delegate.h
deleted file mode 100644
index 8f83bdb409f..00000000000
--- a/chromium/components/copresence/public/copresence_delegate.h
+++ /dev/null
@@ -1,77 +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 COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_DELEGATE_H_
-#define COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_DELEGATE_H_
-
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-
-namespace gcm {
-class GCMDriver;
-}
-
-namespace net {
-class URLRequestContextGetter;
-}
-
-namespace audio_modem {
-class WhispernetClient;
-}
-
-namespace copresence {
-
-class Message;
-
-// AUDIO_FAIL indicates that we weren't able to hear the audio token that
-// we were playing.
-enum CopresenceStatus { SUCCESS, FAIL, AUDIO_FAIL };
-
-// Callback type to send a status.
-using StatusCallback = base::Callback<void(CopresenceStatus)>;
-
-// A delegate interface for users of Copresence.
-class CopresenceDelegate {
- public:
- // This method will be called when we have subscribed messages
- // that need to be sent to their respective apps.
- virtual void HandleMessages(
- const std::string& app_id,
- const std::string& subscription_id,
- const std::vector<Message>& messages) = 0;
-
- virtual void HandleStatusUpdate(CopresenceStatus status) = 0;
-
- // Thw URLRequestContextGetter must outlive the CopresenceManager.
- virtual net::URLRequestContextGetter* GetRequestContext() const = 0;
-
- virtual std::string GetPlatformVersionString() const = 0;
-
- virtual std::string GetAPIKey(const std::string& app_id) const = 0;
-
- // The WhispernetClient must outlive the CopresenceManager.
- virtual audio_modem::WhispernetClient* GetWhispernetClient() = 0;
-
- // Clients may optionally provide a GCMDriver to receive messages from.
- // If no driver is available, this can return null.
- virtual gcm::GCMDriver* GetGCMDriver() = 0;
-
- // Get the copresence device ID for authenticated or anonymous calls,
- // as specified. If none exists, return the empty string.
- virtual std::string GetDeviceId(bool authenticated) = 0;
-
- // Save a copresence device ID for authenticated or anonymous calls.
- // If the device ID is empty, any stored ID should be deleted.
- virtual void SaveDeviceId(bool authenticated,
- const std::string& device_id) = 0;
-
- protected:
- virtual ~CopresenceDelegate() {}
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_DELEGATE_H_
diff --git a/chromium/components/copresence/public/copresence_manager.h b/chromium/components/copresence/public/copresence_manager.h
deleted file mode 100644
index 0807f22c8f8..00000000000
--- a/chromium/components/copresence/public/copresence_manager.h
+++ /dev/null
@@ -1,46 +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 COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_MANAGER_H_
-#define COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_MANAGER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "components/copresence/public/copresence_delegate.h"
-
-namespace copresence {
-
-class CopresenceState;
-class ReportRequest;
-
-// The CopresenceManager class is the central interface for Copresence
-// functionality. This class handles all the initialization and delegation
-// of copresence tasks. Any user of copresence only needs to interact
-// with this class.
-class CopresenceManager {
- public:
- CopresenceManager() {}
- virtual ~CopresenceManager() {}
-
- // Accessor for the CopresenceState instance that tracks debug info.
- virtual CopresenceState* state() = 0;
-
- // This method will execute a report request. Each report request can have
- // multiple (un)publishes, (un)subscribes. This will ensure that once the
- // manager is initialized, it sends all request to the server and handles
- // the response. If an error is encountered, the status callback is used
- // to relay it to the requester.
- virtual void ExecuteReportRequest(const ReportRequest& request,
- const std::string& app_id,
- const std::string& auth_token,
- const StatusCallback& callback) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CopresenceManager);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_MANAGER_H_
diff --git a/chromium/components/copresence/public/copresence_observer.h b/chromium/components/copresence/public/copresence_observer.h
deleted file mode 100644
index 1e28726927e..00000000000
--- a/chromium/components/copresence/public/copresence_observer.h
+++ /dev/null
@@ -1,35 +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 COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_OBSERVER_H_
-#define COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_OBSERVER_H_
-
-namespace copresence {
-
-class Directive;
-struct TransmittedToken;
-struct ReceivedToken;
-
-// Implement this interface to be notified of changes
-// to the state of the copresence component.
-// TODO(ckehoe): Create a LoggingObserver based on this that replaces
-// equivalent logging elsewhere. Then we know what state is being recorded.
-class CopresenceObserver {
- public:
- // Called when the list of active directives has changed.
- virtual void DirectivesUpdated() = 0;
-
- // Called when a token is transmitted.
- virtual void TokenTransmitted(const TransmittedToken& token) = 0;
-
- // Called when a token is received.
- virtual void TokenReceived(const ReceivedToken& token) = 0;
-
- protected:
- virtual ~CopresenceObserver() {}
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_OBSERVER_H_
diff --git a/chromium/components/copresence/public/copresence_state.h b/chromium/components/copresence/public/copresence_state.h
deleted file mode 100644
index f9220078151..00000000000
--- a/chromium/components/copresence/public/copresence_state.h
+++ /dev/null
@@ -1,47 +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 COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_STATE_H_
-#define COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_STATE_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-namespace copresence {
-
-class CopresenceObserver;
-class Directive;
-struct TransmittedToken;
-struct ReceivedToken;
-
-// This class tracks the state of the copresence component and can notify
-// interested parties when it changes. This is useful for debugging purposes.
-class CopresenceState {
- public:
- // Add a listener for future state changes. |observer| is owned by the caller,
- // and must be valid until removed (or the CopresenceState is destroyed).
- virtual void AddObserver(CopresenceObserver* observer) = 0;
-
- // Remove a state change listener.
- virtual void RemoveObserver(CopresenceObserver* observer) = 0;
-
- // Accessor for the currently active directives.
- virtual const std::vector<Directive>& active_directives() const = 0;
-
- // Accessor for recently transmitted tokens.
- virtual const std::map<std::string, TransmittedToken>&
- transmitted_tokens() const = 0;
-
- // Accessor for recently received tokens.
- virtual const std::map<std::string, ReceivedToken>&
- received_tokens() const = 0;
-
- protected:
- virtual ~CopresenceState() {}
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_PUBLIC_COPRESENCE_STATE_H_
diff --git a/chromium/components/copresence/rpc/http_post.cc b/chromium/components/copresence/rpc/http_post.cc
deleted file mode 100644
index 63ea7e74d29..00000000000
--- a/chromium/components/copresence/rpc/http_post.cc
+++ /dev/null
@@ -1,110 +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 "components/copresence/rpc/http_post.h"
-
-// TODO(ckehoe): Support third-party protobufs too.
-#include <google/protobuf/message_lite.h>
-
-#include "base/bind.h"
-#include "google_apis/google_api_keys.h"
-#include "net/base/load_flags.h"
-#include "net/base/net_errors.h"
-#include "net/base/url_util.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "url/gurl.h"
-
-namespace copresence {
-
-const char HttpPost::kApiKeyField[] = "key";
-const char HttpPost::kTracingField[] = "trace";
-
-HttpPost::HttpPost(net::URLRequestContextGetter* url_context_getter,
- const std::string& server_host,
- const std::string& rpc_name,
- std::string api_key,
- const std::string& auth_token,
- const std::string& tracing_token,
- const google::protobuf::MessageLite& request_proto) {
- // Create the base URL to call.
- GURL url(server_host + "/" + rpc_name);
-
- // Add the tracing token, if specified.
- if (!tracing_token.empty()) {
- url = net::AppendQueryParameter(
- url, kTracingField, "token:" + tracing_token);
- }
-
- // If we have no auth token, authenticate using the API key.
- // If no API key is specified, use the Chrome API key.
- if (auth_token.empty()) {
- if (api_key.empty()) {
-#ifdef GOOGLE_CHROME_BUILD
- DCHECK(google_apis::HasKeysConfigured());
- api_key = google_apis::GetAPIKey();
-#else
- LOG(ERROR) << "No Copresence API key provided";
-#endif
- }
- url = net::AppendQueryParameter(url, kApiKeyField, api_key);
- }
-
- // Serialize the proto for transmission.
- std::string request_data;
- bool serialize_success = request_proto.SerializeToString(&request_data);
- DCHECK(serialize_success);
-
- // Configure and send the request.
- url_fetcher_ =
- net::URLFetcher::Create(kUrlFetcherId, url, net::URLFetcher::POST, this);
- url_fetcher_->SetRequestContext(url_context_getter);
- url_fetcher_->SetLoadFlags(net::LOAD_BYPASS_CACHE |
- net::LOAD_DISABLE_CACHE |
- net::LOAD_DO_NOT_SAVE_COOKIES |
- net::LOAD_DO_NOT_SEND_COOKIES |
- net::LOAD_DO_NOT_SEND_AUTH_DATA);
- url_fetcher_->SetUploadData("application/x-protobuf", request_data);
- if (!auth_token.empty()) {
- url_fetcher_->AddExtraRequestHeader("Authorization: Bearer " + auth_token);
- }
-}
-
-HttpPost::~HttpPost() {}
-
-void HttpPost::Start(const ResponseCallback& response_callback) {
- response_callback_ = response_callback;
- DVLOG(3) << "Sending Copresence request to "
- << url_fetcher_->GetOriginalURL().spec();
- url_fetcher_->Start();
-}
-
-void HttpPost::OnURLFetchComplete(const net::URLFetcher* source) {
- DCHECK_EQ(url_fetcher_.get(), source);
-
- // Gather response info.
- std::string response;
- source->GetResponseAsString(&response);
- int response_code = source->GetResponseCode();
-
- // Log any errors.
- if (response_code < 0) {
- net::URLRequestStatus status = source->GetStatus();
- LOG(WARNING) << "Couldn't contact the Copresence server at "
- << source->GetURL() << ". Status code " << status.status();
- LOG_IF(WARNING, status.error())
- << "Network error: " << net::ErrorToString(status.error());
- LOG_IF(WARNING, !response.empty()) << "HTTP response: " << response;
- } else if (response_code != net::HTTP_OK) {
- LOG(WARNING) << "Copresence request got HTTP response code "
- << response_code << ". Response:\n" << response;
- }
-
- // Return the response.
- response_callback_.Run(response_code, response);
- delete this;
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/rpc/http_post.h b/chromium/components/copresence/rpc/http_post.h
deleted file mode 100644
index 911bc5f03a3..00000000000
--- a/chromium/components/copresence/rpc/http_post.h
+++ /dev/null
@@ -1,75 +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 COMPONENTS_COPRESENCE_RPC_HTTP_POST_H_
-#define COMPONENTS_COPRESENCE_RPC_HTTP_POST_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "net/url_request/url_fetcher_delegate.h"
-
-namespace google {
-namespace protobuf {
-class MessageLite;
-}
-}
-
-namespace net {
-class URLRequestContextGetter;
-}
-
-namespace copresence {
-
-// This class handles all Apiary calls to the Copresence server.
-// It configures the HTTP request appropriately and reports any errors.
-// If deleted, the HTTP request is cancelled.
-//
-// TODO(ckehoe): Add retry logic.
-class HttpPost : public net::URLFetcherDelegate {
- public:
- // Callback to receive the HTTP status code and body of the response
- // (if any). A pointer to this HttpPost object is also passed along.
- using ResponseCallback = base::Callback<void(int, const std::string&)>;
-
- // Create a request to the Copresence server.
- // |url_context_getter| is owned by the caller,
- // and the context it provides must be available until the request completes.
- HttpPost(net::URLRequestContextGetter* url_context_getter,
- const std::string& server_host,
- // TODO(ckehoe): Condense some of these into a struct.
- const std::string& rpc_name,
- std::string api_key, // If blank, we overwrite with a default.
- const std::string& auth_token,
- const std::string& tracing_token,
- const google::protobuf::MessageLite& request_proto);
-
- // HTTP requests are cancelled on delete.
- ~HttpPost() override;
-
- // Send an HttpPost request.
- void Start(const ResponseCallback& response_callback);
-
- private:
- static const int kUrlFetcherId = 1;
- static const char kApiKeyField[];
- static const char kTracingField[];
-
- friend class HttpPostTest;
-
- // Overridden from net::URLFetcherDelegate.
- void OnURLFetchComplete(const net::URLFetcher* source) override;
-
- ResponseCallback response_callback_;
-
- std::unique_ptr<net::URLFetcher> url_fetcher_;
-
- DISALLOW_COPY_AND_ASSIGN(HttpPost);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_RPC_HTTP_POST_H_
diff --git a/chromium/components/copresence/rpc/http_post_unittest.cc b/chromium/components/copresence/rpc/http_post_unittest.cc
deleted file mode 100644
index 92bc5808ffa..00000000000
--- a/chromium/components/copresence/rpc/http_post_unittest.cc
+++ /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.
-
-#include "components/copresence/rpc/http_post.h"
-
-#include "base/test/test_simple_task_runner.h"
-#include "components/copresence/proto/data.pb.h"
-#include "net/base/url_util.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace {
-
-const char kFakeServerHost[] = "test.server.google.com";
-const char kRPCName[] = "testRpc";
-const char kTracingToken[] = "trace me!";
-const char kApiKey[] = "unlock ALL the APIz";
-const char kAuthToken[] = "oogabooga";
-
-} // namespace
-
-using google::protobuf::MessageLite;
-
-namespace copresence {
-
-class HttpPostTest : public testing::Test {
- public:
- HttpPostTest() {
- context_getter_ = new net::TestURLRequestContextGetter(
- make_scoped_refptr(new base::TestSimpleTaskRunner));
- proto_.set_client("test_client");
- proto_.set_version_code(123);
- }
- ~HttpPostTest() override {}
-
- // Check that the correct response was sent.
- void TestResponseCallback(int expected_response_code,
- const std::string& expected_response,
- int actual_response_code,
- const std::string& actual_response) {
- CHECK_EQ(expected_response_code, actual_response_code);
- CHECK_EQ(expected_response, actual_response);
- }
-
- protected:
- void CheckPassthrough(int response_code, const std::string& response) {
- HttpPost* post = new HttpPost(
- context_getter_.get(), std::string("http://") + kFakeServerHost,
- kRPCName, kApiKey,
- "", // auth token
- "", // tracing token
- proto_);
- post->Start(base::Bind(&HttpPostTest::TestResponseCallback,
- base::Unretained(this),
- response_code,
- response));
-
- net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(
- HttpPost::kUrlFetcherId);
- fetcher->set_response_code(response_code);
- fetcher->SetResponseString(response);
- fetcher->delegate()->OnURLFetchComplete(fetcher);
- }
-
- net::TestURLFetcher* GetFetcher() {
- return fetcher_factory_.GetFetcherByID(HttpPost::kUrlFetcherId);
- }
-
- const std::string GetApiKeySent() {
- std::string api_key_sent;
- net::GetValueForKeyInQuery(GetFetcher()->GetOriginalURL(),
- HttpPost::kApiKeyField,
- &api_key_sent);
- return api_key_sent;
- }
-
- const std::string GetAuthHeaderSent() {
- net::HttpRequestHeaders headers;
- std::string header;
- GetFetcher()->GetExtraRequestHeaders(&headers);
- return headers.GetHeader("Authorization", &header) ? header : "";
- }
-
- const std::string GetTracingTokenSent() {
- std::string tracing_token_sent;
- net::GetValueForKeyInQuery(GetFetcher()->GetOriginalURL(),
- HttpPost::kTracingField,
- &tracing_token_sent);
- return tracing_token_sent;
- }
-
- net::TestURLFetcherFactory fetcher_factory_;
- scoped_refptr<net::TestURLRequestContextGetter> context_getter_;
-
- ClientVersion proto_;
-};
-
-TEST_F(HttpPostTest, OKResponse) {
- // "Send" the proto to the "server".
- HttpPost* post = new HttpPost(context_getter_.get(),
- std::string("http://") + kFakeServerHost,
- kRPCName,
- kApiKey,
- kAuthToken,
- kTracingToken,
- proto_);
- post->Start(base::Bind(&HttpPostTest::TestResponseCallback,
- base::Unretained(this),
- net::HTTP_OK,
- "Hello World!"));
-
- // Verify that the data was sent to the right place.
- GURL requested_url = GetFetcher()->GetOriginalURL();
- EXPECT_EQ(kFakeServerHost, requested_url.host());
- EXPECT_EQ(std::string("/") + kRPCName, requested_url.path());
-
- // Check parameters.
- EXPECT_EQ("", GetApiKeySent()); // No API key when using an auth token.
- EXPECT_EQ(std::string("Bearer ") + kAuthToken, GetAuthHeaderSent());
- EXPECT_EQ(std::string("token:") + kTracingToken, GetTracingTokenSent());
-
- // Verify that the right data was sent.
- std::string upload_data;
- ASSERT_TRUE(proto_.SerializeToString(&upload_data));
- EXPECT_EQ(upload_data, GetFetcher()->upload_data());
-
- // Send a response and check that it's passed along correctly.
- GetFetcher()->set_response_code(net::HTTP_OK);
- GetFetcher()->SetResponseString("Hello World!");
- GetFetcher()->delegate()->OnURLFetchComplete(GetFetcher());
-}
-
-TEST_F(HttpPostTest, ErrorResponse) {
- CheckPassthrough(net::HTTP_BAD_REQUEST, "Bad client. Shame on you.");
- CheckPassthrough(net::HTTP_INTERNAL_SERVER_ERROR, "I'm dying. Forgive me.");
- CheckPassthrough(-1, "");
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/rpc/rpc_handler.cc b/chromium/components/copresence/rpc/rpc_handler.cc
deleted file mode 100644
index 58eec73d316..00000000000
--- a/chromium/components/copresence/rpc/rpc_handler.cc
+++ /dev/null
@@ -1,620 +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 "components/copresence/rpc/rpc_handler.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-// TODO(ckehoe): time.h includes windows.h, which #defines DeviceCapabilities
-// to DeviceCapabilitiesW. This breaks the pb.h headers below. For now,
-// we fix this with an #undef.
-#include "base/time/time.h"
-#include "build/build_config.h"
-#if defined(OS_WIN)
-#undef DeviceCapabilities
-#endif
-
-#include "components/audio_modem/public/audio_modem_types.h"
-#include "components/copresence/copresence_state_impl.h"
-#include "components/copresence/copresence_switches.h"
-#include "components/copresence/handlers/directive_handler.h"
-#include "components/copresence/handlers/gcm_handler.h"
-#include "components/copresence/proto/codes.pb.h"
-#include "components/copresence/proto/data.pb.h"
-#include "components/copresence/proto/rpcs.pb.h"
-#include "components/copresence/public/copresence_constants.h"
-#include "components/copresence/public/copresence_delegate.h"
-#include "components/copresence/rpc/http_post.h"
-#include "net/http/http_status_code.h"
-
-using google::protobuf::MessageLite;
-
-using audio_modem::AUDIBLE;
-using audio_modem::AudioToken;
-using audio_modem::INAUDIBLE;
-
-// TODO(ckehoe): Return error messages for bad requests.
-
-namespace copresence {
-
-const char RpcHandler::kReportRequestRpcName[] = "report";
-
-namespace {
-
-const int kTokenLoggingSuffix = 5;
-const int kInvalidTokenExpiryTimeMinutes = 10;
-const int kMaxInvalidTokens = 10000;
-const char kRegisterDeviceRpcName[] = "registerdevice";
-const char kDefaultCopresenceServer[] =
- "https://www.googleapis.com/copresence/v2/copresence";
-
-// UrlSafe is defined as:
-// '/' represented by a '_' and '+' represented by a '-'
-// TODO(rkc): Move this to the wrapper.
-std::string ToUrlSafe(std::string token) {
- base::ReplaceChars(token, "+", "-", &token);
- base::ReplaceChars(token, "/", "_", &token);
- return token;
-}
-
-// Logging
-
-// Checks for a copresence error. If there is one, logs it and returns true.
-bool IsErrorStatus(const Status& status) {
- if (status.code() != OK) {
- LOG(ERROR) << "Copresence error code " << status.code()
- << (status.message().empty() ? "" : ": " + status.message());
- }
- return status.code() != OK;
-}
-
-void LogIfErrorStatus(const util::error::Code& code,
- const std::string& context) {
- LOG_IF(ERROR, code != util::error::OK)
- << context << " error " << code << ". See "
- << "cs/google3/util/task/codes.proto for more info.";
-}
-
-// If any errors occurred, logs them and returns true.
-bool ReportErrorLogged(const ReportResponse& response) {
- bool result = IsErrorStatus(response.header().status());
-
- // The Report fails or succeeds as a unit. If any responses had errors,
- // the header will too. Thus we don't need to propagate individual errors.
- if (response.has_update_signals_response())
- LogIfErrorStatus(response.update_signals_response().status(), "Update");
- if (response.has_manage_messages_response())
- LogIfErrorStatus(response.manage_messages_response().status(), "Publish");
- if (response.has_manage_subscriptions_response()) {
- LogIfErrorStatus(response.manage_subscriptions_response().status(),
- "Subscribe");
- }
-
- return result;
-}
-
-const std::string LoggingStrForToken(const std::string& auth_token) {
- if (auth_token.empty())
- return "anonymous";
-
- std::string token_suffix = auth_token.substr(
- auth_token.length() - kTokenLoggingSuffix, kTokenLoggingSuffix);
- return "token ..." + token_suffix;
-}
-
-
-// Request construction
-
-template <typename T>
-BroadcastScanConfiguration GetBroadcastScanConfig(const T& msg) {
- if (msg.has_token_exchange_strategy() &&
- msg.token_exchange_strategy().has_broadcast_scan_configuration()) {
- return msg.token_exchange_strategy().broadcast_scan_configuration();
- }
- return BROADCAST_SCAN_CONFIGURATION_UNKNOWN;
-}
-
-std::unique_ptr<DeviceState> GetDeviceCapabilities(
- const ReportRequest& request) {
- std::unique_ptr<DeviceState> state(new DeviceState);
-
- TokenTechnology* ultrasound =
- state->mutable_capabilities()->add_token_technology();
- ultrasound->set_medium(AUDIO_ULTRASOUND_PASSBAND);
- ultrasound->add_instruction_type(TRANSMIT);
- ultrasound->add_instruction_type(RECEIVE);
-
- TokenTechnology* audible =
- state->mutable_capabilities()->add_token_technology();
- audible->set_medium(AUDIO_AUDIBLE_DTMF);
- audible->add_instruction_type(TRANSMIT);
- audible->add_instruction_type(RECEIVE);
-
- return state;
-}
-
-// TODO(ckehoe): We're keeping this code in a separate function for now
-// because we get a version string from Chrome, but the proto expects
-// an int64_t version. We should probably change the version proto
-// to handle a more detailed version.
-ClientVersion* CreateVersion(const std::string& client,
- const std::string& version_name) {
- ClientVersion* version = new ClientVersion;
- version->set_client(client);
- version->set_version_name(version_name);
- return version;
-}
-
-void AddTokenToRequest(const AudioToken& token, ReportRequest* request) {
- TokenObservation* token_observation =
- request->mutable_update_signals_request()->add_token_observation();
- token_observation->set_token_id(ToUrlSafe(token.token));
-
- TokenSignals* signals = token_observation->add_signals();
- signals->set_medium(token.audible ? AUDIO_AUDIBLE_DTMF
- : AUDIO_ULTRASOUND_PASSBAND);
- signals->set_observed_time_millis(base::Time::Now().ToJsTime());
-}
-
-} // namespace
-
-
-// Public functions.
-
-RpcHandler::RpcHandler(CopresenceDelegate* delegate,
- DirectiveHandler* directive_handler,
- CopresenceStateImpl* state,
- GCMHandler* gcm_handler,
- const MessagesCallback& new_messages_callback,
- const PostCallback& server_post_callback)
- : delegate_(delegate),
- directive_handler_(directive_handler),
- state_(state),
- gcm_handler_(gcm_handler),
- new_messages_callback_(new_messages_callback),
- server_post_callback_(server_post_callback),
- invalid_audio_token_cache_(
- base::TimeDelta::FromMinutes(kInvalidTokenExpiryTimeMinutes),
- kMaxInvalidTokens) {
- DCHECK(delegate_);
- DCHECK(directive_handler_);
- // |gcm_handler_| is optional.
-
- if (server_post_callback_.is_null()) {
- server_post_callback_ =
- base::Bind(&RpcHandler::SendHttpPost, base::Unretained(this));
- }
-
- if (gcm_handler_) {
- gcm_handler_->GetGcmId(
- base::Bind(&RpcHandler::RegisterGcmId, base::Unretained(this)));
- }
- }
-
-RpcHandler::~RpcHandler() {
- // TODO(ckehoe): Cancel the GCM callback?
- for (HttpPost* post : pending_posts_)
- delete post;
-}
-
-void RpcHandler::SendReportRequest(std::unique_ptr<ReportRequest> request,
- const std::string& app_id,
- const std::string& auth_token,
- const StatusCallback& status_callback) {
- DCHECK(request.get());
-
- // Check that the app, if any, has some kind of authentication token.
- // Don't allow it to piggyback on Chrome's credentials.
- if (!app_id.empty() && delegate_->GetAPIKey(app_id).empty() &&
- auth_token.empty()) {
- LOG(ERROR) << "App " << app_id << " has no API key or auth token";
- status_callback.Run(FAIL);
- return;
- }
-
- // Store just one auth token since we should have only one account
- // per instance of the copresence component.
- // TODO(ckehoe): We may eventually need to support multiple auth tokens.
- const bool authenticated = !auth_token.empty();
- if (authenticated && auth_token != auth_token_) {
- LOG_IF(ERROR, !auth_token_.empty())
- << "Overwriting old auth token: " << LoggingStrForToken(auth_token);
- auth_token_ = auth_token;
- }
-
- // Check that we have a "device" registered for this authentication state.
- bool queue_request;
- const std::string device_id = delegate_->GetDeviceId(authenticated);
- if (device_id.empty()) {
- queue_request = true;
- if (pending_registrations_.count(authenticated) == 0)
- RegisterDevice(authenticated);
- // else, registration is already in progress.
- } else {
- queue_request = false;
- }
-
- // We're not registered, or registration is in progress.
- if (queue_request) {
- pending_requests_queue_.push_back(new PendingRequest(
- std::move(request), app_id, authenticated, status_callback));
- return;
- }
-
- DVLOG(3) << "Sending ReportRequest to server.";
-
- // If we are unpublishing or unsubscribing, we need to stop those publish or
- // subscribes right away, we don't need to wait for the server to tell us.
- ProcessRemovedOperations(*request);
-
- request->mutable_update_signals_request()->set_allocated_state(
- GetDeviceCapabilities(*request).release());
-
- AddPlayingTokens(request.get());
-
- request->set_allocated_header(CreateRequestHeader(app_id, device_id));
- server_post_callback_.Run(
- delegate_->GetRequestContext(), kReportRequestRpcName,
- delegate_->GetAPIKey(app_id), auth_token,
- base::WrapUnique<MessageLite>(request.release()),
- // On destruction, this request will be cancelled.
- base::Bind(&RpcHandler::ReportResponseHandler, base::Unretained(this),
- status_callback));
-}
-
-void RpcHandler::ReportTokens(const std::vector<AudioToken>& tokens) {
- DCHECK(!tokens.empty());
-
- std::unique_ptr<ReportRequest> request(new ReportRequest);
- for (const AudioToken& token : tokens) {
- if (invalid_audio_token_cache_.HasKey(ToUrlSafe(token.token)))
- continue;
- DVLOG(3) << "Sending token " << token.token << " to server";
- AddTokenToRequest(token, request.get());
- }
-
- ReportOnAllDevices(std::move(request));
-}
-
-
-// Private functions.
-
-RpcHandler::PendingRequest::PendingRequest(
- std::unique_ptr<ReportRequest> report,
- const std::string& app_id,
- bool authenticated,
- const StatusCallback& callback)
- : report(std::move(report)),
- app_id(app_id),
- authenticated(authenticated),
- callback(callback) {}
-
-RpcHandler::PendingRequest::~PendingRequest() {}
-
-void RpcHandler::RegisterDevice(const bool authenticated) {
- DVLOG(2) << "Sending " << (authenticated ? "authenticated" : "anonymous")
- << " registration to server.";
-
- std::unique_ptr<RegisterDeviceRequest> request(new RegisterDeviceRequest);
-
- // Add a GCM ID for authenticated registration, if we have one.
- if (!authenticated || gcm_id_.empty()) {
- request->mutable_push_service()->set_service(PUSH_SERVICE_NONE);
- } else {
- DVLOG(2) << "Registering GCM ID with " << LoggingStrForToken(auth_token_);
- request->mutable_push_service()->set_service(GCM);
- request->mutable_push_service()->mutable_gcm_registration()
- ->set_device_token(gcm_id_);
- }
-
- // Only identify as a Chrome device if we're in anonymous mode.
- // Authenticated calls come from a "GAIA device".
- if (!authenticated) {
- // Make sure this isn't a duplicate anonymous registration.
- // Duplicate authenticated registrations are allowed, to update the GCM ID.
- DCHECK(delegate_->GetDeviceId(false).empty())
- << "Attempted anonymous re-registration";
-
- Identity* identity =
- request->mutable_device_identifiers()->mutable_registrant();
- identity->set_type(CHROME);
- }
-
- bool gcm_pending = authenticated && gcm_handler_ && gcm_id_.empty();
- pending_registrations_.insert(authenticated);
- request->set_allocated_header(CreateRequestHeader(
- // The device is empty on first registration.
- // When re-registering to pass on the GCM ID, it will be present.
- std::string(), delegate_->GetDeviceId(authenticated)));
- if (authenticated)
- DCHECK(!auth_token_.empty());
- server_post_callback_.Run(
- delegate_->GetRequestContext(), kRegisterDeviceRpcName, std::string(),
- authenticated ? auth_token_ : std::string(),
- base::WrapUnique<MessageLite>(request.release()),
- // On destruction, this request will be cancelled.
- base::Bind(&RpcHandler::RegisterResponseHandler, base::Unretained(this),
- authenticated, gcm_pending));
-}
-
-void RpcHandler::ProcessQueuedRequests(const bool authenticated) {
- // If there is no device ID for this auth state, registration failed.
- bool registration_failed = delegate_->GetDeviceId(authenticated).empty();
-
- // We momentarily take ownership of all the pointers in the queue.
- // They are either deleted here or passed on to a new queue.
- ScopedVector<PendingRequest> requests_being_processed;
- std::swap(requests_being_processed, pending_requests_queue_);
- for (PendingRequest* request : requests_being_processed) {
- if (request->authenticated == authenticated) {
- if (registration_failed) {
- request->callback.Run(FAIL);
- } else {
- if (request->authenticated)
- DCHECK(!auth_token_.empty());
- SendReportRequest(std::move(request->report), request->app_id,
- request->authenticated ? auth_token_ : std::string(),
- request->callback);
- }
- delete request;
- } else {
- // The request is in a different auth state.
- pending_requests_queue_.push_back(request);
- }
- }
-
- // Only keep the requests that weren't processed.
- // All the pointers in the queue are now spoken for.
- requests_being_processed.weak_clear();
-}
-
-void RpcHandler::ReportOnAllDevices(std::unique_ptr<ReportRequest> request) {
- std::vector<bool> auth_states;
- if (!auth_token_.empty() && !delegate_->GetDeviceId(true).empty())
- auth_states.push_back(true);
- if (!delegate_->GetDeviceId(false).empty())
- auth_states.push_back(false);
- if (auth_states.empty()) {
- VLOG(2) << "Skipping reporting because no device IDs are registered";
- return;
- }
-
- for (bool authenticated : auth_states) {
- SendReportRequest(
- base::WrapUnique(new ReportRequest(*request)), std::string(),
- authenticated ? auth_token_ : std::string(), StatusCallback());
- }
-}
-
-// Store a GCM ID and send it to the server if needed. The constructor passes
-// this callback to the GCMHandler to receive the ID whenever it's ready.
-// It may be returned immediately, if the ID is cached, or require a server
-// round-trip. This ID must then be passed along to the copresence server.
-// There are a few ways this can happen:
-//
-// 1. The GCM ID is available when we first register, and is passed along
-// with the RegisterDeviceRequest.
-//
-// 2. The GCM ID becomes available after the RegisterDeviceRequest has
-// completed. Then this function will invoke RegisterDevice()
-// again to pass on the ID.
-//
-// 3. The GCM ID becomes available after the RegisterDeviceRequest is sent,
-// but before it completes. In this case, the gcm_pending flag is passed
-// through to the RegisterResponseHandler, which invokes RegisterDevice()
-// again to pass on the ID. This function must skip pending registrations,
-// as the device ID will be empty.
-//
-// TODO(ckehoe): Add tests for these scenarios.
-void RpcHandler::RegisterGcmId(const std::string& gcm_id) {
- gcm_id_ = gcm_id;
- if (!gcm_id.empty()) {
- const std::string& device_id = delegate_->GetDeviceId(true);
- if (!auth_token_.empty() && !device_id.empty())
- RegisterDevice(true);
- }
-}
-
-void RpcHandler::RegisterResponseHandler(
- bool authenticated,
- bool gcm_pending,
- HttpPost* completed_post,
- int http_status_code,
- const std::string& response_data) {
- if (completed_post) {
- size_t elements_erased = pending_posts_.erase(completed_post);
- DCHECK_GT(elements_erased, 0u);
- }
-
- size_t registrations_completed = pending_registrations_.erase(authenticated);
- DCHECK_GT(registrations_completed, 0u);
-
- RegisterDeviceResponse response;
- const std::string token_str =
- LoggingStrForToken(authenticated ? auth_token_ : std::string());
- if (http_status_code != net::HTTP_OK) {
- // TODO(ckehoe): Retry registration if appropriate.
- LOG(ERROR) << token_str << " device registration failed";
- } else if (!response.ParseFromString(response_data)) {
- LOG(ERROR) << "Invalid RegisterDeviceResponse:\n" << response_data;
- } else if (!IsErrorStatus(response.header().status())) {
- const std::string& device_id = response.registered_device_id();
- DCHECK(!device_id.empty());
- delegate_->SaveDeviceId(authenticated, device_id);
- DVLOG(2) << token_str << " device registration successful. Id: "
- << device_id;
-
- // If we have a GCM ID now, and didn't before, pass it on to the server.
- if (gcm_pending && !gcm_id_.empty())
- RegisterDevice(authenticated);
- }
-
- // Send or fail requests on this auth token.
- ProcessQueuedRequests(authenticated);
-}
-
-void RpcHandler::ReportResponseHandler(const StatusCallback& status_callback,
- HttpPost* completed_post,
- int http_status_code,
- const std::string& response_data) {
- if (completed_post) {
- size_t elements_erased = pending_posts_.erase(completed_post);
- DCHECK_GT(elements_erased, 0u);
- }
-
- if (http_status_code != net::HTTP_OK) {
- if (!status_callback.is_null())
- status_callback.Run(FAIL);
- return;
- }
-
- DVLOG(3) << "Received ReportResponse.";
- ReportResponse response;
- if (!response.ParseFromString(response_data)) {
- LOG(ERROR) << "Invalid ReportResponse";
- if (!status_callback.is_null())
- status_callback.Run(FAIL);
- return;
- }
-
- if (ReportErrorLogged(response)) {
- if (!status_callback.is_null())
- status_callback.Run(FAIL);
- return;
- }
-
- for (const MessageResult& result :
- response.manage_messages_response().published_message_result()) {
- DVLOG(2) << "Published message with id " << result.published_message_id();
- }
-
- for (const SubscriptionResult& result :
- response.manage_subscriptions_response().subscription_result()) {
- DVLOG(2) << "Created subscription with id " << result.subscription_id();
- }
-
- if (response.has_update_signals_response()) {
- const UpdateSignalsResponse& update_response =
- response.update_signals_response();
- new_messages_callback_.Run(update_response.message());
-
- for (const Directive& directive : update_response.directive())
- directive_handler_->AddDirective(directive);
-
- for (const Token& token : update_response.token()) {
- if (state_)
- state_->UpdateTokenStatus(token.id(), token.status());
- switch (token.status()) {
- case VALID:
- // TODO(rkc/ckehoe): Store the token in a |valid_token_cache_| with a
- // short TTL (like 10s) and send it up with every report request.
- // Then we'll still get messages while we're waiting to hear it again.
- VLOG(1) << "Got valid token " << token.id();
- break;
- case INVALID:
- DVLOG(3) << "Discarding invalid token " << token.id();
- invalid_audio_token_cache_.Add(token.id(), true);
- break;
- default:
- DVLOG(2) << "Token " << token.id() << " has status code "
- << token.status();
- }
- }
- }
-
- // TODO(ckehoe): Return a more detailed status response.
- if (!status_callback.is_null())
- status_callback.Run(SUCCESS);
-}
-
-void RpcHandler::ProcessRemovedOperations(const ReportRequest& request) {
- // Remove unpublishes.
- if (request.has_manage_messages_request()) {
- for (const std::string& unpublish :
- request.manage_messages_request().id_to_unpublish()) {
- directive_handler_->RemoveDirectives(unpublish);
- }
- }
-
- // Remove unsubscribes.
- if (request.has_manage_subscriptions_request()) {
- for (const std::string& unsubscribe :
- request.manage_subscriptions_request().id_to_unsubscribe()) {
- directive_handler_->RemoveDirectives(unsubscribe);
- }
- }
-}
-
-void RpcHandler::AddPlayingTokens(ReportRequest* request) {
- const std::string& audible_token =
- directive_handler_->GetCurrentAudioToken(AUDIBLE);
- const std::string& inaudible_token =
- directive_handler_->GetCurrentAudioToken(INAUDIBLE);
-
- if (!audible_token.empty())
- AddTokenToRequest(AudioToken(audible_token, true), request);
- if (!inaudible_token.empty())
- AddTokenToRequest(AudioToken(inaudible_token, false), request);
-}
-
-// TODO(ckehoe): Pass in the version string and
-// group this with the local functions up top.
-RequestHeader* RpcHandler::CreateRequestHeader(
- const std::string& app_id,
- const std::string& device_id) const {
- RequestHeader* header = new RequestHeader;
-
- header->set_allocated_framework_version(CreateVersion(
- "Chrome", delegate_->GetPlatformVersionString()));
- if (!app_id.empty())
- header->set_allocated_client_version(CreateVersion(app_id, std::string()));
- header->set_current_time_millis(base::Time::Now().ToJsTime());
- if (!device_id.empty())
- header->set_registered_device_id(device_id);
-
- DeviceFingerprint* fingerprint = new DeviceFingerprint;
- fingerprint->set_platform_version(delegate_->GetPlatformVersionString());
- fingerprint->set_type(CHROME_PLATFORM_TYPE);
- header->set_allocated_device_fingerprint(fingerprint);
-
- return header;
-}
-
-void RpcHandler::SendHttpPost(net::URLRequestContextGetter* url_context_getter,
- const std::string& rpc_name,
- const std::string& api_key,
- const std::string& auth_token,
- std::unique_ptr<MessageLite> request_proto,
- const PostCleanupCallback& callback) {
- // Create the base URL to call.
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- const std::string copresence_server_host =
- command_line->HasSwitch(switches::kCopresenceServer) ?
- command_line->GetSwitchValueASCII(switches::kCopresenceServer) :
- kDefaultCopresenceServer;
-
- // Create the request and keep a pointer until it completes.
- HttpPost* http_post = new HttpPost(
- url_context_getter,
- copresence_server_host,
- rpc_name,
- api_key,
- auth_token,
- command_line->GetSwitchValueASCII(switches::kCopresenceTracingToken),
- *request_proto);
-
- http_post->Start(base::Bind(callback, http_post));
- pending_posts_.insert(http_post);
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/rpc/rpc_handler.h b/chromium/components/copresence/rpc/rpc_handler.h
deleted file mode 100644
index 16fd1184051..00000000000
--- a/chromium/components/copresence/rpc/rpc_handler.h
+++ /dev/null
@@ -1,213 +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 COMPONENTS_COPRESENCE_RPC_RPC_HANDLER_H_
-#define COMPONENTS_COPRESENCE_RPC_RPC_HANDLER_H_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/scoped_vector.h"
-#include "components/audio_modem/public/audio_modem_types.h"
-#include "components/copresence/proto/enums.pb.h"
-#include "components/copresence/public/copresence_constants.h"
-#include "components/copresence/public/copresence_delegate.h"
-#include "components/copresence/timed_map.h"
-
-namespace copresence {
-
-class CopresenceDelegate;
-class CopresenceStateImpl;
-class DirectiveHandler;
-class GCMHandler;
-class HttpPost;
-class ReportRequest;
-class RequestHeader;
-class SubscribedMessage;
-
-// This class handles all communication with the copresence server.
-// Clients provide a ReportRequest proto containing publishes, subscribes,
-// and token observations they want to send to the server. The RpcHandler
-// will fill in details like the RequestHeader and DeviceCapabilities,
-// and dispatch the results of the server call to the appropriate parts
-// of the system.
-//
-// To create an RpcHandler, clients will need to provide a few other classes
-// that support its functionality. Notable among them is the CopresenceDelegate,
-// an interface clients must implement to provide settings and functionality
-// that may depend on the environment. See the definition in
-// //components/copresence/public/copresence_delegate.h.
-//
-// Here is an example of creating and using an RpcHandler.
-// The GCMHandler and CopresenceStateImpl are optional.
-//
-// MyDelegate delegate(...);
-// copresence::DirectiveHandlerImpl directive_handler;
-//
-// RpcHandler handler(&delegate,
-// &directive_handler,
-// nullptr,
-// nullptr,
-// base::Bind(&HandleMessages));
-//
-// std::unique_ptr<ReportRequest> request(new ReportRequest);
-// (Fill in ReportRequest.)
-//
-// handler.SendReportRequest(std::move(request),
-// "my_app_id",
-// "",
-// base::Bind(&HandleStatus));
-//
-// The server will respond with directives, which get passed to the
-// DirectiveHandlerImpl.
-//
-// Tokens from the audio modem should also be forwarded
-// via ReportTokens() so that messages get delivered properly.
-class RpcHandler final {
- public:
- // An HttpPost::ResponseCallback along with an HttpPost object to be deleted.
- // Arguments:
- // HttpPost*: The handler should take ownership of (i.e. delete) this object.
- // int: The HTTP status code of the response.
- // string: The contents of the response.
- using PostCleanupCallback = base::Callback<void(HttpPost*,
- int,
- const std::string&)>;
-
- // Callback to allow tests to stub out HTTP POST behavior.
- // Arguments:
- // URLRequestContextGetter: Context for the HTTP POST request.
- // string: Name of the rpc to invoke. URL format: server.google.com/rpc_name
- // string: The API key to pass in the request.
- // string: The auth token to pass with the request.
- // MessageLite: Contents of POST request to be sent. This needs to be
- // a (scoped) pointer to ease handling of the abstract MessageLite class.
- // PostCleanupCallback: Receives the response to the request.
- using PostCallback =
- base::Callback<void(net::URLRequestContextGetter*,
- const std::string&,
- const std::string&,
- const std::string&,
- std::unique_ptr<google::protobuf::MessageLite>,
- const PostCleanupCallback&)>;
-
- // Report rpc name to send to Apiary.
- static const char kReportRequestRpcName[];
-
- // Constructor. The CopresenceStateImpl and GCMHandler may be null.
- // The first four parameters are owned by the caller and (if not null)
- // must outlive the RpcHandler.
- RpcHandler(CopresenceDelegate* delegate,
- DirectiveHandler* directive_handler,
- CopresenceStateImpl* state,
- GCMHandler* gcm_handler,
- const MessagesCallback& new_messages_callback,
- const PostCallback& server_post_callback = PostCallback());
-
- // Not copyable.
- RpcHandler(const RpcHandler&) = delete;
- void operator=(const RpcHandler&) = delete;
-
- ~RpcHandler();
-
- // Sends a ReportRequest from a specific app, and get notified of completion.
- void SendReportRequest(std::unique_ptr<ReportRequest> request,
- const std::string& app_id,
- const std::string& auth_token,
- const StatusCallback& callback);
-
- // Reports a set of tokens to the server for a given medium.
- // Uses all active auth tokens (if any).
- void ReportTokens(const std::vector<audio_modem::AudioToken>& tokens);
-
- private:
- // A queued ReportRequest along with its metadata.
- struct PendingRequest {
- PendingRequest(std::unique_ptr<ReportRequest> report,
- const std::string& app_id,
- bool authenticated,
- const StatusCallback& callback);
- ~PendingRequest();
-
- std::unique_ptr<ReportRequest> report;
- const std::string app_id;
- const bool authenticated;
- const StatusCallback callback;
- };
-
- friend class RpcHandlerTest;
-
- // Before accepting any other calls, the server requires registration,
- // which is tied to the auth token (or lack thereof) used to call Report.
- void RegisterDevice(bool authenticated);
-
- // Device registration has completed. Send the requests that it was blocking.
- void ProcessQueuedRequests(bool authenticated);
-
- // Sends a ReportRequest from Chrome itself, i.e. no app id.
- void ReportOnAllDevices(std::unique_ptr<ReportRequest> request);
-
- // Stores a GCM ID and send it to the server if needed.
- void RegisterGcmId(const std::string& gcm_id);
-
- // Server call response handlers.
- void RegisterResponseHandler(bool authenticated,
- bool gcm_pending,
- HttpPost* completed_post,
- int http_status_code,
- const std::string& response_data);
- void ReportResponseHandler(const StatusCallback& status_callback,
- HttpPost* completed_post,
- int http_status_code,
- const std::string& response_data);
-
- // Removes unpublished or unsubscribed operations from the directive handlers.
- void ProcessRemovedOperations(const ReportRequest& request);
-
- // Adds all currently playing tokens to the update signals in this report
- // request. This ensures that the server doesn't keep issueing new tokens to
- // us when we're already playing valid tokens.
- void AddPlayingTokens(ReportRequest* request);
-
- void DispatchMessages(
- const google::protobuf::RepeatedPtrField<SubscribedMessage>&
- subscribed_messages);
-
- RequestHeader* CreateRequestHeader(const std::string& app_id,
- const std::string& device_id) const;
-
- // Wrapper for the http post constructor. This is the default way
- // to contact the server, but it can be overridden for testing.
- void SendHttpPost(
- net::URLRequestContextGetter* url_context_getter,
- const std::string& rpc_name,
- const std::string& api_key,
- const std::string& auth_token,
- std::unique_ptr<google::protobuf::MessageLite> request_proto,
- const PostCleanupCallback& callback);
-
- // These belong to the caller.
- CopresenceDelegate* const delegate_;
- DirectiveHandler* const directive_handler_;
- CopresenceStateImpl* state_;
- GCMHandler* const gcm_handler_;
-
- MessagesCallback new_messages_callback_;
- PostCallback server_post_callback_;
-
- ScopedVector<PendingRequest> pending_requests_queue_;
- TimedMap<std::string, bool> invalid_audio_token_cache_;
- std::set<HttpPost*> pending_posts_;
- std::set<bool> pending_registrations_;
- std::string auth_token_;
- std::string gcm_id_;
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_RPC_RPC_HANDLER_H_
diff --git a/chromium/components/copresence/rpc/rpc_handler_unittest.cc b/chromium/components/copresence/rpc/rpc_handler_unittest.cc
deleted file mode 100644
index ea4baab8f6b..00000000000
--- a/chromium/components/copresence/rpc/rpc_handler_unittest.cc
+++ /dev/null
@@ -1,348 +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 "components/copresence/rpc/rpc_handler.h"
-
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/scoped_vector.h"
-#include "base/message_loop/message_loop.h"
-#include "components/audio_modem/public/modem.h"
-#include "components/audio_modem/test/stub_whispernet_client.h"
-#include "components/copresence/copresence_state_impl.h"
-#include "components/copresence/handlers/directive_handler.h"
-#include "components/copresence/proto/data.pb.h"
-#include "components/copresence/proto/enums.pb.h"
-#include "components/copresence/proto/rpcs.pb.h"
-#include "components/copresence/test/fake_directive_handler.h"
-#include "net/http/http_status_code.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using google::protobuf::MessageLite;
-using google::protobuf::RepeatedPtrField;
-
-using testing::ElementsAre;
-using testing::Property;
-using testing::SizeIs;
-
-using audio_modem::AudioToken;
-using audio_modem::WhispernetClient;
-
-namespace copresence {
-
-namespace {
-
-const char kChromeVersion[] = "Chrome Version String";
-
-void IgnoreMessages(
- const RepeatedPtrField<SubscribedMessage>& /* messages */) {}
-
-} // namespace
-
-class RpcHandlerTest : public testing::Test, public CopresenceDelegate {
- public:
- RpcHandlerTest()
- : whispernet_client_(new audio_modem::StubWhispernetClient),
- // TODO(ckehoe): Use a FakeCopresenceState here
- // and test that it gets called correctly.
- rpc_handler_(this,
- &directive_handler_,
- nullptr,
- nullptr,
- base::Bind(&IgnoreMessages),
- base::Bind(&RpcHandlerTest::CaptureHttpPost,
- base::Unretained(this))),
- status_(SUCCESS) {}
-
- // CopresenceDelegate implementation
-
- void HandleMessages(const std::string& /* app_id */,
- const std::string& subscription_id,
- const std::vector<Message>& messages) override {
- NOTREACHED();
- }
-
- void HandleStatusUpdate(CopresenceStatus /* status */) override {
- NOTREACHED();
- }
-
- net::URLRequestContextGetter* GetRequestContext() const override {
- return nullptr;
- }
-
- std::string GetPlatformVersionString() const override {
- return kChromeVersion;
- }
-
- std::string GetAPIKey(const std::string& app_id) const override {
- return app_id + " API Key";
- }
-
- WhispernetClient* GetWhispernetClient() override {
- return whispernet_client_.get();
- }
-
- // TODO(ckehoe): Add GCM tests.
- gcm::GCMDriver* GetGCMDriver() override {
- return nullptr;
- }
-
- std::string GetDeviceId(bool authenticated) override {
- return device_id_by_auth_state_[authenticated];
- }
-
- void SaveDeviceId(bool authenticated, const std::string& device_id) override {
- device_id_by_auth_state_[authenticated] = device_id;
- }
-
- protected:
-
- // Send test input to RpcHandler
-
- void RegisterDevice(bool authenticated) {
- rpc_handler_.RegisterDevice(authenticated);
- }
-
- void SendRegisterResponse(bool authenticated,
- const std::string& device_id) {
- RegisterDeviceResponse response;
- response.set_registered_device_id(device_id);
- response.mutable_header()->mutable_status()->set_code(OK);
-
- std::string serialized_response;
- response.SerializeToString(&serialized_response);
- rpc_handler_.RegisterResponseHandler(
- authenticated, false, nullptr, net::HTTP_OK, serialized_response);
- }
-
- void SendReport(std::unique_ptr<ReportRequest> request,
- const std::string& app_id,
- const std::string& auth_token) {
- rpc_handler_.SendReportRequest(std::move(request), app_id, auth_token,
- StatusCallback());
- }
-
- void SendReportResponse(int status_code,
- std::unique_ptr<ReportResponse> response) {
- response->mutable_header()->mutable_status()->set_code(OK);
-
- std::string serialized_response;
- response->SerializeToString(&serialized_response);
- rpc_handler_.ReportResponseHandler(
- base::Bind(&RpcHandlerTest::CaptureStatus, base::Unretained(this)),
- nullptr,
- status_code,
- serialized_response);
- }
-
- // Read and modify RpcHandler state
-
- void SetAuthToken(const std::string& auth_token) {
- rpc_handler_.auth_token_ = auth_token;
- }
-
- const ScopedVector<RpcHandler::PendingRequest>& request_queue() const {
- return rpc_handler_.pending_requests_queue_;
- }
-
- void AddInvalidToken(const std::string& token) {
- rpc_handler_.invalid_audio_token_cache_.Add(token, true);
- }
-
- bool TokenIsInvalid(const std::string& token) {
- return rpc_handler_.invalid_audio_token_cache_.HasKey(token);
- }
-
- // For rpc_handler_.invalid_audio_token_cache_
- base::MessageLoop message_loop_;
-
- std::unique_ptr<WhispernetClient> whispernet_client_;
- FakeDirectiveHandler directive_handler_;
- RpcHandler rpc_handler_;
-
- std::map<bool, std::string> device_id_by_auth_state_;
-
- CopresenceStatus status_;
- std::string rpc_name_;
- std::string api_key_;
- std::string auth_token_;
- ScopedVector<MessageLite> request_protos_;
-
- private:
- void CaptureHttpPost(
- net::URLRequestContextGetter* url_context_getter,
- const std::string& rpc_name,
- const std::string& api_key,
- const std::string& auth_token,
- std::unique_ptr<MessageLite> request_proto,
- const RpcHandler::PostCleanupCallback& response_callback) {
- rpc_name_ = rpc_name;
- api_key_ = api_key;
- auth_token_ = auth_token;
- request_protos_.push_back(request_proto.release());
- }
-
- void CaptureStatus(CopresenceStatus status) {
- status_ = status;
- }
-};
-
-TEST_F(RpcHandlerTest, RegisterDevice) {
- RegisterDevice(false);
- EXPECT_THAT(request_protos_, SizeIs(1));
- const RegisterDeviceRequest* registration =
- static_cast<RegisterDeviceRequest*>(request_protos_[0]);
- EXPECT_EQ(CHROME, registration->device_identifiers().registrant().type());
-
- SetAuthToken("Register auth");
- RegisterDevice(true);
- EXPECT_THAT(request_protos_, SizeIs(2));
- registration = static_cast<RegisterDeviceRequest*>(request_protos_[1]);
- EXPECT_FALSE(registration->has_device_identifiers());
-}
-
-TEST_F(RpcHandlerTest, RequestQueuing) {
- // Send a report.
- ReportRequest* report = new ReportRequest;
- report->mutable_manage_messages_request()->add_id_to_unpublish("unpublish");
- SendReport(base::WrapUnique(report), "Q App ID", "Q Auth Token");
- EXPECT_THAT(request_queue(), SizeIs(1));
- EXPECT_TRUE(request_queue()[0]->authenticated);
-
- // Check for registration request.
- EXPECT_THAT(request_protos_, SizeIs(1));
- const RegisterDeviceRequest* registration =
- static_cast<RegisterDeviceRequest*>(request_protos_[0]);
- EXPECT_FALSE(registration->device_identifiers().has_registrant());
- EXPECT_EQ("Q Auth Token", auth_token_);
-
- // Send a second report.
- report = new ReportRequest;
- report->mutable_manage_subscriptions_request()->add_id_to_unsubscribe(
- "unsubscribe");
- SendReport(base::WrapUnique(report), "Q App ID", "Q Auth Token");
- EXPECT_THAT(request_protos_, SizeIs(1));
- EXPECT_THAT(request_queue(), SizeIs(2));
- EXPECT_TRUE(request_queue()[1]->authenticated);
-
- // Send an anonymous report.
- report = new ReportRequest;
- report->mutable_update_signals_request()->add_token_observation()
- ->set_token_id("Q Audio Token");
- SendReport(base::WrapUnique(report), "Q App ID", "");
- EXPECT_THAT(request_queue(), SizeIs(3));
- EXPECT_FALSE(request_queue()[2]->authenticated);
-
- // Check for another registration request.
- EXPECT_THAT(request_protos_, SizeIs(2));
- registration = static_cast<RegisterDeviceRequest*>(request_protos_[1]);
- EXPECT_TRUE(registration->device_identifiers().has_registrant());
- EXPECT_EQ("", auth_token_);
-
- // Respond to the first registration.
- SendRegisterResponse(true, "Q Auth Device ID");
- EXPECT_EQ("Q Auth Device ID", device_id_by_auth_state_[true]);
-
- // Check that queued reports are sent.
- EXPECT_THAT(request_protos_, SizeIs(4));
- EXPECT_THAT(request_queue(), SizeIs(1));
- EXPECT_THAT(directive_handler_.removed_directives(),
- ElementsAre("unpublish", "unsubscribe"));
- report = static_cast<ReportRequest*>(request_protos_[2]);
- EXPECT_EQ("unpublish", report->manage_messages_request().id_to_unpublish(0));
- report = static_cast<ReportRequest*>(request_protos_[3]);
- EXPECT_EQ("unsubscribe",
- report->manage_subscriptions_request().id_to_unsubscribe(0));
-
- // Respond to the second registration.
- SendRegisterResponse(false, "Q Anonymous Device ID");
- EXPECT_EQ("Q Anonymous Device ID", device_id_by_auth_state_[false]);
-
- // Check for last report.
- EXPECT_THAT(request_protos_, SizeIs(5));
- EXPECT_TRUE(request_queue().empty());
- report = static_cast<ReportRequest*>(request_protos_[4]);
- EXPECT_EQ("Q Audio Token",
- report->update_signals_request().token_observation(0).token_id());
-}
-
-TEST_F(RpcHandlerTest, CreateRequestHeader) {
- device_id_by_auth_state_[true] = "CreateRequestHeader Device ID";
- SendReport(base::WrapUnique(new ReportRequest), "CreateRequestHeader App",
- "CreateRequestHeader Auth Token");
-
- EXPECT_EQ(RpcHandler::kReportRequestRpcName, rpc_name_);
- EXPECT_EQ("CreateRequestHeader App API Key", api_key_);
- EXPECT_EQ("CreateRequestHeader Auth Token", auth_token_);
- const ReportRequest* report = static_cast<ReportRequest*>(request_protos_[0]);
- EXPECT_EQ(kChromeVersion,
- report->header().framework_version().version_name());
- EXPECT_EQ("CreateRequestHeader App",
- report->header().client_version().client());
- EXPECT_EQ("CreateRequestHeader Device ID",
- report->header().registered_device_id());
- EXPECT_EQ(CHROME_PLATFORM_TYPE,
- report->header().device_fingerprint().type());
-}
-
-TEST_F(RpcHandlerTest, ReportTokens) {
- std::vector<AudioToken> test_tokens;
- test_tokens.push_back(AudioToken("token 1", false));
- test_tokens.push_back(AudioToken("token 2", false));
- test_tokens.push_back(AudioToken("token 3", true));
- AddInvalidToken("token 2");
-
- device_id_by_auth_state_[false] = "ReportTokens Anonymous Device";
- device_id_by_auth_state_[true] = "ReportTokens Auth Device";
- SetAuthToken("ReportTokens Auth");
-
- rpc_handler_.ReportTokens(test_tokens);
- EXPECT_EQ(RpcHandler::kReportRequestRpcName, rpc_name_);
- EXPECT_EQ(" API Key", api_key_);
- EXPECT_THAT(request_protos_, SizeIs(2));
- const ReportRequest* report = static_cast<ReportRequest*>(request_protos_[0]);
- RepeatedPtrField<TokenObservation> tokens_sent =
- report->update_signals_request().token_observation();
- EXPECT_THAT(tokens_sent, ElementsAre(
- Property(&TokenObservation::token_id, "token 1"),
- Property(&TokenObservation::token_id, "token 3"),
- Property(&TokenObservation::token_id, "current audible"),
- Property(&TokenObservation::token_id, "current inaudible")));
-}
-
-TEST_F(RpcHandlerTest, ReportResponseHandler) {
- // Fail on HTTP status != 200.
- std::unique_ptr<ReportResponse> response(new ReportResponse);
- status_ = SUCCESS;
- SendReportResponse(net::HTTP_BAD_REQUEST, std::move(response));
- EXPECT_EQ(FAIL, status_);
-
- // Construct a test ReportResponse.
- response.reset(new ReportResponse);
- response->mutable_header()->mutable_status()->set_code(OK);
- UpdateSignalsResponse* update_response =
- response->mutable_update_signals_response();
- update_response->set_status(util::error::OK);
- Token* invalid_token = update_response->add_token();
- invalid_token->set_id("bad token");
- invalid_token->set_status(INVALID);
- update_response->add_directive()->set_subscription_id("Subscription 1");
- update_response->add_directive()->set_subscription_id("Subscription 2");
-
- // Check processing.
- status_ = FAIL;
- SendReportResponse(net::HTTP_OK, std::move(response));
- EXPECT_EQ(SUCCESS, status_);
- EXPECT_TRUE(TokenIsInvalid("bad token"));
- EXPECT_THAT(directive_handler_.added_directives(),
- ElementsAre("Subscription 1", "Subscription 2"));
-}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/timed_map.h b/chromium/components/copresence/timed_map.h
deleted file mode 100644
index ef3b9961fd8..00000000000
--- a/chromium/components/copresence/timed_map.h
+++ /dev/null
@@ -1,114 +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 COMPONENTS_COPRESENCE_TIMED_MAP_H_
-#define COMPONENTS_COPRESENCE_TIMED_MAP_H_
-
-#include <stddef.h>
-
-#include <map>
-#include <memory>
-#include <queue>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/time/default_tick_clock.h"
-#include "base/time/tick_clock.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-
-namespace copresence {
-
-// TimedMap is a map with the added functionality of clearing any
-// key/value pair after its specified lifetime is over.
-// TODO(ckehoe): Why is this interface so different from std::map?
-template <typename KeyType, typename ValueType>
-class TimedMap {
- public:
- TimedMap(const base::TimeDelta& lifetime, size_t max_elements)
- : kEmptyValue(ValueType()),
- clock_(new base::DefaultTickClock()),
- lifetime_(lifetime),
- max_elements_(max_elements) {
- timer_.Start(FROM_HERE, lifetime_, this, &TimedMap::ClearExpiredTokens);
- }
-
- ~TimedMap() {}
-
- void Add(const KeyType& key, const ValueType& value) {
- map_[key] = value;
- expiry_queue_.push(KeyTimeTuple(key, clock_->NowTicks() + lifetime_));
- while (map_.size() > max_elements_)
- ClearOldestToken();
- }
-
- bool HasKey(const KeyType& key) {
- ClearExpiredTokens();
- return map_.find(key) != map_.end();
- }
-
- const ValueType& GetValue(const KeyType& key) {
- ClearExpiredTokens();
- auto elt = map_.find(key);
- return elt == map_.end() ? kEmptyValue : elt->second;
- }
-
- ValueType* GetMutableValue(const KeyType& key) {
- ClearExpiredTokens();
- auto elt = map_.find(key);
- return elt == map_.end() ? nullptr : &(elt->second);
- }
-
- // TODO(ckehoe): Add a unit test for this.
- size_t Erase(const KeyType& key) {
- return map_.erase(key);
- }
-
- void set_clock_for_testing(std::unique_ptr<base::TickClock> clock) {
- clock_ = std::move(clock);
- }
-
- private:
- void ClearExpiredTokens() {
- while (!expiry_queue_.empty() &&
- expiry_queue_.top().second <= clock_->NowTicks())
- ClearOldestToken();
- }
-
- void ClearOldestToken() {
- map_.erase(expiry_queue_.top().first);
- expiry_queue_.pop();
- }
-
- using KeyTimeTuple = std::pair<KeyType, base::TimeTicks>;
-
- class EarliestFirstComparator {
- public:
- // This will sort our queue with the 'earliest' time being the top.
- bool operator()(const KeyTimeTuple& left, const KeyTimeTuple& right) const {
- return left.second > right.second;
- }
- };
-
- using ExpiryQueue = std::priority_queue<
- KeyTimeTuple, std::vector<KeyTimeTuple>, EarliestFirstComparator>;
-
- const ValueType kEmptyValue;
-
- std::unique_ptr<base::TickClock> clock_;
- base::RepeatingTimer timer_;
- const base::TimeDelta lifetime_;
- const size_t max_elements_;
- std::map<KeyType, ValueType> map_;
- // Priority queue with our element keys ordered by the earliest expiring keys
- // first.
- ExpiryQueue expiry_queue_;
-
- DISALLOW_COPY_AND_ASSIGN(TimedMap);
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_TIMED_MAP_H_
diff --git a/chromium/components/copresence/timed_map_unittest.cc b/chromium/components/copresence/timed_map_unittest.cc
deleted file mode 100644
index 2d55f6a0fd5..00000000000
--- a/chromium/components/copresence/timed_map_unittest.cc
+++ /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.
-
-#include "components/copresence/timed_map.h"
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-struct Value {
- Value() : value(0) {}
- explicit Value(int new_value) : value(new_value) {}
-
- int value;
-};
-
-} // namespace
-
-class TimedMapTest : public testing::Test {
- public:
- using Map = copresence::TimedMap<int, Value>;
-
- TimedMapTest() {}
-
- private:
- // Exists since the timer needs a message loop.
- base::MessageLoop message_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(TimedMapTest);
-};
-
-TEST_F(TimedMapTest, Basic) {
- Map map(base::TimeDelta::FromSeconds(9999), 3);
-
- EXPECT_FALSE(map.HasKey(0));
- EXPECT_EQ(0, map.GetValue(0).value);
-
- map.Add(0x1337, Value(0x7331));
- EXPECT_TRUE(map.HasKey(0x1337));
- EXPECT_EQ(0x7331, map.GetValue(0x1337).value);
-
- map.Add(0xbaad, Value(0xf00d));
- EXPECT_TRUE(map.HasKey(0xbaad));
- EXPECT_EQ(0xf00d, map.GetValue(0xbaad).value);
- EXPECT_EQ(0x7331, map.GetValue(0x1337).value);
-
- map.Add(0x1234, Value(0x5678));
- EXPECT_TRUE(map.HasKey(0x1234));
- EXPECT_TRUE(map.HasKey(0xbaad));
- EXPECT_TRUE(map.HasKey(0x1337));
-
- EXPECT_EQ(0x5678, map.GetValue(0x1234).value);
- EXPECT_EQ(0xf00d, map.GetValue(0xbaad).value);
- EXPECT_EQ(0x7331, map.GetValue(0x1337).value);
-}
-
-TEST_F(TimedMapTest, ValueReplacement) {
- Map map(base::TimeDelta::FromSeconds(9999), 10);
-
- map.Add(0x1337, Value(0x7331));
- EXPECT_TRUE(map.HasKey(0x1337));
- EXPECT_EQ(0x7331, map.GetValue(0x1337).value);
-
- map.Add(0xbaad, Value(0xf00d));
- EXPECT_TRUE(map.HasKey(0xbaad));
- EXPECT_EQ(0xf00d, map.GetValue(0xbaad).value);
-
- map.Add(0x1337, Value(0xd00d));
- EXPECT_TRUE(map.HasKey(0x1337));
- EXPECT_EQ(0xd00d, map.GetValue(0x1337).value);
-}
-
-TEST_F(TimedMapTest, SizeEvict) {
- Map two_element_map(base::TimeDelta::FromSeconds(9999), 2);
-
- two_element_map.Add(0x1337, Value(0x7331));
- EXPECT_TRUE(two_element_map.HasKey(0x1337));
- EXPECT_EQ(0x7331, two_element_map.GetValue(0x1337).value);
-
- two_element_map.Add(0xbaad, Value(0xf00d));
- EXPECT_TRUE(two_element_map.HasKey(0xbaad));
- EXPECT_EQ(0xf00d, two_element_map.GetValue(0xbaad).value);
-
- two_element_map.Add(0x1234, Value(0x5678));
- EXPECT_TRUE(two_element_map.HasKey(0x1234));
- EXPECT_EQ(0xf00d, two_element_map.GetValue(0xbaad).value);
-
- EXPECT_FALSE(two_element_map.HasKey(0x1337));
- EXPECT_EQ(0, two_element_map.GetValue(0x1337).value);
-}
-
-TEST_F(TimedMapTest, TimedEvict) {
- const int kLargeTimeValueSeconds = 9999;
- Map map(base::TimeDelta::FromSeconds(kLargeTimeValueSeconds), 2);
-
- // The map takes ownership of the clock, but we retain a pointer.
- base::SimpleTestTickClock* clock = new base::SimpleTestTickClock;
- map.set_clock_for_testing(base::WrapUnique<base::TickClock>(clock));
-
- // Add value at T=0.
- map.Add(0x1337, Value(0x7331));
- EXPECT_TRUE(map.HasKey(0x1337));
- EXPECT_EQ(0x7331, map.GetValue(0x1337).value);
-
- // Add value at T=kLargeTimeValueSeconds-1.
- clock->Advance(base::TimeDelta::FromSeconds(kLargeTimeValueSeconds - 1));
- map.Add(0xbaad, Value(0xf00d));
-
- // Check values at T=kLargeTimeValueSeconds-1.
- EXPECT_TRUE(map.HasKey(0xbaad));
- EXPECT_EQ(0xf00d, map.GetValue(0xbaad).value);
- EXPECT_TRUE(map.HasKey(0x1337));
- EXPECT_EQ(0x7331, map.GetValue(0x1337).value);
-
- // Check values at T=kLargeTimeValueSeconds.
- clock->Advance(base::TimeDelta::FromSeconds(1));
- EXPECT_FALSE(map.HasKey(0x1337));
- EXPECT_EQ(0, map.GetValue(0x1337).value);
- EXPECT_TRUE(map.HasKey(0xbaad));
- EXPECT_EQ(0xf00d, map.GetValue(0xbaad).value);
-
- // Check values at T=2*kLargeTimeValueSeconds
- clock->Advance(base::TimeDelta::FromSeconds(kLargeTimeValueSeconds));
- EXPECT_FALSE(map.HasKey(0xbaad));
- EXPECT_EQ(0, map.GetValue(0xbaad).value);
-}
diff --git a/chromium/components/copresence/tokens.cc b/chromium/components/copresence/tokens.cc
deleted file mode 100644
index 0fdb0c7c375..00000000000
--- a/chromium/components/copresence/tokens.cc
+++ /dev/null
@@ -1,25 +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 "components/copresence/tokens.h"
-
-namespace copresence {
-
-TransmittedToken::TransmittedToken()
- : medium(TOKEN_MEDIUM_UNKNOWN),
- broadcast_confirmed(false) {}
-
-ReceivedToken::ReceivedToken()
- : medium(TOKEN_MEDIUM_UNKNOWN),
- valid(UNKNOWN) {}
-
-ReceivedToken::ReceivedToken(const std::string& id,
- TokenMedium medium,
- base::Time last_time)
- : id(id),
- medium(medium),
- last_time(last_time),
- valid(UNKNOWN) {}
-
-} // namespace copresence
diff --git a/chromium/components/copresence/tokens.h b/chromium/components/copresence/tokens.h
deleted file mode 100644
index 8895df9710b..00000000000
--- a/chromium/components/copresence/tokens.h
+++ /dev/null
@@ -1,49 +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 COMPONENTS_COPRESENCE_TOKENS_H_
-#define COMPONENTS_COPRESENCE_TOKENS_H_
-
-#include <string>
-
-#include "base/time/time.h"
-#include "components/copresence/proto/enums.pb.h"
-
-namespace copresence {
-
-// It's an error to define these constructors inline,
-// so they're defined in tokens.cc.
-
-struct TransmittedToken final {
- TransmittedToken();
-
- std::string id;
- TokenMedium medium;
- base::Time start_time;
- base::Time stop_time;
- bool broadcast_confirmed;
-};
-
-struct ReceivedToken final {
- enum Validity {
- UNKNOWN = 0,
- VALID = 1,
- INVALID = 2
- };
-
- ReceivedToken();
- ReceivedToken(const std::string& id,
- TokenMedium medium,
- base::Time last_time);
-
- std::string id;
- TokenMedium medium;
- base::Time start_time;
- base::Time last_time;
- Validity valid;
-};
-
-} // namespace copresence
-
-#endif // COMPONENTS_COPRESENCE_TOKENS_H_
diff --git a/chromium/components/crash.gypi b/chromium/components/crash.gypi
deleted file mode 100644
index 7b154b3febe..00000000000
--- a/chromium/components/crash.gypi
+++ /dev/null
@@ -1,484 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/crash/core/browser
- 'target_name': 'crash_core_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'upload_list',
- '../base/base.gyp:base',
- '../components/components_strings.gyp:components_strings',
- ],
- 'sources': [
- 'crash/core/browser/crashes_ui_util.cc',
- 'crash/core/browser/crashes_ui_util.h',
- ],
- },
- {
- # GN version: //components/crash/core/common
- 'target_name': 'crash_core_common',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- # List of dependencies is intentionally very minimal. Please avoid
- # adding extra dependencies without first checking with OWNERS.
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'crash/core/common/crash_keys.cc',
- 'crash/core/common/crash_keys.h',
- ],
- 'conditions': [
- ['OS=="mac" or OS=="ios"', {
- 'sources': [
- 'crash/core/common/objc_zombie.h',
- 'crash/core/common/objc_zombie.mm',
- ],
- }],
- ],
- },
- ],
- 'conditions': [
- ['OS=="win" and target_arch=="ia32"', {
- 'targets': [
- {
- 'target_name': 'crash_core_common_win64',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- # List of dependencies is intentionally very minimal. Please avoid
- # adding extra dependencies without first checking with OWNERS.
- '../base/base.gyp:base_win64',
- ],
- 'sources': [
- 'crash/core/common/crash_keys.cc',
- 'crash/core/common/crash_keys.h',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- ],
- }],
- ['OS!="ios"', {
- 'targets': [
- {
- 'target_name': 'crash_component_lib',
- 'type': 'static_library',
- 'sources': [
- 'crash/content/app/crash_keys_win.cc',
- 'crash/content/app/crash_keys_win.h',
- 'crash/content/app/crash_reporter_client.cc',
- 'crash/content/app/crash_reporter_client.h',
- ],
- 'include_dirs': [
- '..',
- '../breakpad/src',
- ],
- },
- {
- # TODO(mark): https://crbug.com/466890: merge this target with
- # crash_component.
- #
- # This is a temporary base target that is depended on by both
- # crash_component and crash_component_breakpad_to_be_deleted. It
- # provides everything common to both of those targets. For a short
- # period, there are two Mac and Windows crash component
- # implementations. The new one uses a Crashpad implementation and is
- # used by Chrome. The old one uses a Breakpad implementation and is
- # used by content_shell. Consumers should depend on the desired
- # target. All three targets behave identically on non-Mac/-Windows.
- # When content_shell and any other consumers are migrated to the
- # Crashpad implementation on Mac/Windows, crash_component will merge
- # back into this target, crash_component_non_mac_win, which will be
- # renamed crash_component. crash_component_breakpad_to_be_deleted will
- # be deleted.
- #
- # While this situation exists:
- #
- # Do not depend on this target directly! Depend on
- # crash_component_breakpad_to_be_deleted for old Breakpad behavior on
- # all platforms, or preferably, depend on crash_component to get Breakpad
- # everywhere except for Mac and Windows, where you will get Crashpad.
- #
- # GN version: //components/crash/content/app:app_non_mac
- 'target_name': 'crash_component_non_mac_win',
- 'variables': {
- 'conditions': [
- ['OS == "ios" or OS == "mac"', {
- # On IOS there are no files compiled into the library, and we
- # can't have libraries with zero objects.
- # For now, the same applies to Mac OS X, until this target
- # merges with crash_component.
- 'crash_component_target_type%': 'none',
- }, {
- 'crash_component_target_type%': 'static_library',
- }],
- ],
- },
- 'type': '<(crash_component_target_type)',
- 'sources': [
- 'crash/content/app/breakpad_linux.cc',
- 'crash/content/app/breakpad_linux.h',
- 'crash/content/app/breakpad_linux_impl.h',
- 'crash/content/app/hard_error_handler_win.cc',
- 'crash/content/app/hard_error_handler_win.h',
- ],
- 'dependencies': [
- 'crash_component_lib',
- 'crash_core_common',
- '../base/base.gyp:base',
- ],
- 'defines': ['CRASH_IMPLEMENTATION'],
- 'conditions': [
- ['OS=="win"', {
- 'dependencies': [
- '../breakpad/breakpad.gyp:breakpad_handler',
- '../breakpad/breakpad.gyp:breakpad_sender',
- '../sandbox/sandbox.gyp:sandbox',
- ],
- }],
- ['os_posix == 1 and OS != "mac" and OS != "ios"', {
- 'dependencies': [
- '../breakpad/breakpad.gyp:breakpad_client',
- ],
- 'include_dirs': [
- '../breakpad/src',
- ],
- }],
- ['clang==1 and target_arch=="ia32"', {
- 'cflags!': [
- # Clang's -mstackrealign doesn't work well with
- # linux_syscall_support.h hand written asm syscalls.
- # See https://crbug.com/556393
- '-mstackrealign',
- ],
- }],
- ],
- 'target_conditions': [
- # Need 'target_conditions' to override default filename_rules to include
- # the files on Android.
- ['OS=="android"', {
- 'sources/': [
- ['include', '^crash/content/app/breakpad_linux\\.cc$'],
- ],
- }],
- ],
- },
- {
- # Note: if you depend on this target, you need to either link in
- # content.gyp:content_common, or add
- # content/public/common/content_switches.cc to your sources.
- #
- # GN version: //components/crash/content/app
-
- # TODO(mark): https://crbug.com/466890: merge this target with
- # crash_component_non_mac_win.
- #
- # Most of this target is actually in its dependency,
- # crash_component_non_mac_win. See the comment in that target for an
- # explanation for the split. The split is temporary and the two targets
- # will be unified again soon.
- 'target_name': 'crash_component',
- 'variables': {
- 'conditions': [
- ['OS != "mac" and OS != "win"', {
- # There are no source files except on Mac OS X and Windows.
- 'crash_component_target_type%': 'none',
- }, {
- 'crash_component_target_type%': 'static_library',
- }],
- ],
- },
- 'type': '<(crash_component_target_type)',
- 'sources': [
- 'crash/content/app/crash_switches.cc',
- 'crash/content/app/crash_switches.h',
- 'crash/content/app/crashpad.cc',
- 'crash/content/app/crashpad.h',
- 'crash/content/app/crashpad_mac.mm',
- 'crash/content/app/crashpad_win.cc',
- 'crash/content/app/run_as_crashpad_handler_win.cc',
- 'crash/content/app/run_as_crashpad_handler_win.h',
- ],
- 'dependencies': [
- 'crash_component_non_mac_win',
- 'crash_component_lib',
- '../base/base.gyp:base',
- '../third_party/kasko/kasko.gyp:kasko',
- ],
- 'export_dependent_settings': [
- '../third_party/kasko/kasko.gyp:kasko',
- ],
- 'conditions': [
- ['OS=="mac" or OS=="win"', {
- 'dependencies': [
- '../third_party/crashpad/crashpad/client/client.gyp:crashpad_client',
- '../third_party/crashpad/crashpad/snapshot/snapshot.gyp:crashpad_snapshot_api',
- ],
- }],
- ['OS=="win"', {
- 'dependencies': [
- '../third_party/crashpad/crashpad/handler/handler.gyp:crashpad_handler_lib',
- ],
- }],
- ],
- 'defines': ['CRASH_IMPLEMENTATION'],
- },
- {
- # TODO(mark): https://crbug.com/466890: remove this target.
- #
- # This is a temporary target provided for Mac and Windows Breakpad
- # users that have not yet migrated to Crashpad (namely content_shell).
- # This target will be removed shortly and all consumers will be
- # expected to use Crashpad as the Mac and Windows crash-reporting
- # client. See the comment in the crash_component_non_mac_win target
- # for more details.
- #
- # GN version: //components/crash/content/app:app_breakpad_mac_to_be_deleted
- 'target_name': 'crash_component_breakpad_to_be_deleted',
- 'variables': {
- 'conditions': [
- ['OS != "mac" and OS != "win"', {
- # There are no source files on any platform but Mac OS X and
- # Windows.
- 'crash_component_target_type%': 'none',
- }, {
- 'crash_component_target_type%': 'static_library',
- }],
- ],
- },
- 'type': '<(crash_component_target_type)',
- 'sources': [
- 'crash/content/app/breakpad_mac.h',
- 'crash/content/app/breakpad_mac.mm',
- 'crash/content/app/breakpad_win.cc',
- 'crash/content/app/breakpad_win.h',
- ],
- 'dependencies': [
- 'crash_component_non_mac_win',
- 'crash_component_lib',
- ],
- 'defines': ['CRASH_IMPLEMENTATION'],
- 'conditions': [
- ['OS=="mac"', {
- 'dependencies': [
- '../breakpad/breakpad.gyp:breakpad',
- ],
- 'include_dirs': [
- '..',
- '../breakpad/src',
- ],
- }],
- ['OS=="win"', {
- 'dependencies': [
- '../breakpad/breakpad.gyp:breakpad_handler',
- ],
- 'include_dirs': [
- '..',
- '../breakpad/src',
- ],
- 'all_dependent_settings': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'userenv.lib',
- ],
- },
- },
- },
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'userenv.lib',
- ],
- },
- },
- }],
- ],
- },
- {
- # GN version: //components/crash/content/app:test_support
- 'target_name': 'crash_test_support',
- 'type': 'none',
- 'dependencies': [
- 'crash_component_lib',
- ],
- 'direct_dependent_settings': {
- 'include_dirs' : [
- '../breakpad/src',
- ],
- }
- },
- ],
- 'conditions': [
- ['OS=="win"', {
- 'targets': [
- {
- # GN version: //components/crash/content/tools:crash_service
- 'target_name': 'breakpad_crash_service',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../breakpad/breakpad.gyp:breakpad_handler',
- '../breakpad/breakpad.gyp:breakpad_sender',
- ],
- 'sources': [
- 'crash/content/tools/crash_service.cc',
- 'crash/content/tools/crash_service.h',
- ],
- },
- ],
- }],
- ['OS=="win" and target_arch=="ia32"', {
- 'targets': [
- {
- # Note: if you depend on this target, you need to either link in
- # content.gyp:content_common, or add
- # content/public/common/content_switches.cc to your sources.
- 'target_name': 'breakpad_win64',
- 'type': 'static_library',
- 'sources': [
- 'crash/content/app/breakpad_linux.cc',
- 'crash/content/app/breakpad_linux.h',
- 'crash/content/app/breakpad_linux_impl.h',
- 'crash/content/app/breakpad_mac.h',
- 'crash/content/app/breakpad_mac.mm',
- 'crash/content/app/breakpad_win.cc',
- 'crash/content/app/breakpad_win.h',
- # TODO(siggi): test the x64 version too.
- 'crash/content/app/crash_keys_win.cc',
- 'crash/content/app/crash_keys_win.h',
- 'crash/content/app/crash_reporter_client.cc',
- 'crash/content/app/crash_reporter_client.h',
- 'crash/content/app/hard_error_handler_win.cc',
- 'crash/content/app/hard_error_handler_win.h',
- ],
- 'defines': [
- 'COMPILE_CONTENT_STATICALLY',
- 'CRASH_IMPLEMENTATION',
- ],
- 'dependencies': [
- '../base/base.gyp:base_win64',
- '../breakpad/breakpad.gyp:breakpad_handler_win64',
- '../breakpad/breakpad.gyp:breakpad_sender_win64',
- '../sandbox/sandbox.gyp:sandbox_win64',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- 'conditions': [
- ['OS=="win"', {
- 'all_dependent_settings': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'userenv.lib',
- ],
- },
- },
- },
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'userenv.lib',
- ],
- },
- },
- }],
- ],
- },
- {
- # GN version: //components/crash/content/tools:crash_service
- 'target_name': 'breakpad_crash_service_win64',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base_win64',
- '../breakpad/breakpad.gyp:breakpad_handler_win64',
- '../breakpad/breakpad.gyp:breakpad_sender_win64',
- ],
- 'sources': [
- 'crash/content/tools/crash_service.cc',
- 'crash/content/tools/crash_service.h',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- ],
- }],
- ['OS=="mac"', {
- 'targets': [
- {
- # GN version: //components/crash/content/app:breakpad_stubs
- 'target_name': 'breakpad_stubs',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'crash/content/app/breakpad_mac.h',
- 'crash/content/app/breakpad_mac_stubs.mm',
- 'crash/content/app/crash_reporter_client.cc',
- 'crash/content/app/crash_reporter_client.h',
- ],
- },
- ],
- }],
- ['os_posix == 1 and OS != "mac"', {
- 'targets': [
- {
- # GN version: //components/crash/content/browser
- 'target_name': 'breakpad_host',
- 'type': 'static_library',
- 'dependencies': [
- 'crash_component',
- '../base/base.gyp:base',
- '../breakpad/breakpad.gyp:breakpad_client',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- ],
- 'sources': [
- 'crash/content/browser/crash_dump_manager_android.cc',
- 'crash/content/browser/crash_dump_manager_android.h',
- 'crash/content/browser/crash_handler_host_linux.cc',
- 'crash/content/browser/crash_handler_host_linux.h',
- 'crash/content/browser/crash_micro_dump_manager_android.cc',
- 'crash/content/browser/crash_micro_dump_manager_android.h',
- ],
- 'include_dirs': [
- '../breakpad/src',
- ],
- 'target_conditions': [
- # Need 'target_conditions' to override default filename_rules to include
- # the files on Android.
- ['OS=="android"', {
- 'sources/': [
- ['include', '^crash/content/browser/crash_handler_host_linux\\.cc$'],
- ],
- }],
- ],
- },
- ],
- }],
- ],
- }],
- ],
-}
diff --git a/chromium/components/crash/content/app/BUILD.gn b/chromium/components/crash/content/app/BUILD.gn
index 5f1c1be8657..4bdcc707212 100644
--- a/chromium/components/crash/content/app/BUILD.gn
+++ b/chromium/components/crash/content/app/BUILD.gn
@@ -7,7 +7,7 @@ if (is_android) {
import("//build/config/android/config.gni")
}
-source_set("lib") {
+static_library("lib") {
sources = [
"crash_keys_win.cc",
"crash_keys_win.h",
@@ -26,16 +26,13 @@ source_set("lib") {
}
}
-# GYP version: components/crash.gypi:crash_component
-source_set("app") {
+static_library("app") {
sources = [
"crash_switches.cc",
"crash_switches.h",
"crashpad.h",
"crashpad_mac.mm",
"crashpad_win.cc",
- "run_as_crashpad_handler_win.cc",
- "run_as_crashpad_handler_win.h",
]
if (is_mac || is_win) {
@@ -64,6 +61,22 @@ source_set("app") {
}
}
+if (is_win) {
+ static_library("run_as_crashpad_handler") {
+ sources = [
+ "crash_switches.cc",
+ "crash_switches.h",
+ "run_as_crashpad_handler_win.cc",
+ "run_as_crashpad_handler_win.h",
+ ]
+
+ deps = [
+ "//base",
+ "//third_party/crashpad/crashpad/handler:handler_lib",
+ ]
+ }
+}
+
# TODO(mark): https://crbug.com/466890: merge this target with
# crash_component.
#
@@ -131,8 +144,6 @@ source_set("app_non_mac_win") {
deps += [
"//breakpad:breakpad_handler",
"//sandbox",
-
- #'../breakpad/breakpad.gyp:breakpad_sender', TODO(GYP)
]
} else if (is_posix && !is_ios) {
deps += [ "//breakpad:client" ]
@@ -146,7 +157,7 @@ source_set("app_non_mac_win") {
# removed shortly and all consumers will be expected to use Crashpad as
# the Mac crash-reporting client. See the comment in the
# crash_component_non_mac target for more details.
-source_set("app_breakpad_mac_win_to_be_deleted") {
+static_library("app_breakpad_mac_win_to_be_deleted") {
deps = [
":app_non_mac_win",
]
@@ -161,8 +172,10 @@ source_set("app_breakpad_mac_win_to_be_deleted") {
defines = [ "CRASH_IMPLEMENTATION" ]
- deps += [
+ public_deps = [
":lib",
+ ]
+ deps += [
"//base",
"//base:base_static",
"//breakpad:client",
@@ -183,7 +196,7 @@ source_set("app_breakpad_mac_win_to_be_deleted") {
}
if (is_mac) {
- source_set("breakpad_stubs") {
+ static_library("breakpad_stubs") {
sources = [
"breakpad_mac.h",
"breakpad_mac_stubs.mm",
diff --git a/chromium/components/crash/content/app/breakpad_linux.cc b/chromium/components/crash/content/app/breakpad_linux.cc
index c3a01a99224..9ebc33f4f01 100644
--- a/chromium/components/crash/content/app/breakpad_linux.cc
+++ b/chromium/components/crash/content/app/breakpad_linux.cc
@@ -101,7 +101,6 @@ ExceptionHandler* g_breakpad = nullptr;
const char* g_asan_report_str = nullptr;
#endif
#if defined(OS_ANDROID)
-const char kWebViewProcessType[] = "webview";
char* g_process_type = nullptr;
ExceptionHandler* g_microdump = nullptr;
int g_signal_code_pipe_fd = -1;
@@ -137,6 +136,7 @@ class MicrodumpInfo {
const char* microdump_build_fingerprint_;
const char* microdump_product_info_;
const char* microdump_gpu_fingerprint_;
+ const char* microdump_process_type_;
};
base::LazyInstance<MicrodumpInfo> g_microdump_info =
@@ -878,8 +878,12 @@ void MicrodumpInfo::Initialize(const std::string& process_type,
const char* android_build_fp) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!g_microdump);
- bool is_browser_process =
- process_type.empty() || process_type == kWebViewProcessType;
+ // |process_type| for webview's browser process is kBrowserProcessType or
+ // kWebViewSingleProcessType. |process_type| for chrome's browser process is
+ // an empty string.
+ bool is_browser_process = process_type.empty() ||
+ process_type == kWebViewSingleProcessType ||
+ process_type == kBrowserProcessType;
MinidumpDescriptor descriptor(MinidumpDescriptor::kMicrodumpOnConsole);
@@ -890,6 +894,11 @@ void MicrodumpInfo::Initialize(const std::string& process_type,
descriptor.microdump_extra_info()->product_info = microdump_product_info_;
}
+ microdump_process_type_ =
+ strdup(process_type.empty() ? kBrowserProcessType : process_type.c_str());
+ ANNOTATE_LEAKING_OBJECT_PTR(microdump_process_type_);
+ descriptor.microdump_extra_info()->process_type = microdump_process_type_;
+
if (android_build_fp) {
microdump_build_fingerprint_ = strdup(android_build_fp);
ANNOTATE_LEAKING_OBJECT_PTR(microdump_build_fingerprint_);
@@ -908,7 +917,10 @@ void MicrodumpInfo::Initialize(const std::string& process_type,
true, // Install handlers.
-1); // Server file descriptor. -1 for in-process.
- if (process_type == kWebViewProcessType) {
+ if (process_type == kWebViewSingleProcessType ||
+ process_type == kBrowserProcessType) {
+ // TODO(tobiasjs): figure out what to do with on demand minidump on the
+ // renderer process of webview.
// We do not use |DumpProcess()| for handling programatically
// generated dumps for WebView because we only know the file
// descriptor to which we are dumping at the time of the call to
@@ -920,7 +932,7 @@ void MicrodumpInfo::Initialize(const std::string& process_type,
&GenerateMinidumpOnDemandForAndroid);
} else if (!process_type.empty()) {
g_signal_code_pipe_fd =
- GetCrashReporterClient()->GetAndroidMinidumpDescriptor();
+ GetCrashReporterClient()->GetAndroidCrashSignalFD();
if (g_signal_code_pipe_fd != -1)
g_microdump->set_crash_handler(WriteSignalCodeToPipe);
}
diff --git a/chromium/components/crash/content/app/breakpad_linux.h b/chromium/components/crash/content/app/breakpad_linux.h
index 8f73127c80f..3316fa0cbe6 100644
--- a/chromium/components/crash/content/app/breakpad_linux.h
+++ b/chromium/components/crash/content/app/breakpad_linux.h
@@ -17,6 +17,10 @@ namespace breakpad {
extern void InitCrashReporter(const std::string& process_type);
#if defined(OS_ANDROID)
+
+const char kWebViewSingleProcessType[] = "webview";
+const char kBrowserProcessType[] = "browser";
+
// Enables the crash reporter in child processes.
extern void InitNonBrowserCrashReporterForAndroid(
const std::string& process_type);
diff --git a/chromium/components/crash/content/app/breakpad_mac.mm b/chromium/components/crash/content/app/breakpad_mac.mm
index 6c6934bfa7e..d7ab1ae6389 100644
--- a/chromium/components/crash/content/app/breakpad_mac.mm
+++ b/chromium/components/crash/content/app/breakpad_mac.mm
@@ -241,7 +241,7 @@ void InitCrashReporter(const std::string& process_type) {
// Temporarily run Breakpad in-process on 10.10 and later because APIs that
// it depends on got broken (http://crbug.com/386208).
// This can catch crashes in the browser process only.
- if (is_browser && base::mac::IsOSYosemiteOrLater()) {
+ if (is_browser && base::mac::IsAtLeastOS10_10()) {
[breakpad_config setObject:[NSNumber numberWithBool:YES]
forKey:@BREAKPAD_IN_PROCESS];
}
diff --git a/chromium/components/crash/content/app/breakpad_win.cc b/chromium/components/crash/content/app/breakpad_win.cc
index f2bdc3f0ecc..61455c95912 100644
--- a/chromium/components/crash/content/app/breakpad_win.cc
+++ b/chromium/components/crash/content/app/breakpad_win.cc
@@ -5,6 +5,7 @@
#include "components/crash/content/app/breakpad_win.h"
#include <windows.h>
+#include <intrin.h>
#include <shellapi.h>
#include <stddef.h>
#include <tchar.h>
@@ -149,8 +150,11 @@ MSVC_ENABLE_OPTIMIZE()
} // namespace
// Injects a thread into a remote process to dump state when there is no crash.
-extern "C" HANDLE __declspec(dllexport) __cdecl
-InjectDumpProcessWithoutCrash(HANDLE process) {
+extern "C" HANDLE __declspec(dllexport) __cdecl InjectDumpProcessWithoutCrash(
+ HANDLE process,
+ void* serialized_crash_keys) {
+ // |serialized_crash_keys| is not propagated in breakpad but is in crashpad
+ // since breakpad is deprecated.
return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread,
0, 0, NULL);
}
diff --git a/chromium/components/crash/content/app/crash_reporter_client.cc b/chromium/components/crash/content/app/crash_reporter_client.cc
index 22b95712995..3dfbd99f375 100644
--- a/chromium/components/crash/content/app/crash_reporter_client.cc
+++ b/chromium/components/crash/content/app/crash_reporter_client.cc
@@ -110,6 +110,14 @@ bool CrashReporterClient::GetCrashDumpLocation(base::FilePath* crash_dir) {
return false;
}
+#if defined(OS_WIN)
+bool CrashReporterClient::GetCrashMetricsLocation(base::string16* crash_dir) {
+#else
+bool CrashReporterClient::GetCrashMetricsLocation(base::FilePath* crash_dir) {
+#endif
+ return false;
+}
+
size_t CrashReporterClient::RegisterCrashKeys() {
return 0;
}
@@ -122,6 +130,11 @@ bool CrashReporterClient::GetCollectStatsConsent() {
return false;
}
+bool CrashReporterClient::GetCollectStatsInSample() {
+ // By default, clients don't do sampling, so everything will be "in-sample".
+ return true;
+}
+
#if defined(OS_WIN) || defined(OS_MACOSX)
bool CrashReporterClient::ReportingIsEnforcedByPolicy(bool* breakpad_enabled) {
return false;
@@ -133,6 +146,10 @@ int CrashReporterClient::GetAndroidMinidumpDescriptor() {
return 0;
}
+int CrashReporterClient::GetAndroidCrashSignalFD() {
+ return -1;
+}
+
bool CrashReporterClient::ShouldEnableBreakpadMicrodumps() {
// Always enable microdumps on Android when stripping unwind tables. Rationale:
// when unwind tables are stripped out (to save binary size) the stack traces
diff --git a/chromium/components/crash/content/app/crash_reporter_client.h b/chromium/components/crash/content/app/crash_reporter_client.h
index 157ba53e136..25ae5053358 100644
--- a/chromium/components/crash/content/app/crash_reporter_client.h
+++ b/chromium/components/crash/content/app/crash_reporter_client.h
@@ -121,13 +121,25 @@ class CrashReporterClient {
#endif
// The location where minidump files should be written. Returns true if
- // |crash_dir| was set.
+ // |crash_dir| was set. Windows has to use base::string16 because this code
+ // needs to work in chrome_elf, where only kernel32.dll is allowed, and
+ // base::FilePath and its dependencies pull in other DLLs.
#if defined(OS_WIN)
virtual bool GetCrashDumpLocation(base::string16* crash_dir);
#else
virtual bool GetCrashDumpLocation(base::FilePath* crash_dir);
#endif
+ // The location where metrics files should be written. Returns true if
+ // |metrics_dir| was set. Windows has to use base::string16 because this code
+ // needs to work in chrome_elf, where only kernel32.dll is allowed, and
+ // base::FilePath and its dependencies pull in other DLLs.
+#if defined(OS_WIN)
+ virtual bool GetCrashMetricsLocation(base::string16* metrics_dir);
+#else
+ virtual bool GetCrashMetricsLocation(base::FilePath* metrics_dir);
+#endif
+
// Register all of the potential crash keys that can be sent to the crash
// reporting server. Returns the size of the union of all keys.
virtual size_t RegisterCrashKeys();
@@ -138,6 +150,11 @@ class CrashReporterClient {
// Returns true if the user has given consent to collect stats.
virtual bool GetCollectStatsConsent();
+ // Returns true if the client is currently in the chosen sample that will
+ // report stats and crashes. Crashes should only be reported if this function
+ // returns true and GetCollectStatsConsent returns true.
+ virtual bool GetCollectStatsInSample();
+
#if defined(OS_WIN) || defined(OS_MACOSX)
// Returns true if crash reporting is enforced via management policies. In
// that case, |breakpad_enabled| is set to the value enforced by policies.
@@ -148,6 +165,10 @@ class CrashReporterClient {
// Returns the descriptor key of the android minidump global descriptor.
virtual int GetAndroidMinidumpDescriptor();
+ // Returns the file descriptor of the pipe used to inform apps of
+ // webview renderer crashes.
+ virtual int GetAndroidCrashSignalFD();
+
// Returns true if breakpad microdumps should be enabled. This orthogonal to
// the standard minidump uploader (which depends on the user consent).
virtual bool ShouldEnableBreakpadMicrodumps();
diff --git a/chromium/components/crash/content/app/crashpad.cc b/chromium/components/crash/content/app/crashpad.cc
index 72d68fb89ab..76f67348ab0 100644
--- a/chromium/components/crash/content/app/crashpad.cc
+++ b/chromium/components/crash/content/app/crashpad.cc
@@ -7,10 +7,6 @@
#include <stddef.h>
#include <string.h>
-#if BUILDFLAG(ENABLE_KASKO)
-#include <psapi.h>
-#endif // BUILDFLAG(ENABLE_KASKO)
-
#include <algorithm>
#include <map>
#include <vector>
@@ -40,11 +36,6 @@
#include <unistd.h>
#endif // OS_POSIX
-#if BUILDFLAG(ENABLE_KASKO)
-#include "base/win/scoped_handle.h"
-#include "third_party/crashpad/crashpad/snapshot/api/module_annotations_win.h"
-#endif
-
namespace crash_reporter {
namespace {
@@ -103,74 +94,6 @@ void DumpWithoutCrashing() {
CRASHPAD_SIMULATE_CRASH();
}
-#if BUILDFLAG(ENABLE_KASKO)
-// TODO(ananta)
-// We cannot depend on functionality in base which pulls in dependencies on
-// user32 directly or indirectly. The GetLoadedModulesSnapshot is a copy of the
-// function in base/win/win_util.cc. Depending on the base function pulls in
-// dependencies on user32 due to other functionality in win_util.cc. This
-// function should be removed when KASKO is removed.
-bool GetLoadedModulesSnapshot(HANDLE process, std::vector<HMODULE>* snapshot) {
- DCHECK(snapshot);
- DCHECK_EQ(0u, snapshot->size());
- snapshot->resize(128);
-
- // We will retry at least once after first determining |bytes_required|. If
- // the list of modules changes after we receive |bytes_required| we may retry
- // more than once.
- int retries_remaining = 5;
- do {
- DWORD bytes_required = 0;
- // EnumProcessModules returns 'success' even if the buffer size is too
- // small.
- DCHECK_GE(std::numeric_limits<DWORD>::max(),
- snapshot->size() * sizeof(HMODULE));
- if (!::EnumProcessModules(
- process, &(*snapshot)[0],
- static_cast<DWORD>(snapshot->size() * sizeof(HMODULE)),
- &bytes_required)) {
- DPLOG(ERROR) << "::EnumProcessModules failed.";
- return false;
- }
- DCHECK_EQ(0u, bytes_required % sizeof(HMODULE));
- size_t num_modules = bytes_required / sizeof(HMODULE);
- if (num_modules <= snapshot->size()) {
- // Buffer size was too big, presumably because a module was unloaded.
- snapshot->erase(snapshot->begin() + num_modules, snapshot->end());
- return true;
- } else if (num_modules == 0) {
- DLOG(ERROR) << "Can't determine the module list size.";
- return false;
- } else {
- // Buffer size was too small. Try again with a larger buffer. A little
- // more room is given to avoid multiple expensive calls to
- // ::EnumProcessModules() just because one module has been added.
- snapshot->resize(num_modules + 8, NULL);
- }
- } while (--retries_remaining);
-
- DLOG(ERROR) << "Failed to enumerate modules.";
- return false;
-}
-
-HMODULE GetModuleInProcess(base::ProcessHandle process,
- const wchar_t* module_name) {
- std::vector<HMODULE> modules_snapshot;
- if (!GetLoadedModulesSnapshot(process, &modules_snapshot))
- return nullptr;
-
- for (HMODULE module : modules_snapshot) {
- wchar_t current_module_name[MAX_PATH];
- if (!::GetModuleBaseName(process, module, current_module_name, MAX_PATH))
- continue;
-
- if (std::wcscmp(module_name, current_module_name) == 0)
- return module;
- }
- return nullptr;
-}
-#endif // BUILDFLAG(ENABLE_KASKO)
-
void InitializeCrashpadImpl(bool initial_client,
const std::string& process_type,
bool embedded_handler) {
@@ -228,15 +151,10 @@ void InitializeCrashpadImpl(bool initial_client,
g_simple_string_dictionary = new crashpad::SimpleStringDictionary();
crashpad_info->set_simple_annotations(g_simple_string_dictionary);
-#if !defined(OS_WIN) || !defined(COMPONENT_BUILD)
- // chrome/common/child_process_logging_win.cc registers crash keys for
- // chrome.dll. In a component build, that is sufficient as chrome.dll and
- // chrome.exe share a copy of base (in base.dll). In a static build, the EXE
- // must separately initialize the crash keys configuration as it has its own
- // statically linked copy of base.
+ // On Windows chrome_elf registers crash keys. This should work identically
+ // for component and non component builds.
base::debug::SetCrashKeyReportingFunctions(SetCrashKeyValue, ClearCrashKey);
crash_reporter_client->RegisterCrashKeys();
-#endif
SetCrashKeyValue("ptype", browser_process ? base::StringPiece("browser")
: base::StringPiece(process_type));
@@ -269,18 +187,7 @@ void InitializeCrashpadImpl(bool initial_client,
g_database =
crashpad::CrashReportDatabase::Initialize(database_path).release();
- bool enable_uploads = false;
- if (!crash_reporter_client->ReportingIsEnforcedByPolicy(&enable_uploads)) {
- // Breakpad provided a --disable-breakpad switch to disable crash dumping
- // (not just uploading) here. Crashpad doesn't need it: dumping is enabled
- // unconditionally and uploading is gated on consent, which tests/bots
- // shouldn't have. As a precaution, uploading is also disabled on bots
- // even if consent is present.
- enable_uploads = crash_reporter_client->GetCollectStatsConsent() &&
- !crash_reporter_client->IsRunningUnattended();
- }
-
- SetUploadsEnabled(enable_uploads);
+ SetUploadConsent(crash_reporter_client->GetCollectStatsConsent());
}
}
@@ -297,11 +204,24 @@ void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
}
#endif // OS_WIN
-void SetUploadsEnabled(bool enable_uploads) {
- if (g_database) {
- crashpad::Settings* settings = g_database->GetSettings();
- settings->SetUploadsEnabled(enable_uploads);
+void SetUploadConsent(bool consent) {
+ if (!g_database)
+ return;
+
+ bool enable_uploads = false;
+ CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
+ if (!crash_reporter_client->ReportingIsEnforcedByPolicy(&enable_uploads)) {
+ // Breakpad provided a --disable-breakpad switch to disable crash dumping
+ // (not just uploading) here. Crashpad doesn't need it: dumping is enabled
+ // unconditionally and uploading is gated on consent, which tests/bots
+ // shouldn't have. As a precaution, uploading is also disabled on bots even
+ // if consent is present.
+ enable_uploads = consent && !crash_reporter_client->IsRunningUnattended();
}
+
+ crashpad::Settings* settings = g_database->GetSettings();
+ settings->SetUploadsEnabled(enable_uploads &&
+ crash_reporter_client->GetCollectStatsInSample());
}
bool GetUploadsEnabled() {
@@ -358,7 +278,9 @@ void GetReports(std::vector<Report>* reports) {
report.local_id = pending_report.uuid.ToString();
report.capture_time = pending_report.creation_time;
report.upload_time = 0;
- report.state = ReportUploadState::Pending;
+ report.state = pending_report.upload_explicitly_requested
+ ? ReportUploadState::Pending_UserRequested
+ : report.state = ReportUploadState::Pending;
reports->push_back(report);
}
@@ -368,103 +290,31 @@ void GetReports(std::vector<Report>* reports) {
});
}
-#if BUILDFLAG(ENABLE_KASKO)
-
-void GetCrashKeysForKasko(std::vector<kasko::api::CrashKey>* crash_keys) {
- // Get the platform annotations.
- std::map<std::string, std::string> annotations;
- internal::GetPlatformCrashpadAnnotations(&annotations);
-
- // Reserve room for the GUID and the platform annotations.
- crash_keys->clear();
- crash_keys->reserve(
- g_simple_string_dictionary->GetCount() + 1 + annotations.size());
-
- // Set the Crashpad client ID in the crash keys.
- bool got_guid = false;
- if (g_database) {
- crashpad::Settings* settings = g_database->GetSettings();
- crashpad::UUID uuid;
- if (settings->GetClientID(&uuid)) {
- kasko::api::CrashKey kv;
- wcsncpy_s(kv.name, L"guid", _TRUNCATE);
- wcsncpy_s(kv.value, base::UTF8ToWide(uuid.ToString()).c_str(), _TRUNCATE);
- crash_keys->push_back(kv);
- got_guid = true;
- }
- }
-
- crashpad::SimpleStringDictionary::Iterator iter(*g_simple_string_dictionary);
- for (;;) {
- const auto* entry = iter.Next();
- if (!entry)
- break;
-
- // Skip the 'guid' key if it was already set.
- static const char kGuid[] = "guid";
- if (got_guid && ::strncmp(entry->key, kGuid, arraysize(kGuid)) == 0)
- continue;
-
- // Skip any platform annotations as they'll be set below.
- if (annotations.count(entry->key))
- continue;
-
- kasko::api::CrashKey kv;
- wcsncpy_s(kv.name, base::UTF8ToWide(entry->key).c_str(), _TRUNCATE);
- wcsncpy_s(kv.value, base::UTF8ToWide(entry->value).c_str(), _TRUNCATE);
- crash_keys->push_back(kv);
- }
-
- // Merge in the platform annotations.
- for (const auto& entry : annotations) {
- kasko::api::CrashKey kv;
- wcsncpy_s(kv.name, base::UTF8ToWide(entry.first).c_str(), _TRUNCATE);
- wcsncpy_s(kv.value, base::UTF8ToWide(entry.second).c_str(), _TRUNCATE);
- crash_keys->push_back(kv);
- }
-}
-
-void ReadMainModuleAnnotationsForKasko(
- const base::Process& process,
- std::vector<kasko::api::CrashKey>* crash_keys) {
- // Reopen process with necessary access.
- base::win::ScopedHandle process_handle(::OpenProcess(
- PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process.Pid()));
- if (!process_handle.IsValid())
- return;
-
- // The executable name is the same for the browser process and the crash
- // reporter.
- wchar_t exe_file[MAX_PATH] = {};
- CHECK(::GetModuleFileName(nullptr, exe_file, arraysize(exe_file)));
-
- base::FilePath exe_path(exe_file);
-
- HMODULE module = GetModuleInProcess(process_handle.Get(),
- exe_path.BaseName().value().c_str());
- if (!module)
+void RequestSingleCrashUpload(const std::string& local_id) {
+ if (!g_database)
return;
-
- std::map<std::string, std::string> annotations;
- crashpad::ReadModuleAnnotations(process_handle.Get(), module, &annotations);
-
- // Append the annotations to the crash keys.
- for (const auto& entry : annotations) {
- kasko::api::CrashKey kv;
- wcsncpy_s(kv.name, base::UTF8ToWide(entry.first).c_str(), _TRUNCATE);
- wcsncpy_s(kv.value, base::UTF8ToWide(entry.second).c_str(), _TRUNCATE);
- crash_keys->push_back(kv);
- }
+ crashpad::UUID uuid;
+ uuid.InitializeFromString(local_id);
+ g_database->RequestUpload(uuid);
}
-#endif // BUILDFLAG(ENABLE_KASKO)
-
} // namespace crash_reporter
#if defined(OS_WIN)
extern "C" {
+// This function is used in chrome_metrics_services_manager_client.cc to trigger
+// changes to the upload-enabled state. This is done when the metrics services
+// are initialized, and when the user changes their consent for uploads. See
+// crash_reporter::SetUploadConsent for effects. The given consent value should
+// be consistent with
+// crash_reporter::GetCrashReporterClient()->GetCollectStatsConsent(), but it's
+// not enforced to avoid blocking startup code on synchronizing them.
+void __declspec(dllexport) __cdecl SetUploadConsentImpl(bool consent) {
+ crash_reporter::SetUploadConsent(consent);
+}
+
// NOTE: This function is used by SyzyASAN to annotate crash reports. If you
// change the name or signature of this function you will break SyzyASAN
// instrumented releases of Chrome. Please contact syzygy-team@chromium.org
@@ -479,6 +329,12 @@ void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl(const wchar_t* key) {
crash_reporter::ClearCrashKey(base::UTF16ToUTF8(key));
}
+// This helper is invoked by code in chrome.dll to request a single crash report
+// upload. See CrashUploadListCrashpad.
+void __declspec(dllexport)
+ RequestSingleCrashUploadImpl(const std::string& local_id) {
+ crash_reporter::RequestSingleCrashUpload(local_id);
+}
} // extern "C"
#endif // OS_WIN
diff --git a/chromium/components/crash/content/app/crashpad.h b/chromium/components/crash/content/app/crashpad.h
index 47a30943aae..eeb65ac69b7 100644
--- a/chromium/components/crash/content/app/crashpad.h
+++ b/chromium/components/crash/content/app/crashpad.h
@@ -12,12 +12,6 @@
#include <vector>
#include "base/files/file_path.h"
-#include "third_party/kasko/kasko_features.h"
-
-#if BUILDFLAG(ENABLE_KASKO)
-#include "base/process/process.h"
-#include "syzygy/kasko/api/crash_key.h"
-#endif // BUILDFLAG(ENABLE_KASKO)
namespace crash_reporter {
@@ -61,12 +55,15 @@ void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
const std::string& process_type);
#endif // OS_WIN
-// Enables or disables crash report upload. This is a property of the Crashpad
-// database. In a newly-created database, uploads will be disabled. This
-// function only has an effect when called in the browser process. Its effect is
-// immediate and applies to all other process types, including processes that
-// are already running.
-void SetUploadsEnabled(bool enabled);
+// Enables or disables crash report upload, taking the given consent to upload
+// into account. Consent may be ignored, uploads may not be enabled even with
+// consent, but will only be enabled without consent when policy enforces crash
+// reporting. Whether reports upload is a property of the Crashpad database. In
+// a newly-created database, uploads will be disabled. This function only has an
+// effect when called in the browser process. Its effect is immediate and
+// applies to all other process types, including processes that are already
+// running.
+void SetUploadConsent(bool consent);
// Determines whether uploads are enabled or disabled. This information is only
// available in the browser process.
@@ -75,7 +72,8 @@ bool GetUploadsEnabled();
enum class ReportUploadState {
NotUploaded,
Pending,
- Uploaded,
+ Pending_UserRequested,
+ Uploaded
};
struct Report {
@@ -93,16 +91,8 @@ struct Report {
// reports first).
void GetReports(std::vector<Report>* reports);
-#if BUILDFLAG(ENABLE_KASKO)
-// Returns a copy of the current crash keys for Kasko.
-void GetCrashKeysForKasko(std::vector<kasko::api::CrashKey>* crash_keys);
-
-// Reads the annotations for the executable module for |process| and puts them
-// into |crash_keys|.
-void ReadMainModuleAnnotationsForKasko(
- const base::Process& process,
- std::vector<kasko::api::CrashKey>* crash_keys);
-#endif // BUILDFLAG(ENABLE_KASKO)
+// Requests a user triggered upload for a crash report with a given id.
+void RequestSingleCrashUpload(const std::string& local_id);
namespace internal {
diff --git a/chromium/components/crash/content/app/crashpad_mac.mm b/chromium/components/crash/content/app/crashpad_mac.mm
index 0f6be4cf795..3223dddc38d 100644
--- a/chromium/components/crash/content/app/crashpad_mac.mm
+++ b/chromium/components/crash/content/app/crashpad_mac.mm
@@ -4,6 +4,7 @@
#include "components/crash/content/app/crashpad.h"
+#include <CoreFoundation/CoreFoundation.h>
#include <string.h>
#include <unistd.h>
@@ -34,6 +35,7 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
bool browser_process,
bool embedded_handler) {
base::FilePath database_path; // Only valid in the browser process.
+ base::FilePath metrics_path; // Only valid in the browser process.
DCHECK(!embedded_handler); // This is not used on Mac.
if (initial_client) {
@@ -45,36 +47,38 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
// Is there a way to recover if this fails?
CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
crash_reporter_client->GetCrashDumpLocation(&database_path);
+ crash_reporter_client->GetCrashMetricsLocation(&metrics_path);
- // TODO(mark): Reading the Breakpad keys is temporary and transitional. At
- // the very least, they should be renamed to Crashpad. For the time being,
- // this isn't the worst thing: Crashpad is still uploading to a
- // Breakpad-type server, after all.
- NSBundle* framework_bundle = base::mac::FrameworkBundle();
- NSString* product = base::mac::ObjCCast<NSString>(
- [framework_bundle objectForInfoDictionaryKey:@"BreakpadProduct"]);
- NSString* version = base::mac::ObjCCast<NSString>(
- [framework_bundle objectForInfoDictionaryKey:@"BreakpadVersion"]);
- NSString* url_ns = base::mac::ObjCCast<NSString>(
- [framework_bundle objectForInfoDictionaryKey:@"BreakpadURL"]);
-#if defined(GOOGLE_CHROME_BUILD)
- NSString* channel = base::mac::ObjCCast<NSString>(
- [base::mac::OuterBundle() objectForInfoDictionaryKey:@"KSChannelID"]);
+#if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD)
+ // Only allow the possibility of report upload in official builds. This
+ // crash server won't have symbols for any other build types.
+ std::string url = "https://clients2.google.com/cr/report";
#else
- NSString* channel = nil;
+ std::string url;
#endif
- std::string url = base::SysNSStringToUTF8(url_ns);
-
std::map<std::string, std::string> process_annotations;
- process_annotations["prod"] = base::SysNSStringToUTF8(product);
- process_annotations["ver"] = base::SysNSStringToUTF8(version);
+
+ NSBundle* outer_bundle = base::mac::OuterBundle();
+ NSString* product = base::mac::ObjCCast<NSString>([outer_bundle
+ objectForInfoDictionaryKey:base::mac::CFToNSCast(kCFBundleNameKey)]);
+ process_annotations["prod"] =
+ base::SysNSStringToUTF8(product).append("_Mac");
+
+#if defined(GOOGLE_CHROME_BUILD)
+ NSString* channel = base::mac::ObjCCast<NSString>(
+ [outer_bundle objectForInfoDictionaryKey:@"KSChannelID"]);
if (channel) {
process_annotations["channel"] = base::SysNSStringToUTF8(channel);
}
- process_annotations["plat"] = std::string("OS X");
+#endif
- crashpad::CrashpadClient crashpad_client;
+ NSString* version =
+ base::mac::ObjCCast<NSString>([base::mac::FrameworkBundle()
+ objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
+ process_annotations["ver"] = base::SysNSStringToUTF8(version);
+
+ process_annotations["plat"] = std::string("OS X");
std::vector<std::string> arguments;
if (!browser_process) {
@@ -86,8 +90,10 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
"--reset-own-crash-exception-port-to-system-default");
}
+ crashpad::CrashpadClient crashpad_client;
bool result = crashpad_client.StartHandler(handler_path,
database_path,
+ metrics_path,
url,
process_annotations,
arguments,
diff --git a/chromium/components/crash/content/app/crashpad_win.cc b/chromium/components/crash/content/app/crashpad_win.cc
index ec00a0d4018..d9a408973a2 100644
--- a/chromium/components/crash/content/app/crashpad_win.cc
+++ b/chromium/components/crash/content/app/crashpad_win.cc
@@ -6,11 +6,15 @@
#include <memory>
+#include "base/debug/crash_logging.h"
#include "base/environment.h"
+#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/crash/content/app/crash_reporter_client.h"
@@ -53,6 +57,7 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
bool browser_process,
bool embedded_handler) {
base::FilePath database_path; // Only valid in the browser process.
+ base::FilePath metrics_path; // Only valid in the browser process.
bool result = false;
const char kPipeNameVar[] = "CHROME_CRASHPAD_PIPE_NAME";
@@ -65,6 +70,12 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
if (crash_reporter_client->GetCrashDumpLocation(&database_path_str))
database_path = base::FilePath(database_path_str);
+ base::string16 metrics_path_str;
+ if (crash_reporter_client->GetCrashMetricsLocation(&metrics_path_str)) {
+ metrics_path = base::FilePath(metrics_path_str);
+ CHECK(base::CreateDirectoryAndGetError(metrics_path, nullptr));
+ }
+
std::map<std::string, std::string> process_annotations;
GetPlatformCrashpadAnnotations(&process_annotations);
@@ -107,11 +118,10 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
base::FilePath exe_dir = exe_file.DirName();
exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe"));
}
- // TODO(scottmg): See https://crashpad.chromium.org/bug/23.
- arguments.push_back("--no-rate-limit");
result = g_crashpad_client.Get().StartHandler(
- exe_file, database_path, url, process_annotations, arguments, false);
+ exe_file, database_path, metrics_path, url, process_annotations,
+ arguments, false);
// If we're the browser, push the pipe name into the environment so child
// processes can connect to it. If we inherited another crashpad_handler's
@@ -155,7 +165,15 @@ MSVC_PUSH_DISABLE_WARNING(4748)
// Note that this function must be in a namespace for the [Renderer hang]
// annotations to work on the crash server.
-DWORD WINAPI DumpProcessWithoutCrashThread(void*) {
+DWORD WINAPI DumpProcessWithoutCrashThread(void* crash_keys_str) {
+ base::StringPairs crash_keys;
+ if (crash_keys_str && base::SplitStringIntoKeyValuePairs(
+ reinterpret_cast<const char*>(crash_keys_str), ':',
+ ',', &crash_keys)) {
+ for (const auto& crash_key : crash_keys) {
+ base::debug::SetCrashKeyValue(crash_key.first, crash_key.second);
+ }
+ }
DumpProcessWithoutCrash();
return 0;
}
@@ -194,11 +212,17 @@ int __declspec(dllexport) CrashForException(
}
// Injects a thread into a remote process to dump state when there is no crash.
+// |serialized_crash_keys| is a nul terminated string that represents serialized
+// crash keys sent from the browser. Keys and values are separated by ':', and
+// key/value pairs are separated by ','. All keys should be previously
+// registered as crash keys.
HANDLE __declspec(dllexport) __cdecl InjectDumpProcessWithoutCrash(
- HANDLE process) {
+ HANDLE process,
+ void* serialized_crash_keys) {
return CreateRemoteThread(
process, nullptr, 0,
- crash_reporter::internal::DumpProcessWithoutCrashThread, 0, 0, nullptr);
+ crash_reporter::internal::DumpProcessWithoutCrashThread,
+ serialized_crash_keys, 0, nullptr);
}
HANDLE __declspec(dllexport) __cdecl InjectDumpForHangDebugging(
diff --git a/chromium/components/crash/content/browser/crash_dump_manager_android.cc b/chromium/components/crash/content/browser/crash_dump_manager_android.cc
index 1a618ff205f..0d9c0aa71b3 100644
--- a/chromium/components/crash/content/browser/crash_dump_manager_android.cc
+++ b/chromium/components/crash/content/browser/crash_dump_manager_android.cc
@@ -77,7 +77,8 @@ base::File CrashDumpManager::CreateMinidumpFile(int child_process_id) {
{
base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
- DCHECK(!ContainsKey(child_process_id_to_minidump_path_, child_process_id));
+ DCHECK(!base::ContainsKey(child_process_id_to_minidump_path_,
+ child_process_id));
child_process_id_to_minidump_path_[child_process_id] = minidump_path;
}
return minidump_file;
diff --git a/chromium/components/crash/content/browser/crash_handler_host_linux.cc b/chromium/components/crash/content/browser/crash_handler_host_linux.cc
index 393c047450e..7bb7c805192 100644
--- a/chromium/components/crash/content/browser/crash_handler_host_linux.cc
+++ b/chromium/components/crash/content/browser/crash_handler_host_linux.cc
@@ -28,6 +28,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "breakpad/src/client/linux/handler/exception_handler.h"
#include "breakpad/src/client/linux/minidump_writer/linux_dumper.h"
#include "breakpad/src/client/linux/minidump_writer/minidump_writer.h"
@@ -55,6 +56,12 @@ const size_t kControlMsgSize =
// The length of the regular payload:
const size_t kCrashContextSize = sizeof(ExceptionHandler::CrashContext);
+// Crashing thread might be in "running" state, i.e. after sys_sendmsg() and
+// before sys_read(). Retry 3 times with interval of 100 ms when translating
+// TID.
+const int kNumAttemptsTranslatingTid = 3;
+const int kRetryIntervalTranslatingTidInMs = 100;
+
// Handles the crash dump and frees the allocated BreakpadInfo struct.
void CrashDumpTask(CrashHandlerHostLinux* handler,
std::unique_ptr<BreakpadInfo> info) {
@@ -94,6 +101,8 @@ CrashHandlerHostLinux::CrashHandlerHostLinux(const std::string& process_type,
#endif
shutting_down_(false),
worker_pool_token_(base::SequencedWorkerPool::GetSequenceToken()) {
+ write_dump_file_sequence_checker_.DetachFromSequence();
+
int fds[2];
// We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from
// sending datagrams to other sockets on the system. The sandbox may prevent
@@ -280,11 +289,60 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
// but we just check syscall_number through arg3.
base::StringAppendF(&expected_syscall_data, "%d 0x%x %p 0x1 ",
SYS_read, tid_fd, tid_buf_addr);
+
+ FindCrashingThreadAndDump(crashing_pid,
+ expected_syscall_data,
+ std::move(crash_context),
+ std::move(crash_keys),
+#if defined(ADDRESS_SANITIZER)
+ std::move(asan_report),
+#endif
+ uptime,
+ oom_size,
+ signal_fd.release(),
+ 0);
+}
+
+void CrashHandlerHostLinux::FindCrashingThreadAndDump(
+ pid_t crashing_pid,
+ const std::string& expected_syscall_data,
+ std::unique_ptr<char[]> crash_context,
+ std::unique_ptr<CrashKeyStorage> crash_keys,
+#if defined(ADDRESS_SANITIZER)
+ std::unique_ptr<char[]> asan_report,
+#endif
+ uint64_t uptime,
+ size_t oom_size,
+ int signal_fd,
+ int attempt) {
bool syscall_supported = false;
- pid_t crashing_tid =
- base::FindThreadIDWithSyscall(crashing_pid,
- expected_syscall_data,
- &syscall_supported);
+ pid_t crashing_tid = base::FindThreadIDWithSyscall(
+ crashing_pid, expected_syscall_data, &syscall_supported);
+ ++attempt;
+ if (crashing_tid == -1 && syscall_supported &&
+ attempt <= kNumAttemptsTranslatingTid) {
+ LOG(WARNING) << "Could not translate tid, attempt = " << attempt
+ << " retry ...";
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&CrashHandlerHostLinux::FindCrashingThreadAndDump,
+ base::Unretained(this),
+ crashing_pid,
+ expected_syscall_data,
+ base::Passed(&crash_context),
+ base::Passed(&crash_keys),
+#if defined(ADDRESS_SANITIZER)
+ base::Passed(&asan_report),
+#endif
+ uptime,
+ oom_size,
+ signal_fd,
+ attempt),
+ base::TimeDelta::FromMilliseconds(kRetryIntervalTranslatingTidInMs));
+ return;
+ }
+
+
if (crashing_tid == -1) {
// We didn't find the thread we want. Maybe it didn't reach
// sys_read() yet or the thread went away. We'll just take a
@@ -338,15 +396,14 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
base::Passed(&info),
base::Passed(&crash_context),
crashing_pid,
- signal_fd.release()));
+ signal_fd));
}
void CrashHandlerHostLinux::WriteDumpFile(std::unique_ptr<BreakpadInfo> info,
std::unique_ptr<char[]> crash_context,
pid_t crashing_pid,
int signal_fd) {
- DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
- worker_pool_token_));
+ DCHECK(write_dump_file_sequence_checker_.CalledOnValidSequence());
// Set |info->distro| here because base::GetLinuxDistro() needs to run on a
// blocking thread.
diff --git a/chromium/components/crash/content/browser/crash_handler_host_linux.h b/chromium/components/crash/content/browser/crash_handler_host_linux.h
index 4052d639d84..1c463644ccd 100644
--- a/chromium/components/crash/content/browser/crash_handler_host_linux.h
+++ b/chromium/components/crash/content/browser/crash_handler_host_linux.h
@@ -14,7 +14,9 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/sequence_checker.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "components/crash/content/app/breakpad_linux_impl.h"
namespace base {
class Thread;
@@ -71,6 +73,19 @@ class CrashHandlerHostLinux : public base::MessageLoopForIO::Watcher,
// Continue OnFileCanReadWithoutBlocking()'s work on the IO thread.
void QueueCrashDumpTask(std::unique_ptr<BreakpadInfo> info, int signal_fd);
+ // Find crashing thread (may delay and retry) and dump on IPC thread.
+ void FindCrashingThreadAndDump(pid_t crashing_pid,
+ const std::string& expected_syscall_data,
+ std::unique_ptr<char[]> crash_context,
+ std::unique_ptr<CrashKeyStorage> crash_keys,
+#if defined(ADDRESS_SANITIZER)
+ std::unique_ptr<char[]> asan_report,
+#endif
+ uint64_t uptime,
+ size_t oom_size,
+ int signal_fd,
+ int attempt);
+
std::string process_type_;
base::FilePath dumps_path_;
#if !defined(OS_ANDROID)
@@ -88,6 +103,9 @@ class CrashHandlerHostLinux : public base::MessageLoopForIO::Watcher,
// by other tasks.
base::SequencedWorkerPool::SequenceToken worker_pool_token_;
+ // Used to verify that calls to WriteDumpFile() are sequenced.
+ base::SequenceChecker write_dump_file_sequence_checker_;
+
DISALLOW_COPY_AND_ASSIGN(CrashHandlerHostLinux);
};
diff --git a/chromium/components/crash/content/tools/BUILD.gn b/chromium/components/crash/content/tools/BUILD.gn
index b781bd5f8f5..62060206e4d 100644
--- a/chromium/components/crash/content/tools/BUILD.gn
+++ b/chromium/components/crash/content/tools/BUILD.gn
@@ -4,7 +4,7 @@
assert(is_win)
-source_set("crash_service") {
+static_library("crash_service") {
sources = [
"crash_service.cc",
"crash_service.h",
diff --git a/chromium/components/crash/content/tools/generate_breakpad_symbols.py b/chromium/components/crash/content/tools/generate_breakpad_symbols.py
index b4c3b48a700..d076e8faae4 100755
--- a/chromium/components/crash/content/tools/generate_breakpad_symbols.py
+++ b/chromium/components/crash/content/tools/generate_breakpad_symbols.py
@@ -175,7 +175,7 @@ def GenerateSymbols(options, binaries):
break
binary_info = GetBinaryInfoFromHeaderInfo(
- GetCommandOutput([dump_syms, '-i', binary]))
+ GetCommandOutput([dump_syms, '-i', binary]).splitlines()[0])
if not binary_info:
should_dump_syms = False
reason = "Could not obtain binary information."
diff --git a/chromium/components/crash/core/browser/BUILD.gn b/chromium/components/crash/core/browser/BUILD.gn
index b299d4377b3..d11108e0471 100644
--- a/chromium/components/crash/core/browser/BUILD.gn
+++ b/chromium/components/crash/core/browser/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser") {
+static_library("browser") {
sources = [
"crashes_ui_util.cc",
"crashes_ui_util.h",
diff --git a/chromium/components/crash/core/browser/DEPS b/chromium/components/crash/core/browser/DEPS
index 00f4fc386aa..54699afa1f0 100644
--- a/chromium/components/crash/core/browser/DEPS
+++ b/chromium/components/crash/core/browser/DEPS
@@ -1,6 +1,5 @@
include_rules = [
"+components/upload_list",
"+grit/components_chromium_strings.h",
- "+grit/components_google_chrome_strings.h",
"+grit/components_strings.h",
]
diff --git a/chromium/components/crash/core/browser/crashes_ui_util.cc b/chromium/components/crash/core/browser/crashes_ui_util.cc
index e286fa6a8c1..c83361c0de9 100644
--- a/chromium/components/crash/core/browser/crashes_ui_util.cc
+++ b/chromium/components/crash/core/browser/crashes_ui_util.cc
@@ -13,7 +13,6 @@
#include "base/values.h"
#include "components/upload_list/upload_list.h"
#include "grit/components_chromium_strings.h"
-#include "grit/components_google_chrome_strings.h"
#include "grit/components_strings.h"
namespace crash {
@@ -25,12 +24,15 @@ const CrashesUILocalizedString kCrashesUILocalizedStrings[] = {
{"crashHeaderFormatLocalOnly", IDS_CRASH_CRASH_HEADER_FORMAT_LOCAL_ONLY},
{"crashTimeFormat", IDS_CRASH_CRASH_TIME_FORMAT},
{"crashNotUploaded", IDS_CRASH_CRASH_NOT_UPLOADED},
+ {"crashUserRequested", IDS_CRASH_CRASH_USER_REQUESTED},
{"crashPending", IDS_CRASH_CRASH_PENDING},
{"crashesTitle", IDS_CRASH_TITLE},
{"disabledHeader", IDS_CRASH_DISABLED_HEADER},
{"disabledMessage", IDS_CRASH_DISABLED_MESSAGE},
{"noCrashesMessage", IDS_CRASH_NO_CRASHES_MESSAGE},
{"uploadCrashesLinkText", IDS_CRASH_UPLOAD_MESSAGE},
+ {"uploadNowLinkText", IDS_CRASH_UPLOAD_NOW_LINK_TEXT},
+ {"crashSizeMessage", IDS_CRASH_SIZE_MESSAGE},
};
const size_t kCrashesUILocalizedStringsCount =
@@ -41,6 +43,7 @@ const char kCrashesUIRequestCrashList[] = "requestCrashList";
const char kCrashesUIRequestCrashUpload[] = "requestCrashUpload";
const char kCrashesUIShortProductName[] = "shortProductName";
const char kCrashesUIUpdateCrashList[] = "updateCrashList";
+const char kCrashesUIRequestSingleCrashUpload[] = "requestSingleCrashUpload";
std::string UploadInfoStateAsString(UploadList::UploadInfo::State state) {
switch (state) {
@@ -48,6 +51,8 @@ std::string UploadInfoStateAsString(UploadList::UploadInfo::State state) {
return "not_uploaded";
case UploadList::UploadInfo::State::Pending:
return "pending";
+ case UploadList::UploadInfo::State::Pending_UserRequested:
+ return "pending_user_requested";
case UploadList::UploadInfo::State::Uploaded:
return "uploaded";
}
@@ -72,6 +77,7 @@ void UploadListToValue(UploadList* upload_list, base::ListValue* out_value) {
}
crash->SetString("local_id", info.local_id);
crash->SetString("state", UploadInfoStateAsString(info.state));
+ crash->SetString("file_size", info.file_size);
out_value->Append(std::move(crash));
}
}
diff --git a/chromium/components/crash/core/browser/crashes_ui_util.h b/chromium/components/crash/core/browser/crashes_ui_util.h
index d24f0096fb8..65dcc5bbe08 100644
--- a/chromium/components/crash/core/browser/crashes_ui_util.h
+++ b/chromium/components/crash/core/browser/crashes_ui_util.h
@@ -33,6 +33,7 @@ extern const char kCrashesUIRequestCrashList[];
extern const char kCrashesUIRequestCrashUpload[];
extern const char kCrashesUIShortProductName[];
extern const char kCrashesUIUpdateCrashList[];
+extern const char kCrashesUIRequestSingleCrashUpload[];
// Converts and appends the most recent uploads to |out_value|.
void UploadListToValue(UploadList* upload_list, base::ListValue* out_value);
diff --git a/chromium/components/crash/core/browser/resources/crashes.html b/chromium/components/crash/core/browser/resources/crashes.html
index 1eac449b0e7..19ba4001f42 100644
--- a/chromium/components/crash/core/browser/resources/crashes.html
+++ b/chromium/components/crash/core/browser/resources/crashes.html
@@ -28,15 +28,15 @@
<a is="action-link" role="button" id="uploadCrashes"
i18n-content="uploadCrashesLinkText"></a>
</div>
- <div id="enabledMode">
- <h2 id="countBanner"></h2>
- <div id="crashList"></div>
- <p id="noCrashes" i18n-content="noCrashesMessage" hidden></p>
- </div>
<div id="disabledMode" hidden>
<h2 i18n-content="disabledHeader"></h2>
<p i18n-values=".innerHTML:disabledMessage"></p>
</div>
+ <div id="crashesInfo">
+ <h2 id="countBanner"></h2>
+ <div id="crashList"></div>
+ <p id="noCrashes" i18n-content="noCrashesMessage" hidden></p>
+ </div>
<script src="chrome://resources/js/i18n_template.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
</body>
diff --git a/chromium/components/crash/core/browser/resources/crashes.js b/chromium/components/crash/core/browser/resources/crashes.js
index efd5912becd..8894d32fdc7 100644
--- a/chromium/components/crash/core/browser/resources/crashes.js
+++ b/chromium/components/crash/core/browser/resources/crashes.js
@@ -16,24 +16,23 @@ function requestCrashes() {
* Callback from backend with the list of crashes. Builds the UI.
* @param {boolean} enabled Whether or not crash reporting is enabled.
* @param {boolean} dynamicBackend Whether the crash backend is dynamic.
+ * @param {boolean} manualUploads Whether the manual uploads are supported.
* @param {array} crashes The list of crashes.
* @param {string} version The browser version.
* @param {string} os The OS name and version.
*/
-function updateCrashList(enabled, dynamicBackend, crashes, version, os) {
+function updateCrashList(
+ enabled, dynamicBackend, manualUploads,
+ crashes, version, os) {
$('countBanner').textContent =
loadTimeData.getStringF('crashCountFormat',
crashes.length.toLocaleString());
var crashSection = $('crashList');
- $('enabledMode').hidden = !enabled;
$('disabledMode').hidden = enabled;
$('crashUploadStatus').hidden = !enabled || !dynamicBackend;
- if (!enabled)
- return;
-
// Clear any previous list.
crashSection.textContent = '';
@@ -41,27 +40,27 @@ function updateCrashList(enabled, dynamicBackend, crashes, version, os) {
for (var i = 0; i < crashes.length; i++) {
var crash = crashes[i];
- if (crash['local_id'] == '')
- crash['local_id'] = productName;
+ if (crash.local_id == '')
+ crash.local_id = productName;
var crashBlock = document.createElement('div');
- if (crash['state'] != 'uploaded')
+ if (crash.state != 'uploaded')
crashBlock.className = 'notUploaded';
var title = document.createElement('h3');
- var uploaded = crash['state'] == 'uploaded';
+ var uploaded = crash.state == 'uploaded';
if (uploaded) {
title.textContent = loadTimeData.getStringF('crashHeaderFormat',
- crash['id'],
- crash['local_id']);
+ crash.id,
+ crash.local_id);
} else {
title.textContent = loadTimeData.getStringF('crashHeaderFormatLocalOnly',
- crash['local_id']);
+ crash.local_id);
}
crashBlock.appendChild(title);
if (uploaded) {
var date = document.createElement('p');
date.textContent = loadTimeData.getStringF('crashTimeFormat',
- crash['time']);
+ crash.time);
crashBlock.appendChild(date);
var linkBlock = document.createElement('p');
var link = document.createElement('a');
@@ -102,16 +101,41 @@ function updateCrashList(enabled, dynamicBackend, crashes, version, os) {
link.textContent = loadTimeData.getString('bugLinkText');
linkBlock.appendChild(link);
crashBlock.appendChild(linkBlock);
- } else if (crash['state'] == 'pending') {
- var pending = document.createElement('p');
- pending.textContent = loadTimeData.getStringF('crashPending',
- crash['time']);
- crashBlock.appendChild(pending);
- } else if (crash['state'] == 'not_uploaded') {
- var not_uploaded = document.createElement('p');
- not_uploaded.textContent = loadTimeData.getStringF('crashNotUploaded',
- crash['time']);
- crashBlock.appendChild(not_uploaded);
+ } else {
+ if (crash.state == 'pending_user_requested')
+ var textContentKey = 'crashUserRequested';
+ else if (crash.state == 'pending')
+ var textContentKey = 'crashPending';
+ else if (crash.state == 'not_uploaded')
+ var textContentKey = 'crashNotUploaded';
+ else
+ continue;
+
+ var crashText = document.createElement('p');
+ crashText.textContent = loadTimeData.getStringF(textContentKey,
+ crash.time);
+ crashBlock.appendChild(crashText);
+
+ if (crash.file_size != '') {
+ var crashSizeText = document.createElement('p');
+ crashSizeText.textContent = loadTimeData.getStringF('crashSizeMessage',
+ crash.file_size);
+ crashBlock.appendChild(crashSizeText);
+ }
+
+ // Do not show "Send now" link for already requested crashes.
+ if (crash.state != 'pending_user_requested' && manualUploads) {
+ var uploadNowLinkBlock = document.createElement('p');
+ var link = document.createElement('a');
+ link.href = '';
+ link.textContent = loadTimeData.getString('uploadNowLinkText');
+ link.local_id = crash.local_id;
+ link.onclick = function() {
+ chrome.send('requestSingleCrashUpload', [this.local_id]);
+ };
+ uploadNowLinkBlock.appendChild(link);
+ crashBlock.appendChild(uploadNowLinkBlock);
+ }
}
crashSection.appendChild(crashBlock);
}
diff --git a/chromium/components/crash/core/common/BUILD.gn b/chromium/components/crash/core/common/BUILD.gn
index 3714a2380a5..6cfc0fd0d6f 100644
--- a/chromium/components/crash/core/common/BUILD.gn
+++ b/chromium/components/crash/core/common/BUILD.gn
@@ -2,7 +2,19 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-static_library("common") {
+group("common") {
+ public_deps = [
+ ":crash_keys",
+ ]
+
+ if (is_mac || is_ios) {
+ public_deps += [ ":zombies" ]
+ }
+}
+
+static_library("crash_keys") {
+ visibility = [ ":*" ]
+
sources = [
"crash_keys.cc",
"crash_keys.h",
@@ -11,12 +23,26 @@ static_library("common") {
deps = [
"//base",
]
+}
- if (is_mac || is_ios) {
- sources += [
+if (is_mac || is_ios) {
+ component("zombies") {
+ visibility = [ ":common" ]
+
+ sources = [
+ "crash_keys.h",
"objc_zombie.h",
"objc_zombie.mm",
]
+
+ defines = [ "CRASH_CORE_COMMON_IMPLEMENTATION" ]
+
+ deps = [
+ ":crash_keys",
+ "//base",
+ ]
+
+ libs = [ "Foundation.framework" ]
}
}
diff --git a/chromium/components/crash/core/common/crash_export.h b/chromium/components/crash/core/common/crash_export.h
new file mode 100644
index 00000000000..f7c21b41666
--- /dev/null
+++ b/chromium/components/crash/core/common/crash_export.h
@@ -0,0 +1,29 @@
+// 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 COMPONENTS_CRASH_CORE_COMMON_CRASH_EXPORT_H_
+#define COMPONENTS_CRASH_CORE_COMMON_CRASH_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(CRASH_CORE_COMMON_IMPLEMENTATION)
+#define CRASH_EXPORT __declspec(dllexport)
+#else
+#define CRASH_EXPORT __declspec(dllimport)
+#endif // defined(CRASH_CORE_COMMON_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(CRASH_CORE_COMMON_IMPLEMENTATION)
+#define CRASH_EXPORT __attribute__((visibility("default")))
+#else
+#define CRASH_EXPORT
+#endif // defined(CRASH_CORE_COMMON_IMPLEMENTATION)
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define CRASH_EXPORT
+#endif
+
+#endif // COMPONENTS_CRASH_CORE_COMMON_CRASH_EXPORT_H_
diff --git a/chromium/components/crash/core/common/objc_zombie.h b/chromium/components/crash/core/common/objc_zombie.h
index c023f1c30e1..f1aa8e3f5d7 100644
--- a/chromium/components/crash/core/common/objc_zombie.h
+++ b/chromium/components/crash/core/common/objc_zombie.h
@@ -8,6 +8,7 @@
#include <stddef.h>
#include "build/build_config.h"
+#include "components/crash/core/common/crash_export.h"
// You should think twice every single time you use anything from this
// namespace.
@@ -26,10 +27,10 @@ namespace ObjcEvilDoers {
// |zombieCount| controls how many zombies to store before freeing the
// oldest. Set to 0 to free objects immediately after making them
// zombies.
-bool ZombieEnable(bool zombieAllObjects, size_t zombieCount);
+bool CRASH_EXPORT ZombieEnable(bool zombieAllObjects, size_t zombieCount);
// Disable zombies.
-void ZombieDisable();
+void CRASH_EXPORT ZombieDisable();
} // namespace ObjcEvilDoers
diff --git a/chromium/components/crash_strings.grdp b/chromium/components/crash_strings.grdp
index d37c99e329a..c38d7752a26 100644
--- a/chromium/components/crash_strings.grdp
+++ b/chromium/components/crash_strings.grdp
@@ -22,6 +22,9 @@
<message name="IDS_CRASH_CRASH_PENDING" desc="Format for crash entry occurrence on chrome://crashes that has been captured, but not yet uploaded or ignored">
Crash report captured on <ph name="CRASH_TIME">$1<ex>Tuesday, January 25, 2011 2:58:02 PM</ex></ph> (not yet uploaded or ignored)
</message>
+ <message name="IDS_CRASH_CRASH_USER_REQUESTED" desc="Format for crash entry occurrence on chrome://crashes that has been requested to be uploaded by user">
+ Crash report captured on <ph name="CRASH_TIME">$1<ex>Tuesday, January 25, 2011 2:58:02 PM</ex></ph> (upload requested by user, not yet uploaded)
+ </message>
<message name="IDS_CRASH_BUG_LINK_LABEL" desc="Link text for filing a crash bug on chrome://crashes">
Provide additional details
</message>
@@ -34,5 +37,10 @@
<message name="IDS_CRASH_UPLOAD_MESSAGE" desc="Link text for triggering crash uploading on chrome://crashes">
Start uploading crashes
</message>
-
+ <message name="IDS_CRASH_UPLOAD_NOW_LINK_TEXT" desc="Link text for manual uploads of a crash report">
+ Send now
+ </message>
+ <message name="IDS_CRASH_SIZE_MESSAGE" desc="Format for displaying file size information for not uploaded crash reports.">
+ The size on the local storage is <ph name="CRASH_SIZE">$1<ex>10 kB</ex></ph>.
+ </message>
</grit-part>
diff --git a/chromium/components/cronet.gypi b/chromium/components/cronet.gypi
deleted file mode 100644
index dae9af715d4..00000000000
--- a/chromium/components/cronet.gypi
+++ /dev/null
@@ -1,962 +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.
-
-{
- 'conditions': [
- ['OS=="android"', {
- 'targets': [
- {
- 'target_name': 'cronet_jni_headers',
- 'type': 'none',
- 'sources': [
- 'cronet/android/java/src/org/chromium/net/CronetBidirectionalStream.java',
- 'cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java',
- 'cronet/android/java/src/org/chromium/net/CronetUploadDataStream.java',
- 'cronet/android/java/src/org/chromium/net/CronetUrlRequest.java',
- 'cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java',
- 'cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java',
- 'cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java',
- ],
- 'variables': {
- 'jni_gen_package': 'cronet',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- 'target_name': 'chromium_url_request_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'cronet/android/chromium_url_request.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'net_request_priority_java',
- 'type': 'none',
- 'variables': {
- 'source_file': '../net/base/request_priority.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'network_quality_observation_source_java',
- 'type': 'none',
- 'variables': {
- 'source_file': '../net/nqe/network_quality_observation_source.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'url_request_error_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'cronet/android/url_request_error.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- # This target is a jar file containing classes that Cronet's javadocs
- # may reference but are not included in the javadocs themselves.
- 'target_name': 'cronet_javadoc_classpath',
- 'type': 'none',
- 'variables': {
- # Work around GYP requirement that java targets specify java_in_dir
- # variable that contains at least one java file.
- 'java_in_dir': 'cronet/android/api',
- 'java_in_dir_suffix': '/src_dummy',
- 'never_lint': 1,
- },
- 'dependencies': [
- 'url_request_error_java',
- ],
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'http_cache_type_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'cronet/url_request_context_config.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'load_states_list',
- 'type': 'none',
- 'sources': [
- 'cronet/android/java/src/org/chromium/net/LoadState.template',
- ],
- 'variables': {
- 'package_name': 'org/chromium/cronet',
- 'template_deps': ['../net/base/load_states_list.h'],
- },
- 'includes': [ '../build/android/java_cpp_template.gypi' ],
- },
- {
- 'target_name': 'cronet_version',
- 'type': 'none',
- 'variables': {
- 'lastchange_path': '<(DEPTH)/build/util/LASTCHANGE',
- 'version_py_path': '<(DEPTH)/build/util/version.py',
- 'version_path': '<(DEPTH)/chrome/VERSION',
- 'template_input_path': 'cronet/android/java/src/org/chromium/net/Version.template',
- 'output_path': '<(SHARED_INTERMEDIATE_DIR)/templates/<(_target_name)/org/chromium/cronet/Version.java',
- },
- 'direct_dependent_settings': {
- 'variables': {
- # Ensure that the output directory is used in the class path
- # when building targets that depend on this one.
- 'generated_src_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/templates/<(_target_name)',
- ],
- # Ensure dependents are rebuilt when the generated Java file changes.
- 'additional_input_paths': [
- '<(output_path)',
- ],
- },
- },
- 'actions': [
- {
- 'action_name': 'cronet_version',
- 'inputs': [
- '<(template_input_path)',
- '<(version_path)',
- '<(lastchange_path)',
- ],
- 'outputs': [
- '<(output_path)',
- ],
- 'action': [
- 'python',
- '<(version_py_path)',
- '-f', '<(version_path)',
- '-f', '<(lastchange_path)',
- '<(template_input_path)',
- '<(output_path)',
- ],
- 'message': 'Generating version information',
- },
- ],
- },
- {
- 'target_name': 'cronet_version_header',
- 'type': 'none',
- # Need to set hard_depency flag because cronet_version generates a
- # header.
- 'hard_dependency': 1,
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/',
- ],
- },
- 'actions': [
- {
- 'action_name': 'version_header',
- 'message': 'Generating version header file: <@(_outputs)',
- 'inputs': [
- '<(version_path)',
- 'cronet/version.h.in',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/components/cronet/version.h',
- ],
- 'action': [
- 'python',
- '<(version_py_path)',
- '-e', 'VERSION_FULL="<(version_full)"',
- 'cronet/version.h.in',
- '<@(_outputs)',
- ],
- 'includes': [
- '../build/util/version.gypi',
- ],
- },
- ],
- },
- {
- # Protobuf compiler / generator for certificate verifcation protocol
- # buffer.
- # GN version: //cronet:cronet_android_cert_proto
- 'target_name': 'cronet_android_cert_proto',
- 'type': 'static_library',
- 'sources': [
- 'cronet/android/cert/proto/cert_verification.proto',
- ],
- 'variables': {
- 'enable_wexit_time_destructors': 1,
- 'proto_in_dir': 'cronet/android/cert/proto',
- 'proto_out_dir': 'cronet/android/cert/proto',
- },
- 'includes': [
- '../build/protoc.gypi',
- ],
- },
- {
- 'target_name': 'cronet_static',
- 'type': 'static_library',
- 'dependencies': [
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'conditions': [
- ['enable_data_reduction_proxy_support==1',
- {
- 'dependencies': [
- '../components/components.gyp:data_reduction_proxy_core_browser_small',
- ],
- },
- ],
- ['use_platform_icu_alternatives!=1',
- {
- 'dependencies': [
- '../base/base.gyp:base_i18n',
- ],
- },
- ],
- ],
- 'includes': [ 'cronet/cronet_static.gypi' ],
- },
- {
- 'target_name': 'libcronet',
- 'type': 'shared_library',
- 'sources': [
- 'cronet/android/cronet_jni.cc',
- ],
- 'dependencies': [
- 'cronet_static',
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- ],
- 'ldflags': [
- '-Wl,--version-script=<!(cd <(DEPTH) && pwd -P)/components/cronet/android/only_jni_exports.lst',
- ],
- 'variables': {
- # libcronet doesn't really use native JNI exports, but it does use
- # its own linker version script. The ARM64 linker appears to not
- # work with multiple version scripts with anonymous version tags,
- # so enable use_native_jni_exports which avoids adding another
- # version sript (android_no_jni_exports.lst) so we don't run afoul
- # of this ARM64 linker limitation.
- 'use_native_jni_exports': 1,
- },
- },
- { # cronet_api.jar defines Cronet API and provides implementation of
- # legacy api using HttpUrlConnection (not the Chromium stack).
- 'target_name': 'cronet_api',
- 'type': 'none',
- 'dependencies': [
- 'http_cache_type_java',
- 'url_request_error_java',
- 'cronet_version',
- 'load_states_list',
- 'network_quality_observation_source_java',
- '../third_party/android_tools/android_tools.gyp:android_support_annotations_javalib',
- ],
- 'variables': {
- 'java_in_dir': 'cronet/android/api',
- 'run_findbugs': 1,
- },
- 'includes': [ '../build/java.gypi' ],
- },
- { # cronet.jar implements HttpUrlRequest interface using Chromium stack
- # in native libcronet.so library.
- 'target_name': 'cronet_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base',
- 'cronet_api',
- 'chromium_url_request_java',
- 'libcronet',
- 'net_request_priority_java',
- 'network_quality_observation_source_java',
- '../third_party/android_tools/android_tools.gyp:android_support_annotations_javalib',
- ],
- 'variables': {
- 'java_in_dir': 'cronet/android/java',
- 'javac_includes': [
- '**/ChromiumUrlRequest.java',
- '**/ChromiumUrlRequestContext.java',
- '**/ChromiumUrlRequestError.java',
- '**/ChromiumUrlRequestFactory.java',
- '**/ChromiumUrlRequestPriority.java',
- '**/CronetBidirectionalStream.java',
- '**/CronetLibraryLoader.java',
- '**/CronetUploadDataStream.java',
- '**/CronetUrlRequest.java',
- '**/CronetUrlRequestContext.java',
- '**/RequestPriority.java',
- '**/urlconnection/CronetBufferedOutputStream.java',
- '**/urlconnection/CronetChunkedOutputStream.java',
- '**/urlconnection/CronetFixedModeOutputStream.java',
- '**/urlconnection/CronetInputStream.java',
- '**/urlconnection/CronetHttpURLConnection.java',
- '**/urlconnection/CronetHttpURLStreamHandler.java',
- '**/urlconnection/CronetOutputStream.java',
- '**/urlconnection/CronetURLStreamHandlerFactory.java',
- '**/urlconnection/MessageLoop.java',
- ],
- 'run_findbugs': 1,
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'cronet_sample_apk',
- 'type': 'none',
- 'dependencies': [
- 'cronet_java',
- 'cronet_api',
- ],
- 'variables': {
- 'apk_name': 'CronetSample',
- 'java_in_dir': 'cronet/android/sample',
- 'resource_dir': 'cronet/android/sample/res',
- 'native_lib_target': 'libcronet',
- 'proguard_enabled': 'true',
- 'proguard_flags_paths': [
- 'cronet/android/proguard.cfg',
- 'cronet/android/sample/javatests/proguard.cfg',
- ],
- 'run_findbugs': 1,
- },
- 'includes': [ '../build/java_apk.gypi' ],
- },
- {
- # cronet_sample_apk creates a .jar as a side effect. Any java targets
- # that need that .jar in their classpath should depend on this target,
- # cronet_sample_apk_java. Dependents of cronet_sample_apk receive its
- # jar path in the variable 'apk_output_jar_path'. This target should
- # only be used by targets which instrument cronet_sample_apk.
- 'target_name': 'cronet_sample_apk_java',
- 'type': 'none',
- 'dependencies': [
- 'cronet_sample_apk',
- ],
- 'includes': [ '../build/apk_fake_jar.gypi' ],
- },
- {
- 'target_name': 'cronet_sample_test_apk',
- 'type': 'none',
- 'dependencies': [
- 'cronet_java',
- 'cronet_sample_apk_java',
- 'cronet_api',
- '../base/base.gyp:base_java_test_support',
- '../net/net.gyp:net_java_test_support',
- '../net/net.gyp:require_net_test_support_apk',
- ],
- 'variables': {
- 'apk_name': 'CronetSampleTest',
- 'java_in_dir': 'cronet/android/sample/javatests',
- 'is_test_apk': 1,
- 'run_findbugs': 1,
- 'test_type': 'instrumentation',
- 'additional_apks': [
- '<(PRODUCT_DIR)/apks/ChromiumNetTestSupport.apk',
- ],
- },
- 'includes': [
- '../build/java_apk.gypi',
- '../build/android/test_runner.gypi',
- ],
- },
- {
- 'target_name': 'cronet_tests_jni_headers',
- 'type': 'none',
- 'sources': [
- 'cronet/android/test/src/org/chromium/net/CronetTestUtil.java',
- 'cronet/android/test/src/org/chromium/net/MockUrlRequestJobFactory.java',
- 'cronet/android/test/src/org/chromium/net/MockCertVerifier.java',
- 'cronet/android/test/src/org/chromium/net/NativeTestServer.java',
- 'cronet/android/test/src/org/chromium/net/NetworkChangeNotifierUtil.java',
- 'cronet/android/test/src/org/chromium/net/QuicTestServer.java',
- 'cronet/android/test/src/org/chromium/net/SdchObserver.java',
- 'cronet/android/test/src/org/chromium/net/TestUploadDataStreamHandler.java',
- 'cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java',
- ],
- 'variables': {
- 'jni_gen_package': 'cronet_tests',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- 'target_name': 'libcronet_tests',
- 'type': 'shared_library',
- 'sources': [
- 'cronet/android/test/cronet_test_jni.cc',
- 'cronet/android/test/mock_cert_verifier.cc',
- 'cronet/android/test/mock_cert_verifier.h',
- 'cronet/android/test/mock_url_request_job_factory.cc',
- 'cronet/android/test/mock_url_request_job_factory.h',
- 'cronet/android/test/native_test_server.cc',
- 'cronet/android/test/native_test_server.h',
- 'cronet/android/test/quic_test_server.cc',
- 'cronet/android/test/quic_test_server.h',
- 'cronet/android/test/sdch_test_util.cc',
- 'cronet/android/test/sdch_test_util.h',
- 'cronet/android/test/test_upload_data_stream_handler.cc',
- 'cronet/android/test/test_upload_data_stream_handler.h',
- 'cronet/android/test/network_change_notifier_util.cc',
- 'cronet/android/test/network_change_notifier_util.h',
- 'cronet/android/test/cronet_url_request_context_config_test.cc',
- 'cronet/android/test/cronet_url_request_context_config_test.h',
- 'cronet/android/test/cronet_test_util.cc',
- 'cronet/android/test/cronet_test_util.h',
- ],
- 'dependencies': [
- 'cronet_tests_jni_headers',
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../net/net.gyp:net_quic_proto',
- '../net/net.gyp:net_test_support',
- '../net/net.gyp:simple_quic_tools',
- '../base/base.gyp:base_i18n',
- '../third_party/icu/icu.gyp:icui18n',
- '../third_party/icu/icu.gyp:icuuc',
- ],
- 'ldflags': [
- '-Wl,--version-script=<!(cd <(DEPTH) && pwd -P)/components/cronet/android/only_jni_exports.lst',
- ],
- 'variables': {
- # libcronet doesn't really use native JNI exports, but it does use
- # its own linker version script. The ARM64 linker appears to not
- # work with multiple version scripts with anonymous version tags,
- # so enable use_native_jni_exports which avoids adding another
- # version sript (android_no_jni_exports.lst) so we don't run afoul
- # of this ARM64 linker limitation.
- 'use_native_jni_exports': 1,
- },
- 'conditions': [
- ['enable_data_reduction_proxy_support==1',
- {
- 'dependencies': [
- '../components/components.gyp:data_reduction_proxy_core_browser_small',
- ],
- },
- ],
- ],
- 'includes': [ 'cronet/cronet_static.gypi' ],
- },
- {
- 'target_name': 'cronet_test_support',
- 'type': 'none',
- 'dependencies': [
- 'cronet_java',
- '../net/net.gyp:net_java_test_support',
- '../third_party/netty-tcnative/netty-tcnative.gyp:netty-tcnative',
- '../third_party/netty4/netty.gyp:netty_all',
- ],
- 'variables': {
- 'java_in_dir': 'cronet/android/test',
- 'additional_src_dirs': [ 'cronet/android/test/javatests/src' ],
- 'run_findbugs': 1,
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'cronet_test_apk',
- 'type': 'none',
- 'dependencies': [
- 'cronet_java',
- 'cronet_test_support',
- '../net/net.gyp:net_java_test_support',
- '../third_party/netty-tcnative/netty-tcnative.gyp:netty-tcnative',
- '../third_party/netty4/netty.gyp:netty_all',
- ],
- 'variables': {
- 'apk_name': 'CronetTest',
- # There isn't an easy way to have a java_apk target without any Java
- # so we'll borrow the trick from the net_test_support_apk target of
- # pointing it at placeholder Java via java_in_dir_suffix.
- 'java_in_dir': 'cronet/android/test',
- 'java_in_dir_suffix': '/src_dummy',
- 'resource_dir': 'cronet/android/test/res',
- 'asset_location': 'cronet/android/test/assets',
- 'native_lib_target': 'libcronet_tests',
- 'never_lint': 1,
- 'additional_bundled_libs': [
- '>(netty_tcnative_so_file_location)',
- ],
- },
- 'includes': [ '../build/java_apk.gypi' ],
- },
- {
- # cronet_test_apk creates a .jar as a side effect. Any java targets
- # that need that .jar in their classpath should depend on this target,
- # cronet_test_apk_java. Dependents of cronet_test_apk receive its
- # jar path in the variable 'apk_output_jar_path'. This target should
- # only be used by targets which instrument cronet_test_apk.
- 'target_name': 'cronet_test_apk_java',
- 'type': 'none',
- 'dependencies': [
- 'cronet_test_apk',
- ],
- 'includes': [ '../build/apk_fake_jar.gypi' ],
- },
- {
- 'target_name': 'cronet_test_instrumentation_apk',
- 'type': 'none',
- 'dependencies': [
- 'cronet_test_apk_java',
- '../base/base.gyp:base_java_test_support',
- '../net/net.gyp:net_java_test_support',
- '../net/net.gyp:require_net_test_support_apk',
- ],
- 'variables': {
- 'apk_name': 'CronetTestInstrumentation',
- 'java_in_dir': 'cronet/android/test/javatests',
- 'resource_dir': 'cronet/android/test/res',
- 'is_test_apk': 1,
- 'run_findbugs': 1,
- 'test_type': 'instrumentation',
- 'isolate_file': 'cronet/android/cronet_test_instrumentation_apk.isolate',
- 'additional_apks': [
- '<(PRODUCT_DIR)/apks/ChromiumNetTestSupport.apk',
- ],
- },
- 'includes': [
- '../build/java_apk.gypi',
- '../build/android/test_runner.gypi',
- ],
- },
- {
- 'target_name': 'cronet_perf_test_apk',
- 'type': 'none',
- 'dependencies': [
- 'cronet_java',
- 'cronet_api',
- 'cronet_test_support',
- ],
- 'variables': {
- 'apk_name': 'CronetPerfTest',
- 'java_in_dir': 'cronet/android/test/javaperftests',
- 'native_lib_target': 'libcronet_tests',
- 'proguard_enabled': 'true',
- 'proguard_flags_paths': [
- 'cronet/android/proguard.cfg',
- 'cronet/android/test/javaperftests/proguard.cfg',
- ],
- 'run_findbugs': 1,
- },
- 'includes': [ '../build/java_apk.gypi' ],
- },
- {
- 'target_name': 'cronet_unittests',
- 'type': '<(gtest_target_type)',
- 'dependencies': [
- 'cronet_android_cert_proto',
- 'cronet_static',
- 'metrics',
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../net/net.gyp:net_test_support',
- '../testing/gtest.gyp:gtest',
- '../testing/android/native_test.gyp:native_test_native_code',
- ],
- 'sources': [
- 'cronet/android/cert/cert_verifier_cache_serializer_unittest.cc',
- 'cronet/run_all_unittests.cc',
- 'cronet/url_request_context_config_unittest.cc',
- 'cronet/histogram_manager_unittest.cc',
- ],
- },
- {
- 'target_name': 'cronet_unittests_apk',
- 'type': 'none',
- 'dependencies': [
- 'cronet_unittests',
- ],
- 'variables': {
- 'test_suite_name': 'cronet_unittests',
- 'shard_timeout': 180,
- },
- 'includes': [
- '../build/apk_test.gypi',
- ],
- },
- {
- 'target_name': 'cronet_package',
- 'type': 'none',
- 'dependencies': [
- 'libcronet',
- 'cronet_java',
- 'cronet_api',
- 'cronet_javadoc_classpath',
- '../net/net.gyp:net_unittests_apk',
- ],
- 'variables': {
- 'native_lib': 'libcronet.>(android_product_extension)',
- 'java_lib': 'cronet.jar',
- 'java_api_lib': 'cronet_api.jar',
- 'java_api_src_lib': 'cronet_api-src.jar',
- 'java_src_lib': 'cronet-src.jar',
- 'java_sample_src_lib': 'cronet-sample-src.jar',
- 'lib_java_dir': '<(PRODUCT_DIR)/lib.java',
- 'package_dir': '<(PRODUCT_DIR)/cronet',
- 'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/cronet',
- 'jar_extract_dir': '<(intermediate_dir)/cronet_jar_extract',
- 'jar_extract_stamp': '<(intermediate_dir)/jar_extract.stamp',
- 'cronet_jar_stamp': '<(intermediate_dir)/cronet_jar.stamp',
- },
- 'actions': [
- {
- 'action_name': 'strip libcronet',
- 'inputs': ['<(SHARED_LIB_DIR)/<(native_lib)'],
- 'outputs': ['<(package_dir)/libs/<(android_app_abi)/<(native_lib)'],
- 'action': [
- '<(android_strip)',
- '--strip-unneeded',
- '<@(_inputs)',
- '-o',
- '<@(_outputs)',
- ],
- },
- {
- 'action_name': 'extracting from jars',
- 'inputs': [
- '<(lib_java_dir)/cronet_java.jar',
- '<(lib_java_dir)/base_java.jar',
- '<(lib_java_dir)/net_java.jar',
- '<(lib_java_dir)/url_java.jar',
- ],
- 'outputs': ['<(jar_extract_stamp)', '<(jar_extract_dir)'],
- 'action': [
- 'python',
- 'cronet/tools/extract_from_jars.py',
- '--classes-dir=<(jar_extract_dir)',
- '--jars=<@(_inputs)',
- '--stamp=<(jar_extract_stamp)',
- ],
- },
- {
- 'action_name': 'jar_<(_target_name)',
- 'message': 'Creating <(_target_name) jar',
- 'inputs': [
- '<(DEPTH)/build/android/gyp/util/build_utils.py',
- '<(DEPTH)/build/android/gyp/util/md5_check.py',
- '<(DEPTH)/build/android/gyp/jar.py',
- '<(jar_extract_stamp)',
- ],
- 'outputs': [
- '<(package_dir)/<(java_lib)',
- '<(cronet_jar_stamp)',
- ],
- 'action': [
- 'python', '<(DEPTH)/build/android/gyp/jar.py',
- '--classes-dir=<(jar_extract_dir)',
- '--jar-path=<(package_dir)/<(java_lib)',
- '--stamp=<(cronet_jar_stamp)',
- ]
- },
- {
- 'action_name': 'jar_api_src_<(_target_name)',
- 'inputs': ['cronet/tools/jar_src.py'] ,
- 'outputs': ['<(package_dir)/<(java_api_src_lib)'],
- 'action': [
- 'python',
- '<@(_inputs)',
- '--src-dir=cronet/android/api/src',
- '--jar-path=<(package_dir)/<(java_api_src_lib)',
- ],
- },
- {
- 'action_name': 'jar_src_<(_target_name)',
- 'inputs': ['cronet/tools/jar_src.py'] ,
- 'outputs': ['<(package_dir)/<(java_src_lib)'],
- 'action': [
- 'python',
- '<@(_inputs)',
- '--src-dir=../base/android/java/src',
- '--src-dir=../net/android/java/src',
- '--src-dir=../url/android/java/src',
- '--src-dir=cronet/android/java/src',
- '--jar-path=<(package_dir)/<(java_src_lib)',
- ],
- },
- {
- 'action_name': 'jar_sample_src_<(_target_name)',
- 'inputs': ['cronet/tools/jar_src.py'] ,
- 'outputs': ['<(package_dir)/<(java_sample_src_lib)'],
- 'action': [
- 'python',
- '<@(_inputs)',
- '--src-dir=cronet/android/sample',
- '--jar-path=<(package_dir)/<(java_sample_src_lib)',
- ],
- },
- {
- 'action_name': 'generate licenses',
- 'inputs': ['cronet/tools/cronet_licenses.py'] ,
- 'outputs': ['<(package_dir)/LICENSE'],
- 'action': [
- 'python',
- '<@(_inputs)',
- 'license',
- '<@(_outputs)',
- ],
- },
- {
- 'action_name': 'generate javadoc',
- 'inputs': ['cronet/tools/generate_javadoc.py'] ,
- 'outputs': ['<(package_dir)/javadoc'],
- 'action': [
- 'python',
- '<@(_inputs)',
- '--output-dir=<(package_dir)',
- '--input-dir=cronet/',
- '--overview-file=<(package_dir)/README.md.html',
- '--readme-file=cronet/README.md',
- '--lib-java-dir=<(lib_java_dir)',
- ],
- 'message': 'Generating Javadoc',
- },
- ],
- 'copies': [
- {
- 'destination': '<(package_dir)',
- 'files': [
- '../AUTHORS',
- '../chrome/VERSION',
- 'cronet/android/proguard.cfg',
- '<(lib_java_dir)/<(java_api_lib)'
- ],
- },
- {
- 'destination': '<(package_dir)/symbols/<(android_app_abi)',
- 'files': [
- '<(SHARED_LIB_DIR)/<(native_lib)',
- ],
- },
- ],
- },
- ],
- 'variables': {
- 'enable_data_reduction_proxy_support%': 0,
- },
- }], # OS=="android"
- ['OS=="ios"', {
- 'targets': [
- { # TODO(mef): Dedup this with copy in OS=="android" section.
- 'target_name': 'cronet_version_header',
- 'type': 'none',
- # Need to set hard_depency flag because cronet_version generates a
- # header.
- 'hard_dependency': 1,
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/',
- ],
- },
- 'actions': [
- {
- 'action_name': 'version_header',
- 'message': 'Generating version header file: <@(_outputs)',
- 'inputs': [
- '<(version_path)',
- 'cronet/version.h.in',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/components/cronet/ios/version.h',
- ],
- 'action': [
- 'python',
- '<(version_py_path)',
- '-e', 'VERSION_FULL="<(version_full)"',
- 'cronet/version.h.in',
- '<@(_outputs)',
- ],
- 'includes': [
- '../build/util/version.gypi',
- ],
- },
- ],
- },
- {
- 'target_name': 'cronet_static',
- 'type': 'static_library',
- 'sources': [
- 'cronet/ios/Cronet.h',
- 'cronet/ios/Cronet.mm',
- 'cronet/ios/cronet_bidirectional_stream.h',
- 'cronet/ios/cronet_bidirectional_stream.cc',
- 'cronet/ios/cronet_c_for_grpc.h',
- 'cronet/ios/cronet_c_for_grpc.cc',
- 'cronet/ios/cronet_environment.cc',
- 'cronet/ios/cronet_environment.h',
- 'cronet/url_request_context_config.cc',
- 'cronet/url_request_context_config.h',
- ],
- 'dependencies': [
- 'cronet_version_header',
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- ],
- 'cflags': [
- '-fdata-sections',
- '-ffunction-sections',
- '-fno-rtti',
- '-fvisibility=hidden'
- '-fvisibility-inlines-hidden',
- '-Wno-sign-promo',
- '-Wno-missing-field-initializers',
- ],
- 'ldflags': [
- '-llog',
- '-Wl,--gc-sections',
- '-Wl,--exclude-libs,ALL'
- ],
- },
- {
- 'target_name': 'libcronet_shared',
- 'type': 'shared_library',
- 'sources': [
- 'cronet/ios/Cronet.h',
- 'cronet/ios/Cronet.mm',
- ],
- 'dependencies': [
- 'cronet_static',
- '../base/base.gyp:base',
- ],
- },
- {
- 'target_name': 'cronet_framework',
- 'product_name': 'Cronet',
- 'type': 'shared_library',
- 'mac_bundle': 1,
- 'sources': [
- 'cronet/ios/Cronet.h',
- 'cronet/ios/cronet_c_for_grpc.h',
- 'cronet/ios/empty.cc',
- ],
- 'mac_framework_headers': [
- 'cronet/ios/Cronet.h',
- 'cronet/ios/cronet_c_for_grpc.h',
- ],
- 'link_settings': {
- 'libraries': [
- 'Foundation.framework',
- ],
- },
- 'xcode_settings': {
- 'DEBUGGING_SYMBOLS': 'YES',
- 'INFOPLIST_FILE': 'cronet/ios/Info.plist',
- 'LD_DYLIB_INSTALL_NAME': '@loader_path/Frameworks/Cronet.framework/Cronet',
- },
- 'dependencies': [
- 'cronet_static',
- '../base/base.gyp:base',
- ],
- 'configurations': {
- 'Debug_Base': {
- 'xcode_settings': {
- 'DEPLOYMENT_POSTPROCESSING': 'NO',
- 'DEBUG_INFORMATION_FORMAT': 'dwarf',
- 'STRIP_INSTALLED_PRODUCT': 'NO',
- }
- },
- 'Release_Base': {
- 'xcode_settings': {
- 'DEPLOYMENT_POSTPROCESSING': 'YES',
- 'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
- 'STRIP_INSTALLED_PRODUCT': 'YES',
- 'STRIP_STYLE': 'non-global',
- }
- },
- },
- },
- {
- 'target_name': 'cronet_test',
- 'type': 'executable',
- 'dependencies': [
- 'cronet_static',
- '../net/net.gyp:net_quic_proto',
- '../net/net.gyp:net_test_support',
- '../net/net.gyp:simple_quic_tools',
- '../testing/gtest.gyp:gtest',
- ],
- 'sources': [
- 'cronet/ios/test/cronet_bidirectional_stream_test.mm',
- 'cronet/ios/test/cronet_test_runner.mm',
- 'cronet/ios/test/quic_test_server.cc',
- 'cronet/ios/test/quic_test_server.h',
- ],
- 'mac_bundle_resources': [
- '../net/data/ssl/certificates/quic_test.example.com.crt',
- '../net/data/ssl/certificates/quic_test.example.com.key',
- '../net/data/ssl/certificates/quic_test.example.com.key.pkcs8',
- '../net/data/ssl/certificates/quic_test.example.com.key.sct',
- ],
- 'include_dirs': [
- '..',
- ],
- },
- {
- # Build this target to package a standalone Cronet in a single
- # .a file.
- 'target_name': 'cronet_package',
- 'type': 'none',
- 'variables' : {
- 'package_dir': '<(PRODUCT_DIR)/cronet',
- },
- 'dependencies': [
- # Depend on the dummy target so that all of CrNet's dependencies
- # are built before packaging.
- 'libcronet_shared',
- ],
- 'actions': [
- {
- 'action_name': 'Package Cronet',
- 'variables': {
- 'tool_path':
- 'cronet/tools/link_dependencies.py',
- },
- # Actions need an inputs list, even if it's empty.
- 'inputs': [
- '<(tool_path)',
- '<(PRODUCT_DIR)/libcronet_shared.dylib',
- ],
- # Only specify one output, since this will be libtool's output.
- 'outputs': [ '<(package_dir)/libcronet_standalone_with_symbols.a' ],
- 'action': ['<(tool_path)',
- '<(PRODUCT_DIR)',
- 'libcronet_shared.dylib',
- '<@(_outputs)',
- ],
- },
- {
- 'action_name': 'Stripping standalone library',
- # Actions need an inputs list, even if it's empty.
- 'inputs': [
- '<(package_dir)/libcronet_standalone_with_symbols.a',
- ],
- # Only specify one output, since this will be libtool's output.
- 'outputs': [ '<(package_dir)/libcronet_standalone.a' ],
- 'action': ['strip',
- '-S',
- '<@(_inputs)',
- '-o',
- '<@(_outputs)',
- ],
- },
- ],
- 'copies': [
- {
- 'destination': '<(package_dir)',
- 'files': [
- '../chrome/VERSION',
- 'cronet/ios/Cronet.h',
- 'cronet/ios/cronet_c_for_grpc.h',
- ],
- },
- {
- 'destination': '<(package_dir)/test',
- 'files': [
- 'cronet/ios/test/cronet_bidirectional_stream_test.mm',
- 'cronet/ios/test/cronet_test_runner.mm',
- ],
- },
- ],
- },
- ],
- }], # OS=="ios"
- ],
-}
diff --git a/chromium/components/cronet/android/BUILD.gn b/chromium/components/cronet/android/BUILD.gn
index ec59f29b533..6b1dc41f7ff 100644
--- a/chromium/components/cronet/android/BUILD.gn
+++ b/chromium/components/cronet/android/BUILD.gn
@@ -5,8 +5,8 @@
import("//build/buildflag_header.gni")
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
+import("//build/util/process_version.gni")
import("//build/util/version.gni")
-import("//chrome/version.gni")
import("//testing/test.gni")
import("//third_party/protobuf/proto_library.gni")
import("//url/features.gni")
@@ -19,17 +19,21 @@ declare_args() {
generate_jni("cronet_jni_headers") {
sources = [
- "java/src/org/chromium/net/ChromiumUrlRequest.java",
- "java/src/org/chromium/net/ChromiumUrlRequestContext.java",
- "java/src/org/chromium/net/CronetBidirectionalStream.java",
- "java/src/org/chromium/net/CronetLibraryLoader.java",
- "java/src/org/chromium/net/CronetUploadDataStream.java",
- "java/src/org/chromium/net/CronetUrlRequest.java",
- "java/src/org/chromium/net/CronetUrlRequestContext.java",
+ "java/src/org/chromium/net/impl/CronetBidirectionalStream.java",
+ "java/src/org/chromium/net/impl/CronetLibraryLoader.java",
+ "java/src/org/chromium/net/impl/CronetUploadDataStream.java",
+ "java/src/org/chromium/net/impl/CronetUrlRequest.java",
+ "java/src/org/chromium/net/impl/CronetUrlRequestContext.java",
]
jni_package = "cronet"
}
+java_cpp_enum("effective_connection_type_java") {
+ sources = [
+ "//net/nqe/effective_connection_type.h",
+ ]
+}
+
java_cpp_enum("chromium_url_request_java") {
sources = [
"chromium_url_request.h",
@@ -57,7 +61,13 @@ java_cpp_enum("url_request_error_java") {
# This target is a jar file containing classes that Cronet's javadocs
# may reference but are not included in the javadocs themselves.
android_library("cronet_javadoc_classpath") {
- srcjar_deps = [ ":url_request_error_java" ]
+ deps = [
+ "//third_party/android_tools:android_support_annotations_java",
+ ]
+ srcjar_deps = [
+ ":effective_connection_type_java",
+ ":url_request_error_java",
+ ]
}
java_cpp_enum("http_cache_type_java") {
@@ -76,23 +86,53 @@ java_cpp_template("load_states_list") {
package_name = "org/chromium/net"
}
-_generated_version_java_dir = "$target_gen_dir/templates/cronet_version_java"
-_generated_version_java =
- "$_generated_version_java_dir/org/chromium/net/Version.java"
+_generated_api_version_java_dir =
+ "$target_gen_dir/templates/cronet_api_version_java"
+_generated_api_version_java =
+ "$_generated_api_version_java_dir/org/chromium/net/ApiVersion.java"
-process_version("cronet_version_java") {
- template_file = "java/src/org/chromium/net/Version.template"
- output = _generated_version_java
+process_version("cronet_api_version_java") {
+ template_file = "api/src/org/chromium/net/ApiVersion.template"
+ sources = [
+ "//build/util/LASTCHANGE",
+ "//chrome/VERSION",
+ ]
+ output = _generated_api_version_java
}
-zip("cronet_version_srcjar") {
+zip("cronet_api_version_srcjar") {
inputs = [
- _generated_version_java,
+ _generated_api_version_java,
]
output = "$target_gen_dir/$target_name.srcjar"
- base_dir = _generated_version_java_dir
+ base_dir = _generated_api_version_java_dir
deps = [
- ":cronet_version_java",
+ ":cronet_api_version_java",
+ ]
+}
+
+_generated_impl_version_java_dir =
+ "$target_gen_dir/templates/cronet_impl_version_java"
+_generated_impl_version_java =
+ "$_generated_impl_version_java_dir/org/chromium/net/impl/ImplVersion.java"
+
+process_version("cronet_impl_version_java") {
+ template_file = "java/src/org/chromium/net/impl/ImplVersion.template"
+ sources = [
+ "//build/util/LASTCHANGE",
+ "//chrome/VERSION",
+ ]
+ output = _generated_impl_version_java
+}
+
+zip("cronet_impl_version_srcjar") {
+ inputs = [
+ _generated_impl_version_java,
+ ]
+ output = "$target_gen_dir/$target_name.srcjar"
+ base_dir = _generated_impl_version_java_dir
+ deps = [
+ ":cronet_impl_version_java",
]
}
@@ -141,10 +181,7 @@ template("cronet_static_tmpl") {
sources = [
"//components/cronet/android/cert/cert_verifier_cache_serializer.cc",
"//components/cronet/android/cert/cert_verifier_cache_serializer.h",
- "//components/cronet/android/chromium_url_request.cc",
"//components/cronet/android/chromium_url_request.h",
- "//components/cronet/android/chromium_url_request_context.cc",
- "//components/cronet/android/chromium_url_request_context.h",
"//components/cronet/android/cronet_bidirectional_stream_adapter.cc",
"//components/cronet/android/cronet_bidirectional_stream_adapter.h",
"//components/cronet/android/cronet_in_memory_pref_store.cc",
@@ -161,16 +198,14 @@ template("cronet_static_tmpl") {
"//components/cronet/android/cronet_url_request_context_adapter.h",
"//components/cronet/android/io_buffer_with_byte_buffer.cc",
"//components/cronet/android/io_buffer_with_byte_buffer.h",
- "//components/cronet/android/url_request_adapter.cc",
- "//components/cronet/android/url_request_adapter.h",
- "//components/cronet/android/url_request_context_adapter.cc",
- "//components/cronet/android/url_request_context_adapter.h",
+ "//components/cronet/android/metrics_util.cc",
+ "//components/cronet/android/metrics_util.h",
"//components/cronet/android/url_request_error.cc",
"//components/cronet/android/url_request_error.h",
- "//components/cronet/android/wrapped_channel_upload_element_reader.cc",
- "//components/cronet/android/wrapped_channel_upload_element_reader.h",
"//components/cronet/histogram_manager.cc",
"//components/cronet/histogram_manager.h",
+ "//components/cronet/stale_host_resolver.cc",
+ "//components/cronet/stale_host_resolver.h",
"//components/cronet/url_request_context_config.cc",
"//components/cronet/url_request_context_config.h",
]
@@ -246,15 +281,9 @@ shared_library("cronet") {
android_library("cronet_api") {
java_files = [
"api/src/org/chromium/net/BidirectionalStream.java",
- "api/src/org/chromium/net/ChunkedWritableByteChannel.java",
"api/src/org/chromium/net/CronetEngine.java",
"api/src/org/chromium/net/CronetException.java",
- "api/src/org/chromium/net/HttpUrlConnectionUrlRequest.java",
- "api/src/org/chromium/net/HttpUrlConnectionUrlRequestFactory.java",
- "api/src/org/chromium/net/HttpUrlRequest.java",
- "api/src/org/chromium/net/HttpUrlRequestFactory.java",
- "api/src/org/chromium/net/HttpUrlRequestFactoryConfig.java",
- "api/src/org/chromium/net/HttpUrlRequestListener.java",
+ "api/src/org/chromium/net/InlineExecutionProhibitedException.java",
"api/src/org/chromium/net/InputStreamChannel.java",
"api/src/org/chromium/net/JavaCronetEngine.java",
"api/src/org/chromium/net/JavaUrlRequest.java",
@@ -262,23 +291,23 @@ android_library("cronet_api") {
"api/src/org/chromium/net/NetworkQualityThroughputListener.java",
"api/src/org/chromium/net/Preconditions.java",
"api/src/org/chromium/net/QuicException.java",
- "api/src/org/chromium/net/ResponseTooLargeException.java",
+ "api/src/org/chromium/net/RequestFinishedInfo.java",
"api/src/org/chromium/net/UploadDataProvider.java",
"api/src/org/chromium/net/UploadDataProviders.java",
"api/src/org/chromium/net/UploadDataSink.java",
"api/src/org/chromium/net/UrlRequest.java",
- "api/src/org/chromium/net/UrlRequestContextConfig.java",
"api/src/org/chromium/net/UrlRequestException.java",
"api/src/org/chromium/net/UrlResponseInfo.java",
"api/src/org/chromium/net/UserAgent.java",
]
deps = [
- "//third_party/android_tools:android_support_annotations_javalib",
+ "//third_party/android_tools:android_support_annotations_java",
]
srcjar_deps = [
- ":cronet_version_srcjar",
+ ":cronet_api_version_srcjar",
+ ":effective_connection_type_java",
":http_cache_type_java",
":url_request_error_java",
":load_states_list",
@@ -290,14 +319,12 @@ android_library("cronet_api") {
android_library("cronet_java") {
java_files = [
- "java/src/org/chromium/net/ChromiumUrlRequest.java",
- "java/src/org/chromium/net/ChromiumUrlRequestContext.java",
- "java/src/org/chromium/net/ChromiumUrlRequestFactory.java",
- "java/src/org/chromium/net/CronetBidirectionalStream.java",
- "java/src/org/chromium/net/CronetLibraryLoader.java",
- "java/src/org/chromium/net/CronetUploadDataStream.java",
- "java/src/org/chromium/net/CronetUrlRequest.java",
- "java/src/org/chromium/net/CronetUrlRequestContext.java",
+ "java/src/org/chromium/net/impl/CronetBidirectionalStream.java",
+ "java/src/org/chromium/net/impl/CronetLibraryLoader.java",
+ "java/src/org/chromium/net/impl/CronetMetrics.java",
+ "java/src/org/chromium/net/impl/CronetUploadDataStream.java",
+ "java/src/org/chromium/net/impl/CronetUrlRequest.java",
+ "java/src/org/chromium/net/impl/CronetUrlRequestContext.java",
"java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java",
"java/src/org/chromium/net/urlconnection/CronetChunkedOutputStream.java",
"java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java",
@@ -313,11 +340,12 @@ android_library("cronet_java") {
":cronet_api",
"//base:base_java",
"//net/android:net_java",
- "//third_party/android_tools:android_support_annotations_javalib",
+ "//third_party/android_tools:android_support_annotations_java",
"//third_party/jsr-305:jsr_305_javalib",
]
srcjar_deps = [
+ ":cronet_impl_version_srcjar",
":chromium_url_request_java",
":net_request_priority_java",
]
@@ -364,6 +392,8 @@ android_apk("cronet_sample_apk") {
proguard_configs = [
"proguard.cfg",
"sample/javatests/proguard.cfg",
+ "//base/android/proguard/chromium_apk.flags",
+ "//base/android/proguard/chromium_code.flags",
]
}
}
@@ -374,7 +404,7 @@ android_apk("cronet_sample_apk") {
# "tested apk" are removed from the "instrumentation test apk".
android_resources("cronet_sample_test_apk_resources") {
resource_dirs = [ "sample/res" ]
- android_manifest = "sample/AndroidManifest.xml"
+ android_manifest = "sample/javatests/AndroidManifest.xml"
}
instrumentation_test_apk("cronet_sample_test_apk") {
@@ -571,31 +601,26 @@ android_library("cronet_javatests") {
java_files = [
"test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java",
"test/javatests/src/org/chromium/net/BidirectionalStreamTest.java",
- "test/javatests/src/org/chromium/net/ChromiumUrlRequestTest.java",
- "test/javatests/src/org/chromium/net/ChunkedWritableByteChannelTest.java",
- "test/javatests/src/org/chromium/net/ContextInitTest.java",
"test/javatests/src/org/chromium/net/Criteria.java",
"test/javatests/src/org/chromium/net/CronetTestBase.java",
"test/javatests/src/org/chromium/net/CronetUploadTest.java",
"test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java",
"test/javatests/src/org/chromium/net/CronetUrlRequestTest.java",
- "test/javatests/src/org/chromium/net/CronetUrlTest.java",
"test/javatests/src/org/chromium/net/DiskStorageTest.java",
"test/javatests/src/org/chromium/net/GetStatusTest.java",
- "test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java",
+ "test/javatests/src/org/chromium/net/MetricsTestUtil.java",
"test/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java",
"test/javatests/src/org/chromium/net/PkpTest.java",
"test/javatests/src/org/chromium/net/QuicTest.java",
+ "test/javatests/src/org/chromium/net/RequestFinishedInfoTest.java",
"test/javatests/src/org/chromium/net/SdchTest.java",
"test/javatests/src/org/chromium/net/TestBidirectionalStreamCallback.java",
"test/javatests/src/org/chromium/net/TestDrivenDataProvider.java",
- "test/javatests/src/org/chromium/net/TestHttpUrlRequestListener.java",
"test/javatests/src/org/chromium/net/TestNetworkQualityRttListener.java",
"test/javatests/src/org/chromium/net/TestNetworkQualityThroughputListener.java",
"test/javatests/src/org/chromium/net/TestUploadDataProvider.java",
"test/javatests/src/org/chromium/net/TestUrlRequestCallback.java",
"test/javatests/src/org/chromium/net/UploadDataProvidersTest.java",
- "test/javatests/src/org/chromium/net/UploadTest.java",
"test/javatests/src/org/chromium/net/urlconnection/CronetBufferedOutputStreamTest.java",
"test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java",
"test/javatests/src/org/chromium/net/urlconnection/CronetFixedModeOutputStreamTest.java",
@@ -638,16 +663,10 @@ instrumentation_test_apk("cronet_test_instrumentation_apk") {
]
additional_apks = [ "//net/android:net_test_support_apk" ]
- data = [
- "//net/data/ssl/certificates/quic_test.example.com.crt",
- "//net/data/ssl/certificates/quic_test.example.com.key",
- "//net/data/ssl/certificates/quic_test.example.com.key.pkcs8",
- "//net/data/ssl/certificates/quic_test.example.com.key.sct",
+ data_deps = [
+ "//net:test_support",
]
- # TODO(jbudorick): Remove this once GN uses the generated .isolate files.
- isolate_file = "cronet_test_instrumentation_apk.isolate"
-
run_findbugs_override = true
}
@@ -684,6 +703,8 @@ android_apk("cronet_perf_test_apk") {
proguard_configs = [
"proguard.cfg",
"test/javaperftests/proguard.cfg",
+ "//base/android/proguard/chromium_apk.flags",
+ "//base/android/proguard/chromium_code.flags",
]
}
@@ -692,6 +713,7 @@ test("cronet_unittests") {
"//components/cronet/android/cert/cert_verifier_cache_serializer_unittest.cc",
"//components/cronet/histogram_manager_unittest.cc",
"//components/cronet/run_all_unittests.cc",
+ "//components/cronet/stale_host_resolver_unittest.cc",
"//components/cronet/url_request_context_config_unittest.cc",
]
@@ -725,8 +747,10 @@ action("extract_cronet_jars") {
"$root_out_dir/lib.java/net/android/net_java.jar",
"$root_out_dir/lib.java/url/url_java.jar",
]
+
+ _stamp_file = "$target_gen_dir/$target_name.stamp"
outputs = [
- depfile,
+ _stamp_file,
]
_rebased_sources = rebase_path(sources, root_build_dir)
@@ -737,6 +761,8 @@ action("extract_cronet_jars") {
"--jars=${_rebased_sources}",
"--depfile",
rebase_path(depfile, root_build_dir),
+ "--stamp",
+ rebase_path(_stamp_file, root_build_dir),
]
deps = [
@@ -769,41 +795,112 @@ action("repackage_extracted_jars") {
template("jar_src") {
action(target_name) {
- _rebased_src_dirs = rebase_path(invoker.src_dirs, root_build_dir)
+ _rebased_src_search_dirs =
+ rebase_path(invoker.src_search_dirs, root_build_dir)
script = "//components/cronet/tools/jar_src.py"
depfile = "$target_gen_dir/$target_name.d"
outputs = [
- depfile,
invoker.jar_path,
]
args = [
- "--src-dir=${_rebased_src_dirs}",
+ "--src-search-dirs=${_rebased_src_search_dirs}",
"--jar-path",
rebase_path(invoker.jar_path, root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
]
+
+ deps = []
+ if (defined(invoker.deps)) {
+ deps += invoker.deps
+ }
+
+ _src_jars = []
+
+ # Add src-jar files that are listed in "src_jars".
+ if (defined(invoker.src_jars)) {
+ _rebased_src_jars = rebase_path(invoker.src_jars, root_build_dir)
+ _src_jars += _rebased_src_jars
+ }
+
+ # Add src-jar files that are generated by dependencies in "srcjar_deps".
+ if (defined(invoker.srcjar_deps)) {
+ foreach(_srcjar_dep, invoker.srcjar_deps) {
+ _dep_gen_dir = get_label_info(_srcjar_dep, "target_gen_dir")
+ _dep_name = get_label_info(_srcjar_dep, "name")
+ _src_jars += rebase_path([ "$_dep_gen_dir/$_dep_name.srcjar" ])
+ deps += [ _srcjar_dep ]
+ }
+ }
+
+ # Create the list of all source files that are given in "src_files".
+ _src_files = []
+ if (defined(invoker.src_files)) {
+ _src_files += invoker.src_files
+ }
+
+ # Handle "source_deps".
+ _src_list_files = []
+ if (defined(invoker.source_deps)) {
+ foreach(_source_dep, invoker.source_deps) {
+ _dep_gen_dir = get_label_info(_source_dep, "target_gen_dir")
+ _dep_name = get_label_info(_source_dep, "name")
+ _src_list_files += rebase_path([ "$_dep_gen_dir/$_dep_name.sources" ])
+ deps += [ _source_dep ]
+ }
+ }
+ args += [ "--src-jar=${_src_jars}" ]
+ args += [ "--src-files=${_src_files}" ]
+ args += [ "--src-list-files=${_src_list_files}" ]
+
+ inputs = _src_jars
+ inputs += _src_files
+ inputs += _src_list_files
}
}
jar_src("jar_cronet_api_source") {
- src_dirs = [ "api/src" ]
+ src_search_dirs = [ "api/src" ]
+
+ # Include generated Java files which should be a part of the API.
+ srcjar_deps = [ ":effective_connection_type_java" ]
+ source_deps = [ ":cronet_api" ]
jar_path = "$_package_dir/cronet_api-src.jar"
}
-jar_src("jar_cronet_sample_source") {
- src_dirs = [ "sample" ]
- jar_path = "$_package_dir/cronet-sample-src.jar"
+zip("jar_cronet_sample_source") {
+ inputs = [
+ "sample/AndroidManifest.xml",
+ "sample/javatests/AndroidManifest.xml",
+ "sample/javatests/proguard.cfg",
+ "sample/javatests/src/org/chromium/cronet_sample_apk/Criteria.java",
+ "sample/javatests/src/org/chromium/cronet_sample_apk/CronetSampleTest.java",
+ "sample/README",
+ "sample/res/layout/activity_main.xml",
+ "sample/res/layout/dialog_url.xml",
+ "sample/res/values/dimens.xml",
+ "sample/res/values/strings.xml",
+ "sample/src/org/chromium/cronet_sample_apk/CronetSampleActivity.java",
+ "sample/src/org/chromium/cronet_sample_apk/CronetSampleApplication.java",
+ ]
+ output = "$_package_dir/cronet-sample-src.jar"
+ base_dir = "sample"
}
jar_src("jar_cronet_other_source") {
- src_dirs = [
+ src_search_dirs = [
"//base/android/java/src",
"//components/cronet/android/java/src",
"//net/android/java/src",
"//url/android/java/src",
]
+ source_deps = [
+ ":cronet_java",
+ "//base:base_java",
+ "//net/android:net_java",
+ "//url:url_java",
+ ]
jar_path = "$_package_dir/cronet-src.jar"
}
@@ -823,8 +920,9 @@ action("generate_licenses") {
action("generate_javadoc") {
script = "//components/cronet/tools/generate_javadoc.py"
depfile = "$target_gen_dir/$target_name.d"
+ _stamp_file = "$target_gen_dir/$target_name.stamp"
outputs = [
- depfile,
+ _stamp_file,
]
args = [
"--output-dir",
@@ -837,12 +935,19 @@ action("generate_javadoc") {
rebase_path("//components/cronet/README.md", root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
+ "--stamp",
+ rebase_path(_stamp_file, root_build_dir),
"--lib-java-dir",
rebase_path("$root_build_dir/lib.java/components/cronet/android",
root_build_dir),
+
+ # JavaDoc is generated from Cronet's API source jar.
+ "--input-src-jar",
+ rebase_path("$_package_dir/cronet_api-src.jar", root_build_dir),
]
deps = [
":cronet_javadoc_classpath",
+ ":jar_cronet_api_source",
]
}
@@ -851,7 +956,6 @@ copy("cronet_package_copy") {
"$root_out_dir/lib.java/components/cronet/android/cronet_api.jar",
"//AUTHORS",
"//chrome/VERSION",
- "//components/cronet/android/proguard.cfg",
]
outputs = [
"$_package_dir/{{source_file_part}}",
@@ -862,6 +966,20 @@ copy("cronet_package_copy") {
]
}
+action("cronet_combine_proguard_flags") {
+ script = "//components/cronet/tools/generate_proguard_file.py"
+ outputs = [
+ "$_package_dir/proguard.cfg",
+ ]
+
+ args = [
+ "--output-file",
+ rebase_path("$_package_dir/proguard.cfg", root_build_dir),
+ rebase_path("//base/android/proguard/chromium_code.flags", root_build_dir),
+ rebase_path("//components/cronet/android/proguard.cfg", root_build_dir),
+ ]
+}
+
copy("cronet_package_copy_native_lib") {
sources = [
"$root_out_dir/libcronet.so",
@@ -886,16 +1004,48 @@ copy("cronet_package_copy_native_lib_unstripped") {
]
}
+# Enforce that ARM Neon is not used when building for ARMv7
+if (target_cpu == "arm" && arm_version == 7 && !arm_use_neon) {
+ action("enforce_no_neon") {
+ script = "//components/cronet/tools/check_no_neon.py"
+ outputs = [
+ "$target_gen_dir/$target_name.stamp",
+ ]
+ args = [
+ rebase_path("${android_tool_prefix}objdump", root_build_dir),
+
+ # libcronet.so may contain ARM Neon instructions from BoringSSL, but these
+ # are only used after checking whether the CPU supports NEON at runtime,
+ # so instead check base/ as it represents a large swath of code that only
+ # contains Neon instructions when Neon is enabled by default.
+ rebase_path("$root_out_dir/obj/base/base/*.o", root_build_dir),
+ "--stamp",
+ rebase_path(outputs[0], root_build_dir),
+ ]
+ deps = [
+ "//base:base",
+ ]
+ }
+}
+
group("cronet_package") {
- deps = [
- ":cronet_package_copy",
- ":cronet_package_copy_native_lib",
- ":cronet_package_copy_native_lib_unstripped",
- ":generate_javadoc",
- ":generate_licenses",
- ":jar_cronet_api_source",
- ":jar_cronet_other_source",
- ":jar_cronet_sample_source",
- ":repackage_extracted_jars",
- ]
+ # Enforce that arm_use_neon==false when building for ARMv7 by
+ # not including any deps in cronet_package target otherwise.
+ if (!(target_cpu == "arm" && arm_version == 7) || !arm_use_neon) {
+ deps = [
+ ":cronet_combine_proguard_flags",
+ ":cronet_package_copy",
+ ":cronet_package_copy_native_lib",
+ ":cronet_package_copy_native_lib_unstripped",
+ ":generate_javadoc",
+ ":generate_licenses",
+ ":jar_cronet_api_source",
+ ":jar_cronet_other_source",
+ ":jar_cronet_sample_source",
+ ":repackage_extracted_jars",
+ ]
+ if (current_cpu == "arm" && arm_version == 7) {
+ deps += [ ":enforce_no_neon" ]
+ }
+ }
}
diff --git a/chromium/components/cronet/android/cronet_test_instrumentation_apk.isolate b/chromium/components/cronet/android/cronet_test_instrumentation_apk.isolate
deleted file mode 100644
index 984c8fb6d80..00000000000
--- a/chromium/components/cronet/android/cronet_test_instrumentation_apk.isolate
+++ /dev/null
@@ -1,14 +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.
-
-{
- 'variables': {
- 'files': [
- '<(DEPTH)/net/data/ssl/certificates/quic_test.example.com.crt',
- '<(DEPTH)/net/data/ssl/certificates/quic_test.example.com.key',
- '<(DEPTH)/net/data/ssl/certificates/quic_test.example.com.key.pkcs8',
- '<(DEPTH)/net/data/ssl/certificates/quic_test.example.com.key.sct',
- ],
- },
-}
diff --git a/chromium/components/cronet/cronet_static.gypi b/chromium/components/cronet/cronet_static.gypi
deleted file mode 100644
index 36dc15f49a0..00000000000
--- a/chromium/components/cronet/cronet_static.gypi
+++ /dev/null
@@ -1,87 +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.
-
-{
- # Included in 'cronet_static'.
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../url/url.gyp:url_url_features',
- 'chromium_url_request_java',
- 'cronet_android_cert_proto',
- 'cronet_jni_headers',
- 'cronet_version',
- 'cronet_version_header',
- 'metrics',
- 'url_request_error_java',
- ],
- 'sources': [
- 'android/cert/cert_verifier_cache_serializer.cc',
- 'android/cert/cert_verifier_cache_serializer.h',
- 'android/chromium_url_request.cc',
- 'android/chromium_url_request.h',
- 'android/chromium_url_request_context.cc',
- 'android/chromium_url_request_context.h',
- 'android/cronet_bidirectional_stream_adapter.cc',
- 'android/cronet_bidirectional_stream_adapter.h',
- 'android/cronet_in_memory_pref_store.cc',
- 'android/cronet_in_memory_pref_store.h',
- 'android/cronet_library_loader.cc',
- 'android/cronet_library_loader.h',
- 'android/cronet_upload_data_stream.cc',
- 'android/cronet_upload_data_stream.h',
- 'android/cronet_upload_data_stream_adapter.cc',
- 'android/cronet_upload_data_stream_adapter.h',
- 'android/cronet_url_request_adapter.cc',
- 'android/cronet_url_request_adapter.h',
- 'android/cronet_url_request_context_adapter.cc',
- 'android/cronet_url_request_context_adapter.h',
- 'android/io_buffer_with_byte_buffer.cc',
- 'android/io_buffer_with_byte_buffer.h',
- 'android/url_request_adapter.cc',
- 'android/url_request_adapter.h',
- 'android/url_request_context_adapter.cc',
- 'android/url_request_context_adapter.h',
- 'android/url_request_error.cc',
- 'android/url_request_error.h',
- 'android/wrapped_channel_upload_element_reader.cc',
- 'android/wrapped_channel_upload_element_reader.h',
- 'histogram_manager.cc',
- 'histogram_manager.h',
- 'url_request_context_config.cc',
- 'url_request_context_config.h',
- ],
- 'cflags': [
- '-DLOGGING=1',
- '-fdata-sections',
- '-ffunction-sections',
- '-fno-rtti',
- '-fvisibility=hidden',
- '-fvisibility-inlines-hidden',
- '-Wno-sign-promo',
- '-Wno-missing-field-initializers',
- ],
- 'ldflags': [
- '-llog',
- '-landroid',
- '-Wl,--gc-sections',
- '-Wl,--exclude-libs,ALL'
- ],
- 'conditions': [
- # If Data Reduction Proxy support is enabled, add the following
- # defines and sources. Dependencies are target-specific and are
- # not included here.
- ['enable_data_reduction_proxy_support==1',
- {
- 'defines' : [
- 'DATA_REDUCTION_PROXY_SUPPORT'
- ],
- 'sources': [
- 'android/cronet_data_reduction_proxy.cc',
- 'android/cronet_data_reduction_proxy.h',
- ],
- }
- ],
- ],
-}
diff --git a/chromium/components/cronet/ios/BUILD.gn b/chromium/components/cronet/ios/BUILD.gn
index 19ff7514cf2..027b66da0ae 100644
--- a/chromium/components/cronet/ios/BUILD.gn
+++ b/chromium/components/cronet/ios/BUILD.gn
@@ -4,8 +4,10 @@
import("//build/buildflag_header.gni")
import("//build/config/ios/rules.gni")
+import("//build/config/mac/symbols.gni")
+import("//build/mac/tweak_info_plist.gni")
+import("//build/util/process_version.gni")
import("//build/util/version.gni")
-import("//chrome/version.gni")
import("//testing/test.gni")
import("//url/features.gni")
@@ -17,6 +19,9 @@ declare_args() {
process_version("cronet_version_header") {
template_file = "//components/cronet/version.h.in"
+ sources = [
+ "//chrome/VERSION",
+ ]
output = "$target_gen_dir/version.h"
extra_args = [
"-e",
@@ -38,6 +43,8 @@ source_set("cronet_sources") {
sources = [
"../histogram_manager.cc",
"../histogram_manager.h",
+ "../stale_host_resolver.cc",
+ "../stale_host_resolver.h",
"../url_request_context_config.cc",
"../url_request_context_config.h",
"cronet_bidirectional_stream.cc",
@@ -53,8 +60,15 @@ source_set("cronet_sources") {
}
}
+# Tweak |info_plist| with current version and revision.
+tweak_info_plist("tweak_cronet_plist") {
+ info_plist = "Info.plist"
+ args = [ "--platform=ios" ]
+}
+
ios_framework_bundle("cronet_framework") {
output_name = "Cronet"
+ info_plist_target = ":tweak_cronet_plist"
deps = [
":cronet_sources",
@@ -62,8 +76,6 @@ ios_framework_bundle("cronet_framework") {
"//net:net",
]
- info_plist = "Info.plist"
-
libs = [ "UIKit.Framework" ]
public_headers = [
@@ -75,6 +87,9 @@ ios_framework_bundle("cronet_framework") {
"Cronet.h",
"Cronet.mm",
]
+
+ configs -= [ "//build/config/compiler:default_symbols" ]
+ configs += [ "//build/config/compiler:symbols" ]
}
bundle_data("cronet_test_bundle_data") {
@@ -116,6 +131,7 @@ test("cronet_unittests") {
sources = [
"//components/cronet/histogram_manager_unittest.cc",
"//components/cronet/run_all_unittests.cc",
+ "//components/cronet/stale_host_resolver_unittest.cc",
"//components/cronet/url_request_context_config_unittest.cc",
]
@@ -129,42 +145,48 @@ test("cronet_unittests") {
]
}
-_package_dir = "$root_out_dir/cronet"
-
-action("generate_license") {
- _license_path = "$_package_dir/LICENSE"
-
- script = "//components/cronet/tools/cronet_licenses.py"
- outputs = [
- _license_path,
- ]
- args = [
- "license",
- rebase_path(_license_path, root_build_dir),
- "--gn",
- ]
-}
-
-copy("cronet_package_copy") {
- sources = [
- "$root_out_dir/Cronet.framework",
- "//AUTHORS",
- "//chrome/VERSION",
- "//components/cronet/ios/Cronet.h",
- "//components/cronet/ios/cronet_c_for_grpc.h",
- ]
- outputs = [
- "$_package_dir/{{source_file_part}}",
- ]
+if (additional_toolchains == [] || current_toolchain == default_toolchain) {
+ _package_dir = "$root_out_dir/cronet"
+
+ action("generate_license") {
+ _license_path = "$_package_dir/LICENSE"
+
+ script = "//components/cronet/tools/cronet_licenses.py"
+ inputs = [
+ "//build/util/LASTCHANGE",
+ "//buildtools/$host_os/gn",
+ ]
+ outputs = [
+ _license_path,
+ ]
+ args = [
+ "license",
+ rebase_path(_license_path, root_build_dir),
+ "--gn",
+ "--gn-path",
+ rebase_path("//buildtools/$host_os/gn", root_build_dir),
+ ]
+ }
- deps = [
- ":cronet_framework",
- ]
-}
+ copy("cronet_package_copy") {
+ sources = [
+ "$root_out_dir/Cronet.framework",
+ "//AUTHORS",
+ "//chrome/VERSION",
+ ]
+ outputs = [
+ "$_package_dir/{{source_file_part}}",
+ ]
+
+ deps = [
+ ":cronet_framework",
+ ]
+ }
-group("cronet_package") {
- deps = [
- ":cronet_package_copy",
- ":generate_license",
- ]
+ group("cronet_package") {
+ deps = [
+ ":cronet_package_copy",
+ ":generate_license",
+ ]
+ }
}
diff --git a/chromium/components/crx_file.gypi b/chromium/components/crx_file.gypi
deleted file mode 100644
index 3c81095be12..00000000000
--- a/chromium/components/crx_file.gypi
+++ /dev/null
@@ -1,25 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'crx_file',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'crx_file/crx_file.cc',
- 'crx_file/crx_file.h',
- 'crx_file/id_util.cc',
- 'crx_file/id_util.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/crx_file/BUILD.gn b/chromium/components/crx_file/BUILD.gn
index a7494392daf..8c5cceb5db2 100644
--- a/chromium/components/crx_file/BUILD.gn
+++ b/chromium/components/crx_file/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("crx_file") {
+static_library("crx_file") {
sources = [
"crx_file.cc",
"crx_file.h",
diff --git a/chromium/components/data_reduction_proxy.gypi b/chromium/components/data_reduction_proxy.gypi
deleted file mode 100644
index b67f0d77726..00000000000
--- a/chromium/components/data_reduction_proxy.gypi
+++ /dev/null
@@ -1,303 +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.
-
-
-{
- 'variables' :
- {
- 'data_reduction_proxy_core_browser_sources' : [
- # Note: sources list duplicated in GN build.
- 'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_config.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_config.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_configurator.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_data.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_data.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_debug_ui_service.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_interceptor.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_service.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_service.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_service_observer.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_settings.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection.h',
- 'data_reduction_proxy/core/browser/data_store.cc',
- 'data_reduction_proxy/core/browser/data_store.h',
- 'data_reduction_proxy/core/browser/data_use_group.h',
- 'data_reduction_proxy/core/browser/data_use_group_provider.h',
- 'data_reduction_proxy/core/browser/data_usage_store.cc',
- 'data_reduction_proxy/core/browser/data_usage_store.h',
- 'data_reduction_proxy/core/browser/db_data_owner.cc',
- 'data_reduction_proxy/core/browser/db_data_owner.h',
- ],
- 'data_reduction_proxy_core_browser_deps' : [
- 'data_reduction_proxy_version_header',
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- 'pref_registry',
- ],
- 'data_reduction_proxy_core_common_sources' : [
- # Note: sources list duplicated in GN build.
- 'data_reduction_proxy/core/common/data_reduction_proxy_bypass_action_list.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_bypass_type_list.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_config_values.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_event_creator.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_event_storage_delegate.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_event_store.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_headers.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_headers.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_params.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_params.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_switches.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_switches.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_util.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_util.h',
- 'data_reduction_proxy/core/common/lofi_decider.h',
- 'data_reduction_proxy/core/common/lofi_ui_service.h',
- ],
- },
- 'conditions': [
- # Small versions of libraries for Cronet.
- ['OS=="android"', {
- 'targets' : [
- {
- # GN version: //components/data_reduction_proxy/core/browser:browser_small
- 'target_name': 'data_reduction_proxy_core_browser_small',
- 'type': 'static_library',
- 'dependencies': [
- '<@(data_reduction_proxy_core_browser_deps)',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- 'data_reduction_proxy_core_common',
- 'data_reduction_proxy_proto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- '<@(data_reduction_proxy_core_browser_sources)'
- ],
- },
- ],
- }],
- ['OS!="ios"', {
- 'targets' : [
- {
- # GN version: //components/data_reduction_proxy/content/common
- 'target_name': 'data_reduction_proxy_content_common',
- 'type': 'static_library',
- 'dependencies': [
- '../content/content.gyp:content_common',
- '../ipc/ipc.gyp:ipc',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'data_reduction_proxy/content/common/data_reduction_proxy_messages.cc',
- 'data_reduction_proxy/content/common/data_reduction_proxy_messages.h',
- ],
- },
- {
- # GN version: //components/data_reduction_proxy/content/browser
- 'target_name': 'data_reduction_proxy_content_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../content/content.gyp:content_common',
- '../ipc/ipc.gyp:ipc',
- '../skia/skia.gyp:skia',
- 'data_reduction_proxy_content_common',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'data_reduction_proxy/content/browser/content_lofi_ui_service.cc',
- 'data_reduction_proxy/content/browser/content_lofi_ui_service.h',
- 'data_reduction_proxy/content/browser/content_lofi_decider.cc',
- 'data_reduction_proxy/content/browser/content_lofi_decider.h',
- 'data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc',
- 'data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h',
- ],
- },
- ],
- }],
- ],
- 'targets': [
- {
- # GN version: //components/data_reduction_proxy/core/browser
- 'target_name': 'data_reduction_proxy_core_browser',
- 'type': 'static_library',
- 'conditions': [
- ['OS != "ios"', {
- 'defines': [
- 'USE_GOOGLE_API_KEYS_FOR_AUTH_KEY'
- ]
- }],
- ],
- 'defines': [
- 'USE_GOOGLE_API_KEYS'
- ],
- 'dependencies': [
- '<@(data_reduction_proxy_core_browser_deps)',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- 'data_reduction_proxy_core_common',
- 'data_reduction_proxy_proto',
- '../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
- ],
- 'export_dependent_settings': [
- 'data_reduction_proxy_proto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- '<@(data_reduction_proxy_core_browser_sources)',
- 'data_reduction_proxy/core/browser/data_store_impl.cc',
- 'data_reduction_proxy/core/browser/data_store_impl.h',
- ],
- },
- {
- # GN version: //components/data_reduction_proxy/core/common
- 'target_name': 'data_reduction_proxy_core_common',
- 'type': 'static_library',
- 'defines': [
- 'USE_GOOGLE_API_KEYS'
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../google_apis/google_apis.gyp:google_apis',
- '../url/url.gyp:url_lib',
- 'data_reduction_proxy_proto',
- 'data_reduction_proxy_version_header',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- '<@(data_reduction_proxy_core_common_sources)'
- ],
- },
- {
- # GN version: //components/data_reduction_proxy/core/browser:test_support
- 'target_name': 'data_reduction_proxy_test_support',
- 'type': 'static_library',
- 'dependencies' : [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../net/net.gyp:net_test_support',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- 'data_reduction_proxy_core_browser',
- 'data_reduction_proxy_core_common',
- 'data_reduction_proxy_proto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc',
- 'data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_event_storage_delegate_test_utils.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_event_storage_delegate_test_utils.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.h',
- 'data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc',
- 'data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- # GN version: //components/data_reduction_proxy/proto
- 'target_name': 'data_reduction_proxy_proto',
- 'type': 'static_library',
- 'dependencies': [
- ],
- 'include_dirs': [
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'data_reduction_proxy/proto/client_config.proto',
- 'data_reduction_proxy/proto/data_store.proto',
- 'data_reduction_proxy/proto/pageload_metrics.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'data_reduction_proxy/proto',
- 'proto_out_dir': 'components/data_reduction_proxy/proto',
- },
- 'includes': [ '../build/protoc.gypi' ],
- },
- {
- 'target_name': 'data_reduction_proxy_version_header',
- 'type': 'none',
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)',
- ],
- },
- 'actions': [
- {
- 'action_name': 'version_header',
- 'message': 'Generating version header file: <@(_outputs)',
- 'inputs': [
- '<(version_path)',
- 'data_reduction_proxy/core/common/version.h.in',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/components/data_reduction_proxy/core/common/version.h',
- ],
- 'action': [
- 'python',
- '<(version_py_path)',
- '-e', 'VERSION_FULL="<(version_full)"',
- 'data_reduction_proxy/core/common/version.h.in',
- '<@(_outputs)',
- ],
- 'includes': [
- '../build/util/version.gypi',
- ],
- },
- ],
- },
- ],
-}
diff --git a/chromium/components/data_reduction_proxy/DEPS b/chromium/components/data_reduction_proxy/DEPS
index f7c0da417f1..20847ff1716 100644
--- a/chromium/components/data_reduction_proxy/DEPS
+++ b/chromium/components/data_reduction_proxy/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/data_use_measurement/core",
"+components/pref_registry",
"+components/prefs",
"+components/variations",
diff --git a/chromium/components/data_reduction_proxy/OWNERS b/chromium/components/data_reduction_proxy/OWNERS
index 85817a2fecc..2868ce9f75b 100644
--- a/chromium/components/data_reduction_proxy/OWNERS
+++ b/chromium/components/data_reduction_proxy/OWNERS
@@ -2,6 +2,7 @@ bengr@chromium.org
bolian@chromium.org
kundaji@chromium.org
megjablon@chromium.org
+ryansturm@chromium.org
sclittle@chromium.org
tbansal@chromium.org
diff --git a/chromium/components/data_reduction_proxy/content/browser/BUILD.gn b/chromium/components/data_reduction_proxy/content/browser/BUILD.gn
index 15657e6d05f..d81d3755796 100644
--- a/chromium/components/data_reduction_proxy/content/browser/BUILD.gn
+++ b/chromium/components/data_reduction_proxy/content/browser/BUILD.gn
@@ -2,24 +2,20 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser") {
+static_library("browser") {
sources = [
"content_lofi_decider.cc",
"content_lofi_decider.h",
"content_lofi_ui_service.cc",
"content_lofi_ui_service.h",
- "data_reduction_proxy_message_filter.cc",
- "data_reduction_proxy_message_filter.h",
]
deps = [
"//base",
- "//components/data_reduction_proxy/content/common",
"//components/data_reduction_proxy/core/browser",
"//components/data_reduction_proxy/core/common",
"//content/public/browser",
"//content/public/common",
- "//ipc",
"//net",
]
}
@@ -29,7 +25,6 @@ source_set("unit_tests") {
sources = [
"content_lofi_decider_unittest.cc",
"content_lofi_ui_service_unittest.cc",
- "data_reduction_proxy_message_filter_unittest.cc",
]
deps = [
diff --git a/chromium/components/data_reduction_proxy/content/browser/DEPS b/chromium/components/data_reduction_proxy/content/browser/DEPS
index 897bf2ad715..b2f6f8ed02e 100644
--- a/chromium/components/data_reduction_proxy/content/browser/DEPS
+++ b/chromium/components/data_reduction_proxy/content/browser/DEPS
@@ -1,4 +1,3 @@
include_rules = [
- "+ipc",
"+net",
] \ No newline at end of file
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.cc b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.cc
index 0523f7ea334..e482f6656ec 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider.cc
@@ -49,9 +49,9 @@ bool ContentLoFiDecider::MaybeAddLoFiDirectiveToHeaders(
bool lofi_enabled_via_flag_or_field_trial =
params::IsLoFiOnViaFlags() || params::IsIncludedInLoFiEnabledFieldTrial();
- bool lofi_preview_via_flag_or_field_trial =
- params::AreLoFiPreviewsEnabledViaFlags() ||
- params::IsIncludedInLoFiPreviewFieldTrial();
+ bool lite_page_via_flag_or_field_trial =
+ params::AreLitePagesEnabledViaFlags() ||
+ params::IsIncludedInLitePageFieldTrial();
// User is not using Lo-Fi or is part of the "Control" group.
if (!request_info->IsUsingLoFi() || !lofi_enabled_via_flag_or_field_trial)
@@ -65,18 +65,18 @@ bool ContentLoFiDecider::MaybeAddLoFiDirectiveToHeaders(
header_value += ", ";
}
- // If in the preview field trial or the preview flag is enabled, only add the
+ // If in the lite page field trial or flag is enabled, only add the
// "q=preview" directive on main frame requests. Do not add Lo-Fi directives
- // to other requests when previews are enabled.
- if (lofi_preview_via_flag_or_field_trial) {
- if (request.load_flags() & net::LOAD_MAIN_FRAME) {
- if (params::AreLoFiPreviewsEnabledViaFlags()) {
- header_value += chrome_proxy_lo_fi_ignore_preview_blacklist_directive();
+ // to other requests when lite pages are enabled.
+ if (lite_page_via_flag_or_field_trial) {
+ if (request.load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) {
+ if (params::AreLitePagesEnabledViaFlags()) {
+ header_value += chrome_proxy_lite_page_ignore_blacklist_directive();
header_value += ", ";
}
- header_value += chrome_proxy_lo_fi_preview_directive();
+ header_value += chrome_proxy_lite_page_directive();
}
- } else if (!(request.load_flags() & net::LOAD_MAIN_FRAME)) {
+ } else if (!(request.load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED)) {
// If previews are not enabled, add "q=low" for requests that are not main
// frame.
header_value += chrome_proxy_lo_fi_directive();
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
index a2c43414ca6..c77449d845b 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
@@ -140,25 +140,25 @@ class ContentLoFiDeciderTest : public testing::Test {
header_value.find(chrome_proxy_lo_fi_directive()) != std::string::npos);
}
- static void VerifyLoFiPreviewHeader(bool expected_lofi_preview_used,
- const net::HttpRequestHeaders& headers) {
+ static void VerifyLitePageHeader(bool expected_lite_page_used,
+ const net::HttpRequestHeaders& headers) {
EXPECT_TRUE(headers.HasHeader(chrome_proxy_header()));
std::string header_value;
headers.GetHeader(chrome_proxy_header(), &header_value);
- EXPECT_EQ(expected_lofi_preview_used,
- header_value.find(chrome_proxy_lo_fi_preview_directive()) !=
+ EXPECT_EQ(expected_lite_page_used,
+ header_value.find(chrome_proxy_lite_page_directive()) !=
std::string::npos);
}
- static void VerifyLoFiIgnorePreviewBlacklistHeader(
- bool expected_lofi_preview_used,
+ static void VerifyLitePageIgnoreBlacklistHeader(
+ bool expected_lite_page_used,
const net::HttpRequestHeaders& headers) {
EXPECT_TRUE(headers.HasHeader(chrome_proxy_header()));
std::string header_value;
headers.GetHeader(chrome_proxy_header(), &header_value);
- EXPECT_EQ(expected_lofi_preview_used,
+ EXPECT_EQ(expected_lite_page_used,
header_value.find(
- chrome_proxy_lo_fi_ignore_preview_blacklist_directive()) !=
+ chrome_proxy_lite_page_ignore_blacklist_directive()) !=
std::string::npos);
}
@@ -176,7 +176,7 @@ TEST_F(ContentLoFiDeciderTest, LoFiFlags) {
// Enable Lo-Fi.
const struct {
bool is_using_lofi;
- bool is_using_previews;
+ bool is_using_lite_page;
bool is_main_frame;
} tests[] = {
{false, false, false}, {false, false, true}, {true, false, true},
@@ -189,38 +189,38 @@ TEST_F(ContentLoFiDeciderTest, LoFiFlags) {
CreateRequest(tests[i].is_using_lofi);
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv(command_line->argv());
- if (tests[i].is_using_previews) {
- command_line->AppendSwitch(
- switches::kEnableDataReductionProxyLoFiPreview);
+ if (tests[i].is_using_lite_page) {
+ command_line->AppendSwitch(switches::kEnableDataReductionProxyLitePage);
}
// No flags or field trials. The Lo-Fi header should not be added.
net::HttpRequestHeaders headers;
NotifyBeforeSendHeaders(&headers, request.get(), true);
VerifyLoFiHeader(false, headers);
- VerifyLoFiPreviewHeader(false, headers);
- VerifyLoFiIgnorePreviewBlacklistHeader(false, headers);
+ VerifyLitePageHeader(false, headers);
+ VerifyLitePageIgnoreBlacklistHeader(false, headers);
// The Lo-Fi flag is "always-on", Lo-Fi is being used, and it's a main frame
- // request. Lo-Fi preview header should be added.
+ // request. Lo-Fi or lite page header should be added.
command_line->AppendSwitchASCII(
switches::kDataReductionProxyLoFi,
switches::kDataReductionProxyLoFiValueAlwaysOn);
if (tests[i].is_main_frame)
- request->SetLoadFlags(request->load_flags() | net::LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() |
+ net::LOAD_MAIN_FRAME_DEPRECATED);
headers.Clear();
NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_previews &&
+ VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_lite_page &&
!tests[i].is_main_frame,
headers);
- VerifyLoFiPreviewHeader(tests[i].is_using_lofi &&
- tests[i].is_using_previews &&
- tests[i].is_main_frame,
- headers);
- VerifyLoFiIgnorePreviewBlacklistHeader(tests[i].is_using_lofi &&
- tests[i].is_using_previews &&
- tests[i].is_main_frame,
- headers);
+ VerifyLitePageHeader(tests[i].is_using_lofi &&
+ tests[i].is_using_lite_page &&
+ tests[i].is_main_frame,
+ headers);
+ VerifyLitePageIgnoreBlacklistHeader(tests[i].is_using_lofi &&
+ tests[i].is_using_lite_page &&
+ tests[i].is_main_frame,
+ headers);
DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
// |lofi_requested| should be set to false when Lo-Fi is enabled using
// flags.
@@ -231,10 +231,10 @@ TEST_F(ContentLoFiDeciderTest, LoFiFlags) {
request->SetLoadFlags(0);
headers.Clear();
NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_previews,
+ VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_lite_page,
headers);
- VerifyLoFiPreviewHeader(false, headers);
- VerifyLoFiIgnorePreviewBlacklistHeader(false, headers);
+ VerifyLitePageHeader(false, headers);
+ VerifyLitePageIgnoreBlacklistHeader(false, headers);
// The Lo-Fi flag is "cellular-only" and Lo-Fi is being used. Lo-Fi header
// should be added.
@@ -243,10 +243,10 @@ TEST_F(ContentLoFiDeciderTest, LoFiFlags) {
switches::kDataReductionProxyLoFiValueCellularOnly);
headers.Clear();
NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_previews,
+ VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_lite_page,
headers);
- VerifyLoFiPreviewHeader(false, headers);
- VerifyLoFiIgnorePreviewBlacklistHeader(false, headers);
+ VerifyLitePageHeader(false, headers);
+ VerifyLitePageIgnoreBlacklistHeader(false, headers);
data = DataReductionProxyData::GetData(*request);
// |lofi_requested| should be set to false when Lo-Fi is enabled using
// flags.
@@ -259,10 +259,10 @@ TEST_F(ContentLoFiDeciderTest, LoFiFlags) {
switches::kDataReductionProxyLoFiValueSlowConnectionsOnly);
headers.Clear();
NotifyBeforeSendHeaders(&headers, request.get(), true);
- VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_previews,
+ VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_lite_page,
headers);
- VerifyLoFiPreviewHeader(false, headers);
- VerifyLoFiIgnorePreviewBlacklistHeader(false, headers);
+ VerifyLitePageHeader(false, headers);
+ VerifyLitePageIgnoreBlacklistHeader(false, headers);
data = DataReductionProxyData::GetData(*request);
// |lofi_requested| should be set to false when Lo-Fi is enabled using
// flags.
@@ -284,13 +284,14 @@ TEST_F(ContentLoFiDeciderTest, LoFiEnabledFieldTrial) {
std::unique_ptr<net::URLRequest> request =
CreateRequest(tests[i].is_using_lofi);
if (tests[i].is_main_frame)
- request->SetLoadFlags(request->load_flags() | net::LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() |
+ net::LOAD_MAIN_FRAME_DEPRECATED);
net::HttpRequestHeaders headers;
NotifyBeforeSendHeaders(&headers, request.get(), true);
VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_main_frame,
headers);
- VerifyLoFiPreviewHeader(false, headers);
- VerifyLoFiIgnorePreviewBlacklistHeader(false, headers);
+ VerifyLitePageHeader(false, headers);
+ VerifyLitePageIgnoreBlacklistHeader(false, headers);
DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
EXPECT_EQ(tests[i].is_using_lofi, data->lofi_requested()) << i;
}
@@ -310,18 +311,19 @@ TEST_F(ContentLoFiDeciderTest, LoFiControlFieldTrial) {
std::unique_ptr<net::URLRequest> request =
CreateRequest(tests[i].is_using_lofi);
if (tests[i].is_main_frame)
- request->SetLoadFlags(request->load_flags() | net::LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() |
+ net::LOAD_MAIN_FRAME_DEPRECATED);
net::HttpRequestHeaders headers;
NotifyBeforeSendHeaders(&headers, request.get(), true);
VerifyLoFiHeader(false, headers);
- VerifyLoFiPreviewHeader(false, headers);
- VerifyLoFiIgnorePreviewBlacklistHeader(false, headers);
+ VerifyLitePageHeader(false, headers);
+ VerifyLitePageIgnoreBlacklistHeader(false, headers);
DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
EXPECT_EQ(tests[i].is_using_lofi, data->lofi_requested()) << i;
}
}
-TEST_F(ContentLoFiDeciderTest, LoFiPreviewFieldTrial) {
+TEST_F(ContentLoFiDeciderTest, LitePageFieldTrial) {
base::FieldTrialList field_trial_list(nullptr);
base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(),
"Enabled_Preview");
@@ -337,13 +339,14 @@ TEST_F(ContentLoFiDeciderTest, LoFiPreviewFieldTrial) {
std::unique_ptr<net::URLRequest> request =
CreateRequest(tests[i].is_using_lofi);
if (tests[i].is_main_frame)
- request->SetLoadFlags(request->load_flags() | net::LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() |
+ net::LOAD_MAIN_FRAME_DEPRECATED);
net::HttpRequestHeaders headers;
NotifyBeforeSendHeaders(&headers, request.get(), true);
VerifyLoFiHeader(false, headers);
- VerifyLoFiPreviewHeader(tests[i].is_using_lofi && tests[i].is_main_frame,
- headers);
- VerifyLoFiIgnorePreviewBlacklistHeader(false, headers);
+ VerifyLitePageHeader(tests[i].is_using_lofi && tests[i].is_main_frame,
+ headers);
+ VerifyLitePageIgnoreBlacklistHeader(false, headers);
DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
EXPECT_EQ(tests[i].is_using_lofi, data->lofi_requested()) << i;
}
@@ -391,7 +394,8 @@ TEST_F(ContentLoFiDeciderTest, AutoLoFi) {
std::unique_ptr<net::URLRequest> request =
CreateRequest(tests[i].network_prohibitively_slow);
if (tests[i].is_main_frame)
- request->SetLoadFlags(request->load_flags() | net::LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() |
+ net::LOAD_MAIN_FRAME_DEPRECATED);
net::HttpRequestHeaders headers;
NotifyBeforeSendHeaders(&headers, request.get(), true);
@@ -446,7 +450,8 @@ TEST_F(ContentLoFiDeciderTest, SlowConnectionsFlag) {
std::unique_ptr<net::URLRequest> request =
CreateRequest(tests[i].network_prohibitively_slow);
if (tests[i].is_main_frame)
- request->SetLoadFlags(request->load_flags() | net::LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() |
+ net::LOAD_MAIN_FRAME_DEPRECATED);
net::HttpRequestHeaders headers;
NotifyBeforeSendHeaders(&headers, request.get(), true);
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service.cc b/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service.cc
index c85330f4477..55229557647 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service.cc
@@ -27,8 +27,8 @@ ContentLoFiUIService::ContentLoFiUIService(
ContentLoFiUIService::~ContentLoFiUIService() {}
-void ContentLoFiUIService::OnLoFiReponseReceived(const net::URLRequest& request,
- bool is_preview) {
+void ContentLoFiUIService::OnLoFiReponseReceived(
+ const net::URLRequest& request) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
int render_process_id = -1;
int render_frame_id = -1;
@@ -37,15 +37,13 @@ void ContentLoFiUIService::OnLoFiReponseReceived(const net::URLRequest& request,
ui_task_runner_->PostTask(
FROM_HERE,
base::Bind(&ContentLoFiUIService::OnLoFiResponseReceivedOnUIThread,
- base::Unretained(this), render_process_id, render_frame_id,
- is_preview));
+ base::Unretained(this), render_process_id, render_frame_id));
}
}
void ContentLoFiUIService::OnLoFiResponseReceivedOnUIThread(
int render_process_id,
- int render_frame_id,
- bool is_preview) {
+ int render_frame_id) {
DCHECK(ui_task_runner_->BelongsToCurrentThread());
content::RenderFrameHost* frame =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
@@ -53,7 +51,7 @@ void ContentLoFiUIService::OnLoFiResponseReceivedOnUIThread(
DCHECK(!on_lofi_response_received_callback_.is_null());
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(frame);
- on_lofi_response_received_callback_.Run(web_contents, is_preview);
+ on_lofi_response_received_callback_.Run(web_contents);
}
}
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service.h b/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service.h
index 34757cb3e13..9c0c3f1eadb 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service.h
+++ b/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service.h
@@ -24,8 +24,8 @@ class URLRequest;
namespace data_reduction_proxy {
-typedef base::Callback<void(content::WebContents* web_contents,
- bool is_preview)> OnLoFiResponseReceivedCallback;
+using OnLoFiResponseReceivedCallback =
+ base::Callback<void(content::WebContents* web_contents)>;
// Passes notifications to the UI thread that a Lo-Fi response has been
// received. These notifications may be used to show Lo-Fi UI. This object lives
@@ -38,17 +38,14 @@ class ContentLoFiUIService : public LoFiUIService {
~ContentLoFiUIService() override;
// LoFiUIService implementation:
- void OnLoFiReponseReceived(const net::URLRequest& request,
- bool is_preview) override;
+ void OnLoFiReponseReceived(const net::URLRequest& request) override;
private:
// Using the |render_process_id| and |render_frame_id|, gets the associated
// WebContents if it exists and runs the
- // |notify_lofi_response_received_callback_|. |is_preview| indicates whether
- // the response was a Lo-Fi preview response.
+ // |notify_lofi_response_received_callback_|.
void OnLoFiResponseReceivedOnUIThread(int render_process_id,
- int render_frame_id,
- bool is_preview);
+ int render_frame_id);
// A task runner to post calls to OnLoFiReponseReceivedOnUI on the UI
// thread.
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc b/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc
index 22699f32824..ee9affb9e44 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc
@@ -27,12 +27,12 @@ namespace data_reduction_proxy {
class ContentLoFiUIServiceTest : public content::RenderViewHostTestHarness {
public:
- ContentLoFiUIServiceTest() : callback_called_(false), is_preview_(false) {
+ ContentLoFiUIServiceTest() : callback_called_(false) {
// Cannot use IO_MAIN_LOOP with RenderViewHostTestHarness.
SetThreadBundleOptions(content::TestBrowserThreadBundle::REAL_IO_THREAD);
}
- void RunTestOnIOThread(base::RunLoop* ui_run_loop, bool is_preview) {
+ void RunTestOnIOThread(base::RunLoop* ui_run_loop) {
ASSERT_TRUE(ui_run_loop);
EXPECT_TRUE(
content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
@@ -44,7 +44,7 @@ class ContentLoFiUIServiceTest : public content::RenderViewHostTestHarness {
context.Init();
content_lofi_ui_service_.reset(new ContentLoFiUIService(
- content::BrowserThread::GetMessageLoopProxyForThread(
+ content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::UI),
base::Bind(&ContentLoFiUIServiceTest::OnLoFiResponseReceivedCallback,
base::Unretained(this))));
@@ -52,7 +52,7 @@ class ContentLoFiUIServiceTest : public content::RenderViewHostTestHarness {
std::unique_ptr<net::URLRequest> request =
CreateRequest(context, &delegate);
- content_lofi_ui_service_->OnLoFiReponseReceived(*request, is_preview);
+ content_lofi_ui_service_->OnLoFiReponseReceived(*request);
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
@@ -81,25 +81,21 @@ class ContentLoFiUIServiceTest : public content::RenderViewHostTestHarness {
return request;
}
- void OnLoFiResponseReceivedCallback(content::WebContents* web_contents,
- bool is_preview) {
+ void OnLoFiResponseReceivedCallback(content::WebContents* web_contents) {
EXPECT_TRUE(
content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
callback_called_ = true;
- is_preview_ = is_preview;
}
- void VerifyOnLoFiResponseReceivedCallback(bool is_preview) {
+ void VerifyOnLoFiResponseReceivedCallback() {
EXPECT_TRUE(
content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
EXPECT_TRUE(callback_called_);
- EXPECT_EQ(is_preview, is_preview_);
}
private:
std::unique_ptr<ContentLoFiUIService> content_lofi_ui_service_;
bool callback_called_;
- bool is_preview_;
};
TEST_F(ContentLoFiUIServiceTest, OnLoFiResponseReceived) {
@@ -107,21 +103,10 @@ TEST_F(ContentLoFiUIServiceTest, OnLoFiResponseReceived) {
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&ContentLoFiUIServiceTest::RunTestOnIOThread,
- base::Unretained(this), &ui_run_loop, false));
+ base::Unretained(this), &ui_run_loop));
ui_run_loop.Run();
base::RunLoop().RunUntilIdle();
- VerifyOnLoFiResponseReceivedCallback(false);
-}
-
-TEST_F(ContentLoFiUIServiceTest, OnLoFiPreviewResponseReceived) {
- base::RunLoop ui_run_loop;
- content::BrowserThread::PostTask(
- content::BrowserThread::IO, FROM_HERE,
- base::Bind(&ContentLoFiUIServiceTest::RunTestOnIOThread,
- base::Unretained(this), &ui_run_loop, true));
- ui_run_loop.Run();
- base::RunLoop().RunUntilIdle();
- VerifyOnLoFiResponseReceivedCallback(true);
+ VerifyOnLoFiResponseReceivedCallback();
}
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc b/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc
deleted file mode 100644
index a804d417120..00000000000
--- a/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc
+++ /dev/null
@@ -1,56 +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 "components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h"
-
-#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "content/public/browser/browser_thread.h"
-#include "ipc/ipc_message_macros.h"
-#include "net/base/host_port_pair.h"
-
-namespace data_reduction_proxy {
-
-DataReductionProxyMessageFilter::DataReductionProxyMessageFilter(
- DataReductionProxySettings* settings)
- : BrowserMessageFilter(DataReductionProxyStart),
- config_(nullptr) {
- if (settings)
- config_ = settings->Config();
-}
-
-DataReductionProxyMessageFilter::~DataReductionProxyMessageFilter() {
-}
-
-bool DataReductionProxyMessageFilter::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(DataReductionProxyMessageFilter, message)
- IPC_MESSAGE_HANDLER(DataReductionProxyViewHostMsg_IsDataReductionProxy,
- OnIsDataReductionProxy)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void DataReductionProxyMessageFilter::OverrideThreadForMessage(
- const IPC::Message& message, content::BrowserThread::ID* thread) {
- if (message.type() ==
- DataReductionProxyViewHostMsg_IsDataReductionProxy::ID) {
- *thread = content::BrowserThread::IO;
- }
-}
-
-void DataReductionProxyMessageFilter::OnIsDataReductionProxy(
- const net::HostPortPair& proxy_server,
- bool* is_data_reduction_proxy) {
- *is_data_reduction_proxy = false;
- if (!config_)
- return;
- *is_data_reduction_proxy =
- config_->IsDataReductionProxy(proxy_server, nullptr);
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h b/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h
deleted file mode 100644
index a93038d4b52..00000000000
--- a/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h
+++ /dev/null
@@ -1,48 +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 COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_BROWSER_DATA_REDUCTION_PROXY_MESSAGE_FILTER_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_BROWSER_DATA_REDUCTION_PROXY_MESSAGE_FILTER_H_
-
-#include "base/macros.h"
-#include "content/public/browser/browser_message_filter.h"
-
-namespace net {
-class HostPortPair;
-}
-
-namespace data_reduction_proxy {
-
-class DataReductionProxyConfig;
-class DataReductionProxySettings;
-
-// An IPC listener to handle DataReductionProxy IPC messages from the renderer.
-class DataReductionProxyMessageFilter
- : public content::BrowserMessageFilter {
- public:
- // |settings| may be null.
- DataReductionProxyMessageFilter(DataReductionProxySettings* settings);
-
- // Sets |is_data_reduction_proxy| to true if the |proxy_server| corresponds to
- // a Data Reduction Proxy. |is_data_reduction_proxy| must not be null.
- void OnIsDataReductionProxy(const net::HostPortPair& proxy_server,
- bool* is_data_reduction_proxy);
-
- private:
- ~DataReductionProxyMessageFilter() override;
-
- // BrowserMessageFilter implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
- void OverrideThreadForMessage(const IPC::Message& message,
- content::BrowserThread::ID* thread) override;
-
- // Must outlive |this|. May be null.
- DataReductionProxyConfig* config_;
-
- DISALLOW_COPY_AND_ASSIGN(DataReductionProxyMessageFilter);
-};
-
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_BROWSER_DATA_REDUCTION_PROXY_MESSAGE_FILTER_H_
diff --git a/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc b/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc
deleted file mode 100644
index 1c89e99d4d3..00000000000
--- a/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc
+++ /dev/null
@@ -1,69 +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 "components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h"
-
-#include <memory>
-
-#include "base/command_line.h"
-#include "base/memory/ref_counted.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "net/base/host_port_pair.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace data_reduction_proxy {
-
-class DataReductionProxyMessageFilterTest : public testing::Test {
- public:
- void SetUp() override {
- test_context_ =
- DataReductionProxyTestContext::Builder()
- .WithParamsFlags(DataReductionProxyParams::kAllowed)
- .WithParamsDefinitions(TestDataReductionProxyParams::HAS_EVERYTHING)
- .WithMockConfig()
- .Build();
- message_filter_ = new DataReductionProxyMessageFilter(
- test_context_->settings());
- }
-
- protected:
- DataReductionProxyMessageFilter* message_filter() const {
- return message_filter_.get();
- }
-
- MockDataReductionProxyConfig* config() const {
- return test_context_->mock_config();
- }
-
- private:
- base::MessageLoopForIO message_loop_;
- std::unique_ptr<DataReductionProxyTestContext> test_context_;
- scoped_refptr<DataReductionProxyMessageFilter> message_filter_;
-};
-
-TEST_F(DataReductionProxyMessageFilterTest, TestOnIsDataReductionProxy) {
- net::HostPortPair proxy_server =
- net::HostPortPair::FromString("www.google.com:443");
- bool is_data_reduction_proxy = false;
- EXPECT_CALL(*config(), IsDataReductionProxy(testing::_, nullptr))
- .Times(1)
- .WillOnce(testing::Return(true));
- message_filter()->OnIsDataReductionProxy(proxy_server,
- &is_data_reduction_proxy);
- EXPECT_TRUE(is_data_reduction_proxy);
-
- EXPECT_CALL(*config(), IsDataReductionProxy(testing::_, nullptr))
- .Times(1)
- .WillOnce(testing::Return(false));
- message_filter()->OnIsDataReductionProxy(proxy_server,
- &is_data_reduction_proxy);
- EXPECT_FALSE(is_data_reduction_proxy);
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/content/common/BUILD.gn b/chromium/components/data_reduction_proxy/content/common/BUILD.gn
deleted file mode 100644
index cb33fbee498..00000000000
--- a/chromium/components/data_reduction_proxy/content/common/BUILD.gn
+++ /dev/null
@@ -1,16 +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.
-
-static_library("common") {
- sources = [
- "data_reduction_proxy_messages.cc",
- "data_reduction_proxy_messages.h",
- ]
-
- deps = [
- "//content/public/common",
- "//ipc",
- "//net",
- ]
-}
diff --git a/chromium/components/data_reduction_proxy/content/common/DEPS b/chromium/components/data_reduction_proxy/content/common/DEPS
deleted file mode 100644
index c3505fa54c3..00000000000
--- a/chromium/components/data_reduction_proxy/content/common/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+content/public/common",
- "+ipc",
-]
diff --git a/chromium/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.cc b/chromium/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.cc
deleted file mode 100644
index d2a80bd294a..00000000000
--- a/chromium/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.cc
+++ /dev/null
@@ -1,39 +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.
-
-// Get basic type definitions.
-#define IPC_MESSAGE_IMPL
-#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h"
-
-// Generate constructors.
-#include "ipc/struct_constructor_macros.h"
-#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h"
-
-// Generate destructors.
-#include "ipc/struct_destructor_macros.h"
-#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h"
-
-// Generate param traits size methods.
-#include "ipc/param_traits_size_macros.h"
-namespace IPC {
-#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h"
-} // namespace IPC
-
-// Generate param traits write methods.
-#include "ipc/param_traits_write_macros.h"
-namespace IPC {
-#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h"
-} // namespace IPC
-
-// Generate param traits read methods.
-#include "ipc/param_traits_read_macros.h"
-namespace IPC {
-#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h"
-} // namespace IPC
-
-// Generate param traits log methods.
-#include "ipc/param_traits_log_macros.h"
-namespace IPC {
-#include "components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h"
-} // namespace IPC
diff --git a/chromium/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h b/chromium/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h
deleted file mode 100644
index c7b852e72ea..00000000000
--- a/chromium/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h
+++ /dev/null
@@ -1,15 +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.
-
-// Multiply-included file, no traditional include guard.
-#include "content/public/common/common_param_traits.h"
-#include "ipc/ipc_message_macros.h"
-#include "net/base/host_port_pair.h"
-
-#define IPC_MESSAGE_START DataReductionProxyStart
-
-IPC_SYNC_MESSAGE_CONTROL1_1(
- DataReductionProxyViewHostMsg_IsDataReductionProxy,
- net::HostPortPair /* proxy server */,
- bool /* true iff the proxy server is a Data Reduction Proxy */)
diff --git a/chromium/components/data_reduction_proxy/core/browser/BUILD.gn b/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
index 2b51887d6a4..6b6c428c388 100644
--- a/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
+++ b/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
@@ -51,13 +51,14 @@ browser_sources = [
]
if (is_android) {
- source_set("browser_small") {
+ static_library("browser_small") {
sources = browser_sources
deps = [
"//base",
"//components/data_reduction_proxy/core/common",
"//components/data_reduction_proxy/proto:data_reduction_proxy_proto",
+ "//components/data_use_measurement/core",
"//components/pref_registry",
"//components/prefs",
"//components/variations",
@@ -69,17 +70,20 @@ if (is_android) {
}
}
-source_set("browser") {
+static_library("browser") {
sources = browser_sources
sources += [
"data_store_impl.cc",
"data_store_impl.h",
]
- deps = [
- "//base",
+ public_deps = [
"//components/data_reduction_proxy/core/common",
"//components/data_reduction_proxy/proto:data_reduction_proxy_proto",
+ ]
+ deps = [
+ "//base",
+ "//components/data_use_measurement/core",
"//components/pref_registry",
"//components/prefs",
"//components/variations",
@@ -96,7 +100,7 @@ source_set("browser") {
}
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"data_reduction_proxy_config_test_utils.cc",
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
index 87bd4782b7b..9119d7c22a1 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
@@ -93,7 +93,9 @@ bool DataReductionProxyBypassProtocol::MaybeBypassProxyAndPrepareToRetry(
// Empty implies either that the request was served from cache or that
// request was served directly from the origin.
- if (request->proxy_server().IsEmpty()) {
+ if (!request->proxy_server().is_valid() ||
+ request->proxy_server().is_direct() ||
+ request->proxy_server().host_port_pair().IsEmpty()) {
ReportResponseProxyServerStatusHistogram(
RESPONSE_PROXY_SERVER_STATUS_EMPTY);
return false;
@@ -115,10 +117,15 @@ bool DataReductionProxyBypassProtocol::MaybeBypassProxyAndPrepareToRetry(
// then apply the bypass logic regardless.
// TODO(sclittle): Remove this workaround once http://crbug.com/476610 is
// fixed.
- data_reduction_proxy_type_info.proxy_servers.push_back(net::ProxyServer(
- net::ProxyServer::SCHEME_HTTPS, request->proxy_server()));
- data_reduction_proxy_type_info.proxy_servers.push_back(net::ProxyServer(
- net::ProxyServer::SCHEME_HTTP, request->proxy_server()));
+ const net::HostPortPair host_port_pair =
+ !request->proxy_server().is_valid() ||
+ request->proxy_server().is_direct()
+ ? net::HostPortPair()
+ : request->proxy_server().host_port_pair();
+ data_reduction_proxy_type_info.proxy_servers.push_back(
+ net::ProxyServer(net::ProxyServer::SCHEME_HTTPS, host_port_pair));
+ data_reduction_proxy_type_info.proxy_servers.push_back(
+ net::ProxyServer(net::ProxyServer::SCHEME_HTTP, host_port_pair));
data_reduction_proxy_type_info.proxy_index = 0;
} else {
ReportResponseProxyServerStatusHistogram(RESPONSE_PROXY_SERVER_STATUS_DRP);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
index 561204eb4d6..e44a9c2143f 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
@@ -245,8 +245,7 @@ class DataReductionProxyProtocolTest : public testing::Test {
base::RunLoop().Run();
if (!expected_error) {
- EXPECT_EQ(net::URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(net::OK, r->status().error());
+ EXPECT_EQ(net::OK, d.request_status());
if (expected_retry)
EXPECT_EQ(initial_headers_received_count + 2,
network_delegate_->headers_received_count());
@@ -256,8 +255,7 @@ class DataReductionProxyProtocolTest : public testing::Test {
EXPECT_EQ(content, d.data_received());
return;
}
- EXPECT_EQ(net::URLRequestStatus::FAILED, r->status().status());
- EXPECT_EQ(net::ERR_INVALID_RESPONSE, r->status().error());
+ EXPECT_EQ(net::ERR_INVALID_RESPONSE, d.request_status());
EXPECT_EQ(initial_headers_received_count,
network_delegate_->headers_received_count());
}
@@ -886,9 +884,9 @@ TEST_F(DataReductionProxyBypassProtocolEndToEndTest,
EXPECT_EQ(test.expected_bypass_type,
drp_test_context()->io_data()->bypass_stats()->GetBypassType());
// Check the bad proxy list.
- EXPECT_EQ(
- test.expected_bad_proxy,
- ContainsKey(context()->proxy_service()->proxy_retry_info(), kPrimary));
+ EXPECT_EQ(test.expected_bad_proxy,
+ base::ContainsKey(context()->proxy_service()->proxy_retry_info(),
+ kPrimary));
}
}
@@ -980,8 +978,7 @@ TEST_F(DataReductionProxyProtocolTest,
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(net::URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(net::OK, r->status().error());
+ EXPECT_EQ(net::OK, d.request_status());
EXPECT_EQ("Bypass message", d.data_received());
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
index a06f4d2317d..d9607104d51 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
@@ -117,7 +117,9 @@ DataReductionProxyBypassStats::~DataReductionProxyBypassStats() {
}
void DataReductionProxyBypassStats::OnUrlRequestCompleted(
- const net::URLRequest* request, bool started) {
+ const net::URLRequest* request,
+ bool started,
+ int net_error) {
DataReductionProxyTypeInfo proxy_info;
// Ignore requests that did not use the data reduction proxy. The check for
// LOAD_BYPASS_PROXY is necessary because the proxy_server() in the |request|
@@ -126,7 +128,7 @@ void DataReductionProxyBypassStats::OnUrlRequestCompleted(
if (data_reduction_proxy_config_->WasDataReductionProxyUsed(request,
&proxy_info) &&
(request->load_flags() & net::LOAD_BYPASS_PROXY) == 0 &&
- request->status().status() == net::URLRequestStatus::SUCCESS) {
+ net_error == net::OK) {
successful_requests_through_proxy_count_++;
NotifyUnavailabilityIfChanged();
@@ -134,7 +136,7 @@ void DataReductionProxyBypassStats::OnUrlRequestCompleted(
UMA_HISTOGRAM_COUNTS_100(
"DataReductionProxy.SuccessfulRequestCompletionCounts",
proxy_info.proxy_index);
- if (request->load_flags() & net::LOAD_MAIN_FRAME) {
+ if (request->load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) {
UMA_HISTOGRAM_COUNTS_100(
"DataReductionProxy.SuccessfulRequestCompletionCounts.MainFrame",
proxy_info.proxy_index);
@@ -168,7 +170,7 @@ void DataReductionProxyBypassStats::OnProxyFallback(
DataReductionProxyTypeInfo data_reduction_proxy_info;
if (bypassed_proxy.is_valid() && !bypassed_proxy.is_direct() &&
data_reduction_proxy_config_->IsDataReductionProxy(
- bypassed_proxy.host_port_pair(), &data_reduction_proxy_info)) {
+ bypassed_proxy, &data_reduction_proxy_info)) {
proxy_net_errors_count_++;
// To account for the case when the proxy is reachable for sometime, and
@@ -258,7 +260,8 @@ void DataReductionProxyBypassStats::RecordBypassedBytesHistograms(
// proxy configuration resolves to anything other than direct:// for a URL,
// the data reduction proxy will not be used.
DCHECK(data_reduction_proxy_type_info.proxy_servers.empty());
- if (!request.proxy_server().IsEmpty()) {
+ if (!request.proxy_server().is_valid() ||
+ !request.proxy_server().is_direct()) {
RecordBypassedBytes(last_bypass_type_,
DataReductionProxyBypassStats::PROXY_OVERRIDDEN,
content_length);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
index c8ac07b1a3a..be08aa55afd 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
@@ -57,7 +57,9 @@ class DataReductionProxyBypassStats
// Callback intended to be called from |DataReductionProxyNetworkDelegate|
// when a request completes. This method is used to gather bypass stats.
- void OnUrlRequestCompleted(const net::URLRequest* request, bool started);
+ void OnUrlRequestCompleted(const net::URLRequest* request,
+ bool started,
+ int net_error);
// Records the last bypass reason to |bypass_type_| and sets
// |triggering_request_| to true. A triggering request is the first request to
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
index 27250798a03..a78c18de2ae 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
@@ -35,7 +35,6 @@
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
-#include "net/log/net_log.h"
#include "net/socket/socket_test_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context_getter.h"
@@ -107,8 +106,8 @@ class DataReductionProxyBypassStatsTest : public testing::Test {
protected:
std::unique_ptr<DataReductionProxyBypassStats> BuildBypassStats() {
- return base::WrapUnique(new DataReductionProxyBypassStats(
- test_context_->config(), test_context_->unreachable_callback()));
+ return base::MakeUnique<DataReductionProxyBypassStats>(
+ test_context_->config(), test_context_->unreachable_callback());
}
net::URLRequest* url_request() {
@@ -179,7 +178,7 @@ TEST_F(DataReductionProxyBypassStatsTest, IsDataReductionProxyUnreachable) {
bypass_stats->OnProxyFallback(fallback_proxy_server,
net::ERR_PROXY_CONNECTION_FAILED);
- bypass_stats->OnUrlRequestCompleted(url_request(), false);
+ bypass_stats->OnUrlRequestCompleted(url_request(), false, net::OK);
RunUntilIdle();
EXPECT_EQ(test_case.is_unreachable, IsUnreachable());
@@ -203,7 +202,7 @@ TEST_F(DataReductionProxyBypassStatsTest, ProxyUnreachableThenReachable) {
EXPECT_TRUE(IsUnreachable());
// proxy succeeds
- bypass_stats->OnUrlRequestCompleted(url_request(), false);
+ bypass_stats->OnUrlRequestCompleted(url_request(), false, net::OK);
RunUntilIdle();
EXPECT_FALSE(IsUnreachable());
}
@@ -219,7 +218,7 @@ TEST_F(DataReductionProxyBypassStatsTest, ProxyReachableThenUnreachable) {
.WillRepeatedly(testing::Return(true));
// Proxy succeeds.
- bypass_stats->OnUrlRequestCompleted(url_request(), false);
+ bypass_stats->OnUrlRequestCompleted(url_request(), false, net::OK);
RunUntilIdle();
EXPECT_FALSE(IsUnreachable());
@@ -486,7 +485,7 @@ TEST_F(DataReductionProxyBypassStatsTest, SuccessfulRequestCompletion) {
}
if (test.is_main_frame) {
fake_request->SetLoadFlags(fake_request->load_flags() |
- net::LOAD_MAIN_FRAME);
+ net::LOAD_MAIN_FRAME_DEPRECATED);
}
if (test.net_error != net::OK)
@@ -499,7 +498,8 @@ TEST_F(DataReductionProxyBypassStatsTest, SuccessfulRequestCompletion) {
.WillRepeatedly(testing::DoAll(testing::SetArgPointee<1>(proxy_info),
Return(test.was_proxy_used)));
- bypass_stats->OnUrlRequestCompleted(fake_request.get(), false);
+ bypass_stats->OnUrlRequestCompleted(fake_request.get(), false,
+ test.net_error);
if (test.was_proxy_used && !test.is_load_bypass_proxy &&
test.net_error == net::OK) {
@@ -894,6 +894,10 @@ TEST_F(DataReductionProxyBypassStatsEndToEndTest,
CreateAndExecuteRequest(
GURL("http://foo.com"), test_case.initial_response_headers,
kErrorBody.c_str(), "HTTP/1.1 200 OK\r\n\r\n", kBody.c_str());
+
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
+
// The first request caused the proxy to be marked as bad, so this second
// request should not come through the proxy.
CreateAndExecuteRequest(GURL("http://bar.com"), "HTTP/1.1 200 OK\r\n\r\n",
@@ -906,6 +910,11 @@ TEST_F(DataReductionProxyBypassStatsEndToEndTest,
kNextBody.size(), 1);
ExpectOtherBypassedBytesHistogramsEmpty(histogram_tester,
test_case.histogram_name);
+
+ // "DataReductionProxy.ConfigService.HTTPRequests" should not be recorded
+ // for bypassed requests.
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
}
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
index 1b5063d0dc5..d787ad0e0f8 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
@@ -22,6 +22,7 @@
#include "components/data_reduction_proxy/core/browser/data_use_group.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
+#include "components/data_reduction_proxy/proto/data_store.pb.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "net/base/mime_util.h"
@@ -200,32 +201,6 @@ void RecordDailyContentLengthHistograms(
percent_savings_via_data_reduction_proxy);
}
-// Given a |net::NetworkChangeNotifier::ConnectionType|, returns the
-// corresponding |data_reduction_proxy::ConnectionType|.
-ConnectionType StoredConnectionType(
- net::NetworkChangeNotifier::ConnectionType networkType) {
- switch (networkType) {
- case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
- case net::NetworkChangeNotifier::CONNECTION_NONE:
- return ConnectionType::CONNECTION_UNKNOWN;
- case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
- return ConnectionType::CONNECTION_ETHERNET;
- case net::NetworkChangeNotifier::CONNECTION_WIFI:
- return ConnectionType::CONNECTION_WIFI;
- case net::NetworkChangeNotifier::CONNECTION_2G:
- return ConnectionType::CONNECTION_2G;
- case net::NetworkChangeNotifier::CONNECTION_3G:
- return ConnectionType::CONNECTION_3G;
- case net::NetworkChangeNotifier::CONNECTION_4G:
- return ConnectionType::CONNECTION_4G;
- case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
- return ConnectionType::CONNECTION_BLUETOOTH;
- default:
- NOTREACHED();
- return ConnectionType::CONNECTION_UNKNOWN;
- }
-}
-
} // namespace
class DataReductionProxyCompressionStats::DailyContentLengthUpdate {
@@ -372,8 +347,6 @@ DataReductionProxyCompressionStats::~DataReductionProxyCompressionStats() {
if (current_data_usage_load_status_ == LOADED)
PersistDataUsage();
- net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
-
WritePrefs();
}
@@ -392,10 +365,6 @@ void DataReductionProxyCompressionStats::Init() {
weak_factory_.GetWeakPtr()));
}
- net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
- connection_type_ =
- StoredConnectionType(net::NetworkChangeNotifier::GetConnectionType());
-
if (delay_.is_zero())
return;
@@ -451,28 +420,54 @@ void DataReductionProxyCompressionStats::Init() {
}
}
+void DataReductionProxyCompressionStats::UpdateDataSavings(
+ const std::string& data_usage_host,
+ int64_t data_used,
+ int64_t original_size) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // Data is recorded at the URLRequest level, so an update should only change
+ // the original size amount by the savings amount.
+ int64_t update_to_original_size = original_size - data_used;
+ int64_t update_to_data_used = 0;
+ RecordData(update_to_data_used, update_to_original_size,
+ true /* data_saver_enabled */, UPDATE, data_usage_host,
+ std::string());
+}
+
void DataReductionProxyCompressionStats::UpdateContentLengths(
int64_t data_used,
int64_t original_size,
- bool data_reduction_proxy_enabled,
+ bool data_saver_enabled,
DataReductionProxyRequestType request_type,
const scoped_refptr<DataUseGroup>& data_use_group,
const std::string& mime_type) {
DCHECK(thread_checker_.CalledOnValidThread());
- TRACE_EVENT0("loader",
- "DataReductionProxyCompressionStats::UpdateContentLengths")
+ std::string data_use_host;
+ if (data_use_group) {
+ data_use_host = data_use_group->GetHostname();
+ }
+
+ RecordData(data_used, original_size, data_saver_enabled, request_type,
+ data_use_host, mime_type);
+}
+
+void DataReductionProxyCompressionStats::RecordData(
+ int64_t data_used,
+ int64_t original_size,
+ bool data_saver_enabled,
+ DataReductionProxyRequestType request_type,
+ const std::string& data_use_host,
+ const std::string& mime_type) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ TRACE_EVENT0("loader", "DataReductionProxyCompressionStats::RecordData")
IncreaseInt64Pref(data_reduction_proxy::prefs::kHttpReceivedContentLength,
data_used);
IncreaseInt64Pref(data_reduction_proxy::prefs::kHttpOriginalContentLength,
original_size);
- std::string data_use_host;
- if (data_use_group) {
- data_use_host = data_use_group->GetHostname();
- }
RecordDataUsage(data_use_host, data_used, original_size, base::Time::Now());
- RecordRequestSizePrefs(data_used, original_size, data_reduction_proxy_enabled,
+ RecordRequestSizePrefs(data_used, original_size, data_saver_enabled,
request_type, mime_type, base::Time::Now());
}
@@ -539,19 +534,19 @@ void DataReductionProxyCompressionStats::WritePrefs() {
}
}
-base::Value*
+std::unique_ptr<base::Value>
DataReductionProxyCompressionStats::HistoricNetworkStatsInfoToValue() {
DCHECK(thread_checker_.CalledOnValidThread());
int64_t total_received = GetInt64(prefs::kHttpReceivedContentLength);
int64_t total_original = GetInt64(prefs::kHttpOriginalContentLength);
- base::DictionaryValue* dict = new base::DictionaryValue();
+ auto dict = base::MakeUnique<base::DictionaryValue>();
// Use strings to avoid overflow. base::Value only supports 32-bit integers.
dict->SetString("historic_received_content_length",
base::Int64ToString(total_received));
dict->SetString("historic_original_content_length",
base::Int64ToString(total_original));
- return dict;
+ return std::move(dict);
}
int64_t DataReductionProxyCompressionStats::GetLastUpdateTime() {
@@ -639,11 +634,6 @@ void DataReductionProxyCompressionStats::DeleteBrowsingHistory(
service_->DeleteBrowsingHistory(start, end);
}
-void DataReductionProxyCompressionStats::OnConnectionTypeChanged(
- net::NetworkChangeNotifier::ConnectionType type) {
- connection_type_ = StoredConnectionType(type);
-}
-
void DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded(
std::unique_ptr<DataUsageBucket> data_usage) {
DCHECK(current_data_usage_load_status_ == LOADING);
@@ -666,7 +656,7 @@ void DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded(
for (const auto& connection_usage : data_usage->connection_usage()) {
for (const auto& site_usage : connection_usage.site_usage()) {
data_usage_map_.set(site_usage.hostname(),
- base::WrapUnique(new PerSiteDataUsage(site_usage)));
+ base::MakeUnique<PerSiteDataUsage>(site_usage));
}
}
@@ -721,7 +711,7 @@ void DataReductionProxyCompressionStats::TransferList(
void DataReductionProxyCompressionStats::RecordRequestSizePrefs(
int64_t data_used,
int64_t original_size,
- bool with_data_reduction_proxy_enabled,
+ bool with_data_saver_enabled,
DataReductionProxyRequestType request_type,
const std::string& mime_type,
const base::Time& now) {
@@ -1007,10 +997,10 @@ void DataReductionProxyCompressionStats::RecordRequestSizePrefs(
unknown.UpdateForDateChange(days_since_last_update);
total.Add(original_size, data_used);
- if (with_data_reduction_proxy_enabled) {
+ if (with_data_saver_enabled) {
proxy_enabled.Add(original_size, data_used);
// Ignore data source cases, if exist, when
- // "with_data_reduction_proxy_enabled == false"
+ // "with_data_saver_enabled == false"
switch (request_type) {
case VIA_DATA_REDUCTION_PROXY:
via_proxy.Add(original_size, data_used);
@@ -1024,6 +1014,11 @@ void DataReductionProxyCompressionStats::RecordRequestSizePrefs(
case LONG_BYPASS:
long_bypass.Add(data_used);
break;
+ case UPDATE:
+ // Don't record any request level prefs. If this is an update, this data
+ // was already recorded at the URLRequest level. Updates are generally
+ // page load level optimizations and don't correspond to request types.
+ return;
case UNKNOWN_TYPE:
unknown.Add(data_used);
break;
@@ -1041,7 +1036,7 @@ void DataReductionProxyCompressionStats::RecordRequestSizePrefs(
original_size, data_used,
data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthApplication,
data_reduction_proxy::prefs::kDailyHttpReceivedContentLengthApplication,
- with_data_reduction_proxy_enabled,
+ with_data_saver_enabled,
data_reduction_proxy::prefs::
kDailyOriginalContentLengthWithDataReductionProxyEnabledApplication,
data_reduction_proxy::prefs::
@@ -1056,7 +1051,7 @@ void DataReductionProxyCompressionStats::RecordRequestSizePrefs(
original_size, data_used,
data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthVideo,
data_reduction_proxy::prefs::kDailyHttpReceivedContentLengthVideo,
- with_data_reduction_proxy_enabled,
+ with_data_saver_enabled,
data_reduction_proxy::prefs::
kDailyOriginalContentLengthWithDataReductionProxyEnabledVideo,
data_reduction_proxy::prefs::
@@ -1071,7 +1066,7 @@ void DataReductionProxyCompressionStats::RecordRequestSizePrefs(
original_size, data_used,
data_reduction_proxy::prefs::kDailyHttpOriginalContentLengthUnknown,
data_reduction_proxy::prefs::kDailyHttpReceivedContentLengthUnknown,
- with_data_reduction_proxy_enabled,
+ with_data_saver_enabled,
data_reduction_proxy::prefs::
kDailyOriginalContentLengthWithDataReductionProxyEnabledUnknown,
data_reduction_proxy::prefs::
@@ -1149,7 +1144,7 @@ void DataReductionProxyCompressionStats::RecordDataUsage(
std::string normalized_host = NormalizeHostname(data_usage_host);
auto j = data_usage_map_.add(normalized_host,
- base::WrapUnique(new PerSiteDataUsage()));
+ base::MakeUnique<PerSiteDataUsage>());
PerSiteDataUsage* per_site_usage = j.first->second;
per_site_usage->set_hostname(normalized_host);
per_site_usage->set_original_size(per_site_usage->original_size() +
@@ -1206,7 +1201,7 @@ void DataReductionProxyCompressionStats::GetHistoricalDataUsageImpl(
// This use case is unlikely to occur in practice since current data usage
// should have sufficient time to load before user tries to view data usage.
get_data_usage_callback.Run(
- base::WrapUnique(new std::vector<DataUsageBucket>()));
+ base::MakeUnique<std::vector<DataUsageBucket>>());
return;
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
index 5b03c36fbe0..3dfcf86612a 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
@@ -22,9 +22,8 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
#include "components/data_reduction_proxy/core/browser/db_data_owner.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/data_reduction_proxy/proto/data_store.pb.h"
+#include "components/data_reduction_proxy/core/common/data_savings_recorder.h"
#include "components/prefs/pref_member.h"
-#include "net/base/network_change_notifier.h"
class PrefService;
@@ -35,15 +34,16 @@ class Value;
namespace data_reduction_proxy {
class DataReductionProxyService;
+class DataUsageBucket;
class DataUseGroup;
+class PerSiteDataUsage;
// Data reduction proxy delayed pref service reduces the number calls to pref
// service by storing prefs in memory and writing to the given PrefService after
// |delay| amount of time. If |delay| is zero, the delayed pref service writes
// directly to the PrefService and does not store the prefs in memory. All
// prefs must be stored and read on the UI thread.
-class DataReductionProxyCompressionStats
- : public net::NetworkChangeNotifier::ConnectionTypeObserver {
+class DataReductionProxyCompressionStats {
public:
typedef base::ScopedPtrHashMap<std::string, std::unique_ptr<PerSiteDataUsage>>
SiteUsageMap;
@@ -60,7 +60,14 @@ class DataReductionProxyCompressionStats
DataReductionProxyCompressionStats(DataReductionProxyService* service,
PrefService* pref_service,
const base::TimeDelta& delay);
- ~DataReductionProxyCompressionStats() override;
+ ~DataReductionProxyCompressionStats();
+
+ // Records detailed data usage broken down by connection type and domain.
+ // Assumes that the |data_used| has been recoreded by previous calls to
+ // UpdateContentLengths.
+ void UpdateDataSavings(const std::string& data_usage_host,
+ int64_t data_used,
+ int64_t original_size);
// Records detailed data usage broken down by connection type and domain. Also
// records daily data savings statistics to prefs and reports data savings
@@ -73,9 +80,8 @@ class DataReductionProxyCompressionStats
const std::string& mime_type);
// Creates a |Value| summary of the persistent state of the network session.
- // The caller is responsible for deleting the returned value.
// Must be called on the UI thread.
- base::Value* HistoricNetworkStatsInfoToValue();
+ std::unique_ptr<base::Value> HistoricNetworkStatsInfoToValue();
// Returns the time in milliseconds since epoch that the last update was made
// to the daily original and received content lengths.
@@ -110,12 +116,6 @@ class DataReductionProxyCompressionStats
// range. Currently, this method deletes all data usage for the given range.
void DeleteBrowsingHistory(const base::Time& start, const base::Time& end);
- // Called by |net::NetworkChangeNotifier| when network type changes. Used to
- // keep track of connection type for reporting data usage breakdown by
- // connection type.
- void OnConnectionTypeChanged(
- net::NetworkChangeNotifier::ConnectionType type) override;
-
// Callback from loading detailed data usage. Initializes in memory data
// structures used to collect data usage. |data_usage| contains the data usage
// for the last stored interval.
@@ -232,13 +232,22 @@ class DataReductionProxyCompressionStats
// Example: "http://www.finance.google.com" -> "www.finance.google.com"
static std::string NormalizeHostname(const std::string& host);
+ // Records detailed data usage broken down by |host|. Also records daily data
+ // savings statistics to prefs and reports data savings UMA. |data_used| and
+ // |original_size| are measured in bytes.
+ void RecordData(int64_t data_used,
+ int64_t original_size,
+ bool data_saver_enabled,
+ DataReductionProxyRequestType request_type,
+ const std::string& data_use_host,
+ const std::string& mime_type);
+
DataReductionProxyService* service_;
PrefService* pref_service_;
const base::TimeDelta delay_;
DataReductionProxyPrefMap pref_map_;
DataReductionProxyListPrefMap list_pref_map_;
BooleanPrefMember data_usage_reporting_enabled_;
- ConnectionType connection_type_;
// Maintains detailed data usage for current interval.
SiteUsageMap data_usage_map_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
index 26994de3b34..31a62cc287d 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
@@ -23,6 +23,7 @@
#include "components/data_reduction_proxy/core/browser/data_use_group.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
+#include "components/data_reduction_proxy/proto/data_store.pb.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/testing_pref_service.h"
@@ -178,7 +179,8 @@ class DataReductionProxyCompressionStatsTest : public testing::Test {
base::ListValue* update = compression_stats_->GetList(pref);
update->Clear();
for (size_t i = 0; i < kNumDaysInHistory; ++i) {
- update->Insert(0, new base::StringValue(base::Int64ToString(0)));
+ update->Insert(
+ 0, base::MakeUnique<base::StringValue>(base::Int64ToString(0)));
}
}
@@ -517,7 +519,7 @@ TEST_F(DataReductionProxyCompressionStatsTest,
SetInt64(prefs::kHttpOriginalContentLength, kOriginalLength);
SetInt64(prefs::kHttpReceivedContentLength, kReceivedLength);
- stats_value.reset(compression_stats()->HistoricNetworkStatsInfoToValue());
+ stats_value = compression_stats()->HistoricNetworkStatsInfoToValue();
EXPECT_TRUE(stats_value->GetAsDictionary(&dict));
VerifyPrefs(dict);
}
@@ -536,7 +538,7 @@ TEST_F(DataReductionProxyCompressionStatsTest,
SetInt64(prefs::kHttpOriginalContentLength, kOriginalLength);
SetInt64(prefs::kHttpReceivedContentLength, kReceivedLength);
- stats_value.reset(compression_stats()->HistoricNetworkStatsInfoToValue());
+ stats_value = compression_stats()->HistoricNetworkStatsInfoToValue();
EXPECT_TRUE(stats_value->GetAsDictionary(&dict));
VerifyPrefs(dict);
}
@@ -548,7 +550,8 @@ TEST_F(DataReductionProxyCompressionStatsTest,
data_reduction_proxy::switches::kClearDataReductionProxyDataSavings);
base::ListValue list_value;
- list_value.Insert(0, new base::StringValue(base::Int64ToString(1234)));
+ list_value.Insert(
+ 0, base::MakeUnique<base::StringValue>(base::Int64ToString(1234)));
pref_service()->Set(prefs::kDailyHttpOriginalContentLength, list_value);
ResetCompressionStatsWithDelay(
@@ -562,7 +565,8 @@ TEST_F(DataReductionProxyCompressionStatsTest,
TEST_F(DataReductionProxyCompressionStatsTest,
ClearPrefsOnRestartDisabled) {
base::ListValue list_value;
- list_value.Insert(0, new base::StringValue(base::Int64ToString(1234)));
+ list_value.Insert(
+ 0, base::MakeUnique<base::StringValue>(base::Int64ToString(1234)));
pref_service()->Set(prefs::kDailyHttpOriginalContentLength, list_value);
ResetCompressionStatsWithDelay(
@@ -601,6 +605,28 @@ TEST_F(DataReductionProxyCompressionStatsTest, TotalLengths) {
GetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength));
}
+TEST_F(DataReductionProxyCompressionStatsTest, TotalLengthsUpdate) {
+ const int64_t kOriginalLength = 200;
+ const int64_t kReceivedLength = 100;
+
+ compression_stats()->UpdateDataSavings(std::string(), kReceivedLength,
+ kOriginalLength);
+
+ EXPECT_EQ(0,
+ GetInt64(data_reduction_proxy::prefs::kHttpReceivedContentLength));
+ EXPECT_EQ(kOriginalLength - kReceivedLength,
+ GetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength));
+
+ // Record the same numbers again, and total lengths should be doubled.
+ compression_stats()->UpdateDataSavings(std::string(), kReceivedLength,
+ kOriginalLength);
+
+ EXPECT_EQ(0,
+ GetInt64(data_reduction_proxy::prefs::kHttpReceivedContentLength));
+ EXPECT_EQ(kOriginalLength * 2 - kReceivedLength * 2,
+ GetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength));
+}
+
TEST_F(DataReductionProxyCompressionStatsTest, OneResponse) {
const int64_t kOriginalLength = 200;
const int64_t kReceivedLength = 100;
@@ -1064,8 +1090,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, RecordDataUsageSingleSite) {
RecordDataUsage("https://www.foo.com", 1000, 1250, now);
auto expected_data_usage =
- base::WrapUnique(new std::vector<data_reduction_proxy::DataUsageBucket>(
- kNumExpectedBuckets));
+ base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
+ kNumExpectedBuckets);
data_reduction_proxy::PerConnectionDataUsage* connection_usage =
expected_data_usage->at(kNumExpectedBuckets - 1).add_connection_usage();
data_reduction_proxy::PerSiteDataUsage* site_usage =
@@ -1094,15 +1120,15 @@ TEST_F(DataReductionProxyCompressionStatsTest, DisableDataUsageRecording) {
// Data usage on disk must be deleted.
auto expected_data_usage1 =
- base::WrapUnique(new std::vector<data_reduction_proxy::DataUsageBucket>(
- kNumExpectedBuckets));
+ base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
+ kNumExpectedBuckets);
DataUsageLoadVerifier verifier1(std::move(expected_data_usage1));
LoadHistoricalDataUsage(base::Bind(&DataUsageLoadVerifier::OnLoadDataUsage,
base::Unretained(&verifier1)));
// Public API must return an empty array.
- auto expected_data_usage2 = base::WrapUnique(
- new std::vector<data_reduction_proxy::DataUsageBucket>());
+ auto expected_data_usage2 =
+ base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>();
DataUsageLoadVerifier verifier2(std::move(expected_data_usage2));
GetHistoricalDataUsage(base::Bind(&DataUsageLoadVerifier::OnLoadDataUsage,
base::Unretained(&verifier2)),
@@ -1120,8 +1146,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, RecordDataUsageMultipleSites) {
RecordDataUsage("http://foobar.com", 1002, 1252, now);
auto expected_data_usage =
- base::WrapUnique(new std::vector<data_reduction_proxy::DataUsageBucket>(
- kNumExpectedBuckets));
+ base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
+ kNumExpectedBuckets);
data_reduction_proxy::PerConnectionDataUsage* connection_usage =
expected_data_usage->at(kNumExpectedBuckets - 1).add_connection_usage();
data_reduction_proxy::PerSiteDataUsage* site_usage =
@@ -1161,8 +1187,8 @@ TEST_F(DataReductionProxyCompressionStatsTest,
RecordDataUsage("https://bar.com", 1001, 1251, now);
auto expected_data_usage =
- base::WrapUnique(new std::vector<data_reduction_proxy::DataUsageBucket>(
- kNumExpectedBuckets));
+ base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
+ kNumExpectedBuckets);
data_reduction_proxy::PerConnectionDataUsage* connection_usage =
expected_data_usage->at(kNumExpectedBuckets - 2).add_connection_usage();
data_reduction_proxy::PerSiteDataUsage* site_usage =
@@ -1232,8 +1258,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, DeleteHistoricalDataUsage) {
base::RunLoop().RunUntilIdle();
auto expected_data_usage =
- base::WrapUnique(new std::vector<data_reduction_proxy::DataUsageBucket>(
- kNumExpectedBuckets));
+ base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
+ kNumExpectedBuckets);
DataUsageLoadVerifier verifier(std::move(expected_data_usage));
GetHistoricalDataUsage(base::Bind(&DataUsageLoadVerifier::OnLoadDataUsage,
@@ -1262,8 +1288,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, DeleteBrowsingHistory) {
ASSERT_TRUE(DataUsageMap()->empty());
auto expected_data_usage =
- base::WrapUnique(new std::vector<data_reduction_proxy::DataUsageBucket>(
- kNumExpectedBuckets));
+ base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
+ kNumExpectedBuckets);
data_reduction_proxy::PerConnectionDataUsage* connection_usage =
expected_data_usage->at(kNumExpectedBuckets - 1).add_connection_usage();
data_reduction_proxy::PerSiteDataUsage* site_usage =
@@ -1282,8 +1308,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, DeleteBrowsingHistory) {
base::RunLoop().RunUntilIdle();
expected_data_usage =
- base::WrapUnique(new std::vector<data_reduction_proxy::DataUsageBucket>(
- kNumExpectedBuckets));
+ base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
+ kNumExpectedBuckets);
DataUsageLoadVerifier verifier2(std::move(expected_data_usage));
LoadHistoricalDataUsage(base::Bind(&DataUsageLoadVerifier::OnLoadDataUsage,
base::Unretained(&verifier2)));
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
index 7f2fa9d2320..67d424f5e64 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -28,10 +28,12 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/variations/variations_associated_data.h"
#include "net/base/host_port_pair.h"
#include "net/base/load_flags.h"
#include "net/base/network_change_notifier.h"
+#include "net/log/net_log_source_type.h"
#include "net/proxy/proxy_server.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
@@ -231,6 +233,9 @@ class SecureProxyChecker : public net::URLFetcherDelegate {
FetcherResponseCallback fetcher_callback) {
fetcher_ = net::URLFetcher::Create(secure_proxy_check_url,
net::URLFetcher::GET, this);
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ fetcher_.get(),
+ data_use_measurement::DataUseUserData::DATA_REDUCTION_PROXY);
fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_PROXY);
fetcher_->SetRequestContext(url_request_context_getter_.get());
// Configure max retries to be at most kMaxRetries times for 5xx errors.
@@ -280,7 +285,7 @@ DataReductionProxyConfig::DataReductionProxyConfig(
configurator_(configurator),
event_creator_(event_creator),
lofi_effective_connection_type_threshold_(
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
+ net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
auto_lofi_hysteresis_(base::TimeDelta::Max()),
network_prohibitively_slow_(false),
connection_type_(net::NetworkChangeNotifier::GetConnectionType()),
@@ -339,13 +344,18 @@ bool DataReductionProxyConfig::WasDataReductionProxyUsed(
}
bool DataReductionProxyConfig::IsDataReductionProxy(
- const net::HostPortPair& host_port_pair,
+ const net::ProxyServer& proxy_server,
DataReductionProxyTypeInfo* proxy_info) const {
DCHECK(thread_checker_.CalledOnValidThread());
+ if (!proxy_server.is_valid() || proxy_server.is_direct())
+ return false;
+
const std::vector<net::ProxyServer>& proxy_list =
config_values_->proxies_for_http();
- auto proxy_it =
+
+ net::HostPortPair host_port_pair = proxy_server.host_port_pair();
+ const auto proxy_it =
std::find_if(proxy_list.begin(), proxy_list.end(),
[&host_port_pair](const net::ProxyServer& proxy) {
return proxy.is_valid() &&
@@ -377,7 +387,7 @@ bool DataReductionProxyConfig::IsBypassedByDataReductionProxyLocalRules(
return true;
if (result.proxy_server().is_direct())
return true;
- return !IsDataReductionProxy(result.proxy_server().host_port_pair(), NULL);
+ return !IsDataReductionProxy(result.proxy_server(), NULL);
}
bool DataReductionProxyConfig::AreDataReductionProxiesBypassed(
@@ -422,7 +432,7 @@ bool DataReductionProxyConfig::AreProxiesBypassed(
continue;
base::TimeDelta delay;
- if (IsDataReductionProxy(proxy.host_port_pair(), NULL)) {
+ if (IsDataReductionProxy(proxy, NULL)) {
if (!IsProxyBypassed(retry_map, proxy, &delay))
return false;
if (delay < min_delay)
@@ -456,13 +466,11 @@ bool DataReductionProxyConfig::IsNetworkQualityProhibitivelySlow(
network_type_changed = true;
}
- const net::NetworkQualityEstimator::EffectiveConnectionType
- effective_connection_type =
- network_quality_estimator->GetEffectiveConnectionType();
+ const net::EffectiveConnectionType effective_connection_type =
+ network_quality_estimator->GetEffectiveConnectionType();
const bool is_network_quality_available =
- effective_connection_type !=
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+ effective_connection_type != net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
// True only if the network is currently estimated to be slower than the
// defined thresholds.
@@ -512,9 +520,9 @@ void DataReductionProxyConfig::PopulateAutoLoFiParams() {
std::string field_trial = params::GetLoFiFieldTrialName();
// Default parameters to use.
- const net::NetworkQualityEstimator::EffectiveConnectionType
+ const net::EffectiveConnectionType
default_effective_connection_type_threshold =
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
const base::TimeDelta default_hysterisis = base::TimeDelta::FromSeconds(60);
if (params::IsLoFiSlowConnectionsOnlyViaFlags()) {
@@ -534,9 +542,13 @@ void DataReductionProxyConfig::PopulateAutoLoFiParams() {
std::string variation_value = variations::GetVariationParamValue(
field_trial, "effective_connection_type");
if (!variation_value.empty()) {
- lofi_effective_connection_type_threshold_ =
- net::NetworkQualityEstimator::GetEffectiveConnectionTypeForName(
- variation_value);
+ bool effective_connection_type_available =
+ net::GetEffectiveConnectionTypeForName(
+ variation_value, &lofi_effective_connection_type_threshold_);
+ DCHECK(effective_connection_type_available);
+
+ // Silence unused variable warning in release builds.
+ (void)effective_connection_type_available;
} else {
// Use the default parameters.
lofi_effective_connection_type_threshold_ =
@@ -587,7 +599,7 @@ bool DataReductionProxyConfig::ContainsDataReductionProxy(
proxy_rules.MapUrlSchemeToProxyList("http");
if (http_proxy_list && !http_proxy_list->IsEmpty() &&
// Sufficient to check only the first proxy.
- IsDataReductionProxy(http_proxy_list->Get().host_port_pair(), NULL)) {
+ IsDataReductionProxy(http_proxy_list->Get(), NULL)) {
return true;
}
@@ -641,7 +653,7 @@ void DataReductionProxyConfig::HandleSecureProxyCheckResponse(
bool success_response =
base::StartsWith(response, "OK", base::CompareCase::SENSITIVE);
if (event_creator_)
- event_creator_->EndSecureProxyCheck(bound_net_log_, status.error(),
+ event_creator_->EndSecureProxyCheck(net_log_with_source_, status.error(),
http_response_code, success_response);
if (!status.is_success()) {
@@ -751,11 +763,11 @@ void DataReductionProxyConfig::RecordSecureProxyCheckFetchResult(
void DataReductionProxyConfig::SecureProxyCheck(
const GURL& secure_proxy_check_url,
FetcherResponseCallback fetcher_callback) {
- bound_net_log_ = net::BoundNetLog::Make(
- net_log_, net::NetLog::SOURCE_DATA_REDUCTION_PROXY);
+ net_log_with_source_ = net::NetLogWithSource::Make(
+ net_log_, net::NetLogSourceType::DATA_REDUCTION_PROXY);
if (event_creator_) {
event_creator_->BeginSecureProxyCheck(
- bound_net_log_, config_values_->secure_proxy_check_url());
+ net_log_with_source_, config_values_->secure_proxy_check_url());
}
secure_proxy_checker_->CheckIfSecureProxyIsAllowed(secure_proxy_check_url,
@@ -776,8 +788,8 @@ void DataReductionProxyConfig::RecordAutoLoFiAccuracyRate(
params::IsIncludedInLoFiControlFieldTrial()) &&
!params::IsLoFiSlowConnectionsOnlyViaFlags());
DCHECK_EQ(0, measuring_duration.InMilliseconds() % 1000);
- DCHECK(
- ContainsValue(GetLofiAccuracyRecordingIntervals(), measuring_duration));
+ DCHECK(base::ContainsValue(GetLofiAccuracyRecordingIntervals(),
+ measuring_duration));
if (network_quality_at_last_query_ == NETWORK_QUALITY_AT_LAST_QUERY_UNKNOWN)
return;
@@ -794,12 +806,10 @@ void DataReductionProxyConfig::RecordAutoLoFiAccuracyRate(
if (now - last_query_ > 2 * measuring_duration)
return;
- const net::NetworkQualityEstimator::EffectiveConnectionType
- recent_effective_connection_type =
- network_quality_estimator->GetRecentEffectiveConnectionType(
- last_query_);
+ const net::EffectiveConnectionType recent_effective_connection_type =
+ network_quality_estimator->GetRecentEffectiveConnectionType(last_query_);
if (recent_effective_connection_type ==
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
+ net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
return;
}
@@ -849,17 +859,15 @@ void DataReductionProxyConfig::RecordAutoLoFiAccuracyRate(
}
bool DataReductionProxyConfig::IsEffectiveConnectionTypeSlowerThanThreshold(
- net::NetworkQualityEstimator::EffectiveConnectionType
- effective_connection_type) const {
- return effective_connection_type >=
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_OFFLINE &&
+ net::EffectiveConnectionType effective_connection_type) const {
+ return effective_connection_type >= net::EFFECTIVE_CONNECTION_TYPE_OFFLINE &&
effective_connection_type <= lofi_effective_connection_type_threshold_;
}
bool DataReductionProxyConfig::ShouldEnableLoFiMode(
const net::URLRequest& request) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK((request.load_flags() & net::LOAD_MAIN_FRAME) != 0);
+ DCHECK((request.load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) != 0);
DCHECK(!request.url().SchemeIsCryptographic());
net::NetworkQualityEstimator* network_quality_estimator;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
index 2a4c8ba3487..196203352ba 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -21,7 +21,8 @@
#include "net/base/net_errors.h"
#include "net/base/network_change_notifier.h"
#include "net/base/network_interfaces.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
+#include "net/nqe/effective_connection_type.h"
#include "net/nqe/network_quality_estimator.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_retry_info.h"
@@ -35,6 +36,7 @@ class SingleThreadTaskRunner;
namespace net {
class HostPortPair;
class NetLog;
+class ProxyServer;
class URLFetcher;
class URLRequest;
class URLRequestContextGetter;
@@ -92,9 +94,9 @@ class DataReductionProxyConfig
// of the |DataReductionProxyConfig| instance, with the exception of
// |config_values| which is owned by |this|. |event_creator| is used for
// logging the start and end of a secure proxy check; |net_log| is used to
- // create a net::BoundNetLog for correlating the start and end of the check.
- // |config_values| contains the Data Reduction Proxy configuration values.
- // |configurator| is the target for a configuration update.
+ // create a net::NetLogWithSource for correlating the start and end of the
+ // check. |config_values| contains the Data Reduction Proxy configuration
+ // values. |configurator| is the target for a configuration update.
DataReductionProxyConfig(
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
net::NetLog* net_log,
@@ -129,7 +131,7 @@ class DataReductionProxyConfig
const net::URLRequest* request,
DataReductionProxyTypeInfo* proxy_info) const;
- // Returns true if the specified |host_port_pair| matches a Data Reduction
+ // Returns true if the specified |proxy_server| matches a Data Reduction
// Proxy. If true, |proxy_info.proxy_servers.front()| will contain the name of
// the proxy that matches. Subsequent entries in |proxy_info.proxy_servers|
// will contain the name of the Data Reduction Proxy servers that would be
@@ -138,7 +140,7 @@ class DataReductionProxyConfig
// can be NULL if the caller isn't interested in its values. Virtual for
// testing.
virtual bool IsDataReductionProxy(
- const net::HostPortPair& host_port_pair,
+ const net::ProxyServer& proxy_server,
DataReductionProxyTypeInfo* proxy_info) const;
// Returns true if this request would be bypassed by the Data Reduction Proxy
@@ -310,8 +312,7 @@ class DataReductionProxyConfig
// Returns true if |effective_connection_type| is at least as poor as
// |lofi_effective_connection_type_threshold_|.
bool IsEffectiveConnectionTypeSlowerThanThreshold(
- net::NetworkQualityEstimator::EffectiveConnectionType
- effective_connection_type) const;
+ net::EffectiveConnectionType effective_connection_type) const;
std::unique_ptr<SecureProxyChecker> secure_proxy_checker_;
@@ -327,12 +328,12 @@ class DataReductionProxyConfig
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
// The caller must ensure that the |net_log_|, if set, outlives this instance.
- // It is used to create new instances of |bound_net_log_| on secure proxy
- // checks. |bound_net_log_| permits the correlation of the begin and end
- // phases of a given secure proxy check, and a new one is created for each
- // secure proxy check (with |net_log_| as a parameter).
+ // It is used to create new instances of |net_log_with_source_| on secure
+ // proxy checks. |net_log_with_source_| permits the correlation of the begin
+ // and end phases of a given secure proxy check, and a new one is created for
+ // each secure proxy check (with |net_log_| as a parameter).
net::NetLog* net_log_;
- net::BoundNetLog bound_net_log_;
+ net::NetLogWithSource net_log_with_source_;
// The caller must ensure that the |configurator_| outlives this instance.
DataReductionProxyConfigurator* configurator_;
@@ -346,8 +347,7 @@ class DataReductionProxyConfig
// Thresholds from the field trial at which auto Lo-Fi is turned on.
// If the effective connection type is at least as slow as
// |lofi_effective_connection_type_threshold_|, Lo-Fi would be turned on.
- net::NetworkQualityEstimator::EffectiveConnectionType
- lofi_effective_connection_type_threshold_;
+ net::EffectiveConnectionType lofi_effective_connection_type_threshold_;
// State of auto Lo-Fi is not changed more than once in any period of
// duration shorter than |auto_lofi_hysteresis_|.
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
index 6fac40b29e8..715f3f1d1c4 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -26,6 +26,7 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_util.h"
#include "components/data_reduction_proxy/proto/client_config.pb.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
#include "net/base/host_port_pair.h"
#include "net/base/load_flags.h"
#include "net/base/load_timing_info.h"
@@ -34,10 +35,9 @@
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
+#include "net/log/net_log_source_type.h"
#include "net/proxy/proxy_server.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"
namespace data_reduction_proxy {
@@ -70,13 +70,13 @@ const uint32_t kMaxBackgroundFetchIntervalSeconds = 6 * 60 * 60; // 6 hours.
// This is the default backoff policy used to communicate with the Data
// Reduction Proxy configuration service.
const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
- 0, // num_errors_to_ignore
- 1 * 1000, // initial_delay_ms
- 4, // multiply_factor
- 0.10, // jitter_factor,
- 30 * 60 * 1000, // maximum_backoff_ms
- -1, // entry_lifetime_ms
- true, // always_use_initial_delay
+ 0, // num_errors_to_ignore
+ 30 * 1000, // initial_delay_ms
+ 4, // multiply_factor
+ 0.25, // jitter_factor,
+ 128 * 60 * 1000, // maximum_backoff_ms
+ -1, // entry_lifetime_ms
+ true, // always_use_initial_delay
};
// Extracts the list of Data Reduction Proxy servers to use for HTTP requests.
@@ -114,23 +114,10 @@ void RecordAuthExpiredSessionKey(bool matches) {
: AUTH_EXPIRED_SESSION_KEY_MISMATCH;
UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.ClientConfig.AuthExpiredSessionKey", state,
+ "DataReductionProxy.ConfigService.AuthExpiredSessionKey", state,
AUTH_EXPIRED_SESSION_KEY_BOUNDARY);
}
-// Returns true if QUIC is enabled in the HTTP network session params tied to
-// |url_request_context_getter|. Should be called only on the IO thread.
-bool IsQuicEnabledGlobally(
- net::URLRequestContextGetter* url_request_context_getter) {
- return url_request_context_getter &&
- url_request_context_getter->GetURLRequestContext() &&
- url_request_context_getter->GetURLRequestContext()
- ->GetNetworkSessionParams() &&
- url_request_context_getter->GetURLRequestContext()
- ->GetNetworkSessionParams()
- ->enable_quic;
-}
-
} // namespace
const net::BackoffEntry::Policy& GetBackoffPolicy() {
@@ -164,8 +151,7 @@ DataReductionProxyConfigServiceClient::DataReductionProxyConfigServiceClient(
foreground_fetch_pending_(false),
#endif
previous_request_failed_authentication_(false),
- failed_attempts_before_success_(0),
- quic_enabled_(false) {
+ failed_attempts_before_success_(0) {
DCHECK(request_options);
DCHECK(config_values);
DCHECK(config);
@@ -221,9 +207,6 @@ void DataReductionProxyConfigServiceClient::InitializeOnIOThread(
#endif
net::NetworkChangeNotifier::AddIPAddressObserver(this);
url_request_context_getter_ = url_request_context_getter;
-
- quic_enabled_ = params::IsIncludedInQuicFieldTrial() &&
- IsQuicEnabledGlobally(url_request_context_getter);
}
void DataReductionProxyConfigServiceClient::SetEnabled(bool enabled) {
@@ -236,14 +219,15 @@ void DataReductionProxyConfigServiceClient::RetrieveConfig() {
if (!enabled_)
return;
- bound_net_log_ = net::BoundNetLog::Make(
- net_log_, net::NetLog::SOURCE_DATA_REDUCTION_PROXY);
+ net_log_with_source_ = net::NetLogWithSource::Make(
+ net_log_, net::NetLogSourceType::DATA_REDUCTION_PROXY);
// Strip off query string parameters
GURL::Replacements replacements;
replacements.ClearQuery();
GURL base_config_service_url =
config_service_url_.ReplaceComponents(replacements);
- event_creator_->BeginConfigRequest(bound_net_log_, base_config_service_url);
+ event_creator_->BeginConfigRequest(net_log_with_source_,
+ base_config_service_url);
config_fetch_start_time_ = base::TimeTicks::Now();
RetrieveRemoteConfig();
@@ -266,7 +250,7 @@ void DataReductionProxyConfigServiceClient::ApplySerializedConfig(
bool DataReductionProxyConfigServiceClient::ShouldRetryDueToAuthFailure(
const net::HttpRequestHeaders& request_headers,
const net::HttpResponseHeaders* response_headers,
- const net::HostPortPair& proxy_server,
+ const net::ProxyServer& proxy_server,
const net::LoadTimingInfo& load_timing_info) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(response_headers);
@@ -410,13 +394,16 @@ DataReductionProxyConfigServiceClient::GetURLFetcherForConfig(
DCHECK(thread_checker_.CalledOnValidThread());
std::unique_ptr<net::URLFetcher> fetcher(net::URLFetcher::Create(
secure_proxy_check_url, net::URLFetcher::POST, this));
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ fetcher.get(),
+ data_use_measurement::DataUseUserData::DATA_REDUCTION_PROXY);
fetcher->SetLoadFlags(net::LOAD_BYPASS_PROXY);
fetcher->SetUploadData("application/x-protobuf", request_body);
DCHECK(url_request_context_getter_);
fetcher->SetRequestContext(url_request_context_getter_);
- // Configure max retries to be at most kMaxRetries times for 5xx errors.
+ // |fetcher| should not retry on 5xx errors since the server may already be
+ // overloaded. Spurious 5xx errors are still retried on exponential backoff.
static const int kMaxRetries = 5;
- fetcher->SetMaxRetriesOn5xx(kMaxRetries);
fetcher->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
return fetcher;
}
@@ -470,7 +457,7 @@ void DataReductionProxyConfigServiceClient::HandleResponse(
succeeded, refresh_duration, GetBackoffEntry()->GetTimeUntilRelease());
SetConfigRefreshTimer(next_config_refresh_time);
- event_creator_->EndConfigRequest(bound_net_log_, status.error(),
+ event_creator_->EndConfigRequest(net_log_with_source_, status.error(),
response_code,
GetBackoffEntry()->failure_count(), proxies,
refresh_duration, next_config_refresh_time);
@@ -498,14 +485,6 @@ bool DataReductionProxyConfigServiceClient::ParseAndApplyProxyConfig(
return false;
request_options_->SetSecureSession(config.session_key());
- // If QUIC is enabled, the scheme of the first proxy (if it is HTTPS) would
- // be changed to QUIC.
- if (proxies[0].scheme() == net::ProxyServer::SCHEME_HTTPS && params_ &&
- quic_enabled_) {
- proxies[0] = net::ProxyServer(net::ProxyServer::SCHEME_QUIC,
- proxies[0].host_port_pair());
- DCHECK_EQ(net::ProxyServer::SCHEME_QUIC, proxies[0].scheme());
- }
config_values_->UpdateValues(proxies);
config_->ReloadConfig();
remote_config_applied_ = true;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
index 7357c4beb3a..4a3d8e7c600 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
@@ -18,7 +18,7 @@
#include "base/timer/timer.h"
#include "net/base/backoff_entry.h"
#include "net/base/network_change_notifier.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "url/gurl.h"
@@ -27,10 +27,11 @@
#endif // OS_ANDROID
namespace net {
-class HostPortPair;
class HttpRequestHeaders;
class HttpResponseHeaders;
+class NetLog;
struct LoadTimingInfo;
+class ProxyServer;
class URLFetcher;
class URLRequestContextGetter;
class URLRequestStatus;
@@ -126,7 +127,7 @@ class DataReductionProxyConfigServiceClient
bool ShouldRetryDueToAuthFailure(
const net::HttpRequestHeaders& request_headers,
const net::HttpResponseHeaders* response_headers,
- const net::HostPortPair& proxy_server,
+ const net::ProxyServer& proxy_server,
const net::LoadTimingInfo& load_timing_info);
protected:
@@ -244,7 +245,7 @@ class DataReductionProxyConfigServiceClient
std::unique_ptr<net::URLFetcher> fetcher_;
// Used to correlate the start and end of requests.
- net::BoundNetLog bound_net_log_;
+ net::NetLogWithSource net_log_with_source_;
// Used to determine the latency in retrieving the Data Reduction Proxy
// configuration.
@@ -276,9 +277,6 @@ class DataReductionProxyConfigServiceClient
// Time when the IP address last changed.
base::TimeTicks last_ip_address_change_;
- // True if QUIC can be used to connect to data reduction proxy server.
- bool quic_enabled_;
-
// Enforce usage on the IO thread.
base::ThreadChecker thread_checker_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
index 9724e89bf71..b30a9b900ad 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -130,9 +130,7 @@ class DataReductionProxyConfigServiceClientTest : public testing::Test {
mock_socket_factory_.reset(new net::MockClientSocketFactory());
}
- void Init(bool use_mock_client_socket_factory,
- bool enable_quic_in_params,
- const std::string& quic_field_trial_group) {
+ void Init(bool use_mock_client_socket_factory) {
if (!use_mock_client_socket_factory)
mock_socket_factory_.reset(nullptr);
test_context_ =
@@ -145,21 +143,12 @@ class DataReductionProxyConfigServiceClientTest : public testing::Test {
.SkipSettingsInitialization()
.Build();
- std::unique_ptr<net::HttpNetworkSession::Params> params(
- new net::HttpNetworkSession::Params());
- params->enable_quic = enable_quic_in_params;
- context_->set_http_network_session_params(std::move(params));
context_->set_client_socket_factory(mock_socket_factory_.get());
test_context_->AttachToURLRequestContext(context_storage_.get());
delegate_ = test_context_->io_data()->CreateProxyDelegate();
context_->set_proxy_delegate(delegate_.get());
context_->Init();
- base::FieldTrialList field_trial_list(nullptr);
- if (!quic_field_trial_group.empty()) {
- base::FieldTrialList::CreateFieldTrial(params::GetQuicFieldTrialName(),
- quic_field_trial_group);
- }
test_context_->InitSettings();
ResetBackoffEntryReleaseTime();
@@ -311,25 +300,25 @@ class DataReductionProxyConfigServiceClientTest : public testing::Test {
void AddMockSuccess() {
socket_data_providers_.push_back(
- (base::WrapUnique(new net::StaticSocketDataProvider(
- success_reads_, arraysize(success_reads_), nullptr, 0))));
+ (base::MakeUnique<net::StaticSocketDataProvider>(
+ success_reads_, arraysize(success_reads_), nullptr, 0)));
mock_socket_factory_->AddSocketDataProvider(
socket_data_providers_.back().get());
}
void AddMockPreviousSuccess() {
socket_data_providers_.push_back(
- (base::WrapUnique(new net::StaticSocketDataProvider(
+ (base::MakeUnique<net::StaticSocketDataProvider>(
previous_success_reads_, arraysize(previous_success_reads_),
- nullptr, 0))));
+ nullptr, 0)));
mock_socket_factory_->AddSocketDataProvider(
socket_data_providers_.back().get());
}
void AddMockFailure() {
socket_data_providers_.push_back(
- (base::WrapUnique(new net::StaticSocketDataProvider(
- not_found_reads_, arraysize(not_found_reads_), nullptr, 0))));
+ (base::MakeUnique<net::StaticSocketDataProvider>(
+ not_found_reads_, arraysize(not_found_reads_), nullptr, 0)));
mock_socket_factory_->AddSocketDataProvider(
socket_data_providers_.back().get());
}
@@ -369,51 +358,6 @@ class DataReductionProxyConfigServiceClientTest : public testing::Test {
return context_.get();
}
- void TestQuicProxy(bool enable_quic_in_params,
- const std::string& quic_field_trial_group,
- bool enable_trusted_spdy_proxy_field_trial,
- const std::string& expected_primary_proxy,
- const std::string& expected_fallback_proxy,
- net::ProxyServer::Scheme expected_primary_proxy_scheme) {
- Init(true, enable_quic_in_params, quic_field_trial_group);
-
- base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
- base::FieldTrialList::CreateFieldTrial(
- params::GetTrustedSpdyProxyFieldTrialName(),
- enable_trusted_spdy_proxy_field_trial ? "Enabled" : "Control");
-
- // Use a remote config.
- AddMockSuccess();
-
- SetDataReductionProxyEnabled(true, true);
-
- config_client()->RetrieveConfig();
- RunUntilIdle();
- EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
- config_client()->GetDelay());
-
- // Verify that the proxies were set properly.
- const net::ProxyServer expected_primary_proxy_server(
- expected_primary_proxy_scheme,
- net::ProxyServer::FromURI(expected_primary_proxy,
- expected_primary_proxy_scheme)
- .host_port_pair());
- EXPECT_EQ(std::vector<net::ProxyServer>(
- {expected_primary_proxy_server,
- net::ProxyServer::FromURI(expected_fallback_proxy,
- net::ProxyServer::SCHEME_HTTP)}),
- GetConfiguredProxiesForHttp());
-
- // Test that the trusted SPDY proxy is updated correctly after each config
- // retrieval. Currently, only the HTTPS proxies are marked as trusted.
- bool expect_proxy_is_trusted =
- expected_primary_proxy_scheme == net::ProxyServer::SCHEME_HTTPS &&
- enable_trusted_spdy_proxy_field_trial;
-
- EXPECT_EQ(expect_proxy_is_trusted,
- IsTrustedSpdyProxy(expected_primary_proxy_server));
- }
-
private:
base::MessageLoopForIO message_loop_;
std::unique_ptr<net::TestURLRequestContext> context_;
@@ -460,60 +404,9 @@ class DataReductionProxyConfigServiceClientTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyConfigServiceClientTest);
};
-// Tests that QUIC proxy is not used when QUIC is not enabled globally.
-TEST_F(DataReductionProxyConfigServiceClientTest, DisableQuic) {
- TestQuicProxy(false, "Control", false, kSuccessOrigin, kSuccessFallback,
- net::ProxyServer::SCHEME_HTTPS);
-}
-
-// Tests that QUIC proxy is not used when the session is not in data reduction
-// proxy's QUIC experiment.
-TEST_F(DataReductionProxyConfigServiceClientTest, EnableQuicOnlyInParams) {
- TestQuicProxy(true, "", true, kSuccessOrigin, kSuccessFallback,
- net::ProxyServer::SCHEME_HTTPS);
-}
-
-// Tests that QUIC proxy is not used when the session is in the control group of
-// data reduction proxy's QUIC experiment.
-TEST_F(DataReductionProxyConfigServiceClientTest,
- EnableQuicOnlyInParamsControlGroup) {
- TestQuicProxy(true, "Control", true, kSuccessOrigin, kSuccessFallback,
- net::ProxyServer::SCHEME_HTTPS);
-}
-
-// Tests that QUIC proxy is not used when QUIC is not enabled globally.
-TEST_F(DataReductionProxyConfigServiceClientTest, EnableQuicOnlyViaFieldTrial) {
- TestQuicProxy(false, "Enabled", true, kSuccessOrigin, kSuccessFallback,
- net::ProxyServer::SCHEME_HTTPS);
-}
-
-// Tests that QUIC proxy is used when all conditions are satisfied, and Chromium
-// is in the "Enabled" field trial group.
-TEST_F(DataReductionProxyConfigServiceClientTest,
- EnableQuicButNotTrustedSpdyProxy) {
- TestQuicProxy(true, "Enabled", false, kSuccessOrigin, kSuccessFallback,
- net::ProxyServer::SCHEME_QUIC);
-}
-
-// Tests that QUIC proxy is used when all conditions are satisfied, and Chromium
-// is in the "Enabled_NoControl" field trial group.
-TEST_F(DataReductionProxyConfigServiceClientTest,
- EnableQuicPrefixMatchingButNotTrustedSpdyProxy) {
- TestQuicProxy(true, "Enabled_NoControl", false, kSuccessOrigin,
- kSuccessFallback, net::ProxyServer::SCHEME_QUIC);
-}
-
-// Tests the interaction of the QUIC experiment with the trusted SPDY proxy
-// experiment.
-TEST_F(DataReductionProxyConfigServiceClientTest,
- EnableQuicAndTrustedSpdyProxy) {
- TestQuicProxy(true, "Enabled", true, kSuccessOrigin, kSuccessFallback,
- net::ProxyServer::SCHEME_QUIC);
-}
-
// Tests that backoff values increases with every time config cannot be fetched.
TEST_F(DataReductionProxyConfigServiceClientTest, EnsureBackoff) {
- Init(true, false, std::string());
+ Init(true);
// Use a local/static config.
base::HistogramTester histogram_tester;
AddMockFailure();
@@ -552,13 +445,15 @@ TEST_F(DataReductionProxyConfigServiceClientTest, EnsureBackoff) {
// Tests that the config is read successfully on the first attempt.
TEST_F(DataReductionProxyConfigServiceClientTest, RemoteConfigSuccess) {
- Init(true, false, std::string());
+ Init(true);
AddMockSuccess();
SetDataReductionProxyEnabled(true, true);
+ EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
config_client()->RetrieveConfig();
RunUntilIdle();
VerifyRemoteSuccess(true);
+ EXPECT_TRUE(configurator()->GetProxyConfig().is_valid());
#if defined(OS_ANDROID)
EXPECT_FALSE(config_client()->foreground_fetch_pending());
#endif
@@ -568,7 +463,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest, RemoteConfigSuccess) {
// proxies are not used if the secure check failed.
TEST_F(DataReductionProxyConfigServiceClientTest,
RemoteConfigSuccessWithSecureCheckFail) {
- Init(true, false, std::string());
+ Init(true);
AddMockSuccess();
SetDataReductionProxyEnabled(true, false);
EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
@@ -584,7 +479,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
// proxies are not used if the secure proxy check fails later after some time.
TEST_F(DataReductionProxyConfigServiceClientTest,
RemoteConfigSuccessWithDelayedSecureCheckFail) {
- Init(true, false, std::string());
+ Init(true);
AddMockSuccess();
SetDataReductionProxyEnabled(true, true);
EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
@@ -609,7 +504,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
// Tests that the config is read successfully on the second attempt.
TEST_F(DataReductionProxyConfigServiceClientTest,
RemoteConfigSuccessAfterFailure) {
- Init(true, false, std::string());
+ Init(true);
base::HistogramTester histogram_tester;
AddMockFailure();
@@ -641,7 +536,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
// Verifies that the config is fetched successfully after IP address changes.
TEST_F(DataReductionProxyConfigServiceClientTest, OnIPAddressChange) {
- Init(true, false, std::string());
+ Init(true);
const struct {
bool secure_proxies_allowed;
} tests[] = {
@@ -693,7 +588,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest, OnIPAddressChange) {
// some time.
TEST_F(DataReductionProxyConfigServiceClientTest,
OnIPAddressChangeDelayedSecureProxyCheckFail) {
- Init(true, false, std::string());
+ Init(true);
SetDataReductionProxyEnabled(true, true);
config_client()->RetrieveConfig();
@@ -738,7 +633,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
// Verifies that fetching the remote config has no effect if the config client
// is disabled.
TEST_F(DataReductionProxyConfigServiceClientTest, OnIPAddressChangeDisabled) {
- Init(true, false, std::string());
+ Init(true);
config_client()->SetEnabled(false);
SetDataReductionProxyEnabled(true, true);
config_client()->RetrieveConfig();
@@ -765,7 +660,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest, OnIPAddressChangeDisabled) {
// Verifies the correctness of AuthFailure when the session key in the request
// headers matches the currrent session key.
TEST_F(DataReductionProxyConfigServiceClientTest, AuthFailure) {
- Init(true, false, std::string());
+ Init(true);
net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
net::NetworkChangeNotifier::CONNECTION_WIFI);
net::HttpRequestHeaders request_headers;
@@ -779,12 +674,14 @@ TEST_F(DataReductionProxyConfigServiceClientTest, AuthFailure) {
AddMockPreviousSuccess();
SetDataReductionProxyEnabled(true, true);
+ EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
histogram_tester.ExpectTotalCount(
"DataReductionProxy.ConfigService.AuthExpired", 0);
config_client()->RetrieveConfig();
RunUntilIdle();
// First remote config should be fetched.
VerifyRemoteSuccessWithOldConfig();
+ EXPECT_TRUE(configurator()->GetProxyConfig().is_valid());
EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession());
EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
histogram_tester.ExpectUniqueSample(
@@ -802,9 +699,10 @@ TEST_F(DataReductionProxyConfigServiceClientTest, AuthFailure) {
base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1);
load_timing_info.send_start = load_timing_info.request_start;
EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure(
- request_headers, parsed.get(), origin.host_port_pair(),
- load_timing_info));
+ request_headers, parsed.get(), origin, load_timing_info));
EXPECT_EQ(1, config_client()->GetBackoffErrorCount());
+ EXPECT_FALSE(configurator()->GetProxyConfig().is_valid());
+
// Persisted config on pref should be cleared.
EXPECT_TRUE(persisted_config().empty());
histogram_tester.ExpectBucketCount(
@@ -829,8 +727,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest, AuthFailure) {
// Calling ShouldRetryDueToAuthFailure should trigger fetching of remote
// config.
EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure(
- request_headers, parsed.get(), origin.host_port_pair(),
- load_timing_info));
+ request_headers, parsed.get(), origin, load_timing_info));
EXPECT_EQ(2, config_client()->GetBackoffErrorCount());
histogram_tester.ExpectBucketCount(
"DataReductionProxy.ConfigService.AuthExpired", false, 2);
@@ -843,7 +740,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest, AuthFailure) {
VerifyRemoteSuccessWithOldConfig();
histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.ClientConfig.AuthExpiredSessionKey",
+ "DataReductionProxy.ConfigService.AuthExpiredSessionKey",
1 /* AUTH_EXPIRED_SESSION_KEY_MATCH */, 2);
}
@@ -851,7 +748,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest, AuthFailure) {
// headers do not match the currrent session key.
TEST_F(DataReductionProxyConfigServiceClientTest,
AuthFailureWithRequestHeaders) {
- Init(true, false, std::string());
+ Init(true);
net::HttpRequestHeaders request_headers;
const char kSessionKeyRequestHeaders[] = "123";
ASSERT_NE(kOldSuccessSessionKey, kSessionKeyRequestHeaders);
@@ -887,8 +784,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
load_timing_info.send_start = load_timing_info.request_start;
EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure(
- request_headers, parsed.get(), origin.host_port_pair(),
- load_timing_info));
+ request_headers, parsed.get(), origin, load_timing_info));
EXPECT_EQ(0, config_client()->GetBackoffErrorCount());
// Persisted config on pref should be cleared.
EXPECT_FALSE(persisted_config().empty());
@@ -900,14 +796,14 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
EXPECT_EQ(kOldSuccessSessionKey, request_options()->GetSecureSession());
histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.ClientConfig.AuthExpiredSessionKey",
+ "DataReductionProxy.ConfigService.AuthExpiredSessionKey",
0 /* AUTH_EXPIRED_SESSION_KEY_MISMATCH */, 1);
}
// Verifies that requests that were not proxied through data saver proxy due to
// missing config are recorded properly.
TEST_F(DataReductionProxyConfigServiceClientTest, HTTPRequests) {
- Init(false, false, std::string());
+ Init(false);
const struct {
std::string url;
bool enabled_by_user;
@@ -963,7 +859,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest, HTTPRequests) {
// Tests that remote config can be applied after the serialized config has been
// applied.
TEST_F(DataReductionProxyConfigServiceClientTest, ApplySerializedConfig) {
- Init(true, false, std::string());
+ Init(true);
AddMockSuccess();
SetDataReductionProxyEnabled(true, true);
@@ -982,7 +878,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest, ApplySerializedConfig) {
// secure proxies are not used.
TEST_F(DataReductionProxyConfigServiceClientTest,
ApplySerializedConfigWithSecureTransportRestricted) {
- Init(true, false, std::string());
+ Init(true);
AddMockSuccess();
@@ -1001,7 +897,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
// retrieved successfully.
TEST_F(DataReductionProxyConfigServiceClientTest,
ApplySerializedConfigAfterReceipt) {
- Init(true, false, std::string());
+ Init(true);
AddMockSuccess();
SetDataReductionProxyEnabled(true, true);
@@ -1022,7 +918,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
// Tests that a local serialized config can be applied successfully if remote
// config has not been fetched so far.
TEST_F(DataReductionProxyConfigServiceClientTest, ApplySerializedConfigLocal) {
- Init(true, false, std::string());
+ Init(true);
SetDataReductionProxyEnabled(true, true);
EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
EXPECT_TRUE(request_options()->GetSecureSession().empty());
@@ -1043,7 +939,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest, ApplySerializedConfigLocal) {
// correctly to 0.0f.
TEST_F(DataReductionProxyConfigServiceClientTest,
ApplySerializedConfigZeroReportingFraction) {
- Init(true, false, std::string());
+ Init(true);
// ApplySerializedConfig should apply the encoded config.
config_client()->ApplySerializedConfig(
zero_reporting_fraction_encoded_config());
@@ -1054,7 +950,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
// correctly to 0.0f when the pingback is not set in the protobuf.
TEST_F(DataReductionProxyConfigServiceClientTest,
ApplySerializedConfigEmptyReportingFraction) {
- Init(true, false, std::string());
+ Init(true);
// ApplySerializedConfig should apply the encoded config.
config_client()->ApplySerializedConfig(
empty_reporting_fraction_encoded_config());
@@ -1065,7 +961,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
// correctly to 1.0f.
TEST_F(DataReductionProxyConfigServiceClientTest,
ApplySerializedConfigOneReportingFraction) {
- Init(true, false, std::string());
+ Init(true);
// ApplySerializedConfig should apply the encoded config.
config_client()->ApplySerializedConfig(
one_reporting_fraction_encoded_config());
@@ -1076,7 +972,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
// correctly to 0.5f.
TEST_F(DataReductionProxyConfigServiceClientTest,
ApplySerializedConfigHalfReportingFraction) {
- Init(true, false, std::string());
+ Init(true);
// ApplySerializedConfig should apply the encoded config.
config_client()->ApplySerializedConfig(
half_reporting_fraction_encoded_config());
@@ -1087,7 +983,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
// Verifies the correctness of fetching config when Chromium is in background
// and foreground.
TEST_F(DataReductionProxyConfigServiceClientTest, FetchConfigOnForeground) {
- Init(true, false, std::string());
+ Init(true);
SetDataReductionProxyEnabled(true, true);
{
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
index 7b55b9be80c..86dafdfc9d6 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
@@ -33,9 +33,8 @@ TestDataReductionProxyConfig::TestDataReductionProxyConfig(
DataReductionProxyConfigurator* configurator,
DataReductionProxyEventCreator* event_creator)
: TestDataReductionProxyConfig(
- base::WrapUnique(
- new TestDataReductionProxyParams(params_flags,
- params_definitions)),
+ base::MakeUnique<TestDataReductionProxyParams>(params_flags,
+ params_definitions),
io_task_runner,
net_log,
configurator,
@@ -78,8 +77,8 @@ void TestDataReductionProxyConfig::GetNetworkList(
}
void TestDataReductionProxyConfig::ResetParamFlagsForTest(int flags) {
- config_values_ = base::WrapUnique(new TestDataReductionProxyParams(
- flags, TestDataReductionProxyParams::HAS_EVERYTHING));
+ config_values_ = base::MakeUnique<TestDataReductionProxyParams>(
+ flags, TestDataReductionProxyParams::HAS_EVERYTHING);
}
TestDataReductionProxyParams* TestDataReductionProxyConfig::test_params() {
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
index 23500fb8c90..94425c60ee8 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
@@ -23,6 +23,7 @@ class TickClock;
namespace net {
class NetworkQualityEstimator;
class NetLog;
+class ProxyServer;
}
namespace data_reduction_proxy {
@@ -133,7 +134,7 @@ class MockDataReductionProxyConfig : public TestDataReductionProxyConfig {
void(SecureProxyCheckFetchResult result));
MOCK_METHOD2(SetProxyPrefs, void(bool enabled, bool at_startup));
MOCK_CONST_METHOD2(IsDataReductionProxy,
- bool(const net::HostPortPair& host_port_pair,
+ bool(const net::ProxyServer& proxy_server,
DataReductionProxyTypeInfo* proxy_info));
MOCK_CONST_METHOD2(WasDataReductionProxyUsed,
bool(const net::URLRequest*,
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index 93b03c21dbd..5ac5a87d3cb 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -38,6 +38,7 @@
#include "net/base/net_errors.h"
#include "net/http/http_status_code.h"
#include "net/log/test_net_log.h"
+#include "net/nqe/effective_connection_type.h"
#include "net/nqe/external_estimate_provider.h"
#include "net/nqe/network_quality_estimator.h"
#include "net/proxy/proxy_server.h"
@@ -163,9 +164,9 @@ class DataReductionProxyConfigTest : public testing::Test {
std::unique_ptr<DataReductionProxyConfig> BuildConfig(
std::unique_ptr<DataReductionProxyParams> params) {
- return base::WrapUnique(new DataReductionProxyConfig(
+ return base::MakeUnique<DataReductionProxyConfig>(
task_runner(), test_context_->net_log(), std::move(params),
- test_context_->configurator(), test_context_->event_creator()));
+ test_context_->configurator(), test_context_->event_creator());
}
MockDataReductionProxyConfig* config() {
@@ -589,48 +590,39 @@ TEST_F(DataReductionProxyConfigTest, AreProxiesBypassedRetryDelay) {
TEST_F(DataReductionProxyConfigTest, IsDataReductionProxyWithParams) {
const struct {
- net::HostPortPair host_port_pair;
+ net::ProxyServer proxy_server;
bool fallback_allowed;
bool expected_result;
- net::HostPortPair expected_first;
- net::HostPortPair expected_second;
+ net::ProxyServer expected_first;
+ net::ProxyServer expected_second;
bool expected_is_fallback;
} tests[] = {
{net::ProxyServer::FromURI(TestDataReductionProxyParams::DefaultOrigin(),
- net::ProxyServer::SCHEME_HTTP)
- .host_port_pair(),
+ net::ProxyServer::SCHEME_HTTP),
true, true,
net::ProxyServer::FromURI(TestDataReductionProxyParams::DefaultOrigin(),
- net::ProxyServer::SCHEME_HTTP)
- .host_port_pair(),
+ net::ProxyServer::SCHEME_HTTP),
net::ProxyServer::FromURI(
TestDataReductionProxyParams::DefaultFallbackOrigin(),
- net::ProxyServer::SCHEME_HTTP)
- .host_port_pair(),
+ net::ProxyServer::SCHEME_HTTP),
false},
{net::ProxyServer::FromURI(TestDataReductionProxyParams::DefaultOrigin(),
- net::ProxyServer::SCHEME_HTTP)
- .host_port_pair(),
+ net::ProxyServer::SCHEME_HTTP),
false, true,
net::ProxyServer::FromURI(TestDataReductionProxyParams::DefaultOrigin(),
- net::ProxyServer::SCHEME_HTTP)
- .host_port_pair(),
- net::HostPortPair::FromURL(GURL()), false},
+ net::ProxyServer::SCHEME_HTTP),
+ net::ProxyServer(), false},
{net::ProxyServer::FromURI(
TestDataReductionProxyParams::DefaultFallbackOrigin(),
- net::ProxyServer::SCHEME_HTTP)
- .host_port_pair(),
+ net::ProxyServer::SCHEME_HTTP),
true, true, net::ProxyServer::FromURI(
TestDataReductionProxyParams::DefaultFallbackOrigin(),
- net::ProxyServer::SCHEME_HTTP)
- .host_port_pair(),
- net::HostPortPair::FromURL(GURL()), true},
+ net::ProxyServer::SCHEME_HTTP),
+ net::ProxyServer(), true},
{net::ProxyServer::FromURI(
TestDataReductionProxyParams::DefaultFallbackOrigin(),
- net::ProxyServer::SCHEME_HTTP)
- .host_port_pair(),
- false, false, net::HostPortPair::FromURL(GURL()),
- net::HostPortPair::FromURL(GURL()), false},
+ net::ProxyServer::SCHEME_HTTP),
+ false, false, net::ProxyServer(), net::ProxyServer(), false},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
int flags = DataReductionProxyParams::kAllowed;
@@ -646,30 +638,23 @@ TEST_F(DataReductionProxyConfigTest, IsDataReductionProxyWithParams) {
event_creator()));
EXPECT_EQ(
tests[i].expected_result,
- config->IsDataReductionProxy(tests[i].host_port_pair, &proxy_type_info))
+ config->IsDataReductionProxy(tests[i].proxy_server, &proxy_type_info))
<< i;
- EXPECT_EQ(
- net::ProxyServer::FromURI(tests[i].expected_first.ToString(),
- net::ProxyServer::SCHEME_HTTP).is_valid(),
- proxy_type_info.proxy_servers.size() >= 1 &&
- proxy_type_info.proxy_servers[0].is_valid())
+ EXPECT_EQ(tests[i].expected_first.is_valid(),
+ proxy_type_info.proxy_servers.size() >= 1 &&
+ proxy_type_info.proxy_servers[0].is_valid())
<< i;
if (proxy_type_info.proxy_servers.size() >= 1 &&
proxy_type_info.proxy_servers[0].is_valid()) {
- EXPECT_TRUE(tests[i].expected_first.Equals(
- proxy_type_info.proxy_servers[0].host_port_pair()))
- << i;
+ EXPECT_EQ(tests[i].expected_first, proxy_type_info.proxy_servers[0]) << i;
}
- EXPECT_EQ(
- net::ProxyServer::FromURI(tests[i].expected_second.ToString(),
- net::ProxyServer::SCHEME_HTTP).is_valid(),
- proxy_type_info.proxy_servers.size() >= 2 &&
- proxy_type_info.proxy_servers[1].is_valid())
+ EXPECT_EQ(tests[i].expected_second.is_valid(),
+ proxy_type_info.proxy_servers.size() >= 2 &&
+ proxy_type_info.proxy_servers[1].is_valid())
<< i;
if (proxy_type_info.proxy_servers.size() >= 2 &&
proxy_type_info.proxy_servers[1].is_valid()) {
- EXPECT_TRUE(tests[i].expected_second.Equals(
- proxy_type_info.proxy_servers[1].host_port_pair()))
+ EXPECT_EQ(tests[i].expected_second, proxy_type_info.proxy_servers[1])
<< i;
}
@@ -687,35 +672,56 @@ TEST_F(DataReductionProxyConfigTest, IsDataReductionProxyWithMutableConfig) {
proxies_for_http.push_back(net::ProxyServer::FromURI(
"quic://anotherorigin.net:443", net::ProxyServer::SCHEME_HTTP));
const struct {
- net::HostPortPair host_port_pair;
+ net::ProxyServer proxy_server;
bool expected_result;
std::vector<net::ProxyServer> expected_proxies;
size_t expected_proxy_index;
} tests[] = {
{
- proxies_for_http[0].host_port_pair(), true,
+ proxies_for_http[0], true,
std::vector<net::ProxyServer>(proxies_for_http.begin(),
proxies_for_http.end()),
0,
},
{
- proxies_for_http[1].host_port_pair(), true,
+ proxies_for_http[1], true,
std::vector<net::ProxyServer>(proxies_for_http.begin() + 1,
proxies_for_http.end()),
1,
},
{
- proxies_for_http[2].host_port_pair(), true,
+ proxies_for_http[2], true,
std::vector<net::ProxyServer>(proxies_for_http.begin() + 2,
proxies_for_http.end()),
2,
},
{
- net::HostPortPair(), false, std::vector<net::ProxyServer>(), 0,
+ net::ProxyServer(), false, std::vector<net::ProxyServer>(), 0,
+ },
+ {
+ net::ProxyServer(
+ net::ProxyServer::SCHEME_HTTPS,
+ net::HostPortPair::FromString("otherorigin.net:443")),
+ false, std::vector<net::ProxyServer>(), 0,
+ },
+ {
+ // Verifies that when determining if a proxy is a valid data reduction
+ // proxy, only the host port pairs are compared.
+ net::ProxyServer::FromURI("origin.net:443",
+ net::ProxyServer::SCHEME_QUIC),
+ true, std::vector<net::ProxyServer>(proxies_for_http.begin(),
+ proxies_for_http.end()),
+ 0,
+ },
+ {
+ net::ProxyServer::FromURI("origin2.net:443",
+ net::ProxyServer::SCHEME_HTTPS),
+ false, std::vector<net::ProxyServer>(), 0,
},
{
- net::HostPortPair::FromString("https://otherorigin.net:443"), false,
- std::vector<net::ProxyServer>(), 0,
+ net::ProxyServer::FromURI("origin2.net:443",
+ net::ProxyServer::SCHEME_QUIC),
+ false, std::vector<net::ProxyServer>(), 0,
},
};
@@ -728,7 +734,7 @@ TEST_F(DataReductionProxyConfigTest, IsDataReductionProxyWithMutableConfig) {
for (const auto& test : tests) {
DataReductionProxyTypeInfo proxy_type_info;
EXPECT_EQ(test.expected_result, config->IsDataReductionProxy(
- test.host_port_pair, &proxy_type_info));
+ test.proxy_server, &proxy_type_info));
EXPECT_THAT(proxy_type_info.proxy_servers,
testing::ContainerEq(test.expected_proxies));
EXPECT_EQ(test.expected_proxy_index, proxy_type_info.proxy_index);
@@ -844,7 +850,8 @@ TEST_F(DataReductionProxyConfigTest, LoFiOn) {
net::TestDelegate delegate_;
std::unique_ptr<net::URLRequest> request =
context_.CreateRequest(GURL(), net::IDLE, &delegate_);
- request->SetLoadFlags(request->load_flags() | net::LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() |
+ net::LOAD_MAIN_FRAME_DEPRECATED);
bool should_enable_lofi = config()->ShouldEnableLoFiMode(*request.get());
if (tests[i].expect_bucket_count != 0) {
histogram_tester.ExpectBucketCount(
@@ -865,40 +872,35 @@ class TestNetworkQualityEstimator : public net::NetworkQualityEstimator {
: NetworkQualityEstimator(
std::unique_ptr<net::ExternalEstimateProvider>(),
variation_params),
- effective_connection_type_(
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
+ effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
recent_effective_connection_type_(
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {}
+ net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {}
~TestNetworkQualityEstimator() override {}
- EffectiveConnectionType GetEffectiveConnectionType() const override {
+ net::EffectiveConnectionType GetEffectiveConnectionType() const override {
return effective_connection_type_;
}
- EffectiveConnectionType GetRecentEffectiveConnectionType(
+ net::EffectiveConnectionType GetRecentEffectiveConnectionType(
const base::TimeTicks& start_time) const override {
return recent_effective_connection_type_;
}
void SetEffectiveConnectionType(
- net::NetworkQualityEstimator::EffectiveConnectionType
- effective_connection_type) {
+ net::EffectiveConnectionType effective_connection_type) {
effective_connection_type_ = effective_connection_type;
}
void SetRecentEffectiveConnectionType(
- net::NetworkQualityEstimator::EffectiveConnectionType
- recent_effective_connection_type) {
+ net::EffectiveConnectionType recent_effective_connection_type) {
recent_effective_connection_type_ = recent_effective_connection_type;
}
private:
// Estimate of the quality of the network.
- net::NetworkQualityEstimator::EffectiveConnectionType
- effective_connection_type_;
- net::NetworkQualityEstimator::EffectiveConnectionType
- recent_effective_connection_type_;
+ net::EffectiveConnectionType effective_connection_type_;
+ net::EffectiveConnectionType recent_effective_connection_type_;
base::TimeDelta rtt_since_;
};
@@ -944,9 +946,8 @@ TEST_F(DataReductionProxyConfigTest, AutoLoFiParams) {
};
for (size_t i = 0; i < arraysize(tests); ++i) {
- net::NetworkQualityEstimator::EffectiveConnectionType
- expected_effective_connection_type =
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+ net::EffectiveConnectionType expected_effective_connection_type =
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
int expected_hysteresis_sec = 360;
if (tests[i].lofi_flag_group) {
@@ -954,8 +955,7 @@ TEST_F(DataReductionProxyConfigTest, AutoLoFiParams) {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kDataReductionProxyLoFi,
switches::kDataReductionProxyLoFiValueSlowConnectionsOnly);
- expected_effective_connection_type =
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G;
+ expected_effective_connection_type = net::EFFECTIVE_CONNECTION_TYPE_2G;
expected_hysteresis_sec = 361;
}
@@ -979,7 +979,7 @@ TEST_F(DataReductionProxyConfigTest, AutoLoFiParams) {
// Network quality improved. However, network should still be marked as slow
// because of hysteresis.
test_network_quality_estimator.SetEffectiveConnectionType(
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND);
+ net::EFFECTIVE_CONNECTION_TYPE_4G);
EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
&test_network_quality_estimator));
@@ -1023,7 +1023,7 @@ TEST_F(DataReductionProxyConfigTest, AutoLoFiMissingParams) {
config.PopulateAutoLoFiParams();
- EXPECT_EQ(net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
config.lofi_effective_connection_type_threshold_);
EXPECT_EQ(base::TimeDelta::FromSeconds(60), config.auto_lofi_hysteresis_);
}
@@ -1039,9 +1039,8 @@ TEST_F(DataReductionProxyConfigTest, AutoLoFiParamsSlowConnectionsFlag) {
config.PopulateAutoLoFiParams();
- net::NetworkQualityEstimator::EffectiveConnectionType
- expected_effective_connection_type =
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+ net::EffectiveConnectionType expected_effective_connection_type =
+ net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
int hysteresis_sec = 60;
EXPECT_EQ(expected_effective_connection_type,
config.lofi_effective_connection_type_threshold_);
@@ -1054,14 +1053,14 @@ TEST_F(DataReductionProxyConfigTest, AutoLoFiParamsSlowConnectionsFlag) {
// Network is slow.
test_network_quality_estimator.SetEffectiveConnectionType(
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
&test_network_quality_estimator));
// Network quality improved. However, network should still be marked as slow
// because of hysteresis.
test_network_quality_estimator.SetEffectiveConnectionType(
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G);
+ net::EFFECTIVE_CONNECTION_TYPE_2G);
EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
&test_network_quality_estimator));
@@ -1075,7 +1074,7 @@ TEST_F(DataReductionProxyConfigTest, AutoLoFiParamsSlowConnectionsFlag) {
// Changing the network quality has no effect because of hysteresis.
test_network_quality_estimator.SetEffectiveConnectionType(
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
EXPECT_FALSE(config.IsNetworkQualityProhibitivelySlow(
&test_network_quality_estimator));
@@ -1113,37 +1112,30 @@ TEST_F(DataReductionProxyConfigTest, LoFiAccuracy) {
const struct {
std::string description;
std::string field_trial_group;
- net::NetworkQualityEstimator::EffectiveConnectionType
- effective_connection_type;
- net::NetworkQualityEstimator::EffectiveConnectionType
- recent_effective_connection_type;
+ net::EffectiveConnectionType effective_connection_type;
+ net::EffectiveConnectionType recent_effective_connection_type;
bool expect_network_quality_slow;
uint32_t bucket_to_check;
uint32_t expected_bucket_count;
} tests[] = {
{"Predicted slow, actually slow, Enabled group", "Enabled",
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, true, 0,
- 1},
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, true, 0, 1},
{"Predicted slow, actually slow, Enabled_NoControl group",
- "Enabled_NoControl",
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, true, 0,
- 1},
+ "Enabled_NoControl", net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, true, 0, 1},
{"Predicted slow, actually slow, Control group", "Control",
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, true, 0,
- 1},
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, true, 0, 1},
{"Predicted slow, actually not slow", "Enabled",
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G, true, 1, 1},
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ net::EFFECTIVE_CONNECTION_TYPE_2G, true, 1, 1},
{"Predicted not slow, actually slow", "Enabled",
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G,
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, false,
- 2, 1},
+ net::EFFECTIVE_CONNECTION_TYPE_2G,
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, false, 2, 1},
{"Predicted not slow, actually not slow", "Enabled",
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G,
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G, false, 3, 1},
+ net::EFFECTIVE_CONNECTION_TYPE_2G, net::EFFECTIVE_CONNECTION_TYPE_2G,
+ false, 3, 1},
};
for (const auto& test : tests) {
@@ -1220,9 +1212,9 @@ TEST_F(DataReductionProxyConfigTest, LoFiAccuracyNonZeroDelay) {
base::HistogramTester histogram_tester;
// Network was predicted to be slow and actually was slow.
test_network_quality_estimator.SetEffectiveConnectionType(
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
test_network_quality_estimator.SetRecentEffectiveConnectionType(
- net::NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
ASSERT_TRUE(config.IsNetworkQualityProhibitivelySlow(
&test_network_quality_estimator));
tick_clock->Advance(base::TimeDelta::FromSeconds(1));
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc
index 4a9ce2607d4..5452658353b 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc
@@ -12,7 +12,9 @@ const void* const kDataReductionProxyUserDataKey =
&kDataReductionProxyUserDataKey;
DataReductionProxyData::DataReductionProxyData()
- : used_data_reduction_proxy_(false), lofi_requested_(false) {}
+ : used_data_reduction_proxy_(false),
+ lofi_requested_(false),
+ effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {}
std::unique_ptr<DataReductionProxyData> DataReductionProxyData::DeepCopy()
const {
@@ -20,7 +22,8 @@ std::unique_ptr<DataReductionProxyData> DataReductionProxyData::DeepCopy()
copy->used_data_reduction_proxy_ = used_data_reduction_proxy_;
copy->lofi_requested_ = lofi_requested_;
copy->session_key_ = session_key_;
- copy->original_request_url_ = original_request_url_;
+ copy->request_url_ = request_url_;
+ copy->effective_connection_type_ = effective_connection_type_;
return copy;
}
@@ -43,4 +46,8 @@ DataReductionProxyData* DataReductionProxyData::GetDataAndCreateIfNecessary(
return data;
}
+void DataReductionProxyData::ClearData(net::URLRequest* request) {
+ request->RemoveUserData(kDataReductionProxyUserDataKey);
+}
+
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h
index 4e44d72f3fb..3b4b53f8546 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/supports_user_data.h"
+#include "net/nqe/effective_connection_type.h"
#include "url/gurl.h"
namespace net {
@@ -44,12 +45,24 @@ class DataReductionProxyData : public base::SupportsUserData::Data {
session_key_ = session_key;
}
- // The URL of the request before redirects.
- GURL original_request_url() const { return original_request_url_; }
- void set_original_request_url(const GURL& original_request_url) {
- original_request_url_ = original_request_url;
+ // The URL the frame is navigating to. This may change during the navigation
+ // when encountering a server redirect.
+ GURL request_url() const { return request_url_; }
+ void set_request_url(const GURL& request_url) { request_url_ = request_url; }
+
+ // The EffectiveConnectionType after the proxy is resolved. This is set for
+ // main frame requests only.
+ net::EffectiveConnectionType effective_connection_type() const {
+ return effective_connection_type_;
+ }
+ void set_effective_connection_type(
+ const net::EffectiveConnectionType& effective_connection_type) {
+ effective_connection_type_ = effective_connection_type;
}
+ // Removes |this| from |request|.
+ static void ClearData(net::URLRequest* request);
+
// Returns the Data from the URLRequest's UserData.
static DataReductionProxyData* GetData(const net::URLRequest& request);
// Returns the Data for a given URLRequest. If there is currently no
@@ -75,8 +88,13 @@ class DataReductionProxyData : public base::SupportsUserData::Data {
// The session key used for this request or navigation.
std::string session_key_;
- // The URL of the request before redirects.
- GURL original_request_url_;
+ // The URL the frame is navigating to. This may change during the navigation
+ // when encountering a server redirect.
+ GURL request_url_;
+
+ // The EffectiveConnectionType when the request or navigation starts. This is
+ // set for main frame requests only.
+ net::EffectiveConnectionType effective_connection_type_;
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyData);
};
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc
index e305178b5df..09aaaa199ba 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc
@@ -9,6 +9,7 @@
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "net/base/request_priority.h"
+#include "net/nqe/effective_connection_type.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -41,13 +42,18 @@ TEST_F(DataReductionProxyDataTest, BasicSettersAndGetters) {
EXPECT_FALSE(data->lofi_requested());
EXPECT_EQ(std::string(), data->session_key());
- EXPECT_EQ(GURL(std::string()), data->original_request_url());
+ EXPECT_EQ(GURL(std::string()), data->request_url());
std::string session_key = "test-key";
data->set_session_key(session_key);
EXPECT_EQ(session_key, data->session_key());
GURL test_url("test-url");
- data->set_original_request_url(test_url);
- EXPECT_EQ(test_url, data->original_request_url());
+ data->set_request_url(test_url);
+ EXPECT_EQ(test_url, data->request_url());
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+ data->effective_connection_type());
+ data->set_effective_connection_type(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
+ data->effective_connection_type());
}
TEST_F(DataReductionProxyDataTest, AddToURLRequest) {
@@ -56,12 +62,12 @@ TEST_F(DataReductionProxyDataTest, AddToURLRequest) {
GURL("http://www.google.com"), net::RequestPriority::IDLE, nullptr));
DataReductionProxyData* data =
DataReductionProxyData::GetData(*fake_request.get());
- EXPECT_TRUE(!data);
+ EXPECT_FALSE(data);
data =
DataReductionProxyData::GetDataAndCreateIfNecessary(fake_request.get());
- EXPECT_FALSE(!data);
+ EXPECT_TRUE(data);
data = DataReductionProxyData::GetData(*fake_request.get());
- EXPECT_FALSE(!data);
+ EXPECT_TRUE(data);
DataReductionProxyData* data2 =
DataReductionProxyData::GetDataAndCreateIfNecessary(fake_request.get());
EXPECT_EQ(data, data2);
@@ -93,15 +99,31 @@ TEST_F(DataReductionProxyDataTest, DeepCopy) {
data->set_used_data_reduction_proxy(tests[i].data_reduction_used);
data->set_lofi_requested(tests[i].lofi_on);
data->set_session_key(kSessionKey);
- data->set_original_request_url(kTestURL);
+ data->set_request_url(kTestURL);
+ data->set_effective_connection_type(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
std::unique_ptr<DataReductionProxyData> copy = data->DeepCopy();
EXPECT_EQ(tests[i].lofi_on, copy->lofi_requested());
EXPECT_EQ(tests[i].data_reduction_used, copy->used_data_reduction_proxy());
EXPECT_EQ(kSessionKey, copy->session_key());
- EXPECT_EQ(kTestURL, copy->original_request_url());
+ EXPECT_EQ(kTestURL, copy->request_url());
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
+ copy->effective_connection_type());
}
}
+TEST_F(DataReductionProxyDataTest, ClearData) {
+ std::unique_ptr<net::URLRequestContext> context(new net::URLRequestContext());
+ std::unique_ptr<net::URLRequest> fake_request(context->CreateRequest(
+ GURL("http://www.google.com"), net::RequestPriority::IDLE, nullptr));
+
+ DataReductionProxyData* data =
+ DataReductionProxyData::GetDataAndCreateIfNecessary(fake_request.get());
+ EXPECT_TRUE(data);
+ DataReductionProxyData::ClearData(fake_request.get());
+ data = DataReductionProxyData::GetData(*fake_request.get());
+ EXPECT_FALSE(data);
+}
+
} // namespace
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
index 4acb735e20f..72f9c2f7642 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -7,7 +7,6 @@
#include <cmath>
#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h"
@@ -19,11 +18,14 @@
#include "net/base/url_util.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
-#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_service.h"
namespace data_reduction_proxy {
+namespace {
+static const char kDataReductionCoreProxy[] = "proxy.googlezip.net";
+}
+
DataReductionProxyDelegate::DataReductionProxyDelegate(
DataReductionProxyConfig* config,
const DataReductionProxyConfigurator* configurator,
@@ -34,6 +36,7 @@ DataReductionProxyDelegate::DataReductionProxyDelegate(
configurator_(configurator),
event_creator_(event_creator),
bypass_stats_(bypass_stats),
+ alternative_proxies_broken_(false),
net_log_(net_log) {
DCHECK(config);
DCHECK(configurator);
@@ -48,12 +51,10 @@ DataReductionProxyDelegate::~DataReductionProxyDelegate() {
void DataReductionProxyDelegate::OnResolveProxy(
const GURL& url,
const std::string& method,
- int load_flags,
const net::ProxyService& proxy_service,
net::ProxyInfo* result) {
DCHECK(result);
- OnResolveProxyHandler(url, method, load_flags,
- configurator_->GetProxyConfig(),
+ OnResolveProxyHandler(url, method, configurator_->GetProxyConfig(),
proxy_service.proxy_retry_info(), config_, result);
}
@@ -66,7 +67,7 @@ void DataReductionProxyDelegate::OnTunnelConnectCompleted(
void DataReductionProxyDelegate::OnFallback(const net::ProxyServer& bad_proxy,
int net_error) {
if (bad_proxy.is_valid() &&
- config_->IsDataReductionProxy(bad_proxy.host_port_pair(), nullptr)) {
+ config_->IsDataReductionProxy(bad_proxy, nullptr)) {
event_creator_->AddProxyFallbackEvent(net_log_, bad_proxy.ToURI(),
net_error);
}
@@ -87,8 +88,7 @@ bool DataReductionProxyDelegate::IsTrustedSpdyProxy(
!proxy_server.is_valid()) {
return false;
}
- return config_ &&
- config_->IsDataReductionProxy(proxy_server.host_port_pair(), nullptr);
+ return config_ && config_->IsDataReductionProxy(proxy_server, nullptr);
}
void DataReductionProxyDelegate::OnTunnelHeadersReceived(
@@ -97,17 +97,110 @@ void DataReductionProxyDelegate::OnTunnelHeadersReceived(
const net::HttpResponseHeaders& response_headers) {
}
+void DataReductionProxyDelegate::GetAlternativeProxy(
+ const GURL& url,
+ const net::ProxyServer& resolved_proxy_server,
+ net::ProxyServer* alternative_proxy_server) const {
+ DCHECK(!alternative_proxy_server->is_valid());
+
+ if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS() ||
+ url.SchemeIsCryptographic()) {
+ return;
+ }
+
+ if (!params::IsIncludedInQuicFieldTrial())
+ return;
+
+ if (!resolved_proxy_server.is_valid() || !resolved_proxy_server.is_https())
+ return;
+
+ if (!config_ ||
+ !config_->IsDataReductionProxy(resolved_proxy_server, nullptr)) {
+ return;
+ }
+
+ if (alternative_proxies_broken_) {
+ RecordQuicProxyStatus(QUIC_PROXY_STATUS_MARKED_AS_BROKEN);
+ return;
+ }
+
+ if (!SupportsQUIC(resolved_proxy_server)) {
+ RecordQuicProxyStatus(QUIC_PROXY_NOT_SUPPORTED);
+ return;
+ }
+
+ *alternative_proxy_server = net::ProxyServer(
+ net::ProxyServer::SCHEME_QUIC, resolved_proxy_server.host_port_pair());
+ DCHECK(alternative_proxy_server->is_valid());
+ RecordQuicProxyStatus(QUIC_PROXY_STATUS_AVAILABLE);
+ return;
+}
+
+void DataReductionProxyDelegate::OnAlternativeProxyBroken(
+ const net::ProxyServer& alternative_proxy_server) {
+ // TODO(tbansal): Reset this on connection change events.
+ // Currently, DataReductionProxyDelegate does not maintain a list of broken
+ // proxies. If one alternative proxy is broken, use of all alternative proxies
+ // is disabled because it is likely that other QUIC proxies would be
+ // broken too.
+ alternative_proxies_broken_ = true;
+ UMA_HISTOGRAM_COUNTS_100("DataReductionProxy.Quic.OnAlternativeProxyBroken",
+ 1);
+}
+
+net::ProxyServer DataReductionProxyDelegate::GetDefaultAlternativeProxy()
+ const {
+ if (!params::IsZeroRttQuicEnabled())
+ return net::ProxyServer();
+
+ if (alternative_proxies_broken_) {
+ RecordGetDefaultAlternativeProxy(DEFAULT_ALTERNATIVE_PROXY_STATUS_BROKEN);
+ return net::ProxyServer();
+ }
+
+ net::ProxyServer proxy_server(
+ net::ProxyServer::SCHEME_QUIC,
+ net::HostPortPair(kDataReductionCoreProxy, 443));
+ if (!config_ || !config_->IsDataReductionProxy(proxy_server, NULL)) {
+ RecordGetDefaultAlternativeProxy(
+ DEFAULT_ALTERNATIVE_PROXY_STATUS_UNAVAILABLE);
+ return net::ProxyServer();
+ }
+
+ RecordGetDefaultAlternativeProxy(DEFAULT_ALTERNATIVE_PROXY_STATUS_AVAILABLE);
+ return proxy_server;
+}
+
+bool DataReductionProxyDelegate::SupportsQUIC(
+ const net::ProxyServer& proxy_server) const {
+ // Enable QUIC for whitelisted proxies.
+ // TODO(tbansal): Use client config service to control this whitelist.
+ return proxy_server ==
+ net::ProxyServer(net::ProxyServer::SCHEME_HTTPS,
+ net::HostPortPair(kDataReductionCoreProxy, 443));
+}
+
+void DataReductionProxyDelegate::RecordQuicProxyStatus(
+ QuicProxyStatus status) const {
+ UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.Quic.ProxyStatus", status,
+ QUIC_PROXY_STATUS_BOUNDARY);
+}
+
+void DataReductionProxyDelegate::RecordGetDefaultAlternativeProxy(
+ DefaultAlternativeProxyStatus status) const {
+ UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.Quic.DefaultAlternativeProxy",
+ status, DEFAULT_ALTERNATIVE_PROXY_STATUS_BOUNDARY);
+}
+
void OnResolveProxyHandler(const GURL& url,
const std::string& method,
- int load_flags,
const net::ProxyConfig& data_reduction_proxy_config,
const net::ProxyRetryInfoMap& proxy_retry_info,
const DataReductionProxyConfig* config,
net::ProxyInfo* result) {
DCHECK(config);
DCHECK(result->is_empty() || result->is_direct() ||
- !config->IsDataReductionProxy(result->proxy_server().host_port_pair(),
- NULL));
+ !config->IsDataReductionProxy(result->proxy_server(), NULL));
if (!util::EligibleForDataReductionProxy(*result, url, method))
return;
net::ProxyInfo data_reduction_proxy_info;
@@ -116,8 +209,14 @@ void OnResolveProxyHandler(const GURL& url,
&data_reduction_proxy_info);
if (data_saver_proxy_used)
result->OverrideProxyList(data_reduction_proxy_info.proxy_list());
+
+ // The |data_reduction_proxy_config| must be valid otherwise the proxy
+ // cannot be used.
+ DCHECK(data_reduction_proxy_config.is_valid() || !data_saver_proxy_used);
+
if (config->enabled_by_user_and_reachable() && url.SchemeIsHTTPOrHTTPS() &&
- !url.SchemeIsCryptographic() && !net::IsLocalhost(url.host())) {
+ !url.SchemeIsCryptographic() && !net::IsLocalhost(url.host()) &&
+ (!data_reduction_proxy_config.is_valid() || data_saver_proxy_used)) {
UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.ConfigService.HTTPRequests",
data_saver_proxy_used);
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
index c0ea06bb6c2..e65a9a5caac 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "net/base/proxy_delegate.h"
#include "net/proxy/proxy_retry_info.h"
+#include "net/proxy/proxy_server.h"
#include "url/gurl.h"
namespace net {
@@ -19,7 +20,6 @@ class HttpResponseHeaders;
class NetLog;
class ProxyConfig;
class ProxyInfo;
-class ProxyServer;
class ProxyService;
class URLRequest;
}
@@ -48,7 +48,6 @@ class DataReductionProxyDelegate : public net::ProxyDelegate {
// net::ProxyDelegate implementation:
void OnResolveProxy(const GURL& url,
const std::string& method,
- int load_flags,
const net::ProxyService& proxy_service,
net::ProxyInfo* result) override;
void OnFallback(const net::ProxyServer& bad_proxy, int net_error) override;
@@ -63,11 +62,56 @@ class DataReductionProxyDelegate : public net::ProxyDelegate {
const net::HostPortPair& proxy_server,
const net::HttpResponseHeaders& response_headers) override;
+ protected:
+ // Protected so that these methods are accessible for testing.
+ // net::ProxyDelegate implementation:
+ void GetAlternativeProxy(
+ const GURL& url,
+ const net::ProxyServer& resolved_proxy_server,
+ net::ProxyServer* alternative_proxy_server) const override;
+ void OnAlternativeProxyBroken(
+ const net::ProxyServer& alternative_proxy_server) override;
+ net::ProxyServer GetDefaultAlternativeProxy() const override;
+
+ // Protected so that it can be overridden during testing.
+ // Returns true if |proxy_server| supports QUIC.
+ virtual bool SupportsQUIC(const net::ProxyServer& proxy_server) const;
+
+ // Availability status of data reduction QUIC proxy.
+ // Protected so that the enum values are accessible for testing.
+ enum QuicProxyStatus {
+ QUIC_PROXY_STATUS_AVAILABLE,
+ QUIC_PROXY_NOT_SUPPORTED,
+ QUIC_PROXY_STATUS_MARKED_AS_BROKEN,
+ QUIC_PROXY_STATUS_BOUNDARY
+ };
+
+ // Availability status of data reduction proxy that supports 0-RTT QUIC.
+ // Protected so that the enum values are accessible for testing.
+ enum DefaultAlternativeProxyStatus {
+ DEFAULT_ALTERNATIVE_PROXY_STATUS_AVAILABLE,
+ DEFAULT_ALTERNATIVE_PROXY_STATUS_BROKEN,
+ DEFAULT_ALTERNATIVE_PROXY_STATUS_UNAVAILABLE,
+ DEFAULT_ALTERNATIVE_PROXY_STATUS_BOUNDARY,
+ };
+
private:
+ // Records the availability status of data reduction proxy.
+ void RecordQuicProxyStatus(QuicProxyStatus status) const;
+
+ // Records the availability status of data reduction proxy that supports 0-RTT
+ // QUIC.
+ void RecordGetDefaultAlternativeProxy(
+ DefaultAlternativeProxyStatus status) const;
+
const DataReductionProxyConfig* config_;
const DataReductionProxyConfigurator* configurator_;
DataReductionProxyEventCreator* event_creator_;
DataReductionProxyBypassStats* bypass_stats_;
+
+ // True if the use of alternate proxies is disabled.
+ bool alternative_proxies_broken_;
+
net::NetLog* net_log_;
DISALLOW_COPY_AND_ASSIGN(DataReductionProxyDelegate);
@@ -80,7 +124,6 @@ class DataReductionProxyDelegate : public net::ProxyDelegate {
// This is visible for test purposes.
void OnResolveProxyHandler(const GURL& url,
const std::string& method,
- int load_flags,
const net::ProxyConfig& data_reduction_proxy_config,
const net::ProxyRetryInfoMap& proxy_retry_info,
const DataReductionProxyConfig* config,
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
index 4678e8e71f9..808943d6e80 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
@@ -29,14 +29,13 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
+#include "components/variations/variations_associated_data.h"
#include "net/base/host_port_pair.h"
-#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/proxy_delegate.h"
#include "net/http/http_request_headers.h"
@@ -67,12 +66,115 @@ net::ProxyServer GetProxyWithScheme(net::ProxyServer::Scheme scheme) {
case net::ProxyServer::SCHEME_QUIC:
return net::ProxyServer::FromURI("quic://origin.net:443",
net::ProxyServer::SCHEME_QUIC);
+ case net::ProxyServer::SCHEME_DIRECT:
+ return net::ProxyServer::FromURI("DIRECT",
+ net::ProxyServer::SCHEME_DIRECT);
default:
NOTREACHED();
return net::ProxyServer::FromURI("", net::ProxyServer::SCHEME_INVALID);
}
}
+class TestDataReductionProxyDelegate : public DataReductionProxyDelegate {
+ public:
+ TestDataReductionProxyDelegate(
+ DataReductionProxyConfig* config,
+ const DataReductionProxyConfigurator* configurator,
+ DataReductionProxyEventCreator* event_creator,
+ DataReductionProxyBypassStats* bypass_stats,
+ bool proxy_supports_quic,
+ net::NetLog* net_log)
+ : DataReductionProxyDelegate(config,
+ configurator,
+ event_creator,
+ bypass_stats,
+ net_log),
+ proxy_supports_quic_(proxy_supports_quic) {}
+
+ ~TestDataReductionProxyDelegate() override {}
+
+ bool SupportsQUIC(const net::ProxyServer& proxy_server) const override {
+ return proxy_supports_quic_;
+ }
+
+ // Verifies if the histograms related to use of QUIC proxy are recorded
+ // correctly.
+ void VerifyQuicHistogramCounts(const base::HistogramTester& histogram_tester,
+ bool expect_alternative_proxy_server,
+ bool supports_quic,
+ bool broken) const {
+ if (expect_alternative_proxy_server && !broken) {
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.Quic.ProxyStatus",
+ TestDataReductionProxyDelegate::QuicProxyStatus::
+ QUIC_PROXY_STATUS_AVAILABLE,
+ 1);
+ } else if (!supports_quic && !broken) {
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.Quic.ProxyStatus",
+ TestDataReductionProxyDelegate::QuicProxyStatus::
+ QUIC_PROXY_NOT_SUPPORTED,
+ 1);
+ } else {
+ ASSERT_TRUE(broken);
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.Quic.ProxyStatus",
+ TestDataReductionProxyDelegate::QuicProxyStatus::
+ QUIC_PROXY_STATUS_MARKED_AS_BROKEN,
+ 1);
+ }
+ }
+
+ void VerifyGetDefaultAlternativeProxyHistogram(
+ const base::HistogramTester& histogram_tester,
+ bool is_in_quic_field_trial,
+ bool use_proxyzip_proxy_as_first_proxy,
+ bool alternative_proxy_broken) {
+ static const char kHistogram[] =
+ "DataReductionProxy.Quic.DefaultAlternativeProxy";
+ if (is_in_quic_field_trial && use_proxyzip_proxy_as_first_proxy &&
+ !alternative_proxy_broken) {
+ histogram_tester.ExpectUniqueSample(
+ kHistogram,
+ TestDataReductionProxyDelegate::DefaultAlternativeProxyStatus::
+ DEFAULT_ALTERNATIVE_PROXY_STATUS_AVAILABLE,
+ 1);
+ return;
+ }
+
+ if (is_in_quic_field_trial && alternative_proxy_broken) {
+ histogram_tester.ExpectUniqueSample(
+ kHistogram,
+ TestDataReductionProxyDelegate::DefaultAlternativeProxyStatus::
+ DEFAULT_ALTERNATIVE_PROXY_STATUS_BROKEN,
+ 1);
+ return;
+ }
+
+ if (is_in_quic_field_trial && !use_proxyzip_proxy_as_first_proxy) {
+ histogram_tester.ExpectUniqueSample(
+ kHistogram,
+ TestDataReductionProxyDelegate::DefaultAlternativeProxyStatus::
+ DEFAULT_ALTERNATIVE_PROXY_STATUS_UNAVAILABLE,
+ 1);
+ return;
+ }
+
+ histogram_tester.ExpectTotalCount(kHistogram, 0);
+ }
+
+ using DataReductionProxyDelegate::GetAlternativeProxy;
+ using DataReductionProxyDelegate::OnAlternativeProxyBroken;
+ using DataReductionProxyDelegate::GetDefaultAlternativeProxy;
+ using DataReductionProxyDelegate::QuicProxyStatus;
+ using DataReductionProxyDelegate::DefaultAlternativeProxyStatus;
+
+ private:
+ const bool proxy_supports_quic_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDataReductionProxyDelegate);
+};
+
// Tests that the trusted SPDY proxy is verified correctly.
TEST(DataReductionProxyDelegate, IsTrustedSpdyProxy) {
base::MessageLoopForIO message_loop_;
@@ -87,7 +189,7 @@ TEST(DataReductionProxyDelegate, IsTrustedSpdyProxy) {
net::ProxyServer::Scheme first_proxy_scheme;
net::ProxyServer::Scheme second_proxy_scheme;
bool expect_proxy_is_trusted;
- } tests[] = {
+ } test_cases[] = {
{false, net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_INVALID,
false},
{true, net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_INVALID,
@@ -117,23 +219,22 @@ TEST(DataReductionProxyDelegate, IsTrustedSpdyProxy) {
{true, net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_HTTPS,
true},
};
- for (size_t i = 0; i < arraysize(tests); ++i) {
- ASSERT_EQ(
- tests[i].expect_proxy_is_trusted,
- tests[i].is_in_trusted_spdy_proxy_field_trial &&
- (tests[i].first_proxy_scheme == net::ProxyServer::SCHEME_HTTPS ||
- tests[i].second_proxy_scheme == net::ProxyServer::SCHEME_HTTPS))
- << i;
+ for (const auto& test : test_cases) {
+ ASSERT_EQ(test.expect_proxy_is_trusted,
+ test.is_in_trusted_spdy_proxy_field_trial &&
+ (test.first_proxy_scheme == net::ProxyServer::SCHEME_HTTPS ||
+ test.second_proxy_scheme == net::ProxyServer::SCHEME_HTTPS))
+ << (&test - test_cases);
std::vector<net::ProxyServer> proxies_for_http;
net::ProxyServer first_proxy;
net::ProxyServer second_proxy;
- if (tests[i].first_proxy_scheme != net::ProxyServer::SCHEME_INVALID) {
- first_proxy = GetProxyWithScheme(tests[i].first_proxy_scheme);
+ if (test.first_proxy_scheme != net::ProxyServer::SCHEME_INVALID) {
+ first_proxy = GetProxyWithScheme(test.first_proxy_scheme);
proxies_for_http.push_back(first_proxy);
}
- if (tests[i].second_proxy_scheme != net::ProxyServer::SCHEME_INVALID) {
- second_proxy = GetProxyWithScheme(tests[i].second_proxy_scheme);
+ if (test.second_proxy_scheme != net::ProxyServer::SCHEME_INVALID) {
+ second_proxy = GetProxyWithScheme(test.second_proxy_scheme);
proxies_for_http.push_back(second_proxy);
}
@@ -157,12 +258,309 @@ TEST(DataReductionProxyDelegate, IsTrustedSpdyProxy) {
base::FieldTrialList field_trial_list(nullptr);
base::FieldTrialList::CreateFieldTrial(
params::GetTrustedSpdyProxyFieldTrialName(),
- tests[i].is_in_trusted_spdy_proxy_field_trial ? "Enabled" : "Control");
+ test.is_in_trusted_spdy_proxy_field_trial ? "Enabled" : "Control");
- EXPECT_EQ(tests[i].expect_proxy_is_trusted,
+ EXPECT_EQ(test.expect_proxy_is_trusted,
delegate.IsTrustedSpdyProxy(first_proxy) ||
delegate.IsTrustedSpdyProxy(second_proxy))
- << i;
+ << (&test - test_cases);
+ }
+}
+
+// Verifies that DataReductionProxyDelegate correctly implements
+// alternative proxy functionality.
+TEST(DataReductionProxyDelegate, AlternativeProxy) {
+ base::MessageLoopForIO message_loop_;
+ std::unique_ptr<DataReductionProxyTestContext> test_context =
+ DataReductionProxyTestContext::Builder()
+ .WithConfigClient()
+ .WithMockDataReductionProxyService()
+ .Build();
+
+ const struct {
+ bool is_in_quic_field_trial;
+ bool proxy_supports_quic;
+ GURL gurl;
+ net::ProxyServer::Scheme first_proxy_scheme;
+ net::ProxyServer::Scheme second_proxy_scheme;
+ } tests[] = {
+ {false, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_DIRECT},
+ {false, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_HTTPS, net::ProxyServer::SCHEME_HTTP},
+ {true, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_DIRECT},
+ {true, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_DIRECT},
+ {true, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_DIRECT, net::ProxyServer::SCHEME_DIRECT},
+ {true, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_HTTPS, net::ProxyServer::SCHEME_DIRECT},
+ {true, true, GURL("https://www.example.com"),
+ net::ProxyServer::SCHEME_HTTPS, net::ProxyServer::SCHEME_DIRECT},
+ {true, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_DIRECT, net::ProxyServer::SCHEME_HTTPS},
+ {true, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_HTTPS, net::ProxyServer::SCHEME_HTTPS},
+ {true, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_HTTP, net::ProxyServer::SCHEME_HTTPS},
+ {true, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_HTTP},
+ {true, true, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_QUIC, net::ProxyServer::SCHEME_HTTPS},
+ {true, false, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_HTTPS, net::ProxyServer::SCHEME_HTTP},
+ {true, false, GURL("http://www.example.com"),
+ net::ProxyServer::SCHEME_HTTPS, net::ProxyServer::SCHEME_HTTPS}};
+ for (const auto test : tests) {
+ // True if there should exist a valid alternative proxy server corresponding
+ // to the first proxy in the list of proxies available to the data reduction
+ // proxy.
+ const bool expect_alternative_proxy_server_to_first_proxy =
+ test.is_in_quic_field_trial && test.proxy_supports_quic &&
+ !test.gurl.SchemeIsCryptographic() &&
+ test.first_proxy_scheme == net::ProxyServer::SCHEME_HTTPS;
+
+ // True if there should exist a valid alternative proxy server corresponding
+ // to the second proxy in the list of proxies available to the data
+ // reduction proxy.
+ const bool expect_alternative_proxy_server_to_second_proxy =
+ test.is_in_quic_field_trial && test.proxy_supports_quic &&
+ !test.gurl.SchemeIsCryptographic() &&
+ test.second_proxy_scheme == net::ProxyServer::SCHEME_HTTPS;
+
+ std::vector<net::ProxyServer> proxies_for_http;
+ net::ProxyServer first_proxy;
+ net::ProxyServer second_proxy;
+ if (test.first_proxy_scheme != net::ProxyServer::SCHEME_INVALID) {
+ first_proxy = GetProxyWithScheme(test.first_proxy_scheme);
+ proxies_for_http.push_back(first_proxy);
+ }
+ if (test.second_proxy_scheme != net::ProxyServer::SCHEME_INVALID) {
+ second_proxy = GetProxyWithScheme(test.second_proxy_scheme);
+ proxies_for_http.push_back(second_proxy);
+ }
+
+ std::unique_ptr<DataReductionProxyMutableConfigValues> config_values =
+ DataReductionProxyMutableConfigValues::CreateFromParams(
+ test_context->test_params());
+ config_values->UpdateValues(proxies_for_http);
+
+ std::unique_ptr<DataReductionProxyConfig> config(
+ new DataReductionProxyConfig(
+ message_loop_.task_runner(), test_context->net_log(),
+ std::move(config_values), test_context->configurator(),
+ test_context->event_creator()));
+
+ TestDataReductionProxyDelegate delegate(
+ config.get(), test_context->io_data()->configurator(),
+ test_context->io_data()->event_creator(),
+ test_context->io_data()->bypass_stats(), test.proxy_supports_quic,
+ test_context->io_data()->net_log());
+
+ base::FieldTrialList field_trial_list(nullptr);
+ base::FieldTrialList::CreateFieldTrial(
+ params::GetQuicFieldTrialName(),
+ test.is_in_quic_field_trial ? "Enabled" : "Control");
+
+ net::ProxyServer alternative_proxy_server_to_first_proxy;
+ net::ProxyServer alternative_proxy_server_to_second_proxy;
+
+ {
+ // Test if the alternative proxy is correctly set if the resolved proxy is
+ // |first_proxy|.
+ base::HistogramTester histogram_tester;
+ delegate.GetAlternativeProxy(test.gurl, first_proxy,
+ &alternative_proxy_server_to_first_proxy);
+ EXPECT_EQ(expect_alternative_proxy_server_to_first_proxy,
+ alternative_proxy_server_to_first_proxy.is_valid());
+
+ // Verify that the metrics are recorded correctly.
+ if (test.is_in_quic_field_trial && !test.gurl.SchemeIsCryptographic() &&
+ test.first_proxy_scheme == net::ProxyServer::SCHEME_HTTPS) {
+ delegate.VerifyQuicHistogramCounts(
+ histogram_tester, expect_alternative_proxy_server_to_first_proxy,
+ test.proxy_supports_quic, false);
+ } else {
+ histogram_tester.ExpectTotalCount("DataReductionProxy.Quic.ProxyStatus",
+ 0);
+ }
+ histogram_tester.ExpectTotalCount(
+ "DataReductionProxy.Quic.OnAlternativeProxyBroken", 0);
+ }
+
+ {
+ // Test if the alternative proxy is correctly set if the resolved proxy is
+ // |second_proxy|.
+ base::HistogramTester histogram_tester;
+ delegate.GetAlternativeProxy(test.gurl, second_proxy,
+ &alternative_proxy_server_to_second_proxy);
+ EXPECT_EQ(expect_alternative_proxy_server_to_first_proxy,
+ alternative_proxy_server_to_first_proxy.is_valid());
+ EXPECT_EQ(expect_alternative_proxy_server_to_second_proxy,
+ alternative_proxy_server_to_second_proxy.is_valid());
+
+ // Verify that the metrics are recorded correctly.
+ if (test.is_in_quic_field_trial && !test.gurl.SchemeIsCryptographic() &&
+ test.second_proxy_scheme == net::ProxyServer::SCHEME_HTTPS) {
+ delegate.VerifyQuicHistogramCounts(
+ histogram_tester, expect_alternative_proxy_server_to_second_proxy,
+ test.proxy_supports_quic, false);
+ } else {
+ histogram_tester.ExpectTotalCount("DataReductionProxy.Quic.ProxyStatus",
+ 0);
+ }
+ histogram_tester.ExpectTotalCount(
+ "DataReductionProxy.Quic.OnAlternativeProxyBroken", 0);
+ }
+
+ {
+ // Test if the alternative proxy is correctly set if the resolved proxy is
+ // a not a data reduction proxy.
+ base::HistogramTester histogram_tester;
+ net::ProxyServer alternative_proxy_server_to_non_data_reduction_proxy;
+ delegate.GetAlternativeProxy(
+ test.gurl,
+ net::ProxyServer::FromURI("not.data.reduction.proxy.net:443",
+ net::ProxyServer::SCHEME_HTTPS),
+ &alternative_proxy_server_to_non_data_reduction_proxy);
+ EXPECT_FALSE(
+ alternative_proxy_server_to_non_data_reduction_proxy.is_valid());
+
+ // Verify that the metrics are recorded correctly.
+ histogram_tester.ExpectTotalCount("DataReductionProxy.Quic.ProxyStatus",
+ 0);
+ histogram_tester.ExpectTotalCount(
+ "DataReductionProxy.Quic.OnAlternativeProxyBroken", 0);
+ }
+
+ // Test if the alternative proxy is correctly marked as broken.
+ if (expect_alternative_proxy_server_to_first_proxy) {
+ base::HistogramTester histogram_tester;
+ // Verify that when the alternative proxy server is reported as broken,
+ // then it is no longer returned when GetAlternativeProxy is called.
+ EXPECT_EQ(
+ first_proxy.host_port_pair().host(),
+ alternative_proxy_server_to_first_proxy.host_port_pair().host());
+ EXPECT_EQ(
+ first_proxy.host_port_pair().port(),
+ alternative_proxy_server_to_first_proxy.host_port_pair().port());
+ EXPECT_EQ(net::ProxyServer::SCHEME_QUIC,
+ alternative_proxy_server_to_first_proxy.scheme());
+
+ delegate.OnAlternativeProxyBroken(first_proxy);
+ alternative_proxy_server_to_first_proxy = net::ProxyServer();
+ delegate.GetAlternativeProxy(test.gurl, first_proxy,
+ &alternative_proxy_server_to_first_proxy);
+
+ delegate.VerifyQuicHistogramCounts(
+ histogram_tester, expect_alternative_proxy_server_to_first_proxy,
+ test.proxy_supports_quic, true);
+ histogram_tester.ExpectTotalCount(
+ "DataReductionProxy.Quic.OnAlternativeProxyBroken", 1);
+ EXPECT_FALSE(alternative_proxy_server_to_first_proxy.is_valid());
+ }
+ }
+}
+
+// Verifies that DataReductionProxyDelegate correctly returns the proxy server
+// that supports 0-RTT.
+TEST(DataReductionProxyDelegate, DefaultAlternativeProxyStatus) {
+ base::MessageLoopForIO message_loop_;
+ std::unique_ptr<DataReductionProxyTestContext> test_context =
+ DataReductionProxyTestContext::Builder()
+ .WithConfigClient()
+ .WithMockDataReductionProxyService()
+ .Build();
+
+ const struct {
+ bool is_in_quic_field_trial;
+ bool zero_rtt_param_set;
+ bool use_proxyzip_proxy_as_first_proxy;
+ } tests[] = {{false, false, false},
+ {false, false, true},
+ {true, false, false},
+ {true, false, true},
+ {true, true, true}};
+ for (const auto test : tests) {
+ std::vector<net::ProxyServer> proxies_for_http;
+ net::ProxyServer first_proxy;
+ net::ProxyServer second_proxy =
+ GetProxyWithScheme(net::ProxyServer::SCHEME_HTTP);
+
+ if (test.use_proxyzip_proxy_as_first_proxy) {
+ first_proxy =
+ net::ProxyServer(net::ProxyServer::SCHEME_QUIC,
+ net::HostPortPair("proxy.googlezip.net", 443));
+ } else {
+ first_proxy = GetProxyWithScheme(net::ProxyServer::SCHEME_HTTPS);
+ }
+
+ proxies_for_http.push_back(first_proxy);
+ proxies_for_http.push_back(second_proxy);
+
+ std::unique_ptr<DataReductionProxyMutableConfigValues> config_values =
+ DataReductionProxyMutableConfigValues::CreateFromParams(
+ test_context->test_params());
+ config_values->UpdateValues(proxies_for_http);
+
+ std::unique_ptr<DataReductionProxyConfig> config(
+ new DataReductionProxyConfig(
+ message_loop_.task_runner(), test_context->net_log(),
+ std::move(config_values), test_context->configurator(),
+ test_context->event_creator()));
+
+ TestDataReductionProxyDelegate delegate(
+ config.get(), test_context->io_data()->configurator(),
+ test_context->io_data()->event_creator(),
+ test_context->io_data()->bypass_stats(), true,
+ test_context->io_data()->net_log());
+
+ variations::testing::ClearAllVariationParams();
+ std::map<std::string, std::string> variation_params;
+ if (test.zero_rtt_param_set)
+ variation_params["enable_zero_rtt"] = "true";
+ ASSERT_TRUE(variations::AssociateVariationParams(
+ params::GetQuicFieldTrialName(),
+ test.is_in_quic_field_trial ? "Enabled" : "Control", variation_params));
+ base::FieldTrialList field_trial_list(nullptr);
+ base::FieldTrialList::CreateFieldTrial(
+ params::GetQuicFieldTrialName(),
+ test.is_in_quic_field_trial ? "Enabled" : "Control");
+
+ {
+ // Test if the QUIC supporting proxy is correctly set.
+ base::HistogramTester histogram_tester;
+ if (test.is_in_quic_field_trial && test.zero_rtt_param_set &&
+ test.use_proxyzip_proxy_as_first_proxy) {
+ EXPECT_EQ(delegate.GetDefaultAlternativeProxy(), first_proxy);
+ EXPECT_TRUE(first_proxy.is_quic());
+
+ } else {
+ EXPECT_FALSE(delegate.GetDefaultAlternativeProxy().is_valid());
+ }
+
+ delegate.VerifyGetDefaultAlternativeProxyHistogram(
+ histogram_tester,
+ test.is_in_quic_field_trial && test.zero_rtt_param_set,
+ test.use_proxyzip_proxy_as_first_proxy, false);
+ }
+
+ {
+ // Test if the QUIC supporting proxy is correctly set if the proxy is
+ // marked as broken.
+ base::HistogramTester histogram_tester;
+
+ if (test.is_in_quic_field_trial && test.zero_rtt_param_set &&
+ test.use_proxyzip_proxy_as_first_proxy) {
+ delegate.OnAlternativeProxyBroken(first_proxy);
+ EXPECT_FALSE(delegate.GetDefaultAlternativeProxy().is_quic());
+ delegate.VerifyGetDefaultAlternativeProxyHistogram(
+ histogram_tester,
+ test.is_in_quic_field_trial && test.zero_rtt_param_set,
+ test.use_proxyzip_proxy_as_first_proxy, true);
+ }
+ }
}
}
@@ -195,8 +593,7 @@ class TestLoFiUIService : public LoFiUIService {
TestLoFiUIService() {}
~TestLoFiUIService() override {}
- void OnLoFiReponseReceived(const net::URLRequest& request,
- bool is_preview) override {}
+ void OnLoFiReponseReceived(const net::URLRequest& request) override {}
};
class DataReductionProxyDelegateTest : public testing::Test {
@@ -281,8 +678,8 @@ class DataReductionProxyDelegateTest : public testing::Test {
context_.network_delegate());
std::unique_ptr<base::DictionaryValue> session_network_stats_info =
- base::DictionaryValue::From(base::WrapUnique(
- drp_network_delegate->SessionNetworkStatsInfoToValue()));
+ base::DictionaryValue::From(
+ drp_network_delegate->SessionNetworkStatsInfoToValue());
EXPECT_TRUE(session_network_stats_info);
std::string string_value;
@@ -303,7 +700,6 @@ class DataReductionProxyDelegateTest : public testing::Test {
};
TEST_F(DataReductionProxyDelegateTest, OnResolveProxyHandler) {
- int load_flags = net::LOAD_NORMAL;
GURL url("http://www.google.com/");
// Data reduction proxy info
@@ -350,7 +746,7 @@ TEST_F(DataReductionProxyDelegateTest, OnResolveProxyHandler) {
net::ProxyInfo result;
// Another proxy is used. It should be used afterwards.
result.Use(other_proxy_info);
- OnResolveProxyHandler(url, "GET", load_flags, data_reduction_proxy_config,
+ OnResolveProxyHandler(url, "GET", data_reduction_proxy_config,
empty_proxy_retry_info, config(), &result);
EXPECT_EQ(other_proxy_info.proxy_server(), result.proxy_server());
@@ -359,7 +755,7 @@ TEST_F(DataReductionProxyDelegateTest, OnResolveProxyHandler) {
// Another proxy is used. It should be used afterwards.
result.Use(direct_proxy_info);
net::ProxyConfig::ID prev_id = result.config_id();
- OnResolveProxyHandler(url, "GET", load_flags, data_reduction_proxy_config,
+ OnResolveProxyHandler(url, "GET", data_reduction_proxy_config,
empty_proxy_retry_info, config(), &result);
EXPECT_EQ(data_reduction_proxy_info.proxy_server(), result.proxy_server());
// Only the proxy list should be updated, not the proxy info.
@@ -369,7 +765,7 @@ TEST_F(DataReductionProxyDelegateTest, OnResolveProxyHandler) {
// list. A direct connection should be used afterwards.
result.Use(direct_proxy_info);
prev_id = result.config_id();
- OnResolveProxyHandler(GURL("ws://echo.websocket.org/"), "GET", load_flags,
+ OnResolveProxyHandler(GURL("ws://echo.websocket.org/"), "GET",
data_reduction_proxy_config,
data_reduction_proxy_retry_info, config(), &result);
EXPECT_TRUE(result.proxy_server().is_direct());
@@ -377,31 +773,31 @@ TEST_F(DataReductionProxyDelegateTest, OnResolveProxyHandler) {
// Test that ws:// and wss:// URLs bypass the data reduction proxy.
result.UseDirect();
- OnResolveProxyHandler(GURL("wss://echo.websocket.org/"), "GET", load_flags,
+ OnResolveProxyHandler(GURL("wss://echo.websocket.org/"), "GET",
data_reduction_proxy_config, empty_proxy_retry_info,
config(), &result);
EXPECT_TRUE(result.is_direct());
result.UseDirect();
- OnResolveProxyHandler(GURL("wss://echo.websocket.org/"), "GET", load_flags,
+ OnResolveProxyHandler(GURL("wss://echo.websocket.org/"), "GET",
data_reduction_proxy_config, empty_proxy_retry_info,
config(), &result);
EXPECT_TRUE(result.is_direct());
// POST methods go direct.
result.UseDirect();
- OnResolveProxyHandler(url, "POST", load_flags, data_reduction_proxy_config,
+ OnResolveProxyHandler(url, "POST", data_reduction_proxy_config,
empty_proxy_retry_info, config(), &result);
EXPECT_TRUE(result.is_direct());
// Without DataCompressionProxyCriticalBypass Finch trial set, the
// BYPASS_DATA_REDUCTION_PROXY load flag should be ignored.
result.UseDirect();
- OnResolveProxyHandler(url, "GET", load_flags, data_reduction_proxy_config,
+ OnResolveProxyHandler(url, "GET", data_reduction_proxy_config,
empty_proxy_retry_info, config(), &result);
EXPECT_FALSE(result.is_direct());
- OnResolveProxyHandler(url, "GET", load_flags, data_reduction_proxy_config,
+ OnResolveProxyHandler(url, "GET", data_reduction_proxy_config,
empty_proxy_retry_info, config(), &other_proxy_info);
EXPECT_FALSE(other_proxy_info.is_direct());
}
@@ -410,11 +806,11 @@ TEST_F(DataReductionProxyDelegateTest, OnResolveProxyHandler) {
// missing config are recorded properly.
TEST_F(DataReductionProxyDelegateTest, HTTPRequests) {
const struct {
- std::string url;
+ const char* url;
bool enabled_by_user;
bool use_direct_proxy;
bool expect_histogram;
- } tests[] = {
+ } test_cases[] = {
{
// Request should not be logged because data saver is disabled.
"http://www.example.com/", false, true, false,
@@ -442,16 +838,16 @@ TEST_F(DataReductionProxyDelegateTest, HTTPRequests) {
},
};
- for (size_t i = 0; i < arraysize(tests); ++i) {
- ASSERT_TRUE(tests[i].use_direct_proxy || tests[i].enabled_by_user);
- ASSERT_TRUE(tests[i].enabled_by_user || !tests[i].expect_histogram);
+ for (const auto& test : test_cases) {
+ ASSERT_TRUE(test.use_direct_proxy || test.enabled_by_user);
+ ASSERT_TRUE(test.enabled_by_user || !test.expect_histogram);
base::HistogramTester histogram_tester;
- GURL url(tests[i].url);
+ GURL url(test.url);
net::ProxyInfo data_reduction_proxy_info;
std::string data_reduction_proxy;
- if (!tests[i].use_direct_proxy) {
+ if (!test.use_direct_proxy) {
base::TrimString(params()->DefaultOrigin(), "/", &data_reduction_proxy);
data_reduction_proxy_info.UsePacString(
"PROXY " +
@@ -461,10 +857,10 @@ TEST_F(DataReductionProxyDelegateTest, HTTPRequests) {
.ToString() +
"; DIRECT");
}
- EXPECT_EQ(tests[i].use_direct_proxy, data_reduction_proxy_info.is_empty());
+ EXPECT_EQ(test.use_direct_proxy, data_reduction_proxy_info.is_empty());
net::ProxyConfig data_reduction_proxy_config;
- if (tests[i].use_direct_proxy) {
+ if (test.use_direct_proxy) {
data_reduction_proxy_config = net::ProxyConfig::CreateDirect();
} else {
@@ -472,7 +868,8 @@ TEST_F(DataReductionProxyDelegateTest, HTTPRequests) {
"http=" + data_reduction_proxy + ",direct://;");
data_reduction_proxy_config.set_id(1);
}
- config()->SetStateForTest(tests[i].enabled_by_user /* enabled */,
+ EXPECT_NE(test.use_direct_proxy, data_reduction_proxy_config.is_valid());
+ config()->SetStateForTest(test.enabled_by_user /* enabled */,
false /* at_startup */);
net::ProxyRetryInfoMap empty_proxy_retry_info;
@@ -483,35 +880,22 @@ TEST_F(DataReductionProxyDelegateTest, HTTPRequests) {
net::ProxyInfo result;
result.Use(direct_proxy_info);
- OnResolveProxyHandler(url, "GET", net::LOAD_NORMAL,
- data_reduction_proxy_config, empty_proxy_retry_info,
- config(), &result);
+ OnResolveProxyHandler(url, "GET", data_reduction_proxy_config,
+ empty_proxy_retry_info, config(), &result);
histogram_tester.ExpectTotalCount(
"DataReductionProxy.ConfigService.HTTPRequests",
- tests[i].expect_histogram ? 1 : 0);
+ test.expect_histogram ? 1 : 0);
- if (tests[i].expect_histogram) {
+ if (test.expect_histogram) {
histogram_tester.ExpectUniqueSample(
"DataReductionProxy.ConfigService.HTTPRequests",
- tests[i].use_direct_proxy ? 0 : 1, 1);
+ test.use_direct_proxy ? 0 : 1, 1);
}
}
}
-#if defined(OS_ANDROID)
-#define MAYBE_OnCompletedInternalLoFi DISABLED_OnCompletedInternalLoFi
-#else
-#define MAYBE_OnCompletedInternalLoFi OnCompletedInternalLoFi
-#endif
-
-#if defined(OS_ANDROID)
-#define MAYBE_OnCompletedInternalLoFiPreview \
- DISABLED_OnCompletedInternalLoFiPreview
-#else
-#define MAYBE_OnCompletedInternalLoFiPreview OnCompletedInternalLoFiPreview
-#endif
-
TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeFor200) {
+ base::HistogramTester histogram_tester;
int64_t baseline_received_bytes = total_received_bytes();
int64_t baseline_original_received_bytes = total_original_received_bytes();
@@ -538,6 +922,9 @@ TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeFor200) {
EXPECT_EQ(static_cast<int64_t>(raw_headers.size() +
10000 /* original_response_body */),
total_original_received_bytes() - baseline_original_received_bytes);
+
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
}
TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeFor304) {
@@ -589,10 +976,7 @@ TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeForReadError) {
int64_t baseline_received_bytes = total_received_bytes();
int64_t baseline_original_received_bytes = total_original_received_bytes();
- net::MockRead reads[] = {net::MockRead("HTTP/1.1 200 OK\r\n"
- "Via: 1.1 Chrome-Compression-Proxy\r\n"
- "X-Original-Content-Length: 10000\r\n"
- "Content-Length: 1000\r\n\r\n"),
+ net::MockRead reads[] = {net::MockRead("HTTP/1.1 "),
net::MockRead(net::ASYNC, net::ERR_ABORTED)};
net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
mock_socket_factory()->AddSocketDataProvider(&socket);
@@ -609,6 +993,110 @@ TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeForReadError) {
total_original_received_bytes() - baseline_original_received_bytes);
}
+TEST_F(DataReductionProxyDelegateTest, PartialRangeSavings) {
+ const struct {
+ std::string response_headers;
+ size_t received_content_length;
+ int64_t expected_original_content_length;
+ } test_cases[] = {
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Length: 1000\r\n"
+ "X-Original-Content-Length: 3000\r\n\r\n",
+ 100, 300},
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Length: 1000\r\n"
+ "X-Original-Content-Length: 1000\r\n\r\n",
+ 100, 100},
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Length: 3000\r\n"
+ "X-Original-Content-Length: 1000\r\n\r\n",
+ 300, 100},
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Length: 1000\r\n\r\n",
+ 100, 100},
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Length: 1000\r\n"
+ "X-Original-Content-Length: nonsense\r\n\r\n",
+ 100, 100},
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Length: 0\r\n"
+ "X-Original-Content-Length: 1000\r\n\r\n",
+ 0, 1000},
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "X-Original-Content-Length: 1000\r\n\r\n",
+ 100, 100},
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Length: nonsense\r\n"
+ "X-Original-Content-Length: 3000\r\n\r\n",
+ 100, 100},
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Length: 1000\r\n"
+ "X-Original-Content-Length: 0\r\n\r\n",
+ 100, 0},
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Length: 1000\r\n"
+ "X-Original-Content-Length: 0\r\n\r\n",
+ 0, 0},
+ {"HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n"
+ "Content-Length: " +
+ base::Int64ToString(static_cast<int64_t>(1) << 60) +
+ "\r\n"
+ "X-Original-Content-Length: " +
+ base::Int64ToString((static_cast<int64_t>(1) << 60) * 3) +
+ "\r\n\r\n",
+ 100, 300},
+ };
+
+ for (const auto& test : test_cases) {
+ base::HistogramTester histogram_tester;
+ int64_t baseline_received_bytes = total_received_bytes();
+ int64_t baseline_original_received_bytes = total_original_received_bytes();
+
+ std::string response_body(test.received_content_length, 'a');
+
+ net::MockRead reads[] = {
+ net::MockRead(net::ASYNC, test.response_headers.data(),
+ test.response_headers.size()),
+ net::MockRead(net::ASYNC, response_body.data(), response_body.size()),
+ net::MockRead(net::SYNCHRONOUS, net::ERR_ABORTED)};
+ net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
+ mock_socket_factory()->AddSocketDataProvider(&socket);
+
+ net::TestDelegate test_delegate;
+ std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
+ GURL("http://example.com"), net::IDLE, &test_delegate);
+ request->Start();
+
+ base::RunLoop().RunUntilIdle();
+
+ int64_t expected_original_size =
+ net::HttpUtil::AssembleRawHeaders(test.response_headers.data(),
+ test.response_headers.size())
+ .size() +
+ test.expected_original_content_length;
+
+ EXPECT_EQ(request->GetTotalReceivedBytes(),
+ total_received_bytes() - baseline_received_bytes)
+ << (&test - test_cases);
+ EXPECT_EQ(expected_original_size, total_original_received_bytes() -
+ baseline_original_received_bytes)
+ << (&test - test_cases);
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.ConfigService.HTTPRequests", 1, 1);
+ }
+}
+
} // namespace
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
index 95b485c32af..40d50fd359e 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
@@ -260,8 +260,7 @@ TEST_F(DataReductionProxyInterceptorWithServerTest, TestBypass) {
EXPECT_TRUE(request->is_pending());
base::RunLoop().Run();
- EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status());
- EXPECT_EQ(net::OK, request->status().error());
+ EXPECT_EQ(net::OK, delegate.request_status());
EXPECT_EQ("hello", delegate.data_received());
}
@@ -273,8 +272,7 @@ TEST_F(DataReductionProxyInterceptorWithServerTest, TestNoBypass) {
EXPECT_TRUE(request->is_pending());
base::RunLoop().Run();
- EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status());
- EXPECT_EQ(net::OK, request->status().error());
+ EXPECT_EQ(net::OK, delegate.request_status());
EXPECT_EQ("hello", delegate.data_received());
}
@@ -314,9 +312,7 @@ class DataReductionProxyInterceptorEndToEndTest : public testing::Test {
return request;
}
- const net::TestDelegate& delegate() const {
- return delegate_;
- }
+ const net::TestDelegate& delegate() const { return delegate_; }
net::MockClientSocketFactory* mock_socket_factory() {
return &mock_socket_factory_;
@@ -356,11 +352,10 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, ResponseWithoutRetry) {
std::unique_ptr<net::URLRequest> request =
CreateAndExecuteRequest(GURL("http://foo.com"));
- EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status());
+ EXPECT_EQ(net::OK, delegate().request_status());
EXPECT_EQ(200, request->GetResponseCode());
EXPECT_EQ(kBody, delegate().data_received());
- EXPECT_EQ(origin().host_port_pair().ToString(),
- request->proxy_server().ToString());
+ EXPECT_EQ(origin(), request->proxy_server());
}
TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithoutRetry) {
@@ -390,11 +385,10 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithoutRetry) {
std::unique_ptr<net::URLRequest> request =
CreateAndExecuteRequest(GURL("http://foo.com"));
- EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status());
+ EXPECT_EQ(net::OK, delegate().request_status());
EXPECT_EQ(200, request->GetResponseCode());
EXPECT_EQ(kBody, delegate().data_received());
- EXPECT_EQ(origin().host_port_pair().ToString(),
- request->proxy_server().ToString());
+ EXPECT_EQ(origin(), request->proxy_server());
// The redirect should have been processed and followed normally.
EXPECT_EQ(1, delegate().received_redirect_count());
}
@@ -425,7 +419,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, ResponseWithBypassAndRetry) {
std::unique_ptr<net::URLRequest> request =
CreateAndExecuteRequest(GURL("http://foo.com"));
- EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status());
+ EXPECT_EQ(net::OK, delegate().request_status());
EXPECT_EQ(200, request->GetResponseCode());
EXPECT_EQ(kBody, delegate().data_received());
EXPECT_FALSE(request->was_fetched_via_proxy());
@@ -462,8 +456,9 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithBypassAndRetry) {
};
std::vector<std::unique_ptr<net::SocketDataProvider>> socket_data_providers;
for (MockRead* mock_reads : mock_reads_array) {
- socket_data_providers.push_back(base::WrapUnique(
- new net::StaticSocketDataProvider(mock_reads, 3, nullptr, 0)));
+ socket_data_providers.push_back(
+ base::MakeUnique<net::StaticSocketDataProvider>(mock_reads, 3, nullptr,
+ 0));
mock_socket_factory()->AddSocketDataProvider(
socket_data_providers.back().get());
}
@@ -471,7 +466,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithBypassAndRetry) {
std::unique_ptr<net::URLRequest> request =
CreateAndExecuteRequest(GURL("http://foo.com"));
- EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status());
+ EXPECT_EQ(net::OK, delegate().request_status());
EXPECT_EQ(200, request->GetResponseCode());
EXPECT_EQ(kBody, delegate().data_received());
EXPECT_FALSE(request->was_fetched_via_proxy());
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
index 559e1393016..5ce71b4a3bc 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -4,6 +4,7 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
+#include <string>
#include <utility>
#include "base/bind.h"
@@ -29,7 +30,6 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
#include "net/base/load_flags.h"
-#include "net/log/net_log.h"
#include "net/url_request/http_user_agent_settings.h"
#include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request_context.h"
@@ -223,9 +223,9 @@ void DataReductionProxyIOData::SetPingbackReportingFraction(
std::unique_ptr<net::URLRequestInterceptor>
DataReductionProxyIOData::CreateInterceptor() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
- return base::WrapUnique(new DataReductionProxyInterceptor(
+ return base::MakeUnique<DataReductionProxyInterceptor>(
config_.get(), config_client_.get(), bypass_stats_.get(),
- event_creator_.get()));
+ event_creator_.get());
}
std::unique_ptr<DataReductionProxyNetworkDelegate>
@@ -250,9 +250,9 @@ DataReductionProxyIOData::CreateNetworkDelegate(
std::unique_ptr<DataReductionProxyDelegate>
DataReductionProxyIOData::CreateProxyDelegate() const {
DCHECK(io_task_runner_->BelongsToCurrentThread());
- return base::WrapUnique(new DataReductionProxyDelegate(
+ return base::MakeUnique<DataReductionProxyDelegate>(
config_.get(), configurator_.get(), event_creator_.get(),
- bypass_stats_.get(), net_log_));
+ bypass_stats_.get(), net_log_);
}
// TODO(kundaji): Rename this method to something more descriptive.
@@ -287,7 +287,7 @@ void DataReductionProxyIOData::SetDataReductionProxyConfiguration(
bool DataReductionProxyIOData::ShouldEnableLoFiMode(
const net::URLRequest& request) {
- DCHECK((request.load_flags() & net::LOAD_MAIN_FRAME) != 0);
+ DCHECK((request.load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) != 0);
if (!config_ || (config_->IsBypassedByDataReductionProxyLocalRules(
request, configurator_->GetProxyConfig()))) {
return false;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
index df76a35fd36..fc6c3ce5b35 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
@@ -23,6 +23,7 @@
#include "components/prefs/testing_pref_service.h"
#include "net/http/http_network_session.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h"
@@ -109,7 +110,6 @@ TEST_F(DataReductionProxyIODataTest, TestConstruction) {
io_data->basic_url_request_context_getter_.get()->GetURLRequestContext();
const net::HttpNetworkSession::Params* http_params =
request_context->GetNetworkSessionParams();
- EXPECT_FALSE(http_params->enable_spdy31);
EXPECT_FALSE(http_params->enable_http2);
EXPECT_FALSE(http_params->enable_quic);
@@ -138,8 +138,8 @@ TEST_F(DataReductionProxyIODataTest, TestConstruction) {
// Creating a second delegate with bypass statistics tracking should result
// in usage stats being created.
- io_data->CreateNetworkDelegate(
- base::WrapUnique(new CountingNetworkDelegate()), true);
+ io_data->CreateNetworkDelegate(base::MakeUnique<CountingNetworkDelegate>(),
+ true);
EXPECT_NE(nullptr, io_data->bypass_stats());
io_data->ShutdownOnUIThread();
@@ -167,13 +167,13 @@ TEST_F(DataReductionProxyIODataTest, TestResetBadProxyListOnDisableDataSaver) {
->proxy_service();
net::ProxyInfo proxy_info;
proxy_info.UseNamedProxy("http://foo2.com");
- net::BoundNetLog bound_net_log;
+ net::NetLogWithSource net_log_with_source;
const net::ProxyRetryInfoMap& bad_proxy_list =
proxy_service->proxy_retry_info();
// Simulate network error to add proxies to the bad proxy list.
proxy_service->MarkProxiesAsBadUntil(proxy_info, base::TimeDelta::FromDays(1),
- proxies, bound_net_log);
+ proxies, net_log_with_source);
base::RunLoop().RunUntilIdle();
// Verify that there are 2 proxies in the bad proxies list.
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc
index d8e632de59c..b9a4168edbc 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc
@@ -55,7 +55,8 @@ DataReductionProxyRequestType GetDataReductionProxyRequestType(
// due to other proxies overriding the Data Reduction Proxy, and bypasses due
// to local bypass rules.
if ((request.load_flags() & net::LOAD_BYPASS_PROXY) ||
- (!request.proxy_server().IsEmpty() &&
+ (request.proxy_server().is_valid() &&
+ !request.proxy_server().is_direct() &&
!config.IsDataReductionProxy(request.proxy_server(), NULL)) ||
config.IsBypassedByDataReductionProxyLocalRules(
request, data_reduction_proxy_config)) {
@@ -65,17 +66,4 @@ DataReductionProxyRequestType GetDataReductionProxyRequestType(
return UNKNOWN_TYPE;
}
-int64_t GetAdjustedOriginalContentLength(
- DataReductionProxyRequestType request_type,
- int64_t original_content_length,
- int64_t received_content_length) {
- // Since there was no indication of the original content length, presume
- // it is no different from the number of bytes read.
- if (original_content_length == -1 ||
- request_type != VIA_DATA_REDUCTION_PROXY) {
- return received_content_length;
- }
- return original_content_length;
-}
-
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h
index fb91fd35e01..57fdbe3b5f7 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h
@@ -5,11 +5,8 @@
#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_METRICS_H_
#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_METRICS_H_
-#include <stdint.h>
-
#include <vector>
-
namespace net {
class ProxyConfig;
class URLRequest;
@@ -19,10 +16,10 @@ class PrefService;
namespace data_reduction_proxy {
-typedef std::vector<long long> ContentLengthList;
-
class DataReductionProxyConfig;
+typedef std::vector<long long> ContentLengthList;
+
// A bypass delay more than this is treated as a long delay.
const int kLongBypassDelayInSeconds = 30 * 60;
@@ -38,13 +35,13 @@ static_assert(kNumDaysInHistorySummary <= kNumDaysInHistory,
enum DataReductionProxyRequestType {
VIA_DATA_REDUCTION_PROXY, // A request served by the data reduction proxy.
-
// Below are reasons why a request is not served by the enabled data reduction
// proxy. Off-the-record profile data is not counted in all cases.
- HTTPS, // An https request.
+ HTTPS, // An https request.
SHORT_BYPASS, // The client is bypassed by the proxy for a short time.
- LONG_BYPASS, // The client is bypassed by the proxy for a long time (due
- // to country bypass policy, for example).
+ LONG_BYPASS, // The client is bypassed by the proxy for a long time (due
+ // to country bypass policy, for example).
+ UPDATE, // An update to already counted request data.
UNKNOWN_TYPE, // Any other reason not listed above.
};
@@ -54,14 +51,6 @@ DataReductionProxyRequestType GetDataReductionProxyRequestType(
const net::ProxyConfig& data_reduction_proxy_config,
const DataReductionProxyConfig& config);
-// Returns |received_content_length| as adjusted original content length if
-// |original_content_length| has the invalid value (-1) or |request_type|
-// is not |VIA_DATA_REDUCTION_PROXY|.
-int64_t GetAdjustedOriginalContentLength(
- DataReductionProxyRequestType request_type,
- int64_t original_content_length,
- int64_t received_content_length);
-
} // namespace data_reduction_proxy
#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_METRICS_H_
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc
index d1f5ba39b93..8dd6bc18039 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc
@@ -14,7 +14,8 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
#include "net/base/load_flags.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/socket_test_util.h"
@@ -187,7 +188,8 @@ TEST(ChromeNetworkDailyDataSavingMetricsTest,
EXPECT_TRUE(context.proxy_service()->MarkProxiesAsBadUntil(
proxy_info, test_case.bypass_duration,
std::vector<net::ProxyServer>(),
- net::BoundNetLog::Make(context.net_log(), net::NetLog::SOURCE_NONE)));
+ net::NetLogWithSource::Make(context.net_log(),
+ net::NetLogSourceType::NONE)));
}
EXPECT_EQ(test_case.expected_request_type,
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index 85793f104b6..b45cd94e1ff 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -4,8 +4,10 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
+#include <limits>
#include <utility>
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
@@ -24,6 +26,7 @@
#include "net/base/load_flags.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
+#include "net/nqe/network_quality_estimator.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_service.h"
@@ -95,24 +98,71 @@ void RecordContentLengthHistograms(bool lofi_low_header_added,
received_content_length);
}
+// Scales |byte_count| by the ratio of |numerator|:|denomenator|.
+int64_t ScaleByteCountByRatio(int64_t byte_count,
+ int64_t numerator,
+ int64_t denomenator) {
+ DCHECK_LE(0, byte_count);
+ DCHECK_LE(0, numerator);
+ DCHECK_LT(0, denomenator);
+
+ // As an optimization, use integer arithmetic if it won't overflow.
+ if (byte_count <= std::numeric_limits<int32_t>::max() &&
+ numerator <= std::numeric_limits<int32_t>::max()) {
+ return byte_count * numerator / denomenator;
+ }
+
+ double scaled_byte_count = static_cast<double>(byte_count) *
+ static_cast<double>(numerator) /
+ static_cast<double>(denomenator);
+ if (scaled_byte_count >
+ static_cast<double>(std::numeric_limits<int64_t>::max())) {
+ // If this ever triggers, then byte counts can no longer be safely stored in
+ // 64-bit ints.
+ NOTREACHED();
+ return byte_count;
+ }
+ return static_cast<int64_t>(scaled_byte_count);
+}
+
+// Calculates the effective original content length of the |request|, accounting
+// for partial responses if necessary.
+int64_t CalculateEffectiveOCL(const net::URLRequest& request, int net_error) {
+ int64_t original_content_length_from_header =
+ request.response_headers()->GetInt64HeaderValue(
+ "x-original-content-length");
+
+ if (original_content_length_from_header < 0)
+ return request.received_response_content_length();
+ if (net_error == net::OK)
+ return original_content_length_from_header;
+
+ int64_t content_length_from_header =
+ request.response_headers()->GetContentLength();
+
+ if (content_length_from_header < 0)
+ return request.received_response_content_length();
+ if (content_length_from_header == 0)
+ return original_content_length_from_header;
+
+ return ScaleByteCountByRatio(request.received_response_content_length(),
+ original_content_length_from_header,
+ content_length_from_header);
+}
+
// Given a |request| that went through the Data Reduction Proxy, this function
// estimates how many bytes would have been received if the response had been
// received directly from the origin using HTTP/1.1 with a content length of
// |adjusted_original_content_length|.
-int64_t EstimateOriginalReceivedBytes(
- const net::URLRequest& request,
- int64_t adjusted_original_content_length) {
- DCHECK_LE(0, adjusted_original_content_length);
-
- if (!request.status().is_success() || request.was_cached() ||
- !request.response_headers()) {
+int64_t EstimateOriginalReceivedBytes(const net::URLRequest& request,
+ int net_error) {
+ if (request.was_cached() || !request.response_headers())
return request.GetTotalReceivedBytes();
- }
// TODO(sclittle): Remove headers added by Data Reduction Proxy when computing
// original size. http://crbug/535701.
return request.response_headers()->raw_headers().size() +
- adjusted_original_content_length;
+ CalculateEffectiveOCL(request, net_error);
}
} // namespace
@@ -148,15 +198,15 @@ void DataReductionProxyNetworkDelegate::InitIODataAndUMA(
data_reduction_proxy_bypass_stats_ = bypass_stats;
}
-base::Value*
+std::unique_ptr<base::Value>
DataReductionProxyNetworkDelegate::SessionNetworkStatsInfoToValue() const {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ auto dict = base::MakeUnique<base::DictionaryValue>();
// Use strings to avoid overflow. base::Value only supports 32-bit integers.
dict->SetString("session_received_content_length",
base::Int64ToString(total_received_bytes_));
dict->SetString("session_original_content_length",
base::Int64ToString(total_original_received_bytes_));
- return dict;
+ return std::move(dict);
}
void DataReductionProxyNetworkDelegate::OnBeforeURLRequestInternal(
@@ -175,7 +225,7 @@ void DataReductionProxyNetworkDelegate::OnBeforeURLRequestInternal(
// |data_reduction_proxy_io_data_| can be NULL for Webview.
if (data_reduction_proxy_io_data_ &&
- (request->load_flags() & net::LOAD_MAIN_FRAME)) {
+ (request->load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED)) {
data_reduction_proxy_io_data_->SetLoFiModeActiveOnMainFrame(false);
}
}
@@ -187,6 +237,10 @@ void DataReductionProxyNetworkDelegate::OnBeforeSendHeadersInternal(
net::HttpRequestHeaders* headers) {
DCHECK(data_reduction_proxy_config_);
DCHECK(request);
+
+ // If this is after a redirect, reset |request|'s DataReductionProxyData.
+ DataReductionProxyData::ClearData(request);
+
if (params::IsIncludedInHoldbackFieldTrial()) {
if (!WasEligibleWithoutHoldback(*request, proxy_info, proxy_retry_info))
return;
@@ -204,7 +258,7 @@ void DataReductionProxyNetworkDelegate::OnBeforeSendHeadersInternal(
if (proxy_info.proxy_server().host_port_pair().IsEmpty())
return;
if (!data_reduction_proxy_config_->IsDataReductionProxy(
- proxy_info.proxy_server().host_port_pair(), nullptr)) {
+ proxy_info.proxy_server(), nullptr)) {
return;
}
@@ -216,7 +270,13 @@ void DataReductionProxyNetworkDelegate::OnBeforeSendHeadersInternal(
data->set_used_data_reduction_proxy(true);
data->set_session_key(
data_reduction_proxy_request_options_->GetSecureSession());
- data->set_original_request_url(request->original_url());
+ data->set_request_url(request->url());
+ if ((request->load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) &&
+ request->context()->network_quality_estimator()) {
+ data->set_effective_connection_type(request->context()
+ ->network_quality_estimator()
+ ->GetEffectiveConnectionType());
+ }
}
if (data_reduction_proxy_io_data_ &&
@@ -225,7 +285,7 @@ void DataReductionProxyNetworkDelegate::OnBeforeSendHeadersInternal(
const bool is_using_lofi_mode =
lofi_decider->MaybeAddLoFiDirectiveToHeaders(*request, headers);
- if ((request->load_flags() & net::LOAD_MAIN_FRAME)) {
+ if ((request->load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED)) {
data_reduction_proxy_io_data_->SetLoFiModeActiveOnMainFrame(
is_using_lofi_mode);
}
@@ -243,29 +303,31 @@ void DataReductionProxyNetworkDelegate::OnCompletedInternal(
net::URLRequest* request,
bool started) {
DCHECK(request);
+ // TODO(maksims): remove this once OnCompletedInternal() has net_error in
+ // arguments.
+ int net_error = request->status().error();
+ DCHECK_NE(net::ERR_IO_PENDING, net_error);
if (data_reduction_proxy_bypass_stats_)
- data_reduction_proxy_bypass_stats_->OnUrlRequestCompleted(request, started);
+ data_reduction_proxy_bypass_stats_->OnUrlRequestCompleted(request, started,
+ net_error);
net::HttpRequestHeaders request_headers;
if (data_reduction_proxy_io_data_ && request->response_headers() &&
request->response_headers()->HasHeaderValue(
chrome_proxy_header(), chrome_proxy_lo_fi_directive())) {
data_reduction_proxy_io_data_->lofi_ui_service()->OnLoFiReponseReceived(
- *request, false);
+ *request);
} else if (data_reduction_proxy_io_data_ && request->response_headers() &&
request->response_headers()->HasHeaderValue(
- chrome_proxy_header(),
- chrome_proxy_lo_fi_preview_directive())) {
- data_reduction_proxy_io_data_->lofi_ui_service()->OnLoFiReponseReceived(
- *request, true);
- RecordLoFiTransformationType(PREVIEW);
+ chrome_proxy_header(), chrome_proxy_lite_page_directive())) {
+ RecordLitePageTransformationType(LITE_PAGE);
} else if (request->GetFullRequestHeaders(&request_headers) &&
request_headers.HasHeader(chrome_proxy_header())) {
std::string header_value;
request_headers.GetHeader(chrome_proxy_header(), &header_value);
- if (header_value.find(chrome_proxy_lo_fi_preview_directive()) !=
+ if (header_value.find(chrome_proxy_lite_page_directive()) !=
std::string::npos) {
- RecordLoFiTransformationType(NO_TRANSFORMATION_PREVIEW_REQUESTED);
+ RecordLitePageTransformationType(NO_TRANSFORMATION_LITE_PAGE_REQUESTED);
}
}
@@ -285,7 +347,8 @@ void DataReductionProxyNetworkDelegate::OnCompletedInternal(
"x-original-content-length")
: -1;
- CalculateAndRecordDataUsage(*request, request_type, original_content_length);
+ CalculateAndRecordDataUsage(*request, request_type, original_content_length,
+ net_error);
RecordContentLength(*request, request_type, original_content_length);
}
@@ -293,20 +356,17 @@ void DataReductionProxyNetworkDelegate::OnCompletedInternal(
void DataReductionProxyNetworkDelegate::CalculateAndRecordDataUsage(
const net::URLRequest& request,
DataReductionProxyRequestType request_type,
- int64_t original_content_length) {
+ int64_t original_content_length,
+ int net_error) {
DCHECK_LE(-1, original_content_length);
int64_t data_used = request.GetTotalReceivedBytes();
// Estimate how many bytes would have been used if the DataReductionProxy was
// not used, and record the data usage.
int64_t original_size = data_used;
- if (request_type == VIA_DATA_REDUCTION_PROXY && request.response_headers() &&
- !request.was_cached() && request.status().is_success()) {
- original_size = EstimateOriginalReceivedBytes(
- request, GetAdjustedOriginalContentLength(
- request_type, original_content_length,
- request.received_response_content_length()));
- }
+
+ if (request_type == VIA_DATA_REDUCTION_PROXY)
+ original_size = EstimateOriginalReceivedBytes(request, net_error);
std::string mime_type;
if (request.response_headers())
@@ -370,10 +430,10 @@ void DataReductionProxyNetworkDelegate::RecordContentLength(
}
}
-void DataReductionProxyNetworkDelegate::RecordLoFiTransformationType(
- LoFiTransformationType type) {
+void DataReductionProxyNetworkDelegate::RecordLitePageTransformationType(
+ LitePageTransformationType type) {
UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.LoFi.TransformationType", type,
- LO_FI_TRANSFORMATION_TYPES_INDEX_BOUNDARY);
+ LITE_PAGE_TRANSFORMATION_TYPES_INDEX_BOUNDARY);
}
bool DataReductionProxyNetworkDelegate::WasEligibleWithoutHoldback(
@@ -382,7 +442,7 @@ bool DataReductionProxyNetworkDelegate::WasEligibleWithoutHoldback(
const net::ProxyRetryInfoMap& proxy_retry_info) const {
DCHECK(proxy_info.is_empty() || proxy_info.is_direct() ||
!data_reduction_proxy_config_->IsDataReductionProxy(
- proxy_info.proxy_server().host_port_pair(), nullptr));
+ proxy_info.proxy_server(), nullptr));
if (!util::EligibleForDataReductionProxy(proxy_info, request.url(),
request.method())) {
return false;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
index 7787cd7f347..8f443da3d10 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
@@ -49,10 +49,10 @@ class DataUseGroup;
// This enum must remain synchronized with
// DataReductionProxyLoFiTransformationType in
// metrics/histograms/histograms.xml.
-enum LoFiTransformationType {
- PREVIEW = 0,
- NO_TRANSFORMATION_PREVIEW_REQUESTED,
- LO_FI_TRANSFORMATION_TYPES_INDEX_BOUNDARY,
+enum LitePageTransformationType {
+ LITE_PAGE = 0,
+ NO_TRANSFORMATION_LITE_PAGE_REQUESTED,
+ LITE_PAGE_TRANSFORMATION_TYPES_INDEX_BOUNDARY,
};
// DataReductionProxyNetworkDelegate is a LayeredNetworkDelegate that wraps a
@@ -83,9 +83,8 @@ class DataReductionProxyNetworkDelegate : public net::LayeredNetworkDelegate {
DataReductionProxyIOData* io_data,
DataReductionProxyBypassStats* bypass_stats);
- // Creates a |Value| summary of the state of the network session. The caller
- // is responsible for deleting the returned value.
- base::Value* SessionNetworkStatsInfoToValue() const;
+ // Creates a base::Value summary of the state of the network session.
+ std::unique_ptr<base::Value> SessionNetworkStatsInfoToValue() const;
void SetDataUseGroupProvider(
std::unique_ptr<DataUseGroupProvider> data_use_group_provider);
@@ -117,7 +116,8 @@ class DataReductionProxyNetworkDelegate : public net::LayeredNetworkDelegate {
// that the original content length of the response could not be determined.
void CalculateAndRecordDataUsage(const net::URLRequest& request,
DataReductionProxyRequestType request_type,
- int64_t original_content_length);
+ int64_t original_content_length,
+ int net_error);
// Posts to the UI thread to UpdateContentLengthPrefs in the data reduction
// proxy metrics and updates |received_content_length_| and
@@ -136,9 +136,9 @@ class DataReductionProxyNetworkDelegate : public net::LayeredNetworkDelegate {
DataReductionProxyRequestType request_type,
int64_t original_content_length);
- // Records UMA that counts how many pages were transformed by various Lo-Fi
- // transformations.
- void RecordLoFiTransformationType(LoFiTransformationType type);
+ // Records UMA that counts how many pages were transformed by various lite
+ // page transformations.
+ void RecordLitePageTransformationType(LitePageTransformationType type);
// Returns whether |request| would have used the data reduction proxy server
// if the holdback fieldtrial weren't enabled. |proxy_info| is the list of
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index 8d7bd69b293..93a796dee22 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <map>
#include <string>
#include <utility>
@@ -41,6 +42,8 @@
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
+#include "net/nqe/effective_connection_type.h"
+#include "net/nqe/network_quality_estimator.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_retry_info.h"
@@ -125,21 +128,39 @@ class TestLoFiDecider : public LoFiDecider {
class TestLoFiUIService : public LoFiUIService {
public:
- TestLoFiUIService() : on_lofi_response_(false), is_preview_(false) {}
+ TestLoFiUIService() : on_lofi_response_(false) {}
~TestLoFiUIService() override {}
bool DidNotifyLoFiResponse() const { return on_lofi_response_; }
- bool is_preview() const { return is_preview_; }
- void OnLoFiReponseReceived(const net::URLRequest& request,
- bool is_preview) override {
+ void OnLoFiReponseReceived(const net::URLRequest& request) override {
on_lofi_response_ = true;
- is_preview_ = is_preview;
}
private:
bool on_lofi_response_;
- bool is_preview_;
+};
+
+// Overrides net::NetworkQualityEstimator for testing.
+class TestNetworkQualityEstimator : public net::NetworkQualityEstimator {
+ public:
+ TestNetworkQualityEstimator(
+ const std::map<std::string, std::string>& variation_params,
+ net::EffectiveConnectionType effective_connection_type)
+ : NetworkQualityEstimator(
+ std::unique_ptr<net::ExternalEstimateProvider>(),
+ variation_params),
+ effective_connection_type_(effective_connection_type) {}
+
+ ~TestNetworkQualityEstimator() override {}
+
+ net::EffectiveConnectionType GetEffectiveConnectionType() const override {
+ return effective_connection_type_;
+ }
+
+ private:
+ // Estimate of the quality of the network.
+ net::EffectiveConnectionType effective_connection_type_;
};
class DataReductionProxyNetworkDelegateTest : public testing::Test {
@@ -189,17 +210,14 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
EXPECT_EQ(lofi_response, lofi_ui_service_->DidNotifyLoFiResponse());
}
- void VerifyLoFiPreviewResponse(bool is_preview) const {
- EXPECT_EQ(is_preview, lofi_ui_service_->is_preview());
- }
-
void VerifyDataReductionProxyData(const net::URLRequest& request,
bool data_reduction_proxy_used,
bool lofi_used) {
DataReductionProxyData* data = DataReductionProxyData::GetData(request);
if (!data_reduction_proxy_used) {
- EXPECT_EQ(nullptr, data);
+ EXPECT_FALSE(data);
} else {
+ EXPECT_TRUE(data->used_data_reduction_proxy());
EXPECT_EQ(lofi_used, data->lofi_requested());
}
}
@@ -271,8 +289,8 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
context_.network_delegate());
std::unique_ptr<base::DictionaryValue> session_network_stats_info =
- base::DictionaryValue::From(base::WrapUnique(
- drp_network_delegate->SessionNetworkStatsInfoToValue()));
+ base::DictionaryValue::From(
+ drp_network_delegate->SessionNetworkStatsInfoToValue());
EXPECT_TRUE(session_network_stats_info);
std::string string_value;
@@ -369,7 +387,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
std::unique_ptr<net::URLRequest> fake_request(FetchURLRequest(
GURL("http://www.google.com/"), nullptr, std::string(), 0));
- fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME);
+ fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
lofi_decider()->SetIsUsingLoFiMode(
config()->ShouldEnableLoFiMode(*fake_request.get()));
network_delegate()->NotifyBeforeSendHeaders(fake_request.get(),
@@ -426,7 +444,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
net::ProxyRetryInfoMap proxy_retry_info;
std::unique_ptr<net::URLRequest> fake_request(FetchURLRequest(
GURL("http://www.google.com/"), nullptr, std::string(), 0));
- fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME);
+ fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
lofi_decider()->SetIsUsingLoFiMode(false);
network_delegate()->NotifyBeforeSendHeaders(fake_request.get(),
data_reduction_proxy_info,
@@ -461,7 +479,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
net::ProxyRetryInfoMap proxy_retry_info;
std::unique_ptr<net::URLRequest> fake_request(FetchURLRequest(
GURL("http://www.google.com/"), nullptr, std::string(), 0));
- fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME);
+ fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
lofi_decider()->SetIsUsingLoFiMode(
config()->ShouldEnableLoFiMode(*fake_request.get()));
network_delegate()->NotifyBeforeSendHeaders(fake_request.get(),
@@ -480,23 +498,26 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
const struct {
bool lofi_on;
bool used_data_reduction_proxy;
+ bool main_frame;
} tests[] = {
- {
- // Lo-Fi off.
- false, true,
- },
- {
- // Data reduction proxy not used.
- false, false,
- },
- {
- // Data reduction proxy not used, Lo-Fi should not be used.
- true, false,
- },
- {
- // Lo-Fi on.
- true, true,
- },
+ // Lo-Fi off. Main Frame Request.
+ {false, true, true},
+ // Data reduction proxy not used. Main Frame Request.
+ {false, false, true},
+ // Data reduction proxy not used, Lo-Fi should not be used. Main Frame
+ // Request.
+ {true, false, true},
+ // Lo-Fi on. Main Frame Request.
+ {true, true, true},
+ // Lo-Fi off. Not a Main Frame Request.
+ {false, true, false},
+ // Data reduction proxy not used. Not a Main Frame Request.
+ {false, false, false},
+ // Data reduction proxy not used, Lo-Fi should not be used. Not a Main
+ // Frame Request.
+ {true, false, false},
+ // Lo-Fi on. Not a Main Frame Request.
+ {true, true, false},
};
for (const auto& test : tests) {
@@ -511,8 +532,16 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
net::HttpRequestHeaders headers;
net::ProxyRetryInfoMap proxy_retry_info;
+ std::map<std::string, std::string> network_quality_estimator_params;
+ TestNetworkQualityEstimator test_network_quality_estimator(
+ network_quality_estimator_params,
+ net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+ context()->set_network_quality_estimator(&test_network_quality_estimator);
+
std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
GURL("http://www.google.com/"), net::RequestPriority::IDLE, nullptr);
+ request->SetLoadFlags(test.main_frame ? net::LOAD_MAIN_FRAME_DEPRECATED
+ : 0);
lofi_decider()->SetIsUsingLoFiMode(test.lofi_on);
io_data()->request_options()->SetSecureSession("fake-session");
network_delegate()->NotifyBeforeSendHeaders(
@@ -523,8 +552,11 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
EXPECT_FALSE(data);
} else {
EXPECT_TRUE(data);
+ EXPECT_EQ(test.main_frame ? net::EFFECTIVE_CONNECTION_TYPE_OFFLINE
+ : net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+ data->effective_connection_type());
EXPECT_TRUE(data->used_data_reduction_proxy());
- EXPECT_EQ(GURL("http://www.google.com/"), data->original_request_url());
+ EXPECT_EQ(GURL("http://www.google.com/"), data->request_url());
EXPECT_EQ("fake-session", data->session_key());
EXPECT_EQ(test.lofi_on, data->lofi_requested());
}
@@ -578,6 +610,49 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
}
}
+TEST_F(DataReductionProxyNetworkDelegateTest, RedirectRequestDataCleared) {
+ net::ProxyInfo data_reduction_proxy_info;
+ std::string data_reduction_proxy;
+ base::TrimString(params()->DefaultOrigin(), "/", &data_reduction_proxy);
+ data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy);
+
+ // Main frame loaded. Lo-Fi should be used.
+ net::HttpRequestHeaders headers;
+ net::ProxyRetryInfoMap proxy_retry_info;
+
+ std::map<std::string, std::string> network_quality_estimator_params;
+ TestNetworkQualityEstimator test_network_quality_estimator(
+ network_quality_estimator_params, net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+ context()->set_network_quality_estimator(&test_network_quality_estimator);
+
+ std::unique_ptr<net::URLRequest> request = context()->CreateRequest(
+ GURL("http://www.google.com/"), net::RequestPriority::IDLE, nullptr);
+ request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
+ lofi_decider()->SetIsUsingLoFiMode(true);
+ io_data()->request_options()->SetSecureSession("fake-session");
+ network_delegate()->NotifyBeforeSendHeaders(
+ request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
+ DataReductionProxyData* data =
+ DataReductionProxyData::GetData(*request.get());
+
+ EXPECT_TRUE(data);
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
+ data->effective_connection_type());
+ EXPECT_TRUE(data->used_data_reduction_proxy());
+ EXPECT_EQ(GURL("http://www.google.com/"), data->request_url());
+ EXPECT_EQ("fake-session", data->session_key());
+ EXPECT_TRUE(data->lofi_requested());
+
+ data_reduction_proxy_info.UseNamedProxy("port.of.other.proxy");
+
+ // Simulate a redirect by calling NotifyBeforeSendHeaders again with different
+ // proxy info.
+ network_delegate()->NotifyBeforeSendHeaders(
+ request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
+ data = DataReductionProxyData::GetData(*request.get());
+ EXPECT_FALSE(data);
+}
+
TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
const std::string kReceivedValidOCLHistogramName =
"Net.HttpContentLengthWithValidOCL";
@@ -621,7 +696,8 @@ TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
std::unique_ptr<net::URLRequest> fake_request(
FetchURLRequest(GURL("http://www.google.com/"), nullptr, response_headers,
kResponseContentLength));
- fake_request->SetLoadFlags(fake_request->load_flags() | net::LOAD_MAIN_FRAME);
+ fake_request->SetLoadFlags(fake_request->load_flags() |
+ net::LOAD_MAIN_FRAME_DEPRECATED);
base::TimeDelta freshness_lifetime =
fake_request->response_info().headers->GetFreshnessLifetimes(
@@ -655,7 +731,6 @@ TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
bool lofi_enabled_through_switch;
bool auto_lofi_enabled;
int expected_count;
-
} tests[] = {
{
// Lo-Fi disabled.
@@ -699,7 +774,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
fake_request = (FetchURLRequest(GURL("http://www.example.com/"), nullptr,
response_headers, kResponseContentLength));
fake_request->SetLoadFlags(fake_request->load_flags() |
- net::LOAD_MAIN_FRAME);
+ net::LOAD_MAIN_FRAME_DEPRECATED);
// Histograms are accumulative, so get the sum of all the tests so far.
int expected_count = 0;
@@ -754,34 +829,6 @@ TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedInternalLoFi) {
}
}
-TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedInternalLoFiPreview) {
- // Enable Lo-Fi.
- const struct {
- bool is_preview;
- } tests[] = {
- {false}, {true},
- };
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- std::string response_headers =
- "HTTP/1.1 200 OK\r\n"
- "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
- "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
- "Via: 1.1 Chrome-Compression-Proxy\r\n"
- "x-original-content-length: 200\r\n";
-
- if (tests[i].is_preview)
- response_headers += "Chrome-Proxy: q=preview\r\n";
-
- response_headers += "\r\n";
- FetchURLRequest(GURL("http://www.google.com/"), nullptr, response_headers,
- 140);
-
- VerifyDidNotifyLoFiResponse(tests[i].is_preview);
- VerifyLoFiPreviewResponse(tests[i].is_preview);
- }
-}
-
TEST_F(DataReductionProxyNetworkDelegateTest,
TestLoFiTransformationTypeHistogram) {
const char kLoFiTransformationTypeHistogram[] =
@@ -793,7 +840,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
FetchURLRequest(GURL("http://www.google.com/"), &request_headers,
std::string(), 140);
histogram_tester.ExpectBucketCount(kLoFiTransformationTypeHistogram,
- NO_TRANSFORMATION_PREVIEW_REQUESTED, 1);
+ NO_TRANSFORMATION_LITE_PAGE_REQUESTED, 1);
std::string response_headers =
"HTTP/1.1 200 OK\r\n"
@@ -807,8 +854,8 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
FetchURLRequest(GURL("http://www.google.com/"), nullptr, response_headers,
140);
- histogram_tester.ExpectBucketCount(kLoFiTransformationTypeHistogram, PREVIEW,
- 1);
+ histogram_tester.ExpectBucketCount(kLoFiTransformationTypeHistogram,
+ LITE_PAGE, 1);
}
} // namespace
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
index ece37b2f7ba..89717995175 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
@@ -4,15 +4,18 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/optional.h"
#include "base/rand_util.h"
+#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_util.h"
#include "components/data_reduction_proxy/proto/client_config.pb.h"
-#include "components/data_reduction_proxy/proto/pageload_metrics.pb.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
#include "net/base/load_flags.h"
+#include "net/nqe/effective_connection_type.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
@@ -27,43 +30,75 @@ static const char kHistogramSucceeded[] =
static const char kHistogramAttempted[] =
"DataReductionProxy.Pingback.Attempted";
-// Creates a PageloadMetrics protobuf for this page load and serializes to a
-// string.
-std::string SerializeData(const DataReductionProxyData& request_data,
- const DataReductionProxyPageLoadTiming& timing) {
- RecordPageloadMetricsRequest batched_request;
- PageloadMetrics* request = batched_request.add_pageloads();
+// Adds the relevant information to |request| for this page load based on page
+// timing and data reduction proxy state.
+void AddDataToPageloadMetrics(const DataReductionProxyData& request_data,
+ const DataReductionProxyPageLoadTiming& timing,
+ PageloadMetrics* request) {
request->set_session_key(request_data.session_key());
// For the timing events, any of them could be zero. Fill the message as a
// best effort.
request->set_allocated_first_request_time(
protobuf_parser::CreateTimestampFromTime(timing.navigation_start)
.release());
- if (request_data.original_request_url().is_valid())
- request->set_first_request_url(request_data.original_request_url().spec());
- if (!timing.first_contentful_paint.is_zero()) {
+ if (request_data.request_url().is_valid())
+ request->set_first_request_url(request_data.request_url().spec());
+ if (timing.first_contentful_paint) {
request->set_allocated_time_to_first_contentful_paint(
protobuf_parser::CreateDurationFromTimeDelta(
- timing.first_contentful_paint)
+ timing.first_contentful_paint.value())
.release());
}
- if (!timing.first_image_paint.is_zero()) {
+ if (timing.experimental_first_meaningful_paint) {
+ request->set_allocated_experimental_time_to_first_meaningful_paint(
+ protobuf_parser::CreateDurationFromTimeDelta(
+ timing.experimental_first_meaningful_paint.value())
+ .release());
+ }
+ if (timing.first_image_paint) {
request->set_allocated_time_to_first_image_paint(
- protobuf_parser::CreateDurationFromTimeDelta(timing.first_image_paint)
+ protobuf_parser::CreateDurationFromTimeDelta(
+ timing.first_image_paint.value())
.release());
}
- if (!timing.response_start.is_zero()) {
+ if (timing.response_start) {
request->set_allocated_time_to_first_byte(
- protobuf_parser::CreateDurationFromTimeDelta(timing.response_start)
+ protobuf_parser::CreateDurationFromTimeDelta(
+ timing.response_start.value())
.release());
}
- if (!timing.load_event_start.is_zero()) {
+ if (timing.load_event_start) {
request->set_allocated_page_load_time(
- protobuf_parser::CreateDurationFromTimeDelta(timing.load_event_start)
+ protobuf_parser::CreateDurationFromTimeDelta(
+ timing.load_event_start.value())
+ .release());
+ }
+ if (timing.parse_blocked_on_script_load_duration) {
+ request->set_allocated_parse_blocked_on_script_load_duration(
+ protobuf_parser::CreateDurationFromTimeDelta(
+ timing.parse_blocked_on_script_load_duration.value())
+ .release());
+ }
+ if (timing.parse_stop) {
+ request->set_allocated_parse_stop(
+ protobuf_parser::CreateDurationFromTimeDelta(timing.parse_stop.value())
.release());
}
+
+ request->set_effective_connection_type(
+ protobuf_parser::ProtoEffectiveConnectionTypeFromEffectiveConnectionType(
+ request_data.effective_connection_type()));
+}
+
+// Adds |current_time| as the metrics sent time to |request_data|, and returns
+// the serialized request.
+std::string AddTimeAndSerializeRequest(
+ RecordPageloadMetricsRequest* request_data,
+ base::Time current_time) {
+ request_data->set_allocated_metrics_sent_time(
+ protobuf_parser::CreateTimestampFromTime(current_time).release());
std::string serialized_request;
- batched_request.SerializeToString(&serialized_request);
+ request_data->SerializeToString(&serialized_request);
return serialized_request;
}
@@ -85,9 +120,8 @@ void DataReductionProxyPingbackClient::OnURLFetchComplete(
DCHECK(source == current_fetcher_.get());
UMA_HISTOGRAM_BOOLEAN(kHistogramSucceeded, source->GetStatus().is_success());
current_fetcher_.reset();
- while (!current_fetcher_ && !data_to_send_.empty()) {
- current_fetcher_ = MaybeCreateFetcherForDataAndStart(data_to_send_.front());
- data_to_send_.pop_front();
+ if (metrics_request_.pageloads_size() > 0) {
+ CreateFetcherForDataAndStart();
}
}
@@ -95,33 +129,37 @@ void DataReductionProxyPingbackClient::SendPingback(
const DataReductionProxyData& request_data,
const DataReductionProxyPageLoadTiming& timing) {
DCHECK(thread_checker_.CalledOnValidThread());
- std::string serialized_request = SerializeData(request_data, timing);
- if (current_fetcher_.get()) {
- data_to_send_.push_back(serialized_request);
- } else {
- DCHECK(data_to_send_.empty());
- current_fetcher_ = MaybeCreateFetcherForDataAndStart(serialized_request);
- }
-}
-
-std::unique_ptr<net::URLFetcher>
-DataReductionProxyPingbackClient::MaybeCreateFetcherForDataAndStart(
- const std::string& request_data) {
bool send_pingback = ShouldSendPingback();
UMA_HISTOGRAM_BOOLEAN(kHistogramAttempted, send_pingback);
if (!send_pingback)
- return nullptr;
- std::unique_ptr<net::URLFetcher> fetcher(
- net::URLFetcher::Create(pingback_url_, net::URLFetcher::POST, this));
- fetcher->SetLoadFlags(net::LOAD_BYPASS_PROXY);
- fetcher->SetUploadData("application/x-protobuf", request_data);
- fetcher->SetRequestContext(url_request_context_);
- // Configure max retries to be at most kMaxRetries times for 5xx errors.
+ return;
+ PageloadMetrics* pageload_metrics = metrics_request_.add_pageloads();
+ AddDataToPageloadMetrics(request_data, timing, pageload_metrics);
+ if (current_fetcher_.get())
+ return;
+ DCHECK_EQ(1, metrics_request_.pageloads_size());
+ CreateFetcherForDataAndStart();
+}
+
+void DataReductionProxyPingbackClient::CreateFetcherForDataAndStart() {
+ DCHECK(!current_fetcher_);
+ DCHECK_GE(metrics_request_.pageloads_size(), 1);
+ std::string serialized_request =
+ AddTimeAndSerializeRequest(&metrics_request_, CurrentTime());
+ metrics_request_.Clear();
+ current_fetcher_ =
+ net::URLFetcher::Create(pingback_url_, net::URLFetcher::POST, this);
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ current_fetcher_.get(),
+ data_use_measurement::DataUseUserData::DATA_REDUCTION_PROXY);
+ current_fetcher_->SetLoadFlags(net::LOAD_BYPASS_PROXY);
+ current_fetcher_->SetUploadData("application/x-protobuf", serialized_request);
+ current_fetcher_->SetRequestContext(url_request_context_);
+ // |current_fetcher_| should not retry on 5xx errors since the server may
+ // already be overloaded.
static const int kMaxRetries = 5;
- fetcher->SetMaxRetriesOn5xx(kMaxRetries);
- fetcher->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
- fetcher->Start();
- return fetcher;
+ current_fetcher_->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
+ current_fetcher_->Start();
}
bool DataReductionProxyPingbackClient::ShouldSendPingback() const {
@@ -129,6 +167,10 @@ bool DataReductionProxyPingbackClient::ShouldSendPingback() const {
GenerateRandomFloat() < pingback_reporting_fraction_;
}
+base::Time DataReductionProxyPingbackClient::CurrentTime() const {
+ return base::Time::Now();
+}
+
float DataReductionProxyPingbackClient::GenerateRandomFloat() const {
return static_cast<float>(base::RandDouble());
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h
index 7d9623c931a..a91a44cf0d9 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h
@@ -5,15 +5,19 @@
#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PINGBACK_CLIENT_H_
#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PINGBACK_CLIENT_H_
-#include <list>
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/threading/thread_checker.h"
+#include "components/data_reduction_proxy/proto/pageload_metrics.pb.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "url/gurl.h"
+namespace base {
+class Time;
+}
+
namespace net {
class URLFetcher;
class URLRequestContextGetter;
@@ -46,6 +50,9 @@ class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
// Generates a float in the range [0, 1). Virtualized in testing.
virtual float GenerateRandomFloat() const;
+ // Returns the current time. Virtualized in testing.
+ virtual base::Time CurrentTime() const;
+
private:
// URLFetcherDelegate implmentation:
void OnURLFetchComplete(const net::URLFetcher* source) override;
@@ -54,9 +61,10 @@ class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
bool ShouldSendPingback() const;
// Creates an URLFetcher that will POST to |secure_proxy_url_| using
- // |url_request_context_|. The max retires is set to 5.
- std::unique_ptr<net::URLFetcher> MaybeCreateFetcherForDataAndStart(
- const std::string& data);
+ // |url_request_context_|. The max retries is set to 5.
+ // |data_to_send_| will be used to fill the body of the Fetcher, and will be
+ // reset to an empty RecordPageloadMetricsRequest.
+ void CreateFetcherForDataAndStart();
net::URLRequestContextGetter* url_request_context_;
@@ -67,7 +75,7 @@ class DataReductionProxyPingbackClient : public net::URLFetcherDelegate {
std::unique_ptr<net::URLFetcher> current_fetcher_;
// Serialized data to send to the data saver proxy server.
- std::list<std::string> data_to_send_;
+ RecordPageloadMetricsRequest metrics_request_;
// The probability of sending a pingback to the server.
float pingback_reporting_fraction_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc
index 8131c02771f..4c6f3395a94 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client_unittest.cc
@@ -10,6 +10,7 @@
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
+#include "base/optional.h"
#include "base/test/histogram_tester.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
@@ -19,6 +20,7 @@
#include "components/data_reduction_proxy/proto/client_config.pb.h"
#include "components/data_reduction_proxy/proto/pageload_metrics.pb.h"
#include "net/base/net_errors.h"
+#include "net/nqe/effective_connection_type.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
@@ -46,13 +48,24 @@ class TestDataReductionProxyPingbackClient
net::URLRequestContextGetter* url_request_context_getter)
: DataReductionProxyPingbackClient(url_request_context_getter),
should_override_random_(false),
- override_value_(0.0f) {}
+ override_value_(0.0f),
+ current_time_(base::Time::Now()) {}
+ // Overrides the bahvior of the random float generator in
+ // DataReductionProxyPingbackClient.
+ // If |should_override_random| is true, the typically random value that is
+ // compared with reporting fraction will deterministically be
+ // |override_value|.
void OverrideRandom(bool should_override_random, float override_value) {
should_override_random_ = should_override_random;
override_value_ = override_value;
}
+ // Sets the time used for the metrics reporting time.
+ void set_current_time(base::Time current_time) {
+ current_time_ = current_time;
+ }
+
private:
float GenerateRandomFloat() const override {
if (should_override_random_)
@@ -60,18 +73,32 @@ class TestDataReductionProxyPingbackClient
return DataReductionProxyPingbackClient::GenerateRandomFloat();
}
+ base::Time CurrentTime() const override { return current_time_; }
+
bool should_override_random_;
float override_value_;
+ base::Time current_time_;
};
class DataReductionProxyPingbackClientTest : public testing::Test {
public:
DataReductionProxyPingbackClientTest()
- : timing_(base::Time::FromJsTime(1500),
- base::TimeDelta::FromMilliseconds(1600),
- base::TimeDelta::FromMilliseconds(1700),
- base::TimeDelta::FromMilliseconds(1800),
- base::TimeDelta::FromMilliseconds(1900)) {}
+ : timing_(
+ base::Time::FromJsTime(1500) /* navigation_start */,
+ base::Optional<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(1600)) /* response_start */,
+ base::Optional<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(1700)) /* load_event_start */,
+ base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
+ 1800)) /* first_image_paint */,
+ base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
+ 1900)) /* first_contentful_paint */,
+ base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
+ 2000)) /* experimental_first_meaningful_paint */,
+ base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
+ 100)) /* parse_blocked_on_script_load_duration */,
+ base::Optional<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(2000)) /* parse_stop */) {}
TestDataReductionProxyPingbackClient* pingback_client() const {
return pingback_client_.get();
@@ -88,7 +115,9 @@ class DataReductionProxyPingbackClientTest : public testing::Test {
void CreateAndSendPingback() {
DataReductionProxyData request_data;
request_data.set_session_key(kSessionKey);
- request_data.set_original_request_url(GURL(kFakeURL));
+ request_data.set_request_url(GURL(kFakeURL));
+ request_data.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
factory()->set_remove_fetcher_on_delete(true);
pingback_client()->SendPingback(request_data, timing_);
}
@@ -113,48 +142,137 @@ TEST_F(DataReductionProxyPingbackClientTest, VerifyPingbackContent) {
EXPECT_FALSE(factory()->GetFetcherByID(0));
pingback_client()->OverrideRandom(true, 0.5f);
pingback_client()->SetPingbackReportingFraction(1.0f);
+ base::Time current_time = base::Time::UnixEpoch();
+ pingback_client()->set_current_time(current_time);
CreateAndSendPingback();
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
RecordPageloadMetricsRequest batched_request;
batched_request.ParseFromString(test_fetcher->upload_data());
+ EXPECT_EQ(batched_request.pageloads_size(), 1);
+ EXPECT_EQ(current_time, protobuf_parser::TimestampToTime(
+ batched_request.metrics_sent_time()));
PageloadMetrics pageload_metrics = batched_request.pageloads(0);
EXPECT_EQ(
timing().navigation_start,
protobuf_parser::TimestampToTime(pageload_metrics.first_request_time()));
- EXPECT_EQ(timing().response_start,
+ EXPECT_EQ(timing().response_start.value(),
protobuf_parser::DurationToTimeDelta(
pageload_metrics.time_to_first_byte()));
- EXPECT_EQ(timing().load_event_start, protobuf_parser::DurationToTimeDelta(
- pageload_metrics.page_load_time()));
- EXPECT_EQ(timing().first_image_paint,
+ EXPECT_EQ(
+ timing().load_event_start.value(),
+ protobuf_parser::DurationToTimeDelta(pageload_metrics.page_load_time()));
+ EXPECT_EQ(timing().first_image_paint.value(),
protobuf_parser::DurationToTimeDelta(
pageload_metrics.time_to_first_image_paint()));
- EXPECT_EQ(timing().first_contentful_paint,
+ EXPECT_EQ(timing().first_contentful_paint.value(),
protobuf_parser::DurationToTimeDelta(
pageload_metrics.time_to_first_contentful_paint()));
+ EXPECT_EQ(
+ timing().experimental_first_meaningful_paint.value(),
+ protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.experimental_time_to_first_meaningful_paint()));
+ EXPECT_EQ(timing().parse_blocked_on_script_load_duration.value(),
+ protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.parse_blocked_on_script_load_duration()));
+ EXPECT_EQ(timing().parse_stop.value(), protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.parse_stop()));
EXPECT_EQ(kSessionKey, pageload_metrics.session_key());
EXPECT_EQ(kFakeURL, pageload_metrics.first_request_url());
+ EXPECT_EQ(
+ PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_OFFLINE,
+ pageload_metrics.effective_connection_type());
test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
histogram_tester().ExpectUniqueSample(kHistogramSucceeded, true, 1);
EXPECT_FALSE(factory()->GetFetcherByID(0));
}
-TEST_F(DataReductionProxyPingbackClientTest, SendTwoPingbacks) {
+TEST_F(DataReductionProxyPingbackClientTest, VerifyTwoPingbacksBatchedContent) {
Init();
EXPECT_FALSE(factory()->GetFetcherByID(0));
pingback_client()->OverrideRandom(true, 0.5f);
pingback_client()->SetPingbackReportingFraction(1.0f);
- CreateAndSendPingback();
+ base::Time current_time = base::Time::UnixEpoch();
+ pingback_client()->set_current_time(current_time);
+ // First pingback
CreateAndSendPingback();
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
+ // Two more pingbacks batched together.
+ CreateAndSendPingback();
+ histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 2);
+ CreateAndSendPingback();
+ histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 3);
+
+ // Ignore the first pingback.
net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
histogram_tester().ExpectUniqueSample(kHistogramSucceeded, true, 1);
+
+ // Check the state of the second pingback.
+ test_fetcher = factory()->GetFetcherByID(0);
+ EXPECT_EQ(test_fetcher->upload_content_type(), "application/x-protobuf");
+ RecordPageloadMetricsRequest batched_request;
+ batched_request.ParseFromString(test_fetcher->upload_data());
+ EXPECT_EQ(batched_request.pageloads_size(), 2);
+ EXPECT_EQ(current_time, protobuf_parser::TimestampToTime(
+ batched_request.metrics_sent_time()));
+
+ // Verify the content of both pingbacks.
+ for (size_t i = 0; i < 2; ++i) {
+ PageloadMetrics pageload_metrics = batched_request.pageloads(i);
+ EXPECT_EQ(timing().navigation_start,
+ protobuf_parser::TimestampToTime(
+ pageload_metrics.first_request_time()));
+ EXPECT_EQ(timing().response_start.value(),
+ protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.time_to_first_byte()));
+ EXPECT_EQ(timing().load_event_start.value(),
+ protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.page_load_time()));
+ EXPECT_EQ(timing().first_image_paint.value(),
+ protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.time_to_first_image_paint()));
+ EXPECT_EQ(timing().first_contentful_paint.value(),
+ protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.time_to_first_contentful_paint()));
+ EXPECT_EQ(
+ timing().experimental_first_meaningful_paint.value(),
+ protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.experimental_time_to_first_meaningful_paint()));
+ EXPECT_EQ(timing().parse_blocked_on_script_load_duration.value(),
+ protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.parse_blocked_on_script_load_duration()));
+ EXPECT_EQ(timing().parse_stop.value(), protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.parse_stop()));
+
+ EXPECT_EQ(kSessionKey, pageload_metrics.session_key());
+ EXPECT_EQ(kFakeURL, pageload_metrics.first_request_url());
+ EXPECT_EQ(
+ PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_OFFLINE,
+ pageload_metrics.effective_connection_type());
+ }
+
+ test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+ histogram_tester().ExpectUniqueSample(kHistogramSucceeded, true, 2);
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+}
+
+TEST_F(DataReductionProxyPingbackClientTest, SendTwoPingbacks) {
+ Init();
+ EXPECT_FALSE(factory()->GetFetcherByID(0));
+ pingback_client()->OverrideRandom(true, 0.5f);
+ pingback_client()->SetPingbackReportingFraction(1.0f);
+ CreateAndSendPingback();
+ histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 1);
+ CreateAndSendPingback();
histogram_tester().ExpectUniqueSample(kHistogramAttempted, true, 2);
+
+ net::TestURLFetcher* test_fetcher = factory()->GetFetcherByID(0);
+ test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+ histogram_tester().ExpectUniqueSample(kHistogramSucceeded, true, 1);
EXPECT_TRUE(factory()->GetFetcherByID(0));
test_fetcher = factory()->GetFetcherByID(0);
test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
index f9e43a2d350..167322ef7e5 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
@@ -101,7 +101,7 @@ void RegisterSyncableProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterInt64Pref(prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
registry->RegisterIntegerPref(prefs::kLoFiImplicitOptOutEpoch, 0);
- registry->RegisterIntegerPref(prefs::kLoFiSnackbarsShownPerSession, 0);
+ registry->RegisterIntegerPref(prefs::kLoFiUIShownPerSession, 0);
registry->RegisterIntegerPref(prefs::kLoFiLoadImagesPerSession, 0);
registry->RegisterIntegerPref(prefs::kLoFiConsecutiveSessionDisables, 0);
registry->RegisterBooleanPref(prefs::kLoFiWasUsedThisSession, false);
@@ -186,7 +186,7 @@ void RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterInt64Pref(
prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
registry->RegisterIntegerPref(prefs::kLoFiImplicitOptOutEpoch, 0);
- registry->RegisterIntegerPref(prefs::kLoFiSnackbarsShownPerSession, 0);
+ registry->RegisterIntegerPref(prefs::kLoFiUIShownPerSession, 0);
registry->RegisterIntegerPref(prefs::kLoFiLoadImagesPerSession, 0);
registry->RegisterIntegerPref(prefs::kLoFiConsecutiveSessionDisables, 0);
registry->RegisterBooleanPref(prefs::kLoFiWasUsedThisSession, false);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
index ac901dccdce..28e9cdb5580 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
@@ -223,15 +223,16 @@ void DataReductionProxyService::InitializeLoFiPrefs() {
SetLoFiModeOff();
} else if (prefs_->GetInteger(prefs::kLoFiLoadImagesPerSession) <
lo_fi_user_requests_for_images_per_session &&
- prefs_->GetInteger(prefs::kLoFiSnackbarsShownPerSession) >=
+ prefs_->GetInteger(prefs::kLoFiUIShownPerSession) >=
lo_fi_user_requests_for_images_per_session) {
// If the last session didn't have
// |lo_fi_user_requests_for_images_per_session|, but the user saw at least
- // that many "Load image" snackbars, reset the consecutive sessions count.
+ // that many "Load image" UI notifications, reset the consecutive sessions
+ // count.
prefs_->SetInteger(prefs::kLoFiConsecutiveSessionDisables, 0);
}
prefs_->SetInteger(prefs::kLoFiLoadImagesPerSession, 0);
- prefs_->SetInteger(prefs::kLoFiSnackbarsShownPerSession, 0);
+ prefs_->SetInteger(prefs::kLoFiUIShownPerSession, 0);
prefs_->SetBoolean(prefs::kLoFiWasUsedThisSession, false);
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
index 425a3a3b940..9114b69ae8e 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
@@ -174,7 +174,8 @@ void DataReductionProxySettings::SetLoFiModeActiveOnMainFrame(
}
bool DataReductionProxySettings::WasLoFiModeActiveOnMainFrame() const {
- return lo_fi_mode_active_;
+ return lo_fi_mode_active_ && !params::AreLitePagesEnabledViaFlags() &&
+ !params::IsIncludedInLitePageFieldTrial();
}
bool DataReductionProxySettings::WasLoFiLoadImageRequestedBefore() {
@@ -185,10 +186,9 @@ void DataReductionProxySettings::SetLoFiLoadImageRequested() {
lo_fi_load_image_requested_ = true;
}
-void DataReductionProxySettings::IncrementLoFiSnackbarShown() {
- prefs_->SetInteger(
- prefs::kLoFiSnackbarsShownPerSession,
- prefs_->GetInteger(prefs::kLoFiSnackbarsShownPerSession) + 1);
+void DataReductionProxySettings::IncrementLoFiUIShown() {
+ prefs_->SetInteger(prefs::kLoFiUIShownPerSession,
+ prefs_->GetInteger(prefs::kLoFiUIShownPerSession) + 1);
}
void DataReductionProxySettings::IncrementLoFiUserRequestsForImages() {
@@ -365,4 +365,15 @@ void DataReductionProxySettings::GetContentLengths(
days, original_content_length, received_content_length, last_update_time);
}
+bool DataReductionProxySettings::UpdateDataSavings(
+ const std::string& data_usage_host,
+ int64_t data_used,
+ int64_t original_size) {
+ if (!IsDataReductionProxyEnabled())
+ return false;
+ data_reduction_proxy_service_->compression_stats()->UpdateDataSavings(
+ data_usage_host, data_used, original_size);
+ return true;
+}
+
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
index 7173f526ed2..a6ee82792e6 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -18,6 +18,7 @@
#include "base/threading/thread_checker.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service_observer.h"
+#include "components/data_reduction_proxy/core/common/data_savings_recorder.h"
#include "components/prefs/pref_member.h"
#include "url/gurl.h"
@@ -69,7 +70,8 @@ enum DataReductionSettingsEnabledAction {
// Central point for configuring the data reduction proxy.
// This object lives on the UI thread and all of its methods are expected to
// be called from there.
-class DataReductionProxySettings : public DataReductionProxyServiceObserver {
+class DataReductionProxySettings : public DataReductionProxyServiceObserver,
+ public DataSavingsRecorder {
public:
typedef base::Callback<bool(const std::string&, const std::string&)>
SyntheticFieldTrialRegistrationCallback;
@@ -77,6 +79,11 @@ class DataReductionProxySettings : public DataReductionProxyServiceObserver {
DataReductionProxySettings();
virtual ~DataReductionProxySettings();
+ // DataSavingsRecorder implementation:
+ bool UpdateDataSavings(const std::string& data_usage_host,
+ int64_t data_used,
+ int64_t original_size) override;
+
// Initializes the Data Reduction Proxy with the name of the preference that
// controls enabling it, profile prefs and a |DataReductionProxyIOData|. The
// caller must ensure that all parameters remain alive for the lifetime of
@@ -120,23 +127,24 @@ class DataReductionProxySettings : public DataReductionProxyServiceObserver {
// on main frame requests.
void SetLoFiModeActiveOnMainFrame(bool lo_fi_mode_active);
- // Returns true if Lo-Fi was active on the main frame request.
+ // Returns true if Lo-Fi image replacement was active on the main frame
+ // request. Returns false if the user is using lite pages.
bool WasLoFiModeActiveOnMainFrame() const;
// Returns true if a "Load image" context menu request has not been made since
// the last main frame request.
bool WasLoFiLoadImageRequestedBefore();
- // Increments the number of times the Lo-Fi snackbar has been shown.
- void IncrementLoFiSnackbarShown();
+ // Increments the number of times the Lo-Fi UI has been shown.
+ void IncrementLoFiUIShown();
// Sets |lo_fi_load_image_requested_| to true, which means a "Load image"
// context menu request has been made since the last main frame request.
void SetLoFiLoadImageRequested();
// Counts the number of requests to reload the page with images from the Lo-Fi
- // snackbar. If the user requests the page with images a certain number of
- // times, then Lo-Fi is disabled for the remainder of the session.
+ // UI. If the user requests the page with images a certain number of times,
+ // then Lo-Fi is disabled for the remainder of the session.
void IncrementLoFiUserRequestsForImages();
// Records UMA for Lo-Fi implicit opt out actions.
@@ -294,8 +302,7 @@ class DataReductionProxySettings : public DataReductionProxyServiceObserver {
bool lo_fi_load_image_requested_;
// The number of requests to reload the page with images from the Lo-Fi
- // snackbar until Lo-Fi is disabled for the remainder of the
- // session.
+ // UI until Lo-Fi is disabled for the remainder of the session.
int lo_fi_user_requests_for_images_per_session_;
// The number of consecutive sessions where Lo-Fi was disabled for
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
index 8011688749f..245d75c16c7 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
@@ -62,9 +63,10 @@ void DataReductionProxySettingsTestBase::SetUp() {
ListPrefUpdate received_update(test_context_->pref_service(),
prefs::kDailyHttpReceivedContentLength);
for (int64_t i = 0; i < kNumDaysInHistory; i++) {
- original_update->Insert(0,
- new base::StringValue(base::Int64ToString(2 * i)));
- received_update->Insert(0, new base::StringValue(base::Int64ToString(i)));
+ original_update->Insert(
+ 0, base::MakeUnique<base::StringValue>(base::Int64ToString(2 * i)));
+ received_update->Insert(
+ 0, base::MakeUnique<base::StringValue>(base::Int64ToString(i)));
}
last_update_time_ = base::Time::Now().LocalMidnight();
pref_service->SetInt64(prefs::kDailyHttpContentLengthLastUpdateDate,
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h
index 3457b1131bf..cc537954c91 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h
@@ -9,6 +9,7 @@
#include <memory>
#include <string>
+#include "base/message_loop/message_loop.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
#include "components/prefs/testing_pref_service.h"
#include "net/log/test_net_log.h"
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
index 8b832fa00b6..36d72d8d4b4 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
@@ -64,14 +64,17 @@ TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
test_context_->config()->SetStateForTest(false, true);
EXPECT_FALSE(settings_->IsDataReductionProxyEnabled());
+ EXPECT_FALSE(settings_->UpdateDataSavings(std::string(), 0, 0));
EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
CheckOnPrefChange(true, true, false);
EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
+ EXPECT_TRUE(settings_->UpdateDataSavings(std::string(), 0, 0));
EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
CheckOnPrefChange(true, true, true);
EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
+ EXPECT_TRUE(settings_->UpdateDataSavings(std::string(), 0, 0));
EXPECT_TRUE(settings_->IsDataReductionProxyManaged());
test_context_->RunUntilIdle();
@@ -336,19 +339,19 @@ TEST_F(DataReductionProxySettingsTest, TestLoFiImplicitOptOutClicksPerSession) {
EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
prefs::kLoFiLoadImagesPerSession));
EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
- prefs::kLoFiSnackbarsShownPerSession));
+ prefs::kLoFiUIShownPerSession));
EXPECT_FALSE(test_context_->config()->lofi_off());
// Click "Load images" |lo_fi_user_requests_for_images_per_session_| times.
for (int i = 1; i <= settings_->lo_fi_user_requests_for_images_per_session_;
++i) {
- settings_->IncrementLoFiSnackbarShown();
+ settings_->IncrementLoFiUIShown();
settings_->SetLoFiModeActiveOnMainFrame(true);
settings_->IncrementLoFiUserRequestsForImages();
EXPECT_EQ(i, test_context_->pref_service()->GetInteger(
prefs::kLoFiLoadImagesPerSession));
EXPECT_EQ(i, test_context_->pref_service()->GetInteger(
- prefs::kLoFiSnackbarsShownPerSession));
+ prefs::kLoFiUIShownPerSession));
}
test_context_->RunUntilIdle();
@@ -363,41 +366,41 @@ TEST_F(DataReductionProxySettingsTest, TestLoFiImplicitOptOutClicksPerSession) {
EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
prefs::kLoFiLoadImagesPerSession));
EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
- prefs::kLoFiSnackbarsShownPerSession));
+ prefs::kLoFiUIShownPerSession));
EXPECT_EQ(1, test_context_->pref_service()->GetInteger(
prefs::kLoFiConsecutiveSessionDisables));
EXPECT_FALSE(test_context_->config()->lofi_off());
- // Don't show any snackbars or have any "Load images" requests, but start
+ // Don't show any UI or have any "Load images" requests, but start
// a new session. kLoFiConsecutiveSessionDisables should not reset since
- // the minimum number of snackbars were not shown.
+ // the minimum number of infobars were not shown.
test_context_->config()->ResetLoFiStatusForTest();
settings_->data_reduction_proxy_service_->InitializeLoFiPrefs();
EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
prefs::kLoFiLoadImagesPerSession));
EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
- prefs::kLoFiSnackbarsShownPerSession));
+ prefs::kLoFiUIShownPerSession));
EXPECT_EQ(1, test_context_->pref_service()->GetInteger(
prefs::kLoFiConsecutiveSessionDisables));
EXPECT_FALSE(test_context_->config()->lofi_off());
// Have a session that doesn't have
// |lo_fi_user_requests_for_images_per_session_|, but has that number of
- // snackbars shown so kLoFiConsecutiveSessionDisables resets.
+ // infobars shown so kLoFiConsecutiveSessionDisables resets.
for (int i = 1;
i <= settings_->lo_fi_user_requests_for_images_per_session_ - 1; ++i) {
- settings_->IncrementLoFiSnackbarShown();
+ settings_->IncrementLoFiUIShown();
settings_->SetLoFiModeActiveOnMainFrame(true);
settings_->IncrementLoFiUserRequestsForImages();
EXPECT_EQ(i, test_context_->pref_service()->GetInteger(
prefs::kLoFiLoadImagesPerSession));
EXPECT_EQ(i, test_context_->pref_service()->GetInteger(
- prefs::kLoFiSnackbarsShownPerSession));
+ prefs::kLoFiUIShownPerSession));
}
- settings_->IncrementLoFiSnackbarShown();
- EXPECT_EQ(settings_->lo_fi_user_requests_for_images_per_session_,
- test_context_->pref_service()->GetInteger(
- prefs::kLoFiSnackbarsShownPerSession));
+ settings_->IncrementLoFiUIShown();
+ EXPECT_EQ(
+ settings_->lo_fi_user_requests_for_images_per_session_,
+ test_context_->pref_service()->GetInteger(prefs::kLoFiUIShownPerSession));
test_context_->RunUntilIdle();
// Still should have only one consecutive session disable and Lo-Fi status
@@ -413,7 +416,7 @@ TEST_F(DataReductionProxySettingsTest, TestLoFiImplicitOptOutClicksPerSession) {
EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
prefs::kLoFiConsecutiveSessionDisables));
EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
- prefs::kLoFiSnackbarsShownPerSession));
+ prefs::kLoFiUIShownPerSession));
}
TEST_F(DataReductionProxySettingsTest,
@@ -441,11 +444,11 @@ TEST_F(DataReductionProxySettingsTest,
++j) {
settings_->SetLoFiModeActiveOnMainFrame(true);
settings_->IncrementLoFiUserRequestsForImages();
- settings_->IncrementLoFiSnackbarShown();
+ settings_->IncrementLoFiUIShown();
EXPECT_EQ(j, test_context_->pref_service()->GetInteger(
prefs::kLoFiLoadImagesPerSession));
EXPECT_EQ(j, test_context_->pref_service()->GetInteger(
- prefs::kLoFiSnackbarsShownPerSession));
+ prefs::kLoFiUIShownPerSession));
}
test_context_->RunUntilIdle();
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc
index ed680d182e7..af8f9017f4f 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_tamper_detection_unittest.cc
@@ -25,11 +25,6 @@
#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_ANDROID)
-#include "base/android/jni_android.h"
-#include "net/android/network_library.h"
-#endif
-
namespace {
// Calcuates MD5 hash value for a string and then base64 encode it. Testcases
@@ -83,17 +78,6 @@ std::vector<std::string> StringsToVector(const std::string& values) {
return ret;
}
-void InitEnv() {
-#if defined(OS_ANDROID)
- JNIEnv* env = base::android::AttachCurrentThread();
- static bool inited = false;
- if (!inited) {
- net::android::RegisterNetworkLibrary(env);
- inited = true;
- }
-#endif
-}
-
} // namespace
namespace data_reduction_proxy {
@@ -828,8 +812,6 @@ TEST_F(DataReductionProxyTamperDetectionTest, DetectAndReport) {
},
};
- InitEnv();
-
for (size_t i = 0; i < arraysize(test); ++i) {
std::string raw_headers(test[i].raw_header);
ReplaceWithEncodedString(&raw_headers);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index bef5d0969d1..ae6e0fd8ed5 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -205,7 +205,7 @@ MockDataReductionProxyService::MockDataReductionProxyService(
: DataReductionProxyService(settings,
prefs,
request_context,
- base::WrapUnique(new TestDataStore()),
+ base::MakeUnique<TestDataStore>(),
task_runner,
task_runner,
task_runner,
@@ -581,14 +581,14 @@ std::unique_ptr<DataReductionProxyService>
DataReductionProxyTestContext::CreateDataReductionProxyServiceInternal(
DataReductionProxySettings* settings) {
if (test_context_flags_ & DataReductionProxyTestContext::USE_MOCK_SERVICE) {
- return base::WrapUnique(new MockDataReductionProxyService(
+ return base::MakeUnique<MockDataReductionProxyService>(
settings, simple_pref_service_.get(), request_context_getter_.get(),
- task_runner_));
+ task_runner_);
} else {
- return base::WrapUnique(new DataReductionProxyService(
+ return base::MakeUnique<DataReductionProxyService>(
settings, simple_pref_service_.get(), request_context_getter_.get(),
base::WrapUnique(new TestDataStore()), task_runner_, task_runner_,
- task_runner_, base::TimeDelta()));
+ task_runner_, base::TimeDelta());
}
}
@@ -599,13 +599,13 @@ void DataReductionProxyTestContext::AttachToURLRequestContext(
// |request_context_storage| takes ownership of the network delegate.
request_context_storage->set_network_delegate(
io_data()->CreateNetworkDelegate(
- base::WrapUnique(new net::TestNetworkDelegate()), true));
+ base::MakeUnique<net::TestNetworkDelegate>(), true));
request_context_storage->set_job_factory(
- base::WrapUnique(new net::URLRequestInterceptingJobFactory(
+ base::MakeUnique<net::URLRequestInterceptingJobFactory>(
std::unique_ptr<net::URLRequestJobFactory>(
new net::URLRequestJobFactoryImpl()),
- io_data()->CreateInterceptor())));
+ io_data()->CreateInterceptor()));
}
void DataReductionProxyTestContext::
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc b/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc
index fc269e27aa9..76903bee1df 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc
@@ -47,11 +47,11 @@ DataStoreImpl::DataStoreImpl(const base::FilePath& profile_path)
}
DataStoreImpl::~DataStoreImpl() {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
}
void DataStoreImpl::InitializeOnDBThread() {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(!db_);
DataStore::Status status = OpenDB();
@@ -61,7 +61,7 @@ void DataStoreImpl::InitializeOnDBThread() {
DataStore::Status DataStoreImpl::Get(base::StringPiece key,
std::string* value) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
if (!db_)
return MISC_ERROR;
@@ -78,7 +78,7 @@ DataStore::Status DataStoreImpl::Get(base::StringPiece key,
DataStore::Status DataStoreImpl::Put(
const std::map<std::string, std::string>& map) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
if (!db_)
return MISC_ERROR;
@@ -97,7 +97,7 @@ DataStore::Status DataStoreImpl::Put(
}
DataStore::Status DataStoreImpl::Delete(base::StringPiece key) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
if (!db_)
return MISC_ERROR;
@@ -112,7 +112,7 @@ DataStore::Status DataStoreImpl::Delete(base::StringPiece key) {
}
DataStore::Status DataStoreImpl::OpenDB() {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
leveldb::Options options;
options.create_if_missing = true;
@@ -145,7 +145,7 @@ DataStore::Status DataStoreImpl::OpenDB() {
}
void DataStoreImpl::RecreateDB() {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
LOG(WARNING) << "Deleting corrupt Data Reduction Proxy LevelDB";
db_.reset(nullptr);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc b/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc
index 220231bfd1d..98bcbbd0ed4 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc
@@ -56,7 +56,11 @@ base::Time BucketLowerBoundary(base::Time time) {
exploded.minute -= exploded.minute % kDataUsageBucketLengthInMinutes;
exploded.second = 0;
exploded.millisecond = 0;
- return base::Time::FromUTCExploded(exploded);
+
+ base::Time out_time;
+ bool conversion_success = base::Time::FromUTCExploded(exploded, &out_time);
+ DCHECK(conversion_success);
+ return out_time;
}
} // namespace
@@ -69,7 +73,7 @@ DataUsageStore::DataUsageStore(DataStore* db)
}
DataUsageStore::~DataUsageStore() {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
}
void DataUsageStore::LoadDataUsage(std::vector<DataUsageBucket>* data_usage) {
@@ -89,7 +93,7 @@ void DataUsageStore::LoadDataUsage(std::vector<DataUsageBucket>* data_usage) {
}
void DataUsageStore::LoadCurrentDataUsageBucket(DataUsageBucket* current) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(current);
std::string current_index_string;
@@ -113,7 +117,7 @@ void DataUsageStore::LoadCurrentDataUsageBucket(DataUsageBucket* current) {
void DataUsageStore::StoreCurrentDataUsageBucket(
const DataUsageBucket& current) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(current_bucket_index_ >= 0 &&
current_bucket_index_ < kNumDataUsageBuckets);
@@ -221,7 +225,6 @@ bool DataUsageStore::BucketOverlapsInterval(
const base::Time& start_interval,
const base::Time& end_interval) {
DCHECK(!bucket_last_updated.is_null());
- DCHECK(!start_interval.is_null());
DCHECK(!end_interval.is_null());
DCHECK_LE(start_interval, end_interval);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
index 8a4e640b495..6dc60c8235d 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
@@ -65,7 +65,8 @@ class DataUsageStoreTest : public testing::Test {
void PopulateStore() {
base::Time::Exploded exploded = TestExplodedTime();
- base::Time current_time = base::Time::FromUTCExploded(exploded);
+ base::Time current_time;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &current_time));
DataUsageBucket current_bucket;
current_bucket.set_last_updated_timestamp(current_time.ToInternalValue());
@@ -144,12 +145,14 @@ TEST_F(DataUsageStoreTest, StoreSameBucket) {
exploded.minute = 0;
exploded.second = 0;
exploded.millisecond = 0;
- base::Time time1 = base::Time::FromUTCExploded(exploded);
+ base::Time time1;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time1));
exploded.minute = 14;
exploded.second = 59;
exploded.millisecond = 999;
- base::Time time2 = base::Time::FromUTCExploded(exploded);
+ base::Time time2;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time2));
DataUsageBucket bucket;
data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
@@ -180,12 +183,14 @@ TEST_F(DataUsageStoreTest, StoreConsecutiveBuckets) {
exploded.minute = 0;
exploded.second = 59;
exploded.millisecond = 999;
- base::Time time1 = base::Time::FromUTCExploded(exploded);
+ base::Time time1;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time1));
exploded.minute = 15;
exploded.second = 0;
exploded.millisecond = 0;
- base::Time time2 = base::Time::FromUTCExploded(exploded);
+ base::Time time2;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time2));
DataUsageBucket bucket;
data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
@@ -308,25 +313,32 @@ TEST_F(DataUsageStoreTest, DeleteHistoricalDataUsage) {
TEST_F(DataUsageStoreTest, BucketOverlapsInterval) {
base::Time::Exploded exploded = TestExplodedTime();
- base::Time time1 = base::Time::FromUTCExploded(exploded);
+ base::Time time1;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time1));
exploded.minute = 16;
- base::Time time16 = base::Time::FromUTCExploded(exploded);
+ base::Time time16;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time16));
exploded.minute = 17;
- base::Time time17 = base::Time::FromUTCExploded(exploded);
+ base::Time time17;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time17));
exploded.minute = 18;
- base::Time time18 = base::Time::FromUTCExploded(exploded);
+ base::Time time18;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time18));
exploded.minute = 33;
- base::Time time33 = base::Time::FromUTCExploded(exploded);
+ base::Time time33;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time33));
exploded.minute = 34;
- base::Time time34 = base::Time::FromUTCExploded(exploded);
+ base::Time time34;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time34));
exploded.minute = 46;
- base::Time time46 = base::Time::FromUTCExploded(exploded);
+ base::Time time46;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time46));
ASSERT_FALSE(DataUsageStore::BucketOverlapsInterval(time1, time17, time33));
ASSERT_TRUE(DataUsageStore::BucketOverlapsInterval(time16, time17, time33));
@@ -343,45 +355,53 @@ TEST_F(DataUsageStoreTest, ComputeBucketIndex) {
DataUsageBucket current_bucket;
data_usage_store()->LoadCurrentDataUsageBucket(&current_bucket);
+ base::Time out_time;
+
exploded.minute = 0;
- ASSERT_EQ(kTestCurrentBucketIndex,
- ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
+ ASSERT_EQ(kTestCurrentBucketIndex, ComputeBucketIndex(out_time));
+
exploded.minute = 14;
- ASSERT_EQ(kTestCurrentBucketIndex,
- ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
+ ASSERT_EQ(kTestCurrentBucketIndex, ComputeBucketIndex(out_time));
exploded.minute = 15;
- ASSERT_EQ(kTestCurrentBucketIndex + 1,
- ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
+ ASSERT_EQ(kTestCurrentBucketIndex + 1, ComputeBucketIndex(out_time));
exploded.hour = 11;
exploded.minute = 59;
- ASSERT_EQ(kTestCurrentBucketIndex - 1,
- ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
+ ASSERT_EQ(kTestCurrentBucketIndex - 1, ComputeBucketIndex(out_time));
exploded.minute = 0;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour,
- ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+ ComputeBucketIndex(out_time));
exploded.hour = 1;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 11,
- ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+ ComputeBucketIndex(out_time));
exploded.day_of_month = 1;
exploded.hour = 12;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 30 * 24,
- ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+ ComputeBucketIndex(out_time));
exploded.hour = 11;
exploded.minute = 45;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 30 * 24 - 1 +
static_cast<int>(kNumExpectedBuckets),
- ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+ ComputeBucketIndex(out_time));
exploded.minute = 30;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 30 * 24 - 2 +
static_cast<int>(kNumExpectedBuckets),
- ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+ ComputeBucketIndex(out_time));
}
TEST_F(DataUsageStoreTest, DeleteBrowsingHistory) {
@@ -393,7 +413,8 @@ TEST_F(DataUsageStoreTest, DeleteBrowsingHistory) {
base::Time::Exploded exploded = TestExplodedTime();
exploded.minute = 0;
- base::Time now = base::Time::FromUTCExploded(exploded);
+ base::Time now;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &now));
base::Time fifteen_mins_from_now = now + base::TimeDelta::FromMinutes(15);
// Deleting browsing from the future should be a no-op.
data_usage_store()->DeleteBrowsingHistory(fifteen_mins_from_now,
diff --git a/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc b/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc
index 4a338ca05ab..d416992a93d 100644
--- a/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc
@@ -22,44 +22,44 @@ DBDataOwner::DBDataOwner(std::unique_ptr<DataStore> store)
}
DBDataOwner::~DBDataOwner() {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
}
void DBDataOwner::InitializeOnDBThread() {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
store_->InitializeOnDBThread();
}
void DBDataOwner::LoadHistoricalDataUsage(
std::vector<DataUsageBucket>* data_usage) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
data_usage_->LoadDataUsage(data_usage);
}
void DBDataOwner::LoadCurrentDataUsageBucket(DataUsageBucket* bucket) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
data_usage_->LoadCurrentDataUsageBucket(bucket);
}
void DBDataOwner::StoreCurrentDataUsageBucket(
std::unique_ptr<DataUsageBucket> current) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
data_usage_->StoreCurrentDataUsageBucket(*current.get());
}
void DBDataOwner::DeleteHistoricalDataUsage() {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
data_usage_->DeleteHistoricalDataUsage();
}
void DBDataOwner::DeleteBrowsingHistory(const base::Time& start,
const base::Time& end) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
data_usage_->DeleteBrowsingHistory(start, end);
}
diff --git a/chromium/components/data_reduction_proxy/core/common/BUILD.gn b/chromium/components/data_reduction_proxy/core/common/BUILD.gn
index f5da9da2236..d829ef253f5 100644
--- a/chromium/components/data_reduction_proxy/core/common/BUILD.gn
+++ b/chromium/components/data_reduction_proxy/core/common/BUILD.gn
@@ -2,12 +2,12 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//chrome/version.gni")
+import("//build/util/process_version.gni")
# Variables:
# deps: Extra dependencies.
template("common_tmpl") {
- source_set(target_name) {
+ static_library(target_name) {
sources = [
"data_reduction_proxy_bypass_action_list.h",
"data_reduction_proxy_bypass_type_list.h",
@@ -19,6 +19,7 @@ template("common_tmpl") {
"data_reduction_proxy_event_store.h",
"data_reduction_proxy_headers.cc",
"data_reduction_proxy_headers.h",
+ "data_reduction_proxy_page_load_timing.cc",
"data_reduction_proxy_page_load_timing.h",
"data_reduction_proxy_params.cc",
"data_reduction_proxy_params.h",
@@ -28,6 +29,7 @@ template("common_tmpl") {
"data_reduction_proxy_switches.h",
"data_reduction_proxy_util.cc",
"data_reduction_proxy_util.h",
+ "data_savings_recorder.h",
"lofi_decider.h",
"lofi_ui_service.h",
]
@@ -57,7 +59,7 @@ common_tmpl("common") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"data_reduction_proxy_event_storage_delegate_test_utils.cc",
@@ -107,6 +109,9 @@ source_set("unit_tests") {
process_version("version_header") {
template_file = "version.h.in"
+ sources = [
+ "//chrome/VERSION",
+ ]
output = "$target_gen_dir/version.h"
extra_args = [
"-e",
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.cc
index 2f79aad454d..f915a6bfd4f 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.cc
@@ -11,6 +11,10 @@
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_entry.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_server.h"
namespace data_reduction_proxy {
@@ -18,15 +22,15 @@ namespace data_reduction_proxy {
namespace {
std::unique_ptr<base::Value> BuildDataReductionProxyEvent(
- net::NetLog::EventType type,
- const net::NetLog::Source& source,
- net::NetLog::EventPhase phase,
- const net::NetLog::ParametersCallback& parameters_callback) {
+ net::NetLogEventType type,
+ const net::NetLogSource& source,
+ net::NetLogEventPhase phase,
+ const net::NetLogParametersCallback& parameters_callback) {
base::TimeTicks ticks_now = base::TimeTicks::Now();
- net::NetLog::EntryData entry_data(type, source, phase, ticks_now,
- &parameters_callback);
- net::NetLog::Entry entry(&entry_data,
- net::NetLogCaptureMode::IncludeSocketBytes());
+ net::NetLogEntryData entry_data(type, source, phase, ticks_now,
+ &parameters_callback);
+ net::NetLogEntry entry(&entry_data,
+ net::NetLogCaptureMode::IncludeSocketBytes());
std::unique_ptr<base::Value> entry_value(entry.ToValue());
return entry_value;
@@ -175,24 +179,24 @@ void DataReductionProxyEventCreator::AddProxyEnabledEvent(
bool secure_transport_restricted,
const std::vector<net::ProxyServer>& proxies_for_http) {
DCHECK(thread_checker_.CalledOnValidThread());
- const net::NetLog::ParametersCallback& parameters_callback =
+ const net::NetLogParametersCallback& parameters_callback =
base::Bind(&EnableDataReductionProxyCallback, secure_transport_restricted,
proxies_for_http);
- PostEnabledEvent(net_log, net::NetLog::TYPE_DATA_REDUCTION_PROXY_ENABLED,
+ PostEnabledEvent(net_log, net::NetLogEventType::DATA_REDUCTION_PROXY_ENABLED,
true, parameters_callback);
}
void DataReductionProxyEventCreator::AddProxyDisabledEvent(
net::NetLog* net_log) {
DCHECK(thread_checker_.CalledOnValidThread());
- const net::NetLog::ParametersCallback& parameters_callback =
+ const net::NetLogParametersCallback& parameters_callback =
base::Bind(&DisableDataReductionProxyCallback);
- PostEnabledEvent(net_log, net::NetLog::TYPE_DATA_REDUCTION_PROXY_ENABLED,
+ PostEnabledEvent(net_log, net::NetLogEventType::DATA_REDUCTION_PROXY_ENABLED,
false, parameters_callback);
}
void DataReductionProxyEventCreator::AddBypassActionEvent(
- const net::BoundNetLog& net_log,
+ const net::NetLogWithSource& net_log,
DataReductionProxyBypassAction bypass_action,
const std::string& request_method,
const GURL& url,
@@ -200,16 +204,16 @@ void DataReductionProxyEventCreator::AddBypassActionEvent(
const base::TimeDelta& bypass_duration) {
DCHECK(thread_checker_.CalledOnValidThread());
int64_t expiration_ticks = GetExpirationTicks(bypass_duration.InSeconds());
- const net::NetLog::ParametersCallback& parameters_callback =
+ const net::NetLogParametersCallback& parameters_callback =
base::Bind(&UrlBypassActionCallback, bypass_action, request_method, url,
should_retry, bypass_duration.InSeconds(), expiration_ticks);
- PostBoundNetLogBypassEvent(
- net_log, net::NetLog::TYPE_DATA_REDUCTION_PROXY_BYPASS_REQUESTED,
- net::NetLog::PHASE_NONE, expiration_ticks, parameters_callback);
+ PostNetLogWithSourceBypassEvent(
+ net_log, net::NetLogEventType::DATA_REDUCTION_PROXY_BYPASS_REQUESTED,
+ net::NetLogEventPhase::NONE, expiration_ticks, parameters_callback);
}
void DataReductionProxyEventCreator::AddBypassTypeEvent(
- const net::BoundNetLog& net_log,
+ const net::NetLogWithSource& net_log,
DataReductionProxyBypassType bypass_type,
const std::string& request_method,
const GURL& url,
@@ -217,12 +221,12 @@ void DataReductionProxyEventCreator::AddBypassTypeEvent(
const base::TimeDelta& bypass_duration) {
DCHECK(thread_checker_.CalledOnValidThread());
int64_t expiration_ticks = GetExpirationTicks(bypass_duration.InSeconds());
- const net::NetLog::ParametersCallback& parameters_callback =
+ const net::NetLogParametersCallback& parameters_callback =
base::Bind(&UrlBypassTypeCallback, bypass_type, request_method, url,
should_retry, bypass_duration.InSeconds(), expiration_ticks);
- PostBoundNetLogBypassEvent(
- net_log, net::NetLog::TYPE_DATA_REDUCTION_PROXY_BYPASS_REQUESTED,
- net::NetLog::PHASE_NONE, expiration_ticks, parameters_callback);
+ PostNetLogWithSourceBypassEvent(
+ net_log, net::NetLogEventType::DATA_REDUCTION_PROXY_BYPASS_REQUESTED,
+ net::NetLogEventPhase::NONE, expiration_ticks, parameters_callback);
}
void DataReductionProxyEventCreator::AddProxyFallbackEvent(
@@ -230,55 +234,55 @@ void DataReductionProxyEventCreator::AddProxyFallbackEvent(
const std::string& proxy_url,
int net_error) {
DCHECK(thread_checker_.CalledOnValidThread());
- const net::NetLog::ParametersCallback& parameters_callback =
+ const net::NetLogParametersCallback& parameters_callback =
base::Bind(&FallbackCallback, proxy_url, net_error);
- PostEvent(net_log, net::NetLog::TYPE_DATA_REDUCTION_PROXY_FALLBACK,
+ PostEvent(net_log, net::NetLogEventType::DATA_REDUCTION_PROXY_FALLBACK,
parameters_callback);
}
void DataReductionProxyEventCreator::BeginSecureProxyCheck(
- const net::BoundNetLog& net_log,
+ const net::NetLogWithSource& net_log,
const GURL& url) {
DCHECK(thread_checker_.CalledOnValidThread());
// This callback must be invoked synchronously
- const net::NetLog::ParametersCallback& parameters_callback =
+ const net::NetLogParametersCallback& parameters_callback =
net::NetLog::StringCallback("url", &url.spec());
- PostBoundNetLogSecureProxyCheckEvent(
- net_log, net::NetLog::TYPE_DATA_REDUCTION_PROXY_CANARY_REQUEST,
- net::NetLog::PHASE_BEGIN,
+ PostNetLogWithSourceSecureProxyCheckEvent(
+ net_log, net::NetLogEventType::DATA_REDUCTION_PROXY_CANARY_REQUEST,
+ net::NetLogEventPhase::BEGIN,
DataReductionProxyEventStorageDelegate::CHECK_PENDING,
parameters_callback);
}
void DataReductionProxyEventCreator::EndSecureProxyCheck(
- const net::BoundNetLog& net_log,
+ const net::NetLogWithSource& net_log,
int net_error,
int http_response_code,
bool succeeded) {
DCHECK(thread_checker_.CalledOnValidThread());
- const net::NetLog::ParametersCallback& parameters_callback = base::Bind(
+ const net::NetLogParametersCallback& parameters_callback = base::Bind(
&EndCanaryRequestCallback, net_error, http_response_code, succeeded);
- PostBoundNetLogSecureProxyCheckEvent(
- net_log, net::NetLog::TYPE_DATA_REDUCTION_PROXY_CANARY_REQUEST,
- net::NetLog::PHASE_END,
+ PostNetLogWithSourceSecureProxyCheckEvent(
+ net_log, net::NetLogEventType::DATA_REDUCTION_PROXY_CANARY_REQUEST,
+ net::NetLogEventPhase::END,
succeeded ? DataReductionProxyEventStorageDelegate::CHECK_SUCCESS
: DataReductionProxyEventStorageDelegate::CHECK_FAILED,
parameters_callback);
}
void DataReductionProxyEventCreator::BeginConfigRequest(
- const net::BoundNetLog& net_log,
+ const net::NetLogWithSource& net_log,
const GURL& url) {
// This callback must be invoked synchronously.
- const net::NetLog::ParametersCallback& parameters_callback =
+ const net::NetLogParametersCallback& parameters_callback =
net::NetLog::StringCallback("url", &url.spec());
- PostBoundNetLogConfigRequestEvent(
- net_log, net::NetLog::TYPE_DATA_REDUCTION_PROXY_CONFIG_REQUEST,
- net::NetLog::PHASE_BEGIN, parameters_callback);
+ PostNetLogWithSourceConfigRequestEvent(
+ net_log, net::NetLogEventType::DATA_REDUCTION_PROXY_CONFIG_REQUEST,
+ net::NetLogEventPhase::BEGIN, parameters_callback);
}
void DataReductionProxyEventCreator::EndConfigRequest(
- const net::BoundNetLog& net_log,
+ const net::NetLogWithSource& net_log,
int net_error,
int http_response_code,
int failure_count,
@@ -287,20 +291,20 @@ void DataReductionProxyEventCreator::EndConfigRequest(
const base::TimeDelta& retry_delay) {
int64_t refresh_duration_minutes = refresh_duration.InMinutes();
int64_t expiration_ticks = GetExpirationTicks(retry_delay.InSeconds());
- const net::NetLog::ParametersCallback& parameters_callback = base::Bind(
+ const net::NetLogParametersCallback& parameters_callback = base::Bind(
&EndConfigRequestCallback, net_error, http_response_code, failure_count,
proxies_for_http, refresh_duration_minutes, expiration_ticks);
- PostBoundNetLogConfigRequestEvent(
- net_log, net::NetLog::TYPE_DATA_REDUCTION_PROXY_CONFIG_REQUEST,
- net::NetLog::PHASE_END, parameters_callback);
+ PostNetLogWithSourceConfigRequestEvent(
+ net_log, net::NetLogEventType::DATA_REDUCTION_PROXY_CONFIG_REQUEST,
+ net::NetLogEventPhase::END, parameters_callback);
}
void DataReductionProxyEventCreator::PostEvent(
net::NetLog* net_log,
- net::NetLog::EventType type,
- const net::NetLog::ParametersCallback& callback) {
+ net::NetLogEventType type,
+ const net::NetLogParametersCallback& callback) {
std::unique_ptr<base::Value> event = BuildDataReductionProxyEvent(
- type, net::NetLog::Source(), net::NetLog::PHASE_NONE, callback);
+ type, net::NetLogSource(), net::NetLogEventPhase::NONE, callback);
if (event)
storage_delegate_->AddEvent(std::move(event));
@@ -310,11 +314,11 @@ void DataReductionProxyEventCreator::PostEvent(
void DataReductionProxyEventCreator::PostEnabledEvent(
net::NetLog* net_log,
- net::NetLog::EventType type,
+ net::NetLogEventType type,
bool enabled,
- const net::NetLog::ParametersCallback& callback) {
+ const net::NetLogParametersCallback& callback) {
std::unique_ptr<base::Value> event = BuildDataReductionProxyEvent(
- type, net::NetLog::Source(), net::NetLog::PHASE_NONE, callback);
+ type, net::NetLogSource(), net::NetLogEventPhase::NONE, callback);
if (event)
storage_delegate_->AddEnabledEvent(std::move(event), enabled);
@@ -322,12 +326,12 @@ void DataReductionProxyEventCreator::PostEnabledEvent(
net_log->AddGlobalEntry(type, callback);
}
-void DataReductionProxyEventCreator::PostBoundNetLogBypassEvent(
- const net::BoundNetLog& net_log,
- net::NetLog::EventType type,
- net::NetLog::EventPhase phase,
+void DataReductionProxyEventCreator::PostNetLogWithSourceBypassEvent(
+ const net::NetLogWithSource& net_log,
+ net::NetLogEventType type,
+ net::NetLogEventPhase phase,
int64_t expiration_ticks,
- const net::NetLog::ParametersCallback& callback) {
+ const net::NetLogParametersCallback& callback) {
std::unique_ptr<base::Value> event =
BuildDataReductionProxyEvent(type, net_log.source(), phase, callback);
if (event)
@@ -336,12 +340,12 @@ void DataReductionProxyEventCreator::PostBoundNetLogBypassEvent(
net_log.AddEntry(type, phase, callback);
}
-void DataReductionProxyEventCreator::PostBoundNetLogSecureProxyCheckEvent(
- const net::BoundNetLog& net_log,
- net::NetLog::EventType type,
- net::NetLog::EventPhase phase,
+void DataReductionProxyEventCreator::PostNetLogWithSourceSecureProxyCheckEvent(
+ const net::NetLogWithSource& net_log,
+ net::NetLogEventType type,
+ net::NetLogEventPhase phase,
DataReductionProxyEventStorageDelegate::SecureProxyCheckState state,
- const net::NetLog::ParametersCallback& callback) {
+ const net::NetLogParametersCallback& callback) {
std::unique_ptr<base::Value> event(
BuildDataReductionProxyEvent(type, net_log.source(), phase, callback));
if (event)
@@ -350,11 +354,11 @@ void DataReductionProxyEventCreator::PostBoundNetLogSecureProxyCheckEvent(
net_log.AddEntry(type, phase, callback);
}
-void DataReductionProxyEventCreator::PostBoundNetLogConfigRequestEvent(
- const net::BoundNetLog& net_log,
- net::NetLog::EventType type,
- net::NetLog::EventPhase phase,
- const net::NetLog::ParametersCallback& callback) {
+void DataReductionProxyEventCreator::PostNetLogWithSourceConfigRequestEvent(
+ const net::NetLogWithSource& net_log,
+ net::NetLogEventType type,
+ net::NetLogEventPhase phase,
+ const net::NetLogParametersCallback& callback) {
std::unique_ptr<base::Value> event(
BuildDataReductionProxyEvent(type, net_log.source(), phase, callback));
if (event) {
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h
index 66041de47de..9ac949af126 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h
@@ -14,7 +14,8 @@
#include "base/threading/thread_checker.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_storage_delegate.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
class GURL;
@@ -24,8 +25,9 @@ class Value;
}
namespace net {
-class BoundNetLog;
+class NetLogWithSource;
class ProxyServer;
+class NetLog;
}
namespace data_reduction_proxy {
@@ -56,7 +58,7 @@ class DataReductionProxyEventCreator {
// Adds a DATA_REDUCTION_PROXY_BYPASS_REQUESTED event to the event store
// when the bypass reason is initiated by the data reduction proxy.
- void AddBypassActionEvent(const net::BoundNetLog& net_log,
+ void AddBypassActionEvent(const net::NetLogWithSource& net_log,
DataReductionProxyBypassAction bypass_action,
const std::string& request_method,
const GURL& gurl,
@@ -66,7 +68,7 @@ class DataReductionProxyEventCreator {
// Adds a DATA_REDUCTION_PROXY_BYPASS_REQUESTED event to the event store
// when the bypass reason is not initiated by the data reduction proxy, such
// as HTTP errors.
- void AddBypassTypeEvent(const net::BoundNetLog& net_log,
+ void AddBypassTypeEvent(const net::NetLogWithSource& net_log,
DataReductionProxyBypassType bypass_type,
const std::string& request_method,
const GURL& gurl,
@@ -81,22 +83,24 @@ class DataReductionProxyEventCreator {
// Adds a DATA_REDUCTION_PROXY_CANARY_REQUEST event to the event store
// when the secure proxy request has started.
- void BeginSecureProxyCheck(const net::BoundNetLog& net_log, const GURL& gurl);
+ void BeginSecureProxyCheck(const net::NetLogWithSource& net_log,
+ const GURL& gurl);
// Adds a DATA_REDUCTION_PROXY_CANARY_REQUEST event to the event store
// when the secure proxy request has ended.
- void EndSecureProxyCheck(const net::BoundNetLog& net_log,
+ void EndSecureProxyCheck(const net::NetLogWithSource& net_log,
int net_error,
int http_response_code,
bool succeeded);
// Adds a DATA_REDUCTION_PROXY_CONFIG_REQUEST event to the event store
// when the config request has started.
- void BeginConfigRequest(const net::BoundNetLog& net_log, const GURL& url);
+ void BeginConfigRequest(const net::NetLogWithSource& net_log,
+ const GURL& url);
// Adds a DATA_REDUCTION_PROXY_CONFIG_REQUEST event to the event store
// when the config request has ended.
- void EndConfigRequest(const net::BoundNetLog& net_log,
+ void EndConfigRequest(const net::NetLogWithSource& net_log,
int net_error,
int http_response_code,
int failure_count,
@@ -108,41 +112,41 @@ class DataReductionProxyEventCreator {
// Prepare and post a generic Data Reduction Proxy event with no additional
// parameters.
void PostEvent(net::NetLog* net_log,
- net::NetLog::EventType type,
- const net::NetLog::ParametersCallback& callback);
+ net::NetLogEventType type,
+ const net::NetLogParametersCallback& callback);
// Prepare and post enabling/disabling proxy events for the event store on the
// a net::NetLog.
void PostEnabledEvent(net::NetLog* net_log,
- net::NetLog::EventType type,
+ net::NetLogEventType type,
bool enable,
- const net::NetLog::ParametersCallback& callback);
+ const net::NetLogParametersCallback& callback);
// Prepare and post a Data Reduction Proxy bypass event for the event store
- // on a BoundNetLog.
- void PostBoundNetLogBypassEvent(
- const net::BoundNetLog& net_log,
- net::NetLog::EventType type,
- net::NetLog::EventPhase phase,
+ // on a NetLogWithSource.
+ void PostNetLogWithSourceBypassEvent(
+ const net::NetLogWithSource& net_log,
+ net::NetLogEventType type,
+ net::NetLogEventPhase phase,
int64_t expiration_ticks,
- const net::NetLog::ParametersCallback& callback);
+ const net::NetLogParametersCallback& callback);
// Prepare and post a secure proxy check event for the event store on a
- // BoundNetLog.
- void PostBoundNetLogSecureProxyCheckEvent(
- const net::BoundNetLog& net_log,
- net::NetLog::EventType type,
- net::NetLog::EventPhase phase,
+ // NetLogWithSource.
+ void PostNetLogWithSourceSecureProxyCheckEvent(
+ const net::NetLogWithSource& net_log,
+ net::NetLogEventType type,
+ net::NetLogEventPhase phase,
DataReductionProxyEventStorageDelegate::SecureProxyCheckState state,
- const net::NetLog::ParametersCallback& callback);
+ const net::NetLogParametersCallback& callback);
// Prepare and post a config request event for the event store on a
- // BoundNetLog.
- void PostBoundNetLogConfigRequestEvent(
- const net::BoundNetLog& net_log,
- net::NetLog::EventType type,
- net::NetLog::EventPhase phase,
- const net::NetLog::ParametersCallback& callback);
+ // NetLogWithSource.
+ void PostNetLogWithSourceConfigRequestEvent(
+ const net::NetLogWithSource& net_log,
+ net::NetLogEventType type,
+ net::NetLogEventPhase phase,
+ const net::NetLogParametersCallback& callback);
// Must outlive |this|. Used for posting calls to the UI thread.
DataReductionProxyEventStorageDelegate* storage_delegate_;
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
index 44ab9c1a99e..df8c57c6b6f 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
@@ -11,6 +11,7 @@
#include "base/json/json_writer.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -72,7 +73,7 @@ namespace data_reduction_proxy {
// static
void DataReductionProxyEventStore::AddConstants(
base::DictionaryValue* constants_dict) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ auto dict = base::MakeUnique<base::DictionaryValue>();
for (size_t i = 0;
i < arraysize(kDataReductionProxyBypassEventTypeTable); ++i) {
dict->SetInteger(kDataReductionProxyBypassEventTypeTable[i].name,
@@ -81,7 +82,7 @@ void DataReductionProxyEventStore::AddConstants(
constants_dict->Set("dataReductionProxyBypassEventType", std::move(dict));
- dict.reset(new base::DictionaryValue());
+ dict = base::MakeUnique<base::DictionaryValue>();
for (size_t i = 0; i < arraysize(kDataReductionProxyBypassActionTypeTable);
++i) {
dict->SetInteger(kDataReductionProxyBypassActionTypeTable[i].name,
@@ -98,19 +99,17 @@ DataReductionProxyEventStore::DataReductionProxyEventStore()
}
DataReductionProxyEventStore::~DataReductionProxyEventStore() {
- STLDeleteElements(&stored_events_);
}
-base::Value* DataReductionProxyEventStore::GetSummaryValue() const {
+std::unique_ptr<base::DictionaryValue>
+DataReductionProxyEventStore::GetSummaryValue() const {
DCHECK(thread_checker_.CalledOnValidThread());
- std::unique_ptr<base::DictionaryValue> data_reduction_proxy_values(
- new base::DictionaryValue());
- data_reduction_proxy_values->SetBoolean("enabled", enabled_);
- base::Value* current_configuration = current_configuration_.get();
- if (current_configuration != nullptr) {
+ auto data_reduction_proxy_values = base::MakeUnique<base::DictionaryValue>();
+ data_reduction_proxy_values->SetBoolean("enabled", enabled_);
+ if (current_configuration_) {
data_reduction_proxy_values->Set("proxy_config",
- current_configuration->DeepCopy());
+ current_configuration_->DeepCopy());
}
switch (secure_proxy_check_state_) {
@@ -125,13 +124,10 @@ base::Value* DataReductionProxyEventStore::GetSummaryValue() const {
break;
case CHECK_UNKNOWN:
break;
- default:
- NOTREACHED();
- break;
}
base::Value* last_bypass_event = last_bypass_event_.get();
- if (last_bypass_event != nullptr) {
+ if (last_bypass_event) {
int current_time_ticks_ms =
(base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
if (expiration_ticks_ > current_time_ticks_ms) {
@@ -140,24 +136,18 @@ base::Value* DataReductionProxyEventStore::GetSummaryValue() const {
}
}
- base::ListValue* eventsList = new base::ListValue();
- for (size_t i = 0; i < stored_events_.size(); ++i)
- eventsList->Append(stored_events_[i]->DeepCopy());
-
- data_reduction_proxy_values->Set("events", eventsList);
-
- return data_reduction_proxy_values.release();
+ auto events_list = base::MakeUnique<base::ListValue>();
+ for (const auto& event : stored_events_)
+ events_list->Append(event->CreateDeepCopy());
+ data_reduction_proxy_values->Set("events", std::move(events_list));
+ return data_reduction_proxy_values;
}
void DataReductionProxyEventStore::AddEvent(
std::unique_ptr<base::Value> event) {
- if (stored_events_.size() == kMaxEventsToStore) {
- base::Value* head = stored_events_.front();
+ if (stored_events_.size() == kMaxEventsToStore)
stored_events_.pop_front();
- delete head;
- }
-
- stored_events_.push_back(event.release());
+ stored_events_.push_back(std::move(event));
}
void DataReductionProxyEventStore::AddEnabledEvent(
@@ -223,8 +213,7 @@ std::string DataReductionProxyEventStore::SanitizedLastBypassEvent() const {
return std::string();
// Explicitly add parameters to prevent automatic adding of new parameters.
- std::unique_ptr<base::DictionaryValue> last_bypass(
- new base::DictionaryValue());
+ auto last_bypass = base::MakeUnique<base::DictionaryValue>();
std::string str_value;
int int_value;
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h
index 57b1fe15007..1523fac1a83 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h
@@ -41,8 +41,7 @@ class DataReductionProxyEventStore
// - The proxy configuration
// - The state of the last secure proxy check response
// - A stream of the last Data Reduction Proxy related events.
- // The caller is responsible for deleting the returned value.
- base::Value* GetSummaryValue() const;
+ std::unique_ptr<base::DictionaryValue> GetSummaryValue() const;
// Adds DATA_REDUCTION_PROXY event with no parameters to the event store.
void AddEvent(std::unique_ptr<base::Value> event) override;
@@ -75,7 +74,7 @@ class DataReductionProxyEventStore
// A deque of data reduction proxy related events. It is used as a circular
// buffer to prevent unbounded memory utilization.
- std::deque<base::Value*> stored_events_;
+ std::deque<std::unique_ptr<base::Value>> stored_events_;
// Whether the data reduction proxy is enabled or not.
bool enabled_;
// The current data reduction proxy configuration.
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc
index a71dd014208..b790a00495d 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc
@@ -23,6 +23,9 @@
#include "net/base/net_errors.h"
#include "net/http/http_status_code.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_entry.h"
#include "net/proxy/proxy_server.h"
@@ -33,8 +36,8 @@ namespace data_reduction_proxy {
class DataReductionProxyEventStoreTest : public testing::Test {
public:
DataReductionProxyEventStoreTest() : net_log_(new net::TestNetLog()) {
- bound_net_log_ = net::BoundNetLog::Make(
- net_log_.get(), net::NetLog::SOURCE_DATA_REDUCTION_PROXY);
+ net_log_with_source_ = net::NetLogWithSource::Make(
+ net_log_.get(), net::NetLogSourceType::DATA_REDUCTION_PROXY);
}
void SetUp() override {
@@ -64,8 +67,8 @@ class DataReductionProxyEventStoreTest : public testing::Test {
net::TestNetLog* net_log() { return net_log_.get(); }
- const net::BoundNetLog& bound_net_log() {
- return bound_net_log_;
+ const net::NetLogWithSource& net_log_with_source() {
+ return net_log_with_source_;
}
size_t event_count() const { return event_store_->stored_events_.size(); }
@@ -83,7 +86,7 @@ class DataReductionProxyEventStoreTest : public testing::Test {
std::unique_ptr<net::TestNetLog> net_log_;
std::unique_ptr<DataReductionProxyEventStore> event_store_;
std::unique_ptr<DataReductionProxyEventCreator> event_creator_;
- net::BoundNetLog bound_net_log_;
+ net::NetLogWithSource net_log_with_source_;
};
TEST_F(DataReductionProxyEventStoreTest, TestAddProxyEnabledEvent) {
@@ -92,8 +95,7 @@ TEST_F(DataReductionProxyEventStoreTest, TestAddProxyEnabledEvent) {
event_creator()->AddProxyEnabledEvent(net_log(), false, proxies_for_http);
EXPECT_EQ(1u, event_count());
net::TestNetLogEntry entry = GetSingleEntry();
- EXPECT_EQ(net::NetLog::TYPE_DATA_REDUCTION_PROXY_ENABLED,
- entry.type);
+ EXPECT_EQ(net::NetLogEventType::DATA_REDUCTION_PROXY_ENABLED, entry.type);
}
TEST_F(DataReductionProxyEventStoreTest, TestAddProxyDisabledEvent) {
@@ -101,19 +103,18 @@ TEST_F(DataReductionProxyEventStoreTest, TestAddProxyDisabledEvent) {
event_creator()->AddProxyDisabledEvent(net_log());
EXPECT_EQ(1u, event_count());
net::TestNetLogEntry entry = GetSingleEntry();
- EXPECT_EQ(net::NetLog::TYPE_DATA_REDUCTION_PROXY_ENABLED,
- entry.type);
+ EXPECT_EQ(net::NetLogEventType::DATA_REDUCTION_PROXY_ENABLED, entry.type);
}
TEST_F(DataReductionProxyEventStoreTest, TestAddBypassActionEvent) {
EXPECT_EQ(0u, event_count());
EXPECT_EQ(nullptr, last_bypass_event());
event_creator()->AddBypassActionEvent(
- bound_net_log(), BYPASS_ACTION_TYPE_BYPASS, "GET", GURL(), false,
+ net_log_with_source(), BYPASS_ACTION_TYPE_BYPASS, "GET", GURL(), false,
base::TimeDelta::FromMinutes(1));
EXPECT_EQ(1u, event_count());
net::TestNetLogEntry entry = GetSingleEntry();
- EXPECT_EQ(net::NetLog::TYPE_DATA_REDUCTION_PROXY_BYPASS_REQUESTED,
+ EXPECT_EQ(net::NetLogEventType::DATA_REDUCTION_PROXY_BYPASS_REQUESTED,
entry.type);
EXPECT_NE(nullptr, last_bypass_event());
}
@@ -121,13 +122,13 @@ TEST_F(DataReductionProxyEventStoreTest, TestAddBypassActionEvent) {
TEST_F(DataReductionProxyEventStoreTest, TestAddBypassTypeEvent) {
EXPECT_EQ(0u, event_count());
EXPECT_EQ(nullptr, last_bypass_event());
- event_creator()->AddBypassTypeEvent(bound_net_log(), BYPASS_EVENT_TYPE_LONG,
- "GET", GURL(), false,
- base::TimeDelta::FromMinutes(1));
+ event_creator()->AddBypassTypeEvent(net_log_with_source(),
+ BYPASS_EVENT_TYPE_LONG, "GET", GURL(),
+ false, base::TimeDelta::FromMinutes(1));
EXPECT_EQ(1u, event_count());
EXPECT_EQ(1u, net_log()->GetSize());
net::TestNetLogEntry entry = GetSingleEntry();
- EXPECT_EQ(net::NetLog::TYPE_DATA_REDUCTION_PROXY_BYPASS_REQUESTED,
+ EXPECT_EQ(net::NetLogEventType::DATA_REDUCTION_PROXY_BYPASS_REQUESTED,
entry.type);
EXPECT_NE(nullptr, last_bypass_event());
}
@@ -138,18 +139,18 @@ TEST_F(DataReductionProxyEventStoreTest, TestAddProxyFallbackEvent) {
net::ERR_PROXY_CONNECTION_FAILED);
EXPECT_EQ(1u, event_count());
net::TestNetLogEntry entry = GetSingleEntry();
- EXPECT_EQ(net::NetLog::TYPE_DATA_REDUCTION_PROXY_FALLBACK, entry.type);
+ EXPECT_EQ(net::NetLogEventType::DATA_REDUCTION_PROXY_FALLBACK, entry.type);
}
TEST_F(DataReductionProxyEventStoreTest, TestBeginSecureProxyCheck) {
EXPECT_EQ(0u, event_count());
EXPECT_EQ(DataReductionProxyEventStorageDelegate::CHECK_UNKNOWN,
secure_proxy_check_state());
- event_creator()->BeginSecureProxyCheck(bound_net_log(), GURL());
+ event_creator()->BeginSecureProxyCheck(net_log_with_source(), GURL());
EXPECT_EQ(1u, event_count());
EXPECT_EQ(1u, net_log()->GetSize());
net::TestNetLogEntry entry = GetSingleEntry();
- EXPECT_EQ(net::NetLog::TYPE_DATA_REDUCTION_PROXY_CANARY_REQUEST,
+ EXPECT_EQ(net::NetLogEventType::DATA_REDUCTION_PROXY_CANARY_REQUEST,
entry.type);
EXPECT_EQ(DataReductionProxyEventStorageDelegate::CHECK_PENDING,
secure_proxy_check_state());
@@ -159,11 +160,12 @@ TEST_F(DataReductionProxyEventStoreTest, TestEndSecureProxyCheck) {
EXPECT_EQ(0u, event_count());
EXPECT_EQ(DataReductionProxyEventStorageDelegate::CHECK_UNKNOWN,
secure_proxy_check_state());
- event_creator()->EndSecureProxyCheck(bound_net_log(), 0, net::HTTP_OK, true);
+ event_creator()->EndSecureProxyCheck(net_log_with_source(), 0, net::HTTP_OK,
+ true);
EXPECT_EQ(1u, event_count());
EXPECT_EQ(1u, net_log()->GetSize());
net::TestNetLogEntry entry = GetSingleEntry();
- EXPECT_EQ(net::NetLog::TYPE_DATA_REDUCTION_PROXY_CANARY_REQUEST,
+ EXPECT_EQ(net::NetLogEventType::DATA_REDUCTION_PROXY_CANARY_REQUEST,
entry.type);
EXPECT_EQ(DataReductionProxyEventStorageDelegate::CHECK_SUCCESS,
secure_proxy_check_state());
@@ -196,13 +198,14 @@ TEST_F(DataReductionProxyEventStoreTest, TestEndSecureProxyCheckFailed) {
EXPECT_EQ(DataReductionProxyEventStorageDelegate::CHECK_UNKNOWN,
secure_proxy_check_state());
for (const auto& test : tests) {
- event_creator()->EndSecureProxyCheck(bound_net_log(), test.net_error,
+ event_creator()->EndSecureProxyCheck(net_log_with_source(), test.net_error,
test.http_response_code,
test.secure_proxy_check_succeeded);
EXPECT_EQ(expected_event_count, net_log()->GetSize()) << test.test_case;
EXPECT_EQ(expected_event_count++, event_count()) << test.test_case;
net::TestNetLogEntry entry = GetLatestEntry();
- EXPECT_EQ(net::NetLog::TYPE_DATA_REDUCTION_PROXY_CANARY_REQUEST, entry.type)
+ EXPECT_EQ(net::NetLogEventType::DATA_REDUCTION_PROXY_CANARY_REQUEST,
+ entry.type)
<< test.test_case;
EXPECT_EQ(test.secure_proxy_check_succeeded
? DataReductionProxyEventStorageDelegate::CHECK_SUCCESS
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
index f821a88240a..461e6d6b57b 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -30,8 +30,8 @@ const char kChromeProxyHeader[] = "chrome-proxy";
const char kActionValueDelimiter = '=';
const char kChromeProxyLoFiDirective[] = "q=low";
-const char kChromeProxyLoFiPreviewDirective[] = "q=preview";
-const char kChromeProxyLoFiIngorePreviewBlacklistDirective[] =
+const char kChromeProxyLitePageDirective[] = "q=preview";
+const char kChromeProxyLitePageIngoreBlacklistDirective[] =
"exp=ignore_preview_blacklist";
const char kChromeProxyActionBlockOnce[] = "block-once";
@@ -59,7 +59,7 @@ bool StartsWithActionPrefix(base::StringPiece header_value,
base::StringPiece action_prefix) {
DCHECK(!action_prefix.empty());
// A valid action does not include a trailing '='.
- DCHECK(action_prefix[action_prefix.size() - 1] != kActionValueDelimiter);
+ DCHECK(action_prefix.back() != kActionValueDelimiter);
return header_value.size() > action_prefix.size() + 1 &&
header_value[action_prefix.size()] == kActionValueDelimiter &&
@@ -79,12 +79,12 @@ const char* chrome_proxy_lo_fi_directive() {
return kChromeProxyLoFiDirective;
}
-const char* chrome_proxy_lo_fi_preview_directive() {
- return kChromeProxyLoFiPreviewDirective;
+const char* chrome_proxy_lite_page_directive() {
+ return kChromeProxyLitePageDirective;
}
-const char* chrome_proxy_lo_fi_ignore_preview_blacklist_directive() {
- return kChromeProxyLoFiIngorePreviewBlacklistDirective;
+const char* chrome_proxy_lite_page_ignore_blacklist_directive() {
+ return kChromeProxyLitePageIngoreBlacklistDirective;
}
bool GetDataReductionProxyActionValue(const net::HttpResponseHeaders* headers,
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
index 61c58be6147..b716b59841a 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
@@ -71,17 +71,17 @@ struct DataReductionProxyInfo {
// Gets the header used for data reduction proxy requests and responses.
const char* chrome_proxy_header();
-// Gets the Chrome-Proxy directive used by data reduction proxy Lo-Fi requests
-// and responses.
-const char* chrome_proxy_lo_fi_directive();
-
// Gets the Chrome-Proxy directive used by data reduction proxy Lo-Fi preview
// requests and responses.
-const char* chrome_proxy_lo_fi_preview_directive();
+const char* chrome_proxy_lo_fi_directive();
-// Gets the Chrome-Proxy directive used by data reduction proxy Lo-Fi preview
-// experiment to ignore the blacklist.
-const char* chrome_proxy_lo_fi_ignore_preview_blacklist_directive();
+// Gets the Chrome-Proxy directive used by data reduction proxy lite page
+// preview requests and responses.
+const char* chrome_proxy_lite_page_directive();
+
+// Gets the Chrome-Proxy directive used by data reduction proxy lite page
+// preview experiment to ignore the blacklist.
+const char* chrome_proxy_lite_page_ignore_blacklist_directive();
// Returns true if the Chrome-Proxy header is present and contains a bypass
// delay. Sets |proxy_info->bypass_duration| to the specified delay if greater
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
new file mode 100644
index 00000000000..a5ed2e43856
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
@@ -0,0 +1,32 @@
+// 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 "components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h"
+
+namespace data_reduction_proxy {
+
+DataReductionProxyPageLoadTiming::DataReductionProxyPageLoadTiming(
+ const base::Time& navigation_start,
+ const base::Optional<base::TimeDelta>& response_start,
+ const base::Optional<base::TimeDelta>& load_event_start,
+ const base::Optional<base::TimeDelta>& first_image_paint,
+ const base::Optional<base::TimeDelta>& first_contentful_paint,
+ const base::Optional<base::TimeDelta>& experimental_first_meaningful_paint,
+ const base::Optional<base::TimeDelta>&
+ parse_blocked_on_script_load_duration,
+ const base::Optional<base::TimeDelta>& parse_stop)
+ : navigation_start(navigation_start),
+ response_start(response_start),
+ load_event_start(load_event_start),
+ first_image_paint(first_image_paint),
+ first_contentful_paint(first_contentful_paint),
+ experimental_first_meaningful_paint(experimental_first_meaningful_paint),
+ parse_blocked_on_script_load_duration(
+ parse_blocked_on_script_load_duration),
+ parse_stop(parse_stop) {}
+
+DataReductionProxyPageLoadTiming::DataReductionProxyPageLoadTiming(
+ const DataReductionProxyPageLoadTiming& other) = default;
+
+} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
index d2d8416ac65..e9b023446fa 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PAGE_LOAD_TIMING_H
#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PAGE_LOAD_TIMING_H
+#include "base/optional.h"
#include "base/time/time.h"
namespace data_reduction_proxy {
@@ -13,31 +14,40 @@ namespace data_reduction_proxy {
struct DataReductionProxyPageLoadTiming {
DataReductionProxyPageLoadTiming(
const base::Time& navigation_start,
- const base::TimeDelta& response_start,
- const base::TimeDelta& load_event_start,
- const base::TimeDelta& first_image_paint,
- const base::TimeDelta& first_contentful_paint)
- : navigation_start(navigation_start),
- response_start(response_start),
- load_event_start(load_event_start),
- first_image_paint(first_image_paint),
- first_contentful_paint(first_contentful_paint) {}
+ const base::Optional<base::TimeDelta>& response_start,
+ const base::Optional<base::TimeDelta>& load_event_start,
+ const base::Optional<base::TimeDelta>& first_image_paint,
+ const base::Optional<base::TimeDelta>& first_contentful_paint,
+ const base::Optional<base::TimeDelta>&
+ experimental_first_meaningful_paint,
+ const base::Optional<base::TimeDelta>&
+ parse_blocked_on_script_load_duration,
+ const base::Optional<base::TimeDelta>& parse_stop);
+
+ DataReductionProxyPageLoadTiming(
+ const DataReductionProxyPageLoadTiming& other);
// Time that the navigation for the associated page was initiated.
const base::Time navigation_start;
- // All TimeDeltas are relative to navigation_start
+ // All TimeDeltas are relative to navigation_start.
// Time that the first byte of the response is received.
- const base::TimeDelta response_start;
+ const base::Optional<base::TimeDelta> response_start;
// Time immediately before the load event is fired.
- const base::TimeDelta load_event_start;
+ const base::Optional<base::TimeDelta> load_event_start;
// Time when the first image is painted.
- const base::TimeDelta first_image_paint;
+ const base::Optional<base::TimeDelta> first_image_paint;
// Time when the first contentful thing (image, text, etc.) is painted.
- const base::TimeDelta first_contentful_paint;
+ const base::Optional<base::TimeDelta> first_contentful_paint;
+ // (Experimental) Time when the page's primary content is painted.
+ const base::Optional<base::TimeDelta> experimental_first_meaningful_paint;
+ // Time that parsing was blocked by loading script.
+ const base::Optional<base::TimeDelta> parse_blocked_on_script_load_duration;
+ // Time when parsing completed.
+ const base::Optional<base::TimeDelta> parse_stop;
};
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index 67422212740..7392f2364e7 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -4,13 +4,13 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
+#include <map>
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
@@ -25,7 +25,7 @@ namespace {
const char kEnabled[] = "Enabled";
const char kControl[] = "Control";
const char kDisabled[] = "Disabled";
-const char kPreview[] = "Enabled_Preview";
+const char kLitePage[] = "Enabled_Preview";
const char kDefaultSpdyOrigin[] = "https://proxy.googlezip.net:443";
// A one-off change, until the Data Reduction Proxy configuration service is
// available.
@@ -56,24 +56,39 @@ const char kPingbackURL[] =
const char kServerExperimentsFieldTrial[] =
"DataReductionProxyServerExperiments";
+bool IsIncludedInFieldTrial(const std::string& name) {
+ return base::StartsWith(FieldTrialList::FindFullName(name), kEnabled,
+ base::CompareCase::SENSITIVE);
+}
+
+// Returns the variation value for |parameter_name|. If the value is
+// unavailable, |default_value| is returned.
+std::string GetStringValueForVariationParamWithDefaultValue(
+ const std::map<std::string, std::string>& variation_params,
+ const std::string& parameter_name,
+ const std::string& default_value) {
+ const auto it = variation_params.find(parameter_name);
+ if (it == variation_params.end())
+ return default_value;
+ return it->second;
+}
+
} // namespace
namespace data_reduction_proxy {
namespace params {
bool IsIncludedInPromoFieldTrial() {
- return FieldTrialList::FindFullName("DataCompressionProxyPromoVisibility")
- .find(kEnabled) == 0;
+ return IsIncludedInFieldTrial("DataCompressionProxyPromoVisibility");
}
bool IsIncludedInHoldbackFieldTrial() {
- return FieldTrialList::FindFullName("DataCompressionProxyHoldback")
- .find(kEnabled) == 0;
+ return IsIncludedInFieldTrial("DataCompressionProxyHoldback");
}
-bool IsIncludedInAndroidOnePromoFieldTrial(const char* build_fingerprint) {
- base::StringPiece fingerprint(build_fingerprint);
- return (fingerprint.find(kAndroidOneIdentifier) != std::string::npos);
+bool IsIncludedInAndroidOnePromoFieldTrial(
+ base::StringPiece build_fingerprint) {
+ return build_fingerprint.find(kAndroidOneIdentifier) != std::string::npos;
}
const char* GetTrustedSpdyProxyFieldTrialName() {
@@ -81,8 +96,7 @@ const char* GetTrustedSpdyProxyFieldTrialName() {
}
bool IsIncludedInTrustedSpdyProxyFieldTrial() {
- return base::FieldTrialList::FindFullName(GetTrustedSpdyProxyFieldTrialName())
- .find(kEnabled) == 0;
+ return IsIncludedInFieldTrial(GetTrustedSpdyProxyFieldTrialName());
}
const char* GetLoFiFieldTrialName() {
@@ -95,20 +109,19 @@ const char* GetLoFiFlagFieldTrialName() {
bool IsIncludedInLoFiEnabledFieldTrial() {
return !IsLoFiOnViaFlags() && !IsLoFiDisabledViaFlags() &&
- FieldTrialList::FindFullName(GetLoFiFieldTrialName()).find(kEnabled) ==
- 0;
+ IsIncludedInFieldTrial(GetLoFiFieldTrialName());
}
bool IsIncludedInLoFiControlFieldTrial() {
return !IsLoFiOnViaFlags() && !IsLoFiDisabledViaFlags() &&
- FieldTrialList::FindFullName(GetLoFiFieldTrialName()).find(kControl) ==
- 0;
+ base::StartsWith(FieldTrialList::FindFullName(GetLoFiFieldTrialName()),
+ kControl, base::CompareCase::SENSITIVE);
}
-bool IsIncludedInLoFiPreviewFieldTrial() {
+bool IsIncludedInLitePageFieldTrial() {
return !IsLoFiOnViaFlags() && !IsLoFiDisabledViaFlags() &&
- FieldTrialList::FindFullName(GetLoFiFieldTrialName()).find(kPreview) ==
- 0;
+ base::StartsWith(FieldTrialList::FindFullName(GetLoFiFieldTrialName()),
+ kLitePage, base::CompareCase::SENSITIVE);
}
bool IsIncludedInServerExperimentsFieldTrial() {
@@ -120,8 +133,9 @@ bool IsIncludedInServerExperimentsFieldTrial() {
}
bool IsIncludedInTamperDetectionExperiment() {
return IsIncludedInServerExperimentsFieldTrial() &&
- FieldTrialList::FindFullName(kServerExperimentsFieldTrial)
- .find("TamperDetection_Enabled") == 0;
+ base::StartsWith(
+ FieldTrialList::FindFullName(kServerExperimentsFieldTrial),
+ "TamperDetection_Enabled", base::CompareCase::SENSITIVE);
}
bool IsLoFiOnViaFlags() {
@@ -161,9 +175,9 @@ bool IsLoFiDisabledViaFlags() {
data_reduction_proxy::switches::kDataReductionProxyLoFiValueDisabled;
}
-bool AreLoFiPreviewsEnabledViaFlags() {
+bool AreLitePagesEnabledViaFlags() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
- data_reduction_proxy::switches::kEnableDataReductionProxyLoFiPreview);
+ data_reduction_proxy::switches::kEnableDataReductionProxyLitePage);
}
bool IsForcePingbackEnabledViaFlags() {
@@ -172,22 +186,27 @@ bool IsForcePingbackEnabledViaFlags() {
}
bool WarnIfNoDataReductionProxy() {
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- data_reduction_proxy::switches::
- kEnableDataReductionProxyBypassWarning)) {
- return true;
- }
- return false;
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ data_reduction_proxy::switches::kEnableDataReductionProxyBypassWarning);
}
bool IsIncludedInQuicFieldTrial() {
- return FieldTrialList::FindFullName(kQuicFieldTrial).find(kEnabled) == 0;
+ return IsIncludedInFieldTrial(kQuicFieldTrial);
}
const char* GetQuicFieldTrialName() {
return kQuicFieldTrial;
}
+bool IsZeroRttQuicEnabled() {
+ if (!IsIncludedInQuicFieldTrial())
+ return false;
+ std::map<std::string, std::string> params;
+ variations::GetVariationParams(GetQuicFieldTrialName(), &params);
+ return GetStringValueForVariationParamWithDefaultValue(
+ params, "enable_zero_rtt", "false") == "true";
+}
+
bool IsConfigClientEnabled() {
// Config client is enabled by default. It can be disabled only if Chromium
// belongs to a field trial group whose name starts with "Disabled".
@@ -332,14 +351,12 @@ DataReductionProxyTypeInfo::DataReductionProxyTypeInfo() : proxy_index(0) {}
DataReductionProxyTypeInfo::DataReductionProxyTypeInfo(
const DataReductionProxyTypeInfo& other) = default;
-DataReductionProxyTypeInfo::~DataReductionProxyTypeInfo(){
-}
+DataReductionProxyTypeInfo::~DataReductionProxyTypeInfo() {}
DataReductionProxyParams::DataReductionProxyParams(int flags)
: DataReductionProxyParams(flags, true) {}
-DataReductionProxyParams::~DataReductionProxyParams() {
-}
+DataReductionProxyParams::~DataReductionProxyParams() {}
DataReductionProxyParams::DataReductionProxyParams(int flags,
bool should_call_init)
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
index 57d4affe96c..c48ec854ec9 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PARAMS_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PARAMS_H_
+#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PARAMS_H_
+#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PARAMS_H_
#include <string>
#include <vector>
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h"
#include "net/proxy/proxy_server.h"
#include "url/gurl.h"
@@ -49,7 +50,7 @@ bool IsIncludedInTrustedSpdyProxyFieldTrial();
// Returns true if this client is part of the field trial that should display
// a promotion for the data reduction proxy on Android One devices.
-bool IsIncludedInAndroidOnePromoFieldTrial(const char* build_fingerprint);
+bool IsIncludedInAndroidOnePromoFieldTrial(base::StringPiece build_fingerprint);
// Returns the name of the Lo-Fi field trial.
const char* GetLoFiFieldTrialName();
@@ -68,7 +69,7 @@ bool IsIncludedInLoFiControlFieldTrial();
// Returns true if this client is part of the "Preview" group of the Lo-Fi field
// trial.
-bool IsIncludedInLoFiPreviewFieldTrial();
+bool IsIncludedInLitePageFieldTrial();
// Returns true if this client is part of the field trial that should enable
// server experiments for the data reduction proxy.
@@ -98,10 +99,10 @@ bool IsLoFiSlowConnectionsOnlyViaFlags();
// mode.
bool IsLoFiDisabledViaFlags();
-// Returns true if this client has the command line switch to enable Lo-Fi
-// previews. This means a preview should be requested instead of placeholders
-// whenever Lo-Fi mode is on.
-bool AreLoFiPreviewsEnabledViaFlags();
+// Returns true if this client has the command line switch to enable lite pages.
+// This means a preview should be requested instead of placeholders whenever
+// Lo-Fi mode is on.
+bool AreLitePagesEnabledViaFlags();
// Returns true if this client has the command line switch to enable forced
// pageload metrics pingbacks on every page load.
@@ -117,6 +118,9 @@ bool IsIncludedInQuicFieldTrial();
const char* GetQuicFieldTrialName();
+// Returns true if zero RTT for QUIC is enabled.
+bool IsZeroRttQuicEnabled();
+
// Returns true if the Data Reduction Proxy config client should be used.
bool IsConfigClientEnabled();
@@ -252,4 +256,5 @@ class DataReductionProxyParams : public DataReductionProxyConfigValues {
};
} // namespace data_reduction_proxy
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PARAMS_H_
+
+#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PARAMS_H_
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
index 50dcf4068f3..412e09555eb 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
@@ -334,7 +334,7 @@ TEST_F(DataReductionProxyParamsTest, LoFiEnabledFieldTrial) {
std::string trial_group_name;
bool expected_enabled;
bool expected_control;
- bool expected_preview_enabled;
+ bool expected_lite_page_enabled;
} tests[] = {
{"Enabled", true, false, false},
{"Enabled_Control", true, false, false},
@@ -353,8 +353,8 @@ TEST_F(DataReductionProxyParamsTest, LoFiEnabledFieldTrial) {
EXPECT_EQ(test.expected_control,
params::IsIncludedInLoFiControlFieldTrial())
<< test.trial_group_name;
- EXPECT_EQ(test.expected_preview_enabled,
- params::IsIncludedInLoFiPreviewFieldTrial())
+ EXPECT_EQ(test.expected_lite_page_enabled,
+ params::IsIncludedInLitePageFieldTrial())
<< test.trial_group_name;
}
}
@@ -365,7 +365,7 @@ TEST_F(DataReductionProxyParamsTest, LoFiControlFieldTrial) {
std::string trial_group_name;
bool expected_enabled;
bool expected_control;
- bool expected_preview_enabled;
+ bool expected_lite_page_enabled;
} tests[] = {
{"Control", false, true, false},
{"Control_Enabled", false, true, false},
@@ -384,8 +384,8 @@ TEST_F(DataReductionProxyParamsTest, LoFiControlFieldTrial) {
EXPECT_EQ(test.expected_control,
params::IsIncludedInLoFiControlFieldTrial())
<< test.trial_group_name;
- EXPECT_EQ(test.expected_preview_enabled,
- params::IsIncludedInLoFiPreviewFieldTrial())
+ EXPECT_EQ(test.expected_lite_page_enabled,
+ params::IsIncludedInLitePageFieldTrial())
<< test.trial_group_name;
}
}
@@ -396,7 +396,7 @@ TEST_F(DataReductionProxyParamsTest, LoFiPreviewFieldTrial) {
std::string trial_group_name;
bool expected_enabled;
bool expected_control;
- bool expected_preview_enabled;
+ bool expected_lite_page_enabled;
} tests[] = {
{"Enabled_Preview", true, false, true},
{"Enabled_Preview_Control", true, false, true},
@@ -415,12 +415,46 @@ TEST_F(DataReductionProxyParamsTest, LoFiPreviewFieldTrial) {
EXPECT_EQ(test.expected_control,
params::IsIncludedInLoFiControlFieldTrial())
<< test.trial_group_name;
- EXPECT_EQ(test.expected_preview_enabled,
- params::IsIncludedInLoFiPreviewFieldTrial())
+ EXPECT_EQ(test.expected_lite_page_enabled,
+ params::IsIncludedInLitePageFieldTrial())
<< test.trial_group_name;
}
}
+// Tests if the QUIC field trial is set correctly.
+TEST_F(DataReductionProxyParamsTest, QuicFieldTrial) {
+ const struct {
+ std::string trial_group_name;
+ bool expected_enabled;
+ std::string zero_rtt_param;
+ bool expected_zero_rtt;
+ } tests[] = {
+ {"Enabled", true, "true", true},
+ {"Enabled_Control", true, "true", true},
+ {"Enabled_Control", true, "false", false},
+ {"Enabled_Control", true, std::string(), false},
+ {"Control", false, "true", false},
+ {"Disabled", false, "false", false},
+ {"enabled", false, "false", false},
+ };
+
+ for (const auto& test : tests) {
+ variations::testing::ClearAllVariationParams();
+ std::map<std::string, std::string> variation_params;
+ variation_params["enable_zero_rtt"] = test.zero_rtt_param;
+ ASSERT_TRUE(variations::AssociateVariationParams(
+ params::GetQuicFieldTrialName(), test.trial_group_name,
+ variation_params));
+
+ base::FieldTrialList field_trial_list(nullptr);
+ base::FieldTrialList::CreateFieldTrial(params::GetQuicFieldTrialName(),
+ test.trial_group_name);
+
+ EXPECT_EQ(test.expected_enabled, params::IsIncludedInQuicFieldTrial());
+ EXPECT_EQ(test.expected_zero_rtt, params::IsZeroRttQuicEnabled());
+ }
+}
+
TEST_F(DataReductionProxyParamsTest, HoldbackEnabledFieldTrial) {
const struct {
std::string trial_group_name;
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
index b2c01d196ee..8bd6b35d628 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
@@ -199,13 +199,15 @@ const char kHttpOriginalContentLength[] = "http_original_content_length";
const char kLoFiImplicitOptOutEpoch[] =
"data_reduction_lo_fi.implicit_opt_out_epoch";
-// An integer pref that contains the number of times that "Load images" Lo-Fi
-// snackbar has been shown for the current session.
-const char kLoFiSnackbarsShownPerSession[] =
+// An integer pref that contains the number of times that "Load original" Lo-Fi
+// UI has been shown for the current session. Note the naming of the pref is due
+// to the fact that this UI was originally a snackbar, and has since been
+// changed.
+const char kLoFiUIShownPerSession[] =
"data_reduction_lo_fi.load_images_snackbars_shown_per_session";
-// An integer pref that contains the number of times that "Load images" has been
-// requested on the Lo-Fi snackbar for the current session.
+// An integer pref that contains the number of times that loading the images has
+// been requested from the Lo-Fi UI for the current session.
const char kLoFiLoadImagesPerSession[] =
"data_reduction_lo_fi.load_images_requests_per_session";
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
index d830a94b051..65cc8962e56 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
@@ -50,7 +50,7 @@ extern const char kDataReductionProxyWasEnabledBefore[];
extern const char kHttpOriginalContentLength[];
extern const char kHttpReceivedContentLength[];
extern const char kLoFiImplicitOptOutEpoch[];
-extern const char kLoFiSnackbarsShownPerSession[];
+extern const char kLoFiUIShownPerSession[];
extern const char kLoFiLoadImagesPerSession[];
extern const char kLoFiConsecutiveSessionDisables[];
extern const char kLoFiWasUsedThisSession[];
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
index dc65c529363..53fa471e550 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
@@ -79,11 +79,11 @@ const char kEnableDataReductionProxyBypassWarning[] =
const char kEnableDataReductionProxyCarrierTest[] =
"enable-data-reduction-proxy-carrier-test";
-// Enables preview mode for Lo-Fi. This means a preview should be requested
-// instead of placeholders whenever Lo-Fi mode is on. Lo-Fi must also be enabled
-// via a flag or field trial.
-const char kEnableDataReductionProxyLoFiPreview[] =
- "enable-data-reduction-proxy-lo-fi-preview";
+// Enables lite page from the data reduction proxy. This means a lite page
+// should be requested instead of placeholders whenever Lo-Fi mode is on. Lo-fi
+// must also be enabled via a flag or field trial.
+const char kEnableDataReductionProxyLitePage[] =
+ "enable-data-reduction-proxy-lite-page";
// Enables sending a pageload metrics pingback after every page load.
const char kEnableDataReductionProxyForcePingback[] =
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
index a6d8f85d384..c6af25c8060 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
@@ -31,8 +31,8 @@ extern const char kDataReductionProxyWarmupURL[];
extern const char kEnableDataReductionProxy[];
extern const char kEnableDataReductionProxyBypassWarning[];
extern const char kEnableDataReductionProxyCarrierTest[];
-extern const char kEnableDataReductionProxyLoFiPreview[];
extern const char kEnableDataReductionProxyForcePingback[];
+extern const char kEnableDataReductionProxyLitePage[];
} // namespace switches
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_util.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_util.cc
index cf7dea0b8ce..118c8096a15 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_util.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_util.cc
@@ -137,6 +137,28 @@ bool ApplyProxyConfigToProxyInfo(const net::ProxyConfig& proxy_config,
namespace protobuf_parser {
+PageloadMetrics_EffectiveConnectionType
+ProtoEffectiveConnectionTypeFromEffectiveConnectionType(
+ net::EffectiveConnectionType effective_connection_type) {
+ switch (effective_connection_type) {
+ case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
+ return PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+ case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
+ return PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_OFFLINE;
+ case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
+ return PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+ case net::EFFECTIVE_CONNECTION_TYPE_2G:
+ return PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_2G;
+ case net::EFFECTIVE_CONNECTION_TYPE_3G:
+ return PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_3G;
+ case net::EFFECTIVE_CONNECTION_TYPE_4G:
+ return PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_4G;
+ default:
+ NOTREACHED();
+ return PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+ }
+}
+
net::ProxyServer::Scheme SchemeFromProxyScheme(
ProxyServer_ProxyScheme proxy_scheme) {
switch (proxy_scheme) {
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_util.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_util.h
index b06e279f45f..340c74afd13 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_util.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_util.h
@@ -9,6 +9,8 @@
#include <string>
#include "components/data_reduction_proxy/proto/client_config.pb.h"
+#include "components/data_reduction_proxy/proto/pageload_metrics.pb.h"
+#include "net/nqe/effective_connection_type.h"
#include "net/proxy/proxy_retry_info.h"
#include "net/proxy/proxy_server.h"
#include "url/gurl.h"
@@ -89,6 +91,16 @@ bool ApplyProxyConfigToProxyInfo(const net::ProxyConfig& proxy_config,
namespace protobuf_parser {
+static_assert(net::EFFECTIVE_CONNECTION_TYPE_LAST == 6,
+ "If net::EFFECTIVE_CONNECTION_TYPE changes, "
+ "PageloadMetrics_EffectiveConnectionType needs to be updated.");
+
+// Returns the PageloadMetrics_EffectiveConnection equivalent of
+// |effective_connection_type|.
+PageloadMetrics_EffectiveConnectionType
+ProtoEffectiveConnectionTypeFromEffectiveConnectionType(
+ net::EffectiveConnectionType effective_connection_type);
+
// Returns the |net::ProxyServer::Scheme| for a ProxyServer_ProxyScheme.
net::ProxyServer::Scheme SchemeFromProxyScheme(
ProxyServer_ProxyScheme proxy_scheme);
diff --git a/chromium/components/data_reduction_proxy/core/common/data_savings_recorder.h b/chromium/components/data_reduction_proxy/core/common/data_savings_recorder.h
new file mode 100644
index 00000000000..a96cf5984be
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/core/common/data_savings_recorder.h
@@ -0,0 +1,30 @@
+// 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 COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_SAVINGS_RECORDER_H_
+#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_SAVINGS_RECORDER_H_
+
+#include <stdint.h>
+
+#include <string>
+
+namespace data_reduction_proxy {
+
+// An interface that will record data savings based on the amount of data used,
+// the original size of the data, and the request type.
+class DataSavingsRecorder {
+ public:
+ // Records detailed data usage. Assumes |data_used| is recorded already by
+ // previous handling of URLRequests. Also records daily data savings
+ // statistics to prefs and reports data savings UMA. |data_used| and
+ // |original_size| are measured in bytes.
+ // Returns true if data savings was recorded.
+ virtual bool UpdateDataSavings(const std::string& data_usage_host,
+ int64_t data_used,
+ int64_t original_size) = 0;
+};
+
+} // namespace data_reduction_proxy
+
+#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_SAVINGS_RECORDER_H_
diff --git a/chromium/components/data_reduction_proxy/core/common/lofi_decider.h b/chromium/components/data_reduction_proxy/core/common/lofi_decider.h
index 1a66aad4c56..c1863e951a8 100644
--- a/chromium/components/data_reduction_proxy/core/common/lofi_decider.h
+++ b/chromium/components/data_reduction_proxy/core/common/lofi_decider.h
@@ -26,9 +26,8 @@ class LoFiDecider {
// Returns true when Lo-Fi mode is on for the given |request|. If the
// |request| is using Lo-Fi mode, adds the "q=low" directive to the |headers|.
- // If the |request| is using Lo-Fi preview mode, and it is a main frame
- // request adds the "q=preview" and it is a main frame request directive to
- // the |headers|.
+ // If the |request| is using Lo-Fi mode, lite pages are enabled, and it is a
+ // main frame request adds the "q=preview" directive to the |headers|.
virtual bool MaybeAddLoFiDirectiveToHeaders(
const net::URLRequest& request,
net::HttpRequestHeaders* headers) const = 0;
diff --git a/chromium/components/data_reduction_proxy/core/common/lofi_ui_service.h b/chromium/components/data_reduction_proxy/core/common/lofi_ui_service.h
index d22473a01f4..656dab4de9b 100644
--- a/chromium/components/data_reduction_proxy/core/common/lofi_ui_service.h
+++ b/chromium/components/data_reduction_proxy/core/common/lofi_ui_service.h
@@ -19,10 +19,8 @@ class LoFiUIService {
public:
virtual ~LoFiUIService() {}
- // Notifies the UI thread that |request| has a Lo-Fi response. |is_preview|
- // indicates whether the response was a Lo-Fi preview response.
- virtual void OnLoFiReponseReceived(const net::URLRequest& request,
- bool is_preview) = 0;
+ // Notifies the UI thread that |request| has a Lo-Fi response.
+ virtual void OnLoFiReponseReceived(const net::URLRequest& request) = 0;
};
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/proto/data_store.proto b/chromium/components/data_reduction_proxy/proto/data_store.proto
index 4bfdc39db3f..2bb7c7272a8 100644
--- a/chromium/components/data_reduction_proxy/proto/data_store.proto
+++ b/chromium/components/data_reduction_proxy/proto/data_store.proto
@@ -10,16 +10,6 @@ option optimize_for = LITE_RUNTIME;
package data_reduction_proxy;
-enum ConnectionType {
- CONNECTION_UNKNOWN = 0;
- CONNECTION_ETHERNET = 1;
- CONNECTION_WIFI = 2;
- CONNECTION_2G = 3;
- CONNECTION_3G = 4;
- CONNECTION_4G = 5;
- CONNECTION_BLUETOOTH = 6;
-};
-
// Contains data usage for an interval of time.
message DataUsageBucket {
repeated PerConnectionDataUsage connection_usage = 1;
diff --git a/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto b/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto
index b6240cfcdd8..cd9d1420b25 100644
--- a/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto
+++ b/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto
@@ -14,18 +14,31 @@ package data_reduction_proxy;
message RecordPageloadMetricsRequest {
// The pageload metrics to record.
repeated PageloadMetrics pageloads = 1;
+ // Time metrics were sent.
+ optional Timestamp metrics_sent_time = 2;
}
// Metrics for a single pageload.
message PageloadMetrics {
+ reserved 3;
+
+ // The possible effective connection type values.
+ // See //net/nqe/effective_connection_type.h for the detailed description of
+ // each of the enum values.
+ enum EffectiveConnectionType {
+ EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0;
+ EFFECTIVE_CONNECTION_TYPE_OFFLINE = 1;
+ EFFECTIVE_CONNECTION_TYPE_SLOW_2G = 2;
+ EFFECTIVE_CONNECTION_TYPE_2G = 3;
+ EFFECTIVE_CONNECTION_TYPE_3G = 4;
+ EFFECTIVE_CONNECTION_TYPE_4G = 5;
+ };
+
// The session key used to load the page.
optional string session_key = 1;
// The time at which the first request of the pageload was made, according to
// the client's clock.
optional Timestamp first_request_time = 2;
- // The time at which the last request of the pageload was made, according to
- // the client's clock.
- optional Timestamp last_request_time = 3;
// The URL of the main page request.
optional string first_request_url = 4;
// The URL of the last request.
@@ -46,4 +59,17 @@ message PageloadMetrics {
// The sum of (compressed) content-length, over resources that were not loaded
// from browser cache.
optional int32 compressed_page_size_bytes = 11;
+
+ // The effective connection type at the start of the navigation.
+ optional EffectiveConnectionType effective_connection_type = 12;
+
+ // The amount of time the parser was blocked by loading script.
+ optional Duration parse_blocked_on_script_load_duration = 13;
+
+ // Time until parsing finished.
+ optional Duration parse_stop = 14;
+
+ // Time to first meaningful paint. This measure is unstable and will change
+ // over time.
+ optional Duration experimental_time_to_first_meaningful_paint = 15;
}
diff --git a/chromium/components/data_usage.gypi b/chromium/components/data_usage.gypi
deleted file mode 100644
index 6fcef19dbdd..00000000000
--- a/chromium/components/data_usage.gypi
+++ /dev/null
@@ -1,44 +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.
-{
- 'targets': [
- {
- 'target_name': 'data_usage_core',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'data_usage/core/data_use.cc',
- 'data_usage/core/data_use.h',
- 'data_usage/core/data_use_aggregator.cc',
- 'data_usage/core/data_use_aggregator.h',
- 'data_usage/core/data_use_amortizer.h',
- 'data_usage/core/data_use_annotator.h',
- ]
- },
- ],
- 'conditions': [
- ['OS=="android"', {
- 'targets': [
- {
- 'target_name': 'data_usage_android',
- 'type': 'static_library',
- 'dependencies': [
- ':data_usage_core',
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'data_usage/android/traffic_stats_amortizer.cc',
- 'data_usage/android/traffic_stats_amortizer.h',
- ]
- },
- ]
- }], # OS=="android"
- ],
-}
diff --git a/chromium/components/data_usage/core/BUILD.gn b/chromium/components/data_usage/core/BUILD.gn
index 4d4a1aacde1..42829fe7884 100644
--- a/chromium/components/data_usage/core/BUILD.gn
+++ b/chromium/components/data_usage/core/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("core") {
+static_library("core") {
sources = [
"data_use.cc",
"data_use.h",
diff --git a/chromium/components/data_usage/core/data_use_aggregator_unittest.cc b/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
index e3d121f2bc4..9559e69698a 100644
--- a/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
+++ b/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
@@ -289,7 +289,7 @@ class DataUseAggregatorTest : public testing::Test {
reporting_network_delegate_->set_data_use_context_map(data_use_context_map);
request->Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
return request;
}
diff --git a/chromium/components/data_use_measurement.gypi b/chromium/components/data_use_measurement.gypi
deleted file mode 100644
index 8b0c4900ee8..00000000000
--- a/chromium/components/data_use_measurement.gypi
+++ /dev/null
@@ -1,39 +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.
-{
- 'targets': [
- {
- 'target_name': 'data_use_measurement_core',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- ],
- 'sources': [
- 'data_use_measurement/core/data_use_user_data.cc',
- 'data_use_measurement/core/data_use_user_data.h',
- ]
- },
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'targets': [
- {
- 'target_name': 'data_use_measurement_content',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../net/net.gyp:net',
- 'data_use_measurement_core',
- ],
- 'sources': [
- 'data_use_measurement/content/data_use_measurement.cc',
- 'data_use_measurement/content/data_use_measurement.h',
- ]
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/data_use_measurement/OWNERS b/chromium/components/data_use_measurement/OWNERS
index f63ec14c9c2..8e1d021ac12 100644
--- a/chromium/components/data_use_measurement/OWNERS
+++ b/chromium/components/data_use_measurement/OWNERS
@@ -1,2 +1,4 @@
-sclittle@chromium.org
bengr@chromium.org
+kundaji@chromium.org
+rajendrant@chromium.org
+sclittle@chromium.org
diff --git a/chromium/components/data_use_measurement/content/BUILD.gn b/chromium/components/data_use_measurement/content/BUILD.gn
index f4a7f647a32..fcad46a2dc4 100644
--- a/chromium/components/data_use_measurement/content/BUILD.gn
+++ b/chromium/components/data_use_measurement/content/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("content") {
+static_library("content") {
sources = [
"data_use_measurement.cc",
"data_use_measurement.h",
@@ -15,6 +15,7 @@ source_set("content") {
"//net",
]
}
+
source_set("unit_tests") {
sources = [
"data_use_measurement_unittest.cc",
diff --git a/chromium/components/data_use_measurement/content/data_use_measurement.cc b/chromium/components/data_use_measurement/content/data_use_measurement.cc
index e45368ae1b6..9b296aa540f 100644
--- a/chromium/components/data_use_measurement/content/data_use_measurement.cc
+++ b/chromium/components/data_use_measurement/content/data_use_measurement.cc
@@ -8,12 +8,17 @@
#include "base/metrics/sparse_histogram.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
#include "content/public/browser/resource_request_info.h"
#include "net/base/network_change_notifier.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
+#if defined(OS_ANDROID)
+#include "net/android/traffic_stats.h"
+#endif
+
namespace data_use_measurement {
namespace {
@@ -42,6 +47,20 @@ void IncreaseSparseHistogramByValue(const std::string& name,
histogram->AddCount(sample, value);
}
+#if defined(OS_ANDROID)
+void IncrementLatencyHistogramByCount(const std::string& name,
+ const base::TimeDelta& latency,
+ int64_t count) {
+ base::HistogramBase* histogram_pointer = base::Histogram::FactoryTimeGet(
+ name,
+ base::TimeDelta::FromMilliseconds(1), // Minimum sample
+ base::TimeDelta::FromHours(1), // Maximum sample
+ 50, // Bucket count.
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram_pointer->AddCount(latency.InMilliseconds(), count);
+}
+#endif
+
} // namespace
DataUseMeasurement::DataUseMeasurement(
@@ -52,62 +71,141 @@ DataUseMeasurement::DataUseMeasurement(
app_state_(base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES),
app_listener_(new base::android::ApplicationStatusListener(
base::Bind(&DataUseMeasurement::OnApplicationStateChange,
- base::Unretained(this))))
+ base::Unretained(this)))),
+ rx_bytes_os_(0),
+ tx_bytes_os_(0),
+ bytes_transferred_since_last_traffic_stats_query_(0),
+ no_reads_since_background_(false)
#endif
{
}
DataUseMeasurement::~DataUseMeasurement(){};
-void DataUseMeasurement::ReportDataUseUMA(
- const net::URLRequest* request) const {
+void DataUseMeasurement::OnBeforeURLRequest(net::URLRequest* request) {
+ DataUseUserData* data_use_user_data = reinterpret_cast<DataUseUserData*>(
+ request->GetUserData(DataUseUserData::kUserDataKey));
+ if (!data_use_user_data) {
+ data_use_user_data = new DataUseUserData(
+ DataUseUserData::ServiceName::NOT_TAGGED, CurrentAppState());
+ request->SetUserData(DataUseUserData::kUserDataKey, data_use_user_data);
+ }
+}
- // Counts rely on URLRequest::GetTotalReceivedBytes() and
- // URLRequest::GetTotalSentBytes(), which does not include the send path,
- // network layer overhead, TLS overhead, and DNS.
- // TODO(amohammadkhan): Make these measured bytes more in line with number of
- // bytes in lower levels.
- int64_t total_upload_bytes = request->GetTotalSentBytes();
- int64_t total_received_bytes = request->GetTotalReceivedBytes();
- bool is_user_traffic = IsUserInitiatedRequest(request);
+void DataUseMeasurement::OnBeforeRedirect(const net::URLRequest& request,
+ const GURL& new_location) {
+ // Recording data use of request on redirects.
+ // TODO(rajendrant): May not be needed when http://crbug/651957 is fixed.
+ UpdateDataUsePrefs(request);
+}
+
+void DataUseMeasurement::OnNetworkBytesReceived(const net::URLRequest& request,
+ int64_t bytes_received) {
+ UMA_HISTOGRAM_COUNTS("DataUse.BytesReceived.Delegate", bytes_received);
+ ReportDataUseUMA(request, DOWNSTREAM, bytes_received);
+#if defined(OS_ANDROID)
+ bytes_transferred_since_last_traffic_stats_query_ += bytes_received;
+#endif
+}
+
+void DataUseMeasurement::OnNetworkBytesSent(const net::URLRequest& request,
+ int64_t bytes_sent) {
+ UMA_HISTOGRAM_COUNTS("DataUse.BytesSent.Delegate", bytes_sent);
+ ReportDataUseUMA(request, UPSTREAM, bytes_sent);
+#if defined(OS_ANDROID)
+ bytes_transferred_since_last_traffic_stats_query_ += bytes_sent;
+#endif
+}
+void DataUseMeasurement::OnCompleted(const net::URLRequest& request,
+ bool started) {
+ // TODO(amohammadkhan): Verify that there is no double recording in data use
+ // of redirected requests.
+ UpdateDataUsePrefs(request);
+#if defined(OS_ANDROID)
+ MaybeRecordNetworkBytesOS();
+#endif
+}
+
+void DataUseMeasurement::ReportDataUseUMA(const net::URLRequest& request,
+ TrafficDirection dir,
+ int64_t bytes) {
+ bool is_user_traffic = IsUserInitiatedRequest(request);
bool is_connection_cellular =
net::NetworkChangeNotifier::IsConnectionCellular(
net::NetworkChangeNotifier::GetConnectionType());
+
+ DataUseUserData* attached_service_data = static_cast<DataUseUserData*>(
+ request.GetUserData(DataUseUserData::kUserDataKey));
+ DataUseUserData::ServiceName service_name = DataUseUserData::NOT_TAGGED;
+ DataUseUserData::AppState old_app_state = DataUseUserData::FOREGROUND;
+ DataUseUserData::AppState new_app_state = DataUseUserData::UNKNOWN;
+
+ if (attached_service_data) {
+ service_name = attached_service_data->service_name();
+ old_app_state = attached_service_data->app_state();
+ }
+ if (old_app_state == CurrentAppState())
+ new_app_state = old_app_state;
+
+ if (attached_service_data && old_app_state != new_app_state)
+ attached_service_data->set_app_state(CurrentAppState());
+
RecordUMAHistogramCount(
GetHistogramName(is_user_traffic ? "DataUse.TrafficSize.User"
: "DataUse.TrafficSize.System",
- UPSTREAM, is_connection_cellular),
- total_upload_bytes);
- RecordUMAHistogramCount(
- GetHistogramName(is_user_traffic ? "DataUse.TrafficSize.User"
- : "DataUse.TrafficSize.System",
- DOWNSTREAM, is_connection_cellular),
- total_received_bytes);
+ dir, new_app_state, is_connection_cellular),
+ bytes);
- DataUseUserData* attached_service_data = reinterpret_cast<DataUseUserData*>(
- request->GetUserData(DataUseUserData::kUserDataKey));
+ if (!is_user_traffic) {
+ ReportDataUsageServices(service_name, dir, new_app_state,
+ is_connection_cellular, bytes);
+ }
+#if defined(OS_ANDROID)
+ if (dir == DOWNSTREAM && CurrentAppState() == DataUseUserData::BACKGROUND) {
+ DCHECK(!last_app_background_time_.is_null());
+
+ const base::TimeDelta time_since_background =
+ base::TimeTicks::Now() - last_app_background_time_;
+ IncrementLatencyHistogramByCount(
+ is_user_traffic ? "DataUse.BackgroundToDataRecievedPerByte.User"
+ : "DataUse.BackgroundToDataRecievedPerByte.System",
+ time_since_background, bytes);
+ if (no_reads_since_background_) {
+ no_reads_since_background_ = false;
+ IncrementLatencyHistogramByCount(
+ is_user_traffic ? "DataUse.BackgroundToFirstDownstream.User"
+ : "DataUse.BackgroundToFirstDownstream.System",
+ time_since_background, 1);
+ }
+ }
+#endif
+}
+
+void DataUseMeasurement::UpdateDataUsePrefs(
+ const net::URLRequest& request) const {
+ bool is_connection_cellular =
+ net::NetworkChangeNotifier::IsConnectionCellular(
+ net::NetworkChangeNotifier::GetConnectionType());
+
+ DataUseUserData* attached_service_data = static_cast<DataUseUserData*>(
+ request.GetUserData(DataUseUserData::kUserDataKey));
DataUseUserData::ServiceName service_name =
attached_service_data ? attached_service_data->service_name()
: DataUseUserData::NOT_TAGGED;
- if (!is_user_traffic) {
- ReportDataUsageServices(service_name, UPSTREAM, is_connection_cellular,
- total_upload_bytes);
- ReportDataUsageServices(service_name, DOWNSTREAM, is_connection_cellular,
- total_received_bytes);
- }
// Update data use prefs for cellular connections.
if (!metrics_data_use_forwarder_.is_null()) {
metrics_data_use_forwarder_.Run(
- attached_service_data->GetServiceNameAsString(service_name),
- total_upload_bytes + total_received_bytes, is_connection_cellular);
+ DataUseUserData::GetServiceNameAsString(service_name),
+ request.GetTotalSentBytes() + request.GetTotalReceivedBytes(),
+ is_connection_cellular);
}
}
// static
bool DataUseMeasurement::IsUserInitiatedRequest(
- const net::URLRequest* request) {
+ const net::URLRequest& request) {
// Having ResourceRequestInfo in the URL request is a sign that the request is
// for a web content from user. For now we could add a condition to check
// ProcessType in info is content::PROCESS_TYPE_RENDERER, but it won't be
@@ -116,33 +214,36 @@ bool DataUseMeasurement::IsUserInitiatedRequest(
// with upcoming changes in PlzNavigate.
// TODO(rajendrant): Verify this condition for different use cases. See
// crbug.com/626063.
- return content::ResourceRequestInfo::ForRequest(request) != nullptr;
+ return content::ResourceRequestInfo::ForRequest(&request) != nullptr;
}
#if defined(OS_ANDROID)
void DataUseMeasurement::OnApplicationStateChangeForTesting(
base::android::ApplicationState application_state) {
- app_state_ = application_state;
+ OnApplicationStateChange(application_state);
}
#endif
-DataUseMeasurement::AppState DataUseMeasurement::CurrentAppState() const {
+DataUseUserData::AppState DataUseMeasurement::CurrentAppState() const {
#if defined(OS_ANDROID)
if (app_state_ != base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES)
- return BACKGROUND;
+ return DataUseUserData::BACKGROUND;
#endif
// If the OS is not Android, all the requests are considered Foreground.
- return FOREGROUND;
+ return DataUseUserData::FOREGROUND;
}
std::string DataUseMeasurement::GetHistogramName(
const char* prefix,
TrafficDirection dir,
+ DataUseUserData::AppState app_state,
bool is_connection_cellular) const {
- AppState app_state = CurrentAppState();
return base::StringPrintf(
"%s.%s.%s.%s", prefix, dir == UPSTREAM ? "Upstream" : "Downstream",
- app_state == BACKGROUND ? "Background" : "Foreground",
+ app_state == DataUseUserData::UNKNOWN
+ ? "Unknown"
+ : (app_state == DataUseUserData::FOREGROUND ? "Foreground"
+ : "Background"),
is_connection_cellular ? "Cellular" : "NotCellular");
}
@@ -150,12 +251,52 @@ std::string DataUseMeasurement::GetHistogramName(
void DataUseMeasurement::OnApplicationStateChange(
base::android::ApplicationState application_state) {
app_state_ = application_state;
+ if (app_state_ != base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
+ last_app_background_time_ = base::TimeTicks::Now();
+ no_reads_since_background_ = true;
+ MaybeRecordNetworkBytesOS();
+ } else {
+ last_app_background_time_ = base::TimeTicks();
+ }
+}
+
+void DataUseMeasurement::MaybeRecordNetworkBytesOS() {
+ // Minimum number of bytes that should be reported by the network delegate
+ // before Android's TrafficStats API is queried (if Chrome is not in
+ // background). This reduces the overhead of repeatedly calling the API.
+ static const int64_t kMinDelegateBytes = 25000;
+
+ if (bytes_transferred_since_last_traffic_stats_query_ < kMinDelegateBytes &&
+ CurrentAppState() == DataUseUserData::FOREGROUND) {
+ return;
+ }
+ bytes_transferred_since_last_traffic_stats_query_ = 0;
+ int64_t bytes = 0;
+ // Query Android traffic stats directly instead of registering with the
+ // DataUseAggregator since the latter does not provide notifications for
+ // the incognito traffic.
+ if (net::android::traffic_stats::GetCurrentUidRxBytes(&bytes)) {
+ if (rx_bytes_os_ != 0) {
+ DCHECK_GE(bytes, rx_bytes_os_);
+ UMA_HISTOGRAM_COUNTS("DataUse.BytesReceived.OS", bytes - rx_bytes_os_);
+ }
+ rx_bytes_os_ = bytes;
+ }
+
+ if (net::android::traffic_stats::GetCurrentUidTxBytes(&bytes)) {
+ if (tx_bytes_os_ != 0) {
+ DCHECK_GE(bytes, tx_bytes_os_);
+ UMA_HISTOGRAM_COUNTS("DataUse.BytesSent.OS", bytes - tx_bytes_os_);
+ }
+ tx_bytes_os_ = bytes;
+ }
}
#endif
void DataUseMeasurement::ReportDataUsageServices(
DataUseUserData::ServiceName service,
TrafficDirection dir,
+ DataUseUserData::AppState app_state,
bool is_connection_cellular,
int64_t message_size) const {
RecordUMAHistogramCount(
@@ -163,7 +304,7 @@ void DataUseMeasurement::ReportDataUsageServices(
message_size);
if (message_size > 0) {
IncreaseSparseHistogramByValue(
- GetHistogramName("DataUse.MessageSize.AllServices", dir,
+ GetHistogramName("DataUse.MessageSize.AllServices", dir, app_state,
is_connection_cellular),
service, message_size);
}
diff --git a/chromium/components/data_use_measurement/content/data_use_measurement.h b/chromium/components/data_use_measurement/content/data_use_measurement.h
index cb344fa2b6a..777a50a3623 100644
--- a/chromium/components/data_use_measurement/content/data_use_measurement.h
+++ b/chromium/components/data_use_measurement/content/data_use_measurement.h
@@ -12,6 +12,7 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/metrics/data_use_tracker.h"
@@ -20,6 +21,8 @@
#include "base/android/application_status_listener.h"
#endif
+class GURL;
+
namespace net {
class URLRequest;
}
@@ -38,11 +41,23 @@ class DataUseMeasurement {
const metrics::UpdateUsagePrefCallbackType& metrics_data_use_forwarder);
~DataUseMeasurement();
- // Records the data use of the |request|, thus |request| must be non-null.
- void ReportDataUseUMA(const net::URLRequest* request) const;
+ // Called before a request is sent.
+ void OnBeforeURLRequest(net::URLRequest* request);
+
+ // Called right after a redirect response code was received for |request|.
+ void OnBeforeRedirect(const net::URLRequest& request,
+ const GURL& new_location);
+
+ // Called when data is received or sent on the network, respectively.
+ void OnNetworkBytesReceived(const net::URLRequest& request,
+ int64_t bytes_received);
+ void OnNetworkBytesSent(const net::URLRequest& request, int64_t bytes_sent);
+
+ // Indicates that |request| has been completed or failed.
+ void OnCompleted(const net::URLRequest& request, bool started);
// Returns true if the URLRequest |request| is initiated by user traffic.
- static bool IsUserInitiatedRequest(const net::URLRequest* request);
+ static bool IsUserInitiatedRequest(const net::URLRequest& request);
#if defined(OS_ANDROID)
// This function should just be used for testing purposes. A change in
@@ -52,16 +67,16 @@ class DataUseMeasurement {
#endif
private:
+ friend class DataUseMeasurementTest;
+ FRIEND_TEST_ALL_PREFIXES(DataUseMeasurementTest,
+ TimeOfBackgroundDownstreamBytes);
+
// Specifies that data is received or sent, respectively.
enum TrafficDirection { DOWNSTREAM, UPSTREAM };
- // The state of the application. Only available on Android and on other
- // platforms it is always FOREGROUND.
- enum AppState { BACKGROUND, FOREGROUND };
-
// Returns the current application state (Foreground or Background). It always
// returns Foreground if Chrome is not running on Android.
- AppState CurrentAppState() const;
+ DataUseUserData::AppState CurrentAppState() const;
// Makes the full name of the histogram. It is made from |prefix| and suffix
// which is made based on network and application status. suffix is a string
@@ -69,8 +84,11 @@ class DataUseMeasurement {
// ("Downstream") path, whether the app was in the "Foreground" or
// "Background", and whether a "Cellular" or "WiFi" network was use. For
// example, "Prefix.Upstream.Foreground.Cellular" is a possible output.
+ // |app_state| indicates the app state which can be foreground, background, or
+ // unknown.
std::string GetHistogramName(const char* prefix,
TrafficDirection dir,
+ DataUseUserData::AppState app_state,
bool is_connection_cellular) const;
#if defined(OS_ANDROID)
@@ -78,15 +96,32 @@ class DataUseMeasurement {
// and vice versa.
void OnApplicationStateChange(
base::android::ApplicationState application_state);
+
+ // Records the count of bytes received and sent by Chrome on the network as
+ // reported by the operating system.
+ void MaybeRecordNetworkBytesOS();
#endif
+ // Records the data use of the |request|, thus |request| must be non-null.
+ // |dir| is the direction (which is upstream or downstream) and |bytes| is the
+ // number of bytes in the direction.
+ void ReportDataUseUMA(const net::URLRequest& request,
+ TrafficDirection dir,
+ int64_t bytes);
+
+ // Updates the data use of the |request|, thus |request| must be non-null.
+ void UpdateDataUsePrefs(const net::URLRequest& request) const;
+
// A helper function used to record data use of services. It gets the size of
// exchanged message, its direction (which is upstream or downstream) and
// reports to two histogram groups. DataUse.MessageSize.ServiceName and
// DataUse.Services.{Dimensions}. In the second one, services are buckets.
+ // |app_state| indicates the app state which can be foreground, background, or
+ // unknown.
void ReportDataUsageServices(
data_use_measurement::DataUseUserData::ServiceName service,
TrafficDirection dir,
+ DataUseUserData::AppState app_state,
bool is_connection_cellular,
int64_t message_size) const;
@@ -104,6 +139,24 @@ class DataUseMeasurement {
// ApplicationStatusListener used to monitor whether the application is in the
// foreground or in the background. It is owned by DataUseMeasurement.
std::unique_ptr<base::android::ApplicationStatusListener> app_listener_;
+
+ // Number of bytes received and sent by Chromium as reported by the operating
+ // system when it was last queried for traffic statistics. Set to 0 if the
+ // operating system was never queried.
+ int64_t rx_bytes_os_;
+ int64_t tx_bytes_os_;
+
+ // Number of bytes received and sent by Chromium as reported by the network
+ // delegate since the operating system was last queried for traffic
+ // statistics.
+ int64_t bytes_transferred_since_last_traffic_stats_query_;
+
+ // The time at which Chromium app state changed to background. Can be null if
+ // app is not in background.
+ base::TimeTicks last_app_background_time_;
+
+ // True if app is in background and first network read has not yet happened.
+ bool no_reads_since_background_;
#endif
DISALLOW_COPY_AND_ASSIGN(DataUseMeasurement);
diff --git a/chromium/components/data_use_measurement/content/data_use_measurement_unittest.cc b/chromium/components/data_use_measurement/content/data_use_measurement_unittest.cc
index dba8231b467..de40494d97a 100644
--- a/chromium/components/data_use_measurement/content/data_use_measurement_unittest.cc
+++ b/chromium/components/data_use_measurement/content/data_use_measurement_unittest.cc
@@ -8,6 +8,8 @@
#include <string>
#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/test/histogram_tester.h"
#include "build/build_config.h"
#include "content/public/browser/resource_request_info.h"
@@ -36,9 +38,8 @@ class DataUseMeasurementTest : public testing::Test {
net::NetworkChangeNotifier::GetConnectionType()));
}
- // Sends a request and reports data use attaching either user data or service
- // data based on |is_user_request|.
- void SendRequest(bool is_user_request) {
+ // Creates a test request.
+ std::unique_ptr<net::URLRequest> CreateTestRequest(bool is_user_request) {
net::TestDelegate test_delegate;
InitializeContext();
net::MockRead reads[] = {net::MockRead("HTTP/1.1 200 OK\r\n"
@@ -54,7 +55,8 @@ class DataUseMeasurementTest : public testing::Test {
request->SetUserData(
data_use_measurement::DataUseUserData::kUserDataKey,
new data_use_measurement::DataUseUserData(
- data_use_measurement::DataUseUserData::SUGGESTIONS));
+ data_use_measurement::DataUseUserData::SUGGESTIONS,
+ data_use_measurement_.CurrentAppState()));
} else {
content::ResourceRequestInfo::AllocateForTesting(
request.get(), content::RESOURCE_TYPE_MAIN_FRAME, nullptr, -2, -2, -2,
@@ -62,9 +64,19 @@ class DataUseMeasurementTest : public testing::Test {
}
request->Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
+ return request;
+ }
- data_use_measurement_.ReportDataUseUMA(request.get());
+ // Sends a request and reports data use attaching either user data or service
+ // data based on |is_user_request|.
+ void SendRequest(bool is_user_request) {
+ std::unique_ptr<net::URLRequest> request =
+ CreateTestRequest(is_user_request);
+ data_use_measurement_.OnBeforeURLRequest(request.get());
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
+ data_use_measurement_.OnNetworkBytesSent(*request, 100);
+ data_use_measurement_.OnCompleted(*request, true);
}
// This function makes a user request and confirms that its effect is
@@ -107,7 +119,7 @@ class DataUseMeasurementTest : public testing::Test {
bool IsDataUseForwarderCalled() { return is_data_use_forwarder_called_; }
- private:
+ protected:
void InitializeContext() {
context_.reset(new net::TestURLRequestContext(true));
socket_factory_.reset(new net::MockClientSocketFactory());
@@ -163,4 +175,141 @@ TEST_F(DataUseMeasurementTest, DataUseForwarderIsCalled) {
EXPECT_TRUE(IsDataUseForwarderCalled());
}
+#if defined(OS_ANDROID)
+TEST_F(DataUseMeasurementTest, AppStateUnknown) {
+ base::HistogramTester histogram_tester;
+ std::unique_ptr<net::URLRequest> request = CreateTestRequest(false);
+ data_use_measurement_.OnBeforeURLRequest(request.get());
+
+ {
+ base::HistogramTester histogram_tester;
+ data_use_measurement()->OnApplicationStateChangeForTesting(
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
+ data_use_measurement_.OnNetworkBytesSent(*request, 100);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.TrafficSize.User.Downstream.Foreground." + kConnectionType, 1);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.TrafficSize.User.Upstream.Foreground." + kConnectionType, 1);
+ }
+
+ {
+ base::HistogramTester histogram_tester;
+ data_use_measurement()->OnApplicationStateChangeForTesting(
+ base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.TrafficSize.User.Downstream.Unknown." + kConnectionType, 1);
+ }
+
+ {
+ base::HistogramTester histogram_tester;
+ data_use_measurement()->OnApplicationStateChangeForTesting(
+ base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.TrafficSize.User.Downstream.Background." + kConnectionType, 1);
+ }
+}
+
+TEST_F(DataUseMeasurementTest, TimeOfBackgroundDownstreamBytes) {
+ {
+ std::unique_ptr<net::URLRequest> request = CreateTestRequest(false);
+ data_use_measurement_.OnBeforeURLRequest(request.get());
+ base::HistogramTester histogram_tester;
+ data_use_measurement()->OnApplicationStateChange(
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
+ data_use_measurement_.OnNetworkBytesSent(*request, 100);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
+ data_use_measurement_.OnNetworkBytesSent(*request, 200);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 2000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToDataRecievedPerByte.User", 0);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToFirstDownstream.User", 0);
+ }
+
+ {
+ // Create new request when app is in foreground..
+ base::HistogramTester histogram_tester;
+ std::unique_ptr<net::URLRequest> request = CreateTestRequest(false);
+ data_use_measurement_.OnBeforeURLRequest(request.get());
+ data_use_measurement_.OnNetworkBytesSent(*request, 100);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
+ data_use_measurement_.OnNetworkBytesSent(*request, 200);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 2000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToDataRecievedPerByte.User", 0);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToFirstDownstream.User", 0);
+ }
+
+ {
+ std::unique_ptr<net::URLRequest> request = CreateTestRequest(false);
+ data_use_measurement_.OnBeforeURLRequest(request.get());
+ base::HistogramTester histogram_tester;
+ data_use_measurement()->OnApplicationStateChange(
+ base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
+ data_use_measurement_.OnNetworkBytesSent(*request, 100);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
+ data_use_measurement_.OnNetworkBytesSent(*request, 200);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 2000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToDataRecievedPerByte.User", 3000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToFirstDownstream.User", 1);
+ }
+
+ {
+ // Create new request when app is in background.
+ base::HistogramTester histogram_tester;
+ std::unique_ptr<net::URLRequest> request = CreateTestRequest(false);
+ data_use_measurement_.OnBeforeURLRequest(request.get());
+ data_use_measurement_.OnNetworkBytesSent(*request, 100);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
+ data_use_measurement_.OnNetworkBytesSent(*request, 200);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 2000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToDataRecievedPerByte.User", 3000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToFirstDownstream.User", 0);
+ }
+
+ {
+ // Create new request when app is in background.
+ base::HistogramTester histogram_tester;
+ std::unique_ptr<net::URLRequest> request = CreateTestRequest(true);
+ data_use_measurement_.OnBeforeURLRequest(request.get());
+ data_use_measurement_.OnNetworkBytesSent(*request, 100);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
+ data_use_measurement_.OnNetworkBytesSent(*request, 200);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 2000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToDataRecievedPerByte.System", 3000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToDataRecievedPerByte.User", 0);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToFirstDownstream.System", 0);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToFirstDownstream.User", 0);
+ }
+
+ {
+ std::unique_ptr<net::URLRequest> request = CreateTestRequest(false);
+ data_use_measurement_.OnBeforeURLRequest(request.get());
+ base::HistogramTester histogram_tester;
+ data_use_measurement()->OnApplicationStateChange(
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
+ data_use_measurement_.OnNetworkBytesSent(*request, 100);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
+ data_use_measurement_.OnNetworkBytesSent(*request, 200);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 2000);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToDataRecievedPerByte.User", 0);
+ histogram_tester.ExpectTotalCount(
+ "DataUse.BackgroundToFirstDownstream.User", 0);
+ }
+}
+#endif
+
} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/BUILD.gn b/chromium/components/data_use_measurement/core/BUILD.gn
index c9de08dac00..77e9950a3c4 100644
--- a/chromium/components/data_use_measurement/core/BUILD.gn
+++ b/chromium/components/data_use_measurement/core/BUILD.gn
@@ -2,8 +2,16 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("core") {
+static_library("core") {
sources = [
+ "data_use.cc",
+ "data_use.h",
+ "data_use_ascriber.cc",
+ "data_use_ascriber.h",
+ "data_use_network_delegate.cc",
+ "data_use_network_delegate.h",
+ "data_use_recorder.cc",
+ "data_use_recorder.h",
"data_use_user_data.cc",
"data_use_user_data.h",
]
diff --git a/chromium/components/data_use_measurement/core/data_use.cc b/chromium/components/data_use_measurement/core/data_use.cc
new file mode 100644
index 00000000000..6a8ec7fe61b
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use.cc
@@ -0,0 +1,18 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/data_use_measurement/core/data_use.h"
+
+namespace data_use_measurement {
+
+DataUse::DataUse() : total_bytes_sent_(0), total_bytes_received_(0) {}
+
+DataUse::~DataUse() {}
+
+void DataUse::MergeFrom(const DataUse& other) {
+ total_bytes_sent_ += other.total_bytes_sent_;
+ total_bytes_received_ += other.total_bytes_received_;
+}
+
+} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use.h b/chromium/components/data_use_measurement/core/data_use.h
new file mode 100644
index 00000000000..55cb7e57ed1
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use.h
@@ -0,0 +1,55 @@
+// 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 COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_H_
+#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "url/gurl.h"
+
+namespace data_use_measurement {
+
+// Class to store total network data used by some entity.
+class DataUse {
+ public:
+ DataUse();
+ ~DataUse();
+
+ // Merge data use from another instance.
+ void MergeFrom(const DataUse& other);
+
+ const GURL& url() const { return url_; }
+
+ void set_url(const GURL& url) { url_ = url; }
+
+ const std::string& description() const { return description_; }
+
+ void set_description(const std::string& description) {
+ description_ = description;
+ }
+
+ int64_t total_bytes_received() const { return total_bytes_received_; }
+
+ int64_t total_bytes_sent() const { return total_bytes_sent_; }
+
+ private:
+ friend class DataUseRecorder;
+
+ GURL url_;
+ std::string description_;
+
+ int64_t total_bytes_sent_;
+ int64_t total_bytes_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(DataUse);
+};
+
+} // namespace data_use_measurement
+
+#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_H_
diff --git a/chromium/components/data_use_measurement/core/data_use_ascriber.cc b/chromium/components/data_use_measurement/core/data_use_ascriber.cc
new file mode 100644
index 00000000000..13e4bd4538b
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use_ascriber.cc
@@ -0,0 +1,52 @@
+// 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 "components/data_use_measurement/core/data_use_ascriber.h"
+
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "components/data_use_measurement/core/data_use_network_delegate.h"
+#include "components/data_use_measurement/core/data_use_recorder.h"
+
+namespace data_use_measurement {
+
+std::unique_ptr<net::NetworkDelegate> DataUseAscriber::CreateNetworkDelegate(
+ std::unique_ptr<net::NetworkDelegate> wrapped_network_delegate) {
+ return base::MakeUnique<data_use_measurement::DataUseNetworkDelegate>(
+ std::move(wrapped_network_delegate), this);
+}
+
+void DataUseAscriber::OnBeforeUrlRequest(net::URLRequest* request) {
+ DataUseRecorder* recorder = GetDataUseRecorder(request);
+ if (recorder)
+ recorder->OnBeforeUrlRequest(request);
+}
+
+void DataUseAscriber::OnBeforeRedirect(net::URLRequest* request,
+ const GURL& new_location) {}
+
+void DataUseAscriber::OnNetworkBytesSent(net::URLRequest* request,
+ int64_t bytes_sent) {
+ DataUseRecorder* recorder = GetDataUseRecorder(request);
+ if (recorder)
+ recorder->OnNetworkBytesSent(request, bytes_sent);
+}
+
+void DataUseAscriber::OnNetworkBytesReceived(net::URLRequest* request,
+ int64_t bytes_received) {
+ DataUseRecorder* recorder = GetDataUseRecorder(request);
+ if (recorder)
+ recorder->OnNetworkBytesReceived(request, bytes_received);
+}
+
+void DataUseAscriber::OnUrlRequestCompleted(net::URLRequest* request,
+ bool started) {
+ DataUseRecorder* recorder = GetDataUseRecorder(request);
+ // TODO(kundaji): Enforce DCHECK(recorder).
+ if (recorder)
+ recorder->OnUrlRequestCompleted(request);
+}
+
+} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_ascriber.h b/chromium/components/data_use_measurement/core/data_use_ascriber.h
new file mode 100644
index 00000000000..5abaeabc631
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use_ascriber.h
@@ -0,0 +1,57 @@
+// 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 COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_ASCRIBER_H_
+#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_ASCRIBER_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "url/gurl.h"
+
+namespace net {
+class NetworkDelegate;
+class URLRequest;
+}
+
+namespace data_use_measurement {
+
+class DataUseRecorder;
+
+// Abstract class that manages instances of DataUseRecorder and maps
+// a URLRequest instance to its appropriate DataUseRecorder. An embedder
+// should provide an override if it is interested in tracking data usage. Data
+// use from all URLRequests mapped to the same DataUseRecorder will be grouped
+// together and reported as a single use.
+class DataUseAscriber {
+ public:
+ virtual ~DataUseAscriber() {}
+
+ // Creates a network delegate that will be used to track data use.
+ std::unique_ptr<net::NetworkDelegate> CreateNetworkDelegate(
+ std::unique_ptr<net::NetworkDelegate> wrapped_network_delegate);
+
+ // Returns the DataUseRecorder to which data usage for the given URL should
+ // be ascribed. If no existing DataUseRecorder exists, a new one will be
+ // created.
+ virtual DataUseRecorder* GetDataUseRecorder(net::URLRequest* request) = 0;
+
+ // Methods called by DataUseNetworkDelegate to propagate data use information:
+ virtual void OnBeforeUrlRequest(net::URLRequest* request);
+
+ virtual void OnBeforeRedirect(net::URLRequest* request,
+ const GURL& new_location);
+
+ virtual void OnNetworkBytesSent(net::URLRequest* request, int64_t bytes_sent);
+
+ virtual void OnNetworkBytesReceived(net::URLRequest* request,
+ int64_t bytes_received);
+
+ virtual void OnUrlRequestCompleted(net::URLRequest* request, bool started);
+};
+
+} // namespace data_use_measurement
+
+#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_ASCRIBER_H_
diff --git a/chromium/components/data_use_measurement/core/data_use_network_delegate.cc b/chromium/components/data_use_measurement/core/data_use_network_delegate.cc
new file mode 100644
index 00000000000..e7cb035ab08
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use_network_delegate.cc
@@ -0,0 +1,54 @@
+// 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 "components/data_use_measurement/core/data_use_network_delegate.h"
+
+#include <memory>
+#include <utility>
+
+#include "components/data_use_measurement/core/data_use_ascriber.h"
+#include "net/url_request/url_request.h"
+
+namespace data_use_measurement {
+DataUseNetworkDelegate::DataUseNetworkDelegate(
+ std::unique_ptr<NetworkDelegate> nested_network_delegate,
+ DataUseAscriber* ascriber)
+ : net::LayeredNetworkDelegate(std::move(nested_network_delegate)),
+ ascriber_(ascriber) {
+ DCHECK(ascriber);
+}
+
+DataUseNetworkDelegate::~DataUseNetworkDelegate() {}
+
+void DataUseNetworkDelegate::OnBeforeURLRequestInternal(
+ net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ GURL* new_url) {
+ ascriber_->OnBeforeUrlRequest(request);
+}
+
+void DataUseNetworkDelegate::OnBeforeRedirectInternal(
+ net::URLRequest* request,
+ const GURL& new_location) {
+ ascriber_->OnBeforeRedirect(request, new_location);
+}
+
+void DataUseNetworkDelegate::OnNetworkBytesReceivedInternal(
+ net::URLRequest* request,
+ int64_t bytes_received) {
+ ascriber_->OnNetworkBytesReceived(request, bytes_received);
+}
+
+void DataUseNetworkDelegate::OnNetworkBytesSentInternal(
+ net::URLRequest* request,
+ int64_t bytes_sent) {
+ ascriber_->OnNetworkBytesSent(request, bytes_sent);
+}
+
+void DataUseNetworkDelegate::OnCompletedInternal(net::URLRequest* request,
+ bool started) {
+ ascriber_->OnUrlRequestCompleted(request, started);
+}
+
+} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_network_delegate.h b/chromium/components/data_use_measurement/core/data_use_network_delegate.h
new file mode 100644
index 00000000000..f4aab981b1b
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use_network_delegate.h
@@ -0,0 +1,58 @@
+// 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 COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_NETWORK_DELEGATE_H_
+#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_NETWORK_DELEGATE_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "net/base/completion_callback.h"
+#include "net/base/layered_network_delegate.h"
+
+namespace net {
+class NetworkDelegate;
+class URLRequest;
+}
+
+namespace data_use_measurement {
+
+class DataUseAscriber;
+
+// Propagates network data use events to the |ascriber_|. This class must be
+// set up as a network delegate for the URLRequestContexts whose data use is to
+// be tracked.
+class DataUseNetworkDelegate : public net::LayeredNetworkDelegate {
+ public:
+ DataUseNetworkDelegate(
+ std::unique_ptr<net::NetworkDelegate> nested_network_delegate,
+ DataUseAscriber* ascriber);
+
+ ~DataUseNetworkDelegate() override;
+
+ // LayeredNetworkDelegate:
+ void OnBeforeURLRequestInternal(net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ GURL* new_url) override;
+
+ void OnBeforeRedirectInternal(net::URLRequest* request,
+ const GURL& new_location) override;
+
+ void OnNetworkBytesReceivedInternal(net::URLRequest* request,
+ int64_t bytes_received) override;
+
+ void OnNetworkBytesSentInternal(net::URLRequest* request,
+ int64_t bytes_sent) override;
+
+ void OnCompletedInternal(net::URLRequest* request, bool started) override;
+
+ private:
+ DataUseAscriber* ascriber_;
+};
+
+} // namespace data_use_measurement
+
+#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_NETWORK_DELEGATE_H_
diff --git a/chromium/components/data_use_measurement/core/data_use_recorder.cc b/chromium/components/data_use_measurement/core/data_use_recorder.cc
new file mode 100644
index 00000000000..9f3475e3952
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use_recorder.cc
@@ -0,0 +1,53 @@
+// 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 "components/data_use_measurement/core/data_use_recorder.h"
+
+#include "net/url_request/url_request.h"
+
+namespace data_use_measurement {
+
+DataUseRecorder::DataUseRecorder() {}
+
+DataUseRecorder::~DataUseRecorder() {}
+
+bool DataUseRecorder::IsDataUseComplete() {
+ return pending_url_requests_.empty() && pending_data_sources_.empty();
+}
+
+void DataUseRecorder::OnBeforeUrlRequest(net::URLRequest* request) {
+ pending_url_requests_.insert(request);
+}
+
+void DataUseRecorder::OnUrlRequestCompleted(net::URLRequest* request) {
+ pending_url_requests_.erase(request);
+}
+
+void DataUseRecorder::OnNetworkBytesReceived(net::URLRequest* request,
+ int64_t bytes_received) {
+ data_use_.total_bytes_received_ += bytes_received;
+}
+
+void DataUseRecorder::OnNetworkBytesSent(net::URLRequest* request,
+ int64_t bytes_sent) {
+ data_use_.total_bytes_sent_ += bytes_sent;
+}
+
+void DataUseRecorder::AddPendingDataSource(void* source) {
+ pending_data_sources_.insert(source);
+}
+
+bool DataUseRecorder::HasPendingDataSource(void* source) {
+ return pending_data_sources_.find(source) != pending_data_sources_.end();
+}
+
+void DataUseRecorder::RemovePendingDataSource(void* source) {
+ pending_data_sources_.erase(source);
+}
+
+bool DataUseRecorder::HasPendingURLRequest(const net::URLRequest* request) {
+ return pending_url_requests_.find(request) != pending_url_requests_.end();
+}
+
+} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_recorder.h b/chromium/components/data_use_measurement/core/data_use_recorder.h
new file mode 100644
index 00000000000..becba416dab
--- /dev/null
+++ b/chromium/components/data_use_measurement/core/data_use_recorder.h
@@ -0,0 +1,79 @@
+// 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 COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_RECORDER_H_
+#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_RECORDER_H_
+
+#include <stdint.h>
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/supports_user_data.h"
+#include "components/data_use_measurement/core/data_use.h"
+#include "net/base/net_export.h"
+
+namespace net {
+class URLRequest;
+}
+
+namespace data_use_measurement {
+
+// Tracks all network data used by a single high level entity. An entity
+// can make multiple URLRequests, so there is a one:many relationship between
+// DataUseRecorders and URLRequests. Data used by each URLRequest will be
+// tracked by exactly one DataUseRecorder.
+class DataUseRecorder {
+ public:
+ DataUseRecorder();
+ ~DataUseRecorder();
+
+ // Returns the actual data used by the entity being tracked.
+ DataUse& data_use() { return data_use_; }
+
+ // Returns whether data use is complete and no additional data can be used
+ // by the entity tracked by this recorder. For example,
+ bool IsDataUseComplete();
+
+ // Methods for tracking data use sources. These sources can initiate
+ // URLRequests directly or indirectly. The entity whose data use is being
+ // tracked by this recorder may comprise of sub-entities each of which use
+ // network data. These helper methods help track these sub-entities.
+ // A recorder will not be marked as having completed data use as long as it
+ // has pending data sources.
+ void AddPendingDataSource(void* source);
+ bool HasPendingDataSource(void* source);
+ void RemovePendingDataSource(void* source);
+
+ // Returns whether there are any pending URLRequests whose data use is tracked
+ // by this DataUseRecorder.
+ bool HasPendingURLRequest(const net::URLRequest* request);
+
+ // Method to merge another DataUseRecorder to this instance.
+ void MergeWith(DataUseRecorder* other);
+
+ private:
+ friend class DataUseAscriber;
+
+ // Network Delegate methods:
+ void OnBeforeUrlRequest(net::URLRequest* request);
+ void OnUrlRequestCompleted(net::URLRequest* request);
+ void OnNetworkBytesSent(net::URLRequest* request, int64_t bytes_sent);
+ void OnNetworkBytesReceived(net::URLRequest* request, int64_t bytes_received);
+
+ // Pending URLRequests whose data is being tracked by this DataUseRecorder.
+ base::hash_set<const net::URLRequest*> pending_url_requests_;
+
+ // Data sources other than URLRequests, whose data is being tracked by this
+ // DataUseRecorder.
+ base::hash_set<const void*> pending_data_sources_;
+
+ // The network data use measured by this DataUseRecorder.
+ DataUse data_use_;
+
+ DISALLOW_COPY_AND_ASSIGN(DataUseRecorder);
+};
+
+} // namespace data_use_measurement
+
+#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_RECORDER_H_
diff --git a/chromium/components/data_use_measurement/core/data_use_user_data.cc b/chromium/components/data_use_measurement/core/data_use_user_data.cc
index 50578ffc36e..d1e2f097001 100644
--- a/chromium/components/data_use_measurement/core/data_use_user_data.cc
+++ b/chromium/components/data_use_measurement/core/data_use_user_data.cc
@@ -4,12 +4,32 @@
#include "components/data_use_measurement/core/data_use_user_data.h"
+#if defined(OS_ANDROID)
+#include "base/android/application_status_listener.h"
+#endif
+
#include "net/url_request/url_fetcher.h"
namespace data_use_measurement {
-DataUseUserData::DataUseUserData(ServiceName service_name)
- : service_name_(service_name) {}
+namespace {
+
+DataUseUserData::AppState GetCurrentAppState() {
+#if defined(OS_ANDROID)
+ return base::android::ApplicationStatusListener::GetState() ==
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES
+ ? DataUseUserData::FOREGROUND
+ : DataUseUserData::BACKGROUND;
+#else
+ // If the OS is not Android, all the requests are considered Foreground.
+ return DataUseUserData::FOREGROUND;
+#endif
+}
+
+} // namespace
+
+DataUseUserData::DataUseUserData(ServiceName service_name, AppState app_state)
+ : service_name_(service_name), app_state_(app_state) {}
DataUseUserData::~DataUseUserData() {}
@@ -20,7 +40,7 @@ const void* const DataUseUserData::kUserDataKey =
// static
base::SupportsUserData::Data* DataUseUserData::Create(
ServiceName service_name) {
- return new DataUseUserData(service_name);
+ return new DataUseUserData(service_name, GetCurrentAppState());
}
// static
@@ -58,6 +78,14 @@ std::string DataUseUserData::GetServiceNameAsString(ServiceName service_name) {
return "SpellChecker";
case NTP_SNIPPETS:
return "NTPSnippets";
+ case SAFE_BROWSING:
+ return "SafeBrowsing";
+ case DATA_REDUCTION_PROXY:
+ return "DataReductionProxy";
+ case PRECACHE:
+ return "Precache";
+ case NTP_TILES:
+ return "NTPTiles";
}
return "INVALID";
}
diff --git a/chromium/components/data_use_measurement/core/data_use_user_data.h b/chromium/components/data_use_measurement/core/data_use_user_data.h
index 00d749c2a21..f22008478ac 100644
--- a/chromium/components/data_use_measurement/core/data_use_user_data.h
+++ b/chromium/components/data_use_measurement/core/data_use_user_data.h
@@ -40,9 +40,17 @@ class DataUseUserData : public base::SupportsUserData::Data {
POLICY,
SPELL_CHECKER,
NTP_SNIPPETS,
+ SAFE_BROWSING,
+ DATA_REDUCTION_PROXY,
+ PRECACHE,
+ NTP_TILES,
};
- explicit DataUseUserData(ServiceName service_name);
+ // The state of the application. Only available on Android and on other
+ // platforms it is always FOREGROUND.
+ enum AppState { UNKNOWN, BACKGROUND, FOREGROUND };
+
+ DataUseUserData(ServiceName service_name, AppState app_state);
~DataUseUserData() override;
// Helper function to create DataUseUserData. The caller takes the ownership
@@ -60,12 +68,19 @@ class DataUseUserData : public base::SupportsUserData::Data {
ServiceName service_name() const { return service_name_; }
+ AppState app_state() const { return app_state_; }
+
+ void set_app_state(AppState app_state) { app_state_ = app_state; }
+
// The key for retrieving back this type of user data.
static const void* const kUserDataKey;
private:
const ServiceName service_name_;
+ // App state when network access was performed for the request previously.
+ AppState app_state_;
+
DISALLOW_COPY_AND_ASSIGN(DataUseUserData);
};
diff --git a/chromium/components/device_event_log.gypi b/chromium/components/device_event_log.gypi
deleted file mode 100644
index 8e77790552e..00000000000
--- a/chromium/components/device_event_log.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'device_event_log_component',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'DEVICE_EVENT_LOG_IMPLEMENTATION',
- ],
- 'sources': [
- 'device_event_log/device_event_log.cc',
- 'device_event_log/device_event_log.h',
- 'device_event_log/device_event_log_impl.cc',
- 'device_event_log/device_event_log_impl.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/devtools_discovery.gypi b/chromium/components/devtools_discovery.gypi
deleted file mode 100644
index 9b8232ceefb..00000000000
--- a/chromium/components/devtools_discovery.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'devtools_discovery',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'devtools_discovery/basic_target_descriptor.cc',
- 'devtools_discovery/basic_target_descriptor.h',
- 'devtools_discovery/devtools_discovery_manager.cc',
- 'devtools_discovery/devtools_discovery_manager.h',
- 'devtools_discovery/devtools_target_descriptor.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/devtools_discovery/BUILD.gn b/chromium/components/devtools_discovery/BUILD.gn
deleted file mode 100644
index 7c1ac4e5586..00000000000
--- a/chromium/components/devtools_discovery/BUILD.gn
+++ /dev/null
@@ -1,20 +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.
-
-source_set("devtools_discovery") {
- sources = [
- "basic_target_descriptor.cc",
- "basic_target_descriptor.h",
- "devtools_discovery_manager.cc",
- "devtools_discovery_manager.h",
- "devtools_target_descriptor.h",
- ]
-
- deps = [
- "//base",
- "//content/public/browser",
- "//content/public/common",
- "//url",
- ]
-}
diff --git a/chromium/components/devtools_discovery/DEPS b/chromium/components/devtools_discovery/DEPS
deleted file mode 100644
index f75ba964ae0..00000000000
--- a/chromium/components/devtools_discovery/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
- "+content/public/browser",
- "+content/public/common",
- "+content/public/test",
-]
diff --git a/chromium/components/devtools_discovery/OWNERS b/chromium/components/devtools_discovery/OWNERS
deleted file mode 100644
index fe38b0fad49..00000000000
--- a/chromium/components/devtools_discovery/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-dgozman@chromium.org
-pfeldman@chromium.org
diff --git a/chromium/components/devtools_discovery/basic_target_descriptor.cc b/chromium/components/devtools_discovery/basic_target_descriptor.cc
deleted file mode 100644
index 29b52dd8cc9..00000000000
--- a/chromium/components/devtools_discovery/basic_target_descriptor.cc
+++ /dev/null
@@ -1,105 +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 "components/devtools_discovery/basic_target_descriptor.h"
-
-#include "content/public/browser/devtools_agent_host.h"
-#include "content/public/browser/favicon_status.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/web_contents.h"
-
-using content::DevToolsAgentHost;
-
-namespace devtools_discovery {
-
-const char BasicTargetDescriptor::kTypePage[] = "page";
-const char BasicTargetDescriptor::kTypeServiceWorker[] = "service_worker";
-const char BasicTargetDescriptor::kTypeSharedWorker[] = "worker";
-const char BasicTargetDescriptor::kTypeOther[] = "other";
-
-namespace {
-
-std::string GetTypeFromAgentHost(DevToolsAgentHost* agent_host) {
- switch (agent_host->GetType()) {
- case DevToolsAgentHost::TYPE_WEB_CONTENTS:
- return BasicTargetDescriptor::kTypePage;
- case DevToolsAgentHost::TYPE_SERVICE_WORKER:
- return BasicTargetDescriptor::kTypeServiceWorker;
- case DevToolsAgentHost::TYPE_SHARED_WORKER:
- return BasicTargetDescriptor::kTypeSharedWorker;
- default:
- break;
- }
- return BasicTargetDescriptor::kTypeOther;
-}
-
-} // namespace
-
-BasicTargetDescriptor::BasicTargetDescriptor(
- scoped_refptr<DevToolsAgentHost> agent_host)
- : agent_host_(agent_host),
- type_(GetTypeFromAgentHost(agent_host.get())),
- title_(agent_host->GetTitle()),
- url_(agent_host->GetURL()) {
- if (content::WebContents* web_contents = agent_host_->GetWebContents()) {
- content::NavigationController& controller = web_contents->GetController();
- content::NavigationEntry* entry = controller.GetLastCommittedEntry();
- if (entry != NULL && entry->GetURL().is_valid())
- favicon_url_ = entry->GetFavicon().url;
- last_activity_time_ = web_contents->GetLastActiveTime();
- }
-}
-
-BasicTargetDescriptor::~BasicTargetDescriptor() {
-}
-
-std::string BasicTargetDescriptor::GetId() const {
- return agent_host_->GetId();
-}
-
-std::string BasicTargetDescriptor::GetParentId() const {
- return parent_id_;
-}
-
-std::string BasicTargetDescriptor::GetType() const {
- return type_;
-}
-
-std::string BasicTargetDescriptor::GetTitle() const {
- return title_;
-}
-
-std::string BasicTargetDescriptor::GetDescription() const {
- return description_;
-}
-
-GURL BasicTargetDescriptor::GetURL() const {
- return url_;
-}
-
-GURL BasicTargetDescriptor::GetFaviconURL() const {
- return favicon_url_;
-}
-
-base::TimeTicks BasicTargetDescriptor::GetLastActivityTime() const {
- return last_activity_time_;
-}
-
-bool BasicTargetDescriptor::IsAttached() const {
- return agent_host_->IsAttached();
-}
-
-scoped_refptr<DevToolsAgentHost> BasicTargetDescriptor::GetAgentHost() const {
- return agent_host_;
-}
-
-bool BasicTargetDescriptor::Activate() const {
- return agent_host_->Activate();
-}
-
-bool BasicTargetDescriptor::Close() const {
- return agent_host_->Close();
-}
-
-} // namespace devtools_discovery
diff --git a/chromium/components/devtools_discovery/basic_target_descriptor.h b/chromium/components/devtools_discovery/basic_target_descriptor.h
deleted file mode 100644
index a3b834a7e3a..00000000000
--- a/chromium/components/devtools_discovery/basic_target_descriptor.h
+++ /dev/null
@@ -1,58 +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 COMPONENTS_DEVTOOLS_DISCOVERY_BASIC_TARGET_DESCRIPTOR_H_
-#define COMPONENTS_DEVTOOLS_DISCOVERY_BASIC_TARGET_DESCRIPTOR_H_
-
-#include "components/devtools_discovery/devtools_target_descriptor.h"
-
-namespace devtools_discovery {
-
-class BasicTargetDescriptor : public DevToolsTargetDescriptor {
- public:
- explicit BasicTargetDescriptor(
- scoped_refptr<content::DevToolsAgentHost> agent_host);
- ~BasicTargetDescriptor() override;
-
- static const char kTypePage[];
- static const char kTypeServiceWorker[];
- static const char kTypeSharedWorker[];
- static const char kTypeOther[];
-
- // DevToolsTargetDescriptor implementation.
- std::string GetId() const override;
- std::string GetParentId() const override;
- std::string GetType() const override;
- std::string GetTitle() const override;
- std::string GetDescription() const override;
- GURL GetURL() const override;
- GURL GetFaviconURL() const override;
- base::TimeTicks GetLastActivityTime() const override;
- bool IsAttached() const override;
- scoped_refptr<content::DevToolsAgentHost> GetAgentHost() const override;
- bool Activate() const override;
- bool Close() const override;
-
- protected:
- void set_parent_id(const std::string& parent_id) { parent_id_ = parent_id; }
- void set_type(const std::string& type) { type_ = type; }
- void set_title(const std::string& title) { title_ = title; }
- void set_description(const std::string& desc) { description_ = desc; }
- void set_url(const GURL& url) { url_ = url; }
- void set_favicon_url(const GURL& url) { favicon_url_ = url; }
-
- private:
- scoped_refptr<content::DevToolsAgentHost> agent_host_;
- std::string parent_id_;
- std::string type_;
- std::string title_;
- std::string description_;
- GURL url_;
- GURL favicon_url_;
- base::TimeTicks last_activity_time_;
-};
-
-} // namespace devtools_discovery
-
-#endif // COMPONENTS_DEVTOOLS_DISCOVERY_BASIC_TARGET_DESCRIPTOR_H_
diff --git a/chromium/components/devtools_discovery/devtools_discovery_manager.cc b/chromium/components/devtools_discovery/devtools_discovery_manager.cc
deleted file mode 100644
index aaa998cba3c..00000000000
--- a/chromium/components/devtools_discovery/devtools_discovery_manager.cc
+++ /dev/null
@@ -1,65 +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 "components/devtools_discovery/devtools_discovery_manager.h"
-
-#include "base/stl_util.h"
-#include "components/devtools_discovery/basic_target_descriptor.h"
-#include "content/public/browser/devtools_agent_host.h"
-
-using content::DevToolsAgentHost;
-
-namespace devtools_discovery {
-
-// static
-DevToolsDiscoveryManager* DevToolsDiscoveryManager::GetInstance() {
- return base::Singleton<DevToolsDiscoveryManager>::get();
-}
-
-DevToolsDiscoveryManager::DevToolsDiscoveryManager() {
-}
-
-DevToolsDiscoveryManager::~DevToolsDiscoveryManager() {
- STLDeleteElements(&providers_);
-}
-
-void DevToolsDiscoveryManager::AddProvider(std::unique_ptr<Provider> provider) {
- providers_.push_back(provider.release());
-}
-
-DevToolsTargetDescriptor::List DevToolsDiscoveryManager::GetDescriptors() {
- if (providers_.size())
- return GetDescriptorsFromProviders();
-
- DevToolsAgentHost::List agent_hosts = DevToolsAgentHost::GetOrCreateAll();
- DevToolsTargetDescriptor::List result;
- result.reserve(agent_hosts.size());
- for (const auto& agent_host : agent_hosts)
- result.push_back(new BasicTargetDescriptor(agent_host));
- return result;
-}
-
-void DevToolsDiscoveryManager::SetCreateCallback(
- const CreateCallback& callback) {
- create_callback_ = callback;
-}
-
-std::unique_ptr<DevToolsTargetDescriptor> DevToolsDiscoveryManager::CreateNew(
- const GURL& url) {
- if (create_callback_.is_null())
- return nullptr;
- return create_callback_.Run(url);
-}
-
-DevToolsTargetDescriptor::List
-DevToolsDiscoveryManager::GetDescriptorsFromProviders() {
- DevToolsTargetDescriptor::List result;
- for (const auto& provider : providers_) {
- DevToolsTargetDescriptor::List partial = provider->GetDescriptors();
- result.insert(result.begin(), partial.begin(), partial.end());
- }
- return result;
-}
-
-} // namespace devtools_discovery
diff --git a/chromium/components/devtools_discovery/devtools_discovery_manager.h b/chromium/components/devtools_discovery/devtools_discovery_manager.h
deleted file mode 100644
index 75657d46be6..00000000000
--- a/chromium/components/devtools_discovery/devtools_discovery_manager.h
+++ /dev/null
@@ -1,57 +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 COMPONENTS_DEVTOOLS_DISCOVERY_DEVTOOLS_DISCOVERY_MANAGER_H_
-#define COMPONENTS_DEVTOOLS_DISCOVERY_DEVTOOLS_DISCOVERY_MANAGER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "components/devtools_discovery/devtools_target_descriptor.h"
-
-namespace devtools_discovery {
-
-class DevToolsDiscoveryManager {
- public:
- class Provider {
- public:
- virtual ~Provider() {}
-
- // Caller takes ownership of created descriptors.
- virtual DevToolsTargetDescriptor::List GetDescriptors() = 0;
- };
-
- using CreateCallback =
- base::Callback<std::unique_ptr<DevToolsTargetDescriptor>(
- const GURL& url)>;
-
- // Returns single instance of this class. The instance is destroyed on the
- // browser main loop exit so this method MUST NOT be called after that point.
- static DevToolsDiscoveryManager* GetInstance();
-
- void AddProvider(std::unique_ptr<Provider> provider);
- void SetCreateCallback(const CreateCallback& callback);
-
- // Caller takes ownership of created descriptors.
- DevToolsTargetDescriptor::List GetDescriptors();
- std::unique_ptr<DevToolsTargetDescriptor> CreateNew(const GURL& url);
-
- private:
- friend struct base::DefaultSingletonTraits<DevToolsDiscoveryManager>;
-
- DevToolsDiscoveryManager();
- ~DevToolsDiscoveryManager();
- DevToolsTargetDescriptor::List GetDescriptorsFromProviders();
-
- std::vector<Provider*> providers_;
- CreateCallback create_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(DevToolsDiscoveryManager);
-};
-
-} // namespace devtools_discovery
-
-#endif // COMPONENTS_DEVTOOLS_DISCOVERY_DEVTOOLS_DISCOVERY_MANAGER_H_
diff --git a/chromium/components/devtools_discovery/devtools_target_descriptor.h b/chromium/components/devtools_discovery/devtools_target_descriptor.h
deleted file mode 100644
index d7446319910..00000000000
--- a/chromium/components/devtools_discovery/devtools_target_descriptor.h
+++ /dev/null
@@ -1,69 +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 COMPONENTS_DEVTOOLS_DISCOVERY_DEVTOOLS_TARGET_DESCRIPTOR_H_
-#define COMPONENTS_DEVTOOLS_DISCOVERY_DEVTOOLS_TARGET_DESCRIPTOR_H_
-
-#include <string>
-#include <vector>
-
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-#include "url/gurl.h"
-
-namespace content {
-class DevToolsAgentHost;
-}
-
-namespace devtools_discovery {
-
-// DevToolsTargetDescriptor provides information about devtools target
-// and can be used to manipulate the target and query its details.
-// Instantiation and discovery of DevToolsTargetDescriptor instances
-// is the responsibility of DevToolsDiscoveryManager.
-class DevToolsTargetDescriptor {
- public:
- using List = std::vector<DevToolsTargetDescriptor*>;
- virtual ~DevToolsTargetDescriptor() {}
-
- // Returns the unique target id.
- virtual std::string GetId() const = 0;
-
- // Returns the id of the parent target, or empty string if no parent.
- virtual std::string GetParentId() const = 0;
-
- // Returns the target type.
- virtual std::string GetType() const = 0;
-
- // Returns the target title.
- virtual std::string GetTitle() const = 0;
-
- // Returns the target description.
- virtual std::string GetDescription() const = 0;
-
- // Returns the url associated with this target.
- virtual GURL GetURL() const = 0;
-
- // Returns the favicon url for this target.
- virtual GURL GetFaviconURL() const = 0;
-
- // Returns the time when the target was last active.
- virtual base::TimeTicks GetLastActivityTime() const = 0;
-
- // Returns true if the debugger is attached to the target.
- virtual bool IsAttached() const = 0;
-
- // Returns the agent host for this target.
- virtual scoped_refptr<content::DevToolsAgentHost> GetAgentHost() const = 0;
-
- // Activates the target. Returns false if the operation failed.
- virtual bool Activate() const = 0;
-
- // Closes the target. Returns false if the operation failed.
- virtual bool Close() const = 0;
-};
-
-} // namespace devtools_discovery
-
-#endif // COMPONENTS_DEVTOOLS_DISCOVERY_DEVTOOLS_TARGET_DESCRIPTOR_H_
diff --git a/chromium/components/devtools_http_handler.gypi b/chromium/components/devtools_http_handler.gypi
deleted file mode 100644
index 1215e29cbf5..00000000000
--- a/chromium/components/devtools_http_handler.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'devtools_http_handler',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../components/components.gyp:devtools_discovery',
- '../content/content.gyp:content_browser',
- '../net/net.gyp:net',
- '../net/net.gyp:http_server',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'devtools_http_handler/devtools_http_handler.cc',
- 'devtools_http_handler/devtools_http_handler.h',
- 'devtools_http_handler/devtools_http_handler_delegate.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/devtools_http_handler/BUILD.gn b/chromium/components/devtools_http_handler/BUILD.gn
deleted file mode 100644
index 0cb77baecd3..00000000000
--- a/chromium/components/devtools_http_handler/BUILD.gn
+++ /dev/null
@@ -1,35 +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.
-
-source_set("devtools_http_handler") {
- sources = [
- "devtools_http_handler.cc",
- "devtools_http_handler.h",
- "devtools_http_handler_delegate.h",
- ]
-
- deps = [
- "//base",
- "//components/devtools_discovery",
- "//content/public/browser",
- "//content/public/common",
- "//net",
- "//net:http_server",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "devtools_http_handler_unittest.cc",
- ]
-
- deps = [
- ":devtools_http_handler",
- "//base",
- "//content/test:test_support",
- "//net",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/devtools_http_handler/DEPS b/chromium/components/devtools_http_handler/DEPS
deleted file mode 100644
index c85bd3d4632..00000000000
--- a/chromium/components/devtools_http_handler/DEPS
+++ /dev/null
@@ -1,7 +0,0 @@
-include_rules = [
- "+components/devtools_discovery",
- "+content/public/browser",
- "+content/public/common",
- "+content/public/test",
- "+net",
-]
diff --git a/chromium/components/devtools_http_handler/OWNERS b/chromium/components/devtools_http_handler/OWNERS
deleted file mode 100644
index fe38b0fad49..00000000000
--- a/chromium/components/devtools_http_handler/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-dgozman@chromium.org
-pfeldman@chromium.org
diff --git a/chromium/components/devtools_http_handler/devtools_http_handler.cc b/chromium/components/devtools_http_handler/devtools_http_handler.cc
deleted file mode 100644
index 38f32dc1da2..00000000000
--- a/chromium/components/devtools_http_handler/devtools_http_handler.cc
+++ /dev/null
@@ -1,939 +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 <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/files/file_util.h"
-#include "base/json/json_writer.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/thread.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "components/devtools_discovery/devtools_discovery_manager.h"
-#include "components/devtools_http_handler/devtools_http_handler.h"
-#include "components/devtools_http_handler/devtools_http_handler_delegate.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/devtools_agent_host.h"
-#include "content/public/browser/devtools_external_agent_proxy_delegate.h"
-#include "content/public/common/url_constants.h"
-#include "content/public/common/user_agent.h"
-#include "net/base/escape.h"
-#include "net/base/io_buffer.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "net/server/http_server.h"
-#include "net/server/http_server_request_info.h"
-#include "net/server/http_server_response_info.h"
-#include "net/socket/server_socket.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/build_info.h"
-#endif
-
-using content::BrowserThread;
-using content::DevToolsAgentHost;
-using content::DevToolsAgentHostClient;
-using devtools_discovery::DevToolsTargetDescriptor;
-
-namespace devtools_http_handler {
-
-namespace {
-
-const base::FilePath::CharType kDevToolsActivePortFileName[] =
- FILE_PATH_LITERAL("DevToolsActivePort");
-
-const char kDevToolsHandlerThreadName[] = "Chrome_DevToolsHandlerThread";
-
-const char kThumbUrlPrefix[] = "/thumb/";
-const char kPageUrlPrefix[] = "/devtools/page/";
-
-const char kTargetIdField[] = "id";
-const char kTargetParentIdField[] = "parentId";
-const char kTargetTypeField[] = "type";
-const char kTargetTitleField[] = "title";
-const char kTargetDescriptionField[] = "description";
-const char kTargetUrlField[] = "url";
-const char kTargetThumbnailUrlField[] = "thumbnailUrl";
-const char kTargetFaviconUrlField[] = "faviconUrl";
-const char kTargetWebSocketDebuggerUrlField[] = "webSocketDebuggerUrl";
-const char kTargetDevtoolsFrontendUrlField[] = "devtoolsFrontendUrl";
-
-// Maximum write buffer size of devtools http/websocket connections.
-// TODO(rmcilroy/pfieldman): Reduce this back to 100Mb when we have
-// added back pressure on the TraceComplete message protocol - crbug.com/456845.
-const int32_t kSendBufferSizeForDevTools = 256 * 1024 * 1024; // 256Mb
-
-} // namespace
-
-// ServerWrapper -------------------------------------------------------------
-// All methods in this class are only called on handler thread.
-class ServerWrapper : net::HttpServer::Delegate {
- public:
- ServerWrapper(base::WeakPtr<DevToolsHttpHandler> handler,
- std::unique_ptr<net::ServerSocket> socket,
- const base::FilePath& frontend_dir,
- bool bundles_resources);
-
- int GetLocalAddress(net::IPEndPoint* address);
-
- void AcceptWebSocket(int connection_id,
- const net::HttpServerRequestInfo& request);
- void SendOverWebSocket(int connection_id, const std::string& message);
- void SendResponse(int connection_id,
- const net::HttpServerResponseInfo& response);
- void Send200(int connection_id,
- const std::string& data,
- const std::string& mime_type);
- void Send404(int connection_id);
- void Send500(int connection_id, const std::string& message);
- void Close(int connection_id);
-
- void WriteActivePortToUserProfile(const base::FilePath& output_directory);
-
- ~ServerWrapper() override {}
-
- private:
- // net::HttpServer::Delegate implementation.
- void OnConnect(int connection_id) override {}
- void OnHttpRequest(int connection_id,
- const net::HttpServerRequestInfo& info) override;
- void OnWebSocketRequest(int connection_id,
- const net::HttpServerRequestInfo& info) override;
- void OnWebSocketMessage(int connection_id,
- const std::string& data) override;
- void OnClose(int connection_id) override;
-
- base::WeakPtr<DevToolsHttpHandler> handler_;
- std::unique_ptr<net::HttpServer> server_;
- base::FilePath frontend_dir_;
- bool bundles_resources_;
-};
-
-ServerWrapper::ServerWrapper(base::WeakPtr<DevToolsHttpHandler> handler,
- std::unique_ptr<net::ServerSocket> socket,
- const base::FilePath& frontend_dir,
- bool bundles_resources)
- : handler_(handler),
- server_(new net::HttpServer(std::move(socket), this)),
- frontend_dir_(frontend_dir),
- bundles_resources_(bundles_resources) {}
-
-int ServerWrapper::GetLocalAddress(net::IPEndPoint* address) {
- return server_->GetLocalAddress(address);
-}
-
-void ServerWrapper::AcceptWebSocket(int connection_id,
- const net::HttpServerRequestInfo& request) {
- server_->SetSendBufferSize(connection_id, kSendBufferSizeForDevTools);
- server_->AcceptWebSocket(connection_id, request);
-}
-
-void ServerWrapper::SendOverWebSocket(int connection_id,
- const std::string& message) {
- server_->SendOverWebSocket(connection_id, message);
-}
-
-void ServerWrapper::SendResponse(int connection_id,
- const net::HttpServerResponseInfo& response) {
- server_->SendResponse(connection_id, response);
-}
-
-void ServerWrapper::Send200(int connection_id,
- const std::string& data,
- const std::string& mime_type) {
- server_->Send200(connection_id, data, mime_type);
-}
-
-void ServerWrapper::Send404(int connection_id) {
- server_->Send404(connection_id);
-}
-
-void ServerWrapper::Send500(int connection_id,
- const std::string& message) {
- server_->Send500(connection_id, message);
-}
-
-void ServerWrapper::Close(int connection_id) {
- server_->Close(connection_id);
-}
-
-// Thread and ServerWrapper lifetime management ------------------------------
-
-void TerminateOnUI(base::Thread* thread,
- ServerWrapper* server_wrapper,
- DevToolsHttpHandler::ServerSocketFactory* socket_factory) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (server_wrapper) {
- DCHECK(thread);
- thread->task_runner()->DeleteSoon(FROM_HERE, server_wrapper);
- }
- if (socket_factory) {
- DCHECK(thread);
- thread->task_runner()->DeleteSoon(FROM_HERE, socket_factory);
- }
- if (thread) {
- BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, thread);
- }
-}
-
-void ServerStartedOnUI(base::WeakPtr<DevToolsHttpHandler> handler,
- base::Thread* thread,
- ServerWrapper* server_wrapper,
- DevToolsHttpHandler::ServerSocketFactory* socket_factory,
- std::unique_ptr<net::IPEndPoint> ip_address) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (handler && thread && server_wrapper) {
- handler->ServerStarted(thread, server_wrapper, socket_factory,
- std::move(ip_address));
- } else {
- TerminateOnUI(thread, server_wrapper, socket_factory);
- }
-}
-
-void StartServerOnHandlerThread(
- base::WeakPtr<DevToolsHttpHandler> handler,
- base::Thread* thread,
- DevToolsHttpHandler::ServerSocketFactory* server_socket_factory,
- const base::FilePath& output_directory,
- const base::FilePath& frontend_dir,
- bool bundles_resources) {
- DCHECK(thread->task_runner()->BelongsToCurrentThread());
- ServerWrapper* server_wrapper = nullptr;
- std::unique_ptr<net::ServerSocket> server_socket =
- server_socket_factory->CreateForHttpServer();
- std::unique_ptr<net::IPEndPoint> ip_address(new net::IPEndPoint);
- if (server_socket) {
- server_wrapper = new ServerWrapper(handler, std::move(server_socket),
- frontend_dir, bundles_resources);
- if (!output_directory.empty())
- server_wrapper->WriteActivePortToUserProfile(output_directory);
-
- if (server_wrapper->GetLocalAddress(ip_address.get()) != net::OK)
- ip_address.reset();
- } else {
- ip_address.reset();
- LOG(ERROR) << "Cannot start http server for devtools. Stop devtools.";
- }
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&ServerStartedOnUI,
- handler,
- thread,
- server_wrapper,
- server_socket_factory,
- base::Passed(&ip_address)));
-}
-
-void StartServerOnFile(
- base::WeakPtr<DevToolsHttpHandler> handler,
- DevToolsHttpHandler::ServerSocketFactory* server_socket_factory,
- const base::FilePath& output_directory,
- const base::FilePath& frontend_dir,
- bool bundles_resources) {
- DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- std::unique_ptr<base::Thread> thread(
- new base::Thread(kDevToolsHandlerThreadName));
- base::Thread::Options options;
- options.message_loop_type = base::MessageLoop::TYPE_IO;
- if (thread->StartWithOptions(options)) {
- base::MessageLoop* message_loop = thread->message_loop();
- message_loop->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&StartServerOnHandlerThread, handler,
- base::Unretained(thread.release()), server_socket_factory,
- output_directory, frontend_dir, bundles_resources));
- }
-}
-
-// DevToolsAgentHostClientImpl -----------------------------------------------
-// An internal implementation of DevToolsAgentHostClient that delegates
-// messages sent to a DebuggerShell instance.
-class DevToolsAgentHostClientImpl : public DevToolsAgentHostClient {
- public:
- DevToolsAgentHostClientImpl(base::MessageLoop* message_loop,
- ServerWrapper* server_wrapper,
- int connection_id,
- scoped_refptr<DevToolsAgentHost> agent_host)
- : message_loop_(message_loop),
- server_wrapper_(server_wrapper),
- connection_id_(connection_id),
- agent_host_(agent_host) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- agent_host_->AttachClient(this);
- }
-
- ~DevToolsAgentHostClientImpl() override {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (agent_host_.get())
- agent_host_->DetachClient(this);
- }
-
- void AgentHostClosed(DevToolsAgentHost* agent_host,
- bool replaced_with_another_client) override {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(agent_host == agent_host_.get());
-
- std::string message = base::StringPrintf(
- "{ \"method\": \"Inspector.detached\", "
- "\"params\": { \"reason\": \"%s\"} }",
- replaced_with_another_client ?
- "replaced_with_devtools" : "target_closed");
- DispatchProtocolMessage(agent_host, message);
-
- agent_host_ = nullptr;
- message_loop_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&ServerWrapper::Close, base::Unretained(server_wrapper_),
- connection_id_));
- }
-
- void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
- const std::string& message) override {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(agent_host == agent_host_.get());
- message_loop_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&ServerWrapper::SendOverWebSocket,
- base::Unretained(server_wrapper_), connection_id_, message));
- }
-
- void OnMessage(const std::string& message) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (agent_host_.get())
- agent_host_->DispatchProtocolMessage(this, message);
- }
-
- private:
- base::MessageLoop* const message_loop_;
- ServerWrapper* const server_wrapper_;
- const int connection_id_;
- scoped_refptr<DevToolsAgentHost> agent_host_;
-};
-
-static bool TimeComparator(const DevToolsTargetDescriptor* desc1,
- const DevToolsTargetDescriptor* desc2) {
- return desc1->GetLastActivityTime() > desc2->GetLastActivityTime();
-}
-
-// DevToolsHttpHandler::ServerSocketFactory ----------------------------------
-
-std::unique_ptr<net::ServerSocket>
-DevToolsHttpHandler::ServerSocketFactory::CreateForHttpServer() {
- return nullptr;
-}
-
-std::unique_ptr<net::ServerSocket>
-DevToolsHttpHandler::ServerSocketFactory::CreateForTethering(
- std::string* name) {
- return nullptr;
-}
-
-// DevToolsHttpHandler -------------------------------------------------------
-
-DevToolsHttpHandler::~DevToolsHttpHandler() {
- TerminateOnUI(thread_, server_wrapper_, socket_factory_);
- STLDeleteValues(&descriptor_map_);
- STLDeleteValues(&connection_to_client_);
-}
-
-GURL DevToolsHttpHandler::GetFrontendURL(const std::string& path) {
- if (!server_ip_address_)
- return GURL();
- return GURL(std::string("http://") + server_ip_address_->ToString() +
- (path.empty() ? frontend_url_ : path));
-}
-
-static std::string PathWithoutParams(const std::string& path) {
- size_t query_position = path.find("?");
- if (query_position != std::string::npos)
- return path.substr(0, query_position);
- return path;
-}
-
-static std::string GetMimeType(const std::string& filename) {
- if (base::EndsWith(filename, ".html", base::CompareCase::INSENSITIVE_ASCII)) {
- return "text/html";
- } else if (base::EndsWith(filename, ".css",
- base::CompareCase::INSENSITIVE_ASCII)) {
- return "text/css";
- } else if (base::EndsWith(filename, ".js",
- base::CompareCase::INSENSITIVE_ASCII)) {
- return "application/javascript";
- } else if (base::EndsWith(filename, ".png",
- base::CompareCase::INSENSITIVE_ASCII)) {
- return "image/png";
- } else if (base::EndsWith(filename, ".gif",
- base::CompareCase::INSENSITIVE_ASCII)) {
- return "image/gif";
- } else if (base::EndsWith(filename, ".json",
- base::CompareCase::INSENSITIVE_ASCII)) {
- return "application/json";
- } else if (base::EndsWith(filename, ".svg",
- base::CompareCase::INSENSITIVE_ASCII)) {
- return "image/svg+xml";
- }
- LOG(ERROR) << "GetMimeType doesn't know mime type for: "
- << filename
- << " text/plain will be returned";
- NOTREACHED();
- return "text/plain";
-}
-
-void ServerWrapper::OnHttpRequest(int connection_id,
- const net::HttpServerRequestInfo& info) {
- server_->SetSendBufferSize(connection_id, kSendBufferSizeForDevTools);
-
- if (info.path.find("/json") == 0) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&DevToolsHttpHandler::OnJsonRequest,
- handler_,
- connection_id,
- info));
- return;
- }
-
- if (info.path.find(kThumbUrlPrefix) == 0) {
- // Thumbnail request.
- const std::string target_id = info.path.substr(strlen(kThumbUrlPrefix));
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&DevToolsHttpHandler::OnThumbnailRequest,
- handler_,
- connection_id,
- target_id));
- return;
- }
-
- if (info.path.empty() || info.path == "/") {
- // Discovery page request.
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&DevToolsHttpHandler::OnDiscoveryPageRequest,
- handler_,
- connection_id));
- return;
- }
-
- if (info.path.find("/devtools/") != 0) {
- server_->Send404(connection_id);
- return;
- }
-
- std::string filename = PathWithoutParams(info.path.substr(10));
- std::string mime_type = GetMimeType(filename);
-
- if (!frontend_dir_.empty()) {
- base::FilePath path = frontend_dir_.AppendASCII(filename);
- std::string data;
- base::ReadFileToString(path, &data);
- server_->Send200(connection_id, data, mime_type);
- return;
- }
-
- if (bundles_resources_) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&DevToolsHttpHandler::OnFrontendResourceRequest,
- handler_,
- connection_id,
- filename));
- return;
- }
- server_->Send404(connection_id);
-}
-
-void ServerWrapper::OnWebSocketRequest(
- int connection_id,
- const net::HttpServerRequestInfo& request) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &DevToolsHttpHandler::OnWebSocketRequest,
- handler_,
- connection_id,
- request));
-}
-
-void ServerWrapper::OnWebSocketMessage(int connection_id,
- const std::string& data) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &DevToolsHttpHandler::OnWebSocketMessage,
- handler_,
- connection_id,
- data));
-}
-
-void ServerWrapper::OnClose(int connection_id) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- &DevToolsHttpHandler::OnClose,
- handler_,
- connection_id));
-}
-
-std::string DevToolsHttpHandler::GetFrontendURLInternal(
- const std::string& id,
- const std::string& host) {
- return base::StringPrintf(
- "%s%sws=%s%s%s",
- frontend_url_.c_str(),
- frontend_url_.find("?") == std::string::npos ? "?" : "&",
- host.c_str(),
- kPageUrlPrefix,
- id.c_str());
-}
-
-static bool ParseJsonPath(
- const std::string& path,
- std::string* command,
- std::string* target_id) {
-
- // Fall back to list in case of empty query.
- if (path.empty()) {
- *command = "list";
- return true;
- }
-
- if (path.find("/") != 0) {
- // Malformed command.
- return false;
- }
- *command = path.substr(1);
-
- size_t separator_pos = command->find("/");
- if (separator_pos != std::string::npos) {
- *target_id = command->substr(separator_pos + 1);
- *command = command->substr(0, separator_pos);
- }
- return true;
-}
-
-void DevToolsHttpHandler::OnJsonRequest(
- int connection_id,
- const net::HttpServerRequestInfo& info) {
- // Trim /json
- std::string path = info.path.substr(5);
-
- // Trim fragment and query
- std::string query;
- size_t query_pos = path.find("?");
- if (query_pos != std::string::npos) {
- query = path.substr(query_pos + 1);
- path = path.substr(0, query_pos);
- }
-
- size_t fragment_pos = path.find("#");
- if (fragment_pos != std::string::npos)
- path = path.substr(0, fragment_pos);
-
- std::string command;
- std::string target_id;
- if (!ParseJsonPath(path, &command, &target_id)) {
- SendJson(connection_id,
- net::HTTP_NOT_FOUND,
- NULL,
- "Malformed query: " + info.path);
- return;
- }
-
- if (command == "version") {
- base::DictionaryValue version;
- version.SetString("Protocol-Version",
- DevToolsAgentHost::GetProtocolVersion().c_str());
- version.SetString("WebKit-Version", content::GetWebKitVersion());
- version.SetString("Browser", product_name_);
- version.SetString("User-Agent", user_agent_);
-#if defined(OS_ANDROID)
- version.SetString("Android-Package",
- base::android::BuildInfo::GetInstance()->package_name());
-#endif
- SendJson(connection_id, net::HTTP_OK, &version, std::string());
- return;
- }
-
- if (command == "list") {
- std::string host = info.headers["host"];
- DevToolsTargetDescriptor::List descriptors =
- devtools_discovery::DevToolsDiscoveryManager::GetInstance()->
- GetDescriptors();
- std::sort(descriptors.begin(), descriptors.end(), TimeComparator);
- STLDeleteValues(&descriptor_map_);
- base::ListValue list_value;
- for (DevToolsTargetDescriptor* descriptor : descriptors) {
- descriptor_map_[descriptor->GetId()] = descriptor;
- list_value.Append(SerializeDescriptor(*descriptor, host));
- }
- SendJson(connection_id, net::HTTP_OK, &list_value, std::string());
- return;
- }
-
- if (command == "new") {
- GURL url(net::UnescapeURLComponent(
- query, net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS |
- net::UnescapeRule::PATH_SEPARATORS));
- if (!url.is_valid())
- url = GURL(url::kAboutBlankURL);
- std::unique_ptr<DevToolsTargetDescriptor> descriptor =
- devtools_discovery::DevToolsDiscoveryManager::GetInstance()->CreateNew(
- url);
- if (!descriptor) {
- SendJson(connection_id,
- net::HTTP_INTERNAL_SERVER_ERROR,
- NULL,
- "Could not create new page");
- return;
- }
- std::string host = info.headers["host"];
- std::unique_ptr<base::DictionaryValue> dictionary(
- SerializeDescriptor(*descriptor.get(), host));
- SendJson(connection_id, net::HTTP_OK, dictionary.get(), std::string());
- const std::string target_id = descriptor->GetId();
- descriptor_map_[target_id] = descriptor.release();
- return;
- }
-
- if (command == "activate" || command == "close") {
- DevToolsTargetDescriptor* descriptor = GetDescriptor(target_id);
- if (!descriptor) {
- SendJson(connection_id,
- net::HTTP_NOT_FOUND,
- NULL,
- "No such target id: " + target_id);
- return;
- }
-
- if (command == "activate") {
- if (descriptor->Activate()) {
- SendJson(connection_id, net::HTTP_OK, NULL, "Target activated");
- } else {
- SendJson(connection_id,
- net::HTTP_INTERNAL_SERVER_ERROR,
- NULL,
- "Could not activate target id: " + target_id);
- }
- return;
- }
-
- if (command == "close") {
- if (descriptor->Close()) {
- SendJson(connection_id, net::HTTP_OK, NULL, "Target is closing");
- } else {
- SendJson(connection_id,
- net::HTTP_INTERNAL_SERVER_ERROR,
- NULL,
- "Could not close target id: " + target_id);
- }
- return;
- }
- }
- SendJson(connection_id,
- net::HTTP_NOT_FOUND,
- NULL,
- "Unknown command: " + command);
- return;
-}
-
-DevToolsTargetDescriptor* DevToolsHttpHandler::GetDescriptor(
- const std::string& target_id) {
- DescriptorMap::const_iterator it = descriptor_map_.find(target_id);
- if (it == descriptor_map_.end())
- return nullptr;
- return it->second;
-}
-
-void DevToolsHttpHandler::OnThumbnailRequest(
- int connection_id, const std::string& target_id) {
- DevToolsTargetDescriptor* descriptor = GetDescriptor(target_id);
- GURL page_url;
- if (descriptor)
- page_url = descriptor->GetURL();
- std::string data = delegate_->GetPageThumbnailData(page_url);
- if (!data.empty())
- Send200(connection_id, data, "image/png");
- else
- Send404(connection_id);
-}
-
-void DevToolsHttpHandler::OnDiscoveryPageRequest(int connection_id) {
- std::string response = delegate_->GetDiscoveryPageHTML();
- Send200(connection_id, response, "text/html; charset=UTF-8");
-}
-
-void DevToolsHttpHandler::OnFrontendResourceRequest(
- int connection_id, const std::string& path) {
- Send200(connection_id,
- delegate_->GetFrontendResource(path),
- GetMimeType(path));
-}
-
-void DevToolsHttpHandler::OnWebSocketRequest(
- int connection_id,
- const net::HttpServerRequestInfo& request) {
- if (!thread_)
- return;
-
- std::string browser_prefix = "/devtools/browser";
- size_t browser_pos = request.path.find(browser_prefix);
- if (browser_pos == 0) {
- scoped_refptr<DevToolsAgentHost> browser_agent =
- DevToolsAgentHost::CreateForBrowser(
- thread_->task_runner(),
- base::Bind(&ServerSocketFactory::CreateForTethering,
- base::Unretained(socket_factory_)));
- connection_to_client_[connection_id] = new DevToolsAgentHostClientImpl(
- thread_->message_loop(), server_wrapper_, connection_id, browser_agent);
- AcceptWebSocket(connection_id, request);
- return;
- }
-
- // Handle external connections (such as frontend api) on the embedder level.
- content::DevToolsExternalAgentProxyDelegate* external_delegate =
- delegate_->HandleWebSocketConnection(request.path);
- if (external_delegate) {
- scoped_refptr<DevToolsAgentHost> agent_host =
- DevToolsAgentHost::Create(external_delegate);
- connection_to_client_[connection_id] = new DevToolsAgentHostClientImpl(
- thread_->message_loop(), server_wrapper_, connection_id, agent_host);
- AcceptWebSocket(connection_id, request);
- return;
- }
-
- size_t pos = request.path.find(kPageUrlPrefix);
- if (pos != 0) {
- Send404(connection_id);
- return;
- }
-
- std::string target_id = request.path.substr(strlen(kPageUrlPrefix));
- DevToolsTargetDescriptor* descriptor = GetDescriptor(target_id);
- scoped_refptr<DevToolsAgentHost> agent =
- descriptor ? descriptor->GetAgentHost() : nullptr;
- if (!agent.get()) {
- Send500(connection_id, "No such target id: " + target_id);
- return;
- }
-
- if (agent->IsAttached()) {
- Send500(connection_id,
- "Target with given id is being inspected: " + target_id);
- return;
- }
-
- DevToolsAgentHostClientImpl* client_host = new DevToolsAgentHostClientImpl(
- thread_->message_loop(), server_wrapper_, connection_id, agent);
- connection_to_client_[connection_id] = client_host;
-
- AcceptWebSocket(connection_id, request);
-}
-
-void DevToolsHttpHandler::OnWebSocketMessage(
- int connection_id,
- const std::string& data) {
- ConnectionToClientMap::iterator it =
- connection_to_client_.find(connection_id);
- if (it != connection_to_client_.end())
- it->second->OnMessage(data);
-}
-
-void DevToolsHttpHandler::OnClose(int connection_id) {
- ConnectionToClientMap::iterator it =
- connection_to_client_.find(connection_id);
- if (it != connection_to_client_.end()) {
- delete it->second;
- connection_to_client_.erase(connection_id);
- }
-}
-
-DevToolsHttpHandler::DevToolsHttpHandler(
- std::unique_ptr<ServerSocketFactory> server_socket_factory,
- const std::string& frontend_url,
- DevToolsHttpHandlerDelegate* delegate,
- const base::FilePath& output_directory,
- const base::FilePath& debug_frontend_dir,
- const std::string& product_name,
- const std::string& user_agent)
- : thread_(nullptr),
- frontend_url_(frontend_url),
- product_name_(product_name),
- user_agent_(user_agent),
- server_wrapper_(nullptr),
- delegate_(delegate),
- socket_factory_(nullptr),
- weak_factory_(this) {
- bool bundles_resources = frontend_url_.empty();
- if (frontend_url_.empty())
- frontend_url_ = "/devtools/inspector.html";
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&StartServerOnFile,
- weak_factory_.GetWeakPtr(),
- server_socket_factory.release(),
- output_directory,
- debug_frontend_dir,
- bundles_resources));
-}
-
-void DevToolsHttpHandler::ServerStarted(
- base::Thread* thread,
- ServerWrapper* server_wrapper,
- ServerSocketFactory* socket_factory,
- std::unique_ptr<net::IPEndPoint> ip_address) {
- thread_ = thread;
- server_wrapper_ = server_wrapper;
- socket_factory_ = socket_factory;
- server_ip_address_.swap(ip_address);
-}
-
-void ServerWrapper::WriteActivePortToUserProfile(
- const base::FilePath& output_directory) {
- DCHECK(!output_directory.empty());
- net::IPEndPoint endpoint;
- int err;
- if ((err = server_->GetLocalAddress(&endpoint)) != net::OK) {
- LOG(ERROR) << "Error " << err << " getting local address";
- return;
- }
-
- // Write this port to a well-known file in the profile directory
- // so Telemetry can pick it up.
- base::FilePath path = output_directory.Append(kDevToolsActivePortFileName);
- std::string port_string = base::UintToString(endpoint.port());
- if (base::WriteFile(path, port_string.c_str(),
- static_cast<int>(port_string.length())) < 0) {
- LOG(ERROR) << "Error writing DevTools active port to file";
- }
-}
-
-void DevToolsHttpHandler::SendJson(int connection_id,
- net::HttpStatusCode status_code,
- base::Value* value,
- const std::string& message) {
- if (!thread_)
- return;
-
- // Serialize value and message.
- std::string json_value;
- if (value) {
- base::JSONWriter::WriteWithOptions(
- *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_value);
- }
- std::string json_message;
- base::JSONWriter::Write(base::StringValue(message), &json_message);
-
- net::HttpServerResponseInfo response(status_code);
- response.SetBody(json_value + message, "application/json; charset=UTF-8");
-
- thread_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&ServerWrapper::SendResponse,
- base::Unretained(server_wrapper_), connection_id, response));
-}
-
-void DevToolsHttpHandler::Send200(int connection_id,
- const std::string& data,
- const std::string& mime_type) {
- if (!thread_)
- return;
- thread_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&ServerWrapper::Send200, base::Unretained(server_wrapper_),
- connection_id, data, mime_type));
-}
-
-void DevToolsHttpHandler::Send404(int connection_id) {
- if (!thread_)
- return;
- thread_->task_runner()->PostTask(
- FROM_HERE, base::Bind(&ServerWrapper::Send404,
- base::Unretained(server_wrapper_), connection_id));
-}
-
-void DevToolsHttpHandler::Send500(int connection_id,
- const std::string& message) {
- if (!thread_)
- return;
- thread_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&ServerWrapper::Send500, base::Unretained(server_wrapper_),
- connection_id, message));
-}
-
-void DevToolsHttpHandler::AcceptWebSocket(
- int connection_id,
- const net::HttpServerRequestInfo& request) {
- if (!thread_)
- return;
- thread_->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&ServerWrapper::AcceptWebSocket,
- base::Unretained(server_wrapper_), connection_id, request));
-}
-
-base::DictionaryValue* DevToolsHttpHandler::SerializeDescriptor(
- const DevToolsTargetDescriptor& descriptor,
- const std::string& host) {
- base::DictionaryValue* dictionary = new base::DictionaryValue;
-
- std::string id = descriptor.GetId();
- dictionary->SetString(kTargetIdField, id);
- std::string parent_id = descriptor.GetParentId();
- if (!parent_id.empty())
- dictionary->SetString(kTargetParentIdField, parent_id);
- dictionary->SetString(kTargetTypeField, descriptor.GetType());
- dictionary->SetString(kTargetTitleField,
- net::EscapeForHTML(descriptor.GetTitle()));
- dictionary->SetString(kTargetDescriptionField, descriptor.GetDescription());
-
- GURL url = descriptor.GetURL();
- dictionary->SetString(kTargetUrlField, url.spec());
-
- GURL favicon_url = descriptor.GetFaviconURL();
- if (favicon_url.is_valid())
- dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
-
- if (!delegate_->GetPageThumbnailData(url).empty()) {
- dictionary->SetString(kTargetThumbnailUrlField,
- std::string(kThumbUrlPrefix) + id);
- }
-
- if (!descriptor.IsAttached()) {
- dictionary->SetString(kTargetWebSocketDebuggerUrlField,
- base::StringPrintf("ws://%s%s%s",
- host.c_str(),
- kPageUrlPrefix,
- id.c_str()));
- std::string devtools_frontend_url = GetFrontendURLInternal(
- id.c_str(),
- host);
- dictionary->SetString(
- kTargetDevtoolsFrontendUrlField, devtools_frontend_url);
- }
-
- return dictionary;
-}
-
-} // namespace devtools_http_handler
diff --git a/chromium/components/devtools_http_handler/devtools_http_handler.h b/chromium/components/devtools_http_handler/devtools_http_handler.h
deleted file mode 100644
index d1518c3338e..00000000000
--- a/chromium/components/devtools_http_handler/devtools_http_handler.h
+++ /dev/null
@@ -1,151 +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 COMPONENTS_DEVTOOLS_HTTP_HANDLER_DEVTOOLS_HTTP_HANDLER_H_
-#define COMPONENTS_DEVTOOLS_HTTP_HANDLER_DEVTOOLS_HTTP_HANDLER_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/devtools_discovery/devtools_target_descriptor.h"
-#include "net/http/http_status_code.h"
-
-class GURL;
-
-namespace base {
-class DictionaryValue;
-class Thread;
-class Value;
-}
-
-namespace net {
-class IPEndPoint;
-class HttpServerRequestInfo;
-class ServerSocket;
-}
-
-namespace devtools_http_handler {
-
-class DevToolsAgentHostClientImpl;
-class DevToolsHttpHandlerDelegate;
-class ServerWrapper;
-
-// This class is used for managing DevTools remote debugging server.
-// Clients can connect to the specified ip:port and start debugging
-// this browser.
-class DevToolsHttpHandler {
- public:
-
- // Factory of net::ServerSocket. This is to separate instantiating dev tools
- // and instantiating server sockets.
- // All methods including destructor are called on a separate thread
- // different from any BrowserThread instance.
- class ServerSocketFactory {
- public:
- virtual ~ServerSocketFactory() {}
-
- // Returns a new instance of ServerSocket or nullptr if an error occurred.
- virtual std::unique_ptr<net::ServerSocket> CreateForHttpServer();
-
- // Creates a named socket for reversed tethering implementation (used with
- // remote debugging, primarily for mobile).
- virtual std::unique_ptr<net::ServerSocket> CreateForTethering(
- std::string* out_name);
- };
-
- // Takes ownership over |socket_factory| and |delegate|.
- // If |frontend_url| is empty, assumes it's bundled, and uses
- // |delegate->GetFrontendResource()|.
- // |delegate| is only accessed on UI thread.
- // If |active_port_output_directory| is non-empty, it is assumed the
- // socket_factory was initialized with an ephemeral port (0). The
- // port selected by the OS will be written to a well-known file in
- // the output directory.
- DevToolsHttpHandler(
- std::unique_ptr<ServerSocketFactory> server_socket_factory,
- const std::string& frontend_url,
- DevToolsHttpHandlerDelegate* delegate,
- const base::FilePath& active_port_output_directory,
- const base::FilePath& debug_frontend_dir,
- const std::string& product_name,
- const std::string& user_agent);
- ~DevToolsHttpHandler();
-
- // Returns the URL for the file at |path| in frontend.
- GURL GetFrontendURL(const std::string& path);
-
- private:
- friend class ServerWrapper;
- friend void ServerStartedOnUI(
- base::WeakPtr<DevToolsHttpHandler> handler,
- base::Thread* thread,
- ServerWrapper* server_wrapper,
- DevToolsHttpHandler::ServerSocketFactory* socket_factory,
- std::unique_ptr<net::IPEndPoint> ip_address);
-
- void OnJsonRequest(int connection_id,
- const net::HttpServerRequestInfo& info);
- void OnThumbnailRequest(int connection_id, const std::string& target_id);
- void OnDiscoveryPageRequest(int connection_id);
- void OnFrontendResourceRequest(int connection_id, const std::string& path);
- void OnWebSocketRequest(int connection_id,
- const net::HttpServerRequestInfo& info);
- void OnWebSocketMessage(int connection_id, const std::string& data);
- void OnClose(int connection_id);
-
- void ServerStarted(base::Thread* thread,
- ServerWrapper* server_wrapper,
- ServerSocketFactory* socket_factory,
- std::unique_ptr<net::IPEndPoint> ip_address);
-
- devtools_discovery::DevToolsTargetDescriptor* GetDescriptor(
- const std::string& target_id);
-
- void SendJson(int connection_id,
- net::HttpStatusCode status_code,
- base::Value* value,
- const std::string& message);
- void Send200(int connection_id,
- const std::string& data,
- const std::string& mime_type);
- void Send404(int connection_id);
- void Send500(int connection_id,
- const std::string& message);
- void AcceptWebSocket(int connection_id,
- const net::HttpServerRequestInfo& request);
-
- // Returns the front end url without the host at the beginning.
- std::string GetFrontendURLInternal(const std::string& target_id,
- const std::string& host);
-
- base::DictionaryValue* SerializeDescriptor(
- const devtools_discovery::DevToolsTargetDescriptor& descriptor,
- const std::string& host);
-
- // The thread used by the devtools handler to run server socket.
- base::Thread* thread_;
- std::string frontend_url_;
- std::string product_name_;
- std::string user_agent_;
- ServerWrapper* server_wrapper_;
- std::unique_ptr<net::IPEndPoint> server_ip_address_;
- typedef std::map<int, DevToolsAgentHostClientImpl*> ConnectionToClientMap;
- ConnectionToClientMap connection_to_client_;
- const std::unique_ptr<DevToolsHttpHandlerDelegate> delegate_;
- ServerSocketFactory* socket_factory_;
- using DescriptorMap =
- std::map<std::string, devtools_discovery::DevToolsTargetDescriptor*>;
- DescriptorMap descriptor_map_;
- base::WeakPtrFactory<DevToolsHttpHandler> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(DevToolsHttpHandler);
-};
-
-} // namespace devtools_http_handler
-
-#endif // COMPONENTS_DEVTOOLS_HTTP_HANDLER_DEVTOOLS_HTTP_HANDLER_H_
diff --git a/chromium/components/devtools_http_handler/devtools_http_handler_delegate.h b/chromium/components/devtools_http_handler/devtools_http_handler_delegate.h
deleted file mode 100644
index cf4b9db7c74..00000000000
--- a/chromium/components/devtools_http_handler/devtools_http_handler_delegate.h
+++ /dev/null
@@ -1,42 +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 COMPONENTS_DEVTOOLS_HTTP_HANDLER_DEVTOOLS_HTTP_HANDLER_DELEGATE_H_
-#define COMPONENTS_DEVTOOLS_HTTP_HANDLER_DEVTOOLS_HTTP_HANDLER_DELEGATE_H_
-
-#include <string>
-
-#include "url/gurl.h"
-
-namespace content {
-class DevToolsExternalAgentProxyDelegate;
-}
-
-namespace devtools_http_handler {
-
-class DevToolsHttpHandlerDelegate {
- public:
- virtual ~DevToolsHttpHandlerDelegate() {}
-
- // Should return discovery page HTML that should list available tabs
- // and provide attach links.
- virtual std::string GetDiscoveryPageHTML() = 0;
-
- // Returns frontend resource data by |path|. Only used if
- // |BundlesFrontendResources| returns |true|.
- virtual std::string GetFrontendResource(const std::string& path) = 0;
-
- // Get a thumbnail for a given page. Returns non-empty string iff we have the
- // thumbnail.
- virtual std::string GetPageThumbnailData(const GURL& url) = 0;
-
- // Allows embedder to handle custom websocket-based protocol connection
- // pointing remote debugging port. Returns ownership.
- virtual content::DevToolsExternalAgentProxyDelegate*
- HandleWebSocketConnection(const std::string& path) = 0;
-};
-
-} // namespace devtools_http_handler
-
-#endif // COMPONENTS_DEVTOOLS_HTTP_HANDLER_DEVTOOLS_HTTP_HANDLER_DELEGATE_H_
diff --git a/chromium/components/devtools_http_handler/devtools_http_handler_unittest.cc b/chromium/components/devtools_http_handler/devtools_http_handler_unittest.cc
deleted file mode 100644
index 4a02899e125..00000000000
--- a/chromium/components/devtools_http_handler/devtools_http_handler_unittest.cc
+++ /dev/null
@@ -1,199 +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 "components/devtools_http_handler/devtools_http_handler.h"
-
-#include <stdint.h>
-
-#include <memory>
-#include <utility>
-
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/location.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/values.h"
-#include "components/devtools_http_handler/devtools_http_handler_delegate.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "content/public/test/test_utils.h"
-#include "net/base/ip_address.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "net/socket/server_socket.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using content::BrowserThread;
-
-namespace devtools_http_handler {
-namespace {
-
-const uint16_t kDummyPort = 4321;
-const base::FilePath::CharType kDevToolsActivePortFileName[] =
- FILE_PATH_LITERAL("DevToolsActivePort");
-
-class DummyServerSocket : public net::ServerSocket {
- public:
- DummyServerSocket() {}
-
- // net::ServerSocket "implementation"
- int Listen(const net::IPEndPoint& address, int backlog) override {
- return net::OK;
- }
-
- int GetLocalAddress(net::IPEndPoint* address) const override {
- *address = net::IPEndPoint(net::IPAddress::IPv4Localhost(), kDummyPort);
- return net::OK;
- }
-
- int Accept(std::unique_ptr<net::StreamSocket>* socket,
- const net::CompletionCallback& callback) override {
- return net::ERR_IO_PENDING;
- }
-};
-
-void QuitFromHandlerThread(const base::Closure& quit_closure) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_closure);
-}
-
-class DummyServerSocketFactory
- : public DevToolsHttpHandler::ServerSocketFactory {
- public:
- DummyServerSocketFactory(base::Closure quit_closure_1,
- base::Closure quit_closure_2)
- : quit_closure_1_(quit_closure_1),
- quit_closure_2_(quit_closure_2) {}
-
- ~DummyServerSocketFactory() override {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE, quit_closure_2_);
- }
-
- protected:
- std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&QuitFromHandlerThread, quit_closure_1_));
- return base::WrapUnique(new DummyServerSocket());
- }
-
- base::Closure quit_closure_1_;
- base::Closure quit_closure_2_;
-};
-
-class FailingServerSocketFactory : public DummyServerSocketFactory {
- public:
- FailingServerSocketFactory(const base::Closure& quit_closure_1,
- const base::Closure& quit_closure_2)
- : DummyServerSocketFactory(quit_closure_1, quit_closure_2) {
- }
-
- private:
- std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&QuitFromHandlerThread, quit_closure_1_));
- return nullptr;
- }
-};
-
-class DummyDelegate : public DevToolsHttpHandlerDelegate {
- public:
- std::string GetDiscoveryPageHTML() override { return std::string(); }
-
- std::string GetFrontendResource(const std::string& path) override {
- return std::string();
- }
-
- std::string GetPageThumbnailData(const GURL& url) override {
- return std::string();
- }
-
- content::DevToolsExternalAgentProxyDelegate*
- HandleWebSocketConnection(const std::string& path) override {
- return nullptr;
- }
-};
-
-}
-
-class DevToolsHttpHandlerTest : public testing::Test {
- public:
- DevToolsHttpHandlerTest() : testing::Test() { }
-
- private:
- content::TestBrowserThreadBundle thread_bundle_;
-};
-
-TEST_F(DevToolsHttpHandlerTest, TestStartStop) {
- base::RunLoop run_loop, run_loop_2;
- std::unique_ptr<DevToolsHttpHandler::ServerSocketFactory> factory(
- new DummyServerSocketFactory(run_loop.QuitClosure(),
- run_loop_2.QuitClosure()));
- std::unique_ptr<DevToolsHttpHandler> devtools_http_handler(
- new DevToolsHttpHandler(std::move(factory), std::string(),
- new DummyDelegate(), base::FilePath(),
- base::FilePath(), std::string(), std::string()));
- // Our dummy socket factory will post a quit message once the server will
- // become ready.
- run_loop.Run();
- devtools_http_handler.reset();
- // Make sure the handler actually stops.
- run_loop_2.Run();
-}
-
-TEST_F(DevToolsHttpHandlerTest, TestServerSocketFailed) {
- base::RunLoop run_loop, run_loop_2;
- std::unique_ptr<DevToolsHttpHandler::ServerSocketFactory> factory(
- new FailingServerSocketFactory(run_loop.QuitClosure(),
- run_loop_2.QuitClosure()));
- std::unique_ptr<DevToolsHttpHandler> devtools_http_handler(
- new DevToolsHttpHandler(std::move(factory), std::string(),
- new DummyDelegate(), base::FilePath(),
- base::FilePath(), std::string(), std::string()));
- // Our dummy socket factory will post a quit message once the server will
- // become ready.
- run_loop.Run();
- for (int i = 0; i < 5; i++) {
- RunAllPendingInMessageLoop(BrowserThread::UI);
- RunAllPendingInMessageLoop(BrowserThread::FILE);
- }
- devtools_http_handler.reset();
- // Make sure the handler actually stops.
- run_loop_2.Run();
-}
-
-
-TEST_F(DevToolsHttpHandlerTest, TestDevToolsActivePort) {
- base::RunLoop run_loop, run_loop_2;
- base::ScopedTempDir temp_dir;
- EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
- std::unique_ptr<DevToolsHttpHandler::ServerSocketFactory> factory(
- new DummyServerSocketFactory(run_loop.QuitClosure(),
- run_loop_2.QuitClosure()));
- std::unique_ptr<DevToolsHttpHandler> devtools_http_handler(
- new DevToolsHttpHandler(std::move(factory), std::string(),
- new DummyDelegate(), temp_dir.path(),
- base::FilePath(), std::string(), std::string()));
- // Our dummy socket factory will post a quit message once the server will
- // become ready.
- run_loop.Run();
- devtools_http_handler.reset();
- // Make sure the handler actually stops.
- run_loop_2.Run();
-
- // Now make sure the DevToolsActivePort was written into the
- // temporary directory and its contents are as expected.
- base::FilePath active_port_file = temp_dir.path().Append(
- kDevToolsActivePortFileName);
- EXPECT_TRUE(base::PathExists(active_port_file));
- std::string file_contents;
- EXPECT_TRUE(base::ReadFileToString(active_port_file, &file_contents));
- int port = 0;
- EXPECT_TRUE(base::StringToInt(file_contents, &port));
- EXPECT_EQ(static_cast<int>(kDummyPort), port);
-}
-
-} // namespace devtools_http_handler
diff --git a/chromium/components/display_compositor.gypi b/chromium/components/display_compositor.gypi
deleted file mode 100644
index 54be47b5906..00000000000
--- a/chromium/components/display_compositor.gypi
+++ /dev/null
@@ -1,116 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/display_compositor:display_compositor
- 'target_name': 'display_compositor',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../cc/cc.gyp:cc',
- '../gpu/gpu.gyp:command_buffer_client',
- '../gpu/gpu.gyp:command_buffer_common',
- '../skia/skia.gyp:skia',
- '../third_party/khronos/khronos.gyp:khronos_headers',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/gfx.gyp:gfx_geometry',
- '../ui/gl/gl.gyp:gl',
- ],
-
- 'defines': [
- 'DISPLAY_COMPOSITOR_IMPLEMENTATION',
- ],
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
-
- 'include_dirs': [
- '..',
- ],
-
- 'sources': [
- 'display_compositor/buffer_queue.cc',
- 'display_compositor/buffer_queue.h',
- 'display_compositor/compositor_overlay_candidate_validator.h',
- 'display_compositor/compositor_overlay_candidate_validator_android.cc',
- 'display_compositor/compositor_overlay_candidate_validator_android.h',
- 'display_compositor/compositor_overlay_candidate_validator_mac.h',
- 'display_compositor/compositor_overlay_candidate_validator_mac.mm',
- 'display_compositor/compositor_overlay_candidate_validator_ozone.cc',
- 'display_compositor/compositor_overlay_candidate_validator_ozone.h',
- 'display_compositor/display_compositor_export.h',
- 'display_compositor/gl_helper.cc',
- 'display_compositor/gl_helper.h',
- 'display_compositor/gl_helper_readback_support.cc',
- 'display_compositor/gl_helper_readback_support.h',
- 'display_compositor/gl_helper_scaling.cc',
- 'display_compositor/gl_helper_scaling.h',
- ],
- 'conditions': [
- ['use_ozone==1', {
- 'dependencies': [
- '../ui/ozone/ozone.gyp:ozone_base',
- ],
- }],
- ],
- },
- {
- # GN version: //components/display_compositor:display_compositor_gl_tests
- 'target_name': 'display_compositor_gl_tests',
- 'type': '<(gtest_target_type)',
- 'dependencies': [
- 'display_compositor',
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../cc/cc_tests.gyp:cc_test_support',
- '../gpu/gpu.gyp:command_buffer_client',
- '../media/media.gyp:media',
- '../skia/skia.gyp:skia',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- '../ui/gl/gl.gyp:gl_test_support',
- ],
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
-
- 'sources': [
- "display_compositor/display_compositor_test_suite.cc",
- "display_compositor/display_compositor_test_suite.h",
- "display_compositor/gl_helper_unittest.cc",
- "display_compositor/run_all_unittests.cc",
- "display_compositor/yuv_readback_unittest.cc",
- ]
- },
- {
- # GN version: //components/display_compositor:display_compositor_benchmark
- 'target_name': 'display_compositor_benchmark',
- 'type': '<(gtest_target_type)',
- 'dependencies': [
- 'display_compositor',
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../cc/cc_tests.gyp:cc_test_support',
- '../gpu/gpu.gyp:command_buffer_client',
- '../media/media.gyp:media',
- '../skia/skia.gyp:skia',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- '../ui/gl/gl.gyp:gl_test_support',
- ],
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
-
- 'sources': [
- "display_compositor/display_compositor_test_suite.cc",
- "display_compositor/display_compositor_test_suite.h",
- "display_compositor/gl_helper_benchmark.cc",
- "display_compositor/run_all_unittests.cc",
- ]
- },
- ]
-}
diff --git a/chromium/components/display_compositor/BUILD.gn b/chromium/components/display_compositor/BUILD.gn
index 6afe1e6944d..984f0422d2b 100644
--- a/chromium/components/display_compositor/BUILD.gn
+++ b/chromium/components/display_compositor/BUILD.gn
@@ -29,7 +29,9 @@ component("display_compositor") {
"//gpu/command_buffer/client",
"//gpu/command_buffer/client:gles2_interface",
"//gpu/command_buffer/common",
+ "//gpu/ipc/common:surface_handle_type",
"//skia",
+ "//ui/display/types",
"//ui/gfx",
]
@@ -85,6 +87,7 @@ source_set("unit_tests") {
"//skia",
"//testing/gmock",
"//testing/gtest",
+ "//ui/display/types",
"//ui/gl:test_support",
]
diff --git a/chromium/components/display_compositor/DEPS b/chromium/components/display_compositor/DEPS
index 34fad93b2d5..ee02c380f29 100644
--- a/chromium/components/display_compositor/DEPS
+++ b/chromium/components/display_compositor/DEPS
@@ -7,6 +7,7 @@ include_rules = [
"+gpu/ipc/common",
"+third_party/khronos/GLES2",
"+third_party/skia",
+ "+ui/display",
"+ui/gfx",
"+ui/gl",
"+ui/ozone/public",
diff --git a/chromium/components/display_compositor/buffer_queue.cc b/chromium/components/display_compositor/buffer_queue.cc
index be5840706a2..fafdb406b4f 100644
--- a/chromium/components/display_compositor/buffer_queue.cc
+++ b/chromium/components/display_compositor/buffer_queue.cc
@@ -14,6 +14,7 @@
#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/display/types/display_snapshot.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/skia_util.h"
@@ -22,6 +23,7 @@ namespace display_compositor {
BufferQueue::BufferQueue(gpu::gles2::GLES2Interface* gl,
uint32_t texture_target,
uint32_t internal_format,
+ gfx::BufferFormat format,
GLHelper* gl_helper,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::SurfaceHandle surface_handle)
@@ -30,9 +32,13 @@ BufferQueue::BufferQueue(gpu::gles2::GLES2Interface* gl,
allocated_count_(0),
texture_target_(texture_target),
internal_format_(internal_format),
+ format_(format),
gl_helper_(gl_helper),
gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
- surface_handle_(surface_handle) {}
+ surface_handle_(surface_handle) {
+ DCHECK(gpu::IsImageFormatCompatibleWithGpuMemoryBufferFormat(internal_format,
+ format_));
+}
BufferQueue::~BufferQueue() {
FreeAllSurfaces();
@@ -107,8 +113,10 @@ void BufferQueue::SwapBuffers(const gfx::Rect& damage) {
gl_->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
}
-void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) {
- if (size == size_)
+void BufferQueue::Reshape(const gfx::Size& size,
+ float scale_factor,
+ const gfx::ColorSpace& color_space) {
+ if (size == size_ && color_space == color_space_)
return;
#if !defined(OS_MACOSX)
// TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that
@@ -117,6 +125,7 @@ void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) {
DCHECK(!current_surface_);
#endif
size_ = size;
+ color_space_ = color_space;
// TODO: add stencil buffer when needed.
gl_->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
@@ -208,16 +217,15 @@ std::unique_ptr<BufferQueue::AllocatedSurface> BufferQueue::GetNextSurface() {
// We don't want to allow anything more than triple buffering.
DCHECK_LT(allocated_count_, 4U);
-
std::unique_ptr<gfx::GpuMemoryBuffer> buffer(
gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
- size_, gpu::DefaultBufferFormatForImageFormat(internal_format_),
- gfx::BufferUsage::SCANOUT, surface_handle_));
+ size_, format_, gfx::BufferUsage::SCANOUT, surface_handle_));
if (!buffer.get()) {
gl_->DeleteTextures(1, &texture);
DLOG(ERROR) << "Failed to allocate GPU memory buffer";
return nullptr;
}
+ buffer->SetColorSpaceForScanout(color_space_);
uint32_t id =
gl_->CreateImageCHROMIUM(buffer->AsClientBuffer(), size_.width(),
@@ -231,8 +239,8 @@ std::unique_ptr<BufferQueue::AllocatedSurface> BufferQueue::GetNextSurface() {
allocated_count_++;
gl_->BindTexture(texture_target_, texture);
gl_->BindTexImage2DCHROMIUM(texture_target_, id);
- return base::WrapUnique(new AllocatedSurface(this, std::move(buffer), texture,
- id, gfx::Rect(size_)));
+ return base::MakeUnique<AllocatedSurface>(this, std::move(buffer), texture,
+ id, gfx::Rect(size_));
}
BufferQueue::AllocatedSurface::AllocatedSurface(
diff --git a/chromium/components/display_compositor/buffer_queue.h b/chromium/components/display_compositor/buffer_queue.h
index e0a24848e21..3ae123d4759 100644
--- a/chromium/components/display_compositor/buffer_queue.h
+++ b/chromium/components/display_compositor/buffer_queue.h
@@ -15,6 +15,8 @@
#include "base/memory/ref_counted.h"
#include "components/display_compositor/display_compositor_export.h"
#include "gpu/ipc/common/surface_handle.h"
+#include "ui/gfx/buffer_types.h"
+#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
@@ -43,6 +45,7 @@ class DISPLAY_COMPOSITOR_EXPORT BufferQueue {
BufferQueue(gpu::gles2::GLES2Interface* gl,
uint32_t texture_target,
uint32_t internal_format,
+ gfx::BufferFormat format,
GLHelper* gl_helper,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::SurfaceHandle surface_handle);
@@ -53,7 +56,9 @@ class DISPLAY_COMPOSITOR_EXPORT BufferQueue {
void BindFramebuffer();
void SwapBuffers(const gfx::Rect& damage);
void PageFlipComplete();
- void Reshape(const gfx::Size& size, float scale_factor);
+ void Reshape(const gfx::Size& size,
+ float scale_factor,
+ const gfx::ColorSpace& color_space);
void RecreateBuffers();
@@ -102,10 +107,12 @@ class DISPLAY_COMPOSITOR_EXPORT BufferQueue {
gpu::gles2::GLES2Interface* const gl_;
gfx::Size size_;
+ gfx::ColorSpace color_space_;
uint32_t fbo_;
size_t allocated_count_;
uint32_t texture_target_;
uint32_t internal_format_;
+ gfx::BufferFormat format_;
// This surface is currently bound. This may be nullptr if no surface has
// been bound, or if allocation failed at bind.
std::unique_ptr<AllocatedSurface> current_surface_;
diff --git a/chromium/components/display_compositor/buffer_queue_unittest.cc b/chromium/components/display_compositor/buffer_queue_unittest.cc
index c102a37fe10..17ef79b0a8c 100644
--- a/chromium/components/display_compositor/buffer_queue_unittest.cc
+++ b/chromium/components/display_compositor/buffer_queue_unittest.cc
@@ -19,6 +19,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/khronos/GLES2/gl2ext.h"
+#include "ui/display/types/display_snapshot.h"
using ::testing::_;
using ::testing::Expectation;
@@ -29,7 +30,8 @@ namespace display_compositor {
class StubGpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
public:
- StubGpuMemoryBufferImpl() {}
+ StubGpuMemoryBufferImpl(size_t* set_color_space_count)
+ : set_color_space_count_(set_color_space_count) {}
// Overridden from gfx::GpuMemoryBuffer:
bool Map() override { return false; }
@@ -43,18 +45,25 @@ class StubGpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
gfx::GpuMemoryBufferId GetId() const override {
return gfx::GpuMemoryBufferId(0);
}
+ void SetColorSpaceForScanout(const gfx::ColorSpace& color_space) override {
+ *set_color_space_count_ += 1;
+ }
gfx::GpuMemoryBufferHandle GetHandle() const override {
return gfx::GpuMemoryBufferHandle();
}
ClientBuffer AsClientBuffer() override {
return reinterpret_cast<ClientBuffer>(this);
}
+
+ size_t* set_color_space_count_;
};
class StubGpuMemoryBufferManager : public cc::TestGpuMemoryBufferManager {
public:
StubGpuMemoryBufferManager() : allocate_succeeds_(true) {}
+ size_t set_color_space_count() const { return set_color_space_count_; }
+
void set_allocate_succeeds(bool value) { allocate_succeeds_ = value; }
std::unique_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
@@ -68,12 +77,13 @@ class StubGpuMemoryBufferManager : public cc::TestGpuMemoryBufferManager {
}
if (allocate_succeeds_)
return base::WrapUnique<gfx::GpuMemoryBuffer>(
- new StubGpuMemoryBufferImpl);
+ new StubGpuMemoryBufferImpl(&set_color_space_count_));
return nullptr;
}
private:
bool allocate_succeeds_;
+ size_t set_color_space_count_ = 0;
};
#if defined(OS_WIN)
@@ -92,6 +102,7 @@ class MockBufferQueue : public BufferQueue {
: BufferQueue(gl,
target,
internalformat,
+ ui::DisplaySnapshot::PrimaryFormat(),
nullptr,
gpu_memory_buffer_manager,
kFakeSurfaceHandle) {}
@@ -113,7 +124,7 @@ class BufferQueueTest : public ::testing::Test {
gpu_memory_buffer_manager_.reset(new StubGpuMemoryBufferManager);
mock_output_surface_ = new MockBufferQueue(context_provider_->ContextGL(),
gpu_memory_buffer_manager_.get(),
- GL_TEXTURE_2D, GL_RGBA);
+ GL_TEXTURE_2D, GL_RGB);
output_surface_.reset(mock_output_surface_);
output_surface_->Initialize();
}
@@ -253,8 +264,8 @@ std::unique_ptr<BufferQueue> CreateBufferQueue(
gpu::gles2::GLES2Interface* gl,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) {
std::unique_ptr<BufferQueue> buffer_queue(
- new BufferQueue(gl, target, GL_RGBA, nullptr, gpu_memory_buffer_manager,
- kFakeSurfaceHandle));
+ new BufferQueue(gl, target, GL_RGB, ui::DisplaySnapshot::PrimaryFormat(),
+ nullptr, gpu_memory_buffer_manager, kFakeSurfaceHandle));
buffer_queue->Initialize();
return buffer_queue;
}
@@ -273,7 +284,7 @@ TEST(BufferQueueStandaloneTest, FboInitialization) {
ON_CALL(*context, framebufferTexture2D(_, _, _, _, _))
.WillByDefault(Return());
- output_surface->Reshape(gfx::Size(10, 20), 1.0f);
+ output_surface->Reshape(gfx::Size(10, 20), 1.0f, gfx::ColorSpace());
}
TEST(BufferQueueStandaloneTest, FboBinding) {
@@ -292,7 +303,7 @@ TEST(BufferQueueStandaloneTest, FboBinding) {
EXPECT_CALL(*context, bindTexture(target, Ne(0U)));
EXPECT_CALL(*context, destroyImageCHROMIUM(1));
Expectation image =
- EXPECT_CALL(*context, createImageCHROMIUM(_, 0, 0, GL_RGBA))
+ EXPECT_CALL(*context, createImageCHROMIUM(_, 0, 0, GL_RGB))
.WillOnce(Return(1));
Expectation fb =
EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
@@ -321,11 +332,12 @@ TEST(BufferQueueStandaloneTest, CheckBoundFramebuffer) {
gl_helper.reset(new GLHelper(context_provider->ContextGL(),
context_provider->ContextSupport()));
- output_surface.reset(new BufferQueue(
- context_provider->ContextGL(), GL_TEXTURE_2D, GL_RGBA, gl_helper.get(),
- gpu_memory_buffer_manager.get(), kFakeSurfaceHandle));
+ output_surface.reset(
+ new BufferQueue(context_provider->ContextGL(), GL_TEXTURE_2D, GL_RGB,
+ ui::DisplaySnapshot::PrimaryFormat(), gl_helper.get(),
+ gpu_memory_buffer_manager.get(), kFakeSurfaceHandle));
output_surface->Initialize();
- output_surface->Reshape(screen_size, 1.0f);
+ output_surface->Reshape(screen_size, 1.0f, gfx::ColorSpace());
// Trigger a sub-buffer copy to exercise all paths.
output_surface->BindFramebuffer();
output_surface->SwapBuffers(screen_rect);
@@ -340,7 +352,7 @@ TEST(BufferQueueStandaloneTest, CheckBoundFramebuffer) {
}
TEST_F(BufferQueueTest, PartialSwapReuse) {
- output_surface_->Reshape(screen_size, 1.0f);
+ output_surface_->Reshape(screen_size, 1.0f, gfx::ColorSpace());
ASSERT_TRUE(doublebuffering_);
EXPECT_CALL(*mock_output_surface_,
CopyBufferDamage(_, _, small_damage, screen_rect))
@@ -360,7 +372,7 @@ TEST_F(BufferQueueTest, PartialSwapReuse) {
}
TEST_F(BufferQueueTest, PartialSwapFullFrame) {
- output_surface_->Reshape(screen_size, 1.0f);
+ output_surface_->Reshape(screen_size, 1.0f, gfx::ColorSpace());
ASSERT_TRUE(doublebuffering_);
EXPECT_CALL(*mock_output_surface_,
CopyBufferDamage(_, _, small_damage, screen_rect))
@@ -373,7 +385,7 @@ TEST_F(BufferQueueTest, PartialSwapFullFrame) {
}
TEST_F(BufferQueueTest, PartialSwapOverlapping) {
- output_surface_->Reshape(screen_size, 1.0f);
+ output_surface_->Reshape(screen_size, 1.0f, gfx::ColorSpace());
ASSERT_TRUE(doublebuffering_);
EXPECT_CALL(*mock_output_surface_,
CopyBufferDamage(_, _, small_damage, screen_rect))
@@ -483,7 +495,7 @@ TEST_F(BufferQueueTest, ReshapeWithInFlightSurfaces) {
SwapBuffers();
}
- output_surface_->Reshape(gfx::Size(10, 20), 1.0f);
+ output_surface_->Reshape(gfx::Size(10, 20), 1.0f, gfx::ColorSpace());
EXPECT_EQ(3u, in_flight_surfaces().size());
for (size_t i = 0; i < kSwapCount; ++i) {
@@ -496,19 +508,23 @@ TEST_F(BufferQueueTest, ReshapeWithInFlightSurfaces) {
}
TEST_F(BufferQueueTest, SwapAfterReshape) {
+ DCHECK_EQ(0u, gpu_memory_buffer_manager_->set_color_space_count());
const size_t kSwapCount = 3;
for (size_t i = 0; i < kSwapCount; ++i) {
output_surface_->BindFramebuffer();
SwapBuffers();
}
+ DCHECK_EQ(kSwapCount, gpu_memory_buffer_manager_->set_color_space_count());
- output_surface_->Reshape(gfx::Size(10, 20), 1.0f);
+ output_surface_->Reshape(gfx::Size(10, 20), 1.0f, gfx::ColorSpace());
+ DCHECK_EQ(kSwapCount, gpu_memory_buffer_manager_->set_color_space_count());
for (size_t i = 0; i < kSwapCount; ++i) {
output_surface_->BindFramebuffer();
SwapBuffers();
}
-
+ DCHECK_EQ(2 * kSwapCount,
+ gpu_memory_buffer_manager_->set_color_space_count());
EXPECT_EQ(2 * kSwapCount, in_flight_surfaces().size());
for (size_t i = 0; i < kSwapCount; ++i) {
@@ -524,6 +540,16 @@ TEST_F(BufferQueueTest, SwapAfterReshape) {
EXPECT_EQ(displayed_frame()->texture, next_texture_id);
EXPECT_TRUE(displayed_frame());
}
+
+ DCHECK_EQ(2 * kSwapCount,
+ gpu_memory_buffer_manager_->set_color_space_count());
+ for (size_t i = 0; i < kSwapCount; ++i) {
+ output_surface_->BindFramebuffer();
+ SwapBuffers();
+ output_surface_->PageFlipComplete();
+ }
+ DCHECK_EQ(2 * kSwapCount,
+ gpu_memory_buffer_manager_->set_color_space_count());
}
TEST_F(BufferQueueMockedContextTest, RecreateBuffers) {
@@ -558,7 +584,7 @@ TEST_F(BufferQueueMockedContextTest, RecreateBuffers) {
// Expect all 4 images to be destroyed, 3 of the existing textures to be
// copied from and 3 new images to be created.
- EXPECT_CALL(*context_, createImageCHROMIUM(_, 0, 0, GL_RGBA)).Times(3);
+ EXPECT_CALL(*context_, createImageCHROMIUM(_, 0, 0, GL_RGB)).Times(3);
Expectation copy1 = EXPECT_CALL(*mock_output_surface_,
CopyBufferDamage(_, displayed->texture, _, _))
.Times(1);
@@ -602,7 +628,7 @@ TEST_F(BufferQueueMockedContextTest, RecreateBuffers) {
}
TEST_F(BufferQueueTest, AllocateFails) {
- output_surface_->Reshape(screen_size, 1.0f);
+ output_surface_->Reshape(screen_size, 1.0f, gfx::ColorSpace());
// Succeed in the two swaps.
output_surface_->BindFramebuffer();
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.cc b/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.cc
index d2befbea656..805dae3b917 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.cc
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_android.cc
@@ -21,8 +21,7 @@ CompositorOverlayCandidateValidatorAndroid::
void CompositorOverlayCandidateValidatorAndroid::GetStrategies(
cc::OverlayProcessor::StrategyList* strategies) {
- strategies->push_back(
- base::WrapUnique(new cc::OverlayStrategyUnderlay(this)));
+ strategies->push_back(base::MakeUnique<cc::OverlayStrategyUnderlay>(this));
}
void CompositorOverlayCandidateValidatorAndroid::CheckOverlaySupport(
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc b/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc
index 644f21af3d8..3c0cfb12c23 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "base/memory/ptr_util.h"
+#include "cc/output/overlay_strategy_fullscreen.h"
#include "cc/output/overlay_strategy_single_on_top.h"
#include "cc/output/overlay_strategy_underlay.h"
#include "ui/ozone/public/overlay_candidates_ozone.h"
@@ -29,8 +30,10 @@ static gfx::BufferFormat GetBufferFormat(cc::ResourceFormat overlay_format) {
CompositorOverlayCandidateValidatorOzone::
CompositorOverlayCandidateValidatorOzone(
- std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates)
+ std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates,
+ bool single_fullscreen)
: overlay_candidates_(std::move(overlay_candidates)),
+ single_fullscreen_(single_fullscreen),
software_mirror_active_(false) {}
CompositorOverlayCandidateValidatorOzone::
@@ -38,10 +41,14 @@ CompositorOverlayCandidateValidatorOzone::
void CompositorOverlayCandidateValidatorOzone::GetStrategies(
cc::OverlayProcessor::StrategyList* strategies) {
- strategies->push_back(
- base::WrapUnique(new cc::OverlayStrategySingleOnTop(this)));
- strategies->push_back(
- base::WrapUnique(new cc::OverlayStrategyUnderlay(this)));
+ if (single_fullscreen_) {
+ strategies->push_back(
+ base::MakeUnique<cc::OverlayStrategyFullscreen>(this));
+ } else {
+ strategies->push_back(
+ base::MakeUnique<cc::OverlayStrategySingleOnTop>(this));
+ strategies->push_back(base::MakeUnique<cc::OverlayStrategyUnderlay>(this));
+ }
}
bool CompositorOverlayCandidateValidatorOzone::AllowCALayerOverlays() {
@@ -52,8 +59,16 @@ void CompositorOverlayCandidateValidatorOzone::CheckOverlaySupport(
cc::OverlayCandidateList* surfaces) {
// SW mirroring copies out of the framebuffer, so we can't remove any
// quads for overlaying, otherwise the output is incorrect.
- if (software_mirror_active_)
+ if (software_mirror_active_) {
+ for (size_t i = 0; i < surfaces->size(); i++) {
+ surfaces->at(i).overlay_handled = false;
+ }
return;
+ }
+
+ if (single_fullscreen_) {
+ return; // No need for validation for single fullscreen.
+ }
DCHECK_GE(2U, surfaces->size());
ui::OverlayCandidatesOzone::OverlaySurfaceCandidateList ozone_surface_list;
diff --git a/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.h b/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.h
index e157827f808..3e2c9e38b00 100644
--- a/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.h
+++ b/chromium/components/display_compositor/compositor_overlay_candidate_validator_ozone.h
@@ -21,8 +21,9 @@ namespace display_compositor {
class DISPLAY_COMPOSITOR_EXPORT CompositorOverlayCandidateValidatorOzone
: public CompositorOverlayCandidateValidator {
public:
- explicit CompositorOverlayCandidateValidatorOzone(
- std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates);
+ CompositorOverlayCandidateValidatorOzone(
+ std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates,
+ bool single_fullscreen);
~CompositorOverlayCandidateValidatorOzone() override;
// cc::OverlayCandidateValidator implementation.
@@ -35,6 +36,7 @@ class DISPLAY_COMPOSITOR_EXPORT CompositorOverlayCandidateValidatorOzone
private:
std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates_;
+ bool single_fullscreen_;
bool software_mirror_active_;
DISALLOW_COPY_AND_ASSIGN(CompositorOverlayCandidateValidatorOzone);
diff --git a/chromium/components/display_compositor/gl_helper_benchmark.cc b/chromium/components/display_compositor/gl_helper_benchmark.cc
index bf1cbb5428a..04c60c221a3 100644
--- a/chromium/components/display_compositor/gl_helper_benchmark.cc
+++ b/chromium/components/display_compositor/gl_helper_benchmark.cc
@@ -23,6 +23,7 @@
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/display_compositor/gl_helper.h"
#include "components/display_compositor/gl_helper_scaling.h"
@@ -74,7 +75,8 @@ class GLHelperBenchmark : public testing::Test {
nullptr, /* share_context */
attributes, gpu::SharedMemoryLimits(),
nullptr, /* gpu_memory_buffer_manager */
- nullptr /* image_factory */));
+ nullptr, /* image_factory */
+ base::ThreadTaskRunnerHandle::Get()));
gl_ = context_->GetImplementation();
gpu::ContextSupport* support = context_->GetImplementation();
diff --git a/chromium/components/display_compositor/gl_helper_unittest.cc b/chromium/components/display_compositor/gl_helper_unittest.cc
index 44fe9917713..5e65ee0cbfc 100644
--- a/chromium/components/display_compositor/gl_helper_unittest.cc
+++ b/chromium/components/display_compositor/gl_helper_unittest.cc
@@ -27,6 +27,7 @@
#include "base/synchronization/waitable_event.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "components/display_compositor/gl_helper.h"
@@ -74,7 +75,8 @@ class GLHelperTest : public testing::Test {
nullptr, /* share_context */
attributes, gpu::SharedMemoryLimits(),
nullptr, /* gpu_memory_buffer_manager */
- nullptr /* image_factory */));
+ nullptr, /* image_factory */
+ base::ThreadTaskRunnerHandle::Get()));
gl_ = context_->GetImplementation();
gpu::ContextSupport* support = context_->GetImplementation();
@@ -258,10 +260,8 @@ class GLHelperTest : public testing::Test {
}
// Check the output size matches the destination of the last stage
- EXPECT_EQ(scaler_stages[scaler_stages.size() - 1].dst_size.width(),
- dst_size.width());
- EXPECT_EQ(scaler_stages[scaler_stages.size() - 1].dst_size.height(),
- dst_size.height());
+ EXPECT_EQ(scaler_stages.back().dst_size.width(), dst_size.width());
+ EXPECT_EQ(scaler_stages.back().dst_size.height(), dst_size.height());
// Used to verify that up-scales are not attempted after some
// other scale.
diff --git a/chromium/components/display_compositor/yuv_readback_unittest.cc b/chromium/components/display_compositor/yuv_readback_unittest.cc
index 91f1d2fbdad..5f98f96bd19 100644
--- a/chromium/components/display_compositor/yuv_readback_unittest.cc
+++ b/chromium/components/display_compositor/yuv_readback_unittest.cc
@@ -8,6 +8,8 @@
#include "base/strings/stringprintf.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
#include "components/display_compositor/gl_helper.h"
#include "gpu/command_buffer/client/gl_in_process_context.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
@@ -46,7 +48,8 @@ class YUVReadbackTest : public testing::Test {
nullptr, /* share_context */
attributes, gpu::SharedMemoryLimits(),
nullptr, /* gpu_memory_buffer_manager */
- nullptr /* image_factory */));
+ nullptr, /* image_factory */
+ base::ThreadTaskRunnerHandle::Get()));
gl_ = context_->GetImplementation();
gpu::ContextSupport* support = context_->GetImplementation();
diff --git a/chromium/components/dom_distiller.gypi b/chromium/components/dom_distiller.gypi
deleted file mode 100644
index decd4220ab7..00000000000
--- a/chromium/components/dom_distiller.gypi
+++ /dev/null
@@ -1,366 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/dom_distiller/core
- 'target_name': 'dom_distiller_core',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../skia/skia.gyp:skia',
- '../sync/sync.gyp:sync',
- '../third_party/dom_distiller_js/dom_distiller_js.gyp:dom_distiller_js_proto',
- '../third_party/re2/re2.gyp:re2',
- 'components.gyp:leveldb_proto',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- 'dom_distiller_protos',
- 'prefs/prefs.gyp:prefs',
- 'pref_registry',
- 'variations',
- ],
- 'include_dirs': [
- '..',
- ],
- 'export_dependent_settings': [
- 'dom_distiller_protos',
- '../third_party/dom_distiller_js/dom_distiller_js.gyp:dom_distiller_js_proto',
- ],
- 'sources': [
- 'dom_distiller/android/component_jni_registrar.cc',
- 'dom_distiller/android/component_jni_registrar.h',
- 'dom_distiller/core/article_attachments_data.cc',
- 'dom_distiller/core/article_attachments_data.h',
- 'dom_distiller/core/article_distillation_update.cc',
- 'dom_distiller/core/article_distillation_update.h',
- 'dom_distiller/core/article_entry.cc',
- 'dom_distiller/core/article_entry.h',
- 'dom_distiller/core/distillable_page_detector.cc',
- 'dom_distiller/core/distillable_page_detector.h',
- 'dom_distiller/core/distilled_content_store.cc',
- 'dom_distiller/core/distilled_content_store.h',
- 'dom_distiller/core/distilled_page_prefs.cc',
- 'dom_distiller/core/distilled_page_prefs.h',
- 'dom_distiller/core/distilled_page_prefs_android.cc',
- 'dom_distiller/core/distilled_page_prefs_android.h',
- 'dom_distiller/core/distiller.cc',
- 'dom_distiller/core/distiller.h',
- 'dom_distiller/core/distiller_page.cc',
- 'dom_distiller/core/distiller_page.h',
- 'dom_distiller/core/distiller_url_fetcher.cc',
- 'dom_distiller/core/distiller_url_fetcher.h',
- 'dom_distiller/core/dom_distiller_constants.cc',
- 'dom_distiller/core/dom_distiller_constants.h',
- 'dom_distiller/core/dom_distiller_features.cc',
- 'dom_distiller/core/dom_distiller_features.h',
- 'dom_distiller/core/dom_distiller_model.cc',
- 'dom_distiller/core/dom_distiller_model.h',
- 'dom_distiller/core/dom_distiller_observer.h',
- 'dom_distiller/core/dom_distiller_request_view_base.cc',
- 'dom_distiller/core/dom_distiller_request_view_base.h',
- 'dom_distiller/core/dom_distiller_service.cc',
- 'dom_distiller/core/dom_distiller_service.h',
- 'dom_distiller/core/dom_distiller_service_android.cc',
- 'dom_distiller/core/dom_distiller_service_android.h',
- 'dom_distiller/core/dom_distiller_store.cc',
- 'dom_distiller/core/dom_distiller_store.h',
- 'dom_distiller/core/dom_distiller_switches.cc',
- 'dom_distiller/core/dom_distiller_switches.h',
- 'dom_distiller/core/experiments.cc',
- 'dom_distiller/core/experiments.h',
- 'dom_distiller/core/feedback_reporter.cc',
- 'dom_distiller/core/feedback_reporter.h',
- 'dom_distiller/core/font_family_list.h',
- 'dom_distiller/core/page_features.cc',
- 'dom_distiller/core/page_features.h',
- 'dom_distiller/core/task_tracker.cc',
- 'dom_distiller/core/task_tracker.h',
- 'dom_distiller/core/theme_list.h',
- 'dom_distiller/core/url_constants.cc',
- 'dom_distiller/core/url_constants.h',
- 'dom_distiller/core/url_utils.cc',
- 'dom_distiller/core/url_utils.h',
- 'dom_distiller/core/url_utils_android.cc',
- 'dom_distiller/core/url_utils_android.h',
- 'dom_distiller/core/viewer.cc',
- 'dom_distiller/core/viewer.h',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'dependencies': [
- 'dom_distiller_core_jni_headers',
- ],
- }],
- ],
- },
- {
- # GN version: components/dom_distiller/core:test_support
- 'target_name': 'dom_distiller_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'dom_distiller_core',
- 'components.gyp:leveldb_proto_test_support',
- '../sync/sync.gyp:sync',
- '../testing/gmock.gyp:gmock',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'dom_distiller/core/dom_distiller_test_util.cc',
- 'dom_distiller/core/dom_distiller_test_util.h',
- 'dom_distiller/core/fake_distiller.cc',
- 'dom_distiller/core/fake_distiller.h',
- 'dom_distiller/core/fake_distiller_page.cc',
- 'dom_distiller/core/fake_distiller_page.h',
- 'dom_distiller/core/test_request_view_handle.h',
- ],
- },
- {
- # GN version: //components/dom_distiller/core/proto
- 'target_name': 'dom_distiller_protos',
- 'type': 'static_library',
- 'sources': [
- 'dom_distiller/core/proto/adaboost.proto',
- 'dom_distiller/core/proto/distilled_article.proto',
- 'dom_distiller/core/proto/distilled_page.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'dom_distiller/core/proto',
- 'proto_out_dir': 'components/dom_distiller/core/proto',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
- {
- # GN version: //components/dom_distiller/content:mojo_bindings
- 'target_name': 'dom_distiller_mojo_bindings',
- 'type': 'static_library',
- 'sources': [
- 'dom_distiller/content/common/distillability_service.mojom',
- 'dom_distiller/content/common/distiller_javascript_service.mojom',
- 'dom_distiller/content/common/distiller_page_notifier_service.mojom',
- ],
- 'includes': [
- '../mojo/mojom_bindings_generator.gypi',
- ],
- },
- ],
- 'conditions': [
- ['OS != "ios"', {
- 'targets': [
- {
- # GN version: //components/dom_distiller/content/browser
- 'target_name': 'dom_distiller_content_browser',
- 'type': 'static_library',
- 'dependencies': [
- 'dom_distiller_core',
- 'dom_distiller_mojo_bindings',
- 'dom_distiller_protos',
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../sync/sync.gyp:sync',
- '../ui/display/display.gyp:display',
- '../ui/gfx/gfx.gyp:gfx',
- '../url/url.gyp:url_lib',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'dom_distiller/content/browser/distillability_driver.cc',
- 'dom_distiller/content/browser/distillability_driver.h',
- 'dom_distiller/content/browser/distillable_page_utils.cc',
- 'dom_distiller/content/browser/distillable_page_utils.h',
- 'dom_distiller/content/browser/distillable_page_utils_android.cc',
- 'dom_distiller/content/browser/distillable_page_utils_android.h',
- 'dom_distiller/content/browser/distiller_javascript_service_impl.cc',
- 'dom_distiller/content/browser/distiller_javascript_service_impl.h',
- 'dom_distiller/content/browser/distiller_javascript_utils.cc',
- 'dom_distiller/content/browser/distiller_javascript_utils.h',
- 'dom_distiller/content/browser/distiller_page_web_contents.cc',
- 'dom_distiller/content/browser/distiller_page_web_contents.h',
- 'dom_distiller/content/browser/distiller_ui_handle.h',
- 'dom_distiller/content/browser/dom_distiller_viewer_source.cc',
- 'dom_distiller/content/browser/dom_distiller_viewer_source.h',
- 'dom_distiller/content/browser/web_contents_main_frame_observer.cc',
- 'dom_distiller/content/browser/web_contents_main_frame_observer.h',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'dependencies': [
- 'dom_distiller_content_jni_headers',
- 'dom_distiller_core_jni_headers',
- ],
- }],
- ],
- },
- {
- # GN version: //components/dom_distiller/content/renderer
- 'target_name': 'dom_distiller_content_renderer',
- 'type': 'static_library',
- 'dependencies': [
- 'dom_distiller_mojo_bindings',
- 'dom_distiller_protos',
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../gin/gin.gyp:gin',
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
- ],
- 'include_dirs': [
- '..',
- ],
- 'export_dependent_settings': [
- 'dom_distiller_protos',
- ],
- 'sources': [
- 'dom_distiller/content/renderer/distillability_agent.cc',
- 'dom_distiller/content/renderer/distillability_agent.h',
- 'dom_distiller/content/renderer/distiller_js_render_frame_observer.cc',
- 'dom_distiller/content/renderer/distiller_js_render_frame_observer.h',
- 'dom_distiller/content/renderer/distiller_native_javascript.cc',
- 'dom_distiller/content/renderer/distiller_native_javascript.h',
- 'dom_distiller/content/renderer/distiller_page_notifier_service_impl.cc',
- 'dom_distiller/content/renderer/distiller_page_notifier_service_impl.h',
- ],
- },
- {
- # GN version: //components/dom_distiller/webui
- 'target_name': 'dom_distiller_webui',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../sync/sync.gyp:sync',
- '../url/url.gyp:url_lib',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- 'dom_distiller_core',
- 'dom_distiller_protos',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'dom_distiller/webui/dom_distiller_handler.cc',
- 'dom_distiller/webui/dom_distiller_handler.h',
- 'dom_distiller/webui/dom_distiller_ui.cc',
- 'dom_distiller/webui/dom_distiller_ui.h',
- ],
- },
- ],
- }],
- ['OS=="ios"', {
- 'targets': [
- {
- # GN version: //components/dom_distiller/ios
- 'target_name': 'dom_distiller_ios',
- 'type': 'static_library',
- 'dependencies': [
- '../ios/provider/ios_provider_web.gyp:ios_provider_web',
- 'dom_distiller_protos',
- 'dom_distiller_core',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'dom_distiller/ios/distiller_page_factory_ios.h',
- 'dom_distiller/ios/distiller_page_factory_ios.mm',
- 'dom_distiller/ios/distiller_page_ios.h',
- 'dom_distiller/ios/distiller_page_ios.mm',
- ],
- },
- ],
- }],
- ['OS=="android"', {
- 'targets': [
- {
- # TODO(cjhopman): remove this when it is rolled downstream.
- 'target_name': 'dom_distiller_core_java',
- 'type': 'none',
- 'dependencies': [
- 'dom_distiller_java',
- ],
- },
- {
- # GN: //components/dom_distiller/android:dom_distiller_java
- 'target_name': 'dom_distiller_java',
- 'type': 'none',
- 'dependencies': [
- 'dom_distiller_core_font_family_java',
- 'dom_distiller_core_theme_java',
- '../base/base.gyp:base',
- '../content/content.gyp:content_java',
- ],
- 'variables': {
- 'java_in_dir': 'dom_distiller/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN: //components/dom_distiller/android:dom_distiller_core_font_family_javagen
- 'target_name': 'dom_distiller_core_font_family_java',
- 'type': 'none',
- 'sources': [
- 'dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/FontFamily.template',
- ],
- 'variables': {
- 'package_name': 'org/chromium/components/dom_distiller/core',
- 'template_deps': ['dom_distiller/core/font_family_list.h'],
- },
- 'includes': [ '../build/android/java_cpp_template.gypi' ],
- },
- {
- # GN: //components/dom_distiller/android:dom_distiller_content_java
- 'target_name': 'dom_distiller_content_jni_headers',
- 'type': 'none',
- 'sources': [
- 'dom_distiller/android/java/src/org/chromium/components/dom_distiller/content/DistillablePageUtils.java',
- ],
- 'variables': {
- 'jni_gen_package': 'dom_distiller_content',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- # GN: //components/dom_distiller/android:jni_headers
- 'target_name': 'dom_distiller_core_jni_headers',
- 'type': 'none',
- 'sources': [
- 'dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/DistilledPagePrefs.java',
- 'dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/DomDistillerService.java',
- 'dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/DomDistillerUrlUtils.java',
- ],
- 'variables': {
- 'jni_gen_package': 'dom_distiller_core',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- # GN: //components/dom_distiller/android:dom_distiller_core_theme_javagen
- 'target_name': 'dom_distiller_core_theme_java',
- 'type': 'none',
- 'sources': [
- 'dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/Theme.template',
- ],
- 'variables': {
- 'package_name': 'org/chromium/components/dom_distiller/core',
- 'template_deps': ['dom_distiller/core/theme_list.h'],
- },
- 'includes': [ '../build/android/java_cpp_template.gypi' ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/dom_distiller/DEPS b/chromium/components/dom_distiller/DEPS
index 15150b587b2..8adca12084b 100644
--- a/chromium/components/dom_distiller/DEPS
+++ b/chromium/components/dom_distiller/DEPS
@@ -2,13 +2,13 @@ include_rules = [
"+components/leveldb_proto",
"+components/pref_registry",
"+components/prefs",
+ "+components/sync/api",
+ "+components/sync/core/attachments", # Needed for tests.
+ "+components/sync/protocol",
"+components/variations",
"+google", # For third_party/protobuf.
"+grit", # For generated headers.
"+jni",
- "+sync/api",
- "+sync/internal_api/public/attachments", # Needed for tests.
- "+sync/protocol",
"+third_party/dom_distiller_js",
"+third_party/re2",
"+net/base",
diff --git a/chromium/components/dom_distiller/android/BUILD.gn b/chromium/components/dom_distiller/android/BUILD.gn
deleted file mode 100644
index 1b5c31caa91..00000000000
--- a/chromium/components/dom_distiller/android/BUILD.gn
+++ /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.
-
-import("//build/config/android/rules.gni")
-
-android_library("dom_distiller_core_java") {
- deps = [
- "//base:base_java",
- ]
- java_files = [
- "java/src/org/chromium/components/dom_distiller/core/DomDistillerService.java",
- "java/src/org/chromium/components/dom_distiller/core/DomDistillerUrlUtils.java",
- "java/src/org/chromium/components/dom_distiller/core/DistilledPagePrefs.java",
- ]
-
- srcjar_deps = [
- ":dom_distiller_core_font_family_javagen",
- ":dom_distiller_core_theme_javagen",
- ]
-}
-
-# GYP: //components/dom_distiller.gypi:dom_distiller_java
-android_library("dom_distiller_content_java") {
- deps = [
- ":dom_distiller_core_java",
- "//base:base_java",
- "//content/public/android:content_java",
- ]
- java_files = [ "java/src/org/chromium/components/dom_distiller/content/DistillablePageUtils.java" ]
-}
-
-# GYP: //components/dom_distiller.gypi:dom_distiller_core_font_family_java
-java_cpp_template("dom_distiller_core_font_family_javagen") {
- package_name = "org/chromium/components/dom_distiller/core"
- sources = [
- "java/src/org/chromium/components/dom_distiller/core/FontFamily.template",
- ]
- inputs = [
- "../core/font_family_list.h",
- ]
-}
-
-# GYP: //components/dom_distiller.gypi:dom_distiller_core_font_family_java
-java_cpp_template("dom_distiller_core_theme_javagen") {
- package_name = "org/chromium/components/dom_distiller/core"
- sources = [
- "java/src/org/chromium/components/dom_distiller/core/Theme.template",
- ]
- inputs = [
- "../core/theme_list.h",
- ]
-}
-
-generate_jni("jni_headers") {
- sources = [
- "java/src/org/chromium/components/dom_distiller/content/DistillablePageUtils.java",
- ]
- jni_package = "dom_distiller_content"
-}
diff --git a/chromium/components/dom_distiller/content/browser/BUILD.gn b/chromium/components/dom_distiller/content/browser/BUILD.gn
index 59dc377473f..b1dbd395af3 100644
--- a/chromium/components/dom_distiller/content/browser/BUILD.gn
+++ b/chromium/components/dom_distiller/content/browser/BUILD.gn
@@ -4,7 +4,6 @@
assert(!is_ios)
-# GYP version: components/dom_distiller.gypi:dom_distiller_content_browser
static_library("browser") {
sources = [
"distillability_driver.cc",
@@ -33,13 +32,13 @@ static_library("browser") {
"//components/dom_distiller/content/common:mojo_bindings",
"//components/resources",
"//components/strings",
+ "//components/sync",
"//content/public/browser",
"//content/public/common",
"//mojo/public/cpp/bindings",
"//net",
"//services/shell/public/cpp",
"//skia",
- "//sync",
"//third_party/WebKit/public:blink_headers",
"//ui/base",
"//ui/display",
@@ -49,12 +48,12 @@ static_library("browser") {
if (is_android) {
sources += [
- "//components/dom_distiller/android/component_jni_registrar.cc",
- "//components/dom_distiller/android/component_jni_registrar.h",
+ "android/content_jni_registrar.cc",
+ "android/content_jni_registrar.h",
"distillable_page_utils_android.cc",
"distillable_page_utils_android.h",
]
- deps += [ "//components/dom_distiller/android:jni_headers" ]
+ deps += [ "android:jni_headers" ]
}
}
diff --git a/chromium/components/dom_distiller/content/browser/android/BUILD.gn b/chromium/components/dom_distiller/content/browser/android/BUILD.gn
new file mode 100644
index 00000000000..fb8d612ff37
--- /dev/null
+++ b/chromium/components/dom_distiller/content/browser/android/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+android_library("dom_distiller_content_java") {
+ deps = [
+ "//base:base_java",
+ "//components/dom_distiller/core/android:dom_distiller_core_java",
+ "//content/public/android:content_java",
+ ]
+ java_files = [ "java/src/org/chromium/components/dom_distiller/content/DistillablePageUtils.java" ]
+}
+
+generate_jni("jni_headers") {
+ sources = [
+ "java/src/org/chromium/components/dom_distiller/content/DistillablePageUtils.java",
+ ]
+ jni_package = "dom_distiller_content"
+}
diff --git a/chromium/components/dom_distiller/android/DEPS b/chromium/components/dom_distiller/content/browser/android/DEPS
index 54004a2f77a..54004a2f77a 100644
--- a/chromium/components/dom_distiller/android/DEPS
+++ b/chromium/components/dom_distiller/content/browser/android/DEPS
diff --git a/chromium/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/content/DEPS b/chromium/components/dom_distiller/content/browser/android/java/src/org/chromium/components/dom_distiller/content/DEPS
index 0d019e19974..0d019e19974 100644
--- a/chromium/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/content/DEPS
+++ b/chromium/components/dom_distiller/content/browser/android/java/src/org/chromium/components/dom_distiller/content/DEPS
diff --git a/chromium/components/dom_distiller/content/browser/distillability_driver.cc b/chromium/components/dom_distiller/content/browser/distillability_driver.cc
index f2275b34a9b..d87d36d0b65 100644
--- a/chromium/components/dom_distiller/content/browser/distillability_driver.cc
+++ b/chromium/components/dom_distiller/content/browser/distillability_driver.cc
@@ -8,6 +8,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/shell/public/cpp/interface_registry.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(
@@ -19,11 +20,9 @@ namespace dom_distiller {
// renderer to notify the browser that a page is distillable.
class DistillabilityServiceImpl : public mojom::DistillabilityService {
public:
- DistillabilityServiceImpl(
- mojo::InterfaceRequest<mojom::DistillabilityService> request,
+ explicit DistillabilityServiceImpl(
base::WeakPtr<DistillabilityDriver> distillability_driver)
- : binding_(this, std::move(request)),
- distillability_driver_(distillability_driver) {}
+ : distillability_driver_(distillability_driver) {}
~DistillabilityServiceImpl() override {
if (!distillability_driver_) return;
@@ -36,7 +35,6 @@ class DistillabilityServiceImpl : public mojom::DistillabilityService {
}
private:
- mojo::StrongBinding<mojom::DistillabilityService> binding_;
base::WeakPtr<DistillabilityDriver> distillability_driver_;
};
@@ -55,7 +53,9 @@ DistillabilityDriver::~DistillabilityDriver() {
void DistillabilityDriver::CreateDistillabilityService(
mojo::InterfaceRequest<mojom::DistillabilityService> request) {
- new DistillabilityServiceImpl(std::move(request), weak_factory_.GetWeakPtr());
+ mojo::MakeStrongBinding(
+ base::MakeUnique<DistillabilityServiceImpl>(weak_factory_.GetWeakPtr()),
+ std::move(request));
}
void DistillabilityDriver::SetDelegate(
diff --git a/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.cc b/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.cc
index 8ba1281b88c..f0890f68c60 100644
--- a/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.cc
+++ b/chromium/components/dom_distiller/content/browser/distillable_page_utils_android.cc
@@ -14,6 +14,7 @@
#include "content/public/browser/web_contents.h"
#include "jni/DistillablePageUtils_jni.h"
+using base::android::JavaParamRef;
using base::android::ScopedJavaGlobalRef;
namespace dom_distiller {
diff --git a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc
index ea825c0014f..087c94f5667 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc
+++ b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.cc
@@ -10,22 +10,18 @@
#include "components/dom_distiller/core/feedback_reporter.h"
#include "content/public/browser/user_metrics.h"
#include "mojo/public/cpp/bindings/string.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
namespace dom_distiller {
DistillerJavaScriptServiceImpl::DistillerJavaScriptServiceImpl(
content::RenderFrameHost* render_frame_host,
- DistillerUIHandle* distiller_ui_handle,
- mojo::InterfaceRequest<mojom::DistillerJavaScriptService> request)
- : binding_(this, std::move(request)),
- render_frame_host_(render_frame_host),
+ DistillerUIHandle* distiller_ui_handle)
+ : render_frame_host_(render_frame_host),
distiller_ui_handle_(distiller_ui_handle) {}
DistillerJavaScriptServiceImpl::~DistillerJavaScriptServiceImpl() {}
-void DistillerJavaScriptServiceImpl::HandleDistillerEchoCall(
- const mojo::String& message) {}
-
void DistillerJavaScriptServiceImpl::HandleDistillerFeedbackCall(
bool good) {
FeedbackReporter::ReportQuality(good);
@@ -66,9 +62,9 @@ void CreateDistillerJavaScriptService(
content::RenderFrameHost* render_frame_host,
DistillerUIHandle* distiller_ui_handle,
mojo::InterfaceRequest<mojom::DistillerJavaScriptService> request) {
- // This is strongly bound and owned by the pipe.
- new DistillerJavaScriptServiceImpl(render_frame_host, distiller_ui_handle,
- std::move(request));
+ mojo::MakeStrongBinding(base::MakeUnique<DistillerJavaScriptServiceImpl>(
+ render_frame_host, distiller_ui_handle),
+ std::move(request));
}
} // namespace dom_distiller
diff --git a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h
index cc1659c8e9b..306887e0d35 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h
+++ b/chromium/components/dom_distiller/content/browser/distiller_javascript_service_impl.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLER_JAVASCRIPT_SERVICE_IMPL_H_
#define COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLER_JAVASCRIPT_SERVICE_IMPL_H_
+#include "base/macros.h"
#include "components/dom_distiller/content/browser/distiller_ui_handle.h"
#include "components/dom_distiller/content/common/distiller_javascript_service.mojom.h"
#include "mojo/public/cpp/bindings/string.h"
@@ -16,18 +17,12 @@ namespace dom_distiller {
class DistillerJavaScriptServiceImpl
: public mojom::DistillerJavaScriptService {
public:
- DistillerJavaScriptServiceImpl(
- content::RenderFrameHost* render_frame_host,
- DistillerUIHandle* distiller_ui_handle,
- mojo::InterfaceRequest<mojom::DistillerJavaScriptService> request);
+ DistillerJavaScriptServiceImpl(content::RenderFrameHost* render_frame_host,
+ DistillerUIHandle* distiller_ui_handle);
~DistillerJavaScriptServiceImpl() override;
// Mojo mojom::DistillerJavaScriptService implementation.
- // Echo implementation, this call does not actually return as it would be
- // blocking.
- void HandleDistillerEchoCall(const mojo::String& message) override;
-
// Send UMA feedback and start the external feedback reporter if one exists.
void HandleDistillerFeedbackCall(bool good) override;
@@ -38,9 +33,10 @@ class DistillerJavaScriptServiceImpl
void HandleDistillerOpenSettingsCall() override;
private:
- mojo::StrongBinding<mojom::DistillerJavaScriptService> binding_;
content::RenderFrameHost* render_frame_host_;
DistillerUIHandle* distiller_ui_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(DistillerJavaScriptServiceImpl);
};
// static
diff --git a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
index 27c13cdb169..f062063541a 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
+++ b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/callback.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "components/dom_distiller/content/browser/distiller_javascript_utils.h"
#include "components/dom_distiller/content/browser/web_contents_main_frame_observer.h"
diff --git a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
index a9598dfa702..f79702cd409 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
+++ b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
@@ -102,7 +102,7 @@ class DistillerPageWebContentsTest : public ContentBrowserTest {
embedded_test_server()->GetURL(url),
dom_distiller::proto::DomDistillerOptions(),
base::Bind(&DistillerPageWebContentsTest::OnPageDistillationFinished,
- this, quit_closure));
+ base::Unretained(this), quit_closure));
}
void OnPageDistillationFinished(
@@ -315,7 +315,7 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
}
IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
- UsingCurrentWebContentsNotFinishedLoadingYet) {
+ DISABLED_UsingCurrentWebContentsNotFinishedLoadingYet) {
std::string url(kSimpleArticlePath);
bool expect_new_web_contents = false;
bool setup_main_frame_observer = true;
@@ -327,7 +327,7 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
}
IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
- UsingCurrentWebContentsReadyForDistillation) {
+ DISABLED_UsingCurrentWebContentsReadyForDistillation) {
std::string url(kSimpleArticlePath);
bool expect_new_web_contents = false;
bool setup_main_frame_observer = true;
diff --git a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
index 8ae7f8ca262..e28e11d50ea 100644
--- a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
+++ b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
@@ -32,6 +32,7 @@
#include "components/dom_distiller/core/viewer.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
@@ -56,13 +57,13 @@ class DomDistillerViewerSource::RequestViewerHandle
RequestViewerHandle(content::WebContents* web_contents,
const std::string& expected_scheme,
const std::string& expected_request_path,
- DistilledPagePrefs* distilled_page_prefs);
+ DistilledPagePrefs* distilled_page_prefs,
+ DistillerUIHandle* ui_handle);
~RequestViewerHandle() override;
// content::WebContentsObserver implementation:
- void DidNavigateMainFrame(
- const content::LoadCommittedDetails& details,
- const content::FrameNavigateParams& params) override;
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
void RenderProcessGone(base::TerminationStatus status) override;
void WebContentsDestroyed() override;
void DidFinishLoad(content::RenderFrameHost* render_frame_host,
@@ -91,17 +92,24 @@ class DomDistillerViewerSource::RequestViewerHandle
// Temporary store of pending JavaScript if the page isn't ready to receive
// data from distillation.
std::string buffer_;
+
+ // An object for accessing chrome-specific UI controls including external
+ // feedback and opening the distiller settings. Guaranteed to outlive this
+ // object.
+ DistillerUIHandle* distiller_ui_handle_;
};
DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle(
content::WebContents* web_contents,
const std::string& expected_scheme,
const std::string& expected_request_path,
- DistilledPagePrefs* distilled_page_prefs)
+ DistilledPagePrefs* distilled_page_prefs,
+ DistillerUIHandle* ui_handle)
: DomDistillerRequestViewBase(distilled_page_prefs),
expected_scheme_(expected_scheme),
expected_request_path_(expected_request_path),
- waiting_for_page_ready_(true) {
+ waiting_for_page_ready_(true),
+ distiller_ui_handle_(ui_handle) {
content::WebContentsObserver::Observe(web_contents);
distilled_page_prefs_->AddObserver(this);
}
@@ -122,13 +130,38 @@ void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript(
}
}
-void DomDistillerViewerSource::RequestViewerHandle::DidNavigateMainFrame(
- const content::LoadCommittedDetails& details,
- const content::FrameNavigateParams& params) {
- const GURL& navigation = details.entry->GetURL();
- if (details.is_in_page || (navigation.SchemeIs(expected_scheme_.c_str()) &&
- expected_request_path_ == navigation.query())) {
+void DomDistillerViewerSource::RequestViewerHandle::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted())
+ return;
+
+ const GURL& navigation = navigation_handle->GetURL();
+ bool expected_main_view_request =
+ navigation.SchemeIs(expected_scheme_.c_str()) &&
+ expected_request_path_ == navigation.query();
+ if (navigation_handle->IsSamePage() || expected_main_view_request) {
// In-page navigations, as well as the main view request can be ignored.
+ if (expected_main_view_request) {
+ content::RenderFrameHost* render_frame_host =
+ navigation_handle->GetRenderFrameHost();
+ content::RenderViewHost* render_view_host =
+ render_frame_host->GetRenderViewHost();
+ CHECK_EQ(0, render_view_host->GetEnabledBindings());
+
+ // Add mojo service for JavaScript functionality. This is the receiving
+ // end of this particular service.
+ render_frame_host->GetInterfaceRegistry()->AddInterface(
+ base::Bind(&CreateDistillerJavaScriptService,
+ render_frame_host,
+ distiller_ui_handle_));
+
+ // Tell the renderer that this is currently a distilled page.
+ mojom::DistillerPageNotifierServicePtr page_notifier_service;
+ render_frame_host->GetRemoteInterfaces()->GetInterface(
+ &page_notifier_service);
+ DCHECK(page_notifier_service);
+ page_notifier_service->NotifyIsDistillerPage();
+ }
return;
}
@@ -195,18 +228,11 @@ std::string DomDistillerViewerSource::GetSource() const {
void DomDistillerViewerSource::StartDataRequest(
const std::string& path,
- int render_process_id,
- int render_frame_id,
+ const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
const content::URLDataSource::GotDataCallback& callback) {
- content::RenderFrameHost* render_frame_host =
- content::RenderFrameHost::FromID(render_process_id, render_frame_id);
- if (!render_frame_host)
+ content::WebContents* web_contents = wc_getter.Run();
+ if (!web_contents)
return;
- content::RenderViewHost* render_view_host =
- render_frame_host->GetRenderViewHost();
- DCHECK(render_view_host);
- CHECK_EQ(0, render_view_host->GetEnabledBindings());
-
if (kViewerCssPath == path) {
std::string css = viewer::GetCss();
callback.Run(base::RefCountedString::TakeString(&css));
@@ -223,16 +249,15 @@ void DomDistillerViewerSource::StartDataRequest(
dom_distiller_service_->GetDistilledPagePrefs()->SetFontScaling(scale);
}
}
- content::WebContents* web_contents =
- content::WebContents::FromRenderFrameHost(render_frame_host);
- DCHECK(web_contents);
+
// An empty |path| is invalid, but guard against it. If not empty, assume
// |path| starts with '?', which is stripped away.
const std::string path_after_query_separator =
path.size() > 0 ? path.substr(1) : "";
RequestViewerHandle* request_viewer_handle =
new RequestViewerHandle(web_contents, scheme_, path_after_query_separator,
- dom_distiller_service_->GetDistilledPagePrefs());
+ dom_distiller_service_->GetDistilledPagePrefs(),
+ distiller_ui_handle_.get());
std::unique_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest(
dom_distiller_service_, path, request_viewer_handle,
web_contents->GetContainerBounds().size());
@@ -243,20 +268,6 @@ void DomDistillerViewerSource::StartDataRequest(
dom_distiller_service_->GetDistilledPagePrefs()->GetTheme(),
dom_distiller_service_->GetDistilledPagePrefs()->GetFontFamily());
- // Add mojo service for JavaScript functionality. This is the receiving end
- // of this particular service.
- render_frame_host->GetInterfaceRegistry()->AddInterface(
- base::Bind(&CreateDistillerJavaScriptService,
- render_frame_host,
- distiller_ui_handle_.get()));
-
- // Tell the renderer that this is currently a distilled page.
- mojom::DistillerPageNotifierServicePtr page_notifier_service;
- render_frame_host->GetRemoteInterfaces()->GetInterface(
- &page_notifier_service);
- DCHECK(page_notifier_service);
- page_notifier_service->NotifyIsDistillerPage();
-
if (viewer_handle) {
// The service returned a |ViewerHandle| and guarantees it will call
// the |RequestViewerHandle|, so passing ownership to it, to ensure the
diff --git a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.h b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.h
index 782f26cd1db..1749e8c19ad 100644
--- a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.h
+++ b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.h
@@ -34,8 +34,7 @@ class DomDistillerViewerSource : public content::URLDataSource {
std::string GetSource() const override;
void StartDataRequest(
const std::string& path,
- int render_process_id,
- int render_frame_id,
+ const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
const content::URLDataSource::GotDataCallback& callback) override;
std::string GetMimeType(const std::string& path) const override;
bool ShouldServiceRequest(const net::URLRequest* request) const override;
diff --git a/chromium/components/dom_distiller/content/common/BUILD.gn b/chromium/components/dom_distiller/content/common/BUILD.gn
index 57cbc89375a..88ebc8a6a01 100644
--- a/chromium/components/dom_distiller/content/common/BUILD.gn
+++ b/chromium/components/dom_distiller/content/common/BUILD.gn
@@ -4,11 +4,12 @@
import("//mojo/public/tools/bindings/mojom.gni")
-# GYP version: components/dom_distiller.gypi:dom_distiller_mojo_bindings
mojom("mojo_bindings") {
sources = [
"distillability_service.mojom",
"distiller_javascript_service.mojom",
"distiller_page_notifier_service.mojom",
]
+
+ use_new_wrapper_types = false
}
diff --git a/chromium/components/dom_distiller/content/common/distiller_javascript_service.mojom b/chromium/components/dom_distiller/content/common/distiller_javascript_service.mojom
index 5e2dfa9e366..d16d5d1c858 100644
--- a/chromium/components/dom_distiller/content/common/distiller_javascript_service.mojom
+++ b/chromium/components/dom_distiller/content/common/distiller_javascript_service.mojom
@@ -7,10 +7,6 @@ module dom_distiller.mojom;
// This service is implemented by the browser process and is used by the
// renderer when a distiller JavaScript function is called.
interface DistillerJavaScriptService {
-
- // Handle the "distiller.echo" function.
- HandleDistillerEchoCall(string message);
-
// Handle the "distiller.sendFeedback" function.
HandleDistillerFeedbackCall(bool good);
diff --git a/chromium/components/dom_distiller/content/renderer/BUILD.gn b/chromium/components/dom_distiller/content/renderer/BUILD.gn
index 27485d4e1d8..f774265714e 100644
--- a/chromium/components/dom_distiller/content/renderer/BUILD.gn
+++ b/chromium/components/dom_distiller/content/renderer/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/dom_distiller.gypi:dom_distiller_content_renderer
static_library("renderer") {
sources = [
"distillability_agent.cc",
diff --git a/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc b/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc
index ac24a1f9d07..0ba5d2718cc 100644
--- a/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc
+++ b/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.cc
@@ -10,6 +10,7 @@
#include "components/dom_distiller/content/common/distiller_page_notifier_service.mojom.h"
#include "components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.h"
#include "content/public/renderer/render_frame.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/shell/public/cpp/interface_registry.h"
#include "v8/include/v8.h"
@@ -59,8 +60,9 @@ void DistillerJsRenderFrameObserver::RegisterMojoInterface() {
void DistillerJsRenderFrameObserver::CreateDistillerPageNotifierService(
mojo::InterfaceRequest<mojom::DistillerPageNotifierService> request) {
- // This is strongly bound to and owned by the pipe.
- new DistillerPageNotifierServiceImpl(this, std::move(request));
+ mojo::MakeStrongBinding(
+ base::MakeUnique<DistillerPageNotifierServiceImpl>(this),
+ std::move(request));
}
void DistillerJsRenderFrameObserver::SetIsDistillerPage() {
diff --git a/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h b/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h
index e21cb19ca96..a44d358d1a9 100644
--- a/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h
+++ b/chromium/components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h
@@ -51,8 +51,6 @@ class DistillerJsRenderFrameObserver : public content::RenderFrameObserver {
// Track if the current page is distilled. This is needed for testing.
bool is_distiller_page_;
- // mojo::StrongBinding<mojom::DistillerPageNotifierService> binding_;
-
// Handle to "distiller" JavaScript object functionality.
std::unique_ptr<DistillerNativeJavaScript> native_javascript_handle_;
base::WeakPtrFactory<DistillerJsRenderFrameObserver> weak_factory_;
diff --git a/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc b/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc
index be1af3de17a..7bd6002c462 100644
--- a/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc
+++ b/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.cc
@@ -41,14 +41,6 @@ void DistillerNativeJavaScript::AddJavaScriptObjectToFrame(
EnsureServiceConnected();
- // Some of the JavaScript functions require extra work to be done when it is
- // called, so they have wrapper functions maintained in this class.
- BindFunctionToObject(
- distiller_obj,
- "echo",
- base::Bind(
- &DistillerNativeJavaScript::DistillerEcho, base::Unretained(this)));
-
// Many functions can simply call the Mojo interface directly and have no
// wrapper function for binding. Note that calling distiller_js_service.get()
// does not transfer ownership of the interface.
@@ -90,17 +82,6 @@ void DistillerNativeJavaScript::EnsureServiceConnected() {
}
}
-std::string DistillerNativeJavaScript::DistillerEcho(
- const std::string& message) {
- EnsureServiceConnected();
- // TODO(mdjones): It is possible and beneficial to have information
- // returned from the browser process with these calls. The problem
- // is waiting blocks this process.
- distiller_js_service_->HandleDistillerEchoCall(message);
-
- return message;
-}
-
v8::Local<v8::Object> GetOrCreateDistillerObject(v8::Isolate* isolate,
v8::Local<v8::Object> global) {
v8::Local<v8::Object> distiller_obj;
diff --git a/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.h b/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.h
index b8b608314f5..28078f09639 100644
--- a/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.h
+++ b/chromium/components/dom_distiller/content/renderer/distiller_native_javascript.h
@@ -33,10 +33,6 @@ class DistillerNativeJavaScript {
// Make sure the mojo service is connected.
void EnsureServiceConnected();
- // Native code for "distiller.echo" in JavaScript. This simply returns the
- // provided string.
- std::string DistillerEcho(const std::string& message);
-
content::RenderFrame* render_frame_;
mojom::DistillerJavaScriptServicePtr distiller_js_service_;
};
diff --git a/chromium/components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.cc b/chromium/components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.cc
index d7f1983e7c4..9b7934c9857 100644
--- a/chromium/components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.cc
+++ b/chromium/components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.cc
@@ -8,13 +8,13 @@
#include "components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h"
#include "components/dom_distiller/content/renderer/distiller_native_javascript.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
namespace dom_distiller {
DistillerPageNotifierServiceImpl::DistillerPageNotifierServiceImpl(
- DistillerJsRenderFrameObserver* observer,
- mojo::InterfaceRequest<mojom::DistillerPageNotifierService> request)
- : binding_(this, std::move(request)), distiller_js_observer_(observer) {}
+ DistillerJsRenderFrameObserver* observer)
+ : distiller_js_observer_(observer) {}
void DistillerPageNotifierServiceImpl::NotifyIsDistillerPage() {
// TODO(mdjones): Send some form of unique ID so this call knows
diff --git a/chromium/components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.h b/chromium/components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.h
index 3cfc393c98f..0f6b79beae8 100644
--- a/chromium/components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.h
+++ b/chromium/components/dom_distiller/content/renderer/distiller_page_notifier_service_impl.h
@@ -8,7 +8,6 @@
#include "components/dom_distiller/content/common/distiller_page_notifier_service.mojom.h"
#include "components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h"
#include "components/dom_distiller/content/renderer/distiller_native_javascript.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
namespace dom_distiller {
@@ -23,15 +22,13 @@ class DistillerPageNotifierServiceImpl
: public mojom::DistillerPageNotifierService {
public:
explicit DistillerPageNotifierServiceImpl(
- DistillerJsRenderFrameObserver* observer,
- mojo::InterfaceRequest<mojom::DistillerPageNotifierService> request);
+ DistillerJsRenderFrameObserver* observer);
~DistillerPageNotifierServiceImpl() override;
// Implementation of mojo interface DistillerPageNotifierService.
void NotifyIsDistillerPage() override;
private:
- mojo::StrongBinding<mojom::DistillerPageNotifierService> binding_;
DistillerJsRenderFrameObserver* distiller_js_observer_;
};
diff --git a/chromium/components/dom_distiller/core/BUILD.gn b/chromium/components/dom_distiller/core/BUILD.gn
index 8406d9b8d9f..1ba587aa54c 100644
--- a/chromium/components/dom_distiller/core/BUILD.gn
+++ b/chromium/components/dom_distiller/core/BUILD.gn
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/dom_distiller.gypi:dom_distiller_core
-source_set("core") {
+static_library("core") {
sources = [
"article_attachments_data.cc",
"article_attachments_data.h",
@@ -69,10 +68,10 @@ source_set("core") {
"//components/prefs",
"//components/resources",
"//components/strings",
+ "//components/sync",
"//components/variations",
"//net",
"//skia",
- "//sync",
"//third_party/re2",
"//ui/base",
"//url",
@@ -80,6 +79,8 @@ source_set("core") {
if (is_android) {
sources += [
+ "android/core_jni_registrar.cc",
+ "android/core_jni_registrar.h",
"dom_distiller_service_android.cc",
"dom_distiller_service_android.h",
]
@@ -87,8 +88,7 @@ source_set("core") {
}
}
-# GYP version: components/dom_distiller.gypi:dom_distiller_test_support
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"dom_distiller_test_util.cc",
@@ -104,7 +104,7 @@ source_set("test_support") {
":core",
"//base",
"//components/leveldb_proto:test_support",
- "//sync",
+ "//components/sync",
"//testing/gmock",
"//testing/gtest",
"//url",
@@ -152,8 +152,8 @@ source_set("unit_tests") {
"//components/pref_registry:test_support",
"//components/resources",
"//components/strings",
+ "//components/sync",
"//net:test_support",
- "//sync",
"//testing/gmock",
"//testing/gtest",
"//ui/base",
@@ -166,9 +166,9 @@ if (is_android) {
generate_jni("jni_headers") {
sources = [
- "../android/java/src/org/chromium/components/dom_distiller/core/DistilledPagePrefs.java",
- "../android/java/src/org/chromium/components/dom_distiller/core/DomDistillerService.java",
- "../android/java/src/org/chromium/components/dom_distiller/core/DomDistillerUrlUtils.java",
+ "android/java/src/org/chromium/components/dom_distiller/core/DistilledPagePrefs.java",
+ "android/java/src/org/chromium/components/dom_distiller/core/DomDistillerService.java",
+ "android/java/src/org/chromium/components/dom_distiller/core/DomDistillerUrlUtils.java",
]
jni_package = "dom_distiller_core"
}
diff --git a/chromium/components/dom_distiller/core/android/BUILD.gn b/chromium/components/dom_distiller/core/android/BUILD.gn
new file mode 100644
index 00000000000..658408dd87a
--- /dev/null
+++ b/chromium/components/dom_distiller/core/android/BUILD.gn
@@ -0,0 +1,41 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+android_library("dom_distiller_core_java") {
+ deps = [
+ "//base:base_java",
+ ]
+ java_files = [
+ "java/src/org/chromium/components/dom_distiller/core/DomDistillerService.java",
+ "java/src/org/chromium/components/dom_distiller/core/DomDistillerUrlUtils.java",
+ "java/src/org/chromium/components/dom_distiller/core/DistilledPagePrefs.java",
+ ]
+
+ srcjar_deps = [
+ ":dom_distiller_core_font_family_javagen",
+ ":dom_distiller_core_theme_javagen",
+ ]
+}
+
+java_cpp_template("dom_distiller_core_font_family_javagen") {
+ package_name = "org/chromium/components/dom_distiller/core"
+ sources = [
+ "java/src/org/chromium/components/dom_distiller/core/FontFamily.template",
+ ]
+ inputs = [
+ "../font_family_list.h",
+ ]
+}
+
+java_cpp_template("dom_distiller_core_theme_javagen") {
+ package_name = "org/chromium/components/dom_distiller/core"
+ sources = [
+ "java/src/org/chromium/components/dom_distiller/core/Theme.template",
+ ]
+ inputs = [
+ "../theme_list.h",
+ ]
+}
diff --git a/chromium/components/dom_distiller/core/android/DEPS b/chromium/components/dom_distiller/core/android/DEPS
new file mode 100644
index 00000000000..54004a2f77a
--- /dev/null
+++ b/chromium/components/dom_distiller/core/android/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/dom_distiller",
+]
diff --git a/chromium/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/FontFamily.template b/chromium/components/dom_distiller/core/android/java/src/org/chromium/components/dom_distiller/core/FontFamily.template
index bc0ff25411a..bc0ff25411a 100644
--- a/chromium/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/FontFamily.template
+++ b/chromium/components/dom_distiller/core/android/java/src/org/chromium/components/dom_distiller/core/FontFamily.template
diff --git a/chromium/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/Theme.template b/chromium/components/dom_distiller/core/android/java/src/org/chromium/components/dom_distiller/core/Theme.template
index c74c8a3de0d..c74c8a3de0d 100644
--- a/chromium/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/core/Theme.template
+++ b/chromium/components/dom_distiller/core/android/java/src/org/chromium/components/dom_distiller/core/Theme.template
diff --git a/chromium/components/dom_distiller/core/article_attachments_data.h b/chromium/components/dom_distiller/core/article_attachments_data.h
index d5410c29700..e6ef6d60a71 100644
--- a/chromium/components/dom_distiller/core/article_attachments_data.h
+++ b/chromium/components/dom_distiller/core/article_attachments_data.h
@@ -9,8 +9,8 @@
#include <string>
#include "components/dom_distiller/core/proto/distilled_article.pb.h"
-#include "sync/api/attachments/attachment.h"
-#include "sync/protocol/article_specifics.pb.h"
+#include "components/sync/api/attachments/attachment.h"
+#include "components/sync/protocol/article_specifics.pb.h"
namespace dom_distiller {
diff --git a/chromium/components/dom_distiller/core/article_entry.cc b/chromium/components/dom_distiller/core/article_entry.cc
index 9ed9d7e4f09..bf33f34aaa8 100644
--- a/chromium/components/dom_distiller/core/article_entry.cc
+++ b/chromium/components/dom_distiller/core/article_entry.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "components/dom_distiller/core/article_attachments_data.h"
-#include "sync/api/sync_change.h"
+#include "components/sync/api/sync_change.h"
using sync_pb::EntitySpecifics;
using sync_pb::ArticlePage;
diff --git a/chromium/components/dom_distiller/core/article_entry.h b/chromium/components/dom_distiller/core/article_entry.h
index 6f6efbe1a22..c195ccb683d 100644
--- a/chromium/components/dom_distiller/core/article_entry.h
+++ b/chromium/components/dom_distiller/core/article_entry.h
@@ -8,9 +8,9 @@
#include <string>
#include "components/dom_distiller/core/proto/distilled_article.pb.h"
-#include "sync/api/sync_data.h"
-#include "sync/protocol/article_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/protocol/article_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
namespace syncer {
class SyncChange;
diff --git a/chromium/components/dom_distiller/core/article_entry_unittest.cc b/chromium/components/dom_distiller/core/article_entry_unittest.cc
index a857cafef50..bd861b0b9e5 100644
--- a/chromium/components/dom_distiller/core/article_entry_unittest.cc
+++ b/chromium/components/dom_distiller/core/article_entry_unittest.cc
@@ -4,7 +4,7 @@
#include "components/dom_distiller/core/article_entry.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
using sync_pb::EntitySpecifics;
diff --git a/chromium/components/dom_distiller/core/distillable_page_detector_unittest.cc b/chromium/components/dom_distiller/core/distillable_page_detector_unittest.cc
index fc51fc968c5..d56be15d249 100644
--- a/chromium/components/dom_distiller/core/distillable_page_detector_unittest.cc
+++ b/chromium/components/dom_distiller/core/distillable_page_detector_unittest.cc
@@ -30,8 +30,8 @@ class Builder {
}
proto_.set_num_features(num_features);
proto_.set_num_stumps(proto_.stump_size());
- return base::WrapUnique(new DistillablePageDetector(
- base::WrapUnique(new AdaBoostProto(proto_))));
+ return base::MakeUnique<DistillablePageDetector>(
+ base::WrapUnique(new AdaBoostProto(proto_)));
}
private:
diff --git a/chromium/components/dom_distiller/core/distilled_page_prefs_android.cc b/chromium/components/dom_distiller/core/distilled_page_prefs_android.cc
index 64bfc2bf231..b10cb0fb3ee 100644
--- a/chromium/components/dom_distiller/core/distilled_page_prefs_android.cc
+++ b/chromium/components/dom_distiller/core/distilled_page_prefs_android.cc
@@ -8,6 +8,8 @@
#include "components/dom_distiller/core/dom_distiller_service.h"
#include "jni/DistilledPagePrefs_jni.h"
+using base::android::JavaParamRef;
+
namespace dom_distiller {
namespace android {
@@ -107,21 +109,21 @@ void DistilledPagePrefsObserverAndroid::OnChangeFontFamily(
DistilledPagePrefs::FontFamily new_font_family) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_DistilledPagePrefsObserverWrapper_onChangeFontFamily(
- env, java_ref_.obj(), (int)new_font_family);
+ env, java_ref_, (int)new_font_family);
}
void DistilledPagePrefsObserverAndroid::OnChangeTheme(
DistilledPagePrefs::Theme new_theme) {
JNIEnv* env = base::android::AttachCurrentThread();
- Java_DistilledPagePrefsObserverWrapper_onChangeTheme(
- env, java_ref_.obj(), (int)new_theme);
+ Java_DistilledPagePrefsObserverWrapper_onChangeTheme(env, java_ref_,
+ (int)new_theme);
}
void DistilledPagePrefsObserverAndroid::OnChangeFontScaling(
float scaling) {
JNIEnv* env = base::android::AttachCurrentThread();
- Java_DistilledPagePrefsObserverWrapper_onChangeFontScaling(
- env, java_ref_.obj(), scaling);
+ Java_DistilledPagePrefsObserverWrapper_onChangeFontScaling(env, java_ref_,
+ scaling);
}
jlong InitObserverAndroid(JNIEnv* env, const JavaParamRef<jobject>& obj) {
diff --git a/chromium/components/dom_distiller/core/distiller_url_fetcher_unittest.cc b/chromium/components/dom_distiller/core/distiller_url_fetcher_unittest.cc
index 41df9f82967..36b7b721062 100644
--- a/chromium/components/dom_distiller/core/distiller_url_fetcher_unittest.cc
+++ b/chromium/components/dom_distiller/core/distiller_url_fetcher_unittest.cc
@@ -5,6 +5,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "components/dom_distiller/core/distiller_url_fetcher.h"
#include "net/http/http_status_code.h"
#include "net/url_request/test_url_fetcher_factory.h"
@@ -50,7 +51,7 @@ class DistillerURLFetcherTest : public testing::Test {
url,
base::Bind(&DistillerURLFetcherTest::FetcherCallback,
base::Unretained(this)));
- loop.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
CHECK_EQ(expected_response, response_);
}
diff --git a/chromium/components/dom_distiller/core/dom_distiller_model.h b/chromium/components/dom_distiller/core/dom_distiller_model.h
index 071f9ca5c43..5a70216097d 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_model.h
+++ b/chromium/components/dom_distiller/core/dom_distiller_model.h
@@ -15,9 +15,9 @@
#include "base/id_map.h"
#include "base/macros.h"
#include "components/dom_distiller/core/article_entry.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_change_processor.h" // syncer::SyncChangeList
-#include "sync/api/sync_data.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_change_processor.h" // syncer::SyncChangeList
+#include "components/sync/api/sync_data.h"
#include "url/gurl.h"
namespace dom_distiller {
diff --git a/chromium/components/dom_distiller/core/dom_distiller_service_android.cc b/chromium/components/dom_distiller/core/dom_distiller_service_android.cc
index cdf72894e49..0f4b1311996 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_service_android.cc
+++ b/chromium/components/dom_distiller/core/dom_distiller_service_android.cc
@@ -13,6 +13,7 @@
#include "jni/DomDistillerService_jni.h"
using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
namespace dom_distiller {
diff --git a/chromium/components/dom_distiller/core/dom_distiller_store.cc b/chromium/components/dom_distiller/core/dom_distiller_store.cc
index 1f76d99a473..c70bff387b3 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_store.cc
+++ b/chromium/components/dom_distiller/core/dom_distiller_store.cc
@@ -5,6 +5,7 @@
#include "components/dom_distiller/core/dom_distiller_store.h"
#include <stddef.h>
+
#include <utility>
#include "base/bind.h"
@@ -13,9 +14,9 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/dom_distiller/core/article_entry.h"
-#include "sync/api/sync_change.h"
-#include "sync/protocol/article_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/protocol/article_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
using leveldb_proto::ProtoDatabase;
using sync_pb::ArticleSpecifics;
diff --git a/chromium/components/dom_distiller/core/dom_distiller_store.h b/chromium/components/dom_distiller/core/dom_distiller_store.h
index 9dededd8604..61ef83f32eb 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_store.h
+++ b/chromium/components/dom_distiller/core/dom_distiller_store.h
@@ -17,12 +17,12 @@
#include "components/dom_distiller/core/dom_distiller_model.h"
#include "components/dom_distiller/core/dom_distiller_observer.h"
#include "components/leveldb_proto/proto_database.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/api/sync_merge_result.h"
-#include "sync/api/syncable_service.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/api/sync_merge_result.h"
+#include "components/sync/api/syncable_service.h"
#include "url/gurl.h"
namespace base {
diff --git a/chromium/components/dom_distiller/core/dom_distiller_store_unittest.cc b/chromium/components/dom_distiller/core/dom_distiller_store_unittest.cc
index 15b3452dad7..9ac8004ca22 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_store_unittest.cc
+++ b/chromium/components/dom_distiller/core/dom_distiller_store_unittest.cc
@@ -18,9 +18,9 @@
#include "components/dom_distiller/core/article_entry.h"
#include "components/dom_distiller/core/dom_distiller_test_util.h"
#include "components/leveldb_proto/testing/fake_db.h"
-#include "sync/api/attachments/attachment_id.h"
-#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/attachments/attachment_id.h"
+#include "components/sync/core/attachments/attachment_service_proxy_for_test.h"
+#include "components/sync/protocol/sync.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -353,8 +353,7 @@ TEST_F(DomDistillerStoreTest, TestAttachments) {
article_proto.set_title("A title");
attachments.set_distilled_article(article_proto);
store_->UpdateAttachments(
- entry.entry_id(),
- base::WrapUnique(new ArticleAttachmentsData(attachments)),
+ entry.entry_id(), base::MakeUnique<ArticleAttachmentsData>(attachments),
callbacks.UpdateCallback());
EXPECT_CALL(callbacks, Update(true));
base::RunLoop().RunUntilIdle();
diff --git a/chromium/components/dom_distiller/core/dom_distiller_switches.cc b/chromium/components/dom_distiller/core/dom_distiller_switches.cc
index ea30b68c039..70a90f1d0d3 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_switches.cc
+++ b/chromium/components/dom_distiller/core/dom_distiller_switches.cc
@@ -6,6 +6,7 @@
namespace switches {
+const char kEnableDistillabilityService[] = "enable-distillability-service";
const char kEnableDomDistiller[] = "enable-dom-distiller";
const char kEnableSyncArticles[] = "enable-sync-articles";
const char kReaderModeHeuristics[] = "reader-mode-heuristics";
diff --git a/chromium/components/dom_distiller/core/dom_distiller_switches.h b/chromium/components/dom_distiller/core/dom_distiller_switches.h
index 6b89533c342..91952d7bedc 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_switches.h
+++ b/chromium/components/dom_distiller/core/dom_distiller_switches.h
@@ -10,6 +10,9 @@
namespace switches {
+// Switch to enable the distillability service on the renderer.
+extern const char kEnableDistillabilityService[];
+
// Switch to enable the DOM distiller.
extern const char kEnableDomDistiller[];
diff --git a/chromium/components/dom_distiller/core/experiments.cc b/chromium/components/dom_distiller/core/experiments.cc
index 168f23eb846..cc882d1f0fb 100644
--- a/chromium/components/dom_distiller/core/experiments.cc
+++ b/chromium/components/dom_distiller/core/experiments.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
+#include "base/strings/string_util.h"
#include "components/dom_distiller/core/dom_distiller_switches.h"
namespace dom_distiller {
@@ -31,14 +32,20 @@ DistillerHeuristicsType GetDistillerHeuristicsType() {
}
NOTREACHED() << "Invalid value for " << switches::kReaderModeHeuristics;
} else {
- if (group_name == "AdaBoost") {
+ if (base::StartsWith(group_name, "AdaBoost",
+ base::CompareCase::INSENSITIVE_ASCII)) {
return DistillerHeuristicsType::ADABOOST_MODEL;
}
- if (group_name == "OGArticle") {
+ if (base::StartsWith(group_name, "OGArticle",
+ base::CompareCase::INSENSITIVE_ASCII)) {
return DistillerHeuristicsType::OG_ARTICLE;
}
+ if (base::StartsWith(group_name, "Disabled",
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ return DistillerHeuristicsType::NONE;
+ }
}
- return DistillerHeuristicsType::NONE;
+ return DistillerHeuristicsType::ADABOOST_MODEL;
}
bool ShouldShowFeedbackForm() {
diff --git a/chromium/components/dom_distiller/core/proto/BUILD.gn b/chromium/components/dom_distiller/core/proto/BUILD.gn
index dcea531109c..3b20581e5d8 100644
--- a/chromium/components/dom_distiller/core/proto/BUILD.gn
+++ b/chromium/components/dom_distiller/core/proto/BUILD.gn
@@ -4,7 +4,6 @@
import("//third_party/protobuf/proto_library.gni")
-# GYP version: components/dom_distiller.gypi:dom_distiller_protos
proto_library("proto") {
sources = [
"adaboost.proto",
diff --git a/chromium/components/dom_distiller/core/url_utils_android.cc b/chromium/components/dom_distiller/core/url_utils_android.cc
index fc387869b35..cd07cdc0d13 100644
--- a/chromium/components/dom_distiller/core/url_utils_android.cc
+++ b/chromium/components/dom_distiller/core/url_utils_android.cc
@@ -13,6 +13,9 @@
#include "net/base/url_util.h"
#include "url/gurl.h"
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
namespace dom_distiller {
namespace url_utils {
diff --git a/chromium/components/dom_distiller/ios/distiller_page_ios.h b/chromium/components/dom_distiller/ios/distiller_page_ios.h
index 2103959a76e..1fdf87e9a91 100644
--- a/chromium/components/dom_distiller/ios/distiller_page_ios.h
+++ b/chromium/components/dom_distiller/ios/distiller_page_ios.h
@@ -44,7 +44,10 @@ class DistillerPageIOS : public DistillerPage {
void OnLoadURLDone(web::PageLoadCompletionStatus load_completion_status);
// Called once the |script_| has been evaluated on the page.
- void HandleJavaScriptResultString(NSString* result);
+ void HandleJavaScriptResult(id result);
+
+ // Converts result of WKWebView script evaluation to base::Value
+ std::unique_ptr<base::Value> ValueResultFromScriptResult(id wk_result);
web::BrowserState* browser_state_;
GURL url_;
diff --git a/chromium/components/dom_distiller/ios/distiller_page_ios.mm b/chromium/components/dom_distiller/ios/distiller_page_ios.mm
index a20326d2b7e..213e82fd671 100644
--- a/chromium/components/dom_distiller/ios/distiller_page_ios.mm
+++ b/chromium/components/dom_distiller/ios/distiller_page_ios.mm
@@ -10,11 +10,89 @@
#include "base/json/json_reader.h"
#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
#include "ios/public/provider/web/web_controller_provider.h"
#include "ios/web/public/browser_state.h"
+namespace {
+
+// This is duplicated here from ios/web/web_state/ui/web_view_js_utils.mm in
+// order to handle numbers. The dom distiller proto expects integers and the
+// generated JSON deserializer does not accept doubles in the place of ints.
+// However WKWebView only returns "numbers." However, here the proto expects
+// integers and doubles, which is done by checking if the number has a fraction
+// or not; since this is a hacky method it's isolated to this file so as to
+// limit the risk of broken JS calls.
+
+int const kMaximumParsingRecursionDepth = 6;
+// Converts result of WKWebView script evaluation to base::Value, parsing
+// |wk_result| up to a depth of |max_depth|.
+std::unique_ptr<base::Value> ValueResultFromScriptResult(id wk_result,
+ int max_depth) {
+ if (!wk_result)
+ return nullptr;
+
+ std::unique_ptr<base::Value> result;
+
+ if (max_depth < 0) {
+ DLOG(WARNING) << "JS maximum recursion depth exceeded.";
+ return result;
+ }
+
+ CFTypeID result_type = CFGetTypeID(wk_result);
+ if (result_type == CFStringGetTypeID()) {
+ result.reset(new base::StringValue(base::SysNSStringToUTF16(wk_result)));
+ DCHECK(result->IsType(base::Value::TYPE_STRING));
+ } else if (result_type == CFNumberGetTypeID()) {
+ // Different implementation is here.
+ if ([wk_result intValue] != [wk_result doubleValue]) {
+ result.reset(new base::FundamentalValue([wk_result doubleValue]));
+ DCHECK(result->IsType(base::Value::TYPE_DOUBLE));
+ } else {
+ result.reset(new base::FundamentalValue([wk_result intValue]));
+ DCHECK(result->IsType(base::Value::TYPE_INTEGER));
+ }
+ // End of different implementation.
+ } else if (result_type == CFBooleanGetTypeID()) {
+ result.reset(
+ new base::FundamentalValue(static_cast<bool>([wk_result boolValue])));
+ DCHECK(result->IsType(base::Value::TYPE_BOOLEAN));
+ } else if (result_type == CFNullGetTypeID()) {
+ result = base::Value::CreateNullValue();
+ DCHECK(result->IsType(base::Value::TYPE_NULL));
+ } else if (result_type == CFDictionaryGetTypeID()) {
+ std::unique_ptr<base::DictionaryValue> dictionary =
+ base::MakeUnique<base::DictionaryValue>();
+ for (id key in wk_result) {
+ NSString* obj_c_string = base::mac::ObjCCast<NSString>(key);
+ const std::string path = base::SysNSStringToUTF8(obj_c_string);
+ std::unique_ptr<base::Value> value =
+ ValueResultFromScriptResult(wk_result[obj_c_string], max_depth - 1);
+ if (value) {
+ dictionary->Set(path, std::move(value));
+ }
+ }
+ result = std::move(dictionary);
+ } else if (result_type == CFArrayGetTypeID()) {
+ std::unique_ptr<base::ListValue> list = base::MakeUnique<base::ListValue>();
+ for (id list_item in wk_result) {
+ std::unique_ptr<base::Value> value =
+ ValueResultFromScriptResult(list_item, max_depth - 1);
+ if (value) {
+ list->Append(std::move(value));
+ }
+ }
+ result = std::move(list);
+ } else {
+ NOTREACHED(); // Convert other types as needed.
+ }
+ return result;
+}
+}
+
namespace dom_distiller {
// Helper class for observing the loading of URLs to distill.
@@ -54,8 +132,7 @@ DistillerPageIOS::~DistillerPageIOS() {
}
bool DistillerPageIOS::StringifyOutput() {
- // UIWebView requires JavaScript to return a single string value.
- return true;
+ return false;
}
void DistillerPageIOS::DistillPageImpl(const GURL& url,
@@ -89,30 +166,30 @@ void DistillerPageIOS::OnLoadURLDone(
// provider.
if (load_completion_status == web::PageLoadCompletionStatus::FAILURE ||
!provider_) {
- HandleJavaScriptResultString(@"");
+ HandleJavaScriptResult(nil);
return;
}
// Inject the script.
base::WeakPtr<DistillerPageIOS> weak_this = weak_ptr_factory_.GetWeakPtr();
- provider_->InjectScript(script_, ^(NSString* string, NSError* error) {
+ provider_->InjectScript(script_, ^(id result, NSError* error) {
DistillerPageIOS* distiller_page = weak_this.get();
if (distiller_page)
- distiller_page->HandleJavaScriptResultString(string);
+ distiller_page->HandleJavaScriptResult(result);
});
}
-void DistillerPageIOS::HandleJavaScriptResultString(NSString* result) {
+void DistillerPageIOS::HandleJavaScriptResult(id result) {
std::unique_ptr<base::Value> resultValue = base::Value::CreateNullValue();
- if (result.length) {
- std::unique_ptr<base::Value> dictionaryValue =
- base::JSONReader::Read(base::SysNSStringToUTF8(result));
- if (dictionaryValue &&
- dictionaryValue->IsType(base::Value::TYPE_DICTIONARY)) {
- resultValue = std::move(dictionaryValue);
- }
+ if (result) {
+ resultValue = ValueResultFromScriptResult(result);
}
OnDistillationDone(url_, resultValue.get());
}
+std::unique_ptr<base::Value> DistillerPageIOS::ValueResultFromScriptResult(
+ id wk_result) {
+ return ::ValueResultFromScriptResult(wk_result,
+ kMaximumParsingRecursionDepth);
+}
} // namespace dom_distiller
diff --git a/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc b/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
index 8e620b74fc3..cbae88bcab0 100644
--- a/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
+++ b/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
@@ -351,9 +351,8 @@ class ContentExtractor : public ContentBrowserTest {
command_line, &file_to_url_map);
content::BrowserContext* context =
shell()->web_contents()->GetBrowserContext();
- service_ = CreateDomDistillerService(context,
- db_dir_.path(),
- file_to_url_map);
+ service_ =
+ CreateDomDistillerService(context, db_dir_.GetPath(), file_to_url_map);
PumpQueue();
}
diff --git a/chromium/components/dom_distiller/webui/BUILD.gn b/chromium/components/dom_distiller/webui/BUILD.gn
index 539c04bca45..242e09aeea8 100644
--- a/chromium/components/dom_distiller/webui/BUILD.gn
+++ b/chromium/components/dom_distiller/webui/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/dom_distiller.gyp:dom_distiller_webui
static_library("webui") {
sources = [
"dom_distiller_handler.cc",
@@ -17,10 +16,10 @@ static_library("webui") {
"//components/dom_distiller/core/proto",
"//components/resources",
"//components/strings",
+ "//components/sync",
"//content/public/browser",
"//net",
"//skia",
- "//sync",
"//url",
]
}
diff --git a/chromium/components/dom_distiller/webui/dom_distiller_handler.cc b/chromium/components/dom_distiller/webui/dom_distiller_handler.cc
index 9d8970b6631..71f741a10ad 100644
--- a/chromium/components/dom_distiller/webui/dom_distiller_handler.cc
+++ b/chromium/components/dom_distiller/webui/dom_distiller_handler.cc
@@ -65,11 +65,10 @@ void DomDistillerHandler::HandleAddArticle(const base::ListValue* args) {
GURL gurl(url);
if (gurl.is_valid()) {
service_->AddToList(
- gurl,
- service_->CreateDefaultDistillerPage(
- web_ui()->GetWebContents()->GetContainerBounds().size()),
- base::Bind(base::Bind(&DomDistillerHandler::OnArticleAdded,
- base::Unretained(this))));
+ gurl, service_->CreateDefaultDistillerPage(
+ web_ui()->GetWebContents()->GetContainerBounds().size()),
+ base::Bind(&DomDistillerHandler::OnArticleAdded,
+ base::Unretained(this)));
} else {
web_ui()->CallJavascriptFunctionUnsafe("domDistiller.onArticleAddFailed");
}
diff --git a/chromium/components/domain_reliability.gypi b/chromium/components/domain_reliability.gypi
deleted file mode 100644
index fbd131477be..00000000000
--- a/chromium/components/domain_reliability.gypi
+++ /dev/null
@@ -1,92 +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.
-
-{
- 'includes': [
- 'domain_reliability/baked_in_configs.gypi',
- ],
- 'targets': [
- {
- # GN version: //components/domain_reliability
- 'target_name': 'domain_reliability',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../components/components.gyp:data_use_measurement_core',
- '../components/components.gyp:keyed_service_core',
- '../components/prefs/prefs.gyp:prefs',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'DOMAIN_RELIABILITY_IMPLEMENTATION',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'domain_reliability/baked_in_configs.h',
- 'domain_reliability/beacon.cc',
- 'domain_reliability/beacon.h',
- 'domain_reliability/clear_mode.h',
- 'domain_reliability/config.cc',
- 'domain_reliability/config.h',
- 'domain_reliability/context.cc',
- 'domain_reliability/context.h',
- 'domain_reliability/context_manager.cc',
- 'domain_reliability/context_manager.h',
- 'domain_reliability/dispatcher.cc',
- 'domain_reliability/dispatcher.h',
- 'domain_reliability/domain_reliability_export.h',
- 'domain_reliability/google_configs.cc',
- 'domain_reliability/google_configs.h',
- 'domain_reliability/header.cc',
- 'domain_reliability/header.h',
- 'domain_reliability/monitor.cc',
- 'domain_reliability/monitor.h',
- 'domain_reliability/quic_error_mapping.cc',
- 'domain_reliability/quic_error_mapping.h',
- 'domain_reliability/scheduler.cc',
- 'domain_reliability/scheduler.h',
- 'domain_reliability/service.cc',
- 'domain_reliability/service.h',
- 'domain_reliability/uploader.cc',
- 'domain_reliability/uploader.h',
- 'domain_reliability/util.cc',
- 'domain_reliability/util.h',
- ],
- 'actions': [
- {
- 'action_name': 'bake_in_configs',
- 'variables': {
- 'bake_in_configs_script': 'domain_reliability/bake_in_configs.py',
- 'baked_in_configs_cc':
- '<(INTERMEDIATE_DIR)/domain_reliability/baked_in_configs.cc',
- },
- 'inputs': [
- '<(bake_in_configs_script)',
- '<@(baked_in_configs)',
- 'domain_reliability/baked_in_configs.gypi',
- ],
- 'outputs': [
- '<(baked_in_configs_cc)'
- ],
- # The actual list of JSON files will overflow the command line length
- # limit on Windows, so pass the name of the .gypi file and
- # bake_in_configs.py will read the filenames out of it manually.
- 'action': ['python',
- '<(bake_in_configs_script)',
- '--gypi-relative-to=.',
- '--gypi-file=domain_reliability/baked_in_configs.gypi',
- '--output=<(baked_in_configs_cc)'],
- 'process_outputs_as_sources': 1,
- 'message': 'Baking in Domain Reliability configs',
- },
- ],
- },
- ],
-}
diff --git a/chromium/components/domain_reliability/BUILD.gn b/chromium/components/domain_reliability/BUILD.gn
index 5834a824bcb..52620af9e65 100644
--- a/chromium/components/domain_reliability/BUILD.gn
+++ b/chromium/components/domain_reliability/BUILD.gn
@@ -2,28 +2,30 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# Paths to the JSON files are kind of gross. They're stored in the gypi
-# relative to //components, since that's the working directory gyp seems
-# to use for all of the components. When we depend on them here, we need
-# to remove the leading domain_reliability, since *our* working directory
-# is one level deeper. When we call bake_in_configs.py, we need to give
-# it a properly-rebased path to //components so it can properly join the
-# paths relative to that and find the JSON files.
-
-baked_in_configs_gypi = exec_script("//build/gypi_to_gn.py",
- [ rebase_path("baked_in_configs.gypi") ],
- "scope",
- [ "baked_in_configs.gypi" ])
-
-# The config file names in the .gypi are relative to "//components".
-baked_in_configs =
- rebase_path(baked_in_configs_gypi.baked_in_configs, ".", "//components")
-
action("bake_in_configs") {
visibility = [ ":*" ]
script = "bake_in_configs.py"
- inputs = baked_in_configs + [ "baked_in_configs.gypi" ]
+ inputs = [
+ "baked_in_configs/c_android_clients_google_com.json",
+ "baked_in_configs/c_bigcache_googleapis_com.json",
+ "baked_in_configs/c_doc-0-0-sj_sj_googleusercontent_com.json",
+ "baked_in_configs/c_docs_google_com.json",
+ "baked_in_configs/c_drive_google_com.json",
+ "baked_in_configs/c_googlesyndication_com.json",
+ "baked_in_configs/c_pack_google_com.json",
+ "baked_in_configs/c_play_google_com.json",
+ "baked_in_configs/c_youtube_com.json",
+ "baked_in_configs/clients2_google_com.json",
+ "baked_in_configs/docs_google_com.json",
+ "baked_in_configs/google-analytics_com.json",
+ "baked_in_configs/googlevideo_com.json",
+ "baked_in_configs/gvt1_com.json",
+ "baked_in_configs/gvt2_com.json",
+ "baked_in_configs/ssl_gstatic_com.json",
+ "baked_in_configs/www_google_com.json",
+ ]
+
output_file = "$target_gen_dir/baked_in_configs.cc"
outputs = [
output_file,
@@ -31,7 +33,7 @@ action("bake_in_configs") {
# The JSON file list is too long for the command line on Windows, so put
# them in a response file.
- response_file_contents = rebase_path(baked_in_configs, root_build_dir)
+ response_file_contents = rebase_path(inputs, root_build_dir)
args = [
"--file-list",
"{{response_file_name}}",
diff --git a/chromium/components/domain_reliability/OWNERS b/chromium/components/domain_reliability/OWNERS
index 5532f10dafd..e6a2f014455 100644
--- a/chromium/components/domain_reliability/OWNERS
+++ b/chromium/components/domain_reliability/OWNERS
@@ -3,4 +3,4 @@ rdsmith@chromium.org
juliatuttle@chromium.org
per-file quic_error_mapping*=rch@chromium.org
-per-file quic_error_mapping*=rtenneti@chromium.org
+per-file quic_error_mapping*=zhongyi@chromium.org
diff --git a/chromium/components/domain_reliability/baked_in_configs.gypi b/chromium/components/domain_reliability/baked_in_configs.gypi
deleted file mode 100644
index a872ef8792e..00000000000
--- a/chromium/components/domain_reliability/baked_in_configs.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'variables': {
- 'baked_in_configs': [
- 'domain_reliability/baked_in_configs/c_android_clients_google_com.json',
- 'domain_reliability/baked_in_configs/c_bigcache_googleapis_com.json',
- 'domain_reliability/baked_in_configs/c_doc-0-0-sj_sj_googleusercontent_com.json',
- 'domain_reliability/baked_in_configs/c_docs_google_com.json',
- 'domain_reliability/baked_in_configs/c_drive_google_com.json',
- 'domain_reliability/baked_in_configs/c_googlesyndication_com.json',
- 'domain_reliability/baked_in_configs/c_pack_google_com.json',
- 'domain_reliability/baked_in_configs/c_play_google_com.json',
- 'domain_reliability/baked_in_configs/c_youtube_com.json',
- 'domain_reliability/baked_in_configs/clients2_google_com.json',
- 'domain_reliability/baked_in_configs/docs_google_com.json',
- 'domain_reliability/baked_in_configs/google-analytics_com.json',
- 'domain_reliability/baked_in_configs/googlevideo_com.json',
- 'domain_reliability/baked_in_configs/gvt1_com.json',
- 'domain_reliability/baked_in_configs/gvt2_com.json',
- 'domain_reliability/baked_in_configs/ssl_gstatic_com.json',
- 'domain_reliability/baked_in_configs/www_google_com.json',
- ],
- },
-}
diff --git a/chromium/components/domain_reliability/config.cc b/chromium/components/domain_reliability/config.cc
index df2dd45201e..765e0fa4837 100644
--- a/chromium/components/domain_reliability/config.cc
+++ b/chromium/components/domain_reliability/config.cc
@@ -70,7 +70,7 @@ bool DomainReliabilityConfig::IsValid() const {
return false;
}
- for (const auto& url : collectors) {
+ for (const auto* url : collectors) {
if (!url->is_valid())
return false;
}
diff --git a/chromium/components/domain_reliability/context.cc b/chromium/components/domain_reliability/context.cc
index 34b27cbf24b..bbbd78f8a4e 100644
--- a/chromium/components/domain_reliability/context.cc
+++ b/chromium/components/domain_reliability/context.cc
@@ -10,7 +10,7 @@
#include "base/bind.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/rand_util.h"
#include "base/values.h"
@@ -97,7 +97,7 @@ void DomainReliabilityContext::OnBeacon(
// one layer of recursion, to avoid infinite report loops.
if (beacon->upload_depth <= kMaxUploadDepthToSchedule)
scheduler_.OnBeaconAdded();
- beacons_.push_back(beacon.release());
+ beacons_.push_back(std::move(beacon));
bool should_evict = beacons_.size() > kMaxQueuedBeacons;
if (should_evict)
RemoveOldestBeacon();
@@ -106,7 +106,6 @@ void DomainReliabilityContext::OnBeacon(
}
void DomainReliabilityContext::ClearBeacons() {
- STLDeleteElements(&beacons_);
beacons_.clear();
uploading_beacons_size_ = 0;
}
@@ -127,7 +126,9 @@ void DomainReliabilityContext::GetQueuedBeaconsForTesting(
std::vector<const DomainReliabilityBeacon*>* beacons_out) const {
DCHECK(this);
DCHECK(beacons_out);
- beacons_out->assign(beacons_.begin(), beacons_.end());
+ beacons_out->clear();
+ for (const auto& beacon : beacons_)
+ beacons_out->push_back(beacon.get());
}
void DomainReliabilityContext::ScheduleUpload(
@@ -230,7 +231,6 @@ void DomainReliabilityContext::MarkUpload() {
void DomainReliabilityContext::CommitUpload() {
auto begin = beacons_.begin();
auto end = begin + uploading_beacons_size_;
- STLDeleteContainerPointers(begin, end);
beacons_.erase(begin, end);
DCHECK_NE(0u, uploading_beacons_size_);
uploading_beacons_size_ = 0;
@@ -247,7 +247,6 @@ void DomainReliabilityContext::RemoveOldestBeacon() {
VLOG(1) << "Beacon queue for " << config().origin << " full; "
<< "removing oldest beacon";
- delete beacons_.front();
beacons_.pop_front();
// If that just removed a beacon counted in uploading_beacons_size_, decrement
diff --git a/chromium/components/domain_reliability/context.h b/chromium/components/domain_reliability/context.h
index a598897a5e1..34ef4bf9d2b 100644
--- a/chromium/components/domain_reliability/context.h
+++ b/chromium/components/domain_reliability/context.h
@@ -83,9 +83,6 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityContext {
static const size_t kMaxQueuedBeacons;
private:
- // Deque of beacons owned by this context. (Deleted after uploading.)
- typedef std::deque<DomainReliabilityBeacon*> BeaconDeque;
-
void ScheduleUpload(base::TimeDelta min_delay, base::TimeDelta max_delay);
void StartUpload();
void OnUploadComplete(const DomainReliabilityUploader::UploadResult& result);
@@ -117,7 +114,7 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityContext {
DomainReliabilityDispatcher* dispatcher_;
DomainReliabilityUploader* uploader_;
- BeaconDeque beacons_;
+ std::deque<std::unique_ptr<DomainReliabilityBeacon>> beacons_;
size_t uploading_beacons_size_;
base::TimeTicks upload_time_;
base::TimeTicks last_upload_time_;
diff --git a/chromium/components/domain_reliability/context_manager.cc b/chromium/components/domain_reliability/context_manager.cc
index 54d5eaa176e..bcdb530de64 100644
--- a/chromium/components/domain_reliability/context_manager.cc
+++ b/chromium/components/domain_reliability/context_manager.cc
@@ -14,7 +14,8 @@ DomainReliabilityContextManager::DomainReliabilityContextManager(
}
DomainReliabilityContextManager::~DomainReliabilityContextManager() {
- RemoveAllContexts();
+ RemoveContexts(
+ base::Callback<bool(const GURL&)>() /* no filter - delete everything */);
}
void DomainReliabilityContextManager::RouteBeacon(
@@ -69,9 +70,14 @@ void DomainReliabilityContextManager::ClearConfig(const GURL& origin) {
}
}
-void DomainReliabilityContextManager::ClearBeaconsInAllContexts() {
- for (auto& context_entry : contexts_)
- context_entry.second->ClearBeacons();
+void DomainReliabilityContextManager::ClearBeacons(
+ const base::Callback<bool(const GURL&)>& origin_filter) {
+ for (auto& context_entry : contexts_) {
+ if (origin_filter.is_null() ||
+ origin_filter.Run(context_entry.second->config().origin)) {
+ context_entry.second->ClearBeacons();
+ }
+ }
}
DomainReliabilityContext* DomainReliabilityContextManager::AddContextForConfig(
@@ -89,10 +95,18 @@ DomainReliabilityContext* DomainReliabilityContextManager::AddContextForConfig(
return *entry;
}
-void DomainReliabilityContextManager::RemoveAllContexts() {
- STLDeleteContainerPairSecondPointers(
- contexts_.begin(), contexts_.end());
- contexts_.clear();
+void DomainReliabilityContextManager::RemoveContexts(
+ const base::Callback<bool(const GURL&)>& origin_filter) {
+ for (ContextMap::iterator it = contexts_.begin(); it != contexts_.end(); ) {
+ if (!origin_filter.is_null() &&
+ !origin_filter.Run(it->second->config().origin)) {
+ ++it;
+ continue;
+ }
+
+ delete it->second;
+ it = contexts_.erase(it);
+ }
}
std::unique_ptr<base::Value> DomainReliabilityContextManager::GetWebUIData()
diff --git a/chromium/components/domain_reliability/context_manager.h b/chromium/components/domain_reliability/context_manager.h
index 7691b0518fd..3d3aaead3ea 100644
--- a/chromium/components/domain_reliability/context_manager.h
+++ b/chromium/components/domain_reliability/context_manager.h
@@ -37,9 +37,11 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityContextManager {
base::TimeDelta max_age);
void ClearConfig(const GURL& origin);
- // Calls |ClearBeacons| on all contexts added to this manager, but leaves
- // the contexts themselves intact.
- void ClearBeaconsInAllContexts();
+ // Calls |ClearBeacons| on all contexts matched by |origin_filter| added
+ // to this manager, but leaves the contexts themselves intact. A null
+ // |origin_filter| is interpreted as an always-true filter, indicating
+ // complete deletion.
+ void ClearBeacons(const base::Callback<bool(const GURL&)>& origin_filter);
// TODO(juliatuttle): Once unit tests test ContextManager directly, they can
// use a custom Context::Factory to get the created Context, and this can be
@@ -47,9 +49,10 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityContextManager {
DomainReliabilityContext* AddContextForConfig(
std::unique_ptr<const DomainReliabilityConfig> config);
- // Removes all contexts from this manager (discarding all queued beacons in
- // the process).
- void RemoveAllContexts();
+ // Removes all contexts matched by |origin_filter| from this manager
+ // (discarding all queued beacons in the process). A null |origin_filter|
+ // is interpreted as an always-true filter, indicating complete deletion.
+ void RemoveContexts(const base::Callback<bool(const GURL&)>& origin_filter);
std::unique_ptr<base::Value> GetWebUIData() const;
diff --git a/chromium/components/domain_reliability/context_unittest.cc b/chromium/components/domain_reliability/context_unittest.cc
index d68d9db4f3a..bdaf4633722 100644
--- a/chromium/components/domain_reliability/context_unittest.cc
+++ b/chromium/components/domain_reliability/context_unittest.cc
@@ -13,6 +13,7 @@
#include "base/bind.h"
#include "base/json/json_reader.h"
+#include "base/strings/string_piece.h"
#include "components/domain_reliability/beacon.h"
#include "components/domain_reliability/dispatcher.h"
#include "components/domain_reliability/scheduler.h"
@@ -60,8 +61,8 @@ std::unique_ptr<DomainReliabilityBeacon> MakeBeacon(MockableTime* time) {
}
template <typename ValueType,
- bool (DictionaryValue::* GetValueType)(const std::string&,
- ValueType*) const>
+ bool (DictionaryValue::*GetValueType)(base::StringPiece, ValueType*)
+ const>
struct HasValue {
bool operator()(const DictionaryValue& dict,
const std::string& key,
diff --git a/chromium/components/domain_reliability/dispatcher.cc b/chromium/components/domain_reliability/dispatcher.cc
index c3af45cb424..3abef20e777 100644
--- a/chromium/components/domain_reliability/dispatcher.cc
+++ b/chromium/components/domain_reliability/dispatcher.cc
@@ -4,12 +4,13 @@
#include "components/domain_reliability/dispatcher.h"
+#include <algorithm>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
-#include "base/stl_util.h"
#include "base/timer/timer.h"
#include "components/domain_reliability/util.h"
@@ -45,10 +46,7 @@ DomainReliabilityDispatcher::Task::~Task() {}
DomainReliabilityDispatcher::DomainReliabilityDispatcher(MockableTime* time)
: time_(time) {}
-DomainReliabilityDispatcher::~DomainReliabilityDispatcher() {
- // TODO(juliatuttle): STLElementDeleter?
- STLDeleteElements(&tasks_);
-}
+DomainReliabilityDispatcher::~DomainReliabilityDispatcher() {}
void DomainReliabilityDispatcher::ScheduleTask(
const base::Closure& closure,
@@ -58,8 +56,10 @@ void DomainReliabilityDispatcher::ScheduleTask(
// Would be DCHECK_LE, but you can't << a TimeDelta.
DCHECK(min_delay <= max_delay);
- Task* task = new Task(closure, time_->CreateTimer(), min_delay, max_delay);
- tasks_.insert(task);
+ std::unique_ptr<Task> owned_task = base::MakeUnique<Task>(
+ closure, time_->CreateTimer(), min_delay, max_delay);
+ Task* task = owned_task.get();
+ tasks_.insert(std::move(owned_task));
if (max_delay.InMicroseconds() < 0)
RunAndDeleteTask(task);
else if (min_delay.InMicroseconds() < 0)
@@ -76,7 +76,7 @@ void DomainReliabilityDispatcher::RunEligibleTasks() {
std::set<Task*> tasks;
tasks.swap(eligible_tasks_);
- for (auto& task : tasks) {
+ for (auto* task : tasks) {
DCHECK(task);
DCHECK(task->eligible);
RunAndDeleteTask(task);
@@ -113,8 +113,14 @@ void DomainReliabilityDispatcher::RunAndDeleteTask(Task* task) {
task->closure.Run();
if (task->eligible)
eligible_tasks_.erase(task);
- tasks_.erase(task);
- delete task;
+
+ auto it = std::find_if(tasks_.begin(), tasks_.end(),
+ [task](const std::unique_ptr<Task>& task_ptr) {
+ return task_ptr.get() == task;
+ });
+
+ DCHECK(it != tasks_.end());
+ tasks_.erase(it);
}
} // namespace domain_reliability
diff --git a/chromium/components/domain_reliability/dispatcher.h b/chromium/components/domain_reliability/dispatcher.h
index 2c5d2d79dbf..e12b1674d12 100644
--- a/chromium/components/domain_reliability/dispatcher.h
+++ b/chromium/components/domain_reliability/dispatcher.h
@@ -5,9 +5,11 @@
#ifndef COMPONENTS_DOMAIN_RELIABILITY_DISPATCHER_H_
#define COMPONENTS_DOMAIN_RELIABILITY_DISPATCHER_H_
+#include <memory>
#include <set>
#include "base/callback_forward.h"
+#include "base/macros.h"
#include "base/time/time.h"
#include "components/domain_reliability/domain_reliability_export.h"
@@ -54,8 +56,10 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityDispatcher {
void RunAndDeleteTask(Task* task);
MockableTime* time_;
- std::set<Task*> tasks_;
+ std::set<std::unique_ptr<Task>> tasks_;
std::set<Task*> eligible_tasks_;
+
+ DISALLOW_COPY_AND_ASSIGN(DomainReliabilityDispatcher);
};
} // namespace domain_reliability
diff --git a/chromium/components/domain_reliability/google_configs.cc b/chromium/components/domain_reliability/google_configs.cc
index 740673d699c..00f55d22141 100644
--- a/chromium/components/domain_reliability/google_configs.cc
+++ b/chromium/components/domain_reliability/google_configs.cc
@@ -31,7 +31,9 @@ struct GoogleConfigParams {
};
const GoogleConfigParams kGoogleConfigs[] = {
- // Origins with subdomains and same-origin collectors.
+ // Origins with subdomains and same-origin collectors. Currently, all
+ // origins with same-origin collectors also run collectors on their www
+ // subdomain. (e.g., both foo.com and www.foo.com.)
{ "google.ac", true, true, true },
{ "google.ad", true, true, true },
{ "google.ae", true, true, true },
@@ -88,7 +90,6 @@ const GoogleConfigParams kGoogleConfigs[] = {
{ "google.co.za", true, true, true },
{ "google.co.zm", true, true, true },
{ "google.co.zw", true, true, true },
- { "google.com", true, true, false },
{ "google.com.af", true, true, true },
{ "google.com.ag", true, true, true },
{ "google.com.ai", true, true, true },
@@ -254,6 +255,10 @@ const GoogleConfigParams kGoogleConfigs[] = {
{ "google.ws", true, true, true },
{ "l.google.com", true, true, true },
+ // google.com is a special case. We have a custom config for www.google.com,
+ // so set generate_config_for_www_subdomain = false.
+ { "google.com", true, true, false },
+
// Origins with subdomains and without same-origin collectors.
{ "2mdn.net", true, false, false },
{ "adgoogle.net", true, false, false },
@@ -293,8 +298,8 @@ const GoogleConfigParams kGoogleConfigs[] = {
{ "adwhirl.com", true, false, false },
{ "android.com", true, false, false },
{ "anycast-edge.metric.gstatic.com", true, false, false },
- { "anycast1.metric.gstatic.com", true, false, false },
- { "anycast1-stb.metric.gstatic.com", true, false, false },
+ { "anycast-stb.metric.gstatic.com", true, false, false },
+ { "anycast.metric.gstatic.com", true, false, false },
{ "chromecast.com", true, false, false },
{ "chromeexperiments.com", true, false, false },
{ "chromestatus.com", true, false, false },
@@ -343,22 +348,24 @@ const GoogleConfigParams kGoogleConfigs[] = {
{ "googleusercontent.com", true, false, false },
{ "gstatic.cn", true, false, false },
{ "gstatic.com", true, false, false },
+ { "gvt3.com", true, false, false },
+ { "gvt9.com", true, false, false },
{ "picasa.com", true, false, false },
{ "recaptcha.net", true, false, false },
{ "stackdriver.com", true, false, false },
- { "stbcast.metric.gstatic.com", true, false, false },
- { "stbcast2.metric.gstatic.com", true, false, false },
- { "stbcast3.metric.gstatic.com", true, false, false },
- { "stbcast4.metric.gstatic.com", true, false, false },
{ "stbcast-stb.metric.gstatic.com", true, false, false },
+ { "stbcast.metric.gstatic.com", true, false, false },
{ "stbcast2-stb.metric.gstatic.com", true, false, false },
+ { "stbcast2.metric.gstatic.com", true, false, false },
{ "stbcast3-stb.metric.gstatic.com", true, false, false },
+ { "stbcast3.metric.gstatic.com", true, false, false },
{ "stbcast4-stb.metric.gstatic.com", true, false, false },
- { "unicast.metric.gstatic.com", true, false, false },
+ { "stbcast4.metric.gstatic.com", true, false, false },
{ "unicast-edge.metric.gstatic.com", true, false, false },
{ "unicast-stb.metric.gstatic.com", true, false, false },
- { "unicast2.metric.gstatic.com", true, false, false },
+ { "unicast.metric.gstatic.com", true, false, false },
{ "unicast2-stb.metric.gstatic.com", true, false, false },
+ { "unicast2.metric.gstatic.com", true, false, false },
{ "waze.com", true, false, false },
{ "withgoogle.com", true, false, false },
{ "youtu.be", true, false, false },
@@ -503,8 +510,8 @@ const GoogleConfigParams kGoogleConfigs[] = {
{ "ddm.google.com", false, true, false },
{ "gmail.com", false, true, false },
{ "gmail.google.com", false, true, false },
- { "mail.google.com", false, true, false },
{ "mail-attachment.googleusercontent.com", false, true, false },
+ { "mail.google.com", false, true, false },
{ "www.gmail.com", false, true, false },
// Origins without subdomains or same-origin collectors.
@@ -558,13 +565,13 @@ static std::unique_ptr<DomainReliabilityConfig> CreateGoogleConfig(
// static
void GetAllGoogleConfigs(
- std::vector<DomainReliabilityConfig*>* configs_out) {
+ std::vector<std::unique_ptr<DomainReliabilityConfig>>* configs_out) {
configs_out->clear();
for (auto& params : kGoogleConfigs) {
- configs_out->push_back(CreateGoogleConfig(params, false).release());
+ configs_out->push_back(CreateGoogleConfig(params, false));
if (params.duplicate_for_www)
- configs_out->push_back(CreateGoogleConfig(params, true).release());
+ configs_out->push_back(CreateGoogleConfig(params, true));
}
}
diff --git a/chromium/components/domain_reliability/google_configs.h b/chromium/components/domain_reliability/google_configs.h
index 8cad6a831d0..631edd592f0 100644
--- a/chromium/components/domain_reliability/google_configs.h
+++ b/chromium/components/domain_reliability/google_configs.h
@@ -13,7 +13,7 @@
namespace domain_reliability {
void DOMAIN_RELIABILITY_EXPORT GetAllGoogleConfigs(
- std::vector<DomainReliabilityConfig*>* configs_out);
+ std::vector<std::unique_ptr<DomainReliabilityConfig>>* configs_out);
} // namespace domain_reliability
diff --git a/chromium/components/domain_reliability/google_configs_unittest.cc b/chromium/components/domain_reliability/google_configs_unittest.cc
index f7cf7c4d631..fbe3aecdb2a 100644
--- a/chromium/components/domain_reliability/google_configs_unittest.cc
+++ b/chromium/components/domain_reliability/google_configs_unittest.cc
@@ -4,28 +4,26 @@
#include "components/domain_reliability/google_configs.h"
-#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace domain_reliability {
namespace {
-typedef std::vector<DomainReliabilityConfig*> ConfigPointerVector;
+using ConfigPointerVector =
+ std::vector<std::unique_ptr<DomainReliabilityConfig>>;
TEST(DomainReliabilityGoogleConfigsTest, Enumerate) {
ConfigPointerVector configs;
- STLElementDeleter<ConfigPointerVector> configs_deleter(&configs);
GetAllGoogleConfigs(&configs);
}
TEST(DomainReliabilityGoogleConfigsTest, ConfigsAreValid) {
ConfigPointerVector configs;
- STLElementDeleter<ConfigPointerVector> configs_deleter(&configs);
GetAllGoogleConfigs(&configs);
- for (auto config : configs)
+ for (auto& config : configs)
EXPECT_TRUE(config->IsValid());
}
diff --git a/chromium/components/domain_reliability/header.cc b/chromium/components/domain_reliability/header.cc
index 5a034047d29..1e9cb6af19f 100644
--- a/chromium/components/domain_reliability/header.cc
+++ b/chromium/components/domain_reliability/header.cc
@@ -284,7 +284,7 @@ std::string DomainReliabilityHeader::ToString() const {
DCHECK_EQ(0, max_age_s);
} else {
string += "report-uri=";
- for (const auto& uri : config_->collectors)
+ for (const auto* uri : config_->collectors)
string += uri->spec() + " ";
// Remove trailing space.
string.erase(string.length() - 1, 1);
diff --git a/chromium/components/domain_reliability/monitor.cc b/chromium/components/domain_reliability/monitor.cc
index 54a9c0c42cc..2da1d509dd1 100644
--- a/chromium/components/domain_reliability/monitor.cc
+++ b/chromium/components/domain_reliability/monitor.cc
@@ -171,10 +171,10 @@ void DomainReliabilityMonitor::AddBakedInConfigs() {
context_manager_.AddContextForConfig(std::move(config));
}
- std::vector<DomainReliabilityConfig*> google_configs;
+ std::vector<std::unique_ptr<DomainReliabilityConfig>> google_configs;
GetAllGoogleConfigs(&google_configs);
- for (auto google_config : google_configs)
- context_manager_.AddContextForConfig(base::WrapUnique(google_config));
+ for (auto& google_config : google_configs)
+ context_manager_.AddContextForConfig(std::move(google_config));
}
void DomainReliabilityMonitor::SetDiscardUploads(bool discard_uploads) {
@@ -217,15 +217,16 @@ void DomainReliabilityMonitor::OnNetworkChanged(
}
void DomainReliabilityMonitor::ClearBrowsingData(
- DomainReliabilityClearMode mode) {
+ DomainReliabilityClearMode mode,
+ const base::Callback<bool(const GURL&)>& origin_filter) {
DCHECK(OnNetworkThread());
switch (mode) {
case CLEAR_BEACONS:
- context_manager_.ClearBeaconsInAllContexts();
+ context_manager_.ClearBeacons(origin_filter);
break;
case CLEAR_CONTEXTS:
- context_manager_.RemoveAllContexts();
+ context_manager_.RemoveContexts(origin_filter);
break;
case MAX_CLEAR_MODE:
NOTREACHED();
@@ -255,10 +256,10 @@ DomainReliabilityMonitor::CreateContextForConfig(
DCHECK(config);
DCHECK(config->IsValid());
- return base::WrapUnique(new DomainReliabilityContext(
+ return base::MakeUnique<DomainReliabilityContext>(
time_.get(), scheduler_params_, upload_reporter_string_,
&last_network_change_time_, &dispatcher_, uploader_.get(),
- std::move(config)));
+ std::move(config));
}
DomainReliabilityMonitor::RequestInfo::RequestInfo() {}
diff --git a/chromium/components/domain_reliability/monitor.h b/chromium/components/domain_reliability/monitor.h
index c3efc7b90a9..8fa3501b1f3 100644
--- a/chromium/components/domain_reliability/monitor.h
+++ b/chromium/components/domain_reliability/monitor.h
@@ -111,10 +111,14 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityMonitor
void OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) override;
- // Called to remove browsing data. With CLEAR_BEACONS, leaves contexts in
- // place but clears beacons (which betray browsing history); with
- // CLEAR_CONTEXTS, removes all contexts (which can behave as cookies).
- void ClearBrowsingData(DomainReliabilityClearMode mode);
+ // Called to remove browsing data for origins matched by |origin_filter|.
+ // With CLEAR_BEACONS, leaves contexts in place but clears beacons (which
+ // betray browsing history); with CLEAR_CONTEXTS, removes entire contexts
+ // (which can behave as cookies). A null |origin_filter| is interpreted
+ // as an always-true filter, indicating complete deletion.
+ void ClearBrowsingData(
+ DomainReliabilityClearMode mode,
+ const base::Callback<bool(const GURL&)>& origin_filter);
// Gets a Value containing data that can be formatted into a web page for
// debugging purposes.
diff --git a/chromium/components/domain_reliability/monitor_unittest.cc b/chromium/components/domain_reliability/monitor_unittest.cc
index 6f869937837..b5c928c392c 100644
--- a/chromium/components/domain_reliability/monitor_unittest.cc
+++ b/chromium/components/domain_reliability/monitor_unittest.cc
@@ -269,10 +269,9 @@ TEST_F(DomainReliabilityMonitorTest, AddBakedInConfigs) {
++num_baked_in_configs;
// Also count the Google configs stored in abbreviated form.
- std::vector<DomainReliabilityConfig*> google_configs;
+ std::vector<std::unique_ptr<DomainReliabilityConfig>> google_configs;
GetAllGoogleConfigs(&google_configs);
size_t num_google_configs = google_configs.size();
- STLDeleteElements(&google_configs);
// The monitor should have contexts for all of the baked-in configs.
EXPECT_EQ(num_baked_in_configs + num_google_configs,
@@ -295,25 +294,78 @@ TEST_F(DomainReliabilityMonitorTest, ClearBeacons) {
// Make sure it was added.
EXPECT_EQ(1u, CountQueuedBeacons(context));
- monitor_.ClearBrowsingData(CLEAR_BEACONS);
+ monitor_.ClearBrowsingData(
+ CLEAR_BEACONS, base::Callback<bool(const GURL&)>());
// Make sure the beacon was cleared, but not the contexts.
EXPECT_EQ(1u, monitor_.contexts_size_for_testing());
EXPECT_EQ(0u, CountQueuedBeacons(context));
}
+TEST_F(DomainReliabilityMonitorTest, ClearBeaconsWithFilter) {
+ // Create two contexts, each with one beacon.
+ GURL origin1("http://example.com/");
+ GURL origin2("http://example.org/");
+
+ DomainReliabilityContext* context1 =
+ CreateAndAddContextForOrigin(origin1, false);
+ RequestInfo request = MakeRequestInfo();
+ request.url = origin1;
+ request.status =
+ net::URLRequestStatus::FromError(net::ERR_CONNECTION_RESET);
+ OnRequestLegComplete(request);
+
+ DomainReliabilityContext* context2 =
+ CreateAndAddContextForOrigin(origin2, false);
+ request = MakeRequestInfo();
+ request.url = origin2;
+ request.status =
+ net::URLRequestStatus::FromError(net::ERR_CONNECTION_RESET);
+ OnRequestLegComplete(request);
+
+ // Delete the beacons for |origin1|.
+ monitor_.ClearBrowsingData(
+ CLEAR_BEACONS,
+ base::Bind(&GURL::operator==, base::Unretained(&origin1)));
+
+ // Beacons for |context1| were cleared. Beacons for |context2| and
+ // the contexts themselves were not.
+ EXPECT_EQ(2u, monitor_.contexts_size_for_testing());
+ EXPECT_EQ(0u, CountQueuedBeacons(context1));
+ EXPECT_EQ(1u, CountQueuedBeacons(context2));
+}
+
TEST_F(DomainReliabilityMonitorTest, ClearContexts) {
CreateAndAddContext();
// Initially the monitor should have just the test context.
EXPECT_EQ(1u, monitor_.contexts_size_for_testing());
- monitor_.ClearBrowsingData(CLEAR_CONTEXTS);
+ monitor_.ClearBrowsingData(
+ CLEAR_CONTEXTS, base::Callback<bool(const GURL&)>());
// Clearing contexts should leave the monitor with none.
EXPECT_EQ(0u, monitor_.contexts_size_for_testing());
}
+TEST_F(DomainReliabilityMonitorTest, ClearContextsWithFilter) {
+ GURL origin1("http://example.com/");
+ GURL origin2("http://example.org/");
+
+ CreateAndAddContextForOrigin(origin1, false);
+ CreateAndAddContextForOrigin(origin2, false);
+
+ EXPECT_EQ(2u, monitor_.contexts_size_for_testing());
+
+ // Delete the contexts for |origin1|.
+ monitor_.ClearBrowsingData(
+ CLEAR_CONTEXTS,
+ base::Bind(&GURL::operator==, base::Unretained(&origin1)));
+
+ // Only one of the contexts should have been deleted.
+ EXPECT_EQ(1u, monitor_.contexts_size_for_testing());
+}
+
TEST_F(DomainReliabilityMonitorTest, WildcardMatchesSelf) {
DomainReliabilityContext* context =
CreateAndAddContextForOrigin(GURL("https://wildcard/"), true);
diff --git a/chromium/components/domain_reliability/quic_error_mapping.cc b/chromium/components/domain_reliability/quic_error_mapping.cc
index 494b03c4cbe..d23fc4b26b4 100644
--- a/chromium/components/domain_reliability/quic_error_mapping.cc
+++ b/chromium/components/domain_reliability/quic_error_mapping.cc
@@ -165,6 +165,8 @@ const struct QuicErrorMapping {
// values.
{ net::QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND,
"quic_crypto_message_index_not_found" },
+ // A demand for an unsupport proof type was received.
+ { net::QUIC_UNSUPPORTED_PROOF_DEMAND, "quic.unsupported_proof_demand" },
// An internal error occured in crypto processing.
{ net::QUIC_CRYPTO_INTERNAL_ERROR, "quic.crypto.internal_error" },
// A crypto handshake message specified an unsupported version.
@@ -209,6 +211,12 @@ const struct QuicErrorMapping {
// Multipath is not enabled, but a packet with multipath flag on is received.
{ net::QUIC_BAD_MULTIPATH_FLAG, "quic.bad_multipath_flag" },
+ // A path is supposed to exist but does not.
+ { net::QUIC_MULTIPATH_PATH_DOES_NOT_EXIST,
+ "quic.quic_multipath_path_does_not_exist" },
+ // A path is supposed to be active but is not.
+ { net::QUIC_MULTIPATH_PATH_NOT_ACTIVE,
+ "quic.quic_multipath_path_not_active" },
// Network change and connection migration errors.
@@ -230,13 +238,24 @@ const struct QuicErrorMapping {
// Stream frame overlaps with buffered data.
{ net::QUIC_OVERLAPPING_STREAM_DATA,
"quic.overlapping_stream_data" },
+ // Stream frames arrived too discontiguously so that stream sequencer buffer
+ // has too many gaps.
+ { net::QUIC_TOO_MANY_FRAME_GAPS,
+ "quic.too_many_frame_gaps" },
+ // Sequencer buffer get into weird state where continuing read/write
+ // will lead to crash.
+ { net::QUIC_STREAM_SEQUENCER_INVALID_STATE,
+ "quic.stream_sequencer_invalid_state" },
+ // Connection closed because of server hits max number of sessions allowed.
+ { net::QUIC_TOO_MANY_SESSIONS_ON_SERVER,
+ "quic.too_many_sessions_on_server" },
// No error. Used as bound while iterating.
{ net::QUIC_LAST_ERROR, "quic.last_error"}
};
// Must be updated any time a net::QuicErrorCode is deprecated in
-// net/quic/quic_protocol.h.
+// net/quic/core/quic_protocol.h.
const int kDeprecatedQuicErrorCount = 4;
const int kActiveQuicErrorCount =
net::QUIC_LAST_ERROR - kDeprecatedQuicErrorCount;
diff --git a/chromium/components/domain_reliability/quic_error_mapping.h b/chromium/components/domain_reliability/quic_error_mapping.h
index 7d936eabc33..4d1146bbd4b 100644
--- a/chromium/components/domain_reliability/quic_error_mapping.h
+++ b/chromium/components/domain_reliability/quic_error_mapping.h
@@ -7,7 +7,7 @@
#include <string>
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
// N.B. This file and the .cc are separate from util.h/.cc so that they can be
// independently updated by folks working on QUIC when new errors are added.
diff --git a/chromium/components/domain_reliability/scheduler.cc b/chromium/components/domain_reliability/scheduler.cc
index 6e0aa6b3d96..20bd3347a08 100644
--- a/chromium/components/domain_reliability/scheduler.cc
+++ b/chromium/components/domain_reliability/scheduler.cc
@@ -184,12 +184,11 @@ std::unique_ptr<base::Value> DomainReliabilityScheduler::GetWebUIData() const {
}
std::unique_ptr<base::ListValue> collectors_value(new base::ListValue());
- for (const auto& collector : collectors_) {
+ for (const auto* collector : collectors_) {
std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue());
value->SetInteger("failures", collector->failure_count());
value->SetInteger("next_upload",
(collector->GetReleaseTime() - now).InSeconds());
- // Using release instead of Pass because Pass can't implicitly upcast.
collectors_value->Append(std::move(value));
}
data->Set("collectors", std::move(collectors_value));
diff --git a/chromium/components/domain_reliability/service.cc b/chromium/components/domain_reliability/service.cc
index d110797cc9d..cdc91d7dc27 100644
--- a/chromium/components/domain_reliability/service.cc
+++ b/chromium/components/domain_reliability/service.cc
@@ -12,6 +12,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "components/domain_reliability/monitor.h"
#include "net/url_request/url_request_context_getter.h"
+#include "url/gurl.h"
namespace domain_reliability {
@@ -56,15 +57,18 @@ class DomainReliabilityServiceImpl : public DomainReliabilityService {
return monitor;
}
- void ClearBrowsingData(DomainReliabilityClearMode clear_mode,
- const base::Closure& callback) override {
+ void ClearBrowsingData(
+ DomainReliabilityClearMode clear_mode,
+ const base::Callback<bool(const GURL&)>& origin_filter,
+ const base::Closure& callback) override {
DCHECK(network_task_runner_.get());
network_task_runner_->PostTaskAndReply(
FROM_HERE,
base::Bind(&DomainReliabilityMonitor::ClearBrowsingData,
monitor_,
- clear_mode),
+ clear_mode,
+ base::Callback<bool(const GURL&)>(origin_filter)),
callback);
}
diff --git a/chromium/components/domain_reliability/service.h b/chromium/components/domain_reliability/service.h
index 204cc8148d7..c584aa39e26 100644
--- a/chromium/components/domain_reliability/service.h
+++ b/chromium/components/domain_reliability/service.h
@@ -16,6 +16,7 @@
#include "components/domain_reliability/domain_reliability_export.h"
#include "components/keyed_service/core/keyed_service.h"
+class GURL;
class PrefService;
namespace base {
@@ -54,8 +55,10 @@ class DOMAIN_RELIABILITY_EXPORT DomainReliabilityService
// Clears browsing data on the associated Monitor. |Init()| must have been
// called first.
- virtual void ClearBrowsingData(DomainReliabilityClearMode clear_mode,
- const base::Closure& callback) = 0;
+ virtual void ClearBrowsingData(
+ DomainReliabilityClearMode clear_mode,
+ const base::Callback<bool(const GURL&)>& origin,
+ const base::Closure& callback) = 0;
virtual void GetWebUIData(
const base::Callback<void(std::unique_ptr<base::Value>)>& callback)
diff --git a/chromium/components/domain_reliability/uploader.cc b/chromium/components/domain_reliability/uploader.cc
index 8ed2e0e3714..a3fb91d4620 100644
--- a/chromium/components/domain_reliability/uploader.cc
+++ b/chromium/components/domain_reliability/uploader.cc
@@ -4,10 +4,11 @@
#include "components/domain_reliability/uploader.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/callback.h"
#include "base/metrics/sparse_histogram.h"
-#include "base/stl_util.h"
#include "base/supports_user_data.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/domain_reliability/util.h"
@@ -60,11 +61,7 @@ class DomainReliabilityUploaderImpl
url_request_context_getter_(url_request_context_getter),
discard_uploads_(true) {}
- ~DomainReliabilityUploaderImpl() override {
- // Delete any in-flight URLFetchers.
- STLDeleteContainerPairFirstPointers(
- upload_callbacks_.begin(), upload_callbacks_.end());
- }
+ ~DomainReliabilityUploaderImpl() override {}
// DomainReliabilityUploader implementation:
void UploadReport(
@@ -83,9 +80,9 @@ class DomainReliabilityUploaderImpl
return;
}
- net::URLFetcher* fetcher =
- net::URLFetcher::Create(0, upload_url, net::URLFetcher::POST, this)
- .release();
+ std::unique_ptr<net::URLFetcher> owned_fetcher =
+ net::URLFetcher::Create(0, upload_url, net::URLFetcher::POST, this);
+ net::URLFetcher* fetcher = owned_fetcher.get();
data_use_measurement::DataUseUserData::AttachToFetcher(
fetcher, data_use_measurement::DataUseUserData::DOMAIN_RELIABILITY);
fetcher->SetRequestContext(url_request_context_getter_.get());
@@ -98,7 +95,7 @@ class DomainReliabilityUploaderImpl
UploadUserData::CreateCreateDataCallback(max_upload_depth + 1));
fetcher->Start();
- upload_callbacks_[fetcher] = callback;
+ upload_callbacks_[fetcher] = {std::move(owned_fetcher), callback};
}
void set_discard_uploads(bool discard_uploads) override {
@@ -110,7 +107,7 @@ class DomainReliabilityUploaderImpl
void OnURLFetchComplete(const net::URLFetcher* fetcher) override {
DCHECK(fetcher);
- UploadCallbackMap::iterator callback_it = upload_callbacks_.find(fetcher);
+ auto callback_it = upload_callbacks_.find(fetcher);
DCHECK(callback_it != upload_callbacks_.end());
int net_error = GetNetErrorFromURLRequestStatus(fetcher->GetStatus());
@@ -142,19 +139,19 @@ class DomainReliabilityUploaderImpl
http_response_code,
retry_after,
&result);
- callback_it->second.Run(result);
+ callback_it->second.second.Run(result);
- delete callback_it->first;
upload_callbacks_.erase(callback_it);
}
private:
using DomainReliabilityUploader::UploadCallback;
- typedef std::map<const net::URLFetcher*, UploadCallback> UploadCallbackMap;
MockableTime* time_;
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
- UploadCallbackMap upload_callbacks_;
+ std::map<const net::URLFetcher*,
+ std::pair<std::unique_ptr<net::URLFetcher>, UploadCallback>>
+ upload_callbacks_;
bool discard_uploads_;
};
diff --git a/chromium/components/domain_reliability/uploader_unittest.cc b/chromium/components/domain_reliability/uploader_unittest.cc
index 808ffc39010..4aeb6ddc024 100644
--- a/chromium/components/domain_reliability/uploader_unittest.cc
+++ b/chromium/components/domain_reliability/uploader_unittest.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <memory>
+#include <string>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
@@ -17,6 +18,7 @@
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
+#include "net/log/net_log_with_source.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_filter.h"
#include "net/url_request/url_request_interceptor.h"
@@ -52,7 +54,8 @@ class UploadMockURLRequestJob : public net::URLRequestJob {
void Start() override {
int rv = upload_stream_->Init(
base::Bind(&UploadMockURLRequestJob::OnStreamInitialized,
- base::Unretained(this)));
+ base::Unretained(this)),
+ net::NetLogWithSource());
if (rv == net::ERR_IO_PENDING)
return;
OnStreamInitialized(rv);
diff --git a/chromium/components/domain_reliability/util.cc b/chromium/components/domain_reliability/util.cc
index fbe6c617b89..6e710b33ccd 100644
--- a/chromium/components/domain_reliability/util.cc
+++ b/chromium/components/domain_reliability/util.cc
@@ -113,9 +113,9 @@ std::string GetDomainReliabilityProtocol(
case net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1:
return ssl_info_populated ? "HTTPS" : "HTTP";
case net::HttpResponseInfo::CONNECTION_INFO_DEPRECATED_SPDY2:
- case net::HttpResponseInfo::CONNECTION_INFO_SPDY3:
- case net::HttpResponseInfo::CONNECTION_INFO_HTTP2_14:
- case net::HttpResponseInfo::CONNECTION_INFO_HTTP2_15:
+ case net::HttpResponseInfo::CONNECTION_INFO_DEPRECATED_SPDY3:
+ case net::HttpResponseInfo::CONNECTION_INFO_DEPRECATED_HTTP2_14:
+ case net::HttpResponseInfo::CONNECTION_INFO_DEPRECATED_HTTP2_15:
case net::HttpResponseInfo::CONNECTION_INFO_HTTP2:
return "SPDY";
case net::HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3:
diff --git a/chromium/components/drive.gypi b/chromium/components/drive.gypi
deleted file mode 100644
index 537dc387b57..00000000000
--- a/chromium/components/drive.gypi
+++ /dev/null
@@ -1,218 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/drive:drive
- 'target_name': 'drive',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'drive_proto',
- '../base/base.gyp:base',
- '../components/components.gyp:invalidation_public',
-
- # TODO(lukasza): Remove this dependency (see DEPS file for more info).
- '../content/content.gyp:content_browser',
-
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_proto_cpp',
- '../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
- '../third_party/re2/re2.gyp:re2',
- ],
- 'sources': [
- 'drive/drive_api_util.cc',
- 'drive/drive_api_util.h',
- 'drive/drive_app_registry.cc',
- 'drive/drive_app_registry.h',
- 'drive/drive_app_registry_observer.h',
- 'drive/drive_notification_manager.cc',
- 'drive/drive_notification_manager.h',
- 'drive/drive_notification_observer.h',
- 'drive/drive_pref_names.cc',
- 'drive/drive_pref_names.h',
- 'drive/drive_uploader.cc',
- 'drive/drive_uploader.h',
- 'drive/event_logger.cc',
- 'drive/event_logger.h',
- 'drive/file_change.cc',
- 'drive/file_change.h',
- 'drive/file_errors.cc',
- 'drive/file_errors.h',
- 'drive/file_system_core_util.cc',
- 'drive/file_system_core_util.h',
- 'drive/file_system_metadata.cc',
- 'drive/file_system_metadata.h',
- 'drive/file_write_watcher.cc',
- 'drive/file_write_watcher.h',
- 'drive/job_list.cc',
- 'drive/job_list.h',
- 'drive/job_queue.cc',
- 'drive/job_queue.h',
- 'drive/job_scheduler.cc',
- 'drive/job_scheduler.h',
- 'drive/local_file_reader.cc',
- 'drive/local_file_reader.h',
- 'drive/resource_entry_conversion.cc',
- 'drive/resource_entry_conversion.h',
- 'drive/resource_metadata_storage.cc',
- 'drive/resource_metadata_storage.h',
- 'drive/service/drive_api_service.cc',
- 'drive/service/drive_api_service.h',
- 'drive/service/drive_service_interface.cc',
- 'drive/service/drive_service_interface.h',
- ],
- },
-
- {
- # GN version: //components/drive:proto
- # Protobuf compiler / generator for the Drive protocol buffer.
- 'target_name': 'drive_proto',
- 'type': 'static_library',
- 'sources': [ 'drive/drive.proto' ],
- 'variables': {
- 'proto_in_dir': 'drive',
- 'proto_out_dir': 'components/drive',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
-
- {
- # GN version: //components/drive:test_support
- 'target_name': 'drive_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'drive',
- 'drive_proto',
- '../base/base.gyp:base',
- '../content/content_shell_and_tests.gyp:test_support_content',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- ],
- 'sources': [
- "drive/service/dummy_drive_service.cc",
- "drive/service/dummy_drive_service.h",
- "drive/service/fake_drive_service.cc",
- "drive/service/fake_drive_service.h",
- "drive/service/test_util.cc",
- "drive/service/test_util.h",
- ],
- },
-
- # TODO(lukasza): drive_unittests target.
- # Currently tests are built as part of chrome/chrome_tests_unit.gypi.
- ],
-
- 'conditions': [
- ['chromeos==1', {
- 'targets': [
- {
- # GN version: //components/drive:drive_chromeos
- 'target_name': 'drive_chromeos',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'drive',
- 'drive_proto',
- '../base/base.gyp:base',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- ],
- 'sources': [
- 'drive/chromeos/change_list_loader.cc',
- 'drive/chromeos/change_list_loader.h',
- 'drive/chromeos/change_list_loader_observer.h',
- 'drive/chromeos/change_list_processor.cc',
- 'drive/chromeos/change_list_processor.h',
- 'drive/chromeos/directory_loader.cc',
- 'drive/chromeos/directory_loader.h',
- 'drive/chromeos/file_cache.cc',
- 'drive/chromeos/file_cache.h',
- 'drive/chromeos/file_system.cc',
- 'drive/chromeos/file_system.h',
- 'drive/chromeos/file_system/copy_operation.cc',
- 'drive/chromeos/file_system/copy_operation.h',
- 'drive/chromeos/file_system/create_directory_operation.cc',
- 'drive/chromeos/file_system/create_directory_operation.h',
- 'drive/chromeos/file_system/create_file_operation.cc',
- 'drive/chromeos/file_system/create_file_operation.h',
- 'drive/chromeos/file_system/download_operation.cc',
- 'drive/chromeos/file_system/download_operation.h',
- 'drive/chromeos/file_system/get_file_for_saving_operation.cc',
- 'drive/chromeos/file_system/get_file_for_saving_operation.h',
- 'drive/chromeos/file_system/move_operation.cc',
- 'drive/chromeos/file_system/move_operation.h',
- 'drive/chromeos/file_system/open_file_operation.cc',
- 'drive/chromeos/file_system/open_file_operation.h',
- 'drive/chromeos/file_system/operation_delegate.cc',
- 'drive/chromeos/file_system/operation_delegate.h',
- 'drive/chromeos/file_system/remove_operation.cc',
- 'drive/chromeos/file_system/remove_operation.h',
- 'drive/chromeos/file_system/search_operation.cc',
- 'drive/chromeos/file_system/search_operation.h',
- 'drive/chromeos/file_system/set_property_operation.cc',
- 'drive/chromeos/file_system/set_property_operation.h',
- 'drive/chromeos/file_system/touch_operation.cc',
- 'drive/chromeos/file_system/touch_operation.h',
- 'drive/chromeos/file_system/truncate_operation.cc',
- 'drive/chromeos/file_system/truncate_operation.h',
- 'drive/chromeos/file_system_interface.cc',
- 'drive/chromeos/file_system_interface.h',
- 'drive/chromeos/file_system_observer.h',
- 'drive/chromeos/remove_stale_cache_files.cc',
- 'drive/chromeos/remove_stale_cache_files.h',
- 'drive/chromeos/resource_metadata.cc',
- 'drive/chromeos/resource_metadata.h',
- 'drive/chromeos/search_metadata.cc',
- 'drive/chromeos/search_metadata.h',
- 'drive/chromeos/sync/entry_revert_performer.cc',
- 'drive/chromeos/sync/entry_revert_performer.h',
- 'drive/chromeos/sync/entry_update_performer.cc',
- 'drive/chromeos/sync/entry_update_performer.h',
- 'drive/chromeos/sync/remove_performer.cc',
- 'drive/chromeos/sync/remove_performer.h',
- 'drive/chromeos/sync_client.cc',
- 'drive/chromeos/sync_client.h',
- ],
- },
-
- {
- # GN version: //components/drive:test_support_chromeos
- 'target_name': 'drive_test_support_chromeos',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'drive',
- 'drive_chromeos',
- 'drive_proto',
- '../base/base.gyp:base',
- '../content/content_shell_and_tests.gyp:test_support_content',
- ],
- 'sources': [
- "drive/chromeos/drive_test_util.cc",
- "drive/chromeos/drive_test_util.h",
- "drive/chromeos/dummy_file_system.cc",
- "drive/chromeos/dummy_file_system.h",
- "drive/chromeos/fake_file_system.cc",
- "drive/chromeos/fake_file_system.h",
- "drive/chromeos/fake_free_disk_space_getter.cc",
- "drive/chromeos/fake_free_disk_space_getter.h",
- ]
- }
- ]
- }]
- ]
-}
diff --git a/chromium/components/drive/BUILD.gn b/chromium/components/drive/BUILD.gn
index c5c9516234d..f709a4fd5c8 100644
--- a/chromium/components/drive/BUILD.gn
+++ b/chromium/components/drive/BUILD.gn
@@ -4,7 +4,7 @@
import("//third_party/protobuf/proto_library.gni")
-source_set("drive") {
+static_library("drive") {
sources = [
"drive_api_util.cc",
"drive_api_util.h",
@@ -68,83 +68,13 @@ source_set("drive") {
]
}
-source_set("drive_chromeos") {
- sources = [
- "chromeos/change_list_loader.cc",
- "chromeos/change_list_loader.h",
- "chromeos/change_list_loader_observer.h",
- "chromeos/change_list_processor.cc",
- "chromeos/change_list_processor.h",
- "chromeos/directory_loader.cc",
- "chromeos/directory_loader.h",
- "chromeos/file_cache.cc",
- "chromeos/file_cache.h",
- "chromeos/file_system.cc",
- "chromeos/file_system.h",
- "chromeos/file_system/copy_operation.cc",
- "chromeos/file_system/copy_operation.h",
- "chromeos/file_system/create_directory_operation.cc",
- "chromeos/file_system/create_directory_operation.h",
- "chromeos/file_system/create_file_operation.cc",
- "chromeos/file_system/create_file_operation.h",
- "chromeos/file_system/download_operation.cc",
- "chromeos/file_system/download_operation.h",
- "chromeos/file_system/get_file_for_saving_operation.cc",
- "chromeos/file_system/get_file_for_saving_operation.h",
- "chromeos/file_system/move_operation.cc",
- "chromeos/file_system/move_operation.h",
- "chromeos/file_system/open_file_operation.cc",
- "chromeos/file_system/open_file_operation.h",
- "chromeos/file_system/operation_delegate.cc",
- "chromeos/file_system/operation_delegate.h",
- "chromeos/file_system/remove_operation.cc",
- "chromeos/file_system/remove_operation.h",
- "chromeos/file_system/search_operation.cc",
- "chromeos/file_system/search_operation.h",
- "chromeos/file_system/set_property_operation.cc",
- "chromeos/file_system/set_property_operation.h",
- "chromeos/file_system/touch_operation.cc",
- "chromeos/file_system/touch_operation.h",
- "chromeos/file_system/truncate_operation.cc",
- "chromeos/file_system/truncate_operation.h",
- "chromeos/file_system_interface.cc",
- "chromeos/file_system_interface.h",
- "chromeos/file_system_observer.h",
- "chromeos/remove_stale_cache_files.cc",
- "chromeos/remove_stale_cache_files.h",
- "chromeos/resource_metadata.cc",
- "chromeos/resource_metadata.h",
- "chromeos/search_metadata.cc",
- "chromeos/search_metadata.h",
- "chromeos/sync/entry_revert_performer.cc",
- "chromeos/sync/entry_revert_performer.h",
- "chromeos/sync/entry_update_performer.cc",
- "chromeos/sync/entry_update_performer.h",
- "chromeos/sync/remove_performer.cc",
- "chromeos/sync/remove_performer.h",
- "chromeos/sync_client.cc",
- "chromeos/sync_client.h",
- ]
- deps = [
- ":drive",
- "//base",
- "//base:i18n",
- "//components/prefs",
- "//google_apis:google_apis",
- "//net:net",
- ]
- public_deps = [
- ":proto",
- ]
-}
-
proto_library("proto") {
sources = [
"drive.proto",
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"service/dummy_drive_service.cc",
@@ -165,25 +95,96 @@ source_set("test_support") {
]
}
-source_set("test_support_chromeos") {
- testonly = true
- sources = [
- "chromeos/drive_test_util.cc",
- "chromeos/drive_test_util.h",
- "chromeos/dummy_file_system.cc",
- "chromeos/dummy_file_system.h",
- "chromeos/fake_file_system.cc",
- "chromeos/fake_file_system.h",
- "chromeos/fake_free_disk_space_getter.cc",
- "chromeos/fake_free_disk_space_getter.h",
- ]
- deps = [
- ":drive",
- ":drive_chromeos",
- ":proto",
- "//base",
- "//components/prefs:test_support",
- "//content/test:test_support",
- "//google_apis:test_support",
- ]
+if (is_chromeos) {
+ source_set("drive_chromeos") {
+ sources = [
+ "chromeos/change_list_loader.cc",
+ "chromeos/change_list_loader.h",
+ "chromeos/change_list_loader_observer.h",
+ "chromeos/change_list_processor.cc",
+ "chromeos/change_list_processor.h",
+ "chromeos/directory_loader.cc",
+ "chromeos/directory_loader.h",
+ "chromeos/file_cache.cc",
+ "chromeos/file_cache.h",
+ "chromeos/file_system.cc",
+ "chromeos/file_system.h",
+ "chromeos/file_system/copy_operation.cc",
+ "chromeos/file_system/copy_operation.h",
+ "chromeos/file_system/create_directory_operation.cc",
+ "chromeos/file_system/create_directory_operation.h",
+ "chromeos/file_system/create_file_operation.cc",
+ "chromeos/file_system/create_file_operation.h",
+ "chromeos/file_system/download_operation.cc",
+ "chromeos/file_system/download_operation.h",
+ "chromeos/file_system/get_file_for_saving_operation.cc",
+ "chromeos/file_system/get_file_for_saving_operation.h",
+ "chromeos/file_system/move_operation.cc",
+ "chromeos/file_system/move_operation.h",
+ "chromeos/file_system/open_file_operation.cc",
+ "chromeos/file_system/open_file_operation.h",
+ "chromeos/file_system/operation_delegate.cc",
+ "chromeos/file_system/operation_delegate.h",
+ "chromeos/file_system/remove_operation.cc",
+ "chromeos/file_system/remove_operation.h",
+ "chromeos/file_system/search_operation.cc",
+ "chromeos/file_system/search_operation.h",
+ "chromeos/file_system/set_property_operation.cc",
+ "chromeos/file_system/set_property_operation.h",
+ "chromeos/file_system/touch_operation.cc",
+ "chromeos/file_system/touch_operation.h",
+ "chromeos/file_system/truncate_operation.cc",
+ "chromeos/file_system/truncate_operation.h",
+ "chromeos/file_system_interface.cc",
+ "chromeos/file_system_interface.h",
+ "chromeos/file_system_observer.h",
+ "chromeos/remove_stale_cache_files.cc",
+ "chromeos/remove_stale_cache_files.h",
+ "chromeos/resource_metadata.cc",
+ "chromeos/resource_metadata.h",
+ "chromeos/search_metadata.cc",
+ "chromeos/search_metadata.h",
+ "chromeos/sync/entry_revert_performer.cc",
+ "chromeos/sync/entry_revert_performer.h",
+ "chromeos/sync/entry_update_performer.cc",
+ "chromeos/sync/entry_update_performer.h",
+ "chromeos/sync/remove_performer.cc",
+ "chromeos/sync/remove_performer.h",
+ "chromeos/sync_client.cc",
+ "chromeos/sync_client.h",
+ ]
+ deps = [
+ ":drive",
+ "//base",
+ "//base:i18n",
+ "//components/prefs",
+ "//google_apis:google_apis",
+ "//net:net",
+ ]
+ public_deps = [
+ ":proto",
+ ]
+ }
+ static_library("test_support_chromeos") {
+ testonly = true
+ sources = [
+ "chromeos/drive_test_util.cc",
+ "chromeos/drive_test_util.h",
+ "chromeos/dummy_file_system.cc",
+ "chromeos/dummy_file_system.h",
+ "chromeos/fake_file_system.cc",
+ "chromeos/fake_file_system.h",
+ "chromeos/fake_free_disk_space_getter.cc",
+ "chromeos/fake_free_disk_space_getter.h",
+ ]
+ deps = [
+ ":drive",
+ ":drive_chromeos",
+ ":proto",
+ "//base",
+ "//components/prefs:test_support",
+ "//content/test:test_support",
+ "//google_apis:test_support",
+ ]
+ }
}
diff --git a/chromium/components/error_page.gypi b/chromium/components/error_page.gypi
deleted file mode 100644
index de8bb3be17a..00000000000
--- a/chromium/components/error_page.gypi
+++ /dev/null
@@ -1,64 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/error_page/common
- 'target_name': 'error_page_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- '../ui/base/ui_base.gyp:ui_base',
- 'components_strings.gyp:components_strings',
- 'offline_pages',
- 'url_formatter/url_formatter.gyp:url_formatter',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'error_page/common/error_page_params.cc',
- 'error_page/common/error_page_params.h',
- 'error_page/common/error_page_switches.cc',
- 'error_page/common/error_page_switches.h',
- 'error_page/common/localized_error.cc',
- 'error_page/common/localized_error.h',
- 'error_page/common/net_error_info.cc',
- 'error_page/common/net_error_info.h',
- ],
- },
- ],
- 'conditions': [
- ['OS != "ios"', {
- 'targets': [
- {
- # GN version: //components/error_page/renderer
- 'target_name': 'error_page_renderer',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../components/components_strings.gyp:components_strings',
- '../content/content.gyp:content_common',
- '../net/net.gyp:net',
- '../third_party/WebKit/public/blink.gyp:blink',
- '../ui/base/ui_base.gyp:ui_base',
- '../url/url.gyp:url_lib',
- 'error_page_common',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'error_page/renderer/net_error_helper_core.cc',
- 'error_page/renderer/net_error_helper_core.h',
- ],
- }
- ],
- }],
- ],
-}
diff --git a/chromium/components/error_page/OWNERS b/chromium/components/error_page/OWNERS
index 44a878b5195..2b70a4c33b6 100644
--- a/chromium/components/error_page/OWNERS
+++ b/chromium/components/error_page/OWNERS
@@ -1,2 +1,6 @@
mmenke@chromium.org
juliatuttle@chromium.org
+
+# If changing network error strings, please visit go/chrome-neterror-strings
+# (Google internal) or contact edwardjung@chromium.org and rachelis@chromium.org
+per-file error_page_strings.grdp=edwardjung@chromium.org \ No newline at end of file
diff --git a/chromium/components/error_page/common/OWNERS b/chromium/components/error_page/common/OWNERS
new file mode 100644
index 00000000000..ec20b613d2a
--- /dev/null
+++ b/chromium/components/error_page/common/OWNERS
@@ -0,0 +1 @@
+per-file localized_error.cc=edwardjung@chromium.org \ No newline at end of file
diff --git a/chromium/components/error_page/common/localized_error.cc b/chromium/components/error_page/common/localized_error.cc
index 677c2599033..9d09b9277bf 100644
--- a/chromium/components/error_page/common/localized_error.cc
+++ b/chromium/components/error_page/common/localized_error.cc
@@ -12,6 +12,7 @@
#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
@@ -23,7 +24,6 @@
#include "components/error_page/common/error_page_switches.h"
#include "components/error_page/common/net_error_info.h"
#include "components/strings/grit/components_chromium_strings.h"
-#include "components/strings/grit/components_google_chrome_strings.h"
#include "components/strings/grit/components_strings.h"
#include "components/url_formatter/url_formatter.h"
#include "net/base/escape.h"
@@ -74,7 +74,6 @@ enum SHOW_BUTTONS {
struct LocalizedErrorMap {
int error_code;
- unsigned int title_resource_id;
unsigned int heading_resource_id;
// Detailed summary used when the error is in the main frame and shown on
// mouse over when the error is in a frame.
@@ -85,7 +84,6 @@ struct LocalizedErrorMap {
const LocalizedErrorMap net_error_options[] = {
{net::ERR_TIMED_OUT,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_TIMED_OUT,
SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | SUGGEST_PROXY_CONFIG |
@@ -93,7 +91,6 @@ const LocalizedErrorMap net_error_options[] = {
SHOW_BUTTON_RELOAD,
},
{net::ERR_CONNECTION_TIMED_OUT,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_TIMED_OUT,
SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | SUGGEST_PROXY_CONFIG |
@@ -101,7 +98,6 @@ const LocalizedErrorMap net_error_options[] = {
SHOW_BUTTON_RELOAD,
},
{net::ERR_CONNECTION_CLOSED,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_CONNECTION_CLOSED,
SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | SUGGEST_PROXY_CONFIG |
@@ -109,7 +105,6 @@ const LocalizedErrorMap net_error_options[] = {
SHOW_BUTTON_RELOAD,
},
{net::ERR_CONNECTION_RESET,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_CONNECTION_RESET,
SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | SUGGEST_PROXY_CONFIG |
@@ -117,21 +112,18 @@ const LocalizedErrorMap net_error_options[] = {
SHOW_BUTTON_RELOAD,
},
{net::ERR_CONNECTION_REFUSED,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_CONNECTION_REFUSED,
SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | SUGGEST_PROXY_CONFIG,
SHOW_BUTTON_RELOAD,
},
{net::ERR_CONNECTION_FAILED,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_CONNECTION_FAILED,
SUGGEST_DIAGNOSE_TOOL,
SHOW_BUTTON_RELOAD,
},
{net::ERR_NAME_NOT_RESOLVED,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_NAME_NOT_RESOLVED,
SUGGEST_CHECK_CONNECTION | SUGGEST_DNS_CONFIG | SUGGEST_FIREWALL_CONFIG |
@@ -139,21 +131,18 @@ const LocalizedErrorMap net_error_options[] = {
SHOW_BUTTON_RELOAD,
},
{net::ERR_ICANN_NAME_COLLISION,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_ICANN_NAME_COLLISION,
SUGGEST_NONE,
SHOW_NO_BUTTONS,
},
{net::ERR_ADDRESS_UNREACHABLE,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_ADDRESS_UNREACHABLE,
SUGGEST_DIAGNOSE_TOOL,
SHOW_BUTTON_RELOAD,
},
{net::ERR_NETWORK_ACCESS_DENIED,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NETWORK_ACCESS_DENIED,
IDS_ERRORPAGES_SUMMARY_NETWORK_ACCESS_DENIED,
SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG |
@@ -161,189 +150,156 @@ const LocalizedErrorMap net_error_options[] = {
SHOW_NO_BUTTONS,
},
{net::ERR_PROXY_CONNECTION_FAILED,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED,
IDS_ERRORPAGES_SUMMARY_PROXY_CONNECTION_FAILED,
SUGGEST_PROXY_CONFIG | SUGGEST_CONTACT_ADMINISTRATOR | SUGGEST_DIAGNOSE_TOOL,
SHOW_NO_BUTTONS,
},
{net::ERR_INTERNET_DISCONNECTED,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED,
IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED,
SUGGEST_OFFLINE_CHECKS | SUGGEST_DIAGNOSE_TOOL,
SHOW_NO_BUTTONS,
},
{net::ERR_FILE_NOT_FOUND,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_FILE_NOT_FOUND,
IDS_ERRORPAGES_SUMMARY_FILE_NOT_FOUND,
SUGGEST_NONE,
SHOW_NO_BUTTONS,
},
{net::ERR_CACHE_MISS,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_CACHE_READ_FAILURE,
IDS_ERRORPAGES_SUMMARY_CACHE_READ_FAILURE,
SUGGEST_NONE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_CACHE_READ_FAILURE,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_CACHE_READ_FAILURE,
IDS_ERRORPAGES_SUMMARY_CACHE_READ_FAILURE,
SUGGEST_NONE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_NETWORK_IO_SUSPENDED,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_CONNECTION_INTERRUPTED,
IDS_ERRORPAGES_SUMMARY_NETWORK_IO_SUSPENDED,
SUGGEST_NONE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_TOO_MANY_REDIRECTS,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
IDS_ERRORPAGES_SUMMARY_TOO_MANY_REDIRECTS,
SUGGEST_LEARNMORE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_EMPTY_RESPONSE,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
IDS_ERRORPAGES_SUMMARY_EMPTY_RESPONSE,
SUGGEST_NONE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
IDS_ERRORPAGES_SUMMARY_INVALID_RESPONSE,
SUGGEST_NONE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
IDS_ERRORPAGES_SUMMARY_INVALID_RESPONSE,
SUGGEST_NONE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
+ IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
+ IDS_ERRORPAGES_SUMMARY_INVALID_RESPONSE,
+ SUGGEST_NONE,
+ SHOW_BUTTON_RELOAD,
+ },
+ {net::ERR_INVALID_HTTP_RESPONSE,
IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
IDS_ERRORPAGES_SUMMARY_INVALID_RESPONSE,
SUGGEST_NONE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_CONTENT_LENGTH_MISMATCH,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
IDS_ERRORPAGES_SUMMARY_CONNECTION_CLOSED,
SUGGEST_NONE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_INCOMPLETE_CHUNKED_ENCODING,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
IDS_ERRORPAGES_SUMMARY_CONNECTION_CLOSED,
SUGGEST_NONE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_SSL_PROTOCOL_ERROR,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_INSECURE_CONNECTION,
IDS_ERRORPAGES_SUMMARY_INVALID_RESPONSE,
SUGGEST_DIAGNOSE_TOOL,
SHOW_BUTTON_RELOAD,
},
{net::ERR_BAD_SSL_CLIENT_AUTH_CERT,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_INSECURE_CONNECTION,
IDS_ERRORPAGES_SUMMARY_BAD_SSL_CLIENT_AUTH_CERT,
SUGGEST_CONTACT_ADMINISTRATOR,
SHOW_NO_BUTTONS,
},
{net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_INSECURE_CONNECTION,
IDS_ERRORPAGES_SUMMARY_SSL_SECURITY_ERROR,
SUGGEST_LEARNMORE,
SHOW_NO_BUTTONS,
},
{net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_INSECURE_CONNECTION,
IDS_CERT_ERROR_SUMMARY_PINNING_FAILURE_DETAILS,
SUGGEST_NONE,
SHOW_NO_BUTTONS,
},
{net::ERR_TEMPORARILY_THROTTLED,
- IDS_ERRORPAGES_TITLE_ACCESS_DENIED,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
SUGGEST_DISABLE_EXTENSION,
SHOW_NO_BUTTONS,
},
{net::ERR_BLOCKED_BY_CLIENT,
- IDS_ERRORPAGES_TITLE_BLOCKED,
IDS_ERRORPAGES_HEADING_BLOCKED,
IDS_ERRORPAGES_SUMMARY_BLOCKED_BY_EXTENSION,
SUGGEST_DISABLE_EXTENSION,
SHOW_BUTTON_RELOAD,
},
{net::ERR_NETWORK_CHANGED,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_CONNECTION_INTERRUPTED,
IDS_ERRORPAGES_SUMMARY_NETWORK_CHANGED,
SUGGEST_NONE,
SHOW_BUTTON_RELOAD,
},
{net::ERR_BLOCKED_BY_ADMINISTRATOR,
- IDS_ERRORPAGES_TITLE_BLOCKED,
IDS_ERRORPAGES_HEADING_BLOCKED,
IDS_ERRORPAGES_SUMMARY_BLOCKED_BY_ADMINISTRATOR,
SUGGEST_CONTACT_ADMINISTRATOR,
SHOW_NO_BUTTONS,
},
{net::ERR_BLOCKED_ENROLLMENT_CHECK_PENDING,
- IDS_ERRORPAGES_TITLE_BLOCKED,
IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED,
IDS_ERRORPAGES_SUMMARY_BLOCKED_ENROLLMENT_CHECK_PENDING,
SUGGEST_COMPLETE_SETUP,
SHOW_NO_BUTTONS,
},
- {net::ERR_SSL_FALLBACK_BEYOND_MINIMUM_VERSION,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
- IDS_ERRORPAGES_HEADING_INSECURE_CONNECTION,
- IDS_ERRORPAGES_SUMMARY_INVALID_RESPONSE,
- SUGGEST_NONE,
- SHOW_NO_BUTTONS,
- },
{net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_INSECURE_CONNECTION,
IDS_ERRORPAGES_SUMMARY_SSL_VERSION_OR_CIPHER_MISMATCH,
SUGGEST_UNSUPPORTED_CIPHER,
SHOW_NO_BUTTONS,
},
{net::ERR_SSL_OBSOLETE_CIPHER,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_INSECURE_CONNECTION,
IDS_ERRORPAGES_SUMMARY_SSL_VERSION_OR_CIPHER_MISMATCH,
SUGGEST_UNSUPPORTED_CIPHER,
SHOW_NO_BUTTONS,
},
- {net::ERR_TEMPORARY_BACKOFF,
- IDS_ERRORPAGES_TITLE_ACCESS_DENIED,
- IDS_ERRORPAGES_HEADING_ACCESS_DENIED,
- IDS_ERRORPAGES_SUMMARY_TEMPORARY_BACKOFF,
- SUGGEST_NONE,
- SHOW_NO_BUTTONS,
- },
{net::ERR_SSL_SERVER_CERT_BAD_FORMAT,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
IDS_ERRORPAGES_HEADING_INSECURE_CONNECTION,
IDS_ERRORPAGES_SUMMARY_SSL_SECURITY_ERROR,
SUGGEST_NONE,
@@ -356,7 +312,6 @@ const LocalizedErrorMap net_error_options[] = {
// to also appear in the array above.
const LocalizedErrorMap repost_error = {
net::ERR_CACHE_MISS,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_HTTP_POST_WARNING_TITLE,
IDS_ERRORPAGES_HTTP_POST_WARNING,
SUGGEST_REPOST_RELOAD,
@@ -364,61 +319,48 @@ const LocalizedErrorMap repost_error = {
};
const LocalizedErrorMap http_error_options[] = {
- {403,
- IDS_ERRORPAGES_TITLE_ACCESS_DENIED,
- IDS_ERRORPAGES_HEADING_ACCESS_DENIED,
- IDS_ERRORPAGES_SUMMARY_FORBIDDEN,
- SUGGEST_NONE,
- SHOW_BUTTON_RELOAD,
- },
- {410,
- IDS_ERRORPAGES_TITLE_NOT_FOUND,
- IDS_ERRORPAGES_HEADING_NOT_FOUND,
- IDS_ERRORPAGES_SUMMARY_GONE,
- SUGGEST_NONE,
- SHOW_NO_BUTTONS,
- },
-
- {500,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
- IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
- IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE_REQUEST,
- SUGGEST_NONE,
- SHOW_BUTTON_RELOAD,
- },
- {501,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
- IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
- IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE_REQUEST,
- SUGGEST_NONE,
- SHOW_NO_BUTTONS,
- },
- {502,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
- IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
- IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE_REQUEST,
- SUGGEST_NONE,
- SHOW_BUTTON_RELOAD,
- },
- {503,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
- IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
- IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE_REQUEST,
- SUGGEST_NONE,
- SHOW_BUTTON_RELOAD,
- },
- {504,
- IDS_ERRORPAGES_TITLE_LOAD_FAILED,
- IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
- IDS_ERRORPAGES_SUMMARY_GATEWAY_TIMEOUT,
- SUGGEST_NONE,
- SHOW_BUTTON_RELOAD,
- },
+ {
+ 403, IDS_ERRORPAGES_HEADING_ACCESS_DENIED,
+ IDS_ERRORPAGES_SUMMARY_FORBIDDEN, SUGGEST_NONE, SHOW_BUTTON_RELOAD,
+ },
+ {
+ 404, IDS_ERRORPAGES_HEADING_NOT_FOUND, IDS_ERRORPAGES_SUMMARY_NOT_FOUND,
+ SUGGEST_NONE, SHOW_BUTTON_RELOAD,
+ },
+ {
+ 410, IDS_ERRORPAGES_HEADING_NOT_FOUND, IDS_ERRORPAGES_SUMMARY_GONE,
+ SUGGEST_NONE, SHOW_NO_BUTTONS,
+ },
+
+ {
+ 500, IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
+ IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE_REQUEST, SUGGEST_NONE,
+ SHOW_BUTTON_RELOAD,
+ },
+ {
+ 501, IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
+ IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE_REQUEST, SUGGEST_NONE,
+ SHOW_NO_BUTTONS,
+ },
+ {
+ 502, IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
+ IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE_REQUEST, SUGGEST_NONE,
+ SHOW_BUTTON_RELOAD,
+ },
+ {
+ 503, IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
+ IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE_REQUEST, SUGGEST_NONE,
+ SHOW_BUTTON_RELOAD,
+ },
+ {
+ 504, IDS_ERRORPAGES_HEADING_PAGE_NOT_WORKING,
+ IDS_ERRORPAGES_SUMMARY_GATEWAY_TIMEOUT, SUGGEST_NONE,
+ SHOW_BUTTON_RELOAD,
+ },
};
const LocalizedErrorMap dns_probe_error_options[] = {
{error_page::DNS_PROBE_POSSIBLE,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_DNS_PROBE_RUNNING,
SUGGEST_DIAGNOSE_TOOL,
@@ -429,7 +371,6 @@ const LocalizedErrorMap dns_probe_error_options[] = {
// error, which might be one of several DNS-related errors.
{error_page::DNS_PROBE_STARTED,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_DNS_PROBE_RUNNING,
// Include SUGGEST_RELOAD so the More button doesn't jump when we update.
@@ -441,14 +382,12 @@ const LocalizedErrorMap dns_probe_error_options[] = {
// original error, which might be one of several DNS-related errors.
{error_page::DNS_PROBE_FINISHED_NO_INTERNET,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED,
IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED,
SUGGEST_OFFLINE_CHECKS | SUGGEST_DIAGNOSE_TOOL,
SHOW_NO_BUTTONS,
},
{error_page::DNS_PROBE_FINISHED_BAD_CONFIG,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_NAME_NOT_RESOLVED,
SUGGEST_DNS_CONFIG | SUGGEST_FIREWALL_CONFIG | SUGGEST_PROXY_CONFIG |
@@ -456,7 +395,6 @@ const LocalizedErrorMap dns_probe_error_options[] = {
SHOW_BUTTON_RELOAD,
},
{error_page::DNS_PROBE_FINISHED_NXDOMAIN,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_NAME_NOT_RESOLVED,
SUGGEST_DIAGNOSE_TOOL,
@@ -561,13 +499,13 @@ void AddSingleEntryDictionaryToList(base::ListValue* list,
const char* path,
int message_id,
bool insert_as_first_item) {
- base::DictionaryValue* suggestion_list_item = new base::DictionaryValue;
+ auto suggestion_list_item = base::MakeUnique<base::DictionaryValue>();
suggestion_list_item->SetString(path, l10n_util::GetStringUTF16(message_id));
if (insert_as_first_item) {
- list->Insert(0, suggestion_list_item);
+ list->Insert(0, std::move(suggestion_list_item));
} else {
- list->Append(suggestion_list_item);
+ list->Append(std::move(suggestion_list_item));
}
}
@@ -785,7 +723,7 @@ base::DictionaryValue* AddSuggestionDetailDictionaryToList(
suggestion_list_item->SetString("body",
l10n_util::GetStringUTF16(body_message_id));
}
- list->Append(suggestion_list_item);
+ list->Append(base::WrapUnique(suggestion_list_item));
return suggestion_list_item;
}
@@ -880,7 +818,6 @@ void LocalizedError::GetStrings(
// options with default values.
LocalizedErrorMap options = {
0,
- IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
SUGGEST_NONE,
@@ -899,7 +836,6 @@ void LocalizedError::GetStrings(
if (error_domain == net::kErrorDomain &&
error_code == net::ERR_ACCESS_DENIED &&
failed_url.scheme() == "file") {
- options.title_resource_id = IDS_ERRORPAGES_TITLE_ACCESS_DENIED;
options.heading_resource_id = IDS_ERRORPAGES_HEADING_FILE_ACCESS_DENIED;
options.summary_resource_id = IDS_ERRORPAGES_SUMMARY_FILE_ACCESS_DENIED;
options.suggestions = SUGGEST_NONE;
@@ -912,12 +848,15 @@ void LocalizedError::GetStrings(
// URLs are always LTR.
if (base::i18n::IsRTL())
base::i18n::WrapStringWithLTRFormatting(&failed_url_string);
- error_strings->SetString("title",
- l10n_util::GetStringFUTF16(options.title_resource_id, failed_url_string));
- std::string icon_class = GetIconClassForError(error_domain, error_code);
- error_strings->SetString("iconClass", icon_class);
base::string16 host_name(url_formatter::IDNToUnicode(failed_url.host()));
+ if (failed_url.SchemeIsHTTPOrHTTPS())
+ error_strings->SetString("title", host_name);
+ else
+ error_strings->SetString("title", failed_url_string);
+
+ std::string icon_class = GetIconClassForError(error_domain, error_code);
+ error_strings->SetString("iconClass", icon_class);
base::DictionaryValue* heading = new base::DictionaryValue;
heading->SetString("msg",
diff --git a/chromium/components/error_page/renderer/BUILD.gn b/chromium/components/error_page/renderer/BUILD.gn
index 1541d2c18d8..d80faa9ddc4 100644
--- a/chromium/components/error_page/renderer/BUILD.gn
+++ b/chromium/components/error_page/renderer/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("renderer") {
+static_library("renderer") {
sources = [
"net_error_helper_core.cc",
"net_error_helper_core.h",
@@ -35,7 +35,6 @@ source_set("unit_tests") {
"//base",
"//base/test:test_support",
"//components/error_page/common",
- "//components/test_runner",
"//content/public/common",
"//net",
"//testing/gtest",
diff --git a/chromium/components/error_page/renderer/DEPS b/chromium/components/error_page/renderer/DEPS
index 3d7c4cefe96..3238bc4a131 100644
--- a/chromium/components/error_page/renderer/DEPS
+++ b/chromium/components/error_page/renderer/DEPS
@@ -1,5 +1,4 @@
include_rules = [
- "+components/test_runner",
"+components/url_formatter",
"+content/public/common",
"+grit/components_strings.h",
diff --git a/chromium/components/error_page/renderer/net_error_helper_core.cc b/chromium/components/error_page/renderer/net_error_helper_core.cc
index f9e3c2b76d4..04bc65b98fa 100644
--- a/chromium/components/error_page/renderer/net_error_helper_core.cc
+++ b/chromium/components/error_page/renderer/net_error_helper_core.cc
@@ -126,12 +126,11 @@ base::TimeDelta GetAutoReloadTime(size_t reload_count) {
return base::TimeDelta::FromMilliseconds(kDelaysMs[reload_count]);
}
-// Returns whether |net_error| is a DNS-related error (and therefore whether
-// the tab helper should start a DNS probe after receiving it.)
-bool IsDnsError(const blink::WebURLError& error) {
- return error.domain.utf8() == net::kErrorDomain &&
- (error.reason == net::ERR_NAME_NOT_RESOLVED ||
- error.reason == net::ERR_NAME_RESOLUTION_FAILED);
+// Returns whether |error| is a DNS-related error (and therefore whether
+// the tab helper should start a DNS probe after receiving it).
+bool IsBlinkDnsError(const blink::WebURLError& error) {
+ return (error.domain.utf8() == net::kErrorDomain) &&
+ net::IsDnsError(error.reason);
}
GURL SanitizeURL(const GURL& url) {
@@ -173,7 +172,7 @@ bool ShouldUseFixUrlServiceForError(const blink::WebURLError& error,
*error_param = "http404";
return true;
}
- if (IsDnsError(error)) {
+ if (IsBlinkDnsError(error)) {
*error_param = "dnserror";
return true;
}
@@ -769,7 +768,7 @@ void NetErrorHelperCore::GetErrorHtmlForMainFrame(
return;
}
- if (IsDnsError(pending_error_page_info->error)) {
+ if (IsBlinkDnsError(pending_error_page_info->error)) {
// The last probe status needs to be reset if this is a DNS error. This
// means that if a DNS error page is committed but has not yet finished
// loading, a DNS probe status scheduled to be sent to it may be thrown
diff --git a/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc b/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc
index 943010daedd..666d02d9934 100644
--- a/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc
+++ b/chromium/components/error_page/renderer/net_error_helper_core_unittest.cc
@@ -24,7 +24,6 @@
#include "build/build_config.h"
#include "components/error_page/common/error_page_params.h"
#include "components/error_page/common/net_error_info.h"
-#include "components/test_runner/test_common.h"
#include "content/public/common/url_constants.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -57,8 +56,8 @@ struct NavigationCorrection {
bool is_porn;
bool is_soft_porn;
- base::Value* ToValue() const {
- base::DictionaryValue* dict = new base::DictionaryValue();
+ std::unique_ptr<base::DictionaryValue> ToValue() const {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("correctionType", correction_type);
dict->SetString("urlCorrection", url_correction);
dict->SetString("clickType", click_type);
@@ -171,7 +170,6 @@ class NetErrorHelperCoreTest : public testing::Test,
error_url_(GURL(content::kUnreachableWebDataURL)),
tracking_request_count_(0) {
SetUpCore(false, false, true);
- test_runner::EnsureBlinkInitialized();
}
~NetErrorHelperCoreTest() override {
diff --git a/chromium/components/error_page_strings.grdp b/chromium/components/error_page_strings.grdp
index ac0cad97939..a30640b3388 100644
--- a/chromium/components/error_page_strings.grdp
+++ b/chromium/components/error_page_strings.grdp
@@ -98,21 +98,6 @@
<message name="IDS_ERRORPAGES_SUGGESTION_UNSUPPORTED_CIPHER_BODY" desc="The detailed explanation body text displayed for SSL cipher and version errors.">
The client and server don't support a common SSL protocol version or cipher suite.
</message>
- <message name="IDS_ERRORPAGES_TITLE_NOT_AVAILABLE" desc="Title of the error page when we can't connect to a site.">
- <ph name="SITE">$1<ex>google.com</ex></ph> is not available
- </message>
- <message name="IDS_ERRORPAGES_TITLE_ACCESS_DENIED" desc="Title in the error page when a server returns a 403. Also suitable for similar error codes.">
- Access to <ph name="URL">$1<ex>http://www.google.com/foo/bar</ex></ph> denied.
- </message>
- <message name="IDS_ERRORPAGES_TITLE_NOT_FOUND" desc="Title of the error page when the server returns a 404 or 410.">
- <ph name="URL">$1<ex>http://www.google.com/foo/bar</ex></ph> is not found
- </message>
- <message name="IDS_ERRORPAGES_TITLE_LOAD_FAILED" desc="Title of the error page when we can't load a page.">
- <ph name="URL">$1<ex>http://some-unreliable-site.com/</ex></ph> failed to load
- </message>
- <message name="IDS_ERRORPAGES_TITLE_BLOCKED" desc="Title in the error page when a request is blocked (e.g. by an extension).">
- <ph name="URL">$1<ex>http://www.google.com/foo/bar</ex></ph> was blocked
- </message>
<message name="IDS_ERRORPAGES_HEADING_NOT_AVAILABLE" desc="Heading in the error page when we can't connect to a site.">
This site can’t be reached
</message>
@@ -270,12 +255,7 @@
This site can’t provide a secure connection
</message>
<message name="IDS_ERRORPAGES_SUMMARY_BAD_SSL_CLIENT_AUTH_CERT" desc="Summary in the error page for SSL client certificate authentication failure.">
- <ph name="HOST_NAME">&lt;strong jscontent="hostName"&gt;&lt;/strong&gt;<ex>www.whatever.com</ex></ph> didn’t accept your login certificate, or your login certificate may have expired.
- </message>
- <message name="IDS_ERRORPAGES_SUMMARY_TEMPORARY_BACKOFF" desc="Summary in the error page when we temporarily stop sending requests to a server because of a Backoff header received earlier.">
- The server hosting the webpage might be overloaded or under maintainance.
- In order to avoid generating too much traffic and making the situation worse,
- requests to this URL has been temporarily disallowed.
+ <ph name="HOST_NAME">&lt;strong jscontent="hostName"&gt;&lt;/strong&gt;<ex>www.whatever.com</ex></ph> didn’t accept your login certificate, or one may not have been provided.
</message>
<message name="IDS_ERRORPAGES_SUMMARY_BLOCKED_BY_EXTENSION" desc="Summary in the error page when an extension blocks a request.">
Requests to the server have been blocked by an extension.
diff --git a/chromium/components/exo.gypi b/chromium/components/exo.gypi
deleted file mode 100644
index 82df057acdd..00000000000
--- a/chromium/components/exo.gypi
+++ /dev/null
@@ -1,125 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/exo
- 'target_name': 'exo',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../ash/ash.gyp:ash',
- '../base/base.gyp:base',
- '../cc/cc.gyp:cc',
- '../cc/cc.gyp:cc_surfaces',
- '../device/gamepad/gamepad.gyp:device_gamepad',
- '../gpu/gpu.gyp:gpu',
- '../skia/skia.gyp:skia',
- '../ui/aura/aura.gyp:aura',
- '../ui/compositor/compositor.gyp:compositor',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/gfx.gyp:gfx_geometry',
- '../ui/gl/gl.gyp:gl',
- '../ui/views/views.gyp:views',
- '../ui/wm/wm.gyp:wm',
- ],
- 'export_dependent_settings': [
- '../ui/views/views.gyp:views',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'exo/buffer.cc',
- 'exo/buffer.h',
- 'exo/display.cc',
- 'exo/display.h',
- 'exo/gamepad.cc',
- 'exo/gamepad.h',
- 'exo/keyboard.cc',
- 'exo/keyboard.h',
- 'exo/keyboard_delegate.h',
- 'exo/notification_surface.cc',
- 'exo/notification_surface.h',
- 'exo/notification_surface_manager.h',
- 'exo/pointer.cc',
- 'exo/pointer.h',
- 'exo/pointer_delegate.h',
- 'exo/shared_memory.cc',
- 'exo/shared_memory.h',
- 'exo/shell_surface.cc',
- 'exo/shell_surface.h',
- 'exo/sub_surface.cc',
- 'exo/sub_surface.h',
- 'exo/surface.cc',
- 'exo/surface.h',
- 'exo/surface_property.h',
- 'exo/surface_delegate.h',
- 'exo/surface_observer.h',
- 'exo/touch.cc',
- 'exo/touch.h',
- 'exo/touch_delegate.h',
- ],
- },
- ],
- 'conditions': [
- [ 'OS=="linux"', {
- 'targets': [
- {
- # GN version: //components/exo:wayland
- 'target_name': 'exo_wayland',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../ipc/ipc.gyp:ipc',
- '../skia/skia.gyp:skia',
- '../third_party/wayland-protocols/wayland-protocols.gyp:alpha_compositing_protocol',
- '../third_party/wayland-protocols/wayland-protocols.gyp:gaming_input_protocol',
- '../third_party/wayland-protocols/wayland-protocols.gyp:remote_shell_protocol',
- '../third_party/wayland-protocols/wayland-protocols.gyp:secure_output_protocol',
- '../third_party/wayland-protocols/wayland-protocols.gyp:stylus_protocol',
- '../third_party/wayland-protocols/wayland-protocols.gyp:viewporter_protocol',
- '../third_party/wayland-protocols/wayland-protocols.gyp:xdg_shell_protocol',
- '../third_party/wayland-protocols/wayland-protocols.gyp:vsync_feedback_protocol',
- '../third_party/wayland/wayland.gyp:wayland_server',
- '../ui/aura/aura.gyp:aura',
- '../ui/events/events.gyp:dom_keycode_converter',
- '../ui/display/display.gyp:display',
- '../ui/events/events.gyp:events_base',
- '../ui/views/views.gyp:views',
- 'exo',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'exo/wayland/scoped_wl.cc',
- 'exo/wayland/scoped_wl.h',
- 'exo/wayland/server.cc',
- 'exo/wayland/server.h',
- ],
- 'conditions': [
- ['use_ozone==1', {
- 'dependencies': [
- '../build/linux/system.gyp:libdrm',
- '../third_party/mesa/mesa.gyp:wayland_drm_protocol',
- '../third_party/wayland-protocols/wayland-protocols.gyp:linux_dmabuf_protocol',
- ],
- }],
- ['use_xkbcommon==1', {
- 'dependencies': [
- '../build/linux/system.gyp:xkbcommon',
- ],
- 'defines': [
- 'USE_XKBCOMMON',
- ],
- }],
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/exo/BUILD.gn b/chromium/components/exo/BUILD.gn
index fc04239e014..1afaab21814 100644
--- a/chromium/components/exo/BUILD.gn
+++ b/chromium/components/exo/BUILD.gn
@@ -36,6 +36,12 @@ source_set("exo") {
"touch.cc",
"touch.h",
"touch_delegate.h",
+ "wm_helper.cc",
+ "wm_helper.h",
+ "wm_helper_ash.cc",
+ "wm_helper_ash.h",
+ "wm_helper_mus.cc",
+ "wm_helper_mus.h",
]
deps = [
@@ -46,6 +52,7 @@ source_set("exo") {
"//device/gamepad",
"//gpu",
"//gpu/command_buffer/client:gles2_interface",
+ "//services/ui/public/cpp",
"//skia",
"//ui/aura",
"//ui/compositor",
@@ -53,8 +60,13 @@ source_set("exo") {
"//ui/gfx/geometry",
"//ui/gl",
"//ui/views",
+ "//ui/views/mus",
"//ui/wm:wm",
]
+
+ if (is_chromeos) {
+ deps += [ "//chromeos" ]
+ }
}
source_set("test_support") {
@@ -68,7 +80,9 @@ source_set("test_support") {
]
deps = [
- "//ash:test_support",
+ ":exo",
+ "//ash:ash_with_aura_test_support",
+ "//ash:test_support_without_content",
"//base",
"//gpu",
"//skia",
@@ -132,16 +146,17 @@ test("exo_unittests") {
deps = [
":unit_tests",
- "//ash:test_support",
+ "//ash:ash_with_aura_test_support",
+ "//ash:test_support_without_content",
"//base",
"//base/test:test_support",
"//device/gamepad:test_helpers",
]
data_deps = [
+ "//ash/common/strings:ash_test_strings",
"//ash/resources:ash_test_resources_100_percent",
"//ash/resources:ash_test_resources_200_percent",
- "//ash/strings:ash_test_strings",
]
if (use_x11) {
diff --git a/chromium/components/exo/DEPS b/chromium/components/exo/DEPS
index fb22574625f..6eb071a69a7 100644
--- a/chromium/components/exo/DEPS
+++ b/chromium/components/exo/DEPS
@@ -1,8 +1,10 @@
include_rules = [
"+ash",
"+cc",
+ "+chromeos/audio/chromeos_sounds.h",
"+device/gamepad",
"+gpu",
+ "+services/ui/public/cpp",
"+third_party/khronos",
"+third_party/skia",
"+ui",
diff --git a/chromium/components/exo/buffer.cc b/chromium/components/exo/buffer.cc
index 03e2ddbf37e..9b1778d989d 100644
--- a/chromium/components/exo/buffer.cc
+++ b/chromium/components/exo/buffer.cc
@@ -45,6 +45,7 @@ GLenum GLInternalFormat(gfx::BufferFormat format) {
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, // DXT5
GL_ETC1_RGB8_OES, // ETC1
GL_R8_EXT, // R_8
+ GL_RG8_EXT, // RG_88
GL_RGB, // BGR_565
GL_RGBA, // RGBA_4444
GL_RGB, // RGBX_8888
@@ -52,7 +53,7 @@ GLenum GLInternalFormat(gfx::BufferFormat format) {
GL_RGB, // BGRX_8888
GL_BGRA_EXT, // BGRA_8888
GL_RGB_YCRCB_420_CHROMIUM, // YVU_420
- GL_INVALID_ENUM, // YUV_420_BIPLANAR
+ GL_RGB_YCBCR_420V_CHROMIUM, // YUV_420_BIPLANAR
GL_RGB_YCBCR_422_CHROMIUM, // UYVY_422
};
static_assert(arraysize(kGLInternalFormats) ==
@@ -91,14 +92,19 @@ void CreateGLTextureMailbox(gpu::gles2::GLES2Interface* gles2,
// Buffer::Texture
// Encapsulates the state and logic needed to bind a buffer to a GLES2 texture.
-class Buffer::Texture {
+class Buffer::Texture : public ui::ContextFactoryObserver {
public:
- explicit Texture(cc::ContextProvider* context_provider);
- Texture(cc::ContextProvider* context_provider,
+ Texture(ui::ContextFactory* context_factory,
+ cc::ContextProvider* context_provider);
+ Texture(ui::ContextFactory* context_factory,
+ cc::ContextProvider* context_provider,
gfx::GpuMemoryBuffer* gpu_memory_buffer,
unsigned texture_target,
unsigned query_type);
- ~Texture();
+ ~Texture() override;
+
+ // Overridden from ui::ContextFactoryObserver:
+ void OnLostResources() override;
// Returns true if GLES2 resources for texture have been lost.
bool IsLost();
@@ -130,11 +136,13 @@ class Buffer::Texture {
gpu::Mailbox mailbox() const { return mailbox_; }
private:
+ void DestroyResources();
void ReleaseWhenQueryResultIsAvailable(const base::Closure& callback);
void Released();
void ScheduleWaitForRelease(base::TimeDelta delay);
void WaitForRelease();
+ ui::ContextFactory* context_factory_;
scoped_refptr<cc::ContextProvider> context_provider_;
const unsigned texture_target_;
const unsigned query_type_;
@@ -151,8 +159,10 @@ class Buffer::Texture {
DISALLOW_COPY_AND_ASSIGN(Texture);
};
-Buffer::Texture::Texture(cc::ContextProvider* context_provider)
- : context_provider_(context_provider),
+Buffer::Texture::Texture(ui::ContextFactory* context_factory,
+ cc::ContextProvider* context_provider)
+ : context_factory_(context_factory),
+ context_provider_(context_provider),
texture_target_(GL_TEXTURE_2D),
query_type_(GL_COMMANDS_COMPLETED_CHROMIUM),
internalformat_(GL_RGBA),
@@ -161,13 +171,17 @@ Buffer::Texture::Texture(cc::ContextProvider* context_provider)
texture_id_ = CreateGLTexture(gles2, texture_target_);
// Generate a crypto-secure random mailbox name.
CreateGLTextureMailbox(gles2, texture_id_, texture_target_, &mailbox_);
+ // Provides a notification when |context_provider_| is lost.
+ context_factory_->AddObserver(this);
}
-Buffer::Texture::Texture(cc::ContextProvider* context_provider,
+Buffer::Texture::Texture(ui::ContextFactory* context_factory,
+ cc::ContextProvider* context_provider,
gfx::GpuMemoryBuffer* gpu_memory_buffer,
unsigned texture_target,
unsigned query_type)
- : context_provider_(context_provider),
+ : context_factory_(context_factory),
+ context_provider_(context_provider),
texture_target_(texture_target),
query_type_(query_type),
internalformat_(GLInternalFormat(gpu_memory_buffer->GetFormat())),
@@ -181,28 +195,36 @@ Buffer::Texture::Texture(cc::ContextProvider* context_provider,
gles2->GenQueriesEXT(1, &query_id_);
texture_id_ = CreateGLTexture(gles2, texture_target_);
+ // Provides a notification when |context_provider_| is lost.
+ context_factory_->AddObserver(this);
}
Buffer::Texture::~Texture() {
- gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
- gles2->DeleteTextures(1, &texture_id_);
- if (query_id_)
- gles2->DeleteQueriesEXT(1, &query_id_);
- if (image_id_)
- gles2->DestroyImageCHROMIUM(image_id_);
+ DestroyResources();
+ context_factory_->RemoveObserver(this);
+}
+
+void Buffer::Texture::OnLostResources() {
+ DestroyResources();
+ context_provider_ = nullptr;
}
bool Buffer::Texture::IsLost() {
- gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
- return gles2->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
+ if (context_provider_) {
+ gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
+ return gles2->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
+ }
+ return true;
}
void Buffer::Texture::Release(const base::Closure& callback,
const gpu::SyncToken& sync_token,
bool is_lost) {
- gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
- if (sync_token.HasData())
- gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
+ if (context_provider_) {
+ gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
+ if (sync_token.HasData())
+ gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
+ }
// Run callback as texture can be reused immediately after waiting for sync
// token.
@@ -210,75 +232,93 @@ void Buffer::Texture::Release(const base::Closure& callback,
}
gpu::SyncToken Buffer::Texture::BindTexImage() {
- gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
- gles2->ActiveTexture(GL_TEXTURE0);
- gles2->BindTexture(texture_target_, texture_id_);
- DCHECK_NE(image_id_, 0u);
- gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
- // Generate a crypto-secure random mailbox name if not already done.
- if (mailbox_.IsZero())
- CreateGLTextureMailbox(gles2, texture_id_, texture_target_, &mailbox_);
- // Create and return a sync token that can be used to ensure that the
- // BindTexImage2DCHROMIUM call is processed before issuing any commands
- // that will read from the texture on a different context.
- uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM();
- gles2->OrderingBarrierCHROMIUM();
gpu::SyncToken sync_token;
- gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
+ if (context_provider_) {
+ gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
+ gles2->ActiveTexture(GL_TEXTURE0);
+ gles2->BindTexture(texture_target_, texture_id_);
+ DCHECK_NE(image_id_, 0u);
+ gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
+ // Generate a crypto-secure random mailbox name if not already done.
+ if (mailbox_.IsZero())
+ CreateGLTextureMailbox(gles2, texture_id_, texture_target_, &mailbox_);
+ // Create and return a sync token that can be used to ensure that the
+ // BindTexImage2DCHROMIUM call is processed before issuing any commands
+ // that will read from the texture on a different context.
+ uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM();
+ gles2->OrderingBarrierCHROMIUM();
+ gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
+ }
return sync_token;
}
void Buffer::Texture::ReleaseTexImage(const base::Closure& callback,
const gpu::SyncToken& sync_token,
bool is_lost) {
- gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
- if (sync_token.HasData())
- gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
- gles2->ActiveTexture(GL_TEXTURE0);
- gles2->BindTexture(texture_target_, texture_id_);
- DCHECK_NE(query_id_, 0u);
- gles2->BeginQueryEXT(query_type_, query_id_);
- gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
- gles2->EndQueryEXT(query_type_);
- // Run callback when query result is available and ReleaseTexImage has been
- // handled if sync token has data and buffer has been used. If buffer was
- // never used then run the callback immediately.
- if (sync_token.HasData()) {
- ReleaseWhenQueryResultIsAvailable(callback);
- } else {
- callback.Run();
+ if (context_provider_) {
+ gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
+ if (sync_token.HasData())
+ gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
+ gles2->ActiveTexture(GL_TEXTURE0);
+ gles2->BindTexture(texture_target_, texture_id_);
+ DCHECK_NE(query_id_, 0u);
+ gles2->BeginQueryEXT(query_type_, query_id_);
+ gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
+ gles2->EndQueryEXT(query_type_);
+ // Run callback when query result is available and ReleaseTexImage has been
+ // handled if sync token has data and buffer has been used. If buffer was
+ // never used then run the callback immediately.
+ if (sync_token.HasData()) {
+ ReleaseWhenQueryResultIsAvailable(callback);
+ return;
+ }
}
+ callback.Run();
}
gpu::SyncToken Buffer::Texture::CopyTexImage(Texture* destination,
const base::Closure& callback) {
- gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
- gles2->ActiveTexture(GL_TEXTURE0);
- gles2->BindTexture(texture_target_, texture_id_);
- DCHECK_NE(image_id_, 0u);
- gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
- gles2->CopyTextureCHROMIUM(texture_id_, destination->texture_id_,
- internalformat_, GL_UNSIGNED_BYTE, false, false,
- false);
- DCHECK_NE(query_id_, 0u);
- gles2->BeginQueryEXT(query_type_, query_id_);
- gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
- gles2->EndQueryEXT(query_type_);
- // Run callback when query result is available and ReleaseTexImage has been
- // handled.
- ReleaseWhenQueryResultIsAvailable(callback);
- // Create and return a sync token that can be used to ensure that the
- // CopyTextureCHROMIUM call is processed before issuing any commands
- // that will read from the target texture on a different context.
- uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM();
- gles2->OrderingBarrierCHROMIUM();
gpu::SyncToken sync_token;
- gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
+ if (context_provider_) {
+ gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
+ gles2->ActiveTexture(GL_TEXTURE0);
+ gles2->BindTexture(texture_target_, texture_id_);
+ DCHECK_NE(image_id_, 0u);
+ gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
+ gles2->CopyTextureCHROMIUM(texture_id_, destination->texture_id_,
+ internalformat_, GL_UNSIGNED_BYTE, false, false,
+ false);
+ DCHECK_NE(query_id_, 0u);
+ gles2->BeginQueryEXT(query_type_, query_id_);
+ gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
+ gles2->EndQueryEXT(query_type_);
+ // Run callback when query result is available and ReleaseTexImage has been
+ // handled.
+ ReleaseWhenQueryResultIsAvailable(callback);
+ // Create and return a sync token that can be used to ensure that the
+ // CopyTextureCHROMIUM call is processed before issuing any commands
+ // that will read from the target texture on a different context.
+ uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM();
+ gles2->OrderingBarrierCHROMIUM();
+ gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
+ }
return sync_token;
}
+void Buffer::Texture::DestroyResources() {
+ if (context_provider_) {
+ gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
+ gles2->DeleteTextures(1, &texture_id_);
+ if (query_id_)
+ gles2->DeleteQueriesEXT(1, &query_id_);
+ if (image_id_)
+ gles2->DestroyImageCHROMIUM(image_id_);
+ }
+}
+
void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
const base::Closure& callback) {
+ DCHECK(context_provider_);
DCHECK(release_callback_.is_null());
release_callback_ = callback;
base::TimeDelta wait_for_release_delay =
@@ -321,7 +361,7 @@ void Buffer::Texture::WaitForRelease() {
base::Closure callback = base::ResetAndReturn(&release_callback_);
- {
+ if (context_provider_) {
TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
// We need to wait for the result to be available. Getting the result of
@@ -385,11 +425,11 @@ std::unique_ptr<cc::SingleReleaseCallback> Buffer::ProduceTextureMailbox(
if (texture_ && texture_->IsLost())
texture_.reset();
+ ui::ContextFactory* context_factory =
+ aura::Env::GetInstance()->context_factory();
// Note: This can fail if GPU acceleration has been disabled.
scoped_refptr<cc::ContextProvider> context_provider =
- aura::Env::GetInstance()
- ->context_factory()
- ->SharedMainThreadContextProvider();
+ context_factory->SharedMainThreadContextProvider();
if (!context_provider) {
DLOG(WARNING) << "Failed to acquire a context provider";
Release(); // Decrements the use count
@@ -400,9 +440,9 @@ std::unique_ptr<cc::SingleReleaseCallback> Buffer::ProduceTextureMailbox(
// if one doesn't already exist. The contents of this buffer are copied to
// |texture| using a call to CopyTexImage.
if (!contents_texture_) {
- contents_texture_ = base::WrapUnique(
- new Texture(context_provider.get(), gpu_memory_buffer_.get(),
- texture_target_, query_type_));
+ contents_texture_ = base::MakeUnique<Texture>(
+ context_factory, context_provider.get(), gpu_memory_buffer_.get(),
+ texture_target_, query_type_);
}
if (use_zero_copy_) {
@@ -425,8 +465,10 @@ std::unique_ptr<cc::SingleReleaseCallback> Buffer::ProduceTextureMailbox(
}
// Create a mailbox texture that we copy the buffer contents to.
- if (!texture_)
- texture_ = base::WrapUnique(new Texture(context_provider.get()));
+ if (!texture_) {
+ texture_ =
+ base::MakeUnique<Texture>(context_factory, context_provider.get());
+ }
// Copy the contents of |contents_texture| to |texture| and produce a
// texture mailbox from the result in |texture|.
diff --git a/chromium/components/exo/display.cc b/chromium/components/exo/display.cc
index 03261baf3f1..df470b28122 100644
--- a/chromium/components/exo/display.cc
+++ b/chromium/components/exo/display.cc
@@ -55,15 +55,14 @@ std::unique_ptr<SharedMemory> Display::CreateSharedMemory(
if (!base::SharedMemory::IsHandleValid(handle))
return nullptr;
- return base::WrapUnique(new SharedMemory(handle));
+ return base::MakeUnique<SharedMemory>(handle);
}
#if defined(USE_OZONE)
std::unique_ptr<Buffer> Display::CreateLinuxDMABufBuffer(
const gfx::Size& size,
gfx::BufferFormat format,
- const std::vector<int>& strides,
- const std::vector<int>& offsets,
+ const std::vector<gfx::NativePixmapPlane>& planes,
std::vector<base::ScopedFD>&& fds) {
TRACE_EVENT1("exo", "Display::CreateLinuxDMABufBuffer", "size",
size.ToString());
@@ -73,11 +72,8 @@ std::unique_ptr<Buffer> Display::CreateLinuxDMABufBuffer(
for (auto& fd : fds)
handle.native_pixmap_handle.fds.emplace_back(std::move(fd));
- DCHECK_EQ(strides.size(), offsets.size());
- for (size_t plane = 0; plane < strides.size(); ++plane) {
- handle.native_pixmap_handle.strides_and_offsets.emplace_back(
- strides[plane], offsets[plane]);
- }
+ for (auto& plane : planes)
+ handle.native_pixmap_handle.planes.push_back(plane);
std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
aura::Env::GetInstance()
@@ -94,15 +90,16 @@ std::unique_ptr<Buffer> Display::CreateLinuxDMABufBuffer(
// List of overlay formats that are known to be supported.
// TODO(reveman): Determine this at runtime.
- const gfx::BufferFormat kOverlayFormats[] = {gfx::BufferFormat::BGRX_8888};
+ const gfx::BufferFormat kOverlayFormats[] = {gfx::BufferFormat::RGBA_8888,
+ gfx::BufferFormat::RGBX_8888};
bool is_overlay_candidate =
std::find(std::begin(kOverlayFormats), std::end(kOverlayFormats),
format) != std::end(kOverlayFormats);
- return base::WrapUnique(new Buffer(
+ return base::MakeUnique<Buffer>(
std::move(gpu_memory_buffer), GL_TEXTURE_EXTERNAL_OES,
// COMMANDS_COMPLETED queries are required by native pixmaps.
- GL_COMMANDS_COMPLETED_CHROMIUM, use_zero_copy, is_overlay_candidate));
+ GL_COMMANDS_COMPLETED_CHROMIUM, use_zero_copy, is_overlay_candidate);
}
#endif
@@ -115,9 +112,9 @@ std::unique_ptr<ShellSurface> Display::CreateShellSurface(Surface* surface) {
return nullptr;
}
- return base::WrapUnique(
- new ShellSurface(surface, nullptr, gfx::Rect(), true /* activatable */,
- ash::kShellWindowId_DefaultContainer));
+ return base::MakeUnique<ShellSurface>(surface, nullptr, gfx::Rect(),
+ true /* activatable */,
+ ash::kShellWindowId_DefaultContainer);
}
std::unique_ptr<ShellSurface> Display::CreatePopupShellSurface(
@@ -146,9 +143,9 @@ std::unique_ptr<ShellSurface> Display::CreatePopupShellSurface(
->window(),
parent->GetWidget()->GetNativeWindow()->parent(), &initial_bounds);
- return base::WrapUnique(
- new ShellSurface(surface, parent, initial_bounds, false /* activatable */,
- ash::kShellWindowId_DefaultContainer));
+ return base::MakeUnique<ShellSurface>(surface, parent, initial_bounds,
+ false /* activatable */,
+ ash::kShellWindowId_DefaultContainer);
}
std::unique_ptr<ShellSurface> Display::CreateRemoteShellSurface(
@@ -162,8 +159,8 @@ std::unique_ptr<ShellSurface> Display::CreateRemoteShellSurface(
return nullptr;
}
- return base::WrapUnique(new ShellSurface(surface, nullptr, gfx::Rect(1, 1),
- true /* activatable */, container));
+ return base::MakeUnique<ShellSurface>(surface, nullptr, gfx::Rect(1, 1),
+ true /* activatable */, container);
}
std::unique_ptr<SubSurface> Display::CreateSubSurface(Surface* surface,
@@ -181,7 +178,7 @@ std::unique_ptr<SubSurface> Display::CreateSubSurface(Surface* surface,
return nullptr;
}
- return base::WrapUnique(new SubSurface(surface, parent));
+ return base::MakeUnique<SubSurface>(surface, parent);
}
std::unique_ptr<NotificationSurface> Display::CreateNotificationSurface(
diff --git a/chromium/components/exo/display.h b/chromium/components/exo/display.h
index ce590bbbaba..d4f3b3d0806 100644
--- a/chromium/components/exo/display.h
+++ b/chromium/components/exo/display.h
@@ -17,6 +17,7 @@
#include "base/files/scoped_file.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_pixmap_handle.h"
#endif
namespace gfx {
@@ -58,8 +59,7 @@ class Display {
std::unique_ptr<Buffer> CreateLinuxDMABufBuffer(
const gfx::Size& size,
gfx::BufferFormat format,
- const std::vector<int>& strides,
- const std::vector<int>& offsets,
+ const std::vector<gfx::NativePixmapPlane>& planes,
std::vector<base::ScopedFD>&& fds);
#endif
diff --git a/chromium/components/exo/display_unittest.cc b/chromium/components/exo/display_unittest.cc
index 6d6f6624cb1..694915dbf62 100644
--- a/chromium/components/exo/display_unittest.cc
+++ b/chromium/components/exo/display_unittest.cc
@@ -68,23 +68,20 @@ TEST_F(DisplayTest, DISABLED_CreateLinuxDMABufBuffer) {
gfx::BufferFormat::RGBA_8888,
gfx::BufferUsage::GPU_READ);
gfx::NativePixmapHandle native_pixmap_handle = pixmap->ExportHandle();
- std::vector<int> strides;
- std::vector<int> offsets;
+ std::vector<gfx::NativePixmapPlane> planes;
std::vector<base::ScopedFD> fds;
- strides.push_back(native_pixmap_handle.strides_and_offsets[0].first);
- offsets.push_back(native_pixmap_handle.strides_and_offsets[0].second);
+ planes.push_back(native_pixmap_handle.planes[0]);
fds.push_back(base::ScopedFD(native_pixmap_handle.fds[0].fd));
std::unique_ptr<Buffer> buffer1 = display->CreateLinuxDMABufBuffer(
- buffer_size, gfx::BufferFormat::RGBA_8888, strides, offsets,
- std::move(fds));
+ buffer_size, gfx::BufferFormat::RGBA_8888, planes, std::move(fds));
EXPECT_TRUE(buffer1);
std::vector<base::ScopedFD> invalid_fds;
invalid_fds.push_back(base::ScopedFD());
// Creating a prime buffer using an invalid fd should fail.
std::unique_ptr<Buffer> buffer2 = display->CreateLinuxDMABufBuffer(
- buffer_size, gfx::BufferFormat::RGBA_8888, strides, offsets,
+ buffer_size, gfx::BufferFormat::RGBA_8888, planes,
std::move(invalid_fds));
EXPECT_FALSE(buffer2);
}
diff --git a/chromium/components/exo/gamepad.cc b/chromium/components/exo/gamepad.cc
index b997045dd5a..876d05d809a 100644
--- a/chromium/components/exo/gamepad.cc
+++ b/chromium/components/exo/gamepad.cc
@@ -6,7 +6,6 @@
#include <cmath>
-#include "ash/shell.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
@@ -16,8 +15,8 @@
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
#include "device/gamepad/gamepad_data_fetcher.h"
-#include "device/gamepad/gamepad_platform_data_fetcher.h"
-#include "ui/aura/client/focus_client.h"
+#include "device/gamepad/gamepad_pad_state_provider.h"
+#include "device/gamepad/gamepad_platform_data_fetcher_linux.h"
#include "ui/aura/window.h"
namespace exo {
@@ -30,7 +29,7 @@ bool GamepadButtonValuesAreEqual(double a, double b) {
std::unique_ptr<device::GamepadDataFetcher> CreateGamepadPlatformDataFetcher() {
return std::unique_ptr<device::GamepadDataFetcher>(
- new device::GamepadPlatformDataFetcher());
+ new device::GamepadPlatformDataFetcherLinux());
}
// Time between gamepad polls in milliseconds.
@@ -45,7 +44,8 @@ constexpr unsigned kPollingTimeIntervalMs = 16;
// This class is reference counted to allow it to shut down safely on the
// polling thread even if the Gamepad has been destroyed on the origin thread.
class Gamepad::ThreadSafeGamepadChangeFetcher
- : public base::RefCountedThreadSafe<
+ : public device::GamepadPadStateProvider,
+ public base::RefCountedThreadSafe<
Gamepad::ThreadSafeGamepadChangeFetcher> {
public:
using ProcessGamepadChangesCallback =
@@ -74,7 +74,7 @@ class Gamepad::ThreadSafeGamepadChangeFetcher
private:
friend class base::RefCountedThreadSafe<ThreadSafeGamepadChangeFetcher>;
- virtual ~ThreadSafeGamepadChangeFetcher() {}
+ ~ThreadSafeGamepadChangeFetcher() override {}
// Enables or disables polling.
void EnablePollingOnPollingThread(bool enabled) {
@@ -84,6 +84,7 @@ class Gamepad::ThreadSafeGamepadChangeFetcher
if (is_enabled_) {
if (!fetcher_) {
fetcher_ = create_fetcher_callback_.Run();
+ InitializeDataFetcher(fetcher_.get());
DCHECK(fetcher_);
}
SchedulePollOnPollingThread();
@@ -119,7 +120,31 @@ class Gamepad::ThreadSafeGamepadChangeFetcher
DCHECK(fetcher_);
blink::WebGamepads new_state = state_;
- fetcher_->GetGamepadData(&new_state, false);
+ fetcher_->GetGamepadData(
+ false /* No hardware changed notification from the system */);
+
+ new_state.length = 0;
+ device::PadState& pad_state = pad_states_.get()[0];
+
+ // After querying the gamepad clear the state if it did not have it's active
+ // state updated but is still listed as being associated with a specific
+ // source. This indicates the gamepad is disconnected.
+ if (!pad_state.active_state &&
+ pad_state.source != device::GAMEPAD_SOURCE_NONE) {
+ ClearPadState(pad_state);
+ }
+
+ MapAndSanitizeGamepadData(&pad_state, &new_state.items[0],
+ false /* Don't sanitize gamepad data */);
+
+ // If the gamepad was active then increment the length of the WebGamepads
+ // struct to indicate it's valid, then set the pad state to inactive. If the
+ // gamepad is still actively reporting the next call to GetGamepadData will
+ // set the active state to active again.
+ if (pad_state.active_state) {
+ new_state.length++;
+ pad_state.active_state = device::GAMEPAD_INACTIVE;
+ }
if (std::max(new_state.length, state_.length) > 0) {
if (new_state.items[0].connected != state_.items[0].connected ||
@@ -181,10 +206,9 @@ Gamepad::Gamepad(GamepadDelegate* delegate,
base::Bind(&Gamepad::ProcessGamepadChanges, weak_factory_.GetWeakPtr()),
create_fetcher_callback, polling_task_runner);
- aura::client::FocusClient* focus_client =
- aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
- focus_client->AddObserver(this);
- OnWindowFocused(focus_client->GetFocusedWindow(), nullptr);
+ auto* helper = WMHelper::GetInstance();
+ helper->AddFocusObserver(this);
+ OnWindowFocused(helper->GetFocusedWindow(), nullptr);
}
Gamepad::~Gamepad() {
@@ -193,8 +217,7 @@ Gamepad::~Gamepad() {
gamepad_change_fetcher_->EnablePolling(false);
delegate_->OnGamepadDestroying(this);
- aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
- ->RemoveObserver(this);
+ WMHelper::GetInstance()->RemoveFocusObserver(this);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/components/exo/gamepad.h b/chromium/components/exo/gamepad.h
index 578a8d12fd9..f1991a1fcb0 100644
--- a/chromium/components/exo/gamepad.h
+++ b/chromium/components/exo/gamepad.h
@@ -13,6 +13,7 @@
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/exo/wm_helper.h"
#include "device/gamepad/gamepad_data_fetcher.h"
#include "ui/aura/client/focus_change_observer.h"
@@ -25,7 +26,7 @@ using CreateGamepadDataFetcherCallback =
// This class represents one or more gamepads, it uses a background thread
// for polling gamepad devices and notifies the GamepadDelegate of any
// changes.
-class Gamepad : public aura::client::FocusChangeObserver {
+class Gamepad : public WMHelper::FocusObserver {
public:
// This class will post tasks to invoke the delegate on the thread runner
// which is associated with the thread that is creating this instance.
@@ -38,7 +39,7 @@ class Gamepad : public aura::client::FocusChangeObserver {
CreateGamepadDataFetcherCallback create_fetcher_callback);
~Gamepad() override;
- // Overridden aura::client::FocusChangeObserver:
+ // Overridden WMHelper::FocusObserver:
void OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) override;
diff --git a/chromium/components/exo/gamepad_unittest.cc b/chromium/components/exo/gamepad_unittest.cc
index 98d3e0245c5..34a7e165bd8 100644
--- a/chromium/components/exo/gamepad_unittest.cc
+++ b/chromium/components/exo/gamepad_unittest.cc
@@ -4,6 +4,7 @@
#include "ash/shell.h"
#include "base/command_line.h"
+#include "base/run_loop.h"
#include "base/test/test_simple_task_runner.h"
#include "components/exo/buffer.h"
#include "components/exo/gamepad.h"
@@ -69,7 +70,7 @@ class GamepadTest : public test::ExoTestBase {
// Run one polling cycle, which will post a task to the origin task runner.
polling_task_runner_->RunPendingTasks();
// Run origin task runner to invoke delegate.
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
protected:
diff --git a/chromium/components/exo/keyboard.cc b/chromium/components/exo/keyboard.cc
index 4aba4902c16..7ccf3eef6cd 100644
--- a/chromium/components/exo/keyboard.cc
+++ b/chromium/components/exo/keyboard.cc
@@ -4,7 +4,6 @@
#include "components/exo/keyboard.h"
-#include "ash/shell.h"
#include "components/exo/keyboard_delegate.h"
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
@@ -74,20 +73,19 @@ bool ConsumedByIme(Surface* focus, const ui::KeyEvent* event) {
// Keyboard, public:
Keyboard::Keyboard(KeyboardDelegate* delegate) : delegate_(delegate) {
- ash::Shell::GetInstance()->AddPostTargetHandler(this);
- aura::client::FocusClient* focus_client =
- aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
- focus_client->AddObserver(this);
- OnWindowFocused(focus_client->GetFocusedWindow(), nullptr);
+ auto* helper = WMHelper::GetInstance();
+ helper->AddPostTargetHandler(this);
+ helper->AddFocusObserver(this);
+ OnWindowFocused(helper->GetFocusedWindow(), nullptr);
}
Keyboard::~Keyboard() {
delegate_->OnKeyboardDestroying(this);
if (focus_)
focus_->RemoveSurfaceObserver(this);
- aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
- ->RemoveObserver(this);
- ash::Shell::GetInstance()->RemovePostTargetHandler(this);
+ auto* helper = WMHelper::GetInstance();
+ helper->RemoveFocusObserver(this);
+ helper->RemovePostTargetHandler(this);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/components/exo/keyboard.h b/chromium/components/exo/keyboard.h
index 7bed17dbd1e..dd54a82cec4 100644
--- a/chromium/components/exo/keyboard.h
+++ b/chromium/components/exo/keyboard.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "components/exo/surface_observer.h"
+#include "components/exo/wm_helper.h"
#include "ui/aura/client/focus_change_observer.h"
#include "ui/events/event_handler.h"
@@ -25,7 +26,7 @@ class Surface;
// This class implements a client keyboard that represents one or more keyboard
// devices.
class Keyboard : public ui::EventHandler,
- public aura::client::FocusChangeObserver,
+ public WMHelper::FocusObserver,
public SurfaceObserver {
public:
explicit Keyboard(KeyboardDelegate* delegate);
@@ -34,7 +35,7 @@ class Keyboard : public ui::EventHandler,
// Overridden from ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
- // Overridden aura::client::FocusChangeObserver:
+ // Overridden WMHelper::FocusObserver:
void OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) override;
diff --git a/chromium/components/exo/pointer.cc b/chromium/components/exo/pointer.cc
index 485551aab87..76d52427822 100644
--- a/chromium/components/exo/pointer.cc
+++ b/chromium/components/exo/pointer.cc
@@ -4,15 +4,17 @@
#include "components/exo/pointer.h"
-#include "ash/common/display/display_info.h"
#include "ash/common/shell_window_ids.h"
#include "ash/display/display_manager.h"
-#include "ash/shell.h"
#include "components/exo/pointer_delegate.h"
#include "components/exo/pointer_stylus_delegate.h"
#include "components/exo/surface.h"
+#include "components/exo/wm_helper.h"
+#include "ui/aura/client/cursor_client.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
+#include "ui/display/manager/managed_display_info.h"
+#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/views/widget/widget.h"
@@ -42,12 +44,9 @@ Pointer::Pointer(PointerDelegate* delegate)
surface_(nullptr),
focus_(nullptr),
cursor_scale_(1.0f) {
- ash::Shell* ash_shell = ash::Shell::GetInstance();
- ash_shell->AddPreTargetHandler(this);
-
- wm::CursorManager* cursor_manager = ash_shell->cursor_manager();
- DCHECK(cursor_manager);
- cursor_manager->AddObserver(this);
+ auto* helper = WMHelper::GetInstance();
+ helper->AddPreTargetHandler(this);
+ helper->AddCursorObserver(this);
}
Pointer::~Pointer() {
@@ -63,10 +62,9 @@ Pointer::~Pointer() {
if (widget_)
widget_->CloseNow();
- ash::Shell* ash_shell = ash::Shell::GetInstance();
- DCHECK(ash_shell->cursor_manager());
- ash_shell->cursor_manager()->RemoveObserver(this);
- ash_shell->RemovePreTargetHandler(this);
+ auto* helper = WMHelper::GetInstance();
+ helper->RemoveCursorObserver(this);
+ helper->RemovePreTargetHandler(this);
}
void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
@@ -74,6 +72,9 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
if (!focus_)
return;
+ if (!widget_)
+ CreatePointerWidget();
+
// If surface is different than the current pointer surface then remove the
// current surface and add the new surface.
if (surface != surface_) {
@@ -105,7 +106,7 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
surface_->window()->Show();
// Show widget now that cursor has been defined.
- if (!widget_->IsVisible())
+ if (!widget_->IsVisible() && !is_direct_input_)
widget_->Show();
}
@@ -132,6 +133,13 @@ void Pointer::SetStylusDelegate(PointerStylusDelegate* delegate) {
void Pointer::OnMouseEvent(ui::MouseEvent* event) {
Surface* target = GetEffectiveTargetForEvent(event);
+ auto new_pointer_type = pointer_type_;
+ if ((event->flags() & ui::EF_IS_SYNTHESIZED) == 0) {
+ new_pointer_type = event->pointer_details().pointer_type;
+ if (new_pointer_type == ui::EventPointerType::POINTER_TYPE_UNKNOWN)
+ new_pointer_type = ui::EventPointerType::POINTER_TYPE_MOUSE;
+ }
+
// If target is different than the current pointer focus then we need to
// generate enter and leave events.
if (target != focus_) {
@@ -149,9 +157,10 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
delegate_->OnPointerEnter(target, event->location_f(),
event->button_flags());
location_ = event->location_f();
- // Defaulting pointer_type to POINTER_TYPE_MOUSE prevents the tool change
- // event from being fired when using a mouse.
- pointer_type_ = ui::EventPointerType::POINTER_TYPE_MOUSE;
+ if (stylus_delegate_) {
+ stylus_delegate_->OnPointerToolChange(new_pointer_type);
+ pointer_type_ = new_pointer_type;
+ }
focus_ = target;
focus_->AddSurfaceObserver(this);
@@ -159,15 +168,47 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
delegate_->OnPointerFrame();
}
- // Report changes in pointer type. We treat unknown devices as a mouse.
- auto new_pointer_type = event->pointer_details().pointer_type;
- if (new_pointer_type == ui::EventPointerType::POINTER_TYPE_UNKNOWN)
- new_pointer_type = ui::EventPointerType::POINTER_TYPE_MOUSE;
+ // Report changes in pointer type.
if (focus_ && stylus_delegate_ && new_pointer_type != pointer_type_) {
stylus_delegate_->OnPointerToolChange(new_pointer_type);
pointer_type_ = new_pointer_type;
}
+ if (focus_ && event->IsMouseEvent() && event->type() != ui::ET_MOUSE_EXITED) {
+ bool send_frame = false;
+
+ // Generate motion event if location changed. We need to check location
+ // here as mouse movement can generate both "moved" and "entered" events
+ // but OnPointerMotion should only be called if location changed since
+ // OnPointerEnter was called.
+ if (!SameLocation(event, location_)) {
+ location_ = event->location_f();
+ delegate_->OnPointerMotion(event->time_stamp(), location_);
+ send_frame = true;
+ }
+ if (stylus_delegate_ &&
+ pointer_type_ != ui::EventPointerType::POINTER_TYPE_MOUSE) {
+ constexpr float kEpsilon = std::numeric_limits<float>::epsilon();
+ gfx::Vector2dF new_tilt = gfx::Vector2dF(event->pointer_details().tilt_x,
+ event->pointer_details().tilt_y);
+ if (std::abs(new_tilt.x() - tilt_.x()) > kEpsilon ||
+ std::abs(new_tilt.y() - tilt_.y()) > kEpsilon) {
+ tilt_ = new_tilt;
+ stylus_delegate_->OnPointerTilt(event->time_stamp(), new_tilt);
+ send_frame = true;
+ }
+
+ float new_force = event->pointer_details().force;
+ if (std::abs(new_force - force_) > kEpsilon) {
+ force_ = new_force;
+ stylus_delegate_->OnPointerForce(event->time_stamp(), new_force);
+ send_frame = true;
+ }
+ }
+ if (send_frame)
+ delegate_->OnPointerFrame();
+ }
+
switch (event->type()) {
case ui::ET_MOUSE_PRESSED:
case ui::ET_MOUSE_RELEASED:
@@ -178,42 +219,6 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
delegate_->OnPointerFrame();
}
break;
- case ui::ET_MOUSE_MOVED:
- case ui::ET_MOUSE_DRAGGED:
- if (focus_) {
- bool send_frame = false;
- // Generate motion event if location changed. We need to check location
- // here as mouse movement can generate both "moved" and "entered" events
- // but OnPointerMotion should only be called if location changed since
- // OnPointerEnter was called.
- if (!SameLocation(event, location_)) {
- location_ = event->location_f();
- delegate_->OnPointerMotion(event->time_stamp(), location_);
- send_frame = true;
- }
- if (stylus_delegate_ &&
- pointer_type_ != ui::EventPointerType::POINTER_TYPE_MOUSE) {
- constexpr float kEpsilon = std::numeric_limits<float>::epsilon();
- gfx::Vector2dF new_tilt = gfx::Vector2dF(
- event->pointer_details().tilt_x, event->pointer_details().tilt_y);
- if (std::abs(new_tilt.x() - tilt_.x()) > kEpsilon ||
- std::abs(new_tilt.y() - tilt_.y()) > kEpsilon) {
- tilt_ = new_tilt;
- stylus_delegate_->OnPointerTilt(event->time_stamp(), new_tilt);
- send_frame = true;
- }
-
- float new_force = event->pointer_details().force;
- if (std::abs(new_force - force_) > kEpsilon) {
- force_ = new_force;
- stylus_delegate_->OnPointerForce(event->time_stamp(), new_force);
- send_frame = true;
- }
- }
- if (send_frame)
- delegate_->OnPointerFrame();
- }
- break;
case ui::ET_SCROLL:
if (focus_) {
ui::ScrollEvent* scroll_event = static_cast<ui::ScrollEvent*>(event);
@@ -244,6 +249,8 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
delegate_->OnPointerFrame();
}
break;
+ case ui::ET_MOUSE_MOVED:
+ case ui::ET_MOUSE_DRAGGED:
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_EXITED:
case ui::ET_MOUSE_CAPTURE_CHANGED:
@@ -253,20 +260,25 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
break;
}
+ if ((event->flags() & ui::EF_IS_SYNTHESIZED) == 0)
+ is_direct_input_ = (event->flags() & ui::EF_DIRECT_INPUT) != 0;
+
// Update cursor widget to reflect current focus and pointer location.
- if (focus_) {
+ if (focus_ && !is_direct_input_) {
if (!widget_)
CreatePointerWidget();
// Update cursor location if mouse event caused it to change.
gfx::Point mouse_location = aura::Env::GetInstance()->last_mouse_location();
- if (mouse_location != widget_->GetNativeWindow()->bounds().origin()) {
- gfx::Rect bounds = widget_->GetNativeWindow()->bounds();
+ gfx::Rect bounds = widget_->GetWindowBoundsInScreen();
+ if (mouse_location != bounds.origin()) {
bounds.set_origin(mouse_location);
- widget_->GetNativeWindow()->SetBounds(bounds);
+ widget_->SetBounds(bounds);
}
UpdateCursorScale();
+ if (!widget_->IsVisible())
+ widget_->Show();
} else {
if (widget_ && widget_->IsVisible())
widget_->Hide();
@@ -321,9 +333,8 @@ void Pointer::CreatePointerWidget() {
params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.accept_events = false;
- params.parent =
- ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
- ash::kShellWindowId_MouseCursorContainer);
+ params.parent = WMHelper::GetInstance()->GetContainer(
+ ash::kShellWindowId_MouseCursorContainer);
widget_.reset(new views::Widget);
widget_->Init(params);
widget_->GetNativeWindow()->set_owned_by_parent(false);
@@ -347,13 +358,10 @@ void Pointer::UpdateCursorScale() {
display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(
widget_->GetNativeWindow());
- float ui_scale = ash::Shell::GetInstance()
- ->display_manager()
+ float ui_scale = WMHelper::GetInstance()
->GetDisplayInfo(display.id())
.GetEffectiveUIScale();
-
- ash::Shell* ash_shell = ash::Shell::GetInstance();
- if (ash_shell->cursor_manager()->GetCursorSet() == ui::CURSOR_SET_LARGE)
+ if (WMHelper::GetInstance()->GetCursorSet() == ui::CURSOR_SET_LARGE)
ui_scale *= kLargeCursorScale;
if (ui_scale != cursor_scale_) {
diff --git a/chromium/components/exo/pointer.h b/chromium/components/exo/pointer.h
index 183ee9401e4..8cfdbab8636 100644
--- a/chromium/components/exo/pointer.h
+++ b/chromium/components/exo/pointer.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "components/exo/surface_delegate.h"
#include "components/exo/surface_observer.h"
-#include "ui/aura/client/cursor_client_observer.h"
+#include "components/exo/wm_helper.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
@@ -33,7 +33,7 @@ class Surface;
// This class implements a client pointer that represents one or more input
// devices, such as mice, which control the pointer location and pointer focus.
class Pointer : public ui::EventHandler,
- public aura::client::CursorClientObserver,
+ public WMHelper::CursorObserver,
public SurfaceDelegate,
public SurfaceObserver {
public:
@@ -54,7 +54,7 @@ class Pointer : public ui::EventHandler,
void OnMouseEvent(ui::MouseEvent* event) override;
void OnScrollEvent(ui::ScrollEvent* event) override;
- // Overridden from aura::client::CursorClientObserver:
+ // Overridden from WMHelper::CursorObserver:
void OnCursorSetChanged(ui::CursorSetType cursor_set) override;
// Overridden from SurfaceDelegate:
@@ -107,6 +107,9 @@ class Pointer : public ui::EventHandler,
// The current pointer force.
float force_;
+ // True if the pointer is controlled via direct input.
+ bool is_direct_input_ = false;
+
DISALLOW_COPY_AND_ASSIGN(Pointer);
};
diff --git a/chromium/components/exo/pointer_unittest.cc b/chromium/components/exo/pointer_unittest.cc
index 5549834bbdf..89a9b50a45f 100644
--- a/chromium/components/exo/pointer_unittest.cc
+++ b/chromium/components/exo/pointer_unittest.cc
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ash/aura/wm_window_aura.h"
#include "ash/common/shell_window_ids.h"
+#include "ash/common/wm/window_positioning_utils.h"
+#include "ash/common/wm_shell.h"
#include "ash/shell.h"
#include "components/exo/buffer.h"
#include "components/exo/pointer.h"
@@ -289,5 +292,163 @@ TEST_F(PointerTest, OnPointerScrollDiscrete) {
pointer.reset();
}
+TEST_F(PointerTest, IgnorePointerEventDuringModal) {
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(10, 10))));
+ surface->Attach(buffer.get());
+ surface->Commit();
+ gfx::Point location = surface->window()->GetBoundsInScreen().origin();
+
+ MockPointerDelegate delegate;
+ std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
+ ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+ // Create surface for modal window.
+ std::unique_ptr<Surface> surface2(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface2(
+ new ShellSurface(surface2.get(), nullptr, gfx::Rect(0, 0, 5, 5), true,
+ ash::kShellWindowId_SystemModalContainer));
+ std::unique_ptr<Buffer> buffer2(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(5, 5))));
+ surface2->Attach(buffer2.get());
+ surface2->Commit();
+ ash::wm::CenterWindow(ash::WmWindowAura::Get(surface2->window()));
+ gfx::Point location2 = surface2->window()->GetBoundsInScreen().origin();
+
+ // Make the window modal.
+ shell_surface2->SetSystemModal(true);
+ EXPECT_TRUE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+
+ EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface2.get()))
+ .WillRepeatedly(testing::Return(true));
+
+ // Check if pointer events on modal window are registered.
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerEnter(surface2.get(), gfx::PointF(), 0));
+ }
+ generator.MoveMouseTo(location2);
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1)));
+ }
+ generator.MoveMouseTo(location2 + gfx::Vector2d(1, 1));
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate,
+ OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, true));
+ EXPECT_CALL(delegate,
+ OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, false));
+ }
+ generator.ClickLeftButton();
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerScrollCancel(testing::_));
+ EXPECT_CALL(delegate,
+ OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false));
+ EXPECT_CALL(delegate, OnPointerScrollStop(testing::_));
+ }
+ generator.ScrollSequence(location2, base::TimeDelta(), 1, 1, 1, 1);
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerLeave(surface2.get()));
+ }
+ generator.MoveMouseTo(surface2->window()->GetBoundsInScreen().bottom_right());
+
+ // Check if pointer events on non-modal window are ignored.
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0))
+ .Times(0);
+ }
+ generator.MoveMouseTo(location);
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1)))
+ .Times(0);
+ }
+ generator.MoveMouseTo(location + gfx::Vector2d(1, 1));
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate,
+ OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, true))
+ .Times(0);
+ EXPECT_CALL(delegate,
+ OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, false))
+ .Times(0);
+ }
+ generator.ClickLeftButton();
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerScrollCancel(testing::_)).Times(0);
+ EXPECT_CALL(delegate,
+ OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false))
+ .Times(0);
+ EXPECT_CALL(delegate, OnPointerScrollStop(testing::_)).Times(0);
+ }
+ generator.ScrollSequence(location, base::TimeDelta(), 1, 1, 1, 1);
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerLeave(surface.get())).Times(0);
+ }
+ generator.MoveMouseTo(surface->window()->GetBoundsInScreen().bottom_right());
+
+ // Make the window non-modal.
+ shell_surface2->SetSystemModal(false);
+ EXPECT_FALSE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+
+ // Check if pointer events on non-modal window are registered.
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
+ }
+ generator.MoveMouseTo(location);
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1)));
+ }
+ generator.MoveMouseTo(location + gfx::Vector2d(1, 1));
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate,
+ OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, true));
+ EXPECT_CALL(delegate,
+ OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, false));
+ }
+ generator.ClickLeftButton();
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerScrollCancel(testing::_));
+ EXPECT_CALL(delegate,
+ OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false));
+ EXPECT_CALL(delegate, OnPointerScrollStop(testing::_));
+ }
+ generator.ScrollSequence(location, base::TimeDelta(), 1, 1, 1, 1);
+
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnPointerLeave(surface.get()));
+ }
+ generator.MoveMouseTo(surface->window()->GetBoundsInScreen().bottom_right());
+
+ EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
+ pointer.reset();
+}
+
} // namespace
} // namespace exo
diff --git a/chromium/components/exo/shared_memory.cc b/chromium/components/exo/shared_memory.cc
index 7545f6c5e89..d0b2176c36b 100644
--- a/chromium/components/exo/shared_memory.cc
+++ b/chromium/components/exo/shared_memory.cc
@@ -84,14 +84,14 @@ std::unique_ptr<Buffer> SharedMemory::CreateBuffer(const gfx::Size& size,
// buffers. Making the copy explicit allows the buffer to be reused earlier.
bool use_zero_copy = false;
- return base::WrapUnique(
- new Buffer(std::move(gpu_memory_buffer), GL_TEXTURE_2D,
- // COMMANDS_ISSUED queries are sufficient for shared memory
- // buffers as binding to texture is implemented using a call to
- // glTexImage2D and the buffer can be reused as soon as that
- // command has been issued.
- GL_COMMANDS_ISSUED_CHROMIUM, use_zero_copy,
- false /* is_overlay_candidate */));
+ return base::MakeUnique<Buffer>(
+ std::move(gpu_memory_buffer), GL_TEXTURE_2D,
+ // COMMANDS_ISSUED queries are sufficient for shared memory
+ // buffers as binding to texture is implemented using a call to
+ // glTexImage2D and the buffer can be reused as soon as that
+ // command has been issued.
+ GL_COMMANDS_ISSUED_CHROMIUM, use_zero_copy,
+ false /* is_overlay_candidate */);
}
} // namespace exo
diff --git a/chromium/components/exo/shared_memory_unittest.cc b/chromium/components/exo/shared_memory_unittest.cc
index a3f3730b0a6..567f7a375e0 100644
--- a/chromium/components/exo/shared_memory_unittest.cc
+++ b/chromium/components/exo/shared_memory_unittest.cc
@@ -24,7 +24,7 @@ std::unique_ptr<SharedMemory> CreateSharedMemory(size_t size) {
base::SharedMemoryHandle handle =
base::SharedMemory::DuplicateHandle(shared_memory->handle());
DCHECK(base::SharedMemory::IsHandleValid(handle));
- return base::WrapUnique(new SharedMemory(handle));
+ return base::MakeUnique<SharedMemory>(handle);
}
TEST_F(SharedMemoryTest, CreateBuffer) {
diff --git a/chromium/components/exo/shell_surface.cc b/chromium/components/exo/shell_surface.cc
index 6e24679fd12..2027afdc95c 100644
--- a/chromium/components/exo/shell_surface.cc
+++ b/chromium/components/exo/shell_surface.cc
@@ -4,12 +4,17 @@
#include "components/exo/shell_surface.h"
+#include <algorithm>
+
#include "ash/aura/wm_window_aura.h"
+#include "ash/common/accessibility_delegate.h"
+#include "ash/common/shelf/wm_shelf.h"
#include "ash/common/shell_window_ids.h"
+#include "ash/common/system/tray/system_tray_notifier.h"
#include "ash/common/wm/window_resizer.h"
#include "ash/common/wm/window_state.h"
#include "ash/common/wm/window_state_delegate.h"
-#include "ash/shell.h"
+#include "ash/common/wm_shell.h"
#include "ash/wm/window_state_aura.h"
#include "ash/wm/window_util.h"
#include "base/logging.h"
@@ -20,6 +25,7 @@
#include "base/trace_event/trace_event_argument.h"
#include "components/exo/surface.h"
#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/cursor_client.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_property.h"
@@ -29,11 +35,15 @@
#include "ui/gfx/path.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
+#include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/shadow.h"
#include "ui/wm/core/shadow_controller.h"
#include "ui/wm/core/shadow_types.h"
#include "ui/wm/core/window_util.h"
-#include "ui/wm/public/activation_client.h"
+
+#if defined(OS_CHROMEOS)
+#include "chromeos/audio/chromeos_sounds.h"
+#endif
DECLARE_WINDOW_PROPERTY_TYPE(std::string*)
@@ -52,9 +62,9 @@ const struct Accelerator {
void UpdateShelfStateForFullscreenChange(views::Widget* widget) {
ash::wm::WindowState* window_state =
ash::wm::GetWindowState(widget->GetNativeWindow());
- window_state->set_shelf_mode_in_fullscreen(
- ash::wm::WindowState::SHELF_AUTO_HIDE_INVISIBLE);
- ash::Shell::GetInstance()->UpdateShelfVisibility();
+ window_state->set_hide_shelf_when_fullscreen(false);
+ for (ash::WmWindow* root_window : ash::WmShell::Get()->GetAllRootWindows())
+ ash::WmShelf::ForWindow(root_window)->UpdateVisibilityState();
}
class CustomFrameView : public views::NonClientFrameView {
@@ -85,7 +95,7 @@ class CustomFrameView : public views::NonClientFrameView {
class CustomWindowTargeter : public aura::WindowTargeter {
public:
- CustomWindowTargeter() {}
+ CustomWindowTargeter(views::Widget* widget) : widget_(widget) {}
~CustomWindowTargeter() override {}
// Overridden from aura::WindowTargeter:
@@ -96,6 +106,20 @@ class CustomWindowTargeter : public aura::WindowTargeter {
return false;
gfx::Point local_point = event.location();
+
+ // If there is an underlay, test against it's bounds instead since it will
+ // be equal or larger than the surface's bounds.
+ aura::Window* shadow_underlay =
+ static_cast<ShellSurface*>(
+ widget_->widget_delegate()->GetContentsView())
+ ->shadow_underlay();
+ if (shadow_underlay) {
+ if (window->parent())
+ aura::Window::ConvertPointToTarget(window->parent(), shadow_underlay,
+ &local_point);
+ return gfx::Rect(shadow_underlay->layer()->size()).Contains(local_point);
+ }
+
if (window->parent())
aura::Window::ConvertPointToTarget(window->parent(), window,
&local_point);
@@ -104,7 +128,29 @@ class CustomWindowTargeter : public aura::WindowTargeter {
return surface->HitTestRect(gfx::Rect(local_point, gfx::Size(1, 1)));
}
+ ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
+ ui::Event* event) override {
+ aura::Window* window = static_cast<aura::Window*>(root);
+ Surface* surface = ShellSurface::GetMainSurface(window);
+
+ // Send events which are outside of the surface's bounds to the underlay.
+ aura::Window* shadow_underlay =
+ static_cast<ShellSurface*>(
+ widget_->widget_delegate()->GetContentsView())
+ ->shadow_underlay();
+ if (surface && event->IsLocatedEvent() && shadow_underlay) {
+ gfx::Point local_point = event->AsLocatedEvent()->location();
+ aura::Window::ConvertPointToTarget(window, surface->window(),
+ &local_point);
+ if (!surface->HitTestRect(gfx::Rect(local_point, gfx::Size(1, 1))))
+ return shadow_underlay;
+ }
+ return aura::WindowTargeter::FindTargetForEvent(root, event);
+ }
+
private:
+ views::Widget* const widget_;
+
DISALLOW_COPY_AND_ASSIGN(CustomWindowTargeter);
};
@@ -164,6 +210,42 @@ class ShellSurfaceWidget : public views::Widget {
DISALLOW_COPY_AND_ASSIGN(ShellSurfaceWidget);
};
+class ShadowUnderlayEventHandler : public ui::EventHandler {
+ public:
+ ShadowUnderlayEventHandler() {}
+ ~ShadowUnderlayEventHandler() override {}
+
+ // Overridden from ui::EventHandler:
+ void OnEvent(ui::Event* event) override {
+ // If the event is targeted at the underlay, it means the user has made an
+ // interaction that is outside the surface's bounds and we want to capture
+ // it (usually when in spoken feedback mode). Handle the event (to prevent
+ // behind-windows from receiving it) and play an earcon to notify the user.
+ if (event->IsLocatedEvent()) {
+#if defined(OS_CHROMEOS)
+ const ui::EventType kEarconEventTypes[] = {ui::ET_MOUSE_PRESSED,
+ ui::ET_MOUSEWHEEL,
+ ui::ET_TOUCH_PRESSED,
+ ui::ET_POINTER_DOWN,
+ ui::ET_POINTER_WHEEL_CHANGED,
+ ui::ET_GESTURE_BEGIN,
+ ui::ET_SCROLL,
+ ui::ET_SCROLL_FLING_START};
+ bool is_earcon_event_type =
+ std::find(std::begin(kEarconEventTypes), std::end(kEarconEventTypes),
+ event->type()) != std::end(kEarconEventTypes);
+ if (is_earcon_event_type)
+ ash::WmShell::Get()->accessibility_delegate()->PlayEarcon(
+ chromeos::SOUND_VOLUME_ADJUST);
+#endif
+ event->SetHandled();
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShadowUnderlayEventHandler);
+};
+
} // namespace
// Helper class used to coalesce a number of changes into one "configure"
@@ -264,7 +346,7 @@ ShellSurface::ShellSurface(Surface* surface,
initial_bounds_(initial_bounds),
activatable_(activatable),
container_(container) {
- ash::Shell::GetInstance()->activation_client()->AddObserver(this);
+ WMHelper::GetInstance()->AddActivationObserver(this);
surface_->SetSurfaceDelegate(this);
surface_->AddSurfaceObserver(this);
surface_->window()->Show();
@@ -291,7 +373,7 @@ ShellSurface::~ShellSurface() {
widget_->Hide();
widget_->CloseNow();
}
- ash::Shell::GetInstance()->activation_client()->RemoveObserver(this);
+ WMHelper::GetInstance()->RemoveActivationObserver(this);
if (parent_)
parent_->RemoveObserver(this);
if (surface_) {
@@ -300,6 +382,8 @@ ShellSurface::~ShellSurface() {
surface_->SetSurfaceDelegate(nullptr);
surface_->RemoveSurfaceObserver(this);
}
+ ash::WmShell::Get()->system_tray_notifier()->RemoveAccessibilityObserver(
+ this);
}
void ShellSurface::AcknowledgeConfigure(uint32_t serial) {
@@ -400,11 +484,11 @@ void ShellSurface::SetFullscreen(bool fullscreen) {
// state doesn't change.
ScopedConfigure scoped_configure(this, true);
widget_->SetFullscreen(fullscreen);
- UpdateShelfStateForFullscreenChange(widget_);
}
-void ShellSurface::SetPinned(bool pinned) {
- TRACE_EVENT1("exo", "ShellSurface::SetPinned", "pinned", pinned);
+void ShellSurface::SetPinned(bool pinned, bool trusted) {
+ TRACE_EVENT2("exo", "ShellSurface::SetPinned", "pinned", pinned, "trusted",
+ trusted);
if (!widget_)
CreateShellSurfaceWidget(ui::SHOW_STATE_NORMAL);
@@ -413,7 +497,7 @@ void ShellSurface::SetPinned(bool pinned) {
// state doesn't change.
ScopedConfigure scoped_configure(this, true);
if (pinned) {
- ash::wm::PinWindow(widget_->GetNativeWindow());
+ ash::wm::PinWindow(widget_->GetNativeWindow(), trusted);
} else {
// At the moment, we cannot just unpin the window state, due to ash
// implementation. Instead, we call Restore() to unpin, if it is Pinned
@@ -724,6 +808,14 @@ gfx::Size ShellSurface::GetPreferredSize() const {
}
////////////////////////////////////////////////////////////////////////////////
+// ash::AccessibilityObserver overrides:
+
+void ShellSurface::OnAccessibilityModeChanged(
+ ash::AccessibilityNotificationVisibility) {
+ UpdateShadow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
// ash::wm::WindowStateObserver overrides:
void ShellSurface::OnPreWindowStateTypeChange(
@@ -807,10 +899,9 @@ void ShellSurface::OnWindowDestroying(aura::Window* window) {
}
////////////////////////////////////////////////////////////////////////////////
-// aura::client::ActivationChangeObserver overrides:
+// WMHelper::ActivationObserver overrides:
void ShellSurface::OnWindowActivated(
- aura::client::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) {
if (!widget_)
@@ -820,6 +911,7 @@ void ShellSurface::OnWindowActivated(
lost_active == widget_->GetNativeWindow()) {
DCHECK(activatable_);
Configure();
+ UpdateShadow();
}
}
@@ -916,8 +1008,9 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) {
params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.show_state = show_state;
+ // Make shell surface a transient child if |parent_| has been set.
params.parent =
- ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), container_);
+ parent_ ? parent_ : WMHelper::GetInstance()->GetContainer(container_);
params.bounds = initial_bounds_;
bool activatable = activatable_;
// ShellSurfaces in system modal container are only activatable if input
@@ -934,7 +1027,7 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) {
aura::Window* window = widget_->GetNativeWindow();
window->SetName("ExoShellSurface");
window->AddChild(surface_->window());
- window->SetEventTargeter(base::WrapUnique(new CustomWindowTargeter));
+ window->SetEventTargeter(base::WrapUnique(new CustomWindowTargeter(widget_)));
SetApplicationId(window, &application_id_);
SetMainSurface(window, surface_);
@@ -960,10 +1053,6 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) {
widget_->set_movement_disabled(!initial_bounds_.IsEmpty());
window_state->set_ignore_keyboard_bounds_change(!initial_bounds_.IsEmpty());
- // Make shell surface a transient child if |parent_| has been set.
- if (parent_)
- wm::AddTransientChild(parent_, window);
-
// Allow Ash to manage the position of a top-level shell surfaces if show
// state is one that allows auto positioning and |initial_bounds_| has
// not been set.
@@ -984,6 +1073,9 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) {
window_state->SetDelegate(std::unique_ptr<ash::wm::WindowStateDelegate>(
new CustomWindowStateDelegate(widget_)));
+ // Receive accessibility changes to update shadow underlay.
+ ash::WmShell::Get()->system_tray_notifier()->AddAccessibilityObserver(this);
+
// Show widget next time Commit() is called.
pending_show_widget_ = true;
}
@@ -1091,7 +1183,7 @@ void ShellSurface::AttemptToStartDrag(int component) {
pending_origin_offset_ = gfx::Vector2d();
resize_component_ = pending_resize_component_;
- ash::Shell::GetInstance()->AddPreTargetHandler(this);
+ WMHelper::GetInstance()->AddPreTargetHandler(this);
widget_->GetNativeWindow()->SetCapture();
// Notify client that resizing state has changed.
@@ -1110,7 +1202,7 @@ void ShellSurface::EndDrag(bool revert) {
else
resizer_->CompleteDrag();
- ash::Shell::GetInstance()->RemovePreTargetHandler(this);
+ WMHelper::GetInstance()->RemovePreTargetHandler(this);
widget_->GetNativeWindow()->ReleaseCapture();
resizer_.reset();
@@ -1194,10 +1286,10 @@ void ShellSurface::UpdateWidgetBounds() {
gfx::Rect visible_bounds = GetVisibleBounds();
gfx::Rect new_widget_bounds = visible_bounds;
- // Avoid changing widget origin unless initial bounds were specificed and
+ // Avoid changing widget origin unless initial bounds were specified and
// widget origin is always relative to it.
if (initial_bounds_.IsEmpty())
- new_widget_bounds.set_origin(widget_->GetNativeWindow()->bounds().origin());
+ new_widget_bounds.set_origin(widget_->GetWindowBoundsInScreen().origin());
// Update widget origin using the surface origin if the current location of
// surface is being anchored to one side of the widget as a result of a
@@ -1205,9 +1297,7 @@ void ShellSurface::UpdateWidgetBounds() {
if (resize_component_ != HTCAPTION) {
gfx::Point new_widget_origin =
GetSurfaceOrigin() + visible_bounds.OffsetFromOrigin();
- aura::Window::ConvertPointToTarget(widget_->GetNativeWindow(),
- widget_->GetNativeWindow()->parent(),
- &new_widget_origin);
+ wm::ConvertPointToScreen(widget_->GetNativeWindow(), &new_widget_origin);
new_widget_bounds.set_origin(new_widget_origin);
}
@@ -1215,7 +1305,7 @@ void ShellSurface::UpdateWidgetBounds() {
// should not result in a configure request.
DCHECK(!ignore_window_bounds_changes_);
ignore_window_bounds_changes_ = true;
- if (widget_->GetNativeWindow()->bounds() != new_widget_bounds)
+ if (widget_->GetWindowBoundsInScreen() != new_widget_bounds)
widget_->SetBounds(new_widget_bounds);
ignore_window_bounds_changes_ = false;
@@ -1245,8 +1335,10 @@ void ShellSurface::UpdateShadow() {
// Always create and show the underlay, even in maximized/fullscreen.
if (!shadow_underlay_) {
shadow_underlay_ = new aura::Window(nullptr);
+ shadow_underlay_event_handler_ =
+ base::MakeUnique<ShadowUnderlayEventHandler>();
+ shadow_underlay_->SetTargetHandler(shadow_underlay_event_handler_.get());
DCHECK(shadow_underlay_->owned_by_parent());
- shadow_underlay_->set_ignore_events(true);
// Ensure the background area inside the shadow is solid black.
// Clients that provide translucent contents should not be using
// rectangular shadows as this method requires opaque contents to
@@ -1258,16 +1350,22 @@ void ShellSurface::UpdateShadow() {
window->StackChildAtBottom(shadow_underlay_);
}
+ bool underlay_capture_events = ash::WmShell::Get()
+ ->accessibility_delegate()
+ ->IsSpokenFeedbackEnabled() &&
+ widget_->IsActive();
+
float shadow_underlay_opacity = rectangular_shadow_background_opacity_;
// Put the black background layer behind the window if
- // 1) the window is in immersive fullscreen.
+ // 1) the window is in immersive fullscreen or is active with
+ // spoken feedback enabled.
// 2) the window can control the bounds of the window in fullscreen (
// thus the background can be visible).
// 3) the window has no transform (the transformed background may
// not cover the entire background, e.g. overview mode).
- if (widget_->IsFullscreen() &&
+ if ((widget_->IsFullscreen() || underlay_capture_events) &&
ash::wm::GetWindowState(window)->allow_set_bounds_in_maximized() &&
- window->layer()->transform().IsIdentity()) {
+ window->layer()->GetTargetTransform().IsIdentity()) {
gfx::Point origin;
origin -= window->bounds().origin().OffsetFromOrigin();
shadow_bounds.set_origin(origin);
diff --git a/chromium/components/exo/shell_surface.h b/chromium/components/exo/shell_surface.h
index 1f8ee393522..54a5081659e 100644
--- a/chromium/components/exo/shell_surface.h
+++ b/chromium/components/exo/shell_surface.h
@@ -9,18 +9,19 @@
#include <memory>
#include <string>
+#include "ash/common/system/accessibility_observer.h"
#include "ash/common/wm/window_state_observer.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "components/exo/surface_delegate.h"
#include "components/exo/surface_observer.h"
+#include "components/exo/wm_helper.h"
#include "ui/aura/window_observer.h"
#include "ui/base/hit_test.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/views/widget/widget_delegate.h"
-#include "ui/wm/public/activation_change_observer.h"
namespace ash {
class WindowResizer;
@@ -42,9 +43,10 @@ class ShellSurface : public SurfaceDelegate,
public SurfaceObserver,
public views::WidgetDelegate,
public views::View,
+ public ash::AccessibilityObserver,
public ash::wm::WindowStateObserver,
public aura::WindowObserver,
- public aura::client::ActivationChangeObserver {
+ public WMHelper::ActivationObserver {
public:
ShellSurface(Surface* surface,
ShellSurface* parent,
@@ -112,8 +114,8 @@ class ShellSurface : public SurfaceDelegate,
// Set fullscreen state for shell surface.
void SetFullscreen(bool fullscreen);
- // Pins the shell surface.
- void SetPinned(bool pinned);
+ // Pins the shell surface. |trusted| flag is ignored when |pinned| is false.
+ void SetPinned(bool pinned, bool trusted);
// Set title for surface.
void SetTitle(const base::string16& title);
@@ -194,6 +196,10 @@ class ShellSurface : public SurfaceDelegate,
// Overridden from views::View:
gfx::Size GetPreferredSize() const override;
+ // Overridden from ash::AccessibilityObserver:
+ void OnAccessibilityModeChanged(
+ ash::AccessibilityNotificationVisibility notify) override;
+
// Overridden from ash::wm::WindowStateObserver:
void OnPreWindowStateTypeChange(ash::wm::WindowState* window_state,
ash::wm::WindowStateType old_type) override;
@@ -206,9 +212,8 @@ class ShellSurface : public SurfaceDelegate,
const gfx::Rect& new_bounds) override;
void OnWindowDestroying(aura::Window* window) override;
- // Overridden from aura::client::ActivationChangeObserver:
+ // Overridden from WMHelper::ActivationObserver:
void OnWindowActivated(
- aura::client::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) override;
@@ -219,9 +224,7 @@ class ShellSurface : public SurfaceDelegate,
// Overridden from ui::AcceleratorTarget:
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
- const aura::Window* shadow_underlay_for_test() const {
- return shadow_underlay_;
- }
+ aura::Window* shadow_underlay() { return shadow_underlay_; }
private:
class ScopedConfigure;
@@ -292,6 +295,7 @@ class ShellSurface : public SurfaceDelegate,
int pending_resize_component_ = HTCAPTION;
aura::Window* shadow_overlay_ = nullptr;
aura::Window* shadow_underlay_ = nullptr;
+ std::unique_ptr<ui::EventHandler> shadow_underlay_event_handler_;
gfx::Rect shadow_content_bounds_;
std::deque<Config> pending_configs_;
std::unique_ptr<ash::WindowResizer> resizer_;
diff --git a/chromium/components/exo/shell_surface_unittest.cc b/chromium/components/exo/shell_surface_unittest.cc
index cfeffaaeec4..38d221fc4ca 100644
--- a/chromium/components/exo/shell_surface_unittest.cc
+++ b/chromium/components/exo/shell_surface_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "ash/aura/wm_window_aura.h"
+#include "ash/common/accessibility_delegate.h"
#include "ash/common/shell_window_ids.h"
#include "ash/common/wm/window_state.h"
#include "ash/common/wm/wm_event.h"
@@ -20,9 +21,11 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_targeter.h"
#include "ui/base/hit_test.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
+#include "ui/events/base_event_utils.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/shadow.h"
#include "ui/wm/core/shadow_controller.h"
@@ -167,12 +170,22 @@ TEST_F(ShellSurfaceTest, SetPinned) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
- shell_surface->SetPinned(true);
+ shell_surface->SetPinned(true, /* trusted */ true);
EXPECT_TRUE(
ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
->IsPinned());
- shell_surface->SetPinned(false);
+ shell_surface->SetPinned(false, /* trusted */ true);
+ EXPECT_FALSE(
+ ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
+ ->IsPinned());
+
+ shell_surface->SetPinned(true, /* trusted */ false);
+ EXPECT_TRUE(
+ ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
+ ->IsPinned());
+
+ shell_surface->SetPinned(false, /* trusted */ false);
EXPECT_FALSE(
ash::wm::GetWindowState(shell_surface->GetWidget()->GetNativeWindow())
->IsPinned());
@@ -600,8 +613,8 @@ TEST_F(ShellSurfaceTest, ShadowStartMaximized) {
EXPECT_FALSE(wm::ShadowController::GetShadowForWindow(window));
// Underlay should be created even without shadow.
- ASSERT_TRUE(shell_surface->shadow_underlay_for_test());
- EXPECT_TRUE(shell_surface->shadow_underlay_for_test()->IsVisible());
+ ASSERT_TRUE(shell_surface->shadow_underlay());
+ EXPECT_TRUE(shell_surface->shadow_underlay()->IsVisible());
// Restore the window and make sure the shadow is created, visible and
// has the latest bounds.
@@ -661,7 +674,7 @@ TEST_F(ShellSurfaceTest, ImmersiveFullscreenBackground) {
gfx::Rect shadow_bounds(10, 10, 100, 100);
shell_surface->SetRectangularShadow(shadow_bounds);
surface->Commit();
- ASSERT_EQ(shadow_bounds, shell_surface->shadow_underlay_for_test()->bounds());
+ ASSERT_EQ(shadow_bounds, shell_surface->shadow_underlay()->bounds());
ash::wm::WMEvent event(ash::wm::WM_EVENT_TOGGLE_FULLSCREEN);
ash::WmWindow* window =
@@ -671,16 +684,90 @@ TEST_F(ShellSurfaceTest, ImmersiveFullscreenBackground) {
window->GetWindowState()->OnWMEvent(&event);
EXPECT_EQ(display::Screen::GetScreen()->GetPrimaryDisplay().bounds(),
- shell_surface->shadow_underlay_for_test()->bounds());
- EXPECT_TRUE(shell_surface->shadow_underlay_for_test()->IsVisible());
- EXPECT_EQ(1.f, shell_surface->shadow_underlay_for_test()->layer()->opacity());
+ shell_surface->shadow_underlay()->bounds());
+ EXPECT_TRUE(shell_surface->shadow_underlay()->IsVisible());
+ EXPECT_EQ(1.f, shell_surface->shadow_underlay()->layer()->opacity());
EXPECT_NE(shell_surface->GetWidget()->GetWindowBoundsInScreen(),
- shell_surface->shadow_underlay_for_test()->bounds());
+ shell_surface->shadow_underlay()->bounds());
// Leave fullscreen mode. Shadow underlay is restored.
window->GetWindowState()->OnWMEvent(&event);
- EXPECT_TRUE(shell_surface->shadow_underlay_for_test()->IsVisible());
- EXPECT_EQ(shadow_bounds, shell_surface->shadow_underlay_for_test()->bounds());
+ EXPECT_TRUE(shell_surface->shadow_underlay()->IsVisible());
+ EXPECT_EQ(shadow_bounds, shell_surface->shadow_underlay()->bounds());
+}
+
+TEST_F(ShellSurfaceTest, SpokenFeedbackFullscreenBackground) {
+ gfx::Size buffer_size(256, 256);
+ Buffer buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ Surface surface;
+ ShellSurface shell_surface(&surface, nullptr, gfx::Rect(640, 480), true,
+ ash::kShellWindowId_DefaultContainer);
+
+ surface.Attach(&buffer);
+
+ gfx::Rect shadow_bounds(10, 10, 100, 100);
+ shell_surface.SetRectangularShadow(shadow_bounds);
+ surface.Commit();
+ ASSERT_EQ(shadow_bounds, shell_surface.shadow_underlay()->bounds());
+
+ aura::Window* shell_window = shell_surface.GetWidget()->GetNativeWindow();
+ aura::WindowTargeter* targeter = static_cast<aura::WindowTargeter*>(
+ static_cast<ui::EventTarget*>(shell_window)->GetEventTargeter());
+
+ gfx::Point pt(300, 300);
+ ui::MouseEvent ev_out(ui::ET_MOUSE_PRESSED, pt, pt, ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+ gfx::Point pt2(250, 250);
+ ui::MouseEvent ev_in(ui::ET_MOUSE_PRESSED, pt2, pt2, ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+
+ EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(shell_window, ev_out));
+
+ // Enable spoken feedback.
+ ash::WmShell::Get()->accessibility_delegate()->ToggleSpokenFeedback(
+ ash::A11Y_NOTIFICATION_NONE);
+ shell_surface.OnAccessibilityModeChanged(ash::A11Y_NOTIFICATION_NONE);
+
+ EXPECT_EQ(display::Screen::GetScreen()->GetPrimaryDisplay().bounds(),
+ shell_surface.shadow_underlay()->bounds());
+ EXPECT_TRUE(shell_surface.shadow_underlay()->IsVisible());
+ EXPECT_NE(shell_surface.GetWidget()->GetWindowBoundsInScreen(),
+ shell_surface.shadow_underlay()->bounds());
+
+ // Test event capture
+ EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(shell_window, ev_out));
+ EXPECT_EQ(shell_surface.shadow_underlay(),
+ static_cast<ui::EventTargeter*>(targeter)->FindTargetForEvent(
+ shell_window, &ev_out));
+ EXPECT_NE(shell_surface.shadow_underlay(),
+ static_cast<ui::EventTargeter*>(targeter)->FindTargetForEvent(
+ shell_window, &ev_in));
+
+ // Create a new surface
+ Buffer buffer2(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ Surface surface2;
+ ShellSurface shell_surface2(&surface2, nullptr, gfx::Rect(640, 480), true,
+ ash::kShellWindowId_DefaultContainer);
+ surface2.Attach(&buffer2);
+ shell_surface2.SetRectangularShadow(shadow_bounds);
+ surface2.Commit();
+
+ // spoken-feedback was already on, so underlay should fill screen
+ EXPECT_EQ(display::Screen::GetScreen()->GetPrimaryDisplay().bounds(),
+ shell_surface2.shadow_underlay()->bounds());
+
+ // De-activated shell-surface should NOT have fullscreen underlay
+ EXPECT_EQ(shadow_bounds, shell_surface.shadow_underlay()->bounds());
+
+ // Disable spoken feedback. Shadow underlay is restored.
+ ash::WmShell::Get()->accessibility_delegate()->ToggleSpokenFeedback(
+ ash::A11Y_NOTIFICATION_NONE);
+ shell_surface.OnAccessibilityModeChanged(ash::A11Y_NOTIFICATION_NONE);
+ shell_surface2.OnAccessibilityModeChanged(ash::A11Y_NOTIFICATION_NONE);
+
+ EXPECT_TRUE(shell_surface.shadow_underlay()->IsVisible());
+ EXPECT_EQ(shadow_bounds, shell_surface.shadow_underlay()->bounds());
+ EXPECT_EQ(shadow_bounds, shell_surface2.shadow_underlay()->bounds());
}
} // namespace
diff --git a/chromium/components/exo/sub_surface_unittest.cc b/chromium/components/exo/sub_surface_unittest.cc
index 2cd92ffb640..1132dec0b18 100644
--- a/chromium/components/exo/sub_surface_unittest.cc
+++ b/chromium/components/exo/sub_surface_unittest.cc
@@ -40,7 +40,7 @@ TEST_F(SubSurfaceTest, SetPosition) {
// Create and commit a new sub-surface using the same surface.
sub_surface.reset();
- sub_surface = base::WrapUnique(new SubSurface(surface.get(), parent.get()));
+ sub_surface = base::MakeUnique<SubSurface>(surface.get(), parent.get());
parent->Commit();
// Initial position should be reset to origin.
diff --git a/chromium/components/exo/surface.cc b/chromium/components/exo/surface.cc
index e2f81215bb6..26ebf01528a 100644
--- a/chromium/components/exo/surface.cc
+++ b/chromium/components/exo/surface.cc
@@ -145,7 +145,7 @@ void SatisfyCallback(cc::SurfaceManager* manager,
const cc::SurfaceSequence& sequence) {
std::vector<uint32_t> sequences;
sequences.push_back(sequence.sequence);
- manager->DidSatisfySequences(sequence.id_namespace, &sequences);
+ manager->DidSatisfySequences(sequence.frame_sink_id, &sequences);
}
void RequireCallback(cc::SurfaceManager* manager,
@@ -180,7 +180,7 @@ void SurfaceFactoryOwner::ReturnResources(
}
}
-void SurfaceFactoryOwner::WillDrawSurface(const cc::SurfaceId& id,
+void SurfaceFactoryOwner::WillDrawSurface(const cc::LocalFrameId& id,
const gfx::Rect& damage_rect) {
if (surface_)
surface_->WillDraw(id);
@@ -192,7 +192,11 @@ void SurfaceFactoryOwner::SetBeginFrameSource(
////////////////////////////////////////////////////////////////////////////////
// SurfaceFactoryOwner, private:
-SurfaceFactoryOwner::~SurfaceFactoryOwner() {}
+SurfaceFactoryOwner::~SurfaceFactoryOwner() {
+ if (surface_factory_->manager()) {
+ surface_factory_->manager()->InvalidateFrameSinkId(frame_sink_id_);
+ }
+}
////////////////////////////////////////////////////////////////////////////////
// Surface, public:
@@ -206,14 +210,15 @@ Surface::Surface()
window_->SetName("ExoSurface");
window_->SetProperty(kSurfaceKey, this);
window_->Init(ui::LAYER_SOLID_COLOR);
- window_->set_layer_owner_delegate(this);
window_->SetEventTargeter(base::WrapUnique(new CustomWindowTargeter));
window_->set_owned_by_parent(false);
factory_owner_->surface_ = this;
- factory_owner_->id_allocator_ =
- aura::Env::GetInstance()->context_factory()->CreateSurfaceIdAllocator();
- factory_owner_->surface_factory_.reset(
- new cc::SurfaceFactory(surface_manager_, factory_owner_.get()));
+ factory_owner_->frame_sink_id_ =
+ aura::Env::GetInstance()->context_factory()->AllocateFrameSinkId();
+ factory_owner_->id_allocator_.reset(new cc::SurfaceIdAllocator());
+ surface_manager_->RegisterFrameSinkId(factory_owner_->frame_sink_id_);
+ factory_owner_->surface_factory_.reset(new cc::SurfaceFactory(
+ factory_owner_->frame_sink_id_, surface_manager_, factory_owner_.get()));
aura::Env::GetInstance()->context_factory()->AddObserver(this);
}
@@ -233,8 +238,8 @@ Surface::~Surface() {
for (const auto& frame_callback : active_frame_callbacks_)
frame_callback.Run(base::TimeTicks());
- if (!surface_id_.is_null())
- factory_owner_->surface_factory_->Destroy(surface_id_);
+ if (!local_frame_id_.is_null())
+ factory_owner_->surface_factory_->Destroy(local_frame_id_);
}
// static
@@ -242,6 +247,10 @@ Surface* Surface::AsSurface(const aura::Window* window) {
return window->GetProperty(kSurfaceKey);
}
+cc::SurfaceId Surface::GetSurfaceId() const {
+ return cc::SurfaceId(factory_owner_->frame_sink_id_, local_frame_id_);
+}
+
void Surface::Attach(Buffer* buffer) {
TRACE_EVENT1("exo", "Surface::Attach", "buffer",
buffer ? buffer->GetSize().ToString() : "null");
@@ -436,7 +445,7 @@ void Surface::Commit() {
}
void Surface::OnLostResources() {
- if (surface_id_.is_null())
+ if (local_frame_id_.is_null())
return;
UpdateResource(false);
@@ -460,30 +469,33 @@ void Surface::CommitSurfaceHierarchy() {
UpdateResource(true);
}
- cc::SurfaceId old_surface_id = surface_id_;
- if (needs_commit_to_new_surface_ || surface_id_.is_null()) {
+ cc::LocalFrameId old_local_frame_id = local_frame_id_;
+ if (needs_commit_to_new_surface_ || local_frame_id_.is_null()) {
needs_commit_to_new_surface_ = false;
- surface_id_ = factory_owner_->id_allocator_->GenerateId();
- factory_owner_->surface_factory_->Create(surface_id_);
+ local_frame_id_ = factory_owner_->id_allocator_->GenerateId();
+ factory_owner_->surface_factory_->Create(local_frame_id_);
}
UpdateSurface(true);
- if (!old_surface_id.is_null() && old_surface_id != surface_id_) {
- factory_owner_->surface_factory_->SetPreviousFrameSurface(surface_id_,
- old_surface_id);
- factory_owner_->surface_factory_->Destroy(old_surface_id);
+ if (!old_local_frame_id.is_null() && old_local_frame_id != local_frame_id_) {
+ factory_owner_->surface_factory_->SetPreviousFrameSurface(
+ local_frame_id_, old_local_frame_id);
+ factory_owner_->surface_factory_->Destroy(old_local_frame_id);
}
- if (old_surface_id != surface_id_) {
+ if (old_local_frame_id != local_frame_id_) {
float contents_surface_to_layer_scale = 1.0;
+ // The bounds must be updated before switching to the new surface, because
+ // the layer may be mirrored, in which case a surface change causes the
+ // mirror layer to update its surface using the latest bounds.
+ window_->layer()->SetBounds(
+ gfx::Rect(window_->layer()->bounds().origin(), content_size_));
window_->layer()->SetShowSurface(
- surface_id_,
+ cc::SurfaceId(factory_owner_->frame_sink_id_, local_frame_id_),
base::Bind(&SatisfyCallback, base::Unretained(surface_manager_)),
base::Bind(&RequireCallback, base::Unretained(surface_manager_)),
content_size_, contents_surface_to_layer_scale, content_size_);
- window_->layer()->SetBounds(
- gfx::Rect(window_->layer()->bounds().origin(), content_size_));
window_->layer()->SetFillsBoundsOpaquely(
state_.blend_mode == SkXfermode::kSrc_Mode ||
state_.opaque_region.contains(
@@ -599,18 +611,7 @@ std::unique_ptr<base::trace_event::TracedValue> Surface::AsTracedValue() const {
return value;
}
-////////////////////////////////////////////////////////////////////////////////
-// ui::LayerOwnerDelegate overrides:
-
-void Surface::OnLayerRecreated(ui::Layer* old_layer, ui::Layer* new_layer) {
- if (!current_buffer_.buffer())
- return;
-
- // TODO(reveman): Give the client a chance to provide new contents.
- SetSurfaceLayerContents(new_layer);
-}
-
-void Surface::WillDraw(cc::SurfaceId id) {
+void Surface::WillDraw(const cc::LocalFrameId& id) {
while (!active_frame_callbacks_.empty()) {
active_frame_callbacks_.front().Run(base::TimeTicks::Now());
active_frame_callbacks_.pop_front();
@@ -684,20 +685,6 @@ void Surface::SetSurfaceHierarchyNeedsCommitToNewSurfaces() {
}
}
-void Surface::SetSurfaceLayerContents(ui::Layer* layer) {
- if (surface_id_.is_null())
- return;
-
- gfx::Size layer_size = layer->bounds().size();
- float contents_surface_to_layer_scale = 1.0f;
-
- layer->SetShowSurface(
- surface_id_,
- base::Bind(&SatisfyCallback, base::Unretained(surface_manager_)),
- base::Bind(&RequireCallback, base::Unretained(surface_manager_)),
- layer_size, contents_surface_to_layer_scale, layer_size);
-}
-
void Surface::UpdateResource(bool client_usage) {
std::unique_ptr<cc::SingleReleaseCallback> texture_mailbox_release_callback;
@@ -801,6 +788,8 @@ void Surface::UpdateSurface(bool full_damage) {
current_resource_.id, true, uv_top_left,
uv_bottom_right, SK_ColorTRANSPARENT, vertex_opacity,
false, false, state_.only_visible_on_secure_output);
+ if (current_resource_.is_overlay_candidate)
+ texture_quad->set_resource_size_in_pixels(current_resource_.size);
delegated_frame->resource_list.push_back(current_resource_);
}
} else {
@@ -814,7 +803,7 @@ void Surface::UpdateSurface(bool full_damage) {
frame.delegated_frame_data = std::move(delegated_frame);
factory_owner_->surface_factory_->SubmitCompositorFrame(
- surface_id_, std::move(frame), cc::SurfaceFactory::DrawCallback());
+ local_frame_id_, std::move(frame), cc::SurfaceFactory::DrawCallback());
}
int64_t Surface::SetPropertyInternal(const void* key,
diff --git a/chromium/components/exo/surface.h b/chromium/components/exo/surface.h
index 2db62989149..744587db667 100644
--- a/chromium/components/exo/surface.h
+++ b/chromium/components/exo/surface.h
@@ -21,7 +21,6 @@
#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/aura/window.h"
#include "ui/compositor/compositor.h"
-#include "ui/compositor/layer_owner_delegate.h"
#include "ui/gfx/geometry/rect.h"
namespace base {
@@ -32,7 +31,6 @@ class TracedValue;
namespace cc {
class SurfaceFactory;
-enum class SurfaceDrawStatus;
}
namespace gfx {
@@ -68,7 +66,7 @@ class SurfaceFactoryOwner : public base::RefCounted<SurfaceFactoryOwner>,
// Overridden from cc::SurfaceFactoryClient:
void ReturnResources(const cc::ReturnedResourceArray& resources) override;
- void WillDrawSurface(const cc::SurfaceId& id,
+ void WillDrawSurface(const cc::LocalFrameId& id,
const gfx::Rect& damage_rect) override;
void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
@@ -82,6 +80,7 @@ class SurfaceFactoryOwner : public base::RefCounted<SurfaceFactoryOwner>,
std::pair<scoped_refptr<SurfaceFactoryOwner>,
std::unique_ptr<cc::SingleReleaseCallback>>>
release_callbacks_;
+ cc::FrameSinkId frame_sink_id_;
std::unique_ptr<cc::SurfaceIdAllocator> id_allocator_;
std::unique_ptr<cc::SurfaceFactory> surface_factory_;
Surface* surface_ = nullptr;
@@ -89,8 +88,7 @@ class SurfaceFactoryOwner : public base::RefCounted<SurfaceFactoryOwner>,
// This class represents a rectangular area that is displayed on the screen.
// It has a location, size and pixel contents.
-class Surface : public ui::LayerOwnerDelegate,
- public ui::ContextFactoryObserver {
+class Surface : public ui::ContextFactoryObserver {
public:
using PropertyDeallocator = void (*)(int64_t value);
@@ -102,7 +100,8 @@ class Surface : public ui::LayerOwnerDelegate,
aura::Window* window() { return window_.get(); }
- cc::SurfaceId surface_id() const { return surface_id_; }
+ const cc::LocalFrameId& local_frame_id() const { return local_frame_id_; }
+ cc::SurfaceId GetSurfaceId() const;
// Set a buffer as the content of this surface. A buffer can only be attached
// to one surface at a time.
@@ -209,13 +208,10 @@ class Surface : public ui::LayerOwnerDelegate,
return pending_damage_.contains(gfx::RectToSkIRect(damage));
}
- // Overridden from ui::LayerOwnerDelegate:
- void OnLayerRecreated(ui::Layer* old_layer, ui::Layer* new_layer) override;
-
// Overridden from ui::ContextFactoryObserver.
void OnLostResources() override;
- void WillDraw(cc::SurfaceId surface_id);
+ void WillDraw(const cc::LocalFrameId& local_frame_id);
// Check whether this Surface and its children need to create new cc::Surface
// IDs for their contents next time they get new buffer contents.
@@ -337,7 +333,7 @@ class Surface : public ui::LayerOwnerDelegate,
scoped_refptr<SurfaceFactoryOwner> factory_owner_;
// The Surface Id currently attached to the window.
- cc::SurfaceId surface_id_;
+ cc::LocalFrameId local_frame_id_;
// The next resource id the buffer will be attached to.
int next_resource_id_ = 1;
diff --git a/chromium/components/exo/surface_unittest.cc b/chromium/components/exo/surface_unittest.cc
index 7e9481f4585..01bbff2a7cf 100644
--- a/chromium/components/exo/surface_unittest.cc
+++ b/chromium/components/exo/surface_unittest.cc
@@ -5,6 +5,7 @@
#include "base/bind.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/texture_draw_quad.h"
#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_manager.h"
#include "components/exo/buffer.h"
@@ -128,7 +129,7 @@ TEST_F(SurfaceTest, SetBufferScale) {
surface->content_size().ToString());
}
-TEST_F(SurfaceTest, RecreateLayer) {
+TEST_F(SurfaceTest, MirrorLayers) {
gfx::Size buffer_size(512, 512);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
@@ -140,7 +141,7 @@ TEST_F(SurfaceTest, RecreateLayer) {
EXPECT_EQ(buffer_size, surface->window()->bounds().size());
EXPECT_EQ(buffer_size, surface->window()->layer()->bounds().size());
std::unique_ptr<ui::LayerTreeOwner> old_layer_owner =
- ::wm::RecreateLayers(surface->window(), nullptr);
+ ::wm::MirrorLayers(surface->window(), false /* sync_bounds */);
EXPECT_EQ(buffer_size, surface->window()->bounds().size());
EXPECT_EQ(buffer_size, surface->window()->layer()->bounds().size());
EXPECT_EQ(buffer_size, old_layer_owner->root()->bounds().size());
@@ -188,7 +189,7 @@ TEST_F(SurfaceTest, SetCrop) {
}
const cc::DelegatedFrameData* GetFrameFromSurface(Surface* surface) {
- cc::SurfaceId surface_id = surface->surface_id();
+ cc::SurfaceId surface_id = surface->GetSurfaceId();
cc::SurfaceManager* surface_manager =
aura::Env::GetInstance()->context_factory()->GetSurfaceManager();
const cc::CompositorFrame& frame =
@@ -214,6 +215,27 @@ TEST_F(SurfaceTest, SetBlendMode) {
->ShouldDrawWithBlending());
}
+TEST_F(SurfaceTest, OverlayCandidate) {
+ gfx::Size buffer_size(1, 1);
+ std::unique_ptr<Buffer> buffer(new Buffer(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size), 0, 0, true, true));
+ std::unique_ptr<Surface> surface(new Surface);
+
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ const cc::DelegatedFrameData* frame_data = GetFrameFromSurface(surface.get());
+ ASSERT_EQ(1u, frame_data->render_pass_list.size());
+ ASSERT_EQ(1u, frame_data->render_pass_list.back()->quad_list.size());
+ cc::DrawQuad* draw_quad =
+ frame_data->render_pass_list.back()->quad_list.back();
+ ASSERT_EQ(cc::DrawQuad::TEXTURE_CONTENT, draw_quad->material);
+
+ const cc::TextureDrawQuad* texture_quad =
+ cc::TextureDrawQuad::MaterialCast(draw_quad);
+ EXPECT_FALSE(texture_quad->resource_size_in_pixels().IsEmpty());
+}
+
TEST_F(SurfaceTest, SetAlpha) {
gfx::Size buffer_size(1, 1);
std::unique_ptr<Buffer> buffer(
diff --git a/chromium/components/exo/touch.cc b/chromium/components/exo/touch.cc
index 25507227096..f0db5959441 100644
--- a/chromium/components/exo/touch.cc
+++ b/chromium/components/exo/touch.cc
@@ -4,9 +4,9 @@
#include "components/exo/touch.h"
-#include "ash/shell.h"
#include "components/exo/surface.h"
#include "components/exo/touch_delegate.h"
+#include "components/exo/wm_helper.h"
#include "ui/aura/window.h"
#include "ui/events/event.h"
@@ -32,14 +32,14 @@ bool VectorContainsItem(T& vector, U value) {
// Touch, public:
Touch::Touch(TouchDelegate* delegate) : delegate_(delegate) {
- ash::Shell::GetInstance()->AddPreTargetHandler(this);
+ WMHelper::GetInstance()->AddPreTargetHandler(this);
}
Touch::~Touch() {
delegate_->OnTouchDestroying(this);
if (focus_)
focus_->RemoveSurfaceObserver(this);
- ash::Shell::GetInstance()->RemovePreTargetHandler(this);
+ WMHelper::GetInstance()->RemovePreTargetHandler(this);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/components/exo/touch_unittest.cc b/chromium/components/exo/touch_unittest.cc
index f7542200954..a1fd44180ed 100644
--- a/chromium/components/exo/touch_unittest.cc
+++ b/chromium/components/exo/touch_unittest.cc
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ash/aura/wm_window_aura.h"
+#include "ash/common/shell_window_ids.h"
#include "ash/common/wm/window_positioner.h"
+#include "ash/common/wm/window_positioning_utils.h"
+#include "ash/common/wm_shell.h"
#include "ash/shell.h"
-#include "ash/wm/window_util.h"
#include "components/exo/buffer.h"
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
@@ -13,6 +16,7 @@
#include "components/exo/touch.h"
#include "components/exo/touch_delegate.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/events/base_event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/widget/widget.h"
@@ -46,7 +50,8 @@ TEST_F(TouchTest, OnTouchDown) {
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(bottom_buffer_size)));
bottom_surface->Attach(bottom_buffer.get());
bottom_surface->Commit();
- ash::wm::CenterWindow(bottom_shell_surface->GetWidget()->GetNativeWindow());
+ ash::wm::CenterWindow(ash::WmWindowAura::Get(
+ bottom_shell_surface->GetWidget()->GetNativeWindow()));
std::unique_ptr<Surface> top_surface(new Surface);
std::unique_ptr<ShellSurface> top_shell_surface(
@@ -56,7 +61,8 @@ TEST_F(TouchTest, OnTouchDown) {
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(top_buffer_size)));
top_surface->Attach(top_buffer.get());
top_surface->Commit();
- ash::wm::CenterWindow(top_shell_surface->GetWidget()->GetNativeWindow());
+ ash::wm::CenterWindow(ash::WmWindowAura::Get(
+ top_shell_surface->GetWidget()->GetNativeWindow()));
MockTouchDelegate delegate;
std::unique_ptr<Touch> touch(new Touch(&delegate));
@@ -180,12 +186,92 @@ TEST_F(TouchTest, OnTouchCancel) {
// One touch point being canceled is enough for OnTouchCancel to be called.
EXPECT_CALL(delegate, OnTouchCancel());
ui::TouchEvent cancel_event(ui::ET_TOUCH_CANCELLED, gfx::Point(), 1,
- generator.Now());
+ ui::EventTimeForNow());
generator.Dispatch(&cancel_event);
EXPECT_CALL(delegate, OnTouchDestroying(touch.get()));
touch.reset();
}
+TEST_F(TouchTest, IgnoreTouchEventDuringModal) {
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(10, 10))));
+ surface->Attach(buffer.get());
+ surface->Commit();
+ gfx::Point location = surface->window()->GetBoundsInScreen().origin();
+
+ MockTouchDelegate delegate;
+ std::unique_ptr<Touch> touch(new Touch(&delegate));
+ ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+ // Create surface for modal window.
+ std::unique_ptr<Surface> surface2(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface2(
+ new ShellSurface(surface2.get(), nullptr, gfx::Rect(0, 0, 5, 5), true,
+ ash::kShellWindowId_SystemModalContainer));
+ std::unique_ptr<Buffer> buffer2(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(5, 5))));
+ surface2->Attach(buffer2.get());
+ surface2->Commit();
+ ash::wm::CenterWindow(ash::WmWindowAura::Get(surface2->window()));
+ gfx::Point location2 = surface2->window()->GetBoundsInScreen().origin();
+
+ // Make the window modal.
+ shell_surface2->SetSystemModal(true);
+ EXPECT_TRUE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+
+ EXPECT_CALL(delegate, CanAcceptTouchEventsForSurface(surface.get()))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(delegate, CanAcceptTouchEventsForSurface(surface2.get()))
+ .WillRepeatedly(testing::Return(true));
+
+ // Check if touch events on modal window are registered.
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnTouchDown(surface2.get(), testing::_, testing::_,
+ gfx::Point()));
+ EXPECT_CALL(delegate,
+ OnTouchMotion(testing::_, testing::_, gfx::Point(1, 1)));
+ EXPECT_CALL(delegate, OnTouchUp(testing::_, testing::_));
+ }
+ generator.set_current_location(location2);
+ generator.PressMoveAndReleaseTouchBy(1, 1);
+
+ // Check if touch events on non-modal window are ignored.
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnTouchDown(surface.get(), testing::_, testing::_,
+ gfx::Point()))
+ .Times(0);
+ EXPECT_CALL(delegate,
+ OnTouchMotion(testing::_, testing::_, gfx::Point(1, 1)))
+ .Times(0);
+ EXPECT_CALL(delegate, OnTouchUp(testing::_, testing::_)).Times(0);
+ }
+ generator.set_current_location(location);
+ generator.PressMoveAndReleaseTouchBy(1, 1);
+
+ // Make the window non-modal.
+ shell_surface2->SetSystemModal(false);
+ EXPECT_FALSE(ash::WmShell::Get()->IsSystemModalWindowOpen());
+
+ // Check if touch events on non-modal window are registered.
+ {
+ testing::InSequence sequence;
+ EXPECT_CALL(delegate, OnTouchDown(surface.get(), testing::_, testing::_,
+ gfx::Point()));
+ EXPECT_CALL(delegate,
+ OnTouchMotion(testing::_, testing::_, gfx::Point(1, 1)));
+ EXPECT_CALL(delegate, OnTouchUp(testing::_, testing::_));
+ }
+ generator.set_current_location(location);
+ generator.PressMoveAndReleaseTouchBy(1, 1);
+
+ EXPECT_CALL(delegate, OnTouchDestroying(touch.get()));
+ touch.reset();
+}
+
} // namespace
} // namespace exo
diff --git a/chromium/components/exo/wayland/server.cc b/chromium/components/exo/wayland/server.cc
index 0e160d18389..53b20f9432e 100644
--- a/chromium/components/exo/wayland/server.cc
+++ b/chromium/components/exo/wayland/server.cc
@@ -27,13 +27,9 @@
#include <string>
#include <utility>
-#include "ash/common/display/display_info.h"
#include "ash/common/shell_observer.h"
#include "ash/common/shell_window_ids.h"
-#include "ash/common/wm_shell.h"
-#include "ash/display/display_manager.h"
#include "ash/shell.h"
-#include "ash/wm/maximize_mode/maximize_mode_controller.h"
#include "base/bind.h"
#include "base/cancelable_callback.h"
#include "base/files/file_path.h"
@@ -63,20 +59,20 @@
#include "components/exo/surface_property.h"
#include "components/exo/touch.h"
#include "components/exo/touch_delegate.h"
+#include "components/exo/wm_helper.h"
#include "ipc/unix_domain_socket_util.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/aura/window_property.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/display/display_observer.h"
+#include "ui/display/manager/managed_display_info.h"
#include "ui/display/screen.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/buffer_types.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
-#include "ui/wm/public/activation_change_observer.h"
-#include "ui/wm/public/activation_client.h"
#if defined(USE_OZONE)
#include <drm_fourcc.h>
@@ -477,6 +473,7 @@ const struct drm_supported_format {
{WL_DRM_FORMAT_ABGR8888, gfx::BufferFormat::RGBA_8888},
{WL_DRM_FORMAT_XRGB8888, gfx::BufferFormat::BGRX_8888},
{WL_DRM_FORMAT_ARGB8888, gfx::BufferFormat::BGRA_8888},
+ {WL_DRM_FORMAT_NV12, gfx::BufferFormat::YUV_420_BIPLANAR},
{WL_DRM_FORMAT_YVU420, gfx::BufferFormat::YVU_420}};
void drm_authenticate(wl_client* client, wl_resource* resource, uint32_t id) {
@@ -538,20 +535,21 @@ void drm_create_prime_buffer(wl_client* client,
return;
}
- std::vector<int> strides{stride0, stride1, stride2};
- std::vector<int> offsets{offset0, offset1, offset2};
+ std::vector<gfx::NativePixmapPlane> planes;
+ planes.emplace_back(stride0, offset0, 0, 0);
+ planes.emplace_back(stride1, offset1, 0, 0);
+ planes.emplace_back(stride2, offset2, 0, 0);
std::vector<base::ScopedFD> fds;
- int planes =
+ size_t num_planes =
gfx::NumberOfPlanesForBufferFormat(supported_format->buffer_format);
- strides.resize(planes);
- offsets.resize(planes);
+ planes.resize(num_planes);
fds.push_back(base::ScopedFD(name));
std::unique_ptr<Buffer> buffer =
GetUserDataAs<Display>(resource)->CreateLinuxDMABufBuffer(
- gfx::Size(width, height), supported_format->buffer_format, strides,
- offsets, std::move(fds));
+ gfx::Size(width, height), supported_format->buffer_format, planes,
+ std::move(fds));
if (!buffer) {
wl_resource_post_no_memory(resource);
return;
@@ -684,8 +682,7 @@ void linux_buffer_params_create(wl_client* client,
return;
}
- std::vector<int> strides;
- std::vector<int> offsets;
+ std::vector<gfx::NativePixmapPlane> planes;
std::vector<base::ScopedFD> fds;
for (uint32_t i = 0; i < num_planes; ++i) {
@@ -697,16 +694,15 @@ void linux_buffer_params_create(wl_client* client,
return;
}
LinuxBufferParams::Plane& plane = plane_it->second;
- strides.push_back(plane.stride);
- offsets.push_back(plane.offset);
+ planes.emplace_back(plane.stride, plane.offset, 0, 0);
if (plane.fd.is_valid())
fds.push_back(std::move(plane.fd));
}
std::unique_ptr<Buffer> buffer =
linux_buffer_params->display->CreateLinuxDMABufBuffer(
- gfx::Size(width, height), supported_format->buffer_format, strides,
- offsets, std::move(fds));
+ gfx::Size(width, height), supported_format->buffer_format, planes,
+ std::move(fds));
if (!buffer) {
zwp_linux_buffer_params_v1_send_failed(resource);
return;
@@ -739,7 +735,7 @@ void linux_dmabuf_create_params(wl_client* client,
wl_resource* resource,
uint32_t id) {
std::unique_ptr<LinuxBufferParams> linux_buffer_params =
- base::WrapUnique(new LinuxBufferParams(GetUserDataAs<Display>(resource)));
+ base::MakeUnique<LinuxBufferParams>(GetUserDataAs<Display>(resource));
wl_resource* linux_buffer_params_resource =
wl_resource_create(client, &zwp_linux_buffer_params_v1_interface, 1, id);
@@ -1079,9 +1075,8 @@ class WaylandPrimaryDisplayObserver : public display::DisplayObserver {
display::Display display =
display::Screen::GetScreen()->GetPrimaryDisplay();
- const ash::DisplayInfo& info =
- ash::Shell::GetInstance()->display_manager()->GetDisplayInfo(
- display.id());
+ const display::ManagedDisplayInfo& info =
+ WMHelper::GetInstance()->GetDisplayInfo(display.id());
const float kInchInMm = 25.4f;
const char* kUnknownMake = "unknown";
@@ -1123,9 +1118,8 @@ void bind_output(wl_client* client, void* data, uint32_t version, uint32_t id) {
wl_resource* resource = wl_resource_create(
client, &wl_output_interface, std::min(version, output_version), id);
- SetImplementation(
- resource, nullptr,
- base::WrapUnique(new WaylandPrimaryDisplayObserver(resource)));
+ SetImplementation(resource, nullptr,
+ base::MakeUnique<WaylandPrimaryDisplayObserver>(resource));
}
////////////////////////////////////////////////////////////////////////////////
@@ -1465,8 +1459,41 @@ void remote_surface_set_scale(wl_client* client,
GetUserDataAs<ShellSurface>(resource)->SetScale(wl_fixed_to_double(scale));
}
-void remote_surface_fullscreen(wl_client* client, wl_resource* resource) {
- GetUserDataAs<ShellSurface>(resource)->SetFullscreen(true);
+void remote_surface_set_rectangular_shadow(wl_client* client,
+ wl_resource* resource,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height) {
+ GetUserDataAs<ShellSurface>(resource)->SetRectangularShadow(
+ gfx::Rect(x, y, width, height));
+}
+
+void remote_surface_set_rectangular_shadow_background_opacity(
+ wl_client* client,
+ wl_resource* resource,
+ wl_fixed_t opacity) {
+ GetUserDataAs<ShellSurface>(resource)->SetRectangularShadowBackgroundOpacity(
+ wl_fixed_to_double(opacity));
+}
+
+void remote_surface_set_title(wl_client* client,
+ wl_resource* resource,
+ const char* title) {
+ GetUserDataAs<ShellSurface>(resource)->SetTitle(
+ base::string16(base::UTF8ToUTF16(title)));
+}
+
+void remote_surface_set_top_inset(wl_client* client,
+ wl_resource* resource,
+ int32_t height) {
+ GetUserDataAs<ShellSurface>(resource)->SetTopInset(height);
+}
+
+void remote_surface_activate(wl_client* client,
+ wl_resource* resource,
+ uint32_t serial) {
+ GetUserDataAs<ShellSurface>(resource)->Activate();
}
void remote_surface_maximize(wl_client* client, wl_resource* resource) {
@@ -1481,39 +1508,22 @@ void remote_surface_restore(wl_client* client, wl_resource* resource) {
GetUserDataAs<ShellSurface>(resource)->Restore();
}
-void remote_surface_pin(wl_client* client, wl_resource* resource) {
- GetUserDataAs<ShellSurface>(resource)->SetPinned(true);
-}
-
-void remote_surface_unpin(wl_client* client, wl_resource* resource) {
- GetUserDataAs<ShellSurface>(resource)->SetPinned(false);
+void remote_surface_fullscreen(wl_client* client, wl_resource* resource) {
+ GetUserDataAs<ShellSurface>(resource)->SetFullscreen(true);
}
void remote_surface_unfullscreen(wl_client* client, wl_resource* resource) {
GetUserDataAs<ShellSurface>(resource)->SetFullscreen(false);
}
-void remote_surface_set_rectangular_shadow(wl_client* client,
- wl_resource* resource,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height) {
- GetUserDataAs<ShellSurface>(resource)->SetRectangularShadow(
- gfx::Rect(x, y, width, height));
-}
-
-void remote_surface_set_title(wl_client* client,
- wl_resource* resource,
- const char* title) {
- GetUserDataAs<ShellSurface>(resource)->SetTitle(
- base::string16(base::UTF8ToUTF16(title)));
+void remote_surface_pin(wl_client* client,
+ wl_resource* resource,
+ int32_t trusted) {
+ GetUserDataAs<ShellSurface>(resource)->SetPinned(true, trusted);
}
-void remote_surface_set_top_inset(wl_client* client,
- wl_resource* resource,
- int32_t height) {
- GetUserDataAs<ShellSurface>(resource)->SetTopInset(height);
+void remote_surface_unpin(wl_client* client, wl_resource* resource) {
+ GetUserDataAs<ShellSurface>(resource)->SetPinned(false, /* trusted */ false);
}
void remote_surface_set_system_modal(wl_client* client, wl_resource* resource) {
@@ -1525,39 +1535,25 @@ void remote_surface_unset_system_modal(wl_client* client,
GetUserDataAs<ShellSurface>(resource)->SetSystemModal(false);
}
-void remote_surface_set_rectangular_shadow_background_opacity(
- wl_client* client,
- wl_resource* resource,
- wl_fixed_t opacity) {
- GetUserDataAs<ShellSurface>(resource)->SetRectangularShadowBackgroundOpacity(
- wl_fixed_to_double(opacity));
-}
-
-void remote_surface_activate(wl_client* client,
- wl_resource* resource,
- uint32_t serial) {
- GetUserDataAs<ShellSurface>(resource)->Activate();
-}
-
-const struct zwp_remote_surface_v1_interface remote_surface_implementation = {
+const struct zcr_remote_surface_v1_interface remote_surface_implementation = {
remote_surface_destroy,
remote_surface_set_app_id,
remote_surface_set_window_geometry,
remote_surface_set_scale,
- remote_surface_fullscreen,
+ remote_surface_set_rectangular_shadow,
+ remote_surface_set_rectangular_shadow_background_opacity,
+ remote_surface_set_title,
+ remote_surface_set_top_inset,
+ remote_surface_activate,
remote_surface_maximize,
remote_surface_minimize,
remote_surface_restore,
+ remote_surface_fullscreen,
+ remote_surface_unfullscreen,
remote_surface_pin,
remote_surface_unpin,
- remote_surface_unfullscreen,
- remote_surface_set_rectangular_shadow,
- remote_surface_set_title,
- remote_surface_set_top_inset,
remote_surface_set_system_modal,
- remote_surface_unset_system_modal,
- remote_surface_set_rectangular_shadow_background_opacity,
- remote_surface_activate};
+ remote_surface_unset_system_modal};
////////////////////////////////////////////////////////////////////////////////
// notification_surface_interface:
@@ -1566,7 +1562,7 @@ void notification_surface_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
-const struct zwp_notification_surface_v1_interface
+const struct zcr_notification_surface_v1_interface
notification_surface_implementation = {notification_surface_destroy};
////////////////////////////////////////////////////////////////////////////////
@@ -1574,32 +1570,30 @@ const struct zwp_notification_surface_v1_interface
// Implements remote shell interface and monitors workspace state needed
// for the remote shell interface.
-class WaylandRemoteShell : public ash::ShellObserver,
- public aura::client::ActivationChangeObserver,
+class WaylandRemoteShell : public WMHelper::MaximizeModeObserver,
+ public WMHelper::ActivationObserver,
public display::DisplayObserver {
public:
- WaylandRemoteShell(Display* display,
- wl_resource* remote_shell_resource)
+ WaylandRemoteShell(Display* display, wl_resource* remote_shell_resource)
: display_(display),
remote_shell_resource_(remote_shell_resource),
weak_ptr_factory_(this) {
- ash::WmShell::Get()->AddShellObserver(this);
- ash::Shell* shell = ash::Shell::GetInstance();
- shell->activation_client()->AddObserver(this);
+ auto* helper = WMHelper::GetInstance();
+ helper->AddMaximizeModeObserver(this);
+ helper->AddActivationObserver(this);
display::Screen::GetScreen()->AddObserver(this);
- layout_mode_ = ash::Shell::GetInstance()
- ->maximize_mode_controller()
- ->IsMaximizeModeWindowManagerEnabled()
- ? ZWP_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET
- : ZWP_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
+ layout_mode_ = helper->IsMaximizeModeWindowManagerEnabled()
+ ? ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET
+ : ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
SendPrimaryDisplayMetrics();
- SendActivated(shell->activation_client()->GetActiveWindow(), nullptr);
+ SendActivated(helper->GetActiveWindow(), nullptr);
}
~WaylandRemoteShell() override {
- ash::WmShell::Get()->RemoveShellObserver(this);
- ash::Shell::GetInstance()->activation_client()->RemoveObserver(this);
+ auto* helper = WMHelper::GetInstance();
+ helper->RemoveMaximizeModeObserver(this);
+ helper->RemoveActivationObserver(this);
display::Screen::GetScreen()->RemoveObserver(this);
}
@@ -1630,13 +1624,11 @@ class WaylandRemoteShell : public ash::ShellObserver,
DISPLAY_METRIC_ROTATION | DISPLAY_METRIC_WORK_AREA)) {
SendDisplayMetrics(display);
}
- SendConfigure_DEPRECATED(display);
}
- // Overridden from ash::ShellObserver:
+ // Overridden from WMHelper::MaximizeModeObserver:
void OnMaximizeModeStarted() override {
- layout_mode_ = ZWP_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET;
- SendLayoutModeChange_DEPRECATED();
+ layout_mode_ = ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET;
send_configure_after_layout_change_ = true;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
@@ -1645,8 +1637,7 @@ class WaylandRemoteShell : public ash::ShellObserver,
base::TimeDelta::FromMilliseconds(kConfigureDelayAfterLayoutSwitchMs));
}
void OnMaximizeModeEnded() override {
- layout_mode_ = ZWP_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
- SendLayoutModeChange_DEPRECATED();
+ layout_mode_ = ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
send_configure_after_layout_change_ = true;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::Bind(&WaylandRemoteShell::MaybeSendConfigure,
@@ -1654,11 +1645,9 @@ class WaylandRemoteShell : public ash::ShellObserver,
base::TimeDelta::FromMilliseconds(kConfigureDelayAfterLayoutSwitchMs));
}
- // Overridden from aura::client::ActivationChangeObserver:
- void OnWindowActivated(
- aura::client::ActivationChangeObserver::ActivationReason reason,
- aura::Window* gained_active,
- aura::Window* lost_active) override {
+ // Overridden from WMHelper::ActivationObserver:
+ void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) override {
SendActivated(gained_active, lost_active);
}
@@ -1667,7 +1656,6 @@ class WaylandRemoteShell : public ash::ShellObserver,
const display::Display primary =
display::Screen::GetScreen()->GetPrimaryDisplay();
- SendConfigure_DEPRECATED(primary);
SendDisplayMetrics(primary);
}
@@ -1679,40 +1667,14 @@ class WaylandRemoteShell : public ash::ShellObserver,
void SendDisplayMetrics(const display::Display& display) {
send_configure_after_layout_change_ = false;
- if (wl_resource_get_version(remote_shell_resource_) < 9)
- return;
-
const gfx::Insets& work_area_insets = display.GetWorkAreaInsets();
- zwp_remote_shell_v1_send_configuration_changed(
+ zcr_remote_shell_v1_send_configuration_changed(
remote_shell_resource_, display.size().width(), display.size().height(),
OutputTransform(display.rotation()),
wl_fixed_from_double(display.device_scale_factor()),
work_area_insets.left(), work_area_insets.top(),
work_area_insets.right(), work_area_insets.bottom(), layout_mode_);
-
- wl_client_flush(wl_resource_get_client(remote_shell_resource_));
- }
-
- void SendConfigure_DEPRECATED(const display::Display& display) {
- send_configure_after_layout_change_ = false;
-
- if (wl_resource_get_version(remote_shell_resource_) >= 9)
- return;
-
- const gfx::Insets& work_area_insets = display.GetWorkAreaInsets();
- zwp_remote_shell_v1_send_configure(
- remote_shell_resource_, display.size().width(), display.size().height(),
- work_area_insets.left(), work_area_insets.top(),
- work_area_insets.right(), work_area_insets.bottom());
- wl_client_flush(wl_resource_get_client(remote_shell_resource_));
- }
-
- void SendLayoutModeChange_DEPRECATED() {
- if (wl_resource_get_version(remote_shell_resource_) < 8)
- return;
- zwp_remote_shell_v1_send_layout_mode_changed(remote_shell_resource_,
- layout_mode_);
wl_client_flush(wl_resource_get_client(remote_shell_resource_));
}
@@ -1743,7 +1705,7 @@ class WaylandRemoteShell : public ash::ShellObserver,
lost_active_surface_resource = nullptr;
}
- zwp_remote_shell_v1_send_activated(remote_shell_resource_,
+ zcr_remote_shell_v1_send_activated(remote_shell_resource_,
gained_active_surface_resource,
lost_active_surface_resource);
wl_client_flush(client);
@@ -1757,7 +1719,7 @@ class WaylandRemoteShell : public ash::ShellObserver,
bool send_configure_after_layout_change_ = false;
- int layout_mode_ = ZWP_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
+ int layout_mode_ = ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
base::WeakPtrFactory<WaylandRemoteShell> weak_ptr_factory_;
@@ -1770,9 +1732,9 @@ void remote_shell_destroy(wl_client* client, wl_resource* resource) {
int RemoteSurfaceContainer(uint32_t container) {
switch (container) {
- case ZWP_REMOTE_SHELL_V1_CONTAINER_DEFAULT:
+ case ZCR_REMOTE_SHELL_V1_CONTAINER_DEFAULT:
return ash::kShellWindowId_DefaultContainer;
- case ZWP_REMOTE_SHELL_V1_CONTAINER_OVERLAY:
+ case ZCR_REMOTE_SHELL_V1_CONTAINER_OVERLAY:
return ash::kShellWindowId_SystemModalContainer;
default:
DLOG(WARNING) << "Unsupported container: " << container;
@@ -1781,7 +1743,7 @@ int RemoteSurfaceContainer(uint32_t container) {
}
void HandleRemoteSurfaceCloseCallback(wl_resource* resource) {
- zwp_remote_surface_v1_send_close(resource);
+ zcr_remote_surface_v1_send_close(resource);
wl_client_flush(wl_resource_get_client(resource));
}
@@ -1791,54 +1753,28 @@ void HandleRemoteSurfaceStateChangedCallback(
ash::wm::WindowStateType new_state_type) {
DCHECK_NE(old_state_type, new_state_type);
- switch (old_state_type) {
- case ash::wm::WINDOW_STATE_TYPE_MINIMIZED:
- if (wl_resource_get_version(resource) >= 2)
- zwp_remote_surface_v1_send_unset_minimized(resource);
- break;
- case ash::wm::WINDOW_STATE_TYPE_MAXIMIZED:
- if (wl_resource_get_version(resource) >= 2)
- zwp_remote_surface_v1_send_unset_maximized(resource);
- break;
- case ash::wm::WINDOW_STATE_TYPE_FULLSCREEN:
- zwp_remote_surface_v1_send_unset_fullscreen(resource);
- break;
- case ash::wm::WINDOW_STATE_TYPE_PINNED:
- if (wl_resource_get_version(resource) >= 3)
- zwp_remote_surface_v1_send_unset_pinned(resource);
- break;
- default:
- break;
- }
-
- uint32_t state_type = ZWP_REMOTE_SHELL_V1_STATE_TYPE_NORMAL;
+ uint32_t state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_NORMAL;
switch (new_state_type) {
case ash::wm::WINDOW_STATE_TYPE_MINIMIZED:
- state_type = ZWP_REMOTE_SHELL_V1_STATE_TYPE_MINIMIZED;
- if (wl_resource_get_version(resource) >= 2)
- zwp_remote_surface_v1_send_set_minimized(resource);
+ state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_MINIMIZED;
break;
case ash::wm::WINDOW_STATE_TYPE_MAXIMIZED:
- state_type = ZWP_REMOTE_SHELL_V1_STATE_TYPE_MAXIMIZED;
- if (wl_resource_get_version(resource) >= 2)
- zwp_remote_surface_v1_send_set_maximized(resource);
+ state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_MAXIMIZED;
break;
case ash::wm::WINDOW_STATE_TYPE_FULLSCREEN:
- state_type = ZWP_REMOTE_SHELL_V1_STATE_TYPE_FULLSCREEN;
- zwp_remote_surface_v1_send_set_fullscreen(resource);
+ state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_FULLSCREEN;
break;
case ash::wm::WINDOW_STATE_TYPE_PINNED:
- state_type = ZWP_REMOTE_SHELL_V1_STATE_TYPE_PINNED;
- if (wl_resource_get_version(resource) >= 3)
- zwp_remote_surface_v1_send_set_pinned(resource);
+ state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_PINNED;
+ break;
+ case ash::wm::WINDOW_STATE_TYPE_TRUSTED_PINNED:
+ state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_TRUSTED_PINNED;
break;
default:
break;
}
- if (wl_resource_get_version(resource) >= 7)
- zwp_remote_surface_v1_send_state_type_changed(resource, state_type);
-
+ zcr_remote_surface_v1_send_state_type_changed(resource, state_type);
wl_client_flush(wl_resource_get_client(resource));
}
@@ -1851,13 +1787,13 @@ void remote_shell_get_remote_surface(wl_client* client,
GetUserDataAs<WaylandRemoteShell>(resource)->CreateShellSurface(
GetUserDataAs<Surface>(surface), RemoteSurfaceContainer(container));
if (!shell_surface) {
- wl_resource_post_error(resource, ZWP_REMOTE_SHELL_V1_ERROR_ROLE,
+ wl_resource_post_error(resource, ZCR_REMOTE_SHELL_V1_ERROR_ROLE,
"surface has already been assigned a role");
return;
}
wl_resource* remote_surface_resource =
- wl_resource_create(client, &zwp_remote_surface_v1_interface,
+ wl_resource_create(client, &zcr_remote_surface_v1_interface,
wl_resource_get_version(resource), id);
shell_surface->set_close_callback(
@@ -1877,7 +1813,7 @@ void remote_shell_get_notification_surface(wl_client* client,
wl_resource* surface,
const char* notification_id) {
if (GetUserDataAs<Surface>(surface)->HasSurfaceDelegate()) {
- wl_resource_post_error(resource, ZWP_REMOTE_SHELL_V1_ERROR_ROLE,
+ wl_resource_post_error(resource, ZCR_REMOTE_SHELL_V1_ERROR_ROLE,
"surface has already been assigned a role");
return;
}
@@ -1887,40 +1823,40 @@ void remote_shell_get_notification_surface(wl_client* client,
GetUserDataAs<Surface>(surface), std::string(notification_id));
if (!notification_surface) {
wl_resource_post_error(resource,
- ZWP_REMOTE_SHELL_V1_ERROR_INVALID_NOTIFICATION_ID,
+ ZCR_REMOTE_SHELL_V1_ERROR_INVALID_NOTIFICATION_ID,
"invalid notification id");
return;
}
wl_resource* notification_surface_resource =
- wl_resource_create(client, &zwp_notification_surface_v1_interface,
+ wl_resource_create(client, &zcr_notification_surface_v1_interface,
wl_resource_get_version(resource), id);
SetImplementation(notification_surface_resource,
&notification_surface_implementation,
std::move(notification_surface));
}
-const struct zwp_remote_shell_v1_interface remote_shell_implementation = {
+const struct zcr_remote_shell_v1_interface remote_shell_implementation = {
remote_shell_destroy, remote_shell_get_remote_surface,
remote_shell_get_notification_surface};
-const uint32_t remote_shell_version = 10;
+const uint32_t remote_shell_version = 1;
void bind_remote_shell(wl_client* client,
void* data,
uint32_t version,
uint32_t id) {
wl_resource* resource =
- wl_resource_create(client, &zwp_remote_shell_v1_interface,
+ wl_resource_create(client, &zcr_remote_shell_v1_interface,
std::min(version, remote_shell_version), id);
SetImplementation(resource, &remote_shell_implementation,
- base::WrapUnique(new WaylandRemoteShell(
- static_cast<Display*>(data), resource)));
+ base::MakeUnique<WaylandRemoteShell>(
+ static_cast<Display*>(data), resource));
}
////////////////////////////////////////////////////////////////////////////////
-// zwp_vsync_timing_v1_interface:
+// vsync_timing_interface:
// Implements VSync timing interface by monitoring a compositor for updates
// to VSync parameters.
@@ -1962,7 +1898,7 @@ class VSyncTiming : public ui::CompositorVSyncManager::Observer {
return;
}
- zwp_vsync_timing_v1_send_update(timing_resource_, timebase_us & 0xffffffff,
+ zcr_vsync_timing_v1_send_update(timing_resource_, timebase_us & 0xffffffff,
timebase_us >> 32, interval_us & 0xffffffff,
interval_us >> 32);
wl_client_flush(wl_resource_get_client(timing_resource_));
@@ -1992,11 +1928,11 @@ void vsync_timing_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
-const struct zwp_vsync_timing_v1_interface vsync_timing_implementation = {
+const struct zcr_vsync_timing_v1_interface vsync_timing_implementation = {
vsync_timing_destroy};
////////////////////////////////////////////////////////////////////////////////
-// zwp_vsync_feedback_v1_interface:
+// vsync_feedback_interface:
void vsync_feedback_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
@@ -2007,7 +1943,7 @@ void vsync_feedback_get_vsync_timing(wl_client* client,
uint32_t id,
wl_resource* output) {
wl_resource* timing_resource =
- wl_resource_create(client, &zwp_vsync_timing_v1_interface, 1, id);
+ wl_resource_create(client, &zcr_vsync_timing_v1_interface, 1, id);
// TODO(reveman): Multi-display support.
ui::Compositor* compositor =
@@ -2017,7 +1953,7 @@ void vsync_feedback_get_vsync_timing(wl_client* client,
VSyncTiming::Create(compositor, timing_resource));
}
-const struct zwp_vsync_feedback_v1_interface vsync_feedback_implementation = {
+const struct zcr_vsync_feedback_v1_interface vsync_feedback_implementation = {
vsync_feedback_destroy, vsync_feedback_get_vsync_timing};
void bind_vsync_feedback(wl_client* client,
@@ -2025,7 +1961,7 @@ void bind_vsync_feedback(wl_client* client,
uint32_t version,
uint32_t id) {
wl_resource* resource =
- wl_resource_create(client, &zwp_vsync_feedback_v1_interface, 1, id);
+ wl_resource_create(client, &zcr_vsync_feedback_v1_interface, 1, id);
wl_resource_set_implementation(resource, &vsync_feedback_implementation,
nullptr, nullptr);
@@ -2465,9 +2401,9 @@ void seat_get_pointer(wl_client* client, wl_resource* resource, uint32_t id) {
wl_resource* pointer_resource = wl_resource_create(
client, &wl_pointer_interface, wl_resource_get_version(resource), id);
- SetImplementation(pointer_resource, &pointer_implementation,
- base::WrapUnique(new Pointer(
- new WaylandPointerDelegate(pointer_resource))));
+ SetImplementation(
+ pointer_resource, &pointer_implementation,
+ base::MakeUnique<Pointer>(new WaylandPointerDelegate(pointer_resource)));
}
void seat_get_keyboard(wl_client* client, wl_resource* resource, uint32_t id) {
@@ -2477,8 +2413,8 @@ void seat_get_keyboard(wl_client* client, wl_resource* resource, uint32_t id) {
wl_resource_create(client, &wl_keyboard_interface, version, id);
SetImplementation(keyboard_resource, &keyboard_implementation,
- base::WrapUnique(new Keyboard(
- new WaylandKeyboardDelegate(keyboard_resource))));
+ base::MakeUnique<Keyboard>(
+ new WaylandKeyboardDelegate(keyboard_resource)));
// TODO(reveman): Keep repeat info synchronized with chromium and the host OS.
if (version >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
@@ -2494,7 +2430,7 @@ void seat_get_touch(wl_client* client, wl_resource* resource, uint32_t id) {
SetImplementation(
touch_resource, &touch_implementation,
- base::WrapUnique(new Touch(new WaylandTouchDelegate(touch_resource))));
+ base::MakeUnique<Touch>(new WaylandTouchDelegate(touch_resource)));
}
void seat_release(wl_client* client, wl_resource* resource) {
@@ -2639,7 +2575,7 @@ void viewporter_get_viewport(wl_client* client,
client, &wp_viewport_interface, wl_resource_get_version(resource), id);
SetImplementation(viewport_resource, &viewport_implementation,
- base::WrapUnique(new Viewport(surface)));
+ base::MakeUnique<Viewport>(surface));
}
const struct wp_viewporter_interface viewporter_implementation = {
@@ -2703,7 +2639,7 @@ void security_only_visible_on_secure_output(wl_client* client,
GetUserDataAs<Security>(resource)->OnlyVisibleOnSecureOutput();
}
-const struct zwp_security_v1_interface security_implementation = {
+const struct zcr_security_v1_interface security_implementation = {
security_destroy, security_only_visible_on_secure_output};
////////////////////////////////////////////////////////////////////////////////
@@ -2719,19 +2655,19 @@ void secure_output_get_security(wl_client* client,
wl_resource* surface_resource) {
Surface* surface = GetUserDataAs<Surface>(surface_resource);
if (surface->GetProperty(kSurfaceHasSecurityKey)) {
- wl_resource_post_error(resource, ZWP_SECURE_OUTPUT_V1_ERROR_SECURITY_EXISTS,
+ wl_resource_post_error(resource, ZCR_SECURE_OUTPUT_V1_ERROR_SECURITY_EXISTS,
"a security object for that surface already exists");
return;
}
wl_resource* security_resource =
- wl_resource_create(client, &zwp_security_v1_interface, 1, id);
+ wl_resource_create(client, &zcr_security_v1_interface, 1, id);
SetImplementation(security_resource, &security_implementation,
- base::WrapUnique(new Security(surface)));
+ base::MakeUnique<Security>(surface));
}
-const struct zwp_secure_output_v1_interface secure_output_implementation = {
+const struct zcr_secure_output_v1_interface secure_output_implementation = {
secure_output_destroy, secure_output_get_security};
void bind_secure_output(wl_client* client,
@@ -2739,7 +2675,7 @@ void bind_secure_output(wl_client* client,
uint32_t version,
uint32_t id) {
wl_resource* resource =
- wl_resource_create(client, &zwp_secure_output_v1_interface, 1, id);
+ wl_resource_create(client, &zcr_secure_output_v1_interface, 1, id);
wl_resource_set_implementation(resource, &secure_output_implementation, data,
nullptr);
@@ -2797,14 +2733,14 @@ void blending_set_blending(wl_client* client,
wl_resource* resource,
uint32_t equation) {
switch (equation) {
- case ZWP_BLENDING_V1_BLENDING_EQUATION_NONE:
+ case ZCR_BLENDING_V1_BLENDING_EQUATION_NONE:
GetUserDataAs<Blending>(resource)->SetBlendMode(SkXfermode::kSrc_Mode);
break;
- case ZWP_BLENDING_V1_BLENDING_EQUATION_PREMULT:
+ case ZCR_BLENDING_V1_BLENDING_EQUATION_PREMULT:
GetUserDataAs<Blending>(resource)->SetBlendMode(
SkXfermode::kSrcOver_Mode);
break;
- case ZWP_BLENDING_V1_BLENDING_EQUATION_COVERAGE:
+ case ZCR_BLENDING_V1_BLENDING_EQUATION_COVERAGE:
NOTIMPLEMENTED();
break;
default:
@@ -2819,7 +2755,7 @@ void blending_set_alpha(wl_client* client,
GetUserDataAs<Blending>(resource)->SetAlpha(wl_fixed_to_double(alpha));
}
-const struct zwp_blending_v1_interface blending_implementation = {
+const struct zcr_blending_v1_interface blending_implementation = {
blending_destroy, blending_set_blending, blending_set_alpha};
////////////////////////////////////////////////////////////////////////////////
@@ -2836,19 +2772,19 @@ void alpha_compositing_get_blending(wl_client* client,
Surface* surface = GetUserDataAs<Surface>(surface_resource);
if (surface->GetProperty(kSurfaceHasBlendingKey)) {
wl_resource_post_error(resource,
- ZWP_ALPHA_COMPOSITING_V1_ERROR_BLENDING_EXISTS,
+ ZCR_ALPHA_COMPOSITING_V1_ERROR_BLENDING_EXISTS,
"a blending object for that surface already exists");
return;
}
wl_resource* blending_resource =
- wl_resource_create(client, &zwp_blending_v1_interface, 1, id);
+ wl_resource_create(client, &zcr_blending_v1_interface, 1, id);
SetImplementation(blending_resource, &blending_implementation,
- base::WrapUnique(new Blending(surface)));
+ base::MakeUnique<Blending>(surface));
}
-const struct zwp_alpha_compositing_v1_interface
+const struct zcr_alpha_compositing_v1_interface
alpha_compositing_implementation = {alpha_compositing_destroy,
alpha_compositing_get_blending};
@@ -2857,7 +2793,7 @@ void bind_alpha_compositing(wl_client* client,
uint32_t version,
uint32_t id) {
wl_resource* resource =
- wl_resource_create(client, &zwp_alpha_compositing_v1_interface, 1, id);
+ wl_resource_create(client, &zcr_alpha_compositing_v1_interface, 1, id);
wl_resource_set_implementation(resource, &alpha_compositing_implementation,
data, nullptr);
@@ -2880,23 +2816,23 @@ class WaylandGamepadDelegate : public GamepadDelegate {
wl_resource_get_client(surface_resource) == client();
}
void OnStateChange(bool connected) override {
- uint32_t status = connected ? ZWP_GAMEPAD_V1_GAMEPAD_STATE_ON
- : ZWP_GAMEPAD_V1_GAMEPAD_STATE_OFF;
- zwp_gamepad_v1_send_state_change(gamepad_resource_, status);
+ uint32_t status = connected ? ZCR_GAMEPAD_V1_GAMEPAD_STATE_ON
+ : ZCR_GAMEPAD_V1_GAMEPAD_STATE_OFF;
+ zcr_gamepad_v1_send_state_change(gamepad_resource_, status);
wl_client_flush(client());
}
void OnAxis(int axis, double value) override {
- zwp_gamepad_v1_send_axis(gamepad_resource_, NowInMilliseconds(), axis,
+ zcr_gamepad_v1_send_axis(gamepad_resource_, NowInMilliseconds(), axis,
wl_fixed_from_double(value));
}
void OnButton(int button, bool pressed, double value) override {
- uint32_t state = pressed ? ZWP_GAMEPAD_V1_BUTTON_STATE_PRESSED
- : ZWP_GAMEPAD_V1_BUTTON_STATE_RELEASED;
- zwp_gamepad_v1_send_button(gamepad_resource_, NowInMilliseconds(), button,
+ uint32_t state = pressed ? ZCR_GAMEPAD_V1_BUTTON_STATE_PRESSED
+ : ZCR_GAMEPAD_V1_BUTTON_STATE_RELEASED;
+ zcr_gamepad_v1_send_button(gamepad_resource_, NowInMilliseconds(), button,
state, wl_fixed_from_double(value));
}
void OnFrame() override {
- zwp_gamepad_v1_send_frame(gamepad_resource_, NowInMilliseconds());
+ zcr_gamepad_v1_send_frame(gamepad_resource_, NowInMilliseconds());
wl_client_flush(client());
}
@@ -2916,7 +2852,7 @@ void gamepad_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
-const struct zwp_gamepad_v1_interface gamepad_implementation = {
+const struct zcr_gamepad_v1_interface gamepad_implementation = {
gamepad_destroy};
void gaming_input_get_gamepad(wl_client* client,
@@ -2924,17 +2860,17 @@ void gaming_input_get_gamepad(wl_client* client,
uint32_t id,
wl_resource* seat) {
wl_resource* gamepad_resource = wl_resource_create(
- client, &zwp_gamepad_v1_interface, wl_resource_get_version(resource), id);
+ client, &zcr_gamepad_v1_interface, wl_resource_get_version(resource), id);
base::Thread* gaming_input_thread = GetUserDataAs<base::Thread>(resource);
SetImplementation(
gamepad_resource, &gamepad_implementation,
- base::WrapUnique(new Gamepad(new WaylandGamepadDelegate(gamepad_resource),
- gaming_input_thread->task_runner().get())));
+ base::MakeUnique<Gamepad>(new WaylandGamepadDelegate(gamepad_resource),
+ gaming_input_thread->task_runner().get()));
}
-const struct zwp_gaming_input_v1_interface gaming_input_implementation = {
+const struct zcr_gaming_input_v1_interface gaming_input_implementation = {
gaming_input_get_gamepad};
void bind_gaming_input(wl_client* client,
@@ -2942,7 +2878,7 @@ void bind_gaming_input(wl_client* client,
uint32_t version,
uint32_t id) {
wl_resource* resource =
- wl_resource_create(client, &zwp_gaming_input_v1_interface, version, id);
+ wl_resource_create(client, &zcr_gaming_input_v1_interface, version, id);
std::unique_ptr<base::Thread> gaming_input_thread(
new base::Thread("Exo gaming input polling thread."));
@@ -2968,18 +2904,20 @@ class WaylandPointerStylusDelegate : public PointerStylusDelegate {
}
void OnPointerDestroying(Pointer* pointer) override { pointer_ = nullptr; }
void OnPointerToolChange(ui::EventPointerType type) override {
- uint wayland_type = ZWP_POINTER_STYLUS_V1_TOOL_TYPE_MOUSE;
+ uint wayland_type = ZCR_POINTER_STYLUS_V1_TOOL_TYPE_MOUSE;
if (type == ui::EventPointerType::POINTER_TYPE_PEN)
- wayland_type = ZWP_POINTER_STYLUS_V1_TOOL_TYPE_PEN;
- zwp_pointer_stylus_v1_send_tool_change(resource_, wayland_type);
+ wayland_type = ZCR_POINTER_STYLUS_V1_TOOL_TYPE_PEN;
+ else if (type == ui::EventPointerType::POINTER_TYPE_ERASER)
+ wayland_type = ZCR_POINTER_STYLUS_V1_TOOL_TYPE_ERASER;
+ zcr_pointer_stylus_v1_send_tool_change(resource_, wayland_type);
}
void OnPointerForce(base::TimeTicks time_stamp, float force) override {
- zwp_pointer_stylus_v1_send_force(resource_,
+ zcr_pointer_stylus_v1_send_force(resource_,
TimeTicksToMilliseconds(time_stamp),
wl_fixed_from_double(force));
}
void OnPointerTilt(base::TimeTicks time_stamp, gfx::Vector2dF tilt) override {
- zwp_pointer_stylus_v1_send_tilt(
+ zcr_pointer_stylus_v1_send_tilt(
resource_, TimeTicksToMilliseconds(time_stamp),
wl_fixed_from_double(tilt.x()), wl_fixed_from_double(tilt.y()));
}
@@ -2998,7 +2936,7 @@ void pointer_stylus_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
-const struct zwp_pointer_stylus_v1_interface pointer_stylus_implementation = {
+const struct zcr_pointer_stylus_v1_interface pointer_stylus_implementation = {
pointer_stylus_destroy};
////////////////////////////////////////////////////////////////////////////////
@@ -3011,19 +2949,19 @@ void stylus_get_pointer_stylus(wl_client* client,
Pointer* pointer = GetUserDataAs<Pointer>(pointer_resource);
wl_resource* stylus_resource =
- wl_resource_create(client, &zwp_pointer_stylus_v1_interface, 1, id);
+ wl_resource_create(client, &zcr_pointer_stylus_v1_interface, 1, id);
- SetImplementation(stylus_resource, &pointer_stylus_implementation,
- base::WrapUnique(new WaylandPointerStylusDelegate(
- stylus_resource, pointer)));
+ SetImplementation(
+ stylus_resource, &pointer_stylus_implementation,
+ base::MakeUnique<WaylandPointerStylusDelegate>(stylus_resource, pointer));
}
-const struct zwp_stylus_v1_interface stylus_implementation = {
+const struct zcr_stylus_v1_interface stylus_implementation = {
stylus_get_pointer_stylus};
void bind_stylus(wl_client* client, void* data, uint32_t version, uint32_t id) {
wl_resource* resource =
- wl_resource_create(client, &zwp_stylus_v1_interface, version, id);
+ wl_resource_create(client, &zcr_stylus_v1_interface, version, id);
wl_resource_set_implementation(resource, &stylus_implementation, data,
nullptr);
}
@@ -3052,7 +2990,7 @@ Server::Server(Display* display)
display_, bind_output);
wl_global_create(wl_display_.get(), &xdg_shell_interface, 1, display_,
bind_xdg_shell);
- wl_global_create(wl_display_.get(), &zwp_vsync_feedback_v1_interface, 1,
+ wl_global_create(wl_display_.get(), &zcr_vsync_feedback_v1_interface, 1,
display_, bind_vsync_feedback);
wl_global_create(wl_display_.get(), &wl_data_device_manager_interface, 1,
display_, bind_data_device_manager);
@@ -3060,15 +2998,15 @@ Server::Server(Display* display)
display_, bind_seat);
wl_global_create(wl_display_.get(), &wp_viewporter_interface, 1, display_,
bind_viewporter);
- wl_global_create(wl_display_.get(), &zwp_secure_output_v1_interface, 1,
+ wl_global_create(wl_display_.get(), &zcr_secure_output_v1_interface, 1,
display_, bind_secure_output);
- wl_global_create(wl_display_.get(), &zwp_alpha_compositing_v1_interface, 1,
+ wl_global_create(wl_display_.get(), &zcr_alpha_compositing_v1_interface, 1,
display_, bind_alpha_compositing);
- wl_global_create(wl_display_.get(), &zwp_remote_shell_v1_interface,
+ wl_global_create(wl_display_.get(), &zcr_remote_shell_v1_interface,
remote_shell_version, display_, bind_remote_shell);
- wl_global_create(wl_display_.get(), &zwp_gaming_input_v1_interface, 1,
+ wl_global_create(wl_display_.get(), &zcr_gaming_input_v1_interface, 1,
display_, bind_gaming_input);
- wl_global_create(wl_display_.get(), &zwp_stylus_v1_interface, 1, display_,
+ wl_global_create(wl_display_.get(), &zcr_stylus_v1_interface, 1, display_,
bind_stylus);
}
diff --git a/chromium/components/exo/wayland/server_unittest.cc b/chromium/components/exo/wayland/server_unittest.cc
index f84e62fc07c..9ab42777723 100644
--- a/chromium/components/exo/wayland/server_unittest.cc
+++ b/chromium/components/exo/wayland/server_unittest.cc
@@ -37,7 +37,7 @@ class ServerTest : public testing::Test {
void SetUp() override {
ASSERT_TRUE(xdg_temp_dir_.CreateUniqueTempDir());
- setenv("XDG_RUNTIME_DIR", xdg_temp_dir_.path().MaybeAsASCII().c_str(),
+ setenv("XDG_RUNTIME_DIR", xdg_temp_dir_.GetPath().MaybeAsASCII().c_str(),
1 /* overwrite */);
testing::Test::SetUp();
}
diff --git a/chromium/components/exo/wm_helper.cc b/chromium/components/exo/wm_helper.cc
new file mode 100644
index 00000000000..6e4b495ba5c
--- /dev/null
+++ b/chromium/components/exo/wm_helper.cc
@@ -0,0 +1,97 @@
+// 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 "components/exo/wm_helper.h"
+
+#include "base/memory/ptr_util.h"
+
+namespace exo {
+namespace {
+WMHelper* g_instance = nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WMHelper, public:
+
+WMHelper::WMHelper() {}
+
+WMHelper::~WMHelper() {}
+
+// static
+void WMHelper::SetInstance(WMHelper* helper) {
+ DCHECK_NE(!!helper, !!g_instance);
+ g_instance = helper;
+}
+
+// static
+WMHelper* WMHelper::GetInstance() {
+ DCHECK(g_instance);
+ return g_instance;
+}
+
+void WMHelper::AddActivationObserver(ActivationObserver* observer) {
+ activation_observers_.AddObserver(observer);
+}
+
+void WMHelper::RemoveActivationObserver(ActivationObserver* observer) {
+ activation_observers_.RemoveObserver(observer);
+}
+
+void WMHelper::AddFocusObserver(FocusObserver* observer) {
+ focus_observers_.AddObserver(observer);
+}
+
+void WMHelper::RemoveFocusObserver(FocusObserver* observer) {
+ focus_observers_.RemoveObserver(observer);
+}
+
+void WMHelper::AddCursorObserver(CursorObserver* observer) {
+ cursor_observers_.AddObserver(observer);
+}
+
+void WMHelper::RemoveCursorObserver(CursorObserver* observer) {
+ cursor_observers_.RemoveObserver(observer);
+}
+
+void WMHelper::AddMaximizeModeObserver(MaximizeModeObserver* observer) {
+ maximize_mode_observers_.AddObserver(observer);
+}
+
+void WMHelper::RemoveMaximizeModeObserver(MaximizeModeObserver* observer) {
+ maximize_mode_observers_.RemoveObserver(observer);
+}
+
+void WMHelper::NotifyWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) {
+ FOR_EACH_OBSERVER(ActivationObserver, activation_observers_,
+ OnWindowActivated(gained_active, lost_active));
+}
+
+void WMHelper::NotifyWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) {
+ FOR_EACH_OBSERVER(FocusObserver, focus_observers_,
+ OnWindowFocused(gained_focus, lost_focus));
+}
+
+void WMHelper::NotifyCursorVisibilityChanged(bool is_visible) {
+ FOR_EACH_OBSERVER(CursorObserver, cursor_observers_,
+ OnCursorVisibilityChanged(is_visible));
+}
+
+void WMHelper::NotifyCursorSetChanged(ui::CursorSetType cursor_set) {
+ FOR_EACH_OBSERVER(CursorObserver, cursor_observers_,
+ OnCursorSetChanged(cursor_set));
+}
+
+void WMHelper::NotifyMaximizeModeStarted() {
+ FOR_EACH_OBSERVER(MaximizeModeObserver, maximize_mode_observers_,
+ OnMaximizeModeStarted());
+}
+
+void WMHelper::NotifyMaximizeModeEnded() {
+ FOR_EACH_OBSERVER(MaximizeModeObserver, maximize_mode_observers_,
+ OnMaximizeModeEnded());
+}
+
+} // namespace exo
diff --git a/chromium/components/exo/wm_helper.h b/chromium/components/exo/wm_helper.h
new file mode 100644
index 00000000000..69798803792
--- /dev/null
+++ b/chromium/components/exo/wm_helper.h
@@ -0,0 +1,115 @@
+// 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 COMPONENTS_EXO_WM_HELPER_H_
+#define COMPONENTS_EXO_WM_HELPER_H_
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "ui/base/cursor/cursor.h"
+
+namespace aura {
+class Window;
+}
+
+namespace display {
+class ManagedDisplayInfo;
+}
+
+namespace ui {
+class EventHandler;
+}
+
+namespace exo {
+
+// A helper class for accessing WindowManager related features.
+class WMHelper {
+ public:
+ class ActivationObserver {
+ public:
+ virtual void OnWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active) = 0;
+
+ protected:
+ virtual ~ActivationObserver() {}
+ };
+
+ class FocusObserver {
+ public:
+ virtual void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) = 0;
+
+ protected:
+ virtual ~FocusObserver() {}
+ };
+
+ class CursorObserver {
+ public:
+ virtual void OnCursorVisibilityChanged(bool is_visible) {}
+ virtual void OnCursorSetChanged(ui::CursorSetType cursor_set) {}
+
+ protected:
+ virtual ~CursorObserver() {}
+ };
+
+ class MaximizeModeObserver {
+ public:
+ virtual void OnMaximizeModeStarted() = 0;
+ virtual void OnMaximizeModeEnded() = 0;
+
+ protected:
+ virtual ~MaximizeModeObserver() {}
+ };
+
+ virtual ~WMHelper();
+
+ static void SetInstance(WMHelper* helper);
+ static WMHelper* GetInstance();
+
+ void AddActivationObserver(ActivationObserver* observer);
+ void RemoveActivationObserver(ActivationObserver* observer);
+ void AddFocusObserver(FocusObserver* observer);
+ void RemoveFocusObserver(FocusObserver* observer);
+ void AddCursorObserver(CursorObserver* observer);
+ void RemoveCursorObserver(CursorObserver* observer);
+ void AddMaximizeModeObserver(MaximizeModeObserver* observer);
+ void RemoveMaximizeModeObserver(MaximizeModeObserver* observer);
+
+ virtual const display::ManagedDisplayInfo GetDisplayInfo(
+ int64_t display_id) const = 0;
+ virtual aura::Window* GetContainer(int container_id) = 0;
+ virtual aura::Window* GetActiveWindow() const = 0;
+ virtual aura::Window* GetFocusedWindow() const = 0;
+ virtual ui::CursorSetType GetCursorSet() const = 0;
+ virtual void AddPreTargetHandler(ui::EventHandler* handler) = 0;
+ virtual void PrependPreTargetHandler(ui::EventHandler* handler) = 0;
+ virtual void RemovePreTargetHandler(ui::EventHandler* handler) = 0;
+ virtual void AddPostTargetHandler(ui::EventHandler* handler) = 0;
+ virtual void RemovePostTargetHandler(ui::EventHandler* handler) = 0;
+ virtual bool IsMaximizeModeWindowManagerEnabled() const = 0;
+
+ protected:
+ WMHelper();
+
+ void NotifyWindowActivated(aura::Window* gained_active,
+ aura::Window* lost_active);
+ void NotifyWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus);
+ void NotifyCursorVisibilityChanged(bool is_visible);
+ void NotifyCursorSetChanged(ui::CursorSetType cursor_set);
+ void NotifyMaximizeModeStarted();
+ void NotifyMaximizeModeEnded();
+
+ private:
+ base::ObserverList<ActivationObserver> activation_observers_;
+ base::ObserverList<FocusObserver> focus_observers_;
+ base::ObserverList<CursorObserver> cursor_observers_;
+ base::ObserverList<MaximizeModeObserver> maximize_mode_observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(WMHelper);
+};
+
+} // namespace exo
+
+#endif // COMPONENTS_EXO_WM_HELPER_H_
diff --git a/chromium/components/exo/wm_helper_ash.cc b/chromium/components/exo/wm_helper_ash.cc
new file mode 100644
index 00000000000..1a646132e12
--- /dev/null
+++ b/chromium/components/exo/wm_helper_ash.cc
@@ -0,0 +1,120 @@
+// 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 "components/exo/wm_helper_ash.h"
+
+#include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
+#include "ash/common/wm_shell.h"
+#include "ash/display/display_manager.h"
+#include "ash/shell.h"
+#include "base/memory/singleton.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/wm/public/activation_client.h"
+
+namespace exo {
+
+////////////////////////////////////////////////////////////////////////////////
+// WMHelperAsh, public:
+
+WMHelperAsh::WMHelperAsh() {
+ ash::WmShell::Get()->AddShellObserver(this);
+ ash::Shell::GetInstance()->activation_client()->AddObserver(this);
+ aura::client::FocusClient* focus_client =
+ aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
+ focus_client->AddObserver(this);
+}
+
+WMHelperAsh::~WMHelperAsh() {
+ if (!ash::Shell::HasInstance())
+ return;
+ aura::client::FocusClient* focus_client =
+ aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
+ focus_client->RemoveObserver(this);
+ ash::Shell::GetInstance()->activation_client()->RemoveObserver(this);
+ ash::WmShell::Get()->RemoveShellObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WMHelperAsh, private:
+
+const display::ManagedDisplayInfo WMHelperAsh::GetDisplayInfo(
+ int64_t display_id) const {
+ return ash::Shell::GetInstance()->display_manager()->GetDisplayInfo(
+ display_id);
+}
+
+aura::Window* WMHelperAsh::GetContainer(int container_id) {
+ return ash::Shell::GetContainer(ash::Shell::GetTargetRootWindow(),
+ container_id);
+}
+
+aura::Window* WMHelperAsh::GetActiveWindow() const {
+ return ash::Shell::GetInstance()->activation_client()->GetActiveWindow();
+}
+
+aura::Window* WMHelperAsh::GetFocusedWindow() const {
+ aura::client::FocusClient* focus_client =
+ aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
+ return focus_client->GetFocusedWindow();
+}
+
+ui::CursorSetType WMHelperAsh::GetCursorSet() const {
+ return ash::Shell::GetInstance()->cursor_manager()->GetCursorSet();
+}
+
+void WMHelperAsh::AddPreTargetHandler(ui::EventHandler* handler) {
+ ash::Shell::GetInstance()->AddPreTargetHandler(handler);
+}
+
+void WMHelperAsh::PrependPreTargetHandler(ui::EventHandler* handler) {
+ ash::Shell::GetInstance()->PrependPreTargetHandler(handler);
+}
+
+void WMHelperAsh::RemovePreTargetHandler(ui::EventHandler* handler) {
+ ash::Shell::GetInstance()->RemovePreTargetHandler(handler);
+}
+
+void WMHelperAsh::AddPostTargetHandler(ui::EventHandler* handler) {
+ ash::Shell::GetInstance()->AddPostTargetHandler(handler);
+}
+
+void WMHelperAsh::RemovePostTargetHandler(ui::EventHandler* handler) {
+ ash::Shell::GetInstance()->RemovePostTargetHandler(handler);
+}
+
+bool WMHelperAsh::IsMaximizeModeWindowManagerEnabled() const {
+ return ash::WmShell::Get()
+ ->maximize_mode_controller()
+ ->IsMaximizeModeWindowManagerEnabled();
+}
+
+void WMHelperAsh::OnWindowActivated(
+ aura::client::ActivationChangeObserver::ActivationReason reason,
+ aura::Window* gained_active,
+ aura::Window* lost_active) {
+ NotifyWindowActivated(gained_active, lost_active);
+}
+
+void WMHelperAsh::OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) {
+ NotifyWindowFocused(gained_focus, lost_focus);
+}
+
+void WMHelperAsh::OnCursorVisibilityChanged(bool is_visible) {
+ NotifyCursorVisibilityChanged(is_visible);
+}
+
+void WMHelperAsh::OnCursorSetChanged(ui::CursorSetType cursor_set) {
+ NotifyCursorSetChanged(cursor_set);
+}
+
+void WMHelperAsh::OnMaximizeModeStarted() {
+ NotifyMaximizeModeStarted();
+}
+
+void WMHelperAsh::OnMaximizeModeEnded() {
+ NotifyMaximizeModeEnded();
+}
+
+} // namespace exo
diff --git a/chromium/components/exo/wm_helper_ash.h b/chromium/components/exo/wm_helper_ash.h
new file mode 100644
index 00000000000..138b9642abc
--- /dev/null
+++ b/chromium/components/exo/wm_helper_ash.h
@@ -0,0 +1,65 @@
+// 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 COMPONENTS_EXO_WM_HELPER_ASH_H_
+#define COMPONENTS_EXO_WM_HELPER_ASH_H_
+
+#include "ash/common/shell_observer.h"
+#include "base/macros.h"
+#include "components/exo/wm_helper.h"
+#include "ui/aura/client/cursor_client_observer.h"
+#include "ui/aura/client/focus_change_observer.h"
+#include "ui/wm/public/activation_change_observer.h"
+
+namespace exo {
+
+// A helper class for accessing WindowManager related features.
+class WMHelperAsh : public WMHelper,
+ public aura::client::ActivationChangeObserver,
+ public aura::client::FocusChangeObserver,
+ public aura::client::CursorClientObserver,
+ public ash::ShellObserver {
+ public:
+ WMHelperAsh();
+ ~WMHelperAsh() override;
+
+ // Overriden from WMHelper:
+ const display::ManagedDisplayInfo GetDisplayInfo(
+ int64_t display_id) const override;
+ aura::Window* GetContainer(int container_id) override;
+ aura::Window* GetActiveWindow() const override;
+ aura::Window* GetFocusedWindow() const override;
+ ui::CursorSetType GetCursorSet() const override;
+ void AddPreTargetHandler(ui::EventHandler* handler) override;
+ void PrependPreTargetHandler(ui::EventHandler* handler) override;
+ void RemovePreTargetHandler(ui::EventHandler* handler) override;
+ void AddPostTargetHandler(ui::EventHandler* handler) override;
+ void RemovePostTargetHandler(ui::EventHandler* handler) override;
+ bool IsMaximizeModeWindowManagerEnabled() const override;
+
+ // Overriden from aura::client::ActivationChangeObserver:
+ void OnWindowActivated(
+ aura::client::ActivationChangeObserver::ActivationReason reason,
+ aura::Window* gained_active,
+ aura::Window* lost_active) override;
+
+ // Overriden from aura::client::FocusChangeObserver:
+ void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) override;
+
+ // Overriden from aura::client::CursorClientObserver:
+ void OnCursorVisibilityChanged(bool is_visible) override;
+ void OnCursorSetChanged(ui::CursorSetType cursor_set) override;
+
+ // Overriden from ash::ShellObserver:
+ void OnMaximizeModeStarted() override;
+ void OnMaximizeModeEnded() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WMHelperAsh);
+};
+
+} // namespace exo
+
+#endif // COMPONENTS_EXO_WM_HELPER_H_
diff --git a/chromium/components/exo/wm_helper_mus.cc b/chromium/components/exo/wm_helper_mus.cc
new file mode 100644
index 00000000000..3f36dbd83ec
--- /dev/null
+++ b/chromium/components/exo/wm_helper_mus.cc
@@ -0,0 +1,142 @@
+// 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 "components/exo/wm_helper_mus.h"
+
+#include "services/ui/public/cpp/window_tree_client.h"
+#include "ui/aura/client/focus_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/display/manager/managed_display_info.h"
+#include "ui/views/mus/native_widget_mus.h"
+#include "ui/views/mus/window_manager_connection.h"
+#include "ui/views/widget/widget.h"
+
+namespace exo {
+namespace {
+
+aura::Window* GetToplevelAuraWindow(ui::Window* window) {
+ DCHECK(window);
+ // We never create child ui::Window, so window->parent() should be null.
+ DCHECK(!window->parent());
+ views::Widget* widget = views::NativeWidgetMus::GetWidgetForWindow(window);
+ if (!widget)
+ return nullptr;
+ return widget->GetNativeWindow();
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// WMHelperMus, public:
+
+WMHelperMus::WMHelperMus()
+ : active_window_(WMHelperMus::GetActiveWindow()),
+ focused_window_(WMHelperMus::GetFocusedWindow()) {
+ views::WindowManagerConnection::Get()->client()->AddObserver(this);
+}
+
+WMHelperMus::~WMHelperMus() {
+ views::WindowManagerConnection::Get()->client()->RemoveObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WMHelperMus, private:
+
+const display::ManagedDisplayInfo WMHelperMus::GetDisplayInfo(
+ int64_t display_id) const {
+ // TODO(penghuang): Return real display info when it is supported in mus.
+ return display::ManagedDisplayInfo(display_id, "", false);
+}
+
+aura::Window* WMHelperMus::GetContainer(int container_id) {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+aura::Window* WMHelperMus::GetActiveWindow() const {
+ ui::Window* window =
+ views::WindowManagerConnection::Get()->client()->GetFocusedWindow();
+ return window ? GetToplevelAuraWindow(window) : nullptr;
+}
+
+aura::Window* WMHelperMus::GetFocusedWindow() const {
+ aura::Window* active_window = GetActiveWindow();
+ if (!active_window)
+ return nullptr;
+ aura::client::FocusClient* focus_client =
+ aura::client::GetFocusClient(active_window);
+ return focus_client->GetFocusedWindow();
+}
+
+ui::CursorSetType WMHelperMus::GetCursorSet() const {
+ NOTIMPLEMENTED();
+ return ui::CursorSetType::CURSOR_SET_NORMAL;
+}
+
+void WMHelperMus::AddPreTargetHandler(ui::EventHandler* handler) {
+ aura::Env::GetInstance()->AddPreTargetHandler(handler);
+}
+
+void WMHelperMus::PrependPreTargetHandler(ui::EventHandler* handler) {
+ aura::Env::GetInstance()->PrependPreTargetHandler(handler);
+}
+
+void WMHelperMus::RemovePreTargetHandler(ui::EventHandler* handler) {
+ aura::Env::GetInstance()->RemovePreTargetHandler(handler);
+}
+
+void WMHelperMus::AddPostTargetHandler(ui::EventHandler* handler) {
+ aura::Env::GetInstance()->AddPostTargetHandler(handler);
+}
+
+void WMHelperMus::RemovePostTargetHandler(ui::EventHandler* handler) {
+ aura::Env::GetInstance()->RemovePostTargetHandler(handler);
+}
+
+bool WMHelperMus::IsMaximizeModeWindowManagerEnabled() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void WMHelperMus::OnWindowTreeFocusChanged(ui::Window* gained_focus,
+ ui::Window* lost_focus) {
+ aura::Window* gained_active =
+ gained_focus ? GetToplevelAuraWindow(gained_focus) : nullptr;
+ aura::Window* lost_active =
+ lost_focus ? GetToplevelAuraWindow(lost_focus) : nullptr;
+
+ // Because NativeWidgetMus uses separate FocusClient for every toplevel
+ // window, we have to stop observering the FocusClient of the |lost_active|
+ // and start observering the FocusClient of the |gained_active|.
+ if (active_window_) {
+ aura::client::FocusClient* focus_client =
+ aura::client::GetFocusClient(active_window_);
+ focus_client->RemoveObserver(this);
+ }
+
+ active_window_ = gained_active;
+ NotifyWindowActivated(gained_active, lost_active);
+
+ aura::Window* focused_window = nullptr;
+ if (active_window_) {
+ aura::client::FocusClient* focus_client =
+ aura::client::GetFocusClient(active_window_);
+ focus_client->AddObserver(this);
+ focused_window = focus_client->GetFocusedWindow();
+ }
+
+ // OnWindowFocused() will update |focused_window_|.
+ OnWindowFocused(focused_window, focused_window_);
+}
+
+void WMHelperMus::OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) {
+ if (focused_window_ != gained_focus) {
+ focused_window_ = gained_focus;
+ NotifyWindowFocused(gained_focus, lost_focus);
+ }
+}
+
+} // namespace exo
diff --git a/chromium/components/exo/wm_helper_mus.h b/chromium/components/exo/wm_helper_mus.h
new file mode 100644
index 00000000000..b4f8ea24abd
--- /dev/null
+++ b/chromium/components/exo/wm_helper_mus.h
@@ -0,0 +1,54 @@
+// 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 COMPONENTS_EXO_WM_HELPER_MUS_H_
+#define COMPONENTS_EXO_WM_HELPER_MUS_H_
+
+#include "base/macros.h"
+#include "components/exo/wm_helper.h"
+#include "services/ui/public/cpp/window_tree_client_observer.h"
+#include "ui/aura/client/focus_change_observer.h"
+
+namespace exo {
+
+// A helper class for accessing WindowManager related features.
+class WMHelperMus : public WMHelper,
+ public ui::WindowTreeClientObserver,
+ public aura::client::FocusChangeObserver {
+ public:
+ WMHelperMus();
+ ~WMHelperMus() override;
+
+ // Overriden from WMHelper:
+ const display::ManagedDisplayInfo GetDisplayInfo(
+ int64_t display_id) const override;
+ aura::Window* GetContainer(int container_id) override;
+ aura::Window* GetActiveWindow() const override;
+ aura::Window* GetFocusedWindow() const override;
+ ui::CursorSetType GetCursorSet() const override;
+ void AddPreTargetHandler(ui::EventHandler* handler) override;
+ void PrependPreTargetHandler(ui::EventHandler* handler) override;
+ void RemovePreTargetHandler(ui::EventHandler* handler) override;
+ void AddPostTargetHandler(ui::EventHandler* handler) override;
+ void RemovePostTargetHandler(ui::EventHandler* handler) override;
+ bool IsMaximizeModeWindowManagerEnabled() const override;
+
+ // Overriden from ui::WindowTreeClientObserver:
+ void OnWindowTreeFocusChanged(ui::Window* gained_focus,
+ ui::Window* lost_focus) override;
+
+ // Overriden from ui::client::FocusChangeObserver:
+ void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) override;
+
+ private:
+ aura::Window* active_window_;
+ aura::Window* focused_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(WMHelperMus);
+};
+
+} // namespace exo
+
+#endif // COMPONENTS_EXO_WM_HELPER_H_
diff --git a/chromium/components/external_video_surface.gypi b/chromium/components/external_video_surface.gypi
deleted file mode 100644
index b6abe3dcd92..00000000000
--- a/chromium/components/external_video_surface.gypi
+++ /dev/null
@@ -1,49 +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.
-
-{
- 'variables': {
- 'chromium_code': 1
- },
- 'targets': [
- {
- 'target_name': 'external_video_surface',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- 'external_video_surface_jni_headers',
- ],
- 'sources': [
- 'external_video_surface/browser/android/external_video_surface_container_impl.cc',
- 'external_video_surface/browser/android/external_video_surface_container_impl.h',
- 'external_video_surface/component_jni_registrar.cc',
- 'external_video_surface/component_jni_registrar.h',
- ],
- },
- {
- 'target_name': 'external_video_surface_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_java',
- ],
- 'variables': {
- 'java_in_dir': 'external_video_surface/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'external_video_surface_jni_headers',
- 'type': 'none',
- 'sources': [
- 'external_video_surface/android/java/src/org/chromium/components/external_video_surface/ExternalVideoSurfaceContainer.java',
- ],
- 'variables': {
- 'jni_gen_package': 'external_video_surface',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- ],
-}
diff --git a/chromium/components/external_video_surface/BUILD.gn b/chromium/components/external_video_surface/BUILD.gn
deleted file mode 100644
index f8d45345005..00000000000
--- a/chromium/components/external_video_surface/BUILD.gn
+++ /dev/null
@@ -1,41 +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.
-
-if (is_android) {
- import("//build/config/android/rules.gni")
-}
-
-source_set("external_video_surface") {
- if (is_android) {
- sources = [
- "browser/android/external_video_surface_container_impl.cc",
- "browser/android/external_video_surface_container_impl.h",
- "component_jni_registrar.cc",
- "component_jni_registrar.h",
- ]
-
- deps = [
- ":jni_headers",
- "//base",
- "//content/public/browser",
- "//ui/gfx/geometry",
- ]
- }
-}
-
-if (is_android) {
- android_library("java") {
- java_files = [ "android/java/src/org/chromium/components/external_video_surface/ExternalVideoSurfaceContainer.java" ]
- deps = [
- "//base:base_java",
- "//content/public/android:content_java",
- ]
- }
- generate_jni("jni_headers") {
- sources = [
- "android/java/src/org/chromium/components/external_video_surface/ExternalVideoSurfaceContainer.java",
- ]
- jni_package = "external_video_surface"
- }
-}
diff --git a/chromium/components/external_video_surface/DEPS b/chromium/components/external_video_surface/DEPS
deleted file mode 100644
index f9011b66fc3..00000000000
--- a/chromium/components/external_video_surface/DEPS
+++ /dev/null
@@ -1,6 +0,0 @@
-include_rules = [
- "+content/public/android/java/src/org/chromium/content/browser",
- "+content/public/browser/android",
- "+jni",
- "+ui/gfx/geometry",
-]
diff --git a/chromium/components/external_video_surface/OWNERS b/chromium/components/external_video_surface/OWNERS
deleted file mode 100644
index c77681b5136..00000000000
--- a/chromium/components/external_video_surface/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-boliu@chromium.org
-qinmin@chromium.org
diff --git a/chromium/components/external_video_surface/browser/android/external_video_surface_container_impl.cc b/chromium/components/external_video_surface/browser/android/external_video_surface_container_impl.cc
deleted file mode 100644
index cac766d3cc9..00000000000
--- a/chromium/components/external_video_surface/browser/android/external_video_surface_container_impl.cc
+++ /dev/null
@@ -1,118 +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 "components/external_video_surface/browser/android/external_video_surface_container_impl.h"
-
-#include "base/android/jni_android.h"
-#include "content/public/browser/android/content_view_core.h"
-#include "jni/ExternalVideoSurfaceContainer_jni.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-using base::android::AttachCurrentThread;
-using content::ContentViewCore;
-
-namespace external_video_surface {
-
-// static
-bool ExternalVideoSurfaceContainerImpl::RegisterJni(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-// static
-ExternalVideoSurfaceContainerImpl* ExternalVideoSurfaceContainerImpl::Create(
- content::WebContents* web_contents) {
- ContentViewCore* cvc = ContentViewCore::FromWebContents(web_contents);
- if (!cvc)
- return nullptr;
- base::android::ScopedJavaLocalRef<jobject> jcvc = cvc->GetJavaObject();
- if (jcvc.is_null())
- return nullptr;
- return new ExternalVideoSurfaceContainerImpl(jcvc);
-}
-
-ExternalVideoSurfaceContainerImpl::ExternalVideoSurfaceContainerImpl(
- base::android::ScopedJavaLocalRef<jobject> java_content_view_core) {
- JNIEnv* env = AttachCurrentThread();
- jobject_.Reset(Java_ExternalVideoSurfaceContainer_create(
- env, reinterpret_cast<intptr_t>(this), java_content_view_core.obj()));
-}
-
-ExternalVideoSurfaceContainerImpl::~ExternalVideoSurfaceContainerImpl() {
- JNIEnv* env = AttachCurrentThread();
- Java_ExternalVideoSurfaceContainer_destroy(env, jobject_.obj());
- jobject_.Reset();
-}
-
-void ExternalVideoSurfaceContainerImpl::RequestExternalVideoSurface(
- int player_id,
- const SurfaceCreatedCB& surface_created_cb,
- const SurfaceDestroyedCB& surface_destroyed_cb) {
- surface_created_cb_ = surface_created_cb;
- surface_destroyed_cb_ = surface_destroyed_cb;
-
- JNIEnv* env = AttachCurrentThread();
- Java_ExternalVideoSurfaceContainer_requestExternalVideoSurface(
- env, jobject_.obj(), static_cast<jint>(player_id));
-}
-
-int ExternalVideoSurfaceContainerImpl::GetCurrentPlayerId() {
- JNIEnv* env = AttachCurrentThread();
-
- int current_player = static_cast<int>(
- Java_ExternalVideoSurfaceContainer_getCurrentPlayerId(
- env, jobject_.obj()));
-
- if (current_player < 0)
- return kInvalidPlayerId;
- else
- return current_player;
-}
-
-void ExternalVideoSurfaceContainerImpl::ReleaseExternalVideoSurface(
- int player_id) {
- JNIEnv* env = AttachCurrentThread();
- Java_ExternalVideoSurfaceContainer_releaseExternalVideoSurface(
- env, jobject_.obj(), static_cast<jint>(player_id));
-
- surface_created_cb_.Reset();
- surface_destroyed_cb_.Reset();
-}
-
-void ExternalVideoSurfaceContainerImpl::OnFrameInfoUpdated() {
- JNIEnv* env = AttachCurrentThread();
- Java_ExternalVideoSurfaceContainer_onFrameInfoUpdated(env, jobject_.obj());
-}
-
-void ExternalVideoSurfaceContainerImpl::OnExternalVideoSurfacePositionChanged(
- int player_id, const gfx::RectF& rect) {
- JNIEnv* env = AttachCurrentThread();
- Java_ExternalVideoSurfaceContainer_onExternalVideoSurfacePositionChanged(
- env,
- jobject_.obj(),
- static_cast<jint>(player_id),
- static_cast<jfloat>(rect.x()),
- static_cast<jfloat>(rect.y()),
- static_cast<jfloat>(rect.x() + rect.width()),
- static_cast<jfloat>(rect.y() + rect.height()));
-}
-
-// Methods called from Java.
-void ExternalVideoSurfaceContainerImpl::SurfaceCreated(
- JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- jint player_id,
- const JavaParamRef<jobject>& jsurface) {
- if (!surface_created_cb_.is_null())
- surface_created_cb_.Run(static_cast<int>(player_id), jsurface);
-}
-
-void ExternalVideoSurfaceContainerImpl::SurfaceDestroyed(
- JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- jint player_id) {
- if (!surface_destroyed_cb_.is_null())
- surface_destroyed_cb_.Run(static_cast<int>(player_id));
-}
-
-} // namespace external_video_surface
diff --git a/chromium/components/external_video_surface/browser/android/external_video_surface_container_impl.h b/chromium/components/external_video_surface/browser/android/external_video_surface_container_impl.h
deleted file mode 100644
index 280628f025e..00000000000
--- a/chromium/components/external_video_surface/browser/android/external_video_surface_container_impl.h
+++ /dev/null
@@ -1,64 +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 COMPONENTS_EXTERNAL_VIDEO_SURFACE_EXTERNAL_VIDEO_SURFACE_CONTAINER_IMPL_H_
-#define COMPONENTS_EXTERNAL_VIDEO_SURFACE_EXTERNAL_VIDEO_SURFACE_CONTAINER_IMPL_H_
-
-#include <jni.h>
-
-#include "base/android/scoped_java_ref.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "content/public/browser/android/external_video_surface_container.h"
-
-namespace external_video_surface {
-
-class ExternalVideoSurfaceContainerImpl
- : public content::ExternalVideoSurfaceContainer {
- public:
- static bool RegisterJni(JNIEnv* env);
-
- typedef base::Callback<void(int, jobject)> SurfaceCreatedCB;
- typedef base::Callback<void(int)> SurfaceDestroyedCB;
-
- static ExternalVideoSurfaceContainerImpl* Create(
- content::WebContents* web_contents);
-
- // content::ExternalVideoSurfaceContainer implementation.
- void RequestExternalVideoSurface(
- int player_id,
- const SurfaceCreatedCB& surface_created_cb,
- const SurfaceDestroyedCB& surface_destroyed_cb) override;
- int GetCurrentPlayerId() override;
- void ReleaseExternalVideoSurface(int player_id) override;
- void OnFrameInfoUpdated() override;
- void OnExternalVideoSurfacePositionChanged(int player_id,
- const gfx::RectF& rect) override;
-
- // Methods called from Java.
- void SurfaceCreated(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj,
- jint player_id,
- const base::android::JavaParamRef<jobject>& jsurface);
- void SurfaceDestroyed(JNIEnv* env,
- const base::android::JavaParamRef<jobject>& obj,
- jint player_id);
-
- private:
- explicit ExternalVideoSurfaceContainerImpl(
- base::android::ScopedJavaLocalRef<jobject> java_content_view_core);
- ~ExternalVideoSurfaceContainerImpl() override;
-
- base::android::ScopedJavaGlobalRef<jobject> jobject_;
-
- SurfaceCreatedCB surface_created_cb_;
- SurfaceDestroyedCB surface_destroyed_cb_;
-
- DISALLOW_COPY_AND_ASSIGN(ExternalVideoSurfaceContainerImpl);
-};
-
-} // namespace external_video_surface
-
-#endif // COMPONENTS_EXTERNAL_VIDEO_SURFACE_EXTERNAL_VIDEO_SURFACE_CONTAINER_IMPL_H_
diff --git a/chromium/components/favicon.gypi b/chromium/components/favicon.gypi
deleted file mode 100644
index 9d9ffb60951..00000000000
--- a/chromium/components/favicon.gypi
+++ /dev/null
@@ -1,112 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/favicon/core
- 'target_name': 'favicon_core',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../skia/skia.gyp:skia',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx',
- '../url/url.gyp:url_lib',
- 'bookmarks_browser',
- 'favicon_base',
- 'history_core_browser',
- 'keyed_service_core',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'favicon/core/fallback_url_util.cc',
- 'favicon/core/fallback_url_util.h',
- 'favicon/core/favicon_client.h',
- 'favicon/core/favicon_driver.cc',
- 'favicon/core/favicon_driver.h',
- 'favicon/core/favicon_driver_impl.cc',
- 'favicon/core/favicon_driver_impl.h',
- 'favicon/core/favicon_driver_observer.h',
- 'favicon/core/favicon_handler.cc',
- 'favicon/core/favicon_handler.h',
- 'favicon/core/favicon_service.cc',
- 'favicon/core/favicon_service.h',
- 'favicon/core/favicon_url.cc',
- 'favicon/core/favicon_url.h',
- 'favicon/core/favicon_util.cc',
- 'favicon/core/favicon_util.h',
- 'favicon/core/large_icon_service.cc',
- 'favicon/core/large_icon_service.h',
- ],
- 'include_dirs': [
- '..',
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'sources': [
- 'favicon/core/fallback_icon_client.h',
- 'favicon/core/fallback_icon_service.cc',
- 'favicon/core/fallback_icon_service.h',
- ],
- }],
- ],
- },
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'targets': [
- {
- # GN version: //components/favicon/content
- 'target_name': 'favicon_content',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../ui/gfx/gfx.gyp:gfx',
- 'favicon_base',
- 'favicon_core',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'favicon/content/content_favicon_driver.cc',
- 'favicon/content/content_favicon_driver.h',
- 'favicon/content/favicon_url_util.cc',
- 'favicon/content/favicon_url_util.h',
- ],
- 'include_dirs': [
- '..',
- ],
- },
- ],
- }],
- ['OS=="ios"', {
- 'targets': [
- {
- # GN version: //components/favicon/ios
- 'target_name': 'favicon_ios',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../ios/web/ios_web.gyp:ios_web',
- '../ui/gfx/gfx.gyp:gfx',
- 'favicon_base',
- 'favicon_core',
- ],
- 'sources': [
- 'favicon/ios/favicon_url_util.cc',
- 'favicon/ios/favicon_url_util.h',
- 'favicon/ios/web_favicon_driver.h',
- 'favicon/ios/web_favicon_driver.mm',
- ],
- 'include_dirs': [
- '..',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/favicon/content/BUILD.gn b/chromium/components/favicon/content/BUILD.gn
index 887fe9d68d7..a6ec44d2c67 100644
--- a/chromium/components/favicon/content/BUILD.gn
+++ b/chromium/components/favicon/content/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("content") {
+static_library("content") {
sources = [
"content_favicon_driver.cc",
"content_favicon_driver.h",
@@ -11,11 +11,11 @@ source_set("content") {
]
public_deps = [
+ "//components/favicon/core",
"//ui/gfx",
]
deps = [
"//base",
- "//components/favicon/core",
"//components/favicon_base",
"//components/history/core/browser",
"//content/public/browser",
diff --git a/chromium/components/favicon/content/content_favicon_driver.cc b/chromium/components/favicon/content/content_favicon_driver.cc
index 413517ad0da..dfc40d4e1ba 100644
--- a/chromium/components/favicon/content/content_favicon_driver.cc
+++ b/chromium/components/favicon/content/content_favicon_driver.cc
@@ -164,15 +164,13 @@ void ContentFaviconDriver::DidUpdateFaviconURL(
void ContentFaviconDriver::DidStartNavigationToPendingEntry(
const GURL& url,
- content::NavigationController::ReloadType reload_type) {
- if (reload_type == content::NavigationController::NO_RELOAD ||
- IsOffTheRecord())
+ content::ReloadType reload_type) {
+ if (reload_type == content::ReloadType::NONE || IsOffTheRecord())
return;
bypass_cache_page_url_ = url;
SetFaviconOutOfDateForPage(
- url,
- reload_type == content::NavigationController::RELOAD_BYPASSING_CACHE);
+ url, reload_type == content::ReloadType::BYPASSING_CACHE);
}
void ContentFaviconDriver::DidNavigateMainFrame(
diff --git a/chromium/components/favicon/content/content_favicon_driver.h b/chromium/components/favicon/content/content_favicon_driver.h
index 3405c67a077..70d3c4fdacf 100644
--- a/chromium/components/favicon/content/content_favicon_driver.h
+++ b/chromium/components/favicon/content/content_favicon_driver.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "components/favicon/core/favicon_driver_impl.h"
+#include "content/public/browser/reload_type.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "url/gurl.h"
@@ -72,7 +73,7 @@ class ContentFaviconDriver
const std::vector<content::FaviconURL>& candidates) override;
void DidStartNavigationToPendingEntry(
const GURL& url,
- content::NavigationController::ReloadType reload_type) override;
+ content::ReloadType reload_type) override;
void DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) override;
diff --git a/chromium/components/favicon/core/BUILD.gn b/chromium/components/favicon/core/BUILD.gn
index c461d543342..41aa876b07b 100644
--- a/chromium/components/favicon/core/BUILD.gn
+++ b/chromium/components/favicon/core/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("core") {
+static_library("core") {
sources = [
"fallback_url_util.cc",
"fallback_url_util.h",
diff --git a/chromium/components/favicon/core/favicon_service.cc b/chromium/components/favicon/core/favicon_service.cc
index e9d081fd37b..57a29deaf5f 100644
--- a/chromium/components/favicon/core/favicon_service.cc
+++ b/chromium/components/favicon/core/favicon_service.cc
@@ -11,6 +11,7 @@
#include "base/hash.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
#include "components/favicon/core/favicon_client.h"
#include "components/favicon_base/favicon_util.h"
#include "components/favicon_base/select_favicon_frames.h"
@@ -69,6 +70,7 @@ base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
const GURL& icon_url,
const favicon_base::FaviconImageCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "FaviconService::GetFaviconImage");
favicon_base::FaviconResultsCallback callback_runner =
base::Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
base::Unretained(this), callback, gfx::kFaviconSize);
@@ -91,6 +93,7 @@ base::CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
int desired_size_in_pixel,
const favicon_base::FaviconRawBitmapCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "FaviconService::GetRawFavicon");
favicon_base::FaviconResultsCallback callback_runner =
base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
base::Unretained(this), callback, desired_size_in_pixel);
@@ -113,6 +116,7 @@ base::CancelableTaskTracker::TaskId FaviconService::GetFavicon(
int desired_size_in_dip,
const favicon_base::FaviconResultsCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "FaviconService::GetFavicon");
if (history_service_) {
std::vector<GURL> icon_urls;
icon_urls.push_back(icon_url);
@@ -130,6 +134,7 @@ base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForPageURL(
const GURL& page_url,
const favicon_base::FaviconImageCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "FaviconService::GetFaviconImageForPageURL");
return GetFaviconForPageURLImpl(
page_url, favicon_base::FAVICON,
GetPixelSizesForFaviconScales(gfx::kFaviconSize),
@@ -144,6 +149,7 @@ base::CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForPageURL(
int desired_size_in_pixel,
const favicon_base::FaviconRawBitmapCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "FaviconService::GetRawFaviconForPageURL");
std::vector<int> desired_sizes_in_pixel;
desired_sizes_in_pixel.push_back(desired_size_in_pixel);
return GetFaviconForPageURLImpl(
@@ -160,6 +166,7 @@ FaviconService::GetLargestRawFaviconForPageURL(
int minimum_size_in_pixels,
const favicon_base::FaviconRawBitmapCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "FaviconService::GetLargestRawFaviconForPageURL");
favicon_base::FaviconResultsCallback favicon_results_callback =
base::Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
base::Unretained(this), callback, 0);
@@ -182,6 +189,7 @@ base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURL(
int desired_size_in_dip,
const favicon_base::FaviconResultsCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "FaviconService::GetFaviconForPageURL");
return GetFaviconForPageURLImpl(
page_url,
icon_types,
@@ -214,6 +222,7 @@ base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID(
favicon_base::FaviconID favicon_id,
const favicon_base::FaviconRawBitmapCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "FaviconService::GetLargestRawFaviconForID");
// Use 0 as |desired_size| to get the largest bitmap for |favicon_id| without
// any resizing.
int desired_size = 0;
@@ -314,6 +323,8 @@ void FaviconService::RunFaviconImageCallbackWithBitmapResults(
int desired_size_in_dip,
const std::vector<favicon_base::FaviconRawBitmapResult>&
favicon_bitmap_results) {
+ TRACE_EVENT0("browser",
+ "FaviconService::RunFaviconImageCallbackWithBitmapResults");
favicon_base::FaviconImageResult image_result;
image_result.image = favicon_base::SelectFaviconFramesFromPNGs(
favicon_bitmap_results,
@@ -331,46 +342,10 @@ void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults(
int desired_size_in_pixel,
const std::vector<favicon_base::FaviconRawBitmapResult>&
favicon_bitmap_results) {
- if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) {
- callback.Run(favicon_base::FaviconRawBitmapResult());
- return;
- }
-
- favicon_base::FaviconRawBitmapResult bitmap_result =
- favicon_bitmap_results[0];
-
- // If the desired size is 0, SelectFaviconFrames() will return the largest
- // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
- // data for a single bitmap, return it and avoid an unnecessary decode.
- if (desired_size_in_pixel == 0) {
- callback.Run(bitmap_result);
- return;
- }
-
- // If history bitmap is already desired pixel size, return early.
- if (bitmap_result.pixel_size.width() == desired_size_in_pixel &&
- bitmap_result.pixel_size.height() == desired_size_in_pixel) {
- callback.Run(bitmap_result);
- return;
- }
-
- // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
- // convert back.
- std::vector<float> desired_favicon_scales;
- desired_favicon_scales.push_back(1.0f);
- gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs(
- favicon_bitmap_results, desired_favicon_scales, desired_size_in_pixel);
-
- std::vector<unsigned char> resized_bitmap_data;
- if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
- &resized_bitmap_data)) {
- callback.Run(favicon_base::FaviconRawBitmapResult());
- return;
- }
-
- bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
- &resized_bitmap_data);
- callback.Run(bitmap_result);
+ TRACE_EVENT0("browser",
+ "FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults");
+ callback.Run(
+ ResizeFaviconBitmapResult(favicon_bitmap_results, desired_size_in_pixel));
}
} // namespace favicon
diff --git a/chromium/components/favicon/core/large_icon_service_unittest.cc b/chromium/components/favicon/core/large_icon_service_unittest.cc
index 4775eaff067..e3bc5f9c560 100644
--- a/chromium/components/favicon/core/large_icon_service_unittest.cc
+++ b/chromium/components/favicon/core/large_icon_service_unittest.cc
@@ -13,6 +13,7 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/task/cancelable_task_tracker.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "components/favicon/core/favicon_client.h"
#include "components/favicon/core/favicon_service.h"
#include "components/favicon_base/fallback_icon_style.h"
@@ -71,9 +72,8 @@ class MockFaviconService : public FaviconService {
favicon_base::FaviconRawBitmapResult mock_result =
mock_result_queue_.front();
mock_result_queue_.pop_front();
- return tracker->PostTask(
- base::MessageLoop::current()->task_runner().get(), FROM_HERE,
- base::Bind(callback, mock_result));
+ return tracker->PostTask(base::ThreadTaskRunnerHandle::Get().get(),
+ FROM_HERE, base::Bind(callback, mock_result));
}
void InjectResult(const favicon_base::FaviconRawBitmapResult& mock_result) {
@@ -96,7 +96,7 @@ class TestLargeIconService : public LargeIconService {
public:
explicit TestLargeIconService(MockFaviconService* mock_favicon_service)
: LargeIconService(mock_favicon_service,
- base::MessageLoop::current()->task_runner()) {}
+ base::ThreadTaskRunnerHandle::Get()) {}
~TestLargeIconService() override {
}
@@ -213,6 +213,7 @@ TEST_F(LargeIconServiceTest, FallbackSinceIconTooSmall) {
mock_favicon_service_->InjectResult(CreateTestBitmap(16, 16, kTestColor));
expected_fallback_icon_style_.reset(new favicon_base::FallbackIconStyle);
expected_fallback_icon_style_->background_color = kTestColor;
+ expected_fallback_icon_style_->is_default_background_color = false;
large_icon_service_->GetLargeIconOrFallbackStyle(
GURL(kDummyUrl),
24,
@@ -227,6 +228,7 @@ TEST_F(LargeIconServiceTest, FallbackSinceIconNotSquare) {
mock_favicon_service_->InjectResult(CreateTestBitmap(24, 32, kTestColor));
expected_fallback_icon_style_.reset(new favicon_base::FallbackIconStyle);
expected_fallback_icon_style_->background_color = kTestColor;
+ expected_fallback_icon_style_->is_default_background_color = false;
large_icon_service_->GetLargeIconOrFallbackStyle(
GURL(kDummyUrl),
24,
@@ -271,6 +273,7 @@ TEST_F(LargeIconServiceTest, FallbackSinceTooPicky) {
mock_favicon_service_->InjectResult(CreateTestBitmap(24, 24, kTestColor));
expected_fallback_icon_style_.reset(new favicon_base::FallbackIconStyle);
expected_fallback_icon_style_->background_color = kTestColor;
+ expected_fallback_icon_style_->is_default_background_color = false;
large_icon_service_->GetLargeIconOrFallbackStyle(
GURL(kDummyUrl),
32,
diff --git a/chromium/components/favicon_base.gypi b/chromium/components/favicon_base.gypi
deleted file mode 100644
index b969e54918b..00000000000
--- a/chromium/components/favicon_base.gypi
+++ /dev/null
@@ -1,45 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/favicon_base
- 'target_name': 'favicon_base',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/base/ui_base.gyp:ui_data_pack',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/gfx.gyp:gfx_geometry',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'favicon_base/fallback_icon_style.cc',
- 'favicon_base/fallback_icon_style.h',
- 'favicon_base/fallback_icon_url_parser.cc',
- 'favicon_base/fallback_icon_url_parser.h',
- 'favicon_base/favicon_callback.h',
- 'favicon_base/favicon_types.cc',
- 'favicon_base/favicon_types.h',
- 'favicon_base/favicon_url_parser.cc',
- 'favicon_base/favicon_url_parser.h',
- 'favicon_base/favicon_usage_data.cc',
- 'favicon_base/favicon_usage_data.h',
- 'favicon_base/favicon_util.cc',
- 'favicon_base/favicon_util.h',
- 'favicon_base/large_icon_url_parser.cc',
- 'favicon_base/large_icon_url_parser.h',
- 'favicon_base/select_favicon_frames.cc',
- 'favicon_base/select_favicon_frames.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/favicon_base/BUILD.gn b/chromium/components/favicon_base/BUILD.gn
index a0c9e9c40eb..da2ab692d1c 100644
--- a/chromium/components/favicon_base/BUILD.gn
+++ b/chromium/components/favicon_base/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("favicon_base") {
+static_library("favicon_base") {
sources = [
"fallback_icon_style.cc",
"fallback_icon_style.h",
diff --git a/chromium/components/favicon_base/fallback_icon_style.cc b/chromium/components/favicon_base/fallback_icon_style.cc
index 66ee5997e51..cbb478b1a17 100644
--- a/chromium/components/favicon_base/fallback_icon_style.cc
+++ b/chromium/components/favicon_base/fallback_icon_style.cc
@@ -34,19 +34,20 @@ const double kDefaultRoundness = 0; // Square. Round corners are applied
FallbackIconStyle::FallbackIconStyle()
: background_color(kDefaultBackgroundColor),
+ is_default_background_color(true),
text_color(kDefaultTextColorLight),
font_size_ratio(kDefaultFontSizeRatio),
- roundness(kDefaultRoundness) {
-}
+ roundness(kDefaultRoundness) {}
FallbackIconStyle::~FallbackIconStyle() {
}
bool FallbackIconStyle::operator==(const FallbackIconStyle& other) const {
return background_color == other.background_color &&
- text_color == other.text_color &&
- font_size_ratio == other.font_size_ratio &&
- roundness == other.roundness;
+ is_default_background_color == other.is_default_background_color &&
+ text_color == other.text_color &&
+ font_size_ratio == other.font_size_ratio &&
+ roundness == other.roundness;
}
void MatchFallbackIconTextColorAgainstBackgroundColor(
@@ -80,6 +81,7 @@ void SetDominantColorAsBackground(
color_hsl.l = std::min(color_hsl.l, kMaxBackgroundColorLightness);
style->background_color =
color_utils::HSLToSkColor(color_hsl, SK_AlphaOPAQUE);
+ style->is_default_background_color = false;
}
} // namespace favicon_base
diff --git a/chromium/components/favicon_base/fallback_icon_style.h b/chromium/components/favicon_base/fallback_icon_style.h
index 478efb8eb05..925773080eb 100644
--- a/chromium/components/favicon_base/fallback_icon_style.h
+++ b/chromium/components/favicon_base/fallback_icon_style.h
@@ -21,6 +21,7 @@ struct FallbackIconStyle {
// Icon background fill color.
SkColor background_color;
+ bool is_default_background_color;
// Icon text color.
SkColor text_color;
diff --git a/chromium/components/favicon_base/fallback_icon_url_parser.cc b/chromium/components/favicon_base/fallback_icon_url_parser.cc
index 8855695bfdf..214c88ff9df 100644
--- a/chromium/components/favicon_base/fallback_icon_url_parser.cc
+++ b/chromium/components/favicon_base/fallback_icon_url_parser.cc
@@ -85,8 +85,13 @@ bool ParsedFallbackIconPath::ParseSpecs(
if (*size <= 0)
return false;
- if (!tokens[1].empty() && !ParseColor(tokens[1], &style->background_color))
- return false;
+ *style = favicon_base::FallbackIconStyle();
+
+ if (!tokens[1].empty()) {
+ style->is_default_background_color = false;
+ if (!ParseColor(tokens[1], &style->background_color))
+ return false;
+ }
if (tokens[2].empty())
favicon_base::MatchFallbackIconTextColorAgainstBackgroundColor(style);
diff --git a/chromium/components/favicon_base/fallback_icon_url_parser_unittest.cc b/chromium/components/favicon_base/fallback_icon_url_parser_unittest.cc
index 13809e967b3..4dcb236adc8 100644
--- a/chromium/components/favicon_base/fallback_icon_url_parser_unittest.cc
+++ b/chromium/components/favicon_base/fallback_icon_url_parser_unittest.cc
@@ -93,6 +93,7 @@ TEST_F(FallbackIconUrlParserTest, ParseSpecsEmpty) {
EXPECT_TRUE(ParseSpecs(",,,,", &size, &style));
EXPECT_EQ(16, size);
EXPECT_EQ(kDefaultBackgroundColor, style.background_color);
+ EXPECT_TRUE(style.is_default_background_color);
EXPECT_EQ(kDefaultTextColorLight, style.text_color);
EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio);
EXPECT_EQ(kDefaultRoundness, style.roundness);
@@ -104,6 +105,7 @@ TEST_F(FallbackIconUrlParserTest, ParseSpecsPartial) {
EXPECT_TRUE(ParseSpecs(",,aCE,,0.1", &size, &style));
EXPECT_EQ(16, size);
EXPECT_EQ(kDefaultBackgroundColor, style.background_color);
+ EXPECT_TRUE(style.is_default_background_color);
EXPECT_EQ(SkColorSetRGB(0xAA, 0xCC, 0xEE), style.text_color);
EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio);
EXPECT_EQ(0.1, style.roundness);
@@ -117,6 +119,7 @@ TEST_F(FallbackIconUrlParserTest, ParseSpecsFull) {
EXPECT_TRUE(ParseSpecs("16,000,f01,0.75,0.25", &size, &style));
EXPECT_EQ(16, size);
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+ EXPECT_FALSE(style.is_default_background_color);
EXPECT_EQ(SkColorSetRGB(0xff, 0x00, 0x11), style.text_color);
EXPECT_EQ(0.75, style.font_size_ratio);
EXPECT_EQ(0.25, style.roundness);
@@ -127,6 +130,7 @@ TEST_F(FallbackIconUrlParserTest, ParseSpecsFull) {
EXPECT_TRUE(ParseSpecs("48,black,123456,0.5,0.3", &size, &style));
EXPECT_EQ(48, size);
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+ EXPECT_FALSE(style.is_default_background_color);
EXPECT_EQ(SkColorSetRGB(0x12, 0x34, 0x56), style.text_color);
EXPECT_EQ(0.5, style.font_size_ratio);
EXPECT_EQ(0.3, style.roundness);
@@ -137,6 +141,7 @@ TEST_F(FallbackIconUrlParserTest, ParseSpecsFull) {
EXPECT_TRUE(ParseSpecs("1,000,red,0,0", &size, &style));
EXPECT_EQ(1, size);
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+ EXPECT_FALSE(style.is_default_background_color);
EXPECT_EQ(SkColorSetRGB(0xFF, 0x00, 0x00), style.text_color);
EXPECT_EQ(0, style.font_size_ratio);
EXPECT_EQ(0, style.roundness);
@@ -218,6 +223,7 @@ TEST_F(FallbackIconUrlParserTest, ParseFallbackIconPathSuccess) {
EXPECT_EQ(31, parsed.size_in_pixels());
const favicon_base::FallbackIconStyle& style = parsed.style();
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+ EXPECT_FALSE(style.is_default_background_color);
EXPECT_EQ(SkColorSetRGB(0xFF, 0xFF, 0xFF), style.text_color);
EXPECT_EQ(0.75, style.font_size_ratio);
EXPECT_EQ(0.25, style.roundness);
@@ -232,6 +238,7 @@ TEST_F(FallbackIconUrlParserTest, ParseFallbackIconPathSuccess) {
EXPECT_EQ(31, parsed.size_in_pixels());
const favicon_base::FallbackIconStyle& style = parsed.style();
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+ EXPECT_FALSE(style.is_default_background_color);
EXPECT_EQ(SkColorSetRGB(0xFF, 0xFF, 0xFF), style.text_color);
EXPECT_EQ(0.75, style.font_size_ratio);
EXPECT_EQ(0.25, style.roundness);
@@ -246,6 +253,7 @@ TEST_F(FallbackIconUrlParserTest, ParseFallbackIconPathSuccess) {
EXPECT_EQ(31, parsed.size_in_pixels());
const favicon_base::FallbackIconStyle& style = parsed.style();
EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+ EXPECT_FALSE(style.is_default_background_color);
EXPECT_EQ(SkColorSetRGB(0xFF, 0xFF, 0xFF), style.text_color);
EXPECT_EQ(0.75, style.font_size_ratio);
EXPECT_EQ(0.25, style.roundness);
@@ -261,6 +269,7 @@ TEST_F(FallbackIconUrlParserTest, ParseFallbackIconPathSuccess) {
EXPECT_EQ(gfx::kFaviconSize, parsed.size_in_pixels());
const favicon_base::FallbackIconStyle& style = parsed.style();
EXPECT_EQ(kDefaultBackgroundColor, style.background_color);
+ EXPECT_TRUE(style.is_default_background_color);
EXPECT_EQ(kDefaultTextColorLight, style.text_color);
EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio);
EXPECT_EQ(kDefaultRoundness, style.roundness);
diff --git a/chromium/components/favicon_base/favicon_util.cc b/chromium/components/favicon_base/favicon_util.cc
index e17ebdf97a8..d45196e2a70 100644
--- a/chromium/components/favicon_base/favicon_util.cc
+++ b/chromium/components/favicon_base/favicon_util.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <cmath>
+#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "components/favicon_base/favicon_types.h"
#include "components/favicon_base/select_favicon_frames.h"
@@ -36,6 +37,8 @@ std::vector<gfx::ImagePNGRep> SelectFaviconFramesFromPNGsWithoutResizing(
const std::vector<favicon_base::FaviconRawBitmapResult>& png_data,
const std::vector<float>& favicon_scales,
int favicon_size) {
+ TRACE_EVENT0("browser",
+ "FaviconUtil::SelectFaviconFramesFromPNGsWithoutResizing");
std::vector<gfx::ImagePNGRep> png_reps;
if (png_data.empty())
return png_reps;
@@ -166,6 +169,8 @@ gfx::Image SelectFaviconFramesFromPNGs(
const std::vector<favicon_base::FaviconRawBitmapResult>& png_data,
const std::vector<float>& favicon_scales,
int favicon_size) {
+ TRACE_EVENT0("browser", "FaviconUtil::SelectFaviconFramesFromPNGs");
+
// Create image reps for as many scales as possible without resizing
// the bitmap data or decoding it. FaviconHandler stores already resized
// favicons into history so no additional resizing should be needed in the
@@ -245,4 +250,49 @@ gfx::Image SelectFaviconFramesFromPNGs(
return gfx::Image(png_reps);
}
+favicon_base::FaviconRawBitmapResult ResizeFaviconBitmapResult(
+ const std::vector<favicon_base::FaviconRawBitmapResult>&
+ favicon_bitmap_results,
+ int desired_size_in_pixel) {
+ TRACE_EVENT0("browser", "FaviconUtil::ResizeFaviconBitmapResult");
+
+ if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid())
+ return favicon_base::FaviconRawBitmapResult();
+
+ favicon_base::FaviconRawBitmapResult bitmap_result =
+ favicon_bitmap_results[0];
+
+ // If the desired size is 0, SelectFaviconFrames() will return the largest
+ // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
+ // data for a single bitmap, return it and avoid an unnecessary decode.
+ if (desired_size_in_pixel == 0)
+ return bitmap_result;
+
+ // If history bitmap is already desired pixel size, return early.
+ if (bitmap_result.pixel_size.width() == desired_size_in_pixel &&
+ bitmap_result.pixel_size.height() == desired_size_in_pixel)
+ return bitmap_result;
+
+ // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
+ // convert back.
+ std::vector<float> desired_favicon_scales;
+ desired_favicon_scales.push_back(1.0f);
+
+ gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs(
+ favicon_bitmap_results, desired_favicon_scales, desired_size_in_pixel);
+
+ std::vector<unsigned char> resized_bitmap_data;
+ if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
+ &resized_bitmap_data)) {
+ return favicon_base::FaviconRawBitmapResult();
+ }
+
+ bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
+ &resized_bitmap_data);
+ bitmap_result.pixel_size =
+ gfx::Size(desired_size_in_pixel, desired_size_in_pixel);
+
+ return bitmap_result;
+}
+
} // namespace favicon_base
diff --git a/chromium/components/favicon_base/favicon_util.h b/chromium/components/favicon_base/favicon_util.h
index 912f06f2f8d..088b471c47d 100644
--- a/chromium/components/favicon_base/favicon_util.h
+++ b/chromium/components/favicon_base/favicon_util.h
@@ -36,6 +36,15 @@ gfx::Image SelectFaviconFramesFromPNGs(
const std::vector<float>& favicon_scales,
int favicon_size);
+// Generates a favicon_bitmap_result sized exactly to [desired_size,
+// desired_size] from the provided result set. If the exact size is found in
+// the set, it just returns that; otherwise, it will decode the PNG, scale,
+// and encode a new PNG.
+favicon_base::FaviconRawBitmapResult ResizeFaviconBitmapResult(
+ const std::vector<favicon_base::FaviconRawBitmapResult>&
+ favicon_bitmap_results,
+ int desired_size_in_pixel);
+
} // namspace favicon_base
#endif // COMPONENTS_FAVICON_BASE_FAVICON_UTIL_H_
diff --git a/chromium/components/feedback.gypi b/chromium/components/feedback.gypi
deleted file mode 100644
index e92f00d1beb..00000000000
--- a/chromium/components/feedback.gypi
+++ /dev/null
@@ -1,71 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'feedback_component',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../net/net.gyp:net',
- '../third_party/re2/re2.gyp:re2',
- '../third_party/zlib/google/zip.gyp:zip',
- 'keyed_service_core',
- 'feedback_proto',
- 'components.gyp:variations_net',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- ],
- 'sources': [
- 'feedback/anonymizer_tool.cc',
- 'feedback/anonymizer_tool.h',
- 'feedback/feedback_common.cc',
- 'feedback/feedback_common.h',
- 'feedback/feedback_data.cc',
- 'feedback/feedback_data.h',
- 'feedback/feedback_report.cc',
- 'feedback/feedback_report.h',
- 'feedback/feedback_switches.cc',
- 'feedback/feedback_switches.h',
- 'feedback/feedback_uploader.cc',
- 'feedback/feedback_uploader.h',
- 'feedback/feedback_uploader_chrome.cc',
- 'feedback/feedback_uploader_chrome.h',
- 'feedback/feedback_uploader_delegate.cc',
- 'feedback/feedback_uploader_delegate.h',
- 'feedback/feedback_uploader_factory.cc',
- 'feedback/feedback_uploader_factory.h',
- 'feedback/feedback_util.cc',
- 'feedback/feedback_util.h',
- 'feedback/tracing_manager.cc',
- 'feedback/tracing_manager.h',
- ],
- },
- {
- # Protobuf compiler / generate rule for feedback
- # GN version: //components/feedback/proto
- 'target_name': 'feedback_proto',
- 'type': 'static_library',
- 'sources': [
- 'feedback/proto/annotations.proto',
- 'feedback/proto/chrome.proto',
- 'feedback/proto/common.proto',
- 'feedback/proto/dom.proto',
- 'feedback/proto/extension.proto',
- 'feedback/proto/math.proto',
- 'feedback/proto/web.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'feedback/proto',
- 'proto_out_dir': 'components/feedback/proto',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
- ],
-}
diff --git a/chromium/components/feedback/BUILD.gn b/chromium/components/feedback/BUILD.gn
index 0a017a01615..2382cc68d44 100644
--- a/chromium/components/feedback/BUILD.gn
+++ b/chromium/components/feedback/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("feedback") {
+static_library("feedback") {
sources = [
"anonymizer_tool.cc",
"anonymizer_tool.h",
diff --git a/chromium/components/feedback/OWNERS b/chromium/components/feedback/OWNERS
index 2f7736a88df..e89629f3c57 100644
--- a/chromium/components/feedback/OWNERS
+++ b/chromium/components/feedback/OWNERS
@@ -1,5 +1,6 @@
+afakhry@chromium.org
bsimonnet@chromium.org
-rkc@chromium.org
+steel@chromium.org
zork@chromium.org
per-file anonymizer_tool*=battre@chromium.org
diff --git a/chromium/components/feedback/anonymizer_tool.cc b/chromium/components/feedback/anonymizer_tool.cc
index 4b5070f4889..bc8a223cada 100644
--- a/chromium/components/feedback/anonymizer_tool.cc
+++ b/chromium/components/feedback/anonymizer_tool.cc
@@ -239,7 +239,7 @@ RE2* AnonymizerTool::GetRegExp(const std::string& pattern) {
RE2::Options options;
// set_multiline of pcre is not supported by RE2, yet.
options.set_dot_nl(true); // Dot matches a new line.
- std::unique_ptr<RE2> re = base::WrapUnique(new RE2(pattern, options));
+ std::unique_ptr<RE2> re = base::MakeUnique<RE2>(pattern, options);
DCHECK_EQ(re2::RE2::NoError, re->error_code())
<< "Failed to parse:\n" << pattern << "\n" << re->error();
regexp_cache_[pattern] = std::move(re);
diff --git a/chromium/components/feedback/feedback_common.cc b/chromium/components/feedback/feedback_common.cc
index b658d70411d..1a356d68de4 100644
--- a/chromium/components/feedback/feedback_common.cc
+++ b/chromium/components/feedback/feedback_common.cc
@@ -8,6 +8,8 @@
#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
+#include "components/feedback/feedback_report.h"
+#include "components/feedback/feedback_util.h"
#include "components/feedback/proto/common.pb.h"
#include "components/feedback/proto/dom.pb.h"
#include "components/feedback/proto/extension.pb.h"
@@ -15,43 +17,61 @@
namespace {
-const char kMultilineIndicatorString[] = "<multiline>\n";
-const char kMultilineStartString[] = "---------- START ----------\n";
-const char kMultilineEndString[] = "---------- END ----------\n\n";
+#if defined(OS_CHROMEOS)
+constexpr int kChromeOSProductId = 208;
+#else
+constexpr int kChromeBrowserProductId = 237;
+#endif
-const size_t kFeedbackMaxLength = 4 * 1024;
-const size_t kFeedbackMaxLineCount = 40;
+constexpr char kMultilineIndicatorString[] = "<multiline>\n";
+constexpr char kMultilineStartString[] = "---------- START ----------\n";
+constexpr char kMultilineEndString[] = "---------- END ----------\n\n";
-const base::FilePath::CharType kLogsFilename[] =
+// The below thresholds were chosen arbitrarily to conveniently show small data
+// as part of the report itself without having to look into the system_logs.zip
+// file.
+constexpr size_t kFeedbackMaxLength = 1024;
+constexpr size_t kFeedbackMaxLineCount = 10;
+
+constexpr base::FilePath::CharType kLogsFilename[] =
FILE_PATH_LITERAL("system_logs.txt");
-const char kLogsAttachmentName[] = "system_logs.zip";
+constexpr char kLogsAttachmentName[] = "system_logs.zip";
+
+constexpr char kZipExt[] = ".zip";
-const char kZipExt[] = ".zip";
+constexpr char kPngMimeType[] = "image/png";
+constexpr char kArbitraryMimeType[] = "application/octet-stream";
-const char kPngMimeType[] = "image/png";
-const char kArbitraryMimeType[] = "application/octet-stream";
+// Determine if the given feedback value is small enough to not need to
+// be compressed.
+bool BelowCompressionThreshold(const std::string& content) {
+ if (content.length() > kFeedbackMaxLength)
+ return false;
+ const size_t line_count = std::count(content.begin(), content.end(), '\n');
+ if (line_count > kFeedbackMaxLineCount)
+ return false;
+ return true;
+}
// Converts the system logs into a string that we can compress and send
-// with the report. This method only converts those logs that we want in
-// the compressed zip file sent with the report, hence it ignores any logs
-// below the size threshold of what we want compressed.
+// with the report.
// TODO(dcheng): This should probably just take advantage of string's move
// constructor.
std::unique_ptr<std::string> LogsToString(
const FeedbackCommon::SystemLogsMap& sys_info) {
std::unique_ptr<std::string> syslogs_string(new std::string);
- for (FeedbackCommon::SystemLogsMap::const_iterator it = sys_info.begin();
- it != sys_info.end();
- ++it) {
- std::string key = it->first;
- std::string value = it->second;
-
- if (FeedbackCommon::BelowCompressionThreshold(value))
- continue;
+ for (const auto& iter : sys_info) {
+ std::string key = iter.first;
+ std::string value = iter.second;
base::TrimString(key, "\n ", &key);
base::TrimString(value, "\n ", &value);
+ // We must avoid adding the crash IDs to the system_logs.txt file for
+ // privacy reasons. They should just be part of the product specific data.
+ if (key == feedback::FeedbackReport::kCrashReportIdsKey)
+ continue;
+
if (value.find("\n") != std::string::npos) {
syslogs_string->append(key + "=" + kMultilineIndicatorString +
kMultilineStartString + value + "\n" +
@@ -93,96 +113,70 @@ void AddAttachment(userfeedback::ExtensionSubmit* feedback_data,
} // namespace
+////////////////////////////////////////////////////////////////////////////////
+// FeedbackCommon::AttachedFile::
+////////////////////////////////////////////////////////////////////////////////
+
FeedbackCommon::AttachedFile::AttachedFile(const std::string& filename,
std::unique_ptr<std::string> data)
: name(filename), data(std::move(data)) {}
FeedbackCommon::AttachedFile::~AttachedFile() {}
+////////////////////////////////////////////////////////////////////////////////
+// FeedbackCommon::
+////////////////////////////////////////////////////////////////////////////////
-FeedbackCommon::FeedbackCommon() : product_id_(0) {}
-
-FeedbackCommon::~FeedbackCommon() {}
-
-// static
-bool FeedbackCommon::BelowCompressionThreshold(const std::string& content) {
- if (content.length() > kFeedbackMaxLength)
- return false;
- const size_t line_count = std::count(content.begin(), content.end(), '\n');
- if (line_count > kFeedbackMaxLineCount)
- return false;
- return true;
-}
-
-void FeedbackCommon::CompressFile(const base::FilePath& filename,
- const std::string& zipname,
- std::unique_ptr<std::string> data) {
- std::unique_ptr<AttachedFile> file(
- new AttachedFile(zipname, base::WrapUnique(new std::string())));
- if (file->name.empty()) {
- // We need to use the UTF8Unsafe methods here to accomodate Windows, which
- // uses wide strings to store filepaths.
- file->name = filename.BaseName().AsUTF8Unsafe();
- file->name.append(kZipExt);
- }
- if (feedback_util::ZipString(filename, *data, file->data.get())) {
- base::AutoLock lock(attachments_lock_);
- attachments_.push_back(file.release());
- }
-}
+FeedbackCommon::FeedbackCommon() : product_id_(-1) {}
void FeedbackCommon::AddFile(const std::string& filename,
std::unique_ptr<std::string> data) {
base::AutoLock lock(attachments_lock_);
- attachments_.push_back(new AttachedFile(filename, std::move(data)));
+ attachments_.emplace_back(new AttachedFile(filename, std::move(data)));
}
void FeedbackCommon::AddLog(const std::string& name, const std::string& value) {
- if (!logs_.get())
+ if (!logs_)
logs_ = base::WrapUnique(new SystemLogsMap);
(*logs_)[name] = value;
}
void FeedbackCommon::AddLogs(std::unique_ptr<SystemLogsMap> logs) {
- if (logs_) {
+ if (logs_)
logs_->insert(logs->begin(), logs->end());
- } else {
+ else
logs_ = std::move(logs);
- }
-}
-
-void FeedbackCommon::CompressLogs() {
- if (!logs_)
- return;
- std::unique_ptr<std::string> logs = LogsToString(*logs_);
- if (!logs->empty()) {
- CompressFile(base::FilePath(kLogsFilename), kLogsAttachmentName,
- std::move(logs));
- }
-}
-
-void FeedbackCommon::AddFilesAndLogsToReport(
- userfeedback::ExtensionSubmit* feedback_data) const {
- if (sys_info()) {
- for (FeedbackCommon::SystemLogsMap::const_iterator i = sys_info()->begin();
- i != sys_info()->end();
- ++i) {
- if (BelowCompressionThreshold(i->second))
- AddFeedbackData(feedback_data, i->first, i->second);
- }
- }
-
- for (size_t i = 0; i < attachments(); i++) {
- const AttachedFile* file = attachment(i);
- AddAttachment(feedback_data, file->name.c_str(), *file->data.get());
- }
}
void FeedbackCommon::PrepareReport(
userfeedback::ExtensionSubmit* feedback_data) const {
// Unused field, needs to be 0 though.
feedback_data->set_type_id(0);
- feedback_data->set_product_id(product_id_);
+
+ // Set whether we're reporting from ChromeOS or Chrome on another platform.
+ userfeedback::ChromeData chrome_data;
+#if defined(OS_CHROMEOS)
+ const userfeedback::ChromeData_ChromePlatform chrome_platform =
+ userfeedback::ChromeData_ChromePlatform_CHROME_OS;
+ const int default_product_id = kChromeOSProductId;
+ userfeedback::ChromeOsData chrome_os_data;
+ chrome_os_data.set_category(
+ userfeedback::ChromeOsData_ChromeOsCategory_OTHER);
+ *(chrome_data.mutable_chrome_os_data()) = chrome_os_data;
+#else
+ const userfeedback::ChromeData_ChromePlatform chrome_platform =
+ userfeedback::ChromeData_ChromePlatform_CHROME_BROWSER;
+ const int default_product_id = kChromeBrowserProductId;
+ userfeedback::ChromeBrowserData chrome_browser_data;
+ chrome_browser_data.set_category(
+ userfeedback::ChromeBrowserData_ChromeBrowserCategory_OTHER);
+ *(chrome_data.mutable_chrome_browser_data()) = chrome_browser_data;
+#endif // defined(OS_CHROMEOS)
+ chrome_data.set_chrome_platform(chrome_platform);
+ *(feedback_data->mutable_chrome_data()) = chrome_data;
+
+ feedback_data->set_product_id(HasProductId() ? product_id_
+ : default_product_id);
userfeedback::CommonData* common_data = feedback_data->mutable_common_data();
// We're not using gaia ids, we're using the e-mail field instead.
@@ -216,3 +210,52 @@ void FeedbackCommon::PrepareReport(
if (category_tag().size())
feedback_data->set_bucket(category_tag());
}
+
+FeedbackCommon::~FeedbackCommon() {}
+
+void FeedbackCommon::CompressFile(
+ const base::FilePath& filename,
+ const std::string& zipname,
+ std::unique_ptr<std::string> data_to_be_compressed) {
+ std::unique_ptr<std::string> compressed_data(new std::string());
+ if (feedback_util::ZipString(filename, *data_to_be_compressed,
+ compressed_data.get())) {
+ std::string attachment_file_name = zipname;
+ if (attachment_file_name.empty()) {
+ // We need to use the UTF8Unsafe methods here to accommodate Windows,
+ // which uses wide strings to store file paths.
+ attachment_file_name = filename.BaseName().AsUTF8Unsafe().append(kZipExt);
+ }
+
+ AddFile(attachment_file_name, std::move(compressed_data));
+ }
+}
+
+void FeedbackCommon::CompressLogs() {
+ if (!logs_)
+ return;
+ std::unique_ptr<std::string> logs = LogsToString(*logs_);
+ if (!logs->empty()) {
+ CompressFile(base::FilePath(kLogsFilename), kLogsAttachmentName,
+ std::move(logs));
+ }
+}
+
+void FeedbackCommon::AddFilesAndLogsToReport(
+ userfeedback::ExtensionSubmit* feedback_data) const {
+ for (size_t i = 0; i < attachments(); ++i) {
+ const AttachedFile* file = attachment(i);
+ AddAttachment(feedback_data, file->name.c_str(), *file->data);
+ }
+
+ if (!logs_)
+ return;
+
+ for (const auto& iter : *logs_) {
+ if (BelowCompressionThreshold(iter.second)) {
+ // Small enough logs should end up in the report data itself. However,
+ // they're still added as part of the system_logs.zip file.
+ AddFeedbackData(feedback_data, iter.first, iter.second);
+ }
+ }
+}
diff --git a/chromium/components/feedback/feedback_common.h b/chromium/components/feedback/feedback_common.h
index fadb6bf38a4..2f4016e9568 100644
--- a/chromium/components/feedback/feedback_common.h
+++ b/chromium/components/feedback/feedback_common.h
@@ -12,27 +12,21 @@
#include <memory>
#include <string>
#include <utility>
+#include <vector>
#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
#include "base/synchronization/lock.h"
namespace userfeedback {
class ExtensionSubmit;
}
-namespace feedback_util {
-bool ZipString(const base::FilePath& filename,
- const std::string& data,
- std::string* compressed_data);
-}
-
// This is the base class for FeedbackData. It primarily knows about
// data common to all feedback reports and how to zip things.
class FeedbackCommon : public base::RefCountedThreadSafe<FeedbackCommon> {
public:
- typedef std::map<std::string, std::string> SystemLogsMap;
+ using SystemLogsMap = std::map<std::string, std::string>;
struct AttachedFile {
explicit AttachedFile(const std::string& filename,
@@ -43,23 +37,12 @@ class FeedbackCommon : public base::RefCountedThreadSafe<FeedbackCommon> {
std::unique_ptr<std::string> data;
};
- // Determine if the given feedback value is small enough to not need to
- // be compressed.
- static bool BelowCompressionThreshold(const std::string& content);
-
FeedbackCommon();
- void CompressFile(const base::FilePath& filename,
- const std::string& zipname,
- std::unique_ptr<std::string> data);
void AddFile(const std::string& filename, std::unique_ptr<std::string> data);
void AddLog(const std::string& name, const std::string& value);
void AddLogs(std::unique_ptr<SystemLogsMap> logs);
- void CompressLogs();
-
- void AddFilesAndLogsToReport(
- userfeedback::ExtensionSubmit* feedback_data) const;
// Fill in |feedback_data| with all the data that we have collected.
// CompressLogs() must have already been called.
@@ -76,7 +59,9 @@ class FeedbackCommon : public base::RefCountedThreadSafe<FeedbackCommon> {
std::string user_agent() const { return user_agent_; }
std::string locale() const { return locale_; }
- const AttachedFile* attachment(size_t i) const { return attachments_[i]; }
+ const AttachedFile* attachment(size_t i) const {
+ return attachments_[i].get();
+ }
size_t attachments() const { return attachments_.size(); }
// Setters
@@ -100,12 +85,27 @@ class FeedbackCommon : public base::RefCountedThreadSafe<FeedbackCommon> {
void set_locale(const std::string& locale) { locale_ = locale; }
protected:
+ virtual ~FeedbackCommon();
+
+ // Compresses the |data_to_be_compressed| to an attachment file to this
+ // feedback data with name |zipname|. If |zipname| is empty, the |filename|
+ // will be used and appended a ".zip" extension.
+ void CompressFile(const base::FilePath& filename,
+ const std::string& zipname,
+ std::unique_ptr<std::string> data_to_be_compressed);
+
+ void CompressLogs();
+
+ private:
friend class base::RefCountedThreadSafe<FeedbackCommon>;
friend class FeedbackCommonTest;
- virtual ~FeedbackCommon();
+ void AddFilesAndLogsToReport(
+ userfeedback::ExtensionSubmit* feedback_data) const;
+
+ // Returns true if a product ID was set in the feedback report.
+ bool HasProductId() const { return product_id_ != -1; }
- private:
std::string category_tag_;
std::string page_url_;
std::string description_;
@@ -119,7 +119,7 @@ class FeedbackCommon : public base::RefCountedThreadSafe<FeedbackCommon> {
// It is possible that multiple attachment add calls are running in
// parallel, so synchronize access.
base::Lock attachments_lock_;
- ScopedVector<AttachedFile> attachments_;
+ std::vector<std::unique_ptr<AttachedFile>> attachments_;
std::unique_ptr<SystemLogsMap> logs_;
};
diff --git a/chromium/components/feedback/feedback_common_unittest.cc b/chromium/components/feedback/feedback_common_unittest.cc
index 61895abb6bd..539bd8f7567 100644
--- a/chromium/components/feedback/feedback_common_unittest.cc
+++ b/chromium/components/feedback/feedback_common_unittest.cc
@@ -13,23 +13,34 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-const char kOne[] = "one";
-const char kTwo[] = "two";
-const char kThree[] = "three";
-const char kFour[] = "four";
+constexpr char kOne[] = "one";
+constexpr char kTwo[] = "two";
+constexpr char kThree[] = "three";
+constexpr char kFour[] = "four";
#define TEN_LINES "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n"
-const char kLongLog[] = TEN_LINES TEN_LINES TEN_LINES TEN_LINES TEN_LINES;
-const char kLogsAttachmentName[] = "system_logs.zip";
+constexpr char kLongLog[] = TEN_LINES TEN_LINES TEN_LINES TEN_LINES TEN_LINES;
+constexpr char kLogsAttachmentName[] = "system_logs.zip";
+constexpr int kTestProductId = 3490;
+
+#if defined(OS_CHROMEOS)
+constexpr int kDefaultProductId = 208; // ChromeOS default product ID.
+#else
+constexpr int kDefaultProductId = 237; // Chrome default product ID.
+#endif // defined(OS_CHROMEOS)
} // namespace
class FeedbackCommonTest : public testing::Test {
protected:
- FeedbackCommonTest() {
- feedback_ = scoped_refptr<FeedbackCommon>(new FeedbackCommon());
+ FeedbackCommonTest()
+ : feedback_(new FeedbackCommon()) {
}
~FeedbackCommonTest() override {}
+ void CompressLogs() { feedback_->CompressLogs(); }
+
+ bool FeedbackHasProductId() const { return feedback_->HasProductId(); }
+
scoped_refptr<FeedbackCommon> feedback_;
userfeedback::ExtensionSubmit report_;
};
@@ -40,12 +51,24 @@ TEST_F(FeedbackCommonTest, TestBasicData) {
feedback_->set_description(kTwo);
feedback_->set_page_url(kThree);
feedback_->set_user_email(kFour);
+ EXPECT_FALSE(FeedbackHasProductId());
+ feedback_->set_product_id(kTestProductId);
+ EXPECT_TRUE(FeedbackHasProductId());
feedback_->PrepareReport(&report_);
EXPECT_EQ(kOne, report_.bucket());
EXPECT_EQ(kTwo, report_.common_data().description());
EXPECT_EQ(kThree, report_.web_data().url());
EXPECT_EQ(kFour, report_.common_data().user_email());
+ EXPECT_EQ(kTestProductId, report_.product_id());
+}
+
+// If an feedback requester doesn't set the product ID, the report will be sent
+// with the default product ID for Chrome/ChromeOS depending on the platform.
+TEST_F(FeedbackCommonTest, TestDefaultProductId) {
+ EXPECT_FALSE(FeedbackHasProductId());
+ feedback_->PrepareReport(&report_);
+ EXPECT_EQ(kDefaultProductId, report_.product_id());
}
TEST_F(FeedbackCommonTest, TestAddLogs) {
@@ -71,7 +94,7 @@ TEST_F(FeedbackCommonTest, TestCompression) {
// added with the right name.
feedback_->AddLog(kOne, kTwo);
feedback_->AddLog(kThree, kLongLog);
- feedback_->CompressLogs();
+ CompressLogs();
feedback_->PrepareReport(&report_);
EXPECT_EQ(1, report_.product_specific_binary_data_size());
diff --git a/chromium/components/feedback/feedback_data.cc b/chromium/components/feedback/feedback_data.cc
index f465f6c4ebb..215e07dce6c 100644
--- a/chromium/components/feedback/feedback_data.cc
+++ b/chromium/components/feedback/feedback_data.cc
@@ -60,12 +60,11 @@ void FeedbackData::SetAndCompressSystemInfo(
}
}
- if (sys_info.get()) {
+ if (sys_info) {
++pending_op_count_;
AddLogs(std::move(sys_info));
BrowserThread::PostBlockingPoolTaskAndReply(
- FROM_HERE,
- base::Bind(&FeedbackCommon::CompressLogs, this),
+ FROM_HERE, base::Bind(&FeedbackData::CompressLogs, this),
base::Bind(&FeedbackData::OnCompressComplete, this));
}
}
@@ -74,15 +73,13 @@ void FeedbackData::SetAndCompressHistograms(
std::unique_ptr<std::string> histograms) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!histograms.get())
+ if (!histograms)
return;
++pending_op_count_;
BrowserThread::PostBlockingPoolTaskAndReply(
FROM_HERE,
- base::Bind(&FeedbackCommon::CompressFile,
- this,
- base::FilePath(kHistogramsFilename),
- kHistogramsAttachmentName,
+ base::Bind(&FeedbackData::CompressFile, this,
+ base::FilePath(kHistogramsFilename), kHistogramsAttachmentName,
base::Passed(&histograms)),
base::Bind(&FeedbackData::OnCompressComplete, this));
}
@@ -91,18 +88,14 @@ void FeedbackData::AttachAndCompressFileData(
std::unique_ptr<std::string> attached_filedata) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!attached_filedata.get() || attached_filedata->empty())
+ if (!attached_filedata || attached_filedata->empty())
return;
++pending_op_count_;
base::FilePath attached_file =
base::FilePath::FromUTF8Unsafe(attached_filename_);
BrowserThread::PostBlockingPoolTaskAndReply(
- FROM_HERE,
- base::Bind(&FeedbackCommon::CompressFile,
- this,
- attached_file,
- std::string(),
- base::Passed(&attached_filedata)),
+ FROM_HERE, base::Bind(&FeedbackData::CompressFile, this, attached_file,
+ std::string(), base::Passed(&attached_filedata)),
base::Bind(&FeedbackData::OnCompressComplete, this));
}
diff --git a/chromium/components/feedback/feedback_data.h b/chromium/components/feedback/feedback_data.h
index ad7a76da2a0..a56bfcd4594 100644
--- a/chromium/components/feedback/feedback_data.h
+++ b/chromium/components/feedback/feedback_data.h
@@ -42,12 +42,6 @@ class FeedbackData : public FeedbackCommon {
void AttachAndCompressFileData(
std::unique_ptr<std::string> attached_filedata);
- // Called once we have compressed our system logs.
- void OnCompressLogsComplete(std::unique_ptr<std::string> compressed_logs);
-
- // Called once we have compressed our attached file.
- void OnCompressFileComplete(std::unique_ptr<std::string> compressed_file);
-
// Returns true if we've completed all the tasks needed before we can send
// feedback - at this time this is includes getting the feedback page data
// and compressing the system logs.
diff --git a/chromium/components/feedback/feedback_data_unittest.cc b/chromium/components/feedback/feedback_data_unittest.cc
index 5ba234e4472..c41e0724080 100644
--- a/chromium/components/feedback/feedback_data_unittest.cc
+++ b/chromium/components/feedback/feedback_data_unittest.cc
@@ -46,7 +46,7 @@ std::unique_ptr<KeyedService> CreateFeedbackUploaderService(
}
std::unique_ptr<std::string> MakeScoped(const char* str) {
- return base::WrapUnique(new std::string(str));
+ return base::MakeUnique<std::string>(str);
}
} // namespace
diff --git a/chromium/components/feedback/feedback_report.cc b/chromium/components/feedback/feedback_report.cc
index fb8e5582b5f..fa0e4631633 100644
--- a/chromium/components/feedback/feedback_report.cc
+++ b/chromium/components/feedback/feedback_report.cc
@@ -54,12 +54,8 @@ FeedbackReport::FeedbackReport(
&WriteReportOnBlockingPool, reports_path_, file_, data_));
}
-FeedbackReport::~FeedbackReport() {}
-
-void FeedbackReport::DeleteReportOnDisk() {
- reports_task_runner_->PostTask(FROM_HERE, base::Bind(
- base::IgnoreResult(&base::DeleteFile), file_, false));
-}
+// static
+const char FeedbackReport::kCrashReportIdsKey[] = "crash_report_ids";
// static
void FeedbackReport::LoadReportsAndQueue(
@@ -81,4 +77,12 @@ void FeedbackReport::LoadReportsAndQueue(
}
}
+void FeedbackReport::DeleteReportOnDisk() {
+ reports_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&base::DeleteFile), file_, false));
+}
+
+FeedbackReport::~FeedbackReport() {}
+
} // namespace feedback
diff --git a/chromium/components/feedback/feedback_report.h b/chromium/components/feedback/feedback_report.h
index 15cac5c76f4..11826c26530 100644
--- a/chromium/components/feedback/feedback_report.h
+++ b/chromium/components/feedback/feedback_report.h
@@ -31,6 +31,15 @@ class FeedbackReport : public base::RefCounted<FeedbackReport> {
const std::string& data,
scoped_refptr<base::SequencedTaskRunner> task_runner);
+ // The ID of the product specific data for the crash report IDs as stored by
+ // the feedback server.
+ static const char kCrashReportIdsKey[];
+
+ // Loads the reports still on disk and queues then using the given callback.
+ // This call blocks on the file reads.
+ static void LoadReportsAndQueue(const base::FilePath& user_dir,
+ QueueCallback callback);
+
// Stops the disk write of the report and deletes the report file if already
// written.
void DeleteReportOnDisk();
@@ -38,11 +47,6 @@ class FeedbackReport : public base::RefCounted<FeedbackReport> {
const base::Time& upload_at() const { return upload_at_; }
const std::string& data() const { return data_; }
- // Loads the reports still on disk and queues then using the given callback.
- // This call blocks on the file reads.
- static void LoadReportsAndQueue(const base::FilePath& user_dir,
- QueueCallback callback);
-
private:
friend class base::RefCounted<FeedbackReport>;
virtual ~FeedbackReport();
diff --git a/chromium/components/feedback/feedback_uploader_unittest.cc b/chromium/components/feedback/feedback_uploader_unittest.cc
index 3736b31c8f7..c4bcb6189f4 100644
--- a/chromium/components/feedback/feedback_uploader_unittest.cc
+++ b/chromium/components/feedback/feedback_uploader_unittest.cc
@@ -37,7 +37,7 @@ const base::TimeDelta kRetryDelayForTest =
std::unique_ptr<KeyedService> CreateFeedbackUploaderService(
content::BrowserContext* context) {
- return base::WrapUnique(new feedback::FeedbackUploaderChrome(context));
+ return base::MakeUnique<feedback::FeedbackUploaderChrome>(context);
}
} // namespace
@@ -77,7 +77,7 @@ class FeedbackUploaderTest : public testing::Test {
}
void MockDispatchReport(const std::string& report_data) {
- if (ContainsKey(dispatched_reports_, report_data)) {
+ if (base::ContainsKey(dispatched_reports_, report_data)) {
dispatched_reports_[report_data]++;
} else {
dispatched_reports_[report_data] = 1;
diff --git a/chromium/components/feedback/feedback_util.cc b/chromium/components/feedback/feedback_util.cc
index 61f43e3fa75..aa2615c3bd8 100644
--- a/chromium/components/feedback/feedback_util.cc
+++ b/chromium/components/feedback/feedback_util.cc
@@ -12,24 +12,11 @@
#include "components/feedback/feedback_data.h"
#include "components/feedback/feedback_uploader.h"
#include "components/feedback/feedback_uploader_factory.h"
-#include "components/feedback/proto/common.pb.h"
-#include "components/feedback/proto/dom.pb.h"
#include "components/feedback/proto/extension.pb.h"
-#include "components/feedback/proto/math.pb.h"
#include "third_party/zlib/google/zip.h"
using feedback::FeedbackData;
-namespace {
-
-#if defined(OS_CHROMEOS)
-const int kChromeOSProductId = 208;
-#else
-const int kChromeBrowserProductId = 237;
-#endif
-
-} // namespace
-
namespace feedback_util {
void SendReport(scoped_refptr<FeedbackData> data) {
@@ -42,28 +29,6 @@ void SendReport(scoped_refptr<FeedbackData> data) {
userfeedback::ExtensionSubmit feedback_data;
data->PrepareReport(&feedback_data);
- // Set whether we're reporting from ChromeOS or Chrome on another platform.
- userfeedback::ChromeData chrome_data;
-#if defined(OS_CHROMEOS)
- chrome_data.set_chrome_platform(
- userfeedback::ChromeData_ChromePlatform_CHROME_OS);
- userfeedback::ChromeOsData chrome_os_data;
- chrome_os_data.set_category(
- userfeedback::ChromeOsData_ChromeOsCategory_OTHER);
- *(chrome_data.mutable_chrome_os_data()) = chrome_os_data;
- feedback_data.set_product_id(kChromeOSProductId);
-#else
- chrome_data.set_chrome_platform(
- userfeedback::ChromeData_ChromePlatform_CHROME_BROWSER);
- userfeedback::ChromeBrowserData chrome_browser_data;
- chrome_browser_data.set_category(
- userfeedback::ChromeBrowserData_ChromeBrowserCategory_OTHER);
- *(chrome_data.mutable_chrome_browser_data()) = chrome_browser_data;
- feedback_data.set_product_id(kChromeBrowserProductId);
-#endif
-
- *(feedback_data.mutable_chrome_data()) = chrome_data;
-
// This pointer will eventually get deleted by the PostCleanup class, after
// we've either managed to successfully upload the report or died trying.
std::string post_body;
@@ -84,8 +49,9 @@ bool ZipString(const base::FilePath& filename,
if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &temp_path))
return false;
if (base::WriteFile(temp_path.Append(filename), data.c_str(), data.size()) ==
- -1)
+ -1) {
return false;
+ }
bool succeed = base::CreateTemporaryFile(&zip_file) &&
zip::Zip(temp_path, zip_file, false) &&
diff --git a/chromium/components/feedback/proto/BUILD.gn b/chromium/components/feedback/proto/BUILD.gn
index 15da2c04941..2d18e964292 100644
--- a/chromium/components/feedback/proto/BUILD.gn
+++ b/chromium/components/feedback/proto/BUILD.gn
@@ -4,7 +4,6 @@
import("//third_party/protobuf/proto_library.gni")
-# GYP version: components/feedback.gypi:feedback_proto
proto_library("proto") {
sources = [
"annotations.proto",
diff --git a/chromium/components/filesystem/BUILD.gn b/chromium/components/filesystem/BUILD.gn
index c35762c2dc0..66c16bb1b54 100644
--- a/chromium/components/filesystem/BUILD.gn
+++ b/chromium/components/filesystem/BUILD.gn
@@ -2,11 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//mojo/public/mojo_application.gni")
-import("//mojo/public/mojo_application_manifest.gni")
+import("//services/shell/public/cpp/service.gni")
+import("//services/shell/public/service_manifest.gni")
import("//testing/test.gni")
-source_set("lib") {
+static_library("lib") {
sources = [
"directory_impl.cc",
"directory_impl.h",
@@ -34,7 +34,7 @@ source_set("lib") {
]
}
-mojo_native_application("filesystem") {
+service("filesystem") {
sources = [
"file_system_app.cc",
"file_system_app.h",
@@ -57,8 +57,8 @@ mojo_native_application("filesystem") {
]
}
-mojo_application_manifest("manifest") {
- application_name = "filesystem"
+service_manifest("manifest") {
+ name = "filesystem"
source = "manifest.json"
}
@@ -76,7 +76,7 @@ test("filesystem_service_unittests") {
"//mojo/common",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
- "//services/shell/public/cpp:shell_test_support",
+ "//services/shell/public/cpp:service_test_support",
"//services/shell/public/cpp:sources",
"//services/shell/public/cpp/test:run_all_shelltests",
]
@@ -87,8 +87,8 @@ test("filesystem_service_unittests") {
]
}
-mojo_application_manifest("test_manifest") {
+service_manifest("test_manifest") {
type = "exe"
- application_name = "filesystem_service_unittests"
+ name = "filesystem_service_unittests"
source = "test_manifest.json"
}
diff --git a/chromium/components/filesystem/directory_impl.cc b/chromium/components/filesystem/directory_impl.cc
index 835a0f22029..7fd998142b6 100644
--- a/chromium/components/filesystem/directory_impl.cc
+++ b/chromium/components/filesystem/directory_impl.cc
@@ -16,16 +16,15 @@
#include "components/filesystem/lock_table.h"
#include "components/filesystem/util.h"
#include "mojo/common/common_type_converters.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/platform_handle.h"
namespace filesystem {
-DirectoryImpl::DirectoryImpl(mojo::InterfaceRequest<mojom::Directory> request,
- base::FilePath directory_path,
+DirectoryImpl::DirectoryImpl(base::FilePath directory_path,
scoped_refptr<SharedTempDir> temp_dir,
scoped_refptr<LockTable> lock_table)
- : binding_(this, std::move(request)),
- directory_path_(directory_path),
+ : directory_path_(directory_path),
temp_dir_(std::move(temp_dir)),
lock_table_(std::move(lock_table)) {}
@@ -55,7 +54,7 @@ void DirectoryImpl::Read(const ReadCallback& callback) {
// TODO(vtl): Move the implementation to a thread pool.
void DirectoryImpl::OpenFile(const mojo::String& raw_path,
- mojo::InterfaceRequest<mojom::File> file,
+ mojom::FileRequest file,
uint32_t open_flags,
const OpenFileCallback& callback) {
base::FilePath path;
@@ -80,8 +79,10 @@ void DirectoryImpl::OpenFile(const mojo::String& raw_path,
}
if (file.is_pending()) {
- new FileImpl(std::move(file), path, std::move(base_file), temp_dir_,
- lock_table_);
+ mojo::MakeStrongBinding(
+ base::MakeUnique<FileImpl>(path, std::move(base_file), temp_dir_,
+ lock_table_),
+ std::move(file));
}
callback.Run(mojom::FileError::OK);
}
@@ -110,11 +111,10 @@ void DirectoryImpl::OpenFileHandles(
callback.Run(std::move(results));
}
-void DirectoryImpl::OpenDirectory(
- const mojo::String& raw_path,
- mojo::InterfaceRequest<mojom::Directory> directory,
- uint32_t open_flags,
- const OpenDirectoryCallback& callback) {
+void DirectoryImpl::OpenDirectory(const mojo::String& raw_path,
+ mojom::DirectoryRequest directory,
+ uint32_t open_flags,
+ const OpenDirectoryCallback& callback) {
base::FilePath path;
mojom::FileError error = ValidatePath(raw_path, directory_path_, &path);
if (error != mojom::FileError::OK) {
@@ -143,8 +143,12 @@ void DirectoryImpl::OpenDirectory(
}
}
- if (directory.is_pending())
- new DirectoryImpl(std::move(directory), path, temp_dir_, lock_table_);
+ if (directory.is_pending()) {
+ mojo::MakeStrongBinding(
+ base::MakeUnique<DirectoryImpl>(path, temp_dir_, lock_table_),
+ std::move(directory));
+ }
+
callback.Run(mojom::FileError::OK);
}
@@ -257,10 +261,11 @@ void DirectoryImpl::StatFile(const mojo::String& raw_path,
callback.Run(mojom::FileError::OK, MakeFileInformation(info));
}
-void DirectoryImpl::Clone(mojo::InterfaceRequest<mojom::Directory> directory) {
+void DirectoryImpl::Clone(mojom::DirectoryRequest directory) {
if (directory.is_pending()) {
- new DirectoryImpl(std::move(directory), directory_path_,
- temp_dir_, lock_table_);
+ mojo::MakeStrongBinding(base::MakeUnique<DirectoryImpl>(
+ directory_path_, temp_dir_, lock_table_),
+ std::move(directory));
}
}
diff --git a/chromium/components/filesystem/directory_impl.h b/chromium/components/filesystem/directory_impl.h
index 5b2ed5eb021..8d874432d4a 100644
--- a/chromium/components/filesystem/directory_impl.h
+++ b/chromium/components/filesystem/directory_impl.h
@@ -15,7 +15,6 @@
#include "components/filesystem/public/interfaces/directory.mojom.h"
#include "components/filesystem/shared_temp_dir.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
namespace filesystem {
@@ -25,20 +24,15 @@ class DirectoryImpl : public mojom::Directory {
public:
// Set |temp_dir| only if there's a temporary directory that should be deleted
// when this object is destroyed.
- DirectoryImpl(mojo::InterfaceRequest<mojom::Directory> request,
- base::FilePath directory_path,
+ DirectoryImpl(base::FilePath directory_path,
scoped_refptr<SharedTempDir> temp_dir,
scoped_refptr<LockTable> lock_table);
~DirectoryImpl() override;
- void set_connection_error_handler(const base::Closure& error_handler) {
- binding_.set_connection_error_handler(error_handler);
- }
-
// |Directory| implementation:
void Read(const ReadCallback& callback) override;
void OpenFile(const mojo::String& path,
- mojo::InterfaceRequest<mojom::File> file,
+ mojom::FileRequest file,
uint32_t open_flags,
const OpenFileCallback& callback) override;
void OpenFileHandle(const mojo::String& path,
@@ -47,7 +41,7 @@ class DirectoryImpl : public mojom::Directory {
void OpenFileHandles(mojo::Array<mojom::FileOpenDetailsPtr> details,
const OpenFileHandlesCallback& callback) override;
void OpenDirectory(const mojo::String& path,
- mojo::InterfaceRequest<mojom::Directory> directory,
+ mojom::DirectoryRequest directory,
uint32_t open_flags,
const OpenDirectoryCallback& callback) override;
void Rename(const mojo::String& path,
@@ -63,7 +57,7 @@ class DirectoryImpl : public mojom::Directory {
void Flush(const FlushCallback& callback) override;
void StatFile(const mojo::String& path,
const StatFileCallback& callback) override;
- void Clone(mojo::InterfaceRequest<mojom::Directory> directory) override;
+ void Clone(mojom::DirectoryRequest directory) override;
void ReadEntireFile(const mojo::String& path,
const ReadEntireFileCallback& callback) override;
void WriteFile(const mojo::String& path,
@@ -75,7 +69,6 @@ class DirectoryImpl : public mojom::Directory {
uint32_t open_flags,
mojom::FileError* error);
- mojo::StrongBinding<mojom::Directory> binding_;
base::FilePath directory_path_;
scoped_refptr<SharedTempDir> temp_dir_;
scoped_refptr<LockTable> lock_table_;
diff --git a/chromium/components/filesystem/directory_impl_unittest.cc b/chromium/components/filesystem/directory_impl_unittest.cc
index 47c3de592bd..61ced2e2403 100644
--- a/chromium/components/filesystem/directory_impl_unittest.cc
+++ b/chromium/components/filesystem/directory_impl_unittest.cc
@@ -32,24 +32,23 @@ TEST_F(DirectoryImplTest, Read) {
{"my_file3", mojom::kFlagAppend | mojom::kFlagCreate}};
for (size_t i = 0; i < arraysize(files_to_create); i++) {
error = mojom::FileError::FAILED;
- directory->OpenFile(files_to_create[i].name, nullptr,
- files_to_create[i].open_flags, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled = directory->OpenFile(files_to_create[i].name, nullptr,
+ files_to_create[i].open_flags, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
// Make a directory.
error = mojom::FileError::FAILED;
- directory->OpenDirectory(
+ bool handled = directory->OpenDirectory(
"my_dir", nullptr,
- mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
error = mojom::FileError::FAILED;
mojo::Array<mojom::DirectoryEntryPtr> directory_contents;
- directory->Read(Capture(&error, &directory_contents));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ handled = directory->Read(&error, &directory_contents);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Expected contents of the directory.
@@ -80,48 +79,48 @@ TEST_F(DirectoryImplTest, BasicRenameDelete) {
// Create my_file.
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", nullptr,
- mojom::kFlagWrite | mojom::kFlagCreate, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled = directory->OpenFile(
+ "my_file", nullptr, mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Opening my_file should succeed.
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", nullptr, mojom::kFlagRead | mojom::kFlagOpen,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ handled = directory->OpenFile("my_file", nullptr,
+ mojom::kFlagRead | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Rename my_file to my_new_file.
- directory->Rename("my_file", "my_new_file", Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ handled = directory->Rename("my_file", "my_new_file", &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Opening my_file should fail.
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", nullptr, mojom::kFlagRead | mojom::kFlagOpen,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ handled = directory->OpenFile("my_file", nullptr,
+ mojom::kFlagRead | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::NOT_FOUND, error);
// Opening my_new_file should succeed.
error = mojom::FileError::FAILED;
- directory->OpenFile("my_new_file", nullptr,
- mojom::kFlagRead | mojom::kFlagOpen, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ handled = directory->OpenFile("my_new_file", nullptr,
+ mojom::kFlagRead | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Delete my_new_file (no flags).
- directory->Delete("my_new_file", 0, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ handled = directory->Delete("my_new_file", 0, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Opening my_new_file should fail.
error = mojom::FileError::FAILED;
- directory->OpenFile("my_new_file", nullptr,
- mojom::kFlagRead | mojom::kFlagOpen, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ handled = directory->OpenFile("my_new_file", nullptr,
+ mojom::kFlagRead | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::NOT_FOUND, error);
}
@@ -134,11 +133,10 @@ TEST_F(DirectoryImplTest, CantOpenDirectoriesAsFiles) {
// Create a directory called 'my_file'
mojom::DirectoryPtr my_file_directory;
error = mojom::FileError::FAILED;
- directory->OpenDirectory(
+ bool handled = directory->OpenDirectory(
"my_file", GetProxy(&my_file_directory),
- mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
@@ -146,9 +144,10 @@ TEST_F(DirectoryImplTest, CantOpenDirectoriesAsFiles) {
// Attempt to open that directory as a file. This must fail!
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagRead | mojom::kFlagOpen, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagRead | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::NOT_A_FILE, error);
}
}
@@ -171,16 +170,16 @@ TEST_F(DirectoryImplTest, Clone) {
std::string data("one two three");
{
- clone_one->WriteFile("data", mojo::Array<uint8_t>::From(data),
- Capture(&error));
- ASSERT_TRUE(clone_one.WaitForIncomingResponse());
+ bool handled =
+ clone_one->WriteFile("data", mojo::Array<uint8_t>::From(data), &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
{
mojo::Array<uint8_t> file_contents;
- clone_two->ReadEntireFile("data", Capture(&error, &file_contents));
- ASSERT_TRUE(clone_two.WaitForIncomingResponse());
+ bool handled = clone_two->ReadEntireFile("data", &error, &file_contents);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(data, file_contents.To<std::string>());
@@ -194,16 +193,16 @@ TEST_F(DirectoryImplTest, WriteFileReadFile) {
std::string data("one two three");
{
- directory->WriteFile("data", mojo::Array<uint8_t>::From(data),
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->WriteFile("data", mojo::Array<uint8_t>::From(data), &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
{
mojo::Array<uint8_t> file_contents;
- directory->ReadEntireFile("data", Capture(&error, &file_contents));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled = directory->ReadEntireFile("data", &error, &file_contents);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(data, file_contents.To<std::string>());
@@ -217,8 +216,9 @@ TEST_F(DirectoryImplTest, ReadEmptyFileIsNotFoundError) {
{
mojo::Array<uint8_t> file_contents;
- directory->ReadEntireFile("doesnt_exist", Capture(&error, &file_contents));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->ReadEntireFile("doesnt_exist", &error, &file_contents);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::NOT_FOUND, error);
}
}
@@ -232,19 +232,18 @@ TEST_F(DirectoryImplTest, CantReadEntireFileOnADirectory) {
{
mojom::DirectoryPtr my_file_directory;
error = mojom::FileError::FAILED;
- directory->OpenDirectory(
+ bool handled = directory->OpenDirectory(
"my_dir", GetProxy(&my_file_directory),
- mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
// Try to read it as a file
{
mojo::Array<uint8_t> file_contents;
- directory->ReadEntireFile("my_dir", Capture(&error, &file_contents));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled = directory->ReadEntireFile("my_dir", &error, &file_contents);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::NOT_A_FILE, error);
}
}
@@ -258,19 +257,18 @@ TEST_F(DirectoryImplTest, CantWriteFileOnADirectory) {
{
mojom::DirectoryPtr my_file_directory;
error = mojom::FileError::FAILED;
- directory->OpenDirectory(
+ bool handled = directory->OpenDirectory(
"my_dir", GetProxy(&my_file_directory),
- mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
{
std::string data("one two three");
- directory->WriteFile("my_dir", mojo::Array<uint8_t>::From(data),
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled = directory->WriteFile(
+ "my_dir", mojo::Array<uint8_t>::From(data), &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::NOT_A_FILE, error);
}
}
diff --git a/chromium/components/filesystem/file_impl.cc b/chromium/components/filesystem/file_impl.cc
index 5a2eec9401e..fce387132be 100644
--- a/chromium/components/filesystem/file_impl.cc
+++ b/chromium/components/filesystem/file_impl.cc
@@ -17,6 +17,7 @@
#include "components/filesystem/shared_temp_dir.h"
#include "components/filesystem/util.h"
#include "mojo/common/common_type_converters.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/platform_handle.h"
static_assert(sizeof(off_t) <= sizeof(int64_t), "off_t too big");
@@ -32,26 +33,22 @@ const size_t kMaxReadSize = 1 * 1024 * 1024; // 1 MB.
} // namespace
-FileImpl::FileImpl(mojo::InterfaceRequest<mojom::File> request,
- const base::FilePath& path,
+FileImpl::FileImpl(const base::FilePath& path,
uint32_t flags,
scoped_refptr<SharedTempDir> temp_dir,
scoped_refptr<LockTable> lock_table)
- : binding_(this, std::move(request)),
- file_(path, flags),
+ : file_(path, flags),
path_(path),
temp_dir_(std::move(temp_dir)),
lock_table_(std::move(lock_table)) {
DCHECK(file_.IsValid());
}
-FileImpl::FileImpl(mojo::InterfaceRequest<mojom::File> request,
- const base::FilePath& path,
+FileImpl::FileImpl(const base::FilePath& path,
base::File file,
scoped_refptr<SharedTempDir> temp_dir,
scoped_refptr<LockTable> lock_table)
- : binding_(this, std::move(request)),
- file_(std::move(file)),
+ : file_(std::move(file)),
path_(path),
temp_dir_(std::move(temp_dir)),
lock_table_(std::move(lock_table)) {
@@ -288,8 +285,7 @@ void FileImpl::Touch(mojom::TimespecOrNowPtr atime,
callback.Run(mojom::FileError::OK);
}
-void FileImpl::Dup(mojo::InterfaceRequest<mojom::File> file,
- const DupCallback& callback) {
+void FileImpl::Dup(mojom::FileRequest file, const DupCallback& callback) {
if (!file_.IsValid()) {
callback.Run(GetError(file_));
return;
@@ -301,9 +297,12 @@ void FileImpl::Dup(mojo::InterfaceRequest<mojom::File> file,
return;
}
- if (file.is_pending())
- new FileImpl(std::move(file), path_, std::move(new_file), temp_dir_,
- lock_table_);
+ if (file.is_pending()) {
+ mojo::MakeStrongBinding(
+ base::MakeUnique<FileImpl>(path_, std::move(new_file), temp_dir_,
+ lock_table_),
+ std::move(file));
+ }
callback.Run(mojom::FileError::OK);
}
diff --git a/chromium/components/filesystem/file_impl.h b/chromium/components/filesystem/file_impl.h
index f7eb1b4e5c2..8ad9193777b 100644
--- a/chromium/components/filesystem/file_impl.h
+++ b/chromium/components/filesystem/file_impl.h
@@ -12,7 +12,6 @@
#include "base/macros.h"
#include "components/filesystem/public/interfaces/directory.mojom.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
namespace base {
class FilePath;
@@ -25,13 +24,11 @@ class SharedTempDir;
class FileImpl : public mojom::File {
public:
- FileImpl(mojo::InterfaceRequest<mojom::File> request,
- const base::FilePath& path,
+ FileImpl(const base::FilePath& path,
uint32_t flags,
scoped_refptr<SharedTempDir> temp_dir,
scoped_refptr<LockTable> lock_table);
- FileImpl(mojo::InterfaceRequest<mojom::File> request,
- const base::FilePath& path,
+ FileImpl(const base::FilePath& path,
base::File file,
scoped_refptr<SharedTempDir> temp_dir,
scoped_refptr<LockTable> lock_table);
@@ -66,15 +63,13 @@ class FileImpl : public mojom::File {
void Touch(mojom::TimespecOrNowPtr atime,
mojom::TimespecOrNowPtr mtime,
const TouchCallback& callback) override;
- void Dup(mojo::InterfaceRequest<mojom::File> file,
- const DupCallback& callback) override;
+ void Dup(mojom::FileRequest file, const DupCallback& callback) override;
void Flush(const FlushCallback& callback) override;
void Lock(const LockCallback& callback) override;
void Unlock(const UnlockCallback& callback) override;
void AsHandle(const AsHandleCallback& callback) override;
private:
- mojo::StrongBinding<mojom::File> binding_;
base::File file_;
base::FilePath path_;
scoped_refptr<SharedTempDir> temp_dir_;
diff --git a/chromium/components/filesystem/file_impl_unittest.cc b/chromium/components/filesystem/file_impl_unittest.cc
index 94c8eb4e75e..443a4a9aacf 100644
--- a/chromium/components/filesystem/file_impl_unittest.cc
+++ b/chromium/components/filesystem/file_impl_unittest.cc
@@ -22,15 +22,16 @@ TEST_F(FileImplTest, CreateWriteCloseRenameOpenRead) {
mojom::DirectoryPtr directory;
GetTemporaryRoot(&directory);
mojom::FileError error;
+ bool handled = false;
{
// Create my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Write to it.
@@ -42,40 +43,41 @@ TEST_F(FileImplTest, CreateWriteCloseRenameOpenRead) {
bytes_to_write.push_back(static_cast<uint8_t>('o'));
error = mojom::FileError::FAILED;
uint32_t num_bytes_written = 0;
- file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT,
- Capture(&error, &num_bytes_written));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled =
+ file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
// Close it.
error = mojom::FileError::FAILED;
- file->Close(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Close((&error));
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
// Rename it.
error = mojom::FileError::FAILED;
- directory->Rename("my_file", "your_file", Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ handled = directory->Rename("my_file", "your_file", &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
{
// Open my_file again.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("your_file", GetProxy(&file),
- mojom::kFlagRead | mojom::kFlagOpen, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("your_file", GetProxy(&file),
+ mojom::kFlagRead | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Read from it.
mojo::Array<uint8_t> bytes_read;
error = mojom::FileError::FAILED;
- file->Read(3, 1, mojom::Whence::FROM_BEGIN, Capture(&error, &bytes_read));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Read(3, 1, mojom::Whence::FROM_BEGIN, &error, &bytes_read);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
ASSERT_EQ(3u, bytes_read.size());
EXPECT_EQ(static_cast<uint8_t>('e'), bytes_read[0]);
@@ -102,26 +104,26 @@ TEST_F(FileImplTest, CantWriteInReadMode) {
// Create my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Write to it.
error = mojom::FileError::FAILED;
uint32_t num_bytes_written = 0;
- file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT,
- Capture(&error, &num_bytes_written));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled =
+ file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
// Close it.
error = mojom::FileError::FAILED;
- file->Close(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Close((&error));
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
@@ -129,26 +131,27 @@ TEST_F(FileImplTest, CantWriteInReadMode) {
// Open my_file again, this time with read only mode.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagRead | mojom::kFlagOpen, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagRead | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Try to write in read mode; it should fail.
error = mojom::FileError::OK;
uint32_t num_bytes_written = 0;
- file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT,
- Capture(&error, &num_bytes_written));
+ handled =
+ file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::FAILED, error);
EXPECT_EQ(0u, num_bytes_written);
// Close it.
error = mojom::FileError::FAILED;
- file->Close(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Close((&error));
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
}
@@ -162,10 +165,10 @@ TEST_F(FileImplTest, OpenInAppendMode) {
// Create my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Write to it.
@@ -177,17 +180,17 @@ TEST_F(FileImplTest, OpenInAppendMode) {
bytes_to_write.push_back(static_cast<uint8_t>('o'));
error = mojom::FileError::FAILED;
uint32_t num_bytes_written = 0;
- file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT,
- Capture(&error, &num_bytes_written));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled =
+ file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
// Close it.
error = mojom::FileError::FAILED;
- file->Close(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Close(&error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
@@ -195,9 +198,10 @@ TEST_F(FileImplTest, OpenInAppendMode) {
// Append to my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagAppend | mojom::kFlagOpen, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagAppend | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Write to it.
@@ -211,17 +215,17 @@ TEST_F(FileImplTest, OpenInAppendMode) {
bytes_to_write.push_back(static_cast<uint8_t>('e'));
error = mojom::FileError::FAILED;
uint32_t num_bytes_written = 0;
- file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT,
- Capture(&error, &num_bytes_written));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled =
+ file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
// Close it.
error = mojom::FileError::FAILED;
- file->Close(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Close((&error));
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
@@ -229,16 +233,17 @@ TEST_F(FileImplTest, OpenInAppendMode) {
// Open my_file again.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagRead | mojom::kFlagOpen, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagRead | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Read from it.
mojo::Array<uint8_t> bytes_read;
error = mojom::FileError::FAILED;
- file->Read(12, 0, mojom::Whence::FROM_BEGIN, Capture(&error, &bytes_read));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Read(12, 0, mojom::Whence::FROM_BEGIN, &error, &bytes_read);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
ASSERT_EQ(12u, bytes_read.size());
EXPECT_EQ(static_cast<uint8_t>('l'), bytes_read[3]);
@@ -257,10 +262,10 @@ TEST_F(FileImplTest, OpenInTruncateMode) {
// Create my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Write to it.
@@ -272,17 +277,17 @@ TEST_F(FileImplTest, OpenInTruncateMode) {
bytes_to_write.push_back(static_cast<uint8_t>('o'));
error = mojom::FileError::FAILED;
uint32_t num_bytes_written = 0;
- file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT,
- Capture(&error, &num_bytes_written));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled =
+ file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
// Close it.
error = mojom::FileError::FAILED;
- file->Close(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Close(&error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
@@ -290,10 +295,10 @@ TEST_F(FileImplTest, OpenInTruncateMode) {
// Append to my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagWrite | mojom::kFlagOpenTruncated,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled = directory->OpenFile(
+ "my_file", GetProxy(&file),
+ mojom::kFlagWrite | mojom::kFlagOpenTruncated, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Write to it.
@@ -307,17 +312,17 @@ TEST_F(FileImplTest, OpenInTruncateMode) {
bytes_to_write.push_back(static_cast<uint8_t>('e'));
error = mojom::FileError::FAILED;
uint32_t num_bytes_written = 0;
- file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT,
- Capture(&error, &num_bytes_written));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled =
+ file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
// Close it.
error = mojom::FileError::FAILED;
- file->Close(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Close(&error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
@@ -325,16 +330,17 @@ TEST_F(FileImplTest, OpenInTruncateMode) {
// Open my_file again.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagRead | mojom::kFlagOpen, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagRead | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Read from it.
mojo::Array<uint8_t> bytes_read;
error = mojom::FileError::FAILED;
- file->Read(7, 0, mojom::Whence::FROM_BEGIN, Capture(&error, &bytes_read));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Read(7, 0, mojom::Whence::FROM_BEGIN, &error, &bytes_read);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
ASSERT_EQ(7u, bytes_read.size());
EXPECT_EQ(static_cast<uint8_t>('g'), bytes_read[0]);
@@ -354,16 +360,17 @@ TEST_F(FileImplTest, StatTouch) {
// Create my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagWrite | mojom::kFlagCreate, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Stat it.
error = mojom::FileError::FAILED;
mojom::FileInformationPtr file_info;
- file->Stat(Capture(&error, &file_info));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Stat(&error, &file_info);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
ASSERT_FALSE(file_info.is_null());
EXPECT_EQ(mojom::FsFileType::REGULAR_FILE, file_info->type);
@@ -378,15 +385,15 @@ TEST_F(FileImplTest, StatTouch) {
t->now = false;
const int64_t kPartyTime1 = 1234567890; // Party like it's 2009-02-13.
t->seconds = kPartyTime1;
- file->Touch(std::move(t), nullptr, Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Touch(std::move(t), nullptr, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Stat again.
error = mojom::FileError::FAILED;
file_info.reset();
- file->Stat(Capture(&error, &file_info));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Stat(&error, &file_info);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
ASSERT_FALSE(file_info.is_null());
EXPECT_EQ(kPartyTime1, file_info->atime);
@@ -397,15 +404,15 @@ TEST_F(FileImplTest, StatTouch) {
t->now = false;
const int64_t kPartyTime2 = 1425059525; // No time like the present.
t->seconds = kPartyTime2;
- file->Touch(nullptr, std::move(t), Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Touch(nullptr, std::move(t), &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Stat again.
error = mojom::FileError::FAILED;
file_info.reset();
- file->Stat(Capture(&error, &file_info));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Stat(&error, &file_info);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
ASSERT_FALSE(file_info.is_null());
EXPECT_EQ(kPartyTime1, file_info->atime);
@@ -424,18 +431,20 @@ TEST_F(FileImplTest, TellSeek) {
// Create my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagWrite | mojom::kFlagCreate, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Write to it.
std::vector<uint8_t> bytes_to_write(1000, '!');
error = mojom::FileError::FAILED;
uint32_t num_bytes_written = 0;
- file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT, Capture(&error, &num_bytes_written));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled =
+ file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
const int size = static_cast<int>(num_bytes_written);
@@ -443,8 +452,8 @@ TEST_F(FileImplTest, TellSeek) {
// Tell.
error = mojom::FileError::FAILED;
int64_t position = -1;
- file->Tell(Capture(&error, &position));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Tell(&error, &position);
+ ASSERT_TRUE(handled);
// Should be at the end.
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(size, position);
@@ -452,48 +461,48 @@ TEST_F(FileImplTest, TellSeek) {
// Seek back 100.
error = mojom::FileError::FAILED;
position = -1;
- file->Seek(-100, mojom::Whence::FROM_CURRENT, Capture(&error, &position));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Seek(-100, mojom::Whence::FROM_CURRENT, &error, &position);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(size - 100, position);
// Tell.
error = mojom::FileError::FAILED;
position = -1;
- file->Tell(Capture(&error, &position));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Tell(&error, &position);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(size - 100, position);
// Seek to 123 from start.
error = mojom::FileError::FAILED;
position = -1;
- file->Seek(123, mojom::Whence::FROM_BEGIN, Capture(&error, &position));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Seek(123, mojom::Whence::FROM_BEGIN, &error, &position);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(123, position);
// Tell.
error = mojom::FileError::FAILED;
position = -1;
- file->Tell(Capture(&error, &position));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Tell(&error, &position);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(123, position);
// Seek to 123 back from end.
error = mojom::FileError::FAILED;
position = -1;
- file->Seek(-123, mojom::Whence::FROM_END, Capture(&error, &position));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Seek(-123, mojom::Whence::FROM_END, &error, &position);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(size - 123, position);
// Tell.
error = mojom::FileError::FAILED;
position = -1;
- file->Tell(Capture(&error, &position));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Tell(&error, &position);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(size - 123, position);
@@ -509,10 +518,10 @@ TEST_F(FileImplTest, Dup) {
// Create my_file.
mojom::FilePtr file1;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file1),
- mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled = directory->OpenFile(
+ "my_file", GetProxy(&file1),
+ mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Write to it.
@@ -524,10 +533,10 @@ TEST_F(FileImplTest, Dup) {
bytes_to_write.push_back(static_cast<uint8_t>('o'));
error = mojom::FileError::FAILED;
uint32_t num_bytes_written = 0;
- file1->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT,
- Capture(&error, &num_bytes_written));
- ASSERT_TRUE(file1.WaitForIncomingResponse());
+ handled =
+ file1->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(bytes_to_write.size(), num_bytes_written);
const int end_hello_pos = static_cast<int>(num_bytes_written);
@@ -535,15 +544,15 @@ TEST_F(FileImplTest, Dup) {
// Dup it.
mojom::FilePtr file2;
error = mojom::FileError::FAILED;
- file1->Dup(GetProxy(&file2), Capture(&error));
- ASSERT_TRUE(file1.WaitForIncomingResponse());
+ handled = file1->Dup(GetProxy(&file2), &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// |file2| should have the same position.
error = mojom::FileError::FAILED;
int64_t position = -1;
- file2->Tell(Capture(&error, &position));
- ASSERT_TRUE(file2.WaitForIncomingResponse());
+ handled = file2->Tell(&error, &position);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(end_hello_pos, position);
@@ -556,10 +565,10 @@ TEST_F(FileImplTest, Dup) {
more_bytes_to_write.push_back(static_cast<uint8_t>('d'));
error = mojom::FileError::FAILED;
num_bytes_written = 0;
- file2->Write(mojo::Array<uint8_t>::From(more_bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT,
- Capture(&error, &num_bytes_written));
- ASSERT_TRUE(file2.WaitForIncomingResponse());
+ handled =
+ file2->Write(mojo::Array<uint8_t>::From(more_bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(more_bytes_to_write.size(), num_bytes_written);
const int end_world_pos = end_hello_pos + static_cast<int>(num_bytes_written);
@@ -567,22 +576,23 @@ TEST_F(FileImplTest, Dup) {
// |file1| should have the same position.
error = mojom::FileError::FAILED;
position = -1;
- file1->Tell(Capture(&error, &position));
- ASSERT_TRUE(file1.WaitForIncomingResponse());
+ handled = file1->Tell(&error, &position);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(end_world_pos, position);
// Close |file1|.
error = mojom::FileError::FAILED;
- file1->Close(Capture(&error));
- ASSERT_TRUE(file1.WaitForIncomingResponse());
+ handled = file1->Close(&error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Read everything using |file2|.
mojo::Array<uint8_t> bytes_read;
error = mojom::FileError::FAILED;
- file2->Read(1000, 0, mojom::Whence::FROM_BEGIN, Capture(&error, &bytes_read));
- ASSERT_TRUE(file2.WaitForIncomingResponse());
+ handled =
+ file2->Read(1000, 0, mojom::Whence::FROM_BEGIN, &error, &bytes_read);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
ASSERT_EQ(static_cast<size_t>(end_world_pos), bytes_read.size());
// Just check the first and last bytes.
@@ -603,41 +613,43 @@ TEST_F(FileImplTest, Truncate) {
// Create my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagWrite | mojom::kFlagCreate, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file),
+ mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Write to it.
std::vector<uint8_t> bytes_to_write(kInitialSize, '!');
error = mojom::FileError::FAILED;
uint32_t num_bytes_written = 0;
- file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
- mojom::Whence::FROM_CURRENT, Capture(&error, &num_bytes_written));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled =
+ file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0,
+ mojom::Whence::FROM_CURRENT, &error, &num_bytes_written);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
EXPECT_EQ(kInitialSize, num_bytes_written);
// Stat it.
error = mojom::FileError::FAILED;
mojom::FileInformationPtr file_info;
- file->Stat(Capture(&error, &file_info));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Stat(&error, &file_info);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
ASSERT_FALSE(file_info.is_null());
EXPECT_EQ(kInitialSize, file_info->size);
// Truncate it.
error = mojom::FileError::FAILED;
- file->Truncate(kTruncatedSize, Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Truncate(kTruncatedSize, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Stat again.
error = mojom::FileError::FAILED;
file_info.reset();
- file->Stat(Capture(&error, &file_info));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Stat(&error, &file_info);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
ASSERT_FALSE(file_info.is_null());
EXPECT_EQ(kTruncatedSize, file_info->size);
@@ -652,18 +664,17 @@ TEST_F(FileImplTest, AsHandle) {
// Create my_file.
mojom::FilePtr file1;
error = mojom::FileError::FAILED;
- directory->OpenFile(
+ bool handled = directory->OpenFile(
"my_file", GetProxy(&file1),
- mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Fetch the handle
error = mojom::FileError::FAILED;
mojo::ScopedHandle handle;
- file1->AsHandle(Capture(&error, &handle));
- ASSERT_TRUE(file1.WaitForIncomingResponse());
+ handled = file1->AsHandle(&error, &handle);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Pull a file descriptor out of the scoped handle.
@@ -682,16 +693,17 @@ TEST_F(FileImplTest, AsHandle) {
// Reopen my_file.
mojom::FilePtr file2;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file2),
- mojom::kFlagRead | mojom::kFlagOpen, Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled =
+ directory->OpenFile("my_file", GetProxy(&file2),
+ mojom::kFlagRead | mojom::kFlagOpen, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Verify that we wrote data raw on the file descriptor.
mojo::Array<uint8_t> bytes_read;
error = mojom::FileError::FAILED;
- file2->Read(5, 0, mojom::Whence::FROM_BEGIN, Capture(&error, &bytes_read));
- ASSERT_TRUE(file2.WaitForIncomingResponse());
+ handled = file2->Read(5, 0, mojom::Whence::FROM_BEGIN, &error, &bytes_read);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
ASSERT_EQ(5u, bytes_read.size());
EXPECT_EQ(static_cast<uint8_t>('h'), bytes_read[0]);
@@ -710,22 +722,22 @@ TEST_F(FileImplTest, SimpleLockUnlock) {
// Create my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled = directory->OpenFile(
+ "my_file", GetProxy(&file),
+ mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Lock the file.
error = mojom::FileError::FAILED;
- file->Lock(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Lock(&error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Unlock the file.
error = mojom::FileError::FAILED;
- file->Unlock(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Unlock(&error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
@@ -737,22 +749,22 @@ TEST_F(FileImplTest, CantDoubleLock) {
// Create my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile("my_file", GetProxy(&file),
- mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ bool handled = directory->OpenFile(
+ "my_file", GetProxy(&file),
+ mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagCreate, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Lock the file.
error = mojom::FileError::FAILED;
- file->Lock(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Lock(&error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Lock the file again.
error = mojom::FileError::OK;
- file->Lock(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Lock(&error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::FAILED, error);
}
@@ -765,17 +777,16 @@ TEST_F(FileImplTest, ClosingFileClearsLock) {
// Create my_file.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile(
+ bool handled = directory->OpenFile(
"my_file", GetProxy(&file),
- mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagOpenAlways,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagOpenAlways, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// Lock the file.
error = mojom::FileError::FAILED;
- file->Lock(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Lock(&error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
@@ -783,17 +794,16 @@ TEST_F(FileImplTest, ClosingFileClearsLock) {
// Open the file again.
mojom::FilePtr file;
error = mojom::FileError::FAILED;
- directory->OpenFile(
+ bool handled = directory->OpenFile(
"my_file", GetProxy(&file),
- mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagOpenAlways,
- Capture(&error));
- ASSERT_TRUE(directory.WaitForIncomingResponse());
+ mojom::kFlagRead | mojom::kFlagWrite | mojom::kFlagOpenAlways, &error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
// The file shouldn't be locked (and we check by trying to lock it).
error = mojom::FileError::FAILED;
- file->Lock(Capture(&error));
- ASSERT_TRUE(file.WaitForIncomingResponse());
+ handled = file->Lock(&error);
+ ASSERT_TRUE(handled);
EXPECT_EQ(mojom::FileError::OK, error);
}
}
diff --git a/chromium/components/filesystem/file_system_app.cc b/chromium/components/filesystem/file_system_app.cc
index 1b8d0afd623..054545d9a1f 100644
--- a/chromium/components/filesystem/file_system_app.cc
+++ b/chromium/components/filesystem/file_system_app.cc
@@ -9,6 +9,7 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/shell/public/cpp/connection.h"
#include "services/shell/public/cpp/connector.h"
@@ -39,22 +40,22 @@ FileSystemApp::FileSystemApp() : lock_table_(new LockTable) {}
FileSystemApp::~FileSystemApp() {}
-void FileSystemApp::Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) {
- tracing_.Initialize(connector, identity.name());
+void FileSystemApp::OnStart(const shell::Identity& identity) {
+ tracing_.Initialize(connector(), identity.name());
}
-bool FileSystemApp::AcceptConnection(shell::Connection* connection) {
- connection->AddInterface<mojom::FileSystem>(this);
+bool FileSystemApp::OnConnect(const shell::Identity& remote_identity,
+ shell::InterfaceRegistry* registry) {
+ registry->AddInterface<mojom::FileSystem>(this);
return true;
}
// |InterfaceFactory<Files>| implementation:
-void FileSystemApp::Create(shell::Connection* connection,
- mojo::InterfaceRequest<mojom::FileSystem> request) {
- new FileSystemImpl(connection, std::move(request), GetUserDataDir(),
- lock_table_);
+void FileSystemApp::Create(const shell::Identity& remote_identity,
+ mojom::FileSystemRequest request) {
+ mojo::MakeStrongBinding(base::MakeUnique<FileSystemImpl>(
+ remote_identity, GetUserDataDir(), lock_table_),
+ std::move(request));
}
//static
diff --git a/chromium/components/filesystem/file_system_app.h b/chromium/components/filesystem/file_system_app.h
index 452686a3109..ee72a60831a 100644
--- a/chromium/components/filesystem/file_system_app.h
+++ b/chromium/components/filesystem/file_system_app.h
@@ -11,8 +11,8 @@
#include "components/filesystem/lock_table.h"
#include "components/filesystem/public/interfaces/file_system.mojom.h"
#include "services/shell/public/cpp/interface_factory.h"
-#include "services/shell/public/cpp/shell_client.h"
-#include "services/tracing/public/cpp/tracing_impl.h"
+#include "services/shell/public/cpp/service.h"
+#include "services/tracing/public/cpp/provider.h"
namespace mojo {
class Connector;
@@ -20,7 +20,7 @@ class Connector;
namespace filesystem {
-class FileSystemApp : public shell::ShellClient,
+class FileSystemApp : public shell::Service,
public shell::InterfaceFactory<mojom::FileSystem> {
public:
FileSystemApp();
@@ -30,16 +30,16 @@ class FileSystemApp : public shell::ShellClient,
// Gets the system specific toplevel profile directory.
static base::FilePath GetUserDataDir();
- // |shell::ShellClient| override:
- void Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) override;
- bool AcceptConnection(shell::Connection* connection) override;
+ // |shell::Service| override:
+ void OnStart(const shell::Identity& identity) override;
+ bool OnConnect(const shell::Identity& remote_identity,
+ shell::InterfaceRegistry* registry) override;
+
// |InterfaceFactory<Files>| implementation:
- void Create(shell::Connection* connection,
+ void Create(const shell::Identity& remote_identity,
mojo::InterfaceRequest<mojom::FileSystem> request) override;
- mojo::TracingImpl tracing_;
+ tracing::Provider tracing_;
scoped_refptr<LockTable> lock_table_;
diff --git a/chromium/components/filesystem/file_system_impl.cc b/chromium/components/filesystem/file_system_impl.cc
index c2303d79e1f..1dc80086902 100644
--- a/chromium/components/filesystem/file_system_impl.cc
+++ b/chromium/components/filesystem/file_system_impl.cc
@@ -17,17 +17,16 @@
#include "build/build_config.h"
#include "components/filesystem/directory_impl.h"
#include "components/filesystem/lock_table.h"
-#include "services/shell/public/cpp/connection.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/shell/public/cpp/identity.h"
#include "url/gurl.h"
namespace filesystem {
-FileSystemImpl::FileSystemImpl(shell::Connection* connection,
- mojom::FileSystemRequest request,
+FileSystemImpl::FileSystemImpl(const shell::Identity& remote_identity,
base::FilePath persistent_dir,
scoped_refptr<LockTable> lock_table)
- : remote_application_name_(connection->GetRemoteIdentity().name()),
- binding_(this, std::move(request)),
+ : remote_application_name_(remote_identity.name()),
lock_table_(std::move(lock_table)),
persistent_dir_(persistent_dir) {}
@@ -35,17 +34,18 @@ FileSystemImpl::~FileSystemImpl() {
}
void FileSystemImpl::OpenTempDirectory(
- mojo::InterfaceRequest<mojom::Directory> directory,
+ mojom::DirectoryRequest directory,
const OpenTempDirectoryCallback& callback) {
// Set only if the |DirectoryImpl| will own a temporary directory.
std::unique_ptr<base::ScopedTempDir> temp_dir(new base::ScopedTempDir);
CHECK(temp_dir->CreateUniqueTempDir());
- base::FilePath path = temp_dir->path();
+ base::FilePath path = temp_dir->GetPath();
scoped_refptr<SharedTempDir> shared_temp_dir =
new SharedTempDir(std::move(temp_dir));
- new DirectoryImpl(
- std::move(directory), path, std::move(shared_temp_dir), lock_table_);
+ mojo::MakeStrongBinding(base::MakeUnique<DirectoryImpl>(
+ path, std::move(shared_temp_dir), lock_table_),
+ std::move(directory));
callback.Run(mojom::FileError::OK);
}
@@ -60,8 +60,9 @@ void FileSystemImpl::OpenPersistentFileSystem(
scoped_refptr<SharedTempDir> shared_temp_dir =
new SharedTempDir(std::move(temp_dir));
- new DirectoryImpl(
- std::move(directory), path, std::move(shared_temp_dir), lock_table_);
+ mojo::MakeStrongBinding(base::MakeUnique<DirectoryImpl>(
+ path, std::move(shared_temp_dir), lock_table_),
+ std::move(directory));
callback.Run(mojom::FileError::OK);
}
diff --git a/chromium/components/filesystem/file_system_impl.h b/chromium/components/filesystem/file_system_impl.h
index 05a2cbeb813..8e8abd268d2 100644
--- a/chromium/components/filesystem/file_system_impl.h
+++ b/chromium/components/filesystem/file_system_impl.h
@@ -10,14 +10,13 @@
#include "components/filesystem/public/interfaces/file_system.mojom.h"
#include "components/filesystem/shared_temp_dir.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
namespace base {
class FilePath;
}
namespace shell {
-class Connection;
+class Identity;
}
namespace filesystem {
@@ -30,22 +29,20 @@ class FileSystemImpl : public mojom::FileSystem {
public:
// |persistent_dir| is the directory served to callers of
// |OpenPersistentFileSystem().
- FileSystemImpl(shell::Connection* connection,
- mojo::InterfaceRequest<mojom::FileSystem> request,
+ FileSystemImpl(const shell::Identity& remote_identity,
base::FilePath persistent_dir,
scoped_refptr<LockTable> lock_table);
~FileSystemImpl() override;
// |Files| implementation:
- void OpenTempDirectory(mojo::InterfaceRequest<mojom::Directory> directory,
+ void OpenTempDirectory(mojom::DirectoryRequest directory,
const OpenTempDirectoryCallback& callback) override;
void OpenPersistentFileSystem(
- mojo::InterfaceRequest<mojom::Directory> directory,
+ mojom::DirectoryRequest directory,
const OpenPersistentFileSystemCallback& callback) override;
private:
const std::string remote_application_name_;
- mojo::StrongBinding<mojom::FileSystem> binding_;
scoped_refptr<LockTable> lock_table_;
base::FilePath persistent_dir_;
diff --git a/chromium/components/filesystem/files_test_base.cc b/chromium/components/filesystem/files_test_base.cc
index c1a6d8b4fc2..94728272245 100644
--- a/chromium/components/filesystem/files_test_base.cc
+++ b/chromium/components/filesystem/files_test_base.cc
@@ -12,21 +12,22 @@
namespace filesystem {
-FilesTestBase::FilesTestBase() : ShellTest("exe:filesystem_service_unittests") {
+FilesTestBase::FilesTestBase()
+ : ServiceTest("exe:filesystem_service_unittests") {
}
FilesTestBase::~FilesTestBase() {
}
void FilesTestBase::SetUp() {
- ShellTest::SetUp();
- connector()->ConnectToInterface("mojo:filesystem", &files_);
+ ServiceTest::SetUp();
+ connector()->ConnectToInterface("service:filesystem", &files_);
}
void FilesTestBase::GetTemporaryRoot(mojom::DirectoryPtr* directory) {
mojom::FileError error = mojom::FileError::FAILED;
- files()->OpenTempDirectory(GetProxy(directory), Capture(&error));
- ASSERT_TRUE(files().WaitForIncomingResponse());
+ bool handled = files()->OpenTempDirectory(GetProxy(directory), &error);
+ ASSERT_TRUE(handled);
ASSERT_EQ(mojom::FileError::OK, error);
}
diff --git a/chromium/components/filesystem/files_test_base.h b/chromium/components/filesystem/files_test_base.h
index fc594b0e682..8712a6c5f25 100644
--- a/chromium/components/filesystem/files_test_base.h
+++ b/chromium/components/filesystem/files_test_base.h
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "components/filesystem/public/interfaces/file_system.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
namespace filesystem {
@@ -37,12 +37,12 @@ base::Callback<void(T1, T2, T3)> Capture(T1* t1, T2* t2, T3* t3) {
return base::Bind(&DoCaptures<T1, T2, T3>, t1, t2, t3);
}
-class FilesTestBase : public shell::test::ShellTest {
+class FilesTestBase : public shell::test::ServiceTest {
public:
FilesTestBase();
~FilesTestBase() override;
- // Overridden from shell::test::ShellTest:
+ // Overridden from shell::test::ServiceTest:
void SetUp() override;
protected:
diff --git a/chromium/components/filesystem/filesystem.gyp b/chromium/components/filesystem/filesystem.gyp
deleted file mode 100644
index a2b737feb88..00000000000
--- a/chromium/components/filesystem/filesystem.gyp
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- # This turns on e.g. the filename-based detection of which
- # platforms to include source files on (e.g. files ending in
- # _mac.h or _mac.cc are only compiled on MacOSX).
- 'chromium_code': 1,
- },
- 'targets': [
- {
- # GN version: //components/filesystem:lib
- 'target_name': 'filesystem_lib',
- 'type': 'static_library',
- 'include_dirs': [
- '../..',
- ],
- 'sources': [
- 'directory_impl.cc',
- 'directory_impl.h',
- 'file_impl.cc',
- 'file_impl.h',
- 'file_system_impl.cc',
- 'file_system_impl.h',
- 'lock_table.cc',
- 'lock_table.h',
- 'shared_temp_dir.cc',
- 'shared_temp_dir.h',
- 'util.cc',
- 'util.h',
- ],
- 'dependencies': [
- 'filesystem_bindings',
- '../../mojo/mojo_edk.gyp:mojo_system_impl',
- '../../mojo/mojo_public.gyp:mojo_cpp_bindings',
- '../../mojo/mojo_public.gyp:mojo_cpp_system',
- '../../services/shell/shell_public.gyp:shell_public',
- '../../url/url.gyp:url_lib',
- ],
- 'export_dependent_settings': [
- 'filesystem_bindings',
- ],
- },
- {
- # GN version: //components/filesystem/public/interfaces
- 'target_name': 'filesystem_bindings',
- 'type': 'static_library',
- 'dependencies': [
- 'filesystem_bindings_mojom',
- ],
- 'hard_dependency': 1,
- },
- {
- 'target_name': 'filesystem_bindings_mojom',
- 'type': 'none',
- 'variables': {
- 'mojom_files': [
- 'public/interfaces/directory.mojom',
- 'public/interfaces/file.mojom',
- 'public/interfaces/file_system.mojom',
- 'public/interfaces/types.mojom',
- ],
- },
- 'includes': [
- '../../mojo/mojom_bindings_generator_explicit.gypi',
- ],
- }
- ],
-}
diff --git a/chromium/components/filesystem/main.cc b/chromium/components/filesystem/main.cc
index f73576e6a32..2d7d8a6468c 100644
--- a/chromium/components/filesystem/main.cc
+++ b/chromium/components/filesystem/main.cc
@@ -4,10 +4,10 @@
#include "base/macros.h"
#include "components/filesystem/file_system_app.h"
-#include "mojo/public/c/system/main.h"
-#include "services/shell/public/cpp/application_runner.h"
+#include "services/shell/public/c/main.h"
+#include "services/shell/public/cpp/service_runner.h"
-MojoResult MojoMain(MojoHandle request) {
- shell::ApplicationRunner runner(new filesystem::FileSystemApp());
+MojoResult ServiceMain(MojoHandle request) {
+ shell::ServiceRunner runner(new filesystem::FileSystemApp());
return runner.Run(request);
}
diff --git a/chromium/components/filesystem/manifest.json b/chromium/components/filesystem/manifest.json
index c03a0e185ae..f8ba9ff3c98 100644
--- a/chromium/components/filesystem/manifest.json
+++ b/chromium/components/filesystem/manifest.json
@@ -1,6 +1,6 @@
{
"manifest_version": 1,
- "name": "mojo:filesystem",
+ "name": "service:filesystem",
"display_name": "File System Service",
"capabilities": {
"required": {
diff --git a/chromium/components/filesystem/public/cpp/prefs/pref_service_factory.cc b/chromium/components/filesystem/public/cpp/prefs/pref_service_factory.cc
index c9837923f19..22a1f1db8be 100644
--- a/chromium/components/filesystem/public/cpp/prefs/pref_service_factory.cc
+++ b/chromium/components/filesystem/public/cpp/prefs/pref_service_factory.cc
@@ -26,7 +26,7 @@ void DoNothingHandleReadError(PersistentPrefStore::PrefReadError error) {}
std::unique_ptr<PrefService> CreatePrefService(shell::Connector* connector,
PrefRegistry* pref_registry) {
filesystem::mojom::FileSystemPtr filesystem;
- connector->ConnectToInterface("mojo:filesystem", &filesystem);
+ connector->ConnectToInterface("service:filesystem", &filesystem);
scoped_refptr<FilesystemJsonPrefStore> user_prefs =
new FilesystemJsonPrefStore("preferences.json", std::move(filesystem),
diff --git a/chromium/components/filesystem/public/interfaces/BUILD.gn b/chromium/components/filesystem/public/interfaces/BUILD.gn
index a1ef7b67574..32264fb7336 100644
--- a/chromium/components/filesystem/public/interfaces/BUILD.gn
+++ b/chromium/components/filesystem/public/interfaces/BUILD.gn
@@ -11,4 +11,6 @@ mojom("interfaces") {
"file_system.mojom",
"types.mojom",
]
+
+ use_new_wrapper_types = false
}
diff --git a/chromium/components/filesystem/public/interfaces/directory.mojom b/chromium/components/filesystem/public/interfaces/directory.mojom
index 98a2b8c619c..104a62f5528 100644
--- a/chromium/components/filesystem/public/interfaces/directory.mojom
+++ b/chromium/components/filesystem/public/interfaces/directory.mojom
@@ -91,9 +91,11 @@ interface Directory {
Clone(Directory& directory);
// Reads the contents of an entire file.
+ [Sync]
ReadEntireFile(string path) => (FileError error, array<uint8> data);
// Writes |data| to |path|, overwriting the file if it already exists.
+ [Sync]
WriteFile(string path, array<uint8> data) => (FileError error);
// TODO(vtl): directory "streaming"?
diff --git a/chromium/components/filesystem/public/interfaces/file.mojom b/chromium/components/filesystem/public/interfaces/file.mojom
index 6ef70676902..05bce45cbf2 100644
--- a/chromium/components/filesystem/public/interfaces/file.mojom
+++ b/chromium/components/filesystem/public/interfaces/file.mojom
@@ -16,6 +16,7 @@ interface File {
// Flushes/closes this file; no operations may be performed on this file after
// this. Note that any error code is strictly informational -- the close may
// not be retried.
+ [Sync]
Close() => (FileError err);
// Reads (at most) |num_bytes_to_read| from the location specified by
@@ -24,42 +25,51 @@ interface File {
// are read.
// TODO(vtl): Clarify when (for what values of |offset|/|whence|) this
// modifies the file position. Or maybe there should be a flag?
+ [Sync]
Read(uint32 num_bytes_to_read, int64 offset, Whence whence)
=> (FileError error, array<uint8>? bytes_read);
// Writes |bytes_to_write| to the location specified by |offset|/|whence|.
// TODO(vtl): Clarify behavior when |num_bytes_written| is less than the size
// of |bytes_to_write|.
+ [Sync]
Write(array<uint8> bytes_to_write, int64 offset, Whence whence)
=> (FileError error, uint32 num_bytes_written);
// Gets the current file position. On success, |position| is the current
// offset (in bytes) from the beginning of the file).
+ [Sync]
Tell() => (FileError error, int64 position);
// Sets the current file position to that specified by |offset|/|whence|. On
// success, |position| is the offset (in bytes) from the beginning of the
// file.
+ [Sync]
Seek(int64 offset, Whence whence) => (FileError error, int64 position);
// Gets information about this file. On success, |file_information| is
// non-null and will contain this information.
+ [Sync]
Stat() => (FileError error, FileInformation? file_information);
// Truncates this file to the size specified by |size| (in bytes).
+ [Sync]
Truncate(int64 size) => (FileError error);
// Updates this file's atime and/or mtime to the time specified by |atime| (or
// |mtime|, respectively), which may also indicate "now". If |atime| or
// |mtime| is null, then the corresponding time is not modified.
+ [Sync]
Touch(TimespecOrNow? atime, TimespecOrNow? mtime) => (FileError error);
// Creates a new |File| instance, which shares the same "file description".
// I.e., the access mode, etc. (as specified to |Directory::OpenFile()| by the
// |open_flags| argument) as well as file position.
+ [Sync]
Dup(File& file) => (FileError error);
// Syncs data to disk.
+ [Sync]
Flush() => (FileError error);
// Attempts to take an exclusive write lock on the file. This both takes a
@@ -73,5 +83,6 @@ interface File {
Unlock() => (FileError error);
// Returns a handle to the file for raw access.
+ [Sync]
AsHandle() => (FileError error, handle file_handle);
};
diff --git a/chromium/components/filesystem/public/interfaces/file_system.mojom b/chromium/components/filesystem/public/interfaces/file_system.mojom
index 52b98684b19..a2ab796129e 100644
--- a/chromium/components/filesystem/public/interfaces/file_system.mojom
+++ b/chromium/components/filesystem/public/interfaces/file_system.mojom
@@ -10,8 +10,10 @@ import "components/filesystem/public/interfaces/types.mojom";
interface FileSystem {
// Opens a temporary filesystem. Will return a different directory each time
// it is called.
+ [Sync]
OpenTempDirectory(Directory& directory) => (FileError error);
// Returns a directory which will persist to disk.
+ [Sync]
OpenPersistentFileSystem(Directory& directory) => (FileError error);
};
diff --git a/chromium/components/filesystem/test_manifest.json b/chromium/components/filesystem/test_manifest.json
index 1dc20525ede..370d74b08ab 100644
--- a/chromium/components/filesystem/test_manifest.json
+++ b/chromium/components/filesystem/test_manifest.json
@@ -4,7 +4,7 @@
"display_name": "Filesystem Service Unittests",
"capabilities": {
"required": {
- "mojo:filesystem": { "interfaces": [ "filesystem::mojom::FileSystem" ] }
+ "service:filesystem": { "interfaces": [ "filesystem::mojom::FileSystem" ] }
}
}
}
diff --git a/chromium/components/flags_ui.gypi b/chromium/components/flags_ui.gypi
deleted file mode 100644
index 31e3653e143..00000000000
--- a/chromium/components/flags_ui.gypi
+++ /dev/null
@@ -1,79 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/flags_ui
- 'target_name': 'flags_ui',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../components/components_strings.gyp:components_strings',
- '../components/prefs/prefs.gyp:prefs',
- '../ui/base/ui_base.gyp:ui_base',
- 'flags_ui_switches',
- 'pref_registry',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'flags_ui/feature_entry.cc',
- 'flags_ui/feature_entry.h',
- 'flags_ui/feature_entry_macros.h',
- 'flags_ui/flags_state.cc',
- 'flags_ui/flags_state.h',
- 'flags_ui/flags_storage.h',
- 'flags_ui/flags_ui_constants.cc',
- 'flags_ui/flags_ui_constants.h',
- 'flags_ui/flags_ui_pref_names.cc',
- 'flags_ui/flags_ui_pref_names.h',
- 'flags_ui/pref_service_flags_storage.cc',
- 'flags_ui/pref_service_flags_storage.h',
- ],
- },
- {
- # GN version: //components/flags_ui:switches
- # This is a separate target so that the dependencies of
- # //chrome/common can be kept minimal.
- 'target_name': 'flags_ui_switches',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'flags_ui/flags_ui_switches.cc',
- 'flags_ui/flags_ui_switches.h',
- ],
- },
- ],
- 'conditions': [
- ['OS=="win" and target_arch=="ia32"', {
- 'targets': [
- {
- # The flags_ui_switches_win64 target here allows us to use base for
- # Win64 targets (the normal build is 32 bits).
- 'target_name': 'flags_ui_switches_win64',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'flags_ui/flags_ui_switches.cc',
- 'flags_ui/flags_ui_switches.h',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/flags_ui/BUILD.gn b/chromium/components/flags_ui/BUILD.gn
index 36cfed8a719..9d085a16ad0 100644
--- a/chromium/components/flags_ui/BUILD.gn
+++ b/chromium/components/flags_ui/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("flags_ui") {
+static_library("flags_ui") {
sources = [
"feature_entry.cc",
"feature_entry.h",
@@ -31,7 +31,7 @@ source_set("flags_ui") {
# This is a separate target so that the dependencies of
# //chrome/common can be kept minimal.
-source_set("switches") {
+static_library("switches") {
sources = [
"flags_ui_switches.cc",
"flags_ui_switches.h",
@@ -48,6 +48,7 @@ source_set("unit_tests") {
":flags_ui",
":switches",
"//base",
+ "//base/test:test_support",
"//components/prefs:test_support",
"//components/strings",
"//components/variations",
diff --git a/chromium/components/flags_ui/feature_entry.cc b/chromium/components/flags_ui/feature_entry.cc
index 53a219c3d55..80ea2a72e3e 100644
--- a/chromium/components/flags_ui/feature_entry.cc
+++ b/chromium/components/flags_ui/feature_entry.cc
@@ -41,11 +41,10 @@ base::string16 FeatureEntry::DescriptionForOption(int index) const {
if (index == 0) {
description_id = IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT;
} else if (index == 1) {
- // Variation 1: the default enabled variation => "Enabled".
description_id = IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED;
} else if (index < num_options - 1) {
- // Variations 2 .. n => "Enabled <description_text>".
- int variation_index = index - 1;
+ // First two options do not have variations params.
+ int variation_index = index - 2;
return l10n_util::GetStringUTF16(IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED) +
base::ASCIIToUTF16(" ") +
base::ASCIIToUTF16(
@@ -86,11 +85,12 @@ const FeatureEntry::FeatureVariation* FeatureEntry::VariationForOption(
type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
DCHECK_LT(index, num_options);
- if (type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE && index > 0 &&
+ if (type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE && index > 1 &&
index < num_options - 1) {
// We have no variations for FEATURE_VALUE type. Option at |index|
- // corresponds to variation at |index| - 1 as the first option is "Default".
- return &feature_variations[index - 1];
+ // corresponds to variation at |index| - 2 as the list starts with "Default"
+ // and "Enabled" (with default parameters).
+ return &feature_variations[index - 2];
}
return nullptr;
}
diff --git a/chromium/components/flags_ui/feature_entry.h b/chromium/components/flags_ui/feature_entry.h
index a3930fd2e13..8bf57b8d3f1 100644
--- a/chromium/components/flags_ui/feature_entry.h
+++ b/chromium/components/flags_ui/feature_entry.h
@@ -50,10 +50,12 @@ struct FeatureEntry {
// Corresponds to a base::Feature and additional options [O_1, ..., O_n]
// that specify variation parameters. Each of the options can specify a set
- // of variation parameters. The entry will have n+2 states: Default,
- // Enabled: V_1, ..., Enabled: V_n, Disabled. When not specified or set to
- // Default, the normal default values of the feature and of the parameters
- // are used.
+ // of variation parameters. The entry will have n+3 states: Default,
+ // Enabled, Enabled V_1, ..., Enabled: V_n, Disabled. When set to Default,
+ // the normal default values of the feature and of the parameters are used
+ // (possibly passed from the server in a trial config). When set to Enabled,
+ // the feature is overriden to be enabled and empty set of parameters is
+ // used boiling down to the default behavior in the code.
FEATURE_WITH_VARIATIONS_VALUE,
};
@@ -97,6 +99,10 @@ struct FeatureEntry {
const char* description_text;
const FeatureParam* params;
int num_params;
+ // A variation id number in the format of
+ // VariationsHttpHeaderProvider::SetDefaultVariationIds or nullptr
+ // if you do not need to set any variation_id for this feature variation.
+ const char* variation_id;
};
// The internal name of the feature entry. This is never shown to the user.
diff --git a/chromium/components/flags_ui/feature_entry_macros.h b/chromium/components/flags_ui/feature_entry_macros.h
index 9394b37303a..f83ce31252f 100644
--- a/chromium/components/flags_ui/feature_entry_macros.h
+++ b/chromium/components/flags_ui/feature_entry_macros.h
@@ -35,7 +35,7 @@
#define FEATURE_WITH_VARIATIONS_VALUE_TYPE(feature, feature_variations, \
feature_trial) \
flags_ui::FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE, nullptr, nullptr, \
- nullptr, nullptr, &feature, 2 + arraysize(feature_variations), nullptr, \
+ nullptr, nullptr, &feature, 3 + arraysize(feature_variations), nullptr, \
feature_variations, feature_trial
#endif // COMPONENTS_FLAGS_UI_FEATURE_ENTRY_MACROS_H_
diff --git a/chromium/components/flags_ui/flags_state.cc b/chromium/components/flags_ui/flags_state.cc
index cadb8ee1401..7f039633e7a 100644
--- a/chromium/components/flags_ui/flags_state.cc
+++ b/chromium/components/flags_ui/flags_state.cc
@@ -197,36 +197,38 @@ base::Value* CreateOptionsData(const FeatureEntry& entry,
// been created (e.g. via command-line switches that take precedence over
// about:flags). In the trial, the function creates a new constant group called
// |kTrialGroupAboutFlags|.
-void RegisterFeatureVariationParameters(
+base::FieldTrial* RegisterFeatureVariationParameters(
const std::string& feature_trial_name,
- const FeatureEntry::FeatureVariation& feature_variation) {
+ const FeatureEntry::FeatureVariation* feature_variation) {
std::map<std::string, std::string> params;
- for (int i = 0; i < feature_variation.num_params; ++i) {
- params[feature_variation.params[i].param_name] =
- feature_variation.params[i].param_value;
+ if (feature_variation) {
+ // Copy the parameters for non-null variations.
+ for (int i = 0; i < feature_variation->num_params; ++i) {
+ params[feature_variation->params[i].param_name] =
+ feature_variation->params[i].param_value;
+ }
}
bool success = variations::AssociateVariationParams(
feature_trial_name, internal::kTrialGroupAboutFlags, params);
- if (success) {
- // Successful association also means that no group is created and selected
- // for the trial, yet. Thus, create the trial to select the group. This way,
- // the parameters cannot get overwritten in later phases (such as from the
- // server).
- base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
- feature_trial_name, internal::kTrialGroupAboutFlags);
- if (!trial) {
- DLOG(WARNING) << "Could not create the trial " << feature_trial_name
- << " with group " << internal::kTrialGroupAboutFlags;
- }
+ if (!success)
+ return nullptr;
+ // Successful association also means that no group is created and selected
+ // for the trial, yet. Thus, create the trial to select the group. This way,
+ // the parameters cannot get overwritten in later phases (such as from the
+ // server).
+ base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
+ feature_trial_name, internal::kTrialGroupAboutFlags);
+ if (!trial) {
+ DLOG(WARNING) << "Could not create the trial " << feature_trial_name
+ << " with group " << internal::kTrialGroupAboutFlags;
}
+ return trial;
}
} // namespace
-// Keeps track of affected switches for each FeatureEntry, based on which
-// choice is selected for it.
-struct SwitchEntry {
+struct FlagsState::SwitchEntry {
// Corresponding base::Feature to toggle.
std::string feature_name;
@@ -257,53 +259,54 @@ void FlagsState::ConvertFlagsToSwitches(
const char* enable_features_flag_name,
const char* disable_features_flag_name) {
std::set<std::string> enabled_entries;
+ std::map<std::string, SwitchEntry> name_to_switch_map;
+ GenerateFlagsToSwitchesMapping(flags_storage, &enabled_entries,
+ &name_to_switch_map);
+ AddSwitchesToCommandLine(enabled_entries, name_to_switch_map, sentinels,
+ command_line, enable_features_flag_name,
+ disable_features_flag_name);
+}
- GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, &enabled_entries);
+std::set<std::string> FlagsState::GetSwitchesFromFlags(
+ FlagsStorage* flags_storage) {
+ std::set<std::string> enabled_entries;
+ std::map<std::string, SwitchEntry> name_to_switch_map;
+ GenerateFlagsToSwitchesMapping(flags_storage, &enabled_entries,
+ &name_to_switch_map);
+ std::set<std::string> switches;
+ for (const std::string& entry_name : enabled_entries) {
+ const auto& entry_it = name_to_switch_map.find(entry_name);
+ DCHECK(entry_it != name_to_switch_map.end());
+
+ const SwitchEntry& entry = entry_it->second;
+ if (!entry.switch_name.empty())
+ switches.insert("--" + entry.switch_name);
+ }
+ return switches;
+}
+
+std::set<std::string> FlagsState::GetFeaturesFromFlags(
+ FlagsStorage* flags_storage) {
+ std::set<std::string> enabled_entries;
std::map<std::string, SwitchEntry> name_to_switch_map;
- for (size_t i = 0; i < num_feature_entries_; ++i) {
- const FeatureEntry& e = feature_entries_[i];
- switch (e.type) {
- case FeatureEntry::SINGLE_VALUE:
- case FeatureEntry::SINGLE_DISABLE_VALUE:
- AddSwitchMapping(e.internal_name, e.command_line_switch,
- e.command_line_value, &name_to_switch_map);
- break;
- case FeatureEntry::MULTI_VALUE:
- for (int j = 0; j < e.num_options; ++j) {
- AddSwitchMapping(
- e.NameForOption(j), e.ChoiceForOption(j).command_line_switch,
- e.ChoiceForOption(j).command_line_value, &name_to_switch_map);
- }
- break;
- case FeatureEntry::ENABLE_DISABLE_VALUE:
- AddSwitchMapping(e.NameForOption(0), std::string(), std::string(),
- &name_to_switch_map);
- AddSwitchMapping(e.NameForOption(1), e.command_line_switch,
- e.command_line_value, &name_to_switch_map);
- AddSwitchMapping(e.NameForOption(2), e.disable_command_line_switch,
- e.disable_command_line_value, &name_to_switch_map);
- break;
- case FeatureEntry::FEATURE_VALUE:
- case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
- for (int j = 0; j < e.num_options; ++j) {
- FeatureEntry::FeatureState state = e.StateForOption(j);
- if (state == FeatureEntry::FeatureState::DEFAULT) {
- AddFeatureMapping(e.NameForOption(j), std::string(), false,
- &name_to_switch_map);
- } else {
- AddFeatureMapping(e.NameForOption(j), e.feature->name,
- state == FeatureEntry::FeatureState::ENABLED,
- &name_to_switch_map);
- }
- }
- break;
+ GenerateFlagsToSwitchesMapping(flags_storage, &enabled_entries,
+ &name_to_switch_map);
+
+ std::set<std::string> features;
+ for (const std::string& entry_name : enabled_entries) {
+ const auto& entry_it = name_to_switch_map.find(entry_name);
+ DCHECK(entry_it != name_to_switch_map.end());
+
+ const SwitchEntry& entry = entry_it->second;
+ if (!entry.feature_name.empty()) {
+ if (entry.feature_state)
+ features.insert(entry.feature_name + ":enabled");
+ else
+ features.insert(entry.feature_name + ":disabled");
}
}
-
- AddSwitchesToCommandLine(enabled_entries, name_to_switch_map, sentinels,
- command_line, enable_features_flag_name,
- disable_features_flag_name);
+ return features;
}
bool FlagsState::IsRestartNeededToCommitChanges() {
@@ -400,7 +403,7 @@ void FlagsState::RemoveFlagsSwitches(
// For any featrue name in |features| that is not in |switch_added_values| -
// i.e. it wasn't added by about_flags code, add it to |remaining_features|.
for (const std::string& feature : features) {
- if (!ContainsKey(switch_added_values, feature))
+ if (!base::ContainsKey(switch_added_values, feature))
remaining_features.push_back(feature);
}
@@ -432,10 +435,12 @@ void FlagsState::Reset() {
appended_switches_.clear();
}
-void FlagsState::RegisterAllFeatureVariationParameters(
- FlagsStorage* flags_storage) {
+std::vector<std::string> FlagsState::RegisterAllFeatureVariationParameters(
+ FlagsStorage* flags_storage,
+ base::FeatureList* feature_list) {
std::set<std::string> enabled_entries;
GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, &enabled_entries);
+ std::vector<std::string> variation_ids;
for (size_t i = 0; i < num_feature_entries_; ++i) {
const FeatureEntry& e = feature_entries_[i];
@@ -443,25 +448,26 @@ void FlagsState::RegisterAllFeatureVariationParameters(
for (int j = 0; j < e.num_options; ++j) {
const FeatureEntry::FeatureVariation* variation =
e.VariationForOption(j);
- if (variation != nullptr && enabled_entries.count(e.NameForOption(j))) {
+ if (e.StateForOption(j) == FeatureEntry::FeatureState::ENABLED &&
+ enabled_entries.count(e.NameForOption(j))) {
// If the option is selected by the user & has variation, register it.
- RegisterFeatureVariationParameters(e.feature_trial_name, *variation);
- // TODO(jkrcal) The code does not associate the feature with the field
- // trial |e.feature_trial_name|. The reason is that features
- // overridden in chrome://flags are translated to command-line flags
- // and thus treated earlier in the initialization. The fix requires
- // larger changes. As a result:
- // - the API calls to variations::GetVariationParamValueByFeature and
- // to variations::GetVariationParamsByFeature do not work; and
- // - the API call to base::FeatureList::IsEnabled does not mark the
- // field trial as active (and the trial does not appear in UMA).
- // If the code calls variations::GetVariationParamValue or
- // variations::GetVariationParams providing the trial name, everything
- // should work fine.
+ base::FieldTrial* field_trial = RegisterFeatureVariationParameters(
+ e.feature_trial_name, variation);
+
+ if (!field_trial)
+ continue;
+ feature_list->RegisterFieldTrialOverride(
+ e.feature->name,
+ base::FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE,
+ field_trial);
+
+ if (variation && variation->variation_id)
+ variation_ids.push_back(variation->variation_id);
}
}
}
}
+ return variation_ids;
}
void FlagsState::GetFlagFeatureEntries(
@@ -480,7 +486,7 @@ void FlagsState::GetFlagFeatureEntries(
if (skip_feature_entry.Run(entry))
continue;
- base::DictionaryValue* data = new base::DictionaryValue();
+ std::unique_ptr<base::DictionaryValue> data(new base::DictionaryValue());
data->SetString("internal_name", entry.internal_name);
data->SetString("name", l10n_util::GetStringUTF16(entry.visible_name_id));
data->SetString("description",
@@ -522,9 +528,9 @@ void FlagsState::GetFlagFeatureEntries(
supported = ((entry.supported_platforms & kOsIosAppleReview) != 0);
#endif
if (supported)
- supported_entries->Append(data);
+ supported_entries->Append(std::move(data));
else
- unsupported_entries->Append(data);
+ unsupported_entries->Append(std::move(data));
}
}
@@ -585,7 +591,7 @@ void FlagsState::AddSwitchMapping(
const std::string& switch_name,
const std::string& switch_value,
std::map<std::string, SwitchEntry>* name_to_switch_map) {
- DCHECK(!ContainsKey(*name_to_switch_map, key));
+ DCHECK(!base::ContainsKey(*name_to_switch_map, key));
SwitchEntry* entry = &(*name_to_switch_map)[key];
entry->switch_name = switch_name;
@@ -597,7 +603,7 @@ void FlagsState::AddFeatureMapping(
const std::string& feature_name,
bool feature_state,
std::map<std::string, SwitchEntry>* name_to_switch_map) {
- DCHECK(!ContainsKey(*name_to_switch_map, key));
+ DCHECK(!base::ContainsKey(*name_to_switch_map, key));
SwitchEntry* entry = &(*name_to_switch_map)[key];
entry->feature_name = feature_name;
@@ -658,11 +664,11 @@ void FlagsState::MergeFeatureCommandLineSwitch(
std::vector<std::string> features =
base::FeatureList::SplitFeatureListString(original_switch_value);
// Only add features that don't already exist in the lists.
- // Note: The ContainsValue() call results in O(n^2) performance, but in
+ // Note: The base::ContainsValue() call results in O(n^2) performance, but in
// practice n should be very small.
for (const auto& entry : feature_switches) {
if (entry.second == feature_state &&
- !ContainsValue(features, entry.first)) {
+ !base::ContainsValue(features, entry.first)) {
features.push_back(entry.first);
appended_switches_[switch_name].insert(entry.first);
}
@@ -725,4 +731,51 @@ void FlagsState::GetSanitizedEnabledFlagsForCurrentPlatform(
result->swap(new_enabled_entries);
}
+void FlagsState::GenerateFlagsToSwitchesMapping(
+ FlagsStorage* flags_storage,
+ std::set<std::string>* enabled_entries,
+ std::map<std::string, SwitchEntry>* name_to_switch_map) {
+ GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, enabled_entries);
+
+ for (size_t i = 0; i < num_feature_entries_; ++i) {
+ const FeatureEntry& e = feature_entries_[i];
+ switch (e.type) {
+ case FeatureEntry::SINGLE_VALUE:
+ case FeatureEntry::SINGLE_DISABLE_VALUE:
+ AddSwitchMapping(e.internal_name, e.command_line_switch,
+ e.command_line_value, name_to_switch_map);
+ break;
+ case FeatureEntry::MULTI_VALUE:
+ for (int j = 0; j < e.num_options; ++j) {
+ AddSwitchMapping(
+ e.NameForOption(j), e.ChoiceForOption(j).command_line_switch,
+ e.ChoiceForOption(j).command_line_value, name_to_switch_map);
+ }
+ break;
+ case FeatureEntry::ENABLE_DISABLE_VALUE:
+ AddSwitchMapping(e.NameForOption(0), std::string(), std::string(),
+ name_to_switch_map);
+ AddSwitchMapping(e.NameForOption(1), e.command_line_switch,
+ e.command_line_value, name_to_switch_map);
+ AddSwitchMapping(e.NameForOption(2), e.disable_command_line_switch,
+ e.disable_command_line_value, name_to_switch_map);
+ break;
+ case FeatureEntry::FEATURE_VALUE:
+ case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+ for (int j = 0; j < e.num_options; ++j) {
+ FeatureEntry::FeatureState state = e.StateForOption(j);
+ if (state == FeatureEntry::FeatureState::DEFAULT) {
+ AddFeatureMapping(e.NameForOption(j), std::string(), false,
+ name_to_switch_map);
+ } else {
+ AddFeatureMapping(e.NameForOption(j), e.feature->name,
+ state == FeatureEntry::FeatureState::ENABLED,
+ name_to_switch_map);
+ }
+ }
+ break;
+ }
+ }
+}
+
} // namespace flags_ui
diff --git a/chromium/components/flags_ui/flags_state.h b/chromium/components/flags_ui/flags_state.h
index 6f0ff1f87c8..17b3b99c532 100644
--- a/chromium/components/flags_ui/flags_state.h
+++ b/chromium/components/flags_ui/flags_state.h
@@ -10,12 +10,14 @@
#include <map>
#include <set>
#include <string>
+#include <vector>
#include "base/callback_forward.h"
#include "base/command_line.h"
#include "base/macros.h"
namespace base {
+class FeatureList;
class ListValue;
}
@@ -71,6 +73,17 @@ class FlagsState {
SentinelsMode sentinels,
const char* enable_features_flag_name,
const char* disable_features_flag_name);
+
+ // Reads the state from |flags_storage| and returns a set of strings
+ // corresponding to enabled entries. Does not populate any information about
+ // entries that enable/disable base::Feature states.
+ std::set<std::string> GetSwitchesFromFlags(FlagsStorage* flags_storage);
+
+ // Reads the state from |flags_storage| and returns a set of strings
+ // corresponding to enabled/disabled base::Feature states. Feature names are
+ // suffixed with ":enabled" or ":disabled" depending on their state.
+ std::set<std::string> GetFeaturesFromFlags(FlagsStorage* flags_storage);
+
bool IsRestartNeededToCommitChanges();
void SetFeatureEntryEnabled(FlagsStorage* flags_storage,
const std::string& internal_name,
@@ -80,9 +93,15 @@ class FlagsState {
void ResetAllFlags(FlagsStorage* flags_storage);
void Reset();
- // Registers variations parameter values stored in |flags_storage| (previously
- // selected in about:flags).
- void RegisterAllFeatureVariationParameters(FlagsStorage* flags_storage);
+ // Registers variations parameter values selected for features in about:flags.
+ // The selected flags are retrieved from |flags_storage|, the registered
+ // variation parameters are connected to their corresponding features in
+ // |feature_list|. Returns the (possibly empty) comma separated list of
+ // additional variation ids to register in the MetricsService that come from
+ // variations selected using chrome://flags.
+ std::vector<std::string> RegisterAllFeatureVariationParameters(
+ FlagsStorage* flags_storage,
+ base::FeatureList* feature_list);
// Gets the list of feature entries. Entries that are available for the
// current platform are appended to |supported_entries|; all other entries are
@@ -114,6 +133,10 @@ class FlagsState {
const char* extra_flag_sentinel_end_flag_name);
private:
+ // Keeps track of affected switches for each FeatureEntry, based on which
+ // choice is selected for it.
+ struct SwitchEntry;
+
// Adds mapping to |name_to_switch_map| to set the given switch name/value.
void AddSwitchMapping(const std::string& key,
const std::string& switch_name,
@@ -163,6 +186,15 @@ class FlagsState {
FlagsStorage* flags_storage,
std::set<std::string>* result);
+ // Generates a flags to switches mapping based on the set of enabled flags
+ // from |flags_storage|. On output, |enabled_entries| will contain the
+ // internal names of enabled flags and |name_to_switch_map| will contain
+ // information on how they map to command-line flags or features.
+ void GenerateFlagsToSwitchesMapping(
+ FlagsStorage* flags_storage,
+ std::set<std::string>* enabled_entries,
+ std::map<std::string, SwitchEntry>* name_to_switch_map);
+
const FeatureEntry* feature_entries_;
size_t num_feature_entries_;
diff --git a/chromium/components/flags_ui/flags_state_unittest.cc b/chromium/components/flags_ui/flags_state_unittest.cc
index b95373a5f4b..57893422d9d 100644
--- a/chromium/components/flags_ui/flags_state_unittest.cc
+++ b/chromium/components/flags_ui/flags_state_unittest.cc
@@ -19,6 +19,7 @@
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/flags_ui/feature_entry.h"
@@ -62,23 +63,18 @@ const char kDisableFeatures[] = "dummy-disable-features";
const char kTestTrial[] = "TestTrial";
const char kTestParam[] = "param";
-const char kTestParamValue1[] = "value1";
-const char kTestParamValue2[] = "value2";
+const char kTestParamValue[] = "value";
const base::Feature kTestFeature1{"FeatureName1",
base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kTestFeature2{"FeatureName2",
base::FEATURE_ENABLED_BY_DEFAULT};
-const FeatureEntry::FeatureParam kTestVariationDefault[] = {
- {kTestParam, kTestParamValue1}};
-
const FeatureEntry::FeatureParam kTestVariationOther[] = {
- {kTestParam, kTestParamValue2}};
+ {kTestParam, kTestParamValue}};
const FeatureEntry::FeatureVariation kTestVariations[] = {
- {"", kTestVariationDefault, 1},
- {"dummy description", kTestVariationOther, 1}};
+ {"dummy description", kTestVariationOther, 1, nullptr}};
// Those have to be valid ids for the translation system but the value are
// never used, so pick one at random from the current component.
@@ -148,6 +144,10 @@ class FlagsStateTest : public ::testing::Test {
flags_state_.reset(new FlagsState(kEntries, arraysize(kEntries)));
}
+ ~FlagsStateTest() override {
+ variations::testing::ClearAllVariationParams();
+ }
+
TestingPrefServiceSimple prefs_;
PrefServiceFlagsStorage flags_storage_;
std::unique_ptr<FlagsState> flags_state_;
@@ -268,23 +268,27 @@ TEST_F(FlagsStateTest, ConvertFlagsToSwitches) {
TEST_F(FlagsStateTest, RegisterAllFeatureVariationParameters) {
const FeatureEntry& entry = kEntries[7];
- // Select the "Disabled" variation.
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+
+ // Select the "Default" variation.
flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(0),
true);
- flags_state_->RegisterAllFeatureVariationParameters(&flags_storage_);
+ flags_state_->RegisterAllFeatureVariationParameters(&flags_storage_,
+ feature_list.get());
// No value should be associated.
EXPECT_EQ("", variations::GetVariationParamValue(kTestTrial, kTestParam));
// The trial should not be created.
base::FieldTrial* trial = base::FieldTrialList::Find(kTestTrial);
EXPECT_EQ(nullptr, trial);
- // Select the first "Enabled" variation.
+ // Select the default "Enabled" variation.
flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(1),
true);
- flags_state_->RegisterAllFeatureVariationParameters(&flags_storage_);
- // The value should be associated.
- EXPECT_EQ(kTestParamValue1,
+ flags_state_->RegisterAllFeatureVariationParameters(&flags_storage_,
+ feature_list.get());
+ // No value should be associated as this is the default option.
+ EXPECT_EQ("",
variations::GetVariationParamValue(kTestTrial, kTestParam));
// The trial should be created.
@@ -293,13 +297,38 @@ TEST_F(FlagsStateTest, RegisterAllFeatureVariationParameters) {
// The about:flags group should be selected for the trial.
EXPECT_EQ(internal::kTrialGroupAboutFlags, trial->group_name());
- // Select the second "Enabled" variation.
+ // Select the only one variation.
flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(2),
true);
- flags_state_->RegisterAllFeatureVariationParameters(&flags_storage_);
+ flags_state_->RegisterAllFeatureVariationParameters(&flags_storage_,
+ feature_list.get());
// Associating for the second time should not change the value.
- EXPECT_EQ(kTestParamValue1,
+ EXPECT_EQ("",
+ variations::GetVariationParamValue(kTestTrial, kTestParam));
+}
+
+TEST_F(FlagsStateTest, RegisterAllFeatureVariationParametersNonDefault) {
+ const FeatureEntry& entry = kEntries[7];
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+
+ // Select the only one variation.
+ flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(2),
+ true);
+ flags_state_->RegisterAllFeatureVariationParameters(&flags_storage_,
+ feature_list.get());
+
+ // Set the feature_list as the main instance so that
+ // variations::GetVariationParamValueByFeature below works.
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatureList(std::move(feature_list));
+
+ // The param should have the value predefined in this variation.
+ EXPECT_EQ(kTestParamValue,
variations::GetVariationParamValue(kTestTrial, kTestParam));
+
+ // The value should be associated also via the name of the feature.
+ EXPECT_EQ(kTestParamValue, variations::GetVariationParamValueByFeature(
+ kTestFeature2, kTestParam));
}
base::CommandLine::StringType CreateSwitch(const std::string& value) {
@@ -380,10 +409,10 @@ TEST_F(FlagsStateTest, RemoveFlagSwitches) {
// This shouldn't do anything before ConvertFlagsToSwitches() wasn't called.
flags_state_->RemoveFlagsSwitches(&switch_list);
ASSERT_EQ(4u, switch_list.size());
- EXPECT_TRUE(ContainsKey(switch_list, kSwitch1));
- EXPECT_TRUE(ContainsKey(switch_list, switches::kFlagSwitchesBegin));
- EXPECT_TRUE(ContainsKey(switch_list, switches::kFlagSwitchesEnd));
- EXPECT_TRUE(ContainsKey(switch_list, "foo"));
+ EXPECT_TRUE(base::ContainsKey(switch_list, kSwitch1));
+ EXPECT_TRUE(base::ContainsKey(switch_list, switches::kFlagSwitchesBegin));
+ EXPECT_TRUE(base::ContainsKey(switch_list, switches::kFlagSwitchesEnd));
+ EXPECT_TRUE(base::ContainsKey(switch_list, "foo"));
// Call ConvertFlagsToSwitches(), then RemoveFlagsSwitches() again.
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
@@ -395,7 +424,7 @@ TEST_F(FlagsStateTest, RemoveFlagSwitches) {
// Now the about:flags-related switch should have been removed.
ASSERT_EQ(1u, switch_list.size());
- EXPECT_TRUE(ContainsKey(switch_list, "foo"));
+ EXPECT_TRUE(base::ContainsKey(switch_list, "foo"));
}
TEST_F(FlagsStateTest, RemoveFlagSwitches_Features) {
@@ -446,13 +475,13 @@ TEST_F(FlagsStateTest, RemoveFlagSwitches_Features) {
kDisableFeatures);
auto switch_list = command_line.GetSwitches();
EXPECT_EQ(cases[i].expected_enable_features != nullptr,
- ContainsKey(switch_list, kEnableFeatures));
+ base::ContainsKey(switch_list, kEnableFeatures));
if (cases[i].expected_enable_features)
EXPECT_EQ(CreateSwitch(cases[i].expected_enable_features),
switch_list[kEnableFeatures]);
EXPECT_EQ(cases[i].expected_disable_features != nullptr,
- ContainsKey(switch_list, kDisableFeatures));
+ base::ContainsKey(switch_list, kDisableFeatures));
if (cases[i].expected_disable_features)
EXPECT_EQ(CreateSwitch(cases[i].expected_disable_features),
switch_list[kDisableFeatures]);
@@ -462,12 +491,12 @@ TEST_F(FlagsStateTest, RemoveFlagSwitches_Features) {
switch_list = command_line.GetSwitches();
flags_state_->RemoveFlagsSwitches(&switch_list);
EXPECT_EQ(cases[i].existing_enable_features != nullptr,
- ContainsKey(switch_list, kEnableFeatures));
+ base::ContainsKey(switch_list, kEnableFeatures));
if (cases[i].existing_enable_features)
EXPECT_EQ(CreateSwitch(cases[i].existing_enable_features),
switch_list[kEnableFeatures]);
EXPECT_EQ(cases[i].existing_disable_features != nullptr,
- ContainsKey(switch_list, kEnableFeatures));
+ base::ContainsKey(switch_list, kEnableFeatures));
if (cases[i].existing_disable_features)
EXPECT_EQ(CreateSwitch(cases[i].existing_disable_features),
switch_list[kDisableFeatures]);
diff --git a/chromium/components/flags_ui/resources/flags.css b/chromium/components/flags_ui/resources/flags.css
index 4d1a61c6ebf..d73b13ca457 100644
--- a/chromium/components/flags_ui/resources/flags.css
+++ b/chromium/components/flags_ui/resources/flags.css
@@ -84,6 +84,10 @@ div.content:last-of-type {
line-height: 200%;
}
+select {
+ max-width: 85vw;
+}
+
#experiment-reset-all {
float: right;
}
diff --git a/chromium/components/font_service/BUILD.gn b/chromium/components/font_service/BUILD.gn
index c83667554b9..73a5c84500d 100644
--- a/chromium/components/font_service/BUILD.gn
+++ b/chromium/components/font_service/BUILD.gn
@@ -2,8 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//mojo/public/mojo_application.gni")
-import("//mojo/public/mojo_application_manifest.gni")
+import("//services/shell/public/cpp/service.gni")
+import("//services/shell/public/service_manifest.gni")
source_set("lib") {
sources = [
@@ -26,7 +26,7 @@ source_set("lib") {
]
}
-mojo_native_application("font_service") {
+service("font_service") {
sources = [
"main.cc",
]
@@ -43,7 +43,7 @@ mojo_native_application("font_service") {
]
}
-mojo_application_manifest("manifest") {
- application_name = "font_service"
+service_manifest("manifest") {
+ name = "font_service"
source = "manifest.json"
}
diff --git a/chromium/components/font_service/font_service_app.cc b/chromium/components/font_service/font_service_app.cc
index b0d85a295e4..888709fb6d2 100644
--- a/chromium/components/font_service/font_service_app.cc
+++ b/chromium/components/font_service/font_service_app.cc
@@ -48,19 +48,18 @@ FontServiceApp::FontServiceApp() {}
FontServiceApp::~FontServiceApp() {}
-void FontServiceApp::Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) {
- tracing_.Initialize(connector, identity.name());
+void FontServiceApp::OnStart(const shell::Identity& identity) {
+ tracing_.Initialize(connector(), identity.name());
}
-bool FontServiceApp::AcceptConnection(shell::Connection* connection) {
- connection->AddInterface(this);
+bool FontServiceApp::OnConnect(const shell::Identity& remote_identity,
+ shell::InterfaceRegistry* registry) {
+ registry->AddInterface(this);
return true;
}
void FontServiceApp::Create(
- shell::Connection* connection,
+ const shell::Identity& remote_identity,
mojo::InterfaceRequest<mojom::FontService> request) {
bindings_.AddBinding(this, std::move(request));
}
diff --git a/chromium/components/font_service/font_service_app.h b/chromium/components/font_service/font_service_app.h
index e3579bc4b68..18d1f3c5a56 100644
--- a/chromium/components/font_service/font_service_app.h
+++ b/chromium/components/font_service/font_service_app.h
@@ -12,13 +12,13 @@
#include "components/font_service/public/interfaces/font_service.mojom.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/shell/public/cpp/interface_factory.h"
-#include "services/shell/public/cpp/shell_client.h"
-#include "services/tracing/public/cpp/tracing_impl.h"
+#include "services/shell/public/cpp/service.h"
+#include "services/tracing/public/cpp/provider.h"
#include "skia/ext/skia_utils_base.h"
namespace font_service {
-class FontServiceApp : public shell::ShellClient,
+class FontServiceApp : public shell::Service,
public shell::InterfaceFactory<mojom::FontService>,
public mojom::FontService {
public:
@@ -26,14 +26,13 @@ class FontServiceApp : public shell::ShellClient,
~FontServiceApp() override;
private:
- // shell::ShellClient:
- void Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) override;
- bool AcceptConnection(shell::Connection* connection) override;
+ // shell::Service:
+ void OnStart(const shell::Identity& identity) override;
+ bool OnConnect(const shell::Identity& remote_identity,
+ shell::InterfaceRegistry* registry) override;
// shell::InterfaceFactory<mojom::FontService>:
- void Create(shell::Connection* connection,
+ void Create(const shell::Identity& remote_identity,
mojo::InterfaceRequest<mojom::FontService> request) override;
// FontService:
@@ -47,7 +46,7 @@ class FontServiceApp : public shell::ShellClient,
mojo::BindingSet<mojom::FontService> bindings_;
- mojo::TracingImpl tracing_;
+ tracing::Provider tracing_;
// We don't want to leak paths to our callers; we thus enumerate the paths of
// fonts.
diff --git a/chromium/components/font_service/main.cc b/chromium/components/font_service/main.cc
index 698358cdd8c..ee9e55b99a1 100644
--- a/chromium/components/font_service/main.cc
+++ b/chromium/components/font_service/main.cc
@@ -3,10 +3,10 @@
// found in the LICENSE file.
#include "components/font_service/font_service_app.h"
-#include "mojo/public/c/system/main.h"
-#include "services/shell/public/cpp/application_runner.h"
+#include "services/shell/public/c/main.h"
+#include "services/shell/public/cpp/service_runner.h"
-MojoResult MojoMain(MojoHandle shell_handle) {
- shell::ApplicationRunner runner(new font_service::FontServiceApp);
- return runner.Run(shell_handle);
+MojoResult ServiceMain(MojoHandle service_request_handle) {
+ shell::ServiceRunner runner(new font_service::FontServiceApp);
+ return runner.Run(service_request_handle);
}
diff --git a/chromium/components/font_service/manifest.json b/chromium/components/font_service/manifest.json
index 665c6a37a04..d9588bbeb5f 100644
--- a/chromium/components/font_service/manifest.json
+++ b/chromium/components/font_service/manifest.json
@@ -1,6 +1,6 @@
{
"manifest_version": 1,
- "name": "mojo:font_service",
+ "name": "service:font_service",
"display_name": "Font Service",
"capabilities": {
"provided": {
diff --git a/chromium/components/font_service/public/cpp/font_loader.cc b/chromium/components/font_service/public/cpp/font_loader.cc
index f83846f8b8c..e6e329837cd 100644
--- a/chromium/components/font_service/public/cpp/font_loader.cc
+++ b/chromium/components/font_service/public/cpp/font_loader.cc
@@ -15,7 +15,7 @@ namespace font_service {
FontLoader::FontLoader(shell::Connector* connector) {
mojom::FontServicePtr font_service;
- connector->ConnectToInterface("mojo:font_service", &font_service);
+ connector->ConnectToInterface("service:font_service", &font_service);
thread_ = new internal::FontServiceThread(std::move(font_service));
}
diff --git a/chromium/components/font_service/public/cpp/font_service_thread.cc b/chromium/components/font_service/public/cpp/font_service_thread.cc
index 5d9645acea1..81f8394eb81 100644
--- a/chromium/components/font_service/public/cpp/font_service_thread.cc
+++ b/chromium/components/font_service/public/cpp/font_service_thread.cc
@@ -124,7 +124,7 @@ void FontServiceThread::OnMatchFamilyNameComplete(
DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId());
pending_waitable_events_.erase(done_event);
- *out_valid = font_identity;
+ *out_valid = !font_identity.is_null();
if (font_identity) {
out_font_identity->fID = font_identity->id;
out_font_identity->fTTCIndex = font_identity->ttc_index;
diff --git a/chromium/components/font_service/public/interfaces/BUILD.gn b/chromium/components/font_service/public/interfaces/BUILD.gn
index e60d556129c..5857112a1b0 100644
--- a/chromium/components/font_service/public/interfaces/BUILD.gn
+++ b/chromium/components/font_service/public/interfaces/BUILD.gn
@@ -8,4 +8,6 @@ mojom("interfaces") {
sources = [
"font_service.mojom",
]
+
+ use_new_wrapper_types = false
}
diff --git a/chromium/components/gcm_driver.gypi b/chromium/components/gcm_driver.gypi
deleted file mode 100644
index 5a0b31e1831..00000000000
--- a/chromium/components/gcm_driver.gypi
+++ /dev/null
@@ -1,372 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/gcm_driver/common
- 'target_name': 'gcm_driver_common',
- 'type': '<(component)',
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'GCM_DRIVER_IMPLEMENTATION',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'gcm_driver/common/gcm_driver_export.h',
- 'gcm_driver/common/gcm_messages.cc',
- 'gcm_driver/common/gcm_messages.h',
- ],
- },
- {
- # GN version: //components/gcm_driver
- 'target_name': 'gcm_driver',
- 'type': 'static_library',
- 'dependencies': [
- 'gcm_driver_common',
- 'gcm_driver_crypto',
- 'os_crypt',
- 'sync_driver',
- '../base/base.gyp:base',
- '../google_apis/gcm/gcm.gyp:gcm',
- '../net/net.gyp:net',
- '../sync/sync.gyp:sync_proto',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'gcm_driver/android/component_jni_registrar.cc',
- 'gcm_driver/android/component_jni_registrar.h',
- 'gcm_driver/default_gcm_app_handler.cc',
- 'gcm_driver/default_gcm_app_handler.h',
- 'gcm_driver/gcm_account_mapper.cc',
- 'gcm_driver/gcm_account_mapper.h',
- 'gcm_driver/gcm_account_tracker.cc',
- 'gcm_driver/gcm_account_tracker.h',
- 'gcm_driver/gcm_activity.cc',
- 'gcm_driver/gcm_activity.h',
- 'gcm_driver/gcm_app_handler.cc',
- 'gcm_driver/gcm_app_handler.h',
- 'gcm_driver/gcm_backoff_policy.cc',
- 'gcm_driver/gcm_backoff_policy.h',
- 'gcm_driver/gcm_channel_status_request.cc',
- 'gcm_driver/gcm_channel_status_request.h',
- 'gcm_driver/gcm_channel_status_syncer.cc',
- 'gcm_driver/gcm_channel_status_syncer.h',
- 'gcm_driver/gcm_client.cc',
- 'gcm_driver/gcm_client.h',
- 'gcm_driver/gcm_client_factory.cc',
- 'gcm_driver/gcm_client_factory.h',
- 'gcm_driver/gcm_client_impl.cc',
- 'gcm_driver/gcm_client_impl.h',
- 'gcm_driver/gcm_connection_observer.cc',
- 'gcm_driver/gcm_connection_observer.h',
- 'gcm_driver/gcm_delayed_task_controller.cc',
- 'gcm_driver/gcm_delayed_task_controller.h',
- 'gcm_driver/gcm_desktop_utils.cc',
- 'gcm_driver/gcm_desktop_utils.h',
- 'gcm_driver/gcm_driver.cc',
- 'gcm_driver/gcm_driver.h',
- 'gcm_driver/gcm_driver_android.cc',
- 'gcm_driver/gcm_driver_android.h',
- 'gcm_driver/gcm_driver_constants.cc',
- 'gcm_driver/gcm_driver_constants.h',
- 'gcm_driver/gcm_driver_desktop.cc',
- 'gcm_driver/gcm_driver_desktop.h',
- 'gcm_driver/gcm_internals_constants.cc',
- 'gcm_driver/gcm_internals_constants.h',
- 'gcm_driver/gcm_internals_helper.cc',
- 'gcm_driver/gcm_internals_helper.h',
- 'gcm_driver/gcm_profile_service.cc',
- 'gcm_driver/gcm_profile_service.h',
- 'gcm_driver/gcm_stats_recorder_android.cc',
- 'gcm_driver/gcm_stats_recorder_android.h',
- 'gcm_driver/gcm_stats_recorder_impl.cc',
- 'gcm_driver/gcm_stats_recorder_impl.h',
- 'gcm_driver/registration_info.cc',
- 'gcm_driver/registration_info.h',
- 'gcm_driver/system_encryptor.cc',
- 'gcm_driver/system_encryptor.h',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'dependencies': [
- 'gcm_driver_jni_headers',
- ],
- 'dependencies!': [
- '../google_apis/gcm/gcm.gyp:gcm',
- ],
- 'sources!': [
- 'gcm_driver/gcm_account_mapper.cc',
- 'gcm_driver/gcm_account_mapper.h',
- 'gcm_driver/gcm_channel_status_request.cc',
- 'gcm_driver/gcm_channel_status_request.h',
- 'gcm_driver/gcm_channel_status_syncer.cc',
- 'gcm_driver/gcm_channel_status_syncer.h',
- 'gcm_driver/gcm_client_factory.cc',
- 'gcm_driver/gcm_client_factory.h',
- 'gcm_driver/gcm_client_impl.cc',
- 'gcm_driver/gcm_client_impl.h',
- 'gcm_driver/gcm_desktop_utils.cc',
- 'gcm_driver/gcm_desktop_utils.h',
- 'gcm_driver/gcm_driver_desktop.cc',
- 'gcm_driver/gcm_driver_desktop.h',
- 'gcm_driver/gcm_stats_recorder_impl.cc',
- 'gcm_driver/gcm_stats_recorder_impl.h',
- ],
- }],
- ['chromeos == 1', {
- 'dependencies': [
- 'timers',
- ],
- }],
- ],
- },
- {
- # GN version: //components/gcm_driver:test_support
- 'target_name': 'gcm_driver_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'gcm_driver',
- '../base/base.gyp:base',
- '../google_apis/gcm/gcm.gyp:gcm_test_support',
- '../testing/gtest.gyp:gtest',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'gcm_driver/fake_gcm_app_handler.cc',
- 'gcm_driver/fake_gcm_app_handler.h',
- 'gcm_driver/fake_gcm_client.cc',
- 'gcm_driver/fake_gcm_client.h',
- 'gcm_driver/fake_gcm_client_factory.cc',
- 'gcm_driver/fake_gcm_client_factory.h',
- 'gcm_driver/fake_gcm_driver.cc',
- 'gcm_driver/fake_gcm_driver.h',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'dependencies!': [
- '../google_apis/gcm/gcm.gyp:gcm_test_support',
- ],
- 'sources!': [
- 'gcm_driver/fake_gcm_client.cc',
- 'gcm_driver/fake_gcm_client.h',
- 'gcm_driver/fake_gcm_client_factory.cc',
- 'gcm_driver/fake_gcm_client_factory.h',
- ],
- }],
- ],
- },
- {
- # GN version: //components/gcm_driver/instance_id
- 'target_name': 'instance_id',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'gcm_driver/instance_id/android/component_jni_registrar.cc',
- 'gcm_driver/instance_id/android/component_jni_registrar.h',
- 'gcm_driver/instance_id/instance_id.cc',
- 'gcm_driver/instance_id/instance_id.h',
- 'gcm_driver/instance_id/instance_id_android.cc',
- 'gcm_driver/instance_id/instance_id_android.h',
- 'gcm_driver/instance_id/instance_id_driver.cc',
- 'gcm_driver/instance_id/instance_id_driver.h',
- 'gcm_driver/instance_id/instance_id_impl.cc',
- 'gcm_driver/instance_id/instance_id_impl.h',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'dependencies': [
- 'instance_id_driver_jni_headers',
- ],
- 'sources!': [
- 'gcm_driver/instance_id/instance_id_impl.cc',
- 'gcm_driver/instance_id/instance_id_impl.h',
- ],
- }],
- ],
- },
- {
- # GN version: //components/gcm_driver/instance_id:test_support
- 'target_name': 'instance_id_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'gcm_driver_test_support',
- 'instance_id',
- '../testing/gtest.gyp:gtest',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc',
- 'gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h',
- 'gcm_driver/instance_id/scoped_use_fake_instance_id_android.cc',
- 'gcm_driver/instance_id/scoped_use_fake_instance_id_android.h',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'dependencies': [
- 'instance_id_driver_test_support_jni_headers',
- ],
- }],
- ],
- },
- {
- # GN version: //components/gcm_driver/crypto
- 'target_name': 'gcm_driver_crypto',
- 'type': 'static_library',
- 'dependencies': [
- 'gcm_driver_crypto_proto',
- '../base/base.gyp:base',
- '../components/components.gyp:leveldb_proto',
- '../crypto/crypto.gyp:crypto',
- '../net/net.gyp:net',
- '../third_party/boringssl/boringssl.gyp:boringssl',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'gcm_driver/crypto/encryption_header_parsers.cc',
- 'gcm_driver/crypto/encryption_header_parsers.h',
- 'gcm_driver/crypto/gcm_encryption_provider.cc',
- 'gcm_driver/crypto/gcm_encryption_provider.h',
- 'gcm_driver/crypto/gcm_key_store.cc',
- 'gcm_driver/crypto/gcm_key_store.h',
- 'gcm_driver/crypto/gcm_message_cryptographer.cc',
- 'gcm_driver/crypto/gcm_message_cryptographer.h',
- 'gcm_driver/crypto/p256_key_util.cc',
- 'gcm_driver/crypto/p256_key_util.h',
- ],
- },
- {
- # GN version: //components/gcm_driver/crypto/proto
- 'target_name': 'gcm_driver_crypto_proto',
- 'type': 'static_library',
- 'sources': [
- 'gcm_driver/crypto/proto/gcm_encryption_data.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'gcm_driver/crypto/proto',
- 'proto_out_dir': 'components/gcm_driver/crypto/proto',
- },
- 'includes': [ '../build/protoc.gypi' ],
- },
- {
- # GN version: //components/gcm_driver/crypto:test_support
- 'target_name': 'gcm_driver_crypto_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'gcm_driver_common',
- 'gcm_driver_crypto',
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'gcm_driver/crypto/gcm_crypto_test_helpers.cc',
- 'gcm_driver/crypto/gcm_crypto_test_helpers.h',
- ],
- },
- ],
- 'conditions': [
- ['OS == "android"', {
- 'targets': [
- {
- # GN version: //components/gcm_driver/android:gcm_driver_java
- 'target_name': 'gcm_driver_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base_java',
- '../content/content.gyp:content_java',
- '../sync/sync.gyp:sync_java',
- ],
- 'variables': {
- 'java_in_dir': 'gcm_driver/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN version: //components/gcm_driver/android:jni_headers
- 'target_name': 'gcm_driver_jni_headers',
- 'type': 'none',
- 'sources': [
- 'gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMDriver.java',
- ],
- 'variables': {
- 'jni_gen_package': 'components/gcm_driver',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- # GN version: //components/gcm_driver/instance_id/android:instance_id_driver_java
- 'target_name': 'instance_id_driver_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base_java',
- '../third_party/android_tools/android_tools.gyp:google_play_services_javalib',
- ],
- 'variables': {
- 'java_in_dir': 'gcm_driver/instance_id/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN version: //components/gcm_driver/instance_id/android:instance_id_driver_test_support_java
- 'target_name': 'instance_id_driver_test_support_java',
- 'type': 'none',
- 'dependencies': [
- 'instance_id_driver_java',
- ],
- 'variables': {
- 'java_in_dir': 'gcm_driver/instance_id/android/javatests',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN version: //components/gcm_driver/instance_id/android:jni_headers
- 'target_name': 'instance_id_driver_jni_headers',
- 'type': 'none',
- 'sources': [
- 'gcm_driver/instance_id/android/java/src/org/chromium/components/gcm_driver/instance_id/InstanceIDBridge.java',
- ],
- 'variables': {
- 'jni_gen_package': 'components/gcm_driver/instance_id',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- # GN version: //components/gcm_driver/instance_id/android:test_support_jni_headers
- 'target_name': 'instance_id_driver_test_support_jni_headers',
- 'type': 'none',
- 'sources': [
- 'gcm_driver/instance_id/android/javatests/src/org/chromium/components/gcm_driver/instance_id/FakeInstanceIDWithSubtype.java',
- ],
- 'variables': {
- 'jni_gen_package': 'components/gcm_driver/instance_id',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- ],
- },
- ],
- ],
-}
diff --git a/chromium/components/gcm_driver/BUILD.gn b/chromium/components/gcm_driver/BUILD.gn
index 918029d3042..4d05582cc4c 100644
--- a/chromium/components/gcm_driver/BUILD.gn
+++ b/chromium/components/gcm_driver/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/gcm_driver.gypi:gcm_driver
static_library("gcm_driver") {
sources = [
"android/component_jni_registrar.cc",
@@ -59,24 +58,33 @@ static_library("gcm_driver") {
"system_encryptor.h",
]
- deps = [
+ public_deps = [
"//base",
"//components/gcm_driver/common",
"//components/gcm_driver/crypto",
+ "//components/gcm_driver/instance_id",
+ ]
+ deps = [
+ "//components/crx_file",
"//components/keyed_service/core",
"//components/os_crypt",
"//components/pref_registry",
"//components/prefs",
"//components/signin/core/browser",
- "//components/sync_driver",
+ "//components/sync",
"//components/version_info",
"//google_apis",
"//google_apis/gcm",
"//net",
- "//sync/protocol",
"//url:url",
]
- allow_circular_includes_from = [ "//components/gcm_driver/crypto" ]
+
+ # This target goes with these other deps and they can include headers from
+ # each other.
+ allow_circular_includes_from = [
+ "//components/gcm_driver/crypto",
+ "//components/gcm_driver/instance_id",
+ ]
if (is_chromeos) {
deps += [ "//components/timers" ]
@@ -101,13 +109,15 @@ static_library("gcm_driver") {
"gcm_stats_recorder_impl.cc",
"gcm_stats_recorder_impl.h",
]
- deps -= [ "//google_apis/gcm" ]
+ deps -= [
+ "//components/crx_file",
+ "//google_apis/gcm",
+ ]
deps += [ "android:jni_headers" ]
}
}
-# GYP version: components/gcm_driver.gypi:gcm_driver_test_support
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"fake_gcm_app_handler.cc",
@@ -162,10 +172,10 @@ source_set("unit_tests") {
"//base/test:test_support",
"//components/gcm_driver/crypto",
"//components/prefs:test_support",
+ "//components/sync/protocol",
"//google_apis:test_support",
"//google_apis/gcm:test_support",
"//net:test_support",
- "//sync/protocol",
"//testing/gtest",
"//third_party/protobuf:protobuf_lite",
]
diff --git a/chromium/components/gcm_driver/android/BUILD.gn b/chromium/components/gcm_driver/android/BUILD.gn
index 3f674c61718..c1f63740628 100644
--- a/chromium/components/gcm_driver/android/BUILD.gn
+++ b/chromium/components/gcm_driver/android/BUILD.gn
@@ -4,7 +4,6 @@
import("//build/config/android/rules.gni")
-# GYP version: components/gcm_driver.gypi:gcm_driver_jni_headers
generate_jni("jni_headers") {
sources = [
"java/src/org/chromium/components/gcm_driver/GCMDriver.java",
@@ -12,7 +11,6 @@ generate_jni("jni_headers") {
jni_package = "components/gcm_driver"
}
-# GYP version: components/gcm_driver.gypi:gcm_driver_java
android_library("gcm_driver_java") {
deps = [
"//base:base_java",
@@ -22,7 +20,6 @@ android_library("gcm_driver_java") {
]
java_files = [
- "java/src/org/chromium/components/gcm_driver/FakeGoogleCloudMessagingSubscriber.java",
"java/src/org/chromium/components/gcm_driver/GCMDriver.java",
"java/src/org/chromium/components/gcm_driver/GoogleCloudMessagingSubscriber.java",
"java/src/org/chromium/components/gcm_driver/GoogleCloudMessagingV2.java",
diff --git a/chromium/components/gcm_driver/common/BUILD.gn b/chromium/components/gcm_driver/common/BUILD.gn
index b9dc6e6f253..4658d2e816a 100644
--- a/chromium/components/gcm_driver/common/BUILD.gn
+++ b/chromium/components/gcm_driver/common/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/gcm_driver.gypi:gcm_driver_common
component("common") {
sources = [
"gcm_driver_export.h",
diff --git a/chromium/components/gcm_driver/crypto/BUILD.gn b/chromium/components/gcm_driver/crypto/BUILD.gn
index 3752eb9b100..62aa7179312 100644
--- a/chromium/components/gcm_driver/crypto/BUILD.gn
+++ b/chromium/components/gcm_driver/crypto/BUILD.gn
@@ -4,8 +4,7 @@
import("//build/config/crypto.gni")
-# GYP version: components/gcm_driver.gypi:gcm_driver_crypto
-source_set("crypto") {
+static_library("crypto") {
sources = [
"encryption_header_parsers.cc",
"encryption_header_parsers.h",
@@ -31,8 +30,7 @@ source_set("crypto") {
]
}
-# GYP version: components/gcm_driver.gypi:gcm_driver_crypto_test_support
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"gcm_crypto_test_helpers.cc",
diff --git a/chromium/components/gcm_driver/crypto/proto/BUILD.gn b/chromium/components/gcm_driver/crypto/proto/BUILD.gn
index 852cebf8bc0..b6d951c9afe 100644
--- a/chromium/components/gcm_driver/crypto/proto/BUILD.gn
+++ b/chromium/components/gcm_driver/crypto/proto/BUILD.gn
@@ -4,7 +4,6 @@
import("//third_party/protobuf/proto_library.gni")
-# GYP version: components/gcm_driver.gypi:gcm_driver_crypto_proto
proto_library("proto") {
visibility = [ "//components/gcm_driver/crypto" ]
diff --git a/chromium/components/gcm_driver/instance_id/BUILD.gn b/chromium/components/gcm_driver/instance_id/BUILD.gn
index 7e893ffe6b4..b77c0344be4 100644
--- a/chromium/components/gcm_driver/instance_id/BUILD.gn
+++ b/chromium/components/gcm_driver/instance_id/BUILD.gn
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/gcm_driver.gypi:instance_id_driver
-source_set("instance_id") {
+static_library("instance_id") {
sources = [
"android/component_jni_registrar.cc",
"android/component_jni_registrar.h",
@@ -17,10 +16,8 @@ source_set("instance_id") {
deps = [
"//base",
- "//components/gcm_driver",
"//crypto",
]
- allow_circular_includes_from = [ "//components/gcm_driver" ]
if (is_android) {
sources -= [
@@ -35,8 +32,7 @@ source_set("instance_id") {
}
}
-# GYP version: components/gcm_driver.gypi:instance_id_test_support
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"fake_gcm_driver_for_instance_id.cc",
@@ -70,6 +66,7 @@ source_set("unit_tests") {
":test_support",
"//base",
"//google_apis/gcm",
+ "//net:test_support",
"//testing/gtest",
]
}
diff --git a/chromium/components/gcm_driver/instance_id/android/BUILD.gn b/chromium/components/gcm_driver/instance_id/android/BUILD.gn
index 9d980403b92..54e49e44ac0 100644
--- a/chromium/components/gcm_driver/instance_id/android/BUILD.gn
+++ b/chromium/components/gcm_driver/instance_id/android/BUILD.gn
@@ -4,7 +4,6 @@
import("//build/config/android/rules.gni")
-# GYP version: components/gcm_driver.gypi:instance_id_driver_jni_headers
generate_jni("jni_headers") {
sources = [
"java/src/org/chromium/components/gcm_driver/instance_id/InstanceIDBridge.java",
@@ -12,7 +11,6 @@ generate_jni("jni_headers") {
jni_package = "components/gcm_driver/instance_id"
}
-# GYP version: components/gcm_driver.gypi:instance_id_driver_test_support_jni_headers
generate_jni("test_support_jni_headers") {
sources = [
"javatests/src/org/chromium/components/gcm_driver/instance_id/FakeInstanceIDWithSubtype.java",
@@ -20,7 +18,6 @@ generate_jni("test_support_jni_headers") {
jni_package = "components/gcm_driver/instance_id"
}
-# GYP version: components/gcm_driver.gypi:instance_id_driver_java
android_library("instance_id_driver_java") {
deps = [
"//base:base_java",
@@ -33,7 +30,6 @@ android_library("instance_id_driver_java") {
]
}
-# GYP version: components/gcm_driver.gypi:instance_id_driver_test_support_java
android_library("instance_id_driver_test_support_java") {
deps = [
":instance_id_driver_java",
diff --git a/chromium/components/google.gypi b/chromium/components/google.gypi
deleted file mode 100644
index 5bc0a7429a5..00000000000
--- a/chromium/components/google.gypi
+++ /dev/null
@@ -1,39 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/google/core/browser
- 'target_name': 'google_core_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- 'components_strings.gyp:components_strings',
- 'data_use_measurement_core',
- 'keyed_service_core',
- 'pref_registry',
- 'url_formatter/url_formatter.gyp:url_formatter',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources duplicated in GN build.
- 'google/core/browser/google_pref_names.cc',
- 'google/core/browser/google_pref_names.h',
- 'google/core/browser/google_switches.cc',
- 'google/core/browser/google_switches.h',
- 'google/core/browser/google_url_tracker.cc',
- 'google/core/browser/google_url_tracker.h',
- 'google/core/browser/google_url_tracker_client.cc',
- 'google/core/browser/google_url_tracker_client.h',
- 'google/core/browser/google_util.cc',
- 'google/core/browser/google_util.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/guest_view.gypi b/chromium/components/guest_view.gypi
deleted file mode 100644
index 39e13caa8cc..00000000000
--- a/chromium/components/guest_view.gypi
+++ /dev/null
@@ -1,99 +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.
-{
- 'conditions': [
- ['OS != "ios"', {
- 'targets': [
- {
- 'target_name': 'guest_view_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- 'guest_view_common'
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'guest_view/browser/guest_view.h',
- 'guest_view/browser/guest_view_base.cc',
- 'guest_view/browser/guest_view_base.h',
- 'guest_view/browser/guest_view_event.cc',
- 'guest_view/browser/guest_view_event.h',
- 'guest_view/browser/guest_view_manager.cc',
- 'guest_view/browser/guest_view_manager.h',
- 'guest_view/browser/guest_view_manager_delegate.cc',
- 'guest_view/browser/guest_view_manager_delegate.h',
- 'guest_view/browser/guest_view_manager_factory.h',
- 'guest_view/browser/guest_view_message_filter.cc',
- 'guest_view/browser/guest_view_message_filter.h',
- ],
- },
- {
- 'target_name': 'guest_view_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../ipc/ipc.gyp:ipc',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'guest_view/common/guest_view_constants.cc',
- 'guest_view/common/guest_view_constants.h',
- 'guest_view/common/guest_view_message_generator.cc',
- 'guest_view/common/guest_view_message_generator.h',
- 'guest_view/common/guest_view_messages.h',
- ]
- },
- {
- 'target_name': 'guest_view_renderer',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../content/content.gyp:content_renderer',
- '../third_party/WebKit/public/blink.gyp:blink',
- '../v8/src/v8.gyp:v8',
- 'guest_view_common'
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'guest_view/renderer/guest_view_container_dispatcher.cc',
- 'guest_view/renderer/guest_view_container_dispatcher.h',
- 'guest_view/renderer/guest_view_container.cc',
- 'guest_view/renderer/guest_view_container.h',
- 'guest_view/renderer/guest_view_request.cc',
- 'guest_view/renderer/guest_view_request.h',
- 'guest_view/renderer/iframe_guest_view_container.cc',
- 'guest_view/renderer/iframe_guest_view_container.h',
- 'guest_view/renderer/iframe_guest_view_request.cc',
- 'guest_view/renderer/iframe_guest_view_request.h',
- ],
- },
- {
- 'target_name': 'guest_view_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content_shell_and_tests.gyp:test_support_content',
- 'guest_view_browser',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'guest_view/browser/test_guest_view_manager.h',
- 'guest_view/browser/test_guest_view_manager.cc',
- ],
- }
- ],
- }]
- ]
-}
diff --git a/chromium/components/guest_view/browser/BUILD.gn b/chromium/components/guest_view/browser/BUILD.gn
index e6d27b7b762..a0668fc7782 100644
--- a/chromium/components/guest_view/browser/BUILD.gn
+++ b/chromium/components/guest_view/browser/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser") {
+static_library("browser") {
output_name = "guest_view_browser"
sources = [
"//components/guest_view/browser/guest_view.h",
@@ -19,9 +19,11 @@ source_set("browser") {
"//components/guest_view/browser/guest_view_message_filter.h",
]
- deps = [
+ public_deps = [
"//base",
"//components/guest_view/common",
+ ]
+ deps = [
"//components/zoom",
"//content/public/browser",
"//content/public/common",
@@ -30,7 +32,7 @@ source_set("browser") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"//components/guest_view/browser/test_guest_view_manager.cc",
diff --git a/chromium/components/guest_view/browser/guest_view.h b/chromium/components/guest_view/browser/guest_view.h
index 3bc16ce05db..70c9fb18037 100644
--- a/chromium/components/guest_view/browser/guest_view.h
+++ b/chromium/components/guest_view/browser/guest_view.h
@@ -19,24 +19,24 @@ template <typename T>
class GuestView : public GuestViewBase {
public:
static T* From(int embedder_process_id, int guest_instance_id) {
- auto guest = GuestViewBase::From(embedder_process_id, guest_instance_id);
+ auto* guest = GuestViewBase::From(embedder_process_id, guest_instance_id);
if (!guest)
return nullptr;
return guest->As<T>();
}
static T* FromWebContents(const content::WebContents* contents) {
- auto guest = GuestViewBase::FromWebContents(contents);
+ auto* guest = GuestViewBase::FromWebContents(contents);
return guest ? guest->As<T>() : nullptr;
}
static T* FromFrameID(int render_process_id, int render_frame_id) {
- auto render_frame_host =
+ auto* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
if (!render_frame_host)
return nullptr;
- auto web_contents =
+ auto* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
return FromWebContents(web_contents);
}
diff --git a/chromium/components/guest_view/browser/guest_view_base.cc b/chromium/components/guest_view/browser/guest_view_base.cc
index 45ce1855c5c..e2ffccee70d 100644
--- a/chromium/components/guest_view/browser/guest_view_base.cc
+++ b/chromium/components/guest_view/browser/guest_view_base.cc
@@ -22,7 +22,6 @@
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/browser_plugin_guest_mode.h"
#include "content/public/common/page_zoom.h"
#include "content/public/common/url_constants.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -240,7 +239,7 @@ void GuestViewBase::InitWithWebContents(
SetUpSizing(create_params);
// Observe guest zoom changes.
- auto zoom_controller = zoom::ZoomController::FromWebContents(web_contents());
+ auto* zoom_controller = zoom::ZoomController::FromWebContents(web_contents());
zoom_controller->AddObserver(this);
// Give the derived class an opportunity to perform additional initialization.
@@ -267,7 +266,7 @@ void GuestViewBase::DispatchOnResizeEvent(const gfx::Size& old_size,
args->SetInteger(kNewWidth, new_size.width());
args->SetInteger(kNewHeight, new_size.height());
DispatchEventToGuestProxy(
- base::WrapUnique(new GuestViewEvent(kEventResize, std::move(args))));
+ base::MakeUnique<GuestViewEvent>(kEventResize, std::move(args)));
}
gfx::Size GuestViewBase::GetDefaultSize() const {
@@ -353,7 +352,7 @@ GuestViewBase* GuestViewBase::FromWebContents(const WebContents* web_contents) {
// static
GuestViewBase* GuestViewBase::From(int owner_process_id,
int guest_instance_id) {
- auto host = content::RenderProcessHost::FromID(owner_process_id);
+ auto* host = content::RenderProcessHost::FromID(owner_process_id);
if (!host)
return nullptr;
@@ -394,7 +393,7 @@ void GuestViewBase::SetContextMenuPosition(const gfx::Point& position) {}
WebContents* GuestViewBase::CreateNewGuestWindow(
const WebContents::CreateParams& create_params) {
- auto guest_manager = GuestViewManager::FromBrowserContext(browser_context());
+ auto* guest_manager = GuestViewManager::FromBrowserContext(browser_context());
return guest_manager->CreateGuestWithWebContentsParams(
GetViewType(),
owner_web_contents(),
@@ -478,6 +477,8 @@ void GuestViewBase::Destroy() {
StopTrackingEmbedderZoomLevel();
owner_web_contents_ = nullptr;
+ element_instance_id_ = kInstanceIDNone;
+
DCHECK(web_contents());
// Give the derived class an opportunity to perform some cleanup.
@@ -729,7 +730,7 @@ void GuestViewBase::OnZoomChanged(
const zoom::ZoomController::ZoomChangedEventData& data) {
if (data.web_contents == embedder_web_contents()) {
// The embedder's zoom level has changed.
- auto guest_zoom_controller =
+ auto* guest_zoom_controller =
zoom::ZoomController::FromWebContents(web_contents());
if (content::ZoomValuesEqual(data.new_zoom_level,
guest_zoom_controller->GetZoomLevel())) {
@@ -846,7 +847,7 @@ void GuestViewBase::SetUpSizing(const base::DictionaryValue& params) {
}
void GuestViewBase::SetGuestZoomLevelToMatchEmbedder() {
- auto embedder_zoom_controller =
+ auto* embedder_zoom_controller =
zoom::ZoomController::FromWebContents(owner_web_contents());
if (!embedder_zoom_controller)
return;
@@ -859,7 +860,7 @@ void GuestViewBase::StartTrackingEmbedderZoomLevel() {
if (!ZoomPropagatesFromEmbedderToGuest())
return;
- auto embedder_zoom_controller =
+ auto* embedder_zoom_controller =
zoom::ZoomController::FromWebContents(owner_web_contents());
// Chrome Apps do not have a ZoomController.
if (!embedder_zoom_controller)
@@ -875,7 +876,7 @@ void GuestViewBase::StopTrackingEmbedderZoomLevel() {
if (!attached() || !ZoomPropagatesFromEmbedderToGuest())
return;
- auto embedder_zoom_controller =
+ auto* embedder_zoom_controller =
zoom::ZoomController::FromWebContents(owner_web_contents());
// Chrome Apps do not have a ZoomController.
if (!embedder_zoom_controller)
diff --git a/chromium/components/guest_view/browser/guest_view_manager.cc b/chromium/components/guest_view/browser/guest_view_manager.cc
index 7f0d6841b9a..1734c762657 100644
--- a/chromium/components/guest_view/browser/guest_view_manager.cc
+++ b/chromium/components/guest_view/browser/guest_view_manager.cc
@@ -113,7 +113,8 @@ void GuestViewManager::AttachGuest(int embedder_process_id,
int element_instance_id,
int guest_instance_id,
const base::DictionaryValue& attach_params) {
- auto guest_view = GuestViewBase::From(embedder_process_id, guest_instance_id);
+ auto* guest_view =
+ GuestViewBase::From(embedder_process_id, guest_instance_id);
if (!guest_view)
return;
@@ -126,8 +127,8 @@ void GuestViewManager::AttachGuest(int embedder_process_id,
if (old_guest_instance_id == guest_instance_id)
return;
- auto old_guest_view = GuestViewBase::From(embedder_process_id,
- old_guest_instance_id);
+ auto* old_guest_view =
+ GuestViewBase::From(embedder_process_id, old_guest_instance_id);
old_guest_view->Destroy();
}
instance_id_map_[key] = guest_instance_id;
@@ -176,12 +177,12 @@ content::WebContents* GuestViewManager::CreateGuestWithWebContentsParams(
const std::string& view_type,
content::WebContents* owner_web_contents,
const content::WebContents::CreateParams& create_params) {
- auto guest = CreateGuestInternal(owner_web_contents, view_type);
+ auto* guest = CreateGuestInternal(owner_web_contents, view_type);
if (!guest)
return nullptr;
content::WebContents::CreateParams guest_create_params(create_params);
guest_create_params.guest_delegate = guest;
- auto guest_web_contents = WebContents::Create(guest_create_params);
+ auto* guest_web_contents = WebContents::Create(guest_create_params);
guest->InitWithWebContents(base::DictionaryValue(), guest_web_contents);
return guest_web_contents;
}
@@ -218,7 +219,7 @@ SiteInstance* GuestViewManager::GetGuestSiteInstance(
bool GuestViewManager::ForEachGuest(WebContents* owner_web_contents,
const GuestCallback& callback) {
for (const auto& guest : guest_web_contents_by_instance_id_) {
- auto guest_view = GuestViewBase::FromWebContents(guest.second);
+ auto* guest_view = GuestViewBase::FromWebContents(guest.second);
if (guest_view->owner_web_contents() != owner_web_contents)
continue;
@@ -238,7 +239,8 @@ WebContents* GuestViewManager::GetFullPageGuest(
void GuestViewManager::AddGuest(int guest_instance_id,
WebContents* guest_web_contents) {
- CHECK(!ContainsKey(guest_web_contents_by_instance_id_, guest_instance_id));
+ CHECK(!base::ContainsKey(guest_web_contents_by_instance_id_,
+ guest_instance_id));
CHECK(CanUseGuestInstanceID(guest_instance_id));
guest_web_contents_by_instance_id_[guest_instance_id] = guest_web_contents;
@@ -421,14 +423,14 @@ bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill(
bool GuestViewManager::CanUseGuestInstanceID(int guest_instance_id) {
if (guest_instance_id <= last_instance_id_removed_)
return false;
- return !ContainsKey(removed_instance_ids_, guest_instance_id);
+ return !base::ContainsKey(removed_instance_ids_, guest_instance_id);
}
// static
bool GuestViewManager::GetFullPageGuestHelper(
content::WebContents** result,
content::WebContents* guest_web_contents) {
- auto guest_view = GuestViewBase::FromWebContents(guest_web_contents);
+ auto* guest_view = GuestViewBase::FromWebContents(guest_web_contents);
if (guest_view && guest_view->is_full_page_plugin()) {
*result = guest_web_contents;
return true;
@@ -457,7 +459,7 @@ bool GuestViewManager::CanEmbedderAccessInstanceID(
if (it == guest_web_contents_by_instance_id_.end())
return true;
- auto guest_view = GuestViewBase::FromWebContents(it->second);
+ auto* guest_view = GuestViewBase::FromWebContents(it->second);
if (!guest_view)
return false;
diff --git a/chromium/components/guest_view/browser/guest_view_message_filter.cc b/chromium/components/guest_view/browser/guest_view_message_filter.cc
index c1f65906caf..bb17ea69d4a 100644
--- a/chromium/components/guest_view/browser/guest_view_message_filter.cc
+++ b/chromium/components/guest_view/browser/guest_view_message_filter.cc
@@ -49,11 +49,10 @@ GuestViewMessageFilter::~GuestViewMessageFilter() {
}
GuestViewManager* GuestViewMessageFilter::GetOrCreateGuestViewManager() {
- auto manager = GuestViewManager::FromBrowserContext(browser_context_);
+ auto* manager = GuestViewManager::FromBrowserContext(browser_context_);
if (!manager) {
manager = GuestViewManager::CreateWithDelegate(
- browser_context_, base::WrapUnique(
- new GuestViewManagerDelegate()));
+ browser_context_, base::MakeUnique<GuestViewManagerDelegate>());
}
return manager;
}
@@ -103,7 +102,7 @@ void GuestViewMessageFilter::OnAttachGuest(
int guest_instance_id,
const base::DictionaryValue& params) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- auto manager = GuestViewManager::FromBrowserContext(browser_context_);
+ auto* manager = GuestViewManager::FromBrowserContext(browser_context_);
// We should have a GuestViewManager at this point. If we don't then the
// embedder is misbehaving.
if (!manager)
diff --git a/chromium/components/guest_view/renderer/BUILD.gn b/chromium/components/guest_view/renderer/BUILD.gn
index aa15cc2664f..df68a0ed028 100644
--- a/chromium/components/guest_view/renderer/BUILD.gn
+++ b/chromium/components/guest_view/renderer/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("renderer") {
+static_library("renderer") {
sources = [
"guest_view_container.cc",
"guest_view_container.h",
diff --git a/chromium/components/guest_view/renderer/guest_view_container.cc b/chromium/components/guest_view/renderer/guest_view_container.cc
index 0c63a16f088..0ec3d5fe8c0 100644
--- a/chromium/components/guest_view/renderer/guest_view_container.cc
+++ b/chromium/components/guest_view/renderer/guest_view_container.cc
@@ -103,7 +103,8 @@ void GuestViewContainer::Destroy(bool embedder_frame_destroyed) {
pending_response_->ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
while (pending_requests_.size() > 0) {
- linked_ptr<GuestViewRequest> pending_request = pending_requests_.front();
+ std::unique_ptr<GuestViewRequest> pending_request =
+ std::move(pending_requests_.front());
pending_requests_.pop_front();
// Call the JavaScript callbacks with no arguments which implies an error.
pending_request->ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
@@ -126,29 +127,33 @@ void GuestViewContainer::RenderFrameDestroyed() {
Destroy(true /* embedder_frame_destroyed */);
}
-void GuestViewContainer::IssueRequest(linked_ptr<GuestViewRequest> request) {
- EnqueueRequest(request);
+void GuestViewContainer::IssueRequest(
+ std::unique_ptr<GuestViewRequest> request) {
+ EnqueueRequest(std::move(request));
PerformPendingRequest();
}
-void GuestViewContainer::EnqueueRequest(linked_ptr<GuestViewRequest> request) {
- pending_requests_.push_back(request);
+void GuestViewContainer::EnqueueRequest(
+ std::unique_ptr<GuestViewRequest> request) {
+ pending_requests_.push_back(std::move(request));
}
void GuestViewContainer::PerformPendingRequest() {
if (!ready_ || pending_requests_.empty() || pending_response_.get())
return;
- linked_ptr<GuestViewRequest> pending_request = pending_requests_.front();
+ std::unique_ptr<GuestViewRequest> pending_request =
+ std::move(pending_requests_.front());
pending_requests_.pop_front();
pending_request->PerformRequest();
- pending_response_ = pending_request;
+ pending_response_ = std::move(pending_request);
}
void GuestViewContainer::HandlePendingResponseCallback(
const IPC::Message& message) {
CHECK(pending_response_.get());
- linked_ptr<GuestViewRequest> pending_response(pending_response_.release());
+ std::unique_ptr<GuestViewRequest> pending_response =
+ std::move(pending_response_);
pending_response->HandleResponse(message);
}
diff --git a/chromium/components/guest_view/renderer/guest_view_container.h b/chromium/components/guest_view/renderer/guest_view_container.h
index 65133525fcf..0218e5a75ca 100644
--- a/chromium/components/guest_view/renderer/guest_view_container.h
+++ b/chromium/components/guest_view/renderer/guest_view_container.h
@@ -8,7 +8,6 @@
#include <memory>
#include "base/macros.h"
-#include "base/memory/linked_ptr.h"
#include "content/public/renderer/browser_plugin_delegate.h"
#include "ipc/ipc_message.h"
#include "v8/include/v8.h"
@@ -26,7 +25,7 @@ class GuestViewContainer : public content::BrowserPluginDelegate {
// IssueRequest queues up a |request| until the container is ready and
// the browser process has responded to the last request if it's still
// pending.
- void IssueRequest(linked_ptr<GuestViewRequest> request);
+ void IssueRequest(std::unique_ptr<GuestViewRequest> request);
int element_instance_id() const { return element_instance_id_; }
content::RenderFrame* render_frame() const { return render_frame_; }
@@ -74,7 +73,7 @@ class GuestViewContainer : public content::BrowserPluginDelegate {
void RenderFrameDestroyed();
- void EnqueueRequest(linked_ptr<GuestViewRequest> request);
+ void EnqueueRequest(std::unique_ptr<GuestViewRequest> request);
void PerformPendingRequest();
void HandlePendingResponseCallback(const IPC::Message& message);
void RunDestructionCallback(bool embedder_frame_destroyed);
@@ -90,8 +89,8 @@ class GuestViewContainer : public content::BrowserPluginDelegate {
bool in_destruction_;
- std::deque<linked_ptr<GuestViewRequest> > pending_requests_;
- linked_ptr<GuestViewRequest> pending_response_;
+ std::deque<std::unique_ptr<GuestViewRequest>> pending_requests_;
+ std::unique_ptr<GuestViewRequest> pending_response_;
v8::Global<v8::Function> destruction_callback_;
v8::Isolate* destruction_isolate_;
diff --git a/chromium/components/guest_view/renderer/iframe_guest_view_container.cc b/chromium/components/guest_view/renderer/iframe_guest_view_container.cc
index 36ca0b682b3..eaf1b8b8651 100644
--- a/chromium/components/guest_view/renderer/iframe_guest_view_container.cc
+++ b/chromium/components/guest_view/renderer/iframe_guest_view_container.cc
@@ -5,7 +5,7 @@
#include "components/guest_view/renderer/iframe_guest_view_container.h"
#include "components/guest_view/common/guest_view_messages.h"
-#include "content/public/common/browser_plugin_guest_mode.h"
+#include "content/public/renderer/guest_mode.h"
#include "content/public/renderer/render_frame.h"
namespace guest_view {
@@ -13,7 +13,7 @@ namespace guest_view {
IframeGuestViewContainer::IframeGuestViewContainer(
content::RenderFrame* render_frame)
: GuestViewContainer(render_frame) {
- CHECK(content::BrowserPluginGuestMode::UseCrossProcessFramesForGuests());
+ CHECK(content::GuestMode::UseCrossProcessFramesForGuests());
// There is no BrowserPluginDelegate to wait for.
ready_ = true;
}
diff --git a/chromium/components/handoff.gypi b/chromium/components/handoff.gypi
deleted file mode 100644
index 264e031977b..00000000000
--- a/chromium/components/handoff.gypi
+++ /dev/null
@@ -1,33 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/handoff
- 'target_name': 'handoff',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'conditions': [
- ['OS=="mac" or OS=="ios"', {
- 'sources': [
- 'handoff/handoff_utility.h',
- 'handoff/handoff_utility.mm',
- ],
- }],
- ['OS=="mac"', {
- 'sources': [
- 'handoff/handoff_manager.h',
- 'handoff/handoff_manager.mm',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- }],
- ],
- },
- ],
-}
diff --git a/chromium/components/handoff/handoff_manager.mm b/chromium/components/handoff/handoff_manager.mm
index 0f4fa76a9ed..23a557dce71 100644
--- a/chromium/components/handoff/handoff_manager.mm
+++ b/chromium/components/handoff/handoff_manager.mm
@@ -58,7 +58,7 @@
#if defined(OS_MACOSX) && !defined(OS_IOS)
// Handoff is only available on OSX 10.10+.
- DCHECK(base::mac::IsOSYosemiteOrLater());
+ DCHECK(base::mac::IsAtLeastOS10_10());
#endif
_activeURL = url;
diff --git a/chromium/components/history.gypi b/chromium/components/history.gypi
deleted file mode 100644
index 580eee38fbe..00000000000
--- a/chromium/components/history.gypi
+++ /dev/null
@@ -1,268 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/history/core/browser
- 'target_name': 'history_core_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../sql/sql.gyp:sql',
- '../sync/sync.gyp:sync',
- '../third_party/sqlite/sqlite.gyp:sqlite',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx',
- '../url/url.gyp:url_lib',
- 'favicon_base',
- 'history_core_common',
- 'keyed_service_core',
- 'prefs/prefs.gyp:prefs',
- 'query_parser',
- 'signin_core_browser',
- 'sync_driver',
- 'url_formatter/url_formatter.gyp:url_formatter',
- 'version_info',
- ],
- 'export_dependent_settings': [
- '../skia/skia.gyp:skia',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'history/core/browser/delete_directive_handler.cc',
- 'history/core/browser/delete_directive_handler.h',
- 'history/core/browser/download_constants.h',
- 'history/core/browser/download_database.cc',
- 'history/core/browser/download_database.h',
- 'history/core/browser/download_row.cc',
- 'history/core/browser/download_row.h',
- 'history/core/browser/download_types.cc',
- 'history/core/browser/download_types.h',
- 'history/core/browser/expire_history_backend.cc',
- 'history/core/browser/expire_history_backend.h',
- 'history/core/browser/history_backend.cc',
- 'history/core/browser/history_backend.h',
- 'history/core/browser/history_backend_client.h',
- 'history/core/browser/history_backend_notifier.h',
- 'history/core/browser/history_backend_observer.h',
- 'history/core/browser/history_client.h',
- 'history/core/browser/history_constants.cc',
- 'history/core/browser/history_constants.h',
- 'history/core/browser/history_context.h',
- 'history/core/browser/history_database.cc',
- 'history/core/browser/history_database.h',
- 'history/core/browser/history_database_params.cc',
- 'history/core/browser/history_database_params.h',
- 'history/core/browser/history_db_task.h',
- 'history/core/browser/history_delete_directives_data_type_controller.cc',
- 'history/core/browser/history_delete_directives_data_type_controller.h',
- 'history/core/browser/history_match.cc',
- 'history/core/browser/history_match.h',
- 'history/core/browser/history_model_worker.cc',
- 'history/core/browser/history_model_worker.h',
- 'history/core/browser/history_service.cc',
- 'history/core/browser/history_service.h',
- 'history/core/browser/history_service_observer.h',
- 'history/core/browser/history_types.cc',
- 'history/core/browser/history_types.h',
- 'history/core/browser/in_memory_database.cc',
- 'history/core/browser/in_memory_database.h',
- 'history/core/browser/in_memory_history_backend.cc',
- 'history/core/browser/in_memory_history_backend.h',
- 'history/core/browser/keyword_id.h',
- 'history/core/browser/keyword_search_term.cc',
- 'history/core/browser/keyword_search_term.h',
- 'history/core/browser/page_usage_data.cc',
- 'history/core/browser/page_usage_data.h',
- 'history/core/browser/thumbnail_database.cc',
- 'history/core/browser/thumbnail_database.h',
- 'history/core/browser/top_sites.cc',
- 'history/core/browser/top_sites.h',
- 'history/core/browser/top_sites_backend.cc',
- 'history/core/browser/top_sites_backend.h',
- 'history/core/browser/top_sites_cache.cc',
- 'history/core/browser/top_sites_cache.h',
- 'history/core/browser/top_sites_database.cc',
- 'history/core/browser/top_sites_database.h',
- 'history/core/browser/top_sites_impl.cc',
- 'history/core/browser/top_sites_impl.h',
- 'history/core/browser/top_sites_observer.h',
- 'history/core/browser/typed_url_data_type_controller.cc',
- 'history/core/browser/typed_url_data_type_controller.h',
- 'history/core/browser/typed_url_syncable_service.cc',
- 'history/core/browser/typed_url_syncable_service.h',
- 'history/core/browser/url_database.cc',
- 'history/core/browser/url_database.h',
- 'history/core/browser/url_row.cc',
- 'history/core/browser/url_row.h',
- 'history/core/browser/url_utils.cc',
- 'history/core/browser/url_utils.h',
- 'history/core/browser/visit_database.cc',
- 'history/core/browser/visit_database.h',
- 'history/core/browser/visit_delegate.cc',
- 'history/core/browser/visit_delegate.h',
- 'history/core/browser/visit_tracker.cc',
- 'history/core/browser/visit_tracker.h',
- 'history/core/browser/visitsegment_database.cc',
- 'history/core/browser/visitsegment_database.h',
- 'history/core/browser/web_history_service.cc',
- 'history/core/browser/web_history_service.h',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'sources': [
- 'history/core/browser/android/android_cache_database.cc',
- 'history/core/browser/android/android_cache_database.h',
- 'history/core/browser/android/android_history_types.cc',
- 'history/core/browser/android/android_history_types.h',
- 'history/core/browser/android/android_time.h',
- 'history/core/browser/android/android_urls_database.cc',
- 'history/core/browser/android/android_urls_database.h',
- 'history/core/browser/android/android_urls_sql_handler.cc',
- 'history/core/browser/android/android_urls_sql_handler.h',
- 'history/core/browser/android/favicon_sql_handler.cc',
- 'history/core/browser/android/favicon_sql_handler.h',
- 'history/core/browser/android/sql_handler.cc',
- 'history/core/browser/android/sql_handler.h',
- 'history/core/browser/android/urls_sql_handler.cc',
- 'history/core/browser/android/urls_sql_handler.h',
- 'history/core/browser/android/visit_sql_handler.cc',
- 'history/core/browser/android/visit_sql_handler.h',
- ],
- }],
- ],
- },
- {
- # GN version: //components/history/core/common
- 'target_name': 'history_core_common',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'history/core/common/thumbnail_score.cc',
- 'history/core/common/thumbnail_score.h',
- ],
- },
- {
- # GN version: //components/history/core/test
- 'target_name': 'history_core_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../sql/sql.gyp:sql',
- '../sql/sql.gyp:test_support_sql',
- '../sync/sync.gyp:sync',
- '../testing/gtest.gyp:gtest',
- '../ui/gfx/gfx.gyp:gfx',
- '../url/url.gyp:url_lib',
- 'history_core_browser',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'history/core/test/database_test_utils.cc',
- 'history/core/test/database_test_utils.h',
- 'history/core/test/fake_web_history_service.cc',
- 'history/core/test/fake_web_history_service.h',
- 'history/core/test/history_backend_db_base_test.cc',
- 'history/core/test/history_backend_db_base_test.h',
- 'history/core/test/history_client_fake_bookmarks.cc',
- 'history/core/test/history_client_fake_bookmarks.h',
- 'history/core/test/history_unittest_base.cc',
- 'history/core/test/history_service_test_util.cc',
- 'history/core/test/history_service_test_util.h',
- 'history/core/test/history_unittest_base.h',
- 'history/core/test/test_history_database.cc',
- 'history/core/test/test_history_database.h',
- 'history/core/test/thumbnail-inl.h',
- 'history/core/test/thumbnail.cc',
- 'history/core/test/thumbnail.h',
- 'history/core/test/thumbnail_ios.mm',
- 'history/core/test/wait_top_sites_loaded_observer.cc',
- 'history/core/test/wait_top_sites_loaded_observer.h',
- ],
- 'conditions': [
- ['OS=="ios"', {
- 'sources!': [
- 'history/core/test/thumbnail.cc',
- ],
- }],
- ],
- },
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'targets': [
- {
- # GN version: //components/history/content/browser
- 'target_name': 'history_content_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../url/url.gyp:url_lib',
- 'history_core_browser',
- 'visitedlink_browser',
- ],
- 'sources': [
- 'history/content/browser/content_visit_delegate.cc',
- 'history/content/browser/content_visit_delegate.h',
- 'history/content/browser/download_constants_utils.cc',
- 'history/content/browser/download_constants_utils.h',
- 'history/content/browser/history_context_helper.cc',
- 'history/content/browser/history_context_helper.h',
- 'history/content/browser/history_database_helper.cc',
- 'history/content/browser/history_database_helper.h',
- 'history/content/browser/web_contents_top_sites_observer.cc',
- 'history/content/browser/web_contents_top_sites_observer.h',
- ],
- }
- ],
- }],
- ['OS=="ios"', {
- 'targets': [
- {
- # GN version: //components/history/ios/browser
- 'target_name': 'history_ios_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../ios/web/ios_web.gyp:ios_web',
- '../url/url.gyp:url_lib',
- 'history_core_browser',
- ],
- 'sources': [
- 'history/ios/browser/history_database_helper.cc',
- 'history/ios/browser/history_database_helper.h',
- 'history/ios/browser/web_state_top_sites_observer.h',
- 'history/ios/browser/web_state_top_sites_observer.mm',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/history/DEPS b/chromium/components/history/DEPS
index 01352e6beb8..3208ad1caa6 100644
--- a/chromium/components/history/DEPS
+++ b/chromium/components/history/DEPS
@@ -4,11 +4,10 @@ include_rules = [
"+components/query_parser",
"+components/prefs",
"+components/signin/core",
- "+components/sync_driver",
+ "+components/sync",
"+google_apis/gaia",
"+net",
"+sql",
- "+sync",
"+third_party/skia",
"+third_party/sqlite",
"+ui/base",
diff --git a/chromium/components/history/core/browser/BUILD.gn b/chromium/components/history/core/browser/BUILD.gn
index 855753158f2..d39e9f73b75 100644
--- a/chromium/components/history/core/browser/BUILD.gn
+++ b/chromium/components/history/core/browser/BUILD.gn
@@ -82,6 +82,7 @@ static_library("browser") {
"visitsegment_database.h",
"web_history_service.cc",
"web_history_service.h",
+ "web_history_service_observer.h",
]
public_deps = [
@@ -97,13 +98,12 @@ static_library("browser") {
"//components/prefs",
"//components/query_parser",
"//components/signin/core/browser",
- "//components/sync_driver",
+ "//components/sync",
"//components/url_formatter",
"//components/version_info",
"//google_apis",
"//net",
"//sql",
- "//sync",
"//third_party/sqlite",
"//ui/base",
"//ui/gfx",
@@ -206,10 +206,10 @@ source_set("unit_tests") {
"//components/prefs:test_support",
"//components/signin/core/browser",
"//components/signin/core/browser:test_support",
- "//components/sync_driver:test_support",
+ "//components/sync:test_support_sync_api",
+ "//components/sync:test_support_sync_driver",
"//sql",
"//sql:test_support",
- "//sync:test_support_sync_api",
"//testing/gtest",
"//ui/gfx",
"//ui/gfx:test_support",
diff --git a/chromium/components/history/core/browser/android/android_urls_sql_handler.cc b/chromium/components/history/core/browser/android/android_urls_sql_handler.cc
index e75529192ac..31d22999f40 100644
--- a/chromium/components/history/core/browser/android/android_urls_sql_handler.cc
+++ b/chromium/components/history/core/browser/android/android_urls_sql_handler.cc
@@ -51,14 +51,9 @@ bool AndroidURLsSQLHandler::Insert(HistoryAndBookmarkRow* row) {
bool AndroidURLsSQLHandler::Delete(const TableIDRows& ids_set) {
std::vector<URLID> ids;
- for (TableIDRows::const_iterator id = ids_set.begin();
- id != ids_set.end(); ++id)
- ids.push_back(id->url_id);
-
- if (!ids.size())
- return true;
-
- return android_urls_db_->DeleteAndroidURLRows(ids);
+ for (const auto& id : ids_set)
+ ids.push_back(id.url_id);
+ return ids.empty() || android_urls_db_->DeleteAndroidURLRows(ids);
}
} // namespace history.
diff --git a/chromium/components/history/core/browser/delete_directive_handler.cc b/chromium/components/history/core/browser/delete_directive_handler.cc
index 6d7087bce75..deb3336c50d 100644
--- a/chromium/components/history/core/browser/delete_directive_handler.cc
+++ b/chromium/components/history/core/browser/delete_directive_handler.cc
@@ -5,6 +5,7 @@
#include "components/history/core/browser/delete_directive_handler.h"
#include <stddef.h>
+
#include <utility>
#include "base/json/json_writer.h"
@@ -14,10 +15,10 @@
#include "components/history/core/browser/history_backend.h"
#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/browser/history_service.h"
-#include "sync/api/sync_change.h"
-#include "sync/protocol/history_delete_directive_specifics.pb.h"
-#include "sync/protocol/proto_value_conversions.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/protocol/history_delete_directive_specifics.pb.h"
+#include "components/sync/protocol/proto_value_conversions.h"
+#include "components/sync/protocol/sync.pb.h"
namespace {
diff --git a/chromium/components/history/core/browser/delete_directive_handler.h b/chromium/components/history/core/browser/delete_directive_handler.h
index a72cd6e3501..1c42948f33c 100644
--- a/chromium/components/history/core/browser/delete_directive_handler.h
+++ b/chromium/components/history/core/browser/delete_directive_handler.h
@@ -13,8 +13,8 @@
#include "base/memory/weak_ptr.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/threading/thread_checker.h"
-#include "sync/api/sync_change_processor.h"
-#include "sync/api/sync_data.h"
+#include "components/sync/api/sync_change_processor.h"
+#include "components/sync/api/sync_data.h"
namespace sync_pb {
class HistoryDeleteDirectiveSpecifics;
diff --git a/chromium/components/history/core/browser/download_database.cc b/chromium/components/history/core/browser/download_database.cc
index cf90813a67b..5994bf5e256 100644
--- a/chromium/components/history/core/browser/download_database.cc
+++ b/chromium/components/history/core/browser/download_database.cc
@@ -13,7 +13,7 @@
#include "base/debug/alias.h"
#include "base/files/file_path.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
@@ -29,7 +29,7 @@ namespace history {
namespace {
-// Reason for dropping a particular record.
+// Reason for dropping a particular record. Used for UMA.
enum DroppedReason {
DROPPED_REASON_BAD_STATE = 0,
DROPPED_REASON_BAD_DANGER_TYPE = 1,
@@ -425,7 +425,7 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
dropped_reason,
DROPPED_REASON_MAX + 1);
} else {
- DCHECK(!ContainsKey(info_map, info->id));
+ DCHECK(!base::ContainsKey(info_map, info->id));
uint32_t id = info->id;
info_map[id] = info.release();
}
@@ -453,8 +453,8 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
// Confirm the id has already been seen--if it hasn't, discard the
// record.
- DCHECK(ContainsKey(info_map, id));
- if (!ContainsKey(info_map, id))
+ DCHECK(base::ContainsKey(info_map, id));
+ if (!base::ContainsKey(info_map, id))
continue;
// Confirm all previous URLs in the chain have already been seen;
@@ -624,7 +624,6 @@ bool DownloadDatabase::CreateDownload(const DownloadRow& info) {
count_urls.BindInt(0, info.id);
if (count_urls.Step()) {
bool corrupt_urls = count_urls.ColumnInt(0) > 0;
- UMA_HISTOGRAM_BOOLEAN("Download.DatabaseCorruptUrls", corrupt_urls);
if (corrupt_urls) {
// There should not be any URLs in downloads_url_chains for this
// info.id. If there are, we don't want them to interfere with
diff --git a/chromium/components/history/core/browser/expire_history_backend_unittest.cc b/chromium/components/history/core/browser/expire_history_backend_unittest.cc
index ee87550e85b..11cd46f7578 100644
--- a/chromium/components/history/core/browser/expire_history_backend_unittest.cc
+++ b/chromium/components/history/core/browser/expire_history_backend_unittest.cc
@@ -91,7 +91,7 @@ class ExpireHistoryTest : public testing::Test, public HistoryBackendNotifier {
static bool IsStringInFile(const base::FilePath& filename, const char* str);
// Returns the path the db files are created in.
- const base::FilePath& path() const { return tmp_dir_.path(); }
+ const base::FilePath& path() const { return tmp_dir_.GetPath(); }
// This must be destroyed last.
base::ScopedTempDir tmp_dir_;
diff --git a/chromium/components/history/core/browser/history_backend.cc b/chromium/components/history/core/browser/history_backend.cc
index 784093a864f..166921d35f4 100644
--- a/chromium/components/history/core/browser/history_backend.cc
+++ b/chromium/components/history/core/browser/history_backend.cc
@@ -16,6 +16,7 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/files/file_enumerator.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
@@ -24,7 +25,9 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "components/favicon_base/favicon_util.h"
#include "components/favicon_base/select_favicon_frames.h"
#include "components/history/core/browser/download_constants.h"
#include "components/history/core/browser/download_row.h"
@@ -68,12 +71,14 @@ using base::TimeTicks;
namespace history {
namespace {
+
void RunUnlessCanceled(
const base::Closure& closure,
const base::CancelableTaskTracker::IsCanceledCallback& is_canceled) {
if (!is_canceled.Run())
closure.Run();
}
+
} // namespace
// How long we'll wait to do a commit, so that things are batched together.
@@ -102,7 +107,7 @@ MostVisitedURL MakeMostVisitedURL(const PageUsageData& page_data,
mv.redirects.push_back(mv.url);
} else {
mv.redirects = redirects;
- if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
+ if (mv.redirects.back() != mv.url) {
// The last url must be the target url.
mv.redirects.push_back(mv.url);
}
@@ -215,8 +220,6 @@ HistoryBackend::HistoryBackend(
HistoryBackend::~HistoryBackend() {
DCHECK(!scheduled_commit_) << "Deleting without cleanup";
- STLDeleteContainerPointers(queued_history_db_tasks_.begin(),
- queued_history_db_tasks_.end());
queued_history_db_tasks_.clear();
// Release stashed embedder object before cleaning up the databases.
@@ -518,7 +521,7 @@ void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
// Update the segment for this visit. KEYWORD_GENERATED visits should not
// result in changing most visited, so we don't update segments (most
// visited db).
- if (!is_keyword_generated) {
+ if (!is_keyword_generated && request.consider_for_ntp_most_visited) {
UpdateSegments(request.url, from_visit_id, last_ids.second, t,
request.time);
@@ -588,9 +591,10 @@ void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
last_ids = AddPageVisit(redirects[redirect_index], request.time,
last_ids.second, t, request.visit_source);
if (t & ui::PAGE_TRANSITION_CHAIN_START) {
- // Update the segment for this visit.
- UpdateSegments(redirects[redirect_index], from_visit_id,
- last_ids.second, t, request.time);
+ if (request.consider_for_ntp_most_visited) {
+ UpdateSegments(redirects[redirect_index], from_visit_id,
+ last_ids.second, t, request.time);
+ }
// Update the visit_details for this visit.
UpdateVisitDuration(from_visit_id, request.time);
@@ -652,14 +656,11 @@ void HistoryBackend::InitImpl(
db_->set_error_callback(base::Bind(&HistoryBackend::DatabaseErrorCallback,
base::Unretained(this)));
+ db_diagnostics_.clear();
sql::InitStatus status = db_->Init(history_name);
switch (status) {
case sql::INIT_OK:
break;
- case sql::INIT_TOO_NEW:
- delegate_->NotifyProfileError(status);
- db_.reset();
- return;
case sql::INIT_FAILURE: {
// A null db_ will cause all calls on this object to notice this error
// and to not continue. If the error callback scheduled killing the
@@ -669,7 +670,10 @@ void HistoryBackend::InitImpl(
if (kill_db)
KillHistoryDatabase();
UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
- delegate_->NotifyProfileError(status);
+ } // Falls through.
+ case sql::INIT_TOO_NEW: {
+ db_diagnostics_ += sql::GetCorruptFileDiagnosticsInfo(history_name);
+ delegate_->NotifyProfileError(status, db_diagnostics_);
db_.reset();
return;
}
@@ -1177,7 +1181,15 @@ bool HistoryBackend::CreateDownload(const DownloadRow& history_info) {
if (!db_)
return false;
bool success = db_->CreateDownload(history_info);
+#if defined(OS_ANDROID)
+ // On android, browser process can get easily killed. Download will no longer
+ // be able to resume and the temporary file will linger forever if the
+ // download is not committed before that. Do the commit right away to avoid
+ // uncommitted download entry if browser is killed.
+ Commit();
+#else
ScheduleCommit();
+#endif
return success;
}
@@ -1209,10 +1221,6 @@ void HistoryBackend::RemoveDownloads(const std::set<uint32_t>& ids) {
(1000 * micros) / num_downloads_deleted);
}
DCHECK_GE(ids.size(), num_downloads_deleted);
- if (ids.size() < num_downloads_deleted)
- return;
- UMA_HISTOGRAM_COUNTS("Download.DatabaseRemoveDownloadsCountNotRemoved",
- ids.size() - num_downloads_deleted);
}
void HistoryBackend::QueryHistory(const base::string16& text_query,
@@ -1539,14 +1547,20 @@ void HistoryBackend::GetFaviconsForURL(
int icon_types,
const std::vector<int>& desired_sizes,
std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
+ TRACE_EVENT0("browser", "HistoryBackend::GetFaviconsForURL");
DCHECK(bitmap_results);
GetFaviconsFromDB(page_url, icon_types, desired_sizes, bitmap_results);
+
+ if (desired_sizes.size() == 1)
+ bitmap_results->assign(1, favicon_base::ResizeFaviconBitmapResult(
+ *bitmap_results, desired_sizes[0]));
}
void HistoryBackend::GetFaviconForID(
favicon_base::FaviconID favicon_id,
int desired_size,
std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
+ TRACE_EVENT0("browser", "HistoryBackend::GetFaviconForID");
std::vector<favicon_base::FaviconID> favicon_ids;
favicon_ids.push_back(favicon_id);
std::vector<int> desired_sizes;
@@ -1555,6 +1569,9 @@ void HistoryBackend::GetFaviconForID(
// Get results from DB.
GetFaviconBitmapResultsForBestMatch(favicon_ids, desired_sizes,
bitmap_results);
+
+ bitmap_results->assign(1, favicon_base::ResizeFaviconBitmapResult(
+ *bitmap_results, desired_size));
}
void HistoryBackend::UpdateFaviconMappingsAndFetch(
@@ -2227,7 +2244,7 @@ void HistoryBackend::ScheduleCommit() {
scheduled_commit_ = new CommitLaterTask(this);
task_runner_->PostDelayedTask(
FROM_HERE,
- base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_.get()),
+ base::Bind(&CommitLaterTask::RunCommit, scheduled_commit_),
base::TimeDelta::FromSeconds(kCommitIntervalSeconds));
}
@@ -2241,26 +2258,24 @@ void HistoryBackend::CancelScheduledCommit() {
void HistoryBackend::ProcessDBTaskImpl() {
if (!db_) {
// db went away, release all the refs.
- STLDeleteContainerPointers(queued_history_db_tasks_.begin(),
- queued_history_db_tasks_.end());
queued_history_db_tasks_.clear();
return;
}
// Remove any canceled tasks.
while (!queued_history_db_tasks_.empty()) {
- QueuedHistoryDBTask* task = queued_history_db_tasks_.front();
+ QueuedHistoryDBTask* task = queued_history_db_tasks_.front().get();
if (!task->is_canceled())
break;
- delete task;
queued_history_db_tasks_.pop_front();
}
if (queued_history_db_tasks_.empty())
return;
// Run the first task.
- std::unique_ptr<QueuedHistoryDBTask> task(queued_history_db_tasks_.front());
+ std::unique_ptr<QueuedHistoryDBTask> task =
+ std::move(queued_history_db_tasks_.front());
queued_history_db_tasks_.pop_front();
if (task->Run(this, db_.get())) {
// The task is done, notify the callback.
@@ -2268,7 +2283,7 @@ void HistoryBackend::ProcessDBTaskImpl() {
} else {
// The task wants to run some more. Schedule it at the end of the current
// tasks, and process it after an invoke later.
- queued_history_db_tasks_.push_back(task.release());
+ queued_history_db_tasks_.push_back(std::move(task));
task_runner_->PostTask(
FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTaskImpl, this));
}
@@ -2411,6 +2426,9 @@ void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
if (!scheduled_kill_db_ && sql::IsErrorCatastrophic(error)) {
scheduled_kill_db_ = true;
+
+ db_diagnostics_ = db_->GetDiagnosticInfo(error, stmt);
+
// Don't just do the close/delete here, as we are being called by |db| and
// that seems dangerous.
// TODO(shess): Consider changing KillHistoryDatabase() to use
@@ -2460,8 +2478,8 @@ void HistoryBackend::ProcessDBTask(
scoped_refptr<base::SingleThreadTaskRunner> origin_loop,
const base::CancelableTaskTracker::IsCanceledCallback& is_canceled) {
bool scheduled = !queued_history_db_tasks_.empty();
- queued_history_db_tasks_.push_back(
- new QueuedHistoryDBTask(std::move(task), origin_loop, is_canceled));
+ queued_history_db_tasks_.push_back(base::MakeUnique<QueuedHistoryDBTask>(
+ std::move(task), origin_loop, is_canceled));
if (!scheduled)
ProcessDBTaskImpl();
}
diff --git a/chromium/components/history/core/browser/history_backend.h b/chromium/components/history/core/browser/history_backend.h
index 0b952b4b4b8..0d044f7b334 100644
--- a/chromium/components/history/core/browser/history_backend.h
+++ b/chromium/components/history/core/browser/history_backend.h
@@ -113,7 +113,10 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
virtual ~Delegate() {}
// Called when the database cannot be read correctly for some reason.
- virtual void NotifyProfileError(sql::InitStatus init_status) = 0;
+ // |diagnostics| contains information about the underlying database
+ // which can help in identifying the cause of the profile error.
+ virtual void NotifyProfileError(sql::InitStatus init_status,
+ const std::string& diagnostics) = 0;
// Sets the in-memory history backend. The in-memory backend is created by
// the main backend. For non-unit tests, this happens on the background
@@ -860,7 +863,7 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
bool segment_queried_;
// List of QueuedHistoryDBTasks to run;
- std::list<QueuedHistoryDBTask*> queued_history_db_tasks_;
+ std::list<std::unique_ptr<QueuedHistoryDBTask>> queued_history_db_tasks_;
// Used to determine if a URL is bookmarked; may be null.
std::unique_ptr<HistoryBackendClient> backend_client_;
@@ -879,6 +882,10 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// Listens for the system being under memory pressure.
std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+ // Contains diagnostic information about the sql database that is non-empty
+ // when a catastrophic error occurs.
+ std::string db_diagnostics_;
+
// Map from host to index in the TopHosts list. It is updated only by
// TopHosts(), so it's usually stale.
mutable base::hash_map<std::string, int> host_ranks_;
diff --git a/chromium/components/history/core/browser/history_backend_unittest.cc b/chromium/components/history/core/browser/history_backend_unittest.cc
index 0612d6a4c40..b89d0a76ecc 100644
--- a/chromium/components/history/core/browser/history_backend_unittest.cc
+++ b/chromium/components/history/core/browser/history_backend_unittest.cc
@@ -121,7 +121,8 @@ class HistoryBackendTestDelegate : public HistoryBackend::Delegate {
explicit HistoryBackendTestDelegate(HistoryBackendTestBase* test)
: test_(test) {}
- void NotifyProfileError(sql::InitStatus init_status) override {}
+ void NotifyProfileError(sql::InitStatus init_status,
+ const std::string& diagnostics) override {}
void SetInMemoryBackend(
std::unique_ptr<InMemoryHistoryBackend> backend) override;
void NotifyFaviconsChanged(const std::set<GURL>& page_urls,
@@ -356,7 +357,7 @@ class HistoryBackendTest : public HistoryBackendTestBase {
history::HistoryAddPageArgs request(
redirects.back(), time, context_id, nav_entry_id, GURL(),
redirects, transition, history::SOURCE_BROWSED,
- true);
+ true, true);
backend_->AddPage(request);
}
@@ -382,7 +383,7 @@ class HistoryBackendTest : public HistoryBackendTestBase {
HistoryAddPageArgs request(
url2, time, dummy_context_id, 0, url1,
redirects, ui::PAGE_TRANSITION_CLIENT_REDIRECT,
- history::SOURCE_BROWSED, did_replace);
+ history::SOURCE_BROWSED, did_replace, true);
backend_->AddPage(request);
*transition1 = GetTransition(url1);
@@ -778,7 +779,7 @@ TEST_F(HistoryBackendTest, DeleteAllThenAddData) {
HistoryAddPageArgs request(url, visit_time, NULL, 0, GURL(),
history::RedirectList(),
ui::PAGE_TRANSITION_KEYWORD_GENERATED,
- history::SOURCE_BROWSED, false);
+ history::SOURCE_BROWSED, false, true);
backend_->AddPage(request);
// Check that a row was added.
@@ -920,7 +921,7 @@ TEST_F(HistoryBackendTest, KeywordGenerated) {
HistoryAddPageArgs request(url, visit_time, NULL, 0, GURL(),
history::RedirectList(),
ui::PAGE_TRANSITION_KEYWORD_GENERATED,
- history::SOURCE_BROWSED, false);
+ history::SOURCE_BROWSED, false, true);
backend_->AddPage(request);
// A row should have been added for the url.
@@ -952,7 +953,7 @@ TEST_F(HistoryBackendTest, KeywordGenerated) {
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FORWARD_BACK);
HistoryAddPageArgs back_request(url, visit_time, NULL, 0, GURL(),
history::RedirectList(), back_transition,
- history::SOURCE_BROWSED, false);
+ history::SOURCE_BROWSED, false, true);
backend_->AddPage(back_request);
url_id = backend_->db()->GetRowForURL(url, &row);
ASSERT_NE(0, url_id);
@@ -1481,19 +1482,19 @@ TEST_F(HistoryBackendTest, AddPageArgsSource) {
HistoryAddPageArgs request1(url, base::Time::Now(), NULL, 0, GURL(),
history::RedirectList(),
ui::PAGE_TRANSITION_KEYWORD_GENERATED,
- history::SOURCE_BROWSED, false);
+ history::SOURCE_BROWSED, false, true);
backend_->AddPage(request1);
// Assume this page is synced.
HistoryAddPageArgs request2(url, base::Time::Now(), NULL, 0, GURL(),
history::RedirectList(),
ui::PAGE_TRANSITION_LINK,
- history::SOURCE_SYNCED, false);
+ history::SOURCE_SYNCED, false, true);
backend_->AddPage(request2);
// Assume this page is browsed again.
HistoryAddPageArgs request3(url, base::Time::Now(), NULL, 0, GURL(),
history::RedirectList(),
ui::PAGE_TRANSITION_TYPED,
- history::SOURCE_BROWSED, false);
+ history::SOURCE_BROWSED, false, true);
backend_->AddPage(request3);
// Three visits should be added with proper sources.
@@ -3020,8 +3021,12 @@ TEST_F(HistoryBackendTest, TopHosts) {
urls.push_back(GURL("http://cnn.com/intl"));
urls.push_back(GURL("http://dogtopia.com/"));
for (const GURL& url : urls) {
- backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
- history::SOURCE_BROWSED);
+ backend_->AddPageVisit(
+ url, base::Time::Now(), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ history::SOURCE_BROWSED);
}
EXPECT_THAT(backend_->TopHosts(3),
@@ -3035,8 +3040,12 @@ TEST_F(HistoryBackendTest, TopHosts_ElidePortAndScheme) {
urls.push_back(GURL("https://cnn.com/intl"));
urls.push_back(GURL("http://cnn.com:567/sports"));
for (const GURL& url : urls) {
- backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
- history::SOURCE_BROWSED);
+ backend_->AddPageVisit(
+ url, base::Time::Now(), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ history::SOURCE_BROWSED);
}
EXPECT_THAT(backend_->TopHosts(3), ElementsAre(std::make_pair("cnn.com", 3)));
@@ -3048,8 +3057,12 @@ TEST_F(HistoryBackendTest, TopHosts_ElideWWW) {
urls.push_back(GURL("http://cnn.com/intl"));
urls.push_back(GURL("http://www.dogtopia.com/"));
for (const GURL& url : urls) {
- backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
- history::SOURCE_BROWSED);
+ backend_->AddPageVisit(
+ url, base::Time::Now(), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ history::SOURCE_BROWSED);
}
EXPECT_THAT(backend_->TopHosts(3),
@@ -3063,12 +3076,20 @@ TEST_F(HistoryBackendTest, TopHosts_OnlyLast30Days) {
urls.push_back(GURL("http://cnn.com/intl"));
urls.push_back(GURL("http://dogtopia.com/"));
for (const GURL& url : urls) {
- backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
- history::SOURCE_BROWSED);
+ backend_->AddPageVisit(
+ url, base::Time::Now(), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ history::SOURCE_BROWSED);
}
- backend_->AddPageVisit(GURL("http://www.oracle.com/"),
- base::Time::Now() - base::TimeDelta::FromDays(31), 0,
- ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED);
+ backend_->AddPageVisit(
+ GURL("http://www.oracle.com/"),
+ base::Time::Now() - base::TimeDelta::FromDays(31), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ history::SOURCE_BROWSED);
EXPECT_THAT(backend_->TopHosts(3),
ElementsAre(std::make_pair("cnn.com", 2),
@@ -3084,8 +3105,12 @@ TEST_F(HistoryBackendTest, TopHosts_MaxNumHosts) {
urls.push_back(GURL("http://dogtopia.com/webcam"));
urls.push_back(GURL("http://www.gardenweb.com/"));
for (const GURL& url : urls) {
- backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
- history::SOURCE_BROWSED);
+ backend_->AddPageVisit(
+ url, base::Time::Now(), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ history::SOURCE_BROWSED);
}
EXPECT_THAT(backend_->TopHosts(2),
@@ -3105,21 +3130,42 @@ TEST_F(HistoryBackendTest, TopHosts_IgnoreUnusualURLs) {
urls.push_back(GURL("chrome://version"));
urls.push_back(GURL("about:mammon"));
for (const GURL& url : urls) {
- backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
- history::SOURCE_BROWSED);
+ backend_->AddPageVisit(
+ url, base::Time::Now(), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ history::SOURCE_BROWSED);
}
EXPECT_THAT(backend_->TopHosts(5), ElementsAre(std::make_pair("cnn.com", 3)));
}
+TEST_F(HistoryBackendTest, TopHosts_IgnoreRedirects) {
+ const char* redirect1[] = {"http://foo.com/page1.html",
+ "http://mobile.foo.com/page1.html", NULL};
+ const char* redirect2[] = {"http://bar.com/page1.html",
+ "https://bar.com/page1.html",
+ "https://mobile.bar.com/page1.html", NULL};
+ AddRedirectChain(redirect1, 0);
+ AddRedirectChain(redirect2, 1);
+ EXPECT_THAT(backend_->TopHosts(5),
+ ElementsAre(std::make_pair("mobile.bar.com", 1),
+ std::make_pair("mobile.foo.com", 1)));
+}
+
TEST_F(HistoryBackendTest, HostRankIfAvailable) {
std::vector<GURL> urls;
urls.push_back(GURL("http://cnn.com/us"));
urls.push_back(GURL("http://cnn.com/intl"));
urls.push_back(GURL("http://dogtopia.com/"));
for (const GURL& url : urls) {
- backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
- history::SOURCE_BROWSED);
+ backend_->AddPageVisit(
+ url, base::Time::Now(), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ history::SOURCE_BROWSED);
}
EXPECT_EQ(kMaxTopHosts,
@@ -3142,8 +3188,12 @@ TEST_F(HistoryBackendTest, RecordTopHostsMetrics) {
urls.push_back(GURL("http://cnn.com/intl"));
urls.push_back(GURL("http://dogtopia.com/"));
for (const GURL& url : urls) {
- backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
- history::SOURCE_BROWSED);
+ backend_->AddPageVisit(
+ url, base::Time::Now(), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ history::SOURCE_BROWSED);
}
// Compute host_ranks_ for RecordTopHostsMetrics.
@@ -3506,8 +3556,8 @@ TEST_F(HistoryBackendTest, RemoveNotification) {
std::unique_ptr<HistoryService> service(
new HistoryService(base::WrapUnique(new HistoryClientFakeBookmarks),
std::unique_ptr<history::VisitDelegate>()));
- EXPECT_TRUE(
- service->Init(TestHistoryDatabaseParamsForPath(scoped_temp_dir.path())));
+ EXPECT_TRUE(service->Init(
+ TestHistoryDatabaseParamsForPath(scoped_temp_dir.GetPath())));
service->AddPage(
url, base::Time::Now(), NULL, 1, GURL(), RedirectList(),
@@ -3756,4 +3806,34 @@ TEST_F(InMemoryHistoryBackendTest, OnURLsDeletedWithSearchTerms) {
EXPECT_FALSE(mem_backend_->db()->GetKeywordSearchTermRow(row2.id(), NULL));
}
+TEST_F(HistoryBackendTest, QueryMostVisitedURLs) {
+ ASSERT_TRUE(backend_.get());
+
+ // Pairs from page transitions to consider_for_ntp_most_visited.
+ std::vector<std::pair<ui::PageTransition, bool>> pages;
+ pages.emplace_back(ui::PAGE_TRANSITION_AUTO_BOOKMARK, true); // good.
+ pages.emplace_back(ui::PAGE_TRANSITION_AUTO_BOOKMARK, false); // bad.
+ pages.emplace_back(ui::PAGE_TRANSITION_LINK, true); // bad.
+ pages.emplace_back(ui::PAGE_TRANSITION_TYPED, false); // bad.
+ pages.emplace_back(ui::PAGE_TRANSITION_TYPED, true); // good.
+
+ for (size_t i = 0; i < pages.size(); ++i) {
+ HistoryAddPageArgs args;
+ args.url = GURL("http://example" + base::SizeTToString(i + 1) + ".com");
+ args.time = base::Time::Now() - base::TimeDelta::FromDays(i + 1);
+ args.transition = pages[i].first;
+ args.consider_for_ntp_most_visited = pages[i].second;
+ backend_->AddPage(args);
+ }
+
+ MostVisitedURLList most_visited;
+ backend_->QueryMostVisitedURLs(100, 100, &most_visited);
+
+ const base::string16 kSomeTitle; // Ignored by equality operator.
+ EXPECT_THAT(
+ most_visited,
+ ElementsAre(MostVisitedURL(GURL("http://example1.com"), kSomeTitle),
+ MostVisitedURL(GURL("http://example5.com"), kSomeTitle)));
+}
+
} // namespace history
diff --git a/chromium/components/history/core/browser/history_client.h b/chromium/components/history/core/browser/history_client.h
index d4dc3cf5903..4d6b7e522b9 100644
--- a/chromium/components/history/core/browser/history_client.h
+++ b/chromium/components/history/core/browser/history_client.h
@@ -42,7 +42,8 @@ class HistoryClient {
virtual bool CanAddURL(const GURL& url) = 0;
// Notifies the embedder that there was a problem reading the database.
- virtual void NotifyProfileError(sql::InitStatus init_status) = 0;
+ virtual void NotifyProfileError(sql::InitStatus init_status,
+ const std::string& diagnostics) = 0;
// Returns a new HistoryBackendClient instance.
virtual std::unique_ptr<HistoryBackendClient> CreateBackendClient() = 0;
diff --git a/chromium/components/history/core/browser/history_database.cc b/chromium/components/history/core/browser/history_database.cc
index a11edafc146..9810c5c1c94 100644
--- a/chromium/components/history/core/browser/history_database.cc
+++ b/chromium/components/history/core/browser/history_database.cc
@@ -15,7 +15,7 @@
#include "base/command_line.h"
#include "base/containers/hash_tables.h"
#include "base/files/file_util.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/rand_util.h"
#include "base/strings/string_util.h"
@@ -56,9 +56,6 @@ HistoryDatabase::~HistoryDatabase() {
sql::InitStatus HistoryDatabase::Init(const base::FilePath& history_name) {
db_.set_histogram_tag("History");
- // Set the exceptional sqlite error handler.
- db_.set_error_callback(error_callback_);
-
// Set the database page size to something a little larger to give us
// better performance (we're typically seek rather than bandwidth limited).
// This only has an effect before any tables have been created, otherwise
@@ -201,8 +198,19 @@ TopHostsList HistoryDatabase::TopHosts(size_t num_hosts) {
std::max(base::Time::Now() - base::TimeDelta::FromDays(30), base::Time());
sql::Statement url_sql(db_.GetUniqueStatement(
- "SELECT url, visit_count FROM urls WHERE last_visit_time > ?"));
+ "SELECT u.url, u.visit_count "
+ "FROM urls u JOIN visits v ON u.id = v.url "
+ "WHERE last_visit_time > ? "
+ "AND (v.transition & ?) != 0 " // CHAIN_END
+ "AND (transition & ?) NOT IN (?, ?, ?)")); // NO SUBFRAME or
+ // KEYWORD_GENERATED
+
url_sql.BindInt64(0, one_month_ago.ToInternalValue());
+ url_sql.BindInt(1, ui::PAGE_TRANSITION_CHAIN_END);
+ url_sql.BindInt(2, ui::PAGE_TRANSITION_CORE_MASK);
+ url_sql.BindInt(3, ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+ url_sql.BindInt(4, ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
+ url_sql.BindInt(5, ui::PAGE_TRANSITION_KEYWORD_GENERATED);
// Collect a map from host to visit count.
base::hash_map<std::string, int> host_count;
@@ -259,7 +267,13 @@ void HistoryDatabase::CommitTransaction() {
}
void HistoryDatabase::RollbackTransaction() {
- db_.RollbackTransaction();
+ // If Init() returns with a failure status, the Transaction created there will
+ // be destructed and rolled back. HistoryBackend might try to kill the
+ // database after that, at which point it will try to roll back a non-existing
+ // transaction. This will crash on a DCHECK. So transaction_nesting() is
+ // checked first.
+ if (db_.transaction_nesting())
+ db_.RollbackTransaction();
}
bool HistoryDatabase::RecreateAllTablesButURL() {
@@ -296,6 +310,11 @@ bool HistoryDatabase::Raze() {
return db_.Raze();
}
+std::string HistoryDatabase::GetDiagnosticInfo(int extended_error,
+ sql::Statement* statement) {
+ return db_.GetDiagnosticInfo(extended_error, statement);
+}
+
bool HistoryDatabase::SetSegmentID(VisitID visit_id, SegmentID segment_id) {
sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
"UPDATE visits SET segment_id = ? WHERE id = ?"));
diff --git a/chromium/components/history/core/browser/history_database.h b/chromium/components/history/core/browser/history_database.h
index cf6b1c048cc..0eb74a571af 100644
--- a/chromium/components/history/core/browser/history_database.h
+++ b/chromium/components/history/core/browser/history_database.h
@@ -75,7 +75,7 @@ class HistoryDatabase : public DownloadDatabase,
// underlying database connection.
void set_error_callback(
const sql::Connection::ErrorCallback& error_callback) {
- error_callback_ = error_callback;
+ db_.set_error_callback(error_callback);
}
// Must call this function to complete initialization. Will return
@@ -145,6 +145,8 @@ class HistoryDatabase : public DownloadDatabase,
// Razes the database. Returns true if successful.
bool Raze();
+ std::string GetDiagnosticInfo(int extended_error, sql::Statement* statement);
+
// Visit table functions ----------------------------------------------------
// Update the segment id of a visit. Return true on success.
@@ -190,7 +192,6 @@ class HistoryDatabase : public DownloadDatabase,
// ---------------------------------------------------------------------------
- sql::Connection::ErrorCallback error_callback_;
sql::Connection db_;
sql::MetaTable meta_table_;
diff --git a/chromium/components/history/core/browser/history_database_unittest.cc b/chromium/components/history/core/browser/history_database_unittest.cc
index 3f90bf860b0..d2292786bee 100644
--- a/chromium/components/history/core/browser/history_database_unittest.cc
+++ b/chromium/components/history/core/browser/history_database_unittest.cc
@@ -20,7 +20,7 @@ TEST(HistoryDatabaseTest, DropBookmarks) {
base::FilePath db_file;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- db_file = temp_dir.path().AppendASCII("DropBookmarks.db");
+ db_file = temp_dir.GetPath().AppendASCII("DropBookmarks.db");
sql::Connection::Delete(db_file);
// Copy db file over that contains starred URLs.
diff --git a/chromium/components/history/core/browser/history_delete_directives_data_type_controller.cc b/chromium/components/history/core/browser/history_delete_directives_data_type_controller.cc
index a2f7f1ec199..f067ab9a636 100644
--- a/chromium/components/history/core/browser/history_delete_directives_data_type_controller.cc
+++ b/chromium/components/history/core/browser/history_delete_directives_data_type_controller.cc
@@ -4,20 +4,17 @@
#include "components/history/core/browser/history_delete_directives_data_type_controller.h"
-#include "components/sync_driver/sync_client.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_client.h"
+#include "components/sync/driver/sync_service.h"
namespace browser_sync {
HistoryDeleteDirectivesDataTypeController::
- HistoryDeleteDirectivesDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client)
- : sync_driver::UIDataTypeController(ui_thread,
- error_callback,
- syncer::HISTORY_DELETE_DIRECTIVES,
- sync_client),
+ HistoryDeleteDirectivesDataTypeController(const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client)
+ : syncer::UIDataTypeController(syncer::HISTORY_DELETE_DIRECTIVES,
+ dump_stack,
+ sync_client),
sync_client_(sync_client) {}
HistoryDeleteDirectivesDataTypeController::
@@ -25,10 +22,12 @@ HistoryDeleteDirectivesDataTypeController::
}
bool HistoryDeleteDirectivesDataTypeController::ReadyForStart() const {
+ DCHECK(CalledOnValidThread());
return !sync_client_->GetSyncService()->IsEncryptEverythingEnabled();
}
bool HistoryDeleteDirectivesDataTypeController::StartModels() {
+ DCHECK(CalledOnValidThread());
if (DisableTypeIfNecessary())
return false;
sync_client_->GetSyncService()->AddObserver(this);
@@ -36,6 +35,7 @@ bool HistoryDeleteDirectivesDataTypeController::StartModels() {
}
void HistoryDeleteDirectivesDataTypeController::StopModels() {
+ DCHECK(CalledOnValidThread());
if (sync_client_->GetSyncService()->HasObserver(this))
sync_client_->GetSyncService()->RemoveObserver(this);
}
@@ -45,6 +45,7 @@ void HistoryDeleteDirectivesDataTypeController::OnStateChanged() {
}
bool HistoryDeleteDirectivesDataTypeController::DisableTypeIfNecessary() {
+ DCHECK(CalledOnValidThread());
if (!sync_client_->GetSyncService()->IsSyncActive())
return false;
@@ -58,7 +59,7 @@ bool HistoryDeleteDirectivesDataTypeController::DisableTypeIfNecessary() {
syncer::SyncError::DATATYPE_POLICY_ERROR,
"Delete directives not supported with encryption.",
type());
- OnSingleDataTypeUnrecoverableError(error);
+ CreateErrorHandler()->OnUnrecoverableError(error);
return true;
}
diff --git a/chromium/components/history/core/browser/history_delete_directives_data_type_controller.h b/chromium/components/history/core/browser/history_delete_directives_data_type_controller.h
index 0e79187eafc..07016e763b6 100644
--- a/chromium/components/history/core/browser/history_delete_directives_data_type_controller.h
+++ b/chromium/components/history/core/browser/history_delete_directives_data_type_controller.h
@@ -6,40 +6,37 @@
#define COMPONENTS_HISTORY_CORE_BROWSER_HISTORY_DELETE_DIRECTIVES_DATA_TYPE_CONTROLLER_H_
#include "base/macros.h"
-#include "components/sync_driver/local_device_info_provider.h"
-#include "components/sync_driver/sync_service_observer.h"
-#include "components/sync_driver/ui_data_type_controller.h"
+#include "components/sync/device_info/local_device_info_provider.h"
+#include "components/sync/driver/sync_service_observer.h"
+#include "components/sync/driver/ui_data_type_controller.h"
namespace browser_sync {
// A controller for delete directives, which cannot sync when full encryption
// is enabled.
class HistoryDeleteDirectivesDataTypeController
- : public sync_driver::UIDataTypeController,
- public sync_driver::SyncServiceObserver {
+ : public syncer::UIDataTypeController,
+ public syncer::SyncServiceObserver {
public:
- HistoryDeleteDirectivesDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client);
+ // |dump_stack| is called when an unrecoverable error occurs.
+ HistoryDeleteDirectivesDataTypeController(const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client);
+ ~HistoryDeleteDirectivesDataTypeController() override;
// UIDataTypeController override.
bool ReadyForStart() const override;
bool StartModels() override;
void StopModels() override;
- // sync_driver::SyncServiceObserver implementation.
+ // syncer::SyncServiceObserver implementation.
void OnStateChanged() override;
private:
- // Refcounted.
- ~HistoryDeleteDirectivesDataTypeController() override;
-
// Triggers a SingleDataTypeUnrecoverable error and returns true if the
// type is no longer ready, else does nothing and returns false.
bool DisableTypeIfNecessary();
- sync_driver::SyncClient* sync_client_;
+ syncer::SyncClient* sync_client_;
DISALLOW_COPY_AND_ASSIGN(HistoryDeleteDirectivesDataTypeController);
};
diff --git a/chromium/components/history/core/browser/history_model_worker.h b/chromium/components/history/core/browser/history_model_worker.h
index 17b1b63bca2..1900a0fc57a 100644
--- a/chromium/components/history/core/browser/history_model_worker.h
+++ b/chromium/components/history/core/browser/history_model_worker.h
@@ -13,7 +13,7 @@
#include "base/task/cancelable_task_tracker.h"
#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/browser/history_service.h"
-#include "sync/internal_api/public/engine/model_safe_worker.h"
+#include "components/sync/engine/model_safe_worker.h"
namespace history {
class HistoryService;
diff --git a/chromium/components/history/core/browser/history_querying_unittest.cc b/chromium/components/history/core/browser/history_querying_unittest.cc
index b192f197975..2e8fbb3c431 100644
--- a/chromium/components/history/core/browser/history_querying_unittest.cc
+++ b/chromium/components/history/core/browser/history_querying_unittest.cc
@@ -162,7 +162,7 @@ class HistoryQueryTest : public testing::Test {
private:
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- history_dir_ = temp_dir_.path().AppendASCII("HistoryTest");
+ history_dir_ = temp_dir_.GetPath().AppendASCII("HistoryTest");
ASSERT_TRUE(base::CreateDirectory(history_dir_));
history_.reset(new HistoryService);
diff --git a/chromium/components/history/core/browser/history_service.cc b/chromium/components/history/core/browser/history_service.cc
index c7f0e7fb79f..5e62f478970 100644
--- a/chromium/components/history/core/browser/history_service.cc
+++ b/chromium/components/history/core/browser/history_service.cc
@@ -48,7 +48,7 @@
#include "components/history/core/browser/visit_delegate.h"
#include "components/history/core/browser/web_history_service.h"
#include "components/history/core/common/thumbnail_score.h"
-#include "sync/api/sync_error_factory.h"
+#include "components/sync/api/sync_error_factory.h"
#include "third_party/skia/include/core/SkBitmap.h"
#if defined(OS_IOS)
@@ -65,6 +65,7 @@ static const char* kHistoryThreadName = "Chrome_HistoryThread";
void RunWithFaviconResults(
const favicon_base::FaviconResultsCallback& callback,
std::vector<favicon_base::FaviconRawBitmapResult>* bitmap_results) {
+ TRACE_EVENT0("browser", "RunWithFaviconResults");
callback.Run(*bitmap_results);
}
@@ -107,11 +108,12 @@ class HistoryService::BackendDelegate : public HistoryBackend::Delegate {
: history_service_(history_service),
service_task_runner_(service_task_runner) {}
- void NotifyProfileError(sql::InitStatus init_status) override {
+ void NotifyProfileError(sql::InitStatus init_status,
+ const std::string& diagnostics) override {
// Send to the history service on the main thread.
service_task_runner_->PostTask(
FROM_HERE, base::Bind(&HistoryService::NotifyProfileError,
- history_service_, init_status));
+ history_service_, init_status, diagnostics));
}
void SetInMemoryBackend(
@@ -225,7 +227,7 @@ void HistoryService::ClearCachedDataForContextID(ContextID context_id) {
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_NORMAL,
base::Bind(&HistoryBackend::ClearCachedDataForContextID,
- history_backend_.get(), context_id));
+ history_backend_, context_id));
}
URLDatabase* HistoryService::InMemoryDatabase() {
@@ -249,7 +251,7 @@ void HistoryService::SetKeywordSearchTermsForURL(const GURL& url,
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_UI,
base::Bind(&HistoryBackend::SetKeywordSearchTermsForURL,
- history_backend_.get(), url, keyword_id, term));
+ history_backend_, url, keyword_id, term));
}
void HistoryService::DeleteAllSearchTermsForKeyword(KeywordID keyword_id) {
@@ -261,7 +263,7 @@ void HistoryService::DeleteAllSearchTermsForKeyword(KeywordID keyword_id) {
ScheduleTask(PRIORITY_UI,
base::Bind(&HistoryBackend::DeleteAllSearchTermsForKeyword,
- history_backend_.get(), keyword_id));
+ history_backend_, keyword_id));
}
void HistoryService::DeleteKeywordSearchTermForURL(const GURL& url) {
@@ -269,7 +271,7 @@ void HistoryService::DeleteKeywordSearchTermForURL(const GURL& url) {
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_UI,
base::Bind(&HistoryBackend::DeleteKeywordSearchTermForURL,
- history_backend_.get(), url));
+ history_backend_, url));
}
void HistoryService::DeleteMatchingURLsForKeyword(KeywordID keyword_id,
@@ -278,7 +280,7 @@ void HistoryService::DeleteMatchingURLsForKeyword(KeywordID keyword_id,
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_UI,
base::Bind(&HistoryBackend::DeleteMatchingURLsForKeyword,
- history_backend_.get(), keyword_id, term));
+ history_backend_, keyword_id, term));
}
void HistoryService::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
@@ -286,7 +288,7 @@ void HistoryService::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_NORMAL,
base::Bind(&HistoryBackend::URLsNoLongerBookmarked,
- history_backend_.get(), urls));
+ history_backend_, urls));
}
void HistoryService::AddObserver(HistoryServiceObserver* observer) {
@@ -307,12 +309,12 @@ base::CancelableTaskTracker::TaskId HistoryService::ScheduleDBTask(
base::CancelableTaskTracker::IsCanceledCallback is_canceled;
base::CancelableTaskTracker::TaskId task_id =
tracker->NewTrackedTaskId(&is_canceled);
- // Use base::ThreadTaskRunnerHandler::Get() to get a message loop proxy to
+ // Use base::ThreadTaskRunnerHandler::Get() to get a task runner for
// the current message loop so that we can forward the call to the method
// HistoryDBTask::DoneRunOnMainThread() in the correct thread.
thread_->task_runner()->PostTask(
FROM_HERE, base::Bind(&HistoryBackend::ProcessDBTask,
- history_backend_.get(), base::Passed(&task),
+ history_backend_, base::Passed(&task),
base::ThreadTaskRunnerHandle::Get(), is_canceled));
return task_id;
}
@@ -328,7 +330,7 @@ void HistoryService::SetOnBackendDestroyTask(const base::Closure& task) {
ScheduleTask(
PRIORITY_NORMAL,
base::Bind(&HistoryBackend::SetOnBackendDestroyTask,
- history_backend_.get(), base::MessageLoop::current(), task));
+ history_backend_, base::MessageLoop::current(), task));
}
void HistoryService::TopHosts(size_t num_hosts,
@@ -337,7 +339,7 @@ void HistoryService::TopHosts(size_t num_hosts,
DCHECK(thread_checker_.CalledOnValidThread());
PostTaskAndReplyWithResult(
thread_->task_runner().get(), FROM_HERE,
- base::Bind(&HistoryBackend::TopHosts, history_backend_.get(), num_hosts),
+ base::Bind(&HistoryBackend::TopHosts, history_backend_, num_hosts),
callback);
}
@@ -349,7 +351,7 @@ void HistoryService::GetCountsAndLastVisitForOrigins(
PostTaskAndReplyWithResult(
thread_->task_runner().get(), FROM_HERE,
base::Bind(&HistoryBackend::GetCountsAndLastVisitForOrigins,
- history_backend_.get(), origins),
+ history_backend_, origins),
callback);
}
@@ -360,7 +362,7 @@ void HistoryService::HostRankIfAvailable(
DCHECK(thread_checker_.CalledOnValidThread());
PostTaskAndReplyWithResult(thread_->task_runner().get(), FROM_HERE,
base::Bind(&HistoryBackend::HostRankIfAvailable,
- history_backend_.get(), url),
+ history_backend_, url),
callback);
}
@@ -376,7 +378,7 @@ void HistoryService::AddPage(const GURL& url,
DCHECK(thread_checker_.CalledOnValidThread());
AddPage(HistoryAddPageArgs(url, time, context_id, nav_entry_id, referrer,
redirects, transition, visit_source,
- did_replace_entry));
+ did_replace_entry, true));
}
void HistoryService::AddPage(const GURL& url,
@@ -384,7 +386,8 @@ void HistoryService::AddPage(const GURL& url,
VisitSource visit_source) {
DCHECK(thread_checker_.CalledOnValidThread());
AddPage(HistoryAddPageArgs(url, time, nullptr, 0, GURL(), RedirectList(),
- ui::PAGE_TRANSITION_LINK, visit_source, false));
+ ui::PAGE_TRANSITION_LINK, visit_source, false,
+ true));
}
void HistoryService::AddPage(const HistoryAddPageArgs& add_page_args) {
@@ -413,7 +416,7 @@ void HistoryService::AddPage(const HistoryAddPageArgs& add_page_args) {
}
ScheduleTask(PRIORITY_NORMAL,
- base::Bind(&HistoryBackend::AddPage, history_backend_.get(),
+ base::Bind(&HistoryBackend::AddPage, history_backend_,
add_page_args));
}
@@ -426,7 +429,7 @@ void HistoryService::AddPageNoVisitForBookmark(const GURL& url,
ScheduleTask(PRIORITY_NORMAL,
base::Bind(&HistoryBackend::AddPageNoVisitForBookmark,
- history_backend_.get(), url, title));
+ history_backend_, url, title));
}
void HistoryService::SetPageTitle(const GURL& url,
@@ -434,7 +437,7 @@ void HistoryService::SetPageTitle(const GURL& url,
DCHECK(thread_) << "History service being called after cleanup";
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_NORMAL, base::Bind(&HistoryBackend::SetPageTitle,
- history_backend_.get(), url, title));
+ history_backend_, url, title));
}
void HistoryService::UpdateWithPageEndTime(ContextID context_id,
@@ -445,7 +448,7 @@ void HistoryService::UpdateWithPageEndTime(ContextID context_id,
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(
PRIORITY_NORMAL,
- base::Bind(&HistoryBackend::UpdateWithPageEndTime, history_backend_.get(),
+ base::Bind(&HistoryBackend::UpdateWithPageEndTime, history_backend_,
context_id, nav_entry_id, url, end_ts));
}
@@ -478,7 +481,7 @@ void HistoryService::AddPageWithDetails(const GURL& url,
ScheduleTask(PRIORITY_NORMAL,
base::Bind(&HistoryBackend::AddPagesWithDetails,
- history_backend_.get(), rows, visit_source));
+ history_backend_, rows, visit_source));
}
void HistoryService::AddPagesWithDetails(const URLRows& info,
@@ -497,7 +500,7 @@ void HistoryService::AddPagesWithDetails(const URLRows& info,
ScheduleTask(PRIORITY_NORMAL,
base::Bind(&HistoryBackend::AddPagesWithDetails,
- history_backend_.get(), info, visit_source));
+ history_backend_, info, visit_source));
}
base::CancelableTaskTracker::TaskId HistoryService::GetFavicons(
@@ -506,13 +509,14 @@ base::CancelableTaskTracker::TaskId HistoryService::GetFavicons(
const std::vector<int>& desired_sizes,
const favicon_base::FaviconResultsCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "HistoryService::GetFavicons");
DCHECK(thread_) << "History service being called after cleanup";
DCHECK(thread_checker_.CalledOnValidThread());
std::vector<favicon_base::FaviconRawBitmapResult>* results =
new std::vector<favicon_base::FaviconRawBitmapResult>();
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
- base::Bind(&HistoryBackend::GetFavicons, history_backend_.get(),
+ base::Bind(&HistoryBackend::GetFavicons, history_backend_,
icon_urls, icon_types, desired_sizes, results),
base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
}
@@ -523,13 +527,14 @@ base::CancelableTaskTracker::TaskId HistoryService::GetFaviconsForURL(
const std::vector<int>& desired_sizes,
const favicon_base::FaviconResultsCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "HistoryService::GetFaviconsForURL");
DCHECK(thread_) << "History service being called after cleanup";
DCHECK(thread_checker_.CalledOnValidThread());
std::vector<favicon_base::FaviconRawBitmapResult>* results =
new std::vector<favicon_base::FaviconRawBitmapResult>();
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
- base::Bind(&HistoryBackend::GetFaviconsForURL, history_backend_.get(),
+ base::Bind(&HistoryBackend::GetFaviconsForURL, history_backend_,
page_url, icon_types, desired_sizes, results),
base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
}
@@ -547,7 +552,7 @@ base::CancelableTaskTracker::TaskId HistoryService::GetLargestFaviconForURL(
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
base::Bind(&HistoryBackend::GetLargestFaviconForURL,
- history_backend_.get(), page_url, icon_types,
+ history_backend_, page_url, icon_types,
minimum_size_in_pixels, result),
base::Bind(&RunWithFaviconResult, callback, base::Owned(result)));
}
@@ -557,13 +562,14 @@ base::CancelableTaskTracker::TaskId HistoryService::GetFaviconForID(
int desired_size,
const favicon_base::FaviconResultsCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "HistoryService::GetFaviconForID");
DCHECK(thread_) << "History service being called after cleanup";
DCHECK(thread_checker_.CalledOnValidThread());
std::vector<favicon_base::FaviconRawBitmapResult>* results =
new std::vector<favicon_base::FaviconRawBitmapResult>();
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
- base::Bind(&HistoryBackend::GetFaviconForID, history_backend_.get(),
+ base::Bind(&HistoryBackend::GetFaviconForID, history_backend_,
favicon_id, desired_size, results),
base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
}
@@ -576,6 +582,7 @@ HistoryService::UpdateFaviconMappingsAndFetch(
const std::vector<int>& desired_sizes,
const favicon_base::FaviconResultsCallback& callback,
base::CancelableTaskTracker* tracker) {
+ TRACE_EVENT0("browser", "HistoryService::UpdateFaviconMappingsAndFetch");
DCHECK(thread_) << "History service being called after cleanup";
DCHECK(thread_checker_.CalledOnValidThread());
std::vector<favicon_base::FaviconRawBitmapResult>* results =
@@ -583,7 +590,7 @@ HistoryService::UpdateFaviconMappingsAndFetch(
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
base::Bind(&HistoryBackend::UpdateFaviconMappingsAndFetch,
- history_backend_.get(), page_url, icon_urls, icon_types,
+ history_backend_, page_url, icon_urls, icon_types,
desired_sizes, results),
base::Bind(&RunWithFaviconResults, callback, base::Owned(results)));
}
@@ -594,6 +601,7 @@ void HistoryService::MergeFavicon(
favicon_base::IconType icon_type,
scoped_refptr<base::RefCountedMemory> bitmap_data,
const gfx::Size& pixel_size) {
+ TRACE_EVENT0("browser", "HistoryService::MergeFavicon");
DCHECK(thread_) << "History service being called after cleanup";
DCHECK(thread_checker_.CalledOnValidThread());
if (history_client_ && !history_client_->CanAddURL(page_url))
@@ -601,7 +609,7 @@ void HistoryService::MergeFavicon(
ScheduleTask(
PRIORITY_NORMAL,
- base::Bind(&HistoryBackend::MergeFavicon, history_backend_.get(),
+ base::Bind(&HistoryBackend::MergeFavicon, history_backend_,
page_url, icon_url, icon_type, bitmap_data, pixel_size));
}
@@ -615,7 +623,7 @@ void HistoryService::SetFavicons(const GURL& page_url,
return;
ScheduleTask(PRIORITY_NORMAL,
- base::Bind(&HistoryBackend::SetFavicons, history_backend_.get(),
+ base::Bind(&HistoryBackend::SetFavicons, history_backend_,
page_url, icon_type, icon_url, bitmaps));
}
@@ -624,7 +632,7 @@ void HistoryService::SetFaviconsOutOfDateForPage(const GURL& page_url) {
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_NORMAL,
base::Bind(&HistoryBackend::SetFaviconsOutOfDateForPage,
- history_backend_.get(), page_url));
+ history_backend_, page_url));
}
void HistoryService::SetImportedFavicons(
@@ -633,7 +641,7 @@ void HistoryService::SetImportedFavicons(
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_NORMAL,
base::Bind(&HistoryBackend::SetImportedFavicons,
- history_backend_.get(), favicon_usage));
+ history_backend_, favicon_usage));
}
base::CancelableTaskTracker::TaskId HistoryService::QueryURL(
@@ -646,7 +654,7 @@ base::CancelableTaskTracker::TaskId HistoryService::QueryURL(
QueryURLResult* query_url_result = new QueryURLResult();
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
- base::Bind(&HistoryBackend::QueryURL, history_backend_.get(), url,
+ base::Bind(&HistoryBackend::QueryURL, history_backend_, url,
want_visits, base::Unretained(query_url_result)),
base::Bind(&RunWithQueryURLResult, callback,
base::Owned(query_url_result)));
@@ -665,7 +673,7 @@ base::CancelableTaskTracker::TaskId HistoryService::GetHistoryCount(
return tracker->PostTaskAndReplyWithResult(
thread_->task_runner().get(), FROM_HERE,
base::Bind(&HistoryBackend::GetHistoryCount,
- history_backend_.get(),
+ history_backend_,
begin_time,
end_time),
callback);
@@ -682,7 +690,7 @@ void HistoryService::CreateDownload(
DCHECK(thread_checker_.CalledOnValidThread());
PostTaskAndReplyWithResult(thread_->task_runner().get(), FROM_HERE,
base::Bind(&HistoryBackend::CreateDownload,
- history_backend_.get(), create_info),
+ history_backend_, create_info),
callback);
}
@@ -691,7 +699,7 @@ void HistoryService::GetNextDownloadId(const DownloadIdCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
PostTaskAndReplyWithResult(
thread_->task_runner().get(), FROM_HERE,
- base::Bind(&HistoryBackend::GetNextDownloadId, history_backend_.get()),
+ base::Bind(&HistoryBackend::GetNextDownloadId, history_backend_),
callback);
}
@@ -708,7 +716,7 @@ void HistoryService::QueryDownloads(const DownloadQueryCallback& callback) {
// Bind's arguments.
thread_->task_runner()->PostTaskAndReply(
FROM_HERE,
- base::Bind(&HistoryBackend::QueryDownloads, history_backend_.get(), rows),
+ base::Bind(&HistoryBackend::QueryDownloads, history_backend_, rows),
base::Bind(callback, base::Passed(&scoped_rows)));
}
@@ -718,14 +726,14 @@ void HistoryService::UpdateDownload(const DownloadRow& data) {
DCHECK(thread_) << "History service being called after cleanup";
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_NORMAL, base::Bind(&HistoryBackend::UpdateDownload,
- history_backend_.get(), data));
+ history_backend_, data));
}
void HistoryService::RemoveDownloads(const std::set<uint32_t>& ids) {
DCHECK(thread_) << "History service being called after cleanup";
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_NORMAL, base::Bind(&HistoryBackend::RemoveDownloads,
- history_backend_.get(), ids));
+ history_backend_, ids));
}
base::CancelableTaskTracker::TaskId HistoryService::QueryHistory(
@@ -738,7 +746,7 @@ base::CancelableTaskTracker::TaskId HistoryService::QueryHistory(
QueryResults* query_results = new QueryResults();
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
- base::Bind(&HistoryBackend::QueryHistory, history_backend_.get(),
+ base::Bind(&HistoryBackend::QueryHistory, history_backend_,
text_query, options, base::Unretained(query_results)),
base::Bind(callback, base::Owned(query_results)));
}
@@ -752,7 +760,7 @@ base::CancelableTaskTracker::TaskId HistoryService::QueryRedirectsFrom(
RedirectList* result = new RedirectList();
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
- base::Bind(&HistoryBackend::QueryRedirectsFrom, history_backend_.get(),
+ base::Bind(&HistoryBackend::QueryRedirectsFrom, history_backend_,
from_url, base::Unretained(result)),
base::Bind(callback, base::Owned(result)));
}
@@ -766,7 +774,7 @@ base::CancelableTaskTracker::TaskId HistoryService::QueryRedirectsTo(
RedirectList* result = new RedirectList();
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
- base::Bind(&HistoryBackend::QueryRedirectsTo, history_backend_.get(),
+ base::Bind(&HistoryBackend::QueryRedirectsTo, history_backend_,
to_url, base::Unretained(result)),
base::Bind(callback, base::Owned(result)));
}
@@ -781,7 +789,7 @@ base::CancelableTaskTracker::TaskId HistoryService::GetVisibleVisitCountToHost(
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
base::Bind(&HistoryBackend::GetVisibleVisitCountToHost,
- history_backend_.get(), url, base::Unretained(result)),
+ history_backend_, url, base::Unretained(result)),
base::Bind(&RunWithVisibleVisitCountToHostResult, callback,
base::Owned(result)));
}
@@ -796,7 +804,7 @@ base::CancelableTaskTracker::TaskId HistoryService::QueryMostVisitedURLs(
MostVisitedURLList* result = new MostVisitedURLList();
return tracker->PostTaskAndReply(
thread_->task_runner().get(), FROM_HERE,
- base::Bind(&HistoryBackend::QueryMostVisitedURLs, history_backend_.get(),
+ base::Bind(&HistoryBackend::QueryMostVisitedURLs, history_backend_,
result_count, days_back, base::Unretained(result)),
base::Bind(callback, base::Owned(result)));
}
@@ -843,7 +851,7 @@ void HistoryService::Cleanup() {
// See http://crbug.com/99767.
history_backend_->AddRef();
base::Closure closing_task =
- base::Bind(&HistoryBackend::Closing, history_backend_.get());
+ base::Bind(&HistoryBackend::Closing, history_backend_);
ScheduleTask(PRIORITY_NORMAL, closing_task);
closing_task.Reset();
HistoryBackend* raw_ptr = history_backend_.get();
@@ -883,7 +891,7 @@ bool HistoryService::Init(
history_backend_.swap(backend);
ScheduleTask(PRIORITY_UI,
- base::Bind(&HistoryBackend::Init, history_backend_.get(),
+ base::Bind(&HistoryBackend::Init, history_backend_,
no_db, history_database_params));
if (visit_delegate_ && !visit_delegate_->Init(this))
@@ -899,7 +907,7 @@ void HistoryService::ScheduleAutocomplete(
const base::Callback<void(HistoryBackend*, URLDatabase*)>& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
ScheduleTask(PRIORITY_UI, base::Bind(&HistoryBackend::ScheduleAutocomplete,
- history_backend_.get(), callback));
+ history_backend_, callback));
}
void HistoryService::ScheduleTask(SchedulePriority priority,
@@ -966,10 +974,11 @@ void HistoryService::SetInMemoryBackend(
in_memory_backend_->AttachToHistoryService(this);
}
-void HistoryService::NotifyProfileError(sql::InitStatus init_status) {
+void HistoryService::NotifyProfileError(sql::InitStatus init_status,
+ const std::string& diagnostics) {
DCHECK(thread_checker_.CalledOnValidThread());
if (history_client_)
- history_client_->NotifyProfileError(init_status);
+ history_client_->NotifyProfileError(init_status, diagnostics);
}
void HistoryService::DeleteURL(const GURL& url) {
@@ -977,7 +986,7 @@ void HistoryService::DeleteURL(const GURL& url) {
DCHECK(thread_checker_.CalledOnValidThread());
// We will update the visited links when we observe the delete notifications.
ScheduleTask(PRIORITY_NORMAL, base::Bind(&HistoryBackend::DeleteURL,
- history_backend_.get(), url));
+ history_backend_, url));
}
void HistoryService::DeleteURLsForTest(const std::vector<GURL>& urls) {
@@ -986,7 +995,7 @@ void HistoryService::DeleteURLsForTest(const std::vector<GURL>& urls) {
// We will update the visited links when we observe the delete
// notifications.
ScheduleTask(PRIORITY_NORMAL, base::Bind(&HistoryBackend::DeleteURLs,
- history_backend_.get(), urls));
+ history_backend_, urls));
}
void HistoryService::ExpireHistoryBetween(
diff --git a/chromium/components/history/core/browser/history_service.h b/chromium/components/history/core/browser/history_service.h
index b3be99efb62..5e10f4b0c8f 100644
--- a/chromium/components/history/core/browser/history_service.h
+++ b/chromium/components/history/core/browser/history_service.h
@@ -34,8 +34,8 @@
#include "components/history/core/browser/keyword_id.h"
#include "components/history/core/browser/typed_url_syncable_service.h"
#include "components/keyed_service/core/keyed_service.h"
+#include "components/sync/api/syncable_service.h"
#include "sql/init_status.h"
-#include "sync/api/syncable_service.h"
#include "ui/base/page_transition_types.h"
class GURL;
@@ -777,7 +777,8 @@ class HistoryService : public syncer::SyncableService, public KeyedService {
void SetInMemoryBackend(std::unique_ptr<InMemoryHistoryBackend> mem_backend);
// Called by our BackendDelegate when there is a problem reading the database.
- void NotifyProfileError(sql::InitStatus init_status);
+ void NotifyProfileError(sql::InitStatus init_status,
+ const std::string& diagnostics);
// Call to schedule a given task for running on the history thread with the
// specified priority. The task will have ownership taken.
diff --git a/chromium/components/history/core/browser/history_service_unittest.cc b/chromium/components/history/core/browser/history_service_unittest.cc
index b8049cacf38..7c72523abe7 100644
--- a/chromium/components/history/core/browser/history_service_unittest.cc
+++ b/chromium/components/history/core/browser/history_service_unittest.cc
@@ -34,17 +34,17 @@
#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/test/database_test_utils.h"
#include "components/history/core/test/test_history_database.h"
-#include "sync/api/attachments/attachment_id.h"
-#include "sync/api/fake_sync_change_processor.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_change_processor.h"
-#include "sync/api/sync_change_processor_wrapper_for_test.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/api/sync_merge_result.h"
-#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
-#include "sync/protocol/history_delete_directive_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/attachments/attachment_id.h"
+#include "components/sync/api/fake_sync_change_processor.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_change_processor.h"
+#include "components/sync/api/sync_change_processor_wrapper_for_test.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/api/sync_merge_result.h"
+#include "components/sync/core/attachments/attachment_service_proxy_for_test.h"
+#include "components/sync/protocol/history_delete_directive_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace history {
@@ -66,7 +66,7 @@ class HistoryServiceTest : public testing::Test {
// testing::Test
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- history_dir_ = temp_dir_.path().AppendASCII("HistoryServiceTest");
+ history_dir_ = temp_dir_.GetPath().AppendASCII("HistoryServiceTest");
ASSERT_TRUE(base::CreateDirectory(history_dir_));
history_service_.reset(new history::HistoryService);
if (!history_service_->Init(
diff --git a/chromium/components/history/core/browser/history_types.cc b/chromium/components/history/core/browser/history_types.cc
index 5d9ea3c805b..c6d3edacac1 100644
--- a/chromium/components/history/core/browser/history_types.cc
+++ b/chromium/components/history/core/browser/history_types.cc
@@ -254,7 +254,8 @@ HistoryAddPageArgs::HistoryAddPageArgs()
RedirectList(),
ui::PAGE_TRANSITION_LINK,
SOURCE_BROWSED,
- false) {
+ false,
+ true) {
}
HistoryAddPageArgs::HistoryAddPageArgs(const GURL& url,
@@ -265,7 +266,8 @@ HistoryAddPageArgs::HistoryAddPageArgs(const GURL& url,
const RedirectList& redirects,
ui::PageTransition transition,
VisitSource source,
- bool did_replace_entry)
+ bool did_replace_entry,
+ bool consider_for_ntp_most_visited)
: url(url),
time(time),
context_id(context_id),
@@ -274,7 +276,8 @@ HistoryAddPageArgs::HistoryAddPageArgs(const GURL& url,
redirects(redirects),
transition(transition),
visit_source(source),
- did_replace_entry(did_replace_entry) {
+ did_replace_entry(did_replace_entry),
+ consider_for_ntp_most_visited(consider_for_ntp_most_visited) {
}
HistoryAddPageArgs::HistoryAddPageArgs(const HistoryAddPageArgs& other) =
diff --git a/chromium/components/history/core/browser/history_types.h b/chromium/components/history/core/browser/history_types.h
index 9795ded30ae..64f34c30416 100644
--- a/chromium/components/history/core/browser/history_types.h
+++ b/chromium/components/history/core/browser/history_types.h
@@ -332,7 +332,7 @@ struct MostVisitedURL {
RedirectList redirects;
- bool operator==(const MostVisitedURL& other) {
+ bool operator==(const MostVisitedURL& other) const {
return url == other.url;
}
};
@@ -372,7 +372,7 @@ struct HistoryAddPageArgs {
// HistoryAddPageArgs(
// GURL(), base::Time(), NULL, 0, GURL(),
// RedirectList(), ui::PAGE_TRANSITION_LINK,
- // SOURCE_BROWSED, false)
+ // SOURCE_BROWSED, false, true)
HistoryAddPageArgs();
HistoryAddPageArgs(const GURL& url,
base::Time time,
@@ -382,7 +382,8 @@ struct HistoryAddPageArgs {
const RedirectList& redirects,
ui::PageTransition transition,
VisitSource source,
- bool did_replace_entry);
+ bool did_replace_entry,
+ bool consider_for_ntp_most_visited);
HistoryAddPageArgs(const HistoryAddPageArgs& other);
~HistoryAddPageArgs();
@@ -395,6 +396,11 @@ struct HistoryAddPageArgs {
ui::PageTransition transition;
VisitSource visit_source;
bool did_replace_entry;
+ // Specifies whether a page visit should contribute to the Most Visited tiles
+ // in the New Tab Page. Note that setting this to true (most common case)
+ // doesn't guarantee it's relevant for Most Visited, since other requirements
+ // exist (e.g. certain page transition types).
+ bool consider_for_ntp_most_visited;
};
// TopSites -------------------------------------------------------------------
diff --git a/chromium/components/history/core/browser/in_memory_database.cc b/chromium/components/history/core/browser/in_memory_database.cc
index 5ae9b22166f..b99e202f21d 100644
--- a/chromium/components/history/core/browser/in_memory_database.cc
+++ b/chromium/components/history/core/browser/in_memory_database.cc
@@ -6,7 +6,7 @@
#include "base/files/file_path.h"
#include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h"
diff --git a/chromium/components/history/core/browser/thumbnail_database_unittest.cc b/chromium/components/history/core/browser/thumbnail_database_unittest.cc
index 09c3d2377eb..61873b37978 100644
--- a/chromium/components/history/core/browser/thumbnail_database_unittest.cc
+++ b/chromium/components/history/core/browser/thumbnail_database_unittest.cc
@@ -174,7 +174,7 @@ class ThumbnailDatabaseTest : public testing::Test {
// Get a temporary directory for the test DB files.
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- file_name_ = temp_dir_.path().AppendASCII("TestFavicons.db");
+ file_name_ = temp_dir_.GetPath().AppendASCII("TestFavicons.db");
}
base::ScopedTempDir temp_dir_;
diff --git a/chromium/components/history/core/browser/top_sites_database.cc b/chromium/components/history/core/browser/top_sites_database.cc
index 09efcf70ccc..191b36d547d 100644
--- a/chromium/components/history/core/browser/top_sites_database.cc
+++ b/chromium/components/history/core/browser/top_sites_database.cc
@@ -10,7 +10,7 @@
#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/history/core/browser/history_types.h"
diff --git a/chromium/components/history/core/browser/top_sites_database_unittest.cc b/chromium/components/history/core/browser/top_sites_database_unittest.cc
index c1417fff69a..289b9830404 100644
--- a/chromium/components/history/core/browser/top_sites_database_unittest.cc
+++ b/chromium/components/history/core/browser/top_sites_database_unittest.cc
@@ -68,7 +68,7 @@ class TopSitesDatabaseTest : public testing::Test {
void SetUp() override {
// Get a temporary directory for the test DB files.
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- file_name_ = temp_dir_.path().AppendASCII("TestTopSites.db");
+ file_name_ = temp_dir_.GetPath().AppendASCII("TestTopSites.db");
}
base::ScopedTempDir temp_dir_;
diff --git a/chromium/components/history/core/browser/top_sites_impl_unittest.cc b/chromium/components/history/core/browser/top_sites_impl_unittest.cc
index dc0715d4936..96ae3c1e47b 100644
--- a/chromium/components/history/core/browser/top_sites_impl_unittest.cc
+++ b/chromium/components/history/core/browser/top_sites_impl_unittest.cc
@@ -145,7 +145,7 @@ class TopSitesImplTest : public HistoryUnitTestBase {
history_service_.reset(
new HistoryService(nullptr, std::unique_ptr<VisitDelegate>()));
ASSERT_TRUE(history_service_->Init(
- TestHistoryDatabaseParamsForPath(scoped_temp_dir_.path())));
+ TestHistoryDatabaseParamsForPath(scoped_temp_dir_.GetPath())));
ResetTopSites();
WaitTopSitesLoaded();
}
@@ -316,7 +316,7 @@ class TopSitesImplTest : public HistoryUnitTestBase {
top_sites_impl_ = new TopSitesImpl(
pref_service_.get(), history_service_.get(),
prepopulated_pages, base::Bind(MockCanAddURLToHistory));
- top_sites_impl_->Init(scoped_temp_dir_.path().Append(kTopSitesFilename),
+ top_sites_impl_->Init(scoped_temp_dir_.GetPath().Append(kTopSitesFilename),
message_loop_.task_runner());
}
diff --git a/chromium/components/history/core/browser/typed_url_data_type_controller.cc b/chromium/components/history/core/browser/typed_url_data_type_controller.cc
index 776e698d3e9..8e99a0032b1 100644
--- a/chromium/components/history/core/browser/typed_url_data_type_controller.cc
+++ b/chromium/components/history/core/browser/typed_url_data_type_controller.cc
@@ -4,13 +4,15 @@
#include "components/history/core/browser/typed_url_data_type_controller.h"
+#include <memory>
+
#include "base/bind.h"
#include "base/callback.h"
#include "base/metrics/histogram.h"
#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/browser/history_service.h"
#include "components/prefs/pref_service.h"
-#include "components/sync_driver/sync_client.h"
+#include "components/sync/driver/sync_client.h"
namespace browser_sync {
@@ -21,16 +23,11 @@ namespace {
// the tasks we want to run.
class RunTaskOnHistoryThread : public history::HistoryDBTask {
public:
- explicit RunTaskOnHistoryThread(const base::Closure& task,
- TypedUrlDataTypeController* dtc)
- : task_(new base::Closure(task)), dtc_(dtc) {}
+ explicit RunTaskOnHistoryThread(const base::Closure& task)
+ : task_(new base::Closure(task)) {}
bool RunOnDBThread(history::HistoryBackend* backend,
history::HistoryDatabase* db) override {
- // Set the backend, then release our reference before executing the task.
- dtc_->SetBackend(backend);
- dtc_ = NULL;
-
// Invoke the task, then free it immediately so we don't keep a reference
// around all the way until DoneRunOnMainThread() is invoked back on the
// main thread - we want to release references as soon as possible to avoid
@@ -46,30 +43,23 @@ class RunTaskOnHistoryThread : public history::HistoryDBTask {
~RunTaskOnHistoryThread() override {}
std::unique_ptr<base::Closure> task_;
- scoped_refptr<TypedUrlDataTypeController> dtc_;
};
} // namespace
TypedUrlDataTypeController::TypedUrlDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
const char* history_disabled_pref_name)
- : NonUIDataTypeController(ui_thread, error_callback, sync_client),
+ : NonUIDataTypeController(syncer::TYPED_URLS, dump_stack, sync_client),
history_disabled_pref_name_(history_disabled_pref_name),
- backend_(NULL),
sync_client_(sync_client) {
pref_registrar_.Init(sync_client->GetPrefService());
pref_registrar_.Add(
history_disabled_pref_name_,
base::Bind(
&TypedUrlDataTypeController::OnSavingBrowserHistoryDisabledChanged,
- base::Unretained(this)));
-}
-
-syncer::ModelType TypedUrlDataTypeController::type() const {
- return syncer::TYPED_URLS;
+ base::AsWeakPtr(this)));
}
syncer::ModelSafeGroup TypedUrlDataTypeController::model_safe_group() const {
@@ -77,18 +67,13 @@ syncer::ModelSafeGroup TypedUrlDataTypeController::model_safe_group() const {
}
bool TypedUrlDataTypeController::ReadyForStart() const {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
return !sync_client_->GetPrefService()->GetBoolean(
history_disabled_pref_name_);
}
-void TypedUrlDataTypeController::SetBackend(history::HistoryBackend* backend) {
- DCHECK(!ui_thread()->BelongsToCurrentThread());
- backend_ = backend;
-}
-
void TypedUrlDataTypeController::OnSavingBrowserHistoryDisabledChanged() {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
if (sync_client_->GetPrefService()->GetBoolean(history_disabled_pref_name_)) {
// We've turned off history persistence, so if we are running,
// generate an unrecoverable error. This can be fixed by restarting
@@ -96,8 +81,8 @@ void TypedUrlDataTypeController::OnSavingBrowserHistoryDisabledChanged() {
if (state() != NOT_RUNNING && state() != STOPPING) {
PostTaskOnBackendThread(
FROM_HERE,
- base::Bind(&DataTypeController::OnSingleDataTypeUnrecoverableError,
- this,
+ base::Bind(&syncer::DataTypeErrorHandler::OnUnrecoverableError,
+ base::Passed(CreateErrorHandler()),
syncer::SyncError(
FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR,
"History saving is now disabled by policy.", type())));
@@ -108,11 +93,11 @@ void TypedUrlDataTypeController::OnSavingBrowserHistoryDisabledChanged() {
bool TypedUrlDataTypeController::PostTaskOnBackendThread(
const tracked_objects::Location& from_here,
const base::Closure& task) {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
history::HistoryService* history = sync_client_->GetHistoryService();
if (history) {
history->ScheduleDBTask(std::unique_ptr<history::HistoryDBTask>(
- new RunTaskOnHistoryThread(task, this)),
+ new RunTaskOnHistoryThread(task)),
&task_tracker_);
return true;
} else {
diff --git a/chromium/components/history/core/browser/typed_url_data_type_controller.h b/chromium/components/history/core/browser/typed_url_data_type_controller.h
index 9e84a35d6a3..b3bf9a36f37 100644
--- a/chromium/components/history/core/browser/typed_url_data_type_controller.h
+++ b/chromium/components/history/core/browser/typed_url_data_type_controller.h
@@ -9,11 +9,10 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/ref_counted.h"
#include "base/task/cancelable_task_tracker.h"
#include "components/prefs/pref_change_registrar.h"
-#include "components/sync_driver/non_ui_data_type_controller.h"
-#include "components/sync_driver/sync_api_component_factory.h"
+#include "components/sync/driver/non_ui_data_type_controller.h"
+#include "components/sync/driver/sync_api_component_factory.h"
namespace history {
class HistoryBackend;
@@ -24,44 +23,36 @@ namespace browser_sync {
class ControlTask;
// A class that manages the startup and shutdown of typed_url sync.
-class TypedUrlDataTypeController : public sync_driver::NonUIDataTypeController {
+class TypedUrlDataTypeController : public syncer::NonUIDataTypeController {
public:
- explicit TypedUrlDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
- const char* history_disabled_pref_name);
+ // |dump_stack| is called when an unrecoverable error occurs.
+ TypedUrlDataTypeController(const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
+ const char* history_disabled_pref_name);
+ ~TypedUrlDataTypeController() override;
// NonUIDataTypeController implementation
- syncer::ModelType type() const override;
syncer::ModelSafeGroup model_safe_group() const override;
bool ReadyForStart() const override;
- // Invoked on the history thread to set our history backend - must be called
- // before CreateSyncComponents() is invoked.
- void SetBackend(history::HistoryBackend* backend);
-
protected:
// NonUIDataTypeController interface.
bool PostTaskOnBackendThread(const tracked_objects::Location& from_here,
const base::Closure& task) override;
private:
- ~TypedUrlDataTypeController() override;
-
void OnSavingBrowserHistoryDisabledChanged();
// Name of the pref that indicates whether saving history is disabled.
const char* history_disabled_pref_name_;
- history::HistoryBackend* backend_;
PrefChangeRegistrar pref_registrar_;
// Helper object to make sure we don't leave tasks running on the history
// thread.
base::CancelableTaskTracker task_tracker_;
- sync_driver::SyncClient* const sync_client_;
+ syncer::SyncClient* const sync_client_;
DISALLOW_COPY_AND_ASSIGN(TypedUrlDataTypeController);
};
diff --git a/chromium/components/history/core/browser/typed_url_syncable_service.cc b/chromium/components/history/core/browser/typed_url_syncable_service.cc
index b152df15538..0397d59dba9 100644
--- a/chromium/components/history/core/browser/typed_url_syncable_service.cc
+++ b/chromium/components/history/core/browser/typed_url_syncable_service.cc
@@ -5,6 +5,7 @@
#include "components/history/core/browser/typed_url_syncable_service.h"
#include <stddef.h>
+
#include <utility>
#include "base/auto_reset.h"
@@ -12,9 +13,9 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "components/history/core/browser/history_backend.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/protocol/typed_url_specifics.pb.h"
#include "net/base/url_util.h"
-#include "sync/protocol/sync.pb.h"
-#include "sync/protocol/typed_url_specifics.pb.h"
namespace history {
@@ -150,6 +151,9 @@ syncer::SyncMergeResult TypedUrlSyncableService::MergeDataAndStartSyncing(
const sync_pb::EntitySpecifics& specifics = sync_iter->GetSpecifics();
const sync_pb::TypedUrlSpecifics& typed_url(specifics.typed_url());
+ if (ShouldIgnoreUrl(GURL(typed_url.url())))
+ continue;
+
// Add url to cache of sync state. Note that this is done irrespective of
// whether the synced url is ignored locally, so that we know what to delete
// at a later point.
@@ -747,6 +751,12 @@ bool TypedUrlSyncableService::ShouldIgnoreUrl(const GURL& url) {
if (net::IsLocalhost(url.host()))
return true;
+ // Ignore username and password, sonce history backend will remove user name
+ // and password in URLDatabase::GURLToDatabaseURL and send username/password
+ // removed url to sync later.
+ if (url.has_username() || url.has_password())
+ return true;
+
return false;
}
diff --git a/chromium/components/history/core/browser/typed_url_syncable_service.h b/chromium/components/history/core/browser/typed_url_syncable_service.h
index 8ee8f6c149f..5b386d31bef 100644
--- a/chromium/components/history/core/browser/typed_url_syncable_service.h
+++ b/chromium/components/history/core/browser/typed_url_syncable_service.h
@@ -15,11 +15,11 @@
#include "base/threading/thread_checker.h"
#include "components/history/core/browser/history_backend_observer.h"
#include "components/history/core/browser/history_types.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/api/syncable_service.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/api/syncable_service.h"
#include "ui/base/page_transition_types.h"
class GURL;
diff --git a/chromium/components/history/core/browser/typed_url_syncable_service_unittest.cc b/chromium/components/history/core/browser/typed_url_syncable_service_unittest.cc
index beb3e0e34bc..7d3df4a77d5 100644
--- a/chromium/components/history/core/browser/typed_url_syncable_service_unittest.cc
+++ b/chromium/components/history/core/browser/typed_url_syncable_service_unittest.cc
@@ -23,13 +23,13 @@
#include "components/history/core/browser/history_types.h"
#include "components/history/core/browser/in_memory_history_backend.h"
#include "components/history/core/test/test_history_database.h"
-#include "sync/api/fake_sync_change_processor.h"
-#include "sync/api/sync_change_processor_wrapper_for_test.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_error_factory_mock.h"
-#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
-#include "sync/protocol/sync.pb.h"
-#include "sync/protocol/typed_url_specifics.pb.h"
+#include "components/sync/api/fake_sync_change_processor.h"
+#include "components/sync/api/sync_change_processor_wrapper_for_test.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_error_factory_mock.h"
+#include "components/sync/core/attachments/attachment_service_proxy_for_test.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/protocol/typed_url_specifics.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
using history::HistoryBackend;
@@ -151,7 +151,8 @@ class TestHistoryBackendDelegate : public HistoryBackend::Delegate {
public:
TestHistoryBackendDelegate() {}
- void NotifyProfileError(sql::InitStatus init_status) override {}
+ void NotifyProfileError(sql::InitStatus init_status,
+ const std::string& diagnostics) override {}
void SetInMemoryBackend(
std::unique_ptr<InMemoryHistoryBackend> backend) override{};
void NotifyFaviconsChanged(const std::set<GURL>& page_urls,
@@ -218,8 +219,8 @@ class TypedUrlSyncableServiceTest : public testing::Test {
void SetUp() override {
fake_history_backend_ = new TestHistoryBackend();
ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
- fake_history_backend_->Init(false,
- TestHistoryDatabaseParamsForPath(test_dir_.path()));
+ fake_history_backend_->Init(
+ false, TestHistoryDatabaseParamsForPath(test_dir_.GetPath()));
typed_url_sync_service_ =
fake_history_backend_->GetTypedUrlSyncableService();
fake_change_processor_.reset(new syncer::FakeSyncChangeProcessor);
@@ -1075,6 +1076,50 @@ TEST_F(TypedUrlSyncableServiceTest, MergeUrlOldSync) {
url_specifics.visit_transitions(0));
}
+// Check that there is no crash during start sync, if history backend and sync
+// have same url, but sync has username/password in it.
+// Also check sync will not accept url with username and password.
+TEST_F(TypedUrlSyncableServiceTest, MergeUrlsWithUsernameAndPassword) {
+ const char kURLWithUsernameAndPassword[] =
+ "http://username:password@pie.com/";
+
+ // Add a url to backend.
+ VisitVector visits;
+ URLRow local_row = MakeTypedUrlRow(kURL, kTitle2, 1, 3, false, &visits);
+ fake_history_backend_->SetVisitsForUrl(local_row, visits);
+
+ // Create sync data for the same url but contain username and password.
+ VisitVector server_visits;
+ URLRow server_row = MakeTypedUrlRow(kURLWithUsernameAndPassword, kTitle, 1, 3,
+ false, &server_visits);
+ syncer::SyncDataList initial_sync_data;
+ sync_pb::EntitySpecifics entity_specifics;
+ sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
+ WriteToTypedUrlSpecifics(server_row, server_visits, typed_url);
+ syncer::SyncData data =
+ syncer::SyncData::CreateLocalData(kURL, kTitle, entity_specifics);
+
+ // Make sure there is no crash when merge two urls.
+ initial_sync_data.push_back(data);
+ StartSyncing(initial_sync_data);
+
+ // Check that the username and password url did not get merged.
+ std::set<GURL> sync_state;
+ GetSyncedUrls(&sync_state);
+ EXPECT_EQ(1U, sync_state.size());
+ EXPECT_EQ(1U, sync_state.count(GURL(kURL)));
+
+ // Notify typed url sync service of the update.
+ typed_url_sync_service_->OnURLVisited(
+ fake_history_backend_.get(), ui::PAGE_TRANSITION_TYPED, server_row,
+ RedirectList(), base::Time::FromInternalValue(7));
+
+ // Check username/password url is not synced.
+ GetSyncedUrls(&sync_state);
+ EXPECT_EQ(1U, sync_state.size());
+ EXPECT_EQ(1U, sync_state.count(GURL(kURL)));
+}
+
// Create a remote typed URL and visit, then send to syncable service after sync
// has started. Check that local DB is received the new URL and visit.
TEST_F(TypedUrlSyncableServiceTest, AddUrlAndVisits) {
diff --git a/chromium/components/history/core/browser/url_database.cc b/chromium/components/history/core/browser/url_database.cc
index 4f17fdb158c..282cd158d0e 100644
--- a/chromium/components/history/core/browser/url_database.cc
+++ b/chromium/components/history/core/browser/url_database.cc
@@ -535,8 +535,7 @@ void URLDatabase::GetMostRecentKeywordSearchTerms(
base::string16 lower_prefix = base::i18n::ToLower(prefix);
// This magic gives us a prefix search.
base::string16 next_prefix = lower_prefix;
- next_prefix[next_prefix.size() - 1] =
- next_prefix[next_prefix.size() - 1] + 1;
+ next_prefix.back() = next_prefix.back() + 1;
statement.BindInt64(0, keyword_id);
statement.BindString16(1, lower_prefix);
statement.BindString16(2, next_prefix);
diff --git a/chromium/components/history/core/browser/url_database_unittest.cc b/chromium/components/history/core/browser/url_database_unittest.cc
index 2dc1b79fecb..fe60fcc55c2 100644
--- a/chromium/components/history/core/browser/url_database_unittest.cc
+++ b/chromium/components/history/core/browser/url_database_unittest.cc
@@ -46,7 +46,7 @@ class URLDatabaseTest : public testing::Test,
// Test setup.
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- base::FilePath db_file = temp_dir_.path().AppendASCII("URLTest.db");
+ base::FilePath db_file = temp_dir_.GetPath().AppendASCII("URLTest.db");
EXPECT_TRUE(db_.Open(db_file));
diff --git a/chromium/components/history/core/browser/visit_database_unittest.cc b/chromium/components/history/core/browser/visit_database_unittest.cc
index d558c204077..77218eff842 100644
--- a/chromium/components/history/core/browser/visit_database_unittest.cc
+++ b/chromium/components/history/core/browser/visit_database_unittest.cc
@@ -48,7 +48,7 @@ class VisitDatabaseTest : public PlatformTest,
void SetUp() override {
PlatformTest::SetUp();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- base::FilePath db_file = temp_dir_.path().AppendASCII("VisitTest.db");
+ base::FilePath db_file = temp_dir_.GetPath().AppendASCII("VisitTest.db");
EXPECT_TRUE(db_.Open(db_file));
diff --git a/chromium/components/history/core/browser/visit_tracker.cc b/chromium/components/history/core/browser/visit_tracker.cc
index fccd2e1627f..c9de95646f2 100644
--- a/chromium/components/history/core/browser/visit_tracker.cc
+++ b/chromium/components/history/core/browser/visit_tracker.cc
@@ -6,7 +6,7 @@
#include <stddef.h>
-#include "base/stl_util.h"
+#include "base/memory/ptr_util.h"
namespace history {
@@ -18,12 +18,9 @@ static const size_t kResizeBigTransitionListTo = 64;
static_assert(kResizeBigTransitionListTo < kMaxItemsInTransitionList,
"maxium number of items must be larger than we are resizing to");
-VisitTracker::VisitTracker() {
-}
+VisitTracker::VisitTracker() {}
-VisitTracker::~VisitTracker() {
- STLDeleteContainerPairSecondPointers(contexts_.begin(), contexts_.end());
-}
+VisitTracker::~VisitTracker() {}
// This function is potentially slow because it may do up to two brute-force
// searches of the transitions list. This transitions list is kept to a
@@ -36,10 +33,10 @@ VisitID VisitTracker::GetLastVisit(ContextID context_id,
if (referrer.is_empty() || !context_id)
return 0;
- ContextList::iterator i = contexts_.find(context_id);
+ auto i = contexts_.find(context_id);
if (i == contexts_.end())
return 0; // We don't have any entries for this context.
- TransitionList& transitions = *i->second;
+ TransitionList& transitions = i->second;
// Recall that a navigation entry ID is associated with a single session
// history entry. In the case of automatically loaded iframes, many
@@ -74,28 +71,19 @@ void VisitTracker::AddVisit(ContextID context_id,
int nav_entry_id,
const GURL& url,
VisitID visit_id) {
- TransitionList* transitions = contexts_[context_id];
- if (!transitions) {
- transitions = new TransitionList;
- contexts_[context_id] = transitions;
- }
+ TransitionList& transitions = contexts_[context_id];
Transition t;
t.url = url;
t.nav_entry_id = nav_entry_id;
t.visit_id = visit_id;
- transitions->push_back(t);
+ transitions.push_back(t);
- CleanupTransitionList(transitions);
+ CleanupTransitionList(&transitions);
}
void VisitTracker::ClearCachedDataForContextID(ContextID context_id) {
- ContextList::iterator i = contexts_.find(context_id);
- if (i == contexts_.end())
- return; // We don't have any entries for this context.
-
- delete i->second;
- contexts_.erase(i);
+ contexts_.erase(context_id);
}
diff --git a/chromium/components/history/core/browser/visit_tracker.h b/chromium/components/history/core/browser/visit_tracker.h
index 4f904877305..df3fba9e808 100644
--- a/chromium/components/history/core/browser/visit_tracker.h
+++ b/chromium/components/history/core/browser/visit_tracker.h
@@ -50,7 +50,6 @@ class VisitTracker {
VisitID visit_id; // Visit ID generated by history.
};
typedef std::vector<Transition> TransitionList;
- typedef std::map<ContextID, TransitionList*> ContextList;
// Expires oldish items in the given transition list. This keeps the list
// size small by removing items that are unlikely to be needed, which is
@@ -58,7 +57,7 @@ class VisitTracker {
void CleanupTransitionList(TransitionList* transitions);
// Maps render view hosts to lists of recent transitions.
- ContextList contexts_;
+ std::map<ContextID, TransitionList> contexts_;
DISALLOW_COPY_AND_ASSIGN(VisitTracker);
};
diff --git a/chromium/components/history/core/browser/visitsegment_database.cc b/chromium/components/history/core/browser/visitsegment_database.cc
index 0e8244e33b0..afe0712caad 100644
--- a/chromium/components/history/core/browser/visitsegment_database.cc
+++ b/chromium/components/history/core/browser/visitsegment_database.cc
@@ -228,7 +228,7 @@ VisitSegmentDatabase::QuerySegmentUsage(
while (statement.Step()) {
SegmentID segment_id = statement.ColumnInt64(0);
if (segment_id != previous_segment_id) {
- segments.push_back(base::WrapUnique(new PageUsageData(segment_id)));
+ segments.push_back(base::MakeUnique<PageUsageData>(segment_id));
previous_segment_id = segment_id;
}
diff --git a/chromium/components/history/core/browser/web_history_service.cc b/chromium/components/history/core/browser/web_history_service.cc
index c384f9d8bb5..d66a39c313c 100644
--- a/chromium/components/history/core/browser/web_history_service.cc
+++ b/chromium/components/history/core/browser/web_history_service.cc
@@ -10,14 +10,17 @@
#include "base/command_line.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "components/history/core/browser/history_service_observer.h"
+#include "components/history/core/browser/web_history_service_observer.h"
#include "components/signin/core/browser/signin_manager.h"
-#include "components/sync_driver/sync_util.h"
+#include "components/sync/driver/sync_util.h"
+#include "components/sync/protocol/history_status.pb.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_token_service.h"
@@ -28,7 +31,6 @@
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context_getter.h"
-#include "sync/protocol/history_status.pb.h"
#include "ui/base/device_form_factor.h"
#include "url/gurl.h"
@@ -302,11 +304,11 @@ GURL GetQueryUrl(const base::string16& text_query,
// Creates a DictionaryValue to hold the parameters for a deletion.
// Ownership is passed to the caller.
// |url| may be empty, indicating a time-range deletion.
-base::DictionaryValue* CreateDeletion(
+std::unique_ptr<base::DictionaryValue> CreateDeletion(
const std::string& min_time,
const std::string& max_time,
const GURL& url) {
- base::DictionaryValue* deletion = new base::DictionaryValue;
+ std::unique_ptr<base::DictionaryValue> deletion(new base::DictionaryValue);
deletion->SetString("type", "CHROME_HISTORY");
if (url.is_valid())
deletion->SetString("url", url.spec());
@@ -334,10 +336,18 @@ WebHistoryService::WebHistoryService(
}
WebHistoryService::~WebHistoryService() {
- STLDeleteElements(&pending_expire_requests_);
- STLDeleteElements(&pending_audio_history_requests_);
- STLDeleteElements(&pending_web_and_app_activity_requests_);
- STLDeleteElements(&pending_other_forms_of_browsing_history_requests_);
+ base::STLDeleteElements(&pending_expire_requests_);
+ base::STLDeleteElements(&pending_audio_history_requests_);
+ base::STLDeleteElements(&pending_web_and_app_activity_requests_);
+ base::STLDeleteElements(&pending_other_forms_of_browsing_history_requests_);
+}
+
+void WebHistoryService::AddObserver(WebHistoryServiceObserver* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void WebHistoryService::RemoveObserver(WebHistoryServiceObserver* observer) {
+ observer_list_.RemoveObserver(observer);
}
WebHistoryService::Request* WebHistoryService::CreateRequest(
@@ -419,8 +429,9 @@ void WebHistoryService::ExpireHistory(
std::unique_ptr<Request> request(CreateRequest(url, completion_callback));
request->SetPostData(post_data);
- request->Start();
+ Request* request_ptr = request.get();
pending_expire_requests_.insert(request.release());
+ request_ptr->Start();
}
void WebHistoryService::ExpireHistoryBetween(
@@ -501,8 +512,8 @@ void WebHistoryService::QueryOtherFormsOfBrowsingHistory(
callback);
// Find the Sync request URL.
- GURL url =
- GetSyncServiceURL(*base::CommandLine::ForCurrentProcess(), channel);
+ GURL url = syncer::GetSyncServiceURL(*base::CommandLine::ForCurrentProcess(),
+ channel);
GURL::Replacements replace_path;
std::string new_path =
url.path() + kQueryOtherFormsOfBrowsingHistoryUrlSuffix;
@@ -513,7 +524,7 @@ void WebHistoryService::QueryOtherFormsOfBrowsingHistory(
Request* request = CreateRequest(url, completion_callback);
// Set the Sync-specific user agent.
- std::string user_agent = MakeUserAgentForSync(
+ std::string user_agent = syncer::MakeUserAgentForSync(
channel, ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET);
request->SetUserAgent(user_agent);
@@ -552,6 +563,13 @@ void WebHistoryService::ExpireHistoryCompletionCallback(
if (response_value)
response_value->GetString("version_info", &server_version_info_);
}
+
+ // Inform the observers about the history deletion.
+ if (response_value.get() && success) {
+ FOR_EACH_OBSERVER(WebHistoryServiceObserver, observer_list_,
+ OnWebHistoryDeleted());
+ }
+
callback.Run(response_value.get() && success);
}
diff --git a/chromium/components/history/core/browser/web_history_service.h b/chromium/components/history/core/browser/web_history_service.h
index 0b6c08bdc86..d5681a8d0f5 100644
--- a/chromium/components/history/core/browser/web_history_service.h
+++ b/chromium/components/history/core/browser/web_history_service.h
@@ -14,6 +14,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
#include "components/history/core/browser/history_types.h"
#include "components/keyed_service/core/keyed_service.h"
@@ -34,6 +35,8 @@ class SigninManagerBase;
namespace history {
+class WebHistoryServiceObserver;
+
// Provides an API for querying Google servers for a signed-in user's
// synced history visits. It is roughly analogous to HistoryService, and
// supports a similar API.
@@ -95,6 +98,9 @@ class WebHistoryService : public KeyedService {
const scoped_refptr<net::URLRequestContextGetter>& request_context);
~WebHistoryService() override;
+ void AddObserver(WebHistoryServiceObserver* observer);
+ void RemoveObserver(WebHistoryServiceObserver* observer);
+
// Searches synced history for visits matching |text_query|. The timeframe to
// search, along with other options, is specified in |options|. If
// |text_query| is empty, all visits in the timeframe will be returned.
@@ -219,6 +225,9 @@ class WebHistoryService : public KeyedService {
// complete by profile shutdown.
std::set<Request*> pending_other_forms_of_browsing_history_requests_;
+ // Observers.
+ base::ObserverList<WebHistoryServiceObserver, true> observer_list_;
+
base::WeakPtrFactory<WebHistoryService> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(WebHistoryService);
diff --git a/chromium/components/history/core/browser/web_history_service_observer.h b/chromium/components/history/core/browser/web_history_service_observer.h
new file mode 100644
index 00000000000..00fc817108c
--- /dev/null
+++ b/chromium/components/history/core/browser/web_history_service_observer.h
@@ -0,0 +1,27 @@
+// 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 COMPONENTS_HISTORY_CORE_BROWSER_WEB_HISTORY_SERVICE_OBSERVER_H_
+#define COMPONENTS_HISTORY_CORE_BROWSER_WEB_HISTORY_SERVICE_OBSERVER_H_
+
+namespace history {
+
+// Observes WebHistoryService actions. Currently only history expiration
+// is supported.
+// TODO(msramek): Consider defining ObservableHistoryService as a common
+// abstract ancestor for HistoryService and WebHistoryService. Then, we could
+// change the signatures of HistoryServiceObserver to use it for both classes.
+class WebHistoryServiceObserver {
+ public:
+ // Called after a successful WebHistoryService deletion request. This could
+ // be partial or complete history deletion.
+ virtual void OnWebHistoryDeleted() = 0;
+
+ protected:
+ virtual ~WebHistoryServiceObserver() {}
+};
+
+} // history
+
+#endif // COMPONENTS_HISTORY_CORE_BROWSER_WEB_HISTORY_SERVICE_OBSERVER_H_
diff --git a/chromium/components/history/core/test/BUILD.gn b/chromium/components/history/core/test/BUILD.gn
index 9bc56b1fd5a..70c02fe0a55 100644
--- a/chromium/components/history/core/test/BUILD.gn
+++ b/chromium/components/history/core/test/BUILD.gn
@@ -30,10 +30,10 @@ static_library("test") {
deps = [
"//base",
"//components/history/core/browser",
+ "//components/sync/protocol:protocol",
"//net",
"//sql",
"//sql:test_support",
- "//sync/protocol:protocol",
"//testing/gtest",
"//ui/gfx",
"//url",
diff --git a/chromium/components/history_strings.grdp b/chromium/components/history_strings.grdp
index d00006ad629..9dca85545db 100644
--- a/chromium/components/history_strings.grdp
+++ b/chromium/components/history_strings.grdp
@@ -50,13 +50,13 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY">$1<ex>(Ctrl+Shift+N)</ex></ph> may
Blocked
</message>
<message name="IDS_HISTORY_FOUND_SEARCH_RESULTS" desc="Message shown when zero or multiple search results are found.">
- Found <ph name="NUMBER_OF_RESULTS">$1</ph> <ph name="SEARCH_RESULTS"><ex>search results</ex>$2</ph> for '<ph name="SEARCH_STRING">$3</ph>'.
+ Found <ph name="NUMBER_OF_RESULTS">$1</ph> <ph name="SEARCH_RESULTS"><ex>search results</ex>$2</ph> for '<ph name="SEARCH_STRING">$3</ph>'
</message>
<message name="IDS_HISTORY_HAS_SYNCED_RESULTS" desc="The notification at the top of the history page indicating that it is showing visits synced from other devices.">
Showing history from your signed-in devices. <ph name="BEGIN_LINK">&lt;a href="https://support.google.com/chrome/?p=sync_history&amp;hl=[GRITLANGCODE]"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>.
</message>
<message name="IDS_HISTORY_OTHER_FORMS_OF_HISTORY" desc="The notification at the top of the history page indicating that deleting Chrome browsing history will not delete other forms of history stored at Google My Activity.">
- Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>history.google.com<ph name="END_LINK">&lt;/a&gt;</ph>.
+ Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>history.google.com<ph name="END_LINK">&lt;/a&gt;</ph>
</message>
<message name="IDS_HISTORY_INTERVAL" desc="A history interval shown in the title. The dates are already localized strings.">
<ph name="START_DATE">$1<ex>Wednesday, Aug. 1, 2012</ex></ph> to <ph name="END_DATE">$2<ex>Thursday, Aug. 30, 2012</ex></ph>
@@ -74,10 +74,10 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY">$1<ex>(Ctrl+Shift+N)</ex></ph> may
Newest
</message>
<message name="IDS_HISTORY_NO_RESULTS" desc="Text shown when no history entries are found.">
- No history entries found.
+ No history entries found
</message>
<message name="IDS_HISTORY_NO_SEARCH_RESULTS" desc="Text shown when no history search results have been found">
- No search results found.
+ No search results found
</message>
<message name="IDS_HISTORY_NO_SYNCED_RESULTS" desc="The notification at the top of the history page indicating that it does not include visits from other devices.">
Showing history from this device. <ph name="BEGIN_LINK">&lt;a href="https://support.google.com/chrome/?p=sync_history&amp;hl=[GRITLANGCODE]"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>.
@@ -101,15 +101,20 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY">$1<ex>(Ctrl+Shift+N)</ex></ph> may
<message name="IDS_HISTORY_OTHER_DEVICES_X_MORE" desc="In the 'Other Sessions' section of the history page, the label for showing that X more tabs are available for a session.">
<ph name="NUM_TABS_MORE">$1<ex>42</ex></ph> more...
</message>
- <message name="IDS_HISTORY_OTHER_SESSIONS_COLLAPSE_SESSION" desc="In the 'Other Sessions' menu on the history page, the label for the command to collapse (hide) the list of windows and tabs in a session.">
- Collapse list
- </message>
- <message name="IDS_HISTORY_OTHER_SESSIONS_EXPAND_SESSION" desc="In the 'Other Sessions' menu on the history page, the label for the command to expand (uncollapse) the list of windows and tabs in a session.">
- Expand list
- </message>
- <message name="IDS_HISTORY_OTHER_SESSIONS_OPEN_ALL" desc="In the 'Other Sessions' menu on the history page, the label for the command to open all tabs and windows from a session.">
- Open all
- </message>
+ <if expr="not is_android">
+ <message name="IDS_HISTORY_OTHER_SESSIONS_COLLAPSE_SESSION" desc="In the 'Other Sessions' menu on the history page, the label for the command to collapse (hide) the list of windows and tabs in a session.">
+ Collapse list
+ </message>
+ <message name="IDS_HISTORY_OTHER_SESSIONS_EXPAND_SESSION" desc="In the 'Other Sessions' menu on the history page, the label for the command to expand (uncollapse) the list of windows and tabs in a session.">
+ Expand list
+ </message>
+ <message name="IDS_HISTORY_OTHER_SESSIONS_HIDE_FOR_NOW" desc="In the 'Other Sessions' menu on the history page, the label for the command to remove entry corresponding to a session.">
+ Hide for now
+ </message>
+ <message name="IDS_HISTORY_OTHER_SESSIONS_OPEN_ALL" desc="In the 'Other Sessions' menu on the history page, the label for the command to open all tabs and windows from a session.">
+ Open all
+ </message>
+ </if>
<message name="IDS_HISTORY_RANGE_ALL_TIME" desc="Option in the history range button group. Shows results a page at a time, without grouping them by domain.">
All
</message>
diff --git a/chromium/components/image_fetcher.gypi b/chromium/components/image_fetcher.gypi
deleted file mode 100644
index eaed25b3fa2..00000000000
--- a/chromium/components/image_fetcher.gypi
+++ /dev/null
@@ -1,30 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/image_fetcher
- 'target_name': 'image_fetcher',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'image_fetcher/image_data_fetcher.cc',
- 'image_fetcher/image_data_fetcher.h',
- 'image_fetcher/image_decoder.h',
- 'image_fetcher/image_fetcher.h',
- 'image_fetcher/image_fetcher_delegate.h',
- 'image_fetcher/image_fetcher_impl.cc',
- 'image_fetcher/image_fetcher_impl.h',
- ]
- },
- ],
-}
diff --git a/chromium/components/image_fetcher/BUILD.gn b/chromium/components/image_fetcher/BUILD.gn
index 19063d0f865..cd60562577b 100644
--- a/chromium/components/image_fetcher/BUILD.gn
+++ b/chromium/components/image_fetcher/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("image_fetcher") {
+static_library("image_fetcher") {
sources = [
"image_data_fetcher.cc",
"image_data_fetcher.h",
@@ -15,6 +15,7 @@ source_set("image_fetcher") {
public_deps = [
"//base",
+ "//components/data_use_measurement/core",
"//net",
"//url",
]
diff --git a/chromium/components/image_fetcher/DEPS b/chromium/components/image_fetcher/DEPS
index 31148e3f08c..a07acff5466 100644
--- a/chromium/components/image_fetcher/DEPS
+++ b/chromium/components/image_fetcher/DEPS
@@ -1,4 +1,5 @@
include_rules = [
- "+url",
+ "+components/data_use_measurement/core",
"+net",
+ "+url",
]
diff --git a/chromium/components/image_fetcher/image_data_fetcher.cc b/chromium/components/image_fetcher/image_data_fetcher.cc
index 2100fb5472c..318e755ce65 100644
--- a/chromium/components/image_fetcher/image_data_fetcher.cc
+++ b/chromium/components/image_fetcher/image_data_fetcher.cc
@@ -11,6 +11,8 @@
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"
+using data_use_measurement::DataUseUserData;
+
namespace image_fetcher {
// An active image URL fetcher request. The struct contains the related requests
@@ -33,16 +35,26 @@ struct ImageDataFetcher::ImageDataFetcherRequest {
ImageDataFetcher::ImageDataFetcher(
net::URLRequestContextGetter* url_request_context_getter)
: url_request_context_getter_(url_request_context_getter),
+ data_use_service_name_(DataUseUserData::NOT_TAGGED),
next_url_fetcher_id_(0) {}
ImageDataFetcher::~ImageDataFetcher() {}
+void ImageDataFetcher::SetDataUseServiceName(
+ DataUseServiceName data_use_service_name) {
+ data_use_service_name_ = data_use_service_name;
+}
+
void ImageDataFetcher::FetchImageData(
const GURL& url, const ImageDataFetcherCallback& callback) {
std::unique_ptr<net::URLFetcher> url_fetcher =
net::URLFetcher::Create(
next_url_fetcher_id_++, url, net::URLFetcher::GET, this);
+ if (data_use_service_name_ != DataUseUserData::NOT_TAGGED) {
+ DataUseUserData::AttachToFetcher(url_fetcher.get(), data_use_service_name_);
+ }
+
std::unique_ptr<ImageDataFetcherRequest> request(
new ImageDataFetcherRequest(callback, std::move(url_fetcher)));
request->url_fetcher->SetRequestContext(url_request_context_getter_.get());
diff --git a/chromium/components/image_fetcher/image_data_fetcher.h b/chromium/components/image_fetcher/image_data_fetcher.h
index 94432311f34..92c5a5cf0dc 100644
--- a/chromium/components/image_fetcher/image_data_fetcher.h
+++ b/chromium/components/image_fetcher/image_data_fetcher.h
@@ -12,6 +12,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "url/gurl.h"
@@ -27,10 +28,15 @@ class ImageDataFetcher : public net::URLFetcherDelegate {
using ImageDataFetcherCallback =
base::Callback<void(const std::string& image_data)>;
+ using DataUseServiceName = data_use_measurement::DataUseUserData::ServiceName;
+
explicit ImageDataFetcher(
net::URLRequestContextGetter* url_request_context_getter);
~ImageDataFetcher() override;
+ // Sets a service name against which to track data usage.
+ void SetDataUseServiceName(DataUseServiceName data_use_service_name);
+
// Fetches the raw image bytes from the given |image_url| and calls the given
// |callback|. The callback is run even if fetching the URL fails. In case
// of an error an empty string is passed to the callback.
@@ -49,6 +55,8 @@ class ImageDataFetcher : public net::URLFetcherDelegate {
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+ DataUseServiceName data_use_service_name_;
+
// The next ID to use for a newly created URLFetcher. Each URLFetcher gets an
// id when it is created. The |url_fetcher_id_| is incremented by one for each
// newly created URLFetcher. The URLFetcher ID can be used during testing to
diff --git a/chromium/components/image_fetcher/image_fetcher.h b/chromium/components/image_fetcher/image_fetcher.h
index f6d380f8492..69836385acf 100644
--- a/chromium/components/image_fetcher/image_fetcher.h
+++ b/chromium/components/image_fetcher/image_fetcher.h
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/image_fetcher/image_fetcher_delegate.h"
#include "url/gurl.h"
@@ -25,8 +26,14 @@ class ImageFetcher {
ImageFetcher() {}
virtual ~ImageFetcher() {}
+ using DataUseServiceName = data_use_measurement::DataUseUserData::ServiceName;
+
virtual void SetImageFetcherDelegate(ImageFetcherDelegate* delegate) = 0;
+ // Sets a service name against which to track data usage.
+ virtual void SetDataUseServiceName(
+ DataUseServiceName data_use_service_name) = 0;
+
// An empty gfx::Image will be returned to the callback in case the image
// could not be fetched.
virtual void StartOrQueueNetworkRequest(
diff --git a/chromium/components/image_fetcher/image_fetcher_impl.cc b/chromium/components/image_fetcher/image_fetcher_impl.cc
index a40059bf07c..d260b2cdd2a 100644
--- a/chromium/components/image_fetcher/image_fetcher_impl.cc
+++ b/chromium/components/image_fetcher/image_fetcher_impl.cc
@@ -34,6 +34,11 @@ void ImageFetcherImpl::SetImageFetcherDelegate(ImageFetcherDelegate* delegate) {
delegate_ = delegate;
}
+void ImageFetcherImpl::SetDataUseServiceName(
+ DataUseServiceName data_use_service_name) {
+ image_data_fetcher_->SetDataUseServiceName(data_use_service_name);
+}
+
void ImageFetcherImpl::StartOrQueueNetworkRequest(
const std::string& id,
const GURL& image_url,
diff --git a/chromium/components/image_fetcher/image_fetcher_impl.h b/chromium/components/image_fetcher/image_fetcher_impl.h
index 86334301f66..05856e8b8fd 100644
--- a/chromium/components/image_fetcher/image_fetcher_impl.h
+++ b/chromium/components/image_fetcher/image_fetcher_impl.h
@@ -42,6 +42,9 @@ class ImageFetcherImpl : public image_fetcher::ImageFetcher {
// responsibility to ensure this.
void SetImageFetcherDelegate(ImageFetcherDelegate* delegate) override;
+ // Sets a service name against which to track data usage.
+ void SetDataUseServiceName(DataUseServiceName data_use_service_name) override;
+
void StartOrQueueNetworkRequest(
const std::string& id,
const GURL& image_url,
diff --git a/chromium/components/infobars.gypi b/chromium/components/infobars.gypi
deleted file mode 100644
index a0e36a0052c..00000000000
--- a/chromium/components/infobars.gypi
+++ /dev/null
@@ -1,65 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/infobars/core
- 'target_name': 'infobars_core',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../skia/skia.gyp:skia',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/strings/ui_strings.gyp:ui_strings',
- ],
- 'export_dependent_settings': [
- '../skia/skia.gyp:skia',
- ],
- 'sources': [
- # Note: sources duplicated in GN build.
- 'infobars/core/confirm_infobar_delegate.cc',
- 'infobars/core/confirm_infobar_delegate.h',
- 'infobars/core/infobar.cc',
- 'infobars/core/infobar.h',
- 'infobars/core/infobar_container.cc',
- 'infobars/core/infobar_container.h',
- 'infobars/core/infobar_delegate.cc',
- 'infobars/core/infobar_delegate.h',
- 'infobars/core/infobar_manager.cc',
- 'infobars/core/infobar_manager.h',
- 'infobars/core/infobars_switches.cc',
- 'infobars/core/infobars_switches.h',
- 'infobars/core/simple_alert_infobar_delegate.cc',
- 'infobars/core/simple_alert_infobar_delegate.h',
- ],
- 'conditions': [
- ['OS != "ios" and OS != "android"', {
- 'dependencies': [
- '../ui/gfx/gfx.gyp:gfx_vector_icons',
- '../ui/native_theme/native_theme.gyp:native_theme',
- ],
- }],
- ],
- },
- ],
- 'conditions': [
- ['OS == "android"', {
- 'targets': [
- {
- 'target_name': 'infobar_delegate_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'infobars/core/infobar_delegate.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/infobars/core/BUILD.gn b/chromium/components/infobars/core/BUILD.gn
index 89eca852f70..4b5bf24eb66 100644
--- a/chromium/components/infobars/core/BUILD.gn
+++ b/chromium/components/infobars/core/BUILD.gn
@@ -44,7 +44,6 @@ static_library("core") {
}
if (is_android) {
- # GYP: //components/infobars.gypi:infobar_delegate_java
java_cpp_enum("infobar_enums_java") {
sources = [
"infobar_delegate.h",
diff --git a/chromium/components/infobars/core/infobar_delegate.cc b/chromium/components/infobars/core/infobar_delegate.cc
index 384a96f4426..4514ed59a76 100644
--- a/chromium/components/infobars/core/infobar_delegate.cc
+++ b/chromium/components/infobars/core/infobar_delegate.cc
@@ -12,7 +12,7 @@
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/vector_icons_public.h"
-#if !defined(OS_MACOSX) && !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !defined(OS_IOS) && !defined(OS_ANDROID)
#include "ui/gfx/color_palette.h"
#include "ui/gfx/paint_vector_icon.h"
#endif
@@ -42,15 +42,13 @@ gfx::VectorIconId InfoBarDelegate::GetVectorIconId() const {
}
gfx::Image InfoBarDelegate::GetIcon() const {
-#if !defined(OS_MACOSX) && !defined(OS_IOS) && !defined(OS_ANDROID)
- if (ui::MaterialDesignController::IsModeMaterial()) {
- gfx::VectorIconId vector_id = GetVectorIconId();
- if (vector_id != gfx::VectorIconId::VECTOR_ICON_NONE) {
- return gfx::Image(gfx::CreateVectorIcon(vector_id, 16,
- GetInfoBarType() == WARNING_TYPE
- ? SkColorSetRGB(0xFF, 0x67, 0)
- : gfx::kGoogleBlue500));
- }
+#if !defined(OS_IOS) && !defined(OS_ANDROID)
+ gfx::VectorIconId vector_id = GetVectorIconId();
+ if (vector_id != gfx::VectorIconId::VECTOR_ICON_NONE) {
+ return gfx::Image(gfx::CreateVectorIcon(vector_id, 16,
+ GetInfoBarType() == WARNING_TYPE
+ ? SkColorSetRGB(0xFF, 0x67, 0)
+ : gfx::kGoogleBlue500));
}
#endif
@@ -94,7 +92,7 @@ NativeAppInfoBarDelegate* InfoBarDelegate::AsNativeAppInfoBarDelegate() {
return nullptr;
}
-PermissionInfobarDelegate* InfoBarDelegate::AsPermissionInfobarDelegate() {
+PermissionInfoBarDelegate* InfoBarDelegate::AsPermissionInfoBarDelegate() {
return nullptr;
}
@@ -136,6 +134,11 @@ MediaThrottleInfoBarDelegate*
InfoBarDelegate::AsMediaThrottleInfoBarDelegate() {
return nullptr;
}
+
+offline_pages::OfflinePageInfoBarDelegate*
+InfoBarDelegate::AsOfflinePageInfoBarDelegate() {
+ return nullptr;
+}
#endif
InfoBarDelegate::InfoBarDelegate() : nav_entry_id_(0) {
diff --git a/chromium/components/infobars/core/infobar_delegate.h b/chromium/components/infobars/core/infobar_delegate.h
index 16d546f926f..a72a3237a05 100644
--- a/chromium/components/infobars/core/infobar_delegate.h
+++ b/chromium/components/infobars/core/infobar_delegate.h
@@ -14,7 +14,7 @@ class ConfirmInfoBarDelegate;
class HungRendererInfoBarDelegate;
class InsecureContentInfoBarDelegate;
class NativeAppInfoBarDelegate;
-class PermissionInfobarDelegate;
+class PermissionInfoBarDelegate;
class PopupBlockedInfoBarDelegate;
class RegisterProtocolHandlerInfoBarDelegate;
class ScreenCaptureInfoBarDelegate;
@@ -24,6 +24,10 @@ class ThreeDAPIInfoBarDelegate;
#if defined(OS_ANDROID)
class MediaStreamInfoBarDelegateAndroid;
class MediaThrottleInfoBarDelegate;
+
+namespace offline_pages {
+class OfflinePageInfoBarDelegate;
+}
#endif
namespace translate {
@@ -85,7 +89,7 @@ class InfoBarDelegate {
THEME_INSTALLED_INFOBAR_DELEGATE = 15,
GEOLOCATION_INFOBAR_DELEGATE_ANDROID = 16,
THREE_D_API_INFOBAR_DELEGATE = 17,
- INSECURE_CONTENT_INFOBAR_DELEGATE = 18,
+ // Removed: INSECURE_CONTENT_INFOBAR_DELEGATE = 18,
MIDI_PERMISSION_INFOBAR_DELEGATE_ANDROID = 19,
PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_ANDROID = 20,
NACL_INFOBAR_DELEGATE = 21,
@@ -124,14 +128,21 @@ class InfoBarDelegate {
NATIVE_APP_OPEN_POLICY_INFOBAR_DELEGATE = 54,
RE_SIGN_IN_INFOBAR_DELEGATE = 55,
SHOW_PASSKIT_INFOBAR_ERROR_DELEGATE = 56,
- READER_MODE_INFOBAR_DELEGATE = 57,
+ READER_MODE_INFOBAR_DELEGATE_IOS = 57,
SYNC_ERROR_INFOBAR_DELEGATE = 58,
- UPGRADE_INFOBAR_DELEGATE = 59,
+ UPGRADE_INFOBAR_DELEGATE_IOS = 59,
CHROME_WINDOW_ERROR = 60,
CONFIRM_DANGEROUS_DOWNLOAD = 61,
// Removed: DESKTOP_SEARCH_REDIRECTION_INFOBAR_DELEGATE = 62,
UPDATE_PASSWORD_INFOBAR_DELEGATE = 63,
DATA_REDUCTION_PROMO_INFOBAR_DELEGATE_ANDROID = 64,
+ AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_ANDROID = 65,
+ SUBRESOURCE_FILTER_INFOBAR_DELEGATE_ANDROID = 66,
+ INSTANT_APPS_INFOBAR_DELEGATE_ANDROID = 67,
+ DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE = 68,
+ SCREEN_CAPTURE_INFOBAR_DELEGATE_ANDROID = 69,
+ GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID = 70,
+ OFFLINE_PAGE_INFOBAR_DELEGATE = 71,
};
// Describes navigation events, used to decide whether infobars should be
@@ -204,7 +215,7 @@ class InfoBarDelegate {
virtual HungRendererInfoBarDelegate* AsHungRendererInfoBarDelegate();
virtual InsecureContentInfoBarDelegate* AsInsecureContentInfoBarDelegate();
virtual NativeAppInfoBarDelegate* AsNativeAppInfoBarDelegate();
- virtual PermissionInfobarDelegate* AsPermissionInfobarDelegate();
+ virtual PermissionInfoBarDelegate* AsPermissionInfoBarDelegate();
virtual PopupBlockedInfoBarDelegate* AsPopupBlockedInfoBarDelegate();
virtual RegisterProtocolHandlerInfoBarDelegate*
AsRegisterProtocolHandlerInfoBarDelegate();
@@ -216,6 +227,8 @@ class InfoBarDelegate {
virtual MediaStreamInfoBarDelegateAndroid*
AsMediaStreamInfoBarDelegateAndroid();
virtual MediaThrottleInfoBarDelegate* AsMediaThrottleInfoBarDelegate();
+ virtual offline_pages::OfflinePageInfoBarDelegate*
+ AsOfflinePageInfoBarDelegate();
#endif
void set_infobar(InfoBar* infobar) { infobar_ = infobar; }
diff --git a/chromium/components/invalidation.gypi b/chromium/components/invalidation.gypi
deleted file mode 100644
index 96e36744d74..00000000000
--- a/chromium/components/invalidation.gypi
+++ /dev/null
@@ -1,269 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/invalidation/public
- 'target_name': 'invalidation_public',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation',
- # TODO(akalin): Remove this (http://crbug.com/133352).
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_proto_cpp',
- ],
- 'export_dependent_settings': [
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'invalidation/public/ack_handle.cc',
- 'invalidation/public/ack_handle.h',
- 'invalidation/public/ack_handler.cc',
- 'invalidation/public/ack_handler.h',
- 'invalidation/public/invalidation.cc',
- 'invalidation/public/invalidation.h',
- 'invalidation/public/invalidation_export.h',
- 'invalidation/public/invalidation_handler.cc',
- 'invalidation/public/invalidation_handler.h',
- 'invalidation/public/invalidation_service.h',
- 'invalidation/public/invalidation_util.cc',
- 'invalidation/public/invalidation_util.h',
- 'invalidation/public/invalidator_state.cc',
- 'invalidation/public/invalidator_state.h',
- 'invalidation/public/object_id_invalidation_map.cc',
- 'invalidation/public/object_id_invalidation_map.h',
- 'invalidation/public/single_object_invalidation_set.cc',
- 'invalidation/public/single_object_invalidation_set.h',
- ],
- },
- {
- # GN version: //components/invalidation/impl
- 'target_name': 'invalidation_impl',
- 'type': 'static_library',
- 'dependencies': [
- 'invalidation_public',
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../google_apis/google_apis.gyp:google_apis',
- '../jingle/jingle.gyp:notifier',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_proto_cpp',
- 'data_use_measurement_core',
- 'gcm_driver',
- 'keyed_service_core',
- 'pref_registry',
- 'prefs/prefs.gyp:prefs',
- 'signin_core_browser',
- ],
- 'export_dependent_settings': [
- 'invalidation_public',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'invalidation/impl/invalidation_logger.cc',
- 'invalidation/impl/invalidation_logger.h',
- 'invalidation/impl/invalidation_logger_observer.h',
- 'invalidation/impl/invalidation_prefs.cc',
- 'invalidation/impl/invalidation_prefs.h',
- 'invalidation/impl/invalidation_service_util.cc',
- 'invalidation/impl/invalidation_service_util.h',
- 'invalidation/impl/invalidation_state_tracker.cc',
- 'invalidation/impl/invalidation_state_tracker.h',
- 'invalidation/impl/invalidation_switches.cc',
- 'invalidation/impl/invalidation_switches.h',
- 'invalidation/impl/invalidator.cc',
- 'invalidation/impl/invalidator.h',
- 'invalidation/impl/invalidator_registrar.cc',
- 'invalidation/impl/invalidator_registrar.h',
- 'invalidation/impl/invalidator_storage.cc',
- 'invalidation/impl/invalidator_storage.h',
- 'invalidation/impl/mock_ack_handler.cc',
- 'invalidation/impl/mock_ack_handler.h',
- 'invalidation/impl/profile_invalidation_provider.cc',
- 'invalidation/impl/profile_invalidation_provider.h',
- 'invalidation/impl/unacked_invalidation_set.cc',
- 'invalidation/impl/unacked_invalidation_set.h',
- ],
- 'conditions': [
- ['OS != "android"', {
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'invalidation/impl/gcm_invalidation_bridge.cc',
- 'invalidation/impl/gcm_invalidation_bridge.h',
- 'invalidation/impl/gcm_network_channel.cc',
- 'invalidation/impl/gcm_network_channel.h',
- 'invalidation/impl/gcm_network_channel_delegate.h',
- 'invalidation/impl/invalidation_notifier.cc',
- 'invalidation/impl/invalidation_notifier.h',
- 'invalidation/impl/non_blocking_invalidator.cc',
- 'invalidation/impl/non_blocking_invalidator.h',
- 'invalidation/impl/notifier_reason_util.cc',
- 'invalidation/impl/notifier_reason_util.h',
- 'invalidation/impl/p2p_invalidator.cc',
- 'invalidation/impl/p2p_invalidator.h',
- 'invalidation/impl/push_client_channel.cc',
- 'invalidation/impl/push_client_channel.h',
- 'invalidation/impl/registration_manager.cc',
- 'invalidation/impl/registration_manager.h',
- 'invalidation/impl/state_writer.h',
- 'invalidation/impl/sync_invalidation_listener.cc',
- 'invalidation/impl/sync_invalidation_listener.h',
- 'invalidation/impl/sync_system_resources.cc',
- 'invalidation/impl/sync_system_resources.h',
- 'invalidation/impl/ticl_invalidation_service.cc',
- 'invalidation/impl/ticl_invalidation_service.h',
- 'invalidation/impl/ticl_profile_settings_provider.cc',
- 'invalidation/impl/ticl_profile_settings_provider.h',
- 'invalidation/impl/ticl_settings_provider.cc',
- 'invalidation/impl/ticl_settings_provider.h',
- ],
- }],
- ['OS == "android"', {
- 'dependencies': [
- 'invalidation_jni_headers',
- ],
- 'sources': [
- 'invalidation/impl/android/component_jni_registrar.cc',
- 'invalidation/impl/android/component_jni_registrar.h',
- 'invalidation/impl/invalidation_service_android.cc',
- 'invalidation/impl/invalidation_service_android.h',
- ],
- }],
- ],
- },
- {
- # GN version: //components/invalidation:test_support
- 'target_name': 'invalidation_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../google_apis/google_apis.gyp:google_apis',
- '../jingle/jingle.gyp:notifier',
- '../jingle/jingle.gyp:notifier_test_util',
- '../net/net.gyp:net',
- '../testing/gmock.gyp:gmock',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_proto_cpp',
- 'gcm_driver_test_support',
- 'keyed_service_core',
- ],
- 'export_dependent_settings': [
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_proto_cpp',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'invalidation/impl/fake_invalidation_handler.cc',
- 'invalidation/impl/fake_invalidation_handler.h',
- 'invalidation/impl/fake_invalidation_service.cc',
- 'invalidation/impl/fake_invalidation_service.h',
- 'invalidation/impl/fake_invalidation_state_tracker.cc',
- 'invalidation/impl/fake_invalidation_state_tracker.h',
- 'invalidation/impl/fake_invalidator.cc',
- 'invalidation/impl/fake_invalidator.h',
- 'invalidation/impl/invalidation_service_test_template.cc',
- 'invalidation/impl/invalidation_service_test_template.h',
- 'invalidation/impl/invalidation_test_util.cc',
- 'invalidation/impl/invalidation_test_util.h',
- 'invalidation/impl/invalidator_test_template.cc',
- 'invalidation/impl/invalidator_test_template.h',
- 'invalidation/impl/object_id_invalidation_map_test_util.cc',
- 'invalidation/impl/object_id_invalidation_map_test_util.h',
- 'invalidation/impl/unacked_invalidation_set_test_util.cc',
- 'invalidation/impl/unacked_invalidation_set_test_util.h',
- ],
- 'conditions': [
- ['OS != "android"', {
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'invalidation/impl/p2p_invalidation_service.cc',
- 'invalidation/impl/p2p_invalidation_service.h',
- ],
- }],
- ['OS == "android"', {
- 'dependencies': [
- 'invalidation_jni_headers',
- ],
- }],
- ],
- },
- ],
- 'conditions': [
- ['OS == "android"', {
- 'targets': [
- {
- 'target_name': 'invalidation_java',
- 'type': 'none',
- 'dependencies': [
- 'invalidation_proto_java',
- '../base/base.gyp:base',
- '../sync/sync.gyp:sync_java',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_javalib',
- ],
- 'variables': {
- 'java_in_dir': 'invalidation/impl/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'invalidation_proto_java',
- 'type': 'none',
- 'sources': [
- 'invalidation/impl/android/proto/serialized_invalidation.proto',
- ],
- 'includes': [ '../build/protoc_java.gypi' ],
- },
- {
- 'target_name': 'invalidation_javatests',
- 'type': 'none',
- 'dependencies': [
- 'invalidation_java',
- '../base/base.gyp:base_java_test_support',
- '../content/content_shell_and_tests.gyp:content_java_test_support',
- ],
- 'variables': {
- 'java_in_dir': 'invalidation/impl/android/javatests',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'invalidation_jni_headers',
- 'type': 'none',
- 'sources': [
- 'invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationService.java',
- ],
- 'variables': {
- 'jni_gen_package': 'components/invalidation',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- 'target_name': 'components_invalidation_impl_junit_tests',
- 'type': 'none',
- 'dependencies': [
- '../testing/android/junit/junit_test.gyp:junit_test_support',
- ],
- 'variables': {
- 'main_class': 'org.chromium.testing.local.JunitTestMain',
- 'src_paths': [
- '../testing/android/junit/DummyTest.java',
- ],
- 'wrapper_script_name': 'helper/<(_target_name)',
- },
- 'includes': [ '../build/host_jar.gypi' ],
- },
- ],
- },
- ],
- ],
-}
diff --git a/chromium/components/invalidation/impl/BUILD.gn b/chromium/components/invalidation/impl/BUILD.gn
index c984af957ee..98934dd2eb1 100644
--- a/chromium/components/invalidation/impl/BUILD.gn
+++ b/chromium/components/invalidation/impl/BUILD.gn
@@ -6,7 +6,7 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-source_set("impl") {
+static_library("impl") {
sources = [
"invalidation_logger.cc",
"invalidation_logger.h",
@@ -207,7 +207,8 @@ if (is_android) {
deps = [
":proto_java",
"//base:base_java",
- "//sync/android:sync_java",
+ "//components/signin/core/browser/android:java",
+ "//components/sync/android:sync_java",
"//third_party/android_protobuf:protobuf_nano_javalib",
"//third_party/cacheinvalidation:cacheinvalidation_javalib",
"//third_party/cacheinvalidation:cacheinvalidation_proto_java",
@@ -226,11 +227,13 @@ if (is_android) {
]
}
android_library("javatests") {
+ testonly = true
deps = [
":java",
"//base:base_java",
"//base:base_java_test_support",
- "//sync/android:sync_java",
+ "//components/signin/core/browser/android:java",
+ "//components/sync/android:sync_java",
"//third_party/cacheinvalidation:cacheinvalidation_javalib",
"//third_party/cacheinvalidation:cacheinvalidation_proto_java",
]
diff --git a/chromium/components/json_schema.gypi b/chromium/components/json_schema.gypi
deleted file mode 100644
index fdafc98005a..00000000000
--- a/chromium/components/json_schema.gypi
+++ /dev/null
@@ -1,25 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'json_schema',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../third_party/re2/re2.gyp:re2'
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'json_schema/json_schema_constants.cc',
- 'json_schema/json_schema_constants.h',
- 'json_schema/json_schema_validator.cc',
- 'json_schema/json_schema_validator.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/json_schema/BUILD.gn b/chromium/components/json_schema/BUILD.gn
index 68502ea3f8a..ec9f8703dcf 100644
--- a/chromium/components/json_schema/BUILD.gn
+++ b/chromium/components/json_schema/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("json_schema") {
+static_library("json_schema") {
sources = [
"json_schema_constants.cc",
"json_schema_constants.h",
diff --git a/chromium/components/json_schema/json_schema_validator_unittest_base.cc b/chromium/components/json_schema/json_schema_validator_unittest_base.cc
index 2c4c4e17d52..a1da991f954 100644
--- a/chromium/components/json_schema/json_schema_validator_unittest_base.cc
+++ b/chromium/components/json_schema/json_schema_validator_unittest_base.cc
@@ -13,6 +13,7 @@
#include "base/files/file_util.h"
#include "base/json/json_file_value_serializer.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
@@ -98,7 +99,7 @@ void JSONSchemaValidatorTestBase::TestComplex() {
ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
instance->Remove(instance->GetSize() - 1, NULL);
ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
- instance->Append(new base::DictionaryValue());
+ instance->Append(base::MakeUnique<base::DictionaryValue>());
ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "1",
JSONSchemaValidator::FormatErrorMessage(
JSONSchemaValidator::kInvalidType,
diff --git a/chromium/components/keyed_service.gypi b/chromium/components/keyed_service.gypi
deleted file mode 100644
index 5bfef7023c9..00000000000
--- a/chromium/components/keyed_service.gypi
+++ /dev/null
@@ -1,111 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/keyed_service/core:core
- 'target_name': 'keyed_service_core',
- 'type': '<(component)',
- 'defines': [
- 'KEYED_SERVICE_IMPLEMENTATION',
- ],
- 'include_dirs': [
- '..',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'prefs/prefs.gyp:prefs',
- 'user_prefs',
- ],
- 'sources': [
- 'keyed_service/core/dependency_graph.cc',
- 'keyed_service/core/dependency_graph.h',
- 'keyed_service/core/dependency_manager.cc',
- 'keyed_service/core/dependency_manager.h',
- 'keyed_service/core/dependency_node.h',
- 'keyed_service/core/keyed_service.cc',
- 'keyed_service/core/keyed_service.h',
- 'keyed_service/core/keyed_service_base_factory.cc',
- 'keyed_service/core/keyed_service_base_factory.h',
- 'keyed_service/core/keyed_service_export.h',
- 'keyed_service/core/keyed_service_factory.cc',
- 'keyed_service/core/keyed_service_factory.h',
- 'keyed_service/core/keyed_service_shutdown_notifier.cc',
- 'keyed_service/core/keyed_service_shutdown_notifier.h',
- 'keyed_service/core/refcounted_keyed_service.cc',
- 'keyed_service/core/refcounted_keyed_service.h',
- 'keyed_service/core/refcounted_keyed_service_factory.cc',
- 'keyed_service/core/refcounted_keyed_service_factory.h',
- 'keyed_service/core/service_access_type.h',
- ],
- },
- ],
- 'conditions': [
- ['OS != "ios"', {
- 'targets': [
- {
- # GN version: //components/keyed_service/content:content
- 'target_name': 'keyed_service_content',
- 'type': '<(component)',
- 'defines': [
- 'KEYED_SERVICE_IMPLEMENTATION',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../content/content.gyp:content_common',
- 'keyed_service_core',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'keyed_service/content/browser_context_dependency_manager.cc',
- 'keyed_service/content/browser_context_dependency_manager.h',
- 'keyed_service/content/browser_context_keyed_base_factory.cc',
- 'keyed_service/content/browser_context_keyed_base_factory.h',
- 'keyed_service/content/browser_context_keyed_service_factory.cc',
- 'keyed_service/content/browser_context_keyed_service_factory.h',
- 'keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.cc',
- 'keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h',
- 'keyed_service/content/refcounted_browser_context_keyed_service_factory.cc',
- 'keyed_service/content/refcounted_browser_context_keyed_service_factory.h',
- ],
- }],
- }],
- ['OS == "ios"', {
- 'targets': [
- {
- # GN version: //components/keyed_service/ios
- 'target_name': 'keyed_service_ios',
- 'type': '<(component)',
- 'defines': [
- 'KEYED_SERVICE_IMPLEMENTATION',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../ios/web/ios_web.gyp:ios_web',
- 'keyed_service_core',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'keyed_service/ios/browser_state_dependency_manager.cc',
- 'keyed_service/ios/browser_state_dependency_manager.h',
- 'keyed_service/ios/browser_state_keyed_service_factory.cc',
- 'keyed_service/ios/browser_state_keyed_service_factory.h',
- 'keyed_service/ios/refcounted_browser_state_keyed_service_factory.cc',
- 'keyed_service/ios/refcounted_browser_state_keyed_service_factory.h',
- ],
- }],
- }],
- ],
-}
diff --git a/chromium/components/keyed_service/content/BUILD.gn b/chromium/components/keyed_service/content/BUILD.gn
index 2cc7eca103c..deadc76bc67 100644
--- a/chromium/components/keyed_service/content/BUILD.gn
+++ b/chromium/components/keyed_service/content/BUILD.gn
@@ -24,10 +24,13 @@ component("content") {
defines = [ "KEYED_SERVICE_IMPLEMENTATION" ]
- deps = [
+ public_deps = [
"//base",
- "//base/third_party/dynamic_annotations",
"//components/keyed_service/core",
+ ]
+
+ deps = [
+ "//base/third_party/dynamic_annotations",
"//components/pref_registry",
"//components/user_prefs",
"//content/public/browser",
diff --git a/chromium/components/keyed_service/core/dependency_manager.cc b/chromium/components/keyed_service/core/dependency_manager.cc
index 4f35244e04f..3cc264beddd 100644
--- a/chromium/components/keyed_service/core/dependency_manager.cc
+++ b/chromium/components/keyed_service/core/dependency_manager.cc
@@ -41,7 +41,7 @@ void DependencyManager::RegisterPrefsForServices(
NOTREACHED();
}
- for (const auto& dependency_node : construction_order) {
+ for (auto* dependency_node : construction_order) {
KeyedServiceBaseFactory* factory =
static_cast<KeyedServiceBaseFactory*>(dependency_node);
factory->RegisterPrefsIfNecessaryForContext(context, pref_registry);
@@ -63,7 +63,7 @@ void DependencyManager::CreateContextServices(base::SupportsUserData* context,
DumpContextDependencies(context);
#endif
- for (const auto& dependency_node : construction_order) {
+ for (auto* dependency_node : construction_order) {
KeyedServiceBaseFactory* factory =
static_cast<KeyedServiceBaseFactory*>(dependency_node);
if (is_testing_context && factory->ServiceIsNULLWhileTesting() &&
@@ -86,7 +86,7 @@ void DependencyManager::DestroyContextServices(
DumpContextDependencies(context);
#endif
- for (const auto& dependency_node : destruction_order) {
+ for (auto* dependency_node : destruction_order) {
KeyedServiceBaseFactory* factory =
static_cast<KeyedServiceBaseFactory*>(dependency_node);
factory->ContextShutdown(context);
@@ -97,7 +97,7 @@ void DependencyManager::DestroyContextServices(
dead_context_pointers_.insert(context);
#endif
- for (const auto& dependency_node : destruction_order) {
+ for (auto* dependency_node : destruction_order) {
KeyedServiceBaseFactory* factory =
static_cast<KeyedServiceBaseFactory*>(dependency_node);
factory->ContextDestroyed(context);
diff --git a/chromium/components/keyed_service/core/keyed_service_factory.cc b/chromium/components/keyed_service/core/keyed_service_factory.cc
index 7fe140779bc..938ddc5d41b 100644
--- a/chromium/components/keyed_service/core/keyed_service_factory.cc
+++ b/chromium/components/keyed_service/core/keyed_service_factory.cc
@@ -97,7 +97,7 @@ KeyedService* KeyedServiceFactory::GetServiceForContext(
void KeyedServiceFactory::Associate(base::SupportsUserData* context,
std::unique_ptr<KeyedService> service) {
- DCHECK(!ContainsKey(mapping_, context));
+ DCHECK(!base::ContainsKey(mapping_, context));
mapping_.insert(std::make_pair(context, service.release()));
}
diff --git a/chromium/components/keyed_service/core/refcounted_keyed_service.h b/chromium/components/keyed_service/core/refcounted_keyed_service.h
index 31815d6f8ff..891fc289866 100644
--- a/chromium/components/keyed_service/core/refcounted_keyed_service.h
+++ b/chromium/components/keyed_service/core/refcounted_keyed_service.h
@@ -51,7 +51,7 @@ class KEYED_SERVICE_EXPORT RefcountedKeyedService
// If you need your service to be deleted on a specific thread (for example,
// you're converting a service that used content::DeleteOnThread<IO>), then
// use this constructor with a reference to the SingleThreadTaskRunner (you
- // can get it from content::BrowserThread::GetMessageLoopProxyForThread).
+ // can get it from content::BrowserThread::GetTaskRunnerForThread).
explicit RefcountedKeyedService(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
diff --git a/chromium/components/keyed_service/core/refcounted_keyed_service_factory.cc b/chromium/components/keyed_service/core/refcounted_keyed_service_factory.cc
index d33340b2d53..7c44c2ce389 100644
--- a/chromium/components/keyed_service/core/refcounted_keyed_service_factory.cc
+++ b/chromium/components/keyed_service/core/refcounted_keyed_service_factory.cc
@@ -89,7 +89,7 @@ RefcountedKeyedServiceFactory::GetServiceForContext(
void RefcountedKeyedServiceFactory::Associate(
base::SupportsUserData* context,
const scoped_refptr<RefcountedKeyedService>& service) {
- DCHECK(!ContainsKey(mapping_, context));
+ DCHECK(!base::ContainsKey(mapping_, context));
mapping_.insert(std::make_pair(context, service));
}
diff --git a/chromium/components/language_usage_metrics.gypi b/chromium/components/language_usage_metrics.gypi
deleted file mode 100644
index e150a1bba9e..00000000000
--- a/chromium/components/language_usage_metrics.gypi
+++ /dev/null
@@ -1,22 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'language_usage_metrics',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'language_usage_metrics/language_usage_metrics.cc',
- 'language_usage_metrics/language_usage_metrics.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/language_usage_metrics/BUILD.gn b/chromium/components/language_usage_metrics/BUILD.gn
index 7352845116e..e5f9689e2e2 100644
--- a/chromium/components/language_usage_metrics/BUILD.gn
+++ b/chromium/components/language_usage_metrics/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("language_usage_metrics") {
+static_library("language_usage_metrics") {
sources = [
"language_usage_metrics.cc",
"language_usage_metrics.h",
diff --git a/chromium/components/leveldb/BUILD.gn b/chromium/components/leveldb/BUILD.gn
index fb7068f9bd6..082ab788bb9 100644
--- a/chromium/components/leveldb/BUILD.gn
+++ b/chromium/components/leveldb/BUILD.gn
@@ -2,11 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//mojo/public/mojo_application.gni")
-import("//mojo/public/mojo_application_manifest.gni")
+import("//services/shell/public/cpp/service.gni")
+import("//services/shell/public/service_manifest.gni")
import("//testing/test.gni")
-source_set("lib") {
+static_library("lib") {
sources = [
"env_mojo.cc",
"env_mojo.h",
@@ -18,10 +18,13 @@ source_set("lib") {
"leveldb_service_impl.h",
]
- deps = [
+ public_deps = [
"//components/filesystem/public/interfaces",
"//components/leveldb/public/cpp",
"//components/leveldb/public/interfaces",
+ ]
+
+ deps = [
"//mojo/common",
"//mojo/public/cpp/system",
"//services/shell/public/cpp",
@@ -29,7 +32,7 @@ source_set("lib") {
]
}
-mojo_native_application("leveldb") {
+service("leveldb") {
sources = [
"leveldb_app.cc",
"leveldb_app.h",
@@ -51,8 +54,8 @@ mojo_native_application("leveldb") {
]
}
-mojo_application_manifest("manifest") {
- application_name = "leveldb"
+service_manifest("manifest") {
+ name = "leveldb"
source = "manifest.json"
}
@@ -70,7 +73,7 @@ test("leveldb_service_unittests") {
"//mojo/common",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
- "//services/shell/public/cpp:shell_test_support",
+ "//services/shell/public/cpp:service_test_support",
"//services/shell/public/cpp:sources",
"//services/shell/public/cpp/test:run_all_shelltests",
"//third_party/leveldatabase",
@@ -83,8 +86,8 @@ test("leveldb_service_unittests") {
]
}
-mojo_application_manifest("test_manifest") {
+service_manifest("test_manifest") {
type = "exe"
- application_name = "leveldb_service_unittests"
+ name = "leveldb_service_unittests"
source = "test_manifest.json"
}
diff --git a/chromium/components/leveldb/env_mojo.cc b/chromium/components/leveldb/env_mojo.cc
index 54681d0d142..4c0629a9c67 100644
--- a/chromium/components/leveldb/env_mojo.cc
+++ b/chromium/components/leveldb/env_mojo.cc
@@ -8,6 +8,7 @@
#include <memory>
+#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
#include "third_party/leveldatabase/chromium_logger.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
@@ -137,10 +138,12 @@ class MojoWritableFile : public leveldb::WritableFile {
dir_(dir),
thread_(thread) {
base::FilePath path = base::FilePath::FromUTF8Unsafe(fname);
- if (path.BaseName().AsUTF8Unsafe().find("MANIFEST") == 0)
+ if (base::StartsWith(path.BaseName().AsUTF8Unsafe(), "MANIFEST",
+ base::CompareCase::SENSITIVE)) {
file_type_ = kManifest;
- else if (path.MatchesExtension(table_extension))
+ } else if (path.MatchesExtension(table_extension)) {
file_type_ = kTable;
+ }
parent_dir_ =
base::FilePath::FromUTF8Unsafe(fname).DirName().AsUTF8Unsafe();
}
@@ -365,15 +368,15 @@ Status MojoEnv::GetTestDirectory(std::string* path) {
Status MojoEnv::NewLogger(const std::string& fname, Logger** result) {
TRACE_EVENT1("leveldb", "MojoEnv::NewLogger", "fname", fname);
- std::unique_ptr<base::File> f(new base::File(thread_->OpenFileHandle(
+ base::File f(thread_->OpenFileHandle(
dir_, mojo::String::From(fname),
- filesystem::mojom::kCreateAlways | filesystem::mojom::kFlagWrite)));
- if (!f->IsValid()) {
+ filesystem::mojom::kCreateAlways | filesystem::mojom::kFlagWrite));
+ if (!f.IsValid()) {
*result = NULL;
return MakeIOError(fname, "Unable to create log file",
- leveldb_env::kNewLogger, f->error_details());
+ leveldb_env::kNewLogger, f.error_details());
} else {
- *result = new leveldb::ChromiumLogger(f.release());
+ *result = new leveldb::ChromiumLogger(std::move(f));
return Status::OK();
}
}
diff --git a/chromium/components/leveldb/leveldb.gyp b/chromium/components/leveldb/leveldb.gyp
deleted file mode 100644
index ba1d2f80cad..00000000000
--- a/chromium/components/leveldb/leveldb.gyp
+++ /dev/null
@@ -1,80 +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.
-
-{
- 'variables': {
- # This turns on e.g. the filename-based detection of which
- # platforms to include source files on (e.g. files ending in
- # _mac.h or _mac.cc are only compiled on MacOSX).
- 'chromium_code': 1,
- },
- 'targets': [
- {
- # GN version: //components/leveldb:lib
- 'target_name': 'leveldb_lib',
- 'type': 'static_library',
- 'include_dirs': [
- '../..',
- ],
- 'sources': [
- 'env_mojo.cc',
- 'env_mojo.h',
- 'leveldb_database_impl.cc',
- 'leveldb_database_impl.h',
- 'leveldb_mojo_proxy.cc',
- 'leveldb_mojo_proxy.h',
- 'leveldb_service_impl.cc',
- 'leveldb_service_impl.h',
- ],
- 'dependencies': [
- 'leveldb_public_lib',
- '../../components/filesystem/filesystem.gyp:filesystem_lib',
- '../../mojo/mojo_public.gyp:mojo_cpp_bindings',
- '../../services/shell/shell_public.gyp:shell_public',
- '../../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
- ]
- },
- {
- # GN version: //components/leveldb/public/cpp:cpp
- 'target_name': 'leveldb_public_lib',
- 'type': 'static_library',
- 'sources': [
- 'public/cpp/remote_iterator.cc',
- 'public/cpp/remote_iterator.h',
- 'public/cpp/util.cc',
- 'public/cpp/util.h',
- ],
- 'dependencies': [
- 'leveldb_bindings_mojom',
- '../../mojo/mojo_edk.gyp:mojo_system_impl',
- '../../mojo/mojo_public.gyp:mojo_cpp_bindings',
- '../../services/shell/shell_public.gyp:shell_public',
- '../../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
- ]
- },
- {
- # GN version: //components/leveldb/public/interfaces
- 'target_name': 'leveldb_bindings',
- 'type': 'static_library',
- 'dependencies': [
- 'leveldb_bindings_mojom',
- ],
- },
- {
- 'target_name': 'leveldb_bindings_mojom',
- 'type': 'none',
- 'variables': {
- 'mojom_files': [
- 'public/interfaces/leveldb.mojom',
- ],
- },
- 'dependencies': [
- '../../components/filesystem/filesystem.gyp:filesystem_bindings_mojom',
- ],
- 'includes': [
- '../../mojo/mojom_bindings_generator_explicit.gypi',
- ],
- }
- ],
-}
diff --git a/chromium/components/leveldb/leveldb_app.cc b/chromium/components/leveldb/leveldb_app.cc
index 17afe655688..55eb5908b4c 100644
--- a/chromium/components/leveldb/leveldb_app.cc
+++ b/chromium/components/leveldb/leveldb_app.cc
@@ -4,9 +4,9 @@
#include "components/leveldb/leveldb_app.h"
-#include "base/message_loop/message_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "components/leveldb/leveldb_service_impl.h"
-#include "services/shell/public/cpp/connection.h"
+#include "services/shell/public/cpp/interface_registry.h"
namespace leveldb {
@@ -14,22 +14,20 @@ LevelDBApp::LevelDBApp() {}
LevelDBApp::~LevelDBApp() {}
-void LevelDBApp::Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) {
- tracing_.Initialize(connector, identity.name());
+void LevelDBApp::OnStart(const shell::Identity& identity) {
+ tracing_.Initialize(connector(), identity.name());
}
-bool LevelDBApp::AcceptConnection(shell::Connection* connection) {
- connection->AddInterface<mojom::LevelDBService>(this);
+bool LevelDBApp::OnConnect(const shell::Identity& remote_identity,
+ shell::InterfaceRegistry* registry) {
+ registry->AddInterface<mojom::LevelDBService>(this);
return true;
}
-void LevelDBApp::Create(shell::Connection* connection,
+void LevelDBApp::Create(const shell::Identity& remote_identity,
leveldb::mojom::LevelDBServiceRequest request) {
if (!service_)
- service_.reset(
- new LevelDBServiceImpl(base::MessageLoop::current()->task_runner()));
+ service_.reset(new LevelDBServiceImpl(base::ThreadTaskRunnerHandle::Get()));
bindings_.AddBinding(service_.get(), std::move(request));
}
diff --git a/chromium/components/leveldb/leveldb_app.h b/chromium/components/leveldb/leveldb_app.h
index d53e9373a31..28706c1bf54 100644
--- a/chromium/components/leveldb/leveldb_app.h
+++ b/chromium/components/leveldb/leveldb_app.h
@@ -10,29 +10,28 @@
#include "components/leveldb/public/interfaces/leveldb.mojom.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/shell/public/cpp/interface_factory.h"
-#include "services/shell/public/cpp/shell_client.h"
-#include "services/tracing/public/cpp/tracing_impl.h"
+#include "services/shell/public/cpp/service.h"
+#include "services/tracing/public/cpp/provider.h"
namespace leveldb {
-class LevelDBApp : public shell::ShellClient,
+class LevelDBApp : public shell::Service,
public shell::InterfaceFactory<mojom::LevelDBService> {
public:
LevelDBApp();
~LevelDBApp() override;
private:
- // |ShellClient| override:
- void Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) override;
- bool AcceptConnection(shell::Connection* connection) override;
+ // |Service| override:
+ void OnStart(const shell::Identity& identity) override;
+ bool OnConnect(const shell::Identity& remote_identity,
+ shell::InterfaceRegistry* registry) override;
// |InterfaceFactory<mojom::LevelDBService>| implementation:
- void Create(shell::Connection* connection,
+ void Create(const shell::Identity& remote_identity,
leveldb::mojom::LevelDBServiceRequest request) override;
- mojo::TracingImpl tracing_;
+ tracing::Provider tracing_;
std::unique_ptr<mojom::LevelDBService> service_;
mojo::BindingSet<mojom::LevelDBService> bindings_;
diff --git a/chromium/components/leveldb/leveldb_database_impl.cc b/chromium/components/leveldb/leveldb_database_impl.cc
index f5d618cc190..e94fac25b17 100644
--- a/chromium/components/leveldb/leveldb_database_impl.cc
+++ b/chromium/components/leveldb/leveldb_database_impl.cc
@@ -7,10 +7,10 @@
#include <map>
#include <string>
+#include "base/optional.h"
#include "base/rand_util.h"
#include "components/leveldb/env_mojo.h"
#include "components/leveldb/public/cpp/util.h"
-#include "mojo/common/common_type_converters.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
@@ -46,12 +46,9 @@ leveldb::Status ForEachWithPrefix(leveldb::DB* db,
} // namespace
LevelDBDatabaseImpl::LevelDBDatabaseImpl(
- leveldb::mojom::LevelDBDatabaseRequest request,
std::unique_ptr<leveldb::Env> environment,
std::unique_ptr<leveldb::DB> db)
- : binding_(this, std::move(request)),
- environment_(std::move(environment)),
- db_(std::move(db)) {}
+ : environment_(std::move(environment)), db_(std::move(db)) {}
LevelDBDatabaseImpl::~LevelDBDatabaseImpl() {
for (auto& p : iterator_map_)
@@ -60,15 +57,15 @@ LevelDBDatabaseImpl::~LevelDBDatabaseImpl() {
db_->ReleaseSnapshot(p.second);
}
-void LevelDBDatabaseImpl::Put(mojo::Array<uint8_t> key,
- mojo::Array<uint8_t> value,
+void LevelDBDatabaseImpl::Put(const std::vector<uint8_t>& key,
+ const std::vector<uint8_t>& value,
const PutCallback& callback) {
leveldb::Status status =
db_->Put(leveldb::WriteOptions(), GetSliceFor(key), GetSliceFor(value));
callback.Run(LeveldbStatusToError(status));
}
-void LevelDBDatabaseImpl::Delete(mojo::Array<uint8_t> key,
+void LevelDBDatabaseImpl::Delete(const std::vector<uint8_t>& key,
const DeleteCallback& callback) {
leveldb::Status status =
db_->Delete(leveldb::WriteOptions(), GetSliceFor(key));
@@ -76,7 +73,7 @@ void LevelDBDatabaseImpl::Delete(mojo::Array<uint8_t> key,
}
void LevelDBDatabaseImpl::DeletePrefixed(
- mojo::Array<uint8_t> key_prefix,
+ const std::vector<uint8_t>& key_prefix,
const DeletePrefixedCallback& callback) {
leveldb::WriteBatch batch;
leveldb::Status status = DeletePrefixedHelper(
@@ -87,15 +84,19 @@ void LevelDBDatabaseImpl::DeletePrefixed(
}
void LevelDBDatabaseImpl::Write(
- mojo::Array<mojom::BatchedOperationPtr> operations,
+ std::vector<mojom::BatchedOperationPtr> operations,
const WriteCallback& callback) {
leveldb::WriteBatch batch;
for (size_t i = 0; i < operations.size(); ++i) {
switch (operations[i]->type) {
case mojom::BatchOperationType::PUT_KEY: {
- batch.Put(GetSliceFor(operations[i]->key),
- GetSliceFor(operations[i]->value));
+ if (operations[i]->value) {
+ batch.Put(GetSliceFor(operations[i]->key),
+ GetSliceFor(*(operations[i]->value)));
+ } else {
+ batch.Put(GetSliceFor(operations[i]->key), leveldb::Slice());
+ }
break;
}
case mojom::BatchOperationType::DELETE_KEY: {
@@ -113,23 +114,23 @@ void LevelDBDatabaseImpl::Write(
callback.Run(LeveldbStatusToError(status));
}
-void LevelDBDatabaseImpl::Get(mojo::Array<uint8_t> key,
+void LevelDBDatabaseImpl::Get(const std::vector<uint8_t>& key,
const GetCallback& callback) {
std::string value;
leveldb::Status status =
db_->Get(leveldb::ReadOptions(), GetSliceFor(key), &value);
- callback.Run(LeveldbStatusToError(status), mojo::Array<uint8_t>::From(value));
+ callback.Run(LeveldbStatusToError(status), StdStringToUint8Vector(value));
}
-void LevelDBDatabaseImpl::GetPrefixed(mojo::Array<uint8_t> key_prefix,
+void LevelDBDatabaseImpl::GetPrefixed(const std::vector<uint8_t>& key_prefix,
const GetPrefixedCallback& callback) {
- mojo::Array<mojom::KeyValuePtr> data;
+ std::vector<mojom::KeyValuePtr> data;
leveldb::Status status = ForEachWithPrefix(
db_.get(), GetSliceFor(key_prefix),
[&data](const leveldb::Slice& key, const leveldb::Slice& value) {
mojom::KeyValuePtr kv = mojom::KeyValue::New();
- kv->key = GetArrayFor(key);
- kv->value = GetArrayFor(value);
+ kv->key = GetVectorFor(key);
+ kv->value = GetVectorFor(value);
data.push_back(std::move(kv));
});
callback.Run(LeveldbStatusToError(status), std::move(data));
@@ -151,13 +152,13 @@ void LevelDBDatabaseImpl::ReleaseSnapshot(uint64_t snapshot_id) {
}
void LevelDBDatabaseImpl::GetFromSnapshot(uint64_t snapshot_id,
- mojo::Array<uint8_t> key,
+ const std::vector<uint8_t>& key,
const GetCallback& callback) {
// If the snapshot id is invalid, send back invalid argument
auto it = snapshot_map_.find(snapshot_id);
if (it == snapshot_map_.end()) {
callback.Run(mojom::DatabaseError::INVALID_ARGUMENT,
- mojo::Array<uint8_t>());
+ std::vector<uint8_t>());
return;
}
@@ -165,7 +166,7 @@ void LevelDBDatabaseImpl::GetFromSnapshot(uint64_t snapshot_id,
leveldb::ReadOptions options;
options.snapshot = it->second;
leveldb::Status status = db_->Get(options, GetSliceFor(key), &value);
- callback.Run(LeveldbStatusToError(status), mojo::Array<uint8_t>::From(value));
+ callback.Run(LeveldbStatusToError(status), StdStringToUint8Vector(value));
}
void LevelDBDatabaseImpl::NewIterator(const NewIteratorCallback& callback) {
@@ -207,8 +208,8 @@ void LevelDBDatabaseImpl::IteratorSeekToFirst(
const IteratorSeekToFirstCallback& callback) {
auto it = iterator_map_.find(iterator_id);
if (it == iterator_map_.end()) {
- callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, nullptr,
- nullptr);
+ callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, base::nullopt,
+ base::nullopt);
return;
}
@@ -222,8 +223,8 @@ void LevelDBDatabaseImpl::IteratorSeekToLast(
const IteratorSeekToLastCallback& callback) {
auto it = iterator_map_.find(iterator_id);
if (it == iterator_map_.end()) {
- callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, nullptr,
- nullptr);
+ callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, base::nullopt,
+ base::nullopt);
return;
}
@@ -234,12 +235,12 @@ void LevelDBDatabaseImpl::IteratorSeekToLast(
void LevelDBDatabaseImpl::IteratorSeek(
uint64_t iterator_id,
- mojo::Array<uint8_t> target,
+ const std::vector<uint8_t>& target,
const IteratorSeekToLastCallback& callback) {
auto it = iterator_map_.find(iterator_id);
if (it == iterator_map_.end()) {
- callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, nullptr,
- nullptr);
+ callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, base::nullopt,
+ base::nullopt);
return;
}
@@ -252,8 +253,8 @@ void LevelDBDatabaseImpl::IteratorNext(uint64_t iterator_id,
const IteratorNextCallback& callback) {
auto it = iterator_map_.find(iterator_id);
if (it == iterator_map_.end()) {
- callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, nullptr,
- nullptr);
+ callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, base::nullopt,
+ base::nullopt);
return;
}
@@ -266,8 +267,8 @@ void LevelDBDatabaseImpl::IteratorPrev(uint64_t iterator_id,
const IteratorPrevCallback& callback) {
auto it = iterator_map_.find(iterator_id);
if (it == iterator_map_.end()) {
- callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, nullptr,
- nullptr);
+ callback.Run(false, mojom::DatabaseError::INVALID_ARGUMENT, base::nullopt,
+ base::nullopt);
return;
}
@@ -280,12 +281,13 @@ void LevelDBDatabaseImpl::ReplyToIteratorMessage(
leveldb::Iterator* it,
const IteratorSeekToFirstCallback& callback) {
if (!it->Valid()) {
- callback.Run(false, LeveldbStatusToError(it->status()), nullptr, nullptr);
+ callback.Run(false, LeveldbStatusToError(it->status()), base::nullopt,
+ base::nullopt);
return;
}
- callback.Run(true, LeveldbStatusToError(it->status()), GetArrayFor(it->key()),
- GetArrayFor(it->value()));
+ callback.Run(true, LeveldbStatusToError(it->status()),
+ GetVectorFor(it->key()), GetVectorFor(it->value()));
}
leveldb::Status LevelDBDatabaseImpl::DeletePrefixedHelper(
diff --git a/chromium/components/leveldb/leveldb_database_impl.h b/chromium/components/leveldb/leveldb_database_impl.h
index e16b4bf0e79..23e7bce0c6a 100644
--- a/chromium/components/leveldb/leveldb_database_impl.h
+++ b/chromium/components/leveldb/leveldb_database_impl.h
@@ -9,7 +9,6 @@
#include "components/leveldb/public/interfaces/leveldb.mojom.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
namespace leveldb {
@@ -19,28 +18,28 @@ class MojoEnv;
// The backing to a database object that we pass to our called.
class LevelDBDatabaseImpl : public mojom::LevelDBDatabase {
public:
- LevelDBDatabaseImpl(leveldb::mojom::LevelDBDatabaseRequest request,
- std::unique_ptr<leveldb::Env> environment,
+ LevelDBDatabaseImpl(std::unique_ptr<leveldb::Env> environment,
std::unique_ptr<leveldb::DB> db);
~LevelDBDatabaseImpl() override;
// Overridden from LevelDBDatabase:
- void Put(mojo::Array<uint8_t> key,
- mojo::Array<uint8_t> value,
+ void Put(const std::vector<uint8_t>& key,
+ const std::vector<uint8_t>& value,
const PutCallback& callback) override;
- void Delete(mojo::Array<uint8_t> key,
+ void Delete(const std::vector<uint8_t>& key,
const DeleteCallback& callback) override;
- void DeletePrefixed(mojo::Array<uint8_t> key_prefix,
+ void DeletePrefixed(const std::vector<uint8_t>& key_prefix,
const DeletePrefixedCallback& callback) override;
- void Write(mojo::Array<mojom::BatchedOperationPtr> operations,
+ void Write(std::vector<mojom::BatchedOperationPtr> operations,
const WriteCallback& callback) override;
- void Get(mojo::Array<uint8_t> key, const GetCallback& callback) override;
- void GetPrefixed(mojo::Array<uint8_t> key_prefix,
+ void Get(const std::vector<uint8_t>& key,
+ const GetCallback& callback) override;
+ void GetPrefixed(const std::vector<uint8_t>& key_prefix,
const GetPrefixedCallback& callback) override;
void GetSnapshot(const GetSnapshotCallback& callback) override;
void ReleaseSnapshot(uint64_t snapshot_id) override;
void GetFromSnapshot(uint64_t snapshot_id,
- mojo::Array<uint8_t> key,
+ const std::vector<uint8_t>& key,
const GetCallback& callback) override;
void NewIterator(const NewIteratorCallback& callback) override;
void NewIteratorFromSnapshot(uint64_t snapshot_id,
@@ -52,7 +51,7 @@ class LevelDBDatabaseImpl : public mojom::LevelDBDatabase {
void IteratorSeekToLast(uint64_t iterator_id,
const IteratorSeekToLastCallback& callback) override;
void IteratorSeek(uint64_t iterator_id,
- mojo::Array<uint8_t> target,
+ const std::vector<uint8_t>& target,
const IteratorSeekToLastCallback& callback) override;
void IteratorNext(uint64_t iterator_id,
const IteratorNextCallback& callback) override;
@@ -69,7 +68,6 @@ class LevelDBDatabaseImpl : public mojom::LevelDBDatabase {
leveldb::Status DeletePrefixedHelper(const leveldb::Slice& key_prefix,
leveldb::WriteBatch* batch);
- mojo::StrongBinding<mojom::LevelDBDatabase> binding_;
std::unique_ptr<leveldb::Env> environment_;
std::unique_ptr<leveldb::DB> db_;
diff --git a/chromium/components/leveldb/leveldb_mojo_proxy.cc b/chromium/components/leveldb/leveldb_mojo_proxy.cc
index 96f2853e92a..b25fb60c72d 100644
--- a/chromium/components/leveldb/leveldb_mojo_proxy.cc
+++ b/chromium/components/leveldb/leveldb_mojo_proxy.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/system/platform_handle.h"
diff --git a/chromium/components/leveldb/leveldb_mojo_proxy.h b/chromium/components/leveldb/leveldb_mojo_proxy.h
index 881e8b7e0da..2eef1a41d1d 100644
--- a/chromium/components/leveldb/leveldb_mojo_proxy.h
+++ b/chromium/components/leveldb/leveldb_mojo_proxy.h
@@ -15,9 +15,12 @@
#include "base/files/file.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
#include "components/filesystem/public/interfaces/directory.mojom.h"
+namespace base {
+class SingleThreadTaskRunner;
+}
+
namespace leveldb {
// A proxy for thread safe access to Mojo objects from multiple threads.
diff --git a/chromium/components/leveldb/leveldb_service_impl.cc b/chromium/components/leveldb/leveldb_service_impl.cc
index a36281349c2..6df7ad0b9cc 100644
--- a/chromium/components/leveldb/leveldb_service_impl.cc
+++ b/chromium/components/leveldb/leveldb_service_impl.cc
@@ -10,6 +10,7 @@
#include "components/leveldb/env_mojo.h"
#include "components/leveldb/leveldb_database_impl.h"
#include "components/leveldb/public/cpp/util.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
@@ -26,7 +27,7 @@ LevelDBServiceImpl::LevelDBServiceImpl(
LevelDBServiceImpl::~LevelDBServiceImpl() {}
void LevelDBServiceImpl::Open(filesystem::mojom::DirectoryPtr directory,
- const mojo::String& dbname,
+ const std::string& dbname,
leveldb::mojom::LevelDBDatabaseRequest database,
const OpenCallback& callback) {
OpenWithOptions(leveldb::mojom::OpenOptions::New(), std::move(directory),
@@ -36,7 +37,7 @@ void LevelDBServiceImpl::Open(filesystem::mojom::DirectoryPtr directory,
void LevelDBServiceImpl::OpenWithOptions(
leveldb::mojom::OpenOptionsPtr open_options,
filesystem::mojom::DirectoryPtr directory,
- const mojo::String& dbname,
+ const std::string& dbname,
leveldb::mojom::LevelDBDatabaseRequest database,
const OpenCallback& callback) {
leveldb::Options options;
@@ -57,11 +58,12 @@ void LevelDBServiceImpl::OpenWithOptions(
options.env = env_mojo.get();
leveldb::DB* db = nullptr;
- leveldb::Status s = leveldb::DB::Open(options, dbname.To<std::string>(), &db);
+ leveldb::Status s = leveldb::DB::Open(options, dbname, &db);
if (s.ok()) {
- new LevelDBDatabaseImpl(std::move(database), std::move(env_mojo),
- base::WrapUnique(db));
+ mojo::MakeStrongBinding(base::MakeUnique<LevelDBDatabaseImpl>(
+ std::move(env_mojo), base::WrapUnique(db)),
+ std::move(database));
}
callback.Run(LeveldbStatusToError(s));
@@ -82,8 +84,9 @@ void LevelDBServiceImpl::OpenInMemory(
leveldb::Status s = leveldb::DB::Open(options, "", &db);
if (s.ok()) {
- new LevelDBDatabaseImpl(std::move(database), std::move(env),
- base::WrapUnique(db));
+ mojo::MakeStrongBinding(base::MakeUnique<LevelDBDatabaseImpl>(
+ std::move(env), base::WrapUnique(db)),
+ std::move(database));
}
callback.Run(LeveldbStatusToError(s));
diff --git a/chromium/components/leveldb/leveldb_service_impl.h b/chromium/components/leveldb/leveldb_service_impl.h
index b380f6a123d..bf413dbfa5b 100644
--- a/chromium/components/leveldb/leveldb_service_impl.h
+++ b/chromium/components/leveldb/leveldb_service_impl.h
@@ -20,12 +20,12 @@ class LevelDBServiceImpl : public mojom::LevelDBService {
// Overridden from LevelDBService:
void Open(filesystem::mojom::DirectoryPtr directory,
- const mojo::String& dbname,
+ const std::string& dbname,
leveldb::mojom::LevelDBDatabaseRequest database,
const OpenCallback& callback) override;
void OpenWithOptions(leveldb::mojom::OpenOptionsPtr open_options,
filesystem::mojom::DirectoryPtr directory,
- const mojo::String& dbname,
+ const std::string& dbname,
leveldb::mojom::LevelDBDatabaseRequest database,
const OpenCallback& callback) override;
void OpenInMemory(leveldb::mojom::LevelDBDatabaseRequest database,
diff --git a/chromium/components/leveldb/leveldb_service_unittest.cc b/chromium/components/leveldb/leveldb_service_unittest.cc
index 893ea6f6d16..1f59df2db19 100644
--- a/chromium/components/leveldb/leveldb_service_unittest.cc
+++ b/chromium/components/leveldb/leveldb_service_unittest.cc
@@ -4,14 +4,15 @@
#include "base/bind.h"
#include "base/macros.h"
+#include "base/run_loop.h"
#include "components/filesystem/public/interfaces/directory.mojom.h"
#include "components/filesystem/public/interfaces/file_system.mojom.h"
#include "components/filesystem/public/interfaces/types.mojom.h"
+#include "components/leveldb/public/cpp/util.h"
#include "components/leveldb/public/interfaces/leveldb.mojom.h"
-#include "mojo/common/common_type_converters.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/shell/public/cpp/shell_connection.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_context.h"
+#include "services/shell/public/cpp/service_test.h"
using filesystem::mojom::FileError;
@@ -21,45 +22,105 @@ namespace {
template <typename... Args> void IgnoreAllArgs(Args&&...) {}
template <typename... Args>
-void DoCaptures(Args*... out_args, Args... in_args) {
+void DoCaptures(typename std::decay<Args>::type*... out_args,
+ const base::Closure& quit_closure,
+ Args... in_args) {
IgnoreAllArgs((*out_args = std::move(in_args))...);
+ quit_closure.Run();
}
template <typename T1>
-base::Callback<void(T1)> Capture(T1* t1) {
- return base::Bind(&DoCaptures<T1>, t1);
+base::Callback<void(T1)> Capture(T1* t1, const base::Closure& quit_closure) {
+ return base::Bind(&DoCaptures<T1>, t1, quit_closure);
}
template <typename T1, typename T2>
-base::Callback<void(T1, T2)> Capture(T1* t1, T2* t2) {
- return base::Bind(&DoCaptures<T1, T2>, t1, t2);
+base::Callback<void(T1, T2)> Capture(T1* t1,
+ T2* t2,
+ const base::Closure& quit_closure) {
+ return base::Bind(&DoCaptures<T1, T2>, t1, t2, quit_closure);
}
-class LevelDBServiceTest : public shell::test::ShellTest {
+template <typename T1, typename T2>
+base::Callback<void(T1, const T2&)>
+CaptureConstRef(T1* t1, T2* t2, const base::Closure& quit_closure) {
+ return base::Bind(&DoCaptures<T1, const T2&>, t1, t2, quit_closure);
+}
+
+void DatabaseSyncPut(mojom::LevelDBDatabase* database,
+ const std::string& key,
+ const std::string& value,
+ mojom::DatabaseError* out_error) {
+ base::RunLoop run_loop;
+ database->Put(StdStringToUint8Vector(key), StdStringToUint8Vector(value),
+ Capture(out_error, run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+void DatabaseSyncGet(mojom::LevelDBDatabase* database,
+ const std::string& key,
+ mojom::DatabaseError* out_error,
+ std::vector<uint8_t>* out_value) {
+ base::RunLoop run_loop;
+ database->Get(StdStringToUint8Vector(key),
+ CaptureConstRef(out_error, out_value, run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+void DatabaseSyncGetPrefixed(mojom::LevelDBDatabase* database,
+ const std::string& key_prefix,
+ mojom::DatabaseError* out_error,
+ std::vector<mojom::KeyValuePtr>* out_key_values) {
+ base::RunLoop run_loop;
+ database->GetPrefixed(
+ StdStringToUint8Vector(key_prefix),
+ Capture(out_error, out_key_values, run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+void DatabaseSyncDeletePrefixed(mojom::LevelDBDatabase* database,
+ const std::string& key_prefix,
+ mojom::DatabaseError* out_error) {
+ base::RunLoop run_loop;
+ database->DeletePrefixed(StdStringToUint8Vector(key_prefix),
+ Capture(out_error, run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+void LevelDBSyncOpenInMemory(mojom::LevelDBService* leveldb,
+ mojom::LevelDBDatabaseRequest database,
+ mojom::DatabaseError* out_error) {
+ base::RunLoop run_loop;
+ leveldb->OpenInMemory(std::move(database),
+ Capture(out_error, run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+class LevelDBServiceTest : public shell::test::ServiceTest {
public:
- LevelDBServiceTest() : ShellTest("exe:leveldb_service_unittests") {}
+ LevelDBServiceTest() : ServiceTest("exe:leveldb_service_unittests") {}
~LevelDBServiceTest() override {}
protected:
// Overridden from mojo::test::ApplicationTestBase:
void SetUp() override {
- ShellTest::SetUp();
- connector()->ConnectToInterface("mojo:filesystem", &files_);
- connector()->ConnectToInterface("mojo:leveldb", &leveldb_);
+ ServiceTest::SetUp();
+ connector()->ConnectToInterface("service:filesystem", &files_);
+ connector()->ConnectToInterface("service:leveldb", &leveldb_);
}
void TearDown() override {
leveldb_.reset();
files_.reset();
- ShellTest::TearDown();
+ ServiceTest::TearDown();
}
// Note: This has an out parameter rather than returning the |DirectoryPtr|,
// since |ASSERT_...()| doesn't work with return values.
void GetTempDirectory(filesystem::mojom::DirectoryPtr* directory) {
FileError error = FileError::FAILED;
- files()->OpenTempDirectory(GetProxy(directory), Capture(&error));
- ASSERT_TRUE(files().WaitForIncomingResponse());
+ bool handled = files()->OpenTempDirectory(GetProxy(directory), &error);
+ ASSERT_TRUE(handled);
ASSERT_EQ(FileError::OK, error);
}
@@ -76,130 +137,109 @@ class LevelDBServiceTest : public shell::test::ShellTest {
TEST_F(LevelDBServiceTest, Basic) {
mojom::DatabaseError error;
mojom::LevelDBDatabasePtr database;
- leveldb()->OpenInMemory(GetProxy(&database), Capture(&error));
- ASSERT_TRUE(leveldb().WaitForIncomingResponse());
+ LevelDBSyncOpenInMemory(leveldb().get(), GetProxy(&database), &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Write a key to the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Put(mojo::Array<uint8_t>::From(std::string("key")),
- mojo::Array<uint8_t>::From(std::string("value")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), "key", "value", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Read the key back from the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- mojo::Array<uint8_t> value;
- database->Get(mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ std::vector<uint8_t> value;
+ DatabaseSyncGet(database.get(), "key", &error, &value);
EXPECT_EQ(mojom::DatabaseError::OK, error);
- EXPECT_EQ("value", value.To<std::string>());
+ EXPECT_EQ("value", Uint8VectorToStdString(value));
// Delete the key from the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Delete(mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ base::RunLoop run_loop;
+ database->Delete(StdStringToUint8Vector("key"),
+ Capture(&error, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Read the key back from the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- value.SetToEmpty();
- database->Get(mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ value.clear();
+ DatabaseSyncGet(database.get(), "key", &error, &value);
EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error);
- EXPECT_EQ("", value.To<std::string>());
+ EXPECT_EQ("", Uint8VectorToStdString(value));
}
TEST_F(LevelDBServiceTest, WriteBatch) {
mojom::DatabaseError error;
mojom::LevelDBDatabasePtr database;
- leveldb()->OpenInMemory(GetProxy(&database), Capture(&error));
- ASSERT_TRUE(leveldb().WaitForIncomingResponse());
+ LevelDBSyncOpenInMemory(leveldb().get(), GetProxy(&database), &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Write a key to the database.
- database->Put(mojo::Array<uint8_t>::From(std::string("key")),
- mojo::Array<uint8_t>::From(std::string("value")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), "key", "value", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Create a batched operation which both deletes "key" and adds another write.
- mojo::Array<mojom::BatchedOperationPtr> operations;
+ std::vector<mojom::BatchedOperationPtr> operations;
mojom::BatchedOperationPtr item = mojom::BatchedOperation::New();
item->type = mojom::BatchOperationType::DELETE_KEY;
- item->key = mojo::Array<uint8_t>::From(std::string("key"));
+ item->key = StdStringToUint8Vector("key");
operations.push_back(std::move(item));
item = mojom::BatchedOperation::New();
item->type = mojom::BatchOperationType::PUT_KEY;
- item->key = mojo::Array<uint8_t>::From(std::string("other"));
- item->value = mojo::Array<uint8_t>::From(std::string("more"));
+ item->key = StdStringToUint8Vector("other");
+ item->value = StdStringToUint8Vector("more");
operations.push_back(std::move(item));
- database->Write(std::move(operations), Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ base::RunLoop run_loop;
+ database->Write(std::move(operations),
+ Capture(&error, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Reading "key" should be invalid now.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- mojo::Array<uint8_t> value;
- database->Get(mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ std::vector<uint8_t> value;
+ DatabaseSyncGet(database.get(), "key", &error, &value);
EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error);
- EXPECT_EQ("", value.To<std::string>());
+ EXPECT_EQ("", Uint8VectorToStdString(value));
// Reading "other" should return "more"
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Get(mojo::Array<uint8_t>::From(std::string("other")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncGet(database.get(), "other", &error, &value);
EXPECT_EQ(mojom::DatabaseError::OK, error);
- EXPECT_EQ("more", value.To<std::string>());
+ EXPECT_EQ("more", Uint8VectorToStdString(value));
// Write a some prefixed keys to the database.
- database->Put(mojo::Array<uint8_t>::From(std::string("prefix-key1")),
- mojo::Array<uint8_t>::From(std::string("value")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), "prefix-key1", "value", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
- database->Put(mojo::Array<uint8_t>::From(std::string("prefix-key2")),
- mojo::Array<uint8_t>::From(std::string("value")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), "prefix-key2", "value", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Create a batched operation to delete them.
- operations.SetToEmpty();
+ operations.clear();
item = mojom::BatchedOperation::New();
item->type = mojom::BatchOperationType::DELETE_PREFIXED_KEY;
- item->key = mojo::Array<uint8_t>::From(std::string("prefix"));
+ item->key = StdStringToUint8Vector("prefix");
operations.push_back(std::move(item));
- database->Write(std::move(operations), Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ base::RunLoop run_loop2;
+ database->Write(std::move(operations),
+ Capture(&error, run_loop2.QuitClosure()));
+ run_loop2.Run();
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Reading all "prefix" keys should be invalid now.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- value = nullptr;
- database->Get(mojo::Array<uint8_t>::From(std::string("prefix-key1")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ value.clear();
+ DatabaseSyncGet(database.get(), "prefix-key1", &error, &value);
EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error);
- EXPECT_EQ("", value.To<std::string>());
+ EXPECT_EQ("", Uint8VectorToStdString(value));
// Reading "key" should be invalid now.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- value = nullptr;
- database->Get(mojo::Array<uint8_t>::From(std::string("prefix-key2")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ value.clear();
+ DatabaseSyncGet(database.get(), "prefix-key2", &error, &value);
EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error);
- EXPECT_EQ("", value.To<std::string>());
+ EXPECT_EQ("", Uint8VectorToStdString(value));
}
TEST_F(LevelDBServiceTest, Reconnect) {
@@ -216,19 +256,16 @@ TEST_F(LevelDBServiceTest, Reconnect) {
leveldb::mojom::OpenOptionsPtr options = leveldb::mojom::OpenOptions::New();
options->error_if_exists = true;
options->create_if_missing = true;
- leveldb()->OpenWithOptions(std::move(options),
- std::move(directory), "test",
+ base::RunLoop run_loop;
+ leveldb()->OpenWithOptions(std::move(options), std::move(directory), "test",
GetProxy(&database),
- Capture(&error));
- ASSERT_TRUE(leveldb().WaitForIncomingResponse());
+ Capture(&error, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Write a key to the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Put(mojo::Array<uint8_t>::From(std::string("key")),
- mojo::Array<uint8_t>::From(std::string("value")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), "key", "value", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// The database should go out of scope here.
@@ -240,274 +277,219 @@ TEST_F(LevelDBServiceTest, Reconnect) {
// Reconnect to the database.
mojom::LevelDBDatabasePtr database;
+ base::RunLoop run_loop;
leveldb()->Open(std::move(directory), "test", GetProxy(&database),
- Capture(&error));
- ASSERT_TRUE(leveldb().WaitForIncomingResponse());
+ Capture(&error, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_EQ(mojom::DatabaseError::OK, error);
// We should still be able to read the key back from the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- mojo::Array<uint8_t> value;
- database->Get(mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ std::vector<uint8_t> value;
+ DatabaseSyncGet(database.get(), "key", &error, &value);
EXPECT_EQ(mojom::DatabaseError::OK, error);
- EXPECT_EQ("value", value.To<std::string>());
+ EXPECT_EQ("value", Uint8VectorToStdString(value));
}
}
TEST_F(LevelDBServiceTest, GetSnapshotSimple) {
mojom::DatabaseError error;
mojom::LevelDBDatabasePtr database;
- leveldb()->OpenInMemory(GetProxy(&database), Capture(&error));
- ASSERT_TRUE(leveldb().WaitForIncomingResponse());
+ LevelDBSyncOpenInMemory(leveldb().get(), GetProxy(&database), &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
uint64_t snapshot_id = 0;
- database->GetSnapshot(Capture(&snapshot_id));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ base::RunLoop run_loop;
+ database->GetSnapshot(Capture(&snapshot_id, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_NE(static_cast<uint64_t>(0), snapshot_id);
}
TEST_F(LevelDBServiceTest, GetFromSnapshots) {
mojom::DatabaseError error;
mojom::LevelDBDatabasePtr database;
- leveldb()->OpenInMemory(GetProxy(&database), Capture(&error));
- ASSERT_TRUE(leveldb().WaitForIncomingResponse());
+ LevelDBSyncOpenInMemory(leveldb().get(), GetProxy(&database), &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Write a key to the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Put(mojo::Array<uint8_t>::From(std::string("key")),
- mojo::Array<uint8_t>::From(std::string("value")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), "key", "value", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Take a snapshot where key=value.
uint64_t key_value_snapshot = 0;
- database->GetSnapshot(Capture(&key_value_snapshot));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ base::RunLoop run_loop;
+ database->GetSnapshot(Capture(&key_value_snapshot, run_loop.QuitClosure()));
+ run_loop.Run();
// Change key to "yek".
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Put(mojo::Array<uint8_t>::From(std::string("key")),
- mojo::Array<uint8_t>::From(std::string("yek")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), "key", "yek", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// (Ensure this change is live on the database.)
error = mojom::DatabaseError::INVALID_ARGUMENT;
- mojo::Array<uint8_t> value;
- database->Get(mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ std::vector<uint8_t> value;
+ DatabaseSyncGet(database.get(), "key", &error, &value);
EXPECT_EQ(mojom::DatabaseError::OK, error);
- EXPECT_EQ("yek", value.To<std::string>());
+ EXPECT_EQ("yek", Uint8VectorToStdString(value));
// But if we were to read from the snapshot, we'd still get value.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- value.SetToEmpty();
+ value.clear();
+ base::RunLoop run_loop2;
database->GetFromSnapshot(
- key_value_snapshot,
- mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ key_value_snapshot, StdStringToUint8Vector("key"),
+ CaptureConstRef(&error, &value, run_loop2.QuitClosure()));
+ run_loop2.Run();
EXPECT_EQ(mojom::DatabaseError::OK, error);
- EXPECT_EQ("value", value.To<std::string>());
+ EXPECT_EQ("value", Uint8VectorToStdString(value));
}
TEST_F(LevelDBServiceTest, InvalidArgumentOnInvalidSnapshot) {
mojom::LevelDBDatabasePtr database;
mojom::DatabaseError error = mojom::DatabaseError::INVALID_ARGUMENT;
- leveldb()->OpenInMemory(GetProxy(&database), Capture(&error));
- ASSERT_TRUE(leveldb().WaitForIncomingResponse());
+ LevelDBSyncOpenInMemory(leveldb().get(), GetProxy(&database), &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
uint64_t invalid_snapshot = 8;
error = mojom::DatabaseError::OK;
- mojo::Array<uint8_t> value;
+ std::vector<uint8_t> value;
+ base::RunLoop run_loop;
database->GetFromSnapshot(
- invalid_snapshot,
- mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ invalid_snapshot, StdStringToUint8Vector("key"),
+ CaptureConstRef(&error, &value, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_EQ(mojom::DatabaseError::INVALID_ARGUMENT, error);
}
TEST_F(LevelDBServiceTest, MemoryDBReadWrite) {
mojom::LevelDBDatabasePtr database;
mojom::DatabaseError error = mojom::DatabaseError::INVALID_ARGUMENT;
- leveldb()->OpenInMemory(GetProxy(&database), Capture(&error));
- ASSERT_TRUE(leveldb().WaitForIncomingResponse());
+ LevelDBSyncOpenInMemory(leveldb().get(), GetProxy(&database), &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Write a key to the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Put(mojo::Array<uint8_t>::From(std::string("key")),
- mojo::Array<uint8_t>::From(std::string("value")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), "key", "value", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Read the key back from the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- mojo::Array<uint8_t> value;
- database->Get(mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ std::vector<uint8_t> value;
+ DatabaseSyncGet(database.get(), "key", &error, &value);
EXPECT_EQ(mojom::DatabaseError::OK, error);
- EXPECT_EQ("value", value.To<std::string>());
+ EXPECT_EQ("value", Uint8VectorToStdString(value));
// Delete the key from the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Delete(mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ base::RunLoop run_loop;
+ database->Delete(StdStringToUint8Vector("key"),
+ Capture(&error, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_EQ(mojom::DatabaseError::OK, error);
// Read the key back from the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- value.SetToEmpty();
- database->Get(mojo::Array<uint8_t>::From(std::string("key")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ value.clear();
+ DatabaseSyncGet(database.get(), "key", &error, &value);
EXPECT_EQ(mojom::DatabaseError::NOT_FOUND, error);
- EXPECT_EQ("", value.To<std::string>());
+ EXPECT_EQ("", Uint8VectorToStdString(value));
}
TEST_F(LevelDBServiceTest, Prefixed) {
// Open an in memory database for speed.
mojom::DatabaseError error = mojom::DatabaseError::INVALID_ARGUMENT;
mojom::LevelDBDatabasePtr database;
- leveldb()->OpenInMemory(GetProxy(&database), Capture(&error));
- ASSERT_TRUE(leveldb().WaitForIncomingResponse());
+ LevelDBSyncOpenInMemory(leveldb().get(), GetProxy(&database), &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
const std::string prefix("prefix");
- mojo::Array<mojom::KeyValuePtr> key_values;
+ std::vector<mojom::KeyValuePtr> key_values;
// Completely empty database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->GetPrefixed(mojo::Array<uint8_t>::From(prefix),
- Capture(&error, &key_values));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values);
EXPECT_EQ(mojom::DatabaseError::OK, error);
EXPECT_TRUE(key_values.empty());
// No values with our prefix, but values before and after.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Put(mojo::Array<uint8_t>::From(std::string("a-before-prefix")),
- mojo::Array<uint8_t>::From(std::string("value")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), "a-before-prefix", "value", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Put(mojo::Array<uint8_t>::From(std::string("z-after-prefix")),
- mojo::Array<uint8_t>::From(std::string("value")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), "z-after-prefix", "value", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
- key_values.SetToEmpty();
+ key_values.clear();
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->GetPrefixed(mojo::Array<uint8_t>::From(prefix),
- Capture(&error, &key_values));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values);
EXPECT_EQ(mojom::DatabaseError::OK, error);
EXPECT_TRUE(key_values.empty());
// One value with the exact prefix.
- database->Put(mojo::Array<uint8_t>::From(prefix),
- mojo::Array<uint8_t>::From(std::string("value")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), prefix, "value", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
error = mojom::DatabaseError::INVALID_ARGUMENT;
- key_values.SetToEmpty();
- database->GetPrefixed(mojo::Array<uint8_t>::From(prefix),
- Capture(&error, &key_values));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ key_values.clear();
+ DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values);
EXPECT_EQ(mojom::DatabaseError::OK, error);
EXPECT_EQ(1u, key_values.size());
- EXPECT_EQ("prefix", key_values[0]->key.To<std::string>());
- EXPECT_EQ("value", key_values[0]->value.To<std::string>());
+ EXPECT_EQ("prefix", Uint8VectorToStdString(key_values[0]->key));
+ EXPECT_EQ("value", Uint8VectorToStdString(key_values[0]->value));
// Multiple values with starting with the prefix.
- database->Put(mojo::Array<uint8_t>::From(prefix + "2"),
- mojo::Array<uint8_t>::From(std::string("value2")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), (prefix + "2"), "value2", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
error = mojom::DatabaseError::INVALID_ARGUMENT;
- key_values.SetToEmpty();
- database->GetPrefixed(mojo::Array<uint8_t>::From(prefix),
- Capture(&error, &key_values));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ key_values.clear();
+ DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values);
EXPECT_EQ(mojom::DatabaseError::OK, error);
EXPECT_EQ(2u, key_values.size());
- EXPECT_EQ("prefix", key_values[0]->key.To<std::string>());
- EXPECT_EQ("value", key_values[0]->value.To<std::string>());
- EXPECT_EQ("prefix2", key_values[1]->key.To<std::string>());
- EXPECT_EQ("value2", key_values[1]->value.To<std::string>());
+ EXPECT_EQ("prefix", Uint8VectorToStdString(key_values[0]->key));
+ EXPECT_EQ("value", Uint8VectorToStdString(key_values[0]->value));
+ EXPECT_EQ("prefix2", Uint8VectorToStdString(key_values[1]->key));
+ EXPECT_EQ("value2", Uint8VectorToStdString(key_values[1]->value));
// Delete the prefixed values.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->DeletePrefixed(mojo::Array<uint8_t>::From(prefix),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncDeletePrefixed(database.get(), prefix, &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
error = mojom::DatabaseError::INVALID_ARGUMENT;
- key_values.SetToEmpty();
- database->GetPrefixed(mojo::Array<uint8_t>::From(prefix),
- Capture(&error, &key_values));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ key_values.clear();
+ DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values);
EXPECT_EQ(mojom::DatabaseError::OK, error);
EXPECT_TRUE(key_values.empty());
// Make sure the others are not deleted.
- mojo::Array<uint8_t> value;
- database->Get(mojo::Array<uint8_t>::From(std::string("a-before-prefix")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ std::vector<uint8_t> value;
+ DatabaseSyncGet(database.get(), "a-before-prefix", &error, &value);
EXPECT_EQ(mojom::DatabaseError::OK, error);
- EXPECT_EQ("value", value.To<std::string>());
- value.SetToEmpty();
- database->Get(mojo::Array<uint8_t>::From(std::string("z-after-prefix")),
- Capture(&error, &value));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ EXPECT_EQ("value", Uint8VectorToStdString(value));
+ value.clear();
+ DatabaseSyncGet(database.get(), "z-after-prefix", &error, &value);
EXPECT_EQ(mojom::DatabaseError::OK, error);
- EXPECT_EQ("value", value.To<std::string>());
+ EXPECT_EQ("value", Uint8VectorToStdString(value));
// A key having our prefix, but no key matching it exactly.
// Even thought there is no exact matching key, GetPrefixed
// and DeletePrefixed still operate on the values.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->Put(mojo::Array<uint8_t>::From(prefix + "2"),
- mojo::Array<uint8_t>::From(std::string("value2")),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncPut(database.get(), (prefix + "2"), "value2", &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
error = mojom::DatabaseError::INVALID_ARGUMENT;
- key_values.SetToEmpty();
- database->GetPrefixed(mojo::Array<uint8_t>::From(prefix),
- Capture(&error, &key_values));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ key_values.clear();
+ DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values);
EXPECT_EQ(mojom::DatabaseError::OK, error);
EXPECT_EQ(1u, key_values.size());
- EXPECT_EQ("prefix2", key_values[0]->key.To<std::string>());
- EXPECT_EQ("value2", key_values[0]->value.To<std::string>());
+ EXPECT_EQ("prefix2", Uint8VectorToStdString(key_values[0]->key));
+ EXPECT_EQ("value2", Uint8VectorToStdString(key_values[0]->value));
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database->DeletePrefixed(mojo::Array<uint8_t>::From(prefix),
- Capture(&error));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ DatabaseSyncDeletePrefixed(database.get(), prefix, &error);
EXPECT_EQ(mojom::DatabaseError::OK, error);
error = mojom::DatabaseError::INVALID_ARGUMENT;
- key_values.SetToEmpty();
- database->GetPrefixed(mojo::Array<uint8_t>::From(prefix),
- Capture(&error, &key_values));
- ASSERT_TRUE(database.WaitForIncomingResponse());
+ key_values.clear();
+ DatabaseSyncGetPrefixed(database.get(), prefix, &error, &key_values);
EXPECT_EQ(mojom::DatabaseError::OK, error);
EXPECT_TRUE(key_values.empty());
}
diff --git a/chromium/components/leveldb/main.cc b/chromium/components/leveldb/main.cc
index 7e5c9fb4ab5..937755ae202 100644
--- a/chromium/components/leveldb/main.cc
+++ b/chromium/components/leveldb/main.cc
@@ -4,10 +4,10 @@
#include "base/macros.h"
#include "components/leveldb/leveldb_app.h"
-#include "mojo/public/c/system/main.h"
-#include "services/shell/public/cpp/application_runner.h"
+#include "services/shell/public/c/main.h"
+#include "services/shell/public/cpp/service_runner.h"
-MojoResult MojoMain(MojoHandle application_request) {
- shell::ApplicationRunner runner(new leveldb::LevelDBApp());
+MojoResult ServiceMain(MojoHandle application_request) {
+ shell::ServiceRunner runner(new leveldb::LevelDBApp());
return runner.Run(application_request);
}
diff --git a/chromium/components/leveldb/manifest.json b/chromium/components/leveldb/manifest.json
index a56b36d94c7..4822225d9e1 100644
--- a/chromium/components/leveldb/manifest.json
+++ b/chromium/components/leveldb/manifest.json
@@ -1,6 +1,6 @@
{
"manifest_version": 1,
- "name": "mojo:leveldb",
+ "name": "service:leveldb",
"display_name": "LevelDB Service",
"capabilities": {
"required": {
diff --git a/chromium/components/leveldb/public/cpp/BUILD.gn b/chromium/components/leveldb/public/cpp/BUILD.gn
index f615abf657e..1996c76816d 100644
--- a/chromium/components/leveldb/public/cpp/BUILD.gn
+++ b/chromium/components/leveldb/public/cpp/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("cpp") {
+static_library("cpp") {
sources = [
"remote_iterator.cc",
"remote_iterator.h",
diff --git a/chromium/components/leveldb/public/cpp/remote_iterator.cc b/chromium/components/leveldb/public/cpp/remote_iterator.cc
index b1042f70a53..c7e0c4ac962 100644
--- a/chromium/components/leveldb/public/cpp/remote_iterator.cc
+++ b/chromium/components/leveldb/public/cpp/remote_iterator.cc
@@ -34,7 +34,7 @@ void RemoteIterator::SeekToLast() {
}
void RemoteIterator::Seek(const Slice& target) {
- database_->IteratorSeek(iterator_id_, GetArrayFor(target), &valid_, &status_,
+ database_->IteratorSeek(iterator_id_, GetVectorFor(target), &valid_, &status_,
&key_, &value_);
}
@@ -47,15 +47,19 @@ void RemoteIterator::Prev() {
}
Slice RemoteIterator::key() const {
- return GetSliceFor(key_);
+ if (!key_)
+ return leveldb::Slice();
+ return GetSliceFor(*key_);
}
Slice RemoteIterator::value() const {
- return GetSliceFor(value_);
+ if (!value_)
+ return leveldb::Slice();
+ return GetSliceFor(*value_);
}
Status RemoteIterator::status() const {
- return DatabaseErrorToStatus(status_, GetSliceFor(key_), GetSliceFor(value_));
+ return DatabaseErrorToStatus(status_, key(), value());
}
} // namespace leveldb
diff --git a/chromium/components/leveldb/public/cpp/remote_iterator.h b/chromium/components/leveldb/public/cpp/remote_iterator.h
index 1d3920ba123..0a4ae36d1e0 100644
--- a/chromium/components/leveldb/public/cpp/remote_iterator.h
+++ b/chromium/components/leveldb/public/cpp/remote_iterator.h
@@ -6,7 +6,6 @@
#define COMPONENTS_LEVELDB_PUBLIC_CPP_REMOTE_ITERATOR_H_
#include "components/leveldb/public/interfaces/leveldb.mojom.h"
-#include "mojo/public/cpp/bindings/array.h"
#include "third_party/leveldatabase/src/include/leveldb/iterator.h"
namespace leveldb {
@@ -37,8 +36,8 @@ class RemoteIterator : public Iterator {
bool valid_;
mojom::DatabaseError status_;
- mojo::Array<uint8_t> key_;
- mojo::Array<uint8_t> value_;
+ base::Optional<std::vector<uint8_t>> key_;
+ base::Optional<std::vector<uint8_t>> value_;
DISALLOW_COPY_AND_ASSIGN(RemoteIterator);
};
diff --git a/chromium/components/leveldb/public/cpp/util.cc b/chromium/components/leveldb/public/cpp/util.cc
index 647f12c0d80..d2dd6a60ce7 100644
--- a/chromium/components/leveldb/public/cpp/util.cc
+++ b/chromium/components/leveldb/public/cpp/util.cc
@@ -45,19 +45,28 @@ leveldb::Status DatabaseErrorToStatus(mojom::DatabaseError e,
return leveldb::Status::InvalidArgument(msg, msg2);
}
-leveldb::Slice GetSliceFor(const mojo::Array<uint8_t>& key) {
+leveldb::Slice GetSliceFor(const std::vector<uint8_t>& key) {
if (key.size() == 0)
return leveldb::Slice();
return leveldb::Slice(reinterpret_cast<const char*>(&key.front()),
key.size());
}
-mojo::Array<uint8_t> GetArrayFor(const leveldb::Slice& s) {
+std::vector<uint8_t> GetVectorFor(const leveldb::Slice& s) {
if (s.size() == 0)
- return mojo::Array<uint8_t>();
- return mojo::Array<uint8_t>(std::vector<uint8_t>(
+ return std::vector<uint8_t>();
+ return std::vector<uint8_t>(
reinterpret_cast<const uint8_t*>(s.data()),
- reinterpret_cast<const uint8_t*>(s.data() + s.size())));
+ reinterpret_cast<const uint8_t*>(s.data() + s.size()));
+}
+
+std::string Uint8VectorToStdString(const std::vector<uint8_t>& input) {
+ return std::string(reinterpret_cast<const char*>(input.data()), input.size());
+}
+
+std::vector<uint8_t> StdStringToUint8Vector(const std::string& input) {
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(input.data());
+ return std::vector<uint8_t>(data, data + input.size());
}
} // namespace leveldb
diff --git a/chromium/components/leveldb/public/cpp/util.h b/chromium/components/leveldb/public/cpp/util.h
index 44f733af30d..23e1e1d508f 100644
--- a/chromium/components/leveldb/public/cpp/util.h
+++ b/chromium/components/leveldb/public/cpp/util.h
@@ -25,10 +25,14 @@ leveldb::Status DatabaseErrorToStatus(mojom::DatabaseError e,
// Builds a Slice pointing to the data inside |a|. This is not a type-converter
// as it is not a copy operation; the returned Slice points into |a| and must
// outlive |a|.
-leveldb::Slice GetSliceFor(const mojo::Array<uint8_t>& a);
+leveldb::Slice GetSliceFor(const std::vector<uint8_t>& a);
-// Copies the data that |s| points to into a mojo::Array.
-mojo::Array<uint8_t> GetArrayFor(const leveldb::Slice& s);
+// Copies the data that |s| points to into a std::vector.
+std::vector<uint8_t> GetVectorFor(const leveldb::Slice& s);
+
+std::string Uint8VectorToStdString(const std::vector<uint8_t>& input);
+
+std::vector<uint8_t> StdStringToUint8Vector(const std::string& input);
} // namespace leveldb
diff --git a/chromium/components/leveldb/remote_iterator_unittest.cc b/chromium/components/leveldb/remote_iterator_unittest.cc
index bd616798191..8fc523d7f14 100644
--- a/chromium/components/leveldb/remote_iterator_unittest.cc
+++ b/chromium/components/leveldb/remote_iterator_unittest.cc
@@ -4,38 +4,48 @@
#include <map>
+#include "base/bind.h"
#include "base/macros.h"
+#include "base/run_loop.h"
#include "components/leveldb/public/cpp/remote_iterator.h"
+#include "components/leveldb/public/cpp/util.h"
#include "components/leveldb/public/interfaces/leveldb.mojom.h"
-#include "mojo/common/common_type_converters.h"
-#include "services/shell/public/cpp/shell_connection.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_context.h"
+#include "services/shell/public/cpp/service_test.h"
namespace leveldb {
namespace {
template <typename T>
-void DoCapture(T* t, T got_t) { *t = std::move(got_t); }
+void DoCapture(T* t, const base::Closure& quit_closure, T got_t) {
+ *t = std::move(got_t);
+ if (!quit_closure.is_null())
+ quit_closure.Run();
+}
template <typename T1>
-base::Callback<void(T1)> Capture(T1* t1) {
- return base::Bind(&DoCapture<T1>, t1);
+base::Callback<void(T1)> Capture(
+ T1* t1,
+ const base::Closure& quit_closure = base::Closure()) {
+ return base::Bind(&DoCapture<T1>, t1, quit_closure);
}
-class RemoteIteratorTest : public shell::test::ShellTest {
+class RemoteIteratorTest : public shell::test::ServiceTest {
public:
- RemoteIteratorTest() : ShellTest("exe:leveldb_service_unittests") {}
+ RemoteIteratorTest() : ServiceTest("exe:leveldb_service_unittests") {}
~RemoteIteratorTest() override {}
protected:
// Overridden from mojo::test::ApplicationTestBase:
void SetUp() override {
- ShellTest::SetUp();
- connector()->ConnectToInterface("mojo:leveldb", &leveldb_);
+ ServiceTest::SetUp();
+ connector()->ConnectToInterface("service:leveldb", &leveldb_);
mojom::DatabaseError error;
- leveldb()->OpenInMemory(GetProxy(&database_), Capture(&error));
- ASSERT_TRUE(leveldb().WaitForIncomingResponse());
+ base::RunLoop run_loop;
+ leveldb()->OpenInMemory(GetProxy(&database_),
+ Capture(&error, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_EQ(mojom::DatabaseError::OK, error);
std::map<std::string, std::string> data{
@@ -44,16 +54,18 @@ class RemoteIteratorTest : public shell::test::ShellTest {
for (auto p : data) {
// Write a key to the database.
error = mojom::DatabaseError::INVALID_ARGUMENT;
- database_->Put(mojo::Array<uint8_t>::From(p.first),
- mojo::Array<uint8_t>::From(p.second), Capture(&error));
- ASSERT_TRUE(database_.WaitForIncomingResponse());
+ base::RunLoop run_loop;
+ database_->Put(StdStringToUint8Vector(p.first),
+ StdStringToUint8Vector(p.second),
+ Capture(&error, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_EQ(mojom::DatabaseError::OK, error);
}
}
void TearDown() override {
leveldb_.reset();
- ShellTest::TearDown();
+ ServiceTest::TearDown();
}
mojom::LevelDBServicePtr& leveldb() { return leveldb_; }
@@ -68,8 +80,9 @@ class RemoteIteratorTest : public shell::test::ShellTest {
TEST_F(RemoteIteratorTest, Seeking) {
uint64_t iterator_id = 0;
- database()->NewIterator(Capture(&iterator_id));
- ASSERT_TRUE(database().WaitForIncomingResponse());
+ base::RunLoop run_loop;
+ database()->NewIterator(Capture(&iterator_id, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_NE(0u, iterator_id);
RemoteIterator it(database().get(), iterator_id);
@@ -93,8 +106,9 @@ TEST_F(RemoteIteratorTest, Seeking) {
TEST_F(RemoteIteratorTest, Next) {
uint64_t iterator_id = 0;
- database()->NewIterator(Capture(&iterator_id));
- ASSERT_TRUE(database().WaitForIncomingResponse());
+ base::RunLoop run_loop;
+ database()->NewIterator(Capture(&iterator_id, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_NE(0u, iterator_id);
RemoteIterator it(database().get(), iterator_id);
@@ -121,8 +135,9 @@ TEST_F(RemoteIteratorTest, Next) {
TEST_F(RemoteIteratorTest, Prev) {
uint64_t iterator_id = 0;
- database()->NewIterator(Capture(&iterator_id));
- ASSERT_TRUE(database().WaitForIncomingResponse());
+ base::RunLoop run_loop;
+ database()->NewIterator(Capture(&iterator_id, run_loop.QuitClosure()));
+ run_loop.Run();
EXPECT_NE(0u, iterator_id);
RemoteIterator it(database().get(), iterator_id);
diff --git a/chromium/components/leveldb/test_manifest.json b/chromium/components/leveldb/test_manifest.json
index c59580f7ad3..0705e8c54f9 100644
--- a/chromium/components/leveldb/test_manifest.json
+++ b/chromium/components/leveldb/test_manifest.json
@@ -4,8 +4,8 @@
"display_name": "LevelDB Service Unittests",
"capabilities": {
"required": {
- "mojo:filesystem": { "interfaces": [ "filesystem::mojom::FileSystem" ] },
- "mojo:leveldb": { "interfaces": [ "leveldb::mojom::LevelDBService" ] }
+ "service:filesystem": { "interfaces": [ "filesystem::mojom::FileSystem" ] },
+ "service:leveldb": { "interfaces": [ "leveldb::mojom::LevelDBService" ] }
}
}
}
diff --git a/chromium/components/leveldb_proto.gypi b/chromium/components/leveldb_proto.gypi
deleted file mode 100644
index b90ad904600..00000000000
--- a/chromium/components/leveldb_proto.gypi
+++ /dev/null
@@ -1,44 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'leveldb_proto',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
- ],
- 'sources': [
- 'leveldb_proto/leveldb_database.cc',
- 'leveldb_proto/leveldb_database.h',
- 'leveldb_proto/proto_database.h',
- 'leveldb_proto/proto_database_impl.h',
- ]
- },
- {
- 'target_name': 'leveldb_proto_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'leveldb_proto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'leveldb_proto/testing/fake_db.h',
- 'leveldb_proto/testing/proto/test.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'leveldb_proto/testing/proto',
- 'proto_out_dir': 'components/leveldb_proto/testing/proto',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
- ],
-}
diff --git a/chromium/components/leveldb_proto/BUILD.gn b/chromium/components/leveldb_proto/BUILD.gn
index 120f24175b1..88541d50bbb 100644
--- a/chromium/components/leveldb_proto/BUILD.gn
+++ b/chromium/components/leveldb_proto/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("leveldb_proto") {
+static_library("leveldb_proto") {
sources = [
"leveldb_database.cc",
"leveldb_database.h",
diff --git a/chromium/components/leveldb_proto/leveldb_database.cc b/chromium/components/leveldb_proto/leveldb_database.cc
index 6a8586f8705..5769710cb17 100644
--- a/chromium/components/leveldb_proto/leveldb_database.cc
+++ b/chromium/components/leveldb_proto/leveldb_database.cc
@@ -4,14 +4,21 @@
#include "components/leveldb_proto/leveldb_database.h"
+#include <inttypes.h>
+
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_checker.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/process_memory_dump.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
@@ -31,17 +38,20 @@ bool LevelDB::Destroy(const base::FilePath& database_dir) {
return s.ok();
}
-LevelDB::LevelDB(const char* client_name) : open_histogram_(nullptr) {
+LevelDB::LevelDB(const char* client_name)
+ : open_histogram_(nullptr), client_name_(client_name) {
// Used in lieu of UMA_HISTOGRAM_ENUMERATION because the histogram name is
// not a constant.
open_histogram_ = base::LinearHistogram::FactoryGet(
- std::string("LevelDB.Open.") + client_name, 1,
+ std::string("LevelDB.Open.") + client_name_, 1,
leveldb_env::LEVELDB_STATUS_MAX, leveldb_env::LEVELDB_STATUS_MAX + 1,
base::Histogram::kUmaTargetedHistogramFlag);
}
LevelDB::~LevelDB() {
DFAKE_SCOPED_LOCK(thread_checker_);
+ base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+ this);
}
bool LevelDB::InitWithOptions(const base::FilePath& database_dir,
@@ -62,6 +72,11 @@ bool LevelDB::InitWithOptions(const base::FilePath& database_dir,
if (status.ok()) {
CHECK(db);
db_.reset(db);
+
+ base::trace_event::MemoryDumpManager::GetInstance()
+ ->RegisterDumpProviderWithSequencedTaskRunner(
+ this, "LevelDB", base::SequencedTaskRunnerHandle::Get(),
+ base::trace_event::MemoryDumpProvider::Options());
return true;
}
@@ -123,6 +138,21 @@ bool LevelDB::Load(std::vector<std::string>* entries) {
return true;
}
+bool LevelDB::LoadKeys(std::vector<std::string>* keys) {
+ DFAKE_SCOPED_LOCK(thread_checker_);
+ if (!db_)
+ return false;
+
+ leveldb::ReadOptions options;
+ options.fill_cache = false;
+ std::unique_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
+ for (db_iterator->SeekToFirst(); db_iterator->Valid(); db_iterator->Next()) {
+ leveldb::Slice key_slice = db_iterator->key();
+ keys->push_back(std::string(key_slice.data(), key_slice.size()));
+ }
+ return true;
+}
+
bool LevelDB::Get(const std::string& key, bool* found, std::string* entry) {
DFAKE_SCOPED_LOCK(thread_checker_);
if (!db_)
@@ -144,4 +174,38 @@ bool LevelDB::Get(const std::string& key, bool* found, std::string* entry) {
return false;
}
+bool LevelDB::OnMemoryDump(const base::trace_event::MemoryDumpArgs& dump_args,
+ base::trace_event::ProcessMemoryDump* pmd) {
+ DFAKE_SCOPED_LOCK(thread_checker_);
+ if (!db_)
+ return false;
+
+ std::string value;
+ uint64_t size;
+ bool res = db_->GetProperty("leveldb.approximate-memory-usage", &value);
+ DCHECK(res);
+ res = base::StringToUint64(value, &size);
+ DCHECK(res);
+
+ base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
+ base::StringPrintf("leveldb/leveldb_proto/0x%" PRIXPTR,
+ reinterpret_cast<uintptr_t>(db_.get())));
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes, size);
+ if (!client_name_.empty() &&
+ dump_args.level_of_detail !=
+ base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) {
+ dump->AddString("client_name", "", client_name_);
+ }
+
+ // Memory is allocated from system allocator (malloc).
+ const char* system_allocator_pool_name =
+ base::trace_event::MemoryDumpManager::GetInstance()
+ ->system_allocator_pool_name();
+ if (system_allocator_pool_name)
+ pmd->AddSuballocation(dump->guid(), system_allocator_pool_name);
+
+ return true;
+}
+
} // namespace leveldb_proto
diff --git a/chromium/components/leveldb_proto/leveldb_database.h b/chromium/components/leveldb_proto/leveldb_database.h
index a3caf2f932a..8c984b797fc 100644
--- a/chromium/components/leveldb_proto/leveldb_database.h
+++ b/chromium/components/leveldb_proto/leveldb_database.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/strings/string_split.h"
#include "base/threading/thread_collision_warner.h"
+#include "base/trace_event/memory_dump_provider.h"
namespace base {
class HistogramBase;
@@ -29,14 +30,14 @@ namespace leveldb_proto {
// Interacts with the LevelDB third party module.
// Once constructed, function calls and destruction should all occur on the
// same thread (not necessarily the same as the constructor).
-class LevelDB {
+class LevelDB : base::trace_event::MemoryDumpProvider {
public:
// Constructor. Does *not* open a leveldb - only initialize this class.
// |client_name| is the name of the "client" that owns this instance. Used
// for UMA statics as so: LevelDB.<value>.<client name>. It is best to not
// change once shipped.
explicit LevelDB(const char* client_name);
- virtual ~LevelDB();
+ ~LevelDB() override;
virtual bool InitWithOptions(const base::FilePath& database_dir,
const leveldb::Options& options);
@@ -44,10 +45,15 @@ class LevelDB {
virtual bool Save(const base::StringPairs& pairs_to_save,
const std::vector<std::string>& keys_to_remove);
virtual bool Load(std::vector<std::string>* entries);
+ virtual bool LoadKeys(std::vector<std::string>* keys);
virtual bool Get(const std::string& key, bool* found, std::string* entry);
static bool Destroy(const base::FilePath& database_dir);
+ // base::trace_event::MemoryDumpProvider implementation.
+ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& dump_args,
+ base::trace_event::ProcessMemoryDump* pmd) override;
+
private:
DFAKE_MUTEX(thread_checker_);
@@ -56,6 +62,8 @@ class LevelDB {
std::unique_ptr<leveldb::Env> env_;
std::unique_ptr<leveldb::DB> db_;
base::HistogramBase* open_histogram_;
+ // Name of the client shown in chrome://tracing.
+ std::string client_name_;
DISALLOW_COPY_AND_ASSIGN(LevelDB);
};
diff --git a/chromium/components/leveldb_proto/proto_database.h b/chromium/components/leveldb_proto/proto_database.h
index 20c630e1ee9..081233c9ab1 100644
--- a/chromium/components/leveldb_proto/proto_database.h
+++ b/chromium/components/leveldb_proto/proto_database.h
@@ -27,6 +27,9 @@ class ProtoDatabase {
using UpdateCallback = base::Callback<void(bool success)>;
using LoadCallback =
base::Callback<void(bool success, std::unique_ptr<std::vector<T>>)>;
+ using LoadKeysCallback =
+ base::Callback<void(bool success,
+ std::unique_ptr<std::vector<std::string>>)>;
using GetCallback = base::Callback<void(bool success, std::unique_ptr<T>)>;
using DestroyCallback = base::Callback<void(bool success)>;
@@ -53,6 +56,10 @@ class ProtoDatabase {
// when complete.
virtual void LoadEntries(const LoadCallback& callback) = 0;
+ // Asynchronously loads all keys from the database and invokes |callback| with
+ // those keys when complete.
+ virtual void LoadKeys(const LoadKeysCallback& callback) = 0;
+
// Asynchronously loads a single entry, identified by |key|, from the database
// and invokes |callback| when complete. If no entry with |key| is found,
// a nullptr is passed to the callback, but the success flag is still true.
diff --git a/chromium/components/leveldb_proto/proto_database_impl.h b/chromium/components/leveldb_proto/proto_database_impl.h
index da02eed1387..9997d382877 100644
--- a/chromium/components/leveldb_proto/proto_database_impl.h
+++ b/chromium/components/leveldb_proto/proto_database_impl.h
@@ -53,6 +53,8 @@ class ProtoDatabaseImpl : public ProtoDatabase<T> {
const typename ProtoDatabase<T>::UpdateCallback& callback) override;
void LoadEntries(
const typename ProtoDatabase<T>::LoadCallback& callback) override;
+ void LoadKeys(
+ const typename ProtoDatabase<T>::LoadKeysCallback& callback) override;
void GetEntry(
const std::string& key,
const typename ProtoDatabase<T>::GetCallback& callback) override;
@@ -94,12 +96,20 @@ void RunUpdateCallback(
template <typename T>
void RunLoadCallback(const typename ProtoDatabase<T>::LoadCallback& callback,
- const bool* success,
+ bool* success,
std::unique_ptr<std::vector<T>> entries) {
callback.Run(*success, std::move(entries));
}
template <typename T>
+void RunLoadKeysCallback(
+ const typename ProtoDatabase<T>::LoadKeysCallback& callback,
+ std::unique_ptr<bool> success,
+ std::unique_ptr<std::vector<std::string>> keys) {
+ callback.Run(*success, std::move(keys));
+}
+
+template <typename T>
void RunGetCallback(const typename ProtoDatabase<T>::GetCallback& callback,
const bool* success,
const bool* found,
@@ -171,6 +181,15 @@ void LoadEntriesFromTaskRunner(LevelDB* database,
}
}
+void LoadKeysFromTaskRunner(LevelDB* database,
+ std::vector<std::string>* keys,
+ bool* success) {
+ DCHECK(success);
+ DCHECK(keys);
+ keys->clear();
+ *success = database->LoadKeys(keys);
+}
+
template <typename T>
void GetEntryFromTaskRunner(LevelDB* database,
const std::string& key,
@@ -286,6 +305,21 @@ void ProtoDatabaseImpl<T>::LoadEntries(
}
template <typename T>
+void ProtoDatabaseImpl<T>::LoadKeys(
+ const typename ProtoDatabase<T>::LoadKeysCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ auto success = base::MakeUnique<bool>(false);
+ auto keys = base::MakeUnique<std::vector<std::string>>();
+ auto load_task =
+ base::Bind(LoadKeysFromTaskRunner, base::Unretained(db_.get()),
+ keys.get(), success.get());
+ task_runner_->PostTaskAndReply(
+ FROM_HERE, load_task,
+ base::Bind(RunLoadKeysCallback<T>, callback, base::Passed(&success),
+ base::Passed(&keys)));
+}
+
+template <typename T>
void ProtoDatabaseImpl<T>::GetEntry(
const std::string& key,
const typename ProtoDatabase<T>::GetCallback& callback) {
diff --git a/chromium/components/leveldb_proto/proto_database_impl_unittest.cc b/chromium/components/leveldb_proto/proto_database_impl_unittest.cc
index c3dc76b4ce9..63f9f8836d4 100644
--- a/chromium/components/leveldb_proto/proto_database_impl_unittest.cc
+++ b/chromium/components/leveldb_proto/proto_database_impl_unittest.cc
@@ -17,6 +17,8 @@
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/threading/thread.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/process_memory_dump.h"
#include "components/leveldb_proto/leveldb_database.h"
#include "components/leveldb_proto/testing/proto/test.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -27,6 +29,7 @@ using base::MessageLoop;
using base::ScopedTempDir;
using testing::Invoke;
using testing::Return;
+using testing::UnorderedElementsAre;
using testing::_;
namespace leveldb_proto {
@@ -246,6 +249,56 @@ TEST_F(ProtoDatabaseImplTest, TestDBGetSuccess) {
base::RunLoop().RunUntilIdle();
}
+TEST(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoadKeys) {
+ base::MessageLoop main_loop;
+
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::Thread db_thread("dbthread");
+ ASSERT_TRUE(db_thread.Start());
+ std::unique_ptr<ProtoDatabaseImpl<TestProto>> db(
+ new ProtoDatabaseImpl<TestProto>(db_thread.task_runner()));
+
+ auto expect_init_success =
+ base::Bind([](bool success) { EXPECT_TRUE(success); });
+ db->Init(kTestLevelDBClientName, temp_dir.GetPath(), expect_init_success);
+
+ base::RunLoop run_update_entries;
+ auto expect_update_success = base::Bind(
+ [](base::Closure signal, bool success) {
+ EXPECT_TRUE(success);
+ signal.Run();
+ },
+ run_update_entries.QuitClosure());
+ TestProto test_proto;
+ test_proto.set_data("some data");
+ ProtoDatabase<TestProto>::KeyEntryVector data_set(
+ {{"0", test_proto}, {"1", test_proto}, {"2", test_proto}});
+ db->UpdateEntries(
+ base::MakeUnique<ProtoDatabase<TestProto>::KeyEntryVector>(data_set),
+ base::MakeUnique<std::vector<std::string>>(), expect_update_success);
+ run_update_entries.Run();
+
+ base::RunLoop run_load_keys;
+ auto verify_loaded_keys = base::Bind(
+ [](base::Closure signal, bool success,
+ std::unique_ptr<std::vector<std::string>> keys) {
+ EXPECT_TRUE(success);
+ EXPECT_THAT(*keys, UnorderedElementsAre("0", "1", "2"));
+ signal.Run();
+ },
+ run_load_keys.QuitClosure());
+ db->LoadKeys(verify_loaded_keys);
+ run_load_keys.Run();
+
+ // Shutdown database.
+ db.reset();
+ base::RunLoop run_destruction;
+ db_thread.task_runner()->PostTaskAndReply(
+ FROM_HERE, base::Bind(base::DoNothing), run_destruction.QuitClosure());
+ run_destruction.Run();
+}
+
TEST_F(ProtoDatabaseImplTest, TestDBGetNotFound) {
base::FilePath path(FILE_PATH_LITERAL("/fake/path"));
@@ -440,7 +493,7 @@ TEST(ProtoDatabaseImplThreadingTest, TestDBDestruction) {
MockDatabaseCaller caller;
EXPECT_CALL(caller, InitCallback(_));
db->Init(
- kTestLevelDBClientName, temp_dir.path(),
+ kTestLevelDBClientName, temp_dir.GetPath(),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
db.reset();
@@ -468,7 +521,7 @@ TEST(ProtoDatabaseImplThreadingTest, TestDBDestroy) {
MockDatabaseCaller caller;
EXPECT_CALL(caller, InitCallback(_));
db->Init(
- kTestLevelDBClientName, temp_dir.path(),
+ kTestLevelDBClientName, temp_dir.GetPath(),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
EXPECT_CALL(caller, DestroyCallback(_));
@@ -487,6 +540,8 @@ TEST(ProtoDatabaseImplThreadingTest, TestDBDestroy) {
// entries. If |close_after_save| is true, the database will be closed after
// saving and then re-opened to ensure that the data is properly persisted.
void TestLevelDBSaveAndLoad(bool close_after_save) {
+ base::MessageLoop main_loop;
+
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
@@ -502,12 +557,12 @@ void TestLevelDBSaveAndLoad(bool close_after_save) {
}
std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
- EXPECT_TRUE(db->Init(temp_dir.path()));
+ EXPECT_TRUE(db->Init(temp_dir.GetPath()));
EXPECT_TRUE(db->Save(save_entries, remove_keys));
if (close_after_save) {
db.reset(new LevelDB(kTestLevelDBClientName));
- EXPECT_TRUE(db->Init(temp_dir.path()));
+ EXPECT_TRUE(db->Init(temp_dir.GetPath()));
}
EXPECT_TRUE(db->Load(&load_entries));
@@ -543,12 +598,14 @@ TEST(ProtoDatabaseImplLevelDBTest, TestDBInitFail) {
std::vector<std::string> load_entries;
KeyVector remove_keys;
- EXPECT_FALSE(db->InitWithOptions(temp_dir.path(), options));
+ EXPECT_FALSE(db->InitWithOptions(temp_dir.GetPath(), options));
EXPECT_FALSE(db->Load(&load_entries));
EXPECT_FALSE(db->Save(save_entries, remove_keys));
}
TEST(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) {
+ base::MessageLoop main_loop;
+
std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
std::vector<std::string> load_entries;
@@ -569,4 +626,31 @@ TEST(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) {
EXPECT_EQ(1u, second_load_entries.size());
}
+TEST(ProtoDatabaseImplLevelDBTest, TestOnMemoryDumpEmitsData) {
+ base::MessageLoop main_loop;
+ std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
+ std::vector<std::string> load_entries;
+ ASSERT_TRUE(db->Init(base::FilePath()));
+ KeyValueVector save_entries(1, std::make_pair("foo", "bar"));
+ KeyVector remove_keys;
+ ASSERT_TRUE(db->Save(save_entries, remove_keys));
+
+ base::trace_event::MemoryDumpArgs dump_args = {
+ base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+ std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
+ new base::trace_event::ProcessMemoryDump(nullptr, dump_args));
+ db->OnMemoryDump(dump_args, process_memory_dump.get());
+
+ const auto& allocator_dumps = process_memory_dump->allocator_dumps();
+ const char* system_allocator_pool_name =
+ base::trace_event::MemoryDumpManager::GetInstance()
+ ->system_allocator_pool_name();
+ size_t expected_dump_count = system_allocator_pool_name ? 2 : 1;
+ EXPECT_EQ(expected_dump_count, allocator_dumps.size());
+ for (const auto& dump : allocator_dumps) {
+ ASSERT_TRUE(dump.first.find("leveldb/leveldb_proto/") == 0 ||
+ dump.first.find(system_allocator_pool_name) == 0);
+ }
+}
+
} // namespace leveldb_proto
diff --git a/chromium/components/leveldb_proto/testing/fake_db.h b/chromium/components/leveldb_proto/testing/fake_db.h
index e67ceba7a8c..bd9efb571a4 100644
--- a/chromium/components/leveldb_proto/testing/fake_db.h
+++ b/chromium/components/leveldb_proto/testing/fake_db.h
@@ -39,6 +39,8 @@ class FakeDB : public ProtoDatabase<T> {
const typename ProtoDatabase<T>::UpdateCallback& callback) override;
void LoadEntries(
const typename ProtoDatabase<T>::LoadCallback& callback) override;
+ void LoadKeys(
+ const typename ProtoDatabase<T>::LoadKeysCallback& callback) override;
void GetEntry(
const std::string& key,
const typename ProtoDatabase<T>::GetCallback& callback) override;
@@ -51,6 +53,8 @@ class FakeDB : public ProtoDatabase<T> {
void LoadCallback(bool success);
+ void LoadKeysCallback(bool success);
+
void GetCallback(bool success);
void UpdateCallback(bool success);
@@ -63,6 +67,11 @@ class FakeDB : public ProtoDatabase<T> {
std::unique_ptr<typename std::vector<T>> entries,
bool success);
+ static void RunLoadKeysCallback(
+ const typename ProtoDatabase<T>::LoadKeysCallback& callback,
+ std::unique_ptr<std::vector<std::string>> keys,
+ bool success);
+
static void RunGetCallback(
const typename ProtoDatabase<T>::GetCallback& callback,
std::unique_ptr<T> entry,
@@ -73,6 +82,7 @@ class FakeDB : public ProtoDatabase<T> {
Callback init_callback_;
Callback load_callback_;
+ Callback load_keys_callback_;
Callback get_callback_;
Callback update_callback_;
};
@@ -118,6 +128,18 @@ void FakeDB<T>::LoadEntries(
}
template <typename T>
+void FakeDB<T>::LoadKeys(
+ const typename ProtoDatabase<T>::LoadKeysCallback& callback) {
+ std::unique_ptr<std::vector<std::string>> keys(
+ new std::vector<std::string>());
+ for (const auto& pair : *db_)
+ keys->push_back(pair.first);
+
+ load_keys_callback_ =
+ base::Bind(RunLoadKeysCallback, callback, base::Passed(&keys));
+}
+
+template <typename T>
void FakeDB<T>::GetEntry(
const std::string& key,
const typename ProtoDatabase<T>::GetCallback& callback) {
@@ -152,6 +174,12 @@ void FakeDB<T>::LoadCallback(bool success) {
}
template <typename T>
+void FakeDB<T>::LoadKeysCallback(bool success) {
+ load_keys_callback_.Run(success);
+ load_keys_callback_.Reset();
+}
+
+template <typename T>
void FakeDB<T>::GetCallback(bool success) {
get_callback_.Run(success);
get_callback_.Reset();
@@ -174,6 +202,15 @@ void FakeDB<T>::RunLoadCallback(
// static
template <typename T>
+void FakeDB<T>::RunLoadKeysCallback(
+ const typename ProtoDatabase<T>::LoadKeysCallback& callback,
+ std::unique_ptr<std::vector<std::string>> keys,
+ bool success) {
+ callback.Run(success, std::move(keys));
+}
+
+// static
+template <typename T>
void FakeDB<T>::RunGetCallback(
const typename ProtoDatabase<T>::GetCallback& callback,
std::unique_ptr<T> entry,
diff --git a/chromium/components/link_header_util/link_header_util.gyp b/chromium/components/link_header_util/link_header_util.gyp
deleted file mode 100644
index 4ad5c7363cd..00000000000
--- a/chromium/components/link_header_util/link_header_util.gyp
+++ /dev/null
@@ -1,21 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/link_header_util/link_header_util
- 'target_name': 'link_header_util',
- 'type': 'static_library',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../net/net.gyp:net',
- ],
- 'sources': [
- 'link_header_util.cc',
- 'link_header_util.h',
- ],
- }
- ],
-}
diff --git a/chromium/components/location/android/BUILD.gn b/chromium/components/location/android/BUILD.gn
index d4731fac095..2ea03badd7a 100644
--- a/chromium/components/location/android/BUILD.gn
+++ b/chromium/components/location/android/BUILD.gn
@@ -4,7 +4,6 @@
import("//build/config/android/rules.gni")
-# GYP: //components/location.gypi:location_java
android_library("location_java") {
deps = [
"//base:base_java",
diff --git a/chromium/components/login.gypi b/chromium/components/login.gypi
deleted file mode 100644
index ac66212517e..00000000000
--- a/chromium/components/login.gypi
+++ /dev/null
@@ -1,29 +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.
-
-{
- 'targets': [{
- 'target_name': 'login',
- 'type': '<(component)',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/components/components.gyp:signin_core_account_id',
- '<(DEPTH)/ui/base/ui_base.gyp:ui_base',
- ],
- 'export_dependent_settings': [
- '<(DEPTH)/base/base.gyp:base',
- ],
- 'defines': [
- 'LOGIN_IMPLEMENTATION',
- ],
- 'sources': [
- 'login/base_screen_handler_utils.cc',
- 'login/base_screen_handler_utils.h',
- 'login/localized_values_builder.cc',
- 'login/localized_values_builder.h',
- 'login/screens/screen_context.cc',
- 'login/screens/screen_context.h',
- ],
- }],
-}
diff --git a/chromium/components/login/OWNERS b/chromium/components/login/OWNERS
index 7eafe555026..5539f89a17c 100644
--- a/chromium/components/login/OWNERS
+++ b/chromium/components/login/OWNERS
@@ -1,5 +1,4 @@
achuith@chromium.org
alemate@chromium.org
-dzhioev@chromium.org
piman@chromium.org
xiyuan@chromium.org
diff --git a/chromium/components/memory_coordinator.gypi b/chromium/components/memory_coordinator.gypi
deleted file mode 100644
index bb848e142ed..00000000000
--- a/chromium/components/memory_coordinator.gypi
+++ /dev/null
@@ -1,42 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/memory_coordinator/public/interfaces
- 'target_name': 'memory_coordinator_mojo_bindings',
- 'type': 'static_library',
- 'sources': [
- 'memory_coordinator/public/interfaces/child_memory_coordinator.mojom',
- ],
- 'includes': [ '../mojo/mojom_bindings_generator.gypi' ],
- },
- {
- # GN version: //components/memory_coordinator/common
- 'target_name': 'memory_coordinator_common',
- 'type': 'none',
- 'dependencies': [
- 'memory_coordinator_mojo_bindings',
- ],
- 'sources': [
- 'memory_coordinator/common/memory_coordinator_client.h',
- ],
- },
- {
- # GN version: //components/memory_coordinator/child
- 'target_name': 'memory_coordinator_child',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- 'memory_coordinator_common',
- 'memory_coordinator_mojo_bindings',
- ],
- 'sources': [
- 'memory_coordinator/child/child_memory_coordinator_impl.cc',
- 'memory_coordinator/child/child_memory_coordinator_impl.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/memory_coordinator/DEPS b/chromium/components/memory_coordinator/DEPS
deleted file mode 100644
index ef8ad28d9d4..00000000000
--- a/chromium/components/memory_coordinator/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+mojo/public",
-]
diff --git a/chromium/components/memory_coordinator/OWNERS b/chromium/components/memory_coordinator/OWNERS
deleted file mode 100644
index 26ad3ee4c73..00000000000
--- a/chromium/components/memory_coordinator/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-bashi@chromium.org
-chrisha@chromium.org
-haraken@chromium.org
diff --git a/chromium/components/memory_coordinator/child/BUILD.gn b/chromium/components/memory_coordinator/child/BUILD.gn
deleted file mode 100644
index db58c2ddd4d..00000000000
--- a/chromium/components/memory_coordinator/child/BUILD.gn
+++ /dev/null
@@ -1,30 +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.
-
-source_set("child") {
- sources = [
- "child_memory_coordinator_impl.cc",
- "child_memory_coordinator_impl.h",
- ]
-
- deps = [
- "//base",
- "//components/memory_coordinator/common",
- "//components/memory_coordinator/public/interfaces",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
-
- sources = [
- "child_memory_coordinator_impl_unittest.cc",
- ]
-
- deps = [
- ":child",
- "//mojo/common",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/memory_coordinator/child/child_memory_coordinator_impl.cc b/chromium/components/memory_coordinator/child/child_memory_coordinator_impl.cc
deleted file mode 100644
index 75889ed43f6..00000000000
--- a/chromium/components/memory_coordinator/child/child_memory_coordinator_impl.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/memory_coordinator/child/child_memory_coordinator_impl.h"
-
-namespace memory_coordinator {
-
-ChildMemoryCoordinatorImpl::ChildMemoryCoordinatorImpl(
- mojo::InterfaceRequest<mojom::ChildMemoryCoordinator> request,
- scoped_refptr<ClientList> clients)
- : binding_(this, std::move(request)),
- clients_(clients) {}
-
-ChildMemoryCoordinatorImpl::~ChildMemoryCoordinatorImpl() {}
-
-void ChildMemoryCoordinatorImpl::OnStateChange(mojom::MemoryState state) {
- clients_->Notify(FROM_HERE, &MemoryCoordinatorClient::OnMemoryStateChange,
- state);
-}
-
-} // namespace memory_coordinator
diff --git a/chromium/components/memory_coordinator/child/child_memory_coordinator_impl.h b/chromium/components/memory_coordinator/child/child_memory_coordinator_impl.h
deleted file mode 100644
index bdb6376a694..00000000000
--- a/chromium/components/memory_coordinator/child/child_memory_coordinator_impl.h
+++ /dev/null
@@ -1,40 +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 COMPONENTS_MEMORY_COORDINATOR_CHILD_CHILD_MEMORY_COORDINATOR_IMPL_H_
-#define COMPONENTS_MEMORY_COORDINATOR_CHILD_CHILD_MEMORY_COORDINATOR_IMPL_H_
-
-#include "base/compiler_specific.h"
-#include "base/observer_list_threadsafe.h"
-#include "components/memory_coordinator/common/memory_coordinator_client.h"
-#include "components/memory_coordinator/public/interfaces/child_memory_coordinator.mojom.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace memory_coordinator {
-
-// ChildMemoryCoordinatorImpl is the implementation of ChildMemoryCoordinator.
-// It lives in child processes and is responsible for dispatching memory events
-// to its clients.
-class ChildMemoryCoordinatorImpl
- : NON_EXPORTED_BASE(public mojom::ChildMemoryCoordinator) {
- public:
- using ClientList = base::ObserverListThreadSafe<MemoryCoordinatorClient>;
- ChildMemoryCoordinatorImpl(
- mojo::InterfaceRequest<mojom::ChildMemoryCoordinator> request,
- scoped_refptr<ClientList> clients);
- ~ChildMemoryCoordinatorImpl() override;
-
- // mojom::ChildMemoryCoordinator implementations:
- void OnStateChange(mojom::MemoryState state) override;
-
- private:
- mojo::StrongBinding<mojom::ChildMemoryCoordinator> binding_;
- scoped_refptr<ClientList> clients_;
-
- DISALLOW_COPY_AND_ASSIGN(ChildMemoryCoordinatorImpl);
-};
-
-} // namespace content
-
-#endif // COMPONENTS_MEMORY_COORDINATOR_CHILD_CHILD_MEMORY_COORDINATOR_IMPL_H_
diff --git a/chromium/components/memory_coordinator/child/child_memory_coordinator_impl_unittest.cc b/chromium/components/memory_coordinator/child/child_memory_coordinator_impl_unittest.cc
deleted file mode 100644
index 3b7db4037d6..00000000000
--- a/chromium/components/memory_coordinator/child/child_memory_coordinator_impl_unittest.cc
+++ /dev/null
@@ -1,137 +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 "components/memory_coordinator/child/child_memory_coordinator_impl.h"
-
-#include <memory>
-
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/threading/thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace memory_coordinator {
-
-namespace {
-
-class ChildMemoryCoordinatorImplTest : public testing::Test {
- public:
- ChildMemoryCoordinatorImplTest()
- : clients_(new ChildMemoryCoordinatorImpl::ClientList),
- message_loop_(new base::MessageLoop),
- coordinator_impl_(mojo::GetProxy(&coordinator_), clients_) {}
-
- void RegisterClient(MemoryCoordinatorClient* client) {
- clients_->AddObserver(client);
- }
-
- void UnregisterClient(MemoryCoordinatorClient* client) {
- clients_->RemoveObserver(client);
- }
-
- mojom::ChildMemoryCoordinatorPtr& coordinator() { return coordinator_; }
- ChildMemoryCoordinatorImpl& coordinator_impl() { return coordinator_impl_; }
-
- void ChangeState(mojom::MemoryState state) {
- base::RunLoop loop;
- coordinator()->OnStateChange(state);
- loop.RunUntilIdle();
- }
-
- protected:
- scoped_refptr<ChildMemoryCoordinatorImpl::ClientList> clients_;
-
- private:
- std::unique_ptr<base::MessageLoop> message_loop_;
- mojom::ChildMemoryCoordinatorPtr coordinator_ = nullptr;
- ChildMemoryCoordinatorImpl coordinator_impl_;
-
- DISALLOW_COPY_AND_ASSIGN(ChildMemoryCoordinatorImplTest);
-};
-
-class MockMemoryCoordinatorClient final : public MemoryCoordinatorClient {
-public:
- void OnMemoryStateChange(mojom::MemoryState state) override {
- last_state_ = state;
- }
-
- mojom::MemoryState last_state() const { return last_state_; }
-
- private:
- mojom::MemoryState last_state_ = mojom::MemoryState::UNKNOWN;
-};
-
-class MemoryCoordinatorTestThread : public base::Thread,
- public MemoryCoordinatorClient {
- public:
- MemoryCoordinatorTestThread(
- const std::string& name,
- scoped_refptr<ChildMemoryCoordinatorImpl::ClientList> clients)
- : Thread(name), clients_(clients) {}
- ~MemoryCoordinatorTestThread() override { Stop(); }
-
- void Init() override {
- clients_->AddObserver(this);
- }
-
- void OnMemoryStateChange(mojom::MemoryState state) override {
- EXPECT_EQ(message_loop(), base::MessageLoop::current());
- last_state_ = state;
- }
-
- void CheckLastState(mojom::MemoryState state) {
- task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&MemoryCoordinatorTestThread::CheckLastStateInternal,
- base::Unretained(this), state));
- }
-
- private:
- void CheckLastStateInternal(mojom::MemoryState state) {
- base::RunLoop loop;
- loop.RunUntilIdle();
- EXPECT_EQ(state, last_state_);
- }
-
- scoped_refptr<ChildMemoryCoordinatorImpl::ClientList> clients_;
- mojom::MemoryState last_state_ = mojom::MemoryState::UNKNOWN;
-};
-
-TEST_F(ChildMemoryCoordinatorImplTest, SingleClient) {
- MockMemoryCoordinatorClient client;
- RegisterClient(&client);
-
- ChangeState(mojom::MemoryState::THROTTLED);
- EXPECT_EQ(mojom::MemoryState::THROTTLED, client.last_state());
-
- ChangeState(mojom::MemoryState::NORMAL);
- EXPECT_EQ(mojom::MemoryState::NORMAL, client.last_state());
-
- UnregisterClient(&client);
- ChangeState(mojom::MemoryState::THROTTLED);
- EXPECT_TRUE(mojom::MemoryState::THROTTLED != client.last_state());
-}
-
-TEST_F(ChildMemoryCoordinatorImplTest, MultipleClients) {
- MemoryCoordinatorTestThread t1("thread 1", clients_);
- MemoryCoordinatorTestThread t2("thread 2", clients_);
-
- t1.StartAndWaitForTesting();
- t2.StartAndWaitForTesting();
-
- ChangeState(mojom::MemoryState::THROTTLED);
- t1.CheckLastState(mojom::MemoryState::THROTTLED);
- t2.CheckLastState(mojom::MemoryState::THROTTLED);
-
- ChangeState(mojom::MemoryState::NORMAL);
- t1.CheckLastState(mojom::MemoryState::NORMAL);
- t2.CheckLastState(mojom::MemoryState::NORMAL);
-
- t1.Stop();
- t2.Stop();
-}
-
-} // namespace
-
-} // namespace memory_coordinator
diff --git a/chromium/components/memory_coordinator/common/BUILD.gn b/chromium/components/memory_coordinator/common/BUILD.gn
deleted file mode 100644
index 950b137bda5..00000000000
--- a/chromium/components/memory_coordinator/common/BUILD.gn
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("common") {
- sources = [
- "memory_coordinator_client.h",
- ]
-
- public_deps = [
- "//components/memory_coordinator/public/interfaces",
- ]
-}
diff --git a/chromium/components/memory_coordinator/common/memory_coordinator_client.h b/chromium/components/memory_coordinator/common/memory_coordinator_client.h
deleted file mode 100644
index 44a04ad593d..00000000000
--- a/chromium/components/memory_coordinator/common/memory_coordinator_client.h
+++ /dev/null
@@ -1,24 +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 MEMORY_COORDINATOR_COMMON_MEMORY_COORDINATOR_CLIENT_H_
-#define MEMORY_COORDINATOR_COMMON_MEMORY_COORDINATOR_CLIENT_H_
-
-#include "components/memory_coordinator/public/interfaces/child_memory_coordinator.mojom.h"
-
-namespace memory_coordinator {
-
-// This is an interface for components which can respond to memory status
-// changes.
-class MemoryCoordinatorClient {
- public:
- virtual ~MemoryCoordinatorClient() {}
-
- // Called when memory state has changed.
- virtual void OnMemoryStateChange(mojom::MemoryState state) = 0;
-};
-
-} // namespace memory_coordinator
-
-#endif // MEMORY_COORDINATOR_COMMON_MEMORY_COORDINATOR_CLIENT_H_
diff --git a/chromium/components/memory_coordinator/public/interfaces/BUILD.gn b/chromium/components/memory_coordinator/public/interfaces/BUILD.gn
deleted file mode 100644
index 770bc290214..00000000000
--- a/chromium/components/memory_coordinator/public/interfaces/BUILD.gn
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("interfaces") {
- sources = [
- "child_memory_coordinator.mojom",
- ]
-}
diff --git a/chromium/components/memory_coordinator/public/interfaces/OWNERS b/chromium/components/memory_coordinator/public/interfaces/OWNERS
deleted file mode 100644
index b6fb12b2a87..00000000000
--- a/chromium/components/memory_coordinator/public/interfaces/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Changes to Mojo interfaces require a security review to avoid
-# introducing new sandbox escapes.
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS \ No newline at end of file
diff --git a/chromium/components/memory_coordinator/public/interfaces/child_memory_coordinator.mojom b/chromium/components/memory_coordinator/public/interfaces/child_memory_coordinator.mojom
deleted file mode 100644
index 59c653ebcdb..00000000000
--- a/chromium/components/memory_coordinator/public/interfaces/child_memory_coordinator.mojom
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module memory_coordinator.mojom;
-
-enum MemoryState {
- UNKNOWN = -1,
- NORMAL = 0,
- THROTTLED = 1,
- // TODO(bashi): Define SUSPENDED when we need it.
- // SUSPENDED = 2,
-};
-
-// ChildMemoryCoordinator lives in a child process and receives memory events
-// dispatched by the central memory coordinator which lives in the browser
-// process.
-interface ChildMemoryCoordinator {
- // Called when the central memory coodinator changes the state for child
- // processes.
- OnStateChange(MemoryState state);
-};
diff --git a/chromium/components/memory_pressure.gypi b/chromium/components/memory_pressure.gypi
deleted file mode 100644
index 41d8e0cf176..00000000000
--- a/chromium/components/memory_pressure.gypi
+++ /dev/null
@@ -1,35 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/memory_pressure
- 'target_name': 'memory_pressure',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'memory_pressure/direct_memory_pressure_calculator.h',
- 'memory_pressure/direct_memory_pressure_calculator_linux.cc',
- 'memory_pressure/direct_memory_pressure_calculator_linux.h',
- 'memory_pressure/direct_memory_pressure_calculator_win.cc',
- 'memory_pressure/direct_memory_pressure_calculator_win.h',
- 'memory_pressure/filtered_memory_pressure_calculator.cc',
- 'memory_pressure/filtered_memory_pressure_calculator.h',
- 'memory_pressure/memory_pressure_calculator.h',
- 'memory_pressure/memory_pressure_listener.cc',
- 'memory_pressure/memory_pressure_listener.h',
- 'memory_pressure/memory_pressure_monitor.cc',
- 'memory_pressure/memory_pressure_monitor.h',
- 'memory_pressure/memory_pressure_stats_collector.cc',
- 'memory_pressure/memory_pressure_stats_collector.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/memory_pressure/BUILD.gn b/chromium/components/memory_pressure/BUILD.gn
index a1728071097..0f6af8519e2 100644
--- a/chromium/components/memory_pressure/BUILD.gn
+++ b/chromium/components/memory_pressure/BUILD.gn
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/memory_pressure.gypi:memory_pressure
-source_set("memory_pressure") {
+static_library("memory_pressure") {
sources = [
"direct_memory_pressure_calculator.h",
"direct_memory_pressure_calculator_linux.cc",
diff --git a/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux.cc b/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux.cc
index f1dbc01f16f..358d655c1e6 100644
--- a/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux.cc
+++ b/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux.cc
@@ -4,14 +4,46 @@
#include "components/memory_pressure/direct_memory_pressure_calculator_linux.h"
+#include "base/files/file_util.h"
#include "base/process/process_metrics.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "base/sys_info.h"
+#include "base/threading/thread_restrictions.h"
namespace memory_pressure {
namespace {
-static const int kKiBperMiB = 1024;
+const int kKiBperMiB = 1024;
+
+// Used to calculate a moving average of faults/sec. Our sample times are
+// inconsistent because MemoryPressureMonitor calls
+// CalculateCurrentPressureLevel more frequently when memory pressure is high,
+// and because we're measuring CPU time instead of real time. So our
+// exponentially weighted moving average is generalized to a low-pass filter.
+//
+// Represents the amount of CPU time, in seconds, for a sample to be 50%
+// forgotten in our moving average. Systems with more CPUs that are under high
+// load will have a moving average that changes more quickly than a system with
+// fewer CPUs under the same load. Do not normalize based on the number of CPUs
+// because this behavior is accurate: if a system with a large number of CPUs
+// is getting lots of work done without page faulting, it must not be under
+// memory pressure.
+//
+// TODO(thomasanderson): Experimentally determine the correct value for this
+// constant.
+const double kLowPassHalfLife = 30.0;
+
+// Returns the amount of memory that is available for use right now, or that can
+// be easily reclaimed by the OS, in MBs.
+int GetAvailableSystemMemoryMiB(const base::SystemMemoryInfoKB* mem_info) {
+ return mem_info->available
+ ? mem_info->available / kKiBperMiB
+ : (mem_info->free + mem_info->buffers + mem_info->cached) /
+ kKiBperMiB;
+}
} // namespace
@@ -21,8 +53,10 @@ const int DirectMemoryPressureCalculator::kDefaultModerateThresholdPc = 70;
const int DirectMemoryPressureCalculator::kDefaultCriticalThresholdPc = 90;
DirectMemoryPressureCalculator::DirectMemoryPressureCalculator()
- : moderate_threshold_mb_(0), critical_threshold_mb_(0) {
+ : moderate_threshold_mb_(0),
+ critical_threshold_mb_(0) {
InferThresholds();
+ InitPageFaultMonitor();
}
DirectMemoryPressureCalculator::DirectMemoryPressureCalculator(
@@ -32,34 +66,80 @@ DirectMemoryPressureCalculator::DirectMemoryPressureCalculator(
critical_threshold_mb_(critical_threshold_mb) {
DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
DCHECK_LE(0, critical_threshold_mb_);
+ InitPageFaultMonitor();
}
DirectMemoryPressureCalculator::MemoryPressureLevel
-DirectMemoryPressureCalculator::CalculateCurrentPressureLevel() {
- base::SystemMemoryInfoKB mem_info = {};
- if (!GetSystemMemoryInfo(&mem_info))
+DirectMemoryPressureCalculator::PressureCausedByThrashing(
+ const base::SystemMemoryInfoKB& mem_info) {
+ base::TimeDelta new_user_exec_time = GetUserCpuTimeSinceBoot();
+ if (new_user_exec_time == base::TimeDelta())
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+ uint64_t new_major_page_faults = mem_info.pgmajfault;
+ if (new_user_exec_time != base::TimeDelta() && new_major_page_faults &&
+ (new_user_exec_time - last_user_exec_time_) != base::TimeDelta()) {
+ double delta_user_exec_time =
+ (new_user_exec_time - last_user_exec_time_).InSecondsF();
+ double delta_major_page_faults =
+ new_major_page_faults - last_major_page_faults_;
+
+ double sampled_faults_per_second =
+ delta_major_page_faults / delta_user_exec_time;
+
+ double adjusted_ewma_coefficient =
+ 1 - exp2(-delta_user_exec_time / low_pass_half_life_seconds_);
+
+ current_faults_per_second_ =
+ adjusted_ewma_coefficient * sampled_faults_per_second +
+ (1 - adjusted_ewma_coefficient) * current_faults_per_second_;
+
+ last_user_exec_time_ = new_user_exec_time;
+ last_major_page_faults_ = new_major_page_faults;
+ }
+
+ if (current_faults_per_second_ >
+ critical_multiplier_ * AverageFaultsPerSecond()) {
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+ }
+ if (current_faults_per_second_ >
+ moderate_multiplier_ * AverageFaultsPerSecond()) {
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+ }
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
- // How much system memory is actively available for use right now, in MBs.
- int phys_free = mem_info.free / kKiBperMiB;
+DirectMemoryPressureCalculator::MemoryPressureLevel
+DirectMemoryPressureCalculator::PressureCausedByOOM(
+ const base::SystemMemoryInfoKB& mem_info) {
+ int phys_free = GetAvailableSystemMemoryMiB(&mem_info);
- // Determine if the physical memory is under critical memory pressure.
if (phys_free <= critical_threshold_mb_)
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
-
- // Determine if the physical memory is under moderate memory pressure.
if (phys_free <= moderate_threshold_mb_)
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
-
- // No memory pressure was detected.
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
}
+DirectMemoryPressureCalculator::MemoryPressureLevel
+DirectMemoryPressureCalculator::CalculateCurrentPressureLevel() {
+ base::SystemMemoryInfoKB mem_info = {};
+ if (!GetSystemMemoryInfo(&mem_info))
+ return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+
+ return std::max(PressureCausedByThrashing(mem_info),
+ PressureCausedByOOM(mem_info));
+}
+
bool DirectMemoryPressureCalculator::GetSystemMemoryInfo(
base::SystemMemoryInfoKB* mem_info) const {
return base::GetSystemMemoryInfo(mem_info);
}
+base::TimeDelta DirectMemoryPressureCalculator::GetUserCpuTimeSinceBoot()
+ const {
+ return base::GetUserCpuTimeSinceBoot();
+}
+
void DirectMemoryPressureCalculator::InferThresholds() {
base::SystemMemoryInfoKB mem_info = {};
if (!GetSystemMemoryInfo(&mem_info))
@@ -71,4 +151,19 @@ void DirectMemoryPressureCalculator::InferThresholds() {
mem_info.total * (100 - kDefaultCriticalThresholdPc) / 100 / kKiBperMiB;
}
+void DirectMemoryPressureCalculator::InitPageFaultMonitor() {
+ low_pass_half_life_seconds_ = kLowPassHalfLife;
+ last_user_exec_time_ = GetUserCpuTimeSinceBoot();
+ base::SystemMemoryInfoKB mem_info = {};
+ last_major_page_faults_ =
+ GetSystemMemoryInfo(&mem_info) ? mem_info.pgmajfault : 0;
+ current_faults_per_second_ = AverageFaultsPerSecond();
+}
+
+double DirectMemoryPressureCalculator::AverageFaultsPerSecond() const {
+ return last_major_page_faults_ == 0
+ ? last_user_exec_time_.InSecondsF() / last_major_page_faults_
+ : 0;
+}
+
} // namespace memory_pressure
diff --git a/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux.h b/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux.h
index 4fee7651b6d..315b8d93f19 100644
--- a/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux.h
+++ b/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux.h
@@ -5,13 +5,13 @@
#ifndef COMPONENTS_MEMORY_PRESSURE_DIRECT_MEMORY_PRESSURE_CALCULATOR_LINUX_H_
#define COMPONENTS_MEMORY_PRESSURE_DIRECT_MEMORY_PRESSURE_CALCULATOR_LINUX_H_
-#include "components/memory_pressure/memory_pressure_calculator.h"
-
-#include "base/files/scoped_file.h"
#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
#include "base/process/process_metrics.h"
-#include "base/timer/timer.h"
+#include "components/memory_pressure/memory_pressure_calculator.h"
+
+namespace base {
+class TimeDelta;
+}
namespace memory_pressure {
@@ -46,20 +46,63 @@ class DirectMemoryPressureCalculator : public MemoryPressureCalculator {
private:
friend class TestDirectMemoryPressureCalculator;
+ MemoryPressureLevel PressureCausedByThrashing(
+ const base::SystemMemoryInfoKB& mem_info);
+ MemoryPressureLevel PressureCausedByOOM(
+ const base::SystemMemoryInfoKB& mem_info);
+
// Gets system memory status. This is virtual as a unittesting hook and by
// default this invokes base::GetSystemMemoryInfo.
virtual bool GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info) const;
+ // We use CPU time instead of real time because this eliminates the variable
+ // of average system load. Consumer machines are idle most of the time, so if
+ // we used real time, the average faults/sec would be very low. As soon as
+ // the user loads anything, the instantaneous faults/sec would increase, and
+ // we would overreport the memory pressure.
+ //
+ // We also ignore system time because we don't want to include the time the OS
+ // takes to swap pages in/out on behalf of processes.
+ //
+ // Virtual as a unittesting hook.
+ virtual base::TimeDelta GetUserCpuTimeSinceBoot() const;
+
// Uses GetSystemMemoryInfo to automatically infer appropriate values for
// moderate_threshold_mb_ and critical_threshold_mb_.
void InferThresholds();
+ // Initialize the page fault monitor state so CalculateCurrentPressureLevel
+ // will have a delta to analyze.
+ virtual void InitPageFaultMonitor();
+
+ // Computes last_major_page_faults_/last_user_exec_time_ with some
+ // protection.
+ double AverageFaultsPerSecond() const;
+
// Threshold amounts of available memory that trigger pressure levels. See
// memory_pressure_monitor_win.cc for a discussion of reasonable values for
// these.
int moderate_threshold_mb_;
int critical_threshold_mb_;
+ // State needed by the hard page fault monitor. These values are assumed
+ // not to overflow.
+ base::TimeDelta last_user_exec_time_;
+ uint64_t last_major_page_faults_;
+ // An exponentially weighted moving average of the sampled faults/sec.
+ double current_faults_per_second_;
+
+ double low_pass_half_life_seconds_;
+
+ // |current_faults_per_second_| must be at least |kModerateMultiplier| *
+ // AverageFaultsPerSecond() to report moderate pressure, and similarly for
+ // critical pressure. Non-const members for unit testing.
+ //
+ // TODO(thomasanderson): Experimentally determine the correct value for these
+ // constants.
+ double moderate_multiplier_ = 5.0;
+ double critical_multiplier_ = 10.0;
+
DISALLOW_COPY_AND_ASSIGN(DirectMemoryPressureCalculator);
};
diff --git a/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux_unittest.cc b/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux_unittest.cc
index 52c922c72b5..591f973915e 100644
--- a/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux_unittest.cc
+++ b/chromium/components/memory_pressure/direct_memory_pressure_calculator_linux_unittest.cc
@@ -4,14 +4,15 @@
#include "components/memory_pressure/direct_memory_pressure_calculator_linux.h"
+#include "base/process/process_metrics.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace memory_pressure {
namespace {
-static const int kKBperMB = 1024;
-static const int kTotalMemoryInMB = 4096;
+const int kKBperMB = 1024;
+const int kTotalMemoryInMB = 4096;
} // namespace
@@ -20,7 +21,7 @@ static const int kTotalMemoryInMB = 4096;
class TestDirectMemoryPressureCalculator
: public DirectMemoryPressureCalculator {
public:
- explicit TestDirectMemoryPressureCalculator()
+ TestDirectMemoryPressureCalculator()
: DirectMemoryPressureCalculator(20, 10) {
// The values passed to the MemoryPressureCalculator constructor are dummy
// values that are immediately overwritten by InferTresholds.
@@ -38,8 +39,11 @@ class TestDirectMemoryPressureCalculator
: DirectMemoryPressureCalculator(moderate_threshold_mb,
critical_threshold_mb) {
mem_info_.total = total_memory_mb * kKBperMB;
+ mem_info_.pgmajfault = 0;
}
+ void InitPageFaultMonitor() override {}
+
// Sets up the memory status to reflect the provided absolute memory left.
void SetMemoryFree(int phys_left_mb) {
// |total| is set in the constructor and not modified.
@@ -50,11 +54,34 @@ class TestDirectMemoryPressureCalculator
}
void SetNone() { SetMemoryFree(moderate_threshold_mb() + 1); }
-
void SetModerate() { SetMemoryFree(moderate_threshold_mb() - 1); }
-
void SetCritical() { SetMemoryFree(critical_threshold_mb() - 1); }
+ double GetEwma() { return current_faults_per_second_; }
+
+ // Set the next CPU time to be read.
+ void SetCpuTime(double cpu_time) {
+ user_cpu_time_ = base::TimeDelta::FromSecondsD(cpu_time);
+ }
+ // Set the next page faults value to be read.
+ void SetPageFaults(uint64_t page_faults) {
+ mem_info_.pgmajfault = page_faults;
+ }
+
+ void SetPageFaultMonitorState(double user_exec_time,
+ uint64_t major_page_faults,
+ double current_faults,
+ double low_pass_half_life,
+ double moderate_multiplier,
+ double critical_multiplier) {
+ last_user_exec_time_ = base::TimeDelta::FromSecondsD(user_exec_time);
+ last_major_page_faults_ = major_page_faults;
+ current_faults_per_second_ = current_faults;
+ low_pass_half_life_seconds_ = low_pass_half_life;
+ moderate_multiplier_ = moderate_multiplier;
+ critical_multiplier_ = critical_multiplier;
+ }
+
private:
bool GetSystemMemoryInfo(base::SystemMemoryInfoKB* mem_info) const override {
// Simply copy the memory information set by the test fixture.
@@ -62,6 +89,11 @@ class TestDirectMemoryPressureCalculator
return true;
}
+ base::TimeDelta GetUserCpuTimeSinceBoot() const override {
+ return user_cpu_time_;
+ }
+
+ base::TimeDelta user_cpu_time_;
base::SystemMemoryInfoKB mem_info_;
};
@@ -147,4 +179,66 @@ TEST_F(DirectMemoryPressureCalculatorTest,
ASSERT_NO_FATAL_FAILURE(CalculateCurrentPressureLevelTest(&calc));
}
+// Double-check the math of the Ewma portion of the page fault monitor.
+TEST_F(DirectMemoryPressureCalculatorTest, Ewma) {
+ double half_life = 100.0;
+
+ double cpu_time = 0;
+ uint64_t page_faults = 1;
+
+ double ewma = 100.0;
+
+ TestDirectMemoryPressureCalculator calc;
+ calc.SetPageFaultMonitorState(cpu_time, page_faults, ewma, half_life, 0, 0);
+ // Advance by one half-life. The ewma should be cut in half.
+ calc.SetCpuTime(half_life);
+ calc.SetPageFaults(page_faults);
+ calc.CalculateCurrentPressureLevel();
+ ewma /= 2;
+ EXPECT_DOUBLE_EQ(ewma, calc.GetEwma());
+
+ // We should get the same result if we advance by increments of 10 up to 100.
+ ewma = 100.0;
+ calc.SetPageFaultMonitorState(cpu_time, page_faults, ewma, half_life, 0, 0);
+ static const int kIncrements = 10;
+ for(int i = 1; i <= kIncrements; i++) {
+ calc.SetCpuTime(i * half_life / kIncrements);
+ calc.SetPageFaults(page_faults);
+ calc.CalculateCurrentPressureLevel();
+ }
+ ewma /= 2;
+ EXPECT_DOUBLE_EQ(ewma, calc.GetEwma());
+
+ static const struct {
+ uint64_t delta_time;
+ uint64_t delta_faults;
+ double expected_ewma;
+ } kSamples[] = {
+ // 0.5*0.0 + 0.5*10 = 5.0
+ { 1, 10, 5.0 },
+ // 0.5*5.0 + 0.5*10 = 7.5
+ { 1, 10, 7.5 },
+ // 0.25*7.5 + 0.75*(0/2) = 1.875
+ { 2, 0, 1.875 },
+ // 0.125*1.875 + 0.875*(420/3) = 122.734375
+ { 3, 420, 122.734375 },
+ // 0.5*122.734375 + 0.5*24 = 73.3671875
+ { 1, 24, 73.3671875 },
+ };
+
+ cpu_time = 1;
+ page_faults = 1;
+ ewma = 0.0;
+ half_life = 1.0;
+ calc.SetPageFaultMonitorState(cpu_time, page_faults, ewma, half_life, 0, 0);
+ for (size_t i = 0 ; i < arraysize(kSamples); i++) {
+ cpu_time += kSamples[i].delta_time;
+ page_faults += kSamples[i].delta_faults;
+ calc.SetCpuTime(cpu_time);
+ calc.SetPageFaults(page_faults);
+ calc.CalculateCurrentPressureLevel();
+ EXPECT_DOUBLE_EQ(kSamples[i].expected_ewma, calc.GetEwma());
+ }
+}
+
} // namespace memory_pressure
diff --git a/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.cc b/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.cc
index 5fee012ac14..f393b7cf54f 100644
--- a/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.cc
+++ b/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.cc
@@ -4,13 +4,16 @@
#include "components/memory_pressure/direct_memory_pressure_calculator_win.h"
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+
namespace memory_pressure {
#if defined(MEMORY_PRESSURE_IS_POLLING)
namespace {
-static const int kKBperMB = 1024;
+const int kKBperMB = 1024;
} // namespace
diff --git a/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.h b/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.h
index 10e2d24e285..648dc74a8d8 100644
--- a/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.h
+++ b/chromium/components/memory_pressure/direct_memory_pressure_calculator_win.h
@@ -5,11 +5,10 @@
#ifndef COMPONENTS_MEMORY_PRESSURE_DIRECT_MEMORY_PRESSURE_CALCULATOR_WIN_H_
#define COMPONENTS_MEMORY_PRESSURE_DIRECT_MEMORY_PRESSURE_CALCULATOR_WIN_H_
-#include "components/memory_pressure/memory_pressure_calculator.h"
-
#include "base/macros.h"
#include "base/process/process_metrics.h"
#include "build/build_config.h"
+#include "components/memory_pressure/memory_pressure_calculator.h"
namespace memory_pressure {
diff --git a/chromium/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc b/chromium/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc
index c5c6507d6f1..c7c48e6f199 100644
--- a/chromium/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc
+++ b/chromium/components/memory_pressure/direct_memory_pressure_calculator_win_unittest.cc
@@ -4,6 +4,8 @@
#include "components/memory_pressure/direct_memory_pressure_calculator_win.h"
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace memory_pressure {
@@ -12,7 +14,7 @@ namespace memory_pressure {
namespace {
-static const int kKBperMB = 1024;
+const int kKBperMB = 1024;
} // namespace
diff --git a/chromium/components/memory_pressure/memory_pressure_stats_collector.cc b/chromium/components/memory_pressure/memory_pressure_stats_collector.cc
index 2753b05691b..b4ff482bd4e 100644
--- a/chromium/components/memory_pressure/memory_pressure_stats_collector.cc
+++ b/chromium/components/memory_pressure/memory_pressure_stats_collector.cc
@@ -8,7 +8,7 @@
#include <stdint.h>
#include "base/macros.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/time/tick_clock.h"
namespace memory_pressure {
@@ -50,37 +50,6 @@ MemoryPressureLevel MemoryPressureLevelFromUmaEnumValue(
return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
}
-// Converts a pressure state change to an UMA enumeration value.
-MemoryPressureLevelChangeUMA MemoryPressureLevelChangeToUmaEnumValue(
- MemoryPressureLevel old_level,
- MemoryPressureLevel new_level) {
- switch (old_level) {
- case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: {
- if (new_level == MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE)
- return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_NONE_TO_MODERATE;
- if (new_level == MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL)
- return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_NONE_TO_CRITICAL;
- break; // Should never happen; handled by the NOTREACHED below.
- }
- case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: {
- if (new_level == MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE)
- return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_MODERATE_TO_NONE;
- if (new_level == MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL)
- return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_MODERATE_TO_CRITICAL;
- break; // Should never happen; handled by the NOTREACHED below.
- }
- case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: {
- if (new_level == MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE)
- return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_CRITICAL_TO_MODERATE;
- if (new_level == MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE)
- return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_CRITICAL_TO_MODERATE;
- break; // Should never happen; handled by the NOTREACHED below.
- }
- }
- NOTREACHED();
- return UMA_MEMORY_PRESSURE_LEVEL_CHANGE_NONE_TO_MODERATE;
-}
-
} // namespace
MemoryPressureStatsCollector::MemoryPressureStatsCollector(
@@ -149,10 +118,7 @@ void MemoryPressureStatsCollector::ReportCumulativeTime(
void MemoryPressureStatsCollector::ReportLevelChange(
MemoryPressureLevel old_pressure_level,
MemoryPressureLevel new_pressure_level) {
- UMA_HISTOGRAM_ENUMERATION("Memory.PressureLevelChange",
- MemoryPressureLevelChangeToUmaEnumValue(
- old_pressure_level, new_pressure_level),
- UMA_MEMORY_PRESSURE_LEVEL_CHANGE_COUNT);
+ // TODO(chrisha): Report Memory.PressureLevelChange when this code is in use.
}
} // namespace memory_pressure
diff --git a/chromium/components/memory_pressure/memory_pressure_stats_collector_unittest.cc b/chromium/components/memory_pressure/memory_pressure_stats_collector_unittest.cc
index 9557205df7c..cc7788bac38 100644
--- a/chromium/components/memory_pressure/memory_pressure_stats_collector_unittest.cc
+++ b/chromium/components/memory_pressure/memory_pressure_stats_collector_unittest.cc
@@ -14,7 +14,6 @@ namespace {
// Histogram names.
const char kPressureLevel[] = "Memory.PressureLevel";
-const char kPressureLevelChange[] = "Memory.PressureLevelChange";
} // namespace
@@ -81,7 +80,6 @@ TEST_F(MemoryPressureStatsCollectorTest, EndToEnd) {
// Upon construction no statistics should yet have been reported.
ExpectAccumulated(0, 0, 0);
ExpectReported(0, 0, 0);
- histograms_.ExpectTotalCount(kPressureLevelChange, 0);
// A first call should not invoke any reporting functions, but it should
// modify member variables.
@@ -93,7 +91,6 @@ TEST_F(MemoryPressureStatsCollectorTest, EndToEnd) {
EXPECT_EQ(tick_clock_.NowTicks(), collector_.last_update_time());
ExpectAccumulated(0, 0, 0);
ExpectReported(0, 0, 0);
- histograms_.ExpectTotalCount(kPressureLevelChange, 0);
// A subsequent call with the same pressure level should increment the
// cumulative time but not make a report, as less than one second of time
@@ -106,7 +103,6 @@ TEST_F(MemoryPressureStatsCollectorTest, EndToEnd) {
EXPECT_EQ(tick_clock_.NowTicks(), collector_.last_update_time());
ExpectAccumulated(500, 0, 0);
ExpectReported(0, 0, 0);
- histograms_.ExpectTotalCount(kPressureLevelChange, 0);
// Yet another call and this time a report should be made, as one second
// of time has been accumulated. 500ms should remain unreported.
@@ -118,7 +114,6 @@ TEST_F(MemoryPressureStatsCollectorTest, EndToEnd) {
EXPECT_EQ(tick_clock_.NowTicks(), collector_.last_update_time());
ExpectAccumulated(500, 0, 0);
ExpectReported(1, 0, 0);
- histograms_.ExpectTotalCount(kPressureLevelChange, 0);
// A subsequent call with a different pressure level should increment the
// cumulative time and make several reports.
@@ -130,10 +125,6 @@ TEST_F(MemoryPressureStatsCollectorTest, EndToEnd) {
EXPECT_EQ(tick_clock_.NowTicks(), collector_.last_update_time());
ExpectAccumulated(500, 250, 0);
ExpectReported(1, 2, 0);
- histograms_.ExpectBucketCount(
- kPressureLevelChange, UMA_MEMORY_PRESSURE_LEVEL_CHANGE_NONE_TO_MODERATE,
- 1);
- histograms_.ExpectTotalCount(kPressureLevelChange, 1);
}
} // namespace memory_pressure
diff --git a/chromium/components/metrics.gypi b/chromium/components/metrics.gypi
deleted file mode 100644
index 248795ab284..00000000000
--- a/chromium/components/metrics.gypi
+++ /dev/null
@@ -1,347 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/metrics
- 'target_name': 'metrics',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../third_party/zlib/google/zip.gyp:compression_utils',
- 'component_metrics_proto',
- 'prefs/prefs.gyp:prefs',
- 'variations',
- ],
- 'export_dependent_settings': [
- 'component_metrics_proto',
- ],
- 'sources': [
- 'metrics/call_stack_profile_metrics_provider.cc',
- 'metrics/call_stack_profile_metrics_provider.h',
- 'metrics/clean_exit_beacon.cc',
- 'metrics/clean_exit_beacon.h',
- 'metrics/client_info.cc',
- 'metrics/client_info.h',
- 'metrics/cloned_install_detector.cc',
- 'metrics/cloned_install_detector.h',
- 'metrics/daily_event.cc',
- 'metrics/daily_event.h',
- 'metrics/drive_metrics_provider.cc',
- 'metrics/drive_metrics_provider.h',
- 'metrics/drive_metrics_provider_android.cc',
- 'metrics/drive_metrics_provider_ios.mm',
- 'metrics/drive_metrics_provider_linux.cc',
- 'metrics/drive_metrics_provider_mac.mm',
- 'metrics/drive_metrics_provider_win.cc',
- 'metrics/enabled_state_provider.cc',
- 'metrics/enabled_state_provider.h',
- 'metrics/file_metrics_provider.cc',
- 'metrics/file_metrics_provider.h',
- 'metrics/histogram_encoder.cc',
- 'metrics/histogram_encoder.h',
- 'metrics/machine_id_provider.h',
- 'metrics/machine_id_provider_stub.cc',
- 'metrics/machine_id_provider_win.cc',
- 'metrics/data_use_tracker.cc',
- 'metrics/data_use_tracker.h',
- 'metrics/metrics_log.cc',
- 'metrics/metrics_log.h',
- 'metrics/metrics_log_manager.cc',
- 'metrics/metrics_log_manager.h',
- 'metrics/metrics_log_uploader.cc',
- 'metrics/metrics_log_uploader.h',
- 'metrics/metrics_pref_names.cc',
- 'metrics/metrics_pref_names.h',
- 'metrics/metrics_provider.cc',
- 'metrics/metrics_provider.h',
- 'metrics/metrics_reporting_default_state.cc',
- 'metrics/metrics_reporting_default_state.h',
- 'metrics/metrics_reporting_scheduler.cc',
- 'metrics/metrics_reporting_scheduler.h',
- 'metrics/metrics_service.cc',
- 'metrics/metrics_service.h',
- 'metrics/metrics_service_accessor.cc',
- 'metrics/metrics_service_accessor.h',
- 'metrics/metrics_service_client.cc',
- 'metrics/metrics_service_client.h',
- 'metrics/metrics_state_manager.cc',
- 'metrics/metrics_state_manager.h',
- 'metrics/metrics_switches.cc',
- 'metrics/metrics_switches.h',
- 'metrics/persisted_logs.cc',
- 'metrics/persisted_logs.h',
- 'metrics/stability_metrics_helper.cc',
- 'metrics/stability_metrics_helper.h',
- 'metrics/system_memory_stats_recorder.h',
- 'metrics/system_memory_stats_recorder_linux.cc',
- 'metrics/system_memory_stats_recorder_win.cc',
- 'metrics/url_constants.cc',
- 'metrics/url_constants.h',
- ],
- 'conditions': [
- ['chromeos==1', {
- 'dependencies': [
- 'metrics_serialization',
- ],
- }],
- ['OS == "mac"', {
- 'link_settings': {
- 'libraries': [
- # The below are all needed for drive_metrics_provider_mac.mm.
- '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
- '$(SDKROOT)/System/Library/Frameworks/DiskArbitration.framework',
- '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
- '$(SDKROOT)/System/Library/Frameworks/IOKit.framework',
- ],
- },
- }],
- ['OS=="win"', {
- 'sources!': [
- 'metrics/machine_id_provider_stub.cc',
- ],
- }],
- ],
- },
- {
- # GN version: //components/metrics:net
- 'target_name': 'metrics_net',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- 'component_metrics_proto',
- 'data_use_measurement_core',
- 'metrics',
- 'version_info',
- ],
- 'sources': [
- 'metrics/net/cellular_logic_helper.cc',
- 'metrics/net/cellular_logic_helper.h',
- 'metrics/net/net_metrics_log_uploader.cc',
- 'metrics/net/net_metrics_log_uploader.h',
- 'metrics/net/network_metrics_provider.cc',
- 'metrics/net/network_metrics_provider.h',
- 'metrics/net/version_utils.cc',
- 'metrics/net/version_utils.h',
- 'metrics/net/wifi_access_point_info_provider.cc',
- 'metrics/net/wifi_access_point_info_provider.h',
- 'metrics/net/wifi_access_point_info_provider_chromeos.cc',
- 'metrics/net/wifi_access_point_info_provider_chromeos.h',
- ],
- },
- {
- # GN version: //components/metrics:ui
- 'target_name': 'metrics_ui',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../ui/display/display.gyp:display',
- '../ui/gfx/gfx.gyp:gfx',
- 'metrics',
- ],
- 'sources': [
- 'metrics/ui/screen_info_metrics_provider.cc',
- 'metrics/ui/screen_info_metrics_provider.h',
- ],
- },
- {
- # Protobuf compiler / generator for UMA (User Metrics Analysis).
- #
- # GN version: //components/metrics/proto:proto
- 'target_name': 'component_metrics_proto',
- 'type': 'static_library',
- 'sources': [
- 'metrics/proto/call_stack_profile.proto',
- 'metrics/proto/cast_logs.proto',
- 'metrics/proto/chrome_user_metrics_extension.proto',
- 'metrics/proto/histogram_event.proto',
- 'metrics/proto/memory_leak_report.proto',
- 'metrics/proto/omnibox_event.proto',
- 'metrics/proto/omnibox_input_type.proto',
- 'metrics/proto/perf_data.proto',
- 'metrics/proto/perf_stat.proto',
- 'metrics/proto/profiler_event.proto',
- 'metrics/proto/sampled_profile.proto',
- 'metrics/proto/system_profile.proto',
- 'metrics/proto/user_action_event.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'metrics/proto',
- 'proto_out_dir': 'components/metrics/proto',
- },
- 'includes': [ '../build/protoc.gypi' ],
- },
- {
- # TODO(isherman): Remove all //chrome dependencies on this target, and
- # merge the files in this target with components_unittests.
- # GN version: //components/metrics:test_support
- 'target_name': 'metrics_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'component_metrics_proto',
- 'metrics',
- ],
- 'export_dependent_settings': [
- 'component_metrics_proto',
- ],
- 'sources': [
- 'metrics/test_enabled_state_provider.cc',
- 'metrics/test_enabled_state_provider.h',
- 'metrics/test_metrics_provider.cc',
- 'metrics/test_metrics_provider.h',
- 'metrics/test_metrics_service_client.cc',
- 'metrics/test_metrics_service_client.h',
- ],
- },
- {
- # GN version: //components/metrics:profiler
- 'target_name': 'metrics_profiler',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'component_metrics_proto',
- 'metrics',
- 'variations',
- ],
- 'export_dependent_settings': [
- 'component_metrics_proto',
- ],
- 'sources': [
- 'metrics/profiler/profiler_metrics_provider.cc',
- 'metrics/profiler/profiler_metrics_provider.h',
- 'metrics/profiler/tracking_synchronizer.cc',
- 'metrics/profiler/tracking_synchronizer.h',
- 'metrics/profiler/tracking_synchronizer_delegate.h',
- 'metrics/profiler/tracking_synchronizer_observer.cc',
- 'metrics/profiler/tracking_synchronizer_observer.h',
- ],
- },
- ],
- 'conditions': [
- ['OS=="linux"', {
- 'targets': [
- {
- 'target_name': 'metrics_serialization',
- 'type': 'static_library',
- 'sources': [
- 'metrics/serialization/metric_sample.cc',
- 'metrics/serialization/metric_sample.h',
- 'metrics/serialization/serialization_utils.cc',
- 'metrics/serialization/serialization_utils.h',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- },
- ],
- }],
- ['chromeos==1', {
- 'targets': [
- {
- # GN version: //components/metrics:leak_detector
- 'target_name': 'metrics_leak_detector',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- 'component_metrics_proto',
- ],
- 'sources': [
- 'metrics/leak_detector/call_stack_manager.cc',
- 'metrics/leak_detector/call_stack_manager.h',
- 'metrics/leak_detector/call_stack_table.cc',
- 'metrics/leak_detector/call_stack_table.h',
- 'metrics/leak_detector/custom_allocator.cc',
- 'metrics/leak_detector/custom_allocator.h',
- 'metrics/leak_detector/leak_analyzer.cc',
- 'metrics/leak_detector/leak_analyzer.h',
- 'metrics/leak_detector/leak_detector.cc',
- 'metrics/leak_detector/leak_detector.h',
- 'metrics/leak_detector/leak_detector_impl.cc',
- 'metrics/leak_detector/leak_detector_impl.h',
- 'metrics/leak_detector/leak_detector_value_type.cc',
- 'metrics/leak_detector/leak_detector_value_type.h',
- 'metrics/leak_detector/ranked_set.cc',
- 'metrics/leak_detector/ranked_set.h',
- ],
- },
- ],
- }],
- ['OS!="ios"', {
- 'targets': [
- {
- # GN version: //components/metrics:gpu
- 'target_name': 'metrics_gpu',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- 'component_metrics_proto',
- 'metrics',
- ],
- 'sources': [
- 'metrics/gpu/gpu_metrics_provider.cc',
- 'metrics/gpu/gpu_metrics_provider.h',
- ],
- },
- {
- # GN version: //components/metrics:profiler_content
- 'target_name': 'metrics_profiler_content',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- 'metrics_profiler',
- ],
- 'sources': [
- 'metrics/profiler/content/content_tracking_synchronizer_delegate.cc',
- 'metrics/profiler/content/content_tracking_synchronizer_delegate.h',
- ],
- },
- ],
- }, { # OS==ios
- 'targets': [
- {
- # GN version: //components/metrics:profiler_ios
- 'target_name': 'metrics_profiler_ios',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'metrics_profiler',
- ],
- 'sources': [
- 'metrics/profiler/ios/ios_tracking_synchronizer_delegate.cc',
- 'metrics/profiler/ios/ios_tracking_synchronizer_delegate.h',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/metrics/BUILD.gn b/chromium/components/metrics/BUILD.gn
index 7fc0934af87..5c10219cdec 100644
--- a/chromium/components/metrics/BUILD.gn
+++ b/chromium/components/metrics/BUILD.gn
@@ -13,8 +13,7 @@ if (metrics_use_blimp) {
defines = [ "OVERRIDE_OS_NAME_TO_BLIMP" ]
}
-# GYP version: components/metrics.gypi:metrics
-source_set("metrics") {
+static_library("metrics") {
sources = [
"call_stack_profile_metrics_provider.cc",
"call_stack_profile_metrics_provider.h",
@@ -83,6 +82,7 @@ source_set("metrics") {
"//components/metrics/proto",
]
deps = [
+ ":call_stack_profile_params",
"//base",
"//base:base_static",
"//components/prefs",
@@ -110,8 +110,7 @@ source_set("metrics") {
}
if (!is_ios) {
- # GYP version: components/metrics.gypi:metrics_gpu
- source_set("gpu") {
+ static_library("gpu") {
sources = [
"gpu/gpu_metrics_provider.cc",
"gpu/gpu_metrics_provider.h",
@@ -128,36 +127,6 @@ if (!is_ios) {
}
}
-if (is_chromeos) {
- # GYP version: components/metrics.gypi:metrics_leak_detector
- source_set("leak_detector") {
- sources = [
- "leak_detector/call_stack_manager.cc",
- "leak_detector/call_stack_manager.h",
- "leak_detector/call_stack_table.cc",
- "leak_detector/call_stack_table.h",
- "leak_detector/custom_allocator.cc",
- "leak_detector/custom_allocator.h",
- "leak_detector/leak_analyzer.cc",
- "leak_detector/leak_analyzer.h",
- "leak_detector/leak_detector.cc",
- "leak_detector/leak_detector.h",
- "leak_detector/leak_detector_impl.cc",
- "leak_detector/leak_detector_impl.h",
- "leak_detector/leak_detector_value_type.cc",
- "leak_detector/leak_detector_value_type.h",
- "leak_detector/ranked_set.cc",
- "leak_detector/ranked_set.h",
- ]
-
- deps = [
- "//base",
- "//components/metrics/proto:proto",
- ]
- }
-}
-
-# GYP version: components/metrics.gypi:metrics_net
static_library("net") {
sources = [
"net/cellular_logic_helper.cc",
@@ -195,8 +164,7 @@ static_library("net") {
}
}
-# GYP version: components/metrics.gypi:metrics_profiler
-source_set("profiler") {
+static_library("profiler") {
sources = [
"profiler/profiler_metrics_provider.cc",
"profiler/profiler_metrics_provider.h",
@@ -216,8 +184,7 @@ source_set("profiler") {
]
}
-# GYP version: components/metrics.gypi:metrics_ui
-source_set("ui") {
+static_library("ui") {
sources = [
"ui/screen_info_metrics_provider.cc",
"ui/screen_info_metrics_provider.h",
@@ -235,8 +202,7 @@ source_set("ui") {
}
if (!is_ios) {
- # GYP version: components/metrics.gypi:metrics_profiler_content
- source_set("profiler_content") {
+ static_library("profiler_content") {
sources = [
"profiler/content/content_tracking_synchronizer_delegate.cc",
"profiler/content/content_tracking_synchronizer_delegate.h",
@@ -253,8 +219,7 @@ if (!is_ios) {
]
}
} else {
- # GYP version: components/metrics.gypi:metrics_profiler_ios
- source_set("profiler_ios") {
+ static_library("profiler_ios") {
sources = [
"profiler/ios/ios_tracking_synchronizer_delegate.cc",
"profiler/ios/ios_tracking_synchronizer_delegate.h",
@@ -269,8 +234,36 @@ if (!is_ios) {
}
}
-# GYP version: components/metrics.gypi:metrics_test_support
-source_set("test_support") {
+source_set("call_stack_profile_params") {
+ sources = [
+ "call_stack_profile_params.cc",
+ "call_stack_profile_params.h",
+ ]
+}
+
+source_set("call_stacks") {
+ sources = [
+ "call_stack_profile_collector.cc",
+ "call_stack_profile_collector.h",
+ ]
+ deps = [
+ ":metrics",
+ "//components/metrics/public/interfaces:call_stack_mojo_bindings",
+ ]
+}
+
+source_set("child_call_stacks") {
+ sources = [
+ "child_call_stack_profile_collector.cc",
+ "child_call_stack_profile_collector.h",
+ ]
+ deps = [
+ "//components/metrics/public/interfaces:call_stack_mojo_bindings",
+ "//services/shell/public/cpp",
+ ]
+}
+
+static_library("test_support") {
testonly = true
sources = [
"test_enabled_state_provider.cc",
@@ -290,8 +283,7 @@ source_set("test_support") {
}
if (is_linux) {
- # GYP version: components/metrics.gypi:metrics_serialization
- source_set("serialization") {
+ static_library("serialization") {
sources = [
"serialization/metric_sample.cc",
"serialization/metric_sample.h",
@@ -304,32 +296,11 @@ if (is_linux) {
}
}
-if (is_chromeos) {
- source_set("leak_detector_unit_tests") {
- testonly = true
- sources = [
- "leak_detector/call_stack_manager_unittest.cc",
- "leak_detector/call_stack_table_unittest.cc",
- "leak_detector/leak_analyzer_unittest.cc",
- "leak_detector/leak_detector_impl_unittest.cc",
- "leak_detector/leak_detector_unittest.cc",
- "leak_detector/ranked_set_unittest.cc",
- ]
-
- deps = [
- ":leak_detector",
- "//base",
- "//components/metrics/proto:proto",
- "//content/test:test_support",
- "//testing/gtest",
- ]
- }
-}
-
source_set("unit_tests") {
testonly = true
sources = [
"call_stack_profile_metrics_provider_unittest.cc",
+ "child_call_stack_profile_collector_unittest.cc",
"cloned_install_detector_unittest.cc",
"daily_event_unittest.cc",
"data_use_tracker_unittest.cc",
@@ -351,15 +322,20 @@ source_set("unit_tests") {
]
deps = [
+ ":call_stack_profile_params",
+ ":child_call_stacks",
":metrics",
":net",
":profiler",
":test_support",
":ui",
"//base/test:test_support",
+ "//components/metrics/public/cpp:call_stack_unit_tests",
"//components/prefs:test_support",
"//components/variations",
+ "//mojo/public/cpp/bindings",
"//net:test_support",
+ "//services/shell/public/cpp:sources",
"//testing/gtest",
"//third_party/zlib:compression_utils",
"//ui/gfx/geometry",
@@ -371,6 +347,13 @@ source_set("unit_tests") {
}
if (is_chromeos) {
- deps += [ ":leak_detector_unit_tests" ]
+ deps += [ "leak_detector:unit_tests" ]
+ }
+
+ # iOS is not supported by the profiler and the ios-simulator bot chokes on
+ # these tests.
+ if (is_ios) {
+ sources -= [ "child_call_stack_profile_collector_unittest.cc" ]
+ deps -= [ "//components/metrics/public/cpp:call_stack_unit_tests" ]
}
}
diff --git a/chromium/components/metrics/DEPS b/chromium/components/metrics/DEPS
index 030dd191a6a..a7bf8dc8799 100644
--- a/chromium/components/metrics/DEPS
+++ b/chromium/components/metrics/DEPS
@@ -8,6 +8,8 @@ include_rules = [
"+components/variations",
"+components/version_info",
"+content/public/test",
+ "+mojo/public/cpp",
+ "+services/shell/public/cpp",
"+third_party/zlib/google",
"-net",
]
diff --git a/chromium/components/metrics/call_stack_profile_collector.cc b/chromium/components/metrics/call_stack_profile_collector.cc
new file mode 100644
index 00000000000..cbf466f859a
--- /dev/null
+++ b/chromium/components/metrics/call_stack_profile_collector.cc
@@ -0,0 +1,41 @@
+// 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 "components/metrics/call_stack_profile_collector.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/metrics/call_stack_profile_metrics_provider.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace metrics {
+
+CallStackProfileCollector::CallStackProfileCollector(
+ CallStackProfileParams::Process expected_process)
+ : expected_process_(expected_process) {}
+
+CallStackProfileCollector::~CallStackProfileCollector() {}
+
+// static
+void CallStackProfileCollector::Create(
+ CallStackProfileParams::Process expected_process,
+ mojom::CallStackProfileCollectorRequest request) {
+ mojo::MakeStrongBinding(
+ base::MakeUnique<CallStackProfileCollector>(expected_process),
+ std::move(request));
+}
+
+void CallStackProfileCollector::Collect(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const std::vector<CallStackProfile>& profiles) {
+ if (params.process != expected_process_)
+ return;
+
+ CallStackProfileMetricsProvider::ReceiveCompletedProfiles(params,
+ start_timestamp,
+ profiles);
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/call_stack_profile_collector.h b/chromium/components/metrics/call_stack_profile_collector.h
new file mode 100644
index 00000000000..f6a2ca1ce53
--- /dev/null
+++ b/chromium/components/metrics/call_stack_profile_collector.h
@@ -0,0 +1,41 @@
+// 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 COMPONENTS_METRICS_CALL_STACK_PROFILE_COLLECTOR_H_
+#define COMPONENTS_METRICS_CALL_STACK_PROFILE_COLLECTOR_H_
+
+#include "base/macros.h"
+#include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h"
+
+namespace metrics {
+
+class CallStackProfileCollector : public mojom::CallStackProfileCollector {
+ public:
+ using CallStackProfile = base::StackSamplingProfiler::CallStackProfile;
+
+ explicit CallStackProfileCollector(
+ CallStackProfileParams::Process expected_process);
+ ~CallStackProfileCollector() override;
+
+ // Create a collector to receive profiles from |expected_process|.
+ static void Create(CallStackProfileParams::Process expected_process,
+ mojom::CallStackProfileCollectorRequest request);
+
+ // mojom::CallStackProfileCollector:
+ void Collect(const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const std::vector<CallStackProfile>& profiles) override;
+
+ private:
+ // Profile params are validated to come from this process. Profiles with a
+ // different process declared in the params are considered untrustworthy and
+ // ignored.
+ const CallStackProfileParams::Process expected_process_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallStackProfileCollector);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_CALL_STACK_PROFILE_COLLECTOR_H_
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider.cc b/chromium/components/metrics/call_stack_profile_metrics_provider.cc
index 3b0b3279411..3dc55b9ea6d 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider.cc
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider.cc
@@ -38,13 +38,13 @@ namespace {
// A set of profiles and the CallStackProfileMetricsProvider state associated
// with them.
struct ProfilesState {
- ProfilesState(const CallStackProfileMetricsProvider::Params& params,
+ ProfilesState(const CallStackProfileParams& params,
const base::StackSamplingProfiler::CallStackProfiles& profiles,
base::TimeTicks start_timestamp);
// The metrics-related parameters provided to
// CallStackProfileMetricsProvider::GetProfilerCallback().
- CallStackProfileMetricsProvider::Params params;
+ CallStackProfileParams params;
// The call stack profiles collected by the profiler.
base::StackSamplingProfiler::CallStackProfiles profiles;
@@ -57,7 +57,7 @@ struct ProfilesState {
};
ProfilesState::ProfilesState(
- const CallStackProfileMetricsProvider::Params& params,
+ const CallStackProfileParams& params,
const base::StackSamplingProfiler::CallStackProfiles& profiles,
base::TimeTicks start_timestamp)
: params(params),
@@ -186,10 +186,10 @@ PendingProfiles::~PendingProfiles() {}
// Functions to process completed profiles ------------------------------------
-// Invoked on the profiler's thread. Provides the profiles to PendingProfiles to
-// append, if the collecting state allows.
-void ReceiveCompletedProfiles(
- const CallStackProfileMetricsProvider::Params& params,
+// Will be invoked on either the main thread or the profiler's thread. Provides
+// the profiles to PendingProfiles to append, if the collecting state allows.
+void ReceiveCompletedProfilesImpl(
+ const CallStackProfileParams& params,
base::TimeTicks start_timestamp,
const StackSamplingProfiler::CallStackProfiles& profiles) {
PendingProfiles::GetInstance()->CollectProfilesIfCollectionEnabled(
@@ -239,12 +239,12 @@ void CopySampleToProto(
// Transcode |profile| into |proto_profile|.
void CopyProfileToProto(
const StackSamplingProfiler::CallStackProfile& profile,
- bool preserve_sample_ordering,
+ CallStackProfileParams::SampleOrderingSpec ordering_spec,
CallStackProfile* proto_profile) {
if (profile.samples.empty())
return;
- if (preserve_sample_ordering) {
+ if (ordering_spec == CallStackProfileParams::PRESERVE_ORDER) {
// Collapse only consecutive repeated samples together.
CallStackProfile::Sample* current_sample_proto = nullptr;
for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
@@ -289,23 +289,77 @@ void CopyProfileToProto(
profile.sampling_period.InMilliseconds());
}
-// Translates CallStackProfileMetricsProvider's trigger to the corresponding
+// Translates CallStackProfileParams's process to the corresponding
+// execution context Process.
+Process ToExecutionContextProcess(CallStackProfileParams::Process process) {
+ switch (process) {
+ case CallStackProfileParams::UNKNOWN_PROCESS:
+ return UNKNOWN_PROCESS;
+ case CallStackProfileParams::BROWSER_PROCESS:
+ return BROWSER_PROCESS;
+ case CallStackProfileParams::RENDERER_PROCESS:
+ return RENDERER_PROCESS;
+ case CallStackProfileParams::GPU_PROCESS:
+ return GPU_PROCESS;
+ case CallStackProfileParams::UTILITY_PROCESS:
+ return UTILITY_PROCESS;
+ case CallStackProfileParams::ZYGOTE_PROCESS:
+ return ZYGOTE_PROCESS;
+ case CallStackProfileParams::SANDBOX_HELPER_PROCESS:
+ return SANDBOX_HELPER_PROCESS;
+ case CallStackProfileParams::PPAPI_PLUGIN_PROCESS:
+ return PPAPI_PLUGIN_PROCESS;
+ case CallStackProfileParams::PPAPI_BROKER_PROCESS:
+ return PPAPI_BROKER_PROCESS;
+ }
+ NOTREACHED();
+ return UNKNOWN_PROCESS;
+}
+
+// Translates CallStackProfileParams's thread to the corresponding
+// SampledProfile TriggerEvent.
+Thread ToExecutionContextThread(CallStackProfileParams::Thread thread) {
+ switch (thread) {
+ case CallStackProfileParams::UNKNOWN_THREAD:
+ return UNKNOWN_THREAD;
+ case CallStackProfileParams::UI_THREAD:
+ return UI_THREAD;
+ case CallStackProfileParams::FILE_THREAD:
+ return FILE_THREAD;
+ case CallStackProfileParams::FILE_USER_BLOCKING_THREAD:
+ return FILE_USER_BLOCKING_THREAD;
+ case CallStackProfileParams::PROCESS_LAUNCHER_THREAD:
+ return PROCESS_LAUNCHER_THREAD;
+ case CallStackProfileParams::CACHE_THREAD:
+ return CACHE_THREAD;
+ case CallStackProfileParams::IO_THREAD:
+ return IO_THREAD;
+ case CallStackProfileParams::DB_THREAD:
+ return DB_THREAD;
+ case CallStackProfileParams::GPU_MAIN_THREAD:
+ return GPU_MAIN_THREAD;
+ case CallStackProfileParams::RENDER_THREAD:
+ return RENDER_THREAD;
+ case CallStackProfileParams::UTILITY_THREAD:
+ return UTILITY_THREAD;
+ }
+ NOTREACHED();
+ return UNKNOWN_THREAD;
+}
+
+// Translates CallStackProfileParams's trigger to the corresponding
// SampledProfile TriggerEvent.
SampledProfile::TriggerEvent ToSampledProfileTriggerEvent(
- CallStackProfileMetricsProvider::Trigger trigger) {
+ CallStackProfileParams::Trigger trigger) {
switch (trigger) {
- case CallStackProfileMetricsProvider::UNKNOWN:
+ case CallStackProfileParams::UNKNOWN:
return SampledProfile::UNKNOWN_TRIGGER_EVENT;
- break;
- case CallStackProfileMetricsProvider::PROCESS_STARTUP:
+ case CallStackProfileParams::PROCESS_STARTUP:
return SampledProfile::PROCESS_STARTUP;
- break;
- case CallStackProfileMetricsProvider::JANKY_TASK:
+ case CallStackProfileParams::JANKY_TASK:
return SampledProfile::JANKY_TASK;
- break;
- case CallStackProfileMetricsProvider::THREAD_HUNG:
+ case CallStackProfileParams::THREAD_HUNG:
return SampledProfile::THREAD_HUNG;
- break;
}
NOTREACHED();
return SampledProfile::UNKNOWN_TRIGGER_EVENT;
@@ -313,20 +367,6 @@ SampledProfile::TriggerEvent ToSampledProfileTriggerEvent(
} // namespace
-// CallStackProfileMetricsProvider::Params ------------------------------------
-
-CallStackProfileMetricsProvider::Params::Params(
- CallStackProfileMetricsProvider::Trigger trigger)
- : Params(trigger, false) {
-}
-
-CallStackProfileMetricsProvider::Params::Params(
- CallStackProfileMetricsProvider::Trigger trigger,
- bool preserve_sample_ordering)
- : trigger(trigger),
- preserve_sample_ordering(preserve_sample_ordering) {
-}
-
// CallStackProfileMetricsProvider --------------------------------------------
const char CallStackProfileMetricsProvider::kFieldTrialName[] =
@@ -342,14 +382,24 @@ CallStackProfileMetricsProvider::~CallStackProfileMetricsProvider() {
// This function can be invoked on an abitrary thread.
base::StackSamplingProfiler::CompletedCallback
-CallStackProfileMetricsProvider::GetProfilerCallback(const Params& params) {
+CallStackProfileMetricsProvider::GetProfilerCallback(
+ const CallStackProfileParams& params) {
// Ignore the profiles if the collection is disabled. If the collection state
// changes while collecting, this will be detected by the callback and
// profiles will be ignored at that point.
if (!PendingProfiles::GetInstance()->IsCollectionEnabled())
return base::Bind(&IgnoreCompletedProfiles);
- return base::Bind(&ReceiveCompletedProfiles, params, base::TimeTicks::Now());
+ return base::Bind(&ReceiveCompletedProfilesImpl, params,
+ base::TimeTicks::Now());
+}
+
+// static
+void CallStackProfileMetricsProvider::ReceiveCompletedProfiles(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const base::StackSamplingProfiler::CallStackProfiles& profiles) {
+ ReceiveCompletedProfilesImpl(params, start_timestamp, profiles);
}
void CallStackProfileMetricsProvider::OnRecordingEnabled() {
@@ -371,10 +421,13 @@ void CallStackProfileMetricsProvider::ProvideGeneralMetrics(
for (const StackSamplingProfiler::CallStackProfile& profile :
profiles_state.profiles) {
SampledProfile* sampled_profile = uma_proto->add_sampled_profile();
+ sampled_profile->set_process(ToExecutionContextProcess(
+ profiles_state.params.process));
+ sampled_profile->set_thread(ToExecutionContextThread(
+ profiles_state.params.thread));
sampled_profile->set_trigger_event(ToSampledProfileTriggerEvent(
profiles_state.params.trigger));
- CopyProfileToProto(profile,
- profiles_state.params.preserve_sample_ordering,
+ CopyProfileToProto(profile, profiles_state.params.ordering_spec,
sampled_profile->mutable_call_stack_profile());
}
}
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider.h b/chromium/components/metrics/call_stack_profile_metrics_provider.h
index 746b82928ed..d26000be087 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider.h
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/profiler/stack_sampling_profiler.h"
+#include "components/metrics/call_stack_profile_params.h"
#include "components/metrics/metrics_provider.h"
namespace metrics {
@@ -18,34 +19,6 @@ class ChromeUserMetricsExtension;
// Performs metrics logging for the stack sampling profiler.
class CallStackProfileMetricsProvider : public MetricsProvider {
public:
- // The event that triggered the profile collection.
- // This enum should be kept in sync with content/common/profiled_stack_state.h
- enum Trigger {
- UNKNOWN,
- PROCESS_STARTUP,
- JANKY_TASK,
- THREAD_HUNG,
- TRIGGER_LAST = THREAD_HUNG
- };
-
- // Parameters to pass back to the metrics provider.
- struct Params {
- explicit Params(Trigger trigger);
- Params(Trigger trigger, bool preserve_sample_ordering);
-
- // The triggering event.
- Trigger trigger;
-
- // True if sample ordering is important and should be preserved when the
- // associated profiles are compressed. This should only be set to true if
- // the intended use of the requires that the sequence of call stacks within
- // a particular profile be preserved. The default value of false provides
- // better compression of the encoded profile and is sufficient for the
- // typical use case of recording profiles for stack frequency analysis in
- // aggregate.
- bool preserve_sample_ordering;
- };
-
CallStackProfileMetricsProvider();
~CallStackProfileMetricsProvider() override;
@@ -54,7 +27,15 @@ class CallStackProfileMetricsProvider : public MetricsProvider {
// StackSamplingProfiler, and should not be reused between
// StackSamplingProfilers. This function may be called on any thread.
static base::StackSamplingProfiler::CompletedCallback GetProfilerCallback(
- const Params& params);
+ const CallStackProfileParams& params);
+
+ // Provides completed stack profiles to the metrics provider. Intended for use
+ // when receiving profiles over IPC. In-process StackSamplingProfiler users
+ // should use GetProfilerCallback() instead.
+ static void ReceiveCompletedProfiles(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const base::StackSamplingProfiler::CallStackProfiles& profiles);
// MetricsProvider:
void OnRecordingEnabled() override;
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc b/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
index e361137e168..e5dfb9ad9f6 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
@@ -13,6 +13,7 @@
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
+#include "components/metrics/call_stack_profile_params.h"
#include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
#include "components/variations/entropy_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -26,8 +27,6 @@ using Sample = StackSamplingProfiler::Sample;
namespace metrics {
-using Params = CallStackProfileMetricsProvider::Params;
-
// This test fixture enables the field trial that
// CallStackProfileMetricsProvider depends on to report profiles.
class CallStackProfileMetricsProviderTest : public testing::Test {
@@ -43,7 +42,8 @@ class CallStackProfileMetricsProviderTest : public testing::Test {
~CallStackProfileMetricsProviderTest() override {}
// Utility function to append profiles to the metrics provider.
- void AppendProfiles(const Params& params, const Profiles& profiles) {
+ void AppendProfiles(const CallStackProfileParams& params,
+ const Profiles& profiles) {
CallStackProfileMetricsProvider::GetProfilerCallback(params).Run(profiles);
}
@@ -205,7 +205,10 @@ TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
profiles);
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -266,6 +269,10 @@ TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
ASSERT_TRUE(call_stack_profile.has_sampling_period_ms());
EXPECT_EQ(profile_sampling_periods[i].InMilliseconds(),
call_stack_profile.sampling_period_ms());
+ ASSERT_TRUE(sampled_profile.has_process());
+ EXPECT_EQ(BROWSER_PROCESS, sampled_profile.process());
+ ASSERT_TRUE(sampled_profile.has_thread());
+ EXPECT_EQ(UI_THREAD, sampled_profile.thread());
ASSERT_TRUE(sampled_profile.has_trigger_event());
EXPECT_EQ(SampledProfile::PROCESS_STARTUP, sampled_profile.trigger_event());
}
@@ -313,7 +320,10 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
std::vector<Profile>(1, profile));
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -392,7 +402,10 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
- AppendProfiles(Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, true),
+ AppendProfiles(CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::PRESERVE_ORDER),
std::vector<Profile>(1, profile));
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -444,7 +457,10 @@ TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) {
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
std::vector<Profile>(1, profile));
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -481,7 +497,10 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
provider.OnRecordingEnabled();
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
std::vector<Profile>(1, profile));
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -508,7 +527,10 @@ TEST_F(CallStackProfileMetricsProviderTest,
profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
std::vector<Profile>(1, profile));
CallStackProfileMetricsProvider provider;
@@ -532,7 +554,10 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) {
CallStackProfileMetricsProvider provider;
provider.OnRecordingDisabled();
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
std::vector<Profile>(1, profile));
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -555,7 +580,10 @@ TEST_F(CallStackProfileMetricsProviderTest,
provider.OnRecordingEnabled();
base::StackSamplingProfiler::CompletedCallback callback =
CallStackProfileMetricsProvider::GetProfilerCallback(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false));
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE));
provider.OnRecordingDisabled();
callback.Run(std::vector<Profile>(1, profile));
@@ -580,7 +608,10 @@ TEST_F(CallStackProfileMetricsProviderTest,
provider.OnRecordingEnabled();
base::StackSamplingProfiler::CompletedCallback callback =
CallStackProfileMetricsProvider::GetProfilerCallback(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false));
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE));
provider.OnRecordingDisabled();
provider.OnRecordingEnabled();
@@ -606,7 +637,10 @@ TEST_F(CallStackProfileMetricsProviderTest,
provider.OnRecordingDisabled();
base::StackSamplingProfiler::CompletedCallback callback =
CallStackProfileMetricsProvider::GetProfilerCallback(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false));
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE));
provider.OnRecordingEnabled();
callback.Run(std::vector<Profile>(1, profile));
diff --git a/chromium/components/metrics/call_stack_profile_params.cc b/chromium/components/metrics/call_stack_profile_params.cc
new file mode 100644
index 00000000000..e937283616c
--- /dev/null
+++ b/chromium/components/metrics/call_stack_profile_params.cc
@@ -0,0 +1,22 @@
+// 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 "components/metrics/call_stack_profile_params.h"
+
+namespace metrics {
+
+CallStackProfileParams::CallStackProfileParams()
+ : CallStackProfileParams(UNKNOWN_PROCESS, UNKNOWN_THREAD, UNKNOWN) {}
+
+CallStackProfileParams::CallStackProfileParams(Process process, Thread thread,
+ Trigger trigger)
+ : CallStackProfileParams(process, thread, trigger, MAY_SHUFFLE) {}
+
+CallStackProfileParams::CallStackProfileParams(Process process, Thread thread,
+ Trigger trigger,
+ SampleOrderingSpec ordering_spec)
+ : process(process), thread(thread), trigger(trigger),
+ ordering_spec(ordering_spec) {}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/call_stack_profile_params.h b/chromium/components/metrics/call_stack_profile_params.h
new file mode 100644
index 00000000000..4dd7cd4fef2
--- /dev/null
+++ b/chromium/components/metrics/call_stack_profile_params.h
@@ -0,0 +1,87 @@
+// 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 COMPONENTS_METRICS_CALL_STACK_PROFILE_PARAMS_H_
+#define COMPONENTS_METRICS_CALL_STACK_PROFILE_PARAMS_H_
+
+namespace metrics {
+
+// Parameters to pass back to the metrics provider.
+struct CallStackProfileParams {
+ // The process in which the collection occurred.
+ enum Process {
+ UNKNOWN_PROCESS,
+ BROWSER_PROCESS,
+ RENDERER_PROCESS,
+ GPU_PROCESS,
+ UTILITY_PROCESS,
+ ZYGOTE_PROCESS,
+ SANDBOX_HELPER_PROCESS,
+ PPAPI_PLUGIN_PROCESS,
+ PPAPI_BROKER_PROCESS
+ };
+
+ // The thread from which the collection occurred.
+ enum Thread {
+ UNKNOWN_THREAD,
+
+ // Browser process threads, some of which occur in other processes as well.
+ UI_THREAD,
+ FILE_THREAD,
+ FILE_USER_BLOCKING_THREAD,
+ PROCESS_LAUNCHER_THREAD,
+ CACHE_THREAD,
+ IO_THREAD,
+ DB_THREAD,
+
+ // GPU process thread.
+ GPU_MAIN_THREAD,
+
+ // Renderer process threads.
+ RENDER_THREAD,
+ UTILITY_THREAD
+ };
+
+ // The event that triggered the profile collection.
+ enum Trigger {
+ UNKNOWN,
+ PROCESS_STARTUP,
+ JANKY_TASK,
+ THREAD_HUNG,
+ TRIGGER_LAST = THREAD_HUNG
+ };
+
+ // Allows the caller to specify whether sample ordering is
+ // important. MAY_SHUFFLE should always be used to enable better compression,
+ // unless the use case needs order to be preserved for a specific reason.
+ enum SampleOrderingSpec {
+ // The provider may shuffle the sample order to improve compression.
+ MAY_SHUFFLE,
+ // The provider will not change the sample order.
+ PRESERVE_ORDER
+ };
+
+ // The default constructor is required for mojo and should not be used
+ // otherwise. A valid trigger should always be specified.
+ CallStackProfileParams();
+ CallStackProfileParams(Process process, Thread thread, Trigger trigger);
+ CallStackProfileParams(Process process, Thread thread, Trigger trigger,
+ SampleOrderingSpec ordering_spec);
+
+ // The collection process.
+ Process process;
+
+ // The collection thread.
+ Thread thread;
+
+ // The triggering event.
+ Trigger trigger;
+
+ // Whether to preserve sample ordering.
+ SampleOrderingSpec ordering_spec;
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_CALL_STACK_PROFILE_PARAMS_H_
diff --git a/chromium/components/metrics/child_call_stack_profile_collector.cc b/chromium/components/metrics/child_call_stack_profile_collector.cc
new file mode 100644
index 00000000000..9c62af85568
--- /dev/null
+++ b/chromium/components/metrics/child_call_stack_profile_collector.cc
@@ -0,0 +1,86 @@
+// 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 "components/metrics/child_call_stack_profile_collector.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "services/shell/public/cpp/interface_provider.h"
+
+namespace metrics {
+
+ChildCallStackProfileCollector::ProfilesState::ProfilesState() = default;
+ChildCallStackProfileCollector::ProfilesState::ProfilesState(
+ const ProfilesState&) = default;
+
+ChildCallStackProfileCollector::ProfilesState::ProfilesState(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const base::StackSamplingProfiler::CallStackProfiles& profiles)
+ : params(params), start_timestamp(start_timestamp), profiles(profiles) {}
+
+ChildCallStackProfileCollector::ProfilesState::~ProfilesState() = default;
+
+ChildCallStackProfileCollector::ChildCallStackProfileCollector() {}
+
+ChildCallStackProfileCollector::~ChildCallStackProfileCollector() {}
+
+base::StackSamplingProfiler::CompletedCallback
+ChildCallStackProfileCollector::GetProfilerCallback(
+ const CallStackProfileParams& params) {
+ return base::Bind(&ChildCallStackProfileCollector::Collect,
+ // This class has lazy instance lifetime.
+ base::Unretained(this), params,
+ base::TimeTicks::Now());
+}
+
+void ChildCallStackProfileCollector::SetParentProfileCollector(
+ metrics::mojom::CallStackProfileCollectorPtr parent_collector) {
+ base::AutoLock alock(lock_);
+ // This function should only invoked once, during the mode of operation when
+ // retaining profiles after construction.
+ DCHECK(retain_profiles_);
+ retain_profiles_ = false;
+ task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ parent_collector_ = std::move(parent_collector);
+ if (parent_collector_) {
+ for (const ProfilesState& state : profiles_) {
+ parent_collector_->Collect(state.params, state.start_timestamp,
+ state.profiles);
+ }
+ }
+ profiles_.clear();
+}
+
+void ChildCallStackProfileCollector::Collect(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const std::vector<CallStackProfile>& profiles) {
+ base::AutoLock alock(lock_);
+ if (task_runner_ &&
+ // The profiler thread does not have a task runner. Attempting to
+ // invoke Get() on it results in a DCHECK.
+ (!base::ThreadTaskRunnerHandle::IsSet() ||
+ base::ThreadTaskRunnerHandle::Get() != task_runner_)) {
+ // Post back to the thread that owns the the parent interface.
+ task_runner_->PostTask(FROM_HERE, base::Bind(
+ &ChildCallStackProfileCollector::Collect,
+ // This class has lazy instance lifetime.
+ base::Unretained(this),
+ params,
+ start_timestamp,
+ profiles));
+ return;
+ }
+
+ if (parent_collector_) {
+ parent_collector_->Collect(params, start_timestamp, profiles);
+ } else if (retain_profiles_) {
+ profiles_.push_back(ProfilesState(params, start_timestamp, profiles));
+ }
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/child_call_stack_profile_collector.h b/chromium/components/metrics/child_call_stack_profile_collector.h
new file mode 100644
index 00000000000..adc356d110f
--- /dev/null
+++ b/chromium/components/metrics/child_call_stack_profile_collector.h
@@ -0,0 +1,120 @@
+// 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 COMPONENTS_METRICS_CHILD_CALL_STACK_PROFILE_COLLECTOR_H_
+#define COMPONENTS_METRICS_CHILD_CALL_STACK_PROFILE_COLLECTOR_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h"
+
+namespace shell {
+class InterfaceProvider;
+}
+
+namespace metrics {
+
+// ChildCallStackProfileCollector collects stacks at startup, caching them
+// internally until a CallStackProfileCollector interface is available. If a
+// CallStackProfileCollector is provided via the InterfaceProvider supplied to
+// SetParentProfileCollector, the cached stacks are sent via that interface. All
+// future stacks received via callbacks supplied by GetProfilerCallback are sent
+// via that interface as well.
+//
+// If no CallStackProfileCollector is provided via InterfaceProvider, any cached
+// stacks and all future stacks received via callbacks supplied by
+// GetProfilerCallback are flushed. In typical usage this should not happen
+// because the browser is expected to always supply a CallStackProfileCollector.
+//
+// This class is only necessary if a CallStackProfileCollector is not available
+// at the time the profiler is created. Otherwise the CallStackProfileCollector
+// can be used directly.
+//
+// To use, create as a leaky lazy instance:
+//
+// base::LazyInstance<metrics::ChildCallStackProfileCollector>::Leaky
+// g_call_stack_profile_collector = LAZY_INSTANCE_INITIALIZER;
+//
+// Then, invoke CreateCompletedCallback() to generate the CompletedCallback to
+// pass when creating the StackSamplingProfiler.
+//
+// When the mojo InterfaceProvider becomes available, provide it via
+// SetParentProfileCollector().
+class ChildCallStackProfileCollector {
+ public:
+ ChildCallStackProfileCollector();
+ ~ChildCallStackProfileCollector();
+
+ // Get a callback for use with StackSamplingProfiler that provides completed
+ // profiles to this object. The callback should be immediately passed to the
+ // StackSamplingProfiler, and should not be reused between
+ // StackSamplingProfilers. This function may be called on any thread.
+ base::StackSamplingProfiler::CompletedCallback GetProfilerCallback(
+ const CallStackProfileParams& params);
+
+ // Sets the CallStackProfileCollector interface from |parent_collector|. This
+ // function MUST be invoked exactly once, regardless of whether
+ // |parent_collector| is null, as it flushes pending data in either case.
+ void SetParentProfileCollector(
+ metrics::mojom::CallStackProfileCollectorPtr parent_collector);
+
+ private:
+ friend class ChildCallStackProfileCollectorTest;
+
+ // Bundles together a set of collected profiles and the collection state for
+ // storage, pending availability of the parent mojo interface.
+ struct ProfilesState {
+ ProfilesState();
+ ProfilesState(const ProfilesState&);
+ ProfilesState(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const base::StackSamplingProfiler::CallStackProfiles& profiles);
+ ~ProfilesState();
+
+ CallStackProfileParams params;
+ base::TimeTicks start_timestamp;
+
+ // The sampled profiles.
+ base::StackSamplingProfiler::CallStackProfiles profiles;
+ };
+
+ using CallStackProfile = base::StackSamplingProfiler::CallStackProfile;
+
+ void Collect(const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const std::vector<CallStackProfile>& profiles);
+
+ // This object may be accessed on any thread, including the profiler
+ // thread. The expected use case for the object is to be created and have
+ // GetProfilerCallback before the message loop starts, which prevents the use
+ // of PostTask and the like for inter-thread communication.
+ base::Lock lock_;
+
+ // Whether to retain profiles when the interface is not set. Remains true
+ // until the invocation of SetParentProfileCollector(), at which point it is
+ // false for the rest of the object lifetime.
+ bool retain_profiles_ = true;
+
+ // The task runner associated with the parent interface.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ // The interface to use to collect the stack profiles provided to this
+ // object. Initially null until SetParentProfileCollector() is invoked, at
+ // which point it may either become set or remain null. If set, stacks are
+ // collected via the interface, otherwise they are ignored.
+ mojom::CallStackProfileCollectorPtr parent_collector_;
+
+ // Profiles being cached by this object, pending a parent interface to be
+ // supplied.
+ std::vector<ProfilesState> profiles_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildCallStackProfileCollector);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_CHILD_CALL_STACK_PROFILE_COLLECTOR_H_
diff --git a/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc b/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc
new file mode 100644
index 00000000000..556124feed9
--- /dev/null
+++ b/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc
@@ -0,0 +1,175 @@
+// 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 "components/metrics/child_call_stack_profile_collector.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "components/metrics/call_stack_profile_params.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/shell/public/cpp/interface_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+
+namespace {
+
+
+} // namespace
+
+class ChildCallStackProfileCollectorTest : public testing::Test {
+ protected:
+ class Receiver : public mojom::CallStackProfileCollector {
+ public:
+ using CallStackProfile = base::StackSamplingProfiler::CallStackProfile;
+
+ Receiver(mojom::CallStackProfileCollectorRequest request)
+ : binding_(this, std::move(request)) {}
+ ~Receiver() override {}
+
+ void Collect(const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const std::vector<CallStackProfile>& profiles) override {
+ this->profiles.push_back(ChildCallStackProfileCollector::ProfilesState(
+ params,
+ start_timestamp,
+ profiles));
+ }
+
+ std::vector<ChildCallStackProfileCollector::ProfilesState> profiles;
+
+ private:
+ mojo::Binding<mojom::CallStackProfileCollector> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(Receiver);
+ };
+
+ ChildCallStackProfileCollectorTest()
+ : receiver_impl_(new Receiver(GetProxy(&receiver_))) {}
+
+ void CollectProfiles(
+ const CallStackProfileParams& params,
+ const base::StackSamplingProfiler::CallStackProfiles& profiles) {
+ child_collector_.GetProfilerCallback(params).Run(profiles);
+ }
+
+ const std::vector<ChildCallStackProfileCollector::ProfilesState>&
+ profiles() const {
+ return child_collector_.profiles_;
+ }
+
+ base::MessageLoop loop_;
+ mojom::CallStackProfileCollectorPtr receiver_;
+ std::unique_ptr<Receiver> receiver_impl_;
+ ChildCallStackProfileCollector child_collector_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildCallStackProfileCollectorTest);
+};
+
+// Test the behavior when an interface is provided.
+TEST_F(ChildCallStackProfileCollectorTest, InterfaceProvided) {
+ EXPECT_EQ(0u, profiles().size());
+
+ // Add profiles before providing the interface.
+ CollectProfiles(
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::JANKY_TASK,
+ CallStackProfileParams::PRESERVE_ORDER),
+ { base::StackSamplingProfiler::CallStackProfile(),
+ base::StackSamplingProfiler::CallStackProfile() });
+ ASSERT_EQ(1u, profiles().size());
+ EXPECT_EQ(CallStackProfileParams::BROWSER_PROCESS,
+ profiles()[0].params.process);
+ EXPECT_EQ(CallStackProfileParams::UI_THREAD, profiles()[0].params.thread);
+ EXPECT_EQ(CallStackProfileParams::JANKY_TASK, profiles()[0].params.trigger);
+ EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
+ profiles()[0].params.ordering_spec);
+ base::TimeTicks start_timestamp = profiles()[0].start_timestamp;
+ EXPECT_GE(base::TimeDelta::FromMilliseconds(10),
+ base::TimeTicks::Now() - start_timestamp);
+ EXPECT_EQ(2u, profiles()[0].profiles.size());
+
+ // Set the interface. The profiles should be passed to it.
+ child_collector_.SetParentProfileCollector(std::move(receiver_));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, profiles().size());
+ ASSERT_EQ(1u, receiver_impl_->profiles.size());
+ EXPECT_EQ(CallStackProfileParams::JANKY_TASK,
+ receiver_impl_->profiles[0].params.trigger);
+ EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
+ receiver_impl_->profiles[0].params.ordering_spec);
+ EXPECT_EQ(start_timestamp, receiver_impl_->profiles[0].start_timestamp);
+ EXPECT_EQ(2u, receiver_impl_->profiles[0].profiles.size());
+
+ // Add profiles after providing the interface. They should also be passed to
+ // it.
+ receiver_impl_->profiles.clear();
+ CollectProfiles(
+ CallStackProfileParams(CallStackProfileParams::GPU_PROCESS,
+ CallStackProfileParams::GPU_MAIN_THREAD,
+ CallStackProfileParams::THREAD_HUNG,
+ CallStackProfileParams::PRESERVE_ORDER),
+ { base::StackSamplingProfiler::CallStackProfile() });
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, profiles().size());
+ ASSERT_EQ(1u, receiver_impl_->profiles.size());
+ EXPECT_EQ(CallStackProfileParams::GPU_PROCESS,
+ receiver_impl_->profiles[0].params.process);
+ EXPECT_EQ(CallStackProfileParams::GPU_MAIN_THREAD,
+ receiver_impl_->profiles[0].params.thread);
+ EXPECT_EQ(CallStackProfileParams::THREAD_HUNG,
+ receiver_impl_->profiles[0].params.trigger);
+ EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
+ receiver_impl_->profiles[0].params.ordering_spec);
+ EXPECT_GE(base::TimeDelta::FromMilliseconds(10),
+ (base::TimeTicks::Now() -
+ receiver_impl_->profiles[0].start_timestamp));
+ EXPECT_EQ(1u, receiver_impl_->profiles[0].profiles.size());
+}
+
+TEST_F(ChildCallStackProfileCollectorTest, InterfaceNotProvided) {
+ EXPECT_EQ(0u, profiles().size());
+
+ // Add profiles before providing a null interface.
+ CollectProfiles(
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::JANKY_TASK,
+ CallStackProfileParams::PRESERVE_ORDER),
+ { base::StackSamplingProfiler::CallStackProfile(),
+ base::StackSamplingProfiler::CallStackProfile() });
+ ASSERT_EQ(1u, profiles().size());
+ EXPECT_EQ(CallStackProfileParams::BROWSER_PROCESS,
+ profiles()[0].params.process);
+ EXPECT_EQ(CallStackProfileParams::UI_THREAD, profiles()[0].params.thread);
+ EXPECT_EQ(CallStackProfileParams::JANKY_TASK, profiles()[0].params.trigger);
+ EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
+ profiles()[0].params.ordering_spec);
+ EXPECT_GE(base::TimeDelta::FromMilliseconds(10),
+ base::TimeTicks::Now() - profiles()[0].start_timestamp);
+ EXPECT_EQ(2u, profiles()[0].profiles.size());
+
+ // Set the null interface. The profiles should be flushed.
+ child_collector_.SetParentProfileCollector(
+ mojom::CallStackProfileCollectorPtr());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, profiles().size());
+
+ // Add profiles after providing a null interface. They should also be flushed.
+ CollectProfiles(
+ CallStackProfileParams(CallStackProfileParams::GPU_PROCESS,
+ CallStackProfileParams::GPU_MAIN_THREAD,
+ CallStackProfileParams::THREAD_HUNG,
+ CallStackProfileParams::PRESERVE_ORDER),
+ { base::StackSamplingProfiler::CallStackProfile() });
+ EXPECT_EQ(0u, profiles().size());
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/file_metrics_provider.cc b/chromium/components/metrics/file_metrics_provider.cc
index 2d331d63bfa..aa81a0cd1f0 100644
--- a/chromium/components/metrics/file_metrics_provider.cc
+++ b/chromium/components/metrics/file_metrics_provider.cc
@@ -325,8 +325,8 @@ FileMetricsProvider::AccessResult FileMetricsProvider::CheckAndMapMetricSource(
// Create an allocator for the mapped file. Ownership passes to the allocator.
source->allocator.reset(new base::PersistentHistogramAllocator(
- base::WrapUnique(new base::FilePersistentMemoryAllocator(
- std::move(mapped), 0, 0, base::StringPiece(), read_only))));
+ base::MakeUnique<base::FilePersistentMemoryAllocator>(
+ std::move(mapped), 0, 0, base::StringPiece(), read_only)));
return ACCESS_RESULT_SUCCESS;
}
@@ -372,7 +372,7 @@ void FileMetricsProvider::RecordHistogramSnapshotsFromSource(
std::unique_ptr<base::HistogramBase> histogram = histogram_iter.GetNext();
if (!histogram)
break;
- snapshot_manager->PrepareFinalDeltaTakingOwnership(std::move(histogram));
+ snapshot_manager->PrepareFinalDelta(histogram.get());
++histogram_count;
}
diff --git a/chromium/components/metrics/file_metrics_provider_unittest.cc b/chromium/components/metrics/file_metrics_provider_unittest.cc
index d1d340b9f95..11977099c3e 100644
--- a/chromium/components/metrics/file_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/file_metrics_provider_unittest.cc
@@ -95,9 +95,9 @@ class FileMetricsProviderTest : public testing::TestWithParam<bool> {
}
TestingPrefServiceSimple* prefs() { return prefs_.get(); }
- base::FilePath temp_dir() { return temp_dir_.path(); }
+ base::FilePath temp_dir() { return temp_dir_.GetPath(); }
base::FilePath metrics_file() {
- return temp_dir_.path().AppendASCII(kMetricsFilename);
+ return temp_dir_.GetPath().AppendASCII(kMetricsFilename);
}
FileMetricsProvider* provider() {
@@ -286,36 +286,40 @@ TEST_P(FileMetricsProviderTest, AccessDirectory) {
// ensure that each file has a later timestamp on disk than the previous one.
base::ScopedTempDir metrics_files;
EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII(".foo.pma"),
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII(".foo.pma"),
allocator, base_time);
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("_bar.pma"),
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("_bar.pma"),
allocator, base_time);
histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
histogram->Add(1);
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("a1.pma"), allocator,
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
+ allocator,
base_time + base::TimeDelta::FromMinutes(1));
histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
histogram->Add(2);
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("c2.pma"), allocator,
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("c2.pma"),
+ allocator,
base_time + base::TimeDelta::FromMinutes(2));
histogram = base::Histogram::FactoryGet("h3", 1, 100, 10, 0);
histogram->Add(3);
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("b3.pma"), allocator,
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b3.pma"),
+ allocator,
base_time + base::TimeDelta::FromMinutes(3));
histogram = base::Histogram::FactoryGet("h4", 1, 100, 10, 0);
histogram->Add(3);
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("d4.pma"), allocator,
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("d4.pma"),
+ allocator,
base_time + base::TimeDelta::FromMinutes(4));
- base::TouchFile(metrics_files.path().AppendASCII("b3.pma"),
+ base::TouchFile(metrics_files.GetPath().AppendASCII("b3.pma"),
base_time + base::TimeDelta::FromMinutes(5),
base_time + base::TimeDelta::FromMinutes(5));
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("baz"), allocator,
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("baz"), allocator,
base_time + base::TimeDelta::FromMinutes(6));
// The global allocator has to be detached here so that no metrics created
@@ -324,7 +328,7 @@ TEST_P(FileMetricsProviderTest, AccessDirectory) {
base::GlobalHistogramAllocator::ReleaseForTesting();
// Register the file and allow the "checker" task to run.
- provider()->RegisterSource(metrics_files.path(),
+ provider()->RegisterSource(metrics_files.GetPath(),
FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
FileMetricsProvider::ASSOCIATE_CURRENT_RUN,
kMetricsName);
@@ -339,13 +343,15 @@ TEST_P(FileMetricsProviderTest, AccessDirectory) {
EXPECT_EQ(expect_order[i], GetSnapshotHistogramCount()) << i;
}
- EXPECT_FALSE(base::PathExists(metrics_files.path().AppendASCII("a1.pma")));
- EXPECT_FALSE(base::PathExists(metrics_files.path().AppendASCII("c2.pma")));
- EXPECT_FALSE(base::PathExists(metrics_files.path().AppendASCII("b3.pma")));
- EXPECT_FALSE(base::PathExists(metrics_files.path().AppendASCII("d4.pma")));
- EXPECT_TRUE(base::PathExists(metrics_files.path().AppendASCII(".foo.pma")));
- EXPECT_TRUE(base::PathExists(metrics_files.path().AppendASCII("_bar.pma")));
- EXPECT_TRUE(base::PathExists(metrics_files.path().AppendASCII("baz")));
+ EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
+ EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("c2.pma")));
+ EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b3.pma")));
+ EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("d4.pma")));
+ EXPECT_TRUE(
+ base::PathExists(metrics_files.GetPath().AppendASCII(".foo.pma")));
+ EXPECT_TRUE(
+ base::PathExists(metrics_files.GetPath().AppendASCII("_bar.pma")));
+ EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("baz")));
}
TEST_P(FileMetricsProviderTest, AccessReadWriteMetrics) {
@@ -411,9 +417,7 @@ TEST_P(FileMetricsProviderTest, AccessInitialMetrics) {
{
HistogramFlattenerDeltaRecorder flattener;
base::HistogramSnapshotManager snapshot_manager(&flattener);
- snapshot_manager.StartDeltas();
RecordInitialHistogramSnapshots(&snapshot_manager);
- snapshot_manager.FinishDeltas();
EXPECT_EQ(2U, flattener.GetRecordedDeltaHistogramNames().size());
}
EXPECT_TRUE(base::PathExists(metrics_file()));
diff --git a/chromium/components/metrics/leak_detector/BUILD.gn b/chromium/components/metrics/leak_detector/BUILD.gn
new file mode 100644
index 00000000000..0e13520174f
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/BUILD.gn
@@ -0,0 +1,66 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+if (is_chromeos) {
+ source_set("leak_detector") {
+ sources = [
+ "call_stack_manager.cc",
+ "call_stack_manager.h",
+ "call_stack_table.cc",
+ "call_stack_table.h",
+ "custom_allocator.cc",
+ "custom_allocator.h",
+ "gnu_build_id_reader.cc",
+ "gnu_build_id_reader.h",
+ "leak_analyzer.cc",
+ "leak_analyzer.h",
+ "leak_detector.cc",
+ "leak_detector.h",
+ "leak_detector_impl.cc",
+ "leak_detector_impl.h",
+ "leak_detector_value_type.cc",
+ "leak_detector_value_type.h",
+ "protobuf_to_mojo_converter.cc",
+ "protobuf_to_mojo_converter.h",
+ "ranked_set.cc",
+ "ranked_set.h",
+ ]
+
+ deps = [
+ ":interfaces",
+ "//base",
+ "//components/metrics/proto:proto",
+ ]
+ }
+
+ mojom("interfaces") {
+ sources = [
+ "leak_detector.mojom",
+ ]
+ }
+
+ source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "call_stack_manager_unittest.cc",
+ "call_stack_table_unittest.cc",
+ "leak_analyzer_unittest.cc",
+ "leak_detector_impl_unittest.cc",
+ "leak_detector_unittest.cc",
+ "protobuf_to_mojo_converter_unittest.cc",
+ "ranked_set_unittest.cc",
+ ]
+
+ deps = [
+ ":interfaces",
+ ":leak_detector",
+ "//base",
+ "//components/metrics/proto:proto",
+ "//content/test:test_support",
+ "//testing/gtest",
+ ]
+ }
+}
diff --git a/chromium/components/metrics/leak_detector/OWNERS b/chromium/components/metrics/leak_detector/OWNERS
index d8bfc45aa54..cde5a71325c 100644
--- a/chromium/components/metrics/leak_detector/OWNERS
+++ b/chromium/components/metrics/leak_detector/OWNERS
@@ -1,2 +1,7 @@
sque@chromium.org
wfh@chromium.org
+
+# Changes to Mojo interfaces require a security review to avoid
+# introducing new sandbox escapes.
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/metrics/leak_detector/gnu_build_id_reader.cc b/chromium/components/metrics/leak_detector/gnu_build_id_reader.cc
new file mode 100644
index 00000000000..ac0f07daecc
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/gnu_build_id_reader.cc
@@ -0,0 +1,124 @@
+// 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 "components/metrics/leak_detector/gnu_build_id_reader.h"
+
+#include <elf.h>
+
+#include <algorithm>
+
+#if defined(OS_CHROMEOS)
+#include <link.h> // for dl_iterate_phdr
+#else
+#error "Getting binary mapping info is not supported on this platform."
+#endif // defined(OS_CHROMEOS)
+
+namespace metrics {
+namespace leak_detector {
+namespace gnu_build_id_reader {
+
+namespace {
+
+// Contains data passed to dl_iterate_phdr() for reading build ID.
+struct ReadBuildIDData {
+ // Points to a vector for storing the build ID.
+ std::vector<uint8_t>* build_id;
+ // Indicates whether build ID was read successfully.
+ bool success;
+};
+
+// Given a pointer and an offset, add the offset to the pointer and round it up
+// to the next uint32_t.
+const void* AlignPtrAndOffsetToUint32(const void* ptr, intptr_t offset) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(ptr) + offset;
+ uintptr_t aligned_addr =
+ (addr + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1);
+ return reinterpret_cast<const void*>(aligned_addr);
+}
+
+// Searches for the ELF note containing the build ID within the data range
+// specified by [start, end). Returns the build ID in |*result|. If the build ID
+// is not found, |*result| will be unchanged. Returns true if the build ID was
+// successfully read or false otherwise.
+bool GetBuildIdFromNotes(const void* start,
+ const void* end,
+ std::vector<uint8_t>* result) {
+ using NoteHeaderPtr = const ElfW(Nhdr)*;
+ NoteHeaderPtr note = reinterpret_cast<NoteHeaderPtr>(start);
+
+ while (note < end) {
+ const char* name_ptr = reinterpret_cast<const char*>(note + 1);
+ if (name_ptr >= end) {
+ break;
+ }
+ // |desc_ptr| points the to the actual build ID data.
+ const uint8_t* desc_ptr = reinterpret_cast<const uint8_t*>(
+ AlignPtrAndOffsetToUint32(name_ptr, note->n_namesz));
+ if (note->n_type == NT_GNU_BUILD_ID &&
+ note->n_namesz == sizeof(ELF_NOTE_GNU) &&
+ std::equal(name_ptr, name_ptr + sizeof(ELF_NOTE_GNU), ELF_NOTE_GNU)) {
+ result->assign(desc_ptr, desc_ptr + note->n_descsz);
+ return true;
+ }
+ NoteHeaderPtr next_ptr = reinterpret_cast<NoteHeaderPtr>(
+ AlignPtrAndOffsetToUint32(desc_ptr, note->n_descsz));
+ note = next_ptr;
+ }
+ return false;
+}
+
+// Callback for dl_iterate_phdr(). Finds the notes section and looks for the
+// build ID in there. |data| points to a ReadBuildIDData struct whose |build_id|
+// field should point to a valid std::vector<uint8_t>. Returns the build ID in
+// that field, and sets |ReadBuildIDData::success| based on whether the build ID
+// was successfully read.
+//
+// This function always returns 1 to signal the end of dl_iterate_phdr()'s
+// iteration, because it is only interested in the first binary iterated by
+// dl_iterate_phdr(), which is the current binary.
+int FindNotesAndGetBuildID(struct dl_phdr_info* info,
+ size_t /* size */,
+ void* data) {
+ uintptr_t mapping_addr = reinterpret_cast<uintptr_t>(info->dlpi_addr);
+ const ElfW(Ehdr)* file_header =
+ reinterpret_cast<const ElfW(Ehdr)*>(mapping_addr);
+
+ // Make sure that a valid |mapping_addr| was read.
+ if (!file_header || file_header->e_phentsize != sizeof(ElfW(Phdr))) {
+ return 1;
+ }
+
+ // Find the ELF segment header for the NOTES section.
+ for (int i = 0; i < info->dlpi_phnum; ++i) {
+ const ElfW(Phdr)& segment_header = info->dlpi_phdr[i];
+ if (segment_header.p_type == PT_NOTE) {
+ const void* note = reinterpret_cast<const void*>(
+ mapping_addr + segment_header.p_vaddr);
+ const void* note_end = reinterpret_cast<const void*>(
+ mapping_addr + segment_header.p_vaddr + segment_header.p_memsz);
+ ReadBuildIDData* read_data = reinterpret_cast<ReadBuildIDData*>(data);
+ read_data->success =
+ GetBuildIdFromNotes(note, note_end, read_data->build_id);
+ }
+ }
+ return 1;
+}
+
+} // namespace
+
+bool ReadBuildID(std::vector<uint8_t>* build_id) {
+ ReadBuildIDData data;
+ data.build_id = build_id;
+ data.success = false;
+
+#if defined(OS_CHROMEOS)
+ dl_iterate_phdr(FindNotesAndGetBuildID, &data);
+#endif // defined(OS_CHROMEOS)
+
+ return data.success;
+}
+
+} // namespace gnu_build_id_reader
+} // namespace leak_detector
+} // namespace metrics
diff --git a/chromium/components/metrics/leak_detector/gnu_build_id_reader.h b/chromium/components/metrics/leak_detector/gnu_build_id_reader.h
new file mode 100644
index 00000000000..5cda9f3869a
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/gnu_build_id_reader.h
@@ -0,0 +1,24 @@
+// 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 COMPONENTS_METRICS_LEAK_DETECTOR_GNU_BUILD_ID_READER_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_GNU_BUILD_ID_READER_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+namespace metrics {
+namespace leak_detector {
+namespace gnu_build_id_reader {
+
+// Reads the build ID from the GNU build notes and stores it in |*build_id|.
+// Returns true if it was successfully read, or false otherwise.
+bool ReadBuildID(std::vector<uint8_t>* build_id);
+
+} // namespace gnu_build_id_reader
+} // namespace leak_detector
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_LEAK_DETECTOR_GNU_BUILD_ID_READER_H_
diff --git a/chromium/components/metrics/leak_detector/leak_detector.mojom b/chromium/components/metrics/leak_detector/leak_detector.mojom
new file mode 100644
index 00000000000..d985b79024c
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/leak_detector.mojom
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module metrics.mojom;
+
+struct LeakDetectorParams {
+ float sampling_rate;
+ uint32 max_stack_depth;
+ uint64 analysis_interval_bytes;
+ uint32 size_suspicion_threshold;
+ uint32 call_stack_suspicion_threshold;
+};
+
+struct AllocationBreakdown {
+ array<uint32> counts_by_size;
+ uint32 count_for_call_stack;
+};
+
+struct MemoryLeakReport {
+ uint32 size_bytes;
+ array<uint64> call_stack;
+
+ array<AllocationBreakdown> alloc_breakdown_history;
+};
+
+// Provides a remote interface for enabling LeakDetector on remote processes.
+interface LeakDetector {
+ // Returns a LeakDetectorParams struct. Used to indicate to the remote process
+ // what parameters to use when initializing LeakDetector. Can also return
+ // |params.sampling_rate| == 0 to indicate that LeakDetector should not be
+ // initialized on a particular process.
+ GetParams() => (LeakDetectorParams params);
+
+ // When a remote process running LeakDetector gets some leak reports, it
+ // should call this function to return the leak reports back to the main
+ // process that implements this function. The reports should be sent back as
+ // an array of serialized MemoryLeakReportProtos.
+ SendLeakReports(array<MemoryLeakReport> reports);
+};
diff --git a/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.cc b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.cc
new file mode 100644
index 00000000000..24202dbcb8c
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.cc
@@ -0,0 +1,67 @@
+// 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 "components/metrics/leak_detector/protobuf_to_mojo_converter.h"
+
+namespace metrics {
+namespace leak_detector {
+namespace protobuf_to_mojo_converter {
+
+void ParamsToMojo(const MemoryLeakReportProto::Params& params,
+ mojom::LeakDetectorParams* mojo_params) {
+ mojo_params->sampling_rate = params.sampling_rate();
+ mojo_params->max_stack_depth = params.max_stack_depth();
+ mojo_params->analysis_interval_bytes = params.analysis_interval_bytes();
+ mojo_params->size_suspicion_threshold = params.size_suspicion_threshold();
+ mojo_params->call_stack_suspicion_threshold =
+ params.call_stack_suspicion_threshold();
+}
+
+void MojoToParams(const mojom::LeakDetectorParams& mojo_params,
+ MemoryLeakReportProto::Params* params) {
+ params->set_sampling_rate(mojo_params.sampling_rate);
+ params->set_max_stack_depth(mojo_params.max_stack_depth);
+ params->set_analysis_interval_bytes(mojo_params.analysis_interval_bytes);
+ params->set_size_suspicion_threshold(mojo_params.size_suspicion_threshold);
+ params->set_call_stack_suspicion_threshold(
+ mojo_params.call_stack_suspicion_threshold);
+}
+
+void ReportToMojo(const MemoryLeakReportProto& report,
+ mojom::MemoryLeakReport* mojo_report) {
+ mojo_report->size_bytes = report.size_bytes();
+ for (auto call_stack_value : report.call_stack()) {
+ mojo_report->call_stack.push_back(call_stack_value);
+ }
+
+ for (const auto& history_entry : report.alloc_breakdown_history()) {
+ metrics::mojom::AllocationBreakdownPtr mojo_entry =
+ metrics::mojom::AllocationBreakdown::New();
+ for (auto count : history_entry.counts_by_size()) {
+ mojo_entry->counts_by_size.push_back(count);
+ }
+ mojo_entry->count_for_call_stack = history_entry.count_for_call_stack();
+
+ mojo_report->alloc_breakdown_history.push_back(std::move(mojo_entry));
+ }
+}
+
+void MojoToReport(const mojom::MemoryLeakReport& mojo_report,
+ MemoryLeakReportProto* report) {
+ report->set_size_bytes(mojo_report.size_bytes);
+ for (auto call_stack_addr : mojo_report.call_stack)
+ report->add_call_stack(call_stack_addr);
+
+ for (const auto& history_entry : mojo_report.alloc_breakdown_history) {
+ auto proto_entry = report->add_alloc_breakdown_history();
+ for (auto count : history_entry->counts_by_size) {
+ proto_entry->add_counts_by_size(count);
+ }
+ proto_entry->set_count_for_call_stack(history_entry->count_for_call_stack);
+ }
+}
+
+} // namespace protobuf_to_mojo_converter
+} // namespace leak_detector
+} // namespace metrics
diff --git a/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.h b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.h
new file mode 100644
index 00000000000..9447f76ffab
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.h
@@ -0,0 +1,36 @@
+// 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 COMPONENTS_METRICS_LEAK_DETECTOR_PROTOBUF_TO_MOJO_CONVERTER_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_PROTOBUF_TO_MOJO_CONVERTER_H_
+
+#include "components/metrics/leak_detector/leak_detector.mojom.h"
+#include "components/metrics/proto/memory_leak_report.pb.h"
+
+namespace metrics {
+namespace leak_detector {
+namespace protobuf_to_mojo_converter {
+
+// Converts between a MemoryLeakReportProto::Params protobuf and a
+// mojom::LeakDetectorParams Mojo structure. The Mojo structure must already be
+// allocated.
+void ParamsToMojo(const MemoryLeakReportProto::Params& params,
+ mojom::LeakDetectorParams* mojo_params);
+void MojoToParams(const mojom::LeakDetectorParams& mojo_params,
+ MemoryLeakReportProto::Params* params);
+
+// Converts between a MemoryLeakReportProto protobuf and a
+// mojom::MemoryLeakReport Mojo structure. The Mojo structure must already be
+// allocated. The conversion only covers the fields that are filled in by the
+// LeakDetector class.
+void ReportToMojo(const MemoryLeakReportProto& report,
+ mojom::MemoryLeakReport* mojo_report);
+void MojoToReport(const mojom::MemoryLeakReport& mojo_report,
+ MemoryLeakReportProto* report);
+
+} // namespace protobuf_to_mojo_converter
+} // namespace leak_detector
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_LEAK_DETECTOR_PROTOBUF_TO_MOJO_CONVERTER_H_
diff --git a/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter_unittest.cc b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter_unittest.cc
new file mode 100644
index 00000000000..f768c312f05
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter_unittest.cc
@@ -0,0 +1,139 @@
+// 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 "components/metrics/leak_detector/protobuf_to_mojo_converter.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+namespace leak_detector {
+
+TEST(protobuf_to_mojo_converterTest, ConvertParams) {
+ MemoryLeakReportProto::Params params;
+ params.set_sampling_rate(0.75);
+ params.set_max_stack_depth(19);
+ params.set_analysis_interval_bytes(25 * 1024 * 1024);
+ params.set_size_suspicion_threshold(8);
+ params.set_call_stack_suspicion_threshold(11);
+
+ // Convert to equivalent Mojo struct.
+ mojo::StructPtr<mojom::LeakDetectorParams> mojo_params =
+ mojom::LeakDetectorParams::New();
+ protobuf_to_mojo_converter::ParamsToMojo(params, mojo_params.get());
+
+ EXPECT_DOUBLE_EQ(0.75, mojo_params->sampling_rate);
+ EXPECT_EQ(19U, mojo_params->max_stack_depth);
+ EXPECT_EQ(25U * 1024 * 1024, mojo_params->analysis_interval_bytes);
+ EXPECT_EQ(8U, mojo_params->size_suspicion_threshold);
+ EXPECT_EQ(11U, mojo_params->call_stack_suspicion_threshold);
+
+ // Convert Mojo struct back to protobuf.
+ MemoryLeakReportProto::Params new_params;
+ protobuf_to_mojo_converter::MojoToParams(*mojo_params, &new_params);
+
+ EXPECT_DOUBLE_EQ(0.75, new_params.sampling_rate());
+ EXPECT_EQ(19U, new_params.max_stack_depth());
+ EXPECT_EQ(25U * 1024 * 1024, new_params.analysis_interval_bytes());
+ EXPECT_EQ(8U, new_params.size_suspicion_threshold());
+ EXPECT_EQ(11U, new_params.call_stack_suspicion_threshold());
+}
+
+TEST(protobuf_to_mojo_converterTest, ConvertReport) {
+ MemoryLeakReportProto report;
+ report.add_call_stack(0xdeadbeef);
+ report.add_call_stack(0xc001d00d);
+ report.add_call_stack(0x900df00d);
+ report.set_size_bytes(24);
+
+ auto entry1 = report.add_alloc_breakdown_history();
+ entry1->add_counts_by_size(1);
+ entry1->add_counts_by_size(2);
+ entry1->add_counts_by_size(3);
+ entry1->set_count_for_call_stack(4);
+
+ auto entry2 = report.add_alloc_breakdown_history();
+ entry2->add_counts_by_size(11);
+ entry2->add_counts_by_size(12);
+ entry2->add_counts_by_size(13);
+ entry2->add_counts_by_size(14);
+ entry2->set_count_for_call_stack(15);
+
+ auto entry3 = report.add_alloc_breakdown_history();
+ entry3->add_counts_by_size(21);
+ entry3->add_counts_by_size(22);
+ entry3->add_counts_by_size(23);
+ entry3->add_counts_by_size(24);
+ entry3->add_counts_by_size(25);
+ entry3->set_count_for_call_stack(26);
+
+ // Convert to equivalent Mojo struct.
+ mojo::StructPtr<mojom::MemoryLeakReport> mojo_report =
+ mojom::MemoryLeakReport::New();
+ protobuf_to_mojo_converter::ReportToMojo(report, mojo_report.get());
+
+ ASSERT_EQ(3U, mojo_report->call_stack.size());
+ EXPECT_EQ(0xdeadbeef, mojo_report->call_stack[0]);
+ EXPECT_EQ(0xc001d00d, mojo_report->call_stack[1]);
+ EXPECT_EQ(0x900df00d, mojo_report->call_stack[2]);
+ EXPECT_EQ(24U, mojo_report->size_bytes);
+
+ ASSERT_EQ(3U, mojo_report->alloc_breakdown_history.size());
+
+ ASSERT_EQ(3U, mojo_report->alloc_breakdown_history[0]->counts_by_size.size());
+ EXPECT_EQ(1U, mojo_report->alloc_breakdown_history[0]->counts_by_size[0]);
+ EXPECT_EQ(2U, mojo_report->alloc_breakdown_history[0]->counts_by_size[1]);
+ EXPECT_EQ(3U, mojo_report->alloc_breakdown_history[0]->counts_by_size[2]);
+ EXPECT_EQ(4U, mojo_report->alloc_breakdown_history[0]->count_for_call_stack);
+
+ ASSERT_EQ(4U, mojo_report->alloc_breakdown_history[1]->counts_by_size.size());
+ EXPECT_EQ(11U, mojo_report->alloc_breakdown_history[1]->counts_by_size[0]);
+ EXPECT_EQ(12U, mojo_report->alloc_breakdown_history[1]->counts_by_size[1]);
+ EXPECT_EQ(13U, mojo_report->alloc_breakdown_history[1]->counts_by_size[2]);
+ EXPECT_EQ(14U, mojo_report->alloc_breakdown_history[1]->counts_by_size[3]);
+ EXPECT_EQ(15U, mojo_report->alloc_breakdown_history[1]->count_for_call_stack);
+
+ ASSERT_EQ(5U, mojo_report->alloc_breakdown_history[2]->counts_by_size.size());
+ EXPECT_EQ(21U, mojo_report->alloc_breakdown_history[2]->counts_by_size[0]);
+ EXPECT_EQ(22U, mojo_report->alloc_breakdown_history[2]->counts_by_size[1]);
+ EXPECT_EQ(23U, mojo_report->alloc_breakdown_history[2]->counts_by_size[2]);
+ EXPECT_EQ(24U, mojo_report->alloc_breakdown_history[2]->counts_by_size[3]);
+ EXPECT_EQ(25U, mojo_report->alloc_breakdown_history[2]->counts_by_size[4]);
+ EXPECT_EQ(26U, mojo_report->alloc_breakdown_history[2]->count_for_call_stack);
+
+ // Convert Mojo struct back to protobuf.
+ MemoryLeakReportProto new_report;
+ protobuf_to_mojo_converter::MojoToReport(*mojo_report, &new_report);
+
+ ASSERT_EQ(3, new_report.call_stack().size());
+ EXPECT_EQ(0xdeadbeef, new_report.call_stack(0));
+ EXPECT_EQ(0xc001d00d, new_report.call_stack(1));
+ EXPECT_EQ(0x900df00d, new_report.call_stack(2));
+ EXPECT_EQ(24U, new_report.size_bytes());
+
+ ASSERT_EQ(3, new_report.alloc_breakdown_history().size());
+
+ ASSERT_EQ(3, new_report.alloc_breakdown_history(0).counts_by_size().size());
+ EXPECT_EQ(1U, new_report.alloc_breakdown_history(0).counts_by_size(0));
+ EXPECT_EQ(2U, new_report.alloc_breakdown_history(0).counts_by_size(1));
+ EXPECT_EQ(3U, new_report.alloc_breakdown_history(0).counts_by_size(2));
+ EXPECT_EQ(4U, new_report.alloc_breakdown_history(0).count_for_call_stack());
+
+ ASSERT_EQ(4, new_report.alloc_breakdown_history(1).counts_by_size().size());
+ EXPECT_EQ(11U, new_report.alloc_breakdown_history(1).counts_by_size(0));
+ EXPECT_EQ(12U, new_report.alloc_breakdown_history(1).counts_by_size(1));
+ EXPECT_EQ(13U, new_report.alloc_breakdown_history(1).counts_by_size(2));
+ EXPECT_EQ(14U, new_report.alloc_breakdown_history(1).counts_by_size(3));
+ EXPECT_EQ(15U, new_report.alloc_breakdown_history(1).count_for_call_stack());
+
+ ASSERT_EQ(5, new_report.alloc_breakdown_history(2).counts_by_size().size());
+ EXPECT_EQ(21U, new_report.alloc_breakdown_history(2).counts_by_size(0));
+ EXPECT_EQ(22U, new_report.alloc_breakdown_history(2).counts_by_size(1));
+ EXPECT_EQ(23U, new_report.alloc_breakdown_history(2).counts_by_size(2));
+ EXPECT_EQ(24U, new_report.alloc_breakdown_history(2).counts_by_size(3));
+ EXPECT_EQ(25U, new_report.alloc_breakdown_history(2).counts_by_size(4));
+ EXPECT_EQ(26U, new_report.alloc_breakdown_history(2).count_for_call_stack());
+}
+
+} // namespace leak_detector
+} // namespace metrics
diff --git a/chromium/components/metrics/metrics_log.cc b/chromium/components/metrics/metrics_log.cc
index 3d8cc1886a8..3824762e217 100644
--- a/chromium/components/metrics/metrics_log.cc
+++ b/chromium/components/metrics/metrics_log.cc
@@ -117,9 +117,9 @@ MetricsLog::~MetricsLog() {
// static
void MetricsLog::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityCrashCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityIncompleteSessionEndCount, 0);
+ registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationFail, 0);
registry->RegisterIntegerPref(
prefs::kStabilityBreakpadRegistrationSuccess, 0);
@@ -129,6 +129,9 @@ void MetricsLog::RegisterPrefs(PrefRegistrySimple* registry) {
std::string());
registry->RegisterStringPref(prefs::kStabilitySavedSystemProfileHash,
std::string());
+ registry->RegisterIntegerPref(prefs::kStabilityDeferredCount, 0);
+ registry->RegisterIntegerPref(prefs::kStabilityDiscardCount, 0);
+ registry->RegisterIntegerPref(prefs::kStabilityVersionMismatchCount, 0);
}
// static
@@ -203,37 +206,70 @@ void MetricsLog::RecordStabilityMetrics(
metrics_providers[i]->ProvideStabilityMetrics(system_profile);
}
- // Omit some stats unless this is the initial stability log.
- if (log_type() != INITIAL_STABILITY_LOG)
- return;
+ SystemProfileProto::Stability* stability =
+ system_profile->mutable_stability();
int incomplete_shutdown_count =
pref->GetInteger(prefs::kStabilityIncompleteSessionEndCount);
- pref->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
+ if (incomplete_shutdown_count) {
+ pref->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
+ stability->set_incomplete_shutdown_count(incomplete_shutdown_count);
+ }
+
int breakpad_registration_success_count =
pref->GetInteger(prefs::kStabilityBreakpadRegistrationSuccess);
- pref->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
+ if (breakpad_registration_success_count) {
+ pref->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
+ stability->set_breakpad_registration_success_count(
+ breakpad_registration_success_count);
+ }
+
int breakpad_registration_failure_count =
pref->GetInteger(prefs::kStabilityBreakpadRegistrationFail);
- pref->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
+ if (breakpad_registration_failure_count) {
+ pref->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
+ stability->set_breakpad_registration_failure_count(
+ breakpad_registration_failure_count);
+ }
+
int debugger_present_count =
pref->GetInteger(prefs::kStabilityDebuggerPresent);
- pref->SetInteger(prefs::kStabilityDebuggerPresent, 0);
+ if (debugger_present_count) {
+ pref->SetInteger(prefs::kStabilityDebuggerPresent, 0);
+ stability->set_debugger_present_count(debugger_present_count);
+ }
+
int debugger_not_present_count =
pref->GetInteger(prefs::kStabilityDebuggerNotPresent);
- pref->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
+ if (debugger_not_present_count) {
+ pref->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
+ stability->set_debugger_not_present_count(debugger_not_present_count);
+ }
- // TODO(jar): The following are all optional, so we *could* optimize them for
- // values of zero (and not include them).
- SystemProfileProto::Stability* stability =
- system_profile->mutable_stability();
- stability->set_incomplete_shutdown_count(incomplete_shutdown_count);
- stability->set_breakpad_registration_success_count(
- breakpad_registration_success_count);
- stability->set_breakpad_registration_failure_count(
- breakpad_registration_failure_count);
- stability->set_debugger_present_count(debugger_present_count);
- stability->set_debugger_not_present_count(debugger_not_present_count);
+ // Note: only logging the following histograms for non-zero values.
+
+ int deferred_count = pref->GetInteger(prefs::kStabilityDeferredCount);
+ if (deferred_count) {
+ local_state_->SetInteger(prefs::kStabilityDeferredCount, 0);
+ UMA_STABILITY_HISTOGRAM_COUNTS_100(
+ "Stability.Internals.InitialStabilityLogDeferredCount", deferred_count);
+ }
+
+ int discard_count = local_state_->GetInteger(prefs::kStabilityDiscardCount);
+ if (discard_count) {
+ local_state_->SetInteger(prefs::kStabilityDiscardCount, 0);
+ UMA_STABILITY_HISTOGRAM_COUNTS_100("Stability.Internals.DataDiscardCount",
+ discard_count);
+ }
+
+ int version_mismatch_count =
+ local_state_->GetInteger(prefs::kStabilityVersionMismatchCount);
+ if (version_mismatch_count) {
+ local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0);
+ UMA_STABILITY_HISTOGRAM_COUNTS_100(
+ "Stability.Internals.VersionMismatchCount",
+ version_mismatch_count);
+ }
}
void MetricsLog::RecordGeneralMetrics(
@@ -285,9 +321,11 @@ bool MetricsLog::HasStabilityMetrics() const {
// protobufs is complete.
void MetricsLog::WriteRequiredStabilityAttributes(PrefService* pref) {
int launch_count = pref->GetInteger(prefs::kStabilityLaunchCount);
- pref->SetInteger(prefs::kStabilityLaunchCount, 0);
+ if (launch_count)
+ pref->SetInteger(prefs::kStabilityLaunchCount, 0);
int crash_count = pref->GetInteger(prefs::kStabilityCrashCount);
- pref->SetInteger(prefs::kStabilityCrashCount, 0);
+ if (crash_count)
+ pref->SetInteger(prefs::kStabilityCrashCount, 0);
SystemProfileProto::Stability* stability =
uma_proto()->mutable_system_profile()->mutable_stability();
@@ -379,19 +417,22 @@ void MetricsLog::RecordEnvironment(
for (size_t i = 0; i < metrics_providers.size(); ++i)
metrics_providers[i]->ProvideSystemProfileMetrics(system_profile);
- std::string serialied_system_profile;
+ std::string serialized_system_profile;
std::string base64_system_profile;
- if (system_profile->SerializeToString(&serialied_system_profile)) {
- base::Base64Encode(serialied_system_profile, &base64_system_profile);
+ if (system_profile->SerializeToString(&serialized_system_profile)) {
+ base::Base64Encode(serialized_system_profile, &base64_system_profile);
PrefService* local_state = local_state_;
local_state->SetString(prefs::kStabilitySavedSystemProfile,
base64_system_profile);
local_state->SetString(prefs::kStabilitySavedSystemProfileHash,
- ComputeSHA1(serialied_system_profile));
+ ComputeSHA1(serialized_system_profile));
}
}
-bool MetricsLog::LoadSavedEnvironmentFromPrefs() {
+bool MetricsLog::LoadSavedEnvironmentFromPrefs(std::string* app_version) {
+ DCHECK(app_version);
+ app_version->clear();
+
PrefService* local_state = local_state_;
const std::string base64_system_profile =
local_state->GetString(prefs::kStabilitySavedSystemProfile);
@@ -404,10 +445,15 @@ bool MetricsLog::LoadSavedEnvironmentFromPrefs() {
local_state->ClearPref(prefs::kStabilitySavedSystemProfileHash);
SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
- std::string serialied_system_profile;
- return base::Base64Decode(base64_system_profile, &serialied_system_profile) &&
- ComputeSHA1(serialied_system_profile) == system_profile_hash &&
- system_profile->ParseFromString(serialied_system_profile);
+ std::string serialized_system_profile;
+
+ bool success =
+ base::Base64Decode(base64_system_profile, &serialized_system_profile) &&
+ ComputeSHA1(serialized_system_profile) == system_profile_hash &&
+ system_profile->ParseFromString(serialized_system_profile);
+ if (success)
+ *app_version = system_profile->app_version();
+ return success;
}
void MetricsLog::CloseLog() {
diff --git a/chromium/components/metrics/metrics_log.h b/chromium/components/metrics/metrics_log.h
index 0506df28db0..6b37e7b4c98 100644
--- a/chromium/components/metrics/metrics_log.h
+++ b/chromium/components/metrics/metrics_log.h
@@ -100,9 +100,11 @@ class MetricsLog {
int64_t metrics_reporting_enabled_date);
// Loads the environment proto that was saved by the last RecordEnvironment()
- // call from prefs and clears the pref value. Returns true on success or false
- // if there was no saved environment in prefs or it could not be decoded.
- bool LoadSavedEnvironmentFromPrefs();
+ // call from prefs and clears the pref value. On success, returns true and
+ // |app_version| contains the recovered version. Otherwise (if there was no
+ // saved environment in prefs or it could not be decoded), returns false and
+ // |app_version| is empty.
+ bool LoadSavedEnvironmentFromPrefs(std::string* app_version);
// Writes application stability metrics, including stability metrics provided
// by the specified set of |metrics_providers|. The system profile portion of
diff --git a/chromium/components/metrics/metrics_log_manager.cc b/chromium/components/metrics/metrics_log_manager.cc
index 415db785656..d06b5ae0ada 100644
--- a/chromium/components/metrics/metrics_log_manager.cc
+++ b/chromium/components/metrics/metrics_log_manager.cc
@@ -42,11 +42,13 @@ MetricsLogManager::MetricsLogManager(PrefService* local_state,
: unsent_logs_loaded_(false),
initial_log_queue_(local_state,
prefs::kMetricsInitialLogs,
+ prefs::kDeprecatedMetricsInitialLogs,
kInitialLogsPersistLimit,
kStorageByteLimitPerLogType,
0),
ongoing_log_queue_(local_state,
prefs::kMetricsOngoingLogs,
+ prefs::kDeprecatedMetricsOngoingLogs,
kOngoingLogsPersistLimit,
kStorageByteLimitPerLogType,
max_ongoing_log_size) {}
diff --git a/chromium/components/metrics/metrics_log_manager_unittest.cc b/chromium/components/metrics/metrics_log_manager_unittest.cc
index 7a634609a54..fbd1dd5d2b5 100644
--- a/chromium/components/metrics/metrics_log_manager_unittest.cc
+++ b/chromium/components/metrics/metrics_log_manager_unittest.cc
@@ -37,7 +37,7 @@ class TestLogPrefService : public TestingPrefServiceSimple {
list_length = GetList(prefs::kMetricsInitialLogs)->GetSize();
else
list_length = GetList(prefs::kMetricsOngoingLogs)->GetSize();
- return list_length / 2;
+ return list_length;
}
};
@@ -133,11 +133,11 @@ TEST(MetricsLogManagerTest, InterjectedLogPreservesType) {
MetricsLogManager log_manager(&pref_service, 0);
log_manager.LoadPersistedUnsentLogs();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service));
log_manager.PauseCurrentLog();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
log_manager.ResumePausedLog();
log_manager.StageNextLogForUpload();
@@ -163,8 +163,8 @@ TEST(MetricsLogManagerTest, StoreAndLoad) {
// Simulate a log having already been unsent from a previous session.
{
std::string log("proto");
- PersistedLogs ongoing_logs(&pref_service, prefs::kMetricsOngoingLogs, 1,
- 1, 0);
+ PersistedLogs ongoing_logs(&pref_service, prefs::kMetricsOngoingLogs,
+ prefs::kDeprecatedMetricsOngoingLogs, 1, 1, 0);
ongoing_logs.StoreLog(log);
ongoing_logs.SerializeLogs();
}
@@ -173,11 +173,11 @@ TEST(MetricsLogManagerTest, StoreAndLoad) {
log_manager.LoadPersistedUnsentLogs();
EXPECT_TRUE(log_manager.has_unsent_logs());
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service));
log_manager.StageNextLogForUpload();
log_manager.FinishCurrentLog();
@@ -234,8 +234,8 @@ TEST(MetricsLogManagerTest, StoreStagedLogTypes) {
MetricsLogManager log_manager(&pref_service, 0);
log_manager.LoadPersistedUnsentLogs();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
log_manager.StageNextLogForUpload();
log_manager.PersistUnsentLogs();
@@ -249,8 +249,8 @@ TEST(MetricsLogManagerTest, StoreStagedLogTypes) {
MetricsLogManager log_manager(&pref_service, 0);
log_manager.LoadPersistedUnsentLogs();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
log_manager.StageNextLogForUpload();
log_manager.PersistUnsentLogs();
@@ -267,11 +267,11 @@ TEST(MetricsLogManagerTest, LargeLogDiscarding) {
MetricsLogManager log_manager(&pref_service, 1);
log_manager.LoadPersistedUnsentLogs();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
// Only the ongoing log should be written out, due to the threshold.
@@ -289,11 +289,11 @@ TEST(MetricsLogManagerTest, DiscardOrder) {
MetricsLogManager log_manager(&pref_service, 0);
log_manager.LoadPersistedUnsentLogs();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service));
log_manager.StageNextLogForUpload();
log_manager.FinishCurrentLog();
log_manager.DiscardStagedLog();
diff --git a/chromium/components/metrics/metrics_log_unittest.cc b/chromium/components/metrics/metrics_log_unittest.cc
index fe03ff8607c..57a1209f1ad 100644
--- a/chromium/components/metrics/metrics_log_unittest.cc
+++ b/chromium/components/metrics/metrics_log_unittest.cc
@@ -276,12 +276,15 @@ TEST_F(MetricsLogTest, LoadSavedEnvironmentFromPrefs) {
prefs::kStabilitySavedSystemProfileHash;
TestMetricsServiceClient client;
+ client.set_version_string("bogus version");
// The pref value is empty, so loading it from prefs should fail.
{
TestMetricsLog log(
kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
- EXPECT_FALSE(log.LoadSavedEnvironmentFromPrefs());
+ std::string app_version;
+ EXPECT_FALSE(log.LoadSavedEnvironmentFromPrefs(&app_version));
+ EXPECT_TRUE(app_version.empty());
}
// Do a RecordEnvironment() call and check whether the pref is recorded.
@@ -298,7 +301,9 @@ TEST_F(MetricsLogTest, LoadSavedEnvironmentFromPrefs) {
{
TestMetricsLog log(
kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
- EXPECT_TRUE(log.LoadSavedEnvironmentFromPrefs());
+ std::string app_version;
+ EXPECT_TRUE(log.LoadSavedEnvironmentFromPrefs(&app_version));
+ EXPECT_EQ("bogus version", app_version);
// Check some values in the system profile.
EXPECT_EQ(kInstallDateExpected, log.system_profile().install_date());
EXPECT_EQ(kEnabledDateExpected, log.system_profile().uma_enabled_date());
@@ -322,7 +327,9 @@ TEST_F(MetricsLogTest, LoadSavedEnvironmentFromPrefs) {
prefs_.SetString(kSystemProfileHashPref, "deadbeef");
TestMetricsLog log(
kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
- EXPECT_FALSE(log.LoadSavedEnvironmentFromPrefs());
+ std::string app_version;
+ EXPECT_FALSE(log.LoadSavedEnvironmentFromPrefs(&app_version));
+ EXPECT_TRUE(app_version.empty());
// Ensure that the prefs are cleared, even if the call failed.
EXPECT_TRUE(prefs_.GetString(kSystemProfilePref).empty());
EXPECT_TRUE(prefs_.GetString(kSystemProfileHashPref).empty());
@@ -388,12 +395,12 @@ TEST_F(MetricsLogTest, InitialLogStabilityMetrics) {
// Required metrics:
EXPECT_TRUE(stability.has_launch_count());
EXPECT_TRUE(stability.has_crash_count());
- // Initial log metrics:
- EXPECT_TRUE(stability.has_incomplete_shutdown_count());
- EXPECT_TRUE(stability.has_breakpad_registration_success_count());
- EXPECT_TRUE(stability.has_breakpad_registration_failure_count());
- EXPECT_TRUE(stability.has_debugger_present_count());
- EXPECT_TRUE(stability.has_debugger_not_present_count());
+ // Initial log metrics: only expected if non-zero.
+ EXPECT_FALSE(stability.has_incomplete_shutdown_count());
+ EXPECT_FALSE(stability.has_breakpad_registration_success_count());
+ EXPECT_FALSE(stability.has_breakpad_registration_failure_count());
+ EXPECT_FALSE(stability.has_debugger_present_count());
+ EXPECT_FALSE(stability.has_debugger_not_present_count());
// The test provider should have been called upon to provide initial
// stability and regular stability metrics.
@@ -418,7 +425,7 @@ TEST_F(MetricsLogTest, OngoingLogStabilityMetrics) {
// Required metrics:
EXPECT_TRUE(stability.has_launch_count());
EXPECT_TRUE(stability.has_crash_count());
- // Initial log metrics:
+ // Initial log metrics: only expected if non-zero.
EXPECT_FALSE(stability.has_incomplete_shutdown_count());
EXPECT_FALSE(stability.has_breakpad_registration_success_count());
EXPECT_FALSE(stability.has_breakpad_registration_failure_count());
diff --git a/chromium/components/metrics/metrics_pref_names.cc b/chromium/components/metrics/metrics_pref_names.cc
index b751c02d4f4..1d5a7b63e84 100644
--- a/chromium/components/metrics/metrics_pref_names.cc
+++ b/chromium/components/metrics/metrics_pref_names.cc
@@ -7,6 +7,21 @@
namespace metrics {
namespace prefs {
+// Array of strings that are each UMA logs that were supposed to be sent in the
+// first minute of a browser session. These logs include things like crash count
+// info, etc.
+// Deprecated by kMetricsInitialLogs.
+const char kDeprecatedMetricsInitialLogs[] =
+ "user_experience_metrics.initial_logs_list";
+
+// Array of strings that are each UMA logs that were not sent because the
+// browser terminated before these accumulated metrics could be sent. These
+// logs typically include histograms and memory reports, as well as ongoing
+// user activities.
+// Deprecated by kMetricsOngoingLogs.
+const char kDeprecatedMetricsOngoingLogs[] =
+ "user_experience_metrics.ongoing_logs_list";
+
// Set once, to the current epoch time, on the first run of chrome on this
// machine. Attached to metrics reports forever thereafter.
const char kInstallDate[] = "uninstall_metrics.installation_date2";
@@ -23,11 +38,10 @@ const char kMetricsClientID[] = "user_experience_metrics.client_id2";
// used for the value is metrics::MetricsServiceClient::EnableMetricsDefault.
const char kMetricsDefaultOptIn[] = "user_experience_metrics.default_opt_in";
-// Array of strings that are each UMA logs that were supposed to be sent in the
-// first minute of a browser session. These logs include things like crash count
-// info, etc.
-const char kMetricsInitialLogs[] =
- "user_experience_metrics.initial_logs_list";
+// Array of dictionaries that are each UMA logs that were supposed to be sent in
+// the first minute of a browser session. These logs include things like crash
+// count info, etc.
+const char kMetricsInitialLogs[] = "user_experience_metrics.initial_logs2";
// The metrics entropy source.
// Note: The name low_entropy_source2 is a result of creating
@@ -39,12 +53,11 @@ const char kMetricsLowEntropySource[] =
// stored locally and never transmitted in metrics reports.
const char kMetricsMachineId[] = "user_experience_metrics.machine_id";
-// Array of strings that are each UMA logs that were not sent because the
-// browser terminated before these accumulated metrics could be sent. These
+// Array of dictionaries that are each UMA logs that were not sent because the
+// browser terminated before these accumulated metrics could be sent. These
// logs typically include histograms and memory reports, as well as ongoing
// user activities.
-const char kMetricsOngoingLogs[] =
- "user_experience_metrics.ongoing_logs_list";
+const char kMetricsOngoingLogs[] = "user_experience_metrics.ongoing_logs2";
// Boolean that indicates a cloned install has been detected and the metrics
// client id and low entropy source should be reset.
@@ -55,8 +68,8 @@ const char kMetricsResetIds[] = "user_experience_metrics.reset_metrics_ids";
const char kMetricsReportingEnabled[] =
"user_experience_metrics.reporting_enabled";
-// Date/time when the user opted in to UMA and generated the client id for the
-// very first time (local machine time, stored as a 64-bit time_t value).
+// Date/time when the user opted in to UMA and generated the client id most
+// recently (local machine time, stored as a 64-bit time_t value).
const char kMetricsReportingEnabledTimestamp[] =
"user_experience_metrics.client_id_timestamp";
@@ -86,6 +99,16 @@ const char kStabilityChildProcessCrashCount[] =
const char kStabilityCrashCount[] =
"user_experience_metrics.stability.crash_count";
+// Number of times the initial stability log upload was deferred to the next
+// startup.
+const char kStabilityDeferredCount[] =
+ "user_experience_metrics.stability.deferred_count";
+
+// Number of times stability data was discarded. This is accumulated since the
+// last report, even across versions.
+const char kStabilityDiscardCount[] =
+ "user_experience_metrics.stability.discard_count";
+
// Number of times the browser has been run under a debugger.
const char kStabilityDebuggerPresent[] =
"user_experience_metrics.stability.debugger_present";
@@ -111,6 +134,11 @@ const char kStabilityExtensionRendererCrashCount[] =
const char kStabilityExtensionRendererFailedLaunchCount[] =
"user_experience_metrics.stability.extension_renderer_failed_launch_count";
+// Number of times an extension renderer process successfully launched since the
+// last report.
+const char kStabilityExtensionRendererLaunchCount[] =
+ "user_experience_metrics.stability.extension_renderer_launch_count";
+
// Number of times the session end did not complete.
const char kStabilityIncompleteSessionEndCount[] =
"user_experience_metrics.stability.incomplete_session_end_count";
@@ -145,6 +173,11 @@ const char kStabilityRendererFailedLaunchCount[] =
const char kStabilityRendererHangCount[] =
"user_experience_metrics.stability.renderer_hang_count";
+// Number of times a renderer process successfully launched since the last
+// report.
+const char kStabilityRendererLaunchCount[] =
+ "user_experience_metrics.stability.renderer_launch_count";
+
// Base64 encoded serialized UMA system profile proto from the previous session.
const char kStabilitySavedSystemProfile[] =
"user_experience_metrics.stability.saved_system_profile";
@@ -168,6 +201,11 @@ const char kStabilityStatsBuildTime[] =
const char kStabilityStatsVersion[] =
"user_experience_metrics.stability.stats_version";
+// Number of times the version number stored in prefs did not match the
+// serialized system profile version number.
+const char kStabilityVersionMismatchCount[] =
+ "user_experience_metrics.stability.version_mismatch_count";
+
// The keys below are strictly increasing counters over the lifetime of
// a chrome installation. They are (optionally) sent up to the uninstall
// survey in the event of uninstallation.
diff --git a/chromium/components/metrics/metrics_pref_names.h b/chromium/components/metrics/metrics_pref_names.h
index bcd531892d8..df25e3854a9 100644
--- a/chromium/components/metrics/metrics_pref_names.h
+++ b/chromium/components/metrics/metrics_pref_names.h
@@ -10,6 +10,8 @@ namespace prefs {
// Alphabetical list of preference names specific to the metrics
// component. Document each in the .cc file.
+extern const char kDeprecatedMetricsInitialLogs[];
+extern const char kDeprecatedMetricsOngoingLogs[];
extern const char kInstallDate[];
extern const char kMetricsClientID[];
extern const char kMetricsDefaultOptIn[];
@@ -34,9 +36,12 @@ extern const char kStabilityChildProcessCrashCount[];
extern const char kStabilityCrashCount[];
extern const char kStabilityDebuggerPresent[];
extern const char kStabilityDebuggerNotPresent[];
+extern const char kStabilityDeferredCount[];
+extern const char kStabilityDiscardCount[];
extern const char kStabilityExecutionPhase[];
extern const char kStabilityExtensionRendererCrashCount[];
extern const char kStabilityExtensionRendererFailedLaunchCount[];
+extern const char kStabilityExtensionRendererLaunchCount[];
extern const char kStabilityExitedCleanly[];
extern const char kStabilityIncompleteSessionEndCount[];
extern const char kStabilityLastTimestampSec[];
@@ -46,11 +51,13 @@ extern const char kStabilityPageLoadCount[];
extern const char kStabilityRendererCrashCount[];
extern const char kStabilityRendererFailedLaunchCount[];
extern const char kStabilityRendererHangCount[];
+extern const char kStabilityRendererLaunchCount[];
extern const char kStabilitySavedSystemProfile[];
extern const char kStabilitySavedSystemProfileHash[];
extern const char kStabilitySessionEndCompleted[];
extern const char kStabilityStatsBuildTime[];
extern const char kStabilityStatsVersion[];
+extern const char kStabilityVersionMismatchCount[];
extern const char kUninstallLaunchCount[];
extern const char kUninstallMetricsPageLoadCount[];
extern const char kUninstallMetricsUptimeSec[];
diff --git a/chromium/components/metrics/metrics_provider.cc b/chromium/components/metrics/metrics_provider.cc
index 924cc6f3180..50f621a73ec 100644
--- a/chromium/components/metrics/metrics_provider.cc
+++ b/chromium/components/metrics/metrics_provider.cc
@@ -24,6 +24,9 @@ void MetricsProvider::OnRecordingEnabled() {
void MetricsProvider::OnRecordingDisabled() {
}
+void MetricsProvider::OnAppEnterBackground() {
+}
+
void MetricsProvider::ProvideSystemProfileMetrics(
SystemProfileProto* system_profile_proto) {
}
diff --git a/chromium/components/metrics/metrics_provider.h b/chromium/components/metrics/metrics_provider.h
index 6a690f5251c..d76b6772ccd 100644
--- a/chromium/components/metrics/metrics_provider.h
+++ b/chromium/components/metrics/metrics_provider.h
@@ -36,6 +36,13 @@ class MetricsProvider {
// Called when metrics recording has been disabled.
virtual void OnRecordingDisabled();
+ // Called when the application is going into background mode, on platforms
+ // where applications may be killed when going into the background (Android,
+ // iOS). Providers that buffer histogram data in memory should persist
+ // histograms in this callback, as the application may be killed without
+ // further notification after this callback.
+ virtual void OnAppEnterBackground();
+
// Provides additional metrics into the system profile.
virtual void ProvideSystemProfileMetrics(
SystemProfileProto* system_profile_proto);
diff --git a/chromium/components/metrics/metrics_service.cc b/chromium/components/metrics/metrics_service.cc
index a14b047a6c2..2acc9cb0b88 100644
--- a/chromium/components/metrics/metrics_service.cc
+++ b/chromium/components/metrics/metrics_service.cc
@@ -361,13 +361,6 @@ bool MetricsService::WasLastShutdownClean() const {
return clean_exit_beacon_.exited_cleanly();
}
-std::unique_ptr<const base::FieldTrial::EntropyProvider>
-MetricsService::CreateEntropyProvider() {
- // TODO(asvitkine): Refactor the code so that MetricsService does not expose
- // this method.
- return state_manager_->CreateDefaultEntropyProvider();
-}
-
void MetricsService::EnableRecording() {
DCHECK(IsSingleThreaded());
@@ -396,8 +389,6 @@ void MetricsService::DisableRecording() {
return;
recording_state_ = INACTIVE;
- client_->OnRecordingDisabled();
-
base::RemoveActionCallback(action_callback_);
for (MetricsProvider* provider : metrics_providers_)
@@ -469,6 +460,11 @@ void MetricsService::OnAppEnterBackground() {
MarkAppCleanShutdownAndCommit(&clean_exit_beacon_, local_state_);
+ // Give providers a chance to persist histograms as part of being
+ // backgrounded.
+ for (MetricsProvider* provider : metrics_providers_)
+ provider->OnAppEnterBackground();
+
// At this point, there's no way of knowing when the process will be
// killed, so this has to be treated similar to a shutdown, closing and
// persisting all logs. Unlinke a shutdown, the state is primed to be ready
@@ -520,12 +516,20 @@ void MetricsService::ClearSavedStabilityMetrics() {
provider->ClearSavedStabilityMetrics();
// Reset the prefs that are managed by MetricsService/MetricsLog directly.
+ local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
+ local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
local_state_->SetInteger(prefs::kStabilityCrashCount, 0);
+ local_state_->SetInteger(prefs::kStabilityDebuggerPresent, 0);
+ local_state_->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
local_state_->SetInteger(prefs::kStabilityExecutionPhase,
UNINITIALIZED_PHASE);
local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
local_state_->SetInteger(prefs::kStabilityLaunchCount, 0);
local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
+ local_state_->SetInteger(prefs::kStabilityDeferredCount, 0);
+ // Note: kStabilityDiscardCount is not cleared as its intent is to measure
+ // the number of times data is discarded, even across versions.
+ local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0);
}
void MetricsService::PushExternalLog(const std::string& log) {
@@ -542,6 +546,11 @@ UpdateUsagePrefCallbackType MetricsService::GetDataUseForwardingCallback() {
return UpdateUsagePrefCallbackType();
}
+void MetricsService::MergeHistogramDeltas() {
+ for (MetricsProvider* provider : metrics_providers_)
+ provider->MergeHistogramDeltas();
+}
+
//------------------------------------------------------------------------------
// private methods
//------------------------------------------------------------------------------
@@ -554,8 +563,11 @@ void MetricsService::InitializeMetricsState() {
const int64_t buildtime = MetricsLog::GetBuildTime();
const std::string version = client_->GetVersionString();
bool version_changed = false;
- if (local_state_->GetInt64(prefs::kStabilityStatsBuildTime) != buildtime ||
- local_state_->GetString(prefs::kStabilityStatsVersion) != version) {
+ int64_t previous_buildtime =
+ local_state_->GetInt64(prefs::kStabilityStatsBuildTime);
+ std::string previous_version =
+ local_state_->GetString(prefs::kStabilityStatsVersion);
+ if (previous_buildtime != buildtime || previous_version != version) {
local_state_->SetString(prefs::kStabilityStatsVersion, version);
local_state_->SetInt64(prefs::kStabilityStatsBuildTime, buildtime);
version_changed = true;
@@ -587,8 +599,11 @@ void MetricsService::InitializeMetricsState() {
// If the previous session didn't exit cleanly, or if any provider
// explicitly requests it, prepare an initial stability log -
// provided UMA is enabled.
- if (state_manager_->IsMetricsReportingEnabled())
- has_initial_stability_log = PrepareInitialStabilityLog();
+ if (state_manager_->IsMetricsReportingEnabled()) {
+ has_initial_stability_log = PrepareInitialStabilityLog(previous_version);
+ if (!has_initial_stability_log)
+ IncrementPrefValue(prefs::kStabilityDeferredCount);
+ }
}
// If no initial stability log was generated and there was a version upgrade,
@@ -597,8 +612,10 @@ void MetricsService::InitializeMetricsState() {
// number of different edge cases, such as if the last version crashed before
// it could save off a system profile or if UMA reporting is disabled (which
// normally results in stats being accumulated).
- if (!has_initial_stability_log && version_changed)
+ if (!has_initial_stability_log && version_changed) {
ClearSavedStabilityMetrics();
+ IncrementPrefValue(prefs::kStabilityDiscardCount);
+ }
// Update session ID.
++session_id_;
@@ -637,9 +654,6 @@ void MetricsService::InitializeMetricsState() {
}
void MetricsService::OnUserAction(const std::string& action) {
- if (!ShouldLogEvents())
- return;
-
log_manager_.current_log()->RecordUserAction(action);
HandleIdleSinceLastTransmission(false);
}
@@ -894,7 +908,8 @@ bool MetricsService::ProvidersHaveInitialStabilityMetrics() {
return false;
}
-bool MetricsService::PrepareInitialStabilityLog() {
+bool MetricsService::PrepareInitialStabilityLog(
+ const std::string& prefs_previous_version) {
DCHECK_EQ(INITIALIZED, state_);
std::unique_ptr<MetricsLog> initial_stability_log(
@@ -902,9 +917,13 @@ bool MetricsService::PrepareInitialStabilityLog() {
// Do not call NotifyOnDidCreateMetricsLog here because the stability
// log describes stats from the _previous_ session.
-
- if (!initial_stability_log->LoadSavedEnvironmentFromPrefs())
+ std::string system_profile_app_version;
+ if (!initial_stability_log->LoadSavedEnvironmentFromPrefs(
+ &system_profile_app_version)) {
return false;
+ }
+ if (system_profile_app_version != prefs_previous_version)
+ IncrementPrefValue(prefs::kStabilityVersionMismatchCount);
log_manager_.PauseCurrentLog();
log_manager_.BeginLoggingWithLog(std::move(initial_stability_log));
@@ -1070,6 +1089,33 @@ void MetricsService::RegisterSyntheticFieldTrial(
NotifySyntheticTrialObservers();
}
+void MetricsService::RegisterSyntheticMultiGroupFieldTrial(
+ uint32_t trial_name_hash,
+ const std::vector<uint32_t>& group_name_hashes) {
+ auto has_same_trial_name =
+ [trial_name_hash](const variations::SyntheticTrialGroup& x) {
+ return x.id.name == trial_name_hash;
+ };
+ synthetic_trial_groups_.erase(
+ std::remove_if(synthetic_trial_groups_.begin(),
+ synthetic_trial_groups_.end(), has_same_trial_name),
+ synthetic_trial_groups_.end());
+
+ if (group_name_hashes.empty())
+ return;
+
+ variations::SyntheticTrialGroup trial_group(trial_name_hash,
+ group_name_hashes[0]);
+ trial_group.start_time = base::TimeTicks::Now();
+ for (uint32_t group_name_hash : group_name_hashes) {
+ // Note: Adding the trial group will copy it, so this re-uses the same
+ // |trial_group| struct for convenience (e.g. so start_time's all match).
+ trial_group.id.group = group_name_hash;
+ synthetic_trial_groups_.push_back(trial_group);
+ }
+ NotifySyntheticTrialObservers();
+}
+
void MetricsService::GetCurrentSyntheticFieldTrialsForTesting(
std::vector<variations::ActiveGroupId>* synthetic_trials) {
GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(), synthetic_trials);
@@ -1105,9 +1151,8 @@ void MetricsService::GetSyntheticFieldTrialsOlderThan(
std::unique_ptr<MetricsLog> MetricsService::CreateLog(
MetricsLog::LogType log_type) {
- return base::WrapUnique(new MetricsLog(state_manager_->client_id(),
- session_id_, log_type, client_,
- local_state_));
+ return base::MakeUnique<MetricsLog>(state_manager_->client_id(), session_id_,
+ log_type, client_, local_state_);
}
void MetricsService::RecordCurrentEnvironment(MetricsLog* log) {
@@ -1121,32 +1166,24 @@ void MetricsService::RecordCurrentHistograms() {
DCHECK(log_manager_.current_log());
SCOPED_UMA_HISTOGRAM_TIMER("UMA.MetricsService.RecordCurrentHistograms.Time");
- // Merge any data from metrics providers into the global StatisticsRecorder.
- for (MetricsProvider* provider : metrics_providers_)
- provider->MergeHistogramDeltas();
-
- histogram_snapshot_manager_.StartDeltas();
// "true" to the begin() call indicates that StatisticsRecorder should include
// histograms held in persistent storage.
- histogram_snapshot_manager_.PrepareDeltasWithoutStartFinish(
+ histogram_snapshot_manager_.PrepareDeltas(
base::StatisticsRecorder::begin(true), base::StatisticsRecorder::end(),
base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
for (MetricsProvider* provider : metrics_providers_)
provider->RecordHistogramSnapshots(&histogram_snapshot_manager_);
- histogram_snapshot_manager_.FinishDeltas();
}
void MetricsService::RecordCurrentStabilityHistograms() {
DCHECK(log_manager_.current_log());
- histogram_snapshot_manager_.StartDeltas();
// "true" indicates that StatisticsRecorder should include histograms in
// persistent storage.
- histogram_snapshot_manager_.PrepareDeltasWithoutStartFinish(
+ histogram_snapshot_manager_.PrepareDeltas(
base::StatisticsRecorder::begin(true), base::StatisticsRecorder::end(),
base::Histogram::kNoFlags, base::Histogram::kUmaStabilityHistogramFlag);
for (MetricsProvider* provider : metrics_providers_)
provider->RecordInitialHistogramSnapshots(&histogram_snapshot_manager_);
- histogram_snapshot_manager_.FinishDeltas();
}
void MetricsService::LogCleanShutdown() {
@@ -1160,13 +1197,6 @@ void MetricsService::LogCleanShutdown() {
MetricsService::SHUTDOWN_COMPLETE);
}
-bool MetricsService::ShouldLogEvents() {
- // We simply don't log events to UMA if there is a single incognito
- // session visible. The problem is that we always notify using the original
- // profile in order to simplify notification processing.
- return !client_->IsOffTheRecordSessionActive();
-}
-
void MetricsService::RecordBooleanPrefValue(const char* path, bool value) {
DCHECK(IsSingleThreaded());
local_state_->SetBoolean(path, value);
diff --git a/chromium/components/metrics/metrics_service.h b/chromium/components/metrics/metrics_service.h
index a1f4f63c5a6..3f19a5b3490 100644
--- a/chromium/components/metrics/metrics_service.h
+++ b/chromium/components/metrics/metrics_service.h
@@ -124,16 +124,6 @@ class MetricsService : public base::HistogramFlattener {
// Returns true if the last session exited cleanly.
bool WasLastShutdownClean() const;
- // Returns the preferred entropy provider used to seed persistent activities
- // based on whether or not metrics reporting will be permitted on this client.
- //
- // If metrics reporting is enabled, this method returns an entropy provider
- // that has a high source of entropy, partially based on the client ID.
- // Otherwise, it returns an entropy provider that is based on a low entropy
- // source.
- std::unique_ptr<const base::FieldTrial::EntropyProvider>
- CreateEntropyProvider();
-
// At startup, prefs needs to be called with a list of all the pref names and
// types we'll be using.
static void RegisterPrefs(PrefRegistrySimple* registry);
@@ -220,6 +210,9 @@ class MetricsService : public base::HistogramFlattener {
// from any thread, but this function should be called on UI thread.
UpdateUsagePrefCallbackType GetDataUseForwardingCallback();
+ // Merge any data from metrics providers into the global StatisticsRecorder.
+ void MergeHistogramDeltas();
+
protected:
// Exposed for testing.
MetricsLogManager* log_manager() { return &log_manager_; }
@@ -259,9 +252,18 @@ class MetricsService : public base::HistogramFlattener {
// registered at a time for a given trial_name. Only the last group name that
// is registered for a given trial name will be recorded. The values passed
// in must not correspond to any real field trial in the code.
+ // Note: Should not be used to replace trials that were registered with
+ // RegisterMultiGroupSyntheticFieldTrial().
void RegisterSyntheticFieldTrial(
const variations::SyntheticTrialGroup& trial_group);
+ // Similar to RegisterSyntheticFieldTrial(), but registers a synthetic trial
+ // that has multiple active groups for a given trial name hash. Any previous
+ // groups registered for |trial_name_hash| will be replaced.
+ void RegisterSyntheticMultiGroupFieldTrial(
+ uint32_t trial_name_hash,
+ const std::vector<uint32_t>& group_name_hashes);
+
// Calls into the client to initialize some system profile metrics.
void StartInitTask();
@@ -340,9 +342,10 @@ class MetricsService : public base::HistogramFlattener {
// Prepares the initial stability log, which is only logged when the previous
// run of Chrome crashed. This log contains any stability metrics left over
// from that previous run, and only these stability metrics. It uses the
- // system profile from the previous session. Returns true if a log was
- // created.
- bool PrepareInitialStabilityLog();
+ // system profile from the previous session. |prefs_previous_version| is used
+ // to validate the version number recovered from the system profile. Returns
+ // true if a log was created.
+ bool PrepareInitialStabilityLog(const std::string& prefs_previous_version);
// Prepares the initial metrics log, which includes startup histograms and
// profiler data, as well as incremental stability-related metrics.
@@ -368,9 +371,6 @@ class MetricsService : public base::HistogramFlattener {
// buffered plugin stability statistics.
void RecordCurrentState(PrefService* pref);
- // Checks whether events should currently be logged.
- bool ShouldLogEvents();
-
// Sets the value of the specified path in prefs and schedules a save.
void RecordBooleanPrefValue(const char* path, bool value);
@@ -482,6 +482,8 @@ class MetricsService : public base::HistogramFlattener {
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest,
PermutedEntropyCacheClearedWhenLowEntropyReset);
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RegisterSyntheticTrial);
+ FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest,
+ RegisterSyntheticMultiGroupFieldTrial);
// Pointer used for obtaining data use pref updater callback on above layers.
std::unique_ptr<DataUseTracker> data_use_tracker_;
diff --git a/chromium/components/metrics/metrics_service_accessor.cc b/chromium/components/metrics/metrics_service_accessor.cc
index ac04ba9884d..786895b40a1 100644
--- a/chromium/components/metrics/metrics_service_accessor.cc
+++ b/chromium/components/metrics/metrics_service_accessor.cc
@@ -16,20 +16,13 @@ namespace metrics {
// static
bool MetricsServiceAccessor::IsMetricsReportingEnabled(
PrefService* pref_service) {
- return IsMetricsReportingEnabledWithPrefValue(
- pref_service->GetBoolean(prefs::kMetricsReportingEnabled));
-}
-
-// static
-bool MetricsServiceAccessor::IsMetricsReportingEnabledWithPrefValue(
- bool enabled_in_prefs) {
#if defined(GOOGLE_CHROME_BUILD)
// In official builds, disable metrics when reporting field trials are
// forced; otherwise, use the value of the user's preference to determine
// whether to enable metrics reporting.
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceFieldTrials) &&
- enabled_in_prefs;
+ pref_service->GetBoolean(prefs::kMetricsReportingEnabled);
#else
// In non-official builds, disable metrics reporting completely.
return false;
@@ -46,6 +39,19 @@ bool MetricsServiceAccessor::RegisterSyntheticFieldTrial(
}
// static
+bool MetricsServiceAccessor::RegisterSyntheticMultiGroupFieldTrial(
+ MetricsService* metrics_service,
+ const std::string& trial_name,
+ const std::vector<uint32_t>& group_name_hashes) {
+ if (!metrics_service)
+ return false;
+
+ metrics_service->RegisterSyntheticMultiGroupFieldTrial(HashName(trial_name),
+ group_name_hashes);
+ return true;
+}
+
+// static
bool MetricsServiceAccessor::RegisterSyntheticFieldTrialWithNameHash(
MetricsService* metrics_service,
uint32_t trial_name_hash,
diff --git a/chromium/components/metrics/metrics_service_accessor.h b/chromium/components/metrics/metrics_service_accessor.h
index 8d34675b5fe..c4b5e62f195 100644
--- a/chromium/components/metrics/metrics_service_accessor.h
+++ b/chromium/components/metrics/metrics_service_accessor.h
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <string>
+#include <vector>
#include "base/macros.h"
@@ -28,32 +29,28 @@ class MetricsServiceAccessor {
// Returns whether metrics reporting is enabled, using the value of the
// kMetricsReportingEnabled pref in |pref_service| to determine whether user
// has enabled reporting.
- // NOTE: This method currently does not return the correct value on ChromeOS
- // and Android due to http://crbug.com/362192 and http://crbug.com/532084. See
- // ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled().
static bool IsMetricsReportingEnabled(PrefService* pref_service);
- // Returns whether metrics reporting is enabled, using the value of
- // |enabled_in_prefs| to determine whether the user has enabled reporting.
- // Exists because kMetricsReportingEnabled is currently not used on all
- // platforms.
- // TODO(gayane): Consolidate metric prefs on all platforms and eliminate this
- // method. http://crbug.com/362192, http://crbug.com/532084
- static bool IsMetricsReportingEnabledWithPrefValue(bool enabled_in_prefs);
// Registers a field trial name and group with |metrics_service| (if not
// null), to be used to annotate a UMA report with a particular configuration
- // state. A UMA report will be annotated with this trial group if and only if
- // all events in the report were created after the trial is registered. Only
- // one group name may be registered at a time for a given trial name. Only the
- // last group name that is registered for a given trial name will be recorded.
- // The values passed in must not correspond to any real field trial in the
- // code. Returns true on success.
- // See the comment on MetricsService::RegisterSyntheticFieldTrial for details.
+ // state. Returns true on success.
+ // See the comment on MetricsService::RegisterSyntheticFieldTrial() for
+ // details.
static bool RegisterSyntheticFieldTrial(MetricsService* metrics_service,
const std::string& trial_name,
const std::string& group_name);
+ // Registers a field trial name and set of groups with |metrics_service| (if
+ // not null), to be used to annotate a UMA report with a particular
+ // configuration state. Returns true on success.
+ // See the comment on MetricsService::RegisterSyntheticMultiGroupFieldTrial()
+ // for details.
+ static bool RegisterSyntheticMultiGroupFieldTrial(
+ MetricsService* metrics_service,
+ const std::string& trial_name,
+ const std::vector<uint32_t>& group_name_hashes);
+
// Same as RegisterSyntheticFieldTrial above, but takes in the trial name as a
// hash rather than computing the hash from the string.
static bool RegisterSyntheticFieldTrialWithNameHash(
diff --git a/chromium/components/metrics/metrics_service_client.h b/chromium/components/metrics/metrics_service_client.h
index 8624477d567..af4257784f5 100644
--- a/chromium/components/metrics/metrics_service_client.h
+++ b/chromium/components/metrics/metrics_service_client.h
@@ -41,13 +41,6 @@ class MetricsServiceClient {
// when metrics recording gets enabled.
virtual void SetMetricsClientId(const std::string& client_id) = 0;
- // Notifies the client that recording is disabled, so that other services
- // (such as crash reporting) can clear any association with metrics.
- virtual void OnRecordingDisabled() = 0;
-
- // Whether there's an "off the record" (aka "Incognito") session active.
- virtual bool IsOffTheRecordSessionActive() = 0;
-
// Returns the product value to use in uploaded reports, which will be used to
// set the ChromeUserMetricsExtension.product field. See comments on that
// field on why it's an int32_t rather than an enum.
diff --git a/chromium/components/metrics/metrics_service_unittest.cc b/chromium/components/metrics/metrics_service_unittest.cc
index 96e62f141c0..37dbbddbdbd 100644
--- a/chromium/components/metrics/metrics_service_unittest.cc
+++ b/chromium/components/metrics/metrics_service_unittest.cc
@@ -393,6 +393,53 @@ TEST_F(MetricsServiceTest, RegisterSyntheticTrial) {
service.log_manager_.FinishCurrentLog();
}
+TEST_F(MetricsServiceTest, RegisterSyntheticMultiGroupFieldTrial) {
+ TestMetricsServiceClient client;
+ MetricsService service(GetMetricsStateManager(), &client, GetLocalState());
+
+ // Register a synthetic trial TestTrial1 with groups A and B.
+ uint32_t trial_name_hash = HashName("TestTrial1");
+ std::vector<uint32_t> group_name_hashes = {HashName("A"), HashName("B")};
+ service.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
+ group_name_hashes);
+ // Ensure that time has advanced by at least a tick before proceeding.
+ WaitUntilTimeChanges(base::TimeTicks::Now());
+
+ service.log_manager_.BeginLoggingWithLog(std::unique_ptr<MetricsLog>(
+ new MetricsLog("clientID", 1, MetricsLog::INITIAL_STABILITY_LOG, &client,
+ GetLocalState())));
+
+ std::vector<variations::ActiveGroupId> synthetic_trials;
+ service.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
+ &synthetic_trials);
+ EXPECT_EQ(2U, synthetic_trials.size());
+ EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "A"));
+ EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "B"));
+
+ // Change the group for the trial to a single group.
+ group_name_hashes = {HashName("X")};
+ service.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
+ group_name_hashes);
+ // Ensure that time has advanced by at least a tick before proceeding.
+ WaitUntilTimeChanges(base::TimeTicks::Now());
+
+ service.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
+ &synthetic_trials);
+ EXPECT_EQ(1U, synthetic_trials.size());
+ EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "X"));
+
+ // Register a trial with no groups, which should effectively remove the trial.
+ group_name_hashes.clear();
+ service.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
+ group_name_hashes);
+ // Ensure that time has advanced by at least a tick before proceeding.
+ WaitUntilTimeChanges(base::TimeTicks::Now());
+
+ service.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
+ &synthetic_trials);
+ service.log_manager_.FinishCurrentLog();
+}
+
TEST_F(MetricsServiceTest,
MetricsProviderOnRecordingDisabledCalledOnInitialStop) {
TestMetricsServiceClient client;
diff --git a/chromium/components/metrics/metrics_state_manager.cc b/chromium/components/metrics/metrics_state_manager.cc
index cf1b4a126ab..4cae20d3ae7 100644
--- a/chromium/components/metrics/metrics_state_manager.cc
+++ b/chromium/components/metrics/metrics_state_manager.cc
@@ -83,10 +83,15 @@ bool MetricsStateManager::IsMetricsReportingEnabled() {
}
void MetricsStateManager::ForceClientIdCreation() {
- if (!client_id_.empty())
- return;
+ {
+ std::string client_id_from_prefs =
+ local_state_->GetString(prefs::kMetricsClientID);
+ // If client id in prefs matches the cached copy, return early.
+ if (!client_id_from_prefs.empty() && client_id_from_prefs == client_id_)
+ return;
+ client_id_.swap(client_id_from_prefs);
+ }
- client_id_ = local_state_->GetString(prefs::kMetricsClientID);
if (!client_id_.empty()) {
// It is technically sufficient to only save a backup of the client id when
// it is initially generated below, but since the backup was only introduced
@@ -256,8 +261,10 @@ MetricsStateManager::LoadClientInfoAndMaybeMigrate() {
}
// The GUID retrieved (and possibly fixed above) should be valid unless
- // retrieval failed.
- DCHECK(!client_info || base::IsValidGUID(client_info->client_id));
+ // retrieval failed. If not, return nullptr. This will result in a new GUID
+ // being generated by the calling function ForceClientIdCreation().
+ if (client_info && !base::IsValidGUID(client_info->client_id))
+ return nullptr;
return client_info;
}
diff --git a/chromium/components/metrics/net/cellular_logic_helper.cc b/chromium/components/metrics/net/cellular_logic_helper.cc
index 3651e878cdc..33b351e0a4d 100644
--- a/chromium/components/metrics/net/cellular_logic_helper.cc
+++ b/chromium/components/metrics/net/cellular_logic_helper.cc
@@ -4,7 +4,6 @@
#include "components/metrics/net/cellular_logic_helper.h"
-#include "components/variations/variations_associated_data.h"
#include "net/base/network_change_notifier.h"
namespace metrics {
@@ -21,10 +20,8 @@ const int kStandardUploadIntervalSeconds = 30 * 60; // Thirty minutes.
#if defined(OS_ANDROID)
const bool kDefaultCellularLogicEnabled = true;
-const bool kDefaultCellularLogicOptimization = true;
#else
const bool kDefaultCellularLogicEnabled = false;
-const bool kDefaultCellularLogicOptimization = false;
#endif
} // namespace
@@ -37,22 +34,10 @@ base::TimeDelta GetUploadInterval() {
return base::TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
}
-// Returns true if current connection type is cellular and user is assigned to
-// experimental group for enabled cellular uploads.
+// Returns true if current connection type is cellular and cellular logic is
+// enabled.
bool IsCellularLogicEnabled() {
- std::string enabled = variations::GetVariationParamValue(
- "UMA_EnableCellularLogUpload", "Enabled");
- std::string optimized = variations::GetVariationParamValue(
- "UMA_EnableCellularLogUpload", "Optimize");
- bool is_enabled = kDefaultCellularLogicEnabled;
- if (!enabled.empty())
- is_enabled = (enabled == "true");
-
- bool is_optimized = kDefaultCellularLogicOptimization;
- if (!optimized.empty())
- is_optimized = (optimized == "true");
-
- if (!is_enabled || !is_optimized)
+ if (!kDefaultCellularLogicEnabled)
return false;
return net::NetworkChangeNotifier::IsConnectionCellular(
diff --git a/chromium/components/metrics/persisted_logs.cc b/chromium/components/metrics/persisted_logs.cc
index 52292da55cc..12d3a682188 100644
--- a/chromium/components/metrics/persisted_logs.cc
+++ b/chromium/components/metrics/persisted_logs.cc
@@ -4,12 +4,15 @@
#include "components/metrics/persisted_logs.h"
+#include <memory>
#include <string>
+#include <utility>
#include "base/base64.h"
#include "base/md5.h"
#include "base/metrics/histogram_macros.h"
#include "base/sha1.h"
+#include "base/strings/string_number_conversions.h"
#include "base/timer/elapsed_timer.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
@@ -19,6 +22,10 @@ namespace metrics {
namespace {
+const char kLogHashKey[] = "hash";
+const char kLogTimestampKey[] = "timestamp";
+const char kLogDataKey[] = "data";
+
PersistedLogs::LogReadStatus MakeRecallStatusHistogram(
PersistedLogs::LogReadStatus status) {
UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogRecallProtobufs",
@@ -37,16 +44,22 @@ bool ReadBase64String(const base::ListValue& list_value,
return base::Base64Decode(base64_result, result);
}
-// Base64-encodes |str| and appends the result to |list_value|.
-void AppendBase64String(const std::string& str, base::ListValue* list_value) {
- std::string base64_str;
- base::Base64Encode(str, &base64_str);
- list_value->AppendString(base64_str);
+std::string EncodeToBase64(const std::string& to_convert) {
+ std::string base64_result;
+ base::Base64Encode(to_convert, &base64_result);
+ return base64_result;
+}
+
+std::string DecodeFromBase64(const std::string& to_convert) {
+ std::string result;
+ base::Base64Decode(to_convert, &result);
+ return result;
}
} // namespace
-void PersistedLogs::LogHashPair::Init(const std::string& log_data) {
+void PersistedLogs::LogInfo::Init(const std::string& log_data,
+ const std::string& log_timestamp) {
DCHECK(!log_data.empty());
if (!compression::GzipCompress(log_data, &compressed_log_data)) {
@@ -59,15 +72,18 @@ void PersistedLogs::LogHashPair::Init(const std::string& log_data) {
static_cast<int>(100 * compressed_log_data.size() / log_data.size()));
hash = base::SHA1HashString(log_data);
+ timestamp = log_timestamp;
}
PersistedLogs::PersistedLogs(PrefService* local_state,
const char* pref_name,
+ const char* outdated_pref_name,
size_t min_log_count,
size_t min_log_bytes,
size_t max_log_size)
: local_state_(local_state),
pref_name_(pref_name),
+ outdated_pref_name_(outdated_pref_name),
min_log_count_(min_log_count),
min_log_bytes_(min_log_bytes),
max_log_size_(max_log_size != 0 ? max_log_size : static_cast<size_t>(-1)),
@@ -82,15 +98,26 @@ PersistedLogs::~PersistedLogs() {}
void PersistedLogs::SerializeLogs() const {
ListPrefUpdate update(local_state_, pref_name_);
WriteLogsToPrefList(update.Get());
+
+ // After writing all the logs to the new pref remove old outdated pref.
+ // TODO(gayane): Remove when all users are migrated. crbug.com/649440
+ if (local_state_->HasPrefPath(outdated_pref_name_))
+ local_state_->ClearPref(outdated_pref_name_);
}
PersistedLogs::LogReadStatus PersistedLogs::DeserializeLogs() {
+ // TODO(gayane): Remove the code for reading logs from outdated pref when all
+ // users are migrated. crbug.com/649440
+ if (local_state_->HasPrefPath(outdated_pref_name_)) {
+ return ReadLogsFromOldFormatPrefList(
+ *local_state_->GetList(outdated_pref_name_));
+ }
return ReadLogsFromPrefList(*local_state_->GetList(pref_name_));
}
void PersistedLogs::StoreLog(const std::string& log_data) {
- list_.push_back(LogHashPair());
- list_.back().Init(log_data);
+ list_.push_back(LogInfo());
+ list_.back().Init(log_data, base::Int64ToString(base::Time::Now().ToTimeT()));
}
void PersistedLogs::StageLog() {
@@ -109,6 +136,38 @@ void PersistedLogs::DiscardStagedLog() {
staged_log_index_ = -1;
}
+PersistedLogs::LogReadStatus PersistedLogs::ReadLogsFromPrefList(
+ const base::ListValue& list_value) {
+ if (list_value.empty())
+ return MakeRecallStatusHistogram(LIST_EMPTY);
+
+ const size_t log_count = list_value.GetSize();
+
+ DCHECK(list_.empty());
+ list_.resize(log_count);
+
+ for (size_t i = 0; i < log_count; ++i) {
+ const base::DictionaryValue* dict;
+ if (!list_value.GetDictionary(i, &dict) ||
+ !dict->GetString(kLogDataKey, &list_[i].compressed_log_data) ||
+ !dict->GetString(kLogHashKey, &list_[i].hash)) {
+ list_.clear();
+ return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION);
+ }
+
+ list_[i].compressed_log_data =
+ DecodeFromBase64(list_[i].compressed_log_data);
+ list_[i].hash = DecodeFromBase64(list_[i].hash);
+ // Ignoring the success of this step as timestamp might not be there for
+ // older logs.
+ // NOTE: Should be added to the check with other fields once migration is
+ // over.
+ dict->GetString(kLogTimestampKey, &list_[i].timestamp);
+ }
+
+ return MakeRecallStatusHistogram(RECALL_SUCCESS);
+}
+
void PersistedLogs::WriteLogsToPrefList(base::ListValue* list_value) const {
list_value->Clear();
@@ -140,14 +199,19 @@ void PersistedLogs::WriteLogsToPrefList(base::ListValue* list_value) const {
dropped_logs_num++;
continue;
}
- AppendBase64String(list_[i].compressed_log_data, list_value);
- AppendBase64String(list_[i].hash, list_value);
+ std::unique_ptr<base::DictionaryValue> dict_value(
+ new base::DictionaryValue);
+ dict_value->SetString(kLogHashKey, EncodeToBase64(list_[i].hash));
+ dict_value->SetString(kLogDataKey,
+ EncodeToBase64(list_[i].compressed_log_data));
+ dict_value->SetString(kLogTimestampKey, list_[i].timestamp);
+ list_value->Append(std::move(dict_value));
}
if (dropped_logs_num > 0)
UMA_HISTOGRAM_COUNTS("UMA.UnsentLogs.Dropped", dropped_logs_num);
}
-PersistedLogs::LogReadStatus PersistedLogs::ReadLogsFromPrefList(
+PersistedLogs::LogReadStatus PersistedLogs::ReadLogsFromOldFormatPrefList(
const base::ListValue& list_value) {
if (list_value.empty())
return MakeRecallStatusHistogram(LIST_EMPTY);
diff --git a/chromium/components/metrics/persisted_logs.h b/chromium/components/metrics/persisted_logs.h
index 73ad79a5b06..479924fd0fd 100644
--- a/chromium/components/metrics/persisted_logs.h
+++ b/chromium/components/metrics/persisted_logs.h
@@ -51,6 +51,7 @@ class PersistedLogs {
// that limit will be skipped when writing to disk.
PersistedLogs(PrefService* local_state,
const char* pref_name,
+ const char* outdated_pref_name,
size_t min_log_count,
size_t min_log_bytes,
size_t max_log_size);
@@ -87,6 +88,12 @@ class PersistedLogs {
return list_[staged_log_index_].hash;
}
+ // Returns the timestamp of the element in the front of the list.
+ const std::string& staged_log_timestamp() const {
+ DCHECK(has_staged_log());
+ return list_[staged_log_index_].timestamp;
+ }
+
// The number of elements currently stored.
size_t size() const { return list_.size(); }
@@ -100,6 +107,9 @@ class PersistedLogs {
// Reads the list from the ListValue.
LogReadStatus ReadLogsFromPrefList(const base::ListValue& list);
+ // Reads the list from the ListValue in the old Log-hash pair format.
+ LogReadStatus ReadLogsFromOldFormatPrefList(const base::ListValue& list);
+
// A weak pointer to the PrefService object to read and write the preference
// from. Calling code should ensure this object continues to exist for the
// lifetime of the PersistedLogs object.
@@ -108,6 +118,10 @@ class PersistedLogs {
// The name of the preference to serialize logs to/from.
const char* pref_name_;
+ // The name of the preference to serialize logs to/from which may contain log
+ // in the old formatting.
+ const char* outdated_pref_name_;
+
// We will keep at least this |min_log_count_| logs or |min_log_bytes_| bytes
// of logs, whichever is greater, when writing to disk. These apply after
// skipping logs greater than |max_log_size_|.
@@ -117,19 +131,23 @@ class PersistedLogs {
// Logs greater than this size will not be written to disk.
const size_t max_log_size_;
- struct LogHashPair {
- // Initializes the members based on uncompressed |log_data|.
- void Init(const std::string& log_data);
+ struct LogInfo {
+ // Initializes the members based on uncompressed |log_data| and
+ // |log_timestamp|.
+ void Init(const std::string& log_data, const std::string& log_timestamp);
// Compressed log data - a serialized protobuf that's been gzipped.
std::string compressed_log_data;
// The SHA1 hash of log, stored to catch errors from memory corruption.
std::string hash;
+
+ // The timestamp of when the log was created as a time_t value.
+ std::string timestamp;
};
// A list of all of the stored logs, stored with SHA1 hashes to check for
// corruption while they are stored in memory.
- std::vector<LogHashPair> list_;
+ std::vector<LogInfo> list_;
// The index and type of the log staged for upload. If nothing has been
// staged, the index will be -1.
diff --git a/chromium/components/metrics/persisted_logs_unittest.cc b/chromium/components/metrics/persisted_logs_unittest.cc
index b4a79a73ea6..94b8b7e97de 100644
--- a/chromium/components/metrics/persisted_logs_unittest.cc
+++ b/chromium/components/metrics/persisted_logs_unittest.cc
@@ -22,6 +22,7 @@ namespace metrics {
namespace {
const char kTestPrefName[] = "TestPref";
+const char kTestOutdatedPrefName[] = "OutdatedTestPref";
const size_t kLogCountLimit = 3;
const size_t kLogByteLimit = 1000;
@@ -63,9 +64,12 @@ class PersistedLogsTest : public testing::Test {
class TestPersistedLogs : public PersistedLogs {
public:
TestPersistedLogs(PrefService* service, size_t min_log_bytes)
- : PersistedLogs(service, kTestPrefName, kLogCountLimit, min_log_bytes,
- 0) {
- }
+ : PersistedLogs(service,
+ kTestPrefName,
+ kTestOutdatedPrefName,
+ kLogCountLimit,
+ min_log_bytes,
+ 0) {}
// Stages and removes the next log, while testing it's value.
void ExpectNextLog(const std::string& expected_log) {
@@ -111,6 +115,8 @@ TEST_F(PersistedLogsTest, SingleElementLogList) {
EXPECT_EQ(persisted_logs.staged_log(), result_persisted_logs.staged_log());
EXPECT_EQ(persisted_logs.staged_log_hash(),
result_persisted_logs.staged_log_hash());
+ EXPECT_EQ(persisted_logs.staged_log_timestamp(),
+ result_persisted_logs.staged_log_timestamp());
}
// Store a set of logs over the length limit, but smaller than the min number of
diff --git a/chromium/components/metrics/profiler/profiler_metrics_provider.cc b/chromium/components/metrics/profiler/profiler_metrics_provider.cc
index df64e293aee..2ab8c0314f6 100644
--- a/chromium/components/metrics/profiler/profiler_metrics_provider.cc
+++ b/chromium/components/metrics/profiler/profiler_metrics_provider.cc
@@ -107,7 +107,8 @@ void ProfilerMetricsProvider::RecordProfilerData(
if (IsCellularLogicEnabled())
return;
- const bool new_phase = !ContainsKey(profiler_events_cache_, profiling_phase);
+ const bool new_phase =
+ !base::ContainsKey(profiler_events_cache_, profiling_phase);
ProfilerEventProto* profiler_event = &profiler_events_cache_[profiling_phase];
if (new_phase) {
diff --git a/chromium/components/metrics/profiler/tracking_synchronizer.cc b/chromium/components/metrics/profiler/tracking_synchronizer.cc
index 21ccb85f532..1dc8fa75db4 100644
--- a/chromium/components/metrics/profiler/tracking_synchronizer.cc
+++ b/chromium/components/metrics/profiler/tracking_synchronizer.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/tracked_objects.h"
diff --git a/chromium/components/metrics/profiler/tracking_synchronizer_unittest.cc b/chromium/components/metrics/profiler/tracking_synchronizer_unittest.cc
index 016315caf46..cae6cb208fe 100644
--- a/chromium/components/metrics/profiler/tracking_synchronizer_unittest.cc
+++ b/chromium/components/metrics/profiler/tracking_synchronizer_unittest.cc
@@ -120,8 +120,8 @@ class TestTrackingSynchronizer : public TrackingSynchronizer {
TEST(TrackingSynchronizerTest, ProfilerData) {
// Testing how TrackingSynchronizer reports 2 phases of profiling.
- auto clock = new base::SimpleTestTickClock(); // Will be owned by
- // |tracking_synchronizer|.
+ auto* clock = new base::SimpleTestTickClock(); // Will be owned by
+ // |tracking_synchronizer|.
clock->Advance(base::TimeDelta::FromMilliseconds(111));
scoped_refptr<TestTrackingSynchronizer> tracking_synchronizer =
diff --git a/chromium/components/metrics/proto/BUILD.gn b/chromium/components/metrics/proto/BUILD.gn
index 3271f184cdf..0afdeea21b7 100644
--- a/chromium/components/metrics/proto/BUILD.gn
+++ b/chromium/components/metrics/proto/BUILD.gn
@@ -4,12 +4,12 @@
import("//third_party/protobuf/proto_library.gni")
-# GYP version: components/
proto_library("proto") {
sources = [
"call_stack_profile.proto",
"cast_logs.proto",
"chrome_user_metrics_extension.proto",
+ "execution_context.proto",
"histogram_event.proto",
"memory_leak_report.proto",
"omnibox_event.proto",
diff --git a/chromium/components/metrics/proto/cast_logs.proto b/chromium/components/metrics/proto/cast_logs.proto
index 951dfb24767..987c4f5dde6 100644
--- a/chromium/components/metrics/proto/cast_logs.proto
+++ b/chromium/components/metrics/proto/cast_logs.proto
@@ -22,6 +22,7 @@ message CastLogsProto {
enum CastProductType {
CAST_PRODUCT_TYPE_UNKNOWN = 0;
CAST_PRODUCT_TYPE_CHROMECAST = 1;
+ CAST_PRODUCT_TYPE_TV = 2;
CAST_PRODUCT_TYPE_AUDIO = 3;
CAST_PRODUCT_TYPE_ANDROID_TV = 4;
}
@@ -50,7 +51,7 @@ message CastLogsProto {
// This message describes a detail sender device and sdk. Those are
// parsed from the user agent string sent from sender sdk during connection.
- // Next tag: 9
+ // Next tag: 10
message SenderInfo {
// The identifier for the sender device, that is not tied any kind of
// device id outside of UMA, and this id is reset when user resets sender
@@ -107,6 +108,11 @@ message CastLogsProto {
// Sender device model.
optional string model = 8;
+
+ // Last 2 bytes of the sender’s local IP addresses (both IP4/IP6) when
+ // the sender connected. This field stores ip fragment to last 2 bytes and
+ // first 2 bytes won't be used.
+ optional int32 sender_local_ip_fragment = 9;
}
optional SenderInfo sender_info = 3;
}
@@ -115,7 +121,7 @@ message CastLogsProto {
repeated CastConnectionInfo cast_connection_info = 2;
// Stores Cast-enabled device specific events with a various context data.
- // Next tag: 10
+ // Next tag: 12
message CastEventProto {
// The name of the action, hashed by same logic used to hash user action
// event and histogram.
@@ -147,6 +153,10 @@ message CastLogsProto {
// An optional value for the multi-room group uuid.
optional fixed64 group_uuid = 10;
+
+ // For application events associated with an assistant session, identifies
+ // the assistant conversation.
+ optional string conversation_key = 11;
}
repeated CastEventProto cast_event = 3;
@@ -173,6 +183,10 @@ message CastLogsProto {
// System version which the cast_shell is running.
optional fixed64 system_build_number = 2;
+
+ // An identifier that is specific to the combination of app and device, in
+ // this case the one used by backdrop.
+ optional string backdrop_app_device_id = 3;
}
optional CastDeviceMutableInfo cast_device_mutable_info = 5;
diff --git a/chromium/components/metrics/proto/chrome_user_metrics_extension.proto b/chromium/components/metrics/proto/chrome_user_metrics_extension.proto
index 8b82933ab77..4b9bf68be16 100644
--- a/chromium/components/metrics/proto/chrome_user_metrics_extension.proto
+++ b/chromium/components/metrics/proto/chrome_user_metrics_extension.proto
@@ -31,6 +31,9 @@ message ChromeUserMetricsExtension {
// UMA metrics from Android Webview.
ANDROID_WEBVIEW = 20;
+
+ // Cast receivers, e.g. Chromecast
+ CAST = 35;
}
// The product corresponding to this log. The field type is int32 instead of
// Product so that downstream users of the Chromium metrics component can
diff --git a/chromium/components/metrics/proto/execution_context.proto b/chromium/components/metrics/proto/execution_context.proto
new file mode 100644
index 00000000000..3d8679fe9db
--- /dev/null
+++ b/chromium/components/metrics/proto/execution_context.proto
@@ -0,0 +1,49 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option java_outer_classname = "ExecutionContextProtos";
+option java_package = "org.chromium.components.metrics";
+
+package metrics;
+
+// Enums corresponding to the Chrome execution context in which data was
+// collected.
+
+// Chrome process type. Derived from content/public/common/process_type.h.
+enum Process {
+ UNKNOWN_PROCESS = 0;
+ BROWSER_PROCESS = 1;
+ RENDERER_PROCESS = 2;
+ GPU_PROCESS = 3;
+ UTILITY_PROCESS = 4;
+ ZYGOTE_PROCESS = 5;
+ SANDBOX_HELPER_PROCESS = 6;
+ PPAPI_PLUGIN_PROCESS = 7;
+ PPAPI_BROKER_PROCESS = 8;
+}
+
+// Chrome thread. This list is not exhaustive.
+enum Thread {
+ UNKNOWN_THREAD = 0;
+
+ // Browser process threads from content/public/browser/browser_thread.h,
+ // some of which occur in other processes as well.
+ UI_THREAD = 1;
+ FILE_THREAD = 2;
+ FILE_USER_BLOCKING_THREAD = 3;
+ PROCESS_LAUNCHER_THREAD = 4;
+ CACHE_THREAD = 5;
+ IO_THREAD = 6;
+ DB_THREAD = 7;
+
+ // GPU process thread.
+ GPU_MAIN_THREAD = 8;
+
+ // Renderer process threads.
+ RENDER_THREAD = 9;
+ UTILITY_THREAD = 10;
+}
diff --git a/chromium/components/metrics/proto/memory_leak_report.proto b/chromium/components/metrics/proto/memory_leak_report.proto
index bbd2dbc7a66..1a998fefa0b 100644
--- a/chromium/components/metrics/proto/memory_leak_report.proto
+++ b/chromium/components/metrics/proto/memory_leak_report.proto
@@ -8,7 +8,7 @@ option optimize_for = LITE_RUNTIME;
package metrics;
-// Next tag: 6
+// Next tag: 10
message MemoryLeakReportProto {
// The call stack at which the leak was found. This is a list of offsets
// within the program binary. The first entry is the deepest level of the call
@@ -69,6 +69,12 @@ message MemoryLeakReportProto {
}
optional ProcessType source_process = 5;
+ // The build ID of the Chrome binary from which this leak report was obtained.
+ // The build ID is typically a 16- or 20-byte hash that is generated by the
+ // compiler that built the binary. This value will be read directly from the
+ // GNU build notes section of the Chrome binary.
+ optional bytes build_id = 6;
+
//////////////////////////////////////////////////////////////////////////////
// Represents a single snapshot of the internal bookkeeping of the Runtime
@@ -96,4 +102,39 @@ message MemoryLeakReportProto {
// allocation. The oldest record is at the beginning. The most recent record,
// taken at the time the report was generated, is at the end.
repeated AllocationBreakdown alloc_breakdown_history = 4;
+
+ // The following two fields describe the last increasing trend in the number
+ // of allocations from the size and call stack that generated this
+ // leak report.
+ //
+ // |num_rising_intervals| equals timeslot_now - timeslot_drop,
+ // where timeslot_drop is the timeslot number of the last frame that saw
+ // a drop in the number of allocations (or 0 if there were no drops).
+ // If it is < 32, it will be visible in the allocation history graph.
+ // If it is >= 32, it will not be seen in the graph.
+ // E.g. for history [3,2,4,4,7] |num_rising_intervals| equals 3.
+ optional uint32 num_rising_intervals = 7;
+
+ // Indicates the magnitude of the current uptrend in allocations.
+ // E.g. for history [3,2,4,4,7] |num_allocs_increase| equals 5.
+ optional uint32 num_allocs_increase = 8;
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Contains additional data about the memory usage from the OS.
+ // There is no need to store the total system memory as it is
+ // available under SystemProfileProto::Hardware::system_ram_mb.
+ //
+ // Next tag: 3
+ message MemoryUsageInfo {
+ // How much available physical memory the system has.
+ optional uint64 available_ram_mb = 1;
+
+ // Total private working set memory across all Chrome processes.
+ optional uint64 chrome_ram_usage_mb = 2;
+ }
+
+ // Information about the memory usage from the OS collected right after
+ // the leak report was created in the leak detector.
+ optional MemoryUsageInfo memory_usage_info = 9;
}
diff --git a/chromium/components/metrics/proto/omnibox_event.proto b/chromium/components/metrics/proto/omnibox_event.proto
index 5d4f7199657..2f8f24da94f 100644
--- a/chromium/components/metrics/proto/omnibox_event.proto
+++ b/chromium/components/metrics/proto/omnibox_event.proto
@@ -111,10 +111,8 @@ message OmniboxEventProto {
// The instant new tab page enum value was deprecated on August 2, 2013.
OBSOLETE_INSTANT_NTP = 5;
- // The user is on a search result page that's doing search term
- // replacement, meaning the search terms should've appeared in the omnibox
- // before the user started editing it, not the URL of the page.
- SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT = 6;
+ // The search term replacement enum value was deprecated in August 2016.
+ OBSOLETE_SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT = 6;
// The new tab page in which this omnibox interaction first started
// with the user having focus in the omnibox.
@@ -168,6 +166,8 @@ message OmniboxEventProto {
// a suggestion powered by a Chrome content provider.
ON_DEVICE_CHROME = 13;
CLIPBOARD_URL = 14; // Suggestion coming from clipboard (iOS only).
+ PHYSICAL_WEB = 15; // Suggestions triggered by URLs broadcast by nearby
+ // devices (iOS only).
}
// The result set displayed on the completion popup
@@ -226,6 +226,9 @@ message OmniboxEventProto {
// suggestions of any type.
CALCULATOR = 23; // A calculator answer.
CLIPBOARD = 24; // An URL based on the clipboard.
+ PHYSICAL_WEB = 25; // A Physical Web nearby URL.
+ PHYSICAL_WEB_OVERFLOW = 26; // An item representing multiple Physical
+ // Web nearby URLs.
}
optional ResultType result_type = 2;
diff --git a/chromium/components/metrics/proto/sampled_profile.proto b/chromium/components/metrics/proto/sampled_profile.proto
index b8936e114c6..0d8fcae42b5 100644
--- a/chromium/components/metrics/proto/sampled_profile.proto
+++ b/chromium/components/metrics/proto/sampled_profile.proto
@@ -11,13 +11,14 @@ option java_package = "org.chromium.components.metrics";
package metrics;
import "call_stack_profile.proto";
+import "execution_context.proto";
import "perf_data.proto";
import "perf_stat.proto";
// Protocol buffer for collected sample-based profiling data.
// Contains the parameters and data from a single profile collection event.
-// Next tag: 11
+// Next tag: 13
message SampledProfile {
// Indicates the event that triggered this collection.
enum TriggerEvent {
@@ -35,7 +36,7 @@ message SampledProfile {
// The profile was collected upon restoring a previous session.
RESTORE_SESSION = 3;
-
+
// The profile was collected at process startup.
PROCESS_STARTUP = 4;
@@ -47,6 +48,12 @@ message SampledProfile {
}
optional TriggerEvent trigger_event = 1;
+ // The process in which the profile was collected.
+ optional Process process = 11;
+
+ // The thread in which the profile was collected.
+ optional Thread thread = 12;
+
// Fields 2-3: Time durations are given in ticks, and represent system uptime
// rather than wall time.
diff --git a/chromium/components/metrics/proto/system_profile.proto b/chromium/components/metrics/proto/system_profile.proto
index d814b3597fe..c116a0a1d19 100644
--- a/chromium/components/metrics/proto/system_profile.proto
+++ b/chromium/components/metrics/proto/system_profile.proto
@@ -440,7 +440,7 @@ message SystemProfileProto {
// Figures that can be used to generate application stability metrics.
// All values are counts of events since the last time that these
// values were reported.
- // Next tag: 26
+ // Next tag: 28
message Stability {
// Total amount of time that the program was running, in seconds,
// since the last time a log was recorded, as measured using a client-side
@@ -458,17 +458,19 @@ message SystemProfileProto {
// This field was added for M-35.
optional int64 uptime_sec = 23;
- // Page loads along with renderer crashes, hangs and failed launches, since
- // page load count roughly corresponds to usage.
+ // Page loads along with renderer launches, crashes, hangs and failed
+ // launches, since page load count roughly corresponds to usage.
optional int32 page_load_count = 2;
optional int32 renderer_crash_count = 3;
optional int32 renderer_hang_count = 4;
optional int32 renderer_failed_launch_count = 24;
+ optional int32 renderer_launch_count = 26;
- // Number of renderer crashes and failed launches that were for extensions.
- // These are not counted in the renderer counts above.
+ // Number of renderer launches, crashes and failed launches that were for
+ // extensions. These are not counted in the renderer counts above.
optional int32 extension_renderer_crash_count = 5;
optional int32 extension_renderer_failed_launch_count = 25;
+ optional int32 extension_renderer_launch_count = 27;
// Number of non-renderer child process crashes.
optional int32 child_process_crash_count = 6;
@@ -602,10 +604,10 @@ message SystemProfileProto {
// be consistent between manufacturers.
optional int32 manufacture_week = 6;
- // Max horizontal resolution in pixels.
+ // Selected horizontal resolution in pixels.
optional int32 horizontal_resolution = 7;
- // Max vertical resolution in pixels.
+ // Selected vertical resolution in pixels.
optional int32 vertical_resolution = 8;
// Audio capabilities of the device.
@@ -651,7 +653,6 @@ message SystemProfileProto {
DIGITAL = 1;
}
optional OutputMode output_mode = 6;
-
}
repeated AudioDescription audio_description = 9;
@@ -704,6 +705,50 @@ message SystemProfileProto {
optional int32 num_aborted_unrecognized = 7;
}
repeated CECCommand cec_command = 13;
+
+ // Selected Frame rate
+ optional int32 frame_rate = 14;
+
+ // Selected color encoding.
+ enum ColorEncoding {
+ COLOR_ENCODING_UNKNOWN = 0;
+ COLOR_ENCODING_RGB = 1;
+ COLOR_ENCODING_YUV444 = 2;
+ COLOR_ENCODING_YUV422 = 3;
+ COLOR_ENCODING_YUV420 = 4;
+ }
+ optional ColorEncoding color_encoding = 15;
+
+ // Selected bit-depth.
+ optional int32 bit_depth = 16;
+
+ // Devices's max TMDS char rate.
+ optional int32 tmds = 17;
+
+ // HDR10 support.
+ optional bool hdr10_support = 18;
+
+ // Dolby vision support.
+ optional bool dolby_vision_support = 19;
+
+ // Supported EOTFs.
+ // EOTF support according to the spec:
+ // eotf_support & 0x1 -> SDR supported
+ // (eotf_support > 1) & 0x1 -> traditional HDR supported
+ // (eotf_support > 2) & 0x1 -> ST2084 supported
+ optional int32 eotf_support = 20;
+
+ // Supports YUV.
+ optional bool yuv_support = 21;
+
+ // Supports YUV_420.
+ optional bool yuv_420_support = 22;
+
+ // The maximum HDCP version supported by the sink.
+ optional int32 maximum_supported_hdcp_version = 23;
+
+ // The current HDCP version negotiated with the sink.
+ optional int32 current_hdcp_version = 24;
}
repeated ExternalAudioVideoDevice external_audio_video_device = 14;
diff --git a/chromium/components/metrics/public/cpp/BUILD.gn b/chromium/components/metrics/public/cpp/BUILD.gn
new file mode 100644
index 00000000000..ca2f05741c0
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+source_set("call_stack_unit_tests") {
+ testonly = true
+ sources = [
+ "call_stack_profile_struct_traits_unittest.cc",
+ ]
+
+ deps = [
+ "//base",
+ "//components/metrics/public/interfaces:call_stack_mojo_test_bindings",
+ "//mojo/public/cpp/bindings",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/metrics/public/cpp/OWNERS b/chromium/components/metrics/public/cpp/OWNERS
new file mode 100644
index 00000000000..154435234ea
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/OWNERS
@@ -0,0 +1,4 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/metrics/public/cpp/call_stack_profile.typemap b/chromium/components/metrics/public/cpp/call_stack_profile.typemap
new file mode 100644
index 00000000000..a12ba83f473
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/call_stack_profile.typemap
@@ -0,0 +1,26 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom =
+ "//components/metrics/public/interfaces/call_stack_profile_collector.mojom"
+public_headers = [
+ "//base/profiler/stack_sampling_profiler.h",
+ "//components/metrics/call_stack_profile_params.h",
+]
+traits_headers =
+ [ "//components/metrics/public/cpp/call_stack_profile_struct_traits.h" ]
+deps = [
+ "//base",
+ "//components/metrics:call_stack_profile_params",
+]
+type_mappings = [
+ "metrics.mojom.CallStackModule=base::StackSamplingProfiler::Module",
+ "metrics.mojom.CallStackFrame=base::StackSamplingProfiler::Frame",
+ "metrics.mojom.CallStackProfile=base::StackSamplingProfiler::CallStackProfile",
+ "metrics.mojom.CallStackProfileParams=metrics::CallStackProfileParams",
+ "metrics.mojom.Process=metrics::CallStackProfileParams::Process",
+ "metrics.mojom.SampleOrderingSpec=metrics::CallStackProfileParams::SampleOrderingSpec",
+ "metrics.mojom.Thread=metrics::CallStackProfileParams::Thread",
+ "metrics.mojom.Trigger=metrics::CallStackProfileParams::Trigger",
+]
diff --git a/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h
new file mode 100644
index 00000000000..6e200341c09
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h
@@ -0,0 +1,384 @@
+// 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.
+
+// Defines StructTraits specializations for translating between mojo types and
+// base::StackSamplingProfiler types, with data validity checks.
+
+#ifndef COMPONENTS_METRICS_CALL_STACK_PROFILE_STRUCT_TRAITS_H_
+#define COMPONENTS_METRICS_CALL_STACK_PROFILE_STRUCT_TRAITS_H_
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/profiler/stack_sampling_profiler.h"
+#include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<metrics::mojom::CallStackModuleDataView,
+ base::StackSamplingProfiler::Module> {
+ static uint64_t base_address(
+ const base::StackSamplingProfiler::Module& module) {
+ return module.base_address;
+ }
+ static const std::string& id(
+ const base::StackSamplingProfiler::Module& module) {
+ return module.id;
+ }
+ static const base::FilePath& filename(
+ const base::StackSamplingProfiler::Module& module) {
+ return module.filename;
+ }
+
+ static bool Read(metrics::mojom::CallStackModuleDataView data,
+ base::StackSamplingProfiler::Module* out) {
+ // Linux has the longest build id at 40 bytes.
+ static const size_t kMaxIDSize = 40;
+
+ std::string id;
+ base::FilePath filename;
+ if (!data.ReadId(&id) || id.size() > kMaxIDSize ||
+ !data.ReadFilename(&filename))
+ return false;
+
+ *out =
+ base::StackSamplingProfiler::Module(data.base_address(), id, filename);
+ return true;
+ }
+};
+
+template <>
+struct StructTraits<metrics::mojom::CallStackFrameDataView,
+ base::StackSamplingProfiler::Frame> {
+ static uint64_t instruction_pointer(
+ const base::StackSamplingProfiler::Frame& frame) {
+ return frame.instruction_pointer;
+ }
+ static uint64_t module_index(
+ const base::StackSamplingProfiler::Frame& frame) {
+ return frame.module_index ==
+ base::StackSamplingProfiler::Frame::kUnknownModuleIndex ?
+ static_cast<uint64_t>(-1) :
+ frame.module_index;
+ }
+
+ static bool Read(metrics::mojom::CallStackFrameDataView data,
+ base::StackSamplingProfiler::Frame* out) {
+ size_t module_index = data.module_index() == static_cast<uint64_t>(-1) ?
+ base::StackSamplingProfiler::Frame::kUnknownModuleIndex :
+ data.module_index();
+
+ // We can't know whether the module_index field is valid at this point since
+ // we don't have access to the number of modules here. This will be checked
+ // in CallStackProfile's Read function below.
+ *out = base::StackSamplingProfiler::Frame(data.instruction_pointer(),
+ module_index);
+ return true;
+ }
+};
+
+template <>
+struct StructTraits<metrics::mojom::CallStackProfileDataView,
+ base::StackSamplingProfiler::CallStackProfile> {
+ static const std::vector<base::StackSamplingProfiler::Module>& modules(
+ const base::StackSamplingProfiler::CallStackProfile& profile) {
+ return profile.modules;
+ }
+ static const std::vector<base::StackSamplingProfiler::Sample>& samples(
+ const base::StackSamplingProfiler::CallStackProfile& profile) {
+ return profile.samples;
+ }
+ static const base::TimeDelta profile_duration(
+ const base::StackSamplingProfiler::CallStackProfile& profile) {
+ return profile.profile_duration;
+ }
+ static const base::TimeDelta sampling_period(
+ const base::StackSamplingProfiler::CallStackProfile& profile) {
+ return profile.sampling_period;
+ }
+
+ static bool ValidateSamples(
+ std::vector<base::StackSamplingProfiler::Sample> samples,
+ size_t module_count) {
+ for (const base::StackSamplingProfiler::Sample& sample : samples) {
+ for (const base::StackSamplingProfiler::Frame& frame : sample) {
+ if (frame.module_index >= module_count &&
+ frame.module_index !=
+ base::StackSamplingProfiler::Frame::kUnknownModuleIndex)
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static bool Read(metrics::mojom::CallStackProfileDataView data,
+ base::StackSamplingProfiler::CallStackProfile* out) {
+ std::vector<base::StackSamplingProfiler::Module> modules;
+ std::vector<base::StackSamplingProfiler::Sample> samples;
+ base::TimeDelta profile_duration, sampling_period;
+ if (!data.ReadModules(&modules) || !data.ReadSamples(&samples) ||
+ !data.ReadProfileDuration(&profile_duration) ||
+ !data.ReadSamplingPeriod(&sampling_period) ||
+ !ValidateSamples(samples, modules.size()))
+ return false;
+
+ *out = base::StackSamplingProfiler::CallStackProfile();
+ out->modules = std::move(modules);
+ out->samples = std::move(samples);
+ out->profile_duration = profile_duration;
+ out->sampling_period = sampling_period;
+ return true;
+ }
+};
+
+template <>
+struct EnumTraits<metrics::mojom::Process,
+ metrics::CallStackProfileParams::Process> {
+ static metrics::mojom::Process ToMojom(
+ metrics::CallStackProfileParams::Process process) {
+ switch (process) {
+ case metrics::CallStackProfileParams::Process::UNKNOWN_PROCESS:
+ return metrics::mojom::Process::UNKNOWN_PROCESS;
+ case metrics::CallStackProfileParams::Process::BROWSER_PROCESS:
+ return metrics::mojom::Process::BROWSER_PROCESS;
+ case metrics::CallStackProfileParams::Process::RENDERER_PROCESS:
+ return metrics::mojom::Process::RENDERER_PROCESS;
+ case metrics::CallStackProfileParams::Process::GPU_PROCESS:
+ return metrics::mojom::Process::GPU_PROCESS;
+ case metrics::CallStackProfileParams::Process::UTILITY_PROCESS:
+ return metrics::mojom::Process::UTILITY_PROCESS;
+ case metrics::CallStackProfileParams::Process::ZYGOTE_PROCESS:
+ return metrics::mojom::Process::ZYGOTE_PROCESS;
+ case metrics::CallStackProfileParams::Process::SANDBOX_HELPER_PROCESS:
+ return metrics::mojom::Process::SANDBOX_HELPER_PROCESS;
+ case metrics::CallStackProfileParams::Process::PPAPI_PLUGIN_PROCESS:
+ return metrics::mojom::Process::PPAPI_PLUGIN_PROCESS;
+ case metrics::CallStackProfileParams::Process::PPAPI_BROKER_PROCESS:
+ return metrics::mojom::Process::PPAPI_BROKER_PROCESS;
+ }
+ NOTREACHED();
+ return metrics::mojom::Process::UNKNOWN_PROCESS;
+ }
+
+ static bool FromMojom(metrics::mojom::Process process,
+ metrics::CallStackProfileParams::Process* out) {
+ switch (process) {
+ case metrics::mojom::Process::UNKNOWN_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::UNKNOWN_PROCESS;
+ return true;
+ case metrics::mojom::Process::BROWSER_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::BROWSER_PROCESS;
+ return true;
+ case metrics::mojom::Process::RENDERER_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::RENDERER_PROCESS;
+ return true;
+ case metrics::mojom::Process::GPU_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::GPU_PROCESS;
+ return true;
+ case metrics::mojom::Process::UTILITY_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::UTILITY_PROCESS;
+ return true;
+ case metrics::mojom::Process::ZYGOTE_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::ZYGOTE_PROCESS;
+ return true;
+ case metrics::mojom::Process::SANDBOX_HELPER_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::SANDBOX_HELPER_PROCESS;
+ return true;
+ case metrics::mojom::Process::PPAPI_PLUGIN_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::PPAPI_PLUGIN_PROCESS;
+ return true;
+ case metrics::mojom::Process::PPAPI_BROKER_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::PPAPI_BROKER_PROCESS;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct EnumTraits<metrics::mojom::Thread,
+ metrics::CallStackProfileParams::Thread> {
+ static metrics::mojom::Thread ToMojom(
+ metrics::CallStackProfileParams::Thread thread) {
+ switch (thread) {
+ case metrics::CallStackProfileParams::Thread::UNKNOWN_THREAD:
+ return metrics::mojom::Thread::UNKNOWN_THREAD;
+ case metrics::CallStackProfileParams::Thread::UI_THREAD:
+ return metrics::mojom::Thread::UI_THREAD;
+ case metrics::CallStackProfileParams::Thread::FILE_THREAD:
+ return metrics::mojom::Thread::FILE_THREAD;
+ case metrics::CallStackProfileParams::Thread::FILE_USER_BLOCKING_THREAD:
+ return metrics::mojom::Thread::FILE_USER_BLOCKING_THREAD;
+ case metrics::CallStackProfileParams::Thread::PROCESS_LAUNCHER_THREAD:
+ return metrics::mojom::Thread::PROCESS_LAUNCHER_THREAD;
+ case metrics::CallStackProfileParams::Thread::CACHE_THREAD:
+ return metrics::mojom::Thread::CACHE_THREAD;
+ case metrics::CallStackProfileParams::Thread::IO_THREAD:
+ return metrics::mojom::Thread::IO_THREAD;
+ case metrics::CallStackProfileParams::Thread::DB_THREAD:
+ return metrics::mojom::Thread::DB_THREAD;
+ case metrics::CallStackProfileParams::Thread::GPU_MAIN_THREAD:
+ return metrics::mojom::Thread::GPU_MAIN_THREAD;
+ case metrics::CallStackProfileParams::Thread::RENDER_THREAD:
+ return metrics::mojom::Thread::RENDER_THREAD;
+ case metrics::CallStackProfileParams::Thread::UTILITY_THREAD:
+ return metrics::mojom::Thread::UTILITY_THREAD;
+ }
+ NOTREACHED();
+ return metrics::mojom::Thread::UNKNOWN_THREAD;
+ }
+
+ static bool FromMojom(metrics::mojom::Thread thread,
+ metrics::CallStackProfileParams::Thread* out) {
+ switch (thread) {
+ case metrics::mojom::Thread::UNKNOWN_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::UNKNOWN_THREAD;
+ return true;
+ case metrics::mojom::Thread::UI_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::UI_THREAD;
+ return true;
+ case metrics::mojom::Thread::FILE_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::FILE_THREAD;
+ return true;
+ case metrics::mojom::Thread::FILE_USER_BLOCKING_THREAD:
+ *out =
+ metrics::CallStackProfileParams::Thread::FILE_USER_BLOCKING_THREAD;
+ return true;
+ case metrics::mojom::Thread::PROCESS_LAUNCHER_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::PROCESS_LAUNCHER_THREAD;
+ return true;
+ case metrics::mojom::Thread::CACHE_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::CACHE_THREAD;
+ return true;
+ case metrics::mojom::Thread::IO_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::IO_THREAD;
+ return true;
+ case metrics::mojom::Thread::DB_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::DB_THREAD;
+ return true;
+ case metrics::mojom::Thread::GPU_MAIN_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::GPU_MAIN_THREAD;
+ return true;
+ case metrics::mojom::Thread::RENDER_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::RENDER_THREAD;
+ return true;
+ case metrics::mojom::Thread::UTILITY_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::UTILITY_THREAD;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct EnumTraits<metrics::mojom::Trigger,
+ metrics::CallStackProfileParams::Trigger> {
+ static metrics::mojom::Trigger ToMojom(
+ metrics::CallStackProfileParams::Trigger trigger) {
+ switch (trigger) {
+ case metrics::CallStackProfileParams::Trigger::UNKNOWN:
+ return metrics::mojom::Trigger::UNKNOWN;
+ case metrics::CallStackProfileParams::Trigger::PROCESS_STARTUP:
+ return metrics::mojom::Trigger::PROCESS_STARTUP;
+ case metrics::CallStackProfileParams::Trigger::JANKY_TASK:
+ return metrics::mojom::Trigger::JANKY_TASK;
+ case metrics::CallStackProfileParams::Trigger::THREAD_HUNG:
+ return metrics::mojom::Trigger::THREAD_HUNG;
+ }
+ NOTREACHED();
+ return metrics::mojom::Trigger::UNKNOWN;
+ }
+
+ static bool FromMojom(metrics::mojom::Trigger trigger,
+ metrics::CallStackProfileParams::Trigger* out) {
+ switch (trigger) {
+ case metrics::mojom::Trigger::UNKNOWN:
+ *out = metrics::CallStackProfileParams::Trigger::UNKNOWN;
+ return true;
+ case metrics::mojom::Trigger::PROCESS_STARTUP:
+ *out = metrics::CallStackProfileParams::Trigger::PROCESS_STARTUP;
+ return true;
+ case metrics::mojom::Trigger::JANKY_TASK:
+ *out = metrics::CallStackProfileParams::Trigger::JANKY_TASK;
+ return true;
+ case metrics::mojom::Trigger::THREAD_HUNG:
+ *out = metrics::CallStackProfileParams::Trigger::THREAD_HUNG;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct StructTraits<metrics::mojom::CallStackProfileParamsDataView,
+ metrics::CallStackProfileParams> {
+ static metrics::CallStackProfileParams::Process process(
+ const metrics::CallStackProfileParams& params) {
+ return params.process;
+ }
+ static metrics::CallStackProfileParams::Thread thread(
+ const metrics::CallStackProfileParams& params) {
+ return params.thread;
+ }
+ static metrics::CallStackProfileParams::Trigger trigger(
+ const metrics::CallStackProfileParams& params) {
+ return params.trigger;
+ }
+ static metrics::CallStackProfileParams::SampleOrderingSpec ordering_spec(
+ const metrics::CallStackProfileParams& params) {
+ return params.ordering_spec;
+ }
+
+ static bool Read(metrics::mojom::CallStackProfileParamsDataView data,
+ metrics::CallStackProfileParams* out) {
+ metrics::CallStackProfileParams::Process process;
+ metrics::CallStackProfileParams::Thread thread;
+ metrics::CallStackProfileParams::Trigger trigger;
+ metrics::CallStackProfileParams::SampleOrderingSpec ordering_spec;
+ if (!data.ReadProcess(&process) || !data.ReadThread(&thread) ||
+ !data.ReadTrigger(&trigger) || !data.ReadOrderingSpec(&ordering_spec)) {
+ return false;
+ }
+ *out = metrics::CallStackProfileParams(process, thread, trigger,
+ ordering_spec);
+ return true;
+ }
+};
+
+template <>
+struct EnumTraits<metrics::mojom::SampleOrderingSpec,
+ metrics::CallStackProfileParams::SampleOrderingSpec> {
+
+ static metrics::mojom::SampleOrderingSpec ToMojom(
+ metrics::CallStackProfileParams::SampleOrderingSpec spec) {
+ switch (spec) {
+ case metrics::CallStackProfileParams::SampleOrderingSpec::MAY_SHUFFLE:
+ return metrics::mojom::SampleOrderingSpec::MAY_SHUFFLE;
+ case metrics::CallStackProfileParams::SampleOrderingSpec::PRESERVE_ORDER:
+ return metrics::mojom::SampleOrderingSpec::PRESERVE_ORDER;
+ }
+ NOTREACHED();
+ return metrics::mojom::SampleOrderingSpec::MAY_SHUFFLE;
+ }
+
+ static bool FromMojom(
+ metrics::mojom::SampleOrderingSpec spec,
+ metrics::CallStackProfileParams::SampleOrderingSpec* out) {
+ switch (spec) {
+ case metrics::mojom::SampleOrderingSpec::MAY_SHUFFLE:
+ *out = metrics::CallStackProfileParams::SampleOrderingSpec::MAY_SHUFFLE;
+ return true;
+ case metrics::mojom::SampleOrderingSpec::PRESERVE_ORDER:
+ *out =
+ metrics::CallStackProfileParams::SampleOrderingSpec::PRESERVE_ORDER;
+ return true;
+ }
+ return false;
+ }
+};
+
+} // mojo
+
+#endif // COMPONENTS_METRICS_CALL_STACK_PROFILE_STRUCT_TRAITS_H_
diff --git a/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc
new file mode 100644
index 00000000000..14db487f452
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc
@@ -0,0 +1,402 @@
+// 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 <utility>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "components/metrics/public/interfaces/call_stack_profile_collector_test.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+
+namespace {
+
+base::StackSamplingProfiler::CallStackProfile CreateProfile(
+ const std::vector<base::StackSamplingProfiler::Module>& modules,
+ const std::vector<base::StackSamplingProfiler::Sample>& samples,
+ base::TimeDelta profile_duration,
+ base::TimeDelta sampling_period) {
+ base::StackSamplingProfiler::CallStackProfile profile;
+ profile.modules = modules;
+ profile.samples = samples;
+ profile.profile_duration = profile_duration;
+ profile.sampling_period = sampling_period;
+ return profile;
+}
+
+}
+
+class CallStackProfileCollectorTestImpl
+ : public mojom::CallStackProfileCollectorTest {
+ public:
+ explicit CallStackProfileCollectorTestImpl(
+ mojo::InterfaceRequest<mojom::CallStackProfileCollectorTest> request)
+ : binding_(this, std::move(request)) {
+ }
+
+ // CallStackProfileCollectorTest:
+ void BounceFrame(const base::StackSamplingProfiler::Frame& in,
+ const BounceFrameCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceModule(const base::StackSamplingProfiler::Module& in,
+ const BounceModuleCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceProfile(const base::StackSamplingProfiler::CallStackProfile& in,
+ const BounceProfileCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceTrigger(CallStackProfileParams::Trigger in,
+ const BounceTriggerCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceProcess(CallStackProfileParams::Process in,
+ const BounceProcessCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceThread(CallStackProfileParams::Thread in,
+ const BounceThreadCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceSampleOrderingSpec(
+ CallStackProfileParams::SampleOrderingSpec in,
+ const BounceSampleOrderingSpecCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceCallStackProfileParams(
+ const CallStackProfileParams& in,
+ const BounceCallStackProfileParamsCallback& callback) override {
+ callback.Run(in);
+ }
+
+ private:
+ mojo::Binding<CallStackProfileCollectorTest> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallStackProfileCollectorTestImpl);
+};
+
+class CallStackProfileStructTraitsTest : public testing::Test {
+ public:
+ CallStackProfileStructTraitsTest() : impl_(GetProxy(&proxy_)) {}
+
+ protected:
+ base::MessageLoop message_loop_;
+ mojom::CallStackProfileCollectorTestPtr proxy_;
+ CallStackProfileCollectorTestImpl impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallStackProfileStructTraitsTest);
+};
+
+// Checks serialization/deserialization of Module fields.
+TEST_F(CallStackProfileStructTraitsTest, Module) {
+ using Module = base::StackSamplingProfiler::Module;
+
+ struct SerializeCase {
+ Module module;
+ bool expect_success;
+ };
+
+ const SerializeCase serialize_cases[] = {
+ // Null base address.
+ {
+ Module(0x0, "abcd", base::FilePath(base::FilePath::kCurrentDirectory)),
+ true
+ },
+ // Non-null base address.
+ {
+ Module(0x10, "abcd", base::FilePath(base::FilePath::kCurrentDirectory)),
+ true
+ },
+ // Base address with a bit set beyond 32 bits, when built for x64.
+ {
+ Module(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, "abcd",
+ base::FilePath(base::FilePath::kCurrentDirectory)),
+ true
+ },
+ // Empty module id.
+ {
+ Module(0x10, "", base::FilePath(base::FilePath::kCurrentDirectory)),
+ true
+ },
+ // Module id at the length limit.
+ {
+ Module(0x10, std::string(40, ' '),
+ base::FilePath(base::FilePath::kCurrentDirectory)),
+ true
+ },
+ // Module id beyond the length limit.
+ {
+ Module(0x10, std::string(41, ' '),
+ base::FilePath(base::FilePath::kCurrentDirectory)),
+ false
+ },
+ };
+
+ for (const SerializeCase& input : serialize_cases) {
+ Module output;
+ EXPECT_EQ(input.expect_success,
+ proxy_->BounceModule(input.module, &output));
+
+ if (!input.expect_success)
+ continue;
+
+ EXPECT_EQ(input.module.base_address, output.base_address);
+ EXPECT_EQ(input.module.id, output.id);
+ EXPECT_EQ(input.module.filename, output.filename);
+ }
+}
+
+// Checks serialization/deserialization of Frame fields.
+TEST_F(CallStackProfileStructTraitsTest, Frame) {
+ using Frame = base::StackSamplingProfiler::Frame;
+
+ const Frame serialize_cases[] = {
+ // Null instruction pointer.
+ Frame(0x0, 10),
+ // Non-null instruction pointer.
+ Frame(0x10, 10),
+ // Instruction pointer with a bit set beyond 32 bits, when built for x64.
+ Frame(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, 10),
+ // Zero module index.
+ Frame(0xabcd, 0),
+ // Non-zero module index.
+ Frame(0xabcd, 1),
+ // Non-zero module index.
+ Frame(0xabcd, 10),
+ // Unknown module index.
+ Frame(0xabcd, Frame::kUnknownModuleIndex),
+ };
+
+ for (const Frame& input : serialize_cases) {
+ Frame output;
+ EXPECT_TRUE(proxy_->BounceFrame(input, &output));
+
+ EXPECT_EQ(input.instruction_pointer, output.instruction_pointer);
+ EXPECT_EQ(input.module_index, output.module_index);
+ }
+}
+
+// Checks serialization/deserialization of Profile fields, including validation
+// of the Frame module_index field.
+TEST_F(CallStackProfileStructTraitsTest, Profile) {
+ using Module = base::StackSamplingProfiler::Module;
+ using Frame = base::StackSamplingProfiler::Frame;
+ using Sample = base::StackSamplingProfiler::Sample;
+ using Profile = base::StackSamplingProfiler::CallStackProfile;
+
+ struct SerializeCase {
+ Profile profile;
+ bool expect_success;
+ };
+
+ const SerializeCase serialize_cases[] = {
+ // Empty modules and samples.
+ {
+ CreateProfile(std::vector<Module>(), std::vector<Sample>(),
+ base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromSeconds(2)),
+ true
+ },
+ // Non-empty modules and empty samples.
+ {
+ CreateProfile({ Module(0x4000, "a", base::FilePath()) },
+ std::vector<Sample>(),
+ base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromSeconds(2)),
+ true
+ },
+ // Valid values for modules and samples.
+ {
+ CreateProfile({
+ Module(0x4000, "a", base::FilePath()),
+ Module(0x4100, "b", base::FilePath()),
+ },
+ {
+ {
+ Frame(0x4010, 0),
+ Frame(0x4110, 1),
+ Frame(0x4110, Frame::kUnknownModuleIndex),
+ }
+ },
+ base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromSeconds(2)),
+ true
+ },
+ // Valid values for modules, but an out of range module index in the second
+ // sample.
+ {
+ CreateProfile({
+ Module(0x4000, "a", base::FilePath()),
+ Module(0x4100, "b", base::FilePath()),
+ },
+ {
+ {
+ Frame(0x4010, 0),
+ Frame(0x4110, 1),
+ Frame(0x4110, Frame::kUnknownModuleIndex),
+ },
+ {
+ Frame(0x4010, 0),
+ Frame(0x4110, 2),
+ },
+ },
+ base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromSeconds(2)),
+ false
+ },
+ };
+
+ for (const SerializeCase& input : serialize_cases) {
+ SCOPED_TRACE(&input - &serialize_cases[0]);
+
+ Profile output;
+ EXPECT_EQ(input.expect_success,
+ proxy_->BounceProfile(input.profile, &output));
+
+ if (!input.expect_success)
+ continue;
+
+ EXPECT_EQ(input.profile.modules, output.modules);
+ EXPECT_EQ(input.profile.samples, output.samples);
+ EXPECT_EQ(input.profile.profile_duration, output.profile_duration);
+ EXPECT_EQ(input.profile.sampling_period, output.sampling_period);
+ }
+}
+
+// Checks serialization/deserialization of the process, including validation.
+TEST_F(CallStackProfileStructTraitsTest, Process) {
+ using Process = CallStackProfileParams::Process;
+
+ Process out;
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::UNKNOWN_PROCESS, &out));
+ EXPECT_EQ(Process::UNKNOWN_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::BROWSER_PROCESS, &out));
+ EXPECT_EQ(Process::BROWSER_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::RENDERER_PROCESS, &out));
+ EXPECT_EQ(Process::RENDERER_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::GPU_PROCESS, &out));
+ EXPECT_EQ(Process::GPU_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::UTILITY_PROCESS, &out));
+ EXPECT_EQ(Process::UTILITY_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::ZYGOTE_PROCESS, &out));
+ EXPECT_EQ(Process::ZYGOTE_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::SANDBOX_HELPER_PROCESS, &out));
+ EXPECT_EQ(Process::SANDBOX_HELPER_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::PPAPI_PLUGIN_PROCESS, &out));
+ EXPECT_EQ(Process::PPAPI_PLUGIN_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::PPAPI_BROKER_PROCESS, &out));
+ EXPECT_EQ(Process::PPAPI_BROKER_PROCESS, out);
+}
+
+// Checks serialization/deserialization of the thread, including validation.
+TEST_F(CallStackProfileStructTraitsTest, Thread) {
+ using Thread = CallStackProfileParams::Thread;
+
+ Thread out;
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::UI_THREAD, &out));
+ EXPECT_EQ(Thread::UI_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::FILE_THREAD, &out));
+ EXPECT_EQ(Thread::FILE_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::FILE_USER_BLOCKING_THREAD, &out));
+ EXPECT_EQ(Thread::FILE_USER_BLOCKING_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::PROCESS_LAUNCHER_THREAD, &out));
+ EXPECT_EQ(Thread::PROCESS_LAUNCHER_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::CACHE_THREAD, &out));
+ EXPECT_EQ(Thread::CACHE_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::IO_THREAD, &out));
+ EXPECT_EQ(Thread::IO_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::DB_THREAD, &out));
+ EXPECT_EQ(Thread::DB_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::GPU_MAIN_THREAD, &out));
+ EXPECT_EQ(Thread::GPU_MAIN_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::RENDER_THREAD, &out));
+ EXPECT_EQ(Thread::RENDER_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::UTILITY_THREAD, &out));
+ EXPECT_EQ(Thread::UTILITY_THREAD, out);
+}
+
+// Checks serialization/deserialization of the trigger, including validation.
+TEST_F(CallStackProfileStructTraitsTest, Trigger) {
+ using Trigger = CallStackProfileParams::Trigger;
+
+ Trigger out;
+
+ EXPECT_TRUE(proxy_->BounceTrigger(Trigger::UNKNOWN, &out));
+ EXPECT_EQ(Trigger::UNKNOWN, out);
+
+ EXPECT_TRUE(proxy_->BounceTrigger(Trigger::PROCESS_STARTUP, &out));
+ EXPECT_EQ(Trigger::PROCESS_STARTUP, out);
+
+ EXPECT_TRUE(proxy_->BounceTrigger(Trigger::JANKY_TASK, &out));
+ EXPECT_EQ(Trigger::JANKY_TASK, out);
+
+ EXPECT_TRUE(proxy_->BounceTrigger(Trigger::THREAD_HUNG, &out));
+ EXPECT_EQ(Trigger::THREAD_HUNG, out);
+}
+
+// Checks serialization/deserialization of the SampleOrderingSpec, including
+// validation.
+TEST_F(CallStackProfileStructTraitsTest, SampleOrderingSpec) {
+ using SampleOrderingSpec = CallStackProfileParams::SampleOrderingSpec;
+
+ SampleOrderingSpec out;
+
+ EXPECT_TRUE(proxy_->BounceSampleOrderingSpec(SampleOrderingSpec::MAY_SHUFFLE,
+ &out));
+ EXPECT_EQ(SampleOrderingSpec::MAY_SHUFFLE, out);
+
+ EXPECT_TRUE(proxy_->BounceSampleOrderingSpec(
+ SampleOrderingSpec::PRESERVE_ORDER,
+ &out));
+ EXPECT_EQ(SampleOrderingSpec::PRESERVE_ORDER, out);
+}
+
+// Checks serialization/deserialization of the CallStackProfileParams.
+TEST_F(CallStackProfileStructTraitsTest, CallStackProfileParams) {
+ CallStackProfileParams out;
+
+ EXPECT_TRUE(proxy_->BounceCallStackProfileParams(
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::PRESERVE_ORDER),
+ &out));
+
+ EXPECT_EQ(CallStackProfileParams::BROWSER_PROCESS, out.process);
+ EXPECT_EQ(CallStackProfileParams::UI_THREAD, out.thread);
+ EXPECT_EQ(CallStackProfileParams::PROCESS_STARTUP, out.trigger);
+ EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER, out.ordering_spec);
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/public/cpp/typemaps.gni b/chromium/components/metrics/public/cpp/typemaps.gni
new file mode 100644
index 00000000000..079917f788c
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/typemaps.gni
@@ -0,0 +1,5 @@
+# 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.
+
+typemaps = [ "//components/metrics/public/cpp/call_stack_profile.typemap" ]
diff --git a/chromium/components/metrics/public/interfaces/BUILD.gn b/chromium/components/metrics/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..c6db51a6cf5
--- /dev/null
+++ b/chromium/components/metrics/public/interfaces/BUILD.gn
@@ -0,0 +1,26 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("call_stack_mojo_bindings") {
+ sources = [
+ "call_stack_profile_collector.mojom",
+ ]
+
+ deps = [
+ "//mojo/common:common_custom_types",
+ ]
+}
+
+mojom("call_stack_mojo_test_bindings") {
+ sources = [
+ "call_stack_profile_collector_test.mojom",
+ ]
+
+ deps = [
+ ":call_stack_mojo_bindings",
+ "//mojo/common:common_custom_types",
+ ]
+}
diff --git a/chromium/components/metrics/public/interfaces/OWNERS b/chromium/components/metrics/public/interfaces/OWNERS
new file mode 100644
index 00000000000..154435234ea
--- /dev/null
+++ b/chromium/components/metrics/public/interfaces/OWNERS
@@ -0,0 +1,4 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom b/chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom
new file mode 100644
index 00000000000..6c8f04216c6
--- /dev/null
+++ b/chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom
@@ -0,0 +1,81 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module metrics.mojom;
+
+import "mojo/common/common_custom_types.mojom";
+
+// These structs mirror the corresponding types in base::StackSamplingProfiler.
+
+struct CallStackModule {
+ uint64 base_address;
+ string id;
+ mojo.common.mojom.FilePath filename;
+};
+
+struct CallStackFrame {
+ uint64 instruction_pointer;
+ uint64 module_index;
+};
+
+struct CallStackProfile {
+ array<CallStackModule> modules;
+ array<array<CallStackFrame>> samples;
+ mojo.common.mojom.TimeDelta profile_duration;
+ mojo.common.mojom.TimeDelta sampling_period;
+};
+
+enum Process {
+ UNKNOWN_PROCESS,
+ BROWSER_PROCESS,
+ RENDERER_PROCESS,
+ GPU_PROCESS,
+ UTILITY_PROCESS,
+ ZYGOTE_PROCESS,
+ SANDBOX_HELPER_PROCESS,
+ PPAPI_PLUGIN_PROCESS,
+ PPAPI_BROKER_PROCESS,
+};
+
+enum Thread {
+ UNKNOWN_THREAD,
+
+ UI_THREAD,
+ FILE_THREAD,
+ FILE_USER_BLOCKING_THREAD,
+ PROCESS_LAUNCHER_THREAD,
+ CACHE_THREAD,
+ IO_THREAD,
+ DB_THREAD,
+
+ GPU_MAIN_THREAD,
+
+ RENDER_THREAD,
+ UTILITY_THREAD,
+};
+
+enum Trigger {
+ UNKNOWN,
+ PROCESS_STARTUP,
+ JANKY_TASK,
+ THREAD_HUNG,
+};
+
+enum SampleOrderingSpec {
+ MAY_SHUFFLE,
+ PRESERVE_ORDER,
+};
+
+struct CallStackProfileParams {
+ Process process;
+ Thread thread;
+ Trigger trigger;
+ SampleOrderingSpec ordering_spec;
+};
+
+interface CallStackProfileCollector {
+ Collect(CallStackProfileParams params,
+ mojo.common.mojom.TimeTicks start_timestamp,
+ array<CallStackProfile> profiles);
+};
diff --git a/chromium/components/metrics/public/interfaces/call_stack_profile_collector_test.mojom b/chromium/components/metrics/public/interfaces/call_stack_profile_collector_test.mojom
new file mode 100644
index 00000000000..2c7f1c1471a
--- /dev/null
+++ b/chromium/components/metrics/public/interfaces/call_stack_profile_collector_test.mojom
@@ -0,0 +1,33 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module metrics.mojom;
+
+import "components/metrics/public/interfaces/call_stack_profile_collector.mojom";
+
+interface CallStackProfileCollectorTest {
+ [Sync]
+ BounceFrame(CallStackFrame in) => (CallStackFrame out);
+
+ [Sync]
+ BounceModule(CallStackModule in) => (CallStackModule out);
+
+ [Sync]
+ BounceProfile(CallStackProfile in) => (CallStackProfile out);
+
+ [Sync]
+ BounceProcess(Process in) => (Process out);
+
+ [Sync]
+ BounceThread(Thread in) => (Thread out);
+
+ [Sync]
+ BounceTrigger(Trigger in) => (Trigger out);
+
+ [Sync]
+ BounceSampleOrderingSpec(SampleOrderingSpec in) => (SampleOrderingSpec out);
+
+ [Sync]
+ BounceCallStackProfileParams(CallStackProfileParams in) => (CallStackProfileParams out);
+};
diff --git a/chromium/components/metrics/serialization/serialization_utils_unittest.cc b/chromium/components/metrics/serialization/serialization_utils_unittest.cc
index f3110166670..9d1e3602e34 100644
--- a/chromium/components/metrics/serialization/serialization_utils_unittest.cc
+++ b/chromium/components/metrics/serialization/serialization_utils_unittest.cc
@@ -22,7 +22,7 @@ class SerializationUtilsTest : public testing::Test {
SerializationUtilsTest() {
bool success = temporary_dir.CreateUniqueTempDir();
if (success) {
- base::FilePath dir_path = temporary_dir.path();
+ base::FilePath dir_path = temporary_dir.GetPath();
filename = dir_path.value() + "chromeossampletest";
filepath = base::FilePath(filename);
}
@@ -154,8 +154,8 @@ TEST_F(SerializationUtilsTest, WriteReadTest) {
ScopedVector<MetricSample> vect;
SerializationUtils::ReadAndTruncateMetricsFromFile(filename, &vect);
ASSERT_EQ(vect.size(), size_t(5));
- for (int i = 0; i < 5; i++) {
- ASSERT_TRUE(vect[0] != NULL);
+ for (MetricSample* sample : vect) {
+ ASSERT_NE(nullptr, sample);
}
EXPECT_TRUE(hist->IsEqual(*vect[0]));
EXPECT_TRUE(crash->IsEqual(*vect[1]));
diff --git a/chromium/components/metrics/stability_metrics_helper.cc b/chromium/components/metrics/stability_metrics_helper.cc
index 7b771f9f4d5..8c33f7773e5 100644
--- a/chromium/components/metrics/stability_metrics_helper.cc
+++ b/chromium/components/metrics/stability_metrics_helper.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "build/build_config.h"
#include "components/metrics/metrics_pref_names.h"
@@ -95,6 +95,12 @@ void StabilityMetricsHelper::ProvideStabilityMetrics(
local_state_->SetInteger(prefs::kStabilityRendererFailedLaunchCount, 0);
}
+ count = local_state_->GetInteger(prefs::kStabilityRendererLaunchCount);
+ if (count) {
+ stability_proto->set_renderer_launch_count(count);
+ local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
+ }
+
count =
local_state_->GetInteger(prefs::kStabilityExtensionRendererCrashCount);
if (count) {
@@ -115,6 +121,13 @@ void StabilityMetricsHelper::ProvideStabilityMetrics(
stability_proto->set_renderer_hang_count(count);
local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0);
}
+
+ count =
+ local_state_->GetInteger(prefs::kStabilityExtensionRendererLaunchCount);
+ if (count) {
+ stability_proto->set_extension_renderer_launch_count(count);
+ local_state_->SetInteger(prefs::kStabilityExtensionRendererLaunchCount, 0);
+ }
}
void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
@@ -124,10 +137,12 @@ void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
local_state_->SetInteger(prefs::kStabilityExtensionRendererFailedLaunchCount,
0);
+ local_state_->SetInteger(prefs::kStabilityExtensionRendererLaunchCount, 0);
local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
local_state_->SetInteger(prefs::kStabilityRendererCrashCount, 0);
local_state_->SetInteger(prefs::kStabilityRendererFailedLaunchCount, 0);
local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0);
+ local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
}
// static
@@ -137,10 +152,13 @@ void StabilityMetricsHelper::RegisterPrefs(PrefRegistrySimple* registry) {
0);
registry->RegisterIntegerPref(
prefs::kStabilityExtensionRendererFailedLaunchCount, 0);
+ registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererLaunchCount,
+ 0);
registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityRendererFailedLaunchCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0);
+ registry->RegisterIntegerPref(prefs::kStabilityRendererLaunchCount, 0);
registry->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0);
}
@@ -164,48 +182,73 @@ void StabilityMetricsHelper::LogRendererCrash(bool was_extension_process,
int exit_code) {
int histogram_type =
was_extension_process ? RENDERER_TYPE_EXTENSION : RENDERER_TYPE_RENDERER;
- if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
- status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
- if (was_extension_process) {
- IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
-
- UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
- MapCrashExitCodeForHistogram(exit_code));
- } else {
- IncrementPrefValue(prefs::kStabilityRendererCrashCount);
-
- UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
- MapCrashExitCodeForHistogram(exit_code));
- }
-
- UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildCrashes",
- histogram_type, RENDERER_TYPE_COUNT);
- } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
- RecordChildKills(histogram_type);
+
+ switch (status) {
+ case base::TERMINATION_STATUS_NORMAL_TERMINATION:
+ break;
+ case base::TERMINATION_STATUS_PROCESS_CRASHED:
+ case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
+ case base::TERMINATION_STATUS_OOM:
+ if (was_extension_process) {
+ IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
+
+ UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
+ MapCrashExitCodeForHistogram(exit_code));
+ } else {
+ IncrementPrefValue(prefs::kStabilityRendererCrashCount);
+
+ UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
+ MapCrashExitCodeForHistogram(exit_code));
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildCrashes",
+ histogram_type, RENDERER_TYPE_COUNT);
+ break;
+ case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
+ RecordChildKills(histogram_type);
+ break;
+#if defined(OS_ANDROID)
+ case base::TERMINATION_STATUS_OOM_PROTECTED:
+ // TODO(wfh): Check if this should be a Kill or a Crash on Android.
+ break;
+#endif
#if defined(OS_CHROMEOS)
- } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM) {
- RecordChildKills(histogram_type);
- UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills.OOM",
- was_extension_process ? 2 : 1, 3);
- RecordMemoryStats(was_extension_process
- ? RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED
- : RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED);
+ case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+ RecordChildKills(histogram_type);
+ UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills.OOM",
+ was_extension_process ? 2 : 1, 3);
+ RecordMemoryStats(was_extension_process
+ ? RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED
+ : RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED);
+ break;
#endif
- } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
- UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.DisconnectedAlive",
- histogram_type, RENDERER_TYPE_COUNT);
- } else if (status == base::TERMINATION_STATUS_LAUNCH_FAILED) {
- UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildLaunchFailures",
- histogram_type, RENDERER_TYPE_COUNT);
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- "BrowserRenderProcessHost.ChildLaunchFailureCodes", exit_code);
- if (was_extension_process)
- IncrementPrefValue(prefs::kStabilityExtensionRendererFailedLaunchCount);
- else
- IncrementPrefValue(prefs::kStabilityRendererFailedLaunchCount);
+ case base::TERMINATION_STATUS_STILL_RUNNING:
+ UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.DisconnectedAlive",
+ histogram_type, RENDERER_TYPE_COUNT);
+ break;
+ case base::TERMINATION_STATUS_LAUNCH_FAILED:
+ UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildLaunchFailures",
+ histogram_type, RENDERER_TYPE_COUNT);
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "BrowserRenderProcessHost.ChildLaunchFailureCodes", exit_code);
+ if (was_extension_process)
+ IncrementPrefValue(prefs::kStabilityExtensionRendererFailedLaunchCount);
+ else
+ IncrementPrefValue(prefs::kStabilityRendererFailedLaunchCount);
+ break;
+ case base::TERMINATION_STATUS_MAX_ENUM:
+ NOTREACHED();
+ break;
}
}
+void StabilityMetricsHelper::LogRendererLaunched(bool was_extension_process) {
+ if (was_extension_process)
+ IncrementPrefValue(prefs::kStabilityExtensionRendererLaunchCount);
+ else
+ IncrementPrefValue(prefs::kStabilityRendererLaunchCount);
+}
+
void StabilityMetricsHelper::IncrementPrefValue(const char* path) {
int value = local_state_->GetInteger(path);
local_state_->SetInteger(path, value + 1);
diff --git a/chromium/components/metrics/stability_metrics_helper.h b/chromium/components/metrics/stability_metrics_helper.h
index 42a9ca20217..87f8f400f19 100644
--- a/chromium/components/metrics/stability_metrics_helper.h
+++ b/chromium/components/metrics/stability_metrics_helper.h
@@ -36,10 +36,13 @@ class StabilityMetricsHelper {
void LogLoadStarted();
// Records a renderer process crash.
- void LogRendererCrash(bool was_exception_process,
+ void LogRendererCrash(bool was_extension_process,
base::TerminationStatus status,
int exit_code);
+ // Records that a new renderer process was successfully launched.
+ void LogRendererLaunched(bool was_extension_process);
+
// Records a renderer process hang.
void LogRendererHang();
diff --git a/chromium/components/metrics/stability_metrics_helper_unittest.cc b/chromium/components/metrics/stability_metrics_helper_unittest.cc
index d5aa9291a0c..018906d8a1c 100644
--- a/chromium/components/metrics/stability_metrics_helper_unittest.cc
+++ b/chromium/components/metrics/stability_metrics_helper_unittest.cc
@@ -5,6 +5,7 @@
#include "components/metrics/stability_metrics_helper.h"
#include "base/macros.h"
+#include "base/test/histogram_tester.h"
#include "components/metrics/proto/system_profile.pb.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
@@ -15,6 +16,15 @@ namespace metrics {
namespace {
+enum RendererType {
+ RENDERER_TYPE_RENDERER = 1,
+ RENDERER_TYPE_EXTENSION,
+ // NOTE: Add new action types only immediately above this line. Also,
+ // make sure the enum list in tools/metrics/histograms/histograms.xml is
+ // updated with any change in here.
+ RENDERER_TYPE_COUNT
+};
+
class StabilityMetricsHelperTest : public testing::Test {
protected:
StabilityMetricsHelperTest() : prefs_(new TestingPrefServiceSimple) {
@@ -52,6 +62,7 @@ TEST_F(StabilityMetricsHelperTest, BrowserChildProcessCrashed) {
TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
StabilityMetricsHelper helper(prefs());
+ base::HistogramTester histogram_tester;
// Crash and abnormal termination should increment renderer crash count.
helper.LogRendererCrash(false, base::TERMINATION_STATUS_PROCESS_CRASHED, 1);
@@ -59,6 +70,9 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
helper.LogRendererCrash(false, base::TERMINATION_STATUS_ABNORMAL_TERMINATION,
1);
+ // OOM should increment renderer crash count.
+ helper.LogRendererCrash(false, base::TERMINATION_STATUS_OOM, 1);
+
// Kill does not increment renderer crash count.
helper.LogRendererCrash(false, base::TERMINATION_STATUS_PROCESS_WAS_KILLED,
1);
@@ -72,7 +86,7 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
// be executed immediately.
helper.ProvideStabilityMetrics(&system_profile);
- EXPECT_EQ(2, system_profile.stability().renderer_crash_count());
+ EXPECT_EQ(3, system_profile.stability().renderer_crash_count());
EXPECT_EQ(1, system_profile.stability().renderer_failed_launch_count());
EXPECT_EQ(0, system_profile.stability().extension_renderer_crash_count());
@@ -81,6 +95,9 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
// Crash and abnormal termination should increment extension crash count.
helper.LogRendererCrash(true, base::TERMINATION_STATUS_PROCESS_CRASHED, 1);
+ // OOM should increment extension renderer crash count.
+ helper.LogRendererCrash(true, base::TERMINATION_STATUS_OOM, 1);
+
// Failed launch increments extension failed launch count.
helper.LogRendererCrash(true, base::TERMINATION_STATUS_LAUNCH_FAILED, 1);
@@ -88,9 +105,36 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
helper.ProvideStabilityMetrics(&system_profile);
EXPECT_EQ(0, system_profile.stability().renderer_crash_count());
- EXPECT_EQ(1, system_profile.stability().extension_renderer_crash_count());
+ EXPECT_EQ(2, system_profile.stability().extension_renderer_crash_count());
EXPECT_EQ(
1, system_profile.stability().extension_renderer_failed_launch_count());
+
+ // TERMINATION_STATUS_PROCESS_CRASHED, TERMINATION_STATUS_ABNORMAL_TERMINATION
+ // and TERMINATION_STATUS_OOM = 3.
+ histogram_tester.ExpectUniqueSample("CrashExitCodes.Renderer", 1, 3);
+ histogram_tester.ExpectBucketCount("BrowserRenderProcessHost.ChildCrashes",
+ RENDERER_TYPE_RENDERER, 3);
+
+ // TERMINATION_STATUS_PROCESS_CRASHED and TERMINATION_STATUS_OOM = 2.
+ histogram_tester.ExpectUniqueSample("CrashExitCodes.Extension", 1, 2);
+ histogram_tester.ExpectBucketCount("BrowserRenderProcessHost.ChildCrashes",
+ RENDERER_TYPE_EXTENSION, 2);
+
+ // One launch failure each.
+ histogram_tester.ExpectBucketCount(
+ "BrowserRenderProcessHost.ChildLaunchFailures", RENDERER_TYPE_RENDERER,
+ 1);
+ histogram_tester.ExpectBucketCount(
+ "BrowserRenderProcessHost.ChildLaunchFailures", RENDERER_TYPE_EXTENSION,
+ 1);
+ histogram_tester.ExpectBucketCount(
+ "BrowserRenderProcessHost.ChildLaunchFailureCodes", 1, 2);
+
+ // TERMINATION_STATUS_PROCESS_WAS_KILLED for a renderer.
+ histogram_tester.ExpectBucketCount("BrowserRenderProcessHost.ChildKills",
+ RENDERER_TYPE_RENDERER, 1);
+ histogram_tester.ExpectBucketCount("BrowserRenderProcessHost.ChildKills",
+ RENDERER_TYPE_EXTENSION, 0);
}
} // namespace metrics
diff --git a/chromium/components/metrics/system_memory_stats_recorder_win.cc b/chromium/components/metrics/system_memory_stats_recorder_win.cc
index 539d80ffb1b..7d011821a4d 100644
--- a/chromium/components/metrics/system_memory_stats_recorder_win.cc
+++ b/chromium/components/metrics/system_memory_stats_recorder_win.cc
@@ -23,7 +23,7 @@ void RecordMemoryStats(RecordMemoryStatsType type) {
switch (type) {
case RECORD_MEMORY_STATS_TAB_DISCARDED: {
UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Stats.Win.MemoryLoad",
- mem_status.dwMemoryLoad, 0, 100, 101);
+ mem_status.dwMemoryLoad, 1, 100, 101);
UMA_HISTOGRAM_LARGE_MEMORY_MB("Memory.Stats.Win.TotalPhys2",
mem_status.ullTotalPhys / kMBytes);
UMA_HISTOGRAM_LARGE_MEMORY_MB("Memory.Stats.Win.AvailPhys2",
diff --git a/chromium/components/metrics/test_metrics_service_client.cc b/chromium/components/metrics/test_metrics_service_client.cc
index 643880b6582..7c7ccc68e07 100644
--- a/chromium/components/metrics/test_metrics_service_client.cc
+++ b/chromium/components/metrics/test_metrics_service_client.cc
@@ -31,13 +31,6 @@ void TestMetricsServiceClient::SetMetricsClientId(
client_id_ = client_id;
}
-void TestMetricsServiceClient::OnRecordingDisabled() {
-}
-
-bool TestMetricsServiceClient::IsOffTheRecordSessionActive() {
- return false;
-}
-
int32_t TestMetricsServiceClient::GetProduct() {
return product_;
}
diff --git a/chromium/components/metrics/test_metrics_service_client.h b/chromium/components/metrics/test_metrics_service_client.h
index e935f4a8792..355e7c7c5ae 100644
--- a/chromium/components/metrics/test_metrics_service_client.h
+++ b/chromium/components/metrics/test_metrics_service_client.h
@@ -26,8 +26,6 @@ class TestMetricsServiceClient : public MetricsServiceClient {
// MetricsServiceClient:
metrics::MetricsService* GetMetricsService() override;
void SetMetricsClientId(const std::string& client_id) override;
- void OnRecordingDisabled() override;
- bool IsOffTheRecordSessionActive() override;
int32_t GetProduct() override;
std::string GetApplicationLocale() override;
bool GetBrand(std::string* brand_code) override;
diff --git a/chromium/components/metrics/url_constants.cc b/chromium/components/metrics/url_constants.cc
index 87e721e85e7..4a744d56aff 100644
--- a/chromium/components/metrics/url_constants.cc
+++ b/chromium/components/metrics/url_constants.cc
@@ -8,7 +8,7 @@
namespace metrics {
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_IOS)
const char kDefaultMetricsServerUrl[] =
"https://clientservices.googleapis.com/uma/v2";
#else
diff --git a/chromium/components/metrics_services_manager.gypi b/chromium/components/metrics_services_manager.gypi
deleted file mode 100644
index e4171809966..00000000000
--- a/chromium/components/metrics_services_manager.gypi
+++ /dev/null
@@ -1,28 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/metrics_services_manager
- 'target_name': 'metrics_services_manager',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'metrics',
- 'rappor',
- 'variations',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'metrics_services_manager/metrics_services_manager.cc',
- 'metrics_services_manager/metrics_services_manager.h',
- 'metrics_services_manager/metrics_services_manager_client.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/metrics_services_manager/BUILD.gn b/chromium/components/metrics_services_manager/BUILD.gn
index 9fa17b43ec7..13a2e710879 100644
--- a/chromium/components/metrics_services_manager/BUILD.gn
+++ b/chromium/components/metrics_services_manager/BUILD.gn
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/metrics_services_manager.gypi:metrics_services_manager
-source_set("metrics_services_manager") {
+static_library("metrics_services_manager") {
sources = [
"metrics_services_manager.cc",
"metrics_services_manager.h",
diff --git a/chromium/components/metrics_services_manager/metrics_services_manager.cc b/chromium/components/metrics_services_manager/metrics_services_manager.cc
index e91264c4c2b..652edef82c8 100644
--- a/chromium/components/metrics_services_manager/metrics_services_manager.cc
+++ b/chromium/components/metrics_services_manager/metrics_services_manager.cc
@@ -24,6 +24,11 @@ MetricsServicesManager::MetricsServicesManager(
MetricsServicesManager::~MetricsServicesManager() {}
+std::unique_ptr<const base::FieldTrial::EntropyProvider>
+MetricsServicesManager::CreateEntropyProvider() {
+ return client_->CreateEntropyProvider();
+}
+
metrics::MetricsService* MetricsServicesManager::GetMetricsService() {
DCHECK(thread_checker_.CalledOnValidThread());
return GetMetricsServiceClient()->GetMetricsService();
@@ -85,6 +90,8 @@ void MetricsServicesManager::UpdateRunningServices() {
return;
}
+ client_->UpdateRunningServices(may_record_, may_upload_);
+
if (may_record_) {
if (!metrics->recording_active())
metrics->Start();
@@ -116,7 +123,7 @@ void MetricsServicesManager::UpdateRunningServices() {
}
void MetricsServicesManager::UpdateUploadPermissions(bool may_upload) {
- return UpdatePermissions(client_->IsMetricsReportingEnabled(), may_upload);
+ UpdatePermissions(client_->IsMetricsReportingEnabled(), may_upload);
}
} // namespace metrics_services_manager
diff --git a/chromium/components/metrics_services_manager/metrics_services_manager.h b/chromium/components/metrics_services_manager/metrics_services_manager.h
index d559ffbd92e..e70d6489066 100644
--- a/chromium/components/metrics_services_manager/metrics_services_manager.h
+++ b/chromium/components/metrics_services_manager/metrics_services_manager.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/macros.h"
+#include "base/metrics/field_trial.h"
#include "base/threading/thread_checker.h"
namespace base {
@@ -42,6 +43,16 @@ class MetricsServicesManager {
std::unique_ptr<MetricsServicesManagerClient> client);
virtual ~MetricsServicesManager();
+ // Returns the preferred entropy provider used to seed persistent activities
+ // based on whether or not metrics reporting is permitted on this client.
+ //
+ // If there's consent to report metrics, this method returns an entropy
+ // provider that has a high source of entropy, partially based on the client
+ // ID. Otherwise, it returns an entropy provider that is based on a low
+ // entropy source.
+ std::unique_ptr<const base::FieldTrial::EntropyProvider>
+ CreateEntropyProvider();
+
// Returns the MetricsService, creating it if it hasn't been created yet (and
// additionally creating the MetricsServiceClient in that case).
metrics::MetricsService* GetMetricsService();
diff --git a/chromium/components/metrics_services_manager/metrics_services_manager_client.h b/chromium/components/metrics_services_manager/metrics_services_manager_client.h
index 40c6d0d037a..7a5779c81a8 100644
--- a/chromium/components/metrics_services_manager/metrics_services_manager_client.h
+++ b/chromium/components/metrics_services_manager/metrics_services_manager_client.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/callback_forward.h"
+#include "base/metrics/field_trial.h"
namespace metrics {
class MetricsServiceClient;
@@ -39,6 +40,8 @@ class MetricsServicesManagerClient {
CreateVariationsService() = 0;
virtual std::unique_ptr<metrics::MetricsServiceClient>
CreateMetricsServiceClient() = 0;
+ virtual std::unique_ptr<const base::FieldTrial::EntropyProvider>
+ CreateEntropyProvider() = 0;
// Returns the URL request context in which the metrics services should
// operate.
@@ -57,6 +60,10 @@ class MetricsServicesManagerClient {
// Whether the metrics services should record but not report metrics.
virtual bool OnlyDoMetricsRecording() = 0;
+
+ // Update the running state of metrics services managed by the embedder, for
+ // example, crash reporting.
+ virtual void UpdateRunningServices(bool may_record, bool may_upload) {}
};
} // namespace metrics_services_manager
diff --git a/chromium/components/mime_util/mime_util.cc b/chromium/components/mime_util/mime_util.cc
index 06f9b523783..5f4cf3ffbe4 100644
--- a/chromium/components/mime_util/mime_util.cc
+++ b/chromium/components/mime_util/mime_util.cc
@@ -36,26 +36,27 @@ const char* const kSupportedImageTypes[] = {"image/jpeg",
"image/x-xbitmap", // xbm
"image/x-png"};
-// Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript.
-// Mozilla 1.8 accepts application/javascript, application/ecmascript, and
-// application/x-javascript, but WinIE 7 doesn't.
-// WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and
-// text/livescript, but Mozilla 1.8 doesn't.
-// Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't.
-// Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a
-// whitespace-only string.
-// We want to accept all the values that either of these browsers accept, but
-// not other values.
-const char* const kSupportedJavascriptTypes[] = {"text/javascript",
- "text/ecmascript",
- "application/javascript",
- "application/ecmascript",
- "application/x-javascript",
- "text/javascript1.1",
- "text/javascript1.2",
- "text/javascript1.3",
- "text/jscript",
- "text/livescript"};
+// Support every script type mentioned in the spec, as it notes that "User
+// agents must recognize all JavaScript MIME types." See
+// https://html.spec.whatwg.org/#javascript-mime-type.
+const char* const kSupportedJavascriptTypes[] = {
+ "application/ecmascript",
+ "application/javascript",
+ "application/x-ecmascript",
+ "application/x-javascript",
+ "text/ecmascript",
+ "text/javascript",
+ "text/javascript1.0",
+ "text/javascript1.1",
+ "text/javascript1.2",
+ "text/javascript1.3",
+ "text/javascript1.4",
+ "text/javascript1.5",
+ "text/jscript",
+ "text/livescript",
+ "text/x-ecmascript",
+ "text/x-javascript",
+};
// These types are excluded from the logic that allows all text/ types because
// while they are technically text, it's very unlikely that a user expects to
diff --git a/chromium/components/mime_util/mime_util.gyp b/chromium/components/mime_util/mime_util.gyp
deleted file mode 100644
index c922f98d1e1..00000000000
--- a/chromium/components/mime_util/mime_util.gyp
+++ /dev/null
@@ -1,29 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/mime_util/mime_util
- 'target_name': 'mime_util',
- 'type': 'static_library',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../net/net.gyp:net',
- ],
- 'sources': [
- 'mime_util.cc',
- 'mime_util.h',
- ],
- 'conditions': [
- ['OS!="ios"', {
- # iOS doesn't use and must not depend on //media
- 'dependencies': [
- '../../media/media.gyp:media',
- ],
- }],
- ],
- }
- ],
-}
diff --git a/chromium/components/mus/BUILD.gn b/chromium/components/mus/BUILD.gn
deleted file mode 100644
index a1c52b86a91..00000000000
--- a/chromium/components/mus/BUILD.gn
+++ /dev/null
@@ -1,143 +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.
-
-import("//build/config/ui.gni")
-import("//testing/test.gni")
-import("//mojo/public/mojo_application.gni")
-import("//mojo/public/mojo_application_manifest.gni")
-import("//mojo/public/mojo_constants.gni")
-import("//tools/grit/repack.gni")
-
-group("all") {
- testonly = true
- deps = [
- ":mus",
- "//components/mus/test_wm",
- ]
-}
-
-mojo_native_application("mus") {
- sources = [
- "main.cc",
- ]
-
- deps = [
- ":lib",
- ":resources_100",
- ":resources_200",
- ":resources_strings",
- "//services/shell/public/cpp:sources",
- "//services/tracing/public/interfaces",
- ]
-
- if (is_win) {
- deps += [ ":copy_gl_libraries" ]
- }
-
- data_deps = [
- ":manifest",
- ]
-
- resources = [
- "$root_out_dir/mus_app_resources_strings.pak",
- "$root_out_dir/mus_app_resources_100.pak",
- "$root_out_dir/mus_app_resources_200.pak",
- ]
-}
-
-mojo_application_manifest("manifest") {
- application_name = "mus"
- source = "manifest.json"
-}
-
-if (is_win) {
- copy("copy_gl_libraries") {
- deps = [
- "//third_party/angle:libEGL",
- "//third_party/angle:libGLESv2",
- ]
-
- sources = [
- "$root_shlib_dir/libEGL.dll",
- "$root_shlib_dir/libGLESv2.dll",
- ]
-
- outputs = [
- "$root_out_dir/$mojo_application_subdir/mus/{{source_file_part}}",
- ]
- }
-}
-
-source_set("lib") {
- sources = [
- "mus_app.cc",
- "mus_app.h",
- ]
-
- public_deps = [
- "//components/mus/common:mus_common",
- ]
- deps = [
- "//base",
- "//cc",
- "//cc/surfaces",
- "//components/mus/clipboard:lib",
- "//components/mus/gles2",
- "//components/mus/gpu",
- "//components/mus/gpu/display_compositor",
- "//components/mus/input_devices",
- "//components/mus/public/interfaces",
- "//components/mus/surfaces",
- "//components/mus/ws:lib",
- "//components/mus/ws:test_interface",
- "//mojo/common:common_base",
- "//services/catalog/public/cpp",
- "//services/shell/public/cpp",
- "//services/tracing/public/cpp",
- "//ui/events",
- "//ui/events/ozone:events_ozone_layout",
- "//ui/gl:gl",
- "//ui/platform_window:platform_impls",
- "//ui/platform_window:platform_window",
- ]
-
- if (use_x11) {
- public_configs = [ "//build/config/linux:x11" ]
- public_deps += [ "//ui/events/platform/x11" ]
- }
-
- if (use_ozone) {
- deps += [ "//ui/ozone:ozone" ]
- }
-}
-
-repack("resources_strings") {
- sources = [
- "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak",
- ]
- output = "$root_out_dir/mus_app_resources_strings.pak"
- deps = [
- "//ui/strings",
- ]
-}
-
-repack("resources_100") {
- sources = [
- "$root_gen_dir/ui/resources/ui_resources_100_percent.pak",
- ]
- output = "$root_out_dir/mus_app_resources_100.pak"
- deps = [
- "//ui/resources",
- ]
-}
-
-repack("resources_200") {
- sources = [
- "$root_gen_dir/ui/resources/ui_resources_200_percent.pak",
- ]
- output = "$root_out_dir/mus_app_resources_200.pak"
- deps = [
- "//ui/resources",
- ]
-}
diff --git a/chromium/components/mus/DEPS b/chromium/components/mus/DEPS
deleted file mode 100644
index f3a2b3a7d97..00000000000
--- a/chromium/components/mus/DEPS
+++ /dev/null
@@ -1,12 +0,0 @@
-include_rules = [
- "+cc",
- "+ipc",
- "+mojo/common",
- "+mojo/converters",
- "+mojo/public",
- "+services/catalog/public",
- "+services/shell",
- "+services/tracing/public",
- "+third_party/skia/include",
- "+ui",
-]
diff --git a/chromium/components/mus/OWNERS b/chromium/components/mus/OWNERS
deleted file mode 100644
index e6a7642f300..00000000000
--- a/chromium/components/mus/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-ben@chromium.org
-erg@chromium.org
-msw@chromium.org
-sky@chromium.org
diff --git a/chromium/components/mus/clipboard/BUILD.gn b/chromium/components/mus/clipboard/BUILD.gn
deleted file mode 100644
index 98f51966799..00000000000
--- a/chromium/components/mus/clipboard/BUILD.gn
+++ /dev/null
@@ -1,57 +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.
-
-import("//mojo/public/mojo_application.gni")
-import("//mojo/public/mojo_application_manifest.gni")
-import("//testing/test.gni")
-
-source_set("lib") {
- sources = [
- "clipboard_impl.cc",
- "clipboard_impl.h",
- ]
-
- deps = [
- "//base",
- "//components/mus/public/interfaces",
- "//mojo/common",
- "//mojo/public/cpp/bindings",
- "//services/shell/public/cpp",
- "//services/tracing/public/cpp",
- ]
-}
-
-group("tests") {
- testonly = true
- deps = [
- ":mus_clipboard_unittests",
- ]
-}
-
-test("mus_clipboard_unittests") {
- sources = [
- "clipboard_unittest.cc",
- ]
-
- deps = [
- "//base",
- "//components/mus/public/interfaces",
- "//mojo/common",
- "//services/shell/public/cpp:shell_test_support",
- "//services/shell/public/cpp:sources",
- "//services/shell/public/cpp/test:run_all_shelltests",
- ]
-
- data_deps = [
- ":test_manifest",
- ":lib",
- "//components/mus:mus",
- ]
-}
-
-mojo_application_manifest("test_manifest") {
- type = "exe"
- application_name = "mus_clipboard_unittests"
- source = "test_manifest.json"
-}
diff --git a/chromium/components/mus/clipboard/clipboard_impl.cc b/chromium/components/mus/clipboard/clipboard_impl.cc
deleted file mode 100644
index a82d95e8f03..00000000000
--- a/chromium/components/mus/clipboard/clipboard_impl.cc
+++ /dev/null
@@ -1,108 +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 "components/mus/clipboard/clipboard_impl.h"
-
-#include <string.h>
-#include <utility>
-
-#include "base/macros.h"
-#include "mojo/common/common_type_converters.h"
-#include "mojo/public/cpp/bindings/array.h"
-#include "mojo/public/cpp/bindings/string.h"
-
-using mojo::Array;
-using mojo::Map;
-using mojo::String;
-
-namespace mus {
-namespace clipboard {
-
-// ClipboardData contains data copied to the Clipboard for a variety of formats.
-// It mostly just provides APIs to cleanly access and manipulate this data.
-class ClipboardImpl::ClipboardData {
- public:
- ClipboardData() : sequence_number_(0) {}
- ~ClipboardData() {}
-
- uint64_t sequence_number() const {
- return sequence_number_;
- }
-
- Array<String> GetMimeTypes() const {
- Array<String> types(data_types_.size());
- int i = 0;
- for (auto it = data_types_.begin(); it != data_types_.end(); ++it, ++i)
- types[i] = it->first;
-
- return types;
- }
-
- void SetData(Map<String, Array<uint8_t>> data) {
- sequence_number_++;
- data_types_ = std::move(data);
- }
-
- void GetData(const String& mime_type, Array<uint8_t>* data) const {
- auto it = data_types_.find(mime_type);
- if (it != data_types_.end())
- *data = it->second.Clone();
- }
-
- private:
- uint64_t sequence_number_;
- Map<String, Array<uint8_t>> data_types_;
-
- DISALLOW_COPY_AND_ASSIGN(ClipboardData);
-};
-
-ClipboardImpl::ClipboardImpl() {
- for (int i = 0; i < kNumClipboards; ++i)
- clipboard_state_[i].reset(new ClipboardData);
-}
-
-ClipboardImpl::~ClipboardImpl() {
-}
-
-void ClipboardImpl::AddBinding(mojom::ClipboardRequest request) {
- bindings_.AddBinding(this, std::move(request));
-}
-
-void ClipboardImpl::GetSequenceNumber(
- Clipboard::Type clipboard_type,
- const GetSequenceNumberCallback& callback) {
- callback.Run(
- clipboard_state_[static_cast<int>(clipboard_type)]->sequence_number());
-}
-
-void ClipboardImpl::GetAvailableMimeTypes(
- Clipboard::Type clipboard_type,
- const GetAvailableMimeTypesCallback& callback) {
- int clipboard_num = static_cast<int>(clipboard_type);
- callback.Run(clipboard_state_[clipboard_num]->sequence_number(),
- clipboard_state_[clipboard_num]->GetMimeTypes());
-}
-
-void ClipboardImpl::ReadClipboardData(
- Clipboard::Type clipboard_type,
- const String& mime_type,
- const ReadClipboardDataCallback& callback) {
- int clipboard_num = static_cast<int>(clipboard_type);
- Array<uint8_t> mime_data(nullptr);
- uint64_t sequence = clipboard_state_[clipboard_num]->sequence_number();
- clipboard_state_[clipboard_num]->GetData(mime_type, &mime_data);
- callback.Run(sequence, std::move(mime_data));
-}
-
-void ClipboardImpl::WriteClipboardData(
- Clipboard::Type clipboard_type,
- Map<String, Array<uint8_t>> data,
- const WriteClipboardDataCallback& callback) {
- int clipboard_num = static_cast<int>(clipboard_type);
- clipboard_state_[clipboard_num]->SetData(std::move(data));
- callback.Run(clipboard_state_[clipboard_num]->sequence_number());
-}
-
-} // namespace clipboard
-} // namespace mus
diff --git a/chromium/components/mus/clipboard/clipboard_impl.h b/chromium/components/mus/clipboard/clipboard_impl.h
deleted file mode 100644
index 7f62f1c1df5..00000000000
--- a/chromium/components/mus/clipboard/clipboard_impl.h
+++ /dev/null
@@ -1,65 +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 COMPONENTS_MUS_CLIPBOARD_CLIPBOARD_IMPL_H_
-#define COMPONENTS_MUS_CLIPBOARD_CLIPBOARD_IMPL_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "components/mus/public/interfaces/clipboard.mojom.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-
-namespace mus {
-namespace clipboard {
-
-// Stub clipboard implementation.
-//
-// Eventually, we'll actually want to interact with the system clipboard, but
-// that's hard today because the system clipboard is asynchronous (on X11), the
-// ui::Clipboard interface is synchronous (which is what we'd use), mojo is
-// asynchronous across processes, and the WebClipboard interface is synchronous
-// (which is at least tractable).
-class ClipboardImpl : public mojom::Clipboard {
- public:
- // mojom::Clipboard exposes three possible clipboards.
- static const int kNumClipboards = 3;
-
- ClipboardImpl();
- ~ClipboardImpl() override;
-
- void AddBinding(mojom::ClipboardRequest request);
-
- // mojom::Clipboard implementation.
- void GetSequenceNumber(
- mojom::Clipboard::Type clipboard_type,
- const GetSequenceNumberCallback& callback) override;
- void GetAvailableMimeTypes(
- mojom::Clipboard::Type clipboard_types,
- const GetAvailableMimeTypesCallback& callback) override;
- void ReadClipboardData(mojom::Clipboard::Type clipboard_type,
- const mojo::String& mime_type,
- const ReadClipboardDataCallback& callback) override;
- void WriteClipboardData(
- mojom::Clipboard::Type clipboard_type,
- mojo::Map<mojo::String, mojo::Array<uint8_t>> data,
- const WriteClipboardDataCallback& callback) override;
-
- private:
- // Internal struct which stores the current state of the clipboard.
- class ClipboardData;
-
- // The current clipboard state. This is what is read from.
- std::unique_ptr<ClipboardData> clipboard_state_[kNumClipboards];
- mojo::BindingSet<mojom::Clipboard> bindings_;
-
- DISALLOW_COPY_AND_ASSIGN(ClipboardImpl);
-};
-
-} // namespace clipboard
-} // namespace mus
-
-#endif // COMPONENTS_MUS_CLIPBOARD_CLIPBOARD_IMPL_H_
diff --git a/chromium/components/mus/clipboard/clipboard_unittest.cc b/chromium/components/mus/clipboard/clipboard_unittest.cc
deleted file mode 100644
index 764618395c7..00000000000
--- a/chromium/components/mus/clipboard/clipboard_unittest.cc
+++ /dev/null
@@ -1,145 +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 <stdint.h>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "components/mus/public/interfaces/clipboard.mojom.h"
-#include "mojo/common/common_type_converters.h"
-#include "services/shell/public/cpp/shell_connection.h"
-#include "services/shell/public/cpp/shell_test.h"
-
-using mojo::Array;
-using mojo::Map;
-using mojo::String;
-using mus::mojom::Clipboard;
-
-namespace mus {
-namespace clipboard {
-namespace {
-
-const char* kUninitialized = "Uninitialized data";
-const char* kPlainTextData = "Some plain data";
-const char* kHtmlData = "<html>data</html>";
-
-} // namespace
-
-class ClipboardAppTest : public shell::test::ShellTest {
- public:
- ClipboardAppTest() : ShellTest("exe:mus_clipboard_unittests") {}
- ~ClipboardAppTest() override {}
-
- // Overridden from shell::test::ShellTest:
- void SetUp() override {
- ShellTest::SetUp();
-
- connector()->ConnectToInterface("mojo:mus", &clipboard_);
- ASSERT_TRUE(clipboard_);
- }
-
- uint64_t GetSequenceNumber() {
- uint64_t sequence_num = 999999;
- EXPECT_TRUE(clipboard_->GetSequenceNumber(
- Clipboard::Type::COPY_PASTE, &sequence_num));
- return sequence_num;
- }
-
- std::vector<std::string> GetAvailableFormatMimeTypes() {
- uint64_t sequence_num = 999999;
- Array<String> types;
- types.push_back(kUninitialized);
- clipboard_->GetAvailableMimeTypes(
- Clipboard::Type::COPY_PASTE,
- &sequence_num, &types);
- return types.To<std::vector<std::string>>();
- }
-
- bool GetDataOfType(const std::string& mime_type, std::string* data) {
- bool valid = false;
- Array<uint8_t> raw_data;
- uint64_t sequence_number = 0;
- clipboard_->ReadClipboardData(Clipboard::Type::COPY_PASTE, mime_type,
- &sequence_number, &raw_data);
- valid = !raw_data.is_null();
- *data = raw_data.is_null() ? "" : raw_data.To<std::string>();
- return valid;
- }
-
- void SetStringText(const std::string& data) {
- uint64_t sequence_number;
- Map<String, Array<uint8_t>> mime_data;
- mime_data[mojom::kMimeTypeText] = Array<uint8_t>::From(data);
- clipboard_->WriteClipboardData(Clipboard::Type::COPY_PASTE,
- std::move(mime_data),
- &sequence_number);
- }
-
- protected:
- mojom::ClipboardPtr clipboard_;
-
- DISALLOW_COPY_AND_ASSIGN(ClipboardAppTest);
-};
-
-TEST_F(ClipboardAppTest, EmptyClipboardOK) {
- EXPECT_EQ(0ul, GetSequenceNumber());
- EXPECT_TRUE(GetAvailableFormatMimeTypes().empty());
- std::string data;
- EXPECT_FALSE(GetDataOfType(mojom::kMimeTypeText, &data));
-}
-
-TEST_F(ClipboardAppTest, CanReadBackText) {
- std::string data;
- EXPECT_EQ(0ul, GetSequenceNumber());
- EXPECT_FALSE(GetDataOfType(mojom::kMimeTypeText, &data));
-
- SetStringText(kPlainTextData);
- EXPECT_EQ(1ul, GetSequenceNumber());
-
- EXPECT_TRUE(GetDataOfType(mojom::kMimeTypeText, &data));
- EXPECT_EQ(kPlainTextData, data);
-}
-
-TEST_F(ClipboardAppTest, CanSetMultipleDataTypesAtOnce) {
- Map<String, Array<uint8_t>> mime_data;
- mime_data[mojom::kMimeTypeText] =
- Array<uint8_t>::From(std::string(kPlainTextData));
- mime_data[mojom::kMimeTypeHTML] =
- Array<uint8_t>::From(std::string(kHtmlData));
-
- uint64_t sequence_num = 0;
- clipboard_->WriteClipboardData(Clipboard::Type::COPY_PASTE,
- std::move(mime_data),
- &sequence_num);
- EXPECT_EQ(1ul, sequence_num);
-
- std::string data;
- EXPECT_TRUE(GetDataOfType(mojom::kMimeTypeText, &data));
- EXPECT_EQ(kPlainTextData, data);
- EXPECT_TRUE(GetDataOfType(mojom::kMimeTypeHTML, &data));
- EXPECT_EQ(kHtmlData, data);
-}
-
-TEST_F(ClipboardAppTest, CanClearClipboardWithZeroArray) {
- std::string data;
- SetStringText(kPlainTextData);
- EXPECT_EQ(1ul, GetSequenceNumber());
-
- EXPECT_TRUE(GetDataOfType(mojom::kMimeTypeText, &data));
- EXPECT_EQ(kPlainTextData, data);
-
- Map<String, Array<uint8_t>> mime_data;
- uint64_t sequence_num = 0;
- clipboard_->WriteClipboardData(Clipboard::Type::COPY_PASTE,
- std::move(mime_data),
- &sequence_num);
-
- EXPECT_EQ(2ul, sequence_num);
- EXPECT_FALSE(GetDataOfType(mojom::kMimeTypeText, &data));
-}
-
-} // namespace clipboard
-} // namespace mus
diff --git a/chromium/components/mus/clipboard/test_manifest.json b/chromium/components/mus/clipboard/test_manifest.json
deleted file mode 100644
index 26e694cea02..00000000000
--- a/chromium/components/mus/clipboard/test_manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "manifest_version": 1,
- "name": "exe:mus_clipboard_unittests",
- "display_name": "Clipboard Service Unittests",
- "capabilities": {
- "required": {
- "mojo:mus": { "interfaces": [ "mus::mojom::Clipboard" ] }
- }
- }
-}
diff --git a/chromium/components/mus/common/BUILD.gn b/chromium/components/mus/common/BUILD.gn
deleted file mode 100644
index 01db30922ed..00000000000
--- a/chromium/components/mus/common/BUILD.gn
+++ /dev/null
@@ -1,100 +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.
-
-import("//build/config/ui.gni")
-import("//mojo/public/mojo_application_manifest.gni")
-import("//testing/test.gni")
-
-component("mus_common") {
- sources = [
- "event_matcher_util.cc",
- "event_matcher_util.h",
- "generic_shared_memory_id_generator.cc",
- "generic_shared_memory_id_generator.h",
- "gpu_memory_buffer_impl.cc",
- "gpu_memory_buffer_impl.h",
- "gpu_service.cc",
- "gpu_service.h",
- "gpu_type_converters.cc",
- "gpu_type_converters.h",
- "mojo_buffer_backing.cc",
- "mojo_buffer_backing.h",
- "mojo_gpu_memory_buffer.cc",
- "mojo_gpu_memory_buffer.h",
- "mojo_gpu_memory_buffer_manager.cc",
- "mojo_gpu_memory_buffer_manager.h",
- "mus_common_export.h",
- "switches.cc",
- "switches.h",
- "transient_window_utils.h",
- "types.h",
- "util.h",
- ]
-
- defines = [ "MUS_COMMON_IMPLEMENTATION" ]
-
- deps = [
- "//gpu/command_buffer/client",
- "//gpu/config",
- "//gpu/ipc/client",
- "//gpu/ipc/common:command_buffer_traits",
- "//ipc:ipc",
- "//services/shell/public/cpp",
- "//ui/events:events",
- "//ui/gfx/ipc/geometry",
- ]
-
- public_deps = [
- "//components/mus/public/interfaces",
- "//mojo/public/cpp/bindings",
- "//mojo/public/cpp/system",
- "//ui/base",
- ]
-
- if (use_ozone) {
- deps += [ "//ui/ozone" ]
- }
-}
-
-source_set("run_all_shelltests") {
- testonly = true
-
- sources = [
- "run_all_shelltests.cc",
- ]
-
- deps = [
- "//base/test:test_support",
- "//mojo/edk/system",
- "//services/shell/background:main",
- ]
-
- if (use_ozone) {
- deps += [ "//ui/ozone" ]
- }
-}
-
-test("mus_common_unittests") {
- sources = [
- "gpu_type_converters_unittest.cc",
- ]
- public_deps = [
- ":mus_common",
- ]
- deps = [
- ":run_all_shelltests",
- "//base",
- "//base/test:test_config",
- "//components/mus/public/interfaces",
- "//ipc:ipc",
- "//testing/gtest",
- "//ui/gfx:test_support",
- "//ui/gfx/ipc",
- ]
-}
-
-mojo_application_manifest("mus_common_unittests_app_manifest") {
- application_name = "mus_common_unittests_app"
- source = "mus_common_unittests_app_manifest.json"
-}
diff --git a/chromium/components/mus/common/DEPS b/chromium/components/mus/common/DEPS
deleted file mode 100644
index f77ec566793..00000000000
--- a/chromium/components/mus/common/DEPS
+++ /dev/null
@@ -1,12 +0,0 @@
-include_rules = [
- "+gpu/config",
- "+gpu/command_buffer",
- "+gpu/ipc/client",
- "+gpu/ipc/common",
-]
-
-specific_include_rules = {
- "run_all_shelltests\.cc": [
- "+mojo/edk/embedder/embedder.h",
- ],
-}
diff --git a/chromium/components/mus/common/event_matcher_util.cc b/chromium/components/mus/common/event_matcher_util.cc
deleted file mode 100644
index a82a12d3002..00000000000
--- a/chromium/components/mus/common/event_matcher_util.cc
+++ /dev/null
@@ -1,28 +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 "components/mus/common/event_matcher_util.h"
-
-namespace mus {
-
-mojom::EventMatcherPtr CreateKeyMatcher(ui::mojom::KeyboardCode code,
- int flags) {
- mojom::EventMatcherPtr matcher(mojom::EventMatcher::New());
- matcher->type_matcher = mojom::EventTypeMatcher::New();
- matcher->flags_matcher = mojom::EventFlagsMatcher::New();
- matcher->ignore_flags_matcher = mojom::EventFlagsMatcher::New();
- // Ignoring these makes most accelerator scenarios more straight forward. Code
- // that needs to check them can override this setting.
- matcher->ignore_flags_matcher->flags = ui::mojom::kEventFlagCapsLockOn |
- ui::mojom::kEventFlagScrollLockOn |
- ui::mojom::kEventFlagNumLockOn;
- matcher->key_matcher = mojom::KeyEventMatcher::New();
-
- matcher->type_matcher->type = ui::mojom::EventType::KEY_PRESSED;
- matcher->flags_matcher->flags = flags;
- matcher->key_matcher->keyboard_code = code;
- return matcher;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/common/event_matcher_util.h b/chromium/components/mus/common/event_matcher_util.h
deleted file mode 100644
index 2b99729ea2a..00000000000
--- a/chromium/components/mus/common/event_matcher_util.h
+++ /dev/null
@@ -1,22 +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 COMPONENTS_MUS_COMMON_EVENT_MATCHER_UTIL_H_
-#define COMPONENTS_MUS_COMMON_EVENT_MATCHER_UTIL_H_
-
-#include "components/mus/common/mus_common_export.h"
-#include "components/mus/public/interfaces/event_matcher.mojom.h"
-#include "ui/events/mojo/event_constants.mojom.h"
-#include "ui/events/mojo/keyboard_codes.mojom.h"
-
-namespace mus {
-
-// |flags| is a bitfield of kEventFlag* and kMouseEventFlag* values in
-// input_event_constants.mojom.
-mojom::EventMatcherPtr MUS_COMMON_EXPORT
-CreateKeyMatcher(ui::mojom::KeyboardCode code, int flags);
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_COMMON_EVENT_MATCHER_UTIL_H_
diff --git a/chromium/components/mus/common/generic_shared_memory_id_generator.cc b/chromium/components/mus/common/generic_shared_memory_id_generator.cc
deleted file mode 100644
index 622a53940b2..00000000000
--- a/chromium/components/mus/common/generic_shared_memory_id_generator.cc
+++ /dev/null
@@ -1,21 +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 "components/mus/common/generic_shared_memory_id_generator.h"
-
-#include "base/atomic_sequence_num.h"
-
-namespace mus {
-namespace {
-
-// Global atomic to generate gpu memory buffer unique IDs.
-base::StaticAtomicSequenceNumber g_next_generic_shared_memory_id;
-
-} // namespace
-
-gfx::GenericSharedMemoryId GetNextGenericSharedMemoryId() {
- return gfx::GenericSharedMemoryId(g_next_generic_shared_memory_id.GetNext());
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/common/generic_shared_memory_id_generator.h b/chromium/components/mus/common/generic_shared_memory_id_generator.h
deleted file mode 100644
index c462e093d3a..00000000000
--- a/chromium/components/mus/common/generic_shared_memory_id_generator.h
+++ /dev/null
@@ -1,19 +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 COMPONENTS_MUS_COMMON_GENERIC_SHARED_MEMORY_ID_GENERATOR_H_
-#define COMPONENTS_MUS_COMMON_GENERIC_SHARED_MEMORY_ID_GENERATOR_H_
-
-#include "components/mus/common/mus_common_export.h"
-#include "ui/gfx/generic_shared_memory_id.h"
-
-namespace mus {
-
-// Returns the next GenericSharedMemoryId for the current process. This should
-// be used anywhere a new GenericSharedMemoryId is needed.
-MUS_COMMON_EXPORT gfx::GenericSharedMemoryId GetNextGenericSharedMemoryId();
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_COMMON_GENERIC_SHARED_MEMORY_ID_GENERATOR_H_
diff --git a/chromium/components/mus/common/gpu_memory_buffer_impl.cc b/chromium/components/mus/common/gpu_memory_buffer_impl.cc
deleted file mode 100644
index 415f6548f14..00000000000
--- a/chromium/components/mus/common/gpu_memory_buffer_impl.cc
+++ /dev/null
@@ -1,46 +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 "components/mus/common/gpu_memory_buffer_impl.h"
-
-namespace mus {
-
-GpuMemoryBufferImpl::GpuMemoryBufferImpl(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format)
- : id_(id), size_(size), format_(format), mapped_(false) {}
-
-GpuMemoryBufferImpl::~GpuMemoryBufferImpl() {
- DCHECK(!mapped_);
-}
-
-// static
-GpuMemoryBufferImpl* GpuMemoryBufferImpl::FromClientBuffer(
- ClientBuffer buffer) {
- return reinterpret_cast<GpuMemoryBufferImpl*>(buffer);
-}
-
-gfx::Size GpuMemoryBufferImpl::GetSize() const {
- return size_;
-}
-
-gfx::BufferFormat GpuMemoryBufferImpl::GetFormat() const {
- return format_;
-}
-
-gfx::GpuMemoryBufferId GpuMemoryBufferImpl::GetId() const {
- return id_;
-}
-
-ClientBuffer GpuMemoryBufferImpl::AsClientBuffer() {
- return reinterpret_cast<ClientBuffer>(this);
-}
-
-#if defined(USE_OZONE)
-scoped_refptr<ui::NativePixmap> GpuMemoryBufferImpl::GetNativePixmap() {
- return scoped_refptr<ui::NativePixmap>();
-}
-#endif
-
-} // namespace mus
diff --git a/chromium/components/mus/common/gpu_memory_buffer_impl.h b/chromium/components/mus/common/gpu_memory_buffer_impl.h
deleted file mode 100644
index 84f1f9d90ad..00000000000
--- a/chromium/components/mus/common/gpu_memory_buffer_impl.h
+++ /dev/null
@@ -1,61 +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 COMPONENTS_MUS_COMMON_GPU_MEMORY_BUFFER_IMPL_H_
-#define COMPONENTS_MUS_COMMON_GPU_MEMORY_BUFFER_IMPL_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "components/mus/common/mus_common_export.h"
-#include "gpu/command_buffer/common/sync_token.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/gpu_memory_buffer.h"
-
-#if defined(USE_OZONE)
-#include "ui/ozone/public/native_pixmap.h"
-#endif
-
-namespace mus {
-
-// Provides common implementation of a GPU memory buffer.
-class MUS_COMMON_EXPORT GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
- public:
- ~GpuMemoryBufferImpl() override;
-
- // Type-checking upcast routine. Returns an NULL on failure.
- static GpuMemoryBufferImpl* FromClientBuffer(ClientBuffer buffer);
-
- // Overridden from gfx::GpuMemoryBuffer:
- gfx::Size GetSize() const override;
- gfx::BufferFormat GetFormat() const override;
- gfx::GpuMemoryBufferId GetId() const override;
- ClientBuffer AsClientBuffer() override;
-
- // Returns the type of this GpuMemoryBufferImpl.
- virtual gfx::GpuMemoryBufferType GetBufferType() const = 0;
-
-#if defined(USE_OZONE)
- // Returns a ui::NativePixmap when one is available.
- virtual scoped_refptr<ui::NativePixmap> GetNativePixmap();
-#endif
-
- protected:
- GpuMemoryBufferImpl(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format);
-
- const gfx::GpuMemoryBufferId id_;
- const gfx::Size size_;
- const gfx::BufferFormat format_;
- bool mapped_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImpl);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_COMMON_GPU_MEMORY_BUFFER_IMPL_H_
diff --git a/chromium/components/mus/common/gpu_service.cc b/chromium/components/mus/common/gpu_service.cc
deleted file mode 100644
index 4eea3e45972..00000000000
--- a/chromium/components/mus/common/gpu_service.cc
+++ /dev/null
@@ -1,256 +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 "components/mus/common/gpu_service.h"
-
-#include "base/command_line.h"
-#include "base/memory/singleton.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "components/mus/common/gpu_type_converters.h"
-#include "components/mus/common/switches.h"
-#include "components/mus/public/interfaces/gpu_service.mojom.h"
-#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-#include "services/shell/public/cpp/connector.h"
-
-namespace mus {
-
-namespace {
-
-void PostTask(scoped_refptr<base::SingleThreadTaskRunner> runner,
- const tracked_objects::Location& from_here,
- const base::Closure& callback) {
- runner->PostTask(from_here, callback);
-}
-
-GpuService* g_gpu_service = nullptr;
-}
-
-GpuService::GpuService(shell::Connector* connector)
- : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- connector_(connector),
- shutdown_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED),
- io_thread_("GPUIOThread"),
- gpu_memory_buffer_manager_(new MojoGpuMemoryBufferManager),
- is_establishing_(false),
- establishing_condition_(&lock_) {
- DCHECK(main_task_runner_);
- DCHECK(connector_);
- base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
- thread_options.priority = base::ThreadPriority::NORMAL;
- CHECK(io_thread_.StartWithOptions(thread_options));
-}
-
-GpuService::~GpuService() {
- DCHECK(IsMainThread());
- if (gpu_channel_)
- gpu_channel_->DestroyChannel();
-}
-
-// static
-bool GpuService::UseChromeGpuCommandBuffer() {
-// TODO(penghuang): Kludge: Running with Chrome GPU command buffer by default
-// breaks unit tests on Windows
-#if defined(OS_WIN)
- return false;
-#else
- return !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseMojoGpuCommandBufferInMus);
-#endif
-}
-
-// static
-void GpuService::Initialize(shell::Connector* connector) {
- DCHECK(!g_gpu_service);
- g_gpu_service = new GpuService(connector);
-}
-
-// static
-void GpuService::Terminate() {
- DCHECK(g_gpu_service);
- delete g_gpu_service;
- g_gpu_service = nullptr;
-}
-
-// static
-GpuService* GpuService::GetInstance() {
- DCHECK(g_gpu_service);
- return g_gpu_service;
-}
-
-void GpuService::EstablishGpuChannel(const base::Closure& callback) {
- base::AutoLock auto_lock(lock_);
- auto runner = base::ThreadTaskRunnerHandle::Get();
- if (GetGpuChannelLocked()) {
- runner->PostTask(FROM_HERE, callback);
- return;
- }
-
- base::Closure wrapper_callback =
- IsMainThread() ? callback
- : base::Bind(PostTask, runner, FROM_HERE, callback);
- establish_callbacks_.push_back(wrapper_callback);
-
- if (!is_establishing_) {
- is_establishing_ = true;
- main_task_runner_->PostTask(
- FROM_HERE, base::Bind(&GpuService::EstablishGpuChannelOnMainThread,
- base::Unretained(this)));
- }
-}
-
-scoped_refptr<gpu::GpuChannelHost> GpuService::EstablishGpuChannelSync() {
- base::AutoLock auto_lock(lock_);
- if (GetGpuChannelLocked())
- return gpu_channel_;
-
- if (IsMainThread()) {
- is_establishing_ = true;
- EstablishGpuChannelOnMainThreadSyncLocked();
- } else {
- if (!is_establishing_) {
- // Create an establishing gpu channel task, if there isn't one.
- is_establishing_ = true;
- main_task_runner_->PostTask(
- FROM_HERE, base::Bind(&GpuService::EstablishGpuChannelOnMainThread,
- base::Unretained(this)));
- }
-
- // Wait until the pending establishing task is finished.
- do {
- establishing_condition_.Wait();
- } while (is_establishing_);
- }
- return gpu_channel_;
-}
-
-scoped_refptr<gpu::GpuChannelHost> GpuService::GetGpuChannel() {
- base::AutoLock auto_lock(lock_);
- return GetGpuChannelLocked();
-}
-
-scoped_refptr<gpu::GpuChannelHost> GpuService::GetGpuChannelLocked() {
- if (gpu_channel_ && gpu_channel_->IsLost()) {
- main_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&gpu::GpuChannelHost::DestroyChannel, gpu_channel_));
- gpu_channel_ = nullptr;
- }
- return gpu_channel_;
-}
-
-void GpuService::EstablishGpuChannelOnMainThread() {
- base::AutoLock auto_lock(lock_);
- DCHECK(IsMainThread());
-
- // In GpuService::EstablishGpuChannelOnMainThreadSyncLocked(), we use the sync
- // mojo EstablishGpuChannel call, after that call the gpu_service_ will be
- // reset immediatelly. So gpu_service_ should be always null here.
- DCHECK(!gpu_service_);
-
- // is_establishing_ is false, it means GpuService::EstablishGpuChannelSync()
- // has been used, and we don't need try to establish a new GPU channel
- // anymore.
- if (!is_establishing_)
- return;
-
- connector_->ConnectToInterface("mojo:mus", &gpu_service_);
- const bool locked = false;
- gpu_service_->EstablishGpuChannel(
- base::Bind(&GpuService::EstablishGpuChannelOnMainThreadDone,
- base::Unretained(this), locked));
-}
-
-void GpuService::EstablishGpuChannelOnMainThreadSyncLocked() {
- DCHECK(IsMainThread());
- DCHECK(is_establishing_);
-
- // In browser process, EstablishGpuChannelSync() is only used by testing &
- // GpuProcessTransportFactory::GetGLHelper(). For GetGLHelper(), it expects
- // the gpu channel has been established, so it should not reach here.
- // For testing, the asyc method should not be used.
- // In renderer process, we only use EstablishGpuChannelSync().
- // So the gpu_service_ should be null here.
- DCHECK(!gpu_service_);
-
- int client_id = 0;
- mojom::ChannelHandlePtr channel_handle;
- mojom::GpuInfoPtr gpu_info;
- connector_->ConnectToInterface("mojo:mus", &gpu_service_);
- {
- base::AutoUnlock auto_unlock(lock_);
- mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
- if (!gpu_service_->EstablishGpuChannel(&client_id, &channel_handle,
- &gpu_info)) {
- DLOG(WARNING)
- << "Channel encountered error while establishing gpu channel.";
- return;
- }
- }
- const bool locked = true;
- EstablishGpuChannelOnMainThreadDone(
- locked, client_id, std::move(channel_handle), std::move(gpu_info));
-}
-
-void GpuService::EstablishGpuChannelOnMainThreadDone(
- bool locked,
- int client_id,
- mojom::ChannelHandlePtr channel_handle,
- mojom::GpuInfoPtr gpu_info) {
- DCHECK(IsMainThread());
- scoped_refptr<gpu::GpuChannelHost> gpu_channel;
- if (client_id) {
- // TODO(penghuang): Get the real gpu info from mus.
- gpu_channel = gpu::GpuChannelHost::Create(
- this, client_id, gpu::GPUInfo(),
- channel_handle.To<IPC::ChannelHandle>(), &shutdown_event_,
- gpu_memory_buffer_manager_.get());
- }
-
- auto auto_lock = base::WrapUnique<base::AutoLock>(
- locked ? nullptr : new base::AutoLock(lock_));
- DCHECK(is_establishing_);
- DCHECK(!gpu_channel_);
-
- is_establishing_ = false;
- gpu_channel_ = gpu_channel;
- establishing_condition_.Broadcast();
-
- for (const auto& i : establish_callbacks_)
- i.Run();
- establish_callbacks_.clear();
- gpu_service_.reset();
-}
-
-bool GpuService::IsMainThread() {
- return main_task_runner_->BelongsToCurrentThread();
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-GpuService::GetIOThreadTaskRunner() {
- return io_thread_.task_runner();
-}
-
-std::unique_ptr<base::SharedMemory> GpuService::AllocateSharedMemory(
- size_t size) {
- mojo::ScopedSharedBufferHandle handle =
- mojo::SharedBufferHandle::Create(size);
- if (!handle.is_valid())
- return nullptr;
-
- base::SharedMemoryHandle platform_handle;
- size_t shared_memory_size;
- bool readonly;
- MojoResult result = mojo::UnwrapSharedMemoryHandle(
- std::move(handle), &platform_handle, &shared_memory_size, &readonly);
- if (result != MOJO_RESULT_OK)
- return nullptr;
- DCHECK_EQ(shared_memory_size, size);
-
- return base::MakeUnique<base::SharedMemory>(platform_handle, readonly);
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/common/gpu_service.h b/chromium/components/mus/common/gpu_service.h
deleted file mode 100644
index a3d5cd106f6..00000000000
--- a/chromium/components/mus/common/gpu_service.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_COMMON_GPU_SERVICE_H_
-#define COMPONENTS_MUS_COMMON_GPU_SERVICE_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "components/mus/common/mojo_gpu_memory_buffer_manager.h"
-#include "components/mus/common/mus_common_export.h"
-#include "components/mus/public/interfaces/gpu_service.mojom.h"
-#include "gpu/ipc/client/gpu_channel_host.h"
-
-namespace shell {
-class Connector;
-}
-
-namespace mus {
-
-class MUS_COMMON_EXPORT GpuService : public gpu::GpuChannelHostFactory {
- public:
- void EstablishGpuChannel(const base::Closure& callback);
- scoped_refptr<gpu::GpuChannelHost> EstablishGpuChannelSync();
- scoped_refptr<gpu::GpuChannelHost> GetGpuChannel();
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager() const {
- return gpu_memory_buffer_manager_.get();
- }
-
- static bool UseChromeGpuCommandBuffer();
-
- // The GpuService has to be initialized in the main thread before establishing
- // the gpu channel.
- static void Initialize(shell::Connector* connector);
- // The GpuService has to be terminated in the main thread.
- static void Terminate();
- static GpuService* GetInstance();
-
- private:
- friend struct base::DefaultSingletonTraits<GpuService>;
-
- explicit GpuService(shell::Connector* connector);
- ~GpuService() override;
-
- scoped_refptr<gpu::GpuChannelHost> GetGpuChannelLocked();
- void EstablishGpuChannelOnMainThread();
- void EstablishGpuChannelOnMainThreadSyncLocked();
- void EstablishGpuChannelOnMainThreadDone(
- bool locked,
- int client_id,
- mojom::ChannelHandlePtr channel_handle,
- mojom::GpuInfoPtr gpu_info);
-
- // gpu::GpuChannelHostFactory overrides:
- bool IsMainThread() override;
- scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() override;
- std::unique_ptr<base::SharedMemory> AllocateSharedMemory(
- size_t size) override;
-
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
- shell::Connector* connector_;
- base::WaitableEvent shutdown_event_;
- base::Thread io_thread_;
- std::unique_ptr<MojoGpuMemoryBufferManager> gpu_memory_buffer_manager_;
-
- // Lock for |gpu_channel_|, |establish_callbacks_| & |is_establishing_|.
- base::Lock lock_;
- bool is_establishing_;
- mus::mojom::GpuServicePtr gpu_service_;
- scoped_refptr<gpu::GpuChannelHost> gpu_channel_;
- std::vector<base::Closure> establish_callbacks_;
- base::ConditionVariable establishing_condition_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuService);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_LIB_GPU_SERVICE_CONNECTION_H_
diff --git a/chromium/components/mus/common/gpu_type_converters.cc b/chromium/components/mus/common/gpu_type_converters.cc
deleted file mode 100644
index 7733c7d3bf7..00000000000
--- a/chromium/components/mus/common/gpu_type_converters.cc
+++ /dev/null
@@ -1,164 +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 "components/mus/common/gpu_type_converters.h"
-
-#include "build/build_config.h"
-#include "gpu/config/gpu_info.h"
-#include "ipc/ipc_channel_handle.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-#include "ui/gfx/gpu_memory_buffer.h"
-
-#if defined(USE_OZONE)
-#include "ui/gfx/native_pixmap_handle_ozone.h"
-#endif
-
-namespace mojo {
-
-// static
-mus::mojom::ChannelHandlePtr
-TypeConverter<mus::mojom::ChannelHandlePtr, IPC::ChannelHandle>::Convert(
- const IPC::ChannelHandle& handle) {
- mus::mojom::ChannelHandlePtr result = mus::mojom::ChannelHandle::New();
- result->name = handle.name;
-#if defined(OS_WIN)
- // On windows, a pipe handle Will NOT be marshalled over IPC.
- DCHECK(handle.pipe.handle == NULL);
-#else
- DCHECK(handle.socket.auto_close || handle.socket.fd == -1);
- base::PlatformFile platform_file = handle.socket.fd;
- if (platform_file != -1)
- result->socket = mojo::WrapPlatformFile(platform_file);
-#endif
- return result;
-}
-
-// static
-IPC::ChannelHandle
-TypeConverter<IPC::ChannelHandle, mus::mojom::ChannelHandlePtr>::Convert(
- const mus::mojom::ChannelHandlePtr& handle) {
- if (handle.is_null())
- return IPC::ChannelHandle();
-#if defined(OS_WIN)
- // On windows, a pipe handle Will NOT be marshalled over IPC.
- DCHECK(!handle->socket.is_valid());
- return IPC::ChannelHandle(handle->name);
-#else
- base::PlatformFile platform_file = -1;
- mojo::UnwrapPlatformFile(std::move(handle->socket), &platform_file);
- return IPC::ChannelHandle(handle->name,
- base::FileDescriptor(platform_file, true));
-#endif
-}
-
-#if defined(USE_OZONE)
-// static
-mus::mojom::NativePixmapHandlePtr TypeConverter<
- mus::mojom::NativePixmapHandlePtr,
- gfx::NativePixmapHandle>::Convert(const gfx::NativePixmapHandle& handle) {
- // TODO(penghuang); support NativePixmapHandle.
- mus::mojom::NativePixmapHandlePtr result =
- mus::mojom::NativePixmapHandle::New();
- return result;
-}
-
-// static
-gfx::NativePixmapHandle
-TypeConverter<gfx::NativePixmapHandle, mus::mojom::NativePixmapHandlePtr>::
- Convert(const mus::mojom::NativePixmapHandlePtr& handle) {
- // TODO(penghuang); support NativePixmapHandle.
- gfx::NativePixmapHandle result;
- return result;
-}
-#endif
-
-// static
-mus::mojom::GpuMemoryBufferIdPtr TypeConverter<
- mus::mojom::GpuMemoryBufferIdPtr,
- gfx::GpuMemoryBufferId>::Convert(const gfx::GpuMemoryBufferId& id) {
- mus::mojom::GpuMemoryBufferIdPtr result =
- mus::mojom::GpuMemoryBufferId::New();
- result->id = id.id;
- return result;
-}
-
-// static
-gfx::GpuMemoryBufferId
-TypeConverter<gfx::GpuMemoryBufferId, mus::mojom::GpuMemoryBufferIdPtr>::
- Convert(const mus::mojom::GpuMemoryBufferIdPtr& id) {
- return gfx::GpuMemoryBufferId(id->id);
-}
-
-// static
-mus::mojom::GpuMemoryBufferHandlePtr TypeConverter<
- mus::mojom::GpuMemoryBufferHandlePtr,
- gfx::GpuMemoryBufferHandle>::Convert(const gfx::GpuMemoryBufferHandle&
- handle) {
- DCHECK(handle.type == gfx::SHARED_MEMORY_BUFFER);
- mus::mojom::GpuMemoryBufferHandlePtr result =
- mus::mojom::GpuMemoryBufferHandle::New();
- result->type = static_cast<mus::mojom::GpuMemoryBufferType>(handle.type);
- result->id = mus::mojom::GpuMemoryBufferId::From(handle.id);
- base::PlatformFile platform_file;
-#if defined(OS_WIN)
- platform_file = handle.handle.GetHandle();
-#else
- DCHECK(handle.handle.auto_close || handle.handle.fd == -1);
- platform_file = handle.handle.fd;
-#endif
- result->buffer_handle = mojo::WrapPlatformFile(platform_file);
- result->offset = handle.offset;
- result->stride = handle.stride;
-#if defined(USE_OZONE)
- result->native_pixmap_handle =
- mus::mojom::NativePixmapHandle::From(handle.native_pixmap_handle);
-#endif
- return result;
-}
-
-// static
-gfx::GpuMemoryBufferHandle TypeConverter<gfx::GpuMemoryBufferHandle,
- mus::mojom::GpuMemoryBufferHandlePtr>::
- Convert(const mus::mojom::GpuMemoryBufferHandlePtr& handle) {
- DCHECK(handle->type == mus::mojom::GpuMemoryBufferType::SHARED_MEMORY);
- gfx::GpuMemoryBufferHandle result;
- result.type = static_cast<gfx::GpuMemoryBufferType>(handle->type);
- result.id = handle->id.To<gfx::GpuMemoryBufferId>();
- base::PlatformFile platform_file;
- MojoResult unwrap_result = mojo::UnwrapPlatformFile(
- std::move(handle->buffer_handle), &platform_file);
- if (unwrap_result == MOJO_RESULT_OK) {
-#if defined(OS_WIN)
- result.handle =
- base::SharedMemoryHandle(platform_file, base::GetCurrentProcId());
-#else
- result.handle = base::SharedMemoryHandle(platform_file, true);
-#endif
- }
- result.offset = handle->offset;
- result.stride = handle->stride;
-#if defined(USE_OZONE)
- result.native_pixmap_handle =
- handle->native_pixmap_handle.To<gfx::NativePixmapHandle>();
-#else
- DCHECK(handle->native_pixmap_handle.is_null());
-#endif
- return result;
-}
-
-// static
-mus::mojom::GpuInfoPtr
-TypeConverter<mus::mojom::GpuInfoPtr, gpu::GPUInfo>::Convert(
- const gpu::GPUInfo& input) {
- mus::mojom::GpuInfoPtr result(mus::mojom::GpuInfo::New());
- result->vendor_id = input.gpu.vendor_id;
- result->device_id = input.gpu.device_id;
- result->vendor_info = mojo::String::From<std::string>(input.gl_vendor);
- result->renderer_info = mojo::String::From<std::string>(input.gl_renderer);
- result->driver_version =
- mojo::String::From<std::string>(input.driver_version);
- return result;
-}
-
-} // namespace mojo
diff --git a/chromium/components/mus/common/gpu_type_converters.h b/chromium/components/mus/common/gpu_type_converters.h
deleted file mode 100644
index 74c170c0437..00000000000
--- a/chromium/components/mus/common/gpu_type_converters.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 COMPONENTS_MUS_COMMON_GPU_TYPE_CONVERTERS_H_
-#define COMPONENTS_MUS_COMMON_GPU_TYPE_CONVERTERS_H_
-
-#include "build/build_config.h"
-#include "components/mus/common/mus_common_export.h"
-#include "components/mus/public/interfaces/channel_handle.mojom.h"
-#include "components/mus/public/interfaces/gpu.mojom.h"
-#include "components/mus/public/interfaces/gpu_memory_buffer.mojom.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-
-namespace gfx {
-struct GpuMemoryBufferHandle;
-class GenericSharedMemoryId;
-using GpuMemoryBufferId = GenericSharedMemoryId;
-struct NativePixmapHandle;
-}
-
-namespace gpu {
-struct GPUInfo;
-}
-
-namespace IPC {
-struct ChannelHandle;
-}
-
-namespace mojo {
-
-template <>
-struct MUS_COMMON_EXPORT
- TypeConverter<mus::mojom::ChannelHandlePtr, IPC::ChannelHandle> {
- static mus::mojom::ChannelHandlePtr Convert(const IPC::ChannelHandle& handle);
-};
-
-template <>
-struct MUS_COMMON_EXPORT
- TypeConverter<IPC::ChannelHandle, mus::mojom::ChannelHandlePtr> {
- static IPC::ChannelHandle Convert(const mus::mojom::ChannelHandlePtr& handle);
-};
-
-#if defined(USE_OZONE)
-template <>
-struct MUS_COMMON_EXPORT
- TypeConverter<mus::mojom::NativePixmapHandlePtr, gfx::NativePixmapHandle> {
- static mus::mojom::NativePixmapHandlePtr Convert(
- const gfx::NativePixmapHandle& handle);
-};
-
-template <>
-struct MUS_COMMON_EXPORT
- TypeConverter<gfx::NativePixmapHandle, mus::mojom::NativePixmapHandlePtr> {
- static gfx::NativePixmapHandle Convert(
- const mus::mojom::NativePixmapHandlePtr& handle);
-};
-#endif
-
-template <>
-struct MUS_COMMON_EXPORT
- TypeConverter<mus::mojom::GpuMemoryBufferIdPtr, gfx::GpuMemoryBufferId> {
- static mus::mojom::GpuMemoryBufferIdPtr Convert(
- const gfx::GpuMemoryBufferId& id);
-};
-
-template <>
-struct MUS_COMMON_EXPORT
- TypeConverter<gfx::GpuMemoryBufferId, mus::mojom::GpuMemoryBufferIdPtr> {
- static gfx::GpuMemoryBufferId Convert(
- const mus::mojom::GpuMemoryBufferIdPtr& id);
-};
-
-template <>
-struct MUS_COMMON_EXPORT TypeConverter<mus::mojom::GpuMemoryBufferHandlePtr,
- gfx::GpuMemoryBufferHandle> {
- static mus::mojom::GpuMemoryBufferHandlePtr Convert(
- const gfx::GpuMemoryBufferHandle& handle);
-};
-
-template <>
-struct MUS_COMMON_EXPORT TypeConverter<gfx::GpuMemoryBufferHandle,
- mus::mojom::GpuMemoryBufferHandlePtr> {
- static gfx::GpuMemoryBufferHandle Convert(
- const mus::mojom::GpuMemoryBufferHandlePtr& handle);
-};
-
-template <>
-struct MUS_COMMON_EXPORT TypeConverter<mus::mojom::GpuInfoPtr, gpu::GPUInfo> {
- static mus::mojom::GpuInfoPtr Convert(const gpu::GPUInfo& input);
-};
-
-} // namespace mojo
-
-#endif // COMPONENTS_MUS_COMMON_GPU_TYPE_CONVERTERS_H_
diff --git a/chromium/components/mus/common/gpu_type_converters_unittest.cc b/chromium/components/mus/common/gpu_type_converters_unittest.cc
deleted file mode 100644
index 012664309d9..00000000000
--- a/chromium/components/mus/common/gpu_type_converters_unittest.cc
+++ /dev/null
@@ -1,94 +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 <string>
-
-#include "base/files/scoped_file.h"
-#include "build/build_config.h"
-#include "components/mus/common/gpu_type_converters.h"
-#include "ipc/ipc_channel.h"
-#include "ipc/ipc_channel_handle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/buffer_types.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/gpu_memory_buffer.h"
-
-// Test for mojo TypeConverter of mus::mojom::ChannelHandle.
-TEST(MusGpuTypeConvertersTest, ChannelHandle) {
- {
- const std::string channel_name = "test_channel_name";
- IPC::ChannelHandle handle(channel_name);
-
- mus::mojom::ChannelHandlePtr mojo_handle =
- mus::mojom::ChannelHandle::From(handle);
- ASSERT_EQ(mojo_handle->name, channel_name);
- EXPECT_FALSE(mojo_handle->socket.is_valid());
-
- handle = mojo_handle.To<IPC::ChannelHandle>();
- ASSERT_EQ(handle.name, channel_name);
-#if defined(OS_POSIX)
- ASSERT_EQ(handle.socket.fd, -1);
-#endif
- }
-
-#if defined(OS_POSIX)
- {
- const std::string channel_name = "test_channel_name";
- int fd1 = -1;
- int fd2 = -1;
- bool result = IPC::SocketPair(&fd1, &fd2);
- EXPECT_TRUE(result);
-
- base::ScopedFD scoped_fd1(fd1);
- base::ScopedFD scoped_fd2(fd2);
- IPC::ChannelHandle handle(channel_name,
- base::FileDescriptor(scoped_fd1.release(), true));
-
- mus::mojom::ChannelHandlePtr mojo_handle =
- mus::mojom::ChannelHandle::From(handle);
- ASSERT_EQ(mojo_handle->name, channel_name);
- EXPECT_TRUE(mojo_handle->socket.is_valid());
-
- handle = mojo_handle.To<IPC::ChannelHandle>();
- ASSERT_EQ(handle.name, channel_name);
- ASSERT_NE(handle.socket.fd, -1);
- EXPECT_TRUE(handle.socket.auto_close);
- base::ScopedFD socped_fd3(handle.socket.fd);
- }
-#endif
-}
-
-// Test for mojo TypeConverter of mus::mojom::GpuMemoryBufferHandle
-TEST(MusGpuTypeConvertersTest, GpuMemoryBufferHandle) {
- const gfx::GpuMemoryBufferId kId(99);
- const uint32_t kOffset = 126;
- const int32_t kStride = 256;
- base::SharedMemory shared_memory;
- ASSERT_TRUE(shared_memory.CreateAnonymous(1024));
- ASSERT_TRUE(shared_memory.Map(1024));
-
- gfx::GpuMemoryBufferHandle handle;
- handle.type = gfx::SHARED_MEMORY_BUFFER;
- handle.id = kId;
- handle.handle = base::SharedMemory::DuplicateHandle(shared_memory.handle());
- handle.offset = kOffset;
- handle.stride = kStride;
-
- mus::mojom::GpuMemoryBufferHandlePtr gpu_handle =
- mus::mojom::GpuMemoryBufferHandle::From<gfx::GpuMemoryBufferHandle>(
- handle);
- ASSERT_EQ(gpu_handle->type, mus::mojom::GpuMemoryBufferType::SHARED_MEMORY);
- ASSERT_EQ(gpu_handle->id->id, 99);
- ASSERT_EQ(gpu_handle->offset, kOffset);
- ASSERT_EQ(gpu_handle->stride, kStride);
-
- handle = gpu_handle.To<gfx::GpuMemoryBufferHandle>();
- ASSERT_EQ(handle.type, gfx::SHARED_MEMORY_BUFFER);
- ASSERT_EQ(handle.id, kId);
- ASSERT_EQ(handle.offset, kOffset);
- ASSERT_EQ(handle.stride, kStride);
-
- base::SharedMemory shared_memory1(handle.handle, true);
- ASSERT_TRUE(shared_memory1.Map(1024));
-}
diff --git a/chromium/components/mus/common/mojo_buffer_backing.cc b/chromium/components/mus/common/mojo_buffer_backing.cc
deleted file mode 100644
index ba9da7fcb0d..00000000000
--- a/chromium/components/mus/common/mojo_buffer_backing.cc
+++ /dev/null
@@ -1,34 +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 "components/mus/common/mojo_buffer_backing.h"
-
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-
-namespace mus {
-
-MojoBufferBacking::MojoBufferBacking(mojo::ScopedSharedBufferMapping mapping,
- size_t size)
- : mapping_(std::move(mapping)), size_(size) {}
-
-MojoBufferBacking::~MojoBufferBacking() = default;
-
-// static
-std::unique_ptr<gpu::BufferBacking> MojoBufferBacking::Create(
- mojo::ScopedSharedBufferHandle handle,
- size_t size) {
- mojo::ScopedSharedBufferMapping mapping = handle->Map(size);
- if (!mapping)
- return nullptr;
- return base::MakeUnique<MojoBufferBacking>(std::move(mapping), size);
-}
-void* MojoBufferBacking::GetMemory() const {
- return mapping_.get();
-}
-size_t MojoBufferBacking::GetSize() const {
- return size_;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/common/mojo_buffer_backing.h b/chromium/components/mus/common/mojo_buffer_backing.h
deleted file mode 100644
index 3f6e33f721e..00000000000
--- a/chromium/components/mus/common/mojo_buffer_backing.h
+++ /dev/null
@@ -1,40 +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 COMPONENTS_MUS_COMMON_MOJO_BUFFER_BACKING_H_
-#define COMPONENTS_MUS_COMMON_MOJO_BUFFER_BACKING_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "components/mus/common/mus_common_export.h"
-#include "gpu/command_buffer/common/buffer.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mus {
-
-class MUS_COMMON_EXPORT MojoBufferBacking : public gpu::BufferBacking {
- public:
- MojoBufferBacking(mojo::ScopedSharedBufferMapping mapping, size_t size);
- ~MojoBufferBacking() override;
-
- static std::unique_ptr<gpu::BufferBacking> Create(
- mojo::ScopedSharedBufferHandle handle,
- size_t size);
-
- void* GetMemory() const override;
- size_t GetSize() const override;
-
- private:
- mojo::ScopedSharedBufferMapping mapping_;
- size_t size_;
-
- DISALLOW_COPY_AND_ASSIGN(MojoBufferBacking);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_COMMON_MOJO_BUFFER_BACKING_H_
diff --git a/chromium/components/mus/common/mojo_gpu_memory_buffer.cc b/chromium/components/mus/common/mojo_gpu_memory_buffer.cc
deleted file mode 100644
index 00b046b068d..00000000000
--- a/chromium/components/mus/common/mojo_gpu_memory_buffer.cc
+++ /dev/null
@@ -1,107 +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 "components/mus/common/mojo_gpu_memory_buffer.h"
-
-#include <stdint.h>
-
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/shared_memory.h"
-#include "base/numerics/safe_conversions.h"
-#include "build/build_config.h"
-#include "mojo/public/cpp/system/buffer.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-#include "ui/gfx/buffer_format_util.h"
-
-namespace mus {
-
-MojoGpuMemoryBufferImpl::MojoGpuMemoryBufferImpl(
- const gfx::Size& size,
- gfx::BufferFormat format,
- std::unique_ptr<base::SharedMemory> shared_memory)
- : GpuMemoryBufferImpl(gfx::GenericSharedMemoryId(0), size, format),
- shared_memory_(std::move(shared_memory)) {}
-
-// TODO(rjkroege): Support running a destructor callback as necessary.
-MojoGpuMemoryBufferImpl::~MojoGpuMemoryBufferImpl() {}
-
-std::unique_ptr<gfx::GpuMemoryBuffer> MojoGpuMemoryBufferImpl::Create(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage) {
- size_t bytes = gfx::BufferSizeForBufferFormat(size, format);
-
- mojo::ScopedSharedBufferHandle handle =
- mojo::SharedBufferHandle::Create(bytes);
- if (!handle.is_valid())
- return nullptr;
-
- base::SharedMemoryHandle platform_handle;
- size_t shared_memory_size;
- bool readonly;
- MojoResult result = mojo::UnwrapSharedMemoryHandle(
- std::move(handle), &platform_handle, &shared_memory_size, &readonly);
- if (result != MOJO_RESULT_OK)
- return nullptr;
- DCHECK_EQ(shared_memory_size, bytes);
-
- auto shared_memory =
- base::MakeUnique<base::SharedMemory>(platform_handle, readonly);
- return base::WrapUnique<gfx::GpuMemoryBuffer>(
- new MojoGpuMemoryBufferImpl(size, format, std::move(shared_memory)));
-}
-
-MojoGpuMemoryBufferImpl* MojoGpuMemoryBufferImpl::FromClientBuffer(
- ClientBuffer buffer) {
- return reinterpret_cast<MojoGpuMemoryBufferImpl*>(buffer);
-}
-
-const unsigned char* MojoGpuMemoryBufferImpl::GetMemory() const {
- return static_cast<const unsigned char*>(shared_memory_->memory());
-}
-
-bool MojoGpuMemoryBufferImpl::Map() {
- DCHECK(!mapped_);
- if (!shared_memory_->Map(gfx::BufferSizeForBufferFormat(size_, format_)))
- return false;
- mapped_ = true;
- return true;
-}
-
-void* MojoGpuMemoryBufferImpl::memory(size_t plane) {
- DCHECK(mapped_);
- DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_));
- return reinterpret_cast<uint8_t*>(shared_memory_->memory()) +
- gfx::BufferOffsetForBufferFormat(size_, format_, plane);
-}
-
-void MojoGpuMemoryBufferImpl::Unmap() {
- DCHECK(mapped_);
- shared_memory_->Unmap();
- mapped_ = false;
-}
-
-int MojoGpuMemoryBufferImpl::stride(size_t plane) const {
- DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_));
- return base::checked_cast<int>(gfx::RowSizeForBufferFormat(
- size_.width(), format_, static_cast<int>(plane)));
-}
-
-gfx::GpuMemoryBufferHandle MojoGpuMemoryBufferImpl::GetHandle() const {
- gfx::GpuMemoryBufferHandle handle;
- handle.type = gfx::SHARED_MEMORY_BUFFER;
- handle.handle = shared_memory_->handle();
- handle.offset = 0;
- handle.stride = static_cast<int32_t>(
- gfx::RowSizeForBufferFormat(size_.width(), format_, 0));
-
- return handle;
-}
-
-gfx::GpuMemoryBufferType MojoGpuMemoryBufferImpl::GetBufferType() const {
- return gfx::SHARED_MEMORY_BUFFER;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/common/mojo_gpu_memory_buffer.h b/chromium/components/mus/common/mojo_gpu_memory_buffer.h
deleted file mode 100644
index ffcbf049185..00000000000
--- a/chromium/components/mus/common/mojo_gpu_memory_buffer.h
+++ /dev/null
@@ -1,54 +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 COMPONENTS_MUS_COMMON_MOJO_GPU_MEMORY_BUFFER_H_
-#define COMPONENTS_MUS_COMMON_MOJO_GPU_MEMORY_BUFFER_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "components/mus/common/gpu_memory_buffer_impl.h"
-#include "components/mus/common/mus_common_export.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/gpu_memory_buffer.h"
-
-namespace mus {
-
-class MUS_COMMON_EXPORT MojoGpuMemoryBufferImpl
- : public mus::GpuMemoryBufferImpl {
- public:
- MojoGpuMemoryBufferImpl(const gfx::Size& size,
- gfx::BufferFormat format,
- std::unique_ptr<base::SharedMemory> shared_memory);
- ~MojoGpuMemoryBufferImpl() override;
-
- static std::unique_ptr<gfx::GpuMemoryBuffer> Create(const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage);
-
- static MojoGpuMemoryBufferImpl* FromClientBuffer(ClientBuffer buffer);
-
- const unsigned char* GetMemory() const;
-
- // Overridden from gfx::GpuMemoryBuffer:
- bool Map() override;
- void* memory(size_t plane) override;
- void Unmap() override;
- int stride(size_t plane) const override;
- gfx::GpuMemoryBufferHandle GetHandle() const override;
-
- // Overridden from gfx::GpuMemoryBufferImpl
- gfx::GpuMemoryBufferType GetBufferType() const override;
-
- private:
- std::unique_ptr<base::SharedMemory> shared_memory_;
-
- DISALLOW_COPY_AND_ASSIGN(MojoGpuMemoryBufferImpl);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_COMMON_MOJO_GPU_MEMORY_BUFFER_H_
diff --git a/chromium/components/mus/common/mojo_gpu_memory_buffer_manager.cc b/chromium/components/mus/common/mojo_gpu_memory_buffer_manager.cc
deleted file mode 100644
index 51decafb326..00000000000
--- a/chromium/components/mus/common/mojo_gpu_memory_buffer_manager.cc
+++ /dev/null
@@ -1,46 +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 "components/mus/common/mojo_gpu_memory_buffer_manager.h"
-
-#include "base/logging.h"
-#include "components/mus/common/mojo_gpu_memory_buffer.h"
-
-namespace mus {
-
-MojoGpuMemoryBufferManager::MojoGpuMemoryBufferManager() {}
-
-MojoGpuMemoryBufferManager::~MojoGpuMemoryBufferManager() {}
-
-std::unique_ptr<gfx::GpuMemoryBuffer>
-MojoGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle) {
- return MojoGpuMemoryBufferImpl::Create(size, format, usage);
-}
-
-std::unique_ptr<gfx::GpuMemoryBuffer>
-MojoGpuMemoryBufferManager::CreateGpuMemoryBufferFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::BufferFormat format) {
- NOTIMPLEMENTED();
- return nullptr;
-}
-
-gfx::GpuMemoryBuffer*
-MojoGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer(
- ClientBuffer buffer) {
- return MojoGpuMemoryBufferImpl::FromClientBuffer(buffer);
-}
-
-void MojoGpuMemoryBufferManager::SetDestructionSyncToken(
- gfx::GpuMemoryBuffer* buffer,
- const gpu::SyncToken& sync_token) {
- NOTIMPLEMENTED();
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/common/mojo_gpu_memory_buffer_manager.h b/chromium/components/mus/common/mojo_gpu_memory_buffer_manager.h
deleted file mode 100644
index e3ce95dfc97..00000000000
--- a/chromium/components/mus/common/mojo_gpu_memory_buffer_manager.h
+++ /dev/null
@@ -1,43 +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 COMPONENTS_MUS_COMMON_MOJO_GPU_MEMORY_BUFFER_MANAGER_H_
-#define COMPONENTS_MUS_COMMON_MOJO_GPU_MEMORY_BUFFER_MANAGER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "components/mus/common/mus_common_export.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
-
-namespace mus {
-
-class MUS_COMMON_EXPORT MojoGpuMemoryBufferManager
- : public gpu::GpuMemoryBufferManager {
- public:
- MojoGpuMemoryBufferManager();
- ~MojoGpuMemoryBufferManager() override;
-
- // Overridden from gpu::GpuMemoryBufferManager:
- std::unique_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle) override;
- std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBufferFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::BufferFormat format) override;
- gfx::GpuMemoryBuffer* GpuMemoryBufferFromClientBuffer(
- ClientBuffer buffer) override;
- void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
- const gpu::SyncToken& sync_token) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MojoGpuMemoryBufferManager);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_COMMON_MOJO_GPU_MEMORY_BUFFER_MANAGER_H_
diff --git a/chromium/components/mus/common/mus_common_export.h b/chromium/components/mus/common/mus_common_export.h
deleted file mode 100644
index 7e7526b6710..00000000000
--- a/chromium/components/mus/common/mus_common_export.h
+++ /dev/null
@@ -1,29 +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.
-
-#ifndef COMPONENTS_MUS_COMMON_MUS_COMMON_EXPORT_H_
-#define COMPONENTS_MUS_COMMON_MUS_COMMON_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(MUS_COMMON_IMPLEMENTATION)
-#define MUS_COMMON_EXPORT __declspec(dllexport)
-#else
-#define MUS_COMMON_EXPORT __declspec(dllimport)
-#endif // defined(MUS_COMMON_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(MUS_COMMON_IMPLEMENTATION)
-#define MUS_COMMON_EXPORT __attribute__((visibility("default")))
-#else
-#define MUS_COMMON_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define MUS_COMMON_EXPORT
-#endif
-
-#endif // COMPONENTS_MUS_COMMON_MUS_COMMON_EXPORT_H_
diff --git a/chromium/components/mus/common/mus_common_unittests_app_manifest.json b/chromium/components/mus/common/mus_common_unittests_app_manifest.json
deleted file mode 100644
index 5240ae9b6a9..00000000000
--- a/chromium/components/mus/common/mus_common_unittests_app_manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "manifest_version": 1,
- "name": "mojo:mus_common_unittests_app",
- "display_name": "Mus Common Unittests",
- "capabilities": {
- "required": {
- "*": { "classes": [ "app" ] }
- }
- }
-}
diff --git a/chromium/components/mus/common/run_all_shelltests.cc b/chromium/components/mus/common/run_all_shelltests.cc
deleted file mode 100644
index e795983ec58..00000000000
--- a/chromium/components/mus/common/run_all_shelltests.cc
+++ /dev/null
@@ -1,34 +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 "base/test/launcher/unit_test_launcher.h"
-#include "base/test/test_suite.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "services/shell/background/background_shell_main.h"
-
-#if defined(USE_OZONE)
-#include "ui/ozone/public/ozone_platform.h"
-#endif
-
-class MusGpuTestSuite : public base::TestSuite {
- public:
- MusGpuTestSuite(int argc, char** argv) : base::TestSuite(argc, argv) {}
-
- private:
- void Initialize() override {
- base::TestSuite::Initialize();
-#if defined(USE_OZONE)
- ui::OzonePlatform::InitializeForGPU();
-#endif
- }
-};
-
-int MasterProcessMain(int argc, char** argv) {
- MusGpuTestSuite test_suite(argc, argv);
- mojo::edk::Init();
- return base::LaunchUnitTests(
- argc, argv,
- base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
-}
diff --git a/chromium/components/mus/common/switches.cc b/chromium/components/mus/common/switches.cc
deleted file mode 100644
index f9bead3ed54..00000000000
--- a/chromium/components/mus/common/switches.cc
+++ /dev/null
@@ -1,20 +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 "components/mus/common/switches.h"
-
-namespace mus {
-namespace switches {
-
-// Use mojo GPU command buffer instead of Chrome GPU command buffer.
-const char kUseMojoGpuCommandBufferInMus[] =
- "use-mojo-gpu-command-buffer-in-mus";
-
-// Initializes X11 in threaded mode, and sets the |override_redirect| flag when
-// creating X11 windows. Also, exposes the WindowServerTest interface to clients
-// when launched with this flag.
-const char kUseTestConfig[] = "use-test-config";
-
-} // namespace switches
-} // namespace mus
diff --git a/chromium/components/mus/common/switches.h b/chromium/components/mus/common/switches.h
deleted file mode 100644
index 492aa4c3113..00000000000
--- a/chromium/components/mus/common/switches.h
+++ /dev/null
@@ -1,21 +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 COMPONENTS_MUS_COMMON_SWITCHES_H_
-#define COMPONENTS_MUS_COMMON_SWITCHES_H_
-
-#include "components/mus/common/mus_common_export.h"
-
-namespace mus {
-namespace switches {
-
-// All args in alphabetical order. The switches should be documented
-// alongside the definition of their values in the .cc file.
-extern const char MUS_COMMON_EXPORT kUseMojoGpuCommandBufferInMus[];
-extern const char MUS_COMMON_EXPORT kUseTestConfig[];
-
-} // namespace switches
-} // namespace mus
-
-#endif // COMPONENTS_MUS_COMMON_SWITCHES_H_
diff --git a/chromium/components/mus/common/transient_window_utils.h b/chromium/components/mus/common/transient_window_utils.h
deleted file mode 100644
index 17eedc63a25..00000000000
--- a/chromium/components/mus/common/transient_window_utils.h
+++ /dev/null
@@ -1,126 +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 COMPONENTS_MUS_COMMON_TRANSIENT_WINDOW_UTILS_H_
-#define COMPONENTS_MUS_COMMON_TRANSIENT_WINDOW_UTILS_H_
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "components/mus/public/interfaces/mus_constants.mojom.h"
-
-namespace mus {
-
-// Returns true if |window| has |ancestor| as a transient ancestor. A transient
-// ancestor is found by following the transient parent chain of the window.
-template <class T>
-bool HasTransientAncestor(const T* window, const T* ancestor) {
- const T* transient_parent = window->transient_parent();
- if (transient_parent == ancestor)
- return true;
- return transient_parent ? HasTransientAncestor(transient_parent, ancestor)
- : false;
-}
-
-// Populates |ancestors| with all transient ancestors of |window| that are
-// siblings of |window|. Returns true if any ancestors were found, false if not.
-template <class T>
-bool GetAllTransientAncestors(T* window, std::vector<T*>* ancestors) {
- T* parent = window->parent();
- for (; window; window = window->transient_parent()) {
- if (window->parent() == parent)
- ancestors->push_back(window);
- }
- return !ancestors->empty();
-}
-
-// Replaces |window1| and |window2| with their possible transient ancestors that
-// are still siblings (have a common transient parent). |window1| and |window2|
-// are not modified if such ancestors cannot be found.
-template <class T>
-void FindCommonTransientAncestor(T** window1, T** window2) {
- DCHECK(window1);
- DCHECK(window2);
- DCHECK(*window1);
- DCHECK(*window2);
- // Assemble chains of ancestors of both windows.
- std::vector<T*> ancestors1;
- std::vector<T*> ancestors2;
- if (!GetAllTransientAncestors(*window1, &ancestors1) ||
- !GetAllTransientAncestors(*window2, &ancestors2)) {
- return;
- }
- // Walk the two chains backwards and look for the first difference.
- auto it1 = ancestors1.rbegin();
- auto it2 = ancestors2.rbegin();
- for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) {
- if (*it1 != *it2) {
- *window1 = *it1;
- *window2 = *it2;
- break;
- }
- }
-}
-
-template <class T>
-bool AdjustStackingForTransientWindows(T** child,
- T** target,
- mojom::OrderDirection* direction,
- T* stacking_target) {
- if (stacking_target == *target)
- return true;
-
- // For windows that have transient children stack the transient ancestors that
- // are siblings. This prevents one transient group from being inserted in the
- // middle of another.
- FindCommonTransientAncestor(child, target);
-
- // When stacking above skip to the topmost transient descendant of the target.
- if (*direction == mojom::OrderDirection::ABOVE &&
- !HasTransientAncestor(*child, *target)) {
- const std::vector<T*>& siblings((*child)->parent()->children());
- size_t target_i =
- std::find(siblings.begin(), siblings.end(), *target) - siblings.begin();
- while (target_i + 1 < siblings.size() &&
- HasTransientAncestor(siblings[target_i + 1], *target)) {
- ++target_i;
- }
- *target = siblings[target_i];
- }
-
- return *child != *target;
-}
-
-// Stacks transient descendants of |window| that are its siblings just above it.
-// |GetStackingTarget| is a function that returns a marker associated with a
-// Window that indicates the current Window being stacked.
-// |Reorder| is a function that takes in two windows and orders the first
-// relative to the second based on the provided OrderDirection.
-template <class T>
-void RestackTransientDescendants(T* window,
- T** (*GetStackingTarget)(T*),
- void (*Reorder)(T*,
- T*,
- mojom::OrderDirection)) {
- T* parent = window->parent();
- if (!parent)
- return;
-
- // stack any transient children that share the same parent to be in front of
- // |window_|. the existing stacking order is preserved by iterating backwards
- // and always stacking on top.
- std::vector<T*> children(parent->children());
- for (auto it = children.rbegin(); it != children.rend(); ++it) {
- if ((*it) != window && HasTransientAncestor(*it, window)) {
- T* old_stacking_target = *GetStackingTarget(*it);
- *GetStackingTarget(*it) = window;
- Reorder(*it, window, mojom::OrderDirection::ABOVE);
- *GetStackingTarget(*it) = old_stacking_target;
- }
- }
-}
-} // namespace mus
-
-#endif // COMPONENTS_MUS_COMMON_TRANSIENT_WINDOW_UTILS_H_
diff --git a/chromium/components/mus/common/types.h b/chromium/components/mus/common/types.h
deleted file mode 100644
index 93b96683e6b..00000000000
--- a/chromium/components/mus/common/types.h
+++ /dev/null
@@ -1,25 +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 COMPONENTS_MUS_COMMON_TYPES_H_
-#define COMPONENTS_MUS_COMMON_TYPES_H_
-
-#include <stdint.h>
-
-// Typedefs for the transport types. These typedefs match that of the mojom
-// file, see it for specifics.
-
-namespace mus {
-
-// Used to identify windows and change ids.
-typedef uint32_t Id;
-
-// Used to identify a client as well as a client-specific window id. For
-// example, the Id for a window consists of the ClientSpecificId of the client
-// and the ClientSpecificId of the window.
-typedef uint16_t ClientSpecificId;
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_COMMON_TYPES_H_
diff --git a/chromium/components/mus/common/util.h b/chromium/components/mus/common/util.h
deleted file mode 100644
index daa59efc6b1..00000000000
--- a/chromium/components/mus/common/util.h
+++ /dev/null
@@ -1,32 +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 COMPONENTS_MUS_COMMON_UTIL_H_
-#define COMPONENTS_MUS_COMMON_UTIL_H_
-
-#include <stdint.h>
-
-#include "components/mus/common/types.h"
-
-// TODO(beng): #$*&@#(@ MacOSX SDK!
-#if defined(HiWord)
-#undef HiWord
-#endif
-#if defined(LoWord)
-#undef LoWord
-#endif
-
-namespace mus {
-
-inline uint16_t HiWord(uint32_t id) {
- return static_cast<uint16_t>((id >> 16) & 0xFFFF);
-}
-
-inline uint16_t LoWord(uint32_t id) {
- return static_cast<uint16_t>(id & 0xFFFF);
-}
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_COMMON_UTIL_H_
diff --git a/chromium/components/mus/demo/BUILD.gn b/chromium/components/mus/demo/BUILD.gn
deleted file mode 100644
index 8cabdfdb005..00000000000
--- a/chromium/components/mus/demo/BUILD.gn
+++ /dev/null
@@ -1,42 +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.
-
-import("//mojo/public/mojo_application.gni")
-import("//mojo/public/mojo_application_manifest.gni")
-
-mojo_native_application("mus_demo") {
- sources = [
- "main.cc",
- "mus_demo.cc",
- "mus_demo.h",
- ]
-
- deps = [
- "//base",
- "//components/bitmap_uploader",
- "//components/mus/public/cpp",
- "//components/mus/public/interfaces",
- "//mojo/public/cpp/bindings",
- "//services/shell/public/cpp",
- "//services/shell/public/cpp:sources",
- "//skia",
- "//ui/gfx/geometry",
- ]
-
- data_deps = [
- ":manifest",
- "//components/mus",
- ]
-}
-
-mojo_application_manifest("manifest") {
- application_name = "mus_demo"
- source = "manifest.json"
-}
-
-group("demo") {
- deps = [
- ":mus_demo",
- ]
-}
diff --git a/chromium/components/mus/demo/DEPS b/chromium/components/mus/demo/DEPS
deleted file mode 100644
index ce521506ba2..00000000000
--- a/chromium/components/mus/demo/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+components/bitmap_uploader",
-]
-
diff --git a/chromium/components/mus/demo/OWNERS b/chromium/components/mus/demo/OWNERS
deleted file mode 100644
index 47351aafac9..00000000000
--- a/chromium/components/mus/demo/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-kylechar@chromium.org
-rjkroege@chromium.org
diff --git a/chromium/components/mus/demo/main.cc b/chromium/components/mus/demo/main.cc
deleted file mode 100644
index 62be1b7d81d..00000000000
--- a/chromium/components/mus/demo/main.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/mus/demo/mus_demo.h"
-#include "mojo/public/c/system/main.h"
-#include "services/shell/public/cpp/application_runner.h"
-
-MojoResult MojoMain(MojoHandle shell_handle) {
- shell::ApplicationRunner runner(new mus_demo::MusDemo);
- runner.set_message_loop_type(base::MessageLoop::TYPE_UI);
- return runner.Run(shell_handle);
-}
diff --git a/chromium/components/mus/demo/manifest.json b/chromium/components/mus/demo/manifest.json
deleted file mode 100644
index 7971b79d238..00000000000
--- a/chromium/components/mus/demo/manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "manifest_version": 1,
- "name": "mojo:mus_demo",
- "display_name": "MUS Demo",
- "capabilities": {
- "required": {
- "mojo:mus": {
- "interfaces": [ "mus::mojom::WindowManagerWindowTreeFactory"],
- "classes": [ "app" ]
- }
- }
- }
-}
-
diff --git a/chromium/components/mus/demo/mus_demo.cc b/chromium/components/mus/demo/mus_demo.cc
deleted file mode 100644
index 0853f5ab48c..00000000000
--- a/chromium/components/mus/demo/mus_demo.cc
+++ /dev/null
@@ -1,179 +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 "components/mus/demo/mus_demo.h"
-
-#include "base/time/time.h"
-#include "components/bitmap_uploader/bitmap_uploader.h"
-#include "components/mus/common/gpu_service.h"
-#include "components/mus/public/cpp/window.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-#include "services/shell/public/cpp/connector.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkImageInfo.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace mus_demo {
-
-namespace {
-
-// Milliseconds between frames.
-const int64_t kFrameDelay = 33;
-
-// Size of square in pixels to draw.
-const int kSquareSize = 300;
-
-const SkColor kBgColor = SK_ColorRED;
-const SkColor kFgColor = SK_ColorYELLOW;
-
-void DrawSquare(const gfx::Rect& bounds, double angle, SkCanvas* canvas) {
- // Create SkRect to draw centered inside the bounds.
- gfx::Point top_left = bounds.CenterPoint();
- top_left.Offset(-kSquareSize / 2, -kSquareSize / 2);
- SkRect rect =
- SkRect::MakeXYWH(top_left.x(), top_left.y(), kSquareSize, kSquareSize);
-
- // Set SkPaint to fill solid color.
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(kFgColor);
-
- // Rotate the canvas.
- const gfx::Size canvas_size = bounds.size();
- if (angle != 0.0) {
- canvas->translate(SkFloatToScalar(canvas_size.width() * 0.5f),
- SkFloatToScalar(canvas_size.height() * 0.5f));
- canvas->rotate(angle);
- canvas->translate(-SkFloatToScalar(canvas_size.width() * 0.5f),
- -SkFloatToScalar(canvas_size.height() * 0.5f));
- }
-
- canvas->drawRect(rect, paint);
-}
-
-} // namespace
-
-MusDemo::MusDemo() {}
-
-MusDemo::~MusDemo() {
- delete window_tree_client_;
-}
-
-void MusDemo::Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) {
- connector_ = connector;
- mus::GpuService::Initialize(connector_);
- window_tree_client_ = new mus::WindowTreeClient(this, this, nullptr);
- window_tree_client_->ConnectAsWindowManager(connector);
-}
-
-bool MusDemo::AcceptConnection(shell::Connection* connection) {
- return true;
-}
-
-void MusDemo::OnEmbed(mus::Window* window) {
- // Not called for the WindowManager.
- NOTREACHED();
-}
-
-void MusDemo::OnWindowTreeClientDestroyed(mus::WindowTreeClient* client) {
- window_tree_client_ = nullptr;
- timer_.Stop();
-}
-
-void MusDemo::OnEventObserved(const ui::Event& event, mus::Window* target) {}
-
-void MusDemo::SetWindowManagerClient(mus::WindowManagerClient* client) {}
-
-bool MusDemo::OnWmSetBounds(mus::Window* window, gfx::Rect* bounds) {
- return true;
-}
-
-bool MusDemo::OnWmSetProperty(mus::Window* window,
- const std::string& name,
- std::unique_ptr<std::vector<uint8_t>>* new_data) {
- return true;
-}
-
-mus::Window* MusDemo::OnWmCreateTopLevelWindow(
- std::map<std::string, std::vector<uint8_t>>* properties) {
- return nullptr;
-}
-
-void MusDemo::OnWmClientJankinessChanged(
- const std::set<mus::Window*>& client_windows,
- bool janky) {
- // Don't care
-}
-
-void MusDemo::OnWmNewDisplay(mus::Window* window,
- const display::Display& display) {
- DCHECK(!window_); // Only support one display.
- window_ = window;
-
- // Initialize bitmap uploader for sending frames to MUS.
- uploader_.reset(new bitmap_uploader::BitmapUploader(window_));
- uploader_->Init(connector_);
-
- // Draw initial frame and start the timer to regularly draw frames.
- DrawFrame();
- timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kFrameDelay),
- base::Bind(&MusDemo::DrawFrame, base::Unretained(this)));
-}
-
-void MusDemo::OnAccelerator(uint32_t id, const ui::Event& event) {
- // Don't care
-}
-
-void MusDemo::AllocBitmap() {
- const gfx::Rect bounds = window_->GetBoundsInRoot();
-
- // Allocate bitmap the same size as the window for drawing.
- bitmap_.reset();
- SkImageInfo image_info = SkImageInfo::MakeN32(bounds.width(), bounds.height(),
- kPremul_SkAlphaType);
- bitmap_.allocPixels(image_info);
-}
-
-void MusDemo::DrawFrame() {
- angle_ += 2.0;
- if (angle_ >= 360.0)
- angle_ = 0.0;
-
- const gfx::Rect bounds = window_->GetBoundsInRoot();
-
- // Check that bitmap and window sizes match, otherwise reallocate bitmap.
- const SkImageInfo info = bitmap_.info();
- if (info.width() != bounds.width() || info.height() != bounds.height()) {
- AllocBitmap();
- }
-
- // Draw the rotated square on background in bitmap.
- SkCanvas canvas(bitmap_);
- canvas.clear(kBgColor);
- // TODO(kylechar): Add GL drawing instead of software rasterization in future.
- DrawSquare(bounds, angle_, &canvas);
- canvas.flush();
-
- // Copy pixels data into vector that will be passed to BitmapUploader.
- // TODO(rjkroege): Make a 1/0-copy bitmap uploader for the contents of a
- // SkBitmap.
- bitmap_.lockPixels();
- const unsigned char* addr =
- static_cast<const unsigned char*>(bitmap_.getPixels());
- const int bytes = bounds.width() * bounds.height() * 4;
- std::unique_ptr<std::vector<unsigned char>> data(
- new std::vector<unsigned char>(addr, addr + bytes));
- bitmap_.unlockPixels();
-
- // Send frame to MUS via BitmapUploader.
- uploader_->SetBitmap(bounds.width(), bounds.height(), std::move(data),
- bitmap_uploader::BitmapUploader::BGRA);
-}
-
-} // namespace mus_demo
diff --git a/chromium/components/mus/demo/mus_demo.h b/chromium/components/mus/demo/mus_demo.h
deleted file mode 100644
index dbb62647294..00000000000
--- a/chromium/components/mus/demo/mus_demo.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_DEMO_MUS_DEMO_H_
-#define COMPONENTS_MUS_DEMO_MUS_DEMO_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/timer/timer.h"
-#include "components/mus/public/cpp/window_manager_delegate.h"
-#include "components/mus/public/cpp/window_tree_client_delegate.h"
-#include "services/shell/public/cpp/shell_client.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace bitmap_uploader {
-class BitmapUploader;
-}
-
-namespace mus_demo {
-
-// A simple MUS Demo mojo app. This app connects to the mojo:mus, creates a new
-// window and draws a spinning square in the center of the window. Provides a
-// simple way to demonstrate that the graphic stack works as intended.
-class MusDemo : public shell::ShellClient,
- public mus::WindowTreeClientDelegate,
- public mus::WindowManagerDelegate {
- public:
- MusDemo();
- ~MusDemo() override;
-
- private:
- // shell::ShellClient:
- void Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) override;
- bool AcceptConnection(shell::Connection* connection) override;
-
- // WindowTreeClientDelegate:
- void OnEmbed(mus::Window* root) override;
- void OnWindowTreeClientDestroyed(mus::WindowTreeClient* client) override;
- void OnEventObserved(const ui::Event& event, mus::Window* target) override;
-
- // WindowManagerDelegate:
- void SetWindowManagerClient(mus::WindowManagerClient* client) override;
- bool OnWmSetBounds(mus::Window* window, gfx::Rect* bounds) override;
- bool OnWmSetProperty(
- mus::Window* window,
- const std::string& name,
- std::unique_ptr<std::vector<uint8_t>>* new_data) override;
- mus::Window* OnWmCreateTopLevelWindow(
- std::map<std::string, std::vector<uint8_t>>* properties) override;
- void OnWmClientJankinessChanged(const std::set<mus::Window*>& client_windows,
- bool janky) override;
- void OnWmNewDisplay(mus::Window* window,
- const display::Display& display) override;
- void OnAccelerator(uint32_t id, const ui::Event& event) override;
-
- // Allocate a bitmap the same size as the window to draw into.
- void AllocBitmap();
-
- // Draws one frame, incrementing the rotation angle.
- void DrawFrame();
-
- shell::Connector* connector_ = nullptr;
-
- mus::Window* window_ = nullptr;
- mus::WindowTreeClient* window_tree_client_ = nullptr;
-
- // Used to send frames to mus.
- std::unique_ptr<bitmap_uploader::BitmapUploader> uploader_;
-
- // Bitmap that is the same size as our client window area.
- SkBitmap bitmap_;
-
- // Timer for calling DrawFrame().
- base::RepeatingTimer timer_;
-
- // Current rotation angle for drawing.
- double angle_ = 0.0;
-
- DISALLOW_COPY_AND_ASSIGN(MusDemo);
-};
-
-} // namespace mus_demo
-
-#endif // COMPONENTS_MUS_DEMO_MUS_DEMO_H_
diff --git a/chromium/components/mus/gles2/BUILD.gn b/chromium/components/mus/gles2/BUILD.gn
deleted file mode 100644
index 57ef1b28d83..00000000000
--- a/chromium/components/mus/gles2/BUILD.gn
+++ /dev/null
@@ -1,89 +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("//build/config/ui.gni")
-
-source_set("gles2") {
- visibility = [
- "//components/mus:*",
- "//components/mus/ws:*",
- "//components/mus/surfaces:*",
- "//services/shell/standalone:lib", # For android
- ]
-
- sources = [
- "command_buffer_driver.cc",
- "command_buffer_driver.h",
- "command_buffer_driver_manager.cc",
- "command_buffer_driver_manager.h",
- "command_buffer_impl.cc",
- "command_buffer_impl.h",
- "command_buffer_local.cc",
- "command_buffer_local.h",
- "command_buffer_local_client.h",
- "command_buffer_task_runner.cc",
- "command_buffer_task_runner.h",
- "gl_surface_adapter.cc",
- "gl_surface_adapter.h",
- "gpu_impl.cc",
- "gpu_impl.h",
- "gpu_memory_tracker.cc",
- "gpu_memory_tracker.h",
- "gpu_state.cc",
- "gpu_state.h",
- ]
-
- public_deps = [
- ":lib",
- ]
- deps = [
- "//base",
- "//components/mus/common:mus_common",
- "//components/mus/public/interfaces",
- "//gpu/command_buffer/client",
- "//gpu/command_buffer/client:gles2_interface",
- "//gpu/command_buffer/common:gles2_utils",
- "//gpu/command_buffer/service",
- "//gpu/config:config",
- "//mojo/public/cpp/bindings",
- "//mojo/public/cpp/system",
- "//ui/gfx",
- "//ui/gfx/geometry",
- "//ui/gfx/geometry/mojo",
- "//ui/gl",
- "//ui/gl/init",
- ]
-
- if (use_ozone) {
- deps += [ "//ui/ozone:ozone" ]
- sources += [
- "ozone_gpu_memory_buffer.cc",
- "ozone_gpu_memory_buffer.h",
- ]
- }
-
- include_dirs = [ "../.." ]
-}
-
-source_set("lib") {
- sources = [
- "raster_thread_helper.cc",
- "raster_thread_helper.h",
- ]
-
- deps = [
- "//base",
- "//cc",
- "//components/mus/public/interfaces",
- "//gpu/command_buffer/client",
- "//gpu/command_buffer/common",
- "//gpu/config:config",
- "//mojo/public/cpp/bindings",
- "//mojo/public/cpp/system",
- "//ui/gfx",
- "//ui/gfx/geometry",
- ]
-
- include_dirs = [ "../.." ]
-}
diff --git a/chromium/components/mus/gles2/DEPS b/chromium/components/mus/gles2/DEPS
deleted file mode 100644
index 2ad979f2443..00000000000
--- a/chromium/components/mus/gles2/DEPS
+++ /dev/null
@@ -1,8 +0,0 @@
-include_rules = [
- "+cc",
- "+components/gpu",
- "+gpu",
- "+mojo/converters",
- "+mojo/public",
- "+ui",
-]
diff --git a/chromium/components/mus/gles2/OWNERS b/chromium/components/mus/gles2/OWNERS
deleted file mode 100644
index 1f1af6bcc54..00000000000
--- a/chromium/components/mus/gles2/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-fsamuel@chromium.org
-rjkroege@chromium.org
diff --git a/chromium/components/mus/gles2/command_buffer_driver.cc b/chromium/components/mus/gles2/command_buffer_driver.cc
deleted file mode 100644
index 1c35904e9f6..00000000000
--- a/chromium/components/mus/gles2/command_buffer_driver.cc
+++ /dev/null
@@ -1,568 +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 "components/mus/gles2/command_buffer_driver.h"
-
-#include <stddef.h>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/memory/shared_memory.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "components/mus/common/mojo_buffer_backing.h"
-#include "components/mus/gles2/gl_surface_adapter.h"
-#include "components/mus/gles2/gpu_memory_tracker.h"
-#include "components/mus/gles2/gpu_state.h"
-#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
-#include "gpu/command_buffer/service/command_buffer_service.h"
-#include "gpu/command_buffer/service/command_executor.h"
-#include "gpu/command_buffer/service/context_group.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
-#include "gpu/command_buffer/service/image_manager.h"
-#include "gpu/command_buffer/service/mailbox_manager.h"
-#include "gpu/command_buffer/service/query_manager.h"
-#include "gpu/command_buffer/service/sync_point_manager.h"
-#include "gpu/command_buffer/service/transfer_buffer_manager.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-#include "ui/gfx/buffer_format_util.h"
-#include "ui/gfx/gpu_memory_buffer.h"
-#include "ui/gfx/vsync_provider.h"
-#include "ui/gl/gl_context.h"
-#include "ui/gl/gl_image_shared_memory.h"
-#include "ui/gl/gl_surface.h"
-#include "ui/gl/init/gl_factory.h"
-
-#if defined(USE_OZONE)
-#include "ui/gl/gl_image_ozone_native_pixmap.h"
-#endif
-
-namespace mus {
-
-namespace {
-
-// The first time polling a fence, delay some extra time to allow other
-// stubs to process some work, or else the timing of the fences could
-// allow a pattern of alternating fast and slow frames to occur.
-const int64_t kHandleMoreWorkPeriodMs = 2;
-const int64_t kHandleMoreWorkPeriodBusyMs = 1;
-
-// Prevents idle work from being starved.
-const int64_t kMaxTimeSinceIdleMs = 10;
-
-} // namespace
-
-CommandBufferDriver::Client::~Client() {}
-
-CommandBufferDriver::CommandBufferDriver(
- gpu::CommandBufferNamespace command_buffer_namespace,
- gpu::CommandBufferId command_buffer_id,
- gfx::AcceleratedWidget widget,
- scoped_refptr<GpuState> gpu_state)
- : command_buffer_namespace_(command_buffer_namespace),
- command_buffer_id_(command_buffer_id),
- widget_(widget),
- client_(nullptr),
- gpu_state_(gpu_state),
- previous_processed_num_(0),
- weak_factory_(this) {
- DCHECK_EQ(base::ThreadTaskRunnerHandle::Get(),
- gpu_state_->command_buffer_task_runner()->task_runner());
-}
-
-CommandBufferDriver::~CommandBufferDriver() {
- DCHECK(CalledOnValidThread());
- DestroyDecoder();
-}
-
-bool CommandBufferDriver::Initialize(
- mojo::ScopedSharedBufferHandle shared_state,
- mojo::Array<int32_t> attribs) {
- DCHECK(CalledOnValidThread());
- gpu::gles2::ContextCreationAttribHelper attrib_helper;
- if (!attrib_helper.Parse(attribs.storage()))
- return false;
- // TODO(piman): attribs can't currently represent gpu_preference.
-
- const bool offscreen = widget_ == gfx::kNullAcceleratedWidget;
- if (offscreen) {
- surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size(0, 0));
- } else {
-#if defined(USE_OZONE)
- scoped_refptr<gl::GLSurface> underlying_surface =
- gl::init::CreateSurfacelessViewGLSurface(widget_);
- if (!underlying_surface)
- underlying_surface = gl::init::CreateViewGLSurface(widget_);
-#else
- scoped_refptr<gl::GLSurface> underlying_surface =
- gl::init::CreateViewGLSurface(widget_);
-#endif
- scoped_refptr<GLSurfaceAdapterMus> surface_adapter =
- new GLSurfaceAdapterMus(underlying_surface);
- surface_adapter->SetGpuCompletedSwapBuffersCallback(
- base::Bind(&CommandBufferDriver::OnGpuCompletedSwapBuffers,
- weak_factory_.GetWeakPtr()));
- surface_ = surface_adapter;
-
- gfx::VSyncProvider* vsync_provider =
- surface_ ? surface_->GetVSyncProvider() : nullptr;
- if (vsync_provider) {
- vsync_provider->GetVSyncParameters(
- base::Bind(&CommandBufferDriver::OnUpdateVSyncParameters,
- weak_factory_.GetWeakPtr()));
- }
- }
-
- if (!surface_.get())
- return false;
-
- // TODO(piman): virtual contexts.
- context_ = gl::init::CreateGLContext(
- gpu_state_->share_group(), surface_.get(), attrib_helper.gpu_preference);
- if (!context_.get())
- return false;
-
- if (!context_->MakeCurrent(surface_.get()))
- return false;
-
- // TODO(piman): ShaderTranslatorCache is currently per-ContextGroup but
- // only needs to be per-thread.
- const bool bind_generates_resource = attrib_helper.bind_generates_resource;
- scoped_refptr<gpu::gles2::FeatureInfo> feature_info =
- new gpu::gles2::FeatureInfo(gpu_state_->gpu_driver_bug_workarounds());
- // TODO(erikchen): The ContextGroup needs a reference to the
- // GpuMemoryBufferManager.
- scoped_refptr<gpu::gles2::ContextGroup> context_group =
- new gpu::gles2::ContextGroup(
- gpu_state_->gpu_preferences(), gpu_state_->mailbox_manager(),
- new GpuMemoryTracker,
- new gpu::gles2::ShaderTranslatorCache(gpu_state_->gpu_preferences()),
- new gpu::gles2::FramebufferCompletenessCache, feature_info,
- bind_generates_resource, nullptr);
-
- command_buffer_.reset(
- new gpu::CommandBufferService(context_group->transfer_buffer_manager()));
-
- decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group.get()));
- executor_.reset(new gpu::CommandExecutor(command_buffer_.get(),
- decoder_.get(), decoder_.get()));
- sync_point_order_data_ = gpu::SyncPointOrderData::Create();
- sync_point_client_ = gpu_state_->sync_point_manager()->CreateSyncPointClient(
- sync_point_order_data_, GetNamespaceID(), command_buffer_id_);
- decoder_->set_engine(executor_.get());
- decoder_->SetFenceSyncReleaseCallback(base::Bind(
- &CommandBufferDriver::OnFenceSyncRelease, base::Unretained(this)));
- decoder_->SetWaitFenceSyncCallback(base::Bind(
- &CommandBufferDriver::OnWaitFenceSync, base::Unretained(this)));
- decoder_->SetDescheduleUntilFinishedCallback(base::Bind(
- &CommandBufferDriver::OnDescheduleUntilFinished, base::Unretained(this)));
- decoder_->SetRescheduleAfterFinishedCallback(base::Bind(
- &CommandBufferDriver::OnRescheduleAfterFinished, base::Unretained(this)));
-
- gpu::gles2::DisallowedFeatures disallowed_features;
-
- if (!decoder_->Initialize(surface_, context_, offscreen, disallowed_features,
- attrib_helper))
- return false;
-
- command_buffer_->SetPutOffsetChangeCallback(base::Bind(
- &gpu::CommandExecutor::PutChanged, base::Unretained(executor_.get())));
- command_buffer_->SetGetBufferChangeCallback(base::Bind(
- &gpu::CommandExecutor::SetGetBuffer, base::Unretained(executor_.get())));
- command_buffer_->SetParseErrorCallback(
- base::Bind(&CommandBufferDriver::OnParseError, base::Unretained(this)));
-
- // TODO(piman): other callbacks
-
- const size_t kSize = sizeof(gpu::CommandBufferSharedState);
- std::unique_ptr<gpu::BufferBacking> backing(
- MojoBufferBacking::Create(std::move(shared_state), kSize));
- if (!backing)
- return false;
-
- command_buffer_->SetSharedStateBuffer(std::move(backing));
- gpu_state_->driver_manager()->AddDriver(this);
- return true;
-}
-
-void CommandBufferDriver::SetGetBuffer(int32_t buffer) {
- DCHECK(CalledOnValidThread());
- command_buffer_->SetGetBuffer(buffer);
-}
-
-void CommandBufferDriver::Flush(int32_t put_offset) {
- DCHECK(CalledOnValidThread());
- if (!MakeCurrent())
- return;
-
- command_buffer_->Flush(put_offset);
- ProcessPendingAndIdleWork();
-}
-
-void CommandBufferDriver::RegisterTransferBuffer(
- int32_t id,
- mojo::ScopedSharedBufferHandle transfer_buffer,
- uint32_t size) {
- DCHECK(CalledOnValidThread());
- // Take ownership of the memory and map it into this process.
- // This validates the size.
- std::unique_ptr<gpu::BufferBacking> backing(
- MojoBufferBacking::Create(std::move(transfer_buffer), size));
- if (!backing) {
- DVLOG(0) << "Failed to map shared memory.";
- return;
- }
- command_buffer_->RegisterTransferBuffer(id, std::move(backing));
-}
-
-void CommandBufferDriver::DestroyTransferBuffer(int32_t id) {
- DCHECK(CalledOnValidThread());
- command_buffer_->DestroyTransferBuffer(id);
-}
-
-void CommandBufferDriver::CreateImage(int32_t id,
- mojo::ScopedHandle memory_handle,
- int32_t type,
- const gfx::Size& size,
- int32_t format,
- int32_t internal_format) {
- DCHECK(CalledOnValidThread());
- if (!MakeCurrent())
- return;
-
- gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
- if (image_manager->LookupImage(id)) {
- LOG(ERROR) << "Image already exists with same ID.";
- return;
- }
-
- gfx::BufferFormat gpu_format = static_cast<gfx::BufferFormat>(format);
- if (!gpu::IsGpuMemoryBufferFormatSupported(gpu_format,
- decoder_->GetCapabilities())) {
- LOG(ERROR) << "Format is not supported.";
- return;
- }
-
- if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(size, gpu_format)) {
- LOG(ERROR) << "Invalid image size for format.";
- return;
- }
-
- if (!gpu::IsImageFormatCompatibleWithGpuMemoryBufferFormat(internal_format,
- gpu_format)) {
- LOG(ERROR) << "Incompatible image format.";
- return;
- }
-
- if (type != gfx::SHARED_MEMORY_BUFFER) {
- NOTIMPLEMENTED();
- return;
- }
-
- base::PlatformFile platform_file;
- MojoResult unwrap_result = mojo::UnwrapPlatformFile(std::move(memory_handle),
- &platform_file);
- if (unwrap_result != MOJO_RESULT_OK) {
- NOTREACHED();
- return;
- }
-
-#if defined(OS_WIN)
- base::SharedMemoryHandle handle(platform_file, base::GetCurrentProcId());
-#else
- base::FileDescriptor handle(platform_file, false);
-#endif
-
- scoped_refptr<gl::GLImageSharedMemory> image =
- new gl::GLImageSharedMemory(size, internal_format);
- // TODO(jam): also need a mojo enum for this enum
- if (!image->Initialize(
- handle, gfx::GpuMemoryBufferId(id), gpu_format, 0,
- gfx::RowSizeForBufferFormat(size.width(), gpu_format, 0))) {
- NOTREACHED();
- return;
- }
-
- image_manager->AddImage(image.get(), id);
-}
-
-// TODO(rjkroege): It is conceivable that this code belongs in
-// ozone_gpu_memory_buffer.cc
-void CommandBufferDriver::CreateImageNativeOzone(int32_t id,
- int32_t type,
- gfx::Size size,
- gfx::BufferFormat format,
- uint32_t internal_format,
- ui::NativePixmap* pixmap) {
-#if defined(USE_OZONE)
- gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
- if (image_manager->LookupImage(id)) {
- LOG(ERROR) << "Image already exists with same ID.";
- return;
- }
-
- scoped_refptr<gl::GLImageOzoneNativePixmap> image =
- new gl::GLImageOzoneNativePixmap(size, internal_format);
- if (!image->Initialize(pixmap, format)) {
- NOTREACHED();
- return;
- }
-
- image_manager->AddImage(image.get(), id);
-#endif
-}
-
-void CommandBufferDriver::DestroyImage(int32_t id) {
- DCHECK(CalledOnValidThread());
- gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
- if (!image_manager->LookupImage(id)) {
- LOG(ERROR) << "Image with ID doesn't exist.";
- return;
- }
- if (!MakeCurrent())
- return;
- image_manager->RemoveImage(id);
-}
-
-bool CommandBufferDriver::IsScheduled() const {
- DCHECK(CalledOnValidThread());
- DCHECK(executor_);
- return executor_->scheduled();
-}
-
-bool CommandBufferDriver::HasUnprocessedCommands() const {
- DCHECK(CalledOnValidThread());
- if (command_buffer_) {
- gpu::CommandBuffer::State state = GetLastState();
- return command_buffer_->GetPutOffset() != state.get_offset &&
- !gpu::error::IsError(state.error);
- }
- return false;
-}
-
-gpu::Capabilities CommandBufferDriver::GetCapabilities() const {
- DCHECK(CalledOnValidThread());
- return decoder_->GetCapabilities();
-}
-
-gpu::CommandBuffer::State CommandBufferDriver::GetLastState() const {
- DCHECK(CalledOnValidThread());
- return command_buffer_->GetLastState();
-}
-
-uint32_t CommandBufferDriver::GetUnprocessedOrderNum() const {
- DCHECK(CalledOnValidThread());
- return sync_point_order_data_->unprocessed_order_num();
-}
-
-uint32_t CommandBufferDriver::GetProcessedOrderNum() const {
- DCHECK(CalledOnValidThread());
- return sync_point_order_data_->processed_order_num();
-}
-
-bool CommandBufferDriver::MakeCurrent() {
- DCHECK(CalledOnValidThread());
- if (!decoder_)
- return false;
- if (decoder_->MakeCurrent())
- return true;
- DLOG(ERROR) << "Context lost because MakeCurrent failed.";
- gpu::error::ContextLostReason reason =
- static_cast<gpu::error::ContextLostReason>(
- decoder_->GetContextLostReason());
- command_buffer_->SetContextLostReason(reason);
- command_buffer_->SetParseError(gpu::error::kLostContext);
- OnContextLost(reason);
- return false;
-}
-
-void CommandBufferDriver::ProcessPendingAndIdleWork() {
- DCHECK(CalledOnValidThread());
- executor_->ProcessPendingQueries();
- ScheduleDelayedWork(
- base::TimeDelta::FromMilliseconds(kHandleMoreWorkPeriodMs));
-}
-
-void CommandBufferDriver::ScheduleDelayedWork(base::TimeDelta delay) {
- DCHECK(CalledOnValidThread());
- const bool has_more_work =
- executor_->HasPendingQueries() || executor_->HasMoreIdleWork();
- if (!has_more_work) {
- last_idle_time_ = base::TimeTicks();
- return;
- }
-
- const base::TimeTicks current_time = base::TimeTicks::Now();
- // |process_delayed_work_time_| is set if processing of delayed work is
- // already scheduled. Just update the time if already scheduled.
- if (!process_delayed_work_time_.is_null()) {
- process_delayed_work_time_ = current_time + delay;
- return;
- }
-
- // Idle when no messages are processed between now and when PollWork is
- // called.
- previous_processed_num_ =
- gpu_state_->driver_manager()->GetProcessedOrderNum();
-
- if (last_idle_time_.is_null())
- last_idle_time_ = current_time;
-
- // scheduled() returns true after passing all unschedule fences and this is
- // when we can start performing idle work. Idle work is done synchronously
- // so we can set delay to 0 and instead poll for more work at the rate idle
- // work is performed. This also ensures that idle work is done as
- // efficiently as possible without any unnecessary delays.
- if (executor_->scheduled() && executor_->HasMoreIdleWork())
- delay = base::TimeDelta();
-
- process_delayed_work_time_ = current_time + delay;
- gpu_state_->command_buffer_task_runner()->task_runner()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&CommandBufferDriver::PollWork, weak_factory_.GetWeakPtr()),
- delay);
-}
-
-void CommandBufferDriver::PollWork() {
- DCHECK(CalledOnValidThread());
- // Post another delayed task if we have not yet reached the time at which
- // we should process delayed work.
- base::TimeTicks current_time = base::TimeTicks::Now();
- DCHECK(!process_delayed_work_time_.is_null());
- if (process_delayed_work_time_ > current_time) {
- gpu_state_->command_buffer_task_runner()->task_runner()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&CommandBufferDriver::PollWork, weak_factory_.GetWeakPtr()),
- process_delayed_work_time_ - current_time);
- return;
- }
- process_delayed_work_time_ = base::TimeTicks();
- PerformWork();
-}
-
-void CommandBufferDriver::PerformWork() {
- DCHECK(CalledOnValidThread());
- if (!MakeCurrent())
- return;
-
- if (executor_) {
- const uint32_t current_unprocessed_num =
- gpu_state_->driver_manager()->GetUnprocessedOrderNum();
- // We're idle when no messages were processed or scheduled.
- bool is_idle = (previous_processed_num_ == current_unprocessed_num);
- if (!is_idle && !last_idle_time_.is_null()) {
- base::TimeDelta time_since_idle =
- base::TimeTicks::Now() - last_idle_time_;
- base::TimeDelta max_time_since_idle =
- base::TimeDelta::FromMilliseconds(kMaxTimeSinceIdleMs);
- // Force idle when it's been too long since last time we were idle.
- if (time_since_idle > max_time_since_idle)
- is_idle = true;
- }
-
- if (is_idle) {
- last_idle_time_ = base::TimeTicks::Now();
- executor_->PerformIdleWork();
- }
- executor_->ProcessPendingQueries();
- }
-
- ScheduleDelayedWork(
- base::TimeDelta::FromMilliseconds(kHandleMoreWorkPeriodBusyMs));
-}
-
-void CommandBufferDriver::DestroyDecoder() {
- DCHECK(CalledOnValidThread());
- if (decoder_) {
- gpu_state_->driver_manager()->RemoveDriver(this);
- bool have_context = decoder_->MakeCurrent();
- decoder_->Destroy(have_context);
- decoder_.reset();
- }
-}
-
-void CommandBufferDriver::OnUpdateVSyncParameters(
- const base::TimeTicks timebase,
- const base::TimeDelta interval) {
- DCHECK(CalledOnValidThread());
- if (client_)
- client_->UpdateVSyncParameters(timebase, interval);
-}
-
-void CommandBufferDriver::OnFenceSyncRelease(uint64_t release) {
- DCHECK(CalledOnValidThread());
- if (!sync_point_client_->client_state()->IsFenceSyncReleased(release))
- sync_point_client_->ReleaseFenceSync(release);
-}
-
-bool CommandBufferDriver::OnWaitFenceSync(
- gpu::CommandBufferNamespace namespace_id,
- gpu::CommandBufferId command_buffer_id,
- uint64_t release) {
- DCHECK(CalledOnValidThread());
- DCHECK(IsScheduled());
- gpu::SyncPointManager* sync_point_manager = gpu_state_->sync_point_manager();
- DCHECK(sync_point_manager);
-
- scoped_refptr<gpu::SyncPointClientState> release_state =
- sync_point_manager->GetSyncPointClientState(namespace_id,
- command_buffer_id);
-
- if (!release_state)
- return true;
-
- executor_->SetScheduled(false);
- sync_point_client_->Wait(release_state.get(), release,
- base::Bind(&gpu::CommandExecutor::SetScheduled,
- executor_->AsWeakPtr(), true));
- return executor_->scheduled();
-}
-
-void CommandBufferDriver::OnDescheduleUntilFinished() {
- DCHECK(CalledOnValidThread());
- DCHECK(IsScheduled());
- DCHECK(executor_->HasMoreIdleWork());
-
- executor_->SetScheduled(false);
-}
-
-void CommandBufferDriver::OnRescheduleAfterFinished() {
- DCHECK(CalledOnValidThread());
- DCHECK(!executor_->scheduled());
-
- executor_->SetScheduled(true);
-}
-
-void CommandBufferDriver::OnParseError() {
- DCHECK(CalledOnValidThread());
- gpu::CommandBuffer::State state = GetLastState();
- OnContextLost(state.context_lost_reason);
-}
-
-void CommandBufferDriver::OnContextLost(uint32_t reason) {
- DCHECK(CalledOnValidThread());
- if (client_)
- client_->DidLoseContext(reason);
-}
-
-void CommandBufferDriver::SignalQuery(uint32_t query_id,
- const base::Closure& callback) {
- DCHECK(CalledOnValidThread());
-
- gpu::gles2::QueryManager* query_manager = decoder_->GetQueryManager();
- gpu::gles2::QueryManager::Query* query = query_manager->GetQuery(query_id);
- if (query)
- query->AddCallback(callback);
- else
- callback.Run();
-}
-
-void CommandBufferDriver::OnGpuCompletedSwapBuffers(gfx::SwapResult result) {
- DCHECK(CalledOnValidThread());
- if (client_) {
- client_->OnGpuCompletedSwapBuffers(result);
- }
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gles2/command_buffer_driver.h b/chromium/components/mus/gles2/command_buffer_driver.h
deleted file mode 100644
index bb08ee255fe..00000000000
--- a/chromium/components/mus/gles2/command_buffer_driver.h
+++ /dev/null
@@ -1,173 +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.
-
-#ifndef COMPONENTS_MUS_GLES2_COMMAND_BUFFER_DRIVER_H_
-#define COMPONENTS_MUS_GLES2_COMMAND_BUFFER_DRIVER_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/non_thread_safe.h"
-#include "base/time/time.h"
-#include "gpu/command_buffer/common/capabilities.h"
-#include "gpu/command_buffer/common/command_buffer.h"
-#include "gpu/command_buffer/common/command_buffer_id.h"
-#include "gpu/command_buffer/common/constants.h"
-#include "mojo/public/cpp/bindings/array.h"
-#include "mojo/public/cpp/system/buffer.h"
-#include "ui/gfx/buffer_types.h"
-#include "ui/gfx/geometry/mojo/geometry.mojom.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/swap_result.h"
-
-namespace gl {
-class GLContext;
-class GLSurface;
-}
-
-namespace gpu {
-class CommandBufferService;
-class CommandExecutor;
-class SyncPointClient;
-class SyncPointOrderData;
-
-namespace gles2 {
-class GLES2Decoder;
-} // namespace gles2
-
-} // namespace gpu
-
-namespace ui {
-class NativePixmap;
-}
-
-namespace mus {
-
-class GpuState;
-
-// This class receives CommandBuffer messages on the same thread as the native
-// viewport.
-class CommandBufferDriver : base::NonThreadSafe {
- public:
- class Client {
- public:
- virtual ~Client();
- virtual void DidLoseContext(uint32_t reason) = 0;
- virtual void UpdateVSyncParameters(const base::TimeTicks& timebase,
- const base::TimeDelta& interval) = 0;
- virtual void OnGpuCompletedSwapBuffers(gfx::SwapResult result) = 0;
- };
- CommandBufferDriver(gpu::CommandBufferNamespace command_buffer_namespace,
- gpu::CommandBufferId command_buffer_id,
- gfx::AcceleratedWidget widget,
- scoped_refptr<GpuState> gpu_state);
- ~CommandBufferDriver();
-
- // The class owning the CommandBufferDriver instance (e.g. CommandBufferLocal)
- // is itself the Client implementation so CommandBufferDriver does not own the
- // client.
- void set_client(Client* client) { client_ = client; }
-
- bool Initialize(mojo::ScopedSharedBufferHandle shared_state,
- mojo::Array<int32_t> attribs);
- void SetGetBuffer(int32_t buffer);
- void Flush(int32_t put_offset);
- void RegisterTransferBuffer(int32_t id,
- mojo::ScopedSharedBufferHandle transfer_buffer,
- uint32_t size);
- void DestroyTransferBuffer(int32_t id);
- void CreateImage(int32_t id,
- mojo::ScopedHandle memory_handle,
- int32_t type,
- const gfx::Size& size,
- int32_t format,
- int32_t internal_format);
- void CreateImageNativeOzone(int32_t id,
- int32_t type,
- gfx::Size size,
- gfx::BufferFormat format,
- uint32_t internal_format,
- ui::NativePixmap* pixmap);
- void DestroyImage(int32_t id);
- bool IsScheduled() const;
- bool HasUnprocessedCommands() const;
- gpu::Capabilities GetCapabilities() const;
- gpu::CommandBuffer::State GetLastState() const;
- gpu::CommandBufferNamespace GetNamespaceID() const {
- return command_buffer_namespace_;
- }
- gpu::CommandBufferId GetCommandBufferID() const { return command_buffer_id_; }
- gpu::SyncPointOrderData* sync_point_order_data() {
- return sync_point_order_data_.get();
- }
- uint32_t GetUnprocessedOrderNum() const;
- uint32_t GetProcessedOrderNum() const;
- void SignalQuery(uint32_t query_id, const base::Closure& callback);
-
- private:
- bool MakeCurrent();
-
- // Process pending queries and call |ScheduleDelayedWork| to schedule
- // processing of delayed work.
- void ProcessPendingAndIdleWork();
-
- // Schedule processing of delayed work. This updates the time at which
- // delayed work should be processed. |process_delayed_work_time_| is
- // updated to current time + delay. Call this after processing some amount
- // of delayed work.
- void ScheduleDelayedWork(base::TimeDelta delay);
-
- // Poll the command buffer to execute work.
- void PollWork();
- void PerformWork();
-
- void DestroyDecoder();
-
- // Callbacks:
- void OnUpdateVSyncParameters(const base::TimeTicks timebase,
- const base::TimeDelta interval);
- void OnFenceSyncRelease(uint64_t release);
- bool OnWaitFenceSync(gpu::CommandBufferNamespace namespace_id,
- gpu::CommandBufferId command_buffer_id,
- uint64_t release);
- void OnDescheduleUntilFinished();
- void OnRescheduleAfterFinished();
- void OnParseError();
- void OnContextLost(uint32_t reason);
- void OnGpuCompletedSwapBuffers(gfx::SwapResult result);
-
- const gpu::CommandBufferNamespace command_buffer_namespace_;
- const gpu::CommandBufferId command_buffer_id_;
- gfx::AcceleratedWidget widget_;
- Client* client_; // NOT OWNED.
- std::unique_ptr<gpu::CommandBufferService> command_buffer_;
- std::unique_ptr<gpu::gles2::GLES2Decoder> decoder_;
- std::unique_ptr<gpu::CommandExecutor> executor_;
- scoped_refptr<gpu::SyncPointOrderData> sync_point_order_data_;
- std::unique_ptr<gpu::SyncPointClient> sync_point_client_;
- scoped_refptr<gl::GLContext> context_;
- scoped_refptr<gl::GLSurface> surface_;
- scoped_refptr<GpuState> gpu_state_;
-
- scoped_refptr<base::SingleThreadTaskRunner> context_lost_task_runner_;
- base::Callback<void(int32_t)> context_lost_callback_;
-
- base::TimeTicks process_delayed_work_time_;
- uint32_t previous_processed_num_;
- base::TimeTicks last_idle_time_;
-
- base::WeakPtrFactory<CommandBufferDriver> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(CommandBufferDriver);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_GLES2_COMMAND_BUFFER_DRIVER_H_
diff --git a/chromium/components/mus/gles2/command_buffer_driver_manager.cc b/chromium/components/mus/gles2/command_buffer_driver_manager.cc
deleted file mode 100644
index c8ff3b95a2f..00000000000
--- a/chromium/components/mus/gles2/command_buffer_driver_manager.cc
+++ /dev/null
@@ -1,50 +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 "components/mus/gles2/command_buffer_driver_manager.h"
-
-#include <algorithm>
-
-#include "components/mus/gles2/command_buffer_driver.h"
-
-namespace mus {
-
-CommandBufferDriverManager::CommandBufferDriverManager() {}
-
-CommandBufferDriverManager::~CommandBufferDriverManager() {}
-
-void CommandBufferDriverManager::AddDriver(CommandBufferDriver* driver) {
- DCHECK(CalledOnValidThread());
- DCHECK(std::find(drivers_.begin(), drivers_.end(), driver) == drivers_.end());
- drivers_.push_back(driver);
-}
-
-void CommandBufferDriverManager::RemoveDriver(CommandBufferDriver* driver) {
- DCHECK(CalledOnValidThread());
- auto it = std::find(drivers_.begin(), drivers_.end(), driver);
- DCHECK(it != drivers_.end());
- drivers_.erase(it);
-}
-
-uint32_t CommandBufferDriverManager::GetUnprocessedOrderNum() const {
- DCHECK(CalledOnValidThread());
- uint32_t unprocessed_order_num = 0;
- for (auto& d : drivers_) {
- unprocessed_order_num =
- std::max(unprocessed_order_num, d->GetUnprocessedOrderNum());
- }
- return unprocessed_order_num;
-}
-
-uint32_t CommandBufferDriverManager::GetProcessedOrderNum() const {
- DCHECK(CalledOnValidThread());
- uint32_t processed_order_num = 0;
- for (auto& d : drivers_) {
- processed_order_num =
- std::max(processed_order_num, d->GetProcessedOrderNum());
- }
- return processed_order_num;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gles2/command_buffer_driver_manager.h b/chromium/components/mus/gles2/command_buffer_driver_manager.h
deleted file mode 100644
index b2f8e7c0900..00000000000
--- a/chromium/components/mus/gles2/command_buffer_driver_manager.h
+++ /dev/null
@@ -1,46 +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 COMPONENTS_MUS_GLES2_COMMAND_BUFFER_DRIVER_MANAGER_H_
-#define COMPONENTS_MUS_GLES2_COMMAND_BUFFER_DRIVER_MANAGER_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/threading/non_thread_safe.h"
-
-namespace mus {
-
-class CommandBufferDriver;
-
-// This class manages all initialized |CommandBufferDriver|s.
-class CommandBufferDriverManager : base::NonThreadSafe {
- public:
- CommandBufferDriverManager();
- ~CommandBufferDriverManager();
-
- // Add a new initialized driver to the manager.
- void AddDriver(CommandBufferDriver* driver);
-
- // Remove a driver from the manager.
- void RemoveDriver(CommandBufferDriver* driver);
-
- // Return the global order number for the last unprocessed flush
- // (|CommandBufferDriver::Flush|).
- uint32_t GetUnprocessedOrderNum() const;
-
- // Return the global order number for the last processed flush
- // (|CommandBufferDriver::Flush|).
- uint32_t GetProcessedOrderNum() const;
-
- private:
- std::vector<CommandBufferDriver*> drivers_;
-
- DISALLOW_COPY_AND_ASSIGN(CommandBufferDriverManager);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_GLES2_COMMAND_BUFFER_DRIVER_MANAGER_H_
diff --git a/chromium/components/mus/gles2/command_buffer_impl.cc b/chromium/components/mus/gles2/command_buffer_impl.cc
deleted file mode 100644
index 70de3c2aab6..00000000000
--- a/chromium/components/mus/gles2/command_buffer_impl.cc
+++ /dev/null
@@ -1,301 +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 "components/mus/gles2/command_buffer_impl.h"
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "components/mus/common/gpu_type_converters.h"
-#include "components/mus/gles2/command_buffer_driver.h"
-#include "components/mus/gles2/gpu_state.h"
-#include "gpu/command_buffer/service/sync_point_manager.h"
-
-namespace mus {
-
-namespace {
-
-uint64_t g_next_command_buffer_id = 0;
-
-void RunInitializeCallback(
- const mojom::CommandBuffer::InitializeCallback& callback,
- mojom::CommandBufferInitializeResultPtr result) {
- callback.Run(std::move(result));
-}
-
-void RunMakeProgressCallback(
- const mojom::CommandBuffer::MakeProgressCallback& callback,
- const gpu::CommandBuffer::State& state) {
- callback.Run(state);
-}
-
-} // namespace
-
-CommandBufferImpl::CommandBufferImpl(
- mojo::InterfaceRequest<mus::mojom::CommandBuffer> request,
- scoped_refptr<GpuState> gpu_state)
- : gpu_state_(gpu_state) {
- // Bind |CommandBufferImpl| to the |request| in the GPU control thread.
- gpu_state_->control_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&CommandBufferImpl::BindToRequest,
- base::Unretained(this), base::Passed(&request)));
-}
-
-void CommandBufferImpl::DidLoseContext(uint32_t reason) {
- driver_->set_client(nullptr);
- client_->Destroyed(reason, gpu::error::kLostContext);
-}
-
-void CommandBufferImpl::UpdateVSyncParameters(const base::TimeTicks& timebase,
- const base::TimeDelta& interval) {
-}
-
-void CommandBufferImpl::OnGpuCompletedSwapBuffers(gfx::SwapResult result) {}
-
-CommandBufferImpl::~CommandBufferImpl() {
-}
-
-void CommandBufferImpl::Initialize(
- mus::mojom::CommandBufferClientPtr client,
- mojo::ScopedSharedBufferHandle shared_state,
- mojo::Array<int32_t> attribs,
- const mojom::CommandBuffer::InitializeCallback& callback) {
- gpu_state_->command_buffer_task_runner()->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&CommandBufferImpl::InitializeOnGpuThread,
- base::Unretained(this), base::Passed(&client),
- base::Passed(&shared_state), base::Passed(&attribs),
- base::Bind(&RunInitializeCallback, callback)));
-}
-
-void CommandBufferImpl::SetGetBuffer(int32_t buffer) {
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(), base::Bind(&CommandBufferImpl::SetGetBufferOnGpuThread,
- base::Unretained(this), buffer));
-}
-
-void CommandBufferImpl::Flush(int32_t put_offset) {
- gpu::SyncPointManager* sync_point_manager = gpu_state_->sync_point_manager();
- const uint32_t order_num = driver_->sync_point_order_data()
- ->GenerateUnprocessedOrderNumber(sync_point_manager);
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(), base::Bind(&CommandBufferImpl::FlushOnGpuThread,
- base::Unretained(this), put_offset, order_num));
-}
-
-void CommandBufferImpl::MakeProgress(
- int32_t last_get_offset,
- const mojom::CommandBuffer::MakeProgressCallback& callback) {
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(), base::Bind(&CommandBufferImpl::MakeProgressOnGpuThread,
- base::Unretained(this), last_get_offset,
- base::Bind(&RunMakeProgressCallback,
- callback)));
-}
-
-void CommandBufferImpl::RegisterTransferBuffer(
- int32_t id,
- mojo::ScopedSharedBufferHandle transfer_buffer,
- uint32_t size) {
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(),
- base::Bind(&CommandBufferImpl::RegisterTransferBufferOnGpuThread,
- base::Unretained(this), id, base::Passed(&transfer_buffer),
- size));
-}
-
-void CommandBufferImpl::DestroyTransferBuffer(int32_t id) {
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(),
- base::Bind(&CommandBufferImpl::DestroyTransferBufferOnGpuThread,
- base::Unretained(this), id));
-}
-
-void CommandBufferImpl::CreateImage(int32_t id,
- mojo::ScopedHandle memory_handle,
- int32_t type,
- const gfx::Size& size,
- int32_t format,
- int32_t internal_format) {
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(),
- base::Bind(&CommandBufferImpl::CreateImageOnGpuThread,
- base::Unretained(this), id, base::Passed(&memory_handle), type,
- size, format, internal_format));
-}
-
-void CommandBufferImpl::DestroyImage(int32_t id) {
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(), base::Bind(&CommandBufferImpl::DestroyImageOnGpuThread,
- base::Unretained(this), id));
-}
-
-void CommandBufferImpl::CreateStreamTexture(
- uint32_t client_texture_id,
- const mojom::CommandBuffer::CreateStreamTextureCallback& callback) {
- NOTIMPLEMENTED();
-}
-
-void CommandBufferImpl::TakeFrontBuffer(const gpu::Mailbox& mailbox) {
- NOTIMPLEMENTED();
-}
-
-void CommandBufferImpl::ReturnFrontBuffer(const gpu::Mailbox& mailbox,
- bool is_lost) {
- NOTIMPLEMENTED();
-}
-
-void CommandBufferImpl::SignalQuery(uint32_t query, uint32_t signal_id) {
- NOTIMPLEMENTED();
-}
-
-void CommandBufferImpl::SignalSyncToken(const gpu::SyncToken& sync_token,
- uint32_t signal_id) {
- NOTIMPLEMENTED();
-}
-
-void CommandBufferImpl::WaitForGetOffsetInRange(
- int32_t start, int32_t end,
- const mojom::CommandBuffer::WaitForGetOffsetInRangeCallback& callback) {
- NOTIMPLEMENTED();
-}
-
-void CommandBufferImpl::WaitForTokenInRange(
- int32_t start, int32_t end,
- const mojom::CommandBuffer::WaitForGetOffsetInRangeCallback& callback) {
- NOTIMPLEMENTED();
-}
-
-void CommandBufferImpl::BindToRequest(
- mojo::InterfaceRequest<mus::mojom::CommandBuffer> request) {
- binding_.reset(
- new mojo::Binding<mus::mojom::CommandBuffer>(this, std::move(request)));
- binding_->set_connection_error_handler(
- base::Bind(&CommandBufferImpl::OnConnectionError,
- base::Unretained(this)));
-}
-
-void CommandBufferImpl::InitializeOnGpuThread(
- mojom::CommandBufferClientPtr client,
- mojo::ScopedSharedBufferHandle shared_state,
- mojo::Array<int32_t> attribs,
- const base::Callback<
- void(mojom::CommandBufferInitializeResultPtr)>& callback) {
- DCHECK(!driver_);
- driver_.reset(new CommandBufferDriver(
- gpu::CommandBufferNamespace::MOJO,
- gpu::CommandBufferId::FromUnsafeValue(++g_next_command_buffer_id),
- gfx::kNullAcceleratedWidget, gpu_state_));
- driver_->set_client(this);
- client_ = mojo::MakeProxy(client.PassInterface());
- bool result =
- driver_->Initialize(std::move(shared_state), std::move(attribs));
- mojom::CommandBufferInitializeResultPtr initialize_result;
- if (result) {
- initialize_result = mojom::CommandBufferInitializeResult::New();
- initialize_result->command_buffer_namespace = driver_->GetNamespaceID();
- initialize_result->command_buffer_id =
- driver_->GetCommandBufferID().GetUnsafeValue();
- initialize_result->capabilities = driver_->GetCapabilities();
- }
- gpu_state_->control_task_runner()->PostTask(
- FROM_HERE, base::Bind(callback, base::Passed(&initialize_result)));
-}
-
-bool CommandBufferImpl::SetGetBufferOnGpuThread(int32_t buffer) {
- DCHECK(driver_->IsScheduled());
- driver_->SetGetBuffer(buffer);
- return true;
-}
-
-bool CommandBufferImpl::FlushOnGpuThread(int32_t put_offset,
- uint32_t order_num) {
- DCHECK(driver_->IsScheduled());
- driver_->sync_point_order_data()->BeginProcessingOrderNumber(order_num);
- driver_->Flush(put_offset);
-
- // Return false if the Flush is not finished, so the CommandBufferTaskRunner
- // will not remove this task from the task queue.
- const bool complete = !driver_->HasUnprocessedCommands();
- if (!complete)
- driver_->sync_point_order_data()->PauseProcessingOrderNumber(order_num);
- else
- driver_->sync_point_order_data()->FinishProcessingOrderNumber(order_num);
- return complete;
-}
-
-bool CommandBufferImpl::MakeProgressOnGpuThread(
- int32_t last_get_offset,
- const base::Callback<void(const gpu::CommandBuffer::State&)>& callback) {
- DCHECK(driver_->IsScheduled());
- gpu_state_->control_task_runner()->PostTask(
- FROM_HERE, base::Bind(callback, driver_->GetLastState()));
- return true;
-}
-
-bool CommandBufferImpl::RegisterTransferBufferOnGpuThread(
- int32_t id,
- mojo::ScopedSharedBufferHandle transfer_buffer,
- uint32_t size) {
- DCHECK(driver_->IsScheduled());
- driver_->RegisterTransferBuffer(id, std::move(transfer_buffer), size);
- return true;
-}
-
-bool CommandBufferImpl::DestroyTransferBufferOnGpuThread(int32_t id) {
- DCHECK(driver_->IsScheduled());
- driver_->DestroyTransferBuffer(id);
- return true;
-}
-
-bool CommandBufferImpl::CreateImageOnGpuThread(int32_t id,
- mojo::ScopedHandle memory_handle,
- int32_t type,
- const gfx::Size& size,
- int32_t format,
- int32_t internal_format) {
- DCHECK(driver_->IsScheduled());
- driver_->CreateImage(id, std::move(memory_handle), type, std::move(size),
- format, internal_format);
- return true;
-}
-
-bool CommandBufferImpl::DestroyImageOnGpuThread(int32_t id) {
- DCHECK(driver_->IsScheduled());
- driver_->DestroyImage(id);
- return true;
-}
-
-void CommandBufferImpl::OnConnectionError() {
- // OnConnectionError() is called on the control thread |control_task_runner|.
-
- // Before deleting, we need to delete |binding_| because it is bound to the
- // current thread (|control_task_runner|).
- binding_.reset();
-
- // Objects we own (such as CommandBufferDriver) need to be destroyed on the
- // thread we were created on. It's entirely possible we haven't or are in the
- // process of creating |driver_|.
- if (driver_) {
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(), base::Bind(&CommandBufferImpl::DeleteOnGpuThread,
- base::Unretained(this)));
- } else {
- gpu_state_->command_buffer_task_runner()->task_runner()->PostTask(
- FROM_HERE, base::Bind(&CommandBufferImpl::DeleteOnGpuThread2,
- base::Unretained(this)));
- }
-}
-
-bool CommandBufferImpl::DeleteOnGpuThread() {
- delete this;
- return true;
-}
-
-void CommandBufferImpl::DeleteOnGpuThread2() {
- delete this;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gles2/command_buffer_impl.h b/chromium/components/mus/gles2/command_buffer_impl.h
deleted file mode 100644
index a37f2d1ec43..00000000000
--- a/chromium/components/mus/gles2/command_buffer_impl.h
+++ /dev/null
@@ -1,126 +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 COMPONENTS_MUS_GLES2_COMMAND_BUFFER_IMPL_H_
-#define COMPONENTS_MUS_GLES2_COMMAND_BUFFER_IMPL_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "components/mus/gles2/command_buffer_driver.h"
-#include "components/mus/public/interfaces/command_buffer.mojom.h"
-#include "gpu/command_buffer/common/command_buffer.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace mus {
-
-class CommandBufferDriver;
-class GpuState;
-
-// This class listens to the CommandBuffer message pipe on a low-latency thread
-// so that we can insert sync points without blocking on the GL driver. It
-// forwards most method calls to the CommandBufferDriver, which runs on the
-// same thread as the native viewport.
-class CommandBufferImpl : public mojom::CommandBuffer,
- public CommandBufferDriver::Client {
- public:
- CommandBufferImpl(mojo::InterfaceRequest<CommandBuffer> request,
- scoped_refptr<GpuState> gpu_state);
-
- private:
- class CommandBufferDriverClientImpl;
- ~CommandBufferImpl() override;
-
- // CommandBufferDriver::Client. All called on the GPU thread.
- void DidLoseContext(uint32_t reason) override;
- void UpdateVSyncParameters(const base::TimeTicks& timebase,
- const base::TimeDelta& interval) override;
- void OnGpuCompletedSwapBuffers(gfx::SwapResult result) override;
-
- // mojom::CommandBuffer:
- void Initialize(
- mojom::CommandBufferClientPtr client,
- mojo::ScopedSharedBufferHandle shared_state,
- mojo::Array<int32_t> attribs,
- const mojom::CommandBuffer::InitializeCallback& callback) override;
- void SetGetBuffer(int32_t buffer) override;
- void Flush(int32_t put_offset) override;
- void MakeProgress(
- int32_t last_get_offset,
- const mojom::CommandBuffer::MakeProgressCallback& callback) override;
- void RegisterTransferBuffer(int32_t id,
- mojo::ScopedSharedBufferHandle transfer_buffer,
- uint32_t size) override;
- void DestroyTransferBuffer(int32_t id) override;
- void CreateImage(int32_t id,
- mojo::ScopedHandle memory_handle,
- int32_t type,
- const gfx::Size& size,
- int32_t format,
- int32_t internal_format) override;
- void DestroyImage(int32_t id) override;
- void CreateStreamTexture(
- uint32_t client_texture_id,
- const mojom::CommandBuffer::CreateStreamTextureCallback& callback
- ) override;
- void TakeFrontBuffer(const gpu::Mailbox& mailbox) override;
- void ReturnFrontBuffer(const gpu::Mailbox& mailbox, bool is_lost) override;
- void SignalQuery(uint32_t query, uint32_t signal_id) override;
- void SignalSyncToken(const gpu::SyncToken& sync_token,
- uint32_t signal_id) override;
- void WaitForGetOffsetInRange(
- int32_t start, int32_t end,
- const mojom::CommandBuffer::WaitForGetOffsetInRangeCallback& callback
- ) override;
- void WaitForTokenInRange(
- int32_t start, int32_t end,
- const mojom::CommandBuffer::WaitForGetOffsetInRangeCallback& callback
- ) override;
-
- // All helper functions are called in the GPU therad.
- void InitializeOnGpuThread(
- mojom::CommandBufferClientPtr client,
- mojo::ScopedSharedBufferHandle shared_state,
- mojo::Array<int32_t> attribs,
- const base::Callback<
- void(mojom::CommandBufferInitializeResultPtr)>& callback);
- bool SetGetBufferOnGpuThread(int32_t buffer);
- bool FlushOnGpuThread(int32_t put_offset, uint32_t order_num);
- bool MakeProgressOnGpuThread(
- int32_t last_get_offset,
- const base::Callback<void(const gpu::CommandBuffer::State&)>& callback);
- bool RegisterTransferBufferOnGpuThread(
- int32_t id,
- mojo::ScopedSharedBufferHandle transfer_buffer,
- uint32_t size);
- bool DestroyTransferBufferOnGpuThread(int32_t id);
- bool CreateImageOnGpuThread(int32_t id,
- mojo::ScopedHandle memory_handle,
- int32_t type,
- const gfx::Size& size,
- int32_t format,
- int32_t internal_format);
- bool DestroyImageOnGpuThread(int32_t id);
-
- void BindToRequest(mojo::InterfaceRequest<CommandBuffer> request);
-
- void OnConnectionError();
- bool DeleteOnGpuThread();
- void DeleteOnGpuThread2();
-
- scoped_refptr<GpuState> gpu_state_;
- std::unique_ptr<CommandBufferDriver> driver_;
- std::unique_ptr<mojo::Binding<CommandBuffer>> binding_;
- mojom::CommandBufferClientPtr client_;
-
- DISALLOW_COPY_AND_ASSIGN(CommandBufferImpl);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GLES2_COMMAND_BUFFER_IMPL_H_
diff --git a/chromium/components/mus/gles2/command_buffer_local.cc b/chromium/components/mus/gles2/command_buffer_local.cc
deleted file mode 100644
index 434fb551525..00000000000
--- a/chromium/components/mus/gles2/command_buffer_local.cc
+++ /dev/null
@@ -1,576 +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 "components/mus/gles2/command_buffer_local.h"
-
-#include "base/atomic_sequence_num.h"
-#include "base/bind.h"
-#include "base/memory/shared_memory.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/mus/common/gpu_type_converters.h"
-#include "components/mus/common/mojo_buffer_backing.h"
-#include "components/mus/common/mojo_gpu_memory_buffer.h"
-#include "components/mus/gles2/command_buffer_driver.h"
-#include "components/mus/gles2/command_buffer_local_client.h"
-#include "components/mus/gles2/gpu_memory_tracker.h"
-#include "components/mus/gles2/gpu_state.h"
-#include "gpu/command_buffer/client/gpu_control_client.h"
-#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
-#include "gpu/command_buffer/common/sync_token.h"
-#include "gpu/command_buffer/service/command_buffer_service.h"
-#include "gpu/command_buffer/service/context_group.h"
-#include "gpu/command_buffer/service/image_manager.h"
-#include "gpu/command_buffer/service/memory_tracking.h"
-#include "gpu/command_buffer/service/shader_translator_cache.h"
-#include "gpu/command_buffer/service/transfer_buffer_manager.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-#include "ui/gfx/buffer_format_util.h"
-#include "ui/gfx/vsync_provider.h"
-#include "ui/gl/gl_context.h"
-#include "ui/gl/gl_image_shared_memory.h"
-#include "ui/gl/gl_surface.h"
-
-namespace mus {
-
-namespace {
-
-uint64_t g_next_command_buffer_id = 0;
-
-bool CreateAndMapSharedBuffer(size_t size,
- mojo::ScopedSharedBufferMapping* mapping,
- mojo::ScopedSharedBufferHandle* handle) {
- *handle = mojo::SharedBufferHandle::Create(size);
- if (!handle->is_valid())
- return false;
-
- *mapping = (*handle)->Map(size);
- if (!*mapping)
- return false;
-
- return true;
-}
-
-void PostTask(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- const base::Closure& callback) {
- task_runner->PostTask(FROM_HERE, callback);
-}
-}
-
-const unsigned int GL_READ_WRITE_CHROMIUM = 0x78F2;
-
-CommandBufferLocal::CommandBufferLocal(CommandBufferLocalClient* client,
- gfx::AcceleratedWidget widget,
- const scoped_refptr<GpuState>& gpu_state)
- : widget_(widget),
- gpu_state_(gpu_state),
- client_(client),
- client_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- gpu_control_client_(nullptr),
- next_transfer_buffer_id_(0),
- next_image_id_(0),
- next_fence_sync_release_(1),
- flushed_fence_sync_release_(0),
- lost_context_(false),
- sync_point_client_waiter_(
- gpu_state->sync_point_manager()->CreateSyncPointClientWaiter()),
- weak_factory_(this) {
- weak_ptr_ = weak_factory_.GetWeakPtr();
-}
-
-void CommandBufferLocal::Destroy() {
- DCHECK(CalledOnValidThread());
- // After this |Destroy()| call, this object will not be used by client anymore
- // and it will be deleted on the GPU thread. So we have to detach it from the
- // client thread first.
- DetachFromThread();
-
- weak_factory_.InvalidateWeakPtrs();
- // CommandBufferLocal is initialized on the GPU thread with
- // InitializeOnGpuThread(), so we need delete memebers on the GPU thread
- // too. Additionally we need to make sure we are deleted before returning,
- // otherwise we may attempt to use the AcceleratedWidget which has since been
- // destroyed.
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(), base::Bind(&CommandBufferLocal::DeleteOnGpuThread,
- base::Unretained(this), &event));
- event.Wait();
-}
-
-bool CommandBufferLocal::Initialize() {
- DCHECK(CalledOnValidThread());
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- bool result = false;
- gpu_state_->command_buffer_task_runner()->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&CommandBufferLocal::InitializeOnGpuThread,
- base::Unretained(this), base::Unretained(&event),
- base::Unretained(&result)));
- event.Wait();
- return result;
-}
-
-gpu::CommandBuffer::State CommandBufferLocal::GetLastState() {
- DCHECK(CalledOnValidThread());
- return last_state_;
-}
-
-int32_t CommandBufferLocal::GetLastToken() {
- DCHECK(CalledOnValidThread());
- TryUpdateState();
- return last_state_.token;
-}
-
-void CommandBufferLocal::Flush(int32_t put_offset) {
- DCHECK(CalledOnValidThread());
- if (last_put_offset_ == put_offset)
- return;
-
- last_put_offset_ = put_offset;
- gpu::SyncPointManager* sync_point_manager = gpu_state_->sync_point_manager();
- const uint32_t order_num =
- driver_->sync_point_order_data()->GenerateUnprocessedOrderNumber(
- sync_point_manager);
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(), base::Bind(&CommandBufferLocal::FlushOnGpuThread,
- base::Unretained(this), put_offset, order_num));
- flushed_fence_sync_release_ = next_fence_sync_release_ - 1;
-}
-
-void CommandBufferLocal::OrderingBarrier(int32_t put_offset) {
- DCHECK(CalledOnValidThread());
- // TODO(penghuang): Implement this more efficiently.
- Flush(put_offset);
-}
-
-void CommandBufferLocal::WaitForTokenInRange(int32_t start, int32_t end) {
- DCHECK(CalledOnValidThread());
- TryUpdateState();
- while (!InRange(start, end, last_state_.token) &&
- last_state_.error == gpu::error::kNoError) {
- MakeProgressAndUpdateState();
- }
-}
-
-void CommandBufferLocal::WaitForGetOffsetInRange(int32_t start, int32_t end) {
- DCHECK(CalledOnValidThread());
- TryUpdateState();
- while (!InRange(start, end, last_state_.get_offset) &&
- last_state_.error == gpu::error::kNoError) {
- MakeProgressAndUpdateState();
- }
-}
-
-void CommandBufferLocal::SetGetBuffer(int32_t buffer) {
- DCHECK(CalledOnValidThread());
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(), base::Bind(&CommandBufferLocal::SetGetBufferOnGpuThread,
- base::Unretained(this), buffer));
- last_put_offset_ = -1;
-}
-
-scoped_refptr<gpu::Buffer> CommandBufferLocal::CreateTransferBuffer(
- size_t size,
- int32_t* id) {
- DCHECK(CalledOnValidThread());
- if (size >= std::numeric_limits<uint32_t>::max())
- return nullptr;
-
- mojo::ScopedSharedBufferMapping mapping;
- mojo::ScopedSharedBufferHandle handle;
- if (!CreateAndMapSharedBuffer(size, &mapping, &handle)) {
- if (last_state_.error == gpu::error::kNoError)
- last_state_.error = gpu::error::kLostContext;
- return nullptr;
- }
-
- *id = ++next_transfer_buffer_id_;
-
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(),
- base::Bind(&CommandBufferLocal::RegisterTransferBufferOnGpuThread,
- base::Unretained(this), *id, base::Passed(&handle),
- static_cast<uint32_t>(size)));
- std::unique_ptr<gpu::BufferBacking> backing(
- new mus::MojoBufferBacking(std::move(mapping), size));
- scoped_refptr<gpu::Buffer> buffer(new gpu::Buffer(std::move(backing)));
- return buffer;
-}
-
-void CommandBufferLocal::DestroyTransferBuffer(int32_t id) {
- DCHECK(CalledOnValidThread());
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(),
- base::Bind(&CommandBufferLocal::DestroyTransferBufferOnGpuThread,
- base::Unretained(this), id));
-}
-
-void CommandBufferLocal::SetGpuControlClient(gpu::GpuControlClient* client) {
- gpu_control_client_ = client;
-}
-
-gpu::Capabilities CommandBufferLocal::GetCapabilities() {
- DCHECK(CalledOnValidThread());
- return capabilities_;
-}
-
-int32_t CommandBufferLocal::CreateImage(ClientBuffer buffer,
- size_t width,
- size_t height,
- unsigned internal_format) {
- DCHECK(CalledOnValidThread());
- int32_t new_id = ++next_image_id_;
- gfx::Size size(static_cast<int32_t>(width), static_cast<int32_t>(height));
-
- mus::MojoGpuMemoryBufferImpl* gpu_memory_buffer =
- mus::MojoGpuMemoryBufferImpl::FromClientBuffer(buffer);
-
- bool requires_sync_point = false;
-
- if (gpu_memory_buffer->GetBufferType() == gfx::SHARED_MEMORY_BUFFER) {
- gfx::GpuMemoryBufferHandle handle = gpu_memory_buffer->GetHandle();
- // TODO(rjkroege): Verify that this is required and update appropriately.
- base::SharedMemoryHandle dupd_handle =
- base::SharedMemory::DuplicateHandle(handle.handle);
-#if defined(OS_WIN)
- HANDLE platform_file = dupd_handle.GetHandle();
-#else
- int platform_file = dupd_handle.fd;
-#endif
-
- mojo::ScopedHandle scoped_handle = mojo::WrapPlatformFile(platform_file);
- const int32_t format = static_cast<int32_t>(gpu_memory_buffer->GetFormat());
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(),
- base::Bind(&CommandBufferLocal::CreateImageOnGpuThread,
- base::Unretained(this), new_id, base::Passed(&scoped_handle),
- handle.type, base::Passed(&size), format, internal_format));
-#if defined(USE_OZONE)
- } else if (gpu_memory_buffer->GetBufferType() == gfx::OZONE_NATIVE_PIXMAP) {
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(),
- base::Bind(&CommandBufferLocal::CreateImageNativeOzoneOnGpuThread,
- base::Unretained(this), new_id,
- gpu_memory_buffer->GetBufferType(),
- gpu_memory_buffer->GetSize(), gpu_memory_buffer->GetFormat(),
- internal_format,
- base::RetainedRef(gpu_memory_buffer->GetNativePixmap())));
-#endif
- } else {
- NOTIMPLEMENTED();
- return -1;
- }
-
- if (requires_sync_point) {
- NOTIMPLEMENTED() << "Require sync points";
- // TODO(jam): need to support this if we support types other than
- // SHARED_MEMORY_BUFFER.
- // gpu_memory_buffer_manager->SetDestructionSyncPoint(gpu_memory_buffer,
- // InsertSyncPoint());
- }
-
- return new_id;
-}
-
-void CommandBufferLocal::DestroyImage(int32_t id) {
- DCHECK(CalledOnValidThread());
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(), base::Bind(&CommandBufferLocal::DestroyImageOnGpuThread,
- base::Unretained(this), id));
-}
-
-int32_t CommandBufferLocal::CreateGpuMemoryBufferImage(size_t width,
- size_t height,
- unsigned internal_format,
- unsigned usage) {
- DCHECK(CalledOnValidThread());
- DCHECK_EQ(usage, static_cast<unsigned>(GL_READ_WRITE_CHROMIUM));
- std::unique_ptr<gfx::GpuMemoryBuffer> buffer(MojoGpuMemoryBufferImpl::Create(
- gfx::Size(static_cast<int>(width), static_cast<int>(height)),
- gpu::DefaultBufferFormatForImageFormat(internal_format),
- gfx::BufferUsage::SCANOUT));
- if (!buffer)
- return -1;
- return CreateImage(buffer->AsClientBuffer(), width, height, internal_format);
-}
-
-int32_t CommandBufferLocal::GetImageGpuMemoryBufferId(unsigned image_id) {
- // TODO(erikchen): Once this class supports IOSurface GpuMemoryBuffer backed
- // images, it will also need to keep a local cache from image id to
- // GpuMemoryBuffer id.
- NOTIMPLEMENTED();
- return -1;
-}
-
-void CommandBufferLocal::SignalQuery(uint32_t query_id,
- const base::Closure& callback) {
- DCHECK(CalledOnValidThread());
-
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(), base::Bind(&CommandBufferLocal::SignalQueryOnGpuThread,
- base::Unretained(this), query_id, callback));
-}
-
-void CommandBufferLocal::SetLock(base::Lock* lock) {
- DCHECK(CalledOnValidThread());
- NOTIMPLEMENTED();
-}
-
-void CommandBufferLocal::EnsureWorkVisible() {
- // This is only relevant for out-of-process command buffers.
-}
-
-gpu::CommandBufferNamespace CommandBufferLocal::GetNamespaceID() const {
- DCHECK(CalledOnValidThread());
- return gpu::CommandBufferNamespace::MOJO_LOCAL;
-}
-
-gpu::CommandBufferId CommandBufferLocal::GetCommandBufferID() const {
- DCHECK(CalledOnValidThread());
- return driver_->GetCommandBufferID();
-}
-
-int32_t CommandBufferLocal::GetExtraCommandBufferData() const {
- DCHECK(CalledOnValidThread());
- return 0;
-}
-
-uint64_t CommandBufferLocal::GenerateFenceSyncRelease() {
- DCHECK(CalledOnValidThread());
- return next_fence_sync_release_++;
-}
-
-bool CommandBufferLocal::IsFenceSyncRelease(uint64_t release) {
- DCHECK(CalledOnValidThread());
- return release != 0 && release < next_fence_sync_release_;
-}
-
-bool CommandBufferLocal::IsFenceSyncFlushed(uint64_t release) {
- DCHECK(CalledOnValidThread());
- return release != 0 && release <= flushed_fence_sync_release_;
-}
-
-bool CommandBufferLocal::IsFenceSyncFlushReceived(uint64_t release) {
- DCHECK(CalledOnValidThread());
- return IsFenceSyncFlushed(release);
-}
-
-void CommandBufferLocal::SignalSyncToken(const gpu::SyncToken& sync_token,
- const base::Closure& callback) {
- DCHECK(CalledOnValidThread());
- scoped_refptr<gpu::SyncPointClientState> release_state =
- gpu_state_->sync_point_manager()->GetSyncPointClientState(
- sync_token.namespace_id(), sync_token.command_buffer_id());
- if (!release_state ||
- release_state->IsFenceSyncReleased(sync_token.release_count())) {
- callback.Run();
- return;
- }
-
- sync_point_client_waiter_->WaitOutOfOrderNonThreadSafe(
- release_state.get(), sync_token.release_count(),
- client_thread_task_runner_, callback);
-}
-
-bool CommandBufferLocal::CanWaitUnverifiedSyncToken(
- const gpu::SyncToken* sync_token) {
- DCHECK(CalledOnValidThread());
- // Right now, MOJO_LOCAL is only used by trusted code, so it is safe to wait
- // on a sync token in MOJO_LOCAL command buffer.
- return sync_token->namespace_id() == gpu::CommandBufferNamespace::MOJO_LOCAL;
-}
-
-void CommandBufferLocal::DidLoseContext(uint32_t reason) {
- if (client_) {
- driver_->set_client(nullptr);
- client_thread_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&CommandBufferLocal::DidLoseContextOnClientThread,
- weak_ptr_, reason));
- }
-}
-
-void CommandBufferLocal::UpdateVSyncParameters(
- const base::TimeTicks& timebase,
- const base::TimeDelta& interval) {
- if (client_) {
- client_thread_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&CommandBufferLocal::UpdateVSyncParametersOnClientThread,
- weak_ptr_, timebase, interval));
- }
-}
-
-void CommandBufferLocal::OnGpuCompletedSwapBuffers(gfx::SwapResult result) {
- if (client_) {
- client_thread_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&CommandBufferLocal::OnGpuCompletedSwapBuffersOnClientThread,
- weak_ptr_, result));
- }
-}
-
-CommandBufferLocal::~CommandBufferLocal() {}
-
-void CommandBufferLocal::TryUpdateState() {
- if (last_state_.error == gpu::error::kNoError)
- shared_state()->Read(&last_state_);
-}
-
-void CommandBufferLocal::MakeProgressAndUpdateState() {
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- gpu::CommandBuffer::State state;
- gpu_state_->command_buffer_task_runner()->PostTask(
- driver_.get(),
- base::Bind(&CommandBufferLocal::MakeProgressOnGpuThread,
- base::Unretained(this), base::Unretained(&event),
- base::Unretained(&state)));
- event.Wait();
- if (state.generation - last_state_.generation < 0x80000000U)
- last_state_ = state;
-}
-
-void CommandBufferLocal::InitializeOnGpuThread(base::WaitableEvent* event,
- bool* result) {
- driver_.reset(new CommandBufferDriver(
- gpu::CommandBufferNamespace::MOJO_LOCAL,
- gpu::CommandBufferId::FromUnsafeValue(++g_next_command_buffer_id),
- widget_, gpu_state_));
- driver_->set_client(this);
- const size_t kSharedStateSize = sizeof(gpu::CommandBufferSharedState);
- mojo::ScopedSharedBufferMapping mapping;
- mojo::ScopedSharedBufferHandle handle;
- *result = CreateAndMapSharedBuffer(kSharedStateSize, &shared_state_, &handle);
-
- if (!*result) {
- event->Signal();
- return;
- }
-
- shared_state()->Initialize();
-
- *result =
- driver_->Initialize(std::move(handle), mojo::Array<int32_t>::New(0));
- if (*result)
- capabilities_ = driver_->GetCapabilities();
- event->Signal();
-}
-
-bool CommandBufferLocal::FlushOnGpuThread(int32_t put_offset,
- uint32_t order_num) {
- DCHECK(driver_->IsScheduled());
- driver_->sync_point_order_data()->BeginProcessingOrderNumber(order_num);
- driver_->Flush(put_offset);
-
- // Return false if the Flush is not finished, so the CommandBufferTaskRunner
- // will not remove this task from the task queue.
- const bool complete = !driver_->HasUnprocessedCommands();
- if (complete)
- driver_->sync_point_order_data()->FinishProcessingOrderNumber(order_num);
- return complete;
-}
-
-bool CommandBufferLocal::SetGetBufferOnGpuThread(int32_t buffer) {
- DCHECK(driver_->IsScheduled());
- driver_->SetGetBuffer(buffer);
- return true;
-}
-
-bool CommandBufferLocal::RegisterTransferBufferOnGpuThread(
- int32_t id,
- mojo::ScopedSharedBufferHandle transfer_buffer,
- uint32_t size) {
- DCHECK(driver_->IsScheduled());
- driver_->RegisterTransferBuffer(id, std::move(transfer_buffer), size);
- return true;
-}
-
-bool CommandBufferLocal::DestroyTransferBufferOnGpuThread(int32_t id) {
- DCHECK(driver_->IsScheduled());
- driver_->DestroyTransferBuffer(id);
- return true;
-}
-
-bool CommandBufferLocal::CreateImageOnGpuThread(
- int32_t id,
- mojo::ScopedHandle memory_handle,
- int32_t type,
- const gfx::Size& size,
- int32_t format,
- int32_t internal_format) {
- DCHECK(driver_->IsScheduled());
- driver_->CreateImage(id, std::move(memory_handle), type, std::move(size),
- format, internal_format);
- return true;
-}
-
-bool CommandBufferLocal::CreateImageNativeOzoneOnGpuThread(
- int32_t id,
- int32_t type,
- gfx::Size size,
- gfx::BufferFormat format,
- uint32_t internal_format,
- ui::NativePixmap* pixmap) {
- DCHECK(driver_->IsScheduled());
- driver_->CreateImageNativeOzone(id, type, size, format, internal_format,
- pixmap);
- return true;
-}
-
-bool CommandBufferLocal::DestroyImageOnGpuThread(int32_t id) {
- DCHECK(driver_->IsScheduled());
- driver_->DestroyImage(id);
- return true;
-}
-
-bool CommandBufferLocal::MakeProgressOnGpuThread(
- base::WaitableEvent* event,
- gpu::CommandBuffer::State* state) {
- DCHECK(driver_->IsScheduled());
- *state = driver_->GetLastState();
- event->Signal();
- return true;
-}
-
-bool CommandBufferLocal::DeleteOnGpuThread(base::WaitableEvent* event) {
- delete this;
- event->Signal();
- return true;
-}
-
-bool CommandBufferLocal::SignalQueryOnGpuThread(uint32_t query_id,
- const base::Closure& callback) {
- // |callback| should run on the client thread.
- driver_->SignalQuery(
- query_id, base::Bind(&PostTask, client_thread_task_runner_, callback));
- return true;
-}
-
-void CommandBufferLocal::DidLoseContextOnClientThread(uint32_t reason) {
- DCHECK(gpu_control_client_);
- if (!lost_context_)
- gpu_control_client_->OnGpuControlLostContext();
- lost_context_ = true;
-}
-
-void CommandBufferLocal::UpdateVSyncParametersOnClientThread(
- const base::TimeTicks& timebase,
- const base::TimeDelta& interval) {
- if (client_)
- client_->UpdateVSyncParameters(timebase, interval);
-}
-
-void CommandBufferLocal::OnGpuCompletedSwapBuffersOnClientThread(
- gfx::SwapResult result) {
- if (client_)
- client_->GpuCompletedSwapBuffers(result);
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gles2/command_buffer_local.h b/chromium/components/mus/gles2/command_buffer_local.h
deleted file mode 100644
index 4d893322737..00000000000
--- a/chromium/components/mus/gles2/command_buffer_local.h
+++ /dev/null
@@ -1,185 +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 COMPONENTS_MUS_GLES2_COMMAND_BUFFER_LOCAL_H_
-#define COMPONENTS_MUS_GLES2_COMMAND_BUFFER_LOCAL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/non_thread_safe.h"
-#include "components/mus/gles2/command_buffer_driver.h"
-#include "components/mus/public/interfaces/command_buffer.mojom.h"
-#include "gpu/command_buffer/client/gpu_control.h"
-#include "gpu/command_buffer/common/command_buffer.h"
-#include "gpu/command_buffer/common/command_buffer_id.h"
-#include "gpu/command_buffer/common/command_buffer_shared.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/gpu_memory_buffer.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace {
-class WaitableEvent;
-}
-
-namespace gl {
-class GLContext;
-class GLSurface;
-}
-
-namespace gpu {
-class GpuControlClient;
-class SyncPointClient;
-}
-
-namespace mus {
-
-class CommandBufferDriver;
-class CommandBufferLocalClient;
-class GpuState;
-
-// This class provides a wrapper around a CommandBufferDriver and a GpuControl
-// implementation to allow cc::Display to generate GL directly on the main
-// thread.
-class CommandBufferLocal : public gpu::CommandBuffer,
- public gpu::GpuControl,
- public CommandBufferDriver::Client,
- base::NonThreadSafe {
- public:
- CommandBufferLocal(CommandBufferLocalClient* client,
- gfx::AcceleratedWidget widget,
- const scoped_refptr<GpuState>& gpu_state);
-
- bool Initialize();
- // Destroy the CommandBufferLocal. The client should not use this class
- // after calling it.
- void Destroy();
-
- // gpu::CommandBuffer implementation:
- gpu::CommandBuffer::State GetLastState() override;
- int32_t GetLastToken() override;
- void Flush(int32_t put_offset) override;
- void OrderingBarrier(int32_t put_offset) override;
- void WaitForTokenInRange(int32_t start, int32_t end) override;
- void WaitForGetOffsetInRange(int32_t start, int32_t end) override;
- void SetGetBuffer(int32_t buffer) override;
- scoped_refptr<gpu::Buffer> CreateTransferBuffer(size_t size,
- int32_t* id) override;
- void DestroyTransferBuffer(int32_t id) override;
-
- // gpu::GpuControl implementation:
- void SetGpuControlClient(gpu::GpuControlClient*) override;
- gpu::Capabilities GetCapabilities() override;
- int32_t CreateImage(ClientBuffer buffer,
- size_t width,
- size_t height,
- unsigned internalformat) override;
- void DestroyImage(int32_t id) override;
- int32_t CreateGpuMemoryBufferImage(size_t width,
- size_t height,
- unsigned internal_format,
- unsigned usage) override;
- int32_t GetImageGpuMemoryBufferId(unsigned image_id) override;
- void SignalQuery(uint32_t query_id, const base::Closure& callback) override;
- void SetLock(base::Lock*) override;
- void EnsureWorkVisible() override;
- gpu::CommandBufferNamespace GetNamespaceID() const override;
- gpu::CommandBufferId GetCommandBufferID() const override;
- int32_t GetExtraCommandBufferData() const override;
- uint64_t GenerateFenceSyncRelease() override;
- bool IsFenceSyncRelease(uint64_t release) override;
- bool IsFenceSyncFlushed(uint64_t release) override;
- bool IsFenceSyncFlushReceived(uint64_t release) override;
- void SignalSyncToken(const gpu::SyncToken& sync_token,
- const base::Closure& callback) override;
- bool CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) override;
-
- private:
- // CommandBufferDriver::Client implementation. All called on GPU thread.
- void DidLoseContext(uint32_t reason) override;
- void UpdateVSyncParameters(const base::TimeTicks& timebase,
- const base::TimeDelta& interval) override;
- void OnGpuCompletedSwapBuffers(gfx::SwapResult result) override;
-
- ~CommandBufferLocal() override;
-
- gpu::CommandBufferSharedState* shared_state() const {
- return reinterpret_cast<gpu::CommandBufferSharedState*>(
- shared_state_.get());
- }
- void TryUpdateState();
- void MakeProgressAndUpdateState();
-
- // Helper functions are called in the GPU thread.
- void InitializeOnGpuThread(base::WaitableEvent* event, bool* result);
- bool FlushOnGpuThread(int32_t put_offset, uint32_t order_num);
- bool SetGetBufferOnGpuThread(int32_t buffer);
- bool RegisterTransferBufferOnGpuThread(
- int32_t id,
- mojo::ScopedSharedBufferHandle transfer_buffer,
- uint32_t size);
- bool DestroyTransferBufferOnGpuThread(int32_t id);
- bool CreateImageOnGpuThread(int32_t id,
- mojo::ScopedHandle memory_handle,
- int32_t type,
- const gfx::Size& size,
- int32_t format,
- int32_t internal_format);
- bool CreateImageNativeOzoneOnGpuThread(int32_t id,
- int32_t type,
- gfx::Size size,
- gfx::BufferFormat format,
- uint32_t internal_format,
- ui::NativePixmap* pixmap);
- bool DestroyImageOnGpuThread(int32_t id);
- bool MakeProgressOnGpuThread(base::WaitableEvent* event,
- gpu::CommandBuffer::State* state);
- bool DeleteOnGpuThread(base::WaitableEvent* event);
- bool SignalQueryOnGpuThread(uint32_t query_id, const base::Closure& callback);
-
- // Helper functions are called in the client thread.
- void DidLoseContextOnClientThread(uint32_t reason);
- void UpdateVSyncParametersOnClientThread(const base::TimeTicks& timebase,
- const base::TimeDelta& interval);
- void OnGpuCompletedSwapBuffersOnClientThread(gfx::SwapResult result);
-
- gfx::AcceleratedWidget widget_;
- scoped_refptr<GpuState> gpu_state_;
- std::unique_ptr<CommandBufferDriver> driver_;
- CommandBufferLocalClient* client_;
- scoped_refptr<base::SingleThreadTaskRunner> client_thread_task_runner_;
-
- // Members accessed on the client thread:
- gpu::GpuControlClient* gpu_control_client_;
- gpu::CommandBuffer::State last_state_;
- mojo::ScopedSharedBufferMapping shared_state_;
- int32_t last_put_offset_;
- gpu::Capabilities capabilities_;
- int32_t next_transfer_buffer_id_;
- int32_t next_image_id_;
- uint64_t next_fence_sync_release_;
- uint64_t flushed_fence_sync_release_;
- bool lost_context_;
-
- // This sync point client is only for out of order Wait on client thread.
- std::unique_ptr<gpu::SyncPointClient> sync_point_client_waiter_;
-
- base::WeakPtr<CommandBufferLocal> weak_ptr_;
-
- // This weak factory will be invalidated in the client thread, so all weak
- // pointers have to be dereferenced in the client thread too.
- base::WeakPtrFactory<CommandBufferLocal> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(CommandBufferLocal);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GLES2_COMMAND_BUFFER_LOCAL_H_
diff --git a/chromium/components/mus/gles2/command_buffer_local_client.h b/chromium/components/mus/gles2/command_buffer_local_client.h
deleted file mode 100644
index c26cbdf4941..00000000000
--- a/chromium/components/mus/gles2/command_buffer_local_client.h
+++ /dev/null
@@ -1,31 +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 COMPONENTS_MUS_GLES2_COMMAND_BUFFER_LOCAL_CLIENT_H_
-#define COMPONENTS_MUS_GLES2_COMMAND_BUFFER_LOCAL_CLIENT_H_
-
-#include <stdint.h>
-
-#include "ui/gfx/swap_result.h"
-
-namespace base {
-class TimeDelta;
-class TimeTicks;
-}
-
-namespace mus {
-
-class CommandBufferLocalClient {
- public:
- virtual void UpdateVSyncParameters(const base::TimeTicks& timebase,
- const base::TimeDelta& interval) = 0;
- virtual void GpuCompletedSwapBuffers(gfx::SwapResult result) = 0;
-
- protected:
- virtual ~CommandBufferLocalClient() {}
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GLES2_COMMAND_BUFFER_LOCAL_CLIENT_H_
diff --git a/chromium/components/mus/gles2/command_buffer_task_runner.cc b/chromium/components/mus/gles2/command_buffer_task_runner.cc
deleted file mode 100644
index df1dc548b6a..00000000000
--- a/chromium/components/mus/gles2/command_buffer_task_runner.cc
+++ /dev/null
@@ -1,77 +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 "components/mus/gles2/command_buffer_task_runner.h"
-
-#include "base/bind.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/mus/gles2/command_buffer_driver.h"
-
-namespace mus {
-
-CommandBufferTaskRunner::CommandBufferTaskRunner()
- : task_runner_(base::ThreadTaskRunnerHandle::Get()),
- need_post_task_(true) {
-}
-
-bool CommandBufferTaskRunner::PostTask(
- const CommandBufferDriver* driver,
- const TaskCallback& task) {
- base::AutoLock locker(lock_);
- driver_map_[driver].push_back(task);
- ScheduleTaskIfNecessaryLocked();
- return true;
-}
-
-CommandBufferTaskRunner::~CommandBufferTaskRunner() {}
-
-bool CommandBufferTaskRunner::RunOneTaskInternalLocked() {
- DCHECK(thread_checker_.CalledOnValidThread());
- lock_.AssertAcquired();
-
- for (auto it = driver_map_.begin(); it != driver_map_.end(); ++it) {
- if (!it->first->IsScheduled())
- continue;
- TaskQueue& task_queue = it->second;
- DCHECK(!task_queue.empty());
- const TaskCallback& callback = task_queue.front();
- bool complete = false;
- {
- base::AutoUnlock unlocker(lock_);
- complete = callback.Run();
- }
- if (complete) {
- // Only remove the task if it is complete.
- task_queue.pop_front();
- if (task_queue.empty())
- driver_map_.erase(it);
- }
- return true;
- }
- return false;
-}
-
-void CommandBufferTaskRunner::ScheduleTaskIfNecessaryLocked() {
- lock_.AssertAcquired();
- if (!need_post_task_)
- return;
- task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&CommandBufferTaskRunner::RunCommandBufferTask, this));
- need_post_task_ = false;
-}
-
-void CommandBufferTaskRunner::RunCommandBufferTask() {
- DCHECK(thread_checker_.CalledOnValidThread());
- base::AutoLock locker(lock_);
-
- // Try executing all tasks in |driver_map_| until |RunOneTaskInternalLock()|
- // returns false (Returning false means |driver_map_| is empty or all tasks
- // in it aren't executable currently).
- while (RunOneTaskInternalLocked())
- ;
- need_post_task_ = true;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gles2/command_buffer_task_runner.h b/chromium/components/mus/gles2/command_buffer_task_runner.h
deleted file mode 100644
index 8ee317f5800..00000000000
--- a/chromium/components/mus/gles2/command_buffer_task_runner.h
+++ /dev/null
@@ -1,78 +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 COMPONENTS_MUS_GLES2_COMMAND_BUFFER_TASK_RUNNER_H_
-#define COMPONENTS_MUS_GLES2_COMMAND_BUFFER_TASK_RUNNER_H_
-
-#include <deque>
-#include <map>
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/condition_variable.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
-
-namespace mus {
-
-class CommandBufferDriver;
-
-// This class maintains tasks submitted by |CommandBufferImpl|. Those tasks will
-// be executed on the main thread. But if the main thread is blocked in
-// |CommandBufferLocal::OnWaitFenceSync()| by waiting a sync point, the
-// |CommandBufferTaskRunner::RunOneTask()| could be used for executing a task
-// from other command buffers which may retire the sync point.
-class CommandBufferTaskRunner
- : public base::RefCountedThreadSafe<CommandBufferTaskRunner> {
- public:
- CommandBufferTaskRunner();
-
- // TaskCallback returns true if the task is completed and should be removed
- // from the task queue, otherwise returns false.
- typedef base::Callback<bool(void)> TaskCallback;
- bool PostTask(const CommandBufferDriver* driver,
- const TaskCallback& task);
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
- return task_runner_;
- }
-
- private:
- friend class base::RefCountedThreadSafe<CommandBufferTaskRunner>;
-
- ~CommandBufferTaskRunner();
-
- // Run one command buffer task from a scheduled command buffer.
- // When there isn't any command buffer task, and if the |block| is false,
- // this function will return false immediately, otherwise, this function
- // will be blocked until a task is available for executing.
- bool RunOneTaskInternalLocked();
-
- // Post a task to the main thread to execute tasks in |driver_map_|, if it is
- // necessary.
- void ScheduleTaskIfNecessaryLocked();
-
- // The callback function for executing tasks in |driver_map_|.
- void RunCommandBufferTask();
-
- base::ThreadChecker thread_checker_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
- typedef std::deque<TaskCallback> TaskQueue;
- typedef std::map<const CommandBufferDriver*, TaskQueue> DriverMap;
- DriverMap driver_map_;
- bool need_post_task_;
-
- // The access lock for |driver_map_| and |need_post_task_|.
- base::Lock lock_;
-
- DISALLOW_COPY_AND_ASSIGN(CommandBufferTaskRunner);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GLES2_COMMAND_BUFFER_TASK_RUNNER_H_
diff --git a/chromium/components/mus/gles2/gl_surface_adapter.cc b/chromium/components/mus/gles2/gl_surface_adapter.cc
deleted file mode 100644
index df1761b5854..00000000000
--- a/chromium/components/mus/gles2/gl_surface_adapter.cc
+++ /dev/null
@@ -1,57 +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 "components/mus/gles2/gl_surface_adapter.h"
-
-#include "base/bind.h"
-
-namespace mus {
-
-GLSurfaceAdapterMus::GLSurfaceAdapterMus(scoped_refptr<gl::GLSurface> surface)
- : gl::GLSurfaceAdapter(surface.get()),
- surface_(surface),
- weak_ptr_factory_(this) {}
-
-GLSurfaceAdapterMus::~GLSurfaceAdapterMus() {}
-
-void GLSurfaceAdapterMus::SwapBuffersAsync(
- const GLSurface::SwapCompletionCallback& callback) {
- gl::GLSurfaceAdapter::SwapBuffersAsync(
- base::Bind(&GLSurfaceAdapterMus::WrappedCallbackForSwapBuffersAsync,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void GLSurfaceAdapterMus::PostSubBufferAsync(
- int x,
- int y,
- int width,
- int height,
- const GLSurface::SwapCompletionCallback& callback) {
- gl::GLSurfaceAdapter::PostSubBufferAsync(
- x, y, width, height,
- base::Bind(&GLSurfaceAdapterMus::WrappedCallbackForSwapBuffersAsync,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void GLSurfaceAdapterMus::CommitOverlayPlanesAsync(
- const GLSurface::SwapCompletionCallback& callback) {
- gl::GLSurfaceAdapter::CommitOverlayPlanesAsync(
- base::Bind(&GLSurfaceAdapterMus::WrappedCallbackForSwapBuffersAsync,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void GLSurfaceAdapterMus::WrappedCallbackForSwapBuffersAsync(
- const gl::GLSurface::SwapCompletionCallback& original_callback,
- gfx::SwapResult result) {
- if (!adapter_callback_.is_null())
- adapter_callback_.Run(result);
- original_callback.Run(result);
-}
-
-void GLSurfaceAdapterMus::SetGpuCompletedSwapBuffersCallback(
- gl::GLSurface::SwapCompletionCallback callback) {
- adapter_callback_ = std::move(callback);
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gles2/gl_surface_adapter.h b/chromium/components/mus/gles2/gl_surface_adapter.h
deleted file mode 100644
index 98da7530915..00000000000
--- a/chromium/components/mus/gles2/gl_surface_adapter.h
+++ /dev/null
@@ -1,71 +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.
-
-#ifndef COMPONENTS_MUS_GLES2_GL_SURFACE_ADAPTER_H_
-#define COMPONENTS_MUS_GLES2_GL_SURFACE_ADAPTER_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "ui/gfx/swap_result.h"
-#include "ui/gl/gl_surface.h"
-
-namespace mus {
-
-// Wraps a GLSurface such that there is a real GLSurface instance acting as
-// delegate. Implements the GLSurface interface. The |gl::GLSurfaceAdapter|
-// superclass provides a default implementation that forwards all GLSurface
-// methods to the provided delegate. |GLSurfaceAdapterMus| overrides only the
-// necessary methods to augment the completion callback argument to
-// |SwapBuffersAsync|, |PostSubBufferAsync| and |CommitOverlayPlanesAsync| with
-// a callback provided with the |SetGpuCompletedSwapBuffersCallback| method.
-class GLSurfaceAdapterMus : public gl::GLSurfaceAdapter {
- public:
- // Creates a new |GLSurfaceAdapterMus| that delegates to |surface|.
- explicit GLSurfaceAdapterMus(scoped_refptr<gl::GLSurface> surface);
-
- // gl::GLSurfaceAdapter.
- void SwapBuffersAsync(
- const gl::GLSurface::SwapCompletionCallback& callback) override;
- void PostSubBufferAsync(
- int x,
- int y,
- int width,
- int height,
- const gl::GLSurface::SwapCompletionCallback& callback) override;
- void CommitOverlayPlanesAsync(
- const gl::GLSurface::SwapCompletionCallback& callback) override;
-
- // Set an additional callback to run on SwapBuffers completion.
- void SetGpuCompletedSwapBuffersCallback(
- gl::GLSurface::SwapCompletionCallback callback);
-
- private:
- ~GLSurfaceAdapterMus() override;
-
- // We wrap the callback given to the |gl::GLSurfaceAdapter| overrides above
- // with an invocation of this function. It invokes |adapter_callback_| and the
- // original |original_callback| provided by the original invoker of
- // |SwapBuffersAsync| etc.
- void WrappedCallbackForSwapBuffersAsync(
- const gl::GLSurface::SwapCompletionCallback& original_callback,
- gfx::SwapResult result);
-
- gl::GLSurface::SwapCompletionCallback adapter_callback_;
-
- // gl::GLSurfaceAdapter doesn't own the delegate surface so keep a reference
- // here.
- scoped_refptr<gl::GLSurface> surface_;
-
- base::WeakPtrFactory<GLSurfaceAdapterMus> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(GLSurfaceAdapterMus);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GLES2_GL_SURFACE_ADAPTER_H_
diff --git a/chromium/components/mus/gles2/gpu_impl.cc b/chromium/components/mus/gles2/gpu_impl.cc
deleted file mode 100644
index 7ae0b6d0c25..00000000000
--- a/chromium/components/mus/gles2/gpu_impl.cc
+++ /dev/null
@@ -1,27 +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 "components/mus/gles2/gpu_impl.h"
-
-#include "components/mus/common/gpu_type_converters.h"
-#include "components/mus/gles2/command_buffer_impl.h"
-
-namespace mus {
-
-GpuImpl::GpuImpl(mojo::InterfaceRequest<Gpu> request,
- const scoped_refptr<GpuState>& state)
- : binding_(this, std::move(request)), state_(state) {}
-
-GpuImpl::~GpuImpl() {}
-
-void GpuImpl::CreateOffscreenGLES2Context(
- mojo::InterfaceRequest<mojom::CommandBuffer> request) {
- new CommandBufferImpl(std::move(request), state_);
-}
-
-void GpuImpl::GetGpuInfo(const GetGpuInfoCallback& callback) {
- callback.Run(mojom::GpuInfo::From<gpu::GPUInfo>(state_->gpu_info()));
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gles2/gpu_impl.h b/chromium/components/mus/gles2/gpu_impl.h
deleted file mode 100644
index 73fb66ed27a..00000000000
--- a/chromium/components/mus/gles2/gpu_impl.h
+++ /dev/null
@@ -1,39 +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 COMPONENTS_MUS_GLES2_GPU_IMPL_H_
-#define COMPONENTS_MUS_GLES2_GPU_IMPL_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/threading/thread.h"
-#include "components/mus/gles2/gpu_state.h"
-#include "components/mus/public/interfaces/command_buffer.mojom.h"
-#include "components/mus/public/interfaces/gpu.mojom.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "ui/gfx/geometry/mojo/geometry.mojom.h"
-
-namespace mus {
-
-class GpuImpl : public mojom::Gpu {
- public:
- GpuImpl(mojo::InterfaceRequest<mojom::Gpu> request,
- const scoped_refptr<GpuState>& state);
- ~GpuImpl() override;
-
- private:
- void CreateOffscreenGLES2Context(mojo::InterfaceRequest<mojom::CommandBuffer>
- command_buffer_request) override;
- void GetGpuInfo(const GetGpuInfoCallback& callback) override;
-
- mojo::StrongBinding<Gpu> binding_;
- scoped_refptr<GpuState> state_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuImpl);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GLES2_GPU_IMPL_H_
diff --git a/chromium/components/mus/gles2/gpu_memory_tracker.cc b/chromium/components/mus/gles2/gpu_memory_tracker.cc
deleted file mode 100644
index 0d9f12b989e..00000000000
--- a/chromium/components/mus/gles2/gpu_memory_tracker.cc
+++ /dev/null
@@ -1,36 +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 "components/mus/gles2/gpu_memory_tracker.h"
-
-namespace mus {
-
-GpuMemoryTracker::GpuMemoryTracker() {}
-
-void GpuMemoryTracker::TrackMemoryAllocatedChange(
- size_t old_size,
- size_t new_size) {}
-
-bool GpuMemoryTracker::EnsureGPUMemoryAvailable(size_t size_needed) {
- return true;
-}
-
-uint64_t GpuMemoryTracker::ClientTracingId() const {
- return 0u;
-}
-
-int GpuMemoryTracker::ClientId() const {
- return 0;
-}
-
-uint64_t GpuMemoryTracker::ShareGroupTracingGUID() const {
- // TODO(rjkroege): This should return a GUID which identifies the share group
- // we are tracking memory for. This GUID should correspond to the GUID of the
- // first command buffer in the share group.
- return 0;
-}
-
-GpuMemoryTracker::~GpuMemoryTracker() {}
-
-} // namespace mus
diff --git a/chromium/components/mus/gles2/gpu_memory_tracker.h b/chromium/components/mus/gles2/gpu_memory_tracker.h
deleted file mode 100644
index 925ca978d19..00000000000
--- a/chromium/components/mus/gles2/gpu_memory_tracker.h
+++ /dev/null
@@ -1,39 +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 COMPONENTS_MUS_GLES2_GPU_MEMORY_TRACKER_H_
-#define COMPONENTS_MUS_GLES2_GPU_MEMORY_TRACKER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "gpu/command_buffer/service/memory_tracking.h"
-
-namespace mus {
-
-// TODO(fsamuel, rjkroege): This is a stub implementation that needs to be
-// completed for proper memory tracking.
-class GpuMemoryTracker : public gpu::gles2::MemoryTracker {
- public:
- GpuMemoryTracker();
-
- // gpu::MemoryTracker implementation:
- void TrackMemoryAllocatedChange(
- size_t old_size,
- size_t new_size) override;
- bool EnsureGPUMemoryAvailable(size_t size_needed) override;
- uint64_t ClientTracingId() const override;
- int ClientId() const override;
- uint64_t ShareGroupTracingGUID() const override;
-
- private:
- ~GpuMemoryTracker() override;
-
- DISALLOW_COPY_AND_ASSIGN(GpuMemoryTracker);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GLES2_GPU_MEMORY_TRACKER_H_
diff --git a/chromium/components/mus/gles2/gpu_state.cc b/chromium/components/mus/gles2/gpu_state.cc
deleted file mode 100644
index ce00ae30af9..00000000000
--- a/chromium/components/mus/gles2/gpu_state.cc
+++ /dev/null
@@ -1,82 +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 "components/mus/gles2/gpu_state.h"
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread_restrictions.h"
-#include "gpu/config/gpu_info_collector.h"
-#include "ui/gl/gl_implementation.h"
-#include "ui/gl/init/gl_factory.h"
-
-#if defined(USE_OZONE)
-#include "ui/ozone/public/ozone_platform.h"
-#endif
-
-namespace mus {
-
-GpuState::GpuState()
- : gpu_thread_("gpu_thread"),
- control_thread_("gpu_command_buffer_control"),
- gpu_driver_bug_workarounds_(base::CommandLine::ForCurrentProcess()),
- hardware_rendering_available_(false) {
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- gpu_thread_.Start();
- control_thread_.Start();
- control_thread_task_runner_ = control_thread_.task_runner();
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- gpu_thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&GpuState::InitializeOnGpuThread,
- base::Unretained(this), &event));
- event.Wait();
-}
-
-GpuState::~GpuState() {}
-
-void GpuState::StopThreads() {
- control_thread_.Stop();
- gpu_thread_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&GpuState::DestroyGpuSpecificStateOnGpuThread, this));
- gpu_thread_.Stop();
-}
-
-void GpuState::InitializeOnGpuThread(base::WaitableEvent* event) {
-#if defined(USE_OZONE)
- ui::OzonePlatform::InitializeForGPU();
-#endif
- hardware_rendering_available_ = gl::init::InitializeGLOneOff();
- command_buffer_task_runner_ = new CommandBufferTaskRunner;
- driver_manager_.reset(new CommandBufferDriverManager);
- sync_point_manager_.reset(new gpu::SyncPointManager(true));
- share_group_ = new gl::GLShareGroup;
- mailbox_manager_ = new gpu::gles2::MailboxManagerImpl;
-
- // TODO(penghuang): investigate why gpu::CollectBasicGraphicsInfo() failed on
- // windows remote desktop.
- const gl::GLImplementation impl = gl::GetGLImplementation();
- if (impl != gl::kGLImplementationNone &&
- impl != gl::kGLImplementationOSMesaGL &&
- impl != gl::kGLImplementationMockGL) {
- gpu::CollectInfoResult result = gpu::CollectBasicGraphicsInfo(&gpu_info_);
- LOG_IF(ERROR, result != gpu::kCollectInfoSuccess)
- << "Collect basic graphics info failed!";
- }
- if (impl != gl::kGLImplementationNone) {
- gpu::CollectInfoResult result = gpu::CollectContextGraphicsInfo(&gpu_info_);
- LOG_IF(ERROR, result != gpu::kCollectInfoSuccess)
- << "Collect context graphics info failed!";
- }
- event->Signal();
-
-}
-
-void GpuState::DestroyGpuSpecificStateOnGpuThread() {
- driver_manager_.reset();
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gles2/gpu_state.h b/chromium/components/mus/gles2/gpu_state.h
deleted file mode 100644
index f30d485bfc7..00000000000
--- a/chromium/components/mus/gles2/gpu_state.h
+++ /dev/null
@@ -1,107 +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 COMPONENTS_MUS_GLES2_GPU_STATE_H_
-#define COMPONENTS_MUS_GLES2_GPU_STATE_H_
-
-#include <memory>
-
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread.h"
-#include "components/mus/gles2/command_buffer_driver_manager.h"
-#include "components/mus/gles2/command_buffer_task_runner.h"
-#include "gpu/command_buffer/service/gpu_preferences.h"
-#include "gpu/command_buffer/service/mailbox_manager_impl.h"
-#include "gpu/command_buffer/service/sync_point_manager.h"
-#include "gpu/config/gpu_driver_bug_workarounds.h"
-#include "gpu/config/gpu_info.h"
-#include "ui/gl/gl_share_group.h"
-
-namespace {
-class WaitableEvent;
-}
-
-namespace mus {
-
-// We need to share these across all CommandBuffer instances so that contexts
-// they create can share resources with each other via mailboxes.
-class GpuState : public base::RefCountedThreadSafe<GpuState> {
- public:
- GpuState();
-
- // We run the CommandBufferImpl on the control_task_runner, which forwards
- // most method class to the CommandBufferDriver, which runs on the "driver",
- // thread (i.e., the thread on which GpuImpl instances are created).
- scoped_refptr<base::SingleThreadTaskRunner> control_task_runner() {
- return control_thread_task_runner_;
- }
-
- void StopThreads();
-
- const gpu::GpuPreferences& gpu_preferences() const {
- return gpu_preferences_;
- }
-
- const gpu::GpuDriverBugWorkarounds& gpu_driver_bug_workarounds() const {
- return gpu_driver_bug_workarounds_;
- }
-
- CommandBufferTaskRunner* command_buffer_task_runner() const {
- return command_buffer_task_runner_.get();
- }
-
- CommandBufferDriverManager* driver_manager() const {
- return driver_manager_.get();
- }
-
- // These objects are intended to be used on the "driver" thread (i.e., the
- // thread on which GpuImpl instances are created).
- gl::GLShareGroup* share_group() const { return share_group_.get(); }
- gpu::gles2::MailboxManager* mailbox_manager() const {
- return mailbox_manager_.get();
- }
- gpu::SyncPointManager* sync_point_manager() const {
- return sync_point_manager_.get();
- }
-
- const gpu::GPUInfo& gpu_info() const {
- return gpu_info_;
- }
-
- bool HardwareRenderingAvailable() const {
- return hardware_rendering_available_;
- }
-
- private:
- friend class base::RefCountedThreadSafe<GpuState>;
- ~GpuState();
-
- void InitializeOnGpuThread(base::WaitableEvent* event);
-
- void DestroyGpuSpecificStateOnGpuThread();
-
- // |gpu_thread_| is for executing OS GL calls.
- base::Thread gpu_thread_;
- // |control_thread_| is for mojo incoming calls of CommandBufferImpl.
- base::Thread control_thread_;
-
- // Same as control_thread_->task_runner(). The TaskRunner is cached as it may
- // be needed during shutdown.
- scoped_refptr<base::SingleThreadTaskRunner> control_thread_task_runner_;
-
- gpu::GpuPreferences gpu_preferences_;
- const gpu::GpuDriverBugWorkarounds gpu_driver_bug_workarounds_;
- scoped_refptr<CommandBufferTaskRunner> command_buffer_task_runner_;
- std::unique_ptr<CommandBufferDriverManager> driver_manager_;
- std::unique_ptr<gpu::SyncPointManager> sync_point_manager_;
- scoped_refptr<gl::GLShareGroup> share_group_;
- scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager_;
- gpu::GPUInfo gpu_info_;
- bool hardware_rendering_available_;
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GLES2_GPU_STATE_H_
diff --git a/chromium/components/mus/gles2/ozone_gpu_memory_buffer.cc b/chromium/components/mus/gles2/ozone_gpu_memory_buffer.cc
deleted file mode 100644
index c53b51f5ade..00000000000
--- a/chromium/components/mus/gles2/ozone_gpu_memory_buffer.cc
+++ /dev/null
@@ -1,115 +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 "components/mus/gles2/ozone_gpu_memory_buffer.h"
-
-#include "ui/gfx/buffer_format_util.h"
-#include "ui/ozone/public/client_native_pixmap.h"
-#include "ui/ozone/public/client_native_pixmap_factory.h"
-#include "ui/ozone/public/native_pixmap.h"
-#include "ui/ozone/public/ozone_platform.h"
-#include "ui/ozone/public/surface_factory_ozone.h"
-
-namespace mus {
-
-OzoneGpuMemoryBuffer::OzoneGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- std::unique_ptr<ui::ClientNativePixmap> client_pixmap,
- scoped_refptr<ui::NativePixmap> native_pixmap)
- : GpuMemoryBufferImpl(id, size, format),
- client_pixmap_(std::move(client_pixmap)),
- native_pixmap_(native_pixmap) {}
-
-OzoneGpuMemoryBuffer::~OzoneGpuMemoryBuffer() {
- DCHECK(!mapped_);
-}
-
-// static
-OzoneGpuMemoryBuffer* OzoneGpuMemoryBuffer::FromClientBuffer(
- ClientBuffer buffer) {
- return reinterpret_cast<OzoneGpuMemoryBuffer*>(buffer);
-}
-
-// static
-std::unique_ptr<gfx::GpuMemoryBuffer>
-OzoneGpuMemoryBuffer::CreateOzoneGpuMemoryBuffer(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gfx::AcceleratedWidget widget) {
- scoped_refptr<ui::NativePixmap> pixmap =
- ui::OzonePlatform::GetInstance()
- ->GetSurfaceFactoryOzone()
- ->CreateNativePixmap(widget, size, format, usage);
-
- DCHECK(pixmap) << "need pixmap to exist!";
-
- if (!pixmap.get()) {
- DLOG(ERROR) << "Failed to create pixmap " << size.width() << "x"
- << size.height() << " format " << static_cast<int>(format)
- << ", usage " << static_cast<int>(usage);
- return nullptr;
- }
-
- // We construct a ui::NativePixmapHandle
- gfx::NativePixmapHandle native_pixmap_handle = pixmap->ExportHandle();
- DCHECK(ui::ClientNativePixmapFactory::GetInstance())
- << "need me a ClientNativePixmapFactory";
- std::unique_ptr<ui::ClientNativePixmap> client_native_pixmap =
- ui::ClientNativePixmapFactory::GetInstance()->ImportFromHandle(
- native_pixmap_handle, size, usage);
-
- std::unique_ptr<OzoneGpuMemoryBuffer> nb(
- new OzoneGpuMemoryBuffer(gfx::GpuMemoryBufferId(0), size, format,
- std::move(client_native_pixmap), pixmap));
- return std::move(nb);
-}
-
-bool OzoneGpuMemoryBuffer::Map() {
- DCHECK(!mapped_);
- if (!client_pixmap_->Map())
- return false;
- mapped_ = true;
- return mapped_;
-}
-
-void* OzoneGpuMemoryBuffer::memory(size_t plane) {
- DCHECK(mapped_);
- DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_));
- return client_pixmap_->Map();
-}
-
-void OzoneGpuMemoryBuffer::Unmap() {
- DCHECK(mapped_);
- client_pixmap_->Unmap();
- mapped_ = false;
-}
-
-int OzoneGpuMemoryBuffer::stride(size_t plane) const {
- DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_));
- int stride;
- client_pixmap_->GetStride(&stride);
- return stride;
-}
-
-gfx::GpuMemoryBufferHandle OzoneGpuMemoryBuffer::GetHandle() const {
- gfx::GpuMemoryBufferHandle handle;
- handle.type = gfx::OZONE_NATIVE_PIXMAP;
- handle.id = id_;
- return handle;
-}
-
-gfx::GpuMemoryBufferType OzoneGpuMemoryBuffer::GetBufferType() const {
- return gfx::OZONE_NATIVE_PIXMAP;
-}
-
-#if defined(USE_OZONE)
-scoped_refptr<ui::NativePixmap> OzoneGpuMemoryBuffer::GetNativePixmap() {
- return native_pixmap_;
-}
-#endif
-
-} // namespace mus
diff --git a/chromium/components/mus/gles2/ozone_gpu_memory_buffer.h b/chromium/components/mus/gles2/ozone_gpu_memory_buffer.h
deleted file mode 100644
index c5b2ea8a24b..00000000000
--- a/chromium/components/mus/gles2/ozone_gpu_memory_buffer.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_GLES2_OZONE_GPU_MEMORY_BUFFER_
-#define COMPONENTS_MUS_GLES2_OZONE_GPU_MEMORY_BUFFER_
-
-#include <memory>
-
-#include "components/mus/common/gpu_memory_buffer_impl.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/gpu_memory_buffer.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace ui {
-class ClientNativePixmap;
-class NativePixmap;
-} // namespace ui
-
-namespace mus {
-
-// A not-mojo GpuMemoryBuffer implementation solely for use internally to mus
-// for scanout buffers. Note that OzoneGpuMemoryBuffer is for use on the client
-// (aka CC thread).
-class OzoneGpuMemoryBuffer : public mus::GpuMemoryBufferImpl {
- public:
- ~OzoneGpuMemoryBuffer() override;
-
- // gfx::GpuMemoryBuffer implementation
- bool Map() override;
- void Unmap() override;
- void* memory(size_t plane) override;
- int stride(size_t plane) const override;
- gfx::GpuMemoryBufferHandle GetHandle() const override;
-
- // Returns the type of this GpuMemoryBufferImpl.
- gfx::GpuMemoryBufferType GetBufferType() const override;
- scoped_refptr<ui::NativePixmap> GetNativePixmap() override;
-
- // Create a NativeBuffer. The implementation (mus-specific) will call directly
- // into ozone to allocate the buffer. See the version in the .cc file.
- static std::unique_ptr<gfx::GpuMemoryBuffer> CreateOzoneGpuMemoryBuffer(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gfx::AcceleratedWidget widget);
-
- // Cribbed from content/common/gpu/client/gpu_memory_buffer_impl.h
- static OzoneGpuMemoryBuffer* FromClientBuffer(ClientBuffer buffer);
-
- private:
- // TODO(rjkroege): It is conceivable that we do not need an |id| here. It
- // would seem to be a legacy of content leaking into gfx. In a mojo context,
- // perhaps it should be a mojo handle instead.
- OzoneGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- std::unique_ptr<ui::ClientNativePixmap> client_pixmap,
- scoped_refptr<ui::NativePixmap> native_pixmap);
-
- // The real backing buffer.
- // From content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_pixmap.h
- std::unique_ptr<ui::ClientNativePixmap> client_pixmap_;
- scoped_refptr<ui::NativePixmap> native_pixmap_;
-
- DISALLOW_COPY_AND_ASSIGN(OzoneGpuMemoryBuffer);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GLES2_OZONE_GPU_MEMORY_BUFFER_
diff --git a/chromium/components/mus/gles2/raster_thread_helper.cc b/chromium/components/mus/gles2/raster_thread_helper.cc
deleted file mode 100644
index 93e37405e78..00000000000
--- a/chromium/components/mus/gles2/raster_thread_helper.cc
+++ /dev/null
@@ -1,27 +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 "components/mus/gles2/raster_thread_helper.h"
-
-#include "base/logging.h"
-#include "base/threading/simple_thread.h"
-#include "cc/raster/single_thread_task_graph_runner.h"
-
-namespace gles2 {
-
-RasterThreadHelper::RasterThreadHelper()
- : task_graph_runner_(new cc::SingleThreadTaskGraphRunner) {
- task_graph_runner_->Start("CompositorTileWorker1",
- base::SimpleThread::Options());
-}
-
-RasterThreadHelper::~RasterThreadHelper() {
- task_graph_runner_->Shutdown();
-}
-
-cc::TaskGraphRunner* RasterThreadHelper::task_graph_runner() {
- return task_graph_runner_.get();
-}
-
-} // namespace gles2
diff --git a/chromium/components/mus/gles2/raster_thread_helper.h b/chromium/components/mus/gles2/raster_thread_helper.h
deleted file mode 100644
index a43dfab0810..00000000000
--- a/chromium/components/mus/gles2/raster_thread_helper.h
+++ /dev/null
@@ -1,34 +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 COMPONENTS_MUS_GLES2_RASTER_THREAD_HELPER_H_
-#define COMPONENTS_MUS_GLES2_RASTER_THREAD_HELPER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-
-namespace cc {
-class TaskGraphRunner;
-class SingleThreadTaskGraphRunner;
-}
-
-namespace gles2 {
-
-class RasterThreadHelper {
- public:
- RasterThreadHelper();
- ~RasterThreadHelper();
-
- cc::TaskGraphRunner* task_graph_runner();
-
- private:
- std::unique_ptr<cc::SingleThreadTaskGraphRunner> task_graph_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(RasterThreadHelper);
-};
-
-} // namespace gles2
-
-#endif // COMPONENTS_MUS_GLES2_RASTER_THREAD_HELPER_H_
diff --git a/chromium/components/mus/gpu/BUILD.gn b/chromium/components/mus/gpu/BUILD.gn
deleted file mode 100644
index 8ba5cabfd1e..00000000000
--- a/chromium/components/mus/gpu/BUILD.gn
+++ /dev/null
@@ -1,65 +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.
-
-import("//build/config/ui.gni")
-import("//mojo/public/mojo_application_manifest.gni")
-import("//testing/test.gni")
-
-source_set("gpu") {
- output_name = "mus_gpu"
-
- sources = [
- "gpu_service_impl.cc",
- "gpu_service_impl.h",
- "gpu_service_mus.cc",
- "gpu_service_mus.h",
- "mus_gpu_memory_buffer_manager.cc",
- "mus_gpu_memory_buffer_manager.h",
- ]
-
- deps = [
- "//components/mus/common:mus_common",
- "//components/mus/public/interfaces",
- "//gpu/ipc/common",
- "//gpu/ipc/service",
- "//ipc",
- "//media/gpu/ipc/service",
- "//mojo/public/cpp/system",
- "//services/shell/public/cpp",
- "//ui/gfx:memory_buffer",
- "//ui/gl/init",
- ]
-
- if (use_ozone) {
- deps += [ "//ui/ozone:ozone" ]
- }
-}
-
-group("tests") {
- testonly = true
- deps = [
- ":mus_gpu_unittests",
- ]
-}
-
-test("mus_gpu_unittests") {
- deps = [
- ":gpu",
- "//base",
- "//components/mus/common:run_all_shelltests",
- "//ipc",
- "//testing/gtest",
- "//ui/gfx:memory_buffer",
- "//ui/gfx/geometry",
- ]
-
- data_deps = [
- ":mus_gpu_unittests_app_manifest",
- ]
-}
-
-mojo_application_manifest("mus_gpu_unittests_app_manifest") {
- application_name = "mus_gpu_unittests_app"
- source = "mus_gpu_unittests_app_manifest.json"
-}
diff --git a/chromium/components/mus/gpu/DEPS b/chromium/components/mus/gpu/DEPS
deleted file mode 100644
index 004a2b9f68f..00000000000
--- a/chromium/components/mus/gpu/DEPS
+++ /dev/null
@@ -1,21 +0,0 @@
-include_rules = [
- "+gpu/command_buffer",
- "+gpu/config",
- "+gpu/ipc/common",
- "+gpu/ipc/client/gpu_channel_host.h",
- "+gpu/ipc/service",
- "+media/gpu/ipc/service",
-]
-
-specific_include_rules = {
- "gpu_service_mus\.h": [
- # A GpuChannelHost is used by mus locally.
- "+gpu/ipc/client/gpu_channel_host.h",
- ],
-
- "mus_gpu_memory_buffer_manager\.cc": [
- # The GpuMemoryBufferManager implementation used by mus locally.
- "+gpu/ipc/client/gpu_memory_buffer_impl.h",
- "+gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.h",
- ]
-}
diff --git a/chromium/components/mus/gpu/OWNERS b/chromium/components/mus/gpu/OWNERS
deleted file mode 100644
index 1f1af6bcc54..00000000000
--- a/chromium/components/mus/gpu/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-fsamuel@chromium.org
-rjkroege@chromium.org
diff --git a/chromium/components/mus/gpu/display_compositor/BUILD.gn b/chromium/components/mus/gpu/display_compositor/BUILD.gn
deleted file mode 100644
index a30b59f2c89..00000000000
--- a/chromium/components/mus/gpu/display_compositor/BUILD.gn
+++ /dev/null
@@ -1,30 +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.
-
-import("//build/config/ui.gni")
-
-source_set("display_compositor") {
- sources = [
- "compositor_frame_sink_delegate.h",
- "compositor_frame_sink_factory_impl.cc",
- "compositor_frame_sink_factory_impl.h",
- "compositor_frame_sink_impl.cc",
- "compositor_frame_sink_impl.h",
- "display_compositor_impl.cc",
- "display_compositor_impl.h",
- "display_impl.cc",
- "display_impl.h",
- ]
-
- deps = [
- "//base",
- "//cc",
- "//cc/surfaces",
- "//cc/surfaces:surface_id",
- "//components/mus/public/interfaces/gpu:interfaces",
-
- # TODO(fsamuel): Remove this dependency.
- "//components/mus/surfaces",
- ]
-}
diff --git a/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_delegate.h b/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_delegate.h
deleted file mode 100644
index ee377aadc49..00000000000
--- a/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_delegate.h
+++ /dev/null
@@ -1,27 +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 COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_COMPOSITOR_FRAME_SINK_DELEGATE_H_
-#define COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_COMPOSITOR_FRAME_SINK_DELEGATE_H_
-
-#include "cc/surfaces/surface_id.h"
-
-namespace mus {
-namespace gpu {
-
-class CompositorFrameSinkImpl;
-
-// A CompositorFrameSinkDelegate decouples CompositorFrameSinks from their
-// factories enabling them to be unit tested.
-class CompositorFrameSinkDelegate {
- public:
- virtual void CompositorFrameSinkConnectionLost(int sink_id) = 0;
-
- virtual cc::SurfaceId GenerateSurfaceId() = 0;
-};
-
-} // namespace gpu
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_COMPOSITOR_FRAME_SINK_DELEGATE_H_
diff --git a/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_factory_impl.cc b/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_factory_impl.cc
deleted file mode 100644
index 5c52940a984..00000000000
--- a/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_factory_impl.cc
+++ /dev/null
@@ -1,46 +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 "components/mus/gpu/display_compositor/compositor_frame_sink_factory_impl.h"
-
-#include "base/memory/ptr_util.h"
-#include "cc/surfaces/surface_id.h"
-#include "components/mus/gpu/display_compositor/compositor_frame_sink_impl.h"
-
-namespace mus {
-namespace gpu {
-
-CompositorFrameSinkFactoryImpl::CompositorFrameSinkFactoryImpl(
- uint32_t client_id,
- mojo::InterfaceRequest<mojom::CompositorFrameSinkFactory> request,
- const scoped_refptr<SurfacesState>& surfaces_state)
- : client_id_(client_id),
- surfaces_state_(surfaces_state),
- allocator_(client_id),
- binding_(this, std::move(request)) {}
-
-CompositorFrameSinkFactoryImpl::~CompositorFrameSinkFactoryImpl() {}
-
-void CompositorFrameSinkFactoryImpl::CompositorFrameSinkConnectionLost(
- int local_id) {
- sinks_.erase(local_id);
-}
-
-cc::SurfaceId CompositorFrameSinkFactoryImpl::GenerateSurfaceId() {
- return allocator_.GenerateId();
-}
-
-void CompositorFrameSinkFactoryImpl::CreateCompositorFrameSink(
- uint32_t local_id,
- uint64_t nonce,
- mojo::InterfaceRequest<mojom::CompositorFrameSink> sink,
- mojom::CompositorFrameSinkClientPtr client) {
- // TODO(fsamuel): Use nonce once patch lands:
- // https://codereview.chromium.org/1996783002/
- sinks_[local_id] = base::WrapUnique(new CompositorFrameSinkImpl(
- this, local_id, surfaces_state_, std::move(sink), std::move(client)));
-}
-
-} // namespace gpu
-} // namespace mus
diff --git a/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_factory_impl.h b/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_factory_impl.h
deleted file mode 100644
index 50aa0a5a0d3..00000000000
--- a/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_factory_impl.h
+++ /dev/null
@@ -1,55 +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 COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_COMPOSITOR_FRAME_SINK_FACTORY_IMPL_H_
-#define COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_COMPOSITOR_FRAME_SINK_FACTORY_IMPL_H_
-
-#include "cc/surfaces/surface_id_allocator.h"
-#include "components/mus/gpu/display_compositor/compositor_frame_sink_delegate.h"
-#include "components/mus/public/interfaces/gpu/display_compositor.mojom.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace mus {
-namespace gpu {
-
-class CompositorFrameSinkImpl;
-
-class CompositorFrameSinkFactoryImpl : public mojom::CompositorFrameSinkFactory,
- public CompositorFrameSinkDelegate {
- public:
- CompositorFrameSinkFactoryImpl(
- uint32_t client_id,
- mojo::InterfaceRequest<mojom::CompositorFrameSinkFactory> request,
- const scoped_refptr<SurfacesState>& surfaces_state);
- ~CompositorFrameSinkFactoryImpl() override;
-
- uint32_t client_id() const { return client_id_; }
-
- void CompositorFrameSinkConnectionLost(int local_id) override;
- cc::SurfaceId GenerateSurfaceId() override;
-
- // mojom::CompositorFrameSinkFactory implementation.
- void CreateCompositorFrameSink(
- uint32_t local_id,
- uint64_t nonce,
- mojo::InterfaceRequest<mojom::CompositorFrameSink> sink,
- mojom::CompositorFrameSinkClientPtr client) override;
-
- private:
- const uint32_t client_id_;
- scoped_refptr<SurfacesState> surfaces_state_;
- cc::SurfaceIdAllocator allocator_;
- using CompositorFrameSinkMap =
- std::map<uint32_t, std::unique_ptr<CompositorFrameSinkImpl>>;
- CompositorFrameSinkMap sinks_;
- mojo::StrongBinding<mojom::CompositorFrameSinkFactory> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkFactoryImpl);
-};
-
-} // namespace gpu
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_COMPOSITOR_FRAME_SINK_FACTORY_IMPL_H_
diff --git a/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_impl.cc b/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_impl.cc
deleted file mode 100644
index 80bb15197df..00000000000
--- a/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_impl.cc
+++ /dev/null
@@ -1,112 +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 "components/mus/gpu/display_compositor/compositor_frame_sink_impl.h"
-
-#include "cc/ipc/compositor_frame.mojom.h"
-#include "cc/surfaces/surface_factory.h"
-#include "components/mus/gpu/display_compositor/compositor_frame_sink_delegate.h"
-
-namespace mus {
-namespace gpu {
-
-namespace {
-
-void CallCallback(
- const mojom::CompositorFrameSink::SubmitCompositorFrameCallback& callback,
- cc::SurfaceDrawStatus draw_status) {
- callback.Run(static_cast<mojom::CompositorFrameDrawStatus>(draw_status));
-}
-}
-
-CompositorFrameSinkImpl::CompositorFrameSinkImpl(
- CompositorFrameSinkDelegate* delegate,
- int sink_id,
- const scoped_refptr<SurfacesState>& surfaces_state,
- mojo::InterfaceRequest<mojom::CompositorFrameSink> request,
- mojom::CompositorFrameSinkClientPtr client)
- : delegate_(delegate),
- surfaces_state_(surfaces_state),
- sink_id_(sink_id),
- begin_frame_source_(nullptr),
- needs_begin_frame_(false),
- factory_(surfaces_state->manager(), this),
- client_(std::move(client)),
- binding_(this, std::move(request)) {
- DCHECK(delegate_);
- binding_.set_connection_error_handler(base::Bind(
- &CompositorFrameSinkImpl::OnConnectionLost, base::Unretained(this)));
-}
-
-CompositorFrameSinkImpl::~CompositorFrameSinkImpl() {}
-
-void CompositorFrameSinkImpl::SetNeedsBeginFrame(bool needs_begin_frame) {
- if (needs_begin_frame_ == needs_begin_frame)
- return;
-
- needs_begin_frame_ = needs_begin_frame;
- if (begin_frame_source_) {
- if (needs_begin_frame_)
- begin_frame_source_->AddObserver(this);
- else
- begin_frame_source_->RemoveObserver(this);
- }
-}
-
-void CompositorFrameSinkImpl::SubmitCompositorFrame(
- cc::CompositorFrame compositor_frame,
- const SubmitCompositorFrameCallback& callback) {
- gfx::Size frame_size =
- compositor_frame.delegated_frame_data->render_pass_list.back()
- ->output_rect.size();
- if (frame_size.IsEmpty() || frame_size != last_submitted_frame_size_) {
- if (!surface_id_.is_null())
- factory_.Destroy(surface_id_);
- // TODO(fsamuel): The allocator should live on CompositorFrameSinkFactory.
- surface_id_ = delegate_->GenerateSurfaceId();
- factory_.Create(surface_id_);
- last_submitted_frame_size_ = frame_size;
- }
- factory_.SubmitCompositorFrame(surface_id_, std::move(compositor_frame),
- base::Bind(&CallCallback, callback));
-}
-
-void CompositorFrameSinkImpl::ReturnResources(
- const cc::ReturnedResourceArray& resources) {
- if (!client_)
- return;
-
- client_->ReturnResources(mojo::Array<cc::ReturnedResource>::From(resources));
-}
-
-void CompositorFrameSinkImpl::WillDrawSurface(const cc::SurfaceId& surface_id,
- const gfx::Rect& damage_rect) {
- NOTIMPLEMENTED();
-}
-
-void CompositorFrameSinkImpl::SetBeginFrameSource(
- cc::BeginFrameSource* begin_frame_source) {
- begin_frame_source_ = begin_frame_source;
-}
-
-void CompositorFrameSinkImpl::OnBeginFrame(const cc::BeginFrameArgs& args) {
- // TODO(fsamuel): Implement this.
-}
-
-const cc::BeginFrameArgs& CompositorFrameSinkImpl::LastUsedBeginFrameArgs()
- const {
- // TODO(fsamuel): Implement this.
- return last_used_begin_frame_args_;
-}
-
-void CompositorFrameSinkImpl::OnBeginFrameSourcePausedChanged(bool paused) {
- // TODO(fsamuel): Implement this.
-}
-
-void CompositorFrameSinkImpl::OnConnectionLost() {
- delegate_->CompositorFrameSinkConnectionLost(sink_id_);
-}
-
-} // namespace gpu
-} // namespace mus
diff --git a/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_impl.h b/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_impl.h
deleted file mode 100644
index e402a7ce2ce..00000000000
--- a/chromium/components/mus/gpu/display_compositor/compositor_frame_sink_impl.h
+++ /dev/null
@@ -1,74 +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 COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_COMPOSITOR_FRAME_SINK_IMPL_H_
-#define COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_COMPOSITOR_FRAME_SINK_IMPL_H_
-
-#include "base/memory/ref_counted.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
-#include "cc/surfaces/surface_id.h"
-#include "components/mus/public/interfaces/gpu/display_compositor.mojom.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace mus {
-namespace gpu {
-
-class CompositorFrameSinkDelegate;
-
-// A client presents visuals to screen by submitting CompositorFrames to a
-// CompositorFrameSink.
-class CompositorFrameSinkImpl : public cc::SurfaceFactoryClient,
- public mojom::CompositorFrameSink,
- public cc::BeginFrameObserver {
- public:
- CompositorFrameSinkImpl(
- CompositorFrameSinkDelegate* delegate,
- int sink_id,
- const scoped_refptr<SurfacesState>& surfaces_state,
- mojo::InterfaceRequest<mojom::CompositorFrameSink> request,
- mojom::CompositorFrameSinkClientPtr client);
- ~CompositorFrameSinkImpl() override;
-
- // mojom::CompositorFrameSink implementation.
- void SetNeedsBeginFrame(bool needs_begin_frame) override;
- void SubmitCompositorFrame(
- cc::CompositorFrame compositor_frame,
- const SubmitCompositorFrameCallback& callback) override;
-
- private:
- // SurfaceFactoryClient implementation.
- void ReturnResources(const cc::ReturnedResourceArray& resources) override;
- void WillDrawSurface(const cc::SurfaceId& surface_id,
- const gfx::Rect& damage_rect) override;
- void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
-
- // BeginFrameObserver implementation.
- void OnBeginFrame(const cc::BeginFrameArgs& args) override;
- const cc::BeginFrameArgs& LastUsedBeginFrameArgs() const override;
- void OnBeginFrameSourcePausedChanged(bool paused) override;
-
- void OnConnectionLost();
-
- CompositorFrameSinkDelegate* const delegate_;
- scoped_refptr<SurfacesState> surfaces_state_;
- const int sink_id_;
- cc::BeginFrameSource* begin_frame_source_;
- bool needs_begin_frame_;
- cc::BeginFrameArgs last_used_begin_frame_args_;
- cc::SurfaceFactory factory_;
- cc::SurfaceId surface_id_;
- gfx::Size last_submitted_frame_size_;
- mojom::CompositorFrameSinkClientPtr client_;
- mojo::Binding<mojom::CompositorFrameSink> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkImpl);
-};
-
-} // namespace gpu
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_COMPOSITOR_FRAME_SINK_IMPL_H_
diff --git a/chromium/components/mus/gpu/display_compositor/display_compositor_impl.cc b/chromium/components/mus/gpu/display_compositor/display_compositor_impl.cc
deleted file mode 100644
index cf9a24df684..00000000000
--- a/chromium/components/mus/gpu/display_compositor/display_compositor_impl.cc
+++ /dev/null
@@ -1,28 +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 "components/mus/gpu/display_compositor/display_compositor_impl.h"
-
-#include "components/mus/gpu/display_compositor/display_impl.h"
-
-namespace mus {
-namespace gpu {
-
-DisplayCompositorImpl::DisplayCompositorImpl(
- mojo::InterfaceRequest<mojom::DisplayCompositor> request)
- : binding_(this, std::move(request)) {}
-
-DisplayCompositorImpl::~DisplayCompositorImpl() {}
-
-void DisplayCompositorImpl::CreateDisplay(
- int accelerated_widget,
- mojo::InterfaceRequest<mojom::Display> display,
- mojom::DisplayHostPtr host,
- mojo::InterfaceRequest<mojom::CompositorFrameSink> sink,
- mojom::CompositorFrameSinkClientPtr client) {
- NOTIMPLEMENTED();
-}
-
-} // namespace gpu
-} // namespace mus
diff --git a/chromium/components/mus/gpu/display_compositor/display_compositor_impl.h b/chromium/components/mus/gpu/display_compositor/display_compositor_impl.h
deleted file mode 100644
index 237cc108b7c..00000000000
--- a/chromium/components/mus/gpu/display_compositor/display_compositor_impl.h
+++ /dev/null
@@ -1,37 +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 COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_DISPLAY_COMPOSITOR_IMPL_H_
-#define COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_DISPLAY_COMPOSITOR_IMPL_H_
-
-#include "components/mus/public/interfaces/gpu/display_compositor.mojom.h"
-#include "components/mus/public/interfaces/gpu/display_compositor_host.mojom.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace mus {
-namespace gpu {
-
-class DisplayCompositorImpl : public mojom::DisplayCompositor {
- public:
- explicit DisplayCompositorImpl(
- mojo::InterfaceRequest<mojom::DisplayCompositor> request);
- ~DisplayCompositorImpl() override;
-
- // mojom::DisplayCompositor implementation.
- void CreateDisplay(int accelerated_widget,
- mojo::InterfaceRequest<mojom::Display> display,
- mojom::DisplayHostPtr host,
- mojo::InterfaceRequest<mojom::CompositorFrameSink> sink,
- mojom::CompositorFrameSinkClientPtr client) override;
-
- private:
- mojo::StrongBinding<mojom::DisplayCompositor> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(DisplayCompositorImpl);
-};
-
-} // namespace gpu
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_DISPLAY_COMPOSITOR_IMPL_H_
diff --git a/chromium/components/mus/gpu/display_compositor/display_impl.cc b/chromium/components/mus/gpu/display_compositor/display_impl.cc
deleted file mode 100644
index 274c67acbb1..00000000000
--- a/chromium/components/mus/gpu/display_compositor/display_impl.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/mus/gpu/display_compositor/display_impl.h"
-
-#include "components/mus/gpu/display_compositor/compositor_frame_sink_impl.h"
-
-namespace mus {
-namespace gpu {
-
-DisplayImpl::DisplayImpl(
- int accelerated_widget,
- mojo::InterfaceRequest<mojom::Display> display,
- mojom::DisplayHostPtr host,
- mojo::InterfaceRequest<mojom::CompositorFrameSink> sink,
- mojom::CompositorFrameSinkClientPtr client,
- const scoped_refptr<SurfacesState>& surfaces_state)
- : binding_(this, std::move(display)) {
- const uint32_t client_id = 1;
- sink_.reset(new CompositorFrameSinkImpl(this, client_id, surfaces_state,
- std::move(sink), std::move(client)));
-}
-
-DisplayImpl::~DisplayImpl() {}
-
-void DisplayImpl::CreateClient(
- uint32_t client_id,
- mojo::InterfaceRequest<mojom::DisplayClient> client) {
- NOTIMPLEMENTED();
-}
-
-void DisplayImpl::CompositorFrameSinkConnectionLost(int sink_id) {
- NOTIMPLEMENTED();
-}
-
-cc::SurfaceId DisplayImpl::GenerateSurfaceId() {
- NOTIMPLEMENTED();
- return cc::SurfaceId();
-}
-
-} // namespace gpu
-} // namespace mus
diff --git a/chromium/components/mus/gpu/display_compositor/display_impl.h b/chromium/components/mus/gpu/display_compositor/display_impl.h
deleted file mode 100644
index c667bcbde03..00000000000
--- a/chromium/components/mus/gpu/display_compositor/display_impl.h
+++ /dev/null
@@ -1,44 +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 COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_DISPLAY_IMPL_H_
-#define COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_DISPLAY_IMPL_H_
-
-#include "components/mus/gpu/display_compositor/compositor_frame_sink_delegate.h"
-#include "components/mus/public/interfaces/gpu/display_compositor_host.mojom.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace mus {
-namespace gpu {
-
-class DisplayImpl : public mojom::Display, public CompositorFrameSinkDelegate {
- public:
- DisplayImpl(int accelerated_widget,
- mojo::InterfaceRequest<mojom::Display> display,
- mojom::DisplayHostPtr host,
- mojo::InterfaceRequest<mojom::CompositorFrameSink> sink,
- mojom::CompositorFrameSinkClientPtr client,
- const scoped_refptr<SurfacesState>& surfaces_state);
- ~DisplayImpl() override;
-
- // mojom::Display implementation.
- void CreateClient(
- uint32_t client_id,
- mojo::InterfaceRequest<mojom::DisplayClient> client) override;
-
- private:
- // CompositorFrameSinkDelegate implementation:
- void CompositorFrameSinkConnectionLost(int sink_id) override;
- cc::SurfaceId GenerateSurfaceId() override;
-
- std::unique_ptr<CompositorFrameSinkImpl> sink_;
- mojo::Binding<mojom::Display> binding_;
- DISALLOW_COPY_AND_ASSIGN(DisplayImpl);
-};
-
-} // namespace gpu
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GPU_DISPLAY_COMPOSITOR_DISPLAY_IMPL_H_
diff --git a/chromium/components/mus/gpu/gpu_service_impl.cc b/chromium/components/mus/gpu/gpu_service_impl.cc
deleted file mode 100644
index 9ea83820ffe..00000000000
--- a/chromium/components/mus/gpu/gpu_service_impl.cc
+++ /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.
-
-#include "components/mus/gpu/gpu_service_impl.h"
-
-#include "components/mus/common/gpu_type_converters.h"
-#include "components/mus/gpu/gpu_service_mus.h"
-#include "services/shell/public/cpp/connection.h"
-
-namespace mus {
-
-namespace {
-
-void EstablishGpuChannelDone(
- const mojom::GpuService::EstablishGpuChannelCallback& callback,
- int32_t client_id,
- const IPC::ChannelHandle& channel_handle) {
- // TODO(penghuang): Send the real GPUInfo to the client.
- callback.Run(client_id, mojom::ChannelHandle::From(channel_handle),
- mojom::GpuInfo::From<gpu::GPUInfo>(gpu::GPUInfo()));
-}
-}
-
-GpuServiceImpl::GpuServiceImpl(
- mojo::InterfaceRequest<mojom::GpuService> request,
- shell::Connection* connection)
- : binding_(this, std::move(request)) {}
-
-GpuServiceImpl::~GpuServiceImpl() {}
-
-void GpuServiceImpl::EstablishGpuChannel(
- const mojom::GpuService::EstablishGpuChannelCallback& callback) {
- GpuServiceMus* service = GpuServiceMus::GetInstance();
- // TODO(penghuang): crbug.com/617415 figure out how to generate a meaningful
- // tracing id.
- const uint64_t client_tracing_id = 0;
- // TODO(penghuang): windows server may want to control those flags.
- // Add a private interface for windows server.
- const bool preempts = false;
- const bool allow_view_command_buffers = false;
- const bool allow_real_time_streams = false;
- service->EstablishGpuChannel(
- client_tracing_id, preempts, allow_view_command_buffers,
- allow_real_time_streams, base::Bind(&EstablishGpuChannelDone, callback));
-}
-
-void GpuServiceImpl::CreateGpuMemoryBuffer(
- mojom::GpuMemoryBufferIdPtr id,
- const gfx::Size& size,
- mojom::BufferFormat format,
- mojom::BufferUsage usage,
- uint64_t surface_id,
- const mojom::GpuService::CreateGpuMemoryBufferCallback& callback) {
- NOTIMPLEMENTED();
-}
-
-void GpuServiceImpl::DestroyGpuMemoryBuffer(mojom::GpuMemoryBufferIdPtr id,
- const gpu::SyncToken& sync_token) {
- NOTIMPLEMENTED();
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gpu/gpu_service_impl.h b/chromium/components/mus/gpu/gpu_service_impl.h
deleted file mode 100644
index 9d5f66ec715..00000000000
--- a/chromium/components/mus/gpu/gpu_service_impl.h
+++ /dev/null
@@ -1,49 +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 COMPONENTS_MUS_GPU_GPU_SERVICE_IMPL_H_
-#define COMPONENTS_MUS_GPU_GPU_SERVICE_IMPL_H_
-
-#include "components/mus/public/interfaces/gpu_memory_buffer.mojom.h"
-#include "components/mus/public/interfaces/gpu_service.mojom.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace shell {
-class Connection;
-}
-
-namespace mus {
-
-class GpuServiceImpl : public mojom::GpuService {
- public:
- GpuServiceImpl(mojo::InterfaceRequest<mojom::GpuService> request,
- shell::Connection* connection);
- ~GpuServiceImpl() override;
-
- // mojom::GpuService overrides:
- void EstablishGpuChannel(
- const mojom::GpuService::EstablishGpuChannelCallback& callback) override;
-
- void CreateGpuMemoryBuffer(
- mojom::GpuMemoryBufferIdPtr id,
- const gfx::Size& size,
- mojom::BufferFormat format,
- mojom::BufferUsage usage,
- uint64_t surface_id,
- const mojom::GpuService::CreateGpuMemoryBufferCallback& callback)
- override;
-
- void DestroyGpuMemoryBuffer(mojom::GpuMemoryBufferIdPtr id,
- const gpu::SyncToken& sync_token) override;
-
- private:
- mojo::StrongBinding<GpuService> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuServiceImpl);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GPU_GPU_SERVICE_IMPL_H_
diff --git a/chromium/components/mus/gpu/gpu_service_mus.cc b/chromium/components/mus/gpu/gpu_service_mus.cc
deleted file mode 100644
index 43ddb21ab00..00000000000
--- a/chromium/components/mus/gpu/gpu_service_mus.cc
+++ /dev/null
@@ -1,273 +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 "components/mus/gpu/gpu_service_mus.h"
-
-#include "base/memory/shared_memory.h"
-#include "base/memory/singleton.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "components/mus/gpu/mus_gpu_memory_buffer_manager.h"
-#include "gpu/command_buffer/service/gpu_switches.h"
-#include "gpu/command_buffer/service/sync_point_manager.h"
-#include "gpu/config/gpu_info_collector.h"
-#include "gpu/config/gpu_switches.h"
-#include "gpu/config/gpu_util.h"
-#include "gpu/ipc/common/gpu_memory_buffer_support.h"
-#include "gpu/ipc/common/memory_stats.h"
-#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
-#include "ipc/ipc_channel_handle.h"
-#include "ipc/ipc_sync_message_filter.h"
-#include "media/gpu/ipc/service/gpu_jpeg_decode_accelerator.h"
-#include "media/gpu/ipc/service/gpu_video_decode_accelerator.h"
-#include "media/gpu/ipc/service/gpu_video_encode_accelerator.h"
-#include "media/gpu/ipc/service/media_service.h"
-#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_switches.h"
-#include "ui/gl/gpu_switching_manager.h"
-#include "ui/gl/init/gl_factory.h"
-#include "url/gurl.h"
-
-#if defined(USE_OZONE)
-#include "ui/ozone/public/ozone_platform.h"
-#endif
-
-namespace mus {
-namespace {
-
-const int kLocalGpuChannelClientId = 1;
-const uint64_t kLocalGpuChannelClientTracingId = 1;
-
-void EstablishGpuChannelDone(
- int client_id,
- const IPC::ChannelHandle* channel_handle,
- const GpuServiceMus::EstablishGpuChannelCallback& callback) {
- callback.Run(channel_handle ? client_id : -1, *channel_handle);
-}
-}
-
-GpuServiceMus::GpuServiceMus()
- : next_client_id_(kLocalGpuChannelClientId),
- main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- shutdown_event_(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED),
- gpu_thread_("GpuThread"),
- io_thread_("GpuIOThread") {
- Initialize();
-}
-
-GpuServiceMus::~GpuServiceMus() {
- // Signal this event before destroying the child process. That way all
- // background threads can cleanup.
- // For example, in the renderer the RenderThread instances will be able to
- // notice shutdown before the render process begins waiting for them to exit.
- shutdown_event_.Signal();
- io_thread_.Stop();
-}
-
-void GpuServiceMus::EstablishGpuChannel(
- uint64_t client_tracing_id,
- bool preempts,
- bool allow_view_command_buffers,
- bool allow_real_time_streams,
- const EstablishGpuChannelCallback& callback) {
- DCHECK(CalledOnValidThread());
-
- if (!gpu_channel_manager_) {
- callback.Run(-1, IPC::ChannelHandle());
- return;
- }
-
- const int client_id = ++next_client_id_;
- IPC::ChannelHandle* channel_handle = new IPC::ChannelHandle;
- gpu_thread_.task_runner()->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&GpuServiceMus::EstablishGpuChannelOnGpuThread,
- base::Unretained(this), client_id, client_tracing_id, preempts,
- allow_view_command_buffers, allow_real_time_streams,
- base::Unretained(channel_handle)),
- base::Bind(&EstablishGpuChannelDone, client_id,
- base::Owned(channel_handle), callback));
-}
-
-gfx::GpuMemoryBufferHandle GpuServiceMus::CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- int client_id,
- gpu::SurfaceHandle surface_handle) {
- DCHECK(CalledOnValidThread());
- return gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(
- id, size, format, usage, client_id, surface_handle);
-}
-
-void GpuServiceMus::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- int client_id,
- const gpu::SyncToken& sync_token) {
- DCHECK(CalledOnValidThread());
-
- if (gpu_channel_manager_)
- gpu_channel_manager_->DestroyGpuMemoryBuffer(id, client_id, sync_token);
-}
-
-void GpuServiceMus::DidCreateOffscreenContext(const GURL& active_url) {
- NOTIMPLEMENTED();
-}
-
-void GpuServiceMus::DidDestroyChannel(int client_id) {
- media_service_->RemoveChannel(client_id);
- NOTIMPLEMENTED();
-}
-
-void GpuServiceMus::DidDestroyOffscreenContext(const GURL& active_url) {
- NOTIMPLEMENTED();
-}
-
-void GpuServiceMus::DidLoseContext(bool offscreen,
- gpu::error::ContextLostReason reason,
- const GURL& active_url) {
- NOTIMPLEMENTED();
-}
-
-void GpuServiceMus::GpuMemoryUmaStats(const gpu::GPUMemoryUmaStats& params) {
- NOTIMPLEMENTED();
-}
-
-void GpuServiceMus::StoreShaderToDisk(int client_id,
- const std::string& key,
- const std::string& shader) {
- NOTIMPLEMENTED();
-}
-
-#if defined(OS_WIN)
-void GpuServiceMus::SendAcceleratedSurfaceCreatedChildWindow(
- gpu::SurfaceHandle parent_window,
- gpu::SurfaceHandle child_window) {
- NOTIMPLEMENTED();
-}
-#endif
-
-void GpuServiceMus::SetActiveURL(const GURL& url) {
- NOTIMPLEMENTED();
-}
-
-void GpuServiceMus::Initialize() {
- DCHECK(CalledOnValidThread());
- base::Thread::Options thread_options(base::MessageLoop::TYPE_DEFAULT, 0);
- thread_options.priority = base::ThreadPriority::NORMAL;
- CHECK(gpu_thread_.StartWithOptions(thread_options));
-
- thread_options = base::Thread::Options(base::MessageLoop::TYPE_IO, 0);
- thread_options.priority = base::ThreadPriority::NORMAL;
-#if defined(OS_ANDROID)
- // TODO(reveman): Remove this in favor of setting it explicitly for each type
- // of process.
- thread_options.priority = base::ThreadPriority::DISPLAY;
-#endif
- CHECK(io_thread_.StartWithOptions(thread_options));
-
- IPC::ChannelHandle channel_handle;
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- gpu_thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&GpuServiceMus::InitializeOnGpuThread,
- base::Unretained(this), &channel_handle, &event));
- event.Wait();
-
- gpu_memory_buffer_manager_local_.reset(
- new MusGpuMemoryBufferManager(this, kLocalGpuChannelClientId));
- gpu_channel_local_ = gpu::GpuChannelHost::Create(
- this, kLocalGpuChannelClientId, gpu_info_, channel_handle,
- &shutdown_event_, gpu_memory_buffer_manager_local_.get());
-}
-
-void GpuServiceMus::InitializeOnGpuThread(IPC::ChannelHandle* channel_handle,
- base::WaitableEvent* event) {
- gpu_info_.video_decode_accelerator_capabilities =
- media::GpuVideoDecodeAccelerator::GetCapabilities(gpu_preferences_);
- gpu_info_.video_encode_accelerator_supported_profiles =
- media::GpuVideoEncodeAccelerator::GetSupportedProfiles(gpu_preferences_);
- gpu_info_.jpeg_decode_accelerator_supported =
- media::GpuJpegDecodeAccelerator::IsSupported();
-
-#if defined(USE_OZONE)
- ui::OzonePlatform::InitializeForGPU();
-#endif
-
- if (gpu::GetNativeGpuMemoryBufferType() != gfx::EMPTY_BUFFER) {
- gpu_memory_buffer_factory_ =
- gpu::GpuMemoryBufferFactory::CreateNativeType();
- }
-
- if (!gl::init::InitializeGLOneOff())
- VLOG(1) << "gl::init::InitializeGLOneOff failed";
-
- DCHECK(!owned_sync_point_manager_);
- const bool allow_threaded_wait = false;
- owned_sync_point_manager_.reset(
- new gpu::SyncPointManager(allow_threaded_wait));
-
- // Defer creation of the render thread. This is to prevent it from handling
- // IPC messages before the sandbox has been enabled and all other necessary
- // initialization has succeeded.
- // TODO(penghuang): implement a watchdog.
- gpu::GpuWatchdog* watchdog = nullptr;
- gpu_channel_manager_.reset(new gpu::GpuChannelManager(
- gpu_preferences_, this, watchdog,
- base::ThreadTaskRunnerHandle::Get().get(), io_thread_.task_runner().get(),
- &shutdown_event_, owned_sync_point_manager_.get(),
- gpu_memory_buffer_factory_.get()));
-
- media_service_.reset(new media::MediaService(gpu_channel_manager_.get()));
-
- const bool preempts = true;
- const bool allow_view_command_buffers = true;
- const bool allow_real_time_streams = true;
- EstablishGpuChannelOnGpuThread(
- kLocalGpuChannelClientId, kLocalGpuChannelClientTracingId, preempts,
- allow_view_command_buffers, allow_real_time_streams, channel_handle);
- event->Signal();
-}
-
-void GpuServiceMus::EstablishGpuChannelOnGpuThread(
- int client_id,
- uint64_t client_tracing_id,
- bool preempts,
- bool allow_view_command_buffers,
- bool allow_real_time_streams,
- IPC::ChannelHandle* channel_handle) {
- if (gpu_channel_manager_) {
- *channel_handle = gpu_channel_manager_->EstablishChannel(
- client_id, client_tracing_id, preempts, allow_view_command_buffers,
- allow_real_time_streams);
- media_service_->AddChannel(client_id);
- }
-}
-
-bool GpuServiceMus::IsMainThread() {
- return main_task_runner_->BelongsToCurrentThread();
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-GpuServiceMus::GetIOThreadTaskRunner() {
- return io_thread_.task_runner();
-}
-
-std::unique_ptr<base::SharedMemory> GpuServiceMus::AllocateSharedMemory(
- size_t size) {
- std::unique_ptr<base::SharedMemory> shm(new base::SharedMemory());
- if (!shm->CreateAnonymous(size))
- return std::unique_ptr<base::SharedMemory>();
- return shm;
-}
-
-// static
-GpuServiceMus* GpuServiceMus::GetInstance() {
- return base::Singleton<GpuServiceMus,
- base::LeakySingletonTraits<GpuServiceMus>>::get();
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gpu/gpu_service_mus.h b/chromium/components/mus/gpu/gpu_service_mus.h
deleted file mode 100644
index b6bfd1b69f5..00000000000
--- a/chromium/components/mus/gpu/gpu_service_mus.h
+++ /dev/null
@@ -1,173 +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 COMPONENTS_MUS_GPU_GPU_SERVICE_MUS_H_
-#define COMPONENTS_MUS_GPU_GPU_SERVICE_MUS_H_
-
-#include "base/callback.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/non_thread_safe.h"
-#include "base/threading/thread.h"
-#include "build/build_config.h"
-#include "gpu/command_buffer/service/gpu_preferences.h"
-#include "gpu/config/gpu_info.h"
-#include "gpu/ipc/client/gpu_channel_host.h"
-#include "gpu/ipc/common/surface_handle.h"
-#include "gpu/ipc/service/gpu_channel.h"
-#include "gpu/ipc/service/gpu_channel_manager.h"
-#include "gpu/ipc/service/gpu_channel_manager_delegate.h"
-#include "gpu/ipc/service/gpu_config.h"
-#include "gpu/ipc/service/x_util.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace base {
-template <typename T>
-struct DefaultSingletonTraits;
-}
-
-namespace IPC {
-struct ChannelHandle;
-}
-
-namespace gpu {
-class GpuChannelHost;
-class GpuMemoryBufferFactory;
-class SyncPointManager;
-}
-
-namespace media {
-class MediaService;
-}
-
-namespace mus {
-
-class MusGpuMemoryBufferManager;
-
-// TODO(fsamuel): GpuServiceMus is intended to be the Gpu thread within Mus.
-// Similar to GpuChildThread, it is a GpuChannelManagerDelegate and will have a
-// GpuChannelManager.
-class GpuServiceMus : public gpu::GpuChannelManagerDelegate,
- public gpu::GpuChannelHostFactory,
- public base::NonThreadSafe {
- public:
- typedef base::Callback<void(int client_id, const IPC::ChannelHandle&)>
- EstablishGpuChannelCallback;
- void EstablishGpuChannel(uint64_t client_tracing_id,
- bool preempts,
- bool allow_view_command_buffers,
- bool allow_real_time_streams,
- const EstablishGpuChannelCallback& callback);
- gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- int client_id,
- gpu::SurfaceHandle surface_handle);
- gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromeHandle(
- gfx::GpuMemoryBufferHandle buffer_handle,
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- int client_id);
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- int client_id,
- const gpu::SyncToken& sync_token);
-
- gpu::GpuChannelManager* gpu_channel_manager() const {
- return gpu_channel_manager_.get();
- }
-
- gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory() const {
- return gpu_memory_buffer_factory_.get();
- }
-
- scoped_refptr<gpu::GpuChannelHost> gpu_channel_local() const {
- return gpu_channel_local_;
- }
-
- const gpu::GPUInfo& gpu_info() const { return gpu_info_; }
-
- // GpuChannelManagerDelegate overrides:
- void DidCreateOffscreenContext(const GURL& active_url) override;
- void DidDestroyChannel(int client_id) override;
- void DidDestroyOffscreenContext(const GURL& active_url) override;
- void DidLoseContext(bool offscreen,
- gpu::error::ContextLostReason reason,
- const GURL& active_url) override;
- void GpuMemoryUmaStats(const gpu::GPUMemoryUmaStats& params) override;
- void StoreShaderToDisk(int client_id,
- const std::string& key,
- const std::string& shader) override;
-#if defined(OS_WIN)
- void SendAcceleratedSurfaceCreatedChildWindow(
- gpu::SurfaceHandle parent_window,
- gpu::SurfaceHandle child_window) override;
-#endif
- void SetActiveURL(const GURL& url) override;
-
- // GpuChannelHostFactory overrides:
- bool IsMainThread() override;
- scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() override;
- std::unique_ptr<base::SharedMemory> AllocateSharedMemory(
- size_t size) override;
-
- static GpuServiceMus* GetInstance();
-
- private:
- friend struct base::DefaultSingletonTraits<GpuServiceMus>;
-
- GpuServiceMus();
- ~GpuServiceMus() override;
-
- void Initialize();
- void InitializeOnGpuThread(IPC::ChannelHandle* channel_handle,
- base::WaitableEvent* event);
- void EstablishGpuChannelOnGpuThread(int client_id,
- uint64_t client_tracing_id,
- bool preempts,
- bool allow_view_command_buffers,
- bool allow_real_time_streams,
- IPC::ChannelHandle* channel_handle);
-
- // The next client id.
- int next_client_id_;
-
- // The main thread task runner.
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
-
- // An event that will be signalled when we shutdown.
- base::WaitableEvent shutdown_event_;
-
- // The main thread for GpuService.
- base::Thread gpu_thread_;
-
- // The thread that handles IO events for GpuService.
- base::Thread io_thread_;
-
- std::unique_ptr<gpu::SyncPointManager> owned_sync_point_manager_;
-
- std::unique_ptr<gpu::GpuChannelManager> gpu_channel_manager_;
-
- std::unique_ptr<media::MediaService> media_service_;
-
- std::unique_ptr<gpu::GpuMemoryBufferFactory> gpu_memory_buffer_factory_;
-
- // A GPU memory buffer manager used locally.
- std::unique_ptr<MusGpuMemoryBufferManager> gpu_memory_buffer_manager_local_;
-
- // A GPU channel used locally.
- scoped_refptr<gpu::GpuChannelHost> gpu_channel_local_;
-
- gpu::GpuPreferences gpu_preferences_;
-
- // Information about the GPU, such as device and vendor ID.
- gpu::GPUInfo gpu_info_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuServiceMus);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GPU_GPU_SERVICE_MUS_H_
diff --git a/chromium/components/mus/gpu/mus_gpu_memory_buffer_manager.cc b/chromium/components/mus/gpu/mus_gpu_memory_buffer_manager.cc
deleted file mode 100644
index d9ecbd3257a..00000000000
--- a/chromium/components/mus/gpu/mus_gpu_memory_buffer_manager.cc
+++ /dev/null
@@ -1,115 +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 "components/mus/gpu/mus_gpu_memory_buffer_manager.h"
-
-#include "base/logging.h"
-#include "components/mus/common/generic_shared_memory_id_generator.h"
-#include "components/mus/gpu/gpu_service_mus.h"
-#include "gpu/ipc/client/gpu_memory_buffer_impl.h"
-#include "gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.h"
-#include "gpu/ipc/common/gpu_memory_buffer_support.h"
-#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
-
-namespace mus {
-
-namespace {
-
-MusGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr;
-
-bool IsNativeGpuMemoryBufferFactoryConfigurationSupported(
- gfx::BufferFormat format,
- gfx::BufferUsage usage) {
- switch (gpu::GetNativeGpuMemoryBufferType()) {
- case gfx::SHARED_MEMORY_BUFFER:
- return false;
- case gfx::IO_SURFACE_BUFFER:
- case gfx::SURFACE_TEXTURE_BUFFER:
- case gfx::OZONE_NATIVE_PIXMAP:
- return gpu::IsNativeGpuMemoryBufferConfigurationSupported(format, usage);
- default:
- NOTREACHED();
- return false;
- }
-}
-}
-
-MusGpuMemoryBufferManager* MusGpuMemoryBufferManager::current() {
- return g_gpu_memory_buffer_manager;
-}
-
-MusGpuMemoryBufferManager::MusGpuMemoryBufferManager(GpuServiceMus* gpu_service,
- int client_id)
- : gpu_service_(gpu_service), client_id_(client_id), weak_factory_(this) {
- DCHECK(!g_gpu_memory_buffer_manager);
- g_gpu_memory_buffer_manager = this;
-}
-
-MusGpuMemoryBufferManager::~MusGpuMemoryBufferManager() {
- g_gpu_memory_buffer_manager = nullptr;
-}
-
-std::unique_ptr<gfx::GpuMemoryBuffer>
-MusGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle) {
- gfx::GpuMemoryBufferId id = GetNextGenericSharedMemoryId();
- const bool is_native =
- IsNativeGpuMemoryBufferFactoryConfigurationSupported(format, usage);
- if (is_native) {
- gfx::GpuMemoryBufferHandle handle =
- gpu_service_->gpu_memory_buffer_factory()->CreateGpuMemoryBuffer(
- id, size, format, usage, client_id_, surface_handle);
- if (handle.is_null())
- return nullptr;
- return gpu::GpuMemoryBufferImpl::CreateFromHandle(
- handle, size, format, usage,
- base::Bind(&MusGpuMemoryBufferManager::DestroyGpuMemoryBuffer,
- weak_factory_.GetWeakPtr(), id, client_id_, is_native));
- }
-
- DCHECK(gpu::GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage))
- << static_cast<int>(usage);
- return gpu::GpuMemoryBufferImplSharedMemory::Create(
- id, size, format,
- base::Bind(&MusGpuMemoryBufferManager::DestroyGpuMemoryBuffer,
- weak_factory_.GetWeakPtr(), id, client_id_, is_native));
-}
-
-std::unique_ptr<gfx::GpuMemoryBuffer>
-MusGpuMemoryBufferManager::CreateGpuMemoryBufferFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::BufferFormat format) {
- NOTIMPLEMENTED();
- return nullptr;
-}
-
-gfx::GpuMemoryBuffer*
-MusGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer(
- ClientBuffer buffer) {
- return gpu::GpuMemoryBufferImpl::FromClientBuffer(buffer);
-}
-
-void MusGpuMemoryBufferManager::SetDestructionSyncToken(
- gfx::GpuMemoryBuffer* buffer,
- const gpu::SyncToken& sync_token) {
- static_cast<gpu::GpuMemoryBufferImpl*>(buffer)->set_destruction_sync_token(
- sync_token);
-}
-
-void MusGpuMemoryBufferManager::DestroyGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- int client_id,
- bool is_native,
- const gpu::SyncToken& sync_token) {
- if (is_native) {
- gpu_service_->gpu_channel_manager()->DestroyGpuMemoryBuffer(id, client_id,
- sync_token);
- }
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/gpu/mus_gpu_memory_buffer_manager.h b/chromium/components/mus/gpu/mus_gpu_memory_buffer_manager.h
deleted file mode 100644
index b705dd68bb8..00000000000
--- a/chromium/components/mus/gpu/mus_gpu_memory_buffer_manager.h
+++ /dev/null
@@ -1,57 +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 COMPONENTS_MUS_GPU_MUS_GPU_MEMORY_BUFFER_MANAGER_H_
-#define COMPONENTS_MUS_GPU_MUS_GPU_MEMORY_BUFFER_MANAGER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
-
-namespace mus {
-
-class GpuServiceMus;
-
-// This GpuMemoryBufferManager is for establishing a GpuChannelHost used by
-// mus locally.
-class MusGpuMemoryBufferManager : public gpu::GpuMemoryBufferManager {
- public:
- MusGpuMemoryBufferManager(GpuServiceMus* gpu_service, int client_id);
- ~MusGpuMemoryBufferManager() override;
-
- static MusGpuMemoryBufferManager* current();
-
- // Overridden from gpu::GpuMemoryBufferManager:
- std::unique_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle) override;
- std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBufferFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::BufferFormat format) override;
- gfx::GpuMemoryBuffer* GpuMemoryBufferFromClientBuffer(
- ClientBuffer buffer) override;
- void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
- const gpu::SyncToken& sync_token) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MusGpuMemoryBufferManager);
-
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- int client_id,
- bool is_native,
- const gpu::SyncToken& sync_token);
-
- GpuServiceMus* gpu_service_;
- const int client_id_;
- base::WeakPtrFactory<MusGpuMemoryBufferManager> weak_factory_;
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_GPU_MUS_GPU_MEMORY_BUFFER_MANAGER_H_
diff --git a/chromium/components/mus/gpu/mus_gpu_unittests_app_manifest.json b/chromium/components/mus/gpu/mus_gpu_unittests_app_manifest.json
deleted file mode 100644
index 26e8caa4802..00000000000
--- a/chromium/components/mus/gpu/mus_gpu_unittests_app_manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "manifest_version": 1,
- "name": "mojo:mus_gpu_unittests_app",
- "display_name": "Mus GPU Unittests",
- "capabilities": {
- "required": {
- "*": { "classes": [ "app" ] }
- }
- }
-}
diff --git a/chromium/components/mus/input_devices/BUILD.gn b/chromium/components/mus/input_devices/BUILD.gn
deleted file mode 100644
index ad3b1d73031..00000000000
--- a/chromium/components/mus/input_devices/BUILD.gn
+++ /dev/null
@@ -1,21 +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.
-
-source_set("input_devices") {
- sources = [
- "input_device_server.cc",
- "input_device_server.h",
- ]
-
- deps = [
- "//base",
- "//services/shell/public/cpp:sources",
- "//skia",
- "//ui/events/devices",
- ]
-
- public_deps = [
- "//components/mus/public/interfaces/input_devices",
- ]
-}
diff --git a/chromium/components/mus/input_devices/input_device_server.cc b/chromium/components/mus/input_devices/input_device_server.cc
deleted file mode 100644
index 3514eb35669..00000000000
--- a/chromium/components/mus/input_devices/input_device_server.cc
+++ /dev/null
@@ -1,110 +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 "components/mus/input_devices/input_device_server.h"
-
-#include <utility>
-#include <vector>
-
-#include "mojo/public/cpp/bindings/array.h"
-#include "ui/events/devices/input_device.h"
-#include "ui/events/devices/touchscreen_device.h"
-
-namespace mus {
-
-InputDeviceServer::InputDeviceServer() {}
-
-InputDeviceServer::~InputDeviceServer() {
- if (manager_ && ui::DeviceDataManager::HasInstance()) {
- manager_->RemoveObserver(this);
- manager_ = nullptr;
- }
-}
-
-void InputDeviceServer::RegisterAsObserver() {
- if (!manager_ && ui::DeviceDataManager::HasInstance()) {
- manager_ = ui::DeviceDataManager::GetInstance();
- manager_->AddObserver(this);
- }
-}
-
-bool InputDeviceServer::IsRegisteredAsObserver() const {
- return manager_ != nullptr;
-}
-
-void InputDeviceServer::AddInterface(shell::Connection* connection) {
- DCHECK(manager_);
- connection->AddInterface<mojom::InputDeviceServer>(this);
-}
-
-void InputDeviceServer::AddObserver(
- mojom::InputDeviceObserverMojoPtr observer) {
- // We only want to send this message once, so we need to check to make sure
- // device lists are actually complete before sending it to a new observer.
- if (manager_->AreDeviceListsComplete())
- SendDeviceListsComplete(observer.get());
- observers_.AddPtr(std::move(observer));
-}
-
-void InputDeviceServer::OnKeyboardDeviceConfigurationChanged() {
- if (!manager_->AreDeviceListsComplete())
- return;
-
- auto& devices = manager_->GetKeyboardDevices();
- observers_.ForAllPtrs([&devices](mojom::InputDeviceObserverMojo* observer) {
- observer->OnKeyboardDeviceConfigurationChanged(devices);
- });
-}
-
-void InputDeviceServer::OnTouchscreenDeviceConfigurationChanged() {
- if (!manager_->AreDeviceListsComplete())
- return;
-
- auto& devices = manager_->GetTouchscreenDevices();
- observers_.ForAllPtrs([&devices](mojom::InputDeviceObserverMojo* observer) {
- observer->OnTouchscreenDeviceConfigurationChanged(devices);
- });
-}
-
-void InputDeviceServer::OnMouseDeviceConfigurationChanged() {
- if (!manager_->AreDeviceListsComplete())
- return;
-
- auto& devices = manager_->GetMouseDevices();
- observers_.ForAllPtrs([&devices](mojom::InputDeviceObserverMojo* observer) {
- observer->OnMouseDeviceConfigurationChanged(devices);
- });
-}
-
-void InputDeviceServer::OnTouchpadDeviceConfigurationChanged() {
- if (!manager_->AreDeviceListsComplete())
- return;
-
- auto& devices = manager_->GetTouchpadDevices();
- observers_.ForAllPtrs([&devices](mojom::InputDeviceObserverMojo* observer) {
- observer->OnTouchpadDeviceConfigurationChanged(devices);
- });
-}
-
-void InputDeviceServer::OnDeviceListsComplete() {
- observers_.ForAllPtrs([this](mojom::InputDeviceObserverMojo* observer) {
- SendDeviceListsComplete(observer);
- });
-}
-
-void InputDeviceServer::SendDeviceListsComplete(
- mojom::InputDeviceObserverMojo* observer) {
- DCHECK(manager_->AreDeviceListsComplete());
-
- observer->OnDeviceListsComplete(
- manager_->GetKeyboardDevices(), manager_->GetTouchscreenDevices(),
- manager_->GetMouseDevices(), manager_->GetTouchpadDevices());
-}
-
-void InputDeviceServer::Create(shell::Connection* connection,
- mojom::InputDeviceServerRequest request) {
- bindings_.AddBinding(this, std::move(request));
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/input_devices/input_device_server.h b/chromium/components/mus/input_devices/input_device_server.h
deleted file mode 100644
index af0e0e704e6..00000000000
--- a/chromium/components/mus/input_devices/input_device_server.h
+++ /dev/null
@@ -1,69 +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 COMPONENTS_MUS_INPUT_DEVICES_INPUT_DEVICE_SERVER_H_
-#define COMPONENTS_MUS_INPUT_DEVICES_INPUT_DEVICE_SERVER_H_
-
-#include "base/macros.h"
-#include "components/mus/public/interfaces/input_devices/input_device_server.mojom.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/shell/public/cpp/connection.h"
-#include "services/shell/public/cpp/interface_factory.h"
-#include "ui/events/devices/device_data_manager.h"
-#include "ui/events/devices/input_device_event_observer.h"
-
-namespace mus {
-
-// Listens to DeviceDataManager for updates on input-devices and forwards those
-// updates to any registered InputDeviceObserverMojo in other processes via
-// Mojo IPC. This runs in the mus-ws process.
-class InputDeviceServer
- : public shell::InterfaceFactory<mojom::InputDeviceServer>,
- public mojom::InputDeviceServer,
- public ui::InputDeviceEventObserver {
- public:
- InputDeviceServer();
- ~InputDeviceServer() override;
-
- // Registers this instance as a local observer with DeviceDataManager.
- void RegisterAsObserver();
- bool IsRegisteredAsObserver() const;
-
- // Adds interface with the shell connection so remote observers can connect.
- // You should have already called RegisterAsObserver() to get local
- // input-device event updates and checked it was successful by calling
- // IsRegisteredAsObserver().
- void AddInterface(shell::Connection* connection);
-
- // mojom::InputDeviceServer:
- void AddObserver(mojom::InputDeviceObserverMojoPtr observer) override;
-
- // ui::InputDeviceEventObserver:
- void OnKeyboardDeviceConfigurationChanged() override;
- void OnTouchscreenDeviceConfigurationChanged() override;
- void OnMouseDeviceConfigurationChanged() override;
- void OnTouchpadDeviceConfigurationChanged() override;
- void OnDeviceListsComplete() override;
-
- private:
- // Sends the current state of all input-devices to an observer.
- void SendDeviceListsComplete(mojom::InputDeviceObserverMojo* observer);
-
- // mojo::InterfaceFactory<mojom::InputDeviceServer>:
- void Create(shell::Connection* connection,
- mojom::InputDeviceServerRequest request) override;
-
- mojo::BindingSet<mojom::InputDeviceServer> bindings_;
- mojo::InterfacePtrSet<mojom::InputDeviceObserverMojo> observers_;
-
- // DeviceDataManager instance we are registered as an observer with.
- ui::DeviceDataManager* manager_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(InputDeviceServer);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_INPUT_DEVICES_INPUT_DEVICE_SERVER_H_
diff --git a/chromium/components/mus/main.cc b/chromium/components/mus/main.cc
deleted file mode 100644
index 32c40ef407a..00000000000
--- a/chromium/components/mus/main.cc
+++ /dev/null
@@ -1,13 +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 "components/mus/mus_app.h"
-#include "mojo/public/c/system/main.h"
-#include "services/shell/public/cpp/application_runner.h"
-
-MojoResult MojoMain(MojoHandle shell_handle) {
- shell::ApplicationRunner runner(new mus::MusApp);
- runner.set_message_loop_type(base::MessageLoop::TYPE_UI);
- return runner.Run(shell_handle);
-}
diff --git a/chromium/components/mus/manifest.json b/chromium/components/mus/manifest.json
deleted file mode 100644
index 1969bec66e7..00000000000
--- a/chromium/components/mus/manifest.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "manifest_version": 1,
- "name": "mojo:mus",
- "display_name": "UI Service",
- "capabilities": {
- "provided": {
- // A collection of interfaces needed by a generic client of mus.
- // Additional interfaces may be requested a-la-carte.
- "app": [
- "mus::mojom::Clipboard",
- "mus::mojom::DisplayManager",
- "mus::mojom::Gpu",
- "mus::mojom::GpuService",
- "mus::mojom::InputDeviceServer",
- "mus::mojom::WindowTreeFactory"
- ],
- "test": [
- "mus::mojom::WindowServerTest"
- ]
- },
- "required": {
- "*": { "classes": [ "app" ] },
- "mojo:shell": { "classes": [ "shell:all_users", "shell:explicit_class" ] }
- }
- }
-}
diff --git a/chromium/components/mus/mus_app.cc b/chromium/components/mus/mus_app.cc
deleted file mode 100644
index 8ec1901a0c6..00000000000
--- a/chromium/components/mus/mus_app.cc
+++ /dev/null
@@ -1,388 +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 "components/mus/mus_app.h"
-
-#include <set>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/platform_thread.h"
-#include "build/build_config.h"
-#include "components/mus/clipboard/clipboard_impl.h"
-#include "components/mus/common/switches.h"
-#include "components/mus/gles2/gpu_impl.h"
-#include "components/mus/gpu/gpu_service_impl.h"
-#include "components/mus/gpu/gpu_service_mus.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/display_binding.h"
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/platform_screen.h"
-#include "components/mus/ws/user_activity_monitor.h"
-#include "components/mus/ws/user_display_manager.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_server_test_impl.h"
-#include "components/mus/ws/window_tree.h"
-#include "components/mus/ws/window_tree_binding.h"
-#include "components/mus/ws/window_tree_factory.h"
-#include "components/mus/ws/window_tree_host_factory.h"
-#include "mojo/public/c/system/main.h"
-#include "services/catalog/public/cpp/resource_loader.h"
-#include "services/shell/public/cpp/connection.h"
-#include "services/shell/public/cpp/connector.h"
-#include "services/tracing/public/cpp/tracing_impl.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_paths.h"
-#include "ui/events/event_switches.h"
-#include "ui/events/platform/platform_event_source.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gl/gl_surface.h"
-
-#if defined(USE_X11)
-#include <X11/Xlib.h>
-#include "ui/platform_window/x11/x11_window.h"
-#elif defined(USE_OZONE)
-#include "ui/events/ozone/layout/keyboard_layout_engine.h"
-#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
-#include "ui/ozone/public/ozone_platform.h"
-#endif
-
-using shell::Connection;
-using mojo::InterfaceRequest;
-using mus::mojom::Gpu;
-using mus::mojom::WindowServerTest;
-using mus::mojom::WindowTreeHostFactory;
-
-namespace mus {
-
-namespace {
-
-const char kResourceFileStrings[] = "mus_app_resources_strings.pak";
-const char kResourceFile100[] = "mus_app_resources_100.pak";
-const char kResourceFile200[] = "mus_app_resources_200.pak";
-
-} // namespace
-
-// TODO(sky): this is a pretty typical pattern, make it easier to do.
-struct MusApp::PendingRequest {
- shell::Connection* connection;
- std::unique_ptr<mojom::WindowTreeFactoryRequest> wtf_request;
- std::unique_ptr<mojom::DisplayManagerRequest> dm_request;
-};
-
-struct MusApp::UserState {
- std::unique_ptr<clipboard::ClipboardImpl> clipboard;
- std::unique_ptr<ws::WindowTreeHostFactory> window_tree_host_factory;
-};
-
-MusApp::MusApp()
- : test_config_(false),
- // TODO(penghuang): Kludge: Use mojo command buffer when running on
- // Windows since chrome command buffer breaks unit tests
-#if defined(OS_WIN)
- use_chrome_gpu_command_buffer_(false),
-#else
- use_chrome_gpu_command_buffer_(true),
-#endif
- platform_screen_(ws::PlatformScreen::Create()),
- weak_ptr_factory_(this) {}
-
-MusApp::~MusApp() {
- // Destroy |window_server_| first, since it depends on |event_source_|.
- // WindowServer (or more correctly its Displays) may have state that needs to
- // be destroyed before GpuState as well.
- window_server_.reset();
-
- if (platform_display_init_params_.gpu_state)
- platform_display_init_params_.gpu_state->StopThreads();
-}
-
-void MusApp::InitializeResources(shell::Connector* connector) {
- if (ui::ResourceBundle::HasSharedInstance())
- return;
-
- std::set<std::string> resource_paths;
- resource_paths.insert(kResourceFileStrings);
- resource_paths.insert(kResourceFile100);
- resource_paths.insert(kResourceFile200);
-
- catalog::ResourceLoader loader;
- filesystem::mojom::DirectoryPtr directory;
- connector->ConnectToInterface("mojo:catalog", &directory);
- CHECK(loader.OpenFiles(std::move(directory), resource_paths));
-
- ui::RegisterPathProvider();
-
- // Initialize resource bundle with 1x and 2x cursor bitmaps.
- ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
- loader.TakeFile(kResourceFileStrings),
- base::MemoryMappedFile::Region::kWholeFile);
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- rb.AddDataPackFromFile(loader.TakeFile(kResourceFile100),
- ui::SCALE_FACTOR_100P);
- rb.AddDataPackFromFile(loader.TakeFile(kResourceFile200),
- ui::SCALE_FACTOR_200P);
-}
-
-MusApp::UserState* MusApp::GetUserState(shell::Connection* connection) {
- const ws::UserId& user_id = connection->GetRemoteIdentity().user_id();
- auto it = user_id_to_user_state_.find(user_id);
- if (it != user_id_to_user_state_.end())
- return it->second.get();
- user_id_to_user_state_[user_id] = base::WrapUnique(new UserState);
- return user_id_to_user_state_[user_id].get();
-}
-
-void MusApp::AddUserIfNecessary(shell::Connection* connection) {
- window_server_->user_id_tracker()->AddUserId(
- connection->GetRemoteIdentity().user_id());
-}
-
-void MusApp::Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) {
- platform_display_init_params_.surfaces_state = new SurfacesState;
-
- base::PlatformThread::SetName("mus");
- tracing_.Initialize(connector, identity.name());
- TRACE_EVENT0("mus", "MusApp::Initialize started");
-
- test_config_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseTestConfig);
-// TODO(penghuang): Kludge: use mojo command buffer when running on Windows
-// since Chrome command buffer breaks unit tests
-#if defined(OS_WIN)
- use_chrome_gpu_command_buffer_ = false;
-#else
- use_chrome_gpu_command_buffer_ =
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseMojoGpuCommandBufferInMus);
-#endif
-#if defined(USE_X11)
- XInitThreads();
- if (test_config_)
- ui::test::SetUseOverrideRedirectWindowByDefault(true);
-#endif
-
- InitializeResources(connector);
-
-#if defined(USE_OZONE)
- // The ozone platform can provide its own event source. So initialize the
- // platform before creating the default event source.
- // Because GL libraries need to be initialized before entering the sandbox,
- // in MUS, |InitializeForUI| will load the GL libraries.
- ui::OzonePlatform::InitParams params;
- params.connector = connector;
- params.single_process = false;
-
- ui::OzonePlatform::InitializeForUI(params);
-
- // TODO(kylechar): We might not always want a US keyboard layout.
- ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()
- ->SetCurrentLayoutByName("us");
- client_native_pixmap_factory_ = ui::ClientNativePixmapFactory::Create();
- ui::ClientNativePixmapFactory::SetInstance(
- client_native_pixmap_factory_.get());
-
- DCHECK(ui::ClientNativePixmapFactory::GetInstance());
-#endif
-
-// TODO(rjkroege): Enter sandbox here before we start threads in GpuState
-// http://crbug.com/584532
-
-#if !defined(OS_ANDROID)
- event_source_ = ui::PlatformEventSource::CreateDefault();
-#endif
-
- // This needs to happen after DeviceDataManager has been constructed. That
- // happens either during OzonePlatform or PlatformEventSource initialization,
- // so keep this line below both of those.
- input_device_server_.RegisterAsObserver();
-
- if (use_chrome_gpu_command_buffer_) {
- GpuServiceMus::GetInstance();
- } else {
- // TODO(rjkroege): It is possible that we might want to generalize the
- // GpuState object.
- platform_display_init_params_.gpu_state = new GpuState();
- }
-
- // Gpu must be running before the PlatformScreen can be initialized.
- platform_screen_->Init();
- window_server_.reset(
- new ws::WindowServer(this, platform_display_init_params_.surfaces_state));
-
- // DeviceDataManager must be initialized before TouchController. On non-Linux
- // platforms there is no DeviceDataManager so don't create touch controller.
- if (ui::DeviceDataManager::HasInstance())
- touch_controller_.reset(
- new ws::TouchController(window_server_->display_manager()));
-}
-
-bool MusApp::AcceptConnection(Connection* connection) {
- connection->AddInterface<mojom::Clipboard>(this);
- connection->AddInterface<mojom::DisplayManager>(this);
- connection->AddInterface<mojom::UserAccessManager>(this);
- connection->AddInterface<mojom::UserActivityMonitor>(this);
- connection->AddInterface<WindowTreeHostFactory>(this);
- connection->AddInterface<mojom::WindowManagerWindowTreeFactory>(this);
- connection->AddInterface<mojom::WindowTreeFactory>(this);
- if (test_config_)
- connection->AddInterface<WindowServerTest>(this);
-
- if (use_chrome_gpu_command_buffer_) {
- connection->AddInterface<mojom::GpuService>(this);
- } else {
- connection->AddInterface<Gpu>(this);
- }
-
- // On non-Linux platforms there will be no DeviceDataManager instance and no
- // purpose in adding the Mojo interface to connect to.
- if (input_device_server_.IsRegisteredAsObserver())
- input_device_server_.AddInterface(connection);
-
-#if defined(USE_OZONE)
- ui::OzonePlatform::GetInstance()->AddInterfaces(connection);
-#endif
-
- return true;
-}
-
-void MusApp::OnFirstDisplayReady() {
- PendingRequests requests;
- requests.swap(pending_requests_);
- for (auto& request : requests) {
- if (request->wtf_request)
- Create(request->connection, std::move(*request->wtf_request));
- else
- Create(request->connection, std::move(*request->dm_request));
- }
-}
-
-void MusApp::OnNoMoreDisplays() {
- // We may get here from the destructor, in which case there is no messageloop.
- if (base::MessageLoop::current())
- base::MessageLoop::current()->QuitWhenIdle();
-}
-
-bool MusApp::IsTestConfig() const {
- return test_config_;
-}
-
-void MusApp::CreateDefaultDisplays() {
- // An asynchronous callback will create the Displays once the physical
- // displays are ready.
- platform_screen_->ConfigurePhysicalDisplay(base::Bind(
- &MusApp::OnCreatedPhysicalDisplay, weak_ptr_factory_.GetWeakPtr()));
-}
-
-void MusApp::Create(shell::Connection* connection,
- mojom::ClipboardRequest request) {
- UserState* user_state = GetUserState(connection);
- if (!user_state->clipboard)
- user_state->clipboard.reset(new clipboard::ClipboardImpl);
- user_state->clipboard->AddBinding(std::move(request));
-}
-
-void MusApp::Create(shell::Connection* connection,
- mojom::DisplayManagerRequest request) {
- // DisplayManagerObservers generally expect there to be at least one display.
- if (!window_server_->display_manager()->has_displays()) {
- std::unique_ptr<PendingRequest> pending_request(new PendingRequest);
- pending_request->connection = connection;
- pending_request->dm_request.reset(
- new mojom::DisplayManagerRequest(std::move(request)));
- pending_requests_.push_back(std::move(pending_request));
- return;
- }
- window_server_->display_manager()
- ->GetUserDisplayManager(connection->GetRemoteIdentity().user_id())
- ->AddDisplayManagerBinding(std::move(request));
-}
-
-void MusApp::Create(shell::Connection* connection, mojom::GpuRequest request) {
- if (use_chrome_gpu_command_buffer_)
- return;
- DCHECK(platform_display_init_params_.gpu_state);
- new GpuImpl(std::move(request), platform_display_init_params_.gpu_state);
-}
-
-void MusApp::Create(shell::Connection* connection,
- mojom::GpuServiceRequest request) {
- if (!use_chrome_gpu_command_buffer_)
- return;
- new GpuServiceImpl(std::move(request), connection);
-}
-
-void MusApp::Create(shell::Connection* connection,
- mojom::UserAccessManagerRequest request) {
- window_server_->user_id_tracker()->Bind(std::move(request));
-}
-
-void MusApp::Create(shell::Connection* connection,
- mojom::UserActivityMonitorRequest request) {
- AddUserIfNecessary(connection);
- const ws::UserId& user_id = connection->GetRemoteIdentity().user_id();
- window_server_->GetUserActivityMonitorForUser(user_id)->Add(
- std::move(request));
-}
-
-void MusApp::Create(shell::Connection* connection,
- mojom::WindowManagerWindowTreeFactoryRequest request) {
- AddUserIfNecessary(connection);
- window_server_->window_manager_window_tree_factory_set()->Add(
- connection->GetRemoteIdentity().user_id(), std::move(request));
-}
-
-void MusApp::Create(Connection* connection,
- mojom::WindowTreeFactoryRequest request) {
- AddUserIfNecessary(connection);
- if (!window_server_->display_manager()->has_displays()) {
- std::unique_ptr<PendingRequest> pending_request(new PendingRequest);
- pending_request->connection = connection;
- pending_request->wtf_request.reset(
- new mojom::WindowTreeFactoryRequest(std::move(request)));
- pending_requests_.push_back(std::move(pending_request));
- return;
- }
- AddUserIfNecessary(connection);
- new ws::WindowTreeFactory(
- window_server_.get(), connection->GetRemoteIdentity().user_id(),
- connection->GetRemoteIdentity().name(), std::move(request));
-}
-
-void MusApp::Create(Connection* connection,
- mojom::WindowTreeHostFactoryRequest request) {
- UserState* user_state = GetUserState(connection);
- if (!user_state->window_tree_host_factory) {
- user_state->window_tree_host_factory.reset(new ws::WindowTreeHostFactory(
- window_server_.get(), connection->GetRemoteIdentity().user_id(),
- platform_display_init_params_));
- }
- user_state->window_tree_host_factory->AddBinding(std::move(request));
-}
-
-void MusApp::Create(Connection* connection,
- mojom::WindowServerTestRequest request) {
- if (!test_config_)
- return;
- new ws::WindowServerTestImpl(window_server_.get(), std::move(request));
-}
-
-void MusApp::OnCreatedPhysicalDisplay(int64_t id, const gfx::Rect& bounds) {
- platform_display_init_params_.display_bounds = bounds;
- platform_display_init_params_.display_id = id;
-
- // Display manages its own lifetime.
- ws::Display* host_impl =
- new ws::Display(window_server_.get(), platform_display_init_params_);
- host_impl->Init(nullptr);
-
- if (touch_controller_)
- touch_controller_->UpdateTouchTransforms();
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/mus_app.h b/chromium/components/mus/mus_app.h
deleted file mode 100644
index 6bffa5c1a72..00000000000
--- a/chromium/components/mus/mus_app.h
+++ /dev/null
@@ -1,182 +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 COMPONENTS_MUS_MUS_APP_H_
-#define COMPONENTS_MUS_MUS_APP_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/mus/input_devices/input_device_server.h"
-#include "components/mus/public/interfaces/clipboard.mojom.h"
-#include "components/mus/public/interfaces/display.mojom.h"
-#include "components/mus/public/interfaces/gpu.mojom.h"
-#include "components/mus/public/interfaces/gpu_service.mojom.h"
-#include "components/mus/public/interfaces/user_access_manager.mojom.h"
-#include "components/mus/public/interfaces/user_activity_monitor.mojom.h"
-#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
-#include "components/mus/public/interfaces/window_server_test.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/public/interfaces/window_tree_host.mojom.h"
-#include "components/mus/ws/platform_display_init_params.h"
-#include "components/mus/ws/touch_controller.h"
-#include "components/mus/ws/user_id.h"
-#include "components/mus/ws/window_server_delegate.h"
-#include "services/shell/public/cpp/application_runner.h"
-#include "services/shell/public/cpp/interface_factory.h"
-#include "services/shell/public/cpp/shell_client.h"
-#include "services/tracing/public/cpp/tracing_impl.h"
-
-#if defined(USE_OZONE)
-#include "ui/ozone/public/client_native_pixmap_factory.h"
-#endif
-
-namespace gfx {
-class Rect;
-}
-
-namespace shell {
-class Connector;
-}
-
-namespace ui {
-class PlatformEventSource;
-}
-
-namespace mus {
-namespace ws {
-class ForwardingWindowManager;
-class PlatformScreen;
-class WindowServer;
-}
-
-class MusApp
- : public shell::ShellClient,
- public ws::WindowServerDelegate,
- public shell::InterfaceFactory<mojom::Clipboard>,
- public shell::InterfaceFactory<mojom::DisplayManager>,
- public shell::InterfaceFactory<mojom::Gpu>,
- public shell::InterfaceFactory<mojom::GpuService>,
- public shell::InterfaceFactory<mojom::UserAccessManager>,
- public shell::InterfaceFactory<mojom::UserActivityMonitor>,
- public shell::InterfaceFactory<mojom::WindowManagerWindowTreeFactory>,
- public shell::InterfaceFactory<mojom::WindowTreeFactory>,
- public shell::InterfaceFactory<mojom::WindowTreeHostFactory>,
- public shell::InterfaceFactory<mojom::WindowServerTest> {
- public:
- MusApp();
- ~MusApp() override;
-
- private:
- // Holds InterfaceRequests received before the first WindowTreeHost Display
- // has been established.
- struct PendingRequest;
- struct UserState;
-
- using UserIdToUserState = std::map<ws::UserId, std::unique_ptr<UserState>>;
-
- void InitializeResources(shell::Connector* connector);
-
- // Returns the user specific state for the user id of |connection|. MusApp
- // owns the return value.
- // TODO(sky): if we allow removal of user ids then we need to close anything
- // associated with the user (all incoming pipes...) on removal.
- UserState* GetUserState(shell::Connection* connection);
-
- void AddUserIfNecessary(shell::Connection* connection);
-
- // shell::ShellClient:
- void Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) override;
- bool AcceptConnection(shell::Connection* connection) override;
-
- // WindowServerDelegate:
- void OnFirstDisplayReady() override;
- void OnNoMoreDisplays() override;
- bool IsTestConfig() const override;
- void CreateDefaultDisplays() override;
-
- // shell::InterfaceFactory<mojom::Clipboard> implementation.
- void Create(shell::Connection* connection,
- mojom::ClipboardRequest request) override;
-
- // shell::InterfaceFactory<mojom::DisplayManager> implementation.
- void Create(shell::Connection* connection,
- mojom::DisplayManagerRequest request) override;
-
- // shell::InterfaceFactory<mojom::Gpu> implementation.
- void Create(shell::Connection* connection,
- mojom::GpuRequest request) override;
-
- // shell::InterfaceFactory<mojom::GpuService> implementation.
- void Create(shell::Connection* connection,
- mojom::GpuServiceRequest request) override;
-
- // shell::InterfaceFactory<mojom::UserAccessManager> implementation.
- void Create(shell::Connection* connection,
- mojom::UserAccessManagerRequest request) override;
-
- // shell::InterfaceFactory<mojom::UserActivityMonitor> implementation.
- void Create(shell::Connection* connection,
- mojom::UserActivityMonitorRequest request) override;
-
- // shell::InterfaceFactory<mojom::WindowManagerWindowTreeFactory>
- // implementation.
- void Create(shell::Connection* connection,
- mojom::WindowManagerWindowTreeFactoryRequest request) override;
-
- // shell::InterfaceFactory<mojom::WindowTreeFactory>:
- void Create(shell::Connection* connection,
- mojom::WindowTreeFactoryRequest request) override;
-
- // shell::InterfaceFactory<mojom::WindowTreeHostFactory>:
- void Create(shell::Connection* connection,
- mojom::WindowTreeHostFactoryRequest request) override;
-
- // shell::InterfaceFactory<mojom::WindowServerTest> implementation.
- void Create(shell::Connection* connection,
- mojom::WindowServerTestRequest request) override;
-
- // Callback for display configuration. |id| is the identifying token for the
- // configured display that will identify a specific physical display across
- // configuration changes. |bounds| is the bounds of the display in screen
- // coordinates.
- void OnCreatedPhysicalDisplay(int64_t id, const gfx::Rect& bounds);
-
- ws::PlatformDisplayInitParams platform_display_init_params_;
- std::unique_ptr<ws::WindowServer> window_server_;
- std::unique_ptr<ui::PlatformEventSource> event_source_;
- mojo::TracingImpl tracing_;
- using PendingRequests = std::vector<std::unique_ptr<PendingRequest>>;
- PendingRequests pending_requests_;
-
- UserIdToUserState user_id_to_user_state_;
-
- // Provides input-device information via Mojo IPC.
- InputDeviceServer input_device_server_;
-
- bool test_config_;
- bool use_chrome_gpu_command_buffer_;
-#if defined(USE_OZONE)
- std::unique_ptr<ui::ClientNativePixmapFactory> client_native_pixmap_factory_;
-#endif
-
- std::unique_ptr<ws::PlatformScreen> platform_screen_;
- std::unique_ptr<ws::TouchController> touch_controller_;
-
- base::WeakPtrFactory<MusApp> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(MusApp);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_MUS_APP_H_
diff --git a/chromium/components/mus/public/cpp/BUILD.gn b/chromium/components/mus/public/cpp/BUILD.gn
deleted file mode 100644
index 1f70cf65159..00000000000
--- a/chromium/components/mus/public/cpp/BUILD.gn
+++ /dev/null
@@ -1,74 +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.
-
-source_set("cpp") {
- sources = [
- "context_provider.h",
- "gles2_context.h",
- "input_event_handler.h",
- "lib/command_buffer_client_impl.cc",
- "lib/command_buffer_client_impl.h",
- "lib/context_provider.cc",
- "lib/gles2_context.cc",
- "lib/in_flight_change.cc",
- "lib/in_flight_change.h",
- "lib/output_surface.cc",
- "lib/property_type_converters.cc",
- "lib/scoped_window_ptr.cc",
- "lib/window.cc",
- "lib/window_observer.cc",
- "lib/window_private.cc",
- "lib/window_private.h",
- "lib/window_surface.cc",
- "lib/window_tree_client.cc",
- "lib/window_tree_client_delegate.cc",
- "lib/window_tree_host_factory.cc",
- "output_surface.h",
- "property_type_converters.h",
- "scoped_window_ptr.h",
- "window.h",
- "window_manager_delegate.h",
- "window_observer.h",
- "window_property.h",
- "window_surface.h",
- "window_surface_client.h",
- "window_tracker.h",
- "window_tree_client.h",
- "window_tree_client_delegate.h",
- "window_tree_client_observer.h",
- "window_tree_host_factory.h",
- ]
-
- public_deps = [
- "//base",
- "//cc",
- "//cc/surfaces",
- "//cc/surfaces:surface_id",
- "//components/mus/common:mus_common",
- "//components/mus/public/interfaces",
- "//gpu/command_buffer/client",
- "//gpu/command_buffer/client:gles2_implementation",
- "//gpu/command_buffer/common",
- "//mojo/public/cpp/bindings",
- "//mojo/public/cpp/system",
- "//services/shell/public/interfaces",
- ]
-
- deps = [
- "//components/mus/gles2:lib",
- "//components/mus/public/interfaces",
- "//gpu/command_buffer/client:gles2_cmd_helper",
- "//gpu/command_buffer/client:gles2_interface",
- "//gpu/ipc/client",
- "//services/shell/public/cpp",
- "//ui/display",
- "//ui/display/mojo",
- "//ui/events",
- "//ui/gfx/geometry",
- ]
-
- data_deps = [
- "//components/mus",
- ]
-}
diff --git a/chromium/components/mus/public/cpp/DEPS b/chromium/components/mus/public/cpp/DEPS
deleted file mode 100644
index 9be0bc0fccc..00000000000
--- a/chromium/components/mus/public/cpp/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+gpu",
-]
diff --git a/chromium/components/mus/public/cpp/context_provider.h b/chromium/components/mus/public/cpp/context_provider.h
deleted file mode 100644
index f16366e05c2..00000000000
--- a/chromium/components/mus/public/cpp/context_provider.h
+++ /dev/null
@@ -1,54 +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 COMPONENTS_MUS_PUBLIC_CPP_CONTEXT_PROVIDER_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_CONTEXT_PROVIDER_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "cc/output/context_provider.h"
-#include "components/mus/public/interfaces/command_buffer.mojom.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace shell {
-class Connector;
-}
-
-namespace mus {
-
-class GLES2Context;
-
-class ContextProvider : public cc::ContextProvider {
- public:
- explicit ContextProvider(shell::Connector* connector);
-
- // cc::ContextProvider implementation.
- bool BindToCurrentThread() override;
- gpu::gles2::GLES2Interface* ContextGL() override;
- gpu::ContextSupport* ContextSupport() override;
- class GrContext* GrContext() override;
- void InvalidateGrContext(uint32_t state) override;
- base::Lock* GetLock() override;
- gpu::Capabilities ContextCapabilities() override;
- void DeleteCachedResources() override {}
- void SetLostContextCallback(
- const LostContextCallback& lost_context_callback) override {}
-
- protected:
- friend class base::RefCountedThreadSafe<ContextProvider>;
- ~ContextProvider() override;
-
- private:
- std::unique_ptr<shell::Connector> connector_;
- std::unique_ptr<GLES2Context> context_;
-
- DISALLOW_COPY_AND_ASSIGN(ContextProvider);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_CONTEXT_PROVIDER_H_
diff --git a/chromium/components/mus/public/cpp/gles2_context.h b/chromium/components/mus/public/cpp/gles2_context.h
deleted file mode 100644
index 03b069f478d..00000000000
--- a/chromium/components/mus/public/cpp/gles2_context.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 COMPONENTS_MUS_PUBLIC_CPP_GLES2_CONTEXT_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_GLES2_CONTEXT_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "components/mus/public/interfaces/command_buffer.mojom.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-
-namespace gpu {
-class CommandBufferProxyImpl;
-class TransferBuffer;
-namespace gles2 {
-class GLES2CmdHelper;
-}
-}
-
-namespace shell {
-class Connector;
-}
-
-namespace mus {
-
-class CommandBufferClientImpl;
-
-class GLES2Context {
- public:
- ~GLES2Context();
- gpu::gles2::GLES2Interface* interface() const {
- return implementation_.get();
- }
- gpu::ContextSupport* context_support() const { return implementation_.get(); }
-
- static std::unique_ptr<GLES2Context> CreateOffscreenContext(
- const std::vector<int32_t>& attribs,
- shell::Connector* connector);
-
- private:
- GLES2Context();
- bool Initialize(const std::vector<int32_t>& attribs,
- shell::Connector* connector);
-
- std::unique_ptr<CommandBufferClientImpl> command_buffer_client_impl_;
- std::unique_ptr<gpu::CommandBufferProxyImpl> command_buffer_proxy_impl_;
- std::unique_ptr<gpu::gles2::GLES2CmdHelper> gles2_helper_;
- std::unique_ptr<gpu::TransferBuffer> transfer_buffer_;
- std::unique_ptr<gpu::gles2::GLES2Implementation> implementation_;
-
- DISALLOW_COPY_AND_ASSIGN(GLES2Context);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_GLES2_CONTEXT_H_
diff --git a/chromium/components/mus/public/cpp/input_devices/BUILD.gn b/chromium/components/mus/public/cpp/input_devices/BUILD.gn
deleted file mode 100644
index c5c7734831a..00000000000
--- a/chromium/components/mus/public/cpp/input_devices/BUILD.gn
+++ /dev/null
@@ -1,21 +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.
-
-source_set("input_devices") {
- sources = [
- "input_device_client.cc",
- "input_device_client.h",
- ]
-
- deps = [
- "//base",
- "//services/shell/public/cpp:sources",
- "//skia",
- "//ui/events/devices",
- ]
-
- public_deps = [
- "//components/mus/public/interfaces/input_devices",
- ]
-}
diff --git a/chromium/components/mus/public/cpp/input_devices/input_device_client.cc b/chromium/components/mus/public/cpp/input_devices/input_device_client.cc
deleted file mode 100644
index 6b55d778f58..00000000000
--- a/chromium/components/mus/public/cpp/input_devices/input_device_client.cc
+++ /dev/null
@@ -1,112 +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 "components/mus/public/cpp/input_devices/input_device_client.h"
-
-#include "base/logging.h"
-
-namespace mus {
-
-InputDeviceClient::InputDeviceClient() : binding_(this) {
- InputDeviceManager::SetInstance(this);
-}
-
-InputDeviceClient::~InputDeviceClient() {
- InputDeviceManager::ClearInstance();
-}
-
-void InputDeviceClient::Connect(mojom::InputDeviceServerPtr server) {
- DCHECK(server.is_bound());
-
- server->AddObserver(binding_.CreateInterfacePtrAndBind());
-}
-
-void InputDeviceClient::OnKeyboardDeviceConfigurationChanged(
- mojo::Array<ui::InputDevice> devices) {
- keyboard_devices_ = devices.To<std::vector<ui::InputDevice>>();
- FOR_EACH_OBSERVER(ui::InputDeviceEventObserver, observers_,
- OnKeyboardDeviceConfigurationChanged());
-}
-
-void InputDeviceClient::OnTouchscreenDeviceConfigurationChanged(
- mojo::Array<ui::TouchscreenDevice> devices) {
- touchscreen_devices_ = devices.To<std::vector<ui::TouchscreenDevice>>();
- FOR_EACH_OBSERVER(ui::InputDeviceEventObserver, observers_,
- OnTouchscreenDeviceConfigurationChanged());
-}
-
-void InputDeviceClient::OnMouseDeviceConfigurationChanged(
- mojo::Array<ui::InputDevice> devices) {
- mouse_devices_ = devices.To<std::vector<ui::InputDevice>>();
- FOR_EACH_OBSERVER(ui::InputDeviceEventObserver, observers_,
- OnMouseDeviceConfigurationChanged());
-}
-
-void InputDeviceClient::OnTouchpadDeviceConfigurationChanged(
- mojo::Array<ui::InputDevice> devices) {
- touchpad_devices_ = devices.To<std::vector<ui::InputDevice>>();
- FOR_EACH_OBSERVER(ui::InputDeviceEventObserver, observers_,
- OnTouchpadDeviceConfigurationChanged());
-}
-
-void InputDeviceClient::OnDeviceListsComplete(
- mojo::Array<ui::InputDevice> keyboard_devices,
- mojo::Array<ui::TouchscreenDevice> touchscreen_devices,
- mojo::Array<ui::InputDevice> mouse_devices,
- mojo::Array<ui::InputDevice> touchpad_devices) {
- // Update the cached device lists if the received list isn't empty.
- if (!keyboard_devices.empty())
- OnKeyboardDeviceConfigurationChanged(std::move(keyboard_devices));
- if (!touchscreen_devices.empty())
- OnTouchscreenDeviceConfigurationChanged(std::move(touchscreen_devices));
- if (!mouse_devices.empty())
- OnMouseDeviceConfigurationChanged(std::move(mouse_devices));
- if (!touchpad_devices.empty())
- OnTouchpadDeviceConfigurationChanged(std::move(touchpad_devices));
-
- if (!device_lists_complete_) {
- device_lists_complete_ = true;
- FOR_EACH_OBSERVER(ui::InputDeviceEventObserver, observers_,
- OnDeviceListsComplete());
- }
-}
-
-void InputDeviceClient::AddObserver(ui::InputDeviceEventObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void InputDeviceClient::RemoveObserver(ui::InputDeviceEventObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-const std::vector<ui::InputDevice>& InputDeviceClient::GetKeyboardDevices()
- const {
- return keyboard_devices_;
-}
-
-const std::vector<ui::TouchscreenDevice>&
-InputDeviceClient::GetTouchscreenDevices() const {
- return touchscreen_devices_;
-}
-
-const std::vector<ui::InputDevice>& InputDeviceClient::GetMouseDevices() const {
- return mouse_devices_;
-}
-
-const std::vector<ui::InputDevice>& InputDeviceClient::GetTouchpadDevices()
- const {
- return touchpad_devices_;
-}
-
-bool InputDeviceClient::AreDeviceListsComplete() const {
- return device_lists_complete_;
-}
-
-bool InputDeviceClient::AreTouchscreensEnabled() const {
- // TODO(kylechar): This obviously isn't right. We either need to pass this
- // state around or modify the interface.
- return true;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/input_devices/input_device_client.h b/chromium/components/mus/public/cpp/input_devices/input_device_client.h
deleted file mode 100644
index 88fa41d750f..00000000000
--- a/chromium/components/mus/public/cpp/input_devices/input_device_client.h
+++ /dev/null
@@ -1,84 +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 COMPONENTS_MUS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CLIENT_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CLIENT_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/mus/public/interfaces/input_devices/input_device_server.mojom.h"
-#include "mojo/public/cpp/bindings/array.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "ui/events/devices/input_device.h"
-#include "ui/events/devices/input_device_event_observer.h"
-#include "ui/events/devices/input_device_manager.h"
-#include "ui/events/devices/touchscreen_device.h"
-
-namespace mus {
-
-// Allows in-process client code to register as a InputDeviceEventObserver and
-// get information about input-devices. InputDeviceClient itself acts as an
-// InputDeviceObserverMojo and registers to get updates from InputDeviceServer.
-// Essentially, InputDeviceClient forwards input-device events and caches
-// input-device state.
-class InputDeviceClient : public mojom::InputDeviceObserverMojo,
- public ui::InputDeviceManager {
- public:
- InputDeviceClient();
- ~InputDeviceClient() override;
-
- // Connects to mojo:mus as an observer on InputDeviceServer to receive input
- // device updates.
- void Connect(mojom::InputDeviceServerPtr server);
-
- // ui::InputDeviceManager:
- const std::vector<ui::InputDevice>& GetKeyboardDevices() const override;
- const std::vector<ui::TouchscreenDevice>& GetTouchscreenDevices()
- const override;
- const std::vector<ui::InputDevice>& GetMouseDevices() const override;
- const std::vector<ui::InputDevice>& GetTouchpadDevices() const override;
-
- bool AreDeviceListsComplete() const override;
- bool AreTouchscreensEnabled() const override;
-
- void AddObserver(ui::InputDeviceEventObserver* observer) override;
- void RemoveObserver(ui::InputDeviceEventObserver* observer) override;
-
- private:
- // mojom::InputDeviceObserverMojo:
- void OnKeyboardDeviceConfigurationChanged(
- mojo::Array<ui::InputDevice> devices) override;
- void OnTouchscreenDeviceConfigurationChanged(
- mojo::Array<ui::TouchscreenDevice> devices) override;
- void OnMouseDeviceConfigurationChanged(
- mojo::Array<ui::InputDevice> devices) override;
- void OnTouchpadDeviceConfigurationChanged(
- mojo::Array<ui::InputDevice> devices) override;
- void OnDeviceListsComplete(
- mojo::Array<ui::InputDevice> keyboard_devices,
- mojo::Array<ui::TouchscreenDevice> touchscreen_devices,
- mojo::Array<ui::InputDevice> mouse_devices,
- mojo::Array<ui::InputDevice> touchpad_devices) override;
-
- mojo::Binding<mojom::InputDeviceObserverMojo> binding_;
-
- // Holds the list of input devices and signal that we have received the lists
- // after initialization.
- std::vector<ui::InputDevice> keyboard_devices_;
- std::vector<ui::TouchscreenDevice> touchscreen_devices_;
- std::vector<ui::InputDevice> mouse_devices_;
- std::vector<ui::InputDevice> touchpad_devices_;
- bool device_lists_complete_ = false;
-
- // List of in-process observers.
- base::ObserverList<ui::InputDeviceEventObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(InputDeviceClient);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_INPUT_DEVICES_INPUT_DEVICE_CLIENT_H_
diff --git a/chromium/components/mus/public/cpp/input_event_handler.h b/chromium/components/mus/public/cpp/input_event_handler.h
deleted file mode 100644
index 3d445b23bad..00000000000
--- a/chromium/components/mus/public/cpp/input_event_handler.h
+++ /dev/null
@@ -1,43 +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 COMPONENTS_MUS_PUBLIC_CPP_INPUT_EVENT_HANDLER_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_INPUT_EVENT_HANDLER_H_
-
-#include <memory>
-
-#include "base/callback_forward.h"
-
-namespace ui {
-class Event;
-}
-
-namespace mus {
-
-class Window;
-
-namespace mojom {
-enum class EventResult;
-}
-
-// Responsible for processing input events for mus::Window.
-class InputEventHandler {
- public:
- // The event handler can asynchronously ack the event by taking ownership of
- // the |ack_callback|. The callback takes an EventResult indicating if the
- // handler has consumed the event. If the handler does not take ownership of
- // the callback, then WindowTreeClient will ack the event as not consumed.
- virtual void OnWindowInputEvent(
- Window* target,
- const ui::Event& event,
- std::unique_ptr<base::Callback<void(mojom::EventResult)>>*
- ack_callback) = 0;
-
- protected:
- virtual ~InputEventHandler() {}
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_INPUT_EVENT_HANDLER_H_
diff --git a/chromium/components/mus/public/cpp/lib/DEPS b/chromium/components/mus/public/cpp/lib/DEPS
deleted file mode 100644
index c635ea6f5e4..00000000000
--- a/chromium/components/mus/public/cpp/lib/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+mojo/gpu"
-]
diff --git a/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.cc b/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.cc
deleted file mode 100644
index 062c3f78477..00000000000
--- a/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.cc
+++ /dev/null
@@ -1,370 +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 "components/mus/public/cpp/lib/command_buffer_client_impl.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <limits>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/process/process_handle.h"
-#include "base/threading/thread_restrictions.h"
-#include "components/mus/common/gpu_type_converters.h"
-#include "components/mus/common/mojo_buffer_backing.h"
-#include "components/mus/common/mojo_gpu_memory_buffer.h"
-#include "gpu/command_buffer/client/gpu_control_client.h"
-#include "gpu/command_buffer/common/command_buffer_id.h"
-#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
-#include "gpu/command_buffer/common/sync_token.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-
-namespace mus {
-
-namespace {
-
-bool CreateAndMapSharedBuffer(size_t size,
- mojo::ScopedSharedBufferMapping* mapping,
- mojo::ScopedSharedBufferHandle* handle) {
- *handle = mojo::SharedBufferHandle::Create(size);
- if (!handle->is_valid())
- return false;
-
- *mapping = (*handle)->Map(size);
- if (!*mapping)
- return false;
-
- return true;
-}
-
-void MakeProgressCallback(gpu::CommandBuffer::State* output,
- const gpu::CommandBuffer::State& input) {
- *output = input;
-}
-
-void InitializeCallback(mus::mojom::CommandBufferInitializeResultPtr* output,
- mus::mojom::CommandBufferInitializeResultPtr input) {
- *output = std::move(input);
-}
-
-} // namespace
-
-CommandBufferClientImpl::CommandBufferClientImpl(
- const std::vector<int32_t>& attribs,
- mus::mojom::CommandBufferPtr command_buffer_ptr)
- : gpu_control_client_(nullptr),
- destroyed_(false),
- attribs_(attribs),
- client_binding_(this),
- command_buffer_(std::move(command_buffer_ptr)),
- command_buffer_id_(),
- last_put_offset_(-1),
- next_transfer_buffer_id_(0),
- next_image_id_(0),
- next_fence_sync_release_(1),
- flushed_fence_sync_release_(0) {
- command_buffer_.set_connection_error_handler(
- base::Bind(&CommandBufferClientImpl::Destroyed, base::Unretained(this),
- gpu::error::kUnknown, gpu::error::kLostContext));
-}
-
-CommandBufferClientImpl::~CommandBufferClientImpl() {}
-
-bool CommandBufferClientImpl::Initialize() {
- const size_t kSharedStateSize = sizeof(gpu::CommandBufferSharedState);
- mojo::ScopedSharedBufferHandle handle;
- bool result =
- CreateAndMapSharedBuffer(kSharedStateSize, &shared_state_, &handle);
- if (!result)
- return false;
-
- shared_state()->Initialize();
-
- mus::mojom::CommandBufferClientPtr client_ptr;
- client_binding_.Bind(GetProxy(&client_ptr));
-
- mus::mojom::CommandBufferInitializeResultPtr initialize_result;
- command_buffer_->Initialize(
- std::move(client_ptr), std::move(handle),
- mojo::Array<int32_t>::From(attribs_),
- base::Bind(&InitializeCallback, &initialize_result));
-
- base::ThreadRestrictions::ScopedAllowWait wait;
- if (!command_buffer_.WaitForIncomingResponse()) {
- VLOG(1) << "Channel encountered error while creating command buffer.";
- return false;
- }
-
- if (!initialize_result) {
- VLOG(1) << "Command buffer cannot be initialized successfully.";
- return false;
- }
-
- DCHECK_EQ(gpu::CommandBufferNamespace::MOJO,
- initialize_result->command_buffer_namespace);
- command_buffer_id_ = gpu::CommandBufferId::FromUnsafeValue(
- initialize_result->command_buffer_id);
- capabilities_ = initialize_result->capabilities;
- return true;
-}
-
-gpu::CommandBuffer::State CommandBufferClientImpl::GetLastState() {
- return last_state_;
-}
-
-int32_t CommandBufferClientImpl::GetLastToken() {
- TryUpdateState();
- return last_state_.token;
-}
-
-void CommandBufferClientImpl::Flush(int32_t put_offset) {
- if (last_put_offset_ == put_offset)
- return;
-
- last_put_offset_ = put_offset;
- command_buffer_->Flush(put_offset);
- flushed_fence_sync_release_ = next_fence_sync_release_ - 1;
-}
-
-void CommandBufferClientImpl::OrderingBarrier(int32_t put_offset) {
- // TODO(jamesr): Implement this more efficiently.
- Flush(put_offset);
-}
-
-void CommandBufferClientImpl::WaitForTokenInRange(int32_t start, int32_t end) {
- TryUpdateState();
- while (!InRange(start, end, last_state_.token) &&
- last_state_.error == gpu::error::kNoError) {
- MakeProgressAndUpdateState();
- }
-}
-
-void CommandBufferClientImpl::WaitForGetOffsetInRange(int32_t start,
- int32_t end) {
- TryUpdateState();
- while (!InRange(start, end, last_state_.get_offset) &&
- last_state_.error == gpu::error::kNoError) {
- MakeProgressAndUpdateState();
- }
-}
-
-void CommandBufferClientImpl::SetGetBuffer(int32_t shm_id) {
- command_buffer_->SetGetBuffer(shm_id);
- last_put_offset_ = -1;
-}
-
-scoped_refptr<gpu::Buffer> CommandBufferClientImpl::CreateTransferBuffer(
- size_t size,
- int32_t* id) {
- if (size >= std::numeric_limits<uint32_t>::max())
- return NULL;
-
- mojo::ScopedSharedBufferMapping mapping;
- mojo::ScopedSharedBufferHandle handle;
- if (!CreateAndMapSharedBuffer(size, &mapping, &handle)) {
- if (last_state_.error == gpu::error::kNoError)
- last_state_.error = gpu::error::kLostContext;
- return NULL;
- }
-
- *id = ++next_transfer_buffer_id_;
-
- command_buffer_->RegisterTransferBuffer(*id, std::move(handle),
- static_cast<uint32_t>(size));
-
- std::unique_ptr<gpu::BufferBacking> backing(
- new mus::MojoBufferBacking(std::move(mapping), size));
- scoped_refptr<gpu::Buffer> buffer(new gpu::Buffer(std::move(backing)));
- return buffer;
-}
-
-void CommandBufferClientImpl::DestroyTransferBuffer(int32_t id) {
- command_buffer_->DestroyTransferBuffer(id);
-}
-
-void CommandBufferClientImpl::SetGpuControlClient(gpu::GpuControlClient* c) {
- gpu_control_client_ = c;
-}
-
-gpu::Capabilities CommandBufferClientImpl::GetCapabilities() {
- return capabilities_;
-}
-
-int32_t CommandBufferClientImpl::CreateImage(ClientBuffer buffer,
- size_t width,
- size_t height,
- unsigned internalformat) {
- int32_t new_id = ++next_image_id_;
-
- gfx::Size size(static_cast<int32_t>(width), static_cast<int32_t>(height));
-
- mus::MojoGpuMemoryBufferImpl* gpu_memory_buffer =
- mus::MojoGpuMemoryBufferImpl::FromClientBuffer(buffer);
- gfx::GpuMemoryBufferHandle handle = gpu_memory_buffer->GetHandle();
-
- bool requires_sync_point = false;
- if (handle.type != gfx::SHARED_MEMORY_BUFFER) {
- requires_sync_point = true;
- NOTIMPLEMENTED();
- return -1;
- }
-
- base::SharedMemoryHandle dupd_handle =
- base::SharedMemory::DuplicateHandle(handle.handle);
-#if defined(OS_WIN)
- HANDLE platform_handle = dupd_handle.GetHandle();
-#else
- int platform_handle = dupd_handle.fd;
-#endif
-
- mojo::ScopedHandle scoped_handle = mojo::WrapPlatformFile(platform_handle);
- command_buffer_->CreateImage(
- new_id, std::move(scoped_handle), handle.type, std::move(size),
- static_cast<int32_t>(gpu_memory_buffer->GetFormat()), internalformat);
- if (requires_sync_point) {
- NOTIMPLEMENTED();
- // TODO(jam): need to support this if we support types other than
- // SHARED_MEMORY_BUFFER.
- // gpu_memory_buffer_manager->SetDestructionSyncPoint(gpu_memory_buffer,
- // InsertSyncPoint());
- }
-
- return new_id;
-}
-
-void CommandBufferClientImpl::DestroyImage(int32_t id) {
- command_buffer_->DestroyImage(id);
-}
-
-int32_t CommandBufferClientImpl::CreateGpuMemoryBufferImage(
- size_t width,
- size_t height,
- unsigned internalformat,
- unsigned usage) {
- std::unique_ptr<gfx::GpuMemoryBuffer> buffer(
- mus::MojoGpuMemoryBufferImpl::Create(
- gfx::Size(static_cast<int>(width), static_cast<int>(height)),
- gpu::DefaultBufferFormatForImageFormat(internalformat),
- gfx::BufferUsage::SCANOUT));
- if (!buffer)
- return -1;
-
- return CreateImage(buffer->AsClientBuffer(), width, height, internalformat);
-}
-
-int32_t CommandBufferClientImpl::GetImageGpuMemoryBufferId(unsigned image_id) {
- // TODO(erikchen): Once this class supports IOSurface GpuMemoryBuffer backed
- // images, it will also need to keep a local cache from image id to
- // GpuMemoryBuffer id.
- NOTIMPLEMENTED();
- return -1;
-}
-
-void CommandBufferClientImpl::SignalQuery(uint32_t query,
- const base::Closure& callback) {
- // TODO(piman)
- NOTIMPLEMENTED();
-}
-
-void CommandBufferClientImpl::Destroyed(int32_t lost_reason, int32_t error) {
- if (destroyed_)
- return;
- last_state_.context_lost_reason =
- static_cast<gpu::error::ContextLostReason>(lost_reason);
- last_state_.error = static_cast<gpu::error::Error>(error);
- if (gpu_control_client_)
- gpu_control_client_->OnGpuControlLostContext();
- destroyed_ = true;
-}
-
-void CommandBufferClientImpl::SignalAck(uint32_t id) {}
-
-void CommandBufferClientImpl::SwapBuffersCompleted(int32_t result) {}
-
-void CommandBufferClientImpl::UpdateState(
- const gpu::CommandBuffer::State& state) {}
-
-void CommandBufferClientImpl::UpdateVSyncParameters(int64_t timebase,
- int64_t interval) {}
-
-void CommandBufferClientImpl::TryUpdateState() {
- if (last_state_.error == gpu::error::kNoError)
- shared_state()->Read(&last_state_);
-}
-
-void CommandBufferClientImpl::MakeProgressAndUpdateState() {
- gpu::CommandBuffer::State state;
- command_buffer_->MakeProgress(last_state_.get_offset,
- base::Bind(&MakeProgressCallback, &state));
-
- base::ThreadRestrictions::ScopedAllowWait wait;
- if (!command_buffer_.WaitForIncomingResponse()) {
- VLOG(1) << "Channel encountered error while waiting for command buffer.";
- // TODO(piman): is it ok for this to re-enter?
- Destroyed(gpu::error::kUnknown, gpu::error::kLostContext);
- return;
- }
-
- if (state.generation - last_state_.generation < 0x80000000U)
- last_state_ = state;
-}
-
-void CommandBufferClientImpl::SetLock(base::Lock* lock) {}
-
-void CommandBufferClientImpl::EnsureWorkVisible() {
- // This is only relevant for out-of-process command buffers.
-}
-
-gpu::CommandBufferNamespace CommandBufferClientImpl::GetNamespaceID() const {
- return gpu::CommandBufferNamespace::MOJO;
-}
-
-gpu::CommandBufferId CommandBufferClientImpl::GetCommandBufferID() const {
- return command_buffer_id_;
-}
-
-int32_t CommandBufferClientImpl::GetExtraCommandBufferData() const {
- return 0;
-}
-
-uint64_t CommandBufferClientImpl::GenerateFenceSyncRelease() {
- return next_fence_sync_release_++;
-}
-
-bool CommandBufferClientImpl::IsFenceSyncRelease(uint64_t release) {
- return release != 0 && release < next_fence_sync_release_;
-}
-
-bool CommandBufferClientImpl::IsFenceSyncFlushed(uint64_t release) {
- return release != 0 && release <= flushed_fence_sync_release_;
-}
-
-bool CommandBufferClientImpl::IsFenceSyncFlushReceived(uint64_t release) {
- return IsFenceSyncFlushed(release);
-}
-
-void CommandBufferClientImpl::SignalSyncToken(const gpu::SyncToken& sync_token,
- const base::Closure& callback) {
- // TODO(dyen)
- NOTIMPLEMENTED();
-}
-
-bool CommandBufferClientImpl::CanWaitUnverifiedSyncToken(
- const gpu::SyncToken* sync_token) {
- // Right now, MOJO_LOCAL is only used by trusted code, so it is safe to wait
- // on a sync token in MOJO_LOCAL command buffer.
- if (sync_token->namespace_id() == gpu::CommandBufferNamespace::MOJO_LOCAL)
- return true;
-
- // It is also safe to wait on the same context.
- if (sync_token->namespace_id() == gpu::CommandBufferNamespace::MOJO &&
- sync_token->command_buffer_id() == GetCommandBufferID())
- return true;
-
- return false;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.h b/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.h
deleted file mode 100644
index 80a46e93b7f..00000000000
--- a/chromium/components/mus/public/cpp/lib/command_buffer_client_impl.h
+++ /dev/null
@@ -1,117 +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 COMPONENTS_MUS_PUBLIC_CPP_LIB_COMMAND_BUFFER_CLIENT_IMPL_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_LIB_COMMAND_BUFFER_CLIENT_IMPL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "components/mus/public/interfaces/command_buffer.mojom.h"
-#include "gpu/command_buffer/client/gpu_control.h"
-#include "gpu/command_buffer/common/command_buffer.h"
-#include "gpu/command_buffer/common/command_buffer_id.h"
-#include "gpu/command_buffer/common/command_buffer_shared.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace base {
-class RunLoop;
-}
-
-namespace mus {
-class CommandBufferClientImpl;
-
-class CommandBufferClientImpl : public mus::mojom::CommandBufferClient,
- public gpu::CommandBuffer,
- public gpu::GpuControl {
- public:
- explicit CommandBufferClientImpl(
- const std::vector<int32_t>& attribs,
- mus::mojom::CommandBufferPtr command_buffer_ptr);
- ~CommandBufferClientImpl() override;
- bool Initialize();
-
- // CommandBuffer implementation:
- State GetLastState() override;
- int32_t GetLastToken() override;
- void Flush(int32_t put_offset) override;
- void OrderingBarrier(int32_t put_offset) override;
- void WaitForTokenInRange(int32_t start, int32_t end) override;
- void WaitForGetOffsetInRange(int32_t start, int32_t end) override;
- void SetGetBuffer(int32_t shm_id) override;
- scoped_refptr<gpu::Buffer> CreateTransferBuffer(size_t size,
- int32_t* id) override;
- void DestroyTransferBuffer(int32_t id) override;
-
- // gpu::GpuControl implementation:
- void SetGpuControlClient(gpu::GpuControlClient*) override;
- gpu::Capabilities GetCapabilities() override;
- int32_t CreateImage(ClientBuffer buffer,
- size_t width,
- size_t height,
- unsigned internalformat) override;
- void DestroyImage(int32_t id) override;
- int32_t CreateGpuMemoryBufferImage(size_t width,
- size_t height,
- unsigned internalformat,
- unsigned usage) override;
- int32_t GetImageGpuMemoryBufferId(unsigned image_id) override;
- void SignalQuery(uint32_t query, const base::Closure& callback) override;
- void SetLock(base::Lock*) override;
- void EnsureWorkVisible() override;
- gpu::CommandBufferNamespace GetNamespaceID() const override;
- gpu::CommandBufferId GetCommandBufferID() const override;
- int32_t GetExtraCommandBufferData() const override;
- uint64_t GenerateFenceSyncRelease() override;
- bool IsFenceSyncRelease(uint64_t release) override;
- bool IsFenceSyncFlushed(uint64_t release) override;
- bool IsFenceSyncFlushReceived(uint64_t release) override;
- void SignalSyncToken(const gpu::SyncToken& sync_token,
- const base::Closure& callback) override;
- bool CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) override;
-
- private:
- // mus::mojom::CommandBufferClient implementation:
- void Destroyed(int32_t lost_reason, int32_t error) override;
- void SignalAck(uint32_t id) override;
- void SwapBuffersCompleted(int32_t result) override;
- void UpdateState(const gpu::CommandBuffer::State& state) override;
- void UpdateVSyncParameters(int64_t timebase, int64_t interval) override;
-
- void TryUpdateState();
- void MakeProgressAndUpdateState();
-
- gpu::CommandBufferSharedState* shared_state() const {
- return reinterpret_cast<gpu::CommandBufferSharedState*>(
- shared_state_.get());
- }
-
- gpu::GpuControlClient* gpu_control_client_;
- bool destroyed_;
- std::vector<int32_t> attribs_;
- mojo::Binding<mus::mojom::CommandBufferClient> client_binding_;
- mus::mojom::CommandBufferPtr command_buffer_;
-
- gpu::CommandBufferId command_buffer_id_;
- gpu::Capabilities capabilities_;
- State last_state_;
- mojo::ScopedSharedBufferMapping shared_state_;
- int32_t last_put_offset_;
- int32_t next_transfer_buffer_id_;
-
- // Image IDs are allocated in sequence.
- int next_image_id_;
-
- uint64_t next_fence_sync_release_;
- uint64_t flushed_fence_sync_release_;
-};
-
-} // mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_LIB_COMMAND_BUFFER_CLIENT_IMPL_H_
diff --git a/chromium/components/mus/public/cpp/lib/context_provider.cc b/chromium/components/mus/public/cpp/lib/context_provider.cc
deleted file mode 100644
index 02717112dd7..00000000000
--- a/chromium/components/mus/public/cpp/lib/context_provider.cc
+++ /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.
-
-#include "components/mus/public/cpp/context_provider.h"
-
-#include <stdint.h>
-
-#include "base/logging.h"
-#include "components/mus/public/cpp/gles2_context.h"
-#include "services/shell/public/cpp/connector.h"
-
-namespace mus {
-
-ContextProvider::ContextProvider(shell::Connector* connector)
- : connector_(connector->Clone()) {}
-
-bool ContextProvider::BindToCurrentThread() {
- if (connector_) {
- context_ = GLES2Context::CreateOffscreenContext(std::vector<int32_t>(),
- connector_.get());
- // We don't need the connector anymore, so release it.
- connector_.reset();
- }
- return !!context_;
-}
-
-gpu::gles2::GLES2Interface* ContextProvider::ContextGL() {
- return context_->interface();
-}
-
-gpu::ContextSupport* ContextProvider::ContextSupport() {
- if (!context_)
- return NULL;
- return context_->context_support();
-}
-
-class GrContext* ContextProvider::GrContext() {
- return NULL;
-}
-
-void ContextProvider::InvalidateGrContext(uint32_t state) {}
-
-gpu::Capabilities ContextProvider::ContextCapabilities() {
- gpu::Capabilities capabilities;
- // Enabled the CHROMIUM_image extension to use GpuMemoryBuffers. The
- // implementation of which is used in CommandBufferDriver.
- capabilities.image = true;
- return capabilities;
-}
-
-base::Lock* ContextProvider::GetLock() {
- // This context provider is not used on multiple threads.
- NOTREACHED();
- return nullptr;
-}
-
-ContextProvider::~ContextProvider() {
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/gles2_context.cc b/chromium/components/mus/public/cpp/lib/gles2_context.cc
deleted file mode 100644
index 84363b15cfe..00000000000
--- a/chromium/components/mus/public/cpp/lib/gles2_context.cc
+++ /dev/null
@@ -1,109 +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 "components/mus/public/cpp/gles2_context.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <utility>
-
-#include "components/mus/common/gpu_service.h"
-#include "components/mus/public/cpp/lib/command_buffer_client_impl.h"
-#include "components/mus/public/interfaces/command_buffer.mojom.h"
-#include "components/mus/public/interfaces/gpu_service.mojom.h"
-#include "gpu/command_buffer/client/gles2_cmd_helper.h"
-#include "gpu/command_buffer/client/shared_memory_limits.h"
-#include "gpu/command_buffer/client/transfer_buffer.h"
-#include "gpu/ipc/client/command_buffer_proxy_impl.h"
-#include "mojo/public/cpp/system/core.h"
-#include "services/shell/public/cpp/connector.h"
-#include "url/gurl.h"
-
-namespace mus {
-
-GLES2Context::GLES2Context() {}
-
-GLES2Context::~GLES2Context() {}
-
-bool GLES2Context::Initialize(const std::vector<int32_t>& attribs,
- shell::Connector* connector) {
- gpu::CommandBuffer* command_buffer = nullptr;
- gpu::GpuControl* gpu_control = nullptr;
- // TODO(penghuang): Use type gpu::gles2::ContextCreationAttribHelper for
- // attribs.
- if (!mus::GpuService::UseChromeGpuCommandBuffer()) {
- mojom::GpuPtr gpu;
- connector->ConnectToInterface("mojo:mus", &gpu);
- mojom::CommandBufferPtr command_buffer_ptr;
- gpu->CreateOffscreenGLES2Context(GetProxy(&command_buffer_ptr));
- command_buffer_client_impl_.reset(
- new CommandBufferClientImpl(attribs, std::move(command_buffer_ptr)));
- if (!command_buffer_client_impl_->Initialize())
- return false;
- command_buffer = command_buffer_client_impl_.get();
- gpu_control = command_buffer_client_impl_.get();
- } else {
- scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
- GpuService::GetInstance()->EstablishGpuChannelSync();
- if (!gpu_channel_host)
- return false;
- gpu::SurfaceHandle surface_handle = gfx::kNullAcceleratedWidget;
- // TODO(penghuang): support shared group.
- gpu::CommandBufferProxyImpl* shared_command_buffer = nullptr;
- gpu::GpuStreamId stream_id = gpu::GpuStreamId::GPU_STREAM_DEFAULT;
- gpu::GpuStreamPriority stream_priority = gpu::GpuStreamPriority::NORMAL;
- gpu::gles2::ContextCreationAttribHelper attributes;
- // TODO(penghuang): figure a useful active_url.
- GURL active_url;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- base::ThreadTaskRunnerHandle::Get();
- if (!attributes.Parse(attribs))
- return false;
- command_buffer_proxy_impl_ = gpu::CommandBufferProxyImpl::Create(
- std::move(gpu_channel_host), surface_handle, shared_command_buffer,
- stream_id, stream_priority, attributes, active_url,
- std::move(task_runner));
- if (!command_buffer_proxy_impl_)
- return false;
- command_buffer = command_buffer_proxy_impl_.get();
- gpu_control = command_buffer_proxy_impl_.get();
- }
-
- constexpr gpu::SharedMemoryLimits default_limits;
- gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer));
- if (!gles2_helper_->Initialize(default_limits.command_buffer_size))
- return false;
- gles2_helper_->SetAutomaticFlushes(false);
- transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get()));
- gpu::Capabilities capabilities = gpu_control->GetCapabilities();
- bool bind_generates_resource =
- !!capabilities.bind_generates_resource_chromium;
- // TODO(piman): Some contexts (such as compositor) want this to be true, so
- // this needs to be a public parameter.
- bool lose_context_when_out_of_memory = false;
- bool support_client_side_arrays = false;
- implementation_.reset(new gpu::gles2::GLES2Implementation(
- gles2_helper_.get(), NULL, transfer_buffer_.get(),
- bind_generates_resource, lose_context_when_out_of_memory,
- support_client_side_arrays, gpu_control));
- if (!implementation_->Initialize(default_limits.start_transfer_buffer_size,
- default_limits.min_transfer_buffer_size,
- default_limits.max_transfer_buffer_size,
- default_limits.mapped_memory_reclaim_limit))
- return false;
- return true;
-}
-
-// static
-std::unique_ptr<GLES2Context> GLES2Context::CreateOffscreenContext(
- const std::vector<int32_t>& attribs,
- shell::Connector* connector) {
- std::unique_ptr<GLES2Context> gles2_context(new GLES2Context);
- if (!gles2_context->Initialize(attribs, connector))
- gles2_context.reset();
- return gles2_context;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/in_flight_change.cc b/chromium/components/mus/public/cpp/lib/in_flight_change.cc
deleted file mode 100644
index 04878742350..00000000000
--- a/chromium/components/mus/public/cpp/lib/in_flight_change.cc
+++ /dev/null
@@ -1,220 +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 "components/mus/public/cpp/lib/in_flight_change.h"
-
-#include "components/mus/public/cpp/lib/window_private.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-
-namespace mus {
-
-// InFlightChange -------------------------------------------------------------
-
-InFlightChange::InFlightChange(Window* window, ChangeType type)
- : window_(window), change_type_(type) {}
-
-InFlightChange::~InFlightChange() {}
-
-bool InFlightChange::Matches(const InFlightChange& change) const {
- DCHECK(change.window_ == window_ && change.change_type_ == change_type_);
- return true;
-}
-
-void InFlightChange::ChangeFailed() {}
-
-// InFlightBoundsChange -------------------------------------------------------
-
-InFlightBoundsChange::InFlightBoundsChange(Window* window,
- const gfx::Rect& revert_bounds)
- : InFlightChange(window, ChangeType::BOUNDS),
- revert_bounds_(revert_bounds) {}
-
-void InFlightBoundsChange::SetRevertValueFrom(const InFlightChange& change) {
- revert_bounds_ =
- static_cast<const InFlightBoundsChange&>(change).revert_bounds_;
-}
-
-void InFlightBoundsChange::Revert() {
- WindowPrivate(window()).LocalSetBounds(window()->bounds(), revert_bounds_);
-}
-
-// CrashInFlightChange --------------------------------------------------------
-
-CrashInFlightChange::CrashInFlightChange(Window* window, ChangeType type)
- : InFlightChange(window, type) {}
-
-CrashInFlightChange::~CrashInFlightChange() {}
-
-void CrashInFlightChange::SetRevertValueFrom(const InFlightChange& change) {
- CHECK(false);
-}
-
-void CrashInFlightChange::ChangeFailed() {
- DLOG(ERROR) << "changed failed, type=" << static_cast<int>(change_type());
- CHECK(false);
-}
-
-void CrashInFlightChange::Revert() {
- CHECK(false);
-}
-
-// InFlightWindowChange -------------------------------------------------------
-
-InFlightWindowTreeClientChange::InFlightWindowTreeClientChange(
- WindowTreeClient* client,
- Window* revert_value,
- ChangeType type)
- : InFlightChange(nullptr, type),
- client_(client),
- revert_window_(nullptr) {
- SetRevertWindow(revert_value);
-}
-
-InFlightWindowTreeClientChange::~InFlightWindowTreeClientChange() {
- SetRevertWindow(nullptr);
-}
-
-void InFlightWindowTreeClientChange::SetRevertValueFrom(
- const InFlightChange& change) {
- SetRevertWindow(static_cast<const InFlightWindowTreeClientChange&>(change)
- .revert_window_);
-}
-
-void InFlightWindowTreeClientChange::SetRevertWindow(Window* window) {
- if (revert_window_)
- revert_window_->RemoveObserver(this);
- revert_window_ = window;
- if (revert_window_)
- revert_window_->AddObserver(this);
-}
-
-void InFlightWindowTreeClientChange::OnWindowDestroying(Window* window) {
- SetRevertWindow(nullptr);
-}
-
-// InFlightCaptureChange ------------------------------------------------------
-
-InFlightCaptureChange::InFlightCaptureChange(
- WindowTreeClient* client, Window* revert_value)
- : InFlightWindowTreeClientChange(client,
- revert_value,
- ChangeType::CAPTURE) {}
-
-InFlightCaptureChange::~InFlightCaptureChange() {}
-
-void InFlightCaptureChange::Revert() {
- client()->LocalSetCapture(revert_window());
-}
-
-// InFlightFocusChange --------------------------------------------------------
-
-InFlightFocusChange::InFlightFocusChange(
- WindowTreeClient* client,
- Window* revert_value)
- : InFlightWindowTreeClientChange(client,
- revert_value,
- ChangeType::FOCUS) {}
-
-InFlightFocusChange::~InFlightFocusChange() {}
-
-void InFlightFocusChange::Revert() {
- client()->LocalSetFocus(revert_window());
-}
-
-// InFlightPropertyChange -----------------------------------------------------
-
-InFlightPropertyChange::InFlightPropertyChange(
- Window* window,
- const std::string& property_name,
- const mojo::Array<uint8_t>& revert_value)
- : InFlightChange(window, ChangeType::PROPERTY),
- property_name_(property_name),
- revert_value_(revert_value.Clone()) {}
-
-InFlightPropertyChange::~InFlightPropertyChange() {}
-
-bool InFlightPropertyChange::Matches(const InFlightChange& change) const {
- return static_cast<const InFlightPropertyChange&>(change).property_name_ ==
- property_name_;
-}
-
-void InFlightPropertyChange::SetRevertValueFrom(const InFlightChange& change) {
- revert_value_ =
- static_cast<const InFlightPropertyChange&>(change).revert_value_.Clone();
-}
-
-void InFlightPropertyChange::Revert() {
- WindowPrivate(window())
- .LocalSetSharedProperty(property_name_, std::move(revert_value_));
-}
-
-// InFlightPredefinedCursorChange ---------------------------------------------
-
-InFlightPredefinedCursorChange::InFlightPredefinedCursorChange(
- Window* window,
- mojom::Cursor revert_value)
- : InFlightChange(window, ChangeType::PREDEFINED_CURSOR),
- revert_cursor_(revert_value) {}
-
-InFlightPredefinedCursorChange::~InFlightPredefinedCursorChange() {}
-
-void InFlightPredefinedCursorChange::SetRevertValueFrom(
- const InFlightChange& change) {
- revert_cursor_ =
- static_cast<const InFlightPredefinedCursorChange&>(change).revert_cursor_;
-}
-
-void InFlightPredefinedCursorChange::Revert() {
- WindowPrivate(window()).LocalSetPredefinedCursor(revert_cursor_);
-}
-
-// InFlightVisibleChange -------------------------------------------------------
-
-InFlightVisibleChange::InFlightVisibleChange(Window* window,
- bool revert_value)
- : InFlightChange(window, ChangeType::VISIBLE),
- revert_visible_(revert_value) {}
-
-InFlightVisibleChange::~InFlightVisibleChange() {}
-
-void InFlightVisibleChange::SetRevertValueFrom(const InFlightChange& change) {
- revert_visible_ =
- static_cast<const InFlightVisibleChange&>(change).revert_visible_;
-}
-
-void InFlightVisibleChange::Revert() {
- WindowPrivate(window()).LocalSetVisible(revert_visible_);
-}
-
-// InFlightOpacityChange -------------------------------------------------------
-
-InFlightOpacityChange::InFlightOpacityChange(Window* window, float revert_value)
- : InFlightChange(window, ChangeType::OPACITY),
- revert_opacity_(revert_value) {}
-
-InFlightOpacityChange::~InFlightOpacityChange() {}
-
-void InFlightOpacityChange::SetRevertValueFrom(const InFlightChange& change) {
- revert_opacity_ =
- static_cast<const InFlightOpacityChange&>(change).revert_opacity_;
-}
-
-void InFlightOpacityChange::Revert() {
- WindowPrivate(window()).LocalSetOpacity(revert_opacity_);
-}
-
-// InFlightSetModalChange ------------------------------------------------------
-
-InFlightSetModalChange::InFlightSetModalChange(Window* window)
- : InFlightChange(window, ChangeType::SET_MODAL) {}
-
-InFlightSetModalChange::~InFlightSetModalChange() {}
-
-void InFlightSetModalChange::SetRevertValueFrom(const InFlightChange& change) {}
-
-void InFlightSetModalChange::Revert() {
- WindowPrivate(window()).LocalUnsetModal();
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/in_flight_change.h b/chromium/components/mus/public/cpp/lib/in_flight_change.h
deleted file mode 100644
index bf77fc6e6b1..00000000000
--- a/chromium/components/mus/public/cpp/lib/in_flight_change.h
+++ /dev/null
@@ -1,298 +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 COMPONENTS_MUS_PUBLIC_CPP_LIB_IN_FLIGHT_CHANGE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_LIB_IN_FLIGHT_CHANGE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "components/mus/public/cpp/window_observer.h"
-#include "mojo/public/cpp/bindings/array.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace mus {
-
-namespace mojom {
-enum class Cursor : int32_t;
-}
-
-class Window;
-class WindowTreeClient;
-
-enum class ChangeType {
- ADD_CHILD,
- ADD_TRANSIENT_WINDOW,
- BOUNDS,
- CAPTURE,
- DELETE_WINDOW,
- FOCUS,
- NEW_WINDOW,
- NEW_TOP_LEVEL_WINDOW,
- OPACITY,
- PREDEFINED_CURSOR,
- PROPERTY,
- REMOVE_CHILD,
- REMOVE_TRANSIENT_WINDOW_FROM_PARENT,
- REORDER,
- SET_MODAL,
- VISIBLE,
-};
-
-// InFlightChange is used to track function calls to the server and take the
-// appropriate action when the call fails, or the same property changes while
-// waiting for the response. When a function is called on the server an
-// InFlightChange is created. The function call is complete when
-// OnChangeCompleted() is received from the server. The following may occur
-// while waiting for a response:
-// . A new value is encountered from the server. For example, the bounds of
-// a window is locally changed and while waiting for the ack
-// OnWindowBoundsChanged() is received.
-// When this happens SetRevertValueFrom() is invoked on the InFlightChange.
-// The expectation is SetRevertValueFrom() takes the value to revert from the
-// supplied change.
-// . While waiting for the ack the property is again modified locally. When
-// this happens a new InFlightChange is created. Once the ack for the first
-// call is received, and the server rejected the change ChangeFailed() is
-// invoked on the first change followed by SetRevertValueFrom() on the second
-// InFlightChange. This allows the new change to update the value to revert
-// should the second call fail.
-// . If the server responds that the call failed and there is not another
-// InFlightChange for the same window outstanding, then ChangeFailed() is
-// invoked followed by Revert(). The expectation is Revert() sets the
-// appropriate value back on the Window.
-//
-// In general there are two classes of changes:
-// 1. We are the only side allowed to make the change.
-// 2. The change can also be applied by another client. For example, the
-// window manager may change the bounds as well as the local client.
-//
-// For (1) use CrashInFlightChange. As the name implies this change CHECKs that
-// the change succeeded. Use the following pattern for this. This code goes
-// where the change is sent to the server (in WindowTreeClient):
-// const uint32_t change_id =
-// ScheduleInFlightChange(base::WrapUnique(new CrashInFlightChange(
-// window, ChangeType::REORDER)));
-//
-// For (2) use the same pattern as (1), but in the on change callback from the
-// server (e.g. OnWindowBoundsChanged()) add the following:
-// // value_from_server is the value supplied from the server. It corresponds
-// // to the value of the property at the time the server processed the
-// // change. If the local change fails, this is the value reverted to.
-// InFlightBoundsChange new_change(window, value_from_server);
-// if (ApplyServerChangeToExistingInFlightChange(new_change)) {
-// // There was an in flight change for the same property. The in flight
-// // change takes the value to revert from |new_change|.
-// return;
-// }
-//
-// // else case is no flight in change and the new value can be applied
-// // immediately.
-// WindowPrivate(window).LocalSetValue(new_value_from_server);
-//
-class InFlightChange {
- public:
- InFlightChange(Window* window, ChangeType type);
- virtual ~InFlightChange();
-
- // NOTE: for properties not associated with any window window is null.
- Window* window() { return window_; }
- const Window* window() const { return window_; }
- ChangeType change_type() const { return change_type_; }
-
- // Returns true if the two changes are considered the same. This is only
- // invoked if the window id and ChangeType match.
- virtual bool Matches(const InFlightChange& change) const;
-
- // Called in two cases:
- // . When the corresponding property on the server changes. In this case
- // |change| corresponds to the value from the server.
- // . When |change| unsuccesfully completes.
- virtual void SetRevertValueFrom(const InFlightChange& change) = 0;
-
- // The change failed. Normally you need not take any action here as Revert()
- // is called as appropriate.
- virtual void ChangeFailed();
-
- // The change failed and there is no pending change of the same type
- // outstanding, revert the value.
- virtual void Revert() = 0;
-
- private:
- Window* window_;
- const ChangeType change_type_;
-};
-
-class InFlightBoundsChange : public InFlightChange {
- public:
- InFlightBoundsChange(Window* window, const gfx::Rect& revert_bounds);
-
- // InFlightChange:
- void SetRevertValueFrom(const InFlightChange& change) override;
- void Revert() override;
-
- private:
- gfx::Rect revert_bounds_;
-
- DISALLOW_COPY_AND_ASSIGN(InFlightBoundsChange);
-};
-
-// Inflight change that crashes on failure. This is useful for changes that are
-// expected to always complete.
-class CrashInFlightChange : public InFlightChange {
- public:
- CrashInFlightChange(Window* window, ChangeType type);
- ~CrashInFlightChange() override;
-
- // InFlightChange:
- void SetRevertValueFrom(const InFlightChange& change) override;
- void ChangeFailed() override;
- void Revert() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CrashInFlightChange);
-};
-
-// Use this class for properties that are specific to the client, and not a
-// particular window. For example, only a single window can have focus, so focus
-// is specific to the client.
-//
-// This does not implement InFlightChange::Revert, subclasses must implement
-// that to update the WindowTreeClient.
-class InFlightWindowTreeClientChange : public InFlightChange,
- public WindowObserver {
- public:
- InFlightWindowTreeClientChange(WindowTreeClient* client,
- Window* revert_value,
- ChangeType type);
- ~InFlightWindowTreeClientChange() override;
-
- // InFlightChange:
- void SetRevertValueFrom(const InFlightChange& change) override;
-
- protected:
- WindowTreeClient* client() { return client_; }
- Window* revert_window() { return revert_window_; }
-
- private:
- void SetRevertWindow(Window* window);
-
- // WindowObserver:
- void OnWindowDestroying(Window* window) override;
-
- WindowTreeClient* client_;
- Window* revert_window_;
-
- DISALLOW_COPY_AND_ASSIGN(InFlightWindowTreeClientChange);
-};
-
-class InFlightCaptureChange : public InFlightWindowTreeClientChange {
- public:
- InFlightCaptureChange(WindowTreeClient* client, Window* revert_value);
- ~InFlightCaptureChange() override;
-
- // InFlightChange:
- void Revert() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InFlightCaptureChange);
-};
-
-class InFlightFocusChange : public InFlightWindowTreeClientChange {
- public:
- InFlightFocusChange(WindowTreeClient* client, Window* revert_value);
- ~InFlightFocusChange() override;
-
- // InFlightChange:
- void Revert() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InFlightFocusChange);
-};
-
-class InFlightPropertyChange : public InFlightChange {
- public:
- InFlightPropertyChange(Window* window,
- const std::string& property_name,
- const mojo::Array<uint8_t>& revert_value);
- ~InFlightPropertyChange() override;
-
- // InFlightChange:
- bool Matches(const InFlightChange& change) const override;
- void SetRevertValueFrom(const InFlightChange& change) override;
- void Revert() override;
-
- private:
- const std::string property_name_;
- mojo::Array<uint8_t> revert_value_;
-
- DISALLOW_COPY_AND_ASSIGN(InFlightPropertyChange);
-};
-
-class InFlightPredefinedCursorChange : public InFlightChange {
- public:
- InFlightPredefinedCursorChange(Window* window, mojom::Cursor revert_value);
- ~InFlightPredefinedCursorChange() override;
-
- // InFlightChange:
- void SetRevertValueFrom(const InFlightChange& change) override;
- void Revert() override;
-
- private:
- mojom::Cursor revert_cursor_;
-
- DISALLOW_COPY_AND_ASSIGN(InFlightPredefinedCursorChange);
-};
-
-class InFlightVisibleChange : public InFlightChange {
- public:
- InFlightVisibleChange(Window* window, const bool revert_value);
- ~InFlightVisibleChange() override;
-
- // InFlightChange:
- void SetRevertValueFrom(const InFlightChange& change) override;
- void Revert() override;
-
- private:
- bool revert_visible_;
-
- DISALLOW_COPY_AND_ASSIGN(InFlightVisibleChange);
-};
-
-class InFlightOpacityChange : public InFlightChange {
- public:
- InFlightOpacityChange(Window* window, float revert_value);
- ~InFlightOpacityChange() override;
-
- // InFlightChange:
- void SetRevertValueFrom(const InFlightChange& change) override;
- void Revert() override;
-
- private:
- float revert_opacity_;
-
- DISALLOW_COPY_AND_ASSIGN(InFlightOpacityChange);
-};
-
-class InFlightSetModalChange : public InFlightChange {
- public:
- explicit InFlightSetModalChange(Window* window);
- ~InFlightSetModalChange() override;
-
- // InFlightChange:
- void SetRevertValueFrom(const InFlightChange& change) override;
- void Revert() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InFlightSetModalChange);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_LIB_IN_FLIGHT_CHANGE_H_
diff --git a/chromium/components/mus/public/cpp/lib/output_surface.cc b/chromium/components/mus/public/cpp/lib/output_surface.cc
deleted file mode 100644
index 86462ec95f4..00000000000
--- a/chromium/components/mus/public/cpp/lib/output_surface.cc
+++ /dev/null
@@ -1,70 +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 "components/mus/public/cpp/output_surface.h"
-
-#include "base/bind.h"
-#include "cc/output/compositor_frame.h"
-#include "cc/output/compositor_frame_ack.h"
-#include "cc/output/output_surface_client.h"
-#include "components/mus/public/cpp/window_surface.h"
-
-namespace mus {
-
-OutputSurface::OutputSurface(
- const scoped_refptr<cc::ContextProvider>& context_provider,
- std::unique_ptr<mus::WindowSurface> surface)
- : cc::OutputSurface(context_provider, nullptr, nullptr),
- surface_(std::move(surface)) {
- capabilities_.delegated_rendering = true;
-}
-
-OutputSurface::~OutputSurface() {}
-
-bool OutputSurface::BindToClient(cc::OutputSurfaceClient* client) {
- surface_->BindToThread();
- surface_->set_client(this);
- return cc::OutputSurface::BindToClient(client);
-}
-
-void OutputSurface::DetachFromClient() {
- surface_.reset();
- cc::OutputSurface::DetachFromClient();
-}
-
-void OutputSurface::BindFramebuffer() {
- // This is a delegating output surface, no framebuffer/direct drawing support.
- NOTREACHED();
-}
-
-uint32_t OutputSurface::GetFramebufferCopyTextureFormat() {
- // This is a delegating output surface, no framebuffer/direct drawing support.
- NOTREACHED();
- return 0;
-}
-
-void OutputSurface::SwapBuffers(cc::CompositorFrame frame) {
- // TODO(fsamuel, rjkroege): We should probably throttle compositor frames.
- client_->DidSwapBuffers();
- // OutputSurface owns WindowSurface, and so if OutputSurface is
- // destroyed then SubmitCompositorFrame's callback will never get called.
- // Thus, base::Unretained is safe here.
- surface_->SubmitCompositorFrame(
- std::move(frame),
- base::Bind(&OutputSurface::SwapBuffersComplete, base::Unretained(this)));
-}
-
-void OutputSurface::OnResourcesReturned(
- mus::WindowSurface* surface,
- mojo::Array<cc::ReturnedResource> resources) {
- cc::CompositorFrameAck cfa;
- cfa.resources = resources.To<cc::ReturnedResourceArray>();
- ReclaimResources(&cfa);
-}
-
-void OutputSurface::SwapBuffersComplete() {
- client_->DidSwapBuffersComplete();
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/property_type_converters.cc b/chromium/components/mus/public/cpp/lib/property_type_converters.cc
deleted file mode 100644
index 17cacf1f249..00000000000
--- a/chromium/components/mus/public/cpp/lib/property_type_converters.cc
+++ /dev/null
@@ -1,207 +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 "components/mus/public/cpp/property_type_converters.h"
-
-#include <stdint.h>
-
-#include "base/strings/utf_string_conversions.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace {
-
-// Maximum allowed height or width of a bitmap, in pixels. This limit prevents
-// malformed bitmap headers from causing arbitrarily large memory allocations
-// for pixel data.
-const int kMaxBitmapSize = 4096;
-
-} // namespace
-
-namespace mojo {
-
-// static
-std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, gfx::Rect>::Convert(
- const gfx::Rect& input) {
- std::vector<uint8_t> vec(16);
- vec[0] = (input.x() >> 24) & 0xFF;
- vec[1] = (input.x() >> 16) & 0xFF;
- vec[2] = (input.x() >> 8) & 0xFF;
- vec[3] = input.x() & 0xFF;
- vec[4] = (input.y() >> 24) & 0xFF;
- vec[5] = (input.y() >> 16) & 0xFF;
- vec[6] = (input.y() >> 8) & 0xFF;
- vec[7] = input.y() & 0xFF;
- vec[8] = (input.width() >> 24) & 0xFF;
- vec[9] = (input.width() >> 16) & 0xFF;
- vec[10] = (input.width() >> 8) & 0xFF;
- vec[11] = input.width() & 0xFF;
- vec[12] = (input.height() >> 24) & 0xFF;
- vec[13] = (input.height() >> 16) & 0xFF;
- vec[14] = (input.height() >> 8) & 0xFF;
- vec[15] = input.height() & 0xFF;
- return vec;
-}
-
-// static
-gfx::Rect TypeConverter<gfx::Rect, std::vector<uint8_t>>::Convert(
- const std::vector<uint8_t>& input) {
- return gfx::Rect(
- input[0] << 24 | input[1] << 16 | input[2] << 8 | input[3],
- input[4] << 24 | input[5] << 16 | input[6] << 8 | input[7],
- input[8] << 24 | input[9] << 16 | input[10] << 8 | input[11],
- input[12] << 24 | input[13] << 16 | input[14] << 8 | input[15]);
-}
-
-// static
-std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, gfx::Size>::Convert(
- const gfx::Size& input) {
- std::vector<uint8_t> vec(8);
- vec[0] = (input.width() >> 24) & 0xFF;
- vec[1] = (input.width() >> 16) & 0xFF;
- vec[2] = (input.width() >> 8) & 0xFF;
- vec[3] = input.width() & 0xFF;
- vec[4] = (input.height() >> 24) & 0xFF;
- vec[5] = (input.height() >> 16) & 0xFF;
- vec[6] = (input.height() >> 8) & 0xFF;
- vec[7] = input.height() & 0xFF;
- return vec;
-}
-
-// static
-gfx::Size TypeConverter<gfx::Size, std::vector<uint8_t>>::Convert(
- const std::vector<uint8_t>& input) {
- return gfx::Size(input[0] << 24 | input[1] << 16 | input[2] << 8 | input[3],
- input[4] << 24 | input[5] << 16 | input[6] << 8 | input[7]);
-}
-
-// static
-std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, int32_t>::Convert(
- const int32_t& input) {
- std::vector<uint8_t> vec(4);
- vec[0] = (input >> 24) & 0xFF;
- vec[1] = (input >> 16) & 0xFF;
- vec[2] = (input >> 8) & 0xFF;
- vec[3] = input & 0xFF;
- return vec;
-}
-
-// static
-int32_t TypeConverter<int32_t, std::vector<uint8_t>>::Convert(
- const std::vector<uint8_t>& input) {
- return input[0] << 24 | input[1] << 16 | input[2] << 8 | input[3];
-}
-
-// static
-std::vector<uint8_t>
-TypeConverter<std::vector<uint8_t>, base::string16>::Convert(
- const base::string16& input) {
- return ConvertTo<std::vector<uint8_t>>(base::UTF16ToUTF8(input));
-}
-
-// static
-base::string16 TypeConverter<base::string16, std::vector<uint8_t>>::Convert(
- const std::vector<uint8_t>& input) {
- return base::UTF8ToUTF16(ConvertTo<std::string>(input));
-}
-
-// static
-std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, std::string>::Convert(
- const std::string& input) {
- return std::vector<uint8_t>(input.begin(), input.end());
-}
-
-// static
-std::string TypeConverter<std::string, std::vector<uint8_t>>::Convert(
- const std::vector<uint8_t>& input) {
- return std::string(input.begin(), input.end());
-}
-
-// static
-std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, SkBitmap>::Convert(
- const SkBitmap& input) {
- // Empty images are valid to serialize and are represented by an empty vector.
- if (input.isNull())
- return std::vector<uint8_t>();
-
- // Only RGBA 8888 bitmaps with premultiplied alpha are supported.
- if (input.colorType() != kBGRA_8888_SkColorType ||
- input.alphaType() != kPremul_SkAlphaType) {
- NOTREACHED();
- return std::vector<uint8_t>();
- }
-
- // Sanity check the bitmap size.
- int width = input.width();
- int height = input.height();
- if (width < 0 || width > kMaxBitmapSize || height < 0 ||
- height > kMaxBitmapSize) {
- NOTREACHED();
- return std::vector<uint8_t>();
- }
-
- // Serialize the bitmap. The size is restricted so only 2 bytes are required
- // per dimension.
- std::vector<uint8_t> vec(4 + input.getSize());
- vec[0] = (width >> 8) & 0xFF;
- vec[1] = width & 0xFF;
- vec[2] = (height >> 8) & 0xFF;
- vec[3] = height & 0xFF;
- if (!input.copyPixelsTo(&vec[4], input.getSize()))
- return std::vector<uint8_t>();
- return vec;
-}
-
-// static
-SkBitmap TypeConverter<SkBitmap, std::vector<uint8_t>>::Convert(
- const std::vector<uint8_t>& input) {
- // Empty images are represented by empty vectors.
- if (input.empty())
- return SkBitmap();
-
- // Read and sanity check size.
- int width = input[0] << 8 | input[1];
- int height = input[2] << 8 | input[3];
- if (width < 0 || width > kMaxBitmapSize || height < 0 ||
- height > kMaxBitmapSize) {
- NOTREACHED();
- return SkBitmap();
- }
-
- // Try to allocate a bitmap of the appropriate size.
- SkBitmap bitmap;
- if (!bitmap.tryAllocPixels(SkImageInfo::Make(
- width, height, kBGRA_8888_SkColorType, kPremul_SkAlphaType))) {
- return SkBitmap();
- }
-
- // Ensure the vector contains the right amount of data.
- if (input.size() != bitmap.getSize() + 4) {
- NOTREACHED();
- return SkBitmap();
- }
-
- // Read the pixel data.
- SkAutoLockPixels lock(bitmap);
- memcpy(bitmap.getPixels(), &input[4], bitmap.getSize());
- return bitmap;
-}
-
-// static
-std::vector<uint8_t> TypeConverter<std::vector<uint8_t>, bool>::Convert(
- bool input) {
- std::vector<uint8_t> vec(1);
- vec[0] = input ? 1 : 0;
- return vec;
-}
-
-// static
-bool TypeConverter<bool, std::vector<uint8_t>>::Convert(
- const std::vector<uint8_t>& input) {
- // Empty vectors are interpreted as false.
- return !input.empty() && (input[0] == 1);
-}
-
-} // namespace mojo
diff --git a/chromium/components/mus/public/cpp/lib/scoped_window_ptr.cc b/chromium/components/mus/public/cpp/lib/scoped_window_ptr.cc
deleted file mode 100644
index 360da1ff4b5..00000000000
--- a/chromium/components/mus/public/cpp/lib/scoped_window_ptr.cc
+++ /dev/null
@@ -1,44 +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 "components/mus/public/cpp/scoped_window_ptr.h"
-
-#include "components/mus/public/cpp/window.h"
-#include "components/mus/public/cpp/window_observer.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-
-namespace mus {
-
-ScopedWindowPtr::ScopedWindowPtr(Window* window) : window_(window) {
- window_->AddObserver(this);
-}
-
-ScopedWindowPtr::~ScopedWindowPtr() {
- if (window_)
- DeleteWindowOrWindowManager(window_);
- DetachFromWindow();
-}
-
-// static
-void ScopedWindowPtr::DeleteWindowOrWindowManager(Window* window) {
- if (window->window_tree()->GetRoots().count(window) > 0)
- delete window->window_tree();
- else
- window->Destroy();
-}
-
-void ScopedWindowPtr::DetachFromWindow() {
- if (!window_)
- return;
-
- window_->RemoveObserver(this);
- window_ = nullptr;
-}
-
-void ScopedWindowPtr::OnWindowDestroying(Window* window) {
- DCHECK_EQ(window_, window);
- DetachFromWindow();
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window.cc b/chromium/components/mus/public/cpp/lib/window.cc
deleted file mode 100644
index 83785c4544e..00000000000
--- a/chromium/components/mus/public/cpp/lib/window.cc
+++ /dev/null
@@ -1,891 +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 "components/mus/public/cpp/window.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <set>
-#include <string>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "components/mus/common/transient_window_utils.h"
-#include "components/mus/public/cpp/lib/window_private.h"
-#include "components/mus/public/cpp/property_type_converters.h"
-#include "components/mus/public/cpp/window_observer.h"
-#include "components/mus/public/cpp/window_property.h"
-#include "components/mus/public/cpp/window_surface.h"
-#include "components/mus/public/cpp/window_tracker.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-#include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "ui/display/display.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace mus {
-
-namespace {
-
-void NotifyWindowTreeChangeAtReceiver(
- Window* receiver,
- const WindowObserver::TreeChangeParams& params,
- bool change_applied) {
- WindowObserver::TreeChangeParams local_params = params;
- local_params.receiver = receiver;
- if (change_applied) {
- FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(receiver).observers(),
- OnTreeChanged(local_params));
- } else {
- FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(receiver).observers(),
- OnTreeChanging(local_params));
- }
-}
-
-void NotifyWindowTreeChangeUp(Window* start_at,
- const WindowObserver::TreeChangeParams& params,
- bool change_applied) {
- for (Window* current = start_at; current; current = current->parent())
- NotifyWindowTreeChangeAtReceiver(current, params, change_applied);
-}
-
-void NotifyWindowTreeChangeDown(Window* start_at,
- const WindowObserver::TreeChangeParams& params,
- bool change_applied) {
- NotifyWindowTreeChangeAtReceiver(start_at, params, change_applied);
- Window::Children::const_iterator it = start_at->children().begin();
- for (; it != start_at->children().end(); ++it)
- NotifyWindowTreeChangeDown(*it, params, change_applied);
-}
-
-void NotifyWindowTreeChange(const WindowObserver::TreeChangeParams& params,
- bool change_applied) {
- NotifyWindowTreeChangeDown(params.target, params, change_applied);
- if (params.old_parent)
- NotifyWindowTreeChangeUp(params.old_parent, params, change_applied);
- if (params.new_parent)
- NotifyWindowTreeChangeUp(params.new_parent, params, change_applied);
-}
-
-class ScopedTreeNotifier {
- public:
- ScopedTreeNotifier(Window* target, Window* old_parent, Window* new_parent) {
- params_.target = target;
- params_.old_parent = old_parent;
- params_.new_parent = new_parent;
- NotifyWindowTreeChange(params_, false);
- }
- ~ScopedTreeNotifier() { NotifyWindowTreeChange(params_, true); }
-
- private:
- WindowObserver::TreeChangeParams params_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier);
-};
-
-void RemoveChildImpl(Window* child, Window::Children* children) {
- Window::Children::iterator it =
- std::find(children->begin(), children->end(), child);
- if (it != children->end()) {
- children->erase(it);
- WindowPrivate(child).ClearParent();
- }
-}
-
-class OrderChangedNotifier {
- public:
- OrderChangedNotifier(Window* window,
- Window* relative_window,
- mojom::OrderDirection direction)
- : window_(window),
- relative_window_(relative_window),
- direction_(direction) {}
-
- ~OrderChangedNotifier() {}
-
- void NotifyWindowReordering() {
- FOR_EACH_OBSERVER(
- WindowObserver, *WindowPrivate(window_).observers(),
- OnWindowReordering(window_, relative_window_, direction_));
- }
-
- void NotifyWindowReordered() {
- FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window_).observers(),
- OnWindowReordered(window_, relative_window_, direction_));
- }
-
- private:
- Window* window_;
- Window* relative_window_;
- mojom::OrderDirection direction_;
-
- DISALLOW_COPY_AND_ASSIGN(OrderChangedNotifier);
-};
-
-class ScopedSetBoundsNotifier {
- public:
- ScopedSetBoundsNotifier(Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds)
- : window_(window), old_bounds_(old_bounds), new_bounds_(new_bounds) {
- FOR_EACH_OBSERVER(
- WindowObserver, *WindowPrivate(window_).observers(),
- OnWindowBoundsChanging(window_, old_bounds_, new_bounds_));
- }
- ~ScopedSetBoundsNotifier() {
- FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window_).observers(),
- OnWindowBoundsChanged(window_, old_bounds_, new_bounds_));
- }
-
- private:
- Window* window_;
- const gfx::Rect old_bounds_;
- const gfx::Rect new_bounds_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier);
-};
-
-// Some operations are only permitted in the client that created the window.
-bool OwnsWindow(WindowTreeClient* client, Window* window) {
- return !client || client->OwnsWindow(window);
-}
-
-bool IsClientRoot(Window* window) {
- return window->window_tree() &&
- window->window_tree()->GetRoots().count(window) > 0;
-}
-
-bool OwnsWindowOrIsRoot(Window* window) {
- return OwnsWindow(window->window_tree(), window) || IsClientRoot(window);
-}
-
-void EmptyEmbedCallback(bool result) {}
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// Window, public:
-
-void Window::Destroy() {
- if (!OwnsWindowOrIsRoot(this))
- return;
-
- if (client_)
- client_->DestroyWindow(this);
- while (!children_.empty()) {
- Window* child = children_.front();
- if (!OwnsWindow(client_, child)) {
- WindowPrivate(child).ClearParent();
- children_.erase(children_.begin());
- } else {
- child->Destroy();
- DCHECK(std::find(children_.begin(), children_.end(), child) ==
- children_.end());
- }
- }
- LocalDestroy();
-}
-
-void Window::SetBounds(const gfx::Rect& bounds) {
- if (!OwnsWindowOrIsRoot(this))
- return;
- if (bounds_ == bounds)
- return;
- if (client_)
- client_->SetBounds(this, bounds_, bounds);
- LocalSetBounds(bounds_, bounds);
-}
-
-gfx::Rect Window::GetBoundsInRoot() const {
- gfx::Vector2d offset;
- for (const Window* w = parent(); w != nullptr; w = w->parent())
- offset += w->bounds().OffsetFromOrigin();
- return bounds() + offset;
-}
-
-void Window::SetClientArea(
- const gfx::Insets& client_area,
- const std::vector<gfx::Rect>& additional_client_areas) {
- if (!OwnsWindowOrIsRoot(this))
- return;
-
- if (client_)
- client_->SetClientArea(server_id_, client_area,
- additional_client_areas);
- LocalSetClientArea(client_area, additional_client_areas);
-}
-
-void Window::SetHitTestMask(const gfx::Rect& mask) {
- if (!OwnsWindowOrIsRoot(this))
- return;
-
- if (hit_test_mask_ && *hit_test_mask_ == mask)
- return;
-
- if (client_)
- client_->SetHitTestMask(server_id_, mask);
- hit_test_mask_.reset(new gfx::Rect(mask));
-}
-
-void Window::ClearHitTestMask() {
- if (!OwnsWindowOrIsRoot(this))
- return;
-
- if (!hit_test_mask_)
- return;
-
- if (client_)
- client_->ClearHitTestMask(server_id_);
- hit_test_mask_.reset();
-}
-
-void Window::SetVisible(bool value) {
- if (visible_ == value)
- return;
-
- if (client_)
- client_->SetVisible(this, value);
- LocalSetVisible(value);
-}
-
-void Window::SetOpacity(float opacity) {
- if (client_)
- client_->SetOpacity(this, opacity);
- LocalSetOpacity(opacity);
-}
-
-void Window::SetPredefinedCursor(mus::mojom::Cursor cursor_id) {
- if (cursor_id_ == cursor_id)
- return;
-
- if (client_)
- client_->SetPredefinedCursor(server_id_, cursor_id);
- LocalSetPredefinedCursor(cursor_id);
-}
-
-bool Window::IsDrawn() const {
- if (!visible_)
- return false;
- return parent_ ? parent_->IsDrawn() : parent_drawn_;
-}
-
-std::unique_ptr<WindowSurface> Window::RequestSurface(mojom::SurfaceType type) {
- std::unique_ptr<WindowSurfaceBinding> surface_binding;
- std::unique_ptr<WindowSurface> surface =
- WindowSurface::Create(&surface_binding);
- AttachSurface(type, std::move(surface_binding));
- return surface;
-}
-
-void Window::AttachSurface(
- mojom::SurfaceType type,
- std::unique_ptr<WindowSurfaceBinding> surface_binding) {
- window_tree()->AttachSurface(
- server_id_, type, std::move(surface_binding->surface_request_),
- mojo::MakeProxy(std::move(surface_binding->surface_client_)));
-}
-
-void Window::ClearSharedProperty(const std::string& name) {
- SetSharedPropertyInternal(name, nullptr);
-}
-
-bool Window::HasSharedProperty(const std::string& name) const {
- return properties_.count(name) > 0;
-}
-
-void Window::AddObserver(WindowObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void Window::RemoveObserver(WindowObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-const Window* Window::GetRoot() const {
- const Window* root = this;
- for (const Window* parent = this; parent; parent = parent->parent())
- root = parent;
- return root;
-}
-
-void Window::AddChild(Window* child) {
- // TODO(beng): not necessarily valid to all clients, but possibly to the
- // embeddee in an embedder-embeddee relationship.
- if (client_)
- CHECK_EQ(child->client_, client_);
- // Roots can not be added as children of other windows.
- if (window_tree() && window_tree()->IsRoot(child))
- return;
- LocalAddChild(child);
- if (client_)
- client_->AddChild(this, child->server_id());
-}
-
-void Window::RemoveChild(Window* child) {
- // TODO(beng): not necessarily valid to all clients, but possibly to the
- // embeddee in an embedder-embeddee relationship.
- if (client_)
- CHECK_EQ(child->client_, client_);
- LocalRemoveChild(child);
- if (client_)
- client_->RemoveChild(this, child->server_id());
-}
-
-void Window::Reorder(Window* relative, mojom::OrderDirection direction) {
- if (!LocalReorder(relative, direction))
- return;
- if (client_)
- client_->Reorder(this, relative->server_id(), direction);
-}
-
-void Window::MoveToFront() {
- if (!parent_ || parent_->children_.back() == this)
- return;
- Reorder(parent_->children_.back(), mojom::OrderDirection::ABOVE);
-}
-
-void Window::MoveToBack() {
- if (!parent_ || parent_->children_.front() == this)
- return;
- Reorder(parent_->children_.front(), mojom::OrderDirection::BELOW);
-}
-
-bool Window::Contains(const Window* child) const {
- if (!child)
- return false;
- if (child == this)
- return true;
- if (client_)
- CHECK_EQ(child->client_, client_);
- for (const Window* p = child->parent(); p; p = p->parent()) {
- if (p == this)
- return true;
- }
- return false;
-}
-
-void Window::AddTransientWindow(Window* transient_window) {
- // A system modal window cannot become a transient child.
- DCHECK(!transient_window->is_modal() || transient_window->transient_parent());
-
- if (client_)
- CHECK_EQ(transient_window->client_, client_);
- LocalAddTransientWindow(transient_window);
- if (client_)
- client_->AddTransientWindow(this, transient_window->server_id());
-}
-
-void Window::RemoveTransientWindow(Window* transient_window) {
- if (client_)
- CHECK_EQ(transient_window->window_tree(), client_);
- LocalRemoveTransientWindow(transient_window);
- if (client_)
- client_->RemoveTransientWindowFromParent(transient_window);
-}
-
-void Window::SetModal() {
- if (is_modal_)
- return;
-
- LocalSetModal();
- if (client_)
- client_->SetModal(this);
-}
-
-Window* Window::GetChildByLocalId(int id) {
- if (id == local_id_)
- return this;
- // TODO(beng): this could be improved depending on how we decide to own
- // windows.
- for (Window* child : children_) {
- Window* matching_child = child->GetChildByLocalId(id);
- if (matching_child)
- return matching_child;
- }
- return nullptr;
-}
-
-void Window::SetTextInputState(mojo::TextInputStatePtr state) {
- if (client_)
- client_->SetWindowTextInputState(server_id_, std::move(state));
-}
-
-void Window::SetImeVisibility(bool visible, mojo::TextInputStatePtr state) {
- // SetImeVisibility() shouldn't be used if the window is not editable.
- DCHECK(state.is_null() || state->type != mojo::TextInputType::NONE);
- if (client_)
- client_->SetImeVisibility(server_id_, visible, std::move(state));
-}
-
-bool Window::HasCapture() const {
- return client_ && client_->GetCaptureWindow() == this;
-}
-
-void Window::SetCapture() {
- if (client_)
- client_->SetCapture(this);
-}
-
-void Window::ReleaseCapture() {
- if (client_)
- client_->ReleaseCapture(this);
-}
-
-void Window::SetFocus() {
- if (client_ && IsDrawn())
- client_->SetFocus(this);
-}
-
-bool Window::HasFocus() const {
- return client_ && client_->GetFocusedWindow() == this;
-}
-
-void Window::SetCanFocus(bool can_focus) {
- if (client_)
- client_->SetCanFocus(server_id_, can_focus);
-}
-
-void Window::Embed(mus::mojom::WindowTreeClientPtr client, uint32_t flags) {
- Embed(std::move(client), base::Bind(&EmptyEmbedCallback), flags);
-}
-
-void Window::Embed(mus::mojom::WindowTreeClientPtr client,
- const EmbedCallback& callback,
- uint32_t flags) {
- if (PrepareForEmbed())
- client_->Embed(server_id_, std::move(client), flags, callback);
- else
- callback.Run(false);
-}
-
-void Window::RequestClose() {
- if (client_)
- client_->RequestClose(this);
-}
-
-std::string Window::GetName() const {
- if (HasSharedProperty(mojom::WindowManager::kName_Property))
- return GetSharedProperty<std::string>(mojom::WindowManager::kName_Property);
-
- return std::string();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Window, protected:
-
-Window::Window() : Window(nullptr, static_cast<Id>(-1)) {}
-
-Window::~Window() {
- FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this));
- if (client_)
- client_->OnWindowDestroying(this);
-
- if (HasFocus()) {
- // The focused window is being removed. When this happens the server
- // advances focus. We don't want to randomly pick a Window to get focus, so
- // we update local state only, and wait for the next focus change from the
- // server.
- client_->LocalSetFocus(nullptr);
- }
-
- // Remove from transient parent.
- if (transient_parent_)
- transient_parent_->LocalRemoveTransientWindow(this);
-
- // Remove transient children.
- while (!transient_children_.empty()) {
- Window* transient_child = transient_children_.front();
- LocalRemoveTransientWindow(transient_child);
- transient_child->LocalDestroy();
- DCHECK(transient_children_.empty() ||
- transient_children_.front() != transient_child);
- }
-
- if (parent_)
- parent_->LocalRemoveChild(this);
-
- // We may still have children. This can happen if the embedder destroys the
- // root while we're still alive.
- while (!children_.empty()) {
- Window* child = children_.front();
- LocalRemoveChild(child);
- DCHECK(children_.empty() || children_.front() != child);
- }
-
- // Clear properties.
- for (auto& pair : prop_map_) {
- if (pair.second.deallocator)
- (*pair.second.deallocator)(pair.second.value);
- }
- prop_map_.clear();
-
- FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroyed(this));
-
- // Invoke after observers so that can clean up any internal state observers
- // may have changed.
- if (window_tree())
- window_tree()->OnWindowDestroyed(this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Window, private:
-
-Window::Window(WindowTreeClient* client, Id id)
- : client_(client),
- server_id_(id),
- parent_(nullptr),
- stacking_target_(nullptr),
- transient_parent_(nullptr),
- is_modal_(false),
- // Matches aura, see aura::Window for details.
- observers_(base::ObserverList<WindowObserver>::NOTIFY_EXISTING_ONLY),
- input_event_handler_(nullptr),
- visible_(false),
- opacity_(1.0f),
- display_id_(display::Display::kInvalidDisplayID),
- cursor_id_(mojom::Cursor::CURSOR_NULL),
- parent_drawn_(false) {}
-
-void Window::SetSharedPropertyInternal(const std::string& name,
- const std::vector<uint8_t>* value) {
- if (!OwnsWindowOrIsRoot(this))
- return;
-
- if (client_) {
- mojo::Array<uint8_t> transport_value(nullptr);
- if (value) {
- transport_value.resize(value->size());
- if (value->size())
- memcpy(&transport_value.front(), &(value->front()), value->size());
- }
- // TODO: add test coverage of this (450303).
- client_->SetProperty(this, name, std::move(transport_value));
- }
- LocalSetSharedProperty(name, value);
-}
-
-int64_t Window::SetLocalPropertyInternal(const void* key,
- const char* name,
- PropertyDeallocator deallocator,
- int64_t value,
- int64_t default_value) {
- int64_t old = GetLocalPropertyInternal(key, default_value);
- if (value == default_value) {
- prop_map_.erase(key);
- } else {
- Value prop_value;
- prop_value.name = name;
- prop_value.value = value;
- prop_value.deallocator = deallocator;
- prop_map_[key] = prop_value;
- }
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnWindowLocalPropertyChanged(this, key, old));
- return old;
-}
-
-int64_t Window::GetLocalPropertyInternal(const void* key,
- int64_t default_value) const {
- std::map<const void*, Value>::const_iterator iter = prop_map_.find(key);
- if (iter == prop_map_.end())
- return default_value;
- return iter->second.value;
-}
-
-void Window::LocalDestroy() {
- delete this;
-}
-
-void Window::LocalAddChild(Window* child) {
- ScopedTreeNotifier notifier(child, child->parent(), this);
- if (child->parent())
- RemoveChildImpl(child, &child->parent_->children_);
- children_.push_back(child);
- child->parent_ = this;
- child->display_id_ = display_id_;
-}
-
-void Window::LocalRemoveChild(Window* child) {
- DCHECK_EQ(this, child->parent());
- ScopedTreeNotifier notifier(child, this, nullptr);
- RemoveChildImpl(child, &children_);
-}
-
-void Window::LocalAddTransientWindow(Window* transient_window) {
- if (transient_window->transient_parent())
- RemoveTransientWindowImpl(transient_window);
- transient_children_.push_back(transient_window);
- transient_window->transient_parent_ = this;
-
- // Restack |transient_window| properly above its transient parent, if they
- // share the same parent.
- if (transient_window->parent() == parent())
- RestackTransientDescendants(this, &GetStackingTarget,
- &ReorderWithoutNotification);
-
- // TODO(fsamuel): We might want a notification here.
-}
-
-void Window::LocalRemoveTransientWindow(Window* transient_window) {
- DCHECK_EQ(this, transient_window->transient_parent());
- RemoveTransientWindowImpl(transient_window);
- // TODO(fsamuel): We might want a notification here.
-}
-
-void Window::LocalSetModal() {
- is_modal_ = true;
-}
-
-bool Window::LocalReorder(Window* relative, mojom::OrderDirection direction) {
- OrderChangedNotifier notifier(this, relative, direction);
- return ReorderImpl(this, relative, direction, &notifier);
-}
-
-void Window::LocalSetBounds(const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- // If this client owns the window, then it should be the only one to change
- // the bounds.
- DCHECK(!OwnsWindow(client_, this) || old_bounds == bounds_);
- ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds);
- bounds_ = new_bounds;
-}
-
-void Window::LocalSetClientArea(
- const gfx::Insets& new_client_area,
- const std::vector<gfx::Rect>& additional_client_areas) {
- const std::vector<gfx::Rect> old_additional_client_areas =
- additional_client_areas_;
- const gfx::Insets old_client_area = client_area_;
- client_area_ = new_client_area;
- additional_client_areas_ = additional_client_areas;
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnWindowClientAreaChanged(this, old_client_area,
- old_additional_client_areas));
-}
-
-void Window::LocalSetDisplay(int64_t display_id) {
- display_id_ = display_id;
- // TODO(sad): Notify observers (of this window, and of the descendant windows)
- // when a window moves from one display into another. https://crbug.com/614887
-}
-
-void Window::LocalSetParentDrawn(bool value) {
- if (parent_drawn_ == value)
- return;
-
- // As IsDrawn() is derived from |visible_| and |parent_drawn_|, only send
- // drawn notification is the value of IsDrawn() is really changing.
- if (IsDrawn() == value) {
- parent_drawn_ = value;
- return;
- }
- FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDrawnChanging(this));
- parent_drawn_ = value;
- FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDrawnChanged(this));
-}
-
-void Window::LocalSetVisible(bool visible) {
- if (visible_ == visible)
- return;
-
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnWindowVisibilityChanging(this));
- visible_ = visible;
- NotifyWindowVisibilityChanged(this);
-}
-
-void Window::LocalSetOpacity(float opacity) {
- if (opacity_ == opacity)
- return;
-
- float old_opacity = opacity_;
- opacity_ = opacity;
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnWindowOpacityChanged(this, old_opacity, opacity_));
-}
-
-void Window::LocalSetPredefinedCursor(mojom::Cursor cursor_id) {
- if (cursor_id_ == cursor_id)
- return;
-
- cursor_id_ = cursor_id;
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnWindowPredefinedCursorChanged(this, cursor_id));
-}
-
-void Window::LocalSetSharedProperty(const std::string& name,
- const std::vector<uint8_t>* value) {
- std::vector<uint8_t> old_value;
- std::vector<uint8_t>* old_value_ptr = nullptr;
- auto it = properties_.find(name);
- if (it != properties_.end()) {
- old_value = it->second;
- old_value_ptr = &old_value;
-
- if (value && old_value == *value)
- return;
- } else if (!value) {
- // This property isn't set in |properties_| and |value| is nullptr, so
- // there's no change.
- return;
- }
-
- if (value) {
- properties_[name] = *value;
- } else if (it != properties_.end()) {
- properties_.erase(it);
- }
-
- FOR_EACH_OBSERVER(
- WindowObserver, observers_,
- OnWindowSharedPropertyChanged(this, name, old_value_ptr, value));
-}
-
-void Window::NotifyWindowStackingChanged() {
- if (stacking_target_) {
- Children::const_iterator window_i = std::find(
- parent()->children().begin(), parent()->children().end(), this);
- DCHECK(window_i != parent()->children().end());
- if (window_i != parent()->children().begin() &&
- (*(window_i - 1) == stacking_target_))
- return;
- }
- RestackTransientDescendants(this, &GetStackingTarget,
- &ReorderWithoutNotification);
-}
-
-void Window::NotifyWindowVisibilityChanged(Window* target) {
- if (!NotifyWindowVisibilityChangedDown(target)) {
- return; // |this| has been deleted.
- }
- NotifyWindowVisibilityChangedUp(target);
-}
-
-bool Window::NotifyWindowVisibilityChangedAtReceiver(Window* target) {
- // |this| may be deleted during a call to OnWindowVisibilityChanged() on one
- // of the observers. We create an local observer for that. In that case we
- // exit without further access to any members.
- WindowTracker tracker;
- tracker.Add(this);
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnWindowVisibilityChanged(target));
- return tracker.Contains(this);
-}
-
-bool Window::NotifyWindowVisibilityChangedDown(Window* target) {
- if (!NotifyWindowVisibilityChangedAtReceiver(target))
- return false; // |this| was deleted.
- std::set<const Window*> child_already_processed;
- bool child_destroyed = false;
- do {
- child_destroyed = false;
- for (Window::Children::const_iterator it = children_.begin();
- it != children_.end(); ++it) {
- if (!child_already_processed.insert(*it).second)
- continue;
- if (!(*it)->NotifyWindowVisibilityChangedDown(target)) {
- // |*it| was deleted, |it| is invalid and |children_| has changed. We
- // exit the current for-loop and enter a new one.
- child_destroyed = true;
- break;
- }
- }
- } while (child_destroyed);
- return true;
-}
-
-void Window::NotifyWindowVisibilityChangedUp(Window* target) {
- // Start with the parent as we already notified |this|
- // in NotifyWindowVisibilityChangedDown.
- for (Window* window = parent(); window; window = window->parent()) {
- bool ret = window->NotifyWindowVisibilityChangedAtReceiver(target);
- DCHECK(ret);
- }
-}
-
-bool Window::PrepareForEmbed() {
- if (!OwnsWindow(client_, this))
- return false;
-
- while (!children_.empty())
- RemoveChild(children_[0]);
- return true;
-}
-
-void Window::RemoveTransientWindowImpl(Window* transient_window) {
- Window::Children::iterator it = std::find(
- transient_children_.begin(), transient_children_.end(), transient_window);
- if (it != transient_children_.end()) {
- transient_children_.erase(it);
- transient_window->transient_parent_ = nullptr;
- }
- // If |transient_window| and its former transient parent share the same
- // parent, |transient_window| should be restacked properly so it is not among
- // transient children of its former parent, anymore.
- if (parent() == transient_window->parent())
- RestackTransientDescendants(this, &GetStackingTarget,
- &ReorderWithoutNotification);
-
- // TOOD(fsamuel): We might want to notify observers here.
-}
-
-// static
-void Window::ReorderWithoutNotification(Window* window,
- Window* relative,
- mojom::OrderDirection direction) {
- ReorderImpl(window, relative, direction, nullptr);
-}
-
-// static
-// Returns true if the order actually changed.
-bool Window::ReorderImpl(Window* window,
- Window* relative,
- mojom::OrderDirection direction,
- OrderChangedNotifier* notifier) {
- DCHECK(relative);
- DCHECK_NE(window, relative);
- DCHECK_EQ(window->parent(), relative->parent());
- DCHECK(window->parent());
-
- if (!AdjustStackingForTransientWindows(&window, &relative, &direction,
- window->stacking_target_))
- return false;
-
- const size_t child_i = std::find(window->parent_->children_.begin(),
- window->parent_->children_.end(), window) -
- window->parent_->children_.begin();
- const size_t target_i =
- std::find(window->parent_->children_.begin(),
- window->parent_->children_.end(), relative) -
- window->parent_->children_.begin();
- if ((direction == mojom::OrderDirection::ABOVE && child_i == target_i + 1) ||
- (direction == mojom::OrderDirection::BELOW && child_i + 1 == target_i)) {
- return false;
- }
-
- if (notifier)
- notifier->NotifyWindowReordering();
-
- const size_t dest_i = direction == mojom::OrderDirection::ABOVE
- ? (child_i < target_i ? target_i : target_i + 1)
- : (child_i < target_i ? target_i - 1 : target_i);
- window->parent_->children_.erase(window->parent_->children_.begin() +
- child_i);
- window->parent_->children_.insert(window->parent_->children_.begin() + dest_i,
- window);
-
- window->NotifyWindowStackingChanged();
-
- if (notifier)
- notifier->NotifyWindowReordered();
-
- return true;
-}
-
-// static
-Window** Window::GetStackingTarget(Window* window) {
- return &window->stacking_target_;
-}
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_observer.cc b/chromium/components/mus/public/cpp/lib/window_observer.cc
deleted file mode 100644
index 26e65078f77..00000000000
--- a/chromium/components/mus/public/cpp/lib/window_observer.cc
+++ /dev/null
@@ -1,18 +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 "components/mus/public/cpp/window_observer.h"
-
-namespace mus {
-
-////////////////////////////////////////////////////////////////////////////////
-// WindowObserver, public:
-
-WindowObserver::TreeChangeParams::TreeChangeParams()
- : target(nullptr),
- old_parent(nullptr),
- new_parent(nullptr),
- receiver(nullptr) {}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_private.cc b/chromium/components/mus/public/cpp/lib/window_private.cc
deleted file mode 100644
index 11c7ebeefae..00000000000
--- a/chromium/components/mus/public/cpp/lib/window_private.cc
+++ /dev/null
@@ -1,31 +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 "components/mus/public/cpp/lib/window_private.h"
-
-namespace mus {
-
-WindowPrivate::WindowPrivate(Window* window) : window_(window) {
- CHECK(window);
-}
-
-WindowPrivate::~WindowPrivate() {}
-
-// static
-Window* WindowPrivate::LocalCreate() {
- return new Window;
-}
-
-void WindowPrivate::LocalSetSharedProperty(const std::string& name,
- mojo::Array<uint8_t> new_data) {
- std::vector<uint8_t> data;
- std::vector<uint8_t>* data_ptr = nullptr;
- if (!new_data.is_null()) {
- data = new_data.To<std::vector<uint8_t>>();
- data_ptr = &data;
- }
- LocalSetSharedProperty(name, data_ptr);
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_private.h b/chromium/components/mus/public/cpp/lib/window_private.h
deleted file mode 100644
index 4b2640e8b37..00000000000
--- a/chromium/components/mus/public/cpp/lib/window_private.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/macros.h"
-#include "components/mus/public/cpp/window.h"
-#include "mojo/public/cpp/bindings/array.h"
-
-namespace mus {
-
-// This class is a friend of a Window and contains functions to mutate internal
-// state of Window.
-class WindowPrivate {
- public:
- explicit WindowPrivate(Window* window);
- ~WindowPrivate();
-
- // Creates and returns a new Window. Caller owns the return value.
- static Window* LocalCreate();
-
- base::ObserverList<WindowObserver>* observers() {
- return &window_->observers_;
- }
-
- void ClearParent() { window_->parent_ = nullptr; }
-
- void ClearTransientParent() { window_->transient_parent_ = nullptr; }
-
- void set_visible(bool visible) { window_->visible_ = visible; }
-
- void set_parent_drawn(bool drawn) { window_->parent_drawn_ = drawn; }
- bool parent_drawn() { return window_->parent_drawn_; }
-
- void set_server_id(Id id) { window_->server_id_ = id; }
- Id server_id() { return window_->server_id_; }
-
- void set_client(WindowTreeClient* client) {
- window_->client_ = client;
- }
-
- void set_properties(const std::map<std::string, std::vector<uint8_t>>& data) {
- window_->properties_ = data;
- }
-
- void LocalSetDisplay(int64_t new_display) {
- window_->LocalSetDisplay(new_display);
- }
-
- void LocalDestroy() { window_->LocalDestroy(); }
- void LocalAddChild(Window* child) { window_->LocalAddChild(child); }
- void LocalRemoveChild(Window* child) { window_->LocalRemoveChild(child); }
- void LocalAddTransientWindow(Window* child) {
- window_->LocalAddTransientWindow(child);
- }
- void LocalRemoveTransientWindow(Window* child) {
- window_->LocalRemoveTransientWindow(child);
- }
- void LocalUnsetModal() { window_->is_modal_ = false; }
- void LocalReorder(Window* relative, mojom::OrderDirection direction) {
- window_->LocalReorder(relative, direction);
- }
- void LocalSetBounds(const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- window_->LocalSetBounds(old_bounds, new_bounds);
- }
- void LocalSetClientArea(
- const gfx::Insets& client_area,
- const std::vector<gfx::Rect>& additional_client_areas) {
- window_->LocalSetClientArea(client_area, additional_client_areas);
- }
- void LocalSetParentDrawn(bool drawn) { window_->LocalSetParentDrawn(drawn); }
- void LocalSetVisible(bool visible) { window_->LocalSetVisible(visible); }
- void LocalSetOpacity(float opacity) { window_->LocalSetOpacity(opacity); }
- void LocalSetPredefinedCursor(mojom::Cursor cursor) {
- window_->LocalSetPredefinedCursor(cursor);
- }
- void LocalSetSharedProperty(const std::string& name,
- mojo::Array<uint8_t> new_data);
- void LocalSetSharedProperty(const std::string& name,
- const std::vector<uint8_t>* data) {
- window_->LocalSetSharedProperty(name, data);
- }
- void NotifyWindowStackingChanged() { window_->NotifyWindowStackingChanged(); }
-
- private:
- Window* window_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowPrivate);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_PRIVATE_H_
diff --git a/chromium/components/mus/public/cpp/lib/window_surface.cc b/chromium/components/mus/public/cpp/lib/window_surface.cc
deleted file mode 100644
index 1f0b840a102..00000000000
--- a/chromium/components/mus/public/cpp/lib/window_surface.cc
+++ /dev/null
@@ -1,69 +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 "components/mus/public/cpp/window_surface.h"
-
-#include "base/memory/ptr_util.h"
-#include "components/mus/public/cpp/window_surface_client.h"
-
-namespace mus {
-
-// static
-std::unique_ptr<WindowSurface> WindowSurface::Create(
- std::unique_ptr<WindowSurfaceBinding>* surface_binding) {
- mojom::SurfacePtr surface;
- mojom::SurfaceClientPtr surface_client;
- mojo::InterfaceRequest<mojom::SurfaceClient> surface_client_request =
- GetProxy(&surface_client);
-
- surface_binding->reset(new WindowSurfaceBinding(
- GetProxy(&surface), surface_client.PassInterface()));
- return base::WrapUnique(new WindowSurface(surface.PassInterface(),
- std::move(surface_client_request)));
-}
-
-WindowSurface::~WindowSurface() {}
-
-void WindowSurface::BindToThread() {
- DCHECK(!thread_checker_);
- thread_checker_.reset(new base::ThreadChecker());
- surface_.Bind(std::move(surface_info_));
- client_binding_.reset(new mojo::Binding<mojom::SurfaceClient>(
- this, std::move(client_request_)));
-}
-
-void WindowSurface::SubmitCompositorFrame(cc::CompositorFrame frame,
- const base::Closure& callback) {
- DCHECK(thread_checker_);
- DCHECK(thread_checker_->CalledOnValidThread());
- if (!surface_)
- return;
- surface_->SubmitCompositorFrame(std::move(frame), callback);
-}
-
-WindowSurface::WindowSurface(
- mojo::InterfacePtrInfo<mojom::Surface> surface_info,
- mojo::InterfaceRequest<mojom::SurfaceClient> client_request)
- : client_(nullptr),
- surface_info_(std::move(surface_info)),
- client_request_(std::move(client_request)) {}
-
-void WindowSurface::ReturnResources(
- mojo::Array<cc::ReturnedResource> resources) {
- DCHECK(thread_checker_);
- DCHECK(thread_checker_->CalledOnValidThread());
- if (!client_)
- return;
- client_->OnResourcesReturned(this, std::move(resources));
-}
-
-WindowSurfaceBinding::~WindowSurfaceBinding() {}
-
-WindowSurfaceBinding::WindowSurfaceBinding(
- mojo::InterfaceRequest<mojom::Surface> surface_request,
- mojo::InterfacePtrInfo<mojom::SurfaceClient> surface_client)
- : surface_request_(std::move(surface_request)),
- surface_client_(std::move(surface_client)) {}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_tree_client.cc b/chromium/components/mus/public/cpp/lib/window_tree_client.cc
deleted file mode 100644
index 7a43101ff6a..00000000000
--- a/chromium/components/mus/public/cpp/lib/window_tree_client.cc
+++ /dev/null
@@ -1,1181 +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 "components/mus/public/cpp/window_tree_client.h"
-
-#include <stddef.h>
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "components/mus/common/util.h"
-#include "components/mus/public/cpp/input_event_handler.h"
-#include "components/mus/public/cpp/lib/in_flight_change.h"
-#include "components/mus/public/cpp/lib/window_private.h"
-#include "components/mus/public/cpp/window_manager_delegate.h"
-#include "components/mus/public/cpp/window_observer.h"
-#include "components/mus/public/cpp/window_tracker.h"
-#include "components/mus/public/cpp/window_tree_client_delegate.h"
-#include "components/mus/public/cpp/window_tree_client_observer.h"
-#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
-#include "services/shell/public/cpp/connector.h"
-#include "ui/display/mojo/display_type_converters.h"
-#include "ui/events/event.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace mus {
-
-void DeleteWindowTreeClient(WindowTreeClient* client) { delete client; }
-
-Id MakeTransportId(ClientSpecificId client_id, ClientSpecificId local_id) {
- return (client_id << 16) | local_id;
-}
-
-Id server_id(Window* window) {
- return WindowPrivate(window).server_id();
-}
-
-// Helper called to construct a local window object from transport data.
-Window* AddWindowToClient(WindowTreeClient* client,
- Window* parent,
- const mojom::WindowDataPtr& window_data) {
- // We don't use the ctor that takes a WindowTreeClient here, since it will
- // call back to the service and attempt to create a new window.
- Window* window = WindowPrivate::LocalCreate();
- WindowPrivate private_window(window);
- private_window.set_client(client);
- private_window.set_server_id(window_data->window_id);
- private_window.set_visible(window_data->visible);
- private_window.set_properties(
- window_data->properties
- .To<std::map<std::string, std::vector<uint8_t>>>());
- client->AddWindow(window);
- private_window.LocalSetBounds(gfx::Rect(), window_data->bounds);
- if (parent)
- WindowPrivate(parent).LocalAddChild(window);
- return window;
-}
-
-Window* BuildWindowTree(WindowTreeClient* client,
- const mojo::Array<mojom::WindowDataPtr>& windows,
- Window* initial_parent) {
- std::vector<Window*> parents;
- Window* root = NULL;
- Window* last_window = NULL;
- if (initial_parent)
- parents.push_back(initial_parent);
- for (size_t i = 0; i < windows.size(); ++i) {
- if (last_window && windows[i]->parent_id == server_id(last_window)) {
- parents.push_back(last_window);
- } else if (!parents.empty()) {
- while (server_id(parents.back()) != windows[i]->parent_id)
- parents.pop_back();
- }
- Window* window = AddWindowToClient(
- client, !parents.empty() ? parents.back() : NULL, windows[i]);
- if (!last_window)
- root = window;
- last_window = window;
- }
- return root;
-}
-
-WindowTreeClient::WindowTreeClient(
- WindowTreeClientDelegate* delegate,
- WindowManagerDelegate* window_manager_delegate,
- mojo::InterfaceRequest<mojom::WindowTreeClient> request)
- : client_id_(0),
- next_window_id_(1),
- next_change_id_(1),
- delegate_(delegate),
- window_manager_delegate_(window_manager_delegate),
- capture_window_(nullptr),
- focused_window_(nullptr),
- binding_(this),
- tree_(nullptr),
- delete_on_no_roots_(!window_manager_delegate),
- in_destructor_(false),
- weak_factory_(this) {
- // Allow for a null request in tests.
- if (request.is_pending())
- binding_.Bind(std::move(request));
- if (window_manager_delegate)
- window_manager_delegate->SetWindowManagerClient(this);
-}
-
-WindowTreeClient::~WindowTreeClient() {
- in_destructor_ = true;
-
- std::vector<Window*> non_owned;
- WindowTracker tracker;
- while (!windows_.empty()) {
- IdToWindowMap::iterator it = windows_.begin();
- if (OwnsWindow(it->second)) {
- it->second->Destroy();
- } else {
- tracker.Add(it->second);
- windows_.erase(it);
- }
- }
-
- // Delete the non-owned windows last. In the typical case these are roots. The
- // exception is the window manager and embed roots, which may know about
- // other random windows that it doesn't own.
- // NOTE: we manually delete as we're a friend.
- while (!tracker.windows().empty())
- delete tracker.windows().front();
-
- FOR_EACH_OBSERVER(WindowTreeClientObserver, observers_,
- OnWillDestroyClient(this));
-
- delegate_->OnWindowTreeClientDestroyed(this);
-}
-
-void WindowTreeClient::ConnectViaWindowTreeFactory(
- shell::Connector* connector) {
- // Clients created with no root shouldn't delete automatically.
- delete_on_no_roots_ = false;
-
- // The client id doesn't really matter, we use 101 purely for debugging.
- client_id_ = 101;
-
- mojom::WindowTreeFactoryPtr factory;
- connector->ConnectToInterface("mojo:mus", &factory);
- mojom::WindowTreePtr window_tree;
- factory->CreateWindowTree(GetProxy(&window_tree),
- binding_.CreateInterfacePtrAndBind());
- SetWindowTree(std::move(window_tree));
-}
-
-void WindowTreeClient::ConnectAsWindowManager(shell::Connector* connector) {
- DCHECK(window_manager_delegate_);
-
- mojom::WindowManagerWindowTreeFactoryPtr factory;
- connector->ConnectToInterface("mojo:mus", &factory);
- mojom::WindowTreePtr window_tree;
- factory->CreateWindowTree(GetProxy(&window_tree),
- binding_.CreateInterfacePtrAndBind());
- SetWindowTree(std::move(window_tree));
-}
-
-void WindowTreeClient::WaitForEmbed() {
- DCHECK(roots_.empty());
- // OnEmbed() is the first function called.
- binding_.WaitForIncomingMethodCall();
- // TODO(sky): deal with pipe being closed before we get OnEmbed().
-}
-
-void WindowTreeClient::DestroyWindow(Window* window) {
- DCHECK(tree_);
- const uint32_t change_id = ScheduleInFlightChange(base::WrapUnique(
- new CrashInFlightChange(window, ChangeType::DELETE_WINDOW)));
- tree_->DeleteWindow(change_id, server_id(window));
-}
-
-void WindowTreeClient::AddChild(Window* parent, Id child_id) {
- DCHECK(tree_);
- const uint32_t change_id = ScheduleInFlightChange(
- base::WrapUnique(new CrashInFlightChange(parent, ChangeType::ADD_CHILD)));
- tree_->AddWindow(change_id, parent->server_id(), child_id);
-}
-
-void WindowTreeClient::RemoveChild(Window* parent, Id child_id) {
- DCHECK(tree_);
- const uint32_t change_id = ScheduleInFlightChange(base::WrapUnique(
- new CrashInFlightChange(parent, ChangeType::REMOVE_CHILD)));
- tree_->RemoveWindowFromParent(change_id, child_id);
-}
-
-void WindowTreeClient::AddTransientWindow(Window* window,
- Id transient_window_id) {
- DCHECK(tree_);
- const uint32_t change_id = ScheduleInFlightChange(base::WrapUnique(
- new CrashInFlightChange(window, ChangeType::ADD_TRANSIENT_WINDOW)));
- tree_->AddTransientWindow(change_id, server_id(window), transient_window_id);
-}
-
-void WindowTreeClient::RemoveTransientWindowFromParent(Window* window) {
- DCHECK(tree_);
- const uint32_t change_id =
- ScheduleInFlightChange(base::WrapUnique(new CrashInFlightChange(
- window, ChangeType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT)));
- tree_->RemoveTransientWindowFromParent(change_id, server_id(window));
-}
-
-void WindowTreeClient::SetModal(Window* window) {
- DCHECK(tree_);
- const uint32_t change_id = ScheduleInFlightChange(
- base::WrapUnique(new InFlightSetModalChange(window)));
- tree_->SetModal(change_id, server_id(window));
-}
-
-void WindowTreeClient::Reorder(Window* window,
- Id relative_window_id,
- mojom::OrderDirection direction) {
- DCHECK(tree_);
- const uint32_t change_id = ScheduleInFlightChange(
- base::WrapUnique(new CrashInFlightChange(window, ChangeType::REORDER)));
- tree_->ReorderWindow(change_id, server_id(window), relative_window_id,
- direction);
-}
-
-bool WindowTreeClient::OwnsWindow(Window* window) const {
- // Windows created via CreateTopLevelWindow() are not owned by us, but have
- // our client id.
- return HiWord(server_id(window)) == client_id_ &&
- roots_.count(window) == 0;
-}
-
-void WindowTreeClient::SetBounds(Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& bounds) {
- DCHECK(tree_);
- const uint32_t change_id = ScheduleInFlightChange(
- base::WrapUnique(new InFlightBoundsChange(window, old_bounds)));
- tree_->SetWindowBounds(change_id, server_id(window), bounds);
-}
-
-void WindowTreeClient::SetCapture(Window* window) {
- // In order for us to get here we had to have exposed a window, which implies
- // we got a client.
- DCHECK(tree_);
- if (capture_window_ == window)
- return;
- const uint32_t change_id = ScheduleInFlightChange(
- base::WrapUnique(new InFlightCaptureChange(this, capture_window_)));
- tree_->SetCapture(change_id, server_id(window));
- LocalSetCapture(window);
-}
-
-void WindowTreeClient::ReleaseCapture(Window* window) {
- // In order for us to get here we had to have exposed a window, which implies
- // we got a client.
- DCHECK(tree_);
- if (capture_window_ != window)
- return;
- const uint32_t change_id = ScheduleInFlightChange(
- base::WrapUnique(new InFlightCaptureChange(this, window)));
- tree_->ReleaseCapture(change_id, server_id(window));
- LocalSetCapture(nullptr);
-}
-
-void WindowTreeClient::SetClientArea(
- Id window_id,
- const gfx::Insets& client_area,
- const std::vector<gfx::Rect>& additional_client_areas) {
- DCHECK(tree_);
- tree_->SetClientArea(window_id, client_area, additional_client_areas);
-}
-
-void WindowTreeClient::SetHitTestMask(Id window_id, const gfx::Rect& mask) {
- DCHECK(tree_);
- tree_->SetHitTestMask(window_id, mask);
-}
-
-void WindowTreeClient::ClearHitTestMask(Id window_id) {
- DCHECK(tree_);
- tree_->SetHitTestMask(window_id, {});
-}
-
-void WindowTreeClient::SetFocus(Window* window) {
- // In order for us to get here we had to have exposed a window, which implies
- // we got a client.
- DCHECK(tree_);
- const uint32_t change_id = ScheduleInFlightChange(
- base::WrapUnique(new InFlightFocusChange(this, focused_window_)));
- tree_->SetFocus(change_id, window ? server_id(window) : 0);
- LocalSetFocus(window);
-}
-
-void WindowTreeClient::SetCanFocus(Id window_id, bool can_focus) {
- DCHECK(tree_);
- tree_->SetCanFocus(window_id, can_focus);
-}
-
-void WindowTreeClient::SetPredefinedCursor(Id window_id,
- mus::mojom::Cursor cursor_id) {
- DCHECK(tree_);
-
- Window* window = GetWindowByServerId(window_id);
- if (!window)
- return;
-
- // We make an inflight change thing here.
- const uint32_t change_id = ScheduleInFlightChange(base::WrapUnique(
- new InFlightPredefinedCursorChange(window, window->predefined_cursor())));
- tree_->SetPredefinedCursor(change_id, window_id, cursor_id);
-}
-
-void WindowTreeClient::SetVisible(Window* window, bool visible) {
- DCHECK(tree_);
- const uint32_t change_id = ScheduleInFlightChange(
- base::WrapUnique(new InFlightVisibleChange(window, !visible)));
- tree_->SetWindowVisibility(change_id, server_id(window), visible);
-}
-
-void WindowTreeClient::SetOpacity(Window* window, float opacity) {
- DCHECK(tree_);
- const uint32_t change_id = ScheduleInFlightChange(
- base::WrapUnique(new InFlightOpacityChange(window, window->opacity())));
- tree_->SetWindowOpacity(change_id, server_id(window), opacity);
-}
-
-void WindowTreeClient::SetProperty(Window* window,
- const std::string& name,
- mojo::Array<uint8_t> data) {
- DCHECK(tree_);
-
- mojo::Array<uint8_t> old_value(nullptr);
- if (window->HasSharedProperty(name))
- old_value = mojo::Array<uint8_t>::From(window->properties_[name]);
-
- const uint32_t change_id = ScheduleInFlightChange(
- base::WrapUnique(new InFlightPropertyChange(window, name, old_value)));
- tree_->SetWindowProperty(change_id, server_id(window), mojo::String(name),
- std::move(data));
-}
-
-void WindowTreeClient::SetWindowTextInputState(
- Id window_id,
- mojo::TextInputStatePtr state) {
- DCHECK(tree_);
- tree_->SetWindowTextInputState(window_id, std::move(state));
-}
-
-void WindowTreeClient::SetImeVisibility(Id window_id,
- bool visible,
- mojo::TextInputStatePtr state) {
- DCHECK(tree_);
- tree_->SetImeVisibility(window_id, visible, std::move(state));
-}
-
-void WindowTreeClient::Embed(Id window_id,
- mojom::WindowTreeClientPtr client,
- uint32_t flags,
- const mojom::WindowTree::EmbedCallback& callback) {
- DCHECK(tree_);
- tree_->Embed(window_id, std::move(client), flags, callback);
-}
-
-void WindowTreeClient::RequestClose(Window* window) {
- if (window_manager_internal_client_)
- window_manager_internal_client_->WmRequestClose(server_id(window));
-}
-
-void WindowTreeClient::AttachSurface(
- Id window_id,
- mojom::SurfaceType type,
- mojo::InterfaceRequest<mojom::Surface> surface,
- mojom::SurfaceClientPtr client) {
- DCHECK(tree_);
- tree_->AttachSurface(window_id, type, std::move(surface), std::move(client));
-}
-
-void WindowTreeClient::LocalSetCapture(Window* window) {
- if (capture_window_ == window)
- return;
- Window* lost_capture = capture_window_;
- capture_window_ = window;
- if (lost_capture) {
- FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(lost_capture).observers(),
- OnWindowLostCapture(lost_capture));
- }
-}
-
-void WindowTreeClient::LocalSetFocus(Window* focused) {
- Window* blurred = focused_window_;
- // Update |focused_window_| before calling any of the observers, so that the
- // observers get the correct result from calling |Window::HasFocus()|,
- // |WindowTreeClient::GetFocusedWindow()| etc.
- focused_window_ = focused;
- if (blurred) {
- FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(blurred).observers(),
- OnWindowFocusChanged(focused, blurred));
- }
- if (focused) {
- FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(focused).observers(),
- OnWindowFocusChanged(focused, blurred));
- }
- FOR_EACH_OBSERVER(WindowTreeClientObserver, observers_,
- OnWindowTreeFocusChanged(focused, blurred));
-}
-
-void WindowTreeClient::AddWindow(Window* window) {
- DCHECK(windows_.find(server_id(window)) == windows_.end());
- windows_[server_id(window)] = window;
-}
-
-void WindowTreeClient::OnWindowDestroying(Window* window) {
- if (window == capture_window_) {
- // Normally the queue updates itself upon window destruction. However since
- // |window| is being destroyed, it will not be possible to notify its
- // observers of the lost capture. Update local state now.
- LocalSetCapture(nullptr);
- }
- // For |focused_window_| window destruction clears the entire focus state.
-}
-
-void WindowTreeClient::OnWindowDestroyed(Window* window) {
- windows_.erase(server_id(window));
-
- for (auto& entry : embedded_windows_) {
- auto it = entry.second.find(window);
- if (it != entry.second.end()) {
- entry.second.erase(it);
- break;
- }
- }
-
- // Remove any InFlightChanges associated with the window.
- std::set<uint32_t> in_flight_change_ids_to_remove;
- for (const auto& pair : in_flight_map_) {
- if (pair.second->window() == window)
- in_flight_change_ids_to_remove.insert(pair.first);
- }
- for (auto change_id : in_flight_change_ids_to_remove)
- in_flight_map_.erase(change_id);
-
- if (roots_.erase(window) > 0 && roots_.empty() && delete_on_no_roots_ &&
- !in_destructor_) {
- delete this;
- }
-}
-
-Window* WindowTreeClient::GetWindowByServerId(Id id) {
- IdToWindowMap::const_iterator it = windows_.find(id);
- return it != windows_.end() ? it->second : NULL;
-}
-
-InFlightChange* WindowTreeClient::GetOldestInFlightChangeMatching(
- const InFlightChange& change) {
- for (const auto& pair : in_flight_map_) {
- if (pair.second->window() == change.window() &&
- pair.second->change_type() == change.change_type() &&
- pair.second->Matches(change)) {
- return pair.second.get();
- }
- }
- return nullptr;
-}
-
-uint32_t WindowTreeClient::ScheduleInFlightChange(
- std::unique_ptr<InFlightChange> change) {
- DCHECK(!change->window() ||
- windows_.count(change->window()->server_id()) > 0);
- const uint32_t change_id = next_change_id_++;
- in_flight_map_[change_id] = std::move(change);
- return change_id;
-}
-
-bool WindowTreeClient::ApplyServerChangeToExistingInFlightChange(
- const InFlightChange& change) {
- InFlightChange* existing_change = GetOldestInFlightChangeMatching(change);
- if (!existing_change)
- return false;
-
- existing_change->SetRevertValueFrom(change);
- return true;
-}
-
-Window* WindowTreeClient::NewWindowImpl(
- NewWindowType type,
- const Window::SharedProperties* properties) {
- DCHECK(tree_);
- Window* window =
- new Window(this, MakeTransportId(client_id_, next_window_id_++));
- if (properties)
- window->properties_ = *properties;
- AddWindow(window);
-
- const uint32_t change_id = ScheduleInFlightChange(base::WrapUnique(
- new CrashInFlightChange(window, type == NewWindowType::CHILD
- ? ChangeType::NEW_WINDOW
- : ChangeType::NEW_TOP_LEVEL_WINDOW)));
- mojo::Map<mojo::String, mojo::Array<uint8_t>> transport_properties;
- if (properties) {
- transport_properties =
- mojo::Map<mojo::String, mojo::Array<uint8_t>>::From(*properties);
- }
- if (type == NewWindowType::CHILD) {
- tree_->NewWindow(change_id, server_id(window),
- std::move(transport_properties));
- } else {
- roots_.insert(window);
- tree_->NewTopLevelWindow(change_id, server_id(window),
- std::move(transport_properties));
- }
- return window;
-}
-
-void WindowTreeClient::SetWindowTree(mojom::WindowTreePtr window_tree_ptr) {
- tree_ptr_ = std::move(window_tree_ptr);
- tree_ = tree_ptr_.get();
-
- tree_ptr_->GetCursorLocationMemory(
- base::Bind(&WindowTreeClient::OnReceivedCursorLocationMemory,
- weak_factory_.GetWeakPtr()));
-
- tree_ptr_.set_connection_error_handler(base::Bind(
- &WindowTreeClient::OnConnectionLost, weak_factory_.GetWeakPtr()));
-
- if (window_manager_delegate_) {
- tree_ptr_->GetWindowManagerClient(GetProxy(&window_manager_internal_client_,
- tree_ptr_.associated_group()));
- }
-}
-
-void WindowTreeClient::OnConnectionLost() {
- delete this;
-}
-
-void WindowTreeClient::OnEmbedImpl(mojom::WindowTree* window_tree,
- ClientSpecificId client_id,
- mojom::WindowDataPtr root_data,
- int64_t display_id,
- Id focused_window_id,
- bool drawn) {
- // WARNING: this is only called if WindowTreeClient was created as the
- // result of an embedding.
- tree_ = window_tree;
- client_id_ = client_id;
-
- DCHECK(roots_.empty());
- Window* root = AddWindowToClient(this, nullptr, root_data);
- WindowPrivate(root).LocalSetDisplay(display_id);
- roots_.insert(root);
-
- focused_window_ = GetWindowByServerId(focused_window_id);
-
- WindowPrivate(root).LocalSetParentDrawn(drawn);
-
- delegate_->OnEmbed(root);
-
- if (focused_window_) {
- FOR_EACH_OBSERVER(WindowTreeClientObserver, observers_,
- OnWindowTreeFocusChanged(focused_window_, nullptr));
- }
-}
-
-void WindowTreeClient::WmNewDisplayAddedImpl(const display::Display& display,
- mojom::WindowDataPtr root_data,
- bool parent_drawn) {
- DCHECK(window_manager_delegate_);
-
- Window* root = AddWindowToClient(this, nullptr, root_data);
- WindowPrivate(root).LocalSetDisplay(display.id());
- WindowPrivate(root).LocalSetParentDrawn(parent_drawn);
- roots_.insert(root);
-
- window_manager_delegate_->OnWmNewDisplay(root, display);
-}
-
-void WindowTreeClient::OnReceivedCursorLocationMemory(
- mojo::ScopedSharedBufferHandle handle) {
- cursor_location_mapping_ = handle->Map(sizeof(base::subtle::Atomic32));
- DCHECK(cursor_location_mapping_);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WindowTreeClient, WindowTreeClient implementation:
-
-void WindowTreeClient::SetDeleteOnNoRoots(bool value) {
- delete_on_no_roots_ = value;
-}
-
-const std::set<Window*>& WindowTreeClient::GetRoots() {
- return roots_;
-}
-
-Window* WindowTreeClient::GetFocusedWindow() {
- return focused_window_;
-}
-
-void WindowTreeClient::ClearFocus() {
- if (!focused_window_)
- return;
-
- SetFocus(nullptr);
-}
-
-gfx::Point WindowTreeClient::GetCursorScreenPoint() {
- // We raced initialization. Return (0, 0).
- if (!cursor_location_memory())
- return gfx::Point();
-
- base::subtle::Atomic32 location =
- base::subtle::NoBarrier_Load(cursor_location_memory());
- return gfx::Point(static_cast<int16_t>(location >> 16),
- static_cast<int16_t>(location & 0xFFFF));
-}
-
-void WindowTreeClient::SetEventObserver(mojom::EventMatcherPtr matcher) {
- if (matcher.is_null()) {
- has_event_observer_ = false;
- tree_->SetEventObserver(nullptr, 0u);
- } else {
- has_event_observer_ = true;
- event_observer_id_++;
- tree_->SetEventObserver(std::move(matcher), event_observer_id_);
- }
-}
-
-Window* WindowTreeClient::NewWindow(
- const Window::SharedProperties* properties) {
- return NewWindowImpl(NewWindowType::CHILD, properties);
-}
-
-Window* WindowTreeClient::NewTopLevelWindow(
- const Window::SharedProperties* properties) {
- Window* window = NewWindowImpl(NewWindowType::TOP_LEVEL, properties);
- // Assume newly created top level windows are drawn by default, otherwise
- // requests to focus will fail. We will get the real value in
- // OnTopLevelCreated().
- window->LocalSetParentDrawn(true);
- return window;
-}
-
-#if !defined(NDEBUG)
-std::string WindowTreeClient::GetDebugWindowHierarchy() const {
- std::string result;
- for (Window* root : roots_)
- BuildDebugInfo(std::string(), root, &result);
- return result;
-}
-
-void WindowTreeClient::BuildDebugInfo(const std::string& depth,
- Window* window,
- std::string* result) const {
- std::string name = window->GetName();
- *result += base::StringPrintf(
- "%sid=%d visible=%s bounds=%d,%d %dx%d %s\n", depth.c_str(),
- window->server_id(), window->visible() ? "true" : "false",
- window->bounds().x(), window->bounds().y(), window->bounds().width(),
- window->bounds().height(), !name.empty() ? name.c_str() : "(no name)");
- for (Window* child : window->children())
- BuildDebugInfo(depth + " ", child, result);
-}
-#endif // !defined(NDEBUG)
-
-////////////////////////////////////////////////////////////////////////////////
-// WindowTreeClient, WindowTreeClient implementation:
-
-void WindowTreeClient::AddObserver(WindowTreeClientObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void WindowTreeClient::RemoveObserver(WindowTreeClientObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void WindowTreeClient::OnEmbed(ClientSpecificId client_id,
- mojom::WindowDataPtr root_data,
- mojom::WindowTreePtr tree,
- int64_t display_id,
- Id focused_window_id,
- bool drawn) {
- DCHECK(!tree_ptr_);
- tree_ptr_ = std::move(tree);
- tree_ptr_.set_connection_error_handler(
- base::Bind(&DeleteWindowTreeClient, this));
-
- if (window_manager_delegate_) {
- tree_ptr_->GetWindowManagerClient(GetProxy(&window_manager_internal_client_,
- tree_ptr_.associated_group()));
- }
-
- OnEmbedImpl(tree_ptr_.get(), client_id, std::move(root_data), display_id,
- focused_window_id, drawn);
-}
-
-void WindowTreeClient::OnEmbeddedAppDisconnected(Id window_id) {
- Window* window = GetWindowByServerId(window_id);
- if (window) {
- FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window).observers(),
- OnWindowEmbeddedAppDisconnected(window));
- }
-}
-
-void WindowTreeClient::OnUnembed(Id window_id) {
- Window* window = GetWindowByServerId(window_id);
- if (!window)
- return;
-
- delegate_->OnUnembed(window);
- WindowPrivate(window).LocalDestroy();
-}
-
-void WindowTreeClient::OnLostCapture(Id window_id) {
- Window* window = GetWindowByServerId(window_id);
- if (!window)
- return;
-
- InFlightCaptureChange reset_change(this, nullptr);
- if (ApplyServerChangeToExistingInFlightChange(reset_change))
- return;
-
- LocalSetCapture(nullptr);
-}
-
-void WindowTreeClient::OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr data,
- int64_t display_id,
- bool drawn) {
- // The server ack'd the top level window we created and supplied the state
- // of the window at the time the server created it. For properties we do not
- // have changes in flight for we can update them immediately. For properties
- // with changes in flight we set the revert value from the server.
-
- if (!in_flight_map_.count(change_id)) {
- // The window may have been destroyed locally before the server could finish
- // creating the window, and before the server received the notification that
- // the window has been destroyed.
- return;
- }
- std::unique_ptr<InFlightChange> change(std::move(in_flight_map_[change_id]));
- in_flight_map_.erase(change_id);
-
- Window* window = change->window();
- WindowPrivate window_private(window);
-
- // Drawn state and display-id always come from the server (they can't be
- // modified locally).
- window_private.LocalSetParentDrawn(drawn);
- window_private.LocalSetDisplay(display_id);
-
- // The default visibilty is false, we only need update visibility if it
- // differs from that.
- if (data->visible) {
- InFlightVisibleChange visible_change(window, data->visible);
- InFlightChange* current_change =
- GetOldestInFlightChangeMatching(visible_change);
- if (current_change)
- current_change->SetRevertValueFrom(visible_change);
- else
- window_private.LocalSetVisible(true);
- }
-
- const gfx::Rect bounds(data->bounds);
- {
- InFlightBoundsChange bounds_change(window, bounds);
- InFlightChange* current_change =
- GetOldestInFlightChangeMatching(bounds_change);
- if (current_change)
- current_change->SetRevertValueFrom(bounds_change);
- else if (window->bounds() != bounds)
- window_private.LocalSetBounds(window->bounds(), bounds);
- }
-
- // There is currently no API to bulk set properties, so we iterate over each
- // property individually.
- Window::SharedProperties properties =
- data->properties.To<std::map<std::string, std::vector<uint8_t>>>();
- for (const auto& pair : properties) {
- InFlightPropertyChange property_change(
- window, pair.first, mojo::Array<uint8_t>::From(pair.second));
- InFlightChange* current_change =
- GetOldestInFlightChangeMatching(property_change);
- if (current_change)
- current_change->SetRevertValueFrom(property_change);
- else
- window_private.LocalSetSharedProperty(pair.first, &(pair.second));
- }
-
- // Top level windows should not have a parent.
- DCHECK_EQ(0u, data->parent_id);
-}
-
-void WindowTreeClient::OnWindowBoundsChanged(Id window_id,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- Window* window = GetWindowByServerId(window_id);
- if (!window)
- return;
-
- InFlightBoundsChange new_change(window, new_bounds);
- if (ApplyServerChangeToExistingInFlightChange(new_change))
- return;
-
- WindowPrivate(window).LocalSetBounds(old_bounds, new_bounds);
-}
-
-void WindowTreeClient::OnClientAreaChanged(
- uint32_t window_id,
- const gfx::Insets& new_client_area,
- mojo::Array<gfx::Rect> new_additional_client_areas) {
- Window* window = GetWindowByServerId(window_id);
- if (window) {
- WindowPrivate(window).LocalSetClientArea(
- new_client_area,
- new_additional_client_areas.To<std::vector<gfx::Rect>>());
- }
-}
-
-void WindowTreeClient::OnTransientWindowAdded(
- uint32_t window_id,
- uint32_t transient_window_id) {
- Window* window = GetWindowByServerId(window_id);
- Window* transient_window = GetWindowByServerId(transient_window_id);
- // window or transient_window or both may be null if a local delete occurs
- // with an in flight add from the server.
- if (window && transient_window)
- WindowPrivate(window).LocalAddTransientWindow(transient_window);
-}
-
-void WindowTreeClient::OnTransientWindowRemoved(
- uint32_t window_id,
- uint32_t transient_window_id) {
- Window* window = GetWindowByServerId(window_id);
- Window* transient_window = GetWindowByServerId(transient_window_id);
- // window or transient_window or both may be null if a local delete occurs
- // with an in flight delete from the server.
- if (window && transient_window)
- WindowPrivate(window).LocalRemoveTransientWindow(transient_window);
-}
-
-void WindowTreeClient::OnWindowHierarchyChanged(
- Id window_id,
- Id old_parent_id,
- Id new_parent_id,
- mojo::Array<mojom::WindowDataPtr> windows) {
- Window* initial_parent =
- windows.size() ? GetWindowByServerId(windows[0]->parent_id) : NULL;
-
- const bool was_window_known = GetWindowByServerId(window_id) != nullptr;
-
- BuildWindowTree(this, windows, initial_parent);
-
- // If the window was not known, then BuildWindowTree() will have created it
- // and parented the window.
- if (!was_window_known)
- return;
-
- Window* new_parent = GetWindowByServerId(new_parent_id);
- Window* old_parent = GetWindowByServerId(old_parent_id);
- Window* window = GetWindowByServerId(window_id);
- if (new_parent)
- WindowPrivate(new_parent).LocalAddChild(window);
- else
- WindowPrivate(old_parent).LocalRemoveChild(window);
-}
-
-void WindowTreeClient::OnWindowReordered(Id window_id,
- Id relative_window_id,
- mojom::OrderDirection direction) {
- Window* window = GetWindowByServerId(window_id);
- Window* relative_window = GetWindowByServerId(relative_window_id);
- if (window && relative_window)
- WindowPrivate(window).LocalReorder(relative_window, direction);
-}
-
-void WindowTreeClient::OnWindowDeleted(Id window_id) {
- Window* window = GetWindowByServerId(window_id);
- if (window)
- WindowPrivate(window).LocalDestroy();
-}
-
-Window* WindowTreeClient::GetCaptureWindow() {
- return capture_window_;
-}
-
-void WindowTreeClient::OnWindowVisibilityChanged(Id window_id,
- bool visible) {
- Window* window = GetWindowByServerId(window_id);
- if (!window)
- return;
-
- InFlightVisibleChange new_change(window, visible);
- if (ApplyServerChangeToExistingInFlightChange(new_change))
- return;
-
- WindowPrivate(window).LocalSetVisible(visible);
-}
-
-void WindowTreeClient::OnWindowOpacityChanged(Id window_id,
- float old_opacity,
- float new_opacity) {
- Window* window = GetWindowByServerId(window_id);
- if (!window)
- return;
-
- InFlightOpacityChange new_change(window, new_opacity);
- if (ApplyServerChangeToExistingInFlightChange(new_change))
- return;
-
- WindowPrivate(window).LocalSetOpacity(new_opacity);
-}
-
-void WindowTreeClient::OnWindowParentDrawnStateChanged(Id window_id,
- bool drawn) {
- Window* window = GetWindowByServerId(window_id);
- if (window)
- WindowPrivate(window).LocalSetParentDrawn(drawn);
-}
-
-void WindowTreeClient::OnWindowSharedPropertyChanged(
- Id window_id,
- const mojo::String& name,
- mojo::Array<uint8_t> new_data) {
- Window* window = GetWindowByServerId(window_id);
- if (!window)
- return;
-
- InFlightPropertyChange new_change(window, name, new_data);
- if (ApplyServerChangeToExistingInFlightChange(new_change))
- return;
-
- WindowPrivate(window).LocalSetSharedProperty(name, std::move(new_data));
-}
-
-void WindowTreeClient::OnWindowInputEvent(uint32_t event_id,
- Id window_id,
- std::unique_ptr<ui::Event> event,
- uint32_t event_observer_id) {
- DCHECK(event);
- Window* window = GetWindowByServerId(window_id); // May be null.
-
- // Non-zero event_observer_id means it matched an event observer on the
- // server.
- if (event_observer_id != 0 && has_event_observer_ &&
- event_observer_id == event_observer_id_)
- delegate_->OnEventObserved(*event.get(), window);
-
- if (!window || !window->input_event_handler_) {
- tree_->OnWindowInputEventAck(event_id, mojom::EventResult::UNHANDLED);
- return;
- }
-
- std::unique_ptr<base::Callback<void(mojom::EventResult)>> ack_callback(
- new base::Callback<void(mojom::EventResult)>(
- base::Bind(&mojom::WindowTree::OnWindowInputEventAck,
- base::Unretained(tree_), event_id)));
-
- // TODO(moshayedi): crbug.com/617222. No need to convert to ui::MouseEvent or
- // ui::TouchEvent once we have proper support for pointer events.
- if (event->IsMousePointerEvent()) {
- window->input_event_handler_->OnWindowInputEvent(
- window, ui::MouseEvent(*event->AsPointerEvent()), &ack_callback);
- } else if (event->IsTouchPointerEvent()) {
- window->input_event_handler_->OnWindowInputEvent(
- window, ui::TouchEvent(*event->AsPointerEvent()), &ack_callback);
- } else {
- window->input_event_handler_->OnWindowInputEvent(window, *event.get(),
- &ack_callback);
- }
-
- // The handler did not take ownership of the callback, so we send the ack,
- // marking the event as not consumed.
- if (ack_callback)
- ack_callback->Run(mojom::EventResult::UNHANDLED);
-}
-
-void WindowTreeClient::OnEventObserved(std::unique_ptr<ui::Event> event,
- uint32_t event_observer_id) {
- DCHECK(event);
- if (has_event_observer_ && event_observer_id == event_observer_id_)
- delegate_->OnEventObserved(*event.get(), nullptr /* target */);
-}
-
-void WindowTreeClient::OnWindowFocused(Id focused_window_id) {
- Window* focused_window = GetWindowByServerId(focused_window_id);
- InFlightFocusChange new_change(this, focused_window);
- if (ApplyServerChangeToExistingInFlightChange(new_change))
- return;
-
- LocalSetFocus(focused_window);
-}
-
-void WindowTreeClient::OnWindowPredefinedCursorChanged(
- Id window_id,
- mojom::Cursor cursor) {
- Window* window = GetWindowByServerId(window_id);
- if (!window)
- return;
-
- InFlightPredefinedCursorChange new_change(window, cursor);
- if (ApplyServerChangeToExistingInFlightChange(new_change))
- return;
-
- WindowPrivate(window).LocalSetPredefinedCursor(cursor);
-}
-
-void WindowTreeClient::OnChangeCompleted(uint32_t change_id, bool success) {
- std::unique_ptr<InFlightChange> change(std::move(in_flight_map_[change_id]));
- in_flight_map_.erase(change_id);
- if (!change)
- return;
-
- if (!success)
- change->ChangeFailed();
-
- InFlightChange* next_change = GetOldestInFlightChangeMatching(*change);
- if (next_change) {
- if (!success)
- next_change->SetRevertValueFrom(*change);
- } else if (!success) {
- change->Revert();
- }
-}
-
-void WindowTreeClient::GetWindowManager(
- mojo::AssociatedInterfaceRequest<WindowManager> internal) {
- window_manager_internal_.reset(
- new mojo::AssociatedBinding<mojom::WindowManager>(this,
- std::move(internal)));
-}
-
-void WindowTreeClient::RequestClose(uint32_t window_id) {
- Window* window = GetWindowByServerId(window_id);
- if (!window || !IsRoot(window))
- return;
-
- FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window).observers(),
- OnRequestClose(window));
-}
-
-void WindowTreeClient::OnConnect(ClientSpecificId client_id) {
- client_id_ = client_id;
-}
-
-void WindowTreeClient::WmNewDisplayAdded(mojom::DisplayPtr display,
- mojom::WindowDataPtr root_data,
- bool parent_drawn) {
- WmNewDisplayAddedImpl(display.To<display::Display>(), std::move(root_data),
- parent_drawn);
-}
-
-void WindowTreeClient::WmSetBounds(uint32_t change_id,
- Id window_id,
- const gfx::Rect& transit_bounds) {
- Window* window = GetWindowByServerId(window_id);
- bool result = false;
- if (window) {
- DCHECK(window_manager_delegate_);
- gfx::Rect bounds = transit_bounds;
- result = window_manager_delegate_->OnWmSetBounds(window, &bounds);
- if (result) {
- // If the resulting bounds differ return false. Returning false ensures
- // the client applies the bounds we set below.
- result = bounds == transit_bounds;
- window->SetBounds(bounds);
- }
- }
- if (window_manager_internal_client_)
- window_manager_internal_client_->WmResponse(change_id, result);
-}
-
-void WindowTreeClient::WmSetProperty(uint32_t change_id,
- Id window_id,
- const mojo::String& name,
- mojo::Array<uint8_t> transit_data) {
- Window* window = GetWindowByServerId(window_id);
- bool result = false;
- if (window) {
- DCHECK(window_manager_delegate_);
- std::unique_ptr<std::vector<uint8_t>> data;
- if (!transit_data.is_null()) {
- data.reset(
- new std::vector<uint8_t>(transit_data.To<std::vector<uint8_t>>()));
- }
- result = window_manager_delegate_->OnWmSetProperty(window, name, &data);
- if (result) {
- // If the resulting bounds differ return false. Returning false ensures
- // the client applies the bounds we set below.
- window->SetSharedPropertyInternal(name, data.get());
- }
- }
- if (window_manager_internal_client_)
- window_manager_internal_client_->WmResponse(change_id, result);
-}
-
-void WindowTreeClient::WmCreateTopLevelWindow(
- uint32_t change_id,
- ClientSpecificId requesting_client_id,
- mojo::Map<mojo::String, mojo::Array<uint8_t>> transport_properties) {
- std::map<std::string, std::vector<uint8_t>> properties =
- transport_properties.To<std::map<std::string, std::vector<uint8_t>>>();
- Window* window =
- window_manager_delegate_->OnWmCreateTopLevelWindow(&properties);
- embedded_windows_[requesting_client_id].insert(window);
- if (window_manager_internal_client_) {
- window_manager_internal_client_->OnWmCreatedTopLevelWindow(
- change_id, server_id(window));
- }
-}
-
-void WindowTreeClient::WmClientJankinessChanged(ClientSpecificId client_id,
- bool janky) {
- if (window_manager_delegate_) {
- auto it = embedded_windows_.find(client_id);
- CHECK(it != embedded_windows_.end());
- window_manager_delegate_->OnWmClientJankinessChanged(
- embedded_windows_[client_id], janky);
- }
-}
-
-void WindowTreeClient::OnAccelerator(uint32_t id,
- std::unique_ptr<ui::Event> event) {
- DCHECK(event);
- window_manager_delegate_->OnAccelerator(id, *event.get());
-}
-
-void WindowTreeClient::SetFrameDecorationValues(
- mojom::FrameDecorationValuesPtr values) {
- if (window_manager_internal_client_) {
- window_manager_internal_client_->WmSetFrameDecorationValues(
- std::move(values));
- }
-}
-
-void WindowTreeClient::SetNonClientCursor(Window* window,
- mus::mojom::Cursor cursor_id) {
- window_manager_internal_client_->WmSetNonClientCursor(server_id(window),
- cursor_id);
-}
-
-void WindowTreeClient::AddAccelerator(
- uint32_t id,
- mojom::EventMatcherPtr event_matcher,
- const base::Callback<void(bool)>& callback) {
- if (window_manager_internal_client_) {
- window_manager_internal_client_->AddAccelerator(
- id, std::move(event_matcher), callback);
- }
-}
-
-void WindowTreeClient::RemoveAccelerator(uint32_t id) {
- if (window_manager_internal_client_) {
- window_manager_internal_client_->RemoveAccelerator(id);
- }
-}
-
-void WindowTreeClient::AddActivationParent(Window* window) {
- if (window_manager_internal_client_)
- window_manager_internal_client_->AddActivationParent(server_id(window));
-}
-
-void WindowTreeClient::RemoveActivationParent(Window* window) {
- if (window_manager_internal_client_)
- window_manager_internal_client_->RemoveActivationParent(server_id(window));
-}
-
-void WindowTreeClient::ActivateNextWindow() {
- if (window_manager_internal_client_)
- window_manager_internal_client_->ActivateNextWindow();
-}
-
-void WindowTreeClient::SetUnderlaySurfaceOffsetAndExtendedHitArea(
- Window* window,
- const gfx::Vector2d& offset,
- const gfx::Insets& hit_area) {
- if (window_manager_internal_client_) {
- window_manager_internal_client_->SetUnderlaySurfaceOffsetAndExtendedHitArea(
- server_id(window), offset.x(), offset.y(), hit_area);
- }
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_tree_client_delegate.cc b/chromium/components/mus/public/cpp/lib/window_tree_client_delegate.cc
deleted file mode 100644
index ed53012b227..00000000000
--- a/chromium/components/mus/public/cpp/lib/window_tree_client_delegate.cc
+++ /dev/null
@@ -1,11 +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 "components/mus/public/cpp/window_tree_client_delegate.h"
-
-namespace mus {
-
-void WindowTreeClientDelegate::OnUnembed(Window* root) {}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/lib/window_tree_host_factory.cc b/chromium/components/mus/public/cpp/lib/window_tree_host_factory.cc
deleted file mode 100644
index 0d55bae13fe..00000000000
--- a/chromium/components/mus/public/cpp/lib/window_tree_host_factory.cc
+++ /dev/null
@@ -1,32 +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 "components/mus/public/cpp/window_tree_host_factory.h"
-
-#include "components/mus/public/cpp/window_tree_client.h"
-#include "components/mus/public/cpp/window_tree_client_delegate.h"
-#include "services/shell/public/cpp/connector.h"
-
-namespace mus {
-
-void CreateWindowTreeHost(mojom::WindowTreeHostFactory* factory,
- WindowTreeClientDelegate* delegate,
- mojom::WindowTreeHostPtr* host,
- WindowManagerDelegate* window_manager_delegate) {
- mojom::WindowTreeClientPtr tree_client;
- new WindowTreeClient(delegate, window_manager_delegate,
- GetProxy(&tree_client));
- factory->CreateWindowTreeHost(GetProxy(host), std::move(tree_client));
-}
-
-void CreateWindowTreeHost(shell::Connector* connector,
- WindowTreeClientDelegate* delegate,
- mojom::WindowTreeHostPtr* host,
- WindowManagerDelegate* window_manager_delegate) {
- mojom::WindowTreeHostFactoryPtr factory;
- connector->ConnectToInterface("mojo:mus", &factory);
- CreateWindowTreeHost(factory.get(), delegate, host, window_manager_delegate);
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/public/cpp/output_surface.h b/chromium/components/mus/public/cpp/output_surface.h
deleted file mode 100644
index 1b1feccff37..00000000000
--- a/chromium/components/mus/public/cpp/output_surface.h
+++ /dev/null
@@ -1,45 +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 COMPONENTS_MUS_PUBLIC_CPP_OUTPUT_SURFACE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_OUTPUT_SURFACE_H_
-
-#include "base/macros.h"
-#include "cc/output/output_surface.h"
-#include "cc/surfaces/surface_id.h"
-#include "components/mus/public/cpp/window_surface.h"
-#include "components/mus/public/cpp/window_surface_client.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace mus {
-
-class OutputSurface : public cc::OutputSurface, public WindowSurfaceClient {
- public:
- OutputSurface(const scoped_refptr<cc::ContextProvider>& context_provider,
- std::unique_ptr<WindowSurface> surface);
- ~OutputSurface() override;
-
- // cc::OutputSurface implementation.
- void SwapBuffers(cc::CompositorFrame frame) override;
- bool BindToClient(cc::OutputSurfaceClient* client) override;
- void DetachFromClient() override;
- void BindFramebuffer() override;
- uint32_t GetFramebufferCopyTextureFormat() override;
-
- private:
- // WindowSurfaceClient implementation:
- void OnResourcesReturned(
- WindowSurface* surface,
- mojo::Array<cc::ReturnedResource> resources) override;
-
- void SwapBuffersComplete();
-
- std::unique_ptr<WindowSurface> surface_;
-
- DISALLOW_COPY_AND_ASSIGN(OutputSurface);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_OUTPUT_SURFACE_H_
diff --git a/chromium/components/mus/public/cpp/property_type_converters.h b/chromium/components/mus/public/cpp/property_type_converters.h
deleted file mode 100644
index 5676253e810..00000000000
--- a/chromium/components/mus/public/cpp/property_type_converters.h
+++ /dev/null
@@ -1,96 +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 COMPONENTS_MUS_PUBLIC_CPP_PROPERTY_TYPE_CONVERTERS_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_PROPERTY_TYPE_CONVERTERS_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "base/strings/string16.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-
-class SkBitmap;
-
-namespace gfx {
-class Rect;
-class Size;
-}
-
-namespace mojo {
-
-// TODO(beng): these methods serialize types used for standard properties
-// to vectors of bytes used by Window::SetSharedProperty().
-// replace this with serialization code generated @ bindings.
-// This would be especially useful for SkBitmap, which could be
-// replaced with the skia.Bitmap mojom struct serialization.
-
-template <>
-struct TypeConverter<std::vector<uint8_t>, gfx::Rect> {
- static std::vector<uint8_t> Convert(const gfx::Rect& input);
-};
-template <>
-struct TypeConverter<gfx::Rect, std::vector<uint8_t>> {
- static gfx::Rect Convert(const std::vector<uint8_t>& input);
-};
-
-template <>
-struct TypeConverter<std::vector<uint8_t>, gfx::Size> {
- static std::vector<uint8_t> Convert(const gfx::Size& input);
-};
-template <>
-struct TypeConverter<gfx::Size, std::vector<uint8_t>> {
- static gfx::Size Convert(const std::vector<uint8_t>& input);
-};
-
-template <>
-struct TypeConverter<std::vector<uint8_t>, int32_t> {
- static std::vector<uint8_t> Convert(const int32_t& input);
-};
-template <>
-struct TypeConverter<int32_t, std::vector<uint8_t>> {
- static int32_t Convert(const std::vector<uint8_t>& input);
-};
-
-template <>
-struct TypeConverter<std::vector<uint8_t>, base::string16> {
- static std::vector<uint8_t> Convert(const base::string16& input);
-};
-template <>
-struct TypeConverter<base::string16, std::vector<uint8_t>> {
- static base::string16 Convert(const std::vector<uint8_t>& input);
-};
-
-template <>
-struct TypeConverter<std::vector<uint8_t>, std::string> {
- static std::vector<uint8_t> Convert(const std::string& input);
-};
-template <>
-struct TypeConverter<std::string, std::vector<uint8_t>> {
- static std::string Convert(const std::vector<uint8_t>& input);
-};
-
-// NOTE: These methods only serialize and deserialize the common case of RGBA
-// 8888 bitmaps with premultiplied alpha.
-template <>
-struct TypeConverter<std::vector<uint8_t>, SkBitmap> {
- static std::vector<uint8_t> Convert(const SkBitmap& input);
-};
-template <>
-struct TypeConverter<SkBitmap, std::vector<uint8_t>> {
- static SkBitmap Convert(const std::vector<uint8_t>& input);
-};
-
-template <>
-struct TypeConverter<std::vector<uint8_t>, bool> {
- static std::vector<uint8_t> Convert(bool input);
-};
-template <>
-struct TypeConverter<bool, std::vector<uint8_t>> {
- static bool Convert(const std::vector<uint8_t>& input);
-};
-
-} // namespace mojo
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_PROPERTY_TYPE_CONVERTERS_H_
diff --git a/chromium/components/mus/public/cpp/scoped_window_ptr.h b/chromium/components/mus/public/cpp/scoped_window_ptr.h
deleted file mode 100644
index b94e0f945f3..00000000000
--- a/chromium/components/mus/public/cpp/scoped_window_ptr.h
+++ /dev/null
@@ -1,42 +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 COMPONENTS_MUS_PUBLIC_CPP_SCOPED_WINDOW_PTR_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_SCOPED_WINDOW_PTR_H_
-
-#include "base/macros.h"
-#include "components/mus/public/cpp/window_observer.h"
-
-namespace mus {
-
-// Wraps a Window, taking overship of the Window. Also deals with Window being
-// destroyed while ScopedWindowPtr still exists.
-class ScopedWindowPtr : public WindowObserver {
- public:
- explicit ScopedWindowPtr(Window* window);
- ~ScopedWindowPtr() override;
-
- // Destroys |window|. If |window| is a root of the WindowManager than the
- // WindowManager is destroyed (which in turn destroys |window|).
- //
- // NOTE: this function (and class) are only useful for clients that only
- // ever have a single root.
- static void DeleteWindowOrWindowManager(Window* window);
-
- Window* window() { return window_; }
- const Window* window() const { return window_; }
-
- private:
- void DetachFromWindow();
-
- void OnWindowDestroying(Window* window) override;
-
- Window* window_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedWindowPtr);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_SCOPED_WINDOW_PTR_H_
diff --git a/chromium/components/mus/public/cpp/tests/BUILD.gn b/chromium/components/mus/public/cpp/tests/BUILD.gn
deleted file mode 100644
index e5f756f0726..00000000000
--- a/chromium/components/mus/public/cpp/tests/BUILD.gn
+++ /dev/null
@@ -1,82 +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("//build/config/ui.gni")
-import("//testing/test.gni")
-
-source_set("unittest_support") {
- testonly = true
-
- sources = [
- "test_window.h",
- "test_window_tree.cc",
- "test_window_tree.h",
- "test_window_tree_client_setup.cc",
- "test_window_tree_client_setup.h",
- "window_tree_client_private.cc",
- "window_tree_client_private.h",
- ]
-
- deps = [
- "//base",
- "//components/mus/public/cpp",
- "//testing/gtest",
- "//ui/display",
- "//ui/gfx/geometry/mojo",
- ]
-}
-
-source_set("test_support") {
- testonly = true
-
- sources = [
- "window_server_shelltest_base.cc",
- "window_server_shelltest_base.h",
- "window_server_test_base.cc",
- "window_server_test_base.h",
- ]
-
- deps = [
- "//base",
- "//base/test:test_config",
- "//components/mus/common:mus_common",
- "//components/mus/public/cpp",
- "//services/shell/public/cpp:shell_test_support",
- "//services/shell/public/cpp:sources",
- "//testing/gtest",
- "//ui/gl",
- ]
-}
-
-test("mus_public_unittests") {
- sources = [
- "property_type_converters_unittest.cc",
- "run_all_unittests.cc",
- "window_server_test_suite.cc",
- "window_server_test_suite.h",
- "window_tree_client_unittest.cc",
- "window_unittest.cc",
- ]
-
- deps = [
- ":unittest_support",
- "//base",
- "//base/test:test_support",
- "//components/mus/common:mus_common",
- "//components/mus/public/cpp",
- "//mojo/common:common_base",
- "//mojo/edk/system",
- "//mojo/public/cpp/system",
- "//services/shell/public/cpp",
- "//testing/gtest",
- "//ui/events",
- "//ui/gfx:test_support",
- "//ui/gfx/geometry",
- "//ui/gfx/geometry/mojo",
- ]
-
- if (use_x11) {
- deps += [ "//ui/gfx/x" ]
- }
-}
diff --git a/chromium/components/mus/public/cpp/window.h b/chromium/components/mus/public/cpp/window.h
deleted file mode 100644
index eabc6098a5b..00000000000
--- a/chromium/components/mus/public/cpp/window.h
+++ /dev/null
@@ -1,356 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_H_
-
-#include <stdint.h>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/mus/common/types.h"
-#include "components/mus/public/interfaces/mus_constants.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "mojo/public/cpp/bindings/array.h"
-#include "services/shell/public/interfaces/interface_provider.mojom.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace gfx {
-class Size;
-}
-
-namespace mus {
-
-class InputEventHandler;
-class ServiceProviderImpl;
-class WindowObserver;
-class WindowSurface;
-class WindowSurfaceBinding;
-class WindowTreeClient;
-class WindowTreeClientPrivate;
-
-namespace {
-class OrderChangedNotifier;
-}
-
-// Defined in window_property.h (which we do not include)
-template <typename T>
-struct WindowProperty;
-
-// Windows are owned by the WindowTreeClient. See WindowTreeClientDelegate for
-// details on ownership.
-//
-// TODO(beng): Right now, you'll have to implement a WindowObserver to track
-// destruction and NULL any pointers you have.
-// Investigate some kind of smart pointer or weak pointer for these.
-class Window {
- public:
- using Children = std::vector<Window*>;
- using EmbedCallback = base::Callback<void(bool)>;
- using PropertyDeallocator = void (*)(int64_t value);
- using SharedProperties = std::map<std::string, std::vector<uint8_t>>;
-
- // Destroys this window and all its children. Destruction is allowed for
- // windows that were created by this connection, or the roots. For windows
- // from other connections (except the roots), Destroy() does nothing. If the
- // destruction is allowed observers are notified and the Window is
- // immediately deleted.
- void Destroy();
-
- WindowTreeClient* window_tree() { return client_; }
-
- // The local_id is provided for client code. The local_id is not set or
- // manipulated by mus. The default value is -1.
- void set_local_id(int id) { local_id_ = id; }
- int local_id() const { return local_id_; }
-
- int64_t display_id() const { return display_id_; }
-
- // Geometric disposition relative to parent window.
- const gfx::Rect& bounds() const { return bounds_; }
- void SetBounds(const gfx::Rect& bounds);
-
- // Geometric disposition relative to root window.
- gfx::Rect GetBoundsInRoot() const;
-
- const gfx::Insets& client_area() const { return client_area_; }
- const std::vector<gfx::Rect>& additional_client_areas() {
- return additional_client_areas_;
- }
- void SetClientArea(const gfx::Insets& new_client_area) {
- SetClientArea(new_client_area, std::vector<gfx::Rect>());
- }
- void SetClientArea(const gfx::Insets& new_client_area,
- const std::vector<gfx::Rect>& additional_client_areas);
-
- // Mouse events outside the hit test mask do not hit the window. Returns null
- // if there is no mask.
- const gfx::Rect* hit_test_mask() const { return hit_test_mask_.get(); }
- void SetHitTestMask(const gfx::Rect& mask_rect);
- void ClearHitTestMask();
-
- // Visibility (also see IsDrawn()). When created windows are hidden.
- bool visible() const { return visible_; }
- void SetVisible(bool value);
-
- float opacity() const { return opacity_; }
- void SetOpacity(float opacity);
-
- // Cursors
- mojom::Cursor predefined_cursor() const { return cursor_id_; }
- void SetPredefinedCursor(mus::mojom::Cursor cursor_id);
-
- // A Window is drawn if the Window and all its ancestors are visible and the
- // Window is attached to the root.
- bool IsDrawn() const;
-
- std::unique_ptr<WindowSurface> RequestSurface(mojom::SurfaceType type);
-
- void AttachSurface(mojom::SurfaceType type,
- std::unique_ptr<WindowSurfaceBinding> surface_binding);
-
- // The template-ized versions of the following methods rely on the presence
- // of a mojo::TypeConverter<const std::vector<uint8_t>, T>.
- // Sets a shared property on the window which is sent to the window server and
- // shared with other clients that can view this window.
- template <typename T>
- void SetSharedProperty(const std::string& name, const T& data);
- // Gets a shared property set on the window. The property must exist. Call
- // HasSharedProperty() before calling.
- template <typename T>
- T GetSharedProperty(const std::string& name) const;
- // Removes the shared property.
- void ClearSharedProperty(const std::string& name);
- bool HasSharedProperty(const std::string& name) const;
-
- // TODO(beng): Test only, should move to a helper.
- const SharedProperties& shared_properties() { return properties_; }
-
- // Sets the |value| of the given window |property|. Setting to the default
- // value (e.g., NULL) removes the property. The caller is responsible for the
- // lifetime of any object set as a property on the Window.
- //
- // These properties are not visible to the window server.
- template <typename T>
- void SetLocalProperty(const WindowProperty<T>* property, T value);
-
- // Returns the value of the given window |property|. Returns the
- // property-specific default value if the property was not previously set.
- //
- // These properties are only visible in the current process and are not
- // shared with other mojo services.
- template <typename T>
- T GetLocalProperty(const WindowProperty<T>* property) const;
-
- // Sets the |property| to its default value. Useful for avoiding a cast when
- // setting to NULL.
- //
- // These properties are only visible in the current process and are not
- // shared with other mojo services.
- template <typename T>
- void ClearLocalProperty(const WindowProperty<T>* property);
-
- void set_input_event_handler(InputEventHandler* input_event_handler) {
- input_event_handler_ = input_event_handler;
- }
-
- // Observation.
- void AddObserver(WindowObserver* observer);
- void RemoveObserver(WindowObserver* observer);
-
- // Tree.
- Window* parent() { return parent_; }
- const Window* parent() const { return parent_; }
-
- Window* GetRoot() {
- return const_cast<Window*>(const_cast<const Window*>(this)->GetRoot());
- }
- const Window* GetRoot() const;
-
- void AddChild(Window* child);
- void RemoveChild(Window* child);
- const Children& children() const { return children_; }
-
- void Reorder(Window* relative, mojom::OrderDirection direction);
- void MoveToFront();
- void MoveToBack();
-
- // Returns true if |child| is this or a descendant of this.
- bool Contains(const Window* child) const;
-
- void AddTransientWindow(Window* transient_window);
- void RemoveTransientWindow(Window* transient_window);
-
- // TODO(fsamuel): Figure out if we want to refactor transient window
- // management into a separate class.
- // Transient tree.
- Window* transient_parent() { return transient_parent_; }
- const Window* transient_parent() const { return transient_parent_; }
- const Children& transient_children() const { return transient_children_; }
-
- void SetModal();
- bool is_modal() const { return is_modal_; }
-
- Window* GetChildByLocalId(int id);
-
- void SetTextInputState(mojo::TextInputStatePtr state);
- void SetImeVisibility(bool visible, mojo::TextInputStatePtr state);
-
- bool HasCapture() const;
- void SetCapture();
- void ReleaseCapture();
-
- // Focus. See WindowTreeClient::ClearFocus() to reset focus.
- void SetFocus();
- bool HasFocus() const;
- void SetCanFocus(bool can_focus);
-
- // Embedding. See window_tree.mojom for details.
- void Embed(mus::mojom::WindowTreeClientPtr client, uint32_t flags = 0);
-
- // NOTE: callback is run synchronously if Embed() is not allowed on this
- // Window.
- void Embed(mus::mojom::WindowTreeClientPtr client,
- const EmbedCallback& callback,
- uint32_t flags = 0);
-
- // TODO(sky): this API is only applicable to the WindowManager. Move it
- // to a better place.
- void RequestClose();
-
- // Returns an internal name, set by a client app when it creates a window.
- std::string GetName() const;
-
- protected:
- // This class is subclassed only by test classes that provide a public ctor.
- Window();
- ~Window();
-
- private:
- friend class WindowPrivate;
- friend class WindowTreeClient;
- friend class WindowTreeClientPrivate;
-
- Window(WindowTreeClient* client, Id id);
-
- // Used to identify this Window on the server. Clients can not change this
- // value.
- Id server_id() const { return server_id_; }
-
- // Applies a shared property change locally and forwards to the server. If
- // |data| is null, this property is deleted.
- void SetSharedPropertyInternal(const std::string& name,
- const std::vector<uint8_t>* data);
- // Called by the public {Set,Get,Clear}Property functions.
- int64_t SetLocalPropertyInternal(const void* key,
- const char* name,
- PropertyDeallocator deallocator,
- int64_t value,
- int64_t default_value);
- int64_t GetLocalPropertyInternal(const void* key,
- int64_t default_value) const;
-
- void LocalDestroy();
- void LocalAddChild(Window* child);
- void LocalRemoveChild(Window* child);
- void LocalAddTransientWindow(Window* transient_window);
- void LocalRemoveTransientWindow(Window* transient_window);
- void LocalSetModal();
- // Returns true if the order actually changed.
- bool LocalReorder(Window* relative, mojom::OrderDirection direction);
- void LocalSetBounds(const gfx::Rect& old_bounds, const gfx::Rect& new_bounds);
- void LocalSetClientArea(
- const gfx::Insets& new_client_area,
- const std::vector<gfx::Rect>& additional_client_areas);
- void LocalSetParentDrawn(bool drawn);
- void LocalSetDisplay(int64_t display_id);
- void LocalSetVisible(bool visible);
- void LocalSetOpacity(float opacity);
- void LocalSetPredefinedCursor(mojom::Cursor cursor_id);
- void LocalSetSharedProperty(const std::string& name,
- const std::vector<uint8_t>* data);
-
- // Notifies this winodw that its stacking position has changed.
- void NotifyWindowStackingChanged();
- // Methods implementing visibility change notifications. See WindowObserver
- // for more details.
- void NotifyWindowVisibilityChanged(Window* target);
- // Notifies this window's observers. Returns false if |this| was deleted
- // during the call (by an observer), otherwise true.
- bool NotifyWindowVisibilityChangedAtReceiver(Window* target);
- // Notifies this window and its child hierarchy. Returns false if |this| was
- // deleted during the call (by an observer), otherwise true.
- bool NotifyWindowVisibilityChangedDown(Window* target);
- // Notifies this window and its parent hierarchy.
- void NotifyWindowVisibilityChangedUp(Window* target);
-
- // Returns true if embed is allowed for this node. If embedding is allowed all
- // the children are removed.
- bool PrepareForEmbed();
-
- void RemoveTransientWindowImpl(Window* child);
- static void ReorderWithoutNotification(Window* window,
- Window* relative,
- mojom::OrderDirection direction);
- static bool ReorderImpl(Window* window,
- Window* relative,
- mojom::OrderDirection direction,
- OrderChangedNotifier* notifier);
-
- // Returns a pointer to the stacking target that can be used by
- // RestackTransientDescendants.
- static Window** GetStackingTarget(Window* window);
-
- WindowTreeClient* client_;
- Id server_id_;
- int local_id_ = -1;
- Window* parent_;
- Children children_;
-
- Window* stacking_target_;
- Window* transient_parent_;
- Children transient_children_;
-
- bool is_modal_;
-
- base::ObserverList<WindowObserver> observers_;
- InputEventHandler* input_event_handler_;
-
- gfx::Rect bounds_;
- gfx::Insets client_area_;
- std::vector<gfx::Rect> additional_client_areas_;
- std::unique_ptr<gfx::Rect> hit_test_mask_;
-
- bool visible_;
- float opacity_;
- int64_t display_id_;
-
- mojom::Cursor cursor_id_;
-
- SharedProperties properties_;
-
- // Drawn state of our parent. This is only meaningful for root Windows, in
- // which the parent Window isn't exposed to the client.
- bool parent_drawn_;
-
- // Value struct to keep the name and deallocator for this property.
- // Key cannot be used for this purpose because it can be char* or
- // WindowProperty<>.
- struct Value {
- const char* name;
- int64_t value;
- PropertyDeallocator deallocator;
- };
-
- std::map<const void*, Value> prop_map_;
-
- DISALLOW_COPY_AND_ASSIGN(Window);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_H_
diff --git a/chromium/components/mus/public/cpp/window_manager_delegate.h b/chromium/components/mus/public/cpp/window_manager_delegate.h
deleted file mode 100644
index 99ddf34cc4e..00000000000
--- a/chromium/components/mus/public/cpp/window_manager_delegate.h
+++ /dev/null
@@ -1,116 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_MANAGER_DELEGATE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_MANAGER_DELEGATE_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "components/mus/public/interfaces/cursor.mojom.h"
-#include "components/mus/public/interfaces/event_matcher.mojom.h"
-#include "components/mus/public/interfaces/window_manager_constants.mojom.h"
-#include "ui/events/mojo/event.mojom.h"
-
-namespace display {
-class Display;
-}
-
-namespace gfx {
-class Insets;
-class Rect;
-class Vector2d;
-}
-
-namespace ui {
-class Event;
-}
-
-namespace mus {
-
-class Window;
-
-// See the mojom with the same name for details on the functions in this
-// interface.
-class WindowManagerClient {
- public:
- virtual void SetFrameDecorationValues(
- mojom::FrameDecorationValuesPtr values) = 0;
- virtual void SetNonClientCursor(Window* window,
- mojom::Cursor non_client_cursor) = 0;
-
- virtual void AddAccelerator(uint32_t id,
- mojom::EventMatcherPtr event_matcher,
- const base::Callback<void(bool)>& callback) = 0;
- virtual void RemoveAccelerator(uint32_t id) = 0;
- virtual void AddActivationParent(Window* window) = 0;
- virtual void RemoveActivationParent(Window* window) = 0;
- virtual void ActivateNextWindow() = 0;
- virtual void SetUnderlaySurfaceOffsetAndExtendedHitArea(
- Window* window,
- const gfx::Vector2d& offset,
- const gfx::Insets& hit_area) = 0;
-
- protected:
- virtual ~WindowManagerClient() {}
-};
-
-// Used by clients implementing a window manager.
-// TODO(sky): this should be called WindowManager, but that's rather confusing
-// currently.
-class WindowManagerDelegate {
- public:
- // Called once to give the delegate access to functions only exposed to
- // the WindowManager.
- virtual void SetWindowManagerClient(WindowManagerClient* client) = 0;
-
- // A client requested the bounds of |window| to change to |bounds|. Return
- // true if the bounds are allowed to change. A return value of false
- // indicates the change is not allowed.
- // NOTE: This should not change the bounds of |window|. Instead return the
- // bounds the window should be in |bounds|.
- virtual bool OnWmSetBounds(Window* window, gfx::Rect* bounds) = 0;
-
- // A client requested the shared property named |name| to change to
- // |new_data|. Return true to allow the change to |new_data|, false
- // otherwise.
- virtual bool OnWmSetProperty(
- Window* window,
- const std::string& name,
- std::unique_ptr<std::vector<uint8_t>>* new_data) = 0;
-
- // A client has requested a new top level window. The delegate should create
- // and parent the window appropriately and return it. |properties| is the
- // supplied properties from the client requesting the new window. The
- // delegate may modify |properties| before calling NewWindow(), but the
- // delegate does *not* own |properties|, they are valid only for the life
- // of OnWmCreateTopLevelWindow().
- virtual Window* OnWmCreateTopLevelWindow(
- std::map<std::string, std::vector<uint8_t>>* properties) = 0;
-
- // Called when a Mus client's jankiness changes. |windows| is the set of
- // windows owned by the window manager in which the client is embedded.
- virtual void OnWmClientJankinessChanged(
- const std::set<Window*>& client_windows,
- bool janky) = 0;
-
- // Called when a display is added. |window| is the root of the window tree for
- // the specified display.
- virtual void OnWmNewDisplay(Window* window,
- const display::Display& display) = 0;
-
- virtual void OnAccelerator(uint32_t id, const ui::Event& event) = 0;
-
- protected:
- virtual ~WindowManagerDelegate() {}
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_MANAGER_DELEGATE_H_
diff --git a/chromium/components/mus/public/cpp/window_observer.h b/chromium/components/mus/public/cpp/window_observer.h
deleted file mode 100644
index f1dc27913d7..00000000000
--- a/chromium/components/mus/public/cpp/window_observer.h
+++ /dev/null
@@ -1,110 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_OBSERVER_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_OBSERVER_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "components/mus/public/cpp/window.h"
-
-namespace mus {
-
-class Window;
-
-// A note on -ing and -ed suffixes:
-//
-// -ing methods are called before changes are applied to the local window model.
-// -ed methods are called after changes are applied to the local window model.
-//
-// If the change originated from another connection to the window manager, it's
-// possible that the change has already been applied to the service-side model
-// prior to being called, so for example in the case of OnWindowDestroying(),
-// it's possible the window has already been destroyed on the service side.
-
-class WindowObserver {
- public:
- struct TreeChangeParams {
- TreeChangeParams();
- Window* target;
- Window* old_parent;
- Window* new_parent;
- Window* receiver;
- };
-
- virtual void OnTreeChanging(const TreeChangeParams& params) {}
- virtual void OnTreeChanged(const TreeChangeParams& params) {}
-
- virtual void OnWindowReordering(Window* window,
- Window* relative_window,
- mojom::OrderDirection direction) {}
- virtual void OnWindowReordered(Window* window,
- Window* relative_window,
- mojom::OrderDirection direction) {}
-
- virtual void OnWindowDestroying(Window* window) {}
- virtual void OnWindowDestroyed(Window* window) {}
-
- virtual void OnWindowBoundsChanging(Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {}
- virtual void OnWindowBoundsChanged(Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {}
- virtual void OnWindowLostCapture(Window* window) {}
- virtual void OnWindowClientAreaChanged(
- Window* window,
- const gfx::Insets& old_client_area,
- const std::vector<gfx::Rect>& old_additional_client_areas) {}
-
- virtual void OnWindowFocusChanged(Window* gained_focus, Window* lost_focus) {}
-
- virtual void OnWindowPredefinedCursorChanged(Window* window,
- mojom::Cursor cursor) {}
- virtual void OnWindowVisibilityChanging(Window* window) {}
- virtual void OnWindowVisibilityChanged(Window* window) {}
- virtual void OnWindowOpacityChanged(Window* window,
- float old_opacity,
- float new_opacity) {}
-
- // Invoked when this Window's shared properties have changed. This can either
- // be caused by SetSharedProperty() being called locally, or by us receiving
- // a mojo message that this property has changed. If this property has been
- // added, |old_data| is null. If this property was removed, |new_data| is
- // null.
- virtual void OnWindowSharedPropertyChanged(
- Window* window,
- const std::string& name,
- const std::vector<uint8_t>* old_data,
- const std::vector<uint8_t>* new_data) {}
-
- // Invoked when SetProperty() or ClearProperty() is called on the window.
- // |key| is either a WindowProperty<T>* (SetProperty, ClearProperty). Either
- // way, it can simply be compared for equality with the property
- // constant. |old| is the old property value, which must be cast to the
- // appropriate type before use.
- virtual void OnWindowLocalPropertyChanged(Window* window,
- const void* key,
- intptr_t old) {}
-
- virtual void OnWindowEmbeddedAppDisconnected(Window* window) {}
-
- // Sent when the drawn state changes. This is only sent for the root nodes
- // when embedded.
- virtual void OnWindowDrawnChanging(Window* window) {}
- virtual void OnWindowDrawnChanged(Window* window) {}
-
- // The WindowManager has requested the window to close. If the observer
- // allows the close it should destroy the window as appropriate.
- virtual void OnRequestClose(Window* window) {}
-
- protected:
- virtual ~WindowObserver() {}
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_OBSERVER_H_
diff --git a/chromium/components/mus/public/cpp/window_property.h b/chromium/components/mus/public/cpp/window_property.h
deleted file mode 100644
index 3299ac9db98..00000000000
--- a/chromium/components/mus/public/cpp/window_property.h
+++ /dev/null
@@ -1,156 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_PROPERTY_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_PROPERTY_H_
-
-#include <stdint.h>
-
-// To define a new WindowProperty:
-//
-// #include "components/mus/public/cpp/window_property.h"
-//
-// MUS_DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(FOO_EXPORT, MyType);
-// namespace foo {
-// // Use this to define an exported property that is primitive,
-// // or a pointer you don't want automatically deleted.
-// MUS_DEFINE_WINDOW_PROPERTY_KEY(MyType, kMyKey, MyDefault);
-//
-// // Use this to define an exported property whose value is a heap
-// // allocated object, and has to be owned and freed by the window.
-// MUS_DEFINE_OWNED_WINDOW_PROPERTY_KEY(gfx::Rect, kRestoreBoundsKey,
-// nullptr);
-//
-// // Use this to define a non exported property that is primitive,
-// // or a pointer you don't want to automatically deleted, and is used
-// // only in a specific file. This will define the property in an unnamed
-// // namespace which cannot be accessed from another file.
-// MUS_DEFINE_LOCAL_WINDOW_PROPERTY_KEY(MyType, kMyKey, MyDefault);
-//
-// } // foo namespace
-//
-// To define a new type used for WindowProperty.
-//
-// // outside all namespaces:
-// MUS_DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(FOO_EXPORT, MyType)
-//
-// If a property type is not exported, use
-// MUS_DECLARE_WINDOW_PROPERTY_TYPE(MyType) which is a shorthand for
-// MUS_DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(, MyType).
-
-namespace mus {
-
-template <typename T>
-void Window::SetSharedProperty(const std::string& name, const T& data) {
- const std::vector<uint8_t> bytes =
- mojo::TypeConverter<std::vector<uint8_t>, T>::Convert(data);
- SetSharedPropertyInternal(name, &bytes);
-}
-
-template <typename T>
-T Window::GetSharedProperty(const std::string& name) const {
- DCHECK(HasSharedProperty(name));
- auto it = properties_.find(name);
- return mojo::TypeConverter<T, std::vector<uint8_t>>::Convert(it->second);
-}
-
-namespace {
-
-// No single new-style cast works for every conversion to/from int64_t, so we
-// need this helper class. A third specialization is needed for bool because
-// MSVC warning C4800 (forcing value to bool) is not suppressed by an explicit
-// cast (!).
-template <typename T>
-class WindowPropertyCaster {
- public:
- static int64_t ToInt64(T x) { return static_cast<int64_t>(x); }
- static T FromInt64(int64_t x) { return static_cast<T>(x); }
-};
-template <typename T>
-class WindowPropertyCaster<T*> {
- public:
- static int64_t ToInt64(T* x) { return reinterpret_cast<int64_t>(x); }
- static T* FromInt64(int64_t x) { return reinterpret_cast<T*>(x); }
-};
-template <>
-class WindowPropertyCaster<bool> {
- public:
- static int64_t ToInt64(bool x) { return static_cast<int64_t>(x); }
- static bool FromInt64(int64_t x) { return x != 0; }
-};
-
-} // namespace
-
-template <typename T>
-struct WindowProperty {
- T default_value;
- const char* name;
- Window::PropertyDeallocator deallocator;
-};
-
-template <typename T>
-void Window::SetLocalProperty(const WindowProperty<T>* property, T value) {
- int64_t old = SetLocalPropertyInternal(
- property, property->name,
- value == property->default_value ? nullptr : property->deallocator,
- WindowPropertyCaster<T>::ToInt64(value),
- WindowPropertyCaster<T>::ToInt64(property->default_value));
- if (property->deallocator &&
- old != WindowPropertyCaster<T>::ToInt64(property->default_value)) {
- (*property->deallocator)(old);
- }
-}
-
-template <typename T>
-T Window::GetLocalProperty(const WindowProperty<T>* property) const {
- return WindowPropertyCaster<T>::FromInt64(GetLocalPropertyInternal(
- property, WindowPropertyCaster<T>::ToInt64(property->default_value)));
-}
-
-template <typename T>
-void Window::ClearLocalProperty(const WindowProperty<T>* property) {
- SetLocalProperty(property, property->default_value);
-}
-
-} // namespace mus
-
-// Macros to instantiate the property getter/setter template functions.
-#define MUS_DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(EXPORT, T) \
- template EXPORT void mus::Window::SetLocalProperty( \
- const mus::WindowProperty<T>*, T); \
- template EXPORT T mus::Window::GetLocalProperty( \
- const mus::WindowProperty<T>*) const; \
- template EXPORT void mus::Window::ClearLocalProperty( \
- const mus::WindowProperty<T>*);
-#define MUS_DECLARE_WINDOW_PROPERTY_TYPE(T) \
- MUS_DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(, T)
-
-#define MUS_DEFINE_WINDOW_PROPERTY_KEY(TYPE, NAME, DEFAULT) \
- static_assert(sizeof(TYPE) <= sizeof(int64_t), \
- "Property type must fit in 64 bits"); \
- namespace { \
- const mus::WindowProperty<TYPE> NAME##_Value = {DEFAULT, #NAME, nullptr}; \
- } \
- const mus::WindowProperty<TYPE>* const NAME = &NAME##_Value;
-
-#define MUS_DEFINE_LOCAL_WINDOW_PROPERTY_KEY(TYPE, NAME, DEFAULT) \
- static_assert(sizeof(TYPE) <= sizeof(int64_t), \
- "Property type must fit in 64 bits"); \
- namespace { \
- const mus::WindowProperty<TYPE> NAME##_Value = {DEFAULT, #NAME, nullptr}; \
- const mus::WindowProperty<TYPE>* const NAME = &NAME##_Value; \
- }
-
-#define MUS_DEFINE_OWNED_WINDOW_PROPERTY_KEY(TYPE, NAME, DEFAULT) \
- namespace { \
- void Deallocator##NAME(int64_t p) { \
- enum { type_must_be_complete = sizeof(TYPE) }; \
- delete mus::WindowPropertyCaster<TYPE*>::FromInt64(p); \
- } \
- const mus::WindowProperty<TYPE*> NAME##_Value = {DEFAULT, #NAME, \
- &Deallocator##NAME}; \
- } \
- const mus::WindowProperty<TYPE*>* const NAME = &NAME##_Value;
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_PROPERTY_H_
diff --git a/chromium/components/mus/public/cpp/window_surface.h b/chromium/components/mus/public/cpp/window_surface.h
deleted file mode 100644
index 97af8123d61..00000000000
--- a/chromium/components/mus/public/cpp/window_surface.h
+++ /dev/null
@@ -1,85 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_SURFACE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_SURFACE_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "base/threading/thread_checker.h"
-#include "components/mus/public/interfaces/surface.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/interface_ptr_info.h"
-
-namespace mus {
-
-class WindowSurfaceBinding;
-class WindowSurfaceClient;
-class Window;
-
-// A WindowSurface is wrapper to simplify submitting CompositorFrames to
-// Windows, and receiving ReturnedResources.
-class WindowSurface : public mojom::SurfaceClient {
- public:
- // static
- static std::unique_ptr<WindowSurface> Create(
- std::unique_ptr<WindowSurfaceBinding>* surface_binding);
-
- ~WindowSurface() override;
-
- // Called to indicate that the current thread has assumed control of this
- // object.
- void BindToThread();
-
- void SubmitCompositorFrame(cc::CompositorFrame frame,
- const base::Closure& callback);
-
- void set_client(WindowSurfaceClient* client) { client_ = client; }
-
- private:
- friend class Window;
-
- WindowSurface(mojo::InterfacePtrInfo<mojom::Surface> surface_info,
- mojo::InterfaceRequest<mojom::SurfaceClient> client_request);
-
- // SurfaceClient implementation:
- void ReturnResources(mojo::Array<cc::ReturnedResource> resources) override;
-
- WindowSurfaceClient* client_;
- mojo::InterfacePtrInfo<mojom::Surface> surface_info_;
- mojo::InterfaceRequest<mojom::SurfaceClient> client_request_;
- mojom::SurfacePtr surface_;
- std::unique_ptr<mojo::Binding<mojom::SurfaceClient>> client_binding_;
- std::unique_ptr<base::ThreadChecker> thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowSurface);
-};
-
-// A WindowSurfaceBinding is a bundle of mojo interfaces that are to be used by
-// or implemented by the Mus window server when passed into
-// Window::AttachSurface. WindowSurfaceBinding has no standalone functionality.
-class WindowSurfaceBinding {
- public:
- ~WindowSurfaceBinding();
-
- private:
- friend class WindowSurface;
- friend class Window;
-
- WindowSurfaceBinding(
- mojo::InterfaceRequest<mojom::Surface> surface_request,
- mojo::InterfacePtrInfo<mojom::SurfaceClient> surface_client);
-
- mojo::InterfaceRequest<mojom::Surface> surface_request_;
- mojo::InterfacePtrInfo<mojom::SurfaceClient> surface_client_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowSurfaceBinding);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_SURFACE_H_
diff --git a/chromium/components/mus/public/cpp/window_surface_client.h b/chromium/components/mus/public/cpp/window_surface_client.h
deleted file mode 100644
index 1208d2028f2..00000000000
--- a/chromium/components/mus/public/cpp/window_surface_client.h
+++ /dev/null
@@ -1,24 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_SURFACE_CLIENT_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_SURFACE_CLIENT_H_
-
-namespace mus {
-
-class WindowSurface;
-
-class WindowSurfaceClient {
- public:
- virtual void OnResourcesReturned(
- WindowSurface* surface,
- mojo::Array<cc::ReturnedResource> resources) = 0;
-
- protected:
- virtual ~WindowSurfaceClient() {}
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_SURFACE_CLIENT_H_
diff --git a/chromium/components/mus/public/cpp/window_tracker.h b/chromium/components/mus/public/cpp/window_tracker.h
deleted file mode 100644
index db277531495..00000000000
--- a/chromium/components/mus/public/cpp/window_tracker.h
+++ /dev/null
@@ -1,21 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TRACKER_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TRACKER_H_
-
-#include <stdint.h>
-#include <set>
-
-#include "base/macros.h"
-#include "components/mus/public/cpp/window_observer.h"
-#include "ui/base/window_tracker_template.h"
-
-namespace mus {
-
-using WindowTracker = ui::WindowTrackerTemplate<Window, WindowObserver>;
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TRACKER_H_
diff --git a/chromium/components/mus/public/cpp/window_tree_client.h b/chromium/components/mus/public/cpp/window_tree_client.h
deleted file mode 100644
index 24ef564f3f5..00000000000
--- a/chromium/components/mus/public/cpp/window_tree_client.h
+++ /dev/null
@@ -1,407 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CLIENT_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CLIENT_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/atomicops.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "components/mus/common/types.h"
-#include "components/mus/public/cpp/window.h"
-#include "components/mus/public/cpp/window_manager_delegate.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace display {
-class Display;
-}
-
-namespace gfx {
-class Insets;
-class Size;
-}
-
-namespace shell {
-class Connector;
-}
-
-namespace mus {
-class InFlightChange;
-class WindowTreeClientDelegate;
-class WindowTreeClientPrivate;
-class WindowTreeClientObserver;
-enum class ChangeType;
-
-// Manages the connection with mus.
-//
-// WindowTreeClient is deleted by any of the following:
-// . If all the roots of the connection are destroyed and the connection is
-// configured to delete when there are no roots (true if the WindowTreeClient
-// is created with a mojom::WindowTreeClientRequest). This happens
-// if the owner of the roots Embed()s another app in all the roots, or all
-// the roots are explicitly deleted.
-// . The connection to mus is lost.
-// . Explicitly by way of calling delete.
-//
-// When WindowTreeClient is deleted all windows are deleted (and observers
-// notified). This is followed by calling
-// WindowTreeClientDelegate::OnWindowTreeClientDestroyed().
-class WindowTreeClient : public mojom::WindowTreeClient,
- public mojom::WindowManager,
- public WindowManagerClient {
- public:
- WindowTreeClient(WindowTreeClientDelegate* delegate,
- WindowManagerDelegate* window_manager_delegate,
- mojom::WindowTreeClientRequest request);
- ~WindowTreeClient() override;
-
- // Establishes the connection by way of the WindowTreeFactory.
- void ConnectViaWindowTreeFactory(shell::Connector* connector);
-
- // Establishes the connection by way of WindowManagerWindowTreeFactory.
- void ConnectAsWindowManager(shell::Connector* connector);
-
- // Wait for OnEmbed(), returning when done.
- void WaitForEmbed();
-
- bool connected() const { return tree_ != nullptr; }
- ClientSpecificId client_id() const { return client_id_; }
-
- // API exposed to the window implementations that pushes local changes to the
- // service.
- void DestroyWindow(Window* window);
-
- // These methods take TransportIds. For windows owned by the current client,
- // the client id high word can be zero. In all cases, the TransportId 0x1
- // refers to the root window.
- void AddChild(Window* parent, Id child_id);
- void RemoveChild(Window* parent, Id child_id);
-
- void AddTransientWindow(Window* window, Id transient_window_id);
- void RemoveTransientWindowFromParent(Window* window);
-
- void SetModal(Window* window);
-
- void Reorder(Window* window,
- Id relative_window_id,
- mojom::OrderDirection direction);
-
- // Returns true if the specified window was created by this client.
- bool OwnsWindow(Window* window) const;
-
- void SetBounds(Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& bounds);
- void SetCapture(Window* window);
- void ReleaseCapture(Window* window);
- void SetClientArea(Id window_id,
- const gfx::Insets& client_area,
- const std::vector<gfx::Rect>& additional_client_areas);
- void SetHitTestMask(Id window_id, const gfx::Rect& mask);
- void ClearHitTestMask(Id window_id);
- void SetFocus(Window* window);
- void SetCanFocus(Id window_id, bool can_focus);
- void SetPredefinedCursor(Id window_id, mus::mojom::Cursor cursor_id);
- void SetVisible(Window* window, bool visible);
- void SetOpacity(Window* window, float opacity);
- void SetProperty(Window* window,
- const std::string& name,
- mojo::Array<uint8_t> data);
- void SetWindowTextInputState(Id window_id, mojo::TextInputStatePtr state);
- void SetImeVisibility(Id window_id,
- bool visible,
- mojo::TextInputStatePtr state);
-
- void Embed(Id window_id,
- mojom::WindowTreeClientPtr client,
- uint32_t flags,
- const mojom::WindowTree::EmbedCallback& callback);
-
- void RequestClose(Window* window);
-
- void AttachSurface(Id window_id,
- mojom::SurfaceType type,
- mojo::InterfaceRequest<mojom::Surface> surface,
- mojom::SurfaceClientPtr client);
-
- // Sets the input capture to |window| without notifying the server.
- void LocalSetCapture(Window* window);
- // Sets focus to |window| without notifying the server.
- void LocalSetFocus(Window* window);
-
- // Start/stop tracking windows. While tracked, they can be retrieved via
- // WindowTreeClient::GetWindowById.
- void AddWindow(Window* window);
-
- bool IsRoot(Window* window) const { return roots_.count(window) > 0; }
-
- void OnWindowDestroying(Window* window);
-
- // Called after the window's observers have been notified of destruction (as
- // the last step of ~Window).
- void OnWindowDestroyed(Window* window);
-
- Window* GetWindowByServerId(Id id);
-
- // Sets whether this is deleted when there are no roots. The default is to
- // delete when there are no roots.
- void SetDeleteOnNoRoots(bool value);
-
- // Returns the root of this connection.
- const std::set<Window*>& GetRoots();
-
- // Returns the Window with input capture; null if no window has requested
- // input capture, or if another app has capture.
- Window* GetCaptureWindow();
-
- // Returns the focused window; null if focus is not yet known or another app
- // is focused.
- Window* GetFocusedWindow();
-
- // Sets focus to null. This does nothing if focus is currently null.
- void ClearFocus();
-
- // Returns the current location of the mouse on screen. Note: this method may
- // race the asynchronous initialization; but in that case we return (0, 0).
- gfx::Point GetCursorScreenPoint();
-
- // See description in window_tree.mojom. When an existing event observer is
- // updated or cleared then any future events from the server for that observer
- // will be ignored.
- void SetEventObserver(mojom::EventMatcherPtr matcher);
-
- // Creates and returns a new Window (which is owned by the window server).
- // Windows are initially hidden, use SetVisible(true) to show.
- Window* NewWindow() { return NewWindow(nullptr); }
- Window* NewWindow(
- const std::map<std::string, std::vector<uint8_t>>* properties);
- Window* NewTopLevelWindow(
- const std::map<std::string, std::vector<uint8_t>>* properties);
-
- void AddObserver(WindowTreeClientObserver* observer);
- void RemoveObserver(WindowTreeClientObserver* observer);
-
-#if !defined(NDEBUG)
- std::string GetDebugWindowHierarchy() const;
- void BuildDebugInfo(const std::string& depth,
- Window* window,
- std::string* result) const;
-#endif
-
- private:
- friend class WindowTreeClientPrivate;
-
- enum class NewWindowType {
- CHILD,
- TOP_LEVEL,
- };
-
- using IdToWindowMap = std::map<Id, Window*>;
-
- // TODO(sky): this assumes change_ids never wrap, which is a bad assumption.
- using InFlightMap = std::map<uint32_t, std::unique_ptr<InFlightChange>>;
-
- // Returns the oldest InFlightChange that matches |change|.
- InFlightChange* GetOldestInFlightChangeMatching(const InFlightChange& change);
-
- // See InFlightChange for details on how InFlightChanges are used.
- uint32_t ScheduleInFlightChange(std::unique_ptr<InFlightChange> change);
-
- // Returns true if there is an InFlightChange that matches |change|. If there
- // is an existing change SetRevertValueFrom() is invoked on it. Returns false
- // if there is no InFlightChange matching |change|.
- // See InFlightChange for details on how InFlightChanges are used.
- bool ApplyServerChangeToExistingInFlightChange(const InFlightChange& change);
-
- Window* NewWindowImpl(NewWindowType type,
- const Window::SharedProperties* properties);
-
- // Sets the mojom::WindowTree implementation.
- void SetWindowTree(mojom::WindowTreePtr window_tree_ptr);
-
- // Called when the mojom::WindowTree connection is lost, deletes this.
- void OnConnectionLost();
-
- // OnEmbed() calls into this. Exposed as a separate function for testing.
- void OnEmbedImpl(mojom::WindowTree* window_tree,
- ClientSpecificId client_id,
- mojom::WindowDataPtr root_data,
- int64_t display_id,
- Id focused_window_id,
- bool drawn);
-
- // Called by WmNewDisplayAdded().
- void WmNewDisplayAddedImpl(const display::Display& display,
- mojom::WindowDataPtr root_data,
- bool parent_drawn);
-
- void OnReceivedCursorLocationMemory(mojo::ScopedSharedBufferHandle handle);
-
- // Overridden from WindowTreeClient:
- void OnEmbed(ClientSpecificId client_id,
- mojom::WindowDataPtr root,
- mojom::WindowTreePtr tree,
- int64_t display_id,
- Id focused_window_id,
- bool drawn) override;
- void OnEmbeddedAppDisconnected(Id window_id) override;
- void OnUnembed(Id window_id) override;
- void OnLostCapture(Id window_id) override;
- void OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr data,
- int64_t display_id,
- bool drawn) override;
- void OnWindowBoundsChanged(Id window_id,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) override;
- void OnClientAreaChanged(
- uint32_t window_id,
- const gfx::Insets& new_client_area,
- mojo::Array<gfx::Rect> new_additional_client_areas) override;
- void OnTransientWindowAdded(uint32_t window_id,
- uint32_t transient_window_id) override;
- void OnTransientWindowRemoved(uint32_t window_id,
- uint32_t transient_window_id) override;
- void OnWindowHierarchyChanged(
- Id window_id,
- Id old_parent_id,
- Id new_parent_id,
- mojo::Array<mojom::WindowDataPtr> windows) override;
- void OnWindowReordered(Id window_id,
- Id relative_window_id,
- mojom::OrderDirection direction) override;
- void OnWindowDeleted(Id window_id) override;
- void OnWindowVisibilityChanged(Id window_id, bool visible) override;
- void OnWindowOpacityChanged(Id window_id,
- float old_opacity,
- float new_opacity) override;
- void OnWindowParentDrawnStateChanged(Id window_id, bool drawn) override;
- void OnWindowSharedPropertyChanged(Id window_id,
- const mojo::String& name,
- mojo::Array<uint8_t> new_data) override;
- void OnWindowInputEvent(uint32_t event_id,
- Id window_id,
- std::unique_ptr<ui::Event> event,
- uint32_t event_observer_id) override;
- void OnEventObserved(std::unique_ptr<ui::Event> event,
- uint32_t event_observer_id) override;
- void OnWindowFocused(Id focused_window_id) override;
- void OnWindowPredefinedCursorChanged(Id window_id,
- mojom::Cursor cursor) override;
- void OnChangeCompleted(uint32_t change_id, bool success) override;
- void RequestClose(uint32_t window_id) override;
- void GetWindowManager(
- mojo::AssociatedInterfaceRequest<WindowManager> internal) override;
-
- // Overridden from WindowManager:
- void OnConnect(ClientSpecificId client_id) override;
- void WmNewDisplayAdded(mojom::DisplayPtr display,
- mojom::WindowDataPtr root_data,
- bool parent_drawn) override;
- void WmSetBounds(uint32_t change_id,
- Id window_id,
- const gfx::Rect& transit_bounds) override;
- void WmSetProperty(uint32_t change_id,
- Id window_id,
- const mojo::String& name,
- mojo::Array<uint8_t> transit_data) override;
- void WmCreateTopLevelWindow(uint32_t change_id,
- ClientSpecificId requesting_client_id,
- mojo::Map<mojo::String, mojo::Array<uint8_t>>
- transport_properties) override;
- void WmClientJankinessChanged(ClientSpecificId client_id,
- bool janky) override;
- void OnAccelerator(uint32_t id, std::unique_ptr<ui::Event> event) override;
-
- // Overridden from WindowManagerClient:
- void SetFrameDecorationValues(
- mojom::FrameDecorationValuesPtr values) override;
- void SetNonClientCursor(Window* window,
- mus::mojom::Cursor cursor_id) override;
- void AddAccelerator(uint32_t id,
- mojom::EventMatcherPtr event_matcher,
- const base::Callback<void(bool)>& callback) override;
- void RemoveAccelerator(uint32_t id) override;
- void AddActivationParent(Window* window) override;
- void RemoveActivationParent(Window* window) override;
- void ActivateNextWindow() override;
- void SetUnderlaySurfaceOffsetAndExtendedHitArea(
- Window* window,
- const gfx::Vector2d& offset,
- const gfx::Insets& hit_area) override;
-
- // The one int in |cursor_location_mapping_|. When we read from this
- // location, we must always read from it atomically.
- base::subtle::Atomic32* cursor_location_memory() {
- return reinterpret_cast<base::subtle::Atomic32*>(
- cursor_location_mapping_.get());
- }
-
- // This is set once and only once when we get OnEmbed(). It gives the unique
- // id for this client.
- ClientSpecificId client_id_;
-
- // Id assigned to the next window created.
- ClientSpecificId next_window_id_;
-
- // Id used for the next change id supplied to the server.
- uint32_t next_change_id_;
- InFlightMap in_flight_map_;
-
- WindowTreeClientDelegate* delegate_;
-
- WindowManagerDelegate* window_manager_delegate_;
-
- std::set<Window*> roots_;
-
- IdToWindowMap windows_;
- std::map<ClientSpecificId, std::set<Window*>> embedded_windows_;
-
- Window* capture_window_;
-
- Window* focused_window_;
-
- mojo::Binding<mojom::WindowTreeClient> binding_;
- mojom::WindowTreePtr tree_ptr_;
- // Typically this is the value contained in |tree_ptr_|, but tests may
- // directly set this.
- mojom::WindowTree* tree_;
-
- bool delete_on_no_roots_;
-
- bool in_destructor_;
-
- // A mapping to shared memory that is one 32 bit integer long. The window
- // server uses this to let us synchronously read the cursor location.
- mojo::ScopedSharedBufferMapping cursor_location_mapping_;
-
- base::ObserverList<WindowTreeClientObserver> observers_;
-
- std::unique_ptr<mojo::AssociatedBinding<mojom::WindowManager>>
- window_manager_internal_;
- mojom::WindowManagerClientAssociatedPtr window_manager_internal_client_;
-
- bool has_event_observer_ = false;
-
- // Monotonically increasing ID for event observers.
- uint32_t event_observer_id_ = 0u;
-
- base::WeakPtrFactory<WindowTreeClient> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTreeClient);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CLIENT_H_
diff --git a/chromium/components/mus/public/cpp/window_tree_client_delegate.h b/chromium/components/mus/public/cpp/window_tree_client_delegate.h
deleted file mode 100644
index 41f09dfdbf0..00000000000
--- a/chromium/components/mus/public/cpp/window_tree_client_delegate.h
+++ /dev/null
@@ -1,53 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CLIENT_DELEGATE_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CLIENT_DELEGATE_H_
-
-#include <string>
-
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "services/shell/public/interfaces/interface_provider.mojom.h"
-
-namespace ui {
-class Event;
-}
-
-namespace mus {
-
-class Window;
-class WindowTreeClient;
-
-// Interface implemented by an application using mus.
-class WindowTreeClientDelegate {
- public:
- // Called when the application implementing this interface is embedded at
- // |root|.
- // NOTE: this is only invoked if the WindowTreeClient is created with an
- // InterfaceRequest.
- virtual void OnEmbed(Window* root) = 0;
-
- // Sent when another app is embedded in |root| (one of the roots of the
- // connection). Afer this call |root| is deleted. If |root| is the only root
- // and the connection is configured to delete when there are no roots (the
- // default), then after |root| is destroyed the connection is destroyed as
- // well.
- virtual void OnUnembed(Window* root);
-
- // Called from the destructor of WindowTreeClient after all the Windows have
- // been destroyed. |client| is no longer valid after this call.
- virtual void OnWindowTreeClientDestroyed(WindowTreeClient* client) = 0;
-
- // Called when the WindowTreeClient receives an input event observed via
- // SetEventObserver(). |target| may be null for events that were sent to
- // windows owned by other processes.
- virtual void OnEventObserved(const ui::Event& event, Window* target) = 0;
-
- protected:
- virtual ~WindowTreeClientDelegate() {}
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CLIENT_DELEGATE_H_
diff --git a/chromium/components/mus/public/cpp/window_tree_client_observer.h b/chromium/components/mus/public/cpp/window_tree_client_observer.h
deleted file mode 100644
index 394a5cea1e1..00000000000
--- a/chromium/components/mus/public/cpp/window_tree_client_observer.h
+++ /dev/null
@@ -1,27 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CLIENT_OBSERVER_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CLIENT_OBSERVER_H_
-
-namespace mus {
-
-class Window;
-class WindowTreeClient;
-
-class WindowTreeClientObserver {
- public:
- virtual void OnWindowTreeFocusChanged(Window* gained_focus,
- Window* lost_focus) {}
-
- // Called right before the client is destroyed.
- virtual void OnWillDestroyClient(WindowTreeClient* client) {}
-
- protected:
- virtual ~WindowTreeClientObserver() {}
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_CLIENT_OBSERVER_H_
diff --git a/chromium/components/mus/public/cpp/window_tree_host_factory.h b/chromium/components/mus/public/cpp/window_tree_host_factory.h
deleted file mode 100644
index 75661af89d6..00000000000
--- a/chromium/components/mus/public/cpp/window_tree_host_factory.h
+++ /dev/null
@@ -1,37 +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 COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_HOST_FACTORY_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_HOST_FACTORY_H_
-
-#include <memory>
-
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/public/interfaces/window_tree_host.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace shell {
-class Connector;
-}
-
-namespace mus {
-
-class WindowManagerDelegate;
-class WindowTreeClientDelegate;
-
-// The following create a new window tree host. Supply a |factory| if you have
-// already connected to mus, otherwise supply |shell|, which contacts mus and
-// obtains a WindowTreeHostFactory.
-void CreateWindowTreeHost(mojom::WindowTreeHostFactory* factory,
- WindowTreeClientDelegate* delegate,
- mojom::WindowTreeHostPtr* host,
- WindowManagerDelegate* window_manager_delegate);
-void CreateWindowTreeHost(shell::Connector* connector,
- WindowTreeClientDelegate* delegate,
- mojom::WindowTreeHostPtr* host,
- WindowManagerDelegate* window_manager_delegate);
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_PUBLIC_CPP_WINDOW_TREE_HOST_FACTORY_H_
diff --git a/chromium/components/mus/public/interfaces/BUILD.gn b/chromium/components/mus/public/interfaces/BUILD.gn
deleted file mode 100644
index 33a07da3831..00000000000
--- a/chromium/components/mus/public/interfaces/BUILD.gn
+++ /dev/null
@@ -1,46 +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("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("interfaces") {
- sources = [
- "accelerator_registrar.mojom",
- "animations.mojom",
- "channel_handle.mojom",
- "clipboard.mojom",
- "command_buffer.mojom",
- "cursor.mojom",
- "display.mojom",
- "event_matcher.mojom",
- "gpu.mojom",
- "gpu_memory_buffer.mojom",
- "gpu_service.mojom",
- "mus_constants.mojom",
- "surface.mojom",
- "user_access_manager.mojom",
- "user_activity_monitor.mojom",
- "window_manager.mojom",
- "window_manager_constants.mojom",
- "window_manager_window_tree_factory.mojom",
- "window_server_test.mojom",
- "window_tree.mojom",
- "window_tree_constants.mojom",
- "window_tree_host.mojom",
- ]
-
- import_dirs = [
- get_path_info("../../../..", "abspath"),
- "//mojo/services",
- ]
-
- public_deps = [
- "//cc/ipc:interfaces",
- "//gpu/ipc/common:interfaces",
- "//ui/events/mojo:interfaces",
- "//ui/gfx/geometry/mojo",
- "//ui/gfx/mojo",
- "//ui/platform_window/mojo:interfaces",
- ]
-}
diff --git a/chromium/components/mus/public/interfaces/accelerator_registrar.mojom b/chromium/components/mus/public/interfaces/accelerator_registrar.mojom
deleted file mode 100644
index 00948424eb3..00000000000
--- a/chromium/components/mus/public/interfaces/accelerator_registrar.mojom
+++ /dev/null
@@ -1,22 +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.
-
-module mus.mojom;
-
-import "components/mus/public/interfaces/event_matcher.mojom";
-import "ui/events/mojo/event.mojom";
-
-interface AcceleratorHandler {
- OnAccelerator(uint32 id, ui.mojom.Event event);
-};
-
-interface AcceleratorRegistrar {
- // The AcceleratorHandler is responsible for handling all the accelerators
- // registered from this AcceleratorRegistrar connection.
- SetHandler(AcceleratorHandler handler);
-
- // An AcceleratorHandler must be set before accelerators can be added.
- AddAccelerator(uint32 id, EventMatcher matcher) => (bool success);
- RemoveAccelerator(uint32 id);
-};
diff --git a/chromium/components/mus/public/interfaces/animations.mojom b/chromium/components/mus/public/interfaces/animations.mojom
deleted file mode 100644
index 847b406ed0d..00000000000
--- a/chromium/components/mus/public/interfaces/animations.mojom
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-import "ui/gfx/mojo/transform.mojom";
-
-enum AnimationTweenType {
- LINEAR,
- EASE_IN,
- EASE_OUT,
- EASE_IN_OUT,
-};
-
-enum AnimationProperty {
- // Used for pausing.
- NONE,
- OPACITY,
- TRANSFORM,
-};
-
-struct AnimationValue {
- float float_value;
- gfx.mojom.Transform? transform;
-};
-
-// Identifies how a particular property should be animated between a start and
-// target value.
-struct AnimationElement {
- AnimationProperty property;
-
- // Duration is in microseconds.
- int64 duration;
-
- AnimationTweenType tween_type;
-
- // If not specified the start value is taken from either the current value
- // (for the first element) or the target_value of the previous element.
- AnimationValue? start_value;
-
- // target_value may be null when property is NONE.
- AnimationValue? target_value;
-};
-
-// An AnimationSequence consists of a number of AnimationElements to animate.
-// Each element is animated serially.
-struct AnimationSequence {
- // Number of times to run the sequence. Value of 0 means run until
- // explicitly stopped.
- uint32 cycle_count;
-
- array<AnimationElement> elements;
-};
-
-// AnimationGroup identifies a window and a set of AnimationSequences to apply
-// to the window. Each sequence is run in parallel.
-struct AnimationGroup {
- uint32 window_id;
- array<AnimationSequence> sequences;
-};
diff --git a/chromium/components/mus/public/interfaces/channel_handle.mojom b/chromium/components/mus/public/interfaces/channel_handle.mojom
deleted file mode 100644
index d78a53f5977..00000000000
--- a/chromium/components/mus/public/interfaces/channel_handle.mojom
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-// See IPC::ChannelHandle in src/ipc/ipc_channel_handle.h
-struct ChannelHandle {
- string name;
-
- // On POSIX, it is one endpoint of a socket pair. On Windows, it is not used.
- handle socket;
-};
diff --git a/chromium/components/mus/public/interfaces/clipboard.mojom b/chromium/components/mus/public/interfaces/clipboard.mojom
deleted file mode 100644
index 201a7c3dea5..00000000000
--- a/chromium/components/mus/public/interfaces/clipboard.mojom
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-const string kMimeTypeHTML = "text/html";
-const string kMimeTypeMozillaURL = "text/x-moz-url";
-const string kMimeTypePNG = "image/png";
-const string kMimeTypeRTF = "text/rtf";
-const string kMimeTypeText = "text/plain";
-const string kMimeTypeURIList = "text/uri-list";
-const string kMimeTypeURL = "text/url";
-
-interface Clipboard {
- enum Type {
- COPY_PASTE = 0,
- SELECTION = 1,
- DRAG = 2
- };
-
- // Returns a sequence number which uniquely identifies clipboard state.
- // Clients are able to assume that the clipboard contents are unchanged as
- // long as this number has not changed. This number is monotonically
- // increasing, is increased when the clipboard state changes, and is
- // provided by Windows, Linux, and Mac.
- [Sync]
- GetSequenceNumber(Type clipboard_type) => (uint64 sequence);
-
- // Returns the available mime types, and the current sequence number.
- [Sync]
- GetAvailableMimeTypes(Type clipboard_types)
- => (uint64 sequence, array<string> types);
-
- // Returns the current data associated with the requested Mime type.
- //
- // We don't want to provide one API to return the entire clipboard state
- // because the combined size of the clipboard can be megabytes, especially
- // when image data is involved.
- [Sync]
- ReadClipboardData(Type clipboard_type, string mime_type)
- => (uint64 sequence, array<uint8>? data);
-
- // Writes a set of mime types to the clipboard. This will increment the
- // sequence number and return that. In the case of an empty or null map,
- // this will just clear the clipboard.
- [Sync]
- WriteClipboardData(Type clipboard_type, map<string, array<uint8>>? data)
- => (uint64 sequence);
-};
diff --git a/chromium/components/mus/public/interfaces/command_buffer.mojom b/chromium/components/mus/public/interfaces/command_buffer.mojom
deleted file mode 100644
index f9a977135e7..00000000000
--- a/chromium/components/mus/public/interfaces/command_buffer.mojom
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-import "gpu/ipc/common/capabilities.mojom";
-import "gpu/ipc/common/command_buffer.mojom";
-import "gpu/ipc/common/mailbox.mojom";
-import "gpu/ipc/common/sync_token.mojom";
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-struct CommandBufferInitializeResult {
- int32 command_buffer_namespace;
- uint64 command_buffer_id;
- gpu.mojom.Capabilities capabilities;
-};
-
-interface CommandBufferClient {
- Destroyed(int32 context_lost_reason,
- int32 error);
- SignalAck(uint32 id);
- // TODO(penghuang): support latency_info and use gfx::SwapResult for result.
- SwapBuffersCompleted(/* array<ui.mojom.LatencyInfo> latency_info, */
- int32 result);
- UpdateState(gpu.mojom.CommandBufferState state);
- // TODO(penghuang): use base::TimeTicks & base::TimeDelta.
- UpdateVSyncParameters(int64 timebase, int64 interval);
-};
-
-interface CommandBuffer {
- // Initialize attempts to initialize the command buffer.
- // If the context is lost after creation the LostContext method on the
- // CommandBufferClient's will be called then this pipe will be
- // closed.
- Initialize(CommandBufferClient client,
- handle<shared_buffer> shared_state,
- array<int32> attribs) => (CommandBufferInitializeResult? result);
- SetGetBuffer(int32 buffer);
- Flush(int32 put_offset);
- MakeProgress(int32 last_get_offset) => (gpu.mojom.CommandBufferState state);
- RegisterTransferBuffer(
- int32 id, handle<shared_buffer> transfer_buffer, uint32 size);
- DestroyTransferBuffer(int32 id);
- CreateImage(int32 id,
- handle memory_handle,
- int32 type,
- gfx.mojom.Size size,
- int32 format,
- int32 internal_format);
- DestroyImage(int32 id);
- CreateStreamTexture(uint32 client_texture_id)
- => (int32 stream_id, bool succeeded);
- TakeFrontBuffer(gpu.mojom.Mailbox mailbox);
- ReturnFrontBuffer(gpu.mojom.Mailbox mailbox, bool is_lost);
- SignalQuery(uint32 query, uint32 signal_id);
- SignalSyncToken(gpu.mojom.SyncToken sync_token, uint32 signal_id);
- WaitForGetOffsetInRange(int32 start, int32 end)
- => (gpu.mojom.CommandBufferState state);
- WaitForTokenInRange(int32 start, int32 end)
- => (gpu.mojom.CommandBufferState state);
-};
diff --git a/chromium/components/mus/public/interfaces/cursor.mojom b/chromium/components/mus/public/interfaces/cursor.mojom
deleted file mode 100644
index 878cd0113cd..00000000000
--- a/chromium/components/mus/public/interfaces/cursor.mojom
+++ /dev/null
@@ -1,57 +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.
-
-module mus.mojom;
-
-// Standard Cursor numbers. These are the same as Chrome's ui::Cursor and
-// blink's WebCursorInfo.
-enum Cursor {
- // NULL is kept for compatibility with chrome declarations. In chrome code, it
- // is treated exactly like POINTER, the default pointer.
- CURSOR_NULL = 0,
- POINTER,
- CROSS,
- HAND,
- IBEAM,
- WAIT,
- HELP,
- EAST_RESIZE,
- NORTH_RESIZE,
- NORTH_EAST_RESIZE,
- NORTH_WEST_RESIZE,
- SOUTH_RESIZE,
- SOUTH_EAST_RESIZE,
- SOUTH_WEST_RESIZE,
- WEST_RESIZE,
- NORTH_SOUTH_RESIZE,
- EAST_WEST_RESIZE,
- NORTH_EAST_SOUTH_WEST_RESIZE,
- NORTH_WEST_SOUTH_EAST_RESIZE,
- COLUMN_RESIZE,
- ROW_RESIZE,
- MIDDLE_PANNING,
- EAST_PANNING,
- NORTH_PANNING,
- NORTH_EAST_PANNING,
- NORTH_WEST_PANNING,
- SOUTH_PANNING,
- SOUTH_EAST_PANNING,
- SOUTH_WEST_PANNING,
- WEST_PANNING,
- MOVE,
- VERTICAL_TEXT,
- CELL,
- CONTEXT_MENU,
- ALIAS,
- PROGRESS,
- NO_DROP,
- COPY,
- NONE,
- NOT_ALLOWED,
- ZOOM_IN,
- ZOOM_OUT,
- GRAB,
- GRABBING,
- CUSTOM
-};
diff --git a/chromium/components/mus/public/interfaces/display.mojom b/chromium/components/mus/public/interfaces/display.mojom
deleted file mode 100644
index 71364999b0a..00000000000
--- a/chromium/components/mus/public/interfaces/display.mojom
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-import "components/mus/public/interfaces/window_manager_constants.mojom";
-
-interface DisplayManagerObserver {
- // Sent when the observer is added. Gives the initial state.
- OnDisplays(array<Display> displays);
-
- // The specified set of displays has changed in some way. This is used both
- // when a new display is added, or when a property of a display changes.
- // |displays| does not necessarily contain the complete set of displays,
- // only those that changed.
- OnDisplaysChanged(array<Display> displays);
-
- // An existing display was removed.
- OnDisplayRemoved(int64 id);
-};
-
-interface DisplayManager {
- AddObserver(DisplayManagerObserver observer);
-};
diff --git a/chromium/components/mus/public/interfaces/event_matcher.mojom b/chromium/components/mus/public/interfaces/event_matcher.mojom
deleted file mode 100644
index 34ec670f00f..00000000000
--- a/chromium/components/mus/public/interfaces/event_matcher.mojom
+++ /dev/null
@@ -1,55 +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.
-
-module mus.mojom;
-
-import "ui/events/mojo/event_constants.mojom";
-import "ui/events/mojo/keyboard_codes.mojom";
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-struct KeyEventMatcher {
- ui.mojom.KeyboardCode keyboard_code;
-};
-
-struct PointerKindMatcher {
- ui.mojom.PointerKind pointer_kind;
-};
-
-struct PointerLocationMatcher {
- gfx.mojom.RectF region;
-};
-
-struct EventTypeMatcher {
- ui.mojom.EventType type;
-};
-
-struct EventFlagsMatcher {
- // A bitfield of kEventFlag* and kMouseEventFlag* values in
- // input_event_constants.mojom.
- int32 flags;
-};
-
-// If a specific matcher is missing, then an Event will match this EventMatcher
-// (if relevant). For example, if |type_matcher| is missing, then events of all
-// types will match this EventMatcher. Similarly, if |key_matcher| is missing,
-// then all key-events will match.
-// An example matcher to match the Ctrl+A accelerator would be:
-// - |type_matcher.type| = ui::mojom::EventType::KEY_PRESSED
-// - |flags_matcher.flags| = ui::mojom::kEventVlagControlDown
-// - |key_matcher.keyboard_code| = ui::mojom::KeyboardCode::A
-//
-// A matcher to match any key-press event would be:
-// - |type_matcher.type| = ui::mojom::EventType::KEY_PRESSED
-struct EventMatcher {
- // TODO(jamescook): Move this to somewhere accelerator-specific.
- ui.mojom.AcceleratorPhase accelerator_phase;
- EventTypeMatcher? type_matcher;
- EventFlagsMatcher? flags_matcher;
- // These flags will be stripped from incoming events' flags when comparing
- // against |flags_matcher|.
- EventFlagsMatcher? ignore_flags_matcher;
- KeyEventMatcher? key_matcher;
- PointerKindMatcher? pointer_kind_matcher;
- PointerLocationMatcher? pointer_location_matcher;
-};
diff --git a/chromium/components/mus/public/interfaces/gpu.mojom b/chromium/components/mus/public/interfaces/gpu.mojom
deleted file mode 100644
index 643443d2822..00000000000
--- a/chromium/components/mus/public/interfaces/gpu.mojom
+++ /dev/null
@@ -1,23 +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.
-
-module mus.mojom;
-
-import "components/mus/public/interfaces/command_buffer.mojom";
-
-struct GpuInfo {
- uint32 vendor_id;
- uint32 device_id;
- string vendor_info;
- string renderer_info;
- string driver_version;
-};
-
-interface Gpu {
- // Creates a new offscreen OpenGL ES 2.0 context.
- CreateOffscreenGLES2Context(CommandBuffer& gles2_client);
-
- // Query Gpu information
- GetGpuInfo() => (GpuInfo gpu_info);
-};
diff --git a/chromium/components/mus/public/interfaces/gpu/BUILD.gn b/chromium/components/mus/public/interfaces/gpu/BUILD.gn
deleted file mode 100644
index 6ac8f1c23d3..00000000000
--- a/chromium/components/mus/public/interfaces/gpu/BUILD.gn
+++ /dev/null
@@ -1,17 +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.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("interfaces") {
- sources = [
- "display_compositor.mojom",
- "display_compositor_host.mojom",
- ]
-
- public_deps = [
- "//components/mus/public/interfaces",
- "//gpu/ipc/common:interfaces",
- ]
-}
diff --git a/chromium/components/mus/public/interfaces/gpu/OWNERS b/chromium/components/mus/public/interfaces/gpu/OWNERS
deleted file mode 100644
index 08850f42120..00000000000
--- a/chromium/components/mus/public/interfaces/gpu/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/mus/public/interfaces/gpu/display_compositor.mojom b/chromium/components/mus/public/interfaces/gpu/display_compositor.mojom
deleted file mode 100644
index f8460623ddf..00000000000
--- a/chromium/components/mus/public/interfaces/gpu/display_compositor.mojom
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.gpu.mojom;
-
-import "cc/ipc/compositor_frame.mojom";
-import "cc/ipc/returned_resource.mojom";
-
-
-// Indicates whether the submitted CompositorFrame has been drawn to the display
-// or has been skipped (e.g. another frame may have been submitted before
-// vblank).
-enum CompositorFrameDrawStatus {
- DRAW_SKIPPED,
- DRAWN
-};
-
-// A CompositorFrameSinkFactory represents a single Display client.
-// The client (a process) can use this interface to create
-// CompositorFrameSinks.
-// TODO(fsamuel): This needs a better name.
-interface CompositorFrameSinkFactory {
- // Requests a CompositorFrameSink interface from the display compositor.
- // A CompositorFrameSink has an associated ID consisting of three components:
- // 1. Namespace picked by the service associated with this
- // CompositorFrameSinkFactory.
- // 2. |local_id| which is a monotonically increasing ID allocated by the
- // client.
- // 3. |nonce| is a cryptographically secure random number making this Sink
- // unguessable by other clients.
- CreateCompositorFrameSink(uint32 local_id,
- uint64 nonce,
- CompositorFrameSink& sink,
- CompositorFrameSinkClient client);
-};
-
-// A CompositorFrameSink is an interface for receiving CompositorFrame structs.
-// A CompositorFrame contains the complete output meant for display. Each time a
-// client has a graphical update, and receives an OnBeginFrame, it is
-// responsible for creating a CompositorFrame to update its portion of the
-// screen.
-interface CompositorFrameSink {
- // After the submitted frame is either drawn for the first time by the display
- // compositor or discarded, the callback will be called with the status of the
- // submitted frame. Clients should use this acknowledgement to ratelimit frame
- // submissions.
- // TODO(fsamuel): We should support identifying the CF in the callback.
- SubmitCompositorFrame(cc.mojom.CompositorFrame frame) =>
- (CompositorFrameDrawStatus status);
-
- // Lets the display compositor know that the client wishes to receive the next
- // BeginFrame event.
- SetNeedsBeginFrame(bool needs_begin_frame);
-
- // TODO(fsamuel): ReadbackBitmap API would be useful here.
-};
-
-interface CompositorFrameSinkClient {
- ReturnResources(array<cc.mojom.ReturnedResource> resources);
-};
-
-// This is a public interface implemented by Display clients.
-// Each client implements a single instance of the DisplayClient interface.
-interface DisplayClient {
- // Clients can register CompositorFrameSinks via the provided |factory|.
- OnClientCreated(uint32 client_id, CompositorFrameSinkFactory factory);
-
- // TODO(fsamuel): OnBeginFrame needs to take a BeginFrameArgs instance per
- // cc/output/begin_frame_args.h.
- OnBeginFrame();
-};
diff --git a/chromium/components/mus/public/interfaces/gpu/display_compositor_host.mojom b/chromium/components/mus/public/interfaces/gpu/display_compositor_host.mojom
deleted file mode 100644
index 3c7b6d402f2..00000000000
--- a/chromium/components/mus/public/interfaces/gpu/display_compositor_host.mojom
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.gpu.mojom;
-
-import "components/mus/public/interfaces/gpu/display_compositor.mojom";
-
-// This is a privileged API to be used only by the Mus Window Server.
-// There is one Display per accelerated widget. This corresponds to a physical
-// display on Chrome OS, and a window on other Chrome platforms.
-interface Display {
- // Each client (process) has a unique |client_id| and implements the
- // DisplayClient interface.
- CreateClient(uint32 client_id, DisplayClient& client);
-};
-
-interface DisplayHost {
- // TODO(fsamuel): OnBeginFrame needs to take a BeginFrameArgs instance per
- // cc/output/begin_frame_args.h.
- OnBeginFrame();
-};
-
-// This is a privileged API to be used only by the Mus Window Server.
-// There should be only one DisplayCompositor connection.
-interface DisplayCompositor {
- CreateDisplay(int32 accelerated_widget,
- Display& display,
- DisplayHost display_host,
- CompositorFrameSink& sink,
- CompositorFrameSinkClient client);
-};
diff --git a/chromium/components/mus/public/interfaces/gpu_memory_buffer.mojom b/chromium/components/mus/public/interfaces/gpu_memory_buffer.mojom
deleted file mode 100644
index 0cb6e19ee0a..00000000000
--- a/chromium/components/mus/public/interfaces/gpu_memory_buffer.mojom
+++ /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.
-
-module mus.mojom;
-
-enum BufferFormat {
- ATC,
- ATCIA,
- DXT1,
- DXT5,
- ETC1,
- R_8,
- RGBA_4444,
- RGBX_8888,
- RGBA_8888,
- BGRX_8888,
- BGRA_8888,
- YUV_420,
- YUV_420_BIPLANAR,
- UYVY_422,
- LAST = UYVY_422
-};
-
-enum BufferUsage {
- GPU_READ,
- SCANOUT,
- GPU_READ_CPU_READ_WRITE,
- GPU_READ_CPU_READ_WRITE_PERSISTENT,
- LAST = GPU_READ_CPU_READ_WRITE_PERSISTENT
-};
-
-enum GpuMemoryBufferType {
- EMPTY,
- SHARED_MEMORY,
- IO_SURFACE,
- SURFACE_TEXTURE,
- OZONE_NATIVE_PIXMAP,
- LAST = OZONE_NATIVE_PIXMAP
-};
-
-struct GpuMemoryBufferId {
- int32 id;
-};
-
-struct NativePixmapHandle {
- // A file descriptor for the underlying memory object (usually dmabuf).
- handle fd;
-
- // The stride used when accessing the buffer via a memory mapping.
- int32 stride;
-};
-
-
-struct GpuMemoryBufferHandle {
- GpuMemoryBufferType type;
- GpuMemoryBufferId id;
- handle buffer_handle;
- uint32 offset;
- int32 stride;
- NativePixmapHandle? native_pixmap_handle;
- // TODO(fsamuel): Add support for Machports.
-};
diff --git a/chromium/components/mus/public/interfaces/gpu_service.mojom b/chromium/components/mus/public/interfaces/gpu_service.mojom
deleted file mode 100644
index 64ad2d1b9f0..00000000000
--- a/chromium/components/mus/public/interfaces/gpu_service.mojom
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-import "components/mus/public/interfaces/channel_handle.mojom";
-import "components/mus/public/interfaces/gpu.mojom";
-import "components/mus/public/interfaces/gpu_memory_buffer.mojom";
-import "gpu/ipc/common/sync_token.mojom";
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-interface GpuService {
- // Tells the GPU service to create a new channel for communication with a
- // client. The GPU service responds with client ID, IPC handle and
- // GPUInfo.
- [Sync]
- EstablishGpuChannel()
- => (int32 client_id, ChannelHandle channel_handle, GpuInfo gpu_info);
-
- // Tells the GPU service to create a new GPU memory buffer.
- CreateGpuMemoryBuffer(GpuMemoryBufferId id,
- gfx.mojom.Size size,
- BufferFormat format,
- BufferUsage usage,
- uint64 surface_id)
- => (GpuMemoryBufferHandle buffer_handle);
-
- // Tells the GPU process to destroy GPU memory buffer.
- DestroyGpuMemoryBuffer(GpuMemoryBufferId id,
- gpu.mojom.SyncToken sync_token);
-};
diff --git a/chromium/components/mus/public/interfaces/input_devices/BUILD.gn b/chromium/components/mus/public/interfaces/input_devices/BUILD.gn
deleted file mode 100644
index f2de99d1ae1..00000000000
--- a/chromium/components/mus/public/interfaces/input_devices/BUILD.gn
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("input_devices") {
- sources = [
- "input_device_server.mojom",
- ]
-
- public_deps = [
- "//ui/events/devices/mojo",
- ]
-}
diff --git a/chromium/components/mus/public/interfaces/input_devices/input_device_server.mojom b/chromium/components/mus/public/interfaces/input_devices/input_device_server.mojom
deleted file mode 100644
index b50f7d0a939..00000000000
--- a/chromium/components/mus/public/interfaces/input_devices/input_device_server.mojom
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-import "ui/events/devices/mojo/input_devices.mojom";
-
-// Receives updates about changes to input-devices. See InputDeviceServer for
-// the expected behaviour.
-interface InputDeviceObserverMojo {
- // Is called when the list of keyboards changes.
- OnKeyboardDeviceConfigurationChanged(array<ui.mojom.InputDevice> devices);
-
- // Is called when the list of touchscreens changes.
- OnTouchscreenDeviceConfigurationChanged(
- array<ui.mojom.TouchscreenDevice> devices);
-
- // Is called when the list of mice changes.
- OnMouseDeviceConfigurationChanged(array<ui.mojom.InputDevice> devices);
-
- // Is called when the list of touchpads changes.
- OnTouchpadDeviceConfigurationChanged(array<ui.mojom.InputDevice> devices);
-
- // Is called once all of the input-device lists are available. This will
- // always be the first call that an observer receives.
- OnDeviceListsComplete(
- array<ui.mojom.InputDevice> keyboard_devices,
- array<ui.mojom.TouchscreenDevice> touchscreen_devices,
- array<ui.mojom.InputDevice> mouse_devices,
- array<ui.mojom.InputDevice> touchpad_devices);
-};
-
-// Sends updates about input-devices to observers.
-interface InputDeviceServer {
- // Adds an InputDeviceObserverMojo in another process as an observer to get
- // notified of changes to input-devices over Mojo IPC. If all input-device
- // lists are complete when a new observer connects, the implementation will
- // immediately call OnDeviceListsComplete() with the input-device lists. If
- // not, the implementation will wait until all input-device lists are complete
- // then call OnDeviceListsComplete() for all connected observers.
- AddObserver(InputDeviceObserverMojo observer);
-};
diff --git a/chromium/components/mus/public/interfaces/mus_constants.mojom b/chromium/components/mus/public/interfaces/mus_constants.mojom
deleted file mode 100644
index 91407a2c4eb..00000000000
--- a/chromium/components/mus/public/interfaces/mus_constants.mojom
+++ /dev/null
@@ -1,15 +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.
-
-module mus.mojom;
-
-enum OrderDirection {
- ABOVE = 1,
- BELOW,
-};
-
-// If this property is present on a window then the window is only shown once
-// the underlay has been provided. This property is only checked once at
-// construction time.
-const string kWaitForUnderlay_Property = "property:wait-for-underlay";
diff --git a/chromium/components/mus/public/interfaces/surface.mojom b/chromium/components/mus/public/interfaces/surface.mojom
deleted file mode 100644
index 2c531d3729c..00000000000
--- a/chromium/components/mus/public/interfaces/surface.mojom
+++ /dev/null
@@ -1,22 +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.
-
-module mus.mojom;
-
-import "cc/ipc/compositor_frame.mojom";
-import "cc/ipc/returned_resource.mojom";
-
-// A Surface is an interface for receiving CompositorFrame structs. This is a
-// separate interface to allow CompositorFrames to be delivered from
-// supplementary (not main) threads of a mojo app.
-interface Surface {
- // After the submitted frame is drawn for the first time, the receiver will
- // respond to the SubmitFrame message. Clients should use this acknowledgement
- // to ratelimit frame submissions.
- SubmitCompositorFrame(cc.mojom.CompositorFrame frame) => ();
-};
-
-interface SurfaceClient {
- ReturnResources(array<cc.mojom.ReturnedResource> resources);
-};
diff --git a/chromium/components/mus/public/interfaces/user_access_manager.mojom b/chromium/components/mus/public/interfaces/user_access_manager.mojom
deleted file mode 100644
index ad0eeed9311..00000000000
--- a/chromium/components/mus/public/interfaces/user_access_manager.mojom
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-// Used to change the active user.
-interface UserAccessManager {
- // Sets the active user. By default the root user is the active user.
- SetActiveUser(string user_id);
-};
diff --git a/chromium/components/mus/public/interfaces/user_activity_monitor.mojom b/chromium/components/mus/public/interfaces/user_activity_monitor.mojom
deleted file mode 100644
index 9f9e75f7837..00000000000
--- a/chromium/components/mus/public/interfaces/user_activity_monitor.mojom
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-interface UserActivityObserver {
- OnUserActivity();
-};
-
-interface UserIdleObserver {
- enum IdleState {
- ACTIVE,
- IDLE,
- };
- OnUserIdleStateChanged(IdleState new_state);
-};
-
-interface UserActivityMonitor {
- // Notifies the observer of user activity at most once every
- // |delay_between_notify_secs| seconds.
- AddUserActivityObserver(uint32 delay_between_notify_secs,
- UserActivityObserver observer);
-
- // Notifies the observer when user is idle for more than
- // |idle_time_in_minutes| minutes. When the observer is first added, if the
- // user has already been idle for |idle_time_in_minutes|, then
- // OnUserIdleStateChanged(IDLE) is called on the observer, otherwise
- // OnUserIdleStateChanged(ACTIVE) is called.
- AddUserIdleObserver(uint32 idle_time_in_minutes, UserIdleObserver observer);
-};
diff --git a/chromium/components/mus/public/interfaces/window_manager.mojom b/chromium/components/mus/public/interfaces/window_manager.mojom
deleted file mode 100644
index ed0ffe172a1..00000000000
--- a/chromium/components/mus/public/interfaces/window_manager.mojom
+++ /dev/null
@@ -1,134 +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.
-
-module mus.mojom;
-
-import "components/mus/public/interfaces/cursor.mojom";
-import "components/mus/public/interfaces/event_matcher.mojom";
-import "components/mus/public/interfaces/window_manager_constants.mojom";
-import "components/mus/public/interfaces/window_tree_constants.mojom";
-import "ui/events/mojo/event.mojom";
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-// WindowManager is used when a WindowTreeClient attempts to modify
-// a property of the embed root. When this happens WindowTree calls the
-// appropriate function on WindowManager. For example, if a
-// WindowTreeClient calls SetWindowBounds() on its embed root, WindowTree
-// calls WmSetBounds(). WindowManager can then decide if it wants to
-// change the bounds or not.
-//
-// This interface is only used as an associated interface and is associated
-// with WindowTreeClient, further WindowTree requests this interface from
-// WindowTreeClient supplied at the time the WindowTreeHost is created.
-interface WindowManager {
- // Whether the window is always on top. Type: bool.
- const string kAlwaysOnTop_Property = "prop:always_on_top";
- // Initial bounds to create the window at. If empty the WindowManager decides
- // the initial bounds.
- const string kInitialBounds_Property = "prop:initial_bounds";
- // Internal window name. Useful for debugging. Type: mojom::String
- const string kName_Property = "prop:name";
- // The window's preferred size as defined by its content. Type: gfx::Size.
- const string kPreferredSize_Property = "prop:preferred-size";
- // The window's resize behavior. Type: ResizeBehavior.
- const string kResizeBehavior_Property = "prop:resize-behavior";
- // Bounds the window is restored to. Type: gfx::Rect.
- const string kRestoreBounds_Property = "prop:restore-bounds";
- // Shadow style for the window. Type: mojom::ShadowStyle.
- const string kShadowStyle_Property = "prop:shadow-style";
- // The window's show state. Type: ShowState.
- const string kShowState_Property = "prop:show-state";
- // The window bounds as set by user input. Type: gfx::Rect.
- const string kUserSetBounds_Property = "prop:user-set-bounds";
- // The window's app icon. Type: SkBitmap
- const string kWindowAppIcon_Property = "prop:window-app-icon";
- // The window type. Type: mojom::WindowType
- const string kWindowType_Property = "prop:window-type";
- // The window's title. Type: mojom::String
- const string kWindowTitle_Property = "prop:window-title";
- // A flag controlling the window's presence on the mash shelf. Type: bool
- const string kWindowIgnoredByShelf_Property = "prop:window-ignored-by-shelf";
- // The application ID (eg. 'mojo:foo'). Type: mojom::String
- const string kAppID_Property = "prop:app-id";
- // Specifies that the system default caption and icon should not be rendered,
- // and the client area should be equivalent to the window area. Type: bool
- const string kRemoveStandardFrame_Property = "prop:remove-standard-frame";
-
- // Called immediately when the WindowManager is obtained.
- OnConnect(uint16 client_id);
-
- // Called when a new display is added. |root| gives the root window specific
- // to this WindowManager for |display|.
- WmNewDisplayAdded(Display display, WindowData root, bool parent_drawn);
-
- // When the WindowManager completes a request it must call back to
- // WindowManagerClient::WmResponse().
- WmSetBounds(uint32 change_id, uint32 window_id, gfx.mojom.Rect bounds);
- WmSetProperty(uint32 change_id,
- uint32 window_id,
- string name,
- array<uint8>? value);
-
- // Asks the WindowManager to create a new window.
- // |requesting_client_id| is the id of the client issuing the request. This
- // allows the window manager to track top level windows by client.
- WmCreateTopLevelWindow(uint32 change_id,
- uint16 requesting_client_id,
- map<string, array<uint8>> properties);
-
- // A WindowTreeClient is considered "janky" by Mus when it stops ACK'ing input
- // events within a reasonable timeframe. When a client enters or exits this
- // state, Mus will tell the window manager about it so that the window manager
- // can update the UI for the janky windows.
- WmClientJankinessChanged(uint16 client_id, bool janky);
-
- // An accelerator registered via AddAccelerator() has been triggered.
- OnAccelerator(uint32 id, ui.mojom.Event event);
-};
-
-// This interface is only used as an associated interface and is associated
-// with WindowTree.
-interface WindowManagerClient {
- // Enables (or disables) child windows of |window_id| to be activated.
- AddActivationParent(uint32 window_id);
- RemoveActivationParent(uint32 window_id);
-
- ActivateNextWindow();
-
- // Sets the underlay surface offset for the specified window and additional
- // hit area. The underlay surface is drawn at the bounds of the window minus
- // the offset. The hit area is extended from the bounds of the window by
- // |hit_area|.
- SetUnderlaySurfaceOffsetAndExtendedHitArea(uint32 window_id,
- int32 x_offset,
- int32 y_offset,
- gfx.mojom.Insets hit_area);
-
- // Add and remove accelerators. When accelerators are registered the
- // WindowManager receives the event via OnAccelerator() rather than the
- // target window. The id is defined by the client and can be used to more
- // easily identify the accelerator's action. If an accelerator with the same
- // id or the same matcher already exists, then the accelerator is not added.
- // Accelerator ids 1 << 31 and above are reserved for internal use.
- AddAccelerator(uint32 id, EventMatcher matcher) => (bool success);
- RemoveAccelerator(uint32 id);
-
- // The window manager has completed a request with the specific change id.
- WmResponse(uint32 change_id, bool response);
-
- // Calls WindowTreeClient::RequestClose() on the embedded app at the
- // specified window.
- WmRequestClose(uint32 window_id);
-
- // Sets the frame decoration constants of the display the window manager is
- // associated with.
- WmSetFrameDecorationValues(FrameDecorationValues values);
-
- // Sets the cursor that the non-client areas of the window should use.
- WmSetNonClientCursor(uint32 window_id, Cursor cursor_id);
-
- // Response from WmCreateTopLevelWindow() informing the client of the id for
- // the new window.
- OnWmCreatedTopLevelWindow(uint32 change_id, uint32 window_id);
-};
diff --git a/chromium/components/mus/public/interfaces/window_manager_constants.mojom b/chromium/components/mus/public/interfaces/window_manager_constants.mojom
deleted file mode 100644
index acdf16b4478..00000000000
--- a/chromium/components/mus/public/interfaces/window_manager_constants.mojom
+++ /dev/null
@@ -1,78 +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.
-
-module mus.mojom;
-
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-enum WindowManagerErrorCode {
- SUCCESS,
- ACCESS_DENIED
-};
-
-// TODO(sky): seems like this should not be defined in mus, rather in mash.
-// Only thing mus cares about is minimized and that should be expressed
-// differently.
-enum ShowState {
- DEFAULT,
- NORMAL,
- MINIMIZED,
- MAXIMIZED,
- INACTIVE,
- FULLSCREEN,
- DOCKED,
-};
-
-enum Rotation {
- VALUE_0,
- VALUE_90,
- VALUE_180,
- VALUE_270,
-};
-
-const int32 kResizeBehaviorNone = 0;
-const int32 kResizeBehaviorCanResize = 1;
-const int32 kResizeBehaviorCanMaximize = 2;
-const int32 kResizeBehaviorCanMinimize = 4;
-
-struct FrameDecorationValues {
- gfx.mojom.Insets normal_client_area_insets;
- gfx.mojom.Insets maximized_client_area_insets;
- // Max width needed to display the buttons on the title bar. The buttons are
- // aligned to the trailing edge of the titlebar.
- // TODO(sky): this API is very narrow, and assumes a particular config.
- uint32 max_title_bar_button_width;
-};
-
-enum TouchSupport {
- UNKNOWN,
- AVAILABLE,
- UNAVAILABLE,
-};
-
-struct Display {
- int64 id;
- gfx.mojom.Rect bounds;
- gfx.mojom.Rect work_area;
- float device_pixel_ratio;
- Rotation rotation;
- TouchSupport touch_support;
- bool is_primary;
- FrameDecorationValues frame_decoration_values;
-};
-
-enum WindowType {
- // These constants come from Widget::InitParams. See it for details.
- // TODO: see if we can reduce this set. For example, why do we need both
- // BUBBLE and POPUP.
- WINDOW,
- PANEL,
- WINDOW_FRAMELESS,
- CONTROL,
- POPUP,
- MENU,
- TOOLTIP,
- BUBBLE,
- DRAG,
-};
diff --git a/chromium/components/mus/public/interfaces/window_manager_window_tree_factory.mojom b/chromium/components/mus/public/interfaces/window_manager_window_tree_factory.mojom
deleted file mode 100644
index 7e875f4cf7b..00000000000
--- a/chromium/components/mus/public/interfaces/window_manager_window_tree_factory.mojom
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-import "components/mus/public/interfaces/window_manager_constants.mojom";
-import "components/mus/public/interfaces/window_tree.mojom";
-
-// Interface used by the WindowManager to obtain a WindowTree. The
-// WindowManager is informed of the roots (one per display) by way of
-// WmNewDisplayAdded(). See it for details.
-interface WindowManagerWindowTreeFactory {
- // NOTE: it is expected this is called only once.
- CreateWindowTree(WindowTree& tree_request, WindowTreeClient client);
-};
diff --git a/chromium/components/mus/public/interfaces/window_server_test.mojom b/chromium/components/mus/public/interfaces/window_server_test.mojom
deleted file mode 100644
index 6e03ab23780..00000000000
--- a/chromium/components/mus/public/interfaces/window_server_test.mojom
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-interface WindowServerTest {
- EnsureClientHasDrawnWindow(string client_name) => (bool success);
-};
diff --git a/chromium/components/mus/public/interfaces/window_tree.mojom b/chromium/components/mus/public/interfaces/window_tree.mojom
deleted file mode 100644
index 96c2f73fe75..00000000000
--- a/chromium/components/mus/public/interfaces/window_tree.mojom
+++ /dev/null
@@ -1,378 +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.
-
-module mus.mojom;
-
-import "cc/ipc/surface_id.mojom";
-import "components/mus/public/interfaces/cursor.mojom";
-import "components/mus/public/interfaces/event_matcher.mojom";
-import "components/mus/public/interfaces/mus_constants.mojom";
-import "components/mus/public/interfaces/surface.mojom";
-import "components/mus/public/interfaces/window_manager.mojom";
-import "components/mus/public/interfaces/window_manager_constants.mojom";
-import "components/mus/public/interfaces/window_tree_constants.mojom";
-import "ui/events/mojo/event.mojom";
-import "ui/gfx/geometry/mojo/geometry.mojom";
-import "ui/platform_window/mojo/text_input_state.mojom";
-
-// Windows are identified by a uint32. The upper 16 bits are the connection id,
-// and the lower 16 the id assigned by the client.
-//
-// The root window is identified with a connection id of 0, and value of 1.
-//
-// Most functions to the WindowTree take a change_id parameter. When
-// WindowTree completes processing of a function WindowTree calls
-// WindowTreeClient::OnChangeCompleted() with the change_id supplied by the
-// client and the result of the function. This allows the client to track
-// whether the call succeeded or not. Calls are done via the client interface
-// rather than a callback to ensure ordering. The server does not interpret the
-// change id in anyway, it is up to the client to assign a value and use it.
-// Generally the change id is an ever increasing integer.
-interface WindowTree {
- // Creates a new window with the specified id. It is up to the client to
- // ensure the id is unique to the connection (the id need not be globally
- // unique). Additionally the connection id (embedded in |window_id|) must
- // match that of the connection.
- // Errors:
- // ERROR_CODE_VALUE_IN_USE: a window already exists with the specified id.
- // ERROR_CODE_ILLEGAL_ARGUMENT: The connection part of |window_id| does not
- // match the connection id of the client.
- NewWindow(uint32 change_id,
- uint32 window_id,
- map<string, array<uint8>>? properties);
-
- // Requests the WindowManager to create a new top level window. On success
- // OnTopLevelCreated() is called with the WindowData for the new window. On
- // failure OnChangeCompleted() is called.
- // TODO(sky): this likely needs context, maybe in |properties|.
- NewTopLevelWindow(uint32 change_id,
- uint32 window_id,
- map<string, array<uint8>> properties);
-
- // Deletes a window. This does not recurse. No hierarchy change notifications
- // are sent as a result of this. Only the connection that created the window
- // can delete it.
- DeleteWindow(uint32 change_id, uint32 window_id);
-
- // Requests input event capture for the given |window_id|. Capture is only
- // allowed if the window is processing an event. When a window gains capture,
- // current input events are canceled. The given window will receive all
- // subsequent input until an alternate window is set via SetCapture, or
- // ReleaseCapture is called for |window_id|. OnLostCapture is called to notify
- // of capture ending.
- SetCapture(uint32 change_id, uint32 window_id);
-
- // Releases input event capture for the given |window_id|. This does nothing
- // if |window_id| does not currently have capture.
- ReleaseCapture(uint32 change_id, uint32 window_id);
-
- // Sets an observer that monitors all events, even if they are not targeted
- // at a window in this tree. If an event matchs |matcher| the observer reports
- // it to the WindowTreeClient via OnWindowInputEvent (if the event target is
- // this window tree) or OnEventObserved (if the target is another tree). The
- // client must supply a non-zero |observer_id|, which is reported back with
- // observed events. Set the matcher to null to clear the observer.
- SetEventObserver(EventMatcher? matcher, uint32 observer_id);
-
- // Sets the specified bounds of the specified window.
- SetWindowBounds(uint32 change_id, uint32 window_id, gfx.mojom.Rect bounds);
-
- // Sets the client area of the specified window. The client area is specified
- // by way of insets. Everything outside of the insets, and not in
- // |additional_client_areas| is considered non-client area.
- // TODO(sky): convert additional_client_areas to a path.
- SetClientArea(uint32 window_id,
- gfx.mojom.Insets insets,
- array<gfx.mojom.Rect>? additional_client_areas);
-
- // Mouse events outside a hit test mask do not hit the window. The |mask| is
- // in window local coordinates. Pass null to clear the mask.
- // TODO(jamescook): Convert |mask| to a path. http://crbug.com/613210
- SetHitTestMask(uint32 window_id, gfx.mojom.Rect? mask);
-
- // Sets the visibility of the specified window to |visible|. Connections are
- // allowed to change the visibility of any window they have created, as well
- // as any of their roots.
- SetWindowVisibility(uint32 change_id, uint32 window_id, bool visible);
-
- // Sets an individual named property. Setting an individual property to null
- // deletes the property.
- SetWindowProperty(uint32 change_id,
- uint32 window_id,
- string name,
- array<uint8>? value);
-
- // Sets the opacity of the specified window to |opacity|.
- SetWindowOpacity(uint32 change_id, uint32 window_id, float opacity);
-
- // Attaches a Surface to a particular window.
- AttachSurface(uint32 window_id,
- SurfaceType type,
- Surface& surface,
- SurfaceClient client);
-
- // Reparents a window.
- // This fails for any of the following reasons:
- // . |parent| or |child| does not identify a valid window.
- // . |child| is an ancestor of |parent|.
- // . |child| is already a child of |parent|.
- //
- // This may result in a connection getting OnWindowDeleted(). See
- // RemoveWindowFromParent for details.
- AddWindow(uint32 change_id, uint32 parent, uint32 child);
-
- // Removes a window from its current parent. This fails if the window is not
- // valid or the window already has no parent.
- //
- // Removing a window from a parent may result in OnWindowDeleted() being sent
- // to other connections. For example, connection A has windows 1 and 2, with 2
- // a child of 1. Connection B has a root 1. If 2 is removed from 1 then B gets
- // OnWindowDeleted(). This is done as window 2 is effectively no longer
- // visible to connection B.
- RemoveWindowFromParent(uint32 change_id, uint32 window_id);
-
- // Ties the lifetime of |transient_window_id| to the lifetime of |window_id|.
- // This also places |transient_window_id| on top of |window_id|.
- // This fails for any of the following reasons:
- // . |window_id| or |transient_window_id| does not identify a valid window.
- // . |transient_window_id| is an ancestor of |window_id|.
- // . |transient_window_id| is modal to system.
- AddTransientWindow(uint32 change_id,
- uint32 window_id,
- uint32 transient_window_id);
-
- // Decouples the lifetime of |transient_window_id| from its transient parent.
- // This does not change transient window's position in the window hierarchy.
- RemoveTransientWindowFromParent(uint32 change_id, uint32 transient_window_id);
-
- // Sets |window_id| to be modal. If the window has a transient parent, then
- // the window is modal to the transient parent. Otherwise, the window is modal
- // to the system. This releases capture if necessary.
- // This fails for any of the following reasons:
- // . |window_id| does not identify a valid window.
- // . Client does not have a valid user id (i.e., it is an embedded app).
- SetModal(uint32 change_id, uint32 window_id);
-
- // Reorders a window in its parent, relative to |relative_window_id| according
- // to |direction|. Only the connection that created the window's parent can
- // reorder its children.
- ReorderWindow(uint32 change_id,
- uint32 window_id,
- uint32 relative_window_id,
- OrderDirection direction);
-
- // Returns the windows comprising the tree starting at |window_id|.
- // |window_id| is the first result in the return value, unless |window_id| is
- // invalid, in which case an empty vector is returned. The windows are visited
- // using a depth first search (pre-order).
- GetWindowTree(uint32 window_id) => (array<WindowData> windows);
-
- // A connection may grant access to another connection by way of Embed().
- // Embed() results in the supplied WindowTreeClient being configured with a
- // root window of |window_id|. The supplied WindowTreeClient may create child
- // windows and do other various tree operations (including Embed()), but does
- // not see nor have access to any of the windows above the embed point.
- //
- // The caller must have created |window_id|. If not the request fails and the
- // response is false.
- //
- // The embedder can dictate the behaviour of the embedded client by setting
- // the appropriate embed flags (e.g. kEmbedFlagEmbedderInterceptsEvents).
- //
- // When a connection embeds a WindowTreeClient the originating connection no
- // longer has privileges to access or see any of the children of the window.
- // If the window had existing children the children are removed. The
- // WindowManager gets to see the whole tree.
- //
- // A window may only have one embedding in it at a time. Subsequent calls to
- // Embed() for the same window result in the currently embedded
- // WindowTreeClient being removed. The embedded app is told this by way of
- // OnUnembed(), which is followed by OnWindowDeleted() (as the connection no
- // longer has access to the window).
- //
- // The embedder can detect when the embedded app disconnects by way of
- // OnEmbeddedAppDisconnected().
- //
- // The callback returns whether the embedding was successful.
- Embed(uint32 window_id, WindowTreeClient client, uint32 embed_flags)
- => (bool success);
-
- // Sets focus to the specified window, use 0 to clear focus. For a window to
- // get focus the following has to happen: the window is drawn, the window has
- // been marked as focusable (see SetCanFocus()) and the window is in a
- // container the WindowManager has identified as allowing activation
- // (see WindowManagerClient::AddActivationParent()).
- SetFocus(uint32 change_id, uint32 window_id);
-
- // Marks the specified window as being able to receive focus.
- SetCanFocus(uint32 window_id, bool can_focus);
-
- // Sets the cursor when the pointer is inside |window_id| to a system standard
- // cursor provided by the window manager.
- SetPredefinedCursor(uint32 change_id, uint32 window_id, Cursor cursor_id);
-
- // TODO(erg): Additional cursor methods. Image based cursors, visibility,
- // and cursor locking.
-
- // Set text input state for the given window.
- SetWindowTextInputState(uint32 window_id, mojo.TextInputState state);
-
- // Set the input method editor UI (software keyboard, etc) visibility.
- // If state is non-null, the specified window's text input state is updated.
- // Otherwise the existing state is used.
- SetImeVisibility(uint32 window_id, bool visible, mojo.TextInputState? state);
-
- // See documentation for WindowTreeClient::OnWindowInputEvent().
- OnWindowInputEventAck(uint32 event_id, EventResult result);
-
- // See description of WindowManager for details.
- GetWindowManagerClient(associated WindowManagerClient& internal);
-
- // Returns a shared memory segment that contains two 16-bit ints packed into a
- // single Atomic32, which represent the current location of the mouse cursor
- // where the location is (x << 16) | y.
- GetCursorLocationMemory() => (handle<shared_buffer> cursor_buffer);
-};
-
-// Changes to windows are not sent to the connection that originated the
-// change. For example, if connection 1 changes the bounds of a window by
-// calling SetWindowBounds(), connection 1 does not receive
-// OnWindowBoundsChanged().
-interface WindowTreeClient {
- // Invoked when the client application has been embedded at |root|.
- // See Embed() on WindowTree for more details. |tree| will be a handle back to
- // the window manager service, unless the connection is to the root connection
- // in which case it will be null. |parent_drawn| is true if roots parent is
- // drawn, see OnParentDrawnStateChanged() for details. |display_id| identifies
- // the display this root window is on.
- OnEmbed(uint16 connection_id,
- WindowData root,
- WindowTree? tree,
- int64 display_id,
- uint32 focused_window,
- bool parent_drawn);
-
- // Invoked when the application embedded at |window| is disconnected. In other
- // words the embedded app closes the connection to the server. This is called
- // on the connection that created |window| as well as any ancestors that have
- // the embed root policy.
- OnEmbeddedAppDisconnected(uint32 window);
-
- // Sent when another connection is embedded in the Window this connection was
- // previously embedded in. See Embed() for more information.
- OnUnembed(uint32 window);
-
- // Sent when a window loses capture.
- OnLostCapture(uint32 window);
-
- // Called in response to NewTopLevelWindow() successfully completing.
- // |parent_drawn| is true if the parent of the window is drawn, see
- // OnDrawnStateChanged() for details. |display_id| identifies the display this
- // window is on.
- OnTopLevelCreated(uint32 change_id,
- WindowData data,
- int64 display_id,
- bool parent_drawn);
-
- // Invoked when a window's bounds have changed.
- OnWindowBoundsChanged(uint32 window,
- gfx.mojom.Rect old_bounds,
- gfx.mojom.Rect new_bounds);
-
- OnClientAreaChanged(uint32 window_id,
- gfx.mojom.Insets new_client_area,
- array<gfx.mojom.Rect> new_additional_client_areas);
-
- OnTransientWindowAdded(uint32 window_id,
- uint32 transient_window_id);
-
- OnTransientWindowRemoved(uint32 window_id,
- uint32 transient_window_id);
-
- // Invoked when a change is done to the hierarchy. A value of 0 is used to
- // identify a null window. For example, if the old_parent is NULL, 0 is
- // supplied.
- // |windows| contains any windows that are that the client has not been told
- // about. This is not sent for hierarchy changes of windows not known to this
- // client or not attached to the tree.
- OnWindowHierarchyChanged(uint32 window,
- uint32 old_parent,
- uint32 new_parent,
- array<WindowData> windows);
-
- // Invoked when the order of windows within a parent changes.
- OnWindowReordered(uint32 window_id,
- uint32 relative_window_id,
- OrderDirection direction);
-
- // Invoked when a window is deleted.
- OnWindowDeleted(uint32 window);
-
- // Invoked when the visibility of the specified window changes.
- OnWindowVisibilityChanged(uint32 window, bool visible);
-
- // Invoked when the opacity of the specified window has changed.
- OnWindowOpacityChanged(uint32 window, float old_opacity, float new_opacity);
-
- // Invoked when the drawn state of |window|'s parent changes. The drawn state
- // is determined by the visibility of a Window and the Windows ancestors. A
- // Window is drawn if all ancestors are visible, not drawn if any ancestor is
- // hidden.
- //
- // The initial drawn state is communicated by way of OnTopLevelCreated() or
- // OnEmbed().
- //
- // This function is only called for root Windows as the drawn state of all
- // other windows can be determined from their parent.
- OnWindowParentDrawnStateChanged(uint32 window, bool drawn);
-
- // Invoked when a window property is changed. If this change is a removal,
- // |new_data| is null.
- OnWindowSharedPropertyChanged(uint32 window,
- string name,
- array<uint8>? new_data);
-
- // Invoked when an event is targeted at the specified window. The client must
- // call WindowTree::OnWindowInputEventAck() with the same |event_id| to notify
- // that the event has been processed, and with an EventResult value to notify
- // if the event was consumed. |event_observer_id| is non-zero if the event
- // also matched the active event observer for this client. The client will not
- // receive farther events until the event is ack'ed.
- OnWindowInputEvent(uint32 event_id,
- uint32 window,
- ui.mojom.Event event,
- uint32 event_observer_id);
-
- // Invoked when an |event| is sent via the EventObserver and not targeted at a
- // specific window. The |event_observer_id| is the one supplied to
- // SetEventObserver. The client should not acknowledge these events.
- OnEventObserved(ui.mojom.Event event, uint32 event_observer_id);
-
- // Called in two distinct cases: when a window known to the connection gains
- // focus, or when focus moves from a window known to the connection to a
- // window not known to the connection. In the later case |focused_window_id|
- // is 0. As with other functions this is only called if the client did not
- // initiate the change.
- OnWindowFocused(uint32 focused_window_id);
-
- OnWindowPredefinedCursorChanged(uint32 window_id, Cursor cursor_id);
-
- // A change initiated from the client has completed. See description of
- // change ids for details.
- OnChangeCompleted(uint32 change_id, bool success);
-
- // The WindowManager is requesting the specified window to close. If the
- // client allows the change it should delete the window.
- RequestClose(uint32 window_id);
-
- // See description of WindowManager for details.
- GetWindowManager(associated WindowManager& internal);
-};
-
-// Mus provides this interface as a way for clients to connect and obtain a
-// WindowTree handle with a supplied WindowTreeClient handle. The
-// WindowTreeClient has no roots, use NewTopLevelWindow() to create one.
-interface WindowTreeFactory {
- CreateWindowTree(WindowTree& tree_request, WindowTreeClient client);
-};
diff --git a/chromium/components/mus/public/interfaces/window_tree_constants.mojom b/chromium/components/mus/public/interfaces/window_tree_constants.mojom
deleted file mode 100644
index c8e1c689510..00000000000
--- a/chromium/components/mus/public/interfaces/window_tree_constants.mojom
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-// Contains state of a single window.
-struct WindowData {
- // Unique identifier of the parent. If the client can not see the parent an
- // id of 0 is supplied.
- uint32 parent_id;
-
- // Unique identifier of the window.
- uint32 window_id;
-
- gfx.mojom.Rect bounds;
-
- // Arbitrary key/value pairs. The interpretation of these is left to the
- // client. See SetWindowProperty() for more information.
- map<string, array<uint8>> properties;
-
- // True if this window is visible. The window may not be drawn on screen (see
- // OnWindowParentDrawnStateChanged() for details).
- bool visible;
-};
-
-// Each Window has support for two surfaces. Generally the |DEFAULT| surface
-// is used. The |UNDERLAY| surface is useful if the owner of a window wants to
-// to Embed() another client and at the same time draw something under the
-// embedded apps representation.
-enum SurfaceType {
- // Only the owner of a window may obtain this surface.
- // The window manager can change the offset of this by way of
- // SetUnderlaySurfaceOffsetAndExtendedHitArea().
- UNDERLAY,
-
- // Only the embedded app may obtain this surface. If an app is not embedded
- // in the Window than the owner may also render to this surface as well.
- DEFAULT,
-};
-
-// The result of an input event sent to a client app.
-enum EventResult {
- HANDLED,
- UNHANDLED,
-};
-
-// When this flag is set in a call to Embed(), the embedder (i.e. the client
-// that is making the call to Embed()) will receive events that are targeted to
-// the embedded client. The embedded client will not receive any input events
-// from the window server. However, the embedder can choose to dispatch events
-// to the embedded client through other mechanism.
-// TODO(sad): Provide an API in mus for the embedder to dispatch events to the
-// embedded client. https://crbug.com/621085
-const uint32 kEmbedFlagEmbedderInterceptsEvents = 0x01;
diff --git a/chromium/components/mus/public/interfaces/window_tree_host.mojom b/chromium/components/mus/public/interfaces/window_tree_host.mojom
deleted file mode 100644
index 4c61eb9a1ce..00000000000
--- a/chromium/components/mus/public/interfaces/window_tree_host.mojom
+++ /dev/null
@@ -1,25 +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.
-
-module mus.mojom;
-
-import "components/mus/public/interfaces/window_tree.mojom";
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-// WindowTreeHost encapsulates a unique underlying platform window, with a tree
-// of windows.
-interface WindowTreeHost {
- // Sets the size of the platform window.
- SetSize(gfx.mojom.Size size);
-
- // Sets a title string to be displayed on the platform window.
- SetTitle(string title);
-};
-
-interface WindowTreeHostFactory {
- // Creates a new WindowTreeHost. |tree_client| is queried for the
- // WindowManager.
- CreateWindowTreeHost(WindowTreeHost& window_tree_host,
- WindowTreeClient tree_client);
-};
diff --git a/chromium/components/mus/surfaces/BUILD.gn b/chromium/components/mus/surfaces/BUILD.gn
deleted file mode 100644
index 95270535660..00000000000
--- a/chromium/components/mus/surfaces/BUILD.gn
+++ /dev/null
@@ -1,51 +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("//build/config/ui.gni")
-
-source_set("surfaces") {
- sources = [
- "direct_output_surface.cc",
- "direct_output_surface.h",
- "display_compositor.cc",
- "display_compositor.h",
- "surfaces_context_provider.cc",
- "surfaces_context_provider.h",
- "surfaces_context_provider_delegate.h",
- "surfaces_state.cc",
- "surfaces_state.h",
- ]
-
- deps = [
- "//base",
- "//cc",
- "//cc/surfaces",
- "//cc/surfaces:surface_id",
- "//components/display_compositor",
- "//components/mus/common:mus_common",
- "//components/mus/gles2",
- "//components/mus/gpu",
- "//components/mus/public/interfaces",
- "//gpu/command_buffer/client",
- "//gpu/command_buffer/client:gles2_cmd_helper",
- "//gpu/command_buffer/client:gles2_implementation",
- "//gpu/command_buffer/client:gles2_interface",
- "//gpu/ipc/client",
- "//services/shell/public/cpp",
- "//services/tracing/public/cpp",
- "//ui/gfx",
- "//ui/gfx/geometry/mojo",
- "//ui/gl",
- ]
-
- if (use_ozone) {
- sources += [
- "direct_output_surface_ozone.cc",
- "direct_output_surface_ozone.h",
- "ozone_gpu_memory_buffer_manager.cc",
- "ozone_gpu_memory_buffer_manager.h",
- ]
- deps += [ "//gpu/command_buffer/common" ]
- }
-}
diff --git a/chromium/components/mus/surfaces/DEPS b/chromium/components/mus/surfaces/DEPS
deleted file mode 100644
index e21114ea1d7..00000000000
--- a/chromium/components/mus/surfaces/DEPS
+++ /dev/null
@@ -1,10 +0,0 @@
-include_rules = [
- "+cc",
- "+components/display_compositor",
- "+components/gpu",
- "+gpu",
- "+services/shell",
- "+mojo/common",
- "+mojo/converters",
- "+mojo/public",
-]
diff --git a/chromium/components/mus/surfaces/OWNERS b/chromium/components/mus/surfaces/OWNERS
deleted file mode 100644
index 1f1af6bcc54..00000000000
--- a/chromium/components/mus/surfaces/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-fsamuel@chromium.org
-rjkroege@chromium.org
diff --git a/chromium/components/mus/surfaces/direct_output_surface.cc b/chromium/components/mus/surfaces/direct_output_surface.cc
deleted file mode 100644
index 7c7bc55f4c9..00000000000
--- a/chromium/components/mus/surfaces/direct_output_surface.cc
+++ /dev/null
@@ -1,81 +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 "components/mus/surfaces/direct_output_surface.h"
-
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "cc/output/compositor_frame.h"
-#include "cc/output/context_provider.h"
-#include "cc/output/output_surface_client.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-
-namespace mus {
-
-DirectOutputSurface::DirectOutputSurface(
- scoped_refptr<SurfacesContextProvider> context_provider,
- cc::SyntheticBeginFrameSource* synthetic_begin_frame_source)
- : cc::OutputSurface(context_provider, nullptr, nullptr),
- synthetic_begin_frame_source_(synthetic_begin_frame_source),
- weak_ptr_factory_(this) {
- context_provider->SetDelegate(this);
-}
-
-DirectOutputSurface::~DirectOutputSurface() = default;
-
-bool DirectOutputSurface::BindToClient(cc::OutputSurfaceClient* client) {
- if (!cc::OutputSurface::BindToClient(client))
- return false;
-
- if (capabilities_.uses_default_gl_framebuffer) {
- capabilities_.flipped_output_surface =
- context_provider()->ContextCapabilities().flips_vertically;
- }
- return true;
-}
-
-void DirectOutputSurface::OnVSyncParametersUpdated(
- const base::TimeTicks& timebase,
- const base::TimeDelta& interval) {
- // TODO(brianderson): We should not be receiving 0 intervals.
- synthetic_begin_frame_source_->OnUpdateVSyncParameters(
- timebase,
- interval.is_zero() ? cc::BeginFrameArgs::DefaultInterval() : interval);
-}
-
-void DirectOutputSurface::SwapBuffers(cc::CompositorFrame frame) {
- DCHECK(context_provider_);
- DCHECK(frame.gl_frame_data);
- if (frame.gl_frame_data->sub_buffer_rect ==
- gfx::Rect(frame.gl_frame_data->size)) {
- context_provider_->ContextSupport()->Swap();
- } else {
- context_provider_->ContextSupport()->PartialSwapBuffers(
- frame.gl_frame_data->sub_buffer_rect);
- }
-
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
- const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM();
- gl->ShallowFlushCHROMIUM();
-
- gpu::SyncToken sync_token;
- gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
-
- context_provider_->ContextSupport()->SignalSyncToken(
- sync_token, base::Bind(&OutputSurface::OnSwapBuffersComplete,
- weak_ptr_factory_.GetWeakPtr()));
- client_->DidSwapBuffers();
-}
-
-uint32_t DirectOutputSurface::GetFramebufferCopyTextureFormat() {
- // TODO(danakj): What attributes are used for the default framebuffer here?
- // Can it have alpha? SurfacesContextProvider doesn't take any attributes.
- return GL_RGB;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/surfaces/direct_output_surface.h b/chromium/components/mus/surfaces/direct_output_surface.h
deleted file mode 100644
index 6e08485cfbb..00000000000
--- a/chromium/components/mus/surfaces/direct_output_surface.h
+++ /dev/null
@@ -1,47 +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 COMPONENTS_MUS_SURFACES_DIRECT_OUTPUT_SURFACE_H_
-#define COMPONENTS_MUS_SURFACES_DIRECT_OUTPUT_SURFACE_H_
-
-#include <memory>
-
-#include "cc/output/output_surface.h"
-#include "components/mus/surfaces/surfaces_context_provider.h"
-#include "components/mus/surfaces/surfaces_context_provider_delegate.h"
-
-namespace cc {
-class CompositorFrame;
-class SyntheticBeginFrameSource;
-}
-
-namespace mus {
-
-// An OutputSurface implementation that directly draws and
-// swaps to an actual GL surface.
-class DirectOutputSurface : public cc::OutputSurface,
- public SurfacesContextProviderDelegate {
- public:
- explicit DirectOutputSurface(
- scoped_refptr<SurfacesContextProvider> context_provider,
- cc::SyntheticBeginFrameSource* synthetic_begin_frame_source);
- ~DirectOutputSurface() override;
-
- // cc::OutputSurface implementation
- bool BindToClient(cc::OutputSurfaceClient* client) override;
- void SwapBuffers(cc::CompositorFrame frame) override;
- uint32_t GetFramebufferCopyTextureFormat() override;
-
- // SurfacesContextProviderDelegate implementation
- void OnVSyncParametersUpdated(const base::TimeTicks& timebase,
- const base::TimeDelta& interval) override;
-
- private:
- cc::SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
- base::WeakPtrFactory<DirectOutputSurface> weak_ptr_factory_;
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_SURFACES_DIRECT_OUTPUT_SURFACE_H_
diff --git a/chromium/components/mus/surfaces/direct_output_surface_ozone.cc b/chromium/components/mus/surfaces/direct_output_surface_ozone.cc
deleted file mode 100644
index 5148336078a..00000000000
--- a/chromium/components/mus/surfaces/direct_output_surface_ozone.cc
+++ /dev/null
@@ -1,166 +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 "components/mus/surfaces/direct_output_surface_ozone.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "cc/output/compositor_frame.h"
-#include "cc/output/context_provider.h"
-#include "cc/output/output_surface_client.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "components/display_compositor/buffer_queue.h"
-#include "components/mus/common/gpu_service.h"
-#include "components/mus/common/mojo_gpu_memory_buffer_manager.h"
-#include "components/mus/gpu/mus_gpu_memory_buffer_manager.h"
-#include "components/mus/surfaces/surfaces_context_provider.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-
-using display_compositor::BufferQueue;
-
-namespace mus {
-
-DirectOutputSurfaceOzone::DirectOutputSurfaceOzone(
- scoped_refptr<SurfacesContextProvider> context_provider,
- gfx::AcceleratedWidget widget,
- cc::SyntheticBeginFrameSource* synthetic_begin_frame_source,
- uint32_t target,
- uint32_t internalformat)
- : cc::OutputSurface(context_provider, nullptr, nullptr),
- gl_helper_(context_provider->ContextGL(),
- context_provider->ContextSupport()),
- synthetic_begin_frame_source_(synthetic_begin_frame_source),
- weak_ptr_factory_(this) {
- if (!GpuService::UseChromeGpuCommandBuffer()) {
- ozone_gpu_memory_buffer_manager_.reset(new OzoneGpuMemoryBufferManager());
- buffer_queue_.reset(new BufferQueue(
- context_provider->ContextGL(), target, internalformat, &gl_helper_,
- ozone_gpu_memory_buffer_manager_.get(), widget));
- } else {
- buffer_queue_.reset(new BufferQueue(
- context_provider->ContextGL(), target, internalformat, &gl_helper_,
- MusGpuMemoryBufferManager::current(), widget));
- }
-
- capabilities_.uses_default_gl_framebuffer = false;
- capabilities_.flipped_output_surface = true;
- // Set |max_frames_pending| to 2 for surfaceless, which aligns scheduling
- // more closely with the previous surfaced behavior.
- // With a surface, swap buffer ack used to return early, before actually
- // presenting the back buffer, enabling the browser compositor to run ahead.
- // Surfaceless implementation acks at the time of actual buffer swap, which
- // shifts the start of the new frame forward relative to the old
- // implementation.
- capabilities_.max_frames_pending = 2;
-
- buffer_queue_->Initialize();
-
- context_provider->SetSwapBuffersCompletionCallback(
- base::Bind(&DirectOutputSurfaceOzone::OnGpuSwapBuffersCompleted,
- base::Unretained(this)));
-}
-
-DirectOutputSurfaceOzone::~DirectOutputSurfaceOzone() {
- // TODO(rjkroege): Support cleanup.
-}
-
-bool DirectOutputSurfaceOzone::IsDisplayedAsOverlayPlane() const {
- // TODO(rjkroege): implement remaining overlay functionality.
- return true;
-}
-
-unsigned DirectOutputSurfaceOzone::GetOverlayTextureId() const {
- DCHECK(buffer_queue_);
- return buffer_queue_->current_texture_id();
-}
-
-void DirectOutputSurfaceOzone::SwapBuffers(cc::CompositorFrame frame) {
- DCHECK(buffer_queue_);
- DCHECK(frame.gl_frame_data);
-
- buffer_queue_->SwapBuffers(frame.gl_frame_data->sub_buffer_rect);
-
- // Code combining GpuBrowserCompositorOutputSurface + DirectOutputSurface
- if (frame.gl_frame_data->sub_buffer_rect ==
- gfx::Rect(frame.gl_frame_data->size)) {
- context_provider_->ContextSupport()->Swap();
- } else {
- context_provider_->ContextSupport()->PartialSwapBuffers(
- frame.gl_frame_data->sub_buffer_rect);
- }
-
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
- const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM();
- gl->ShallowFlushCHROMIUM();
-
- gpu::SyncToken sync_token;
- gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
-
- client_->DidSwapBuffers();
-}
-
-bool DirectOutputSurfaceOzone::BindToClient(cc::OutputSurfaceClient* client) {
- if (!cc::OutputSurface::BindToClient(client))
- return false;
-
- if (capabilities_.uses_default_gl_framebuffer) {
- capabilities_.flipped_output_surface =
- context_provider()->ContextCapabilities().flips_vertically;
- }
- return true;
-}
-
-void DirectOutputSurfaceOzone::OnUpdateVSyncParametersFromGpu(
- base::TimeTicks timebase,
- base::TimeDelta interval) {
- DCHECK(HasClient());
- synthetic_begin_frame_source_->OnUpdateVSyncParameters(timebase, interval);
-}
-
-void DirectOutputSurfaceOzone::OnGpuSwapBuffersCompleted(
- gfx::SwapResult result) {
- DCHECK(buffer_queue_);
- bool force_swap = false;
- if (result == gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS) {
- // Even through the swap failed, this is a fixable error so we can pretend
- // it succeeded to the rest of the system.
- result = gfx::SwapResult::SWAP_ACK;
- buffer_queue_->RecreateBuffers();
- force_swap = true;
- }
-
- buffer_queue_->PageFlipComplete();
- OnSwapBuffersComplete();
-
- if (force_swap)
- client_->SetNeedsRedrawRect(gfx::Rect(SurfaceSize()));
-}
-
-void DirectOutputSurfaceOzone::BindFramebuffer() {
- DCHECK(buffer_queue_);
- buffer_queue_->BindFramebuffer();
-}
-
-uint32_t DirectOutputSurfaceOzone::GetFramebufferCopyTextureFormat() {
- return buffer_queue_->internal_format();
-}
-
-// We call this on every frame but changing the size once we've allocated
-// backing NativePixmapOzone instances will cause a DCHECK because
-// Chrome never Reshape(s) after the first one from (0,0). NB: this implies
-// that screen size changes need to be plumbed differently. In particular, we
-// must create the native window in the size that the hardware reports.
-void DirectOutputSurfaceOzone::Reshape(const gfx::Size& size,
- float scale_factor,
- const gfx::ColorSpace& color_space,
- bool alpha) {
- OutputSurface::Reshape(size, scale_factor, color_space, alpha);
- DCHECK(buffer_queue_);
- buffer_queue_->Reshape(SurfaceSize(), scale_factor);
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/surfaces/direct_output_surface_ozone.h b/chromium/components/mus/surfaces/direct_output_surface_ozone.h
deleted file mode 100644
index 8f6f4e4bb76..00000000000
--- a/chromium/components/mus/surfaces/direct_output_surface_ozone.h
+++ /dev/null
@@ -1,84 +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 COMPONENTS_MUS_SURFACES_DIRECT_OUTPUT_SURFACE_OZONE_H_
-#define COMPONENTS_MUS_SURFACES_DIRECT_OUTPUT_SURFACE_OZONE_H_
-
-#include <memory>
-
-#include "base/memory/weak_ptr.h"
-#include "cc/output/context_provider.h"
-#include "cc/output/output_surface.h"
-#include "components/display_compositor/gl_helper.h"
-#include "components/mus/surfaces/ozone_gpu_memory_buffer_manager.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/swap_result.h"
-#include "ui/gl/gl_surface.h"
-
-namespace display_compositor {
-class BufferQueue;
-}
-
-namespace ui {
-class LatencyInfo;
-} // namespace ui
-
-namespace cc {
-class CompositorFrame;
-class SyntheticBeginFrameSource;
-} // namespace cc
-
-namespace mus {
-
-class SurfacesContextProvider;
-
-// An OutputSurface implementation that directly draws and swap to a GL
-// "surfaceless" surface (aka one backed by a buffer managed explicitly in
-// mus/ozone. This class is adapted from
-// GpuSurfacelessBrowserCompositorOutputSurface.
-class DirectOutputSurfaceOzone : public cc::OutputSurface {
- public:
- DirectOutputSurfaceOzone(
- scoped_refptr<SurfacesContextProvider> context_provider,
- gfx::AcceleratedWidget widget,
- cc::SyntheticBeginFrameSource* synthetic_begin_frame_source,
- uint32_t target,
- uint32_t internalformat);
-
- ~DirectOutputSurfaceOzone() override;
-
- // TODO(rjkroege): Implement the equivalent of Reflector.
-
- private:
- // cc::OutputSurface implementation.
- void SwapBuffers(cc::CompositorFrame frame) override;
- void BindFramebuffer() override;
- uint32_t GetFramebufferCopyTextureFormat() override;
- void Reshape(const gfx::Size& size,
- float scale_factor,
- const gfx::ColorSpace& color_space,
- bool alpha) override;
- bool IsDisplayedAsOverlayPlane() const override;
- unsigned GetOverlayTextureId() const override;
- bool BindToClient(cc::OutputSurfaceClient* client) override;
-
- // Taken from BrowserCompositor specific API.
- void OnUpdateVSyncParametersFromGpu(base::TimeTicks timebase,
- base::TimeDelta interval);
-
- // Called when a swap completion is sent from the GPU process.
- void OnGpuSwapBuffersCompleted(gfx::SwapResult result);
-
- display_compositor::GLHelper gl_helper_;
- std::unique_ptr<OzoneGpuMemoryBufferManager> ozone_gpu_memory_buffer_manager_;
- std::unique_ptr<display_compositor::BufferQueue> buffer_queue_;
- cc::SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
-
- base::WeakPtrFactory<DirectOutputSurfaceOzone> weak_ptr_factory_;
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_SURFACES_DIRECT_OUTPUT_SURFACE_OZONE_H_
diff --git a/chromium/components/mus/surfaces/display_compositor.cc b/chromium/components/mus/surfaces/display_compositor.cc
deleted file mode 100644
index 8ffa0b86276..00000000000
--- a/chromium/components/mus/surfaces/display_compositor.cc
+++ /dev/null
@@ -1,124 +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 "components/mus/surfaces/display_compositor.h"
-
-#include "cc/output/copy_output_request.h"
-#include "cc/output/output_surface.h"
-#include "cc/output/renderer_settings.h"
-#include "cc/output/texture_mailbox_deleter.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/scheduler/delay_based_time_source.h"
-#include "cc/surfaces/display.h"
-#include "cc/surfaces/display_scheduler.h"
-#include "components/mus/surfaces/direct_output_surface.h"
-#include "components/mus/surfaces/surfaces_context_provider.h"
-
-#if defined(USE_OZONE)
-#include "components/mus/surfaces/direct_output_surface_ozone.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#endif
-
-namespace mus {
-
-DisplayCompositor::DisplayCompositor(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- gfx::AcceleratedWidget widget,
- const scoped_refptr<GpuState>& gpu_state,
- const scoped_refptr<SurfacesState>& surfaces_state)
- : task_runner_(task_runner),
- surfaces_state_(surfaces_state),
- factory_(surfaces_state->manager(), this),
- allocator_(surfaces_state->next_id_namespace()) {
- allocator_.RegisterSurfaceIdNamespace(surfaces_state_->manager());
- surfaces_state_->manager()->RegisterSurfaceFactoryClient(
- allocator_.id_namespace(), this);
-
- scoped_refptr<SurfacesContextProvider> surfaces_context_provider(
- new SurfacesContextProvider(widget, gpu_state));
- // TODO(rjkroege): If there is something better to do than CHECK, add it.
- CHECK(surfaces_context_provider->BindToCurrentThread());
-
- std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source(
- new cc::DelayBasedBeginFrameSource(
- base::MakeUnique<cc::DelayBasedTimeSource>(task_runner_.get())));
-
- std::unique_ptr<cc::OutputSurface> display_output_surface;
- if (surfaces_context_provider->ContextCapabilities().surfaceless) {
-#if defined(USE_OZONE)
- display_output_surface = base::WrapUnique(new DirectOutputSurfaceOzone(
- surfaces_context_provider, widget, synthetic_begin_frame_source.get(),
- GL_TEXTURE_2D, GL_RGB));
-#else
- NOTREACHED();
-#endif
- } else {
- display_output_surface = base::WrapUnique(new DirectOutputSurface(
- surfaces_context_provider, synthetic_begin_frame_source.get()));
- }
-
- int max_frames_pending =
- display_output_surface->capabilities().max_frames_pending;
- DCHECK_GT(max_frames_pending, 0);
-
- std::unique_ptr<cc::DisplayScheduler> scheduler(
- new cc::DisplayScheduler(synthetic_begin_frame_source.get(),
- task_runner_.get(), max_frames_pending));
-
- display_.reset(new cc::Display(
- surfaces_state_->manager(), nullptr /* bitmap_manager */,
- nullptr /* gpu_memory_buffer_manager */, cc::RendererSettings(),
- allocator_.id_namespace(), std::move(synthetic_begin_frame_source),
- std::move(display_output_surface), std::move(scheduler),
- base::MakeUnique<cc::TextureMailboxDeleter>(task_runner_.get())));
- display_->Initialize(this);
-}
-
-DisplayCompositor::~DisplayCompositor() {
- surfaces_state_->manager()->UnregisterSurfaceFactoryClient(
- allocator_.id_namespace());
-}
-
-void DisplayCompositor::SubmitCompositorFrame(
- cc::CompositorFrame frame,
- const base::Callback<void(cc::SurfaceDrawStatus)>& callback) {
- gfx::Size frame_size =
- frame.delegated_frame_data->render_pass_list.back()->output_rect.size();
- if (frame_size.IsEmpty() || frame_size != display_size_) {
- if (!surface_id_.is_null())
- factory_.Destroy(surface_id_);
- surface_id_ = allocator_.GenerateId();
- factory_.Create(surface_id_);
- display_size_ = frame_size;
- display_->Resize(display_size_);
- }
- display_->SetSurfaceId(surface_id_, frame.metadata.device_scale_factor);
- factory_.SubmitCompositorFrame(surface_id_, std::move(frame), callback);
-}
-
-void DisplayCompositor::RequestCopyOfOutput(
- std::unique_ptr<cc::CopyOutputRequest> output_request) {
- factory_.RequestCopyOfSurface(surface_id_, std::move(output_request));
-}
-
-void DisplayCompositor::ReturnResources(
- const cc::ReturnedResourceArray& resources) {
- // TODO(fsamuel): Implement this.
-}
-
-void DisplayCompositor::SetBeginFrameSource(
- cc::BeginFrameSource* begin_frame_source) {
- // TODO(fsamuel): Implement this.
-}
-
-void DisplayCompositor::DisplayOutputSurfaceLost() {
- // TODO(fsamuel): This looks like it would crash if a frame was in flight and
- // will be submitted.
- display_.reset();
-}
-
-void DisplayCompositor::DisplaySetMemoryPolicy(
- const cc::ManagedMemoryPolicy& policy) {}
-
-} // namespace mus
diff --git a/chromium/components/mus/surfaces/display_compositor.h b/chromium/components/mus/surfaces/display_compositor.h
deleted file mode 100644
index 27d1eebf3cf..00000000000
--- a/chromium/components/mus/surfaces/display_compositor.h
+++ /dev/null
@@ -1,80 +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 COMPONENTS_MUS_SURFACES_DISPLAY_COMPOSITOR_H_
-#define COMPONENTS_MUS_SURFACES_DISPLAY_COMPOSITOR_H_
-
-#include "cc/surfaces/display_client.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
-#include "cc/surfaces/surface_id_allocator.h"
-#include "components/mus/gles2/gpu_state.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace cc {
-class Display;
-}
-
-namespace mus {
-
-// TODO(fsamuel): This should become a mojo interface for the mus-gpu split.
-// TODO(fsamuel): This should not be a SurfaceFactoryClient.
-// The DisplayCompositor receives CompositorFrames from all sources,
-// creates a top-level CompositorFrame once per tick, and generates graphical
-// output.
-class DisplayCompositor : public cc::SurfaceFactoryClient,
- public cc::DisplayClient {
- public:
- DisplayCompositor(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- gfx::AcceleratedWidget widget,
- const scoped_refptr<GpuState>& gpu_state,
- const scoped_refptr<SurfacesState>& surfaces_state);
- ~DisplayCompositor() override;
-
- // DisplayCompositor embedders submit a CompositorFrame when content on the
- // display should be changed. A well-behaving embedder should only submit
- // a CompositorFrame once per BeginFrame tick. The callback is called the
- // first time this frame is used to draw, or if the frame is discarded.
- void SubmitCompositorFrame(
- cc::CompositorFrame frame,
- const base::Callback<void(cc::SurfaceDrawStatus)>& callback);
-
- // TODO(fsamuel): This is used for surface hittesting and should not be
- // exposed outside of DisplayCompositor.
- const cc::SurfaceId& surface_id() const { return surface_id_; }
-
- // This requests the display CompositorFrame be rendered and given to the
- // callback within CopyOutputRequest.
- void RequestCopyOfOutput(
- std::unique_ptr<cc::CopyOutputRequest> output_request);
-
- // TODO(fsamuel): Invent an async way to create a SurfaceNamespace
- // A SurfaceNamespace can create CompositorFrameSinks where the client can
- // make up the ID.
-
- private:
- // SurfaceFactoryClient implementation.
- void ReturnResources(const cc::ReturnedResourceArray& resources) override;
- void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
-
- // DisplayClient implementation.
- void DisplayOutputSurfaceLost() override;
- void DisplaySetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override;
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- scoped_refptr<SurfacesState> surfaces_state_;
- cc::SurfaceFactory factory_;
- cc::SurfaceIdAllocator allocator_;
- cc::SurfaceId surface_id_;
-
- gfx::Size display_size_;
- std::unique_ptr<cc::Display> display_;
- DISALLOW_COPY_AND_ASSIGN(DisplayCompositor);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_SURFACES_DISPLAY_COMPOSITOR_H_
diff --git a/chromium/components/mus/surfaces/ozone_gpu_memory_buffer_manager.cc b/chromium/components/mus/surfaces/ozone_gpu_memory_buffer_manager.cc
deleted file mode 100644
index b14cd1394fe..00000000000
--- a/chromium/components/mus/surfaces/ozone_gpu_memory_buffer_manager.cc
+++ /dev/null
@@ -1,49 +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 "components/mus/surfaces/ozone_gpu_memory_buffer_manager.h"
-
-#include "components/mus/gles2/ozone_gpu_memory_buffer.h"
-#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
-#include "ui/gfx/buffer_types.h"
-
-namespace mus {
-
-OzoneGpuMemoryBufferManager::OzoneGpuMemoryBufferManager() {}
-
-OzoneGpuMemoryBufferManager::~OzoneGpuMemoryBufferManager() {}
-
-std::unique_ptr<gfx::GpuMemoryBuffer>
-OzoneGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle) {
- return OzoneGpuMemoryBuffer::CreateOzoneGpuMemoryBuffer(
- size, format, gfx::BufferUsage::SCANOUT, surface_handle);
-}
-
-std::unique_ptr<gfx::GpuMemoryBuffer>
-OzoneGpuMemoryBufferManager::CreateGpuMemoryBufferFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::BufferFormat format) {
- NOTIMPLEMENTED();
- return nullptr;
-}
-
-gfx::GpuMemoryBuffer*
-OzoneGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer(
- ClientBuffer buffer) {
- NOTIMPLEMENTED();
- return nullptr;
-}
-
-void OzoneGpuMemoryBufferManager::SetDestructionSyncToken(
- gfx::GpuMemoryBuffer* buffer,
- const gpu::SyncToken& sync_token) {
- NOTIMPLEMENTED();
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/surfaces/ozone_gpu_memory_buffer_manager.h b/chromium/components/mus/surfaces/ozone_gpu_memory_buffer_manager.h
deleted file mode 100644
index d6cf15f55fe..00000000000
--- a/chromium/components/mus/surfaces/ozone_gpu_memory_buffer_manager.h
+++ /dev/null
@@ -1,39 +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 COMPONENTS_MUS_SURFACES_DIRECT_OUTPUT_SURFACES_OZONE_H_
-#define COMPONENTS_MUS_SURFACES_DIRECT_OUTPUT_SURFACES_OZONE_H_
-
-#include "base/macros.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
-
-namespace mus {
-
-class OzoneGpuMemoryBufferManager : public gpu::GpuMemoryBufferManager {
- public:
- OzoneGpuMemoryBufferManager();
- ~OzoneGpuMemoryBufferManager() override;
-
- // gpu::GpuMemoryBufferManager:
- std::unique_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- gpu::SurfaceHandle surface_handle) override;
- std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBufferFromHandle(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- gfx::BufferFormat format) override;
- gfx::GpuMemoryBuffer* GpuMemoryBufferFromClientBuffer(
- ClientBuffer buffer) override;
- void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer,
- const gpu::SyncToken& sync_token) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(OzoneGpuMemoryBufferManager);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_SURFACES_DIRECT_OUTPUT_SURFACES_OZONE_H_
diff --git a/chromium/components/mus/surfaces/surfaces_context_provider.cc b/chromium/components/mus/surfaces/surfaces_context_provider.cc
deleted file mode 100644
index 291a4402eb5..00000000000
--- a/chromium/components/mus/surfaces/surfaces_context_provider.cc
+++ /dev/null
@@ -1,206 +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 "components/mus/surfaces/surfaces_context_provider.h"
-
-#include <stddef.h>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "components/mus/common/switches.h"
-#include "components/mus/gles2/command_buffer_driver.h"
-#include "components/mus/gles2/command_buffer_impl.h"
-#include "components/mus/gles2/command_buffer_local.h"
-#include "components/mus/gles2/gpu_state.h"
-#include "components/mus/gpu/gpu_service_mus.h"
-#include "components/mus/surfaces/surfaces_context_provider_delegate.h"
-#include "gpu/command_buffer/client/gles2_cmd_helper.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/command_buffer/client/shared_memory_limits.h"
-#include "gpu/command_buffer/client/transfer_buffer.h"
-#include "gpu/ipc/client/command_buffer_proxy_impl.h"
-#include "ui/gl/gpu_preference.h"
-
-namespace mus {
-
-SurfacesContextProvider::SurfacesContextProvider(
- gfx::AcceleratedWidget widget,
- const scoped_refptr<GpuState>& state)
- : use_chrome_gpu_command_buffer_(false),
- delegate_(nullptr),
- widget_(widget),
- command_buffer_local_(nullptr) {
-// TODO(penghuang): Kludge: Use mojo command buffer when running on Windows
-// since Chrome command buffer breaks unit tests
-#if defined(OS_WIN)
- use_chrome_gpu_command_buffer_ = false;
-#else
- use_chrome_gpu_command_buffer_ =
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseMojoGpuCommandBufferInMus);
-#endif
- if (!use_chrome_gpu_command_buffer_) {
- command_buffer_local_ = new CommandBufferLocal(this, widget_, state);
- } else {
- GpuServiceMus* service = GpuServiceMus::GetInstance();
- gpu::CommandBufferProxyImpl* shared_command_buffer = nullptr;
- gpu::GpuStreamId stream_id = gpu::GpuStreamId::GPU_STREAM_DEFAULT;
- gpu::GpuStreamPriority stream_priority = gpu::GpuStreamPriority::NORMAL;
- gpu::gles2::ContextCreationAttribHelper attributes;
- attributes.alpha_size = -1;
- attributes.depth_size = 0;
- attributes.stencil_size = 0;
- attributes.samples = 0;
- attributes.sample_buffers = 0;
- attributes.bind_generates_resource = false;
- attributes.lose_context_when_out_of_memory = true;
- GURL active_url;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- base::ThreadTaskRunnerHandle::Get();
- command_buffer_proxy_impl_ = gpu::CommandBufferProxyImpl::Create(
- service->gpu_channel_local(), widget, shared_command_buffer, stream_id,
- stream_priority, attributes, active_url, task_runner);
- command_buffer_proxy_impl_->SetSwapBuffersCompletionCallback(
- base::Bind(&SurfacesContextProvider::OnGpuSwapBuffersCompleted,
- base::Unretained(this)));
- command_buffer_proxy_impl_->SetUpdateVSyncParametersCallback(
- base::Bind(&SurfacesContextProvider::OnUpdateVSyncParameters,
- base::Unretained(this)));
- }
-}
-
-void SurfacesContextProvider::SetDelegate(
- SurfacesContextProviderDelegate* delegate) {
- DCHECK(!delegate_);
- delegate_ = delegate;
-}
-
-// This routine needs to be safe to call more than once.
-// This is called when we have an accelerated widget.
-bool SurfacesContextProvider::BindToCurrentThread() {
- if (implementation_)
- return true;
-
- // SurfacesContextProvider should always live on the same thread as the
- // Window Manager.
- DCHECK(CalledOnValidThread());
- gpu::GpuControl* gpu_control = nullptr;
- gpu::CommandBuffer* command_buffer = nullptr;
- if (!use_chrome_gpu_command_buffer_) {
- if (!command_buffer_local_->Initialize())
- return false;
- gpu_control = command_buffer_local_;
- command_buffer = command_buffer_local_;
- } else {
- if (!command_buffer_proxy_impl_)
- return false;
- gpu_control = command_buffer_proxy_impl_.get();
- command_buffer = command_buffer_proxy_impl_.get();
- }
-
- gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer));
- constexpr gpu::SharedMemoryLimits default_limits;
- if (!gles2_helper_->Initialize(default_limits.command_buffer_size))
- return false;
- gles2_helper_->SetAutomaticFlushes(false);
- transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get()));
- capabilities_ = gpu_control->GetCapabilities();
- bool bind_generates_resource =
- !!capabilities_.bind_generates_resource_chromium;
- // TODO(piman): Some contexts (such as compositor) want this to be true, so
- // this needs to be a public parameter.
- bool lose_context_when_out_of_memory = false;
- bool support_client_side_arrays = false;
- implementation_.reset(new gpu::gles2::GLES2Implementation(
- gles2_helper_.get(), NULL, transfer_buffer_.get(),
- bind_generates_resource, lose_context_when_out_of_memory,
- support_client_side_arrays, gpu_control));
- return implementation_->Initialize(
- default_limits.start_transfer_buffer_size,
- default_limits.min_transfer_buffer_size,
- default_limits.max_transfer_buffer_size,
- default_limits.mapped_memory_reclaim_limit);
-}
-
-gpu::gles2::GLES2Interface* SurfacesContextProvider::ContextGL() {
- DCHECK(implementation_);
- return implementation_.get();
-}
-
-gpu::ContextSupport* SurfacesContextProvider::ContextSupport() {
- return implementation_.get();
-}
-
-class GrContext* SurfacesContextProvider::GrContext() {
- return NULL;
-}
-
-void SurfacesContextProvider::InvalidateGrContext(uint32_t state) {}
-
-gpu::Capabilities SurfacesContextProvider::ContextCapabilities() {
- return capabilities_;
-}
-
-base::Lock* SurfacesContextProvider::GetLock() {
- // This context provider is not used on multiple threads.
- NOTREACHED();
- return nullptr;
-}
-
-void SurfacesContextProvider::SetLostContextCallback(
- const LostContextCallback& lost_context_callback) {
- implementation_->SetLostContextCallback(lost_context_callback);
-}
-
-SurfacesContextProvider::~SurfacesContextProvider() {
- implementation_->Flush();
- implementation_.reset();
- transfer_buffer_.reset();
- gles2_helper_.reset();
- command_buffer_proxy_impl_.reset();
- if (command_buffer_local_) {
- command_buffer_local_->Destroy();
- command_buffer_local_ = nullptr;
- }
-}
-
-void SurfacesContextProvider::UpdateVSyncParameters(
- const base::TimeTicks& timebase,
- const base::TimeDelta& interval) {
- if (delegate_)
- delegate_->OnVSyncParametersUpdated(timebase, interval);
-}
-
-void SurfacesContextProvider::GpuCompletedSwapBuffers(gfx::SwapResult result) {
- if (!swap_buffers_completion_callback_.is_null()) {
- swap_buffers_completion_callback_.Run(result);
- }
-}
-
-void SurfacesContextProvider::OnGpuSwapBuffersCompleted(
- const std::vector<ui::LatencyInfo>& latency_info,
- gfx::SwapResult result,
- const gpu::GpuProcessHostedCALayerTreeParamsMac* params_mac) {
- if (!swap_buffers_completion_callback_.is_null()) {
- swap_buffers_completion_callback_.Run(result);
- }
-}
-
-void SurfacesContextProvider::OnUpdateVSyncParameters(
- base::TimeTicks timebase,
- base::TimeDelta interval) {
- if (delegate_)
- delegate_->OnVSyncParametersUpdated(timebase, interval);
-}
-
-void SurfacesContextProvider::SetSwapBuffersCompletionCallback(
- gl::GLSurface::SwapCompletionCallback callback) {
- swap_buffers_completion_callback_ = callback;
-}
-
-} // namespace mus
diff --git a/chromium/components/mus/surfaces/surfaces_context_provider.h b/chromium/components/mus/surfaces/surfaces_context_provider.h
deleted file mode 100644
index 8dab0bcb9d6..00000000000
--- a/chromium/components/mus/surfaces/surfaces_context_provider.h
+++ /dev/null
@@ -1,109 +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 COMPONENTS_MUS_SURFACES_SURFACES_CONTEXT_PROVIDER_H_
-#define COMPONENTS_MUS_SURFACES_SURFACES_CONTEXT_PROVIDER_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/threading/non_thread_safe.h"
-#include "cc/output/context_provider.h"
-#include "components/mus/gles2/command_buffer_local_client.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gl/gl_surface.h"
-
-namespace gpu {
-
-class CommandBufferProxyImpl;
-struct GpuProcessHostedCALayerTreeParamsMac;
-class TransferBuffer;
-
-namespace gles2 {
-class GLES2CmdHelper;
-class GLES2Implementation;
-}
-
-} // namespace gpu
-
-namespace ui {
-class LatencyInfo;
-}
-
-namespace mus {
-
-class CommandBufferDriver;
-class CommandBufferImpl;
-class CommandBufferLocal;
-class GpuState;
-class SurfacesContextProviderDelegate;
-
-class SurfacesContextProvider : public cc::ContextProvider,
- public CommandBufferLocalClient,
- public base::NonThreadSafe {
- public:
- SurfacesContextProvider(gfx::AcceleratedWidget widget,
- const scoped_refptr<GpuState>& state);
-
- void SetDelegate(SurfacesContextProviderDelegate* delegate);
-
- // cc::ContextProvider implementation.
- bool BindToCurrentThread() override;
- gpu::gles2::GLES2Interface* ContextGL() override;
- gpu::ContextSupport* ContextSupport() override;
- class GrContext* GrContext() override;
- void InvalidateGrContext(uint32_t state) override;
- gpu::Capabilities ContextCapabilities() override;
- void DeleteCachedResources() override {}
- void SetLostContextCallback(
- const LostContextCallback& lost_context_callback) override;
- base::Lock* GetLock() override;
-
- // SurfacesContextProvider API.
- void SetSwapBuffersCompletionCallback(
- gl::GLSurface::SwapCompletionCallback callback);
-
- protected:
- friend class base::RefCountedThreadSafe<SurfacesContextProvider>;
- ~SurfacesContextProvider() override;
-
- private:
- // CommandBufferLocalClient:
- void UpdateVSyncParameters(const base::TimeTicks& timebase,
- const base::TimeDelta& interval) override;
- void GpuCompletedSwapBuffers(gfx::SwapResult result) override;
-
- // Callbacks for CommandBufferProxyImpl:
- void OnGpuSwapBuffersCompleted(
- const std::vector<ui::LatencyInfo>& latency_info,
- gfx::SwapResult result,
- const gpu::GpuProcessHostedCALayerTreeParamsMac* params_mac);
- void OnUpdateVSyncParameters(base::TimeTicks timebase,
- base::TimeDelta interval);
-
- bool use_chrome_gpu_command_buffer_;
-
- // From GLES2Context:
- // Initialized in BindToCurrentThread.
- std::unique_ptr<gpu::gles2::GLES2CmdHelper> gles2_helper_;
- std::unique_ptr<gpu::TransferBuffer> transfer_buffer_;
- std::unique_ptr<gpu::gles2::GLES2Implementation> implementation_;
-
- gpu::Capabilities capabilities_;
- LostContextCallback lost_context_callback_;
-
- SurfacesContextProviderDelegate* delegate_;
- gfx::AcceleratedWidget widget_;
- CommandBufferLocal* command_buffer_local_;
- std::unique_ptr<gpu::CommandBufferProxyImpl> command_buffer_proxy_impl_;
- gl::GLSurface::SwapCompletionCallback swap_buffers_completion_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(SurfacesContextProvider);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_SURFACES_SURFACES_CONTEXT_PROVIDER_H_
diff --git a/chromium/components/mus/surfaces/surfaces_context_provider_delegate.h b/chromium/components/mus/surfaces/surfaces_context_provider_delegate.h
deleted file mode 100644
index 170190a923f..00000000000
--- a/chromium/components/mus/surfaces/surfaces_context_provider_delegate.h
+++ /dev/null
@@ -1,28 +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 COMPONENTS_MUS_SURFACES_SURFACES_CONTEXT_PROVIDER_DELEGATE_H_
-#define COMPONENTS_MUS_SURFACES_SURFACES_CONTEXT_PROVIDER_DELEGATE_H_
-
-#include <stdint.h>
-
-namespace base {
-class TimeDelta;
-class TimeTicks;
-}
-
-namespace mus {
-
-class SurfacesContextProviderDelegate {
- public:
- virtual void OnVSyncParametersUpdated(const base::TimeTicks& timebase,
- const base::TimeDelta& interval) = 0;
-
- protected:
- virtual ~SurfacesContextProviderDelegate() {}
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_SURFACES_SURFACES_CONTEXT_PROVIDER_DELEGATE_H_
diff --git a/chromium/components/mus/surfaces/surfaces_state.cc b/chromium/components/mus/surfaces/surfaces_state.cc
deleted file mode 100644
index e3dfeb8d85d..00000000000
--- a/chromium/components/mus/surfaces/surfaces_state.cc
+++ /dev/null
@@ -1,13 +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 "components/mus/surfaces/surfaces_state.h"
-
-namespace mus {
-
-SurfacesState::SurfacesState() : next_id_namespace_(1u) {}
-
-SurfacesState::~SurfacesState() {}
-
-} // namespace mus
diff --git a/chromium/components/mus/surfaces/surfaces_state.h b/chromium/components/mus/surfaces/surfaces_state.h
deleted file mode 100644
index daaf5587ab6..00000000000
--- a/chromium/components/mus/surfaces/surfaces_state.h
+++ /dev/null
@@ -1,49 +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 COMPONENTS_MUS_SURFACES_SURFACES_STATE_H_
-#define COMPONENTS_MUS_SURFACES_SURFACES_STATE_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "cc/surfaces/surface_manager.h"
-
-namespace cc {
-class SurfaceHittest;
-class SurfaceManager;
-} // namespace cc
-
-namespace mus {
-
-// The SurfacesState object is an object global to the Window Manager app that
-// holds the SurfaceManager and allocates new Surfaces namespaces.
-// This object lives on the main thread of the Window Manager.
-// TODO(rjkroege, fsamuel): This object will need to change to support multiple
-// displays.
-class SurfacesState : public base::RefCounted<SurfacesState> {
- public:
- SurfacesState();
-
- uint32_t next_id_namespace() { return next_id_namespace_++; }
-
- cc::SurfaceManager* manager() { return &manager_; }
-
- private:
- friend class base::RefCounted<SurfacesState>;
- ~SurfacesState();
-
- // A Surface ID is an unsigned 64-bit int where the high 32-bits are generated
- // by the Surfaces service, and the low 32-bits are generated by the process
- // that requested the Surface.
- uint32_t next_id_namespace_;
- cc::SurfaceManager manager_;
-
- DISALLOW_COPY_AND_ASSIGN(SurfacesState);
-};
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_SURFACES_SURFACES_STATE_H_
diff --git a/chromium/components/mus/test_wm/BUILD.gn b/chromium/components/mus/test_wm/BUILD.gn
deleted file mode 100644
index 92c2c9292f8..00000000000
--- a/chromium/components/mus/test_wm/BUILD.gn
+++ /dev/null
@@ -1,31 +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.
-
-import("//mojo/public/mojo_application.gni")
-import("//mojo/public/mojo_application_manifest.gni")
-
-mojo_native_application("test_wm") {
- sources = [
- "test_wm.cc",
- ]
-
- deps = [
- "//base",
- "//components/mus/public/cpp",
- "//components/mus/public/interfaces",
- "//services/shell/public/cpp",
- "//ui/display/mojo",
- "//ui/gfx/geometry/mojo",
- ]
-
- data_deps = [
- ":manifest",
- "//components/mus",
- ]
-}
-
-mojo_application_manifest("manifest") {
- application_name = "test_wm"
- source = "manifest.json"
-}
diff --git a/chromium/components/mus/test_wm/manifest.json b/chromium/components/mus/test_wm/manifest.json
deleted file mode 100644
index 67f2fa96671..00000000000
--- a/chromium/components/mus/test_wm/manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "manifest_version": 1,
- "name": "mojo:test_wm",
- "display_name": "Test Window Manager",
- "capabilities": {
- "required": {
- "mojo:mus": { "interfaces": [ "mus::mojom::WindowManagerWindowTreeFactory" ] }
- }
- }
-}
diff --git a/chromium/components/mus/test_wm/test_wm.cc b/chromium/components/mus/test_wm/test_wm.cc
deleted file mode 100644
index 39ad3759839..00000000000
--- a/chromium/components/mus/test_wm/test_wm.cc
+++ /dev/null
@@ -1,107 +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 "components/mus/public/cpp/window.h"
-#include "components/mus/public/cpp/window_manager_delegate.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-#include "components/mus/public/cpp/window_tree_client_delegate.h"
-#include "mojo/public/c/system/main.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/shell/public/cpp/application_runner.h"
-#include "services/shell/public/cpp/connector.h"
-#include "services/shell/public/cpp/shell_client.h"
-#include "ui/display/display.h"
-#include "ui/display/mojo/display_type_converters.h"
-
-namespace mus {
-namespace test {
-
-class TestWM : public shell::ShellClient,
- public mus::WindowTreeClientDelegate,
- public mus::WindowManagerDelegate {
- public:
- TestWM() {}
- ~TestWM() override { delete window_tree_client_; }
-
- private:
- // shell::ShellClient:
- void Initialize(shell::Connector* connector,
- const shell::Identity& identity,
- uint32_t id) override {
- window_tree_client_ = new mus::WindowTreeClient(this, this, nullptr);
- window_tree_client_->ConnectAsWindowManager(connector);
- }
- bool AcceptConnection(shell::Connection* connection) override {
- return true;
- }
-
- // mus::WindowTreeClientDelegate:
- void OnEmbed(mus::Window* root) override {
- // WindowTreeClients configured as the window manager should never get
- // OnEmbed().
- NOTREACHED();
- }
- void OnWindowTreeClientDestroyed(mus::WindowTreeClient* client) override {
- window_tree_client_ = nullptr;
- }
- void OnEventObserved(const ui::Event& event, mus::Window* target) override {
- // Don't care.
- }
-
- // mus::WindowManagerDelegate:
- void SetWindowManagerClient(mus::WindowManagerClient* client) override {
- window_manager_client_ = client;
- }
- bool OnWmSetBounds(mus::Window* window, gfx::Rect* bounds) override {
- return true;
- }
- bool OnWmSetProperty(
- mus::Window* window,
- const std::string& name,
- std::unique_ptr<std::vector<uint8_t>>* new_data) override {
- return true;
- }
- mus::Window* OnWmCreateTopLevelWindow(
- std::map<std::string, std::vector<uint8_t>>* properties) override {
- mus::Window* window = root_->window_tree()->NewWindow(properties);
- window->SetBounds(gfx::Rect(10, 10, 500, 500));
- root_->AddChild(window);
- return window;
- }
- void OnWmClientJankinessChanged(const std::set<Window*>& client_windows,
- bool janky) override {
- // Don't care.
- }
- void OnWmNewDisplay(Window* window,
- const display::Display& display) override {
- // Only handles a single root.
- DCHECK(!root_);
- root_ = window;
- DCHECK(window_manager_client_);
- window_manager_client_->AddActivationParent(root_);
- mus::mojom::FrameDecorationValuesPtr frame_decoration_values =
- mus::mojom::FrameDecorationValues::New();
- frame_decoration_values->max_title_bar_button_width = 0;
- window_manager_client_->SetFrameDecorationValues(
- std::move(frame_decoration_values));
- }
- void OnAccelerator(uint32_t id, const ui::Event& event) override {
- // Don't care.
- }
-
- mus::Window* root_ = nullptr;
- mus::WindowManagerClient* window_manager_client_ = nullptr;
- // See WindowTreeClient for details on ownership.
- mus::WindowTreeClient* window_tree_client_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(TestWM);
-};
-
-} // namespace test
-} // namespace mus
-
-MojoResult MojoMain(MojoHandle shell_handle) {
- shell::ApplicationRunner runner(new mus::test::TestWM);
- return runner.Run(shell_handle);
-}
diff --git a/chromium/components/mus/ws/BUILD.gn b/chromium/components/mus/ws/BUILD.gn
deleted file mode 100644
index 4a7ccd1063f..00000000000
--- a/chromium/components/mus/ws/BUILD.gn
+++ /dev/null
@@ -1,254 +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("//build/config/ui.gni")
-import("//testing/test.gni")
-import("//mojo/public/mojo_application.gni")
-import("//mojo/public/mojo_application_manifest.gni")
-
-source_set("lib") {
- sources = [
- "accelerator.cc",
- "accelerator.h",
- "access_policy.h",
- "access_policy_delegate.h",
- "animation_runner.cc",
- "animation_runner.h",
- "animation_runner_observer.h",
- "default_access_policy.cc",
- "default_access_policy.h",
- "display.cc",
- "display.h",
- "display_binding.cc",
- "display_binding.h",
- "display_manager.cc",
- "display_manager.h",
- "display_manager_delegate.h",
- "event_dispatcher.cc",
- "event_dispatcher.h",
- "event_dispatcher_delegate.h",
- "event_matcher.cc",
- "event_matcher.h",
- "focus_controller.cc",
- "focus_controller.h",
- "focus_controller_delegate.h",
- "focus_controller_observer.h",
- "modal_window_controller.cc",
- "modal_window_controller.h",
- "operation.cc",
- "operation.h",
- "platform_display.cc",
- "platform_display.h",
- "platform_display_delegate.h",
- "platform_display_factory.h",
- "platform_display_init_params.cc",
- "platform_display_init_params.h",
- "platform_screen.h",
- "platform_screen_impl.cc",
- "platform_screen_impl.h",
- "scheduled_animation_group.cc",
- "scheduled_animation_group.h",
- "server_window.cc",
- "server_window.h",
- "server_window_delegate.h",
- "server_window_drawn_tracker.cc",
- "server_window_drawn_tracker.h",
- "server_window_drawn_tracker_observer.h",
- "server_window_observer.h",
- "server_window_surface.cc",
- "server_window_surface.h",
- "server_window_surface_manager.cc",
- "server_window_surface_manager.h",
- "server_window_tracker.h",
- "touch_controller.cc",
- "touch_controller.h",
- "user_activity_monitor.cc",
- "user_activity_monitor.h",
- "user_display_manager.cc",
- "user_display_manager.h",
- "user_id.h",
- "user_id_tracker.cc",
- "user_id_tracker.h",
- "user_id_tracker_observer.h",
- "window_coordinate_conversions.cc",
- "window_coordinate_conversions.h",
- "window_finder.cc",
- "window_finder.h",
- "window_manager_access_policy.cc",
- "window_manager_access_policy.h",
- "window_manager_display_root.cc",
- "window_manager_display_root.h",
- "window_manager_state.cc",
- "window_manager_state.h",
- "window_manager_window_tree_factory.cc",
- "window_manager_window_tree_factory.h",
- "window_manager_window_tree_factory_set.cc",
- "window_manager_window_tree_factory_set.h",
- "window_manager_window_tree_factory_set_observer.h",
- "window_server.cc",
- "window_server.h",
- "window_server_delegate.cc",
- "window_server_delegate.h",
- "window_tree.cc",
- "window_tree.h",
- "window_tree_binding.cc",
- "window_tree_binding.h",
- "window_tree_factory.cc",
- "window_tree_factory.h",
- "window_tree_host_factory.cc",
- "window_tree_host_factory.h",
- ]
-
- public_deps = [
- "//base",
- "//cc",
- "//cc/ipc:interfaces",
- "//cc/surfaces",
- "//cc/surfaces:surface_id",
- "//components/mus/common:mus_common",
- "//components/mus/gles2",
- "//components/mus/public/interfaces",
- "//components/mus/surfaces",
- "//mojo/common:common_base",
- "//mojo/public/cpp/bindings",
- "//services/shell/public/cpp",
- "//services/shell/public/interfaces",
- "//services/tracing/public/cpp",
- "//ui/base",
- "//ui/display",
- "//ui/events",
- "//ui/events/devices",
- "//ui/events/platform",
- "//ui/gfx",
- "//ui/gfx/geometry",
- "//ui/gfx/geometry/mojo",
- "//ui/gl",
- "//ui/platform_window",
- "//ui/platform_window:platform_impls",
- "//ui/platform_window/mojo",
- ]
-
- if (use_ozone) {
- sources -= [
- "platform_screen_impl.cc",
- "platform_screen_impl.h",
- ]
- sources += [
- "platform_screen_impl_ozone.cc",
- "platform_screen_impl_ozone.h",
- ]
- public_deps += [ "//ui/ozone:ozone" ]
- }
-}
-
-source_set("test_interface") {
- sources = [
- "window_server_test_impl.cc",
- "window_server_test_impl.h",
- ]
-
- deps = [
- ":lib",
- "//components/mus/public/interfaces",
- "//mojo/public/cpp/bindings:bindings",
- "//ui/gfx",
- ]
-}
-
-source_set("test_support") {
- testonly = true
-
- sources = [
- "test_change_tracker.cc",
- "test_change_tracker.h",
- ]
-
- deps = [
- "//base",
- "//components/mus/common:mus_common",
- "//components/mus/public/cpp",
- "//components/mus/public/interfaces",
- "//mojo/common",
- "//mojo/public/cpp/bindings:bindings",
- "//ui/gfx/geometry/mojo",
- ]
-}
-
-group("tests") {
- testonly = true
- deps = [
- ":mus_ws_unittests",
- ]
- if (!is_android) {
- deps += [ "//components/mus/public/cpp/tests:mus_public_unittests" ]
- }
-}
-
-test("mus_ws_unittests") {
- sources = [
- "animation_runner_unittest.cc",
- "cursor_unittest.cc",
- "display_unittest.cc",
- "event_dispatcher_unittest.cc",
- "event_matcher_unittest.cc",
- "focus_controller_unittest.cc",
- "scheduled_animation_group_unittest.cc",
- "server_window_drawn_tracker_unittest.cc",
- "server_window_surface_manager_test_api.cc",
- "server_window_surface_manager_test_api.h",
- "test_server_window_delegate.cc",
- "test_server_window_delegate.h",
- "test_utils.cc",
- "test_utils.h",
- "transient_windows_unittest.cc",
- "user_activity_monitor_unittest.cc",
- "user_display_manager_unittest.cc",
- "window_coordinate_conversions_unittest.cc",
- "window_finder_unittest.cc",
- "window_manager_client_unittest.cc",
- "window_manager_state_unittest.cc",
- "window_tree_client_unittest.cc",
- "window_tree_unittest.cc",
- ]
-
- deps = [
- ":lib",
- ":test_support",
- "//base",
- "//base/test:test_config",
- "//base/test:test_support",
- "//cc:cc",
- "//components/mus/common:mus_common",
- "//components/mus/public/cpp",
- "//components/mus/public/cpp/tests:test_support",
- "//components/mus/public/interfaces",
- "//components/mus/surfaces",
- "//mojo/public/cpp/bindings:bindings",
- "//services/shell/public/cpp:shell_test_support",
- "//services/shell/public/cpp:sources",
- "//services/shell/public/cpp/test:run_all_shelltests",
- "//services/shell/public/interfaces",
- "//testing/gtest",
- "//third_party/mesa:osmesa",
- "//ui/events",
- "//ui/gfx",
- "//ui/gfx:test_support",
- "//ui/gfx/geometry",
- "//ui/gfx/geometry/mojo",
- "//ui/gl",
- ]
-
- if (use_x11) {
- deps += [ "//tools/xdisplaycheck" ]
- }
-
- data_deps = [
- ":mus_ws_unittests_app_manifest",
- ]
-}
-
-mojo_application_manifest("mus_ws_unittests_app_manifest") {
- application_name = "mus_ws_unittests_app"
- source = "mus_ws_unittests_app_manifest.json"
-}
diff --git a/chromium/components/mus/ws/accelerator.cc b/chromium/components/mus/ws/accelerator.cc
deleted file mode 100644
index fd8cde39668..00000000000
--- a/chromium/components/mus/ws/accelerator.cc
+++ /dev/null
@@ -1,33 +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 "components/mus/ws/accelerator.h"
-
-namespace mus {
-namespace ws {
-
-Accelerator::Accelerator(uint32_t id, const mojom::EventMatcher& matcher)
- : id_(id),
- accelerator_phase_(matcher.accelerator_phase),
- event_matcher_(matcher),
- weak_factory_(this) {}
-
-Accelerator::~Accelerator() {}
-
-bool Accelerator::MatchesEvent(const ui::Event& event,
- const ui::mojom::AcceleratorPhase phase) const {
- if (accelerator_phase_ != phase)
- return false;
- if (!event_matcher_.MatchesEvent(event))
- return false;
- return true;
-}
-
-bool Accelerator::EqualEventMatcher(const Accelerator* other) const {
- return accelerator_phase_ == other->accelerator_phase_ &&
- event_matcher_.Equals(other->event_matcher_);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/accelerator.h b/chromium/components/mus/ws/accelerator.h
deleted file mode 100644
index 2113ad1ec9b..00000000000
--- a/chromium/components/mus/ws/accelerator.h
+++ /dev/null
@@ -1,57 +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 COMPONENTS_MUS_WS_ACCELERATOR_H_
-#define COMPONENTS_MUS_WS_ACCELERATOR_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/mus/public/interfaces/event_matcher.mojom.h"
-#include "components/mus/ws/event_matcher.h"
-
-namespace ui {
-class Event;
-}
-
-namespace mus {
-namespace ws {
-
-// An Accelerator encompasses an id defined by the client, along with a unique
-// mojom::EventMatcher. See WindowManagerClient.
-//
-// This provides a WeakPtr, as the client might delete the accelerator between
-// an event having been matched and the dispatch of the accelerator to the
-// client.
-class Accelerator {
- public:
- Accelerator(uint32_t id, const mojom::EventMatcher& matcher);
- ~Accelerator();
-
- // Returns true if |event| and |phase | matches the definition in the
- // mojom::EventMatcher used for initialization.
- bool MatchesEvent(const ui::Event& event,
- const ui::mojom::AcceleratorPhase phase) const;
-
- // Returns true if |other| was created with an identical mojom::EventMatcher.
- bool EqualEventMatcher(const Accelerator* other) const;
-
- base::WeakPtr<Accelerator> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
-
- uint32_t id() const { return id_; }
-
- private:
- uint32_t id_;
- ui::mojom::AcceleratorPhase accelerator_phase_;
- EventMatcher event_matcher_;
- base::WeakPtrFactory<Accelerator> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(Accelerator);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_ACCELERATOR_H_
diff --git a/chromium/components/mus/ws/access_policy.h b/chromium/components/mus/ws/access_policy.h
deleted file mode 100644
index 2f0cb366cc5..00000000000
--- a/chromium/components/mus/ws/access_policy.h
+++ /dev/null
@@ -1,84 +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 COMPONENTS_MUS_WS_ACCESS_POLICY_H_
-#define COMPONENTS_MUS_WS_ACCESS_POLICY_H_
-
-#include <stdint.h>
-
-#include "components/mus/public/interfaces/mus_constants.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/ws/ids.h"
-
-namespace mus {
-namespace ws {
-
-class AccessPolicyDelegate;
-class ServerWindow;
-
-// AccessPolicy is used by WindowTree to determine what the WindowTree is
-// allowed to do.
-class AccessPolicy {
- public:
- virtual ~AccessPolicy() {}
-
- virtual void Init(ClientSpecificId client_id,
- AccessPolicyDelegate* delegate) = 0;
-
- // Unless otherwise mentioned all arguments have been validated. That is the
- // |window| arguments are non-null unless otherwise stated (eg CanSetWindow()
- // is allowed to take a NULL window).
- virtual bool CanRemoveWindowFromParent(const ServerWindow* window) const = 0;
- virtual bool CanAddWindow(const ServerWindow* parent,
- const ServerWindow* child) const = 0;
- virtual bool CanAddTransientWindow(const ServerWindow* parent,
- const ServerWindow* child) const = 0;
- virtual bool CanRemoveTransientWindowFromParent(
- const ServerWindow* window) const = 0;
- virtual bool CanSetModal(const ServerWindow* window) const = 0;
- virtual bool CanReorderWindow(const ServerWindow* window,
- const ServerWindow* relative_window,
- mojom::OrderDirection direction) const = 0;
- virtual bool CanDeleteWindow(const ServerWindow* window) const = 0;
- virtual bool CanGetWindowTree(const ServerWindow* window) const = 0;
- // Used when building a window tree (GetWindowTree()) to decide if we should
- // descend into |window|.
- virtual bool CanDescendIntoWindowForWindowTree(
- const ServerWindow* window) const = 0;
- virtual bool CanEmbed(const ServerWindow* window) const = 0;
- virtual bool CanChangeWindowVisibility(const ServerWindow* window) const = 0;
- virtual bool CanChangeWindowOpacity(const ServerWindow* window) const = 0;
- virtual bool CanSetWindowSurface(const ServerWindow* window,
- mojom::SurfaceType surface_type) const = 0;
- virtual bool CanSetWindowBounds(const ServerWindow* window) const = 0;
- virtual bool CanSetWindowProperties(const ServerWindow* window) const = 0;
- virtual bool CanSetWindowTextInputState(const ServerWindow* window) const = 0;
- virtual bool CanSetCapture(const ServerWindow* window) const = 0;
- virtual bool CanSetFocus(const ServerWindow* window) const = 0;
- virtual bool CanSetClientArea(const ServerWindow* window) const = 0;
- virtual bool CanSetHitTestMask(const ServerWindow* window) const = 0;
- // Used for all client controllable cursor properties; which cursor should be
- // displayed, visibility, locking, etc.
- virtual bool CanSetCursorProperties(const ServerWindow* window) const = 0;
-
- // Returns whether the client should notify on a hierarchy change.
- // |new_parent| and |old_parent| are initially set to the new and old parents
- // but may be altered so that the client only sees a certain set of windows.
- virtual bool ShouldNotifyOnHierarchyChange(
- const ServerWindow* window,
- const ServerWindow** new_parent,
- const ServerWindow** old_parent) const = 0;
- virtual bool CanSetWindowManager() const = 0;
-
- // Returns the window to supply to the client when focus changes to |focused|.
- virtual const ServerWindow* GetWindowForFocusChange(
- const ServerWindow* focused) = 0;
-
- virtual bool IsValidIdForNewWindow(const ClientWindowId& id) const = 0;
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_ACCESS_POLICY_H_
diff --git a/chromium/components/mus/ws/access_policy_delegate.h b/chromium/components/mus/ws/access_policy_delegate.h
deleted file mode 100644
index 3e33de55c46..00000000000
--- a/chromium/components/mus/ws/access_policy_delegate.h
+++ /dev/null
@@ -1,41 +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 COMPONENTS_MUS_WS_ACCESS_POLICY_DELEGATE_H_
-#define COMPONENTS_MUS_WS_ACCESS_POLICY_DELEGATE_H_
-
-#include <vector>
-
-#include "base/containers/hash_tables.h"
-#include "components/mus/ws/ids.h"
-
-namespace mus {
-
-namespace ws {
-
-class ServerWindow;
-
-// Delegate used by the AccessPolicy implementations to get state.
-class AccessPolicyDelegate {
- public:
- // Returns true if the tree has |window| as one of its roots.
- virtual bool HasRootForAccessPolicy(const ServerWindow* window) const = 0;
-
- // Returns true if |window| has been exposed to the client.
- virtual bool IsWindowKnownForAccessPolicy(
- const ServerWindow* window) const = 0;
-
- // Returns true if Embed(window) has been invoked on |window|.
- virtual bool IsWindowRootOfAnotherTreeForAccessPolicy(
- const ServerWindow* window) const = 0;
-
- protected:
- virtual ~AccessPolicyDelegate() {}
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_ACCESS_POLICY_DELEGATE_H_
diff --git a/chromium/components/mus/ws/animation_runner.cc b/chromium/components/mus/ws/animation_runner.cc
deleted file mode 100644
index 080fb2c0f45..00000000000
--- a/chromium/components/mus/ws/animation_runner.cc
+++ /dev/null
@@ -1,163 +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 "components/mus/ws/animation_runner.h"
-
-#include "base/memory/scoped_vector.h"
-#include "components/mus/ws/animation_runner_observer.h"
-#include "components/mus/ws/scheduled_animation_group.h"
-#include "components/mus/ws/server_window.h"
-
-namespace mus {
-namespace ws {
-namespace {
-
-bool ConvertWindowAndAnimationPairsToScheduledAnimationGroups(
- const std::vector<AnimationRunner::WindowAndAnimationPair>& pairs,
- AnimationRunner::AnimationId id,
- base::TimeTicks now,
- std::vector<std::unique_ptr<ScheduledAnimationGroup>>* groups) {
- for (const auto& window_animation_pair : pairs) {
- DCHECK(window_animation_pair.first);
- DCHECK(window_animation_pair.second);
- std::unique_ptr<ScheduledAnimationGroup> group(
- ScheduledAnimationGroup::Create(window_animation_pair.first, now, id,
- *(window_animation_pair.second)));
- if (!group.get())
- return false;
- groups->push_back(std::move(group));
- }
- return true;
-}
-
-} // namespace
-
-AnimationRunner::AnimationRunner(base::TimeTicks now)
- : next_id_(1), last_tick_time_(now) {}
-
-AnimationRunner::~AnimationRunner() {}
-
-void AnimationRunner::AddObserver(AnimationRunnerObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void AnimationRunner::RemoveObserver(AnimationRunnerObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-AnimationRunner::AnimationId AnimationRunner::Schedule(
- const std::vector<WindowAndAnimationPair>& pairs,
- base::TimeTicks now) {
- DCHECK_GE(now, last_tick_time_);
-
- const AnimationId animation_id = next_id_++;
- std::vector<std::unique_ptr<ScheduledAnimationGroup>> groups;
- if (!ConvertWindowAndAnimationPairsToScheduledAnimationGroups(
- pairs, animation_id, now, &groups)) {
- return 0;
- }
-
- // Cancel any animations for the affected windows. If the cancelled animations
- // also animated properties that are not animated by the new group - instantly
- // set those to the target value.
- for (auto& group : groups) {
- ScheduledAnimationGroup* current_group =
- window_to_animation_map_[group->window()].get();
- if (current_group)
- current_group->SetValuesToTargetValuesForPropertiesNotIn(*group.get());
-
- CancelAnimationForWindowImpl(group->window(), CANCEL_SOURCE_SCHEDULE);
- }
-
- // Update internal maps
- for (auto& group : groups) {
- group->ObtainStartValues();
- ServerWindow* window = group->window();
- window_to_animation_map_[window] = std::move(group);
- DCHECK(!id_to_windows_map_[animation_id].count(window));
- id_to_windows_map_[animation_id].insert(window);
- }
-
- FOR_EACH_OBSERVER(AnimationRunnerObserver, observers_,
- OnAnimationScheduled(animation_id));
- return animation_id;
-}
-
-void AnimationRunner::CancelAnimation(AnimationId id) {
- if (id_to_windows_map_.count(id) == 0)
- return;
-
- std::set<ServerWindow*> windows(id_to_windows_map_[id]);
- for (ServerWindow* window : windows)
- CancelAnimationForWindow(window);
-}
-
-void AnimationRunner::CancelAnimationForWindow(ServerWindow* window) {
- CancelAnimationForWindowImpl(window, CANCEL_SOURCE_CANCEL);
-}
-
-void AnimationRunner::Tick(base::TimeTicks time) {
- DCHECK(time >= last_tick_time_);
- last_tick_time_ = time;
- if (window_to_animation_map_.empty())
- return;
-
- // The animation ids of any windows whose animation completes are added here.
- // We notify after processing all windows so that if an observer mutates us in
- // some way we're aren't left in a weird state.
- std::set<AnimationId> animations_completed;
- for (WindowToAnimationMap::iterator i = window_to_animation_map_.begin();
- i != window_to_animation_map_.end();) {
- bool animation_done = i->second->Tick(time);
- if (animation_done) {
- const AnimationId animation_id = i->second->id();
- ServerWindow* window = i->first;
- ++i;
- bool animation_completed = RemoveWindowFromMaps(window);
- if (animation_completed)
- animations_completed.insert(animation_id);
- } else {
- ++i;
- }
- }
- for (const AnimationId& id : animations_completed) {
- FOR_EACH_OBSERVER(AnimationRunnerObserver, observers_, OnAnimationDone(id));
- }
-}
-
-void AnimationRunner::CancelAnimationForWindowImpl(ServerWindow* window,
- CancelSource source) {
- if (!window_to_animation_map_[window])
- return;
-
- const AnimationId animation_id = window_to_animation_map_[window]->id();
- if (RemoveWindowFromMaps(window)) {
- // This was the last window in the group.
- if (source == CANCEL_SOURCE_CANCEL) {
- FOR_EACH_OBSERVER(AnimationRunnerObserver, observers_,
- OnAnimationCanceled(animation_id));
- } else {
- FOR_EACH_OBSERVER(AnimationRunnerObserver, observers_,
- OnAnimationInterrupted(animation_id));
- }
- }
-}
-
-bool AnimationRunner::RemoveWindowFromMaps(ServerWindow* window) {
- DCHECK(window_to_animation_map_[window]);
-
- const AnimationId animation_id = window_to_animation_map_[window]->id();
- window_to_animation_map_.erase(window);
-
- DCHECK(id_to_windows_map_.count(animation_id));
- id_to_windows_map_[animation_id].erase(window);
- if (!id_to_windows_map_[animation_id].empty())
- return false;
-
- id_to_windows_map_.erase(animation_id);
- return true;
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/animation_runner.h b/chromium/components/mus/ws/animation_runner.h
deleted file mode 100644
index 5a7d80c4774..00000000000
--- a/chromium/components/mus/ws/animation_runner.h
+++ /dev/null
@@ -1,119 +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 COMPONENTS_MUS_WS_ANIMATION_RUNNER_H_
-#define COMPONENTS_MUS_WS_ANIMATION_RUNNER_H_
-
-#include <algorithm>
-#include <map>
-#include <memory>
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-#include "base/observer_list.h"
-#include "base/time/time.h"
-
-namespace mus {
-namespace mojom {
-class AnimationGroup;
-}
-
-namespace ws {
-
-class AnimationRunnerObserver;
-class ScheduledAnimationGroup;
-class ServerWindow;
-
-// AnimationRunner is responsible for maintaining and running a set of
-// animations. The animations are represented as a set of AnimationGroups. New
-// animations are scheduled by way of Schedule(). A |window| may only have one
-// animation running at a time. Schedule()ing a new animation for a window
-// already animating implicitly cancels the current animation for the window.
-// Animations progress by way of the Tick() function.
-class AnimationRunner {
- public:
- using AnimationId = uint32_t;
- using WindowAndAnimationPair =
- std::pair<ServerWindow*, const mojom::AnimationGroup*>;
-
- explicit AnimationRunner(base::TimeTicks now);
- ~AnimationRunner();
-
- void AddObserver(AnimationRunnerObserver* observer);
- void RemoveObserver(AnimationRunnerObserver* observer);
-
- // Schedules animations. If any of the groups are not valid no animations are
- // scheuled and 0 is returned. If there is an existing animation in progress
- // for any of the windows it is canceled and any properties that were
- // animating but are no longer animating are set to their target value.
- AnimationId Schedule(const std::vector<WindowAndAnimationPair>& groups,
- base::TimeTicks now);
-
- // Cancels an animation scheduled by an id that was previously returned from
- // Schedule().
- void CancelAnimation(AnimationId id);
-
- // Cancels the animation scheduled for |window|. Does nothing if there is no
- // animation scheduled for |window|. This does not change |window|. That is,
- // any in progress animations are stopped.
- void CancelAnimationForWindow(ServerWindow* window);
-
- // Advance the animations updating values appropriately.
- void Tick(base::TimeTicks time);
-
- // Returns true if there are animations currently scheduled.
- bool HasAnimations() const { return !window_to_animation_map_.empty(); }
-
- // Returns true if the animation identified by |id| is valid and animating.
- bool IsAnimating(AnimationId id) const {
- return id_to_windows_map_.count(id) > 0;
- }
-
- // Returns the windows that are currently animating for |id|. Returns an empty
- // set if |id| does not identify a valid animation.
- std::set<ServerWindow*> GetWindowsAnimating(AnimationId id) {
- return IsAnimating(id) ? id_to_windows_map_.find(id)->second
- : std::set<ServerWindow*>();
- }
-
- private:
- enum CancelSource {
- // Cancel is the result of scheduling another animation for the window.
- CANCEL_SOURCE_SCHEDULE,
-
- // Cancel originates from an explicit call to cancel.
- CANCEL_SOURCE_CANCEL,
- };
-
- using WindowToAnimationMap =
- std::unordered_map<ServerWindow*,
- std::unique_ptr<ScheduledAnimationGroup>>;
- using IdToWindowsMap = std::map<AnimationId, std::set<ServerWindow*>>;
-
- void CancelAnimationForWindowImpl(ServerWindow* window, CancelSource source);
-
- // Removes |window| from both |window_to_animation_map_| and
- // |id_to_windows_map_|.
- // Returns true if there are no more windows animating with the animation id
- // the window is associated with.
- bool RemoveWindowFromMaps(ServerWindow* window);
-
- AnimationId next_id_;
-
- base::TimeTicks last_tick_time_;
-
- base::ObserverList<AnimationRunnerObserver> observers_;
-
- WindowToAnimationMap window_to_animation_map_;
-
- IdToWindowsMap id_to_windows_map_;
-
- DISALLOW_COPY_AND_ASSIGN(AnimationRunner);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_ANIMATION_RUNNER_H_
diff --git a/chromium/components/mus/ws/animation_runner_observer.h b/chromium/components/mus/ws/animation_runner_observer.h
deleted file mode 100644
index 4c73e6cdbae..00000000000
--- a/chromium/components/mus/ws/animation_runner_observer.h
+++ /dev/null
@@ -1,25 +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 COMPONENTS_MUS_WS_ANIMATION_RUNNER_OBSERVER_H_
-#define COMPONENTS_MUS_WS_ANIMATION_RUNNER_OBSERVER_H_
-
-namespace mus {
-namespace ws {
-
-class AnimationRunnerObserver {
- public:
- virtual void OnAnimationScheduled(uint32_t id) = 0;
- virtual void OnAnimationDone(uint32_t id) = 0;
- virtual void OnAnimationInterrupted(uint32_t id) = 0;
- virtual void OnAnimationCanceled(uint32_t id) = 0;
-
- protected:
- virtual ~AnimationRunnerObserver() {}
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_ANIMATION_RUNNER_OBSERVER_H_
diff --git a/chromium/components/mus/ws/animation_runner_unittest.cc b/chromium/components/mus/ws/animation_runner_unittest.cc
deleted file mode 100644
index 660a920b313..00000000000
--- a/chromium/components/mus/ws/animation_runner_unittest.cc
+++ /dev/null
@@ -1,639 +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 "components/mus/ws/animation_runner.h"
-
-#include "base/strings/stringprintf.h"
-#include "components/mus/public/interfaces/window_manager_constants.mojom.h"
-#include "components/mus/ws/animation_runner_observer.h"
-#include "components/mus/ws/scheduled_animation_group.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::TimeDelta;
-
-namespace mus {
-using mojom::AnimationProperty;
-using mojom::AnimationTweenType;
-using mojom::AnimationElement;
-using mojom::AnimationGroup;
-using mojom::AnimationProperty;
-using mojom::AnimationSequence;
-using mojom::AnimationTweenType;
-using mojom::AnimationValue;
-using mojom::AnimationValuePtr;
-
-namespace ws {
-namespace {
-
-class TestAnimationRunnerObserver : public AnimationRunnerObserver {
- public:
- TestAnimationRunnerObserver() {}
- ~TestAnimationRunnerObserver() override {}
-
- std::vector<std::string>* changes() { return &changes_; }
- std::vector<uint32_t>* change_ids() { return &change_ids_; }
-
- void clear_changes() {
- changes_.clear();
- change_ids_.clear();
- }
-
- // AnimationRunnerDelgate:
- void OnAnimationScheduled(uint32_t id) override {
- change_ids_.push_back(id);
- changes_.push_back("scheduled");
- }
- void OnAnimationDone(uint32_t id) override {
- change_ids_.push_back(id);
- changes_.push_back("done");
- }
- void OnAnimationInterrupted(uint32_t id) override {
- change_ids_.push_back(id);
- changes_.push_back("interrupted");
- }
- void OnAnimationCanceled(uint32_t id) override {
- change_ids_.push_back(id);
- changes_.push_back("canceled");
- }
-
- private:
- std::vector<uint32_t> change_ids_;
- std::vector<std::string> changes_;
-
- DISALLOW_COPY_AND_ASSIGN(TestAnimationRunnerObserver);
-};
-
-// Creates an AnimationValuePtr from the specified float value.
-AnimationValuePtr FloatAnimationValue(float float_value) {
- AnimationValuePtr value(AnimationValue::New());
- value->float_value = float_value;
- return value;
-}
-
-// Creates an AnimationValuePtr from the specified transform.
-AnimationValuePtr TransformAnimationValue(const gfx::Transform& transform) {
- AnimationValuePtr value(AnimationValue::New());
- value->transform = transform;
- return value;
-}
-
-// Adds an AnimationElement to |group|s last sequence with the specified value.
-void AddElement(AnimationGroup* group,
- TimeDelta time,
- AnimationValuePtr start_value,
- AnimationValuePtr target_value,
- AnimationProperty property,
- AnimationTweenType tween_type) {
- AnimationSequence& sequence =
- *(group->sequences[group->sequences.size() - 1]);
- sequence.elements.push_back(AnimationElement::New());
- AnimationElement& element =
- *(sequence.elements[sequence.elements.size() - 1]);
- element.property = property;
- element.duration = time.InMicroseconds();
- element.tween_type = tween_type;
- element.start_value = std::move(start_value);
- element.target_value = std::move(target_value);
-}
-
-void AddOpacityElement(AnimationGroup* group,
- TimeDelta time,
- AnimationValuePtr start_value,
- AnimationValuePtr target_value) {
- AddElement(group, time, std::move(start_value), std::move(target_value),
- AnimationProperty::OPACITY, AnimationTweenType::LINEAR);
-}
-
-void AddTransformElement(AnimationGroup* group,
- TimeDelta time,
- AnimationValuePtr start_value,
- AnimationValuePtr target_value) {
- AddElement(group, time, std::move(start_value), std::move(target_value),
- AnimationProperty::TRANSFORM, AnimationTweenType::LINEAR);
-}
-
-void AddPauseElement(AnimationGroup* group, TimeDelta time) {
- AddElement(group, time, AnimationValuePtr(), AnimationValuePtr(),
- AnimationProperty::NONE, AnimationTweenType::LINEAR);
-}
-
-void InitGroupForWindow(AnimationGroup* group,
- const WindowId& id,
- int cycle_count) {
- group->window_id = WindowIdToTransportId(id);
- group->sequences.push_back(AnimationSequence::New());
- group->sequences[group->sequences.size() - 1]->cycle_count = cycle_count;
-}
-
-} // namespace
-
-class AnimationRunnerTest : public testing::Test {
- public:
- AnimationRunnerTest()
- : initial_time_(base::TimeTicks::Now()), runner_(initial_time_) {
- runner_.AddObserver(&runner_observer_);
- }
- ~AnimationRunnerTest() override { runner_.RemoveObserver(&runner_observer_); }
-
- protected:
- // Convenience to schedule an animation for a single window/group pair.
- AnimationRunner::AnimationId ScheduleForSingleWindow(
- ServerWindow* window,
- const AnimationGroup* group,
- base::TimeTicks now) {
- std::vector<AnimationRunner::WindowAndAnimationPair> pairs;
- pairs.push_back(std::make_pair(window, group));
- return runner_.Schedule(pairs, now);
- }
-
- // If |id| is valid and there is only one window schedule against the
- // animation it is returned; otherwise returns null.
- ServerWindow* GetSingleWindowAnimating(AnimationRunner::AnimationId id) {
- std::set<ServerWindow*> windows(runner_.GetWindowsAnimating(id));
- return windows.size() == 1 ? *windows.begin() : nullptr;
- }
-
- const base::TimeTicks initial_time_;
- TestAnimationRunnerObserver runner_observer_;
- AnimationRunner runner_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AnimationRunnerTest);
-};
-
-// Opacity from 1 to .5 over 1000.
-TEST_F(AnimationRunnerTest, SingleProperty) {
- TestServerWindowDelegate window_delegate;
- ServerWindow window(&window_delegate, WindowId());
-
- AnimationGroup group;
- InitGroupForWindow(&group, window.id(), 1);
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(1000),
- AnimationValuePtr(), FloatAnimationValue(.5));
-
- const uint32_t animation_id =
- ScheduleForSingleWindow(&window, &group, initial_time_);
-
- ASSERT_EQ(1u, runner_observer_.changes()->size());
- EXPECT_EQ("scheduled", runner_observer_.changes()->at(0));
- EXPECT_EQ(animation_id, runner_observer_.change_ids()->at(0));
- runner_observer_.clear_changes();
-
- EXPECT_TRUE(runner_.HasAnimations());
-
- // Opacity should still be 1 (the initial value).
- EXPECT_EQ(1.f, window.opacity());
-
- // Animate half way.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(500));
-
- EXPECT_EQ(.75f, window.opacity());
- EXPECT_TRUE(runner_observer_.changes()->empty());
-
- // Run well past the end. Value should progress to end and delegate should
- // be notified.
- runner_.Tick(initial_time_ + TimeDelta::FromSeconds(10));
- EXPECT_EQ(.5f, window.opacity());
-
- ASSERT_EQ(1u, runner_observer_.changes()->size());
- EXPECT_EQ("done", runner_observer_.changes()->at(0));
- EXPECT_EQ(animation_id, runner_observer_.change_ids()->at(0));
-
- EXPECT_FALSE(runner_.HasAnimations());
-}
-
-// Opacity from 1 to .5, followed by transform from identity to 2x,3x.
-TEST_F(AnimationRunnerTest, TwoPropertiesInSequence) {
- TestServerWindowDelegate window_delegate;
- ServerWindow window(&window_delegate, WindowId());
-
- AnimationGroup group;
- InitGroupForWindow(&group, window.id(), 1);
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(1000),
- AnimationValuePtr(), FloatAnimationValue(.5f));
-
- gfx::Transform done_transform;
- done_transform.Scale(2, 4);
- AddTransformElement(&group, TimeDelta::FromMicroseconds(2000),
- AnimationValuePtr(),
- TransformAnimationValue(done_transform));
-
- const uint32_t animation_id =
- ScheduleForSingleWindow(&window, &group, initial_time_);
- runner_observer_.clear_changes();
-
- // Nothing in the window should have changed yet.
- EXPECT_EQ(1.f, window.opacity());
- EXPECT_TRUE(window.transform().IsIdentity());
-
- // Animate half way from through opacity animation.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(500));
-
- EXPECT_EQ(.75f, window.opacity());
- EXPECT_TRUE(window.transform().IsIdentity());
-
- // Finish first element (opacity).
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(1000));
- EXPECT_EQ(.5f, window.opacity());
- EXPECT_TRUE(window.transform().IsIdentity());
-
- // Half way through second (transform).
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(2000));
- EXPECT_EQ(.5f, window.opacity());
- gfx::Transform half_way_transform;
- half_way_transform.Scale(1.5, 2.5);
- EXPECT_EQ(half_way_transform, window.transform());
-
- EXPECT_TRUE(runner_observer_.changes()->empty());
-
- // To end.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(3500));
- EXPECT_EQ(.5f, window.opacity());
- EXPECT_EQ(done_transform, window.transform());
-
- ASSERT_EQ(1u, runner_observer_.changes()->size());
- EXPECT_EQ("done", runner_observer_.changes()->at(0));
- EXPECT_EQ(animation_id, runner_observer_.change_ids()->at(0));
-}
-
-// Opacity from .5 to 1 over 1000, transform to 2x,4x over 500.
-TEST_F(AnimationRunnerTest, TwoPropertiesInParallel) {
- TestServerWindowDelegate window_delegate;
- ServerWindow window(&window_delegate, WindowId(1, 1));
-
- AnimationGroup group;
- InitGroupForWindow(&group, window.id(), 1);
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(1000),
- FloatAnimationValue(.5f), FloatAnimationValue(1));
-
- group.sequences.push_back(AnimationSequence::New());
- group.sequences[1]->cycle_count = 1;
- gfx::Transform done_transform;
- done_transform.Scale(2, 4);
- AddTransformElement(&group, TimeDelta::FromMicroseconds(500),
- AnimationValuePtr(),
- TransformAnimationValue(done_transform));
-
- const uint32_t animation_id =
- ScheduleForSingleWindow(&window, &group, initial_time_);
-
- runner_observer_.clear_changes();
-
- // Nothing in the window should have changed yet.
- EXPECT_EQ(1.f, window.opacity());
- EXPECT_TRUE(window.transform().IsIdentity());
-
- // Animate to 250, which is 1/4 way through opacity and half way through
- // transform.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(250));
-
- EXPECT_EQ(.625f, window.opacity());
- gfx::Transform half_way_transform;
- half_way_transform.Scale(1.5, 2.5);
- EXPECT_EQ(half_way_transform, window.transform());
-
- // Animate to 500, which is 1/2 way through opacity and transform done.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(500));
- EXPECT_EQ(.75f, window.opacity());
- EXPECT_EQ(done_transform, window.transform());
-
- // Animate to 750, which is 3/4 way through opacity and transform done.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(750));
- EXPECT_EQ(.875f, window.opacity());
- EXPECT_EQ(done_transform, window.transform());
-
- EXPECT_TRUE(runner_observer_.changes()->empty());
-
- // To end.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(3500));
- EXPECT_EQ(1.f, window.opacity());
- EXPECT_EQ(done_transform, window.transform());
-
- ASSERT_EQ(1u, runner_observer_.changes()->size());
- EXPECT_EQ("done", runner_observer_.changes()->at(0));
- EXPECT_EQ(animation_id, runner_observer_.change_ids()->at(0));
-}
-
-// Opacity from .5 to 1 over 1000, pause for 500, 1 to .5 over 500, with a cycle
-// count of 3.
-TEST_F(AnimationRunnerTest, Cycles) {
- TestServerWindowDelegate window_delegate;
- ServerWindow window(&window_delegate, WindowId(1, 2));
-
- window.SetOpacity(.5f);
-
- AnimationGroup group;
- InitGroupForWindow(&group, window.id(), 3);
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(1000),
- AnimationValuePtr(), FloatAnimationValue(1));
- AddPauseElement(&group, TimeDelta::FromMicroseconds(500));
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(500),
- AnimationValuePtr(), FloatAnimationValue(.5));
-
- ScheduleForSingleWindow(&window, &group, initial_time_);
- runner_observer_.clear_changes();
-
- // Nothing in the window should have changed yet.
- EXPECT_EQ(.5f, window.opacity());
-
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(500));
- EXPECT_EQ(.75f, window.opacity());
-
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(1250));
- EXPECT_EQ(1.f, window.opacity());
-
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(1750));
- EXPECT_EQ(.75f, window.opacity());
-
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(2500));
- EXPECT_EQ(.75f, window.opacity());
-
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(3250));
- EXPECT_EQ(1.f, window.opacity());
-
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(3750));
- EXPECT_EQ(.75f, window.opacity());
-
- // Animate to the end.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(6500));
- EXPECT_EQ(.5f, window.opacity());
-
- ASSERT_EQ(1u, runner_observer_.changes()->size());
- EXPECT_EQ("done", runner_observer_.changes()->at(0));
-}
-
-// Verifies scheduling the same window twice sends an interrupt.
-TEST_F(AnimationRunnerTest, ScheduleTwice) {
- TestServerWindowDelegate window_delegate;
- ServerWindow window(&window_delegate, WindowId(1, 2));
-
- AnimationGroup group;
- InitGroupForWindow(&group, window.id(), 1);
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(1000),
- AnimationValuePtr(), FloatAnimationValue(.5));
-
- const uint32_t animation_id =
- ScheduleForSingleWindow(&window, &group, initial_time_);
- runner_observer_.clear_changes();
-
- // Animate half way.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(500));
-
- EXPECT_EQ(.75f, window.opacity());
- EXPECT_TRUE(runner_observer_.changes()->empty());
-
- // Schedule again. We should get an interrupt, but opacity shouldn't change.
- const uint32_t animation2_id = ScheduleForSingleWindow(
- &window, &group, initial_time_ + TimeDelta::FromMicroseconds(500));
-
- // Id should have changed.
- EXPECT_NE(animation_id, animation2_id);
-
- EXPECT_FALSE(runner_.IsAnimating(animation_id));
- EXPECT_EQ(&window, GetSingleWindowAnimating(animation2_id));
-
- EXPECT_EQ(.75f, window.opacity());
- EXPECT_EQ(2u, runner_observer_.changes()->size());
- EXPECT_EQ("interrupted", runner_observer_.changes()->at(0));
- EXPECT_EQ(animation_id, runner_observer_.change_ids()->at(0));
- EXPECT_EQ("scheduled", runner_observer_.changes()->at(1));
- EXPECT_EQ(animation2_id, runner_observer_.change_ids()->at(1));
- runner_observer_.clear_changes();
-
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(1000));
- EXPECT_EQ(.625f, window.opacity());
- EXPECT_TRUE(runner_observer_.changes()->empty());
-
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(2000));
- EXPECT_EQ(.5f, window.opacity());
- EXPECT_EQ(1u, runner_observer_.changes()->size());
- EXPECT_EQ("done", runner_observer_.changes()->at(0));
- EXPECT_EQ(animation2_id, runner_observer_.change_ids()->at(0));
-}
-
-// Verifies Remove() works.
-TEST_F(AnimationRunnerTest, CancelAnimationForWindow) {
- // Create an animation and advance it part way.
- TestServerWindowDelegate window_delegate;
- ServerWindow window(&window_delegate, WindowId());
- AnimationGroup group;
- InitGroupForWindow(&group, window.id(), 1);
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(1000),
- AnimationValuePtr(), FloatAnimationValue(.5));
-
- const uint32_t animation_id =
- ScheduleForSingleWindow(&window, &group, initial_time_);
- runner_observer_.clear_changes();
- EXPECT_EQ(&window, GetSingleWindowAnimating(animation_id));
-
- EXPECT_TRUE(runner_.HasAnimations());
-
- // Animate half way.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(500));
- EXPECT_EQ(.75f, window.opacity());
- EXPECT_TRUE(runner_observer_.changes()->empty());
-
- // Cancel the animation.
- runner_.CancelAnimationForWindow(&window);
-
- EXPECT_FALSE(runner_.HasAnimations());
- EXPECT_EQ(nullptr, GetSingleWindowAnimating(animation_id));
-
- EXPECT_EQ(.75f, window.opacity());
-
- EXPECT_EQ(1u, runner_observer_.changes()->size());
- EXPECT_EQ("canceled", runner_observer_.changes()->at(0));
- EXPECT_EQ(animation_id, runner_observer_.change_ids()->at(0));
-}
-
-// Verifies a tick with a very large delta and a sequence that repeats forever
-// doesn't take a long time.
-TEST_F(AnimationRunnerTest, InfiniteRepeatWithHugeGap) {
- TestServerWindowDelegate window_delegate;
- ServerWindow window(&window_delegate, WindowId(1, 2));
-
- window.SetOpacity(.5f);
-
- AnimationGroup group;
- InitGroupForWindow(&group, window.id(), 0);
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(500),
- AnimationValuePtr(), FloatAnimationValue(1));
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(500),
- AnimationValuePtr(), FloatAnimationValue(.5));
-
- ScheduleForSingleWindow(&window, &group, initial_time_);
- runner_observer_.clear_changes();
-
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(1000000000750));
-
- EXPECT_EQ(.75f, window.opacity());
-
- ASSERT_EQ(0u, runner_observer_.changes()->size());
-}
-
-// Verifies a second schedule sets any properties that are no longer animating
-// to their final value.
-TEST_F(AnimationRunnerTest, RescheduleSetsPropertiesToFinalValue) {
- TestServerWindowDelegate window_delegate;
- ServerWindow window(&window_delegate, WindowId());
-
- AnimationGroup group;
- InitGroupForWindow(&group, window.id(), 1);
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(1000),
- AnimationValuePtr(), FloatAnimationValue(.5));
-
- gfx::Transform done_transform;
- done_transform.Scale(2, 4);
- AddTransformElement(&group, TimeDelta::FromMicroseconds(500),
- AnimationValuePtr(),
- TransformAnimationValue(done_transform));
-
- ScheduleForSingleWindow(&window, &group, initial_time_);
-
- // Schedule() again, this time without animating opacity.
- group.sequences[0]->elements[0]->property = AnimationProperty::NONE;
- ScheduleForSingleWindow(&window, &group, initial_time_);
-
- // Opacity should go to final value.
- EXPECT_EQ(.5f, window.opacity());
- // Transform shouldn't have changed since newly scheduled animation also has
- // transform in it.
- EXPECT_TRUE(window.transform().IsIdentity());
-}
-
-// Opacity from 1 to .5 over 1000 of v1 and v2 transform to 2x,4x over 500.
-TEST_F(AnimationRunnerTest, TwoWindows) {
- TestServerWindowDelegate window_delegate;
- ServerWindow window1(&window_delegate, WindowId());
- ServerWindow window2(&window_delegate, WindowId(1, 2));
-
- AnimationGroup group1;
- InitGroupForWindow(&group1, window1.id(), 1);
- AddOpacityElement(&group1, TimeDelta::FromMicroseconds(1000),
- AnimationValuePtr(), FloatAnimationValue(.5));
-
- AnimationGroup group2;
- InitGroupForWindow(&group2, window2.id(), 1);
- gfx::Transform done_transform;
- done_transform.Scale(2, 4);
- AddTransformElement(&group2, TimeDelta::FromMicroseconds(500),
- AnimationValuePtr(),
- TransformAnimationValue(done_transform));
-
- std::vector<AnimationRunner::WindowAndAnimationPair> pairs;
- pairs.push_back(std::make_pair(&window1, &group1));
- pairs.push_back(std::make_pair(&window2, &group2));
-
- const uint32_t animation_id = runner_.Schedule(pairs, initial_time_);
-
- ASSERT_EQ(1u, runner_observer_.changes()->size());
- EXPECT_EQ("scheduled", runner_observer_.changes()->at(0));
- EXPECT_EQ(animation_id, runner_observer_.change_ids()->at(0));
- runner_observer_.clear_changes();
-
- EXPECT_TRUE(runner_.HasAnimations());
- EXPECT_TRUE(runner_.IsAnimating(animation_id));
-
- // Properties should be at the initial value.
- EXPECT_EQ(1.f, window1.opacity());
- EXPECT_TRUE(window2.transform().IsIdentity());
-
- // Animate 250ms in, which is quarter way for opacity and half way for
- // transform.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(250));
- EXPECT_EQ(.875f, window1.opacity());
- gfx::Transform half_way_transform;
- half_way_transform.Scale(1.5, 2.5);
- EXPECT_EQ(half_way_transform, window2.transform());
- std::set<ServerWindow*> windows_animating(
- runner_.GetWindowsAnimating(animation_id));
- EXPECT_EQ(2u, windows_animating.size());
- EXPECT_EQ(1u, windows_animating.count(&window1));
- EXPECT_EQ(1u, windows_animating.count(&window2));
-
- // Animate 750ms in, window1 should be done 3/4 done, and window2 done.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(750));
- EXPECT_EQ(.625, window1.opacity());
- EXPECT_EQ(done_transform, window2.transform());
- windows_animating = runner_.GetWindowsAnimating(animation_id);
- EXPECT_EQ(1u, windows_animating.size());
- EXPECT_EQ(1u, windows_animating.count(&window1));
- EXPECT_TRUE(runner_.HasAnimations());
- EXPECT_TRUE(runner_.IsAnimating(animation_id));
-
- // Animate to end.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(1750));
- EXPECT_EQ(.5, window1.opacity());
- EXPECT_EQ(done_transform, window2.transform());
- windows_animating = runner_.GetWindowsAnimating(animation_id);
- EXPECT_TRUE(windows_animating.empty());
- EXPECT_FALSE(runner_.HasAnimations());
- EXPECT_FALSE(runner_.IsAnimating(animation_id));
-}
-
-TEST_F(AnimationRunnerTest, Reschedule) {
- TestServerWindowDelegate window_delegate;
- ServerWindow window(&window_delegate, WindowId());
-
- // Animation from 1-0 over 1ms and in parallel transform to 2x,4x over 1ms.
- AnimationGroup group;
- InitGroupForWindow(&group, window.id(), 1);
- AddOpacityElement(&group, TimeDelta::FromMicroseconds(1000),
- AnimationValuePtr(), FloatAnimationValue(0));
- group.sequences.push_back(AnimationSequence::New());
- group.sequences[1]->cycle_count = 1;
- gfx::Transform done_transform;
- done_transform.Scale(2, 4);
- AddTransformElement(&group, TimeDelta::FromMicroseconds(1000),
- AnimationValuePtr(),
- TransformAnimationValue(done_transform));
- const uint32_t animation_id1 =
- ScheduleForSingleWindow(&window, &group, initial_time_);
-
- // Animate half way in.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(500));
- EXPECT_EQ(.5f, window.opacity());
- gfx::Transform half_way_transform;
- half_way_transform.Scale(1.5, 2.5);
- EXPECT_EQ(half_way_transform, window.transform());
-
- runner_observer_.clear_changes();
-
- // Schedule the same window animating opacity to 1.
- AnimationGroup group2;
- InitGroupForWindow(&group2, window.id(), 1);
- AddOpacityElement(&group2, TimeDelta::FromMicroseconds(1000),
- AnimationValuePtr(), FloatAnimationValue(1));
- const uint32_t animation_id2 = ScheduleForSingleWindow(
- &window, &group2, initial_time_ + TimeDelta::FromMicroseconds(500));
-
- // Opacity should remain at .5, but transform should go to end state.
- EXPECT_EQ(.5f, window.opacity());
- EXPECT_EQ(done_transform, window.transform());
-
- ASSERT_EQ(2u, runner_observer_.changes()->size());
- EXPECT_EQ("interrupted", runner_observer_.changes()->at(0));
- EXPECT_EQ(animation_id1, runner_observer_.change_ids()->at(0));
- EXPECT_EQ("scheduled", runner_observer_.changes()->at(1));
- EXPECT_EQ(animation_id2, runner_observer_.change_ids()->at(1));
- runner_observer_.clear_changes();
-
- // Animate half way through new sequence. Opacity should be the only thing
- // changing.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(1000));
- EXPECT_EQ(.75f, window.opacity());
- EXPECT_EQ(done_transform, window.transform());
- ASSERT_EQ(0u, runner_observer_.changes()->size());
-
- // Animate to end.
- runner_.Tick(initial_time_ + TimeDelta::FromMicroseconds(2000));
- ASSERT_EQ(1u, runner_observer_.changes()->size());
- EXPECT_EQ("done", runner_observer_.changes()->at(0));
- EXPECT_EQ(animation_id2, runner_observer_.change_ids()->at(0));
-}
-
-} // ws
-} // mus
diff --git a/chromium/components/mus/ws/cursor_unittest.cc b/chromium/components/mus/ws/cursor_unittest.cc
deleted file mode 100644
index 995318e85f0..00000000000
--- a/chromium/components/mus/ws/cursor_unittest.cc
+++ /dev/null
@@ -1,198 +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 <stdint.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "components/mus/common/types.h"
-#include "components/mus/common/util.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/ids.h"
-#include "components/mus/ws/platform_display.h"
-#include "components/mus/ws/platform_display_factory.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_surface_manager_test_api.h"
-#include "components/mus/ws/test_utils.h"
-#include "components/mus/ws/window_manager_display_root.h"
-#include "components/mus/ws/window_manager_state.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_server_delegate.h"
-#include "components/mus/ws/window_tree.h"
-#include "components/mus/ws/window_tree_binding.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace mus {
-namespace ws {
-namespace test {
-
-const UserId kTestId1 = "20";
-
-class CursorTest : public testing::Test {
- public:
- CursorTest() : cursor_id_(-1), platform_display_factory_(&cursor_id_) {}
- ~CursorTest() override {}
-
- protected:
- // testing::Test:
- void SetUp() override {
- PlatformDisplay::set_factory_for_testing(&platform_display_factory_);
- window_server_.reset(
- new WindowServer(&window_server_delegate_,
- scoped_refptr<SurfacesState>(new SurfacesState)));
- window_server_delegate_.set_window_server(window_server_.get());
-
- window_server_delegate_.set_num_displays_to_create(1);
-
- // As a side effect, this allocates Displays.
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId1);
- window_server_->user_id_tracker()->AddUserId(kTestId1);
- window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
- }
-
- ServerWindow* GetRoot() {
- DisplayManager* display_manager = window_server_->display_manager();
- // ASSERT_EQ(1u, display_manager->displays().size());
- Display* display = *display_manager->displays().begin();
- return display->GetWindowManagerDisplayRootForUser(kTestId1)->root();
- }
-
- // Create a 30x30 window where the outer 10 pixels is non-client.
- ServerWindow* BuildServerWindow() {
- DisplayManager* display_manager = window_server_->display_manager();
- Display* display = *display_manager->displays().begin();
- WindowManagerDisplayRoot* active_display_root =
- display->GetActiveWindowManagerDisplayRoot();
- WindowTree* tree =
- active_display_root->window_manager_state()->window_tree();
- ClientWindowId child_window_id;
- if (!NewWindowInTree(tree, &child_window_id))
- return nullptr;
-
- ServerWindow* w = tree->GetWindowByClientId(child_window_id);
- w->SetBounds(gfx::Rect(10, 10, 30, 30));
- w->SetClientArea(gfx::Insets(10, 10), std::vector<gfx::Rect>());
- w->SetVisible(true);
-
- ServerWindowSurfaceManagerTestApi test_api(w->GetOrCreateSurfaceManager());
- test_api.CreateEmptyDefaultSurface();
-
- return w;
- }
-
- void MoveCursorTo(const gfx::Point& p) {
- DisplayManager* display_manager = window_server_->display_manager();
- ASSERT_EQ(1u, display_manager->displays().size());
- Display* display = *display_manager->displays().begin();
- WindowManagerDisplayRoot* active_display_root =
- display->GetActiveWindowManagerDisplayRoot();
- ASSERT_TRUE(active_display_root);
- static_cast<PlatformDisplayDelegate*>(display)->OnEvent(ui::PointerEvent(
- ui::MouseEvent(ui::ET_MOUSE_MOVED, p, p, base::TimeTicks(), 0, 0)));
- WindowManagerState* wms = active_display_root->window_manager_state();
- wms->OnEventAck(wms->window_tree(), mojom::EventResult::HANDLED);
- }
-
- protected:
- int32_t cursor_id_;
- TestPlatformDisplayFactory platform_display_factory_;
- TestWindowServerDelegate window_server_delegate_;
- std::unique_ptr<WindowServer> window_server_;
- base::MessageLoop message_loop_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CursorTest);
-};
-
-TEST_F(CursorTest, ChangeByMouseMove) {
- ServerWindow* win = BuildServerWindow();
- win->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
- win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE,
- mojom::Cursor(win->non_client_cursor()));
-
- // Non client area
- MoveCursorTo(gfx::Point(15, 15));
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id_));
-
- // Client area
- MoveCursorTo(gfx::Point(25, 25));
- EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(cursor_id_));
-}
-
-TEST_F(CursorTest, ChangeByClientAreaChange) {
- ServerWindow* win = BuildServerWindow();
- win->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
- win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE,
- mojom::Cursor(win->non_client_cursor()));
-
- // Non client area before we move.
- MoveCursorTo(gfx::Point(15, 15));
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id_));
-
- // Changing the client area should cause a change.
- win->SetClientArea(gfx::Insets(1, 1), std::vector<gfx::Rect>());
- EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(cursor_id_));
-}
-
-TEST_F(CursorTest, NonClientCursorChange) {
- ServerWindow* win = BuildServerWindow();
- win->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
- win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE,
- mojom::Cursor(win->non_client_cursor()));
-
- MoveCursorTo(gfx::Point(15, 15));
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id_));
-
- win->SetNonClientCursor(mojom::Cursor::WEST_RESIZE);
- EXPECT_EQ(mojom::Cursor::WEST_RESIZE, mojom::Cursor(cursor_id_));
-}
-
-TEST_F(CursorTest, IgnoreClientCursorChangeInNonClientArea) {
- ServerWindow* win = BuildServerWindow();
- win->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
- win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE,
- mojom::Cursor(win->non_client_cursor()));
-
- MoveCursorTo(gfx::Point(15, 15));
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id_));
-
- win->SetPredefinedCursor(mojom::Cursor::HELP);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id_));
-}
-
-TEST_F(CursorTest, NonClientToClientByBoundsChange) {
- ServerWindow* win = BuildServerWindow();
- win->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
- win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE,
- mojom::Cursor(win->non_client_cursor()));
-
- // Non client area before we move.
- MoveCursorTo(gfx::Point(15, 15));
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, mojom::Cursor(cursor_id_));
-
- win->SetBounds(gfx::Rect(0, 0, 30, 30));
- EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(cursor_id_));
-}
-
-} // namespace test
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/default_access_policy.cc b/chromium/components/mus/ws/default_access_policy.cc
deleted file mode 100644
index 1930dc05925..00000000000
--- a/chromium/components/mus/ws/default_access_policy.cc
+++ /dev/null
@@ -1,203 +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 "components/mus/ws/default_access_policy.h"
-
-#include "components/mus/ws/access_policy_delegate.h"
-#include "components/mus/ws/server_window.h"
-
-namespace mus {
-namespace ws {
-
-DefaultAccessPolicy::DefaultAccessPolicy() {}
-
-DefaultAccessPolicy::~DefaultAccessPolicy() {}
-
-void DefaultAccessPolicy::Init(ClientSpecificId client_id,
- AccessPolicyDelegate* delegate) {
- client_id_ = client_id;
- delegate_ = delegate;
-}
-
-bool DefaultAccessPolicy::CanRemoveWindowFromParent(
- const ServerWindow* window) const {
- if (!WasCreatedByThisClient(window))
- return false; // Can only unparent windows we created.
-
- return delegate_->HasRootForAccessPolicy(window->parent()) ||
- WasCreatedByThisClient(window->parent());
-}
-
-bool DefaultAccessPolicy::CanAddWindow(const ServerWindow* parent,
- const ServerWindow* child) const {
- return WasCreatedByThisClient(child) &&
- (delegate_->HasRootForAccessPolicy(parent) ||
- (WasCreatedByThisClient(parent) &&
- !delegate_->IsWindowRootOfAnotherTreeForAccessPolicy(parent)));
-}
-
-bool DefaultAccessPolicy::CanAddTransientWindow(
- const ServerWindow* parent,
- const ServerWindow* child) const {
- return (delegate_->HasRootForAccessPolicy(child) ||
- WasCreatedByThisClient(child)) &&
- (delegate_->HasRootForAccessPolicy(parent) ||
- WasCreatedByThisClient(parent));
-}
-
-bool DefaultAccessPolicy::CanRemoveTransientWindowFromParent(
- const ServerWindow* window) const {
- return (delegate_->HasRootForAccessPolicy(window) ||
- WasCreatedByThisClient(window)) &&
- (delegate_->HasRootForAccessPolicy(window->transient_parent()) ||
- WasCreatedByThisClient(window->transient_parent()));
-}
-
-bool DefaultAccessPolicy::CanSetModal(const ServerWindow* window) const {
- return delegate_->HasRootForAccessPolicy(window) ||
- WasCreatedByThisClient(window);
-}
-
-bool DefaultAccessPolicy::CanReorderWindow(
- const ServerWindow* window,
- const ServerWindow* relative_window,
- mojom::OrderDirection direction) const {
- return WasCreatedByThisClient(window) &&
- WasCreatedByThisClient(relative_window);
-}
-
-bool DefaultAccessPolicy::CanDeleteWindow(const ServerWindow* window) const {
- return WasCreatedByThisClient(window);
-}
-
-bool DefaultAccessPolicy::CanGetWindowTree(const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::CanDescendIntoWindowForWindowTree(
- const ServerWindow* window) const {
- return (WasCreatedByThisClient(window) &&
- !delegate_->IsWindowRootOfAnotherTreeForAccessPolicy(window)) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::CanEmbed(const ServerWindow* window) const {
- return WasCreatedByThisClient(window);
-}
-
-bool DefaultAccessPolicy::CanChangeWindowVisibility(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::CanChangeWindowOpacity(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::CanSetWindowSurface(
- const ServerWindow* window,
- mojom::SurfaceType surface_type) const {
- if (surface_type == mojom::SurfaceType::UNDERLAY)
- return WasCreatedByThisClient(window);
-
- // Once a window embeds another app, the embedder app is no longer able to
- // call SetWindowSurfaceId() - this ability is transferred to the embedded
- // app.
- if (delegate_->IsWindowRootOfAnotherTreeForAccessPolicy(window))
- return false;
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::CanSetWindowBounds(const ServerWindow* window) const {
- return WasCreatedByThisClient(window);
-}
-
-bool DefaultAccessPolicy::CanSetWindowProperties(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window);
-}
-
-bool DefaultAccessPolicy::CanSetWindowTextInputState(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::CanSetCapture(const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::CanSetFocus(const ServerWindow* window) const {
- return !window || WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::CanSetClientArea(const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::CanSetHitTestMask(const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::CanSetCursorProperties(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool DefaultAccessPolicy::ShouldNotifyOnHierarchyChange(
- const ServerWindow* window,
- const ServerWindow** new_parent,
- const ServerWindow** old_parent) const {
- if (!WasCreatedByThisClient(window))
- return false;
-
- if (*new_parent && !WasCreatedByThisClient(*new_parent) &&
- !delegate_->HasRootForAccessPolicy((*new_parent))) {
- *new_parent = nullptr;
- }
-
- if (*old_parent && !WasCreatedByThisClient(*old_parent) &&
- !delegate_->HasRootForAccessPolicy((*old_parent))) {
- *old_parent = nullptr;
- }
- return true;
-}
-
-const ServerWindow* DefaultAccessPolicy::GetWindowForFocusChange(
- const ServerWindow* focused) {
- if (WasCreatedByThisClient(focused) ||
- delegate_->HasRootForAccessPolicy(focused))
- return focused;
- return nullptr;
-}
-
-bool DefaultAccessPolicy::CanSetWindowManager() const {
- return false;
-}
-
-bool DefaultAccessPolicy::WasCreatedByThisClient(
- const ServerWindow* window) const {
- return window->id().client_id == client_id_;
-}
-
-bool DefaultAccessPolicy::IsValidIdForNewWindow(
- const ClientWindowId& id) const {
- // Clients using DefaultAccessPolicy only see windows they have created (for
- // the embed point they choose the id), so it's ok for clients to use whatever
- // id they want.
- return true;
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/default_access_policy.h b/chromium/components/mus/ws/default_access_policy.h
deleted file mode 100644
index 9135fb9901d..00000000000
--- a/chromium/components/mus/ws/default_access_policy.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_DEFAULT_ACCESS_POLICY_H_
-#define COMPONENTS_MUS_WS_DEFAULT_ACCESS_POLICY_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "components/mus/ws/access_policy.h"
-
-namespace mus {
-namespace ws {
-
-class AccessPolicyDelegate;
-
-// AccessPolicy for all clients, except the window manager.
-class DefaultAccessPolicy : public AccessPolicy {
- public:
- DefaultAccessPolicy();
- ~DefaultAccessPolicy() override;
-
- // AccessPolicy:
- void Init(ClientSpecificId client_id,
- AccessPolicyDelegate* delegate) override;
- bool CanRemoveWindowFromParent(const ServerWindow* window) const override;
- bool CanAddWindow(const ServerWindow* parent,
- const ServerWindow* child) const override;
- bool CanAddTransientWindow(const ServerWindow* parent,
- const ServerWindow* child) const override;
- bool CanRemoveTransientWindowFromParent(
- const ServerWindow* window) const override;
- bool CanSetModal(const ServerWindow* window) const override;
- bool CanReorderWindow(const ServerWindow* window,
- const ServerWindow* relative_window,
- mojom::OrderDirection direction) const override;
- bool CanDeleteWindow(const ServerWindow* window) const override;
- bool CanGetWindowTree(const ServerWindow* window) const override;
- bool CanDescendIntoWindowForWindowTree(
- const ServerWindow* window) const override;
- bool CanEmbed(const ServerWindow* window) const override;
- bool CanChangeWindowVisibility(const ServerWindow* window) const override;
- bool CanChangeWindowOpacity(const ServerWindow* window) const override;
- bool CanSetWindowSurface(const ServerWindow* window,
- mus::mojom::SurfaceType surface_type) const override;
- bool CanSetWindowBounds(const ServerWindow* window) const override;
- bool CanSetWindowProperties(const ServerWindow* window) const override;
- bool CanSetWindowTextInputState(const ServerWindow* window) const override;
- bool CanSetCapture(const ServerWindow* window) const override;
- bool CanSetFocus(const ServerWindow* window) const override;
- bool CanSetClientArea(const ServerWindow* window) const override;
- bool CanSetHitTestMask(const ServerWindow* window) const override;
- bool CanSetCursorProperties(const ServerWindow* window) const override;
- bool ShouldNotifyOnHierarchyChange(
- const ServerWindow* window,
- const ServerWindow** new_parent,
- const ServerWindow** old_parent) const override;
- const ServerWindow* GetWindowForFocusChange(
- const ServerWindow* focused) override;
- bool CanSetWindowManager() const override;
- bool IsValidIdForNewWindow(const ClientWindowId& id) const override;
-
- private:
- bool WasCreatedByThisClient(const ServerWindow* window) const;
-
- ClientSpecificId client_id_ = 0u;
- AccessPolicyDelegate* delegate_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(DefaultAccessPolicy);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_DEFAULT_ACCESS_POLICY_H_
diff --git a/chromium/components/mus/ws/display.cc b/chromium/components/mus/ws/display.cc
deleted file mode 100644
index 84a4162de05..00000000000
--- a/chromium/components/mus/ws/display.cc
+++ /dev/null
@@ -1,419 +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 "components/mus/ws/display.h"
-
-#include <set>
-#include <vector>
-
-#include "base/debug/debugger.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/mus/common/types.h"
-#include "components/mus/ws/display_binding.h"
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/focus_controller.h"
-#include "components/mus/ws/platform_display.h"
-#include "components/mus/ws/platform_display_init_params.h"
-#include "components/mus/ws/user_activity_monitor.h"
-#include "components/mus/ws/window_manager_display_root.h"
-#include "components/mus/ws/window_manager_state.h"
-#include "components/mus/ws/window_manager_window_tree_factory.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_server_delegate.h"
-#include "components/mus/ws/window_tree.h"
-#include "components/mus/ws/window_tree_binding.h"
-#include "mojo/common/common_type_converters.h"
-#include "services/shell/public/interfaces/connector.mojom.h"
-#include "ui/base/cursor/cursor.h"
-
-namespace mus {
-namespace ws {
-
-Display::Display(WindowServer* window_server,
- const PlatformDisplayInitParams& platform_display_init_params)
- : id_(window_server->display_manager()->GetAndAdvanceNextDisplayId()),
- window_server_(window_server),
- platform_display_(PlatformDisplay::Create(platform_display_init_params)),
- last_cursor_(ui::kCursorNone) {
- platform_display_->Init(this);
-
- window_server_->window_manager_window_tree_factory_set()->AddObserver(this);
- window_server_->user_id_tracker()->AddObserver(this);
-}
-
-Display::~Display() {
- window_server_->user_id_tracker()->RemoveObserver(this);
-
- window_server_->window_manager_window_tree_factory_set()->RemoveObserver(
- this);
-
- if (!focus_controller_) {
- focus_controller_->RemoveObserver(this);
- focus_controller_.reset();
- }
-
- for (ServerWindow* window : windows_needing_frame_destruction_)
- window->RemoveObserver(this);
-
- // If there is a |binding_| then the tree was created specifically for this
- // display (which corresponds to a WindowTreeHost).
- if (binding_ && !window_manager_display_root_map_.empty()) {
- window_server_->DestroyTree(window_manager_display_root_map_.begin()
- ->second->window_manager_state()
- ->window_tree());
- }
-}
-
-void Display::Init(std::unique_ptr<DisplayBinding> binding) {
- init_called_ = true;
- binding_ = std::move(binding);
- display_manager()->AddDisplay(this);
- InitWindowManagerDisplayRootsIfNecessary();
-}
-
-DisplayManager* Display::display_manager() {
- return window_server_->display_manager();
-}
-
-const DisplayManager* Display::display_manager() const {
- return window_server_->display_manager();
-}
-
-mojom::DisplayPtr Display::ToMojomDisplay() const {
- mojom::DisplayPtr display_ptr = mojom::Display::New();
- display_ptr = mojom::Display::New();
- display_ptr->id = id_;
- // TODO(sky): Display should know it's origin.
- display_ptr->bounds.SetRect(0, 0, root_->bounds().size().width(),
- root_->bounds().size().height());
- // TODO(sky): window manager needs an API to set the work area.
- display_ptr->work_area = display_ptr->bounds;
- display_ptr->device_pixel_ratio = platform_display_->GetDeviceScaleFactor();
- display_ptr->rotation = platform_display_->GetRotation();
- // TODO(sky): make this real.
- display_ptr->is_primary = true;
- // TODO(sky): make this real.
- display_ptr->touch_support = mojom::TouchSupport::UNKNOWN;
- display_ptr->frame_decoration_values = mojom::FrameDecorationValues::New();
- return display_ptr;
-}
-
-void Display::SchedulePaint(const ServerWindow* window,
- const gfx::Rect& bounds) {
- DCHECK(root_->Contains(window));
- platform_display_->SchedulePaint(window, bounds);
-}
-
-void Display::ScheduleSurfaceDestruction(ServerWindow* window) {
- if (!platform_display_->IsFramePending()) {
- window->DestroySurfacesScheduledForDestruction();
- return;
- }
- if (windows_needing_frame_destruction_.count(window))
- return;
- windows_needing_frame_destruction_.insert(window);
- window->AddObserver(this);
-}
-
-mojom::Rotation Display::GetRotation() const {
- return platform_display_->GetRotation();
-}
-
-gfx::Size Display::GetSize() const {
- return root_->bounds().size();
-}
-
-int64_t Display::GetPlatformDisplayId() const {
- return platform_display_->GetDisplayId();
-}
-
-ServerWindow* Display::GetRootWithId(const WindowId& id) {
- if (id == root_->id())
- return root_.get();
- for (auto& pair : window_manager_display_root_map_) {
- if (pair.second->root()->id() == id)
- return pair.second->root();
- }
- return nullptr;
-}
-
-WindowManagerDisplayRoot* Display::GetWindowManagerDisplayRootWithRoot(
- const ServerWindow* window) {
- for (auto& pair : window_manager_display_root_map_) {
- if (pair.second->root() == window)
- return pair.second.get();
- }
- return nullptr;
-}
-
-const WindowManagerDisplayRoot* Display::GetWindowManagerDisplayRootForUser(
- const UserId& user_id) const {
- auto iter = window_manager_display_root_map_.find(user_id);
- return iter == window_manager_display_root_map_.end() ? nullptr
- : iter->second.get();
-}
-
-const WindowManagerDisplayRoot* Display::GetActiveWindowManagerDisplayRoot()
- const {
- return GetWindowManagerDisplayRootForUser(
- window_server_->user_id_tracker()->active_id());
-}
-
-bool Display::SetFocusedWindow(ServerWindow* new_focused_window) {
- ServerWindow* old_focused_window = focus_controller_->GetFocusedWindow();
- if (old_focused_window == new_focused_window)
- return true;
- DCHECK(!new_focused_window || root_window()->Contains(new_focused_window));
- return focus_controller_->SetFocusedWindow(new_focused_window);
-}
-
-ServerWindow* Display::GetFocusedWindow() {
- return focus_controller_->GetFocusedWindow();
-}
-
-void Display::ActivateNextWindow() {
- // TODO(sky): this is wrong, needs to figure out the next window to activate
- // and then route setting through WindowServer.
- focus_controller_->ActivateNextWindow();
-}
-
-void Display::AddActivationParent(ServerWindow* window) {
- activation_parents_.Add(window);
-}
-
-void Display::RemoveActivationParent(ServerWindow* window) {
- activation_parents_.Remove(window);
-}
-
-void Display::UpdateTextInputState(ServerWindow* window,
- const ui::TextInputState& state) {
- // Do not need to update text input for unfocused windows.
- if (!platform_display_ || focus_controller_->GetFocusedWindow() != window)
- return;
- platform_display_->UpdateTextInputState(state);
-}
-
-void Display::SetImeVisibility(ServerWindow* window, bool visible) {
- // Do not need to show or hide IME for unfocused window.
- if (focus_controller_->GetFocusedWindow() != window)
- return;
- platform_display_->SetImeVisibility(visible);
-}
-
-void Display::OnWillDestroyTree(WindowTree* tree) {
- for (auto it = window_manager_display_root_map_.begin();
- it != window_manager_display_root_map_.end(); ++it) {
- if (it->second->window_manager_state()->window_tree() == tree) {
- window_manager_display_root_map_.erase(it);
- break;
- }
- }
-}
-
-void Display::UpdateNativeCursor(int32_t cursor_id) {
- if (cursor_id != last_cursor_) {
- platform_display_->SetCursorById(cursor_id);
- last_cursor_ = cursor_id;
- }
-}
-
-void Display::SetSize(const gfx::Size& size) {
- platform_display_->SetViewportSize(size);
-}
-
-void Display::SetTitle(const mojo::String& title) {
- platform_display_->SetTitle(title.To<base::string16>());
-}
-
-void Display::InitWindowManagerDisplayRootsIfNecessary() {
- if (!init_called_ || !root_)
- return;
-
- display_manager()->OnDisplayAcceleratedWidgetAvailable(this);
- if (binding_) {
- std::unique_ptr<WindowManagerDisplayRoot> display_root_ptr(
- new WindowManagerDisplayRoot(this));
- WindowManagerDisplayRoot* display_root = display_root_ptr.get();
- // For this case we never create additional displays roots, so any
- // id works.
- window_manager_display_root_map_[shell::mojom::kRootUserID] =
- std::move(display_root_ptr);
- WindowTree* window_tree = binding_->CreateWindowTree(display_root->root());
- display_root->window_manager_state_ = window_tree->window_manager_state();
- } else {
- CreateWindowManagerDisplayRootsFromFactories();
- }
-}
-
-void Display::CreateWindowManagerDisplayRootsFromFactories() {
- std::vector<WindowManagerWindowTreeFactory*> factories =
- window_server_->window_manager_window_tree_factory_set()->GetFactories();
- for (WindowManagerWindowTreeFactory* factory : factories) {
- if (factory->window_tree())
- CreateWindowManagerDisplayRootFromFactory(factory);
- }
-}
-
-void Display::CreateWindowManagerDisplayRootFromFactory(
- WindowManagerWindowTreeFactory* factory) {
- std::unique_ptr<WindowManagerDisplayRoot> display_root_ptr(
- new WindowManagerDisplayRoot(this));
- WindowManagerDisplayRoot* display_root = display_root_ptr.get();
- window_manager_display_root_map_[factory->user_id()] =
- std::move(display_root_ptr);
- display_root->window_manager_state_ =
- factory->window_tree()->window_manager_state();
- const bool is_active =
- factory->user_id() == window_server_->user_id_tracker()->active_id();
- display_root->root()->SetVisible(is_active);
- display_root->window_manager_state()->window_tree()->AddRootForWindowManager(
- display_root->root());
-}
-
-ServerWindow* Display::GetRootWindow() {
- return root_.get();
-}
-
-void Display::OnEvent(const ui::Event& event) {
- WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot();
- if (display_root)
- display_root->window_manager_state()->ProcessEvent(event);
- window_server_
- ->GetUserActivityMonitorForUser(
- window_server_->user_id_tracker()->active_id())
- ->OnUserActivity();
-}
-
-void Display::OnNativeCaptureLost() {
- WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot();
- if (display_root)
- display_root->window_manager_state()->SetCapture(nullptr, kInvalidClientId);
-}
-
-void Display::OnDisplayClosed() {
- display_manager()->DestroyDisplay(this);
-}
-
-void Display::OnViewportMetricsChanged(const ViewportMetrics& old_metrics,
- const ViewportMetrics& new_metrics) {
- if (!root_) {
- root_.reset(window_server_->CreateServerWindow(
- display_manager()->GetAndAdvanceNextRootId(),
- ServerWindow::Properties()));
- root_->SetBounds(gfx::Rect(new_metrics.size_in_pixels));
- root_->SetVisible(true);
- focus_controller_.reset(new FocusController(this, root_.get()));
- focus_controller_->AddObserver(this);
- InitWindowManagerDisplayRootsIfNecessary();
- } else {
- root_->SetBounds(gfx::Rect(new_metrics.size_in_pixels));
- const gfx::Rect wm_bounds(root_->bounds().size());
- for (auto& pair : window_manager_display_root_map_)
- pair.second->root()->SetBounds(wm_bounds);
- }
- display_manager()->OnDisplayUpdate(this);
-}
-
-void Display::OnCompositorFrameDrawn() {
- std::set<ServerWindow*> windows;
- windows.swap(windows_needing_frame_destruction_);
- for (ServerWindow* window : windows) {
- window->RemoveObserver(this);
- window->DestroySurfacesScheduledForDestruction();
- }
-}
-
-bool Display::CanHaveActiveChildren(ServerWindow* window) const {
- return window && activation_parents_.Contains(window);
-}
-
-void Display::OnActivationChanged(ServerWindow* old_active_window,
- ServerWindow* new_active_window) {
- DCHECK_NE(new_active_window, old_active_window);
- if (new_active_window && new_active_window->parent()) {
- // Raise the new active window.
- // TODO(sad): Let the WM dictate whether to raise the window or not?
- new_active_window->parent()->StackChildAtTop(new_active_window);
- }
-}
-
-void Display::OnFocusChanged(FocusControllerChangeSource change_source,
- ServerWindow* old_focused_window,
- ServerWindow* new_focused_window) {
- // TODO(sky): focus is global, not per windowtreehost. Move.
-
- // There are up to four clients that need to be notified:
- // . the client containing |old_focused_window|.
- // . the client with |old_focused_window| as its root.
- // . the client containing |new_focused_window|.
- // . the client with |new_focused_window| as its root.
- // Some of these client may be the same. The following takes care to notify
- // each only once.
- WindowTree* owning_tree_old = nullptr;
- WindowTree* embedded_tree_old = nullptr;
-
- if (old_focused_window) {
- owning_tree_old =
- window_server_->GetTreeWithId(old_focused_window->id().client_id);
- if (owning_tree_old) {
- owning_tree_old->ProcessFocusChanged(old_focused_window,
- new_focused_window);
- }
- embedded_tree_old = window_server_->GetTreeWithRoot(old_focused_window);
- if (embedded_tree_old) {
- DCHECK_NE(owning_tree_old, embedded_tree_old);
- embedded_tree_old->ProcessFocusChanged(old_focused_window,
- new_focused_window);
- }
- }
- WindowTree* owning_tree_new = nullptr;
- WindowTree* embedded_tree_new = nullptr;
- if (new_focused_window) {
- owning_tree_new =
- window_server_->GetTreeWithId(new_focused_window->id().client_id);
- if (owning_tree_new && owning_tree_new != owning_tree_old &&
- owning_tree_new != embedded_tree_old) {
- owning_tree_new->ProcessFocusChanged(old_focused_window,
- new_focused_window);
- }
- embedded_tree_new = window_server_->GetTreeWithRoot(new_focused_window);
- if (embedded_tree_new && embedded_tree_new != owning_tree_old &&
- embedded_tree_new != embedded_tree_old) {
- DCHECK_NE(owning_tree_new, embedded_tree_new);
- embedded_tree_new->ProcessFocusChanged(old_focused_window,
- new_focused_window);
- }
- }
-
- // WindowManagers are always notified of focus changes.
- WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot();
- if (display_root) {
- WindowTree* wm_tree = display_root->window_manager_state()->window_tree();
- if (wm_tree != owning_tree_old && wm_tree != embedded_tree_old &&
- wm_tree != owning_tree_new && wm_tree != embedded_tree_new) {
- wm_tree->ProcessFocusChanged(old_focused_window, new_focused_window);
- }
- }
-
- UpdateTextInputState(new_focused_window,
- new_focused_window->text_input_state());
-}
-
-void Display::OnWindowDestroyed(ServerWindow* window) {
- windows_needing_frame_destruction_.erase(window);
- window->RemoveObserver(this);
-}
-
-void Display::OnUserIdRemoved(const UserId& id) {
- window_manager_display_root_map_.erase(id);
-}
-
-void Display::OnWindowManagerWindowTreeFactoryReady(
- WindowManagerWindowTreeFactory* factory) {
- if (!binding_)
- CreateWindowManagerDisplayRootFromFactory(factory);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/display.h b/chromium/components/mus/ws/display.h
deleted file mode 100644
index 419b1909c03..00000000000
--- a/chromium/components/mus/ws/display.h
+++ /dev/null
@@ -1,224 +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 COMPONENTS_MUS_WS_DISPLAY_H_
-#define COMPONENTS_MUS_WS_DISPLAY_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <queue>
-#include <set>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/mus/common/types.h"
-#include "components/mus/public/interfaces/window_manager_constants.mojom.h"
-#include "components/mus/public/interfaces/window_tree_host.mojom.h"
-#include "components/mus/ws/focus_controller_delegate.h"
-#include "components/mus/ws/focus_controller_observer.h"
-#include "components/mus/ws/platform_display.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_observer.h"
-#include "components/mus/ws/server_window_tracker.h"
-#include "components/mus/ws/user_id_tracker_observer.h"
-#include "components/mus/ws/window_manager_window_tree_factory_set_observer.h"
-
-namespace mus {
-namespace ws {
-
-class DisplayBinding;
-class DisplayManager;
-class FocusController;
-struct PlatformDisplayInitParams;
-class WindowManagerDisplayRoot;
-class WindowServer;
-class WindowTree;
-
-namespace test {
-class DisplayTestApi;
-}
-
-// Displays manages the state associated with a single display. Display has a
-// single root window whose children are the roots for a per-user
-// WindowManager. Display is configured in two distinct
-// ways:
-// . with a DisplayBinding. In this mode there is only ever one WindowManager
-// for the display, which comes from the client that created the
-// Display.
-// . without a DisplayBinding. In this mode a WindowManager is automatically
-// created per user.
-class Display : public PlatformDisplayDelegate,
- public mojom::WindowTreeHost,
- public FocusControllerObserver,
- public FocusControllerDelegate,
- public ServerWindowObserver,
- public UserIdTrackerObserver,
- public WindowManagerWindowTreeFactorySetObserver {
- public:
- Display(WindowServer* window_server,
- const PlatformDisplayInitParams& platform_display_init_params);
- ~Display() override;
-
- // Initializes state that depends on the existence of a Display.
- void Init(std::unique_ptr<DisplayBinding> binding);
-
- uint32_t id() const { return id_; }
-
- DisplayManager* display_manager();
- const DisplayManager* display_manager() const;
-
- PlatformDisplay* platform_display() { return platform_display_.get(); }
-
- // Returns a mojom::Display for the specified display. WindowManager specific
- // values are not set.
- mojom::DisplayPtr ToMojomDisplay() const;
-
- // Schedules a paint for the specified region in the coordinates of |window|.
- void SchedulePaint(const ServerWindow* window, const gfx::Rect& bounds);
-
- // Schedules destruction of surfaces in |window|. If a frame has been
- // scheduled but not drawn surface destruction is delayed until the frame is
- // drawn, otherwise destruction is immediate.
- void ScheduleSurfaceDestruction(ServerWindow* window);
-
- mojom::Rotation GetRotation() const;
- gfx::Size GetSize() const;
-
- // Returns the id for the corresponding id.
- int64_t GetPlatformDisplayId() const;
-
- WindowServer* window_server() { return window_server_; }
-
- // Returns the root of the Display. The root's children are the roots
- // of the corresponding WindowManagers.
- ServerWindow* root_window() { return root_.get(); }
- const ServerWindow* root_window() const { return root_.get(); }
-
- // Returns the ServerWindow whose id is |id|. This does not do a search over
- // all windows, rather just the display and window manager root windows.
- //
- // In general you shouldn't use this, rather use WindowServer::GetWindow(),
- // which calls this as necessary.
- ServerWindow* GetRootWithId(const WindowId& id);
-
- WindowManagerDisplayRoot* GetWindowManagerDisplayRootWithRoot(
- const ServerWindow* window);
- WindowManagerDisplayRoot* GetWindowManagerDisplayRootForUser(
- const UserId& user_id) {
- return const_cast<WindowManagerDisplayRoot*>(
- const_cast<const Display*>(this)->GetWindowManagerDisplayRootForUser(
- user_id));
- }
- const WindowManagerDisplayRoot* GetWindowManagerDisplayRootForUser(
- const UserId& user_id) const;
- WindowManagerDisplayRoot* GetActiveWindowManagerDisplayRoot() {
- return const_cast<WindowManagerDisplayRoot*>(
- const_cast<const Display*>(this)->GetActiveWindowManagerDisplayRoot());
- }
- const WindowManagerDisplayRoot* GetActiveWindowManagerDisplayRoot() const;
- size_t num_window_manger_states() const {
- return window_manager_display_root_map_.size();
- }
-
- // TODO(sky): this should only be called by WindowServer, move to interface
- // used by WindowServer.
- // See description of WindowServer::SetFocusedWindow() for details on return
- // value.
- bool SetFocusedWindow(ServerWindow* window);
- // NOTE: this returns the focused window only if the focused window is in this
- // display. If this returns null focus may be in another display.
- ServerWindow* GetFocusedWindow();
-
- void ActivateNextWindow();
-
- void AddActivationParent(ServerWindow* window);
- void RemoveActivationParent(ServerWindow* window);
-
- void UpdateTextInputState(ServerWindow* window,
- const ui::TextInputState& state);
- void SetImeVisibility(ServerWindow* window, bool visible);
-
- // Called just before |tree| is destroyed.
- void OnWillDestroyTree(WindowTree* tree);
-
- void UpdateNativeCursor(int32_t cursor_id);
-
- // mojom::WindowTreeHost:
- void SetSize(const gfx::Size& size) override;
- void SetTitle(const mojo::String& title) override;
-
- private:
- friend class test::DisplayTestApi;
-
- using WindowManagerDisplayRootMap =
- std::map<UserId, std::unique_ptr<WindowManagerDisplayRoot>>;
-
- // Inits the necessary state once the display is ready.
- void InitWindowManagerDisplayRootsIfNecessary();
-
- // Creates the set of WindowManagerDisplayRoots from the
- // WindowManagerWindowTreeFactorySet.
- void CreateWindowManagerDisplayRootsFromFactories();
-
- void CreateWindowManagerDisplayRootFromFactory(
- WindowManagerWindowTreeFactory* factory);
-
- // PlatformDisplayDelegate:
- ServerWindow* GetRootWindow() override;
- void OnEvent(const ui::Event& event) override;
- void OnNativeCaptureLost() override;
- void OnDisplayClosed() override;
- void OnViewportMetricsChanged(const ViewportMetrics& old_metrics,
- const ViewportMetrics& new_metrics) override;
- void OnCompositorFrameDrawn() override;
-
- // FocusControllerDelegate:
- bool CanHaveActiveChildren(ServerWindow* window) const override;
-
- // FocusControllerObserver:
- void OnActivationChanged(ServerWindow* old_active_window,
- ServerWindow* new_active_window) override;
- void OnFocusChanged(FocusControllerChangeSource change_source,
- ServerWindow* old_focused_window,
- ServerWindow* new_focused_window) override;
-
- // ServerWindowObserver:
- void OnWindowDestroyed(ServerWindow* window) override;
-
- // UserIdTrackerObserver:
- void OnUserIdRemoved(const UserId& id) override;
-
- // WindowManagerWindowTreeFactorySetObserver:
- void OnWindowManagerWindowTreeFactoryReady(
- WindowManagerWindowTreeFactory* factory) override;
-
- const uint32_t id_;
- std::unique_ptr<DisplayBinding> binding_;
- // Set once Init() has been called.
- bool init_called_ = false;
- WindowServer* const window_server_;
- std::unique_ptr<ServerWindow> root_;
- std::unique_ptr<PlatformDisplay> platform_display_;
- std::unique_ptr<FocusController> focus_controller_;
-
- // The last cursor set. Used to track whether we need to change the cursor.
- int32_t last_cursor_;
-
- ServerWindowTracker activation_parents_;
-
- // Set of windows with surfaces that need to be destroyed once the frame
- // draws.
- std::set<ServerWindow*> windows_needing_frame_destruction_;
-
- WindowManagerDisplayRootMap window_manager_display_root_map_;
-
- DISALLOW_COPY_AND_ASSIGN(Display);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_DISPLAY_H_
diff --git a/chromium/components/mus/ws/display_binding.cc b/chromium/components/mus/ws/display_binding.cc
deleted file mode 100644
index 519bef4a2f8..00000000000
--- a/chromium/components/mus/ws/display_binding.cc
+++ /dev/null
@@ -1,39 +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 "components/mus/ws/display_binding.h"
-
-#include "base/memory/ptr_util.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/window_manager_access_policy.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_tree.h"
-#include "services/shell/public/interfaces/connector.mojom.h"
-
-namespace mus {
-namespace ws {
-
-DisplayBindingImpl::DisplayBindingImpl(mojom::WindowTreeHostRequest request,
- Display* display,
- const UserId& user_id,
- mojom::WindowTreeClientPtr client,
- WindowServer* window_server)
- : window_server_(window_server),
- user_id_(user_id),
- binding_(display, std::move(request)),
- client_(std::move(client)) {}
-
-DisplayBindingImpl::~DisplayBindingImpl() {}
-
-WindowTree* DisplayBindingImpl::CreateWindowTree(ServerWindow* root) {
- const uint32_t embed_flags = 0;
- WindowTree* tree = window_server_->EmbedAtWindow(
- root, user_id_, std::move(client_), embed_flags,
- base::WrapUnique(new WindowManagerAccessPolicy));
- tree->ConfigureWindowManager();
- return tree;
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/display_binding.h b/chromium/components/mus/ws/display_binding.h
deleted file mode 100644
index e1f46124870..00000000000
--- a/chromium/components/mus/ws/display_binding.h
+++ /dev/null
@@ -1,60 +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 COMPONENTS_MUS_WS_DISPLAY_BINDING_H_
-#define COMPONENTS_MUS_WS_DISPLAY_BINDING_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "components/mus/public/interfaces/window_tree_host.mojom.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/user_id.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace mus {
-namespace ws {
-
-class ServerWindow;
-class WindowServer;
-class WindowTree;
-
-// DisplayBinding manages the binding between a Display and it's mojo clients.
-// DisplayBinding is used when a Display is created via a
-// WindowTreeHostFactory.
-//
-// DisplayBinding is owned by Display.
-class DisplayBinding {
- public:
- virtual ~DisplayBinding() {}
-
- virtual WindowTree* CreateWindowTree(ServerWindow* root) = 0;
-};
-
-// Live implementation of DisplayBinding.
-class DisplayBindingImpl : public DisplayBinding {
- public:
- DisplayBindingImpl(mojom::WindowTreeHostRequest request,
- Display* display,
- const UserId& user_id,
- mojom::WindowTreeClientPtr client,
- WindowServer* window_server);
- ~DisplayBindingImpl() override;
-
- private:
- // DisplayBinding:
- WindowTree* CreateWindowTree(ServerWindow* root) override;
-
- WindowServer* window_server_;
- const UserId user_id_;
- mojo::Binding<mojom::WindowTreeHost> binding_;
- mojom::WindowTreeClientPtr client_;
-
- DISALLOW_COPY_AND_ASSIGN(DisplayBindingImpl);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_DISPLAY_BINDING_H_
diff --git a/chromium/components/mus/ws/display_manager.cc b/chromium/components/mus/ws/display_manager.cc
deleted file mode 100644
index d5554093ec1..00000000000
--- a/chromium/components/mus/ws/display_manager.cc
+++ /dev/null
@@ -1,167 +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 "components/mus/ws/display_manager.h"
-
-#include "base/memory/ptr_util.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/display_manager_delegate.h"
-#include "components/mus/ws/event_dispatcher.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/user_display_manager.h"
-#include "components/mus/ws/user_id_tracker.h"
-#include "components/mus/ws/window_manager_state.h"
-
-namespace mus {
-namespace ws {
-
-DisplayManager::DisplayManager(DisplayManagerDelegate* delegate,
- UserIdTracker* user_id_tracker)
- // |next_root_id_| is used as the lower bits, so that starting at 0 is
- // fine. |next_display_id_| is used by itself, so we start at 1 to reserve
- // 0 as invalid.
- : delegate_(delegate),
- user_id_tracker_(user_id_tracker),
- next_root_id_(0),
- next_display_id_(1) {
- user_id_tracker_->AddObserver(this);
-}
-
-DisplayManager::~DisplayManager() {
- user_id_tracker_->RemoveObserver(this);
- DestroyAllDisplays();
-}
-
-UserDisplayManager* DisplayManager::GetUserDisplayManager(
- const UserId& user_id) {
- if (!user_display_managers_.count(user_id)) {
- user_display_managers_[user_id] =
- base::WrapUnique(new UserDisplayManager(this, delegate_, user_id));
- }
- return user_display_managers_[user_id].get();
-}
-
-void DisplayManager::AddDisplay(Display* display) {
- DCHECK_EQ(0u, pending_displays_.count(display));
- pending_displays_.insert(display);
-}
-
-void DisplayManager::DestroyDisplay(Display* display) {
- if (pending_displays_.count(display)) {
- pending_displays_.erase(display);
- } else {
- for (const auto& pair : user_display_managers_)
- pair.second->OnWillDestroyDisplay(display);
-
- DCHECK(displays_.count(display));
- displays_.erase(display);
- }
- delete display;
-
- // If we have no more roots left, let the app know so it can terminate.
- // TODO(sky): move to delegate/observer.
- if (!displays_.size() && !pending_displays_.size())
- delegate_->OnNoMoreDisplays();
-}
-
-void DisplayManager::DestroyAllDisplays() {
- while (!pending_displays_.empty())
- DestroyDisplay(*pending_displays_.begin());
- DCHECK(pending_displays_.empty());
-
- while (!displays_.empty())
- DestroyDisplay(*displays_.begin());
- DCHECK(displays_.empty());
-}
-
-std::set<const Display*> DisplayManager::displays() const {
- std::set<const Display*> ret_value(displays_.begin(), displays_.end());
- return ret_value;
-}
-
-void DisplayManager::OnDisplayUpdate(Display* display) {
- for (const auto& pair : user_display_managers_)
- pair.second->OnDisplayUpdate(display);
-}
-
-Display* DisplayManager::GetDisplayContaining(ServerWindow* window) {
- return const_cast<Display*>(
- static_cast<const DisplayManager*>(this)->GetDisplayContaining(window));
-}
-
-const Display* DisplayManager::GetDisplayContaining(
- const ServerWindow* window) const {
- while (window && window->parent())
- window = window->parent();
- for (Display* display : displays_) {
- if (window == display->root_window())
- return display;
- }
- return nullptr;
-}
-
-const WindowManagerDisplayRoot* DisplayManager::GetWindowManagerDisplayRoot(
- const ServerWindow* window) const {
- const ServerWindow* last = window;
- while (window && window->parent()) {
- last = window;
- window = window->parent();
- }
- for (Display* display : displays_) {
- if (window == display->root_window())
- return display->GetWindowManagerDisplayRootWithRoot(last);
- }
- return nullptr;
-}
-
-WindowManagerDisplayRoot* DisplayManager::GetWindowManagerDisplayRoot(
- const ServerWindow* window) {
- return const_cast<WindowManagerDisplayRoot*>(
- const_cast<const DisplayManager*>(this)->GetWindowManagerDisplayRoot(
- window));
-}
-
-WindowId DisplayManager::GetAndAdvanceNextRootId() {
- // TODO(sky): handle wrapping!
- const uint16_t id = next_root_id_++;
- DCHECK_LT(id, next_root_id_);
- return RootWindowId(id);
-}
-
-uint32_t DisplayManager::GetAndAdvanceNextDisplayId() {
- // TODO(sky): handle wrapping!
- const uint32_t id = next_display_id_++;
- DCHECK_LT(id, next_display_id_);
- return id;
-}
-
-void DisplayManager::OnDisplayAcceleratedWidgetAvailable(Display* display) {
- DCHECK_NE(0u, pending_displays_.count(display));
- DCHECK_EQ(0u, displays_.count(display));
- const bool is_first_display = displays_.empty();
- displays_.insert(display);
- pending_displays_.erase(display);
- if (is_first_display)
- delegate_->OnFirstDisplayReady();
-}
-
-void DisplayManager::OnActiveUserIdChanged(const UserId& previously_active_id,
- const UserId& active_id) {
- WindowManagerState* previous_window_manager_state =
- delegate_->GetWindowManagerStateForUser(previously_active_id);
- gfx::Point mouse_location_on_screen;
- if (previous_window_manager_state) {
- mouse_location_on_screen = previous_window_manager_state->event_dispatcher()
- ->mouse_pointer_last_location();
- previous_window_manager_state->Deactivate();
- }
-
- WindowManagerState* current_window_manager_state =
- delegate_->GetWindowManagerStateForUser(active_id);
- if (current_window_manager_state)
- current_window_manager_state->Activate(mouse_location_on_screen);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/display_manager.h b/chromium/components/mus/ws/display_manager.h
deleted file mode 100644
index 0c01f217e31..00000000000
--- a/chromium/components/mus/ws/display_manager.h
+++ /dev/null
@@ -1,102 +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 COMPONENTS_MUS_WS_DISPLAY_MANAGER_H_
-#define COMPONENTS_MUS_WS_DISPLAY_MANAGER_H_
-
-#include <map>
-#include <memory>
-#include <set>
-
-#include "base/macros.h"
-#include "components/mus/ws/ids.h"
-#include "components/mus/ws/user_id.h"
-#include "components/mus/ws/user_id_tracker_observer.h"
-
-namespace mus {
-namespace ws {
-
-class Display;
-class DisplayManagerDelegate;
-class ServerWindow;
-class UserDisplayManager;
-class UserIdTracker;
-class WindowManagerDisplayRoot;
-
-// DisplayManager manages the set of Displays. DisplayManager distinguishes
-// between displays that do yet have an accelerated widget (pending), vs
-// those that do.
-class DisplayManager : public UserIdTrackerObserver {
- public:
- DisplayManager(DisplayManagerDelegate* delegate,
- UserIdTracker* user_id_tracker);
- ~DisplayManager() override;
-
- // Returns the UserDisplayManager for |user_id|. DisplayManager owns the
- // return value.
- UserDisplayManager* GetUserDisplayManager(const UserId& user_id);
-
- // Adds/removes a Display. DisplayManager owns the Displays.
- // TODO(sky): make add take a scoped_ptr.
- void AddDisplay(Display* display);
- void DestroyDisplay(Display* display);
- void DestroyAllDisplays();
- const std::set<Display*>& displays() { return displays_; }
- std::set<const Display*> displays() const;
-
- // Notifies when something about the Display changes.
- void OnDisplayUpdate(Display* display);
-
- // Returns the Display that contains |window|, or null if |window| is not
- // attached to a display.
- Display* GetDisplayContaining(ServerWindow* window);
- const Display* GetDisplayContaining(const ServerWindow* window) const;
-
- const WindowManagerDisplayRoot* GetWindowManagerDisplayRoot(
- const ServerWindow* window) const;
- // TODO(sky): constness here is wrong! fix!
- WindowManagerDisplayRoot* GetWindowManagerDisplayRoot(
- const ServerWindow* window);
-
- bool has_displays() const { return !displays_.empty(); }
- bool has_active_or_pending_displays() const {
- return !displays_.empty() || !pending_displays_.empty();
- }
-
- // Returns the id for the next root window (both for the root of a Display
- // as well as the root of WindowManagers).
- WindowId GetAndAdvanceNextRootId();
-
- uint32_t GetAndAdvanceNextDisplayId();
-
- // Called when the AcceleratedWidget is available for |display|.
- void OnDisplayAcceleratedWidgetAvailable(Display* display);
-
- private:
- // UserIdTrackerObserver:
- void OnActiveUserIdChanged(const UserId& previously_active_id,
- const UserId& active_id) override;
-
- DisplayManagerDelegate* delegate_;
- UserIdTracker* user_id_tracker_;
-
- // Displays are initially added to |pending_displays_|. When the display is
- // initialized it is moved to |displays_|. WindowServer owns the Displays.
- std::set<Display*> pending_displays_;
- std::set<Display*> displays_;
-
- std::map<UserId, std::unique_ptr<UserDisplayManager>> user_display_managers_;
-
- // ID to use for next root node.
- ClientSpecificId next_root_id_;
-
- uint32_t next_display_id_;
-
- DISALLOW_COPY_AND_ASSIGN(DisplayManager);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_DISPLAY_MANAGER_H_
diff --git a/chromium/components/mus/ws/display_manager_delegate.h b/chromium/components/mus/ws/display_manager_delegate.h
deleted file mode 100644
index 9d59e2fba8b..00000000000
--- a/chromium/components/mus/ws/display_manager_delegate.h
+++ /dev/null
@@ -1,38 +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 COMPONENTS_MUS_WS_DISPLAY_MANAGER_DELEGATE_H_
-#define COMPONENTS_MUS_WS_DISPLAY_MANAGER_DELEGATE_H_
-
-#include "components/mus/public/interfaces/display.mojom.h"
-#include "components/mus/ws/user_id.h"
-
-namespace mus {
-namespace ws {
-
-class Display;
-class WindowManagerState;
-
-class DisplayManagerDelegate {
- public:
- virtual void OnFirstDisplayReady() = 0;
- virtual void OnNoMoreDisplays() = 0;
-
- // Gets the frame decorations for the specified user. Returns true if the
- // decorations have been set, false otherwise. |values| may be null.
- virtual bool GetFrameDecorationsForUser(
- const UserId& user_id,
- mojom::FrameDecorationValuesPtr* values) = 0;
-
- virtual WindowManagerState* GetWindowManagerStateForUser(
- const UserId& user_id) = 0;
-
- protected:
- virtual ~DisplayManagerDelegate() {}
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_DISPLAY_MANAGER_DELEGATE_H_
diff --git a/chromium/components/mus/ws/display_unittest.cc b/chromium/components/mus/ws/display_unittest.cc
deleted file mode 100644
index dfc24ef25a8..00000000000
--- a/chromium/components/mus/ws/display_unittest.cc
+++ /dev/null
@@ -1,308 +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 <stdint.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "components/mus/common/types.h"
-#include "components/mus/common/util.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/ids.h"
-#include "components/mus/ws/platform_display.h"
-#include "components/mus/ws/platform_display_factory.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/test_utils.h"
-#include "components/mus/ws/window_manager_display_root.h"
-#include "components/mus/ws/window_manager_state.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_server_delegate.h"
-#include "components/mus/ws/window_tree.h"
-#include "components/mus/ws/window_tree_binding.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace mus {
-namespace ws {
-namespace test {
-namespace {
-
-const UserId kTestId1 = "2";
-const UserId kTestId2 = "21";
-
-ClientWindowId ClientWindowIdForFirstRoot(WindowTree* tree) {
- if (tree->roots().empty())
- return ClientWindowId();
- return ClientWindowIdForWindow(tree, *tree->roots().begin());
-}
-
-WindowManagerState* GetWindowManagerStateForUser(Display* display,
- const UserId& user_id) {
- WindowManagerDisplayRoot* display_root =
- display->GetWindowManagerDisplayRootForUser(user_id);
- return display_root ? display_root->window_manager_state() : nullptr;
-}
-
-} // namespace
-
-// -----------------------------------------------------------------------------
-
-class DisplayTest : public testing::Test {
- public:
- DisplayTest() : cursor_id_(0), platform_display_factory_(&cursor_id_) {}
- ~DisplayTest() override {}
-
- protected:
- // testing::Test:
- void SetUp() override {
- PlatformDisplay::set_factory_for_testing(&platform_display_factory_);
- window_server_.reset(new WindowServer(&window_server_delegate_,
- scoped_refptr<SurfacesState>()));
- window_server_delegate_.set_window_server(window_server_.get());
- window_server_->user_id_tracker()->AddUserId(kTestId1);
- window_server_->user_id_tracker()->AddUserId(kTestId2);
- }
-
- protected:
- int32_t cursor_id_;
- TestPlatformDisplayFactory platform_display_factory_;
- TestWindowServerDelegate window_server_delegate_;
- std::unique_ptr<WindowServer> window_server_;
- base::MessageLoop message_loop_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DisplayTest);
-};
-
-TEST_F(DisplayTest, CallsCreateDefaultDisplays) {
- const int kNumHostsToCreate = 2;
- window_server_delegate_.set_num_displays_to_create(kNumHostsToCreate);
-
- DisplayManager* display_manager = window_server_->display_manager();
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId1);
- // The first register should trigger creation of the default
- // Displays. There should be kNumHostsToCreate Displays.
- EXPECT_EQ(static_cast<size_t>(kNumHostsToCreate),
- display_manager->displays().size());
-
- // Each host should have a WindowManagerState for kTestId1.
- for (Display* display : display_manager->displays()) {
- EXPECT_EQ(1u, display->num_window_manger_states());
- EXPECT_TRUE(GetWindowManagerStateForUser(display, kTestId1));
- EXPECT_FALSE(GetWindowManagerStateForUser(display, kTestId2));
- }
-
- // Add another registry, should trigger creation of another wm.
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId2);
- for (Display* display : display_manager->displays()) {
- ASSERT_EQ(2u, display->num_window_manger_states());
- WindowManagerDisplayRoot* root1 =
- display->GetWindowManagerDisplayRootForUser(kTestId1);
- ASSERT_TRUE(root1);
- WindowManagerDisplayRoot* root2 =
- display->GetWindowManagerDisplayRootForUser(kTestId2);
- ASSERT_TRUE(root2);
- // Verify the two states have different roots.
- EXPECT_NE(root1, root2);
- EXPECT_NE(root1->root(), root2->root());
- }
-}
-
-TEST_F(DisplayTest, Destruction) {
- window_server_delegate_.set_num_displays_to_create(1);
-
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId1);
-
- // Add another registry, should trigger creation of another wm.
- DisplayManager* display_manager = window_server_->display_manager();
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId2);
- ASSERT_EQ(1u, display_manager->displays().size());
- Display* display = *display_manager->displays().begin();
- ASSERT_EQ(2u, display->num_window_manger_states());
- // There should be two trees, one for each windowmanager.
- EXPECT_EQ(2u, window_server_->num_trees());
-
- {
- WindowManagerState* state = GetWindowManagerStateForUser(display, kTestId1);
- // Destroy the tree associated with |state|. Should result in deleting
- // |state|.
- window_server_->DestroyTree(state->window_tree());
- ASSERT_EQ(1u, display->num_window_manger_states());
- EXPECT_FALSE(GetWindowManagerStateForUser(display, kTestId1));
- EXPECT_EQ(1u, display_manager->displays().size());
- EXPECT_EQ(1u, window_server_->num_trees());
- }
-
- EXPECT_FALSE(window_server_delegate_.got_on_no_more_displays());
- window_server_->display_manager()->DestroyDisplay(display);
- // There is still one tree left.
- EXPECT_EQ(1u, window_server_->num_trees());
- EXPECT_TRUE(window_server_delegate_.got_on_no_more_displays());
-}
-
-TEST_F(DisplayTest, EventStateResetOnUserSwitch) {
- window_server_delegate_.set_num_displays_to_create(1);
-
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId1);
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId2);
-
- window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
-
- DisplayManager* display_manager = window_server_->display_manager();
- ASSERT_EQ(1u, display_manager->displays().size());
- Display* display = *display_manager->displays().begin();
- WindowManagerState* active_wms =
- display->GetActiveWindowManagerDisplayRoot()->window_manager_state();
- ASSERT_TRUE(active_wms);
- EXPECT_EQ(kTestId1, active_wms->user_id());
-
- static_cast<PlatformDisplayDelegate*>(display)->OnEvent(ui::PointerEvent(
- ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(20, 25),
- gfx::Point(20, 25), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)));
-
- EXPECT_TRUE(EventDispatcherTestApi(active_wms->event_dispatcher())
- .AreAnyPointersDown());
- EXPECT_EQ(gfx::Point(20, 25),
- active_wms->event_dispatcher()->mouse_pointer_last_location());
-
- // Switch the user. Should trigger resetting state in old event dispatcher
- // and update state in new event dispatcher.
- window_server_->user_id_tracker()->SetActiveUserId(kTestId2);
- EXPECT_NE(
- active_wms,
- display->GetActiveWindowManagerDisplayRoot()->window_manager_state());
- EXPECT_FALSE(EventDispatcherTestApi(active_wms->event_dispatcher())
- .AreAnyPointersDown());
- active_wms =
- display->GetActiveWindowManagerDisplayRoot()->window_manager_state();
- EXPECT_EQ(kTestId2, active_wms->user_id());
- EXPECT_EQ(gfx::Point(20, 25),
- active_wms->event_dispatcher()->mouse_pointer_last_location());
- EXPECT_FALSE(EventDispatcherTestApi(active_wms->event_dispatcher())
- .AreAnyPointersDown());
-}
-
-// Verifies capture fails when wm is inactive and succeeds when wm is active.
-TEST_F(DisplayTest, SetCaptureFromWindowManager) {
- window_server_delegate_.set_num_displays_to_create(1);
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId1);
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId2);
- window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
- DisplayManager* display_manager = window_server_->display_manager();
- ASSERT_EQ(1u, display_manager->displays().size());
- Display* display = *display_manager->displays().begin();
- WindowManagerState* wms_for_id2 =
- GetWindowManagerStateForUser(display, kTestId2);
- ASSERT_TRUE(wms_for_id2);
- EXPECT_FALSE(wms_for_id2->IsActive());
-
- // Create a child of the root that we can set capture on.
- WindowTree* tree = wms_for_id2->window_tree();
- ClientWindowId child_window_id;
- ASSERT_TRUE(NewWindowInTree(tree, &child_window_id));
-
- WindowTreeTestApi(tree).EnableCapture();
-
- // SetCapture() should fail for user id2 as it is inactive.
- EXPECT_FALSE(tree->SetCapture(child_window_id));
-
- // Make the second user active and verify capture works.
- window_server_->user_id_tracker()->SetActiveUserId(kTestId2);
- EXPECT_TRUE(wms_for_id2->IsActive());
- EXPECT_TRUE(tree->SetCapture(child_window_id));
-}
-
-TEST_F(DisplayTest, FocusFailsForInactiveUser) {
- window_server_delegate_.set_num_displays_to_create(1);
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId1);
- TestWindowTreeClient* window_tree_client1 =
- window_server_delegate_.last_client();
- ASSERT_TRUE(window_tree_client1);
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId2);
- window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
- DisplayManager* display_manager = window_server_->display_manager();
- ASSERT_EQ(1u, display_manager->displays().size());
- Display* display = *display_manager->displays().begin();
- WindowManagerState* wms_for_id2 =
- GetWindowManagerStateForUser(display, kTestId2);
- wms_for_id2->window_tree()->AddActivationParent(
- ClientWindowIdForFirstRoot(wms_for_id2->window_tree()));
- ASSERT_TRUE(wms_for_id2);
- EXPECT_FALSE(wms_for_id2->IsActive());
- ClientWindowId child2_id;
- NewWindowInTree(wms_for_id2->window_tree(), &child2_id);
-
- // Focus should fail for windows in inactive window managers.
- EXPECT_FALSE(wms_for_id2->window_tree()->SetFocus(child2_id));
-
- // Focus should succeed for the active window manager.
- WindowManagerState* wms_for_id1 =
- GetWindowManagerStateForUser(display, kTestId1);
- ASSERT_TRUE(wms_for_id1);
- wms_for_id1->window_tree()->AddActivationParent(
- ClientWindowIdForFirstRoot(wms_for_id1->window_tree()));
- ClientWindowId child1_id;
- NewWindowInTree(wms_for_id1->window_tree(), &child1_id);
- EXPECT_TRUE(wms_for_id1->IsActive());
- EXPECT_TRUE(wms_for_id1->window_tree()->SetFocus(child1_id));
-}
-
-// Verifies a single tree is used for multiple displays.
-TEST_F(DisplayTest, MultipleDisplays) {
- window_server_delegate_.set_num_displays_to_create(2);
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kTestId1);
- window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
- ASSERT_EQ(1u, window_server_delegate_.bindings()->size());
- TestWindowTreeBinding* window_tree_binding =
- (*window_server_delegate_.bindings())[0];
- WindowTree* tree = window_tree_binding->tree();
- ASSERT_EQ(2u, tree->roots().size());
- std::set<const ServerWindow*> roots = tree->roots();
- auto it = roots.begin();
- ServerWindow* root1 = tree->GetWindow((*it)->id());
- ++it;
- ServerWindow* root2 = tree->GetWindow((*it)->id());
- ASSERT_NE(root1, root2);
- Display* display1 = tree->GetDisplay(root1);
- WindowManagerState* display1_wms =
- display1->GetWindowManagerDisplayRootForUser(kTestId1)
- ->window_manager_state();
- Display* display2 = tree->GetDisplay(root2);
- WindowManagerState* display2_wms =
- display2->GetWindowManagerDisplayRootForUser(kTestId1)
- ->window_manager_state();
- EXPECT_EQ(display1_wms->window_tree(), display2_wms->window_tree());
-}
-
-} // namespace test
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/event_dispatcher.cc b/chromium/components/mus/ws/event_dispatcher.cc
deleted file mode 100644
index 23874c3abc4..00000000000
--- a/chromium/components/mus/ws/event_dispatcher.cc
+++ /dev/null
@@ -1,559 +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 "components/mus/ws/event_dispatcher.h"
-
-#include <algorithm>
-
-#include "base/time/time.h"
-#include "components/mus/ws/accelerator.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/event_dispatcher_delegate.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_delegate.h"
-#include "components/mus/ws/window_coordinate_conversions.h"
-#include "components/mus/ws/window_finder.h"
-#include "ui/events/event_utils.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/point_conversions.h"
-
-namespace mus {
-namespace ws {
-
-using Entry = std::pair<uint32_t, std::unique_ptr<Accelerator>>;
-
-namespace {
-
-bool IsOnlyOneMouseButtonDown(int flags) {
- const uint32_t button_only_flags =
- flags & (ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON |
- ui::EF_RIGHT_MOUSE_BUTTON);
- return button_only_flags == ui::EF_LEFT_MOUSE_BUTTON ||
- button_only_flags == ui::EF_MIDDLE_MOUSE_BUTTON ||
- button_only_flags == ui::EF_RIGHT_MOUSE_BUTTON;
-}
-
-bool IsLocationInNonclientArea(const ServerWindow* target,
- const gfx::Point& location) {
- if (!target->parent())
- return false;
-
- gfx::Rect client_area(target->bounds().size());
- client_area.Inset(target->client_area());
- if (client_area.Contains(location))
- return false;
-
- for (const auto& rect : target->additional_client_areas()) {
- if (rect.Contains(location))
- return false;
- }
-
- return true;
-}
-
-uint32_t PointerId(const ui::LocatedEvent& event) {
- if (event.IsPointerEvent())
- return event.AsPointerEvent()->pointer_id();
- if (event.IsMouseWheelEvent())
- return ui::PointerEvent::kMousePointerId;
-
- NOTREACHED();
- return 0;
-}
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-
-EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
- : delegate_(delegate),
- capture_window_(nullptr),
- capture_window_client_id_(kInvalidClientId),
- modal_window_controller_(this),
- mouse_button_down_(false),
- mouse_cursor_source_window_(nullptr),
- mouse_cursor_in_non_client_area_(false) {}
-
-EventDispatcher::~EventDispatcher() {
- if (capture_window_) {
- UnobserveWindow(capture_window_);
- capture_window_ = nullptr;
- capture_window_client_id_ = kInvalidClientId;
- }
- for (const auto& pair : pointer_targets_) {
- if (pair.second.window)
- UnobserveWindow(pair.second.window);
- }
- pointer_targets_.clear();
-}
-
-void EventDispatcher::Reset() {
- if (capture_window_) {
- CancelPointerEventsToTarget(capture_window_);
- DCHECK(capture_window_ == nullptr);
- }
-
- while (!pointer_targets_.empty())
- StopTrackingPointer(pointer_targets_.begin()->first);
-
- mouse_button_down_ = false;
-}
-
-void EventDispatcher::SetMousePointerScreenLocation(
- const gfx::Point& screen_location) {
- DCHECK(pointer_targets_.empty());
- mouse_pointer_last_location_ = screen_location;
- UpdateCursorProviderByLastKnownLocation();
- // Write our initial location back to our shared screen coordinate. This
- // shouldn't cause problems because we already read the cursor before we
- // process any events in views during window construction.
- delegate_->OnMouseCursorLocationChanged(screen_location);
-}
-
-bool EventDispatcher::GetCurrentMouseCursor(int32_t* cursor_out) {
- if (!mouse_cursor_source_window_)
- return false;
-
- *cursor_out = mouse_cursor_in_non_client_area_
- ? mouse_cursor_source_window_->non_client_cursor()
- : mouse_cursor_source_window_->cursor();
- return true;
-}
-
-bool EventDispatcher::SetCaptureWindow(ServerWindow* window,
- ClientSpecificId client_id) {
- if (!window)
- client_id = kInvalidClientId;
-
- if (window == capture_window_ && client_id == capture_window_client_id_)
- return true;
-
- // A window that is blocked by a modal window cannot gain capture.
- if (window && modal_window_controller_.IsWindowBlocked(window))
- return false;
-
- if (capture_window_) {
- // Stop observing old capture window. |pointer_targets_| are cleared on
- // initial setting of a capture window.
- delegate_->OnServerWindowCaptureLost(capture_window_);
- UnobserveWindow(capture_window_);
- } else {
- // Cancel implicit capture to all other windows.
- for (const auto& pair : pointer_targets_) {
- ServerWindow* target = pair.second.window;
- if (!target)
- continue;
- UnobserveWindow(target);
- if (target == window)
- continue;
-
- ui::EventType event_type = pair.second.is_mouse_event
- ? ui::ET_POINTER_EXITED
- : ui::ET_POINTER_CANCELLED;
- ui::EventPointerType pointer_type =
- pair.second.is_mouse_event ? ui::EventPointerType::POINTER_TYPE_MOUSE
- : ui::EventPointerType::POINTER_TYPE_TOUCH;
- // TODO(jonross): Track previous location in PointerTarget for sending
- // cancels.
- ui::PointerEvent event(
- event_type, gfx::Point(), gfx::Point(), ui::EF_NONE, pair.first,
- ui::PointerDetails(pointer_type), ui::EventTimeForNow());
- DispatchToPointerTarget(pair.second, event);
- }
- pointer_targets_.clear();
- }
-
- // Set the capture before changing native capture; otherwise, the callback
- // from native platform might try to set the capture again.
- bool had_capture_window = capture_window_ != nullptr;
- capture_window_ = window;
- capture_window_client_id_ = client_id;
-
- // Begin tracking the capture window if it is not yet being observed.
- if (window) {
- ObserveWindow(window);
- // TODO(sky): this conditional is problematic for the case of capture moving
- // to a different display.
- if (!had_capture_window)
- delegate_->SetNativeCapture(window);
- } else {
- delegate_->ReleaseNativeCapture();
- if (!mouse_button_down_)
- UpdateCursorProviderByLastKnownLocation();
- }
-
- return true;
-}
-
-void EventDispatcher::AddSystemModalWindow(ServerWindow* window) {
- modal_window_controller_.AddSystemModalWindow(window);
-}
-
-void EventDispatcher::ReleaseCaptureBlockedByModalWindow(
- const ServerWindow* modal_window) {
- if (!capture_window_)
- return;
-
- if (modal_window_controller_.IsWindowBlockedBy(capture_window_,
- modal_window)) {
- SetCaptureWindow(nullptr, kInvalidClientId);
- }
-}
-
-void EventDispatcher::ReleaseCaptureBlockedByAnyModalWindow() {
- if (!capture_window_)
- return;
-
- if (modal_window_controller_.IsWindowBlocked(capture_window_))
- SetCaptureWindow(nullptr, kInvalidClientId);
-}
-
-void EventDispatcher::UpdateNonClientAreaForCurrentWindow() {
- if (mouse_cursor_source_window_) {
- gfx::Point location = mouse_pointer_last_location_;
- ServerWindow* target = FindDeepestVisibleWindowForEvents(&location);
- if (target == mouse_cursor_source_window_) {
- mouse_cursor_in_non_client_area_ =
- mouse_cursor_source_window_
- ? IsLocationInNonclientArea(mouse_cursor_source_window_, location)
- : false;
- }
- }
-}
-
-void EventDispatcher::UpdateCursorProviderByLastKnownLocation() {
- if (!mouse_button_down_) {
- gfx::Point location = mouse_pointer_last_location_;
- mouse_cursor_source_window_ = FindDeepestVisibleWindowForEvents(&location);
-
- mouse_cursor_in_non_client_area_ =
- mouse_cursor_source_window_
- ? IsLocationInNonclientArea(mouse_cursor_source_window_, location)
- : false;
- }
-}
-
-bool EventDispatcher::AddAccelerator(uint32_t id,
- mojom::EventMatcherPtr event_matcher) {
- std::unique_ptr<Accelerator> accelerator(new Accelerator(id, *event_matcher));
- // If an accelerator with the same id or matcher already exists, then abort.
- for (const auto& pair : accelerators_) {
- if (pair.first == id || accelerator->EqualEventMatcher(pair.second.get()))
- return false;
- }
- accelerators_.insert(Entry(id, std::move(accelerator)));
- return true;
-}
-
-void EventDispatcher::RemoveAccelerator(uint32_t id) {
- auto it = accelerators_.find(id);
- // Clients may pass bogus ids.
- if (it != accelerators_.end())
- accelerators_.erase(it);
-}
-
-void EventDispatcher::ProcessEvent(const ui::Event& event) {
- if (event.IsKeyEvent()) {
- const ui::KeyEvent* key_event = event.AsKeyEvent();
- if (event.type() == ui::ET_KEY_PRESSED && !key_event->is_char()) {
- Accelerator* pre_target =
- FindAccelerator(*key_event, ui::mojom::AcceleratorPhase::PRE_TARGET);
- if (pre_target) {
- delegate_->OnAccelerator(pre_target->id(), event);
- return;
- }
- }
- ProcessKeyEvent(*key_event);
- return;
- }
-
- if (event.IsPointerEvent() || event.IsMouseWheelEvent()) {
- ProcessLocatedEvent(*event.AsLocatedEvent());
- return;
- }
-
- NOTREACHED();
-}
-
-void EventDispatcher::ProcessKeyEvent(const ui::KeyEvent& event) {
- Accelerator* post_target =
- FindAccelerator(event, ui::mojom::AcceleratorPhase::POST_TARGET);
- ServerWindow* focused_window =
- delegate_->GetFocusedWindowForEventDispatcher();
- if (focused_window) {
- // Assume key events are for the client area.
- const bool in_nonclient_area = false;
- const ClientSpecificId client_id =
- delegate_->GetEventTargetClientId(focused_window, in_nonclient_area);
- delegate_->DispatchInputEventToWindow(focused_window, client_id, event,
- post_target);
- return;
- }
- delegate_->OnEventTargetNotFound(event);
- if (post_target)
- delegate_->OnAccelerator(post_target->id(), event);
-}
-
-void EventDispatcher::ProcessLocatedEvent(const ui::LocatedEvent& event) {
- DCHECK(event.IsPointerEvent() || event.IsMouseWheelEvent());
- const bool is_mouse_event =
- event.IsMousePointerEvent() || event.IsMouseWheelEvent();
-
- if (is_mouse_event) {
- mouse_pointer_last_location_ = event.location();
- delegate_->OnMouseCursorLocationChanged(event.root_location());
- }
-
- // Release capture on pointer up. For mouse we only release if there are
- // no buttons down.
- const bool is_pointer_going_up =
- (event.type() == ui::ET_POINTER_UP ||
- event.type() == ui::ET_POINTER_CANCELLED) &&
- (!is_mouse_event || IsOnlyOneMouseButtonDown(event.flags()));
-
- // Update mouse down state upon events which change it.
- if (is_mouse_event) {
- if (event.type() == ui::ET_POINTER_DOWN)
- mouse_button_down_ = true;
- else if (is_pointer_going_up)
- mouse_button_down_ = false;
- }
-
- if (capture_window_) {
- mouse_cursor_source_window_ = capture_window_;
- DispatchToClient(capture_window_, capture_window_client_id_, event);
- return;
- }
-
- const int32_t pointer_id = PointerId(event);
- if (!IsTrackingPointer(pointer_id) ||
- !pointer_targets_[pointer_id].is_pointer_down) {
- const bool any_pointers_down = AreAnyPointersDown();
- UpdateTargetForPointer(pointer_id, event);
- if (is_mouse_event)
- mouse_cursor_source_window_ = pointer_targets_[pointer_id].window;
-
- PointerTarget& pointer_target = pointer_targets_[pointer_id];
- if (pointer_target.is_pointer_down) {
- if (is_mouse_event)
- mouse_cursor_source_window_ = pointer_target.window;
- if (!any_pointers_down) {
- delegate_->SetFocusedWindowFromEventDispatcher(pointer_target.window);
- delegate_->SetNativeCapture(pointer_target.window);
- }
- }
- }
-
- // When we release the mouse button, we want the cursor to be sourced from
- // the window under the mouse pointer, even though we're sending the button
- // up event to the window that had implicit capture. We have to set this
- // before we perform dispatch because the Delegate is going to read this
- // information from us.
- if (is_pointer_going_up && is_mouse_event)
- UpdateCursorProviderByLastKnownLocation();
-
- DispatchToPointerTarget(pointer_targets_[pointer_id], event);
-
- if (is_pointer_going_up) {
- if (is_mouse_event)
- pointer_targets_[pointer_id].is_pointer_down = false;
- else
- StopTrackingPointer(pointer_id);
- if (!AreAnyPointersDown())
- delegate_->ReleaseNativeCapture();
- }
-}
-
-void EventDispatcher::StartTrackingPointer(
- int32_t pointer_id,
- const PointerTarget& pointer_target) {
- DCHECK(!IsTrackingPointer(pointer_id));
- ObserveWindow(pointer_target.window);
- pointer_targets_[pointer_id] = pointer_target;
-}
-
-void EventDispatcher::StopTrackingPointer(int32_t pointer_id) {
- DCHECK(IsTrackingPointer(pointer_id));
- ServerWindow* window = pointer_targets_[pointer_id].window;
- pointer_targets_.erase(pointer_id);
- if (window)
- UnobserveWindow(window);
-}
-
-void EventDispatcher::UpdateTargetForPointer(int32_t pointer_id,
- const ui::LocatedEvent& event) {
- if (!IsTrackingPointer(pointer_id)) {
- StartTrackingPointer(pointer_id, PointerTargetForEvent(event));
- return;
- }
-
- const PointerTarget pointer_target = PointerTargetForEvent(event);
- if (pointer_target.window == pointer_targets_[pointer_id].window &&
- pointer_target.in_nonclient_area ==
- pointer_targets_[pointer_id].in_nonclient_area) {
- // The targets are the same, only set the down state to true if necessary.
- // Down going to up is handled by ProcessLocatedEvent().
- if (pointer_target.is_pointer_down)
- pointer_targets_[pointer_id].is_pointer_down = true;
- return;
- }
-
- // The targets are changing. Send an exit if appropriate.
- if (event.IsMousePointerEvent()) {
- ui::PointerEvent exit_event(
- ui::ET_POINTER_EXITED, event.location(), event.root_location(),
- event.flags(), ui::PointerEvent::kMousePointerId,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE),
- event.time_stamp());
- DispatchToPointerTarget(pointer_targets_[pointer_id], exit_event);
- }
-
- // Technically we're updating in place, but calling start then stop makes for
- // simpler code.
- StopTrackingPointer(pointer_id);
- StartTrackingPointer(pointer_id, pointer_target);
-}
-
-EventDispatcher::PointerTarget EventDispatcher::PointerTargetForEvent(
- const ui::LocatedEvent& event) {
- PointerTarget pointer_target;
- gfx::Point location(event.location());
- ServerWindow* target_window = FindDeepestVisibleWindowForEvents(&location);
- pointer_target.window =
- modal_window_controller_.GetTargetForWindow(target_window);
- pointer_target.is_mouse_event = event.IsMousePointerEvent();
- pointer_target.in_nonclient_area =
- target_window != pointer_target.window ||
- IsLocationInNonclientArea(pointer_target.window, location);
- pointer_target.is_pointer_down = event.type() == ui::ET_POINTER_DOWN;
- return pointer_target;
-}
-
-bool EventDispatcher::AreAnyPointersDown() const {
- for (const auto& pair : pointer_targets_) {
- if (pair.second.is_pointer_down)
- return true;
- }
- return false;
-}
-
-void EventDispatcher::DispatchToPointerTarget(const PointerTarget& target,
- const ui::LocatedEvent& event) {
- if (!target.window) {
- delegate_->OnEventTargetNotFound(event);
- return;
- }
-
- if (target.is_mouse_event)
- mouse_cursor_in_non_client_area_ = target.in_nonclient_area;
-
- DispatchToClient(target.window, delegate_->GetEventTargetClientId(
- target.window, target.in_nonclient_area),
- event);
-}
-
-void EventDispatcher::DispatchToClient(ServerWindow* window,
- ClientSpecificId client_id,
- const ui::LocatedEvent& event) {
- gfx::Point location(event.location());
- gfx::Transform transform(GetTransformToWindow(window));
- transform.TransformPoint(&location);
- std::unique_ptr<ui::Event> clone = ui::Event::Clone(event);
- clone->AsLocatedEvent()->set_location(location);
- // TODO(jonross): add post-target accelerator support once accelerators
- // support pointer events.
- delegate_->DispatchInputEventToWindow(window, client_id, *clone, nullptr);
-}
-
-void EventDispatcher::CancelPointerEventsToTarget(ServerWindow* window) {
- if (capture_window_ == window) {
- UnobserveWindow(window);
- capture_window_ = nullptr;
- capture_window_client_id_ = kInvalidClientId;
- mouse_button_down_ = false;
- // A window only cares to be informed that it lost capture if it explicitly
- // requested capture. A window can lose capture if another window gains
- // explicit capture.
- delegate_->OnServerWindowCaptureLost(window);
- delegate_->ReleaseNativeCapture();
- UpdateCursorProviderByLastKnownLocation();
- return;
- }
-
- for (auto& pair : pointer_targets_) {
- if (pair.second.window == window) {
- UnobserveWindow(window);
- pair.second.window = nullptr;
- }
- }
-}
-
-void EventDispatcher::ObserveWindow(ServerWindow* window) {
- auto res = observed_windows_.insert(std::make_pair(window, 0u));
- res.first->second++;
- if (res.second)
- window->AddObserver(this);
-}
-
-void EventDispatcher::UnobserveWindow(ServerWindow* window) {
- auto it = observed_windows_.find(window);
- DCHECK(it != observed_windows_.end());
- DCHECK_LT(0u, it->second);
- it->second--;
- if (!it->second) {
- window->RemoveObserver(this);
- observed_windows_.erase(it);
- }
-}
-
-Accelerator* EventDispatcher::FindAccelerator(
- const ui::KeyEvent& event,
- const ui::mojom::AcceleratorPhase phase) {
- for (const auto& pair : accelerators_) {
- if (pair.second->MatchesEvent(event, phase)) {
- return pair.second.get();
- }
- }
- return nullptr;
-}
-
-ServerWindow* EventDispatcher::FindDeepestVisibleWindowForEvents(
- gfx::Point* location) {
- ServerWindow* root = delegate_->GetRootWindowContaining(*location);
- if (!root)
- return nullptr;
-
- return mus::ws::FindDeepestVisibleWindowForEvents(root, location);
-}
-
-void EventDispatcher::OnWillChangeWindowHierarchy(ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) {
- // TODO(sky): moving to a different root likely needs to transfer capture.
- // TODO(sky): this isn't quite right, I think the logic should be (assuming
- // moving in same root and still drawn):
- // . if there is capture and window is still in the same root, continue
- // sending to it.
- // . if there isn't capture, then reevaluate each of the pointer targets
- // sending exit as necessary.
- // http://crbug.com/613646 .
- if (!new_parent || !new_parent->IsDrawn() ||
- new_parent->GetRoot() != old_parent->GetRoot()) {
- CancelPointerEventsToTarget(window);
- }
-}
-
-void EventDispatcher::OnWindowVisibilityChanged(ServerWindow* window) {
- CancelPointerEventsToTarget(window);
-}
-
-void EventDispatcher::OnWindowDestroyed(ServerWindow* window) {
- CancelPointerEventsToTarget(window);
-
- if (mouse_cursor_source_window_ == window)
- mouse_cursor_source_window_ = nullptr;
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/event_dispatcher.h b/chromium/components/mus/ws/event_dispatcher.h
deleted file mode 100644
index a6178073981..00000000000
--- a/chromium/components/mus/ws/event_dispatcher.h
+++ /dev/null
@@ -1,236 +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 COMPONENTS_MUS_WS_EVENT_DISPATCHER_H_
-#define COMPONENTS_MUS_WS_EVENT_DISPATCHER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <utility>
-
-#include "base/macros.h"
-#include "components/mus/common/types.h"
-#include "components/mus/public/interfaces/event_matcher.mojom.h"
-#include "components/mus/ws/modal_window_controller.h"
-#include "components/mus/ws/server_window_observer.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace ui {
-class Event;
-class KeyEvent;
-class LocatedEvent;
-}
-
-namespace mus {
-namespace ws {
-
-class Accelerator;
-class EventDispatcherDelegate;
-class ServerWindow;
-
-namespace test {
-class EventDispatcherTestApi;
-}
-
-// Handles dispatching events to the right location as well as updating focus.
-class EventDispatcher : public ServerWindowObserver {
- public:
- explicit EventDispatcher(EventDispatcherDelegate* delegate);
- ~EventDispatcher() override;
-
- // Cancels capture and stops tracking any pointer events. This does not send
- // any events to the delegate.
- void Reset();
-
- void SetMousePointerScreenLocation(const gfx::Point& screen_location);
- const gfx::Point& mouse_pointer_last_location() const {
- return mouse_pointer_last_location_;
- }
-
- // If we still have the window of the last mouse move, returns true and sets
- // the current cursor to use to |cursor_out|.
- bool GetCurrentMouseCursor(int32_t* cursor_out);
-
- // |capture_window_| will receive all input. See window_tree.mojom for
- // details.
- ServerWindow* capture_window() { return capture_window_; }
- const ServerWindow* capture_window() const { return capture_window_; }
- // Setting capture can fail if the window is blocked by a modal window
- // (indicated by returning |false|).
- bool SetCaptureWindow(ServerWindow* capture_window,
- ClientSpecificId client_id);
-
- // Id of the client that capture events are sent to.
- ClientSpecificId capture_window_client_id() const {
- return capture_window_client_id_;
- }
-
- // Adds a system modal window. The window remains modal to system until it is
- // destroyed. There can exist multiple system modal windows, in which case the
- // one that is visible and added most recently or shown most recently would be
- // the active one.
- void AddSystemModalWindow(ServerWindow* window);
-
- // Checks if |modal_window| is a visible modal window that blocks current
- // capture window and if that's the case, releases the capture.
- void ReleaseCaptureBlockedByModalWindow(const ServerWindow* modal_window);
-
- // Checks if the current capture window is blocked by any visible modal window
- // and if that's the case, releases the capture.
- void ReleaseCaptureBlockedByAnyModalWindow();
-
- // Retrieves the ServerWindow of the last mouse move.
- ServerWindow* mouse_cursor_source_window() const {
- return mouse_cursor_source_window_;
- }
-
- // If the mouse cursor is still over |mouse_cursor_source_window_|, updates
- // whether we are in the non-client area. Used when
- // |mouse_cursor_source_window_| has changed its properties.
- void UpdateNonClientAreaForCurrentWindow();
-
- // Possibly updates the cursor. If we aren't in an implicit capture, we take
- // the last known location of the mouse pointer, and look for the
- // ServerWindow* under it.
- void UpdateCursorProviderByLastKnownLocation();
-
- // Adds an accelerator with the given id and event-matcher. If an accelerator
- // already exists with the same id or the same matcher, then the accelerator
- // is not added. Returns whether adding the accelerator was successful or not.
- bool AddAccelerator(uint32_t id, mojom::EventMatcherPtr event_matcher);
- void RemoveAccelerator(uint32_t id);
-
- // Processes the supplied event, informing the delegate as approriate. This
- // may result in generating any number of events.
- void ProcessEvent(const ui::Event& event);
-
- private:
- friend class test::EventDispatcherTestApi;
-
- // Keeps track of state associated with an active pointer.
- struct PointerTarget {
- PointerTarget()
- : window(nullptr),
- is_mouse_event(false),
- in_nonclient_area(false),
- is_pointer_down(false) {}
-
- // NOTE: this is set to null if the window is destroyed before a
- // corresponding release/cancel.
- ServerWindow* window;
-
- bool is_mouse_event;
-
- // Did the pointer event start in the non-client area.
- bool in_nonclient_area;
-
- bool is_pointer_down;
- };
-
- void ProcessKeyEvent(const ui::KeyEvent& event);
-
- bool IsTrackingPointer(int32_t pointer_id) const {
- return pointer_targets_.count(pointer_id) > 0;
- }
-
- // EventDispatcher provides the following logic for pointer events:
- // . wheel events go to the current target of the associated pointer. If
- // there is no target, they go to the deepest window.
- // . move (not drag) events go to the deepest window.
- // . when a pointer goes down all events until the corresponding up or
- // cancel go to the deepest target. For mouse events the up only occurs
- // when no buttons on the mouse are down.
- // This also generates exit events as appropriate. For example, if the mouse
- // moves between one window to another an exit is generated on the first.
- void ProcessLocatedEvent(const ui::LocatedEvent& event);
-
- // Adds |pointer_target| to |pointer_targets_|.
- void StartTrackingPointer(int32_t pointer_id,
- const PointerTarget& pointer_target);
-
- // Removes a PointerTarget from |pointer_targets_|.
- void StopTrackingPointer(int32_t pointer_id);
-
- // Starts tracking the pointer for |event|, or if already tracking the
- // pointer sends the appropriate event to the delegate and updates the
- // currently tracked PointerTarget appropriately.
- void UpdateTargetForPointer(int32_t pointer_id,
- const ui::LocatedEvent& event);
-
- // Returns a PointerTarget from the supplied event.
- PointerTarget PointerTargetForEvent(const ui::LocatedEvent& event);
-
- // Returns true if any pointers are in the pressed/down state.
- bool AreAnyPointersDown() const;
-
- // If |target->window| is valid, then passes the event to the delegate.
- void DispatchToPointerTarget(const PointerTarget& target,
- const ui::LocatedEvent& event);
-
- // Dispatch |event| to the delegate.
- void DispatchToClient(ServerWindow* window,
- ClientSpecificId client_id,
- const ui::LocatedEvent& event);
-
- // Stops sending pointer events to |window|. This does not remove the entry
- // for |window| from |pointer_targets_|, rather it nulls out the window. This
- // way we continue to eat events until the up/cancel is received.
- void CancelPointerEventsToTarget(ServerWindow* window);
-
- // Used to observe a window. Can be called multiple times on a window. To
- // unobserve a window, UnobserveWindow() should be called the same number of
- // times.
- void ObserveWindow(ServerWindow* winodw);
- void UnobserveWindow(ServerWindow* winodw);
-
- // Returns an Accelerator bound to the specified code/flags, and of the
- // matching |phase|. Otherwise returns null.
- Accelerator* FindAccelerator(const ui::KeyEvent& event,
- const ui::mojom::AcceleratorPhase phase);
-
- ServerWindow* FindDeepestVisibleWindowForEvents(gfx::Point* location);
-
- // ServerWindowObserver:
- void OnWillChangeWindowHierarchy(ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) override;
- void OnWindowVisibilityChanged(ServerWindow* window) override;
- void OnWindowDestroyed(ServerWindow* window) override;
-
- EventDispatcherDelegate* delegate_;
-
- ServerWindow* capture_window_;
- ClientSpecificId capture_window_client_id_;
-
- ModalWindowController modal_window_controller_;
-
- bool mouse_button_down_;
- ServerWindow* mouse_cursor_source_window_;
- bool mouse_cursor_in_non_client_area_;
-
- // The on screen location of the mouse pointer. This can be outside the
- // bounds of |mouse_cursor_source_window_|, which can capture the cursor.
- gfx::Point mouse_pointer_last_location_;
-
- std::map<uint32_t, std::unique_ptr<Accelerator>> accelerators_;
-
- using PointerIdToTargetMap = std::map<int32_t, PointerTarget>;
- // |pointer_targets_| contains the active pointers. For a mouse based pointer
- // a PointerTarget is always active (and present in |pointer_targets_|). For
- // touch based pointers the pointer is active while down and removed on
- // cancel or up.
- PointerIdToTargetMap pointer_targets_;
-
- // Keeps track of number of observe requests for each observed window.
- std::map<const ServerWindow*, uint8_t> observed_windows_;
-
- DISALLOW_COPY_AND_ASSIGN(EventDispatcher);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_EVENT_DISPATCHER_H_
diff --git a/chromium/components/mus/ws/event_dispatcher_delegate.h b/chromium/components/mus/ws/event_dispatcher_delegate.h
deleted file mode 100644
index 1d31fb99d50..00000000000
--- a/chromium/components/mus/ws/event_dispatcher_delegate.h
+++ /dev/null
@@ -1,73 +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 COMPONENTS_MUS_WS_EVENT_DISPATCHER_DELEGATE_H_
-#define COMPONENTS_MUS_WS_EVENT_DISPATCHER_DELEGATE_H_
-
-#include <stdint.h>
-
-#include "components/mus/common/types.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace ui {
-class Event;
-}
-
-namespace mus {
-namespace ws {
-
-class Accelerator;
-class ServerWindow;
-
-// Used by EventDispatcher for mocking in tests.
-class EventDispatcherDelegate {
- public:
- virtual void OnAccelerator(uint32_t accelerator, const ui::Event& event) = 0;
-
- virtual void SetFocusedWindowFromEventDispatcher(ServerWindow* window) = 0;
- virtual ServerWindow* GetFocusedWindowForEventDispatcher() = 0;
-
- // Called when capture should be set on the native display. |window| is the
- // window capture is being set on.
- virtual void SetNativeCapture(ServerWindow* window) = 0;
- // Called when the native display is having capture released. There is no
- // longer a ServerWindow holding capture.
- virtual void ReleaseNativeCapture() = 0;
- // Called when |window| has lost capture. The native display may still be
- // holding capture. The delegate should not change native display capture.
- // ReleaseNativeCapture() is invoked if appropriate.
- virtual void OnServerWindowCaptureLost(ServerWindow* window) = 0;
-
- virtual void OnMouseCursorLocationChanged(const gfx::Point& point) = 0;
-
- // Dispatches an event to the specific client.
- virtual void DispatchInputEventToWindow(ServerWindow* target,
- ClientSpecificId client_id,
- const ui::Event& event,
- Accelerator* accelerator) = 0;
-
- // Returns the id of the client to send events to. |in_nonclient_area| is
- // true if the event occurred in the non-client area of the window.
- virtual ClientSpecificId GetEventTargetClientId(const ServerWindow* window,
- bool in_nonclient_area) = 0;
-
- // Returns the window to start searching from at the specified location, or
- // null if there is a no window containing |location|.
- virtual ServerWindow* GetRootWindowContaining(const gfx::Point& location) = 0;
-
- // Called when event dispatch could not find a target. OnAccelerator may still
- // be called.
- virtual void OnEventTargetNotFound(const ui::Event& event) = 0;
-
- protected:
- virtual ~EventDispatcherDelegate() {}
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_EVENT_DISPATCHER_DELEGATE_H_
diff --git a/chromium/components/mus/ws/event_dispatcher_unittest.cc b/chromium/components/mus/ws/event_dispatcher_unittest.cc
deleted file mode 100644
index e47e961aff4..00000000000
--- a/chromium/components/mus/ws/event_dispatcher_unittest.cc
+++ /dev/null
@@ -1,1614 +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 "components/mus/ws/event_dispatcher.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <queue>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/mus/common/event_matcher_util.h"
-#include "components/mus/ws/accelerator.h"
-#include "components/mus/ws/event_dispatcher_delegate.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_surface_manager_test_api.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "components/mus/ws/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event.h"
-
-namespace mus {
-namespace ws {
-namespace test {
-namespace {
-
-// Client ids used to indicate the client area and non-client area.
-const ClientSpecificId kClientAreaId = 11;
-const ClientSpecificId kNonclientAreaId = 111;
-
-// Identifies a generated event.
-struct DispatchedEventDetails {
- DispatchedEventDetails()
- : window(nullptr), client_id(kInvalidClientId), accelerator(nullptr) {}
-
- bool IsNonclientArea() const { return client_id == kNonclientAreaId; }
- bool IsClientArea() const { return client_id == kClientAreaId; }
-
- ServerWindow* window;
- ClientSpecificId client_id;
- std::unique_ptr<ui::Event> event;
- Accelerator* accelerator;
-};
-
-class TestEventDispatcherDelegate : public EventDispatcherDelegate {
- public:
- // Delegate interface used by this class to release capture on event
- // dispatcher.
- class Delegate {
- public:
- virtual void ReleaseCapture() = 0;
- };
-
- explicit TestEventDispatcherDelegate(Delegate* delegate)
- : delegate_(delegate),
- focused_window_(nullptr),
- lost_capture_window_(nullptr),
- last_accelerator_(0) {}
- ~TestEventDispatcherDelegate() override {}
-
- ui::Event* last_event_target_not_found() {
- return last_event_target_not_found_.get();
- }
-
- uint32_t GetAndClearLastAccelerator() {
- uint32_t return_value = last_accelerator_;
- last_accelerator_ = 0;
- return return_value;
- }
-
- void set_root(ServerWindow* root) { root_ = root; }
-
- // Returns the last dispatched event, or null if there are no more.
- std::unique_ptr<DispatchedEventDetails>
- GetAndAdvanceDispatchedEventDetails() {
- if (dispatched_event_queue_.empty())
- return nullptr;
-
- std::unique_ptr<DispatchedEventDetails> details =
- std::move(dispatched_event_queue_.front());
- dispatched_event_queue_.pop();
- return details;
- }
-
- ServerWindow* GetAndClearLastFocusedWindow() {
- ServerWindow* result = focused_window_;
- focused_window_ = nullptr;
- return result;
- }
-
- bool has_queued_events() const { return !dispatched_event_queue_.empty(); }
- ServerWindow* lost_capture_window() { return lost_capture_window_; }
-
- // EventDispatcherDelegate:
- void SetFocusedWindowFromEventDispatcher(ServerWindow* window) override {
- focused_window_ = window;
- }
-
- private:
- // EventDispatcherDelegate:
- void OnAccelerator(uint32_t accelerator, const ui::Event& event) override {
- EXPECT_EQ(0u, last_accelerator_);
- last_accelerator_ = accelerator;
- }
- ServerWindow* GetFocusedWindowForEventDispatcher() override {
- return focused_window_;
- }
- void SetNativeCapture(ServerWindow* window) override {}
- void ReleaseNativeCapture() override {
- if (delegate_)
- delegate_->ReleaseCapture();
- }
- void OnServerWindowCaptureLost(ServerWindow* window) override {
- lost_capture_window_ = window;
- }
- void OnMouseCursorLocationChanged(const gfx::Point& point) override {}
- void DispatchInputEventToWindow(ServerWindow* target,
- ClientSpecificId client_id,
- const ui::Event& event,
- Accelerator* accelerator) override {
- std::unique_ptr<DispatchedEventDetails> details(new DispatchedEventDetails);
- details->window = target;
- details->client_id = client_id;
- details->event = ui::Event::Clone(event);
- details->accelerator = accelerator;
- dispatched_event_queue_.push(std::move(details));
- }
- ClientSpecificId GetEventTargetClientId(const ServerWindow* window,
- bool in_nonclient_area) override {
- return in_nonclient_area ? kNonclientAreaId : kClientAreaId;
- }
- ServerWindow* GetRootWindowContaining(const gfx::Point& location) override {
- return root_;
- }
- void OnEventTargetNotFound(const ui::Event& event) override {
- last_event_target_not_found_ = ui::Event::Clone(event);
- }
-
- Delegate* delegate_;
- ServerWindow* focused_window_;
- ServerWindow* lost_capture_window_;
- uint32_t last_accelerator_;
- std::queue<std::unique_ptr<DispatchedEventDetails>> dispatched_event_queue_;
- ServerWindow* root_ = nullptr;
- std::unique_ptr<ui::Event> last_event_target_not_found_;
-
- DISALLOW_COPY_AND_ASSIGN(TestEventDispatcherDelegate);
-};
-
-// Used by RunMouseEventTests(). Can identify up to two generated events. The
-// first ServerWindow and two points identify the first event, the second
-// ServerWindow and points identify the second event. If only one event is
-// generated set the second window to null.
-struct MouseEventTest {
- ui::MouseEvent input_event;
- ServerWindow* expected_target_window1;
- gfx::Point expected_root_location1;
- gfx::Point expected_location1;
- ServerWindow* expected_target_window2;
- gfx::Point expected_root_location2;
- gfx::Point expected_location2;
-};
-
-// Verifies |details| matches the supplied ServerWindow and points.
-void ExpectDispatchedEventDetailsMatches(const DispatchedEventDetails* details,
- ServerWindow* target,
- const gfx::Point& root_location,
- const gfx::Point& location) {
- if (!target) {
- ASSERT_FALSE(details);
- return;
- }
-
- ASSERT_EQ(target, details->window);
- ASSERT_TRUE(details->event);
- ASSERT_TRUE(details->event->IsLocatedEvent());
- ASSERT_TRUE(details->IsClientArea());
- ASSERT_EQ(root_location, details->event->AsLocatedEvent()->root_location());
- ASSERT_EQ(location, details->event->AsLocatedEvent()->location());
-}
-
-void RunMouseEventTests(EventDispatcher* dispatcher,
- TestEventDispatcherDelegate* dispatcher_delegate,
- MouseEventTest* tests,
- size_t test_count) {
- for (size_t i = 0; i < test_count; ++i) {
- const MouseEventTest& test = tests[i];
- ASSERT_FALSE(dispatcher_delegate->has_queued_events())
- << " unexpected queued events before running " << i;
- if (test.input_event.IsMouseWheelEvent())
- dispatcher->ProcessEvent(test.input_event);
- else
- dispatcher->ProcessEvent(ui::PointerEvent(test.input_event));
-
- std::unique_ptr<DispatchedEventDetails> details =
- dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- ASSERT_NO_FATAL_FAILURE(ExpectDispatchedEventDetailsMatches(
- details.get(), test.expected_target_window1,
- test.expected_root_location1, test.expected_location1))
- << " details don't match " << i;
- details = dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- ASSERT_NO_FATAL_FAILURE(ExpectDispatchedEventDetailsMatches(
- details.get(), test.expected_target_window2,
- test.expected_root_location2, test.expected_location2))
- << " details2 don't match " << i;
- ASSERT_FALSE(dispatcher_delegate->has_queued_events())
- << " unexpected queued events after running " << i;
- }
-}
-
-} // namespace
-
-// Test fixture for EventDispatcher with friend access to verify the internal
-// state. Setup creates a TestServerWindowDelegate, a visible root ServerWindow,
-// a TestEventDispatcher and the EventDispatcher for testing.
-class EventDispatcherTest : public testing::Test,
- public TestEventDispatcherDelegate::Delegate {
- public:
- EventDispatcherTest() {}
- ~EventDispatcherTest() override {}
-
- ServerWindow* root_window() { return root_window_.get(); }
- TestEventDispatcherDelegate* test_event_dispatcher_delegate() {
- return test_event_dispatcher_delegate_.get();
- }
- EventDispatcher* event_dispatcher() { return event_dispatcher_.get(); }
-
- bool AreAnyPointersDown() const;
- // Deletes everything created during SetUp()
- void ClearSetup();
- std::unique_ptr<ServerWindow> CreateChildWindowWithParent(
- const WindowId& id,
- ServerWindow* parent);
- // Creates a window which is a child of |root_window_|.
- std::unique_ptr<ServerWindow> CreateChildWindow(const WindowId& id);
- bool IsMouseButtonDown() const;
- bool IsWindowPointerTarget(const ServerWindow* window) const;
- int NumberPointerTargetsForWindow(ServerWindow* window) const;
- ServerWindow* GetActiveSystemModalWindow() const;
-
- protected:
- // testing::Test:
- void SetUp() override;
-
- private:
- // TestEventDispatcherDelegate::Delegate:
- void ReleaseCapture() override {
- event_dispatcher_->SetCaptureWindow(nullptr, kInvalidClientId);
- }
-
- std::unique_ptr<TestServerWindowDelegate> window_delegate_;
- std::unique_ptr<ServerWindow> root_window_;
- std::unique_ptr<TestEventDispatcherDelegate> test_event_dispatcher_delegate_;
- std::unique_ptr<EventDispatcher> event_dispatcher_;
-
- DISALLOW_COPY_AND_ASSIGN(EventDispatcherTest);
-};
-
-bool EventDispatcherTest::AreAnyPointersDown() const {
- return EventDispatcherTestApi(event_dispatcher_.get()).AreAnyPointersDown();
-}
-
-void EventDispatcherTest::ClearSetup() {
- window_delegate_.reset();
- root_window_.reset();
- test_event_dispatcher_delegate_.reset();
- event_dispatcher_.reset();
-}
-
-std::unique_ptr<ServerWindow> EventDispatcherTest::CreateChildWindowWithParent(
- const WindowId& id,
- ServerWindow* parent) {
- std::unique_ptr<ServerWindow> child(
- new ServerWindow(window_delegate_.get(), id));
- parent->Add(child.get());
- child->SetVisible(true);
- EnableHitTest(child.get());
- return child;
-}
-
-std::unique_ptr<ServerWindow> EventDispatcherTest::CreateChildWindow(
- const WindowId& id) {
- return CreateChildWindowWithParent(id, root_window_.get());
-}
-
-bool EventDispatcherTest::IsMouseButtonDown() const {
- return EventDispatcherTestApi(event_dispatcher_.get()).is_mouse_button_down();
-}
-
-bool EventDispatcherTest::IsWindowPointerTarget(
- const ServerWindow* window) const {
- return EventDispatcherTestApi(event_dispatcher_.get())
- .IsWindowPointerTarget(window);
-}
-
-int EventDispatcherTest::NumberPointerTargetsForWindow(
- ServerWindow* window) const {
- return EventDispatcherTestApi(event_dispatcher_.get())
- .NumberPointerTargetsForWindow(window);
-}
-
-ServerWindow* EventDispatcherTest::GetActiveSystemModalWindow() const {
- ModalWindowController* mwc =
- EventDispatcherTestApi(event_dispatcher_.get()).modal_window_controller();
- return ModalWindowControllerTestApi(mwc).GetActiveSystemModalWindow();
-}
-
-void EventDispatcherTest::SetUp() {
- testing::Test::SetUp();
-
- window_delegate_.reset(new TestServerWindowDelegate());
- root_window_.reset(new ServerWindow(window_delegate_.get(), WindowId(1, 2)));
- window_delegate_->set_root_window(root_window_.get());
- root_window_->SetVisible(true);
-
- test_event_dispatcher_delegate_.reset(new TestEventDispatcherDelegate(this));
- event_dispatcher_.reset(
- new EventDispatcher(test_event_dispatcher_delegate_.get()));
- test_event_dispatcher_delegate_->set_root(root_window_.get());
-}
-
-TEST_F(EventDispatcherTest, ProcessEvent) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- // Send event that is over child.
- const ui::PointerEvent ui_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), gfx::Point(20, 25),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(ui_event);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- ASSERT_EQ(child.get(), details->window);
-
- ASSERT_TRUE(details->event);
- ASSERT_TRUE(details->event->IsPointerEvent());
-
- ui::PointerEvent* dispatched_event = details->event->AsPointerEvent();
- EXPECT_EQ(gfx::Point(20, 25), dispatched_event->root_location());
- EXPECT_EQ(gfx::Point(10, 15), dispatched_event->location());
-}
-
-TEST_F(EventDispatcherTest, ProcessEventNoTarget) {
- // Send event without a target.
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
- event_dispatcher()->ProcessEvent(key);
-
- // Event wasn't dispatched to a target.
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(details);
-
- // Delegate was informed that there wasn't a target.
- ui::Event* event_out =
- test_event_dispatcher_delegate()->last_event_target_not_found();
- ASSERT_TRUE(event_out);
- EXPECT_TRUE(event_out->IsKeyEvent());
- EXPECT_EQ(ui::VKEY_A, event_out->AsKeyEvent()->key_code());
-}
-
-TEST_F(EventDispatcherTest, AcceleratorBasic) {
- ClearSetup();
- TestEventDispatcherDelegate event_dispatcher_delegate(nullptr);
- EventDispatcher dispatcher(&event_dispatcher_delegate);
-
- uint32_t accelerator_1 = 1;
- mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher(
- ui::mojom::KeyboardCode::W, ui::mojom::kEventFlagControlDown);
- EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_1, std::move(matcher)));
-
- uint32_t accelerator_2 = 2;
- matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::N,
- ui::mojom::kEventFlagNone);
- EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_2, std::move(matcher)));
-
- // Attempting to add a new accelerator with the same id should fail.
- matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::T,
- ui::mojom::kEventFlagNone);
- EXPECT_FALSE(dispatcher.AddAccelerator(accelerator_2, std::move(matcher)));
-
- // Adding the accelerator with the same id should succeed once the existing
- // accelerator is removed.
- dispatcher.RemoveAccelerator(accelerator_2);
- matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::T,
- ui::mojom::kEventFlagNone);
- EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_2, std::move(matcher)));
-
- // Attempting to add an accelerator with the same matcher should fail.
- uint32_t accelerator_3 = 3;
- matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::T,
- ui::mojom::kEventFlagNone);
- EXPECT_FALSE(dispatcher.AddAccelerator(accelerator_3, std::move(matcher)));
-
- matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::T,
- ui::mojom::kEventFlagControlDown);
- EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_3, std::move(matcher)));
-}
-
-TEST_F(EventDispatcherTest, EventMatching) {
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- EventDispatcher* dispatcher = event_dispatcher();
-
- mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher(
- ui::mojom::KeyboardCode::W, ui::mojom::kEventFlagControlDown);
- uint32_t accelerator_1 = 1;
- dispatcher->AddAccelerator(accelerator_1, std::move(matcher));
-
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
- dispatcher->ProcessEvent(key);
- EXPECT_EQ(accelerator_1,
- event_dispatcher_delegate->GetAndClearLastAccelerator());
-
- // EF_NUM_LOCK_ON should be ignored since CreateKeyMatcher defaults to
- // ignoring.
- key = ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_W,
- ui::EF_CONTROL_DOWN | ui::EF_NUM_LOCK_ON);
- dispatcher->ProcessEvent(key);
- EXPECT_EQ(accelerator_1,
- event_dispatcher_delegate->GetAndClearLastAccelerator());
-
- key = ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_NONE);
- dispatcher->ProcessEvent(key);
- EXPECT_EQ(0u, event_dispatcher_delegate->GetAndClearLastAccelerator());
-
- uint32_t accelerator_2 = 2;
- matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::W,
- ui::mojom::kEventFlagNone);
- dispatcher->AddAccelerator(accelerator_2, std::move(matcher));
- dispatcher->ProcessEvent(key);
- EXPECT_EQ(accelerator_2,
- event_dispatcher_delegate->GetAndClearLastAccelerator());
-
- dispatcher->RemoveAccelerator(accelerator_2);
- dispatcher->ProcessEvent(key);
- EXPECT_EQ(0u, event_dispatcher_delegate->GetAndClearLastAccelerator());
-}
-
-// Tests that a post-target accelerator is not triggered by ProcessEvent.
-TEST_F(EventDispatcherTest, PostTargetAccelerator) {
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- EventDispatcher* dispatcher = event_dispatcher();
-
- mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher(
- ui::mojom::KeyboardCode::W, ui::mojom::kEventFlagControlDown);
- matcher->accelerator_phase = ui::mojom::AcceleratorPhase::POST_TARGET;
- uint32_t accelerator_1 = 1;
- dispatcher->AddAccelerator(accelerator_1, std::move(matcher));
-
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
- // The post-target accelerator should be fired if there is no focused window.
- dispatcher->ProcessEvent(key);
- EXPECT_EQ(accelerator_1,
- event_dispatcher_delegate->GetAndClearLastAccelerator());
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(details);
-
- // Set focused window for EventDispatcher dispatches key events.
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
- event_dispatcher_delegate->SetFocusedWindowFromEventDispatcher(child.get());
-
- // With a focused window the event should be dispatched.
- dispatcher->ProcessEvent(key);
- EXPECT_EQ(0u, event_dispatcher_delegate->GetAndClearLastAccelerator());
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_TRUE(details);
- EXPECT_TRUE(details->accelerator);
-
- base::WeakPtr<Accelerator> accelerator_weak_ptr =
- details->accelerator->GetWeakPtr();
- dispatcher->RemoveAccelerator(accelerator_1);
- EXPECT_FALSE(accelerator_weak_ptr);
-
- // Post deletion there should be no accelerator
- dispatcher->ProcessEvent(key);
- EXPECT_EQ(0u, event_dispatcher_delegate->GetAndClearLastAccelerator());
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_TRUE(details);
- EXPECT_FALSE(details->accelerator);
-}
-
-TEST_F(EventDispatcherTest, Capture) {
- ServerWindow* root = root_window();
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- MouseEventTest tests[] = {
- // Send a mouse down event over child.
- {ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(20, 25),
- gfx::Point(20, 25), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON),
- child.get(), gfx::Point(20, 25), gfx::Point(10, 15), nullptr,
- gfx::Point(), gfx::Point()},
-
- // Capture should be activated. Let's send a mouse move outside the bounds
- // of the child.
- {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50),
- gfx::Point(50, 50), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON),
- child.get(), gfx::Point(50, 50), gfx::Point(40, 40), nullptr,
- gfx::Point(), gfx::Point()},
- // Release the mouse and verify that the mouse up event goes to the child.
- {ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(50, 50),
- gfx::Point(50, 50), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON),
- child.get(), gfx::Point(50, 50), gfx::Point(40, 40), nullptr,
- gfx::Point(), gfx::Point()},
-
- // A mouse move at (50, 50) should now go to the root window. As the
- // move crosses between |child| and |root| |child| gets an exit, and
- // |root| the move.
- {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50),
- gfx::Point(50, 50), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON),
- child.get(), gfx::Point(50, 50), gfx::Point(40, 40), root,
- gfx::Point(50, 50), gfx::Point(50, 50)},
-
- };
- RunMouseEventTests(event_dispatcher(), test_event_dispatcher_delegate(),
- tests, arraysize(tests));
-}
-
-TEST_F(EventDispatcherTest, CaptureMultipleMouseButtons) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- MouseEventTest tests[] = {
- // Send a mouse down event over child with a left mouse button
- {ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(20, 25),
- gfx::Point(20, 25), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON),
- child.get(), gfx::Point(20, 25), gfx::Point(10, 15), nullptr,
- gfx::Point(), gfx::Point()},
-
- // Capture should be activated. Let's send a mouse move outside the bounds
- // of the child and press the right mouse button too.
- {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50),
- gfx::Point(50, 50), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON, 0),
- child.get(), gfx::Point(50, 50), gfx::Point(40, 40), nullptr,
- gfx::Point(), gfx::Point()},
-
- // Release the left mouse button and verify that the mouse up event goes
- // to the child.
- {ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(50, 50),
- gfx::Point(50, 50), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON,
- ui::EF_RIGHT_MOUSE_BUTTON),
- child.get(), gfx::Point(50, 50), gfx::Point(40, 40), nullptr,
- gfx::Point(), gfx::Point()},
-
- // A mouse move at (50, 50) should still go to the child.
- {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50),
- gfx::Point(50, 50), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON, 0),
- child.get(), gfx::Point(50, 50), gfx::Point(40, 40), nullptr,
- gfx::Point(), gfx::Point()},
-
- };
- RunMouseEventTests(event_dispatcher(), test_event_dispatcher_delegate(),
- tests, arraysize(tests));
-}
-
-TEST_F(EventDispatcherTest, ClientAreaGoesToOwner) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- child->SetClientArea(gfx::Insets(5, 5, 5, 5), std::vector<gfx::Rect>());
-
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- EventDispatcher* dispatcher = event_dispatcher();
-
- // Start move loop by sending mouse event over non-client area.
- const ui::PointerEvent press_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(12, 12), gfx::Point(12, 12),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(press_event);
-
- // Events should target child and be in the non-client area.
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- ASSERT_TRUE(details);
- ASSERT_EQ(child.get(), details->window);
- EXPECT_TRUE(details->IsNonclientArea());
-
- // Move the mouse 5,6 pixels and target is the same.
- const ui::PointerEvent move_event(
- ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(17, 18), gfx::Point(17, 18),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, 0));
- dispatcher->ProcessEvent(move_event);
-
- // Still same target.
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- ASSERT_EQ(child.get(), details->window);
- EXPECT_TRUE(details->IsNonclientArea());
-
- // Release the mouse.
- const ui::PointerEvent release_event(ui::MouseEvent(
- ui::ET_MOUSE_RELEASED, gfx::Point(17, 18), gfx::Point(17, 18),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(release_event);
-
- // The event should not have been dispatched to the delegate.
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- ASSERT_EQ(child.get(), details->window);
- EXPECT_TRUE(details->IsNonclientArea());
-
- // Press in the client area and verify target/client area. The non-client area
- // should get an exit first.
- const ui::PointerEvent press_event2(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(21, 22), gfx::Point(21, 22),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(press_event2);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_TRUE(event_dispatcher_delegate->has_queued_events());
- ASSERT_EQ(child.get(), details->window);
- EXPECT_TRUE(details->IsNonclientArea());
- EXPECT_EQ(ui::ET_POINTER_EXITED, details->event->type());
-
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- ASSERT_EQ(child.get(), details->window);
- EXPECT_TRUE(details->IsClientArea());
- EXPECT_EQ(ui::ET_POINTER_DOWN, details->event->type());
-}
-
-TEST_F(EventDispatcherTest, AdditionalClientArea) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- std::vector<gfx::Rect> additional_client_areas;
- additional_client_areas.push_back(gfx::Rect(18, 0, 2, 2));
- child->SetClientArea(gfx::Insets(5, 5, 5, 5), additional_client_areas);
-
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- // Press in the additional client area, it should go to the child.
- const ui::PointerEvent press_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(28, 11), gfx::Point(28, 11),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(press_event);
-
- // Events should target child and be in the client area.
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- ASSERT_EQ(child.get(), details->window);
- EXPECT_TRUE(details->IsClientArea());
-}
-
-TEST_F(EventDispatcherTest, HitTestMask) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
- child->SetHitTestMask(gfx::Rect(2, 2, 16, 16));
-
- // Move in the masked area.
- const ui::PointerEvent move1(ui::MouseEvent(
- ui::ET_MOUSE_MOVED, gfx::Point(11, 11), gfx::Point(11, 11),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, 0));
- event_dispatcher()->ProcessEvent(move1);
-
- // Event went through the child window and hit the root.
- std::unique_ptr<DispatchedEventDetails> details1 =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(root_window(), details1->window);
- EXPECT_TRUE(details1->IsClientArea());
-
- child->ClearHitTestMask();
-
- // Move right in the same part of the window.
- const ui::PointerEvent move2(ui::MouseEvent(
- ui::ET_MOUSE_MOVED, gfx::Point(11, 12), gfx::Point(11, 12),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, 0));
- event_dispatcher()->ProcessEvent(move2);
-
- // Mouse exits the root.
- std::unique_ptr<DispatchedEventDetails> details2 =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(ui::ET_POINTER_EXITED, details2->event->type());
-
- // Mouse hits the child.
- std::unique_ptr<DispatchedEventDetails> details3 =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(child.get(), details3->window);
- EXPECT_TRUE(details3->IsClientArea());
-}
-
-TEST_F(EventDispatcherTest, DontFocusOnSecondDown) {
- std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child1->SetBounds(gfx::Rect(10, 10, 20, 20));
- child2->SetBounds(gfx::Rect(50, 51, 11, 12));
-
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- EventDispatcher* dispatcher = event_dispatcher();
-
- // Press on child1. First press event should change focus.
- const ui::PointerEvent press_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(12, 12), gfx::Point(12, 12),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(press_event);
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- EXPECT_EQ(child1.get(), details->window);
- EXPECT_EQ(child1.get(),
- event_dispatcher_delegate->GetAndClearLastFocusedWindow());
-
- // Press (with a different pointer id) on child2. Event should go to child2,
- // but focus should not change.
- const ui::PointerEvent touch_event(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(53, 54), 2, base::TimeTicks()));
- dispatcher->ProcessEvent(touch_event);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- EXPECT_EQ(child2.get(), details->window);
- EXPECT_EQ(nullptr, event_dispatcher_delegate->GetAndClearLastFocusedWindow());
-}
-
-TEST_F(EventDispatcherTest, TwoPointersActive) {
- std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child1->SetBounds(gfx::Rect(10, 10, 20, 20));
- child2->SetBounds(gfx::Rect(50, 51, 11, 12));
-
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- EventDispatcher* dispatcher = event_dispatcher();
-
- // Press on child1.
- const ui::PointerEvent touch_event1(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks()));
- dispatcher->ProcessEvent(touch_event1);
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(child1.get(), details->window);
-
- // Drag over child2, child1 should get the drag.
- const ui::PointerEvent drag_event1(ui::TouchEvent(
- ui::ET_TOUCH_MOVED, gfx::Point(53, 54), 1, base::TimeTicks()));
- dispatcher->ProcessEvent(drag_event1);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(child1.get(), details->window);
-
- // Press on child2 with a different touch id.
- const ui::PointerEvent touch_event2(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(54, 55), 2, base::TimeTicks()));
- dispatcher->ProcessEvent(touch_event2);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(child2.get(), details->window);
-
- // Drag over child1 with id 2, child2 should continue to get the drag.
- const ui::PointerEvent drag_event2(ui::TouchEvent(
- ui::ET_TOUCH_MOVED, gfx::Point(13, 14), 2, base::TimeTicks()));
- dispatcher->ProcessEvent(drag_event2);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(child2.get(), details->window);
-
- // Drag again with id 1, child1 should continue to get it.
- dispatcher->ProcessEvent(drag_event1);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(child1.get(), details->window);
-
- // Release touch id 1, and click on 2. 2 should get it.
- const ui::PointerEvent touch_release(ui::TouchEvent(
- ui::ET_TOUCH_RELEASED, gfx::Point(54, 55), 1, base::TimeTicks()));
- dispatcher->ProcessEvent(touch_release);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(child1.get(), details->window);
- const ui::PointerEvent touch_event3(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(54, 55), 2, base::TimeTicks()));
- dispatcher->ProcessEvent(touch_event3);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(child2.get(), details->window);
-}
-
-TEST_F(EventDispatcherTest, DestroyWindowWhileGettingEvents) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- EventDispatcher* dispatcher = event_dispatcher();
-
- // Press on child.
- const ui::PointerEvent touch_event1(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks()));
- dispatcher->ProcessEvent(touch_event1);
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- EXPECT_EQ(child.get(), details->window);
-
- // Delete child, and continue the drag. Event should not be dispatched.
- child.reset();
-
- const ui::PointerEvent drag_event1(ui::TouchEvent(
- ui::ET_TOUCH_MOVED, gfx::Point(53, 54), 1, base::TimeTicks()));
- dispatcher->ProcessEvent(drag_event1);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(nullptr, details.get());
-}
-
-TEST_F(EventDispatcherTest, MouseInExtendedHitTestRegion) {
- ServerWindow* root = root_window();
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- EventDispatcher* dispatcher = event_dispatcher();
-
- // Send event that is not over child.
- const ui::PointerEvent ui_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(8, 9), gfx::Point(8, 9),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(ui_event);
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- ASSERT_EQ(root, details->window);
-
- // Release the mouse.
- const ui::PointerEvent release_event(ui::MouseEvent(
- ui::ET_MOUSE_RELEASED, gfx::Point(8, 9), gfx::Point(8, 9),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(release_event);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- ASSERT_EQ(root, details->window);
- EXPECT_TRUE(details->IsClientArea());
-
- // Change the extended hit test region and send event in extended hit test
- // region. Should result in exit for root, followed by press for child.
- child->set_extended_hit_test_region(gfx::Insets(5, 5, 5, 5));
- dispatcher->ProcessEvent(ui_event);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_EQ(root, details->window);
- EXPECT_EQ(ui::ET_POINTER_EXITED, details->event->type());
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
-
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- EXPECT_TRUE(details->IsNonclientArea());
- ASSERT_EQ(child.get(), details->window);
- EXPECT_EQ(ui::ET_POINTER_DOWN, details->event->type());
- ASSERT_TRUE(details->event.get());
- ASSERT_TRUE(details->event->IsPointerEvent());
- EXPECT_EQ(gfx::Point(-2, -1), details->event->AsPointerEvent()->location());
-}
-
-TEST_F(EventDispatcherTest, WheelWhileDown) {
- std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child1->SetBounds(gfx::Rect(10, 10, 20, 20));
- child2->SetBounds(gfx::Rect(50, 51, 11, 12));
-
- MouseEventTest tests[] = {
- // Send a mouse down event over child1.
- {ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(15, 15),
- gfx::Point(15, 15), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON),
- child1.get(), gfx::Point(15, 15), gfx::Point(5, 5), nullptr,
- gfx::Point(), gfx::Point()},
- // Send mouse wheel over child2, should go to child1 as it has capture.
- {ui::MouseWheelEvent(gfx::Vector2d(1, 0), gfx::Point(53, 54),
- gfx::Point(53, 54), base::TimeTicks(), ui::EF_NONE,
- ui::EF_NONE),
- child1.get(), gfx::Point(53, 54), gfx::Point(43, 44), nullptr,
- gfx::Point(), gfx::Point()},
- };
- RunMouseEventTests(event_dispatcher(), test_event_dispatcher_delegate(),
- tests, arraysize(tests));
-}
-
-// Tests that when explicit capture has been set that all events go to the
-// designated window, and that when capture is cleared, events find the
-// appropriate target window.
-TEST_F(EventDispatcherTest, SetExplicitCapture) {
- ServerWindow* root = root_window();
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- EventDispatcher* dispatcher = event_dispatcher();
-
- {
- // Send all pointer events to the child.
- dispatcher->SetCaptureWindow(child.get(), kClientAreaId);
-
- // The mouse press should go to the child even though its outside its
- // bounds.
- const ui::PointerEvent left_press_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(5, 5), gfx::Point(5, 5),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(left_press_event);
-
- // Events should target child.
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
-
- ASSERT_TRUE(details);
- ASSERT_EQ(child.get(), details->window);
- EXPECT_TRUE(details->IsClientArea());
- EXPECT_TRUE(IsMouseButtonDown());
-
- // The mouse down state should update while capture is set.
- const ui::PointerEvent right_press_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(5, 5), gfx::Point(5, 5),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON,
- ui::EF_RIGHT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(right_press_event);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_TRUE(IsMouseButtonDown());
-
- // One button released should not clear mouse down
- const ui::PointerEvent left_release_event(ui::MouseEvent(
- ui::ET_MOUSE_RELEASED, gfx::Point(5, 5), gfx::Point(5, 5),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(left_release_event);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_TRUE(IsMouseButtonDown());
-
- // Touch Event while mouse is down should not affect state.
- const ui::PointerEvent touch_event(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(15, 15), 2, base::TimeTicks()));
- dispatcher->ProcessEvent(touch_event);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_TRUE(IsMouseButtonDown());
-
- // Move event should not affect down
- const ui::PointerEvent move_event(
- ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(15, 5), gfx::Point(15, 5),
- base::TimeTicks(), ui::EF_RIGHT_MOUSE_BUTTON,
- ui::EF_RIGHT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(move_event);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_TRUE(IsMouseButtonDown());
-
- // All mouse buttons up should clear mouse down.
- const ui::PointerEvent right_release_event(
- ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(5, 5),
- gfx::Point(5, 5), base::TimeTicks(),
- ui::EF_RIGHT_MOUSE_BUTTON, ui::EF_RIGHT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(right_release_event);
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(IsMouseButtonDown());
- }
-
- {
- // Releasing capture and sending the same event will go to the root.
- dispatcher->SetCaptureWindow(nullptr, kClientAreaId);
- const ui::PointerEvent press_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(5, 5), gfx::Point(5, 5),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(press_event);
-
- // Events should target the root.
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
-
- ASSERT_TRUE(details);
- ASSERT_EQ(root, details->window);
- }
-}
-
-// This test verifies that explicit capture overrides and resets implicit
-// capture.
-TEST_F(EventDispatcherTest, ExplicitCaptureOverridesImplicitCapture) {
- ServerWindow* root = root_window();
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- EventDispatcher* dispatcher = event_dispatcher();
-
- // Run some implicit capture tests.
- MouseEventTest tests[] = {
- // Send a mouse down event over child with a left mouse button
- {ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(20, 25),
- gfx::Point(20, 25), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON),
- child.get(), gfx::Point(20, 25), gfx::Point(10, 15)},
- // Capture should be activated. Let's send a mouse move outside the bounds
- // of the child and press the right mouse button too.
- {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50),
- gfx::Point(50, 50), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON, 0),
- child.get(), gfx::Point(50, 50), gfx::Point(40, 40)},
- // Release the left mouse button and verify that the mouse up event goes
- // to the child.
- {ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(50, 50),
- gfx::Point(50, 50), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON,
- ui::EF_RIGHT_MOUSE_BUTTON),
- child.get(), gfx::Point(50, 50), gfx::Point(40, 40)},
- // A mouse move at (50, 50) should still go to the child.
- {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50),
- gfx::Point(50, 50), base::TimeTicks(),
- ui::EF_LEFT_MOUSE_BUTTON, 0),
- child.get(), gfx::Point(50, 50), gfx::Point(40, 40)},
-
- };
- RunMouseEventTests(dispatcher, event_dispatcher_delegate, tests,
- arraysize(tests));
-
- // Add a second pointer target to the child.
- {
- const ui::PointerEvent touch_event(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks()));
- dispatcher->ProcessEvent(touch_event);
- }
-
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- EXPECT_EQ(child.get(), details->window);
-
- // Verify that no window has explicit capture and hence we did indeed do
- // implicit capture.
- ASSERT_EQ(nullptr, dispatcher->capture_window());
-
- // Give the root window explicit capture and verify input events over the
- // child go to the root instead.
- dispatcher->SetCaptureWindow(root, kNonclientAreaId);
-
- // The implicit target should receive a cancel event for each pointer target.
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- EXPECT_TRUE(event_dispatcher_delegate->has_queued_events());
- EXPECT_EQ(child.get(), details->window);
- EXPECT_EQ(ui::ET_POINTER_CANCELLED, details->event->type());
-
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- EXPECT_EQ(child.get(), details->window);
- EXPECT_EQ(ui::ET_POINTER_EXITED, details->event->type());
-
- const ui::PointerEvent press_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(15, 15), gfx::Point(15, 15),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(press_event);
-
- // Events should target the root.
- details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- ASSERT_EQ(root, details->window);
- ASSERT_TRUE(details->IsNonclientArea());
-}
-
-// Tests that setting capture does delete active pointer targets for the capture
-// window.
-TEST_F(EventDispatcherTest, CaptureUpdatesActivePointerTargets) {
- ServerWindow* root = root_window();
- root->SetBounds(gfx::Rect(0, 0, 100, 100));
-
- EventDispatcher* dispatcher = event_dispatcher();
- {
- const ui::PointerEvent press_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(5, 5), gfx::Point(5, 5),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- dispatcher->ProcessEvent(press_event);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- ASSERT_EQ(root, details->window);
- }
- {
- const ui::PointerEvent touch_event(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks()));
- dispatcher->ProcessEvent(touch_event);
- }
-
- ASSERT_TRUE(AreAnyPointersDown());
- ASSERT_TRUE(IsWindowPointerTarget(root));
- EXPECT_EQ(2, NumberPointerTargetsForWindow(root));
-
- // Setting the capture should clear the implicit pointers for the specified
- // window.
- dispatcher->SetCaptureWindow(root, kNonclientAreaId);
- EXPECT_FALSE(AreAnyPointersDown());
- EXPECT_FALSE(IsWindowPointerTarget(root));
-}
-
-// Tests that when explicit capture is changed, that the previous window with
-// capture is no longer being observed.
-TEST_F(EventDispatcherTest, UpdatingCaptureStopsObservingPreviousCapture) {
- std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child1->SetBounds(gfx::Rect(10, 10, 20, 20));
- child2->SetBounds(gfx::Rect(50, 51, 11, 12));
-
- EventDispatcher* dispatcher = event_dispatcher();
- ASSERT_FALSE(AreAnyPointersDown());
- ASSERT_FALSE(IsWindowPointerTarget(child1.get()));
- ASSERT_FALSE(IsWindowPointerTarget(child2.get()));
- dispatcher->SetCaptureWindow(child1.get(), kClientAreaId);
- dispatcher->SetCaptureWindow(child2.get(), kClientAreaId);
- EXPECT_EQ(child1.get(),
- test_event_dispatcher_delegate()->lost_capture_window());
-
- // If observing does not stop during the capture update this crashes.
- child1->AddObserver(dispatcher);
-}
-
-// Tests that destroying a window with explicit capture clears the capture
-// state.
-TEST_F(EventDispatcherTest, DestroyingCaptureWindowRemovesExplicitCapture) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- EventDispatcher* dispatcher = event_dispatcher();
- dispatcher->SetCaptureWindow(child.get(), kClientAreaId);
- EXPECT_EQ(child.get(), dispatcher->capture_window());
-
- ServerWindow* lost_capture_window = child.get();
- child.reset();
- EXPECT_EQ(nullptr, dispatcher->capture_window());
- EXPECT_EQ(lost_capture_window,
- test_event_dispatcher_delegate()->lost_capture_window());
-}
-
-// Tests that when |client_id| is set for a window performing capture, that this
-// preference is used regardless of whether an event targets the client region.
-TEST_F(EventDispatcherTest, CaptureInNonClientAreaOverridesActualPoint) {
- ServerWindow* root = root_window();
- root->SetBounds(gfx::Rect(0, 0, 100, 100));
-
- root->SetClientArea(gfx::Insets(5, 5, 5, 5), std::vector<gfx::Rect>());
- EventDispatcher* dispatcher = event_dispatcher();
- dispatcher->SetCaptureWindow(root, kNonclientAreaId);
-
- TestEventDispatcherDelegate* event_dispatcher_delegate =
- test_event_dispatcher_delegate();
- // Press in the client area, it should be marked as non client.
- const ui::PointerEvent press_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(6, 6), gfx::Point(6, 6),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(press_event);
-
- // Events should target child and be in the client area.
- std::unique_ptr<DispatchedEventDetails> details =
- event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
- EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
- ASSERT_EQ(root, details->window);
- EXPECT_TRUE(details->IsNonclientArea());
-}
-
-TEST_F(EventDispatcherTest, ProcessPointerEvents) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- {
- const ui::PointerEvent pointer_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), gfx::Point(20, 25),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(pointer_event);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- ASSERT_EQ(child.get(), details->window);
-
- ASSERT_TRUE(details->event);
- ASSERT_TRUE(details->event->IsPointerEvent());
-
- ui::PointerEvent* dispatched_event = details->event->AsPointerEvent();
- EXPECT_EQ(gfx::Point(20, 25), dispatched_event->root_location());
- EXPECT_EQ(gfx::Point(10, 15), dispatched_event->location());
- }
-
- {
- const int touch_id = 3;
- const ui::PointerEvent pointer_event(
- ui::TouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(25, 20), touch_id,
- base::TimeTicks()));
- event_dispatcher()->ProcessEvent(pointer_event);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- ASSERT_EQ(child.get(), details->window);
-
- ASSERT_TRUE(details->event);
- ASSERT_TRUE(details->event->IsPointerEvent());
-
- ui::PointerEvent* dispatched_event = details->event->AsPointerEvent();
- EXPECT_EQ(gfx::Point(25, 20), dispatched_event->root_location());
- EXPECT_EQ(gfx::Point(15, 10), dispatched_event->location());
- EXPECT_EQ(touch_id, dispatched_event->pointer_id());
- }
-}
-
-TEST_F(EventDispatcherTest, ResetClearsPointerDown) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- child->SetBounds(gfx::Rect(10, 10, 20, 20));
-
- // Send event that is over child.
- const ui::PointerEvent ui_event(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), gfx::Point(20, 25),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(ui_event);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- ASSERT_EQ(child.get(), details->window);
-
- EXPECT_TRUE(AreAnyPointersDown());
-
- event_dispatcher()->Reset();
- EXPECT_FALSE(test_event_dispatcher_delegate()->has_queued_events());
- EXPECT_FALSE(AreAnyPointersDown());
-}
-
-TEST_F(EventDispatcherTest, ResetClearsCapture) {
- ServerWindow* root = root_window();
- root->SetBounds(gfx::Rect(0, 0, 100, 100));
-
- root->SetClientArea(gfx::Insets(5, 5, 5, 5), std::vector<gfx::Rect>());
- EventDispatcher* dispatcher = event_dispatcher();
- dispatcher->SetCaptureWindow(root, kNonclientAreaId);
-
- event_dispatcher()->Reset();
- EXPECT_FALSE(test_event_dispatcher_delegate()->has_queued_events());
- EXPECT_EQ(nullptr, event_dispatcher()->capture_window());
-}
-
-// Tests that events on a modal parent target the modal child.
-TEST_F(EventDispatcherTest, ModalWindowEventOnModalParent) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
-
- w1->AddTransientWindow(w2.get());
- w2->SetModal();
-
- // Send event that is over |w1|.
- const ui::PointerEvent mouse_pressed(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(15, 15), gfx::Point(15, 15),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(mouse_pressed);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- EXPECT_EQ(w2.get(), details->window);
- EXPECT_TRUE(details->IsNonclientArea());
-
- ASSERT_TRUE(details->event);
- ASSERT_TRUE(details->event->IsPointerEvent());
-
- ui::PointerEvent* dispatched_event = details->event->AsPointerEvent();
- EXPECT_EQ(gfx::Point(15, 15), dispatched_event->root_location());
- EXPECT_EQ(gfx::Point(-35, 5), dispatched_event->location());
-}
-
-// Tests that events on a modal child target the modal child itself.
-TEST_F(EventDispatcherTest, ModalWindowEventOnModalChild) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
-
- w1->AddTransientWindow(w2.get());
- w2->SetModal();
-
- // Send event that is over |w2|.
- const ui::PointerEvent mouse_pressed(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(55, 15), gfx::Point(55, 15),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(mouse_pressed);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- EXPECT_EQ(w2.get(), details->window);
- EXPECT_TRUE(details->IsClientArea());
-
- ASSERT_TRUE(details->event);
- ASSERT_TRUE(details->event->IsPointerEvent());
-
- ui::PointerEvent* dispatched_event = details->event->AsPointerEvent();
- EXPECT_EQ(gfx::Point(55, 15), dispatched_event->root_location());
- EXPECT_EQ(gfx::Point(5, 5), dispatched_event->location());
-}
-
-// Tests that events on an unrelated window are not affected by the modal
-// window.
-TEST_F(EventDispatcherTest, ModalWindowEventOnUnrelatedWindow) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
- std::unique_ptr<ServerWindow> w3 = CreateChildWindow(WindowId(1, 6));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
- w3->SetBounds(gfx::Rect(70, 10, 10, 10));
-
- w1->AddTransientWindow(w2.get());
- w2->SetModal();
-
- // Send event that is over |w3|.
- const ui::PointerEvent mouse_pressed(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(75, 15), gfx::Point(75, 15),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(mouse_pressed);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- EXPECT_EQ(w3.get(), details->window);
- EXPECT_TRUE(details->IsClientArea());
-
- ASSERT_TRUE(details->event);
- ASSERT_TRUE(details->event->IsPointerEvent());
-
- ui::PointerEvent* dispatched_event = details->event->AsPointerEvent();
- EXPECT_EQ(gfx::Point(75, 15), dispatched_event->root_location());
- EXPECT_EQ(gfx::Point(5, 5), dispatched_event->location());
-}
-
-// Tests that events events on a descendant of a modal parent target the modal
-// child.
-TEST_F(EventDispatcherTest, ModalWindowEventOnDescendantOfModalParent) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w11 =
- CreateChildWindowWithParent(WindowId(1, 4), w1.get());
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w11->SetBounds(gfx::Rect(10, 10, 10, 10));
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
-
- w1->AddTransientWindow(w2.get());
- w2->SetModal();
-
- // Send event that is over |w11|.
- const ui::PointerEvent mouse_pressed(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(25, 25), gfx::Point(25, 25),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(mouse_pressed);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- EXPECT_EQ(w2.get(), details->window);
- EXPECT_TRUE(details->IsNonclientArea());
-
- ASSERT_TRUE(details->event);
- ASSERT_TRUE(details->event->IsPointerEvent());
-
- ui::PointerEvent* dispatched_event = details->event->AsPointerEvent();
- EXPECT_EQ(gfx::Point(25, 25), dispatched_event->root_location());
- EXPECT_EQ(gfx::Point(-25, 15), dispatched_event->location());
-}
-
-// Tests that events on a system modal window target the modal window itself.
-TEST_F(EventDispatcherTest, ModalWindowEventOnSystemModal) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w1->SetModal();
-
- // Send event that is over |w1|.
- const ui::PointerEvent mouse_pressed(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(15, 15), gfx::Point(15, 15),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(mouse_pressed);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- EXPECT_EQ(w1.get(), details->window);
- EXPECT_TRUE(details->IsClientArea());
-
- ASSERT_TRUE(details->event);
- ASSERT_TRUE(details->event->IsPointerEvent());
-
- ui::PointerEvent* dispatched_event = details->event->AsPointerEvent();
- EXPECT_EQ(gfx::Point(15, 15), dispatched_event->root_location());
- EXPECT_EQ(gfx::Point(5, 5), dispatched_event->location());
-}
-
-// Tests that events outside of system modal window target the modal window.
-TEST_F(EventDispatcherTest, ModalWindowEventOutsideSystemModal) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w1->SetModal();
- event_dispatcher()->AddSystemModalWindow(w1.get());
-
- // Send event that is over |w1|.
- const ui::PointerEvent mouse_pressed(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(45, 15), gfx::Point(45, 15),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(mouse_pressed);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- EXPECT_EQ(w1.get(), details->window);
- EXPECT_TRUE(details->IsNonclientArea());
-
- ASSERT_TRUE(details->event);
- ASSERT_TRUE(details->event->IsPointerEvent());
-
- ui::PointerEvent* dispatched_event = details->event->AsPointerEvent();
- EXPECT_EQ(gfx::Point(45, 15), dispatched_event->root_location());
- EXPECT_EQ(gfx::Point(35, 5), dispatched_event->location());
-}
-
-// Tests that setting capture to a descendant of a modal parent fails.
-TEST_F(EventDispatcherTest, ModalWindowSetCaptureDescendantOfModalParent) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w11 =
- CreateChildWindowWithParent(WindowId(1, 4), w1.get());
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w11->SetBounds(gfx::Rect(10, 10, 10, 10));
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
-
- w1->AddTransientWindow(w2.get());
- w2->SetModal();
-
- EXPECT_FALSE(event_dispatcher()->SetCaptureWindow(w11.get(), kClientAreaId));
- EXPECT_EQ(nullptr, event_dispatcher()->capture_window());
-}
-
-// Tests that setting capture to a window unrelated to a modal parent works.
-TEST_F(EventDispatcherTest, ModalWindowSetCaptureUnrelatedWindow) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 4));
- std::unique_ptr<ServerWindow> w3 = CreateChildWindow(WindowId(1, 5));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
- w3->SetBounds(gfx::Rect(70, 10, 10, 10));
-
- w1->AddTransientWindow(w2.get());
- w2->SetModal();
-
- EXPECT_TRUE(event_dispatcher()->SetCaptureWindow(w3.get(), kClientAreaId));
- EXPECT_EQ(w3.get(), event_dispatcher()->capture_window());
-}
-
-// Tests that setting capture fails when there is a system modal window.
-TEST_F(EventDispatcherTest, ModalWindowSystemSetCapture) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 4));
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
-
- event_dispatcher()->AddSystemModalWindow(w2.get());
-
- EXPECT_FALSE(event_dispatcher()->SetCaptureWindow(w1.get(), kClientAreaId));
- EXPECT_EQ(nullptr, event_dispatcher()->capture_window());
-}
-
-// Tests having multiple system modal windows.
-TEST_F(EventDispatcherTest, ModalWindowMultipleSystemModals) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 4));
- std::unique_ptr<ServerWindow> w3 = CreateChildWindow(WindowId(1, 5));
-
- w2->SetVisible(false);
-
- // In the beginning, there should be no active system modal window.
- EXPECT_EQ(nullptr, GetActiveSystemModalWindow());
-
- // Add a visible system modal window. It should become the active one.
- event_dispatcher()->AddSystemModalWindow(w1.get());
- EXPECT_EQ(w1.get(), GetActiveSystemModalWindow());
-
- // Add an invisible system modal window. It should not change the active one.
- event_dispatcher()->AddSystemModalWindow(w2.get());
- EXPECT_EQ(w1.get(), GetActiveSystemModalWindow());
-
- // Add another visible system modal window. It should become the active one.
- event_dispatcher()->AddSystemModalWindow(w3.get());
- EXPECT_EQ(w3.get(), GetActiveSystemModalWindow());
-
- // Make an existing system modal window visible. It should become the active
- // one.
- w2->SetVisible(true);
- EXPECT_EQ(w2.get(), GetActiveSystemModalWindow());
-
- // Remove the active system modal window. Next one should become active.
- w2.reset();
- EXPECT_EQ(w3.get(), GetActiveSystemModalWindow());
-
- // Remove an inactive system modal window. It should not change the active
- // one.
- w1.reset();
- EXPECT_EQ(w3.get(), GetActiveSystemModalWindow());
-
- // Remove the last remaining system modal window. There should be no active
- // one anymore.
- w3.reset();
- EXPECT_EQ(nullptr, GetActiveSystemModalWindow());
-}
-
-TEST_F(EventDispatcherTest, CaptureNotResetOnParentChange) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- DisableHitTest(w1.get());
- std::unique_ptr<ServerWindow> w11 =
- CreateChildWindowWithParent(WindowId(1, 4), w1.get());
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
- DisableHitTest(w2.get());
-
- root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->SetBounds(gfx::Rect(0, 0, 100, 100));
- w11->SetBounds(gfx::Rect(10, 10, 10, 10));
- w2->SetBounds(gfx::Rect(0, 0, 100, 100));
-
- // Send event that is over |w11|.
- const ui::PointerEvent mouse_pressed(ui::MouseEvent(
- ui::ET_MOUSE_PRESSED, gfx::Point(15, 15), gfx::Point(15, 15),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
- event_dispatcher()->ProcessEvent(mouse_pressed);
- event_dispatcher()->SetCaptureWindow(w11.get(), kClientAreaId);
-
- std::unique_ptr<DispatchedEventDetails> details =
- test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
- ASSERT_TRUE(details);
- EXPECT_EQ(w11.get(), details->window);
- EXPECT_TRUE(details->IsClientArea());
-
- // Move |w11| to |w2| and verify the mouse is still down, and |w11| has
- // capture.
- w2->Add(w11.get());
- EXPECT_TRUE(IsMouseButtonDown());
- EXPECT_EQ(w11.get(),
- EventDispatcherTestApi(event_dispatcher()).capture_window());
-}
-
-TEST_F(EventDispatcherTest, ChangeCaptureFromClientToNonclient) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
- event_dispatcher()->SetCaptureWindow(child.get(), kNonclientAreaId);
- EXPECT_EQ(kNonclientAreaId,
- event_dispatcher()->capture_window_client_id());
- EXPECT_EQ(nullptr, test_event_dispatcher_delegate()->lost_capture_window());
- event_dispatcher()->SetCaptureWindow(child.get(), kClientAreaId);
- // Changing capture from client to non-client should notify the delegate.
- // The delegate can decide if it really wants to forward the event or not.
- EXPECT_EQ(child.get(),
- test_event_dispatcher_delegate()->lost_capture_window());
- EXPECT_EQ(child.get(), event_dispatcher()->capture_window());
- EXPECT_EQ(kClientAreaId, event_dispatcher()->capture_window_client_id());
-}
-
-} // namespace test
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/event_matcher.cc b/chromium/components/mus/ws/event_matcher.cc
deleted file mode 100644
index da45554d2ea..00000000000
--- a/chromium/components/mus/ws/event_matcher.cc
+++ /dev/null
@@ -1,113 +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 "components/mus/ws/event_matcher.h"
-
-namespace mus {
-namespace ws {
-
-EventMatcher::EventMatcher(const mojom::EventMatcher& matcher)
- : fields_to_match_(NONE),
- event_type_(ui::ET_UNKNOWN),
- event_flags_(ui::EF_NONE),
- ignore_event_flags_(ui::EF_NONE),
- keyboard_code_(ui::VKEY_UNKNOWN),
- pointer_type_(ui::EventPointerType::POINTER_TYPE_UNKNOWN) {
- if (matcher.type_matcher) {
- fields_to_match_ |= TYPE;
- switch (matcher.type_matcher->type) {
- case ui::mojom::EventType::POINTER_DOWN:
- event_type_ = ui::ET_POINTER_DOWN;
- break;
- case ui::mojom::EventType::POINTER_MOVE:
- event_type_ = ui::ET_POINTER_MOVED;
- break;
- case ui::mojom::EventType::MOUSE_EXIT:
- event_type_ = ui::ET_POINTER_EXITED;
- break;
- case ui::mojom::EventType::POINTER_UP:
- event_type_ = ui::ET_POINTER_UP;
- break;
- case ui::mojom::EventType::POINTER_CANCEL:
- event_type_ = ui::ET_POINTER_CANCELLED;
- break;
- case ui::mojom::EventType::KEY_PRESSED:
- event_type_ = ui::ET_KEY_PRESSED;
- break;
- case ui::mojom::EventType::KEY_RELEASED:
- event_type_ = ui::ET_KEY_RELEASED;
- break;
- default:
- NOTREACHED();
- }
- }
- if (matcher.flags_matcher) {
- fields_to_match_ |= FLAGS;
- event_flags_ = matcher.flags_matcher->flags;
- if (matcher.ignore_flags_matcher)
- ignore_event_flags_ = matcher.ignore_flags_matcher->flags;
- }
- if (matcher.key_matcher) {
- fields_to_match_ |= KEYBOARD_CODE;
- keyboard_code_ = static_cast<uint16_t>(matcher.key_matcher->keyboard_code);
- }
- if (matcher.pointer_kind_matcher) {
- fields_to_match_ |= POINTER_KIND;
- switch (matcher.pointer_kind_matcher->pointer_kind) {
- case ui::mojom::PointerKind::MOUSE:
- pointer_type_ = ui::EventPointerType::POINTER_TYPE_MOUSE;
- break;
- case ui::mojom::PointerKind::TOUCH:
- pointer_type_ = ui::EventPointerType::POINTER_TYPE_TOUCH;
- break;
- default:
- NOTREACHED();
- }
- }
- if (matcher.pointer_location_matcher) {
- fields_to_match_ |= POINTER_LOCATION;
- pointer_region_ = matcher.pointer_location_matcher->region;
- }
-}
-
-EventMatcher::~EventMatcher() {}
-
-bool EventMatcher::MatchesEvent(const ui::Event& event) const {
- if ((fields_to_match_ & TYPE) && event.type() != event_type_)
- return false;
- int flags = event.flags() & ~ignore_event_flags_;
- if ((fields_to_match_ & FLAGS) && flags != event_flags_)
- return false;
- if (fields_to_match_ & KEYBOARD_CODE) {
- if (!event.IsKeyEvent())
- return false;
- if (keyboard_code_ != event.AsKeyEvent()->GetConflatedWindowsKeyCode())
- return false;
- }
- if (fields_to_match_ & POINTER_KIND) {
- if (!event.IsPointerEvent() ||
- pointer_type_ != event.AsPointerEvent()->pointer_details().pointer_type)
- return false;
- }
- if (fields_to_match_ & POINTER_LOCATION) {
- // TODO(sad): The tricky part here is to make sure the same coord-space is
- // used for the location-region and the event-location.
- NOTIMPLEMENTED();
- return false;
- }
- return true;
-}
-
-bool EventMatcher::Equals(const EventMatcher& other) const {
- return fields_to_match_ == other.fields_to_match_ &&
- event_type_ == other.event_type_ &&
- event_flags_ == other.event_flags_ &&
- ignore_event_flags_ == other.ignore_event_flags_ &&
- keyboard_code_ == other.keyboard_code_ &&
- pointer_type_ == other.pointer_type_ &&
- pointer_region_ == other.pointer_region_;
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/event_matcher.h b/chromium/components/mus/ws/event_matcher.h
deleted file mode 100644
index ec9231b57a4..00000000000
--- a/chromium/components/mus/ws/event_matcher.h
+++ /dev/null
@@ -1,56 +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 COMPONENTS_MUS_WS_EVENT_MATCHER_H_
-#define COMPONENTS_MUS_WS_EVENT_MATCHER_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "components/mus/public/interfaces/event_matcher.mojom.h"
-#include "ui/events/event.h"
-#include "ui/events/mojo/event_constants.mojom.h"
-#include "ui/events/mojo/keyboard_codes.mojom.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace mus {
-namespace ws {
-
-// Wraps a mojom::EventMatcher and allows events to be tested against it.
-class EventMatcher {
- public:
- explicit EventMatcher(const mojom::EventMatcher& matcher);
- ~EventMatcher();
-
- bool MatchesEvent(const ui::Event& event) const;
-
- bool Equals(const EventMatcher& other) const;
-
- private:
- enum MatchFields {
- NONE = 0,
- TYPE = 1 << 0,
- FLAGS = 1 << 1,
- KEYBOARD_CODE = 1 << 2,
- POINTER_KIND = 1 << 3,
- POINTER_LOCATION = 1 << 4,
- };
-
- uint32_t fields_to_match_;
- ui::EventType event_type_;
- // Bitfields of kEventFlag* and kMouseEventFlag* values in
- // input_event_constants.mojom.
- int event_flags_;
- int ignore_event_flags_;
- uint16_t keyboard_code_;
- ui::EventPointerType pointer_type_;
- gfx::RectF pointer_region_;
-
- DISALLOW_COPY_AND_ASSIGN(EventMatcher);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_EVENT_MATCHER_H_
diff --git a/chromium/components/mus/ws/event_matcher_unittest.cc b/chromium/components/mus/ws/event_matcher_unittest.cc
deleted file mode 100644
index 04c011fb459..00000000000
--- a/chromium/components/mus/ws/event_matcher_unittest.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/mus/ws/event_matcher.h"
-
-#include "base/time/time.h"
-#include "components/mus/public/interfaces/event_matcher.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event.h"
-#include "ui/events/mojo/event_constants.mojom.h"
-#include "ui/gfx/geometry/point.h"
-
-namespace mus {
-namespace ws {
-
-// NOTE: Most of the matching functionality is exercised by tests of Accelerator
-// handling in the EventDispatcher and WindowTree tests. These are just basic
-// sanity checks.
-
-using EventTesterTest = testing::Test;
-
-TEST_F(EventTesterTest, MatchesEventByType) {
- mojom::EventMatcherPtr matcher = mojom::EventMatcher::New();
- matcher->type_matcher = mojom::EventTypeMatcher::New();
- matcher->type_matcher->type = ui::mojom::EventType::POINTER_DOWN;
- EventMatcher pointer_down_matcher(*matcher);
-
- ui::PointerEvent pointer_down(
- ui::TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(), 1, base::TimeTicks()));
- EXPECT_TRUE(pointer_down_matcher.MatchesEvent(pointer_down));
-
- ui::PointerEvent pointer_up(ui::TouchEvent(
- ui::ET_TOUCH_RELEASED, gfx::Point(), 1, base::TimeTicks()));
- EXPECT_FALSE(pointer_down_matcher.MatchesEvent(pointer_up));
-}
-
-TEST_F(EventTesterTest, MatchesEventByKeyCode) {
- mojom::EventMatcherPtr matcher(mojom::EventMatcher::New());
- matcher->type_matcher = mojom::EventTypeMatcher::New();
- matcher->type_matcher->type = ui::mojom::EventType::KEY_PRESSED;
- matcher->key_matcher = mojom::KeyEventMatcher::New();
- matcher->key_matcher->keyboard_code = ui::mojom::KeyboardCode::Z;
- EventMatcher z_matcher(*matcher);
-
- ui::KeyEvent z_key(ui::ET_KEY_PRESSED, ui::VKEY_Z, ui::EF_NONE);
- EXPECT_TRUE(z_matcher.MatchesEvent(z_key));
-
- ui::KeyEvent y_key(ui::ET_KEY_PRESSED, ui::VKEY_Y, ui::EF_NONE);
- EXPECT_FALSE(z_matcher.MatchesEvent(y_key));
-}
-
-TEST_F(EventTesterTest, MatchesEventByKeyFlags) {
- mojom::EventMatcherPtr matcher(mojom::EventMatcher::New());
- matcher->type_matcher = mojom::EventTypeMatcher::New();
- matcher->type_matcher->type = ui::mojom::EventType::KEY_PRESSED;
- matcher->flags_matcher = mojom::EventFlagsMatcher::New();
- matcher->flags_matcher->flags = ui::mojom::kEventFlagControlDown;
- matcher->key_matcher = mojom::KeyEventMatcher::New();
- matcher->key_matcher->keyboard_code = ui::mojom::KeyboardCode::N;
- EventMatcher control_n_matcher(*matcher);
-
- ui::KeyEvent control_n(ui::ET_KEY_PRESSED, ui::VKEY_N, ui::EF_CONTROL_DOWN);
- EXPECT_TRUE(control_n_matcher.MatchesEvent(control_n));
-
- ui::KeyEvent shift_n(ui::ET_KEY_PRESSED, ui::VKEY_N, ui::EF_SHIFT_DOWN);
- EXPECT_FALSE(control_n_matcher.MatchesEvent(shift_n));
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/focus_controller.cc b/chromium/components/mus/ws/focus_controller.cc
deleted file mode 100644
index 5728acbe154..00000000000
--- a/chromium/components/mus/ws/focus_controller.cc
+++ /dev/null
@@ -1,311 +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 "components/mus/ws/focus_controller.h"
-
-#include "base/macros.h"
-#include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "components/mus/ws/focus_controller_delegate.h"
-#include "components/mus/ws/focus_controller_observer.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_drawn_tracker.h"
-
-namespace mus {
-namespace ws {
-
-namespace {
-
-ServerWindow* GetDeepestLastDescendant(ServerWindow* window) {
- while (!window->children().empty())
- window = window->children().back();
- return window;
-}
-
-// This can be used to iterate over each node in a rooted tree for the purpose
-// of shifting focus/activation.
-class WindowTreeIterator {
- public:
- explicit WindowTreeIterator(ServerWindow* root) : root_(root) {}
- ~WindowTreeIterator() {}
-
- ServerWindow* GetNext(ServerWindow* window) const {
- if (window == root_ || window == nullptr)
- return GetDeepestLastDescendant(root_);
-
- // Return the next sibling.
- ServerWindow* parent = window->parent();
- if (parent) {
- const ServerWindow::Windows& siblings = parent->children();
- ServerWindow::Windows::const_reverse_iterator iter =
- std::find(siblings.rbegin(), siblings.rend(), window);
- DCHECK(iter != siblings.rend());
- ++iter;
- if (iter != siblings.rend())
- return GetDeepestLastDescendant(*iter);
- }
-
- // All children and siblings have been explored. Next is the parent.
- return parent;
- }
-
- private:
- ServerWindow* root_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTreeIterator);
-};
-
-} // namespace
-
-FocusController::FocusController(FocusControllerDelegate* delegate,
- ServerWindow* root)
- : delegate_(delegate),
- root_(root),
- focused_window_(nullptr),
- active_window_(nullptr),
- activation_reason_(ActivationChangeReason::UNKNONW) {
- DCHECK(delegate_);
- DCHECK(root_);
-}
-
-FocusController::~FocusController() {
-}
-
-bool FocusController::SetFocusedWindow(ServerWindow* window) {
- if (GetFocusedWindow() == window)
- return true;
-
- return SetFocusedWindowImpl(FocusControllerChangeSource::EXPLICIT, window);
-}
-
-ServerWindow* FocusController::GetFocusedWindow() {
- return focused_window_;
-}
-
-void FocusController::ActivateNextWindow() {
- WindowTreeIterator iter(root_);
- ServerWindow* activate = active_window_;
- while (true) {
- activate = iter.GetNext(activate);
- if (activation_reason_ == ActivationChangeReason::CYCLE) {
- if (activate == active_window_) {
- // We have cycled over all the activatable windows. Remove the oldest
- // window that was cycled.
- if (!cycle_windows_->windows().empty()) {
- cycle_windows_->Remove(cycle_windows_->windows().front());
- continue;
- }
- } else if (cycle_windows_->Contains(activate)) {
- // We are cycling between activated windows, and this window has already
- // been through the cycle. So skip over it.
- continue;
- }
- }
- if (activate == active_window_ || CanBeActivated(activate))
- break;
- }
- SetActiveWindow(activate, ActivationChangeReason::CYCLE);
-
- if (active_window_) {
- // Do not shift focus if the focused window already lives in the active
- // window.
- if (focused_window_ && active_window_->Contains(focused_window_))
- return;
- // Focus the first focusable window in the tree.
- WindowTreeIterator iter(active_window_);
- ServerWindow* focus = nullptr;
- do {
- focus = iter.GetNext(focus);
- } while (focus != active_window_ && !CanBeFocused(focus));
- SetFocusedWindow(focus);
- } else {
- SetFocusedWindow(nullptr);
- }
-}
-
-void FocusController::AddObserver(FocusControllerObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void FocusController::RemoveObserver(FocusControllerObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void FocusController::SetActiveWindow(ServerWindow* window,
- ActivationChangeReason reason) {
- DCHECK(!window || CanBeActivated(window));
- if (active_window_ == window)
- return;
- if (reason != ActivationChangeReason::CYCLE) {
- cycle_windows_.reset();
- } else if (activation_reason_ != ActivationChangeReason::CYCLE) {
- DCHECK(!cycle_windows_);
- cycle_windows_.reset(new ServerWindowTracker());
- if (active_window_)
- cycle_windows_->Add(active_window_);
- }
-
- ServerWindow* old_active = active_window_;
- active_window_ = window;
- activation_reason_ = reason;
- FOR_EACH_OBSERVER(FocusControllerObserver, observers_,
- OnActivationChanged(old_active, active_window_));
- if (active_window_ && activation_reason_ == ActivationChangeReason::CYCLE)
- cycle_windows_->Add(active_window_);
-}
-
-bool FocusController::CanBeFocused(ServerWindow* window) const {
- // All ancestors of |window| must be drawn, and be focusable.
- for (ServerWindow* w = window; w; w = w->parent()) {
- if (!w->IsDrawn())
- return false;
- if (!w->can_focus())
- return false;
- }
-
- // |window| must be a descendent of an activatable window.
- return GetActivatableAncestorOf(window) != nullptr;
-}
-
-bool FocusController::CanBeActivated(ServerWindow* window) const {
- DCHECK(window);
- // A detached window cannot be activated.
- if (!root_->Contains(window))
- return false;
-
- // The parent window must be allowed to have active children.
- if (!delegate_->CanHaveActiveChildren(window->parent()))
- return false;
-
- if (!window->can_focus())
- return false;
-
- // The window must be drawn, or if it's not drawn, it must be minimized.
- if (!window->IsDrawn()) {
- bool is_minimized = false;
- const ServerWindow::Properties& props = window->properties();
- if (props.count(mojom::WindowManager::kShowState_Property)) {
- is_minimized =
- props.find(mojom::WindowManager::kShowState_Property)->second[0] ==
- static_cast<int>(mus::mojom::ShowState::MINIMIZED);
- }
- if (!is_minimized)
- return false;
- }
-
- // TODO(sad): If there's a transient modal window, then this cannot be
- // activated.
- return true;
-}
-
-ServerWindow* FocusController::GetActivatableAncestorOf(
- ServerWindow* window) const {
- for (ServerWindow* w = window; w; w = w->parent()) {
- if (CanBeActivated(w))
- return w;
- }
- return nullptr;
-}
-
-bool FocusController::SetFocusedWindowImpl(
- FocusControllerChangeSource change_source,
- ServerWindow* window) {
- if (window && !CanBeFocused(window))
- return false;
-
- ServerWindow* old_focused = GetFocusedWindow();
-
- DCHECK(!window || window->IsDrawn());
-
- // Activate the closest activatable ancestor window.
- // TODO(sad): The window to activate doesn't necessarily have to be a direct
- // ancestor (e.g. could be a transient parent).
- SetActiveWindow(GetActivatableAncestorOf(window),
- ActivationChangeReason::FOCUS);
-
- FOR_EACH_OBSERVER(FocusControllerObserver, observers_,
- OnFocusChanged(change_source, old_focused, window));
-
- focused_window_ = window;
- // We can currently use only a single ServerWindowDrawnTracker since focused
- // window is expected to be a direct descendant of the active window.
- if (focused_window_ && active_window_) {
- DCHECK(active_window_->Contains(focused_window_));
- }
- ServerWindow* track_window = focused_window_;
- if (!track_window)
- track_window = active_window_;
- if (track_window)
- drawn_tracker_.reset(new ServerWindowDrawnTracker(track_window, this));
- else
- drawn_tracker_.reset();
- return true;
-}
-
-void FocusController::OnDrawnStateWillChange(ServerWindow* ancestor,
- ServerWindow* window,
- bool is_drawn) {
- DCHECK(!is_drawn);
- DCHECK_NE(ancestor, window);
- DCHECK(root_->Contains(window));
- drawn_tracker_.reset();
-
- // Find the window that triggered this state-change notification.
- ServerWindow* trigger = window;
- while (trigger->parent() != ancestor)
- trigger = trigger->parent();
- DCHECK(trigger);
- auto will_be_hidden = [trigger](ServerWindow* w) {
- return trigger->Contains(w);
- };
-
- // If |window| is |active_window_|, then activate the next activatable window
- // that does not belong to the subtree which is getting hidden.
- if (window == active_window_) {
- WindowTreeIterator iter(root_);
- ServerWindow* activate = active_window_;
- do {
- activate = iter.GetNext(activate);
- } while (activate != active_window_ &&
- (will_be_hidden(activate) || !CanBeActivated(activate)));
- if (activate == window)
- activate = nullptr;
- SetActiveWindow(activate, ActivationChangeReason::DRAWN_STATE_CHANGED);
-
- // Now make sure focus is in the active window.
- ServerWindow* focus = nullptr;
- if (active_window_) {
- WindowTreeIterator iter(active_window_);
- focus = nullptr;
- do {
- focus = iter.GetNext(focus);
- } while (focus != active_window_ &&
- (will_be_hidden(focus) || !CanBeFocused(focus)));
- DCHECK(focus && CanBeFocused(focus));
- }
- SetFocusedWindowImpl(FocusControllerChangeSource::DRAWN_STATE_CHANGED,
- focus);
- return;
- }
-
- // Move focus to the next focusable window in |active_window_|.
- DCHECK_EQ(focused_window_, window);
- WindowTreeIterator iter(active_window_);
- ServerWindow* focus = focused_window_;
- do {
- focus = iter.GetNext(focus);
- } while (focus != focused_window_ &&
- (will_be_hidden(focus) || !CanBeFocused(focus)));
- if (focus == window)
- focus = nullptr;
- SetFocusedWindowImpl(FocusControllerChangeSource::DRAWN_STATE_CHANGED, focus);
-}
-
-void FocusController::OnDrawnStateChanged(ServerWindow* ancestor,
- ServerWindow* window,
- bool is_drawn) {
- // DCHECK(false); TODO(sadrul):
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/focus_controller.h b/chromium/components/mus/ws/focus_controller.h
deleted file mode 100644
index 96a08609ad0..00000000000
--- a/chromium/components/mus/ws/focus_controller.h
+++ /dev/null
@@ -1,104 +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 COMPONENTS_MUS_WS_FOCUS_CONTROLLER_H_
-#define COMPONENTS_MUS_WS_FOCUS_CONTROLLER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/mus/ws/server_window_drawn_tracker_observer.h"
-#include "components/mus/ws/server_window_tracker.h"
-
-namespace mus {
-
-namespace ws {
-
-class FocusControllerDelegate;
-class FocusControllerObserver;
-class ServerWindow;
-class ServerWindowDrawnTracker;
-struct WindowId;
-
-// Describes the source of the change.
-enum class FocusControllerChangeSource {
- EXPLICIT,
- DRAWN_STATE_CHANGED,
-};
-
-// Tracks the focused window. Focus is moved to another window when the drawn
-// state of the focused window changes.
-class FocusController : public ServerWindowDrawnTrackerObserver {
- public:
- FocusController(FocusControllerDelegate* delegate, ServerWindow* root);
- ~FocusController() override;
-
- // Sets the focused window. Does nothing if |window| is currently focused.
- // This does not notify the delegate. See ServerWindow::SetFocusedWindow()
- // for details on return value.
- bool SetFocusedWindow(ServerWindow* window);
- ServerWindow* GetFocusedWindow();
-
- // Moves activation to the next activatable window.
- void ActivateNextWindow();
-
- void AddObserver(FocusControllerObserver* observer);
- void RemoveObserver(FocusControllerObserver* observer);
-
- private:
- enum class ActivationChangeReason {
- UNKNONW,
- CYCLE, // Activation changed because of ActivateNextWindow().
- FOCUS, // Focus change required a different window to be activated.
- DRAWN_STATE_CHANGED, // Active window was hidden or destroyed.
- };
- void SetActiveWindow(ServerWindow* window, ActivationChangeReason reason);
-
- // Returns whether |window| can be focused or activated.
- bool CanBeFocused(ServerWindow* window) const;
- bool CanBeActivated(ServerWindow* window) const;
-
- // Returns the closest activatable ancestor of |window|. Returns nullptr if
- // there is no such ancestor.
- ServerWindow* GetActivatableAncestorOf(ServerWindow* window) const;
-
- // Implementation of SetFocusedWindow().
- bool SetFocusedWindowImpl(FocusControllerChangeSource change_source,
- ServerWindow* window);
-
- // ServerWindowDrawnTrackerObserver:
- void OnDrawnStateWillChange(ServerWindow* ancestor,
- ServerWindow* window,
- bool is_drawn) override;
- void OnDrawnStateChanged(ServerWindow* ancestor,
- ServerWindow* window,
- bool is_drawn) override;
-
- FocusControllerDelegate* delegate_;
-
- ServerWindow* root_;
- ServerWindow* focused_window_;
- ServerWindow* active_window_;
- // Tracks what caused |active_window_| to be activated.
- ActivationChangeReason activation_reason_;
-
- // Keeps track of the list of windows that have already been visited during a
- // window cycle. This is only active when |activation_reason_| is set to
- // CYCLE.
- std::unique_ptr<ServerWindowTracker> cycle_windows_;
-
- base::ObserverList<FocusControllerObserver> observers_;
-
- // Keeps track of the visibility of the focused and active window.
- std::unique_ptr<ServerWindowDrawnTracker> drawn_tracker_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusController);
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_FOCUS_CONTROLLER_H_
diff --git a/chromium/components/mus/ws/focus_controller_delegate.h b/chromium/components/mus/ws/focus_controller_delegate.h
deleted file mode 100644
index 6eca41cabbb..00000000000
--- a/chromium/components/mus/ws/focus_controller_delegate.h
+++ /dev/null
@@ -1,26 +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 COMPONENTS_MUS_WS_FOCUS_CONTROLLER_DELEGATE_H_
-#define COMPONENTS_MUS_WS_FOCUS_CONTROLLER_DELEGATE_H_
-
-namespace mus {
-
-namespace ws {
-
-class ServerWindow;
-
-class FocusControllerDelegate {
- public:
- virtual bool CanHaveActiveChildren(ServerWindow* window) const = 0;
-
- protected:
- ~FocusControllerDelegate() {}
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_FOCUS_CONTROLLER_DELEGATE_H_
diff --git a/chromium/components/mus/ws/focus_controller_observer.h b/chromium/components/mus/ws/focus_controller_observer.h
deleted file mode 100644
index 8edbae18c35..00000000000
--- a/chromium/components/mus/ws/focus_controller_observer.h
+++ /dev/null
@@ -1,29 +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 COMPONENTS_MUS_WS_FOCUS_CONTROLLER_OBSERVER_H_
-#define COMPONENTS_MUS_WS_FOCUS_CONTROLLER_OBSERVER_H_
-
-namespace mus {
-namespace ws {
-
-enum class FocusControllerChangeSource;
-class ServerWindow;
-
-class FocusControllerObserver {
- public:
- virtual void OnActivationChanged(ServerWindow* old_active_window,
- ServerWindow* new_active_window) = 0;
- virtual void OnFocusChanged(FocusControllerChangeSource change_source,
- ServerWindow* old_focused_window,
- ServerWindow* new_focused_window) = 0;
-
- protected:
- ~FocusControllerObserver() {}
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_FOCUS_CONTROLLER_OBSERVER_H_
diff --git a/chromium/components/mus/ws/focus_controller_unittest.cc b/chromium/components/mus/ws/focus_controller_unittest.cc
deleted file mode 100644
index 563de06e875..00000000000
--- a/chromium/components/mus/ws/focus_controller_unittest.cc
+++ /dev/null
@@ -1,312 +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 "components/mus/ws/focus_controller.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "components/mus/ws/focus_controller_delegate.h"
-#include "components/mus/ws/focus_controller_observer.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mus {
-
-namespace ws {
-namespace {
-
-const char kDisallowActiveChildren[] = "disallow-active-children";
-
-class TestFocusControllerObserver : public FocusControllerObserver,
- public FocusControllerDelegate {
- public:
- TestFocusControllerObserver()
- : ignore_explicit_(true),
- focus_change_count_(0u),
- old_focused_window_(nullptr),
- new_focused_window_(nullptr),
- old_active_window_(nullptr),
- new_active_window_(nullptr) {}
-
- void ClearAll() {
- focus_change_count_ = 0u;
- old_focused_window_ = nullptr;
- new_focused_window_ = nullptr;
- old_active_window_ = nullptr;
- new_active_window_ = nullptr;
- }
- size_t focus_change_count() const { return focus_change_count_; }
- ServerWindow* old_focused_window() { return old_focused_window_; }
- ServerWindow* new_focused_window() { return new_focused_window_; }
-
- ServerWindow* old_active_window() { return old_active_window_; }
- ServerWindow* new_active_window() { return new_active_window_; }
-
- void set_ignore_explicit(bool ignore) { ignore_explicit_ = ignore; }
-
- private:
- // FocusControllerDelegate:
- bool CanHaveActiveChildren(ServerWindow* window) const override {
- return !window || window->properties().count(kDisallowActiveChildren) == 0;
- }
- // FocusControllerObserver:
- void OnActivationChanged(ServerWindow* old_active_window,
- ServerWindow* new_active_window) override {
- old_active_window_ = old_active_window;
- new_active_window_ = new_active_window;
- }
- void OnFocusChanged(FocusControllerChangeSource source,
- ServerWindow* old_focused_window,
- ServerWindow* new_focused_window) override {
- if (ignore_explicit_ && source == FocusControllerChangeSource::EXPLICIT)
- return;
-
- focus_change_count_++;
- old_focused_window_ = old_focused_window;
- new_focused_window_ = new_focused_window;
- }
-
- bool ignore_explicit_;
- size_t focus_change_count_;
- ServerWindow* old_focused_window_;
- ServerWindow* new_focused_window_;
- ServerWindow* old_active_window_;
- ServerWindow* new_active_window_;
-
- DISALLOW_COPY_AND_ASSIGN(TestFocusControllerObserver);
-};
-
-} // namespace
-
-TEST(FocusControllerTest, Basic) {
- TestServerWindowDelegate server_window_delegate;
- ServerWindow root(&server_window_delegate, WindowId());
- server_window_delegate.set_root_window(&root);
- root.SetVisible(true);
- ServerWindow child(&server_window_delegate, WindowId());
- child.SetVisible(true);
- root.Add(&child);
- ServerWindow child_child(&server_window_delegate, WindowId());
- child_child.SetVisible(true);
- child.Add(&child_child);
-
- TestFocusControllerObserver focus_observer;
- FocusController focus_controller(&focus_observer, &root);
- focus_controller.AddObserver(&focus_observer);
-
- focus_controller.SetFocusedWindow(&child_child);
- EXPECT_EQ(0u, focus_observer.focus_change_count());
-
- // Remove the ancestor of the focused window, focus should go to the |root|.
- root.Remove(&child);
- EXPECT_EQ(1u, focus_observer.focus_change_count());
- EXPECT_EQ(&root, focus_observer.new_focused_window());
- EXPECT_EQ(&child_child, focus_observer.old_focused_window());
- focus_observer.ClearAll();
-
- // Make the focused window invisible. Focus is lost in this case (as no one
- // to give focus to).
- root.SetVisible(false);
- EXPECT_EQ(1u, focus_observer.focus_change_count());
- EXPECT_EQ(nullptr, focus_observer.new_focused_window());
- EXPECT_EQ(&root, focus_observer.old_focused_window());
- focus_observer.ClearAll();
-
- // Go back to initial state and focus |child_child|.
- root.SetVisible(true);
- root.Add(&child);
- focus_controller.SetFocusedWindow(&child_child);
- EXPECT_EQ(0u, focus_observer.focus_change_count());
-
- // Hide the focused window, focus should go to parent.
- child_child.SetVisible(false);
- EXPECT_EQ(1u, focus_observer.focus_change_count());
- EXPECT_EQ(&child, focus_observer.new_focused_window());
- EXPECT_EQ(&child_child, focus_observer.old_focused_window());
- focus_observer.ClearAll();
-
- child_child.SetVisible(true);
- focus_controller.SetFocusedWindow(&child_child);
- EXPECT_EQ(0u, focus_observer.focus_change_count());
-
- // Hide the parent of the focused window.
- child.SetVisible(false);
- EXPECT_EQ(1u, focus_observer.focus_change_count());
- EXPECT_EQ(&root, focus_observer.new_focused_window());
- EXPECT_EQ(&child_child, focus_observer.old_focused_window());
- focus_observer.ClearAll();
- focus_controller.RemoveObserver(&focus_observer);
-}
-
-// Tests that focus shifts correctly if the focused window is destroyed.
-TEST(FocusControllerTest, FocusShiftsOnDestroy) {
- TestServerWindowDelegate server_window_delegate;
- ServerWindow parent(&server_window_delegate, WindowId());
- server_window_delegate.set_root_window(&parent);
- parent.SetVisible(true);
- ServerWindow child_first(&server_window_delegate, WindowId());
- child_first.SetVisible(true);
- parent.Add(&child_first);
- std::unique_ptr<ServerWindow> child_second(
- new ServerWindow(&server_window_delegate, WindowId()));
- child_second->SetVisible(true);
- parent.Add(child_second.get());
- std::vector<uint8_t> dummy;
- // Allow only |parent| to be activated.
- parent.SetProperty(kDisallowActiveChildren, &dummy);
-
- TestFocusControllerObserver focus_observer;
- focus_observer.set_ignore_explicit(false);
- FocusController focus_controller(&focus_observer, &parent);
- focus_controller.AddObserver(&focus_observer);
-
- focus_controller.ActivateNextWindow();
- EXPECT_EQ(nullptr, focus_observer.old_active_window());
- EXPECT_EQ(&parent, focus_observer.new_active_window());
- EXPECT_EQ(nullptr, focus_observer.old_focused_window());
- EXPECT_EQ(child_second.get(), focus_observer.new_focused_window());
- focus_observer.ClearAll();
-
- // Destroying |child_second| should move focus to |child_first|.
- child_second.reset();
- EXPECT_NE(nullptr, focus_observer.old_focused_window());
- EXPECT_EQ(&child_first, focus_observer.new_focused_window());
-
- focus_controller.RemoveObserver(&focus_observer);
-}
-
-TEST(FocusControllerTest, ActivationSkipsOverHiddenWindow) {
- TestServerWindowDelegate server_window_delegate;
- ServerWindow parent(&server_window_delegate, WindowId());
- server_window_delegate.set_root_window(&parent);
- parent.SetVisible(true);
-
- ServerWindow child_first(&server_window_delegate, WindowId());
- ServerWindow child_second(&server_window_delegate, WindowId());
- ServerWindow child_third(&server_window_delegate, WindowId());
-
- parent.Add(&child_first);
- parent.Add(&child_second);
- parent.Add(&child_third);
-
- child_first.SetVisible(true);
- child_second.SetVisible(false);
- child_third.SetVisible(true);
-
- TestFocusControllerObserver focus_observer;
- focus_observer.set_ignore_explicit(false);
- FocusController focus_controller(&focus_observer, &parent);
- focus_controller.AddObserver(&focus_observer);
-
- // Since |child_second| is invisible, activation should cycle from
- // |child_third|, to |child_first|, to |parent|, back to |child_third|.
- focus_controller.ActivateNextWindow();
- EXPECT_EQ(nullptr, focus_observer.old_active_window());
- EXPECT_EQ(&child_third, focus_observer.new_active_window());
- focus_observer.ClearAll();
-
- focus_controller.ActivateNextWindow();
- EXPECT_EQ(&child_third, focus_observer.old_active_window());
- EXPECT_EQ(&child_first, focus_observer.new_active_window());
- focus_observer.ClearAll();
-
- focus_controller.ActivateNextWindow();
- EXPECT_EQ(&child_first, focus_observer.old_active_window());
- EXPECT_EQ(&parent, focus_observer.new_active_window());
- focus_observer.ClearAll();
-
- focus_controller.ActivateNextWindow();
- EXPECT_EQ(&parent, focus_observer.old_active_window());
- EXPECT_EQ(&child_third, focus_observer.new_active_window());
- focus_observer.ClearAll();
-
- // Once |child_second| is made visible, activation should go from
- // |child_third| to |child_second|.
- child_second.SetVisible(true);
- focus_controller.ActivateNextWindow();
- EXPECT_EQ(&child_third, focus_observer.old_active_window());
- EXPECT_EQ(&child_second, focus_observer.new_active_window());
-}
-
-TEST(FocusControllerTest, ActivationSkipsOverHiddenContainers) {
- TestServerWindowDelegate server_window_delegate;
- ServerWindow parent(&server_window_delegate, WindowId());
- server_window_delegate.set_root_window(&parent);
- parent.SetVisible(true);
-
- ServerWindow child1(&server_window_delegate, WindowId());
- ServerWindow child2(&server_window_delegate, WindowId());
-
- parent.Add(&child1);
- parent.Add(&child2);
-
- child1.SetVisible(true);
- child2.SetVisible(true);
-
- ServerWindow child11(&server_window_delegate, WindowId());
- ServerWindow child12(&server_window_delegate, WindowId());
- ServerWindow child21(&server_window_delegate, WindowId());
- ServerWindow child22(&server_window_delegate, WindowId());
-
- child1.Add(&child11);
- child1.Add(&child12);
- child2.Add(&child21);
- child2.Add(&child22);
-
- child11.SetVisible(true);
- child12.SetVisible(true);
- child21.SetVisible(true);
- child22.SetVisible(true);
-
- TestFocusControllerObserver focus_observer;
- FocusController focus_controller(&focus_observer, &parent);
- focus_controller.AddObserver(&focus_observer);
-
- focus_controller.ActivateNextWindow();
- EXPECT_EQ(nullptr, focus_observer.old_active_window());
- EXPECT_EQ(&child22, focus_observer.new_active_window());
- focus_observer.ClearAll();
-
- child2.SetVisible(false);
- EXPECT_EQ(&child22, focus_observer.old_active_window());
- EXPECT_EQ(&child12, focus_observer.new_active_window());
-}
-
-TEST(FocusControllerTest, NonFocusableWindowNotActivated) {
- TestServerWindowDelegate server_window_delegate;
- ServerWindow parent(&server_window_delegate, WindowId());
- server_window_delegate.set_root_window(&parent);
- parent.SetVisible(true);
-
- ServerWindow child_first(&server_window_delegate, WindowId());
- ServerWindow child_second(&server_window_delegate, WindowId());
- parent.Add(&child_first);
- parent.Add(&child_second);
- child_first.SetVisible(true);
- child_second.SetVisible(true);
-
- TestFocusControllerObserver focus_observer;
- focus_observer.set_ignore_explicit(false);
- FocusController focus_controller(&focus_observer, &parent);
- focus_controller.AddObserver(&focus_observer);
-
- child_first.set_can_focus(false);
-
- // |child_second| is activated first, but then activation skips over
- // |child_first| and goes to |parent| instead.
- focus_controller.ActivateNextWindow();
- EXPECT_EQ(nullptr, focus_observer.old_active_window());
- EXPECT_EQ(&child_second, focus_observer.new_active_window());
- focus_observer.ClearAll();
-
- focus_controller.ActivateNextWindow();
- EXPECT_EQ(&child_second, focus_observer.old_active_window());
- EXPECT_EQ(&parent, focus_observer.new_active_window());
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/ids.h b/chromium/components/mus/ws/ids.h
deleted file mode 100644
index 3cdf4b29b87..00000000000
--- a/chromium/components/mus/ws/ids.h
+++ /dev/null
@@ -1,113 +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 COMPONENTS_MUS_WS_IDS_H_
-#define COMPONENTS_MUS_WS_IDS_H_
-
-#include <stdint.h>
-
-#include <tuple>
-
-#include "base/containers/hash_tables.h"
-#include "base/hash.h"
-#include "components/mus/common/types.h"
-#include "components/mus/common/util.h"
-
-namespace mus {
-namespace ws {
-
-// A client id used to indicate no client. That is, no WindowTree ever gets this
-// id.
-const ClientSpecificId kInvalidClientId = 0;
-
-// Every window has a unique id associated with it (WindowId). The id is a
-// combination of the id assigned to the client (the high order bits) and
-// a unique id for the window. Each client (WindowTree) refers to the window
-// by an id assigned by the client (ClientWindowId). To facilitate this
-// WindowTree maintains a mapping between WindowId and ClientWindowId.
-//
-// This model works when the client initiates creation of windows, which is
-// the typical use case. Embed roots and the WindowManager are special, they
-// get access to windows created by other clients. These clients see the
-// id assigned on the server. Such clients have to take care that they only
-// create windows using their client id. To do otherwise could result in
-// multiple windows having the same ClientWindowId. WindowTree enforces
-// that embed roots use the client id in creating the window id to avoid
-// possible conflicts.
-struct WindowId {
- WindowId(ClientSpecificId client_id, ClientSpecificId window_id)
- : client_id(client_id), window_id(window_id) {}
- WindowId() : client_id(0), window_id(0) {}
-
- bool operator==(const WindowId& other) const {
- return other.client_id == client_id && other.window_id == window_id;
- }
-
- bool operator!=(const WindowId& other) const { return !(*this == other); }
-
- bool operator<(const WindowId& other) const {
- return std::tie(client_id, window_id) <
- std::tie(other.client_id, other.window_id);
- }
-
- ClientSpecificId client_id;
- ClientSpecificId window_id;
-};
-
-// Used for ids assigned by the client.
-struct ClientWindowId {
- explicit ClientWindowId(Id id) : id(id) {}
- ClientWindowId() : id(0u) {}
-
- bool operator==(const ClientWindowId& other) const { return other.id == id; }
-
- bool operator!=(const ClientWindowId& other) const {
- return !(*this == other);
- }
-
- bool operator<(const ClientWindowId& other) const { return id < other.id; }
-
- Id id;
-};
-
-inline WindowId WindowIdFromTransportId(Id id) {
- return WindowId(HiWord(id), LoWord(id));
-}
-inline Id WindowIdToTransportId(const WindowId& id) {
- return (id.client_id << 16) | id.window_id;
-}
-
-// Returns a WindowId that is reserved to indicate no window. That is, no window
-// will ever be created with this id.
-inline WindowId InvalidWindowId() {
- return WindowId(kInvalidClientId, 0);
-}
-
-// Returns a root window id with a given index offset.
-inline WindowId RootWindowId(uint16_t index) {
- return WindowId(kInvalidClientId, 2 + index);
-}
-
-} // namespace ws
-} // namespace mus
-
-namespace BASE_HASH_NAMESPACE {
-
-template <>
-struct hash<mus::ws::ClientWindowId> {
- size_t operator()(const mus::ws::ClientWindowId& id) const {
- return hash<mus::Id>()(id.id);
- }
-};
-
-template <>
-struct hash<mus::ws::WindowId> {
- size_t operator()(const mus::ws::WindowId& id) const {
- return hash<mus::Id>()(WindowIdToTransportId(id));
- }
-};
-
-} // namespace BASE_HASH_NAMESPACE
-
-#endif // COMPONENTS_MUS_WS_IDS_H_
diff --git a/chromium/components/mus/ws/modal_window_controller.cc b/chromium/components/mus/ws/modal_window_controller.cc
deleted file mode 100644
index 89ec02e3720..00000000000
--- a/chromium/components/mus/ws/modal_window_controller.cc
+++ /dev/null
@@ -1,121 +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 "components/mus/ws/modal_window_controller.h"
-
-#include "base/stl_util.h"
-#include "components/mus/ws/event_dispatcher.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_drawn_tracker.h"
-
-namespace mus {
-namespace ws {
-namespace {
-
-const ServerWindow* GetModalChildForWindowAncestor(const ServerWindow* window) {
- for (const ServerWindow* ancestor = window; ancestor;
- ancestor = ancestor->parent()) {
- for (const auto& transient_child : ancestor->transient_children()) {
- if (transient_child->is_modal() && transient_child->IsDrawn())
- return transient_child;
- }
- }
- return nullptr;
-}
-
-const ServerWindow* GetWindowModalTargetForWindow(const ServerWindow* window) {
- const ServerWindow* modal_window = GetModalChildForWindowAncestor(window);
- if (!modal_window)
- return window;
- return GetWindowModalTargetForWindow(modal_window);
-}
-
-} // namespace
-
-ModalWindowController::ModalWindowController(EventDispatcher* event_dispatcher)
- : event_dispatcher_(event_dispatcher) {}
-
-ModalWindowController::~ModalWindowController() {
- for (auto it = system_modal_windows_.begin();
- it != system_modal_windows_.end(); it++) {
- (*it)->RemoveObserver(this);
- }
-}
-
-void ModalWindowController::AddSystemModalWindow(ServerWindow* window) {
- DCHECK(window);
- DCHECK(!ContainsValue(system_modal_windows_, window));
-
- window->SetModal();
- system_modal_windows_.push_back(window);
- window_drawn_trackers_.insert(make_pair(
- window, base::WrapUnique(new ServerWindowDrawnTracker(window, this))));
- window->AddObserver(this);
-
- event_dispatcher_->ReleaseCaptureBlockedByModalWindow(window);
-}
-
-bool ModalWindowController::IsWindowBlockedBy(
- const ServerWindow* window,
- const ServerWindow* modal_window) const {
- DCHECK(window);
- DCHECK(modal_window);
- if (!modal_window->is_modal() || !modal_window->IsDrawn())
- return false;
-
- if (modal_window->transient_parent() &&
- !modal_window->transient_parent()->Contains(window)) {
- return false;
- }
-
- return true;
-}
-
-bool ModalWindowController::IsWindowBlocked(const ServerWindow* window) const {
- DCHECK(window);
- return GetActiveSystemModalWindow() || GetModalChildForWindowAncestor(window);
-}
-
-const ServerWindow* ModalWindowController::GetTargetForWindow(
- const ServerWindow* window) const {
- ServerWindow* system_modal_window = GetActiveSystemModalWindow();
- return system_modal_window ? system_modal_window
- : GetWindowModalTargetForWindow(window);
-}
-
-ServerWindow* ModalWindowController::GetActiveSystemModalWindow() const {
- for (auto it = system_modal_windows_.rbegin();
- it != system_modal_windows_.rend(); it++) {
- ServerWindow* modal = *it;
- if (modal->IsDrawn())
- return modal;
- }
- return nullptr;
-}
-
-void ModalWindowController::OnWindowDestroyed(ServerWindow* window) {
- window->RemoveObserver(this);
- auto it = std::find(system_modal_windows_.begin(),
- system_modal_windows_.end(), window);
- DCHECK(it != system_modal_windows_.end());
- system_modal_windows_.erase(it);
- window_drawn_trackers_.erase(window);
-}
-
-void ModalWindowController::OnDrawnStateChanged(ServerWindow* ancestor,
- ServerWindow* window,
- bool is_drawn) {
- if (!is_drawn)
- return;
-
- // Move the most recently shown window to the end of the list.
- auto it = std::find(system_modal_windows_.begin(),
- system_modal_windows_.end(), window);
- DCHECK(it != system_modal_windows_.end());
- system_modal_windows_.splice(system_modal_windows_.end(),
- system_modal_windows_, it);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/modal_window_controller.h b/chromium/components/mus/ws/modal_window_controller.h
deleted file mode 100644
index 112fce771e6..00000000000
--- a/chromium/components/mus/ws/modal_window_controller.h
+++ /dev/null
@@ -1,87 +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 COMPONENTS_MUS_WS_MODAL_WINDOW_CONTROLLER_H_
-#define COMPONENTS_MUS_WS_MODAL_WINDOW_CONTROLLER_H_
-
-#include <list>
-#include <map>
-
-#include "components/mus/ws/server_window_drawn_tracker_observer.h"
-#include "components/mus/ws/server_window_observer.h"
-
-namespace mus {
-namespace ws {
-
-class EventDispatcher;
-class ServerWindow;
-class ServerWindowDrawnTracker;
-
-namespace test {
-class ModalWindowControllerTestApi;
-}
-
-// Used to keeps track of system modal windows and check whether windows are
-// blocked by modal windows or not to do appropriate retargetting of events.
-class ModalWindowController : public ServerWindowObserver,
- public ServerWindowDrawnTrackerObserver {
- public:
- explicit ModalWindowController(EventDispatcher* event_dispatcher);
- ~ModalWindowController() override;
-
- // Adds a system modal window. The window remains modal to system until it is
- // destroyed. There can exist multiple system modal windows, in which case the
- // one that is visible and added most recently or shown most recently would be
- // the active one.
- void AddSystemModalWindow(ServerWindow* window);
-
- // Checks whether |modal_window| is a visible modal window that blocks
- // |window|.
- bool IsWindowBlockedBy(const ServerWindow* window,
- const ServerWindow* modal_window) const;
-
- // Checks whether |window| is blocked by any visible modal window.
- bool IsWindowBlocked(const ServerWindow* window) const;
-
- // Returns the window that events targeted to |window| should be retargeted
- // to; according to modal windows. If any modal window is blocking |window|
- // (either system modal or window modal), returns the topmost one; otherwise,
- // returns |window| itself.
- const ServerWindow* GetTargetForWindow(const ServerWindow* window) const;
- ServerWindow* GetTargetForWindow(ServerWindow* window) const {
- return const_cast<ServerWindow*>(
- GetTargetForWindow(static_cast<const ServerWindow*>(window)));
- }
-
- private:
- friend class test::ModalWindowControllerTestApi;
-
- // Returns the system modal window that is visible and added/shown most
- // recently, if any.
- ServerWindow* GetActiveSystemModalWindow() const;
-
- // ServerWindowObserver:
- void OnWindowDestroyed(ServerWindow* window) override;
-
- // ServerWindowDrawnTrackerObserver:
- void OnDrawnStateChanged(ServerWindow* ancestor,
- ServerWindow* window,
- bool is_drawn) override;
-
- EventDispatcher* event_dispatcher_;
-
- // List of system modal windows in order they are added/shown.
- std::list<ServerWindow*> system_modal_windows_;
-
- // Drawn trackers for system modal windows.
- std::map<ServerWindow*, std::unique_ptr<ServerWindowDrawnTracker>>
- window_drawn_trackers_;
-
- DISALLOW_COPY_AND_ASSIGN(ModalWindowController);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_MODAL_WINDOW_CONTROLLER_H_
diff --git a/chromium/components/mus/ws/mus_ws_unittests_app_manifest.json b/chromium/components/mus/ws/mus_ws_unittests_app_manifest.json
deleted file mode 100644
index 5e3872e21ac..00000000000
--- a/chromium/components/mus/ws/mus_ws_unittests_app_manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "manifest_version": 1,
- "name": "mojo:mus_ws_unittests_app",
- "display_name": "Mus Window Server Unittests",
- "capabilities": {
- "required": {
- "*": { "classes": [ "app" ] },
- "mojo:mus_ws_unittests_app": {
- "interfaces": [ "mus::mojom::WindowTreeClient" ]
- },
- "mojo:mus": {
- "interfaces": [ "mus::mojom::WindowTreeHostFactory" ]
- }
- }
- }
-}
diff --git a/chromium/components/mus/ws/operation.cc b/chromium/components/mus/ws/operation.cc
deleted file mode 100644
index 6c04bc34c01..00000000000
--- a/chromium/components/mus/ws/operation.cc
+++ /dev/null
@@ -1,30 +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 "components/mus/ws/operation.h"
-
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_tree.h"
-
-namespace mus {
-namespace ws {
-
-Operation::Operation(WindowTree* tree,
- WindowServer* window_server,
- OperationType operation_type)
- : window_server_(window_server),
- source_tree_id_(tree->id()),
- operation_type_(operation_type) {
- DCHECK(operation_type != OperationType::NONE);
- // Tell the window server about the operation currently in flight. The window
- // server uses this information to suppress certain calls out to clients.
- window_server_->PrepareForOperation(this);
-}
-
-Operation::~Operation() {
- window_server_->FinishOperation();
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/operation.h b/chromium/components/mus/ws/operation.h
deleted file mode 100644
index 15d0034fddc..00000000000
--- a/chromium/components/mus/ws/operation.h
+++ /dev/null
@@ -1,77 +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 COMPONENTS_MUS_WS_OPERATION_H_
-#define COMPONENTS_MUS_WS_OPERATION_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "components/mus/common/types.h"
-
-namespace mus {
-namespace ws {
-
-class WindowServer;
-class WindowTree;
-
-enum class OperationType {
- NONE,
- ADD_TRANSIENT_WINDOW,
- ADD_WINDOW,
- DELETE_WINDOW,
- EMBED,
- RELEASE_CAPTURE,
- REMOVE_TRANSIENT_WINDOW_FROM_PARENT,
- REMOVE_WINDOW_FROM_PARENT,
- REORDER_WINDOW,
- SET_CAPTURE,
- SET_FOCUS,
- SET_WINDOW_BOUNDS,
- SET_WINDOW_OPACITY,
- SET_WINDOW_PREDEFINED_CURSOR,
- SET_WINDOW_PROPERTY,
- SET_WINDOW_VISIBILITY,
-};
-
-// This class tracks the currently pending client-initiated operation.
-// This is typically used to suppress superfluous notifications generated
-// by suboperations in the window server.
-class Operation {
- public:
- Operation(WindowTree* tree,
- WindowServer* window_server,
- OperationType operation_type);
- ~Operation();
-
- ClientSpecificId source_tree_id() const { return source_tree_id_; }
-
- const OperationType& type() const { return operation_type_; }
-
- // Marks the tree with the specified id as having been sent a message
- // during the course of |this| operation.
- void MarkTreeAsMessaged(ClientSpecificId tree_id) {
- message_ids_.insert(tree_id);
- }
-
- // Returns true if MarkTreeAsMessaged(tree_id) was invoked.
- bool DidMessageTree(ClientSpecificId tree_id) const {
- return message_ids_.count(tree_id) > 0;
- }
-
- private:
- WindowServer* const window_server_;
- const ClientSpecificId source_tree_id_;
- const OperationType operation_type_;
-
- // See description of MarkTreeAsMessaged/DidMessageTree.
- std::set<ClientSpecificId> message_ids_;
-
- DISALLOW_COPY_AND_ASSIGN(Operation);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_OPERATION_H_
diff --git a/chromium/components/mus/ws/platform_display.cc b/chromium/components/mus/ws/platform_display.cc
deleted file mode 100644
index 84ca1fde8ba..00000000000
--- a/chromium/components/mus/ws/platform_display.cc
+++ /dev/null
@@ -1,414 +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 "components/mus/ws/platform_display.h"
-
-#include "base/numerics/safe_conversions.h"
-#include "build/build_config.h"
-#include "cc/ipc/quads.mojom.h"
-#include "cc/output/compositor_frame.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/output/delegated_frame_data.h"
-#include "cc/quads/render_pass.h"
-#include "cc/quads/shared_quad_state.h"
-#include "cc/quads/surface_draw_quad.h"
-#include "components/mus/gles2/gpu_state.h"
-#include "components/mus/public/interfaces/gpu.mojom.h"
-#include "components/mus/surfaces/display_compositor.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/platform_display_factory.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_surface.h"
-#include "components/mus/ws/server_window_surface_manager.h"
-#include "components/mus/ws/window_coordinate_conversions.h"
-#include "services/shell/public/cpp/connection.h"
-#include "services/shell/public/cpp/connector.h"
-#include "third_party/skia/include/core/SkXfermode.h"
-#include "ui/base/cursor/cursor_loader.h"
-#include "ui/display/display.h"
-#include "ui/events/event.h"
-#include "ui/events/event_utils.h"
-#include "ui/platform_window/platform_ime_controller.h"
-#include "ui/platform_window/platform_window.h"
-
-#if defined(OS_WIN)
-#include "ui/platform_window/win/win_window.h"
-#elif defined(USE_X11)
-#include "ui/platform_window/x11/x11_window.h"
-#elif defined(OS_ANDROID)
-#include "ui/platform_window/android/platform_window_android.h"
-#elif defined(USE_OZONE)
-#include "ui/ozone/public/ozone_platform.h"
-#endif
-
-namespace mus {
-
-namespace ws {
-namespace {
-
-// DrawWindowTree recursively visits ServerWindows, creating a SurfaceDrawQuad
-// for each that lacks one.
-void DrawWindowTree(cc::RenderPass* pass,
- ServerWindow* window,
- const gfx::Vector2d& parent_to_root_origin_offset,
- float opacity) {
- if (!window->visible())
- return;
-
- ServerWindowSurface* default_surface =
- window->surface_manager() ? window->surface_manager()->GetDefaultSurface()
- : nullptr;
-
- const gfx::Rect absolute_bounds =
- window->bounds() + parent_to_root_origin_offset;
- std::vector<ServerWindow*> children(window->GetChildren());
- // TODO(rjkroege, fsamuel): Make sure we're handling alpha correctly.
- const float combined_opacity = opacity * window->opacity();
- for (auto it = children.rbegin(); it != children.rend(); ++it) {
- DrawWindowTree(pass, *it, absolute_bounds.OffsetFromOrigin(),
- combined_opacity);
- }
-
- if (!window->surface_manager() || !window->surface_manager()->ShouldDraw())
- return;
-
- ServerWindowSurface* underlay_surface =
- window->surface_manager()->GetUnderlaySurface();
- if (!default_surface && !underlay_surface)
- return;
-
- if (default_surface) {
- gfx::Transform quad_to_target_transform;
- quad_to_target_transform.Translate(absolute_bounds.x(),
- absolute_bounds.y());
-
- cc::SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
-
- const gfx::Rect bounds_at_origin(window->bounds().size());
- // TODO(fsamuel): These clipping and visible rects are incorrect. They need
- // to be populated from CompositorFrame structs.
- sqs->SetAll(quad_to_target_transform,
- bounds_at_origin.size() /* layer_bounds */,
- bounds_at_origin /* visible_layer_bounds */,
- bounds_at_origin /* clip_rect */, false /* is_clipped */,
- window->opacity(), SkXfermode::kSrcOver_Mode,
- 0 /* sorting-context_id */);
- auto quad = pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
- quad->SetAll(sqs, bounds_at_origin /* rect */,
- gfx::Rect() /* opaque_rect */,
- bounds_at_origin /* visible_rect */, true /* needs_blending*/,
- default_surface->id());
- }
- if (underlay_surface) {
- const gfx::Rect underlay_absolute_bounds =
- absolute_bounds - window->underlay_offset();
- gfx::Transform quad_to_target_transform;
- quad_to_target_transform.Translate(underlay_absolute_bounds.x(),
- underlay_absolute_bounds.y());
- cc::SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
- const gfx::Rect bounds_at_origin(
- underlay_surface->last_submitted_frame_size());
- sqs->SetAll(quad_to_target_transform,
- bounds_at_origin.size() /* layer_bounds */,
- bounds_at_origin /* visible_layer_bounds */,
- bounds_at_origin /* clip_rect */, false /* is_clipped */,
- window->opacity(), SkXfermode::kSrcOver_Mode,
- 0 /* sorting-context_id */);
-
- auto quad = pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
- quad->SetAll(sqs, bounds_at_origin /* rect */,
- gfx::Rect() /* opaque_rect */,
- bounds_at_origin /* visible_rect */, true /* needs_blending*/,
- underlay_surface->id());
- }
-}
-
-} // namespace
-
-// static
-PlatformDisplayFactory* PlatformDisplay::factory_ = nullptr;
-
-// static
-PlatformDisplay* PlatformDisplay::Create(
- const PlatformDisplayInitParams& init_params) {
- if (factory_)
- return factory_->CreatePlatformDisplay();
-
- return new DefaultPlatformDisplay(init_params);
-}
-
-DefaultPlatformDisplay::DefaultPlatformDisplay(
- const PlatformDisplayInitParams& init_params)
- : display_id_(init_params.display_id),
- gpu_state_(init_params.gpu_state),
- surfaces_state_(init_params.surfaces_state),
- delegate_(nullptr),
- draw_timer_(false, false),
- frame_pending_(false),
-#if !defined(OS_ANDROID)
- cursor_loader_(ui::CursorLoader::Create()),
-#endif
- weak_factory_(this) {
- metrics_.size_in_pixels = init_params.display_bounds.size();
- // TODO(rjkroege): Preserve the display_id when Ozone platform can use it.
-}
-
-void DefaultPlatformDisplay::Init(PlatformDisplayDelegate* delegate) {
- delegate_ = delegate;
-
- gfx::Rect bounds(metrics_.size_in_pixels);
-#if defined(OS_WIN)
- platform_window_.reset(new ui::WinWindow(this, bounds));
-#elif defined(USE_X11)
- platform_window_.reset(new ui::X11Window(this));
-#elif defined(OS_ANDROID)
- platform_window_.reset(new ui::PlatformWindowAndroid(this));
-#elif defined(USE_OZONE)
- platform_window_ =
- ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds);
-#else
- NOTREACHED() << "Unsupported platform";
-#endif
- platform_window_->SetBounds(bounds);
- platform_window_->Show();
-}
-
-DefaultPlatformDisplay::~DefaultPlatformDisplay() {
- // Don't notify the delegate from the destructor.
- delegate_ = nullptr;
-
- // Invalidate WeakPtrs now to avoid callbacks back into the
- // DefaultPlatformDisplay during destruction of |display_compositor_|.
- weak_factory_.InvalidateWeakPtrs();
- display_compositor_.reset();
- // Destroy the PlatformWindow early on as it may call us back during
- // destruction and we want to be in a known state. But destroy the surface
- // first because it can still be using the platform window.
- platform_window_.reset();
-}
-
-void DefaultPlatformDisplay::SchedulePaint(const ServerWindow* window,
- const gfx::Rect& bounds) {
- DCHECK(window);
- if (!window->IsDrawn())
- return;
- const gfx::Rect root_relative_rect =
- ConvertRectBetweenWindows(window, delegate_->GetRootWindow(), bounds);
- if (root_relative_rect.IsEmpty())
- return;
- dirty_rect_.Union(root_relative_rect);
- WantToDraw();
-}
-
-void DefaultPlatformDisplay::SetViewportSize(const gfx::Size& size) {
- platform_window_->SetBounds(gfx::Rect(size));
-}
-
-void DefaultPlatformDisplay::SetTitle(const base::string16& title) {
- platform_window_->SetTitle(title);
-}
-
-void DefaultPlatformDisplay::SetCapture() {
- platform_window_->SetCapture();
-}
-
-void DefaultPlatformDisplay::ReleaseCapture() {
- platform_window_->ReleaseCapture();
-}
-
-void DefaultPlatformDisplay::SetCursorById(int32_t cursor_id) {
-#if !defined(OS_ANDROID)
- // TODO(erg): This still isn't sufficient, and will only use native cursors
- // that chrome would use, not custom image cursors. For that, we should
- // delegate to the window manager to load images from resource packs.
- //
- // We probably also need to deal with different DPIs.
- ui::Cursor cursor(cursor_id);
- cursor_loader_->SetPlatformCursor(&cursor);
- platform_window_->SetCursor(cursor.platform());
-#endif
-}
-
-float DefaultPlatformDisplay::GetDeviceScaleFactor() {
- return metrics_.device_scale_factor;
-}
-
-mojom::Rotation DefaultPlatformDisplay::GetRotation() {
- // TODO(sky): implement me.
- return mojom::Rotation::VALUE_0;
-}
-
-void DefaultPlatformDisplay::UpdateTextInputState(
- const ui::TextInputState& state) {
- ui::PlatformImeController* ime = platform_window_->GetPlatformImeController();
- if (ime)
- ime->UpdateTextInputState(state);
-}
-
-void DefaultPlatformDisplay::SetImeVisibility(bool visible) {
- ui::PlatformImeController* ime = platform_window_->GetPlatformImeController();
- if (ime)
- ime->SetImeVisibility(visible);
-}
-
-void DefaultPlatformDisplay::Draw() {
- if (!delegate_->GetRootWindow()->visible())
- return;
-
- // TODO(fsamuel): We should add a trace for generating a top level frame.
- cc::CompositorFrame frame(GenerateCompositorFrame());
- frame_pending_ = true;
- if (display_compositor_) {
- display_compositor_->SubmitCompositorFrame(
- std::move(frame), base::Bind(&DefaultPlatformDisplay::DidDraw,
- weak_factory_.GetWeakPtr()));
- }
- dirty_rect_ = gfx::Rect();
-}
-
-void DefaultPlatformDisplay::DidDraw(cc::SurfaceDrawStatus status) {
- frame_pending_ = false;
- delegate_->OnCompositorFrameDrawn();
- if (!dirty_rect_.IsEmpty())
- WantToDraw();
-}
-
-bool DefaultPlatformDisplay::IsFramePending() const {
- return frame_pending_;
-}
-
-int64_t DefaultPlatformDisplay::GetDisplayId() const {
- return display_id_;
-}
-
-void DefaultPlatformDisplay::WantToDraw() {
- if (draw_timer_.IsRunning() || frame_pending_)
- return;
-
- // TODO(rjkroege): Use vblank to kick off Draw.
- draw_timer_.Start(
- FROM_HERE, base::TimeDelta(),
- base::Bind(&DefaultPlatformDisplay::Draw, weak_factory_.GetWeakPtr()));
-}
-
-void DefaultPlatformDisplay::UpdateMetrics(const gfx::Size& size,
- float device_scale_factor) {
- if (display::Display::HasForceDeviceScaleFactor())
- device_scale_factor = display::Display::GetForcedDeviceScaleFactor();
- if (metrics_.size_in_pixels == size &&
- metrics_.device_scale_factor == device_scale_factor)
- return;
-
- ViewportMetrics old_metrics = metrics_;
- metrics_.size_in_pixels = size;
- metrics_.device_scale_factor = device_scale_factor;
- delegate_->OnViewportMetricsChanged(old_metrics, metrics_);
-}
-
-cc::CompositorFrame DefaultPlatformDisplay::GenerateCompositorFrame() {
- std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create();
- render_pass->damage_rect = dirty_rect_;
- render_pass->output_rect = gfx::Rect(metrics_.size_in_pixels);
-
- DrawWindowTree(render_pass.get(), delegate_->GetRootWindow(), gfx::Vector2d(),
- 1.0f);
-
- std::unique_ptr<cc::DelegatedFrameData> frame_data(
- new cc::DelegatedFrameData);
- frame_data->render_pass_list.push_back(std::move(render_pass));
-
- cc::CompositorFrame frame;
- frame.delegated_frame_data = std::move(frame_data);
- return frame;
-}
-
-void DefaultPlatformDisplay::OnBoundsChanged(const gfx::Rect& new_bounds) {
- UpdateMetrics(new_bounds.size(), metrics_.device_scale_factor);
-}
-
-void DefaultPlatformDisplay::OnDamageRect(const gfx::Rect& damaged_region) {
- dirty_rect_.Union(damaged_region);
- WantToDraw();
-}
-
-void DefaultPlatformDisplay::DispatchEvent(ui::Event* event) {
- if (event->IsScrollEvent()) {
- // TODO(moshayedi): crbug.com/602859. Dispatch scroll events as
- // they are once we have proper support for scroll events.
- delegate_->OnEvent(ui::MouseWheelEvent(*event->AsScrollEvent()));
- } else if (event->IsMouseEvent() && !event->IsMouseWheelEvent()) {
- delegate_->OnEvent(ui::PointerEvent(*event->AsMouseEvent()));
- } else if (event->IsTouchEvent()) {
- delegate_->OnEvent(ui::PointerEvent(*event->AsTouchEvent()));
- } else {
- delegate_->OnEvent(*event);
- }
-
-#if defined(USE_X11) || defined(USE_OZONE)
- // We want to emulate the WM_CHAR generation behaviour of Windows.
- //
- // On Linux, we've previously inserted characters by having
- // InputMethodAuraLinux take all key down events and send a character event
- // to the TextInputClient. This causes a mismatch in code that has to be
- // shared between Windows and Linux, including blink code. Now that we're
- // trying to have one way of doing things, we need to standardize on and
- // emulate Windows character events.
- //
- // This is equivalent to what we're doing in the current Linux port, but
- // done once instead of done multiple times in different places.
- if (event->type() == ui::ET_KEY_PRESSED) {
- ui::KeyEvent* key_press_event = event->AsKeyEvent();
- ui::KeyEvent char_event(key_press_event->GetCharacter(),
- key_press_event->key_code(),
- key_press_event->flags());
- DCHECK_EQ(key_press_event->GetCharacter(), char_event.GetCharacter());
- DCHECK_EQ(key_press_event->key_code(), char_event.key_code());
- DCHECK_EQ(key_press_event->flags(), char_event.flags());
- delegate_->OnEvent(char_event);
- }
-#endif
-}
-
-void DefaultPlatformDisplay::OnCloseRequest() {
- platform_window_->Close();
-}
-
-void DefaultPlatformDisplay::OnClosed() {
- if (delegate_)
- delegate_->OnDisplayClosed();
-}
-
-void DefaultPlatformDisplay::OnWindowStateChanged(
- ui::PlatformWindowState new_state) {}
-
-void DefaultPlatformDisplay::OnLostCapture() {
- delegate_->OnNativeCaptureLost();
-}
-
-void DefaultPlatformDisplay::OnAcceleratedWidgetAvailable(
- gfx::AcceleratedWidget widget,
- float device_scale_factor) {
- if (widget != gfx::kNullAcceleratedWidget) {
- display_compositor_.reset(
- new DisplayCompositor(base::ThreadTaskRunnerHandle::Get(), widget,
- gpu_state_, surfaces_state_));
- }
- UpdateMetrics(metrics_.size_in_pixels, device_scale_factor);
-}
-
-void DefaultPlatformDisplay::OnAcceleratedWidgetDestroyed() {
- NOTREACHED();
-}
-
-void DefaultPlatformDisplay::OnActivationChanged(bool active) {}
-
-void DefaultPlatformDisplay::RequestCopyOfOutput(
- std::unique_ptr<cc::CopyOutputRequest> output_request) {
- if (display_compositor_)
- display_compositor_->RequestCopyOfOutput(std::move(output_request));
-}
-
-} // namespace ws
-
-} // namespace mus
diff --git a/chromium/components/mus/ws/platform_display.h b/chromium/components/mus/ws/platform_display.h
deleted file mode 100644
index e16a46c1936..00000000000
--- a/chromium/components/mus/ws/platform_display.h
+++ /dev/null
@@ -1,195 +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 COMPONENTS_MUS_WS_PLATFORM_DISPLAY_H_
-#define COMPONENTS_MUS_WS_PLATFORM_DISPLAY_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "base/timer/timer.h"
-#include "build/build_config.h"
-#include "cc/surfaces/surface.h"
-#include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "components/mus/public/interfaces/window_manager_constants.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/ws/platform_display_delegate.h"
-#include "components/mus/ws/platform_display_init_params.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/platform_window/platform_window_delegate.h"
-
-namespace cc {
-class CompositorFrame;
-class CopyOutputRequest;
-class SurfaceIdAllocator;
-class SurfaceManager;
-} // namespace cc
-
-namespace gles2 {
-class GpuState;
-} // namespace gles2
-
-namespace shell {
-class Connector;
-} // namespace shell
-
-namespace ui {
-class CursorLoader;
-class PlatformWindow;
-struct TextInputState;
-} // namespace ui
-
-namespace mus {
-
-class GpuState;
-class SurfacesState;
-class DisplayCompositor;
-
-namespace ws {
-
-class EventDispatcher;
-class PlatformDisplayFactory;
-class ServerWindow;
-
-struct ViewportMetrics {
- gfx::Size size_in_pixels;
- float device_scale_factor = 0.f;
-};
-
-// PlatformDisplay is used to connect the root ServerWindow to a display.
-class PlatformDisplay {
- public:
- virtual ~PlatformDisplay() {}
-
- static PlatformDisplay* Create(const PlatformDisplayInitParams& init_params);
-
- virtual void Init(PlatformDisplayDelegate* delegate) = 0;
-
- // Schedules a paint for the specified region in the coordinates of |window|.
- virtual void SchedulePaint(const ServerWindow* window,
- const gfx::Rect& bounds) = 0;
-
- virtual void SetViewportSize(const gfx::Size& size) = 0;
-
- virtual void SetTitle(const base::string16& title) = 0;
-
- virtual void SetCapture() = 0;
-
- virtual void ReleaseCapture() = 0;
-
- virtual void SetCursorById(int32_t cursor) = 0;
-
- virtual mojom::Rotation GetRotation() = 0;
-
- virtual float GetDeviceScaleFactor() = 0;
-
- virtual void UpdateTextInputState(const ui::TextInputState& state) = 0;
- virtual void SetImeVisibility(bool visible) = 0;
-
- // Returns true if a compositor frame has been submitted but not drawn yet.
- virtual bool IsFramePending() const = 0;
-
- virtual void RequestCopyOfOutput(
- std::unique_ptr<cc::CopyOutputRequest> output_request) = 0;
-
- virtual int64_t GetDisplayId() const = 0;
-
- // Overrides factory for testing. Default (NULL) value indicates regular
- // (non-test) environment.
- static void set_factory_for_testing(PlatformDisplayFactory* factory) {
- PlatformDisplay::factory_ = factory;
- }
-
- private:
- // Static factory instance (always NULL for non-test).
- static PlatformDisplayFactory* factory_;
-};
-
-// PlatformDisplay implementation that connects to the services necessary to
-// actually display.
-class DefaultPlatformDisplay : public PlatformDisplay,
- public ui::PlatformWindowDelegate {
- public:
- explicit DefaultPlatformDisplay(const PlatformDisplayInitParams& init_params);
- ~DefaultPlatformDisplay() override;
-
- // PlatformDisplay:
- void Init(PlatformDisplayDelegate* delegate) override;
- void SchedulePaint(const ServerWindow* window,
- const gfx::Rect& bounds) override;
- void SetViewportSize(const gfx::Size& size) override;
- void SetTitle(const base::string16& title) override;
- void SetCapture() override;
- void ReleaseCapture() override;
- void SetCursorById(int32_t cursor) override;
- float GetDeviceScaleFactor() override;
- mojom::Rotation GetRotation() override;
- void UpdateTextInputState(const ui::TextInputState& state) override;
- void SetImeVisibility(bool visible) override;
- bool IsFramePending() const override;
- void RequestCopyOfOutput(
- std::unique_ptr<cc::CopyOutputRequest> output_request) override;
- int64_t GetDisplayId() const override;
-
- private:
- void WantToDraw();
-
- // This method initiates a top level redraw of the display.
- // TODO(fsamuel): This should use vblank as a signal rather than a timer
- // http://crbug.com/533042
- void Draw();
-
- // This is called after cc::Display has completed generating a new frame
- // for the display. TODO(fsamuel): Idle time processing should happen here
- // if there is budget for it.
- void DidDraw(cc::SurfaceDrawStatus status);
- void UpdateMetrics(const gfx::Size& size, float device_scale_factor);
- cc::CompositorFrame GenerateCompositorFrame();
-
- // ui::PlatformWindowDelegate:
- void OnBoundsChanged(const gfx::Rect& new_bounds) override;
- void OnDamageRect(const gfx::Rect& damaged_region) override;
- void DispatchEvent(ui::Event* event) override;
- void OnCloseRequest() override;
- void OnClosed() override;
- void OnWindowStateChanged(ui::PlatformWindowState new_state) override;
- void OnLostCapture() override;
- void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget,
- float device_scale_factor) override;
- void OnAcceleratedWidgetDestroyed() override;
- void OnActivationChanged(bool active) override;
-
- int64_t display_id_;
-
- scoped_refptr<GpuState> gpu_state_;
- scoped_refptr<SurfacesState> surfaces_state_;
- PlatformDisplayDelegate* delegate_;
-
- ViewportMetrics metrics_;
- gfx::Rect dirty_rect_;
- base::Timer draw_timer_;
- bool frame_pending_;
-
- std::unique_ptr<DisplayCompositor> display_compositor_;
- std::unique_ptr<ui::PlatformWindow> platform_window_;
-
-#if !defined(OS_ANDROID)
- std::unique_ptr<ui::CursorLoader> cursor_loader_;
-#endif
-
- base::WeakPtrFactory<DefaultPlatformDisplay> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(DefaultPlatformDisplay);
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_PLATFORM_DISPLAY_H_
diff --git a/chromium/components/mus/ws/platform_display_delegate.h b/chromium/components/mus/ws/platform_display_delegate.h
deleted file mode 100644
index 95a9c761dc4..00000000000
--- a/chromium/components/mus/ws/platform_display_delegate.h
+++ /dev/null
@@ -1,53 +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 COMPONENTS_MUS_WS_PLATFORM_DISPLAY_DELEGATE_H_
-#define COMPONENTS_MUS_WS_PLATFORM_DISPLAY_DELEGATE_H_
-
-#include "components/mus/ws/ids.h"
-
-namespace ui {
-class Event;
-}
-
-namespace mus {
-
-namespace ws {
-
-class ServerWindow;
-struct ViewportMetrics;
-
-// PlatformDisplayDelegate is implemented by an object that manages the
-// lifetime of a PlatformDisplay, forwards events to the appropriate windows,
-/// and responses to changes in viewport size.
-class PlatformDisplayDelegate {
- public:
- // Returns the root window of this display.
- virtual ServerWindow* GetRootWindow() = 0;
-
- // Called when the window managed by the PlatformDisplay is closed.
- virtual void OnDisplayClosed() = 0;
-
- // Called when an event arrives.
- virtual void OnEvent(const ui::Event& event) = 0;
-
- // Called when the Display loses capture.
- virtual void OnNativeCaptureLost() = 0;
-
- // Signals that the metrics of this display's viewport has changed.
- virtual void OnViewportMetricsChanged(const ViewportMetrics& old_metrics,
- const ViewportMetrics& new_metrics) = 0;
-
- // Called when a compositor frame is finished drawing.
- virtual void OnCompositorFrameDrawn() = 0;
-
- protected:
- virtual ~PlatformDisplayDelegate() {}
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_PLATFORM_DISPLAY_DELEGATE_H_
diff --git a/chromium/components/mus/ws/platform_display_factory.h b/chromium/components/mus/ws/platform_display_factory.h
deleted file mode 100644
index 1cad7dd8331..00000000000
--- a/chromium/components/mus/ws/platform_display_factory.h
+++ /dev/null
@@ -1,23 +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 COMPONENTS_MUS_WS_PLATFORM_DISPLAY_FACTORY_H_
-#define COMPONENTS_MUS_WS_PLATFORM_DISPLAY_FACTORY_H_
-
-namespace mus {
-namespace ws {
-
-class PlatformDisplay;
-
-// Abstract factory for PlatformDisplays. Used by tests to construct test
-// PlatformDisplays.
-class PlatformDisplayFactory {
- public:
- virtual PlatformDisplay* CreatePlatformDisplay() = 0;
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_PLATFORM_DISPLAY_FACTORY_H_
diff --git a/chromium/components/mus/ws/platform_display_init_params.cc b/chromium/components/mus/ws/platform_display_init_params.cc
deleted file mode 100644
index 394b5711637..00000000000
--- a/chromium/components/mus/ws/platform_display_init_params.cc
+++ /dev/null
@@ -1,21 +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 "components/mus/ws/platform_display_init_params.h"
-
-#include "components/mus/gles2/gpu_state.h"
-#include "components/mus/surfaces/surfaces_state.h"
-
-namespace mus {
-namespace ws {
-
-PlatformDisplayInitParams::PlatformDisplayInitParams()
- : display_bounds(gfx::Rect(0, 0, 1024, 768)), display_id(1) {}
-
-PlatformDisplayInitParams::PlatformDisplayInitParams(
- const PlatformDisplayInitParams& other) = default;
-PlatformDisplayInitParams::~PlatformDisplayInitParams() {}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/platform_display_init_params.h b/chromium/components/mus/ws/platform_display_init_params.h
deleted file mode 100644
index e596834f49b..00000000000
--- a/chromium/components/mus/ws/platform_display_init_params.h
+++ /dev/null
@@ -1,39 +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 COMPONENTS_MUS_WS_PLATFORM_DISPLAY_INIT_PARAMS_H_
-#define COMPONENTS_MUS_WS_PLATFORM_DISPLAY_INIT_PARAMS_H_
-
-#include <stdint.h>
-
-#include "base/memory/ref_counted.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace shell {
-class Connector;
-}
-
-namespace mus {
-
-class GpuState;
-class SurfacesState;
-
-namespace ws {
-
-struct PlatformDisplayInitParams {
- PlatformDisplayInitParams();
- PlatformDisplayInitParams(const PlatformDisplayInitParams& other);
- ~PlatformDisplayInitParams();
-
- scoped_refptr<GpuState> gpu_state;
- scoped_refptr<SurfacesState> surfaces_state;
-
- gfx::Rect display_bounds;
- int64_t display_id;
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_PLATFORM_DISPLAY_INIT_PARAMS_H_
diff --git a/chromium/components/mus/ws/platform_screen.h b/chromium/components/mus/ws/platform_screen.h
deleted file mode 100644
index 3215c28c257..00000000000
--- a/chromium/components/mus/ws/platform_screen.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_PLATFORM_SCREEN_H_
-#define COMPONENTS_MUS_WS_PLATFORM_SCREEN_H_
-
-#include <stdint.h>
-
-#include "base/callback.h"
-
-namespace gfx {
-class Rect;
-}
-
-namespace mus {
-namespace ws {
-
-// PlatformScreen provides the necessary functionality to configure all
-// attached physical displays.
-class PlatformScreen {
- public:
- virtual ~PlatformScreen() {}
-
- // Creates a PlatformScreen instance.
- static std::unique_ptr<PlatformScreen> Create();
-
- // Initializes platform specific screen resources.
- virtual void Init() = 0;
-
- using ConfiguredDisplayCallback =
- base::Callback<void(int64_t, const gfx::Rect&)>;
-
- // ConfigurePhysicalDisplay() configures a single physical display and returns
- // its id and bounds for it via |callback|.
- virtual void ConfigurePhysicalDisplay(
- const ConfiguredDisplayCallback& callback) = 0;
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_PLATFORM_SCREEN_H_
diff --git a/chromium/components/mus/ws/platform_screen_impl.cc b/chromium/components/mus/ws/platform_screen_impl.cc
deleted file mode 100644
index e5ec99f660f..00000000000
--- a/chromium/components/mus/ws/platform_screen_impl.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/mus/ws/platform_screen_impl.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/memory/ptr_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace mus {
-
-namespace ws {
-namespace {
-
-void FixedSizeScreenConfiguration(
- const PlatformScreen::ConfiguredDisplayCallback& callback) {
- callback.Run(1, gfx::Rect(1024, 768));
-}
-
-} // namespace
-
-// static
-std::unique_ptr<PlatformScreen> PlatformScreen::Create() {
- return base::WrapUnique(new PlatformScreenImpl);
-}
-
-PlatformScreenImpl::PlatformScreenImpl() {}
-
-PlatformScreenImpl::~PlatformScreenImpl() {}
-
-void PlatformScreenImpl::Init() {}
-
-void PlatformScreenImpl::ConfigurePhysicalDisplay(
- const PlatformScreen::ConfiguredDisplayCallback& callback) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&FixedSizeScreenConfiguration, callback));
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/platform_screen_impl.h b/chromium/components/mus/ws/platform_screen_impl.h
deleted file mode 100644
index 166bff771b4..00000000000
--- a/chromium/components/mus/ws/platform_screen_impl.h
+++ /dev/null
@@ -1,39 +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 COMPONENTS_MUS_WS_PLATFORM_SCREEN_IMPL_H_
-#define COMPONENTS_MUS_WS_PLATFORM_SCREEN_IMPL_H_
-
-#include <stdint.h>
-
-#include "base/callback.h"
-#include "components/mus/ws/platform_screen.h"
-
-namespace gfx {
-class Rect;
-}
-
-namespace mus {
-namespace ws {
-
-// PlatformScreenImpl provides the necessary functionality to configure all
-// attached physical displays on non-ozone platforms.
-class PlatformScreenImpl : public PlatformScreen {
- public:
- PlatformScreenImpl();
- ~PlatformScreenImpl() override;
-
- private:
- // PlatformScreen.
- void Init() override;
- void ConfigurePhysicalDisplay(
- const PlatformScreen::ConfiguredDisplayCallback& callback) override;
-
- DISALLOW_COPY_AND_ASSIGN(PlatformScreenImpl);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_PLATFORM_SCREEN_IMPL_H_
diff --git a/chromium/components/mus/ws/platform_screen_impl_ozone.cc b/chromium/components/mus/ws/platform_screen_impl_ozone.cc
deleted file mode 100644
index 91f2ba249da..00000000000
--- a/chromium/components/mus/ws/platform_screen_impl_ozone.cc
+++ /dev/null
@@ -1,126 +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 "components/mus/ws/platform_screen_impl_ozone.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/memory/ptr_util.h"
-#include "base/sys_info.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "ui/display/types/display_snapshot.h"
-#include "ui/display/types/native_display_delegate.h"
-#include "ui/ozone/public/ozone_platform.h"
-
-namespace mus {
-
-namespace ws {
-namespace {
-
-// TODO(rjkroege): Remove this code once ozone oxygen has the same
-// display creation semantics as ozone drm.
-// Some ozone platforms do not configure physical displays and so do not
-// callback into this class via the implementation of NativeDisplayObserver.
-// FixedSizeScreenConfiguration() short-circuits the implementation of display
-// configuration in this case by calling the |callback| provided to
-// ConfigurePhysicalDisplay() with a hard-coded |id| and |bounds|.
-void FixedSizeScreenConfiguration(
- const PlatformScreen::ConfiguredDisplayCallback& callback) {
- callback.Run(1, gfx::Rect(1024, 768));
-}
-
-void GetDisplaysFinished(const std::vector<ui::DisplaySnapshot*>& displays) {
- // We don't really care about list of displays, we just want the snapshots
- // held by DrmDisplayManager to be updated. This only only happens when we
- // call NativeDisplayDelegate::GetDisplays(). Although, this would be a good
- // place to have PlatformScreen cache the snapshots if need be.
-}
-
-} // namespace
-
-// static
-std::unique_ptr<PlatformScreen> PlatformScreen::Create() {
- return base::WrapUnique(new PlatformScreenImplOzone);
-}
-
-PlatformScreenImplOzone::PlatformScreenImplOzone() : weak_ptr_factory_(this) {}
-
-PlatformScreenImplOzone::~PlatformScreenImplOzone() {}
-
-void PlatformScreenImplOzone::Init() {
- native_display_delegate_ =
- ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate();
- native_display_delegate_->AddObserver(this);
- native_display_delegate_->Initialize();
-}
-
-void PlatformScreenImplOzone::ConfigurePhysicalDisplay(
- const PlatformScreen::ConfiguredDisplayCallback& callback) {
-#if defined(OS_CHROMEOS)
- if (base::SysInfo::IsRunningOnChromeOS()) {
- // Kick off the configuration of the physical displays comprising the
- // |PlatformScreenImplOzone|
-
- DCHECK(native_display_delegate_) << "DefaultDisplayManager::"
- "OnConfigurationChanged requires a "
- "native_display_delegate_ to work.";
-
- native_display_delegate_->GetDisplays(
- base::Bind(&PlatformScreenImplOzone::OnDisplaysAquired,
- weak_ptr_factory_.GetWeakPtr(), callback));
-
- return;
- }
-#endif // defined(OS_CHROMEOS)
- // PostTask()ed to maximize control flow similarity with the ChromeOS case.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&FixedSizeScreenConfiguration, callback));
-}
-
-void PlatformScreenImplOzone::OnConfigurationChanged() {}
-
-// The display subsystem calls |OnDisplaysAquired| to deliver |displays|
-// describing the attached displays.
-void PlatformScreenImplOzone::OnDisplaysAquired(
- const ConfiguredDisplayCallback& callback,
- const std::vector<ui::DisplaySnapshot*>& displays) {
- DCHECK(native_display_delegate_) << "DefaultDisplayManager::"
- "OnConfigurationChanged requires a "
- "native_display_delegate_ to work.";
- CHECK(displays.size() == 1) << "Mus only supports one 1 display\n";
- gfx::Point origin;
- for (auto display : displays) {
- if (!display->native_mode()) {
- LOG(ERROR) << "Display " << display->display_id()
- << " doesn't have a native mode";
- continue;
- }
- // Setup each native display. This places a task on the DRM thread's
- // runqueue that configures the window size correctly before the call to
- // Configure.
- native_display_delegate_->Configure(
- *display, display->native_mode(), origin,
- base::Bind(&PlatformScreenImplOzone::OnDisplayConfigured,
- weak_ptr_factory_.GetWeakPtr(), callback,
- display->display_id(),
- gfx::Rect(origin, display->native_mode()->size())));
- origin.Offset(display->native_mode()->size().width(), 0);
- }
-}
-
-void PlatformScreenImplOzone::OnDisplayConfigured(
- const ConfiguredDisplayCallback& callback,
- int64_t id,
- const gfx::Rect& bounds,
- bool success) {
- if (success) {
- native_display_delegate_->GetDisplays(base::Bind(&GetDisplaysFinished));
- callback.Run(id, bounds);
- } else {
- LOG(FATAL) << "Failed to configure display at " << bounds.ToString();
- }
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/platform_screen_impl_ozone.h b/chromium/components/mus/ws/platform_screen_impl_ozone.h
deleted file mode 100644
index 55949e4b45c..00000000000
--- a/chromium/components/mus/ws/platform_screen_impl_ozone.h
+++ /dev/null
@@ -1,72 +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 COMPONENTS_MUS_WS_PLATFORM_SCREEN_IMPL_OZONE_H_
-#define COMPONENTS_MUS_WS_PLATFORM_SCREEN_IMPL_OZONE_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "components/mus/ws/platform_screen.h"
-#include "ui/display/types/native_display_observer.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace gfx {
-class Rect;
-}
-
-namespace ui {
-class NativeDisplayDelegate;
-class DisplaySnapshot;
-}
-
-namespace mus {
-namespace ws {
-
-// PlatformScreenImplOzone provides the necessary functionality to configure all
-// attached physical displays on the ozone platform.
-class PlatformScreenImplOzone : public PlatformScreen,
- public ui::NativeDisplayObserver {
- public:
- PlatformScreenImplOzone();
- ~PlatformScreenImplOzone() override;
-
- private:
- // PlatformScreen
- void Init() override; // Must not be called until after the ozone platform is
- // initialized.
- void ConfigurePhysicalDisplay(
- const ConfiguredDisplayCallback& callback) override;
-
- // TODO(rjkroege): NativeDisplayObserver is misnamed as it tracks changes in
- // the physical "Screen". Consider renaming it to NativeScreenObserver.
- // ui::NativeDisplayObserver:
- void OnConfigurationChanged() override;
-
- // Display management callback.
- void OnDisplaysAquired(const ConfiguredDisplayCallback& callback,
- const std::vector<ui::DisplaySnapshot*>& displays);
-
- // The display subsystem calls |OnDisplayConfigured| for each display that has
- // been successfully configured. This in turn calls |callback_| with the
- // identity and bounds of each physical display.
- void OnDisplayConfigured(const ConfiguredDisplayCallback& callback,
- int64_t id,
- const gfx::Rect& bounds,
- bool success);
-
- std::unique_ptr<ui::NativeDisplayDelegate> native_display_delegate_;
-
- base::WeakPtrFactory<PlatformScreenImplOzone> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(PlatformScreenImplOzone);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_PLATFORM_SCREEN_IMPL_OZONE_H_
diff --git a/chromium/components/mus/ws/scheduled_animation_group.cc b/chromium/components/mus/ws/scheduled_animation_group.cc
deleted file mode 100644
index d76b7895597..00000000000
--- a/chromium/components/mus/ws/scheduled_animation_group.cc
+++ /dev/null
@@ -1,356 +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 "components/mus/ws/scheduled_animation_group.h"
-
-#include <set>
-
-#include "components/mus/ws/server_window.h"
-
-using mus::mojom::AnimationProperty;
-
-namespace mus {
-namespace ws {
-namespace {
-
-using Sequences = std::vector<ScheduledAnimationSequence>;
-
-// Gets the value of |property| from |window| into |value|.
-void GetValueFromWindow(const ServerWindow* window,
- AnimationProperty property,
- ScheduledAnimationValue* value) {
- switch (property) {
- case AnimationProperty::NONE:
- NOTREACHED();
- break;
- case AnimationProperty::OPACITY:
- value->float_value = window->opacity();
- break;
- case AnimationProperty::TRANSFORM:
- value->transform = window->transform();
- break;
- }
-}
-
-// Sets the value of |property| from |value| into |window|.
-void SetWindowPropertyFromValue(ServerWindow* window,
- AnimationProperty property,
- const ScheduledAnimationValue& value) {
- switch (property) {
- case AnimationProperty::NONE:
- break;
- case AnimationProperty::OPACITY:
- window->SetOpacity(value.float_value);
- break;
- case AnimationProperty::TRANSFORM:
- window->SetTransform(value.transform);
- break;
- }
-}
-
-// Sets the value of |property| into |window| between two points.
-void SetWindowPropertyFromValueBetween(ServerWindow* window,
- AnimationProperty property,
- double value,
- gfx::Tween::Type tween_type,
- const ScheduledAnimationValue& start,
- const ScheduledAnimationValue& target) {
- const double tween_value = gfx::Tween::CalculateValue(tween_type, value);
- switch (property) {
- case AnimationProperty::NONE:
- break;
- case AnimationProperty::OPACITY:
- window->SetOpacity(gfx::Tween::FloatValueBetween(
- tween_value, start.float_value, target.float_value));
- break;
- case AnimationProperty::TRANSFORM:
- window->SetTransform(gfx::Tween::TransformValueBetween(
- tween_value, start.transform, target.transform));
- break;
- }
-}
-
-// TODO(mfomitchev): Use struct traits for this?
-gfx::Tween::Type AnimationTypeToTweenType(mojom::AnimationTweenType type) {
- switch (type) {
- case mojom::AnimationTweenType::LINEAR:
- return gfx::Tween::LINEAR;
- case mojom::AnimationTweenType::EASE_IN:
- return gfx::Tween::EASE_IN;
- case mojom::AnimationTweenType::EASE_OUT:
- return gfx::Tween::EASE_OUT;
- case mojom::AnimationTweenType::EASE_IN_OUT:
- return gfx::Tween::EASE_IN_OUT;
- }
- return gfx::Tween::LINEAR;
-}
-
-void ConvertToScheduledValue(const mojom::AnimationValue& transport_value,
- ScheduledAnimationValue* value) {
- value->float_value = transport_value.float_value;
- value->transform = transport_value.transform;
-}
-
-void ConvertToScheduledElement(const mojom::AnimationElement& transport_element,
- ScheduledAnimationElement* element) {
- element->property = transport_element.property;
- element->duration =
- base::TimeDelta::FromMicroseconds(transport_element.duration);
- element->tween_type = AnimationTypeToTweenType(transport_element.tween_type);
- if (transport_element.property != AnimationProperty::NONE) {
- if (transport_element.start_value.get()) {
- element->is_start_valid = true;
- ConvertToScheduledValue(*transport_element.start_value,
- &(element->start_value));
- } else {
- element->is_start_valid = false;
- }
- ConvertToScheduledValue(*transport_element.target_value,
- &(element->target_value));
- }
-}
-
-bool IsAnimationValueValid(AnimationProperty property,
- const mojom::AnimationValue& value) {
- bool result;
- switch (property) {
- case AnimationProperty::NONE:
- NOTREACHED();
- return false;
- case AnimationProperty::OPACITY:
- result = value.float_value >= 0.f && value.float_value <= 1.f;
- DVLOG_IF(1, !result) << "Invalid AnimationValue for opacity: "
- << value.float_value;
- return result;
- case AnimationProperty::TRANSFORM:
- return true;
- }
- return false;
-}
-
-bool IsAnimationElementValid(const mojom::AnimationElement& element) {
- if (element.property == AnimationProperty::NONE)
- return true; // None is a pause and doesn't need any values.
- if (element.start_value.get() &&
- !IsAnimationValueValid(element.property, *element.start_value))
- return false;
- // For all other properties we require a target.
- return element.target_value.get() &&
- IsAnimationValueValid(element.property, *element.target_value);
-}
-
-bool IsAnimationSequenceValid(const mojom::AnimationSequence& sequence) {
- if (sequence.elements.size() == 0) {
- DVLOG(1) << "Empty or null AnimationSequence - invalid.";
- return false;
- }
-
- for (size_t i = 0; i < sequence.elements.size(); ++i) {
- if (!IsAnimationElementValid(*sequence.elements[i]))
- return false;
- }
- return true;
-}
-
-bool IsAnimationGroupValid(const mojom::AnimationGroup& transport_group) {
- if (transport_group.sequences.size() == 0) {
- DVLOG(1) << "Empty or null AnimationGroup - invalid; window_id="
- << transport_group.window_id;
- return false;
- }
- for (size_t i = 0; i < transport_group.sequences.size(); ++i) {
- if (!IsAnimationSequenceValid(*transport_group.sequences[i]))
- return false;
- }
- return true;
-}
-
-// If the start value for |element| isn't valid, the value for the property
-// is obtained from |window| and placed into |element|.
-void GetStartValueFromWindowIfNecessary(const ServerWindow* window,
- ScheduledAnimationElement* element) {
- if (element->property != AnimationProperty::NONE &&
- !element->is_start_valid) {
- GetValueFromWindow(window, element->property, &(element->start_value));
- }
-}
-
-void GetScheduledAnimationProperties(const Sequences& sequences,
- std::set<AnimationProperty>* properties) {
- for (const ScheduledAnimationSequence& sequence : sequences) {
- for (const ScheduledAnimationElement& element : sequence.elements)
- properties->insert(element.property);
- }
-}
-
-// Set |window|'s specified |property| to the value resulting from running all
-// the |sequences|.
-void SetPropertyToTargetProperty(ServerWindow* window,
- mojom::AnimationProperty property,
- const Sequences& sequences) {
- // NOTE: this doesn't deal with |cycle_count| quite right, but I'm honestly
- // not sure we really want to support the same property in multiple sequences
- // animating at once so I'm not dealing.
- base::TimeDelta max_end_duration;
- std::unique_ptr<ScheduledAnimationValue> value;
- for (const ScheduledAnimationSequence& sequence : sequences) {
- base::TimeDelta duration;
- for (const ScheduledAnimationElement& element : sequence.elements) {
- if (element.property != property)
- continue;
-
- duration += element.duration;
- if (duration > max_end_duration) {
- max_end_duration = duration;
- value.reset(new ScheduledAnimationValue(element.target_value));
- }
- }
- }
- if (value.get())
- SetWindowPropertyFromValue(window, property, *value);
-}
-
-void ConvertSequenceToScheduled(
- const mojom::AnimationSequence& transport_sequence,
- base::TimeTicks now,
- ScheduledAnimationSequence* sequence) {
- sequence->run_until_stopped = transport_sequence.cycle_count == 0u;
- sequence->cycle_count = transport_sequence.cycle_count;
- DCHECK_NE(0u, transport_sequence.elements.size());
- sequence->elements.resize(transport_sequence.elements.size());
-
- base::TimeTicks element_start_time = now;
- for (size_t i = 0; i < transport_sequence.elements.size(); ++i) {
- ConvertToScheduledElement(*(transport_sequence.elements[i].get()),
- &(sequence->elements[i]));
- sequence->elements[i].start_time = element_start_time;
- sequence->duration += sequence->elements[i].duration;
- element_start_time += sequence->elements[i].duration;
- }
-}
-
-bool AdvanceSequence(ServerWindow* window,
- ScheduledAnimationSequence* sequence,
- base::TimeTicks now) {
- ScheduledAnimationElement* element =
- &(sequence->elements[sequence->current_index]);
- while (element->start_time + element->duration < now) {
- SetWindowPropertyFromValue(window, element->property,
- element->target_value);
- if (++sequence->current_index == sequence->elements.size()) {
- if (!sequence->run_until_stopped && --sequence->cycle_count == 0) {
- return false;
- }
-
- sequence->current_index = 0;
- }
- sequence->elements[sequence->current_index].start_time =
- element->start_time + element->duration;
- element = &(sequence->elements[sequence->current_index]);
- GetStartValueFromWindowIfNecessary(window, element);
-
- // It's possible for the delta between now and |last_tick_time_| to be very
- // big (could happen if machine sleeps and is woken up much later). Normally
- // the repeat count is smallish, so we don't bother optimizing it. OTOH if
- // a sequence repeats forever we optimize it lest we get stuck in this loop
- // for a very long time.
- if (sequence->run_until_stopped && sequence->current_index == 0) {
- element->start_time =
- now - base::TimeDelta::FromMicroseconds(
- (now - element->start_time).InMicroseconds() %
- sequence->duration.InMicroseconds());
- }
- }
- return true;
-}
-
-} // namespace
-
-ScheduledAnimationValue::ScheduledAnimationValue() : float_value(0) {}
-ScheduledAnimationValue::~ScheduledAnimationValue() {}
-
-ScheduledAnimationElement::ScheduledAnimationElement()
- : property(AnimationProperty::OPACITY),
- tween_type(gfx::Tween::EASE_IN),
- is_start_valid(false) {}
-ScheduledAnimationElement::ScheduledAnimationElement(
- const ScheduledAnimationElement& other) = default;
-ScheduledAnimationElement::~ScheduledAnimationElement() {}
-
-ScheduledAnimationSequence::ScheduledAnimationSequence()
- : run_until_stopped(false), cycle_count(0), current_index(0u) {}
-ScheduledAnimationSequence::ScheduledAnimationSequence(
- const ScheduledAnimationSequence& other) = default;
-ScheduledAnimationSequence::~ScheduledAnimationSequence() {}
-
-ScheduledAnimationGroup::~ScheduledAnimationGroup() {}
-
-// static
-std::unique_ptr<ScheduledAnimationGroup> ScheduledAnimationGroup::Create(
- ServerWindow* window,
- base::TimeTicks now,
- uint32_t id,
- const mojom::AnimationGroup& transport_group) {
- if (!IsAnimationGroupValid(transport_group))
- return nullptr;
-
- std::unique_ptr<ScheduledAnimationGroup> group(
- new ScheduledAnimationGroup(window, id, now));
- group->sequences_.resize(transport_group.sequences.size());
- for (size_t i = 0; i < transport_group.sequences.size(); ++i) {
- const mojom::AnimationSequence& transport_sequence(
- *(transport_group.sequences[i]));
- DCHECK_NE(0u, transport_sequence.elements.size());
- ConvertSequenceToScheduled(transport_sequence, now, &group->sequences_[i]);
- }
- return group;
-}
-
-void ScheduledAnimationGroup::ObtainStartValues() {
- for (ScheduledAnimationSequence& sequence : sequences_)
- GetStartValueFromWindowIfNecessary(window_, &(sequence.elements[0]));
-}
-
-void ScheduledAnimationGroup::SetValuesToTargetValuesForPropertiesNotIn(
- const ScheduledAnimationGroup& other) {
- std::set<AnimationProperty> our_properties;
- GetScheduledAnimationProperties(sequences_, &our_properties);
-
- std::set<AnimationProperty> other_properties;
- GetScheduledAnimationProperties(other.sequences_, &other_properties);
-
- for (AnimationProperty property : our_properties) {
- if (other_properties.count(property) == 0 &&
- property != AnimationProperty::NONE) {
- SetPropertyToTargetProperty(window_, property, sequences_);
- }
- }
-}
-
-bool ScheduledAnimationGroup::Tick(base::TimeTicks time) {
- for (Sequences::iterator i = sequences_.begin(); i != sequences_.end();) {
- if (!AdvanceSequence(window_, &(*i), time)) {
- i = sequences_.erase(i);
- continue;
- }
- const ScheduledAnimationElement& active_element(
- i->elements[i->current_index]);
- const double percent =
- (time - active_element.start_time).InMillisecondsF() /
- active_element.duration.InMillisecondsF();
- SetWindowPropertyFromValueBetween(
- window_, active_element.property, percent, active_element.tween_type,
- active_element.start_value, active_element.target_value);
- ++i;
- }
- return sequences_.empty();
-}
-
-ScheduledAnimationGroup::ScheduledAnimationGroup(ServerWindow* window,
- uint32_t id,
- base::TimeTicks time_scheduled)
- : window_(window), id_(id), time_scheduled_(time_scheduled) {}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/scheduled_animation_group.h b/chromium/components/mus/ws/scheduled_animation_group.h
deleted file mode 100644
index 2c19bcd2e09..00000000000
--- a/chromium/components/mus/ws/scheduled_animation_group.h
+++ /dev/null
@@ -1,116 +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 COMPONENTS_MUS_WS_SCHEDULED_ANIMATION_GROUP_H_
-#define COMPONENTS_MUS_WS_SCHEDULED_ANIMATION_GROUP_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/time/time.h"
-#include "components/mus/public/interfaces/animations.mojom.h"
-#include "ui/gfx/animation/tween.h"
-#include "ui/gfx/transform.h"
-
-namespace mus {
-namespace ws {
-
-class ServerWindow;
-
-struct ScheduledAnimationValue {
- ScheduledAnimationValue();
- ~ScheduledAnimationValue();
-
- float float_value;
- gfx::Transform transform;
-};
-
-struct ScheduledAnimationElement {
- ScheduledAnimationElement();
- // Needed because we call resize() vector of elements.
- ScheduledAnimationElement(const ScheduledAnimationElement& other);
- ~ScheduledAnimationElement();
-
- mojom::AnimationProperty property;
- base::TimeDelta duration;
- gfx::Tween::Type tween_type;
- bool is_start_valid;
- ScheduledAnimationValue start_value;
- ScheduledAnimationValue target_value;
- // Start time is based on scheduled time and relative to any other elements
- // in the sequence.
- base::TimeTicks start_time;
-};
-
-struct ScheduledAnimationSequence {
- ScheduledAnimationSequence();
- // Needed because we call resize() and erase() on vector of sequences.
- ScheduledAnimationSequence(const ScheduledAnimationSequence& other);
- ~ScheduledAnimationSequence();
-
- bool run_until_stopped;
- std::vector<ScheduledAnimationElement> elements;
-
- // Sum of the duration of all elements. This does not take into account
- // |cycle_count|.
- base::TimeDelta duration;
-
- // The following values are updated as the animation progresses.
-
- // Number of cycles remaining. This is only used if |run_until_stopped| is
- // false.
- uint32_t cycle_count;
-
- // Index into |elements| of the element currently animating.
- size_t current_index;
-};
-
-// Corresponds to a mojom::AnimationGroup and is responsible for running the
-// actual animation.
-class ScheduledAnimationGroup {
- public:
- ~ScheduledAnimationGroup();
-
- // Returns a new ScheduledAnimationGroup from the supplied parameters, or
- // null if |transport_group| isn't valid.
- static std::unique_ptr<ScheduledAnimationGroup> Create(
- ServerWindow* window,
- base::TimeTicks now,
- uint32_t id,
- const mojom::AnimationGroup& transport_group);
-
- uint32_t id() const { return id_; }
-
- // Gets the start value for any elements that don't have an explicit start.
- // value.
- void ObtainStartValues();
-
- // Sets the values of any properties that are not in |other| to their final
- // value.
- void SetValuesToTargetValuesForPropertiesNotIn(
- const ScheduledAnimationGroup& other);
-
- // Advances the group. |time| is the current time. Returns true if the group
- // is done (nothing left to animate).
- bool Tick(base::TimeTicks time);
-
- ServerWindow* window() { return window_; }
-
- private:
- ScheduledAnimationGroup(ServerWindow* window,
- uint32_t id,
- base::TimeTicks time_scheduled);
-
- ServerWindow* window_;
- const uint32_t id_;
- base::TimeTicks time_scheduled_;
- std::vector<ScheduledAnimationSequence> sequences_;
-
- DISALLOW_COPY_AND_ASSIGN(ScheduledAnimationGroup);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_SCHEDULED_ANIMATION_GROUP_H_
diff --git a/chromium/components/mus/ws/scheduled_animation_group_unittest.cc b/chromium/components/mus/ws/scheduled_animation_group_unittest.cc
deleted file mode 100644
index 27c2f76c9b7..00000000000
--- a/chromium/components/mus/ws/scheduled_animation_group_unittest.cc
+++ /dev/null
@@ -1,92 +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 "components/mus/ws/scheduled_animation_group.h"
-
-#include "components/mus/public/interfaces/animations.mojom.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using mus::mojom::AnimationProperty;
-using mus::mojom::AnimationTweenType;
-using mus::mojom::AnimationGroup;
-using mus::mojom::AnimationSequence;
-using mus::mojom::AnimationElement;
-using mus::mojom::AnimationValue;
-
-namespace mus {
-namespace ws {
-namespace {
-
-bool IsAnimationGroupValid(const AnimationGroup& transport_group) {
- TestServerWindowDelegate window_delegate;
- ServerWindow window(&window_delegate, WindowId());
- std::unique_ptr<ScheduledAnimationGroup> group(
- ScheduledAnimationGroup::Create(&window, base::TimeTicks::Now(), 1,
- transport_group));
- return group.get() != nullptr;
-}
-
-} // namespace
-
-TEST(ScheduledAnimationGroupTest, IsAnimationGroupValid) {
- AnimationGroup group;
-
- // AnimationGroup with no sequences is not valid.
- EXPECT_FALSE(IsAnimationGroupValid(group));
-
- group.sequences.push_back(AnimationSequence::New());
-
- // Sequence with no elements is not valid.
- EXPECT_FALSE(IsAnimationGroupValid(group));
-
- AnimationSequence& sequence = *(group.sequences[0]);
- sequence.elements.push_back(AnimationElement::New());
- AnimationElement& element = *(sequence.elements[0]);
- element.property = AnimationProperty::OPACITY;
- element.tween_type = AnimationTweenType::LINEAR;
-
- // Element with no target_value is not valid.
- EXPECT_FALSE(IsAnimationGroupValid(group));
-
- // Opacity must be between 0 and 1.
- element.target_value = AnimationValue::New();
- element.target_value->float_value = 2.5f;
- EXPECT_FALSE(IsAnimationGroupValid(group));
-
- element.target_value->float_value = .5f;
- EXPECT_TRUE(IsAnimationGroupValid(group));
-
- // Bogus start value.
- element.start_value = AnimationValue::New();
- element.start_value->float_value = 2.5f;
- EXPECT_FALSE(IsAnimationGroupValid(group));
-
- element.start_value->float_value = .5f;
- EXPECT_TRUE(IsAnimationGroupValid(group));
-
- // All transforms are valid.
- element.property = AnimationProperty::TRANSFORM;
- EXPECT_TRUE(IsAnimationGroupValid(group));
-
- // Add another empty sequence, should be invalid again.
- group.sequences.push_back(AnimationSequence::New());
- EXPECT_FALSE(IsAnimationGroupValid(group));
-
- AnimationSequence& sequence2 = *(group.sequences[1]);
- sequence2.elements.push_back(AnimationElement::New());
- AnimationElement& element2 = *(sequence2.elements[0]);
- element2.property = AnimationProperty::OPACITY;
- element2.tween_type = AnimationTweenType::LINEAR;
-
- // Element with no target_value is not valid.
- EXPECT_FALSE(IsAnimationGroupValid(group));
-
- element2.property = AnimationProperty::NONE;
- EXPECT_TRUE(IsAnimationGroupValid(group));
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/server_window.cc b/chromium/components/mus/ws/server_window.cc
deleted file mode 100644
index f6a9304a03b..00000000000
--- a/chromium/components/mus/ws/server_window.cc
+++ /dev/null
@@ -1,470 +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 "components/mus/ws/server_window.h"
-
-#include <inttypes.h>
-#include <stddef.h>
-
-#include "base/strings/stringprintf.h"
-#include "components/mus/common/transient_window_utils.h"
-#include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "components/mus/ws/server_window_delegate.h"
-#include "components/mus/ws/server_window_observer.h"
-#include "components/mus/ws/server_window_surface_manager.h"
-
-namespace mus {
-
-namespace ws {
-
-ServerWindow::ServerWindow(ServerWindowDelegate* delegate, const WindowId& id)
- : ServerWindow(delegate, id, Properties()) {}
-
-ServerWindow::ServerWindow(ServerWindowDelegate* delegate,
- const WindowId& id,
- const Properties& properties)
- : delegate_(delegate),
- id_(id),
- parent_(nullptr),
- stacking_target_(nullptr),
- transient_parent_(nullptr),
- is_modal_(false),
- visible_(false),
- cursor_id_(mojom::Cursor::CURSOR_NULL),
- non_client_cursor_id_(mojom::Cursor::CURSOR_NULL),
- opacity_(1),
- can_focus_(true),
- properties_(properties),
- // Don't notify newly added observers during notification. This causes
- // problems for code that adds an observer as part of an observer
- // notification (such as ServerWindowDrawTracker).
- observers_(
- base::ObserverList<ServerWindowObserver>::NOTIFY_EXISTING_ONLY) {
- DCHECK(delegate); // Must provide a delegate.
-}
-
-ServerWindow::~ServerWindow() {
- FOR_EACH_OBSERVER(ServerWindowObserver, observers_, OnWindowDestroying(this));
-
- if (transient_parent_)
- transient_parent_->RemoveTransientWindow(this);
-
- // Destroy transient children, only after we've removed ourselves from our
- // parent, as destroying an active transient child may otherwise attempt to
- // refocus us.
- Windows transient_children(transient_children_);
- STLDeleteElements(&transient_children);
- DCHECK(transient_children_.empty());
-
- while (!children_.empty())
- children_.front()->parent()->Remove(children_.front());
-
- if (parent_)
- parent_->Remove(this);
-
- FOR_EACH_OBSERVER(ServerWindowObserver, observers_, OnWindowDestroyed(this));
-}
-
-void ServerWindow::AddObserver(ServerWindowObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void ServerWindow::RemoveObserver(ServerWindowObserver* observer) {
- DCHECK(observers_.HasObserver(observer));
- observers_.RemoveObserver(observer);
-}
-
-void ServerWindow::CreateSurface(mojom::SurfaceType surface_type,
- mojo::InterfaceRequest<mojom::Surface> request,
- mojom::SurfaceClientPtr client) {
- GetOrCreateSurfaceManager()->CreateSurface(surface_type, std::move(request),
- std::move(client));
-}
-
-void ServerWindow::Add(ServerWindow* child) {
- // We assume validation checks happened already.
- DCHECK(child);
- DCHECK(child != this);
- DCHECK(!child->Contains(this));
- if (child->parent() == this) {
- if (children_.size() == 1)
- return; // Already in the right position.
- child->Reorder(children_.back(), mojom::OrderDirection::ABOVE);
- return;
- }
-
- ServerWindow* old_parent = child->parent();
- FOR_EACH_OBSERVER(ServerWindowObserver, child->observers_,
- OnWillChangeWindowHierarchy(child, this, old_parent));
-
- if (child->parent())
- child->parent()->RemoveImpl(child);
-
- child->parent_ = this;
- children_.push_back(child);
-
- // Stack the child properly if it is a transient child of a sibling.
- if (child->transient_parent_ && child->transient_parent_->parent() == this)
- RestackTransientDescendants(child->transient_parent_, &GetStackingTarget,
- &ReorderImpl);
-
- FOR_EACH_OBSERVER(ServerWindowObserver, child->observers_,
- OnWindowHierarchyChanged(child, this, old_parent));
-}
-
-void ServerWindow::Remove(ServerWindow* child) {
- // We assume validation checks happened else where.
- DCHECK(child);
- DCHECK(child != this);
- DCHECK(child->parent() == this);
-
- FOR_EACH_OBSERVER(ServerWindowObserver, child->observers_,
- OnWillChangeWindowHierarchy(child, nullptr, this));
- RemoveImpl(child);
-
- // Stack the child properly if it is a transient child of a sibling.
- if (child->transient_parent_ && child->transient_parent_->parent() == this)
- RestackTransientDescendants(child->transient_parent_, &GetStackingTarget,
- &ReorderImpl);
-
- FOR_EACH_OBSERVER(ServerWindowObserver, child->observers_,
- OnWindowHierarchyChanged(child, nullptr, this));
-}
-
-void ServerWindow::Reorder(ServerWindow* relative,
- mojom::OrderDirection direction) {
- ReorderImpl(this, relative, direction);
-}
-
-void ServerWindow::StackChildAtBottom(ServerWindow* child) {
- // There's nothing to do if the child is already at the bottom.
- if (children_.size() <= 1 || child == children_.front())
- return;
- child->Reorder(children_.front(), mojom::OrderDirection::BELOW);
-}
-
-void ServerWindow::StackChildAtTop(ServerWindow* child) {
- // There's nothing to do if the child is already at the top.
- if (children_.size() <= 1 || child == children_.back())
- return;
- child->Reorder(children_.back(), mojom::OrderDirection::ABOVE);
-}
-
-void ServerWindow::SetBounds(const gfx::Rect& bounds) {
- if (bounds_ == bounds)
- return;
-
- // TODO(fsamuel): figure out how will this work with CompositorFrames.
-
- const gfx::Rect old_bounds = bounds_;
- bounds_ = bounds;
- FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
- OnWindowBoundsChanged(this, old_bounds, bounds));
-}
-
-void ServerWindow::SetClientArea(
- const gfx::Insets& insets,
- const std::vector<gfx::Rect>& additional_client_areas) {
- if (client_area_ == insets &&
- additional_client_areas == additional_client_areas_) {
- return;
- }
-
- additional_client_areas_ = additional_client_areas;
- client_area_ = insets;
- FOR_EACH_OBSERVER(
- ServerWindowObserver, observers_,
- OnWindowClientAreaChanged(this, insets, additional_client_areas));
-}
-
-void ServerWindow::SetHitTestMask(const gfx::Rect& mask) {
- hit_test_mask_.reset(new gfx::Rect(mask));
-}
-
-void ServerWindow::ClearHitTestMask() {
- hit_test_mask_.reset();
-}
-
-const ServerWindow* ServerWindow::GetRoot() const {
- return delegate_->GetRootWindow(this);
-}
-
-std::vector<const ServerWindow*> ServerWindow::GetChildren() const {
- std::vector<const ServerWindow*> children;
- children.reserve(children_.size());
- for (size_t i = 0; i < children_.size(); ++i)
- children.push_back(children_[i]);
- return children;
-}
-
-std::vector<ServerWindow*> ServerWindow::GetChildren() {
- // TODO(sky): rename to children() and fix return type.
- return children_;
-}
-
-ServerWindow* ServerWindow::GetChildWindow(const WindowId& window_id) {
- if (id_ == window_id)
- return this;
-
- for (ServerWindow* child : children_) {
- ServerWindow* window = child->GetChildWindow(window_id);
- if (window)
- return window;
- }
-
- return nullptr;
-}
-
-bool ServerWindow::AddTransientWindow(ServerWindow* child) {
- // A system modal window cannot become a transient child.
- if (child->is_modal() && !child->transient_parent())
- return false;
-
- if (child->transient_parent())
- child->transient_parent()->RemoveTransientWindow(child);
-
- DCHECK(std::find(transient_children_.begin(), transient_children_.end(),
- child) == transient_children_.end());
- transient_children_.push_back(child);
- child->transient_parent_ = this;
-
- // Restack |child| properly above its transient parent, if they share the same
- // parent.
- if (child->parent() == parent())
- RestackTransientDescendants(this, &GetStackingTarget, &ReorderImpl);
-
- FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
- OnTransientWindowAdded(this, child));
- return true;
-}
-
-void ServerWindow::RemoveTransientWindow(ServerWindow* child) {
- Windows::iterator i =
- std::find(transient_children_.begin(), transient_children_.end(), child);
- DCHECK(i != transient_children_.end());
- transient_children_.erase(i);
- DCHECK_EQ(this, child->transient_parent());
- child->transient_parent_ = nullptr;
-
- // If |child| and its former transient parent share the same parent, |child|
- // should be restacked properly so it is not among transient children of its
- // former parent, anymore.
- if (parent() == child->parent())
- RestackTransientDescendants(this, &GetStackingTarget, &ReorderImpl);
-
- FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
- OnTransientWindowRemoved(this, child));
-}
-
-void ServerWindow::SetModal() {
- is_modal_ = true;
-}
-
-bool ServerWindow::Contains(const ServerWindow* window) const {
- for (const ServerWindow* parent = window; parent; parent = parent->parent_) {
- if (parent == this)
- return true;
- }
- return false;
-}
-
-void ServerWindow::SetVisible(bool value) {
- if (visible_ == value)
- return;
-
- FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
- OnWillChangeWindowVisibility(this));
- visible_ = value;
- FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
- OnWindowVisibilityChanged(this));
-}
-
-void ServerWindow::SetOpacity(float value) {
- if (value == opacity_)
- return;
- float old_opacity = opacity_;
- opacity_ = value;
- delegate_->OnScheduleWindowPaint(this);
- FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
- OnWindowOpacityChanged(this, old_opacity, opacity_));
-}
-
-void ServerWindow::SetPredefinedCursor(mus::mojom::Cursor value) {
- if (value == cursor_id_)
- return;
- cursor_id_ = value;
- FOR_EACH_OBSERVER(
- ServerWindowObserver, observers_,
- OnWindowPredefinedCursorChanged(this, static_cast<int32_t>(value)));
-}
-
-void ServerWindow::SetNonClientCursor(mus::mojom::Cursor value) {
- if (value == non_client_cursor_id_)
- return;
- non_client_cursor_id_ = value;
- FOR_EACH_OBSERVER(
- ServerWindowObserver, observers_,
- OnWindowNonClientCursorChanged(this, static_cast<int32_t>(value)));
-}
-
-void ServerWindow::SetTransform(const gfx::Transform& transform) {
- if (transform_ == transform)
- return;
-
- transform_ = transform;
- delegate_->OnScheduleWindowPaint(this);
-}
-
-void ServerWindow::SetProperty(const std::string& name,
- const std::vector<uint8_t>* value) {
- auto it = properties_.find(name);
- if (it != properties_.end()) {
- if (value && it->second == *value)
- return;
- } else if (!value) {
- // This property isn't set in |properties_| and |value| is nullptr, so
- // there's
- // no change.
- return;
- }
-
- if (value) {
- properties_[name] = *value;
- } else if (it != properties_.end()) {
- properties_.erase(it);
- }
-
- FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
- OnWindowSharedPropertyChanged(this, name, value));
-}
-
-std::string ServerWindow::GetName() const {
- auto it = properties_.find(mojom::WindowManager::kName_Property);
- if (it == properties_.end())
- return std::string();
- return std::string(it->second.begin(), it->second.end());
-}
-
-void ServerWindow::SetTextInputState(const ui::TextInputState& state) {
- const bool changed = !(text_input_state_ == state);
- if (changed) {
- text_input_state_ = state;
- // keyboard even if the state is not changed. So we have to notify
- // |observers_|.
- FOR_EACH_OBSERVER(ServerWindowObserver, observers_,
- OnWindowTextInputStateChanged(this, state));
- }
-}
-
-bool ServerWindow::IsDrawn() const {
- const ServerWindow* root = delegate_->GetRootWindow(this);
- if (!root || !root->visible())
- return false;
- const ServerWindow* window = this;
- while (window && window != root && window->visible())
- window = window->parent();
- return root == window;
-}
-
-void ServerWindow::DestroySurfacesScheduledForDestruction() {
- if (!surface_manager_)
- return;
- ServerWindowSurface* surface = surface_manager_->GetDefaultSurface();
- if (surface)
- surface->DestroySurfacesScheduledForDestruction();
-
- surface = surface_manager_->GetUnderlaySurface();
- if (surface)
- surface->DestroySurfacesScheduledForDestruction();
-}
-
-ServerWindowSurfaceManager* ServerWindow::GetOrCreateSurfaceManager() {
- if (!surface_manager_.get())
- surface_manager_.reset(new ServerWindowSurfaceManager(this));
- return surface_manager_.get();
-}
-
-void ServerWindow::SetUnderlayOffset(const gfx::Vector2d& offset) {
- if (offset == underlay_offset_)
- return;
-
- underlay_offset_ = offset;
- delegate_->OnScheduleWindowPaint(this);
-}
-
-#if !defined(NDEBUG)
-std::string ServerWindow::GetDebugWindowHierarchy() const {
- std::string result;
- BuildDebugInfo(std::string(), &result);
- return result;
-}
-
-void ServerWindow::BuildDebugInfo(const std::string& depth,
- std::string* result) const {
- std::string name = GetName();
- *result += base::StringPrintf(
- "%sid=%d,%d visible=%s bounds=%d,%d %dx%d %s\n", depth.c_str(),
- static_cast<int>(id_.client_id), static_cast<int>(id_.window_id),
- visible_ ? "true" : "false", bounds_.x(), bounds_.y(), bounds_.width(),
- bounds_.height(), !name.empty() ? name.c_str() : "(no name)");
- for (const ServerWindow* child : children_)
- child->BuildDebugInfo(depth + " ", result);
-}
-#endif
-
-void ServerWindow::RemoveImpl(ServerWindow* window) {
- window->parent_ = nullptr;
- children_.erase(std::find(children_.begin(), children_.end(), window));
-}
-
-void ServerWindow::OnStackingChanged() {
- if (stacking_target_) {
- Windows::const_iterator window_i = std::find(
- parent()->children().begin(), parent()->children().end(), this);
- DCHECK(window_i != parent()->children().end());
- if (window_i != parent()->children().begin() &&
- (*(window_i - 1) == stacking_target_)) {
- return;
- }
- }
- RestackTransientDescendants(this, &GetStackingTarget, &ReorderImpl);
-}
-
-// static
-void ServerWindow::ReorderImpl(ServerWindow* window,
- ServerWindow* relative,
- mojom::OrderDirection direction) {
- DCHECK(relative);
- DCHECK_NE(window, relative);
- DCHECK_EQ(window->parent(), relative->parent());
-
- if (!AdjustStackingForTransientWindows(&window, &relative, &direction,
- window->stacking_target_))
- return;
-
- window->parent_->children_.erase(std::find(window->parent_->children_.begin(),
- window->parent_->children_.end(),
- window));
- Windows::iterator i = std::find(window->parent_->children_.begin(),
- window->parent_->children_.end(), relative);
- if (direction == mojom::OrderDirection::ABOVE) {
- DCHECK(i != window->parent_->children_.end());
- window->parent_->children_.insert(++i, window);
- } else if (direction == mojom::OrderDirection::BELOW) {
- DCHECK(i != window->parent_->children_.end());
- window->parent_->children_.insert(i, window);
- }
- FOR_EACH_OBSERVER(ServerWindowObserver, window->observers_,
- OnWindowReordered(window, relative, direction));
- window->OnStackingChanged();
-}
-
-// static
-ServerWindow** ServerWindow::GetStackingTarget(ServerWindow* window) {
- return &window->stacking_target_;
-}
-
-} // namespace ws
-
-} // namespace mus
diff --git a/chromium/components/mus/ws/server_window.h b/chromium/components/mus/ws/server_window.h
deleted file mode 100644
index 75f4f081406..00000000000
--- a/chromium/components/mus/ws/server_window.h
+++ /dev/null
@@ -1,249 +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 COMPONENTS_MUS_WS_SERVER_WINDOW_H_
-#define COMPONENTS_MUS_WS_SERVER_WINDOW_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/mus/public/interfaces/surface.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/ws/ids.h"
-#include "components/mus/ws/server_window_surface.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/transform.h"
-#include "ui/platform_window/text_input_state.h"
-
-namespace mus {
-namespace ws {
-
-class ServerWindowDelegate;
-class ServerWindowObserver;
-class ServerWindowSurfaceManager;
-
-// Server side representation of a window. Delegate is informed of interesting
-// events.
-//
-// It is assumed that all functions that mutate the tree have validated the
-// mutation is possible before hand. For example, Reorder() assumes the supplied
-// window is a child and not already in position.
-//
-// ServerWindows do not own their children. If you delete a window that has
-// children the children are implicitly removed. Similarly if a window has a
-// parent and the window is deleted the deleted window is implicitly removed
-// from the parent.
-class ServerWindow {
- public:
- using Properties = std::map<std::string, std::vector<uint8_t>>;
- using Windows = std::vector<ServerWindow*>;
-
- ServerWindow(ServerWindowDelegate* delegate, const WindowId& id);
- ServerWindow(ServerWindowDelegate* delegate,
- const WindowId& id,
- const Properties& properties);
- ~ServerWindow();
-
- void AddObserver(ServerWindowObserver* observer);
- void RemoveObserver(ServerWindowObserver* observer);
-
- // Creates a new surface of the specified type, replacing the existing.
- void CreateSurface(mojom::SurfaceType surface_type,
- mojo::InterfaceRequest<mojom::Surface> request,
- mojom::SurfaceClientPtr client);
-
- const WindowId& id() const { return id_; }
-
- void Add(ServerWindow* child);
- void Remove(ServerWindow* child);
- void Reorder(ServerWindow* relative, mojom::OrderDirection diretion);
- void StackChildAtBottom(ServerWindow* child);
- void StackChildAtTop(ServerWindow* child);
-
- const gfx::Rect& bounds() const { return bounds_; }
- // Sets the bounds. If the size changes this implicitly resets the client
- // area to fill the whole bounds.
- void SetBounds(const gfx::Rect& bounds);
-
- const std::vector<gfx::Rect>& additional_client_areas() const {
- return additional_client_areas_;
- }
- const gfx::Insets& client_area() const { return client_area_; }
- void SetClientArea(const gfx::Insets& insets,
- const std::vector<gfx::Rect>& additional_client_areas);
-
- const gfx::Rect* hit_test_mask() const { return hit_test_mask_.get(); }
- void SetHitTestMask(const gfx::Rect& mask);
- void ClearHitTestMask();
-
- int32_t cursor() const { return static_cast<int32_t>(cursor_id_); }
- int32_t non_client_cursor() const {
- return static_cast<int32_t>(non_client_cursor_id_);
- }
-
- const ServerWindow* parent() const { return parent_; }
- ServerWindow* parent() { return parent_; }
-
- const ServerWindow* GetRoot() const;
- ServerWindow* GetRoot() {
- return const_cast<ServerWindow*>(
- const_cast<const ServerWindow*>(this)->GetRoot());
- }
-
- std::vector<const ServerWindow*> GetChildren() const;
- std::vector<ServerWindow*> GetChildren();
- const Windows& children() const { return children_; }
-
- // Returns the ServerWindow object with the provided |id| if it lies in a
- // subtree of |this|.
- ServerWindow* GetChildWindow(const WindowId& id);
-
- // Transient window management.
- // Adding transient child fails if the child window is modal to system.
- bool AddTransientWindow(ServerWindow* child);
- void RemoveTransientWindow(ServerWindow* child);
-
- ServerWindow* transient_parent() { return transient_parent_; }
- const ServerWindow* transient_parent() const { return transient_parent_; }
-
- const Windows& transient_children() const { return transient_children_; }
-
- bool is_modal() const { return is_modal_; }
- void SetModal();
-
- // Returns true if this contains |window| or is |window|.
- bool Contains(const ServerWindow* window) const;
-
- // Returns the visibility requested by this window. IsDrawn() returns whether
- // the window is actually visible on screen.
- bool visible() const { return visible_; }
- void SetVisible(bool value);
-
- float opacity() const { return opacity_; }
- void SetOpacity(float value);
-
- void SetPredefinedCursor(mus::mojom::Cursor cursor_id);
- void SetNonClientCursor(mus::mojom::Cursor cursor_id);
-
- const gfx::Transform& transform() const { return transform_; }
- void SetTransform(const gfx::Transform& transform);
-
- const std::map<std::string, std::vector<uint8_t>>& properties() const {
- return properties_;
- }
- void SetProperty(const std::string& name, const std::vector<uint8_t>* value);
-
- std::string GetName() const;
-
- void SetTextInputState(const ui::TextInputState& state);
- const ui::TextInputState& text_input_state() const {
- return text_input_state_;
- }
-
- void set_can_focus(bool can_focus) { can_focus_ = can_focus; }
- bool can_focus() const { return can_focus_; }
-
- // Returns true if this window is attached to a root and all ancestors are
- // visible.
- bool IsDrawn() const;
-
- // Called when its appropriate to destroy surfaces scheduled for destruction.
- void DestroySurfacesScheduledForDestruction();
-
- const gfx::Insets& extended_hit_test_region() const {
- return extended_hit_test_region_;
- }
- void set_extended_hit_test_region(const gfx::Insets& insets) {
- extended_hit_test_region_ = insets;
- }
-
- ServerWindowSurfaceManager* GetOrCreateSurfaceManager();
- ServerWindowSurfaceManager* surface_manager() {
- return surface_manager_.get();
- }
- const ServerWindowSurfaceManager* surface_manager() const {
- return surface_manager_.get();
- }
-
- // Offset of the underlay from the the window bounds (used for shadows).
- const gfx::Vector2d& underlay_offset() const { return underlay_offset_; }
- void SetUnderlayOffset(const gfx::Vector2d& offset);
-
- ServerWindowDelegate* delegate() { return delegate_; }
-
-#if !defined(NDEBUG)
- std::string GetDebugWindowHierarchy() const;
- void BuildDebugInfo(const std::string& depth, std::string* result) const;
-#endif
-
- private:
- // Implementation of removing a window. Doesn't send any notification.
- void RemoveImpl(ServerWindow* window);
-
- // Called when this window's stacking order among its siblings is changed.
- void OnStackingChanged();
-
- static void ReorderImpl(ServerWindow* window,
- ServerWindow* relative,
- mojom::OrderDirection diretion);
-
- // Returns a pointer to the stacking target that can be used by
- // RestackTransientDescendants.
- static ServerWindow** GetStackingTarget(ServerWindow* window);
-
- ServerWindowDelegate* delegate_;
- const WindowId id_;
- ServerWindow* parent_;
- Windows children_;
-
- // Transient window management.
- // If non-null we're actively restacking transient as the result of a
- // transient ancestor changing.
- ServerWindow* stacking_target_;
- ServerWindow* transient_parent_;
- Windows transient_children_;
-
- bool is_modal_;
- bool visible_;
- gfx::Rect bounds_;
- gfx::Insets client_area_;
- std::vector<gfx::Rect> additional_client_areas_;
- std::unique_ptr<ServerWindowSurfaceManager> surface_manager_;
- mojom::Cursor cursor_id_;
- mojom::Cursor non_client_cursor_id_;
- float opacity_;
- bool can_focus_;
- gfx::Transform transform_;
- ui::TextInputState text_input_state_;
-
- Properties properties_;
-
- gfx::Vector2d underlay_offset_;
-
- // The hit test for windows extends outside the bounds of the window by this
- // amount.
- gfx::Insets extended_hit_test_region_;
-
- // Mouse events outside the hit test mask don't hit the window. An empty mask
- // means all events miss the window. If null there is no mask.
- std::unique_ptr<gfx::Rect> hit_test_mask_;
-
- base::ObserverList<ServerWindowObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(ServerWindow);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_SERVER_WINDOW_H_
diff --git a/chromium/components/mus/ws/server_window_delegate.h b/chromium/components/mus/ws/server_window_delegate.h
deleted file mode 100644
index 24d6bbd0daa..00000000000
--- a/chromium/components/mus/ws/server_window_delegate.h
+++ /dev/null
@@ -1,46 +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 COMPONENTS_MUS_WS_SERVER_WINDOW_DELEGATE_H_
-#define COMPONENTS_MUS_WS_SERVER_WINDOW_DELEGATE_H_
-
-#include <memory>
-
-#include "components/mus/public/interfaces/mus_constants.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-
-namespace mus {
-
-class SurfacesState;
-
-namespace ws {
-
-struct ClientWindowId;
-class ServerWindow;
-struct WindowId;
-
-class ServerWindowDelegate {
- public:
- virtual SurfacesState* GetSurfacesState() = 0;
-
- virtual void OnScheduleWindowPaint(ServerWindow* window) = 0;
-
- // Returns the root of the window tree to which this |window| is attached.
- // Returns null if this window is not attached up through to a root window.
- virtual const ServerWindow* GetRootWindow(
- const ServerWindow* window) const = 0;
-
- // Schedules a callback to DestroySurfacesScheduledForDestruction() at the
- // appropriate time, which may be synchronously.
- virtual void ScheduleSurfaceDestruction(ServerWindow* window) = 0;
-
- protected:
- virtual ~ServerWindowDelegate() {}
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_SERVER_WINDOW_DELEGATE_H_
diff --git a/chromium/components/mus/ws/server_window_drawn_tracker.cc b/chromium/components/mus/ws/server_window_drawn_tracker.cc
deleted file mode 100644
index cdbca8ccddf..00000000000
--- a/chromium/components/mus/ws/server_window_drawn_tracker.cc
+++ /dev/null
@@ -1,136 +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 "components/mus/ws/server_window_drawn_tracker.h"
-
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_drawn_tracker_observer.h"
-
-namespace mus {
-
-namespace ws {
-
-ServerWindowDrawnTracker::ServerWindowDrawnTracker(
- ServerWindow* window,
- ServerWindowDrawnTrackerObserver* observer)
- : window_(window), observer_(observer), drawn_(window->IsDrawn()) {
- AddObservers();
-}
-
-ServerWindowDrawnTracker::~ServerWindowDrawnTracker() {
- RemoveObservers();
-}
-
-void ServerWindowDrawnTracker::SetDrawn(ServerWindow* ancestor, bool drawn) {
- // If |windows_| is empty when this code runs, that means |window_| has been
- // destroyed. So set |window_| to nullptr, but make sure the right value is
- // sent to OnDrawnStateChanged().
- ServerWindow* window = window_;
- if (windows_.empty())
- window_ = nullptr;
-
- if (drawn == drawn_)
- return;
-
- drawn_ = drawn;
- observer_->OnDrawnStateChanged(ancestor, window, drawn);
-}
-
-void ServerWindowDrawnTracker::AddObservers() {
- if (!window_)
- return;
-
- for (ServerWindow* v = window_; v; v = v->parent()) {
- v->AddObserver(this);
- windows_.insert(v);
- }
-}
-
-void ServerWindowDrawnTracker::RemoveObservers() {
- for (ServerWindow* window : windows_)
- window->RemoveObserver(this);
-
- windows_.clear();
-}
-
-void ServerWindowDrawnTracker::OnWindowDestroying(ServerWindow* window) {
- if (!drawn_)
- return;
- observer_->OnDrawnStateWillChange(window->parent(), window_, false);
-}
-
-void ServerWindowDrawnTracker::OnWindowDestroyed(ServerWindow* window) {
- // As windows are removed before being destroyed, resulting in
- // OnWindowHierarchyChanged() and us removing ourself as an observer, the only
- // window we should ever get notified of destruction on is |window_|.
- DCHECK_EQ(window, window_);
- RemoveObservers();
- SetDrawn(nullptr, false);
-}
-
-void ServerWindowDrawnTracker::OnWillChangeWindowHierarchy(
- ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) {
- bool new_is_drawn = new_parent && new_parent->IsDrawn();
- if (new_is_drawn) {
- for (ServerWindow* w = window_; new_is_drawn && w != old_parent;
- w = w->parent()) {
- new_is_drawn = w->visible();
- }
- }
- if (drawn_ != new_is_drawn) {
- observer_->OnDrawnStateWillChange(new_is_drawn ? nullptr : old_parent,
- window_, new_is_drawn);
- }
-}
-
-void ServerWindowDrawnTracker::OnWindowHierarchyChanged(
- ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) {
- RemoveObservers();
- AddObservers();
- const bool is_drawn = window_->IsDrawn();
- SetDrawn(is_drawn ? nullptr : old_parent, is_drawn);
-}
-
-void ServerWindowDrawnTracker::OnWillChangeWindowVisibility(
- ServerWindow* window) {
- bool will_change = false;
- if (drawn_) {
- // If |window_| is currently drawn, then any change of visibility of the
- // windows will toggle the drawn status.
- will_change = true;
- } else {
- // If |window| is currently visible, then it's becoming invisible, and so
- // |window_| will remain not drawn.
- if (window->visible()) {
- will_change = false;
- } else {
- bool is_drawn = (window->GetRoot() == window) ||
- (window->parent() && window->parent()->IsDrawn());
- if (is_drawn) {
- for (ServerWindow* w = window_; is_drawn && w != window;
- w = w->parent())
- is_drawn = w->visible();
- }
- will_change = drawn_ != is_drawn;
- }
- }
- if (will_change) {
- bool new_is_drawn = !drawn_;
- observer_->OnDrawnStateWillChange(new_is_drawn ? nullptr : window->parent(),
- window_, new_is_drawn);
- }
-}
-
-void ServerWindowDrawnTracker::OnWindowVisibilityChanged(ServerWindow* window) {
- const bool is_drawn = window_->IsDrawn();
- SetDrawn(is_drawn ? nullptr : window->parent(), is_drawn);
-}
-
-} // namespace ws
-
-} // namespace mus
diff --git a/chromium/components/mus/ws/server_window_drawn_tracker.h b/chromium/components/mus/ws/server_window_drawn_tracker.h
deleted file mode 100644
index 36f2de27590..00000000000
--- a/chromium/components/mus/ws/server_window_drawn_tracker.h
+++ /dev/null
@@ -1,65 +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 COMPONENTS_MUS_WS_SERVER_WINDOW_DRAWN_TRACKER_H_
-#define COMPONENTS_MUS_WS_SERVER_WINDOW_DRAWN_TRACKER_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "components/mus/ws/server_window_observer.h"
-
-namespace mus {
-
-namespace ws {
-
-class ServerWindowDrawnTrackerObserver;
-
-// ServerWindowDrawnTracker notifies its observer any time the drawn state of
-// the supplied window changes.
-//
-// NOTE: you must ensure this class is destroyed before the root.
-class ServerWindowDrawnTracker : public ServerWindowObserver {
- public:
- ServerWindowDrawnTracker(ServerWindow* window,
- ServerWindowDrawnTrackerObserver* observer);
- ~ServerWindowDrawnTracker() override;
-
- ServerWindow* window() { return window_; }
-
- private:
- void SetDrawn(ServerWindow* ancestor, bool drawn);
-
- // Adds |this| as an observer to |window_| and its ancestors.
- void AddObservers();
-
- // Stops observerving any windows we added as an observer in AddObservers().
- void RemoveObservers();
-
- // ServerWindowObserver:
- void OnWindowDestroying(ServerWindow* window) override;
- void OnWindowDestroyed(ServerWindow* window) override;
- void OnWillChangeWindowHierarchy(ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) override;
- void OnWindowHierarchyChanged(ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) override;
- void OnWillChangeWindowVisibility(ServerWindow* window) override;
- void OnWindowVisibilityChanged(ServerWindow* window) override;
-
- ServerWindow* window_;
- ServerWindowDrawnTrackerObserver* observer_;
- bool drawn_;
- // Set of windows we're observing. This is |window_| and all its ancestors.
- std::set<ServerWindow*> windows_;
-
- DISALLOW_COPY_AND_ASSIGN(ServerWindowDrawnTracker);
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_SERVER_WINDOW_DRAWN_TRACKER_H_
diff --git a/chromium/components/mus/ws/server_window_drawn_tracker_observer.h b/chromium/components/mus/ws/server_window_drawn_tracker_observer.h
deleted file mode 100644
index 55f44cbbbc5..00000000000
--- a/chromium/components/mus/ws/server_window_drawn_tracker_observer.h
+++ /dev/null
@@ -1,41 +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 COMPONENTS_MUS_WS_SERVER_WINDOW_DRAWN_TRACKER_OBSERVER_H_
-#define COMPONENTS_MUS_WS_SERVER_WINDOW_DRAWN_TRACKER_OBSERVER_H_
-
-namespace mus {
-
-namespace ws {
-
-class ServerWindow;
-
-class ServerWindowDrawnTrackerObserver {
- public:
- // Invoked right before the drawn state changes. If |is_drawn| is false,
- // |ancestor| identifies where the change will occur. In the case of a remove,
- // |ancestor| is the parent of the window that will be removed (causing the
- // drawn state to change). In the case of visibility change, |ancestor| is the
- // parent of the window whose visibility will change.
- virtual void OnDrawnStateWillChange(ServerWindow* ancestor,
- ServerWindow* window,
- bool is_drawn) {}
-
- // Invoked when the drawn state changes. If |is_drawn| is false |ancestor|
- // identifies where the change occurred. In the case of a remove |ancestor| is
- // the parent of the window that was removed. In the case of a visibility
- // change |ancestor| is the parent of the window whose visibility changed.
- virtual void OnDrawnStateChanged(ServerWindow* ancestor,
- ServerWindow* window,
- bool is_drawn) {}
-
- protected:
- virtual ~ServerWindowDrawnTrackerObserver() {}
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_SERVER_WINDOW_DRAWN_TRACKER_OBSERVER_H_
diff --git a/chromium/components/mus/ws/server_window_drawn_tracker_unittest.cc b/chromium/components/mus/ws/server_window_drawn_tracker_unittest.cc
deleted file mode 100644
index 53ffa39f7b1..00000000000
--- a/chromium/components/mus/ws/server_window_drawn_tracker_unittest.cc
+++ /dev/null
@@ -1,235 +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 "components/mus/ws/server_window_drawn_tracker.h"
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_drawn_tracker_observer.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mus {
-
-namespace ws {
-namespace {
-
-class TestServerWindowDrawnTrackerObserver
- : public ServerWindowDrawnTrackerObserver {
- public:
- TestServerWindowDrawnTrackerObserver()
- : change_count_(0u),
- ancestor_(nullptr),
- window_(nullptr),
- is_drawn_(false) {}
-
- void clear_change_count() { change_count_ = 0u; }
- size_t change_count() const { return change_count_; }
- const ServerWindow* ancestor() const { return ancestor_; }
- const ServerWindow* window() const { return window_; }
- bool is_drawn() const { return is_drawn_; }
-
- private:
- // ServerWindowDrawnTrackerObserver:
- void OnDrawnStateWillChange(ServerWindow* ancestor,
- ServerWindow* window,
- bool is_drawn) override {
- change_count_++;
- ancestor_ = ancestor;
- window_ = window;
- is_drawn_ = is_drawn;
- }
-
- void OnDrawnStateChanged(ServerWindow* ancestor,
- ServerWindow* window,
- bool is_drawn) override {
- EXPECT_EQ(ancestor_, ancestor);
- EXPECT_EQ(window_, window);
- EXPECT_EQ(is_drawn_, is_drawn);
- }
-
- size_t change_count_;
- const ServerWindow* ancestor_;
- const ServerWindow* window_;
- bool is_drawn_;
-
- DISALLOW_COPY_AND_ASSIGN(TestServerWindowDrawnTrackerObserver);
-};
-
-} // namespace
-
-TEST(ServerWindowDrawnTrackerTest, ChangeBecauseOfDeletionAndVisibility) {
- TestServerWindowDelegate server_window_delegate;
- std::unique_ptr<ServerWindow> window(
- new ServerWindow(&server_window_delegate, WindowId()));
- server_window_delegate.set_root_window(window.get());
- TestServerWindowDrawnTrackerObserver drawn_observer;
- ServerWindowDrawnTracker tracker(window.get(), &drawn_observer);
- window->SetVisible(true);
- EXPECT_EQ(1u, drawn_observer.change_count());
- EXPECT_EQ(window.get(), drawn_observer.window());
- EXPECT_EQ(nullptr, drawn_observer.ancestor());
- EXPECT_TRUE(drawn_observer.is_drawn());
- drawn_observer.clear_change_count();
-
- window->SetVisible(false);
- EXPECT_EQ(1u, drawn_observer.change_count());
- EXPECT_EQ(window.get(), drawn_observer.window());
- EXPECT_EQ(nullptr, drawn_observer.ancestor());
- EXPECT_FALSE(drawn_observer.is_drawn());
- drawn_observer.clear_change_count();
-
- window->SetVisible(true);
- EXPECT_EQ(1u, drawn_observer.change_count());
- EXPECT_EQ(window.get(), drawn_observer.window());
- EXPECT_EQ(nullptr, drawn_observer.ancestor());
- EXPECT_TRUE(drawn_observer.is_drawn());
- drawn_observer.clear_change_count();
-
- ServerWindow* old_window = window.get();
- window.reset();
- EXPECT_EQ(1u, drawn_observer.change_count());
- EXPECT_EQ(old_window, drawn_observer.window());
- EXPECT_EQ(nullptr, drawn_observer.ancestor());
- EXPECT_FALSE(drawn_observer.is_drawn());
-}
-
-TEST(ServerWindowDrawnTrackerTest, ChangeBecauseOfRemovingFromRoot) {
- TestServerWindowDelegate server_window_delegate;
- ServerWindow root(&server_window_delegate, WindowId());
- server_window_delegate.set_root_window(&root);
- root.SetVisible(true);
- ServerWindow child(&server_window_delegate, WindowId());
- child.SetVisible(true);
- root.Add(&child);
-
- TestServerWindowDrawnTrackerObserver drawn_observer;
- ServerWindowDrawnTracker tracker(&child, &drawn_observer);
- root.Remove(&child);
- EXPECT_EQ(1u, drawn_observer.change_count());
- EXPECT_EQ(&child, drawn_observer.window());
- EXPECT_EQ(&root, drawn_observer.ancestor());
- EXPECT_FALSE(drawn_observer.is_drawn());
- drawn_observer.clear_change_count();
-
- root.Add(&child);
- EXPECT_EQ(1u, drawn_observer.change_count());
- EXPECT_EQ(&child, drawn_observer.window());
- EXPECT_EQ(nullptr, drawn_observer.ancestor());
- EXPECT_TRUE(drawn_observer.is_drawn());
-}
-
-TEST(ServerWindowDrawnTrackerTest, ChangeBecauseOfRemovingAncestorFromRoot) {
- TestServerWindowDelegate server_window_delegate;
- ServerWindow root(&server_window_delegate, WindowId());
- server_window_delegate.set_root_window(&root);
- root.SetVisible(true);
- ServerWindow child(&server_window_delegate, WindowId());
- child.SetVisible(true);
- root.Add(&child);
-
- ServerWindow child_child(&server_window_delegate, WindowId());
- child_child.SetVisible(true);
- child.Add(&child_child);
-
- TestServerWindowDrawnTrackerObserver drawn_observer;
- ServerWindowDrawnTracker tracker(&child_child, &drawn_observer);
- root.Remove(&child);
- EXPECT_EQ(1u, drawn_observer.change_count());
- EXPECT_EQ(&child_child, drawn_observer.window());
- EXPECT_EQ(&root, drawn_observer.ancestor());
- EXPECT_FALSE(drawn_observer.is_drawn());
- drawn_observer.clear_change_count();
-
- root.Add(&child_child);
- EXPECT_EQ(1u, drawn_observer.change_count());
- EXPECT_EQ(&child_child, drawn_observer.window());
- EXPECT_EQ(nullptr, drawn_observer.ancestor());
- EXPECT_TRUE(drawn_observer.is_drawn());
-}
-
-TEST(ServerWindowDrawnTrackerTest, VisibilityChangeFromNonParentAncestor) {
- TestServerWindowDelegate server_window_delegate;
- ServerWindow root(&server_window_delegate, WindowId());
- ServerWindow child1(&server_window_delegate, WindowId());
- ServerWindow child2(&server_window_delegate, WindowId());
- ServerWindow child3(&server_window_delegate, WindowId());
- server_window_delegate.set_root_window(&root);
-
- root.Add(&child1);
- child1.Add(&child2);
- child2.Add(&child3);
-
- root.SetVisible(true);
- child1.SetVisible(false);
- child2.SetVisible(false);
- child3.SetVisible(true);
-
- TestServerWindowDrawnTrackerObserver drawn_observer;
- ServerWindowDrawnTracker tracker(&child3, &drawn_observer);
-
- EXPECT_FALSE(child3.IsDrawn());
-
- // Make |child1| visible. |child3| should still be not drawn, since |child2|
- // is still invisible.
- child1.SetVisible(true);
- EXPECT_EQ(0u, drawn_observer.change_count());
- EXPECT_EQ(nullptr, drawn_observer.window());
- EXPECT_EQ(nullptr, drawn_observer.ancestor());
- EXPECT_FALSE(drawn_observer.is_drawn());
- EXPECT_FALSE(child3.IsDrawn());
-
- child2.SetVisible(true);
- EXPECT_EQ(1u, drawn_observer.change_count());
- EXPECT_EQ(&child3, drawn_observer.window());
- EXPECT_EQ(nullptr, drawn_observer.ancestor());
- EXPECT_TRUE(drawn_observer.is_drawn());
- EXPECT_TRUE(child3.IsDrawn());
-}
-
-TEST(ServerWindowDrawnTrackerTest, TreeHierarchyChangeFromNonParentAncestor) {
- TestServerWindowDelegate server_window_delegate;
- ServerWindow root(&server_window_delegate, WindowId());
- ServerWindow child1(&server_window_delegate, WindowId());
- ServerWindow child2(&server_window_delegate, WindowId());
- ServerWindow child11(&server_window_delegate, WindowId());
- ServerWindow child111(&server_window_delegate, WindowId());
- server_window_delegate.set_root_window(&root);
-
- root.Add(&child1);
- root.Add(&child2);
- child1.Add(&child11);
- child11.Add(&child111);
-
- root.SetVisible(true);
- child1.SetVisible(false);
- child2.SetVisible(true);
- child11.SetVisible(false);
- child111.SetVisible(true);
-
- TestServerWindowDrawnTrackerObserver drawn_observer;
- ServerWindowDrawnTracker tracker(&child111, &drawn_observer);
- EXPECT_FALSE(child111.IsDrawn());
-
- // Move |child11| as a child of |child2|. |child111| should remain not drawn.
- child2.Add(&child11);
- EXPECT_EQ(0u, drawn_observer.change_count());
- EXPECT_EQ(nullptr, drawn_observer.window());
- EXPECT_EQ(nullptr, drawn_observer.ancestor());
- EXPECT_FALSE(drawn_observer.is_drawn());
- EXPECT_FALSE(child111.IsDrawn());
-
- child11.SetVisible(true);
- EXPECT_EQ(1u, drawn_observer.change_count());
- EXPECT_EQ(&child111, drawn_observer.window());
- EXPECT_EQ(nullptr, drawn_observer.ancestor());
- EXPECT_TRUE(drawn_observer.is_drawn());
- EXPECT_TRUE(child111.IsDrawn());
-}
-
-} // namespace ws
-
-} // namespace mus
diff --git a/chromium/components/mus/ws/server_window_observer.h b/chromium/components/mus/ws/server_window_observer.h
deleted file mode 100644
index 2ea2f4c310a..00000000000
--- a/chromium/components/mus/ws/server_window_observer.h
+++ /dev/null
@@ -1,97 +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 COMPONENTS_MUS_WS_SERVER_WINDOW_OBSERVER_H_
-#define COMPONENTS_MUS_WS_SERVER_WINDOW_OBSERVER_H_
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "components/mus/public/interfaces/mus_constants.mojom.h"
-
-namespace gfx {
-class Insets;
-class Rect;
-}
-
-namespace ui {
-struct TextInputState;
-}
-
-namespace mus {
-
-namespace ws {
-
-class ServerWindow;
-
-// TODO(sky): rename to OnDid and OnWill everywhere.
-class ServerWindowObserver {
- public:
- // Invoked when a window is about to be destroyed; before any of the children
- // have been removed and before the window has been removed from its parent.
- virtual void OnWindowDestroying(ServerWindow* window) {}
-
- // Invoked at the end of the window's destructor (after it has been removed
- // from the hierarchy.
- virtual void OnWindowDestroyed(ServerWindow* window) {}
-
- virtual void OnWillChangeWindowHierarchy(ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) {}
-
- virtual void OnWindowHierarchyChanged(ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) {}
-
- virtual void OnWindowBoundsChanged(ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {}
-
- virtual void OnWindowClientAreaChanged(
- ServerWindow* window,
- const gfx::Insets& new_client_area,
- const std::vector<gfx::Rect>& new_additional_client_areas) {}
-
- virtual void OnWindowReordered(ServerWindow* window,
- ServerWindow* relative,
- mojom::OrderDirection direction) {}
-
- virtual void OnWillChangeWindowVisibility(ServerWindow* window) {}
- virtual void OnWindowVisibilityChanged(ServerWindow* window) {}
- virtual void OnWindowOpacityChanged(ServerWindow* window,
- float old_opacity,
- float new_opacity) {}
-
- virtual void OnWindowPredefinedCursorChanged(ServerWindow* window,
- int32_t cursor_id) {}
- virtual void OnWindowNonClientCursorChanged(ServerWindow* window,
- int32_t cursor_id) {}
-
- virtual void OnWindowTextInputStateChanged(ServerWindow* window,
- const ui::TextInputState& state) {}
-
- virtual void OnWindowSharedPropertyChanged(
- ServerWindow* window,
- const std::string& name,
- const std::vector<uint8_t>* new_data) {}
-
- // Called when a transient child is added to |window|.
- virtual void OnTransientWindowAdded(ServerWindow* window,
- ServerWindow* transient_child) {}
-
- // Called when a transient child is removed from |window|.
- virtual void OnTransientWindowRemoved(ServerWindow* window,
- ServerWindow* transient_child) {}
-
- protected:
- virtual ~ServerWindowObserver() {}
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_SERVER_WINDOW_OBSERVER_H_
diff --git a/chromium/components/mus/ws/server_window_surface.cc b/chromium/components/mus/ws/server_window_surface.cc
deleted file mode 100644
index d03bc5bd789..00000000000
--- a/chromium/components/mus/ws/server_window_surface.cc
+++ /dev/null
@@ -1,110 +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 "components/mus/ws/server_window_surface.h"
-
-#include "base/callback.h"
-#include "cc/output/compositor_frame.h"
-#include "cc/quads/shared_quad_state.h"
-#include "cc/quads/surface_draw_quad.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_delegate.h"
-#include "components/mus/ws/server_window_surface_manager.h"
-
-namespace mus {
-namespace ws {
-namespace {
-
-void CallCallback(const base::Closure& callback, cc::SurfaceDrawStatus status) {
- callback.Run();
-}
-
-} // namespace
-
-ServerWindowSurface::ServerWindowSurface(
- ServerWindowSurfaceManager* manager,
- mojo::InterfaceRequest<Surface> request,
- mojom::SurfaceClientPtr client)
- : manager_(manager),
- surface_id_(manager->GenerateId()),
- surface_factory_(manager_->GetSurfaceManager(), this),
- client_(std::move(client)),
- binding_(this, std::move(request)),
- registered_surface_factory_client_(false) {
- surface_factory_.Create(surface_id_);
-}
-
-ServerWindowSurface::~ServerWindowSurface() {
- // SurfaceFactory's destructor will attempt to return resources which will
- // call back into here and access |client_| so we should destroy
- // |surface_factory_|'s resources early on.
- surface_factory_.DestroyAll();
-
- if (registered_surface_factory_client_) {
- cc::SurfaceManager* surface_manager = manager_->GetSurfaceManager();
- surface_manager->UnregisterSurfaceFactoryClient(manager_->id_namespace());
- }
-}
-
-void ServerWindowSurface::SubmitCompositorFrame(
- cc::CompositorFrame frame,
- const SubmitCompositorFrameCallback& callback) {
- gfx::Size frame_size =
- frame.delegated_frame_data->render_pass_list[0]->output_rect.size();
- if (!surface_id_.is_null()) {
- // If the size of the CompostiorFrame has changed then destroy the existing
- // Surface and create a new one of the appropriate size.
- if (frame_size != last_submitted_frame_size_) {
- // Rendering of the topmost frame happens in two phases. First the frame
- // is generated and submitted, and a later date it is actually drawn.
- // During the time the frame is generated and drawn we can't destroy the
- // surface, otherwise when drawn you get an empty surface. To deal with
- // this we schedule destruction via the delegate. The delegate will call
- // us back when we're not waiting on a frame to be drawn (which may be
- // synchronously).
- surfaces_scheduled_for_destruction_.insert(surface_id_);
- window()->delegate()->ScheduleSurfaceDestruction(window());
- surface_id_ = manager_->GenerateId();
- surface_factory_.Create(surface_id_);
- }
- }
- surface_factory_.SubmitCompositorFrame(surface_id_, std::move(frame),
- base::Bind(&CallCallback, callback));
- last_submitted_frame_size_ = frame_size;
- window()->delegate()->OnScheduleWindowPaint(window());
-}
-
-void ServerWindowSurface::DestroySurfacesScheduledForDestruction() {
- std::set<cc::SurfaceId> surfaces;
- surfaces.swap(surfaces_scheduled_for_destruction_);
- for (auto& id : surfaces)
- surface_factory_.Destroy(id);
-}
-
-void ServerWindowSurface::RegisterForBeginFrames() {
- DCHECK(!registered_surface_factory_client_);
- registered_surface_factory_client_ = true;
- cc::SurfaceManager* surface_manager = manager_->GetSurfaceManager();
- surface_manager->RegisterSurfaceFactoryClient(manager_->id_namespace(), this);
-}
-
-ServerWindow* ServerWindowSurface::window() {
- return manager_->window();
-}
-
-void ServerWindowSurface::ReturnResources(
- const cc::ReturnedResourceArray& resources) {
- if (!client_ || !base::MessageLoop::current())
- return;
- client_->ReturnResources(mojo::Array<cc::ReturnedResource>::From(resources));
-}
-
-void ServerWindowSurface::SetBeginFrameSource(
- cc::BeginFrameSource* begin_frame_source) {
- // TODO(tansell): Implement this.
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/server_window_surface.h b/chromium/components/mus/ws/server_window_surface.h
deleted file mode 100644
index 126a99f73fc..00000000000
--- a/chromium/components/mus/ws/server_window_surface.h
+++ /dev/null
@@ -1,86 +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 COMPONENTS_MUS_WS_SERVER_WINDOW_SURFACE_H_
-#define COMPONENTS_MUS_WS_SERVER_WINDOW_SURFACE_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "cc/ipc/compositor_frame.mojom.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
-#include "cc/surfaces/surface_id.h"
-#include "cc/surfaces/surface_id_allocator.h"
-#include "components/mus/public/interfaces/surface.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/ws/ids.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace mus {
-
-class SurfacesState;
-
-namespace ws {
-
-class ServerWindow;
-class ServerWindowSurfaceManager;
-
-// Server side representation of a WindowSurface.
-class ServerWindowSurface : public mojom::Surface,
- public cc::SurfaceFactoryClient {
- public:
- ServerWindowSurface(ServerWindowSurfaceManager* manager,
- mojo::InterfaceRequest<mojom::Surface> request,
- mojom::SurfaceClientPtr client);
-
- ~ServerWindowSurface() override;
-
- const gfx::Size& last_submitted_frame_size() const {
- return last_submitted_frame_size_;
- }
-
- // mojom::Surface:
- void SubmitCompositorFrame(
- cc::CompositorFrame frame,
- const SubmitCompositorFrameCallback& callback) override;
-
- const cc::SurfaceId& id() const { return surface_id_; }
-
- // Destroys old surfaces that have been outdated by a new surface.
- void DestroySurfacesScheduledForDestruction();
-
- // Registers this with the SurfaceManager
- void RegisterForBeginFrames();
-
- private:
- ServerWindow* window();
-
- // SurfaceFactoryClient implementation.
- void ReturnResources(const cc::ReturnedResourceArray& resources) override;
- void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
-
- ServerWindowSurfaceManager* manager_; // Owns this.
-
- gfx::Size last_submitted_frame_size_;
-
- cc::SurfaceId surface_id_;
- cc::SurfaceFactory surface_factory_;
-
- mojom::SurfaceClientPtr client_;
- mojo::Binding<Surface> binding_;
-
- // Set of surface ids that need to be destroyed.
- std::set<cc::SurfaceId> surfaces_scheduled_for_destruction_;
-
- bool registered_surface_factory_client_;
-
- DISALLOW_COPY_AND_ASSIGN(ServerWindowSurface);
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_SERVER_WINDOW_SURFACE_H_
diff --git a/chromium/components/mus/ws/server_window_surface_manager.cc b/chromium/components/mus/ws/server_window_surface_manager.cc
deleted file mode 100644
index 1109d6ee8ac..00000000000
--- a/chromium/components/mus/ws/server_window_surface_manager.cc
+++ /dev/null
@@ -1,102 +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 "components/mus/ws/server_window_surface_manager.h"
-
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_delegate.h"
-#include "components/mus/ws/server_window_surface.h"
-
-namespace mus {
-namespace ws {
-
-ServerWindowSurfaceManager::ServerWindowSurfaceManager(ServerWindow* window)
- : window_(window),
- surface_id_allocator_(
- window->delegate()->GetSurfacesState()->next_id_namespace()),
- waiting_for_initial_frames_(
- window_->properties().count(mus::mojom::kWaitForUnderlay_Property) >
- 0) {
- surface_id_allocator_.RegisterSurfaceIdNamespace(GetSurfaceManager());
-}
-
-ServerWindowSurfaceManager::~ServerWindowSurfaceManager() {
- // Explicitly clear the type to surface manager so that this manager
- // is still valid prior during ~ServerWindowSurface.
- type_to_surface_map_.clear();
-}
-
-bool ServerWindowSurfaceManager::ShouldDraw() {
- if (!waiting_for_initial_frames_)
- return true;
-
- waiting_for_initial_frames_ =
- !IsSurfaceReadyAndNonEmpty(mojom::SurfaceType::DEFAULT) ||
- !IsSurfaceReadyAndNonEmpty(mojom::SurfaceType::UNDERLAY);
- return !waiting_for_initial_frames_;
-}
-
-void ServerWindowSurfaceManager::CreateSurface(
- mojom::SurfaceType surface_type,
- mojo::InterfaceRequest<mojom::Surface> request,
- mojom::SurfaceClientPtr client) {
- std::unique_ptr<ServerWindowSurface> surface(
- new ServerWindowSurface(this, std::move(request), std::move(client)));
- if (!HasAnySurface()) {
- // Only one SurfaceFactoryClient can be registered per surface id namespace,
- // so register the first one. Since all surfaces created by this manager
- // represent the same window, the begin frame source can be shared by
- // all surfaces created here.
- surface->RegisterForBeginFrames();
- }
- type_to_surface_map_[surface_type] = std::move(surface);
-}
-
-ServerWindowSurface* ServerWindowSurfaceManager::GetDefaultSurface() const {
- return GetSurfaceByType(mojom::SurfaceType::DEFAULT);
-}
-
-ServerWindowSurface* ServerWindowSurfaceManager::GetUnderlaySurface() const {
- return GetSurfaceByType(mojom::SurfaceType::UNDERLAY);
-}
-
-ServerWindowSurface* ServerWindowSurfaceManager::GetSurfaceByType(
- mojom::SurfaceType type) const {
- auto iter = type_to_surface_map_.find(type);
- return iter == type_to_surface_map_.end() ? nullptr : iter->second.get();
-}
-
-bool ServerWindowSurfaceManager::HasSurfaceOfType(
- mojom::SurfaceType type) const {
- return type_to_surface_map_.count(type) > 0;
-}
-
-bool ServerWindowSurfaceManager::HasAnySurface() const {
- return GetDefaultSurface() || GetUnderlaySurface();
-}
-
-cc::SurfaceManager* ServerWindowSurfaceManager::GetSurfaceManager() {
- return window()->delegate()->GetSurfacesState()->manager();
-}
-
-bool ServerWindowSurfaceManager::IsSurfaceReadyAndNonEmpty(
- mojom::SurfaceType type) const {
- auto iter = type_to_surface_map_.find(type);
- if (iter == type_to_surface_map_.end())
- return false;
- if (iter->second->last_submitted_frame_size().IsEmpty())
- return false;
- const gfx::Size& last_submitted_frame_size =
- iter->second->last_submitted_frame_size();
- return last_submitted_frame_size.width() >= window_->bounds().width() &&
- last_submitted_frame_size.height() >= window_->bounds().height();
-}
-
-cc::SurfaceId ServerWindowSurfaceManager::GenerateId() {
- return surface_id_allocator_.GenerateId();
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/server_window_surface_manager.h b/chromium/components/mus/ws/server_window_surface_manager.h
deleted file mode 100644
index 1bae2008ca8..00000000000
--- a/chromium/components/mus/ws/server_window_surface_manager.h
+++ /dev/null
@@ -1,84 +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 COMPONENTS_MUS_WS_SERVER_WINDOW_SURFACE_MANAGER_H_
-#define COMPONENTS_MUS_WS_SERVER_WINDOW_SURFACE_MANAGER_H_
-
-#include <map>
-
-#include "base/macros.h"
-#include "cc/ipc/compositor_frame.mojom.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_id.h"
-#include "cc/surfaces/surface_id_allocator.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace mus {
-namespace ws {
-
-class ServerWindow;
-class ServerWindowSurface;
-class ServerWindowSurfaceManagerTestApi;
-
-// ServerWindowSurfaceManager tracks the surfaces associated with a
-// ServerWindow.
-class ServerWindowSurfaceManager {
- public:
- explicit ServerWindowSurfaceManager(ServerWindow* window);
- ~ServerWindowSurfaceManager();
-
- // Returns true if the surfaces from this manager should be drawn.
- bool ShouldDraw();
-
- // Creates a new surface of the specified type, replacing the existing one of
- // the specified type.
- void CreateSurface(mojom::SurfaceType surface_type,
- mojo::InterfaceRequest<mojom::Surface> request,
- mojom::SurfaceClientPtr client);
-
- ServerWindow* window() { return window_; }
-
- ServerWindowSurface* GetDefaultSurface() const;
- ServerWindowSurface* GetUnderlaySurface() const;
- ServerWindowSurface* GetSurfaceByType(mojom::SurfaceType type) const;
- bool HasSurfaceOfType(mojom::SurfaceType type) const;
- bool HasAnySurface() const;
-
- uint32_t id_namespace() const { return surface_id_allocator_.id_namespace(); }
- cc::SurfaceManager* GetSurfaceManager();
-
- private:
- friend class ServerWindowSurfaceManagerTestApi;
- friend class ServerWindowSurface;
-
- // Returns true if a surface of |type| has been set and its size is greater
- // than the size of the window.
- bool IsSurfaceReadyAndNonEmpty(mojom::SurfaceType type) const;
-
- cc::SurfaceId GenerateId();
-
- ServerWindow* window_;
-
- cc::SurfaceIdAllocator surface_id_allocator_;
-
- using TypeToSurfaceMap =
- std::map<mojom::SurfaceType, std::unique_ptr<ServerWindowSurface>>;
-
- TypeToSurfaceMap type_to_surface_map_;
-
- // While true the window is not drawn. This is initially true if the window
- // has the property |kWaitForUnderlay_Property|. This is set to false once
- // the underlay and default surface have been set *and* their size is at
- // least that of the window. Ideally we would wait for sizes to match, but
- // the underlay is not necessarily as big as the window.
- bool waiting_for_initial_frames_;
-
- DISALLOW_COPY_AND_ASSIGN(ServerWindowSurfaceManager);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_SERVER_WINDOW_SURFACE_MANAGER_H_
diff --git a/chromium/components/mus/ws/server_window_surface_manager_test_api.cc b/chromium/components/mus/ws/server_window_surface_manager_test_api.cc
deleted file mode 100644
index d65ae0f6376..00000000000
--- a/chromium/components/mus/ws/server_window_surface_manager_test_api.cc
+++ /dev/null
@@ -1,39 +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 "components/mus/ws/server_window_surface_manager_test_api.h"
-
-#include "components/mus/ws/server_window.h"
-
-namespace mus {
-namespace ws {
-
-ServerWindowSurfaceManagerTestApi::ServerWindowSurfaceManagerTestApi(
- ServerWindowSurfaceManager* manager)
- : manager_(manager) {}
-
-ServerWindowSurfaceManagerTestApi::~ServerWindowSurfaceManagerTestApi() {}
-
-void ServerWindowSurfaceManagerTestApi::CreateEmptyDefaultSurface() {
- manager_->type_to_surface_map_[mojom::SurfaceType::DEFAULT] = nullptr;
-}
-
-void ServerWindowSurfaceManagerTestApi::DestroyDefaultSurface() {
- manager_->type_to_surface_map_.erase(mojom::SurfaceType::DEFAULT);
-}
-
-void EnableHitTest(ServerWindow* window) {
- ServerWindowSurfaceManagerTestApi test_api(
- window->GetOrCreateSurfaceManager());
- test_api.CreateEmptyDefaultSurface();
-}
-
-void DisableHitTest(ServerWindow* window) {
- ServerWindowSurfaceManagerTestApi test_api(
- window->GetOrCreateSurfaceManager());
- test_api.DestroyDefaultSurface();
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/server_window_surface_manager_test_api.h b/chromium/components/mus/ws/server_window_surface_manager_test_api.h
deleted file mode 100644
index bc34027110a..00000000000
--- a/chromium/components/mus/ws/server_window_surface_manager_test_api.h
+++ /dev/null
@@ -1,39 +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 COMPONENTS_MUS_WS_SERVER_WINDOW_SURFACE_MANAGER_TEST_API_H_
-#define COMPONENTS_MUS_WS_SERVER_WINDOW_SURFACE_MANAGER_TEST_API_H_
-
-#include "base/macros.h"
-#include "components/mus/ws/server_window_surface_manager.h"
-
-namespace mus {
-namespace ws {
-
-class ServerWindow;
-
-// Use to poke at the internals of ServerWindowSurfaceManager.
-class ServerWindowSurfaceManagerTestApi {
- public:
- explicit ServerWindowSurfaceManagerTestApi(
- ServerWindowSurfaceManager* manager);
- ~ServerWindowSurfaceManagerTestApi();
-
- void CreateEmptyDefaultSurface();
- void DestroyDefaultSurface();
-
- private:
- ServerWindowSurfaceManager* manager_;
-
- DISALLOW_COPY_AND_ASSIGN(ServerWindowSurfaceManagerTestApi);
-};
-
-// Use to make |window| a target for events.
-void EnableHitTest(ServerWindow* window);
-void DisableHitTest(ServerWindow* window);
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_SERVER_WINDOW_SURFACE_MANAGER_TEST_API_H_
diff --git a/chromium/components/mus/ws/server_window_tracker.h b/chromium/components/mus/ws/server_window_tracker.h
deleted file mode 100644
index d3b73f06be1..00000000000
--- a/chromium/components/mus/ws/server_window_tracker.h
+++ /dev/null
@@ -1,25 +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 COMPONENTS_MUS_WS_SERVER_WINDOW_TRACKER_H_
-#define COMPONENTS_MUS_WS_SERVER_WINDOW_TRACKER_H_
-
-#include <stdint.h>
-#include <set>
-
-#include "base/macros.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_observer.h"
-#include "ui/base/window_tracker_template.h"
-
-namespace mus {
-namespace ws {
-
-using ServerWindowTracker =
- ui::WindowTrackerTemplate<ServerWindow, ServerWindowObserver>;
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_SERVER_WINDOW_TRACKER_H_
diff --git a/chromium/components/mus/ws/test_change_tracker.cc b/chromium/components/mus/ws/test_change_tracker.cc
deleted file mode 100644
index 26cd89ed64a..00000000000
--- a/chromium/components/mus/ws/test_change_tracker.cc
+++ /dev/null
@@ -1,448 +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 "components/mus/ws/test_change_tracker.h"
-
-#include <stddef.h>
-
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "components/mus/common/util.h"
-#include "mojo/common/common_type_converters.h"
-
-using mojo::Array;
-using mojo::String;
-
-namespace mus {
-
-namespace ws {
-
-std::string WindowIdToString(Id id) {
- return (id == 0) ? "null"
- : base::StringPrintf("%d,%d", HiWord(id), LoWord(id));
-}
-
-namespace {
-
-std::string DirectionToString(mojom::OrderDirection direction) {
- return direction == mojom::OrderDirection::ABOVE ? "above" : "below";
-}
-
-enum class ChangeDescriptionType {
- ONE,
- TWO,
-};
-
-std::string ChangeToDescription(const Change& change,
- ChangeDescriptionType type) {
- switch (change.type) {
- case CHANGE_TYPE_EMBED:
- if (type == ChangeDescriptionType::ONE)
- return "OnEmbed";
- return base::StringPrintf("OnEmbed drawn=%s",
- change.bool_value ? "true" : "false");
-
- case CHANGE_TYPE_EMBEDDED_APP_DISCONNECTED:
- return base::StringPrintf("OnEmbeddedAppDisconnected window=%s",
- WindowIdToString(change.window_id).c_str());
-
- case CHANGE_TYPE_UNEMBED:
- return base::StringPrintf("OnUnembed window=%s",
- WindowIdToString(change.window_id).c_str());
-
- case CHANGE_TYPE_LOST_CAPTURE:
- return base::StringPrintf("OnLostCapture window=%s",
- WindowIdToString(change.window_id).c_str());
-
- case CHANGE_TYPE_NODE_ADD_TRANSIENT_WINDOW:
- return base::StringPrintf("AddTransientWindow parent = %s child = %s",
- WindowIdToString(change.window_id).c_str(),
- WindowIdToString(change.window_id2).c_str());
-
- case CHANGE_TYPE_NODE_BOUNDS_CHANGED:
- return base::StringPrintf(
- "BoundsChanged window=%s old_bounds=%s new_bounds=%s",
- WindowIdToString(change.window_id).c_str(),
- change.bounds.ToString().c_str(), change.bounds2.ToString().c_str());
-
- case CHANGE_TYPE_NODE_HIERARCHY_CHANGED:
- return base::StringPrintf(
- "HierarchyChanged window=%s old_parent=%s new_parent=%s",
- WindowIdToString(change.window_id).c_str(),
- WindowIdToString(change.window_id2).c_str(),
- WindowIdToString(change.window_id3).c_str());
-
- case CHANGE_TYPE_NODE_REMOVE_TRANSIENT_WINDOW_FROM_PARENT:
- return base::StringPrintf(
- "RemoveTransientWindowFromParent parent = %s child = %s",
- WindowIdToString(change.window_id).c_str(),
- WindowIdToString(change.window_id2).c_str());
-
- case CHANGE_TYPE_NODE_REORDERED:
- return base::StringPrintf("Reordered window=%s relative=%s direction=%s",
- WindowIdToString(change.window_id).c_str(),
- WindowIdToString(change.window_id2).c_str(),
- DirectionToString(change.direction).c_str());
-
- case CHANGE_TYPE_NODE_DELETED:
- return base::StringPrintf("WindowDeleted window=%s",
- WindowIdToString(change.window_id).c_str());
-
- case CHANGE_TYPE_NODE_VISIBILITY_CHANGED:
- return base::StringPrintf("VisibilityChanged window=%s visible=%s",
- WindowIdToString(change.window_id).c_str(),
- change.bool_value ? "true" : "false");
-
- case CHANGE_TYPE_NODE_DRAWN_STATE_CHANGED:
- return base::StringPrintf("DrawnStateChanged window=%s drawn=%s",
- WindowIdToString(change.window_id).c_str(),
- change.bool_value ? "true" : "false");
-
- case CHANGE_TYPE_INPUT_EVENT: {
- std::string result = base::StringPrintf(
- "InputEvent window=%s event_action=%d",
- WindowIdToString(change.window_id).c_str(), change.event_action);
- if (change.event_observer_id != 0)
- base::StringAppendF(&result, " event_observer_id=%u",
- change.event_observer_id);
- return result;
- }
-
- case CHANGE_TYPE_EVENT_OBSERVED:
- return base::StringPrintf(
- "EventObserved event_action=%d event_observer_id=%u",
- change.event_action, change.event_observer_id);
-
- case CHANGE_TYPE_PROPERTY_CHANGED:
- return base::StringPrintf("PropertyChanged window=%s key=%s value=%s",
- WindowIdToString(change.window_id).c_str(),
- change.property_key.c_str(),
- change.property_value.c_str());
-
- case CHANGE_TYPE_FOCUSED:
- return base::StringPrintf("Focused id=%s",
- WindowIdToString(change.window_id).c_str());
-
- case CHANGE_TYPE_CURSOR_CHANGED:
- return base::StringPrintf("CursorChanged id=%s cursor_id=%d",
- WindowIdToString(change.window_id).c_str(),
- change.cursor_id);
- case CHANGE_TYPE_ON_CHANGE_COMPLETED:
- return base::StringPrintf("ChangeCompleted id=%d sucess=%s",
- change.change_id,
- change.bool_value ? "true" : "false");
-
- case CHANGE_TYPE_ON_TOP_LEVEL_CREATED:
- return base::StringPrintf("TopLevelCreated id=%d window_id=%s drawn=%s",
- change.change_id,
- WindowIdToString(change.window_id).c_str(),
- change.bool_value ? "true" : "false");
- case CHANGE_TYPE_OPACITY:
- return base::StringPrintf("OpacityChanged window_id=%s opacity=%.2f",
- WindowIdToString(change.window_id).c_str(),
- change.float_value);
- }
- return std::string();
-}
-
-std::string SingleChangeToDescriptionImpl(const std::vector<Change>& changes,
- ChangeDescriptionType change_type) {
- std::string result;
- for (auto& change : changes) {
- if (!result.empty())
- result += "\n";
- result += ChangeToDescription(change, change_type);
- }
- return result;
-}
-
-} // namespace
-
-std::vector<std::string> ChangesToDescription1(
- const std::vector<Change>& changes) {
- std::vector<std::string> strings(changes.size());
- for (size_t i = 0; i < changes.size(); ++i)
- strings[i] = ChangeToDescription(changes[i], ChangeDescriptionType::ONE);
- return strings;
-}
-
-std::string SingleChangeToDescription(const std::vector<Change>& changes) {
- return SingleChangeToDescriptionImpl(changes, ChangeDescriptionType::ONE);
-}
-
-std::string SingleChangeToDescription2(const std::vector<Change>& changes) {
- return SingleChangeToDescriptionImpl(changes, ChangeDescriptionType::TWO);
-}
-
-std::string SingleWindowDescription(const std::vector<TestWindow>& windows) {
- if (windows.empty())
- return "no windows";
- std::string result;
- for (const TestWindow& window : windows)
- result += window.ToString();
- return result;
-}
-
-std::string ChangeWindowDescription(const std::vector<Change>& changes) {
- if (changes.size() != 1)
- return std::string();
- std::vector<std::string> window_strings(changes[0].windows.size());
- for (size_t i = 0; i < changes[0].windows.size(); ++i)
- window_strings[i] = "[" + changes[0].windows[i].ToString() + "]";
- return base::JoinString(window_strings, ",");
-}
-
-TestWindow WindowDataToTestWindow(const mojom::WindowDataPtr& data) {
- TestWindow window;
- window.parent_id = data->parent_id;
- window.window_id = data->window_id;
- window.visible = data->visible;
- window.properties =
- data->properties.To<std::map<std::string, std::vector<uint8_t>>>();
- return window;
-}
-
-void WindowDatasToTestWindows(const Array<mojom::WindowDataPtr>& data,
- std::vector<TestWindow>* test_windows) {
- for (size_t i = 0; i < data.size(); ++i)
- test_windows->push_back(WindowDataToTestWindow(data[i]));
-}
-
-Change::Change()
- : type(CHANGE_TYPE_EMBED),
- client_id(0),
- window_id(0),
- window_id2(0),
- window_id3(0),
- event_action(0),
- event_observer_id(0u),
- direction(mojom::OrderDirection::ABOVE),
- bool_value(false),
- float_value(0.f),
- cursor_id(0),
- change_id(0u) {}
-
-Change::Change(const Change& other) = default;
-
-Change::~Change() {}
-
-TestChangeTracker::TestChangeTracker() : delegate_(NULL) {}
-
-TestChangeTracker::~TestChangeTracker() {}
-
-void TestChangeTracker::OnEmbed(ClientSpecificId client_id,
- mojom::WindowDataPtr root,
- bool drawn) {
- Change change;
- change.type = CHANGE_TYPE_EMBED;
- change.client_id = client_id;
- change.bool_value = drawn;
- change.windows.push_back(WindowDataToTestWindow(root));
- AddChange(change);
-}
-
-void TestChangeTracker::OnEmbeddedAppDisconnected(Id window_id) {
- Change change;
- change.type = CHANGE_TYPE_EMBEDDED_APP_DISCONNECTED;
- change.window_id = window_id;
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowBoundsChanged(Id window_id,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- Change change;
- change.type = CHANGE_TYPE_NODE_BOUNDS_CHANGED;
- change.window_id = window_id;
- change.bounds = old_bounds;
- change.bounds2 = new_bounds;
- AddChange(change);
-}
-
-void TestChangeTracker::OnUnembed(Id window_id) {
- Change change;
- change.type = CHANGE_TYPE_UNEMBED;
- change.window_id = window_id;
- AddChange(change);
-}
-
-void TestChangeTracker::OnTransientWindowAdded(Id window_id,
- Id transient_window_id) {
- Change change;
- change.type = CHANGE_TYPE_NODE_ADD_TRANSIENT_WINDOW;
- change.window_id = window_id;
- change.window_id2 = transient_window_id;
- AddChange(change);
-}
-
-void TestChangeTracker::OnTransientWindowRemoved(Id window_id,
- Id transient_window_id) {
- Change change;
- change.type = CHANGE_TYPE_NODE_REMOVE_TRANSIENT_WINDOW_FROM_PARENT;
- change.window_id = window_id;
- change.window_id2 = transient_window_id;
- AddChange(change);
-}
-
-void TestChangeTracker::OnLostCapture(Id window_id) {
- Change change;
- change.type = CHANGE_TYPE_LOST_CAPTURE;
- change.window_id = window_id;
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowHierarchyChanged(
- Id window_id,
- Id old_parent_id,
- Id new_parent_id,
- Array<mojom::WindowDataPtr> windows) {
- Change change;
- change.type = CHANGE_TYPE_NODE_HIERARCHY_CHANGED;
- change.window_id = window_id;
- change.window_id2 = old_parent_id;
- change.window_id3 = new_parent_id;
- WindowDatasToTestWindows(windows, &change.windows);
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowReordered(Id window_id,
- Id relative_window_id,
- mojom::OrderDirection direction) {
- Change change;
- change.type = CHANGE_TYPE_NODE_REORDERED;
- change.window_id = window_id;
- change.window_id2 = relative_window_id;
- change.direction = direction;
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowDeleted(Id window_id) {
- Change change;
- change.type = CHANGE_TYPE_NODE_DELETED;
- change.window_id = window_id;
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowVisibilityChanged(Id window_id, bool visible) {
- Change change;
- change.type = CHANGE_TYPE_NODE_VISIBILITY_CHANGED;
- change.window_id = window_id;
- change.bool_value = visible;
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowOpacityChanged(Id window_id, float opacity) {
- Change change;
- change.type = CHANGE_TYPE_OPACITY;
- change.window_id = window_id;
- change.float_value = opacity;
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowParentDrawnStateChanged(Id window_id,
- bool drawn) {
- Change change;
- change.type = CHANGE_TYPE_NODE_DRAWN_STATE_CHANGED;
- change.window_id = window_id;
- change.bool_value = drawn;
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowInputEvent(Id window_id,
- const ui::Event& event,
- uint32_t event_observer_id) {
- Change change;
- change.type = CHANGE_TYPE_INPUT_EVENT;
- change.window_id = window_id;
- change.event_action = static_cast<int32_t>(event.type());
- change.event_observer_id = event_observer_id;
- AddChange(change);
-}
-
-void TestChangeTracker::OnEventObserved(const ui::Event& event,
- uint32_t event_observer_id) {
- Change change;
- change.type = CHANGE_TYPE_EVENT_OBSERVED;
- change.event_action = static_cast<int32_t>(event.type());
- change.event_observer_id = event_observer_id;
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowSharedPropertyChanged(Id window_id,
- String name,
- Array<uint8_t> data) {
- Change change;
- change.type = CHANGE_TYPE_PROPERTY_CHANGED;
- change.window_id = window_id;
- change.property_key = name;
- if (data.is_null())
- change.property_value = "NULL";
- else
- change.property_value = data.To<std::string>();
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowFocused(Id window_id) {
- Change change;
- change.type = CHANGE_TYPE_FOCUSED;
- change.window_id = window_id;
- AddChange(change);
-}
-
-void TestChangeTracker::OnWindowPredefinedCursorChanged(
- Id window_id,
- mojom::Cursor cursor_id) {
- Change change;
- change.type = CHANGE_TYPE_CURSOR_CHANGED;
- change.window_id = window_id;
- change.cursor_id = static_cast<int32_t>(cursor_id);
- AddChange(change);
-}
-
-void TestChangeTracker::OnChangeCompleted(uint32_t change_id, bool success) {
- Change change;
- change.type = CHANGE_TYPE_ON_CHANGE_COMPLETED;
- change.change_id = change_id;
- change.bool_value = success;
- AddChange(change);
-}
-
-void TestChangeTracker::OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr window_data,
- bool drawn) {
- Change change;
- change.type = CHANGE_TYPE_ON_TOP_LEVEL_CREATED;
- change.change_id = change_id;
- change.window_id = window_data->window_id;
- change.bool_value = drawn;
- AddChange(change);
-}
-
-void TestChangeTracker::AddChange(const Change& change) {
- changes_.push_back(change);
- if (delegate_)
- delegate_->OnChangeAdded();
-}
-
-TestWindow::TestWindow() {}
-
-TestWindow::TestWindow(const TestWindow& other) = default;
-
-TestWindow::~TestWindow() {}
-
-std::string TestWindow::ToString() const {
- return base::StringPrintf("window=%s parent=%s",
- WindowIdToString(window_id).c_str(),
- WindowIdToString(parent_id).c_str());
-}
-
-std::string TestWindow::ToString2() const {
- return base::StringPrintf(
- "window=%s parent=%s visible=%s", WindowIdToString(window_id).c_str(),
- WindowIdToString(parent_id).c_str(), visible ? "true" : "false");
-}
-
-} // namespace ws
-
-} // namespace mus
diff --git a/chromium/components/mus/ws/test_change_tracker.h b/chromium/components/mus/ws/test_change_tracker.h
deleted file mode 100644
index 7d82b2f339b..00000000000
--- a/chromium/components/mus/ws/test_change_tracker.h
+++ /dev/null
@@ -1,185 +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 COMPONENTS_MUS_WS_TEST_CHANGE_TRACKER_H_
-#define COMPONENTS_MUS_WS_TEST_CHANGE_TRACKER_H_
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "components/mus/common/types.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "mojo/public/cpp/bindings/array.h"
-#include "ui/gfx/geometry/mojo/geometry.mojom.h"
-
-namespace mus {
-
-namespace ws {
-
-enum ChangeType {
- CHANGE_TYPE_EMBED,
- CHANGE_TYPE_EMBEDDED_APP_DISCONNECTED,
- CHANGE_TYPE_UNEMBED,
- CHANGE_TYPE_LOST_CAPTURE,
- // TODO(sky): nuke NODE.
- CHANGE_TYPE_NODE_ADD_TRANSIENT_WINDOW,
- CHANGE_TYPE_NODE_BOUNDS_CHANGED,
- CHANGE_TYPE_NODE_HIERARCHY_CHANGED,
- CHANGE_TYPE_NODE_REMOVE_TRANSIENT_WINDOW_FROM_PARENT,
- CHANGE_TYPE_NODE_REORDERED,
- CHANGE_TYPE_NODE_VISIBILITY_CHANGED,
- CHANGE_TYPE_NODE_DRAWN_STATE_CHANGED,
- CHANGE_TYPE_NODE_DELETED,
- CHANGE_TYPE_INPUT_EVENT,
- CHANGE_TYPE_EVENT_OBSERVED,
- CHANGE_TYPE_PROPERTY_CHANGED,
- CHANGE_TYPE_FOCUSED,
- CHANGE_TYPE_CURSOR_CHANGED,
- CHANGE_TYPE_ON_CHANGE_COMPLETED,
- CHANGE_TYPE_ON_TOP_LEVEL_CREATED,
- CHANGE_TYPE_OPACITY,
-};
-
-// TODO(sky): consider nuking and converting directly to WindowData.
-struct TestWindow {
- TestWindow();
- TestWindow(const TestWindow& other);
- ~TestWindow();
-
- // Returns a string description of this.
- std::string ToString() const;
-
- // Returns a string description that includes visible and drawn.
- std::string ToString2() const;
-
- Id parent_id;
- Id window_id;
- bool visible;
- std::map<std::string, std::vector<uint8_t>> properties;
-};
-
-// Tracks a call to WindowTreeClient. See the individual functions for the
-// fields that are used.
-struct Change {
- Change();
- Change(const Change& other);
- ~Change();
-
- ChangeType type;
- ClientSpecificId client_id;
- std::vector<TestWindow> windows;
- Id window_id;
- Id window_id2;
- Id window_id3;
- gfx::Rect bounds;
- gfx::Rect bounds2;
- int32_t event_action;
- uint32_t event_observer_id;
- mojo::String embed_url;
- mojom::OrderDirection direction;
- bool bool_value;
- float float_value;
- std::string property_key;
- std::string property_value;
- int32_t cursor_id;
- uint32_t change_id;
-};
-
-// Converts Changes to string descriptions.
-std::vector<std::string> ChangesToDescription1(
- const std::vector<Change>& changes);
-
-// Convenience for returning the description of the first item in |changes|.
-// Returns an empty string if |changes| has something other than one entry.
-std::string SingleChangeToDescription(const std::vector<Change>& changes);
-std::string SingleChangeToDescription2(const std::vector<Change>& changes);
-
-// Convenience for returning the description of the first item in |windows|.
-// Returns an empty string if |windows| has something other than one entry.
-std::string SingleWindowDescription(const std::vector<TestWindow>& windows);
-
-// Returns a string description of |changes[0].windows|. Returns an empty string
-// if change.size() != 1.
-std::string ChangeWindowDescription(const std::vector<Change>& changes);
-
-// Converts WindowDatas to TestWindows.
-void WindowDatasToTestWindows(const mojo::Array<mojom::WindowDataPtr>& data,
- std::vector<TestWindow>* test_windows);
-
-// TestChangeTracker is used to record WindowTreeClient functions. It notifies
-// a delegate any time a change is added.
-class TestChangeTracker {
- public:
- // Used to notify the delegate when a change is added. A change corresponds to
- // a single WindowTreeClient function.
- class Delegate {
- public:
- virtual void OnChangeAdded() = 0;
-
- protected:
- virtual ~Delegate() {}
- };
-
- TestChangeTracker();
- ~TestChangeTracker();
-
- void set_delegate(Delegate* delegate) { delegate_ = delegate; }
-
- std::vector<Change>* changes() { return &changes_; }
-
- // Each of these functions generate a Change. There is one per
- // WindowTreeClient function.
- void OnEmbed(ClientSpecificId client_id,
- mojom::WindowDataPtr root,
- bool drawn);
- void OnEmbeddedAppDisconnected(Id window_id);
- void OnUnembed(Id window_id);
- void OnLostCapture(Id window_id);
- void OnTransientWindowAdded(Id window_id, Id transient_window_id);
- void OnTransientWindowRemoved(Id window_id, Id transient_window_id);
- void OnWindowBoundsChanged(Id window_id,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds);
- void OnWindowHierarchyChanged(Id window_id,
- Id old_parent_id,
- Id new_parent_id,
- mojo::Array<mojom::WindowDataPtr> windows);
- void OnWindowReordered(Id window_id,
- Id relative_window_id,
- mojom::OrderDirection direction);
- void OnWindowDeleted(Id window_id);
- void OnWindowVisibilityChanged(Id window_id, bool visible);
- void OnWindowOpacityChanged(Id window_id, float opacity);
- void OnWindowParentDrawnStateChanged(Id window_id, bool drawn);
- void OnWindowInputEvent(Id window_id,
- const ui::Event& event,
- uint32_t event_observer_id);
- void OnEventObserved(const ui::Event& event, uint32_t event_observer_id);
- void OnWindowSharedPropertyChanged(Id window_id,
- mojo::String name,
- mojo::Array<uint8_t> data);
- void OnWindowFocused(Id window_id);
- void OnWindowPredefinedCursorChanged(Id window_id, mojom::Cursor cursor_id);
- void OnChangeCompleted(uint32_t change_id, bool success);
- void OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr window_data,
- bool drawn);
-
- private:
- void AddChange(const Change& change);
-
- Delegate* delegate_;
- std::vector<Change> changes_;
-
- DISALLOW_COPY_AND_ASSIGN(TestChangeTracker);
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_TEST_CHANGE_TRACKER_H_
diff --git a/chromium/components/mus/ws/test_server_window_delegate.cc b/chromium/components/mus/ws/test_server_window_delegate.cc
deleted file mode 100644
index 57f1aaec6ed..00000000000
--- a/chromium/components/mus/ws/test_server_window_delegate.cc
+++ /dev/null
@@ -1,34 +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 "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "components/mus/ws/server_window.h"
-
-namespace mus {
-
-namespace ws {
-
-TestServerWindowDelegate::TestServerWindowDelegate()
- : root_window_(nullptr), surfaces_state_(new SurfacesState()) {}
-
-TestServerWindowDelegate::~TestServerWindowDelegate() {}
-
-mus::SurfacesState* TestServerWindowDelegate::GetSurfacesState() {
- return surfaces_state_.get();
-}
-
-void TestServerWindowDelegate::OnScheduleWindowPaint(ServerWindow* window) {}
-
-const ServerWindow* TestServerWindowDelegate::GetRootWindow(
- const ServerWindow* window) const {
- return root_window_;
-}
-
-void TestServerWindowDelegate::ScheduleSurfaceDestruction(
- ServerWindow* window) {}
-
-} // namespace ws
-
-} // namespace mus
diff --git a/chromium/components/mus/ws/test_server_window_delegate.h b/chromium/components/mus/ws/test_server_window_delegate.h
deleted file mode 100644
index 77808771d9d..00000000000
--- a/chromium/components/mus/ws/test_server_window_delegate.h
+++ /dev/null
@@ -1,41 +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 COMPONENTS_MUS_WS_TEST_SERVER_WINDOW_DELEGATE_H_
-#define COMPONENTS_MUS_WS_TEST_SERVER_WINDOW_DELEGATE_H_
-
-#include "base/macros.h"
-#include "components/mus/ws/server_window_delegate.h"
-
-namespace mus {
-
-namespace ws {
-
-struct WindowId;
-
-class TestServerWindowDelegate : public ServerWindowDelegate {
- public:
- TestServerWindowDelegate();
- ~TestServerWindowDelegate() override;
-
- void set_root_window(const ServerWindow* window) { root_window_ = window; }
-
- private:
- // ServerWindowDelegate:
- mus::SurfacesState* GetSurfacesState() override;
- void OnScheduleWindowPaint(ServerWindow* window) override;
- const ServerWindow* GetRootWindow(const ServerWindow* window) const override;
- void ScheduleSurfaceDestruction(ServerWindow* window) override;
-
- const ServerWindow* root_window_;
- scoped_refptr<mus::SurfacesState> surfaces_state_;
-
- DISALLOW_COPY_AND_ASSIGN(TestServerWindowDelegate);
-};
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_TEST_SERVER_WINDOW_DELEGATE_H_
diff --git a/chromium/components/mus/ws/test_utils.cc b/chromium/components/mus/ws/test_utils.cc
deleted file mode 100644
index 78f7d4714d3..00000000000
--- a/chromium/components/mus/ws/test_utils.cc
+++ /dev/null
@@ -1,496 +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 "components/mus/ws/test_utils.h"
-
-#include "base/memory/ptr_util.h"
-#include "cc/output/copy_output_request.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/display_binding.h"
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/server_window_surface_manager_test_api.h"
-#include "components/mus/ws/window_manager_access_policy.h"
-#include "components/mus/ws/window_manager_window_tree_factory.h"
-#include "services/shell/public/interfaces/connector.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mus {
-namespace ws {
-namespace test {
-namespace {
-
-// -----------------------------------------------------------------------------
-// Empty implementation of PlatformDisplay.
-class TestPlatformDisplay : public PlatformDisplay {
- public:
- explicit TestPlatformDisplay(int32_t* cursor_id_storage)
- : cursor_id_storage_(cursor_id_storage) {
- display_metrics_.size_in_pixels = gfx::Size(400, 300);
- display_metrics_.device_scale_factor = 1.f;
- }
- ~TestPlatformDisplay() override {}
-
- // PlatformDisplay:
- void Init(PlatformDisplayDelegate* delegate) override {
- // It is necessary to tell the delegate about the ViewportMetrics to make
- // sure that the DisplayBinding is correctly initialized (and a root-window
- // is created).
- delegate->OnViewportMetricsChanged(ViewportMetrics(), display_metrics_);
- }
- void SchedulePaint(const ServerWindow* window,
- const gfx::Rect& bounds) override {}
- void SetViewportSize(const gfx::Size& size) override {}
- void SetTitle(const base::string16& title) override {}
- void SetCapture() override {}
- void ReleaseCapture() override {}
- void SetCursorById(int32_t cursor) override { *cursor_id_storage_ = cursor; }
- mojom::Rotation GetRotation() override { return mojom::Rotation::VALUE_0; }
- float GetDeviceScaleFactor() override {
- return display_metrics_.device_scale_factor;
- }
- void UpdateTextInputState(const ui::TextInputState& state) override {}
- void SetImeVisibility(bool visible) override {}
- bool IsFramePending() const override { return false; }
- void RequestCopyOfOutput(
- std::unique_ptr<cc::CopyOutputRequest> output_request) override {}
- int64_t GetDisplayId() const override { return 1; }
-
- private:
- ViewportMetrics display_metrics_;
-
- int32_t* cursor_id_storage_;
-
- DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplay);
-};
-
-ClientWindowId NextUnusedClientWindowId(WindowTree* tree) {
- ClientWindowId client_id;
- for (ClientSpecificId id = 1;; ++id) {
- // Used the id of the client in the upper bits to simplify things.
- const ClientWindowId client_id =
- ClientWindowId(WindowIdToTransportId(WindowId(tree->id(), id)));
- if (!tree->GetWindowByClientId(client_id))
- return client_id;
- }
-}
-
-} // namespace
-
-// WindowManagerWindowTreeFactorySetTestApi ------------------------------------
-
-WindowManagerWindowTreeFactorySetTestApi::
- WindowManagerWindowTreeFactorySetTestApi(
- WindowManagerWindowTreeFactorySet*
- window_manager_window_tree_factory_set)
- : window_manager_window_tree_factory_set_(
- window_manager_window_tree_factory_set) {}
-
-WindowManagerWindowTreeFactorySetTestApi::
- ~WindowManagerWindowTreeFactorySetTestApi() {}
-
-void WindowManagerWindowTreeFactorySetTestApi::Add(const UserId& user_id) {
- WindowManagerWindowTreeFactory* factory =
- window_manager_window_tree_factory_set_->Add(user_id, nullptr);
- factory->CreateWindowTree(nullptr, nullptr);
-}
-
-// TestPlatformDisplayFactory -------------------------------------------------
-
-TestPlatformDisplayFactory::TestPlatformDisplayFactory(
- int32_t* cursor_id_storage)
- : cursor_id_storage_(cursor_id_storage) {}
-
-TestPlatformDisplayFactory::~TestPlatformDisplayFactory() {}
-
-PlatformDisplay* TestPlatformDisplayFactory::CreatePlatformDisplay() {
- return new TestPlatformDisplay(cursor_id_storage_);
-}
-
-// WindowTreeTestApi ---------------------------------------------------------
-
-WindowTreeTestApi::WindowTreeTestApi(WindowTree* tree) : tree_(tree) {}
-WindowTreeTestApi::~WindowTreeTestApi() {}
-
-void WindowTreeTestApi::SetEventObserver(mojom::EventMatcherPtr matcher,
- uint32_t event_observer_id) {
- tree_->SetEventObserver(std::move(matcher), event_observer_id);
-}
-
-// DisplayTestApi ------------------------------------------------------------
-
-DisplayTestApi::DisplayTestApi(Display* display) : display_(display) {}
-DisplayTestApi::~DisplayTestApi() {}
-
-// EventDispatcherTestApi ----------------------------------------------------
-
-bool EventDispatcherTestApi::IsWindowPointerTarget(
- const ServerWindow* window) const {
- for (const auto& pair : ed_->pointer_targets_) {
- if (pair.second.window == window)
- return true;
- }
- return false;
-}
-
-int EventDispatcherTestApi::NumberPointerTargetsForWindow(
- ServerWindow* window) {
- int count = 0;
- for (const auto& pair : ed_->pointer_targets_)
- if (pair.second.window == window)
- count++;
- return count;
-}
-
-// TestDisplayBinding ---------------------------------------------------------
-
-WindowTree* TestDisplayBinding::CreateWindowTree(ServerWindow* root) {
- const uint32_t embed_flags = 0;
- WindowTree* tree = window_server_->EmbedAtWindow(
- root, shell::mojom::kRootUserID, mus::mojom::WindowTreeClientPtr(),
- embed_flags, base::WrapUnique(new WindowManagerAccessPolicy));
- tree->ConfigureWindowManager();
- return tree;
-}
-
-// TestWindowManager ----------------------------------------------------------
-
-void TestWindowManager::WmCreateTopLevelWindow(
- uint32_t change_id,
- ClientSpecificId requesting_client_id,
- mojo::Map<mojo::String, mojo::Array<uint8_t>> properties) {
- got_create_top_level_window_ = true;
- change_id_ = change_id;
-}
-
-void TestWindowManager::WmClientJankinessChanged(ClientSpecificId client_id,
- bool janky) {}
-
-void TestWindowManager::OnAccelerator(uint32_t id,
- std::unique_ptr<ui::Event> event) {
- on_accelerator_called_ = true;
- on_accelerator_id_ = id;
-}
-
-// TestWindowTreeClient -------------------------------------------------------
-
-TestWindowTreeClient::TestWindowTreeClient()
- : binding_(this), record_on_change_completed_(false) {}
-TestWindowTreeClient::~TestWindowTreeClient() {}
-
-void TestWindowTreeClient::Bind(
- mojo::InterfaceRequest<mojom::WindowTreeClient> request) {
- binding_.Bind(std::move(request));
-}
-
-void TestWindowTreeClient::OnEmbed(uint16_t client_id,
- mojom::WindowDataPtr root,
- mus::mojom::WindowTreePtr tree,
- int64_t display_id,
- Id focused_window_id,
- bool drawn) {
- // TODO(sky): add test coverage of |focused_window_id|.
- tracker_.OnEmbed(client_id, std::move(root), drawn);
-}
-
-void TestWindowTreeClient::OnEmbeddedAppDisconnected(uint32_t window) {
- tracker_.OnEmbeddedAppDisconnected(window);
-}
-
-void TestWindowTreeClient::OnUnembed(Id window_id) {
- tracker_.OnUnembed(window_id);
-}
-
-void TestWindowTreeClient::OnLostCapture(Id window_id) {}
-
-void TestWindowTreeClient::OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr data,
- int64_t display_id,
- bool drawn) {
- tracker_.OnTopLevelCreated(change_id, std::move(data), drawn);
-}
-
-void TestWindowTreeClient::OnWindowBoundsChanged(uint32_t window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- tracker_.OnWindowBoundsChanged(window, std::move(old_bounds),
- std::move(new_bounds));
-}
-
-void TestWindowTreeClient::OnClientAreaChanged(
- uint32_t window_id,
- const gfx::Insets& new_client_area,
- mojo::Array<gfx::Rect> new_additional_client_areas) {}
-
-void TestWindowTreeClient::OnTransientWindowAdded(
- uint32_t window_id,
- uint32_t transient_window_id) {}
-
-void TestWindowTreeClient::OnTransientWindowRemoved(
- uint32_t window_id,
- uint32_t transient_window_id) {}
-
-void TestWindowTreeClient::OnWindowHierarchyChanged(
- uint32_t window,
- uint32_t old_parent,
- uint32_t new_parent,
- mojo::Array<mojom::WindowDataPtr> windows) {
- tracker_.OnWindowHierarchyChanged(window, old_parent, new_parent,
- std::move(windows));
-}
-
-void TestWindowTreeClient::OnWindowReordered(uint32_t window_id,
- uint32_t relative_window_id,
- mojom::OrderDirection direction) {
- tracker_.OnWindowReordered(window_id, relative_window_id, direction);
-}
-
-void TestWindowTreeClient::OnWindowDeleted(uint32_t window) {
- tracker_.OnWindowDeleted(window);
-}
-
-void TestWindowTreeClient::OnWindowVisibilityChanged(uint32_t window,
- bool visible) {
- tracker_.OnWindowVisibilityChanged(window, visible);
-}
-
-void TestWindowTreeClient::OnWindowOpacityChanged(uint32_t window,
- float old_opacity,
- float new_opacity) {
- tracker_.OnWindowOpacityChanged(window, new_opacity);
-}
-
-void TestWindowTreeClient::OnWindowParentDrawnStateChanged(uint32_t window,
- bool drawn) {
- tracker_.OnWindowParentDrawnStateChanged(window, drawn);
-}
-
-void TestWindowTreeClient::OnWindowSharedPropertyChanged(
- uint32_t window,
- const mojo::String& name,
- mojo::Array<uint8_t> new_data) {
- tracker_.OnWindowSharedPropertyChanged(window, name, std::move(new_data));
-}
-
-void TestWindowTreeClient::OnWindowInputEvent(uint32_t event_id,
- uint32_t window,
- std::unique_ptr<ui::Event> event,
- uint32_t event_observer_id) {
- tracker_.OnWindowInputEvent(window, *event.get(), event_observer_id);
-}
-
-void TestWindowTreeClient::OnEventObserved(std::unique_ptr<ui::Event> event,
- uint32_t event_observer_id) {
- tracker_.OnEventObserved(*event.get(), event_observer_id);
-}
-
-void TestWindowTreeClient::OnWindowFocused(uint32_t focused_window_id) {
- tracker_.OnWindowFocused(focused_window_id);
-}
-
-void TestWindowTreeClient::OnWindowPredefinedCursorChanged(
- uint32_t window_id,
- mojom::Cursor cursor_id) {
- tracker_.OnWindowPredefinedCursorChanged(window_id, cursor_id);
-}
-
-void TestWindowTreeClient::OnChangeCompleted(uint32_t change_id, bool success) {
- if (record_on_change_completed_)
- tracker_.OnChangeCompleted(change_id, success);
-}
-
-void TestWindowTreeClient::RequestClose(uint32_t window_id) {}
-
-void TestWindowTreeClient::GetWindowManager(
- mojo::AssociatedInterfaceRequest<mojom::WindowManager> internal) {}
-
-// TestWindowTreeBinding ------------------------------------------------------
-
-TestWindowTreeBinding::TestWindowTreeBinding(WindowTree* tree)
- : WindowTreeBinding(&client_), tree_(tree) {}
-TestWindowTreeBinding::~TestWindowTreeBinding() {}
-
-mojom::WindowManager* TestWindowTreeBinding::GetWindowManager() {
- if (!window_manager_.get())
- window_manager_.reset(new TestWindowManager);
- return window_manager_.get();
-}
-void TestWindowTreeBinding::SetIncomingMethodCallProcessingPaused(bool paused) {
- is_paused_ = paused;
-}
-
-// TestWindowServerDelegate ----------------------------------------------
-
-TestWindowServerDelegate::TestWindowServerDelegate() {}
-TestWindowServerDelegate::~TestWindowServerDelegate() {}
-
-Display* TestWindowServerDelegate::AddDisplay() {
- // Display manages its own lifetime.
- Display* display = new Display(window_server_, PlatformDisplayInitParams());
- display->Init(nullptr);
- return display;
-}
-
-void TestWindowServerDelegate::OnNoMoreDisplays() {
- got_on_no_more_displays_ = true;
-}
-
-std::unique_ptr<WindowTreeBinding>
-TestWindowServerDelegate::CreateWindowTreeBinding(
- BindingType type,
- ws::WindowServer* window_server,
- ws::WindowTree* tree,
- mojom::WindowTreeRequest* tree_request,
- mojom::WindowTreeClientPtr* client) {
- std::unique_ptr<TestWindowTreeBinding> binding(
- new TestWindowTreeBinding(tree));
- bindings_.push_back(binding.get());
- return std::move(binding);
-}
-
-void TestWindowServerDelegate::CreateDefaultDisplays() {
- DCHECK(num_displays_to_create_);
- DCHECK(window_server_);
-
- for (int i = 0; i < num_displays_to_create_; ++i)
- AddDisplay();
-}
-
-bool TestWindowServerDelegate::IsTestConfig() const {
- return true;
-}
-
-// WindowEventTargetingHelper ------------------------------------------------
-
-WindowEventTargetingHelper::WindowEventTargetingHelper()
- : wm_client_(nullptr),
- cursor_id_(0),
- platform_display_factory_(&cursor_id_),
- display_binding_(nullptr),
- display_(nullptr),
- surfaces_state_(new SurfacesState()),
- window_server_(nullptr) {
- PlatformDisplay::set_factory_for_testing(&platform_display_factory_);
- window_server_.reset(
- new WindowServer(&window_server_delegate_, surfaces_state_));
- PlatformDisplayInitParams display_init_params;
- display_init_params.surfaces_state = surfaces_state_;
- display_ = new Display(window_server_.get(), display_init_params);
- display_binding_ = new TestDisplayBinding(window_server_.get());
- display_->Init(base::WrapUnique(display_binding_));
- wm_client_ = window_server_delegate_.last_client();
- wm_client_->tracker()->changes()->clear();
-}
-
-WindowEventTargetingHelper::~WindowEventTargetingHelper() {}
-
-ServerWindow* WindowEventTargetingHelper::CreatePrimaryTree(
- const gfx::Rect& root_window_bounds,
- const gfx::Rect& window_bounds) {
- WindowTree* wm_tree = window_server_->GetTreeWithId(1);
- const ClientWindowId embed_window_id(
- WindowIdToTransportId(WindowId(wm_tree->id(), 1)));
- EXPECT_TRUE(wm_tree->NewWindow(embed_window_id, ServerWindow::Properties()));
- EXPECT_TRUE(wm_tree->SetWindowVisibility(embed_window_id, true));
- EXPECT_TRUE(wm_tree->AddWindow(FirstRootId(wm_tree), embed_window_id));
- display_->root_window()->SetBounds(root_window_bounds);
- mojom::WindowTreeClientPtr client;
- mojom::WindowTreeClientRequest client_request = GetProxy(&client);
- wm_client_->Bind(std::move(client_request));
- const uint32_t embed_flags = 0;
- wm_tree->Embed(embed_window_id, std::move(client), embed_flags);
- ServerWindow* embed_window = wm_tree->GetWindowByClientId(embed_window_id);
- WindowTree* tree1 = window_server_->GetTreeWithRoot(embed_window);
- EXPECT_NE(nullptr, tree1);
- EXPECT_NE(tree1, wm_tree);
- WindowTreeTestApi(tree1).set_user_id(wm_tree->user_id());
-
- embed_window->SetBounds(window_bounds);
-
- return embed_window;
-}
-
-void WindowEventTargetingHelper::CreateSecondaryTree(
- ServerWindow* embed_window,
- const gfx::Rect& window_bounds,
- TestWindowTreeClient** out_client,
- WindowTree** window_tree,
- ServerWindow** window) {
- WindowTree* tree1 = window_server_->GetTreeWithRoot(embed_window);
- ASSERT_TRUE(tree1 != nullptr);
- const ClientWindowId child1_id(
- WindowIdToTransportId(WindowId(tree1->id(), 1)));
- EXPECT_TRUE(tree1->NewWindow(child1_id, ServerWindow::Properties()));
- ServerWindow* child1 = tree1->GetWindowByClientId(child1_id);
- ASSERT_TRUE(child1);
- EXPECT_TRUE(tree1->AddWindow(ClientWindowIdForWindow(tree1, embed_window),
- child1_id));
- tree1->GetDisplay(embed_window)->AddActivationParent(embed_window);
-
- child1->SetVisible(true);
- child1->SetBounds(window_bounds);
- EnableHitTest(child1);
-
- TestWindowTreeClient* embed_client =
- window_server_delegate_.last_client();
- embed_client->tracker()->changes()->clear();
- wm_client_->tracker()->changes()->clear();
-
- *out_client = embed_client;
- *window_tree = tree1;
- *window = child1;
-}
-
-void WindowEventTargetingHelper::SetTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- message_loop_.SetTaskRunner(task_runner);
-}
-
-// ----------------------------------------------------------------------------
-
-ServerWindow* FirstRoot(WindowTree* tree) {
- return tree->roots().size() == 1u
- ? tree->GetWindow((*tree->roots().begin())->id())
- : nullptr;
-}
-
-ClientWindowId FirstRootId(WindowTree* tree) {
- ServerWindow* first_root = FirstRoot(tree);
- return first_root ? ClientWindowIdForWindow(tree, first_root)
- : ClientWindowId();
-}
-
-ClientWindowId ClientWindowIdForWindow(WindowTree* tree,
- const ServerWindow* window) {
- ClientWindowId client_window_id;
- // If window isn't known we'll return 0, which should then error out.
- tree->IsWindowKnown(window, &client_window_id);
- return client_window_id;
-}
-
-ServerWindow* NewWindowInTree(WindowTree* tree, ClientWindowId* client_id) {
- return NewWindowInTreeWithParent(tree, FirstRoot(tree), client_id);
-}
-
-ServerWindow* NewWindowInTreeWithParent(WindowTree* tree,
- ServerWindow* parent,
- ClientWindowId* client_id) {
- if (!parent)
- return nullptr;
- ClientWindowId parent_client_id;
- if (!tree->IsWindowKnown(parent, &parent_client_id))
- return nullptr;
- ClientWindowId client_window_id = NextUnusedClientWindowId(tree);
- if (!tree->NewWindow(client_window_id, ServerWindow::Properties()))
- return nullptr;
- if (!tree->SetWindowVisibility(client_window_id, true))
- return nullptr;
- if (!tree->AddWindow(parent_client_id, client_window_id))
- return nullptr;
- *client_id = client_window_id;
- return tree->GetWindowByClientId(client_window_id);
-}
-
-} // namespace test
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/test_utils.h b/chromium/components/mus/ws/test_utils.h
deleted file mode 100644
index ede927722ec..00000000000
--- a/chromium/components/mus/ws/test_utils.h
+++ /dev/null
@@ -1,537 +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 COMPONENTS_MUS_WS_TEST_UTILS_H_
-#define COMPONENTS_MUS_WS_TEST_UTILS_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "components/mus/public/interfaces/display.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/display_binding.h"
-#include "components/mus/ws/event_dispatcher.h"
-#include "components/mus/ws/platform_display.h"
-#include "components/mus/ws/platform_display_factory.h"
-#include "components/mus/ws/test_change_tracker.h"
-#include "components/mus/ws/user_activity_monitor.h"
-#include "components/mus/ws/user_display_manager.h"
-#include "components/mus/ws/user_id.h"
-#include "components/mus/ws/window_manager_state.h"
-#include "components/mus/ws/window_manager_window_tree_factory_set.h"
-#include "components/mus/ws/window_server_delegate.h"
-#include "components/mus/ws/window_tree.h"
-#include "components/mus/ws/window_tree_binding.h"
-
-namespace mus {
-namespace ws {
-namespace test {
-
-// Collection of utilities useful in creating mus tests.
-
-class WindowManagerWindowTreeFactorySetTestApi {
- public:
- explicit WindowManagerWindowTreeFactorySetTestApi(
- WindowManagerWindowTreeFactorySet*
- window_manager_window_tree_factory_set);
- ~WindowManagerWindowTreeFactorySetTestApi();
-
- void Add(const UserId& user_id);
-
- private:
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowTreeFactorySetTestApi);
-};
-
-// -----------------------------------------------------------------------------
-
-class UserDisplayManagerTestApi {
- public:
- explicit UserDisplayManagerTestApi(UserDisplayManager* udm) : udm_(udm) {}
- ~UserDisplayManagerTestApi() {}
-
- void SetTestObserver(mojom::DisplayManagerObserver* observer) {
- udm_->test_observer_ = observer;
- if (observer)
- udm_->OnObserverAdded(observer);
- }
-
- private:
- UserDisplayManager* udm_;
-
- DISALLOW_COPY_AND_ASSIGN(UserDisplayManagerTestApi);
-};
-
-// -----------------------------------------------------------------------------
-
-class UserActivityMonitorTestApi {
- public:
- explicit UserActivityMonitorTestApi(UserActivityMonitor* monitor)
- : monitor_(monitor) {}
-
- void SetTimerTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- monitor_->idle_timer_.SetTaskRunner(task_runner);
- }
-
- private:
- UserActivityMonitor* monitor_;
- DISALLOW_COPY_AND_ASSIGN(UserActivityMonitorTestApi);
-};
-
-// -----------------------------------------------------------------------------
-
-class WindowTreeTestApi {
- public:
- explicit WindowTreeTestApi(WindowTree* tree);
- ~WindowTreeTestApi();
-
- void set_user_id(const UserId& user_id) { tree_->user_id_ = user_id; }
- void set_window_manager_internal(mojom::WindowManager* wm_internal) {
- tree_->window_manager_internal_ = wm_internal;
- }
- void AckOldestEvent() {
- tree_->OnWindowInputEventAck(tree_->event_ack_id_,
- mojom::EventResult::UNHANDLED);
- }
- void EnableCapture() { tree_->event_ack_id_ = 1u; }
- void AckLastEvent(mojom::EventResult result) {
- tree_->OnWindowInputEventAck(tree_->event_ack_id_, result);
- }
-
- void SetEventObserver(mojom::EventMatcherPtr matcher,
- uint32_t event_observer_id);
-
- private:
- WindowTree* tree_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTreeTestApi);
-};
-
-// -----------------------------------------------------------------------------
-
-class DisplayTestApi {
- public:
- explicit DisplayTestApi(Display* display);
- ~DisplayTestApi();
-
- void OnEvent(const ui::Event& event) { display_->OnEvent(event); }
-
- private:
- Display* display_;
-
- DISALLOW_COPY_AND_ASSIGN(DisplayTestApi);
-};
-
-// -----------------------------------------------------------------------------
-
-class EventDispatcherTestApi {
- public:
- explicit EventDispatcherTestApi(EventDispatcher* ed) : ed_(ed) {}
- ~EventDispatcherTestApi() {}
-
- bool AreAnyPointersDown() const { return ed_->AreAnyPointersDown(); }
- bool is_mouse_button_down() const { return ed_->mouse_button_down_; }
- bool IsWindowPointerTarget(const ServerWindow* window) const;
- int NumberPointerTargetsForWindow(ServerWindow* window);
- ModalWindowController* modal_window_controller() const {
- return &ed_->modal_window_controller_;
- }
- ServerWindow* capture_window() { return ed_->capture_window_; }
-
- private:
- EventDispatcher* ed_;
-
- DISALLOW_COPY_AND_ASSIGN(EventDispatcherTestApi);
-};
-
-// -----------------------------------------------------------------------------
-
-class ModalWindowControllerTestApi {
- public:
- explicit ModalWindowControllerTestApi(ModalWindowController* mwc)
- : mwc_(mwc) {}
- ~ModalWindowControllerTestApi() {}
-
- ServerWindow* GetActiveSystemModalWindow() const {
- return mwc_->GetActiveSystemModalWindow();
- }
-
- private:
- ModalWindowController* mwc_;
-
- DISALLOW_COPY_AND_ASSIGN(ModalWindowControllerTestApi);
-};
-
-// -----------------------------------------------------------------------------
-
-class WindowManagerStateTestApi {
- public:
- explicit WindowManagerStateTestApi(WindowManagerState* wms) : wms_(wms) {}
- ~WindowManagerStateTestApi() {}
-
- void DispatchInputEventToWindow(ServerWindow* target,
- ClientSpecificId client_id,
- const ui::Event& event,
- Accelerator* accelerator) {
- wms_->DispatchInputEventToWindow(target, client_id, event, accelerator);
- }
-
- ClientSpecificId GetEventTargetClientId(ServerWindow* window,
- bool in_nonclient_area) {
- return wms_->GetEventTargetClientId(window, in_nonclient_area);
- }
-
- void ProcessEvent(const ui::Event& event) { wms_->ProcessEvent(event); }
-
- void OnEventAckTimeout(ClientSpecificId client_id) {
- wms_->OnEventAckTimeout(client_id);
- }
-
- ClientSpecificId GetEventTargetClientId(const ServerWindow* window,
- bool in_nonclient_area) {
- return wms_->GetEventTargetClientId(window, in_nonclient_area);
- }
-
- mojom::WindowTree* tree_awaiting_input_ack() {
- return wms_->tree_awaiting_input_ack_;
- }
-
- private:
- WindowManagerState* wms_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowManagerStateTestApi);
-};
-
-// -----------------------------------------------------------------------------
-
-// Factory that always embeds the new WindowTree as the root user id.
-class TestDisplayBinding : public DisplayBinding {
- public:
- explicit TestDisplayBinding(WindowServer* window_server)
- : window_server_(window_server) {}
- ~TestDisplayBinding() override {}
-
- private:
- // DisplayBinding:
- WindowTree* CreateWindowTree(ServerWindow* root) override;
-
- WindowServer* window_server_;
-
- DISALLOW_COPY_AND_ASSIGN(TestDisplayBinding);
-};
-
-// -----------------------------------------------------------------------------
-
-// Factory that dispenses TestPlatformDisplays.
-class TestPlatformDisplayFactory : public PlatformDisplayFactory {
- public:
- explicit TestPlatformDisplayFactory(int32_t* cursor_id_storage);
- ~TestPlatformDisplayFactory();
-
- // PlatformDisplayFactory:
- PlatformDisplay* CreatePlatformDisplay() override;
-
- private:
- int32_t* cursor_id_storage_;
-
- DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplayFactory);
-};
-
-// -----------------------------------------------------------------------------
-
-class TestWindowManager : public mojom::WindowManager {
- public:
- TestWindowManager()
- : got_create_top_level_window_(false),
- change_id_(0u),
- on_accelerator_called_(false),
- on_accelerator_id_(0u) {}
- ~TestWindowManager() override {}
-
- bool did_call_create_top_level_window(uint32_t* change_id) {
- if (!got_create_top_level_window_)
- return false;
-
- got_create_top_level_window_ = false;
- *change_id = change_id_;
- return true;
- }
-
- bool on_accelerator_called() { return on_accelerator_called_; }
- uint32_t on_accelerator_id() { return on_accelerator_id_; }
-
- private:
- // WindowManager:
- void OnConnect(uint16_t client_id) override {}
- void WmNewDisplayAdded(mus::mojom::DisplayPtr display,
- mus::mojom::WindowDataPtr root,
- bool drawn) override {}
- void WmSetBounds(uint32_t change_id,
- uint32_t window_id,
- const gfx::Rect& bounds) override {}
- void WmSetProperty(uint32_t change_id,
- uint32_t window_id,
- const mojo::String& name,
- mojo::Array<uint8_t> value) override {}
- void WmCreateTopLevelWindow(
- uint32_t change_id,
- ClientSpecificId requesting_client_id,
- mojo::Map<mojo::String, mojo::Array<uint8_t>> properties) override;
- void WmClientJankinessChanged(ClientSpecificId client_id,
- bool janky) override;
- void OnAccelerator(uint32_t id, std::unique_ptr<ui::Event> event) override;
-
- bool got_create_top_level_window_;
- uint32_t change_id_;
-
- bool on_accelerator_called_;
- uint32_t on_accelerator_id_;
-
- DISALLOW_COPY_AND_ASSIGN(TestWindowManager);
-};
-
-// -----------------------------------------------------------------------------
-
-// WindowTreeClient implementation that logs all calls to a TestChangeTracker.
-class TestWindowTreeClient : public mus::mojom::WindowTreeClient {
- public:
- TestWindowTreeClient();
- ~TestWindowTreeClient() override;
-
- TestChangeTracker* tracker() { return &tracker_; }
-
- void Bind(mojo::InterfaceRequest<mojom::WindowTreeClient> request);
-
- void set_record_on_change_completed(bool value) {
- record_on_change_completed_ = value;
- }
-
- private:
- // WindowTreeClient:
- void OnEmbed(uint16_t client_id,
- mojom::WindowDataPtr root,
- mus::mojom::WindowTreePtr tree,
- int64_t display_id,
- Id focused_window_id,
- bool drawn) override;
- void OnEmbeddedAppDisconnected(uint32_t window) override;
- void OnUnembed(Id window_id) override;
- void OnLostCapture(Id window_id) override;
- void OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr data,
- int64_t display_id,
- bool drawn) override;
- void OnWindowBoundsChanged(uint32_t window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) override;
- void OnClientAreaChanged(
- uint32_t window_id,
- const gfx::Insets& new_client_area,
- mojo::Array<gfx::Rect> new_additional_client_areas) override;
- void OnTransientWindowAdded(uint32_t window_id,
- uint32_t transient_window_id) override;
- void OnTransientWindowRemoved(uint32_t window_id,
- uint32_t transient_window_id) override;
- void OnWindowHierarchyChanged(
- uint32_t window,
- uint32_t old_parent,
- uint32_t new_parent,
- mojo::Array<mojom::WindowDataPtr> windows) override;
- void OnWindowReordered(uint32_t window_id,
- uint32_t relative_window_id,
- mojom::OrderDirection direction) override;
- void OnWindowDeleted(uint32_t window) override;
- void OnWindowVisibilityChanged(uint32_t window, bool visible) override;
- void OnWindowOpacityChanged(uint32_t window,
- float old_opacity,
- float new_opacity) override;
- void OnWindowParentDrawnStateChanged(uint32_t window, bool drawn) override;
- void OnWindowSharedPropertyChanged(uint32_t window,
- const mojo::String& name,
- mojo::Array<uint8_t> new_data) override;
- void OnWindowInputEvent(uint32_t event_id,
- uint32_t window,
- std::unique_ptr<ui::Event> event,
- uint32_t event_observer_id) override;
- void OnEventObserved(std::unique_ptr<ui::Event> event,
- uint32_t event_observer_id) override;
- void OnWindowFocused(uint32_t focused_window_id) override;
- void OnWindowPredefinedCursorChanged(uint32_t window_id,
- mojom::Cursor cursor_id) override;
- void OnChangeCompleted(uint32_t change_id, bool success) override;
- void RequestClose(uint32_t window_id) override;
- void GetWindowManager(
- mojo::AssociatedInterfaceRequest<mojom::WindowManager> internal) override;
-
- TestChangeTracker tracker_;
- mojo::Binding<mojom::WindowTreeClient> binding_;
- bool record_on_change_completed_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClient);
-};
-
-// -----------------------------------------------------------------------------
-
-// WindowTreeBinding implementation that vends TestWindowTreeBinding.
-class TestWindowTreeBinding : public WindowTreeBinding {
- public:
- explicit TestWindowTreeBinding(WindowTree* tree);
- ~TestWindowTreeBinding() override;
-
- WindowTree* tree() { return tree_; }
- TestWindowTreeClient* client() { return &client_; }
-
- bool is_paused() const { return is_paused_; }
-
- // WindowTreeBinding:
- mojom::WindowManager* GetWindowManager() override;
- void SetIncomingMethodCallProcessingPaused(bool paused) override;
-
- private:
- WindowTree* tree_;
- TestWindowTreeClient client_;
- bool is_paused_ = false;
- std::unique_ptr<TestWindowManager> window_manager_;
-
- DISALLOW_COPY_AND_ASSIGN(TestWindowTreeBinding);
-};
-
-// -----------------------------------------------------------------------------
-
-// WindowServerDelegate that creates TestWindowTreeClients.
-class TestWindowServerDelegate : public WindowServerDelegate {
- public:
- TestWindowServerDelegate();
- ~TestWindowServerDelegate() override;
-
- void set_window_server(WindowServer* window_server) {
- window_server_ = window_server;
- }
-
- void set_num_displays_to_create(int count) {
- num_displays_to_create_ = count;
- }
-
- TestWindowTreeClient* last_client() {
- return last_binding() ? last_binding()->client() : nullptr;
- }
- TestWindowTreeBinding* last_binding() {
- return bindings_.empty() ? nullptr : bindings_.back();
- }
-
- std::vector<TestWindowTreeBinding*>* bindings() { return &bindings_; }
-
- bool got_on_no_more_displays() const { return got_on_no_more_displays_; }
-
- Display* AddDisplay();
-
- // WindowServerDelegate:
- void OnNoMoreDisplays() override;
- std::unique_ptr<WindowTreeBinding> CreateWindowTreeBinding(
- BindingType type,
- ws::WindowServer* window_server,
- ws::WindowTree* tree,
- mojom::WindowTreeRequest* tree_request,
- mojom::WindowTreeClientPtr* client) override;
- void CreateDefaultDisplays() override;
- bool IsTestConfig() const override;
-
- private:
- // If CreateDefaultDisplays() this is the number of Displays that are
- // created. The default is 0, which results in a DCHECK.
- int num_displays_to_create_ = 0;
- WindowServer* window_server_ = nullptr;
- bool got_on_no_more_displays_ = false;
- // All TestWindowTreeBinding objects created via CreateWindowTreeBinding.
- // These are owned by the corresponding WindowTree.
- std::vector<TestWindowTreeBinding*> bindings_;
-
- DISALLOW_COPY_AND_ASSIGN(TestWindowServerDelegate);
-};
-
-// -----------------------------------------------------------------------------
-
-// Helper class which owns all of the necessary objects to test event targeting
-// of ServerWindow objects.
-class WindowEventTargetingHelper {
- public:
- WindowEventTargetingHelper();
- ~WindowEventTargetingHelper();
-
- // Creates |window| as an embeded window of the primary tree. This window is a
- // root window of its own tree, with bounds |window_bounds|. The bounds of the
- // root window of |display_| are defined by |root_window_bounds|.
- ServerWindow* CreatePrimaryTree(const gfx::Rect& root_window_bounds,
- const gfx::Rect& window_bounds);
- // Creates a secondary tree, embedded as a child of |embed_window|. The
- // resulting |window| is setup for event targeting, with bounds
- // |window_bounds|.
- void CreateSecondaryTree(ServerWindow* embed_window,
- const gfx::Rect& window_bounds,
- TestWindowTreeClient** out_client,
- WindowTree** window_tree,
- ServerWindow** window);
- // Sets the task runner for |message_loop_|
- void SetTaskRunner(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
-
- int32_t cursor_id() { return cursor_id_; }
- Display* display() { return display_; }
- TestWindowTreeBinding* last_binding() {
- return window_server_delegate_.last_binding();
- }
- TestWindowTreeClient* last_window_tree_client() {
- return window_server_delegate_.last_client();
- }
- TestWindowTreeClient* wm_client() { return wm_client_; }
- WindowServer* window_server() { return window_server_.get(); }
-
- private:
- // TestWindowTreeClient that is used for the WM client. Owned by
- // |window_server_delegate_|
- TestWindowTreeClient* wm_client_;
- int32_t cursor_id_;
- TestPlatformDisplayFactory platform_display_factory_;
- TestWindowServerDelegate window_server_delegate_;
- // Owned by WindowServer
- TestDisplayBinding* display_binding_;
- // Owned by WindowServer's DisplayManager.
- Display* display_;
- scoped_refptr<SurfacesState> surfaces_state_;
- std::unique_ptr<WindowServer> window_server_;
- // Needed to Bind to |wm_client_|
- base::MessageLoop message_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowEventTargetingHelper);
-};
-
-// -----------------------------------------------------------------------------
-
-// Returns the first and only root of |tree|. If |tree| has zero or more than
-// one root returns null.
-ServerWindow* FirstRoot(WindowTree* tree);
-
-// Returns the ClientWindowId of the first root of |tree|, or an empty
-// ClientWindowId if |tree| has zero or more than one root.
-ClientWindowId FirstRootId(WindowTree* tree);
-
-// Returns |tree|s ClientWindowId for |window|.
-ClientWindowId ClientWindowIdForWindow(WindowTree* tree,
- const ServerWindow* window);
-
-// Creates a new visible window as a child of the single root of |tree|.
-// |client_id| set to the ClientWindowId of the new window.
-ServerWindow* NewWindowInTree(WindowTree* tree, ClientWindowId* client_id);
-ServerWindow* NewWindowInTreeWithParent(WindowTree* tree,
- ServerWindow* parent,
- ClientWindowId* client_id);
-
-} // namespace test
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_TEST_UTILS_H_
diff --git a/chromium/components/mus/ws/touch_controller.cc b/chromium/components/mus/ws/touch_controller.cc
deleted file mode 100644
index e78b3489dc9..00000000000
--- a/chromium/components/mus/ws/touch_controller.cc
+++ /dev/null
@@ -1,105 +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 "components/mus/ws/touch_controller.h"
-
-#include <set>
-#include <vector>
-
-#include "base/logging.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/display_manager.h"
-#include "ui/events/devices/device_data_manager.h"
-#include "ui/events/devices/touchscreen_device.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/transform.h"
-
-namespace mus {
-namespace ws {
-
-namespace {
-
-// Computes the scale ratio for the TouchEvent's radius.
-double ComputeTouchResolutionScale(const Display* touch_display,
- const ui::TouchscreenDevice& touch_device) {
- gfx::Size touch_display_size = touch_display->GetSize();
-
- if (touch_device.size.IsEmpty() || touch_display_size.IsEmpty())
- return 1.0;
-
- double display_area = touch_display_size.GetArea();
- double touch_area = touch_device.size.GetArea();
- double ratio = std::sqrt(display_area / touch_area);
-
- return ratio;
-}
-
-// Computes a touch transform that maps from window bounds to touchscreen size.
-// Assumes scale factor of 1.0.
-gfx::Transform ComputeTouchTransform(
- const Display* touch_display,
- const ui::TouchscreenDevice& touch_device) {
- gfx::Size touch_display_size = touch_display->GetSize();
-
- gfx::SizeF current_size(touch_display_size);
- gfx::SizeF touch_area(touch_device.size);
- gfx::Transform transform;
-
- if (current_size.IsEmpty() || touch_area.IsEmpty())
- return transform;
-
- // Take care of scaling between touchscreen area and display resolution.
- transform.Scale(current_size.width() / touch_area.width(),
- current_size.height() / touch_area.height());
- return transform;
-}
-
-} // namespace
-
-TouchController::TouchController(DisplayManager* display_manager)
- : display_manager_(display_manager) {
- DCHECK(display_manager_);
- ui::DeviceDataManager::GetInstance()->AddObserver(this);
-}
-
-TouchController::~TouchController() {
- ui::DeviceDataManager::GetInstance()->RemoveObserver(this);
-}
-
-void TouchController::UpdateTouchTransforms() const {
- ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance();
- device_manager->ClearTouchDeviceAssociations();
-
- const std::set<Display*>& touch_displays = display_manager_->displays();
- const std::vector<ui::TouchscreenDevice>& touch_devices =
- device_manager->GetTouchscreenDevices();
-
- // Mash can only handle a single display so this doesn't implement support for
- // matching touchscreens with multiple displays.
- // TODO(kylechar): Implement support for multiple displays when needed.
- if (touch_displays.size() == 1 && touch_devices.size() == 1) {
- const Display* touch_display = *touch_displays.begin();
- const ui::TouchscreenDevice& touch_device = touch_devices[0];
-
- int64_t touch_display_id = touch_display->GetPlatformDisplayId();
- int touch_device_id = touch_device.id;
-
- if (touch_device_id != ui::InputDevice::kInvalidId) {
- device_manager->UpdateTouchRadiusScale(
- touch_device_id,
- ComputeTouchResolutionScale(touch_display, touch_device));
-
- device_manager->UpdateTouchInfoForDisplay(
- touch_display_id, touch_device_id,
- ComputeTouchTransform(touch_display, touch_device));
- }
- }
-}
-
-void TouchController::OnTouchscreenDeviceConfigurationChanged() {
- UpdateTouchTransforms();
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/touch_controller.h b/chromium/components/mus/ws/touch_controller.h
deleted file mode 100644
index 4505ce47164..00000000000
--- a/chromium/components/mus/ws/touch_controller.h
+++ /dev/null
@@ -1,37 +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 COMPONENTS_MUS_WS_TOUCH_CONTROLLER_H_
-#define COMPONENTS_MUS_WS_TOUCH_CONTROLLER_H_
-
-#include "base/macros.h"
-#include "ui/events/devices/input_device_event_observer.h"
-
-namespace mus {
-namespace ws {
-
-class DisplayManager;
-
-// Tracks changes to displays and touchscreen devices. Updates the mapping
-// between display devices and touchscreen devices when changes occur.
-class TouchController : public ui::InputDeviceEventObserver {
- public:
- explicit TouchController(DisplayManager* display_manager);
- ~TouchController() override;
-
- void UpdateTouchTransforms() const;
-
- // ui::InputDeviceEventObserver:
- void OnTouchscreenDeviceConfigurationChanged() override;
-
- private:
- DisplayManager* display_manager_;
-
- DISALLOW_COPY_AND_ASSIGN(TouchController);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_TOUCH_CONTROLLER_H_
diff --git a/chromium/components/mus/ws/transient_windows_unittest.cc b/chromium/components/mus/ws/transient_windows_unittest.cc
deleted file mode 100644
index b20e40e467f..00000000000
--- a/chromium/components/mus/ws/transient_windows_unittest.cc
+++ /dev/null
@@ -1,342 +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 "base/macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_observer.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mus {
-namespace ws {
-
-namespace {
-
-class TestTransientWindowObserver : public ServerWindowObserver {
- public:
- TestTransientWindowObserver() : add_count_(0), remove_count_(0) {}
-
- ~TestTransientWindowObserver() override {}
-
- int add_count() const { return add_count_; }
- int remove_count() const { return remove_count_; }
-
- // TransientWindowObserver overrides:
- void OnTransientWindowAdded(ServerWindow* window,
- ServerWindow* transient) override {
- add_count_++;
- }
- void OnTransientWindowRemoved(ServerWindow* window,
- ServerWindow* transient) override {
- remove_count_++;
- }
-
- private:
- int add_count_;
- int remove_count_;
-
- DISALLOW_COPY_AND_ASSIGN(TestTransientWindowObserver);
-};
-
-ServerWindow* CreateTestWindow(TestServerWindowDelegate* delegate,
- const WindowId& window_id,
- ServerWindow* parent) {
- ServerWindow* window = new ServerWindow(delegate, window_id);
- window->SetVisible(true);
- if (parent)
- parent->Add(window);
- else
- delegate->set_root_window(window);
- return window;
-}
-
-std::string ChildWindowIDsAsString(ServerWindow* parent) {
- std::string result;
- for (auto i = parent->children().begin(); i != parent->children().end();
- ++i) {
- if (!result.empty())
- result += " ";
- result += base::IntToString(WindowIdToTransportId((*i)->id()));
- }
- return result;
-}
-
-} // namespace
-
-class TransientWindowsTest : public testing::Test {
- public:
- TransientWindowsTest() {}
- ~TransientWindowsTest() override {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TransientWindowsTest);
-};
-
-TEST_F(TransientWindowsTest, TransientChildren) {
- TestServerWindowDelegate server_window_delegate;
-
- std::unique_ptr<ServerWindow> parent(
- CreateTestWindow(&server_window_delegate, WindowId(), nullptr));
- std::unique_ptr<ServerWindow> w1(
- CreateTestWindow(&server_window_delegate, WindowId(1, 1), parent.get()));
- std::unique_ptr<ServerWindow> w3(
- CreateTestWindow(&server_window_delegate, WindowId(1, 2), parent.get()));
-
- ServerWindow* w2 =
- CreateTestWindow(&server_window_delegate, WindowId(1, 3), parent.get());
-
- // w2 is now owned by w1.
- w1->AddTransientWindow(w2);
- // Stack w1 at the top (end), this should force w2 to be last (on top of w1).
- parent->StackChildAtTop(w1.get());
- ASSERT_EQ(3u, parent->children().size());
- EXPECT_EQ(w2, parent->children().back());
-
- // Destroy w1, which should also destroy w3 (since it's a transient child).
- w1.reset();
- w2 = nullptr;
- ASSERT_EQ(1u, parent->children().size());
- EXPECT_EQ(w3.get(), parent->children()[0]);
-}
-
-// Tests that transient children are stacked as a unit when using stack above.
-TEST_F(TransientWindowsTest, TransientChildrenGroupAbove) {
- TestServerWindowDelegate server_window_delegate;
-
- std::unique_ptr<ServerWindow> parent(
- CreateTestWindow(&server_window_delegate, WindowId(), nullptr));
- std::unique_ptr<ServerWindow> w1(
- CreateTestWindow(&server_window_delegate, WindowId(0, 1), parent.get()));
-
- ServerWindow* w11 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 11), parent.get());
- std::unique_ptr<ServerWindow> w2(
- CreateTestWindow(&server_window_delegate, WindowId(0, 2), parent.get()));
-
- ServerWindow* w21 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 21), parent.get());
- ServerWindow* w211 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 211), parent.get());
- ServerWindow* w212 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 212), parent.get());
- ServerWindow* w213 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 213), parent.get());
- ServerWindow* w22 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 22), parent.get());
- ASSERT_EQ(8u, parent->children().size());
-
- // w11 is now owned by w1.
- w1->AddTransientWindow(w11);
- // w21 is now owned by w2.
- w2->AddTransientWindow(w21);
- // w22 is now owned by w2.
- w2->AddTransientWindow(w22);
- // w211 is now owned by w21.
- w21->AddTransientWindow(w211);
- // w212 is now owned by w21.
- w21->AddTransientWindow(w212);
- // w213 is now owned by w21.
- w21->AddTransientWindow(w213);
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
- parent->StackChildAtTop(w1.get());
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- // This tests that the order in children_ array rather than in
- // transient_children_ array is used when reinserting transient children.
- // If transient_children_ array was used '22' would be following '21'.
- parent->StackChildAtTop(w2.get());
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- w11->Reorder(w2.get(), mojom::OrderDirection::ABOVE);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- w21->Reorder(w1.get(), mojom::OrderDirection::ABOVE);
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- w21->Reorder(w22, mojom::OrderDirection::ABOVE);
- EXPECT_EQ(w213, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
-
- w11->Reorder(w21, mojom::OrderDirection::ABOVE);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
-
- w213->Reorder(w21, mojom::OrderDirection::ABOVE);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- // No change when stacking a transient parent above its transient child.
- w21->Reorder(w211, mojom::OrderDirection::ABOVE);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- // This tests that the order in children_ array rather than in
- // transient_children_ array is used when reinserting transient children.
- // If transient_children_ array was used '22' would be following '21'.
- w2->Reorder(w1.get(), mojom::OrderDirection::ABOVE);
- EXPECT_EQ(w212, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
-
- w11->Reorder(w213, mojom::OrderDirection::ABOVE);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-}
-
-TEST_F(TransientWindowsTest, TransienChildGroupBelow) {
- TestServerWindowDelegate server_window_delegate;
-
- std::unique_ptr<ServerWindow> parent(
- CreateTestWindow(&server_window_delegate, WindowId(), nullptr));
- std::unique_ptr<ServerWindow> w1(
- CreateTestWindow(&server_window_delegate, WindowId(0, 1), parent.get()));
-
- ServerWindow* w11 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 11), parent.get());
- std::unique_ptr<ServerWindow> w2(
- CreateTestWindow(&server_window_delegate, WindowId(0, 2), parent.get()));
-
- ServerWindow* w21 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 21), parent.get());
- ServerWindow* w211 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 211), parent.get());
- ServerWindow* w212 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 212), parent.get());
- ServerWindow* w213 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 213), parent.get());
- ServerWindow* w22 =
- CreateTestWindow(&server_window_delegate, WindowId(0, 22), parent.get());
- ASSERT_EQ(8u, parent->children().size());
-
- // w11 is now owned by w1.
- w1->AddTransientWindow(w11);
- // w21 is now owned by w2.
- w2->AddTransientWindow(w21);
- // w22 is now owned by w2.
- w2->AddTransientWindow(w22);
- // w211 is now owned by w21.
- w21->AddTransientWindow(w211);
- // w212 is now owned by w21.
- w21->AddTransientWindow(w212);
- // w213 is now owned by w21.
- w21->AddTransientWindow(w213);
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
- // This also tests that the order in children_ array rather than in
- // transient_children_ array is used when reinserting transient children.
- // If transient_children_ array was used '22' would be following '21'.
- parent->StackChildAtBottom(w2.get());
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAtBottom(w1.get());
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- w21->Reorder(w1.get(), mojom::OrderDirection::BELOW);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- w11->Reorder(w2.get(), mojom::OrderDirection::BELOW);
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- w22->Reorder(w21, mojom::OrderDirection::BELOW);
- EXPECT_EQ(w213, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
-
- w21->Reorder(w11, mojom::OrderDirection::BELOW);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
-
- w213->Reorder(w211, mojom::OrderDirection::BELOW);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- // No change when stacking a transient parent below its transient child.
- w21->Reorder(w211, mojom::OrderDirection::BELOW);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- w1->Reorder(w2.get(), mojom::OrderDirection::BELOW);
- EXPECT_EQ(w212, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
-
- w213->Reorder(w11, mojom::OrderDirection::BELOW);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-}
-
-// Tests that transient windows are stacked properly when created.
-TEST_F(TransientWindowsTest, StackUponCreation) {
- TestServerWindowDelegate delegate;
- std::unique_ptr<ServerWindow> parent(
- CreateTestWindow(&delegate, WindowId(), nullptr));
- std::unique_ptr<ServerWindow> window0(
- CreateTestWindow(&delegate, WindowId(0, 1), parent.get()));
- std::unique_ptr<ServerWindow> window1(
- CreateTestWindow(&delegate, WindowId(0, 2), parent.get()));
-
- ServerWindow* window2 =
- CreateTestWindow(&delegate, WindowId(0, 3), parent.get());
- window0->AddTransientWindow(window2);
- EXPECT_EQ("1 3 2", ChildWindowIDsAsString(parent.get()));
-}
-
-// Tests that windows are restacked properly after a call to
-// AddTransientWindow() or RemoveTransientWindow().
-TEST_F(TransientWindowsTest, RestackUponAddOrRemoveTransientWindow) {
- TestServerWindowDelegate delegate;
- std::unique_ptr<ServerWindow> parent(
- CreateTestWindow(&delegate, WindowId(), nullptr));
- std::unique_ptr<ServerWindow> windows[4];
- for (int i = 0; i < 4; i++)
- windows[i].reset(CreateTestWindow(&delegate, WindowId(0, i), parent.get()));
-
- EXPECT_EQ("0 1 2 3", ChildWindowIDsAsString(parent.get()));
-
- windows[0]->AddTransientWindow(windows[2].get());
- EXPECT_EQ("0 2 1 3", ChildWindowIDsAsString(parent.get()));
-
- windows[0]->AddTransientWindow(windows[3].get());
- EXPECT_EQ("0 2 3 1", ChildWindowIDsAsString(parent.get()));
-
- windows[0]->RemoveTransientWindow(windows[2].get());
- EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(parent.get()));
-
- windows[0]->RemoveTransientWindow(windows[3].get());
- EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(parent.get()));
-}
-
-// Verifies TransientWindowObserver is notified appropriately.
-TEST_F(TransientWindowsTest, TransientWindowObserverNotified) {
- TestServerWindowDelegate delegate;
- std::unique_ptr<ServerWindow> parent(
- CreateTestWindow(&delegate, WindowId(), nullptr));
- std::unique_ptr<ServerWindow> w1(
- CreateTestWindow(&delegate, WindowId(0, 1), parent.get()));
-
- TestTransientWindowObserver test_observer;
- parent->AddObserver(&test_observer);
-
- parent->AddTransientWindow(w1.get());
- EXPECT_EQ(1, test_observer.add_count());
- EXPECT_EQ(0, test_observer.remove_count());
-
- parent->RemoveTransientWindow(w1.get());
- EXPECT_EQ(1, test_observer.add_count());
- EXPECT_EQ(1, test_observer.remove_count());
-
- parent->RemoveObserver(&test_observer);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/user_activity_monitor.cc b/chromium/components/mus/ws/user_activity_monitor.cc
deleted file mode 100644
index 3cd66419a27..00000000000
--- a/chromium/components/mus/ws/user_activity_monitor.cc
+++ /dev/null
@@ -1,134 +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 "components/mus/ws/user_activity_monitor.h"
-
-#include "base/bind.h"
-#include "base/time/default_tick_clock.h"
-
-namespace mus {
-namespace ws {
-
-UserActivityMonitor::UserActivityMonitor(std::unique_ptr<base::TickClock> clock)
- : now_clock_(std::move(clock)) {
- if (!now_clock_)
- now_clock_ = base::WrapUnique(new base::DefaultTickClock);
- last_activity_ = now_clock_->NowTicks();
-}
-
-UserActivityMonitor::~UserActivityMonitor() {}
-
-void UserActivityMonitor::OnUserActivity() {
- base::TimeTicks now = now_clock_->NowTicks();
- for (auto& pair : activity_observers_) {
- ActivityObserverInfo* info = &(pair.first);
- if (info->last_activity_notification.is_null() ||
- (now - info->last_activity_notification) > info->delay) {
- pair.second->OnUserActivity();
- info->last_activity_notification = now;
- }
- }
-
- // Wake up all the 'idle' observers.
- for (auto& pair : idle_observers_) {
- IdleObserverInfo* info = &(pair.first);
- if (info->idle_state == mojom::UserIdleObserver::IdleState::ACTIVE)
- continue;
- info->last_idle_state_notification = now;
- info->idle_state = mojom::UserIdleObserver::IdleState::ACTIVE;
- pair.second->OnUserIdleStateChanged(info->idle_state);
- }
-
- last_activity_ = now;
-
- // Start the timer if there are some idle observers.
- if (idle_timer_.IsRunning())
- idle_timer_.Reset();
-}
-
-void UserActivityMonitor::Add(mojom::UserActivityMonitorRequest request) {
- bindings_.AddBinding(this, std::move(request));
-}
-
-void UserActivityMonitor::AddUserActivityObserver(
- uint32_t delay_between_notify_secs,
- mojom::UserActivityObserverPtr observer) {
- ActivityObserverInfo info;
- info.delay = base::TimeDelta::FromSeconds(delay_between_notify_secs);
- observer.set_connection_error_handler(
- base::Bind(&UserActivityMonitor::OnActivityObserverDisconnected,
- base::Unretained(this), observer.get()));
- activity_observers_.push_back(std::make_pair(info, std::move(observer)));
-}
-
-void UserActivityMonitor::AddUserIdleObserver(
- uint32_t idleness_in_minutes,
- mojom::UserIdleObserverPtr observer) {
- IdleObserverInfo info;
- info.idle_duration = base::TimeDelta::FromMinutes(idleness_in_minutes);
- base::TimeTicks now = now_clock_->NowTicks();
- DCHECK(!last_activity_.is_null());
- bool user_is_active = (now - last_activity_ < info.idle_duration);
- info.idle_state = user_is_active ? mojom::UserIdleObserver::IdleState::ACTIVE
- : mojom::UserIdleObserver::IdleState::IDLE;
- info.last_idle_state_notification = now;
- observer->OnUserIdleStateChanged(info.idle_state);
- observer.set_connection_error_handler(
- base::Bind(&UserActivityMonitor::OnIdleObserverDisconnected,
- base::Unretained(this), observer.get()));
- idle_observers_.push_back(std::make_pair(info, std::move(observer)));
- if (user_is_active)
- ActivateIdleTimer();
-}
-
-void UserActivityMonitor::ActivateIdleTimer() {
- if (idle_timer_.IsRunning())
- return;
- idle_timer_.Start(FROM_HERE, base::TimeDelta::FromMinutes(1), this,
- &UserActivityMonitor::OnMinuteTimer);
-}
-
-void UserActivityMonitor::OnMinuteTimer() {
- base::TimeTicks now = now_clock_->NowTicks();
- bool active_observer = false;
- for (auto& pair : idle_observers_) {
- IdleObserverInfo* info = &(pair.first);
- if (info->idle_state == mojom::UserIdleObserver::IdleState::IDLE)
- continue;
- if (now - info->last_idle_state_notification < info->idle_duration) {
- active_observer = true;
- continue;
- }
- info->last_idle_state_notification = now;
- info->idle_state = mojom::UserIdleObserver::IdleState::IDLE;
- pair.second->OnUserIdleStateChanged(info->idle_state);
- }
- // All observers are already notified of IDLE. No point running the timer
- // anymore.
- if (!active_observer)
- idle_timer_.Stop();
-}
-
-void UserActivityMonitor::OnActivityObserverDisconnected(
- mojom::UserActivityObserver* observer) {
- activity_observers_.erase(std::remove_if(
- activity_observers_.begin(), activity_observers_.end(),
- [observer](const std::pair<ActivityObserverInfo,
- mojom::UserActivityObserverPtr>& pair) {
- return pair.second.get() == observer;
- }));
-}
-
-void UserActivityMonitor::OnIdleObserverDisconnected(
- mojom::UserIdleObserver* observer) {
- idle_observers_.erase(std::remove_if(
- idle_observers_.begin(), idle_observers_.end(),
- [observer](
- const std::pair<IdleObserverInfo, mojom::UserIdleObserverPtr>& pair) {
- return pair.second.get() == observer;
- }));
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/user_activity_monitor.h b/chromium/components/mus/ws/user_activity_monitor.h
deleted file mode 100644
index f490a6dfdfb..00000000000
--- a/chromium/components/mus/ws/user_activity_monitor.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_USER_ACTIVITY_MONITOR_H_
-#define COMPONENTS_MUS_WS_USER_ACTIVITY_MONITOR_H_
-
-#include "base/time/tick_clock.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "components/mus/public/interfaces/user_activity_monitor.mojom.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-
-namespace mus {
-namespace ws {
-
-namespace test {
-class UserActivityMonitorTestApi;
-}
-
-class UserActivityMonitor : public mojom::UserActivityMonitor {
- public:
- // |now_clock| is used to get the timestamp. If |now_clock| is nullptr, then
- // DefaultTickClock is used.
- explicit UserActivityMonitor(std::unique_ptr<base::TickClock> now_clock);
- ~UserActivityMonitor() override;
-
- // Should be called whenever some input event is received from the user.
- void OnUserActivity();
-
- // Provides an implementation for the remote request.
- void Add(mojom::UserActivityMonitorRequest request);
-
- // mojom::UserActivityMonitor:
- void AddUserActivityObserver(
- uint32_t delay_between_notify_secs,
- mojom::UserActivityObserverPtr observer) override;
- void AddUserIdleObserver(uint32_t idleness_in_minutes,
- mojom::UserIdleObserverPtr observer) override;
-
- private:
- friend class test::UserActivityMonitorTestApi;
-
- // Makes sure the idle timer is running.
- void ActivateIdleTimer();
-
- // Called every minute when |idle_timer_| is active.
- void OnMinuteTimer();
-
- void OnActivityObserverDisconnected(mojom::UserActivityObserver* observer);
- void OnIdleObserverDisconnected(mojom::UserIdleObserver* observer);
-
- mojo::BindingSet<mojom::UserActivityMonitor> bindings_;
- std::unique_ptr<base::TickClock> now_clock_;
-
- struct ActivityObserverInfo {
- base::TimeTicks last_activity_notification;
- base::TimeDelta delay;
- };
- std::vector<std::pair<ActivityObserverInfo, mojom::UserActivityObserverPtr>>
- activity_observers_;
-
- struct IdleObserverInfo {
- base::TimeTicks last_idle_state_notification;
- base::TimeDelta idle_duration;
- mojom::UserIdleObserver::IdleState idle_state;
- };
- std::vector<std::pair<IdleObserverInfo, mojom::UserIdleObserverPtr>>
- idle_observers_;
- // Timer used to determine user's idleness. The timer is run only when at
- // least one of the idle-observers are notified ACTIVE.
- base::RepeatingTimer idle_timer_;
- base::TimeTicks last_activity_;
-
- DISALLOW_COPY_AND_ASSIGN(UserActivityMonitor);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_USER_ACTIVITY_MONITOR_H_
diff --git a/chromium/components/mus/ws/user_activity_monitor_unittest.cc b/chromium/components/mus/ws/user_activity_monitor_unittest.cc
deleted file mode 100644
index 6c26ead8608..00000000000
--- a/chromium/components/mus/ws/user_activity_monitor_unittest.cc
+++ /dev/null
@@ -1,218 +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 "components/mus/ws/user_activity_monitor.h"
-
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "components/mus/ws/test_utils.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using mus::mojom::UserIdleObserver;
-
-namespace mus {
-namespace ws {
-namespace test {
-
-class TestUserActivityObserver : public mojom::UserActivityObserver {
- public:
- TestUserActivityObserver() : binding_(this) {}
- ~TestUserActivityObserver() override {}
-
- mojom::UserActivityObserverPtr GetPtr() {
- return binding_.CreateInterfacePtrAndBind();
- }
-
- bool GetAndResetReceivedUserActivity() {
- bool val = received_user_activity_;
- received_user_activity_ = false;
- return val;
- }
-
- private:
- // mojom::UserActivityObserver:
- void OnUserActivity() override { received_user_activity_ = true; }
-
- mojo::Binding<mojom::UserActivityObserver> binding_;
- bool received_user_activity_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(TestUserActivityObserver);
-};
-
-class TestUserIdleObserver : public mojom::UserIdleObserver {
- public:
- TestUserIdleObserver() : binding_(this) {}
- ~TestUserIdleObserver() override {}
-
- mojom::UserIdleObserverPtr GetPtr() {
- return binding_.CreateInterfacePtrAndBind();
- }
-
- bool GetAndResetIdleState(UserIdleObserver::IdleState* state) {
- if (!received_idle_state_)
- return false;
- received_idle_state_ = false;
- *state = idle_state_;
- return true;
- }
-
- private:
- // mojom::UserIdleObserver:
- void OnUserIdleStateChanged(UserIdleObserver::IdleState new_state) override {
- received_idle_state_ = true;
- idle_state_ = new_state;
- }
-
- mojo::Binding<mojom::UserIdleObserver> binding_;
- bool received_idle_state_ = false;
- UserIdleObserver::IdleState idle_state_ = UserIdleObserver::IdleState::ACTIVE;
-
- DISALLOW_COPY_AND_ASSIGN(TestUserIdleObserver);
-};
-
-class UserActivityMonitorTest : public testing::Test {
- public:
- UserActivityMonitorTest() {}
- ~UserActivityMonitorTest() override {}
-
- UserActivityMonitor* monitor() { return monitor_.get(); }
-
- void FastForwardBy(base::TimeDelta delta) {
- task_runner_->FastForwardBy(delta);
- }
- void RunUntilIdle() { task_runner_->RunUntilIdle(); }
-
- private:
- // testing::Test:
- void SetUp() override {
- task_runner_ = make_scoped_refptr(new base::TestMockTimeTaskRunner(
- base::Time::Now(), base::TimeTicks::Now()));
- message_loop_.SetTaskRunner(task_runner_);
- monitor_.reset(new UserActivityMonitor(task_runner_->GetMockTickClock()));
- }
-
- base::MessageLoop message_loop_;
- scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
- std::unique_ptr<UserActivityMonitor> monitor_;
-
- DISALLOW_COPY_AND_ASSIGN(UserActivityMonitorTest);
-};
-
-TEST_F(UserActivityMonitorTest, UserActivityObserver) {
- TestUserActivityObserver first_observer, second_observer;
- monitor()->AddUserActivityObserver(3, first_observer.GetPtr());
- monitor()->AddUserActivityObserver(4, second_observer.GetPtr());
-
- // The first activity should notify both observers.
- monitor()->OnUserActivity();
- RunUntilIdle();
- EXPECT_TRUE(first_observer.GetAndResetReceivedUserActivity());
- EXPECT_TRUE(second_observer.GetAndResetReceivedUserActivity());
-
- // The next activity after just one second should not notify either observer.
- FastForwardBy(base::TimeDelta::FromSeconds(1));
- monitor()->OnUserActivity();
- RunUntilIdle();
- EXPECT_FALSE(first_observer.GetAndResetReceivedUserActivity());
- EXPECT_FALSE(second_observer.GetAndResetReceivedUserActivity());
-
- FastForwardBy(base::TimeDelta::FromMilliseconds(2001));
- monitor()->OnUserActivity();
- RunUntilIdle();
- EXPECT_TRUE(first_observer.GetAndResetReceivedUserActivity());
- EXPECT_FALSE(second_observer.GetAndResetReceivedUserActivity());
-
- FastForwardBy(base::TimeDelta::FromSeconds(1));
- monitor()->OnUserActivity();
- RunUntilIdle();
- EXPECT_FALSE(first_observer.GetAndResetReceivedUserActivity());
- EXPECT_TRUE(second_observer.GetAndResetReceivedUserActivity());
-}
-
-// Tests that idleness observers receive the correct notification upon
-// connection.
-TEST_F(UserActivityMonitorTest, UserIdleObserverConnectNotification) {
- UserIdleObserver::IdleState idle_state;
-
- // If an observer is added without any user activity, then it still receives
- // an ACTIVE notification immediately.
- TestUserIdleObserver first_observer;
- monitor()->AddUserIdleObserver(1, first_observer.GetPtr());
- RunUntilIdle();
- EXPECT_TRUE(first_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::ACTIVE, idle_state);
-
- // If an observer is added without any user activity and the system has been
- // idle, then the observer receives an IDLE notification immediately.
- FastForwardBy(base::TimeDelta::FromMinutes(5));
- TestUserIdleObserver second_observer;
- monitor()->AddUserIdleObserver(4, second_observer.GetPtr());
- RunUntilIdle();
- EXPECT_TRUE(second_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::IDLE, idle_state);
- EXPECT_TRUE(first_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::IDLE, idle_state);
-
- // If an observer is added after some user activity, then it receives an
- // immediate ACTIVE notification.
- monitor()->OnUserActivity();
- TestUserIdleObserver third_observer;
- monitor()->AddUserIdleObserver(1, third_observer.GetPtr());
- RunUntilIdle();
- EXPECT_TRUE(third_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::ACTIVE, idle_state);
- EXPECT_TRUE(second_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::ACTIVE, idle_state);
- EXPECT_TRUE(first_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::ACTIVE, idle_state);
-
- FastForwardBy(base::TimeDelta::FromMinutes(10));
- TestUserIdleObserver fourth_observer;
- monitor()->AddUserIdleObserver(1, fourth_observer.GetPtr());
- RunUntilIdle();
- EXPECT_TRUE(fourth_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::IDLE, idle_state);
- EXPECT_TRUE(third_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::IDLE, idle_state);
- EXPECT_TRUE(second_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::IDLE, idle_state);
- EXPECT_TRUE(first_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::IDLE, idle_state);
-
- // All observers are idle. These should not receive any IDLE notifications as
- // more time passes by.
- FastForwardBy(base::TimeDelta::FromMinutes(100));
- RunUntilIdle();
- EXPECT_FALSE(first_observer.GetAndResetIdleState(&idle_state));
- EXPECT_FALSE(second_observer.GetAndResetIdleState(&idle_state));
- EXPECT_FALSE(third_observer.GetAndResetIdleState(&idle_state));
- EXPECT_FALSE(fourth_observer.GetAndResetIdleState(&idle_state));
-
- // Some activity would notify ACTIVE to all observers.
- monitor()->OnUserActivity();
- RunUntilIdle();
- EXPECT_TRUE(fourth_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::ACTIVE, idle_state);
- EXPECT_TRUE(third_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::ACTIVE, idle_state);
- EXPECT_TRUE(second_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::ACTIVE, idle_state);
- EXPECT_TRUE(first_observer.GetAndResetIdleState(&idle_state));
- EXPECT_EQ(UserIdleObserver::IdleState::ACTIVE, idle_state);
-
- // Yet more activity should not send any notifications.
- monitor()->OnUserActivity();
- RunUntilIdle();
- EXPECT_FALSE(first_observer.GetAndResetIdleState(&idle_state));
- EXPECT_FALSE(second_observer.GetAndResetIdleState(&idle_state));
- EXPECT_FALSE(third_observer.GetAndResetIdleState(&idle_state));
- EXPECT_FALSE(fourth_observer.GetAndResetIdleState(&idle_state));
-}
-
-} // namespace test
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/user_display_manager.cc b/chromium/components/mus/ws/user_display_manager.cc
deleted file mode 100644
index 92aeac675fc..00000000000
--- a/chromium/components/mus/ws/user_display_manager.cc
+++ /dev/null
@@ -1,151 +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 "components/mus/ws/user_display_manager.h"
-
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/display_manager_delegate.h"
-
-namespace mus {
-namespace ws {
-
-UserDisplayManager::UserDisplayManager(ws::DisplayManager* display_manager,
- DisplayManagerDelegate* delegate,
- const UserId& user_id)
- : display_manager_(display_manager),
- delegate_(delegate),
- user_id_(user_id),
- got_valid_frame_decorations_(
- delegate->GetFrameDecorationsForUser(user_id, nullptr)),
- current_cursor_location_(0) {}
-
-UserDisplayManager::~UserDisplayManager() {}
-
-void UserDisplayManager::OnFrameDecorationValuesChanged() {
- if (!got_valid_frame_decorations_) {
- got_valid_frame_decorations_ = true;
- display_manager_observers_.ForAllPtrs([this](
- mojom::DisplayManagerObserver* observer) { CallOnDisplays(observer); });
- if (test_observer_)
- CallOnDisplays(test_observer_);
- return;
- }
-
- mojo::Array<mojom::DisplayPtr> displays = GetAllDisplays();
- display_manager_observers_.ForAllPtrs(
- [this, &displays](mojom::DisplayManagerObserver* observer) {
- observer->OnDisplaysChanged(displays.Clone());
- });
- if (test_observer_)
- test_observer_->OnDisplaysChanged(displays.Clone());
-}
-
-void UserDisplayManager::AddDisplayManagerBinding(
- mojo::InterfaceRequest<mojom::DisplayManager> request) {
- display_manager_bindings_.AddBinding(this, std::move(request));
-}
-
-void UserDisplayManager::OnWillDestroyDisplay(Display* display) {
- if (!got_valid_frame_decorations_)
- return;
-
- display_manager_observers_.ForAllPtrs(
- [this, &display](mojom::DisplayManagerObserver* observer) {
- observer->OnDisplayRemoved(display->id());
- });
- if (test_observer_)
- test_observer_->OnDisplayRemoved(display->id());
-}
-
-void UserDisplayManager::OnMouseCursorLocationChanged(const gfx::Point& point) {
- current_cursor_location_ =
- static_cast<base::subtle::Atomic32>(
- (point.x() & 0xFFFF) << 16 | (point.y() & 0xFFFF));
- if (cursor_location_memory()) {
- base::subtle::NoBarrier_Store(cursor_location_memory(),
- current_cursor_location_);
- }
-}
-
-void UserDisplayManager::OnDisplayUpdate(Display* display) {
- if (!got_valid_frame_decorations_)
- return;
-
- mojo::Array<mojom::DisplayPtr> displays(1);
- displays[0] = display->ToMojomDisplay();
- delegate_->GetFrameDecorationsForUser(
- user_id_, &(displays[0]->frame_decoration_values));
- display_manager_observers_.ForAllPtrs(
- [this, &displays](mojom::DisplayManagerObserver* observer) {
- observer->OnDisplaysChanged(displays.Clone());
- });
- if (test_observer_)
- test_observer_->OnDisplaysChanged(displays.Clone());
-}
-
-mojo::ScopedSharedBufferHandle UserDisplayManager::GetCursorLocationMemory() {
- if (!cursor_location_handle_.is_valid()) {
- // Create our shared memory segment to share the cursor state with our
- // window clients.
- cursor_location_handle_ =
- mojo::SharedBufferHandle::Create(sizeof(base::subtle::Atomic32));
-
- if (!cursor_location_handle_.is_valid())
- return mojo::ScopedSharedBufferHandle();
-
- cursor_location_mapping_ =
- cursor_location_handle_->Map(sizeof(base::subtle::Atomic32));
- if (!cursor_location_mapping_)
- return mojo::ScopedSharedBufferHandle();
- base::subtle::NoBarrier_Store(cursor_location_memory(),
- current_cursor_location_);
- }
-
- return cursor_location_handle_->Clone(
- mojo::SharedBufferHandle::AccessMode::READ_ONLY);
-}
-
-
-void UserDisplayManager::OnObserverAdded(
- mojom::DisplayManagerObserver* observer) {
- // Many clients key off the frame decorations to size widgets. Wait for frame
- // decorations before notifying so that we don't have to worry about clients
- // resizing appropriately.
- if (!got_valid_frame_decorations_)
- return;
-
- CallOnDisplays(observer);
-}
-
-mojo::Array<mojom::DisplayPtr> UserDisplayManager::GetAllDisplays() {
- const std::set<Display*>& displays = display_manager_->displays();
- mojo::Array<mojom::DisplayPtr> display_ptrs(displays.size());
- {
- size_t i = 0;
- // TODO(sky): need ordering!
- for (Display* display : displays) {
- display_ptrs[i] = display->ToMojomDisplay();
- delegate_->GetFrameDecorationsForUser(
- user_id_, &(display_ptrs[i]->frame_decoration_values));
- ++i;
- }
- }
- return display_ptrs;
-}
-
-void UserDisplayManager::CallOnDisplays(
- mojom::DisplayManagerObserver* observer) {
- observer->OnDisplays(GetAllDisplays());
-}
-
-void UserDisplayManager::AddObserver(
- mojom::DisplayManagerObserverPtr observer) {
- mojom::DisplayManagerObserver* observer_impl = observer.get();
- display_manager_observers_.AddPtr(std::move(observer));
- OnObserverAdded(observer_impl);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/user_display_manager.h b/chromium/components/mus/ws/user_display_manager.h
deleted file mode 100644
index 1bfcdf81d8c..00000000000
--- a/chromium/components/mus/ws/user_display_manager.h
+++ /dev/null
@@ -1,118 +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 COMPONENTS_MUS_WS_USER_DISPLAY_MANAGER_H_
-#define COMPONENTS_MUS_WS_USER_DISPLAY_MANAGER_H_
-
-#include <set>
-
-#include "base/atomicops.h"
-#include "base/macros.h"
-#include "components/mus/public/interfaces/display.mojom.h"
-#include "components/mus/ws/user_id.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace mus {
-namespace ws {
-
-class Display;
-class DisplayManager;
-class DisplayManagerDelegate;
-
-namespace test {
-class UserDisplayManagerTestApi;
-}
-
-// Provides per user display state.
-class UserDisplayManager : public mojom::DisplayManager {
- public:
- UserDisplayManager(ws::DisplayManager* display_manager,
- DisplayManagerDelegate* delegate,
- const UserId& user_id);
- ~UserDisplayManager() override;
-
- // Called when the frame decorations for this user change.
- void OnFrameDecorationValuesChanged();
-
- void AddDisplayManagerBinding(
- mojo::InterfaceRequest<mojom::DisplayManager> request);
-
- // Called by Display prior to |display| being removed and destroyed.
- void OnWillDestroyDisplay(Display* display);
-
- // Called from WindowManagerState when its EventDispatcher receives a mouse
- // event.
- void OnMouseCursorLocationChanged(const gfx::Point& point);
-
- // Called when something about the display (e.g. pixel-ratio, size) changes.
- void OnDisplayUpdate(Display* display);
-
- // Returns a read-only handle to the shared memory which contains the global
- // mouse cursor position. Each call returns a new handle.
- mojo::ScopedSharedBufferHandle GetCursorLocationMemory();
-
- private:
- friend class test::UserDisplayManagerTestApi;
-
- // Called when a new observer is added. If frame decorations are available
- // notifies the observer immediately.
- void OnObserverAdded(mojom::DisplayManagerObserver* observer);
-
- mojo::Array<mojom::DisplayPtr> GetAllDisplays();
-
- // Calls OnDisplays() on |observer|.
- void CallOnDisplays(mojom::DisplayManagerObserver* observer);
-
- // Overriden from mojom::DisplayManager:
- void AddObserver(mojom::DisplayManagerObserverPtr observer) override;
-
- base::subtle::Atomic32* cursor_location_memory() {
- return reinterpret_cast<base::subtle::Atomic32*>(
- cursor_location_mapping_.get());
- }
-
- ws::DisplayManager* display_manager_;
-
- DisplayManagerDelegate* delegate_;
-
- const UserId user_id_;
-
- // Set to true the first time at least one Display has valid frame values.
- bool got_valid_frame_decorations_;
-
- mojo::BindingSet<mojom::DisplayManager> display_manager_bindings_;
-
- // WARNING: only use these once |got_valid_frame_decorations_| is true.
- mojo::InterfacePtrSet<mojom::DisplayManagerObserver>
- display_manager_observers_;
-
- // Observer used for tests.
- mojom::DisplayManagerObserver* test_observer_ = nullptr;
-
- // The current location of the cursor. This is always kept up to date so we
- // can atomically write this to |cursor_location_memory()| once it is created.
- base::subtle::Atomic32 current_cursor_location_;
-
- // A handle to a shared memory buffer that is one 64 bit integer long. We
- // share this with any client as the same user. This buffer is lazily
- // created on the first access.
- mojo::ScopedSharedBufferHandle cursor_location_handle_;
-
- // The one int32 in |cursor_location_handle_|. When we write to this
- // location, we must always write to it atomically. (On the other side of the
- // mojo connection, this data must be read atomically.)
- mojo::ScopedSharedBufferMapping cursor_location_mapping_;
-
- DISALLOW_COPY_AND_ASSIGN(UserDisplayManager);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_USER_DISPLAY_MANAGER_H_
diff --git a/chromium/components/mus/ws/user_display_manager_unittest.cc b/chromium/components/mus/ws/user_display_manager_unittest.cc
deleted file mode 100644
index 2c2506cce26..00000000000
--- a/chromium/components/mus/ws/user_display_manager_unittest.cc
+++ /dev/null
@@ -1,244 +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 <stdint.h>
-
-#include <string>
-
-#include "base/atomicops.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "components/mus/common/types.h"
-#include "components/mus/common/util.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/display_binding.h"
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/ids.h"
-#include "components/mus/ws/platform_display.h"
-#include "components/mus/ws/platform_display_factory.h"
-#include "components/mus/ws/platform_display_init_params.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/test_utils.h"
-#include "components/mus/ws/window_manager_state.h"
-#include "components/mus/ws/window_manager_window_tree_factory_set.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_server_delegate.h"
-#include "components/mus/ws/window_tree.h"
-#include "components/mus/ws/window_tree_binding.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace mus {
-namespace ws {
-namespace test {
-namespace {
-
-class TestDisplayManagerObserver : public mojom::DisplayManagerObserver {
- public:
- TestDisplayManagerObserver() {}
- ~TestDisplayManagerObserver() override {}
-
- std::string GetAndClearObserverCalls() {
- std::string result;
- std::swap(observer_calls_, result);
- return result;
- }
-
- private:
- void AddCall(const std::string& call) {
- if (!observer_calls_.empty())
- observer_calls_ += "\n";
- observer_calls_ += call;
- }
-
- std::string DisplayIdsToString(
- const mojo::Array<mojom::DisplayPtr>& displays) {
- std::string display_ids;
- for (const auto& display : displays) {
- if (!display_ids.empty())
- display_ids += " ";
- display_ids += base::Int64ToString(display->id);
- }
- return display_ids;
- }
-
- // mojom::DisplayManagerObserver:
- void OnDisplays(mojo::Array<mojom::DisplayPtr> displays) override {
- AddCall("OnDisplays " + DisplayIdsToString(displays));
- }
- void OnDisplaysChanged(mojo::Array<mojom::DisplayPtr> displays) override {
- AddCall("OnDisplaysChanged " + DisplayIdsToString(displays));
- }
- void OnDisplayRemoved(int64_t id) override {
- AddCall("OnDisplayRemoved " + base::Int64ToString(id));
- }
-
- std::string observer_calls_;
-
- DISALLOW_COPY_AND_ASSIGN(TestDisplayManagerObserver);
-};
-
-mojom::FrameDecorationValuesPtr CreateDefaultFrameDecorationValues() {
- return mojom::FrameDecorationValues::New();
-}
-
-} // namespace
-
-// -----------------------------------------------------------------------------
-
-class UserDisplayManagerTest : public testing::Test {
- public:
- UserDisplayManagerTest()
- : cursor_id_(0), platform_display_factory_(&cursor_id_) {}
- ~UserDisplayManagerTest() override {}
-
- protected:
- // testing::Test:
- void SetUp() override {
- PlatformDisplay::set_factory_for_testing(&platform_display_factory_);
- window_server_.reset(new WindowServer(&window_server_delegate_,
- scoped_refptr<SurfacesState>()));
- window_server_delegate_.set_window_server(window_server_.get());
- }
-
- protected:
- int32_t cursor_id_;
- TestPlatformDisplayFactory platform_display_factory_;
- TestWindowServerDelegate window_server_delegate_;
- std::unique_ptr<WindowServer> window_server_;
- base::MessageLoop message_loop_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(UserDisplayManagerTest);
-};
-
-TEST_F(UserDisplayManagerTest, OnlyNotifyWhenFrameDecorationsSet) {
- window_server_delegate_.set_num_displays_to_create(1);
-
- const UserId kUserId1 = "2";
- TestDisplayManagerObserver display_manager_observer1;
- DisplayManager* display_manager = window_server_->display_manager();
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kUserId1);
- UserDisplayManager* user_display_manager1 =
- display_manager->GetUserDisplayManager(kUserId1);
- ASSERT_TRUE(user_display_manager1);
- UserDisplayManagerTestApi(user_display_manager1)
- .SetTestObserver(&display_manager_observer1);
- // Observer should not have been notified yet.
- EXPECT_EQ(std::string(),
- display_manager_observer1.GetAndClearObserverCalls());
-
- // Set the frame decoration values, which should trigger sending immediately.
- ASSERT_EQ(1u, display_manager->displays().size());
- window_server_->window_manager_window_tree_factory_set()
- ->GetWindowManagerStateForUser(kUserId1)
- ->SetFrameDecorationValues(CreateDefaultFrameDecorationValues());
- EXPECT_EQ("OnDisplays 1",
- display_manager_observer1.GetAndClearObserverCalls());
-
- UserDisplayManagerTestApi(user_display_manager1).SetTestObserver(nullptr);
-}
-
-TEST_F(UserDisplayManagerTest, AddObserverAfterFrameDecorationsSet) {
- window_server_delegate_.set_num_displays_to_create(1);
-
- const UserId kUserId1 = "2";
- TestDisplayManagerObserver display_manager_observer1;
- DisplayManager* display_manager = window_server_->display_manager();
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kUserId1);
- UserDisplayManager* user_display_manager1 =
- display_manager->GetUserDisplayManager(kUserId1);
- ASSERT_TRUE(user_display_manager1);
- ASSERT_EQ(1u, display_manager->displays().size());
- window_server_->window_manager_window_tree_factory_set()
- ->GetWindowManagerStateForUser(kUserId1)
- ->SetFrameDecorationValues(CreateDefaultFrameDecorationValues());
-
- UserDisplayManagerTestApi(user_display_manager1)
- .SetTestObserver(&display_manager_observer1);
- EXPECT_EQ("OnDisplays 1",
- display_manager_observer1.GetAndClearObserverCalls());
-
- UserDisplayManagerTestApi(user_display_manager1).SetTestObserver(nullptr);
-}
-
-TEST_F(UserDisplayManagerTest, AddRemoveDisplay) {
- window_server_delegate_.set_num_displays_to_create(1);
-
- const UserId kUserId1 = "2";
- TestDisplayManagerObserver display_manager_observer1;
- DisplayManager* display_manager = window_server_->display_manager();
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kUserId1);
- UserDisplayManager* user_display_manager1 =
- display_manager->GetUserDisplayManager(kUserId1);
- ASSERT_TRUE(user_display_manager1);
- ASSERT_EQ(1u, display_manager->displays().size());
- window_server_->window_manager_window_tree_factory_set()
- ->GetWindowManagerStateForUser(kUserId1)
- ->SetFrameDecorationValues(CreateDefaultFrameDecorationValues());
- UserDisplayManagerTestApi(user_display_manager1)
- .SetTestObserver(&display_manager_observer1);
- EXPECT_EQ("OnDisplays 1",
- display_manager_observer1.GetAndClearObserverCalls());
-
- // Add another display.
- Display* display2 =
- new Display(window_server_.get(), PlatformDisplayInitParams());
- display2->Init(nullptr);
-
- // Observer should be notified immediately as frame decorations were set.
- EXPECT_EQ("OnDisplaysChanged 2",
- display_manager_observer1.GetAndClearObserverCalls());
-
- // Remove the display and verify observer is notified.
- display_manager->DestroyDisplay(display2);
- display2 = nullptr;
- EXPECT_EQ("OnDisplayRemoved 2",
- display_manager_observer1.GetAndClearObserverCalls());
-
- UserDisplayManagerTestApi(user_display_manager1).SetTestObserver(nullptr);
-}
-
-TEST_F(UserDisplayManagerTest, NegativeCoordinates) {
- window_server_delegate_.set_num_displays_to_create(1);
-
- const UserId kUserId1 = "2";
- TestDisplayManagerObserver display_manager_observer1;
- DisplayManager* display_manager = window_server_->display_manager();
- WindowManagerWindowTreeFactorySetTestApi(
- window_server_->window_manager_window_tree_factory_set())
- .Add(kUserId1);
- UserDisplayManager* user_display_manager1 =
- display_manager->GetUserDisplayManager(kUserId1);
- ASSERT_TRUE(user_display_manager1);
-
- user_display_manager1->OnMouseCursorLocationChanged(gfx::Point(-10, -11));
-
- base::subtle::Atomic32* cursor_location_memory = nullptr;
- mojo::ScopedSharedBufferHandle handle =
- user_display_manager1->GetCursorLocationMemory();
- mojo::ScopedSharedBufferMapping cursor_location_mapping =
- handle->Map(sizeof(base::subtle::Atomic32));
- ASSERT_TRUE(cursor_location_mapping);
- cursor_location_memory =
- reinterpret_cast<base::subtle::Atomic32*>(cursor_location_mapping.get());
-
- base::subtle::Atomic32 location =
- base::subtle::NoBarrier_Load(cursor_location_memory);
- EXPECT_EQ(gfx::Point(static_cast<int16_t>(location >> 16),
- static_cast<int16_t>(location & 0xFFFF)),
- gfx::Point(-10, -11));
-}
-
-} // namespace test
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/user_id.h b/chromium/components/mus/ws/user_id.h
deleted file mode 100644
index dbb59965487..00000000000
--- a/chromium/components/mus/ws/user_id.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_USER_ID_H_
-#define COMPONENTS_MUS_WS_USER_ID_H_
-
-#include <string>
-
-namespace mus {
-namespace ws {
-
-using UserId = std::string;
-
-inline UserId InvalidUserId() {
- return std::string();
-}
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_USER_ID_H_
diff --git a/chromium/components/mus/ws/user_id_tracker.cc b/chromium/components/mus/ws/user_id_tracker.cc
deleted file mode 100644
index 40a7dde987b..00000000000
--- a/chromium/components/mus/ws/user_id_tracker.cc
+++ /dev/null
@@ -1,68 +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 "components/mus/ws/user_id_tracker.h"
-
-#include "components/mus/ws/user_id_tracker_observer.h"
-#include "services/shell/public/interfaces/connector.mojom.h"
-
-namespace mus {
-namespace ws {
-
-UserIdTracker::UserIdTracker() : active_id_(shell::mojom::kRootUserID) {
- ids_.insert(active_id_);
-}
-
-UserIdTracker::~UserIdTracker() {
-}
-
-bool UserIdTracker::IsValidUserId(const UserId& id) const {
- return ids_.count(id) > 0;
-}
-
-void UserIdTracker::SetActiveUserId(const UserId& id) {
- DCHECK(IsValidUserId(id));
- if (id == active_id_)
- return;
-
- const UserId previously_active_id = active_id_;
- active_id_ = id;
- FOR_EACH_OBSERVER(UserIdTrackerObserver, observers_,
- OnActiveUserIdChanged(previously_active_id, id));
-}
-
-void UserIdTracker::AddUserId(const UserId& id) {
- if (IsValidUserId(id))
- return;
-
- ids_.insert(id);
- FOR_EACH_OBSERVER(UserIdTrackerObserver, observers_, OnUserIdAdded(id));
-}
-
-void UserIdTracker::RemoveUserId(const UserId& id) {
- DCHECK(IsValidUserId(id));
- ids_.erase(id);
- FOR_EACH_OBSERVER(UserIdTrackerObserver, observers_, OnUserIdRemoved(id));
-}
-
-void UserIdTracker::AddObserver(UserIdTrackerObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void UserIdTracker::RemoveObserver(UserIdTrackerObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void UserIdTracker::Bind(mojom::UserAccessManagerRequest request) {
- bindings_.AddBinding(this, std::move(request));
-}
-
-void UserIdTracker::SetActiveUser(const mojo::String& user_id) {
- if (!IsValidUserId(user_id))
- AddUserId(user_id);
- SetActiveUserId(user_id);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/user_id_tracker.h b/chromium/components/mus/ws/user_id_tracker.h
deleted file mode 100644
index c0b2ca54407..00000000000
--- a/chromium/components/mus/ws/user_id_tracker.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_USER_ID_TRACKER_H_
-#define COMPONENTS_MUS_WS_USER_ID_TRACKER_H_
-
-#include <stdint.h>
-
-#include <set>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/mus/public/interfaces/user_access_manager.mojom.h"
-#include "components/mus/ws/user_id.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-
-namespace mus {
-namespace ws {
-
-class UserIdTrackerObserver;
-
-// Tracks the set of known/valid user ids.
-class UserIdTracker : public mojom::UserAccessManager {
- public:
- UserIdTracker();
- ~UserIdTracker() override;
-
- bool IsValidUserId(const UserId& id) const;
-
- const UserId& active_id() const { return active_id_; }
-
- // Adds a new known user. Does nothing if |id| is not known.
- void SetActiveUserId(const UserId& id);
- void AddUserId(const UserId& id);
- void RemoveUserId(const UserId& id);
-
- void AddObserver(UserIdTrackerObserver* observer);
- void RemoveObserver(UserIdTrackerObserver* observer);
-
- void Bind(mojom::UserAccessManagerRequest request);
-
- private:
- using UserIdSet = std::set<UserId>;
-
- // mojom::UserAccessManager:
- void SetActiveUser(const mojo::String& user_id) override;
-
- base::ObserverList<UserIdTrackerObserver> observers_;
-
- UserIdSet ids_;
- UserId active_id_;
-
- mojo::BindingSet<mojom::UserAccessManager> bindings_;
-
- DISALLOW_COPY_AND_ASSIGN(UserIdTracker);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_USER_ID_TRACKER_H_
diff --git a/chromium/components/mus/ws/user_id_tracker_observer.h b/chromium/components/mus/ws/user_id_tracker_observer.h
deleted file mode 100644
index e770ac3de23..00000000000
--- a/chromium/components/mus/ws/user_id_tracker_observer.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_USER_ID_TRACKER_OBSERVER_H_
-#define COMPONENTS_MUS_WS_USER_ID_TRACKER_OBSERVER_H_
-
-#include <stdint.h>
-
-#include "components/mus/ws/user_id.h"
-
-namespace mus {
-namespace ws {
-
-class UserIdTrackerObserver {
- public:
- virtual void OnActiveUserIdChanged(const UserId& previously_active_id,
- const UserId& active_id) {}
- virtual void OnUserIdAdded(const UserId& id) {}
- virtual void OnUserIdRemoved(const UserId& id) {}
-
- protected:
- virtual ~UserIdTrackerObserver() {}
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_USER_ID_TRACKER_OBSERVER_H_
diff --git a/chromium/components/mus/ws/window_coordinate_conversions.cc b/chromium/components/mus/ws/window_coordinate_conversions.cc
deleted file mode 100644
index 81530fa820e..00000000000
--- a/chromium/components/mus/ws/window_coordinate_conversions.cc
+++ /dev/null
@@ -1,74 +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 "components/mus/ws/window_coordinate_conversions.h"
-
-#include "components/mus/ws/server_window.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/point_conversions.h"
-#include "ui/gfx/geometry/point_f.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/geometry/vector2d_f.h"
-
-namespace mus {
-
-namespace ws {
-
-namespace {
-
-gfx::Vector2dF CalculateOffsetToAncestor(const ServerWindow* window,
- const ServerWindow* ancestor) {
- DCHECK(ancestor->Contains(window));
- gfx::Vector2d result;
- for (const ServerWindow* v = window; v != ancestor; v = v->parent())
- result += v->bounds().OffsetFromOrigin();
- return gfx::Vector2dF(result.x(), result.y());
-}
-
-} // namespace
-
-gfx::Point ConvertPointBetweenWindows(const ServerWindow* from,
- const ServerWindow* to,
- const gfx::Point& point) {
- return gfx::ToFlooredPoint(
- ConvertPointFBetweenWindows(from, to, gfx::PointF(point.x(), point.y())));
-}
-
-gfx::PointF ConvertPointFBetweenWindows(const ServerWindow* from,
- const ServerWindow* to,
- const gfx::PointF& point) {
- DCHECK(from);
- DCHECK(to);
- if (from == to)
- return point;
-
- if (from->Contains(to)) {
- const gfx::Vector2dF offset(CalculateOffsetToAncestor(to, from));
- return point - offset;
- }
- DCHECK(to->Contains(from));
- const gfx::Vector2dF offset(CalculateOffsetToAncestor(from, to));
- return point + offset;
-}
-
-gfx::Rect ConvertRectBetweenWindows(const ServerWindow* from,
- const ServerWindow* to,
- const gfx::Rect& rect) {
- DCHECK(from);
- DCHECK(to);
- if (from == to)
- return rect;
-
- const gfx::Point top_left(
- ConvertPointBetweenWindows(from, to, rect.origin()));
- const gfx::Point bottom_right(gfx::ToCeiledPoint(ConvertPointFBetweenWindows(
- from, to, gfx::PointF(rect.right(), rect.bottom()))));
- return gfx::Rect(top_left.x(), top_left.y(), bottom_right.x() - top_left.x(),
- bottom_right.y() - top_left.y());
-}
-
-} // namespace ws
-
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_coordinate_conversions.h b/chromium/components/mus/ws/window_coordinate_conversions.h
deleted file mode 100644
index 39601590a80..00000000000
--- a/chromium/components/mus/ws/window_coordinate_conversions.h
+++ /dev/null
@@ -1,39 +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 COMPONENTS_MUS_WS_WINDOW_COORDINATE_CONVERSIONS_H_
-#define COMPONENTS_MUS_WS_WINDOW_COORDINATE_CONVERSIONS_H_
-
-namespace gfx {
-class Point;
-class PointF;
-class Rect;
-}
-
-namespace mus {
-
-namespace ws {
-
-class ServerWindow;
-
-// Converts |point| from the coordinates of |from| to the coordinates of |to|.
-// |from| and |to| must be an ancestors or descendants of each other.
-gfx::Point ConvertPointBetweenWindows(const ServerWindow* from,
- const ServerWindow* to,
- const gfx::Point& point);
-gfx::PointF ConvertPointFBetweenWindows(const ServerWindow* from,
- const ServerWindow* to,
- const gfx::PointF& point);
-
-// Converts |rect| from the coordinates of |from| to the coordinates of |to|.
-// |from| and |to| must be an ancestors or descendants of each other.
-gfx::Rect ConvertRectBetweenWindows(const ServerWindow* from,
- const ServerWindow* to,
- const gfx::Rect& rect);
-
-} // namespace ws
-
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_COORDINATE_CONVERSIONS_H_
diff --git a/chromium/components/mus/ws/window_coordinate_conversions_unittest.cc b/chromium/components/mus/ws/window_coordinate_conversions_unittest.cc
deleted file mode 100644
index 8c42c09f6c7..00000000000
--- a/chromium/components/mus/ws/window_coordinate_conversions_unittest.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/mus/ws/window_coordinate_conversions.h"
-
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_delegate.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/point_f.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace mus {
-
-namespace ws {
-
-using WindowCoordinateConversionsTest = testing::Test;
-
-TEST_F(WindowCoordinateConversionsTest, ConvertRectBetweenWindows) {
- TestServerWindowDelegate d1, d2, d3;
- ServerWindow v1(&d1, WindowId()), v2(&d2, WindowId()), v3(&d3, WindowId());
- v1.SetBounds(gfx::Rect(1, 2, 100, 100));
- v2.SetBounds(gfx::Rect(3, 4, 100, 100));
- v3.SetBounds(gfx::Rect(5, 6, 100, 100));
- v1.Add(&v2);
- v2.Add(&v3);
-
- EXPECT_EQ(gfx::Rect(2, 1, 8, 9),
- ConvertRectBetweenWindows(&v1, &v3, gfx::Rect(10, 11, 8, 9)));
-
- EXPECT_EQ(gfx::Rect(18, 21, 8, 9),
- ConvertRectBetweenWindows(&v3, &v1, gfx::Rect(10, 11, 8, 9)));
-}
-
-TEST_F(WindowCoordinateConversionsTest, ConvertPointFBetweenWindows) {
- TestServerWindowDelegate d1, d2, d3;
- ServerWindow v1(&d1, WindowId()), v2(&d2, WindowId()), v3(&d3, WindowId());
- v1.SetBounds(gfx::Rect(1, 2, 100, 100));
- v2.SetBounds(gfx::Rect(3, 4, 100, 100));
- v3.SetBounds(gfx::Rect(5, 6, 100, 100));
- v1.Add(&v2);
- v2.Add(&v3);
-
- {
- const gfx::PointF result(
- ConvertPointFBetweenWindows(&v1, &v3, gfx::PointF(10.5f, 11.9f)));
- EXPECT_FLOAT_EQ(2.5f, result.x());
- EXPECT_FLOAT_EQ(1.9f, result.y());
- }
-
- {
- const gfx::PointF result(
- ConvertPointFBetweenWindows(&v3, &v1, gfx::PointF(10.2f, 11.4f)));
- EXPECT_FLOAT_EQ(18.2f, result.x());
- EXPECT_FLOAT_EQ(21.4f, result.y());
- }
-}
-
-} // namespace ws
-
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_finder.cc b/chromium/components/mus/ws/window_finder.cc
deleted file mode 100644
index 466bd5a6a8e..00000000000
--- a/chromium/components/mus/ws/window_finder.cc
+++ /dev/null
@@ -1,68 +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 "components/mus/ws/window_finder.h"
-
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_delegate.h"
-#include "components/mus/ws/server_window_surface.h"
-#include "components/mus/ws/server_window_surface_manager.h"
-#include "components/mus/ws/window_coordinate_conversions.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/point_f.h"
-#include "ui/gfx/transform.h"
-
-namespace mus {
-namespace ws {
-
-bool IsValidWindowForEvents(ServerWindow* window) {
- ServerWindowSurfaceManager* surface_manager = window->surface_manager();
- return surface_manager &&
- surface_manager->HasSurfaceOfType(mojom::SurfaceType::DEFAULT);
-}
-
-ServerWindow* FindDeepestVisibleWindowForEvents(ServerWindow* window,
- gfx::Point* location) {
- const ServerWindow::Windows children(window->GetChildren());
- for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
- ServerWindow* child = *iter;
- if (!child->visible())
- continue;
-
- // TODO(sky): support transform.
- gfx::Point child_location(location->x() - child->bounds().x(),
- location->y() - child->bounds().y());
- gfx::Rect child_bounds(child->bounds().size());
- child_bounds.Inset(-child->extended_hit_test_region().left(),
- -child->extended_hit_test_region().top(),
- -child->extended_hit_test_region().right(),
- -child->extended_hit_test_region().bottom());
- if (!child_bounds.Contains(child_location))
- continue;
-
- if (child->hit_test_mask() &&
- !child->hit_test_mask()->Contains(child_location))
- continue;
-
- *location = child_location;
- ServerWindow* result = FindDeepestVisibleWindowForEvents(child, location);
- if (IsValidWindowForEvents(result))
- return result;
- }
- return window;
-}
-
-gfx::Transform GetTransformToWindow(ServerWindow* window) {
- gfx::Transform transform;
- ServerWindow* current = window;
- while (current->parent()) {
- transform.Translate(-current->bounds().x(), -current->bounds().y());
- current = current->parent();
- }
- return transform;
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_finder.h b/chromium/components/mus/ws/window_finder.h
deleted file mode 100644
index 2b535fcb35b..00000000000
--- a/chromium/components/mus/ws/window_finder.h
+++ /dev/null
@@ -1,33 +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 COMPONENTS_MUS_WS_WINDOW_FINDER_H_
-#define COMPONENTS_MUS_WS_WINDOW_FINDER_H_
-
-namespace gfx {
-class Point;
-class Transform;
-}
-
-namespace mus {
-namespace ws {
-
-class ServerWindow;
-
-// Find the deepest visible child of |root| that should receive an event at
-// |location|. |location| is initially in the coordinate space of
-// |root_window|, on return it is converted to the coordinates of the return
-// value.
-ServerWindow* FindDeepestVisibleWindowForEvents(
- ServerWindow* root_window,
- gfx::Point* location);
-
-// Retrieve the transform to the provided |window|'s coordinate space from the
-// root.
-gfx::Transform GetTransformToWindow(ServerWindow* window);
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_FINDER_H_
diff --git a/chromium/components/mus/ws/window_finder_unittest.cc b/chromium/components/mus/ws/window_finder_unittest.cc
deleted file mode 100644
index f910624ce43..00000000000
--- a/chromium/components/mus/ws/window_finder_unittest.cc
+++ /dev/null
@@ -1,79 +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 "components/mus/ws/window_finder.h"
-
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_surface_manager.h"
-#include "components/mus/ws/server_window_surface_manager_test_api.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "components/mus/ws/window_finder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mus {
-namespace ws {
-
-TEST(WindowFinderTest, FindDeepestVisibleWindow) {
- TestServerWindowDelegate window_delegate;
- ServerWindow root(&window_delegate, WindowId(1, 2));
- window_delegate.set_root_window(&root);
- root.SetVisible(true);
- root.SetBounds(gfx::Rect(0, 0, 100, 100));
-
- ServerWindow child1(&window_delegate, WindowId(1, 3));
- root.Add(&child1);
- EnableHitTest(&child1);
- child1.SetVisible(true);
- child1.SetBounds(gfx::Rect(10, 10, 20, 20));
-
- ServerWindow child2(&window_delegate, WindowId(1, 4));
- root.Add(&child2);
- EnableHitTest(&child2);
- child2.SetVisible(true);
- child2.SetBounds(gfx::Rect(15, 15, 20, 20));
-
- gfx::Point local_point(16, 16);
- EXPECT_EQ(&child2, FindDeepestVisibleWindowForEvents(&root, &local_point));
- EXPECT_EQ(gfx::Point(1, 1), local_point);
-
- local_point.SetPoint(13, 14);
- EXPECT_EQ(&child1, FindDeepestVisibleWindowForEvents(&root, &local_point));
- EXPECT_EQ(gfx::Point(3, 4), local_point);
-
- child2.set_extended_hit_test_region(gfx::Insets(10, 10, 10, 10));
- local_point.SetPoint(13, 14);
- EXPECT_EQ(&child2, FindDeepestVisibleWindowForEvents(&root, &local_point));
- EXPECT_EQ(gfx::Point(-2, -1), local_point);
-}
-
-TEST(WindowFinderTest, FindDeepestVisibleWindowHitTestMask) {
- TestServerWindowDelegate window_delegate;
- ServerWindow root(&window_delegate, WindowId(1, 2));
- window_delegate.set_root_window(&root);
- EnableHitTest(&root);
- root.SetVisible(true);
- root.SetBounds(gfx::Rect(0, 0, 100, 100));
-
- ServerWindow child_with_mask(&window_delegate, WindowId(1, 4));
- root.Add(&child_with_mask);
- EnableHitTest(&child_with_mask);
- child_with_mask.SetVisible(true);
- child_with_mask.SetBounds(gfx::Rect(10, 10, 20, 20));
- child_with_mask.SetHitTestMask(gfx::Rect(2, 2, 16, 16));
-
- // Test a point inside the window but outside the mask.
- gfx::Point point_outside_mask(11, 11);
- EXPECT_EQ(&root,
- FindDeepestVisibleWindowForEvents(&root, &point_outside_mask));
- EXPECT_EQ(gfx::Point(11, 11), point_outside_mask);
-
- // Test a point inside the window and inside the mask.
- gfx::Point point_inside_mask(15, 15);
- EXPECT_EQ(&child_with_mask,
- FindDeepestVisibleWindowForEvents(&root, &point_inside_mask));
- EXPECT_EQ(gfx::Point(5, 5), point_inside_mask);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_manager_access_policy.cc b/chromium/components/mus/ws/window_manager_access_policy.cc
deleted file mode 100644
index 7682c264383..00000000000
--- a/chromium/components/mus/ws/window_manager_access_policy.cc
+++ /dev/null
@@ -1,184 +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 "components/mus/ws/window_manager_access_policy.h"
-
-#include "components/mus/ws/access_policy_delegate.h"
-#include "components/mus/ws/server_window.h"
-
-namespace mus {
-namespace ws {
-
-WindowManagerAccessPolicy::WindowManagerAccessPolicy() {}
-
-WindowManagerAccessPolicy::~WindowManagerAccessPolicy() {}
-
-void WindowManagerAccessPolicy::Init(ClientSpecificId client_id,
- AccessPolicyDelegate* delegate) {
- client_id_ = client_id;
- delegate_ = delegate;
-}
-
-bool WindowManagerAccessPolicy::CanRemoveWindowFromParent(
- const ServerWindow* window) const {
- return true;
-}
-
-bool WindowManagerAccessPolicy::CanAddWindow(const ServerWindow* parent,
- const ServerWindow* child) const {
- return true;
-}
-
-bool WindowManagerAccessPolicy::CanAddTransientWindow(
- const ServerWindow* parent,
- const ServerWindow* child) const {
- return true;
-}
-
-bool WindowManagerAccessPolicy::CanRemoveTransientWindowFromParent(
- const ServerWindow* window) const {
- return true;
-}
-
-bool WindowManagerAccessPolicy::CanSetModal(
- const ServerWindow* window) const {
- return true;
-}
-
-bool WindowManagerAccessPolicy::CanReorderWindow(
- const ServerWindow* window,
- const ServerWindow* relative_window,
- mojom::OrderDirection direction) const {
- return true;
-}
-
-bool WindowManagerAccessPolicy::CanDeleteWindow(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window);
-}
-
-bool WindowManagerAccessPolicy::CanGetWindowTree(
- const ServerWindow* window) const {
- return true;
-}
-
-bool WindowManagerAccessPolicy::CanDescendIntoWindowForWindowTree(
- const ServerWindow* window) const {
- return true;
-}
-
-bool WindowManagerAccessPolicy::CanEmbed(const ServerWindow* window) const {
- return !delegate_->HasRootForAccessPolicy(window);
-}
-
-bool WindowManagerAccessPolicy::CanChangeWindowVisibility(
- const ServerWindow* window) const {
- if (WasCreatedByThisClient(window))
- return true;
- // The WindowManager can change the visibility of the WindowManager root.
- const ServerWindow* root = window->GetRoot();
- return root && window->parent() == root;
-}
-
-bool WindowManagerAccessPolicy::CanChangeWindowOpacity(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window);
-}
-
-bool WindowManagerAccessPolicy::CanSetWindowSurface(
- const ServerWindow* window,
- mus::mojom::SurfaceType surface_type) const {
- if (surface_type == mojom::SurfaceType::UNDERLAY)
- return WasCreatedByThisClient(window);
-
- if (delegate_->IsWindowRootOfAnotherTreeForAccessPolicy(window))
- return false;
- return WasCreatedByThisClient(window) ||
- (delegate_->HasRootForAccessPolicy(window));
-}
-
-bool WindowManagerAccessPolicy::CanSetWindowBounds(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window);
-}
-
-bool WindowManagerAccessPolicy::CanSetWindowProperties(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window);
-}
-
-bool WindowManagerAccessPolicy::CanSetWindowTextInputState(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window);
-}
-
-bool WindowManagerAccessPolicy::CanSetCapture(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window);
-}
-
-bool WindowManagerAccessPolicy::CanSetFocus(const ServerWindow* window) const {
- return true;
-}
-
-bool WindowManagerAccessPolicy::CanSetClientArea(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool WindowManagerAccessPolicy::CanSetHitTestMask(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool WindowManagerAccessPolicy::CanSetCursorProperties(
- const ServerWindow* window) const {
- return WasCreatedByThisClient(window) ||
- delegate_->HasRootForAccessPolicy(window);
-}
-
-bool WindowManagerAccessPolicy::ShouldNotifyOnHierarchyChange(
- const ServerWindow* window,
- const ServerWindow** new_parent,
- const ServerWindow** old_parent) const {
- // Notify if we've already told the window manager about the window, or if
- // we've
- // already told the window manager about the parent. The later handles the
- // case of a window that wasn't parented to the root getting added to the
- // root.
- return IsWindowKnown(window) || (*new_parent && IsWindowKnown(*new_parent));
-}
-
-bool WindowManagerAccessPolicy::CanSetWindowManager() const {
- return true;
-}
-
-const ServerWindow* WindowManagerAccessPolicy::GetWindowForFocusChange(
- const ServerWindow* focused) {
- return focused;
-}
-
-bool WindowManagerAccessPolicy::IsWindowKnown(
- const ServerWindow* window) const {
- return delegate_->IsWindowKnownForAccessPolicy(window);
-}
-
-bool WindowManagerAccessPolicy::IsValidIdForNewWindow(
- const ClientWindowId& id) const {
- // The WindowManager see windows created from other clients. If the WM doesn't
- // use the client id when creating windows the WM could end up with two
- // windows with the same id. Because of this the wm must use the same
- // client id for all windows it creates.
- return WindowIdFromTransportId(id.id).client_id == client_id_;
-}
-
-bool WindowManagerAccessPolicy::WasCreatedByThisClient(
- const ServerWindow* window) const {
- return window->id().client_id == client_id_;
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_manager_access_policy.h b/chromium/components/mus/ws/window_manager_access_policy.h
deleted file mode 100644
index 8b9c6edcec9..00000000000
--- a/chromium/components/mus/ws/window_manager_access_policy.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_WINDOW_MANAGER_ACCESS_POLICY_H_
-#define COMPONENTS_MUS_WS_WINDOW_MANAGER_ACCESS_POLICY_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "components/mus/ws/access_policy.h"
-
-namespace mus {
-namespace ws {
-
-class AccessPolicyDelegate;
-
-class WindowManagerAccessPolicy : public AccessPolicy {
- public:
- WindowManagerAccessPolicy();
- ~WindowManagerAccessPolicy() override;
-
- // AccessPolicy:
- void Init(ClientSpecificId client_id,
- AccessPolicyDelegate* delegate) override;
- bool CanRemoveWindowFromParent(const ServerWindow* window) const override;
- bool CanAddWindow(const ServerWindow* parent,
- const ServerWindow* child) const override;
- bool CanAddTransientWindow(const ServerWindow* parent,
- const ServerWindow* child) const override;
- bool CanRemoveTransientWindowFromParent(
- const ServerWindow* window) const override;
- bool CanSetModal(const ServerWindow* window) const override;
- bool CanReorderWindow(const ServerWindow* window,
- const ServerWindow* relative_window,
- mojom::OrderDirection direction) const override;
- bool CanDeleteWindow(const ServerWindow* window) const override;
- bool CanGetWindowTree(const ServerWindow* window) const override;
- bool CanDescendIntoWindowForWindowTree(
- const ServerWindow* window) const override;
- bool CanEmbed(const ServerWindow* window) const override;
- bool CanChangeWindowVisibility(const ServerWindow* window) const override;
- bool CanChangeWindowOpacity(const ServerWindow* window) const override;
- bool CanSetWindowSurface(const ServerWindow* window,
- mus::mojom::SurfaceType surface_type) const override;
- bool CanSetWindowBounds(const ServerWindow* window) const override;
- bool CanSetWindowProperties(const ServerWindow* window) const override;
- bool CanSetWindowTextInputState(const ServerWindow* window) const override;
- bool CanSetCapture(const ServerWindow* window) const override;
- bool CanSetFocus(const ServerWindow* window) const override;
- bool CanSetClientArea(const ServerWindow* window) const override;
- bool CanSetHitTestMask(const ServerWindow* window) const override;
- bool CanSetCursorProperties(const ServerWindow* window) const override;
- bool ShouldNotifyOnHierarchyChange(
- const ServerWindow* window,
- const ServerWindow** new_parent,
- const ServerWindow** old_parent) const override;
- const ServerWindow* GetWindowForFocusChange(
- const ServerWindow* focused) override;
- bool CanSetWindowManager() const override;
- bool IsValidIdForNewWindow(const ClientWindowId& id) const override;
-
- private:
- bool IsWindowKnown(const ServerWindow* window) const;
- bool WasCreatedByThisClient(const ServerWindow* window) const;
-
- ClientSpecificId client_id_ = 0u;
- AccessPolicyDelegate* delegate_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(WindowManagerAccessPolicy);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_MANAGER_ACCESS_POLICY_H_
diff --git a/chromium/components/mus/ws/window_manager_client_unittest.cc b/chromium/components/mus/ws/window_manager_client_unittest.cc
deleted file mode 100644
index a8049c6b69b..00000000000
--- a/chromium/components/mus/ws/window_manager_client_unittest.cc
+++ /dev/null
@@ -1,1171 +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 <stddef.h>
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "components/mus/common/util.h"
-#include "components/mus/public/cpp/lib/window_private.h"
-#include "components/mus/public/cpp/tests/window_server_test_base.h"
-#include "components/mus/public/cpp/window_observer.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-#include "components/mus/public/cpp/window_tree_client_delegate.h"
-#include "components/mus/public/cpp/window_tree_client_observer.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace mus {
-namespace ws {
-
-namespace {
-
-Id server_id(mus::Window* window) {
- return WindowPrivate(window).server_id();
-}
-
-mus::Window* GetChildWindowByServerId(WindowTreeClient* client,
- uint32_t id) {
- return client->GetWindowByServerId(id);
-}
-
-int ValidIndexOf(const Window::Children& windows, Window* window) {
- Window::Children::const_iterator it =
- std::find(windows.begin(), windows.end(), window);
- return (it != windows.end()) ? (it - windows.begin()) : -1;
-}
-
-class TestWindowManagerDelegate : public WindowManagerDelegate {
- public:
- TestWindowManagerDelegate() {}
- ~TestWindowManagerDelegate() override {}
-
- // WindowManagerDelegate:
- void SetWindowManagerClient(WindowManagerClient* client) override {}
- bool OnWmSetBounds(Window* window, gfx::Rect* bounds) override {
- return false;
- }
- bool OnWmSetProperty(
- Window* window,
- const std::string& name,
- std::unique_ptr<std::vector<uint8_t>>* new_data) override {
- return true;
- }
- Window* OnWmCreateTopLevelWindow(
- std::map<std::string, std::vector<uint8_t>>* properties) override {
- return nullptr;
- }
- void OnWmClientJankinessChanged(const std::set<Window*>& client_windows,
- bool janky) override {}
- void OnWmNewDisplay(Window* window,
- const display::Display& display) override {}
- void OnAccelerator(uint32_t id, const ui::Event& event) override {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestWindowManagerDelegate);
-};
-
-class BoundsChangeObserver : public WindowObserver {
- public:
- explicit BoundsChangeObserver(Window* window) : window_(window) {
- window_->AddObserver(this);
- }
- ~BoundsChangeObserver() override { window_->RemoveObserver(this); }
-
- private:
- // Overridden from WindowObserver:
- void OnWindowBoundsChanged(Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) override {
- DCHECK_EQ(window, window_);
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- Window* window_;
-
- DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver);
-};
-
-// Wait until the bounds of the supplied window change; returns false on
-// timeout.
-bool WaitForBoundsToChange(Window* window) {
- BoundsChangeObserver observer(window);
- return WindowServerTestBase::DoRunLoopWithTimeout();
-}
-
-class ClientAreaChangeObserver : public WindowObserver {
- public:
- explicit ClientAreaChangeObserver(Window* window) : window_(window) {
- window_->AddObserver(this);
- }
- ~ClientAreaChangeObserver() override { window_->RemoveObserver(this); }
-
- private:
- // Overridden from WindowObserver:
- void OnWindowClientAreaChanged(
- Window* window,
- const gfx::Insets& old_client_area,
- const std::vector<gfx::Rect>& old_additional_client_areas) override {
- DCHECK_EQ(window, window_);
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- Window* window_;
-
- DISALLOW_COPY_AND_ASSIGN(ClientAreaChangeObserver);
-};
-
-// Wait until the bounds of the supplied window change; returns false on
-// timeout.
-bool WaitForClientAreaToChange(Window* window) {
- ClientAreaChangeObserver observer(window);
- return WindowServerTestBase::DoRunLoopWithTimeout();
-}
-
-// Spins a run loop until the tree beginning at |root| has |tree_size| windows
-// (including |root|).
-class TreeSizeMatchesObserver : public WindowObserver {
- public:
- TreeSizeMatchesObserver(Window* tree, size_t tree_size)
- : tree_(tree), tree_size_(tree_size) {
- tree_->AddObserver(this);
- }
- ~TreeSizeMatchesObserver() override { tree_->RemoveObserver(this); }
-
- bool IsTreeCorrectSize() { return CountWindows(tree_) == tree_size_; }
-
- private:
- // Overridden from WindowObserver:
- void OnTreeChanged(const TreeChangeParams& params) override {
- if (IsTreeCorrectSize())
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- size_t CountWindows(const Window* window) const {
- size_t count = 1;
- Window::Children::const_iterator it = window->children().begin();
- for (; it != window->children().end(); ++it)
- count += CountWindows(*it);
- return count;
- }
-
- Window* tree_;
- size_t tree_size_;
-
- DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver);
-};
-
-// Wait until |window| has |tree_size| descendants; returns false on timeout.
-// The count includes |window|. For example, if you want to wait for |window| to
-// have a single child, use a |tree_size| of 2.
-bool WaitForTreeSizeToMatch(Window* window, size_t tree_size) {
- TreeSizeMatchesObserver observer(window, tree_size);
- return observer.IsTreeCorrectSize() ||
- WindowServerTestBase::DoRunLoopWithTimeout();
-}
-
-class OrderChangeObserver : public WindowObserver {
- public:
- OrderChangeObserver(Window* window) : window_(window) {
- window_->AddObserver(this);
- }
- ~OrderChangeObserver() override { window_->RemoveObserver(this); }
-
- private:
- // Overridden from WindowObserver:
- void OnWindowReordered(Window* window,
- Window* relative_window,
- mojom::OrderDirection direction) override {
- DCHECK_EQ(window, window_);
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- Window* window_;
-
- DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver);
-};
-
-// Wait until |window|'s tree size matches |tree_size|; returns false on
-// timeout.
-bool WaitForOrderChange(WindowTreeClient* client, Window* window) {
- OrderChangeObserver observer(window);
- return WindowServerTestBase::DoRunLoopWithTimeout();
-}
-
-// Tracks a window's destruction. Query is_valid() for current state.
-class WindowTracker : public WindowObserver {
- public:
- explicit WindowTracker(Window* window) : window_(window) {
- window_->AddObserver(this);
- }
- ~WindowTracker() override {
- if (window_)
- window_->RemoveObserver(this);
- }
-
- bool is_valid() const { return !!window_; }
-
- private:
- // Overridden from WindowObserver:
- void OnWindowDestroyed(Window* window) override {
- DCHECK_EQ(window, window_);
- window_ = nullptr;
- }
-
- Window* window_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTracker);
-};
-
-} // namespace
-
-// WindowServer
-// -----------------------------------------------------------------
-
-struct EmbedResult {
- EmbedResult(WindowTreeClient* client, ClientSpecificId id)
- : client(client), client_id(id) {}
- EmbedResult() : client(nullptr), client_id(0) {}
-
- WindowTreeClient* client;
-
- // The id supplied to the callback from OnEmbed(). Depending upon the
- // access policy this may or may not match the client id of
- // |client|.
- ClientSpecificId client_id;
-};
-
-Window* GetFirstRoot(WindowTreeClient* client) {
- return client->GetRoots().empty() ? nullptr : *client->GetRoots().begin();
-}
-
-// These tests model synchronization of two peer clients of the window server,
-// that are given access to some root window.
-
-class WindowServerTest : public WindowServerTestBase {
- public:
- WindowServerTest() {}
-
- Window* GetFirstWMRoot() { return GetFirstRoot(window_manager()); }
-
- Window* NewVisibleWindow(Window* parent, WindowTreeClient* client) {
- Window* window = client->NewWindow();
- window->SetVisible(true);
- parent->AddChild(window);
- return window;
- }
-
- // Embeds another version of the test app @ window. This runs a run loop until
- // a response is received, or a timeout. On success the new WindowServer is
- // returned.
- EmbedResult Embed(Window* window) {
- DCHECK(!embed_details_);
- embed_details_.reset(new EmbedDetails);
- window->Embed(ConnectAndGetWindowServerClient(),
- base::Bind(&WindowServerTest::EmbedCallbackImpl,
- base::Unretained(this)));
- embed_details_->waiting = true;
- if (!WindowServerTestBase::DoRunLoopWithTimeout())
- return EmbedResult();
- const EmbedResult result(embed_details_->client,
- embed_details_->client_id);
- embed_details_.reset();
- return result;
- }
-
- // Establishes a connection to this application and asks for a
- // WindowTreeClient.
- mus::mojom::WindowTreeClientPtr ConnectAndGetWindowServerClient() {
- mus::mojom::WindowTreeClientPtr client;
- connector()->ConnectToInterface(test_name(), &client);
- return client;
- }
-
- // WindowServerTestBase:
- void OnEmbed(Window* root) override {
- if (!embed_details_) {
- WindowServerTestBase::OnEmbed(root);
- return;
- }
-
- embed_details_->client = root->window_tree();
- if (embed_details_->callback_run)
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- private:
- // Used to track the state of a call to window->Embed().
- struct EmbedDetails {
- EmbedDetails()
- : callback_run(false),
- result(false),
- waiting(false),
- client(nullptr) {}
-
- // The callback supplied to Embed() was received.
- bool callback_run;
-
- // The boolean supplied to the Embed() callback.
- bool result;
-
- // Whether a MessageLoop is running.
- bool waiting;
-
- // Client id supplied to the Embed() callback.
- ClientSpecificId client_id;
-
- // The WindowTreeClient that resulted from the Embed(). null if |result| is
- // false.
- WindowTreeClient* client;
- };
-
- void EmbedCallbackImpl(bool result) {
- embed_details_->callback_run = true;
- embed_details_->result = result;
- if (embed_details_->waiting && (!result || embed_details_->client))
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- std::unique_ptr<EmbedDetails> embed_details_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowServerTest);
-};
-
-TEST_F(WindowServerTest, RootWindow) {
- ASSERT_NE(nullptr, window_manager());
- EXPECT_EQ(1u, window_manager()->GetRoots().size());
-}
-
-TEST_F(WindowServerTest, Embed) {
- Window* window = window_manager()->NewWindow();
- ASSERT_NE(nullptr, window);
- window->SetVisible(true);
- GetFirstWMRoot()->AddChild(window);
- WindowTreeClient* embedded = Embed(window).client;
- ASSERT_NE(nullptr, embedded);
-
- Window* window_in_embedded = GetFirstRoot(embedded);
- ASSERT_NE(nullptr, window_in_embedded);
- EXPECT_EQ(server_id(window), server_id(window_in_embedded));
- EXPECT_EQ(nullptr, window_in_embedded->parent());
- EXPECT_TRUE(window_in_embedded->children().empty());
-}
-
-// Window manager has two windows, N1 and N11. Embeds A at N1. A should not see
-// N11.
-TEST_F(WindowServerTest, EmbeddedDoesntSeeChild) {
- Window* window = window_manager()->NewWindow();
- ASSERT_NE(nullptr, window);
- window->SetVisible(true);
- GetFirstWMRoot()->AddChild(window);
- Window* nested = window_manager()->NewWindow();
- ASSERT_NE(nullptr, nested);
- nested->SetVisible(true);
- window->AddChild(nested);
-
- WindowTreeClient* embedded = Embed(window).client;
- ASSERT_NE(nullptr, embedded);
- Window* window_in_embedded = GetFirstRoot(embedded);
- EXPECT_EQ(server_id(window), server_id(window_in_embedded));
- EXPECT_EQ(nullptr, window_in_embedded->parent());
- EXPECT_TRUE(window_in_embedded->children().empty());
-}
-
-// TODO(beng): write a replacement test for the one that once existed here:
-// This test validates the following scenario:
-// - a window originating from one client
-// - a window originating from a second client
-// + the client originating the window is destroyed
-// -> the window should still exist (since the second client is live) but
-// should be disconnected from any windows.
-// http://crbug.com/396300
-//
-// TODO(beng): The new test should validate the scenario as described above
-// except that the second client still has a valid tree.
-
-// Verifies that bounds changes applied to a window hierarchy in one client
-// are reflected to another.
-TEST_F(WindowServerTest, SetBounds) {
- Window* window = window_manager()->NewWindow();
- window->SetVisible(true);
- GetFirstWMRoot()->AddChild(window);
- WindowTreeClient* embedded = Embed(window).client;
- ASSERT_NE(nullptr, embedded);
-
- Window* window_in_embedded =
- GetChildWindowByServerId(embedded, server_id(window));
- EXPECT_EQ(window->bounds(), window_in_embedded->bounds());
-
- window->SetBounds(gfx::Rect(0, 0, 100, 100));
- ASSERT_TRUE(WaitForBoundsToChange(window_in_embedded));
- EXPECT_TRUE(window->bounds() == window_in_embedded->bounds());
-}
-
-// Verifies that bounds changes applied to a window owned by a different
-// client can be refused.
-TEST_F(WindowServerTest, SetBoundsSecurity) {
- TestWindowManagerDelegate wm_delegate;
- set_window_manager_delegate(&wm_delegate);
-
- Window* window = window_manager()->NewWindow();
- window->SetVisible(true);
- GetFirstWMRoot()->AddChild(window);
- WindowTreeClient* embedded = Embed(window).client;
- ASSERT_NE(nullptr, embedded);
-
- Window* window_in_embedded =
- GetChildWindowByServerId(embedded, server_id(window));
- window->SetBounds(gfx::Rect(0, 0, 800, 600));
- ASSERT_TRUE(WaitForBoundsToChange(window_in_embedded));
-
- window_in_embedded->SetBounds(gfx::Rect(0, 0, 1024, 768));
- // Bounds change is initially accepted, but the server declines the request.
- EXPECT_FALSE(window->bounds() == window_in_embedded->bounds());
-
- // The client is notified when the requested is declined, and updates the
- // local bounds accordingly.
- ASSERT_TRUE(WaitForBoundsToChange(window_in_embedded));
- EXPECT_TRUE(window->bounds() == window_in_embedded->bounds());
- set_window_manager_delegate(nullptr);
-}
-
-// Verifies that a root window can always be destroyed.
-TEST_F(WindowServerTest, DestroySecurity) {
- Window* window = window_manager()->NewWindow();
- window->SetVisible(true);
- GetFirstWMRoot()->AddChild(window);
-
- WindowTreeClient* embedded = Embed(window).client;
- ASSERT_NE(nullptr, embedded);
-
- // The root can be destroyed, even though it was not created by the client.
- Window* embed_root = GetChildWindowByServerId(embedded, server_id(window));
- WindowTracker tracker1(window);
- WindowTracker tracker2(embed_root);
- embed_root->Destroy();
- EXPECT_FALSE(tracker2.is_valid());
- EXPECT_TRUE(tracker1.is_valid());
-
- window->Destroy();
- EXPECT_FALSE(tracker1.is_valid());
-}
-
-TEST_F(WindowServerTest, MultiRoots) {
- Window* window1 = window_manager()->NewWindow();
- window1->SetVisible(true);
- GetFirstWMRoot()->AddChild(window1);
- Window* window2 = window_manager()->NewWindow();
- window2->SetVisible(true);
- GetFirstWMRoot()->AddChild(window2);
- WindowTreeClient* embedded1 = Embed(window1).client;
- ASSERT_NE(nullptr, embedded1);
- WindowTreeClient* embedded2 = Embed(window2).client;
- ASSERT_NE(nullptr, embedded2);
- EXPECT_NE(embedded1, embedded2);
-}
-
-TEST_F(WindowServerTest, Reorder) {
- Window* window1 = window_manager()->NewWindow();
- window1->SetVisible(true);
- GetFirstWMRoot()->AddChild(window1);
-
- WindowTreeClient* embedded = Embed(window1).client;
- ASSERT_NE(nullptr, embedded);
-
- Window* window11 = embedded->NewWindow();
- window11->SetVisible(true);
- GetFirstRoot(embedded)->AddChild(window11);
- Window* window12 = embedded->NewWindow();
- window12->SetVisible(true);
- GetFirstRoot(embedded)->AddChild(window12);
- ASSERT_TRUE(WaitForTreeSizeToMatch(window1, 3u));
-
- Window* root_in_embedded = GetFirstRoot(embedded);
-
- {
- window11->MoveToFront();
- // The |embedded| tree should be updated immediately.
- EXPECT_EQ(root_in_embedded->children().front(),
- GetChildWindowByServerId(embedded, server_id(window12)));
- EXPECT_EQ(root_in_embedded->children().back(),
- GetChildWindowByServerId(embedded, server_id(window11)));
-
- // The |window_manager()| tree is still not updated.
- EXPECT_EQ(window1->children().back(),
- GetChildWindowByServerId(window_manager(), server_id(window12)));
-
- // Wait until |window_manager()| tree is updated.
- ASSERT_TRUE(WaitForOrderChange(
- window_manager(),
- GetChildWindowByServerId(window_manager(), server_id(window11))));
- EXPECT_EQ(window1->children().front(),
- GetChildWindowByServerId(window_manager(), server_id(window12)));
- EXPECT_EQ(window1->children().back(),
- GetChildWindowByServerId(window_manager(), server_id(window11)));
- }
-
- {
- window11->MoveToBack();
- // |embedded| should be updated immediately.
- EXPECT_EQ(root_in_embedded->children().front(),
- GetChildWindowByServerId(embedded, server_id(window11)));
- EXPECT_EQ(root_in_embedded->children().back(),
- GetChildWindowByServerId(embedded, server_id(window12)));
-
- // |window_manager()| is also eventually updated.
- EXPECT_EQ(window1->children().back(),
- GetChildWindowByServerId(window_manager(), server_id(window11)));
- ASSERT_TRUE(WaitForOrderChange(
- window_manager(),
- GetChildWindowByServerId(window_manager(), server_id(window11))));
- EXPECT_EQ(window1->children().front(),
- GetChildWindowByServerId(window_manager(), server_id(window11)));
- EXPECT_EQ(window1->children().back(),
- GetChildWindowByServerId(window_manager(), server_id(window12)));
- }
-}
-
-namespace {
-
-class VisibilityChangeObserver : public WindowObserver {
- public:
- explicit VisibilityChangeObserver(Window* window) : window_(window) {
- window_->AddObserver(this);
- }
- ~VisibilityChangeObserver() override { window_->RemoveObserver(this); }
-
- private:
- // Overridden from WindowObserver:
- void OnWindowVisibilityChanged(Window* window) override {
- EXPECT_EQ(window, window_);
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- Window* window_;
-
- DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver);
-};
-
-} // namespace
-
-TEST_F(WindowServerTest, Visible) {
- Window* window1 = window_manager()->NewWindow();
- window1->SetVisible(true);
- GetFirstWMRoot()->AddChild(window1);
-
- // Embed another app and verify initial state.
- WindowTreeClient* embedded = Embed(window1).client;
- ASSERT_NE(nullptr, embedded);
- ASSERT_NE(nullptr, GetFirstRoot(embedded));
- Window* embedded_root = GetFirstRoot(embedded);
- EXPECT_TRUE(embedded_root->visible());
- EXPECT_TRUE(embedded_root->IsDrawn());
-
- // Change the visible state from the first client and verify its mirrored
- // correctly to the embedded app.
- {
- VisibilityChangeObserver observer(embedded_root);
- window1->SetVisible(false);
- ASSERT_TRUE(WindowServerTestBase::DoRunLoopWithTimeout());
- }
-
- EXPECT_FALSE(window1->visible());
- EXPECT_FALSE(window1->IsDrawn());
-
- EXPECT_FALSE(embedded_root->visible());
- EXPECT_FALSE(embedded_root->IsDrawn());
-
- // Make the node visible again.
- {
- VisibilityChangeObserver observer(embedded_root);
- window1->SetVisible(true);
- ASSERT_TRUE(WindowServerTestBase::DoRunLoopWithTimeout());
- }
-
- EXPECT_TRUE(window1->visible());
- EXPECT_TRUE(window1->IsDrawn());
-
- EXPECT_TRUE(embedded_root->visible());
- EXPECT_TRUE(embedded_root->IsDrawn());
-}
-
-namespace {
-
-class DrawnChangeObserver : public WindowObserver {
- public:
- explicit DrawnChangeObserver(Window* window) : window_(window) {
- window_->AddObserver(this);
- }
- ~DrawnChangeObserver() override { window_->RemoveObserver(this); }
-
- private:
- // Overridden from WindowObserver:
- void OnWindowDrawnChanged(Window* window) override {
- EXPECT_EQ(window, window_);
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- Window* window_;
-
- DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver);
-};
-
-} // namespace
-
-TEST_F(WindowServerTest, Drawn) {
- Window* window1 = window_manager()->NewWindow();
- window1->SetVisible(true);
- GetFirstWMRoot()->AddChild(window1);
-
- // Embed another app and verify initial state.
- WindowTreeClient* embedded = Embed(window1).client;
- ASSERT_NE(nullptr, embedded);
- ASSERT_NE(nullptr, GetFirstRoot(embedded));
- Window* embedded_root = GetFirstRoot(embedded);
- EXPECT_TRUE(embedded_root->visible());
- EXPECT_TRUE(embedded_root->IsDrawn());
-
- // Change the visibility of the root, this should propagate a drawn state
- // change to |embedded|.
- {
- DrawnChangeObserver observer(embedded_root);
- GetFirstWMRoot()->SetVisible(false);
- ASSERT_TRUE(DoRunLoopWithTimeout());
- }
-
- EXPECT_TRUE(window1->visible());
- EXPECT_FALSE(window1->IsDrawn());
-
- EXPECT_TRUE(embedded_root->visible());
- EXPECT_FALSE(embedded_root->IsDrawn());
-}
-
-// TODO(beng): tests for window event dispatcher.
-// - verify that we see events for all windows.
-
-namespace {
-
-class FocusChangeObserver : public WindowObserver {
- public:
- explicit FocusChangeObserver(Window* window)
- : window_(window),
- last_gained_focus_(nullptr),
- last_lost_focus_(nullptr),
- quit_on_change_(true) {
- window_->AddObserver(this);
- }
- ~FocusChangeObserver() override { window_->RemoveObserver(this); }
-
- void set_quit_on_change(bool value) { quit_on_change_ = value; }
-
- Window* last_gained_focus() { return last_gained_focus_; }
-
- Window* last_lost_focus() { return last_lost_focus_; }
-
- private:
- // Overridden from WindowObserver.
- void OnWindowFocusChanged(Window* gained_focus, Window* lost_focus) override {
- EXPECT_TRUE(!gained_focus || gained_focus->HasFocus());
- EXPECT_FALSE(lost_focus && lost_focus->HasFocus());
- last_gained_focus_ = gained_focus;
- last_lost_focus_ = lost_focus;
- if (quit_on_change_)
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- Window* window_;
- Window* last_gained_focus_;
- Window* last_lost_focus_;
- bool quit_on_change_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver);
-};
-
-class NullFocusChangeObserver : public WindowTreeClientObserver {
- public:
- explicit NullFocusChangeObserver(WindowTreeClient* client)
- : client_(client) {
- client_->AddObserver(this);
- }
- ~NullFocusChangeObserver() override { client_->RemoveObserver(this); }
-
- private:
- // Overridden from WindowTreeClientObserver.
- void OnWindowTreeFocusChanged(Window* gained_focus,
- Window* lost_focus) override {
- if (!gained_focus)
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- WindowTreeClient* client_;
-
- DISALLOW_COPY_AND_ASSIGN(NullFocusChangeObserver);
-};
-
-bool WaitForWindowToHaveFocus(Window* window) {
- if (window->HasFocus())
- return true;
- FocusChangeObserver observer(window);
- return WindowServerTestBase::DoRunLoopWithTimeout();
-}
-
-bool WaitForNoWindowToHaveFocus(WindowTreeClient* client) {
- if (!client->GetFocusedWindow())
- return true;
- NullFocusChangeObserver observer(client);
- return WindowServerTestBase::DoRunLoopWithTimeout();
-}
-
-} // namespace
-
-TEST_F(WindowServerTest, Focus) {
- Window* window1 = window_manager()->NewWindow();
- window1->SetVisible(true);
- GetFirstWMRoot()->AddChild(window1);
-
- WindowTreeClient* embedded = Embed(window1).client;
- ASSERT_NE(nullptr, embedded);
- Window* window11 = embedded->NewWindow();
- window11->SetVisible(true);
- GetFirstRoot(embedded)->AddChild(window11);
-
- {
- // Focus the embed root in |embedded|.
- Window* embedded_root = GetFirstRoot(embedded);
- FocusChangeObserver observer(embedded_root);
- observer.set_quit_on_change(false);
- embedded_root->SetFocus();
- ASSERT_TRUE(embedded_root->HasFocus());
- ASSERT_NE(nullptr, observer.last_gained_focus());
- EXPECT_EQ(server_id(embedded_root),
- server_id(observer.last_gained_focus()));
-
- // |embedded_root| is the same as |window1|, make sure |window1| got
- // focus too.
- ASSERT_TRUE(WaitForWindowToHaveFocus(window1));
- }
-
- // Focus a child of GetFirstRoot(embedded).
- {
- FocusChangeObserver observer(window11);
- observer.set_quit_on_change(false);
- window11->SetFocus();
- ASSERT_TRUE(window11->HasFocus());
- ASSERT_NE(nullptr, observer.last_gained_focus());
- ASSERT_NE(nullptr, observer.last_lost_focus());
- EXPECT_EQ(server_id(window11), server_id(observer.last_gained_focus()));
- EXPECT_EQ(server_id(GetFirstRoot(embedded)),
- server_id(observer.last_lost_focus()));
- }
-
- {
- // Add an observer on the Window that loses focus, and make sure the
- // observer sees the right values.
- FocusChangeObserver observer(window11);
- observer.set_quit_on_change(false);
- GetFirstRoot(embedded)->SetFocus();
- ASSERT_NE(nullptr, observer.last_gained_focus());
- ASSERT_NE(nullptr, observer.last_lost_focus());
- EXPECT_EQ(server_id(window11), server_id(observer.last_lost_focus()));
- EXPECT_EQ(server_id(GetFirstRoot(embedded)),
- server_id(observer.last_gained_focus()));
- }
-}
-
-TEST_F(WindowServerTest, ClearFocus) {
- Window* window1 = window_manager()->NewWindow();
- window1->SetVisible(true);
- GetFirstWMRoot()->AddChild(window1);
-
- WindowTreeClient* embedded = Embed(window1).client;
- ASSERT_NE(nullptr, embedded);
- Window* window11 = embedded->NewWindow();
- window11->SetVisible(true);
- GetFirstRoot(embedded)->AddChild(window11);
-
- // Focus the embed root in |embedded|.
- Window* embedded_root = GetFirstRoot(embedded);
- {
- FocusChangeObserver observer(embedded_root);
- observer.set_quit_on_change(false);
- embedded_root->SetFocus();
- ASSERT_TRUE(embedded_root->HasFocus());
- ASSERT_NE(nullptr, observer.last_gained_focus());
- EXPECT_EQ(server_id(embedded_root),
- server_id(observer.last_gained_focus()));
-
- // |embedded_root| is the same as |window1|, make sure |window1| got
- // focus too.
- ASSERT_TRUE(WaitForWindowToHaveFocus(window1));
- }
-
- {
- FocusChangeObserver observer(window1);
- embedded->ClearFocus();
- ASSERT_FALSE(embedded_root->HasFocus());
- EXPECT_FALSE(embedded->GetFocusedWindow());
-
- ASSERT_TRUE(WindowServerTestBase::DoRunLoopWithTimeout());
- EXPECT_FALSE(window1->HasFocus());
- EXPECT_FALSE(window_manager()->GetFocusedWindow());
- }
-}
-
-TEST_F(WindowServerTest, FocusNonFocusableWindow) {
- Window* window = window_manager()->NewWindow();
- window->SetVisible(true);
- GetFirstWMRoot()->AddChild(window);
-
- WindowTreeClient* client = Embed(window).client;
- ASSERT_NE(nullptr, client);
- ASSERT_FALSE(client->GetRoots().empty());
- Window* client_window = *client->GetRoots().begin();
- client_window->SetCanFocus(false);
-
- client_window->SetFocus();
- ASSERT_TRUE(client_window->HasFocus());
-
- WaitForNoWindowToHaveFocus(client);
- ASSERT_FALSE(client_window->HasFocus());
-}
-
-TEST_F(WindowServerTest, Activation) {
- Window* parent = NewVisibleWindow(GetFirstWMRoot(), window_manager());
-
- // Allow the child windows to be activated. Do this before we wait, that way
- // we're guaranteed that when we request focus from a separate client the
- // requests are processed in order.
- window_manager_client()->AddActivationParent(parent);
-
- Window* child1 = NewVisibleWindow(parent, window_manager());
- Window* child2 = NewVisibleWindow(parent, window_manager());
- Window* child3 = NewVisibleWindow(parent, window_manager());
-
- child1->AddTransientWindow(child3);
-
- WindowTreeClient* embedded1 = Embed(child1).client;
- ASSERT_NE(nullptr, embedded1);
- WindowTreeClient* embedded2 = Embed(child2).client;
- ASSERT_NE(nullptr, embedded2);
-
- Window* child11 = NewVisibleWindow(GetFirstRoot(embedded1), embedded1);
- Window* child21 = NewVisibleWindow(GetFirstRoot(embedded2), embedded2);
-
- WaitForTreeSizeToMatch(parent, 6);
-
- // |child2| and |child3| are stacked about |child1|.
- EXPECT_GT(ValidIndexOf(parent->children(), child2),
- ValidIndexOf(parent->children(), child1));
- EXPECT_GT(ValidIndexOf(parent->children(), child3),
- ValidIndexOf(parent->children(), child1));
-
- // Set focus on |child11|. This should activate |child1|, and raise it over
- // |child2|. But |child3| should still be above |child1| because of
- // transiency.
- child11->SetFocus();
- ASSERT_TRUE(WaitForWindowToHaveFocus(child11));
- ASSERT_TRUE(WaitForWindowToHaveFocus(
- GetChildWindowByServerId(window_manager(), server_id(child11))));
- EXPECT_EQ(server_id(child11),
- server_id(window_manager()->GetFocusedWindow()));
- EXPECT_EQ(server_id(child11), server_id(embedded1->GetFocusedWindow()));
- EXPECT_EQ(nullptr, embedded2->GetFocusedWindow());
- EXPECT_GT(ValidIndexOf(parent->children(), child1),
- ValidIndexOf(parent->children(), child2));
- EXPECT_GT(ValidIndexOf(parent->children(), child3),
- ValidIndexOf(parent->children(), child1));
-
- // Set focus on |child21|. This should activate |child2|, and raise it over
- // |child1|.
- child21->SetFocus();
- ASSERT_TRUE(WaitForWindowToHaveFocus(child21));
- ASSERT_TRUE(WaitForWindowToHaveFocus(
- GetChildWindowByServerId(window_manager(), server_id(child21))));
- EXPECT_EQ(server_id(child21),
- server_id(window_manager()->GetFocusedWindow()));
- EXPECT_EQ(server_id(child21), server_id(embedded2->GetFocusedWindow()));
- EXPECT_TRUE(WaitForNoWindowToHaveFocus(embedded1));
- EXPECT_EQ(nullptr, embedded1->GetFocusedWindow());
- EXPECT_GT(ValidIndexOf(parent->children(), child2),
- ValidIndexOf(parent->children(), child1));
- EXPECT_GT(ValidIndexOf(parent->children(), child3),
- ValidIndexOf(parent->children(), child1));
-}
-
-TEST_F(WindowServerTest, ActivationNext) {
- Window* parent = GetFirstWMRoot();
- Window* child1 = NewVisibleWindow(parent, window_manager());
- Window* child2 = NewVisibleWindow(parent, window_manager());
- Window* child3 = NewVisibleWindow(parent, window_manager());
-
- WindowTreeClient* embedded1 = Embed(child1).client;
- ASSERT_NE(nullptr, embedded1);
- WindowTreeClient* embedded2 = Embed(child2).client;
- ASSERT_NE(nullptr, embedded2);
- WindowTreeClient* embedded3 = Embed(child3).client;
- ASSERT_NE(nullptr, embedded3);
-
- Window* child11 = NewVisibleWindow(GetFirstRoot(embedded1), embedded1);
- Window* child21 = NewVisibleWindow(GetFirstRoot(embedded2), embedded2);
- Window* child31 = NewVisibleWindow(GetFirstRoot(embedded3), embedded3);
- WaitForTreeSizeToMatch(parent, 7);
-
- Window* expecteds[] = { child3, child2, child1, child3, nullptr };
- Window* focused[] = { child31, child21, child11, child31, nullptr };
- for (size_t index = 0; expecteds[index]; ++index) {
- window_manager_client()->ActivateNextWindow();
- WaitForWindowToHaveFocus(focused[index]);
- EXPECT_TRUE(focused[index]->HasFocus());
- EXPECT_EQ(parent->children().back(), expecteds[index]);
- }
-}
-
-namespace {
-
-class DestroyedChangedObserver : public WindowObserver {
- public:
- DestroyedChangedObserver(WindowServerTestBase* test,
- Window* window,
- bool* got_destroy)
- : test_(test), window_(window), got_destroy_(got_destroy) {
- window_->AddObserver(this);
- }
- ~DestroyedChangedObserver() override {
- if (window_)
- window_->RemoveObserver(this);
- }
-
- private:
- // Overridden from WindowObserver:
- void OnWindowDestroyed(Window* window) override {
- EXPECT_EQ(window, window_);
- window_->RemoveObserver(this);
- *got_destroy_ = true;
- window_ = nullptr;
-
- // We should always get OnWindowDestroyed() before
- // OnWindowTreeClientDestroyed().
- EXPECT_FALSE(test_->window_tree_client_destroyed());
- }
-
- WindowServerTestBase* test_;
- Window* window_;
- bool* got_destroy_;
-
- DISALLOW_COPY_AND_ASSIGN(DestroyedChangedObserver);
-};
-
-} // namespace
-
-// Verifies deleting a WindowServer sends the right notifications.
-TEST_F(WindowServerTest, DeleteWindowServer) {
- Window* window = window_manager()->NewWindow();
- ASSERT_NE(nullptr, window);
- window->SetVisible(true);
- GetFirstWMRoot()->AddChild(window);
- WindowTreeClient* client = Embed(window).client;
- ASSERT_TRUE(client);
- bool got_destroy = false;
- DestroyedChangedObserver observer(this, GetFirstRoot(client),
- &got_destroy);
- delete client;
- EXPECT_TRUE(window_tree_client_destroyed());
- EXPECT_TRUE(got_destroy);
-}
-
-// Verifies two Embed()s in the same window trigger deletion of the first
-// WindowServer.
-TEST_F(WindowServerTest, DisconnectTriggersDelete) {
- Window* window = window_manager()->NewWindow();
- ASSERT_NE(nullptr, window);
- window->SetVisible(true);
- GetFirstWMRoot()->AddChild(window);
- WindowTreeClient* client = Embed(window).client;
- EXPECT_NE(client, window_manager());
- Window* embedded_window = client->NewWindow();
- // Embed again, this should trigger disconnect and deletion of client.
- bool got_destroy;
- DestroyedChangedObserver observer(this, embedded_window, &got_destroy);
- EXPECT_FALSE(window_tree_client_destroyed());
- Embed(window);
- EXPECT_TRUE(window_tree_client_destroyed());
-}
-
-class WindowRemovedFromParentObserver : public WindowObserver {
- public:
- explicit WindowRemovedFromParentObserver(Window* window)
- : window_(window), was_removed_(false) {
- window_->AddObserver(this);
- }
- ~WindowRemovedFromParentObserver() override { window_->RemoveObserver(this); }
-
- bool was_removed() const { return was_removed_; }
-
- private:
- // Overridden from WindowObserver:
- void OnTreeChanged(const TreeChangeParams& params) override {
- if (params.target == window_ && !params.new_parent)
- was_removed_ = true;
- }
-
- Window* window_;
- bool was_removed_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowRemovedFromParentObserver);
-};
-
-TEST_F(WindowServerTest, EmbedRemovesChildren) {
- Window* window1 = window_manager()->NewWindow();
- Window* window2 = window_manager()->NewWindow();
- GetFirstWMRoot()->AddChild(window1);
- window1->AddChild(window2);
-
- WindowRemovedFromParentObserver observer(window2);
- window1->Embed(ConnectAndGetWindowServerClient());
- EXPECT_TRUE(observer.was_removed());
- EXPECT_EQ(nullptr, window2->parent());
- EXPECT_TRUE(window1->children().empty());
-
- // Run the message loop so the Embed() call above completes. Without this
- // we may end up reconnecting to the test and rerunning the test, which is
- // problematic since the other services don't shut down.
- ASSERT_TRUE(DoRunLoopWithTimeout());
-}
-
-namespace {
-
-class DestroyObserver : public WindowObserver {
- public:
- DestroyObserver(WindowServerTestBase* test,
- WindowTreeClient* client,
- bool* got_destroy)
- : test_(test), got_destroy_(got_destroy) {
- GetFirstRoot(client)->AddObserver(this);
- }
- ~DestroyObserver() override {}
-
- private:
- // Overridden from WindowObserver:
- void OnWindowDestroyed(Window* window) override {
- *got_destroy_ = true;
- window->RemoveObserver(this);
-
- // We should always get OnWindowDestroyed() before
- // OnWindowManagerDestroyed().
- EXPECT_FALSE(test_->window_tree_client_destroyed());
-
- EXPECT_TRUE(WindowServerTestBase::QuitRunLoop());
- }
-
- WindowServerTestBase* test_;
- bool* got_destroy_;
-
- DISALLOW_COPY_AND_ASSIGN(DestroyObserver);
-};
-
-} // namespace
-
-// Verifies deleting a Window that is the root of another client notifies
-// observers in the right order (OnWindowDestroyed() before
-// OnWindowManagerDestroyed()).
-TEST_F(WindowServerTest, WindowServerDestroyedAfterRootObserver) {
- Window* embed_window = window_manager()->NewWindow();
- GetFirstWMRoot()->AddChild(embed_window);
-
- WindowTreeClient* embedded_client = Embed(embed_window).client;
-
- bool got_destroy = false;
- DestroyObserver observer(this, embedded_client, &got_destroy);
- // Delete the window |embedded_client| is embedded in. This is async,
- // but will eventually trigger deleting |embedded_client|.
- embed_window->Destroy();
- EXPECT_TRUE(DoRunLoopWithTimeout());
- EXPECT_TRUE(got_destroy);
-}
-
-TEST_F(WindowServerTest, ClientAreaChanged) {
- Window* embed_window = window_manager()->NewWindow();
- GetFirstWMRoot()->AddChild(embed_window);
-
- WindowTreeClient* embedded_client = Embed(embed_window).client;
-
- // Verify change from embedded makes it to parent.
- GetFirstRoot(embedded_client)->SetClientArea(gfx::Insets(1, 2, 3, 4));
- ASSERT_TRUE(WaitForClientAreaToChange(embed_window));
- EXPECT_TRUE(gfx::Insets(1, 2, 3, 4) == embed_window->client_area());
-
- // Changing bounds shouldn't effect client area.
- embed_window->SetBounds(gfx::Rect(21, 22, 23, 24));
- WaitForBoundsToChange(GetFirstRoot(embedded_client));
- EXPECT_TRUE(gfx::Rect(21, 22, 23, 24) ==
- GetFirstRoot(embedded_client)->bounds());
- EXPECT_TRUE(gfx::Insets(1, 2, 3, 4) ==
- GetFirstRoot(embedded_client)->client_area());
-}
-
-class EstablishConnectionViaFactoryDelegate : public TestWindowManagerDelegate {
- public:
- explicit EstablishConnectionViaFactoryDelegate(
- WindowTreeClient* client)
- : client_(client), run_loop_(nullptr), created_window_(nullptr) {}
- ~EstablishConnectionViaFactoryDelegate() override {}
-
- bool QuitOnCreate() {
- if (run_loop_)
- return false;
-
- created_window_ = nullptr;
- run_loop_.reset(new base::RunLoop);
- run_loop_->Run();
- run_loop_.reset();
- return created_window_ != nullptr;
- }
-
- Window* created_window() { return created_window_; }
-
- // WindowManagerDelegate:
- Window* OnWmCreateTopLevelWindow(
- std::map<std::string, std::vector<uint8_t>>* properties) override {
- created_window_ = client_->NewWindow(properties);
- (*client_->GetRoots().begin())->AddChild(created_window_);
- if (run_loop_)
- run_loop_->Quit();
- return created_window_;
- }
-
- private:
- WindowTreeClient* client_;
- std::unique_ptr<base::RunLoop> run_loop_;
- Window* created_window_;
-
- DISALLOW_COPY_AND_ASSIGN(EstablishConnectionViaFactoryDelegate);
-};
-
-TEST_F(WindowServerTest, EstablishConnectionViaFactory) {
- EstablishConnectionViaFactoryDelegate delegate(window_manager());
- set_window_manager_delegate(&delegate);
- std::unique_ptr<WindowTreeClient> second_client(
- new WindowTreeClient(this, nullptr, nullptr));
- second_client->ConnectViaWindowTreeFactory(connector());
- Window* window_in_second_client =
- second_client->NewTopLevelWindow(nullptr);
- ASSERT_TRUE(window_in_second_client);
- ASSERT_TRUE(second_client->GetRoots().count(window_in_second_client) >
- 0);
- // Wait for the window to appear in the wm.
- ASSERT_TRUE(delegate.QuitOnCreate());
-
- Window* window_in_wm = delegate.created_window();
- ASSERT_TRUE(window_in_wm);
-
- // Change the bounds in the wm, and make sure the child sees it.
- window_in_wm->SetBounds(gfx::Rect(1, 11, 12, 101));
- ASSERT_TRUE(WaitForBoundsToChange(window_in_second_client));
- EXPECT_EQ(gfx::Rect(1, 11, 12, 101), window_in_second_client->bounds());
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_manager_display_root.cc b/chromium/components/mus/ws/window_manager_display_root.cc
deleted file mode 100644
index 351208d4af6..00000000000
--- a/chromium/components/mus/ws/window_manager_display_root.cc
+++ /dev/null
@@ -1,34 +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 "components/mus/ws/window_manager_display_root.h"
-
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/window_server.h"
-
-namespace mus {
-namespace ws {
-
-WindowManagerDisplayRoot::WindowManagerDisplayRoot(Display* display)
- : display_(display) {
- root_.reset(window_server()->CreateServerWindow(
- window_server()->display_manager()->GetAndAdvanceNextRootId(),
- ServerWindow::Properties()));
- // Our root is always a child of the Display's root. Do this
- // before the WindowTree has been created so that the client doesn't get
- // notified of the add, bounds change and visibility change.
- root_->SetBounds(gfx::Rect(display->root_window()->bounds().size()));
- root_->SetVisible(true);
- display->root_window()->Add(root_.get());
-}
-
-WindowManagerDisplayRoot::~WindowManagerDisplayRoot() {}
-
-WindowServer* WindowManagerDisplayRoot::window_server() {
- return display_->window_server();
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_manager_display_root.h b/chromium/components/mus/ws/window_manager_display_root.h
deleted file mode 100644
index 94eda737201..00000000000
--- a/chromium/components/mus/ws/window_manager_display_root.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_WINDOW_MANAGER_DISPLAY_ROOT_H_
-#define COMPONENTS_MUS_WS_WINDOW_MANAGER_DISPLAY_ROOT_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-
-namespace mus {
-namespace ws {
-
-class Display;
-class ServerWindow;
-class WindowManagerState;
-class WindowServer;
-
-namespace test {
-class WindowManagerDisplayRootTestApi;
-}
-
-// Owns the root window of a window manager for one display. Each window manager
-// has one WindowManagerDisplayRoot for each Display. The root window is
-// parented to the root of a Display.
-class WindowManagerDisplayRoot {
- public:
- explicit WindowManagerDisplayRoot(Display* display);
- ~WindowManagerDisplayRoot();
-
- ServerWindow* root() { return root_.get(); }
- const ServerWindow* root() const { return root_.get(); }
-
- Display* display() { return display_; }
- const Display* display() const { return display_; }
-
- WindowManagerState* window_manager_state() { return window_manager_state_; }
- const WindowManagerState* window_manager_state() const {
- return window_manager_state_;
- }
-
- private:
- friend class Display;
-
- WindowServer* window_server();
-
- Display* display_;
- // Root ServerWindow of this WindowManagerDisplayRoot. |root_| has a parent,
- // the root ServerWindow of the Display.
- std::unique_ptr<ServerWindow> root_;
- WindowManagerState* window_manager_state_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(WindowManagerDisplayRoot);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_MANAGER_DISPLAY_ROOT_H_
diff --git a/chromium/components/mus/ws/window_manager_state.cc b/chromium/components/mus/ws/window_manager_state.cc
deleted file mode 100644
index b394514bef2..00000000000
--- a/chromium/components/mus/ws/window_manager_state.cc
+++ /dev/null
@@ -1,485 +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 "components/mus/ws/window_manager_state.h"
-
-#include "base/memory/weak_ptr.h"
-#include "components/mus/common/event_matcher_util.h"
-#include "components/mus/ws/accelerator.h"
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/platform_display.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/user_display_manager.h"
-#include "components/mus/ws/user_id_tracker.h"
-#include "components/mus/ws/window_manager_display_root.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_tree.h"
-#include "services/shell/public/interfaces/connector.mojom.h"
-#include "ui/events/event.h"
-
-namespace mus {
-namespace ws {
-namespace {
-
-// Debug accelerator IDs start far above the highest valid Windows command ID
-// (0xDFFF) and Chrome's highest IDC command ID.
-const uint32_t kPrintWindowsDebugAcceleratorId = 1u << 31;
-
-base::TimeDelta GetDefaultAckTimerDelay() {
-#if defined(NDEBUG)
- return base::TimeDelta::FromMilliseconds(100);
-#else
- return base::TimeDelta::FromMilliseconds(1000);
-#endif
-}
-
-bool EventsCanBeCoalesced(const ui::Event& one, const ui::Event& two) {
- if (one.type() != two.type() || one.flags() != two.flags())
- return false;
-
- // TODO(sad): wheel events can also be merged.
- if (one.type() != ui::ET_POINTER_MOVED)
- return false;
-
- return one.AsPointerEvent()->pointer_id() ==
- two.AsPointerEvent()->pointer_id();
-}
-
-std::unique_ptr<ui::Event> CoalesceEvents(std::unique_ptr<ui::Event> first,
- std::unique_ptr<ui::Event> second) {
- DCHECK(first->type() == ui::ET_POINTER_MOVED)
- << " Non-move events cannot be merged yet.";
- // For mouse moves, the new event just replaces the old event.
- return second;
-}
-
-const ServerWindow* GetEmbedRoot(const ServerWindow* window) {
- DCHECK(window);
- const ServerWindow* embed_root = window->parent();
- while (embed_root && embed_root->id().client_id == window->id().client_id)
- embed_root = embed_root->parent();
- return embed_root;
-}
-
-} // namespace
-
-class WindowManagerState::ProcessedEventTarget {
- public:
- ProcessedEventTarget(ServerWindow* window,
- ClientSpecificId client_id,
- Accelerator* accelerator)
- : client_id_(client_id) {
- tracker_.Add(window);
- if (accelerator)
- accelerator_ = accelerator->GetWeakPtr();
- }
-
- ~ProcessedEventTarget() {}
-
- // Return true if the event is still valid. The event becomes invalid if
- // the window is destroyed while waiting to dispatch.
- bool IsValid() const { return !tracker_.windows().empty(); }
-
- ServerWindow* window() {
- DCHECK(IsValid());
- return tracker_.windows().front();
- }
-
- ClientSpecificId client_id() const { return client_id_; }
-
- base::WeakPtr<Accelerator> accelerator() { return accelerator_; }
-
- private:
- ServerWindowTracker tracker_;
- const ClientSpecificId client_id_;
- base::WeakPtr<Accelerator> accelerator_;
-
- DISALLOW_COPY_AND_ASSIGN(ProcessedEventTarget);
-};
-
-WindowManagerState::QueuedEvent::QueuedEvent() {}
-WindowManagerState::QueuedEvent::~QueuedEvent() {}
-
-WindowManagerState::WindowManagerState(WindowTree* window_tree)
- : window_tree_(window_tree), event_dispatcher_(this), weak_factory_(this) {
- frame_decoration_values_ = mojom::FrameDecorationValues::New();
- frame_decoration_values_->max_title_bar_button_width = 0u;
-
- AddDebugAccelerators();
-}
-
-WindowManagerState::~WindowManagerState() {}
-
-void WindowManagerState::SetFrameDecorationValues(
- mojom::FrameDecorationValuesPtr values) {
- got_frame_decoration_values_ = true;
- frame_decoration_values_ = values.Clone();
- display_manager()
- ->GetUserDisplayManager(user_id())
- ->OnFrameDecorationValuesChanged();
-}
-
-bool WindowManagerState::SetCapture(ServerWindow* window,
- ClientSpecificId client_id) {
- DCHECK(IsActive());
- if (capture_window() == window &&
- client_id == event_dispatcher_.capture_window_client_id()) {
- return true;
- }
-#if !defined(NDEBUG)
- if (window) {
- WindowManagerDisplayRoot* display_root =
- display_manager()->GetWindowManagerDisplayRoot(window);
- DCHECK(display_root && display_root->window_manager_state() == this);
- }
-#endif
- return event_dispatcher_.SetCaptureWindow(window, client_id);
-}
-
-void WindowManagerState::ReleaseCaptureBlockedByModalWindow(
- const ServerWindow* modal_window) {
- event_dispatcher_.ReleaseCaptureBlockedByModalWindow(modal_window);
-}
-
-void WindowManagerState::ReleaseCaptureBlockedByAnyModalWindow() {
- event_dispatcher_.ReleaseCaptureBlockedByAnyModalWindow();
-}
-
-void WindowManagerState::AddSystemModalWindow(ServerWindow* window) {
- DCHECK(!window->transient_parent());
- event_dispatcher_.AddSystemModalWindow(window);
-}
-
-const UserId& WindowManagerState::user_id() const {
- return window_tree_->user_id();
-}
-
-void WindowManagerState::OnWillDestroyTree(WindowTree* tree) {
- if (tree_awaiting_input_ack_ != tree)
- return;
-
- // The WindowTree is dying. So it's not going to ack the event.
- // If the dying tree matches the root |tree_| marked as handled so we don't
- // notify it of accelerators.
- OnEventAck(tree_awaiting_input_ack_, tree == window_tree_
- ? mojom::EventResult::HANDLED
- : mojom::EventResult::UNHANDLED);
-}
-
-bool WindowManagerState::IsActive() const {
- return window_server()->user_id_tracker()->active_id() == user_id();
-}
-
-void WindowManagerState::Activate(const gfx::Point& mouse_location_on_screen) {
- SetAllRootWindowsVisible(true);
- event_dispatcher_.Reset();
- event_dispatcher_.SetMousePointerScreenLocation(mouse_location_on_screen);
-}
-
-void WindowManagerState::Deactivate() {
- SetAllRootWindowsVisible(false);
- event_dispatcher_.Reset();
- // The tree is no longer active, so no point in dispatching any further
- // events.
- std::queue<std::unique_ptr<QueuedEvent>> event_queue;
- event_queue.swap(event_queue_);
-}
-
-void WindowManagerState::ProcessEvent(const ui::Event& event) {
- // If this is still waiting for an ack from a previously sent event, then
- // queue up the event to be dispatched once the ack is received.
- if (event_ack_timer_.IsRunning()) {
- if (!event_queue_.empty() && !event_queue_.back()->processed_target &&
- EventsCanBeCoalesced(*event_queue_.back()->event, event)) {
- event_queue_.back()->event = CoalesceEvents(
- std::move(event_queue_.back()->event), ui::Event::Clone(event));
- return;
- }
- QueueEvent(event, nullptr);
- return;
- }
- event_dispatcher_.ProcessEvent(event);
-}
-
-void WindowManagerState::OnEventAck(mojom::WindowTree* tree,
- mojom::EventResult result) {
- if (tree_awaiting_input_ack_ != tree) {
- // TODO(sad): The ack must have arrived after the timeout. We should do
- // something here, and in OnEventAckTimeout().
- return;
- }
- tree_awaiting_input_ack_ = nullptr;
- event_ack_timer_.Stop();
-
- if (result == mojom::EventResult::UNHANDLED && post_target_accelerator_)
- OnAccelerator(post_target_accelerator_->id(), *event_awaiting_input_ack_);
-
- ProcessNextEventFromQueue();
-}
-
-const WindowServer* WindowManagerState::window_server() const {
- return window_tree_->window_server();
-}
-
-WindowServer* WindowManagerState::window_server() {
- return window_tree_->window_server();
-}
-
-DisplayManager* WindowManagerState::display_manager() {
- return window_tree_->display_manager();
-}
-
-const DisplayManager* WindowManagerState::display_manager() const {
- return window_tree_->display_manager();
-}
-
-void WindowManagerState::SetAllRootWindowsVisible(bool value) {
- for (Display* display : display_manager()->displays()) {
- WindowManagerDisplayRoot* display_root =
- display->GetWindowManagerDisplayRootForUser(user_id());
- if (display_root)
- display_root->root()->SetVisible(value);
- }
-}
-
-ServerWindow* WindowManagerState::GetWindowManagerRoot(ServerWindow* window) {
- for (Display* display : display_manager()->displays()) {
- WindowManagerDisplayRoot* display_root =
- display->GetWindowManagerDisplayRootForUser(user_id());
- if (display_root && display_root->root()->parent() == window)
- return display_root->root();
- }
- NOTREACHED();
- return nullptr;
-}
-
-void WindowManagerState::OnEventAckTimeout(ClientSpecificId client_id) {
- WindowTree* hung_tree = window_server()->GetTreeWithId(client_id);
- if (hung_tree && !hung_tree->janky())
- window_tree_->ClientJankinessChanged(hung_tree);
- OnEventAck(tree_awaiting_input_ack_, mojom::EventResult::UNHANDLED);
-}
-
-void WindowManagerState::QueueEvent(
- const ui::Event& event,
- std::unique_ptr<ProcessedEventTarget> processed_event_target) {
- std::unique_ptr<QueuedEvent> queued_event(new QueuedEvent);
- queued_event->event = ui::Event::Clone(event);
- queued_event->processed_target = std::move(processed_event_target);
- event_queue_.push(std::move(queued_event));
-}
-
-void WindowManagerState::ProcessNextEventFromQueue() {
- // Loop through |event_queue_| stopping after dispatching the first valid
- // event.
- while (!event_queue_.empty()) {
- std::unique_ptr<QueuedEvent> queued_event = std::move(event_queue_.front());
- event_queue_.pop();
- if (!queued_event->processed_target) {
- event_dispatcher_.ProcessEvent(*queued_event->event);
- return;
- }
- if (queued_event->processed_target->IsValid()) {
- DispatchInputEventToWindowImpl(
- queued_event->processed_target->window(),
- queued_event->processed_target->client_id(), *queued_event->event,
- queued_event->processed_target->accelerator());
- return;
- }
- }
-}
-
-void WindowManagerState::DispatchInputEventToWindowImpl(
- ServerWindow* target,
- ClientSpecificId client_id,
- const ui::Event& event,
- base::WeakPtr<Accelerator> accelerator) {
- if (target && target->parent() == nullptr)
- target = GetWindowManagerRoot(target);
-
- if (event.IsMousePointerEvent()) {
- DCHECK(event_dispatcher_.mouse_cursor_source_window());
-
- int32_t cursor_id = 0;
- if (event_dispatcher_.GetCurrentMouseCursor(&cursor_id)) {
- WindowManagerDisplayRoot* display_root =
- display_manager()->GetWindowManagerDisplayRoot(target);
- display_root->display()->UpdateNativeCursor(cursor_id);
- }
- }
-
- WindowTree* tree = window_server()->GetTreeWithId(client_id);
-
- // TOOD(sad): Adjust this delay, possibly make this dynamic.
- const base::TimeDelta max_delay = base::debug::BeingDebugged()
- ? base::TimeDelta::FromDays(1)
- : GetDefaultAckTimerDelay();
- event_ack_timer_.Start(
- FROM_HERE, max_delay,
- base::Bind(&WindowManagerState::OnEventAckTimeout,
- weak_factory_.GetWeakPtr(), tree->id()));
-
- tree_awaiting_input_ack_ = tree;
- if (accelerator) {
- event_awaiting_input_ack_ = ui::Event::Clone(event);
- post_target_accelerator_ = accelerator;
- }
-
- // Ignore |tree| because it will receive the event via normal dispatch.
- window_server()->SendToEventObservers(event, user_id(), tree);
-
- tree->DispatchInputEvent(target, event);
-}
-
-void WindowManagerState::AddDebugAccelerators() {
- // Always register the accelerators, even if they only work in debug, so that
- // keyboard behavior is the same in release and debug builds.
- mojom::EventMatcherPtr matcher = CreateKeyMatcher(
- ui::mojom::KeyboardCode::S, ui::mojom::kEventFlagControlDown |
- ui::mojom::kEventFlagAltDown |
- ui::mojom::kEventFlagShiftDown);
- event_dispatcher_.AddAccelerator(kPrintWindowsDebugAcceleratorId,
- std::move(matcher));
-}
-
-bool WindowManagerState::HandleDebugAccelerator(uint32_t accelerator_id) {
-#if !defined(NDEBUG)
- if (accelerator_id == kPrintWindowsDebugAcceleratorId) {
- // Error so it will be collected in system logs.
- for (Display* display : display_manager()->displays()) {
- WindowManagerDisplayRoot* display_root =
- display->GetWindowManagerDisplayRootForUser(user_id());
- if (display_root) {
- LOG(ERROR) << "ServerWindow hierarchy:\n"
- << display_root->root()->GetDebugWindowHierarchy();
- }
- }
- return true;
- }
-#endif
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// EventDispatcherDelegate:
-
-void WindowManagerState::OnAccelerator(uint32_t accelerator_id,
- const ui::Event& event) {
- DCHECK(IsActive());
- if (HandleDebugAccelerator(accelerator_id))
- return;
- window_tree_->OnAccelerator(accelerator_id, event);
-}
-
-void WindowManagerState::SetFocusedWindowFromEventDispatcher(
- ServerWindow* new_focused_window) {
- DCHECK(IsActive());
- window_server()->SetFocusedWindow(new_focused_window);
-}
-
-ServerWindow* WindowManagerState::GetFocusedWindowForEventDispatcher() {
- return window_server()->GetFocusedWindow();
-}
-
-void WindowManagerState::SetNativeCapture(ServerWindow* window) {
- DCHECK(IsActive());
- WindowManagerDisplayRoot* display_root =
- display_manager()->GetWindowManagerDisplayRoot(window);
- DCHECK(display_root);
- platform_display_with_capture_ = display_root->display()->platform_display();
- platform_display_with_capture_->SetCapture();
-}
-
-void WindowManagerState::ReleaseNativeCapture() {
- // Tests trigger calling this without a corresponding SetNativeCapture().
- // TODO(sky): maybe abstract this away so that DCHECK can be added?
- if (!platform_display_with_capture_)
- return;
-
- platform_display_with_capture_->ReleaseCapture();
- platform_display_with_capture_ = nullptr;
-}
-
-void WindowManagerState::OnServerWindowCaptureLost(ServerWindow* window) {
- DCHECK(window);
- window_server()->ProcessLostCapture(window);
-}
-
-void WindowManagerState::OnMouseCursorLocationChanged(const gfx::Point& point) {
- window_server()
- ->display_manager()
- ->GetUserDisplayManager(user_id())
- ->OnMouseCursorLocationChanged(point);
-}
-
-void WindowManagerState::DispatchInputEventToWindow(ServerWindow* target,
- ClientSpecificId client_id,
- const ui::Event& event,
- Accelerator* accelerator) {
- DCHECK(IsActive());
- // TODO(sky): this needs to see if another wms has capture and if so forward
- // to it.
- if (event_ack_timer_.IsRunning()) {
- std::unique_ptr<ProcessedEventTarget> processed_event_target(
- new ProcessedEventTarget(target, client_id, accelerator));
- QueueEvent(event, std::move(processed_event_target));
- return;
- }
-
- base::WeakPtr<Accelerator> weak_accelerator;
- if (accelerator)
- weak_accelerator = accelerator->GetWeakPtr();
- DispatchInputEventToWindowImpl(target, client_id, event, weak_accelerator);
-}
-
-ClientSpecificId WindowManagerState::GetEventTargetClientId(
- const ServerWindow* window,
- bool in_nonclient_area) {
- // If the event is in the non-client area the event goes to the owner of
- // the window.
- WindowTree* tree = nullptr;
- if (in_nonclient_area) {
- tree = window_server()->GetTreeWithId(window->id().client_id);
- } else {
- // If the window is an embed root, forward to the embedded window.
- tree = window_server()->GetTreeWithRoot(window);
- if (!tree)
- tree = window_server()->GetTreeWithId(window->id().client_id);
- }
-
- const ServerWindow* embed_root =
- tree->HasRoot(window) ? window : GetEmbedRoot(window);
- while (tree && tree->embedder_intercepts_events()) {
- DCHECK(tree->HasRoot(embed_root));
- tree = window_server()->GetTreeWithId(embed_root->id().client_id);
- embed_root = GetEmbedRoot(embed_root);
- }
-
- if (!tree) {
- DCHECK(in_nonclient_area);
- tree = window_tree_;
- }
- return tree->id();
-}
-
-ServerWindow* WindowManagerState::GetRootWindowContaining(
- const gfx::Point& location) {
- if (display_manager()->displays().empty())
- return nullptr;
-
- // TODO(sky): this isn't right. To correctly implement need bounds of
- // Display, which we aren't tracking yet. For now, use the first display.
- Display* display = *(display_manager()->displays().begin());
- WindowManagerDisplayRoot* display_root =
- display->GetWindowManagerDisplayRootForUser(user_id());
- return display_root ? display_root->root() : nullptr;
-}
-
-void WindowManagerState::OnEventTargetNotFound(const ui::Event& event) {
- window_server()->SendToEventObservers(event, user_id(),
- nullptr /* ignore_tree */);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_manager_state.h b/chromium/components/mus/ws/window_manager_state.h
deleted file mode 100644
index dca6670d400..00000000000
--- a/chromium/components/mus/ws/window_manager_state.h
+++ /dev/null
@@ -1,183 +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 COMPONENTS_MUS_WS_WINDOW_MANAGER_STATE_H_
-#define COMPONENTS_MUS_WS_WINDOW_MANAGER_STATE_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
-#include "components/mus/public/interfaces/display.mojom.h"
-#include "components/mus/ws/event_dispatcher.h"
-#include "components/mus/ws/event_dispatcher_delegate.h"
-#include "components/mus/ws/user_id.h"
-#include "components/mus/ws/window_server.h"
-
-namespace mus {
-namespace ws {
-
-class DisplayManager;
-class WindowTree;
-
-namespace test {
-class WindowManagerStateTestApi;
-}
-
-// Manages state specific to a WindowManager that is shared across displays.
-// WindowManagerState is owned by the WindowTree the window manager is
-// associated with.
-class WindowManagerState : public EventDispatcherDelegate {
- public:
- explicit WindowManagerState(WindowTree* window_tree);
- ~WindowManagerState() override;
-
- const UserId& user_id() const;
-
- WindowTree* window_tree() { return window_tree_; }
- const WindowTree* window_tree() const { return window_tree_; }
-
- void OnWillDestroyTree(WindowTree* tree);
-
- void SetFrameDecorationValues(mojom::FrameDecorationValuesPtr values);
- const mojom::FrameDecorationValues& frame_decoration_values() const {
- return *frame_decoration_values_;
- }
- bool got_frame_decoration_values() const {
- return got_frame_decoration_values_;
- }
-
- bool SetCapture(ServerWindow* window, ClientSpecificId client_id);
- ServerWindow* capture_window() { return event_dispatcher_.capture_window(); }
- const ServerWindow* capture_window() const {
- return event_dispatcher_.capture_window();
- }
-
- void ReleaseCaptureBlockedByModalWindow(const ServerWindow* modal_window);
- void ReleaseCaptureBlockedByAnyModalWindow();
-
- void AddSystemModalWindow(ServerWindow* window);
-
- // TODO(sky): EventDispatcher is really an implementation detail and should
- // not be exposed.
- EventDispatcher* event_dispatcher() { return &event_dispatcher_; }
-
- // Returns true if this is the WindowManager of the active user.
- bool IsActive() const;
-
- void Activate(const gfx::Point& mouse_location_on_screen);
- void Deactivate();
-
- // Processes an event from PlatformDisplay.
- void ProcessEvent(const ui::Event& event);
-
- // Called when the ack from an event dispatched to WindowTree |tree| is
- // received.
- // TODO(sky): make this private and use a callback.
- void OnEventAck(mojom::WindowTree* tree, mojom::EventResult result);
-
- private:
- class ProcessedEventTarget;
- friend class Display;
- friend class test::WindowManagerStateTestApi;
-
- // There are two types of events that may be queued, both occur only when
- // waiting for an ack from a client.
- // . We get an event from the PlatformDisplay. This results in |event| being
- // set, but |processed_target| is null.
- // . We get an event from the EventDispatcher. In this case both |event| and
- // |processed_target| are valid.
- // The second case happens if EventDispatcher generates more than one event
- // at a time.
- struct QueuedEvent {
- QueuedEvent();
- ~QueuedEvent();
-
- std::unique_ptr<ui::Event> event;
- std::unique_ptr<ProcessedEventTarget> processed_target;
- };
-
- const WindowServer* window_server() const;
- WindowServer* window_server();
-
- DisplayManager* display_manager();
- const DisplayManager* display_manager() const;
-
- // Sets the visibility of all window manager roots windows to |value|.
- void SetAllRootWindowsVisible(bool value);
-
- // Returns the ServerWindow that is the root of the WindowManager for
- // |window|. |window| corresponds to the root of a Display.
- ServerWindow* GetWindowManagerRoot(ServerWindow* window);
-
- void OnEventAckTimeout(ClientSpecificId client_id);
-
- // Schedules an event to be processed later.
- void QueueEvent(const ui::Event& event,
- std::unique_ptr<ProcessedEventTarget> processed_event_target);
-
- // Processes the next valid event in |event_queue_|. If the event has already
- // been processed it is dispatched, otherwise the event is passed to the
- // EventDispatcher for processing.
- void ProcessNextEventFromQueue();
-
- // Dispatches the event to the appropriate client and starts the ack timer.
- void DispatchInputEventToWindowImpl(ServerWindow* target,
- ClientSpecificId client_id,
- const ui::Event& event,
- base::WeakPtr<Accelerator> accelerator);
-
- // Registers accelerators used internally for debugging.
- void AddDebugAccelerators();
-
- // Returns true if the accelerator was handled.
- bool HandleDebugAccelerator(uint32_t accelerator_id);
-
- // EventDispatcherDelegate:
- void OnAccelerator(uint32_t accelerator_id, const ui::Event& event) override;
- void SetFocusedWindowFromEventDispatcher(ServerWindow* window) override;
- ServerWindow* GetFocusedWindowForEventDispatcher() override;
- void SetNativeCapture(ServerWindow* window) override;
- void ReleaseNativeCapture() override;
- void OnServerWindowCaptureLost(ServerWindow* window) override;
- void OnMouseCursorLocationChanged(const gfx::Point& point) override;
- void DispatchInputEventToWindow(ServerWindow* target,
- ClientSpecificId client_id,
- const ui::Event& event,
- Accelerator* accelerator) override;
- ClientSpecificId GetEventTargetClientId(const ServerWindow* window,
- bool in_nonclient_area) override;
- ServerWindow* GetRootWindowContaining(const gfx::Point& location) override;
- void OnEventTargetNotFound(const ui::Event& event) override;
-
- // The single WindowTree this WindowManagerState is associated with.
- // |window_tree_| owns this.
- WindowTree* window_tree_;
-
- // Set to true the first time SetFrameDecorationValues() is called.
- bool got_frame_decoration_values_ = false;
- mojom::FrameDecorationValuesPtr frame_decoration_values_;
-
- mojom::WindowTree* tree_awaiting_input_ack_ = nullptr;
- std::unique_ptr<ui::Event> event_awaiting_input_ack_;
- base::WeakPtr<Accelerator> post_target_accelerator_;
- std::queue<std::unique_ptr<QueuedEvent>> event_queue_;
- base::OneShotTimer event_ack_timer_;
-
- EventDispatcher event_dispatcher_;
-
- // PlatformDisplay that currently has capture.
- PlatformDisplay* platform_display_with_capture_ = nullptr;
-
- base::WeakPtrFactory<WindowManagerState> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowManagerState);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_MANAGER_STATE_H_
diff --git a/chromium/components/mus/ws/window_manager_state_unittest.cc b/chromium/components/mus/ws/window_manager_state_unittest.cc
deleted file mode 100644
index 20980f75b4c..00000000000
--- a/chromium/components/mus/ws/window_manager_state_unittest.cc
+++ /dev/null
@@ -1,419 +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 "components/mus/ws/window_manager_state.h"
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/mus/common/event_matcher_util.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/accelerator.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/display_binding.h"
-#include "components/mus/ws/platform_display.h"
-#include "components/mus/ws/platform_display_init_params.h"
-#include "components/mus/ws/server_window_surface_manager_test_api.h"
-#include "components/mus/ws/test_change_tracker.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "components/mus/ws/test_utils.h"
-#include "components/mus/ws/window_manager_access_policy.h"
-#include "components/mus/ws/window_manager_display_root.h"
-#include "components/mus/ws/window_manager_state.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_tree.h"
-#include "services/shell/public/interfaces/connector.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event.h"
-
-namespace mus {
-namespace ws {
-namespace test {
-
-class WindowManagerStateTest : public testing::Test {
- public:
- WindowManagerStateTest();
- ~WindowManagerStateTest() override {}
-
- std::unique_ptr<Accelerator> CreateAccelerator();
-
- // Creates a child |server_window| with associataed |window_tree| and
- // |test_client|. The window is setup for processing input.
- void CreateSecondaryTree(TestWindowTreeClient** test_client,
- WindowTree** window_tree,
- ServerWindow** server_window);
-
- void DispatchInputEventToWindow(ServerWindow* target,
- const ui::Event& event,
- Accelerator* accelerator);
- void OnEventAckTimeout(ClientSpecificId client_id);
-
- WindowTree* tree() {
- return window_event_targeting_helper_.window_server()->GetTreeWithId(1);
- }
- WindowTree* window_tree() { return window_tree_; }
- TestWindowTreeClient* window_tree_client() { return window_tree_client_; }
- ServerWindow* window() { return window_; }
- TestWindowManager* window_manager() { return &window_manager_; }
- TestWindowTreeClient* wm_client() {
- return window_event_targeting_helper_.wm_client();
- }
- TestWindowTreeClient* last_tree_client() {
- return window_event_targeting_helper_.last_window_tree_client();
- }
- WindowTree* last_tree() {
- return window_event_targeting_helper_.last_binding()->tree();
- }
- WindowManagerState* window_manager_state() { return window_manager_state_; }
-
- void EmbedAt(WindowTree* tree,
- const ClientWindowId& embed_window_id,
- uint32_t embed_flags,
- WindowTree** embed_tree,
- TestWindowTreeClient** embed_client_proxy) {
- mojom::WindowTreeClientPtr embed_client;
- mojom::WindowTreeClientRequest client_request = GetProxy(&embed_client);
- ASSERT_TRUE(
- tree->Embed(embed_window_id, std::move(embed_client), embed_flags));
- TestWindowTreeClient* client =
- window_event_targeting_helper_.last_window_tree_client();
- ASSERT_EQ(1u, client->tracker()->changes()->size());
- EXPECT_EQ(CHANGE_TYPE_EMBED, (*client->tracker()->changes())[0].type);
- client->tracker()->changes()->clear();
- *embed_client_proxy = client;
- *embed_tree = window_event_targeting_helper_.last_binding()->tree();
- }
-
- // testing::Test:
- void SetUp() override;
-
- private:
- WindowEventTargetingHelper window_event_targeting_helper_;
-
- WindowManagerState* window_manager_state_;
-
- // Handles WindowStateManager ack timeouts.
- scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
- TestWindowManager window_manager_;
- ServerWindow* window_ = nullptr;
- WindowTree* window_tree_ = nullptr;
- TestWindowTreeClient* window_tree_client_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(WindowManagerStateTest);
-};
-
-WindowManagerStateTest::WindowManagerStateTest()
- : task_runner_(new base::TestSimpleTaskRunner) {}
-
-std::unique_ptr<Accelerator> WindowManagerStateTest::CreateAccelerator() {
- mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher(
- ui::mojom::KeyboardCode::W, ui::mojom::kEventFlagControlDown);
- matcher->accelerator_phase = ui::mojom::AcceleratorPhase::POST_TARGET;
- uint32_t accelerator_id = 1;
- std::unique_ptr<Accelerator> accelerator(
- new Accelerator(accelerator_id, *matcher));
- return accelerator;
-}
-
-void WindowManagerStateTest::CreateSecondaryTree(
- TestWindowTreeClient** test_client,
- WindowTree** window_tree,
- ServerWindow** server_window) {
- window_event_targeting_helper_.CreateSecondaryTree(
- window_, gfx::Rect(20, 20, 20, 20), test_client, window_tree,
- server_window);
-}
-
-void WindowManagerStateTest::DispatchInputEventToWindow(
- ServerWindow* target,
- const ui::Event& event,
- Accelerator* accelerator) {
- WindowManagerStateTestApi test_api(window_manager_state_);
- ClientSpecificId client_id = test_api.GetEventTargetClientId(target, false);
- test_api.DispatchInputEventToWindow(target, client_id, event, accelerator);
-}
-
-void WindowManagerStateTest::OnEventAckTimeout(
- ClientSpecificId client_id) {
- WindowManagerStateTestApi test_api(window_manager_state_);
- test_api.OnEventAckTimeout(client_id);
-}
-
-void WindowManagerStateTest::SetUp() {
- window_event_targeting_helper_.SetTaskRunner(task_runner_);
- window_manager_state_ = window_event_targeting_helper_.display()
- ->GetActiveWindowManagerDisplayRoot()
- ->window_manager_state();
- window_ = window_event_targeting_helper_.CreatePrimaryTree(
- gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 50, 50));
- window_tree_ = window_event_targeting_helper_.last_binding()->tree();
- window_tree_client_ =
- window_event_targeting_helper_.last_window_tree_client();
- DCHECK(window_tree_->HasRoot(window_));
-
- WindowTreeTestApi(tree()).set_window_manager_internal(&window_manager_);
- wm_client()->tracker()->changes()->clear();
- window_tree_client_->tracker()->changes()->clear();
-}
-
-// Tests that when an event is dispatched with no accelerator, that post target
-// accelerator is not triggered.
-TEST_F(WindowManagerStateTest, NullAccelerator) {
- WindowManagerState* state = window_manager_state();
- EXPECT_TRUE(state);
-
- ServerWindow* target = window();
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
- DispatchInputEventToWindow(target, key, nullptr);
- WindowTree* target_tree = window_tree();
- TestChangeTracker* tracker = window_tree_client()->tracker();
- ASSERT_EQ(1u, tracker->changes()->size());
- EXPECT_EQ("InputEvent window=1,1 event_action=7",
- ChangesToDescription1(*tracker->changes())[0]);
-
- WindowTreeTestApi(target_tree).AckOldestEvent();
- EXPECT_FALSE(window_manager()->on_accelerator_called());
-}
-
-// Tests that when a post target accelerator is provided on an event, that it is
-// called on ack.
-TEST_F(WindowManagerStateTest, PostTargetAccelerator) {
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
- std::unique_ptr<Accelerator> accelerator = CreateAccelerator();
-
- ServerWindow* target = window();
- DispatchInputEventToWindow(target, key, accelerator.get());
- TestChangeTracker* tracker = window_tree_client()->tracker();
- ASSERT_EQ(1u, tracker->changes()->size());
- EXPECT_EQ("InputEvent window=1,1 event_action=7",
- ChangesToDescription1(*tracker->changes())[0]);
-
- WindowTreeTestApi(window_tree()).AckOldestEvent();
- EXPECT_TRUE(window_manager()->on_accelerator_called());
- EXPECT_EQ(accelerator->id(), window_manager()->on_accelerator_id());
-}
-
-// Tests that when a client handles an event that post target accelerators are
-// not called.
-TEST_F(WindowManagerStateTest, ClientHandlesEvent) {
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
- std::unique_ptr<Accelerator> accelerator = CreateAccelerator();
-
- ServerWindow* target = window();
- DispatchInputEventToWindow(target, key, accelerator.get());
- TestChangeTracker* tracker = window_tree_client()->tracker();
- ASSERT_EQ(1u, tracker->changes()->size());
- EXPECT_EQ("InputEvent window=1,1 event_action=7",
- ChangesToDescription1(*tracker->changes())[0]);
-
- window_manager_state()->OnEventAck(tree(), mojom::EventResult::HANDLED);
- EXPECT_FALSE(window_manager()->on_accelerator_called());
-}
-
-// Tests that when an accelerator is deleted before an ack, that it is not
-// called.
-TEST_F(WindowManagerStateTest, AcceleratorDeleted) {
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
- std::unique_ptr<Accelerator> accelerator(CreateAccelerator());
-
- ServerWindow* target = window();
- DispatchInputEventToWindow(target, key, accelerator.get());
- TestChangeTracker* tracker = window_tree_client()->tracker();
- ASSERT_EQ(1u, tracker->changes()->size());
- EXPECT_EQ("InputEvent window=1,1 event_action=7",
- ChangesToDescription1(*tracker->changes())[0]);
-
- accelerator.reset();
- window_manager_state()->OnEventAck(tree(), mojom::EventResult::UNHANDLED);
- EXPECT_FALSE(window_manager()->on_accelerator_called());
-}
-
-// Tests that a events arriving before an ack don't notify the tree until the
-// ack arrives, and that the correct accelerator is called.
-TEST_F(WindowManagerStateTest, EnqueuedAccelerators) {
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
- std::unique_ptr<Accelerator> accelerator(CreateAccelerator());
-
- ServerWindow* target = window();
- DispatchInputEventToWindow(target, key, accelerator.get());
- TestChangeTracker* tracker = window_tree_client()->tracker();
- ASSERT_EQ(1u, tracker->changes()->size());
- EXPECT_EQ("InputEvent window=1,1 event_action=7",
- ChangesToDescription1(*tracker->changes())[0]);
-
- tracker->changes()->clear();
- ui::KeyEvent key2(ui::ET_KEY_PRESSED, ui::VKEY_Y, ui::EF_CONTROL_DOWN);
- mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher(
- ui::mojom::KeyboardCode::Y, ui::mojom::kEventFlagControlDown);
- matcher->accelerator_phase = ui::mojom::AcceleratorPhase::POST_TARGET;
- uint32_t accelerator_id = 2;
- std::unique_ptr<Accelerator> accelerator2(
- new Accelerator(accelerator_id, *matcher));
- DispatchInputEventToWindow(target, key2, accelerator2.get());
- EXPECT_TRUE(tracker->changes()->empty());
-
- WindowTreeTestApi(window_tree()).AckOldestEvent();
- ASSERT_EQ(1u, tracker->changes()->size());
- EXPECT_EQ("InputEvent window=1,1 event_action=7",
- ChangesToDescription1(*tracker->changes())[0]);
- EXPECT_TRUE(window_manager()->on_accelerator_called());
- EXPECT_EQ(accelerator->id(), window_manager()->on_accelerator_id());
-}
-
-// Tests that the accelerator is not sent when the tree is dying.
-TEST_F(WindowManagerStateTest, DeleteTree) {
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
- std::unique_ptr<Accelerator> accelerator = CreateAccelerator();
-
- ServerWindow* target = window();
- DispatchInputEventToWindow(target, key, accelerator.get());
- TestChangeTracker* tracker = window_tree_client()->tracker();
- ASSERT_EQ(1u, tracker->changes()->size());
- EXPECT_EQ("InputEvent window=1,1 event_action=7",
- ChangesToDescription1(*tracker->changes())[0]);
-
- window_manager_state()->OnWillDestroyTree(tree());
- EXPECT_FALSE(window_manager()->on_accelerator_called());
-}
-
-// Tests that if a tree is destroyed before acking, that the accelerator is
-// still sent if it is not the root tree.
-TEST_F(WindowManagerStateTest, DeleteNonRootTree) {
- TestWindowTreeClient* embed_connection = nullptr;
- WindowTree* target_tree = nullptr;
- ServerWindow* target = nullptr;
- CreateSecondaryTree(&embed_connection, &target_tree, &target);
- TestWindowManager target_window_manager;
- WindowTreeTestApi(target_tree)
- .set_window_manager_internal(&target_window_manager);
-
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
- std::unique_ptr<Accelerator> accelerator = CreateAccelerator();
- DispatchInputEventToWindow(target, key, accelerator.get());
- TestChangeTracker* tracker = embed_connection->tracker();
- ASSERT_EQ(1u, tracker->changes()->size());
- EXPECT_EQ("InputEvent window=2,1 event_action=7",
- ChangesToDescription1(*tracker->changes())[0]);
- EXPECT_TRUE(wm_client()->tracker()->changes()->empty());
-
- window_manager_state()->OnWillDestroyTree(target_tree);
- EXPECT_FALSE(target_window_manager.on_accelerator_called());
- EXPECT_TRUE(window_manager()->on_accelerator_called());
-}
-
-// Tests that when an ack times out that the accelerator is notified.
-TEST_F(WindowManagerStateTest, AckTimeout) {
- ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
- std::unique_ptr<Accelerator> accelerator = CreateAccelerator();
- DispatchInputEventToWindow(window(), key, accelerator.get());
- TestChangeTracker* tracker = window_tree_client()->tracker();
- ASSERT_EQ(1u, tracker->changes()->size());
- EXPECT_EQ("InputEvent window=1,1 event_action=7",
- ChangesToDescription1(*tracker->changes())[0]);
-
- OnEventAckTimeout(window()->id().client_id);
- EXPECT_TRUE(window_manager()->on_accelerator_called());
- EXPECT_EQ(accelerator->id(), window_manager()->on_accelerator_id());
-}
-
-TEST_F(WindowManagerStateTest, InterceptingEmbedderReceivesEvents) {
- WindowTree* embedder_tree = tree();
- ServerWindow* embedder_root = window();
- const ClientWindowId embed_window_id(
- WindowIdToTransportId(WindowId(embedder_tree->id(), 12)));
- embedder_tree->NewWindow(embed_window_id, ServerWindow::Properties());
- ServerWindow* embedder_window =
- embedder_tree->GetWindowByClientId(embed_window_id);
- ASSERT_TRUE(embedder_tree->AddWindow(
- ClientWindowId(WindowIdToTransportId(embedder_root->id())),
- embed_window_id));
-
- TestWindowTreeClient* embedder_client = wm_client();
-
- {
- // Do a normal embed.
- const uint32_t embed_flags = 0;
- WindowTree* embed_tree = nullptr;
- TestWindowTreeClient* embed_client_proxy = nullptr;
- EmbedAt(embedder_tree, embed_window_id, embed_flags, &embed_tree,
- &embed_client_proxy);
- ASSERT_TRUE(embed_client_proxy);
-
- // Send an event to the embed window. It should go to the embedded client.
- ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
- base::TimeTicks(), 0, 0);
- DispatchInputEventToWindow(embedder_window, mouse, nullptr);
- ASSERT_EQ(1u, embed_client_proxy->tracker()->changes()->size());
- EXPECT_EQ(CHANGE_TYPE_INPUT_EVENT,
- (*embed_client_proxy->tracker()->changes())[0].type);
- WindowTreeTestApi(embed_tree).AckLastEvent(mojom::EventResult::UNHANDLED);
- embed_client_proxy->tracker()->changes()->clear();
- }
-
- {
- // Do an embed where the embedder wants to intercept events to the embedded
- // tree.
- const uint32_t embed_flags = mojom::kEmbedFlagEmbedderInterceptsEvents;
- WindowTree* embed_tree = nullptr;
- TestWindowTreeClient* embed_client_proxy = nullptr;
- EmbedAt(embedder_tree, embed_window_id, embed_flags, &embed_tree,
- &embed_client_proxy);
- ASSERT_TRUE(embed_client_proxy);
- embedder_client->tracker()->changes()->clear();
-
- // Send an event to the embed window. But this time, it should reach the
- // embedder.
- ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
- base::TimeTicks(), 0, 0);
- DispatchInputEventToWindow(embedder_window, mouse, nullptr);
- ASSERT_EQ(0u, embed_client_proxy->tracker()->changes()->size());
- ASSERT_EQ(1u, embedder_client->tracker()->changes()->size());
- EXPECT_EQ(CHANGE_TYPE_INPUT_EVENT,
- (*embedder_client->tracker()->changes())[0].type);
- WindowTreeTestApi(embedder_tree)
- .AckLastEvent(mojom::EventResult::UNHANDLED);
- embedder_client->tracker()->changes()->clear();
-
- // Embed another tree in the embedded tree.
- const ClientWindowId nested_embed_window_id(
- WindowIdToTransportId(WindowId(embed_tree->id(), 23)));
- embed_tree->NewWindow(nested_embed_window_id, ServerWindow::Properties());
- const ClientWindowId embed_root_id(
- WindowIdToTransportId((*embed_tree->roots().begin())->id()));
- ASSERT_TRUE(embed_tree->AddWindow(embed_root_id, nested_embed_window_id));
-
- WindowTree* nested_embed_tree = nullptr;
- TestWindowTreeClient* nested_embed_client_proxy = nullptr;
- EmbedAt(embed_tree, nested_embed_window_id, embed_flags, &nested_embed_tree,
- &nested_embed_client_proxy);
- ASSERT_TRUE(nested_embed_client_proxy);
- embed_client_proxy->tracker()->changes()->clear();
- embedder_client->tracker()->changes()->clear();
-
- // Send an event to the nested embed window. The event should still reach
- // the outermost embedder.
- ServerWindow* nested_embed_window =
- embed_tree->GetWindowByClientId(nested_embed_window_id);
- DCHECK(nested_embed_window->parent());
- mouse = ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
- base::TimeTicks(), 0, 0);
- DispatchInputEventToWindow(nested_embed_window, mouse, nullptr);
- ASSERT_EQ(0u, nested_embed_client_proxy->tracker()->changes()->size());
- ASSERT_EQ(0u, embed_client_proxy->tracker()->changes()->size());
-
- ASSERT_EQ(1u, embedder_client->tracker()->changes()->size());
- EXPECT_EQ(CHANGE_TYPE_INPUT_EVENT,
- (*embedder_client->tracker()->changes())[0].type);
- WindowTreeTestApi(embedder_tree)
- .AckLastEvent(mojom::EventResult::UNHANDLED);
- }
-}
-
-} // namespace test
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_manager_window_tree_factory.cc b/chromium/components/mus/ws/window_manager_window_tree_factory.cc
deleted file mode 100644
index a851092bd48..00000000000
--- a/chromium/components/mus/ws/window_manager_window_tree_factory.cc
+++ /dev/null
@@ -1,64 +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 "components/mus/ws/window_manager_window_tree_factory.h"
-
-#include "base/bind.h"
-#include "components/mus/ws/window_manager_window_tree_factory_set.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_tree.h"
-
-namespace mus {
-namespace ws {
-
-WindowManagerWindowTreeFactory::WindowManagerWindowTreeFactory(
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set,
- const UserId& user_id,
- mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request)
- : window_manager_window_tree_factory_set_(
- window_manager_window_tree_factory_set),
- user_id_(user_id),
- binding_(this),
- window_tree_(nullptr) {
- if (request.is_pending())
- binding_.Bind(std::move(request));
-}
-
-WindowManagerWindowTreeFactory::~WindowManagerWindowTreeFactory() {}
-
-void WindowManagerWindowTreeFactory::CreateWindowTree(
- mojom::WindowTreeRequest window_tree_request,
- mojom::WindowTreeClientPtr window_tree_client) {
- // CreateWindowTree() can only be called once, so there is no reason to keep
- // the binding around.
- if (binding_.is_bound())
- binding_.Close();
-
- SetWindowTree(GetWindowServer()->CreateTreeForWindowManager(
- user_id_, std::move(window_tree_request), std::move(window_tree_client)));
-}
-
-WindowManagerWindowTreeFactory::WindowManagerWindowTreeFactory(
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set,
- const UserId& user_id)
- : window_manager_window_tree_factory_set_(
- window_manager_window_tree_factory_set),
- user_id_(user_id),
- binding_(this),
- window_tree_(nullptr) {}
-
-WindowServer* WindowManagerWindowTreeFactory::GetWindowServer() {
- return window_manager_window_tree_factory_set_->window_server();
-}
-
-void WindowManagerWindowTreeFactory::SetWindowTree(WindowTree* window_tree) {
- DCHECK(!window_tree_);
- window_tree_ = window_tree;
-
- window_manager_window_tree_factory_set_
- ->OnWindowManagerWindowTreeFactoryReady(this);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_manager_window_tree_factory.h b/chromium/components/mus/ws/window_manager_window_tree_factory.h
deleted file mode 100644
index 909e3391d7f..00000000000
--- a/chromium/components/mus/ws/window_manager_window_tree_factory.h
+++ /dev/null
@@ -1,68 +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 COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_H_
-#define COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_H_
-
-#include <stdint.h>
-
-#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
-#include "components/mus/ws/user_id.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace mus {
-namespace ws {
-
-class ServerWindow;
-class WindowManagerWindowTreeFactorySet;
-class WindowServer;
-class WindowTree;
-
-namespace test {
-class WindowManagerWindowTreeFactorySetTestApi;
-}
-
-// Implementation of mojom::WindowManagerWindowTreeFactory.
-class WindowManagerWindowTreeFactory
- : public mojom::WindowManagerWindowTreeFactory {
- public:
- WindowManagerWindowTreeFactory(
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set,
- const UserId& user_id,
- mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request);
- ~WindowManagerWindowTreeFactory() override;
-
- const UserId& user_id() const { return user_id_; }
-
- WindowTree* window_tree() { return window_tree_; }
-
- // mojom::WindowManagerWindowTreeFactory:
- void CreateWindowTree(mojom::WindowTreeRequest window_tree_request,
- mojom::WindowTreeClientPtr window_tree_client) override;
-
- private:
- friend class test::WindowManagerWindowTreeFactorySetTestApi;
-
- // Used by tests.
- WindowManagerWindowTreeFactory(WindowManagerWindowTreeFactorySet* registry,
- const UserId& user_id);
-
- WindowServer* GetWindowServer();
-
- void SetWindowTree(WindowTree* window_tree);
-
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set_;
- const UserId user_id_;
- mojo::Binding<mojom::WindowManagerWindowTreeFactory> binding_;
-
- // Owned by WindowServer.
- WindowTree* window_tree_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowTreeFactory);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_H_
diff --git a/chromium/components/mus/ws/window_manager_window_tree_factory_set.cc b/chromium/components/mus/ws/window_manager_window_tree_factory_set.cc
deleted file mode 100644
index 91d01a8ab47..00000000000
--- a/chromium/components/mus/ws/window_manager_window_tree_factory_set.cc
+++ /dev/null
@@ -1,99 +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 "components/mus/ws/window_manager_window_tree_factory_set.h"
-
-#include "components/mus/ws/user_id_tracker_observer.h"
-#include "components/mus/ws/window_manager_window_tree_factory.h"
-#include "components/mus/ws/window_manager_window_tree_factory_set_observer.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_tree.h"
-
-namespace mus {
-namespace ws {
-
-WindowManagerWindowTreeFactorySet::WindowManagerWindowTreeFactorySet(
- WindowServer* window_server,
- UserIdTracker* id_tracker)
- : id_tracker_(id_tracker), window_server_(window_server) {
- id_tracker_->AddObserver(this);
-}
-
-WindowManagerWindowTreeFactorySet::~WindowManagerWindowTreeFactorySet() {
- id_tracker_->RemoveObserver(this);
-}
-
-WindowManagerWindowTreeFactory* WindowManagerWindowTreeFactorySet::Add(
- const UserId& user_id,
- mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request) {
- if (factories_.count(user_id)) {
- DVLOG(1) << "can only have one factory per user";
- return nullptr;
- }
-
- std::unique_ptr<WindowManagerWindowTreeFactory> factory_ptr(
- new WindowManagerWindowTreeFactory(this, user_id, std::move(request)));
- WindowManagerWindowTreeFactory* factory = factory_ptr.get();
- factories_[user_id] = std::move(factory_ptr);
- return factory;
-}
-
-WindowManagerState*
-WindowManagerWindowTreeFactorySet::GetWindowManagerStateForUser(
- const UserId& user_id) {
- auto it = factories_.find(user_id);
- if (it == factories_.end())
- return nullptr;
- return it->second->window_tree()
- ? it->second->window_tree()->window_manager_state()
- : nullptr;
-}
-
-void WindowManagerWindowTreeFactorySet::DeleteFactoryAssociatedWithTree(
- WindowTree* window_tree) {
- for (auto it = factories_.begin(); it != factories_.end(); ++it) {
- if (it->second->window_tree() == window_tree) {
- factories_.erase(it);
- return;
- }
- }
-}
-
-std::vector<WindowManagerWindowTreeFactory*>
-WindowManagerWindowTreeFactorySet::GetFactories() {
- std::vector<WindowManagerWindowTreeFactory*> result;
- for (auto& pair : factories_)
- result.push_back(pair.second.get());
- return result;
-}
-
-void WindowManagerWindowTreeFactorySet::AddObserver(
- WindowManagerWindowTreeFactorySetObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void WindowManagerWindowTreeFactorySet::RemoveObserver(
- WindowManagerWindowTreeFactorySetObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void WindowManagerWindowTreeFactorySet::OnWindowManagerWindowTreeFactoryReady(
- WindowManagerWindowTreeFactory* factory) {
- const bool is_first_valid_factory = !got_valid_factory_;
- got_valid_factory_ = true;
- FOR_EACH_OBSERVER(WindowManagerWindowTreeFactorySetObserver, observers_,
- OnWindowManagerWindowTreeFactoryReady(factory));
-
- // Notify after other observers as WindowServer triggers other
- // observers being added, which will have already processed the add.
- if (is_first_valid_factory)
- window_server_->OnFirstWindowManagerWindowTreeFactoryReady();
-}
-
-void WindowManagerWindowTreeFactorySet::OnUserIdRemoved(const UserId& id) {
- factories_.erase(id);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_manager_window_tree_factory_set.h b/chromium/components/mus/ws/window_manager_window_tree_factory_set.h
deleted file mode 100644
index a118e6978bc..00000000000
--- a/chromium/components/mus/ws/window_manager_window_tree_factory_set.h
+++ /dev/null
@@ -1,93 +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 COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_H_
-#define COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
-#include "components/mus/ws/user_id_tracker_observer.h"
-
-namespace mus {
-namespace ws {
-
-class UserIdTracker;
-class WindowManagerState;
-class WindowManagerWindowTreeFactory;
-class WindowManagerWindowTreeFactorySetObserver;
-class WindowServer;
-class WindowTree;
-
-namespace test {
-class WindowManagerWindowTreeFactorySetTestApi;
-}
-
-// WindowManagerWindowTreeFactorySet tracks the set of registered
-// WindowManagerWindowTreeHostFactories.
-class WindowManagerWindowTreeFactorySet : public UserIdTrackerObserver {
- public:
- WindowManagerWindowTreeFactorySet(WindowServer* window_server,
- UserIdTracker* tracker);
- ~WindowManagerWindowTreeFactorySet() override;
-
- WindowServer* window_server() { return window_server_; }
-
- // Creates a new WindowManagerWindowTreeFactory for the specified user,
- // unless one has been set, in which case the call is ignored. The newly
- // created WindowManagerWindowTreeFactory does not immediately have a
- // WindowTree associated with it.
- WindowManagerWindowTreeFactory* Add(
- const UserId& user_id,
- mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request);
-
- // Returns the WindowManagerState for the specified user, or null if
- // not yet set.
- WindowManagerState* GetWindowManagerStateForUser(const UserId& user_id);
-
- // Deletes the WindowManagerWindowTreeFactory associated with |tree|. Does
- // nothing if there is no WindowManagerWindowTreeFactory associated with
- // |tree|.
- void DeleteFactoryAssociatedWithTree(WindowTree* tree);
-
- // Returns all the factories, even those that may not have a WindowTree
- // associated with them.
- std::vector<WindowManagerWindowTreeFactory*> GetFactories();
-
- void AddObserver(WindowManagerWindowTreeFactorySetObserver* observer);
- void RemoveObserver(WindowManagerWindowTreeFactorySetObserver* observer);
-
- private:
- friend class WindowManagerWindowTreeFactory;
- friend class test::WindowManagerWindowTreeFactorySetTestApi;
-
- // Called by WindowManagerWindowTreeFactory when CreateWindowTree() has
- // been called.
- void OnWindowManagerWindowTreeFactoryReady(
- WindowManagerWindowTreeFactory* factory);
-
- // UserIdTrackerObserver:
- void OnUserIdRemoved(const UserId& id) override;
-
- // Set to true the first time a valid factory has been found.
- bool got_valid_factory_ = false;
- UserIdTracker* id_tracker_;
- WindowServer* window_server_;
-
- std::map<UserId, std::unique_ptr<WindowManagerWindowTreeFactory>> factories_;
-
- base::ObserverList<WindowManagerWindowTreeFactorySetObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowTreeFactorySet);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_H_
diff --git a/chromium/components/mus/ws/window_manager_window_tree_factory_set_observer.h b/chromium/components/mus/ws/window_manager_window_tree_factory_set_observer.h
deleted file mode 100644
index dd5f876d839..00000000000
--- a/chromium/components/mus/ws/window_manager_window_tree_factory_set_observer.h
+++ /dev/null
@@ -1,26 +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 COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_OBSERVER_H_
-#define COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_OBSERVER_H_
-
-namespace mus {
-namespace ws {
-
-class WindowManagerWindowTreeFactory;
-
-class WindowManagerWindowTreeFactorySetObserver {
- public:
- // Called when the WindowTree associated with |factory| has been set
- virtual void OnWindowManagerWindowTreeFactoryReady(
- WindowManagerWindowTreeFactory* factory) = 0;
-
- protected:
- virtual ~WindowManagerWindowTreeFactorySetObserver() {}
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_OBSERVER_H_
diff --git a/chromium/components/mus/ws/window_server.cc b/chromium/components/mus/ws/window_server.cc
deleted file mode 100644
index 77ef0e2595c..00000000000
--- a/chromium/components/mus/ws/window_server.cc
+++ /dev/null
@@ -1,707 +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 "components/mus/ws/window_server.h"
-
-#include <set>
-#include <string>
-
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/display_binding.h"
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/operation.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/user_activity_monitor.h"
-#include "components/mus/ws/window_coordinate_conversions.h"
-#include "components/mus/ws/window_manager_access_policy.h"
-#include "components/mus/ws/window_manager_display_root.h"
-#include "components/mus/ws/window_manager_state.h"
-#include "components/mus/ws/window_manager_window_tree_factory.h"
-#include "components/mus/ws/window_server_delegate.h"
-#include "components/mus/ws/window_tree.h"
-#include "components/mus/ws/window_tree_binding.h"
-#include "services/shell/public/cpp/connection.h"
-#include "ui/gfx/geometry/size_conversions.h"
-
-namespace mus {
-namespace ws {
-
-WindowServer::WindowServer(
- WindowServerDelegate* delegate,
- const scoped_refptr<mus::SurfacesState>& surfaces_state)
- : delegate_(delegate),
- surfaces_state_(surfaces_state),
- next_client_id_(1),
- display_manager_(new DisplayManager(this, &user_id_tracker_)),
- current_operation_(nullptr),
- in_destructor_(false),
- next_wm_change_id_(0),
- window_manager_window_tree_factory_set_(this, &user_id_tracker_) {
- user_id_tracker_.AddObserver(this);
- OnUserIdAdded(user_id_tracker_.active_id());
-}
-
-WindowServer::~WindowServer() {
- in_destructor_ = true;
-
- // Destroys the window trees results in querying for the display. Tear down
- // the displays first so that the trees are notified of the display going
- // away while the display is still valid.
- display_manager_->DestroyAllDisplays();
-
- while (!tree_map_.empty())
- DestroyTree(tree_map_.begin()->second.get());
-
- display_manager_.reset();
-}
-
-ServerWindow* WindowServer::CreateServerWindow(
- const WindowId& id,
- const std::map<std::string, std::vector<uint8_t>>& properties) {
- ServerWindow* window = new ServerWindow(this, id, properties);
- window->AddObserver(this);
- return window;
-}
-
-ClientSpecificId WindowServer::GetAndAdvanceNextClientId() {
- const ClientSpecificId id = next_client_id_++;
- DCHECK_LT(id, next_client_id_);
- return id;
-}
-
-WindowTree* WindowServer::EmbedAtWindow(
- ServerWindow* root,
- const UserId& user_id,
- mojom::WindowTreeClientPtr client,
- uint32_t flags,
- std::unique_ptr<AccessPolicy> access_policy) {
- std::unique_ptr<WindowTree> tree_ptr(
- new WindowTree(this, user_id, root, std::move(access_policy)));
- WindowTree* tree = tree_ptr.get();
- if (flags & mojom::kEmbedFlagEmbedderInterceptsEvents)
- tree->set_embedder_intercepts_events();
-
- mojom::WindowTreePtr window_tree_ptr;
- mojom::WindowTreeRequest window_tree_request = GetProxy(&window_tree_ptr);
- std::unique_ptr<WindowTreeBinding> binding =
- delegate_->CreateWindowTreeBinding(
- WindowServerDelegate::BindingType::EMBED, this, tree,
- &window_tree_request, &client);
- if (!binding) {
- binding.reset(new ws::DefaultWindowTreeBinding(
- tree, this, std::move(window_tree_request), std::move(client)));
- }
-
- AddTree(std::move(tree_ptr), std::move(binding), std::move(window_tree_ptr));
- OnTreeMessagedClient(tree->id());
- return tree;
-}
-
-void WindowServer::AddTree(std::unique_ptr<WindowTree> tree_impl_ptr,
- std::unique_ptr<WindowTreeBinding> binding,
- mojom::WindowTreePtr tree_ptr) {
- CHECK_EQ(0u, tree_map_.count(tree_impl_ptr->id()));
- WindowTree* tree = tree_impl_ptr.get();
- tree_map_[tree->id()] = std::move(tree_impl_ptr);
- tree->Init(std::move(binding), std::move(tree_ptr));
-}
-
-WindowTree* WindowServer::CreateTreeForWindowManager(
- const UserId& user_id,
- mojom::WindowTreeRequest window_tree_request,
- mojom::WindowTreeClientPtr window_tree_client) {
- std::unique_ptr<WindowTree> window_tree(new WindowTree(
- this, user_id, nullptr, base::WrapUnique(new WindowManagerAccessPolicy)));
- std::unique_ptr<WindowTreeBinding> window_tree_binding =
- delegate_->CreateWindowTreeBinding(
- WindowServerDelegate::BindingType::WINDOW_MANAGER, this,
- window_tree.get(), &window_tree_request, &window_tree_client);
- if (!window_tree_binding) {
- window_tree_binding.reset(new DefaultWindowTreeBinding(
- window_tree.get(), this, std::move(window_tree_request),
- std::move(window_tree_client)));
- }
- WindowTree* window_tree_ptr = window_tree.get();
- AddTree(std::move(window_tree), std::move(window_tree_binding), nullptr);
- window_tree_ptr->ConfigureWindowManager();
- return window_tree_ptr;
-}
-
-void WindowServer::DestroyTree(WindowTree* tree) {
- std::unique_ptr<WindowTree> tree_ptr;
- {
- auto iter = tree_map_.find(tree->id());
- DCHECK(iter != tree_map_.end());
- tree_ptr = std::move(iter->second);
- tree_map_.erase(iter);
- }
-
- // Notify remaining connections so that they can cleanup.
- for (auto& pair : tree_map_)
- pair.second->OnWindowDestroyingTreeImpl(tree);
-
- // Notify the hosts, taking care to only notify each host once.
- std::set<Display*> displays_notified;
- for (auto* root : tree->roots()) {
- // WindowTree holds its roots as a const, which is right as WindowTree
- // doesn't need to modify the window. OTOH we do. We could look up the
- // window using the id to get non-const version, but instead we cast.
- Display* display =
- display_manager_->GetDisplayContaining(const_cast<ServerWindow*>(root));
- if (display && displays_notified.count(display) == 0) {
- display->OnWillDestroyTree(tree);
- displays_notified.insert(display);
- }
- }
-
- window_manager_window_tree_factory_set_.DeleteFactoryAssociatedWithTree(tree);
-
- // Remove any requests from the client that resulted in a call to the window
- // manager and we haven't gotten a response back yet.
- std::set<uint32_t> to_remove;
- for (auto& pair : in_flight_wm_change_map_) {
- if (pair.second.client_id == tree->id())
- to_remove.insert(pair.first);
- }
- for (uint32_t id : to_remove)
- in_flight_wm_change_map_.erase(id);
-}
-
-WindowTree* WindowServer::GetTreeWithId(ClientSpecificId client_id) {
- auto iter = tree_map_.find(client_id);
- return iter == tree_map_.end() ? nullptr : iter->second.get();
-}
-
-WindowTree* WindowServer::GetTreeWithClientName(
- const std::string& client_name) {
- for (const auto& entry : tree_map_) {
- if (entry.second->name() == client_name)
- return entry.second.get();
- }
- return nullptr;
-}
-
-ServerWindow* WindowServer::GetWindow(const WindowId& id) {
- // kInvalidClientId is used for Display and WindowManager nodes.
- if (id.client_id == kInvalidClientId) {
- for (Display* display : display_manager_->displays()) {
- ServerWindow* window = display->GetRootWithId(id);
- if (window)
- return window;
- }
- }
- WindowTree* tree = GetTreeWithId(id.client_id);
- return tree ? tree->GetWindow(id) : nullptr;
-}
-
-void WindowServer::SchedulePaint(ServerWindow* window,
- const gfx::Rect& bounds) {
- Display* display = display_manager_->GetDisplayContaining(window);
- if (display)
- display->SchedulePaint(window, bounds);
-}
-
-void WindowServer::OnTreeMessagedClient(ClientSpecificId id) {
- if (current_operation_)
- current_operation_->MarkTreeAsMessaged(id);
-}
-
-bool WindowServer::DidTreeMessageClient(ClientSpecificId id) const {
- return current_operation_ && current_operation_->DidMessageTree(id);
-}
-
-const WindowTree* WindowServer::GetTreeWithRoot(
- const ServerWindow* window) const {
- if (!window)
- return nullptr;
- for (auto& pair : tree_map_) {
- if (pair.second->HasRoot(window))
- return pair.second.get();
- }
- return nullptr;
-}
-
-void WindowServer::OnFirstWindowManagerWindowTreeFactoryReady() {
- if (display_manager_->has_active_or_pending_displays())
- return;
-
- // We've been supplied a WindowManagerFactory and no displays have been
- // created yet. Treat this as a signal to create a Display.
- // TODO(sky): we need a better way to determine this, most likely a switch.
- delegate_->CreateDefaultDisplays();
-}
-
-UserActivityMonitor* WindowServer::GetUserActivityMonitorForUser(
- const UserId& user_id) {
- DCHECK_GT(activity_monitor_map_.count(user_id), 0u);
- return activity_monitor_map_[user_id].get();
-}
-
-bool WindowServer::SetFocusedWindow(ServerWindow* window) {
- // TODO(sky): this should fail if there is modal dialog active and |window|
- // is outside that.
- ServerWindow* currently_focused = GetFocusedWindow();
- Display* focused_display =
- currently_focused
- ? display_manager_->GetDisplayContaining(currently_focused)
- : nullptr;
- if (!window)
- return focused_display ? focused_display->SetFocusedWindow(nullptr) : true;
-
- Display* display = display_manager_->GetDisplayContaining(window);
- DCHECK(display); // It's assumed callers do validation before calling this.
- const bool result = display->SetFocusedWindow(window);
- // If the focus actually changed, and focus was in another display, then we
- // need to notify the previously focused display so that it cleans up state
- // and notifies appropriately.
- if (result && display->GetFocusedWindow() && display != focused_display &&
- focused_display) {
- const bool cleared_focus = focused_display->SetFocusedWindow(nullptr);
- DCHECK(cleared_focus);
- }
- return result;
-}
-
-ServerWindow* WindowServer::GetFocusedWindow() {
- for (Display* display : display_manager_->displays()) {
- ServerWindow* focused_window = display->GetFocusedWindow();
- if (focused_window)
- return focused_window;
- }
- return nullptr;
-}
-
-uint32_t WindowServer::GenerateWindowManagerChangeId(
- WindowTree* source,
- uint32_t client_change_id) {
- const uint32_t wm_change_id = next_wm_change_id_++;
- in_flight_wm_change_map_[wm_change_id] = {source->id(), client_change_id};
- return wm_change_id;
-}
-
-void WindowServer::WindowManagerChangeCompleted(
- uint32_t window_manager_change_id,
- bool success) {
- InFlightWindowManagerChange change;
- if (!GetAndClearInFlightWindowManagerChange(window_manager_change_id,
- &change)) {
- return;
- }
-
- WindowTree* tree = GetTreeWithId(change.client_id);
- tree->OnChangeCompleted(change.client_change_id, success);
-}
-
-void WindowServer::WindowManagerCreatedTopLevelWindow(
- WindowTree* wm_tree,
- uint32_t window_manager_change_id,
- const ServerWindow* window) {
- InFlightWindowManagerChange change;
- if (!GetAndClearInFlightWindowManagerChange(window_manager_change_id,
- &change)) {
- return;
- }
- if (!window) {
- WindowManagerSentBogusMessage();
- return;
- }
-
- WindowTree* tree = GetTreeWithId(change.client_id);
- // The window manager should have created the window already, and it should
- // be ready for embedding.
- if (!tree->IsWaitingForNewTopLevelWindow(window_manager_change_id) ||
- !window || window->id().client_id != wm_tree->id() ||
- !window->children().empty() || GetTreeWithRoot(window)) {
- WindowManagerSentBogusMessage();
- return;
- }
-
- tree->OnWindowManagerCreatedTopLevelWindow(window_manager_change_id,
- change.client_change_id, window);
-}
-
-void WindowServer::ProcessWindowBoundsChanged(const ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- for (auto& pair : tree_map_) {
- pair.second->ProcessWindowBoundsChanged(window, old_bounds, new_bounds,
- IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::ProcessClientAreaChanged(
- const ServerWindow* window,
- const gfx::Insets& new_client_area,
- const std::vector<gfx::Rect>& new_additional_client_areas) {
- for (auto& pair : tree_map_) {
- pair.second->ProcessClientAreaChanged(window, new_client_area,
- new_additional_client_areas,
- IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::ProcessLostCapture(const ServerWindow* window) {
- for (auto& pair : tree_map_)
- pair.second->ProcessLostCapture(window, IsOperationSource(pair.first));
-}
-
-void WindowServer::ProcessWillChangeWindowHierarchy(
- const ServerWindow* window,
- const ServerWindow* new_parent,
- const ServerWindow* old_parent) {
- for (auto& pair : tree_map_) {
- pair.second->ProcessWillChangeWindowHierarchy(
- window, new_parent, old_parent, IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::ProcessWindowHierarchyChanged(
- const ServerWindow* window,
- const ServerWindow* new_parent,
- const ServerWindow* old_parent) {
- for (auto& pair : tree_map_) {
- pair.second->ProcessWindowHierarchyChanged(window, new_parent, old_parent,
- IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::ProcessWindowReorder(const ServerWindow* window,
- const ServerWindow* relative_window,
- const mojom::OrderDirection direction) {
- // We'll probably do a bit of reshuffling when we add a transient window.
- if ((current_operation_type() == OperationType::ADD_TRANSIENT_WINDOW) ||
- (current_operation_type() ==
- OperationType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT)) {
- return;
- }
- for (auto& pair : tree_map_) {
- pair.second->ProcessWindowReorder(window, relative_window, direction,
- IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::ProcessWindowDeleted(const ServerWindow* window) {
- for (auto& pair : tree_map_)
- pair.second->ProcessWindowDeleted(window, IsOperationSource(pair.first));
-}
-
-void WindowServer::ProcessWillChangeWindowPredefinedCursor(ServerWindow* window,
- int32_t cursor_id) {
- for (auto& pair : tree_map_) {
- pair.second->ProcessCursorChanged(window, cursor_id,
- IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::SendToEventObservers(const ui::Event& event,
- const UserId& user_id,
- WindowTree* ignore_tree) {
- for (auto& pair : tree_map_) {
- WindowTree* tree = pair.second.get();
- if (tree->user_id() == user_id && tree != ignore_tree)
- tree->SendToEventObserver(event);
- }
-}
-
-void WindowServer::SetPaintCallback(
- const base::Callback<void(ServerWindow*)>& callback) {
- DCHECK(delegate_->IsTestConfig()) << "Paint callbacks are expensive, and "
- << "allowed only in tests.";
- DCHECK(window_paint_callback_.is_null() || callback.is_null());
- window_paint_callback_ = callback;
-}
-
-bool WindowServer::GetAndClearInFlightWindowManagerChange(
- uint32_t window_manager_change_id,
- InFlightWindowManagerChange* change) {
- // There are valid reasons as to why we wouldn't know about the id. The
- // most likely is the client disconnected before the response from the window
- // manager came back.
- auto iter = in_flight_wm_change_map_.find(window_manager_change_id);
- if (iter == in_flight_wm_change_map_.end())
- return false;
-
- *change = iter->second;
- in_flight_wm_change_map_.erase(iter);
- return true;
-}
-
-void WindowServer::PrepareForOperation(Operation* op) {
- // Should only ever have one change in flight.
- CHECK(!current_operation_);
- current_operation_ = op;
-}
-
-void WindowServer::FinishOperation() {
- // PrepareForOperation/FinishOperation should be balanced.
- CHECK(current_operation_);
- current_operation_ = nullptr;
-}
-
-void WindowServer::UpdateNativeCursorFromMouseLocation(ServerWindow* window) {
- WindowManagerDisplayRoot* display_root =
- display_manager_->GetWindowManagerDisplayRoot(window);
- if (display_root) {
- EventDispatcher* event_dispatcher =
- display_root->window_manager_state()->event_dispatcher();
- event_dispatcher->UpdateCursorProviderByLastKnownLocation();
- int32_t cursor_id = 0;
- if (event_dispatcher->GetCurrentMouseCursor(&cursor_id))
- display_root->display()->UpdateNativeCursor(cursor_id);
- }
-}
-
-void WindowServer::UpdateNativeCursorIfOver(ServerWindow* window) {
- WindowManagerDisplayRoot* display_root =
- display_manager_->GetWindowManagerDisplayRoot(window);
- if (!display_root)
- return;
-
- EventDispatcher* event_dispatcher =
- display_root->window_manager_state()->event_dispatcher();
- if (window != event_dispatcher->mouse_cursor_source_window())
- return;
-
- event_dispatcher->UpdateNonClientAreaForCurrentWindow();
- int32_t cursor_id = 0;
- if (event_dispatcher->GetCurrentMouseCursor(&cursor_id))
- display_root->display()->UpdateNativeCursor(cursor_id);
-}
-
-mus::SurfacesState* WindowServer::GetSurfacesState() {
- return surfaces_state_.get();
-}
-
-void WindowServer::OnScheduleWindowPaint(ServerWindow* window) {
- if (in_destructor_)
- return;
-
- SchedulePaint(window, gfx::Rect(window->bounds().size()));
- if (!window_paint_callback_.is_null())
- window_paint_callback_.Run(window);
-}
-
-const ServerWindow* WindowServer::GetRootWindow(
- const ServerWindow* window) const {
- const Display* display = display_manager_->GetDisplayContaining(window);
- return display ? display->root_window() : nullptr;
-}
-
-void WindowServer::ScheduleSurfaceDestruction(ServerWindow* window) {
- Display* display = display_manager_->GetDisplayContaining(window);
- if (display)
- display->ScheduleSurfaceDestruction(window);
-}
-
-void WindowServer::OnWindowDestroyed(ServerWindow* window) {
- ProcessWindowDeleted(window);
-}
-
-void WindowServer::OnWillChangeWindowHierarchy(ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) {
- if (in_destructor_)
- return;
-
- ProcessWillChangeWindowHierarchy(window, new_parent, old_parent);
-}
-
-void WindowServer::OnWindowHierarchyChanged(ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) {
- if (in_destructor_)
- return;
-
- WindowManagerDisplayRoot* display_root =
- display_manager_->GetWindowManagerDisplayRoot(window);
- if (display_root)
- display_root->window_manager_state()
- ->ReleaseCaptureBlockedByAnyModalWindow();
-
- ProcessWindowHierarchyChanged(window, new_parent, old_parent);
-
- // TODO(beng): optimize.
- if (old_parent)
- SchedulePaint(old_parent, gfx::Rect(old_parent->bounds().size()));
- if (new_parent)
- SchedulePaint(new_parent, gfx::Rect(new_parent->bounds().size()));
-
- UpdateNativeCursorFromMouseLocation(window);
-}
-
-void WindowServer::OnWindowBoundsChanged(ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
- if (in_destructor_)
- return;
-
- ProcessWindowBoundsChanged(window, old_bounds, new_bounds);
- if (!window->parent())
- return;
-
- SchedulePaint(window->parent(), old_bounds);
- SchedulePaint(window->parent(), new_bounds);
-
- UpdateNativeCursorFromMouseLocation(window);
-}
-
-void WindowServer::OnWindowClientAreaChanged(
- ServerWindow* window,
- const gfx::Insets& new_client_area,
- const std::vector<gfx::Rect>& new_additional_client_areas) {
- if (in_destructor_)
- return;
-
- ProcessClientAreaChanged(window, new_client_area,
- new_additional_client_areas);
-
- UpdateNativeCursorIfOver(window);
-}
-
-void WindowServer::OnWindowReordered(ServerWindow* window,
- ServerWindow* relative,
- mojom::OrderDirection direction) {
- ProcessWindowReorder(window, relative, direction);
- if (!in_destructor_)
- SchedulePaint(window, gfx::Rect(window->bounds().size()));
- UpdateNativeCursorFromMouseLocation(window);
-}
-
-void WindowServer::OnWillChangeWindowVisibility(ServerWindow* window) {
- if (in_destructor_)
- return;
-
- // Need to repaint if the window was drawn (which means it's in the process of
- // hiding) or the window is transitioning to drawn.
- if (window->parent() &&
- (window->IsDrawn() ||
- (!window->visible() && window->parent()->IsDrawn()))) {
- SchedulePaint(window->parent(), window->bounds());
- }
-
- for (auto& pair : tree_map_) {
- pair.second->ProcessWillChangeWindowVisibility(
- window, IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::OnWindowOpacityChanged(ServerWindow* window,
- float old_opacity,
- float new_opacity) {
- DCHECK(!in_destructor_);
-
- for (auto& pair : tree_map_) {
- pair.second->ProcessWindowOpacityChanged(window, old_opacity, new_opacity,
- IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::OnWindowVisibilityChanged(ServerWindow* window) {
- if (in_destructor_)
- return;
-
- WindowManagerDisplayRoot* display_root =
- display_manager_->GetWindowManagerDisplayRoot(window);
- if (display_root)
- display_root->window_manager_state()->ReleaseCaptureBlockedByModalWindow(
- window);
-}
-
-void WindowServer::OnWindowPredefinedCursorChanged(ServerWindow* window,
- int32_t cursor_id) {
- if (in_destructor_)
- return;
-
- ProcessWillChangeWindowPredefinedCursor(window, cursor_id);
-
- UpdateNativeCursorIfOver(window);
-}
-
-void WindowServer::OnWindowNonClientCursorChanged(ServerWindow* window,
- int32_t cursor_id) {
- if (in_destructor_)
- return;
-
- UpdateNativeCursorIfOver(window);
-}
-
-void WindowServer::OnWindowSharedPropertyChanged(
- ServerWindow* window,
- const std::string& name,
- const std::vector<uint8_t>* new_data) {
- for (auto& pair : tree_map_) {
- pair.second->ProcessWindowPropertyChanged(window, name, new_data,
- IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::OnWindowTextInputStateChanged(
- ServerWindow* window,
- const ui::TextInputState& state) {
- Display* display = display_manager_->GetDisplayContaining(window);
- display->UpdateTextInputState(window, state);
-}
-
-void WindowServer::OnTransientWindowAdded(ServerWindow* window,
- ServerWindow* transient_child) {
- for (auto& pair : tree_map_) {
- pair.second->ProcessTransientWindowAdded(window, transient_child,
- IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::OnTransientWindowRemoved(ServerWindow* window,
- ServerWindow* transient_child) {
- // If we're deleting a window, then this is a superfluous message.
- if (current_operation_type() == OperationType::DELETE_WINDOW)
- return;
- for (auto& pair : tree_map_) {
- pair.second->ProcessTransientWindowRemoved(window, transient_child,
- IsOperationSource(pair.first));
- }
-}
-
-void WindowServer::OnFirstDisplayReady() {
- delegate_->OnFirstDisplayReady();
-}
-
-void WindowServer::OnNoMoreDisplays() {
- delegate_->OnNoMoreDisplays();
-}
-
-bool WindowServer::GetFrameDecorationsForUser(
- const UserId& user_id,
- mojom::FrameDecorationValuesPtr* values) {
- WindowManagerState* window_manager_state =
- window_manager_window_tree_factory_set_.GetWindowManagerStateForUser(
- user_id);
- if (!window_manager_state)
- return false;
- if (values && window_manager_state->got_frame_decoration_values())
- *values = window_manager_state->frame_decoration_values().Clone();
- return window_manager_state->got_frame_decoration_values();
-}
-
-WindowManagerState* WindowServer::GetWindowManagerStateForUser(
- const UserId& user_id) {
- return window_manager_window_tree_factory_set_.GetWindowManagerStateForUser(
- user_id);
-}
-
-void WindowServer::OnActiveUserIdChanged(const UserId& previously_active_id,
- const UserId& active_id) {}
-
-void WindowServer::OnUserIdAdded(const UserId& id) {
- activity_monitor_map_[id] = base::MakeUnique<UserActivityMonitor>(nullptr);
-}
-
-void WindowServer::OnUserIdRemoved(const UserId& id) {
- activity_monitor_map_.erase(id);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_server.h b/chromium/components/mus/ws/window_server.h
deleted file mode 100644
index 0ecbc76ee4c..00000000000
--- a/chromium/components/mus/ws/window_server.h
+++ /dev/null
@@ -1,342 +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 COMPONENTS_MUS_WS_WINDOW_SERVER_H_
-#define COMPONENTS_MUS_WS_WINDOW_SERVER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/public/interfaces/window_tree_host.mojom.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/display_manager_delegate.h"
-#include "components/mus/ws/ids.h"
-#include "components/mus/ws/operation.h"
-#include "components/mus/ws/server_window_delegate.h"
-#include "components/mus/ws/server_window_observer.h"
-#include "components/mus/ws/user_id_tracker.h"
-#include "components/mus/ws/user_id_tracker_observer.h"
-#include "components/mus/ws/window_manager_window_tree_factory_set.h"
-#include "mojo/public/cpp/bindings/array.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace mus {
-namespace ws {
-
-class AccessPolicy;
-class DisplayManager;
-class ServerWindow;
-class UserActivityMonitor;
-class WindowManagerState;
-class WindowServerDelegate;
-class WindowTree;
-class WindowTreeBinding;
-
-// WindowServer manages the set of clients of the window server (all the
-// WindowTrees) as well as providing the root of the hierarchy.
-class WindowServer : public ServerWindowDelegate,
- public ServerWindowObserver,
- public DisplayManagerDelegate,
- public UserIdTrackerObserver {
- public:
- WindowServer(WindowServerDelegate* delegate,
- const scoped_refptr<mus::SurfacesState>& surfaces_state);
- ~WindowServer() override;
-
- WindowServerDelegate* delegate() { return delegate_; }
-
- UserIdTracker* user_id_tracker() { return &user_id_tracker_; }
- const UserIdTracker* user_id_tracker() const { return &user_id_tracker_; }
-
- DisplayManager* display_manager() { return display_manager_.get(); }
- const DisplayManager* display_manager() const {
- return display_manager_.get();
- }
-
- // Creates a new ServerWindow. The return value is owned by the caller, but
- // must be destroyed before WindowServer.
- ServerWindow* CreateServerWindow(
- const WindowId& id,
- const std::map<std::string, std::vector<uint8_t>>& properties);
-
- // Returns the id for the next WindowTree.
- ClientSpecificId GetAndAdvanceNextClientId();
-
- // See description of WindowTree::Embed() for details. This assumes
- // |transport_window_id| is valid.
- WindowTree* EmbedAtWindow(ServerWindow* root,
- const UserId& user_id,
- mojom::WindowTreeClientPtr client,
- uint32_t flags,
- std::unique_ptr<AccessPolicy> access_policy);
-
- // Adds |tree_impl_ptr| to the set of known trees. Use DestroyTree() to
- // destroy the tree.
- void AddTree(std::unique_ptr<WindowTree> tree_impl_ptr,
- std::unique_ptr<WindowTreeBinding> binding,
- mojom::WindowTreePtr tree_ptr);
- WindowTree* CreateTreeForWindowManager(
- const UserId& user_id,
- mojom::WindowTreeRequest window_tree_request,
- mojom::WindowTreeClientPtr window_tree_client);
- // Invoked when a WindowTree's connection encounters an error.
- void DestroyTree(WindowTree* tree);
-
- // Returns the tree by client id.
- WindowTree* GetTreeWithId(ClientSpecificId client_id);
-
- WindowTree* GetTreeWithClientName(const std::string& client_name);
-
- size_t num_trees() const { return tree_map_.size(); }
-
- // Returns the Window identified by |id|.
- ServerWindow* GetWindow(const WindowId& id);
-
- // Schedules a paint for the specified region in the coordinates of |window|.
- void SchedulePaint(ServerWindow* window, const gfx::Rect& bounds);
-
- OperationType current_operation_type() const {
- return current_operation_ ? current_operation_->type()
- : OperationType::NONE;
- }
-
- // Returns true if the specified client issued the current operation.
- bool IsOperationSource(ClientSpecificId client_id) const {
- return current_operation_ &&
- current_operation_->source_tree_id() == client_id;
- }
-
- // Invoked when a client messages a client about the change. This is used
- // to avoid sending ServerChangeIdAdvanced() unnecessarily.
- void OnTreeMessagedClient(ClientSpecificId id);
-
- // Returns true if OnTreeMessagedClient() was invoked for id.
- bool DidTreeMessageClient(ClientSpecificId id) const;
-
- // Returns the WindowTree that has |id| as a root.
- WindowTree* GetTreeWithRoot(const ServerWindow* window) {
- return const_cast<WindowTree*>(
- const_cast<const WindowServer*>(this)->GetTreeWithRoot(window));
- }
- const WindowTree* GetTreeWithRoot(const ServerWindow* window) const;
-
- void OnFirstWindowManagerWindowTreeFactoryReady();
-
- UserActivityMonitor* GetUserActivityMonitorForUser(const UserId& user_id);
-
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set() {
- return &window_manager_window_tree_factory_set_;
- }
-
- // Sets focus to |window|. Returns true if |window| already has focus, or
- // focus was successfully changed. Returns |false| if |window| is not a valid
- // window to receive focus.
- bool SetFocusedWindow(ServerWindow* window);
- ServerWindow* GetFocusedWindow();
-
- // Returns a change id for the window manager that is associated with
- // |source| and |client_change_id|. When the window manager replies
- // WindowManagerChangeCompleted() is called to obtain the original source
- // and client supplied change_id that initiated the called.
- uint32_t GenerateWindowManagerChangeId(WindowTree* source,
- uint32_t client_change_id);
-
- // Called when a response from the window manager is obtained. Calls to
- // the client that initiated the change with the change id originally
- // supplied by the client.
- void WindowManagerChangeCompleted(uint32_t window_manager_change_id,
- bool success);
- void WindowManagerCreatedTopLevelWindow(WindowTree* wm_tree,
- uint32_t window_manager_change_id,
- const ServerWindow* window);
-
- // Called when we get an unexpected message from the WindowManager.
- // TODO(sky): decide what we want to do here.
- void WindowManagerSentBogusMessage() {}
-
- // These functions trivially delegate to all WindowTrees, which in
- // term notify their clients.
- void ProcessWindowBoundsChanged(const ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds);
- void ProcessClientAreaChanged(
- const ServerWindow* window,
- const gfx::Insets& new_client_area,
- const std::vector<gfx::Rect>& new_additional_client_areas);
- void ProcessLostCapture(const ServerWindow* window);
- void ProcessWillChangeWindowHierarchy(const ServerWindow* window,
- const ServerWindow* new_parent,
- const ServerWindow* old_parent);
- void ProcessWindowHierarchyChanged(const ServerWindow* window,
- const ServerWindow* new_parent,
- const ServerWindow* old_parent);
- void ProcessWindowReorder(const ServerWindow* window,
- const ServerWindow* relative_window,
- const mojom::OrderDirection direction);
- void ProcessWindowDeleted(const ServerWindow* window);
- void ProcessWillChangeWindowPredefinedCursor(ServerWindow* window,
- int32_t cursor_id);
-
- // Sends an |event| to all WindowTrees belonging to |user_id| that might be
- // observing events. Skips |ignore_tree| if it is non-null.
- void SendToEventObservers(const ui::Event& event,
- const UserId& user_id,
- WindowTree* ignore_tree);
-
- // Sets a callback to be called whenever a ServerWindow is scheduled for
- // a [re]paint. This should only be called in a test configuration.
- void SetPaintCallback(const base::Callback<void(ServerWindow*)>& callback);
-
- private:
- friend class Operation;
-
- using WindowTreeMap =
- std::map<ClientSpecificId, std::unique_ptr<WindowTree>>;
- using UserActivityMonitorMap =
- std::map<UserId, std::unique_ptr<UserActivityMonitor>>;
-
- struct InFlightWindowManagerChange {
- // Identifies the client that initiated the change.
- ClientSpecificId client_id;
-
- // Change id supplied by the client.
- uint32_t client_change_id;
- };
-
- using InFlightWindowManagerChangeMap =
- std::map<uint32_t, InFlightWindowManagerChange>;
-
- bool GetAndClearInFlightWindowManagerChange(
- uint32_t window_manager_change_id,
- InFlightWindowManagerChange* change);
-
- // Invoked when a client is about to execute a window server operation.
- // Subsequently followed by FinishOperation() once the change is done.
- //
- // Changes should never nest, meaning each PrepareForOperation() must be
- // balanced with a call to FinishOperation() with no PrepareForOperation()
- // in between.
- void PrepareForOperation(Operation* op);
-
- // Balances a call to PrepareForOperation().
- void FinishOperation();
-
- // Updates the native cursor by figuring out what window is under the mouse
- // cursor. This is run in response to events that change the bounds or window
- // hierarchy.
- void UpdateNativeCursorFromMouseLocation(ServerWindow* window);
-
- // Updates the native cursor if the cursor is currently inside |window|. This
- // is run in response to events that change the mouse cursor properties of
- // |window|.
- void UpdateNativeCursorIfOver(ServerWindow* window);
-
- // Overridden from ServerWindowDelegate:
- mus::SurfacesState* GetSurfacesState() override;
- void OnScheduleWindowPaint(ServerWindow* window) override;
- const ServerWindow* GetRootWindow(const ServerWindow* window) const override;
- void ScheduleSurfaceDestruction(ServerWindow* window) override;
-
- // Overridden from ServerWindowObserver:
- void OnWindowDestroyed(ServerWindow* window) override;
- void OnWillChangeWindowHierarchy(ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) override;
- void OnWindowHierarchyChanged(ServerWindow* window,
- ServerWindow* new_parent,
- ServerWindow* old_parent) override;
- void OnWindowBoundsChanged(ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) override;
- void OnWindowClientAreaChanged(
- ServerWindow* window,
- const gfx::Insets& new_client_area,
- const std::vector<gfx::Rect>& new_additional_client_areas) override;
- void OnWindowReordered(ServerWindow* window,
- ServerWindow* relative,
- mojom::OrderDirection direction) override;
- void OnWillChangeWindowVisibility(ServerWindow* window) override;
- void OnWindowVisibilityChanged(ServerWindow* window) override;
- void OnWindowOpacityChanged(ServerWindow* window,
- float old_opacity,
- float new_opacity) override;
- void OnWindowSharedPropertyChanged(
- ServerWindow* window,
- const std::string& name,
- const std::vector<uint8_t>* new_data) override;
- void OnWindowPredefinedCursorChanged(ServerWindow* window,
- int32_t cursor_id) override;
- void OnWindowNonClientCursorChanged(ServerWindow* window,
- int32_t cursor_id) override;
- void OnWindowTextInputStateChanged(ServerWindow* window,
- const ui::TextInputState& state) override;
- void OnTransientWindowAdded(ServerWindow* window,
- ServerWindow* transient_child) override;
- void OnTransientWindowRemoved(ServerWindow* window,
- ServerWindow* transient_child) override;
-
- // DisplayManagerDelegate:
- void OnFirstDisplayReady() override;
- void OnNoMoreDisplays() override;
- bool GetFrameDecorationsForUser(
- const UserId& user_id,
- mojom::FrameDecorationValuesPtr* values) override;
- WindowManagerState* GetWindowManagerStateForUser(
- const UserId& user_id) override;
-
- // UserIdTrackerObserver:
- void OnActiveUserIdChanged(const UserId& previously_active_id,
- const UserId& active_id) override;
- void OnUserIdAdded(const UserId& id) override;
- void OnUserIdRemoved(const UserId& id) override;
-
- UserIdTracker user_id_tracker_;
-
- WindowServerDelegate* delegate_;
-
- // State for rendering into a Surface.
- scoped_refptr<mus::SurfacesState> surfaces_state_;
-
- // ID to use for next WindowTree.
- ClientSpecificId next_client_id_;
-
- std::unique_ptr<DisplayManager> display_manager_;
-
- // Set of WindowTrees.
- WindowTreeMap tree_map_;
-
- // If non-null then we're processing a client operation. The Operation is
- // not owned by us (it's created on the stack by WindowTree).
- Operation* current_operation_;
-
- bool in_destructor_;
-
- // Maps from window manager change id to the client that initiated the
- // request.
- InFlightWindowManagerChangeMap in_flight_wm_change_map_;
-
- // Next id supplied to the window manager.
- uint32_t next_wm_change_id_;
-
- base::Callback<void(ServerWindow*)> window_paint_callback_;
-
- UserActivityMonitorMap activity_monitor_map_;
-
- WindowManagerWindowTreeFactorySet window_manager_window_tree_factory_set_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowServer);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_SERVER_H_
diff --git a/chromium/components/mus/ws/window_server_delegate.cc b/chromium/components/mus/ws/window_server_delegate.cc
deleted file mode 100644
index 1d9a1045f3c..00000000000
--- a/chromium/components/mus/ws/window_server_delegate.cc
+++ /dev/null
@@ -1,25 +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 "components/mus/ws/window_server_delegate.h"
-
-#include "components/mus/ws/window_tree_binding.h"
-
-namespace mus {
-namespace ws {
-
-void WindowServerDelegate::OnFirstDisplayReady() {}
-
-std::unique_ptr<WindowTreeBinding>
-WindowServerDelegate::CreateWindowTreeBinding(
- BindingType type,
- ws::WindowServer* window_server,
- ws::WindowTree* tree,
- mojom::WindowTreeRequest* tree_request,
- mojom::WindowTreeClientPtr* client) {
- return nullptr;
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_server_delegate.h b/chromium/components/mus/ws/window_server_delegate.h
deleted file mode 100644
index 62a8db4b07a..00000000000
--- a/chromium/components/mus/ws/window_server_delegate.h
+++ /dev/null
@@ -1,67 +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 COMPONENTS_MUS_WS_WINDOW_SERVER_DELEGATE_H_
-#define COMPONENTS_MUS_WS_WINDOW_SERVER_DELEGATE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "components/mus/common/types.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-
-namespace mus {
-
-namespace mojom {
-class Display;
-class WindowManagerFactory;
-class WindowTree;
-}
-
-namespace ws {
-
-class Display;
-class ServerWindow;
-class WindowServer;
-class WindowTree;
-class WindowTreeBinding;
-
-class WindowServerDelegate {
- public:
- enum BindingType {
- EMBED,
- WINDOW_MANAGER,
- };
-
- // Called if no Displays have been created, but a WindowManagerFactory has
- // been set.
- virtual void CreateDefaultDisplays() = 0;
-
- // Called once when the AcceleratedWidget of a Display is available.
- virtual void OnFirstDisplayReady();
-
- virtual void OnNoMoreDisplays() = 0;
-
- virtual bool IsTestConfig() const = 0;
-
- // Creates a WindowTreeBinding. Default implementation returns null, which
- // creates DefaultBinding.
- virtual std::unique_ptr<WindowTreeBinding> CreateWindowTreeBinding(
- BindingType type,
- ws::WindowServer* window_server,
- ws::WindowTree* tree,
- mojom::WindowTreeRequest* tree_request,
- mojom::WindowTreeClientPtr* client);
-
- protected:
- virtual ~WindowServerDelegate() {}
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_SERVER_DELEGATE_H_
diff --git a/chromium/components/mus/ws/window_server_test_impl.cc b/chromium/components/mus/ws/window_server_test_impl.cc
deleted file mode 100644
index a61eb2d2bc9..00000000000
--- a/chromium/components/mus/ws/window_server_test_impl.cc
+++ /dev/null
@@ -1,66 +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 "components/mus/ws/window_server_test_impl.h"
-
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_surface_manager.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_tree.h"
-
-namespace mus {
-namespace ws {
-
-namespace {
-
-bool WindowHasValidFrame(const ServerWindow* window) {
- const ServerWindowSurfaceManager* manager = window->surface_manager();
- return manager &&
- !manager->GetDefaultSurface()->last_submitted_frame_size().IsEmpty();
-}
-
-} // namespace
-
-WindowServerTestImpl::WindowServerTestImpl(
- WindowServer* window_server,
- mojo::InterfaceRequest<WindowServerTest> request)
- : window_server_(window_server), binding_(this, std::move(request)) {}
-
-WindowServerTestImpl::~WindowServerTestImpl() {}
-
-void WindowServerTestImpl::OnWindowPaint(
- const std::string& name,
- const EnsureClientHasDrawnWindowCallback& cb,
- ServerWindow* window) {
- WindowTree* tree = window_server_->GetTreeWithClientName(name);
- if (!tree)
- return;
- if (tree->HasRoot(window) && WindowHasValidFrame(window)) {
- cb.Run(true);
- window_server_->SetPaintCallback(base::Callback<void(ServerWindow*)>());
- }
-}
-
-void WindowServerTestImpl::EnsureClientHasDrawnWindow(
- const mojo::String& client_name,
- const EnsureClientHasDrawnWindowCallback& callback) {
- std::string name = client_name.To<std::string>();
- WindowTree* tree = window_server_->GetTreeWithClientName(name);
- if (tree) {
- for (const ServerWindow* window : tree->roots()) {
- if (WindowHasValidFrame(window)) {
- callback.Run(true);
- return;
- }
- }
- }
-
- window_server_->SetPaintCallback(
- base::Bind(&WindowServerTestImpl::OnWindowPaint, base::Unretained(this),
- name, std::move(callback)));
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_server_test_impl.h b/chromium/components/mus/ws/window_server_test_impl.h
deleted file mode 100644
index deacb773c61..00000000000
--- a/chromium/components/mus/ws/window_server_test_impl.h
+++ /dev/null
@@ -1,45 +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 COMPONENTS_MUS_WS_WINDOW_SERVER_TEST_IMPL_H_
-#define COMPONENTS_MUS_WS_WINDOW_SERVER_TEST_IMPL_H_
-
-#include "components/mus/public/interfaces/window_server_test.mojom.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace mus {
-namespace ws {
-
-class ServerWindow;
-class WindowServer;
-class WindowTree;
-struct WindowId;
-
-class WindowServerTestImpl : public mojom::WindowServerTest {
- public:
- WindowServerTestImpl(WindowServer* server,
- mojo::InterfaceRequest<WindowServerTest> request);
-
- private:
- ~WindowServerTestImpl() override;
-
- void OnWindowPaint(const std::string& name,
- const EnsureClientHasDrawnWindowCallback& cb,
- ServerWindow* window);
-
- // mojom::WindowServerTest:
- void EnsureClientHasDrawnWindow(
- const mojo::String& client_name,
- const EnsureClientHasDrawnWindowCallback& callback) override;
-
- WindowServer* window_server_;
- mojo::StrongBinding<WindowServerTest> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowServerTestImpl);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_SERVER_TEST_IMPL_H_
diff --git a/chromium/components/mus/ws/window_tree.cc b/chromium/components/mus/ws/window_tree.cc
deleted file mode 100644
index aafdfce96ec..00000000000
--- a/chromium/components/mus/ws/window_tree.cc
+++ /dev/null
@@ -1,1539 +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 "components/mus/ws/window_tree.h"
-
-#include <stddef.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
-#include "components/mus/ws/default_access_policy.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/display_manager.h"
-#include "components/mus/ws/event_matcher.h"
-#include "components/mus/ws/focus_controller.h"
-#include "components/mus/ws/operation.h"
-#include "components/mus/ws/platform_display.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_observer.h"
-#include "components/mus/ws/user_display_manager.h"
-#include "components/mus/ws/window_manager_display_root.h"
-#include "components/mus/ws/window_manager_state.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_tree_binding.h"
-#include "ui/display/display.h"
-#include "ui/platform_window/mojo/ime_type_converters.h"
-#include "ui/platform_window/text_input_state.h"
-
-using mojo::Array;
-using mojo::InterfaceRequest;
-using mojo::String;
-
-namespace mus {
-namespace ws {
-
-class TargetedEvent : public ServerWindowObserver {
- public:
- TargetedEvent(ServerWindow* target, const ui::Event& event)
- : target_(target), event_(ui::Event::Clone(event)) {
- target_->AddObserver(this);
- }
- ~TargetedEvent() override {
- if (target_)
- target_->RemoveObserver(this);
- }
-
- ServerWindow* target() { return target_; }
- std::unique_ptr<ui::Event> TakeEvent() { return std::move(event_); }
-
- private:
- // ServerWindowObserver:
- void OnWindowDestroyed(ServerWindow* window) override {
- DCHECK_EQ(target_, window);
- target_->RemoveObserver(this);
- target_ = nullptr;
- }
-
- ServerWindow* target_;
- std::unique_ptr<ui::Event> event_;
-
- DISALLOW_COPY_AND_ASSIGN(TargetedEvent);
-};
-
-WindowTree::WindowTree(WindowServer* window_server,
- const UserId& user_id,
- ServerWindow* root,
- std::unique_ptr<AccessPolicy> access_policy)
- : window_server_(window_server),
- user_id_(user_id),
- id_(window_server_->GetAndAdvanceNextClientId()),
- next_window_id_(1),
- access_policy_(std::move(access_policy)),
- event_ack_id_(0),
- window_manager_internal_(nullptr) {
- if (root)
- roots_.insert(root);
- access_policy_->Init(id_, this);
-}
-
-WindowTree::~WindowTree() {
- DestroyWindows();
-}
-
-void WindowTree::Init(std::unique_ptr<WindowTreeBinding> binding,
- mojom::WindowTreePtr tree) {
- DCHECK(!binding_);
- binding_ = std::move(binding);
-
- if (roots_.empty())
- return;
-
- std::vector<const ServerWindow*> to_send;
- CHECK_EQ(1u, roots_.size());
- const ServerWindow* root = *roots_.begin();
- GetUnknownWindowsFrom(root, &to_send);
-
- Display* display = GetDisplay(root);
- int64_t display_id =
- display ? display->id() : display::Display::kInvalidDisplayID;
- const ServerWindow* focused_window =
- display ? display->GetFocusedWindow() : nullptr;
- if (focused_window)
- focused_window = access_policy_->GetWindowForFocusChange(focused_window);
- ClientWindowId focused_window_id;
- if (focused_window)
- IsWindowKnown(focused_window, &focused_window_id);
-
- const bool drawn = root->parent() && root->parent()->IsDrawn();
- client()->OnEmbed(id_, WindowToWindowData(to_send.front()), std::move(tree),
- display_id, focused_window_id.id, drawn);
-}
-
-void WindowTree::ConfigureWindowManager() {
- DCHECK(!window_manager_internal_);
- window_manager_internal_ = binding_->GetWindowManager();
- window_manager_internal_->OnConnect(id_);
- window_manager_state_.reset(new WindowManagerState(this));
-}
-
-const ServerWindow* WindowTree::GetWindow(const WindowId& id) const {
- if (id_ == id.client_id) {
- auto iter = created_window_map_.find(id);
- return iter == created_window_map_.end() ? nullptr : iter->second;
- }
- return window_server_->GetWindow(id);
-}
-
-bool WindowTree::IsWindowKnown(const ServerWindow* window,
- ClientWindowId* id) const {
- if (!window)
- return false;
- auto iter = window_id_to_client_id_map_.find(window->id());
- if (iter == window_id_to_client_id_map_.end())
- return false;
- if (id)
- *id = iter->second;
- return true;
-}
-
-bool WindowTree::HasRoot(const ServerWindow* window) const {
- return roots_.count(window) > 0;
-}
-
-const ServerWindow* WindowTree::GetWindowByClientId(
- const ClientWindowId& id) const {
- auto iter = client_id_to_window_id_map_.find(id);
- return iter == client_id_to_window_id_map_.end() ? nullptr
- : GetWindow(iter->second);
-}
-
-const Display* WindowTree::GetDisplay(const ServerWindow* window) const {
- return window ? display_manager()->GetDisplayContaining(window) : nullptr;
-}
-
-const WindowManagerDisplayRoot* WindowTree::GetWindowManagerDisplayRoot(
- const ServerWindow* window) const {
- return window ? display_manager()->GetWindowManagerDisplayRoot(window)
- : nullptr;
-}
-
-DisplayManager* WindowTree::display_manager() {
- return window_server_->display_manager();
-}
-
-const DisplayManager* WindowTree::display_manager() const {
- return window_server_->display_manager();
-}
-
-void WindowTree::AddRootForWindowManager(const ServerWindow* root) {
- DCHECK(window_manager_internal_);
- const ClientWindowId client_window_id(WindowIdToTransportId(root->id()));
- DCHECK_EQ(0u, client_id_to_window_id_map_.count(client_window_id));
- client_id_to_window_id_map_[client_window_id] = root->id();
- window_id_to_client_id_map_[root->id()] = client_window_id;
- roots_.insert(root);
-
- Display* display = GetDisplay(root);
- DCHECK(display);
-
- window_manager_internal_->WmNewDisplayAdded(display->ToMojomDisplay(),
- WindowToWindowData(root),
- root->parent()->IsDrawn());
-}
-
-void WindowTree::OnWindowDestroyingTreeImpl(WindowTree* tree) {
- if (window_manager_state_)
- window_manager_state_->OnWillDestroyTree(tree);
-
- if (event_source_wms_ && event_source_wms_->window_tree() == tree)
- event_source_wms_ = nullptr;
-
- // Notify our client if |tree| was embedded in any of our views.
- for (const auto* tree_root : tree->roots_) {
- const bool owns_tree_root = tree_root->id().client_id == id_;
- if (owns_tree_root) {
- client()->OnEmbeddedAppDisconnected(
- ClientWindowIdForWindow(tree_root).id);
- }
- }
-}
-
-void WindowTree::NotifyChangeCompleted(
- uint32_t change_id,
- mojom::WindowManagerErrorCode error_code) {
- client()->OnChangeCompleted(
- change_id, error_code == mojom::WindowManagerErrorCode::SUCCESS);
-}
-
-bool WindowTree::SetCapture(const ClientWindowId& client_window_id) {
- ServerWindow* window = GetWindowByClientId(client_window_id);
- WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(window);
- ServerWindow* current_capture_window =
- display_root ? display_root->window_manager_state()->capture_window()
- : nullptr;
- if (window && window->IsDrawn() && display_root &&
- display_root->window_manager_state()->IsActive() &&
- access_policy_->CanSetCapture(window) &&
- (!current_capture_window ||
- access_policy_->CanSetCapture(current_capture_window))) {
- return display_root->window_manager_state()->SetCapture(window, id_);
- }
- return false;
-}
-
-bool WindowTree::NewWindow(
- const ClientWindowId& client_window_id,
- const std::map<std::string, std::vector<uint8_t>>& properties) {
- if (!IsValidIdForNewWindow(client_window_id))
- return false;
- const WindowId window_id = GenerateNewWindowId();
- DCHECK(!GetWindow(window_id));
- ServerWindow* window =
- window_server_->CreateServerWindow(window_id, properties);
- created_window_map_[window_id] = window;
- client_id_to_window_id_map_[client_window_id] = window_id;
- window_id_to_client_id_map_[window_id] = client_window_id;
- return true;
-}
-
-bool WindowTree::AddWindow(const ClientWindowId& parent_id,
- const ClientWindowId& child_id) {
- ServerWindow* parent = GetWindowByClientId(parent_id);
- ServerWindow* child = GetWindowByClientId(child_id);
- if (parent && child && child->parent() != parent &&
- !child->Contains(parent) && access_policy_->CanAddWindow(parent, child)) {
- Operation op(this, window_server_, OperationType::ADD_WINDOW);
- parent->Add(child);
- return true;
- }
- return false;
-}
-
-bool WindowTree::AddTransientWindow(const ClientWindowId& window_id,
- const ClientWindowId& transient_window_id) {
- ServerWindow* window = GetWindowByClientId(window_id);
- ServerWindow* transient_window = GetWindowByClientId(transient_window_id);
- if (window && transient_window && !transient_window->Contains(window) &&
- access_policy_->CanAddTransientWindow(window, transient_window)) {
- Operation op(this, window_server_, OperationType::ADD_TRANSIENT_WINDOW);
- return window->AddTransientWindow(transient_window);
- }
- return false;
-}
-
-bool WindowTree::SetModal(const ClientWindowId& window_id) {
- ServerWindow* window = GetWindowByClientId(window_id);
- if (window && access_policy_->CanSetModal(window)) {
- WindowManagerDisplayRoot* display_root =
- GetWindowManagerDisplayRoot(window);
- if (window->transient_parent()) {
- window->SetModal();
- } else if (user_id_ != InvalidUserId()) {
- if (display_root)
- display_root->window_manager_state()->AddSystemModalWindow(window);
- } else {
- return false;
- }
- if (display_root)
- display_root->window_manager_state()->ReleaseCaptureBlockedByModalWindow(
- window);
- return true;
- }
- return false;
-}
-
-std::vector<const ServerWindow*> WindowTree::GetWindowTree(
- const ClientWindowId& window_id) const {
- const ServerWindow* window = GetWindowByClientId(window_id);
- std::vector<const ServerWindow*> windows;
- if (window)
- GetWindowTreeImpl(window, &windows);
- return windows;
-}
-
-bool WindowTree::SetWindowVisibility(const ClientWindowId& window_id,
- bool visible) {
- ServerWindow* window = GetWindowByClientId(window_id);
- if (!window || !access_policy_->CanChangeWindowVisibility(window))
- return false;
- if (window->visible() == visible)
- return true;
- Operation op(this, window_server_, OperationType::SET_WINDOW_VISIBILITY);
- window->SetVisible(visible);
- return true;
-}
-
-bool WindowTree::SetWindowOpacity(const ClientWindowId& window_id,
- float opacity) {
- ServerWindow* window = GetWindowByClientId(window_id);
- if (!window || !access_policy_->CanChangeWindowOpacity(window))
- return false;
- if (window->opacity() == opacity)
- return true;
- Operation op(this, window_server_, OperationType::SET_WINDOW_OPACITY);
- window->SetOpacity(opacity);
- return true;
-}
-
-bool WindowTree::SetFocus(const ClientWindowId& window_id) {
- ServerWindow* window = GetWindowByClientId(window_id);
- ServerWindow* currently_focused = window_server_->GetFocusedWindow();
- if (!currently_focused && !window) {
- DVLOG(1) << "SetFocus failure, no focused window to clear.";
- return false;
- }
-
- Display* display = GetDisplay(window);
- if (window && (!display || !window->can_focus() || !window->IsDrawn())) {
- DVLOG(1) << "SetFocus failure, window cannot be focused.";
- return false;
- }
-
- if (!access_policy_->CanSetFocus(window)) {
- DVLOG(1) << "SetFocus failure, blocked by access policy.";
- return false;
- }
-
- Operation op(this, window_server_, OperationType::SET_FOCUS);
- bool success = window_server_->SetFocusedWindow(window);
- if (!success) {
- DVLOG(1) << "SetFocus failure, could not SetFocusedWindow.";
- }
- return success;
-}
-
-bool WindowTree::Embed(const ClientWindowId& window_id,
- mojom::WindowTreeClientPtr client,
- uint32_t flags) {
- if (!client || !CanEmbed(window_id))
- return false;
- ServerWindow* window = GetWindowByClientId(window_id);
- PrepareForEmbed(window);
- // When embedding we don't know the user id of where the TreeClient came
- // from. Use an invalid id, which limits what the client is able to do.
- window_server_->EmbedAtWindow(window, InvalidUserId(), std::move(client),
- flags,
- base::WrapUnique(new DefaultAccessPolicy));
- return true;
-}
-
-void WindowTree::DispatchInputEvent(ServerWindow* target,
- const ui::Event& event) {
- if (event_ack_id_) {
- // This is currently waiting for an event ack. Add it to the queue.
- event_queue_.push(base::WrapUnique(new TargetedEvent(target, event)));
- // TODO(sad): If the |event_queue_| grows too large, then this should notify
- // Display, so that it can stop sending events.
- return;
- }
-
- // If there are events in the queue, then store this new event in the queue,
- // and dispatch the latest event from the queue instead that still has a live
- // target.
- if (!event_queue_.empty()) {
- event_queue_.push(base::WrapUnique(new TargetedEvent(target, event)));
- return;
- }
-
- DispatchInputEventImpl(target, event);
-}
-
-bool WindowTree::IsWaitingForNewTopLevelWindow(uint32_t wm_change_id) {
- return waiting_for_top_level_window_info_ &&
- waiting_for_top_level_window_info_->wm_change_id == wm_change_id;
-}
-
-void WindowTree::OnWindowManagerCreatedTopLevelWindow(
- uint32_t wm_change_id,
- uint32_t client_change_id,
- const ServerWindow* window) {
- DCHECK(IsWaitingForNewTopLevelWindow(wm_change_id));
- std::unique_ptr<WaitingForTopLevelWindowInfo>
- waiting_for_top_level_window_info(
- std::move(waiting_for_top_level_window_info_));
- binding_->SetIncomingMethodCallProcessingPaused(false);
- // We were paused, so the id should still be valid.
- DCHECK(IsValidIdForNewWindow(
- waiting_for_top_level_window_info->client_window_id));
- client_id_to_window_id_map_[waiting_for_top_level_window_info
- ->client_window_id] = window->id();
- window_id_to_client_id_map_[window->id()] =
- waiting_for_top_level_window_info->client_window_id;
- roots_.insert(window);
- Display* display = GetDisplay(window);
- int64_t display_id =
- display ? display->id() : display::Display::kInvalidDisplayID;
- const bool drawn = window->parent() && window->parent()->IsDrawn();
- client()->OnTopLevelCreated(client_change_id, WindowToWindowData(window),
- display_id, drawn);
-}
-
-void WindowTree::AddActivationParent(const ClientWindowId& window_id) {
- ServerWindow* window = GetWindowByClientId(window_id);
- if (window) {
- Display* display = GetDisplay(window);
- if (display)
- display->AddActivationParent(window);
- else
- DVLOG(1) << "AddActivationParent window not associated with display";
- } else {
- DVLOG(1) << "AddActivationParent supplied invalid window id";
- }
-}
-
-void WindowTree::OnChangeCompleted(uint32_t change_id, bool success) {
- client()->OnChangeCompleted(change_id, success);
-}
-
-void WindowTree::OnAccelerator(uint32_t accelerator_id,
- const ui::Event& event) {
- DCHECK(window_manager_internal_);
- // TODO(moshayedi): crbug.com/617167. Don't clone even once we map
- // mojom::Event directly to ui::Event.
- window_manager_internal_->OnAccelerator(accelerator_id,
- ui::Event::Clone(event));
-}
-
-void WindowTree::ClientJankinessChanged(WindowTree* tree) {
- tree->janky_ = !tree->janky_;
- if (window_manager_internal_) {
- window_manager_internal_->WmClientJankinessChanged(
- tree->id(), tree->janky());
- }
-}
-
-void WindowTree::ProcessWindowBoundsChanged(const ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds,
- bool originated_change) {
- ClientWindowId client_window_id;
- if (originated_change || !IsWindowKnown(window, &client_window_id))
- return;
- client()->OnWindowBoundsChanged(client_window_id.id, old_bounds, new_bounds);
-}
-
-void WindowTree::ProcessClientAreaChanged(
- const ServerWindow* window,
- const gfx::Insets& new_client_area,
- const std::vector<gfx::Rect>& new_additional_client_areas,
- bool originated_change) {
- ClientWindowId client_window_id;
- if (originated_change || !IsWindowKnown(window, &client_window_id))
- return;
- client()->OnClientAreaChanged(
- client_window_id.id, new_client_area,
- std::vector<gfx::Rect>(new_additional_client_areas));
-}
-
-void WindowTree::ProcessWillChangeWindowHierarchy(
- const ServerWindow* window,
- const ServerWindow* new_parent,
- const ServerWindow* old_parent,
- bool originated_change) {
- if (originated_change)
- return;
-
- const bool old_drawn = window->IsDrawn();
- const bool new_drawn =
- window->visible() && new_parent && new_parent->IsDrawn();
- if (old_drawn == new_drawn)
- return;
-
- NotifyDrawnStateChanged(window, new_drawn);
-}
-
-void WindowTree::ProcessWindowPropertyChanged(
- const ServerWindow* window,
- const std::string& name,
- const std::vector<uint8_t>* new_data,
- bool originated_change) {
- if (originated_change)
- return;
-
- ClientWindowId client_window_id;
- if (!IsWindowKnown(window, &client_window_id))
- return;
-
- Array<uint8_t> data(nullptr);
- if (new_data)
- data = Array<uint8_t>::From(*new_data);
-
- client()->OnWindowSharedPropertyChanged(client_window_id.id, String(name),
- std::move(data));
-}
-
-void WindowTree::ProcessWindowHierarchyChanged(const ServerWindow* window,
- const ServerWindow* new_parent,
- const ServerWindow* old_parent,
- bool originated_change) {
- const bool knows_new = new_parent && IsWindowKnown(new_parent);
- if (originated_change && !IsWindowKnown(window) && knows_new) {
- std::vector<const ServerWindow*> unused;
- GetUnknownWindowsFrom(window, &unused);
- }
- if (originated_change || (window_server_->current_operation_type() ==
- OperationType::DELETE_WINDOW) ||
- (window_server_->current_operation_type() == OperationType::EMBED) ||
- window_server_->DidTreeMessageClient(id_)) {
- return;
- }
-
- if (!access_policy_->ShouldNotifyOnHierarchyChange(window, &new_parent,
- &old_parent)) {
- return;
- }
- // Inform the client of any new windows and update the set of windows we know
- // about.
- std::vector<const ServerWindow*> to_send;
- if (!IsWindowKnown(window))
- GetUnknownWindowsFrom(window, &to_send);
- const bool knows_old = old_parent && IsWindowKnown(old_parent);
- if (!knows_old && !knows_new)
- return;
-
- const ClientWindowId new_parent_client_window_id =
- knows_new ? ClientWindowIdForWindow(new_parent) : ClientWindowId();
- const ClientWindowId old_parent_client_window_id =
- knows_old ? ClientWindowIdForWindow(old_parent) : ClientWindowId();
- const ClientWindowId client_window_id =
- window ? ClientWindowIdForWindow(window) : ClientWindowId();
- client()->OnWindowHierarchyChanged(
- client_window_id.id, old_parent_client_window_id.id,
- new_parent_client_window_id.id, WindowsToWindowDatas(to_send));
- window_server_->OnTreeMessagedClient(id_);
-}
-
-void WindowTree::ProcessWindowReorder(const ServerWindow* window,
- const ServerWindow* relative_window,
- mojom::OrderDirection direction,
- bool originated_change) {
- DCHECK_EQ(window->parent(), relative_window->parent());
- ClientWindowId client_window_id, relative_client_window_id;
- if (originated_change || !IsWindowKnown(window, &client_window_id) ||
- !IsWindowKnown(relative_window, &relative_client_window_id) ||
- window_server_->DidTreeMessageClient(id_))
- return;
-
- // Do not notify ordering changes of the root windows, since the client
- // doesn't know about the ancestors of the roots, and so can't do anything
- // about this ordering change of the root.
- if (HasRoot(window) || HasRoot(relative_window))
- return;
-
- client()->OnWindowReordered(client_window_id.id, relative_client_window_id.id,
- direction);
- window_server_->OnTreeMessagedClient(id_);
-}
-
-void WindowTree::ProcessWindowDeleted(const ServerWindow* window,
- bool originated_change) {
- if (window->id().client_id == id_)
- created_window_map_.erase(window->id());
-
- ClientWindowId client_window_id;
- if (!IsWindowKnown(window, &client_window_id))
- return;
-
- if (HasRoot(window))
- RemoveRoot(window, RemoveRootReason::DELETED);
- else
- RemoveFromMaps(window);
-
- if (originated_change)
- return;
-
- client()->OnWindowDeleted(client_window_id.id);
- window_server_->OnTreeMessagedClient(id_);
-}
-
-void WindowTree::ProcessWillChangeWindowVisibility(const ServerWindow* window,
- bool originated_change) {
- if (originated_change)
- return;
-
- ClientWindowId client_window_id;
- if (IsWindowKnown(window, &client_window_id)) {
- client()->OnWindowVisibilityChanged(client_window_id.id,
- !window->visible());
- return;
- }
-
- bool window_target_drawn_state;
- if (window->visible()) {
- // Window is being hidden, won't be drawn.
- window_target_drawn_state = false;
- } else {
- // Window is being shown. Window will be drawn if its parent is drawn.
- window_target_drawn_state = window->parent() && window->parent()->IsDrawn();
- }
-
- NotifyDrawnStateChanged(window, window_target_drawn_state);
-}
-
-void WindowTree::ProcessWindowOpacityChanged(const ServerWindow* window,
- float old_opacity,
- float new_opacity,
- bool originated_change) {
- if (originated_change)
- return;
-
- ClientWindowId client_window_id;
- if (IsWindowKnown(window, &client_window_id)) {
- client()->OnWindowOpacityChanged(client_window_id.id, old_opacity,
- new_opacity);
- }
-}
-
-void WindowTree::ProcessCursorChanged(const ServerWindow* window,
- int32_t cursor_id,
- bool originated_change) {
- if (originated_change)
- return;
- ClientWindowId client_window_id;
- if (!IsWindowKnown(window, &client_window_id))
- return;
-
- client()->OnWindowPredefinedCursorChanged(client_window_id.id,
- mojom::Cursor(cursor_id));
-}
-
-void WindowTree::ProcessFocusChanged(const ServerWindow* old_focused_window,
- const ServerWindow* new_focused_window) {
- if (window_server_->current_operation_type() == OperationType::SET_FOCUS &&
- window_server_->IsOperationSource(id_)) {
- return;
- }
- const ServerWindow* window =
- new_focused_window
- ? access_policy_->GetWindowForFocusChange(new_focused_window)
- : nullptr;
- ClientWindowId client_window_id;
- // If the window isn't known we'll supply null, which is ok.
- IsWindowKnown(window, &client_window_id);
- client()->OnWindowFocused(client_window_id.id);
-}
-
-void WindowTree::ProcessTransientWindowAdded(
- const ServerWindow* window,
- const ServerWindow* transient_window,
- bool originated_change) {
- if (originated_change)
- return;
-
- ClientWindowId client_window_id, transient_client_window_id;
- if (!IsWindowKnown(window, &client_window_id) ||
- !IsWindowKnown(transient_window, &transient_client_window_id)) {
- return;
- }
- client()->OnTransientWindowAdded(client_window_id.id,
- transient_client_window_id.id);
-}
-
-void WindowTree::ProcessTransientWindowRemoved(
- const ServerWindow* window,
- const ServerWindow* transient_window,
- bool originated_change) {
- if (originated_change)
- return;
- ClientWindowId client_window_id, transient_client_window_id;
- if (!IsWindowKnown(window, &client_window_id) ||
- !IsWindowKnown(transient_window, &transient_client_window_id)) {
- return;
- }
- client()->OnTransientWindowRemoved(client_window_id.id,
- transient_client_window_id.id);
-}
-
-bool WindowTree::ShouldRouteToWindowManager(const ServerWindow* window) const {
- if (window_manager_state_)
- return false; // We are the window manager, don't route to ourself.
-
- // If the client created this window, then do not route it through the WM.
- if (window->id().client_id == id_)
- return false;
-
- // If the client did not create the window, then it must be the root of the
- // client. If not, that means the client should not know about this window,
- // and so do not route the request to the WM.
- if (roots_.count(window) == 0)
- return false;
-
- // The WindowManager is attached to the root of the Display, if there isn't a
- // WindowManager attached no need to route to it.
- const WindowManagerDisplayRoot* display_root =
- GetWindowManagerDisplayRoot(window);
- if (!display_root)
- return false;
-
- // Route to the windowmanager if the windowmanager created the window.
- return display_root->window_manager_state()->window_tree()->id() ==
- window->id().client_id;
-}
-
-void WindowTree::ProcessLostCapture(const ServerWindow* old_capture_window,
- bool originated_change) {
- if ((originated_change &&
- window_server_->current_operation_type() ==
- OperationType::RELEASE_CAPTURE) ||
- !IsWindowKnown(old_capture_window)) {
- return;
- }
- client()->OnLostCapture(WindowIdToTransportId(old_capture_window->id()));
-}
-
-ClientWindowId WindowTree::ClientWindowIdForWindow(
- const ServerWindow* window) const {
- auto iter = window_id_to_client_id_map_.find(window->id());
- DCHECK(iter != window_id_to_client_id_map_.end());
- return iter->second;
-}
-
-bool WindowTree::IsValidIdForNewWindow(const ClientWindowId& id) const {
- // Reserve 0 to indicate a null window.
- return client_id_to_window_id_map_.count(id) == 0u &&
- access_policy_->IsValidIdForNewWindow(id) && id != ClientWindowId();
-}
-
-WindowId WindowTree::GenerateNewWindowId() {
- // TODO(sky): deal with wrapping and uniqueness.
- return WindowId(id_, next_window_id_++);
-}
-
-bool WindowTree::CanReorderWindow(const ServerWindow* window,
- const ServerWindow* relative_window,
- mojom::OrderDirection direction) const {
- if (!window || !relative_window)
- return false;
-
- if (!window->parent() || window->parent() != relative_window->parent())
- return false;
-
- if (!access_policy_->CanReorderWindow(window, relative_window, direction))
- return false;
-
- std::vector<const ServerWindow*> children = window->parent()->GetChildren();
- const size_t child_i =
- std::find(children.begin(), children.end(), window) - children.begin();
- const size_t target_i =
- std::find(children.begin(), children.end(), relative_window) -
- children.begin();
- if ((direction == mojom::OrderDirection::ABOVE && child_i == target_i + 1) ||
- (direction == mojom::OrderDirection::BELOW && child_i + 1 == target_i)) {
- return false;
- }
-
- return true;
-}
-
-bool WindowTree::DeleteWindowImpl(WindowTree* source, ServerWindow* window) {
- DCHECK(window);
- DCHECK_EQ(window->id().client_id, id_);
- Operation op(source, window_server_, OperationType::DELETE_WINDOW);
- delete window;
- return true;
-}
-
-void WindowTree::GetUnknownWindowsFrom(
- const ServerWindow* window,
- std::vector<const ServerWindow*>* windows) {
- if (IsWindowKnown(window) || !access_policy_->CanGetWindowTree(window))
- return;
- windows->push_back(window);
- // There are two cases where this gets hit:
- // . During init, in which case using the window id as the client id is
- // fine.
- // . When a window is moved to a parent of a window we know about. This is
- // only encountered for the WM or embed roots. We assume such clients want
- // to see the real id of the window and are only created ClientWindowIds
- // with the client_id.
- const ClientWindowId client_window_id(WindowIdToTransportId(window->id()));
- DCHECK_EQ(0u, client_id_to_window_id_map_.count(client_window_id));
- client_id_to_window_id_map_[client_window_id] = window->id();
- window_id_to_client_id_map_[window->id()] = client_window_id;
- if (!access_policy_->CanDescendIntoWindowForWindowTree(window))
- return;
- std::vector<const ServerWindow*> children(window->GetChildren());
- for (size_t i = 0; i < children.size(); ++i)
- GetUnknownWindowsFrom(children[i], windows);
-}
-
-bool WindowTree::RemoveFromMaps(const ServerWindow* window) {
- auto iter = window_id_to_client_id_map_.find(window->id());
- if (iter == window_id_to_client_id_map_.end())
- return false;
-
- client_id_to_window_id_map_.erase(iter->second);
- window_id_to_client_id_map_.erase(iter);
- return true;
-}
-
-void WindowTree::RemoveFromKnown(const ServerWindow* window,
- std::vector<ServerWindow*>* local_windows) {
- if (window->id().client_id == id_) {
- if (local_windows)
- local_windows->push_back(GetWindow(window->id()));
- return;
- }
-
- RemoveFromMaps(window);
-
- std::vector<const ServerWindow*> children = window->GetChildren();
- for (size_t i = 0; i < children.size(); ++i)
- RemoveFromKnown(children[i], local_windows);
-}
-
-void WindowTree::RemoveRoot(const ServerWindow* window,
- RemoveRootReason reason) {
- DCHECK(roots_.count(window) > 0);
- roots_.erase(window);
-
- const ClientWindowId client_window_id(ClientWindowIdForWindow(window));
-
- // No need to do anything if we created the window.
- if (window->id().client_id == id_)
- return;
-
- if (reason == RemoveRootReason::EMBED) {
- client()->OnUnembed(client_window_id.id);
- client()->OnWindowDeleted(client_window_id.id);
- window_server_->OnTreeMessagedClient(id_);
- }
-
- // This client no longer knows about the window. Unparent any windows that
- // were parented to windows in the root.
- std::vector<ServerWindow*> local_windows;
- RemoveFromKnown(window, &local_windows);
- for (size_t i = 0; i < local_windows.size(); ++i)
- local_windows[i]->parent()->Remove(local_windows[i]);
-}
-
-Array<mojom::WindowDataPtr> WindowTree::WindowsToWindowDatas(
- const std::vector<const ServerWindow*>& windows) {
- Array<mojom::WindowDataPtr> array(windows.size());
- for (size_t i = 0; i < windows.size(); ++i)
- array[i] = WindowToWindowData(windows[i]);
- return array;
-}
-
-mojom::WindowDataPtr WindowTree::WindowToWindowData(
- const ServerWindow* window) {
- DCHECK(IsWindowKnown(window));
- const ServerWindow* parent = window->parent();
- // If the parent isn't known, it means the parent is not visible to us (not
- // in roots), and should not be sent over.
- if (parent && !IsWindowKnown(parent))
- parent = nullptr;
- mojom::WindowDataPtr window_data(mojom::WindowData::New());
- window_data->parent_id =
- parent ? ClientWindowIdForWindow(parent).id : ClientWindowId().id;
- window_data->window_id =
- window ? ClientWindowIdForWindow(window).id : ClientWindowId().id;
- window_data->bounds = window->bounds();
- window_data->properties =
- mojo::Map<String, Array<uint8_t>>::From(window->properties());
- window_data->visible = window->visible();
- return window_data;
-}
-
-void WindowTree::GetWindowTreeImpl(
- const ServerWindow* window,
- std::vector<const ServerWindow*>* windows) const {
- DCHECK(window);
-
- if (!access_policy_->CanGetWindowTree(window))
- return;
-
- windows->push_back(window);
-
- if (!access_policy_->CanDescendIntoWindowForWindowTree(window))
- return;
-
- std::vector<const ServerWindow*> children(window->GetChildren());
- for (size_t i = 0; i < children.size(); ++i)
- GetWindowTreeImpl(children[i], windows);
-}
-
-void WindowTree::NotifyDrawnStateChanged(const ServerWindow* window,
- bool new_drawn_value) {
- // Even though we don't know about window, it may be an ancestor of our root,
- // in which case the change may effect our roots drawn state.
- if (roots_.empty())
- return;
-
- for (auto* root : roots_) {
- if (window->Contains(root) && (new_drawn_value != root->IsDrawn())) {
- client()->OnWindowParentDrawnStateChanged(
- ClientWindowIdForWindow(root).id, new_drawn_value);
- }
- }
-}
-
-void WindowTree::DestroyWindows() {
- if (created_window_map_.empty())
- return;
-
- Operation op(this, window_server_, OperationType::DELETE_WINDOW);
- // If we get here from the destructor we're not going to get
- // ProcessWindowDeleted(). Copy the map and delete from the copy so that we
- // don't have to worry about whether |created_window_map_| changes or not.
- base::hash_map<WindowId, ServerWindow*> created_window_map_copy;
- created_window_map_.swap(created_window_map_copy);
- // A sibling can be a transient parent of another window so we detach windows
- // from their transient parents to avoid double deletes.
- for (auto& pair : created_window_map_copy) {
- ServerWindow* transient_parent = pair.second->transient_parent();
- if (transient_parent)
- transient_parent->RemoveTransientWindow(pair.second);
- }
- STLDeleteValues(&created_window_map_copy);
-}
-
-bool WindowTree::CanEmbed(const ClientWindowId& window_id) const {
- const ServerWindow* window = GetWindowByClientId(window_id);
- return window && access_policy_->CanEmbed(window);
-}
-
-void WindowTree::PrepareForEmbed(ServerWindow* window) {
- DCHECK(window);
-
- // Only allow a node to be the root for one client.
- WindowTree* existing_owner = window_server_->GetTreeWithRoot(window);
-
- Operation op(this, window_server_, OperationType::EMBED);
- RemoveChildrenAsPartOfEmbed(window);
- if (existing_owner) {
- // Never message the originating client.
- window_server_->OnTreeMessagedClient(id_);
- existing_owner->RemoveRoot(window, RemoveRootReason::EMBED);
- }
-}
-
-void WindowTree::RemoveChildrenAsPartOfEmbed(ServerWindow* window) {
- CHECK(window);
- std::vector<ServerWindow*> children = window->GetChildren();
- for (size_t i = 0; i < children.size(); ++i)
- window->Remove(children[i]);
-}
-
-void WindowTree::DispatchInputEventImpl(ServerWindow* target,
- const ui::Event& event) {
- DCHECK(!event_ack_id_);
- // We do not want to create a sequential id for each event, because that can
- // leak some information to the client. So instead, manufacture the id
- // randomly.
- // TODO(moshayedi): Find a faster way to generate ids.
- event_ack_id_ = 0x1000000 | (rand() & 0xffffff);
- WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(target);
- DCHECK(display_root);
- event_source_wms_ = display_root->window_manager_state();
- // Should only get events from windows attached to a host.
- DCHECK(event_source_wms_);
- bool matched_observer =
- event_observer_matcher_ && event_observer_matcher_->MatchesEvent(event);
- client()->OnWindowInputEvent(
- event_ack_id_, ClientWindowIdForWindow(target).id,
- ui::Event::Clone(event), matched_observer ? event_observer_id_ : 0);
-}
-
-void WindowTree::SendToEventObserver(const ui::Event& event) {
- if (event_observer_matcher_ && event_observer_matcher_->MatchesEvent(event))
- client()->OnEventObserved(ui::Event::Clone(event), event_observer_id_);
-}
-
-void WindowTree::NewWindow(
- uint32_t change_id,
- Id transport_window_id,
- mojo::Map<mojo::String, mojo::Array<uint8_t>> transport_properties) {
- std::map<std::string, std::vector<uint8_t>> properties;
- if (!transport_properties.is_null()) {
- properties =
- transport_properties.To<std::map<std::string, std::vector<uint8_t>>>();
- }
- client()->OnChangeCompleted(
- change_id, NewWindow(ClientWindowId(transport_window_id), properties));
-}
-
-void WindowTree::NewTopLevelWindow(
- uint32_t change_id,
- Id transport_window_id,
- mojo::Map<mojo::String, mojo::Array<uint8_t>> transport_properties) {
- DCHECK(!waiting_for_top_level_window_info_);
- const ClientWindowId client_window_id(transport_window_id);
- // TODO(sky): need a way for client to provide context to figure out display.
- Display* display = display_manager()->displays().empty()
- ? nullptr
- : *(display_manager()->displays().begin());
- // TODO(sky): move checks to accesspolicy.
- WindowManagerDisplayRoot* display_root =
- display && user_id_ != InvalidUserId()
- ? display->GetWindowManagerDisplayRootForUser(user_id_)
- : nullptr;
- if (!display_root ||
- display_root->window_manager_state()->window_tree() == this ||
- !IsValidIdForNewWindow(client_window_id)) {
- client()->OnChangeCompleted(change_id, false);
- return;
- }
-
- // The server creates the real window. Any further messages from the client
- // may try to alter the window. Pause incoming messages so that we know we
- // can't get a message for a window before the window is created. Once the
- // window is created we'll resume processing.
- binding_->SetIncomingMethodCallProcessingPaused(true);
-
- const uint32_t wm_change_id =
- window_server_->GenerateWindowManagerChangeId(this, change_id);
-
- waiting_for_top_level_window_info_.reset(
- new WaitingForTopLevelWindowInfo(client_window_id, wm_change_id));
-
- display_root->window_manager_state()
- ->window_tree()
- ->window_manager_internal_->WmCreateTopLevelWindow(
- wm_change_id, id_, std::move(transport_properties));
-}
-
-void WindowTree::DeleteWindow(uint32_t change_id, Id transport_window_id) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- bool success = false;
- bool should_close = window && (access_policy_->CanDeleteWindow(window) ||
- ShouldRouteToWindowManager(window));
- if (should_close) {
- WindowTree* tree =
- window_server_->GetTreeWithId(window->id().client_id);
- success = tree && tree->DeleteWindowImpl(this, window);
- }
- client()->OnChangeCompleted(change_id, success);
-}
-
-void WindowTree::AddWindow(uint32_t change_id, Id parent_id, Id child_id) {
- client()->OnChangeCompleted(change_id, AddWindow(ClientWindowId(parent_id),
- ClientWindowId(child_id)));
-}
-
-void WindowTree::RemoveWindowFromParent(uint32_t change_id, Id window_id) {
- bool success = false;
- ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id));
- if (window && window->parent() &&
- access_policy_->CanRemoveWindowFromParent(window)) {
- success = true;
- Operation op(this, window_server_,
- OperationType::REMOVE_WINDOW_FROM_PARENT);
- window->parent()->Remove(window);
- }
- client()->OnChangeCompleted(change_id, success);
-}
-
-void WindowTree::AddTransientWindow(uint32_t change_id,
- Id window,
- Id transient_window) {
- client()->OnChangeCompleted(
- change_id, AddTransientWindow(ClientWindowId(window),
- ClientWindowId(transient_window)));
-}
-
-void WindowTree::RemoveTransientWindowFromParent(uint32_t change_id,
- Id transient_window_id) {
- bool success = false;
- ServerWindow* transient_window =
- GetWindowByClientId(ClientWindowId(transient_window_id));
- if (transient_window && transient_window->transient_parent() &&
- access_policy_->CanRemoveTransientWindowFromParent(transient_window)) {
- success = true;
- Operation op(this, window_server_,
- OperationType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT);
- transient_window->transient_parent()->RemoveTransientWindow(
- transient_window);
- }
- client()->OnChangeCompleted(change_id, success);
-}
-
-void WindowTree::SetModal(uint32_t change_id, Id window_id) {
- client()->OnChangeCompleted(change_id, SetModal(ClientWindowId(window_id)));
-}
-
-void WindowTree::ReorderWindow(uint32_t change_id,
- Id window_id,
- Id relative_window_id,
- mojom::OrderDirection direction) {
- bool success = false;
- ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id));
- ServerWindow* relative_window =
- GetWindowByClientId(ClientWindowId(relative_window_id));
- if (CanReorderWindow(window, relative_window, direction)) {
- success = true;
- Operation op(this, window_server_, OperationType::REORDER_WINDOW);
- window->Reorder(relative_window, direction);
- window_server_->ProcessWindowReorder(window, relative_window, direction);
- }
- client()->OnChangeCompleted(change_id, success);
-}
-
-void WindowTree::GetWindowTree(
- Id window_id,
- const base::Callback<void(Array<mojom::WindowDataPtr>)>& callback) {
- std::vector<const ServerWindow*> windows(
- GetWindowTree(ClientWindowId(window_id)));
- callback.Run(WindowsToWindowDatas(windows));
-}
-
-void WindowTree::SetCapture(uint32_t change_id, Id window_id) {
- client()->OnChangeCompleted(change_id, SetCapture(ClientWindowId(window_id)));
-}
-
-void WindowTree::ReleaseCapture(uint32_t change_id, Id window_id) {
- ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id));
- WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(window);
- ServerWindow* current_capture_window =
- display_root ? display_root->window_manager_state()->capture_window()
- : nullptr;
- bool success = window && display_root &&
- display_root->window_manager_state()->IsActive() &&
- (!current_capture_window ||
- access_policy_->CanSetCapture(current_capture_window)) &&
- window == current_capture_window;
- if (success) {
- Operation op(this, window_server_, OperationType::RELEASE_CAPTURE);
- success = display_root->window_manager_state()->SetCapture(
- nullptr, kInvalidClientId);
- }
- client()->OnChangeCompleted(change_id, success);
-}
-
-void WindowTree::SetEventObserver(mojom::EventMatcherPtr matcher,
- uint32_t observer_id) {
- if (matcher.is_null() || observer_id == 0) {
- // Clear any existing event observer.
- event_observer_matcher_.reset();
- event_observer_id_ = 0;
- return;
- }
-
- // Do not allow key events to be observed, as a compromised app could register
- // itself as an event observer and spy on keystrokes to another app.
- if (!matcher->type_matcher) {
- DVLOG(1) << "SetEventObserver must specify an event type.";
- return;
- }
- const ui::mojom::EventType event_type_whitelist[] = {
- ui::mojom::EventType::POINTER_CANCEL, ui::mojom::EventType::POINTER_DOWN,
- ui::mojom::EventType::POINTER_MOVE, ui::mojom::EventType::POINTER_UP,
- ui::mojom::EventType::MOUSE_EXIT, ui::mojom::EventType::WHEEL,
- };
- bool allowed = false;
- for (ui::mojom::EventType event_type : event_type_whitelist) {
- if (matcher->type_matcher->type == event_type) {
- allowed = true;
- break;
- }
- }
- if (!allowed) {
- DVLOG(1) << "SetEventObserver event type not allowed";
- return;
- }
-
- event_observer_matcher_.reset(new EventMatcher(*matcher));
- event_observer_id_ = observer_id;
-}
-
-void WindowTree::SetWindowBounds(uint32_t change_id,
- Id window_id,
- const gfx::Rect& bounds) {
- ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id));
- if (window && ShouldRouteToWindowManager(window)) {
- const uint32_t wm_change_id =
- window_server_->GenerateWindowManagerChangeId(this, change_id);
- // |window_id| may be a client id, use the id from the window to ensure
- // the windowmanager doesn't get an id it doesn't know about.
- WindowManagerDisplayRoot* display_root =
- GetWindowManagerDisplayRoot(window);
- WindowTree* wm_tree = display_root->window_manager_state()->window_tree();
- wm_tree->window_manager_internal_->WmSetBounds(
- wm_change_id, wm_tree->ClientWindowIdForWindow(window).id,
- std::move(bounds));
- return;
- }
-
- // Only the owner of the window can change the bounds.
- bool success = window && access_policy_->CanSetWindowBounds(window);
- if (success) {
- Operation op(this, window_server_, OperationType::SET_WINDOW_BOUNDS);
- window->SetBounds(bounds);
- }
- client()->OnChangeCompleted(change_id, success);
-}
-
-void WindowTree::SetWindowVisibility(uint32_t change_id,
- Id transport_window_id,
- bool visible) {
- client()->OnChangeCompleted(
- change_id,
- SetWindowVisibility(ClientWindowId(transport_window_id), visible));
-}
-
-void WindowTree::SetWindowProperty(uint32_t change_id,
- Id transport_window_id,
- const mojo::String& name,
- mojo::Array<uint8_t> value) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- if (window && ShouldRouteToWindowManager(window)) {
- const uint32_t wm_change_id =
- window_server_->GenerateWindowManagerChangeId(this, change_id);
- WindowManagerDisplayRoot* display_root =
- GetWindowManagerDisplayRoot(window);
- WindowTree* wm_tree = display_root->window_manager_state()->window_tree();
- wm_tree->window_manager_internal_->WmSetProperty(
- wm_change_id, wm_tree->ClientWindowIdForWindow(window).id, name,
- std::move(value));
- return;
- }
- const bool success = window && access_policy_->CanSetWindowProperties(window);
- if (success) {
- Operation op(this, window_server_, OperationType::SET_WINDOW_PROPERTY);
- if (value.is_null()) {
- window->SetProperty(name, nullptr);
- } else {
- std::vector<uint8_t> data = value.To<std::vector<uint8_t>>();
- window->SetProperty(name, &data);
- }
- }
- client()->OnChangeCompleted(change_id, success);
-}
-
-void WindowTree::SetWindowOpacity(uint32_t change_id,
- Id window_id,
- float opacity) {
- client()->OnChangeCompleted(
- change_id, SetWindowOpacity(ClientWindowId(window_id), opacity));
-}
-
-void WindowTree::AttachSurface(Id transport_window_id,
- mojom::SurfaceType type,
- mojo::InterfaceRequest<mojom::Surface> surface,
- mojom::SurfaceClientPtr client) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- const bool success =
- window && access_policy_->CanSetWindowSurface(window, type);
- if (!success)
- return;
- window->CreateSurface(type, std::move(surface), std::move(client));
-}
-
-void WindowTree::SetWindowTextInputState(Id transport_window_id,
- mojo::TextInputStatePtr state) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- bool success = window && access_policy_->CanSetWindowTextInputState(window);
- if (success)
- window->SetTextInputState(state.To<ui::TextInputState>());
-}
-
-void WindowTree::SetImeVisibility(Id transport_window_id,
- bool visible,
- mojo::TextInputStatePtr state) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- bool success = window && access_policy_->CanSetWindowTextInputState(window);
- if (success) {
- if (!state.is_null())
- window->SetTextInputState(state.To<ui::TextInputState>());
-
- Display* display = GetDisplay(window);
- if (display)
- display->SetImeVisibility(window, visible);
- }
-}
-
-void WindowTree::OnWindowInputEventAck(uint32_t event_id,
- mojom::EventResult result) {
- if (event_ack_id_ == 0 || event_id != event_ack_id_) {
- // TODO(sad): Something bad happened. Kill the client?
- NOTIMPLEMENTED() << "Wrong event acked.";
- }
- event_ack_id_ = 0;
-
- if (janky_)
- event_source_wms_->window_tree()->ClientJankinessChanged(this);
-
- WindowManagerState* event_source_wms = event_source_wms_;
- event_source_wms_ = nullptr;
- if (event_source_wms)
- event_source_wms->OnEventAck(this, result);
-
- if (!event_queue_.empty()) {
- DCHECK(!event_ack_id_);
- ServerWindow* target = nullptr;
- std::unique_ptr<ui::Event> event;
- do {
- std::unique_ptr<TargetedEvent> targeted_event =
- std::move(event_queue_.front());
- event_queue_.pop();
- target = targeted_event->target();
- event = targeted_event->TakeEvent();
- } while (!event_queue_.empty() && !GetDisplay(target));
- if (target)
- DispatchInputEventImpl(target, *event);
- }
-}
-
-void WindowTree::SetClientArea(
- Id transport_window_id,
- const gfx::Insets& insets,
- mojo::Array<gfx::Rect> transport_additional_client_areas) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- if (!window || !access_policy_->CanSetClientArea(window))
- return;
-
- std::vector<gfx::Rect> additional_client_areas =
- transport_additional_client_areas.To<std::vector<gfx::Rect>>();
- window->SetClientArea(insets, additional_client_areas);
-}
-
-void WindowTree::SetHitTestMask(Id transport_window_id, const gfx::Rect& mask) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- if (!window || !access_policy_->CanSetHitTestMask(window)) {
- DVLOG(1) << "SetHitTestMask failed";
- return;
- }
-
- if (!mask.IsEmpty())
- window->SetHitTestMask(mask);
- else
- window->ClearHitTestMask();
-}
-
-void WindowTree::Embed(Id transport_window_id,
- mojom::WindowTreeClientPtr client,
- uint32_t flags,
- const EmbedCallback& callback) {
- callback.Run(
- Embed(ClientWindowId(transport_window_id), std::move(client), flags));
-}
-
-void WindowTree::SetFocus(uint32_t change_id, Id transport_window_id) {
- client()->OnChangeCompleted(change_id,
- SetFocus(ClientWindowId(transport_window_id)));
-}
-
-void WindowTree::SetCanFocus(Id transport_window_id, bool can_focus) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- // TODO(sky): there should be an else case (it shouldn't route to wm and
- // policy allows, then set_can_focus).
- if (window && ShouldRouteToWindowManager(window))
- window->set_can_focus(can_focus);
-}
-
-void WindowTree::SetPredefinedCursor(uint32_t change_id,
- Id transport_window_id,
- mus::mojom::Cursor cursor_id) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
-
- // Only the owner of the window can change the bounds.
- bool success = window && access_policy_->CanSetCursorProperties(window);
- if (success) {
- Operation op(this, window_server_,
- OperationType::SET_WINDOW_PREDEFINED_CURSOR);
- window->SetPredefinedCursor(cursor_id);
- }
- client()->OnChangeCompleted(change_id, success);
-}
-
-void WindowTree::GetWindowManagerClient(
- mojo::AssociatedInterfaceRequest<mojom::WindowManagerClient> internal) {
- if (!access_policy_->CanSetWindowManager() || !window_manager_internal_ ||
- window_manager_internal_client_binding_) {
- return;
- }
- window_manager_internal_client_binding_.reset(
- new mojo::AssociatedBinding<mojom::WindowManagerClient>(
- this, std::move(internal)));
-}
-
-void WindowTree::GetCursorLocationMemory(
- const GetCursorLocationMemoryCallback& callback) {
- callback.Run(
- window_server_->display_manager()->GetUserDisplayManager(user_id_)->
- GetCursorLocationMemory());
-}
-
-void WindowTree::AddAccelerator(uint32_t id,
- mojom::EventMatcherPtr event_matcher,
- const AddAcceleratorCallback& callback) {
- DCHECK(window_manager_state_);
- const bool success =
- window_manager_state_->event_dispatcher()->AddAccelerator(
- id, std::move(event_matcher));
- callback.Run(success);
-}
-
-void WindowTree::RemoveAccelerator(uint32_t id) {
- window_manager_state_->event_dispatcher()->RemoveAccelerator(id);
-}
-
-void WindowTree::AddActivationParent(Id transport_window_id) {
- AddActivationParent(ClientWindowId(transport_window_id));
-}
-
-void WindowTree::RemoveActivationParent(Id transport_window_id) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- if (window) {
- Display* display = GetDisplay(window);
- if (display)
- display->RemoveActivationParent(window);
- else
- DVLOG(1) << "RemoveActivationParent window not associated with display";
- } else {
- DVLOG(1) << "RemoveActivationParent supplied invalid window id";
- }
-}
-
-void WindowTree::ActivateNextWindow() {
- DCHECK(window_manager_state_);
- if (window_server_->user_id_tracker()->active_id() != user_id_)
- return;
-
- ServerWindow* focused_window = window_server_->GetFocusedWindow();
- if (focused_window) {
- WindowManagerDisplayRoot* display_root =
- GetWindowManagerDisplayRoot(focused_window);
- if (display_root->window_manager_state() != window_manager_state_.get()) {
- // We aren't active.
- return;
- }
- display_root->display()->ActivateNextWindow();
- return;
- }
- // Use the first display.
- std::set<Display*> displays = window_server_->display_manager()->displays();
- if (displays.empty())
- return;
-
- (*displays.begin())->ActivateNextWindow();
-}
-
-void WindowTree::SetUnderlaySurfaceOffsetAndExtendedHitArea(
- Id window_id,
- int32_t x_offset,
- int32_t y_offset,
- const gfx::Insets& hit_area) {
- ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id));
- if (!window)
- return;
-
- window->SetUnderlayOffset(gfx::Vector2d(x_offset, y_offset));
- window->set_extended_hit_test_region(hit_area);
-}
-
-void WindowTree::WmResponse(uint32_t change_id, bool response) {
- window_server_->WindowManagerChangeCompleted(change_id, response);
-}
-
-void WindowTree::WmRequestClose(Id transport_window_id) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- WindowTree* tree = window_server_->GetTreeWithRoot(window);
- if (tree && tree != this) {
- tree->client()->RequestClose(tree->ClientWindowIdForWindow(window).id);
- }
- // TODO(sky): think about what else case means.
-}
-
-void WindowTree::WmSetFrameDecorationValues(
- mojom::FrameDecorationValuesPtr values) {
- DCHECK(window_manager_state_);
- window_manager_state_->SetFrameDecorationValues(std::move(values));
-}
-
-void WindowTree::WmSetNonClientCursor(uint32_t window_id,
- mojom::Cursor cursor_id) {
- DCHECK(window_manager_state_);
- ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id));
- if (window) {
- window->SetNonClientCursor(cursor_id);
- } else {
- DVLOG(1) << "trying to update non-client cursor of invalid window";
- }
-}
-
-void WindowTree::OnWmCreatedTopLevelWindow(uint32_t change_id,
- Id transport_window_id) {
- ServerWindow* window =
- GetWindowByClientId(ClientWindowId(transport_window_id));
- if (window && window->id().client_id != id_) {
- DVLOG(1) << "OnWmCreatedTopLevelWindow supplied invalid window id";
- window_server_->WindowManagerSentBogusMessage();
- window = nullptr;
- }
- window_server_->WindowManagerCreatedTopLevelWindow(this, change_id, window);
-}
-
-bool WindowTree::HasRootForAccessPolicy(const ServerWindow* window) const {
- return HasRoot(window);
-}
-
-bool WindowTree::IsWindowKnownForAccessPolicy(
- const ServerWindow* window) const {
- return IsWindowKnown(window);
-}
-
-bool WindowTree::IsWindowRootOfAnotherTreeForAccessPolicy(
- const ServerWindow* window) const {
- WindowTree* tree = window_server_->GetTreeWithRoot(window);
- return tree && tree != this;
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_tree.h b/chromium/components/mus/ws/window_tree.h
deleted file mode 100644
index 0e804f355a1..00000000000
--- a/chromium/components/mus/ws/window_tree.h
+++ /dev/null
@@ -1,497 +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 COMPONENTS_MUS_WS_WINDOW_TREE_H_
-#define COMPONENTS_MUS_WS_WINDOW_TREE_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <queue>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "cc/ipc/surface_id.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/ws/access_policy_delegate.h"
-#include "components/mus/ws/ids.h"
-#include "components/mus/ws/user_id.h"
-#include "components/mus/ws/window_tree_binding.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-
-namespace gfx {
-class Insets;
-class Rect;
-}
-
-namespace ui {
-class Event;
-}
-
-namespace mus {
-namespace ws {
-
-class AccessPolicy;
-class DisplayManager;
-class Display;
-class EventMatcher;
-class ServerWindow;
-class TargetedEvent;
-class WindowManagerDisplayRoot;
-class WindowManagerState;
-class WindowServer;
-class WindowTreeTest;
-
-namespace test {
-class WindowTreeTestApi;
-}
-
-// WindowTree represents a view onto portions of the window tree. The parts of
-// the tree exposed to the client start at the root windows. A WindowTree may
-// have any number of roots (including none). A WindowTree may not have
-// visibility of all the descendants of its roots.
-//
-// WindowTree notifies its client as changes happen to windows exposed to the
-// the client.
-//
-// See ids.h for details on how WindowTree handles identity of windows.
-class WindowTree : public mojom::WindowTree,
- public AccessPolicyDelegate,
- public mojom::WindowManagerClient {
- public:
- WindowTree(WindowServer* window_server,
- const UserId& user_id,
- ServerWindow* root,
- std::unique_ptr<AccessPolicy> access_policy);
- ~WindowTree() override;
-
- void Init(std::unique_ptr<WindowTreeBinding> binding,
- mojom::WindowTreePtr tree);
-
- // Called if this WindowTree hosts a WindowManager.
- void ConfigureWindowManager();
-
- ClientSpecificId id() const { return id_; }
-
- void set_embedder_intercepts_events() { embedder_intercepts_events_ = true; }
- bool embedder_intercepts_events() const {
- return embedder_intercepts_events_;
- }
-
- const UserId& user_id() const { return user_id_; }
-
- mojom::WindowTreeClient* client() { return binding_->client(); }
-
- // Returns the Window with the specified id.
- ServerWindow* GetWindow(const WindowId& id) {
- return const_cast<ServerWindow*>(
- const_cast<const WindowTree*>(this)->GetWindow(id));
- }
- const ServerWindow* GetWindow(const WindowId& id) const;
-
- // Returns the Window with the specified client id *only* if known to this
- // client, returns null if not known.
- ServerWindow* GetWindowByClientId(const ClientWindowId& id) {
- return const_cast<ServerWindow*>(
- const_cast<const WindowTree*>(this)->GetWindowByClientId(id));
- }
- const ServerWindow* GetWindowByClientId(const ClientWindowId& id) const;
-
- bool IsWindowKnown(const ServerWindow* window) const {
- return IsWindowKnown(window, nullptr);
- }
- // Returns whether |window| is known to this tree. If |window| is known and
- // |client_window_id| is non-null |client_window_id| is set to the
- // ClientWindowId of the window.
- bool IsWindowKnown(const ServerWindow* window,
- ClientWindowId* client_window_id) const;
-
- // Returns true if |window| is one of this trees roots.
- bool HasRoot(const ServerWindow* window) const;
-
- std::set<const ServerWindow*> roots() { return roots_; }
-
- void set_name(const std::string& name) { name_ = name; }
- const std::string& name() const { return name_; }
-
- bool janky() const { return janky_; }
-
- const Display* GetDisplay(const ServerWindow* window) const;
- Display* GetDisplay(const ServerWindow* window) {
- return const_cast<Display*>(
- const_cast<const WindowTree*>(this)->GetDisplay(window));
- }
-
- const WindowManagerDisplayRoot* GetWindowManagerDisplayRoot(
- const ServerWindow* window) const;
- WindowManagerDisplayRoot* GetWindowManagerDisplayRoot(
- const ServerWindow* window) {
- return const_cast<WindowManagerDisplayRoot*>(
- const_cast<const WindowTree*>(this)->GetWindowManagerDisplayRoot(
- window));
- }
- WindowManagerState* window_manager_state() {
- return window_manager_state_.get();
- }
-
- DisplayManager* display_manager();
- const DisplayManager* display_manager() const;
-
- WindowServer* window_server() { return window_server_; }
- const WindowServer* window_server() const { return window_server_; }
-
- // Adds a new root to this tree. This is only valid for window managers.
- void AddRootForWindowManager(const ServerWindow* root);
-
- // Invoked when a tree is about to be destroyed.
- void OnWindowDestroyingTreeImpl(WindowTree* tree);
-
- // These functions are synchronous variants of those defined in the mojom. The
- // WindowTree implementations all call into these. See the mojom for details.
- bool SetCapture(const ClientWindowId& client_window_id);
- bool NewWindow(const ClientWindowId& client_window_id,
- const std::map<std::string, std::vector<uint8_t>>& properties);
- bool AddWindow(const ClientWindowId& parent_id,
- const ClientWindowId& child_id);
- bool AddTransientWindow(const ClientWindowId& window_id,
- const ClientWindowId& transient_window_id);
- bool SetModal(const ClientWindowId& window_id);
- std::vector<const ServerWindow*> GetWindowTree(
- const ClientWindowId& window_id) const;
- bool SetWindowVisibility(const ClientWindowId& window_id, bool visible);
- bool SetWindowOpacity(const ClientWindowId& window_id, float opacity);
- bool SetFocus(const ClientWindowId& window_id);
- bool Embed(const ClientWindowId& window_id,
- mojom::WindowTreeClientPtr client,
- uint32_t flags);
- void DispatchInputEvent(ServerWindow* target, const ui::Event& event);
-
- bool IsWaitingForNewTopLevelWindow(uint32_t wm_change_id);
- void OnWindowManagerCreatedTopLevelWindow(uint32_t wm_change_id,
- uint32_t client_change_id,
- const ServerWindow* window);
- void AddActivationParent(const ClientWindowId& window_id);
-
- // Calls through to the client.
- void OnChangeCompleted(uint32_t change_id, bool success);
- void OnAccelerator(uint32_t accelerator_id, const ui::Event& event);
-
- // Called when |tree|'s jankiness changes (see janky_ for definition).
- // Notifies the window manager client so it can update UI for the affected
- // window(s).
- void ClientJankinessChanged(WindowTree* tree);
-
- // The following methods are invoked after the corresponding change has been
- // processed. They do the appropriate bookkeeping and update the client as
- // necessary.
- void ProcessWindowBoundsChanged(const ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds,
- bool originated_change);
- void ProcessClientAreaChanged(
- const ServerWindow* window,
- const gfx::Insets& new_client_area,
- const std::vector<gfx::Rect>& new_additional_client_areas,
- bool originated_change);
- void ProcessWillChangeWindowHierarchy(const ServerWindow* window,
- const ServerWindow* new_parent,
- const ServerWindow* old_parent,
- bool originated_change);
- void ProcessWindowPropertyChanged(const ServerWindow* window,
- const std::string& name,
- const std::vector<uint8_t>* new_data,
- bool originated_change);
- void ProcessWindowHierarchyChanged(const ServerWindow* window,
- const ServerWindow* new_parent,
- const ServerWindow* old_parent,
- bool originated_change);
- void ProcessWindowReorder(const ServerWindow* window,
- const ServerWindow* relative_window,
- mojom::OrderDirection direction,
- bool originated_change);
- void ProcessWindowDeleted(const ServerWindow* window, bool originated_change);
- void ProcessWillChangeWindowVisibility(const ServerWindow* window,
- bool originated_change);
- void ProcessWindowOpacityChanged(const ServerWindow* window,
- float old_opacity,
- float new_opacity,
- bool originated_change);
- void ProcessCursorChanged(const ServerWindow* window,
- int32_t cursor_id,
- bool originated_change);
- void ProcessFocusChanged(const ServerWindow* old_focused_window,
- const ServerWindow* new_focused_window);
- void ProcessLostCapture(const ServerWindow* old_lost_capture,
- bool originated_change);
- void ProcessTransientWindowAdded(const ServerWindow* window,
- const ServerWindow* transient_window,
- bool originated_change);
- void ProcessTransientWindowRemoved(const ServerWindow* window,
- const ServerWindow* transient_window,
- bool originated_change);
-
- // Sends this event to the client if it matches an active event observer.
- void SendToEventObserver(const ui::Event& event);
-
- private:
- friend class test::WindowTreeTestApi;
-
- struct WaitingForTopLevelWindowInfo {
- WaitingForTopLevelWindowInfo(const ClientWindowId& client_window_id,
- uint32_t wm_change_id)
- : client_window_id(client_window_id), wm_change_id(wm_change_id) {}
- ~WaitingForTopLevelWindowInfo() {}
-
- // Id supplied from the client.
- ClientWindowId client_window_id;
-
- // Change id we created for the window manager.
- uint32_t wm_change_id;
- };
-
- enum class RemoveRootReason {
- // The window is being removed.
- DELETED,
-
- // Another client is being embedded in the window.
- EMBED,
- };
-
- bool ShouldRouteToWindowManager(const ServerWindow* window) const;
-
- ClientWindowId ClientWindowIdForWindow(const ServerWindow* window) const;
-
- // Returns true if |id| is a valid WindowId for a new window.
- bool IsValidIdForNewWindow(const ClientWindowId& id) const;
-
- WindowId GenerateNewWindowId();
-
- // These functions return true if the corresponding mojom function is allowed
- // for this tree.
- bool CanReorderWindow(const ServerWindow* window,
- const ServerWindow* relative_window,
- mojom::OrderDirection direction) const;
-
- // Deletes a window owned by this tree. Returns true on success. |source| is
- // the tree that originated the change.
- bool DeleteWindowImpl(WindowTree* source, ServerWindow* window);
-
- // If |window| is known does nothing. Otherwise adds |window| to |windows|,
- // marks |window| as known and recurses.
- void GetUnknownWindowsFrom(const ServerWindow* window,
- std::vector<const ServerWindow*>* windows);
-
- // Removes |window| from the appropriate maps. If |window| is known to this
- // client true is returned.
- bool RemoveFromMaps(const ServerWindow* window);
-
- // Removes |window| and all its descendants from the necessary maps. This
- // does not recurse through windows that were created by this tree. All
- // windows owned by this tree are added to |local_windows|.
- void RemoveFromKnown(const ServerWindow* window,
- std::vector<ServerWindow*>* local_windows);
-
- // Removes a root from set of roots of this tree. This does not remove
- // the window from the window tree, only from the set of roots.
- void RemoveRoot(const ServerWindow* window, RemoveRootReason reason);
-
- // Converts Window(s) to WindowData(s) for transport. This assumes all the
- // windows are valid for the client. The parent of windows the client is not
- // allowed to see are set to NULL (in the returned WindowData(s)).
- mojo::Array<mojom::WindowDataPtr> WindowsToWindowDatas(
- const std::vector<const ServerWindow*>& windows);
- mojom::WindowDataPtr WindowToWindowData(const ServerWindow* window);
-
- // Implementation of GetWindowTree(). Adds |window| to |windows| and recurses
- // if CanDescendIntoWindowForWindowTree() returns true.
- void GetWindowTreeImpl(const ServerWindow* window,
- std::vector<const ServerWindow*>* windows) const;
-
- // Notify the client if the drawn state of any of the roots changes.
- // |window| is the window that is changing to the drawn state
- // |new_drawn_value|.
- void NotifyDrawnStateChanged(const ServerWindow* window,
- bool new_drawn_value);
-
- // Deletes all Windows we own.
- void DestroyWindows();
-
- bool CanEmbed(const ClientWindowId& window_id) const;
- void PrepareForEmbed(ServerWindow* window);
- void RemoveChildrenAsPartOfEmbed(ServerWindow* window);
-
- void DispatchInputEventImpl(ServerWindow* target, const ui::Event& event);
-
- // Calls OnChangeCompleted() on the client.
- void NotifyChangeCompleted(uint32_t change_id,
- mojom::WindowManagerErrorCode error_code);
-
- // WindowTree:
- void NewWindow(uint32_t change_id,
- Id transport_window_id,
- mojo::Map<mojo::String, mojo::Array<uint8_t>>
- transport_properties) override;
- void NewTopLevelWindow(uint32_t change_id,
- Id transport_window_id,
- mojo::Map<mojo::String, mojo::Array<uint8_t>>
- transport_properties) override;
- void DeleteWindow(uint32_t change_id, Id transport_window_id) override;
- void AddWindow(uint32_t change_id, Id parent_id, Id child_id) override;
- void RemoveWindowFromParent(uint32_t change_id, Id window_id) override;
- void AddTransientWindow(uint32_t change_id,
- Id window,
- Id transient_window) override;
- void RemoveTransientWindowFromParent(uint32_t change_id,
- Id transient_window_id) override;
- void SetModal(uint32_t change_id, Id window_id) override;
- void ReorderWindow(uint32_t change_Id,
- Id window_id,
- Id relative_window_id,
- mojom::OrderDirection direction) override;
- void GetWindowTree(
- Id window_id,
- const base::Callback<void(mojo::Array<mojom::WindowDataPtr>)>& callback)
- override;
- void SetCapture(uint32_t change_id, Id window_id) override;
- void ReleaseCapture(uint32_t change_id, Id window_id) override;
- void SetEventObserver(mojom::EventMatcherPtr matcher,
- uint32_t observer_id) override;
- void SetWindowBounds(uint32_t change_id,
- Id window_id,
- const gfx::Rect& bounds) override;
- void SetWindowVisibility(uint32_t change_id,
- Id window_id,
- bool visible) override;
- void SetWindowProperty(uint32_t change_id,
- Id transport_window_id,
- const mojo::String& name,
- mojo::Array<uint8_t> value) override;
- void SetWindowOpacity(uint32_t change_id,
- Id window_id,
- float opacity) override;
- void AttachSurface(Id transport_window_id,
- mojom::SurfaceType type,
- mojo::InterfaceRequest<mojom::Surface> surface,
- mojom::SurfaceClientPtr client) override;
- void Embed(Id transport_window_id,
- mojom::WindowTreeClientPtr client,
- uint32_t flags,
- const EmbedCallback& callback) override;
- void SetFocus(uint32_t change_id, Id transport_window_id) override;
- void SetCanFocus(Id transport_window_id, bool can_focus) override;
- void SetPredefinedCursor(uint32_t change_id,
- Id transport_window_id,
- mus::mojom::Cursor cursor_id) override;
- void SetWindowTextInputState(Id transport_window_id,
- mojo::TextInputStatePtr state) override;
- void SetImeVisibility(Id transport_window_id,
- bool visible,
- mojo::TextInputStatePtr state) override;
- void OnWindowInputEventAck(uint32_t event_id,
- mojom::EventResult result) override;
- void SetClientArea(
- Id transport_window_id,
- const gfx::Insets& insets,
- mojo::Array<gfx::Rect> transport_additional_client_areas) override;
- void SetHitTestMask(Id transport_window_id, const gfx::Rect& mask) override;
- void GetWindowManagerClient(
- mojo::AssociatedInterfaceRequest<mojom::WindowManagerClient> internal)
- override;
- void GetCursorLocationMemory(const GetCursorLocationMemoryCallback& callback)
- override;
-
- // mojom::WindowManagerClient:
- void AddAccelerator(uint32_t id,
- mojom::EventMatcherPtr event_matcher,
- const AddAcceleratorCallback& callback) override;
- void RemoveAccelerator(uint32_t id) override;
- void AddActivationParent(Id transport_window_id) override;
- void RemoveActivationParent(Id transport_window_id) override;
- void ActivateNextWindow() override;
- void SetUnderlaySurfaceOffsetAndExtendedHitArea(
- Id window_id,
- int32_t x_offset,
- int32_t y_offset,
- const gfx::Insets& hit_area) override;
- void WmResponse(uint32_t change_id, bool response) override;
- void WmRequestClose(Id transport_window_id) override;
- void WmSetFrameDecorationValues(
- mojom::FrameDecorationValuesPtr values) override;
- void WmSetNonClientCursor(uint32_t window_id,
- mojom::Cursor cursor_id) override;
- void OnWmCreatedTopLevelWindow(uint32_t change_id,
- Id transport_window_id) override;
-
- // AccessPolicyDelegate:
- bool HasRootForAccessPolicy(const ServerWindow* window) const override;
- bool IsWindowKnownForAccessPolicy(const ServerWindow* window) const override;
- bool IsWindowRootOfAnotherTreeForAccessPolicy(
- const ServerWindow* window) const override;
-
- WindowServer* window_server_;
-
- UserId user_id_;
-
- // Id of this tree as assigned by WindowServer.
- const ClientSpecificId id_;
- std::string name_;
-
- ClientSpecificId next_window_id_;
-
- std::unique_ptr<WindowTreeBinding> binding_;
-
- std::unique_ptr<mus::ws::AccessPolicy> access_policy_;
-
- // The roots, or embed points, of this tree. A WindowTree may have any
- // number of roots, including 0.
- std::set<const ServerWindow*> roots_;
-
- // The windows created by this tree. This tree owns these objects.
- base::hash_map<WindowId, ServerWindow*> created_window_map_;
-
- // The client is allowed to assign ids. These two maps providing the mapping
- // from the ids native to the server (WindowId) to those understood by the
- // client (ClientWindowId).
- base::hash_map<ClientWindowId, WindowId> client_id_to_window_id_map_;
- base::hash_map<WindowId, ClientWindowId> window_id_to_client_id_map_;
-
- uint32_t event_ack_id_;
-
- // A client is considered janky if it hasn't ACK'ed input events within a
- // reasonable timeframe.
- bool janky_ = false;
-
- // Set when the client is using SetEventObserver() to observe events,
- // otherwise null.
- std::unique_ptr<EventMatcher> event_observer_matcher_;
-
- // The ID supplied by the client for the current event observer.
- uint32_t event_observer_id_ = 0;
-
- // WindowManager the current event came from.
- WindowManagerState* event_source_wms_ = nullptr;
-
- std::queue<std::unique_ptr<TargetedEvent>> event_queue_;
-
- std::unique_ptr<mojo::AssociatedBinding<mojom::WindowManagerClient>>
- window_manager_internal_client_binding_;
- mojom::WindowManager* window_manager_internal_;
- std::unique_ptr<WindowManagerState> window_manager_state_;
-
- std::unique_ptr<WaitingForTopLevelWindowInfo>
- waiting_for_top_level_window_info_;
- bool embedder_intercepts_events_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTree);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_TREE_H_
diff --git a/chromium/components/mus/ws/window_tree_binding.cc b/chromium/components/mus/ws/window_tree_binding.cc
deleted file mode 100644
index 6f64a9f895f..00000000000
--- a/chromium/components/mus/ws/window_tree_binding.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/mus/ws/window_tree_binding.h"
-
-#include "base/bind.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_tree.h"
-
-namespace mus {
-namespace ws {
-
-WindowTreeBinding::WindowTreeBinding(mojom::WindowTreeClient* client)
- : client_(client) {}
-
-WindowTreeBinding::~WindowTreeBinding() {}
-
-DefaultWindowTreeBinding::DefaultWindowTreeBinding(
- WindowTree* tree,
- WindowServer* window_server,
- mojom::WindowTreeRequest service_request,
- mojom::WindowTreeClientPtr client)
- : WindowTreeBinding(client.get()),
- binding_(tree, std::move(service_request)),
- client_(std::move(client)) {
- // Both |window_server| and |tree| outlive us.
- binding_.set_connection_error_handler(
- base::Bind(&WindowServer::DestroyTree, base::Unretained(window_server),
- base::Unretained(tree)));
-}
-
-DefaultWindowTreeBinding::DefaultWindowTreeBinding(
- WindowTree* tree,
- mojom::WindowTreeClientPtr client)
- : WindowTreeBinding(client.get()),
- binding_(tree),
- client_(std::move(client)) {}
-
-DefaultWindowTreeBinding::~DefaultWindowTreeBinding() {}
-
-void DefaultWindowTreeBinding::SetIncomingMethodCallProcessingPaused(
- bool paused) {
- if (paused)
- binding_.PauseIncomingMethodCallProcessing();
- else
- binding_.ResumeIncomingMethodCallProcessing();
-}
-
-mojom::WindowTreePtr DefaultWindowTreeBinding::CreateInterfacePtrAndBind() {
- DCHECK(!binding_.is_bound());
- return binding_.CreateInterfacePtrAndBind();
-}
-
-mojom::WindowManager* DefaultWindowTreeBinding::GetWindowManager() {
- client_->GetWindowManager(
- GetProxy(&window_manager_internal_, client_.associated_group()));
- return window_manager_internal_.get();
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_tree_binding.h b/chromium/components/mus/ws/window_tree_binding.h
deleted file mode 100644
index a9472b3566c..00000000000
--- a/chromium/components/mus/ws/window_tree_binding.h
+++ /dev/null
@@ -1,72 +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 COMPONENTS_MUS_WS_WINDOW_TREE_BINDING_H_
-#define COMPONENTS_MUS_WS_WINDOW_TREE_BINDING_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace mus {
-namespace ws {
-
-class WindowServer;
-class WindowTree;
-
-// WindowTreeBinding manages the binding between a WindowTree and its
-// WindowTreeClient. WindowTreeBinding exists so that a mock implementation
-// of WindowTreeClient can be injected for tests. WindowTree owns its
-// associated WindowTreeBinding.
-class WindowTreeBinding {
- public:
- explicit WindowTreeBinding(mojom::WindowTreeClient* client);
- virtual ~WindowTreeBinding();
-
- mojom::WindowTreeClient* client() { return client_; }
-
- // Obtains a new WindowManager. This should only be called once.
- virtual mojom::WindowManager* GetWindowManager() = 0;
-
- virtual void SetIncomingMethodCallProcessingPaused(bool paused) = 0;
-
- private:
- mojom::WindowTreeClient* client_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTreeBinding);
-};
-
-// Bindings implementation of WindowTreeBinding.
-class DefaultWindowTreeBinding : public WindowTreeBinding {
- public:
- DefaultWindowTreeBinding(WindowTree* tree,
- WindowServer* window_server,
- mojom::WindowTreeRequest service_request,
- mojom::WindowTreeClientPtr client);
- DefaultWindowTreeBinding(WindowTree* tree,
- mojom::WindowTreeClientPtr client);
- ~DefaultWindowTreeBinding() override;
-
- // Use when created with the constructor that does not take a
- // WindowTreeRequest.
- mojom::WindowTreePtr CreateInterfacePtrAndBind();
-
- // WindowTreeBinding:
- mojom::WindowManager* GetWindowManager() override;
- void SetIncomingMethodCallProcessingPaused(bool paused) override;
-
- private:
- mojo::Binding<mojom::WindowTree> binding_;
- mojom::WindowTreeClientPtr client_;
- mojom::WindowManagerAssociatedPtr window_manager_internal_;
-
- DISALLOW_COPY_AND_ASSIGN(DefaultWindowTreeBinding);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_TREE_BINDING_H_
diff --git a/chromium/components/mus/ws/window_tree_client_unittest.cc b/chromium/components/mus/ws/window_tree_client_unittest.cc
deleted file mode 100644
index 34169dd2152..00000000000
--- a/chromium/components/mus/ws/window_tree_client_unittest.cc
+++ /dev/null
@@ -1,2042 +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 <stddef.h>
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
-#include "components/mus/public/cpp/tests/window_server_shelltest_base.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/public/interfaces/window_tree_host.mojom.h"
-#include "components/mus/ws/ids.h"
-#include "components/mus/ws/test_change_tracker.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "services/shell/public/cpp/shell_test.h"
-
-using mojo::Array;
-using shell::Connection;
-using mojo::InterfaceRequest;
-using shell::ShellClient;
-using mojo::String;
-using mus::mojom::WindowDataPtr;
-using mus::mojom::WindowTree;
-using mus::mojom::WindowTreeClient;
-
-namespace mus {
-namespace ws {
-namespace test {
-
-namespace {
-
-// Creates an id used for transport from the specified parameters.
-Id BuildWindowId(ClientSpecificId client_id,
- ClientSpecificId window_id) {
- return (client_id << 16) | window_id;
-}
-
-// Callback function from WindowTree functions.
-// ----------------------------------
-
-void WindowTreeResultCallback(base::RunLoop* run_loop,
- std::vector<TestWindow>* windows,
- Array<WindowDataPtr> results) {
- WindowDatasToTestWindows(results, windows);
- run_loop->Quit();
-}
-
-void EmbedCallbackImpl(base::RunLoop* run_loop,
- bool* result_cache,
- bool result) {
- *result_cache = result;
- run_loop->Quit();
-}
-
-// -----------------------------------------------------------------------------
-
-bool EmbedUrl(shell::Connector* connector,
- WindowTree* tree,
- const String& url,
- Id root_id) {
- bool result = false;
- base::RunLoop run_loop;
- {
- mojom::WindowTreeClientPtr client;
- connector->ConnectToInterface(url.get(), &client);
- const uint32_t embed_flags = 0;
- tree->Embed(root_id, std::move(client), embed_flags,
- base::Bind(&EmbedCallbackImpl, &run_loop, &result));
- }
- run_loop.Run();
- return result;
-}
-
-bool Embed(WindowTree* tree, Id root_id, mojom::WindowTreeClientPtr client) {
- bool result = false;
- base::RunLoop run_loop;
- {
- const uint32_t embed_flags = 0;
- tree->Embed(root_id, std::move(client), embed_flags,
- base::Bind(&EmbedCallbackImpl, &run_loop, &result));
- }
- run_loop.Run();
- return result;
-}
-
-void GetWindowTree(WindowTree* tree,
- Id window_id,
- std::vector<TestWindow>* windows) {
- base::RunLoop run_loop;
- tree->GetWindowTree(
- window_id, base::Bind(&WindowTreeResultCallback, &run_loop, windows));
- run_loop.Run();
-}
-
-// Utility functions -----------------------------------------------------------
-
-const Id kNullParentId = 0;
-std::string IdToString(Id id) {
- return (id == kNullParentId) ? "null" : base::StringPrintf(
- "%d,%d", HiWord(id), LoWord(id));
-}
-
-std::string WindowParentToString(Id window, Id parent) {
- return base::StringPrintf("window=%s parent=%s", IdToString(window).c_str(),
- IdToString(parent).c_str());
-}
-
-// -----------------------------------------------------------------------------
-
-// A WindowTreeClient implementation that logs all changes to a tracker.
-class TestWindowTreeClient : public mojom::WindowTreeClient,
- public TestChangeTracker::Delegate,
- public mojom::WindowManager {
- public:
- TestWindowTreeClient()
- : binding_(this),
- client_id_(0),
- root_window_id_(0),
- // Start with a random large number so tests can use lower ids if they
- // want.
- next_change_id_(10000),
- waiting_change_id_(0),
- on_change_completed_result_(false),
- track_root_bounds_changes_(false) {
- tracker_.set_delegate(this);
- }
-
- void Bind(mojo::InterfaceRequest<mojom::WindowTreeClient> request) {
- binding_.Bind(std::move(request));
- }
-
- mojom::WindowTree* tree() { return tree_.get(); }
- TestChangeTracker* tracker() { return &tracker_; }
- Id root_window_id() const { return root_window_id_; }
-
- // Sets whether changes to the bounds of the root should be tracked. Normally
- // they are ignored (as during startup we often times get random size
- // changes).
- void set_track_root_bounds_changes(bool value) {
- track_root_bounds_changes_ = value;
- }
-
- // Runs a nested MessageLoop until |count| changes (calls to
- // WindowTreeClient functions) have been received.
- void WaitForChangeCount(size_t count) {
- if (tracker_.changes()->size() >= count)
- return;
-
- ASSERT_TRUE(wait_state_.get() == nullptr);
- wait_state_.reset(new WaitState);
- wait_state_->change_count = count;
- wait_state_->run_loop.Run();
- wait_state_.reset();
- }
-
- uint32_t GetAndAdvanceChangeId() { return next_change_id_++; }
-
- // Runs a nested MessageLoop until OnEmbed() has been encountered.
- void WaitForOnEmbed() {
- if (tree_)
- return;
- embed_run_loop_.reset(new base::RunLoop);
- embed_run_loop_->Run();
- embed_run_loop_.reset();
- }
-
- bool WaitForChangeCompleted(uint32_t id) {
- waiting_change_id_ = id;
- change_completed_run_loop_.reset(new base::RunLoop);
- change_completed_run_loop_->Run();
- return on_change_completed_result_;
- }
-
- bool DeleteWindow(Id id) {
- const uint32_t change_id = GetAndAdvanceChangeId();
- tree()->DeleteWindow(change_id, id);
- return WaitForChangeCompleted(change_id);
- }
-
- bool AddWindow(Id parent, Id child) {
- const uint32_t change_id = GetAndAdvanceChangeId();
- tree()->AddWindow(change_id, parent, child);
- return WaitForChangeCompleted(change_id);
- }
-
- bool RemoveWindowFromParent(Id window_id) {
- const uint32_t change_id = GetAndAdvanceChangeId();
- tree()->RemoveWindowFromParent(change_id, window_id);
- return WaitForChangeCompleted(change_id);
- }
-
- bool ReorderWindow(Id window_id,
- Id relative_window_id,
- mojom::OrderDirection direction) {
- const uint32_t change_id = GetAndAdvanceChangeId();
- tree()->ReorderWindow(change_id, window_id, relative_window_id, direction);
- return WaitForChangeCompleted(change_id);
- }
-
- // Waits for all messages to be received by |ws|. This is done by attempting
- // to create a bogus window. When we get the response we know all messages
- // have been processed.
- bool WaitForAllMessages() {
- return NewWindowWithCompleteId(WindowIdToTransportId(InvalidWindowId())) ==
- 0;
- }
-
- Id NewWindow(ClientSpecificId window_id) {
- return NewWindowWithCompleteId(BuildWindowId(client_id_, window_id));
- }
-
- // Generally you want NewWindow(), but use this if you need to test given
- // a complete window id (NewWindow() ors with the client id).
- Id NewWindowWithCompleteId(Id id) {
- mojo::Map<mojo::String, mojo::Array<uint8_t>> properties;
- const uint32_t change_id = GetAndAdvanceChangeId();
- tree()->NewWindow(change_id, id, std::move(properties));
- return WaitForChangeCompleted(change_id) ? id : 0;
- }
-
- bool SetWindowProperty(Id window_id,
- const std::string& name,
- const std::vector<uint8_t>* data) {
- Array<uint8_t> mojo_data(nullptr);
- if (data)
- mojo_data = Array<uint8_t>::From(*data);
- const uint32_t change_id = GetAndAdvanceChangeId();
- tree()->SetWindowProperty(change_id, window_id, name, std::move(mojo_data));
- return WaitForChangeCompleted(change_id);
- }
-
- bool SetPredefinedCursor(Id window_id, mojom::Cursor cursor) {
- const uint32_t change_id = GetAndAdvanceChangeId();
- tree()->SetPredefinedCursor(change_id, window_id, cursor);
- return WaitForChangeCompleted(change_id);
- }
-
- bool SetWindowVisibility(Id window_id, bool visible) {
- const uint32_t change_id = GetAndAdvanceChangeId();
- tree()->SetWindowVisibility(change_id, window_id, visible);
- return WaitForChangeCompleted(change_id);
- }
-
- bool SetWindowOpacity(Id window_id, float opacity) {
- const uint32_t change_id = GetAndAdvanceChangeId();
- tree()->SetWindowOpacity(change_id, window_id, opacity);
- return WaitForChangeCompleted(change_id);
- }
-
- private:
- // Used when running a nested MessageLoop.
- struct WaitState {
- WaitState() : change_count(0) {}
-
- // Number of changes waiting for.
- size_t change_count;
- base::RunLoop run_loop;
- };
-
- // TestChangeTracker::Delegate:
- void OnChangeAdded() override {
- if (wait_state_.get() &&
- tracker_.changes()->size() >= wait_state_->change_count) {
- wait_state_->run_loop.Quit();
- }
- }
-
- // WindowTreeClient:
- void OnEmbed(ClientSpecificId client_id,
- WindowDataPtr root,
- mojom::WindowTreePtr tree,
- int64_t display_id,
- Id focused_window_id,
- bool drawn) override {
- // TODO(sky): add coverage of |focused_window_id|.
- ASSERT_TRUE(root);
- root_window_id_ = root->window_id;
- tree_ = std::move(tree);
- client_id_ = client_id;
- tracker()->OnEmbed(client_id, std::move(root), drawn);
- if (embed_run_loop_)
- embed_run_loop_->Quit();
- }
- void OnEmbeddedAppDisconnected(Id window_id) override {
- tracker()->OnEmbeddedAppDisconnected(window_id);
- }
- void OnUnembed(Id window_id) override { tracker()->OnUnembed(window_id); }
- void OnLostCapture(Id window_id) override {
- tracker()->OnLostCapture(window_id);
- }
- void OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr data,
- int64_t display_id,
- bool drawn) override {
- tracker()->OnTopLevelCreated(change_id, std::move(data), drawn);
- }
- void OnWindowBoundsChanged(Id window_id,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) override {
- // The bounds of the root may change during startup on Android at random
- // times. As this doesn't matter, and shouldn't impact test exepctations,
- // it is ignored.
- if (window_id == root_window_id_ && !track_root_bounds_changes_)
- return;
- tracker()->OnWindowBoundsChanged(window_id, old_bounds, new_bounds);
- }
- void OnClientAreaChanged(
- uint32_t window_id,
- const gfx::Insets& new_client_area,
- mojo::Array<gfx::Rect> new_additional_client_areas) override {}
- void OnTransientWindowAdded(uint32_t window_id,
- uint32_t transient_window_id) override {
- tracker()->OnTransientWindowAdded(window_id, transient_window_id);
- }
- void OnTransientWindowRemoved(uint32_t window_id,
- uint32_t transient_window_id) override {
- tracker()->OnTransientWindowRemoved(window_id, transient_window_id);
- }
- void OnWindowHierarchyChanged(Id window,
- Id old_parent,
- Id new_parent,
- Array<WindowDataPtr> windows) override {
- tracker()->OnWindowHierarchyChanged(window, old_parent, new_parent,
- std::move(windows));
- }
- void OnWindowReordered(Id window_id,
- Id relative_window_id,
- mojom::OrderDirection direction) override {
- tracker()->OnWindowReordered(window_id, relative_window_id, direction);
- }
- void OnWindowDeleted(Id window) override {
- tracker()->OnWindowDeleted(window);
- }
- void OnWindowVisibilityChanged(uint32_t window, bool visible) override {
- tracker()->OnWindowVisibilityChanged(window, visible);
- }
- void OnWindowOpacityChanged(uint32_t window,
- float old_opacity,
- float new_opacity) override {
- tracker()->OnWindowOpacityChanged(window, new_opacity);
- }
- void OnWindowParentDrawnStateChanged(uint32_t window, bool drawn) override {
- tracker()->OnWindowParentDrawnStateChanged(window, drawn);
- }
- void OnWindowInputEvent(uint32_t event_id,
- Id window_id,
- std::unique_ptr<ui::Event> event,
- uint32_t event_observer_id) override {
- // Ack input events to clear the state on the server. These can be received
- // during test startup. X11Window::DispatchEvent sends a synthetic move
- // event to notify of entry.
- tree()->OnWindowInputEventAck(event_id, mojom::EventResult::HANDLED);
- // Don't log input events as none of the tests care about them and they
- // may come in at random points.
- }
- void OnEventObserved(std::unique_ptr<ui::Event>,
- uint32_t event_observer_id) override {}
- void OnWindowSharedPropertyChanged(uint32_t window,
- const String& name,
- Array<uint8_t> new_data) override {
- tracker_.OnWindowSharedPropertyChanged(window, name, std::move(new_data));
- }
- // TODO(sky): add testing coverage.
- void OnWindowFocused(uint32_t focused_window_id) override {}
- void OnWindowPredefinedCursorChanged(uint32_t window_id,
- mojom::Cursor cursor_id) override {
- tracker_.OnWindowPredefinedCursorChanged(window_id, cursor_id);
- }
- void OnChangeCompleted(uint32_t change_id, bool success) override {
- if (waiting_change_id_ == change_id && change_completed_run_loop_) {
- on_change_completed_result_ = success;
- change_completed_run_loop_->Quit();
- }
- }
- void RequestClose(uint32_t window_id) override {}
- void GetWindowManager(mojo::AssociatedInterfaceRequest<mojom::WindowManager>
- internal) override {
- window_manager_binding_.reset(
- new mojo::AssociatedBinding<mojom::WindowManager>(this,
- std::move(internal)));
- tree_->GetWindowManagerClient(
- GetProxy(&window_manager_client_, tree_.associated_group()));
- }
-
- // mojom::WindowManager:
- void OnConnect(uint16_t client_id) override {}
- void WmNewDisplayAdded(mojom::DisplayPtr display,
- mojom::WindowDataPtr root_data,
- bool drawn) override {
- NOTIMPLEMENTED();
- }
- void WmSetBounds(uint32_t change_id,
- uint32_t window_id,
- const gfx::Rect& bounds) override {
- window_manager_client_->WmResponse(change_id, false);
- }
- void WmSetProperty(uint32_t change_id,
- uint32_t window_id,
- const mojo::String& name,
- mojo::Array<uint8_t> value) override {
- window_manager_client_->WmResponse(change_id, false);
- }
- void WmCreateTopLevelWindow(
- uint32_t change_id,
- ClientSpecificId requesting_client_id,
- mojo::Map<mojo::String, mojo::Array<uint8_t>> properties) override {
- NOTIMPLEMENTED();
- }
- void WmClientJankinessChanged(ClientSpecificId client_id,
- bool janky) override {
- NOTIMPLEMENTED();
- }
- void OnAccelerator(uint32_t id, std::unique_ptr<ui::Event> event) override {
- NOTIMPLEMENTED();
- }
-
- TestChangeTracker tracker_;
-
- mojom::WindowTreePtr tree_;
-
- // If non-null we're waiting for OnEmbed() using this RunLoop.
- std::unique_ptr<base::RunLoop> embed_run_loop_;
-
- // If non-null we're waiting for a certain number of change notifications to
- // be encountered.
- std::unique_ptr<WaitState> wait_state_;
-
- mojo::Binding<WindowTreeClient> binding_;
- Id client_id_;
- Id root_window_id_;
- uint32_t next_change_id_;
- uint32_t waiting_change_id_;
- bool on_change_completed_result_;
- bool track_root_bounds_changes_;
- std::unique_ptr<base::RunLoop> change_completed_run_loop_;
-
- std::unique_ptr<mojo::AssociatedBinding<mojom::WindowManager>>
- window_manager_binding_;
- mojom::WindowManagerClientAssociatedPtr window_manager_client_;
-
- DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClient);
-};
-
-// -----------------------------------------------------------------------------
-
-// InterfaceFactory for vending TestWindowTreeClients.
-class WindowTreeClientFactory
- : public shell::InterfaceFactory<WindowTreeClient> {
- public:
- WindowTreeClientFactory() {}
- ~WindowTreeClientFactory() override {}
-
- // Runs a nested MessageLoop until a new instance has been created.
- std::unique_ptr<TestWindowTreeClient> WaitForInstance() {
- if (!client_impl_.get()) {
- DCHECK(!run_loop_);
- run_loop_.reset(new base::RunLoop);
- run_loop_->Run();
- run_loop_.reset();
- }
- return std::move(client_impl_);
- }
-
- private:
- // InterfaceFactory<WindowTreeClient>:
- void Create(Connection* connection,
- InterfaceRequest<WindowTreeClient> request) override {
- client_impl_.reset(new TestWindowTreeClient());
- client_impl_->Bind(std::move(request));
- if (run_loop_.get())
- run_loop_->Quit();
- }
-
- std::unique_ptr<TestWindowTreeClient> client_impl_;
- std::unique_ptr<base::RunLoop> run_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTreeClientFactory);
-};
-
-} // namespace
-
-class WindowTreeClientTest : public WindowServerShellTestBase {
- public:
- WindowTreeClientTest()
- : client_id_1_(0), client_id_2_(0), root_window_id_(0) {}
-
- ~WindowTreeClientTest() override {}
-
- protected:
- // Returns the changes from the various clients.
- std::vector<Change>* changes1() { return wt_client1_->tracker()->changes(); }
- std::vector<Change>* changes2() { return wt_client2_->tracker()->changes(); }
- std::vector<Change>* changes3() { return wt_client3_->tracker()->changes(); }
-
- // Various clients. |wt1()|, being the first client, has special permissions
- // (it's treated as the window manager).
- WindowTree* wt1() { return wt_client1_->tree(); }
- WindowTree* wt2() { return wt_client2_->tree(); }
- WindowTree* wt3() { return wt_client3_->tree(); }
-
- TestWindowTreeClient* wt_client1() { return wt_client1_.get(); }
- TestWindowTreeClient* wt_client2() { return wt_client2_.get(); }
- TestWindowTreeClient* wt_client3() { return wt_client3_.get(); }
-
- Id root_window_id() const { return root_window_id_; }
-
- int client_id_1() const { return client_id_1_; }
- int client_id_2() const { return client_id_2_; }
-
- void EstablishSecondClientWithRoot(Id root_id) {
- ASSERT_TRUE(wt_client2_.get() == nullptr);
- wt_client2_ =
- EstablishClientViaEmbed(wt1(), root_id, &client_id_2_);
- ASSERT_GT(client_id_2_, 0);
- ASSERT_TRUE(wt_client2_.get() != nullptr);
- }
-
- void EstablishSecondClient(bool create_initial_window) {
- Id window_1_1 = 0;
- if (create_initial_window) {
- window_1_1 = wt_client1()->NewWindow(1);
- ASSERT_TRUE(window_1_1);
- }
- ASSERT_NO_FATAL_FAILURE(
- EstablishSecondClientWithRoot(BuildWindowId(client_id_1(), 1)));
-
- if (create_initial_window) {
- EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]",
- ChangeWindowDescription(*changes2()));
- }
- }
-
- void EstablishThirdClient(WindowTree* owner, Id root_id) {
- ASSERT_TRUE(wt_client3_.get() == nullptr);
- wt_client3_ = EstablishClientViaEmbed(owner, root_id, nullptr);
- ASSERT_TRUE(wt_client3_.get() != nullptr);
- }
-
- std::unique_ptr<TestWindowTreeClient> WaitForWindowTreeClient() {
- return client_factory_->WaitForInstance();
- }
-
- // Establishes a new client by way of Embed() on the specified WindowTree.
- std::unique_ptr<TestWindowTreeClient> EstablishClientViaEmbed(
- WindowTree* owner,
- Id root_id,
- int* client_id) {
- return EstablishClientViaEmbedWithPolicyBitmask(owner, root_id, client_id);
- }
-
- std::unique_ptr<TestWindowTreeClient>
- EstablishClientViaEmbedWithPolicyBitmask(WindowTree* owner,
- Id root_id,
- int* client_id) {
- if (!EmbedUrl(connector(), owner, test_name(), root_id)) {
- ADD_FAILURE() << "Embed() failed";
- return nullptr;
- }
- std::unique_ptr<TestWindowTreeClient> client =
- client_factory_->WaitForInstance();
- if (!client.get()) {
- ADD_FAILURE() << "WaitForInstance failed";
- return nullptr;
- }
- client->WaitForOnEmbed();
-
- EXPECT_EQ("OnEmbed",
- SingleChangeToDescription(*client->tracker()->changes()));
- if (client_id)
- *client_id = (*client->tracker()->changes())[0].client_id;
- return client;
- }
-
- // WindowServerShellTestBase:
- bool AcceptConnection(shell::Connection* connection) override {
- connection->AddInterface(client_factory_.get());
- return true;
- }
-
- void SetUp() override {
- client_factory_.reset(new WindowTreeClientFactory());
-
- WindowServerShellTestBase::SetUp();
-
- mojom::WindowTreeHostFactoryPtr factory;
- connector()->ConnectToInterface("mojo:mus", &factory);
-
- mojom::WindowTreeClientPtr tree_client_ptr;
- wt_client1_.reset(new TestWindowTreeClient());
- wt_client1_->Bind(GetProxy(&tree_client_ptr));
-
- factory->CreateWindowTreeHost(GetProxy(&host_),
- std::move(tree_client_ptr));
-
- // Next we should get an embed call on the "window manager" client.
- wt_client1_->WaitForOnEmbed();
-
- ASSERT_EQ(1u, changes1()->size());
- EXPECT_EQ(CHANGE_TYPE_EMBED, (*changes1())[0].type);
- // All these tests assume 1 for the client id. The only real assertion here
- // is the client id is not zero, but adding this as rest of code here
- // assumes 1.
- ASSERT_GT((*changes1())[0].client_id, 0);
- client_id_1_ = (*changes1())[0].client_id;
- ASSERT_FALSE((*changes1())[0].windows.empty());
- root_window_id_ = (*changes1())[0].windows[0].window_id;
- ASSERT_EQ(root_window_id_, wt_client1_->root_window_id());
- changes1()->clear();
- }
-
- void TearDown() override {
- // Destroy these before the message loop is destroyed (happens in
- // WindowServerShellTestBase::TearDown).
- wt_client1_.reset();
- wt_client2_.reset();
- wt_client3_.reset();
- client_factory_.reset();
- WindowServerShellTestBase::TearDown();
- }
-
- std::unique_ptr<TestWindowTreeClient> wt_client1_;
- std::unique_ptr<TestWindowTreeClient> wt_client2_;
- std::unique_ptr<TestWindowTreeClient> wt_client3_;
-
- mojom::WindowTreeHostPtr host_;
-
- private:
- std::unique_ptr<WindowTreeClientFactory> client_factory_;
- int client_id_1_;
- int client_id_2_;
- Id root_window_id_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTreeClientTest);
-};
-
-// Verifies two clients get different ids.
-TEST_F(WindowTreeClientTest, TwoClientsGetDifferentClientIds) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
-
- ASSERT_EQ(1u, changes2()->size());
- ASSERT_NE(client_id_1(), client_id_2());
-}
-
-// Verifies when Embed() is invoked any child windows are removed.
-TEST_F(WindowTreeClientTest, WindowsRemovedWhenEmbedding) {
- // Two windows 1 and 2. 2 is parented to 1.
- Id window_1_1 = wt_client1()->NewWindow(1);
- ASSERT_TRUE(window_1_1);
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
-
- Id window_1_2 = wt_client1()->NewWindow(2);
- ASSERT_TRUE(window_1_2);
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
-
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
- ASSERT_EQ(1u, changes2()->size());
- ASSERT_EQ(1u, (*changes2())[0].windows.size());
- EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]",
- ChangeWindowDescription(*changes2()));
-
- // Embed() removed window 2.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), window_1_2, &windows);
- EXPECT_EQ(WindowParentToString(window_1_2, kNullParentId),
- SingleWindowDescription(windows));
- }
-
- // ws2 should not see window 2.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt2(), window_1_1, &windows);
- EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
- SingleWindowDescription(windows));
- }
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt2(), window_1_2, &windows);
- EXPECT_TRUE(windows.empty());
- }
-
- // Windows 3 and 4 in client 2.
- Id window_2_3 = wt_client2()->NewWindow(3);
- Id window_2_4 = wt_client2()->NewWindow(4);
- ASSERT_TRUE(window_2_3);
- ASSERT_TRUE(window_2_4);
- ASSERT_TRUE(wt_client2()->AddWindow(window_2_3, window_2_4));
-
- // Client 3 rooted at 2.
- ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_3));
-
- // Window 4 should no longer have a parent.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt2(), window_2_3, &windows);
- EXPECT_EQ(WindowParentToString(window_2_3, kNullParentId),
- SingleWindowDescription(windows));
-
- windows.clear();
- GetWindowTree(wt2(), window_2_4, &windows);
- EXPECT_EQ(WindowParentToString(window_2_4, kNullParentId),
- SingleWindowDescription(windows));
- }
-
- // And window 4 should not be visible to client 3.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt3(), window_2_3, &windows);
- EXPECT_EQ("no windows", SingleWindowDescription(windows));
- }
-}
-
-// Verifies once Embed() has been invoked the parent client can't see any
-// children.
-TEST_F(WindowTreeClientTest, CantAccessChildrenOfEmbeddedWindow) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
-
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- Id window_2_2 = wt_client2()->NewWindow(2);
- ASSERT_TRUE(window_2_2);
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
-
- ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_2));
-
- Id window_3_3 = wt_client3()->NewWindow(3);
- ASSERT_TRUE(window_3_3);
- ASSERT_TRUE(
- wt_client3()->AddWindow(wt_client3()->root_window_id(), window_3_3));
-
- // Even though 3 is a child of 2 client 2 can't see 3 as it's from a
- // different client.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt2(), window_2_2, &windows);
- EXPECT_EQ(WindowParentToString(window_2_2, window_1_1),
- SingleWindowDescription(windows));
- }
-
- // Client 2 shouldn't be able to get window 3 at all.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt2(), window_3_3, &windows);
- EXPECT_TRUE(windows.empty());
- }
-
- // Client 1 should be able to see it all (its the root).
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), window_1_1, &windows);
- ASSERT_EQ(3u, windows.size());
- EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
- windows[0].ToString());
- // NOTE: we expect a match of WindowParentToString(window_2_2, window_1_1),
- // but the ids are in the id space of client2, which is not the same as
- // the id space of wt1().
- EXPECT_EQ("window=2,1 parent=1,1", windows[1].ToString());
- // Same thing here, we really want to test for
- // WindowParentToString(window_3_3, window_2_2).
- EXPECT_EQ("window=3,1 parent=2,1", windows[2].ToString());
- }
-}
-
-// Verifies once Embed() has been invoked the parent can't mutate the children.
-TEST_F(WindowTreeClientTest, CantModifyChildrenOfEmbeddedWindow) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
-
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- Id window_2_1 = wt_client2()->NewWindow(1);
- ASSERT_TRUE(window_2_1);
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
-
- ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_1));
-
- Id window_2_2 = wt_client2()->NewWindow(2);
- ASSERT_TRUE(window_2_2);
- // Client 2 shouldn't be able to add anything to the window anymore.
- ASSERT_FALSE(wt_client2()->AddWindow(window_2_1, window_2_2));
-
- // Create window 3 in client 3 and add it to window 3.
- Id window_3_1 = wt_client3()->NewWindow(1);
- ASSERT_TRUE(window_3_1);
- ASSERT_TRUE(wt_client3()->AddWindow(window_2_1, window_3_1));
-
- // Client 2 shouldn't be able to remove window 3.
- ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_3_1));
-}
-
-// Verifies client gets a valid id.
-TEST_F(WindowTreeClientTest, NewWindow) {
- Id window_1_1 = wt_client1()->NewWindow(1);
- ASSERT_TRUE(window_1_1);
- EXPECT_TRUE(changes1()->empty());
-
- // Can't create a window with the same id.
- ASSERT_EQ(0u, wt_client1()->NewWindowWithCompleteId(window_1_1));
- EXPECT_TRUE(changes1()->empty());
-
- // Can't create a window with a bogus client id.
- ASSERT_EQ(0u, wt_client1()->NewWindowWithCompleteId(
- BuildWindowId(client_id_1() + 1, 1)));
- EXPECT_TRUE(changes1()->empty());
-}
-
-// Verifies AddWindow fails when window is already in position.
-TEST_F(WindowTreeClientTest, AddWindowWithNoChange) {
- // Create the embed point now so that the ids line up.
- ASSERT_TRUE(wt_client1()->NewWindow(1));
- Id window_1_2 = wt_client1()->NewWindow(2);
- Id window_1_3 = wt_client1()->NewWindow(3);
- ASSERT_TRUE(window_1_2);
- ASSERT_TRUE(window_1_3);
-
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
-
- // Make 3 a child of 2.
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_2, window_1_3));
-
- // Try again, this should fail.
- EXPECT_FALSE(wt_client1()->AddWindow(window_1_2, window_1_3));
-}
-
-// Verifies AddWindow fails when window is already in position.
-TEST_F(WindowTreeClientTest, AddAncestorFails) {
- // Create the embed point now so that the ids line up.
- ASSERT_TRUE(wt_client1()->NewWindow(1));
- Id window_1_2 = wt_client1()->NewWindow(2);
- Id window_1_3 = wt_client1()->NewWindow(3);
- ASSERT_TRUE(window_1_2);
- ASSERT_TRUE(window_1_3);
-
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
-
- // Make 3 a child of 2.
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_2, window_1_3));
-
- // Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3.
- EXPECT_FALSE(wt_client1()->AddWindow(window_1_3, window_1_2));
-}
-
-// Verifies adding to root sends right notifications.
-TEST_F(WindowTreeClientTest, AddToRoot) {
- // Create the embed point now so that the ids line up.
- Id window_1_1 = wt_client1()->NewWindow(1);
- ASSERT_TRUE(window_1_1);
- Id window_1_21 = wt_client1()->NewWindow(21);
- Id window_1_3 = wt_client1()->NewWindow(3);
- ASSERT_TRUE(window_1_21);
- ASSERT_TRUE(window_1_3);
-
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
- changes2()->clear();
-
- // Make 3 a child of 21.
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_21, window_1_3));
-
- // Make 21 a child of 1.
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_21));
-
- // Client 2 should not be told anything (because the window is from a
- // different client). Create a window to ensure we got a response from
- // the server.
- ASSERT_TRUE(wt_client2()->NewWindow(100));
- EXPECT_TRUE(changes2()->empty());
-}
-
-// Verifies HierarchyChanged is correctly sent for various adds/removes.
-TEST_F(WindowTreeClientTest, WindowHierarchyChangedWindows) {
- // Create the embed point now so that the ids line up.
- Id window_1_1 = wt_client1()->NewWindow(1);
- // 1,2->1,11.
- Id window_1_2 = wt_client1()->NewWindow(2);
- ASSERT_TRUE(window_1_2);
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
- Id window_1_11 = wt_client1()->NewWindow(11);
- ASSERT_TRUE(window_1_11);
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_11, true));
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_2, window_1_11));
-
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
-
- ASSERT_TRUE(wt_client2()->WaitForAllMessages());
- changes2()->clear();
-
- // 1,1->1,2->1,11
- {
- // Client 2 should not get anything (1,2 is from another client).
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
- ASSERT_TRUE(wt_client2()->WaitForAllMessages());
- EXPECT_TRUE(changes2()->empty());
- }
-
- // 0,1->1,1->1,2->1,11.
- {
- // Client 2 is now connected to the root, so it should have gotten a drawn
- // notification.
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- wt_client2_->WaitForChangeCount(1u);
- EXPECT_EQ(
- "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=true",
- SingleChangeToDescription(*changes2()));
- }
-
- // 1,1->1,2->1,11.
- {
- // Client 2 is no longer connected to the root, should get drawn state
- // changed.
- changes2()->clear();
- ASSERT_TRUE(wt_client1()->RemoveWindowFromParent(window_1_1));
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=false",
- SingleChangeToDescription(*changes2()));
- }
-
- // 1,1->1,2->1,11->1,111.
- Id window_1_111 = wt_client1()->NewWindow(111);
- ASSERT_TRUE(window_1_111);
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_111, true));
- {
- changes2()->clear();
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_11, window_1_111));
- ASSERT_TRUE(wt_client2()->WaitForAllMessages());
- EXPECT_TRUE(changes2()->empty());
- }
-
- // 0,1->1,1->1,2->1,11->1,111
- {
- changes2()->clear();
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=true",
- SingleChangeToDescription(*changes2()));
- }
-}
-
-TEST_F(WindowTreeClientTest, WindowHierarchyChangedAddingKnownToUnknown) {
- // Create the following structure: root -> 1 -> 11 and 2->21 (2 has no
- // parent).
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
-
- Id window_2_11 = wt_client2()->NewWindow(11);
- Id window_2_2 = wt_client2()->NewWindow(2);
- Id window_2_21 = wt_client2()->NewWindow(21);
- ASSERT_TRUE(window_2_11);
- ASSERT_TRUE(window_2_2);
- ASSERT_TRUE(window_2_21);
-
- // Set up the hierarchy.
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_11));
- ASSERT_TRUE(wt_client2()->AddWindow(window_2_2, window_2_21));
-
- // Remove 11, should result in a hierarchy change for the root.
- {
- changes1()->clear();
- ASSERT_TRUE(wt_client2()->RemoveWindowFromParent(window_2_11));
-
- wt_client1_->WaitForChangeCount(1);
- // 2,1 should be IdToString(window_2_11), but window_2_11 is in the id
- // space of client2, not client1.
- EXPECT_EQ("HierarchyChanged window=2,1 old_parent=" +
- IdToString(window_1_1) + " new_parent=null",
- SingleChangeToDescription(*changes1()));
- }
-
- // Add 2 to 1.
- {
- changes1()->clear();
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_2) +
- " old_parent=null new_parent=" + IdToString(window_1_1),
- SingleChangeToDescription(*changes1()));
- // "window=2,3 parent=2,2]" should be,
- // WindowParentToString(window_2_21, window_2_2), but isn't because of
- // differing id spaces.
- EXPECT_EQ("[" + WindowParentToString(window_2_2, window_1_1) +
- "],[window=2,3 parent=2,2]",
- ChangeWindowDescription(*changes1()));
- }
-}
-
-TEST_F(WindowTreeClientTest, ReorderWindow) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
-
- Id window_2_1 = wt_client2()->NewWindow(1);
- Id window_2_2 = wt_client2()->NewWindow(2);
- Id window_2_3 = wt_client2()->NewWindow(3);
- Id window_1_4 = wt_client1()->NewWindow(4); // Peer to 1,1
- Id window_1_5 = wt_client1()->NewWindow(5); // Peer to 1,1
- Id window_2_6 = wt_client2()->NewWindow(6); // Child of 1,2.
- Id window_2_7 = wt_client2()->NewWindow(7); // Unparented.
- Id window_2_8 = wt_client2()->NewWindow(8); // Unparented.
- ASSERT_TRUE(window_2_1);
- ASSERT_TRUE(window_2_2);
- ASSERT_TRUE(window_2_3);
- ASSERT_TRUE(window_1_4);
- ASSERT_TRUE(window_1_5);
- ASSERT_TRUE(window_2_6);
- ASSERT_TRUE(window_2_7);
- ASSERT_TRUE(window_2_8);
-
- ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_2));
- ASSERT_TRUE(wt_client2()->AddWindow(window_2_2, window_2_6));
- ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_3));
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_4));
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_5));
- ASSERT_TRUE(
- wt_client2()->AddWindow(BuildWindowId(client_id_1(), 1), window_2_1));
-
- {
- changes1()->clear();
- ASSERT_TRUE(wt_client2()->ReorderWindow(window_2_2, window_2_3,
- mojom::OrderDirection::ABOVE));
-
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("Reordered window=" + IdToString(window_2_2) + " relative=" +
- IdToString(window_2_3) + " direction=above",
- SingleChangeToDescription(*changes1()));
- }
-
- {
- changes1()->clear();
- ASSERT_TRUE(wt_client2()->ReorderWindow(window_2_2, window_2_3,
- mojom::OrderDirection::BELOW));
-
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("Reordered window=" + IdToString(window_2_2) + " relative=" +
- IdToString(window_2_3) + " direction=below",
- SingleChangeToDescription(*changes1()));
- }
-
- // view2 is already below view3.
- EXPECT_FALSE(wt_client2()->ReorderWindow(window_2_2, window_2_3,
- mojom::OrderDirection::BELOW));
-
- // view4 & 5 are unknown to client 2.
- EXPECT_FALSE(wt_client2()->ReorderWindow(window_1_4, window_1_5,
- mojom::OrderDirection::ABOVE));
-
- // view6 & view3 have different parents.
- EXPECT_FALSE(wt_client1()->ReorderWindow(window_2_3, window_2_6,
- mojom::OrderDirection::ABOVE));
-
- // Non-existent window-ids
- EXPECT_FALSE(wt_client1()->ReorderWindow(BuildWindowId(client_id_1(), 27),
- BuildWindowId(client_id_1(), 28),
- mojom::OrderDirection::ABOVE));
-
- // view7 & view8 are un-parented.
- EXPECT_FALSE(wt_client1()->ReorderWindow(window_2_7, window_2_8,
- mojom::OrderDirection::ABOVE));
-}
-
-// Verifies DeleteWindow works.
-TEST_F(WindowTreeClientTest, DeleteWindow) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- Id window_2_1 = wt_client2()->NewWindow(1);
- ASSERT_TRUE(window_2_1);
-
- // Make 2 a child of 1.
- {
- changes1()->clear();
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_1) +
- " old_parent=null new_parent=" + IdToString(window_1_1),
- SingleChangeToDescription(*changes1()));
- }
-
- // Delete 2.
- {
- changes1()->clear();
- changes2()->clear();
- ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1));
- EXPECT_TRUE(changes2()->empty());
-
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_1),
- SingleChangeToDescription(*changes1()));
- }
-}
-
-// Verifies DeleteWindow isn't allowed from a separate client.
-TEST_F(WindowTreeClientTest, DeleteWindowFromAnotherClientDisallowed) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- EXPECT_FALSE(wt_client2()->DeleteWindow(BuildWindowId(client_id_1(), 1)));
-}
-
-// Verifies if a window was deleted and then reused that other clients are
-// properly notified.
-TEST_F(WindowTreeClientTest, ReuseDeletedWindowId) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- Id window_2_1 = wt_client2()->NewWindow(1);
- ASSERT_TRUE(window_2_1);
-
- // Add 2 to 1.
- {
- changes1()->clear();
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_1) +
- " old_parent=null new_parent=" + IdToString(window_1_1),
- SingleChangeToDescription(*changes1()));
- EXPECT_EQ("[" + WindowParentToString(window_2_1, window_1_1) + "]",
- ChangeWindowDescription(*changes1()));
- }
-
- // Delete 2.
- {
- changes1()->clear();
- ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1));
-
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_1),
- SingleChangeToDescription(*changes1()));
- }
-
- // Create 2 again, and add it back to 1. Should get the same notification.
- window_2_1 = wt_client2()->NewWindow(2);
- ASSERT_TRUE(window_2_1);
- {
- changes1()->clear();
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
-
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_1) +
- " old_parent=null new_parent=" + IdToString(window_1_1),
- SingleChangeToDescription(*changes1()));
- EXPECT_EQ("[" + WindowParentToString(window_2_1, window_1_1) + "]",
- ChangeWindowDescription(*changes1()));
- }
-}
-
-// Assertions for GetWindowTree.
-TEST_F(WindowTreeClientTest, GetWindowTree) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
-
- // Create 11 in first client and make it a child of 1.
- Id window_1_11 = wt_client1()->NewWindow(11);
- ASSERT_TRUE(window_1_11);
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_11));
-
- // Create two windows in second client, 2 and 3, both children of 1.
- Id window_2_1 = wt_client2()->NewWindow(1);
- Id window_2_2 = wt_client2()->NewWindow(2);
- ASSERT_TRUE(window_2_1);
- ASSERT_TRUE(window_2_2);
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
-
- // Verifies GetWindowTree() on the root. The root client sees all.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), root_window_id(), &windows);
- ASSERT_EQ(5u, windows.size());
- EXPECT_EQ(WindowParentToString(root_window_id(), kNullParentId),
- windows[0].ToString());
- EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()),
- windows[1].ToString());
- EXPECT_EQ(WindowParentToString(window_1_11, window_1_1),
- windows[2].ToString());
- EXPECT_EQ(WindowParentToString(window_2_1, window_1_1),
- windows[3].ToString());
- EXPECT_EQ(WindowParentToString(window_2_2, window_1_1),
- windows[4].ToString());
- }
-
- // Verifies GetWindowTree() on the window 1,1 from wt2(). wt2() sees 1,1 as
- // 1,1
- // is wt2()'s root and wt2() sees all the windows it created.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt2(), window_1_1, &windows);
- ASSERT_EQ(3u, windows.size());
- EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
- windows[0].ToString());
- EXPECT_EQ(WindowParentToString(window_2_1, window_1_1),
- windows[1].ToString());
- EXPECT_EQ(WindowParentToString(window_2_2, window_1_1),
- windows[2].ToString());
- }
-
- // Client 2 shouldn't be able to get the root tree.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt2(), root_window_id(), &windows);
- ASSERT_EQ(0u, windows.size());
- }
-}
-
-TEST_F(WindowTreeClientTest, SetWindowBounds) {
- Id window_1_1 = wt_client1()->NewWindow(1);
- ASSERT_TRUE(window_1_1);
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
-
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
-
- changes2()->clear();
-
- wt_client2_->set_track_root_bounds_changes(true);
-
- wt1()->SetWindowBounds(10, window_1_1, gfx::Rect(0, 0, 100, 100));
- ASSERT_TRUE(wt_client1()->WaitForChangeCompleted(10));
-
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ("BoundsChanged window=" + IdToString(window_1_1) +
- " old_bounds=0,0 0x0 new_bounds=0,0 100x100",
- SingleChangeToDescription(*changes2()));
-
- // Should not be possible to change the bounds of a window created by another
- // client.
- wt2()->SetWindowBounds(11, window_1_1, gfx::Rect(0, 0, 0, 0));
- ASSERT_FALSE(wt_client2()->WaitForChangeCompleted(11));
-}
-
-// Verify AddWindow fails when trying to manipulate windows in other roots.
-TEST_F(WindowTreeClientTest, CantMoveWindowsFromOtherRoot) {
- // Create 1 and 2 in the first client.
- Id window_1_1 = wt_client1()->NewWindow(1);
- Id window_1_2 = wt_client1()->NewWindow(2);
- ASSERT_TRUE(window_1_1);
- ASSERT_TRUE(window_1_2);
-
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
-
- // Try to move 2 to be a child of 1 from client 2. This should fail as 2
- // should not be able to access 1.
- ASSERT_FALSE(wt_client2()->AddWindow(window_1_1, window_1_2));
-
- // Try to reparent 1 to the root. A client is not allowed to reparent its
- // roots.
- ASSERT_FALSE(wt_client2()->AddWindow(root_window_id(), window_1_1));
-}
-
-// Verify RemoveWindowFromParent fails for windows that are descendants of the
-// roots.
-TEST_F(WindowTreeClientTest, CantRemoveWindowsInOtherRoots) {
- // Create 1 and 2 in the first client and parent both to the root.
- Id window_1_1 = wt_client1()->NewWindow(1);
- Id window_1_2 = wt_client1()->NewWindow(2);
- ASSERT_TRUE(window_1_1);
- ASSERT_TRUE(window_1_2);
-
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2));
-
- // Establish the second client and give it the root 1.
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
-
- // Client 2 should not be able to remove window 2 or 1 from its parent.
- ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_1_2));
- ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_1_1));
-
- // Create windows 10 and 11 in 2.
- Id window_2_10 = wt_client2()->NewWindow(10);
- Id window_2_11 = wt_client2()->NewWindow(11);
- ASSERT_TRUE(window_2_10);
- ASSERT_TRUE(window_2_11);
-
- // Parent 11 to 10.
- ASSERT_TRUE(wt_client2()->AddWindow(window_2_10, window_2_11));
- // Remove 11 from 10.
- ASSERT_TRUE(wt_client2()->RemoveWindowFromParent(window_2_11));
-
- // Verify nothing was actually removed.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), root_window_id(), &windows);
- ASSERT_EQ(3u, windows.size());
- EXPECT_EQ(WindowParentToString(root_window_id(), kNullParentId),
- windows[0].ToString());
- EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()),
- windows[1].ToString());
- EXPECT_EQ(WindowParentToString(window_1_2, root_window_id()),
- windows[2].ToString());
- }
-}
-
-// Verify GetWindowTree fails for windows that are not descendants of the roots.
-TEST_F(WindowTreeClientTest, CantGetWindowTreeOfOtherRoots) {
- // Create 1 and 2 in the first client and parent both to the root.
- Id window_1_1 = wt_client1()->NewWindow(1);
- Id window_1_2 = wt_client1()->NewWindow(2);
- ASSERT_TRUE(window_1_1);
- ASSERT_TRUE(window_1_2);
-
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2));
-
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
-
- std::vector<TestWindow> windows;
-
- // Should get nothing for the root.
- GetWindowTree(wt2(), root_window_id(), &windows);
- ASSERT_TRUE(windows.empty());
-
- // Should get nothing for window 2.
- GetWindowTree(wt2(), window_1_2, &windows);
- ASSERT_TRUE(windows.empty());
-
- // Should get window 1 if asked for.
- GetWindowTree(wt2(), window_1_1, &windows);
- ASSERT_EQ(1u, windows.size());
- EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
- windows[0].ToString());
-}
-
-TEST_F(WindowTreeClientTest, EmbedWithSameWindowId) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- changes2()->clear();
-
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt1(), window_1_1));
-
- // Client 2 should have been told of the unembed and delete.
- {
- wt_client2_->WaitForChangeCount(2);
- EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1),
- ChangesToDescription1(*changes2())[0]);
- EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1),
- ChangesToDescription1(*changes2())[1]);
- }
-
- // Client 2 has no root. Verify it can't see window 1,1 anymore.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt2(), window_1_1, &windows);
- EXPECT_TRUE(windows.empty());
- }
-}
-
-TEST_F(WindowTreeClientTest, EmbedWithSameWindowId2) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- changes2()->clear();
-
- ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt1(), window_1_1));
-
- // Client 2 should have been told about the unembed and delete.
- wt_client2_->WaitForChangeCount(2);
- changes2()->clear();
-
- // Create a window in the third client and parent it to the root.
- Id window_3_1 = wt_client3()->NewWindow(1);
- ASSERT_TRUE(window_3_1);
- ASSERT_TRUE(wt_client3()->AddWindow(window_1_1, window_3_1));
-
- // Client 1 should have been told about the add (it owns the window).
- {
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("HierarchyChanged window=" + IdToString(window_3_1) +
- " old_parent=null new_parent=" + IdToString(window_1_1),
- SingleChangeToDescription(*changes1()));
- }
-
- // Embed 1,1 again.
- {
- changes3()->clear();
-
- // We should get a new client for the new embedding.
- std::unique_ptr<TestWindowTreeClient> client4(
- EstablishClientViaEmbed(wt1(), window_1_1, nullptr));
- ASSERT_TRUE(client4.get());
- EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]",
- ChangeWindowDescription(*client4->tracker()->changes()));
-
- // And 3 should get an unembed and delete.
- wt_client3_->WaitForChangeCount(2);
- EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1),
- ChangesToDescription1(*changes3())[0]);
- EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1),
- ChangesToDescription1(*changes3())[1]);
- }
-
- // wt3() has no root. Verify it can't see window 1,1 anymore.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt3(), window_1_1, &windows);
- EXPECT_TRUE(windows.empty());
- }
-
- // Verify 3,1 is no longer parented to 1,1. We have to do this from 1,1 as
- // wt3() can no longer see 1,1.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), window_1_1, &windows);
- ASSERT_EQ(1u, windows.size());
- EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
- windows[0].ToString());
- }
-
- // Verify wt3() can still see the window it created 3,1.
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt3(), window_3_1, &windows);
- ASSERT_EQ(1u, windows.size());
- EXPECT_EQ(WindowParentToString(window_3_1, kNullParentId),
- windows[0].ToString());
- }
-}
-
-// Assertions for SetWindowVisibility.
-TEST_F(WindowTreeClientTest, SetWindowVisibility) {
- // Create 1 and 2 in the first client and parent both to the root.
- Id window_1_1 = wt_client1()->NewWindow(1);
- Id window_1_2 = wt_client1()->NewWindow(2);
- ASSERT_TRUE(window_1_1);
- ASSERT_TRUE(window_1_2);
-
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), root_window_id(), &windows);
- ASSERT_EQ(2u, windows.size());
- EXPECT_EQ(
- WindowParentToString(root_window_id(), kNullParentId) + " visible=true",
- windows[0].ToString2());
- EXPECT_EQ(
- WindowParentToString(window_1_1, root_window_id()) + " visible=false",
- windows[1].ToString2());
- }
-
- // Show all the windows.
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), root_window_id(), &windows);
- ASSERT_EQ(2u, windows.size());
- EXPECT_EQ(
- WindowParentToString(root_window_id(), kNullParentId) + " visible=true",
- windows[0].ToString2());
- EXPECT_EQ(
- WindowParentToString(window_1_1, root_window_id()) + " visible=true",
- windows[1].ToString2());
- }
-
- // Hide 1.
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, false));
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), window_1_1, &windows);
- ASSERT_EQ(1u, windows.size());
- EXPECT_EQ(
- WindowParentToString(window_1_1, root_window_id()) + " visible=false",
- windows[0].ToString2());
- }
-
- // Attach 2 to 1.
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), window_1_1, &windows);
- ASSERT_EQ(2u, windows.size());
- EXPECT_EQ(
- WindowParentToString(window_1_1, root_window_id()) + " visible=false",
- windows[0].ToString2());
- EXPECT_EQ(WindowParentToString(window_1_2, window_1_1) + " visible=true",
- windows[1].ToString2());
- }
-
- // Show 1.
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), window_1_1, &windows);
- ASSERT_EQ(2u, windows.size());
- EXPECT_EQ(
- WindowParentToString(window_1_1, root_window_id()) + " visible=true",
- windows[0].ToString2());
- EXPECT_EQ(WindowParentToString(window_1_2, window_1_1) + " visible=true",
- windows[1].ToString2());
- }
-}
-
-// Test that we hear the cursor change in other clients.
-TEST_F(WindowTreeClientTest, SetCursor) {
- // Get a second client to listen in.
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- changes2()->clear();
-
- ASSERT_TRUE(
- wt_client1()->SetPredefinedCursor(window_1_1, mojom::Cursor::IBEAM));
- wt_client2_->WaitForChangeCount(1u);
-
- EXPECT_EQ("CursorChanged id=" + IdToString(window_1_1) + " cursor_id=4",
- SingleChangeToDescription(*changes2()));
-}
-
-// Assertions for SetWindowVisibility sending notifications.
-TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications) {
- // Create 1,1 and 1,2. 1,2 is made a child of 1,1 and 1,1 a child of the root.
- Id window_1_1 = wt_client1()->NewWindow(1);
- ASSERT_TRUE(window_1_1);
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
- // Setting to the same value should return true.
- EXPECT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
-
- Id window_1_2 = wt_client1()->NewWindow(2);
- ASSERT_TRUE(window_1_2);
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
-
- // Establish the second client at 1,2.
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2));
-
- // Add 2,3 as a child of 1,2.
- Id window_2_1 = wt_client2()->NewWindow(1);
- ASSERT_TRUE(window_2_1);
- ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_2_1, true));
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_2, window_2_1));
- ASSERT_TRUE(wt_client1()->WaitForAllMessages());
-
- changes2()->clear();
- // Hide 1,2 from client 1. Client 2 should see this.
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, false));
- {
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "VisibilityChanged window=" + IdToString(window_1_2) + " visible=false",
- SingleChangeToDescription(*changes2()));
- }
-
- changes1()->clear();
- // Show 1,2 from client 2, client 1 should be notified.
- ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_1_2, true));
- {
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ(
- "VisibilityChanged window=" + IdToString(window_1_2) + " visible=true",
- SingleChangeToDescription(*changes1()));
- }
-
- changes2()->clear();
- // Hide 1,1, client 2 should be told the draw state changed.
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, false));
- {
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=false",
- SingleChangeToDescription(*changes2()));
- }
-
- changes2()->clear();
- // Show 1,1 from client 1. Client 2 should see this.
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
- {
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=true",
- SingleChangeToDescription(*changes2()));
- }
-
- // Change visibility of 2,3, client 1 should see this.
- changes1()->clear();
- ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_2_1, false));
- {
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ(
- "VisibilityChanged window=" + IdToString(window_2_1) + " visible=false",
- SingleChangeToDescription(*changes1()));
- }
-
- changes2()->clear();
- // Remove 1,1 from the root, client 2 should see drawn state changed.
- ASSERT_TRUE(wt_client1()->RemoveWindowFromParent(window_1_1));
- {
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=false",
- SingleChangeToDescription(*changes2()));
- }
-
- changes2()->clear();
- // Add 1,1 back to the root, client 2 should see drawn state changed.
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- {
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=true",
- SingleChangeToDescription(*changes2()));
- }
-}
-
-// Assertions for SetWindowVisibility sending notifications.
-TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications2) {
- // Create 1,1 and 1,2. 1,2 is made a child of 1,1 and 1,1 a child of the root.
- Id window_1_1 = wt_client1()->NewWindow(1);
- ASSERT_TRUE(window_1_1);
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
- Id window_1_2 = wt_client1()->NewWindow(2);
- ASSERT_TRUE(window_1_2);
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
-
- // Establish the second client at 1,2.
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2));
- EXPECT_EQ("OnEmbed drawn=true", SingleChangeToDescription2(*changes2()));
- changes2()->clear();
-
- // Show 1,2 from client 1. Client 2 should see this.
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
- {
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "VisibilityChanged window=" + IdToString(window_1_2) + " visible=true",
- SingleChangeToDescription(*changes2()));
- }
-}
-
-// Assertions for SetWindowVisibility sending notifications.
-TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications3) {
- // Create 1,1 and 1,2. 1,2 is made a child of 1,1 and 1,1 a child of the root.
- Id window_1_1 = wt_client1()->NewWindow(1);
- ASSERT_TRUE(window_1_1);
- Id window_1_2 = wt_client1()->NewWindow(2);
- ASSERT_TRUE(window_1_2);
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
-
- // Establish the second client at 1,2.
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2));
- EXPECT_EQ("OnEmbed drawn=false", SingleChangeToDescription2(*changes2()));
- changes2()->clear();
-
- // Show 1,1, drawn should be true for 1,2 (as that is all the child sees).
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
- {
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=true",
- SingleChangeToDescription(*changes2()));
- }
- changes2()->clear();
-
- // Show 1,2, visible should be true.
- ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
- {
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "VisibilityChanged window=" + IdToString(window_1_2) + " visible=true",
- SingleChangeToDescription(*changes2()));
- }
-}
-
-// Tests that when opacity is set on a window, that the calling client is not
-// notified, however children are. Also that setting the same opacity is
-// rejected and no on eis notifiyed.
-TEST_F(WindowTreeClientTest, SetOpacityNotifications) {
- Id window_1_1 = wt_client1()->NewWindow(1);
- ASSERT_TRUE(window_1_1);
-
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_1));
- Id window_2_1 = wt_client2()->NewWindow(1);
- ASSERT_TRUE(window_2_1);
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
- ASSERT_TRUE(wt_client1()->WaitForAllMessages());
-
- changes1()->clear();
- changes2()->clear();
- // Change opacity, no notification for calling client.
- ASSERT_TRUE(wt_client1()->SetWindowOpacity(window_1_1, 0.5f));
- EXPECT_TRUE(changes1()->empty());
- wt_client2()->WaitForChangeCount(1);
- EXPECT_EQ(
- "OpacityChanged window_id=" + IdToString(window_1_1) + " opacity=0.50",
- SingleChangeToDescription(*changes2()));
-
- changes2()->clear();
- // Attempting to set the same opacity should succeed, but no notification as
- // there was no actual change.
- ASSERT_TRUE(wt_client1()->SetWindowOpacity(window_1_1, 0.5f));
- EXPECT_TRUE(changes1()->empty());
- wt_client2()->WaitForAllMessages();
- EXPECT_TRUE(changes2()->empty());
-}
-
-TEST_F(WindowTreeClientTest, SetWindowProperty) {
- Id window_1_1 = wt_client1()->NewWindow(1);
- ASSERT_TRUE(window_1_1);
-
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
- changes2()->clear();
-
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), root_window_id(), &windows);
- ASSERT_EQ(2u, windows.size());
- EXPECT_EQ(root_window_id(), windows[0].window_id);
- EXPECT_EQ(window_1_1, windows[1].window_id);
- ASSERT_EQ(0u, windows[1].properties.size());
- }
-
- // Set properties on 1.
- changes2()->clear();
- std::vector<uint8_t> one(1, '1');
- ASSERT_TRUE(wt_client1()->SetWindowProperty(window_1_1, "one", &one));
- {
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ(
- "PropertyChanged window=" + IdToString(window_1_1) + " key=one value=1",
- SingleChangeToDescription(*changes2()));
- }
-
- // Test that our properties exist in the window tree
- {
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), window_1_1, &windows);
- ASSERT_EQ(1u, windows.size());
- ASSERT_EQ(1u, windows[0].properties.size());
- EXPECT_EQ(one, windows[0].properties["one"]);
- }
-
- changes2()->clear();
- // Set back to null.
- ASSERT_TRUE(wt_client1()->SetWindowProperty(window_1_1, "one", NULL));
- {
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ("PropertyChanged window=" + IdToString(window_1_1) +
- " key=one value=NULL",
- SingleChangeToDescription(*changes2()));
- }
-}
-
-TEST_F(WindowTreeClientTest, OnEmbeddedAppDisconnected) {
- // Create client 2 and 3.
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- Id window_2_1 = wt_client2()->NewWindow(1);
- ASSERT_TRUE(window_2_1);
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
- changes2()->clear();
- ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_1));
-
- // Client 1 should get a hierarchy change for window_2_1.
- wt_client1_->WaitForChangeCount(1);
- changes1()->clear();
-
- // Close client 3. Client 2 (which had previously embedded 3) should
- // be notified of this.
- wt_client3_.reset();
- wt_client2_->WaitForChangeCount(1);
- EXPECT_EQ("OnEmbeddedAppDisconnected window=" + IdToString(window_2_1),
- SingleChangeToDescription(*changes2()));
-
- // The closing is only interesting to the root that did the embedding. Other
- // clients should not be notified of this.
- wt_client1_->WaitForAllMessages();
- EXPECT_TRUE(changes1()->empty());
-}
-
-// Verifies when the parent of an Embed() is destroyed the embedded app gets
-// a WindowDeleted (and doesn't trigger a DCHECK).
-TEST_F(WindowTreeClientTest, OnParentOfEmbedDisconnects) {
- // Create client 2 and 3.
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- Id window_2_1 = wt_client2()->NewWindow(1);
- Id window_2_2 = wt_client2()->NewWindow(2);
- ASSERT_TRUE(window_2_1);
- ASSERT_TRUE(window_2_2);
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
- ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_2));
- changes2()->clear();
- ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_2));
- changes3()->clear();
-
- // Close client 2. Client 3 should get a delete (for its root).
- wt_client2_.reset();
- wt_client3_->WaitForChangeCount(1);
- EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_2),
- SingleChangeToDescription(*changes3()));
-}
-
-// Verifies WindowTreeImpl doesn't incorrectly erase from its internal
-// map when a window from another client with the same window_id is removed.
-TEST_F(WindowTreeClientTest, DontCleanMapOnDestroy) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- ASSERT_TRUE(wt_client2()->NewWindow(1));
- changes1()->clear();
- wt_client2_.reset();
- wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("OnEmbeddedAppDisconnected window=" + IdToString(window_1_1),
- SingleChangeToDescription(*changes1()));
- std::vector<TestWindow> windows;
- GetWindowTree(wt1(), window_1_1, &windows);
- EXPECT_FALSE(windows.empty());
-}
-
-// Verifies Embed() works when supplying a WindowTreeClient.
-TEST_F(WindowTreeClientTest, EmbedSupplyingWindowTreeClient) {
- ASSERT_TRUE(wt_client1()->NewWindow(1));
-
- TestWindowTreeClient client2;
- mojom::WindowTreeClientPtr client2_ptr;
- mojo::Binding<WindowTreeClient> client2_binding(&client2, &client2_ptr);
- ASSERT_TRUE(Embed(wt1(), BuildWindowId(client_id_1(), 1),
- std::move(client2_ptr)));
- client2.WaitForOnEmbed();
- EXPECT_EQ("OnEmbed",
- SingleChangeToDescription(*client2.tracker()->changes()));
-}
-
-TEST_F(WindowTreeClientTest, EmbedFailsFromOtherClient) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
-
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- Id window_2_1 = wt_client2()->NewWindow(1);
- ASSERT_TRUE(window_2_1);
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
- ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_1));
-
- Id window_3_3 = wt_client3()->NewWindow(3);
- ASSERT_TRUE(window_3_3);
- ASSERT_TRUE(wt_client3()->AddWindow(window_2_1, window_3_3));
-
- // 2 should not be able to embed in window_3_3 as window_3_3 was not created
- // by
- // 2.
- EXPECT_FALSE(EmbedUrl(connector(), wt2(), test_name(), window_3_3));
-}
-
-// Verifies Embed() from window manager on another clients window works.
-TEST_F(WindowTreeClientTest, EmbedFromOtherClient) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
-
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
- Id window_2_1 = wt_client2()->NewWindow(1);
- ASSERT_TRUE(window_2_1);
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
-
- changes2()->clear();
-
- // Establish a third client in window_2_1.
- ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt1(), window_2_1));
-
- ASSERT_TRUE(wt_client2()->WaitForAllMessages());
- EXPECT_EQ(std::string(), SingleChangeToDescription(*changes2()));
-}
-
-TEST_F(WindowTreeClientTest, CantEmbedFromClientRoot) {
- // Shouldn't be able to embed into the root.
- ASSERT_FALSE(EmbedUrl(connector(), wt1(), test_name(), root_window_id()));
-
- // Even though the call above failed a WindowTreeClient was obtained. We need
- // to
- // wait for it else we throw off the next connect.
- WaitForWindowTreeClient();
-
- // Don't allow a client to embed into its own root.
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- EXPECT_FALSE(EmbedUrl(connector(), wt2(), test_name(),
- BuildWindowId(client_id_1(), 1)));
-
- // Need to wait for a WindowTreeClient for same reason as above.
- WaitForWindowTreeClient();
-
- Id window_1_2 = wt_client1()->NewWindow(2);
- ASSERT_TRUE(window_1_2);
- ASSERT_TRUE(
- wt_client1()->AddWindow(BuildWindowId(client_id_1(), 1), window_1_2));
- ASSERT_TRUE(wt_client3_.get() == nullptr);
- wt_client3_ =
- EstablishClientViaEmbedWithPolicyBitmask(wt1(), window_1_2, nullptr);
- ASSERT_TRUE(wt_client3_.get() != nullptr);
-
- // window_1_2 is ws3's root, so even though v3 is an embed root it should not
- // be able to Embed into itself.
- ASSERT_FALSE(EmbedUrl(connector(), wt3(), test_name(), window_1_2));
-}
-
-// Verifies that a transient window tracks its parent's lifetime.
-TEST_F(WindowTreeClientTest, TransientWindowTracksTransientParentLifetime) {
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
- Id window_1_1 = BuildWindowId(client_id_1(), 1);
-
- Id window_2_1 = wt_client2()->NewWindow(1);
- Id window_2_2 = wt_client2()->NewWindow(2);
- Id window_2_3 = wt_client2()->NewWindow(3);
- ASSERT_TRUE(window_2_1);
-
- // root -> window_1_1 -> window_2_1
- // root -> window_1_1 -> window_2_2
- // root -> window_1_1 -> window_2_3
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_3));
-
- // window_2_2 and window_2_3 now track the lifetime of window_2_1.
- changes1()->clear();
- wt2()->AddTransientWindow(10, window_2_1, window_2_2);
- wt2()->AddTransientWindow(11, window_2_1, window_2_3);
- wt_client1()->WaitForChangeCount(2);
- EXPECT_EQ("AddTransientWindow parent = " + IdToString(window_2_1) +
- " child = " + IdToString(window_2_2),
- ChangesToDescription1(*changes1())[0]);
- EXPECT_EQ("AddTransientWindow parent = " + IdToString(window_2_1) +
- " child = " + IdToString(window_2_3),
- ChangesToDescription1(*changes1())[1]);
-
- changes1()->clear();
- wt2()->RemoveTransientWindowFromParent(12, window_2_3);
- wt_client1()->WaitForChangeCount(1);
- EXPECT_EQ("RemoveTransientWindowFromParent parent = " +
- IdToString(window_2_1) + " child = " + IdToString(window_2_3),
- SingleChangeToDescription(*changes1()));
-
- changes1()->clear();
- ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1));
- wt_client1()->WaitForChangeCount(2);
- EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_2),
- ChangesToDescription1(*changes1())[0]);
- EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_1),
- ChangesToDescription1(*changes1())[1]);
-}
-
-TEST_F(WindowTreeClientTest, Ids) {
- const Id window_1_100 = wt_client1()->NewWindow(100);
- ASSERT_TRUE(window_1_100);
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_100));
-
- // Establish the second client at 1,100.
- ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_100));
-
- // 1,100 is the id in the wt_client1's id space. The new client should see
- // 2,1 (the server id).
- const Id window_1_100_in_ws2 = BuildWindowId(client_id_1(), 1);
- EXPECT_EQ(window_1_100_in_ws2, wt_client2()->root_window_id());
-
- // The first window created in the second client gets a server id of 2,1
- // regardless of the id the client uses.
- const Id window_2_101 = wt_client2()->NewWindow(101);
- ASSERT_TRUE(wt_client2()->AddWindow(window_1_100_in_ws2, window_2_101));
- const Id window_2_101_in_ws1 = BuildWindowId(client_id_2(), 1);
- wt_client1()->WaitForChangeCount(1);
- EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_101_in_ws1) +
- " old_parent=null new_parent=" + IdToString(window_1_100),
- SingleChangeToDescription(*changes1()));
- changes1()->clear();
-
- // Change the bounds of window_2_101 and make sure server gets it.
- wt2()->SetWindowBounds(11, window_2_101, gfx::Rect(1, 2, 3, 4));
- ASSERT_TRUE(wt_client2()->WaitForChangeCompleted(11));
- wt_client1()->WaitForChangeCount(1);
- EXPECT_EQ("BoundsChanged window=" + IdToString(window_2_101_in_ws1) +
- " old_bounds=0,0 0x0 new_bounds=1,2 3x4",
- SingleChangeToDescription(*changes1()));
- changes2()->clear();
-
- // Remove 2_101 from wm, client1 should see the change.
- wt1()->RemoveWindowFromParent(12, window_2_101_in_ws1);
- ASSERT_TRUE(wt_client1()->WaitForChangeCompleted(12));
- wt_client2()->WaitForChangeCount(1);
- EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_101) +
- " old_parent=" + IdToString(window_1_100_in_ws2) +
- " new_parent=null",
- SingleChangeToDescription(*changes2()));
-}
-
-// Tests that setting capture fails when no input event has occurred, and there
-// is no notification of lost capture.
-TEST_F(WindowTreeClientTest, ExplicitCaptureWithoutInput) {
- Id window_1_1 = wt_client1()->NewWindow(1);
-
- // Add the window to the root, so that they have a Display to handle input
- // capture.
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- changes1()->clear();
-
- // Since there has been no input, capture should not succeed. No lost capture
- // message is expected.
- wt1()->SetCapture(1, window_1_1);
- wt_client1_->WaitForAllMessages();
- EXPECT_TRUE(changes1()->empty());
-
- // Since there is no window with capture, lost capture should not be notified.
- wt1()->ReleaseCapture(3, window_1_1);
- wt_client1_->WaitForAllMessages();
- EXPECT_TRUE(changes1()->empty());
-}
-
-// TODO(jonross): Enable this once apptests can send input events to the server.
-// Enabling capture requires that the client be processing events.
-TEST_F(WindowTreeClientTest, DISABLED_ExplicitCapturePropagation) {
- Id window_1_1 = wt_client1()->NewWindow(1);
- Id window_1_2 = wt_client1()->NewWindow(2);
-
- // Add the windows to the root, so that they have a Display to handle input
- // capture.
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
- ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2));
-
- changes1()->clear();
- // Window 1 takes capture then Window 2 takes capture.
- // Verify that window 1 has lost capture.
- wt1()->SetCapture(1, window_1_1);
- wt1()->SetCapture(2, window_1_2);
- wt_client1_->WaitForChangeCount(1);
-
- EXPECT_EQ("OnLostCapture window=" + IdToString(window_1_1),
- SingleChangeToDescription(*changes1()));
-
- changes1()->clear();
- // Explicitly releasing capture should not notify of lost capture.
- wt1()->ReleaseCapture(3, window_1_2);
- wt_client1_->WaitForAllMessages();
-
- EXPECT_TRUE(changes1()->empty());
-}
-
-// TODO(sky): need to better track changes to initial client. For example,
-// that SetBounsdWindows/AddWindow and the like don't result in messages to the
-// originating client.
-
-// TODO(sky): make sure coverage of what was
-// WindowManagerTest.SecondEmbedRoot_InitService and
-// WindowManagerTest.MultipleEmbedRootsBeforeWTHReady gets added to window
-// manager
-// tests.
-
-} // namespace test
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_tree_factory.cc b/chromium/components/mus/ws/window_tree_factory.cc
deleted file mode 100644
index c8befb724ab..00000000000
--- a/chromium/components/mus/ws/window_tree_factory.cc
+++ /dev/null
@@ -1,42 +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 "components/mus/ws/window_tree_factory.h"
-
-#include "base/memory/ptr_util.h"
-#include "components/mus/ws/default_access_policy.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_tree.h"
-#include "components/mus/ws/window_tree_binding.h"
-
-namespace mus {
-namespace ws {
-
-WindowTreeFactory::WindowTreeFactory(WindowServer* window_server,
- const UserId& user_id,
- const std::string& client_name,
- mojom::WindowTreeFactoryRequest request)
- : window_server_(window_server),
- user_id_(user_id),
- client_name_(client_name),
- binding_(this, std::move(request)) {}
-
-WindowTreeFactory::~WindowTreeFactory() {}
-
-void WindowTreeFactory::CreateWindowTree(
- mojo::InterfaceRequest<mojom::WindowTree> tree_request,
- mojom::WindowTreeClientPtr client) {
- std::unique_ptr<ws::WindowTree> service(
- new ws::WindowTree(window_server_, user_id_, nullptr,
- base::WrapUnique(new DefaultAccessPolicy)));
- std::unique_ptr<ws::DefaultWindowTreeBinding> binding(
- new ws::DefaultWindowTreeBinding(service.get(), window_server_,
- std::move(tree_request),
- std::move(client)));
- service->set_name(client_name_);
- window_server_->AddTree(std::move(service), std::move(binding), nullptr);
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_tree_factory.h b/chromium/components/mus/ws/window_tree_factory.h
deleted file mode 100644
index 7a21ea94a23..00000000000
--- a/chromium/components/mus/ws/window_tree_factory.h
+++ /dev/null
@@ -1,42 +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 COMPONENTS_MUS_WS_WINDOW_TREE_FACTORY_H_
-#define COMPONENTS_MUS_WS_WINDOW_TREE_FACTORY_H_
-
-#include "base/macros.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/ws/user_id.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace mus {
-namespace ws {
-
-class WindowServer;
-
-class WindowTreeFactory : public mus::mojom::WindowTreeFactory {
- public:
- WindowTreeFactory(WindowServer* window_server,
- const UserId& user_id,
- const std::string& client_name,
- mojom::WindowTreeFactoryRequest request);
- private:
- ~WindowTreeFactory() override;
-
- // mus::mojom::WindowTreeFactory:
- void CreateWindowTree(mojo::InterfaceRequest<mojom::WindowTree> tree_request,
- mojom::WindowTreeClientPtr client) override;
-
- WindowServer* window_server_;
- const UserId user_id_;
- const std::string client_name_;
- mojo::StrongBinding<mus::mojom::WindowTreeFactory> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTreeFactory);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_TREE_FACTORY_H_
diff --git a/chromium/components/mus/ws/window_tree_host_factory.cc b/chromium/components/mus/ws/window_tree_host_factory.cc
deleted file mode 100644
index c5c6cbc208b..00000000000
--- a/chromium/components/mus/ws/window_tree_host_factory.cc
+++ /dev/null
@@ -1,42 +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 "components/mus/ws/window_tree_host_factory.h"
-
-#include "components/mus/gles2/gpu_state.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/display.h"
-#include "components/mus/ws/display_binding.h"
-#include "components/mus/ws/window_server.h"
-
-namespace mus {
-namespace ws {
-
-WindowTreeHostFactory::WindowTreeHostFactory(
- WindowServer* window_server,
- const UserId& user_id,
- const PlatformDisplayInitParams& platform_display_init_params)
- : window_server_(window_server),
- user_id_(user_id),
- platform_display_init_params_(platform_display_init_params) {}
-
-WindowTreeHostFactory::~WindowTreeHostFactory() {}
-
-void WindowTreeHostFactory::AddBinding(
- mojom::WindowTreeHostFactoryRequest request) {
- bindings_.AddBinding(this, std::move(request));
-}
-
-void WindowTreeHostFactory::CreateWindowTreeHost(
- mojom::WindowTreeHostRequest host,
- mojom::WindowTreeClientPtr tree_client) {
- Display* display = new Display(window_server_, platform_display_init_params_);
- std::unique_ptr<DisplayBindingImpl> display_binding(
- new DisplayBindingImpl(std::move(host), display, user_id_,
- std::move(tree_client), window_server_));
- display->Init(std::move(display_binding));
-}
-
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/mus/ws/window_tree_host_factory.h b/chromium/components/mus/ws/window_tree_host_factory.h
deleted file mode 100644
index 3df36ee7f85..00000000000
--- a/chromium/components/mus/ws/window_tree_host_factory.h
+++ /dev/null
@@ -1,46 +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 COMPONENTS_MUS_WS_WINDOW_TREE_HOST_FACTORY_H_
-#define COMPONENTS_MUS_WS_WINDOW_TREE_HOST_FACTORY_H_
-
-#include <stdint.h>
-
-#include "components/mus/public/interfaces/window_tree_host.mojom.h"
-#include "components/mus/ws/platform_display_init_params.h"
-#include "components/mus/ws/user_id.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-
-namespace mus {
-namespace ws {
-
-class WindowServer;
-
-class WindowTreeHostFactory : public mojom::WindowTreeHostFactory {
- public:
- WindowTreeHostFactory(
- WindowServer* window_server,
- const UserId& user_id,
- const PlatformDisplayInitParams& platform_display_init_params);
- ~WindowTreeHostFactory() override;
-
- void AddBinding(mojom::WindowTreeHostFactoryRequest request);
-
- private:
- // mojom::WindowTreeHostFactory implementation.
- void CreateWindowTreeHost(mojom::WindowTreeHostRequest host,
- mojom::WindowTreeClientPtr tree_client) override;
-
- WindowServer* window_server_;
- const UserId user_id_;
- const PlatformDisplayInitParams platform_display_init_params_;
- mojo::BindingSet<mojom::WindowTreeHostFactory> bindings_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTreeHostFactory);
-};
-
-} // namespace ws
-} // namespace mus
-
-#endif // COMPONENTS_MUS_WS_WINDOW_TREE_HOST_FACTORY_H_
diff --git a/chromium/components/mus/ws/window_tree_unittest.cc b/chromium/components/mus/ws/window_tree_unittest.cc
deleted file mode 100644
index 15356763085..00000000000
--- a/chromium/components/mus/ws/window_tree_unittest.cc
+++ /dev/null
@@ -1,1017 +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 "components/mus/ws/window_tree.h"
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/stringprintf.h"
-#include "components/mus/common/types.h"
-#include "components/mus/common/util.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/surfaces/surfaces_state.h"
-#include "components/mus/ws/default_access_policy.h"
-#include "components/mus/ws/display_binding.h"
-#include "components/mus/ws/ids.h"
-#include "components/mus/ws/platform_display.h"
-#include "components/mus/ws/platform_display_factory.h"
-#include "components/mus/ws/platform_display_init_params.h"
-#include "components/mus/ws/server_window.h"
-#include "components/mus/ws/server_window_surface_manager_test_api.h"
-#include "components/mus/ws/test_change_tracker.h"
-#include "components/mus/ws/test_server_window_delegate.h"
-#include "components/mus/ws/test_utils.h"
-#include "components/mus/ws/window_manager_access_policy.h"
-#include "components/mus/ws/window_manager_display_root.h"
-#include "components/mus/ws/window_server.h"
-#include "components/mus/ws/window_server_delegate.h"
-#include "components/mus/ws/window_tree_binding.h"
-#include "services/shell/public/interfaces/connector.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event.h"
-#include "ui/events/event_utils.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace mus {
-namespace ws {
-namespace test {
-namespace {
-
-std::string WindowIdToString(const WindowId& id) {
- return base::StringPrintf("%d,%d", id.client_id, id.window_id);
-}
-
-ClientWindowId BuildClientWindowId(WindowTree* tree,
- ClientSpecificId window_id) {
- return ClientWindowId(WindowIdToTransportId(WindowId(tree->id(), window_id)));
-}
-
-// -----------------------------------------------------------------------------
-
-ui::PointerEvent CreatePointerDownEvent(int x, int y) {
- return ui::PointerEvent(ui::TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(x, y),
- 1, ui::EventTimeForNow()));
-}
-
-ui::PointerEvent CreatePointerUpEvent(int x, int y) {
- return ui::PointerEvent(ui::TouchEvent(
- ui::ET_TOUCH_RELEASED, gfx::Point(x, y), 1, ui::EventTimeForNow()));
-}
-
-ui::PointerEvent CreateMouseMoveEvent(int x, int y) {
- return ui::PointerEvent(
- ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(x, y), gfx::Point(x, y),
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE));
-}
-
-ui::PointerEvent CreateMouseDownEvent(int x, int y) {
- return ui::PointerEvent(
- ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(x, y), gfx::Point(x, y),
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON));
-}
-
-ui::PointerEvent CreateMouseUpEvent(int x, int y) {
- return ui::PointerEvent(
- ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(x, y), gfx::Point(x, y),
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON));
-}
-
-ServerWindow* GetCaptureWindow(Display* display) {
- return display->GetActiveWindowManagerDisplayRoot()
- ->window_manager_state()
- ->capture_window();
-}
-
-mojom::EventMatcherPtr CreateEventMatcher(ui::mojom::EventType type) {
- mojom::EventMatcherPtr matcher = mojom::EventMatcher::New();
- matcher->type_matcher = mojom::EventTypeMatcher::New();
- matcher->type_matcher->type = type;
- return matcher;
-}
-
-} // namespace
-
-// -----------------------------------------------------------------------------
-
-class WindowTreeTest : public testing::Test {
- public:
- WindowTreeTest() {}
- ~WindowTreeTest() override {}
-
- mus::mojom::Cursor cursor_id() {
- return static_cast<mus::mojom::Cursor>(
- window_event_targeting_helper_.cursor_id());
- }
- Display* display() { return window_event_targeting_helper_.display(); }
- TestWindowTreeBinding* last_binding() {
- return window_event_targeting_helper_.last_binding();
- }
- TestWindowTreeClient* last_window_tree_client() {
- return window_event_targeting_helper_.last_window_tree_client();
- }
- TestWindowTreeClient* wm_client() {
- return window_event_targeting_helper_.wm_client();
- }
- WindowServer* window_server() {
- return window_event_targeting_helper_.window_server();
- }
- WindowTree* wm_tree() {
- return window_event_targeting_helper_.window_server()->GetTreeWithId(1);
- }
-
- void DispatchEventWithoutAck(const ui::Event& event) {
- DisplayTestApi(display()).OnEvent(event);
- }
-
- void set_window_manager_internal(WindowTree* tree,
- mojom::WindowManager* wm_internal) {
- WindowTreeTestApi(tree).set_window_manager_internal(wm_internal);
- }
-
- void AckPreviousEvent() {
- WindowManagerStateTestApi test_api(
- display()->GetActiveWindowManagerDisplayRoot()->window_manager_state());
- while (test_api.tree_awaiting_input_ack()) {
- test_api.tree_awaiting_input_ack()->OnWindowInputEventAck(
- 0, mojom::EventResult::HANDLED);
- }
- }
-
- void DispatchEventAndAckImmediately(const ui::Event& event) {
- DispatchEventWithoutAck(event);
- AckPreviousEvent();
- }
-
- // Creates a new window from wm_tree() and embeds a new client in it.
- void SetupEventTargeting(TestWindowTreeClient** out_client,
- WindowTree** window_tree,
- ServerWindow** window);
-
- // Creates a new tree as the specified user. This does what creation via
- // a WindowTreeFactory does.
- WindowTree* CreateNewTree(const UserId& user_id,
- TestWindowTreeBinding** binding) {
- WindowTree* tree =
- new WindowTree(window_server(), user_id, nullptr,
- base::WrapUnique(new DefaultAccessPolicy));
- *binding = new TestWindowTreeBinding(tree);
- window_server()->AddTree(base::WrapUnique(tree), base::WrapUnique(*binding),
- nullptr);
- return tree;
- }
-
- protected:
- WindowEventTargetingHelper window_event_targeting_helper_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WindowTreeTest);
-};
-
-// Creates a new window in wm_tree(), adds it to the root, embeds a
-// new client in the window and creates a child of said window. |window| is
-// set to the child of |window_tree| that is created.
-void WindowTreeTest::SetupEventTargeting(TestWindowTreeClient** out_client,
- WindowTree** window_tree,
- ServerWindow** window) {
- ServerWindow* embed_window = window_event_targeting_helper_.CreatePrimaryTree(
- gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 50, 50));
- window_event_targeting_helper_.CreateSecondaryTree(
- embed_window, gfx::Rect(20, 20, 20, 20), out_client, window_tree, window);
-}
-
-// Verifies focus correctly changes on pointer events.
-TEST_F(WindowTreeTest, FocusOnPointer) {
- const ClientWindowId embed_window_id = BuildClientWindowId(wm_tree(), 1);
- EXPECT_TRUE(
- wm_tree()->NewWindow(embed_window_id, ServerWindow::Properties()));
- ServerWindow* embed_window = wm_tree()->GetWindowByClientId(embed_window_id);
- ASSERT_TRUE(embed_window);
- EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id, true));
- ASSERT_TRUE(FirstRoot(wm_tree()));
- const ClientWindowId wm_root_id = FirstRootId(wm_tree());
- EXPECT_TRUE(wm_tree()->AddWindow(wm_root_id, embed_window_id));
- display()->root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
- mojom::WindowTreeClientPtr client;
- mojom::WindowTreeClientRequest client_request = GetProxy(&client);
- wm_client()->Bind(std::move(client_request));
- const uint32_t embed_flags = 0;
- wm_tree()->Embed(embed_window_id, std::move(client), embed_flags);
- WindowTree* tree1 = window_server()->GetTreeWithRoot(embed_window);
- ASSERT_TRUE(tree1 != nullptr);
- ASSERT_NE(tree1, wm_tree());
-
- embed_window->SetBounds(gfx::Rect(0, 0, 50, 50));
-
- const ClientWindowId child1_id(BuildClientWindowId(tree1, 1));
- EXPECT_TRUE(tree1->NewWindow(child1_id, ServerWindow::Properties()));
- EXPECT_TRUE(tree1->AddWindow(ClientWindowIdForWindow(tree1, embed_window),
- child1_id));
- ServerWindow* child1 = tree1->GetWindowByClientId(child1_id);
- ASSERT_TRUE(child1);
- child1->SetVisible(true);
- child1->SetBounds(gfx::Rect(20, 20, 20, 20));
- EnableHitTest(child1);
-
- TestWindowTreeClient* tree1_client = last_window_tree_client();
- tree1_client->tracker()->changes()->clear();
- wm_client()->tracker()->changes()->clear();
-
- // Focus should not go to |child1| yet, since the parent still doesn't allow
- // active children.
- DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
- Display* display1 = tree1->GetDisplay(embed_window);
- EXPECT_EQ(nullptr, display1->GetFocusedWindow());
- DispatchEventAndAckImmediately(CreatePointerUpEvent(21, 22));
- tree1_client->tracker()->changes()->clear();
- wm_client()->tracker()->changes()->clear();
-
- display1->AddActivationParent(embed_window);
-
- // Focus should go to child1. This result in notifying both the window
- // manager and client client being notified.
- DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
- EXPECT_EQ(child1, display1->GetFocusedWindow());
- ASSERT_GE(wm_client()->tracker()->changes()->size(), 1u);
- EXPECT_EQ("Focused id=2,1",
- ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
- ASSERT_GE(tree1_client->tracker()->changes()->size(), 1u);
- EXPECT_EQ("Focused id=2,1",
- ChangesToDescription1(*tree1_client->tracker()->changes())[0]);
-
- DispatchEventAndAckImmediately(CreatePointerUpEvent(21, 22));
- wm_client()->tracker()->changes()->clear();
- tree1_client->tracker()->changes()->clear();
-
- // Press outside of the embedded window. Note that root cannot be focused
- // (because it cannot be activated). So the focus would not move in this case.
- DispatchEventAndAckImmediately(CreatePointerDownEvent(61, 22));
- EXPECT_EQ(child1, display()->GetFocusedWindow());
-
- DispatchEventAndAckImmediately(CreatePointerUpEvent(21, 22));
- wm_client()->tracker()->changes()->clear();
- tree1_client->tracker()->changes()->clear();
-
- // Press in the same location. Should not get a focus change event (only input
- // event).
- DispatchEventAndAckImmediately(CreatePointerDownEvent(61, 22));
- EXPECT_EQ(child1, display()->GetFocusedWindow());
- ASSERT_EQ(wm_client()->tracker()->changes()->size(), 1u)
- << SingleChangeToDescription(*wm_client()->tracker()->changes());
- EXPECT_EQ("InputEvent window=0,3 event_action=16",
- ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
- EXPECT_TRUE(tree1_client->tracker()->changes()->empty());
-}
-
-TEST_F(WindowTreeTest, BasicInputEventTarget) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(
- SetupEventTargeting(&embed_client, &tree, &window));
-
- // Send an event to |v1|. |embed_client| should get the event, not
- // |wm_client|, since |v1| lives inside an embedded window.
- DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
- ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
- EXPECT_EQ("Focused id=2,1",
- ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
- ASSERT_EQ(2u, embed_client->tracker()->changes()->size());
- EXPECT_EQ("Focused id=2,1",
- ChangesToDescription1(*embed_client->tracker()->changes())[0]);
- EXPECT_EQ("InputEvent window=2,1 event_action=16",
- ChangesToDescription1(*embed_client->tracker()->changes())[1]);
-}
-
-// Tests that a client can observe events outside its bounds.
-TEST_F(WindowTreeTest, SetEventObserver) {
- // Create an embedded client.
- TestWindowTreeClient* client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&client, &tree, &window));
-
- // Create an event outside the bounds of the client.
- ui::PointerEvent pointer_down = CreatePointerDownEvent(5, 5);
-
- // Events are not observed before setting an observer.
- DispatchEventAndAckImmediately(pointer_down);
- ASSERT_EQ(0u, client->tracker()->changes()->size());
-
- // Create an observer for pointer-down events.
- WindowTreeTestApi(tree).SetEventObserver(
- CreateEventMatcher(ui::mojom::EventType::POINTER_DOWN), 111u);
-
- // Pointer-down events are sent to the client.
- DispatchEventAndAckImmediately(pointer_down);
- ASSERT_EQ(1u, client->tracker()->changes()->size());
- EXPECT_EQ("EventObserved event_action=16 event_observer_id=111",
- ChangesToDescription1(*client->tracker()->changes())[0]);
- client->tracker()->changes()->clear();
-
- // Clearing the observer stops sending events to the client.
- WindowTreeTestApi(tree).SetEventObserver(nullptr, 0u);
- DispatchEventAndAckImmediately(pointer_down);
- ASSERT_EQ(0u, client->tracker()->changes()->size());
-}
-
-// Tests that a client using an event observer does not receive events that
-// don't match the EventMatcher spec.
-TEST_F(WindowTreeTest, SetEventObserverNonMatching) {
- // Create an embedded client.
- TestWindowTreeClient* client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&client, &tree, &window));
-
- // Create an observer for pointer-down events.
- WindowTreeTestApi(tree).SetEventObserver(
- CreateEventMatcher(ui::mojom::EventType::POINTER_DOWN), 111u);
-
- // Pointer-up events are not sent to the client, since they don't match.
- DispatchEventAndAckImmediately(CreatePointerUpEvent(5, 5));
- ASSERT_EQ(0u, client->tracker()->changes()->size());
-}
-
-// Tests that an event that both hits a client window and matches an event
-// observer is sent only once to the client.
-TEST_F(WindowTreeTest, SetEventObserverSendsOnce) {
- // Create an embedded client.
- TestWindowTreeClient* client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&client, &tree, &window));
-
- // Create an observer for pointer-up events (which do not cause focus
- // changes).
- WindowTreeTestApi(tree).SetEventObserver(
- CreateEventMatcher(ui::mojom::EventType::POINTER_UP), 111u);
-
- // Create an event inside the bounds of the client.
- ui::PointerEvent pointer_up = CreatePointerUpEvent(25, 25);
-
- // The event is dispatched once, with a flag set that it matched the event
- // observer.
- DispatchEventAndAckImmediately(pointer_up);
- ASSERT_EQ(1u, client->tracker()->changes()->size());
- EXPECT_EQ("InputEvent window=2,1 event_action=18 event_observer_id=111",
- SingleChangeToDescription(*client->tracker()->changes()));
-}
-
-// Tests that events generated by user A are not observed by event observers for
-// user B.
-TEST_F(WindowTreeTest, SetEventObserverWrongUser) {
- // Embed a window tree belonging to a different user.
- TestWindowTreeBinding* other_binding;
- WindowTree* other_tree = CreateNewTree("other_user", &other_binding);
- other_binding->client()->tracker()->changes()->clear();
-
- // Set event observers on both the wm tree and the other user's tree.
- WindowTreeTestApi(wm_tree()).SetEventObserver(
- CreateEventMatcher(ui::mojom::EventType::POINTER_UP), 111u);
- WindowTreeTestApi(other_tree)
- .SetEventObserver(CreateEventMatcher(ui::mojom::EventType::POINTER_UP),
- 222u);
-
- // An event is observed by the wm tree, but not by the other user's tree.
- DispatchEventAndAckImmediately(CreatePointerUpEvent(5, 5));
- ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
- EXPECT_EQ("InputEvent window=0,3 event_action=18 event_observer_id=111",
- SingleChangeToDescription(*wm_client()->tracker()->changes()));
- ASSERT_EQ(0u, other_binding->client()->tracker()->changes()->size());
-}
-
-// Tests that an event observer cannot observe keystrokes.
-TEST_F(WindowTreeTest, SetEventObserverKeyEventsDisallowed) {
- WindowTreeTestApi(wm_tree()).SetEventObserver(
- CreateEventMatcher(ui::mojom::EventType::KEY_PRESSED), 111u);
- ui::KeyEvent key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
- DispatchEventAndAckImmediately(key_pressed);
- EXPECT_EQ(0u, wm_client()->tracker()->changes()->size());
-
- WindowTreeTestApi(wm_tree()).SetEventObserver(
- CreateEventMatcher(ui::mojom::EventType::KEY_RELEASED), 222u);
- ui::KeyEvent key_released(ui::ET_KEY_RELEASED, ui::VKEY_A, ui::EF_NONE);
- DispatchEventAndAckImmediately(key_released);
- EXPECT_EQ(0u, wm_client()->tracker()->changes()->size());
-}
-
-TEST_F(WindowTreeTest, CursorChangesWhenMouseOverWindowAndWindowSetsCursor) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
-
- // Like in BasicInputEventTarget, we send a pointer down event to be
- // dispatched. This is only to place the mouse cursor over that window though.
- DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
-
- window->SetPredefinedCursor(mojom::Cursor::IBEAM);
-
- // Because the cursor is over the window when SetCursor was called, we should
- // have immediately changed the cursor.
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
-}
-
-TEST_F(WindowTreeTest, CursorChangesWhenEnteringWindowWithDifferentCursor) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
-
- // Let's create a pointer event outside the window and then move the pointer
- // inside.
- DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
- window->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
-
- DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
-}
-
-TEST_F(WindowTreeTest, TouchesDontChangeCursor) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
-
- // Let's create a pointer event outside the window and then move the pointer
- // inside.
- DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
- window->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
-
- // With a touch event, we shouldn't update the cursor.
- DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
- EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
-}
-
-TEST_F(WindowTreeTest, DragOutsideWindow) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
-
- // Start with the cursor outside the window. Setting the cursor shouldn't
- // change the cursor.
- DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
- window->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
-
- // Move the pointer to the inside of the window
- DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
-
- // Start the drag.
- DispatchEventAndAckImmediately(CreateMouseDownEvent(21, 22));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
-
- // Move the cursor (mouse is still down) outside the window.
- DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
-
- // Release the cursor. We should now adapt the cursor of the window
- // underneath the pointer.
- DispatchEventAndAckImmediately(CreateMouseUpEvent(5, 5));
- EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
-}
-
-TEST_F(WindowTreeTest, ChangingWindowBoundsChangesCursor) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
-
- // Put the cursor just outside the bounds of the window.
- DispatchEventAndAckImmediately(CreateMouseMoveEvent(41, 41));
- window->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
-
- // Expand the bounds of the window so they now include where the cursor now
- // is.
- window->SetBounds(gfx::Rect(20, 20, 25, 25));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
-
- // Contract the bounds again.
- window->SetBounds(gfx::Rect(20, 20, 20, 20));
- EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
-}
-
-TEST_F(WindowTreeTest, WindowReorderingChangesCursor) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window1 = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window1));
-
- // Create a second window right over the first.
- const ClientWindowId embed_window_id(FirstRootId(tree));
- const ClientWindowId child2_id(BuildClientWindowId(tree, 2));
- EXPECT_TRUE(tree->NewWindow(child2_id, ServerWindow::Properties()));
- ServerWindow* child2 = tree->GetWindowByClientId(child2_id);
- ASSERT_TRUE(child2);
- EXPECT_TRUE(tree->AddWindow(embed_window_id, child2_id));
- child2->SetVisible(true);
- child2->SetBounds(gfx::Rect(20, 20, 20, 20));
- EnableHitTest(child2);
-
- // Give each window a different cursor.
- window1->SetPredefinedCursor(mojom::Cursor::IBEAM);
- child2->SetPredefinedCursor(mojom::Cursor::HAND);
-
- // We expect window2 to be over window1 now.
- DispatchEventAndAckImmediately(CreateMouseMoveEvent(22, 22));
- EXPECT_EQ(mojom::Cursor::HAND, cursor_id());
-
- // But when we put window2 at the bottom, we should adapt window1's cursor.
- child2->parent()->StackChildAtBottom(child2);
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
-}
-
-TEST_F(WindowTreeTest, EventAck) {
- const ClientWindowId embed_window_id = BuildClientWindowId(wm_tree(), 1);
- EXPECT_TRUE(
- wm_tree()->NewWindow(embed_window_id, ServerWindow::Properties()));
- EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id, true));
- ASSERT_TRUE(FirstRoot(wm_tree()));
- EXPECT_TRUE(wm_tree()->AddWindow(FirstRootId(wm_tree()), embed_window_id));
- display()->root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
-
- wm_client()->tracker()->changes()->clear();
- DispatchEventWithoutAck(CreateMouseMoveEvent(21, 22));
- ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
- EXPECT_EQ("InputEvent window=0,3 event_action=17",
- ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
- wm_client()->tracker()->changes()->clear();
-
- // Send another event. This event shouldn't reach the client.
- DispatchEventWithoutAck(CreateMouseMoveEvent(21, 22));
- ASSERT_EQ(0u, wm_client()->tracker()->changes()->size());
-
- // Ack the first event. That should trigger the dispatch of the second event.
- AckPreviousEvent();
- ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
- EXPECT_EQ("InputEvent window=0,3 event_action=17",
- ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
-}
-
-// Establish client, call NewTopLevelWindow(), make sure get id, and make
-// sure client paused.
-TEST_F(WindowTreeTest, NewTopLevelWindow) {
- TestWindowManager wm_internal;
- set_window_manager_internal(wm_tree(), &wm_internal);
-
- TestWindowTreeBinding* child_binding;
- WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding);
- child_binding->client()->tracker()->changes()->clear();
- child_binding->client()->set_record_on_change_completed(true);
-
- // Create a new top level window.
- mojo::Map<mojo::String, mojo::Array<uint8_t>> properties;
- const uint32_t initial_change_id = 17;
- // Explicitly use an id that does not contain the client id.
- const ClientWindowId embed_window_id2_in_child(45 << 16 | 27);
- static_cast<mojom::WindowTree*>(child_tree)
- ->NewTopLevelWindow(initial_change_id, embed_window_id2_in_child.id,
- std::move(properties));
-
- // The binding should be paused until the wm acks the change.
- uint32_t wm_change_id = 0u;
- ASSERT_TRUE(wm_internal.did_call_create_top_level_window(&wm_change_id));
- EXPECT_TRUE(child_binding->is_paused());
-
- // Create the window for |embed_window_id2_in_child|.
- const ClientWindowId embed_window_id2 = BuildClientWindowId(wm_tree(), 2);
- EXPECT_TRUE(
- wm_tree()->NewWindow(embed_window_id2, ServerWindow::Properties()));
- EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id2, true));
- EXPECT_TRUE(wm_tree()->AddWindow(FirstRootId(wm_tree()), embed_window_id2));
-
- // Ack the change, which should resume the binding.
- child_binding->client()->tracker()->changes()->clear();
- static_cast<mojom::WindowManagerClient*>(wm_tree())
- ->OnWmCreatedTopLevelWindow(wm_change_id, embed_window_id2.id);
- EXPECT_FALSE(child_binding->is_paused());
- EXPECT_EQ("TopLevelCreated id=17 window_id=" +
- WindowIdToString(
- WindowIdFromTransportId(embed_window_id2_in_child.id)) +
- " drawn=true",
- SingleChangeToDescription(
- *child_binding->client()->tracker()->changes()));
- child_binding->client()->tracker()->changes()->clear();
-
- // Change the visibility of the window from the owner and make sure the
- // client sees the right id.
- ServerWindow* embed_window = wm_tree()->GetWindowByClientId(embed_window_id2);
- ASSERT_TRUE(embed_window);
- EXPECT_TRUE(embed_window->visible());
- ASSERT_TRUE(wm_tree()->SetWindowVisibility(
- ClientWindowIdForWindow(wm_tree(), embed_window), false));
- EXPECT_FALSE(embed_window->visible());
- EXPECT_EQ("VisibilityChanged window=" +
- WindowIdToString(
- WindowIdFromTransportId(embed_window_id2_in_child.id)) +
- " visible=false",
- SingleChangeToDescription(
- *child_binding->client()->tracker()->changes()));
-
- // Set the visibility from the child using the client assigned id.
- ASSERT_TRUE(child_tree->SetWindowVisibility(embed_window_id2_in_child, true));
- EXPECT_TRUE(embed_window->visible());
-}
-
-// Tests that only the capture window can release capture.
-TEST_F(WindowTreeTest, ExplicitSetCapture) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
- const ServerWindow* root_window = *tree->roots().begin();
- tree->AddWindow(FirstRootId(tree), ClientWindowIdForWindow(tree, window));
- window->SetBounds(gfx::Rect(0, 0, 100, 100));
- ASSERT_TRUE(tree->GetDisplay(window));
-
- // Set capture.
- mojom::WindowTree* mojom_window_tree = static_cast<mojom::WindowTree*>(tree);
- uint32_t change_id = 42;
- mojom_window_tree->SetCapture(change_id, WindowIdToTransportId(window->id()));
- Display* display = tree->GetDisplay(window);
- EXPECT_EQ(window, GetCaptureWindow(display));
-
- // Only the capture window should be able to release capture
- mojom_window_tree->ReleaseCapture(++change_id,
- WindowIdToTransportId(root_window->id()));
- EXPECT_EQ(window, GetCaptureWindow(display));
- mojom_window_tree->ReleaseCapture(++change_id,
- WindowIdToTransportId(window->id()));
- EXPECT_EQ(nullptr, GetCaptureWindow(display));
-}
-
-// Tests that while a client is interacting with input, that capture is not
-// allowed for invisible windows.
-TEST_F(WindowTreeTest, CaptureWindowMustBeVisible) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
- tree->AddWindow(FirstRootId(tree), ClientWindowIdForWindow(tree, window));
- window->SetBounds(gfx::Rect(0, 0, 100, 100));
- ASSERT_TRUE(tree->GetDisplay(window));
-
- DispatchEventWithoutAck(CreatePointerDownEvent(10, 10));
- window->SetVisible(false);
- EXPECT_FALSE(tree->SetCapture(ClientWindowIdForWindow(tree, window)));
- EXPECT_NE(window, GetCaptureWindow(tree->GetDisplay(window)));
-}
-
-// Tests that showing a modal window releases the capture if the capture is on a
-// descendant of the modal parent.
-TEST_F(WindowTreeTest, ShowModalWindowWithDescendantCapture) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* w1 = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
-
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- const ServerWindow* root_window = *tree->roots().begin();
- ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
- ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
- Display* display = tree->GetDisplay(w1);
-
- // Create |w11| as a child of |w1| and make it visible.
- ClientWindowId w11_id = BuildClientWindowId(tree, 11);
- ASSERT_TRUE(tree->NewWindow(w11_id, ServerWindow::Properties()));
- ServerWindow* w11 = tree->GetWindowByClientId(w11_id);
- w11->SetBounds(gfx::Rect(10, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(w1_id, w11_id));
- ASSERT_TRUE(tree->SetWindowVisibility(w11_id, true));
-
- // Create |w2| as a child of |root_window| and modal to |w1| and leave it
- // hidden.
- ClientWindowId w2_id = BuildClientWindowId(tree, 2);
- ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
- ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
- ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
-
- // Set capture to |w11|.
- DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
- ASSERT_TRUE(tree->SetCapture(w11_id));
- EXPECT_EQ(w11, GetCaptureWindow(display));
- AckPreviousEvent();
-
- // Make |w2| visible. This should release capture as capture is set to a
- // descendant of the modal parent.
- ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
- EXPECT_EQ(nullptr, GetCaptureWindow(display));
-}
-
-// Tests that setting a visible window as modal releases the capture if the
-// capture is on a descendant of the modal parent.
-TEST_F(WindowTreeTest, VisibleWindowToModalWithDescendantCapture) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* w1 = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
-
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- const ServerWindow* root_window = *tree->roots().begin();
- ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
- ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
- Display* display = tree->GetDisplay(w1);
-
- // Create |w11| as a child of |w1| and make it visible.
- ClientWindowId w11_id = BuildClientWindowId(tree, 11);
- ASSERT_TRUE(tree->NewWindow(w11_id, ServerWindow::Properties()));
- ServerWindow* w11 = tree->GetWindowByClientId(w11_id);
- w11->SetBounds(gfx::Rect(10, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(w1_id, w11_id));
- ASSERT_TRUE(tree->SetWindowVisibility(w11_id, true));
-
- // Create |w2| as a child of |root_window| and make it visible.
- ClientWindowId w2_id = BuildClientWindowId(tree, 2);
- ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
- ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
- ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
-
- // Set capture to |w11|.
- DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
- ASSERT_TRUE(tree->SetCapture(w11_id));
- EXPECT_EQ(w11, GetCaptureWindow(display));
- AckPreviousEvent();
-
- // Set |w2| modal to |w1|. This should release the capture as the capture is
- // set to a descendant of the modal parent.
- ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
- EXPECT_EQ(nullptr, GetCaptureWindow(display));
-}
-
-// Tests that showing a modal window does not change capture if the capture is
-// not on a descendant of the modal parent.
-TEST_F(WindowTreeTest, ShowModalWindowWithNonDescendantCapture) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* w1 = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
-
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- const ServerWindow* root_window = *tree->roots().begin();
- ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
- ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
- Display* display = tree->GetDisplay(w1);
-
- // Create |w2| as a child of |root_window| and modal to |w1| and leave it
- // hidden..
- ClientWindowId w2_id = BuildClientWindowId(tree, 2);
- ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
- ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
- ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
-
- // Create |w3| as a child of |root_window| and make it visible.
- ClientWindowId w3_id = BuildClientWindowId(tree, 3);
- ASSERT_TRUE(tree->NewWindow(w3_id, ServerWindow::Properties()));
- ServerWindow* w3 = tree->GetWindowByClientId(w3_id);
- w3->SetBounds(gfx::Rect(70, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(root_window_id, w3_id));
- ASSERT_TRUE(tree->SetWindowVisibility(w3_id, true));
-
- // Set capture to |w3|.
- DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
- ASSERT_TRUE(tree->SetCapture(w3_id));
- EXPECT_EQ(w3, GetCaptureWindow(display));
- AckPreviousEvent();
-
- // Make |w2| visible. This should not change the capture as the capture is not
- // set to a descendant of the modal parent.
- ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
- EXPECT_EQ(w3, GetCaptureWindow(display));
-}
-
-// Tests that setting a visible window as modal does not change the capture if
-// the capture is not set to a descendant of the modal parent.
-TEST_F(WindowTreeTest, VisibleWindowToModalWithNonDescendantCapture) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* w1 = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
-
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- const ServerWindow* root_window = *tree->roots().begin();
- ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
- ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
- Display* display = tree->GetDisplay(w1);
-
- // Create |w2| and |w3| as children of |root_window| and make them visible.
- ClientWindowId w2_id = BuildClientWindowId(tree, 2);
- ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
- ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
- ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
-
- ClientWindowId w3_id = BuildClientWindowId(tree, 3);
- ASSERT_TRUE(tree->NewWindow(w3_id, ServerWindow::Properties()));
- ServerWindow* w3 = tree->GetWindowByClientId(w3_id);
- w3->SetBounds(gfx::Rect(70, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(root_window_id, w3_id));
- ASSERT_TRUE(tree->SetWindowVisibility(w3_id, true));
-
- // Set capture to |w3|.
- DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
- ASSERT_TRUE(tree->SetCapture(w3_id));
- EXPECT_EQ(w3, GetCaptureWindow(display));
- AckPreviousEvent();
-
- // Set |w2| modal to |w1|. This should not release the capture as the capture
- // is not set to a descendant of the modal parent.
- ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
- EXPECT_EQ(w3, GetCaptureWindow(display));
-}
-
-// Tests that showing a system modal window releases the capture.
-TEST_F(WindowTreeTest, ShowSystemModalWindowWithCapture) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* w1 = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
-
- w1->SetBounds(gfx::Rect(10, 10, 10, 10));
- const ServerWindow* root_window = *tree->roots().begin();
- ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
- ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
- Display* display = tree->GetDisplay(w1);
-
- // Create a system modal window |w2| as a child of |root_window| and leave it
- // hidden.
- ClientWindowId w2_id = BuildClientWindowId(tree, 2);
- ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
- ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
- w2->SetBounds(gfx::Rect(30, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
-
- // Set capture to |w1|.
- DispatchEventWithoutAck(CreatePointerDownEvent(15, 15));
- ASSERT_TRUE(tree->SetCapture(w1_id));
- EXPECT_EQ(w1, GetCaptureWindow(display));
- AckPreviousEvent();
-
- // Make |w2| visible. This should release capture as it is system modal
- // window.
- ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
- EXPECT_EQ(nullptr, GetCaptureWindow(display));
-}
-
-// Tests that setting a visible window as modal to system releases the capture.
-TEST_F(WindowTreeTest, VisibleWindowToSystemModalWithCapture) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* w1 = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
-
- w1->SetBounds(gfx::Rect(10, 10, 10, 10));
- const ServerWindow* root_window = *tree->roots().begin();
- ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
- ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
- Display* display = tree->GetDisplay(w1);
-
- // Create |w2| as a child of |root_window| and make it visible.
- ClientWindowId w2_id = BuildClientWindowId(tree, 2);
- ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
- ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
- w2->SetBounds(gfx::Rect(30, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
- ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
-
- // Set capture to |w1|.
- DispatchEventWithoutAck(CreatePointerDownEvent(15, 15));
- ASSERT_TRUE(tree->SetCapture(w1_id));
- EXPECT_EQ(w1, GetCaptureWindow(display));
- AckPreviousEvent();
-
- // Make |w2| modal to system. This should release capture.
- ASSERT_TRUE(tree->SetModal(w2_id));
- EXPECT_EQ(nullptr, GetCaptureWindow(display));
-}
-
-// Tests that moving the capture window to a modal parent releases the capture
-// as capture cannot be blocked by a modal window.
-TEST_F(WindowTreeTest, MoveCaptureWindowToModalParent) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* w1 = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
-
- w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- const ServerWindow* root_window = *tree->roots().begin();
- ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
- ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
- Display* display = tree->GetDisplay(w1);
-
- // Create |w2| and |w3| as children of |root_window| and make them visible.
- ClientWindowId w2_id = BuildClientWindowId(tree, 2);
- ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
- ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
- w2->SetBounds(gfx::Rect(50, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
- ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
-
- ClientWindowId w3_id = BuildClientWindowId(tree, 3);
- ASSERT_TRUE(tree->NewWindow(w3_id, ServerWindow::Properties()));
- ServerWindow* w3 = tree->GetWindowByClientId(w3_id);
- w3->SetBounds(gfx::Rect(70, 10, 10, 10));
- ASSERT_TRUE(tree->AddWindow(root_window_id, w3_id));
- ASSERT_TRUE(tree->SetWindowVisibility(w3_id, true));
-
- // Set |w2| modal to |w1|.
- ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
-
- // Set capture to |w3|.
- DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
- ASSERT_TRUE(tree->SetCapture(w3_id));
- EXPECT_EQ(w3, GetCaptureWindow(display));
- AckPreviousEvent();
-
- // Make |w3| child of |w1|. This should release capture as |w3| is now blocked
- // by a modal window.
- ASSERT_TRUE(tree->AddWindow(w1_id, w3_id));
- EXPECT_EQ(nullptr, GetCaptureWindow(display));
-}
-
-// Tests that opacity can be set on a known window.
-TEST_F(WindowTreeTest, SetOpacity) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
-
- const float new_opacity = 0.5f;
- EXPECT_NE(new_opacity, window->opacity());
- ASSERT_TRUE(tree->SetWindowOpacity(ClientWindowIdForWindow(tree, window),
- new_opacity));
- EXPECT_EQ(new_opacity, window->opacity());
-
- // Re-applying the same opacity will succeed.
- EXPECT_TRUE(tree->SetWindowOpacity(ClientWindowIdForWindow(tree, window),
- new_opacity));
-}
-
-// Tests that opacity requests for unknown windows are rejected.
-TEST_F(WindowTreeTest, SetOpacityFailsOnUnknownWindow) {
- TestWindowTreeClient* embed_client = nullptr;
- WindowTree* tree = nullptr;
- ServerWindow* window = nullptr;
- EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
-
- TestServerWindowDelegate delegate;
- WindowId window_id(42, 1337);
- ServerWindow unknown_window(&delegate, window_id);
- const float new_opacity = 0.5f;
- ASSERT_NE(new_opacity, unknown_window.opacity());
-
- EXPECT_FALSE(tree->SetWindowOpacity(
- ClientWindowId(WindowIdToTransportId(window_id)), new_opacity));
- EXPECT_NE(new_opacity, unknown_window.opacity());
-}
-
-TEST_F(WindowTreeTest, SetCaptureTargetsRightConnection) {
- ServerWindow* window = window_event_targeting_helper_.CreatePrimaryTree(
- gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 50, 50));
- WindowTree* owning_tree =
- window_server()->GetTreeWithId(window->id().client_id);
- WindowTree* embed_tree = window_server()->GetTreeWithRoot(window);
- ASSERT_NE(owning_tree, embed_tree);
- ASSERT_TRUE(
- owning_tree->SetCapture(ClientWindowIdForWindow(owning_tree, window)));
- DispatchEventWithoutAck(CreateMouseMoveEvent(21, 22));
- WindowManagerStateTestApi wm_state_test_api(
- display()->GetActiveWindowManagerDisplayRoot()->window_manager_state());
- EXPECT_EQ(owning_tree, wm_state_test_api.tree_awaiting_input_ack());
- AckPreviousEvent();
-
- // Set capture from the embedded client and make sure it gets the event.
- ASSERT_TRUE(
- embed_tree->SetCapture(ClientWindowIdForWindow(embed_tree, window)));
- DispatchEventWithoutAck(CreateMouseMoveEvent(22, 23));
- EXPECT_EQ(embed_tree, wm_state_test_api.tree_awaiting_input_ack());
-}
-
-} // namespace test
-} // namespace ws
-} // namespace mus
diff --git a/chromium/components/nacl.gyp b/chromium/components/nacl.gyp
deleted file mode 100644
index 677fbc4de9c..00000000000
--- a/chromium/components/nacl.gyp
+++ /dev/null
@@ -1,466 +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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'target_defaults': {
- 'variables': {
- 'nacl_target': 0,
- },
- 'target_conditions': [
- # This part is shared between the targets defined below. Only files and
- # settings relevant for building the Win64 target should be added here.
- ['nacl_target==1', {
- 'include_dirs': [
- '<(INTERMEDIATE_DIR)',
- ],
- 'sources': [
- # .cc, .h, and .mm files under nacl that are used on all
- # platforms, including both 32-bit and 64-bit Windows.
- # Test files are also not included.
- 'nacl/loader/nacl_ipc_adapter.cc',
- 'nacl/loader/nacl_ipc_adapter.h',
- 'nacl/loader/nacl_listener.cc',
- 'nacl/loader/nacl_listener.h',
- 'nacl/loader/nacl_main.cc',
- 'nacl/loader/nacl_main_platform_delegate.h',
- 'nacl/loader/nacl_main_platform_delegate_linux.cc',
- 'nacl/loader/nacl_main_platform_delegate_mac.mm',
- 'nacl/loader/nacl_main_platform_delegate_win.cc',
- 'nacl/loader/nacl_trusted_listener.cc',
- 'nacl/loader/nacl_trusted_listener.h',
- 'nacl/loader/nacl_validation_db.h',
- 'nacl/loader/nacl_validation_query.cc',
- 'nacl/loader/nacl_validation_query.h',
- ],
- # TODO(gregoryd): consider switching NaCl to use Chrome OS defines
- 'conditions': [
- ['OS=="win"', {
- 'defines': [
- '__STDC_LIMIT_MACROS=1',
- ],
- 'include_dirs': [
- '<(DEPTH)/third_party/wtl/include',
- ],
- },],
- ['OS=="linux"', {
- 'defines': [
- '__STDC_LIMIT_MACROS=1',
- ],
- 'sources': [
- '../components/nacl/common/nacl_paths.cc',
- '../components/nacl/common/nacl_paths.h',
- ],
- },],
- ],
- }],
- ],
- },
- 'conditions': [
- ['disable_nacl!=1', {
- 'targets': [
- {
- # GN version: //components/nacl/loader
- 'target_name': 'nacl',
- 'type': 'static_library',
- 'variables': {
- 'nacl_target': 1,
- },
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_static',
- '../crypto/crypto.gyp:crypto',
- '../ipc/ipc.gyp:ipc',
- '../mojo/mojo_edk.gyp:mojo_system_impl',
- '../native_client/src/trusted/service_runtime/service_runtime.gyp:sel_main_chrome',
- '../ppapi/ppapi_internal.gyp:ppapi_ipc',
- '../ppapi/ppapi_internal.gyp:ppapi_shared',
- ],
- 'conditions': [
- ['disable_nacl_untrusted==0', {
- 'dependencies': [
- '../ppapi/native_client/native_client.gyp:nacl_irt',
- '../ppapi/native_client/src/untrusted/pnacl_support_extension/pnacl_support_extension.gyp:pnacl_support_extension',
- ],
- }],
- ],
- },
- {
- # GN version: //components/nacl/browser
- 'target_name': 'nacl_browser',
- 'type': 'static_library',
- 'sources': [
- 'nacl/browser/bad_message.cc',
- 'nacl/browser/bad_message.h',
- 'nacl/browser/nacl_broker_host_win.cc',
- 'nacl/browser/nacl_broker_host_win.h',
- 'nacl/browser/nacl_broker_service_win.cc',
- 'nacl/browser/nacl_broker_service_win.h',
- 'nacl/browser/nacl_browser.cc',
- 'nacl/browser/nacl_browser.h',
- 'nacl/browser/nacl_file_host.cc',
- 'nacl/browser/nacl_file_host.h',
- 'nacl/browser/nacl_host_message_filter.cc',
- 'nacl/browser/nacl_host_message_filter.h',
- 'nacl/browser/nacl_process_host.cc',
- 'nacl/browser/nacl_process_host.h',
- 'nacl/browser/nacl_validation_cache.cc',
- 'nacl/browser/nacl_validation_cache.h',
- 'nacl/browser/pnacl_host.cc',
- 'nacl/browser/pnacl_host.h',
- 'nacl/browser/pnacl_translation_cache.cc',
- 'nacl/browser/pnacl_translation_cache.h',
- 'nacl/common/nacl_debug_exception_handler_win.cc',
- 'nacl/common/nacl_debug_exception_handler_win.h',
- ],
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'nacl_common',
- 'nacl_switches',
- 'url_formatter/url_formatter.gyp:url_formatter',
- '../native_client/src/trusted/service_runtime/service_runtime.gyp:sel',
- '../content/content.gyp:content_browser',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- 'conditions': [
- ['OS=="linux"', {
- 'sources': [
- '../components/nacl/zygote/nacl_fork_delegate_linux.cc',
- '../components/nacl/zygote/nacl_fork_delegate_linux.h',
- ],
- 'dependencies': [
- # Required by nacl_fork_delegate_linux.cc.
- '../sandbox/sandbox.gyp:suid_sandbox_client',
- '../sandbox/sandbox.gyp:sandbox_services',
- ]
- }],
- ],
- },
- {
- # GN version: //components/nacl/renderer
- 'target_name': 'nacl_renderer',
- 'type': 'static_library',
- 'sources': [
- 'nacl/renderer/file_downloader.cc',
- 'nacl/renderer/file_downloader.h',
- 'nacl/renderer/histogram.cc',
- 'nacl/renderer/histogram.h',
- 'nacl/renderer/json_manifest.cc',
- 'nacl/renderer/json_manifest.h',
- 'nacl/renderer/manifest_downloader.cc',
- 'nacl/renderer/manifest_downloader.h',
- 'nacl/renderer/manifest_service_channel.cc',
- 'nacl/renderer/manifest_service_channel.h',
- 'nacl/renderer/nacl_helper.cc',
- 'nacl/renderer/nacl_helper.h',
- 'nacl/renderer/nexe_load_manager.cc',
- 'nacl/renderer/nexe_load_manager.h',
- 'nacl/renderer/platform_info.cc',
- 'nacl/renderer/platform_info.h',
- 'nacl/renderer/pnacl_translation_resource_host.cc',
- 'nacl/renderer/pnacl_translation_resource_host.h',
- 'nacl/renderer/ppb_nacl_private_impl.cc',
- 'nacl/renderer/ppb_nacl_private_impl.h',
- 'nacl/renderer/progress_event.cc',
- 'nacl/renderer/progress_event.h',
- 'nacl/renderer/trusted_plugin_channel.cc',
- 'nacl/renderer/trusted_plugin_channel.h',
- ],
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'nacl_common',
- '../content/content.gyp:content_renderer',
- '../components/nacl/renderer/plugin/plugin.gyp:nacl_trusted_plugin',
- '../third_party/WebKit/public/blink.gyp:blink',
- ],
- },
- {
- # GN version: //components/nacl/loader:nacl_loader_unittests
- 'target_name': 'nacl_loader_unittests',
- 'type': '<(gtest_target_type)',
- 'sources': [
- 'nacl/loader/nacl_ipc_adapter_unittest.cc',
- 'nacl/loader/nacl_validation_query_unittest.cc',
- 'nacl/loader/run_all_unittests.cc',
- ],
- 'dependencies': [
- 'nacl',
- '../base/base.gyp:test_support_base',
- '../ipc/ipc.gyp:test_support_ipc',
- '../testing/gtest.gyp:gtest',
- ],
- },
- ],
- 'conditions': [
- ['OS=="linux"', {
- 'targets': [
- {
- # GN version: //components/nacl/loader:nacl_helper
- 'target_name': 'nacl_helper',
- 'type': 'executable',
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'nacl/loader/nacl_helper_linux.cc',
- 'nacl/loader/nacl_helper_linux.h',
- ],
- 'dependencies': [
- 'nacl_linux',
- ],
- 'cflags': ['-fPIE'],
- 'ldflags!': [
- # Do not pick the default ASan options from
- # build/sanitizers/sanitizer_options.cc to avoid a conflict with
- # those in nacl/nacl_helper_linux.cc.
- '-Wl,-u_sanitizer_options_link_helper',
- ],
- 'link_settings': {
- 'ldflags': ['-pie'],
- },
- }, {
- # GN version: //components/nacl/loader/sandbox_linux
- 'target_name': 'nacl_linux',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- # Allow .cc files to know if they're being compiled as part
- # of nacl_helper.
- 'IN_NACL_HELPER=1',
- ],
- 'sources': [
- 'nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.cc',
- 'nacl/loader/sandbox_linux/nacl_sandbox_linux.cc',
- ],
- 'dependencies': [
- 'nacl',
- 'nacl_common',
- 'nacl_switches',
- '../crypto/crypto.gyp:crypto',
- '../sandbox/sandbox.gyp:sandbox',
- ],
- 'conditions': [
- ['use_glib == 1', {
- 'dependencies': [
- '../build/linux/system.gyp:glib',
- ],
- }],
- ['use_seccomp_bpf == 0', {
- 'sources!': [
- '../content/common/sandbox_linux/sandbox_bpf_base_policy_linux.cc',
- '../content/common/sandbox_linux/sandbox_init_linux.cc',
- ],
- }, {
- 'defines': ['USE_SECCOMP_BPF'],
- }],
- ],
- 'cflags': ['-fPIE'],
- },
- ],
- }],
- ['OS=="win" and target_arch=="ia32"', {
- 'targets': [
- {
- 'target_name': 'nacl_win64',
- 'type': 'static_library',
- 'variables': {
- 'nacl_target': 1,
- },
- 'dependencies': [
- 'nacl_common_win64',
- '../mojo/mojo_edk.gyp:mojo_system_impl_win64',
- '../native_client/src/trusted/service_runtime/service_runtime.gyp:sel_main_chrome64',
- '../ppapi/ppapi_internal.gyp:ppapi_shared_win64',
- '../ppapi/ppapi_internal.gyp:ppapi_ipc_win64',
- ],
- 'export_dependent_settings': [
- '../ppapi/ppapi_internal.gyp:ppapi_ipc_win64',
- ],
- 'sources': [
- '../components/nacl/broker/nacl_broker_listener.cc',
- '../components/nacl/broker/nacl_broker_listener.h',
- '../components/nacl/common/nacl_debug_exception_handler_win.cc',
- '../components/nacl/loader/nacl_helper_win_64.cc',
- '../components/nacl/loader/nacl_helper_win_64.h',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- '<@(nacl_win64_defines)',
- 'COMPILE_CONTENT_STATICALLY',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- {
- # GN version: //components/nacl/common:switches
- 'target_name': 'nacl_switches_win64',
- 'type': 'static_library',
- 'sources': [
- 'nacl/common/nacl_switches.cc',
- 'nacl/common/nacl_switches.h',
- ],
- 'include_dirs': [
- '..',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- {
- # GN version: //components/nacl/common
- 'target_name': 'nacl_common_win64',
- 'type': 'static_library',
- 'defines': [
- 'COMPILE_CONTENT_STATICALLY',
- ],
- 'sources': [
- 'nacl/common/nacl_cmd_line.cc',
- 'nacl/common/nacl_cmd_line.h',
- 'nacl/common/nacl_constants.cc',
- 'nacl/common/nacl_constants.h',
- 'nacl/common/nacl_messages.cc',
- 'nacl/common/nacl_messages.h',
- 'nacl/common/nacl_renderer_messages.cc',
- 'nacl/common/nacl_renderer_messages.h',
- 'nacl/common/nacl_types.cc',
- 'nacl/common/nacl_types.h',
- 'nacl/common/nacl_types_param_traits.cc',
- 'nacl/common/nacl_types_param_traits.h',
- ],
- 'include_dirs': [
- '..',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- ],
- }],
- ],
- }, { # else (disable_nacl==1)
- 'targets': [
- {
- 'target_name': 'nacl',
- 'type': 'none',
- 'sources': [],
- },
- ],
- 'conditions': [
- ['OS=="win"', {
- 'targets': [
- {
- 'target_name': 'nacl_win64',
- 'type': 'none',
- 'sources': [],
- },
- {
- 'target_name': 'nacl_switches_win64',
- 'type': 'none',
- 'sources': [],
- },
- ],
- }],
- ],
- }],
- ['disable_nacl!=1 and test_isolation_mode!="noop"', {
- 'targets': [
- {
- 'target_name': 'nacl_loader_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'nacl_loader_unittests',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'nacl_loader_unittests.isolate',
- ],
- },
- ],
- }],
- ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
- 'targets': [
- {
- 'target_name': 'nacl_helper_nonsfi_unittests',
- 'type': '<(gtest_target_type)',
- 'sources': [
- 'nacl/loader/nonsfi/nacl_helper_nonsfi_unittests.cc',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_launcher_nacl_nonsfi',
- 'nacl_nonsfi.gyp:nacl_helper_nonsfi_unittests_main',
- ],
- },
- ],
- }],
- ],
- 'targets': [
- {
- # GN version: //components/nacl/common:switches
- 'target_name': 'nacl_switches',
- 'type': 'static_library',
- 'sources': [
- 'nacl/common/nacl_switches.cc',
- 'nacl/common/nacl_switches.h',
- ],
- 'include_dirs': [
- '..',
- ],
- },
- {
- # GN version: //components/nacl/common
- 'target_name': 'nacl_common',
- 'type': 'static_library',
- 'sources': [
- 'nacl/common/nacl_cmd_line.cc',
- 'nacl/common/nacl_cmd_line.h',
- 'nacl/common/nacl_constants.cc',
- 'nacl/common/nacl_constants.h',
- 'nacl/common/nacl_host_messages.cc',
- 'nacl/common/nacl_host_messages.h',
- 'nacl/common/nacl_messages.cc',
- 'nacl/common/nacl_messages.h',
- 'nacl/common/nacl_nonsfi_util.cc',
- 'nacl/common/nacl_nonsfi_util.h',
- 'nacl/common/nacl_process_type.h',
- 'nacl/common/nacl_renderer_messages.cc',
- 'nacl/common/nacl_renderer_messages.h',
- 'nacl/common/nacl_sandbox_type.h',
- 'nacl/common/nacl_types.cc',
- 'nacl/common/nacl_types.h',
- 'nacl/common/nacl_types_param_traits.cc',
- 'nacl/common/nacl_types_param_traits.h',
- 'nacl/common/pnacl_types.cc',
- 'nacl/common/pnacl_types.h',
- ],
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../content/content.gyp:content_common',
- '../url/ipc/url_ipc.gyp:url_ipc',
- ],
- },
- ]
-}
diff --git a/chromium/components/nacl/broker/BUILD.gn b/chromium/components/nacl/broker/BUILD.gn
index a2fa9a670db..25a5ac7db96 100644
--- a/chromium/components/nacl/broker/BUILD.gn
+++ b/chromium/components/nacl/broker/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/features.gni")
+import("//build/config/compiler/compiler.gni")
# This file builds nacl64.exe, which is a 64-bit x86 Windows executable
# used only in the 32-bit x86 Windows build. The :broker code runs both
@@ -26,6 +27,7 @@ source_set("broker") {
"//components/nacl/common:switches",
"//content/public/common:static_switches",
"//ipc",
+ "//mojo/edk/system",
"//sandbox",
]
@@ -67,6 +69,9 @@ if (current_cpu == "x86") {
sources = [
"$nacl64_out_dir/nacl64.exe",
]
+ if (symbol_level != 0) {
+ sources += [ "$nacl64_out_dir/nacl64.exe.pdb" ]
+ }
outputs = [
"$root_out_dir/{{source_file_part}}",
]
@@ -104,6 +109,7 @@ if (current_cpu == "x86") {
"//chrome:nacl64_exe_version",
"//components/crash/content/app:app_breakpad_mac_win_to_be_deleted",
"//components/nacl/loader:nacl_helper_win_64",
+ "//content/public/common:static_features",
"//content/public/common:static_switches",
"//ppapi/proxy:ipc",
"//sandbox",
@@ -155,7 +161,7 @@ if (current_cpu == "x86") {
"//chrome/installer/util:with_no_strings",
"//components/browser_watcher:browser_watcher_client",
"//components/flags_ui:switches",
- "//components/policy",
+ "//components/policy:generated",
"//content/public/common:static_switches",
"//ipc",
"//third_party/kasko",
diff --git a/chromium/components/nacl/browser/BUILD.gn b/chromium/components/nacl/browser/BUILD.gn
index 6336573e1ca..5307b79ceec 100644
--- a/chromium/components/nacl/browser/BUILD.gn
+++ b/chromium/components/nacl/browser/BUILD.gn
@@ -6,7 +6,7 @@ import("//build/config/features.gni")
assert(enable_nacl)
-source_set("browser") {
+static_library("browser") {
sources = [
"bad_message.cc",
"bad_message.h",
@@ -39,6 +39,7 @@ source_set("browser") {
"//content/public/browser",
"//content/public/common",
"//ipc",
+ "//mojo/edk/system",
"//native_client/src/trusted/service_runtime:sel_main_chrome",
"//net",
"//ppapi/host",
@@ -60,7 +61,9 @@ source_set("browser") {
"//sandbox/linux:suid_sandbox_client",
]
- data_deps += [ "//components/nacl/loader:helper_nonsfi" ]
+ if (enable_nacl_nonsfi) {
+ data_deps += [ "//components/nacl/loader:helper_nonsfi" ]
+ }
}
if (is_win && current_cpu == "x86") {
diff --git a/chromium/components/nacl/common/BUILD.gn b/chromium/components/nacl/common/BUILD.gn
index f1822b36782..2114eafcecf 100644
--- a/chromium/components/nacl/common/BUILD.gn
+++ b/chromium/components/nacl/common/BUILD.gn
@@ -6,7 +6,7 @@ import("//build/config/features.gni")
if (enable_nacl) {
# This is separate so it can be used by ../broker:nacl64.
- source_set("minimal") {
+ static_library("minimal") {
sources = [
"nacl_cmd_line.cc",
"nacl_cmd_line.h",
@@ -49,7 +49,7 @@ if (enable_nacl) {
]
}
- source_set("common") {
+ static_library("common") {
sources = [
"nacl_host_messages.cc",
"nacl_host_messages.h",
@@ -105,7 +105,7 @@ source_set("process_type") {
]
}
-source_set("switches") {
+static_library("switches") {
sources = [
"nacl_switches.cc",
"nacl_switches.h",
diff --git a/chromium/components/nacl/loader/BUILD.gn b/chromium/components/nacl/loader/BUILD.gn
index 4f394d32586..cef8842020d 100644
--- a/chromium/components/nacl/loader/BUILD.gn
+++ b/chromium/components/nacl/loader/BUILD.gn
@@ -49,8 +49,10 @@ source_set("minimal_content_dummy") {
check_includes = false
sources = [
"//content/public/common/child_process_sandbox_support_linux.h",
+ "//content/public/common/content_descriptors.h",
"//content/public/common/content_switches.h",
"//content/public/common/main_function_params.h",
+ "//content/public/common/mojo_channel_switches.h",
"//content/public/common/sandbox_init.h",
]
}
@@ -141,23 +143,25 @@ if (is_linux) {
]
}
- test("nacl_helper_nonsfi_unittests") {
- sources = [
- "nonsfi/nacl_helper_nonsfi_unittests.cc",
- ]
- deps = [
- "//base",
- "//base/test:test_launcher_nacl_nonsfi",
- ]
- data_deps = [
- ":nacl_helper_nonsfi_unittests_main_copy(//build/toolchain/nacl:newlib_pnacl_nonsfi)",
- ]
- }
+ if (enable_nacl_nonsfi) {
+ test("nacl_helper_nonsfi_unittests") {
+ sources = [
+ "nonsfi/nacl_helper_nonsfi_unittests.cc",
+ ]
+ deps = [
+ "//base",
+ "//base/test:test_launcher_nacl_nonsfi",
+ ]
+ data_deps = [
+ ":nacl_helper_nonsfi_unittests_main_copy(//build/toolchain/nacl:newlib_pnacl_nonsfi)",
+ ]
+ }
- group("helper_nonsfi") {
- data_deps = [
- ":nacl_helper_nonsfi_copy(//build/toolchain/nacl:newlib_pnacl_nonsfi)",
- ]
+ group("helper_nonsfi") {
+ data_deps = [
+ ":nacl_helper_nonsfi_copy(//build/toolchain/nacl:newlib_pnacl_nonsfi)",
+ ]
+ }
}
}
@@ -175,6 +179,7 @@ if (is_win && target_cpu == "x86" && current_cpu == "x64") {
"//components/nacl/broker",
"//components/nacl/common:switches",
"//content/public/common:static_switches",
+ "//mojo/edk/system",
"//sandbox",
]
}
diff --git a/chromium/components/nacl/renderer/BUILD.gn b/chromium/components/nacl/renderer/BUILD.gn
index 9a1ac38a812..065ca4fac5d 100644
--- a/chromium/components/nacl/renderer/BUILD.gn
+++ b/chromium/components/nacl/renderer/BUILD.gn
@@ -6,7 +6,7 @@ import("//build/config/features.gni")
assert(enable_nacl)
-source_set("renderer") {
+static_library("renderer") {
sources = [
"file_downloader.cc",
"file_downloader.h",
@@ -45,5 +45,6 @@ source_set("renderer") {
"//ppapi/proxy:ipc",
"//ppapi/shared_impl",
"//third_party/WebKit/public:blink",
+ "//v8",
]
}
diff --git a/chromium/components/nacl/renderer/plugin/BUILD.gn b/chromium/components/nacl/renderer/plugin/BUILD.gn
index 8f8d6206214..873422e0021 100644
--- a/chromium/components/nacl/renderer/plugin/BUILD.gn
+++ b/chromium/components/nacl/renderer/plugin/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("nacl_trusted_plugin") {
+static_library("nacl_trusted_plugin") {
sources = [
"module_ppapi.cc",
"nacl_subprocess.cc",
diff --git a/chromium/components/nacl/renderer/plugin/plugin.gyp b/chromium/components/nacl/renderer/plugin/plugin.gyp
deleted file mode 100644
index 6fb305d4eb9..00000000000
--- a/chromium/components/nacl/renderer/plugin/plugin.gyp
+++ /dev/null
@@ -1,33 +0,0 @@
-# -*- python -*-
-# Copyright (c) 2011 The Native Client Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'chromium_code': 1, # Use higher warning level.
- },
- 'targets': [
- {
- 'target_name': 'nacl_trusted_plugin',
- 'type': 'static_library',
- 'sources': [
- 'module_ppapi.cc',
- 'nacl_subprocess.cc',
- 'plugin.cc',
- 'pnacl_coordinator.cc',
- 'pnacl_resources.cc',
- 'pnacl_translate_thread.cc',
- 'ppapi_entrypoints.cc',
- 'service_runtime.cc',
- ],
- 'dependencies': [
- '<(DEPTH)/media/media.gyp:shared_memory_support',
- '<(DEPTH)/ppapi/ppapi.gyp:ppapi_cpp_objects',
- '<(DEPTH)/ppapi/ppapi.gyp:ppapi_internal_module',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- ],
-}
diff --git a/chromium/components/nacl_helper_nonsfi_unittests.isolate b/chromium/components/nacl_helper_nonsfi_unittests.isolate
deleted file mode 100644
index f0e05a26a56..00000000000
--- a/chromium/components/nacl_helper_nonsfi_unittests.isolate
+++ /dev/null
@@ -1,18 +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.
-{
- 'conditions': [
- ['OS=="linux"', {
- 'variables': {
- 'command': [
- '<(PRODUCT_DIR)/nacl_helper_nonsfi_unittests',
- ],
- 'files': [
- '<(PRODUCT_DIR)/nacl_helper_nonsfi_unittests',
- '<(PRODUCT_DIR)/nacl_helper_nonsfi_unittests_main',
- ],
- },
- }],
- ],
-}
diff --git a/chromium/components/nacl_loader_unittests.isolate b/chromium/components/nacl_loader_unittests.isolate
deleted file mode 100644
index 4a6fe8c1310..00000000000
--- a/chromium/components/nacl_loader_unittests.isolate
+++ /dev/null
@@ -1,18 +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.
-{
- 'conditions': [
- ['OS=="linux" or OS=="mac" or OS=="win"', {
- 'variables': {
- 'command': [
- '<(PRODUCT_DIR)/nacl_loader_unittests<(EXECUTABLE_SUFFIX)',
- ],
- },
- }],
- ],
- 'includes': [
- # This is needed because of base/ dependencies on icudtl.dat.
- '../base/base.isolate',
- ],
-}
diff --git a/chromium/components/nacl_nonsfi.gyp b/chromium/components/nacl_nonsfi.gyp
deleted file mode 100644
index 20df8231dad..00000000000
--- a/chromium/components/nacl_nonsfi.gyp
+++ /dev/null
@@ -1,297 +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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'includes': [
- '../build/common_untrusted.gypi',
- ],
- 'conditions': [
- ['disable_nacl==0 and disable_nacl_untrusted==0', {
- 'targets': [
- {
- # nacl_helper_nonsfi is similar to nacl_helper (built in nacl.gyp)
- # but for the NaCl plugin in Non-SFI mode.
- # This binary is built using the PNaCl toolchain, but it is native
- # linux binary and will run on Linux directly.
- # Most library code can be shared with the one for untrusted build
- # (i.e. the one for irt.nexe built by the NaCl/PNaCl toolchain), but
- # as nacl_helper_nonsfi runs on Linux, there are some differences,
- # such as MessageLoopForIO (which is based on libevent in Non-SFI
- # mode) or ipc_channel implementation.
- # Because of the toolchain, in both builds, OS_NACL macro (derived
- # from __native_client__ macro) is defined. Code can test whether
- # __native_client_nonsfi__ is #defined in order to determine
- # whether it is being compiled for SFI mode or Non-SFI mode.
- #
- # Currently, nacl_helper_nonsfi is under development and the binary
- # does nothing (i.e. it has only empty main(), now).
- # TODO(crbug.com/358465): Implement it then switch nacl_helper in
- # Non-SFI mode to nacl_helper_nonsfi.
- 'target_name': 'nacl_helper_nonsfi',
- 'type': 'none',
- 'variables': {
- 'nacl_untrusted_build': 1,
- 'nexe_target': 'nacl_helper_nonsfi',
- # Rename the output binary file to nacl_helper_nonsfi and put it
- # directly under out/{Debug,Release}/.
- 'out_newlib32_nonsfi': '<(PRODUCT_DIR)/nacl_helper_nonsfi',
- 'out_newlib_arm_nonsfi': '<(PRODUCT_DIR)/nacl_helper_nonsfi',
-
- 'build_glibc': 0,
- 'build_newlib': 0,
- 'build_irt': 0,
- 'build_pnacl_newlib': 0,
- 'build_nonsfi_helper': 1,
-
- 'sources': [
- 'nacl/common/nacl_messages.cc',
- 'nacl/common/nacl_switches.cc',
- 'nacl/common/nacl_types.cc',
- 'nacl/common/nacl_types_param_traits.cc',
- 'nacl/loader/nacl_helper_linux.cc',
- 'nacl/loader/nacl_trusted_listener.cc',
- 'nacl/loader/nonsfi/nonsfi_listener.cc',
- 'nacl/loader/nonsfi/nonsfi_main.cc',
- ],
-
- 'link_flags': [
- '-lbase_nacl_nonsfi',
- '-lcommand_buffer_client_nacl',
- '-lcommand_buffer_common_nacl',
- '-lcontent_common_nacl_nonsfi',
- '-lelf_loader',
- '-levent_nacl_nonsfi',
- '-lgio',
- '-lgles2_cmd_helper_nacl',
- '-lgles2_implementation_nacl',
- '-lgles2_utils_nacl',
- '-lgpu_ipc_nacl',
- '-lipc_nacl_nonsfi',
- '-lmojo_cpp_bindings_nacl',
- '-lmojo_cpp_system_nacl',
- '-lmojo_public_system_nacl',
- '-lmojo_system_impl_nacl_nonsfi',
- '-lnacl_helper_nonsfi_sandbox',
- '-lplatform',
- '-lppapi_ipc_nacl',
- '-lppapi_proxy_nacl',
- '-lppapi_shared_nacl',
- '-lsandbox_linux_nacl_nonsfi',
- '-lshared_memory_support_nacl',
- '-ltracing_nacl',
- ],
-
- 'conditions': [
- ['target_arch=="ia32" or target_arch=="x64"', {
- 'extra_deps_newlib32_nonsfi': [
- '>(tc_lib_dir_nonsfi_helper32)/libbase_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libcommand_buffer_client_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libcommand_buffer_common_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libcontent_common_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libelf_loader.a',
- '>(tc_lib_dir_nonsfi_helper32)/libevent_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libgio.a',
- '>(tc_lib_dir_nonsfi_helper32)/libgles2_cmd_helper_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libgles2_implementation_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libgles2_utils_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libgpu_ipc_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libipc_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libmojo_cpp_bindings_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libmojo_cpp_system_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libmojo_public_system_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libmojo_system_impl_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libnacl_helper_nonsfi_sandbox.a',
- '>(tc_lib_dir_nonsfi_helper32)/libplatform.a',
- '>(tc_lib_dir_nonsfi_helper32)/libppapi_ipc_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libppapi_proxy_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libppapi_shared_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libsandbox_linux_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libshared_memory_support_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libtracing_nacl.a',
- ],
- }],
- ['target_arch=="arm"', {
- 'extra_deps_newlib_arm_nonsfi': [
- '>(tc_lib_dir_nonsfi_helper_arm)/libbase_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libcommand_buffer_client_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libcommand_buffer_common_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libcontent_common_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libelf_loader.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libevent_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libgio.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libgles2_cmd_helper_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libgles2_implementation_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libgles2_utils_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libgpu_ipc_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libipc_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libmojo_cpp_bindings_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libmojo_cpp_system_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libmojo_public_system_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libmojo_system_impl_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libnacl_helper_nonsfi_sandbox.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libplatform.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libppapi_ipc_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libppapi_proxy_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libppapi_shared_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libsandbox_linux_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libshared_memory_support_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libtracing_nacl.a',
- ],
- }],
- ],
- },
- 'dependencies': [
- '../base/base_nacl.gyp:base_nacl_nonsfi',
- '../content/content_nacl_nonsfi.gyp:content_common_nacl_nonsfi',
- '../ipc/ipc_nacl.gyp:ipc_nacl_nonsfi',
- '../mojo/mojo_edk_nacl.gyp:mojo_system_impl_nacl_nonsfi',
- '../mojo/mojo_public_nacl.gyp:mojo_cpp_bindings_nacl',
- '../mojo/mojo_public_nacl.gyp:mojo_cpp_system_nacl',
- '../mojo/mojo_public_nacl.gyp:mojo_public_system_nacl',
- '../native_client/src/nonsfi/irt/irt.gyp:nacl_sys_private',
- '../native_client/src/nonsfi/loader/loader.gyp:elf_loader',
- '../native_client/src/untrusted/nacl/nacl.gyp:nacl_lib_newlib',
- '../ppapi/ppapi_proxy_nacl.gyp:ppapi_proxy_nacl',
- '../sandbox/linux/sandbox_linux_nacl_nonsfi.gyp:sandbox_linux_nacl_nonsfi',
- 'nacl_helper_nonsfi_sandbox',
- ],
- },
-
- {
- 'target_name': 'nacl_helper_nonsfi_sandbox',
- 'type': 'none',
- 'variables': {
- 'nacl_untrusted_build': 1,
- 'nlib_target': 'libnacl_helper_nonsfi_sandbox.a',
-
- 'build_glibc': 0,
- 'build_newlib': 0,
- 'build_irt': 0,
- 'build_pnacl_newlib': 0,
- 'build_nonsfi_helper': 1,
-
- 'sources': [
- 'nacl/loader/nonsfi/nonsfi_sandbox.cc',
- 'nacl/loader/sandbox_linux/nacl_sandbox_linux.cc',
- ],
- },
- 'dependencies': [
- '../base/base_nacl.gyp:base_nacl_nonsfi',
- '../content/content_nacl_nonsfi.gyp:content_common_nacl_nonsfi',
- '../sandbox/linux/sandbox_linux_nacl_nonsfi.gyp:sandbox_linux_nacl_nonsfi',
- ],
- },
- ],
- }],
-
- ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
- 'targets': [
- {
- 'target_name': 'nacl_helper_nonsfi_unittests_main',
- 'type': 'none',
- 'variables': {
- 'nacl_untrusted_build': 1,
- 'nexe_target': 'nacl_helper_nonsfi_unittests_main',
- # Rename the output binary file to
- # nacl_helper_nonsfi_unittests_main and put it directly under
- # out/{Debug,Release}/, so that this is in the standard location,
- # for running on the buildbots.
- 'out_newlib32_nonsfi': '<(PRODUCT_DIR)/nacl_helper_nonsfi_unittests_main',
- 'out_newlib_arm_nonsfi': '<(PRODUCT_DIR)/nacl_helper_nonsfi_unittests_main',
-
- 'build_glibc': 0,
- 'build_newlib': 0,
- 'build_irt': 0,
- 'build_pnacl_newlib': 0,
- 'build_nonsfi_helper': 1,
-
- 'sources': [
- 'nacl/loader/nonsfi/nonsfi_sandbox_sigsys_unittest.cc',
- 'nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc',
- 'nacl/loader/nonsfi/run_all_unittests.cc',
- ],
-
- 'link_flags': [
- '-lbase_nacl_nonsfi',
- '-lcontent_common_nacl_nonsfi',
- '-levent_nacl_nonsfi',
- '-lgio',
- '-lgtest_nacl',
- '-lnacl_helper_nonsfi_sandbox',
- '-lplatform',
- '-lsandbox_linux_nacl_nonsfi',
- '-lsandbox_linux_test_utils_nacl_nonsfi',
- '-ltest_support_base_nacl_nonsfi',
- ],
-
- 'conditions': [
- ['target_arch=="ia32" or target_arch=="x64"', {
- 'extra_deps_newlib32_nonsfi': [
- '>(tc_lib_dir_nonsfi_helper32)/libbase_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libcontent_common_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libevent_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libgio.a',
- '>(tc_lib_dir_nonsfi_helper32)/libgtest_nacl.a',
- '>(tc_lib_dir_nonsfi_helper32)/libnacl_helper_nonsfi_sandbox.a',
- '>(tc_lib_dir_nonsfi_helper32)/libplatform.a',
- '>(tc_lib_dir_nonsfi_helper32)/libsandbox_linux_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libsandbox_linux_test_utils_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper32)/libtest_support_base_nacl_nonsfi.a',
- ],
- }],
- ['target_arch=="arm"', {
- 'extra_deps_newlib_arm_nonsfi': [
- '>(tc_lib_dir_nonsfi_helper_arm)/libbase_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libcontent_common_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libevent_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libgio.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libgtest_nacl.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libnacl_helper_nonsfi_sandbox.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libplatform.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libsandbox_linux_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libsandbox_linux_test_utils_nacl_nonsfi.a',
- '>(tc_lib_dir_nonsfi_helper_arm)/libtest_support_base_nacl_nonsfi.a',
- ],
- }],
- ],
- },
-
- 'dependencies': [
- '../base/base_nacl.gyp:base_nacl_nonsfi',
- '../base/base_nacl.gyp:test_support_base_nacl_nonsfi',
- '../content/content_nacl_nonsfi.gyp:content_common_nacl_nonsfi',
- '../native_client/src/nonsfi/irt/irt.gyp:nacl_sys_private',
- '../native_client/src/untrusted/nacl/nacl.gyp:nacl_lib_newlib',
- '../sandbox/linux/sandbox_linux_nacl_nonsfi.gyp:sandbox_linux_nacl_nonsfi',
- '../sandbox/linux/sandbox_linux_nacl_nonsfi.gyp:sandbox_linux_test_utils_nacl_nonsfi',
- '../testing/gtest_nacl.gyp:gtest_nacl',
- 'nacl_helper_nonsfi_sandbox',
- ],
- },
- ],
- }],
-
- ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1 and test_isolation_mode!="noop"', {
- 'targets': [
- {
- 'target_name': 'nacl_helper_nonsfi_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'nacl.gyp:nacl_helper_nonsfi_unittests',
- 'nacl_helper_nonsfi_unittests_main',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'nacl_helper_nonsfi_unittests.isolate',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/navigation_interception.gypi b/chromium/components/navigation_interception.gypi
deleted file mode 100644
index 7ccc4cd80d6..00000000000
--- a/chromium/components/navigation_interception.gypi
+++ /dev/null
@@ -1,81 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/navigation_interception
- 'target_name': 'navigation_interception',
- 'type': 'static_library',
- 'defines!': ['CONTENT_IMPLEMENTATION'],
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../net/net.gyp:net',
- '../ui/base/ui_base.gyp:ui_base',
- ],
- 'include_dirs': [
- '..',
- '../skia/config',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'navigation_interception/intercept_navigation_throttle.cc',
- 'navigation_interception/intercept_navigation_throttle.h',
- 'navigation_interception/navigation_params.cc',
- 'navigation_interception/navigation_params.h',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'dependencies': [
- 'navigation_interception_jni_headers',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'navigation_interception/component_jni_registrar.cc',
- 'navigation_interception/component_jni_registrar.h',
- 'navigation_interception/intercept_navigation_delegate.cc',
- 'navigation_interception/intercept_navigation_delegate.h',
- 'navigation_interception/navigation_params_android.cc',
- 'navigation_interception/navigation_params_android.h',
- ],
- }],
- ],
- },
- ],
- 'conditions': [
- ['OS=="android"', {
- 'targets': [
- {
- # GN version: //components/navigation_intercaption/android:navigation_interception_java
- 'target_name': 'navigation_interception_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'variables': {
- 'java_in_dir': 'navigation_interception/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN version: //components/navigation_intercaption:jni_headers
- 'target_name': 'navigation_interception_jni_headers',
- 'type': 'none',
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'navigation_interception/android/java/src/org/chromium/components/navigation_interception/InterceptNavigationDelegate.java',
- 'navigation_interception/android/java/src/org/chromium/components/navigation_interception/NavigationParams.java',
- ],
- 'variables': {
- 'jni_gen_package': 'navigation_interception',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/navigation_interception/BUILD.gn b/chromium/components/navigation_interception/BUILD.gn
index 568a5f8da9a..4b2ba36c76f 100644
--- a/chromium/components/navigation_interception/BUILD.gn
+++ b/chromium/components/navigation_interception/BUILD.gn
@@ -6,7 +6,7 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-source_set("navigation_interception") {
+static_library("navigation_interception") {
sources = [
"intercept_navigation_throttle.cc",
"intercept_navigation_throttle.h",
@@ -24,8 +24,6 @@ source_set("navigation_interception") {
if (is_android) {
sources += [
- "component_jni_registrar.cc",
- "component_jni_registrar.h",
"intercept_navigation_delegate.cc",
"intercept_navigation_delegate.h",
"navigation_params_android.cc",
@@ -36,7 +34,6 @@ source_set("navigation_interception") {
}
if (is_android) {
- # GYP: //components/navigation_interception.gypi:navigation_interception_jni_headers
generate_jni("jni_headers") {
sources = [
"android/java/src/org/chromium/components/navigation_interception/InterceptNavigationDelegate.java",
diff --git a/chromium/components/navigation_interception/intercept_navigation_delegate.cc b/chromium/components/navigation_interception/intercept_navigation_delegate.cc
index 13f6b0b315e..710c0c782b1 100644
--- a/chromium/components/navigation_interception/intercept_navigation_delegate.cc
+++ b/chromium/components/navigation_interception/intercept_navigation_delegate.cc
@@ -88,8 +88,8 @@ InterceptNavigationDelegate* InterceptNavigationDelegate::Get(
std::unique_ptr<content::NavigationThrottle>
InterceptNavigationDelegate::CreateThrottleFor(
content::NavigationHandle* handle) {
- return base::WrapUnique(new InterceptNavigationThrottle(
- handle, base::Bind(&CheckIfShouldIgnoreNavigationOnUIThread), false));
+ return base::MakeUnique<InterceptNavigationThrottle>(
+ handle, base::Bind(&CheckIfShouldIgnoreNavigationOnUIThread), false);
}
// static
@@ -138,19 +138,11 @@ bool InterceptNavigationDelegate::ShouldIgnoreNavigation(
env, navigation_params, has_user_gesture_carryover);
return Java_InterceptNavigationDelegate_shouldIgnoreNavigation(
- env,
- jdelegate.obj(),
- jobject_params.obj());
+ env, jdelegate, jobject_params);
}
void InterceptNavigationDelegate::UpdateLastUserGestureCarryoverTimestamp() {
last_user_gesture_carryover_timestamp_ = base::TimeTicks::Now();
}
-// Register native methods.
-
-bool RegisterInterceptNavigationDelegate(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace navigation_interception
diff --git a/chromium/components/navigation_interception/intercept_navigation_delegate.h b/chromium/components/navigation_interception/intercept_navigation_delegate.h
index f549126fed4..e8e0ecb2875 100644
--- a/chromium/components/navigation_interception/intercept_navigation_delegate.h
+++ b/chromium/components/navigation_interception/intercept_navigation_delegate.h
@@ -75,8 +75,6 @@ class InterceptNavigationDelegate : public base::SupportsUserData::Data {
DISALLOW_COPY_AND_ASSIGN(InterceptNavigationDelegate);
};
-bool RegisterInterceptNavigationDelegate(JNIEnv* env);
-
} // namespace navigation_interception
#endif // COMPONENTS_NAVIGATION_INTERCEPTION_INTERCEPT_NAVIGATION_DELEGATE_H_
diff --git a/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc b/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc
index 33817bb0d3c..a32c2fc4429 100644
--- a/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc
+++ b/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc
@@ -65,11 +65,11 @@ class InterceptNavigationThrottleTest
content::NavigationHandle::CreateNavigationHandleForTesting(url,
main_rfh());
test_handle->RegisterThrottleForTesting(
- base::WrapUnique(new InterceptNavigationThrottle(
+ base::MakeUnique<InterceptNavigationThrottle>(
test_handle.get(),
base::Bind(&MockInterceptCallbackReceiver::ShouldIgnoreNavigation,
base::Unretained(mock_callback_receiver_.get())),
- true)));
+ true));
return test_handle->CallWillStartRequestForTesting(
is_post, content::Referrer(), false, ui::PAGE_TRANSITION_LINK, false);
}
@@ -79,11 +79,11 @@ class InterceptNavigationThrottleTest
content::NavigationHandle::CreateNavigationHandleForTesting(
GURL(kTestUrl), main_rfh());
test_handle->RegisterThrottleForTesting(
- base::WrapUnique(new InterceptNavigationThrottle(
+ base::MakeUnique<InterceptNavigationThrottle>(
test_handle.get(),
base::Bind(&MockInterceptCallbackReceiver::ShouldIgnoreNavigation,
base::Unretained(mock_callback_receiver_.get())),
- true)));
+ true));
test_handle->CallWillStartRequestForTesting(
true, content::Referrer(), false, ui::PAGE_TRANSITION_LINK, false);
return test_handle->CallWillRedirectRequestForTesting(GURL(kTestUrl), false,
diff --git a/chromium/components/navigation_interception/navigation_params_android.cc b/chromium/components/navigation_interception/navigation_params_android.cc
index e6848d8853b..e459d36273a 100644
--- a/chromium/components/navigation_interception/navigation_params_android.cc
+++ b/chromium/components/navigation_interception/navigation_params_android.cc
@@ -8,6 +8,7 @@
#include "jni/NavigationParams_jni.h"
using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaLocalRef;
namespace navigation_interception {
@@ -22,22 +23,10 @@ base::android::ScopedJavaLocalRef<jobject> CreateJavaNavigationParams(
ConvertUTF8ToJavaString(env, params.referrer().url.spec());
return Java_NavigationParams_create(
- env,
- jstring_url.obj(),
- jstring_referrer.obj(),
- params.is_post(),
- params.has_user_gesture(),
- params.transition_type(),
- params.is_redirect(),
- params.is_external_protocol(),
- params.is_main_frame(),
+ env, jstring_url, jstring_referrer, params.is_post(),
+ params.has_user_gesture(), params.transition_type(), params.is_redirect(),
+ params.is_external_protocol(), params.is_main_frame(),
has_user_gesture_carryover);
}
-// Register native methods.
-
-bool RegisterNavigationParams(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace navigation_interception
diff --git a/chromium/components/navigation_interception/navigation_params_android.h b/chromium/components/navigation_interception/navigation_params_android.h
index 5b3a45549a2..7bb164dd98c 100644
--- a/chromium/components/navigation_interception/navigation_params_android.h
+++ b/chromium/components/navigation_interception/navigation_params_android.h
@@ -16,8 +16,6 @@ base::android::ScopedJavaLocalRef<jobject> CreateJavaNavigationParams(
const NavigationParams& params,
bool has_user_gesture_carryover);
-bool RegisterNavigationParams(JNIEnv* env);
-
} // namespace navigation_interception
#endif // COMPONENTS_NAVIGATION_INTERCEPTION_NAVIGATION_PARAMS_ANDROID_H_
diff --git a/chromium/components/navigation_metrics.gypi b/chromium/components/navigation_metrics.gypi
deleted file mode 100644
index 5e20c466c6b..00000000000
--- a/chromium/components/navigation_metrics.gypi
+++ /dev/null
@@ -1,26 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'navigation_metrics',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../url/url.gyp:url_lib',
- 'keyed_service_core',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'navigation_metrics/navigation_metrics.cc',
- 'navigation_metrics/navigation_metrics.h',
- 'navigation_metrics/origins_seen_service.cc',
- 'navigation_metrics/origins_seen_service.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/navigation_metrics/BUILD.gn b/chromium/components/navigation_metrics/BUILD.gn
index 757babd8d05..df986e8a8f2 100644
--- a/chromium/components/navigation_metrics/BUILD.gn
+++ b/chromium/components/navigation_metrics/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("navigation_metrics") {
+static_library("navigation_metrics") {
sources = [
"navigation_metrics.cc",
"navigation_metrics.h",
diff --git a/chromium/components/net_log.gypi b/chromium/components/net_log.gypi
deleted file mode 100644
index b99ad3ebb42..00000000000
--- a/chromium/components/net_log.gypi
+++ /dev/null
@@ -1,31 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/net_log
- 'target_name': 'net_log',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- 'data_reduction_proxy_core_common',
- 'version_info',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'net_log/chrome_net_log.cc',
- 'net_log/chrome_net_log.h',
- 'net_log/net_export_ui_constants.cc',
- 'net_log/net_export_ui_constants.h',
- 'net_log/net_log_temp_file.cc',
- 'net_log/net_log_temp_file.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/net_log/BUILD.gn b/chromium/components/net_log/BUILD.gn
index 8bdc1617c29..ec0c7f833fc 100644
--- a/chromium/components/net_log/BUILD.gn
+++ b/chromium/components/net_log/BUILD.gn
@@ -2,14 +2,14 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("net_log") {
+static_library("net_log") {
sources = [
"chrome_net_log.cc",
"chrome_net_log.h",
"net_export_ui_constants.cc",
"net_export_ui_constants.h",
- "net_log_temp_file.cc",
- "net_log_temp_file.h",
+ "net_log_file_writer.cc",
+ "net_log_file_writer.h",
]
deps = [
@@ -23,7 +23,7 @@ source_set("net_log") {
source_set("unit_tests") {
testonly = true
sources = [
- "net_log_temp_file_unittest.cc",
+ "net_log_file_writer_unittest.cc",
]
deps = [
":net_log",
diff --git a/chromium/components/net_log/chrome_net_log.cc b/chromium/components/net_log/chrome_net_log.cc
index f1f552239af..5ec2e55a7c5 100644
--- a/chromium/components/net_log/chrome_net_log.cc
+++ b/chromium/components/net_log/chrome_net_log.cc
@@ -10,13 +10,13 @@
#include "base/command_line.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/sys_info.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h"
-#include "components/net_log/net_log_temp_file.h"
-#include "components/net_log/net_log_temp_file.h"
+#include "components/net_log/net_log_file_writer.h"
#include "components/version_info/version_info.h"
#include "net/log/net_log_util.h"
#include "net/log/trace_net_log_observer.h"
@@ -29,8 +29,8 @@ ChromeNetLog::ChromeNetLog(
net::NetLogCaptureMode log_file_mode,
const base::CommandLine::StringType& command_line_string,
const std::string& channel_string)
- : net_log_temp_file_(
- new NetLogTempFile(this, command_line_string, channel_string)) {
+ : net_log_file_writer_(
+ new NetLogFileWriter(this, command_line_string, channel_string)) {
if (!log_file.empty()) {
// Much like logging.h, bypass threading restrictions by using fopen
// directly. Have to write on a thread that's shutdown to handle events on
@@ -65,7 +65,7 @@ ChromeNetLog::ChromeNetLog(
}
ChromeNetLog::~ChromeNetLog() {
- net_log_temp_file_.reset();
+ net_log_file_writer_.reset();
// Remove the observers we own before we're destroyed.
if (write_to_file_observer_)
write_to_file_observer_->StopObserving(nullptr);
@@ -74,7 +74,7 @@ ChromeNetLog::~ChromeNetLog() {
}
// static
-base::Value* ChromeNetLog::GetConstants(
+std::unique_ptr<base::Value> ChromeNetLog::GetConstants(
const base::CommandLine::StringType& command_line_string,
const std::string& channel_string) {
std::unique_ptr<base::DictionaryValue> constants_dict =
@@ -83,30 +83,28 @@ base::Value* ChromeNetLog::GetConstants(
// Add a dictionary with the version of the client and its command line
// arguments.
- {
- base::DictionaryValue* dict = new base::DictionaryValue();
-
- // We have everything we need to send the right values.
- dict->SetString("name", version_info::GetProductName());
- dict->SetString("version", version_info::GetVersionNumber());
- dict->SetString("cl", version_info::GetLastChange());
- dict->SetString("version_mod", channel_string);
- dict->SetString("official", version_info::IsOfficialBuild() ? "official"
- : "unofficial");
- std::string os_type = base::StringPrintf(
- "%s: %s (%s)", base::SysInfo::OperatingSystemName().c_str(),
- base::SysInfo::OperatingSystemVersion().c_str(),
- base::SysInfo::OperatingSystemArchitecture().c_str());
- dict->SetString("os_type", os_type);
- dict->SetString("command_line", command_line_string);
-
- constants_dict->Set("clientInfo", dict);
-
- data_reduction_proxy::DataReductionProxyEventStore::AddConstants(
- constants_dict.get());
- }
-
- return constants_dict.release();
+ auto dict = base::MakeUnique<base::DictionaryValue>();
+
+ // We have everything we need to send the right values.
+ dict->SetString("name", version_info::GetProductName());
+ dict->SetString("version", version_info::GetVersionNumber());
+ dict->SetString("cl", version_info::GetLastChange());
+ dict->SetString("version_mod", channel_string);
+ dict->SetString("official",
+ version_info::IsOfficialBuild() ? "official" : "unofficial");
+ std::string os_type = base::StringPrintf(
+ "%s: %s (%s)", base::SysInfo::OperatingSystemName().c_str(),
+ base::SysInfo::OperatingSystemVersion().c_str(),
+ base::SysInfo::OperatingSystemArchitecture().c_str());
+ dict->SetString("os_type", os_type);
+ dict->SetString("command_line", command_line_string);
+
+ constants_dict->Set("clientInfo", std::move(dict));
+
+ data_reduction_proxy::DataReductionProxyEventStore::AddConstants(
+ constants_dict.get());
+
+ return std::move(constants_dict);
}
} // namespace net_log
diff --git a/chromium/components/net_log/chrome_net_log.h b/chromium/components/net_log/chrome_net_log.h
index 6c9bc5e60e8..bca0d2889df 100644
--- a/chromium/components/net_log/chrome_net_log.h
+++ b/chromium/components/net_log/chrome_net_log.h
@@ -24,7 +24,7 @@ class TraceNetLogObserver;
namespace net_log {
-class NetLogTempFile;
+class NetLogFileWriter;
// ChromeNetLog is an implementation of NetLog that adds file loggers
// as its observers.
@@ -40,17 +40,17 @@ class ChromeNetLog : public net::NetLog {
const std::string& channel_string);
~ChromeNetLog() override;
- NetLogTempFile* net_log_temp_file() { return net_log_temp_file_.get(); }
+ NetLogFileWriter* net_log_file_writer() { return net_log_file_writer_.get(); }
// Returns a Value containing constants needed to load a log file.
- // Safe to call on any thread. Caller takes ownership of the returned Value.
- static base::Value* GetConstants(
+ // Safe to call on any thread.
+ static std::unique_ptr<base::Value> GetConstants(
const base::CommandLine::StringType& command_line_string,
const std::string& channel_string);
private:
std::unique_ptr<net::WriteToFileNetLogObserver> write_to_file_observer_;
- std::unique_ptr<NetLogTempFile> net_log_temp_file_;
+ std::unique_ptr<NetLogFileWriter> net_log_file_writer_;
std::unique_ptr<net::TraceNetLogObserver> trace_net_log_observer_;
DISALLOW_COPY_AND_ASSIGN(ChromeNetLog);
diff --git a/chromium/components/net_log/net_log_file_writer.cc b/chromium/components/net_log/net_log_file_writer.cc
new file mode 100644
index 00000000000..db51ca7d2df
--- /dev/null
+++ b/chromium/components/net_log/net_log_file_writer.cc
@@ -0,0 +1,246 @@
+// 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 "components/net_log/net_log_file_writer.h"
+
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "components/net_log/chrome_net_log.h"
+#include "net/log/write_to_file_net_log_observer.h"
+
+namespace net_log {
+
+// Path of logs if relative to default temporary directory of
+// base::GetTempDir(). Must be kept in sync with
+// chrome/android/java/res/xml/file_paths.xml. Only used if
+// not saving log file to a custom path.
+base::FilePath::CharType kLogRelativePath[] =
+ FILE_PATH_LITERAL("net-export/chrome-net-export-log.json");
+
+// Old path used by net-export. Used to delete old files.
+// TODO(mmenke): Should remove at some point. Added in M46.
+base::FilePath::CharType kOldLogRelativePath[] =
+ FILE_PATH_LITERAL("chrome-net-export-log.json");
+
+NetLogFileWriter::~NetLogFileWriter() {
+ if (write_to_file_observer_)
+ write_to_file_observer_->StopObserving(nullptr);
+}
+
+void NetLogFileWriter::ProcessCommand(Command command) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!EnsureInit())
+ return;
+
+ switch (command) {
+ case DO_START_LOG_BYTES:
+ StartNetLog(LOG_TYPE_LOG_BYTES);
+ break;
+ case DO_START:
+ StartNetLog(LOG_TYPE_NORMAL);
+ break;
+ case DO_START_STRIP_PRIVATE_DATA:
+ StartNetLog(LOG_TYPE_STRIP_PRIVATE_DATA);
+ break;
+ case DO_STOP:
+ StopNetLog();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+bool NetLogFileWriter::GetFilePath(base::FilePath* path) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (log_type_ == LOG_TYPE_NONE || state_ == STATE_LOGGING)
+ return false;
+
+ if (!NetExportLogExists())
+ return false;
+
+ DCHECK(!log_path_.empty());
+#if defined(OS_POSIX)
+ // Users, group and others can read, write and traverse.
+ int mode = base::FILE_PERMISSION_MASK;
+ base::SetPosixFilePermissions(log_path_, mode);
+#endif // defined(OS_POSIX)
+
+ *path = log_path_;
+ return true;
+}
+
+base::DictionaryValue* NetLogFileWriter::GetState() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ base::DictionaryValue* dict = new base::DictionaryValue;
+
+ EnsureInit();
+
+#ifndef NDEBUG
+ dict->SetString("file", log_path_.LossyDisplayName());
+#endif // NDEBUG
+
+ switch (state_) {
+ case STATE_NOT_LOGGING:
+ dict->SetString("state", "NOT_LOGGING");
+ break;
+ case STATE_LOGGING:
+ dict->SetString("state", "LOGGING");
+ break;
+ case STATE_UNINITIALIZED:
+ dict->SetString("state", "UNINITIALIZED");
+ break;
+ }
+
+ switch (log_type_) {
+ case LOG_TYPE_NONE:
+ dict->SetString("logType", "NONE");
+ break;
+ case LOG_TYPE_UNKNOWN:
+ dict->SetString("logType", "UNKNOWN");
+ break;
+ case LOG_TYPE_LOG_BYTES:
+ dict->SetString("logType", "LOG_BYTES");
+ break;
+ case LOG_TYPE_NORMAL:
+ dict->SetString("logType", "NORMAL");
+ break;
+ case LOG_TYPE_STRIP_PRIVATE_DATA:
+ dict->SetString("logType", "STRIP_PRIVATE_DATA");
+ break;
+ }
+
+ return dict;
+}
+
+NetLogFileWriter::NetLogFileWriter(
+ ChromeNetLog* chrome_net_log,
+ const base::CommandLine::StringType& command_line_string,
+ const std::string& channel_string)
+ : state_(STATE_UNINITIALIZED),
+ log_type_(LOG_TYPE_NONE),
+ chrome_net_log_(chrome_net_log),
+ command_line_string_(command_line_string),
+ channel_string_(channel_string) {
+ // NetLogFileWriter can be created on one thread and used on another.
+ thread_checker_.DetachFromThread();
+}
+
+bool NetLogFileWriter::GetNetExportLogBaseDirectory(
+ base::FilePath* path) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return base::GetTempDir(path);
+}
+
+net::NetLogCaptureMode NetLogFileWriter::GetCaptureModeForLogType(
+ LogType log_type) {
+ switch (log_type) {
+ case LOG_TYPE_LOG_BYTES:
+ return net::NetLogCaptureMode::IncludeSocketBytes();
+ case LOG_TYPE_NORMAL:
+ return net::NetLogCaptureMode::IncludeCookiesAndCredentials();
+ case LOG_TYPE_STRIP_PRIVATE_DATA:
+ return net::NetLogCaptureMode::Default();
+ case LOG_TYPE_NONE:
+ case LOG_TYPE_UNKNOWN:
+ NOTREACHED();
+ }
+ return net::NetLogCaptureMode::Default();
+}
+
+bool NetLogFileWriter::EnsureInit() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (state_ != STATE_UNINITIALIZED)
+ return true;
+
+ if (log_path_.empty() && !SetUpDefaultNetExportLogPath())
+ return false;
+
+ state_ = STATE_NOT_LOGGING;
+ if (NetExportLogExists())
+ log_type_ = LOG_TYPE_UNKNOWN;
+ else
+ log_type_ = LOG_TYPE_NONE;
+
+ return true;
+}
+
+void NetLogFileWriter::StartNetLog(LogType log_type) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (state_ == STATE_LOGGING)
+ return;
+
+ DCHECK_NE(STATE_UNINITIALIZED, state_);
+ DCHECK(!log_path_.empty());
+
+ // Try to make sure we can create the file.
+ // TODO(rtenneti): Find a better for doing the following. Surface some error
+ // to the user if we couldn't create the file.
+ base::ScopedFILE file(base::OpenFile(log_path_, "w"));
+ if (!file)
+ return;
+
+ log_type_ = log_type;
+ state_ = STATE_LOGGING;
+
+ std::unique_ptr<base::Value> constants(
+ ChromeNetLog::GetConstants(command_line_string_, channel_string_));
+ write_to_file_observer_.reset(new net::WriteToFileNetLogObserver());
+ write_to_file_observer_->set_capture_mode(GetCaptureModeForLogType(log_type));
+ write_to_file_observer_->StartObserving(chrome_net_log_, std::move(file),
+ constants.get(), nullptr);
+}
+
+void NetLogFileWriter::StopNetLog() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (state_ != STATE_LOGGING)
+ return;
+
+ write_to_file_observer_->StopObserving(nullptr);
+ write_to_file_observer_.reset();
+ state_ = STATE_NOT_LOGGING;
+}
+
+void NetLogFileWriter::SetUpNetExportLogPath(
+ const base::FilePath& custom_path) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // The directory should always exist because the custom path
+ // is taken from a file selector dialog window.
+ DCHECK(base::PathExists(custom_path.DirName()));
+
+ log_path_ = custom_path;
+}
+
+bool NetLogFileWriter::SetUpDefaultNetExportLogPath() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ base::FilePath temp_dir;
+ if (!GetNetExportLogBaseDirectory(&temp_dir))
+ return false;
+
+ // Delete log file at old location, if present.
+ DeleteFile(temp_dir.Append(kOldLogRelativePath), false);
+
+ base::FilePath log_path = temp_dir.Append(kLogRelativePath);
+
+ if (!base::CreateDirectoryAndGetError(log_path.DirName(), nullptr)) {
+ return false;
+ }
+
+ log_path_ = log_path;
+ return true;
+}
+
+bool NetLogFileWriter::NetExportLogExists() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!log_path_.empty());
+ return base::PathExists(log_path_);
+}
+
+} // namespace net_log
diff --git a/chromium/components/net_log/net_log_file_writer.h b/chromium/components/net_log/net_log_file_writer.h
new file mode 100644
index 00000000000..17033e624b8
--- /dev/null
+++ b/chromium/components/net_log/net_log_file_writer.h
@@ -0,0 +1,177 @@
+// 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 COMPONENTS_NET_LOG_NET_LOG_FILE_WRITER_H_
+#define COMPONENTS_NET_LOG_NET_LOG_FILE_WRITER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace net {
+class NetLogCaptureMode;
+class WriteToFileNetLogObserver;
+}
+
+namespace net_log {
+
+class ChromeNetLog;
+
+// NetLogFileWriter logs all the NetLog entries into a specified file.
+//
+// NetLogFileWriter maintains the current logging state (state_) and log file
+// type (log_type_) of the logging into a chrome-net-export-log.json file.
+//
+// The following are the possible states
+// a) Only Start is allowed (STATE_NOT_LOGGING, LOG_TYPE_NONE).
+// b) Only Stop is allowed (STATE_LOGGING).
+// c) Either Send or Start is allowed (STATE_NOT_LOGGING, anything but
+// LOG_TYPE_NONE).
+//
+// This is created/destroyed on the main thread, but all other function calls
+// occur on a background thread.
+//
+// This relies on the UI thread outlasting all other threads for thread safety.
+class NetLogFileWriter {
+ public:
+ // This enum lists the UI button commands it could receive.
+ enum Command {
+ DO_START_LOG_BYTES, // Call StartNetLog logging all bytes received.
+ DO_START, // Call StartNetLog.
+ DO_START_STRIP_PRIVATE_DATA, // Call StartNetLog stripping private data.
+ DO_STOP, // Call StopNetLog.
+ };
+
+ virtual ~NetLogFileWriter();
+
+ // Accepts the button command and executes it.
+ void ProcessCommand(Command command);
+
+ // Returns true and the path to the file. If there is no file to
+ // send, then it returns false. It also returns false when actively logging to
+ // the file.
+ bool GetFilePath(base::FilePath* path);
+
+ // Creates a Value summary of the state of the NetLogFileWriter. The caller is
+ // responsible for deleting the returned value.
+ base::DictionaryValue* GetState();
+
+ // Updates |log_path_| to the |custom_path|.
+ void SetUpNetExportLogPath(const base::FilePath& custom_path);
+
+ protected:
+ // Constructs a NetLogFileWriter. Only one instance is created in browser
+ // process.
+ NetLogFileWriter(ChromeNetLog* chrome_net_log,
+ const base::CommandLine::StringType& command_line_string,
+ const std::string& channel_string);
+
+ // Returns path name to base::GetTempDir() directory. Returns false if
+ // base::GetTempDir() fails.
+ virtual bool GetNetExportLogBaseDirectory(base::FilePath* path) const;
+
+ private:
+ friend class ChromeNetLog;
+ friend class NetLogFileWriterTest;
+
+ // Allow tests to access our innards for testing purposes.
+ FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, EnsureInitFailure);
+ FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, EnsureInitAllowStart);
+ FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, EnsureInitAllowStartOrSend);
+ FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, ProcessCommandDoStartAndStop);
+ FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, DoStartClearsFile);
+ FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, CheckAddEvent);
+ FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, CheckAddEventWithCustomPath);
+
+ // This enum lists the possible state NetLogFileWriter could be in. It is used
+ // to enable/disable "Start", "Stop" and "Send" (email) UI actions.
+ enum State {
+ STATE_UNINITIALIZED,
+ // Not currently logging to file.
+ STATE_NOT_LOGGING,
+ // Currently logging to file.
+ STATE_LOGGING,
+ };
+
+ // The type of the current log file on disk.
+ enum LogType {
+ // There is no current log file.
+ LOG_TYPE_NONE,
+ // The file predates this session. May or may not have private data.
+ // TODO(davidben): This state is kind of silly.
+ LOG_TYPE_UNKNOWN,
+ // The log includes raw bytes.
+ LOG_TYPE_LOG_BYTES,
+ // The file includes all data.
+ LOG_TYPE_NORMAL,
+ // The file has credentials and cookies stripped.
+ LOG_TYPE_STRIP_PRIVATE_DATA,
+ };
+
+ // Returns the NetLog::CaptureMode corresponding to a LogType.
+ static net::NetLogCaptureMode GetCaptureModeForLogType(LogType log_type);
+
+ // Initializes the |state_| to STATE_NOT_LOGGING and |log_type_| to
+ // LOG_TYPE_NONE (if there is no file from earlier run) or
+ // LOG_TYPE_UNKNOWN (if there is a file from earlier run). Returns
+ // false if initialization of |log_path_| fails.
+ bool EnsureInit();
+
+ // Start collecting NetLog data into chrome-net-export-log.json file in
+ // a directory, using the specified capture mode. It is a no-op if we are
+ // already collecting data into a file, and |capture_mode| is ignored.
+ // ignored.
+ // TODO(mmenke): That's rather weird behavior, think about improving it.
+ void StartNetLog(LogType log_type);
+
+ // Stop collecting NetLog data into the file. It is a no-op if we
+ // are not collecting data into a file.
+ void StopNetLog();
+
+ // Updates |log_path_| to be the base::FilePath to use for log files, which
+ // will be inside the base::GetTempDir() directory. Returns false if
+ // base::GetTempDir() fails, or unable to create a subdirectory for logging
+ // within that directory.
+ bool SetUpDefaultNetExportLogPath();
+
+ // Returns true if a file exists at |log_path_|.
+ bool NetExportLogExists() const;
+
+ base::ThreadChecker thread_checker_;
+
+ // Helper function for unit tests.
+ State state() const { return state_; }
+ LogType log_type() const { return log_type_; }
+
+ State state_; // Current state of NetLogFileWriter.
+ LogType log_type_; // Type of current log file on disk.
+
+ base::FilePath log_path_; // base::FilePath to the NetLog file.
+
+ // |write_to_file_observer_| watches the NetLog event stream, and
+ // sends all entries to the file created in StartNetLog().
+ std::unique_ptr<net::WriteToFileNetLogObserver> write_to_file_observer_;
+
+ // The |chrome_net_log_| is owned by the browser process, cached here to avoid
+ // using global (g_browser_process).
+ ChromeNetLog* chrome_net_log_;
+
+ const base::CommandLine::StringType command_line_string_;
+ const std::string channel_string_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetLogFileWriter);
+};
+
+} // namespace net_log
+
+#endif // COMPONENTS_NET_LOG_NET_LOG_FILE_WRITER_H_
diff --git a/chromium/components/net_log/net_log_file_writer_unittest.cc b/chromium/components/net_log/net_log_file_writer_unittest.cc
new file mode 100644
index 00000000000..47b80833e70
--- /dev/null
+++ b/chromium/components/net_log/net_log_file_writer_unittest.cc
@@ -0,0 +1,446 @@
+// 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 "components/net_log/net_log_file_writer.h"
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/json/json_reader.h"
+#include "base/message_loop/message_loop.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "components/net_log/chrome_net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/write_to_file_net_log_observer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kChannelString[] = "SomeChannel";
+
+} // namespace
+
+namespace net_log {
+
+class TestNetLogFileWriter : public NetLogFileWriter {
+ public:
+ explicit TestNetLogFileWriter(ChromeNetLog* chrome_net_log)
+ : NetLogFileWriter(
+ chrome_net_log,
+ base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
+ kChannelString),
+ lie_about_net_export_log_directory_(false) {
+ EXPECT_TRUE(net_log_temp_dir_.CreateUniqueTempDir());
+ }
+
+ ~TestNetLogFileWriter() override { EXPECT_TRUE(net_log_temp_dir_.Delete()); }
+
+ // NetLogFileWriter implementation:
+ bool GetNetExportLogBaseDirectory(base::FilePath* path) const override {
+ if (lie_about_net_export_log_directory_)
+ return false;
+ *path = net_log_temp_dir_.GetPath();
+ return true;
+ }
+
+ void set_lie_about_net_export_log_directory(
+ bool lie_about_net_export_log_directory) {
+ lie_about_net_export_log_directory_ = lie_about_net_export_log_directory;
+ }
+
+ private:
+ bool lie_about_net_export_log_directory_;
+
+ base::ScopedTempDir net_log_temp_dir_;
+};
+
+class NetLogFileWriterTest : public ::testing::Test {
+ public:
+ NetLogFileWriterTest()
+ : net_log_(new ChromeNetLog(
+ base::FilePath(),
+ net::NetLogCaptureMode::Default(),
+ base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
+ kChannelString)),
+ net_log_file_writer_(new TestNetLogFileWriter(net_log_.get())) {}
+
+ std::string GetStateString() const {
+ std::unique_ptr<base::DictionaryValue> dict(
+ net_log_file_writer_->GetState());
+ std::string state;
+ EXPECT_TRUE(dict->GetString("state", &state));
+ return state;
+ }
+
+ std::string GetLogTypeString() const {
+ std::unique_ptr<base::DictionaryValue> dict(
+ net_log_file_writer_->GetState());
+ std::string log_type;
+ EXPECT_TRUE(dict->GetString("logType", &log_type));
+ return log_type;
+ }
+
+ // Make sure the export file has been created and is non-empty, as net
+ // constants will always be written to it on creation.
+ void VerifyNetExportLogExists() {
+ net_export_log_ = net_log_file_writer_->log_path_;
+ ASSERT_TRUE(base::PathExists(net_export_log_));
+
+ int64_t file_size;
+ // base::GetFileSize returns proper file size on open handles.
+ ASSERT_TRUE(base::GetFileSize(net_export_log_, &file_size));
+ EXPECT_GT(file_size, 0);
+ }
+
+ // Make sure the export file has been created and a valid JSON file. This
+ // should always be the case once logging has been stopped.
+ void VerifyNetExportLogComplete() {
+ VerifyNetExportLogExists();
+
+ std::string log;
+ ASSERT_TRUE(ReadFileToString(net_export_log_, &log));
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> json = base::JSONReader::Read(log);
+ EXPECT_TRUE(json);
+ }
+
+ // Verify state and GetFilePath return correct values if EnsureInit() fails.
+ void VerifyFilePathAndStateAfterEnsureInitFailure() {
+ EXPECT_EQ("UNINITIALIZED", GetStateString());
+ EXPECT_EQ(NetLogFileWriter::STATE_UNINITIALIZED,
+ net_log_file_writer_->state());
+
+ base::FilePath net_export_file_path;
+ EXPECT_FALSE(net_log_file_writer_->GetFilePath(&net_export_file_path));
+ }
+
+ // When we lie in NetExportLogExists, make sure state and GetFilePath return
+ // correct values.
+ void VerifyFilePathAndStateAfterEnsureInit() {
+ EXPECT_EQ("NOT_LOGGING", GetStateString());
+ EXPECT_EQ(NetLogFileWriter::STATE_NOT_LOGGING,
+ net_log_file_writer_->state());
+ EXPECT_EQ("NONE", GetLogTypeString());
+ EXPECT_EQ(NetLogFileWriter::LOG_TYPE_NONE,
+ net_log_file_writer_->log_type());
+
+ base::FilePath net_export_file_path;
+ EXPECT_FALSE(net_log_file_writer_->GetFilePath(&net_export_file_path));
+ EXPECT_FALSE(net_log_file_writer_->NetExportLogExists());
+ }
+
+ // The following methods make sure the export file has been successfully
+ // initialized by a DO_START command of the given type.
+
+ void VerifyFileAndStateAfterDoStart() {
+ VerifyFileAndStateAfterStart(
+ NetLogFileWriter::LOG_TYPE_NORMAL, "NORMAL",
+ net::NetLogCaptureMode::IncludeCookiesAndCredentials());
+ }
+
+ void VerifyFileAndStateAfterDoStartStripPrivateData() {
+ VerifyFileAndStateAfterStart(NetLogFileWriter::LOG_TYPE_STRIP_PRIVATE_DATA,
+ "STRIP_PRIVATE_DATA",
+ net::NetLogCaptureMode::Default());
+ }
+
+ void VerifyFileAndStateAfterDoStartLogBytes() {
+ VerifyFileAndStateAfterStart(NetLogFileWriter::LOG_TYPE_LOG_BYTES,
+ "LOG_BYTES",
+ net::NetLogCaptureMode::IncludeSocketBytes());
+ }
+
+ // Make sure the export file has been successfully initialized after DO_STOP
+ // command following a DO_START command of the given type.
+
+ void VerifyFileAndStateAfterDoStop() {
+ VerifyFileAndStateAfterDoStop(NetLogFileWriter::LOG_TYPE_NORMAL, "NORMAL");
+ }
+
+ void VerifyFileAndStateAfterDoStopWithStripPrivateData() {
+ VerifyFileAndStateAfterDoStop(NetLogFileWriter::LOG_TYPE_STRIP_PRIVATE_DATA,
+ "STRIP_PRIVATE_DATA");
+ }
+
+ void VerifyFileAndStateAfterDoStopWithLogBytes() {
+ VerifyFileAndStateAfterDoStop(NetLogFileWriter::LOG_TYPE_LOG_BYTES,
+ "LOG_BYTES");
+ }
+
+ std::unique_ptr<ChromeNetLog> net_log_;
+ // |net_log_file_writer_| is initialized after |net_log_| so that it can stop
+ // obvserving on destruction.
+ std::unique_ptr<TestNetLogFileWriter> net_log_file_writer_;
+ base::FilePath net_export_log_;
+
+ private:
+ // Checks state after one of the DO_START* commands.
+ void VerifyFileAndStateAfterStart(
+ NetLogFileWriter::LogType expected_log_type,
+ const std::string& expected_log_type_string,
+ net::NetLogCaptureMode expected_capture_mode) {
+ EXPECT_EQ(NetLogFileWriter::STATE_LOGGING, net_log_file_writer_->state());
+ EXPECT_EQ("LOGGING", GetStateString());
+ EXPECT_EQ(expected_log_type, net_log_file_writer_->log_type());
+ EXPECT_EQ(expected_log_type_string, GetLogTypeString());
+ EXPECT_EQ(expected_capture_mode,
+ net_log_file_writer_->write_to_file_observer_->capture_mode());
+
+ // Check GetFilePath returns false when still writing to the file.
+ base::FilePath net_export_file_path;
+ EXPECT_FALSE(net_log_file_writer_->GetFilePath(&net_export_file_path));
+
+ VerifyNetExportLogExists();
+ }
+
+ void VerifyFileAndStateAfterDoStop(
+ NetLogFileWriter::LogType expected_log_type,
+ const std::string& expected_log_type_string) {
+ EXPECT_EQ(NetLogFileWriter::STATE_NOT_LOGGING,
+ net_log_file_writer_->state());
+ EXPECT_EQ("NOT_LOGGING", GetStateString());
+ EXPECT_EQ(expected_log_type, net_log_file_writer_->log_type());
+ EXPECT_EQ(expected_log_type_string, GetLogTypeString());
+
+ base::FilePath net_export_file_path;
+ EXPECT_TRUE(net_log_file_writer_->GetFilePath(&net_export_file_path));
+ EXPECT_EQ(net_export_log_, net_export_file_path);
+
+ VerifyNetExportLogComplete();
+ }
+
+ base::MessageLoop message_loop_;
+};
+
+TEST_F(NetLogFileWriterTest, EnsureInitFailure) {
+ net_log_file_writer_->set_lie_about_net_export_log_directory(true);
+
+ EXPECT_FALSE(net_log_file_writer_->EnsureInit());
+ VerifyFilePathAndStateAfterEnsureInitFailure();
+
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START);
+ VerifyFilePathAndStateAfterEnsureInitFailure();
+}
+
+TEST_F(NetLogFileWriterTest, EnsureInitAllowStart) {
+ EXPECT_TRUE(net_log_file_writer_->EnsureInit());
+ VerifyFilePathAndStateAfterEnsureInit();
+
+ // Calling EnsureInit() second time should be a no-op.
+ EXPECT_TRUE(net_log_file_writer_->EnsureInit());
+ VerifyFilePathAndStateAfterEnsureInit();
+
+ // GetFilePath() should failed when there's no file.
+ base::FilePath net_export_file_path;
+ EXPECT_FALSE(net_log_file_writer_->GetFilePath(&net_export_file_path));
+}
+
+TEST_F(NetLogFileWriterTest, EnsureInitAllowStartOrSend) {
+ net_log_file_writer_->SetUpDefaultNetExportLogPath();
+ net_export_log_ = net_log_file_writer_->log_path_;
+
+ // Create and close an empty log file, to simulate an old log file already
+ // existing.
+ base::ScopedFILE created_file(base::OpenFile(net_export_log_, "w"));
+ ASSERT_TRUE(created_file.get());
+ created_file.reset();
+
+ EXPECT_TRUE(net_log_file_writer_->EnsureInit());
+
+ EXPECT_EQ("NOT_LOGGING", GetStateString());
+ EXPECT_EQ(NetLogFileWriter::STATE_NOT_LOGGING, net_log_file_writer_->state());
+ EXPECT_EQ("UNKNOWN", GetLogTypeString());
+ EXPECT_EQ(NetLogFileWriter::LOG_TYPE_UNKNOWN,
+ net_log_file_writer_->log_type());
+ EXPECT_EQ(net_export_log_, net_log_file_writer_->log_path_);
+ EXPECT_TRUE(base::PathExists(net_export_log_));
+
+ base::FilePath net_export_file_path;
+ EXPECT_TRUE(net_log_file_writer_->GetFilePath(&net_export_file_path));
+ EXPECT_TRUE(base::PathExists(net_export_file_path));
+ EXPECT_EQ(net_export_log_, net_export_file_path);
+}
+
+TEST_F(NetLogFileWriterTest, ProcessCommandDoStartAndStop) {
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START);
+ VerifyFileAndStateAfterDoStart();
+
+ // Calling a second time should be a no-op.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START);
+ VerifyFileAndStateAfterDoStart();
+
+ // starting with other log levels should also be no-ops.
+ net_log_file_writer_->ProcessCommand(
+ NetLogFileWriter::DO_START_STRIP_PRIVATE_DATA);
+ VerifyFileAndStateAfterDoStart();
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START_LOG_BYTES);
+ VerifyFileAndStateAfterDoStart();
+
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStop();
+
+ // Calling DO_STOP second time should be a no-op.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStop();
+}
+
+TEST_F(NetLogFileWriterTest,
+ ProcessCommandDoStartAndStopWithPrivateDataStripping) {
+ net_log_file_writer_->ProcessCommand(
+ NetLogFileWriter::DO_START_STRIP_PRIVATE_DATA);
+ VerifyFileAndStateAfterDoStartStripPrivateData();
+
+ // Calling a second time should be a no-op.
+ net_log_file_writer_->ProcessCommand(
+ NetLogFileWriter::DO_START_STRIP_PRIVATE_DATA);
+ VerifyFileAndStateAfterDoStartStripPrivateData();
+
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStopWithStripPrivateData();
+
+ // Calling DO_STOP second time should be a no-op.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStopWithStripPrivateData();
+}
+
+TEST_F(NetLogFileWriterTest, ProcessCommandDoStartAndStopWithByteLogging) {
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START_LOG_BYTES);
+ VerifyFileAndStateAfterDoStartLogBytes();
+
+ // Calling a second time should be a no-op.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START_LOG_BYTES);
+ VerifyFileAndStateAfterDoStartLogBytes();
+
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStopWithLogBytes();
+
+ // Calling DO_STOP second time should be a no-op.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStopWithLogBytes();
+}
+
+TEST_F(NetLogFileWriterTest, DoStartClearsFile) {
+ // Verify file sizes after two consecutive starts/stops are the same (even if
+ // we add some junk data in between).
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START);
+ VerifyFileAndStateAfterDoStart();
+
+ int64_t start_file_size;
+ EXPECT_TRUE(base::GetFileSize(net_export_log_, &start_file_size));
+
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStop();
+
+ int64_t stop_file_size;
+ EXPECT_TRUE(base::GetFileSize(net_export_log_, &stop_file_size));
+ EXPECT_GE(stop_file_size, start_file_size);
+
+ // Add some junk at the end of the file.
+ std::string junk_data("Hello");
+ EXPECT_TRUE(
+ base::AppendToFile(net_export_log_, junk_data.c_str(), junk_data.size()));
+
+ int64_t junk_file_size;
+ EXPECT_TRUE(base::GetFileSize(net_export_log_, &junk_file_size));
+ EXPECT_GT(junk_file_size, stop_file_size);
+
+ // Execute DO_START/DO_STOP commands and make sure the file is back to the
+ // size before addition of junk data.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START);
+ VerifyFileAndStateAfterDoStart();
+
+ int64_t new_start_file_size;
+ EXPECT_TRUE(base::GetFileSize(net_export_log_, &new_start_file_size));
+ EXPECT_EQ(new_start_file_size, start_file_size);
+
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStop();
+
+ int64_t new_stop_file_size;
+ EXPECT_TRUE(base::GetFileSize(net_export_log_, &new_stop_file_size));
+ EXPECT_EQ(new_stop_file_size, stop_file_size);
+}
+
+TEST_F(NetLogFileWriterTest, CheckAddEvent) {
+ // Add an event to |net_log_| and then test to make sure that, after we stop
+ // logging, the file is larger than the file created without that event.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START);
+ VerifyFileAndStateAfterDoStart();
+
+ // Get file size without the event.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStop();
+
+ int64_t stop_file_size;
+ EXPECT_TRUE(base::GetFileSize(net_export_log_, &stop_file_size));
+
+ // Perform DO_START and add an Event and then DO_STOP and then compare
+ // file sizes.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START);
+ VerifyFileAndStateAfterDoStart();
+
+ // Log an event.
+ net_log_->AddGlobalEntry(net::NetLogEventType::CANCELLED);
+
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStop();
+
+ int64_t new_stop_file_size;
+ EXPECT_TRUE(base::GetFileSize(net_export_log_, &new_stop_file_size));
+ EXPECT_GE(new_stop_file_size, stop_file_size);
+}
+
+TEST_F(NetLogFileWriterTest, CheckAddEventWithCustomPath) {
+ // Using a custom path to make sure logging can still occur when
+ // the path has changed.
+ base::FilePath path;
+ net_log_file_writer_->GetNetExportLogBaseDirectory(&path);
+
+ base::FilePath::CharType kCustomPath[] =
+ FILE_PATH_LITERAL("custom/custom/chrome-net-export-log.json");
+ base::FilePath custom_path = path.Append(kCustomPath);
+
+ EXPECT_TRUE(base::CreateDirectoryAndGetError(custom_path.DirName(), nullptr));
+
+ net_log_file_writer_->SetUpNetExportLogPath(custom_path);
+ net_export_log_ = net_log_file_writer_->log_path_;
+ EXPECT_EQ(custom_path, net_export_log_);
+
+ // Add an event to |net_log_| and then test to make sure that, after we stop
+ // logging, the file is larger than the file created without that event.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START);
+ VerifyFileAndStateAfterDoStart();
+
+ // Get file size without the event.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStop();
+
+ int64_t stop_file_size;
+ EXPECT_TRUE(base::GetFileSize(net_export_log_, &stop_file_size));
+
+ // Perform DO_START and add an Event and then DO_STOP and then compare
+ // file sizes.
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_START);
+ VerifyFileAndStateAfterDoStart();
+
+ // Log an event.
+ net_log_->AddGlobalEntry(net::NetLogEventType::CANCELLED);
+
+ net_log_file_writer_->ProcessCommand(NetLogFileWriter::DO_STOP);
+ VerifyFileAndStateAfterDoStop();
+
+ int64_t new_stop_file_size;
+ EXPECT_TRUE(base::GetFileSize(net_export_log_, &new_stop_file_size));
+ EXPECT_GE(new_stop_file_size, stop_file_size);
+}
+
+} // namespace net_log
diff --git a/chromium/components/net_log/net_log_temp_file.cc b/chromium/components/net_log/net_log_temp_file.cc
deleted file mode 100644
index 58b5bd5903f..00000000000
--- a/chromium/components/net_log/net_log_temp_file.cc
+++ /dev/null
@@ -1,232 +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 "components/net_log/net_log_temp_file.h"
-
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "components/net_log/chrome_net_log.h"
-#include "net/log/write_to_file_net_log_observer.h"
-
-namespace net_log {
-
-// Path of logs relative to base::GetTempDir(). Must be kept in sync
-// with chrome/android/java/res/xml/file_paths.xml
-base::FilePath::CharType kLogRelativePath[] =
- FILE_PATH_LITERAL("net-export/chrome-net-export-log.json");
-
-// Old path used by net-export. Used to delete old files.
-// TODO(mmenke): Should remove at some point. Added in M46.
-base::FilePath::CharType kOldLogRelativePath[] =
- FILE_PATH_LITERAL("chrome-net-export-log.json");
-
-NetLogTempFile::~NetLogTempFile() {
- if (write_to_file_observer_)
- write_to_file_observer_->StopObserving(nullptr);
-}
-
-void NetLogTempFile::ProcessCommand(Command command) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!EnsureInit())
- return;
-
- switch (command) {
- case DO_START_LOG_BYTES:
- StartNetLog(LOG_TYPE_LOG_BYTES);
- break;
- case DO_START:
- StartNetLog(LOG_TYPE_NORMAL);
- break;
- case DO_START_STRIP_PRIVATE_DATA:
- StartNetLog(LOG_TYPE_STRIP_PRIVATE_DATA);
- break;
- case DO_STOP:
- StopNetLog();
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
-bool NetLogTempFile::GetFilePath(base::FilePath* path) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (log_type_ == LOG_TYPE_NONE || state_ == STATE_LOGGING)
- return false;
-
- if (!NetExportLogExists())
- return false;
-
- DCHECK(!log_path_.empty());
-#if defined(OS_POSIX)
- // Users, group and others can read, write and traverse.
- int mode = base::FILE_PERMISSION_MASK;
- base::SetPosixFilePermissions(log_path_, mode);
-#endif // defined(OS_POSIX)
-
- *path = log_path_;
- return true;
-}
-
-base::DictionaryValue* NetLogTempFile::GetState() {
- DCHECK(thread_checker_.CalledOnValidThread());
- base::DictionaryValue* dict = new base::DictionaryValue;
-
- EnsureInit();
-
-#ifndef NDEBUG
- dict->SetString("file", log_path_.LossyDisplayName());
-#endif // NDEBUG
-
- switch (state_) {
- case STATE_NOT_LOGGING:
- dict->SetString("state", "NOT_LOGGING");
- break;
- case STATE_LOGGING:
- dict->SetString("state", "LOGGING");
- break;
- case STATE_UNINITIALIZED:
- dict->SetString("state", "UNINITIALIZED");
- break;
- }
-
- switch (log_type_) {
- case LOG_TYPE_NONE:
- dict->SetString("logType", "NONE");
- break;
- case LOG_TYPE_UNKNOWN:
- dict->SetString("logType", "UNKNOWN");
- break;
- case LOG_TYPE_LOG_BYTES:
- dict->SetString("logType", "LOG_BYTES");
- break;
- case LOG_TYPE_NORMAL:
- dict->SetString("logType", "NORMAL");
- break;
- case LOG_TYPE_STRIP_PRIVATE_DATA:
- dict->SetString("logType", "STRIP_PRIVATE_DATA");
- break;
- }
-
- return dict;
-}
-
-NetLogTempFile::NetLogTempFile(
- ChromeNetLog* chrome_net_log,
- const base::CommandLine::StringType& command_line_string,
- const std::string& channel_string)
- : state_(STATE_UNINITIALIZED),
- log_type_(LOG_TYPE_NONE),
- chrome_net_log_(chrome_net_log),
- command_line_string_(command_line_string),
- channel_string_(channel_string) {
- // NetLogTempFile can be created on one thread and used on another.
- thread_checker_.DetachFromThread();
-}
-
-bool NetLogTempFile::GetNetExportLogBaseDirectory(base::FilePath* path) const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return base::GetTempDir(path);
-}
-
-net::NetLogCaptureMode NetLogTempFile::GetCaptureModeForLogType(
- LogType log_type) {
- switch (log_type) {
- case LOG_TYPE_LOG_BYTES:
- return net::NetLogCaptureMode::IncludeSocketBytes();
- case LOG_TYPE_NORMAL:
- return net::NetLogCaptureMode::IncludeCookiesAndCredentials();
- case LOG_TYPE_STRIP_PRIVATE_DATA:
- return net::NetLogCaptureMode::Default();
- case LOG_TYPE_NONE:
- case LOG_TYPE_UNKNOWN:
- NOTREACHED();
- }
- return net::NetLogCaptureMode::Default();
-}
-
-bool NetLogTempFile::EnsureInit() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (state_ != STATE_UNINITIALIZED)
- return true;
-
- if (!SetUpNetExportLogPath())
- return false;
-
- state_ = STATE_NOT_LOGGING;
- if (NetExportLogExists())
- log_type_ = LOG_TYPE_UNKNOWN;
- else
- log_type_ = LOG_TYPE_NONE;
-
- return true;
-}
-
-void NetLogTempFile::StartNetLog(LogType log_type) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (state_ == STATE_LOGGING)
- return;
-
- DCHECK_NE(STATE_UNINITIALIZED, state_);
- DCHECK(!log_path_.empty());
-
- // Try to make sure we can create the file.
- // TODO(rtenneti): Find a better for doing the following. Surface some error
- // to the user if we couldn't create the file.
- base::ScopedFILE file(base::OpenFile(log_path_, "w"));
- if (!file)
- return;
-
- log_type_ = log_type;
- state_ = STATE_LOGGING;
-
- std::unique_ptr<base::Value> constants(
- ChromeNetLog::GetConstants(command_line_string_, channel_string_));
- write_to_file_observer_.reset(new net::WriteToFileNetLogObserver());
- write_to_file_observer_->set_capture_mode(GetCaptureModeForLogType(log_type));
- write_to_file_observer_->StartObserving(chrome_net_log_, std::move(file),
- constants.get(), nullptr);
-}
-
-void NetLogTempFile::StopNetLog() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (state_ != STATE_LOGGING)
- return;
-
- write_to_file_observer_->StopObserving(nullptr);
- write_to_file_observer_.reset();
- state_ = STATE_NOT_LOGGING;
-}
-
-bool NetLogTempFile::SetUpNetExportLogPath() {
- DCHECK(thread_checker_.CalledOnValidThread());
- base::FilePath temp_dir;
- if (!GetNetExportLogBaseDirectory(&temp_dir))
- return false;
-
- // Delete log file at old location, if present.
- DeleteFile(temp_dir.Append(kOldLogRelativePath), false);
-
- base::FilePath log_path = temp_dir.Append(kLogRelativePath);
-
- if (!base::CreateDirectoryAndGetError(log_path.DirName(), nullptr)) {
- return false;
- }
-
- log_path_ = log_path;
- return true;
-}
-
-bool NetLogTempFile::NetExportLogExists() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!log_path_.empty());
- return base::PathExists(log_path_);
-}
-
-} // namespace net_log
diff --git a/chromium/components/net_log/net_log_temp_file.h b/chromium/components/net_log/net_log_temp_file.h
deleted file mode 100644
index 486f9354247..00000000000
--- a/chromium/components/net_log/net_log_temp_file.h
+++ /dev/null
@@ -1,174 +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 COMPONENTS_NET_LOG_NET_LOG_TEMP_FILE_H_
-#define COMPONENTS_NET_LOG_NET_LOG_TEMP_FILE_H_
-
-#include <memory>
-#include <string>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "net/log/net_log.h"
-
-namespace base {
-class DictionaryValue;
-}
-
-namespace net {
-class WriteToFileNetLogObserver;
-}
-
-namespace net_log {
-
-class ChromeNetLog;
-
-// NetLogTempFile logs all the NetLog entries into a temporary file
-// "chrome-net-export-log.json" created in base::GetTempDir() directory.
-//
-// NetLogTempFile maintains the current logging state (state_) and log file type
-// (log_type_) of the logging into a chrome-net-export-log.json file.
-//
-// The following are the possible states
-// a) Only Start is allowed (STATE_NOT_LOGGING, LOG_TYPE_NONE).
-// b) Only Stop is allowed (STATE_LOGGING).
-// c) Either Send or Start is allowed (STATE_NOT_LOGGING, anything but
-// LOG_TYPE_NONE).
-//
-// This is created/destroyed on the main thread, but all other function calls
-// occur on a background thread.
-//
-// This relies on the UI thread outlasting all other threads for thread safety.
-class NetLogTempFile {
- public:
- // This enum lists the UI button commands it could receive.
- enum Command {
- DO_START_LOG_BYTES, // Call StartNetLog logging all bytes received.
- DO_START, // Call StartNetLog.
- DO_START_STRIP_PRIVATE_DATA, // Call StartNetLog stripping private data.
- DO_STOP, // Call StopNetLog.
- };
-
- virtual ~NetLogTempFile();
-
- // Accepts the button command and executes it.
- void ProcessCommand(Command command);
-
- // Returns true and the path to the temporary file. If there is no file to
- // send, then it returns false. It also returns false when actively logging to
- // the file.
- bool GetFilePath(base::FilePath* path);
-
- // Creates a Value summary of the state of the NetLogTempFile. The caller is
- // responsible for deleting the returned value.
- base::DictionaryValue* GetState();
-
- protected:
- // Constructs a NetLogTempFile. Only one instance is created in browser
- // process.
- NetLogTempFile(ChromeNetLog* chrome_net_log,
- const base::CommandLine::StringType& command_line_string,
- const std::string& channel_string);
-
- // Returns path name to base::GetTempDir() directory. Returns false if
- // base::GetTempDir() fails.
- virtual bool GetNetExportLogBaseDirectory(base::FilePath* path) const;
-
- private:
- friend class ChromeNetLog;
- friend class NetLogTempFileTest;
-
- // Allow tests to access our innards for testing purposes.
- FRIEND_TEST_ALL_PREFIXES(NetLogTempFileTest, EnsureInitFailure);
- FRIEND_TEST_ALL_PREFIXES(NetLogTempFileTest, EnsureInitAllowStart);
- FRIEND_TEST_ALL_PREFIXES(NetLogTempFileTest, EnsureInitAllowStartOrSend);
- FRIEND_TEST_ALL_PREFIXES(NetLogTempFileTest, ProcessCommandDoStartAndStop);
- FRIEND_TEST_ALL_PREFIXES(NetLogTempFileTest, DoStartClearsFile);
- FRIEND_TEST_ALL_PREFIXES(NetLogTempFileTest, CheckAddEvent);
-
- // This enum lists the possible state NetLogTempFile could be in. It is used
- // to enable/disable "Start", "Stop" and "Send" (email) UI actions.
- enum State {
- STATE_UNINITIALIZED,
- // Not currently logging to file.
- STATE_NOT_LOGGING,
- // Currently logging to file.
- STATE_LOGGING,
- };
-
- // The type of the current log file on disk.
- enum LogType {
- // There is no current log file.
- LOG_TYPE_NONE,
- // The file predates this session. May or may not have private data.
- // TODO(davidben): This state is kind of silly.
- LOG_TYPE_UNKNOWN,
- // The log includes raw bytes.
- LOG_TYPE_LOG_BYTES,
- // The file includes all data.
- LOG_TYPE_NORMAL,
- // The file has credentials and cookies stripped.
- LOG_TYPE_STRIP_PRIVATE_DATA,
- };
-
- // Returns the NetLog::CaptureMode corresponding to a LogType.
- static net::NetLogCaptureMode GetCaptureModeForLogType(LogType log_type);
-
- // Initializes the |state_| to STATE_NOT_LOGGING and |log_type_| to
- // LOG_TYPE_NONE (if there is no temporary file from earlier run) or
- // LOG_TYPE_UNKNOWN (if there is a temporary file from earlier run). Returns
- // false if initialization of |log_path_| fails.
- bool EnsureInit();
-
- // Start collecting NetLog data into chrome-net-export-log.json file in
- // base::GetTempDir() directory, using the specified capture mode. It is a
- // no-op if we are already collecting data into a file, and |capture_mode| is
- // ignored.
- // TODO(mmenke): That's rather weird behavior, think about improving it.
- void StartNetLog(LogType log_type);
-
- // Stop collecting NetLog data into the temporary file. It is a no-op if we
- // are not collecting data into a file.
- void StopNetLog();
-
- // Updates |log_path_| to be the base::FilePath to use for log files, which
- // will be inside the base::GetTempDir() directory. Returns false if
- // base::GetTempDir() fails, or unable to create a subdirectory for logging
- // withinh that directory.
- bool SetUpNetExportLogPath();
-
- // Returns true if a file exists at |log_path_|.
- bool NetExportLogExists() const;
-
- base::ThreadChecker thread_checker_;
-
- // Helper function for unit tests.
- State state() const { return state_; }
- LogType log_type() const { return log_type_; }
-
- State state_; // Current state of NetLogTempFile.
- LogType log_type_; // Type of current log file on disk.
-
- base::FilePath log_path_; // base::FilePath to the temporary file.
-
- // |write_to_file_observer_| watches the NetLog event stream, and
- // sends all entries to the file created in StartNetLog().
- std::unique_ptr<net::WriteToFileNetLogObserver> write_to_file_observer_;
-
- // The |chrome_net_log_| is owned by the browser process, cached here to avoid
- // using global (g_browser_process).
- ChromeNetLog* chrome_net_log_;
-
- const base::CommandLine::StringType command_line_string_;
- const std::string channel_string_;
-
- DISALLOW_COPY_AND_ASSIGN(NetLogTempFile);
-};
-
-} // namespace net_log
-
-#endif // COMPONENTS_NET_LOG_NET_LOG_TEMP_FILE_H_
diff --git a/chromium/components/net_log/net_log_temp_file_unittest.cc b/chromium/components/net_log/net_log_temp_file_unittest.cc
deleted file mode 100644
index 63f39aee1f4..00000000000
--- a/chromium/components/net_log/net_log_temp_file_unittest.cc
+++ /dev/null
@@ -1,394 +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 "components/net_log/net_log_temp_file.h"
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/json/json_reader.h"
-#include "base/message_loop/message_loop.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "components/net_log/chrome_net_log.h"
-#include "net/log/net_log_capture_mode.h"
-#include "net/log/write_to_file_net_log_observer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const char kChannelString[] = "SomeChannel";
-
-} // namespace
-
-namespace net_log {
-
-class TestNetLogTempFile : public NetLogTempFile {
- public:
- explicit TestNetLogTempFile(ChromeNetLog* chrome_net_log)
- : NetLogTempFile(
- chrome_net_log,
- base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
- kChannelString),
- lie_about_net_export_log_directory_(false) {
- EXPECT_TRUE(net_log_temp_dir_.CreateUniqueTempDir());
- }
-
- ~TestNetLogTempFile() override { EXPECT_TRUE(net_log_temp_dir_.Delete()); }
-
- // NetLogTempFile implementation:
- bool GetNetExportLogBaseDirectory(base::FilePath* path) const override {
- if (lie_about_net_export_log_directory_)
- return false;
- *path = net_log_temp_dir_.path();
- return true;
- }
-
- void set_lie_about_net_export_log_directory(
- bool lie_about_net_export_log_directory) {
- lie_about_net_export_log_directory_ = lie_about_net_export_log_directory;
- }
-
- private:
- bool lie_about_net_export_log_directory_;
-
- base::ScopedTempDir net_log_temp_dir_;
-};
-
-class NetLogTempFileTest : public ::testing::Test {
- public:
- NetLogTempFileTest()
- : net_log_(new ChromeNetLog(
- base::FilePath(),
- net::NetLogCaptureMode::Default(),
- base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
- kChannelString)),
- net_log_temp_file_(new TestNetLogTempFile(net_log_.get())) {
- EXPECT_TRUE(net_log_temp_file_->SetUpNetExportLogPath());
- net_export_log_ = net_log_temp_file_->log_path_;
- }
-
- std::string GetStateString() const {
- std::unique_ptr<base::DictionaryValue> dict(net_log_temp_file_->GetState());
- std::string state;
- EXPECT_TRUE(dict->GetString("state", &state));
- return state;
- }
-
- std::string GetLogTypeString() const {
- std::unique_ptr<base::DictionaryValue> dict(net_log_temp_file_->GetState());
- std::string log_type;
- EXPECT_TRUE(dict->GetString("logType", &log_type));
- return log_type;
- }
-
- // Make sure the export file has been created and is non-empty, as net
- // constants will always be written to it on creation.
- void VerifyNetExportLogExists() const {
- EXPECT_EQ(net_export_log_, net_log_temp_file_->log_path_);
- ASSERT_TRUE(base::PathExists(net_export_log_));
-
- int64_t file_size;
- // base::GetFileSize returns proper file size on open handles.
- ASSERT_TRUE(base::GetFileSize(net_export_log_, &file_size));
- EXPECT_GT(file_size, 0);
- }
-
- // Make sure the export file has been created and a valid JSON file. This
- // should always be the case once logging has been stopped.
- void VerifyNetExportLogComplete() const {
- VerifyNetExportLogExists();
-
- std::string log;
- ASSERT_TRUE(ReadFileToString(net_export_log_, &log));
- base::JSONReader reader;
- std::unique_ptr<base::Value> json = base::JSONReader::Read(log);
- EXPECT_TRUE(json);
- }
-
- // Verify state and GetFilePath return correct values if EnsureInit() fails.
- void VerifyFilePathAndStateAfterEnsureInitFailure() {
- EXPECT_EQ("UNINITIALIZED", GetStateString());
- EXPECT_EQ(NetLogTempFile::STATE_UNINITIALIZED, net_log_temp_file_->state());
-
- base::FilePath net_export_file_path;
- EXPECT_FALSE(net_log_temp_file_->GetFilePath(&net_export_file_path));
- }
-
- // When we lie in NetExportLogExists, make sure state and GetFilePath return
- // correct values.
- void VerifyFilePathAndStateAfterEnsureInit() {
- EXPECT_EQ("NOT_LOGGING", GetStateString());
- EXPECT_EQ(NetLogTempFile::STATE_NOT_LOGGING, net_log_temp_file_->state());
- EXPECT_EQ("NONE", GetLogTypeString());
- EXPECT_EQ(NetLogTempFile::LOG_TYPE_NONE, net_log_temp_file_->log_type());
-
- base::FilePath net_export_file_path;
- EXPECT_FALSE(net_log_temp_file_->GetFilePath(&net_export_file_path));
- EXPECT_FALSE(net_log_temp_file_->NetExportLogExists());
- }
-
- // The following methods make sure the export file has been successfully
- // initialized by a DO_START command of the given type.
-
- void VerifyFileAndStateAfterDoStart() {
- VerifyFileAndStateAfterStart(
- NetLogTempFile::LOG_TYPE_NORMAL, "NORMAL",
- net::NetLogCaptureMode::IncludeCookiesAndCredentials());
- }
-
- void VerifyFileAndStateAfterDoStartStripPrivateData() const {
- VerifyFileAndStateAfterStart(NetLogTempFile::LOG_TYPE_STRIP_PRIVATE_DATA,
- "STRIP_PRIVATE_DATA",
- net::NetLogCaptureMode::Default());
- }
-
- void VerifyFileAndStateAfterDoStartLogBytes() const {
- VerifyFileAndStateAfterStart(NetLogTempFile::LOG_TYPE_LOG_BYTES,
- "LOG_BYTES",
- net::NetLogCaptureMode::IncludeSocketBytes());
- }
-
- // Make sure the export file has been successfully initialized after DO_STOP
- // command following a DO_START command of the given type.
-
- void VerifyFileAndStateAfterDoStop() const {
- VerifyFileAndStateAfterDoStop(NetLogTempFile::LOG_TYPE_NORMAL, "NORMAL");
- }
-
- void VerifyFileAndStateAfterDoStopWithStripPrivateData() const {
- VerifyFileAndStateAfterDoStop(NetLogTempFile::LOG_TYPE_STRIP_PRIVATE_DATA,
- "STRIP_PRIVATE_DATA");
- }
-
- void VerifyFileAndStateAfterDoStopWithLogBytes() const {
- VerifyFileAndStateAfterDoStop(NetLogTempFile::LOG_TYPE_LOG_BYTES,
- "LOG_BYTES");
- }
-
- std::unique_ptr<ChromeNetLog> net_log_;
- // |net_log_temp_file_| is initialized after |net_log_| so that it can stop
- // obvserving on destruction.
- std::unique_ptr<TestNetLogTempFile> net_log_temp_file_;
- base::FilePath net_export_log_;
-
- private:
- // Checks state after one of the DO_START* commands.
- void VerifyFileAndStateAfterStart(
- NetLogTempFile::LogType expected_log_type,
- const std::string& expected_log_type_string,
- net::NetLogCaptureMode expected_capture_mode) const {
- EXPECT_EQ(NetLogTempFile::STATE_LOGGING, net_log_temp_file_->state());
- EXPECT_EQ("LOGGING", GetStateString());
- EXPECT_EQ(expected_log_type, net_log_temp_file_->log_type());
- EXPECT_EQ(expected_log_type_string, GetLogTypeString());
- EXPECT_EQ(expected_capture_mode,
- net_log_temp_file_->write_to_file_observer_->capture_mode());
-
- // Check GetFilePath returns false when still writing to the file.
- base::FilePath net_export_file_path;
- EXPECT_FALSE(net_log_temp_file_->GetFilePath(&net_export_file_path));
-
- VerifyNetExportLogExists();
- }
-
- void VerifyFileAndStateAfterDoStop(
- NetLogTempFile::LogType expected_log_type,
- const std::string& expected_log_type_string) const {
- EXPECT_EQ(NetLogTempFile::STATE_NOT_LOGGING, net_log_temp_file_->state());
- EXPECT_EQ("NOT_LOGGING", GetStateString());
- EXPECT_EQ(expected_log_type, net_log_temp_file_->log_type());
- EXPECT_EQ(expected_log_type_string, GetLogTypeString());
-
- base::FilePath net_export_file_path;
- EXPECT_TRUE(net_log_temp_file_->GetFilePath(&net_export_file_path));
- EXPECT_EQ(net_export_log_, net_export_file_path);
-
- VerifyNetExportLogComplete();
- }
-
- base::MessageLoop message_loop_;
-};
-
-TEST_F(NetLogTempFileTest, EnsureInitFailure) {
- net_log_temp_file_->set_lie_about_net_export_log_directory(true);
-
- EXPECT_FALSE(net_log_temp_file_->EnsureInit());
- VerifyFilePathAndStateAfterEnsureInitFailure();
-
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_START);
- VerifyFilePathAndStateAfterEnsureInitFailure();
-}
-
-TEST_F(NetLogTempFileTest, EnsureInitAllowStart) {
- EXPECT_TRUE(net_log_temp_file_->EnsureInit());
- VerifyFilePathAndStateAfterEnsureInit();
-
- // Calling EnsureInit() second time should be a no-op.
- EXPECT_TRUE(net_log_temp_file_->EnsureInit());
- VerifyFilePathAndStateAfterEnsureInit();
-
- // GetFilePath() should failed when there's no temp file.
- base::FilePath net_export_file_path;
- EXPECT_FALSE(net_log_temp_file_->GetFilePath(&net_export_file_path));
-}
-
-TEST_F(NetLogTempFileTest, EnsureInitAllowStartOrSend) {
- // Create and close an empty log file, to simulate an old log file already
- // existing.
- base::ScopedFILE created_file(base::OpenFile(net_export_log_, "w"));
- ASSERT_TRUE(created_file.get());
- created_file.reset();
-
- EXPECT_TRUE(net_log_temp_file_->EnsureInit());
-
- EXPECT_EQ("NOT_LOGGING", GetStateString());
- EXPECT_EQ(NetLogTempFile::STATE_NOT_LOGGING, net_log_temp_file_->state());
- EXPECT_EQ("UNKNOWN", GetLogTypeString());
- EXPECT_EQ(NetLogTempFile::LOG_TYPE_UNKNOWN, net_log_temp_file_->log_type());
- EXPECT_EQ(net_export_log_, net_log_temp_file_->log_path_);
- EXPECT_TRUE(base::PathExists(net_export_log_));
-
- base::FilePath net_export_file_path;
- EXPECT_TRUE(net_log_temp_file_->GetFilePath(&net_export_file_path));
- EXPECT_TRUE(base::PathExists(net_export_file_path));
- EXPECT_EQ(net_export_log_, net_export_file_path);
-}
-
-TEST_F(NetLogTempFileTest, ProcessCommandDoStartAndStop) {
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_START);
- VerifyFileAndStateAfterDoStart();
-
- // Calling a second time should be a no-op.
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_START);
- VerifyFileAndStateAfterDoStart();
-
- // starting with other log levels should also be no-ops.
- net_log_temp_file_->ProcessCommand(
- NetLogTempFile::DO_START_STRIP_PRIVATE_DATA);
- VerifyFileAndStateAfterDoStart();
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_START_LOG_BYTES);
- VerifyFileAndStateAfterDoStart();
-
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_STOP);
- VerifyFileAndStateAfterDoStop();
-
- // Calling DO_STOP second time should be a no-op.
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_STOP);
- VerifyFileAndStateAfterDoStop();
-}
-
-TEST_F(NetLogTempFileTest,
- ProcessCommandDoStartAndStopWithPrivateDataStripping) {
- net_log_temp_file_->ProcessCommand(
- NetLogTempFile::DO_START_STRIP_PRIVATE_DATA);
- VerifyFileAndStateAfterDoStartStripPrivateData();
-
- // Calling a second time should be a no-op.
- net_log_temp_file_->ProcessCommand(
- NetLogTempFile::DO_START_STRIP_PRIVATE_DATA);
- VerifyFileAndStateAfterDoStartStripPrivateData();
-
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_STOP);
- VerifyFileAndStateAfterDoStopWithStripPrivateData();
-
- // Calling DO_STOP second time should be a no-op.
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_STOP);
- VerifyFileAndStateAfterDoStopWithStripPrivateData();
-}
-
-TEST_F(NetLogTempFileTest, ProcessCommandDoStartAndStopWithByteLogging) {
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_START_LOG_BYTES);
- VerifyFileAndStateAfterDoStartLogBytes();
-
- // Calling a second time should be a no-op.
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_START_LOG_BYTES);
- VerifyFileAndStateAfterDoStartLogBytes();
-
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_STOP);
- VerifyFileAndStateAfterDoStopWithLogBytes();
-
- // Calling DO_STOP second time should be a no-op.
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_STOP);
- VerifyFileAndStateAfterDoStopWithLogBytes();
-}
-
-TEST_F(NetLogTempFileTest, DoStartClearsFile) {
- // Verify file sizes after two consecutive starts/stops are the same (even if
- // we add some junk data in between).
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_START);
- VerifyFileAndStateAfterDoStart();
-
- int64_t start_file_size;
- EXPECT_TRUE(base::GetFileSize(net_export_log_, &start_file_size));
-
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_STOP);
- VerifyFileAndStateAfterDoStop();
-
- int64_t stop_file_size;
- EXPECT_TRUE(base::GetFileSize(net_export_log_, &stop_file_size));
- EXPECT_GE(stop_file_size, start_file_size);
-
- // Add some junk at the end of the file.
- std::string junk_data("Hello");
- EXPECT_TRUE(
- base::AppendToFile(net_export_log_, junk_data.c_str(), junk_data.size()));
-
- int64_t junk_file_size;
- EXPECT_TRUE(base::GetFileSize(net_export_log_, &junk_file_size));
- EXPECT_GT(junk_file_size, stop_file_size);
-
- // Execute DO_START/DO_STOP commands and make sure the file is back to the
- // size before addition of junk data.
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_START);
- VerifyFileAndStateAfterDoStart();
-
- int64_t new_start_file_size;
- EXPECT_TRUE(base::GetFileSize(net_export_log_, &new_start_file_size));
- EXPECT_EQ(new_start_file_size, start_file_size);
-
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_STOP);
- VerifyFileAndStateAfterDoStop();
-
- int64_t new_stop_file_size;
- EXPECT_TRUE(base::GetFileSize(net_export_log_, &new_stop_file_size));
- EXPECT_EQ(new_stop_file_size, stop_file_size);
-}
-
-TEST_F(NetLogTempFileTest, CheckAddEvent) {
- // Add an event to |net_log_| and then test to make sure that, after we stop
- // logging, the file is larger than the file created without that event.
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_START);
- VerifyFileAndStateAfterDoStart();
-
- // Get file size without the event.
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_STOP);
- VerifyFileAndStateAfterDoStop();
-
- int64_t stop_file_size;
- EXPECT_TRUE(base::GetFileSize(net_export_log_, &stop_file_size));
-
- // Perform DO_START and add an Event and then DO_STOP and then compare
- // file sizes.
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_START);
- VerifyFileAndStateAfterDoStart();
-
- // Log an event.
- net_log_->AddGlobalEntry(net::NetLog::TYPE_CANCELLED);
-
- net_log_temp_file_->ProcessCommand(NetLogTempFile::DO_STOP);
- VerifyFileAndStateAfterDoStop();
-
- int64_t new_stop_file_size;
- EXPECT_TRUE(base::GetFileSize(net_export_log_, &new_stop_file_size));
- EXPECT_GE(new_stop_file_size, stop_file_size);
-}
-
-} // namespace net_log
diff --git a/chromium/components/net_log/resources/net_export.html b/chromium/components/net_log/resources/net_export.html
index 0aefeb70664..b3904fff13a 100644
--- a/chromium/components/net_log/resources/net_export.html
+++ b/chromium/components/net_log/resources/net_export.html
@@ -48,6 +48,8 @@
starting to log again. Otherwise, the log will be deleted.
</p>
<p>
+ <!-- TODO(rayraymond): Change link to that of new standalone webapp.
+ See http://crbug.com/472699 -->
Logs can be loaded in
<a href="chrome://net-internals" target="_blank">net-internals</a>
of desktop Chrome.
diff --git a/chromium/components/net_log/resources/net_export.js b/chromium/components/net_log/resources/net_export.js
index 702b22e5835..442379d305c 100644
--- a/chromium/components/net_log/resources/net_export.js
+++ b/chromium/components/net_log/resources/net_export.js
@@ -70,6 +70,13 @@ var NetExportView = (function() {
* the file where NetLog data is collected.
*/
onExportNetLogInfoChanged: function(exportNetLogInfo) {
+ if (!exportNetLogInfo.useMobileUI) {
+ document.getElementById('export-view-send-data').style.display =
+ "none";
+ document.getElementById('export-view-deletes-log-text').style.display =
+ "none";
+ }
+
if (exportNetLogInfo.file) {
var message = '';
if (exportNetLogInfo.state == 'LOGGING')
diff --git a/chromium/components/neterror/OWNERS b/chromium/components/neterror/OWNERS
index fd1666b446f..9f303e4e6fc 100644
--- a/chromium/components/neterror/OWNERS
+++ b/chromium/components/neterror/OWNERS
@@ -1,3 +1,4 @@
jar@chromium.org
mmenke@chromium.org
juliatuttle@chromium.org
+edwardjung@chromium.org \ No newline at end of file
diff --git a/chromium/components/neterror/resources/offline.js b/chromium/components/neterror/resources/offline.js
index 32ecc66372a..63336038b6f 100644
--- a/chromium/components/neterror/resources/offline.js
+++ b/chromium/components/neterror/resources/offline.js
@@ -43,8 +43,8 @@ function Runner(outerContainerId, opt_config) {
this.obstacles = [];
- this.started = false;
- this.activated = false;
+ this.activated = false; // Whether the easter egg has been activated.
+ this.playing = false; // Whether the game is currently in play state.
this.crashed = false;
this.paused = false;
this.inverted = false;
@@ -114,6 +114,7 @@ Runner.config = {
INITIAL_JUMP_VELOCITY: 12,
INVERT_FADE_DURATION: 12000,
INVERT_DISTANCE: 700,
+ MAX_BLINK_COUNT: 3,
MAX_CLOUDS: 6,
MAX_OBSTACLE_LENGTH: 3,
MAX_OBSTACLE_DUPLICATION: 2,
@@ -433,7 +434,7 @@ Runner.prototype = {
this.tRex.update(0);
// Outer container and distance meter.
- if (this.activated || this.crashed || this.paused) {
+ if (this.playing || this.crashed || this.paused) {
this.containerEl.style.width = this.dimensions.WIDTH + 'px';
this.containerEl.style.height = this.dimensions.HEIGHT + 'px';
this.distanceMeter.update(0, Math.ceil(this.distanceRan));
@@ -455,7 +456,7 @@ Runner.prototype = {
* Canvas container width expands out to the full width.
*/
playIntro: function() {
- if (!this.started && !this.crashed) {
+ if (!this.activated && !this.crashed) {
this.playingIntro = true;
this.tRex.playingIntro = true;
@@ -475,8 +476,8 @@ Runner.prototype = {
if (this.touchController) {
this.outerContainerEl.appendChild(this.touchController);
}
+ this.playing = true;
this.activated = true;
- this.started = true;
} else if (this.crashed) {
this.restart();
}
@@ -510,16 +511,16 @@ Runner.prototype = {
},
/**
- * Update the game frame.
+ * Update the game frame and schedules the next one.
*/
update: function() {
- this.drawPending = false;
+ this.updatePending = false;
var now = getTimeStamp();
var deltaTime = now - (this.time || now);
this.time = now;
- if (this.activated) {
+ if (this.playing) {
this.clearCanvas();
if (this.tRex.jumping) {
@@ -538,7 +539,7 @@ Runner.prototype = {
if (this.playingIntro) {
this.horizon.update(0, this.currentSpeed, hasObstacles);
} else {
- deltaTime = !this.started ? 0 : deltaTime;
+ deltaTime = !this.activated ? 0 : deltaTime;
this.horizon.update(deltaTime, this.currentSpeed, hasObstacles,
this.inverted);
}
@@ -587,9 +588,10 @@ Runner.prototype = {
}
}
- if (!this.crashed) {
+ if (this.playing || (!this.activated &&
+ this.tRex.blinkCount < Runner.config.MAX_BLINK_COUNT)) {
this.tRex.update(deltaTime);
- this.raq();
+ this.scheduleNextUpdate();
}
},
@@ -656,21 +658,22 @@ Runner.prototype = {
*/
onKeyDown: function(e) {
// Prevent native page scrolling whilst tapping on mobile.
- if (IS_MOBILE && this.activated) {
+ if (IS_MOBILE && this.playing) {
e.preventDefault();
}
if (e.target != this.detailsButton) {
if (!this.crashed && (Runner.keycodes.JUMP[e.keyCode] ||
e.type == Runner.events.TOUCHSTART)) {
- if (!this.activated) {
+ if (!this.playing) {
this.loadSounds();
- this.activated = true;
+ this.playing = true;
+ this.update();
if (window.errorPageController) {
errorPageController.trackEasterEgg();
}
}
-
+ // Play sound effect and jump on starting the game for the first time.
if (!this.tRex.jumping && !this.tRex.ducking) {
this.playSound(this.soundFx.BUTTON_PRESS);
this.tRex.startJump(this.currentSpeed);
@@ -683,7 +686,7 @@ Runner.prototype = {
}
}
- if (this.activated && !this.crashed && Runner.keycodes.DUCK[e.keyCode]) {
+ if (this.playing && !this.crashed && Runner.keycodes.DUCK[e.keyCode]) {
e.preventDefault();
if (this.tRex.jumping) {
// Speed drop, activated only when jump key is not pressed.
@@ -741,9 +744,9 @@ Runner.prototype = {
/**
* RequestAnimationFrame wrapper.
*/
- raq: function() {
- if (!this.drawPending) {
- this.drawPending = true;
+ scheduleNextUpdate: function() {
+ if (!this.updatePending) {
+ this.updatePending = true;
this.raqId = requestAnimationFrame(this.update.bind(this));
}
},
@@ -789,7 +792,7 @@ Runner.prototype = {
},
stop: function() {
- this.activated = false;
+ this.playing = false;
this.paused = true;
cancelAnimationFrame(this.raqId);
this.raqId = 0;
@@ -797,7 +800,7 @@ Runner.prototype = {
play: function() {
if (!this.crashed) {
- this.activated = true;
+ this.playing = true;
this.paused = false;
this.tRex.update(0, Trex.status.RUNNING);
this.time = getTimeStamp();
@@ -809,7 +812,7 @@ Runner.prototype = {
if (!this.raqId) {
this.playCount++;
this.runningTime = 0;
- this.activated = true;
+ this.playing = true;
this.crashed = false;
this.distanceRan = 0;
this.setSpeed(this.config.SPEED);
@@ -1488,6 +1491,7 @@ function Trex(canvas, spritePos) {
this.currentFrame = 0;
this.currentAnimFrames = [];
this.blinkDelay = 0;
+ this.blinkCount = 0;
this.animStartTime = 0;
this.timer = 0;
this.msPerFrame = 1000 / FPS;
@@ -1600,7 +1604,6 @@ Trex.prototype = {
* Sets the t-rex to blink at random intervals.
*/
init: function() {
- this.blinkDelay = this.setBlinkDelay();
this.groundYPos = Runner.defaultDimensions.HEIGHT - this.config.HEIGHT -
Runner.config.BOTTOM_PAD;
this.yPos = this.groundYPos;
@@ -1729,6 +1732,7 @@ Trex.prototype = {
// Set new random delay to blink.
this.setBlinkDelay();
this.animStartTime = time;
+ this.blinkCount++;
}
}
},
diff --git a/chromium/components/network_hints.gypi b/chromium/components/network_hints.gypi
deleted file mode 100644
index f78f480e482..00000000000
--- a/chromium/components/network_hints.gypi
+++ /dev/null
@@ -1,74 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/network_hints/common
- 'target_name': 'network_hints_common',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../ui/accessibility/accessibility.gyp:accessibility',
- '../url/ipc/url_ipc.gyp:url_ipc',
- ],
- 'sources': [
- 'network_hints/common/network_hints_common.cc',
- 'network_hints/common/network_hints_common.h',
- 'network_hints/common/network_hints_message_generator.cc',
- 'network_hints/common/network_hints_message_generator.h',
- 'network_hints/common/network_hints_messages.cc',
- 'network_hints/common/network_hints_messages.h',
- ],
- },
- {
- # GN version: //components/network_hints/browser
- 'target_name': 'network_hints_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../content/content.gyp:content_browser',
- '../net/net.gyp:net',
- ],
- 'sources': [
- 'network_hints/browser/network_hints_message_filter.cc',
- 'network_hints/browser/network_hints_message_filter.h',
- ],
- },
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'targets': [
- {
- # GN version: //components/network_hints/renderer
- 'target_name': 'network_hints_renderer',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'network_hints_common',
- '../content/content.gyp:content_renderer',
- '../third_party/WebKit/public/blink.gyp:blink',
- ],
- 'sources': [
- 'network_hints/renderer/dns_prefetch_queue.cc',
- 'network_hints/renderer/dns_prefetch_queue.h',
- 'network_hints/renderer/prescient_networking_dispatcher.cc',
- 'network_hints/renderer/prescient_networking_dispatcher.h',
- 'network_hints/renderer/renderer_dns_prefetch.cc',
- 'network_hints/renderer/renderer_dns_prefetch.h',
- 'network_hints/renderer/renderer_preconnect.cc',
- 'network_hints/renderer/renderer_preconnect.h',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/network_hints/browser/BUILD.gn b/chromium/components/network_hints/browser/BUILD.gn
index 315a535002a..9ff711498f5 100644
--- a/chromium/components/network_hints/browser/BUILD.gn
+++ b/chromium/components/network_hints/browser/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/network_hints.gypi:network_hints_browser
source_set("browser") {
sources = [
"network_hints_message_filter.cc",
diff --git a/chromium/components/network_hints/browser/network_hints_message_filter.cc b/chromium/components/network_hints/browser/network_hints_message_filter.cc
index 20f8342cc95..02f1c4983fb 100644
--- a/chromium/components/network_hints/browser/network_hints_message_filter.cc
+++ b/chromium/components/network_hints/browser/network_hints_message_filter.cc
@@ -4,6 +4,8 @@
#include "components/network_hints/browser/network_hints_message_filter.h"
+#include <string>
+
#include "base/logging.h"
#include "base/macros.h"
#include "components/network_hints/common/network_hints_common.h"
@@ -12,7 +14,7 @@
#include "net/base/address_list.h"
#include "net/base/net_errors.h"
#include "net/dns/host_resolver.h"
-#include "net/dns/single_request_host_resolver.h"
+#include "net/log/net_log_with_source.h"
#include "url/gurl.h"
namespace network_hints {
@@ -41,12 +43,10 @@ class DnsLookupRequest {
// separating it from real navigations in the observer's callback, and
// lets the HostResolver know it can be de-prioritized.
resolve_info.set_is_speculative(true);
- return resolver_.Resolve(
- resolve_info,
- net::DEFAULT_PRIORITY,
- &addresses_,
+ return resolver_->Resolve(
+ resolve_info, net::DEFAULT_PRIORITY, &addresses_,
base::Bind(&DnsLookupRequest::OnLookupFinished, base::Owned(this)),
- net::BoundNetLog());
+ &request_, net::NetLogWithSource());
}
private:
@@ -55,7 +55,8 @@ class DnsLookupRequest {
}
const std::string hostname_;
- net::SingleRequestHostResolver resolver_;
+ net::HostResolver* resolver_;
+ std::unique_ptr<net::HostResolver::Request> request_;
net::AddressList addresses_;
DISALLOW_COPY_AND_ASSIGN(DnsLookupRequest);
diff --git a/chromium/components/network_hints/common/BUILD.gn b/chromium/components/network_hints/common/BUILD.gn
index 2b0b0848934..9cba7b7192b 100644
--- a/chromium/components/network_hints/common/BUILD.gn
+++ b/chromium/components/network_hints/common/BUILD.gn
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/network_hints.gypi:predictor
-source_set("common") {
+static_library("common") {
sources = [
"network_hints_common.cc",
"network_hints_common.h",
diff --git a/chromium/components/content_settings/content/common/OWNERS b/chromium/components/network_hints/common/OWNERS
index 42444bcd16d..42444bcd16d 100644
--- a/chromium/components/content_settings/content/common/OWNERS
+++ b/chromium/components/network_hints/common/OWNERS
diff --git a/chromium/components/network_hints/common/network_hints_messages.h b/chromium/components/network_hints/common/network_hints_messages.h
index 82fce8f0f93..bc4d163a4d1 100644
--- a/chromium/components/network_hints/common/network_hints_messages.h
+++ b/chromium/components/network_hints/common/network_hints_messages.h
@@ -9,6 +9,7 @@
#include "components/network_hints/common/network_hints_common.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"
+#include "third_party/WebKit/public/platform/WebNavigationHintType.h"
#include "url/ipc/url_param_traits.h"
// Singly-included section for custom IPC traits.
@@ -33,6 +34,9 @@ struct ParamTraits<network_hints::LookupRequest> {
#define IPC_MESSAGE_START NetworkHintsMsgStart
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebNavigationHintType,
+ blink::WebNavigationHintType::Last)
+
//-----------------------------------------------------------------------------
// Host messages
// These are messages sent from the renderer process to the browser process.
@@ -48,3 +52,8 @@ IPC_MESSAGE_CONTROL3(NetworkHintsMsg_Preconnect,
GURL /* preconnect target url */,
bool /* Does connection have its credentials flag set */,
int /* number of connections */)
+
+// Request to trigger possible optimizations for navigation.
+IPC_MESSAGE_CONTROL2(NetworkHintsMsg_NavigationHint,
+ GURL /* document url */,
+ blink::WebNavigationHintType /* navigation hint type */)
diff --git a/chromium/components/network_hints/renderer/BUILD.gn b/chromium/components/network_hints/renderer/BUILD.gn
index 8ddd2abad44..70079343ae2 100644
--- a/chromium/components/network_hints/renderer/BUILD.gn
+++ b/chromium/components/network_hints/renderer/BUILD.gn
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/network_hints.gypi:predictor_renderer
-source_set("renderer") {
+static_library("renderer") {
sources = [
"dns_prefetch_queue.cc",
"dns_prefetch_queue.h",
@@ -16,9 +15,11 @@ source_set("renderer") {
]
public_deps = [
+ "//base",
"//components/network_hints/common",
"//content/public/renderer",
"//third_party/WebKit/public:blink",
+ "//url",
]
}
diff --git a/chromium/components/network_hints/renderer/prescient_networking_dispatcher.cc b/chromium/components/network_hints/renderer/prescient_networking_dispatcher.cc
index a5145ac48b9..7284bc2f5bb 100644
--- a/chromium/components/network_hints/renderer/prescient_networking_dispatcher.cc
+++ b/chromium/components/network_hints/renderer/prescient_networking_dispatcher.cc
@@ -5,6 +5,10 @@
#include "components/network_hints/renderer/prescient_networking_dispatcher.h"
#include "base/logging.h"
+#include "components/network_hints/common/network_hints_messages.h"
+#include "content/public/renderer/render_thread.h"
+
+using content::RenderThread;
namespace network_hints {
@@ -30,4 +34,12 @@ void PrescientNetworkingDispatcher::preconnect(const blink::WebURL& url,
preconnect_.Preconnect(url, allow_credentials);
}
+void PrescientNetworkingDispatcher::sendNavigationHint(
+ const blink::WebURL& url,
+ blink::WebNavigationHintType type) {
+ if (!url.isValid())
+ return;
+ RenderThread::Get()->Send(new NetworkHintsMsg_NavigationHint(url, type));
+}
+
} // namespace network_hints
diff --git a/chromium/components/network_hints/renderer/prescient_networking_dispatcher.h b/chromium/components/network_hints/renderer/prescient_networking_dispatcher.h
index a4e7ecd8802..c7f68ec4374 100644
--- a/chromium/components/network_hints/renderer/prescient_networking_dispatcher.h
+++ b/chromium/components/network_hints/renderer/prescient_networking_dispatcher.h
@@ -10,6 +10,10 @@
#include "components/network_hints/renderer/renderer_preconnect.h"
#include "third_party/WebKit/public/platform/WebPrescientNetworking.h"
+namespace blink {
+enum class WebNavigationHintType;
+}
+
namespace network_hints {
// The main entry point from blink for sending DNS prefetch requests to the
@@ -22,6 +26,8 @@ class PrescientNetworkingDispatcher : public blink::WebPrescientNetworking {
void prefetchDNS(const blink::WebString& hostname) override;
void preconnect(const blink::WebURL& url,
const bool allow_credentials) override;
+ void sendNavigationHint(const blink::WebURL& url,
+ blink::WebNavigationHintType type) override;
private:
network_hints::RendererDnsPrefetch dns_prefetch_;
diff --git a/chromium/components/network_session_configurator.gypi b/chromium/components/network_session_configurator.gypi
deleted file mode 100644
index e456e7cb52b..00000000000
--- a/chromium/components/network_session_configurator.gypi
+++ /dev/null
@@ -1,40 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/network_session_configurator
- 'target_name': 'network_session_configurator',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- 'data_reduction_proxy_core_common',
- 'network_session_configurator_switches',
- 'variations',
- 'version_info',
- ],
- 'sources': [
- 'network_session_configurator/network_session_configurator.cc',
- 'network_session_configurator/network_session_configurator.h',
- ],
- },
- {
- # GN version: //components/network_session_configurator_switches
- 'target_name': 'network_session_configurator_switches',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'network_session_configurator/switches.cc',
- 'network_session_configurator/switches.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/network_session_configurator/BUILD.gn b/chromium/components/network_session_configurator/BUILD.gn
index fcbd106ef73..63593e28c4f 100644
--- a/chromium/components/network_session_configurator/BUILD.gn
+++ b/chromium/components/network_session_configurator/BUILD.gn
@@ -2,16 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version:
-# components/components.gyp:network_session_configurator
-source_set("network_session_configurator") {
+static_library("network_session_configurator") {
sources = [
"network_session_configurator.cc",
"network_session_configurator.h",
]
public_deps = [
- ":switches",
"//base",
"//net",
]
@@ -23,15 +20,6 @@ source_set("network_session_configurator") {
]
}
-# GYP version:
-# components/components.gyp:network_session_configurator_switches
-source_set("switches") {
- sources = [
- "switches.cc",
- "switches.h",
- ]
-}
-
source_set("unit_tests") {
testonly = true
sources = [
diff --git a/chromium/components/network_session_configurator/network_session_configurator.cc b/chromium/components/network_session_configurator/network_session_configurator.cc
index a54ae4447fc..593da58040c 100644
--- a/chromium/components/network_session_configurator/network_session_configurator.cc
+++ b/chromium/components/network_session_configurator/network_session_configurator.cc
@@ -12,12 +12,11 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/network_session_configurator/switches.h"
#include "components/variations/variations_associated_data.h"
#include "components/version_info/version_info.h"
#include "net/http/http_stream_factory.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
#include "net/url_request/url_fetcher.h"
namespace {
@@ -32,38 +31,9 @@ const char kQuicFieldTrialName[] = "QUIC";
const char kQuicFieldTrialEnabledGroupName[] = "Enabled";
const char kQuicFieldTrialHttpsEnabledGroupName[] = "HttpsEnabled";
-// The SPDY trial composes two different trial plus control groups:
-// * A "holdback" group with SPDY disabled, and corresponding control
-// (SPDY/3.1). The primary purpose of the holdback group is to encourage site
-// operators to do feature detection rather than UA-sniffing. As such, this
-// trial runs continuously.
-// * A SPDY/4 experiment, for SPDY/4 (aka HTTP/2) vs SPDY/3.1 comparisons and
-// eventual SPDY/4 deployment.
-const char kSpdyFieldTrialName[] = "SPDY";
-const char kSpdyFieldTrialHoldbackGroupNamePrefix[] = "SpdyDisabled";
-const char kSpdyFieldTrialSpdy31GroupNamePrefix[] = "Spdy31Enabled";
-const char kSpdyFieldTrialSpdy4GroupNamePrefix[] = "Spdy4Enabled";
-const char kSpdyFieldTrialParametrizedPrefix[] = "Parametrized";
-
-// Field trial for NPN.
-const char kNpnTrialName[] = "NPN";
-const char kNpnTrialEnabledGroupNamePrefix[] = "Enable";
-const char kNpnTrialDisabledGroupNamePrefix[] = "Disable";
-
-// Field trial for priority dependencies.
-const char kSpdyDependenciesFieldTrial[] = "SpdyEnableDependencies";
-const char kSpdyDependenciesFieldTrialEnable[] = "Enable";
-const char kSpdyDepencenciesFieldTrialDisable[] = "Disable";
-
-int GetSwitchValueAsInt(const base::CommandLine& command_line,
- const std::string& switch_name) {
- int value;
- if (!base::StringToInt(command_line.GetSwitchValueASCII(switch_name),
- &value)) {
- return 0;
- }
- return value;
-}
+// Field trial for HTTP/2.
+const char kHttp2FieldTrialName[] = "HTTP2";
+const char kHttp2FieldTrialDisablePrefix[] = "Disable";
// Returns the value associated with |key| in |params| or "" if the
// key is not present in the map.
@@ -83,93 +53,19 @@ void ConfigureTCPFastOpenParams(base::StringPiece tfo_trial_group,
params->enable_tcp_fast_open_for_ssl = true;
}
-void ConfigureSpdyParams(const base::CommandLine& command_line,
- base::StringPiece spdy_trial_group,
- const VariationParameters& spdy_trial_params,
- bool is_spdy_allowed_by_policy,
- net::HttpNetworkSession::Params* params) {
- // Only handle SPDY field trial parameters and command line flags if
- // "spdy.disabled" preference is not forced via policy.
- if (!is_spdy_allowed_by_policy) {
- params->enable_spdy31 = false;
- return;
- }
-
- if (command_line.HasSwitch(switches::kIgnoreUrlFetcherCertRequests))
- net::URLFetcher::SetIgnoreCertificateRequests(true);
-
- if (command_line.HasSwitch(switches::kDisableHttp2)) {
- params->enable_spdy31 = false;
- params->enable_http2 = false;
- return;
- }
-
- if (spdy_trial_group.starts_with(kSpdyFieldTrialHoldbackGroupNamePrefix)) {
- net::HttpStreamFactory::set_spdy_enabled(false);
- return;
- }
- if (spdy_trial_group.starts_with(kSpdyFieldTrialSpdy31GroupNamePrefix)) {
- params->enable_spdy31 = true;
- params->enable_http2 = false;
- return;
- }
- if (spdy_trial_group.starts_with(kSpdyFieldTrialSpdy4GroupNamePrefix)) {
- params->enable_spdy31 = true;
- params->enable_http2 = true;
- return;
- }
- if (spdy_trial_group.starts_with(kSpdyFieldTrialParametrizedPrefix)) {
- bool spdy_enabled = false;
- params->enable_spdy31 = false;
+void ConfigureHttp2Params(base::StringPiece http2_trial_group,
+ net::HttpNetworkSession::Params* params) {
+ if (http2_trial_group.starts_with(kHttp2FieldTrialDisablePrefix)) {
params->enable_http2 = false;
- if (base::LowerCaseEqualsASCII(
- GetVariationParam(spdy_trial_params, "enable_http2"), "true")) {
- spdy_enabled = true;
- params->enable_http2 = true;
- }
- if (base::LowerCaseEqualsASCII(
- GetVariationParam(spdy_trial_params, "enable_spdy31"), "true")) {
- spdy_enabled = true;
- params->enable_spdy31 = true;
- }
- // TODO(bnc): https://crbug.com/521597
- // HttpStreamFactory::spdy_enabled_ is redundant with params->enable_http2
- // and enable_spdy31, can it be eliminated?
- net::HttpStreamFactory::set_spdy_enabled(spdy_enabled);
- return;
}
}
-void ConfigureNPNParams(const base::CommandLine& command_line,
- base::StringPiece npn_trial_group,
- net::HttpNetworkSession::Params* params) {
- if (npn_trial_group.starts_with(kNpnTrialEnabledGroupNamePrefix)) {
- params->enable_npn = true;
- } else if (npn_trial_group.starts_with(kNpnTrialDisabledGroupNamePrefix)) {
- params->enable_npn = false;
- }
-}
-
-void ConfigurePriorityDependencies(
- base::StringPiece priority_dependencies_trial_group,
- net::HttpNetworkSession::Params* params) {
- if (priority_dependencies_trial_group.starts_with(
- kSpdyDependenciesFieldTrialEnable)) {
- params->enable_priority_dependencies = true;
- } else if (priority_dependencies_trial_group.starts_with(
- kSpdyDepencenciesFieldTrialDisable)) {
- params->enable_priority_dependencies = false;
- }
-}
-
-bool ShouldEnableQuic(const base::CommandLine& command_line,
- base::StringPiece quic_trial_group,
- bool is_quic_allowed_by_policy) {
- if (command_line.HasSwitch(switches::kDisableQuic) ||
- !is_quic_allowed_by_policy)
+bool ShouldEnableQuic(base::StringPiece quic_trial_group,
+ bool is_quic_force_disabled,
+ bool is_quic_force_enabled) {
+ if (is_quic_force_disabled)
return false;
-
- if (command_line.HasSwitch(switches::kEnableQuic))
+ if (is_quic_force_enabled)
return true;
return quic_trial_group.starts_with(kQuicFieldTrialEnabledGroupName) ||
@@ -192,7 +88,6 @@ bool ShouldQuicDisableConnectionPooling(
}
bool ShouldQuicEnableAlternativeServicesForDifferentHost(
- const base::CommandLine& command_line,
const VariationParameters& quic_trial_params) {
return !base::LowerCaseEqualsASCII(
GetVariationParam(quic_trial_params,
@@ -200,24 +95,8 @@ bool ShouldQuicEnableAlternativeServicesForDifferentHost(
"false");
}
-bool ShouldEnableQuicPortSelection(const base::CommandLine& command_line) {
- if (command_line.HasSwitch(switches::kDisableQuicPortSelection))
- return false;
-
- if (command_line.HasSwitch(switches::kEnableQuicPortSelection))
- return true;
-
- return false; // Default to disabling port selection on all channels.
-}
-
net::QuicTagVector GetQuicConnectionOptions(
- const base::CommandLine& command_line,
const VariationParameters& quic_trial_params) {
- if (command_line.HasSwitch(switches::kQuicConnectionOptions)) {
- return net::QuicUtils::ParseQuicConnectionOptions(
- command_line.GetSwitchValueASCII(switches::kQuicConnectionOptions));
- }
-
VariationParameters::const_iterator it =
quic_trial_params.find("connection_options");
if (it == quic_trial_params.end()) {
@@ -268,25 +147,9 @@ bool ShouldQuicPreferAes(const VariationParameters& quic_trial_params) {
GetVariationParam(quic_trial_params, "prefer_aes"), "true");
}
-int GetQuicMaxNumberOfLossyConnections(
- const VariationParameters& quic_trial_params) {
- int value;
- if (base::StringToInt(GetVariationParam(quic_trial_params,
- "max_number_of_lossy_connections"),
- &value)) {
- return value;
- }
- return 0;
-}
-
-float GetQuicPacketLossThreshold(const VariationParameters& quic_trial_params) {
- double value;
- if (base::StringToDouble(
- GetVariationParam(quic_trial_params, "packet_loss_threshold"),
- &value)) {
- return static_cast<float>(value);
- }
- return 0.0f;
+bool ShouldForceHolBlocking(const VariationParameters& quic_trial_params) {
+ return base::LowerCaseEqualsASCII(
+ GetVariationParam(quic_trial_params, "force_hol_blocking"), "true");
}
int GetQuicSocketReceiveBufferSize(
@@ -323,6 +186,43 @@ int GetQuicIdleConnectionTimeoutSeconds(
return 0;
}
+int GetQuicReducedPingTimeoutSeconds(
+ const VariationParameters& quic_trial_params) {
+ int value;
+ if (base::StringToInt(
+ GetVariationParam(quic_trial_params, "reduced_ping_timeout_seconds"),
+ &value)) {
+ return value;
+ }
+ return 0;
+}
+
+int GetQuicPacketReaderYieldAfterDurationMilliseconds(
+ const VariationParameters& quic_trial_params) {
+ int value;
+ if (base::StringToInt(
+ GetVariationParam(quic_trial_params,
+ "packet_reader_yield_after_duration_milliseconds"),
+ &value)) {
+ return value;
+ }
+ return 0;
+}
+
+bool ShouldQuicRaceCertVerification(
+ const VariationParameters& quic_trial_params) {
+ return base::LowerCaseEqualsASCII(
+ GetVariationParam(quic_trial_params, "race_cert_verification"),
+ "true");
+}
+
+bool ShouldQuicDoNotFragment(
+ const VariationParameters& quic_trial_params) {
+ return base::LowerCaseEqualsASCII(
+ GetVariationParam(quic_trial_params, "do_not_fragment"),
+ "true");
+}
+
bool ShouldQuicDisablePreConnectIfZeroRtt(
const VariationParameters& quic_trial_params) {
return base::LowerCaseEqualsASCII(
@@ -331,14 +231,9 @@ bool ShouldQuicDisablePreConnectIfZeroRtt(
}
std::unordered_set<std::string> GetQuicHostWhitelist(
- const base::CommandLine& command_line,
const VariationParameters& quic_trial_params) {
- std::string whitelist;
- if (command_line.HasSwitch(switches::kQuicHostWhitelist)) {
- whitelist = command_line.GetSwitchValueASCII(switches::kQuicHostWhitelist);
- } else {
- whitelist = GetVariationParam(quic_trial_params, "quic_host_whitelist");
- }
+ std::string whitelist =
+ GetVariationParam(quic_trial_params, "quic_host_whitelist");
std::unordered_set<std::string> hosts;
for (const std::string& host : base::SplitString(
whitelist, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
@@ -361,18 +256,15 @@ bool ShouldQuicMigrateSessionsEarly(
GetVariationParam(quic_trial_params, "migrate_sessions_early"), "true");
}
-size_t GetQuicMaxPacketLength(const base::CommandLine& command_line,
- const VariationParameters& quic_trial_params) {
- if (command_line.HasSwitch(switches::kQuicMaxPacketLength)) {
- unsigned value;
- if (!base::StringToUint(
- command_line.GetSwitchValueASCII(switches::kQuicMaxPacketLength),
- &value)) {
- return 0;
- }
- return value;
- }
+bool ShouldQuicAllowServerMigration(
+ const VariationParameters& quic_trial_params) {
+ return base::LowerCaseEqualsASCII(
+ GetVariationParam(quic_trial_params,
+ "allow_server_migration"),
+ "true");
+}
+size_t GetQuicMaxPacketLength(const VariationParameters& quic_trial_params) {
unsigned value;
if (base::StringToUint(
GetVariationParam(quic_trial_params, "max_packet_length"), &value)) {
@@ -381,42 +273,24 @@ size_t GetQuicMaxPacketLength(const base::CommandLine& command_line,
return 0;
}
-net::QuicVersion ParseQuicVersion(const std::string& quic_version) {
- net::QuicVersionVector supported_versions = net::QuicSupportedVersions();
- for (size_t i = 0; i < supported_versions.size(); ++i) {
- net::QuicVersion version = supported_versions[i];
- if (net::QuicVersionToString(version) == quic_version) {
- return version;
- }
- }
-
- return net::QUIC_VERSION_UNSUPPORTED;
-}
-
-net::QuicVersion GetQuicVersion(const base::CommandLine& command_line,
- const VariationParameters& quic_trial_params) {
- if (command_line.HasSwitch(switches::kQuicVersion)) {
- return ParseQuicVersion(
- command_line.GetSwitchValueASCII(switches::kQuicVersion));
- }
-
- return ParseQuicVersion(GetVariationParam(quic_trial_params, "quic_version"));
+net::QuicVersion GetQuicVersion(const VariationParameters& quic_trial_params) {
+ return network_session_configurator::ParseQuicVersion(
+ GetVariationParam(quic_trial_params, "quic_version"));
}
-void ConfigureQuicParams(const base::CommandLine& command_line,
- base::StringPiece quic_trial_group,
+void ConfigureQuicParams(base::StringPiece quic_trial_group,
const VariationParameters& quic_trial_params,
- bool is_quic_allowed_by_policy,
+ bool is_quic_force_disabled,
+ bool is_quic_force_enabled,
const std::string& quic_user_agent_id,
net::HttpNetworkSession::Params* params) {
- params->enable_quic = ShouldEnableQuic(command_line, quic_trial_group,
- is_quic_allowed_by_policy);
+ params->enable_quic = ShouldEnableQuic(
+ quic_trial_group, is_quic_force_disabled, is_quic_force_enabled);
params->disable_quic_on_timeout_with_open_streams =
ShouldDisableQuicWhenConnectionTimesOutWithOpenStreams(quic_trial_params);
params->enable_quic_alternative_service_with_different_host =
- ShouldQuicEnableAlternativeServicesForDifferentHost(command_line,
- quic_trial_params);
+ ShouldQuicEnableAlternativeServicesForDifferentHost(quic_trial_params);
if (params->enable_quic) {
params->quic_always_require_handshake_confirmation =
@@ -441,19 +315,11 @@ void ConfigureQuicParams(const base::CommandLine& command_line,
params->quic_disable_disk_cache =
ShouldQuicDisableDiskCache(quic_trial_params);
params->quic_prefer_aes = ShouldQuicPreferAes(quic_trial_params);
- int max_number_of_lossy_connections =
- GetQuicMaxNumberOfLossyConnections(quic_trial_params);
- if (max_number_of_lossy_connections != 0) {
- params->quic_max_number_of_lossy_connections =
- max_number_of_lossy_connections;
- }
- float packet_loss_threshold = GetQuicPacketLossThreshold(quic_trial_params);
- if (packet_loss_threshold != 0)
- params->quic_packet_loss_threshold = packet_loss_threshold;
- params->enable_quic_port_selection =
- ShouldEnableQuicPortSelection(command_line);
+ params->quic_force_hol_blocking = ShouldForceHolBlocking(quic_trial_params);
+ // Default to disabling port selection on all channels.
+ params->enable_quic_port_selection = false;
params->quic_connection_options =
- GetQuicConnectionOptions(command_line, quic_trial_params);
+ GetQuicConnectionOptions(quic_trial_params);
params->quic_close_sessions_on_ip_change =
ShouldQuicCloseSessionsOnIpChange(quic_trial_params);
int idle_connection_timeout_seconds =
@@ -462,122 +328,84 @@ void ConfigureQuicParams(const base::CommandLine& command_line,
params->quic_idle_connection_timeout_seconds =
idle_connection_timeout_seconds;
}
+ int reduced_ping_timeout_seconds =
+ GetQuicReducedPingTimeoutSeconds(quic_trial_params);
+ if (reduced_ping_timeout_seconds > 0 &&
+ reduced_ping_timeout_seconds < net::kPingTimeoutSecs) {
+ params->quic_reduced_ping_timeout_seconds = reduced_ping_timeout_seconds;
+ }
+ int packet_reader_yield_after_duration_milliseconds =
+ GetQuicPacketReaderYieldAfterDurationMilliseconds(quic_trial_params);
+ if (packet_reader_yield_after_duration_milliseconds != 0) {
+ params->quic_packet_reader_yield_after_duration_milliseconds =
+ packet_reader_yield_after_duration_milliseconds;
+ }
+ params->quic_race_cert_verification =
+ ShouldQuicRaceCertVerification(quic_trial_params);
+ params->quic_do_not_fragment =
+ ShouldQuicDoNotFragment(quic_trial_params);
params->quic_disable_preconnect_if_0rtt =
ShouldQuicDisablePreConnectIfZeroRtt(quic_trial_params);
- params->quic_host_whitelist =
- GetQuicHostWhitelist(command_line, quic_trial_params);
+ params->quic_host_whitelist = GetQuicHostWhitelist(quic_trial_params);
params->quic_migrate_sessions_on_network_change =
ShouldQuicMigrateSessionsOnNetworkChange(quic_trial_params);
params->quic_migrate_sessions_early =
ShouldQuicMigrateSessionsEarly(quic_trial_params);
+ params->quic_allow_server_migration =
+ ShouldQuicAllowServerMigration(quic_trial_params);
}
- size_t max_packet_length =
- GetQuicMaxPacketLength(command_line, quic_trial_params);
+ size_t max_packet_length = GetQuicMaxPacketLength(quic_trial_params);
if (max_packet_length != 0) {
params->quic_max_packet_length = max_packet_length;
}
params->quic_user_agent_id = quic_user_agent_id;
- net::QuicVersion version = GetQuicVersion(command_line, quic_trial_params);
+ net::QuicVersion version = GetQuicVersion(quic_trial_params);
if (version != net::QUIC_VERSION_UNSUPPORTED) {
net::QuicVersionVector supported_versions;
supported_versions.push_back(version);
params->quic_supported_versions = supported_versions;
}
-
- if (command_line.HasSwitch(switches::kOriginToForceQuicOn)) {
- std::string origins =
- command_line.GetSwitchValueASCII(switches::kOriginToForceQuicOn);
- for (const std::string& host_port : base::SplitString(
- origins, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
- net::HostPortPair quic_origin = net::HostPortPair::FromString(host_port);
- if (!quic_origin.IsEmpty())
- params->origins_to_force_quic_on.insert(quic_origin);
- }
- }
}
-void ParseFieldTrialsAndCommandLineInternal(
- const base::CommandLine& command_line,
- bool is_spdy_allowed_by_policy,
- bool is_quic_allowed_by_policy,
- const std::string& quic_user_agent_id,
- net::HttpNetworkSession::Params* params) {
- // Parameters only controlled by command line.
- if (command_line.HasSwitch(switches::kIgnoreCertificateErrors))
- params->ignore_certificate_errors = true;
- if (command_line.HasSwitch(switches::kTestingFixedHttpPort)) {
- params->testing_fixed_http_port =
- GetSwitchValueAsInt(command_line, switches::kTestingFixedHttpPort);
- }
- if (command_line.HasSwitch(switches::kTestingFixedHttpsPort)) {
- params->testing_fixed_https_port =
- GetSwitchValueAsInt(command_line, switches::kTestingFixedHttpsPort);
+} // anonymous namespace
+
+namespace network_session_configurator {
+
+net::QuicVersion ParseQuicVersion(const std::string& quic_version) {
+ net::QuicVersionVector supported_versions = net::AllSupportedVersions();
+ for (size_t i = 0; i < supported_versions.size(); ++i) {
+ net::QuicVersion version = supported_versions[i];
+ if (net::QuicVersionToString(version) == quic_version) {
+ return version;
+ }
}
- // Always fetch the field trial groups to ensure they are reported correctly.
- // The command line flags will be associated with a group that is reported so
- // long as trial is actually queried.
+ return net::QUIC_VERSION_UNSUPPORTED;
+}
+void ParseFieldTrials(bool is_quic_force_disabled,
+ bool is_quic_force_enabled,
+ const std::string& quic_user_agent_id,
+ net::HttpNetworkSession::Params* params) {
std::string quic_trial_group =
base::FieldTrialList::FindFullName(kQuicFieldTrialName);
VariationParameters quic_trial_params;
if (!variations::GetVariationParams(kQuicFieldTrialName, &quic_trial_params))
quic_trial_params.clear();
- ConfigureQuicParams(command_line, quic_trial_group, quic_trial_params,
- is_quic_allowed_by_policy, quic_user_agent_id, params);
+ ConfigureQuicParams(quic_trial_group, quic_trial_params,
+ is_quic_force_disabled, is_quic_force_enabled,
+ quic_user_agent_id, params);
- if (!is_spdy_allowed_by_policy) {
- base::FieldTrial* trial = base::FieldTrialList::Find(kSpdyFieldTrialName);
- if (trial)
- trial->Disable();
- }
- std::string spdy_trial_group =
- base::FieldTrialList::FindFullName(kSpdyFieldTrialName);
- VariationParameters spdy_trial_params;
- if (!variations::GetVariationParams(kSpdyFieldTrialName, &spdy_trial_params))
- spdy_trial_params.clear();
- ConfigureSpdyParams(command_line, spdy_trial_group, spdy_trial_params,
- is_spdy_allowed_by_policy, params);
+ std::string http2_trial_group =
+ base::FieldTrialList::FindFullName(kHttp2FieldTrialName);
+ ConfigureHttp2Params(http2_trial_group, params);
const std::string tfo_trial_group =
base::FieldTrialList::FindFullName(kTCPFastOpenFieldTrialName);
ConfigureTCPFastOpenParams(tfo_trial_group, params);
-
- std::string npn_trial_group =
- base::FieldTrialList::FindFullName(kNpnTrialName);
- ConfigureNPNParams(command_line, npn_trial_group, params);
-
- std::string priority_dependencies_trial_group =
- base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial);
- ConfigurePriorityDependencies(priority_dependencies_trial_group, params);
-}
-
-} // anonymous namespace
-
-namespace network_session_configurator {
-
-void ParseFieldTrials(bool is_spdy_allowed_by_policy,
- bool is_quic_allowed_by_policy,
- const std::string& quic_user_agent_id,
- net::HttpNetworkSession::Params* params) {
- const base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
- ParseFieldTrialsAndCommandLineInternal(
- command_line, is_spdy_allowed_by_policy, is_quic_allowed_by_policy,
- quic_user_agent_id, params);
-}
-
-void ParseFieldTrialsAndCommandLine(bool is_spdy_allowed_by_policy,
- bool is_quic_allowed_by_policy,
- const std::string& quic_user_agent_id,
- net::HttpNetworkSession::Params* params) {
- const base::CommandLine& command_line =
- *base::CommandLine::ForCurrentProcess();
- ParseFieldTrialsAndCommandLineInternal(
- command_line, is_spdy_allowed_by_policy, is_quic_allowed_by_policy,
- quic_user_agent_id, params);
}
} // namespace network_session_configurator
diff --git a/chromium/components/network_session_configurator/network_session_configurator.h b/chromium/components/network_session_configurator/network_session_configurator.h
index 4af164810b1..4dcb2f6283f 100644
--- a/chromium/components/network_session_configurator/network_session_configurator.h
+++ b/chromium/components/network_session_configurator/network_session_configurator.h
@@ -10,24 +10,21 @@
#include <string>
-#include "base/command_line.h"
#include "net/http/http_network_session.h"
namespace network_session_configurator {
-// Configure |params| based on field trials and policy arguments.
-void ParseFieldTrials(bool is_spdy_allowed_by_policy,
- bool is_quic_allowed_by_policy,
+// Parse serialized QUIC version string.
+// Return QUIC_VERSION_UNSUPPORTED on failure.
+net::QuicVersion ParseQuicVersion(const std::string& quic_version);
+
+// Configure |params| based on field trials
+// and forcing (policy or command line) arguments.
+void ParseFieldTrials(bool is_quic_force_disabled,
+ bool is_quic_force_enabled,
const std::string& quic_user_agent_id,
net::HttpNetworkSession::Params* params);
-// Configure |params| based on field trials, policy arguments,
-// and command line.
-void ParseFieldTrialsAndCommandLine(bool is_spdy_allowed_by_policy,
- bool is_quic_allowed_by_policy,
- const std::string& quic_user_agent_id,
- net::HttpNetworkSession::Params* params);
-
} // namespace network_session_configurator
#endif // COMPONENTS_NETWORK_SESSION_CONFIGURATOR_NETWORK_SESSION_CONFIGURATOR_H_
diff --git a/chromium/components/network_session_configurator/network_session_configurator_unittest.cc b/chromium/components/network_session_configurator/network_session_configurator_unittest.cc
index 861f071182c..26e5ad9ebff 100644
--- a/chromium/components/network_session_configurator/network_session_configurator_unittest.cc
+++ b/chromium/components/network_session_configurator/network_session_configurator_unittest.cc
@@ -7,12 +7,12 @@
#include <map>
#include <memory>
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/test/mock_entropy_provider.h"
-#include "components/network_session_configurator/switches.h"
#include "components/variations/variations_associated_data.h"
#include "net/http/http_stream_factory.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace test {
@@ -20,165 +20,45 @@ namespace test {
class NetworkSessionConfiguratorTest : public testing::Test {
public:
NetworkSessionConfiguratorTest()
- : is_spdy_allowed_by_policy_(true),
- is_quic_allowed_by_policy_(true),
- quic_user_agent_id_("Chrome/52.0.2709.0 Linux x86_64") {
+ : quic_user_agent_id_("Chrome/52.0.2709.0 Linux x86_64") {
field_trial_list_.reset(
- new base::FieldTrialList(new base::MockEntropyProvider()));
+ new base::FieldTrialList(
+ base::MakeUnique<base::MockEntropyProvider>()));
variations::testing::ClearAllVariationParams();
}
void ParseFieldTrials() {
network_session_configurator::ParseFieldTrials(
- is_spdy_allowed_by_policy_, is_quic_allowed_by_policy_,
- quic_user_agent_id_, &params_);
+ /*is_quic_force_disabled=*/false,
+ /*is_quic_force_enabled=*/false, quic_user_agent_id_, &params_);
}
- void ParseFieldTrialsAndCommandLine() {
- network_session_configurator::ParseFieldTrialsAndCommandLine(
- is_spdy_allowed_by_policy_, is_quic_allowed_by_policy_,
- quic_user_agent_id_, &params_);
- }
-
- bool is_spdy_allowed_by_policy_;
- bool is_quic_allowed_by_policy_;
std::string quic_user_agent_id_;
std::unique_ptr<base::FieldTrialList> field_trial_list_;
net::HttpNetworkSession::Params params_;
};
TEST_F(NetworkSessionConfiguratorTest, Defaults) {
- ParseFieldTrialsAndCommandLine();
+ ParseFieldTrials();
EXPECT_FALSE(params_.ignore_certificate_errors);
EXPECT_EQ("Chrome/52.0.2709.0 Linux x86_64", params_.quic_user_agent_id);
EXPECT_EQ(0u, params_.testing_fixed_http_port);
EXPECT_EQ(0u, params_.testing_fixed_https_port);
- EXPECT_FALSE(params_.enable_spdy31);
EXPECT_TRUE(params_.enable_http2);
EXPECT_FALSE(params_.enable_tcp_fast_open_for_ssl);
EXPECT_TRUE(params_.enable_quic_alternative_service_with_different_host);
- EXPECT_FALSE(params_.enable_npn);
- EXPECT_TRUE(params_.enable_priority_dependencies);
EXPECT_FALSE(params_.enable_quic);
}
-TEST_F(NetworkSessionConfiguratorTest, IgnoreCertificateErrors) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- "ignore-certificate-errors");
-
- ParseFieldTrialsAndCommandLine();
-
- EXPECT_TRUE(params_.ignore_certificate_errors);
-}
-
-TEST_F(NetworkSessionConfiguratorTest, TestingFixedPort) {
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- "testing-fixed-http-port", "42");
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- "testing-fixed-https-port", "1234");
-
- ParseFieldTrialsAndCommandLine();
-
- EXPECT_EQ(42u, params_.testing_fixed_http_port);
- EXPECT_EQ(1234u, params_.testing_fixed_https_port);
-}
-
-TEST_F(NetworkSessionConfiguratorTest, SpdyFieldTrialHoldbackEnabled) {
- net::HttpStreamFactory::set_spdy_enabled(true);
- base::FieldTrialList::CreateFieldTrial("SPDY", "SpdyDisabled");
+TEST_F(NetworkSessionConfiguratorTest, Http2FieldTrialHttp2Disable) {
+ base::FieldTrialList::CreateFieldTrial("HTTP2", "Disable");
ParseFieldTrials();
- EXPECT_FALSE(net::HttpStreamFactory::spdy_enabled());
-}
-
-TEST_F(NetworkSessionConfiguratorTest, SpdyFieldTrialSpdy31Enabled) {
- base::FieldTrialList::CreateFieldTrial("SPDY", "Spdy31Enabled");
-
- ParseFieldTrials();
-
- EXPECT_TRUE(params_.enable_spdy31);
EXPECT_FALSE(params_.enable_http2);
}
-TEST_F(NetworkSessionConfiguratorTest, SpdyFieldTrialSpdy4Enabled) {
- base::FieldTrialList::CreateFieldTrial("SPDY", "Spdy4Enabled");
-
- ParseFieldTrials();
-
- EXPECT_TRUE(params_.enable_spdy31);
- EXPECT_TRUE(params_.enable_http2);
-}
-
-TEST_F(NetworkSessionConfiguratorTest, SpdyFieldTrialParametrized) {
- std::map<std::string, std::string> field_trial_params;
- field_trial_params["enable_spdy31"] = "false";
- field_trial_params["enable_http2"] = "true";
- variations::AssociateVariationParams("SPDY", "ParametrizedHTTP2Only",
- field_trial_params);
- base::FieldTrialList::CreateFieldTrial("SPDY", "ParametrizedHTTP2Only");
-
- ParseFieldTrials();
-
- EXPECT_FALSE(params_.enable_spdy31);
- EXPECT_TRUE(params_.enable_http2);
-}
-
-TEST_F(NetworkSessionConfiguratorTest, SpdyCommandLineDisableHttp2) {
- // Command line should overwrite field trial group.
- base::CommandLine::ForCurrentProcess()->AppendSwitch("disable-http2");
- base::FieldTrialList::CreateFieldTrial("SPDY", "Spdy4Enabled");
-
- ParseFieldTrialsAndCommandLine();
-
- EXPECT_FALSE(params_.enable_spdy31);
- EXPECT_FALSE(params_.enable_http2);
-}
-
-TEST_F(NetworkSessionConfiguratorTest, SpdyDisallowedByPolicy) {
- is_spdy_allowed_by_policy_ = false;
-
- ParseFieldTrialsAndCommandLine();
-
- EXPECT_FALSE(params_.enable_spdy31);
- EXPECT_TRUE(params_.enable_http2);
-}
-
-TEST_F(NetworkSessionConfiguratorTest, NPNFieldTrialEnabled) {
- base::FieldTrialList::CreateFieldTrial("NPN", "Enable-experiment");
-
- ParseFieldTrials();
-
- EXPECT_TRUE(params_.enable_npn);
-}
-
-TEST_F(NetworkSessionConfiguratorTest, NPNFieldTrialDisabled) {
- base::FieldTrialList::CreateFieldTrial("NPN", "Disable-holdback");
-
- ParseFieldTrials();
-
- EXPECT_FALSE(params_.enable_npn);
-}
-
-TEST_F(NetworkSessionConfiguratorTest, PriorityDependenciesTrialEnabled) {
- base::FieldTrialList::CreateFieldTrial("SpdyEnableDependencies",
- "Enable-experiment");
-
- ParseFieldTrials();
-
- EXPECT_TRUE(params_.enable_priority_dependencies);
-}
-
-TEST_F(NetworkSessionConfiguratorTest, PriorityDependenciesTrialDisabled) {
- base::FieldTrialList::CreateFieldTrial("SpdyEnableDependencies",
- "Disable-holdback");
-
- ParseFieldTrials();
-
- EXPECT_FALSE(params_.enable_priority_dependencies);
-}
-
TEST_F(NetworkSessionConfiguratorTest, EnableQuicFromFieldTrialGroup) {
base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
@@ -196,37 +76,33 @@ TEST_F(NetworkSessionConfiguratorTest, EnableQuicFromFieldTrialGroup) {
EXPECT_FALSE(params_.quic_disable_disk_cache);
EXPECT_FALSE(params_.quic_prefer_aes);
EXPECT_TRUE(params_.enable_quic_alternative_service_with_different_host);
- EXPECT_EQ(0, params_.quic_max_number_of_lossy_connections);
- EXPECT_EQ(1.0f, params_.quic_packet_loss_threshold);
EXPECT_TRUE(params_.quic_delay_tcp_race);
EXPECT_FALSE(params_.quic_close_sessions_on_ip_change);
EXPECT_EQ(net::kIdleConnectionTimeoutSeconds,
params_.quic_idle_connection_timeout_seconds);
+ EXPECT_EQ(net::kPingTimeoutSecs, params_.quic_reduced_ping_timeout_seconds);
+ EXPECT_EQ(net::kQuicYieldAfterDurationMilliseconds,
+ params_.quic_packet_reader_yield_after_duration_milliseconds);
+ EXPECT_FALSE(params_.quic_race_cert_verification);
+ EXPECT_FALSE(params_.quic_do_not_fragment);
EXPECT_FALSE(params_.quic_disable_preconnect_if_0rtt);
EXPECT_FALSE(params_.quic_migrate_sessions_on_network_change);
EXPECT_FALSE(params_.quic_migrate_sessions_early);
+ EXPECT_FALSE(params_.quic_allow_server_migration);
EXPECT_TRUE(params_.quic_host_whitelist.empty());
+ EXPECT_FALSE(params_.quic_force_hol_blocking);
net::HttpNetworkSession::Params default_params;
EXPECT_EQ(default_params.quic_supported_versions,
params_.quic_supported_versions);
}
-TEST_F(NetworkSessionConfiguratorTest, DisableQuicFromCommandLine) {
- base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
- base::CommandLine::ForCurrentProcess()->AppendSwitch("disable-quic");
-
- ParseFieldTrialsAndCommandLine();
-
- EXPECT_FALSE(params_.enable_quic);
-}
-
TEST_F(NetworkSessionConfiguratorTest, EnableQuicForDataReductionProxy) {
base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
base::FieldTrialList::CreateFieldTrial("DataReductionProxyUseQuic",
"Enabled");
- ParseFieldTrialsAndCommandLine();
+ ParseFieldTrials();
EXPECT_TRUE(params_.enable_quic);
}
@@ -243,69 +119,92 @@ TEST_F(NetworkSessionConfiguratorTest,
EXPECT_TRUE(params_.disable_quic_on_timeout_with_open_streams);
}
-TEST_F(NetworkSessionConfiguratorTest, EnableQuicFromCommandLine) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch("enable-quic");
+TEST_F(NetworkSessionConfiguratorTest,
+ QuicCloseSessionsOnIpChangeFromFieldTrialParams) {
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["close_sessions_on_ip_change"] = "true";
+ variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
- ParseFieldTrialsAndCommandLine();
+ ParseFieldTrials();
- EXPECT_TRUE(params_.enable_quic);
+ EXPECT_TRUE(params_.quic_close_sessions_on_ip_change);
}
TEST_F(NetworkSessionConfiguratorTest,
- EnableAlternativeServicesFromCommandLineWithQuicDisabled) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- "enable-alternative-services");
+ QuicIdleConnectionTimeoutSecondsFieldTrialParams) {
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["idle_connection_timeout_seconds"] = "300";
+ variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
- ParseFieldTrialsAndCommandLine();
+ ParseFieldTrials();
- EXPECT_FALSE(params_.enable_quic);
- EXPECT_TRUE(params_.enable_quic_alternative_service_with_different_host);
+ EXPECT_EQ(300, params_.quic_idle_connection_timeout_seconds);
}
TEST_F(NetworkSessionConfiguratorTest,
- EnableAlternativeServicesFromCommandLineWithQuicEnabled) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch("enable-quic");
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- "enable-alternative-services");
+ NegativeQuicReducedPingTimeoutSecondsFieldTrialParams) {
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["reduced_ping_timeout_seconds"] = "-5";
+ variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
+ ParseFieldTrials();
+ EXPECT_EQ(net::kPingTimeoutSecs, params_.quic_reduced_ping_timeout_seconds);
+}
- ParseFieldTrialsAndCommandLine();
+TEST_F(NetworkSessionConfiguratorTest,
+ LargeQuicReducedPingTimeoutSecondsFieldTrialParams) {
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["reduced_ping_timeout_seconds"] = "50";
+ variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
+ ParseFieldTrials();
+ EXPECT_EQ(net::kPingTimeoutSecs, params_.quic_reduced_ping_timeout_seconds);
+}
- EXPECT_TRUE(params_.enable_quic);
- EXPECT_TRUE(params_.enable_quic_alternative_service_with_different_host);
+TEST_F(NetworkSessionConfiguratorTest,
+ QuicReducedPingTimeoutSecondsFieldTrialParams) {
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["reduced_ping_timeout_seconds"] = "10";
+ variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
+ ParseFieldTrials();
+ EXPECT_EQ(10, params_.quic_reduced_ping_timeout_seconds);
}
-TEST_F(NetworkSessionConfiguratorTest, PacketLengthFromCommandLine) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch("enable-quic");
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- "quic-max-packet-length", "1450");
+TEST_F(NetworkSessionConfiguratorTest,
+ QuicPacketReaderYieldAfterDurationMillisecondsFieldTrialParams) {
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["packet_reader_yield_after_duration_milliseconds"] = "10";
+ variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
- ParseFieldTrialsAndCommandLine();
+ ParseFieldTrials();
- EXPECT_EQ(1450u, params_.quic_max_packet_length);
+ EXPECT_EQ(10, params_.quic_packet_reader_yield_after_duration_milliseconds);
}
-TEST_F(NetworkSessionConfiguratorTest,
- QuicCloseSessionsOnIpChangeFromFieldTrialParams) {
+TEST_F(NetworkSessionConfiguratorTest, QuicRaceCertVerification) {
std::map<std::string, std::string> field_trial_params;
- field_trial_params["close_sessions_on_ip_change"] = "true";
+ field_trial_params["race_cert_verification"] = "true";
variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
ParseFieldTrials();
- EXPECT_TRUE(params_.quic_close_sessions_on_ip_change);
+ EXPECT_TRUE(params_.quic_race_cert_verification);
}
-TEST_F(NetworkSessionConfiguratorTest,
- QuicIdleConnectionTimeoutSecondsFieldTrialParams) {
+TEST_F(NetworkSessionConfiguratorTest, QuicDoNotFragment) {
std::map<std::string, std::string> field_trial_params;
- field_trial_params["idle_connection_timeout_seconds"] = "300";
+ field_trial_params["do_not_fragment"] = "true";
variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
ParseFieldTrials();
- EXPECT_EQ(300, params_.quic_idle_connection_timeout_seconds);
+ EXPECT_TRUE(params_.quic_do_not_fragment);
}
TEST_F(NetworkSessionConfiguratorTest, QuicDisablePreConnectIfZeroRtt) {
@@ -343,59 +242,43 @@ TEST_F(NetworkSessionConfiguratorTest,
EXPECT_TRUE(params_.quic_migrate_sessions_early);
}
-TEST_F(NetworkSessionConfiguratorTest, PacketLengthFromFieldTrialParams) {
+TEST_F(NetworkSessionConfiguratorTest,
+ QuicAllowServerMigrationFromFieldTrialParams) {
std::map<std::string, std::string> field_trial_params;
- field_trial_params["max_packet_length"] = "1450";
+ field_trial_params["allow_server_migration"] = "true";
variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
ParseFieldTrials();
- EXPECT_EQ(1450u, params_.quic_max_packet_length);
+ EXPECT_TRUE(params_.quic_allow_server_migration);
}
-TEST_F(NetworkSessionConfiguratorTest, QuicVersionFromCommandLine) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch("enable-quic");
- std::string version =
- net::QuicVersionToString(net::QuicSupportedVersions().back());
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII("quic-version",
- version);
+TEST_F(NetworkSessionConfiguratorTest, PacketLengthFromFieldTrialParams) {
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["max_packet_length"] = "1450";
+ variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
- ParseFieldTrialsAndCommandLine();
+ ParseFieldTrials();
- net::QuicVersionVector supported_versions;
- supported_versions.push_back(net::QuicSupportedVersions().back());
- EXPECT_EQ(supported_versions, params_.quic_supported_versions);
+ EXPECT_EQ(1450u, params_.quic_max_packet_length);
}
TEST_F(NetworkSessionConfiguratorTest, QuicVersionFromFieldTrialParams) {
std::map<std::string, std::string> field_trial_params;
field_trial_params["quic_version"] =
- net::QuicVersionToString(net::QuicSupportedVersions().back());
+ net::QuicVersionToString(net::AllSupportedVersions().back());
variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
ParseFieldTrials();
net::QuicVersionVector supported_versions;
- supported_versions.push_back(net::QuicSupportedVersions().back());
+ supported_versions.push_back(net::AllSupportedVersions().back());
EXPECT_EQ(supported_versions, params_.quic_supported_versions);
}
-TEST_F(NetworkSessionConfiguratorTest, QuicConnectionOptionsFromCommandLine) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch("enable-quic");
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- "quic-connection-options", "TIME,TBBR,REJ");
-
- ParseFieldTrialsAndCommandLine();
-
- net::QuicTagVector options;
- options.push_back(net::kTIME);
- options.push_back(net::kTBBR);
- options.push_back(net::kREJ);
- EXPECT_EQ(options, params_.quic_connection_options);
-}
-
TEST_F(NetworkSessionConfiguratorTest,
QuicConnectionOptionsFromFieldTrialParams) {
std::map<std::string, std::string> field_trial_params;
@@ -504,30 +387,6 @@ TEST_F(NetworkSessionConfiguratorTest,
EXPECT_TRUE(params_.enable_quic_alternative_service_with_different_host);
}
-TEST_F(NetworkSessionConfiguratorTest,
- QuicMaxNumberOfLossyConnectionsFieldTrialParams) {
- std::map<std::string, std::string> field_trial_params;
- field_trial_params["max_number_of_lossy_connections"] = "5";
- variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
- base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
-
- ParseFieldTrials();
-
- EXPECT_EQ(5, params_.quic_max_number_of_lossy_connections);
-}
-
-TEST_F(NetworkSessionConfiguratorTest,
- QuicPacketLossThresholdFieldTrialParams) {
- std::map<std::string, std::string> field_trial_params;
- field_trial_params["packet_loss_threshold"] = "0.5";
- variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
- base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
-
- ParseFieldTrials();
-
- EXPECT_EQ(0.5f, params_.quic_packet_loss_threshold);
-}
-
TEST_F(NetworkSessionConfiguratorTest, QuicReceiveBufferSize) {
std::map<std::string, std::string> field_trial_params;
field_trial_params["receive_buffer_size"] = "2097152";
@@ -550,34 +409,6 @@ TEST_F(NetworkSessionConfiguratorTest, QuicDisableDelayTcpRace) {
EXPECT_FALSE(params_.quic_delay_tcp_race);
}
-TEST_F(NetworkSessionConfiguratorTest, QuicOriginsToForceQuicOn) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch("enable-quic");
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- "origin-to-force-quic-on", "www.example.com:443, www.example.org:443");
-
- ParseFieldTrialsAndCommandLine();
-
- EXPECT_EQ(2u, params_.origins_to_force_quic_on.size());
- EXPECT_TRUE(
- ContainsKey(params_.origins_to_force_quic_on,
- net::HostPortPair::FromString("www.example.com:443")));
- EXPECT_TRUE(
- ContainsKey(params_.origins_to_force_quic_on,
- net::HostPortPair::FromString("www.example.org:443")));
-}
-
-TEST_F(NetworkSessionConfiguratorTest, QuicWhitelistFromCommandLinet) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch("enable-quic");
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- "quic-host-whitelist", "www.example.org, www.example.com");
-
- ParseFieldTrialsAndCommandLine();
-
- EXPECT_EQ(2u, params_.quic_host_whitelist.size());
- EXPECT_TRUE(ContainsKey(params_.quic_host_whitelist, "www.example.org"));
- EXPECT_TRUE(ContainsKey(params_.quic_host_whitelist, "www.example.com"));
-}
-
TEST_F(NetworkSessionConfiguratorTest, QuicWhitelistFromParams) {
std::map<std::string, std::string> field_trial_params;
field_trial_params["quic_host_whitelist"] =
@@ -588,25 +419,29 @@ TEST_F(NetworkSessionConfiguratorTest, QuicWhitelistFromParams) {
ParseFieldTrials();
EXPECT_EQ(2u, params_.quic_host_whitelist.size());
- EXPECT_TRUE(ContainsKey(params_.quic_host_whitelist, "www.example.org"));
- EXPECT_TRUE(ContainsKey(params_.quic_host_whitelist, "www.example.com"));
+ EXPECT_TRUE(
+ base::ContainsKey(params_.quic_host_whitelist, "www.example.org"));
+ EXPECT_TRUE(
+ base::ContainsKey(params_.quic_host_whitelist, "www.example.com"));
}
-TEST_F(NetworkSessionConfiguratorTest, QuicDisallowedByPolicy) {
- base::CommandLine::ForCurrentProcess()->AppendSwitch("enable-quic");
- is_quic_allowed_by_policy_ = false;
+TEST_F(NetworkSessionConfiguratorTest, TCPFastOpenHttpsEnabled) {
+ base::FieldTrialList::CreateFieldTrial("TCPFastOpen", "HttpsEnabled");
- ParseFieldTrialsAndCommandLine();
+ ParseFieldTrials();
- EXPECT_FALSE(params_.enable_quic);
+ EXPECT_TRUE(params_.enable_tcp_fast_open_for_ssl);
}
-TEST_F(NetworkSessionConfiguratorTest, TCPFastOpenHttpsEnabled) {
- base::FieldTrialList::CreateFieldTrial("TCPFastOpen", "HttpsEnabled");
+TEST_F(NetworkSessionConfiguratorTest, QuicForceHolBlocking) {
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["force_hol_blocking"] = "true";
+ variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
ParseFieldTrials();
- EXPECT_TRUE(params_.enable_tcp_fast_open_for_ssl);
+ EXPECT_TRUE(params_.quic_force_hol_blocking);
}
} // namespace test
diff --git a/chromium/components/network_session_configurator/switches.cc b/chromium/components/network_session_configurator/switches.cc
deleted file mode 100644
index b82f15b69a1..00000000000
--- a/chromium/components/network_session_configurator/switches.cc
+++ /dev/null
@@ -1,55 +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 "components/network_session_configurator/switches.h"
-
-namespace switches {
-
-// Disables the HTTP/2 and SPDY/3.1 protocols.
-const char kDisableHttp2[] = "disable-http2";
-
-// Disables the QUIC protocol.
-const char kDisableQuic[] = "disable-quic";
-
-// Disable use of Chromium's port selection for the ephemeral port via bind().
-// This only has an effect if QUIC protocol is enabled.
-const char kDisableQuicPortSelection[] = "disable-quic-port-selection";
-
-// Enables the QUIC protocol. This is a temporary testing flag.
-const char kEnableQuic[] = "enable-quic";
-
-// Enable use of Chromium's port selection for the ephemeral port via bind().
-// This only has an effect if the QUIC protocol is enabled.
-const char kEnableQuicPortSelection[] = "enable-quic-port-selection";
-
-// Ignores certificate-related errors.
-const char kIgnoreCertificateErrors[] = "ignore-certificate-errors";
-
-// Causes net::URLFetchers to ignore requests for SSL client certificates,
-// causing them to attempt an unauthenticated SSL/TLS session. This is intended
-// for use when testing various service URLs (eg: kPromoServerURL, kSbURLPrefix,
-// kSyncServiceURL, etc)
-const char kIgnoreUrlFetcherCertRequests[] = "ignore-urlfetcher-cert-requests";
-
-// Specifies a comma separated list of host-port pairs to force use of QUIC on.
-const char kOriginToForceQuicOn[] = "origin-to-force-quic-on";
-
-// Specifies a comma separated list of QUIC connection options to send to
-// the server.
-const char kQuicConnectionOptions[] = "quic-connection-options";
-
-// Specifies a comma separated list of hosts to whitelist QUIC for.
-const char kQuicHostWhitelist[] = "quic-host-whitelist";
-
-// Specifies the maximum length for a QUIC packet.
-const char kQuicMaxPacketLength[] = "quic-max-packet-length";
-
-// Specifies the version of QUIC to use.
-const char kQuicVersion[] = "quic-version";
-
-// Allows for forcing socket connections to http/https to use fixed ports.
-const char kTestingFixedHttpPort[] = "testing-fixed-http-port";
-const char kTestingFixedHttpsPort[] = "testing-fixed-https-port";
-
-} // namespace switches
diff --git a/chromium/components/network_session_configurator/switches.h b/chromium/components/network_session_configurator/switches.h
deleted file mode 100644
index 4fda0375fa6..00000000000
--- a/chromium/components/network_session_configurator/switches.h
+++ /dev/null
@@ -1,27 +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 COMPONENTS_NETWORK_SESSION_CONFIGURATOR_SWITCHES_H_
-#define COMPONENTS_NETWORK_SESSION_CONFIGURATOR_SWITCHES_H_
-
-namespace switches {
-
-extern const char kDisableHttp2[];
-extern const char kDisableQuicPortSelection[];
-extern const char kDisableQuic[];
-extern const char kEnableQuicPortSelection[];
-extern const char kEnableQuic[];
-extern const char kIgnoreCertificateErrors[];
-extern const char kIgnoreUrlFetcherCertRequests[];
-extern const char kOriginToForceQuicOn[];
-extern const char kQuicConnectionOptions[];
-extern const char kQuicHostWhitelist[];
-extern const char kQuicMaxPacketLength[];
-extern const char kQuicVersion[];
-extern const char kTestingFixedHttpPort[];
-extern const char kTestingFixedHttpsPort[];
-
-} // namespace switches
-
-#endif // COMPONENTS_NETWORK_SESSION_CONFIGURATOR_SWITCHES_H_
diff --git a/chromium/components/network_time.gypi b/chromium/components/network_time.gypi
deleted file mode 100644
index 8458771908a..00000000000
--- a/chromium/components/network_time.gypi
+++ /dev/null
@@ -1,28 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/network_time
- 'target_name': 'network_time',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- 'client_update_protocol'
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'network_time/network_time_pref_names.cc',
- 'network_time/network_time_pref_names.h',
- 'network_time/network_time_tracker.cc',
- 'network_time/network_time_tracker.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/network_time/OWNERS b/chromium/components/network_time/OWNERS
index abb98daf3bc..03d8b24b753 100644
--- a/chromium/components/network_time/OWNERS
+++ b/chromium/components/network_time/OWNERS
@@ -1,2 +1,2 @@
zea@chromium.org
-
+estark@chromium.org
diff --git a/chromium/components/network_time/network_time_tracker.cc b/chromium/components/network_time/network_time_tracker.cc
index dc4ccbb56d3..71223e0e7a7 100644
--- a/chromium/components/network_time/network_time_tracker.cc
+++ b/chromium/components/network_time/network_time_tracker.cc
@@ -8,11 +8,11 @@
#include <string>
#include <utility>
-#include "base/feature_list.h"
#include "base/i18n/time_formatting.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
@@ -33,6 +33,9 @@
namespace network_time {
+const base::Feature kNetworkTimeServiceQuerying{
+ "NetworkTimeServiceQuerying", base::FEATURE_DISABLED_BY_DEFAULT};
+
namespace {
// Time updates happen in two ways. First, other components may call
@@ -93,10 +96,6 @@ const uint32_t kTimeServerMaxSkewSeconds = 10;
const char kTimeServiceURL[] = "http://clients2.google.com/time/1/current";
-// Variations Service feature that enables network time service querying.
-const base::Feature kNetworkTimeServiceQuerying{
- "NetworkTimeServiceQuerying", base::FEATURE_DISABLED_BY_DEFAULT};
-
const char kVariationsServiceCheckTimeIntervalSeconds[] =
"CheckTimeIntervalSeconds";
const char kVariationsServiceRandomQueryProbability[] =
@@ -166,6 +165,10 @@ double RandomQueryProbability() {
return kRandomQueryProbability;
}
+void RecordFetchValidHistogram(bool valid) {
+ UMA_HISTOGRAM_BOOLEAN("NetworkTimeTracker.UpdateTimeFetchValid", valid);
+}
+
} // namespace
// static
@@ -183,7 +186,6 @@ NetworkTimeTracker::NetworkTimeTracker(
max_response_size_(1024),
backoff_(base::TimeDelta::FromMinutes(kBackoffMinutes)),
getter_(std::move(getter)),
- loop_(nullptr),
clock_(std::move(clock)),
tick_clock_(std::move(tick_clock)),
pref_service_(pref_service) {
@@ -286,13 +288,15 @@ void NetworkTimeTracker::SetPublicKeyForTesting(const base::StringPiece& key) {
bool NetworkTimeTracker::QueryTimeServiceForTesting() {
CheckTime();
- loop_ = base::MessageLoop::current(); // Gets Quit on completion.
return time_fetcher_ != nullptr;
}
void NetworkTimeTracker::WaitForFetchForTesting(uint32_t nonce) {
query_signer_->OverrideNonceForTesting(kKeyVersion, nonce);
- base::RunLoop().Run();
+ base::RunLoop run_loop;
+ run_loop_for_testing_ = &run_loop;
+ run_loop.Run();
+ run_loop_for_testing_ = nullptr;
}
base::TimeDelta NetworkTimeTracker::GetTimerDelayForTesting() const {
@@ -300,12 +304,13 @@ base::TimeDelta NetworkTimeTracker::GetTimerDelayForTesting() const {
return timer_.GetCurrentDelay();
}
-bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time,
- base::TimeDelta* uncertainty) const {
+NetworkTimeTracker::NetworkTimeResult NetworkTimeTracker::GetNetworkTime(
+ base::Time* network_time,
+ base::TimeDelta* uncertainty) const {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(network_time);
if (network_time_at_last_measurement_.is_null()) {
- return false;
+ return NETWORK_TIME_NO_SYNC;
}
DCHECK(!ticks_at_last_measurement_.is_null());
DCHECK(!time_at_last_measurement_.is_null());
@@ -314,23 +319,41 @@ bool NetworkTimeTracker::GetNetworkTime(base::Time* network_time,
base::TimeDelta time_delta = clock_->Now() - time_at_last_measurement_;
if (time_delta.InMilliseconds() < 0) { // Has wall clock run backward?
DVLOG(1) << "Discarding network time due to wall clock running backward";
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NetworkTimeTracker.WallClockRanBackwards", time_delta.magnitude(),
+ base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(7), 50);
network_time_at_last_measurement_ = base::Time();
- return false;
+ return NETWORK_TIME_SYNC_LOST;
}
// Now we know that both |tick_delta| and |time_delta| are positive.
- base::TimeDelta divergence = (tick_delta - time_delta).magnitude();
- if (divergence > base::TimeDelta::FromSeconds(kClockDivergenceSeconds)) {
+ base::TimeDelta divergence = tick_delta - time_delta;
+ if (divergence.magnitude() >
+ base::TimeDelta::FromSeconds(kClockDivergenceSeconds)) {
// Most likely either the machine has suspended, or the wall clock has been
// reset.
DVLOG(1) << "Discarding network time due to clocks diverging";
+
+ // The below histograms do not use |kClockDivergenceSeconds| as the
+ // lower-bound, so that |kClockDivergenceSeconds| can be changed
+ // without causing the buckets to change and making data from
+ // old/new clients incompatible.
+ if (divergence.InMilliseconds() < 0) {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NetworkTimeTracker.ClockDivergence.Negative", divergence.magnitude(),
+ base::TimeDelta::FromSeconds(60), base::TimeDelta::FromDays(7), 50);
+ } else {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "NetworkTimeTracker.ClockDivergence.Positive", divergence.magnitude(),
+ base::TimeDelta::FromSeconds(60), base::TimeDelta::FromDays(7), 50);
+ }
network_time_at_last_measurement_ = base::Time();
- return false;
+ return NETWORK_TIME_SYNC_LOST;
}
*network_time = network_time_at_last_measurement_ + tick_delta;
if (uncertainty) {
*uncertainty = network_time_uncertainty_ + divergence;
}
- return true;
+ return NETWORK_TIME_AVAILABLE;
}
void NetworkTimeTracker::CheckTime() {
@@ -367,6 +390,7 @@ void NetworkTimeTracker::CheckTime() {
net::LOAD_DO_NOT_SAVE_COOKIES |
net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SEND_AUTH_DATA);
+
time_fetcher_->Start();
fetch_started_ = tick_clock_->NowTicks();
@@ -374,10 +398,14 @@ void NetworkTimeTracker::CheckTime() {
}
bool NetworkTimeTracker::UpdateTimeFromResponse() {
- if (time_fetcher_->GetStatus().status() != net::URLRequestStatus::SUCCESS &&
+ if (time_fetcher_->GetStatus().status() != net::URLRequestStatus::SUCCESS ||
time_fetcher_->GetResponseCode() != 200) {
DVLOG(1) << "fetch failed, status=" << time_fetcher_->GetStatus().status()
<< ",code=" << time_fetcher_->GetResponseCode();
+ // The error code is negated because net errors are negative, but
+ // the corresponding histogram enum is positive.
+ UMA_HISTOGRAM_SPARSE_SLOWLY("NetworkTimeTracker.UpdateTimeFetchFailed",
+ -time_fetcher_->GetStatus().error());
return false;
}
@@ -390,24 +418,31 @@ bool NetworkTimeTracker::UpdateTimeFromResponse() {
if (!query_signer_->ValidateResponse(response_body,
GetServerProof(time_fetcher_.get()))) {
DVLOG(1) << "invalid signature";
+ RecordFetchValidHistogram(false);
return false;
}
response_body = response_body.substr(5); // Skips leading )]}'\n
std::unique_ptr<base::Value> value = base::JSONReader::Read(response_body);
if (!value) {
DVLOG(1) << "bad JSON";
+ RecordFetchValidHistogram(false);
return false;
}
const base::DictionaryValue* dict;
if (!value->GetAsDictionary(&dict)) {
DVLOG(1) << "not a dictionary";
+ RecordFetchValidHistogram(false);
return false;
}
double current_time_millis;
if (!dict->GetDouble("current_time_millis", &current_time_millis)) {
DVLOG(1) << "no current_time_millis";
+ RecordFetchValidHistogram(false);
return false;
}
+
+ RecordFetchValidHistogram(true);
+
// There is a "server_nonce" key here too, but it serves no purpose other than
// to make the server's response unpredictable.
base::Time current_time = base::Time::FromJsTime(current_time_millis);
@@ -435,10 +470,8 @@ void NetworkTimeTracker::OnURLFetchComplete(const net::URLFetcher* source) {
}
QueueCheckTime(backoff_);
time_fetcher_.reset();
- if (loop_ != nullptr) {
- loop_->QuitWhenIdle();
- loop_ = nullptr;
- }
+ if (run_loop_for_testing_ != nullptr)
+ run_loop_for_testing_->QuitWhenIdle();
}
void NetworkTimeTracker::QueueCheckTime(base::TimeDelta delay) {
@@ -451,10 +484,10 @@ bool NetworkTimeTracker::ShouldIssueTimeQuery() {
return false;
}
- // If GetNetworkTime() returns false, synchronization has been lost
- // and a query is needed.
+ // If GetNetworkTime() does not return NETWORK_TIME_AVAILABLE,
+ // synchronization has been lost and a query is needed.
base::Time network_time;
- if (!GetNetworkTime(&network_time, nullptr)) {
+ if (GetNetworkTime(&network_time, nullptr) != NETWORK_TIME_AVAILABLE) {
return true;
}
diff --git a/chromium/components/network_time/network_time_tracker.h b/chromium/components/network_time/network_time_tracker.h
index 07869e3f271..ae1f2682072 100644
--- a/chromium/components/network_time/network_time_tracker.h
+++ b/chromium/components/network_time/network_time_tracker.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <memory>
+#include "base/feature_list.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -22,7 +23,7 @@ class PrefRegistrySimple;
class PrefService;
namespace base {
-class MessageLoop;
+class RunLoop;
class TickClock;
} // namespace base
@@ -44,10 +45,27 @@ const int64_t kTicksResolutionMs = base::Time::kMinLowResolutionThresholdMs;
const int64_t kTicksResolutionMs = 1; // Assume 1ms for non-windows platforms.
#endif
+// Variations Service feature that enables network time service querying.
+extern const base::Feature kNetworkTimeServiceQuerying;
+
// A class that receives network time updates and can provide the network time
// for a corresponding local time. This class is not thread safe.
class NetworkTimeTracker : public net::URLFetcherDelegate {
public:
+ // Describes the result of a GetNetworkTime() call, describing whether
+ // network time was available and if not, why not.
+ enum NetworkTimeResult {
+ // Network time is available.
+ NETWORK_TIME_AVAILABLE,
+ // A time has been retrieved from the network in the past, but
+ // network time is no longer available because the tracker fell out
+ // of sync due to, for example, a suspend/resume.
+ NETWORK_TIME_SYNC_LOST,
+ // Network time is unavailable because the tracker has not yet
+ // retrieved a time from the network.
+ NETWORK_TIME_NO_SYNC,
+ };
+
static void RegisterPrefs(PrefRegistrySimple* registry);
// Constructor. Arguments may be stubbed out for tests. |getter|, if not
@@ -59,9 +77,13 @@ class NetworkTimeTracker : public net::URLFetcherDelegate {
scoped_refptr<net::URLRequestContextGetter> getter);
~NetworkTimeTracker() override;
- // Sets |network_time| to an estimate of the true time. Returns true if time
- // is available, and false otherwise. If |uncertainty| is non-NULL, it will
- // be set to an estimate of the error range.
+ // Sets |network_time| to an estimate of the true time. Returns
+ // NETWORK_TIME_AVAILABLE if time is available. If |uncertainty| is
+ // non-NULL, it will be set to an estimate of the error range.
+ //
+ // If network time is unavailable, this method returns
+ // NETWORK_TIME_SYNC_LOST or NETWORK_TIME_NO_SYNC to indicate the
+ // reason.
//
// Network time may be available on startup if deserialized from a pref.
// Failing that, a call to |UpdateNetworkTime| is required to make time
@@ -69,8 +91,8 @@ class NetworkTimeTracker : public net::URLFetcherDelegate {
// become unavailable if |NetworkTimeTracker| has reason to believe it is no
// longer accurate. Consumers should even be prepared to handle the case
// where calls to |GetNetworkTime| never once succeeds.
- bool GetNetworkTime(base::Time* network_time,
- base::TimeDelta* uncertainty) const;
+ NetworkTimeResult GetNetworkTime(base::Time* network_time,
+ base::TimeDelta* uncertainty) const;
// Calculates corresponding time ticks according to the given parameters.
// The provided |network_time| is precise at the given |resolution| and
@@ -126,7 +148,9 @@ class NetworkTimeTracker : public net::URLFetcherDelegate {
std::unique_ptr<net::URLFetcher> time_fetcher_;
base::TimeTicks fetch_started_;
std::unique_ptr<client_update_protocol::Ecdsa> query_signer_;
- base::MessageLoop* loop_; // For testing; quit on fetch complete.
+
+ // Run by WaitForFetchForTesting() and quit by OnURLFetchComplete().
+ base::RunLoop* run_loop_for_testing_ = nullptr;
// The |Clock| and |TickClock| are used to sanity-check one another, allowing
// the NetworkTimeTracker to notice e.g. suspend/resume events and clock
diff --git a/chromium/components/network_time/network_time_tracker_unittest.cc b/chromium/components/network_time/network_time_tracker_unittest.cc
index d4d5c939177..401839a06f9 100644
--- a/chromium/components/network_time/network_time_tracker_unittest.cc
+++ b/chromium/components/network_time/network_time_tracker_unittest.cc
@@ -11,10 +11,13 @@
#include "base/compiler_specific.h"
#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
+#include "base/test/histogram_tester.h"
#include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/test/simple_test_tick_clock.h"
#include "components/client_update_protocol/ecdsa.h"
@@ -30,6 +33,18 @@
namespace network_time {
+namespace {
+const uint32_t kOneDayInSeconds = 86400;
+const char kFetchFailedHistogram[] = "NetworkTimeTracker.UpdateTimeFetchFailed";
+const char kFetchValidHistogram[] = "NetworkTimeTracker.UpdateTimeFetchValid";
+const char kClockDivergencePositiveHistogram[] =
+ "NetworkTimeTracker.ClockDivergence.Positive";
+const char kClockDivergenceNegativeHistogram[] =
+ "NetworkTimeTracker.ClockDivergence.Negative";
+const char kWallClockBackwardsHistogram[] =
+ "NetworkTimeTracker.WallClockRanBackwards";
+} // namespace
+
class NetworkTimeTrackerTest : public testing::Test {
public:
~NetworkTimeTrackerTest() override {}
@@ -173,7 +188,6 @@ class NetworkTimeTrackerTest : public testing::Test {
base::FEATURE_DISABLED_BY_DEFAULT};
// Clear all the things.
- base::FeatureList::ClearInstanceForTesting();
variations::testing::ClearAllVariationParams();
std::map<std::string, std::string> params;
@@ -184,13 +198,15 @@ class NetworkTimeTrackerTest : public testing::Test {
// FeatureList. Don't get confused! The FieldTrial is reference-counted,
// and a reference is held by the FieldTrialList. The FieldTrialList and
// FeatureList are both singletons. The authorized way to reset the former
- // for testing is to destruct it (above). The latter, by contrast, is reset
- // with |ClearInstanceForTesting|, above. If this comment was useful to you
+ // for testing is to destruct it (above). The latter, by contrast, should
+ // should already start in a clean state and can be manipulated via the
+ // ScopedFeatureList helper class. If this comment was useful to you
// please send me a postcard.
field_trial_list_.reset(); // Averts a CHECK fail in constructor below.
field_trial_list_.reset(
- new base::FieldTrialList(new base::MockEntropyProvider()));
+ new base::FieldTrialList(
+ base::MakeUnique<base::MockEntropyProvider>()));
// refcounted, and reference held by field_trial_list_.
base::FieldTrial* trial = base::FieldTrialList::FactoryGetFieldTrial(
kTrialName, 100, kGroupName, 1971, 1, 1,
@@ -204,7 +220,8 @@ class NetworkTimeTrackerTest : public testing::Test {
kFeature.name, enable ? base::FeatureList::OVERRIDE_ENABLE_FEATURE
: base::FeatureList::OVERRIDE_DISABLE_FEATURE,
trial);
- base::FeatureList::SetInstance(std::move(feature_list));
+ scoped_feature_list_.reset(new base::test::ScopedFeatureList);
+ scoped_feature_list_->InitWithFeatureList(std::move(feature_list));
}
base::Thread io_thread_;
@@ -218,12 +235,14 @@ class NetworkTimeTrackerTest : public testing::Test {
std::unique_ptr<base::FieldTrialList> field_trial_list_;
std::unique_ptr<NetworkTimeTracker> tracker_;
std::unique_ptr<net::EmbeddedTestServer> test_server_;
+ std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
};
TEST_F(NetworkTimeTrackerTest, Uninitialized) {
base::Time network_time;
base::TimeDelta uncertainty;
- EXPECT_FALSE(tracker_->GetNetworkTime(&network_time, &uncertainty));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_NO_SYNC,
+ tracker_->GetNetworkTime(&network_time, &uncertainty));
}
TEST_F(NetworkTimeTrackerTest, LongPostingDelay) {
@@ -244,7 +263,8 @@ TEST_F(NetworkTimeTrackerTest, LongPostingDelay) {
base::Time out_network_time;
base::TimeDelta uncertainty;
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, &uncertainty));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, &uncertainty));
EXPECT_EQ(resolution_ + latency_ + adjustment_, uncertainty);
EXPECT_EQ(clock_->Now(), out_network_time);
}
@@ -261,7 +281,8 @@ TEST_F(NetworkTimeTrackerTest, LopsidedLatency) {
// But, the answer is still within the uncertainty bounds!
base::Time out_network_time;
base::TimeDelta uncertainty;
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, &uncertainty));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, &uncertainty));
EXPECT_LT(out_network_time - uncertainty / 2, clock_->Now());
EXPECT_GT(out_network_time + uncertainty / 2, clock_->Now());
}
@@ -273,12 +294,17 @@ TEST_F(NetworkTimeTrackerTest, ClockIsWack) {
tick_clock_->NowTicks());
base::Time out_network_time;
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
EXPECT_EQ(in_network_time, out_network_time);
}
TEST_F(NetworkTimeTrackerTest, ClocksDivergeSlightly) {
// The two clocks are allowed to diverge a little bit.
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kClockDivergencePositiveHistogram, 0);
+ histograms.ExpectTotalCount(kClockDivergenceNegativeHistogram, 0);
+ histograms.ExpectTotalCount(kWallClockBackwardsHistogram, 0);
base::Time in_network_time = clock_->Now();
UpdateNetworkTime(in_network_time - latency_ / 2, resolution_, latency_,
tick_clock_->NowTicks());
@@ -287,10 +313,14 @@ TEST_F(NetworkTimeTrackerTest, ClocksDivergeSlightly) {
tick_clock_->Advance(small);
base::Time out_network_time;
base::TimeDelta out_uncertainty;
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, &out_uncertainty));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, &out_uncertainty));
EXPECT_EQ(in_network_time + small, out_network_time);
// The clock divergence should show up in the uncertainty.
EXPECT_EQ(resolution_ + latency_ + adjustment_ + small, out_uncertainty);
+ histograms.ExpectTotalCount(kClockDivergencePositiveHistogram, 0);
+ histograms.ExpectTotalCount(kClockDivergenceNegativeHistogram, 0);
+ histograms.ExpectTotalCount(kWallClockBackwardsHistogram, 0);
}
TEST_F(NetworkTimeTrackerTest, NetworkTimeUpdates) {
@@ -301,13 +331,15 @@ TEST_F(NetworkTimeTrackerTest, NetworkTimeUpdates) {
UpdateNetworkTime(clock_->Now() - latency_ / 2, resolution_, latency_,
tick_clock_->NowTicks());
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, &uncertainty));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, &uncertainty));
EXPECT_EQ(clock_->Now(), out_network_time);
EXPECT_EQ(resolution_ + latency_ + adjustment_, uncertainty);
// Fake a wait to make sure we keep tracking.
AdvanceBoth(base::TimeDelta::FromSeconds(1));
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, &uncertainty));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, &uncertainty));
EXPECT_EQ(clock_->Now(), out_network_time);
EXPECT_EQ(resolution_ + latency_ + adjustment_, uncertainty);
@@ -315,29 +347,75 @@ TEST_F(NetworkTimeTrackerTest, NetworkTimeUpdates) {
UpdateNetworkTime(clock_->Now() - latency_ / 2, resolution_, latency_,
tick_clock_->NowTicks());
AdvanceBoth(base::TimeDelta::FromSeconds(1));
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, &uncertainty));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, &uncertainty));
EXPECT_EQ(clock_->Now(), out_network_time);
EXPECT_EQ(resolution_ + latency_ + adjustment_, uncertainty);
}
TEST_F(NetworkTimeTrackerTest, SpringForward) {
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kClockDivergencePositiveHistogram, 0);
+ histograms.ExpectTotalCount(kClockDivergenceNegativeHistogram, 0);
+ histograms.ExpectTotalCount(kWallClockBackwardsHistogram, 0);
// Simulate the wall clock advancing faster than the tick clock.
UpdateNetworkTime(clock_->Now(), resolution_, latency_,
tick_clock_->NowTicks());
tick_clock_->Advance(base::TimeDelta::FromSeconds(1));
clock_->Advance(base::TimeDelta::FromDays(1));
base::Time out_network_time;
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_SYNC_LOST,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
+ histograms.ExpectTotalCount(kClockDivergencePositiveHistogram, 0);
+ histograms.ExpectTotalCount(kClockDivergenceNegativeHistogram, 1);
+ histograms.ExpectTotalCount(kWallClockBackwardsHistogram, 0);
+ // The recorded clock divergence should be 1 second - 1 day in seconds.
+ histograms.ExpectBucketCount(
+ kClockDivergenceNegativeHistogram,
+ base::TimeDelta::FromSeconds(kOneDayInSeconds - 1).InMilliseconds(), 1);
+}
+
+TEST_F(NetworkTimeTrackerTest, TickClockSpringsForward) {
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kClockDivergencePositiveHistogram, 0);
+ histograms.ExpectTotalCount(kClockDivergenceNegativeHistogram, 0);
+ histograms.ExpectTotalCount(kWallClockBackwardsHistogram, 0);
+ // Simulate the tick clock advancing faster than the wall clock.
+ UpdateNetworkTime(clock_->Now(), resolution_, latency_,
+ tick_clock_->NowTicks());
+ tick_clock_->Advance(base::TimeDelta::FromDays(1));
+ clock_->Advance(base::TimeDelta::FromSeconds(1));
+ base::Time out_network_time;
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_SYNC_LOST,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
+ histograms.ExpectTotalCount(kClockDivergencePositiveHistogram, 1);
+ histograms.ExpectTotalCount(kClockDivergenceNegativeHistogram, 0);
+ histograms.ExpectTotalCount(kWallClockBackwardsHistogram, 0);
+ // The recorded clock divergence should be 1 day - 1 second.
+ histograms.ExpectBucketCount(
+ kClockDivergencePositiveHistogram,
+ base::TimeDelta::FromSeconds(kOneDayInSeconds - 1).InMilliseconds(), 1);
}
TEST_F(NetworkTimeTrackerTest, FallBack) {
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kClockDivergencePositiveHistogram, 0);
+ histograms.ExpectTotalCount(kClockDivergenceNegativeHistogram, 0);
+ histograms.ExpectTotalCount(kWallClockBackwardsHistogram, 0);
// Simulate the wall clock running backward.
UpdateNetworkTime(clock_->Now(), resolution_, latency_,
tick_clock_->NowTicks());
tick_clock_->Advance(base::TimeDelta::FromSeconds(1));
clock_->Advance(base::TimeDelta::FromDays(-1));
base::Time out_network_time;
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_SYNC_LOST,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
+ histograms.ExpectTotalCount(kClockDivergencePositiveHistogram, 0);
+ histograms.ExpectTotalCount(kClockDivergenceNegativeHistogram, 0);
+ histograms.ExpectTotalCount(kWallClockBackwardsHistogram, 1);
+ histograms.ExpectBucketCount(
+ kWallClockBackwardsHistogram,
+ base::TimeDelta::FromSeconds(kOneDayInSeconds - 1).InMilliseconds(), 1);
}
TEST_F(NetworkTimeTrackerTest, SuspendAndResume) {
@@ -347,7 +425,8 @@ TEST_F(NetworkTimeTrackerTest, SuspendAndResume) {
tick_clock_->NowTicks());
clock_->Advance(base::TimeDelta::FromHours(1));
base::Time out_network_time;
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_SYNC_LOST,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
}
TEST_F(NetworkTimeTrackerTest, Serialize) {
@@ -358,7 +437,8 @@ TEST_F(NetworkTimeTrackerTest, Serialize) {
tick_clock_->NowTicks());
base::Time out_network_time;
base::TimeDelta out_uncertainty;
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, &out_uncertainty));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, &out_uncertainty));
EXPECT_EQ(in_network_time, out_network_time);
EXPECT_EQ(resolution_ + latency_ + adjustment_, out_uncertainty);
@@ -366,7 +446,8 @@ TEST_F(NetworkTimeTrackerTest, Serialize) {
base::TimeDelta delta = base::TimeDelta::FromDays(6);
AdvanceBoth(delta);
Reset();
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, &out_uncertainty));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, &out_uncertainty));
EXPECT_EQ(in_network_time + delta, out_network_time);
EXPECT_EQ(resolution_ + latency_ + adjustment_, out_uncertainty);
}
@@ -379,7 +460,8 @@ TEST_F(NetworkTimeTrackerTest, DeserializeOldFormat) {
tick_clock_->NowTicks());
base::Time out_network_time;
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
double local, network;
const base::DictionaryValue* saved_prefs =
pref_service_.GetDictionary(prefs::kNetworkTimeMapping);
@@ -390,7 +472,8 @@ TEST_F(NetworkTimeTrackerTest, DeserializeOldFormat) {
prefs.SetDouble("network", network);
pref_service_.Set(prefs::kNetworkTimeMapping, prefs);
Reset();
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_NO_SYNC,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
}
TEST_F(NetworkTimeTrackerTest, SerializeWithLongDelay) {
@@ -400,10 +483,12 @@ TEST_F(NetworkTimeTrackerTest, SerializeWithLongDelay) {
UpdateNetworkTime(in_network_time - latency_ / 2, resolution_, latency_,
tick_clock_->NowTicks());
base::Time out_network_time;
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
AdvanceBoth(base::TimeDelta::FromDays(8));
Reset();
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_NO_SYNC,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
}
TEST_F(NetworkTimeTrackerTest, SerializeWithTickClockAdvance) {
@@ -413,10 +498,12 @@ TEST_F(NetworkTimeTrackerTest, SerializeWithTickClockAdvance) {
UpdateNetworkTime(in_network_time - latency_ / 2, resolution_, latency_,
tick_clock_->NowTicks());
base::Time out_network_time;
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
tick_clock_->Advance(base::TimeDelta::FromDays(1));
Reset();
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_SYNC_LOST,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
}
TEST_F(NetworkTimeTrackerTest, SerializeWithWallClockAdvance) {
@@ -427,15 +514,22 @@ TEST_F(NetworkTimeTrackerTest, SerializeWithWallClockAdvance) {
tick_clock_->NowTicks());
base::Time out_network_time;
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
clock_->Advance(base::TimeDelta::FromDays(1));
Reset();
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_SYNC_LOST,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
}
TEST_F(NetworkTimeTrackerTest, UpdateFromNetwork) {
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 0);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 0);
+
base::Time out_network_time;
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_NO_SYNC,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
// First query should happen soon.
EXPECT_EQ(base::TimeDelta::FromMinutes(0),
tracker_->GetTimerDelayForTesting());
@@ -447,13 +541,18 @@ TEST_F(NetworkTimeTrackerTest, UpdateFromNetwork) {
EXPECT_TRUE(tracker_->QueryTimeServiceForTesting());
tracker_->WaitForFetchForTesting(123123123);
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
EXPECT_EQ(base::Time::UnixEpoch() +
base::TimeDelta::FromMilliseconds(1461621971825),
out_network_time);
// Should see no backoff in the success case.
EXPECT_EQ(base::TimeDelta::FromMinutes(60),
tracker_->GetTimerDelayForTesting());
+
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 0);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 1);
+ histograms.ExpectBucketCount(kFetchValidHistogram, true, 1);
}
TEST_F(NetworkTimeTrackerTest, NoNetworkQueryWhileSynced) {
@@ -494,6 +593,10 @@ TEST_F(NetworkTimeTrackerTest, NoNetworkQueryWhileFeatureDisabled) {
}
TEST_F(NetworkTimeTrackerTest, UpdateFromNetworkBadSignature) {
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 0);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 0);
+
test_server_->RegisterRequestHandler(
base::Bind(&NetworkTimeTrackerTest::BadSignatureResponseHandler));
EXPECT_TRUE(test_server_->Start());
@@ -502,9 +605,14 @@ TEST_F(NetworkTimeTrackerTest, UpdateFromNetworkBadSignature) {
tracker_->WaitForFetchForTesting(123123123);
base::Time out_network_time;
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_NO_SYNC,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
EXPECT_EQ(base::TimeDelta::FromMinutes(120),
tracker_->GetTimerDelayForTesting());
+
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 0);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 1);
+ histograms.ExpectBucketCount(kFetchValidHistogram, false, 1);
}
static const uint8_t kDevKeyPubBytes[] = {
@@ -518,6 +626,10 @@ static const uint8_t kDevKeyPubBytes[] = {
0x04, 0x16, 0xe2, 0x3d, 0x21, 0x76, 0x2b};
TEST_F(NetworkTimeTrackerTest, UpdateFromNetworkBadData) {
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 0);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 0);
+
test_server_->RegisterRequestHandler(
base::Bind(&NetworkTimeTrackerTest::BadDataResponseHandler));
EXPECT_TRUE(test_server_->Start());
@@ -528,12 +640,21 @@ TEST_F(NetworkTimeTrackerTest, UpdateFromNetworkBadData) {
EXPECT_TRUE(tracker_->QueryTimeServiceForTesting());
tracker_->WaitForFetchForTesting(123123123);
base::Time out_network_time;
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_NO_SYNC,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
EXPECT_EQ(base::TimeDelta::FromMinutes(120),
tracker_->GetTimerDelayForTesting());
+
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 0);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 1);
+ histograms.ExpectBucketCount(kFetchValidHistogram, false, 1);
}
TEST_F(NetworkTimeTrackerTest, UpdateFromNetworkServerError) {
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 0);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 0);
+
test_server_->RegisterRequestHandler(
base::Bind(&NetworkTimeTrackerTest::ServerErrorResponseHandler));
EXPECT_TRUE(test_server_->Start());
@@ -542,13 +663,25 @@ TEST_F(NetworkTimeTrackerTest, UpdateFromNetworkServerError) {
tracker_->WaitForFetchForTesting(123123123);
base::Time out_network_time;
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_NO_SYNC,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
// Should see backoff in the error case.
EXPECT_EQ(base::TimeDelta::FromMinutes(120),
tracker_->GetTimerDelayForTesting());
+
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 1);
+ // There was no network error, so the histogram is recorded as
+ // net::OK, indicating that the connection succeeded but there was a
+ // non-200 HTTP status code.
+ histograms.ExpectBucketCount(kFetchFailedHistogram, net::OK, 1);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 0);
}
-TEST_F(NetworkTimeTrackerTest, UpdateFromNetworNetworkError) {
+TEST_F(NetworkTimeTrackerTest, UpdateFromNetworkNetworkError) {
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 0);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 0);
+
test_server_->RegisterRequestHandler(
base::Bind(&NetworkTimeTrackerTest::NetworkErrorResponseHandler));
EXPECT_TRUE(test_server_->Start());
@@ -557,13 +690,23 @@ TEST_F(NetworkTimeTrackerTest, UpdateFromNetworNetworkError) {
tracker_->WaitForFetchForTesting(123123123);
base::Time out_network_time;
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_NO_SYNC,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
// Should see backoff in the error case.
EXPECT_EQ(base::TimeDelta::FromMinutes(120),
tracker_->GetTimerDelayForTesting());
+
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 1);
+ histograms.ExpectBucketCount(kFetchFailedHistogram, -net::ERR_EMPTY_RESPONSE,
+ 1);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 0);
}
TEST_F(NetworkTimeTrackerTest, UpdateFromNetworkLargeResponse) {
+ base::HistogramTester histograms;
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 0);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 0);
+
test_server_->RegisterRequestHandler(
base::Bind(&NetworkTimeTrackerTest::GoodTimeResponseHandler));
EXPECT_TRUE(test_server_->Start());
@@ -574,12 +717,21 @@ TEST_F(NetworkTimeTrackerTest, UpdateFromNetworkLargeResponse) {
tracker_->SetMaxResponseSizeForTesting(3);
EXPECT_TRUE(tracker_->QueryTimeServiceForTesting());
tracker_->WaitForFetchForTesting(123123123);
- EXPECT_FALSE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_NO_SYNC,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
+
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 1);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 0);
tracker_->SetMaxResponseSizeForTesting(1024);
EXPECT_TRUE(tracker_->QueryTimeServiceForTesting());
tracker_->WaitForFetchForTesting(123123123);
- EXPECT_TRUE(tracker_->GetNetworkTime(&out_network_time, nullptr));
+ EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
+ tracker_->GetNetworkTime(&out_network_time, nullptr));
+
+ histograms.ExpectTotalCount(kFetchFailedHistogram, 1);
+ histograms.ExpectTotalCount(kFetchValidHistogram, 1);
+ histograms.ExpectBucketCount(kFetchValidHistogram, true, 1);
}
} // namespace network_time
diff --git a/chromium/components/new_or_sad_tab_strings.grdp b/chromium/components/new_or_sad_tab_strings.grdp
index e756c8610b0..b04b83d57f9 100644
--- a/chromium/components/new_or_sad_tab_strings.grdp
+++ b/chromium/components/new_or_sad_tab_strings.grdp
@@ -12,6 +12,16 @@
<message name="IDS_SAD_TAB_MESSAGE" desc="The message displayed on the sad tab page." formatter_data="android_java">
Something went wrong while displaying this webpage.
</message>
+ <if expr="_google_chrome">
+ <message name="IDS_SAD_TAB_OOM_MESSAGE" desc="The message displayed on the sad tab page if the tab died due to being out of memory." formatter_data="android_java">
+ Google Chrome ran out of memory while trying to display this webpage.
+ </message>
+ </if>
+ <if expr="not _google_chrome">
+ <message name="IDS_SAD_TAB_OOM_MESSAGE" desc="The message displayed on the sad tab page if the tab died due to being out of memory." formatter_data="android_java">
+ Chromium ran out of memory while trying to display this webpage.
+ </message>
+ </if>
<message name="IDS_SAD_TAB_HELP_MESSAGE" desc="The help message displayed on the sad tab page, with IDS_SAD_TAB_HELP_LINK embedded as a link to help.">
If you're seeing this frequently, try these <ph name="HELP_LINK">$1<ex>suggestions</ex></ph>.
</message>
diff --git a/chromium/components/ntp_snippets.gypi b/chromium/components/ntp_snippets.gypi
deleted file mode 100644
index 2bd939be151..00000000000
--- a/chromium/components/ntp_snippets.gypi
+++ /dev/null
@@ -1,62 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/ntp_snippets
- 'target_name': 'ntp_snippets',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- '../third_party/icu/icu.gyp:icuuc',
- 'data_use_measurement_core',
- 'image_fetcher',
- 'keyed_service_core',
- 'leveldb_proto',
- 'prefs/prefs.gyp:prefs',
- 'signin_core_browser',
- 'suggestions',
- 'sync_driver',
- 'variations',
- 'variations_net',
- ],
- 'sources': [
- 'ntp_snippets/content_suggestion_category.h',
- 'ntp_snippets/content_suggestion.cc',
- 'ntp_snippets/content_suggestion.h',
- 'ntp_snippets/content_suggestions_provider_type.h',
- 'ntp_snippets/ntp_snippet.cc',
- 'ntp_snippets/ntp_snippet.h',
- 'ntp_snippets/ntp_snippets_constants.cc',
- 'ntp_snippets/ntp_snippets_constants.h',
- 'ntp_snippets/ntp_snippets_database.cc',
- 'ntp_snippets/ntp_snippets_database.h',
- 'ntp_snippets/ntp_snippets_fetcher.cc',
- 'ntp_snippets/ntp_snippets_fetcher.h',
- 'ntp_snippets/ntp_snippets_scheduler.h',
- 'ntp_snippets/ntp_snippets_service.cc',
- 'ntp_snippets/ntp_snippets_service.h',
- 'ntp_snippets/ntp_snippets_status_service.cc',
- 'ntp_snippets/ntp_snippets_status_service.h',
- 'ntp_snippets/pref_names.cc',
- 'ntp_snippets/pref_names.h',
- 'ntp_snippets/proto/ntp_snippets.proto',
- 'ntp_snippets/switches.cc',
- 'ntp_snippets/switches.h',
- ],
- 'variables': {
- 'proto_in_dir': 'ntp_snippets/proto',
- 'proto_out_dir': 'components/ntp_snippets/proto',
- },
- 'includes': [ '../build/protoc.gypi' ],
- },
- ],
-}
diff --git a/chromium/components/ntp_snippets/BUILD.gn b/chromium/components/ntp_snippets/BUILD.gn
index f520319d589..8e712af9eae 100644
--- a/chromium/components/ntp_snippets/BUILD.gn
+++ b/chromium/components/ntp_snippets/BUILD.gn
@@ -9,30 +9,63 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-# GYP version: components/ntp_snippets.gypi:ntp_snippets
-source_set("ntp_snippets") {
+static_library("ntp_snippets") {
sources = [
+ "bookmarks/bookmark_last_visit_utils.cc",
+ "bookmarks/bookmark_last_visit_utils.h",
+ "bookmarks/bookmark_suggestions_provider.cc",
+ "bookmarks/bookmark_suggestions_provider.h",
+ "category.cc",
+ "category.h",
+ "category_factory.cc",
+ "category_factory.h",
+ "category_info.cc",
+ "category_info.h",
+ "category_status.cc",
+ "category_status.h",
"content_suggestion.cc",
"content_suggestion.h",
- "content_suggestion_category.h",
- "content_suggestions_provider_type.h",
- "ntp_snippet.cc",
- "ntp_snippet.h",
+ "content_suggestions_metrics.cc",
+ "content_suggestions_metrics.h",
+ "content_suggestions_provider.cc",
+ "content_suggestions_provider.h",
+ "content_suggestions_service.cc",
+ "content_suggestions_service.h",
+ "features.cc",
+ "features.h",
"ntp_snippets_constants.cc",
"ntp_snippets_constants.h",
- "ntp_snippets_database.cc",
- "ntp_snippets_database.h",
- "ntp_snippets_fetcher.cc",
- "ntp_snippets_fetcher.h",
- "ntp_snippets_scheduler.h",
- "ntp_snippets_service.cc",
- "ntp_snippets_service.h",
- "ntp_snippets_status_service.cc",
- "ntp_snippets_status_service.h",
+ "offline_pages/offline_page_proxy.cc",
+ "offline_pages/offline_page_proxy.h",
+ "offline_pages/recent_tab_suggestions_provider.cc",
+ "offline_pages/recent_tab_suggestions_provider.h",
+ "physical_web_pages/physical_web_page_suggestions_provider.cc",
+ "physical_web_pages/physical_web_page_suggestions_provider.h",
"pref_names.cc",
"pref_names.h",
+ "pref_util.cc",
+ "pref_util.h",
+ "remote/ntp_snippet.cc",
+ "remote/ntp_snippet.h",
+ "remote/ntp_snippets_database.cc",
+ "remote/ntp_snippets_database.h",
+ "remote/ntp_snippets_fetcher.cc",
+ "remote/ntp_snippets_fetcher.h",
+ "remote/ntp_snippets_scheduler.h",
+ "remote/ntp_snippets_service.cc",
+ "remote/ntp_snippets_service.h",
+ "remote/ntp_snippets_status_service.cc",
+ "remote/ntp_snippets_status_service.h",
+ "remote/request_throttler.cc",
+ "remote/request_throttler.h",
+ "sessions/foreign_sessions_suggestions_provider.cc",
+ "sessions/foreign_sessions_suggestions_provider.h",
+ "sessions/tab_delegate_sync_adapter.cc",
+ "sessions/tab_delegate_sync_adapter.h",
"switches.cc",
"switches.h",
+ "user_classifier.cc",
+ "user_classifier.h",
]
public_deps = [
@@ -41,18 +74,24 @@ source_set("ntp_snippets") {
"//components/leveldb_proto",
"//components/prefs",
"//components/signin/core/browser",
- "//components/suggestions",
- "//components/sync_driver",
+ "//components/sync",
"//google_apis",
"//net",
+ "//ui/base",
"//url",
]
deps = [
+ "//components/bookmarks/browser",
"//components/data_use_measurement/core",
+ "//components/history/core/browser",
"//components/image_fetcher",
"//components/metrics",
- "//components/ntp_snippets/proto",
+ "//components/ntp_snippets/remote/proto",
+ "//components/offline_pages",
+ "//components/sessions",
+ "//components/strings",
+ "//components/sync_sessions",
"//components/variations",
"//components/variations/net",
"//third_party/icu/",
@@ -63,7 +102,9 @@ source_set("ntp_snippets") {
if (is_android) {
java_cpp_enum("ntp_snippets_java_enums_srcjar") {
sources = [
- "ntp_snippets_status_service.h",
+ "category.h",
+ "category_info.h",
+ "category_status.h",
]
}
}
@@ -71,27 +112,45 @@ if (is_android) {
source_set("unit_tests") {
testonly = true
sources = [
- "ntp_snippet_unittest.cc",
- "ntp_snippets_database_unittest.cc",
- "ntp_snippets_fetcher_unittest.cc",
- "ntp_snippets_service_unittest.cc",
- "ntp_snippets_status_service_unittest.cc",
- "ntp_snippets_test_utils.cc",
- "ntp_snippets_test_utils.h",
+ "bookmarks/bookmark_last_visit_utils_unittest.cc",
+ "category_factory_unittest.cc",
+ "content_suggestions_service_unittest.cc",
+ "mock_content_suggestions_provider_observer.cc",
+ "mock_content_suggestions_provider_observer.h",
+ "offline_pages/recent_tab_suggestions_provider_unittest.cc",
+ "physical_web_pages/physical_web_page_suggestions_provider_unittest.cc",
+ "remote/ntp_snippet_unittest.cc",
+ "remote/ntp_snippets_database_unittest.cc",
+ "remote/ntp_snippets_fetcher_unittest.cc",
+ "remote/ntp_snippets_service_unittest.cc",
+ "remote/ntp_snippets_status_service_unittest.cc",
+ "remote/ntp_snippets_test_utils.cc",
+ "remote/ntp_snippets_test_utils.h",
+ "remote/request_throttler_unittest.cc",
+ "sessions/foreign_sessions_suggestions_provider_unittest.cc",
]
deps = [
":ntp_snippets",
"//base",
"//base/test:test_support",
+ "//components/bookmarks/browser",
+ "//components/bookmarks/test",
"//components/image_fetcher",
"//components/leveldb_proto:test_support",
+ "//components/offline_pages",
+ "//components/offline_pages:test_support",
+ "//components/sessions",
+ "//components/sessions:test_support",
"//components/signin/core/browser:test_support",
"//components/signin/core/common",
- "//components/sync_driver:test_support",
+ "//components/strings",
+ "//components/sync:test_support_sync_driver",
+ "//components/sync_sessions",
"//components/variations",
"//net:test_support",
"//testing/gtest",
"//third_party/icu/",
+ "//ui/gfx:test_support",
]
}
diff --git a/chromium/components/ntp_snippets/DEPS b/chromium/components/ntp_snippets/DEPS
index 02c7f3b3a8c..51bcdffcecb 100644
--- a/chromium/components/ntp_snippets/DEPS
+++ b/chromium/components/ntp_snippets/DEPS
@@ -1,17 +1,19 @@
include_rules = [
"+components/data_use_measurement/core",
+ "+components/history/core",
"+components/image_fetcher",
"+components/keyed_service/core",
"+components/leveldb_proto",
"+components/metrics",
"+components/prefs",
"+components/signin",
- "+components/suggestions",
- "+components/sync_driver",
+ "+components/sync/driver",
"+components/variations",
+ "+grit/components_strings.h",
"+net/base",
"+net/http",
"+net/url_request",
"+google_apis",
+ "+ui/base",
"+ui/gfx",
]
diff --git a/chromium/components/ntp_snippets/bookmarks/DEPS b/chromium/components/ntp_snippets/bookmarks/DEPS
new file mode 100644
index 00000000000..fe6f7075507
--- /dev/null
+++ b/chromium/components/ntp_snippets/bookmarks/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/bookmarks",
+]
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc
new file mode 100644
index 00000000000..90aea5bf49b
--- /dev/null
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc
@@ -0,0 +1,273 @@
+// 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 "components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h"
+
+#include <algorithm>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/bookmark_node.h"
+#include "url/gurl.h"
+
+using bookmarks::BookmarkModel;
+using bookmarks::BookmarkNode;
+
+namespace ntp_snippets {
+
+namespace {
+
+struct RecentBookmark {
+ const bookmarks::BookmarkNode* node;
+ bool visited_recently;
+};
+
+const char* kBookmarksURLBlacklist[] = {"chrome://newtab/",
+ "chrome-native://newtab/",
+ "chrome://bookmarks/"};
+
+const char kBookmarkLastVisitDateKey[] = "last_visited";
+const char kBookmarkDismissedFromNTP[] = "dismissed_from_ntp";
+
+base::Time ParseLastVisitDate(const std::string& date_string) {
+ int64_t date = 0;
+ if (!base::StringToInt64(date_string, &date))
+ return base::Time::UnixEpoch();
+ return base::Time::FromInternalValue(date);
+}
+
+std::string FormatLastVisitDate(const base::Time& date) {
+ return base::Int64ToString(date.ToInternalValue());
+}
+
+bool CompareBookmarksByLastVisitDate(const BookmarkNode* a,
+ const BookmarkNode* b,
+ bool creation_date_fallback) {
+ return GetLastVisitDateForBookmark(a, creation_date_fallback) >
+ GetLastVisitDateForBookmark(b, creation_date_fallback);
+}
+
+bool IsBlacklisted(const GURL& url) {
+ for (const char* blacklisted : kBookmarksURLBlacklist) {
+ if (url.spec() == blacklisted)
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+void UpdateBookmarkOnURLVisitedInMainFrame(BookmarkModel* bookmark_model,
+ const GURL& url) {
+ // Skip URLs that are blacklisted.
+ if (IsBlacklisted(url))
+ return;
+
+ // Skip URLs that are not bookmarked.
+ std::vector<const BookmarkNode*> bookmarks_for_url;
+ bookmark_model->GetNodesByURL(url, &bookmarks_for_url);
+ if (bookmarks_for_url.empty())
+ return;
+
+ // If there are bookmarks for |url|, set their last visit date to now.
+ std::string now = FormatLastVisitDate(base::Time::Now());
+ for (const BookmarkNode* node : bookmarks_for_url) {
+ bookmark_model->SetNodeMetaInfo(node, kBookmarkLastVisitDateKey, now);
+ // If the bookmark has been dismissed from NTP before, a new visit overrides
+ // such a dismissal.
+ bookmark_model->DeleteNodeMetaInfo(node, kBookmarkDismissedFromNTP);
+ }
+}
+
+base::Time GetLastVisitDateForBookmark(const BookmarkNode* node,
+ bool creation_date_fallback) {
+ if (!node)
+ return base::Time::UnixEpoch();
+
+ std::string last_visit_date_string;
+ if (!node->GetMetaInfo(kBookmarkLastVisitDateKey, &last_visit_date_string) &&
+ creation_date_fallback) {
+ return node->date_added();
+ }
+ return ParseLastVisitDate(last_visit_date_string);
+}
+
+base::Time GetLastVisitDateForBookmarkIfNotDismissed(
+ const BookmarkNode* node,
+ bool creation_date_fallback) {
+ if (IsDismissedFromNTPForBookmark(node))
+ return base::Time::UnixEpoch();
+
+ return GetLastVisitDateForBookmark(node, creation_date_fallback);
+}
+
+void MarkBookmarksDismissed(BookmarkModel* bookmark_model, const GURL& url) {
+ std::vector<const BookmarkNode*> nodes;
+ bookmark_model->GetNodesByURL(url, &nodes);
+ for (const BookmarkNode* node : nodes)
+ bookmark_model->SetNodeMetaInfo(node, kBookmarkDismissedFromNTP, "1");
+}
+
+bool IsDismissedFromNTPForBookmark(const BookmarkNode* node) {
+ if (!node)
+ return false;
+
+ std::string dismissed_from_ntp;
+ bool result =
+ node->GetMetaInfo(kBookmarkDismissedFromNTP, &dismissed_from_ntp);
+ DCHECK(!result || dismissed_from_ntp == "1");
+ return result;
+}
+
+void MarkAllBookmarksUndismissed(BookmarkModel* bookmark_model) {
+ // Get all the bookmark URLs.
+ std::vector<BookmarkModel::URLAndTitle> bookmarks;
+ bookmark_model->GetBookmarks(&bookmarks);
+
+ // Remove dismissed flag from all bookmarks
+ for (const BookmarkModel::URLAndTitle& bookmark : bookmarks) {
+ std::vector<const BookmarkNode*> nodes;
+ bookmark_model->GetNodesByURL(bookmark.url, &nodes);
+ for (const BookmarkNode* node : nodes)
+ bookmark_model->DeleteNodeMetaInfo(node, kBookmarkDismissedFromNTP);
+ }
+}
+
+std::vector<const BookmarkNode*> GetRecentlyVisitedBookmarks(
+ BookmarkModel* bookmark_model,
+ int min_count,
+ int max_count,
+ const base::Time& min_visit_time,
+ bool creation_date_fallback) {
+ // Get all the bookmark URLs.
+ std::vector<BookmarkModel::URLAndTitle> bookmark_urls;
+ bookmark_model->GetBookmarks(&bookmark_urls);
+
+ std::vector<RecentBookmark> bookmarks;
+ int recently_visited_count = 0;
+ // Find for each bookmark the most recently visited BookmarkNode and find out
+ // whether it is visited since |min_visit_time|.
+ for (const BookmarkModel::URLAndTitle& url_and_title : bookmark_urls) {
+ // Skip URLs that are blacklisted.
+ if (IsBlacklisted(url_and_title.url))
+ continue;
+
+ // Get all bookmarks for the given URL.
+ std::vector<const BookmarkNode*> bookmarks_for_url;
+ bookmark_model->GetNodesByURL(url_and_title.url, &bookmarks_for_url);
+ DCHECK(!bookmarks_for_url.empty());
+
+ // Find the most recent node (minimal w.r.t.
+ // CompareBookmarksByLastVisitDate).
+ const BookmarkNode* most_recent = *std::min_element(
+ bookmarks_for_url.begin(), bookmarks_for_url.end(),
+ [creation_date_fallback](const BookmarkNode* a, const BookmarkNode* b) {
+ return CompareBookmarksByLastVisitDate(a, b, creation_date_fallback);
+ });
+
+ // Find out if it has been _visited_ recently enough.
+ bool visited_recently =
+ min_visit_time < GetLastVisitDateForBookmark(
+ most_recent, /*creation_date_fallback=*/false);
+ if (visited_recently)
+ recently_visited_count++;
+ if (!IsDismissedFromNTPForBookmark(most_recent))
+ bookmarks.push_back({most_recent, visited_recently});
+ }
+
+ if (recently_visited_count < min_count) {
+ // There aren't enough recently-visited bookmarks. Fill the list up to
+ // |min_count| with older bookmarks (in particular those with only a
+ // creation date, if creation_date_fallback is true).
+ max_count = min_count;
+ } else {
+ // Remove the bookmarks that are not recently visited; we do not need them.
+ // (We might end up with fewer than |min_count| bookmarks if all the recent
+ // ones are dismissed.)
+ bookmarks.erase(
+ std::remove_if(bookmarks.begin(), bookmarks.end(),
+ [](const RecentBookmark& bookmark) {
+ return !bookmark.visited_recently;
+ }),
+ bookmarks.end());
+ }
+
+ // Sort the remaining entries by date.
+ std::sort(bookmarks.begin(), bookmarks.end(),
+ [creation_date_fallback](const RecentBookmark& a,
+ const RecentBookmark& b) {
+ return CompareBookmarksByLastVisitDate(a.node, b.node,
+ creation_date_fallback);
+ });
+
+ // Insert the first |max_count| items from |bookmarks| into |result|.
+ std::vector<const BookmarkNode*> result;
+ for (const RecentBookmark& bookmark : bookmarks) {
+ if (!creation_date_fallback &&
+ GetLastVisitDateForBookmark(bookmark.node, creation_date_fallback) <
+ min_visit_time) {
+ break;
+ }
+
+ result.push_back(bookmark.node);
+ if (result.size() >= static_cast<size_t>(max_count))
+ break;
+ }
+ return result;
+}
+
+std::vector<const BookmarkNode*> GetDismissedBookmarksForDebugging(
+ BookmarkModel* bookmark_model) {
+ // Get all the bookmark URLs.
+ std::vector<BookmarkModel::URLAndTitle> bookmarks;
+ bookmark_model->GetBookmarks(&bookmarks);
+
+ // Remove the bookmark URLs which have at least one non-dismissed bookmark.
+ bookmarks.erase(
+ std::remove_if(
+ bookmarks.begin(), bookmarks.end(),
+ [&bookmark_model](const BookmarkModel::URLAndTitle& bookmark) {
+ std::vector<const BookmarkNode*> bookmarks_for_url;
+ bookmark_model->GetNodesByURL(bookmark.url, &bookmarks_for_url);
+ DCHECK(!bookmarks_for_url.empty());
+
+ for (const BookmarkNode* node : bookmarks_for_url) {
+ if (!IsDismissedFromNTPForBookmark(node))
+ return true;
+ }
+ return false;
+ }),
+ bookmarks.end());
+
+ // Insert into |result|.
+ std::vector<const BookmarkNode*> result;
+ for (const BookmarkModel::URLAndTitle& bookmark : bookmarks) {
+ result.push_back(
+ bookmark_model->GetMostRecentlyAddedUserNodeForURL(bookmark.url));
+ }
+ return result;
+}
+
+void RemoveAllLastVisitDates(bookmarks::BookmarkModel* bookmark_model) {
+ // Get all the bookmark URLs.
+ std::vector<BookmarkModel::URLAndTitle> bookmark_urls;
+ bookmark_model->GetBookmarks(&bookmark_urls);
+
+ for (const BookmarkModel::URLAndTitle& url_and_title : bookmark_urls) {
+ // Get all bookmarks for the given URL.
+ std::vector<const BookmarkNode*> bookmarks_for_url;
+ bookmark_model->GetNodesByURL(url_and_title.url, &bookmarks_for_url);
+
+ for (const BookmarkNode* bookmark : bookmarks_for_url) {
+ bookmark_model->DeleteNodeMetaInfo(bookmark, kBookmarkLastVisitDateKey);
+ }
+ }
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h
new file mode 100644
index 00000000000..b056deaeb30
--- /dev/null
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h
@@ -0,0 +1,74 @@
+// 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 COMPONENTS_NTP_SNIPPETS_BOOKMARKS_BOOKMARK_LAST_VISIT_UTILS_H_
+#define COMPONENTS_NTP_SNIPPETS_BOOKMARKS_BOOKMARK_LAST_VISIT_UTILS_H_
+
+#include <vector>
+
+class GURL;
+
+namespace base {
+class Time;
+} // namespace base
+
+namespace bookmarks {
+class BookmarkModel;
+class BookmarkNode;
+} // namespace bookmarks
+
+namespace ntp_snippets {
+
+// If there is a bookmark for |url|, this function updates its last visit date
+// to now. If there are multiple bookmarks for a given URL, it updates all of
+// them.
+void UpdateBookmarkOnURLVisitedInMainFrame(
+ bookmarks::BookmarkModel* bookmark_model,
+ const GURL& url);
+
+// Gets the last visit date for a given bookmark |node|. The visit when the
+// bookmark is created also counts. If no info about last visit date is present
+// and |creation_date_fallback| is true, creation date is used.
+base::Time GetLastVisitDateForBookmark(const bookmarks::BookmarkNode* node,
+ bool creation_date_fallback);
+
+// Like GetLastVisitDateForBookmark, but it returns the unix epoch if the
+// bookmark is dismissed from NTP.
+base::Time GetLastVisitDateForBookmarkIfNotDismissed(
+ const bookmarks::BookmarkNode* node,
+ bool creation_date_fallback);
+
+// Marks all bookmarks with the given URL as dismissed.
+void MarkBookmarksDismissed(bookmarks::BookmarkModel* bookmark_model,
+ const GURL& url);
+
+// Gets the dismissed flag for a given bookmark |node|. Defaults to false.
+bool IsDismissedFromNTPForBookmark(const bookmarks::BookmarkNode* node);
+
+// Removes the dismissed flag from all bookmarks (only for debugging).
+void MarkAllBookmarksUndismissed(bookmarks::BookmarkModel* bookmark_model);
+
+// Returns the list of most recently visited, non-dismissed bookmarks.
+// For each bookmarked URL, it returns the most recently created bookmark.
+// The result is ordered by visit time (the most recent first). Only bookmarks
+// visited after |min_visit_time| are considered, at most |max_count| bookmarks
+// are returned. If this results into less than |min_count| bookmarks, the list
+// is filled up with older bookmarks sorted by their last visit / creation date.
+std::vector<const bookmarks::BookmarkNode*> GetRecentlyVisitedBookmarks(
+ bookmarks::BookmarkModel* bookmark_model,
+ int min_count,
+ int max_count,
+ const base::Time& min_visit_time,
+ bool creation_date_fallback);
+
+// Returns the list of all dismissed bookmarks. Only used for debugging.
+std::vector<const bookmarks::BookmarkNode*> GetDismissedBookmarksForDebugging(
+ bookmarks::BookmarkModel* bookmark_model);
+
+// Removes last visited date metadata for all bookmarks.
+void RemoveAllLastVisitDates(bookmarks::BookmarkModel* bookmark_model);
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_BOOKMARKS_BOOKMARK_LAST_VISIT_UTILS_H_
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils_unittest.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils_unittest.cc
new file mode 100644
index 00000000000..45e595d56ea
--- /dev/null
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils_unittest.cc
@@ -0,0 +1,122 @@
+// 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 "components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h"
+
+#include <string>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/bookmark_node.h"
+#include "components/bookmarks/test/test_bookmark_client.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using bookmarks::BookmarkModel;
+using bookmarks::BookmarkNode;
+
+using testing::IsEmpty;
+using testing::SizeIs;
+
+namespace ntp_snippets {
+
+namespace {
+
+const char kBookmarkLastVisitDateKey[] = "last_visited";
+
+std::unique_ptr<BookmarkModel> CreateModelWithRecentBookmarks(
+ int number_of_bookmarks,
+ int number_of_recent,
+ const base::Time& threshold_time) {
+ std::unique_ptr<BookmarkModel> model =
+ bookmarks::TestBookmarkClient::CreateModel();
+
+ base::TimeDelta week = base::TimeDelta::FromDays(7);
+ base::Time recent_time = threshold_time + week;
+ std::string recent_time_string =
+ base::Int64ToString(recent_time.ToInternalValue());
+ base::Time nonrecent_time = threshold_time - week;
+ std::string nonrecent_time_string =
+ base::Int64ToString(nonrecent_time.ToInternalValue());
+
+ for (int index = 0; index < number_of_bookmarks; ++index) {
+ base::string16 title =
+ base::ASCIIToUTF16(base::StringPrintf("title%d", index));
+ GURL url(base::StringPrintf("http://url%d.com", index));
+ const BookmarkNode* node =
+ model->AddURL(model->bookmark_bar_node(), index, title, url);
+
+ model->SetNodeMetaInfo(
+ node, kBookmarkLastVisitDateKey,
+ index < number_of_recent ? recent_time_string : nonrecent_time_string);
+ }
+
+ return model;
+}
+
+} // namespace
+
+class GetRecentlyVisitedBookmarksTest : public testing::Test {
+ public:
+ GetRecentlyVisitedBookmarksTest() {
+ base::TimeDelta week = base::TimeDelta::FromDays(7);
+ threshold_time_ = base::Time::UnixEpoch() + 52 * week;
+ }
+
+ const base::Time& threshold_time() const { return threshold_time_; }
+
+ private:
+ base::Time threshold_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(GetRecentlyVisitedBookmarksTest);
+};
+
+TEST_F(GetRecentlyVisitedBookmarksTest,
+ WithoutDateFallbackShouldNotReturnNonRecent) {
+ const int number_of_recent = 0;
+ const int number_of_bookmarks = 3;
+ std::unique_ptr<BookmarkModel> model = CreateModelWithRecentBookmarks(
+ number_of_bookmarks, number_of_recent, threshold_time());
+
+ std::vector<const bookmarks::BookmarkNode*> result =
+ GetRecentlyVisitedBookmarks(model.get(), 0, number_of_bookmarks,
+ threshold_time(),
+ /*creation_date_fallback=*/false);
+ EXPECT_THAT(result, IsEmpty());
+}
+
+TEST_F(GetRecentlyVisitedBookmarksTest,
+ WithDateFallbackShouldReturnNonRecentUpToMinCount) {
+ const int number_of_recent = 0;
+ const int number_of_bookmarks = 3;
+ std::unique_ptr<BookmarkModel> model = CreateModelWithRecentBookmarks(
+ number_of_bookmarks, number_of_recent, threshold_time());
+
+ const int min_count = number_of_bookmarks - 1;
+ const int max_count = min_count + 10;
+ std::vector<const bookmarks::BookmarkNode*> result =
+ GetRecentlyVisitedBookmarks(model.get(), min_count, max_count,
+ threshold_time(),
+ /*creation_date_fallback=*/true);
+ EXPECT_THAT(result, SizeIs(min_count));
+}
+
+TEST_F(GetRecentlyVisitedBookmarksTest, ShouldReturnNotMoreThanMaxCount) {
+ const int number_of_recent = 3;
+ const int number_of_bookmarks = number_of_recent;
+ std::unique_ptr<BookmarkModel> model = CreateModelWithRecentBookmarks(
+ number_of_bookmarks, number_of_recent, threshold_time());
+
+ const int max_count = number_of_recent - 1;
+ std::vector<const bookmarks::BookmarkNode*> result =
+ GetRecentlyVisitedBookmarks(model.get(), max_count, max_count,
+ threshold_time(),
+ /*creation_date_fallback=*/false);
+ EXPECT_THAT(result, SizeIs(max_count));
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
new file mode 100644
index 00000000000..b5020910f0c
--- /dev/null
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
@@ -0,0 +1,327 @@
+// 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 "components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/content_suggestion.h"
+#include "components/ntp_snippets/features.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/variations/variations_associated_data.h"
+#include "grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/image/image.h"
+
+using bookmarks::BookmarkModel;
+using bookmarks::BookmarkNode;
+
+namespace ntp_snippets {
+
+namespace {
+
+const int kMaxBookmarks = 10;
+const int kMinBookmarks = 3;
+const int kMaxBookmarkAgeInDays = 42;
+const int kUseCreationDateFallbackForDays = 0;
+
+const char* kMaxBookmarksParamName = "bookmarks_max_count";
+const char* kMinBookmarksParamName = "bookmarks_min_count";
+const char* kMaxBookmarkAgeInDaysParamName = "bookmarks_max_age_in_days";
+const char* kUseCreationDateFallbackForDaysParamName =
+ "bookmarks_creation_date_fallback_days";
+const char* kShowIfEmptyParamName = "bookmarks_show_if_empty";
+
+// Any bookmark created or visited after this time will be considered recent.
+// Note that bookmarks can be shown that do not meet this threshold.
+base::Time GetThresholdTime() {
+ return base::Time::Now() -
+ base::TimeDelta::FromDays(GetParamAsInt(
+ ntp_snippets::kBookmarkSuggestionsFeature,
+ kMaxBookmarkAgeInDaysParamName, kMaxBookmarkAgeInDays));
+}
+
+// The number of days used as a threshold where if this is larger than the time
+// since M54 started, then the creation timestamp of a bookmark be used as a
+// fallback if no last visited timestamp is present.
+int UseCreationDateFallbackForDays() {
+ return GetParamAsInt(ntp_snippets::kBookmarkSuggestionsFeature,
+ kUseCreationDateFallbackForDaysParamName,
+ kUseCreationDateFallbackForDays);
+}
+
+// The maximum number of suggestions ever provided.
+int GetMaxCount() {
+ return GetParamAsInt(ntp_snippets::kBookmarkSuggestionsFeature,
+ kMaxBookmarksParamName, kMaxBookmarks);
+}
+
+// The minimum number of suggestions to try to provide. Depending on other
+// parameters this may or not be respected. Currently creation date fallback
+// must be active in order for older bookmarks to be incorporated to meet this
+// min.
+int GetMinCount() {
+ return GetParamAsInt(ntp_snippets::kBookmarkSuggestionsFeature,
+ kMinBookmarksParamName, kMinBookmarks);
+}
+
+bool ShouldShowIfEmpty() {
+ std::string show_if_empty = variations::GetVariationParamValueByFeature(
+ ntp_snippets::kBookmarkSuggestionsFeature, kShowIfEmptyParamName);
+ if (show_if_empty.empty() || show_if_empty == "false")
+ return false;
+ if (show_if_empty == "true")
+ return true;
+
+ LOG(WARNING) << "Failed to parse show if empty " << show_if_empty;
+ return false;
+}
+
+} // namespace
+
+BookmarkSuggestionsProvider::BookmarkSuggestionsProvider(
+ ContentSuggestionsProvider::Observer* observer,
+ CategoryFactory* category_factory,
+ bookmarks::BookmarkModel* bookmark_model,
+ PrefService* pref_service)
+ : ContentSuggestionsProvider(observer, category_factory),
+ category_status_(CategoryStatus::AVAILABLE_LOADING),
+ provided_category_(
+ category_factory->FromKnownCategory(KnownCategories::BOOKMARKS)),
+ bookmark_model_(bookmark_model),
+ fetch_requested_(false),
+ end_of_list_last_visit_date_(GetThresholdTime()) {
+ observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
+ base::Time first_m54_start;
+ base::Time now = base::Time::Now();
+ if (pref_service->HasPrefPath(prefs::kBookmarksFirstM54Start)) {
+ first_m54_start = base::Time::FromInternalValue(
+ pref_service->GetInt64(prefs::kBookmarksFirstM54Start));
+ } else {
+ first_m54_start = now;
+ pref_service->SetInt64(prefs::kBookmarksFirstM54Start,
+ first_m54_start.ToInternalValue());
+ }
+ base::TimeDelta time_since_first_m54_start = now - first_m54_start;
+ // Note: Setting the fallback timeout to zero effectively turns off the
+ // fallback entirely.
+ creation_date_fallback_ =
+ time_since_first_m54_start.InDays() < UseCreationDateFallbackForDays();
+ bookmark_model_->AddObserver(this);
+ FetchBookmarks();
+}
+
+BookmarkSuggestionsProvider::~BookmarkSuggestionsProvider() {
+ bookmark_model_->RemoveObserver(this);
+}
+
+// static
+void BookmarkSuggestionsProvider::RegisterProfilePrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterInt64Pref(prefs::kBookmarksFirstM54Start, 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private methods
+
+CategoryStatus BookmarkSuggestionsProvider::GetCategoryStatus(
+ Category category) {
+ DCHECK_EQ(category, provided_category_);
+ return category_status_;
+}
+
+CategoryInfo BookmarkSuggestionsProvider::GetCategoryInfo(Category category) {
+ return CategoryInfo(
+ l10n_util::GetStringUTF16(IDS_NTP_BOOKMARK_SUGGESTIONS_SECTION_HEADER),
+ ContentSuggestionsCardLayout::MINIMAL_CARD,
+ /*has_more_button=*/true,
+ /*show_if_empty=*/ShouldShowIfEmpty() && bookmark_model_->HasBookmarks());
+ // TODO(treib): Setting show_if_empty to true is a temporary hack, see
+ // crbug.com/640568.
+}
+
+void BookmarkSuggestionsProvider::DismissSuggestion(
+ const ContentSuggestion::ID& suggestion_id) {
+ DCHECK(bookmark_model_->loaded());
+ GURL url(suggestion_id.id_within_category());
+ MarkBookmarksDismissed(bookmark_model_, url);
+}
+
+void BookmarkSuggestionsProvider::FetchSuggestionImage(
+ const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, gfx::Image()));
+}
+
+void BookmarkSuggestionsProvider::ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) {
+ // TODO(vitaliii): Do not remove all dates, but only the ones matched by the
+ // time range and the filter.
+ RemoveAllLastVisitDates(bookmark_model_);
+ ClearDismissedSuggestionsForDebugging(provided_category_);
+ FetchBookmarks();
+ // Temporarily enter an "explicitly disabled" state, so that any open UIs
+ // will clear the suggestions too.
+ if (category_status_ != CategoryStatus::CATEGORY_EXPLICITLY_DISABLED) {
+ CategoryStatus old_category_status = category_status_;
+ NotifyStatusChanged(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED);
+ NotifyStatusChanged(old_category_status);
+ }
+}
+
+void BookmarkSuggestionsProvider::ClearCachedSuggestions(Category category) {
+ DCHECK_EQ(category, provided_category_);
+ // Ignored.
+}
+
+void BookmarkSuggestionsProvider::GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) {
+ DCHECK_EQ(category, provided_category_);
+ std::vector<const BookmarkNode*> bookmarks =
+ GetDismissedBookmarksForDebugging(bookmark_model_);
+
+ std::vector<ContentSuggestion> suggestions;
+ for (const BookmarkNode* bookmark : bookmarks)
+ suggestions.emplace_back(ConvertBookmark(bookmark));
+ callback.Run(std::move(suggestions));
+}
+
+void BookmarkSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
+ Category category) {
+ DCHECK_EQ(category, provided_category_);
+ if (!bookmark_model_->loaded())
+ return;
+ MarkAllBookmarksUndismissed(bookmark_model_);
+}
+
+void BookmarkSuggestionsProvider::BookmarkModelLoaded(
+ bookmarks::BookmarkModel* model,
+ bool ids_reassigned) {
+ DCHECK_EQ(bookmark_model_, model);
+ if (fetch_requested_) {
+ fetch_requested_ = false;
+ FetchBookmarksInternal();
+ }
+}
+
+void BookmarkSuggestionsProvider::OnWillChangeBookmarkMetaInfo(
+ BookmarkModel* model,
+ const BookmarkNode* node) {
+ // Store the last visit date of the node that is about to change.
+ node_to_change_last_visit_date_ =
+ GetLastVisitDateForBookmarkIfNotDismissed(node, creation_date_fallback_);
+}
+
+void BookmarkSuggestionsProvider::BookmarkMetaInfoChanged(
+ BookmarkModel* model,
+ const BookmarkNode* node) {
+ base::Time time =
+ GetLastVisitDateForBookmarkIfNotDismissed(node, creation_date_fallback_);
+ if (time == node_to_change_last_visit_date_ ||
+ time < end_of_list_last_visit_date_)
+ return;
+
+ // Last visit date of a node has changed (and is relevant for the list), we
+ // should update the suggestions.
+ FetchBookmarks();
+}
+
+void BookmarkSuggestionsProvider::BookmarkNodeRemoved(
+ bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* parent,
+ int old_index,
+ const bookmarks::BookmarkNode* node,
+ const std::set<GURL>& no_longer_bookmarked) {
+ if (GetLastVisitDateForBookmarkIfNotDismissed(node, creation_date_fallback_) <
+ end_of_list_last_visit_date_) {
+ return;
+ }
+
+ // Some node from our list got deleted, we should update the suggestions.
+ FetchBookmarks();
+}
+
+void BookmarkSuggestionsProvider::BookmarkNodeAdded(
+ bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* parent,
+ int index) {
+ if (GetLastVisitDateForBookmarkIfNotDismissed(parent->GetChild(index),
+ creation_date_fallback_) <
+ end_of_list_last_visit_date_) {
+ return;
+ }
+
+ // Some node with last_visit info that is relevant for our list got created
+ // (e.g. by sync), we should update the suggestions.
+ FetchBookmarks();
+}
+
+ContentSuggestion BookmarkSuggestionsProvider::ConvertBookmark(
+ const BookmarkNode* bookmark) {
+ ContentSuggestion suggestion(provided_category_, bookmark->url().spec(),
+ bookmark->url());
+
+ suggestion.set_title(bookmark->GetTitle());
+ suggestion.set_snippet_text(base::string16());
+ suggestion.set_publish_date(
+ GetLastVisitDateForBookmark(bookmark, creation_date_fallback_));
+ suggestion.set_publisher_name(base::UTF8ToUTF16(bookmark->url().host()));
+ return suggestion;
+}
+
+void BookmarkSuggestionsProvider::FetchBookmarksInternal() {
+ DCHECK(bookmark_model_->loaded());
+
+ NotifyStatusChanged(CategoryStatus::AVAILABLE);
+
+ base::Time threshold_time = GetThresholdTime();
+ std::vector<const BookmarkNode*> bookmarks =
+ GetRecentlyVisitedBookmarks(bookmark_model_, GetMinCount(), GetMaxCount(),
+ threshold_time, creation_date_fallback_);
+
+ std::vector<ContentSuggestion> suggestions;
+ for (const BookmarkNode* bookmark : bookmarks)
+ suggestions.emplace_back(ConvertBookmark(bookmark));
+
+ if (suggestions.empty())
+ end_of_list_last_visit_date_ = threshold_time;
+ else
+ end_of_list_last_visit_date_ = suggestions.back().publish_date();
+
+ observer()->OnNewSuggestions(this, provided_category_,
+ std::move(suggestions));
+}
+
+void BookmarkSuggestionsProvider::FetchBookmarks() {
+ if (bookmark_model_->loaded())
+ FetchBookmarksInternal();
+ else
+ fetch_requested_ = true;
+}
+
+void BookmarkSuggestionsProvider::NotifyStatusChanged(
+ CategoryStatus new_status) {
+ if (category_status_ == new_status)
+ return;
+ category_status_ = new_status;
+ observer()->OnCategoryStatusChanged(this, provided_category_, new_status);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
new file mode 100644
index 00000000000..2bf8ebb0fe2
--- /dev/null
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
@@ -0,0 +1,122 @@
+// 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 COMPONENTS_NTP_SNIPPETS_BOOKMARKS_BOOKMARK_SUGGESTIONS_PROVIDER_H_
+#define COMPONENTS_NTP_SNIPPETS_BOOKMARKS_BOOKMARK_SUGGESTIONS_PROVIDER_H_
+
+#include <set>
+#include <string>
+
+#include "components/bookmarks/browser/bookmark_model_observer.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_status.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace gfx {
+class Image;
+} // namespace gfx
+
+namespace ntp_snippets {
+
+// Provides content suggestions from the bookmarks model.
+class BookmarkSuggestionsProvider : public ContentSuggestionsProvider,
+ public bookmarks::BookmarkModelObserver {
+ public:
+ BookmarkSuggestionsProvider(ContentSuggestionsProvider::Observer* observer,
+ CategoryFactory* category_factory,
+ bookmarks::BookmarkModel* bookmark_model,
+ PrefService* pref_service);
+ ~BookmarkSuggestionsProvider() override;
+
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ private:
+ // ContentSuggestionsProvider implementation.
+ CategoryStatus GetCategoryStatus(Category category) override;
+ CategoryInfo GetCategoryInfo(Category category) override;
+ void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+ void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) override;
+ void ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) override;
+ void ClearCachedSuggestions(Category category) override;
+ void GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) override;
+ void ClearDismissedSuggestionsForDebugging(Category category) override;
+
+ // bookmarks::BookmarkModelObserver implementation.
+ void BookmarkModelLoaded(bookmarks::BookmarkModel* model,
+ bool ids_reassigned) override;
+ void OnWillChangeBookmarkMetaInfo(
+ bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* node) override;
+ void BookmarkMetaInfoChanged(bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* node) override;
+
+ void BookmarkNodeMoved(bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* old_parent,
+ int old_index,
+ const bookmarks::BookmarkNode* new_parent,
+ int new_index) override {}
+ void BookmarkNodeAdded(bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* parent,
+ int index) override;
+ void BookmarkNodeRemoved(
+ bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* parent,
+ int old_index,
+ const bookmarks::BookmarkNode* node,
+ const std::set<GURL>& no_longer_bookmarked) override;
+ void BookmarkNodeChanged(bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* node) override {}
+ void BookmarkNodeFaviconChanged(
+ bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* node) override {}
+ void BookmarkNodeChildrenReordered(
+ bookmarks::BookmarkModel* model,
+ const bookmarks::BookmarkNode* node) override {}
+ void BookmarkAllUserNodesRemoved(
+ bookmarks::BookmarkModel* model,
+ const std::set<GURL>& removed_urls) override {}
+
+ ContentSuggestion ConvertBookmark(const bookmarks::BookmarkNode* bookmark);
+
+ // The actual method to fetch bookmarks - follows each call to FetchBookmarks
+ // but not sooner than the BookmarkModel gets loaded.
+ void FetchBookmarksInternal();
+
+ // Queries the BookmarkModel for recently visited bookmarks and pushes the
+ // results to the ContentSuggestionService. The actual fetching does not
+ // happen before the Bookmark model gets loaded.
+ void FetchBookmarks();
+
+ // Updates the |category_status_| and notifies the |observer_|, if necessary.
+ void NotifyStatusChanged(CategoryStatus new_status);
+
+ CategoryStatus category_status_;
+ const Category provided_category_;
+ bookmarks::BookmarkModel* bookmark_model_;
+ bool fetch_requested_;
+
+ base::Time node_to_change_last_visit_date_;
+ base::Time end_of_list_last_visit_date_;
+
+ // TODO(jkrcal): Remove this field and the pref after M55.
+ // For six weeks after first installing M54, this is true and the
+ // fallback implemented in BookmarkLastVisitUtils is activated.
+ bool creation_date_fallback_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkSuggestionsProvider);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_BOOKMARKS_BOOKMARK_SUGGESTIONS_PROVIDER_H_
diff --git a/chromium/components/ntp_snippets/category.cc b/chromium/components/ntp_snippets/category.cc
new file mode 100644
index 00000000000..abc86ab9f2c
--- /dev/null
+++ b/chromium/components/ntp_snippets/category.cc
@@ -0,0 +1,37 @@
+// 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 "components/ntp_snippets/category.h"
+
+#include "base/logging.h"
+
+namespace ntp_snippets {
+
+Category::Category(int id) : id_(id) {}
+
+bool Category::IsKnownCategory(KnownCategories known_category) const {
+ DCHECK_NE(known_category, KnownCategories::LOCAL_CATEGORIES_COUNT);
+ DCHECK_NE(known_category, KnownCategories::REMOTE_CATEGORIES_OFFSET);
+ return id_ == static_cast<int>(known_category);
+}
+
+bool operator==(const Category& left, const Category& right) {
+ return left.id() == right.id();
+}
+
+bool operator!=(const Category& left, const Category& right) {
+ return !(left == right);
+}
+
+bool Category::CompareByID::operator()(const Category& left,
+ const Category& right) const {
+ return left.id() < right.id();
+}
+
+std::ostream& operator<<(std::ostream& os, const Category& obj) {
+ os << obj.id();
+ return os;
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/category.h b/chromium/components/ntp_snippets/category.h
new file mode 100644
index 00000000000..0220cb54e97
--- /dev/null
+++ b/chromium/components/ntp_snippets/category.h
@@ -0,0 +1,89 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NTP_SNIPPETS_CATEGORY_H_
+#define COMPONENTS_NTP_SNIPPETS_CATEGORY_H_
+
+#include <ostream>
+
+namespace ntp_snippets {
+
+class CategoryFactory;
+
+// These are the categories that the client knows about.
+// The values before LOCAL_CATEGORIES_COUNT are the categories that are provided
+// locally on the device. Categories provided by the server (IDs strictly larger
+// than REMOTE_CATEGORIES_OFFSET) only need to be hard-coded here if they need
+// to be recognized by the client implementation.
+// NOTE: These are persisted, so don't reorder or remove values, and insert new
+// values only in the appropriate places marked below.
+// On Android builds, a Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp.snippets
+enum class KnownCategories {
+ // Pages recently downloaded during normal navigation.
+ RECENT_TABS,
+
+ // Pages downloaded by the user for offline consumption.
+ DOWNLOADS,
+
+ // Recently used bookmarks.
+ BOOKMARKS,
+
+ // Physical Web page available in the vicinity.
+ PHYSICAL_WEB_PAGES,
+
+ // Pages recently browsed to on other devices.
+ FOREIGN_TABS,
+ // INSERT NEW LOCAL CATEGORIES HERE!
+
+ // Follows the last local category.
+ LOCAL_CATEGORIES_COUNT,
+
+ // Remote categories come after this.
+ REMOTE_CATEGORIES_OFFSET = 10000,
+
+ // Articles for you.
+ ARTICLES,
+ // INSERT NEW REMOTE CATEGORIES HERE!
+};
+
+// A category groups ContentSuggestions which belong together. Use the
+// CategoryFactory to obtain instances.
+class Category {
+ public:
+ // An arbitrary but consistent ordering. Can be used to look up categories in
+ // a std::map, but should not be used to order categories for other purposes.
+ struct CompareByID;
+
+ // Returns a non-negative identifier that is unique for the category and can
+ // be converted back to a Category instance using
+ // |CategoryFactory::FromIDValue(id)|.
+ int id() const { return id_; }
+
+ // Returns whether this category matches the given |known_category|.
+ bool IsKnownCategory(KnownCategories known_category) const;
+
+ private:
+ friend class CategoryFactory;
+
+ explicit Category(int id);
+
+ int id_;
+
+ // Allow copy and assignment.
+};
+
+bool operator==(const Category& left, const Category& right);
+
+bool operator!=(const Category& left, const Category& right);
+
+struct Category::CompareByID {
+ bool operator()(const Category& left, const Category& right) const;
+};
+
+std::ostream& operator<<(std::ostream& os, const Category& obj);
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_CATEGORY_H_
diff --git a/chromium/components/ntp_snippets/category_factory.cc b/chromium/components/ntp_snippets/category_factory.cc
new file mode 100644
index 00000000000..4da984e0162
--- /dev/null
+++ b/chromium/components/ntp_snippets/category_factory.cc
@@ -0,0 +1,85 @@
+// 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 "components/ntp_snippets/category_factory.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+
+namespace ntp_snippets {
+
+CategoryFactory::CategoryFactory() {
+ // Add all local categories in a fixed order.
+ AddKnownCategory(KnownCategories::DOWNLOADS);
+ AddKnownCategory(KnownCategories::RECENT_TABS);
+ AddKnownCategory(KnownCategories::FOREIGN_TABS);
+ AddKnownCategory(KnownCategories::BOOKMARKS);
+ AddKnownCategory(KnownCategories::PHYSICAL_WEB_PAGES);
+
+ DCHECK_EQ(static_cast<size_t>(KnownCategories::LOCAL_CATEGORIES_COUNT),
+ ordered_categories_.size());
+}
+
+CategoryFactory::~CategoryFactory() = default;
+
+Category CategoryFactory::FromKnownCategory(KnownCategories known_category) {
+ if (known_category < KnownCategories::LOCAL_CATEGORIES_COUNT) {
+ // Local categories should have been added already.
+ DCHECK(CategoryExists(static_cast<int>(known_category)));
+ } else {
+ DCHECK_GT(known_category, KnownCategories::REMOTE_CATEGORIES_OFFSET);
+ }
+ return InternalFromID(static_cast<int>(known_category));
+}
+
+Category CategoryFactory::FromRemoteCategory(int remote_category) {
+ DCHECK_GT(remote_category, 0);
+ return InternalFromID(
+ static_cast<int>(KnownCategories::REMOTE_CATEGORIES_OFFSET) +
+ remote_category);
+}
+
+Category CategoryFactory::FromIDValue(int id) {
+ DCHECK_GE(id, 0);
+ DCHECK(id < static_cast<int>(KnownCategories::LOCAL_CATEGORIES_COUNT) ||
+ id > static_cast<int>(KnownCategories::REMOTE_CATEGORIES_OFFSET));
+ return InternalFromID(id);
+}
+
+bool CategoryFactory::CompareCategories(const Category& left,
+ const Category& right) const {
+ if (left == right)
+ return false;
+ return std::find(ordered_categories_.begin(), ordered_categories_.end(),
+ left) < std::find(ordered_categories_.begin(),
+ ordered_categories_.end(), right);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private methods
+
+bool CategoryFactory::CategoryExists(int id) {
+ return std::find(ordered_categories_.begin(), ordered_categories_.end(),
+ Category(id)) != ordered_categories_.end();
+}
+
+void CategoryFactory::AddKnownCategory(KnownCategories known_category) {
+ InternalFromID(static_cast<int>(known_category));
+}
+
+Category CategoryFactory::InternalFromID(int id) {
+ auto it = std::find(ordered_categories_.begin(), ordered_categories_.end(),
+ Category(id));
+ if (it != ordered_categories_.end())
+ return *it;
+
+ Category category(id);
+ ordered_categories_.push_back(category);
+ return category;
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/category_factory.h b/chromium/components/ntp_snippets/category_factory.h
new file mode 100644
index 00000000000..c3941eaea2f
--- /dev/null
+++ b/chromium/components/ntp_snippets/category_factory.h
@@ -0,0 +1,61 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CATEGORY_FACTORY_H_
+#define COMPONENTS_NTP_SNIPPETS_CATEGORY_FACTORY_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/ntp_snippets/category.h"
+
+namespace ntp_snippets {
+
+// Creates and orders Category instances.
+class CategoryFactory {
+ public:
+ CategoryFactory();
+ ~CategoryFactory();
+
+ // Creates a category from a KnownCategory value. The passed |known_category|
+ // must not be one of the special values (LOCAL_CATEGORIES_COUNT or
+ // REMOTE_CATEGORIES_OFFSET).
+ Category FromKnownCategory(KnownCategories known_category);
+
+ // Creates a category from a category identifier delivered by the server.
+ // |remote_category| must be positive.
+ // Note that remote categories are ordered in the order in which they were
+ // first created by calling this method.
+ Category FromRemoteCategory(int remote_category);
+
+ // Creates a category from an ID as returned by |Category::id()|.
+ // |id| must be a non-negative value.
+ Category FromIDValue(int id);
+
+ // Compares the given categories according to a strict ordering, returning
+ // true if and only if |left| is strictly less than |right|.
+ // This method satisfies the "Compare" contract required by sort algorithms.
+ // The order is determined as follows: All local categories go first, in a
+ // specific order hard-coded in the |CategoryFactory| constructor. All remote
+ // categories follow in the order in which they were first created through
+ // |FromRemoteCategory|.
+ bool CompareCategories(const Category& left, const Category& right) const;
+
+ private:
+ bool CategoryExists(int id);
+ void AddKnownCategory(KnownCategories known_category);
+ Category InternalFromID(int id);
+
+ // Stores all known categories in the order which is also returned by
+ // |CompareCategories|.
+ std::vector<Category> ordered_categories_;
+
+ DISALLOW_COPY_AND_ASSIGN(CategoryFactory);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_CATEGORY_FACTORY_H_
diff --git a/chromium/components/ntp_snippets/category_factory_unittest.cc b/chromium/components/ntp_snippets/category_factory_unittest.cc
new file mode 100644
index 00000000000..6ffd149b79e
--- /dev/null
+++ b/chromium/components/ntp_snippets/category_factory_unittest.cc
@@ -0,0 +1,126 @@
+// 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 "components/ntp_snippets/category_factory.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "components/ntp_snippets/category.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ntp_snippets {
+
+class CategoryFactoryTest : public testing::Test {
+ public:
+ CategoryFactoryTest() : unused_remote_category_id_(1) {}
+
+ int GetUnusedRemoteCategoryID() { return unused_remote_category_id_++; }
+
+ bool CompareCategories(const Category& left, const Category& right) {
+ return factory()->CompareCategories(left, right);
+ }
+
+ void AddDummyRemoteCategories(int quantity) {
+ for (int i = 0; i < quantity; ++i) {
+ factory()->FromRemoteCategory(GetUnusedRemoteCategoryID());
+ }
+ }
+
+ CategoryFactory* factory() { return &factory_; }
+
+ private:
+ CategoryFactory factory_;
+ int unused_remote_category_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(CategoryFactoryTest);
+};
+
+TEST_F(CategoryFactoryTest,
+ FromKnownCategoryShouldReturnSameIdForSameCategories) {
+ const KnownCategories known_category = KnownCategories::BOOKMARKS;
+ Category first = factory()->FromKnownCategory(known_category);
+ Category second = factory()->FromKnownCategory(known_category);
+ EXPECT_EQ(first, second);
+}
+
+TEST_F(CategoryFactoryTest,
+ FromRemoteCategoryShouldReturnSameIdForSameCategories) {
+ const int remote_category_id = GetUnusedRemoteCategoryID();
+ Category first = factory()->FromRemoteCategory(remote_category_id);
+ Category second = factory()->FromRemoteCategory(remote_category_id);
+ EXPECT_EQ(first, second);
+}
+
+TEST_F(CategoryFactoryTest, FromRemoteCategoryOrder) {
+ const int small_id = GetUnusedRemoteCategoryID();
+ const int large_id = GetUnusedRemoteCategoryID();
+ // Categories are added in decreasing id order to test that they are not
+ // compared by id.
+ Category added_first = factory()->FromRemoteCategory(large_id);
+ Category added_second = factory()->FromRemoteCategory(small_id);
+ EXPECT_TRUE(CompareCategories(added_first, added_second));
+ EXPECT_FALSE(CompareCategories(added_second, added_first));
+}
+
+TEST_F(CategoryFactoryTest, FromIDValueReturnsSameKnownCategory) {
+ Category known_category =
+ factory()->FromKnownCategory(KnownCategories::BOOKMARKS);
+ Category known_category_by_id = factory()->FromIDValue(known_category.id());
+ EXPECT_EQ(known_category, known_category_by_id);
+}
+
+TEST_F(CategoryFactoryTest, FromIDValueReturnsSameRemoteCategory) {
+ const int remote_category_id = GetUnusedRemoteCategoryID();
+ Category remote_category = factory()->FromRemoteCategory(remote_category_id);
+ Category remote_category_by_id = factory()->FromIDValue(remote_category.id());
+ EXPECT_EQ(remote_category, remote_category_by_id);
+}
+
+TEST_F(CategoryFactoryTest, CompareCategoriesLocalBeforeRemote) {
+ const int remote_category_id = GetUnusedRemoteCategoryID();
+ Category remote_category = factory()->FromRemoteCategory(remote_category_id);
+ Category local_category =
+ factory()->FromKnownCategory(KnownCategories::BOOKMARKS);
+ EXPECT_TRUE(CompareCategories(local_category, remote_category));
+ EXPECT_FALSE(CompareCategories(remote_category, local_category));
+}
+
+TEST_F(CategoryFactoryTest, CompareCategoriesSame) {
+ const int remote_category_id = GetUnusedRemoteCategoryID();
+ Category remote_category = factory()->FromRemoteCategory(remote_category_id);
+ EXPECT_FALSE(CompareCategories(remote_category, remote_category));
+
+ Category local_category =
+ factory()->FromKnownCategory(KnownCategories::BOOKMARKS);
+ EXPECT_FALSE(CompareCategories(local_category, local_category));
+}
+
+TEST_F(CategoryFactoryTest, CompareCategoriesAfterAddingNew) {
+ AddDummyRemoteCategories(3);
+
+ Category consequtive_first =
+ factory()->FromRemoteCategory(GetUnusedRemoteCategoryID());
+ Category consequtive_second =
+ factory()->FromRemoteCategory(GetUnusedRemoteCategoryID());
+
+ AddDummyRemoteCategories(3);
+
+ Category nonconsequtive_first =
+ factory()->FromRemoteCategory(GetUnusedRemoteCategoryID());
+ AddDummyRemoteCategories(3);
+ Category nonconsequtive_second =
+ factory()->FromRemoteCategory(GetUnusedRemoteCategoryID());
+
+ AddDummyRemoteCategories(3);
+
+ EXPECT_TRUE(CompareCategories(consequtive_first, consequtive_second));
+ EXPECT_FALSE(CompareCategories(consequtive_second, consequtive_first));
+
+ EXPECT_TRUE(CompareCategories(nonconsequtive_first, nonconsequtive_second));
+ EXPECT_FALSE(CompareCategories(nonconsequtive_second, nonconsequtive_first));
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/category_info.cc b/chromium/components/ntp_snippets/category_info.cc
new file mode 100644
index 00000000000..4037551f5e8
--- /dev/null
+++ b/chromium/components/ntp_snippets/category_info.cc
@@ -0,0 +1,20 @@
+// 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 "components/ntp_snippets/category_info.h"
+
+namespace ntp_snippets {
+
+CategoryInfo::CategoryInfo(const base::string16& title,
+ ContentSuggestionsCardLayout card_layout,
+ bool has_more_button,
+ bool show_if_empty)
+ : title_(title),
+ card_layout_(card_layout),
+ has_more_button_(has_more_button),
+ show_if_empty_(show_if_empty) {}
+
+CategoryInfo::~CategoryInfo() = default;
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/category_info.h b/chromium/components/ntp_snippets/category_info.h
new file mode 100644
index 00000000000..1a659ed232d
--- /dev/null
+++ b/chromium/components/ntp_snippets/category_info.h
@@ -0,0 +1,60 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CATEGORY_INFO_H_
+#define COMPONENTS_NTP_SNIPPETS_CATEGORY_INFO_H_
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+
+namespace ntp_snippets {
+
+// On Android builds, a Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp.snippets
+enum class ContentSuggestionsCardLayout {
+ // Uses all fields.
+ FULL_CARD,
+
+ // No snippet_text and no thumbnail image.
+ MINIMAL_CARD
+};
+
+// Contains static meta information about a Category.
+class CategoryInfo {
+ public:
+ CategoryInfo(const base::string16& title,
+ ContentSuggestionsCardLayout card_layout,
+ bool has_more_button,
+ bool show_if_empty);
+ CategoryInfo(CategoryInfo&&) = default;
+ CategoryInfo& operator=(CategoryInfo&&) = default;
+
+ ~CategoryInfo();
+
+ // Localized title of the category.
+ const base::string16& title() const { return title_; }
+
+ // Layout of the cards to be used to display suggestions in this category.
+ ContentSuggestionsCardLayout card_layout() const { return card_layout_; }
+
+ // Whether the category supports a "More" button. The button either triggers
+ // a fixed action (like opening a native page) or, if there is no such fixed
+ // action, it queries the provider for more suggestions.
+ bool has_more_button() const { return has_more_button_; }
+
+ // Whether this category should be shown if it offers no suggestions.
+ bool show_if_empty() const { return show_if_empty_; }
+
+ private:
+ base::string16 title_;
+ ContentSuggestionsCardLayout card_layout_;
+ bool has_more_button_;
+ bool show_if_empty_;
+
+ DISALLOW_COPY_AND_ASSIGN(CategoryInfo);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_CATEGORY_INFO_H_
diff --git a/chromium/components/ntp_snippets/category_status.cc b/chromium/components/ntp_snippets/category_status.cc
new file mode 100644
index 00000000000..5afa5100d5e
--- /dev/null
+++ b/chromium/components/ntp_snippets/category_status.cc
@@ -0,0 +1,21 @@
+// 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 "components/ntp_snippets/category_status.h"
+
+namespace ntp_snippets {
+
+bool IsCategoryStatusAvailable(CategoryStatus status) {
+ // Note: This code is duplicated in SnippetsBridge.java.
+ return status == CategoryStatus::AVAILABLE_LOADING ||
+ status == CategoryStatus::AVAILABLE;
+}
+
+bool IsCategoryStatusInitOrAvailable(CategoryStatus status) {
+ // Note: This code is duplicated in SnippetsBridge.java.
+ return status == CategoryStatus::INITIALIZING ||
+ IsCategoryStatusAvailable(status);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/category_status.h b/chromium/components/ntp_snippets/category_status.h
new file mode 100644
index 00000000000..2f6c7cdfbd9
--- /dev/null
+++ b/chromium/components/ntp_snippets/category_status.h
@@ -0,0 +1,52 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CATEGORY_STATUS_H_
+#define COMPONENTS_NTP_SNIPPETS_CATEGORY_STATUS_H_
+
+namespace ntp_snippets {
+
+// Represents the status of a category of content suggestions.
+// On Android builds, a Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp.snippets
+enum class CategoryStatus {
+ // The provider is still initializing and it is not yet determined whether
+ // content suggestions will be available or not.
+ INITIALIZING,
+
+ // Content suggestions are available (though the list of available suggestions
+ // may be empty simply because there are no reasonable suggestions to be made
+ // at the moment).
+ AVAILABLE,
+ // Content suggestions are provided but not yet loaded.
+ AVAILABLE_LOADING,
+
+ // There is no provider that provides suggestions for this category.
+ NOT_PROVIDED,
+ // The entire content suggestions feature has explicitly been disabled as part
+ // of the service configuration.
+ ALL_SUGGESTIONS_EXPLICITLY_DISABLED,
+ // Content suggestions from a specific category have been disabled as part of
+ // the service configuration.
+ CATEGORY_EXPLICITLY_DISABLED,
+
+ // Content suggestions are not available because the user is not signed in.
+ SIGNED_OUT,
+
+ // Content suggestions are not available because an error occurred when
+ // loading or updating them.
+ LOADING_ERROR
+};
+
+// Determines whether the given status is one of the AVAILABLE statuses.
+bool IsCategoryStatusAvailable(CategoryStatus status);
+
+// Determines whether the given status is INITIALIZING or one of the AVAILABLE
+// statuses. All of these statuses have in common that there is or will soon be
+// content.
+bool IsCategoryStatusInitOrAvailable(CategoryStatus status);
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_CATEGORY_STATUS_H_
diff --git a/chromium/components/ntp_snippets/content_suggestion.cc b/chromium/components/ntp_snippets/content_suggestion.cc
index 0fa4f0cd9dd..44524cb8bf9 100644
--- a/chromium/components/ntp_snippets/content_suggestion.cc
+++ b/chromium/components/ntp_snippets/content_suggestion.cc
@@ -6,13 +6,32 @@
namespace ntp_snippets {
-ContentSuggestion::ContentSuggestion(
- const std::string& id,
- const ContentSuggestionsProviderType provider,
- const ContentSuggestionCategory category,
- const GURL& url)
- : id_(id), provider_(provider), category_(category), url_(url), score_(0) {}
-
-ContentSuggestion::~ContentSuggestion() {}
+bool ContentSuggestion::ID::operator==(const ID& rhs) const {
+ return category_ == rhs.category_ &&
+ id_within_category_ == rhs.id_within_category_;
+}
+
+bool ContentSuggestion::ID::operator!=(const ID& rhs) const {
+ return !(*this == rhs);
+}
+
+ContentSuggestion::ContentSuggestion(ID id, const GURL& url)
+ : id_(id), url_(url), score_(0) {}
+
+ContentSuggestion::ContentSuggestion(Category category,
+ const std::string& id_within_category,
+ const GURL& url)
+ : id_(category, id_within_category), url_(url), score_(0) {}
+
+ContentSuggestion::ContentSuggestion(ContentSuggestion&&) = default;
+
+ContentSuggestion& ContentSuggestion::operator=(ContentSuggestion&&) = default;
+
+ContentSuggestion::~ContentSuggestion() = default;
+
+std::ostream& operator<<(std::ostream& os, ContentSuggestion::ID id) {
+ os << id.category() << "|" << id.id_within_category();
+ return os;
+}
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/content_suggestion.h b/chromium/components/ntp_snippets/content_suggestion.h
index 60ab27285d3..bf8442cfa10 100644
--- a/chromium/components/ntp_snippets/content_suggestion.h
+++ b/chromium/components/ntp_snippets/content_suggestion.h
@@ -5,41 +5,54 @@
#ifndef COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_H_
#define COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_H_
-#include <memory>
#include <string>
-#include <vector>
#include "base/macros.h"
+#include "base/strings/string16.h"
#include "base/time/time.h"
-#include "components/ntp_snippets/content_suggestion_category.h"
-#include "components/ntp_snippets/content_suggestions_provider_type.h"
+#include "components/ntp_snippets/category.h"
#include "url/gurl.h"
namespace ntp_snippets {
// A content suggestion for the new tab page, which can be an article or an
// offline page, for example.
-// NOTE: This class is not yet in use, please use NTPSnippet for now
-// (see ntp_snippet.h).
class ContentSuggestion {
public:
- ContentSuggestion(const std::string& id,
- const ContentSuggestionsProviderType provider,
- const ContentSuggestionCategory category,
- const GURL& url);
+ class ID {
+ public:
+ ID(Category category, const std::string& id_within_category)
+ : category_(category), id_within_category_(id_within_category) {}
- ~ContentSuggestion();
+ Category category() const { return category_; }
+
+ const std::string& id_within_category() const {
+ return id_within_category_;
+ }
- // An ID for identifying the suggestion. The ID is unique among all
- // suggestions from the same provider, so to determine a globally unique
- // identifier, combine this ID with the provider type.
- const std::string& id() const { return id_; }
+ bool operator==(const ID& rhs) const;
+ bool operator!=(const ID& rhs) const;
- // The provider that created this suggestion.
- ContentSuggestionsProviderType provider() const { return provider_; }
+ private:
+ Category category_;
+ std::string id_within_category_;
- // The category that this suggestion belongs to.
- ContentSuggestionCategory category() const { return category_; }
+ // Allow copy and assignment.
+ };
+
+ // Creates a new ContentSuggestion. The caller must ensure that the |id|
+ // passed in here is unique application-wide.
+ ContentSuggestion(ID id, const GURL& url);
+ ContentSuggestion(Category category,
+ const std::string& id_within_category,
+ const GURL& url);
+ ContentSuggestion(ContentSuggestion&&);
+ ContentSuggestion& operator=(ContentSuggestion&&);
+
+ ~ContentSuggestion();
+
+ // An ID for identifying the suggestion. The ID is unique application-wide.
+ const ID& id() const { return id_; }
// The normal content URL where the content referenced by the suggestion can
// be accessed.
@@ -51,12 +64,12 @@ class ContentSuggestion {
void set_amp_url(const GURL& amp_url) { amp_url_ = amp_url; }
// Title of the suggestion.
- const std::string& title() const { return title_; }
- void set_title(const std::string& title) { title_ = title; }
+ const base::string16& title() const { return title_; }
+ void set_title(const base::string16& title) { title_ = title; }
// Summary or relevant textual extract from the content.
- const std::string& snippet_text() const { return snippet_text_; }
- void set_snippet_text(const std::string& snippet_text) {
+ const base::string16& snippet_text() const { return snippet_text_; }
+ void set_snippet_text(const base::string16& snippet_text) {
snippet_text_ = snippet_text;
}
@@ -67,12 +80,12 @@ class ContentSuggestion {
}
// The name of the source/publisher of this suggestion.
- const std::string& publisher_name() const { return publisher_name_; }
- void set_publisher_name(const std::string& publisher_name) {
+ const base::string16& publisher_name() const { return publisher_name_; }
+ void set_publisher_name(const base::string16& publisher_name) {
publisher_name_ = publisher_name;
}
- // TODO(pke) Remove the score from the ContentSuggestion class. The UI only
+ // TODO(pke): Remove the score from the ContentSuggestion class. The UI only
// uses it to track user clicks (histogram data). Instead, the providers
// should be informed about clicks and do appropriate logging themselves.
// IMPORTANT: The score may simply be 0 for suggestions from providers which
@@ -81,21 +94,20 @@ class ContentSuggestion {
void set_score(float score) { score_ = score; }
private:
- std::string id_;
- ContentSuggestionsProviderType provider_;
- ContentSuggestionCategory category_;
+ ID id_;
GURL url_;
GURL amp_url_;
- std::string title_;
- std::string snippet_text_;
- GURL salient_image_url_;
+ base::string16 title_;
+ base::string16 snippet_text_;
base::Time publish_date_;
- std::string publisher_name_;
+ base::string16 publisher_name_;
float score_;
DISALLOW_COPY_AND_ASSIGN(ContentSuggestion);
};
+std::ostream& operator<<(std::ostream& os, ContentSuggestion::ID id);
+
} // namespace ntp_snippets
#endif // COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_H_
diff --git a/chromium/components/ntp_snippets/content_suggestion_category.h b/chromium/components/ntp_snippets/content_suggestion_category.h
deleted file mode 100644
index 80268fbe140..00000000000
--- a/chromium/components/ntp_snippets/content_suggestion_category.h
+++ /dev/null
@@ -1,18 +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 COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_CATEGORY_H_
-#define COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_CATEGORY_H_
-
-namespace ntp_snippets {
-
-// The category of a content suggestion. Note that even though these categories
-// currently match the provider types, a provider type is not limited to provide
-// suggestions of a single (fixed) category only. The category is used to
-// determine where to display the suggestion.
-enum class ContentSuggestionCategory : int { ARTICLE };
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_CATEGORY_H_
diff --git a/chromium/components/ntp_snippets/content_suggestions_metrics.cc b/chromium/components/ntp_snippets/content_suggestions_metrics.cc
new file mode 100644
index 00000000000..4117fae096b
--- /dev/null
+++ b/chromium/components/ntp_snippets/content_suggestions_metrics.cc
@@ -0,0 +1,272 @@
+// 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 "components/ntp_snippets/content_suggestions_metrics.h"
+
+#include <string>
+#include <type_traits>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/template_util.h"
+
+namespace ntp_snippets {
+namespace metrics {
+
+namespace {
+
+const int kMaxSuggestionsPerCategory = 10;
+const int kMaxSuggestionsTotal = 50;
+
+const char kHistogramCountOnNtpOpened[] =
+ "NewTabPage.ContentSuggestions.CountOnNtpOpened";
+const char kHistogramShown[] = "NewTabPage.ContentSuggestions.Shown";
+const char kHistogramShownAge[] = "NewTabPage.ContentSuggestions.ShownAge";
+const char kHistogramShownScore[] = "NewTabPage.ContentSuggestions.ShownScore";
+const char kHistogramOpened[] = "NewTabPage.ContentSuggestions.Opened";
+const char kHistogramOpenedAge[] = "NewTabPage.ContentSuggestions.OpenedAge";
+const char kHistogramOpenedScore[] =
+ "NewTabPage.ContentSuggestions.OpenedScore";
+const char kHistogramOpenDisposition[] =
+ "NewTabPage.ContentSuggestions.OpenDisposition";
+const char kHistogramMenuOpened[] = "NewTabPage.ContentSuggestions.MenuOpened";
+const char kHistogramMenuOpenedAge[] =
+ "NewTabPage.ContentSuggestions.MenuOpenedAge";
+const char kHistogramMenuOpenedScore[] =
+ "NewTabPage.ContentSuggestions.MenuOpenedScore";
+const char kHistogramDismissedUnvisited[] =
+ "NewTabPage.ContentSuggestions.DismissedUnvisited";
+const char kHistogramDismissedVisited[] =
+ "NewTabPage.ContentSuggestions.DismissedVisited";
+const char kHistogramVisitDuration[] =
+ "NewTabPage.ContentSuggestions.VisitDuration";
+const char kHistogramMoreButtonShown[] =
+ "NewTabPage.ContentSuggestions.MoreButtonShown";
+const char kHistogramMoreButtonClicked[] =
+ "NewTabPage.ContentSuggestions.MoreButtonClicked";
+
+const char kPerCategoryHistogramFormat[] = "%s.%s";
+
+// Each suffix here should correspond to an entry under histogram suffix
+// ContentSuggestionCategory in histograms.xml.
+std::string GetCategorySuffix(Category category) {
+ static_assert(
+ std::is_same<decltype(category.id()), typename base::underlying_type<
+ KnownCategories>::type>::value,
+ "KnownCategories must have the same underlying type as category.id()");
+ // Note: Since the underlying type of KnownCategories is int, it's legal to
+ // cast from int to KnownCategories, even if the given value isn't listed in
+ // the enumeration. The switch still makes sure that all known values are
+ // listed here.
+ KnownCategories known_category = static_cast<KnownCategories>(category.id());
+ switch (known_category) {
+ case KnownCategories::RECENT_TABS:
+ return "RecentTabs";
+ case KnownCategories::DOWNLOADS:
+ return "Downloads";
+ case KnownCategories::BOOKMARKS:
+ return "Bookmarks";
+ case KnownCategories::PHYSICAL_WEB_PAGES:
+ return "PhysicalWeb";
+ case KnownCategories::FOREIGN_TABS:
+ return "ForeignTabs";
+ case KnownCategories::ARTICLES:
+ return "Articles";
+ case KnownCategories::LOCAL_CATEGORIES_COUNT:
+ case KnownCategories::REMOTE_CATEGORIES_OFFSET:
+ NOTREACHED();
+ break;
+ }
+ // All other (unknown) categories go into a single "Experimental" bucket.
+ return "Experimental";
+}
+
+std::string GetCategoryHistogramName(const char* base_name, Category category) {
+ return base::StringPrintf(kPerCategoryHistogramFormat, base_name,
+ GetCategorySuffix(category).c_str());
+}
+
+// This corresponds to UMA_HISTOGRAM_ENUMERATION, for use with dynamic histogram
+// names.
+void UmaHistogramEnumeration(const std::string& name,
+ int value,
+ int boundary_value) {
+ base::LinearHistogram::FactoryGet(
+ name, 1, boundary_value, boundary_value + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag)
+ ->Add(value);
+}
+
+// This corresponds to UMA_HISTOGRAM_LONG_TIMES for use with dynamic histogram
+// names.
+void UmaHistogramLongTimes(const std::string& name,
+ const base::TimeDelta& value) {
+ base::Histogram::FactoryTimeGet(
+ name, base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1),
+ 50, base::HistogramBase::kUmaTargetedHistogramFlag)
+ ->AddTime(value);
+}
+
+// This corresponds to UMA_HISTOGRAM_CUSTOM_TIMES (with min/max appropriate
+// for the age of suggestions) for use with dynamic histogram names.
+void UmaHistogramAge(const std::string& name, const base::TimeDelta& value) {
+ base::Histogram::FactoryTimeGet(
+ name, base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(7), 100,
+ base::HistogramBase::kUmaTargetedHistogramFlag)
+ ->AddTime(value);
+}
+
+// This corresponds to UMA_HISTOGRAM_CUSTOM_COUNTS (with min/max appropriate
+// for the score of suggestions) for use with dynamic histogram names.
+void UmaHistogramScore(const std::string& name, float value) {
+ base::Histogram::FactoryGet(name, 1, 100000, 50,
+ base::HistogramBase::kUmaTargetedHistogramFlag)
+ ->Add(value);
+}
+
+void LogCategoryHistogramEnumeration(const char* base_name,
+ Category category,
+ int value,
+ int boundary_value) {
+ std::string name = GetCategoryHistogramName(base_name, category);
+ // Since the histogram name is dynamic, we can't use the regular macro.
+ UmaHistogramEnumeration(name, value, boundary_value);
+}
+
+void LogCategoryHistogramLongTimes(const char* base_name,
+ Category category,
+ const base::TimeDelta& value) {
+ std::string name = GetCategoryHistogramName(base_name, category);
+ // Since the histogram name is dynamic, we can't use the regular macro.
+ UmaHistogramLongTimes(name, value);
+}
+
+void LogCategoryHistogramAge(const char* base_name,
+ Category category,
+ const base::TimeDelta& value) {
+ std::string name = GetCategoryHistogramName(base_name, category);
+ // Since the histogram name is dynamic, we can't use the regular macro.
+ UmaHistogramAge(name, value);
+}
+
+void LogCategoryHistogramScore(const char* base_name,
+ Category category,
+ float score) {
+ std::string name = GetCategoryHistogramName(base_name, category);
+ // Since the histogram name is dynamic, we can't use the regular macro.
+ UmaHistogramScore(name, score);
+}
+
+} // namespace
+
+void OnPageShown(
+ const std::vector<std::pair<Category, int>>& suggestions_per_category) {
+ int suggestions_total = 0;
+ for (const std::pair<Category, int>& item : suggestions_per_category) {
+ LogCategoryHistogramEnumeration(kHistogramCountOnNtpOpened, item.first,
+ item.second, kMaxSuggestionsPerCategory);
+ suggestions_total += item.second;
+ }
+
+ UMA_HISTOGRAM_ENUMERATION(kHistogramCountOnNtpOpened, suggestions_total,
+ kMaxSuggestionsTotal);
+}
+
+void OnSuggestionShown(int global_position,
+ Category category,
+ int category_position,
+ base::Time publish_date,
+ float score) {
+ UMA_HISTOGRAM_ENUMERATION(kHistogramShown, global_position,
+ kMaxSuggestionsTotal);
+ LogCategoryHistogramEnumeration(kHistogramShown, category, category_position,
+ kMaxSuggestionsPerCategory);
+
+ base::TimeDelta age = base::Time::Now() - publish_date;
+ LogCategoryHistogramAge(kHistogramShownAge, category, age);
+
+ LogCategoryHistogramScore(kHistogramShownScore, category, score);
+}
+
+void OnSuggestionOpened(int global_position,
+ Category category,
+ int category_position,
+ base::Time publish_date,
+ float score,
+ WindowOpenDisposition disposition) {
+ UMA_HISTOGRAM_ENUMERATION(kHistogramOpened, global_position,
+ kMaxSuggestionsTotal);
+ LogCategoryHistogramEnumeration(kHistogramOpened, category, category_position,
+ kMaxSuggestionsPerCategory);
+
+ base::TimeDelta age = base::Time::Now() - publish_date;
+ LogCategoryHistogramAge(kHistogramOpenedAge, category, age);
+
+ LogCategoryHistogramScore(kHistogramOpenedScore, category, score);
+
+ UMA_HISTOGRAM_ENUMERATION(
+ kHistogramOpenDisposition, static_cast<int>(disposition),
+ static_cast<int>(WindowOpenDisposition::MAX_VALUE) + 1);
+ LogCategoryHistogramEnumeration(
+ kHistogramOpenDisposition, category, static_cast<int>(disposition),
+ static_cast<int>(WindowOpenDisposition::MAX_VALUE) + 1);
+}
+
+void OnSuggestionMenuOpened(int global_position,
+ Category category,
+ int category_position,
+ base::Time publish_date,
+ float score) {
+ UMA_HISTOGRAM_ENUMERATION(kHistogramMenuOpened, global_position,
+ kMaxSuggestionsTotal);
+ LogCategoryHistogramEnumeration(kHistogramMenuOpened, category,
+ category_position,
+ kMaxSuggestionsPerCategory);
+
+ base::TimeDelta age = base::Time::Now() - publish_date;
+ LogCategoryHistogramAge(kHistogramMenuOpenedAge, category, age);
+
+ LogCategoryHistogramScore(kHistogramMenuOpenedScore, category, score);
+}
+
+void OnSuggestionDismissed(int global_position,
+ Category category,
+ int category_position,
+ bool visited) {
+ if (visited) {
+ UMA_HISTOGRAM_ENUMERATION(kHistogramDismissedVisited, global_position,
+ kMaxSuggestionsTotal);
+ LogCategoryHistogramEnumeration(kHistogramDismissedVisited, category,
+ category_position,
+ kMaxSuggestionsPerCategory);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION(kHistogramDismissedUnvisited, global_position,
+ kMaxSuggestionsTotal);
+ LogCategoryHistogramEnumeration(kHistogramDismissedUnvisited, category,
+ category_position,
+ kMaxSuggestionsPerCategory);
+ }
+}
+
+void OnSuggestionTargetVisited(Category category, base::TimeDelta visit_time) {
+ LogCategoryHistogramLongTimes(kHistogramVisitDuration, category, visit_time);
+}
+
+void OnMoreButtonShown(Category category, int position) {
+ // The "more" card can appear in addition to the actual suggestions, so add
+ // one extra bucket to this histogram.
+ LogCategoryHistogramEnumeration(kHistogramMoreButtonShown, category, position,
+ kMaxSuggestionsPerCategory + 1);
+}
+
+void OnMoreButtonClicked(Category category, int position) {
+ // The "more" card can appear in addition to the actual suggestions, so add
+ // one extra bucket to this histogram.
+ LogCategoryHistogramEnumeration(kHistogramMoreButtonClicked, category,
+ position, kMaxSuggestionsPerCategory + 1);
+}
+
+} // namespace metrics
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/content_suggestions_metrics.h b/chromium/components/ntp_snippets/content_suggestions_metrics.h
new file mode 100644
index 00000000000..cba4846e19c
--- /dev/null
+++ b/chromium/components/ntp_snippets/content_suggestions_metrics.h
@@ -0,0 +1,56 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_METRICS_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_METRICS_H_
+
+#include <utility>
+#include <vector>
+
+#include "base/time/time.h"
+#include "components/ntp_snippets/category.h"
+#include "ui/base/window_open_disposition.h"
+
+namespace ntp_snippets {
+namespace metrics {
+
+void OnPageShown(
+ const std::vector<std::pair<Category, int>>& suggestions_per_category);
+
+// Should only be called once per NTP for each suggestion.
+void OnSuggestionShown(int global_position,
+ Category category,
+ int category_position,
+ base::Time publish_date,
+ float score);
+
+void OnSuggestionOpened(int global_position,
+ Category category,
+ int category_position,
+ base::Time publish_date,
+ float score,
+ WindowOpenDisposition disposition);
+
+void OnSuggestionMenuOpened(int global_position,
+ Category category,
+ int category_position,
+ base::Time publish_date,
+ float score);
+
+void OnSuggestionDismissed(int global_position,
+ Category category,
+ int category_position,
+ bool visited);
+
+void OnSuggestionTargetVisited(Category category, base::TimeDelta visit_time);
+
+// Should only be called once per NTP for each "more" button.
+void OnMoreButtonShown(Category category, int position);
+
+void OnMoreButtonClicked(Category category, int position);
+
+} // namespace metrics
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_SERVICE_H_
diff --git a/chromium/components/ntp_snippets/content_suggestions_provider.cc b/chromium/components/ntp_snippets/content_suggestions_provider.cc
new file mode 100644
index 00000000000..34896577b98
--- /dev/null
+++ b/chromium/components/ntp_snippets/content_suggestions_provider.cc
@@ -0,0 +1,18 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/ntp_snippets/content_suggestions_provider.h"
+
+#include "components/ntp_snippets/category_factory.h"
+
+namespace ntp_snippets {
+
+ContentSuggestionsProvider::ContentSuggestionsProvider(
+ Observer* observer,
+ CategoryFactory* category_factory)
+ : observer_(observer), category_factory_(category_factory) {}
+
+ContentSuggestionsProvider::~ContentSuggestionsProvider() = default;
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/content_suggestions_provider.h b/chromium/components/ntp_snippets/content_suggestions_provider.h
new file mode 100644
index 00000000000..f6741356d66
--- /dev/null
+++ b/chromium/components/ntp_snippets/content_suggestions_provider.h
@@ -0,0 +1,148 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_PROVIDER_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_PROVIDER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_info.h"
+#include "components/ntp_snippets/category_status.h"
+#include "components/ntp_snippets/content_suggestion.h"
+
+namespace gfx {
+class Image;
+} // namespace gfx
+
+namespace ntp_snippets {
+
+// Provides content suggestions from one particular source.
+// A provider can provide suggestions for multiple ContentSuggestionCategories,
+// but for every category that it provides, it will be the only provider in the
+// system which provides suggestions for that category.
+// Providers are created by the ContentSuggestionsServiceFactory and owned and
+// shut down by the ContentSuggestionsService.
+class ContentSuggestionsProvider {
+ public:
+ using ImageFetchedCallback = base::Callback<void(const gfx::Image&)>;
+ using DismissedSuggestionsCallback = base::Callback<void(
+ std::vector<ContentSuggestion> dismissed_suggestions)>;
+
+ // The observer of a provider is notified when new data is available.
+ class Observer {
+ public:
+ // Called when the available content changed.
+ // If a provider provides suggestions for multiple categories, this callback
+ // is called once per category. The |suggestions| parameter always contains
+ // the full list of currently available suggestions for that category, i.e.,
+ // an empty list will remove all suggestions from the given category. Note
+ // that to clear them from the UI immediately, the provider needs to change
+ // the status of the respective category. If the given |category| is not
+ // known yet, the calling |provider| will be registered as its provider.
+ virtual void OnNewSuggestions(
+ ContentSuggestionsProvider* provider,
+ Category category,
+ std::vector<ContentSuggestion> suggestions) = 0;
+
+ // Called when the status of a category changed, including when it is added.
+ // If |new_status| is NOT_PROVIDED, the calling provider must be the one
+ // that currently provides the |category|, and the category is unregistered
+ // without clearing the UI.
+ // If |new_status| is any other value, it must match the value that is
+ // currently returned from the provider's |GetCategoryStatus(category)|. In
+ // case the given |category| is not known yet, the calling |provider| will
+ // be registered as its provider. Whenever the status changes to an
+ // unavailable status, all suggestions in that category must immediately be
+ // removed from all caches and from the UI, but the provider remains
+ // registered.
+ virtual void OnCategoryStatusChanged(ContentSuggestionsProvider* provider,
+ Category category,
+ CategoryStatus new_status) = 0;
+
+ // Called when a suggestion has been invalidated. It will not be provided
+ // through |OnNewSuggestions| anymore, is not supported by
+ // |FetchSuggestionImage| or |DismissSuggestion| anymore, and should
+ // immediately be cleared from the UI and caches. This happens, for example,
+ // when the content that the suggestion refers to is gone.
+ // Note that this event may be fired even if the corresponding category is
+ // not currently AVAILABLE, because open UIs may still be showing the
+ // suggestion that is to be removed. This event may also be fired for
+ // |suggestion_id|s that never existed and should be ignored in that case.
+ virtual void OnSuggestionInvalidated(
+ ContentSuggestionsProvider* provider,
+ const ContentSuggestion::ID& suggestion_id) = 0;
+ };
+
+ virtual ~ContentSuggestionsProvider();
+
+ // Determines the status of the given |category|, see CategoryStatus.
+ virtual CategoryStatus GetCategoryStatus(Category category) = 0;
+
+ // Returns the meta information for the given |category|.
+ virtual CategoryInfo GetCategoryInfo(Category category) = 0;
+
+ // Dismisses the suggestion with the given ID. A provider needs to ensure that
+ // a once-dismissed suggestion is never delivered again (through the
+ // Observer). The provider must not call Observer::OnSuggestionsChanged if the
+ // removal of the dismissed suggestion is the only change.
+ virtual void DismissSuggestion(
+ const ContentSuggestion::ID& suggestion_id) = 0;
+
+ // Fetches the image for the suggestion with the given ID and returns it
+ // through the callback. This fetch may occur locally or from the internet.
+ // If that suggestion doesn't exist, doesn't have an image or if the fetch
+ // fails, the callback gets a null image. The callback will not be called
+ // synchronously.
+ virtual void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) = 0;
+
+ // Removes history from the specified time range where the URL matches the
+ // |filter|. The data removed depends on the provider. Note that the
+ // data outside the time range may be deleted, for example suggestions, which
+ // are based on history from that time range. Providers should immediately
+ // clear any data related to history from the specified time range where the
+ // URL matches the |filter|.
+ virtual void ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) = 0;
+
+ // Clears all caches for the given category, so that the next fetch starts
+ // from scratch.
+ virtual void ClearCachedSuggestions(Category category) = 0;
+
+ // Used only for debugging purposes. Retrieves suggestions for the given
+ // |category| that have previously been dismissed and are still stored in the
+ // provider. If the provider doesn't store dismissed suggestions for the given
+ // |category|, it always calls the callback with an empty vector. The callback
+ // may be called synchronously.
+ virtual void GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) = 0;
+
+ // Used only for debugging purposes. Clears the cache of dismissed
+ // suggestions for the given |category|, if present, so that no suggestions
+ // are suppressed. This does not necessarily make previously dismissed
+ // suggestions reappear, as they may have been permanently deleted, depending
+ // on the provider implementation.
+ virtual void ClearDismissedSuggestionsForDebugging(Category category) = 0;
+
+ protected:
+ ContentSuggestionsProvider(Observer* observer,
+ CategoryFactory* category_factory);
+
+ Observer* observer() const { return observer_; }
+ CategoryFactory* category_factory() const { return category_factory_; }
+
+ private:
+ Observer* observer_;
+ CategoryFactory* category_factory_;
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_PROVIDER_H_
diff --git a/chromium/components/ntp_snippets/content_suggestions_provider_type.h b/chromium/components/ntp_snippets/content_suggestions_provider_type.h
deleted file mode 100644
index 9825de8bcd7..00000000000
--- a/chromium/components/ntp_snippets/content_suggestions_provider_type.h
+++ /dev/null
@@ -1,19 +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 COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_PROVIDER_TYPE_H_
-#define COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_PROVIDER_TYPE_H_
-
-namespace ntp_snippets {
-
-// A type of content suggestion provider. For each of these types, there will be
-// at most one provider instance registered and running. Note that these
-// provider types do not necessarily match the suggestion categories. The
-// provider type is used to identify the source of a suggestion and to direct
-// calls from the UI like discarding back to the right provider.
-enum class ContentSuggestionsProviderType : int { ARTICLES };
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_PROVIDER_TYPE_H_
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.cc b/chromium/components/ntp_snippets/content_suggestions_service.cc
new file mode 100644
index 00000000000..75b4f7db182
--- /dev/null
+++ b/chromium/components/ntp_snippets/content_suggestions_service.cc
@@ -0,0 +1,337 @@
+// 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 "components/ntp_snippets/content_suggestions_service.h"
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "ui/gfx/image/image.h"
+
+namespace ntp_snippets {
+
+ContentSuggestionsService::ContentSuggestionsService(
+ State state,
+ history::HistoryService* history_service,
+ PrefService* pref_service)
+ : state_(state),
+ history_service_observer_(this),
+ ntp_snippets_service_(nullptr),
+ user_classifier_(pref_service) {
+ // Can be null in tests.
+ if (history_service)
+ history_service_observer_.Add(history_service);
+}
+
+ContentSuggestionsService::~ContentSuggestionsService() = default;
+
+void ContentSuggestionsService::Shutdown() {
+ ntp_snippets_service_ = nullptr;
+ suggestions_by_category_.clear();
+ providers_by_category_.clear();
+ categories_.clear();
+ providers_.clear();
+ state_ = State::DISABLED;
+ FOR_EACH_OBSERVER(Observer, observers_, ContentSuggestionsServiceShutdown());
+}
+
+CategoryStatus ContentSuggestionsService::GetCategoryStatus(
+ Category category) const {
+ if (state_ == State::DISABLED) {
+ return CategoryStatus::ALL_SUGGESTIONS_EXPLICITLY_DISABLED;
+ }
+
+ auto iterator = providers_by_category_.find(category);
+ if (iterator == providers_by_category_.end())
+ return CategoryStatus::NOT_PROVIDED;
+
+ return iterator->second->GetCategoryStatus(category);
+}
+
+base::Optional<CategoryInfo> ContentSuggestionsService::GetCategoryInfo(
+ Category category) const {
+ auto iterator = providers_by_category_.find(category);
+ if (iterator == providers_by_category_.end())
+ return base::Optional<CategoryInfo>();
+ return iterator->second->GetCategoryInfo(category);
+}
+
+const std::vector<ContentSuggestion>&
+ContentSuggestionsService::GetSuggestionsForCategory(Category category) const {
+ auto iterator = suggestions_by_category_.find(category);
+ if (iterator == suggestions_by_category_.end())
+ return no_suggestions_;
+ return iterator->second;
+}
+
+void ContentSuggestionsService::FetchSuggestionImage(
+ const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) {
+ if (!providers_by_category_.count(suggestion_id.category())) {
+ LOG(WARNING) << "Requested image for suggestion " << suggestion_id
+ << " for unavailable category " << suggestion_id.category();
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, gfx::Image()));
+ return;
+ }
+ providers_by_category_[suggestion_id.category()]->FetchSuggestionImage(
+ suggestion_id, callback);
+}
+
+void ContentSuggestionsService::ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) {
+ for (const auto& provider : providers_) {
+ provider->ClearHistory(begin, end, filter);
+ }
+}
+
+void ContentSuggestionsService::ClearAllCachedSuggestions() {
+ suggestions_by_category_.clear();
+ for (const auto& category_provider_pair : providers_by_category_) {
+ category_provider_pair.second->ClearCachedSuggestions(
+ category_provider_pair.first);
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnNewSuggestions(category_provider_pair.first));
+ }
+}
+
+void ContentSuggestionsService::ClearCachedSuggestions(Category category) {
+ suggestions_by_category_[category].clear();
+ auto iterator = providers_by_category_.find(category);
+ if (iterator != providers_by_category_.end())
+ iterator->second->ClearCachedSuggestions(category);
+}
+
+void ContentSuggestionsService::GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) {
+ auto iterator = providers_by_category_.find(category);
+ if (iterator != providers_by_category_.end())
+ iterator->second->GetDismissedSuggestionsForDebugging(category, callback);
+ else
+ callback.Run(std::vector<ContentSuggestion>());
+}
+
+void ContentSuggestionsService::ClearDismissedSuggestionsForDebugging(
+ Category category) {
+ auto iterator = providers_by_category_.find(category);
+ if (iterator != providers_by_category_.end())
+ iterator->second->ClearDismissedSuggestionsForDebugging(category);
+}
+
+void ContentSuggestionsService::DismissSuggestion(
+ const ContentSuggestion::ID& suggestion_id) {
+ if (!providers_by_category_.count(suggestion_id.category())) {
+ LOG(WARNING) << "Dismissed suggestion " << suggestion_id
+ << " for unavailable category " << suggestion_id.category();
+ return;
+ }
+ providers_by_category_[suggestion_id.category()]->DismissSuggestion(
+ suggestion_id);
+
+ // Remove the suggestion locally.
+ bool removed = RemoveSuggestionByID(suggestion_id);
+ DCHECK(removed) << "The dismissed suggestion " << suggestion_id
+ << " has already been removed. Providers must not call"
+ << " OnNewSuggestions in response to DismissSuggestion.";
+}
+
+void ContentSuggestionsService::DismissCategory(Category category) {
+ auto providers_it = providers_by_category_.find(category);
+ if (providers_it == providers_by_category_.end())
+ return;
+
+ providers_by_category_.erase(providers_it);
+ categories_.erase(
+ std::find(categories_.begin(), categories_.end(), category));
+}
+
+void ContentSuggestionsService::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ContentSuggestionsService::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void ContentSuggestionsService::RegisterProvider(
+ std::unique_ptr<ContentSuggestionsProvider> provider) {
+ DCHECK(state_ == State::ENABLED);
+ providers_.push_back(std::move(provider));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private methods
+
+void ContentSuggestionsService::OnNewSuggestions(
+ ContentSuggestionsProvider* provider,
+ Category category,
+ std::vector<ContentSuggestion> suggestions) {
+ if (RegisterCategoryIfRequired(provider, category))
+ NotifyCategoryStatusChanged(category);
+
+ if (!IsCategoryStatusAvailable(provider->GetCategoryStatus(category))) {
+ // A provider shouldn't send us suggestions while it's not available.
+ DCHECK(suggestions.empty());
+ return;
+ }
+
+ suggestions_by_category_[category] = std::move(suggestions);
+
+ // The positioning of the bookmarks category depends on whether it's empty.
+ // TODO(treib): Remove this temporary hack, crbug.com/640568.
+ if (category.IsKnownCategory(KnownCategories::BOOKMARKS))
+ SortCategories();
+
+ FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions(category));
+}
+
+void ContentSuggestionsService::OnCategoryStatusChanged(
+ ContentSuggestionsProvider* provider,
+ Category category,
+ CategoryStatus new_status) {
+ if (!IsCategoryStatusAvailable(new_status)) {
+ suggestions_by_category_.erase(category);
+ }
+ if (new_status == CategoryStatus::NOT_PROVIDED) {
+ DCHECK(providers_by_category_.find(category) !=
+ providers_by_category_.end());
+ DCHECK_EQ(provider, providers_by_category_.find(category)->second);
+ DismissCategory(category);
+ } else {
+ RegisterCategoryIfRequired(provider, category);
+ DCHECK_EQ(new_status, provider->GetCategoryStatus(category));
+ }
+ NotifyCategoryStatusChanged(category);
+}
+
+void ContentSuggestionsService::OnSuggestionInvalidated(
+ ContentSuggestionsProvider* provider,
+ const ContentSuggestion::ID& suggestion_id) {
+ RemoveSuggestionByID(suggestion_id);
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnSuggestionInvalidated(suggestion_id));
+}
+
+// history::HistoryServiceObserver implementation.
+void ContentSuggestionsService::OnURLsDeleted(
+ history::HistoryService* history_service,
+ bool all_history,
+ bool expired,
+ const history::URLRows& deleted_rows,
+ const std::set<GURL>& favicon_urls) {
+ // We don't care about expired entries.
+ if (expired)
+ return;
+
+ // Redirect to ClearHistory().
+ if (all_history) {
+ base::Time begin = base::Time();
+ base::Time end = base::Time::Max();
+ base::Callback<bool(const GURL& url)> filter =
+ base::Bind([](const GURL& url) { return true; });
+ ClearHistory(begin, end, filter);
+ } else {
+ if (deleted_rows.empty())
+ return;
+
+ base::Time begin = deleted_rows[0].last_visit();
+ base::Time end = deleted_rows[0].last_visit();
+ std::set<GURL> deleted_urls;
+ for (const history::URLRow& row : deleted_rows) {
+ if (row.last_visit() < begin)
+ begin = row.last_visit();
+ if (row.last_visit() > end)
+ end = row.last_visit();
+ deleted_urls.insert(row.url());
+ }
+ base::Callback<bool(const GURL& url)> filter = base::Bind(
+ [](const std::set<GURL>& set, const GURL& url) {
+ return set.count(url) != 0;
+ },
+ deleted_urls);
+ ClearHistory(begin, end, filter);
+ }
+}
+
+void ContentSuggestionsService::HistoryServiceBeingDeleted(
+ history::HistoryService* history_service) {
+ history_service_observer_.RemoveAll();
+}
+
+bool ContentSuggestionsService::RegisterCategoryIfRequired(
+ ContentSuggestionsProvider* provider,
+ Category category) {
+ auto it = providers_by_category_.find(category);
+ if (it != providers_by_category_.end()) {
+ DCHECK_EQ(it->second, provider);
+ return false;
+ }
+
+ providers_by_category_[category] = provider;
+ categories_.push_back(category);
+ SortCategories();
+ if (IsCategoryStatusAvailable(provider->GetCategoryStatus(category))) {
+ suggestions_by_category_.insert(
+ std::make_pair(category, std::vector<ContentSuggestion>()));
+ }
+ return true;
+}
+
+bool ContentSuggestionsService::RemoveSuggestionByID(
+ const ContentSuggestion::ID& suggestion_id) {
+ std::vector<ContentSuggestion>* suggestions =
+ &suggestions_by_category_[suggestion_id.category()];
+ auto position =
+ std::find_if(suggestions->begin(), suggestions->end(),
+ [&suggestion_id](const ContentSuggestion& suggestion) {
+ return suggestion_id == suggestion.id();
+ });
+ if (position == suggestions->end())
+ return false;
+ suggestions->erase(position);
+
+ // The positioning of the bookmarks category depends on whether it's empty.
+ // TODO(treib): Remove this temporary hack, crbug.com/640568.
+ if (suggestion_id.category().IsKnownCategory(KnownCategories::BOOKMARKS))
+ SortCategories();
+
+ return true;
+}
+
+void ContentSuggestionsService::NotifyCategoryStatusChanged(Category category) {
+ FOR_EACH_OBSERVER(
+ Observer, observers_,
+ OnCategoryStatusChanged(category, GetCategoryStatus(category)));
+}
+
+void ContentSuggestionsService::SortCategories() {
+ auto it = suggestions_by_category_.find(
+ category_factory_.FromKnownCategory(KnownCategories::BOOKMARKS));
+ bool bookmarks_empty =
+ (it == suggestions_by_category_.end() || it->second.empty());
+ std::sort(
+ categories_.begin(), categories_.end(),
+ [this, bookmarks_empty](const Category& left, const Category& right) {
+ // If the bookmarks section is empty, put it at the end.
+ // TODO(treib): This is a temporary hack, see crbug.com/640568.
+ if (bookmarks_empty) {
+ if (left.IsKnownCategory(KnownCategories::BOOKMARKS))
+ return false;
+ if (right.IsKnownCategory(KnownCategories::BOOKMARKS))
+ return true;
+ }
+ return category_factory_.CompareCategories(left, right);
+ });
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.h b/chromium/components/ntp_snippets/content_suggestions_service.h
new file mode 100644
index 00000000000..987a9fb4acc
--- /dev/null
+++ b/chromium/components/ntp_snippets/content_suggestions_service.h
@@ -0,0 +1,273 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_SERVICE_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_SERVICE_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/observer_list.h"
+#include "base/optional.h"
+#include "base/scoped_observer.h"
+#include "base/time/time.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/history_service_observer.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/category_status.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/ntp_snippets/user_classifier.h"
+
+class PrefService;
+
+namespace gfx {
+class Image;
+} // namespace gfx
+
+namespace ntp_snippets {
+
+class NTPSnippetsService;
+
+// Retrieves suggestions from a number of ContentSuggestionsProviders and serves
+// them grouped into categories. There can be at most one provider per category.
+class ContentSuggestionsService : public KeyedService,
+ public ContentSuggestionsProvider::Observer,
+ public history::HistoryServiceObserver {
+ public:
+ using ImageFetchedCallback = base::Callback<void(const gfx::Image&)>;
+ using DismissedSuggestionsCallback = base::Callback<void(
+ std::vector<ContentSuggestion> dismissed_suggestions)>;
+
+ class Observer {
+ public:
+ // Fired every time the service receives a new set of data for the given
+ // |category|, replacing any previously available data (though in most cases
+ // there will be an overlap and only a few changes within the data). The new
+ // data is then available through |GetSuggestionsForCategory(category)|.
+ virtual void OnNewSuggestions(Category category) = 0;
+
+ // Fired when the status of a suggestions category changed. When the status
+ // changes to an unavailable status, the suggestions of the respective
+ // category have been invalidated, which means that they must no longer be
+ // displayed to the user. The UI must immediately clear any suggestions of
+ // that category.
+ virtual void OnCategoryStatusChanged(Category category,
+ CategoryStatus new_status) = 0;
+
+ // Fired when a suggestion has been invalidated. The UI must immediately
+ // clear the suggestion even from open NTPs. Invalidation happens, for
+ // example, when the content that the suggestion refers to is gone.
+ // Note that this event may be fired even if the corresponding category is
+ // not currently AVAILABLE, because open UIs may still be showing the
+ // suggestion that is to be removed. This event may also be fired for
+ // |suggestion_id|s that never existed and should be ignored in that case.
+ virtual void OnSuggestionInvalidated(
+ const ContentSuggestion::ID& suggestion_id) = 0;
+
+ // Sent when the service is shutting down. After the service has shut down,
+ // it will not provide any data anymore, though calling the getters is still
+ // safe.
+ virtual void ContentSuggestionsServiceShutdown() = 0;
+
+ protected:
+ virtual ~Observer() = default;
+ };
+
+ enum State {
+ ENABLED,
+ DISABLED,
+ };
+
+ ContentSuggestionsService(State state,
+ history::HistoryService* history_service,
+ PrefService* pref_service);
+ ~ContentSuggestionsService() override;
+
+ // Inherited from KeyedService.
+ void Shutdown() override;
+
+ State state() { return state_; }
+
+ // Gets all categories for which a provider is registered. The categories
+ // may or may not be available, see |GetCategoryStatus()|.
+ const std::vector<Category>& GetCategories() const { return categories_; }
+
+ // Gets the status of a category.
+ CategoryStatus GetCategoryStatus(Category category) const;
+
+ // Gets the meta information of a category.
+ base::Optional<CategoryInfo> GetCategoryInfo(Category category) const;
+
+ // Gets the available suggestions for a category. The result is empty if the
+ // category is available and empty, but also if the category is unavailable
+ // for any reason, see |GetCategoryStatus()|.
+ const std::vector<ContentSuggestion>& GetSuggestionsForCategory(
+ Category category) const;
+
+ // Fetches the image for the suggestion with the given |suggestion_id| and
+ // runs the |callback|. If that suggestion doesn't exist or the fetch fails,
+ // the callback gets an empty image. The callback will not be called
+ // synchronously.
+ void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback);
+
+ // Dismisses the suggestion with the given |suggestion_id|, if it exists.
+ // This will not trigger an update through the observers.
+ void DismissSuggestion(const ContentSuggestion::ID& suggestion_id);
+
+ // Dismisses the given |category|, if it exists.
+ // This will not trigger an update through the observers.
+ void DismissCategory(Category category);
+
+ // Observer accessors.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Registers a new ContentSuggestionsProvider. It must be ensured that at most
+ // one provider is registered for every category and that this method is
+ // called only once per provider.
+ void RegisterProvider(std::unique_ptr<ContentSuggestionsProvider> provider);
+
+ // Removes history from the specified time range where the URL matches the
+ // |filter| from all providers. The data removed depends on the provider. Note
+ // that the data outside the time range may be deleted, for example
+ // suggestions, which are based on history from that time range. Providers
+ // should immediately clear any data related to history from the specified
+ // time range where the URL matches the |filter|.
+ void ClearHistory(base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter);
+
+ // Removes all suggestions from all caches or internal stores in all
+ // providers. See |ClearCachedSuggestions|.
+ void ClearAllCachedSuggestions();
+
+ // Removes all suggestions of the given |category| from all caches or internal
+ // stores in the service and the corresponding provider. It does, however, not
+ // remove any suggestions from the provider's sources, so if its configuration
+ // hasn't changed, it might return the same results when it fetches the next
+ // time. In particular, calling this method will not mark any suggestions as
+ // dismissed.
+ void ClearCachedSuggestions(Category category);
+
+ // Only for debugging use through the internals page.
+ // Retrieves suggestions of the given |category| that have previously been
+ // dismissed and are still stored in the respective provider. If the
+ // provider doesn't store dismissed suggestions, the callback receives an
+ // empty vector. The callback may be called synchronously.
+ void GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback);
+
+ // Only for debugging use through the internals page. Some providers
+ // internally store a list of dismissed suggestions to prevent them from
+ // reappearing. This function clears all suggestions of the given |category|
+ // from such lists, making dismissed suggestions reappear (if the provider
+ // supports it).
+ void ClearDismissedSuggestionsForDebugging(Category category);
+
+ CategoryFactory* category_factory() { return &category_factory_; }
+
+ // The reference to the NTPSnippetsService provider should only be set by the
+ // factory and only be used for scheduling, periodic fetching and debugging.
+ NTPSnippetsService* ntp_snippets_service() { return ntp_snippets_service_; }
+ void set_ntp_snippets_service(NTPSnippetsService* ntp_snippets_service) {
+ ntp_snippets_service_ = ntp_snippets_service;
+ }
+
+ UserClassifier* user_classifier() { return &user_classifier_; }
+
+ private:
+ friend class ContentSuggestionsServiceTest;
+
+ // Implementation of ContentSuggestionsProvider::Observer.
+ void OnNewSuggestions(ContentSuggestionsProvider* provider,
+ Category category,
+ std::vector<ContentSuggestion> suggestions) override;
+ void OnCategoryStatusChanged(ContentSuggestionsProvider* provider,
+ Category category,
+ CategoryStatus new_status) override;
+ void OnSuggestionInvalidated(
+ ContentSuggestionsProvider* provider,
+ const ContentSuggestion::ID& suggestion_id) override;
+
+ // history::HistoryServiceObserver implementation.
+ void OnURLsDeleted(history::HistoryService* history_service,
+ bool all_history,
+ bool expired,
+ const history::URLRows& deleted_rows,
+ const std::set<GURL>& favicon_urls) override;
+ void HistoryServiceBeingDeleted(
+ history::HistoryService* history_service) override;
+
+ // Registers the given |provider| for the given |category|, unless it is
+ // already registered. Returns true if the category was newly registered or
+ // false if it was present before.
+ bool RegisterCategoryIfRequired(ContentSuggestionsProvider* provider,
+ Category category);
+
+ // Removes a suggestion from the local store |suggestions_by_category_|, if it
+ // exists. Returns true if a suggestion was removed.
+ bool RemoveSuggestionByID(const ContentSuggestion::ID& suggestion_id);
+
+ // Fires the OnCategoryStatusChanged event for the given |category|.
+ void NotifyCategoryStatusChanged(Category category);
+
+ void SortCategories();
+
+ // Whether the content suggestions feature is enabled.
+ State state_;
+
+ // Provides new and existing categories and an order for them.
+ CategoryFactory category_factory_;
+
+ // All registered providers, owned by the service.
+ std::vector<std::unique_ptr<ContentSuggestionsProvider>> providers_;
+
+ // All registered categories and their providers. A provider may be contained
+ // multiple times, if it provides multiple categories. The keys of this map
+ // are exactly the entries of |categories_| and the values are a subset of
+ // |providers_|.
+ std::map<Category, ContentSuggestionsProvider*, Category::CompareByID>
+ providers_by_category_;
+
+ // All current suggestion categories, in an order determined by the
+ // |category_factory_|. This vector contains exactly the same categories as
+ // |providers_by_category_|.
+ std::vector<Category> categories_;
+
+ // All current suggestions grouped by category. This contains an entry for
+ // every category in |categories_| whose status is an available status. It may
+ // contain an empty vector if the category is available but empty (or still
+ // loading).
+ std::map<Category, std::vector<ContentSuggestion>, Category::CompareByID>
+ suggestions_by_category_;
+
+ // Observer for the HistoryService. All providers are notified when history is
+ // deleted.
+ ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
+ history_service_observer_;
+
+ base::ObserverList<Observer> observers_;
+
+ const std::vector<ContentSuggestion> no_suggestions_;
+
+ // Keep a direct reference to this special provider to redirect scheduling,
+ // background fetching and debugging calls to it. If the NTPSnippetsService is
+ // loaded, it is also present in |providers_|, otherwise this is a nullptr.
+ NTPSnippetsService* ntp_snippets_service_;
+
+ UserClassifier user_classifier_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentSuggestionsService);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTIONS_SERVICE_H_
diff --git a/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc b/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
new file mode 100644
index 00000000000..a2245bfd6cb
--- /dev/null
+++ b/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
@@ -0,0 +1,604 @@
+// 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 "components/ntp_snippets/content_suggestions_service.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/ntp_snippets/category_info.h"
+#include "components/ntp_snippets/category_status.h"
+#include "components/ntp_snippets/content_suggestion.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/image/image.h"
+
+using testing::ElementsAre;
+using testing::Eq;
+using testing::InvokeWithoutArgs;
+using testing::IsEmpty;
+using testing::Mock;
+using testing::Property;
+using testing::_;
+
+namespace ntp_snippets {
+
+namespace {
+
+class MockProvider : public ContentSuggestionsProvider {
+ public:
+ MockProvider(Observer* observer,
+ CategoryFactory* category_factory,
+ const std::vector<Category>& provided_categories)
+ : ContentSuggestionsProvider(observer, category_factory) {
+ SetProvidedCategories(provided_categories);
+ }
+
+ void SetProvidedCategories(const std::vector<Category>& provided_categories) {
+ statuses_.clear();
+ provided_categories_ = provided_categories;
+ for (Category category : provided_categories) {
+ statuses_[category.id()] = CategoryStatus::AVAILABLE;
+ }
+ }
+
+ CategoryStatus GetCategoryStatus(Category category) override {
+ return statuses_[category.id()];
+ }
+
+ CategoryInfo GetCategoryInfo(Category category) override {
+ return CategoryInfo(base::ASCIIToUTF16("Section title"),
+ ContentSuggestionsCardLayout::FULL_CARD, true, true);
+ }
+
+ void FireSuggestionsChanged(
+ Category category,
+ std::vector<ContentSuggestion> suggestions) {
+ observer()->OnNewSuggestions(this, category, std::move(suggestions));
+ }
+
+ void FireCategoryStatusChanged(Category category, CategoryStatus new_status) {
+ statuses_[category.id()] = new_status;
+ observer()->OnCategoryStatusChanged(this, category, new_status);
+ }
+
+ void FireCategoryStatusChangedWithCurrentStatus(Category category) {
+ observer()->OnCategoryStatusChanged(this, category,
+ statuses_[category.id()]);
+ }
+
+ void FireSuggestionInvalidated(const ContentSuggestion::ID& suggestion_id) {
+ observer()->OnSuggestionInvalidated(this, suggestion_id);
+ }
+
+ MOCK_METHOD3(ClearHistory,
+ void(base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter));
+ MOCK_METHOD1(ClearCachedSuggestions, void(Category category));
+ MOCK_METHOD2(GetDismissedSuggestionsForDebugging,
+ void(Category category,
+ const DismissedSuggestionsCallback& callback));
+ MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category category));
+ MOCK_METHOD1(DismissSuggestion,
+ void(const ContentSuggestion::ID& suggestion_id));
+ MOCK_METHOD2(FetchSuggestionImage,
+ void(const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback));
+
+ private:
+ std::vector<Category> provided_categories_;
+ std::map<int, CategoryStatus> statuses_;
+};
+
+class MockServiceObserver : public ContentSuggestionsService::Observer {
+ public:
+ MockServiceObserver() = default;
+ ~MockServiceObserver() override = default;
+
+ MOCK_METHOD1(OnNewSuggestions, void(Category category));
+ MOCK_METHOD2(OnCategoryStatusChanged,
+ void(Category changed_category, CategoryStatus new_status));
+ MOCK_METHOD1(OnSuggestionInvalidated,
+ void(const ContentSuggestion::ID& suggestion_id));
+ MOCK_METHOD0(ContentSuggestionsServiceShutdown, void());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockServiceObserver);
+};
+
+} // namespace
+
+class ContentSuggestionsServiceTest : public testing::Test {
+ public:
+ ContentSuggestionsServiceTest() {}
+
+ void SetUp() override {
+ CreateContentSuggestionsService(ContentSuggestionsService::State::ENABLED);
+ }
+
+ void TearDown() override {
+ service_->Shutdown();
+ service_.reset();
+ }
+
+ // Verifies that exactly the suggestions with the given |numbers| are
+ // returned by the service for the given |category|.
+ void ExpectThatSuggestionsAre(Category category, std::vector<int> numbers) {
+ std::vector<Category> categories = service()->GetCategories();
+ auto position = std::find(categories.begin(), categories.end(), category);
+ if (!numbers.empty()) {
+ EXPECT_NE(categories.end(), position);
+ }
+
+ for (const auto& suggestion :
+ service()->GetSuggestionsForCategory(category)) {
+ std::string id_within_category = suggestion.id().id_within_category();
+ int id;
+ ASSERT_TRUE(base::StringToInt(id_within_category, &id));
+ auto position = std::find(numbers.begin(), numbers.end(), id);
+ if (position == numbers.end()) {
+ ADD_FAILURE() << "Unexpected suggestion with ID " << id;
+ } else {
+ numbers.erase(position);
+ }
+ }
+ for (int number : numbers) {
+ ADD_FAILURE() << "Suggestion number " << number
+ << " not present, though expected";
+ }
+ }
+
+ const std::map<Category, ContentSuggestionsProvider*, Category::CompareByID>&
+ providers() {
+ return service()->providers_by_category_;
+ }
+
+ CategoryFactory* category_factory() { return service()->category_factory(); }
+
+ Category FromKnownCategory(KnownCategories known_category) {
+ return service()->category_factory()->FromKnownCategory(known_category);
+ }
+
+ Category FromRemoteCategory(int remote_category) {
+ return service()->category_factory()->FromRemoteCategory(remote_category);
+ }
+
+ MockProvider* RegisterProvider(Category provided_category) {
+ return RegisterProvider(std::vector<Category>({provided_category}));
+ }
+
+ MockProvider* RegisterProvider(
+ const std::vector<Category>& provided_categories) {
+ std::unique_ptr<MockProvider> provider = base::MakeUnique<MockProvider>(
+ service(), category_factory(), provided_categories);
+ MockProvider* result = provider.get();
+ service()->RegisterProvider(std::move(provider));
+ return result;
+ }
+
+ MOCK_METHOD1(OnImageFetched, void(const gfx::Image&));
+
+ protected:
+ void CreateContentSuggestionsService(
+ ContentSuggestionsService::State enabled) {
+ ASSERT_FALSE(service_);
+ service_.reset(new ContentSuggestionsService(enabled,
+ nullptr /* history_service */,
+ nullptr /* pref_service */));
+ }
+
+ ContentSuggestionsService* service() { return service_.get(); }
+
+ // Returns a suggestion instance for testing.
+ ContentSuggestion CreateSuggestion(Category category, int number) {
+ return ContentSuggestion(
+ category, base::IntToString(number),
+ GURL("http://testsuggestion/" + base::IntToString(number)));
+ }
+
+ std::vector<ContentSuggestion> CreateSuggestions(
+ Category category,
+ const std::vector<int>& numbers) {
+ std::vector<ContentSuggestion> result;
+ for (int number : numbers) {
+ result.push_back(CreateSuggestion(category, number));
+ }
+ return result;
+ }
+
+ private:
+ std::unique_ptr<ContentSuggestionsService> service_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentSuggestionsServiceTest);
+};
+
+class ContentSuggestionsServiceDisabledTest
+ : public ContentSuggestionsServiceTest {
+ public:
+ void SetUp() override {
+ CreateContentSuggestionsService(ContentSuggestionsService::State::DISABLED);
+ }
+};
+
+TEST_F(ContentSuggestionsServiceTest, ShouldRegisterProviders) {
+ EXPECT_THAT(service()->state(),
+ Eq(ContentSuggestionsService::State::ENABLED));
+ Category articles_category = FromKnownCategory(KnownCategories::ARTICLES);
+ Category offline_pages_category =
+ FromKnownCategory(KnownCategories::DOWNLOADS);
+ ASSERT_THAT(providers(), IsEmpty());
+ EXPECT_THAT(service()->GetCategories(), IsEmpty());
+ EXPECT_THAT(service()->GetCategoryStatus(articles_category),
+ Eq(CategoryStatus::NOT_PROVIDED));
+ EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category),
+ Eq(CategoryStatus::NOT_PROVIDED));
+
+ MockProvider* provider1 = RegisterProvider(articles_category);
+ provider1->FireCategoryStatusChangedWithCurrentStatus(articles_category);
+ EXPECT_THAT(providers().count(offline_pages_category), Eq(0ul));
+ ASSERT_THAT(providers().count(articles_category), Eq(1ul));
+ EXPECT_THAT(providers().at(articles_category), Eq(provider1));
+ EXPECT_THAT(providers().size(), Eq(1ul));
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(articles_category));
+ EXPECT_THAT(service()->GetCategoryStatus(articles_category),
+ Eq(CategoryStatus::AVAILABLE));
+ EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category),
+ Eq(CategoryStatus::NOT_PROVIDED));
+
+ MockProvider* provider2 = RegisterProvider(offline_pages_category);
+ provider2->FireCategoryStatusChangedWithCurrentStatus(offline_pages_category);
+ ASSERT_THAT(providers().count(offline_pages_category), Eq(1ul));
+ EXPECT_THAT(providers().at(articles_category), Eq(provider1));
+ ASSERT_THAT(providers().count(articles_category), Eq(1ul));
+ EXPECT_THAT(providers().at(offline_pages_category), Eq(provider2));
+ EXPECT_THAT(providers().size(), Eq(2ul));
+ EXPECT_THAT(service()->GetCategories(),
+ ElementsAre(offline_pages_category, articles_category));
+ EXPECT_THAT(service()->GetCategoryStatus(articles_category),
+ Eq(CategoryStatus::AVAILABLE));
+ EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category),
+ Eq(CategoryStatus::AVAILABLE));
+}
+
+TEST_F(ContentSuggestionsServiceDisabledTest, ShouldDoNothingWhenDisabled) {
+ Category articles_category = FromKnownCategory(KnownCategories::ARTICLES);
+ Category offline_pages_category =
+ FromKnownCategory(KnownCategories::DOWNLOADS);
+ EXPECT_THAT(service()->state(),
+ Eq(ContentSuggestionsService::State::DISABLED));
+ EXPECT_THAT(providers(), IsEmpty());
+ EXPECT_THAT(service()->GetCategoryStatus(articles_category),
+ Eq(CategoryStatus::ALL_SUGGESTIONS_EXPLICITLY_DISABLED));
+ EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category),
+ Eq(CategoryStatus::ALL_SUGGESTIONS_EXPLICITLY_DISABLED));
+ EXPECT_THAT(service()->GetCategories(), IsEmpty());
+ EXPECT_THAT(service()->GetSuggestionsForCategory(articles_category),
+ IsEmpty());
+}
+
+TEST_F(ContentSuggestionsServiceTest, ShouldRedirectFetchSuggestionImage) {
+ Category articles_category = FromKnownCategory(KnownCategories::ARTICLES);
+ Category offline_pages_category =
+ FromKnownCategory(KnownCategories::DOWNLOADS);
+ MockProvider* provider1 = RegisterProvider(articles_category);
+ MockProvider* provider2 = RegisterProvider(offline_pages_category);
+
+ provider1->FireSuggestionsChanged(articles_category,
+ CreateSuggestions(articles_category, {1}));
+ ContentSuggestion::ID suggestion_id(articles_category, "1");
+
+ EXPECT_CALL(*provider1, FetchSuggestionImage(suggestion_id, _));
+ EXPECT_CALL(*provider2, FetchSuggestionImage(_, _)).Times(0);
+ service()->FetchSuggestionImage(
+ suggestion_id, base::Bind(&ContentSuggestionsServiceTest::OnImageFetched,
+ base::Unretained(this)));
+}
+
+TEST_F(ContentSuggestionsServiceTest,
+ ShouldCallbackEmptyImageForUnavailableProvider) {
+ // Setup the current thread's MessageLoop.
+ base::MessageLoop message_loop;
+
+ base::RunLoop run_loop;
+ // Assuming there will never be a category with the id below.
+ ContentSuggestion::ID suggestion_id(category_factory()->FromIDValue(21563),
+ "TestID");
+ EXPECT_CALL(*this, OnImageFetched(Property(&gfx::Image::IsEmpty, Eq(true))))
+ .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+ service()->FetchSuggestionImage(
+ suggestion_id, base::Bind(&ContentSuggestionsServiceTest::OnImageFetched,
+ base::Unretained(this)));
+ run_loop.Run();
+}
+
+TEST_F(ContentSuggestionsServiceTest, ShouldRedirectDismissSuggestion) {
+ Category articles_category = FromKnownCategory(KnownCategories::ARTICLES);
+ Category offline_pages_category =
+ FromKnownCategory(KnownCategories::DOWNLOADS);
+ MockProvider* provider1 = RegisterProvider(articles_category);
+ MockProvider* provider2 = RegisterProvider(offline_pages_category);
+
+ provider2->FireSuggestionsChanged(
+ offline_pages_category, CreateSuggestions(offline_pages_category, {11}));
+ ContentSuggestion::ID suggestion_id(offline_pages_category, "11");
+
+ EXPECT_CALL(*provider1, DismissSuggestion(_)).Times(0);
+ EXPECT_CALL(*provider2, DismissSuggestion(suggestion_id));
+ service()->DismissSuggestion(suggestion_id);
+}
+
+TEST_F(ContentSuggestionsServiceTest, ShouldRedirectSuggestionInvalidated) {
+ Category articles_category = FromKnownCategory(KnownCategories::ARTICLES);
+
+ MockProvider* provider = RegisterProvider(articles_category);
+ MockServiceObserver observer;
+ service()->AddObserver(&observer);
+
+ provider->FireSuggestionsChanged(
+ articles_category, CreateSuggestions(articles_category, {11, 12, 13}));
+ ExpectThatSuggestionsAre(articles_category, {11, 12, 13});
+
+ ContentSuggestion::ID suggestion_id(articles_category, "12");
+ EXPECT_CALL(observer, OnSuggestionInvalidated(suggestion_id));
+ provider->FireSuggestionInvalidated(suggestion_id);
+ ExpectThatSuggestionsAre(articles_category, {11, 13});
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Unknown IDs must be forwarded (though no change happens to the service's
+ // internal data structures) because previously opened UIs, which can still
+ // show the invalidated suggestion, must be notified.
+ ContentSuggestion::ID unknown_id(articles_category, "1234");
+ EXPECT_CALL(observer, OnSuggestionInvalidated(unknown_id));
+ provider->FireSuggestionInvalidated(unknown_id);
+ ExpectThatSuggestionsAre(articles_category, {11, 13});
+ Mock::VerifyAndClearExpectations(&observer);
+
+ service()->RemoveObserver(&observer);
+}
+
+TEST_F(ContentSuggestionsServiceTest, ShouldForwardSuggestions) {
+ Category articles_category = FromKnownCategory(KnownCategories::ARTICLES);
+ Category offline_pages_category =
+ FromKnownCategory(KnownCategories::DOWNLOADS);
+
+ // Create and register providers
+ MockProvider* provider1 = RegisterProvider(articles_category);
+ provider1->FireCategoryStatusChangedWithCurrentStatus(articles_category);
+ MockProvider* provider2 = RegisterProvider(offline_pages_category);
+ provider2->FireCategoryStatusChangedWithCurrentStatus(offline_pages_category);
+ ASSERT_THAT(providers().count(articles_category), Eq(1ul));
+ EXPECT_THAT(providers().at(articles_category), Eq(provider1));
+ ASSERT_THAT(providers().count(offline_pages_category), Eq(1ul));
+ EXPECT_THAT(providers().at(offline_pages_category), Eq(provider2));
+
+ // Create and register observer
+ MockServiceObserver observer;
+ service()->AddObserver(&observer);
+
+ // Send suggestions 1 and 2
+ EXPECT_CALL(observer, OnNewSuggestions(articles_category));
+ provider1->FireSuggestionsChanged(
+ articles_category, CreateSuggestions(articles_category, {1, 2}));
+ ExpectThatSuggestionsAre(articles_category, {1, 2});
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Send them again, make sure they're not reported twice
+ EXPECT_CALL(observer, OnNewSuggestions(articles_category));
+ provider1->FireSuggestionsChanged(
+ articles_category, CreateSuggestions(articles_category, {1, 2}));
+ ExpectThatSuggestionsAre(articles_category, {1, 2});
+ ExpectThatSuggestionsAre(offline_pages_category, std::vector<int>());
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Send suggestions 13 and 14
+ EXPECT_CALL(observer, OnNewSuggestions(offline_pages_category));
+ provider2->FireSuggestionsChanged(
+ offline_pages_category, CreateSuggestions(articles_category, {13, 14}));
+ ExpectThatSuggestionsAre(articles_category, {1, 2});
+ ExpectThatSuggestionsAre(offline_pages_category, {13, 14});
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Send suggestion 1 only
+ EXPECT_CALL(observer, OnNewSuggestions(articles_category));
+ provider1->FireSuggestionsChanged(articles_category,
+ CreateSuggestions(articles_category, {1}));
+ ExpectThatSuggestionsAre(articles_category, {1});
+ ExpectThatSuggestionsAre(offline_pages_category, {13, 14});
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // provider2 reports BOOKMARKS as unavailable
+ EXPECT_CALL(observer, OnCategoryStatusChanged(
+ offline_pages_category,
+ CategoryStatus::CATEGORY_EXPLICITLY_DISABLED));
+ provider2->FireCategoryStatusChanged(
+ offline_pages_category, CategoryStatus::CATEGORY_EXPLICITLY_DISABLED);
+ EXPECT_THAT(service()->GetCategoryStatus(articles_category),
+ Eq(CategoryStatus::AVAILABLE));
+ EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category),
+ Eq(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED));
+ ExpectThatSuggestionsAre(articles_category, {1});
+ ExpectThatSuggestionsAre(offline_pages_category, std::vector<int>());
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Shutdown the service
+ EXPECT_CALL(observer, ContentSuggestionsServiceShutdown());
+ service()->Shutdown();
+ service()->RemoveObserver(&observer);
+ // The service will receive two Shutdown() calls.
+}
+
+TEST_F(ContentSuggestionsServiceTest,
+ ShouldNotReturnCategoryInfoForNonexistentCategory) {
+ Category category = FromKnownCategory(KnownCategories::DOWNLOADS);
+ base::Optional<CategoryInfo> result = service()->GetCategoryInfo(category);
+ EXPECT_FALSE(result.has_value());
+}
+
+TEST_F(ContentSuggestionsServiceTest, ShouldReturnCategoryInfo) {
+ Category category = FromKnownCategory(KnownCategories::DOWNLOADS);
+ MockProvider* provider = RegisterProvider(category);
+ provider->FireCategoryStatusChangedWithCurrentStatus(category);
+ base::Optional<CategoryInfo> result = service()->GetCategoryInfo(category);
+ ASSERT_TRUE(result.has_value());
+ CategoryInfo expected = provider->GetCategoryInfo(category);
+ const CategoryInfo& actual = result.value();
+ EXPECT_THAT(expected.title(), Eq(actual.title()));
+ EXPECT_THAT(expected.card_layout(), Eq(actual.card_layout()));
+ EXPECT_THAT(expected.has_more_button(), Eq(actual.has_more_button()));
+}
+
+TEST_F(ContentSuggestionsServiceTest,
+ ShouldRegisterNewCategoryOnNewSuggestions) {
+ Category category = FromKnownCategory(KnownCategories::DOWNLOADS);
+ MockProvider* provider = RegisterProvider(category);
+ provider->FireCategoryStatusChangedWithCurrentStatus(category);
+ MockServiceObserver observer;
+ service()->AddObserver(&observer);
+
+ // Provider starts providing |new_category| without calling
+ // |OnCategoryStatusChanged|. This is supported for now until further
+ // reconsideration.
+ Category new_category = FromKnownCategory(KnownCategories::ARTICLES);
+ provider->SetProvidedCategories(
+ std::vector<Category>({category, new_category}));
+
+ EXPECT_CALL(observer, OnNewSuggestions(new_category));
+ EXPECT_CALL(observer,
+ OnCategoryStatusChanged(new_category, CategoryStatus::AVAILABLE));
+ provider->FireSuggestionsChanged(new_category,
+ CreateSuggestions(new_category, {1, 2}));
+
+ ExpectThatSuggestionsAre(new_category, {1, 2});
+ ASSERT_THAT(providers().count(category), Eq(1ul));
+ EXPECT_THAT(providers().at(category), Eq(provider));
+ EXPECT_THAT(service()->GetCategoryStatus(category),
+ Eq(CategoryStatus::AVAILABLE));
+ ASSERT_THAT(providers().count(new_category), Eq(1ul));
+ EXPECT_THAT(providers().at(new_category), Eq(provider));
+ EXPECT_THAT(service()->GetCategoryStatus(new_category),
+ Eq(CategoryStatus::AVAILABLE));
+
+ service()->RemoveObserver(&observer);
+}
+
+TEST_F(ContentSuggestionsServiceTest,
+ ShouldRegisterNewCategoryOnCategoryStatusChanged) {
+ Category category = FromKnownCategory(KnownCategories::DOWNLOADS);
+ MockProvider* provider = RegisterProvider(category);
+ provider->FireCategoryStatusChangedWithCurrentStatus(category);
+ MockServiceObserver observer;
+ service()->AddObserver(&observer);
+
+ // Provider starts providing |new_category| and calls
+ // |OnCategoryStatusChanged|, but the category is not yet available.
+ Category new_category = FromKnownCategory(KnownCategories::ARTICLES);
+ provider->SetProvidedCategories(
+ std::vector<Category>({category, new_category}));
+ EXPECT_CALL(observer, OnCategoryStatusChanged(new_category,
+ CategoryStatus::INITIALIZING));
+ provider->FireCategoryStatusChanged(new_category,
+ CategoryStatus::INITIALIZING);
+
+ ASSERT_THAT(providers().count(new_category), Eq(1ul));
+ EXPECT_THAT(providers().at(new_category), Eq(provider));
+ ExpectThatSuggestionsAre(new_category, std::vector<int>());
+ EXPECT_THAT(service()->GetCategoryStatus(new_category),
+ Eq(CategoryStatus::INITIALIZING));
+ EXPECT_THAT(service()->GetCategories(),
+ Eq(std::vector<Category>({category, new_category})));
+
+ service()->RemoveObserver(&observer);
+}
+
+TEST_F(ContentSuggestionsServiceTest, ShouldRemoveCategoryWhenNotProvided) {
+ Category category = FromKnownCategory(KnownCategories::DOWNLOADS);
+ MockProvider* provider = RegisterProvider(category);
+ MockServiceObserver observer;
+ service()->AddObserver(&observer);
+
+ provider->FireSuggestionsChanged(category,
+ CreateSuggestions(category, {1, 2}));
+ ExpectThatSuggestionsAre(category, {1, 2});
+
+ EXPECT_CALL(observer,
+ OnCategoryStatusChanged(category, CategoryStatus::NOT_PROVIDED));
+ provider->FireCategoryStatusChanged(category, CategoryStatus::NOT_PROVIDED);
+
+ EXPECT_THAT(service()->GetCategoryStatus(category),
+ Eq(CategoryStatus::NOT_PROVIDED));
+ EXPECT_TRUE(service()->GetCategories().empty());
+ ExpectThatSuggestionsAre(category, std::vector<int>());
+
+ service()->RemoveObserver(&observer);
+}
+
+// This tests the temporary special-casing of the bookmarks section: If it is
+// empty, it should appear at the end; see crbug.com/640568.
+TEST_F(ContentSuggestionsServiceTest, ShouldPutBookmarksAtEndIfEmpty) {
+ // Register a bookmarks provider and an arbitrary remote provider.
+ Category bookmarks = FromKnownCategory(KnownCategories::BOOKMARKS);
+ MockProvider* bookmarks_provider = RegisterProvider(bookmarks);
+ bookmarks_provider->FireCategoryStatusChangedWithCurrentStatus(bookmarks);
+ Category remote = FromRemoteCategory(123);
+ MockProvider* remote_provider = RegisterProvider(remote);
+ remote_provider->FireCategoryStatusChangedWithCurrentStatus(remote);
+
+ // By default, the bookmarks category is empty, so it should be at the end.
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks));
+
+ // Add two bookmark suggestions; now bookmarks should be in the front.
+ bookmarks_provider->FireSuggestionsChanged(
+ bookmarks, CreateSuggestions(bookmarks, {1, 2}));
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote));
+ // Dismiss the first suggestion; bookmarks should stay in the front.
+ service()->DismissSuggestion(CreateSuggestion(bookmarks, 1).id());
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote));
+ // Dismiss the second suggestion; now bookmarks should go back to the end.
+ service()->DismissSuggestion(CreateSuggestion(bookmarks, 2).id());
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks));
+
+ // Same thing, but invalidate instead of dismissing.
+ bookmarks_provider->FireSuggestionsChanged(
+ bookmarks, CreateSuggestions(bookmarks, {1, 2}));
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote));
+ bookmarks_provider->FireSuggestionInvalidated(
+ ContentSuggestion::ID(bookmarks, "1"));
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote));
+ bookmarks_provider->FireSuggestionInvalidated(
+ ContentSuggestion::ID(bookmarks, "2"));
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks));
+
+ // Same thing, but now the bookmarks category updates "naturally".
+ bookmarks_provider->FireSuggestionsChanged(
+ bookmarks, CreateSuggestions(bookmarks, {1, 2}));
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote));
+ bookmarks_provider->FireSuggestionsChanged(bookmarks,
+ CreateSuggestions(bookmarks, {1}));
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote));
+ bookmarks_provider->FireSuggestionsChanged(
+ bookmarks, CreateSuggestions(bookmarks, std::vector<int>()));
+ EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks));
+}
+
+TEST_F(ContentSuggestionsServiceTest, ShouldForwardClearHistory) {
+ Category category = FromKnownCategory(KnownCategories::DOWNLOADS);
+ MockProvider* provider = RegisterProvider(category);
+ base::Time begin = base::Time::FromTimeT(123),
+ end = base::Time::FromTimeT(456);
+ EXPECT_CALL(*provider, ClearHistory(begin, end, _));
+ base::Callback<bool(const GURL& url)> filter;
+ service()->ClearHistory(begin, end, filter);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/features.cc b/chromium/components/ntp_snippets/features.cc
new file mode 100644
index 00000000000..7baf3d7bc0a
--- /dev/null
+++ b/chromium/components/ntp_snippets/features.cc
@@ -0,0 +1,55 @@
+// 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 "components/ntp_snippets/features.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "components/variations/variations_associated_data.h"
+
+namespace ntp_snippets {
+
+const base::Feature kArticleSuggestionsFeature{
+ "NTPArticleSuggestions", base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kBookmarkSuggestionsFeature{
+ "NTPBookmarkSuggestions", base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kRecentOfflineTabSuggestionsFeature{
+ "NTPOfflinePageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kSaveToOfflineFeature{
+ "NTPSaveToOffline", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kDownloadSuggestionsFeature{
+ "NTPDownloadSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kPhysicalWebPageSuggestionsFeature{
+ "NTPPhysicalWebPageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kContentSuggestionsFeature{
+ "NTPSnippets", base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kForeignSessionsSuggestionsFeature{
+ "NTPForeignSessionsSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
+
+int GetParamAsInt(const base::Feature& feature,
+ const std::string& param_name,
+ const int default_value) {
+ std::string value_as_string =
+ variations::GetVariationParamValueByFeature(feature, param_name);
+ int value_as_int = 0;
+ if (!base::StringToInt(value_as_string, &value_as_int)) {
+ if (!value_as_string.empty()) {
+ LOG(WARNING) << "Failed to parse variation param " << param_name
+ << " with string value " << value_as_string
+ << " under feature " << feature.name
+ << " into an int. Falling back to default value of "
+ << default_value;
+ }
+ value_as_int = default_value;
+ }
+ return value_as_int;
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/features.h b/chromium/components/ntp_snippets/features.h
new file mode 100644
index 00000000000..a3b16089253
--- /dev/null
+++ b/chromium/components/ntp_snippets/features.h
@@ -0,0 +1,37 @@
+// 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 COMPONENTS_NTP_SNIPPETS_FEATURES_H_
+#define COMPONENTS_NTP_SNIPPETS_FEATURES_H_
+
+#include <string>
+
+#include "base/feature_list.h"
+
+namespace ntp_snippets {
+
+// Features to turn individual providers/categories on/off.
+extern const base::Feature kArticleSuggestionsFeature;
+extern const base::Feature kBookmarkSuggestionsFeature;
+extern const base::Feature kRecentOfflineTabSuggestionsFeature;
+extern const base::Feature kDownloadSuggestionsFeature;
+extern const base::Feature kPhysicalWebPageSuggestionsFeature;
+extern const base::Feature kForeignSessionsSuggestionsFeature;
+
+// Feature to allow the 'save to offline' option to appear in the snippets
+// context menu.
+extern const base::Feature kSaveToOfflineFeature;
+
+// Global toggle for the whole content suggestions feature. If this is set to
+// false, all the per-provider features are ignored.
+extern const base::Feature kContentSuggestionsFeature;
+
+// Returns a feature param as an int instead of a string.
+int GetParamAsInt(const base::Feature& feature,
+ const std::string& param_name,
+ int default_value);
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_FEATURES_H_
diff --git a/chromium/components/ntp_snippets/mock_content_suggestions_provider_observer.cc b/chromium/components/ntp_snippets/mock_content_suggestions_provider_observer.cc
new file mode 100644
index 00000000000..38f97191106
--- /dev/null
+++ b/chromium/components/ntp_snippets/mock_content_suggestions_provider_observer.cc
@@ -0,0 +1,26 @@
+// 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 "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
+
+namespace ntp_snippets {
+
+MockContentSuggestionsProviderObserver::
+ MockContentSuggestionsProviderObserver() = default;
+
+MockContentSuggestionsProviderObserver::
+ ~MockContentSuggestionsProviderObserver() = default;
+
+void MockContentSuggestionsProviderObserver::OnNewSuggestions(
+ ContentSuggestionsProvider* provider,
+ Category category,
+ std::vector<ContentSuggestion> suggestions) {
+ std::list<ContentSuggestion> suggestions_list;
+ for (ContentSuggestion& suggestion : suggestions) {
+ suggestions_list.push_back(std::move(suggestion));
+ }
+ OnNewSuggestions(provider, category, suggestions_list);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/mock_content_suggestions_provider_observer.h b/chromium/components/ntp_snippets/mock_content_suggestions_provider_observer.h
new file mode 100644
index 00000000000..12bb1fdc55b
--- /dev/null
+++ b/chromium/components/ntp_snippets/mock_content_suggestions_provider_observer.h
@@ -0,0 +1,47 @@
+// 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 COMPONENTS_NTP_SNIPPETS_MOCK_CONTENT_SUGGESTIONS_PROVIDER_OBSERVER_H_
+#define COMPONENTS_NTP_SNIPPETS_MOCK_CONTENT_SUGGESTIONS_PROVIDER_OBSERVER_H_
+
+#include <list>
+#include <vector>
+
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace ntp_snippets {
+
+class MockContentSuggestionsProviderObserver
+ : public ContentSuggestionsProvider::Observer {
+ public:
+ MockContentSuggestionsProviderObserver();
+ ~MockContentSuggestionsProviderObserver();
+
+ // Call of this function is redirected to the mock function OnNewSuggestions
+ // which takes const list of suggestions. We do this trick so that the
+ // MOCK_METHOD behaves the same way in tests as the actual method and we can
+ // keep this gMock issue limited to the mock class. MOCK_METHOD cannot be
+ // applied here directly, since gMock does not support movable-only types
+ // such as ContentSuggestion.
+ void OnNewSuggestions(ContentSuggestionsProvider* provider,
+ Category category,
+ std::vector<ContentSuggestion> suggestions) override;
+
+ MOCK_METHOD3(OnNewSuggestions,
+ void(ContentSuggestionsProvider* provider,
+ Category category,
+ const std::list<ContentSuggestion>& suggestions));
+ MOCK_METHOD3(OnCategoryStatusChanged,
+ void(ContentSuggestionsProvider* provider,
+ Category category,
+ CategoryStatus new_status));
+ MOCK_METHOD2(OnSuggestionInvalidated,
+ void(ContentSuggestionsProvider* provider,
+ const ContentSuggestion::ID& suggestion_id));
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_MOCK_CONTENT_SUGGESTIONS_PROVIDER_OBSERVER_H_
diff --git a/chromium/components/ntp_snippets/ntp_snippet.cc b/chromium/components/ntp_snippets/ntp_snippet.cc
deleted file mode 100644
index f7870f919d6..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippet.cc
+++ /dev/null
@@ -1,300 +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 "components/ntp_snippets/ntp_snippet.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/values.h"
-#include "components/ntp_snippets/content_suggestion.h"
-#include "components/ntp_snippets/content_suggestion_category.h"
-#include "components/ntp_snippets/content_suggestions_provider_type.h"
-#include "components/ntp_snippets/proto/ntp_snippets.pb.h"
-
-namespace {
-
-// dict.Get() specialization for base::Time values
-bool GetTimeValue(const base::DictionaryValue& dict,
- const std::string& key,
- base::Time* time) {
- std::string time_value;
- return dict.GetString(key, &time_value) &&
- base::Time::FromString(time_value.c_str(), time);
-}
-
-// dict.Get() specialization for GURL values
-bool GetURLValue(const base::DictionaryValue& dict,
- const std::string& key,
- GURL* url) {
- std::string spec;
- if (!dict.GetString(key, &spec)) {
- return false;
- }
- *url = GURL(spec);
- return url->is_valid();
-}
-
-} // namespace
-
-namespace ntp_snippets {
-
-NTPSnippet::NTPSnippet(const std::string& id)
- : id_(id), score_(0), is_discarded_(false), best_source_index_(0) {}
-
-NTPSnippet::~NTPSnippet() {}
-
-// static
-std::unique_ptr<NTPSnippet> NTPSnippet::CreateFromChromeReaderDictionary(
- const base::DictionaryValue& dict) {
- const base::DictionaryValue* content = nullptr;
- if (!dict.GetDictionary("contentInfo", &content))
- return nullptr;
-
- // Need at least the id.
- std::string id;
- if (!content->GetString("url", &id) || id.empty())
- return nullptr;
-
- std::unique_ptr<NTPSnippet> snippet(new NTPSnippet(id));
-
- std::string title;
- if (content->GetString("title", &title))
- snippet->set_title(title);
- std::string salient_image_url;
- if (content->GetString("thumbnailUrl", &salient_image_url))
- snippet->set_salient_image_url(GURL(salient_image_url));
- std::string snippet_str;
- if (content->GetString("snippet", &snippet_str))
- snippet->set_snippet(snippet_str);
- // The creation and expiry timestamps are uint64s which are stored as strings.
- std::string creation_timestamp_str;
- if (content->GetString("creationTimestampSec", &creation_timestamp_str))
- snippet->set_publish_date(TimeFromJsonString(creation_timestamp_str));
- std::string expiry_timestamp_str;
- if (content->GetString("expiryTimestampSec", &expiry_timestamp_str))
- snippet->set_expiry_date(TimeFromJsonString(expiry_timestamp_str));
-
- const base::ListValue* corpus_infos_list = nullptr;
- if (!content->GetList("sourceCorpusInfo", &corpus_infos_list)) {
- DLOG(WARNING) << "No sources found for article " << title;
- return nullptr;
- }
-
- for (const auto& value : *corpus_infos_list) {
- const base::DictionaryValue* dict_value = nullptr;
- if (!value->GetAsDictionary(&dict_value)) {
- DLOG(WARNING) << "Invalid source info for article " << id;
- continue;
- }
-
- std::string corpus_id_str;
- GURL corpus_id;
- if (dict_value->GetString("corpusId", &corpus_id_str))
- corpus_id = GURL(corpus_id_str);
-
- if (!corpus_id.is_valid()) {
- // We must at least have a valid source URL.
- DLOG(WARNING) << "Invalid article url " << corpus_id_str;
- continue;
- }
-
- const base::DictionaryValue* publisher_data = nullptr;
- std::string site_title;
- if (dict_value->GetDictionary("publisherData", &publisher_data)) {
- if (!publisher_data->GetString("sourceName", &site_title)) {
- // It's possible but not desirable to have no publisher data.
- DLOG(WARNING) << "No publisher name for article " << corpus_id.spec();
- }
- } else {
- DLOG(WARNING) << "No publisher data for article " << corpus_id.spec();
- }
-
- std::string amp_url_str;
- GURL amp_url;
- // Expected to not have AMP url sometimes.
- if (dict_value->GetString("ampUrl", &amp_url_str)) {
- amp_url = GURL(amp_url_str);
- DLOG_IF(WARNING, !amp_url.is_valid()) << "Invalid AMP url "
- << amp_url_str;
- }
- SnippetSource source(corpus_id, site_title,
- amp_url.is_valid() ? amp_url : GURL());
- snippet->add_source(source);
- }
-
- if (snippet->sources_.empty()) {
- DLOG(WARNING) << "No sources found for article " << id;
- return nullptr;
- }
-
- snippet->FindBestSource();
-
- double score;
- if (dict.GetDouble("score", &score))
- snippet->set_score(score);
-
- return snippet;
-}
-
-// static
-std::unique_ptr<NTPSnippet> NTPSnippet::CreateFromContentSuggestionsDictionary(
- const base::DictionaryValue& dict) {
- const base::ListValue* id_list;
- std::string id;
- if (!(dict.GetList("id", &id_list) &&
- id_list->GetString(0, &id))) { // TODO(sfiera): multiple IDs
- return nullptr;
- }
-
- auto snippet = base::MakeUnique<NTPSnippet>(id);
- snippet->sources_.emplace_back(GURL(), std::string(), GURL());
- auto source = &snippet->sources_.back();
- snippet->best_source_index_ = 0;
-
- if (!(dict.GetString("title", &snippet->title_) &&
- dict.GetString("summaryText", &snippet->snippet_) &&
- GetTimeValue(dict, "publishTime", &snippet->publish_date_) &&
- GetTimeValue(dict, "expirationTime", &snippet->expiry_date_) &&
- GetURLValue(dict, "imageUrl", &snippet->salient_image_url_) &&
- dict.GetString("publisherName", &source->publisher_name) &&
- GetURLValue(dict, "fullPageUrl", &source->url))) {
- return nullptr;
- }
- GetURLValue(dict, "ampUrl", &source->amp_url); // May fail; OK.
- // TODO(sfiera): also favicon URL.
-
- snippet->score_ = 0.0; // TODO(sfiera): put score in protocol.
-
- return snippet;
-}
-
-// static
-std::unique_ptr<NTPSnippet> NTPSnippet::CreateFromProto(
- const SnippetProto& proto) {
- // Need at least the id.
- if (!proto.has_id() || proto.id().empty())
- return nullptr;
-
- std::unique_ptr<NTPSnippet> snippet(new NTPSnippet(proto.id()));
-
- snippet->set_title(proto.title());
- snippet->set_snippet(proto.snippet());
- snippet->set_salient_image_url(GURL(proto.salient_image_url()));
- snippet->set_publish_date(
- base::Time::FromInternalValue(proto.publish_date()));
- snippet->set_expiry_date(base::Time::FromInternalValue(proto.expiry_date()));
- snippet->set_score(proto.score());
- snippet->set_discarded(proto.discarded());
-
- for (int i = 0; i < proto.sources_size(); ++i) {
- const SnippetSourceProto& source_proto = proto.sources(i);
- GURL url(source_proto.url());
- if (!url.is_valid()) {
- // We must at least have a valid source URL.
- DLOG(WARNING) << "Invalid article url " << source_proto.url();
- continue;
- }
- std::string publisher_name = source_proto.publisher_name();
- GURL amp_url;
- if (source_proto.has_amp_url()) {
- amp_url = GURL(source_proto.amp_url());
- DLOG_IF(WARNING, !amp_url.is_valid()) << "Invalid AMP URL "
- << source_proto.amp_url();
- }
-
- snippet->add_source(SnippetSource(url, publisher_name, amp_url));
- }
-
- if (snippet->sources_.empty()) {
- DLOG(WARNING) << "No sources found for article " << snippet->id();
- return nullptr;
- }
-
- snippet->FindBestSource();
-
- return snippet;
-}
-
-SnippetProto NTPSnippet::ToProto() const {
- SnippetProto result;
-
- result.set_id(id_);
- if (!title_.empty())
- result.set_title(title_);
- if (!snippet_.empty())
- result.set_snippet(snippet_);
- if (salient_image_url_.is_valid())
- result.set_salient_image_url(salient_image_url_.spec());
- if (!publish_date_.is_null())
- result.set_publish_date(publish_date_.ToInternalValue());
- if (!expiry_date_.is_null())
- result.set_expiry_date(expiry_date_.ToInternalValue());
- result.set_score(score_);
- result.set_discarded(is_discarded_);
-
- for (const SnippetSource& source : sources_) {
- SnippetSourceProto* source_proto = result.add_sources();
- source_proto->set_url(source.url.spec());
- if (!source.publisher_name.empty())
- source_proto->set_publisher_name(source.publisher_name);
- if (source.amp_url.is_valid())
- source_proto->set_amp_url(source.amp_url.spec());
- }
-
- return result;
-}
-
-std::unique_ptr<ContentSuggestion> NTPSnippet::ToContentSuggestion() const {
- std::unique_ptr<ContentSuggestion> result(new ContentSuggestion(
- id_, ContentSuggestionsProviderType::ARTICLES,
- ContentSuggestionCategory::ARTICLE, best_source().url));
- result->set_amp_url(best_source().amp_url);
- result->set_title(title_);
- result->set_snippet_text(snippet_);
- result->set_publish_date(publish_date_);
- result->set_publisher_name(best_source().publisher_name);
- result->set_score(score_);
- return result;
-}
-
-// static
-base::Time NTPSnippet::TimeFromJsonString(const std::string& timestamp_str) {
- int64_t timestamp;
- if (!base::StringToInt64(timestamp_str, &timestamp)) {
- // Even if there's an error in the conversion, some garbage data may still
- // be written to the output var, so reset it.
- timestamp = 0;
- }
- return base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(timestamp);
-}
-
-// static
-std::string NTPSnippet::TimeToJsonString(const base::Time& time) {
- return base::Int64ToString((time - base::Time::UnixEpoch()).InSeconds());
-}
-
-void NTPSnippet::FindBestSource() {
- // The same article can be hosted by multiple sources, e.g. nytimes.com,
- // cnn.com, etc. We need to parse the list of sources for this article and
- // find the best match. In order of preference:
- // 1 A source that has URL, publisher name, AMP URL
- // 2) A source that has URL, publisher name
- // 3) A source that has URL and AMP URL, or URL only (since we won't show
- // the snippet to users if the article does not have a publisher name, it
- // doesn't matter whether the snippet has the AMP URL or not)
- best_source_index_ = 0;
- for (size_t i = 0; i < sources_.size(); ++i) {
- const SnippetSource& source = sources_[i];
- if (!source.publisher_name.empty()) {
- best_source_index_ = i;
- if (!source.amp_url.is_empty()) {
- // This is the best possible source, stop looking.
- break;
- }
- }
- }
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippet.h b/chromium/components/ntp_snippets/ntp_snippet.h
deleted file mode 100644
index 416cffca7db..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippet.h
+++ /dev/null
@@ -1,156 +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 COMPONENTS_NTP_SNIPPETS_NTP_SNIPPET_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPET_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "components/ntp_snippets/content_suggestion.h"
-#include "url/gurl.h"
-
-namespace base {
-class DictionaryValue;
-}
-
-namespace ntp_snippets {
-
-class SnippetProto;
-
-struct SnippetSource {
- SnippetSource(const GURL& url,
- const std::string& publisher_name,
- const GURL& amp_url)
- : url(url), publisher_name(publisher_name), amp_url(amp_url) {}
- GURL url;
- std::string publisher_name;
- GURL amp_url;
-};
-
-class NTPSnippet {
- public:
- using PtrVector = std::vector<std::unique_ptr<NTPSnippet>>;
-
- // Creates a new snippet with the given |id|.
- // Public for testing only - create snippets using the Create* methods below.
- // TODO(treib): Make this private and add a CreateSnippetForTest?
- NTPSnippet(const std::string& id);
-
- ~NTPSnippet();
-
- // Creates an NTPSnippet from a dictionary, as returned by Chrome Reader.
- // Returns a null pointer if the dictionary doesn't correspond to a valid
- // snippet. The keys in the dictionary are expected to be the same as the
- // property name, with exceptions documented in the property comment.
- static std::unique_ptr<NTPSnippet> CreateFromChromeReaderDictionary(
- const base::DictionaryValue& dict);
-
- // Creates an NTPSnippet from a dictionary, as returned by Chrome Content
- // Suggestions. Returns a null pointer if the dictionary doesn't correspond to
- // a valid snippet. Maps field names to Chrome Reader field names.
- static std::unique_ptr<NTPSnippet> CreateFromContentSuggestionsDictionary(
- const base::DictionaryValue& dict);
-
- // Creates an NTPSnippet from a protocol buffer. Returns a null pointer if the
- // protocol buffer doesn't correspond to a valid snippet.
- static std::unique_ptr<NTPSnippet> CreateFromProto(const SnippetProto& proto);
-
- // Creates a protocol buffer corresponding to this snippet, for persisting.
- SnippetProto ToProto() const;
-
- // A unique ID for identifying the snippet. If initialized by
- // CreateFromChromeReaderDictionary() the relevant key is 'url'.
- // TODO(treib): For now, the ID has to be a valid URL spec, otherwise
- // fetching the salient image will fail. See TODO in ntp_snippets_service.cc.
- const std::string& id() const { return id_; }
-
- // Title of the snippet.
- const std::string& title() const { return title_; }
- void set_title(const std::string& title) { title_ = title; }
-
- // Summary or relevant extract from the content.
- const std::string& snippet() const { return snippet_; }
- void set_snippet(const std::string& snippet) { snippet_ = snippet; }
-
- // Link to an image representative of the content. Do not fetch this image
- // directly. If initialized by CreateFromChromeReaderDictionary() the relevant
- // key is 'thumbnailUrl'
- const GURL& salient_image_url() const { return salient_image_url_; }
- void set_salient_image_url(const GURL& salient_image_url) {
- salient_image_url_ = salient_image_url;
- }
-
- // When the page pointed by this snippet was published. If initialized by
- // CreateFromChromeReaderDictionary() the relevant key is
- // 'creationTimestampSec'
- const base::Time& publish_date() const { return publish_date_; }
- void set_publish_date(const base::Time& publish_date) {
- publish_date_ = publish_date;
- }
-
- // After this expiration date this snippet should no longer be presented to
- // the user.
- const base::Time& expiry_date() const { return expiry_date_; }
- void set_expiry_date(const base::Time& expiry_date) {
- expiry_date_ = expiry_date;
- }
-
- size_t source_index() const { return best_source_index_; }
- void set_source_index(size_t index) { best_source_index_ = index; }
-
- // We should never construct an NTPSnippet object if we don't have any sources
- // so this should never fail
- const SnippetSource& best_source() const {
- return sources_[best_source_index_];
- }
-
- const std::vector<SnippetSource>& sources() const { return sources_; }
- void add_source(const SnippetSource& source) { sources_.push_back(source); }
-
- // If this snippet has all the data we need to show a full card to the user
- bool is_complete() const {
- return !id().empty() && !sources().empty() && !title().empty() &&
- !snippet().empty() && salient_image_url().is_valid() &&
- !publish_date().is_null() && !expiry_date().is_null() &&
- !best_source().publisher_name.empty();
- }
-
- float score() const { return score_; }
- void set_score(float score) { score_ = score; }
-
- bool is_discarded() const { return is_discarded_; }
- void set_discarded(bool discarded) { is_discarded_ = discarded; }
-
- std::unique_ptr<ContentSuggestion> ToContentSuggestion() const;
-
- // Public for testing.
- static base::Time TimeFromJsonString(const std::string& timestamp_str);
- static std::string TimeToJsonString(const base::Time& time);
-
- private:
- void FindBestSource();
-
- std::string id_;
- std::string title_;
- GURL salient_image_url_;
- std::string snippet_;
- base::Time publish_date_;
- base::Time expiry_date_;
- float score_;
- bool is_discarded_;
-
- size_t best_source_index_;
-
- std::vector<SnippetSource> sources_;
-
- DISALLOW_COPY_AND_ASSIGN(NTPSnippet);
-};
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPET_H_
diff --git a/chromium/components/ntp_snippets/ntp_snippet_unittest.cc b/chromium/components/ntp_snippets/ntp_snippet_unittest.cc
deleted file mode 100644
index 6e254c66929..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippet_unittest.cc
+++ /dev/null
@@ -1,51 +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 "components/ntp_snippets/ntp_snippet.h"
-
-#include "base/json/json_reader.h"
-#include "base/values.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ntp_snippets {
-namespace {
-
-TEST(NTPSnippetTest, FromChromeContentSuggestionsDictionary) {
- const std::string kJsonStr =
- "{"
- " \"id\" : [\"http://localhost/foobar\"],"
- " \"title\" : \"Foo Barred from Baz\","
- " \"summaryText\" : \"...\","
- " \"fullPageUrl\" : \"http://localhost/foobar\","
- " \"publishTime\" : \"2016-06-30T11:01:37.000Z\","
- " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\","
- " \"publisherName\" : \"Foo News\","
- " \"imageUrl\" : \"http://localhost/foobar.jpg\","
- " \"ampUrl\" : \"http://localhost/amp\","
- " \"faviconUrl\" : \"http://localhost/favicon.ico\" "
- "}";
- auto json_value = base::JSONReader::Read(kJsonStr);
- base::DictionaryValue* json_dict;
- ASSERT_TRUE(json_value->GetAsDictionary(&json_dict));
-
- auto snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*json_dict);
- ASSERT_THAT(snippet, testing::NotNull());
-
- EXPECT_EQ(snippet->id(), "http://localhost/foobar");
- EXPECT_EQ(snippet->title(), "Foo Barred from Baz");
- EXPECT_EQ(snippet->snippet(), "...");
- EXPECT_EQ(snippet->salient_image_url(), GURL("http://localhost/foobar.jpg"));
- auto unix_publish_date = snippet->publish_date() - base::Time::UnixEpoch();
- auto expiry_duration = snippet->expiry_date() - snippet->publish_date();
- EXPECT_FLOAT_EQ(unix_publish_date.InSecondsF(), 1467284497.000000f);
- EXPECT_FLOAT_EQ(expiry_duration.InSecondsF(), 86400.000000f);
-
- EXPECT_EQ(snippet->best_source().publisher_name, "Foo News");
- EXPECT_EQ(snippet->best_source().url, GURL("http://localhost/foobar"));
- EXPECT_EQ(snippet->best_source().amp_url, GURL("http://localhost/amp"));
-}
-
-} // namespace
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_constants.cc b/chromium/components/ntp_snippets/ntp_snippets_constants.cc
index 5ee43fbb473..4b92ddd8f22 100644
--- a/chromium/components/ntp_snippets/ntp_snippets_constants.cc
+++ b/chromium/components/ntp_snippets/ntp_snippets_constants.cc
@@ -12,4 +12,13 @@ const char kStudyName[] = "NTPSnippets";
const base::FilePath::CharType kDatabaseFolder[] =
FILE_PATH_LITERAL("NTPSnippets");
+const char kChromeReaderServer[] =
+ "https://chromereader-pa.googleapis.com/v1/fetch";
+const char kContentSuggestionsServer[] =
+ "https://chromecontentsuggestions-pa.googleapis.com/v1/suggestions/fetch";
+const char kContentSuggestionsDevServer[] =
+ "https://dev-chromecontentsuggestions-pa.googleapis.com/v1/suggestions/fetch";
+const char kContentSuggestionsAlphaServer[] =
+ "https://alpha-chromecontentsuggestions-pa.sandbox.googleapis.com/v1/suggestions/fetch";
+
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_constants.h b/chromium/components/ntp_snippets/ntp_snippets_constants.h
index 0bb403cba5d..9c39975ff43 100644
--- a/chromium/components/ntp_snippets/ntp_snippets_constants.h
+++ b/chromium/components/ntp_snippets/ntp_snippets_constants.h
@@ -17,6 +17,12 @@ extern const char kStudyName[];
// profile path.
extern const base::FilePath::CharType kDatabaseFolder[];
+// Server endpoints for fetching snippets.
+extern const char kChromeReaderServer[]; // old endpoint
+extern const char kContentSuggestionsServer[]; // new, used on stable/beta
+extern const char kContentSuggestionsDevServer[]; // new, used on dev/canary
+extern const char kContentSuggestionsAlphaServer[]; // new, for testing
+
} // namespace ntp_snippets
#endif
diff --git a/chromium/components/ntp_snippets/ntp_snippets_database.cc b/chromium/components/ntp_snippets/ntp_snippets_database.cc
deleted file mode 100644
index 4b142796158..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_database.cc
+++ /dev/null
@@ -1,292 +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 "components/ntp_snippets/ntp_snippets_database.h"
-
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "components/leveldb_proto/proto_database_impl.h"
-#include "components/ntp_snippets/proto/ntp_snippets.pb.h"
-
-using leveldb_proto::ProtoDatabaseImpl;
-
-namespace {
-// Statistics are logged to UMA with this string as part of histogram name. They
-// can all be found under LevelDB.*.NTPSnippets. Changing this needs to
-// synchronize with histograms.xml, AND will also become incompatible with older
-// browsers still reporting the previous values.
-const char kDatabaseUMAClientName[] = "NTPSnippets";
-const char kImageDatabaseUMAClientName[] = "NTPSnippetImages";
-
-const char kSnippetDatabaseFolder[] = "snippets";
-const char kImageDatabaseFolder[] = "images";
-}
-
-namespace ntp_snippets {
-
-NTPSnippetsDatabase::NTPSnippetsDatabase(
- const base::FilePath& database_dir,
- scoped_refptr<base::SequencedTaskRunner> file_task_runner)
- : database_(
- new ProtoDatabaseImpl<SnippetProto>(file_task_runner)),
- database_initialized_(false),
- image_database_(
- new ProtoDatabaseImpl<SnippetImageProto>(file_task_runner)),
- image_database_initialized_(false),
- weak_ptr_factory_(this) {
- base::FilePath snippet_dir = database_dir.AppendASCII(kSnippetDatabaseFolder);
- database_->Init(kDatabaseUMAClientName, snippet_dir,
- base::Bind(&NTPSnippetsDatabase::OnDatabaseInited,
- weak_ptr_factory_.GetWeakPtr()));
-
- base::FilePath image_dir = database_dir.AppendASCII(kImageDatabaseFolder);
- image_database_->Init(kImageDatabaseUMAClientName, image_dir,
- base::Bind(&NTPSnippetsDatabase::OnImageDatabaseInited,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-NTPSnippetsDatabase::~NTPSnippetsDatabase() {}
-
-bool NTPSnippetsDatabase::IsInitialized() const {
- return !IsErrorState() && database_initialized_ &&
- image_database_initialized_;
-}
-
-bool NTPSnippetsDatabase::IsErrorState() const {
- return !database_ || !image_database_;
-}
-
-void NTPSnippetsDatabase::SetErrorCallback(
- const base::Closure& error_callback) {
- error_callback_ = error_callback;
-}
-
-void NTPSnippetsDatabase::LoadSnippets(const SnippetsCallback& callback) {
- if (IsInitialized())
- LoadSnippetsImpl(callback);
- else
- pending_snippets_callbacks_.emplace_back(callback);
-}
-
-void NTPSnippetsDatabase::SaveSnippet(const NTPSnippet& snippet) {
- std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
- entries_to_save->emplace_back(snippet.id(), snippet.ToProto());
- SaveSnippetsImpl(std::move(entries_to_save));
-}
-
-void NTPSnippetsDatabase::SaveSnippets(const NTPSnippet::PtrVector& snippets) {
- std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
- for (const std::unique_ptr<NTPSnippet>& snippet : snippets)
- entries_to_save->emplace_back(snippet->id(), snippet->ToProto());
- SaveSnippetsImpl(std::move(entries_to_save));
-}
-
-void NTPSnippetsDatabase::DeleteSnippet(const std::string& snippet_id) {
- DeleteSnippetsImpl(
- base::WrapUnique(new std::vector<std::string>(1, snippet_id)));
-}
-
-void NTPSnippetsDatabase::DeleteSnippets(
- const NTPSnippet::PtrVector& snippets) {
- std::unique_ptr<std::vector<std::string>> keys_to_remove(
- new std::vector<std::string>());
- for (const std::unique_ptr<NTPSnippet>& snippet : snippets)
- keys_to_remove->emplace_back(snippet->id());
- DeleteSnippetsImpl(std::move(keys_to_remove));
-}
-
-void NTPSnippetsDatabase::LoadImage(const std::string& snippet_id,
- const SnippetImageCallback& callback) {
- if (IsInitialized())
- LoadImageImpl(snippet_id, callback);
- else
- pending_image_callbacks_.emplace_back(snippet_id, callback);
-}
-
-void NTPSnippetsDatabase::SaveImage(const std::string& snippet_id,
- const std::string& image_data) {
- DCHECK(IsInitialized());
-
- SnippetImageProto image_proto;
- image_proto.set_data(image_data);
-
- std::unique_ptr<ImageKeyEntryVector> entries_to_save(
- new ImageKeyEntryVector());
- entries_to_save->emplace_back(snippet_id, std::move(image_proto));
-
- image_database_->UpdateEntries(
- std::move(entries_to_save),
- base::WrapUnique(new std::vector<std::string>()),
- base::Bind(&NTPSnippetsDatabase::OnImageDatabaseSaved,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void NTPSnippetsDatabase::DeleteImage(const std::string& snippet_id) {
- DeleteImagesImpl(
- base::WrapUnique(new std::vector<std::string>(1, snippet_id)));
-}
-
-void NTPSnippetsDatabase::OnDatabaseInited(bool success) {
- DCHECK(!database_initialized_);
- if (!success) {
- DVLOG(1) << "NTPSnippetsDatabase init failed.";
- OnDatabaseError();
- return;
- }
- database_initialized_ = true;
- if (IsInitialized())
- ProcessPendingLoads();
-}
-
-void NTPSnippetsDatabase::OnDatabaseLoaded(
- const SnippetsCallback& callback,
- bool success,
- std::unique_ptr<std::vector<SnippetProto>> entries) {
- if (!success) {
- DVLOG(1) << "NTPSnippetsDatabase load failed.";
- OnDatabaseError();
- return;
- }
-
- std::unique_ptr<std::vector<std::string>> keys_to_remove(
- new std::vector<std::string>());
-
- NTPSnippet::PtrVector snippets;
- for (const SnippetProto& proto : *entries) {
- std::unique_ptr<NTPSnippet> snippet = NTPSnippet::CreateFromProto(proto);
- if (snippet) {
- snippets.emplace_back(std::move(snippet));
- } else {
- LOG(WARNING) << "Invalid proto from DB " << proto.id();
- keys_to_remove->emplace_back(proto.id());
- }
- }
-
- callback.Run(std::move(snippets));
-
- // If any of the snippet protos couldn't be converted to actual snippets,
- // clean them up now.
- if (!keys_to_remove->empty())
- DeleteSnippetsImpl(std::move(keys_to_remove));
-}
-
-void NTPSnippetsDatabase::OnDatabaseSaved(bool success) {
- if (!success) {
- DVLOG(1) << "NTPSnippetsDatabase save failed.";
- OnDatabaseError();
- }
-}
-
-void NTPSnippetsDatabase::OnImageDatabaseInited(bool success) {
- DCHECK(!image_database_initialized_);
- if (!success) {
- DVLOG(1) << "NTPSnippetsDatabase init failed.";
- OnDatabaseError();
- return;
- }
- image_database_initialized_ = true;
- if (IsInitialized())
- ProcessPendingLoads();
-}
-
-void NTPSnippetsDatabase::OnImageDatabaseLoaded(
- const SnippetImageCallback& callback,
- bool success,
- std::unique_ptr<SnippetImageProto> entry) {
- if (!success) {
- DVLOG(1) << "NTPSnippetsDatabase load failed.";
- OnDatabaseError();
- return;
- }
-
- if (!entry) {
- callback.Run(std::string());
- return;
- }
-
- std::unique_ptr<std::string> data(entry->release_data());
- callback.Run(std::move(*data));
-}
-
-void NTPSnippetsDatabase::OnImageDatabaseSaved(bool success) {
- if (!success) {
- DVLOG(1) << "NTPSnippetsDatabase save failed.";
- OnDatabaseError();
- }
-}
-
-void NTPSnippetsDatabase::OnDatabaseError() {
- database_.reset();
- image_database_.reset();
- if (!error_callback_.is_null())
- error_callback_.Run();
-}
-
-void NTPSnippetsDatabase::ProcessPendingLoads() {
- DCHECK(IsInitialized());
-
- for (const auto& callback : pending_snippets_callbacks_)
- LoadSnippetsImpl(callback);
- pending_snippets_callbacks_.clear();
-
- for (const auto& id_callback : pending_image_callbacks_)
- LoadImageImpl(id_callback.first, id_callback.second);
- pending_image_callbacks_.clear();
-}
-
-void NTPSnippetsDatabase::LoadSnippetsImpl(const SnippetsCallback& callback) {
- DCHECK(IsInitialized());
- database_->LoadEntries(base::Bind(&NTPSnippetsDatabase::OnDatabaseLoaded,
- weak_ptr_factory_.GetWeakPtr(),
- callback));
-}
-
-void NTPSnippetsDatabase::SaveSnippetsImpl(
- std::unique_ptr<KeyEntryVector> entries_to_save) {
- DCHECK(IsInitialized());
-
- std::unique_ptr<std::vector<std::string>> keys_to_remove(
- new std::vector<std::string>());
- database_->UpdateEntries(std::move(entries_to_save),
- std::move(keys_to_remove),
- base::Bind(&NTPSnippetsDatabase::OnDatabaseSaved,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void NTPSnippetsDatabase::DeleteSnippetsImpl(
- std::unique_ptr<std::vector<std::string>> keys_to_remove) {
- DCHECK(IsInitialized());
-
- DeleteImagesImpl(
- base::WrapUnique(new std::vector<std::string>(*keys_to_remove)));
-
- std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
- database_->UpdateEntries(std::move(entries_to_save),
- std::move(keys_to_remove),
- base::Bind(&NTPSnippetsDatabase::OnDatabaseSaved,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void NTPSnippetsDatabase::LoadImageImpl(const std::string& snippet_id,
- const SnippetImageCallback& callback) {
- DCHECK(IsInitialized());
- image_database_->GetEntry(
- snippet_id,
- base::Bind(&NTPSnippetsDatabase::OnImageDatabaseLoaded,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void NTPSnippetsDatabase::DeleteImagesImpl(
- std::unique_ptr<std::vector<std::string>> keys_to_remove) {
- DCHECK(IsInitialized());
-
- image_database_->UpdateEntries(
- base::WrapUnique(new ImageKeyEntryVector()),
- std::move(keys_to_remove),
- base::Bind(&NTPSnippetsDatabase::OnImageDatabaseSaved,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_database.h b/chromium/components/ntp_snippets/ntp_snippets_database.h
deleted file mode 100644
index 983166235f0..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_database.h
+++ /dev/null
@@ -1,131 +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 COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_DATABASE_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_DATABASE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequenced_task_runner.h"
-#include "components/leveldb_proto/proto_database.h"
-#include "components/ntp_snippets/ntp_snippet.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace ntp_snippets {
-
-class SnippetImageProto;
-class SnippetProto;
-
-class NTPSnippetsDatabase {
- public:
- using SnippetsCallback = base::Callback<void(NTPSnippet::PtrVector)>;
- using SnippetImageCallback = base::Callback<void(std::string)>;
-
- NTPSnippetsDatabase(
- const base::FilePath& database_dir,
- scoped_refptr<base::SequencedTaskRunner> file_task_runner);
- ~NTPSnippetsDatabase();
-
- // Returns whether the database has finished initialization. While this is
- // false, loads may already be started (they'll be serviced after
- // initialization finishes), but no updates are allowed.
- bool IsInitialized() const;
-
- // Returns whether the database is in an (unrecoverable) error state. If this
- // is true, the database must not be used anymore
- bool IsErrorState() const;
-
- // Set a callback to be called when the database enters an error state.
- void SetErrorCallback(const base::Closure& error_callback);
-
- // Loads all snippets from storage and passes them to |callback|.
- void LoadSnippets(const SnippetsCallback& callback);
-
- // Adds or updates the given snippet.
- void SaveSnippet(const NTPSnippet& snippet);
- // Adds or updates all the given snippets.
- void SaveSnippets(const NTPSnippet::PtrVector& snippets);
-
- // Deletes the snippet with the given ID, and its image.
- void DeleteSnippet(const std::string& snippet_id);
- // Deletes all the given snippets (identified by their IDs) and their images.
- void DeleteSnippets(const NTPSnippet::PtrVector& snippets);
-
- // Loads the image data for the snippet with the given ID and passes it to
- // |callback|. Passes an empty string if not found.
- void LoadImage(const std::string& snippet_id,
- const SnippetImageCallback& callback);
-
- // Adds or updates the image data for the given snippet ID.
- void SaveImage(const std::string& snippet_id, const std::string& image_data);
-
- // Deletes the image data for the given snippet ID.
- void DeleteImage(const std::string& snippet_id);
-
- private:
- friend class NTPSnippetsDatabaseTest;
-
- using KeyEntryVector =
- leveldb_proto::ProtoDatabase<SnippetProto>::KeyEntryVector;
-
- using ImageKeyEntryVector =
- leveldb_proto::ProtoDatabase<SnippetImageProto>::KeyEntryVector;
-
- // Callbacks for ProtoDatabase<SnippetProto> operations.
- void OnDatabaseInited(bool success);
- void OnDatabaseLoaded(const SnippetsCallback& callback,
- bool success,
- std::unique_ptr<std::vector<SnippetProto>> entries);
- void OnDatabaseSaved(bool success);
-
- // Callbacks for ProtoDatabase<SnippetImageProto> operations.
- void OnImageDatabaseInited(bool success);
- void OnImageDatabaseLoaded(const SnippetImageCallback& callback,
- bool success,
- std::unique_ptr<SnippetImageProto> entry);
- void OnImageDatabaseSaved(bool success);
-
- void OnDatabaseError();
-
- void ProcessPendingLoads();
-
- void LoadSnippetsImpl(const SnippetsCallback& callback);
- void SaveSnippetsImpl(std::unique_ptr<KeyEntryVector> entries_to_save);
- void DeleteSnippetsImpl(
- std::unique_ptr<std::vector<std::string>> keys_to_remove);
-
- void LoadImageImpl(const std::string& snippet_id,
- const SnippetImageCallback& callback);
- void DeleteImagesImpl(
- std::unique_ptr<std::vector<std::string>> keys_to_remove);
-
- std::unique_ptr<leveldb_proto::ProtoDatabase<SnippetProto>> database_;
- bool database_initialized_;
- std::vector<SnippetsCallback> pending_snippets_callbacks_;
-
- std::unique_ptr<leveldb_proto::ProtoDatabase<SnippetImageProto>>
- image_database_;
- bool image_database_initialized_;
- std::vector<std::pair<std::string, SnippetImageCallback>>
- pending_image_callbacks_;
-
- base::Closure error_callback_;
-
- base::WeakPtrFactory<NTPSnippetsDatabase> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(NTPSnippetsDatabase);
-};
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_DATABASE_H_
diff --git a/chromium/components/ntp_snippets/ntp_snippets_database_unittest.cc b/chromium/components/ntp_snippets/ntp_snippets_database_unittest.cc
deleted file mode 100644
index 1640d43e313..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_database_unittest.cc
+++ /dev/null
@@ -1,289 +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 "components/ntp_snippets/ntp_snippets_database.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::ElementsAre;
-using testing::IsEmpty;
-using testing::Mock;
-using testing::_;
-
-namespace ntp_snippets {
-
-bool operator==(const SnippetSource& lhs, const SnippetSource& rhs) {
- return lhs.url == rhs.url && lhs.publisher_name == rhs.publisher_name &&
- lhs.amp_url == rhs.amp_url;
-}
-
-bool operator==(const NTPSnippet& lhs, const NTPSnippet& rhs) {
- return lhs.id() == rhs.id() && lhs.title() == rhs.title() &&
- lhs.snippet() == rhs.snippet() &&
- lhs.salient_image_url() == rhs.salient_image_url() &&
- lhs.publish_date() == rhs.publish_date() &&
- lhs.expiry_date() == rhs.expiry_date() &&
- lhs.source_index() == rhs.source_index() &&
- lhs.sources() == rhs.sources() && lhs.score() == rhs.score() &&
- lhs.is_discarded() == rhs.is_discarded();
-}
-
-namespace {
-
-std::unique_ptr<NTPSnippet> CreateTestSnippet() {
- std::unique_ptr<NTPSnippet> snippet(new NTPSnippet("http://localhost"));
- snippet->add_source(
- SnippetSource(GURL("http://localhost"), "Publisher", GURL("http://amp")));
- return snippet;
-}
-
-MATCHER_P(SnippetEq, snippet, "") {
- return *arg == *snippet;
-}
-
-} // namespace
-
-class NTPSnippetsDatabaseTest : public testing::Test {
- public:
- NTPSnippetsDatabaseTest() {
- EXPECT_TRUE(database_dir_.CreateUniqueTempDir());
- }
-
- ~NTPSnippetsDatabaseTest() override {
- // We need to run the message loop after deleting the database, because
- // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task
- // runner. Without this, we'd get reports of memory leaks.
- db_.reset();
- base::RunLoop().RunUntilIdle();
- }
-
- void CreateDatabase() {
- // Explicitly destroy any existing database first, so it releases the lock
- // on the file.
- db_.reset();
-
- db_.reset(new NTPSnippetsDatabase(database_dir_.path(),
- base::ThreadTaskRunnerHandle::Get()));
- }
-
- NTPSnippetsDatabase* db() { return db_.get(); }
-
- void OnSnippetsLoaded(NTPSnippet::PtrVector snippets) {
- OnSnippetsLoadedImpl(snippets);
- }
- MOCK_METHOD1(OnSnippetsLoadedImpl,
- void(const NTPSnippet::PtrVector& snippets));
-
- MOCK_METHOD1(OnImageLoaded, void(std::string));
-
- private:
- base::MessageLoop message_loop_;
- base::ScopedTempDir database_dir_;
- std::unique_ptr<NTPSnippetsDatabase> db_;
-
- DISALLOW_COPY_AND_ASSIGN(NTPSnippetsDatabaseTest);
-};
-
-TEST_F(NTPSnippetsDatabaseTest, Init) {
- ASSERT_FALSE(db());
-
- CreateDatabase();
- EXPECT_FALSE(db()->IsInitialized());
-
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(db()->IsInitialized());
-}
-
-TEST_F(NTPSnippetsDatabaseTest, LoadBeforeInit) {
- CreateDatabase();
- EXPECT_FALSE(db()->IsInitialized());
-
- // Start a snippet and image load before the DB is initialized.
- db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
- base::Unretained(this)));
- db()->LoadImage("id", base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
- base::Unretained(this)));
-
- // They should be serviced once initialization finishes.
- EXPECT_CALL(*this, OnSnippetsLoadedImpl(_));
- EXPECT_CALL(*this, OnImageLoaded(_));
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(db()->IsInitialized());
-}
-
-TEST_F(NTPSnippetsDatabaseTest, LoadAfterInit) {
- CreateDatabase();
- EXPECT_FALSE(db()->IsInitialized());
-
- EXPECT_CALL(*this, OnSnippetsLoadedImpl(_)).Times(0);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(db()->IsInitialized());
-
- Mock::VerifyAndClearExpectations(this);
-
- EXPECT_CALL(*this, OnSnippetsLoadedImpl(_));
- db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
- base::Unretained(this)));
- EXPECT_CALL(*this, OnImageLoaded(_));
- db()->LoadImage("id", base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(NTPSnippetsDatabaseTest, Save) {
- CreateDatabase();
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(db()->IsInitialized());
-
- std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
- std::string image_data("pretty image");
-
- // Store a snippet and an image.
- db()->SaveSnippet(*snippet);
- db()->SaveImage(snippet->id(), image_data);
-
- // Make sure they're there.
- EXPECT_CALL(*this,
- OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
- db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
-
- Mock::VerifyAndClearExpectations(this);
-
- EXPECT_CALL(*this, OnImageLoaded(image_data));
- db()->LoadImage(snippet->id(),
- base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(NTPSnippetsDatabaseTest, SavePersist) {
- CreateDatabase();
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(db()->IsInitialized());
-
- std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
- std::string image_data("pretty image");
-
- // Store a snippet and an image.
- db()->SaveSnippet(*snippet);
- db()->SaveImage(snippet->id(), image_data);
- base::RunLoop().RunUntilIdle();
-
- // They should still exist after recreating the database.
- CreateDatabase();
-
- EXPECT_CALL(*this,
- OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
- db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
- base::Unretained(this)));
- EXPECT_CALL(*this, OnImageLoaded(image_data));
- db()->LoadImage(snippet->id(),
- base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(NTPSnippetsDatabaseTest, Update) {
- CreateDatabase();
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(db()->IsInitialized());
-
- std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
-
- // Store a snippet.
- db()->SaveSnippet(*snippet);
-
- // Change it.
- const std::string text("some text");
- snippet->set_snippet(text);
- db()->SaveSnippet(*snippet);
-
- // Make sure we get the updated version.
- EXPECT_CALL(*this,
- OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
- db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(NTPSnippetsDatabaseTest, Delete) {
- CreateDatabase();
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(db()->IsInitialized());
-
- std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
-
- // Store a snippet.
- db()->SaveSnippet(*snippet);
-
- // Make sure it's there.
- EXPECT_CALL(*this,
- OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
- db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
-
- Mock::VerifyAndClearExpectations(this);
-
- // Delete the snippet.
- db()->DeleteSnippet(snippet->id());
-
- // Make sure it's gone.
- EXPECT_CALL(*this, OnSnippetsLoadedImpl(IsEmpty()));
- db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(NTPSnippetsDatabaseTest, DeleteSnippetAlsoDeletesImage) {
- CreateDatabase();
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(db()->IsInitialized());
-
- std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
- std::string image_data("pretty image");
-
- // Store a snippet and image.
- db()->SaveSnippet(*snippet);
- db()->SaveImage(snippet->id(), image_data);
- base::RunLoop().RunUntilIdle();
-
- // Make sure they're there.
- EXPECT_CALL(*this,
- OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
- db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
- base::Unretained(this)));
- EXPECT_CALL(*this, OnImageLoaded(image_data));
- db()->LoadImage(snippet->id(),
- base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
-
- Mock::VerifyAndClearExpectations(this);
-
- // Delete the snippet.
- db()->DeleteSnippet(snippet->id());
-
- // Make sure the image is gone.
- EXPECT_CALL(*this, OnImageLoaded(std::string()));
- db()->LoadImage(snippet->id(),
- base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_fetcher.cc b/chromium/components/ntp_snippets/ntp_snippets_fetcher.cc
deleted file mode 100644
index 4490ef24c3c..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_fetcher.cc
+++ /dev/null
@@ -1,533 +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 "components/ntp_snippets/ntp_snippets_fetcher.h"
-
-#include <stdlib.h>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/json/json_writer.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
-#include "base/path_service.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/time/default_tick_clock.h"
-#include "base/values.h"
-#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/ntp_snippets/ntp_snippets_constants.h"
-#include "components/ntp_snippets/switches.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "components/signin/core/browser/signin_manager_base.h"
-#include "components/variations/net/variations_http_headers.h"
-#include "components/variations/variations_associated_data.h"
-#include "google_apis/google_api_keys.h"
-#include "net/base/load_flags.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/url_fetcher.h"
-#include "third_party/icu/source/common/unicode/uloc.h"
-#include "third_party/icu/source/common/unicode/utypes.h"
-
-using net::URLFetcher;
-using net::URLRequestContextGetter;
-using net::HttpRequestHeaders;
-using net::URLRequestStatus;
-
-namespace ntp_snippets {
-
-namespace {
-
-const char kChromeReaderApiScope[] =
- "https://www.googleapis.com/auth/webhistory";
-const char kContentSuggestionsApiScope[] =
- "https://www.googleapis.com/auth/chrome-content-suggestions";
-const char kChromeReaderServer[] =
- "https://chromereader-pa.googleapis.com/v1/fetch";
-const char kContentSuggestionsServer[] =
- "https://chromecontentsuggestions-pa.googleapis.com/v1/snippets/list";
-const char kContentSuggestionsSandboxServer[] =
- "https://chromecontentsuggestions-pa.sandbox.googleapis.com/v1/snippets/"
- "list";
-const char kSnippetsServerNonAuthorizedFormat[] = "%s?key=%s";
-const char kAuthorizationRequestHeaderFormat[] = "Bearer %s";
-
-// Variation parameter for personalizing fetching of snippets.
-const char kPersonalizationName[] = "fetching_personalization";
-// Variation parameter for setting whether to restrict to a passed set of hosts.
-const char kHostRestrictionName[] = "fetching_host_restrict";
-
-// Variation parameter for chrome-content-suggestions backend.
-const char kContentSuggestionsBackend[] = "content_suggestions_backend";
-
-// Constants for possible values of the "fetching_personalization" parameter.
-const char kPersonalizationPersonalString[] = "personal";
-const char kPersonalizationNonPersonalString[] = "non_personal";
-const char kPersonalizationBothString[] = "both"; // the default value
-
-// Constants for possible values of the "fetching_host_restrict" parameter.
-const char kHostRestrictionOnString[] = "on"; // the default value
-const char kHostRestrictionOffString[] = "off";
-
-std::string FetchResultToString(NTPSnippetsFetcher::FetchResult result) {
- switch (result) {
- case NTPSnippetsFetcher::FetchResult::SUCCESS:
- return "OK";
- case NTPSnippetsFetcher::FetchResult::EMPTY_HOSTS:
- return "Cannot fetch for empty hosts list.";
- case NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR:
- return "URLRequestStatus error";
- case NTPSnippetsFetcher::FetchResult::HTTP_ERROR:
- return "HTTP error";
- case NTPSnippetsFetcher::FetchResult::JSON_PARSE_ERROR:
- return "Received invalid JSON";
- case NTPSnippetsFetcher::FetchResult::INVALID_SNIPPET_CONTENT_ERROR:
- return "Invalid / empty list.";
- case NTPSnippetsFetcher::FetchResult::OAUTH_TOKEN_ERROR:
- return "Error in obtaining an OAuth2 access token.";
- case NTPSnippetsFetcher::FetchResult::RESULT_MAX:
- break;
- }
- NOTREACHED();
- return "Unknown error";
-}
-
-std::string GetFetchEndpoint() {
- std::string endpoint = variations::GetVariationParamValue(
- ntp_snippets::kStudyName, kContentSuggestionsBackend);
- return endpoint.empty() ? kChromeReaderServer : endpoint;
-}
-
-bool UsesChromeContentSuggestionsAPI(const GURL& endpoint) {
- if (endpoint == GURL(kChromeReaderServer)) {
- return false;
- } else if (endpoint != GURL(kContentSuggestionsServer) &&
- endpoint != GURL(kContentSuggestionsSandboxServer)) {
- LOG(WARNING) << "Unknown value for " << kContentSuggestionsBackend << ": "
- << "assuming chromecontentsuggestions-style API";
- }
- return true;
-}
-
-// Creates snippets from dictionary values in |list| and adds them to
-// |snippets|. Returns true on success, false if anything went wrong.
-bool AddSnippetsFromListValue(bool content_suggestions_api,
- const base::ListValue& list,
- NTPSnippet::PtrVector* snippets) {
- for (const auto& value : list) {
- const base::DictionaryValue* dict = nullptr;
- if (!value->GetAsDictionary(&dict))
- return false;
-
- std::unique_ptr<NTPSnippet> snippet;
- if (content_suggestions_api) {
- snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*dict);
- } else {
- snippet = NTPSnippet::CreateFromChromeReaderDictionary(*dict);
- }
- if (!snippet)
- return false;
-
- snippets->push_back(std::move(snippet));
- }
- return true;
-}
-
-// Translate the BCP 47 |language_code| into a posix locale string.
-std::string PosixLocaleFromBCP47Language(const std::string& language_code) {
- char locale[ULOC_FULLNAME_CAPACITY];
- UErrorCode error = U_ZERO_ERROR;
- // Translate the input to a posix locale.
- uloc_forLanguageTag(language_code.c_str(), locale, ULOC_FULLNAME_CAPACITY,
- nullptr, &error);
- DLOG_IF(WARNING, U_ZERO_ERROR != error)
- << "Error in translating language code to a locale string: " << error;
- return locale;
-}
-
-} // namespace
-
-NTPSnippetsFetcher::NTPSnippetsFetcher(
- SigninManagerBase* signin_manager,
- OAuth2TokenService* token_service,
- scoped_refptr<URLRequestContextGetter> url_request_context_getter,
- const ParseJSONCallback& parse_json_callback,
- bool is_stable_channel)
- : OAuth2TokenService::Consumer("ntp_snippets"),
- signin_manager_(signin_manager),
- token_service_(token_service),
- waiting_for_refresh_token_(false),
- url_request_context_getter_(url_request_context_getter),
- parse_json_callback_(parse_json_callback),
- fetch_url_(GetFetchEndpoint()),
- fetch_api_(UsesChromeContentSuggestionsAPI(fetch_url_)
- ? CHROME_CONTENT_SUGGESTIONS_API
- : CHROME_READER_API),
- is_stable_channel_(is_stable_channel),
- tick_clock_(new base::DefaultTickClock()),
- weak_ptr_factory_(this) {
- // Parse the variation parameters and set the defaults if missing.
- std::string personalization = variations::GetVariationParamValue(
- ntp_snippets::kStudyName, kPersonalizationName);
- if (personalization == kPersonalizationNonPersonalString) {
- personalization_ = Personalization::kNonPersonal;
- } else if (personalization == kPersonalizationPersonalString) {
- personalization_ = Personalization::kPersonal;
- } else {
- personalization_ = Personalization::kBoth;
- LOG_IF(WARNING, !personalization.empty() &&
- personalization != kPersonalizationBothString)
- << "Unknown value for " << kPersonalizationName << ": "
- << personalization;
- }
-
- std::string host_restriction = variations::GetVariationParamValue(
- ntp_snippets::kStudyName, kHostRestrictionName);
- if (host_restriction == kHostRestrictionOnString) {
- use_host_restriction_ = true;
- } else {
- use_host_restriction_ = false;
- LOG_IF(WARNING, !host_restriction.empty() &&
- host_restriction != kHostRestrictionOffString)
- << "Unknown value for " << kHostRestrictionName << ": "
- << host_restriction;
- }
-}
-
-NTPSnippetsFetcher::~NTPSnippetsFetcher() {
- if (waiting_for_refresh_token_)
- token_service_->RemoveObserver(this);
-}
-
-void NTPSnippetsFetcher::SetCallback(
- const SnippetsAvailableCallback& callback) {
- snippets_available_callback_ = callback;
-}
-
-void NTPSnippetsFetcher::FetchSnippetsFromHosts(
- const std::set<std::string>& hosts,
- const std::string& language_code,
- int count) {
- hosts_ = hosts;
- fetch_start_time_ = tick_clock_->NowTicks();
-
- if (UsesHostRestrictions() && hosts_.empty()) {
- FetchFinished(OptionalSnippets(), FetchResult::EMPTY_HOSTS,
- /*extra_message=*/std::string());
- return;
- }
-
- locale_ = PosixLocaleFromBCP47Language(language_code);
- count_to_fetch_ = count;
-
- bool use_authentication = UsesAuthentication();
-
- if (use_authentication && signin_manager_->IsAuthenticated()) {
- // Signed-in: get OAuth token --> fetch snippets.
- StartTokenRequest();
- } else if (use_authentication && signin_manager_->AuthInProgress()) {
- // Currently signing in: wait for auth to finish (the refresh token) -->
- // get OAuth token --> fetch snippets.
- if (!waiting_for_refresh_token_) {
- // Wait until we get a refresh token.
- waiting_for_refresh_token_ = true;
- token_service_->AddObserver(this);
- }
- } else {
- // Not signed in: fetch snippets (without authentication).
- FetchSnippetsNonAuthenticated();
- }
-}
-
-NTPSnippetsFetcher::RequestParams::RequestParams()
- : fetch_api(),
- obfuscated_gaia_id(),
- only_return_personalized_results(),
- user_locale(),
- host_restricts(),
- count_to_fetch() {}
-
-NTPSnippetsFetcher::RequestParams::~RequestParams() = default;
-
-std::string NTPSnippetsFetcher::RequestParams::BuildRequest() {
- auto request = base::MakeUnique<base::DictionaryValue>();
- if (fetch_api == CHROME_READER_API) {
- auto content_params = base::MakeUnique<base::DictionaryValue>();
- content_params->SetBoolean("only_return_personalized_results",
- only_return_personalized_results);
-
- auto content_restricts = base::MakeUnique<base::ListValue>();
- for (const auto& metadata : {"TITLE", "SNIPPET", "THUMBNAIL"}) {
- auto entry = base::MakeUnique<base::DictionaryValue>();
- entry->SetString("type", "METADATA");
- entry->SetString("value", metadata);
- content_restricts->Append(std::move(entry));
- }
-
- auto content_selectors = base::MakeUnique<base::ListValue>();
- for (const auto& host : host_restricts) {
- auto entry = base::MakeUnique<base::DictionaryValue>();
- entry->SetString("type", "HOST_RESTRICT");
- entry->SetString("value", host);
- content_selectors->Append(std::move(entry));
- }
-
- auto local_scoring_params = base::MakeUnique<base::DictionaryValue>();
- local_scoring_params->Set("content_params", std::move(content_params));
- local_scoring_params->Set("content_restricts",
- std::move(content_restricts));
- local_scoring_params->Set("content_selectors",
- std::move(content_selectors));
-
- auto global_scoring_params = base::MakeUnique<base::DictionaryValue>();
- global_scoring_params->SetInteger("num_to_return", count_to_fetch);
- global_scoring_params->SetInteger("sort_type", 1);
-
- auto advanced = base::MakeUnique<base::DictionaryValue>();
- advanced->Set("local_scoring_params", std::move(local_scoring_params));
- advanced->Set("global_scoring_params", std::move(global_scoring_params));
-
- request->SetString("response_detail_level", "STANDARD");
- request->Set("advanced_options", std::move(advanced));
- if (!obfuscated_gaia_id.empty()) {
- request->SetString("obfuscated_gaia_id", obfuscated_gaia_id);
- }
- if (!user_locale.empty()) {
- request->SetString("user_locale", user_locale);
- }
- } else {
- if (!user_locale.empty()) {
- request->SetString("uiLanguage", user_locale);
- }
- auto regular_hosts = base::MakeUnique<base::ListValue>();
- for (const auto& host : host_restricts) {
- regular_hosts->AppendString(host);
- }
- request->Set("regularlyVisitedHostName", std::move(regular_hosts));
-
- // TODO(sfiera): support authentication and personalization
- // TODO(sfiera): support count_to_fetch
- }
-
- std::string request_json;
- bool success = base::JSONWriter::WriteWithOptions(
- *request, base::JSONWriter::OPTIONS_PRETTY_PRINT, &request_json);
- DCHECK(success);
- return request_json;
-}
-
-void NTPSnippetsFetcher::FetchSnippetsImpl(const GURL& url,
- const std::string& auth_header,
- const std::string& request) {
- url_fetcher_ = URLFetcher::Create(url, URLFetcher::POST, this);
-
- url_fetcher_->SetRequestContext(url_request_context_getter_.get());
- url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
- net::LOAD_DO_NOT_SAVE_COOKIES);
-
- data_use_measurement::DataUseUserData::AttachToFetcher(
- url_fetcher_.get(), data_use_measurement::DataUseUserData::NTP_SNIPPETS);
-
- HttpRequestHeaders headers;
- if (!auth_header.empty())
- headers.SetHeader("Authorization", auth_header);
- headers.SetHeader("Content-Type", "application/json; charset=UTF-8");
- // Add X-Client-Data header with experiment IDs from field trials.
- variations::AppendVariationHeaders(url,
- false, // incognito
- false, // uma_enabled
- &headers);
- url_fetcher_->SetExtraRequestHeaders(headers.ToString());
- url_fetcher_->SetUploadData("application/json", request);
- // Log the request for debugging network issues.
- VLOG(1) << "Sending a NTP snippets request to " << url << ":" << std::endl
- << headers.ToString() << std::endl << request;
- // Fetchers are sometimes cancelled because a network change was detected.
- url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
- // Try to make fetching the files bit more robust even with poor connection.
- url_fetcher_->SetMaxRetriesOn5xx(3);
- url_fetcher_->Start();
-}
-
-bool NTPSnippetsFetcher::UsesHostRestrictions() const {
- return use_host_restriction_ &&
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDontRestrict);
-}
-
-bool NTPSnippetsFetcher::UsesAuthentication() const {
- return (personalization_ == Personalization::kPersonal ||
- personalization_ == Personalization::kBoth);
-}
-
-void NTPSnippetsFetcher::FetchSnippetsNonAuthenticated() {
- // When not providing OAuth token, we need to pass the Google API key.
- const std::string& key = is_stable_channel_
- ? google_apis::GetAPIKey()
- : google_apis::GetNonStableAPIKey();
- GURL url(base::StringPrintf(kSnippetsServerNonAuthorizedFormat,
- fetch_url_.spec().c_str(), key.c_str()));
-
- RequestParams params;
- params.fetch_api = fetch_api_;
- params.host_restricts =
- UsesHostRestrictions() ? hosts_ : std::set<std::string>();
- params.count_to_fetch = count_to_fetch_;
- FetchSnippetsImpl(url, std::string(), params.BuildRequest());
-}
-
-void NTPSnippetsFetcher::FetchSnippetsAuthenticated(
- const std::string& account_id,
- const std::string& oauth_access_token) {
- RequestParams params;
- params.fetch_api = fetch_api_;
- params.obfuscated_gaia_id = account_id;
- params.only_return_personalized_results =
- personalization_ == Personalization::kPersonal;
- params.user_locale = locale_;
- params.host_restricts =
- UsesHostRestrictions() ? hosts_ : std::set<std::string>();
- params.count_to_fetch = count_to_fetch_;
- FetchSnippetsImpl(fetch_url_,
- base::StringPrintf(kAuthorizationRequestHeaderFormat,
- oauth_access_token.c_str()),
- params.BuildRequest());
-}
-
-void NTPSnippetsFetcher::StartTokenRequest() {
- OAuth2TokenService::ScopeSet scopes;
- scopes.insert(fetch_api_ == CHROME_CONTENT_SUGGESTIONS_API
- ? kContentSuggestionsApiScope
- : kChromeReaderApiScope);
- oauth_request_ = token_service_->StartRequest(
- signin_manager_->GetAuthenticatedAccountId(), scopes, this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// OAuth2TokenService::Consumer overrides
-void NTPSnippetsFetcher::OnGetTokenSuccess(
- const OAuth2TokenService::Request* request,
- const std::string& access_token,
- const base::Time& expiration_time) {
- // Delete the request after we leave this method.
- std::unique_ptr<OAuth2TokenService::Request> oauth_request(
- std::move(oauth_request_));
- DCHECK_EQ(oauth_request.get(), request)
- << "Got tokens from some previous request";
-
- FetchSnippetsAuthenticated(oauth_request->GetAccountId(), access_token);
-}
-
-void NTPSnippetsFetcher::OnGetTokenFailure(
- const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) {
- oauth_request_.reset();
- DLOG(ERROR) << "Unable to get token: " << error.ToString()
- << " - fetching the snippets without authentication.";
- FetchFinished(
- OptionalSnippets(), FetchResult::OAUTH_TOKEN_ERROR,
- /*extra_message=*/base::StringPrintf(" (%s)", error.ToString().c_str()));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// OAuth2TokenService::Observer overrides
-void NTPSnippetsFetcher::OnRefreshTokenAvailable(
- const std::string& account_id) {
- // Only react on tokens for the account the user has signed in with.
- if (account_id != signin_manager_->GetAuthenticatedAccountId())
- return;
-
- token_service_->RemoveObserver(this);
- waiting_for_refresh_token_ = false;
- StartTokenRequest();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// URLFetcherDelegate overrides
-void NTPSnippetsFetcher::OnURLFetchComplete(const URLFetcher* source) {
- DCHECK_EQ(url_fetcher_.get(), source);
-
- const URLRequestStatus& status = source->GetStatus();
-
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode",
- status.is_success() ? source->GetResponseCode() : status.error());
-
- if (!status.is_success()) {
- FetchFinished(OptionalSnippets(), FetchResult::URL_REQUEST_STATUS_ERROR,
- /*extra_message=*/base::StringPrintf(" %d", status.error()));
- } else if (source->GetResponseCode() != net::HTTP_OK) {
- // TODO(jkrcal): https://crbug.com/609084
- // We need to deal with the edge case again where the auth
- // token expires just before we send the request (in which case we need to
- // fetch a new auth token). We should extract that into a common class
- // instead of adding it to every single class that uses auth tokens.
- FetchFinished(
- OptionalSnippets(), FetchResult::HTTP_ERROR,
- /*extra_message=*/base::StringPrintf(" %d", source->GetResponseCode()));
- } else {
- bool stores_result_to_string = source->GetResponseAsString(
- &last_fetch_json_);
- DCHECK(stores_result_to_string);
-
- parse_json_callback_.Run(
- last_fetch_json_,
- base::Bind(&NTPSnippetsFetcher::OnJsonParsed,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&NTPSnippetsFetcher::OnJsonError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-}
-
-void NTPSnippetsFetcher::OnJsonParsed(std::unique_ptr<base::Value> parsed) {
- const base::DictionaryValue* top_dict = nullptr;
- const base::ListValue* list = nullptr;
- NTPSnippet::PtrVector snippets;
- const std::string list_key =
- fetch_api_ == CHROME_CONTENT_SUGGESTIONS_API ? "snippet" : "recos";
- if (!parsed->GetAsDictionary(&top_dict) ||
- !top_dict->GetList(list_key, &list) ||
- !AddSnippetsFromListValue(fetch_api_ == CHROME_CONTENT_SUGGESTIONS_API,
- *list, &snippets)) {
- LOG(WARNING) << "Received invalid snippets: " << last_fetch_json_;
- FetchFinished(OptionalSnippets(),
- FetchResult::INVALID_SNIPPET_CONTENT_ERROR,
- /*extra_message=*/std::string());
- } else {
- FetchFinished(OptionalSnippets(std::move(snippets)), FetchResult::SUCCESS,
- /*extra_message=*/std::string());
- }
-}
-
-void NTPSnippetsFetcher::OnJsonError(const std::string& error) {
- LOG(WARNING) << "Received invalid JSON (" << error << "): "
- << last_fetch_json_;
- FetchFinished(
- OptionalSnippets(), FetchResult::JSON_PARSE_ERROR,
- /*extra_message=*/base::StringPrintf(" (error %s)", error.c_str()));
-}
-
-void NTPSnippetsFetcher::FetchFinished(OptionalSnippets snippets,
- FetchResult result,
- const std::string& extra_message) {
- DCHECK(result == FetchResult::SUCCESS || !snippets);
- last_status_ = FetchResultToString(result) + extra_message;
-
- UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime",
- tick_clock_->NowTicks() - fetch_start_time_);
- UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult",
- static_cast<int>(result),
- static_cast<int>(FetchResult::RESULT_MAX));
-
- if (!snippets_available_callback_.is_null())
- snippets_available_callback_.Run(std::move(snippets));
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_fetcher.h b/chromium/components/ntp_snippets/ntp_snippets_fetcher.h
deleted file mode 100644
index 18cb4eca445..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_fetcher.h
+++ /dev/null
@@ -1,223 +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 COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_FETCHER_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_FETCHER_H_
-
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
-#include "base/time/tick_clock.h"
-#include "base/time/time.h"
-#include "components/ntp_snippets/ntp_snippet.h"
-#include "google_apis/gaia/oauth2_token_service.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "net/url_request/url_request_context_getter.h"
-
-class SigninManagerBase;
-
-namespace base {
-class Value;
-} // namespace base
-
-namespace net {
-class HttpRequestHeaders;
-} // namespace net
-
-namespace ntp_snippets {
-
-// Fetches snippet data for the NTP from the server.
-class NTPSnippetsFetcher : public OAuth2TokenService::Consumer,
- public OAuth2TokenService::Observer,
- public net::URLFetcherDelegate {
- public:
- // Callbacks for JSON parsing, needed because the parsing is platform-
- // dependent.
- using SuccessCallback = base::Callback<void(std::unique_ptr<base::Value>)>;
- using ErrorCallback = base::Callback<void(const std::string&)>;
- using ParseJSONCallback = base::Callback<
- void(const std::string&, const SuccessCallback&, const ErrorCallback&)>;
-
- using OptionalSnippets = base::Optional<NTPSnippet::PtrVector>;
- // |snippets| contains parsed snippets if a fetch succeeded. If problems
- // occur, |snippets| contains no value (no actual vector in base::Optional).
- // Error details can be retrieved using last_status().
- using SnippetsAvailableCallback =
- base::Callback<void(OptionalSnippets snippets)>;
-
- // Enumeration listing all possible outcomes for fetch attempts. Used for UMA
- // histograms, so do not change existing values. Insert new values at the end,
- // and update the histogram definition.
- enum class FetchResult {
- SUCCESS,
- EMPTY_HOSTS,
- URL_REQUEST_STATUS_ERROR,
- HTTP_ERROR,
- JSON_PARSE_ERROR,
- INVALID_SNIPPET_CONTENT_ERROR,
- OAUTH_TOKEN_ERROR,
- RESULT_MAX
- };
-
- // Enumeration listing all possible variants of dealing with personalization.
- enum class Personalization {
- kPersonal,
- kNonPersonal,
- kBoth
- };
-
- NTPSnippetsFetcher(
- SigninManagerBase* signin_manager,
- OAuth2TokenService* oauth2_token_service,
- scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
- const ParseJSONCallback& parse_json_callback,
- bool is_stable_channel);
- ~NTPSnippetsFetcher() override;
-
- // Set a callback that is called when a new set of snippets are downloaded,
- // overriding any previously set callback.
- void SetCallback(const SnippetsAvailableCallback& callback);
-
- // Fetches snippets from the server. |hosts| restricts the results to a set of
- // hosts, e.g. "www.google.com". An empty host set produces an error.
- //
- // If an ongoing fetch exists, it will be cancelled and a new one started,
- // without triggering an additional callback (i.e. not noticeable by
- // subscriber of SetCallback()).
- void FetchSnippetsFromHosts(const std::set<std::string>& hosts,
- const std::string& language_code,
- int count);
-
- // Debug string representing the status/result of the last fetch attempt.
- const std::string& last_status() const { return last_status_; }
-
- // Returns the last JSON fetched from the server.
- const std::string& last_json() const {
- return last_fetch_json_;
- }
-
- // Returns the personalization setting of the fetcher.
- Personalization personalization() const { return personalization_; }
-
- // Does the fetcher use host restrictions?
- bool UsesHostRestrictions() const;
- // Does the fetcher use authentication to get personalized results?
- bool UsesAuthentication() const;
-
- // Overrides internal clock for testing purposes.
- void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock) {
- tick_clock_ = std::move(tick_clock);
- }
-
- void SetPersonalizationForTesting(Personalization personalization) {
- personalization_ = personalization;
- }
-
- private:
- FRIEND_TEST_ALL_PREFIXES(NTPSnippetsFetcherTest, BuildRequestAuthenticated);
- FRIEND_TEST_ALL_PREFIXES(NTPSnippetsFetcherTest, BuildRequestUnauthenticated);
-
- enum FetchAPI {
- CHROME_READER_API,
- CHROME_CONTENT_SUGGESTIONS_API,
- };
-
- struct RequestParams {
- FetchAPI fetch_api;
- std::string obfuscated_gaia_id;
- bool only_return_personalized_results;
- std::string user_locale;
- std::set<std::string> host_restricts;
- int count_to_fetch;
-
- RequestParams();
- ~RequestParams();
-
- std::string BuildRequest();
- };
-
- void FetchSnippetsImpl(const GURL& url,
- const std::string& auth_header,
- const std::string& request);
- void FetchSnippetsNonAuthenticated();
- void FetchSnippetsAuthenticated(const std::string& account_id,
- const std::string& oauth_access_token);
- void StartTokenRequest();
-
- // OAuth2TokenService::Consumer overrides:
- void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
- const std::string& access_token,
- const base::Time& expiration_time) override;
- void OnGetTokenFailure(const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) override;
-
- // OAuth2TokenService::Observer overrides:
- void OnRefreshTokenAvailable(const std::string& account_id) override;
-
- // URLFetcherDelegate implementation.
- void OnURLFetchComplete(const net::URLFetcher* source) override;
-
- void OnJsonParsed(std::unique_ptr<base::Value> parsed);
- void OnJsonError(const std::string& error);
- void FetchFinished(OptionalSnippets snippets,
- FetchResult result,
- const std::string& extra_message);
-
- // Authorization for signed-in users.
- SigninManagerBase* signin_manager_;
- OAuth2TokenService* token_service_;
- std::unique_ptr<OAuth2TokenService::Request> oauth_request_;
- bool waiting_for_refresh_token_;
-
- // Holds the URL request context.
- scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
-
- const ParseJSONCallback parse_json_callback_;
- base::TimeTicks fetch_start_time_;
- std::string last_status_;
- std::string last_fetch_json_;
-
- // Hosts to restrict the snippets to.
- std::set<std::string> hosts_;
-
- // Count of snippets to fetch.
- int count_to_fetch_;
-
- // Language code to restrict to for personalized results.
- std::string locale_;
-
- // API endpoint for fetching snippets.
- const GURL fetch_url_;
- // Which API to use
- const FetchAPI fetch_api_;
-
- // The fetcher for downloading the snippets.
- std::unique_ptr<net::URLFetcher> url_fetcher_;
-
- // The callback to notify when new snippets get fetched.
- SnippetsAvailableCallback snippets_available_callback_;
-
- // Flag for picking the right (stable/non-stable) API key for Chrome Reader.
- bool is_stable_channel_;
-
- // The variant of the fetching to use, loaded from variation parameters.
- Personalization personalization_;
- // Should we apply host restriction? It is loaded from variation parameters.
- bool use_host_restriction_;
-
- // Allow for an injectable tick clock for testing.
- std::unique_ptr<base::TickClock> tick_clock_;
-
- base::WeakPtrFactory<NTPSnippetsFetcher> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(NTPSnippetsFetcher);
-};
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_FETCHER_H_
diff --git a/chromium/components/ntp_snippets/ntp_snippets_fetcher_unittest.cc b/chromium/components/ntp_snippets/ntp_snippets_fetcher_unittest.cc
deleted file mode 100644
index a0f7893ac6e..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_fetcher_unittest.cc
+++ /dev/null
@@ -1,572 +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 "components/ntp_snippets/ntp_snippets_fetcher.h"
-
-#include "base/json/json_reader.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/histogram_tester.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "components/ntp_snippets/ntp_snippet.h"
-#include "components/ntp_snippets/ntp_snippets_constants.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
-#include "components/signin/core/browser/test_signin_client.h"
-#include "components/variations/entropy_provider.h"
-#include "components/variations/variations_associated_data.h"
-#include "google_apis/google_api_keys.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ntp_snippets {
-
-namespace {
-
-using testing::ElementsAre;
-using testing::Eq;
-using testing::IsEmpty;
-using testing::IsNull;
-using testing::Not;
-using testing::NotNull;
-using testing::PrintToString;
-using testing::SizeIs;
-using testing::StartsWith;
-
-const char kTestChromeReaderUrlFormat[] =
- "https://chromereader-pa.googleapis.com/v1/fetch?key=%s";
-const char kTestChromeContentSuggestionsUrlFormat[] =
- "https://chromecontentsuggestions-pa.googleapis.com/v1/snippets/"
- "list?key=%s";
-const char kContentSuggestionsBackend[] =
- "https://chromecontentsuggestions-pa.googleapis.com/v1/snippets/list";
-
-// Artificial time delay for JSON parsing.
-const int64_t kTestJsonParsingLatencyMs = 20;
-
-MATCHER(HasValue, "") {
- return static_cast<bool>(arg);
-}
-
-MATCHER_P(PointeeSizeIs,
- size,
- std::string("contains a value with size ") + PrintToString(size)) {
- return arg && static_cast<int>(arg->size()) == size;
-}
-
-MATCHER_P(EqualsJSON, json, "equals JSON") {
- std::unique_ptr<base::Value> expected = base::JSONReader::Read(json);
- if (!expected) {
- *result_listener << "INTERNAL ERROR: couldn't parse expected JSON";
- return false;
- }
-
- std::string err_msg;
- int err_line, err_col;
- std::unique_ptr<base::Value> actual = base::JSONReader::ReadAndReturnError(
- arg, base::JSON_PARSE_RFC, nullptr, &err_msg, &err_line, &err_col);
- if (!actual) {
- *result_listener << "input:" << err_line << ":" << err_col << ": "
- << "parse error: " << err_msg;
- return false;
- }
- return base::Value::Equals(actual.get(), expected.get());
-}
-
-class MockSnippetsAvailableCallback {
- public:
- // Workaround for gMock's lack of support for movable arguments.
- void WrappedRun(NTPSnippetsFetcher::OptionalSnippets snippets) {
- Run(snippets);
- }
-
- MOCK_METHOD1(Run, void(const NTPSnippetsFetcher::OptionalSnippets& snippets));
-};
-
-// Factory for FakeURLFetcher objects that always generate errors.
-class FailingFakeURLFetcherFactory : public net::URLFetcherFactory {
- public:
- std::unique_ptr<net::URLFetcher> CreateURLFetcher(
- int id, const GURL& url, net::URLFetcher::RequestType request_type,
- net::URLFetcherDelegate* d) override {
- return base::WrapUnique(new net::FakeURLFetcher(
- url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND,
- net::URLRequestStatus::FAILED));
- }
-};
-
-void ParseJson(
- const std::string& json,
- const ntp_snippets::NTPSnippetsFetcher::SuccessCallback& success_callback,
- const ntp_snippets::NTPSnippetsFetcher::ErrorCallback& error_callback) {
- base::JSONReader json_reader;
- std::unique_ptr<base::Value> value = json_reader.ReadToValue(json);
- if (value)
- success_callback.Run(std::move(value));
- else
- error_callback.Run(json_reader.GetErrorMessage());
-}
-
-void ParseJsonDelayed(
- const std::string& json,
- const ntp_snippets::NTPSnippetsFetcher::SuccessCallback& success_callback,
- const ntp_snippets::NTPSnippetsFetcher::ErrorCallback& error_callback) {
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&ParseJson, json, success_callback, error_callback),
- base::TimeDelta::FromMilliseconds(kTestJsonParsingLatencyMs));
-}
-
-class VariationParams {
- public:
- VariationParams(const std::string& trial_name,
- const std::map<std::string, std::string>& params)
- : field_trial_list_(new metrics::SHA1EntropyProvider("foo")) {
- variations::AssociateVariationParams(trial_name, "Group1", params);
- base::FieldTrialList::CreateFieldTrial(trial_name, "Group1");
- }
-
- ~VariationParams() { variations::testing::ClearAllVariationParams(); }
-
- private:
- base::FieldTrialList field_trial_list_;
-};
-
-} // namespace
-
-class NTPSnippetsFetcherTest : public testing::Test {
- public:
- NTPSnippetsFetcherTest()
- : NTPSnippetsFetcherTest(
- GURL(base::StringPrintf(kTestChromeReaderUrlFormat,
- google_apis::GetAPIKey().c_str())),
- std::map<std::string, std::string>()) {}
-
- NTPSnippetsFetcherTest(const GURL& gurl,
- const std::map<std::string, std::string>& params)
- : params_(ntp_snippets::kStudyName, params),
- mock_task_runner_(new base::TestMockTimeTaskRunner()),
- mock_task_runner_handle_(mock_task_runner_),
- signin_client_(new TestSigninClient(nullptr)),
- account_tracker_(new AccountTrackerService()),
- fake_signin_manager_(new FakeSigninManagerBase(signin_client_.get(),
- account_tracker_.get())),
- fake_token_service_(new FakeProfileOAuth2TokenService()),
- snippets_fetcher_(
- fake_signin_manager_.get(),
- fake_token_service_.get(),
- scoped_refptr<net::TestURLRequestContextGetter>(
- new net::TestURLRequestContextGetter(mock_task_runner_.get())),
- base::Bind(&ParseJsonDelayed),
- /*is_stable_channel=*/true),
- test_lang_("en-US"),
- test_url_(gurl) {
- snippets_fetcher_.SetCallback(
- base::Bind(&MockSnippetsAvailableCallback::WrappedRun,
- base::Unretained(&mock_callback_)));
- snippets_fetcher_.SetTickClockForTesting(
- mock_task_runner_->GetMockTickClock());
- test_hosts_.insert("www.somehost.com");
- // Increase initial time such that ticks are non-zero.
- mock_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(1234));
- }
-
- NTPSnippetsFetcher& snippets_fetcher() { return snippets_fetcher_; }
- MockSnippetsAvailableCallback& mock_callback() { return mock_callback_; }
- void FastForwardUntilNoTasksRemain() {
- mock_task_runner_->FastForwardUntilNoTasksRemain();
- }
- const std::string& test_lang() const { return test_lang_; }
- const GURL& test_url() { return test_url_; }
- const std::set<std::string>& test_hosts() const { return test_hosts_; }
- base::HistogramTester& histogram_tester() { return histogram_tester_; }
-
- void InitFakeURLFetcherFactory() {
- if (fake_url_fetcher_factory_)
- return;
- // Instantiation of factory automatically sets itself as URLFetcher's
- // factory.
- fake_url_fetcher_factory_.reset(new net::FakeURLFetcherFactory(
- /*default_factory=*/&failing_url_fetcher_factory_));
- }
-
- void SetFakeResponse(const std::string& response_data,
- net::HttpStatusCode response_code,
- net::URLRequestStatus::Status status) {
- InitFakeURLFetcherFactory();
- fake_url_fetcher_factory_->SetFakeResponse(test_url_, response_data,
- response_code, status);
- }
-
- private:
- VariationParams params_;
- scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_;
- base::ThreadTaskRunnerHandle mock_task_runner_handle_;
- FailingFakeURLFetcherFactory failing_url_fetcher_factory_;
- // Initialized lazily in SetFakeResponse().
- std::unique_ptr<net::FakeURLFetcherFactory> fake_url_fetcher_factory_;
- std::unique_ptr<TestSigninClient> signin_client_;
- std::unique_ptr<AccountTrackerService> account_tracker_;
- std::unique_ptr<SigninManagerBase> fake_signin_manager_;
- std::unique_ptr<OAuth2TokenService> fake_token_service_;
- NTPSnippetsFetcher snippets_fetcher_;
- MockSnippetsAvailableCallback mock_callback_;
- const std::string test_lang_;
- const GURL test_url_;
- std::set<std::string> test_hosts_;
- base::HistogramTester histogram_tester_;
-
- DISALLOW_COPY_AND_ASSIGN(NTPSnippetsFetcherTest);
-};
-
-class NTPSnippetsContentSuggestionsFetcherTest : public NTPSnippetsFetcherTest {
- public:
- NTPSnippetsContentSuggestionsFetcherTest()
- : NTPSnippetsFetcherTest(
- GURL(base::StringPrintf(kTestChromeContentSuggestionsUrlFormat,
- google_apis::GetAPIKey().c_str())),
- std::map<std::string, std::string>{
- {"content_suggestions_backend", kContentSuggestionsBackend}}) {}
-};
-
-TEST_F(NTPSnippetsFetcherTest, BuildRequestAuthenticated) {
- NTPSnippetsFetcher::RequestParams params;
- params.obfuscated_gaia_id = "0BFUSGAIA";
- params.only_return_personalized_results = true;
- params.user_locale = "en";
- params.host_restricts = {"chromium.org"};
- params.count_to_fetch = 25;
-
- params.fetch_api = NTPSnippetsFetcher::CHROME_READER_API;
- EXPECT_THAT(params.BuildRequest(),
- EqualsJSON("{"
- " \"response_detail_level\": \"STANDARD\","
- " \"obfuscated_gaia_id\": \"0BFUSGAIA\","
- " \"user_locale\": \"en\","
- " \"advanced_options\": {"
- " \"local_scoring_params\": {"
- " \"content_params\": {"
- " \"only_return_personalized_results\": true"
- " },"
- " \"content_restricts\": ["
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"TITLE\""
- " },"
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"SNIPPET\""
- " },"
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"THUMBNAIL\""
- " }"
- " ],"
- " \"content_selectors\": ["
- " {"
- " \"type\": \"HOST_RESTRICT\","
- " \"value\": \"chromium.org\""
- " }"
- " ]"
- " },"
- " \"global_scoring_params\": {"
- " \"num_to_return\": 25,"
- " \"sort_type\": 1"
- " }"
- " }"
- "}"));
-
- params.fetch_api = NTPSnippetsFetcher::CHROME_CONTENT_SUGGESTIONS_API;
- EXPECT_THAT(params.BuildRequest(),
- EqualsJSON("{"
- " \"uiLanguage\": \"en\","
- " \"regularlyVisitedHostName\": ["
- " \"chromium.org\""
- " ]"
- "}"));
-}
-
-TEST_F(NTPSnippetsFetcherTest, BuildRequestUnauthenticated) {
- NTPSnippetsFetcher::RequestParams params;
- params.only_return_personalized_results = false;
- params.host_restricts = {};
- params.count_to_fetch = 10;
-
- params.fetch_api = NTPSnippetsFetcher::CHROME_READER_API;
- EXPECT_THAT(params.BuildRequest(),
- EqualsJSON("{"
- " \"response_detail_level\": \"STANDARD\","
- " \"advanced_options\": {"
- " \"local_scoring_params\": {"
- " \"content_params\": {"
- " \"only_return_personalized_results\": false"
- " },"
- " \"content_restricts\": ["
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"TITLE\""
- " },"
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"SNIPPET\""
- " },"
- " {"
- " \"type\": \"METADATA\","
- " \"value\": \"THUMBNAIL\""
- " }"
- " ],"
- " \"content_selectors\": []"
- " },"
- " \"global_scoring_params\": {"
- " \"num_to_return\": 10,"
- " \"sort_type\": 1"
- " }"
- " }"
- "}"));
-
- params.fetch_api = NTPSnippetsFetcher::CHROME_CONTENT_SUGGESTIONS_API;
- EXPECT_THAT(params.BuildRequest(),
- EqualsJSON("{"
- " \"regularlyVisitedHostName\": []"
- "}"));
-}
-
-TEST_F(NTPSnippetsFetcherTest, ShouldNotFetchOnCreation) {
- // The lack of registered baked in responses would cause any fetch to fail.
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- IsEmpty());
- EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
- IsEmpty());
- EXPECT_THAT(snippets_fetcher().last_status(), IsEmpty());
-}
-
-TEST_F(NTPSnippetsFetcherTest, ShouldFetchSuccessfully) {
- const std::string kJsonStr =
- "{\"recos\": [{"
- " \"contentInfo\": {"
- " \"url\" : \"http://localhost/foobar\","
- " \"sourceCorpusInfo\" : [{"
- " \"ampUrl\" : \"http://localhost/amp\","
- " \"corpusId\" : \"http://localhost/foobar\","
- " \"publisherData\": { \"sourceName\" : \"Foo News\" }"
- " }]"
- " }"
- "}]}";
- SetFakeResponse(/*data=*/kJsonStr, net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(), Run(/*snippets=*/PointeeSizeIs(1))).Times(1);
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK"));
- EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
- ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
- /*count=*/1)));
-}
-
-TEST_F(NTPSnippetsContentSuggestionsFetcherTest, ShouldFetchSuccessfully) {
- const std::string kJsonStr =
- "{\"snippet\" : [{"
- " \"id\" : [\"http://localhost/foobar\"],"
- " \"title\" : \"Foo Barred from Baz\","
- " \"summaryText\" : \"...\","
- " \"fullPageUrl\" : \"http://localhost/foobar\","
- " \"publishTime\" : \"2016-06-30T11:01:37.000Z\","
- " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\","
- " \"publisherName\" : \"Foo News\","
- " \"imageUrl\" : \"http://localhost/foobar.jpg\","
- " \"ampUrl\" : \"http://localhost/amp\","
- " \"faviconUrl\" : \"http://localhost/favicon.ico\" "
- "}]}";
- SetFakeResponse(/*data=*/kJsonStr, net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(), Run(/*snippets=*/PointeeSizeIs(1))).Times(1);
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK"));
- EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
- ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
- /*count=*/1)));
-}
-
-TEST_F(NTPSnippetsFetcherTest, ShouldFetchSuccessfullyEmptyList) {
- const std::string kJsonStr = "{\"recos\": []}";
- SetFakeResponse(/*data=*/kJsonStr, net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(), Run(/*snippets=*/PointeeSizeIs(0))).Times(1);
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK"));
- EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
- EXPECT_THAT(
- histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
-}
-
-// TODO(jkrcal) Return the tests ShouldReportEmptyHostsError and
-// ShouldRestrictToHosts once we have a way to change variation parameters from
-// unittests. The tests were tailored to previous default value of the parameter
-// fetching_host_restrict, which changed now.
-TEST_F(NTPSnippetsFetcherTest, ShouldReportUrlStatusError) {
- SetFakeResponse(/*data=*/std::string(), net::HTTP_NOT_FOUND,
- net::URLRequestStatus::FAILED);
- EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(snippets_fetcher().last_status(),
- Eq("URLRequestStatus error -2"));
- EXPECT_THAT(snippets_fetcher().last_json(), IsEmpty());
- EXPECT_THAT(
- histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
- ElementsAre(base::Bucket(/*min=*/2, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- ElementsAre(base::Bucket(/*min=*/-2, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
- Not(IsEmpty()));
-}
-
-TEST_F(NTPSnippetsFetcherTest, ShouldReportHttpError) {
- SetFakeResponse(/*data=*/std::string(), net::HTTP_NOT_FOUND,
- net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(snippets_fetcher().last_json(), IsEmpty());
- EXPECT_THAT(
- histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
- ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- ElementsAre(base::Bucket(/*min=*/404, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
- Not(IsEmpty()));
-}
-
-TEST_F(NTPSnippetsFetcherTest, ShouldReportJsonError) {
- const std::string kInvalidJsonStr = "{ \"recos\": []";
- SetFakeResponse(/*data=*/kInvalidJsonStr, net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(snippets_fetcher().last_status(),
- StartsWith("Received invalid JSON (error "));
- EXPECT_THAT(snippets_fetcher().last_json(), Eq(kInvalidJsonStr));
- EXPECT_THAT(
- histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
- ElementsAre(base::Bucket(/*min=*/4, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
- ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
- /*count=*/1)));
-}
-
-TEST_F(NTPSnippetsFetcherTest, ShouldReportJsonErrorForEmptyResponse) {
- SetFakeResponse(/*data=*/std::string(), net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(snippets_fetcher().last_json(), std::string());
- EXPECT_THAT(
- histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
- ElementsAre(base::Bucket(/*min=*/4, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
-}
-
-TEST_F(NTPSnippetsFetcherTest, ShouldReportInvalidListError) {
- const std::string kJsonStr =
- "{\"recos\": [{ \"contentInfo\": { \"foo\" : \"bar\" }}]}";
- SetFakeResponse(/*data=*/kJsonStr, net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
- EXPECT_THAT(
- histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
- ElementsAre(base::Bucket(/*min=*/5, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
- Not(IsEmpty()));
-}
-
-// This test actually verifies that the test setup itself is sane, to prevent
-// hard-to-reproduce test failures.
-TEST_F(NTPSnippetsFetcherTest, ShouldReportHttpErrorForMissingBakedResponse) {
- InitFakeURLFetcherFactory();
- EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- FastForwardUntilNoTasksRemain();
-}
-
-TEST_F(NTPSnippetsFetcherTest, ShouldCancelOngoingFetch) {
- const std::string kJsonStr = "{ \"recos\": [] }";
- SetFakeResponse(/*data=*/kJsonStr, net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
- EXPECT_CALL(mock_callback(), Run(/*snippets=*/PointeeSizeIs(0))).Times(1);
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- // Second call to FetchSnippetsFromHosts() overrides/cancels the previous.
- // Callback is expected to be called once.
- snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
- /*count=*/1);
- FastForwardUntilNoTasksRemain();
- EXPECT_THAT(
- histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
- ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
- EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
- ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
- /*count=*/1)));
-}
-
-::std::ostream& operator<<(
- ::std::ostream& os,
- const NTPSnippetsFetcher::OptionalSnippets& snippets) {
- if (snippets) {
- // Matchers above aren't any more precise than this, so this is sufficient
- // for test-failure diagnostics.
- return os << "list with " << snippets->size() << " elements";
- } else {
- return os << "null";
- }
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_scheduler.h b/chromium/components/ntp_snippets/ntp_snippets_scheduler.h
deleted file mode 100644
index d46e03b182e..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_scheduler.h
+++ /dev/null
@@ -1,40 +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 COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SCHEDULER_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SCHEDULER_H_
-
-#include "base/macros.h"
-#include "base/time/time.h"
-
-namespace ntp_snippets {
-
-// Interface to schedule the periodic fetching of snippets.
-class NTPSnippetsScheduler {
- public:
- // Schedule periodic fetching of snippets, with different period depending on
- // network and charging state, and also set up a delay after which the periods
- // may change. The concrete implementation should call
- // NTPSnippetsService::FetchSnippets once per period, and
- // NTPSnippetsService::RescheduleFetching at |reschedule_time|.
- // Any of the values can be zero to indicate that the corresponding task
- // should not be scheduled.
- virtual bool Schedule(base::TimeDelta period_wifi_charging,
- base::TimeDelta period_wifi,
- base::TimeDelta period_fallback,
- base::Time reschedule_time) = 0;
-
- // Cancel any scheduled tasks.
- virtual bool Unschedule() = 0;
-
- protected:
- NTPSnippetsScheduler() = default;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NTPSnippetsScheduler);
-};
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SCHEDULER_H_
diff --git a/chromium/components/ntp_snippets/ntp_snippets_service.cc b/chromium/components/ntp_snippets/ntp_snippets_service.cc
deleted file mode 100644
index 08f4203ee24..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_service.cc
+++ /dev/null
@@ -1,766 +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 "components/ntp_snippets/ntp_snippets_service.h"
-
-#include <algorithm>
-#include <iterator>
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/location.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
-#include "base/path_service.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/task_runner_util.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "components/image_fetcher/image_decoder.h"
-#include "components/image_fetcher/image_fetcher.h"
-#include "components/ntp_snippets/ntp_snippets_constants.h"
-#include "components/ntp_snippets/ntp_snippets_database.h"
-#include "components/ntp_snippets/pref_names.h"
-#include "components/ntp_snippets/switches.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/suggestions/proto/suggestions.pb.h"
-#include "components/variations/variations_associated_data.h"
-#include "ui/gfx/image/image.h"
-
-using image_fetcher::ImageDecoder;
-using image_fetcher::ImageFetcher;
-using suggestions::ChromeSuggestion;
-using suggestions::SuggestionsProfile;
-using suggestions::SuggestionsService;
-
-namespace ntp_snippets {
-
-namespace {
-
-// Number of snippets requested to the server. Consider replacing sparse UMA
-// histograms with COUNTS() if this number increases beyond 50.
-const int kMaxSnippetCount = 10;
-
-// Default values for snippets fetching intervals.
-const int kDefaultFetchingIntervalWifiChargingSeconds = 30 * 60;
-const int kDefaultFetchingIntervalWifiSeconds = 2 * 60 * 60;
-const int kDefaultFetchingIntervalFallbackSeconds = 24 * 60 * 60;
-
-// Variation parameters than can override the default fetching intervals.
-const char kFetchingIntervalWifiChargingParamName[] =
- "fetching_interval_wifi_charging_seconds";
-const char kFetchingIntervalWifiParamName[] =
- "fetching_interval_wifi_seconds";
-const char kFetchingIntervalFallbackParamName[] =
- "fetching_interval_fallback_seconds";
-
-// These define the times of day during which we will fetch via Wifi (without
-// charging) - 6 AM to 10 PM.
-const int kWifiFetchingHourMin = 6;
-const int kWifiFetchingHourMax = 22;
-
-const int kDefaultExpiryTimeMins = 24 * 60;
-
-base::TimeDelta GetFetchingInterval(const char* switch_name,
- const char* param_name,
- int default_value_seconds) {
- int value_seconds = default_value_seconds;
-
- // The default value can be overridden by a variation parameter.
- // TODO(treib,jkrcal): Use GetVariationParamValueByFeature and get rid of
- // kStudyName, also in NTPSnippetsFetcher.
- std::string param_value_str = variations::GetVariationParamValue(
- ntp_snippets::kStudyName, param_name);
- if (!param_value_str.empty()) {
- int param_value_seconds = 0;
- if (base::StringToInt(param_value_str, &param_value_seconds))
- value_seconds = param_value_seconds;
- else
- LOG(WARNING) << "Invalid value for variation parameter " << param_name;
- }
-
- // A value from the command line parameter overrides anything else.
- const base::CommandLine& cmdline = *base::CommandLine::ForCurrentProcess();
- if (cmdline.HasSwitch(switch_name)) {
- std::string str = cmdline.GetSwitchValueASCII(switch_name);
- int switch_value_seconds = 0;
- if (base::StringToInt(str, &switch_value_seconds))
- value_seconds = switch_value_seconds;
- else
- LOG(WARNING) << "Invalid value for switch " << switch_name;
- }
- return base::TimeDelta::FromSeconds(value_seconds);
-}
-
-base::TimeDelta GetFetchingIntervalWifiCharging() {
- return GetFetchingInterval(switches::kFetchingIntervalWifiChargingSeconds,
- kFetchingIntervalWifiChargingParamName,
- kDefaultFetchingIntervalWifiChargingSeconds);
-}
-
-base::TimeDelta GetFetchingIntervalWifi(const base::Time& now) {
- // Only fetch via Wifi (without charging) during the proper times of day.
- base::Time::Exploded exploded;
- now.LocalExplode(&exploded);
- if (kWifiFetchingHourMin <= exploded.hour &&
- exploded.hour < kWifiFetchingHourMax) {
- return GetFetchingInterval(switches::kFetchingIntervalWifiSeconds,
- kFetchingIntervalWifiParamName,
- kDefaultFetchingIntervalWifiSeconds);
- }
- return base::TimeDelta();
-}
-
-base::TimeDelta GetFetchingIntervalFallback() {
- return GetFetchingInterval(switches::kFetchingIntervalFallbackSeconds,
- kFetchingIntervalFallbackParamName,
- kDefaultFetchingIntervalFallbackSeconds);
-}
-
-base::Time GetRescheduleTime(const base::Time& now) {
- base::Time::Exploded exploded;
- now.LocalExplode(&exploded);
- // The scheduling changes at both |kWifiFetchingHourMin| and
- // |kWifiFetchingHourMax|. Find the time of the next one that we'll hit.
- bool next_day = false;
- if (exploded.hour < kWifiFetchingHourMin) {
- exploded.hour = kWifiFetchingHourMin;
- } else if (exploded.hour < kWifiFetchingHourMax) {
- exploded.hour = kWifiFetchingHourMax;
- } else {
- next_day = true;
- exploded.hour = kWifiFetchingHourMin;
- }
- // In any case, reschedule at the full hour.
- exploded.minute = 0;
- exploded.second = 0;
- exploded.millisecond = 0;
- base::Time reschedule = base::Time::FromLocalExploded(exploded);
- if (next_day)
- reschedule += base::TimeDelta::FromDays(1);
-
- return reschedule;
-}
-
-// Extracts the hosts from |suggestions| and returns them in a set.
-std::set<std::string> GetSuggestionsHostsImpl(
- const SuggestionsProfile& suggestions) {
- std::set<std::string> hosts;
- for (int i = 0; i < suggestions.suggestions_size(); ++i) {
- const ChromeSuggestion& suggestion = suggestions.suggestions(i);
- GURL url(suggestion.url());
- if (url.is_valid())
- hosts.insert(url.host());
- }
- return hosts;
-}
-
-void InsertAllIDs(const NTPSnippet::PtrVector& snippets,
- std::set<std::string>* ids) {
- for (const std::unique_ptr<NTPSnippet>& snippet : snippets) {
- ids->insert(snippet->id());
- for (const SnippetSource& source : snippet->sources())
- ids->insert(source.url.spec());
- }
-}
-
-void Compact(NTPSnippet::PtrVector* snippets) {
- snippets->erase(
- std::remove_if(
- snippets->begin(), snippets->end(),
- [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }),
- snippets->end());
-}
-
-} // namespace
-
-NTPSnippetsService::NTPSnippetsService(
- bool enabled,
- PrefService* pref_service,
- SuggestionsService* suggestions_service,
- const std::string& application_language_code,
- NTPSnippetsScheduler* scheduler,
- std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
- std::unique_ptr<ImageFetcher> image_fetcher,
- std::unique_ptr<ImageDecoder> image_decoder,
- std::unique_ptr<NTPSnippetsDatabase> database,
- std::unique_ptr<NTPSnippetsStatusService> status_service)
- : state_(State::NOT_INITED),
- pref_service_(pref_service),
- suggestions_service_(suggestions_service),
- application_language_code_(application_language_code),
- scheduler_(scheduler),
- snippets_fetcher_(std::move(snippets_fetcher)),
- image_fetcher_(std::move(image_fetcher)),
- image_decoder_(std::move(image_decoder)),
- database_(std::move(database)),
- snippets_status_service_(std::move(status_service)),
- fetch_after_load_(false) {
- // TODO(dgn) should be removed after branch point (https://crbug.com/617585).
- ClearDeprecatedPrefs();
-
- if (!enabled || database_->IsErrorState()) {
- // Don't even bother loading the database.
- EnterState(State::SHUT_DOWN);
- return;
- }
-
- database_->SetErrorCallback(base::Bind(&NTPSnippetsService::OnDatabaseError,
- base::Unretained(this)));
-
- // We transition to other states while finalizing the initialization, when the
- // database is done loading.
- database_->LoadSnippets(base::Bind(&NTPSnippetsService::OnDatabaseLoaded,
- base::Unretained(this)));
-}
-
-NTPSnippetsService::~NTPSnippetsService() {
- DCHECK(state_ == State::SHUT_DOWN);
-}
-
-// static
-void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
- registry->RegisterListPref(prefs::kDeprecatedSnippets);
- registry->RegisterListPref(prefs::kDeprecatedDiscardedSnippets);
- registry->RegisterListPref(prefs::kSnippetHosts);
-}
-
-// Inherited from KeyedService.
-void NTPSnippetsService::Shutdown() {
- EnterState(State::SHUT_DOWN);
-}
-
-void NTPSnippetsService::FetchSnippets() {
- if (ready())
- FetchSnippetsFromHosts(GetSuggestionsHosts());
- else
- fetch_after_load_ = true;
-}
-
-void NTPSnippetsService::FetchSnippetsFromHosts(
- const std::set<std::string>& hosts) {
- if (!ready())
- return;
- snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_,
- kMaxSnippetCount);
-}
-
-void NTPSnippetsService::RescheduleFetching() {
- // The scheduler only exists on Android so far, it's null on other platforms.
- if (!scheduler_)
- return;
-
- if (ready()) {
- base::Time now = base::Time::Now();
- scheduler_->Schedule(
- GetFetchingIntervalWifiCharging(), GetFetchingIntervalWifi(now),
- GetFetchingIntervalFallback(), GetRescheduleTime(now));
- } else {
- scheduler_->Unschedule();
- }
-}
-
-void NTPSnippetsService::FetchSnippetImage(
- const std::string& snippet_id,
- const ImageFetchedCallback& callback) {
- database_->LoadImage(
- snippet_id,
- base::Bind(&NTPSnippetsService::OnSnippetImageFetchedFromDatabase,
- base::Unretained(this), snippet_id, callback));
-}
-
-void NTPSnippetsService::ClearSnippets() {
- if (!initialized())
- return;
-
- if (snippets_.empty())
- return;
-
- database_->DeleteSnippets(snippets_);
- snippets_.clear();
-
- FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
- NTPSnippetsServiceLoaded());
-}
-
-std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const {
- // |suggestions_service_| can be null in tests.
- if (!suggestions_service_)
- return std::set<std::string>();
-
- // TODO(treib): This should just call GetSnippetHostsFromPrefs.
- return GetSuggestionsHostsImpl(
- suggestions_service_->GetSuggestionsDataFromCache());
-}
-
-bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) {
- if (!ready())
- return false;
-
- auto it =
- std::find_if(snippets_.begin(), snippets_.end(),
- [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
- return snippet->id() == snippet_id;
- });
- if (it == snippets_.end())
- return false;
-
- (*it)->set_discarded(true);
-
- database_->SaveSnippet(**it);
- database_->DeleteImage((*it)->id());
-
- discarded_snippets_.push_back(std::move(*it));
- snippets_.erase(it);
-
- FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
- NTPSnippetsServiceLoaded());
- return true;
-}
-
-void NTPSnippetsService::ClearDiscardedSnippets() {
- if (!initialized())
- return;
-
- if (discarded_snippets_.empty())
- return;
-
- database_->DeleteSnippets(discarded_snippets_);
- discarded_snippets_.clear();
-}
-
-void NTPSnippetsService::AddObserver(NTPSnippetsServiceObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void NTPSnippetsService::RemoveObserver(NTPSnippetsServiceObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-// static
-int NTPSnippetsService::GetMaxSnippetCountForTesting() {
- return kMaxSnippetCount;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private methods
-
-// image_fetcher::ImageFetcherDelegate implementation.
-void NTPSnippetsService::OnImageDataFetched(const std::string& snippet_id,
- const std::string& image_data) {
- if (image_data.empty())
- return;
-
- // Only save the image if the corresponding snippet still exists.
- auto it =
- std::find_if(snippets_.begin(), snippets_.end(),
- [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
- return snippet->id() == snippet_id;
- });
- if (it == snippets_.end())
- return;
-
- database_->SaveImage(snippet_id, image_data);
-}
-
-void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) {
- DCHECK(state_ == State::NOT_INITED || state_ == State::SHUT_DOWN);
- if (state_ == State::SHUT_DOWN)
- return;
-
- DCHECK(snippets_.empty());
- DCHECK(discarded_snippets_.empty());
- for (std::unique_ptr<NTPSnippet>& snippet : snippets) {
- if (snippet->is_discarded())
- discarded_snippets_.emplace_back(std::move(snippet));
- else
- snippets_.emplace_back(std::move(snippet));
- }
- std::sort(snippets_.begin(), snippets_.end(),
- [](const std::unique_ptr<NTPSnippet>& lhs,
- const std::unique_ptr<NTPSnippet>& rhs) {
- return lhs->score() > rhs->score();
- });
-
- ClearExpiredSnippets();
- FinishInitialization();
-}
-
-void NTPSnippetsService::OnDatabaseError() {
- EnterState(State::SHUT_DOWN);
-}
-
-void NTPSnippetsService::OnSuggestionsChanged(
- const SuggestionsProfile& suggestions) {
- DCHECK(initialized());
-
- std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions);
- if (hosts == GetSnippetHostsFromPrefs())
- return;
-
- // Remove existing snippets that aren't in the suggestions anymore.
- // TODO(treib,maybelle): If there is another source with an allowed host,
- // then we should fall back to that.
- // First, move them over into |to_delete|.
- NTPSnippet::PtrVector to_delete;
- for (std::unique_ptr<NTPSnippet>& snippet : snippets_) {
- if (!hosts.count(snippet->best_source().url.host()))
- to_delete.emplace_back(std::move(snippet));
- }
- Compact(&snippets_);
- // Then delete the removed snippets from the database.
- database_->DeleteSnippets(to_delete);
-
- StoreSnippetHostsToPrefs(hosts);
-
- FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
- NTPSnippetsServiceLoaded());
-
- FetchSnippetsFromHosts(hosts);
-}
-
-void NTPSnippetsService::OnFetchFinished(
- NTPSnippetsFetcher::OptionalSnippets snippets) {
- if (!ready())
- return;
-
- if (snippets) {
- // Sparse histogram used because the number of snippets is small (bound by
- // kMaxSnippetCount).
- DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount));
- UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched",
- snippets->size());
- MergeSnippets(std::move(*snippets));
- }
-
- ClearExpiredSnippets();
-
- // If there are more snippets than we want to show, delete the extra ones.
- if (snippets_.size() > kMaxSnippetCount) {
- NTPSnippet::PtrVector to_delete(
- std::make_move_iterator(snippets_.begin() + kMaxSnippetCount),
- std::make_move_iterator(snippets_.end()));
- snippets_.resize(kMaxSnippetCount);
- database_->DeleteSnippets(to_delete);
- }
-
- UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
- snippets_.size());
- if (snippets_.empty() && !discarded_snippets_.empty()) {
- UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
- discarded_snippets_.size());
- }
-
- FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
- NTPSnippetsServiceLoaded());
-}
-
-void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) {
- DCHECK(ready());
-
- // Remove new snippets that we already have, or that have been discarded.
- std::set<std::string> old_snippet_ids;
- InsertAllIDs(discarded_snippets_, &old_snippet_ids);
- InsertAllIDs(snippets_, &old_snippet_ids);
- new_snippets.erase(
- std::remove_if(
- new_snippets.begin(), new_snippets.end(),
- [&old_snippet_ids](const std::unique_ptr<NTPSnippet>& snippet) {
- if (old_snippet_ids.count(snippet->id()))
- return true;
- for (const SnippetSource& source : snippet->sources()) {
- if (old_snippet_ids.count(source.url.spec()))
- return true;
- }
- return false;
- }),
- new_snippets.end());
-
- // Fill in default publish/expiry dates where required.
- for (std::unique_ptr<NTPSnippet>& snippet : new_snippets) {
- if (snippet->publish_date().is_null())
- snippet->set_publish_date(base::Time::Now());
- if (snippet->expiry_date().is_null()) {
- snippet->set_expiry_date(
- snippet->publish_date() +
- base::TimeDelta::FromMinutes(kDefaultExpiryTimeMins));
- }
-
- // TODO(treib): Prefetch and cache the snippet image. crbug.com/605870
- }
-
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAddIncompleteSnippets)) {
- int num_new_snippets = new_snippets.size();
- // Remove snippets that do not have all the info we need to display it to
- // the user.
- new_snippets.erase(
- std::remove_if(new_snippets.begin(), new_snippets.end(),
- [](const std::unique_ptr<NTPSnippet>& snippet) {
- return !snippet->is_complete();
- }),
- new_snippets.end());
- int num_snippets_discarded = num_new_snippets - new_snippets.size();
- UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch",
- num_snippets_discarded > 0);
- if (num_snippets_discarded > 0) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets",
- num_snippets_discarded);
- }
- }
-
- // Save the new snippets to the DB.
- database_->SaveSnippets(new_snippets);
-
- // Insert the new snippets at the front.
- snippets_.insert(snippets_.begin(),
- std::make_move_iterator(new_snippets.begin()),
- std::make_move_iterator(new_snippets.end()));
-}
-
-std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const {
- std::set<std::string> hosts;
- const base::ListValue* list = pref_service_->GetList(prefs::kSnippetHosts);
- for (const auto& value : *list) {
- std::string str;
- bool success = value->GetAsString(&str);
- DCHECK(success) << "Failed to parse snippet host from prefs";
- hosts.insert(std::move(str));
- }
- return hosts;
-}
-
-void NTPSnippetsService::StoreSnippetHostsToPrefs(
- const std::set<std::string>& hosts) {
- base::ListValue list;
- for (const std::string& host : hosts)
- list.AppendString(host);
- pref_service_->Set(prefs::kSnippetHosts, list);
-}
-
-void NTPSnippetsService::ClearExpiredSnippets() {
- base::Time expiry = base::Time::Now();
-
- // Move expired snippets over into |to_delete|.
- NTPSnippet::PtrVector to_delete;
- for (std::unique_ptr<NTPSnippet>& snippet : snippets_) {
- if (snippet->expiry_date() <= expiry)
- to_delete.emplace_back(std::move(snippet));
- }
- Compact(&snippets_);
-
- // Move expired discarded snippets over into |to_delete| as well.
- for (std::unique_ptr<NTPSnippet>& snippet : discarded_snippets_) {
- if (snippet->expiry_date() <= expiry)
- to_delete.emplace_back(std::move(snippet));
- }
- Compact(&discarded_snippets_);
-
- // Finally, actually delete the removed snippets from the DB.
- database_->DeleteSnippets(to_delete);
-
- // If there are any snippets left, schedule a timer for the next expiry.
- if (snippets_.empty() && discarded_snippets_.empty())
- return;
-
- base::Time next_expiry = base::Time::Max();
- for (const auto& snippet : snippets_) {
- if (snippet->expiry_date() < next_expiry)
- next_expiry = snippet->expiry_date();
- }
- for (const auto& snippet : discarded_snippets_) {
- if (snippet->expiry_date() < next_expiry)
- next_expiry = snippet->expiry_date();
- }
- DCHECK_GT(next_expiry, expiry);
- expiry_timer_.Start(FROM_HERE, next_expiry - expiry,
- base::Bind(&NTPSnippetsService::ClearExpiredSnippets,
- base::Unretained(this)));
-}
-
-void NTPSnippetsService::OnSnippetImageFetchedFromDatabase(
- const std::string& snippet_id,
- const ImageFetchedCallback& callback,
- std::string data) {
- // |image_decoder_| is null in tests.
- if (image_decoder_ && !data.empty()) {
- image_decoder_->DecodeImage(
- std::move(data),
- base::Bind(&NTPSnippetsService::OnSnippetImageDecoded,
- base::Unretained(this), snippet_id, callback));
- return;
- }
-
- // Fetching from the DB failed; start a network fetch.
- FetchSnippetImageFromNetwork(snippet_id, callback);
-}
-
-void NTPSnippetsService::OnSnippetImageDecoded(
- const std::string& snippet_id,
- const ImageFetchedCallback& callback,
- const gfx::Image& image) {
- if (!image.IsEmpty()) {
- callback.Run(snippet_id, image);
- return;
- }
-
- // If decoding the image failed, delete the DB entry.
- database_->DeleteImage(snippet_id);
-
- FetchSnippetImageFromNetwork(snippet_id, callback);
-}
-
-void NTPSnippetsService::FetchSnippetImageFromNetwork(
- const std::string& snippet_id,
- const ImageFetchedCallback& callback) {
- auto it =
- std::find_if(snippets_.begin(), snippets_.end(),
- [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
- return snippet->id() == snippet_id;
- });
- if (it == snippets_.end()) {
- callback.Run(snippet_id, gfx::Image());
- return;
- }
-
- const NTPSnippet& snippet = *it->get();
- image_fetcher_->StartOrQueueNetworkRequest(
- snippet.id(), snippet.salient_image_url(), callback);
-}
-
-void NTPSnippetsService::EnterStateEnabled(bool fetch_snippets) {
- if (fetch_snippets)
- FetchSnippets();
-
- // If host restrictions are enabled, register for host list updates.
- // |suggestions_service_| can be null in tests.
- if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) {
- suggestions_service_subscription_ =
- suggestions_service_->AddCallback(base::Bind(
- &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this)));
- }
-
- RescheduleFetching();
-}
-
-void NTPSnippetsService::EnterStateDisabled() {
- ClearSnippets();
- ClearDiscardedSnippets();
-
- expiry_timer_.Stop();
- suggestions_service_subscription_.reset();
- RescheduleFetching();
-}
-
-void NTPSnippetsService::EnterStateShutdown() {
- FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
- NTPSnippetsServiceShutdown());
-
- expiry_timer_.Stop();
- suggestions_service_subscription_.reset();
- RescheduleFetching();
-
- snippets_status_service_.reset();
-}
-
-void NTPSnippetsService::FinishInitialization() {
- snippets_fetcher_->SetCallback(
- base::Bind(&NTPSnippetsService::OnFetchFinished, base::Unretained(this)));
-
- // |image_fetcher_| can be null in tests.
- if (image_fetcher_)
- image_fetcher_->SetImageFetcherDelegate(this);
-
- // Note: Initializing the status service will run the callback right away with
- // the current state.
- snippets_status_service_->Init(base::Bind(
- &NTPSnippetsService::UpdateStateForStatus, base::Unretained(this)));
-
- FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
- NTPSnippetsServiceLoaded());
-}
-
-void NTPSnippetsService::UpdateStateForStatus(DisabledReason disabled_reason) {
- FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
- NTPSnippetsServiceDisabledReasonChanged(disabled_reason));
-
- State new_state;
- switch (disabled_reason) {
- case DisabledReason::NONE:
- new_state = State::READY;
- break;
-
- case DisabledReason::HISTORY_SYNC_STATE_UNKNOWN:
- // HistorySync is not initialized yet, so we don't know what the actual
- // state is and we just return the current one. If things change,
- // |OnStateChanged| will call this function again to update the state.
- DVLOG(1) << "Sync configuration incomplete, continuing based on the "
- "current state.";
- new_state = state_;
- break;
-
- case DisabledReason::EXPLICITLY_DISABLED:
- case DisabledReason::SIGNED_OUT:
- case DisabledReason::SYNC_DISABLED:
- case DisabledReason::PASSPHRASE_ENCRYPTION_ENABLED:
- case DisabledReason::HISTORY_SYNC_DISABLED:
- new_state = State::DISABLED;
- break;
-
- default:
- // All cases should be handled by the above switch
- NOTREACHED();
- new_state = State::DISABLED;
- break;
- }
-
- EnterState(new_state);
-}
-
-void NTPSnippetsService::EnterState(State state) {
- if (state == state_)
- return;
-
- switch (state) {
- case State::NOT_INITED:
- // Initial state, it should not be possible to get back there.
- NOTREACHED();
- return;
-
- case State::READY: {
- DCHECK(state_ == State::NOT_INITED || state_ == State::DISABLED);
-
- bool fetch_snippets = snippets_.empty() || fetch_after_load_;
- DVLOG(1) << "Entering state: READY";
- state_ = State::READY;
- fetch_after_load_ = false;
- EnterStateEnabled(fetch_snippets);
- return;
- }
-
- case State::DISABLED:
- DCHECK(state_ == State::NOT_INITED || state_ == State::READY);
-
- DVLOG(1) << "Entering state: DISABLED";
- state_ = State::DISABLED;
- EnterStateDisabled();
- return;
-
- case State::SHUT_DOWN:
- DVLOG(1) << "Entering state: SHUT_DOWN";
- state_ = State::SHUT_DOWN;
- EnterStateShutdown();
- return;
- }
-}
-
-void NTPSnippetsService::ClearDeprecatedPrefs() {
- pref_service_->ClearPref(prefs::kDeprecatedSnippets);
- pref_service_->ClearPref(prefs::kDeprecatedDiscardedSnippets);
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_service.h b/chromium/components/ntp_snippets/ntp_snippets_service.h
deleted file mode 100644
index faf064a98bb..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_service.h
+++ /dev/null
@@ -1,326 +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 COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SERVICE_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SERVICE_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "base/timer/timer.h"
-#include "components/image_fetcher/image_fetcher_delegate.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/ntp_snippets/ntp_snippet.h"
-#include "components/ntp_snippets/ntp_snippets_fetcher.h"
-#include "components/ntp_snippets/ntp_snippets_scheduler.h"
-#include "components/ntp_snippets/ntp_snippets_status_service.h"
-#include "components/suggestions/suggestions_service.h"
-#include "components/sync_driver/sync_service_observer.h"
-
-class PrefRegistrySimple;
-class PrefService;
-class SigninManagerBase;
-
-namespace base {
-class RefCountedMemory;
-class Value;
-}
-
-namespace gfx {
-class Image;
-}
-
-namespace image_fetcher {
-class ImageDecoder;
-class ImageFetcher;
-}
-
-namespace suggestions {
-class SuggestionsProfile;
-}
-
-namespace sync_driver {
-class SyncService;
-}
-
-namespace ntp_snippets {
-
-class NTPSnippetsDatabase;
-class NTPSnippetsServiceObserver;
-
-// Stores and vends fresh content data for the NTP.
-class NTPSnippetsService : public KeyedService,
- public image_fetcher::ImageFetcherDelegate {
- public:
- using ImageFetchedCallback =
- base::Callback<void(const std::string& snippet_id, const gfx::Image&)>;
-
- // |application_language_code| should be a ISO 639-1 compliant string, e.g.
- // 'en' or 'en-US'. Note that this code should only specify the language, not
- // the locale, so 'en_US' (English language with US locale) and 'en-GB_US'
- // (British English person in the US) are not language codes.
- NTPSnippetsService(bool enabled,
- PrefService* pref_service,
- suggestions::SuggestionsService* suggestions_service,
- const std::string& application_language_code,
- NTPSnippetsScheduler* scheduler,
- std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
- std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
- std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
- std::unique_ptr<NTPSnippetsDatabase> database,
- std::unique_ptr<NTPSnippetsStatusService> status_service);
-
- ~NTPSnippetsService() override;
-
- static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
- // Inherited from KeyedService.
- void Shutdown() override;
-
- // Returns whether the service is ready. While this is false, the list of
- // snippets will be empty, and all modifications to it (fetch, discard, etc)
- // will be ignored.
- bool ready() const { return state_ == State::READY; }
-
- // Returns whether the service is initialized. While this is false, some
- // calls may trigger DCHECKs.
- bool initialized() const { return ready() || state_ == State::DISABLED; }
-
- // Fetches snippets from the server and adds them to the current ones.
- void FetchSnippets();
- // Fetches snippets from the server for specified hosts (overriding
- // suggestions from the suggestion service) and adds them to the current ones.
- // Only called from chrome://snippets-internals, DO NOT USE otherwise!
- // Ignored while |loaded()| is false.
- void FetchSnippetsFromHosts(const std::set<std::string>& hosts);
-
- // Available snippets.
- const NTPSnippet::PtrVector& snippets() const { return snippets_; }
-
- // Returns the list of snippets previously discarded by the user (that are
- // not expired yet).
- const NTPSnippet::PtrVector& discarded_snippets() const {
- return discarded_snippets_;
- }
-
- const NTPSnippetsFetcher* snippets_fetcher() const {
- return snippets_fetcher_.get();
- }
-
- // Returns a reason why the service is disabled, or DisabledReason::NONE
- // if it's not.
- DisabledReason disabled_reason() const {
- return snippets_status_service_->disabled_reason();
- }
-
- // (Re)schedules the periodic fetching of snippets. This is necessary because
- // the schedule depends on the time of day.
- void RescheduleFetching();
-
- // Fetches the image for the snippet with the given |snippet_id| and runs the
- // |callback|. If that snippet doesn't exist or the fetch fails, the callback
- // gets a null image.
- void FetchSnippetImage(const std::string& snippet_id,
- const ImageFetchedCallback& callback);
-
- // Deletes all currently stored snippets.
- void ClearSnippets();
-
- // Discards the snippet with the given |snippet_id|, if it exists. Returns
- // true iff a snippet was discarded.
- bool DiscardSnippet(const std::string& snippet_id);
-
- // Clears the lists of snippets previously discarded by the user.
- void ClearDiscardedSnippets();
-
- // Returns the lists of suggestion hosts the snippets are restricted to.
- std::set<std::string> GetSuggestionsHosts() const;
-
- // Observer accessors.
- void AddObserver(NTPSnippetsServiceObserver* observer);
- void RemoveObserver(NTPSnippetsServiceObserver* observer);
-
- // Returns the maximum number of snippets that will be shown at once.
- static int GetMaxSnippetCountForTesting();
-
- private:
- FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, HistorySyncStateChanges);
-
- // Possible state transitions:
- // +------- NOT_INITED ------+
- // | / \ |
- // | READY <--> DISABLED <-+
- // | \ /
- // +-----> SHUT_DOWN
- enum class State {
- // The service has just been created. Can change to states:
- // - DISABLED: if the constructor was called with |enabled == false| . In
- // that case the service will stay disabled until it is shut
- // down. It can also enter this state after the database is
- // done loading and GetStateForDependenciesStatus identifies
- // the next state to be DISABLED.
- // - READY: if GetStateForDependenciesStatus returns it, after the database
- // is done loading.
- NOT_INITED,
-
- // The service registered observers, timers, etc. and is ready to answer to
- // queries, fetch snippets... Can change to states:
- // - DISABLED: when the global Chrome state changes, for example after
- // |OnStateChanged| is called and sync is disabled.
- // - SHUT_DOWN: when |Shutdown| is called, during the browser shutdown.
- READY,
-
- // The service is disabled and unregistered the related resources.
- // Can change to states:
- // - READY: when the global Chrome state changes, for example after
- // |OnStateChanged| is called and sync is enabled.
- // - SHUT_DOWN: when |Shutdown| is called, during the browser shutdown.
- DISABLED,
-
- // The service shutdown and can't be used anymore. This state is checked
- // for early exit in callbacks from observers.
- SHUT_DOWN
- };
-
- // image_fetcher::ImageFetcherDelegate implementation.
- void OnImageDataFetched(const std::string& snippet_id,
- const std::string& image_data) override;
-
- // Callbacks for the NTPSnippetsDatabase.
- void OnDatabaseLoaded(NTPSnippet::PtrVector snippets);
- void OnDatabaseError();
-
- // Callback for the SuggestionsService.
- void OnSuggestionsChanged(const suggestions::SuggestionsProfile& suggestions);
-
- // Callback for the NTPSnippetsFetcher.
- void OnFetchFinished(NTPSnippetsFetcher::OptionalSnippets snippets);
-
- // Merges newly available snippets with the previously available list.
- void MergeSnippets(NTPSnippet::PtrVector new_snippets);
-
- std::set<std::string> GetSnippetHostsFromPrefs() const;
- void StoreSnippetHostsToPrefs(const std::set<std::string>& hosts);
-
- // Removes the expired snippets (including discarded) from the service and the
- // database, and schedules another pass for the next expiration.
- void ClearExpiredSnippets();
-
- // Completes the initialization phase of the service, registering the last
- // observers. This is done after construction, once the database is loaded.
- void FinishInitialization();
-
- void LoadingSnippetsFinished();
-
- void OnSnippetImageFetchedFromDatabase(const std::string& snippet_id,
- const ImageFetchedCallback& callback,
- std::string data);
-
- void OnSnippetImageDecoded(const std::string& snippet_id,
- const ImageFetchedCallback& callback,
- const gfx::Image& image);
-
- void FetchSnippetImageFromNetwork(const std::string& snippet_id,
- const ImageFetchedCallback& callback);
-
- // Triggers a state transition depending on the provided reason to be
- // disabled (or lack thereof). This method is called when a change is detected
- // by |snippets_status_service_|
- void UpdateStateForStatus(DisabledReason disabled_reason);
-
- // Verifies state transitions (see |State|'s documentation) and applies them.
- // Does nothing if called with the current state.
- void EnterState(State state);
-
- // Enables the service and triggers a fetch if required. Do not call directly,
- // use |EnterState| instead.
- void EnterStateEnabled(bool fetch_snippets);
-
- // Disables the service. Do not call directly, use |EnterState| instead.
- void EnterStateDisabled();
-
- // Applies the effects of the transition to the SHUT_DOWN state. Do not call
- // directly, use |EnterState| instead.
- void EnterStateShutdown();
-
- void ClearDeprecatedPrefs();
-
- State state_;
-
- PrefService* pref_service_;
-
- suggestions::SuggestionsService* suggestions_service_;
-
- // All current suggestions (i.e. not discarded ones).
- NTPSnippet::PtrVector snippets_;
-
- // Suggestions that the user discarded. We keep these around until they expire
- // so we won't re-add them on the next fetch.
- NTPSnippet::PtrVector discarded_snippets_;
-
- // The ISO 639-1 code of the language used by the application.
- const std::string application_language_code_;
-
- // The observers.
- base::ObserverList<NTPSnippetsServiceObserver> observers_;
-
- // Scheduler for fetching snippets. Not owned.
- NTPSnippetsScheduler* scheduler_;
-
- // The subscription to the SuggestionsService. When the suggestions change,
- // SuggestionsService will call |OnSuggestionsChanged|, which triggers an
- // update to the set of snippets.
- using SuggestionsSubscription =
- suggestions::SuggestionsService::ResponseCallbackList::Subscription;
- std::unique_ptr<SuggestionsSubscription> suggestions_service_subscription_;
-
- // The snippets fetcher.
- std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher_;
-
- // Timer that calls us back when the next snippet expires.
- base::OneShotTimer expiry_timer_;
-
- std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
- std::unique_ptr<image_fetcher::ImageDecoder> image_decoder_;
-
- // The database for persisting snippets.
- std::unique_ptr<NTPSnippetsDatabase> database_;
-
- // The service that provides events and data about the signin and sync state.
- std::unique_ptr<NTPSnippetsStatusService> snippets_status_service_;
-
- // Set to true if FetchSnippets is called before the database has been loaded.
- // The fetch will be executed after the database load finishes.
- bool fetch_after_load_;
-
- DISALLOW_COPY_AND_ASSIGN(NTPSnippetsService);
-};
-
-class NTPSnippetsServiceObserver {
- public:
- // Sent every time the service loads a new set of data.
- virtual void NTPSnippetsServiceLoaded() = 0;
-
- // Sent when the service is shutting down.
- virtual void NTPSnippetsServiceShutdown() = 0;
-
- // Sent when the state of the service is changing. Something changed in its
- // dependencies so it's notifying observers about incoming data changes.
- // If the service might be enabled, DisabledReason::NONE will be provided.
- virtual void NTPSnippetsServiceDisabledReasonChanged(DisabledReason) = 0;
-
- protected:
- virtual ~NTPSnippetsServiceObserver() {}
-};
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SERVICE_H_
diff --git a/chromium/components/ntp_snippets/ntp_snippets_service_unittest.cc b/chromium/components/ntp_snippets/ntp_snippets_service_unittest.cc
deleted file mode 100644
index 22678af60f9..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_service_unittest.cc
+++ /dev/null
@@ -1,876 +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 "components/ntp_snippets/ntp_snippets_service.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/json/json_reader.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/histogram_tester.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/image_fetcher/image_decoder.h"
-#include "components/image_fetcher/image_fetcher.h"
-#include "components/ntp_snippets/ntp_snippet.h"
-#include "components/ntp_snippets/ntp_snippets_database.h"
-#include "components/ntp_snippets/ntp_snippets_fetcher.h"
-#include "components/ntp_snippets/ntp_snippets_scheduler.h"
-#include "components/ntp_snippets/ntp_snippets_test_utils.h"
-#include "components/ntp_snippets/switches.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
-#include "google_apis/google_api_keys.h"
-#include "net/url_request/test_url_fetcher_factory.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::ElementsAre;
-using testing::Eq;
-using testing::Return;
-using testing::IsEmpty;
-using testing::SizeIs;
-using testing::StartsWith;
-using testing::_;
-
-namespace ntp_snippets {
-
-namespace {
-
-MATCHER_P(IdEq, value, "") {
- return arg->id() == value;
-}
-
-const base::Time::Exploded kDefaultCreationTime = {2015, 11, 4, 25, 13, 46, 45};
-const char kTestContentSnippetsServerFormat[] =
- "https://chromereader-pa.googleapis.com/v1/fetch?key=%s";
-
-const char kSnippetUrl[] = "http://localhost/foobar";
-const char kSnippetTitle[] = "Title";
-const char kSnippetText[] = "Snippet";
-const char kSnippetSalientImage[] = "http://localhost/salient_image";
-const char kSnippetPublisherName[] = "Foo News";
-const char kSnippetAmpUrl[] = "http://localhost/amp";
-const float kSnippetScore = 5.0;
-
-base::Time GetDefaultCreationTime() {
- return base::Time::FromUTCExploded(kDefaultCreationTime);
-}
-
-base::Time GetDefaultExpirationTime() {
- return base::Time::Now() + base::TimeDelta::FromHours(1);
-}
-
-std::string GetTestJson(const std::vector<std::string>& snippets) {
- return base::StringPrintf("{\"recos\":[%s]}",
- base::JoinString(snippets, ", ").c_str());
-}
-
-std::string GetSnippetWithUrlAndTimesAndSources(
- const std::string& url,
- const std::string& content_creation_time_str,
- const std::string& expiry_time_str,
- const std::vector<std::string>& source_urls,
- const std::vector<std::string>& publishers,
- const std::vector<std::string>& amp_urls) {
- char json_str_format[] =
- "{ \"contentInfo\": {"
- "\"url\" : \"%s\","
- "\"title\" : \"%s\","
- "\"snippet\" : \"%s\","
- "\"thumbnailUrl\" : \"%s\","
- "\"creationTimestampSec\" : \"%s\","
- "\"expiryTimestampSec\" : \"%s\","
- "\"sourceCorpusInfo\" : [%s]"
- "}, "
- "\"score\" : %f}";
-
- char source_corpus_info_format[] =
- "{\"corpusId\": \"%s\","
- "\"publisherData\": {"
- "\"sourceName\": \"%s\""
- "},"
- "\"ampUrl\": \"%s\"}";
-
- std::string source_corpus_info_list_str;
- for (size_t i = 0; i < source_urls.size(); ++i) {
- std::string source_corpus_info_str =
- base::StringPrintf(source_corpus_info_format,
- source_urls[i].empty() ? "" : source_urls[i].c_str(),
- publishers[i].empty() ? "" : publishers[i].c_str(),
- amp_urls[i].empty() ? "" : amp_urls[i].c_str());
- source_corpus_info_list_str.append(source_corpus_info_str);
- source_corpus_info_list_str.append(",");
- }
- // Remove the last comma
- source_corpus_info_list_str.erase(source_corpus_info_list_str.size()-1, 1);
- return base::StringPrintf(json_str_format, url.c_str(), kSnippetTitle,
- kSnippetText, kSnippetSalientImage,
- content_creation_time_str.c_str(),
- expiry_time_str.c_str(),
- source_corpus_info_list_str.c_str(), kSnippetScore);
-}
-
-std::string GetSnippetWithSources(const std::vector<std::string>& source_urls,
- const std::vector<std::string>& publishers,
- const std::vector<std::string>& amp_urls) {
- return GetSnippetWithUrlAndTimesAndSources(
- kSnippetUrl, NTPSnippet::TimeToJsonString(GetDefaultCreationTime()),
- NTPSnippet::TimeToJsonString(GetDefaultExpirationTime()), source_urls,
- publishers, amp_urls);
-}
-
-std::string GetSnippetWithUrlAndTimes(
- const std::string& url,
- const std::string& content_creation_time_str,
- const std::string& expiry_time_str) {
- return GetSnippetWithUrlAndTimesAndSources(
- url, content_creation_time_str, expiry_time_str,
- {std::string(url)}, {std::string(kSnippetPublisherName)},
- {std::string(kSnippetAmpUrl)});
-}
-
-std::string GetSnippetWithTimes(const std::string& content_creation_time_str,
- const std::string& expiry_time_str) {
- return GetSnippetWithUrlAndTimes(kSnippetUrl, content_creation_time_str,
- expiry_time_str);
-}
-
-std::string GetSnippetWithUrl(const std::string& url) {
- return GetSnippetWithUrlAndTimes(
- url, NTPSnippet::TimeToJsonString(GetDefaultCreationTime()),
- NTPSnippet::TimeToJsonString(GetDefaultExpirationTime()));
-}
-
-std::string GetSnippet() {
- return GetSnippetWithUrlAndTimes(
- kSnippetUrl, NTPSnippet::TimeToJsonString(GetDefaultCreationTime()),
- NTPSnippet::TimeToJsonString(GetDefaultExpirationTime()));
-}
-
-std::string GetExpiredSnippet() {
- return GetSnippetWithTimes(
- NTPSnippet::TimeToJsonString(GetDefaultCreationTime()),
- NTPSnippet::TimeToJsonString(base::Time::Now()));
-}
-
-std::string GetInvalidSnippet() {
- std::string json_str = GetSnippet();
- // Make the json invalid by removing the final closing brace.
- return json_str.substr(0, json_str.size() - 1);
-}
-
-std::string GetIncompleteSnippet() {
- std::string json_str = GetSnippet();
- // Rename the "url" entry. The result is syntactically valid json that will
- // fail to parse as snippets.
- size_t pos = json_str.find("\"url\"");
- if (pos == std::string::npos) {
- NOTREACHED();
- return std::string();
- }
- json_str[pos + 1] = 'x';
- return json_str;
-}
-
-void ParseJson(
- const std::string& json,
- const ntp_snippets::NTPSnippetsFetcher::SuccessCallback& success_callback,
- const ntp_snippets::NTPSnippetsFetcher::ErrorCallback& error_callback) {
- base::JSONReader json_reader;
- std::unique_ptr<base::Value> value = json_reader.ReadToValue(json);
- if (value) {
- success_callback.Run(std::move(value));
- } else {
- error_callback.Run(json_reader.GetErrorMessage());
- }
-}
-
-// Factory for FakeURLFetcher objects that always generate errors.
-class FailingFakeURLFetcherFactory : public net::URLFetcherFactory {
- public:
- std::unique_ptr<net::URLFetcher> CreateURLFetcher(
- int id, const GURL& url, net::URLFetcher::RequestType request_type,
- net::URLFetcherDelegate* d) override {
- return base::MakeUnique<net::FakeURLFetcher>(
- url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND,
- net::URLRequestStatus::FAILED);
- }
-};
-
-class MockScheduler : public NTPSnippetsScheduler {
- public:
- MOCK_METHOD4(Schedule,
- bool(base::TimeDelta period_wifi_charging,
- base::TimeDelta period_wifi,
- base::TimeDelta period_fallback,
- base::Time reschedule_time));
- MOCK_METHOD0(Unschedule, bool());
-};
-
-class MockServiceObserver : public NTPSnippetsServiceObserver {
- public:
- MOCK_METHOD0(NTPSnippetsServiceLoaded, void());
- MOCK_METHOD0(NTPSnippetsServiceShutdown, void());
- MOCK_METHOD1(NTPSnippetsServiceDisabledReasonChanged,
- void(DisabledReason disabled_reason));
-};
-
-class WaitForDBLoad : public NTPSnippetsServiceObserver {
- public:
- WaitForDBLoad(NTPSnippetsService* service) : service_(service) {
- service_->AddObserver(this);
- if (!service_->ready())
- run_loop_.Run();
- }
-
- ~WaitForDBLoad() override {
- service_->RemoveObserver(this);
- }
-
- private:
- void NTPSnippetsServiceLoaded() override {
- EXPECT_TRUE(service_->ready());
- run_loop_.Quit();
- }
-
- void NTPSnippetsServiceShutdown() override {}
- void NTPSnippetsServiceDisabledReasonChanged(
- DisabledReason disabled_reason) override {}
-
- NTPSnippetsService* service_;
- base::RunLoop run_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(WaitForDBLoad);
-};
-
-} // namespace
-
-class NTPSnippetsServiceTest : public test::NTPSnippetsTestBase {
- public:
- NTPSnippetsServiceTest()
- : fake_url_fetcher_factory_(
- /*default_factory=*/&failing_url_fetcher_factory_),
- test_url_(base::StringPrintf(kTestContentSnippetsServerFormat,
- google_apis::GetAPIKey().c_str())) {
- NTPSnippetsService::RegisterProfilePrefs(pref_service()->registry());
-
- // Since no SuggestionsService is injected in tests, we need to force the
- // service to fetch from all hosts.
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kDontRestrict);
- EXPECT_TRUE(database_dir_.CreateUniqueTempDir());
- }
-
- ~NTPSnippetsServiceTest() override {
- if (service_)
- service_->Shutdown();
-
- // We need to run the message loop after deleting the database, because
- // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task
- // runner. Without this, we'd get reports of memory leaks.
- service_.reset();
- base::RunLoop().RunUntilIdle();
- }
-
- void SetUp() override {
- test::NTPSnippetsTestBase::SetUp();
- EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1);
- CreateSnippetsService(/*enabled=*/true);
- }
-
- void CreateSnippetsService(bool enabled) {
- if (service_)
- service_->Shutdown();
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner(
- base::ThreadTaskRunnerHandle::Get());
- scoped_refptr<net::TestURLRequestContextGetter> request_context_getter =
- new net::TestURLRequestContextGetter(task_runner.get());
-
- // Delete the current service, so that the database is destroyed before we
- // create the new one, otherwise opening the new database will fail.
- service_.reset();
-
- ResetSigninManager();
- std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher =
- base::MakeUnique<NTPSnippetsFetcher>(
- fake_signin_manager(), fake_token_service_.get(),
- std::move(request_context_getter), base::Bind(&ParseJson),
- /*is_stable_channel=*/true);
-
- fake_signin_manager()->SignIn("foo@bar.com");
- snippets_fetcher->SetPersonalizationForTesting(
- NTPSnippetsFetcher::Personalization::kNonPersonal);
-
- service_.reset(new NTPSnippetsService(
- enabled, pref_service(), nullptr, "fr", &scheduler_,
- std::move(snippets_fetcher), /*image_fetcher=*/nullptr,
- /*image_fetcher=*/nullptr, base::MakeUnique<NTPSnippetsDatabase>(
- database_dir_.path(), task_runner),
- base::MakeUnique<NTPSnippetsStatusService>(fake_signin_manager(),
- mock_sync_service())));
-
- if (enabled)
- WaitForDBLoad(service_.get());
- }
-
- protected:
- const GURL& test_url() { return test_url_; }
- NTPSnippetsService* service() { return service_.get(); }
- MockScheduler& mock_scheduler() { return scheduler_; }
-
- // Provide the json to be returned by the fake fetcher.
- void SetUpFetchResponse(const std::string& json) {
- fake_url_fetcher_factory_.SetFakeResponse(test_url_, json, net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
- }
-
- void LoadFromJSONString(const std::string& json) {
- SetUpFetchResponse(json);
- service()->FetchSnippets();
- base::RunLoop().RunUntilIdle();
- }
-
- private:
- base::MessageLoop message_loop_;
- FailingFakeURLFetcherFactory failing_url_fetcher_factory_;
- // Instantiation of factory automatically sets itself as URLFetcher's factory.
- net::FakeURLFetcherFactory fake_url_fetcher_factory_;
- const GURL test_url_;
- std::unique_ptr<OAuth2TokenService> fake_token_service_;
- MockScheduler scheduler_;
- // Last so that the dependencies are deleted after the service.
- std::unique_ptr<NTPSnippetsService> service_;
-
- base::ScopedTempDir database_dir_;
-
- DISALLOW_COPY_AND_ASSIGN(NTPSnippetsServiceTest);
-};
-
-class NTPSnippetsServiceDisabledTest : public NTPSnippetsServiceTest {
- public:
- void SetUp() override {
- test::NTPSnippetsTestBase::SetUp();
- EXPECT_CALL(mock_scheduler(), Unschedule()).Times(1);
- CreateSnippetsService(/*enabled=*/false);
- }
-};
-
-TEST_F(NTPSnippetsServiceTest, ScheduleIfEnabled) {
- // SetUp() checks that Schedule is called.
-}
-
-TEST_F(NTPSnippetsServiceDisabledTest, Unschedule) {
- // SetUp() checks that Unschedule is called.
-}
-
-TEST_F(NTPSnippetsServiceTest, Full) {
- std::string json_str(GetTestJson({GetSnippet()}));
-
- LoadFromJSONString(json_str);
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- const NTPSnippet& snippet = *service()->snippets().front();
-
- EXPECT_EQ(snippet.id(), kSnippetUrl);
- EXPECT_EQ(snippet.title(), kSnippetTitle);
- EXPECT_EQ(snippet.snippet(), kSnippetText);
- EXPECT_EQ(snippet.salient_image_url(), GURL(kSnippetSalientImage));
- EXPECT_EQ(GetDefaultCreationTime(), snippet.publish_date());
- EXPECT_EQ(snippet.best_source().publisher_name, kSnippetPublisherName);
- EXPECT_EQ(snippet.best_source().amp_url, GURL(kSnippetAmpUrl));
-}
-
-TEST_F(NTPSnippetsServiceTest, Clear) {
- std::string json_str(GetTestJson({GetSnippet()}));
-
- LoadFromJSONString(json_str);
- EXPECT_THAT(service()->snippets(), SizeIs(1));
-
- service()->ClearSnippets();
- EXPECT_THAT(service()->snippets(), IsEmpty());
-}
-
-TEST_F(NTPSnippetsServiceTest, InsertAtFront) {
- std::string first("http://first");
- LoadFromJSONString(GetTestJson({GetSnippetWithUrl(first)}));
- EXPECT_THAT(service()->snippets(), ElementsAre(IdEq(first)));
-
- std::string second("http://second");
- LoadFromJSONString(GetTestJson({GetSnippetWithUrl(second)}));
- // The snippet loaded last should be at the first position in the list now.
- EXPECT_THAT(service()->snippets(), ElementsAre(IdEq(second), IdEq(first)));
-}
-
-TEST_F(NTPSnippetsServiceTest, LimitNumSnippets) {
- int max_snippet_count = NTPSnippetsService::GetMaxSnippetCountForTesting();
- int snippets_per_load = max_snippet_count / 2 + 1;
- char url_format[] = "http://localhost/%i";
-
- std::vector<std::string> snippets1;
- std::vector<std::string> snippets2;
- for (int i = 0; i < snippets_per_load; i++) {
- snippets1.push_back(GetSnippetWithUrl(base::StringPrintf(url_format, i)));
- snippets2.push_back(GetSnippetWithUrl(
- base::StringPrintf(url_format, snippets_per_load + i)));
- }
-
- LoadFromJSONString(GetTestJson(snippets1));
- ASSERT_THAT(service()->snippets(), SizeIs(snippets1.size()));
-
- LoadFromJSONString(GetTestJson(snippets2));
- EXPECT_THAT(service()->snippets(), SizeIs(max_snippet_count));
-}
-
-TEST_F(NTPSnippetsServiceTest, LoadInvalidJson) {
- LoadFromJSONString(GetTestJson({GetInvalidSnippet()}));
- EXPECT_THAT(service()->snippets_fetcher()->last_status(),
- StartsWith("Received invalid JSON"));
- EXPECT_THAT(service()->snippets(), IsEmpty());
-}
-
-TEST_F(NTPSnippetsServiceTest, LoadInvalidJsonWithExistingSnippets) {
- LoadFromJSONString(GetTestJson({GetSnippet()}));
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- ASSERT_EQ("OK", service()->snippets_fetcher()->last_status());
-
- LoadFromJSONString(GetTestJson({GetInvalidSnippet()}));
- EXPECT_THAT(service()->snippets_fetcher()->last_status(),
- StartsWith("Received invalid JSON"));
- // This should not have changed the existing snippets.
- EXPECT_THAT(service()->snippets(), SizeIs(1));
-}
-
-TEST_F(NTPSnippetsServiceTest, LoadIncompleteJson) {
- LoadFromJSONString(GetTestJson({GetIncompleteSnippet()}));
- EXPECT_EQ("Invalid / empty list.",
- service()->snippets_fetcher()->last_status());
- EXPECT_THAT(service()->snippets(), IsEmpty());
-}
-
-TEST_F(NTPSnippetsServiceTest, LoadIncompleteJsonWithExistingSnippets) {
- LoadFromJSONString(GetTestJson({GetSnippet()}));
- ASSERT_THAT(service()->snippets(), SizeIs(1));
-
- LoadFromJSONString(GetTestJson({GetIncompleteSnippet()}));
- EXPECT_EQ("Invalid / empty list.",
- service()->snippets_fetcher()->last_status());
- // This should not have changed the existing snippets.
- EXPECT_THAT(service()->snippets(), SizeIs(1));
-}
-
-TEST_F(NTPSnippetsServiceTest, Discard) {
- std::vector<std::string> source_urls, publishers, amp_urls;
- source_urls.push_back(std::string("http://site.com"));
- publishers.push_back(std::string("Source 1"));
- amp_urls.push_back(std::string());
- std::string json_str(
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
-
- LoadFromJSONString(json_str);
-
- ASSERT_THAT(service()->snippets(), SizeIs(1));
-
- // Discarding a non-existent snippet shouldn't do anything.
- EXPECT_FALSE(service()->DiscardSnippet("http://othersite.com"));
- EXPECT_THAT(service()->snippets(), SizeIs(1));
-
- // Discard the snippet.
- EXPECT_TRUE(service()->DiscardSnippet(kSnippetUrl));
- EXPECT_THAT(service()->snippets(), IsEmpty());
-
- // Make sure that fetching the same snippet again does not re-add it.
- LoadFromJSONString(json_str);
- EXPECT_THAT(service()->snippets(), IsEmpty());
-
- // The snippet should stay discarded even after re-creating the service.
- EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1);
- CreateSnippetsService(/*enabled=*/true);
- LoadFromJSONString(json_str);
- EXPECT_THAT(service()->snippets(), IsEmpty());
-
- // The snippet can be added again after clearing discarded snippets.
- service()->ClearDiscardedSnippets();
- EXPECT_THAT(service()->snippets(), IsEmpty());
- LoadFromJSONString(json_str);
- EXPECT_THAT(service()->snippets(), SizeIs(1));
-}
-
-TEST_F(NTPSnippetsServiceTest, GetDiscarded) {
- LoadFromJSONString(GetTestJson({GetSnippet()}));
-
- // For the test, we need the snippet to get discarded.
- ASSERT_TRUE(service()->DiscardSnippet(kSnippetUrl));
- const NTPSnippet::PtrVector& snippets = service()->discarded_snippets();
- EXPECT_EQ(1u, snippets.size());
- for (auto& snippet : snippets) {
- EXPECT_EQ(kSnippetUrl, snippet->id());
- }
-
- // There should be no discarded snippet after clearing the list.
- service()->ClearDiscardedSnippets();
- EXPECT_EQ(0u, service()->discarded_snippets().size());
-}
-
-TEST_F(NTPSnippetsServiceTest, CreationTimestampParseFail) {
- std::string json_str(GetTestJson({GetSnippetWithTimes(
- "aaa1448459205",
- NTPSnippet::TimeToJsonString(GetDefaultExpirationTime()))}));
-
- LoadFromJSONString(json_str);
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- const NTPSnippet& snippet = *service()->snippets().front();
- EXPECT_EQ(snippet.id(), kSnippetUrl);
- EXPECT_EQ(snippet.title(), kSnippetTitle);
- EXPECT_EQ(snippet.snippet(), kSnippetText);
- EXPECT_EQ(base::Time::UnixEpoch(), snippet.publish_date());
-}
-
-TEST_F(NTPSnippetsServiceTest, RemoveExpiredContent) {
- std::string json_str(GetTestJson({GetExpiredSnippet()}));
-
- LoadFromJSONString(json_str);
- EXPECT_THAT(service()->snippets(), IsEmpty());
-}
-
-TEST_F(NTPSnippetsServiceTest, TestSingleSource) {
- std::vector<std::string> source_urls, publishers, amp_urls;
- source_urls.push_back(std::string("http://source1.com"));
- publishers.push_back(std::string("Source 1"));
- amp_urls.push_back(std::string("http://source1.amp.com"));
- std::string json_str(
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
-
- LoadFromJSONString(json_str);
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- const NTPSnippet& snippet = *service()->snippets().front();
- EXPECT_EQ(snippet.sources().size(), 1u);
- EXPECT_EQ(snippet.id(), kSnippetUrl);
- EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com"));
- EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1"));
- EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com"));
-}
-
-TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMalformedUrl) {
- std::vector<std::string> source_urls, publishers, amp_urls;
- source_urls.push_back(std::string("aaaa"));
- publishers.push_back(std::string("Source 1"));
- amp_urls.push_back(std::string("http://source1.amp.com"));
- std::string json_str(
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
-
- LoadFromJSONString(json_str);
- EXPECT_THAT(service()->snippets(), IsEmpty());
-}
-
-TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMissingData) {
- std::vector<std::string> source_urls, publishers, amp_urls;
- source_urls.push_back(std::string("http://source1.com"));
- publishers.push_back(std::string());
- amp_urls.push_back(std::string());
- std::string json_str(
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
-
- LoadFromJSONString(json_str);
- EXPECT_THAT(service()->snippets(), IsEmpty());
-}
-
-TEST_F(NTPSnippetsServiceTest, TestMultipleSources) {
- std::vector<std::string> source_urls, publishers, amp_urls;
- source_urls.push_back(std::string("http://source1.com"));
- source_urls.push_back(std::string("http://source2.com"));
- publishers.push_back(std::string("Source 1"));
- publishers.push_back(std::string("Source 2"));
- amp_urls.push_back(std::string("http://source1.amp.com"));
- amp_urls.push_back(std::string("http://source2.amp.com"));
- std::string json_str(
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
-
- LoadFromJSONString(json_str);
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- const NTPSnippet& snippet = *service()->snippets().front();
- // Expect the first source to be chosen
- EXPECT_EQ(snippet.sources().size(), 2u);
- EXPECT_EQ(snippet.id(), kSnippetUrl);
- EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com"));
- EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1"));
- EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com"));
-}
-
-TEST_F(NTPSnippetsServiceTest, TestMultipleIncompleteSources) {
- // Set Source 2 to have no AMP url, and Source 1 to have no publisher name
- // Source 2 should win since we favor publisher name over amp url
- std::vector<std::string> source_urls, publishers, amp_urls;
- source_urls.push_back(std::string("http://source1.com"));
- source_urls.push_back(std::string("http://source2.com"));
- publishers.push_back(std::string());
- publishers.push_back(std::string("Source 2"));
- amp_urls.push_back(std::string("http://source1.amp.com"));
- amp_urls.push_back(std::string());
- std::string json_str(
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
-
- LoadFromJSONString(json_str);
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- {
- const NTPSnippet& snippet = *service()->snippets().front();
- EXPECT_EQ(snippet.sources().size(), 2u);
- EXPECT_EQ(snippet.id(), kSnippetUrl);
- EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com"));
- EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2"));
- EXPECT_EQ(snippet.best_source().amp_url, GURL());
- }
-
- service()->ClearSnippets();
- // Set Source 1 to have no AMP url, and Source 2 to have no publisher name
- // Source 1 should win in this case since we prefer publisher name to AMP url
- source_urls.clear();
- source_urls.push_back(std::string("http://source1.com"));
- source_urls.push_back(std::string("http://source2.com"));
- publishers.clear();
- publishers.push_back(std::string("Source 1"));
- publishers.push_back(std::string());
- amp_urls.clear();
- amp_urls.push_back(std::string());
- amp_urls.push_back(std::string("http://source2.amp.com"));
- json_str =
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)});
-
- LoadFromJSONString(json_str);
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- {
- const NTPSnippet& snippet = *service()->snippets().front();
- EXPECT_EQ(snippet.sources().size(), 2u);
- EXPECT_EQ(snippet.id(), kSnippetUrl);
- EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com"));
- EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1"));
- EXPECT_EQ(snippet.best_source().amp_url, GURL());
- }
-
- service()->ClearSnippets();
- // Set source 1 to have no AMP url and no source, and source 2 to only have
- // amp url. There should be no snippets since we only add sources we consider
- // complete
- source_urls.clear();
- source_urls.push_back(std::string("http://source1.com"));
- source_urls.push_back(std::string("http://source2.com"));
- publishers.clear();
- publishers.push_back(std::string());
- publishers.push_back(std::string());
- amp_urls.clear();
- amp_urls.push_back(std::string());
- amp_urls.push_back(std::string("http://source2.amp.com"));
- json_str =
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)});
-
- LoadFromJSONString(json_str);
- EXPECT_THAT(service()->snippets(), IsEmpty());
-}
-
-TEST_F(NTPSnippetsServiceTest, TestMultipleCompleteSources) {
- // Test 2 complete sources, we should choose the first complete source
- std::vector<std::string> source_urls, publishers, amp_urls;
- source_urls.push_back(std::string("http://source1.com"));
- source_urls.push_back(std::string("http://source2.com"));
- source_urls.push_back(std::string("http://source3.com"));
- publishers.push_back(std::string("Source 1"));
- publishers.push_back(std::string());
- publishers.push_back(std::string("Source 3"));
- amp_urls.push_back(std::string("http://source1.amp.com"));
- amp_urls.push_back(std::string("http://source2.amp.com"));
- amp_urls.push_back(std::string("http://source3.amp.com"));
- std::string json_str(
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
-
- LoadFromJSONString(json_str);
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- {
- const NTPSnippet& snippet = *service()->snippets().front();
- EXPECT_EQ(snippet.sources().size(), 3u);
- EXPECT_EQ(snippet.id(), kSnippetUrl);
- EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com"));
- EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1"));
- EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com"));
- }
-
- // Test 2 complete sources, we should choose the first complete source
- service()->ClearSnippets();
- source_urls.clear();
- source_urls.push_back(std::string("http://source1.com"));
- source_urls.push_back(std::string("http://source2.com"));
- source_urls.push_back(std::string("http://source3.com"));
- publishers.clear();
- publishers.push_back(std::string());
- publishers.push_back(std::string("Source 2"));
- publishers.push_back(std::string("Source 3"));
- amp_urls.clear();
- amp_urls.push_back(std::string("http://source1.amp.com"));
- amp_urls.push_back(std::string("http://source2.amp.com"));
- amp_urls.push_back(std::string("http://source3.amp.com"));
- json_str =
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)});
-
- LoadFromJSONString(json_str);
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- {
- const NTPSnippet& snippet = *service()->snippets().front();
- EXPECT_EQ(snippet.sources().size(), 3u);
- EXPECT_EQ(snippet.id(), kSnippetUrl);
- EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com"));
- EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2"));
- EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source2.amp.com"));
- }
-
- // Test 3 complete sources, we should choose the first complete source
- service()->ClearSnippets();
- source_urls.clear();
- source_urls.push_back(std::string("http://source1.com"));
- source_urls.push_back(std::string("http://source2.com"));
- source_urls.push_back(std::string("http://source3.com"));
- publishers.clear();
- publishers.push_back(std::string("Source 1"));
- publishers.push_back(std::string("Source 2"));
- publishers.push_back(std::string("Source 3"));
- amp_urls.clear();
- amp_urls.push_back(std::string());
- amp_urls.push_back(std::string("http://source2.amp.com"));
- amp_urls.push_back(std::string("http://source3.amp.com"));
- json_str =
- GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)});
-
- LoadFromJSONString(json_str);
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- {
- const NTPSnippet& snippet = *service()->snippets().front();
- EXPECT_EQ(snippet.sources().size(), 3u);
- EXPECT_EQ(snippet.id(), kSnippetUrl);
- EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com"));
- EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2"));
- EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source2.amp.com"));
- }
-}
-
-TEST_F(NTPSnippetsServiceTest, LogNumArticlesHistogram) {
- base::HistogramTester tester;
- LoadFromJSONString(GetTestJson({GetInvalidSnippet()}));
-
- EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
- // Invalid JSON shouldn't contribute to NumArticlesFetched.
- EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
- IsEmpty());
- // Valid JSON with empty list.
- LoadFromJSONString(GetTestJson(std::vector<std::string>()));
- EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/2)));
- EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
- // Snippet list should be populated with size 1.
- LoadFromJSONString(GetTestJson({GetSnippet()}));
- EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/2),
- base::Bucket(/*min=*/1, /*count=*/1)));
- EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
- base::Bucket(/*min=*/1, /*count=*/1)));
- // Duplicate snippet shouldn't increase the list size.
- LoadFromJSONString(GetTestJson({GetSnippet()}));
- EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/2),
- base::Bucket(/*min=*/1, /*count=*/2)));
- EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
- base::Bucket(/*min=*/1, /*count=*/2)));
- EXPECT_THAT(
- tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"),
- IsEmpty());
- // Discarding a snippet should decrease the list size. This will only be
- // logged after the next fetch.
- EXPECT_TRUE(service()->DiscardSnippet(kSnippetUrl));
- LoadFromJSONString(GetTestJson({GetSnippet()}));
- EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/3),
- base::Bucket(/*min=*/1, /*count=*/2)));
- // Discarded snippets shouldn't influence NumArticlesFetched.
- EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
- base::Bucket(/*min=*/1, /*count=*/3)));
- EXPECT_THAT(
- tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"),
- ElementsAre(base::Bucket(/*min=*/1, /*count=*/1)));
- // Recreating the service and loading from prefs shouldn't count as fetched
- // articles.
- EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1);
- CreateSnippetsService(/*enabled=*/true);
- tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 4);
-}
-
-TEST_F(NTPSnippetsServiceTest, DiscardShouldRespectAllKnownUrls) {
- const std::string creation =
- NTPSnippet::TimeToJsonString(GetDefaultCreationTime());
- const std::string expiry =
- NTPSnippet::TimeToJsonString(GetDefaultExpirationTime());
- const std::vector<std::string> source_urls = {
- "http://mashable.com/2016/05/11/stolen",
- "http://www.aol.com/article/2016/05/stolen-doggie",
- "http://mashable.com/2016/05/11/stolen?utm_cid=1"};
- const std::vector<std::string> publishers = {"Mashable", "AOL", "Mashable"};
- const std::vector<std::string> amp_urls = {
- "http://mashable-amphtml.googleusercontent.com/1",
- "http://t2.gstatic.com/images?q=tbn:3",
- "http://t2.gstatic.com/images?q=tbn:3"};
-
- // Add the snippet from the mashable domain.
- LoadFromJSONString(GetTestJson({GetSnippetWithUrlAndTimesAndSources(
- source_urls[0], creation, expiry, source_urls, publishers, amp_urls)}));
- ASSERT_THAT(service()->snippets(), SizeIs(1));
- // Discard the snippet via the mashable source corpus ID.
- EXPECT_TRUE(service()->DiscardSnippet(source_urls[0]));
- EXPECT_THAT(service()->snippets(), IsEmpty());
-
- // The same article from the AOL domain should now be detected as discarded.
- LoadFromJSONString(GetTestJson({GetSnippetWithUrlAndTimesAndSources(
- source_urls[1], creation, expiry, source_urls, publishers, amp_urls)}));
- ASSERT_THAT(service()->snippets(), IsEmpty());
-}
-
-TEST_F(NTPSnippetsServiceTest, HistorySyncStateChanges) {
- MockServiceObserver mock_observer;
- service()->AddObserver(&mock_observer);
-
- // Simulate user signed out
- SetUpFetchResponse(GetTestJson({GetSnippet()}));
- EXPECT_CALL(mock_observer, NTPSnippetsServiceDisabledReasonChanged(
- DisabledReason::SIGNED_OUT));
- service()->UpdateStateForStatus(DisabledReason::SIGNED_OUT);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(NTPSnippetsService::State::DISABLED, service()->state_);
- EXPECT_THAT(service()->snippets(), IsEmpty()); // No fetch should be made.
-
- // Simulate user sign in. The service should be ready again and load snippets.
- SetUpFetchResponse(GetTestJson({GetSnippet()}));
- EXPECT_CALL(mock_observer,
- NTPSnippetsServiceDisabledReasonChanged(DisabledReason::NONE));
- EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1);
- service()->UpdateStateForStatus(DisabledReason::NONE);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(NTPSnippetsService::State::READY, service()->state_);
- EXPECT_FALSE(service()->snippets().empty());
-
- service()->RemoveObserver(&mock_observer);
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_status_service.cc b/chromium/components/ntp_snippets/ntp_snippets_status_service.cc
deleted file mode 100644
index 5c279991b1e..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_status_service.cc
+++ /dev/null
@@ -1,80 +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 "components/ntp_snippets/ntp_snippets_status_service.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "components/sync_driver/sync_service.h"
-
-namespace ntp_snippets {
-
-NTPSnippetsStatusService::NTPSnippetsStatusService(
- SigninManagerBase* signin_manager,
- sync_driver::SyncService* sync_service)
- : disabled_reason_(DisabledReason::EXPLICITLY_DISABLED),
- signin_manager_(signin_manager),
- sync_service_(sync_service),
- sync_service_observer_(this) {}
-
-NTPSnippetsStatusService::~NTPSnippetsStatusService() {}
-
-void NTPSnippetsStatusService::Init(
- const DisabledReasonChangeCallback& callback) {
- DCHECK(disabled_reason_change_callback_.is_null());
-
- disabled_reason_change_callback_ = callback;
-
- // Notify about the current state before registering the observer, to make
- // sure we don't get a double notification due to an undefined start state.
- disabled_reason_ = GetDisabledReasonFromDeps();
- disabled_reason_change_callback_.Run(disabled_reason_);
-
- sync_service_observer_.Add(sync_service_);
-}
-
-void NTPSnippetsStatusService::OnStateChanged() {
- DisabledReason new_disabled_reason = GetDisabledReasonFromDeps();
-
- if (new_disabled_reason == disabled_reason_)
- return;
-
- disabled_reason_ = new_disabled_reason;
- disabled_reason_change_callback_.Run(disabled_reason_);
-}
-
-DisabledReason NTPSnippetsStatusService::GetDisabledReasonFromDeps() const {
- if (!signin_manager_ || !signin_manager_->IsAuthenticated()) {
- DVLOG(1) << "[GetNewDisabledReason] Signed out";
- return DisabledReason::SIGNED_OUT;
- }
-
- if (!sync_service_ || !sync_service_->CanSyncStart()) {
- DVLOG(1) << "[GetNewDisabledReason] Sync disabled";
- return DisabledReason::SYNC_DISABLED;
- }
-
- // !IsSyncActive in cases where CanSyncStart is true hints at the backend not
- // being initialized.
- // ConfigurationDone() verifies that the sync service has properly loaded its
- // configuration and is aware of the different data types to sync.
- if (!sync_service_->IsSyncActive() || !sync_service_->ConfigurationDone()) {
- DVLOG(1) << "[GetNewDisabledReason] Sync initialization is not complete.";
- return DisabledReason::HISTORY_SYNC_STATE_UNKNOWN;
- }
-
- if (sync_service_->IsEncryptEverythingEnabled()) {
- DVLOG(1) << "[GetNewDisabledReason] Encryption is enabled";
- return DisabledReason::PASSPHRASE_ENCRYPTION_ENABLED;
- }
-
- if (!sync_service_->GetActiveDataTypes().Has(
- syncer::HISTORY_DELETE_DIRECTIVES)) {
- DVLOG(1) << "[GetNewDisabledReason] History sync disabled";
- return DisabledReason::HISTORY_SYNC_DISABLED;
- }
-
- DVLOG(1) << "[GetNewDisabledReason] Enabled";
- return DisabledReason::NONE;
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_status_service.h b/chromium/components/ntp_snippets/ntp_snippets_status_service.h
deleted file mode 100644
index b5a73eea1c1..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_status_service.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_STATUS_SERVICE_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_STATUS_SERVICE_H_
-
-#include "base/callback.h"
-#include "base/gtest_prod_util.h"
-#include "base/scoped_observer.h"
-#include "components/sync_driver/sync_service_observer.h"
-
-class SigninManagerBase;
-
-namespace sync_driver {
-class SyncService;
-}
-
-namespace ntp_snippets {
-
-// On Android builds, a Java counterpart will be generated for this enum.
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp.snippets
-enum class DisabledReason : int {
- // Snippets are enabled
- NONE,
- // Snippets have been disabled as part of the service configuration.
- EXPLICITLY_DISABLED,
- // The user is not signed in, and the service requires it to be enabled.
- SIGNED_OUT,
- // Sync is not enabled, and the service requires it to be enabled.
- SYNC_DISABLED,
- // The service requires passphrase encryption to be disabled.
- PASSPHRASE_ENCRYPTION_ENABLED,
- // History sync is not enabled, and the service requires it to be enabled.
- HISTORY_SYNC_DISABLED,
- // The sync service is not completely initialized, and the status is unknown.
- HISTORY_SYNC_STATE_UNKNOWN
-};
-
-// Aggregates data from sync and signin to notify the snippet service of
-// relevant changes in their states.
-class NTPSnippetsStatusService : public sync_driver::SyncServiceObserver {
- public:
- typedef base::Callback<void(DisabledReason)> DisabledReasonChangeCallback;
-
- NTPSnippetsStatusService(SigninManagerBase* signin_manager,
- sync_driver::SyncService* sync_service);
-
- ~NTPSnippetsStatusService() override;
-
- // Starts listening for changes from the dependencies. |callback| will be
- // called when a significant change in state is detected.
- void Init(const DisabledReasonChangeCallback& callback);
-
- DisabledReason disabled_reason() const { return disabled_reason_; }
-
- private:
- FRIEND_TEST_ALL_PREFIXES(NTPSnippetsStatusServiceTest,
- SyncStateCompatibility);
-
- // sync_driver::SyncServiceObserver implementation
- void OnStateChanged() override;
-
- DisabledReason GetDisabledReasonFromDeps() const;
-
- DisabledReason disabled_reason_;
- DisabledReasonChangeCallback disabled_reason_change_callback_;
-
- SigninManagerBase* signin_manager_;
- sync_driver::SyncService* sync_service_;
-
- // The observer for the SyncService. When the sync state changes,
- // SyncService will call |OnStateChanged|.
- ScopedObserver<sync_driver::SyncService, sync_driver::SyncServiceObserver>
- sync_service_observer_;
-
- DISALLOW_COPY_AND_ASSIGN(NTPSnippetsStatusService);
-};
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_STATUS_SERVICE_H_
diff --git a/chromium/components/ntp_snippets/ntp_snippets_status_service_unittest.cc b/chromium/components/ntp_snippets/ntp_snippets_status_service_unittest.cc
deleted file mode 100644
index 5568d805349..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_status_service_unittest.cc
+++ /dev/null
@@ -1,70 +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 "components/ntp_snippets/ntp_snippets_status_service.h"
-
-#include <memory>
-
-#include "components/ntp_snippets/ntp_snippets_test_utils.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
-#include "components/signin/core/browser/test_signin_client.h"
-#include "components/signin/core/common/signin_pref_names.h"
-#include "components/sync_driver/fake_sync_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::Return;
-
-namespace ntp_snippets {
-
-class NTPSnippetsStatusServiceTest : public test::NTPSnippetsTestBase {
- public:
- void SetUp() override {
- test::NTPSnippetsTestBase::SetUp();
-
- service_.reset(new NTPSnippetsStatusService(fake_signin_manager(),
- mock_sync_service()));
- }
-
- protected:
- NTPSnippetsStatusService* service() { return service_.get(); }
-
- private:
- std::unique_ptr<NTPSnippetsStatusService> service_;
-};
-
-TEST_F(NTPSnippetsStatusServiceTest, SyncStateCompatibility) {
- // The default test setup is signed out.
- EXPECT_EQ(DisabledReason::SIGNED_OUT, service()->GetDisabledReasonFromDeps());
-
- // Once signed in, we should be in a compatible sync state.
- fake_signin_manager()->SignIn("foo@bar.com");
- EXPECT_EQ(DisabledReason::NONE, service()->GetDisabledReasonFromDeps());
-
- // History sync disabled.
- mock_sync_service()->active_data_types_ = syncer::ModelTypeSet();
- EXPECT_EQ(DisabledReason::HISTORY_SYNC_DISABLED,
- service()->GetDisabledReasonFromDeps());
-
- // Encryption enabled.
- mock_sync_service()->is_encrypt_everything_enabled_ = true;
- EXPECT_EQ(DisabledReason::PASSPHRASE_ENCRYPTION_ENABLED,
- service()->GetDisabledReasonFromDeps());
-
- // Not done loading.
- mock_sync_service()->configuration_done_ = false;
- mock_sync_service()->active_data_types_ = syncer::ModelTypeSet();
- EXPECT_EQ(DisabledReason::HISTORY_SYNC_STATE_UNKNOWN,
- service()->GetDisabledReasonFromDeps());
-
- // Sync disabled.
- mock_sync_service()->can_sync_start_ = false;
- EXPECT_EQ(DisabledReason::SYNC_DISABLED,
- service()->GetDisabledReasonFromDeps());
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_test_utils.cc b/chromium/components/ntp_snippets/ntp_snippets_test_utils.cc
deleted file mode 100644
index c00629c7632..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_test_utils.cc
+++ /dev/null
@@ -1,74 +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 "components/ntp_snippets/ntp_snippets_test_utils.h"
-
-#include <memory>
-
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
-#include "components/signin/core/browser/test_signin_client.h"
-#include "components/signin/core/common/signin_pref_names.h"
-#include "components/sync_driver/fake_sync_service.h"
-
-namespace ntp_snippets {
-namespace test {
-
-MockSyncService::MockSyncService()
- : can_sync_start_(true),
- is_sync_active_(true),
- configuration_done_(true),
- is_encrypt_everything_enabled_(false),
- active_data_types_(syncer::HISTORY_DELETE_DIRECTIVES) {}
-
-MockSyncService::~MockSyncService() {}
-
-bool MockSyncService::CanSyncStart() const {
- return can_sync_start_;
-}
-
-bool MockSyncService::IsSyncActive() const {
- return is_sync_active_;
-}
-
-bool MockSyncService::ConfigurationDone() const {
- return configuration_done_;
-}
-
-bool MockSyncService::IsEncryptEverythingEnabled() const {
- return is_encrypt_everything_enabled_;
-}
-
-syncer::ModelTypeSet MockSyncService::GetActiveDataTypes() const {
- return active_data_types_;
-}
-
-NTPSnippetsTestBase::NTPSnippetsTestBase()
- : pref_service_(new TestingPrefServiceSimple()) {
- pref_service_->registry()->RegisterStringPref(prefs::kGoogleServicesAccountId,
- std::string());
- pref_service_->registry()->RegisterStringPref(
- prefs::kGoogleServicesLastAccountId, std::string());
- pref_service_->registry()->RegisterStringPref(
- prefs::kGoogleServicesLastUsername, std::string());
-}
-
-NTPSnippetsTestBase::~NTPSnippetsTestBase() {}
-
-void NTPSnippetsTestBase::SetUp() {
- signin_client_.reset(new TestSigninClient(pref_service_.get()));
- account_tracker_.reset(new AccountTrackerService());
- mock_sync_service_.reset(new MockSyncService());
- ResetSigninManager();
-}
-
-void NTPSnippetsTestBase::ResetSigninManager() {
- fake_signin_manager_.reset(
- new FakeSigninManagerBase(signin_client_.get(), account_tracker_.get()));
-}
-
-} // namespace test
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/ntp_snippets_test_utils.h b/chromium/components/ntp_snippets/ntp_snippets_test_utils.h
deleted file mode 100644
index 20e9c854b61..00000000000
--- a/chromium/components/ntp_snippets/ntp_snippets_test_utils.h
+++ /dev/null
@@ -1,68 +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 COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_TEST_UTILS_H_
-#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_TEST_UTILS_H_
-
-#include <memory>
-
-#include "components/sync_driver/fake_sync_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class AccountTrackerService;
-class FakeSigninManagerBase;
-class MockSyncService;
-class TestingPrefServiceSimple;
-class TestSigninClient;
-
-namespace ntp_snippets {
-namespace test {
-
-class MockSyncService : public sync_driver::FakeSyncService {
- public:
- MockSyncService();
- ~MockSyncService() override;
-
- bool CanSyncStart() const override;
- bool IsSyncActive() const override;
- bool ConfigurationDone() const override;
- bool IsEncryptEverythingEnabled() const override;
- syncer::ModelTypeSet GetActiveDataTypes() const override;
-
- bool can_sync_start_;
- bool is_sync_active_;
- bool configuration_done_;
- bool is_encrypt_everything_enabled_;
- syncer::ModelTypeSet active_data_types_;
-};
-
-// Common base for snippet tests, handles initializing mocks for sync and
-// signin. |SetUp()| should be called if a subclass overrides it.
-class NTPSnippetsTestBase : public testing::Test {
- public:
- void SetUp() override;
-
- protected:
- NTPSnippetsTestBase();
- ~NTPSnippetsTestBase() override;
- void ResetSigninManager();
-
- MockSyncService* mock_sync_service() { return mock_sync_service_.get(); }
- FakeSigninManagerBase* fake_signin_manager() {
- return fake_signin_manager_.get();
- }
- TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
-
- private:
- std::unique_ptr<FakeSigninManagerBase> fake_signin_manager_;
- std::unique_ptr<MockSyncService> mock_sync_service_;
- std::unique_ptr<TestingPrefServiceSimple> pref_service_;
- std::unique_ptr<TestSigninClient> signin_client_;
- std::unique_ptr<AccountTrackerService> account_tracker_;
-};
-
-} // namespace test
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_TEST_UTILS_H_
diff --git a/chromium/components/ntp_snippets/offline_pages/DEPS b/chromium/components/ntp_snippets/offline_pages/DEPS
new file mode 100644
index 00000000000..984d8cbcbb5
--- /dev/null
+++ b/chromium/components/ntp_snippets/offline_pages/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/offline_pages"
+]
diff --git a/chromium/components/ntp_snippets/offline_pages/offline_page_proxy.cc b/chromium/components/ntp_snippets/offline_pages/offline_page_proxy.cc
new file mode 100644
index 00000000000..4e3f17212ce
--- /dev/null
+++ b/chromium/components/ntp_snippets/offline_pages/offline_page_proxy.cc
@@ -0,0 +1,66 @@
+// 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 "components/ntp_snippets/offline_pages/offline_page_proxy.h"
+
+#include "base/bind.h"
+
+using offline_pages::MultipleOfflinePageItemResult;
+using offline_pages::MultipleOfflinePageItemCallback;
+using offline_pages::OfflinePageModel;
+
+namespace ntp_snippets {
+
+OfflinePageProxy::OfflinePageProxy(OfflinePageModel* offline_page_model)
+ : offline_page_model_(offline_page_model), weak_ptr_factory_(this) {
+ offline_page_model_->AddObserver(this);
+}
+
+void OfflinePageProxy::GetAllPages(
+ const MultipleOfflinePageItemCallback& callback) {
+ offline_page_model_->GetAllPages(callback);
+}
+
+void OfflinePageProxy::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void OfflinePageProxy::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private methods
+
+OfflinePageProxy::~OfflinePageProxy() {
+ offline_page_model_->RemoveObserver(this);
+}
+
+void OfflinePageProxy::OfflinePageModelLoaded(OfflinePageModel* model) {
+ DCHECK_EQ(offline_page_model_, model);
+}
+
+void OfflinePageProxy::OfflinePageModelChanged(OfflinePageModel* model) {
+ DCHECK_EQ(offline_page_model_, model);
+ FetchOfflinePagesAndNotify();
+}
+
+void OfflinePageProxy::OfflinePageDeleted(
+ int64_t offline_id,
+ const offline_pages::ClientId& client_id) {
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OfflinePageDeleted(offline_id, client_id));
+}
+
+void OfflinePageProxy::FetchOfflinePagesAndNotify() {
+ offline_page_model_->GetAllPages(base::Bind(
+ &OfflinePageProxy::OnOfflinePagesLoaded, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void OfflinePageProxy::OnOfflinePagesLoaded(
+ const MultipleOfflinePageItemResult& result) {
+ FOR_EACH_OBSERVER(Observer, observers_, OfflinePageModelChanged(result));
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/offline_pages/offline_page_proxy.h b/chromium/components/ntp_snippets/offline_pages/offline_page_proxy.h
new file mode 100644
index 00000000000..a3fa62ea0ca
--- /dev/null
+++ b/chromium/components/ntp_snippets/offline_pages/offline_page_proxy.h
@@ -0,0 +1,84 @@
+// 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 COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_PROXY_OFFLINE_PAGE_PROXY_H_
+#define COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_PROXY_OFFLINE_PAGE_PROXY_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "components/offline_pages/offline_page_model.h"
+#include "components/offline_pages/offline_page_types.h"
+
+namespace ntp_snippets {
+
+// Observes offline pages model and propagates updates to its observers.
+class OfflinePageProxy : public offline_pages::OfflinePageModel::Observer,
+ public base::RefCounted<OfflinePageProxy> {
+ public:
+ class Observer {
+ public:
+ // Corresponds to OfflinePageModel::Observer::OfflinePageModelChanged.
+ // Invoked when the model is being updated, due to adding, removing or
+ // updating an offline page. |offline_pages| contains all offline pages
+ // after the update.
+ virtual void OfflinePageModelChanged(
+ const std::vector<offline_pages::OfflinePageItem>& offline_pages) = 0;
+
+ // Corresponds to OfflinePageModel::Observer::OfflinePageDeleted.
+ // Invoked when an offline copy related to |offline_id| was deleted.
+ virtual void OfflinePageDeleted(
+ int64_t offline_id,
+ const offline_pages::ClientId& client_id) = 0;
+
+ protected:
+ virtual ~Observer() = default;
+ };
+
+ explicit OfflinePageProxy(
+ offline_pages::OfflinePageModel* offline_page_model);
+
+ // TODO(vitaliii): Remove this function and provide a better way for providers
+ // to get data at the start up, while querying OfflinePagesModel only once.
+ // Queries OfflinePageModel for all pages and returns them through |callback|.
+ void GetAllPages(
+ const offline_pages::MultipleOfflinePageItemCallback& callback);
+
+ // Observer accessors.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ private:
+ friend class base::RefCounted<OfflinePageProxy>;
+
+ ~OfflinePageProxy() override;
+
+ // OfflinePageModel::Observer implementation.
+ void OfflinePageModelLoaded(offline_pages::OfflinePageModel* model) override;
+ void OfflinePageModelChanged(offline_pages::OfflinePageModel* model) override;
+ void OfflinePageDeleted(int64_t offline_id,
+ const offline_pages::ClientId& client_id) override;
+
+ // Queries the OfflinePageModel for offline pages and notifies observers
+ // through |OfflinePageModelChanged|.
+ void FetchOfflinePagesAndNotify();
+
+ // Callback from the |OfflinePageModel::GetAllPages|.
+ void OnOfflinePagesLoaded(
+ const offline_pages::MultipleOfflinePageItemResult& result);
+
+ offline_pages::OfflinePageModel* offline_page_model_;
+ base::ObserverList<Observer> observers_;
+ base::WeakPtrFactory<OfflinePageProxy> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(OfflinePageProxy);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_PROXY_OFFLINE_PAGE_PROXY_H_
diff --git a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
new file mode 100644
index 00000000000..777e2a32254
--- /dev/null
+++ b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
@@ -0,0 +1,274 @@
+// 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 "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/ntp_snippets/pref_util.h"
+#include "components/offline_pages/client_namespace_constants.h"
+#include "components/offline_pages/offline_page_item.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/image/image.h"
+
+using offline_pages::ClientId;
+using offline_pages::OfflinePageItem;
+
+namespace ntp_snippets {
+
+namespace {
+
+const int kMaxSuggestionsCount = 5;
+
+struct OrderOfflinePagesByMostRecentlyVisitedFirst {
+ bool operator()(const OfflinePageItem* left,
+ const OfflinePageItem* right) const {
+ return left->last_access_time > right->last_access_time;
+ }
+};
+
+bool IsRecentTab(const ClientId& client_id) {
+ return client_id.name_space == offline_pages::kLastNNamespace;
+}
+
+} // namespace
+
+RecentTabSuggestionsProvider::RecentTabSuggestionsProvider(
+ ContentSuggestionsProvider::Observer* observer,
+ CategoryFactory* category_factory,
+ scoped_refptr<OfflinePageProxy> offline_page_proxy,
+ PrefService* pref_service)
+ : ContentSuggestionsProvider(observer, category_factory),
+ category_status_(CategoryStatus::AVAILABLE_LOADING),
+ provided_category_(
+ category_factory->FromKnownCategory(KnownCategories::RECENT_TABS)),
+ offline_page_proxy_(offline_page_proxy),
+ pref_service_(pref_service),
+ weak_ptr_factory_(this) {
+ observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
+ offline_page_proxy_->AddObserver(this);
+ FetchRecentTabs();
+}
+
+RecentTabSuggestionsProvider::~RecentTabSuggestionsProvider() {
+ offline_page_proxy_->RemoveObserver(this);
+}
+
+CategoryStatus RecentTabSuggestionsProvider::GetCategoryStatus(
+ Category category) {
+ if (category == provided_category_)
+ return category_status_;
+ NOTREACHED() << "Unknown category " << category.id();
+ return CategoryStatus::NOT_PROVIDED;
+}
+
+CategoryInfo RecentTabSuggestionsProvider::GetCategoryInfo(Category category) {
+ if (category == provided_category_) {
+ return CategoryInfo(l10n_util::GetStringUTF16(
+ IDS_NTP_RECENT_TAB_SUGGESTIONS_SECTION_HEADER),
+ ContentSuggestionsCardLayout::MINIMAL_CARD,
+ /*has_more_button=*/false,
+ /*show_if_empty=*/false);
+ }
+ NOTREACHED() << "Unknown category " << category.id();
+ return CategoryInfo(base::string16(),
+ ContentSuggestionsCardLayout::MINIMAL_CARD,
+ /*has_more_button=*/false,
+ /*show_if_empty=*/false);
+}
+
+void RecentTabSuggestionsProvider::DismissSuggestion(
+ const ContentSuggestion::ID& suggestion_id) {
+ DCHECK_EQ(provided_category_, suggestion_id.category());
+ std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
+ dismissed_ids.insert(suggestion_id.id_within_category());
+ StoreDismissedIDsToPrefs(dismissed_ids);
+}
+
+void RecentTabSuggestionsProvider::FetchSuggestionImage(
+ const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) {
+ // TODO(vitaliii): Fetch proper thumbnail from OfflinePageModel once it's
+ // available there.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, gfx::Image()));
+}
+
+void RecentTabSuggestionsProvider::ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) {
+ ClearDismissedSuggestionsForDebugging(provided_category_);
+ FetchRecentTabs();
+}
+
+void RecentTabSuggestionsProvider::ClearCachedSuggestions(Category category) {
+ // Ignored.
+}
+
+void RecentTabSuggestionsProvider::GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) {
+ DCHECK_EQ(provided_category_, category);
+ offline_page_proxy_->GetAllPages(
+ base::Bind(&RecentTabSuggestionsProvider::
+ GetAllPagesCallbackForGetDismissedSuggestions,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void RecentTabSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
+ Category category) {
+ DCHECK_EQ(provided_category_, category);
+ StoreDismissedIDsToPrefs(std::set<std::string>());
+ FetchRecentTabs();
+}
+
+// static
+void RecentTabSuggestionsProvider::RegisterProfilePrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterListPref(prefs::kDismissedRecentOfflineTabSuggestions);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private methods
+
+void RecentTabSuggestionsProvider::
+ GetAllPagesCallbackForGetDismissedSuggestions(
+ const DismissedSuggestionsCallback& callback,
+ const std::vector<OfflinePageItem>& offline_pages) const {
+ std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
+ std::vector<ContentSuggestion> suggestions;
+ for (const OfflinePageItem& item : offline_pages) {
+ if (!IsRecentTab(item.client_id) ||
+ !dismissed_ids.count(base::IntToString(item.offline_id)))
+ continue;
+ suggestions.push_back(ConvertOfflinePage(item));
+ }
+ callback.Run(std::move(suggestions));
+}
+
+void RecentTabSuggestionsProvider::OfflinePageModelChanged(
+ const std::vector<OfflinePageItem>& offline_pages) {
+ NotifyStatusChanged(CategoryStatus::AVAILABLE);
+ std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs();
+ std::set<std::string> new_dismissed_ids;
+ std::vector<const OfflinePageItem*> recent_tab_items;
+ for (const OfflinePageItem& item : offline_pages) {
+ std::string offline_page_id = base::IntToString(item.offline_id);
+ if (!IsRecentTab(item.client_id)) {
+ continue;
+ }
+
+ if (old_dismissed_ids.count(offline_page_id))
+ new_dismissed_ids.insert(offline_page_id);
+ else
+ recent_tab_items.push_back(&item);
+ }
+
+ observer()->OnNewSuggestions(
+ this, provided_category_,
+ GetMostRecentlyVisited(std::move(recent_tab_items)));
+ if (new_dismissed_ids.size() != old_dismissed_ids.size())
+ StoreDismissedIDsToPrefs(new_dismissed_ids);
+}
+
+void RecentTabSuggestionsProvider::OfflinePageDeleted(
+ int64_t offline_id,
+ const ClientId& client_id) {
+ // Because we never switch to NOT_PROVIDED dynamically, there can be no open
+ // UI containing an invalidated suggestion unless the status is something
+ // other than NOT_PROVIDED, so only notify invalidation in that case.
+ if (category_status_ != CategoryStatus::NOT_PROVIDED &&
+ IsRecentTab(client_id)) {
+ InvalidateSuggestion(offline_id);
+ }
+}
+
+void RecentTabSuggestionsProvider::FetchRecentTabs() {
+ // TODO(vitaliii): When something other than GetAllPages is used here, the
+ // dismissed IDs cleanup in OfflinePageModelChanged needs to be changed to
+ // avoid accidentally undismissing suggestions.
+ offline_page_proxy_->GetAllPages(
+ base::Bind(&RecentTabSuggestionsProvider::OfflinePageModelChanged,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void RecentTabSuggestionsProvider::NotifyStatusChanged(
+ CategoryStatus new_status) {
+ DCHECK_NE(CategoryStatus::NOT_PROVIDED, category_status_);
+ if (category_status_ == new_status)
+ return;
+ category_status_ = new_status;
+ observer()->OnCategoryStatusChanged(this, provided_category_, new_status);
+}
+
+ContentSuggestion RecentTabSuggestionsProvider::ConvertOfflinePage(
+ const OfflinePageItem& offline_page) const {
+ // TODO(vitaliii): Make sure the URL is opened in the existing tab.
+ ContentSuggestion suggestion(provided_category_,
+ base::IntToString(offline_page.offline_id),
+ offline_page.url);
+
+ if (offline_page.title.empty()) {
+ // TODO(vitaliii): Remove this fallback once the OfflinePageModel provides
+ // titles for all (relevant) OfflinePageItems.
+ suggestion.set_title(base::UTF8ToUTF16(offline_page.url.spec()));
+ } else {
+ suggestion.set_title(offline_page.title);
+ }
+ suggestion.set_publish_date(offline_page.creation_time);
+ suggestion.set_publisher_name(base::UTF8ToUTF16(offline_page.url.host()));
+ return suggestion;
+}
+
+std::vector<ContentSuggestion>
+RecentTabSuggestionsProvider::GetMostRecentlyVisited(
+ std::vector<const OfflinePageItem*> offline_page_items) const {
+ std::sort(offline_page_items.begin(), offline_page_items.end(),
+ OrderOfflinePagesByMostRecentlyVisitedFirst());
+ std::vector<ContentSuggestion> suggestions;
+ for (const OfflinePageItem* offline_page_item : offline_page_items) {
+ suggestions.push_back(ConvertOfflinePage(*offline_page_item));
+ if (suggestions.size() == kMaxSuggestionsCount)
+ break;
+ }
+ return suggestions;
+}
+
+void RecentTabSuggestionsProvider::InvalidateSuggestion(int64_t offline_id) {
+ std::string offline_page_id = base::IntToString(offline_id);
+ observer()->OnSuggestionInvalidated(
+ this, ContentSuggestion::ID(provided_category_, offline_page_id));
+
+ std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
+ auto it = dismissed_ids.find(offline_page_id);
+ if (it != dismissed_ids.end()) {
+ dismissed_ids.erase(it);
+ StoreDismissedIDsToPrefs(dismissed_ids);
+ }
+}
+
+std::set<std::string> RecentTabSuggestionsProvider::ReadDismissedIDsFromPrefs()
+ const {
+ return prefs::ReadDismissedIDsFromPrefs(
+ *pref_service_, prefs::kDismissedRecentOfflineTabSuggestions);
+}
+
+void RecentTabSuggestionsProvider::StoreDismissedIDsToPrefs(
+ const std::set<std::string>& dismissed_ids) {
+ prefs::StoreDismissedIDsToPrefs(pref_service_,
+ prefs::kDismissedRecentOfflineTabSuggestions,
+ dismissed_ids);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h
new file mode 100644
index 00000000000..033a6533d5f
--- /dev/null
+++ b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h
@@ -0,0 +1,119 @@
+// 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 COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_RECENT_TAB_SUGGESTIONS_PROVIDER_H_
+#define COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_RECENT_TAB_SUGGESTIONS_PROVIDER_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/category_status.h"
+#include "components/ntp_snippets/content_suggestion.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/ntp_snippets/offline_pages/offline_page_proxy.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace gfx {
+class Image;
+} // namespace gfx
+
+namespace ntp_snippets {
+
+// Provides recent tabs content suggestions from the offline pages model
+// obtaining the data through OfflinePageProxy.
+class RecentTabSuggestionsProvider : public ContentSuggestionsProvider,
+ public OfflinePageProxy::Observer {
+ public:
+ RecentTabSuggestionsProvider(
+ ContentSuggestionsProvider::Observer* observer,
+ CategoryFactory* category_factory,
+ scoped_refptr<OfflinePageProxy> offline_page_proxy,
+ PrefService* pref_service);
+ ~RecentTabSuggestionsProvider() override;
+
+ // ContentSuggestionsProvider implementation.
+ CategoryStatus GetCategoryStatus(Category category) override;
+ CategoryInfo GetCategoryInfo(Category category) override;
+ void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+ void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) override;
+ void ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) override;
+ void ClearCachedSuggestions(Category category) override;
+ void GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) override;
+ void ClearDismissedSuggestionsForDebugging(Category category) override;
+
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ private:
+ friend class RecentTabSuggestionsProviderTest;
+
+ void GetAllPagesCallbackForGetDismissedSuggestions(
+ const DismissedSuggestionsCallback& callback,
+ const std::vector<offline_pages::OfflinePageItem>& offline_pages) const;
+
+ // OfflinePageProxy::Observer implementation.
+ void OfflinePageModelChanged(
+ const std::vector<offline_pages::OfflinePageItem>& offline_pages)
+ override;
+ void OfflinePageDeleted(int64_t offline_id,
+ const offline_pages::ClientId& client_id) override;
+
+ // Updates the |category_status_| of the |provided_category_| and notifies the
+ // |observer_|, if necessary.
+ void NotifyStatusChanged(CategoryStatus new_status);
+
+ // Manually requests all offline pages and updates the suggestions.
+ void FetchRecentTabs();
+
+ // Converts an OfflinePageItem to a ContentSuggestion for the
+ // |provided_category_|.
+ ContentSuggestion ConvertOfflinePage(
+ const offline_pages::OfflinePageItem& offline_page) const;
+
+ // Gets the |kMaxSuggestionsCount| most recently visited OfflinePageItems from
+ // the list, orders them by last visit date and converts them to
+ // ContentSuggestions for the |provided_category_|.
+ std::vector<ContentSuggestion> GetMostRecentlyVisited(
+ std::vector<const offline_pages::OfflinePageItem*> offline_page_items)
+ const;
+
+ // Fires the |OnSuggestionInvalidated| event for the suggestion corresponding
+ // to the given |offline_id| and clears it from the dismissed IDs list, if
+ // necessary.
+ void InvalidateSuggestion(int64_t offline_id);
+
+ // Reads dismissed IDs from Prefs.
+ std::set<std::string> ReadDismissedIDsFromPrefs() const;
+
+ // Writes |dismissed_ids| into Prefs.
+ void StoreDismissedIDsToPrefs(const std::set<std::string>& dismissed_ids);
+
+ CategoryStatus category_status_;
+ const Category provided_category_;
+ scoped_refptr<OfflinePageProxy> offline_page_proxy_;
+
+ PrefService* pref_service_;
+
+ base::WeakPtrFactory<RecentTabSuggestionsProvider> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(RecentTabSuggestionsProvider);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_RECENT_TAB_SUGGESTIONS_PROVIDER_H_
diff --git a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
new file mode 100644
index 00000000000..2688b518a11
--- /dev/null
+++ b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
@@ -0,0 +1,272 @@
+// 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 "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h"
+
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/guid.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
+#include "components/offline_pages/client_namespace_constants.h"
+#include "components/offline_pages/offline_page_item.h"
+#include "components/offline_pages/stub_offline_page_model.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using offline_pages::ClientId;
+using offline_pages::MultipleOfflinePageItemCallback;
+using offline_pages::OfflinePageItem;
+using offline_pages::StubOfflinePageModel;
+using testing::_;
+using testing::IsEmpty;
+using testing::Mock;
+using testing::Property;
+using testing::SizeIs;
+
+namespace ntp_snippets {
+
+namespace {
+
+OfflinePageItem CreateDummyRecentTab(int id) {
+ std::string strid = base::IntToString(id);
+ return OfflinePageItem(
+ GURL("http://dummy.com/" + strid), id,
+ ClientId(offline_pages::kLastNNamespace, base::GenerateGUID()),
+ base::FilePath::FromUTF8Unsafe("some/folder/test" + strid + ".mhtml"), 0,
+ base::Time::Now());
+}
+
+std::vector<OfflinePageItem> CreateDummyRecentTabs(
+ const std::vector<int>& ids) {
+ std::vector<OfflinePageItem> result;
+ for (int id : ids) {
+ result.push_back(CreateDummyRecentTab(id));
+ }
+ return result;
+}
+
+OfflinePageItem CreateDummyRecentTab(int id, base::Time time) {
+ OfflinePageItem item = CreateDummyRecentTab(id);
+ item.last_access_time = time;
+ return item;
+}
+
+void CaptureDismissedSuggestions(
+ std::vector<ContentSuggestion>* captured_suggestions,
+ std::vector<ContentSuggestion> dismissed_suggestions) {
+ std::move(dismissed_suggestions.begin(), dismissed_suggestions.end(),
+ std::back_inserter(*captured_suggestions));
+}
+
+} // namespace
+
+// This model is needed only when a provider is expected to call |GetAllPages|.
+// In other cases, keeping this model empty ensures that provider listens to
+// proxy notifications without calling |GetAllPages|.
+class FakeOfflinePageModel : public StubOfflinePageModel {
+ public:
+ FakeOfflinePageModel() {}
+
+ void GetAllPages(const MultipleOfflinePageItemCallback& callback) override {
+ callback.Run(items_);
+ }
+
+ const std::vector<OfflinePageItem>& items() { return items_; }
+ std::vector<OfflinePageItem>* mutable_items() { return &items_; }
+
+ private:
+ std::vector<OfflinePageItem> items_;
+};
+
+class RecentTabSuggestionsProviderTest : public testing::Test {
+ public:
+ RecentTabSuggestionsProviderTest()
+ : pref_service_(new TestingPrefServiceSimple()) {
+ RecentTabSuggestionsProvider::RegisterProfilePrefs(
+ pref_service()->registry());
+
+ scoped_refptr<OfflinePageProxy> proxy(new OfflinePageProxy(&model_));
+ provider_.reset(new RecentTabSuggestionsProvider(
+ &observer_, &category_factory_, proxy, pref_service()));
+ }
+
+ Category recent_tabs_category() {
+ return category_factory_.FromKnownCategory(KnownCategories::RECENT_TABS);
+ }
+
+ ContentSuggestion::ID GetDummySuggestionId(int id) {
+ return ContentSuggestion::ID(recent_tabs_category(), base::IntToString(id));
+ }
+
+ void FireOfflinePageModelChanged(const std::vector<OfflinePageItem>& items) {
+ provider_->OfflinePageModelChanged(items);
+ }
+
+ void FireOfflinePageDeleted(const OfflinePageItem& item) {
+ provider_->OfflinePageDeleted(item.offline_id, item.client_id);
+ }
+
+ std::set<std::string> ReadDismissedIDsFromPrefs() {
+ return provider_->ReadDismissedIDsFromPrefs();
+ }
+
+ ContentSuggestionsProvider* provider() { return provider_.get(); }
+ FakeOfflinePageModel* model() { return &model_; }
+ MockContentSuggestionsProviderObserver* observer() { return &observer_; }
+ TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
+
+ private:
+ FakeOfflinePageModel model_;
+ MockContentSuggestionsProviderObserver observer_;
+ CategoryFactory category_factory_;
+ std::unique_ptr<TestingPrefServiceSimple> pref_service_;
+ // Last so that the dependencies are deleted after the provider.
+ std::unique_ptr<RecentTabSuggestionsProvider> provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(RecentTabSuggestionsProviderTest);
+};
+
+TEST_F(RecentTabSuggestionsProviderTest, ShouldConvertToSuggestions) {
+ std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3});
+
+ EXPECT_CALL(
+ *observer(),
+ OnNewSuggestions(_, recent_tabs_category(),
+ UnorderedElementsAre(
+ Property(&ContentSuggestion::url,
+ GURL("http://dummy.com/1")),
+ Property(&ContentSuggestion::url,
+ GURL("http://dummy.com/2")),
+ Property(&ContentSuggestion::url,
+ GURL("http://dummy.com/3")))));
+ FireOfflinePageModelChanged(offline_pages);
+}
+
+TEST_F(RecentTabSuggestionsProviderTest, ShouldSortByMostRecentlyVisited) {
+ base::Time now = base::Time::Now();
+ base::Time yesterday = now - base::TimeDelta::FromDays(1);
+ base::Time tomorrow = now + base::TimeDelta::FromDays(1);
+ std::vector<OfflinePageItem> offline_pages = {
+ CreateDummyRecentTab(1, now), CreateDummyRecentTab(2, yesterday),
+ CreateDummyRecentTab(3, tomorrow)};
+
+ EXPECT_CALL(
+ *observer(),
+ OnNewSuggestions(
+ _, recent_tabs_category(),
+ ElementsAre(Property(&ContentSuggestion::url,
+ GURL("http://dummy.com/3")),
+ Property(&ContentSuggestion::url,
+ GURL("http://dummy.com/1")),
+ Property(&ContentSuggestion::url,
+ GURL("http://dummy.com/2")))));
+ FireOfflinePageModelChanged(offline_pages);
+}
+
+TEST_F(RecentTabSuggestionsProviderTest, ShouldDeliverCorrectCategoryInfo) {
+ EXPECT_FALSE(
+ provider()->GetCategoryInfo(recent_tabs_category()).has_more_button());
+}
+
+TEST_F(RecentTabSuggestionsProviderTest, ShouldDismiss) {
+ // OfflinePageModel is initialised here because
+ // |GetDismissedSuggestionsForDebugging| may need to call |GetAllPages|
+ *(model()->mutable_items()) = CreateDummyRecentTabs({1, 2, 3, 4});
+ FireOfflinePageModelChanged(model()->items());
+
+ // Dismiss 2 and 3.
+ EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
+ provider()->DismissSuggestion(GetDummySuggestionId(2));
+ provider()->DismissSuggestion(GetDummySuggestionId(3));
+ Mock::VerifyAndClearExpectations(observer());
+
+ // They should disappear from the reported suggestions.
+ EXPECT_CALL(
+ *observer(),
+ OnNewSuggestions(_, recent_tabs_category(),
+ UnorderedElementsAre(
+ Property(&ContentSuggestion::url,
+ GURL("http://dummy.com/1")),
+ Property(&ContentSuggestion::url,
+ GURL("http://dummy.com/4")))));
+
+ FireOfflinePageModelChanged(model()->items());
+ Mock::VerifyAndClearExpectations(observer());
+
+ // And appear in the dismissed suggestions.
+ std::vector<ContentSuggestion> dismissed_suggestions;
+ provider()->GetDismissedSuggestionsForDebugging(
+ recent_tabs_category(),
+ base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
+ EXPECT_THAT(
+ dismissed_suggestions,
+ UnorderedElementsAre(Property(&ContentSuggestion::url,
+ GURL("http://dummy.com/2")),
+ Property(&ContentSuggestion::url,
+ GURL("http://dummy.com/3"))));
+
+ // Clear dismissed suggestions.
+ provider()->ClearDismissedSuggestionsForDebugging(recent_tabs_category());
+
+ // They should be gone from the dismissed suggestions.
+ dismissed_suggestions.clear();
+ provider()->GetDismissedSuggestionsForDebugging(
+ recent_tabs_category(),
+ base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
+ EXPECT_THAT(dismissed_suggestions, IsEmpty());
+
+ // And appear in the reported suggestions for the category again.
+ EXPECT_CALL(*observer(),
+ OnNewSuggestions(_, recent_tabs_category(), SizeIs(4)));
+ FireOfflinePageModelChanged(model()->items());
+ Mock::VerifyAndClearExpectations(observer());
+}
+
+TEST_F(RecentTabSuggestionsProviderTest,
+ ShouldInvalidateWhenOfflinePageDeleted) {
+ std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3});
+ FireOfflinePageModelChanged(offline_pages);
+
+ // Invalidation of suggestion 2 should be forwarded.
+ EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, GetDummySuggestionId(2)));
+ FireOfflinePageDeleted(offline_pages[1]);
+}
+
+TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnInvalidate) {
+ std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3});
+ FireOfflinePageModelChanged(offline_pages);
+ EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty());
+
+ provider()->DismissSuggestion(GetDummySuggestionId(2));
+ EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(1));
+
+ FireOfflinePageDeleted(offline_pages[1]);
+ EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty());
+}
+
+TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnFetch) {
+ FireOfflinePageModelChanged(CreateDummyRecentTabs({1, 2, 3}));
+
+ provider()->DismissSuggestion(GetDummySuggestionId(2));
+ provider()->DismissSuggestion(GetDummySuggestionId(3));
+ EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(2));
+
+ FireOfflinePageModelChanged(CreateDummyRecentTabs({2}));
+ EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(1));
+
+ FireOfflinePageModelChanged(std::vector<OfflinePageItem>());
+ EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty());
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/physical_web_pages/DEPS b/chromium/components/ntp_snippets/physical_web_pages/DEPS
new file mode 100644
index 00000000000..179f98f1617
--- /dev/null
+++ b/chromium/components/ntp_snippets/physical_web_pages/DEPS
@@ -0,0 +1,2 @@
+include_rules = [
+] \ No newline at end of file
diff --git a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
new file mode 100644
index 00000000000..b87f20ed039
--- /dev/null
+++ b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
@@ -0,0 +1,125 @@
+// 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 "components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h"
+
+#include "base/bind.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "ui/gfx/image/image.h"
+
+namespace ntp_snippets {
+
+namespace {
+
+const size_t kMaxSuggestionsCount = 10;
+
+} // namespace
+
+// TODO(vitaliii): remove when Physical Web C++ interface is provided.
+UrlInfo::UrlInfo() = default;
+UrlInfo::~UrlInfo() = default;
+UrlInfo::UrlInfo(const UrlInfo& other) = default;
+
+PhysicalWebPageSuggestionsProvider::PhysicalWebPageSuggestionsProvider(
+ ContentSuggestionsProvider::Observer* observer,
+ CategoryFactory* category_factory)
+ : ContentSuggestionsProvider(observer, category_factory),
+ category_status_(CategoryStatus::AVAILABLE_LOADING),
+ provided_category_(category_factory->FromKnownCategory(
+ KnownCategories::PHYSICAL_WEB_PAGES)) {
+ observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
+}
+
+PhysicalWebPageSuggestionsProvider::~PhysicalWebPageSuggestionsProvider() =
+ default;
+
+void PhysicalWebPageSuggestionsProvider::OnDisplayableUrlsChanged(
+ const std::vector<UrlInfo>& urls) {
+ NotifyStatusChanged(CategoryStatus::AVAILABLE);
+ std::vector<ContentSuggestion> suggestions;
+
+ for (const UrlInfo& url_info : urls) {
+ if (suggestions.size() >= kMaxSuggestionsCount) break;
+
+ ContentSuggestion suggestion(provided_category_, url_info.site_url.spec(),
+ url_info.site_url);
+
+ suggestion.set_title(base::UTF8ToUTF16(url_info.title));
+ suggestion.set_snippet_text(base::UTF8ToUTF16(url_info.description));
+ suggestion.set_publish_date(url_info.scan_time);
+ suggestion.set_publisher_name(base::UTF8ToUTF16(url_info.site_url.host()));
+ suggestions.push_back(std::move(suggestion));
+ }
+
+ observer()->OnNewSuggestions(this, provided_category_,
+ std::move(suggestions));
+}
+
+CategoryStatus PhysicalWebPageSuggestionsProvider::GetCategoryStatus(
+ Category category) {
+ return category_status_;
+}
+
+CategoryInfo PhysicalWebPageSuggestionsProvider::GetCategoryInfo(
+ Category category) {
+ // TODO(vitaliii): Use a proper string once it's been agreed on.
+ return CategoryInfo(base::ASCIIToUTF16("Physical web pages"),
+ ContentSuggestionsCardLayout::MINIMAL_CARD,
+ /* has_more_button */ true,
+ /* show_if_empty */ false);
+}
+
+void PhysicalWebPageSuggestionsProvider::DismissSuggestion(
+ const ContentSuggestion::ID& suggestion_id) {
+ // TODO(vitaliii): Implement this and then
+ // ClearDismissedSuggestionsForDebugging.
+}
+
+void PhysicalWebPageSuggestionsProvider::FetchSuggestionImage(
+ const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) {
+ // TODO(vitaliii): Implement.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, gfx::Image()));
+}
+
+void PhysicalWebPageSuggestionsProvider::ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) {
+ ClearDismissedSuggestionsForDebugging(provided_category_);
+}
+
+void PhysicalWebPageSuggestionsProvider::ClearCachedSuggestions(
+ Category category) {
+ // Ignored
+}
+
+void PhysicalWebPageSuggestionsProvider::GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) {
+ // Not implemented.
+ callback.Run(std::vector<ContentSuggestion>());
+}
+
+void PhysicalWebPageSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
+ Category category) {
+ // TODO(vitaliii): Implement when dismissed suggestions are supported.
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private methods
+
+// Updates the |category_status_| and notifies the |observer_|, if necessary.
+void PhysicalWebPageSuggestionsProvider::NotifyStatusChanged(
+ CategoryStatus new_status) {
+ if (category_status_ == new_status) return;
+ category_status_ = new_status;
+ observer()->OnCategoryStatusChanged(this, provided_category_, new_status);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
new file mode 100644
index 00000000000..934dd74038e
--- /dev/null
+++ b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
@@ -0,0 +1,72 @@
+// 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 COMPONENTS_NTP_SNIPPETS_PHYSICAL_WEB_PAGES_PHYSICAL_WEB_PAGE_SUGGESTIONS_PROVIDER_H_
+#define COMPONENTS_NTP_SNIPPETS_PHYSICAL_WEB_PAGES_PHYSICAL_WEB_PAGE_SUGGESTIONS_PROVIDER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/category_status.h"
+#include "components/ntp_snippets/content_suggestion.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+
+namespace gfx {
+class Image;
+} // namespace gfx
+
+namespace ntp_snippets {
+
+// TODO(vitaliii): remove when Physical Web C++ interface is provided.
+struct UrlInfo {
+ UrlInfo();
+ UrlInfo(const UrlInfo& other);
+ ~UrlInfo();
+ base::Time scan_time;
+ GURL site_url;
+ std::string title;
+ std::string description;
+};
+
+// Provides content suggestions from the Physical Web Service.
+class PhysicalWebPageSuggestionsProvider : public ContentSuggestionsProvider {
+ public:
+ PhysicalWebPageSuggestionsProvider(
+ ContentSuggestionsProvider::Observer* observer,
+ CategoryFactory* category_factory);
+ ~PhysicalWebPageSuggestionsProvider() override;
+
+ void OnDisplayableUrlsChanged(const std::vector<UrlInfo>& urls);
+
+ // ContentSuggestionsProvider implementation.
+ CategoryStatus GetCategoryStatus(Category category) override;
+ CategoryInfo GetCategoryInfo(Category category) override;
+ void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+ void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) override;
+ void ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) override;
+ void ClearCachedSuggestions(Category category) override;
+ void GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) override;
+ void ClearDismissedSuggestionsForDebugging(Category category) override;
+
+ private:
+ void NotifyStatusChanged(CategoryStatus new_status);
+
+ CategoryStatus category_status_;
+ const Category provided_category_;
+
+ DISALLOW_COPY_AND_ASSIGN(PhysicalWebPageSuggestionsProvider);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_PHYSICAL_WEB_PAGES_PHYSICAL_WEB_PAGE_SUGGESTIONS_PROVIDER_H_
diff --git a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc
new file mode 100644
index 00000000000..b70d2c3d9cb
--- /dev/null
+++ b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc
@@ -0,0 +1,63 @@
+// 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 "components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h"
+
+#include <string>
+#include <vector>
+
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::UnorderedElementsAre;
+
+namespace ntp_snippets {
+
+namespace {
+
+UrlInfo CreateUrlInfo(const std::string& site_url) {
+ UrlInfo url_info;
+ url_info.site_url = GURL(site_url);
+ return url_info;
+}
+
+std::vector<UrlInfo> CreateUrlInfos(const std::vector<std::string>& site_urls) {
+ std::vector<UrlInfo> url_infos;
+ for (const std::string& site_url : site_urls) {
+ url_infos.emplace_back(CreateUrlInfo(site_url));
+ }
+ return url_infos;
+}
+
+MATCHER_P(HasUrl, url, "") {
+ *result_listener << "expected URL: " << url
+ << "has URL: " << arg.url().spec();
+ return arg.url().spec() == url;
+}
+
+} // namespace
+
+TEST(PhysicalWebPageSuggestionsProviderTest, ShouldCreateSuggestions) {
+ MockContentSuggestionsProviderObserver observer;
+ CategoryFactory category_factory;
+ Category category =
+ category_factory.FromKnownCategory(KnownCategories::PHYSICAL_WEB_PAGES);
+ PhysicalWebPageSuggestionsProvider provider(&observer, &category_factory);
+ const std::string first_url = "http://test1.com/";
+ const std::string second_url = "http://test2.com/";
+ const std::vector<UrlInfo> url_infos =
+ CreateUrlInfos({first_url, second_url});
+
+ EXPECT_CALL(observer,
+ OnNewSuggestions(
+ &provider, category,
+ UnorderedElementsAre(HasUrl(first_url), HasUrl(second_url))));
+ provider.OnDisplayableUrlsChanged(url_infos);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/pref_names.cc b/chromium/components/ntp_snippets/pref_names.cc
index 57822e3f047..7b0c9bdcb3d 100644
--- a/chromium/components/ntp_snippets/pref_names.cc
+++ b/chromium/components/ntp_snippets/pref_names.cc
@@ -7,10 +7,55 @@
namespace ntp_snippets {
namespace prefs {
-const char kDeprecatedSnippets[] = "ntp_snippets.snippets";
-const char kDeprecatedDiscardedSnippets[] = "ntp_snippets.discarded_snippets";
+const char kEnableSnippets[] = "ntp_snippets.enable";
const char kSnippetHosts[] = "ntp_snippets.hosts";
+const char kRemoteSuggestionCategories[] = "ntp_snippets.remote_categories";
+
+const char kSnippetBackgroundFetchingIntervalWifi[] =
+ "ntp_snippets.fetching_interval_wifi";
+
+const char kSnippetBackgroundFetchingIntervalFallback[] =
+ "ntp_snippets.fetching_interval_fallback";
+
+const char kSnippetFetcherRequestCount[] =
+ "ntp.request_throttler.suggestion_fetcher.count";
+const char kSnippetFetcherInteractiveRequestCount[] =
+ "ntp.request_throttler.suggestion_fetcher.interactive_count";
+const char kSnippetFetcherRequestsDay[] =
+ "ntp.request_throttler.suggestion_fetcher.day";
+
+const char kSnippetThumbnailsRequestCount[] =
+ "ntp.request_throttler.suggestion_thumbnails.count";
+const char kSnippetThumbnailsInteractiveRequestCount[] =
+ "ntp.request_throttler.suggestion_thumbnails.interactive_count";
+const char kSnippetThumbnailsRequestsDay[] =
+ "ntp.request_throttler.suggestion_thumbnails.day";
+
+const char kDismissedRecentOfflineTabSuggestions[] =
+ "ntp_suggestions.offline_pages.recent_tabs.dismissed_ids";
+const char kDismissedDownloadSuggestions[] =
+ "ntp_suggestions.offline_pages.downloads.dismissed_ids";
+const char kDismissedForeignSessionsSuggestions[] =
+ "ntp_suggestions.foreign_sessions.dismissed_ids";
+
+const char kBookmarksFirstM54Start[] =
+ "ntp_suggestions.bookmarks.first_M54_start";
+
+const char kUserClassifierAverageNTPOpenedPerHour[] =
+ "ntp_suggestions.user_classifier.average_ntp_opened_per_hour";
+const char kUserClassifierAverageSuggestionsShownPerHour[] =
+ "ntp_suggestions.user_classifier.average_suggestions_shown_per_hour";
+const char kUserClassifierAverageSuggestionsUsedPerHour[] =
+ "ntp_suggestions.user_classifier.average_suggestions_used_per_hour";
+
+const char kUserClassifierLastTimeToOpenNTP[] =
+ "ntp_suggestions.user_classifier.last_time_to_open_ntp";
+const char kUserClassifierLastTimeToShowSuggestions[] =
+ "ntp_suggestions.user_classifier.last_time_to_show_suggestions";
+const char kUserClassifierLastTimeToUseSuggestions[] =
+ "ntp_suggestions.user_classifier.last_time_to_use_suggestions";
+
} // namespace prefs
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/pref_names.h b/chromium/components/ntp_snippets/pref_names.h
index 14f53cee403..2f9c3778abd 100644
--- a/chromium/components/ntp_snippets/pref_names.h
+++ b/chromium/components/ntp_snippets/pref_names.h
@@ -8,13 +8,67 @@
namespace ntp_snippets {
namespace prefs {
-// TODO(treib): Completely remove these after M53.
-extern const char kDeprecatedSnippets[];
-extern const char kDeprecatedDiscardedSnippets[];
+// If set to false, remote suggestions are completely disabled. This is set by
+// an enterprise policy.
+extern const char kEnableSnippets[];
+// TODO(treib): Remove this after M56.
extern const char kSnippetHosts[];
+// The pref name under which remote suggestion categories (including their ID
+// and title) are stored.
+extern const char kRemoteSuggestionCategories[];
+
+// The pref name for the currently-scheduled background fetching interval when
+// there is WiFi connectivity.
+extern const char kSnippetBackgroundFetchingIntervalWifi[];
+// The pref name for the currently-scheduled background fetching interval when
+// there is no WiFi connectivity.
+extern const char kSnippetBackgroundFetchingIntervalFallback[];
+
+// The pref name for today's count of NTPSnippetsFetcher requests, so far.
+extern const char kSnippetFetcherRequestCount[];
+// The pref name for today's count of NTPSnippetsFetcher interactive requests.
+extern const char kSnippetFetcherInteractiveRequestCount[];
+// The pref name for the current day for the counter of NTPSnippetsFetcher
+// requests.
+extern const char kSnippetFetcherRequestsDay[];
+
+// The pref name for today's count of requests for article thumbnails, so far.
+extern const char kSnippetThumbnailsRequestCount[];
+// The pref name for today's count of interactive requests for article
+// thumbnails, so far.
+extern const char kSnippetThumbnailsInteractiveRequestCount[];
+// The pref name for the current day for the counter of requests for article
+// thumbnails.
+extern const char kSnippetThumbnailsRequestsDay[];
+
+extern const char kDismissedRecentOfflineTabSuggestions[];
+extern const char kDismissedDownloadSuggestions[];
+extern const char kDismissedForeignSessionsSuggestions[];
+
+// The pref name for the time when M54 was first started on the device.
+extern const char kBookmarksFirstM54Start[];
+
+// The pref name for the discounted average number of browsing sessions per hour
+// that involve opening a new NTP.
+extern const char kUserClassifierAverageNTPOpenedPerHour[];
+// The pref name for the discounted average number of browsing sessions per hour
+// that involve opening showing the content suggestions.
+extern const char kUserClassifierAverageSuggestionsShownPerHour[];
+// The pref name for the discounted average number of browsing sessions per hour
+// that involve using content suggestions (i.e. opening one or clicking on the
+// "More" button).
+extern const char kUserClassifierAverageSuggestionsUsedPerHour[];
+
+// The pref name for the last time a new NTP was opened.
+extern const char kUserClassifierLastTimeToOpenNTP[];
+// The pref name for the last time content suggestions were shown to the user.
+extern const char kUserClassifierLastTimeToShowSuggestions[];
+// The pref name for the last time content suggestions were used by the user.
+extern const char kUserClassifierLastTimeToUseSuggestions[];
+
} // namespace prefs
} // namespace ntp_snippets
-#endif
+#endif // COMPONENTS_NTP_SNIPPETS_PREF_NAMES_H_
diff --git a/chromium/components/ntp_snippets/pref_util.cc b/chromium/components/ntp_snippets/pref_util.cc
new file mode 100644
index 00000000000..a6288f92535
--- /dev/null
+++ b/chromium/components/ntp_snippets/pref_util.cc
@@ -0,0 +1,40 @@
+// 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 "components/ntp_snippets/pref_util.h"
+
+#include <memory>
+
+#include "base/values.h"
+#include "components/prefs/pref_service.h"
+
+namespace ntp_snippets {
+namespace prefs {
+
+std::set<std::string> ReadDismissedIDsFromPrefs(const PrefService& pref_service,
+ const std::string& pref_name) {
+ std::set<std::string> dismissed_ids;
+ const base::ListValue* list = pref_service.GetList(pref_name);
+ for (const std::unique_ptr<base::Value>& value : *list) {
+ std::string dismissed_id;
+ bool success = value->GetAsString(&dismissed_id);
+ DCHECK(success) << "Failed to parse dismissed id from prefs param "
+ << pref_name << " into string.";
+ dismissed_ids.insert(dismissed_id);
+ }
+ return dismissed_ids;
+}
+
+void StoreDismissedIDsToPrefs(PrefService* pref_service,
+ const std::string& pref_name,
+ const std::set<std::string>& dismissed_ids) {
+ base::ListValue list;
+ for (const std::string& dismissed_id : dismissed_ids) {
+ list.AppendString(dismissed_id);
+ }
+ pref_service->Set(pref_name, list);
+}
+
+} // namespace prefs
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/pref_util.h b/chromium/components/ntp_snippets/pref_util.h
new file mode 100644
index 00000000000..06ea838bbc5
--- /dev/null
+++ b/chromium/components/ntp_snippets/pref_util.h
@@ -0,0 +1,28 @@
+// 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 COMPONENTS_NTP_SNIPPETS_PREF_UTIL_H_
+#define COMPONENTS_NTP_SNIPPETS_PREF_UTIL_H_
+
+#include <set>
+#include <string>
+
+class PrefService;
+
+namespace ntp_snippets {
+namespace prefs {
+
+// Reads a given preference and then deserializes it into a set of strings.
+std::set<std::string> ReadDismissedIDsFromPrefs(const PrefService& pref_service,
+ const std::string& pref_name);
+
+// Serializes a set of strings into a given preference.
+void StoreDismissedIDsToPrefs(PrefService* pref_service,
+ const std::string& pref_name,
+ const std::set<std::string>& dismissed_ids);
+
+} // namespace prefs
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_PREF_UTIL_H_
diff --git a/chromium/components/ntp_snippets/proto/ntp_snippets.proto b/chromium/components/ntp_snippets/proto/ntp_snippets.proto
deleted file mode 100644
index 0225dc69dba..00000000000
--- a/chromium/components/ntp_snippets/proto/ntp_snippets.proto
+++ /dev/null
@@ -1,31 +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.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package ntp_snippets;
-
-message SnippetSourceProto {
- optional string url = 1;
- optional string publisher_name = 2;
- optional string amp_url = 3;
-}
-
-message SnippetProto {
- optional string id = 1;
- optional string title = 2;
- optional string snippet = 3;
- optional string salient_image_url = 4;
- optional int64 publish_date = 5;
- optional int64 expiry_date = 6;
- optional float score = 7;
- repeated SnippetSourceProto sources = 8;
- optional bool discarded = 9;
-}
-
-message SnippetImageProto {
- optional bytes data = 1;
-}
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippet.cc b/chromium/components/ntp_snippets/remote/ntp_snippet.cc
new file mode 100644
index 00000000000..767d7e616da
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippet.cc
@@ -0,0 +1,303 @@
+// 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 "components/ntp_snippets/remote/ntp_snippet.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h"
+
+namespace {
+
+// dict.Get() specialization for base::Time values
+bool GetTimeValue(const base::DictionaryValue& dict,
+ const std::string& key,
+ base::Time* time) {
+ std::string time_value;
+ return dict.GetString(key, &time_value) &&
+ base::Time::FromString(time_value.c_str(), time);
+}
+
+// dict.Get() specialization for GURL values
+bool GetURLValue(const base::DictionaryValue& dict,
+ const std::string& key,
+ GURL* url) {
+ std::string spec;
+ if (!dict.GetString(key, &spec)) {
+ return false;
+ }
+ *url = GURL(spec);
+ return url->is_valid();
+}
+
+} // namespace
+
+namespace ntp_snippets {
+
+const int kArticlesRemoteId = 1;
+static_assert(
+ static_cast<int>(KnownCategories::ARTICLES) -
+ static_cast<int>(KnownCategories::REMOTE_CATEGORIES_OFFSET) ==
+ kArticlesRemoteId,
+ "kArticlesRemoteId has a wrong value?!");
+
+NTPSnippet::NTPSnippet(const std::string& id, int remote_category_id)
+ : id_(id),
+ score_(0),
+ is_dismissed_(false),
+ remote_category_id_(remote_category_id),
+ best_source_index_(0) {}
+
+NTPSnippet::~NTPSnippet() = default;
+
+// static
+std::unique_ptr<NTPSnippet> NTPSnippet::CreateFromChromeReaderDictionary(
+ const base::DictionaryValue& dict) {
+ const base::DictionaryValue* content = nullptr;
+ if (!dict.GetDictionary("contentInfo", &content))
+ return nullptr;
+
+ // Need at least the id.
+ std::string id;
+ if (!content->GetString("url", &id) || id.empty())
+ return nullptr;
+
+ std::unique_ptr<NTPSnippet> snippet(new NTPSnippet(id, kArticlesRemoteId));
+
+ std::string title;
+ if (content->GetString("title", &title))
+ snippet->set_title(title);
+ std::string salient_image_url;
+ if (content->GetString("thumbnailUrl", &salient_image_url))
+ snippet->set_salient_image_url(GURL(salient_image_url));
+ std::string snippet_str;
+ if (content->GetString("snippet", &snippet_str))
+ snippet->set_snippet(snippet_str);
+ // The creation and expiry timestamps are uint64s which are stored as strings.
+ std::string creation_timestamp_str;
+ if (content->GetString("creationTimestampSec", &creation_timestamp_str))
+ snippet->set_publish_date(TimeFromJsonString(creation_timestamp_str));
+ std::string expiry_timestamp_str;
+ if (content->GetString("expiryTimestampSec", &expiry_timestamp_str))
+ snippet->set_expiry_date(TimeFromJsonString(expiry_timestamp_str));
+
+ const base::ListValue* corpus_infos_list = nullptr;
+ if (!content->GetList("sourceCorpusInfo", &corpus_infos_list)) {
+ DLOG(WARNING) << "No sources found for article " << title;
+ return nullptr;
+ }
+
+ for (const auto& value : *corpus_infos_list) {
+ const base::DictionaryValue* dict_value = nullptr;
+ if (!value->GetAsDictionary(&dict_value)) {
+ DLOG(WARNING) << "Invalid source info for article " << id;
+ continue;
+ }
+
+ std::string corpus_id_str;
+ GURL corpus_id;
+ if (dict_value->GetString("corpusId", &corpus_id_str))
+ corpus_id = GURL(corpus_id_str);
+
+ if (!corpus_id.is_valid()) {
+ // We must at least have a valid source URL.
+ DLOG(WARNING) << "Invalid article url " << corpus_id_str;
+ continue;
+ }
+
+ const base::DictionaryValue* publisher_data = nullptr;
+ std::string site_title;
+ if (dict_value->GetDictionary("publisherData", &publisher_data)) {
+ if (!publisher_data->GetString("sourceName", &site_title)) {
+ // It's possible but not desirable to have no publisher data.
+ DLOG(WARNING) << "No publisher name for article " << corpus_id.spec();
+ }
+ } else {
+ DLOG(WARNING) << "No publisher data for article " << corpus_id.spec();
+ }
+
+ std::string amp_url_str;
+ GURL amp_url;
+ // Expected to not have AMP url sometimes.
+ if (dict_value->GetString("ampUrl", &amp_url_str)) {
+ amp_url = GURL(amp_url_str);
+ DLOG_IF(WARNING, !amp_url.is_valid()) << "Invalid AMP url "
+ << amp_url_str;
+ }
+ SnippetSource source(corpus_id, site_title,
+ amp_url.is_valid() ? amp_url : GURL());
+ snippet->add_source(source);
+ }
+
+ if (snippet->sources_.empty()) {
+ DLOG(WARNING) << "No sources found for article " << id;
+ return nullptr;
+ }
+
+ snippet->FindBestSource();
+
+ double score;
+ if (dict.GetDouble("score", &score))
+ snippet->set_score(score);
+
+ return snippet;
+}
+
+// static
+std::unique_ptr<NTPSnippet> NTPSnippet::CreateFromContentSuggestionsDictionary(
+ const base::DictionaryValue& dict,
+ int remote_category_id) {
+ const base::ListValue* ids;
+ std::string id;
+ if (!(dict.GetList("ids", &ids) &&
+ ids->GetString(0, &id))) { // TODO(sfiera): multiple IDs
+ return nullptr;
+ }
+
+ auto snippet = base::MakeUnique<NTPSnippet>(id, remote_category_id);
+ snippet->sources_.emplace_back(GURL(), std::string(), GURL());
+ auto* source = &snippet->sources_.back();
+ snippet->best_source_index_ = 0;
+
+ if (!(dict.GetString("title", &snippet->title_) &&
+ dict.GetString("snippet", &snippet->snippet_) &&
+ GetTimeValue(dict, "creationTime", &snippet->publish_date_) &&
+ GetTimeValue(dict, "expirationTime", &snippet->expiry_date_) &&
+ GetURLValue(dict, "imageUrl", &snippet->salient_image_url_) &&
+ dict.GetString("attribution", &source->publisher_name) &&
+ GetURLValue(dict, "fullPageUrl", &source->url))) {
+ return nullptr;
+ }
+ GetURLValue(dict, "ampUrl", &source->amp_url); // May fail; OK.
+ // TODO(sfiera): also favicon URL.
+
+ snippet->score_ = 0.0; // TODO(sfiera): put score in protocol.
+
+ return snippet;
+}
+
+// static
+std::unique_ptr<NTPSnippet> NTPSnippet::CreateFromProto(
+ const SnippetProto& proto) {
+ // Need at least the id.
+ if (!proto.has_id() || proto.id().empty())
+ return nullptr;
+
+ int remote_category_id = proto.has_remote_category_id()
+ ? proto.remote_category_id()
+ : kArticlesRemoteId;
+
+ std::unique_ptr<NTPSnippet> snippet(
+ new NTPSnippet(proto.id(), remote_category_id));
+
+ snippet->set_title(proto.title());
+ snippet->set_snippet(proto.snippet());
+ snippet->set_salient_image_url(GURL(proto.salient_image_url()));
+ snippet->set_publish_date(
+ base::Time::FromInternalValue(proto.publish_date()));
+ snippet->set_expiry_date(base::Time::FromInternalValue(proto.expiry_date()));
+ snippet->set_score(proto.score());
+ snippet->set_dismissed(proto.dismissed());
+
+ for (int i = 0; i < proto.sources_size(); ++i) {
+ const SnippetSourceProto& source_proto = proto.sources(i);
+ GURL url(source_proto.url());
+ if (!url.is_valid()) {
+ // We must at least have a valid source URL.
+ DLOG(WARNING) << "Invalid article url " << source_proto.url();
+ continue;
+ }
+ GURL amp_url;
+ if (source_proto.has_amp_url()) {
+ amp_url = GURL(source_proto.amp_url());
+ DLOG_IF(WARNING, !amp_url.is_valid()) << "Invalid AMP URL "
+ << source_proto.amp_url();
+ }
+
+ snippet->add_source(
+ SnippetSource(url, source_proto.publisher_name(), amp_url));
+ }
+
+ if (snippet->sources_.empty()) {
+ DLOG(WARNING) << "No sources found for article " << snippet->id();
+ return nullptr;
+ }
+
+ snippet->FindBestSource();
+
+ return snippet;
+}
+
+SnippetProto NTPSnippet::ToProto() const {
+ SnippetProto result;
+
+ result.set_id(id_);
+ if (!title_.empty())
+ result.set_title(title_);
+ if (!snippet_.empty())
+ result.set_snippet(snippet_);
+ if (salient_image_url_.is_valid())
+ result.set_salient_image_url(salient_image_url_.spec());
+ if (!publish_date_.is_null())
+ result.set_publish_date(publish_date_.ToInternalValue());
+ if (!expiry_date_.is_null())
+ result.set_expiry_date(expiry_date_.ToInternalValue());
+ result.set_score(score_);
+ result.set_dismissed(is_dismissed_);
+ result.set_remote_category_id(remote_category_id_);
+
+ for (const SnippetSource& source : sources_) {
+ SnippetSourceProto* source_proto = result.add_sources();
+ source_proto->set_url(source.url.spec());
+ if (!source.publisher_name.empty())
+ source_proto->set_publisher_name(source.publisher_name);
+ if (source.amp_url.is_valid())
+ source_proto->set_amp_url(source.amp_url.spec());
+ }
+
+ return result;
+}
+
+// static
+base::Time NTPSnippet::TimeFromJsonString(const std::string& timestamp_str) {
+ int64_t timestamp;
+ if (!base::StringToInt64(timestamp_str, &timestamp)) {
+ // Even if there's an error in the conversion, some garbage data may still
+ // be written to the output var, so reset it.
+ timestamp = 0;
+ }
+ return base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(timestamp);
+}
+
+// static
+std::string NTPSnippet::TimeToJsonString(const base::Time& time) {
+ return base::Int64ToString((time - base::Time::UnixEpoch()).InSeconds());
+}
+
+void NTPSnippet::FindBestSource() {
+ // The same article can be hosted by multiple sources, e.g. nytimes.com,
+ // cnn.com, etc. We need to parse the list of sources for this article and
+ // find the best match. In order of preference:
+ // 1 A source that has URL, publisher name, AMP URL
+ // 2) A source that has URL, publisher name
+ // 3) A source that has URL and AMP URL, or URL only (since we won't show
+ // the snippet to users if the article does not have a publisher name, it
+ // doesn't matter whether the snippet has the AMP URL or not)
+ best_source_index_ = 0;
+ for (size_t i = 0; i < sources_.size(); ++i) {
+ const SnippetSource& source = sources_[i];
+ if (!source.publisher_name.empty()) {
+ best_source_index_ = i;
+ if (!source.amp_url.is_empty()) {
+ // This is the best possible source, stop looking.
+ break;
+ }
+ }
+ }
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippet.h b/chromium/components/ntp_snippets/remote/ntp_snippet.h
new file mode 100644
index 00000000000..d169eb8b387
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippet.h
@@ -0,0 +1,160 @@
+// 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 COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPET_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPET_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "url/gurl.h"
+
+namespace base {
+class DictionaryValue;
+} // namespace base
+
+namespace ntp_snippets {
+
+extern const int kArticlesRemoteId;
+
+class SnippetProto;
+
+struct SnippetSource {
+ SnippetSource(const GURL& url,
+ const std::string& publisher_name,
+ const GURL& amp_url)
+ : url(url), publisher_name(publisher_name), amp_url(amp_url) {}
+ GURL url;
+ std::string publisher_name;
+ GURL amp_url;
+};
+
+class NTPSnippet {
+ public:
+ using PtrVector = std::vector<std::unique_ptr<NTPSnippet>>;
+
+ // Creates a new snippet with the given |id|.
+ // Public for testing only - create snippets using the Create* methods below.
+ // TODO(treib): Make this private and add a CreateSnippetForTest?
+ NTPSnippet(const std::string& id, int remote_category_id);
+
+ ~NTPSnippet();
+
+ // Creates an NTPSnippet from a dictionary, as returned by Chrome Reader.
+ // Returns a null pointer if the dictionary doesn't correspond to a valid
+ // snippet. The keys in the dictionary are expected to be the same as the
+ // property name, with exceptions documented in the property comment.
+ static std::unique_ptr<NTPSnippet> CreateFromChromeReaderDictionary(
+ const base::DictionaryValue& dict);
+
+ // Creates an NTPSnippet from a dictionary, as returned by Chrome Content
+ // Suggestions. Returns a null pointer if the dictionary doesn't correspond to
+ // a valid snippet. Maps field names to Chrome Reader field names.
+ static std::unique_ptr<NTPSnippet> CreateFromContentSuggestionsDictionary(
+ const base::DictionaryValue& dict,
+ int remote_category_id);
+
+ // Creates an NTPSnippet from a protocol buffer. Returns a null pointer if the
+ // protocol buffer doesn't correspond to a valid snippet.
+ static std::unique_ptr<NTPSnippet> CreateFromProto(const SnippetProto& proto);
+
+ // Creates a protocol buffer corresponding to this snippet, for persisting.
+ SnippetProto ToProto() const;
+
+ // A unique ID for identifying the snippet. If initialized by
+ // CreateFromChromeReaderDictionary() the relevant key is 'url'.
+ const std::string& id() const { return id_; }
+
+ // Title of the snippet.
+ const std::string& title() const { return title_; }
+ void set_title(const std::string& title) { title_ = title; }
+
+ // Summary or relevant extract from the content.
+ const std::string& snippet() const { return snippet_; }
+ void set_snippet(const std::string& snippet) { snippet_ = snippet; }
+
+ // Link to an image representative of the content. Do not fetch this image
+ // directly. If initialized by CreateFromChromeReaderDictionary() the relevant
+ // key is 'thumbnailUrl'
+ const GURL& salient_image_url() const { return salient_image_url_; }
+ void set_salient_image_url(const GURL& salient_image_url) {
+ salient_image_url_ = salient_image_url;
+ }
+
+ // When the page pointed by this snippet was published. If initialized by
+ // CreateFromChromeReaderDictionary() the relevant key is
+ // 'creationTimestampSec'
+ const base::Time& publish_date() const { return publish_date_; }
+ void set_publish_date(const base::Time& publish_date) {
+ publish_date_ = publish_date;
+ }
+
+ // After this expiration date this snippet should no longer be presented to
+ // the user.
+ const base::Time& expiry_date() const { return expiry_date_; }
+ void set_expiry_date(const base::Time& expiry_date) {
+ expiry_date_ = expiry_date;
+ }
+
+ size_t source_index() const { return best_source_index_; }
+ void set_source_index(size_t index) { best_source_index_ = index; }
+
+ // We should never construct an NTPSnippet object if we don't have any sources
+ // so this should never fail
+ const SnippetSource& best_source() const {
+ return sources_[best_source_index_];
+ }
+
+ const std::vector<SnippetSource>& sources() const { return sources_; }
+ void add_source(const SnippetSource& source) { sources_.push_back(source); }
+
+ // If this snippet has all the data we need to show a full card to the user
+ bool is_complete() const {
+ return !id().empty() && !sources().empty() && !title().empty() &&
+ !snippet().empty() && salient_image_url().is_valid() &&
+ !publish_date().is_null() && !expiry_date().is_null() &&
+ !best_source().publisher_name.empty();
+ }
+
+ float score() const { return score_; }
+ void set_score(float score) { score_ = score; }
+
+ bool is_dismissed() const { return is_dismissed_; }
+ void set_dismissed(bool dismissed) { is_dismissed_ = dismissed; }
+
+ // The ID of the remote category this snippet belongs to, for use with
+ // CategoryFactory::FromRemoteCategory.
+ int remote_category_id() const { return remote_category_id_; }
+
+ // Public for testing.
+ static base::Time TimeFromJsonString(const std::string& timestamp_str);
+ static std::string TimeToJsonString(const base::Time& time);
+
+ private:
+ void FindBestSource();
+
+ std::string id_;
+ std::string title_;
+ GURL salient_image_url_;
+ std::string snippet_;
+ base::Time publish_date_;
+ base::Time expiry_date_;
+ float score_;
+ bool is_dismissed_;
+ int remote_category_id_;
+
+ size_t best_source_index_;
+
+ std::vector<SnippetSource> sources_;
+
+ DISALLOW_COPY_AND_ASSIGN(NTPSnippet);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPET_H_
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippet_unittest.cc b/chromium/components/ntp_snippets/remote/ntp_snippet_unittest.cc
new file mode 100644
index 00000000000..44498837e42
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippet_unittest.cc
@@ -0,0 +1,268 @@
+// 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 "components/ntp_snippets/remote/ntp_snippet.h"
+
+#include "base/json/json_reader.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ntp_snippets {
+namespace {
+
+std::unique_ptr<NTPSnippet> SnippetFromContentSuggestionJSON(
+ const std::string& json) {
+ auto json_value = base::JSONReader::Read(json);
+ base::DictionaryValue* json_dict;
+ if (!json_value->GetAsDictionary(&json_dict)) {
+ return nullptr;
+ }
+ return NTPSnippet::CreateFromContentSuggestionsDictionary(*json_dict,
+ kArticlesRemoteId);
+}
+
+TEST(NTPSnippetTest, FromChromeContentSuggestionsDictionary) {
+ const std::string kJsonStr =
+ "{"
+ " \"ids\" : [\"http://localhost/foobar\"],"
+ " \"title\" : \"Foo Barred from Baz\","
+ " \"snippet\" : \"...\","
+ " \"fullPageUrl\" : \"http://localhost/foobar\","
+ " \"creationTime\" : \"2016-06-30T11:01:37.000Z\","
+ " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\","
+ " \"attribution\" : \"Foo News\","
+ " \"imageUrl\" : \"http://localhost/foobar.jpg\","
+ " \"ampUrl\" : \"http://localhost/amp\","
+ " \"faviconUrl\" : \"http://localhost/favicon.ico\" "
+ "}";
+ auto snippet = SnippetFromContentSuggestionJSON(kJsonStr);
+ ASSERT_THAT(snippet, testing::NotNull());
+
+ EXPECT_EQ(snippet->id(), "http://localhost/foobar");
+ EXPECT_EQ(snippet->title(), "Foo Barred from Baz");
+ EXPECT_EQ(snippet->snippet(), "...");
+ EXPECT_EQ(snippet->salient_image_url(), GURL("http://localhost/foobar.jpg"));
+ auto unix_publish_date = snippet->publish_date() - base::Time::UnixEpoch();
+ auto expiry_duration = snippet->expiry_date() - snippet->publish_date();
+ EXPECT_FLOAT_EQ(unix_publish_date.InSecondsF(), 1467284497.000000f);
+ EXPECT_FLOAT_EQ(expiry_duration.InSecondsF(), 86400.000000f);
+
+ EXPECT_EQ(snippet->best_source().publisher_name, "Foo News");
+ EXPECT_EQ(snippet->best_source().url, GURL("http://localhost/foobar"));
+ EXPECT_EQ(snippet->best_source().amp_url, GURL("http://localhost/amp"));
+}
+
+std::unique_ptr<NTPSnippet> SnippetFromChromeReaderDict(
+ std::unique_ptr<base::DictionaryValue> dict) {
+ if (!dict) {
+ return nullptr;
+ }
+ return NTPSnippet::CreateFromChromeReaderDictionary(*dict);
+}
+
+std::unique_ptr<base::DictionaryValue> SnippetWithTwoSources() {
+ const std::string kJsonStr =
+ "{\n"
+ " \"contentInfo\": {\n"
+ " \"url\": \"http://url.com\",\n"
+ " \"title\": \"Source 1 Title\",\n"
+ " \"snippet\": \"Source 1 Snippet\",\n"
+ " \"thumbnailUrl\": \"http://url.com/thumbnail\",\n"
+ " \"creationTimestampSec\": 1234567890,\n"
+ " \"expiryTimestampSec\": 2345678901,\n"
+ " \"sourceCorpusInfo\": [{\n"
+ " \"corpusId\": \"http://source1.com\",\n"
+ " \"publisherData\": {\n"
+ " \"sourceName\": \"Source 1\"\n"
+ " },\n"
+ " \"ampUrl\": \"http://source1.amp.com\"\n"
+ " }, {\n"
+ " \"corpusId\": \"http://source2.com\",\n"
+ " \"publisherData\": {\n"
+ " \"sourceName\": \"Source 2\"\n"
+ " },\n"
+ " \"ampUrl\": \"http://source2.amp.com\"\n"
+ " }]\n"
+ " },\n"
+ " \"score\": 5.0\n"
+ "}\n";
+
+ auto json_value = base::JSONReader::Read(kJsonStr);
+ base::DictionaryValue* json_dict;
+ if (!json_value->GetAsDictionary(&json_dict)) {
+ return nullptr;
+ }
+ return json_dict->CreateDeepCopy();
+}
+
+TEST(NTPSnippetTest, TestMultipleSources) {
+ auto snippet = SnippetFromChromeReaderDict(SnippetWithTwoSources());
+ ASSERT_THAT(snippet, testing::NotNull());
+
+ // Expect the first source to be chosen.
+ EXPECT_EQ(snippet->sources().size(), 2u);
+ EXPECT_EQ(snippet->id(), "http://url.com");
+ EXPECT_EQ(snippet->best_source().url, GURL("http://source1.com"));
+ EXPECT_EQ(snippet->best_source().publisher_name, std::string("Source 1"));
+ EXPECT_EQ(snippet->best_source().amp_url, GURL("http://source1.amp.com"));
+}
+
+TEST(NTPSnippetTest, TestMultipleIncompleteSources1) {
+ // Set Source 2 to have no AMP url, and Source 1 to have no publisher name
+ // Source 2 should win since we favor publisher name over amp url
+ auto dict = SnippetWithTwoSources();
+ base::ListValue* sources;
+ ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources));
+ base::DictionaryValue* source;
+ ASSERT_TRUE(sources->GetDictionary(0, &source));
+ source->Remove("publisherData.sourceName", nullptr);
+ ASSERT_TRUE(sources->GetDictionary(1, &source));
+ source->Remove("ampUrl", nullptr);
+
+ auto snippet = SnippetFromChromeReaderDict(std::move(dict));
+ ASSERT_THAT(snippet, testing::NotNull());
+
+ EXPECT_EQ(snippet->sources().size(), 2u);
+ EXPECT_EQ(snippet->id(), "http://url.com");
+ EXPECT_EQ(snippet->best_source().url, GURL("http://source2.com"));
+ EXPECT_EQ(snippet->best_source().publisher_name, std::string("Source 2"));
+ EXPECT_EQ(snippet->best_source().amp_url, GURL());
+}
+
+TEST(NTPSnippetTest, TestMultipleIncompleteSources2) {
+ // Set Source 1 to have no AMP url, and Source 2 to have no publisher name
+ // Source 1 should win in this case since we prefer publisher name to AMP url
+ auto dict = SnippetWithTwoSources();
+ base::ListValue* sources;
+ ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources));
+ base::DictionaryValue* source;
+ ASSERT_TRUE(sources->GetDictionary(0, &source));
+ source->Remove("ampUrl", nullptr);
+ ASSERT_TRUE(sources->GetDictionary(1, &source));
+ source->Remove("publisherData.sourceName", nullptr);
+
+ auto snippet = SnippetFromChromeReaderDict(std::move(dict));
+ ASSERT_THAT(snippet, testing::NotNull());
+
+ EXPECT_EQ(snippet->sources().size(), 2u);
+ EXPECT_EQ(snippet->id(), "http://url.com");
+ EXPECT_EQ(snippet->best_source().url, GURL("http://source1.com"));
+ EXPECT_EQ(snippet->best_source().publisher_name, std::string("Source 1"));
+ EXPECT_EQ(snippet->best_source().amp_url, GURL());
+}
+
+TEST(NTPSnippetTest, TestMultipleIncompleteSources3) {
+ // Set source 1 to have no AMP url and no source, and source 2 to only have
+ // amp url. There should be no snippets since we only add sources we consider
+ // complete
+ auto dict = SnippetWithTwoSources();
+ base::ListValue* sources;
+ ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources));
+ base::DictionaryValue* source;
+ ASSERT_TRUE(sources->GetDictionary(0, &source));
+ source->Remove("publisherData.sourceName", nullptr);
+ source->Remove("ampUrl", nullptr);
+ ASSERT_TRUE(sources->GetDictionary(1, &source));
+ source->Remove("publisherData.sourceName", nullptr);
+
+ auto snippet = SnippetFromChromeReaderDict(std::move(dict));
+ ASSERT_THAT(snippet, testing::NotNull());
+ ASSERT_FALSE(snippet->is_complete());
+}
+
+std::unique_ptr<base::DictionaryValue> SnippetWithThreeSources() {
+ const std::string kJsonStr =
+ "{\n"
+ " \"contentInfo\": {\n"
+ " \"url\": \"http://url.com\",\n"
+ " \"title\": \"Source 1 Title\",\n"
+ " \"snippet\": \"Source 1 Snippet\",\n"
+ " \"thumbnailUrl\": \"http://url.com/thumbnail\",\n"
+ " \"creationTimestampSec\": 1234567890,\n"
+ " \"expiryTimestampSec\": 2345678901,\n"
+ " \"sourceCorpusInfo\": [{\n"
+ " \"corpusId\": \"http://source1.com\",\n"
+ " \"publisherData\": {\n"
+ " \"sourceName\": \"Source 1\"\n"
+ " },\n"
+ " \"ampUrl\": \"http://source1.amp.com\"\n"
+ " }, {\n"
+ " \"corpusId\": \"http://source2.com\",\n"
+ " \"publisherData\": {\n"
+ " \"sourceName\": \"Source 2\"\n"
+ " },\n"
+ " \"ampUrl\": \"http://source2.amp.com\"\n"
+ " }, {\n"
+ " \"corpusId\": \"http://source3.com\",\n"
+ " \"publisherData\": {\n"
+ " \"sourceName\": \"Source 3\"\n"
+ " },\n"
+ " \"ampUrl\": \"http://source3.amp.com\"\n"
+ " }]\n"
+ " },\n"
+ " \"score\": 5.0\n"
+ "}\n";
+
+ auto json_value = base::JSONReader::Read(kJsonStr);
+ base::DictionaryValue* json_dict;
+ if (!json_value->GetAsDictionary(&json_dict)) {
+ return nullptr;
+ }
+ return json_dict->CreateDeepCopy();
+}
+
+TEST(NTPSnippetTest, TestMultipleCompleteSources1) {
+ // Test 2 complete sources, we should choose the first complete source
+ auto dict = SnippetWithThreeSources();
+ base::ListValue* sources;
+ ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources));
+ base::DictionaryValue* source;
+ ASSERT_TRUE(sources->GetDictionary(1, &source));
+ source->Remove("publisherData.sourceName", nullptr);
+
+ auto snippet = SnippetFromChromeReaderDict(std::move(dict));
+ ASSERT_THAT(snippet, testing::NotNull());
+
+ EXPECT_EQ(snippet->sources().size(), 3u);
+ EXPECT_EQ(snippet->id(), "http://url.com");
+ EXPECT_EQ(snippet->best_source().url, GURL("http://source1.com"));
+ EXPECT_EQ(snippet->best_source().publisher_name, std::string("Source 1"));
+ EXPECT_EQ(snippet->best_source().amp_url, GURL("http://source1.amp.com"));
+}
+
+TEST(NTPSnippetTest, TestMultipleCompleteSources2) {
+ // Test 2 complete sources, we should choose the first complete source
+ auto dict = SnippetWithThreeSources();
+ base::ListValue* sources;
+ ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources));
+ base::DictionaryValue* source;
+ ASSERT_TRUE(sources->GetDictionary(0, &source));
+ source->Remove("publisherData.sourceName", nullptr);
+
+ auto snippet = SnippetFromChromeReaderDict(std::move(dict));
+ ASSERT_THAT(snippet, testing::NotNull());
+
+ EXPECT_EQ(snippet->sources().size(), 3u);
+ EXPECT_EQ(snippet->id(), "http://url.com");
+ EXPECT_EQ(snippet->best_source().url, GURL("http://source2.com"));
+ EXPECT_EQ(snippet->best_source().publisher_name, std::string("Source 2"));
+ EXPECT_EQ(snippet->best_source().amp_url, GURL("http://source2.amp.com"));
+}
+
+TEST(NTPSnippetTest, TestMultipleCompleteSources3) {
+ // Test 3 complete sources, we should choose the first complete source
+ auto dict = SnippetWithThreeSources();
+ auto snippet = SnippetFromChromeReaderDict(std::move(dict));
+ ASSERT_THAT(snippet, testing::NotNull());
+
+ EXPECT_EQ(snippet->sources().size(), 3u);
+ EXPECT_EQ(snippet->id(), "http://url.com");
+ EXPECT_EQ(snippet->best_source().url, GURL("http://source1.com"));
+ EXPECT_EQ(snippet->best_source().publisher_name, std::string("Source 1"));
+ EXPECT_EQ(snippet->best_source().amp_url, GURL("http://source1.amp.com"));
+}
+
+} // namespace
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_database.cc b/chromium/components/ntp_snippets/remote/ntp_snippets_database.cc
new file mode 100644
index 00000000000..c11143a172d
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_database.cc
@@ -0,0 +1,303 @@
+// 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 "components/ntp_snippets/remote/ntp_snippets_database.h"
+
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "components/leveldb_proto/proto_database_impl.h"
+#include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h"
+
+using leveldb_proto::ProtoDatabaseImpl;
+
+namespace {
+// Statistics are logged to UMA with this string as part of histogram name. They
+// can all be found under LevelDB.*.NTPSnippets. Changing this needs to
+// synchronize with histograms.xml, AND will also become incompatible with older
+// browsers still reporting the previous values.
+const char kDatabaseUMAClientName[] = "NTPSnippets";
+const char kImageDatabaseUMAClientName[] = "NTPSnippetImages";
+
+const char kSnippetDatabaseFolder[] = "snippets";
+const char kImageDatabaseFolder[] = "images";
+} // namespace
+
+namespace ntp_snippets {
+
+NTPSnippetsDatabase::NTPSnippetsDatabase(
+ const base::FilePath& database_dir,
+ scoped_refptr<base::SequencedTaskRunner> file_task_runner)
+ : database_(
+ new ProtoDatabaseImpl<SnippetProto>(file_task_runner)),
+ database_initialized_(false),
+ image_database_(
+ new ProtoDatabaseImpl<SnippetImageProto>(file_task_runner)),
+ image_database_initialized_(false),
+ weak_ptr_factory_(this) {
+ base::FilePath snippet_dir = database_dir.AppendASCII(kSnippetDatabaseFolder);
+ database_->Init(kDatabaseUMAClientName, snippet_dir,
+ base::Bind(&NTPSnippetsDatabase::OnDatabaseInited,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ base::FilePath image_dir = database_dir.AppendASCII(kImageDatabaseFolder);
+ image_database_->Init(kImageDatabaseUMAClientName, image_dir,
+ base::Bind(&NTPSnippetsDatabase::OnImageDatabaseInited,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+NTPSnippetsDatabase::~NTPSnippetsDatabase() = default;
+
+bool NTPSnippetsDatabase::IsInitialized() const {
+ return !IsErrorState() && database_initialized_ &&
+ image_database_initialized_;
+}
+
+bool NTPSnippetsDatabase::IsErrorState() const {
+ return !database_ || !image_database_;
+}
+
+void NTPSnippetsDatabase::SetErrorCallback(
+ const base::Closure& error_callback) {
+ error_callback_ = error_callback;
+}
+
+void NTPSnippetsDatabase::LoadSnippets(const SnippetsCallback& callback) {
+ if (IsInitialized())
+ LoadSnippetsImpl(callback);
+ else
+ pending_snippets_callbacks_.emplace_back(callback);
+}
+
+void NTPSnippetsDatabase::SaveSnippet(const NTPSnippet& snippet) {
+ std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
+ entries_to_save->emplace_back(snippet.id(), snippet.ToProto());
+ SaveSnippetsImpl(std::move(entries_to_save));
+}
+
+void NTPSnippetsDatabase::SaveSnippets(const NTPSnippet::PtrVector& snippets) {
+ std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
+ for (const std::unique_ptr<NTPSnippet>& snippet : snippets)
+ entries_to_save->emplace_back(snippet->id(), snippet->ToProto());
+ SaveSnippetsImpl(std::move(entries_to_save));
+}
+
+void NTPSnippetsDatabase::DeleteSnippet(const std::string& snippet_id) {
+ DeleteSnippets(base::MakeUnique<std::vector<std::string>>(1, snippet_id));
+}
+
+void NTPSnippetsDatabase::DeleteSnippets(
+ std::unique_ptr<std::vector<std::string>> keys_to_remove) {
+ DCHECK(IsInitialized());
+
+ std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
+ database_->UpdateEntries(std::move(entries_to_save),
+ std::move(keys_to_remove),
+ base::Bind(&NTPSnippetsDatabase::OnDatabaseSaved,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NTPSnippetsDatabase::LoadImage(const std::string& snippet_id,
+ const SnippetImageCallback& callback) {
+ if (IsInitialized())
+ LoadImageImpl(snippet_id, callback);
+ else
+ pending_image_callbacks_.emplace_back(snippet_id, callback);
+}
+
+void NTPSnippetsDatabase::SaveImage(const std::string& snippet_id,
+ const std::string& image_data) {
+ DCHECK(IsInitialized());
+
+ SnippetImageProto image_proto;
+ image_proto.set_data(image_data);
+
+ std::unique_ptr<ImageKeyEntryVector> entries_to_save(
+ new ImageKeyEntryVector());
+ entries_to_save->emplace_back(snippet_id, std::move(image_proto));
+
+ image_database_->UpdateEntries(
+ std::move(entries_to_save), base::MakeUnique<std::vector<std::string>>(),
+ base::Bind(&NTPSnippetsDatabase::OnImageDatabaseSaved,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NTPSnippetsDatabase::DeleteImage(const std::string& snippet_id) {
+ DeleteImages(base::MakeUnique<std::vector<std::string>>(1, snippet_id));
+}
+
+void NTPSnippetsDatabase::DeleteImages(
+ std::unique_ptr<std::vector<std::string>> keys_to_remove) {
+ DCHECK(IsInitialized());
+ image_database_->UpdateEntries(
+ base::MakeUnique<ImageKeyEntryVector>(), std::move(keys_to_remove),
+ base::Bind(&NTPSnippetsDatabase::OnImageDatabaseSaved,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NTPSnippetsDatabase::GarbageCollectImages(
+ std::unique_ptr<std::set<std::string>> alive_snippet_ids) {
+ DCHECK(image_database_initialized_);
+ image_database_->LoadKeys(
+ base::Bind(&NTPSnippetsDatabase::DeleteUnreferencedImages,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(std::move(alive_snippet_ids))));
+}
+
+void NTPSnippetsDatabase::OnDatabaseInited(bool success) {
+ DCHECK(!database_initialized_);
+ if (!success) {
+ DVLOG(1) << "NTPSnippetsDatabase init failed.";
+ OnDatabaseError();
+ return;
+ }
+ database_initialized_ = true;
+ if (IsInitialized())
+ ProcessPendingLoads();
+}
+
+void NTPSnippetsDatabase::OnDatabaseLoaded(
+ const SnippetsCallback& callback,
+ bool success,
+ std::unique_ptr<std::vector<SnippetProto>> entries) {
+ if (!success) {
+ DVLOG(1) << "NTPSnippetsDatabase load failed.";
+ OnDatabaseError();
+ return;
+ }
+
+ std::unique_ptr<std::vector<std::string>> keys_to_remove(
+ new std::vector<std::string>());
+
+ NTPSnippet::PtrVector snippets;
+ for (const SnippetProto& proto : *entries) {
+ std::unique_ptr<NTPSnippet> snippet = NTPSnippet::CreateFromProto(proto);
+ if (snippet) {
+ snippets.emplace_back(std::move(snippet));
+ } else {
+ LOG(WARNING) << "Invalid proto from DB " << proto.id();
+ keys_to_remove->emplace_back(proto.id());
+ }
+ }
+
+ callback.Run(std::move(snippets));
+
+ // If any of the snippet protos couldn't be converted to actual snippets,
+ // clean them up now.
+ if (!keys_to_remove->empty())
+ DeleteSnippets(std::move(keys_to_remove));
+}
+
+void NTPSnippetsDatabase::OnDatabaseSaved(bool success) {
+ if (!success) {
+ DVLOG(1) << "NTPSnippetsDatabase save failed.";
+ OnDatabaseError();
+ }
+}
+
+void NTPSnippetsDatabase::OnImageDatabaseInited(bool success) {
+ DCHECK(!image_database_initialized_);
+ if (!success) {
+ DVLOG(1) << "NTPSnippetsDatabase init failed.";
+ OnDatabaseError();
+ return;
+ }
+ image_database_initialized_ = true;
+ if (IsInitialized())
+ ProcessPendingLoads();
+}
+
+void NTPSnippetsDatabase::OnImageDatabaseLoaded(
+ const SnippetImageCallback& callback,
+ bool success,
+ std::unique_ptr<SnippetImageProto> entry) {
+ if (!success) {
+ DVLOG(1) << "NTPSnippetsDatabase load failed.";
+ OnDatabaseError();
+ return;
+ }
+
+ if (!entry) {
+ callback.Run(std::string());
+ return;
+ }
+
+ std::unique_ptr<std::string> data(entry->release_data());
+ callback.Run(std::move(*data));
+}
+
+void NTPSnippetsDatabase::OnImageDatabaseSaved(bool success) {
+ if (!success) {
+ DVLOG(1) << "NTPSnippetsDatabase save failed.";
+ OnDatabaseError();
+ }
+}
+
+void NTPSnippetsDatabase::OnDatabaseError() {
+ database_.reset();
+ image_database_.reset();
+ if (!error_callback_.is_null())
+ error_callback_.Run();
+}
+
+void NTPSnippetsDatabase::ProcessPendingLoads() {
+ DCHECK(IsInitialized());
+
+ for (const auto& callback : pending_snippets_callbacks_)
+ LoadSnippetsImpl(callback);
+ pending_snippets_callbacks_.clear();
+
+ for (const auto& id_callback : pending_image_callbacks_)
+ LoadImageImpl(id_callback.first, id_callback.second);
+ pending_image_callbacks_.clear();
+}
+
+void NTPSnippetsDatabase::LoadSnippetsImpl(const SnippetsCallback& callback) {
+ DCHECK(IsInitialized());
+ database_->LoadEntries(base::Bind(&NTPSnippetsDatabase::OnDatabaseLoaded,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+}
+
+void NTPSnippetsDatabase::SaveSnippetsImpl(
+ std::unique_ptr<KeyEntryVector> entries_to_save) {
+ DCHECK(IsInitialized());
+
+ std::unique_ptr<std::vector<std::string>> keys_to_remove(
+ new std::vector<std::string>());
+ database_->UpdateEntries(std::move(entries_to_save),
+ std::move(keys_to_remove),
+ base::Bind(&NTPSnippetsDatabase::OnDatabaseSaved,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NTPSnippetsDatabase::LoadImageImpl(const std::string& snippet_id,
+ const SnippetImageCallback& callback) {
+ DCHECK(IsInitialized());
+ image_database_->GetEntry(
+ snippet_id,
+ base::Bind(&NTPSnippetsDatabase::OnImageDatabaseLoaded,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void NTPSnippetsDatabase::DeleteUnreferencedImages(
+ std::unique_ptr<std::set<std::string>> references,
+ bool load_keys_success,
+ std::unique_ptr<std::vector<std::string>> image_keys) {
+ if (!load_keys_success) {
+ DVLOG(1) << "NTPSnippetsDatabase garbage collection failed.";
+ OnDatabaseError();
+ return;
+ }
+ auto keys_to_remove = base::MakeUnique<std::vector<std::string>>();
+ for (const std::string& key : *image_keys) {
+ if (references->count(key) == 0) {
+ keys_to_remove->emplace_back(key);
+ }
+ }
+ DeleteImages(std::move(keys_to_remove));
+}
+
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_database.h b/chromium/components/ntp_snippets/remote/ntp_snippets_database.h
new file mode 100644
index 00000000000..f711edbab44
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_database.h
@@ -0,0 +1,139 @@
+// 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 COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_DATABASE_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_DATABASE_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
+#include "components/leveldb_proto/proto_database.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
+
+namespace base {
+class FilePath;
+} // namespace base
+
+namespace ntp_snippets {
+
+class SnippetImageProto;
+class SnippetProto;
+
+class NTPSnippetsDatabase {
+ public:
+ using SnippetsCallback = base::Callback<void(NTPSnippet::PtrVector)>;
+ using SnippetImageCallback = base::Callback<void(std::string)>;
+
+ NTPSnippetsDatabase(
+ const base::FilePath& database_dir,
+ scoped_refptr<base::SequencedTaskRunner> file_task_runner);
+ ~NTPSnippetsDatabase();
+
+ // Returns whether the database has finished initialization. While this is
+ // false, loads may already be started (they'll be serviced after
+ // initialization finishes), but no updates are allowed.
+ bool IsInitialized() const;
+
+ // Returns whether the database is in an (unrecoverable) error state. If this
+ // is true, the database must not be used anymore
+ bool IsErrorState() const;
+
+ // Set a callback to be called when the database enters an error state.
+ void SetErrorCallback(const base::Closure& error_callback);
+
+ // Loads all snippets from storage and passes them to |callback|.
+ void LoadSnippets(const SnippetsCallback& callback);
+
+ // Adds or updates the given snippet.
+ void SaveSnippet(const NTPSnippet& snippet);
+ // Adds or updates all the given snippets.
+ void SaveSnippets(const NTPSnippet::PtrVector& snippets);
+
+ // Deletes the snippet with the given ID.
+ void DeleteSnippet(const std::string& snippet_id);
+ // Deletes all the given snippets (identified by their IDs).
+ void DeleteSnippets(std::unique_ptr<std::vector<std::string>> keys_to_remove);
+
+ // Loads the image data for the snippet with the given ID and passes it to
+ // |callback|. Passes an empty string if not found.
+ void LoadImage(const std::string& snippet_id,
+ const SnippetImageCallback& callback);
+
+ // Adds or updates the image data for the given snippet ID.
+ void SaveImage(const std::string& snippet_id, const std::string& image_data);
+
+ // Deletes the image data for the given snippet ID.
+ void DeleteImage(const std::string& snippet_id);
+ // Deletes the image data for the given snippets (identified by their IDs).
+ void DeleteImages(std::unique_ptr<std::vector<std::string>> snippet_ids);
+ // Deletes all images which are not associated with any of the provided
+ // snippets.
+ void GarbageCollectImages(
+ std::unique_ptr<std::set<std::string>> alive_snippet_ids);
+
+ private:
+ friend class NTPSnippetsDatabaseTest;
+
+ using KeyEntryVector =
+ leveldb_proto::ProtoDatabase<SnippetProto>::KeyEntryVector;
+
+ using ImageKeyEntryVector =
+ leveldb_proto::ProtoDatabase<SnippetImageProto>::KeyEntryVector;
+
+ // Callbacks for ProtoDatabase<SnippetProto> operations.
+ void OnDatabaseInited(bool success);
+ void OnDatabaseLoaded(const SnippetsCallback& callback,
+ bool success,
+ std::unique_ptr<std::vector<SnippetProto>> entries);
+ void OnDatabaseSaved(bool success);
+
+ // Callbacks for ProtoDatabase<SnippetImageProto> operations.
+ void OnImageDatabaseInited(bool success);
+ void OnImageDatabaseLoaded(const SnippetImageCallback& callback,
+ bool success,
+ std::unique_ptr<SnippetImageProto> entry);
+ void OnImageDatabaseSaved(bool success);
+
+ void OnDatabaseError();
+
+ void ProcessPendingLoads();
+
+ void LoadSnippetsImpl(const SnippetsCallback& callback);
+ void SaveSnippetsImpl(std::unique_ptr<KeyEntryVector> entries_to_save);
+
+ void LoadImageImpl(const std::string& snippet_id,
+ const SnippetImageCallback& callback);
+ void DeleteUnreferencedImages(
+ std::unique_ptr<std::set<std::string>> references,
+ bool load_keys_success,
+ std::unique_ptr<std::vector<std::string>> image_keys);
+
+ std::unique_ptr<leveldb_proto::ProtoDatabase<SnippetProto>> database_;
+ bool database_initialized_;
+ std::vector<SnippetsCallback> pending_snippets_callbacks_;
+
+ std::unique_ptr<leveldb_proto::ProtoDatabase<SnippetImageProto>>
+ image_database_;
+ bool image_database_initialized_;
+ std::vector<std::pair<std::string, SnippetImageCallback>>
+ pending_image_callbacks_;
+
+ base::Closure error_callback_;
+
+ base::WeakPtrFactory<NTPSnippetsDatabase> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(NTPSnippetsDatabase);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_DATABASE_H_
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_database_unittest.cc b/chromium/components/ntp_snippets/remote/ntp_snippets_database_unittest.cc
new file mode 100644
index 00000000000..3a8fc5c300f
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_database_unittest.cc
@@ -0,0 +1,371 @@
+// 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 "components/ntp_snippets/remote/ntp_snippets_database.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::ElementsAre;
+using testing::Eq;
+using testing::IsEmpty;
+using testing::Mock;
+using testing::_;
+
+namespace ntp_snippets {
+
+bool operator==(const SnippetSource& lhs, const SnippetSource& rhs) {
+ return lhs.url == rhs.url && lhs.publisher_name == rhs.publisher_name &&
+ lhs.amp_url == rhs.amp_url;
+}
+
+bool operator==(const NTPSnippet& lhs, const NTPSnippet& rhs) {
+ return lhs.id() == rhs.id() && lhs.title() == rhs.title() &&
+ lhs.snippet() == rhs.snippet() &&
+ lhs.salient_image_url() == rhs.salient_image_url() &&
+ lhs.publish_date() == rhs.publish_date() &&
+ lhs.expiry_date() == rhs.expiry_date() &&
+ lhs.source_index() == rhs.source_index() &&
+ lhs.sources() == rhs.sources() && lhs.score() == rhs.score() &&
+ lhs.is_dismissed() == rhs.is_dismissed();
+}
+
+namespace {
+
+std::unique_ptr<NTPSnippet> CreateTestSnippet() {
+ std::unique_ptr<NTPSnippet> snippet(new NTPSnippet("http://localhost",
+ kArticlesRemoteId));
+ snippet->add_source(
+ SnippetSource(GURL("http://localhost"), "Publisher", GURL("http://amp")));
+ return snippet;
+}
+
+MATCHER_P(SnippetEq, snippet, "") {
+ return *arg == *snippet;
+}
+
+} // namespace
+
+class NTPSnippetsDatabaseTest : public testing::Test {
+ public:
+ NTPSnippetsDatabaseTest() {
+ EXPECT_TRUE(database_dir_.CreateUniqueTempDir());
+ }
+
+ ~NTPSnippetsDatabaseTest() override {
+ // We need to run the message loop after deleting the database, because
+ // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task
+ // runner. Without this, we'd get reports of memory leaks.
+ db_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void CreateDatabase() {
+ // Explicitly destroy any existing database first, so it releases the lock
+ // on the file.
+ db_.reset();
+
+ db_.reset(new NTPSnippetsDatabase(database_dir_.GetPath(),
+ base::ThreadTaskRunnerHandle::Get()));
+ }
+
+ NTPSnippetsDatabase* db() { return db_.get(); }
+
+ // TODO(tschumann): MOCK_METHODS on non mock objects are an anti-pattern.
+ // Clean up.
+ void OnSnippetsLoaded(NTPSnippet::PtrVector snippets) {
+ OnSnippetsLoadedImpl(snippets);
+ }
+ MOCK_METHOD1(OnSnippetsLoadedImpl,
+ void(const NTPSnippet::PtrVector& snippets));
+
+ MOCK_METHOD1(OnImageLoaded, void(std::string));
+
+ private:
+ base::MessageLoop message_loop_;
+ base::ScopedTempDir database_dir_;
+ std::unique_ptr<NTPSnippetsDatabase> db_;
+
+ DISALLOW_COPY_AND_ASSIGN(NTPSnippetsDatabaseTest);
+};
+
+TEST_F(NTPSnippetsDatabaseTest, Init) {
+ ASSERT_FALSE(db());
+
+ CreateDatabase();
+ EXPECT_FALSE(db()->IsInitialized());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(db()->IsInitialized());
+}
+
+TEST_F(NTPSnippetsDatabaseTest, LoadBeforeInit) {
+ CreateDatabase();
+ EXPECT_FALSE(db()->IsInitialized());
+
+ // Start a snippet and image load before the DB is initialized.
+ db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+ base::Unretained(this)));
+ db()->LoadImage("id", base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
+ base::Unretained(this)));
+
+ // They should be serviced once initialization finishes.
+ EXPECT_CALL(*this, OnSnippetsLoadedImpl(_));
+ EXPECT_CALL(*this, OnImageLoaded(_));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(db()->IsInitialized());
+}
+
+TEST_F(NTPSnippetsDatabaseTest, LoadAfterInit) {
+ CreateDatabase();
+ EXPECT_FALSE(db()->IsInitialized());
+
+ EXPECT_CALL(*this, OnSnippetsLoadedImpl(_)).Times(0);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(db()->IsInitialized());
+
+ Mock::VerifyAndClearExpectations(this);
+
+ EXPECT_CALL(*this, OnSnippetsLoadedImpl(_));
+ db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+ base::Unretained(this)));
+ EXPECT_CALL(*this, OnImageLoaded(_));
+ db()->LoadImage("id", base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(NTPSnippetsDatabaseTest, Save) {
+ CreateDatabase();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(db()->IsInitialized());
+
+ std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
+ std::string image_data("pretty image");
+
+ // Store a snippet and an image.
+ db()->SaveSnippet(*snippet);
+ db()->SaveImage(snippet->id(), image_data);
+
+ // Make sure they're there.
+ EXPECT_CALL(*this,
+ OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
+ db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+
+ Mock::VerifyAndClearExpectations(this);
+
+ EXPECT_CALL(*this, OnImageLoaded(image_data));
+ db()->LoadImage(snippet->id(),
+ base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(NTPSnippetsDatabaseTest, SavePersist) {
+ CreateDatabase();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(db()->IsInitialized());
+
+ std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
+ std::string image_data("pretty image");
+
+ // Store a snippet and an image.
+ db()->SaveSnippet(*snippet);
+ db()->SaveImage(snippet->id(), image_data);
+ base::RunLoop().RunUntilIdle();
+
+ // They should still exist after recreating the database.
+ CreateDatabase();
+
+ EXPECT_CALL(*this,
+ OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
+ db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+ base::Unretained(this)));
+ EXPECT_CALL(*this, OnImageLoaded(image_data));
+ db()->LoadImage(snippet->id(),
+ base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(NTPSnippetsDatabaseTest, Update) {
+ CreateDatabase();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(db()->IsInitialized());
+
+ std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
+
+ // Store a snippet.
+ db()->SaveSnippet(*snippet);
+
+ // Change it.
+ const std::string text("some text");
+ snippet->set_snippet(text);
+ db()->SaveSnippet(*snippet);
+
+ // Make sure we get the updated version.
+ EXPECT_CALL(*this,
+ OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
+ db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(NTPSnippetsDatabaseTest, Delete) {
+ CreateDatabase();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(db()->IsInitialized());
+
+ std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
+
+ // Store a snippet.
+ db()->SaveSnippet(*snippet);
+
+ // Make sure it's there.
+ EXPECT_CALL(*this,
+ OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
+ db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+
+ Mock::VerifyAndClearExpectations(this);
+
+ // Delete the snippet.
+ db()->DeleteSnippet(snippet->id());
+
+ // Make sure it's gone.
+ EXPECT_CALL(*this, OnSnippetsLoadedImpl(IsEmpty()));
+ db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(NTPSnippetsDatabaseTest, DeleteSnippetDoesNotDeleteImage) {
+ CreateDatabase();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(db()->IsInitialized());
+
+ std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
+ std::string image_data("pretty image");
+
+ // Store a snippet and image.
+ db()->SaveSnippet(*snippet);
+ db()->SaveImage(snippet->id(), image_data);
+ base::RunLoop().RunUntilIdle();
+
+ // Make sure they're there.
+ EXPECT_CALL(*this,
+ OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
+ db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+ base::Unretained(this)));
+ EXPECT_CALL(*this, OnImageLoaded(image_data));
+ db()->LoadImage(snippet->id(),
+ base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+
+ Mock::VerifyAndClearExpectations(this);
+
+ // Delete the snippet.
+ db()->DeleteSnippet(snippet->id());
+
+ // Make sure the image is still there.
+ EXPECT_CALL(*this, OnImageLoaded(image_data));
+ db()->LoadImage(snippet->id(),
+ base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(NTPSnippetsDatabaseTest, DeleteImage) {
+ CreateDatabase();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(db()->IsInitialized());
+
+ std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
+ std::string image_data("pretty image");
+
+ // Store the image.
+ db()->SaveImage(snippet->id(), image_data);
+ base::RunLoop().RunUntilIdle();
+
+ // Make sure the image is there.
+ EXPECT_CALL(*this, OnImageLoaded(image_data));
+ db()->LoadImage(snippet->id(),
+ base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+
+ Mock::VerifyAndClearExpectations(this);
+
+ // Delete the snippet.
+ db()->DeleteImage(snippet->id());
+
+ // Make sure the image is gone.
+ EXPECT_CALL(*this, OnImageLoaded(std::string()));
+ db()->LoadImage(snippet->id(),
+ base::Bind(&NTPSnippetsDatabaseTest::OnImageLoaded,
+ base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
+}
+
+namespace {
+
+void LoadExpectedImage(NTPSnippetsDatabase* db,
+ const std::string& id,
+ const std::string& expected_data) {
+ base::RunLoop run_loop;
+ db->LoadImage(id, base::Bind(
+ [](base::Closure signal, std::string expected_data,
+ std::string actual_data) {
+ EXPECT_THAT(actual_data, Eq(expected_data));
+ signal.Run();
+ },
+ run_loop.QuitClosure(), expected_data));
+ run_loop.Run();
+}
+
+} // namespace
+
+TEST_F(NTPSnippetsDatabaseTest, ShouldGarbageCollectImages) {
+ CreateDatabase();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(db()->IsInitialized());
+
+ // Store images.
+ db()->SaveImage("snippet-id-1", "pretty-image-1");
+ db()->SaveImage("snippet-id-2", "pretty-image-2");
+ db()->SaveImage("snippet-id-3", "pretty-image-3");
+ base::RunLoop().RunUntilIdle();
+
+ // Make sure the to-be-garbage collected images are there.
+ LoadExpectedImage(db(), "snippet-id-1", "pretty-image-1");
+ LoadExpectedImage(db(), "snippet-id-3", "pretty-image-3");
+
+ // Garbage collect all except the second.
+ db()->GarbageCollectImages(base::MakeUnique<std::set<std::string>>(
+ std::set<std::string>({"snippet-id-2"})));
+ base::RunLoop().RunUntilIdle();
+
+ // Make sure the images are gone.
+ LoadExpectedImage(db(), "snippet-id-1", "");
+ LoadExpectedImage(db(), "snippet-id-3", "");
+ // Make sure the second still exists.
+ LoadExpectedImage(db(), "snippet-id-2", "pretty-image-2");
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_fetcher.cc b/chromium/components/ntp_snippets/remote/ntp_snippets_fetcher.cc
new file mode 100644
index 00000000000..59a534460d5
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_fetcher.cc
@@ -0,0 +1,650 @@
+// 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 "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
+
+#include <cstdlib>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/json/json_writer.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/default_tick_clock.h"
+#include "base/values.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/ntp_snippets_constants.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/browser/signin_manager_base.h"
+#include "components/variations/net/variations_http_headers.h"
+#include "components/variations/variations_associated_data.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/url_fetcher.h"
+#include "third_party/icu/source/common/unicode/uloc.h"
+#include "third_party/icu/source/common/unicode/utypes.h"
+
+using net::URLFetcher;
+using net::URLRequestContextGetter;
+using net::HttpRequestHeaders;
+using net::URLRequestStatus;
+
+namespace ntp_snippets {
+
+namespace {
+
+const char kChromeReaderApiScope[] =
+ "https://www.googleapis.com/auth/webhistory";
+const char kContentSuggestionsApiScope[] =
+ "https://www.googleapis.com/auth/chrome-content-suggestions";
+const char kSnippetsServerNonAuthorizedFormat[] = "%s?key=%s";
+const char kAuthorizationRequestHeaderFormat[] = "Bearer %s";
+
+// Variation parameter for personalizing fetching of snippets.
+const char kPersonalizationName[] = "fetching_personalization";
+
+// Variation parameter for chrome-content-suggestions backend.
+const char kContentSuggestionsBackend[] = "content_suggestions_backend";
+
+// Constants for possible values of the "fetching_personalization" parameter.
+const char kPersonalizationPersonalString[] = "personal";
+const char kPersonalizationNonPersonalString[] = "non_personal";
+const char kPersonalizationBothString[] = "both"; // the default value
+
+const int kMaxExcludedIds = 100;
+
+std::string FetchResultToString(NTPSnippetsFetcher::FetchResult result) {
+ switch (result) {
+ case NTPSnippetsFetcher::FetchResult::SUCCESS:
+ return "OK";
+ case NTPSnippetsFetcher::FetchResult::DEPRECATED_EMPTY_HOSTS:
+ return "Cannot fetch for empty hosts list.";
+ case NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR:
+ return "URLRequestStatus error";
+ case NTPSnippetsFetcher::FetchResult::HTTP_ERROR:
+ return "HTTP error";
+ case NTPSnippetsFetcher::FetchResult::JSON_PARSE_ERROR:
+ return "Received invalid JSON";
+ case NTPSnippetsFetcher::FetchResult::INVALID_SNIPPET_CONTENT_ERROR:
+ return "Invalid / empty list.";
+ case NTPSnippetsFetcher::FetchResult::OAUTH_TOKEN_ERROR:
+ return "Error in obtaining an OAuth2 access token.";
+ case NTPSnippetsFetcher::FetchResult::INTERACTIVE_QUOTA_ERROR:
+ return "Out of interactive quota.";
+ case NTPSnippetsFetcher::FetchResult::NON_INTERACTIVE_QUOTA_ERROR:
+ return "Out of non-interactive quota.";
+ case NTPSnippetsFetcher::FetchResult::RESULT_MAX:
+ break;
+ }
+ NOTREACHED();
+ return "Unknown error";
+}
+
+bool IsFetchPreconditionFailed(NTPSnippetsFetcher::FetchResult result) {
+ switch (result) {
+ case NTPSnippetsFetcher::FetchResult::DEPRECATED_EMPTY_HOSTS:
+ case NTPSnippetsFetcher::FetchResult::OAUTH_TOKEN_ERROR:
+ case NTPSnippetsFetcher::FetchResult::INTERACTIVE_QUOTA_ERROR:
+ case NTPSnippetsFetcher::FetchResult::NON_INTERACTIVE_QUOTA_ERROR:
+ return true;
+ case NTPSnippetsFetcher::FetchResult::SUCCESS:
+ case NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR:
+ case NTPSnippetsFetcher::FetchResult::HTTP_ERROR:
+ case NTPSnippetsFetcher::FetchResult::JSON_PARSE_ERROR:
+ case NTPSnippetsFetcher::FetchResult::INVALID_SNIPPET_CONTENT_ERROR:
+ case NTPSnippetsFetcher::FetchResult::RESULT_MAX:
+ return false;
+ }
+ NOTREACHED();
+ return true;
+}
+
+std::string GetFetchEndpoint() {
+ std::string endpoint = variations::GetVariationParamValue(
+ ntp_snippets::kStudyName, kContentSuggestionsBackend);
+ return endpoint.empty() ? kChromeReaderServer : endpoint;
+}
+
+bool UsesChromeContentSuggestionsAPI(const GURL& endpoint) {
+ if (endpoint == GURL(kChromeReaderServer))
+ return false;
+
+ if (endpoint != GURL(kContentSuggestionsServer) &&
+ endpoint != GURL(kContentSuggestionsDevServer) &&
+ endpoint != GURL(kContentSuggestionsAlphaServer)) {
+ LOG(WARNING) << "Unknown value for " << kContentSuggestionsBackend << ": "
+ << "assuming chromecontentsuggestions-style API";
+ }
+ return true;
+}
+
+// Creates snippets from dictionary values in |list| and adds them to
+// |snippets|. Returns true on success, false if anything went wrong.
+// |remote_category_id| is only used if |content_suggestions_api| is true.
+bool AddSnippetsFromListValue(bool content_suggestions_api,
+ int remote_category_id,
+ const base::ListValue& list,
+ NTPSnippet::PtrVector* snippets) {
+ for (const auto& value : list) {
+ const base::DictionaryValue* dict = nullptr;
+ if (!value->GetAsDictionary(&dict)) {
+ return false;
+ }
+
+ std::unique_ptr<NTPSnippet> snippet;
+ if (content_suggestions_api) {
+ snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(
+ *dict, remote_category_id);
+ } else {
+ snippet = NTPSnippet::CreateFromChromeReaderDictionary(*dict);
+ }
+ if (!snippet) {
+ return false;
+ }
+
+ snippets->push_back(std::move(snippet));
+ }
+ return true;
+}
+
+// Translate the BCP 47 |language_code| into a posix locale string.
+std::string PosixLocaleFromBCP47Language(const std::string& language_code) {
+ char locale[ULOC_FULLNAME_CAPACITY];
+ UErrorCode error = U_ZERO_ERROR;
+ // Translate the input to a posix locale.
+ uloc_forLanguageTag(language_code.c_str(), locale, ULOC_FULLNAME_CAPACITY,
+ nullptr, &error);
+ DLOG_IF(WARNING, U_ZERO_ERROR != error)
+ << "Error in translating language code to a locale string: " << error;
+ return locale;
+}
+
+} // namespace
+
+NTPSnippetsFetcher::FetchedCategory::FetchedCategory(Category c)
+ : category(c) {}
+
+NTPSnippetsFetcher::FetchedCategory::FetchedCategory(FetchedCategory&&) =
+ default;
+NTPSnippetsFetcher::FetchedCategory::~FetchedCategory() = default;
+NTPSnippetsFetcher::FetchedCategory& NTPSnippetsFetcher::FetchedCategory::
+operator=(FetchedCategory&&) = default;
+
+NTPSnippetsFetcher::NTPSnippetsFetcher(
+ SigninManagerBase* signin_manager,
+ OAuth2TokenService* token_service,
+ scoped_refptr<URLRequestContextGetter> url_request_context_getter,
+ PrefService* pref_service,
+ CategoryFactory* category_factory,
+ const ParseJSONCallback& parse_json_callback,
+ const std::string& api_key)
+ : OAuth2TokenService::Consumer("ntp_snippets"),
+ signin_manager_(signin_manager),
+ token_service_(token_service),
+ waiting_for_refresh_token_(false),
+ url_request_context_getter_(std::move(url_request_context_getter)),
+ category_factory_(category_factory),
+ parse_json_callback_(parse_json_callback),
+ count_to_fetch_(0),
+ fetch_url_(GetFetchEndpoint()),
+ fetch_api_(UsesChromeContentSuggestionsAPI(fetch_url_)
+ ? CHROME_CONTENT_SUGGESTIONS_API
+ : CHROME_READER_API),
+ api_key_(api_key),
+ interactive_request_(false),
+ tick_clock_(new base::DefaultTickClock()),
+ request_throttler_(
+ pref_service,
+ RequestThrottler::RequestType::CONTENT_SUGGESTION_FETCHER),
+ oauth_token_retried_(false),
+ weak_ptr_factory_(this) {
+ // Parse the variation parameters and set the defaults if missing.
+ std::string personalization = variations::GetVariationParamValue(
+ ntp_snippets::kStudyName, kPersonalizationName);
+ if (personalization == kPersonalizationNonPersonalString) {
+ personalization_ = Personalization::kNonPersonal;
+ } else if (personalization == kPersonalizationPersonalString) {
+ personalization_ = Personalization::kPersonal;
+ } else {
+ personalization_ = Personalization::kBoth;
+ LOG_IF(WARNING, !personalization.empty() &&
+ personalization != kPersonalizationBothString)
+ << "Unknown value for " << kPersonalizationName << ": "
+ << personalization;
+ }
+}
+
+NTPSnippetsFetcher::~NTPSnippetsFetcher() {
+ if (waiting_for_refresh_token_)
+ token_service_->RemoveObserver(this);
+}
+
+void NTPSnippetsFetcher::SetCallback(
+ const SnippetsAvailableCallback& callback) {
+ snippets_available_callback_ = callback;
+}
+
+void NTPSnippetsFetcher::FetchSnippetsFromHosts(
+ const std::set<std::string>& hosts,
+ const std::string& language_code,
+ const std::set<std::string>& excluded_ids,
+ int count,
+ bool interactive_request) {
+ if (!request_throttler_.DemandQuotaForRequest(interactive_request)) {
+ FetchFinished(OptionalFetchedCategories(),
+ interactive_request
+ ? FetchResult::INTERACTIVE_QUOTA_ERROR
+ : FetchResult::NON_INTERACTIVE_QUOTA_ERROR,
+ /*extra_message=*/std::string());
+ return;
+ }
+
+ hosts_ = hosts;
+ fetch_start_time_ = tick_clock_->NowTicks();
+ excluded_ids_ = excluded_ids;
+
+ locale_ = PosixLocaleFromBCP47Language(language_code);
+ count_to_fetch_ = count;
+
+ bool use_authentication = UsesAuthentication();
+ interactive_request_ = interactive_request;
+
+ if (use_authentication && signin_manager_->IsAuthenticated()) {
+ // Signed-in: get OAuth token --> fetch snippets.
+ oauth_token_retried_ = false;
+ StartTokenRequest();
+ } else if (use_authentication && signin_manager_->AuthInProgress()) {
+ // Currently signing in: wait for auth to finish (the refresh token) -->
+ // get OAuth token --> fetch snippets.
+ if (!waiting_for_refresh_token_) {
+ // Wait until we get a refresh token.
+ waiting_for_refresh_token_ = true;
+ token_service_->AddObserver(this);
+ }
+ } else {
+ // Not signed in: fetch snippets (without authentication).
+ FetchSnippetsNonAuthenticated();
+ }
+}
+
+NTPSnippetsFetcher::RequestParams::RequestParams()
+ : fetch_api(),
+ obfuscated_gaia_id(),
+ only_return_personalized_results(),
+ user_locale(),
+ host_restricts(),
+ count_to_fetch(),
+ interactive_request() {}
+
+NTPSnippetsFetcher::RequestParams::~RequestParams() = default;
+
+std::string NTPSnippetsFetcher::RequestParams::BuildRequest() {
+ auto request = base::MakeUnique<base::DictionaryValue>();
+ switch (fetch_api) {
+ case CHROME_READER_API: {
+ auto content_params = base::MakeUnique<base::DictionaryValue>();
+ content_params->SetBoolean("only_return_personalized_results",
+ only_return_personalized_results);
+
+ auto content_restricts = base::MakeUnique<base::ListValue>();
+ for (const auto* metadata : {"TITLE", "SNIPPET", "THUMBNAIL"}) {
+ auto entry = base::MakeUnique<base::DictionaryValue>();
+ entry->SetString("type", "METADATA");
+ entry->SetString("value", metadata);
+ content_restricts->Append(std::move(entry));
+ }
+
+ auto content_selectors = base::MakeUnique<base::ListValue>();
+ for (const auto& host : host_restricts) {
+ auto entry = base::MakeUnique<base::DictionaryValue>();
+ entry->SetString("type", "HOST_RESTRICT");
+ entry->SetString("value", host);
+ content_selectors->Append(std::move(entry));
+ }
+
+ auto local_scoring_params = base::MakeUnique<base::DictionaryValue>();
+ local_scoring_params->Set("content_params", std::move(content_params));
+ local_scoring_params->Set("content_restricts",
+ std::move(content_restricts));
+ local_scoring_params->Set("content_selectors",
+ std::move(content_selectors));
+
+ auto global_scoring_params = base::MakeUnique<base::DictionaryValue>();
+ global_scoring_params->SetInteger("num_to_return", count_to_fetch);
+ global_scoring_params->SetInteger("sort_type", 1);
+
+ auto advanced = base::MakeUnique<base::DictionaryValue>();
+ advanced->Set("local_scoring_params", std::move(local_scoring_params));
+ advanced->Set("global_scoring_params", std::move(global_scoring_params));
+
+ request->SetString("response_detail_level", "STANDARD");
+ request->Set("advanced_options", std::move(advanced));
+ if (!obfuscated_gaia_id.empty()) {
+ request->SetString("obfuscated_gaia_id", obfuscated_gaia_id);
+ }
+ if (!user_locale.empty()) {
+ request->SetString("user_locale", user_locale);
+ }
+ break;
+ }
+
+ case CHROME_CONTENT_SUGGESTIONS_API: {
+ if (!user_locale.empty()) {
+ request->SetString("uiLanguage", user_locale);
+ }
+
+ auto regular_hosts = base::MakeUnique<base::ListValue>();
+ for (const auto& host : host_restricts) {
+ regular_hosts->AppendString(host);
+ }
+ request->Set("regularlyVisitedHostNames", std::move(regular_hosts));
+ request->SetString("priority", interactive_request
+ ? "USER_ACTION"
+ : "BACKGROUND_PREFETCH");
+
+ auto excluded = base::MakeUnique<base::ListValue>();
+ for (const auto& id : excluded_ids) {
+ excluded->AppendString(id);
+ if (excluded->GetSize() >= kMaxExcludedIds)
+ break;
+ }
+ request->Set("excludedSuggestionIds", std::move(excluded));
+
+ // TODO(sfiera): support authentication and personalization
+ // TODO(sfiera): support count_to_fetch
+ break;
+ }
+ }
+
+ std::string request_json;
+ bool success = base::JSONWriter::WriteWithOptions(
+ *request, base::JSONWriter::OPTIONS_PRETTY_PRINT, &request_json);
+ DCHECK(success);
+ return request_json;
+}
+
+void NTPSnippetsFetcher::FetchSnippetsImpl(const GURL& url,
+ const std::string& auth_header,
+ const std::string& request) {
+ url_fetcher_ = URLFetcher::Create(url, URLFetcher::POST, this);
+
+ url_fetcher_->SetRequestContext(url_request_context_getter_.get());
+ url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES);
+
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ url_fetcher_.get(), data_use_measurement::DataUseUserData::NTP_SNIPPETS);
+
+ HttpRequestHeaders headers;
+ if (!auth_header.empty())
+ headers.SetHeader("Authorization", auth_header);
+ headers.SetHeader("Content-Type", "application/json; charset=UTF-8");
+ // Add X-Client-Data header with experiment IDs from field trials.
+ variations::AppendVariationHeaders(url,
+ false, // incognito
+ false, // uma_enabled
+ &headers);
+ url_fetcher_->SetExtraRequestHeaders(headers.ToString());
+ url_fetcher_->SetUploadData("application/json", request);
+ // Log the request for debugging network issues.
+ VLOG(1) << "Sending a NTP snippets request to " << url << ":" << std::endl
+ << headers.ToString() << std::endl
+ << request;
+ // Fetchers are sometimes cancelled because a network change was detected.
+ url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
+ // Try to make fetching the files bit more robust even with poor connection.
+ url_fetcher_->SetMaxRetriesOn5xx(3);
+ url_fetcher_->Start();
+}
+
+bool NTPSnippetsFetcher::UsesAuthentication() const {
+ return (personalization_ == Personalization::kPersonal ||
+ personalization_ == Personalization::kBoth);
+}
+
+void NTPSnippetsFetcher::FetchSnippetsNonAuthenticated() {
+ // When not providing OAuth token, we need to pass the Google API key.
+ GURL url(base::StringPrintf(kSnippetsServerNonAuthorizedFormat,
+ fetch_url_.spec().c_str(), api_key_.c_str()));
+
+ RequestParams params;
+ params.fetch_api = fetch_api_;
+ params.host_restricts = hosts_;
+ params.excluded_ids = excluded_ids_;
+ params.count_to_fetch = count_to_fetch_;
+ params.interactive_request = interactive_request_;
+ params.user_locale = locale_;
+ FetchSnippetsImpl(url, std::string(), params.BuildRequest());
+}
+
+void NTPSnippetsFetcher::FetchSnippetsAuthenticated(
+ const std::string& account_id,
+ const std::string& oauth_access_token) {
+ RequestParams params;
+ params.fetch_api = fetch_api_;
+ params.obfuscated_gaia_id = account_id;
+ params.only_return_personalized_results =
+ personalization_ == Personalization::kPersonal;
+ params.user_locale = locale_;
+ params.host_restricts = hosts_;
+ params.excluded_ids = excluded_ids_;
+ params.count_to_fetch = count_to_fetch_;
+ params.interactive_request = interactive_request_;
+ // TODO(jkrcal, treib): Add unit-tests for authenticated fetches.
+ FetchSnippetsImpl(fetch_url_,
+ base::StringPrintf(kAuthorizationRequestHeaderFormat,
+ oauth_access_token.c_str()),
+ params.BuildRequest());
+}
+
+void NTPSnippetsFetcher::StartTokenRequest() {
+ OAuth2TokenService::ScopeSet scopes;
+ scopes.insert(fetch_api_ == CHROME_CONTENT_SUGGESTIONS_API
+ ? kContentSuggestionsApiScope
+ : kChromeReaderApiScope);
+ oauth_request_ = token_service_->StartRequest(
+ signin_manager_->GetAuthenticatedAccountId(), scopes, this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// OAuth2TokenService::Consumer overrides
+void NTPSnippetsFetcher::OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) {
+ // Delete the request after we leave this method.
+ std::unique_ptr<OAuth2TokenService::Request> oauth_request(
+ std::move(oauth_request_));
+ DCHECK_EQ(oauth_request.get(), request)
+ << "Got tokens from some previous request";
+
+ FetchSnippetsAuthenticated(oauth_request->GetAccountId(), access_token);
+}
+
+void NTPSnippetsFetcher::OnGetTokenFailure(
+ const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ oauth_request_.reset();
+
+ if (!oauth_token_retried_ &&
+ error.state() == GoogleServiceAuthError::State::REQUEST_CANCELED) {
+ // The request (especially on startup) can get reset by loading the refresh
+ // token - do it one more time.
+ oauth_token_retried_ = true;
+ StartTokenRequest();
+ return;
+ }
+
+ DLOG(ERROR) << "Unable to get token: " << error.ToString();
+ FetchFinished(
+ OptionalFetchedCategories(), FetchResult::OAUTH_TOKEN_ERROR,
+ /*extra_message=*/base::StringPrintf(" (%s)", error.ToString().c_str()));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// OAuth2TokenService::Observer overrides
+void NTPSnippetsFetcher::OnRefreshTokenAvailable(
+ const std::string& account_id) {
+ // Only react on tokens for the account the user has signed in with.
+ if (account_id != signin_manager_->GetAuthenticatedAccountId())
+ return;
+
+ token_service_->RemoveObserver(this);
+ waiting_for_refresh_token_ = false;
+ oauth_token_retried_ = false;
+ StartTokenRequest();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// URLFetcherDelegate overrides
+void NTPSnippetsFetcher::OnURLFetchComplete(const URLFetcher* source) {
+ DCHECK_EQ(url_fetcher_.get(), source);
+
+ const URLRequestStatus& status = source->GetStatus();
+
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode",
+ status.is_success() ? source->GetResponseCode() : status.error());
+
+ if (!status.is_success()) {
+ FetchFinished(OptionalFetchedCategories(),
+ FetchResult::URL_REQUEST_STATUS_ERROR,
+ /*extra_message=*/base::StringPrintf(" %d", status.error()));
+ } else if (source->GetResponseCode() != net::HTTP_OK) {
+ // TODO(jkrcal): https://crbug.com/609084
+ // We need to deal with the edge case again where the auth
+ // token expires just before we send the request (in which case we need to
+ // fetch a new auth token). We should extract that into a common class
+ // instead of adding it to every single class that uses auth tokens.
+ FetchFinished(
+ OptionalFetchedCategories(), FetchResult::HTTP_ERROR,
+ /*extra_message=*/base::StringPrintf(" %d", source->GetResponseCode()));
+ } else {
+ bool stores_result_to_string =
+ source->GetResponseAsString(&last_fetch_json_);
+ DCHECK(stores_result_to_string);
+
+ parse_json_callback_.Run(last_fetch_json_,
+ base::Bind(&NTPSnippetsFetcher::OnJsonParsed,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&NTPSnippetsFetcher::OnJsonError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+bool NTPSnippetsFetcher::JsonToSnippets(const base::Value& parsed,
+ FetchedCategoriesVector* categories) {
+ const base::DictionaryValue* top_dict = nullptr;
+ if (!parsed.GetAsDictionary(&top_dict)) {
+ return false;
+ }
+
+ switch (fetch_api_) {
+ case CHROME_READER_API: {
+ const int kUnusedRemoteCategoryId = -1;
+ categories->push_back(FetchedCategory(
+ category_factory_->FromKnownCategory(KnownCategories::ARTICLES)));
+ const base::ListValue* recos = nullptr;
+ return top_dict->GetList("recos", &recos) &&
+ AddSnippetsFromListValue(/*content_suggestions_api=*/false,
+ kUnusedRemoteCategoryId,
+ *recos, &categories->back().snippets);
+ }
+
+ case CHROME_CONTENT_SUGGESTIONS_API: {
+ const base::ListValue* categories_value = nullptr;
+ if (!top_dict->GetList("categories", &categories_value)) {
+ return false;
+ }
+
+ for (const auto& v : *categories_value) {
+ std::string utf8_title;
+ int remote_category_id = -1;
+ const base::DictionaryValue* category_value = nullptr;
+ if (!(v->GetAsDictionary(&category_value) &&
+ category_value->GetString("localizedTitle", &utf8_title) &&
+ category_value->GetInteger("id", &remote_category_id) &&
+ (remote_category_id > 0))) {
+ return false;
+ }
+
+ categories->push_back(FetchedCategory(
+ category_factory_->FromRemoteCategory(remote_category_id)));
+ categories->back().localized_title = base::UTF8ToUTF16(utf8_title);
+
+ const base::ListValue* suggestions = nullptr;
+ if (!category_value->GetList("suggestions", &suggestions)) {
+ // Absence of a list of suggestions is treated as an empty list, which
+ // is permissible.
+ continue;
+ }
+ if (!AddSnippetsFromListValue(
+ /*content_suggestions_api=*/true, remote_category_id,
+ *suggestions, &categories->back().snippets)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ NOTREACHED();
+ return false;
+}
+
+void NTPSnippetsFetcher::OnJsonParsed(std::unique_ptr<base::Value> parsed) {
+ FetchedCategoriesVector categories;
+ if (JsonToSnippets(*parsed, &categories)) {
+ FetchFinished(OptionalFetchedCategories(std::move(categories)),
+ FetchResult::SUCCESS,
+ /*extra_message=*/std::string());
+ } else {
+ LOG(WARNING) << "Received invalid snippets: " << last_fetch_json_;
+ FetchFinished(OptionalFetchedCategories(),
+ FetchResult::INVALID_SNIPPET_CONTENT_ERROR,
+ /*extra_message=*/std::string());
+ }
+}
+
+void NTPSnippetsFetcher::OnJsonError(const std::string& error) {
+ LOG(WARNING) << "Received invalid JSON (" << error
+ << "): " << last_fetch_json_;
+ FetchFinished(
+ OptionalFetchedCategories(), FetchResult::JSON_PARSE_ERROR,
+ /*extra_message=*/base::StringPrintf(" (error %s)", error.c_str()));
+}
+
+void NTPSnippetsFetcher::FetchFinished(
+ OptionalFetchedCategories fetched_categories,
+ FetchResult result,
+ const std::string& extra_message) {
+ DCHECK(result == FetchResult::SUCCESS || !fetched_categories);
+ last_status_ = FetchResultToString(result) + extra_message;
+
+ // Don't record FetchTimes if the result indicates that a precondition
+ // failed and we never actually sent a network request
+ if (!IsFetchPreconditionFailed(result)) {
+ UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime",
+ tick_clock_->NowTicks() - fetch_start_time_);
+ }
+ UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult",
+ static_cast<int>(result),
+ static_cast<int>(FetchResult::RESULT_MAX));
+
+ DVLOG(1) << "Fetch finished: " << last_status_;
+ if (!snippets_available_callback_.is_null())
+ snippets_available_callback_.Run(std::move(fetched_categories));
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_fetcher.h b/chromium/components/ntp_snippets/remote/ntp_snippets_fetcher.h
new file mode 100644
index 00000000000..a72e644ff27
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_fetcher.h
@@ -0,0 +1,265 @@
+// 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 COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_FETCHER_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_FETCHER_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
+#include "components/ntp_snippets/remote/request_throttler.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_context_getter.h"
+
+class PrefService;
+class SigninManagerBase;
+
+namespace base {
+class Value;
+} // namespace base
+
+namespace ntp_snippets {
+
+// Fetches snippet data for the NTP from the server.
+class NTPSnippetsFetcher : public OAuth2TokenService::Consumer,
+ public OAuth2TokenService::Observer,
+ public net::URLFetcherDelegate {
+ public:
+ // Callbacks for JSON parsing, needed because the parsing is platform-
+ // dependent.
+ using SuccessCallback = base::Callback<void(std::unique_ptr<base::Value>)>;
+ using ErrorCallback = base::Callback<void(const std::string&)>;
+ using ParseJSONCallback = base::Callback<
+ void(const std::string&, const SuccessCallback&, const ErrorCallback&)>;
+
+ struct FetchedCategory {
+ Category category;
+ base::string16 localized_title; // Ignored for non-server categories.
+ NTPSnippet::PtrVector snippets;
+
+ explicit FetchedCategory(Category c);
+ FetchedCategory(FetchedCategory&&); // = default, in .cc
+ ~FetchedCategory(); // = default, in .cc
+ FetchedCategory& operator=(FetchedCategory&&); // = default, in .cc
+ };
+ using FetchedCategoriesVector = std::vector<FetchedCategory>;
+ using OptionalFetchedCategories = base::Optional<FetchedCategoriesVector>;
+
+ // |snippets| contains parsed snippets if a fetch succeeded. If problems
+ // occur, |snippets| contains no value (no actual vector in base::Optional).
+ // Error details can be retrieved using last_status().
+ using SnippetsAvailableCallback =
+ base::Callback<void(OptionalFetchedCategories fetched_categories)>;
+
+ // Enumeration listing all possible outcomes for fetch attempts. Used for UMA
+ // histograms, so do not change existing values. Insert new values at the end,
+ // and update the histogram definition.
+ enum class FetchResult {
+ SUCCESS,
+ DEPRECATED_EMPTY_HOSTS,
+ URL_REQUEST_STATUS_ERROR,
+ HTTP_ERROR,
+ JSON_PARSE_ERROR,
+ INVALID_SNIPPET_CONTENT_ERROR,
+ OAUTH_TOKEN_ERROR,
+ INTERACTIVE_QUOTA_ERROR,
+ NON_INTERACTIVE_QUOTA_ERROR,
+ RESULT_MAX
+ };
+
+ // Enumeration listing all possible variants of dealing with personalization.
+ enum class Personalization {
+ kPersonal,
+ kNonPersonal,
+ kBoth
+ };
+
+ NTPSnippetsFetcher(
+ SigninManagerBase* signin_manager,
+ OAuth2TokenService* token_service,
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
+ PrefService* pref_service,
+ CategoryFactory* category_factory,
+ const ParseJSONCallback& parse_json_callback,
+ const std::string& api_key);
+ ~NTPSnippetsFetcher() override;
+
+ // Set a callback that is called when a new set of snippets are downloaded,
+ // overriding any previously set callback.
+ void SetCallback(const SnippetsAvailableCallback& callback);
+
+ // Fetches snippets from the server. |hosts| restricts the results to a set of
+ // hosts, e.g. "www.google.com". If |hosts| is empty, no host restrictions are
+ // applied.
+ //
+ // |excluded_ids| will be reported to the server; the server should not return
+ // suggestions with those IDs.
+ //
+ // If an ongoing fetch exists, it will be cancelled and a new one started,
+ // without triggering an additional callback (i.e. not noticeable by
+ // subscriber of SetCallback()).
+ //
+ // Fetches snippets only if the daily quota not exceeded, unless
+ // |interactive_request| is set to true (use only for user-initiated fetches).
+ void FetchSnippetsFromHosts(const std::set<std::string>& hosts,
+ const std::string& language_code,
+ const std::set<std::string>& excluded_ids,
+ int count,
+ bool interactive_request);
+
+ // Debug string representing the status/result of the last fetch attempt.
+ const std::string& last_status() const { return last_status_; }
+
+ // Returns the last JSON fetched from the server.
+ const std::string& last_json() const {
+ return last_fetch_json_;
+ }
+
+ // Returns the personalization setting of the fetcher.
+ Personalization personalization() const { return personalization_; }
+
+ // Returns the URL endpoint used by the fetcher.
+ GURL fetch_url() const { return fetch_url_; }
+
+ // Does the fetcher use authentication to get personalized results?
+ bool UsesAuthentication() const;
+
+ // Overrides internal clock for testing purposes.
+ void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock) {
+ tick_clock_ = std::move(tick_clock);
+ }
+
+ void SetPersonalizationForTesting(Personalization personalization) {
+ personalization_ = personalization;
+ }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(NTPSnippetsFetcherTest, BuildRequestAuthenticated);
+ FRIEND_TEST_ALL_PREFIXES(NTPSnippetsFetcherTest, BuildRequestUnauthenticated);
+ FRIEND_TEST_ALL_PREFIXES(NTPSnippetsFetcherTest, BuildRequestExcludedIds);
+
+ enum FetchAPI {
+ CHROME_READER_API,
+ CHROME_CONTENT_SUGGESTIONS_API,
+ };
+
+ struct RequestParams {
+ FetchAPI fetch_api;
+ std::string obfuscated_gaia_id;
+ bool only_return_personalized_results;
+ std::string user_locale;
+ std::set<std::string> host_restricts;
+ std::set<std::string> excluded_ids;
+ int count_to_fetch;
+ bool interactive_request;
+
+ RequestParams();
+ ~RequestParams();
+
+ std::string BuildRequest();
+ };
+
+ void FetchSnippetsImpl(const GURL& url,
+ const std::string& auth_header,
+ const std::string& request);
+ void FetchSnippetsNonAuthenticated();
+ void FetchSnippetsAuthenticated(const std::string& account_id,
+ const std::string& oauth_access_token);
+ void StartTokenRequest();
+
+ // OAuth2TokenService::Consumer overrides:
+ void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) override;
+ void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) override;
+
+ // OAuth2TokenService::Observer overrides:
+ void OnRefreshTokenAvailable(const std::string& account_id) override;
+
+ // URLFetcherDelegate implementation.
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+ bool JsonToSnippets(const base::Value& parsed,
+ FetchedCategoriesVector* categories);
+ void OnJsonParsed(std::unique_ptr<base::Value> parsed);
+ void OnJsonError(const std::string& error);
+ void FetchFinished(OptionalFetchedCategories fetched_categories,
+ FetchResult result,
+ const std::string& extra_message);
+
+ // Authorization for signed-in users.
+ SigninManagerBase* signin_manager_;
+ OAuth2TokenService* token_service_;
+ std::unique_ptr<OAuth2TokenService::Request> oauth_request_;
+ bool waiting_for_refresh_token_;
+
+ // Holds the URL request context.
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+
+ CategoryFactory* const category_factory_;
+ const ParseJSONCallback parse_json_callback_;
+ base::TimeTicks fetch_start_time_;
+ std::string last_status_;
+ std::string last_fetch_json_;
+
+ // Hosts to restrict the snippets to.
+ std::set<std::string> hosts_;
+
+ // Snippets to exclude from the results.
+ std::set<std::string> excluded_ids_;
+
+ // Count of snippets to fetch.
+ int count_to_fetch_;
+
+ // Language code to restrict to for personalized results.
+ std::string locale_;
+
+ // API endpoint for fetching snippets.
+ const GURL fetch_url_;
+ // Which API to use
+ const FetchAPI fetch_api_;
+
+ // The fetcher for downloading the snippets.
+ std::unique_ptr<net::URLFetcher> url_fetcher_;
+
+ // The callback to notify when new snippets get fetched.
+ SnippetsAvailableCallback snippets_available_callback_;
+
+ // API key to use for non-authenticated requests.
+ const std::string api_key_;
+
+ // The variant of the fetching to use, loaded from variation parameters.
+ Personalization personalization_;
+
+ // Is the request user initiated?
+ bool interactive_request_;
+
+ // Allow for an injectable tick clock for testing.
+ std::unique_ptr<base::TickClock> tick_clock_;
+
+ // Request throttler for limiting requests.
+ RequestThrottler request_throttler_;
+
+ // When a token request gets canceled, we want to retry once.
+ bool oauth_token_retried_;
+
+ base::WeakPtrFactory<NTPSnippetsFetcher> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(NTPSnippetsFetcher);
+};
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_FETCHER_H_
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_fetcher_unittest.cc b/chromium/components/ntp_snippets/remote/ntp_snippets_fetcher_unittest.cc
new file mode 100644
index 00000000000..daf478dc81f
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_fetcher_unittest.cc
@@ -0,0 +1,781 @@
+// 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 "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
+
+#include <map>
+#include <utility>
+
+#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/ntp_snippets_constants.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/signin/core/browser/test_signin_client.h"
+#include "components/variations/entropy_provider.h"
+#include "components/variations/variations_associated_data.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ntp_snippets {
+
+namespace {
+
+using testing::_;
+using testing::ElementsAre;
+using testing::Eq;
+using testing::IsEmpty;
+using testing::Not;
+using testing::NotNull;
+using testing::PrintToString;
+using testing::StartsWith;
+using testing::WithArg;
+
+const char kAPIKey[] = "fakeAPIkey";
+const char kTestChromeReaderUrl[] =
+ "https://chromereader-pa.googleapis.com/v1/fetch?key=fakeAPIkey";
+const char kTestChromeContentSuggestionsUrl[] =
+ "https://chromecontentsuggestions-pa.googleapis.com/v1/suggestions/"
+ "fetch?key=fakeAPIkey";
+
+// Artificial time delay for JSON parsing.
+const int64_t kTestJsonParsingLatencyMs = 20;
+
+ACTION_P(MovePointeeTo, ptr) {
+ *ptr = std::move(*arg0);
+}
+
+MATCHER(HasValue, "") {
+ return static_cast<bool>(*arg);
+}
+
+MATCHER(IsEmptyArticleList, "is an empty list of articles") {
+ NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories = *arg;
+ return fetched_categories && fetched_categories->size() == 1 &&
+ fetched_categories->begin()->snippets.empty();
+}
+
+MATCHER_P(IsSingleArticle, url, "is a list with the single article %(url)s") {
+ NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories = *arg;
+ return fetched_categories && fetched_categories->size() == 1 &&
+ fetched_categories->begin()->snippets.size() == 1 &&
+ fetched_categories->begin()->snippets[0]->best_source().url.spec() ==
+ url;
+}
+
+MATCHER_P(EqualsJSON, json, "equals JSON") {
+ std::unique_ptr<base::Value> expected = base::JSONReader::Read(json);
+ if (!expected) {
+ *result_listener << "INTERNAL ERROR: couldn't parse expected JSON";
+ return false;
+ }
+
+ std::string err_msg;
+ int err_line, err_col;
+ std::unique_ptr<base::Value> actual = base::JSONReader::ReadAndReturnError(
+ arg, base::JSON_PARSE_RFC, nullptr, &err_msg, &err_line, &err_col);
+ if (!actual) {
+ *result_listener << "input:" << err_line << ":" << err_col << ": "
+ << "parse error: " << err_msg;
+ return false;
+ }
+ return base::Value::Equals(actual.get(), expected.get());
+}
+
+class MockSnippetsAvailableCallback {
+ public:
+ // Workaround for gMock's lack of support for movable arguments.
+ void WrappedRun(
+ NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) {
+ Run(&fetched_categories);
+ }
+
+ MOCK_METHOD1(
+ Run,
+ void(NTPSnippetsFetcher::OptionalFetchedCategories* fetched_categories));
+};
+
+// Factory for FakeURLFetcher objects that always generate errors.
+class FailingFakeURLFetcherFactory : public net::URLFetcherFactory {
+ public:
+ std::unique_ptr<net::URLFetcher> CreateURLFetcher(
+ int id, const GURL& url, net::URLFetcher::RequestType request_type,
+ net::URLFetcherDelegate* d) override {
+ return base::MakeUnique<net::FakeURLFetcher>(
+ url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND,
+ net::URLRequestStatus::FAILED);
+ }
+};
+
+void ParseJson(
+ const std::string& json,
+ const ntp_snippets::NTPSnippetsFetcher::SuccessCallback& success_callback,
+ const ntp_snippets::NTPSnippetsFetcher::ErrorCallback& error_callback) {
+ base::JSONReader json_reader;
+ std::unique_ptr<base::Value> value = json_reader.ReadToValue(json);
+ if (value)
+ success_callback.Run(std::move(value));
+ else
+ error_callback.Run(json_reader.GetErrorMessage());
+}
+
+void ParseJsonDelayed(
+ const std::string& json,
+ const ntp_snippets::NTPSnippetsFetcher::SuccessCallback& success_callback,
+ const ntp_snippets::NTPSnippetsFetcher::ErrorCallback& error_callback) {
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&ParseJson, json, success_callback, error_callback),
+ base::TimeDelta::FromMilliseconds(kTestJsonParsingLatencyMs));
+}
+
+} // namespace
+
+class NTPSnippetsFetcherTest : public testing::Test {
+ public:
+ NTPSnippetsFetcherTest()
+ : NTPSnippetsFetcherTest(GURL(kTestChromeReaderUrl),
+ std::map<std::string, std::string>()) {}
+
+ NTPSnippetsFetcherTest(const GURL& gurl,
+ const std::map<std::string, std::string>& params)
+ : params_manager_(ntp_snippets::kStudyName, params),
+ mock_task_runner_(new base::TestMockTimeTaskRunner()),
+ mock_task_runner_handle_(mock_task_runner_),
+ signin_client_(new TestSigninClient(nullptr)),
+ account_tracker_(new AccountTrackerService()),
+ fake_signin_manager_(new FakeSigninManagerBase(signin_client_.get(),
+ account_tracker_.get())),
+ fake_token_service_(new FakeProfileOAuth2TokenService()),
+ pref_service_(new TestingPrefServiceSimple()),
+ test_lang_("en-US"),
+ test_url_(gurl) {
+ RequestThrottler::RegisterProfilePrefs(pref_service_->registry());
+
+ snippets_fetcher_ = base::MakeUnique<NTPSnippetsFetcher>(
+ fake_signin_manager_.get(), fake_token_service_.get(),
+ scoped_refptr<net::TestURLRequestContextGetter>(
+ new net::TestURLRequestContextGetter(mock_task_runner_.get())),
+ pref_service_.get(), &category_factory_, base::Bind(&ParseJsonDelayed),
+ kAPIKey);
+
+ snippets_fetcher_->SetCallback(
+ base::Bind(&MockSnippetsAvailableCallback::WrappedRun,
+ base::Unretained(&mock_callback_)));
+ snippets_fetcher_->SetTickClockForTesting(
+ mock_task_runner_->GetMockTickClock());
+ test_excluded_.insert("1234567890");
+ // Increase initial time such that ticks are non-zero.
+ mock_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(1234));
+ }
+
+ NTPSnippetsFetcher& snippets_fetcher() { return *snippets_fetcher_; }
+ MockSnippetsAvailableCallback& mock_callback() { return mock_callback_; }
+ void FastForwardUntilNoTasksRemain() {
+ mock_task_runner_->FastForwardUntilNoTasksRemain();
+ }
+ const std::string& test_lang() const { return test_lang_; }
+ const GURL& test_url() { return test_url_; }
+ const std::set<std::string>& test_hosts() const { return test_hosts_; }
+ const std::set<std::string>& test_excluded() const { return test_excluded_; }
+ base::HistogramTester& histogram_tester() { return histogram_tester_; }
+
+ void InitFakeURLFetcherFactory() {
+ if (fake_url_fetcher_factory_)
+ return;
+ // Instantiation of factory automatically sets itself as URLFetcher's
+ // factory.
+ fake_url_fetcher_factory_.reset(new net::FakeURLFetcherFactory(
+ /*default_factory=*/&failing_url_fetcher_factory_));
+ }
+
+ void SetFakeResponse(const std::string& response_data,
+ net::HttpStatusCode response_code,
+ net::URLRequestStatus::Status status) {
+ InitFakeURLFetcherFactory();
+ fake_url_fetcher_factory_->SetFakeResponse(test_url_, response_data,
+ response_code, status);
+ }
+
+ private:
+ variations::testing::VariationParamsManager params_manager_;
+ scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_;
+ base::ThreadTaskRunnerHandle mock_task_runner_handle_;
+ FailingFakeURLFetcherFactory failing_url_fetcher_factory_;
+ // Initialized lazily in SetFakeResponse().
+ std::unique_ptr<net::FakeURLFetcherFactory> fake_url_fetcher_factory_;
+ std::unique_ptr<TestSigninClient> signin_client_;
+ std::unique_ptr<AccountTrackerService> account_tracker_;
+ std::unique_ptr<SigninManagerBase> fake_signin_manager_;
+ std::unique_ptr<OAuth2TokenService> fake_token_service_;
+ std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher_;
+ std::unique_ptr<TestingPrefServiceSimple> pref_service_;
+ CategoryFactory category_factory_;
+ MockSnippetsAvailableCallback mock_callback_;
+ const std::string test_lang_;
+ const GURL test_url_;
+ std::set<std::string> test_hosts_;
+ std::set<std::string> test_excluded_;
+ base::HistogramTester histogram_tester_;
+
+ DISALLOW_COPY_AND_ASSIGN(NTPSnippetsFetcherTest);
+};
+
+class NTPSnippetsContentSuggestionsFetcherTest : public NTPSnippetsFetcherTest {
+ public:
+ NTPSnippetsContentSuggestionsFetcherTest()
+ : NTPSnippetsFetcherTest(
+ GURL(kTestChromeContentSuggestionsUrl),
+ {{"content_suggestions_backend", kContentSuggestionsServer}}) {}
+};
+
+TEST_F(NTPSnippetsFetcherTest, BuildRequestAuthenticated) {
+ NTPSnippetsFetcher::RequestParams params;
+ params.obfuscated_gaia_id = "0BFUSGAIA";
+ params.only_return_personalized_results = true;
+ params.user_locale = "en";
+ params.host_restricts = {"chromium.org"};
+ params.excluded_ids = {"1234567890"};
+ params.count_to_fetch = 25;
+ params.interactive_request = false;
+
+ params.fetch_api = NTPSnippetsFetcher::CHROME_READER_API;
+ EXPECT_THAT(params.BuildRequest(),
+ EqualsJSON("{"
+ " \"response_detail_level\": \"STANDARD\","
+ " \"obfuscated_gaia_id\": \"0BFUSGAIA\","
+ " \"user_locale\": \"en\","
+ " \"advanced_options\": {"
+ " \"local_scoring_params\": {"
+ " \"content_params\": {"
+ " \"only_return_personalized_results\": true"
+ " },"
+ " \"content_restricts\": ["
+ " {"
+ " \"type\": \"METADATA\","
+ " \"value\": \"TITLE\""
+ " },"
+ " {"
+ " \"type\": \"METADATA\","
+ " \"value\": \"SNIPPET\""
+ " },"
+ " {"
+ " \"type\": \"METADATA\","
+ " \"value\": \"THUMBNAIL\""
+ " }"
+ " ],"
+ " \"content_selectors\": ["
+ " {"
+ " \"type\": \"HOST_RESTRICT\","
+ " \"value\": \"chromium.org\""
+ " }"
+ " ]"
+ " },"
+ " \"global_scoring_params\": {"
+ " \"num_to_return\": 25,"
+ " \"sort_type\": 1"
+ " }"
+ " }"
+ "}"));
+
+ params.fetch_api = NTPSnippetsFetcher::CHROME_CONTENT_SUGGESTIONS_API;
+ EXPECT_THAT(params.BuildRequest(),
+ EqualsJSON("{"
+ " \"uiLanguage\": \"en\","
+ " \"priority\": \"BACKGROUND_PREFETCH\","
+ " \"regularlyVisitedHostNames\": ["
+ " \"chromium.org\""
+ " ],"
+ " \"excludedSuggestionIds\": ["
+ " \"1234567890\""
+ " ]"
+ "}"));
+}
+
+TEST_F(NTPSnippetsFetcherTest, BuildRequestUnauthenticated) {
+ NTPSnippetsFetcher::RequestParams params;
+ params.only_return_personalized_results = false;
+ params.host_restricts = {};
+ params.count_to_fetch = 10;
+ params.excluded_ids = {};
+ params.interactive_request = true;
+
+
+ params.fetch_api = NTPSnippetsFetcher::CHROME_READER_API;
+ EXPECT_THAT(params.BuildRequest(),
+ EqualsJSON("{"
+ " \"response_detail_level\": \"STANDARD\","
+ " \"advanced_options\": {"
+ " \"local_scoring_params\": {"
+ " \"content_params\": {"
+ " \"only_return_personalized_results\": false"
+ " },"
+ " \"content_restricts\": ["
+ " {"
+ " \"type\": \"METADATA\","
+ " \"value\": \"TITLE\""
+ " },"
+ " {"
+ " \"type\": \"METADATA\","
+ " \"value\": \"SNIPPET\""
+ " },"
+ " {"
+ " \"type\": \"METADATA\","
+ " \"value\": \"THUMBNAIL\""
+ " }"
+ " ],"
+ " \"content_selectors\": []"
+ " },"
+ " \"global_scoring_params\": {"
+ " \"num_to_return\": 10,"
+ " \"sort_type\": 1"
+ " }"
+ " }"
+ "}"));
+
+ params.fetch_api = NTPSnippetsFetcher::CHROME_CONTENT_SUGGESTIONS_API;
+ EXPECT_THAT(params.BuildRequest(),
+ EqualsJSON("{"
+ " \"regularlyVisitedHostNames\": [],"
+ " \"priority\": \"USER_ACTION\","
+ " \"excludedSuggestionIds\": []"
+ "}"));
+}
+
+TEST_F(NTPSnippetsFetcherTest, BuildRequestExcludedIds) {
+ NTPSnippetsFetcher::RequestParams params;
+ params.only_return_personalized_results = false;
+ params.host_restricts = {};
+ params.count_to_fetch = 10;
+ params.interactive_request = false;
+ for (int i = 0; i < 200; ++i) {
+ params.excluded_ids.insert(base::StringPrintf("%03d", i));
+ }
+
+ params.fetch_api = NTPSnippetsFetcher::CHROME_CONTENT_SUGGESTIONS_API;
+ EXPECT_THAT(params.BuildRequest(),
+ EqualsJSON("{"
+ " \"regularlyVisitedHostNames\": [],"
+ " \"priority\": \"BACKGROUND_PREFETCH\","
+ " \"excludedSuggestionIds\": ["
+ " \"000\", \"001\", \"002\", \"003\", \"004\","
+ " \"005\", \"006\", \"007\", \"008\", \"009\","
+ " \"010\", \"011\", \"012\", \"013\", \"014\","
+ " \"015\", \"016\", \"017\", \"018\", \"019\","
+ " \"020\", \"021\", \"022\", \"023\", \"024\","
+ " \"025\", \"026\", \"027\", \"028\", \"029\","
+ " \"030\", \"031\", \"032\", \"033\", \"034\","
+ " \"035\", \"036\", \"037\", \"038\", \"039\","
+ " \"040\", \"041\", \"042\", \"043\", \"044\","
+ " \"045\", \"046\", \"047\", \"048\", \"049\","
+ " \"050\", \"051\", \"052\", \"053\", \"054\","
+ " \"055\", \"056\", \"057\", \"058\", \"059\","
+ " \"060\", \"061\", \"062\", \"063\", \"064\","
+ " \"065\", \"066\", \"067\", \"068\", \"069\","
+ " \"070\", \"071\", \"072\", \"073\", \"074\","
+ " \"075\", \"076\", \"077\", \"078\", \"079\","
+ " \"080\", \"081\", \"082\", \"083\", \"084\","
+ " \"085\", \"086\", \"087\", \"088\", \"089\","
+ " \"090\", \"091\", \"092\", \"093\", \"094\","
+ " \"095\", \"096\", \"097\", \"098\", \"099\""
+ // Truncated to 100 entries. Currently, they happen to
+ // be those lexically first.
+ " ]"
+ "}"));
+}
+
+TEST_F(NTPSnippetsFetcherTest, ShouldNotFetchOnCreation) {
+ // The lack of registered baked in responses would cause any fetch to fail.
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ IsEmpty());
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ IsEmpty());
+ EXPECT_THAT(snippets_fetcher().last_status(), IsEmpty());
+}
+
+TEST_F(NTPSnippetsFetcherTest, ShouldFetchSuccessfully) {
+ const std::string kJsonStr =
+ "{\"recos\": [{"
+ " \"contentInfo\": {"
+ " \"url\" : \"http://localhost/foobar\","
+ " \"sourceCorpusInfo\" : [{"
+ " \"ampUrl\" : \"http://localhost/amp\","
+ " \"corpusId\" : \"http://localhost/foobar\","
+ " \"publisherData\": { \"sourceName\" : \"Foo News\" }"
+ " }]"
+ " }"
+ "}]}";
+ SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_callback(), Run(IsSingleArticle("http://localhost/foobar")));
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK"));
+ EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
+ /*count=*/1)));
+}
+
+TEST_F(NTPSnippetsContentSuggestionsFetcherTest, ShouldFetchSuccessfully) {
+ const std::string kJsonStr =
+ "{\"categories\" : [{"
+ " \"id\": 1,"
+ " \"localizedTitle\": \"Articles for You\","
+ " \"suggestions\" : [{"
+ " \"ids\" : [\"http://localhost/foobar\"],"
+ " \"title\" : \"Foo Barred from Baz\","
+ " \"snippet\" : \"...\","
+ " \"fullPageUrl\" : \"http://localhost/foobar\","
+ " \"creationTime\" : \"2016-06-30T11:01:37.000Z\","
+ " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\","
+ " \"attribution\" : \"Foo News\","
+ " \"imageUrl\" : \"http://localhost/foobar.jpg\","
+ " \"ampUrl\" : \"http://localhost/amp\","
+ " \"faviconUrl\" : \"http://localhost/favicon.ico\" "
+ " }]"
+ "}]}";
+ SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_callback(), Run(IsSingleArticle("http://localhost/foobar")));
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK"));
+ EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
+ /*count=*/1)));
+}
+
+TEST_F(NTPSnippetsContentSuggestionsFetcherTest, EmptyCategoryIsOK) {
+ const std::string kJsonStr =
+ "{\"categories\" : [{"
+ " \"id\": 1,"
+ " \"localizedTitle\": \"Articles for You\""
+ "}]}";
+ SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_callback(), Run(IsEmptyArticleList()));
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK"));
+ EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
+ /*count=*/1)));
+}
+
+TEST_F(NTPSnippetsContentSuggestionsFetcherTest, ServerCategories) {
+ const std::string kJsonStr =
+ "{\"categories\" : [{"
+ " \"id\": 1,"
+ " \"localizedTitle\": \"Articles for You\","
+ " \"suggestions\" : [{"
+ " \"ids\" : [\"http://localhost/foobar\"],"
+ " \"title\" : \"Foo Barred from Baz\","
+ " \"snippet\" : \"...\","
+ " \"fullPageUrl\" : \"http://localhost/foobar\","
+ " \"creationTime\" : \"2016-06-30T11:01:37.000Z\","
+ " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\","
+ " \"attribution\" : \"Foo News\","
+ " \"imageUrl\" : \"http://localhost/foobar.jpg\","
+ " \"ampUrl\" : \"http://localhost/amp\","
+ " \"faviconUrl\" : \"http://localhost/favicon.ico\" "
+ " }]"
+ "}, {"
+ " \"id\": 2,"
+ " \"localizedTitle\": \"Articles for Me\","
+ " \"suggestions\" : [{"
+ " \"ids\" : [\"http://localhost/foo2\"],"
+ " \"title\" : \"Foo Barred from Baz\","
+ " \"snippet\" : \"...\","
+ " \"fullPageUrl\" : \"http://localhost/foo2\","
+ " \"creationTime\" : \"2016-06-30T11:01:37.000Z\","
+ " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\","
+ " \"attribution\" : \"Foo News\","
+ " \"imageUrl\" : \"http://localhost/foo2.jpg\","
+ " \"ampUrl\" : \"http://localhost/amp\","
+ " \"faviconUrl\" : \"http://localhost/favicon.ico\" "
+ " }]"
+ "}]}";
+ SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories;
+ EXPECT_CALL(mock_callback(), Run(_))
+ .WillOnce(WithArg<0>(MovePointeeTo(&fetched_categories)));
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+
+ ASSERT_TRUE(fetched_categories);
+ ASSERT_THAT(fetched_categories->size(), Eq(2u));
+ for (const auto& category : *fetched_categories) {
+ const auto& articles = category.snippets;
+ switch (category.category.id()) {
+ case static_cast<int>(KnownCategories::ARTICLES):
+ ASSERT_THAT(articles.size(), Eq(1u));
+ EXPECT_THAT(articles[0]->best_source().url.spec(),
+ Eq("http://localhost/foobar"));
+ break;
+ case static_cast<int>(KnownCategories::ARTICLES) + 1:
+ ASSERT_THAT(articles.size(), Eq(1u));
+ EXPECT_THAT(articles[0]->best_source().url.spec(),
+ Eq("http://localhost/foo2"));
+ break;
+ default:
+ FAIL() << "unknown category ID " << category.category.id();
+ }
+ }
+
+ EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK"));
+ EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
+ /*count=*/1)));
+}
+
+TEST_F(NTPSnippetsFetcherTest, ShouldFetchSuccessfullyEmptyList) {
+ const std::string kJsonStr = "{\"recos\": []}";
+ SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_callback(), Run(IsEmptyArticleList()));
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(snippets_fetcher().last_status(), Eq("OK"));
+ EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
+ EXPECT_THAT(
+ histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
+}
+
+TEST_F(NTPSnippetsFetcherTest, ShouldRestrictToHosts) {
+ net::TestURLFetcherFactory test_url_fetcher_factory;
+ snippets_fetcher().FetchSnippetsFromHosts(
+ {"www.somehost1.com", "www.somehost2.com"}, test_lang(), test_excluded(),
+ /*count=*/17,
+ /*interactive_request=*/true);
+ net::TestURLFetcher* fetcher = test_url_fetcher_factory.GetFetcherByID(0);
+ ASSERT_THAT(fetcher, NotNull());
+ std::unique_ptr<base::Value> value =
+ base::JSONReader::Read(fetcher->upload_data());
+ ASSERT_TRUE(value) << " failed to parse JSON: "
+ << PrintToString(fetcher->upload_data());
+ const base::DictionaryValue* dict = nullptr;
+ ASSERT_TRUE(value->GetAsDictionary(&dict));
+ const base::DictionaryValue* local_scoring_params = nullptr;
+ ASSERT_TRUE(dict->GetDictionary("advanced_options.local_scoring_params",
+ &local_scoring_params));
+ const base::ListValue* content_selectors = nullptr;
+ ASSERT_TRUE(
+ local_scoring_params->GetList("content_selectors", &content_selectors));
+ ASSERT_THAT(content_selectors->GetSize(), Eq(static_cast<size_t>(2)));
+ const base::DictionaryValue* content_selector = nullptr;
+ ASSERT_TRUE(content_selectors->GetDictionary(0, &content_selector));
+ std::string content_selector_value;
+ EXPECT_TRUE(content_selector->GetString("value", &content_selector_value));
+ EXPECT_THAT(content_selector_value, Eq("www.somehost1.com"));
+ ASSERT_TRUE(content_selectors->GetDictionary(1, &content_selector));
+ EXPECT_TRUE(content_selector->GetString("value", &content_selector_value));
+ EXPECT_THAT(content_selector_value, Eq("www.somehost2.com"));
+}
+
+TEST_F(NTPSnippetsFetcherTest, ShouldReportUrlStatusError) {
+ SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND,
+ net::URLRequestStatus::FAILED);
+ EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(snippets_fetcher().last_status(),
+ Eq("URLRequestStatus error -2"));
+ EXPECT_THAT(snippets_fetcher().last_json(), IsEmpty());
+ EXPECT_THAT(
+ histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
+ ElementsAre(base::Bucket(/*min=*/2, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/-2, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ Not(IsEmpty()));
+}
+
+TEST_F(NTPSnippetsFetcherTest, ShouldReportHttpError) {
+ SetFakeResponse(/*response_data=*/std::string(), net::HTTP_NOT_FOUND,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(snippets_fetcher().last_json(), IsEmpty());
+ EXPECT_THAT(
+ histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
+ ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/404, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ Not(IsEmpty()));
+}
+
+TEST_F(NTPSnippetsFetcherTest, ShouldReportJsonError) {
+ const std::string kInvalidJsonStr = "{ \"recos\": []";
+ SetFakeResponse(/*response_data=*/kInvalidJsonStr, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(snippets_fetcher().last_status(),
+ StartsWith("Received invalid JSON (error "));
+ EXPECT_THAT(snippets_fetcher().last_json(), Eq(kInvalidJsonStr));
+ EXPECT_THAT(
+ histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
+ ElementsAre(base::Bucket(/*min=*/4, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
+ /*count=*/1)));
+}
+
+TEST_F(NTPSnippetsFetcherTest, ShouldReportJsonErrorForEmptyResponse) {
+ SetFakeResponse(/*response_data=*/std::string(), net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(snippets_fetcher().last_json(), std::string());
+ EXPECT_THAT(
+ histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
+ ElementsAre(base::Bucket(/*min=*/4, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
+}
+
+TEST_F(NTPSnippetsFetcherTest, ShouldReportInvalidListError) {
+ const std::string kJsonStr =
+ "{\"recos\": [{ \"contentInfo\": { \"foo\" : \"bar\" }}]}";
+ SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(snippets_fetcher().last_json(), Eq(kJsonStr));
+ EXPECT_THAT(
+ histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
+ ElementsAre(base::Bucket(/*min=*/5, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ Not(IsEmpty()));
+}
+
+// This test actually verifies that the test setup itself is sane, to prevent
+// hard-to-reproduce test failures.
+TEST_F(NTPSnippetsFetcherTest, ShouldReportHttpErrorForMissingBakedResponse) {
+ InitFakeURLFetcherFactory();
+ EXPECT_CALL(mock_callback(), Run(/*snippets=*/Not(HasValue()))).Times(1);
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+}
+
+TEST_F(NTPSnippetsFetcherTest, ShouldCancelOngoingFetch) {
+ const std::string kJsonStr = "{ \"recos\": [] }";
+ SetFakeResponse(/*response_data=*/kJsonStr, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ EXPECT_CALL(mock_callback(), Run(IsEmptyArticleList()));
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ // Second call to FetchSnippetsFromHosts() overrides/cancels the previous.
+ // Callback is expected to be called once.
+ snippets_fetcher().FetchSnippetsFromHosts(test_hosts(), test_lang(),
+ test_excluded(),
+ /*count=*/1,
+ /*interactive_request=*/true);
+ FastForwardUntilNoTasksRemain();
+ EXPECT_THAT(
+ histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples(
+ "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"),
+ ElementsAre(base::Bucket(/*min=*/200, /*count=*/1)));
+ EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"),
+ ElementsAre(base::Bucket(/*min=*/kTestJsonParsingLatencyMs,
+ /*count=*/1)));
+}
+
+::std::ostream& operator<<(
+ ::std::ostream& os,
+ const NTPSnippetsFetcher::OptionalFetchedCategories& fetched_categories) {
+ if (fetched_categories) {
+ // Matchers above aren't any more precise than this, so this is sufficient
+ // for test-failure diagnostics.
+ return os << "list with " << fetched_categories->size() << " elements";
+ }
+ return os << "null";
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_scheduler.h b/chromium/components/ntp_snippets/remote/ntp_snippets_scheduler.h
new file mode 100644
index 00000000000..7a4fc1ef5c9
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_scheduler.h
@@ -0,0 +1,36 @@
+// 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 COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SCHEDULER_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SCHEDULER_H_
+
+#include "base/macros.h"
+#include "base/time/time.h"
+
+namespace ntp_snippets {
+
+// Interface to schedule the periodic fetching of snippets.
+class NTPSnippetsScheduler {
+ public:
+ // Schedule periodic fetching of snippets, with different periods depending on
+ // network state. The concrete implementation should call
+ // NTPSnippetsService::FetchSnippets once per period.
+ // Any of the periods can be zero to indicate that the corresponding task
+ // should not be scheduled.
+ virtual bool Schedule(base::TimeDelta period_wifi,
+ base::TimeDelta period_fallback) = 0;
+
+ // Cancel any scheduled tasks.
+ virtual bool Unschedule() = 0;
+
+ protected:
+ NTPSnippetsScheduler() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NTPSnippetsScheduler);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SCHEDULER_H_
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_service.cc b/chromium/components/ntp_snippets/remote/ntp_snippets_service.cc
new file mode 100644
index 00000000000..165790bc607
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_service.cc
@@ -0,0 +1,1121 @@
+// 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 "components/ntp_snippets/remote/ntp_snippets_service.h"
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task_runner_util.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/image_fetcher/image_decoder.h"
+#include "components/image_fetcher/image_fetcher.h"
+#include "components/ntp_snippets/features.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/ntp_snippets/remote/ntp_snippets_database.h"
+#include "components/ntp_snippets/switches.h"
+#include "components/ntp_snippets/user_classifier.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/variations/variations_associated_data.h"
+#include "grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/image/image.h"
+
+namespace ntp_snippets {
+
+namespace {
+
+// Number of snippets requested to the server. Consider replacing sparse UMA
+// histograms with COUNTS() if this number increases beyond 50.
+const int kMaxSnippetCount = 10;
+
+// Number of archived snippets we keep around in memory.
+const int kMaxArchivedSnippetCount = 200;
+
+// Default values for fetching intervals, fallback and wifi.
+const double kDefaultFetchingIntervalRareNtpUser[] = {48.0, 24.0};
+const double kDefaultFetchingIntervalActiveNtpUser[] = {24.0, 6.0};
+const double kDefaultFetchingIntervalActiveSuggestionsConsumer[] = {24.0, 6.0};
+
+// Variation parameters than can override the default fetching intervals.
+const char* kFetchingIntervalParamNameRareNtpUser[] = {
+ "fetching_interval_hours-fallback-rare_ntp_user",
+ "fetching_interval_hours-wifi-rare_ntp_user"};
+const char* kFetchingIntervalParamNameActiveNtpUser[] = {
+ "fetching_interval_hours-fallback-active_ntp_user",
+ "fetching_interval_hours-wifi-active_ntp_user"};
+const char* kFetchingIntervalParamNameActiveSuggestionsConsumer[] = {
+ "fetching_interval_hours-fallback-active_suggestions_consumer",
+ "fetching_interval_hours-wifi-active_suggestions_consumer"};
+
+const int kDefaultExpiryTimeMins = 3 * 24 * 60;
+
+// Keys for storing CategoryContent info in prefs.
+const char kCategoryContentId[] = "id";
+const char kCategoryContentTitle[] = "title";
+const char kCategoryContentProvidedByServer[] = "provided_by_server";
+
+base::TimeDelta GetFetchingInterval(bool is_wifi,
+ UserClassifier::UserClass user_class) {
+ double value_hours = 0.0;
+
+ const int index = is_wifi ? 1 : 0;
+ const char* param_name = "";
+ switch (user_class) {
+ case UserClassifier::UserClass::RARE_NTP_USER:
+ value_hours = kDefaultFetchingIntervalRareNtpUser[index];
+ param_name = kFetchingIntervalParamNameRareNtpUser[index];
+ break;
+ case UserClassifier::UserClass::ACTIVE_NTP_USER:
+ value_hours = kDefaultFetchingIntervalActiveNtpUser[index];
+ param_name = kFetchingIntervalParamNameActiveNtpUser[index];
+ break;
+ case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER:
+ value_hours = kDefaultFetchingIntervalActiveSuggestionsConsumer[index];
+ param_name = kFetchingIntervalParamNameActiveSuggestionsConsumer[index];
+ break;
+ }
+
+ // The default value can be overridden by a variation parameter.
+ std::string param_value_str = variations::GetVariationParamValueByFeature(
+ ntp_snippets::kArticleSuggestionsFeature, param_name);
+ if (!param_value_str.empty()) {
+ double param_value_hours = 0.0;
+ if (base::StringToDouble(param_value_str, &param_value_hours))
+ value_hours = param_value_hours;
+ else
+ LOG(WARNING) << "Invalid value for variation parameter " << param_name;
+ }
+
+ return base::TimeDelta::FromSecondsD(value_hours * 3600.0);
+}
+
+std::set<std::string> GetAllIDs(const NTPSnippet::PtrVector& snippets) {
+ std::set<std::string> ids;
+ for (const std::unique_ptr<NTPSnippet>& snippet : snippets) {
+ ids.insert(snippet->id());
+ for (const SnippetSource& source : snippet->sources())
+ ids.insert(source.url.spec());
+ }
+ return ids;
+}
+
+std::set<std::string> GetSnippetIDSet(const NTPSnippet::PtrVector& snippets) {
+ std::set<std::string> ids;
+ for (const std::unique_ptr<NTPSnippet>& snippet : snippets)
+ ids.insert(snippet->id());
+ return ids;
+}
+
+std::unique_ptr<std::vector<std::string>> GetSnippetIDVector(
+ const NTPSnippet::PtrVector& snippets) {
+ auto result = base::MakeUnique<std::vector<std::string>>();
+ for (const auto& snippet : snippets) {
+ result->push_back(snippet->id());
+ }
+ return result;
+}
+
+bool IsSnippetInSet(const std::unique_ptr<NTPSnippet>& snippet,
+ const std::set<std::string>& ids,
+ bool match_all_ids) {
+ if (ids.count(snippet->id()))
+ return true;
+ if (!match_all_ids)
+ return false;
+ for (const SnippetSource& source : snippet->sources()) {
+ if (ids.count(source.url.spec()))
+ return true;
+ }
+ return false;
+}
+
+void EraseMatchingSnippets(NTPSnippet::PtrVector* snippets,
+ const std::set<std::string>& matching_ids,
+ bool match_all_ids) {
+ snippets->erase(
+ std::remove_if(snippets->begin(), snippets->end(),
+ [&matching_ids, match_all_ids](
+ const std::unique_ptr<NTPSnippet>& snippet) {
+ return IsSnippetInSet(snippet, matching_ids,
+ match_all_ids);
+ }),
+ snippets->end());
+}
+
+void Compact(NTPSnippet::PtrVector* snippets) {
+ snippets->erase(
+ std::remove_if(
+ snippets->begin(), snippets->end(),
+ [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }),
+ snippets->end());
+}
+
+} // namespace
+
+NTPSnippetsService::NTPSnippetsService(
+ Observer* observer,
+ CategoryFactory* category_factory,
+ PrefService* pref_service,
+ const std::string& application_language_code,
+ const UserClassifier* user_classifier,
+ NTPSnippetsScheduler* scheduler,
+ std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
+ std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
+ std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
+ std::unique_ptr<NTPSnippetsDatabase> database,
+ std::unique_ptr<NTPSnippetsStatusService> status_service)
+ : ContentSuggestionsProvider(observer, category_factory),
+ state_(State::NOT_INITED),
+ pref_service_(pref_service),
+ articles_category_(
+ category_factory->FromKnownCategory(KnownCategories::ARTICLES)),
+ application_language_code_(application_language_code),
+ user_classifier_(user_classifier),
+ scheduler_(scheduler),
+ snippets_fetcher_(std::move(snippets_fetcher)),
+ image_fetcher_(std::move(image_fetcher)),
+ image_decoder_(std::move(image_decoder)),
+ database_(std::move(database)),
+ snippets_status_service_(std::move(status_service)),
+ fetch_when_ready_(false),
+ nuke_when_initialized_(false),
+ thumbnail_requests_throttler_(
+ pref_service,
+ RequestThrottler::RequestType::CONTENT_SUGGESTION_THUMBNAIL) {
+ RestoreCategoriesFromPrefs();
+ // The articles category always exists. Add it if we didn't get it from prefs.
+ // TODO(treib): Rethink this.
+ if (!base::ContainsKey(categories_, articles_category_)) {
+ categories_[articles_category_] = CategoryContent();
+ categories_[articles_category_].localized_title =
+ l10n_util::GetStringUTF16(IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER);
+ }
+ // Tell the observer about all the categories.
+ for (const auto& entry : categories_) {
+ observer->OnCategoryStatusChanged(this, entry.first, entry.second.status);
+ }
+
+ if (database_->IsErrorState()) {
+ EnterState(State::ERROR_OCCURRED);
+ UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR);
+ return;
+ }
+
+ database_->SetErrorCallback(base::Bind(&NTPSnippetsService::OnDatabaseError,
+ base::Unretained(this)));
+
+ // We transition to other states while finalizing the initialization, when the
+ // database is done loading.
+ database_->LoadSnippets(base::Bind(&NTPSnippetsService::OnDatabaseLoaded,
+ base::Unretained(this)));
+}
+
+NTPSnippetsService::~NTPSnippetsService() = default;
+
+// static
+void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+ // TODO(treib): Add cleanup logic for prefs::kSnippetHosts, then remove it
+ // completely after M56.
+ registry->RegisterListPref(prefs::kSnippetHosts);
+ registry->RegisterListPref(prefs::kRemoteSuggestionCategories);
+ registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalWifi, 0);
+ registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalFallback,
+ 0);
+
+ NTPSnippetsStatusService::RegisterProfilePrefs(registry);
+}
+
+void NTPSnippetsService::FetchSnippets(bool interactive_request) {
+ if (ready())
+ FetchSnippetsFromHosts(std::set<std::string>(), interactive_request);
+ else
+ fetch_when_ready_ = true;
+}
+
+void NTPSnippetsService::FetchSnippetsFromHosts(
+ const std::set<std::string>& hosts,
+ bool interactive_request) {
+ if (!ready())
+ return;
+
+ // Empty categories are marked as loading; others are unchanged.
+ for (const auto& item : categories_) {
+ Category category = item.first;
+ const CategoryContent& content = item.second;
+ if (content.snippets.empty())
+ UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING);
+ }
+
+ std::set<std::string> excluded_ids;
+ for (const auto& item : categories_) {
+ const CategoryContent& content = item.second;
+ for (const auto& snippet : content.dismissed)
+ excluded_ids.insert(snippet->id());
+ }
+ snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_,
+ excluded_ids, kMaxSnippetCount,
+ interactive_request);
+}
+
+void NTPSnippetsService::RescheduleFetching(bool force) {
+ // The scheduler only exists on Android so far, it's null on other platforms.
+ if (!scheduler_)
+ return;
+
+ if (ready()) {
+ base::TimeDelta old_interval_wifi =
+ base::TimeDelta::FromInternalValue(pref_service_->GetInt64(
+ prefs::kSnippetBackgroundFetchingIntervalWifi));
+ base::TimeDelta old_interval_fallback =
+ base::TimeDelta::FromInternalValue(pref_service_->GetInt64(
+ prefs::kSnippetBackgroundFetchingIntervalFallback));
+ UserClassifier::UserClass user_class = user_classifier_->GetUserClass();
+ base::TimeDelta interval_wifi =
+ GetFetchingInterval(/*is_wifi=*/true, user_class);
+ base::TimeDelta interval_fallback =
+ GetFetchingInterval(/*is_wifi=*/false, user_class);
+ if (force || interval_wifi != old_interval_wifi ||
+ interval_fallback != old_interval_fallback) {
+ scheduler_->Schedule(interval_wifi, interval_fallback);
+ pref_service_->SetInt64(prefs::kSnippetBackgroundFetchingIntervalWifi,
+ interval_wifi.ToInternalValue());
+ pref_service_->SetInt64(
+ prefs::kSnippetBackgroundFetchingIntervalFallback,
+ interval_fallback.ToInternalValue());
+ }
+ } else {
+ // If we're NOT_INITED, we don't know whether to schedule or unschedule.
+ // If |force| is false, all is well: We'll reschedule on the next state
+ // change anyway. If it's true, then unschedule here, to make sure that the
+ // next reschedule actually happens.
+ if (state_ != State::NOT_INITED || force) {
+ scheduler_->Unschedule();
+ pref_service_->ClearPref(prefs::kSnippetBackgroundFetchingIntervalWifi);
+ pref_service_->ClearPref(
+ prefs::kSnippetBackgroundFetchingIntervalFallback);
+ }
+ }
+}
+
+CategoryStatus NTPSnippetsService::GetCategoryStatus(Category category) {
+ DCHECK(base::ContainsKey(categories_, category));
+ return categories_[category].status;
+}
+
+CategoryInfo NTPSnippetsService::GetCategoryInfo(Category category) {
+ DCHECK(base::ContainsKey(categories_, category));
+ const CategoryContent& content = categories_[category];
+ bool is_article = category == articles_category_;
+ return CategoryInfo(content.localized_title,
+ ContentSuggestionsCardLayout::FULL_CARD,
+ /*has_more_button=*/false,
+ /*show_if_empty=*/is_article);
+}
+
+void NTPSnippetsService::DismissSuggestion(
+ const ContentSuggestion::ID& suggestion_id) {
+ if (!ready())
+ return;
+
+ DCHECK(base::ContainsKey(categories_, suggestion_id.category()));
+
+ CategoryContent* content = &categories_[suggestion_id.category()];
+ auto it = std::find_if(
+ content->snippets.begin(), content->snippets.end(),
+ [&suggestion_id](const std::unique_ptr<NTPSnippet>& snippet) {
+ return snippet->id() == suggestion_id.id_within_category();
+ });
+ if (it == content->snippets.end())
+ return;
+
+ (*it)->set_dismissed(true);
+
+ database_->SaveSnippet(**it);
+ database_->DeleteImage(suggestion_id.id_within_category());
+
+ content->dismissed.push_back(std::move(*it));
+ content->snippets.erase(it);
+}
+
+void NTPSnippetsService::FetchSuggestionImage(
+ const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) {
+ database_->LoadImage(
+ suggestion_id.id_within_category(),
+ base::Bind(&NTPSnippetsService::OnSnippetImageFetchedFromDatabase,
+ base::Unretained(this), callback, suggestion_id));
+}
+
+void NTPSnippetsService::ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) {
+ // Both time range and the filter are ignored and all suggestions are removed,
+ // because it is not known which history entries were used for the suggestions
+ // personalization.
+ if (!ready())
+ nuke_when_initialized_ = true;
+ else
+ NukeAllSnippets();
+}
+
+void NTPSnippetsService::ClearCachedSuggestions(Category category) {
+ if (!initialized())
+ return;
+
+ if (!base::ContainsKey(categories_, category))
+ return;
+ CategoryContent* content = &categories_[category];
+ if (content->snippets.empty())
+ return;
+
+ database_->DeleteSnippets(GetSnippetIDVector(content->snippets));
+ database_->DeleteImages(GetSnippetIDVector(content->snippets));
+ content->snippets.clear();
+
+ NotifyNewSuggestions();
+}
+
+void NTPSnippetsService::GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) {
+ DCHECK(base::ContainsKey(categories_, category));
+
+ std::vector<ContentSuggestion> result;
+ const CategoryContent& content = categories_[category];
+ for (const std::unique_ptr<NTPSnippet>& snippet : content.dismissed) {
+ if (!snippet->is_complete())
+ continue;
+ ContentSuggestion suggestion(category, snippet->id(),
+ snippet->best_source().url);
+ suggestion.set_amp_url(snippet->best_source().amp_url);
+ suggestion.set_title(base::UTF8ToUTF16(snippet->title()));
+ suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet()));
+ suggestion.set_publish_date(snippet->publish_date());
+ suggestion.set_publisher_name(
+ base::UTF8ToUTF16(snippet->best_source().publisher_name));
+ suggestion.set_score(snippet->score());
+ result.emplace_back(std::move(suggestion));
+ }
+ callback.Run(std::move(result));
+}
+
+void NTPSnippetsService::ClearDismissedSuggestionsForDebugging(
+ Category category) {
+ DCHECK(base::ContainsKey(categories_, category));
+
+ if (!initialized())
+ return;
+
+ CategoryContent* content = &categories_[category];
+ if (content->dismissed.empty())
+ return;
+
+ database_->DeleteSnippets(GetSnippetIDVector(content->dismissed));
+ // The image got already deleted when the suggestion was dismissed.
+
+ content->dismissed.clear();
+}
+
+// static
+int NTPSnippetsService::GetMaxSnippetCountForTesting() {
+ return kMaxSnippetCount;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private methods
+
+GURL NTPSnippetsService::FindSnippetImageUrl(
+ const ContentSuggestion::ID& suggestion_id) const {
+ DCHECK(base::ContainsKey(categories_, suggestion_id.category()));
+
+ const CategoryContent& content = categories_.at(suggestion_id.category());
+ const NTPSnippet* snippet =
+ content.FindSnippet(suggestion_id.id_within_category());
+ if (!snippet)
+ return GURL();
+ return snippet->salient_image_url();
+}
+
+// image_fetcher::ImageFetcherDelegate implementation.
+void NTPSnippetsService::OnImageDataFetched(
+ const std::string& id_within_category,
+ const std::string& image_data) {
+ if (image_data.empty())
+ return;
+
+ // Only save the image if the corresponding snippet still exists.
+ bool found = false;
+ for (const std::pair<const Category, CategoryContent>& entry : categories_) {
+ if (entry.second.FindSnippet(id_within_category)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return;
+
+ // Only cache the data in the DB, the actual serving is done in the callback
+ // provided to |image_fetcher_| (OnSnippetImageDecodedFromNetwork()).
+ database_->SaveImage(id_within_category, image_data);
+}
+
+void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) {
+ if (state_ == State::ERROR_OCCURRED)
+ return;
+ DCHECK(state_ == State::NOT_INITED);
+ DCHECK(base::ContainsKey(categories_, articles_category_));
+
+ NTPSnippet::PtrVector to_delete;
+ for (std::unique_ptr<NTPSnippet>& snippet : snippets) {
+ Category snippet_category =
+ category_factory()->FromRemoteCategory(snippet->remote_category_id());
+ // We should already know about the category.
+ if (!base::ContainsKey(categories_, snippet_category)) {
+ DLOG(WARNING) << "Loaded a suggestion for unknown category "
+ << snippet_category << " from the DB; deleting";
+ to_delete.emplace_back(std::move(snippet));
+ continue;
+ }
+
+ CategoryContent* content = &categories_[snippet_category];
+ if (snippet->is_dismissed())
+ content->dismissed.emplace_back(std::move(snippet));
+ else
+ content->snippets.emplace_back(std::move(snippet));
+ }
+ if (!to_delete.empty()) {
+ database_->DeleteSnippets(GetSnippetIDVector(to_delete));
+ database_->DeleteImages(GetSnippetIDVector(to_delete));
+ }
+
+ // Sort the suggestions in each category.
+ // TODO(treib): Persist the actual order in the DB somehow? crbug.com/654409
+ for (auto& entry : categories_) {
+ CategoryContent* content = &entry.second;
+ std::sort(content->snippets.begin(), content->snippets.end(),
+ [](const std::unique_ptr<NTPSnippet>& lhs,
+ const std::unique_ptr<NTPSnippet>& rhs) {
+ return lhs->score() > rhs->score();
+ });
+ }
+
+ // TODO(tschumann): If I move ClearExpiredDismisedSnippets() to the beginning
+ // of the function, it essentially does nothing but tests are still green. Fix
+ // this!
+ ClearExpiredDismissedSnippets();
+ ClearOrphanedImages();
+ FinishInitialization();
+}
+
+void NTPSnippetsService::OnDatabaseError() {
+ EnterState(State::ERROR_OCCURRED);
+ UpdateAllCategoryStatus(CategoryStatus::LOADING_ERROR);
+}
+
+void NTPSnippetsService::OnFetchFinished(
+ NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories) {
+ if (!ready())
+ return;
+
+ // Mark all categories as not provided by the server in the latest fetch. The
+ // ones we got will be marked again below.
+ for (auto& item : categories_) {
+ CategoryContent* content = &item.second;
+ content->provided_by_server = false;
+ }
+
+ // Clear up expired dismissed snippets before we use them to filter new ones.
+ ClearExpiredDismissedSnippets();
+
+ // If snippets were fetched successfully, update our |categories_| from each
+ // category provided by the server.
+ if (fetched_categories) {
+ // TODO(treib): Reorder |categories_| to match the order we received from
+ // the server. crbug.com/653816
+ // TODO(jkrcal): A bit hard to understand with so many variables called
+ // "*categor*". Isn't here some room for simplification?
+ for (NTPSnippetsFetcher::FetchedCategory& fetched_category :
+ *fetched_categories) {
+ Category category = fetched_category.category;
+
+ // The ChromeReader backend doesn't provide category titles, so don't
+ // overwrite the existing title for ARTICLES if the new one is empty.
+ // TODO(treib): Remove this check after we fully switch to the content
+ // suggestions backend.
+ if (category != articles_category_ ||
+ !fetched_category.localized_title.empty()) {
+ categories_[category].localized_title =
+ fetched_category.localized_title;
+ }
+ categories_[category].provided_by_server = true;
+
+ // TODO(tschumann): Remove this histogram once we only talk to the content
+ // suggestions cloud backend.
+ if (category == articles_category_) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "NewTabPage.Snippets.NumArticlesFetched",
+ std::min(fetched_category.snippets.size(),
+ static_cast<size_t>(kMaxSnippetCount + 1)));
+ }
+ ReplaceSnippets(category, std::move(fetched_category.snippets));
+ }
+ }
+
+ // We might have gotten new categories (or updated the titles of existing
+ // ones), so update the pref.
+ StoreCategoriesToPrefs();
+
+ for (const auto& item : categories_) {
+ Category category = item.first;
+ UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
+ }
+
+ // TODO(sfiera): equivalent metrics for non-articles.
+ const CategoryContent& content = categories_[articles_category_];
+ UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
+ content.snippets.size());
+ if (content.snippets.empty() && !content.dismissed.empty()) {
+ UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
+ content.dismissed.size());
+ }
+
+ // TODO(sfiera): notify only when a category changed above.
+ NotifyNewSuggestions();
+
+ // Reschedule after a successful fetch. This resets all currently scheduled
+ // fetches, to make sure the fallback interval triggers only if no wifi fetch
+ // succeeded, and also that we don't do a background fetch immediately after
+ // a user-initiated one.
+ if (fetched_categories)
+ RescheduleFetching(true);
+}
+
+void NTPSnippetsService::ArchiveSnippets(Category category,
+ NTPSnippet::PtrVector* to_archive) {
+ CategoryContent* content = &categories_[category];
+
+ database_->DeleteSnippets(GetSnippetIDVector(*to_archive));
+ // Do not delete the thumbnail images as they are still handy on open NTPs.
+
+ // Archive previous snippets - move them at the beginning of the list.
+ content->archived.insert(content->archived.begin(),
+ std::make_move_iterator(to_archive->begin()),
+ std::make_move_iterator(to_archive->end()));
+ Compact(to_archive);
+
+ // If there are more archived snippets than we want to keep, delete the
+ // oldest ones by their fetch time (which are always in the back).
+ if (content->archived.size() > kMaxArchivedSnippetCount) {
+ NTPSnippet::PtrVector to_delete(
+ std::make_move_iterator(content->archived.begin() +
+ kMaxArchivedSnippetCount),
+ std::make_move_iterator(content->archived.end()));
+ content->archived.resize(kMaxArchivedSnippetCount);
+ database_->DeleteImages(GetSnippetIDVector(to_delete));
+ }
+}
+
+void NTPSnippetsService::ReplaceSnippets(Category category,
+ NTPSnippet::PtrVector new_snippets) {
+ DCHECK(ready());
+ CategoryContent* content = &categories_[category];
+
+ // Remove new snippets that have been dismissed.
+ EraseMatchingSnippets(&new_snippets, GetAllIDs(content->dismissed),
+ /*match_all_ids=*/true);
+
+ // Fill in default publish/expiry dates where required.
+ for (std::unique_ptr<NTPSnippet>& snippet : new_snippets) {
+ if (snippet->publish_date().is_null())
+ snippet->set_publish_date(base::Time::Now());
+ if (snippet->expiry_date().is_null()) {
+ snippet->set_expiry_date(
+ snippet->publish_date() +
+ base::TimeDelta::FromMinutes(kDefaultExpiryTimeMins));
+ }
+ }
+
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAddIncompleteSnippets)) {
+ int num_new_snippets = new_snippets.size();
+ // Remove snippets that do not have all the info we need to display it to
+ // the user.
+ new_snippets.erase(
+ std::remove_if(new_snippets.begin(), new_snippets.end(),
+ [](const std::unique_ptr<NTPSnippet>& snippet) {
+ return !snippet->is_complete();
+ }),
+ new_snippets.end());
+ int num_snippets_dismissed = num_new_snippets - new_snippets.size();
+ UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch",
+ num_snippets_dismissed > 0);
+ if (num_snippets_dismissed > 0) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets",
+ num_snippets_dismissed);
+ }
+ }
+
+ // Do not touch the current set of snippets if the newly fetched one is empty.
+ if (new_snippets.empty())
+ return;
+
+ // Remove current snippets that have been fetched again. We do not need to
+ // archive those as they will be in the new current set.
+ EraseMatchingSnippets(&content->snippets, GetSnippetIDSet(new_snippets),
+ /*match_all_ids=*/false);
+
+ ArchiveSnippets(category, &content->snippets);
+
+ // Save new articles to the DB.
+ database_->SaveSnippets(new_snippets);
+
+ content->snippets = std::move(new_snippets);
+}
+
+void NTPSnippetsService::ClearExpiredDismissedSnippets() {
+ std::vector<Category> categories_to_erase;
+
+ const base::Time now = base::Time::Now();
+
+ for (auto& item : categories_) {
+ Category category = item.first;
+ CategoryContent* content = &item.second;
+
+ NTPSnippet::PtrVector to_delete;
+ // Move expired dismissed snippets over into |to_delete|.
+ for (std::unique_ptr<NTPSnippet>& snippet : content->dismissed) {
+ if (snippet->expiry_date() <= now)
+ to_delete.emplace_back(std::move(snippet));
+ }
+ Compact(&content->dismissed);
+
+ // Delete the removed article suggestions from the DB.
+ database_->DeleteSnippets(GetSnippetIDVector(to_delete));
+ // The image got already deleted when the suggestion was dismissed.
+
+ if (content->snippets.empty() && content->dismissed.empty() &&
+ category != articles_category_ && !content->provided_by_server) {
+ categories_to_erase.push_back(category);
+ }
+ }
+
+ for (Category category : categories_to_erase) {
+ UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED);
+ categories_.erase(category);
+ }
+
+ StoreCategoriesToPrefs();
+}
+
+void NTPSnippetsService::ClearOrphanedImages() {
+ auto alive_snippets = base::MakeUnique<std::set<std::string>>();
+ for (const auto& entry : categories_) {
+ const CategoryContent& content = entry.second;
+ for (const auto& snippet_ptr : content.snippets) {
+ alive_snippets->insert(snippet_ptr->id());
+ }
+ for (const auto& snippet_ptr : content.dismissed) {
+ alive_snippets->insert(snippet_ptr->id());
+ }
+ }
+ database_->GarbageCollectImages(std::move(alive_snippets));
+}
+
+void NTPSnippetsService::NukeAllSnippets() {
+ std::vector<Category> categories_to_erase;
+
+ // Empty the ARTICLES category and remove all others, since they may or may
+ // not be personalized.
+ for (const auto& item : categories_) {
+ Category category = item.first;
+
+ ClearCachedSuggestions(category);
+ ClearDismissedSuggestionsForDebugging(category);
+
+ UpdateCategoryStatus(category, CategoryStatus::NOT_PROVIDED);
+
+ // Remove the category entirely; it may or may not reappear.
+ if (category != articles_category_)
+ categories_to_erase.push_back(category);
+ }
+
+ for (Category category : categories_to_erase) {
+ categories_.erase(category);
+ }
+
+ StoreCategoriesToPrefs();
+}
+
+void NTPSnippetsService::OnSnippetImageFetchedFromDatabase(
+ const ImageFetchedCallback& callback,
+ const ContentSuggestion::ID& suggestion_id,
+ std::string data) {
+ // |image_decoder_| is null in tests.
+ if (image_decoder_ && !data.empty()) {
+ image_decoder_->DecodeImage(
+ data, base::Bind(&NTPSnippetsService::OnSnippetImageDecodedFromDatabase,
+ base::Unretained(this), callback, suggestion_id));
+ return;
+ }
+
+ // Fetching from the DB failed; start a network fetch.
+ FetchSnippetImageFromNetwork(suggestion_id, callback);
+}
+
+void NTPSnippetsService::OnSnippetImageDecodedFromDatabase(
+ const ImageFetchedCallback& callback,
+ const ContentSuggestion::ID& suggestion_id,
+ const gfx::Image& image) {
+ if (!image.IsEmpty()) {
+ callback.Run(image);
+ return;
+ }
+
+ // If decoding the image failed, delete the DB entry.
+ database_->DeleteImage(suggestion_id.id_within_category());
+
+ FetchSnippetImageFromNetwork(suggestion_id, callback);
+}
+
+void NTPSnippetsService::FetchSnippetImageFromNetwork(
+ const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) {
+ if (!base::ContainsKey(categories_, suggestion_id.category())) {
+ OnSnippetImageDecodedFromNetwork(
+ callback, suggestion_id.id_within_category(), gfx::Image());
+ return;
+ }
+
+ GURL image_url = FindSnippetImageUrl(suggestion_id);
+
+ if (image_url.is_empty() ||
+ !thumbnail_requests_throttler_.DemandQuotaForRequest(
+ /*interactive_request=*/true)) {
+ // Return an empty image. Directly, this is never synchronous with the
+ // original FetchSuggestionImage() call - an asynchronous database query has
+ // happened in the meantime.
+ OnSnippetImageDecodedFromNetwork(
+ callback, suggestion_id.id_within_category(), gfx::Image());
+ return;
+ }
+
+ image_fetcher_->StartOrQueueNetworkRequest(
+ suggestion_id.id_within_category(), image_url,
+ base::Bind(&NTPSnippetsService::OnSnippetImageDecodedFromNetwork,
+ base::Unretained(this), callback));
+}
+
+void NTPSnippetsService::OnSnippetImageDecodedFromNetwork(
+ const ImageFetchedCallback& callback,
+ const std::string& id_within_category,
+ const gfx::Image& image) {
+ callback.Run(image);
+}
+
+void NTPSnippetsService::EnterStateReady() {
+ if (nuke_when_initialized_) {
+ NukeAllSnippets();
+ nuke_when_initialized_ = false;
+ }
+
+ if (categories_[articles_category_].snippets.empty() || fetch_when_ready_) {
+ // TODO(jkrcal): Fetching snippets automatically upon creation of this
+ // lazily created service can cause troubles, e.g. in unit tests where
+ // network I/O is not allowed.
+ // Either add a DCHECK here that we actually are allowed to do network I/O
+ // or change the logic so that some explicit call is always needed for the
+ // network request.
+ FetchSnippets(/*interactive_request=*/false);
+ fetch_when_ready_ = false;
+ }
+
+ for (const auto& item : categories_) {
+ Category category = item.first;
+ const CategoryContent& content = item.second;
+ // FetchSnippets has set the status to |AVAILABLE_LOADING| if relevant,
+ // otherwise we transition to |AVAILABLE| here.
+ if (content.status != CategoryStatus::AVAILABLE_LOADING)
+ UpdateCategoryStatus(category, CategoryStatus::AVAILABLE);
+ }
+}
+
+void NTPSnippetsService::EnterStateDisabled() {
+ NukeAllSnippets();
+}
+
+void NTPSnippetsService::EnterStateError() {
+ snippets_status_service_.reset();
+}
+
+void NTPSnippetsService::FinishInitialization() {
+ if (nuke_when_initialized_) {
+ // We nuke here in addition to EnterStateReady, so that it happens even if
+ // we enter the DISABLED state below.
+ NukeAllSnippets();
+ nuke_when_initialized_ = false;
+ }
+
+ snippets_fetcher_->SetCallback(
+ base::Bind(&NTPSnippetsService::OnFetchFinished, base::Unretained(this)));
+
+ // |image_fetcher_| can be null in tests.
+ if (image_fetcher_) {
+ image_fetcher_->SetImageFetcherDelegate(this);
+ image_fetcher_->SetDataUseServiceName(
+ data_use_measurement::DataUseUserData::NTP_SNIPPETS);
+ }
+
+ // Note: Initializing the status service will run the callback right away with
+ // the current state.
+ snippets_status_service_->Init(base::Bind(
+ &NTPSnippetsService::OnSnippetsStatusChanged, base::Unretained(this)));
+
+ // Always notify here even if we got nothing from the database, because we
+ // don't know how long the fetch will take or if it will even complete.
+ NotifyNewSuggestions();
+}
+
+void NTPSnippetsService::OnSnippetsStatusChanged(
+ SnippetsStatus old_snippets_status,
+ SnippetsStatus new_snippets_status) {
+ switch (new_snippets_status) {
+ case SnippetsStatus::ENABLED_AND_SIGNED_IN:
+ if (old_snippets_status == SnippetsStatus::ENABLED_AND_SIGNED_OUT) {
+ DCHECK(state_ == State::READY);
+ // Clear nonpersonalized suggestions.
+ NukeAllSnippets();
+ // Fetch personalized ones.
+ FetchSnippets(/*interactive_request=*/true);
+ } else {
+ // Do not change the status. That will be done in EnterStateReady().
+ EnterState(State::READY);
+ }
+ break;
+
+ case SnippetsStatus::ENABLED_AND_SIGNED_OUT:
+ if (old_snippets_status == SnippetsStatus::ENABLED_AND_SIGNED_IN) {
+ DCHECK(state_ == State::READY);
+ // Clear personalized suggestions.
+ NukeAllSnippets();
+ // Fetch nonpersonalized ones.
+ FetchSnippets(/*interactive_request=*/true);
+ } else {
+ // Do not change the status. That will be done in EnterStateReady().
+ EnterState(State::READY);
+ }
+ break;
+
+ case SnippetsStatus::EXPLICITLY_DISABLED:
+ EnterState(State::DISABLED);
+ UpdateAllCategoryStatus(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED);
+ break;
+
+ case SnippetsStatus::SIGNED_OUT_AND_DISABLED:
+ EnterState(State::DISABLED);
+ UpdateAllCategoryStatus(CategoryStatus::SIGNED_OUT);
+ break;
+ }
+}
+
+void NTPSnippetsService::EnterState(State state) {
+ if (state == state_)
+ return;
+
+ switch (state) {
+ case State::NOT_INITED:
+ // Initial state, it should not be possible to get back there.
+ NOTREACHED();
+ break;
+
+ case State::READY:
+ DCHECK(state_ == State::NOT_INITED || state_ == State::DISABLED);
+
+ DVLOG(1) << "Entering state: READY";
+ state_ = State::READY;
+ EnterStateReady();
+ break;
+
+ case State::DISABLED:
+ DCHECK(state_ == State::NOT_INITED || state_ == State::READY);
+
+ DVLOG(1) << "Entering state: DISABLED";
+ state_ = State::DISABLED;
+ EnterStateDisabled();
+ break;
+
+ case State::ERROR_OCCURRED:
+ DVLOG(1) << "Entering state: ERROR_OCCURRED";
+ state_ = State::ERROR_OCCURRED;
+ EnterStateError();
+ break;
+ }
+
+ // Schedule or un-schedule background fetching after each state change.
+ RescheduleFetching(false);
+}
+
+void NTPSnippetsService::NotifyNewSuggestions() {
+ for (const auto& item : categories_) {
+ Category category = item.first;
+ const CategoryContent& content = item.second;
+
+ std::vector<ContentSuggestion> result;
+ for (const std::unique_ptr<NTPSnippet>& snippet : content.snippets) {
+ // TODO(sfiera): if a snippet is not going to be displayed, move it
+ // directly to content.dismissed on fetch. Otherwise, we might prune
+ // other snippets to get down to kMaxSnippetCount, only to hide one of the
+ // incomplete ones we kept.
+ if (!snippet->is_complete())
+ continue;
+ ContentSuggestion suggestion(category, snippet->id(),
+ snippet->best_source().url);
+ suggestion.set_amp_url(snippet->best_source().amp_url);
+ suggestion.set_title(base::UTF8ToUTF16(snippet->title()));
+ suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet()));
+ suggestion.set_publish_date(snippet->publish_date());
+ suggestion.set_publisher_name(
+ base::UTF8ToUTF16(snippet->best_source().publisher_name));
+ suggestion.set_score(snippet->score());
+ result.emplace_back(std::move(suggestion));
+ }
+
+ DVLOG(1) << "NotifyNewSuggestions(): " << result.size()
+ << " items in category " << category;
+ observer()->OnNewSuggestions(this, category, std::move(result));
+ }
+}
+
+void NTPSnippetsService::UpdateCategoryStatus(Category category,
+ CategoryStatus status) {
+ DCHECK(base::ContainsKey(categories_, category));
+ CategoryContent& content = categories_[category];
+ if (status == content.status)
+ return;
+
+ DVLOG(1) << "UpdateCategoryStatus(): " << category.id() << ": "
+ << static_cast<int>(content.status) << " -> "
+ << static_cast<int>(status);
+ content.status = status;
+ observer()->OnCategoryStatusChanged(this, category, content.status);
+}
+
+void NTPSnippetsService::UpdateAllCategoryStatus(CategoryStatus status) {
+ for (const auto& category : categories_) {
+ UpdateCategoryStatus(category.first, status);
+ }
+}
+
+const NTPSnippet* NTPSnippetsService::CategoryContent::FindSnippet(
+ const std::string& id_within_category) const {
+ // Search for the snippet in current and archived snippets.
+ auto it = std::find_if(
+ snippets.begin(), snippets.end(),
+ [&id_within_category](const std::unique_ptr<NTPSnippet>& snippet) {
+ return snippet->id() == id_within_category;
+ });
+ if (it != snippets.end())
+ return it->get();
+
+ it = std::find_if(
+ archived.begin(), archived.end(),
+ [&id_within_category](const std::unique_ptr<NTPSnippet>& snippet) {
+ return snippet->id() == id_within_category;
+ });
+ if (it != archived.end())
+ return it->get();
+
+ return nullptr;
+}
+
+void NTPSnippetsService::RestoreCategoriesFromPrefs() {
+ // This must only be called at startup, before there are any categories.
+ DCHECK(categories_.empty());
+
+ const base::ListValue* list =
+ pref_service_->GetList(prefs::kRemoteSuggestionCategories);
+ for (const std::unique_ptr<base::Value>& entry : *list) {
+ const base::DictionaryValue* dict = nullptr;
+ if (!entry->GetAsDictionary(&dict)) {
+ DLOG(WARNING) << "Invalid category pref value: " << *entry;
+ continue;
+ }
+ int id = 0;
+ if (!dict->GetInteger(kCategoryContentId, &id)) {
+ DLOG(WARNING) << "Invalid category pref value, missing '"
+ << kCategoryContentId << "': " << *entry;
+ continue;
+ }
+ base::string16 title;
+ if (!dict->GetString(kCategoryContentTitle, &title)) {
+ DLOG(WARNING) << "Invalid category pref value, missing '"
+ << kCategoryContentTitle << "': " << *entry;
+ continue;
+ }
+ bool provided_by_server = false;
+ if (!dict->GetBoolean(kCategoryContentProvidedByServer,
+ &provided_by_server)) {
+ DLOG(WARNING) << "Invalid category pref value, missing '"
+ << kCategoryContentProvidedByServer << "': " << *entry;
+ continue;
+ }
+
+ Category category = category_factory()->FromIDValue(id);
+ categories_[category] = CategoryContent();
+ categories_[category].localized_title = title;
+ categories_[category].provided_by_server = provided_by_server;
+ }
+}
+
+void NTPSnippetsService::StoreCategoriesToPrefs() {
+ // Collect all the CategoryContents.
+ std::vector<std::pair<Category, const CategoryContent*>> to_store;
+ for (const auto& entry : categories_)
+ to_store.emplace_back(entry.first, &entry.second);
+ // Sort them into the proper category order.
+ std::sort(to_store.begin(), to_store.end(),
+ [this](const std::pair<Category, const CategoryContent*>& left,
+ const std::pair<Category, const CategoryContent*>& right) {
+ return category_factory()->CompareCategories(left.first,
+ right.first);
+ });
+ // Convert the relevant info into a base::ListValue for storage.
+ base::ListValue list;
+ for (const auto& entry : to_store) {
+ Category category = entry.first;
+ const base::string16& title = entry.second->localized_title;
+ bool provided_by_server = entry.second->provided_by_server;
+ auto dict = base::MakeUnique<base::DictionaryValue>();
+ dict->SetInteger(kCategoryContentId, category.id());
+ dict->SetString(kCategoryContentTitle, title);
+ dict->SetBoolean(kCategoryContentProvidedByServer, provided_by_server);
+ list.Append(std::move(dict));
+ }
+ // Finally, store the result in the pref service.
+ pref_service_->Set(prefs::kRemoteSuggestionCategories, list);
+}
+
+NTPSnippetsService::CategoryContent::CategoryContent() = default;
+NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) =
+ default;
+NTPSnippetsService::CategoryContent::~CategoryContent() = default;
+NTPSnippetsService::CategoryContent& NTPSnippetsService::CategoryContent::
+operator=(CategoryContent&&) = default;
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_service.h b/chromium/components/ntp_snippets/remote/ntp_snippets_service.h
new file mode 100644
index 00000000000..af9c017bafb
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_service.h
@@ -0,0 +1,366 @@
+// 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 COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SERVICE_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SERVICE_H_
+
+#include <cstddef>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "components/image_fetcher/image_fetcher_delegate.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/category_status.h"
+#include "components/ntp_snippets/content_suggestion.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
+#include "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
+#include "components/ntp_snippets/remote/ntp_snippets_scheduler.h"
+#include "components/ntp_snippets/remote/ntp_snippets_status_service.h"
+#include "components/ntp_snippets/remote/request_throttler.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace gfx {
+class Image;
+} // namespace gfx
+
+namespace image_fetcher {
+class ImageDecoder;
+class ImageFetcher;
+} // namespace image_fetcher
+
+namespace ntp_snippets {
+
+class NTPSnippetsDatabase;
+class UserClassifier;
+
+// Retrieves fresh content data (articles) from the server, stores them and
+// provides them as content suggestions.
+// This class is final because it does things in its constructor which make it
+// unsafe to derive from it.
+// TODO(treib): Introduce two-phase initialization and make the class not final?
+// TODO(pke): Rename this service to ArticleSuggestionsProvider and move to
+// a subdirectory.
+// TODO(jkrcal): this class grows really, really large. The fact that
+// NTPSnippetService also implements ImageFetcherDelegate adds unnecessary
+// complexity (and after all the Service is conceptually not an
+// ImagerFetcherDeletage ;-)). Instead, the cleaner solution would be to define
+// a CachedImageFetcher class that handles the caching aspects and looks like an
+// image fetcher to the NTPSnippetService.
+class NTPSnippetsService final : public ContentSuggestionsProvider,
+ public image_fetcher::ImageFetcherDelegate {
+ public:
+ // |application_language_code| should be a ISO 639-1 compliant string, e.g.
+ // 'en' or 'en-US'. Note that this code should only specify the language, not
+ // the locale, so 'en_US' (English language with US locale) and 'en-GB_US'
+ // (British English person in the US) are not language codes.
+ NTPSnippetsService(Observer* observer,
+ CategoryFactory* category_factory,
+ PrefService* pref_service,
+ const std::string& application_language_code,
+ const UserClassifier* user_classifier,
+ NTPSnippetsScheduler* scheduler,
+ std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
+ std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
+ std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
+ std::unique_ptr<NTPSnippetsDatabase> database,
+ std::unique_ptr<NTPSnippetsStatusService> status_service);
+
+ ~NTPSnippetsService() override;
+
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ // Returns whether the service is ready. While this is false, the list of
+ // snippets will be empty, and all modifications to it (fetch, dismiss, etc)
+ // will be ignored.
+ bool ready() const { return state_ == State::READY; }
+
+ // Returns whether the service is initialized. While this is false, some
+ // calls may trigger DCHECKs.
+ bool initialized() const { return ready() || state_ == State::DISABLED; }
+
+ // Fetches snippets from the server and replaces old snippets by the new ones.
+ // Requests can be marked more important by setting |interactive_request| to
+ // true (such request might circumvent the daily quota for requests, etc.)
+ // Useful for requests triggered by the user.
+ void FetchSnippets(bool interactive_request);
+
+ // Fetches snippets from the server for specified hosts and adds them to the
+ // current ones. Only called from chrome://snippets-internals, DO NOT USE
+ // otherwise! Ignored while ready() is false.
+ void FetchSnippetsFromHosts(const std::set<std::string>& hosts,
+ bool interactive_request);
+
+ const NTPSnippetsFetcher* snippets_fetcher() const {
+ return snippets_fetcher_.get();
+ }
+
+ // (Re)schedules the periodic fetching of snippets. If |force| is true, the
+ // tasks will be re-scheduled even if they already exist and have the correct
+ // periods.
+ void RescheduleFetching(bool force);
+
+ // ContentSuggestionsProvider implementation
+ CategoryStatus GetCategoryStatus(Category category) override;
+ CategoryInfo GetCategoryInfo(Category category) override;
+ void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+ void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) override;
+ void ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) override;
+ void ClearCachedSuggestions(Category category) override;
+ void GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) override;
+ void ClearDismissedSuggestionsForDebugging(Category category) override;
+
+ // Returns the maximum number of snippets that will be shown at once.
+ static int GetMaxSnippetCountForTesting();
+
+ // Available snippets, only for unit tests.
+ // TODO(treib): Get rid of this. Tests should use a fake observer instead.
+ const NTPSnippet::PtrVector& GetSnippetsForTesting(Category category) const {
+ return categories_.find(category)->second.snippets;
+ }
+
+ // Available snippets, only for unit tests.
+ const NTPSnippet::PtrVector& GetArchivedSnippetsForTesting(
+ Category category) const {
+ return categories_.find(category)->second.archived;
+ }
+
+ // Dismissed snippets, only for unit tests.
+ const NTPSnippet::PtrVector& GetDismissedSnippetsForTesting(
+ Category category) const {
+ return categories_.find(category)->second.dismissed;
+ }
+
+ private:
+ friend class NTPSnippetsServiceTest;
+ FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest,
+ RemoveExpiredDismissedContent);
+ FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, RescheduleOnStateChange);
+ FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, StatusChanges);
+ FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest,
+ SuggestionsFetchedOnSignInAndSignOut);
+
+ // Possible state transitions:
+ // NOT_INITED --------+
+ // / \ |
+ // v v |
+ // READY <--> DISABLED |
+ // \ / |
+ // v v |
+ // ERROR_OCCURRED <-----+
+ enum class State {
+ // The service has just been created. Can change to states:
+ // - DISABLED: After the database is done loading,
+ // GetStateForDependenciesStatus can identify the next state to
+ // be DISABLED.
+ // - READY: if GetStateForDependenciesStatus returns it, after the database
+ // is done loading.
+ // - ERROR_OCCURRED: when an unrecoverable error occurred.
+ NOT_INITED,
+
+ // The service registered observers, timers, etc. and is ready to answer to
+ // queries, fetch snippets... Can change to states:
+ // - DISABLED: when the global Chrome state changes, for example after
+ // |OnStateChanged| is called and sync is disabled.
+ // - ERROR_OCCURRED: when an unrecoverable error occurred.
+ READY,
+
+ // The service is disabled and unregistered the related resources.
+ // Can change to states:
+ // - READY: when the global Chrome state changes, for example after
+ // |OnStateChanged| is called and sync is enabled.
+ // - ERROR_OCCURRED: when an unrecoverable error occurred.
+ DISABLED,
+
+ // The service or one of its dependencies encountered an unrecoverable error
+ // and the service can't be used anymore.
+ ERROR_OCCURRED
+ };
+
+ // Returns the URL of the image of a snippet if it is among the current or
+ // among the archived snippets in the matching category. Returns an empty URL
+ // otherwise.
+ GURL FindSnippetImageUrl(const ContentSuggestion::ID& suggestion_id) const;
+
+ // image_fetcher::ImageFetcherDelegate implementation.
+ void OnImageDataFetched(const std::string& id_within_category,
+ const std::string& image_data) override;
+
+ // Callbacks for the NTPSnippetsDatabase.
+ void OnDatabaseLoaded(NTPSnippet::PtrVector snippets);
+ void OnDatabaseError();
+
+ // Callback for the NTPSnippetsFetcher.
+ void OnFetchFinished(
+ NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories);
+
+ // Moves all snippets from |to_archive| into the archive of the |category|.
+ // It also deletes the snippets from the DB and keeps the archive reasonably
+ // short.
+ void ArchiveSnippets(Category category, NTPSnippet::PtrVector* to_archive);
+
+ // Replace old snippets in |category| by newly available snippets.
+ void ReplaceSnippets(Category category, NTPSnippet::PtrVector new_snippets);
+
+ // Removes expired dismissed snippets from the service and the database.
+ void ClearExpiredDismissedSnippets();
+
+ // Removes images from the DB that are not referenced from any known snippet.
+ // Needs to iterate the whole snippet database -- so do it often enough to
+ // keep it small but not too often as it still iterates over the file system.
+ void ClearOrphanedImages();
+
+ // Clears all stored snippets and updates the observer.
+ void NukeAllSnippets();
+
+ // Completes the initialization phase of the service, registering the last
+ // observers. This is done after construction, once the database is loaded.
+ void FinishInitialization();
+
+ void OnSnippetImageFetchedFromDatabase(
+ const ImageFetchedCallback& callback,
+ const ContentSuggestion::ID& suggestion_id,
+ std::string data);
+
+ void OnSnippetImageDecodedFromDatabase(
+ const ImageFetchedCallback& callback,
+ const ContentSuggestion::ID& suggestion_id,
+ const gfx::Image& image);
+
+ void FetchSnippetImageFromNetwork(const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback);
+
+ void OnSnippetImageDecodedFromNetwork(const ImageFetchedCallback& callback,
+ const std::string& id_within_category,
+ const gfx::Image& image);
+
+ // Triggers a state transition depending on the provided snippets status. This
+ // method is called when a change is detected by |snippets_status_service_|.
+ void OnSnippetsStatusChanged(SnippetsStatus old_snippets_status,
+ SnippetsStatus new_snippets_status);
+
+ // Verifies state transitions (see |State|'s documentation) and applies them.
+ // Also updates the provider status. Does nothing except updating the provider
+ // status if called with the current state.
+ void EnterState(State state);
+
+ // Enables the service. Do not call directly, use |EnterState| instead.
+ void EnterStateReady();
+
+ // Disables the service. Do not call directly, use |EnterState| instead.
+ void EnterStateDisabled();
+
+ // Disables the service permanently because an unrecoverable error occurred.
+ // Do not call directly, use |EnterState| instead.
+ void EnterStateError();
+
+ // Converts the cached snippets to article content suggestions and notifies
+ // the observers.
+ void NotifyNewSuggestions();
+
+ // Updates the internal status for |category| to |category_status_| and
+ // notifies the content suggestions observer if it changed.
+ void UpdateCategoryStatus(Category category, CategoryStatus status);
+ // Calls UpdateCategoryStatus() for all provided categories.
+ void UpdateAllCategoryStatus(CategoryStatus status);
+
+ void RestoreCategoriesFromPrefs();
+ void StoreCategoriesToPrefs();
+
+ State state_;
+
+ PrefService* pref_service_;
+
+ const Category articles_category_;
+
+ // TODO(sfiera): Reduce duplication of CategoryContent with CategoryInfo.
+ struct CategoryContent {
+ CategoryStatus status = CategoryStatus::INITIALIZING;
+
+ // The title of the section, localized to the running UI language.
+ base::string16 localized_title;
+
+ // True iff the server returned results in this category in the last fetch.
+ // We never remove categories that the server still provides, but if the
+ // server stops providing a category, we won't yet report it as NOT_PROVIDED
+ // while we still have non-expired snippets in it.
+ bool provided_by_server = true;
+
+ // All currently active suggestions (excl. the dismissed ones).
+ NTPSnippet::PtrVector snippets;
+
+ // All previous suggestions that we keep around in memory because they can
+ // be on some open NTP. We do not persist this list so that on a new start
+ // of Chrome, this is empty.
+ NTPSnippet::PtrVector archived;
+
+ // Suggestions that the user dismissed. We keep these around until they
+ // expire so we won't re-add them to |snippets| on the next fetch.
+ NTPSnippet::PtrVector dismissed;
+
+ // Returns a non-dismissed snippet with the given |id_within_category|, or
+ // null if none exist.
+ const NTPSnippet* FindSnippet(const std::string& id_within_category) const;
+
+ CategoryContent();
+ CategoryContent(CategoryContent&&);
+ ~CategoryContent();
+ CategoryContent& operator=(CategoryContent&&);
+ };
+ std::map<Category, CategoryContent, Category::CompareByID> categories_;
+
+ // The ISO 639-1 code of the language used by the application.
+ const std::string application_language_code_;
+
+ // Classifier that tells us how active the user is. Not owned.
+ const UserClassifier* user_classifier_;
+
+ // Scheduler for fetching snippets. Not owned.
+ NTPSnippetsScheduler* scheduler_;
+
+ // The snippets fetcher.
+ std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher_;
+
+ std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
+ std::unique_ptr<image_fetcher::ImageDecoder> image_decoder_;
+
+ // The database for persisting snippets.
+ std::unique_ptr<NTPSnippetsDatabase> database_;
+
+ // The service that provides events and data about the signin and sync state.
+ std::unique_ptr<NTPSnippetsStatusService> snippets_status_service_;
+
+ // Set to true if FetchSnippets is called while the service isn't ready.
+ // The fetch will be executed once the service enters the READY state.
+ bool fetch_when_ready_;
+
+ // Set to true if NukeAllSnippets is called while the service isn't ready.
+ // The nuke will be executed once the service finishes initialization or
+ // enters the READY state.
+ bool nuke_when_initialized_;
+
+ // Request throttler for limiting requests to thumbnail images.
+ RequestThrottler thumbnail_requests_throttler_;
+
+ DISALLOW_COPY_AND_ASSIGN(NTPSnippetsService);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_SERVICE_H_
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_service_unittest.cc b/chromium/components/ntp_snippets/remote/ntp_snippets_service_unittest.cc
new file mode 100644
index 00000000000..5b6fb4fc45d
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_service_unittest.cc
@@ -0,0 +1,1305 @@
+// 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 "components/ntp_snippets/remote/ntp_snippets_service.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/histogram_tester.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/image_fetcher/image_decoder.h"
+#include "components/image_fetcher/image_fetcher.h"
+#include "components/image_fetcher/image_fetcher_delegate.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/ntp_snippets_constants.h"
+#include "components/ntp_snippets/remote/ntp_snippet.h"
+#include "components/ntp_snippets/remote/ntp_snippets_database.h"
+#include "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
+#include "components/ntp_snippets/remote/ntp_snippets_scheduler.h"
+#include "components/ntp_snippets/remote/ntp_snippets_test_utils.h"
+#include "components/ntp_snippets/user_classifier.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/variations/variations_associated_data.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_unittest_util.h"
+
+using image_fetcher::ImageFetcher;
+using image_fetcher::ImageFetcherDelegate;
+using testing::ElementsAre;
+using testing::Eq;
+using testing::InSequence;
+using testing::Invoke;
+using testing::IsEmpty;
+using testing::Mock;
+using testing::MockFunction;
+using testing::NiceMock;
+using testing::SaveArg;
+using testing::SizeIs;
+using testing::StartsWith;
+using testing::WithArgs;
+using testing::_;
+
+namespace ntp_snippets {
+
+namespace {
+
+MATCHER_P(IdEq, value, "") {
+ return arg->id() == value;
+}
+
+MATCHER_P(IsCategory, id, "") {
+ return arg.id() == static_cast<int>(id);
+}
+
+const base::Time::Exploded kDefaultCreationTime = {2015, 11, 4, 25, 13, 46, 45};
+const char kTestContentSuggestionsServerEndpoint[] =
+ "https://localunittest-chromecontentsuggestions-pa.googleapis.com/v1/"
+ "suggestions/fetch";
+const char kAPIKey[] = "fakeAPIkey";
+const char kTestContentSuggestionsServerWithAPIKey[] =
+ "https://localunittest-chromecontentsuggestions-pa.googleapis.com/v1/"
+ "suggestions/fetch?key=fakeAPIkey";
+
+const char kSnippetUrl[] = "http://localhost/foobar";
+const char kSnippetTitle[] = "Title";
+const char kSnippetText[] = "Snippet";
+const char kSnippetSalientImage[] = "http://localhost/salient_image";
+const char kSnippetPublisherName[] = "Foo News";
+const char kSnippetAmpUrl[] = "http://localhost/amp";
+
+const char kSnippetUrl2[] = "http://foo.com/bar";
+
+const char kTestJsonDefaultCategoryTitle[] = "Some title";
+
+const int kUnknownRemoteCategoryId = 1234;
+
+base::Time GetDefaultCreationTime() {
+ base::Time out_time;
+ EXPECT_TRUE(base::Time::FromUTCExploded(kDefaultCreationTime, &out_time));
+ return out_time;
+}
+
+base::Time GetDefaultExpirationTime() {
+ return base::Time::Now() + base::TimeDelta::FromHours(1);
+}
+
+std::string GetTestJson(const std::vector<std::string>& snippets,
+ const std::string& category_title) {
+ return base::StringPrintf(
+ "{\n"
+ " \"categories\": [{\n"
+ " \"id\": 1,\n"
+ " \"localizedTitle\": \"%s\",\n"
+ " \"suggestions\": [%s]\n"
+ " }]\n"
+ "}\n",
+ category_title.c_str(),
+ base::JoinString(snippets, ", ").c_str());
+}
+
+std::string GetTestJson(const std::vector<std::string>& snippets) {
+ return GetTestJson(snippets, kTestJsonDefaultCategoryTitle);
+}
+
+std::string GetTestJsonWithoutTitle(const std::vector<std::string>& snippets) {
+ return GetTestJson(snippets, std::string());
+}
+
+std::string GetMultiCategoryJson(const std::vector<std::string>& articles,
+ const std::vector<std::string>& others,
+ int other_id = 2) {
+ return base::StringPrintf(
+ "{\n"
+ " \"categories\": [{\n"
+ " \"id\": 1,\n"
+ " \"localizedTitle\": \"Articles for You\",\n"
+ " \"suggestions\": [%s]\n"
+ " }, {\n"
+ " \"id\": %i,\n"
+ " \"localizedTitle\": \"Other Things\",\n"
+ " \"suggestions\": [%s]\n"
+ " }]\n"
+ "}\n",
+ base::JoinString(articles, ", ").c_str(), other_id,
+ base::JoinString(others, ", ").c_str());
+}
+
+std::string FormatTime(const base::Time& t) {
+ base::Time::Exploded x;
+ t.UTCExplode(&x);
+ return base::StringPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ", x.year, x.month,
+ x.day_of_month, x.hour, x.minute, x.second);
+}
+
+std::string GetSnippetWithUrlAndTimesAndSource(
+ const std::vector<std::string>& ids,
+ const std::string& url,
+ const base::Time& creation_time,
+ const base::Time& expiry_time,
+ const std::string& publisher,
+ const std::string& amp_url) {
+ const std::string ids_string = base::JoinString(ids, "\",\n \"");
+ return base::StringPrintf(
+ "{\n"
+ " \"ids\": [\n"
+ " \"%s\"\n"
+ " ],\n"
+ " \"title\": \"%s\",\n"
+ " \"snippet\": \"%s\",\n"
+ " \"fullPageUrl\": \"%s\",\n"
+ " \"creationTime\": \"%s\",\n"
+ " \"expirationTime\": \"%s\",\n"
+ " \"attribution\": \"%s\",\n"
+ " \"imageUrl\": \"%s\",\n"
+ " \"ampUrl\": \"%s\"\n"
+ " }",
+ ids_string.c_str(), kSnippetTitle, kSnippetText, url.c_str(),
+ FormatTime(creation_time).c_str(), FormatTime(expiry_time).c_str(),
+ publisher.c_str(), kSnippetSalientImage, amp_url.c_str());
+}
+
+std::string GetSnippetWithSources(const std::string& source_url,
+ const std::string& publisher,
+ const std::string& amp_url) {
+ return GetSnippetWithUrlAndTimesAndSource(
+ {kSnippetUrl}, source_url, GetDefaultCreationTime(),
+ GetDefaultExpirationTime(), publisher, amp_url);
+}
+
+std::string GetSnippetWithUrlAndTimes(const std::string& url,
+ const base::Time& content_creation_time,
+ const base::Time& expiry_time) {
+ return GetSnippetWithUrlAndTimesAndSource({url}, url, content_creation_time,
+ expiry_time, kSnippetPublisherName,
+ kSnippetAmpUrl);
+}
+
+std::string GetSnippetWithTimes(const base::Time& content_creation_time,
+ const base::Time& expiry_time) {
+ return GetSnippetWithUrlAndTimes(kSnippetUrl, content_creation_time,
+ expiry_time);
+}
+
+std::string GetSnippetWithUrl(const std::string& url) {
+ return GetSnippetWithUrlAndTimes(url, GetDefaultCreationTime(),
+ GetDefaultExpirationTime());
+}
+
+std::string GetSnippet() {
+ return GetSnippetWithUrlAndTimes(kSnippetUrl, GetDefaultCreationTime(),
+ GetDefaultExpirationTime());
+}
+
+std::string GetSnippetN(int n) {
+ return GetSnippetWithUrlAndTimes(base::StringPrintf("%s/%d", kSnippetUrl, n),
+ GetDefaultCreationTime(),
+ GetDefaultExpirationTime());
+}
+
+std::string GetExpiredSnippet() {
+ return GetSnippetWithTimes(GetDefaultCreationTime(), base::Time::Now());
+}
+
+std::string GetInvalidSnippet() {
+ std::string json_str = GetSnippet();
+ // Make the json invalid by removing the final closing brace.
+ return json_str.substr(0, json_str.size() - 1);
+}
+
+std::string GetIncompleteSnippet() {
+ std::string json_str = GetSnippet();
+ // Rename the "url" entry. The result is syntactically valid json that will
+ // fail to parse as snippets.
+ size_t pos = json_str.find("\"fullPageUrl\"");
+ if (pos == std::string::npos) {
+ NOTREACHED();
+ return std::string();
+ }
+ json_str[pos + 1] = 'x';
+ return json_str;
+}
+
+using ServeImageCallback = base::Callback<void(
+ const std::string&,
+ base::Callback<void(const std::string&, const gfx::Image&)>)>;
+
+void ServeOneByOneImage(
+ image_fetcher::ImageFetcherDelegate* notify,
+ const std::string& id,
+ base::Callback<void(const std::string&, const gfx::Image&)> callback) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, id, gfx::test::CreateImage(1, 1)));
+ notify->OnImageDataFetched(id, "1-by-1-image-data");
+}
+
+void ParseJson(
+ const std::string& json,
+ const ntp_snippets::NTPSnippetsFetcher::SuccessCallback& success_callback,
+ const ntp_snippets::NTPSnippetsFetcher::ErrorCallback& error_callback) {
+ base::JSONReader json_reader;
+ std::unique_ptr<base::Value> value = json_reader.ReadToValue(json);
+ if (value) {
+ success_callback.Run(std::move(value));
+ } else {
+ error_callback.Run(json_reader.GetErrorMessage());
+ }
+}
+
+// Factory for FakeURLFetcher objects that always generate errors.
+class FailingFakeURLFetcherFactory : public net::URLFetcherFactory {
+ public:
+ std::unique_ptr<net::URLFetcher> CreateURLFetcher(
+ int id, const GURL& url, net::URLFetcher::RequestType request_type,
+ net::URLFetcherDelegate* d) override {
+ return base::MakeUnique<net::FakeURLFetcher>(
+ url, d, /*response_data=*/std::string(), net::HTTP_NOT_FOUND,
+ net::URLRequestStatus::FAILED);
+ }
+};
+
+class MockScheduler : public NTPSnippetsScheduler {
+ public:
+ MOCK_METHOD2(Schedule,
+ bool(base::TimeDelta period_wifi,
+ base::TimeDelta period_fallback));
+ MOCK_METHOD0(Unschedule, bool());
+};
+
+class MockImageFetcher : public ImageFetcher {
+ public:
+ MOCK_METHOD1(SetImageFetcherDelegate, void(ImageFetcherDelegate*));
+ MOCK_METHOD1(SetDataUseServiceName, void(DataUseServiceName));
+ MOCK_METHOD3(
+ StartOrQueueNetworkRequest,
+ void(const std::string&,
+ const GURL&,
+ base::Callback<void(const std::string&, const gfx::Image&)>));
+};
+
+class FakeContentSuggestionsProviderObserver
+ : public ContentSuggestionsProvider::Observer {
+ public:
+ FakeContentSuggestionsProviderObserver()
+ : loaded_(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+ void OnNewSuggestions(ContentSuggestionsProvider* provider,
+ Category category,
+ std::vector<ContentSuggestion> suggestions) override {
+ suggestions_[category] = std::move(suggestions);
+ }
+
+ void OnCategoryStatusChanged(ContentSuggestionsProvider* provider,
+ Category category,
+ CategoryStatus new_status) override {
+ if (category.IsKnownCategory(KnownCategories::ARTICLES) &&
+ IsCategoryStatusAvailable(new_status)) {
+ loaded_.Signal();
+ }
+ statuses_[category] = new_status;
+ }
+
+ void OnSuggestionInvalidated(
+ ContentSuggestionsProvider* provider,
+ const ContentSuggestion::ID& suggestion_id) override {}
+
+ const std::map<Category, CategoryStatus, Category::CompareByID>& statuses()
+ const {
+ return statuses_;
+ }
+
+ CategoryStatus StatusForCategory(Category category) const {
+ auto it = statuses_.find(category);
+ if (it == statuses_.end()) {
+ return CategoryStatus::NOT_PROVIDED;
+ }
+ return it->second;
+ }
+
+ const std::vector<ContentSuggestion>& SuggestionsForCategory(
+ Category category) {
+ return suggestions_[category];
+ }
+
+ void WaitForLoad() { loaded_.Wait(); }
+ bool Loaded() { return loaded_.IsSignaled(); }
+
+ void Reset() {
+ loaded_.Reset();
+ statuses_.clear();
+ }
+
+ private:
+ base::WaitableEvent loaded_;
+ std::map<Category, CategoryStatus, Category::CompareByID> statuses_;
+ std::map<Category, std::vector<ContentSuggestion>, Category::CompareByID>
+ suggestions_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeContentSuggestionsProviderObserver);
+};
+
+class FakeImageDecoder : public image_fetcher::ImageDecoder {
+ public:
+ FakeImageDecoder() {}
+ ~FakeImageDecoder() override = default;
+ void DecodeImage(
+ const std::string& image_data,
+ const image_fetcher::ImageDecodedCallback& callback) override {
+ callback.Run(decoded_image_);
+ }
+
+ void SetDecodedImage(const gfx::Image& image) { decoded_image_ = image; }
+
+ private:
+ gfx::Image decoded_image_;
+};
+
+} // namespace
+
+class NTPSnippetsServiceTest : public ::testing::Test {
+ public:
+ NTPSnippetsServiceTest()
+ : params_manager_(ntp_snippets::kStudyName,
+ {{"content_suggestions_backend",
+ kTestContentSuggestionsServerEndpoint}}),
+ fake_url_fetcher_factory_(
+ /*default_factory=*/&failing_url_fetcher_factory_),
+ test_url_(kTestContentSuggestionsServerWithAPIKey),
+ user_classifier_(/*pref_service=*/nullptr),
+ image_fetcher_(nullptr),
+ image_decoder_(nullptr) {
+ NTPSnippetsService::RegisterProfilePrefs(utils_.pref_service()->registry());
+ RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry());
+
+ EXPECT_TRUE(database_dir_.CreateUniqueTempDir());
+ }
+
+ ~NTPSnippetsServiceTest() override {
+ // We need to run the message loop after deleting the database, because
+ // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task
+ // runner. Without this, we'd get reports of memory leaks.
+ base::RunLoop().RunUntilIdle();
+ }
+
+ std::unique_ptr<NTPSnippetsService> MakeSnippetsService(
+ bool set_empty_response = true) {
+ auto service = MakeSnippetsServiceWithoutInitialization();
+ WaitForSnippetsServiceInitialization(set_empty_response);
+ return service;
+ }
+
+ std::unique_ptr<NTPSnippetsService>
+ MakeSnippetsServiceWithoutInitialization() {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner(
+ base::ThreadTaskRunnerHandle::Get());
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_getter =
+ new net::TestURLRequestContextGetter(task_runner.get());
+
+ utils_.ResetSigninManager();
+ std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher =
+ base::MakeUnique<NTPSnippetsFetcher>(
+ utils_.fake_signin_manager(), fake_token_service_.get(),
+ std::move(request_context_getter), utils_.pref_service(),
+ &category_factory_, base::Bind(&ParseJson), kAPIKey);
+
+ utils_.fake_signin_manager()->SignIn("foo@bar.com");
+ snippets_fetcher->SetPersonalizationForTesting(
+ NTPSnippetsFetcher::Personalization::kNonPersonal);
+
+ auto image_fetcher = base::MakeUnique<NiceMock<MockImageFetcher>>();
+
+ image_fetcher_ = image_fetcher.get();
+ EXPECT_CALL(*image_fetcher, SetImageFetcherDelegate(_));
+ auto image_decoder = base::MakeUnique<FakeImageDecoder>();
+ image_decoder_ = image_decoder.get();
+ EXPECT_FALSE(observer_);
+ observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>();
+ return base::MakeUnique<NTPSnippetsService>(
+ observer_.get(), &category_factory_, utils_.pref_service(), "fr",
+ &user_classifier_, &scheduler_, std::move(snippets_fetcher),
+ std::move(image_fetcher), std::move(image_decoder),
+ base::MakeUnique<NTPSnippetsDatabase>(database_dir_.GetPath(),
+ task_runner),
+ base::MakeUnique<NTPSnippetsStatusService>(utils_.fake_signin_manager(),
+ utils_.pref_service()));
+ }
+
+ void WaitForSnippetsServiceInitialization(bool set_empty_response = true) {
+ EXPECT_TRUE(observer_);
+ EXPECT_FALSE(observer_->Loaded());
+
+ // Add an initial fetch response, as the service tries to fetch when there
+ // is nothing in the DB.
+ if (set_empty_response)
+ SetUpFetchResponse(GetTestJsonWithoutTitle(std::vector<std::string>()));
+
+ base::RunLoop().RunUntilIdle();
+ observer_->WaitForLoad();
+ }
+
+ void ResetSnippetsService(std::unique_ptr<NTPSnippetsService>* service) {
+ service->reset();
+ observer_.reset();
+ *service = MakeSnippetsService();
+ }
+
+ ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) {
+ return ContentSuggestion::ID(articles_category(), id_within_category);
+ }
+
+ Category articles_category() {
+ return category_factory_.FromKnownCategory(KnownCategories::ARTICLES);
+ }
+
+ ContentSuggestion::ID MakeOtherID(const std::string& id_within_category) {
+ return ContentSuggestion::ID(other_category(), id_within_category);
+ }
+
+ Category other_category() { return category_factory_.FromRemoteCategory(2); }
+
+ Category unknown_category() {
+ return category_factory_.FromRemoteCategory(kUnknownRemoteCategoryId);
+ }
+
+ protected:
+ const GURL& test_url() { return test_url_; }
+ FakeContentSuggestionsProviderObserver& observer() { return *observer_; }
+ MockScheduler& mock_scheduler() { return scheduler_; }
+ NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; }
+ FakeImageDecoder* image_decoder() { return image_decoder_; }
+
+ // Provide the json to be returned by the fake fetcher.
+ void SetUpFetchResponse(const std::string& json) {
+ fake_url_fetcher_factory_.SetFakeResponse(test_url_, json, net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ }
+
+ void LoadFromJSONString(NTPSnippetsService* service,
+ const std::string& json) {
+ SetUpFetchResponse(json);
+ service->FetchSnippets(true);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ private:
+ variations::testing::VariationParamsManager params_manager_;
+ test::NTPSnippetsTestUtils utils_;
+ base::MessageLoop message_loop_;
+ FailingFakeURLFetcherFactory failing_url_fetcher_factory_;
+ // Instantiation of factory automatically sets itself as URLFetcher's factory.
+ net::FakeURLFetcherFactory fake_url_fetcher_factory_;
+ const GURL test_url_;
+ std::unique_ptr<OAuth2TokenService> fake_token_service_;
+ UserClassifier user_classifier_;
+ NiceMock<MockScheduler> scheduler_;
+ std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_;
+ CategoryFactory category_factory_;
+ NiceMock<MockImageFetcher>* image_fetcher_;
+ FakeImageDecoder* image_decoder_;
+
+ base::ScopedTempDir database_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(NTPSnippetsServiceTest);
+};
+
+TEST_F(NTPSnippetsServiceTest, ScheduleOnStart) {
+ // We should get two |Schedule| calls: The first when initialization
+ // completes, the second one after the automatic (since the service doesn't
+ // have any data yet) fetch finishes.
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
+ EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0);
+ auto service = MakeSnippetsService();
+
+ // When we have no snippets are all, loading the service initiates a fetch.
+ EXPECT_EQ("OK", service->snippets_fetcher()->last_status());
+}
+
+TEST_F(NTPSnippetsServiceTest, DontRescheduleOnStart) {
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
+ EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0);
+ SetUpFetchResponse(GetTestJson({GetSnippet()}));
+ auto service = MakeSnippetsService(/*set_empty_response=*/false);
+
+ // When recreating the service, we should not get any |Schedule| calls:
+ // The tasks are already scheduled with the correct intervals, so nothing on
+ // initialization, and the service has data from the DB, so no automatic fetch
+ // should happen.
+ Mock::VerifyAndClearExpectations(&mock_scheduler());
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(0);
+ EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0);
+ ResetSnippetsService(&service);
+}
+
+TEST_F(NTPSnippetsServiceTest, RescheduleAfterSuccessfulFetch) {
+ // We should get two |Schedule| calls: The first when initialization
+ // completes, the second one after the automatic (since the service doesn't
+ // have any data yet) fetch finishes.
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
+ auto service = MakeSnippetsService();
+
+ // A successful fetch should trigger another |Schedule|.
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _));
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
+}
+
+TEST_F(NTPSnippetsServiceTest, DontRescheduleAfterFailedFetch) {
+ // We should get two |Schedule| calls: The first when initialization
+ // completes, the second one after the automatic (since the service doesn't
+ // have any data yet) fetch finishes.
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
+ auto service = MakeSnippetsService();
+
+ // A failed fetch should NOT trigger another |Schedule|.
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(0);
+ LoadFromJSONString(service.get(), GetTestJson({GetInvalidSnippet()}));
+}
+
+TEST_F(NTPSnippetsServiceTest, IgnoreRescheduleBeforeInit) {
+ // We should get two |Schedule| calls: The first when initialization
+ // completes, the second one after the automatic (since the service doesn't
+ // have any data yet) fetch finishes.
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
+ // The |RescheduleFetching| call shouldn't do anything (in particular not
+ // result in an |Unschedule|), since the service isn't initialized yet.
+ EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0);
+ auto service = MakeSnippetsServiceWithoutInitialization();
+ service->RescheduleFetching(false);
+ WaitForSnippetsServiceInitialization();
+}
+
+TEST_F(NTPSnippetsServiceTest, HandleForcedRescheduleBeforeInit) {
+ {
+ InSequence s;
+ // The |RescheduleFetching| call with force=true should result in an
+ // |Unschedule|, since the service isn't initialized yet.
+ EXPECT_CALL(mock_scheduler(), Unschedule()).Times(1);
+ // We should get two |Schedule| calls: The first when initialization
+ // completes, the second one after the automatic (since the service doesn't
+ // have any data yet) fetch finishes.
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
+ }
+ auto service = MakeSnippetsServiceWithoutInitialization();
+ service->RescheduleFetching(true);
+ WaitForSnippetsServiceInitialization();
+}
+
+TEST_F(NTPSnippetsServiceTest, RescheduleOnStateChange) {
+ {
+ InSequence s;
+ // Initial startup.
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
+ // Service gets disabled.
+ EXPECT_CALL(mock_scheduler(), Unschedule());
+ // Service gets enabled again.
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
+ }
+ auto service = MakeSnippetsService();
+ ASSERT_TRUE(service->ready());
+
+ service->OnSnippetsStatusChanged(SnippetsStatus::ENABLED_AND_SIGNED_IN,
+ SnippetsStatus::EXPLICITLY_DISABLED);
+ ASSERT_FALSE(service->ready());
+ base::RunLoop().RunUntilIdle();
+
+ service->OnSnippetsStatusChanged(SnippetsStatus::EXPLICITLY_DISABLED,
+ SnippetsStatus::ENABLED_AND_SIGNED_OUT);
+ ASSERT_TRUE(service->ready());
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(NTPSnippetsServiceTest, DontUnscheduleOnShutdown) {
+ EXPECT_CALL(mock_scheduler(), Schedule(_, _)).Times(2);
+ EXPECT_CALL(mock_scheduler(), Unschedule()).Times(0);
+
+ auto service = MakeSnippetsService();
+
+ service.reset();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(NTPSnippetsServiceTest, Full) {
+ std::string json_str(GetTestJson({GetSnippet()}));
+
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(), json_str);
+
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+ ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+
+ const ContentSuggestion& suggestion =
+ observer().SuggestionsForCategory(articles_category()).front();
+
+ EXPECT_EQ(MakeArticleID(kSnippetUrl), suggestion.id());
+ EXPECT_EQ(kSnippetTitle, base::UTF16ToUTF8(suggestion.title()));
+ EXPECT_EQ(kSnippetText, base::UTF16ToUTF8(suggestion.snippet_text()));
+ EXPECT_EQ(GetDefaultCreationTime(), suggestion.publish_date());
+ EXPECT_EQ(kSnippetPublisherName,
+ base::UTF16ToUTF8(suggestion.publisher_name()));
+ EXPECT_EQ(GURL(kSnippetAmpUrl), suggestion.amp_url());
+}
+
+TEST_F(NTPSnippetsServiceTest, CategoryTitle) {
+ const base::string16 response_title =
+ base::UTF8ToUTF16(kTestJsonDefaultCategoryTitle);
+
+ auto service = MakeSnippetsService();
+
+ // The articles category should be there by default, and have a title.
+ CategoryInfo info_before = service->GetCategoryInfo(articles_category());
+ ASSERT_FALSE(info_before.title().empty());
+ ASSERT_NE(info_before.title(), response_title);
+
+ std::string json_str_no_title(GetTestJsonWithoutTitle({GetSnippet()}));
+ LoadFromJSONString(service.get(), json_str_no_title);
+
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+ ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+
+ // The response didn't contain a category title. Make sure we didn't touch
+ // the existing one.
+ CategoryInfo info_no_title = service->GetCategoryInfo(articles_category());
+ EXPECT_EQ(info_before.title(), info_no_title.title());
+
+ std::string json_str_with_title(GetTestJson({GetSnippet()}));
+ LoadFromJSONString(service.get(), json_str_with_title);
+
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+ ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+
+ // This time, the response contained a title, |kTestJsonDefaultCategoryTitle|.
+ // Make sure we updated the title in the CategoryInfo.
+ CategoryInfo info_with_title = service->GetCategoryInfo(articles_category());
+ EXPECT_NE(info_before.title(), info_with_title.title());
+ EXPECT_EQ(response_title, info_with_title.title());
+}
+
+TEST_F(NTPSnippetsServiceTest, MultipleCategories) {
+ std::string json_str(
+ GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)}));
+
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(), json_str);
+
+ ASSERT_THAT(observer().statuses(),
+ Eq(std::map<Category, CategoryStatus, Category::CompareByID>{
+ {articles_category(), CategoryStatus::AVAILABLE},
+ {other_category(), CategoryStatus::AVAILABLE},
+ }));
+
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+ EXPECT_THAT(service->GetSnippetsForTesting(other_category()), SizeIs(1));
+
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+
+ ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1));
+
+ {
+ const ContentSuggestion& suggestion =
+ observer().SuggestionsForCategory(articles_category()).front();
+ EXPECT_EQ(MakeArticleID(std::string(kSnippetUrl) + "/0"), suggestion.id());
+ EXPECT_EQ(kSnippetTitle, base::UTF16ToUTF8(suggestion.title()));
+ EXPECT_EQ(kSnippetText, base::UTF16ToUTF8(suggestion.snippet_text()));
+ EXPECT_EQ(GetDefaultCreationTime(), suggestion.publish_date());
+ EXPECT_EQ(kSnippetPublisherName,
+ base::UTF16ToUTF8(suggestion.publisher_name()));
+ EXPECT_EQ(GURL(kSnippetAmpUrl), suggestion.amp_url());
+ }
+
+ {
+ const ContentSuggestion& suggestion =
+ observer().SuggestionsForCategory(other_category()).front();
+ EXPECT_EQ(MakeOtherID(std::string(kSnippetUrl) + "/1"), suggestion.id());
+ EXPECT_EQ(kSnippetTitle, base::UTF16ToUTF8(suggestion.title()));
+ EXPECT_EQ(kSnippetText, base::UTF16ToUTF8(suggestion.snippet_text()));
+ EXPECT_EQ(GetDefaultCreationTime(), suggestion.publish_date());
+ EXPECT_EQ(kSnippetPublisherName,
+ base::UTF16ToUTF8(suggestion.publisher_name()));
+ EXPECT_EQ(GURL(kSnippetAmpUrl), suggestion.amp_url());
+ }
+}
+
+TEST_F(NTPSnippetsServiceTest, PersistCategoryInfos) {
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(),
+ GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)},
+ kUnknownRemoteCategoryId));
+
+ ASSERT_EQ(observer().StatusForCategory(articles_category()),
+ CategoryStatus::AVAILABLE);
+ ASSERT_EQ(observer().StatusForCategory(unknown_category()),
+ CategoryStatus::AVAILABLE);
+
+ CategoryInfo info_articles_before =
+ service->GetCategoryInfo(articles_category());
+ CategoryInfo info_unknown_before =
+ service->GetCategoryInfo(unknown_category());
+
+ // Recreate the service to simulate a Chrome restart.
+ ResetSnippetsService(&service);
+
+ // The categories should have been restored.
+ ASSERT_NE(observer().StatusForCategory(articles_category()),
+ CategoryStatus::NOT_PROVIDED);
+ ASSERT_NE(observer().StatusForCategory(unknown_category()),
+ CategoryStatus::NOT_PROVIDED);
+
+ EXPECT_EQ(observer().StatusForCategory(articles_category()),
+ CategoryStatus::AVAILABLE);
+ EXPECT_EQ(observer().StatusForCategory(unknown_category()),
+ CategoryStatus::AVAILABLE);
+
+ CategoryInfo info_articles_after =
+ service->GetCategoryInfo(articles_category());
+ CategoryInfo info_unknown_after =
+ service->GetCategoryInfo(unknown_category());
+
+ EXPECT_EQ(info_articles_before.title(), info_articles_after.title());
+ EXPECT_EQ(info_unknown_before.title(), info_unknown_after.title());
+}
+
+TEST_F(NTPSnippetsServiceTest, PersistSuggestions) {
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(),
+ GetMultiCategoryJson({GetSnippetN(0)}, {GetSnippetN(1)}));
+
+ ASSERT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+ ASSERT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1));
+
+ // Recreate the service to simulate a Chrome restart.
+ ResetSnippetsService(&service);
+
+ // The suggestions in both categories should have been restored.
+ EXPECT_THAT(observer().SuggestionsForCategory(articles_category()),
+ SizeIs(1));
+ EXPECT_THAT(observer().SuggestionsForCategory(other_category()), SizeIs(1));
+}
+
+TEST_F(NTPSnippetsServiceTest, Clear) {
+ auto service = MakeSnippetsService();
+
+ std::string json_str(GetTestJson({GetSnippet()}));
+
+ LoadFromJSONString(service.get(), json_str);
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+
+ service->ClearCachedSuggestions(articles_category());
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, ReplaceSnippets) {
+ auto service = MakeSnippetsService();
+
+ std::string first("http://first");
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippetWithUrl(first)}));
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()),
+ ElementsAre(IdEq(first)));
+
+ std::string second("http://second");
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippetWithUrl(second)}));
+ // The snippets loaded last replace all that was loaded previously.
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()),
+ ElementsAre(IdEq(second)));
+}
+
+TEST_F(NTPSnippetsServiceTest, LoadInvalidJson) {
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(), GetTestJson({GetInvalidSnippet()}));
+ EXPECT_THAT(service->snippets_fetcher()->last_status(),
+ StartsWith("Received invalid JSON"));
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, LoadInvalidJsonWithExistingSnippets) {
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
+ ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+ ASSERT_EQ("OK", service->snippets_fetcher()->last_status());
+
+ LoadFromJSONString(service.get(), GetTestJson({GetInvalidSnippet()}));
+ EXPECT_THAT(service->snippets_fetcher()->last_status(),
+ StartsWith("Received invalid JSON"));
+ // This should not have changed the existing snippets.
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+}
+
+TEST_F(NTPSnippetsServiceTest, LoadIncompleteJson) {
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(), GetTestJson({GetIncompleteSnippet()}));
+ EXPECT_EQ("Invalid / empty list.",
+ service->snippets_fetcher()->last_status());
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, LoadIncompleteJsonWithExistingSnippets) {
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
+ ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+
+ LoadFromJSONString(service.get(), GetTestJson({GetIncompleteSnippet()}));
+ EXPECT_EQ("Invalid / empty list.",
+ service->snippets_fetcher()->last_status());
+ // This should not have changed the existing snippets.
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+}
+
+TEST_F(NTPSnippetsServiceTest, Dismiss) {
+ auto service = MakeSnippetsService();
+
+ std::string json_str(
+ GetTestJson({GetSnippetWithSources("http://site.com", "Source 1", "")}));
+
+ LoadFromJSONString(service.get(), json_str);
+
+ ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+
+ // Dismissing a non-existent snippet shouldn't do anything.
+ service->DismissSuggestion(MakeArticleID("http://othersite.com"));
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+
+ // Dismiss the snippet.
+ service->DismissSuggestion(MakeArticleID(kSnippetUrl));
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+
+ // Make sure that fetching the same snippet again does not re-add it.
+ LoadFromJSONString(service.get(), json_str);
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+
+ // The snippet should stay dismissed even after re-creating the service.
+ ResetSnippetsService(&service);
+ LoadFromJSONString(service.get(), json_str);
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+
+ // The snippet can be added again after clearing dismissed snippets.
+ service->ClearDismissedSuggestionsForDebugging(articles_category());
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+ LoadFromJSONString(service.get(), json_str);
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+}
+
+TEST_F(NTPSnippetsServiceTest, GetDismissed) {
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
+
+ service->DismissSuggestion(MakeArticleID(kSnippetUrl));
+
+ service->GetDismissedSuggestionsForDebugging(
+ articles_category(),
+ base::Bind(
+ [](NTPSnippetsService* service, NTPSnippetsServiceTest* test,
+ std::vector<ContentSuggestion> dismissed_suggestions) {
+ EXPECT_EQ(1u, dismissed_suggestions.size());
+ for (auto& suggestion : dismissed_suggestions) {
+ EXPECT_EQ(test->MakeArticleID(kSnippetUrl), suggestion.id());
+ }
+ },
+ service.get(), this));
+ base::RunLoop().RunUntilIdle();
+
+ // There should be no dismissed snippet after clearing the list.
+ service->ClearDismissedSuggestionsForDebugging(articles_category());
+ service->GetDismissedSuggestionsForDebugging(
+ articles_category(),
+ base::Bind(
+ [](NTPSnippetsService* service, NTPSnippetsServiceTest* test,
+ std::vector<ContentSuggestion> dismissed_suggestions) {
+ EXPECT_EQ(0u, dismissed_suggestions.size());
+ },
+ service.get(), this));
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(NTPSnippetsServiceTest, CreationTimestampParseFail) {
+ auto service = MakeSnippetsService();
+
+ std::string json =
+ GetSnippetWithTimes(GetDefaultCreationTime(), GetDefaultExpirationTime());
+ base::ReplaceFirstSubstringAfterOffset(
+ &json, 0, FormatTime(GetDefaultCreationTime()), "aaa1448459205");
+ std::string json_str(GetTestJson({json}));
+
+ LoadFromJSONString(service.get(), json_str);
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, RemoveExpiredDismissedContent) {
+ auto service = MakeSnippetsService();
+
+ std::string json_str1(GetTestJson({GetExpiredSnippet()}));
+ // Load it.
+ LoadFromJSONString(service.get(), json_str1);
+ // Dismiss the suggestion
+ service->DismissSuggestion(
+ ContentSuggestion::ID(articles_category(), kSnippetUrl));
+
+ // Load a different snippet - this will clear the expired dismissed ones.
+ std::string json_str2(GetTestJson({GetSnippetWithUrl(kSnippetUrl2)}));
+ LoadFromJSONString(service.get(), json_str2);
+
+ EXPECT_THAT(service->GetDismissedSnippetsForTesting(articles_category()),
+ IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, ExpiredContentNotRemoved) {
+ auto service = MakeSnippetsService();
+
+ std::string json_str(GetTestJson({GetExpiredSnippet()}));
+
+ LoadFromJSONString(service.get(), json_str);
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+}
+
+TEST_F(NTPSnippetsServiceTest, TestSingleSource) {
+ auto service = MakeSnippetsService();
+
+ std::string json_str(GetTestJson({GetSnippetWithSources(
+ "http://source1.com", "Source 1", "http://source1.amp.com")}));
+
+ LoadFromJSONString(service.get(), json_str);
+ ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+ const NTPSnippet& snippet =
+ *service->GetSnippetsForTesting(articles_category()).front();
+ EXPECT_EQ(snippet.sources().size(), 1u);
+ EXPECT_EQ(snippet.id(), kSnippetUrl);
+ EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com"));
+ EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1"));
+ EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com"));
+}
+
+TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMalformedUrl) {
+ auto service = MakeSnippetsService();
+
+ std::string json_str(GetTestJson({GetSnippetWithSources(
+ "ceci n'est pas un url", "Source 1", "http://source1.amp.com")}));
+
+ LoadFromJSONString(service.get(), json_str);
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMissingData) {
+ auto service = MakeSnippetsService();
+
+ std::string json_str(
+ GetTestJson({GetSnippetWithSources("http://source1.com", "", "")}));
+
+ LoadFromJSONString(service.get(), json_str);
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, LogNumArticlesHistogram) {
+ auto service = MakeSnippetsService();
+
+ base::HistogramTester tester;
+ LoadFromJSONString(service.get(), GetTestJson({GetInvalidSnippet()}));
+
+ EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
+
+ // Invalid JSON shouldn't contribute to NumArticlesFetched.
+ EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
+ IsEmpty());
+
+ // Valid JSON with empty list.
+ LoadFromJSONString(service.get(), GetTestJson(std::vector<std::string>()));
+ EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/2)));
+ EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
+
+ // Snippet list should be populated with size 1.
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
+ EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/2),
+ base::Bucket(/*min=*/1, /*count=*/1)));
+ EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
+ base::Bucket(/*min=*/1, /*count=*/1)));
+
+ // Duplicate snippet shouldn't increase the list size.
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
+ EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/2),
+ base::Bucket(/*min=*/1, /*count=*/2)));
+ EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
+ base::Bucket(/*min=*/1, /*count=*/2)));
+ EXPECT_THAT(
+ tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"),
+ IsEmpty());
+
+ // Dismissing a snippet should decrease the list size. This will only be
+ // logged after the next fetch.
+ service->DismissSuggestion(MakeArticleID(kSnippetUrl));
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
+ EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/3),
+ base::Bucket(/*min=*/1, /*count=*/2)));
+ // Dismissed snippets shouldn't influence NumArticlesFetched.
+ EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"),
+ ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
+ base::Bucket(/*min=*/1, /*count=*/3)));
+ EXPECT_THAT(
+ tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"),
+ ElementsAre(base::Bucket(/*min=*/1, /*count=*/1)));
+
+ // There is only a single, dismissed snippet in the database, so recreating
+ // the service will require us to re-fetch.
+ tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 4);
+ ResetSnippetsService(&service);
+ EXPECT_EQ(observer().StatusForCategory(articles_category()),
+ CategoryStatus::AVAILABLE);
+ tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 5);
+ EXPECT_THAT(
+ tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"),
+ ElementsAre(base::Bucket(/*min=*/1, /*count=*/2)));
+
+ // But if there's a non-dismissed snippet in the database, recreating it
+ // shouldn't trigger a fetch.
+ LoadFromJSONString(
+ service.get(),
+ GetTestJson({GetSnippetWithUrl("http://not-dismissed.com")}));
+ tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6);
+ ResetSnippetsService(&service);
+ tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 6);
+}
+
+TEST_F(NTPSnippetsServiceTest, DismissShouldRespectAllKnownUrls) {
+ auto service = MakeSnippetsService();
+
+ const base::Time creation = GetDefaultCreationTime();
+ const base::Time expiry = GetDefaultExpirationTime();
+ const std::vector<std::string> source_urls = {
+ "http://mashable.com/2016/05/11/stolen",
+ "http://www.aol.com/article/2016/05/stolen-doggie"};
+ const std::vector<std::string> publishers = {"Mashable", "AOL"};
+ const std::vector<std::string> amp_urls = {
+ "http://mashable-amphtml.googleusercontent.com/1",
+ "http://t2.gstatic.com/images?q=tbn:3"};
+
+ // Add the snippet from the mashable domain.
+ LoadFromJSONString(service.get(),
+ GetTestJson({GetSnippetWithUrlAndTimesAndSource(
+ source_urls, source_urls[0], creation, expiry,
+ publishers[0], amp_urls[0])}));
+ ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+ // Dismiss the snippet via the mashable source corpus ID.
+ service->DismissSuggestion(MakeArticleID(source_urls[0]));
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+
+ // The same article from the AOL domain should now be detected as dismissed.
+ LoadFromJSONString(service.get(),
+ GetTestJson({GetSnippetWithUrlAndTimesAndSource(
+ source_urls, source_urls[1], creation, expiry,
+ publishers[1], amp_urls[1])}));
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, StatusChanges) {
+ auto service = MakeSnippetsService();
+
+ // Simulate user signed out
+ SetUpFetchResponse(GetTestJson({GetSnippet()}));
+ service->OnSnippetsStatusChanged(SnippetsStatus::ENABLED_AND_SIGNED_IN,
+ SnippetsStatus::SIGNED_OUT_AND_DISABLED);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(observer().StatusForCategory(articles_category()),
+ Eq(CategoryStatus::SIGNED_OUT));
+ EXPECT_THAT(NTPSnippetsService::State::DISABLED, Eq(service->state_));
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()),
+ IsEmpty()); // No fetch should be made.
+
+ // Simulate user sign in. The service should be ready again and load snippets.
+ SetUpFetchResponse(GetTestJson({GetSnippet()}));
+ service->OnSnippetsStatusChanged(SnippetsStatus::SIGNED_OUT_AND_DISABLED,
+ SnippetsStatus::ENABLED_AND_SIGNED_IN);
+ EXPECT_THAT(observer().StatusForCategory(articles_category()),
+ Eq(CategoryStatus::AVAILABLE_LOADING));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(observer().StatusForCategory(articles_category()),
+ Eq(CategoryStatus::AVAILABLE));
+ EXPECT_THAT(NTPSnippetsService::State::READY, Eq(service->state_));
+ EXPECT_FALSE(service->GetSnippetsForTesting(articles_category()).empty());
+}
+
+TEST_F(NTPSnippetsServiceTest, ImageReturnedWithTheSameId) {
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
+
+ gfx::Image image;
+ MockFunction<void(const gfx::Image&)> image_fetched;
+ ServeImageCallback cb = base::Bind(&ServeOneByOneImage, service.get());
+ {
+ InSequence s;
+ EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
+ .WillOnce(WithArgs<0, 2>(Invoke(&cb, &ServeImageCallback::Run)));
+ EXPECT_CALL(image_fetched, Call(_)).WillOnce(SaveArg<0>(&image));
+ }
+
+ service->FetchSuggestionImage(
+ MakeArticleID(kSnippetUrl),
+ base::Bind(&MockFunction<void(const gfx::Image&)>::Call,
+ base::Unretained(&image_fetched)));
+ base::RunLoop().RunUntilIdle();
+ // Check that the image by ServeOneByOneImage is really served.
+ EXPECT_EQ(1, image.Width());
+}
+
+TEST_F(NTPSnippetsServiceTest, EmptyImageReturnedForNonExistentId) {
+ auto service = MakeSnippetsService();
+
+ // Create a non-empty image so that we can test the image gets updated.
+ gfx::Image image = gfx::test::CreateImage(1, 1);
+ MockFunction<void(const gfx::Image&)> image_fetched;
+ EXPECT_CALL(image_fetched, Call(_)).WillOnce(SaveArg<0>(&image));
+
+ service->FetchSuggestionImage(
+ MakeArticleID(kSnippetUrl2),
+ base::Bind(&MockFunction<void(const gfx::Image&)>::Call,
+ base::Unretained(&image_fetched)));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(image.IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, ClearHistoryRemovesAllSuggestions) {
+ auto service = MakeSnippetsService();
+
+ std::string first_snippet = GetSnippetWithUrl("http://url1.com");
+ std::string second_snippet = GetSnippetWithUrl("http://url2.com");
+ std::string json_str = GetTestJson({first_snippet, second_snippet});
+ LoadFromJSONString(service.get(), json_str);
+ ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(2));
+
+ service->DismissSuggestion(MakeArticleID("http://url1.com"));
+ ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+ ASSERT_THAT(service->GetDismissedSnippetsForTesting(articles_category()),
+ SizeIs(1));
+
+ base::Time begin = base::Time::FromTimeT(123),
+ end = base::Time::FromTimeT(456);
+ base::Callback<bool(const GURL& url)> filter;
+ service->ClearHistory(begin, end, filter);
+
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
+ EXPECT_THAT(service->GetDismissedSnippetsForTesting(articles_category()),
+ IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, SuggestionsFetchedOnSignInAndSignOut) {
+ auto service = MakeSnippetsService();
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(0));
+
+ // |MakeSnippetsService()| creates a service where user is signed in already,
+ // so we start by signing out.
+ SetUpFetchResponse(GetTestJson({GetSnippetN(1)}));
+ service->OnSnippetsStatusChanged(SnippetsStatus::ENABLED_AND_SIGNED_IN,
+ SnippetsStatus::ENABLED_AND_SIGNED_OUT);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
+
+ // Sign in to check a transition from signed out to signed in.
+ SetUpFetchResponse(GetTestJson({GetSnippetN(1), GetSnippetN(2)}));
+ service->OnSnippetsStatusChanged(SnippetsStatus::ENABLED_AND_SIGNED_OUT,
+ SnippetsStatus::ENABLED_AND_SIGNED_IN);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(2));
+}
+
+namespace {
+
+gfx::Image FetchImage(NTPSnippetsService* service,
+ const ContentSuggestion::ID& suggestion_id) {
+ gfx::Image result;
+ base::RunLoop run_loop;
+ service->FetchSuggestionImage(suggestion_id,
+ base::Bind(
+ [](base::Closure signal, gfx::Image* output,
+ const gfx::Image& loaded) {
+ *output = loaded;
+ signal.Run();
+ },
+ run_loop.QuitClosure(), &result));
+ run_loop.Run();
+ return result;
+}
+
+} // namespace
+
+TEST_F(NTPSnippetsServiceTest, ShouldClearOrphanedImagesOnRestart) {
+ auto service = MakeSnippetsService();
+
+ LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
+ ServeImageCallback cb = base::Bind(&ServeOneByOneImage, service.get());
+
+ EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
+ .WillOnce(WithArgs<0, 2>(Invoke(&cb, &ServeImageCallback::Run)));
+ image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
+
+ gfx::Image image = FetchImage(service.get(), MakeArticleID(kSnippetUrl));
+ EXPECT_EQ(1, image.Width());
+ EXPECT_FALSE(image.IsEmpty());
+
+ // Send new suggestion which don't include the snippet referencing the image.
+ LoadFromJSONString(service.get(),
+ GetTestJson({GetSnippetWithUrl(
+ "http://something.com/pletely/unrelated")}));
+ // The image should still be available until a restart happens.
+ EXPECT_FALSE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty());
+ ResetSnippetsService(&service);
+ // After the restart, the image should be garbage collected.
+ EXPECT_TRUE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty());
+}
+
+TEST_F(NTPSnippetsServiceTest, ShouldHandleMoreThanMaxSnippetsInResponse) {
+ auto service = MakeSnippetsService();
+
+ std::vector<std::string> suggestions;
+ for (int i = 0 ; i < service->GetMaxSnippetCountForTesting() + 1; ++i) {
+ suggestions.push_back(GetSnippetWithUrl(
+ base::StringPrintf("http://localhost/snippet-id-%d", i)));
+ }
+ LoadFromJSONString(service.get(), GetTestJson(suggestions));
+ // TODO(tschumann): We should probably trim out any additional results and
+ // only serve the MaxSnippetCount items.
+ EXPECT_THAT(service->GetSnippetsForTesting(articles_category()),
+ SizeIs(service->GetMaxSnippetCountForTesting() + 1));
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_status_service.cc b/chromium/components/ntp_snippets/remote/ntp_snippets_status_service.cc
new file mode 100644
index 00000000000..62514d270b1
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_status_service.cc
@@ -0,0 +1,119 @@
+// 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 "components/ntp_snippets/remote/ntp_snippets_status_service.h"
+
+#include <string>
+
+#include "components/ntp_snippets/features.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/variations/variations_associated_data.h"
+
+namespace ntp_snippets {
+
+namespace {
+
+const char kFetchingRequiresSignin[] = "fetching_requires_signin";
+const char kFetchingRequiresSigninEnabled[] = "true";
+const char kFetchingRequiresSigninDisabled[] = "false";
+
+} // namespace
+
+NTPSnippetsStatusService::NTPSnippetsStatusService(
+ SigninManagerBase* signin_manager,
+ PrefService* pref_service)
+ : snippets_status_(SnippetsStatus::EXPLICITLY_DISABLED),
+ require_signin_(false),
+ signin_manager_(signin_manager),
+ pref_service_(pref_service),
+ signin_observer_(this) {
+ std::string param_value_str = variations::GetVariationParamValueByFeature(
+ kArticleSuggestionsFeature, kFetchingRequiresSignin);
+ if (param_value_str == kFetchingRequiresSigninEnabled) {
+ require_signin_ = true;
+ } else if (!param_value_str.empty() &&
+ param_value_str != kFetchingRequiresSigninDisabled) {
+ DLOG(WARNING) << "Unknow value for the variations parameter "
+ << kFetchingRequiresSignin << ": " << param_value_str;
+ }
+}
+
+NTPSnippetsStatusService::~NTPSnippetsStatusService() = default;
+
+// static
+void NTPSnippetsStatusService::RegisterProfilePrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterBooleanPref(prefs::kEnableSnippets, true);
+}
+
+void NTPSnippetsStatusService::Init(
+ const SnippetsStatusChangeCallback& callback) {
+ DCHECK(snippets_status_change_callback_.is_null());
+
+ snippets_status_change_callback_ = callback;
+
+ // Notify about the current state before registering the observer, to make
+ // sure we don't get a double notification due to an undefined start state.
+ SnippetsStatus old_snippets_status = snippets_status_;
+ snippets_status_ = GetSnippetsStatusFromDeps();
+ snippets_status_change_callback_.Run(old_snippets_status, snippets_status_);
+
+ signin_observer_.Add(signin_manager_);
+
+ pref_change_registrar_.Init(pref_service_);
+ pref_change_registrar_.Add(
+ prefs::kEnableSnippets,
+ base::Bind(&NTPSnippetsStatusService::OnSnippetsEnabledChanged,
+ base::Unretained(this)));
+}
+
+void NTPSnippetsStatusService::OnSnippetsEnabledChanged() {
+ OnStateChanged(GetSnippetsStatusFromDeps());
+}
+
+void NTPSnippetsStatusService::OnStateChanged(
+ SnippetsStatus new_snippets_status) {
+ if (new_snippets_status == snippets_status_)
+ return;
+
+ snippets_status_change_callback_.Run(snippets_status_, new_snippets_status);
+ snippets_status_ = new_snippets_status;
+}
+
+bool NTPSnippetsStatusService::IsSignedIn() const {
+ return signin_manager_ && signin_manager_->IsAuthenticated();
+}
+
+void NTPSnippetsStatusService::GoogleSigninSucceeded(
+ const std::string& account_id,
+ const std::string& username,
+ const std::string& password) {
+ OnStateChanged(GetSnippetsStatusFromDeps());
+}
+
+void NTPSnippetsStatusService::GoogleSignedOut(const std::string& account_id,
+ const std::string& username) {
+ OnStateChanged(GetSnippetsStatusFromDeps());
+}
+
+SnippetsStatus NTPSnippetsStatusService::GetSnippetsStatusFromDeps() const {
+ if (!pref_service_->GetBoolean(prefs::kEnableSnippets)) {
+ DVLOG(1) << "[GetNewSnippetsStatus] Disabled via pref";
+ return SnippetsStatus::EXPLICITLY_DISABLED;
+ }
+
+ if (require_signin_ && !IsSignedIn()) {
+ DVLOG(1) << "[GetNewSnippetsStatus] Signed out and disabled due to this.";
+ return SnippetsStatus::SIGNED_OUT_AND_DISABLED;
+ }
+
+ DVLOG(1) << "[GetNewSnippetsStatus] Enabled, signed "
+ << (IsSignedIn() ? "in" : "out");
+ return IsSignedIn() ? SnippetsStatus::ENABLED_AND_SIGNED_IN
+ : SnippetsStatus::ENABLED_AND_SIGNED_OUT;
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_status_service.h b/chromium/components/ntp_snippets/remote/ntp_snippets_status_service.h
new file mode 100644
index 00000000000..2f8f47a7635
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_status_service.h
@@ -0,0 +1,86 @@
+// 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 COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_STATUS_SERVICE_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_STATUS_SERVICE_H_
+
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/scoped_observer.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/signin/core/browser/signin_manager.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace ntp_snippets {
+
+enum class SnippetsStatus : int {
+ // Snippets are enabled and the user is signed in.
+ ENABLED_AND_SIGNED_IN,
+ // Snippets are enabled and the user is signed out (sign in is not required).
+ ENABLED_AND_SIGNED_OUT,
+ // Snippets have been disabled as part of the service configuration.
+ EXPLICITLY_DISABLED,
+ // The user is not signed in, and the service requires it to be enabled.
+ SIGNED_OUT_AND_DISABLED,
+};
+
+// Aggregates data from preferences and signin to notify the snippet service of
+// relevant changes in their states.
+class NTPSnippetsStatusService : public SigninManagerBase::Observer {
+ public:
+ using SnippetsStatusChangeCallback =
+ base::Callback<void(SnippetsStatus /*old_status*/,
+ SnippetsStatus /*new_status*/)>;
+
+ NTPSnippetsStatusService(SigninManagerBase* signin_manager,
+ PrefService* pref_service);
+
+ ~NTPSnippetsStatusService() override;
+
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ // Starts listening for changes from the dependencies. |callback| will be
+ // called when a significant change in state is detected.
+ void Init(const SnippetsStatusChangeCallback& callback);
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(NTPSnippetsStatusServiceTest, DisabledViaPref);
+
+ // SigninManagerBase::Observer implementation
+ void GoogleSigninSucceeded(const std::string& account_id,
+ const std::string& username,
+ const std::string& password) override;
+ void GoogleSignedOut(const std::string& account_id,
+ const std::string& username) override;
+
+ // Callback for the PrefChangeRegistrar.
+ void OnSnippetsEnabledChanged();
+
+ void OnStateChanged(SnippetsStatus new_snippets_status);
+
+ bool IsSignedIn() const;
+
+ SnippetsStatus GetSnippetsStatusFromDeps() const;
+
+ SnippetsStatus snippets_status_;
+ SnippetsStatusChangeCallback snippets_status_change_callback_;
+
+ bool require_signin_;
+ SigninManagerBase* signin_manager_;
+ PrefService* pref_service_;
+
+ PrefChangeRegistrar pref_change_registrar_;
+
+ // The observer for the SigninManager.
+ ScopedObserver<SigninManagerBase, SigninManagerBase::Observer>
+ signin_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(NTPSnippetsStatusService);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_STATUS_SERVICE_H_
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_status_service_unittest.cc b/chromium/components/ntp_snippets/remote/ntp_snippets_status_service_unittest.cc
new file mode 100644
index 00000000000..827f7de45ff
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_status_service_unittest.cc
@@ -0,0 +1,59 @@
+// 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 "components/ntp_snippets/remote/ntp_snippets_status_service.h"
+
+#include <memory>
+
+#include "components/ntp_snippets/pref_names.h"
+#include "components/ntp_snippets/remote/ntp_snippets_test_utils.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/signin/core/browser/test_signin_client.h"
+#include "components/signin/core/common/signin_pref_names.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ntp_snippets {
+
+class NTPSnippetsStatusServiceTest : public ::testing::Test {
+ public:
+ NTPSnippetsStatusServiceTest() {
+ NTPSnippetsStatusService::RegisterProfilePrefs(
+ utils_.pref_service()->registry());
+ }
+
+ std::unique_ptr<NTPSnippetsStatusService> MakeService() {
+ return base::MakeUnique<NTPSnippetsStatusService>(
+ utils_.fake_signin_manager(), utils_.pref_service());
+ }
+
+ protected:
+ test::NTPSnippetsTestUtils utils_;
+};
+
+// TODO(jkrcal): Extend the ways to override variation parameters in unit-test
+// (bug 645447), and recover the SigninStateCompatibility test that sign-in is
+// required when the parameter is overriden.
+TEST_F(NTPSnippetsStatusServiceTest, DisabledViaPref) {
+ auto service = MakeService();
+
+ // The default test setup is signed out. The service is enabled.
+ ASSERT_EQ(SnippetsStatus::ENABLED_AND_SIGNED_OUT,
+ service->GetSnippetsStatusFromDeps());
+
+ // Once the enabled pref is set to false, we should be disabled.
+ utils_.pref_service()->SetBoolean(prefs::kEnableSnippets, false);
+ EXPECT_EQ(SnippetsStatus::EXPLICITLY_DISABLED,
+ service->GetSnippetsStatusFromDeps());
+
+ // Signing-in shouldn't matter anymore.
+ utils_.fake_signin_manager()->SignIn("foo@bar.com");
+ EXPECT_EQ(SnippetsStatus::EXPLICITLY_DISABLED,
+ service->GetSnippetsStatusFromDeps());
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_test_utils.cc b/chromium/components/ntp_snippets/remote/ntp_snippets_test_utils.cc
new file mode 100644
index 00000000000..cdcb4501b14
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_test_utils.cc
@@ -0,0 +1,71 @@
+// 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 "components/ntp_snippets/remote/ntp_snippets_test_utils.h"
+
+#include <memory>
+
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/signin/core/browser/test_signin_client.h"
+#include "components/signin/core/common/signin_pref_names.h"
+#include "components/sync/driver/fake_sync_service.h"
+
+namespace ntp_snippets {
+namespace test {
+
+FakeSyncService::FakeSyncService()
+ : can_sync_start_(true),
+ is_sync_active_(true),
+ configuration_done_(true),
+ is_encrypt_everything_enabled_(false),
+ active_data_types_(syncer::HISTORY_DELETE_DIRECTIVES) {}
+
+FakeSyncService::~FakeSyncService() = default;
+
+bool FakeSyncService::CanSyncStart() const {
+ return can_sync_start_;
+}
+
+bool FakeSyncService::IsSyncActive() const {
+ return is_sync_active_;
+}
+
+bool FakeSyncService::ConfigurationDone() const {
+ return configuration_done_;
+}
+
+bool FakeSyncService::IsEncryptEverythingEnabled() const {
+ return is_encrypt_everything_enabled_;
+}
+
+syncer::ModelTypeSet FakeSyncService::GetActiveDataTypes() const {
+ return active_data_types_;
+}
+
+NTPSnippetsTestUtils::NTPSnippetsTestUtils()
+ : pref_service_(new TestingPrefServiceSimple()) {
+ pref_service_->registry()->RegisterStringPref(prefs::kGoogleServicesAccountId,
+ std::string());
+ pref_service_->registry()->RegisterStringPref(
+ prefs::kGoogleServicesLastAccountId, std::string());
+ pref_service_->registry()->RegisterStringPref(
+ prefs::kGoogleServicesLastUsername, std::string());
+ signin_client_.reset(new TestSigninClient(pref_service_.get()));
+ account_tracker_.reset(new AccountTrackerService());
+ fake_sync_service_.reset(new FakeSyncService());
+ ResetSigninManager();
+}
+
+NTPSnippetsTestUtils::~NTPSnippetsTestUtils() = default;
+
+void NTPSnippetsTestUtils::ResetSigninManager() {
+ fake_signin_manager_.reset(
+ new FakeSigninManagerBase(signin_client_.get(), account_tracker_.get()));
+}
+
+} // namespace test
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/ntp_snippets_test_utils.h b/chromium/components/ntp_snippets/remote/ntp_snippets_test_utils.h
new file mode 100644
index 00000000000..2a61b3d037e
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/ntp_snippets_test_utils.h
@@ -0,0 +1,66 @@
+// 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 COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_TEST_UTILS_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_TEST_UTILS_H_
+
+#include <memory>
+
+#include "components/sync/driver/fake_sync_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class AccountTrackerService;
+class FakeSigninManagerBase;
+class MockSyncService;
+class TestingPrefServiceSimple;
+class TestSigninClient;
+
+namespace ntp_snippets {
+namespace test {
+
+class FakeSyncService : public syncer::FakeSyncService {
+ public:
+ FakeSyncService();
+ ~FakeSyncService() override;
+
+ bool CanSyncStart() const override;
+ bool IsSyncActive() const override;
+ bool ConfigurationDone() const override;
+ bool IsEncryptEverythingEnabled() const override;
+ syncer::ModelTypeSet GetActiveDataTypes() const override;
+
+ bool can_sync_start_;
+ bool is_sync_active_;
+ bool configuration_done_;
+ bool is_encrypt_everything_enabled_;
+ syncer::ModelTypeSet active_data_types_;
+};
+
+// Common utilities for snippet tests, handles initializing fakes for sync and
+// signin.
+class NTPSnippetsTestUtils {
+ public:
+ NTPSnippetsTestUtils();
+ ~NTPSnippetsTestUtils();
+
+ void ResetSigninManager();
+
+ FakeSyncService* fake_sync_service() { return fake_sync_service_.get(); }
+ FakeSigninManagerBase* fake_signin_manager() {
+ return fake_signin_manager_.get();
+ }
+ TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
+
+ private:
+ std::unique_ptr<FakeSigninManagerBase> fake_signin_manager_;
+ std::unique_ptr<FakeSyncService> fake_sync_service_;
+ std::unique_ptr<TestingPrefServiceSimple> pref_service_;
+ std::unique_ptr<TestSigninClient> signin_client_;
+ std::unique_ptr<AccountTrackerService> account_tracker_;
+};
+
+} // namespace test
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_NTP_SNIPPETS_TEST_UTILS_H_
diff --git a/chromium/components/ntp_snippets/proto/BUILD.gn b/chromium/components/ntp_snippets/remote/proto/BUILD.gn
index 95ba1796625..95ba1796625 100644
--- a/chromium/components/ntp_snippets/proto/BUILD.gn
+++ b/chromium/components/ntp_snippets/remote/proto/BUILD.gn
diff --git a/chromium/components/ntp_snippets/remote/proto/ntp_snippets.proto b/chromium/components/ntp_snippets/remote/proto/ntp_snippets.proto
new file mode 100644
index 00000000000..d51c774810f
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/proto/ntp_snippets.proto
@@ -0,0 +1,32 @@
+// 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package ntp_snippets;
+
+message SnippetSourceProto {
+ optional string url = 1;
+ optional string publisher_name = 2;
+ optional string amp_url = 3;
+}
+
+message SnippetProto {
+ optional string id = 1;
+ optional string title = 2;
+ optional string snippet = 3;
+ optional string salient_image_url = 4;
+ optional int64 publish_date = 5;
+ optional int64 expiry_date = 6;
+ optional float score = 7;
+ repeated SnippetSourceProto sources = 8;
+ optional bool dismissed = 9;
+ optional int32 remote_category_id = 10;
+}
+
+message SnippetImageProto {
+ optional bytes data = 1;
+}
diff --git a/chromium/components/ntp_snippets/remote/request_throttler.cc b/chromium/components/ntp_snippets/remote/request_throttler.cc
new file mode 100644
index 00000000000..b6d3bbbf536
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/request_throttler.cc
@@ -0,0 +1,192 @@
+// 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 "components/ntp_snippets/remote/request_throttler.h"
+
+#include <climits>
+#include <vector>
+
+#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "components/ntp_snippets/ntp_snippets_constants.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/variations/variations_associated_data.h"
+
+namespace ntp_snippets {
+
+namespace {
+
+// Enumeration listing all possible outcomes for fetch attempts. Used for UMA
+// histogram, so do not change existing values. Insert new values at the end,
+// and update the histogram definition.
+enum class RequestStatus {
+ INTERACTIVE_QUOTA_GRANTED,
+ BACKGROUND_QUOTA_GRANTED,
+ BACKGROUND_QUOTA_EXCEEDED,
+ INTERACTIVE_QUOTA_EXCEEDED,
+ REQUEST_STATUS_COUNT
+};
+
+// Quota value to use if no quota should be applied (by default).
+const int kUnlimitedQuota = INT_MAX;
+
+} // namespace
+
+struct RequestThrottler::RequestTypeInfo {
+ const char* name;
+ const char* count_pref;
+ const char* interactive_count_pref;
+ const char* day_pref;
+ const int default_quota;
+ const int default_interactive_quota;
+};
+
+// When adding a new type here, extend also the "RequestThrottlerTypes"
+// <histogram_suffixes> in histograms.xml with the |name| string.
+const RequestThrottler::RequestTypeInfo RequestThrottler::kRequestTypeInfo[] = {
+ // RequestCounter::RequestType::CONTENT_SUGGESTION_FETCHER,
+ {"SuggestionFetcher", prefs::kSnippetFetcherRequestCount,
+ prefs::kSnippetFetcherInteractiveRequestCount,
+ prefs::kSnippetFetcherRequestsDay, 50, kUnlimitedQuota},
+ // RequestCounter::RequestType::CONTENT_SUGGESTION_THUMBNAIL,
+ {"SuggestionThumbnailFetcher", prefs::kSnippetThumbnailsRequestCount,
+ prefs::kSnippetThumbnailsInteractiveRequestCount,
+ prefs::kSnippetThumbnailsRequestsDay, kUnlimitedQuota, kUnlimitedQuota}};
+
+RequestThrottler::RequestThrottler(PrefService* pref_service, RequestType type)
+ : pref_service_(pref_service),
+ type_info_(kRequestTypeInfo[static_cast<int>(type)]) {
+ DCHECK(pref_service);
+
+ std::string quota = variations::GetVariationParamValue(
+ ntp_snippets::kStudyName,
+ base::StringPrintf("quota_%s", GetRequestTypeName()));
+ if (!base::StringToInt(quota, &quota_)) {
+ LOG_IF(WARNING, !quota.empty())
+ << "Invalid variation parameter for quota for "
+ << GetRequestTypeName();
+ quota_ = type_info_.default_quota;
+ }
+
+ std::string interactive_quota = variations::GetVariationParamValue(
+ ntp_snippets::kStudyName,
+ base::StringPrintf("interactive_quota_%s", GetRequestTypeName()));
+ if (!base::StringToInt(interactive_quota, &interactive_quota_)) {
+ LOG_IF(WARNING, !interactive_quota.empty())
+ << "Invalid variation parameter for interactive quota for "
+ << GetRequestTypeName();
+ interactive_quota_ = type_info_.default_interactive_quota;
+ }
+
+ // Since the histogram names are dynamic, we cannot use the standard macros
+ // and we need to lookup the histograms, instead.
+ int status_count = static_cast<int>(RequestStatus::REQUEST_STATUS_COUNT);
+ // Corresponds to UMA_HISTOGRAM_ENUMERATION(name, sample, |status_count|).
+ histogram_request_status_ = base::LinearHistogram::FactoryGet(
+ base::StringPrintf("NewTabPage.RequestThrottler.RequestStatus_%s",
+ GetRequestTypeName()),
+ 1, status_count, status_count + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ // Corresponds to UMA_HISTOGRAM_COUNTS_100(name, sample).
+ histogram_per_day_background_ = base::Histogram::FactoryGet(
+ base::StringPrintf("NewTabPage.RequestThrottler.PerDay_%s",
+ GetRequestTypeName()),
+ 1, 100, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
+ // Corresponds to UMA_HISTOGRAM_COUNTS_100(name, sample).
+ histogram_per_day_interactive_ = base::Histogram::FactoryGet(
+ base::StringPrintf("NewTabPage.RequestThrottler.PerDayInteractive_%s",
+ GetRequestTypeName()),
+ 1, 100, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
+}
+
+// static
+void RequestThrottler::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+ for (const RequestTypeInfo& info : kRequestTypeInfo) {
+ registry->RegisterIntegerPref(info.count_pref, 0);
+ registry->RegisterIntegerPref(info.interactive_count_pref, 0);
+ registry->RegisterIntegerPref(info.day_pref, 0);
+ }
+}
+
+bool RequestThrottler::DemandQuotaForRequest(bool interactive_request) {
+ ResetCounterIfDayChanged();
+
+ int new_count = GetCount(interactive_request) + 1;
+ SetCount(interactive_request, new_count);
+ bool available = (new_count <= GetQuota(interactive_request));
+
+ if (interactive_request) {
+ histogram_request_status_->Add(static_cast<int>(
+ available ? RequestStatus::INTERACTIVE_QUOTA_GRANTED
+ : RequestStatus::INTERACTIVE_QUOTA_EXCEEDED));
+ } else {
+ histogram_request_status_->Add(
+ static_cast<int>(available ? RequestStatus::BACKGROUND_QUOTA_GRANTED
+ : RequestStatus::BACKGROUND_QUOTA_EXCEEDED));
+ }
+ return available;
+}
+
+void RequestThrottler::ResetCounterIfDayChanged() {
+ // Get the date, "concatenated" into an int in "YYYYMMDD" format.
+ base::Time::Exploded now_exploded;
+ base::Time::Now().LocalExplode(&now_exploded);
+ int now_day = 10000 * now_exploded.year + 100 * now_exploded.month +
+ now_exploded.day_of_month;
+
+ if (!HasDay()) {
+ // The counter is used for the first time in this profile.
+ SetDay(now_day);
+ } else if (now_day != GetDay()) {
+ // Day has changed - report the number of requests from the previous day.
+ histogram_per_day_background_->Add(GetCount(/*interactive_request=*/false));
+ histogram_per_day_interactive_->Add(GetCount(/*interactive_request=*/true));
+ // Reset the counters.
+ SetCount(/*interactive_request=*/false, 0);
+ SetCount(/*interactive_request=*/true, 0);
+ SetDay(now_day);
+ }
+}
+
+const char* RequestThrottler::GetRequestTypeName() const {
+ return type_info_.name;
+}
+
+// TODO(jkrcal): turn RequestTypeInfo into a proper class, move those methods
+// onto the class and hide the members.
+int RequestThrottler::GetQuota(bool interactive_request) const {
+ return interactive_request ? interactive_quota_ : quota_;
+}
+
+int RequestThrottler::GetCount(bool interactive_request) const {
+ return pref_service_->GetInteger(interactive_request
+ ? type_info_.interactive_count_pref
+ : type_info_.count_pref);
+}
+
+void RequestThrottler::SetCount(bool interactive_request, int count) {
+ pref_service_->SetInteger(interactive_request
+ ? type_info_.interactive_count_pref
+ : type_info_.count_pref,
+ count);
+}
+
+int RequestThrottler::GetDay() const {
+ return pref_service_->GetInteger(type_info_.day_pref);
+}
+
+void RequestThrottler::SetDay(int day) {
+ pref_service_->SetInteger(type_info_.day_pref, day);
+}
+
+bool RequestThrottler::HasDay() const {
+ return pref_service_->HasPrefPath(type_info_.day_pref);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/remote/request_throttler.h b/chromium/components/ntp_snippets/remote/request_throttler.h
new file mode 100644
index 00000000000..30c2dd557c5
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/request_throttler.h
@@ -0,0 +1,96 @@
+// 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 COMPONENTS_NTP_SNIPPETS_REMOTE_REQUEST_THROTTLER_H_
+#define COMPONENTS_NTP_SNIPPETS_REMOTE_REQUEST_THROTTLER_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace base {
+class HistogramBase;
+} // namespace base
+
+namespace ntp_snippets {
+
+// Counts requests to external services, compares them to a daily quota, reports
+// them to UMA. In the application code, create one local instance for each type
+// of requests, identified by the RequestType. The request counter is based on:
+// - daily quota from a variation param "quota_|type|" in the NTPSnippets trial
+// - pref "ntp.request_throttler.|type|.count" to store the current counter,
+// - pref "ntp.request_throttler.|type|.day" to store current day to which the
+// current counter value applies.
+// Furthermore the counter reports to histograms:
+// - "NewTabPage.RequestThrottler.RequestStatus_|type|" - status of each
+// request;
+// - "NewTabPage.RequestThrottler.PerDay_|type|" - the daily count of requests.
+//
+// Implementation notes: When extending this class for a new RequestType, please
+// 1) define in request_counter.cc in kRequestTypeInfo
+// a) the string value for your |type| and
+// b) constants for day/count prefs;
+// 2) define a new RequestThrottlerTypes histogram suffix in histogram.xml
+// (with the same string value as in 1a)).
+class RequestThrottler {
+ public:
+ // Enumeration listing all current applications of the request counter.
+ enum class RequestType {
+ CONTENT_SUGGESTION_FETCHER,
+ CONTENT_SUGGESTION_THUMBNAIL,
+ };
+
+ RequestThrottler(PrefService* pref_service, RequestType type);
+
+ // Registers profile prefs for all RequestTypes. Called from browser_prefs.cc.
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ // Returns whether quota is available for another request and reports this
+ // information to UMA. Interactive requests should be always granted (upon
+ // standard conditions) and should be only used for requests initiated by the
+ // user (if it is safe to assume that all users cannot generate an amount of
+ // requests we cannot handle).
+ bool DemandQuotaForRequest(bool interactive_request);
+
+ private:
+ friend class RequestThrottlerTest;
+ // Used internally for working with a RequestType.
+ struct RequestTypeInfo;
+
+ // The array of info entries - one per each RequestType.
+ static const RequestTypeInfo kRequestTypeInfo[];
+
+ // Also emits the PerDay histogram if the day changed.
+ void ResetCounterIfDayChanged();
+
+ const char* GetRequestTypeName() const;
+
+ int GetQuota(bool interactive_request) const;
+ int GetCount(bool interactive_request) const;
+ void SetCount(bool interactive_request, int count);
+ int GetDay() const;
+ void SetDay(int day);
+ bool HasDay() const;
+
+ PrefService* pref_service_;
+ const RequestTypeInfo& type_info_;
+
+ // The quotas are hardcoded, but can be overridden by variation params.
+ int quota_;
+ int interactive_quota_;
+
+ // The histograms for reporting the requests of the given |type_|.
+ base::HistogramBase* histogram_request_status_;
+ base::HistogramBase* histogram_per_day_background_;
+ base::HistogramBase* histogram_per_day_interactive_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestThrottler);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_REMOTE_REQUEST_THROTTLER_H_
diff --git a/chromium/components/ntp_snippets/remote/request_throttler_unittest.cc b/chromium/components/ntp_snippets/remote/request_throttler_unittest.cc
new file mode 100644
index 00000000000..79eca3b0b88
--- /dev/null
+++ b/chromium/components/ntp_snippets/remote/request_throttler_unittest.cc
@@ -0,0 +1,72 @@
+// 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 "components/ntp_snippets/remote/request_throttler.h"
+
+#include <memory>
+
+#include "base/strings/stringprintf.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const int kCounterQuota = 2;
+} // namespace
+
+namespace ntp_snippets {
+
+class RequestThrottlerTest : public testing::Test {
+ public:
+ RequestThrottlerTest() {
+ RequestThrottler::RegisterProfilePrefs(test_prefs_.registry());
+ // Use any arbitrary RequestType for this unittest.
+ throttler_.reset(new RequestThrottler(
+ &test_prefs_,
+ RequestThrottler::RequestType::CONTENT_SUGGESTION_FETCHER));
+ throttler_->quota_ = kCounterQuota;
+ }
+
+ protected:
+ TestingPrefServiceSimple test_prefs_;
+ std::unique_ptr<RequestThrottler> throttler_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RequestThrottlerTest);
+};
+
+TEST_F(RequestThrottlerTest, QuotaExceeded) {
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(false));
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(false));
+ EXPECT_FALSE(throttler_->DemandQuotaForRequest(false));
+}
+
+TEST_F(RequestThrottlerTest, ForcedDoesNotCountInQuota) {
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(false));
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(true));
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(false));
+}
+
+TEST_F(RequestThrottlerTest, ForcedWorksRegardlessOfQuota) {
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(false));
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(false));
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(true));
+}
+
+TEST_F(RequestThrottlerTest, QuotaIsPerDay) {
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(false));
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(false));
+
+ // Now fake the day pref so that the counter believes the count comes from
+ // yesterday.
+ int now_day = (base::Time::Now() - base::Time::UnixEpoch()).InDays();
+ test_prefs_.SetInteger(ntp_snippets::prefs::kSnippetFetcherRequestsDay,
+ now_day - 1);
+
+ // The quota should get reset as the day has changed.
+ EXPECT_TRUE(throttler_->DemandQuotaForRequest(false));
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/sessions/DEPS b/chromium/components/ntp_snippets/sessions/DEPS
new file mode 100644
index 00000000000..e279a07903d
--- /dev/null
+++ b/chromium/components/ntp_snippets/sessions/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+components/sessions",
+ "+components/sync_sessions",
+]
diff --git a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
new file mode 100644
index 00000000000..f913d660fca
--- /dev/null
+++ b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
@@ -0,0 +1,314 @@
+// 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 "components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h"
+
+#include <algorithm>
+#include <map>
+#include <tuple>
+#include <utility>
+
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/category_info.h"
+#include "components/ntp_snippets/content_suggestion.h"
+#include "components/ntp_snippets/features.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/ntp_snippets/pref_util.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/sessions/core/session_types.h"
+#include "components/sync_sessions/synced_session.h"
+#include "grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/image/image.h"
+#include "url/gurl.h"
+
+using base::TimeDelta;
+using sessions::SerializedNavigationEntry;
+using sessions::SessionTab;
+using sessions::SessionWindow;
+using sync_sessions::SyncedSession;
+
+namespace ntp_snippets {
+namespace {
+
+const int kMaxForeignTabsTotal = 10;
+const int kMaxForeignTabsPerDevice = 3;
+const int kMaxForeignTabAgeInMinutes = 180;
+
+const char* kMaxForeignTabsTotalParamName = "max_foreign_tabs_total";
+const char* kMaxForeignTabsPerDeviceParamName = "max_foreign_tabs_per_device";
+const char* kMaxForeignTabAgeInMinutesParamName =
+ "max_foreign_tabs_age_in_minutes";
+
+int GetMaxForeignTabsTotal() {
+ return GetParamAsInt(ntp_snippets::kForeignSessionsSuggestionsFeature,
+ kMaxForeignTabsTotalParamName, kMaxForeignTabsTotal);
+}
+
+int GetMaxForeignTabsPerDevice() {
+ return GetParamAsInt(ntp_snippets::kForeignSessionsSuggestionsFeature,
+ kMaxForeignTabsPerDeviceParamName,
+ kMaxForeignTabsPerDevice);
+}
+
+TimeDelta GetMaxForeignTabAge() {
+ return TimeDelta::FromMinutes(GetParamAsInt(
+ ntp_snippets::kForeignSessionsSuggestionsFeature,
+ kMaxForeignTabAgeInMinutesParamName, kMaxForeignTabAgeInMinutes));
+}
+
+} // namespace
+
+// Collection of pointers to various sessions objects that contain a superset of
+// the information needed to create a single suggestion.
+struct ForeignSessionsSuggestionsProvider::SessionData {
+ const sync_sessions::SyncedSession* session;
+ const sessions::SessionTab* tab;
+ const sessions::SerializedNavigationEntry* navigation;
+ bool operator<(const SessionData& other) const {
+ // Note that SerializedNavigationEntry::timestamp() is never set to a
+ // value, so always use SessionTab::timestamp() instead.
+ // TODO(skym): It might be better if we sorted by recency of session, and
+ // only then by recency of the tab. Right now this causes a single
+ // device's tabs to be interleaved with another devices' tabs.
+ return tab->timestamp > other.tab->timestamp;
+ }
+};
+
+ForeignSessionsSuggestionsProvider::ForeignSessionsSuggestionsProvider(
+ ContentSuggestionsProvider::Observer* observer,
+ CategoryFactory* category_factory,
+ std::unique_ptr<ForeignSessionsProvider> foreign_sessions_provider,
+ PrefService* pref_service)
+ : ContentSuggestionsProvider(observer, category_factory),
+ category_status_(CategoryStatus::INITIALIZING),
+ provided_category_(
+ category_factory->FromKnownCategory(KnownCategories::FOREIGN_TABS)),
+ foreign_sessions_provider_(std::move(foreign_sessions_provider)),
+ pref_service_(pref_service) {
+ foreign_sessions_provider_->SubscribeForForeignTabChange(
+ base::Bind(&ForeignSessionsSuggestionsProvider::OnForeignTabChange,
+ base::Unretained(this)));
+
+ // If sync is already initialzed, try suggesting now, though this is unlikely.
+ OnForeignTabChange();
+}
+
+ForeignSessionsSuggestionsProvider::~ForeignSessionsSuggestionsProvider() =
+ default;
+
+// static
+void ForeignSessionsSuggestionsProvider::RegisterProfilePrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterListPref(prefs::kDismissedForeignSessionsSuggestions);
+}
+
+CategoryStatus ForeignSessionsSuggestionsProvider::GetCategoryStatus(
+ Category category) {
+ DCHECK_EQ(category, provided_category_);
+ return category_status_;
+}
+
+CategoryInfo ForeignSessionsSuggestionsProvider::GetCategoryInfo(
+ Category category) {
+ DCHECK_EQ(category, provided_category_);
+ return CategoryInfo(l10n_util::GetStringUTF16(
+ IDS_NTP_FOREIGN_SESSIONS_SUGGESTIONS_SECTION_HEADER),
+ ContentSuggestionsCardLayout::MINIMAL_CARD,
+ /*has_more_button=*/true,
+ /*show_if_empty=*/false);
+}
+
+void ForeignSessionsSuggestionsProvider::DismissSuggestion(
+ const ContentSuggestion::ID& suggestion_id) {
+ // TODO(skym): Right now this continuously grows, without clearing out old and
+ // irrelevant entries. Could either use a timestamp and expire after a
+ // threshold, or compare with current foreign tabs and remove anything that
+ // isn't actively blockign a foreign_sessions tab.
+ std::set<std::string> dismissed_ids = prefs::ReadDismissedIDsFromPrefs(
+ *pref_service_, prefs::kDismissedForeignSessionsSuggestions);
+ dismissed_ids.insert(suggestion_id.id_within_category());
+ prefs::StoreDismissedIDsToPrefs(pref_service_,
+ prefs::kDismissedForeignSessionsSuggestions,
+ dismissed_ids);
+}
+
+void ForeignSessionsSuggestionsProvider::FetchSuggestionImage(
+ const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, gfx::Image()));
+}
+
+void ForeignSessionsSuggestionsProvider::ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) {
+ std::set<std::string> dismissed_ids = prefs::ReadDismissedIDsFromPrefs(
+ *pref_service_, prefs::kDismissedForeignSessionsSuggestions);
+ for (auto iter = dismissed_ids.begin(); iter != dismissed_ids.end();) {
+ if (filter.Run(GURL(*iter))) {
+ iter = dismissed_ids.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+ prefs::StoreDismissedIDsToPrefs(pref_service_,
+ prefs::kDismissedForeignSessionsSuggestions,
+ dismissed_ids);
+}
+
+void ForeignSessionsSuggestionsProvider::ClearCachedSuggestions(
+ Category category) {
+ DCHECK_EQ(category, provided_category_);
+ // Ignored.
+}
+
+void ForeignSessionsSuggestionsProvider::GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) {
+ DCHECK_EQ(category, provided_category_);
+ callback.Run(std::vector<ContentSuggestion>());
+}
+
+void ForeignSessionsSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
+ Category category) {
+ DCHECK_EQ(category, provided_category_);
+ pref_service_->ClearPref(prefs::kDismissedForeignSessionsSuggestions);
+}
+
+void ForeignSessionsSuggestionsProvider::OnForeignTabChange() {
+ if (!foreign_sessions_provider_->HasSessionsData()) {
+ if (category_status_ == CategoryStatus::AVAILABLE) {
+ // This is to handle the case where the user disabled sync [sessions] or
+ // logs out after we've already provided actual suggestions.
+ category_status_ = CategoryStatus::NOT_PROVIDED;
+ observer()->OnCategoryStatusChanged(this, provided_category_,
+ category_status_);
+ }
+ return;
+ }
+
+ if (category_status_ != CategoryStatus::AVAILABLE) {
+ // The further below logic will overwrite any error state. This is
+ // currently okay because no where in the current implementation does the
+ // status get set to an error state. Should this change, reconsider the
+ // overwriting logic.
+ DCHECK(category_status_ == CategoryStatus::INITIALIZING ||
+ category_status_ == CategoryStatus::NOT_PROVIDED);
+
+ // It is difficult to tell if sync simply has not initialized yet or there
+ // will never be data because the user is signed out or has disabled the
+ // sessions data type. Because this provider is hidden when there are no
+ // results, always just update to AVAILABLE once we might have results.
+ category_status_ = CategoryStatus::AVAILABLE;
+ observer()->OnCategoryStatusChanged(this, provided_category_,
+ category_status_);
+ }
+
+ // observer()->OnNewSuggestions must be called even when we have no
+ // suggestions to remove previous suggestions that are now filtered out.
+ observer()->OnNewSuggestions(this, provided_category_, BuildSuggestions());
+}
+
+std::vector<ContentSuggestion>
+ForeignSessionsSuggestionsProvider::BuildSuggestions() {
+ const int max_foreign_tabs_total = GetMaxForeignTabsTotal();
+ const int max_foreign_tabs_per_device = GetMaxForeignTabsPerDevice();
+
+ std::vector<SessionData> suggestion_candidates = GetSuggestionCandidates();
+ // This sorts by recency so that we keep the most recent entries and they
+ // appear as suggestions in reverse chronological order.
+ std::sort(suggestion_candidates.begin(), suggestion_candidates.end());
+
+ std::vector<ContentSuggestion> suggestions;
+ std::set<std::string> included_urls;
+ std::map<std::string, int> suggestions_per_session;
+ for (const SessionData& candidate : suggestion_candidates) {
+ const std::string& session_tag = candidate.session->session_tag;
+ auto duplicates_iter =
+ included_urls.find(candidate.navigation->virtual_url().spec());
+ auto count_iter = suggestions_per_session.find(session_tag);
+ int count =
+ count_iter == suggestions_per_session.end() ? 0 : count_iter->second;
+
+ // Pick up to max (total and per device) tabs, and ensure no duplicates
+ // are selected. This filtering must be done in a second pass because
+ // this can cause newer tabs occluding less recent tabs, requiring more
+ // than |max_foreign_tabs_per_device| to be considered per device.
+ if (static_cast<int>(suggestions.size()) >= max_foreign_tabs_total ||
+ duplicates_iter != included_urls.end() ||
+ count >= max_foreign_tabs_per_device) {
+ continue;
+ }
+ included_urls.insert(candidate.navigation->virtual_url().spec());
+ suggestions_per_session[session_tag] = count + 1;
+ suggestions.push_back(BuildSuggestion(candidate));
+ }
+
+ return suggestions;
+}
+
+std::vector<ForeignSessionsSuggestionsProvider::SessionData>
+ForeignSessionsSuggestionsProvider::GetSuggestionCandidates() {
+ // TODO(skym): If a tab was previously dismissed, but was since updated,
+ // should it be resurrected and removed from the dismissed list? This would
+ // likely require a change to the dismissed ids.
+ // TODO(skym): No sense in keeping around dismissals for urls that no longer
+ // exist on any current foreign devices. Should prune and save the pref back.
+ const std::vector<const SyncedSession*>& foreign_sessions =
+ foreign_sessions_provider_->GetAllForeignSessions();
+ std::set<std::string> dismissed_ids = prefs::ReadDismissedIDsFromPrefs(
+ *pref_service_, prefs::kDismissedForeignSessionsSuggestions);
+ const TimeDelta max_foreign_tab_age = GetMaxForeignTabAge();
+ std::vector<SessionData> suggestion_candidates;
+
+ for (const SyncedSession* session : foreign_sessions) {
+ for (const std::pair<const SessionID::id_type,
+ std::unique_ptr<sessions::SessionWindow>>& key_value :
+ session->windows) {
+ for (const std::unique_ptr<SessionTab>& tab : key_value.second->tabs) {
+ if (tab->navigations.empty())
+ continue;
+
+ const SerializedNavigationEntry& navigation = tab->navigations.back();
+ const std::string id = navigation.virtual_url().spec();
+ // TODO(skym): Filter out internal pages. Tabs that contain only
+ // non-syncable content should never reach the local client, but
+ // sometimes the most recent navigation may be internal while one
+ // of the previous ones was more valid.
+ if (dismissed_ids.find(id) == dismissed_ids.end() &&
+ (base::Time::Now() - tab->timestamp) < max_foreign_tab_age) {
+ suggestion_candidates.push_back(
+ SessionData{session, tab.get(), &navigation});
+ }
+ }
+ }
+ }
+ return suggestion_candidates;
+}
+
+ContentSuggestion ForeignSessionsSuggestionsProvider::BuildSuggestion(
+ const SessionData& data) {
+ ContentSuggestion suggestion(provided_category_,
+ data.navigation->virtual_url().spec(),
+ data.navigation->virtual_url());
+ suggestion.set_title(data.navigation->title());
+ suggestion.set_publish_date(data.tab->timestamp);
+ // TODO(skym): It's unclear if this simple approach is sufficient for
+ // right-to-left languages.
+ // This field is sandwiched between the url's favicon, which is on the left,
+ // and the |publish_date|, which is to the right. The domain should always
+ // appear next to the favicon.
+ suggestion.set_publisher_name(
+ base::UTF8ToUTF16(data.navigation->virtual_url().host() + " - " +
+ data.session->session_name));
+ return suggestion;
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
new file mode 100644
index 00000000000..4d21a3f9157
--- /dev/null
+++ b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
@@ -0,0 +1,85 @@
+// 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 COMPONENTS_NTP_SNIPPETS_SESSIONS_FOREIGN_SESSIONS_SUGGESTIONS_PROVIDER_H_
+#define COMPONENTS_NTP_SNIPPETS_SESSIONS_FOREIGN_SESSIONS_SUGGESTIONS_PROVIDER_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_status.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/sessions/core/session_types.h"
+#include "components/sync_sessions/synced_session.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace ntp_snippets {
+
+// Simple interface to get foreign tab data on demand and on change.
+class ForeignSessionsProvider {
+ public:
+ virtual ~ForeignSessionsProvider() = default;
+ virtual bool HasSessionsData() = 0;
+ virtual std::vector<const sync_sessions::SyncedSession*>
+ GetAllForeignSessions() = 0;
+ // Should only be called at most once.
+ virtual void SubscribeForForeignTabChange(
+ const base::Closure& change_callback) = 0;
+};
+
+// Provides content suggestions from foreign sessions.
+class ForeignSessionsSuggestionsProvider : public ContentSuggestionsProvider {
+ public:
+ ForeignSessionsSuggestionsProvider(
+ ContentSuggestionsProvider::Observer* observer,
+ CategoryFactory* category_factory,
+ std::unique_ptr<ForeignSessionsProvider> foreign_sessions_provider,
+ PrefService* pref_service);
+ ~ForeignSessionsSuggestionsProvider() override;
+
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ private:
+ friend class ForeignSessionsSuggestionsProviderTest;
+ struct SessionData;
+
+ // ContentSuggestionsProvider implementation.
+ CategoryStatus GetCategoryStatus(Category category) override;
+ CategoryInfo GetCategoryInfo(Category category) override;
+ void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+ void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
+ const ImageFetchedCallback& callback) override;
+ void ClearHistory(
+ base::Time begin,
+ base::Time end,
+ const base::Callback<bool(const GURL& url)>& filter) override;
+ void ClearCachedSuggestions(Category category) override;
+ void GetDismissedSuggestionsForDebugging(
+ Category category,
+ const DismissedSuggestionsCallback& callback) override;
+ void ClearDismissedSuggestionsForDebugging(Category category) override;
+
+ void OnForeignTabChange();
+ std::vector<ContentSuggestion> BuildSuggestions();
+ std::vector<SessionData> GetSuggestionCandidates();
+ ContentSuggestion BuildSuggestion(const SessionData& data);
+
+ CategoryStatus category_status_;
+ const Category provided_category_;
+ std::unique_ptr<ForeignSessionsProvider> foreign_sessions_provider_;
+ PrefService* pref_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(ForeignSessionsSuggestionsProvider);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_SESSIONS_FOREIGN_SESSIONS_SUGGESTIONS_PROVIDER_H_
diff --git a/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
new file mode 100644
index 00000000000..e36cf2351d8
--- /dev/null
+++ b/chromium/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
@@ -0,0 +1,326 @@
+// 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 "components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h"
+
+#include <map>
+#include <utility>
+
+#include "base/callback_forward.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/ntp_snippets/category.h"
+#include "components/ntp_snippets/category_factory.h"
+#include "components/ntp_snippets/content_suggestions_provider.h"
+#include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/sessions/core/serialized_navigation_entry.h"
+#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
+#include "components/sessions/core/session_types.h"
+#include "components/sync_sessions/synced_session.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using base::TimeDelta;
+using sessions::SerializedNavigationEntry;
+using sessions::SessionTab;
+using sessions::SessionWindow;
+using sync_sessions::SyncedSession;
+using testing::ElementsAre;
+using testing::IsEmpty;
+using testing::Property;
+using testing::Test;
+using testing::_;
+
+namespace ntp_snippets {
+namespace {
+
+const char kUrl1[] = "http://www.fake1.com/";
+const char kUrl2[] = "http://www.fake2.com/";
+const char kUrl3[] = "http://www.fake3.com/";
+const char kUrl4[] = "http://www.fake4.com/";
+const char kUrl5[] = "http://www.fake5.com/";
+const char kUrl6[] = "http://www.fake6.com/";
+const char kUrl7[] = "http://www.fake7.com/";
+const char kUrl8[] = "http://www.fake8.com/";
+const char kUrl9[] = "http://www.fake9.com/";
+const char kUrl10[] = "http://www.fake10.com/";
+const char kUrl11[] = "http://www.fake11.com/";
+const char kTitle[] = "title is ignored";
+
+SessionWindow* GetOrCreateWindow(SyncedSession* session, int window_id) {
+ if (session->windows.find(window_id) == session->windows.end())
+ session->windows[window_id] = base::MakeUnique<SessionWindow>();
+
+ return session->windows[window_id].get();
+}
+
+void AddTabToSession(SyncedSession* session,
+ int window_id,
+ const std::string& url,
+ TimeDelta age) {
+ SerializedNavigationEntry navigation =
+ sessions::SerializedNavigationEntryTestHelper::CreateNavigation(url,
+ kTitle);
+
+ std::unique_ptr<SessionTab> tab = base::MakeUnique<SessionTab>();
+ tab->timestamp = Time::Now() - age;
+ tab->navigations.push_back(navigation);
+
+ SessionWindow* window = GetOrCreateWindow(session, window_id);
+ // The window deletes the tabs it points at upon destruction.
+ window->tabs.push_back(std::move(tab));
+}
+
+class FakeForeignSessionsProvider : public ForeignSessionsProvider {
+ public:
+ ~FakeForeignSessionsProvider() override = default;
+ void SetAllForeignSessions(std::vector<const SyncedSession*> sessions) {
+ sessions_ = std::move(sessions);
+ change_callback_.Run();
+ }
+
+ // ForeignSessionsProvider implementation.
+ void SubscribeForForeignTabChange(
+ const base::Closure& change_callback) override {
+ change_callback_ = change_callback;
+ }
+ bool HasSessionsData() override { return true; }
+ std::vector<const sync_sessions::SyncedSession*> GetAllForeignSessions()
+ override {
+ return sessions_;
+ }
+
+ private:
+ std::vector<const SyncedSession*> sessions_;
+ base::Closure change_callback_;
+};
+} // namespace
+
+class ForeignSessionsSuggestionsProviderTest : public Test {
+ public:
+ ForeignSessionsSuggestionsProviderTest() {
+ ForeignSessionsSuggestionsProvider::RegisterProfilePrefs(
+ pref_service_.registry());
+
+ std::unique_ptr<FakeForeignSessionsProvider>
+ fake_foreign_sessions_provider =
+ base::MakeUnique<FakeForeignSessionsProvider>();
+ fake_foreign_sessions_provider_ = fake_foreign_sessions_provider.get();
+
+ // During the provider's construction the following mock calls occur.
+ EXPECT_CALL(*observer(), OnNewSuggestions(_, category(), IsEmpty()));
+ EXPECT_CALL(*observer(), OnCategoryStatusChanged(
+ _, category(), CategoryStatus::AVAILABLE));
+
+ provider_ = base::MakeUnique<ForeignSessionsSuggestionsProvider>(
+ &observer_, &category_factory_,
+ std::move(fake_foreign_sessions_provider), &pref_service_);
+ }
+
+ protected:
+ SyncedSession* GetOrCreateSession(int session_id) {
+ if (sessions_map_.find(session_id) == sessions_map_.end()) {
+ std::string id_as_string = base::IntToString(session_id);
+ std::unique_ptr<SyncedSession> owned_session =
+ base::MakeUnique<SyncedSession>();
+ owned_session->session_tag = id_as_string;
+ owned_session->session_name = id_as_string;
+ sessions_map_[session_id] = std::move(owned_session);
+ }
+ return sessions_map_[session_id].get();
+ }
+
+ void AddTab(int session_id,
+ int window_id,
+ const std::string& url,
+ TimeDelta age) {
+ AddTabToSession(GetOrCreateSession(session_id), window_id, url, age);
+ }
+
+ void TriggerOnChange() {
+ std::vector<const SyncedSession*> sessions;
+ for (const auto& kv : sessions_map_) {
+ sessions.push_back(kv.second.get());
+ }
+ fake_foreign_sessions_provider_->SetAllForeignSessions(std::move(sessions));
+ }
+
+ void Dismiss(const std::string& url) {
+ // The url of a given suggestion is used as the |id_within_category|.
+ provider_->DismissSuggestion(ContentSuggestion::ID(category(), url));
+ }
+
+ Category category() {
+ return category_factory_.FromKnownCategory(KnownCategories::FOREIGN_TABS);
+ }
+
+ MockContentSuggestionsProviderObserver* observer() { return &observer_; }
+
+ private:
+ FakeForeignSessionsProvider* fake_foreign_sessions_provider_;
+ MockContentSuggestionsProviderObserver observer_;
+ CategoryFactory category_factory_;
+ TestingPrefServiceSimple pref_service_;
+ std::unique_ptr<ForeignSessionsSuggestionsProvider> provider_;
+ std::map<int, std::unique_ptr<SyncedSession>> sessions_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(ForeignSessionsSuggestionsProviderTest);
+};
+
+TEST_F(ForeignSessionsSuggestionsProviderTest, Empty) {
+ // When no sessions data is added, expect no suggestions.
+ EXPECT_CALL(*observer(), OnNewSuggestions(_, category(), IsEmpty()));
+ TriggerOnChange();
+}
+
+TEST_F(ForeignSessionsSuggestionsProviderTest, Single) {
+ // Expect a single valid tab because that is what has been added.
+ EXPECT_CALL(*observer(),
+ OnNewSuggestions(
+ _, category(),
+ ElementsAre(Property(&ContentSuggestion::url, GURL(kUrl1)))));
+ AddTab(0, 0, kUrl1, TimeDelta::FromMinutes(1));
+ TriggerOnChange();
+}
+
+TEST_F(ForeignSessionsSuggestionsProviderTest, Old) {
+ // The only sessions data is too old to be suggested, so expect empty.
+ EXPECT_CALL(*observer(), OnNewSuggestions(_, category(), IsEmpty()));
+ AddTab(0, 0, kUrl1, TimeDelta::FromHours(4));
+ TriggerOnChange();
+}
+
+TEST_F(ForeignSessionsSuggestionsProviderTest, Ordered) {
+ // Suggestions ordering should be in reverse chronological order, or youngest
+ // first.
+ EXPECT_CALL(*observer(),
+ OnNewSuggestions(
+ _, category(),
+ ElementsAre(Property(&ContentSuggestion::url, GURL(kUrl1)),
+ Property(&ContentSuggestion::url, GURL(kUrl2)),
+ Property(&ContentSuggestion::url, GURL(kUrl3)),
+ Property(&ContentSuggestion::url, GURL(kUrl4)))));
+ AddTab(0, 0, kUrl2, TimeDelta::FromMinutes(2));
+ AddTab(0, 0, kUrl4, TimeDelta::FromMinutes(4));
+ AddTab(0, 1, kUrl3, TimeDelta::FromMinutes(3));
+ AddTab(1, 0, kUrl1, TimeDelta::FromMinutes(1));
+ TriggerOnChange();
+}
+
+TEST_F(ForeignSessionsSuggestionsProviderTest, MaxPerDevice) {
+ // Each device, which is to equivalent a unique |session_tag|, has a limit to
+ // the number of suggestions it is allowed to contribute. Here all four
+ // suggestions are within the recency threshold, but only three are allowed
+ // per device. As such, expect that the oldest of the four will not be
+ // suggested.
+ EXPECT_CALL(*observer(),
+ OnNewSuggestions(
+ _, category(),
+ ElementsAre(Property(&ContentSuggestion::url, GURL(kUrl1)),
+ Property(&ContentSuggestion::url, GURL(kUrl2)),
+ Property(&ContentSuggestion::url, GURL(kUrl3)))));
+ AddTab(0, 0, kUrl1, TimeDelta::FromMinutes(1));
+ AddTab(0, 0, kUrl2, TimeDelta::FromMinutes(2));
+ AddTab(0, 0, kUrl3, TimeDelta::FromMinutes(3));
+ AddTab(0, 0, kUrl4, TimeDelta::FromMinutes(4));
+ TriggerOnChange();
+}
+
+TEST_F(ForeignSessionsSuggestionsProviderTest, MaxTotal) {
+ // There's a limit to the total nubmer of suggestions that the provider will
+ // ever return, which should be ten. Here there are eleven valid suggestion
+ // entries, spread out over multiple devices/sessions to avoid the per device
+ // cutoff. Expect that the least recent of the eleven to be dropped.
+ EXPECT_CALL(
+ *observer(),
+ OnNewSuggestions(
+ _, category(),
+ ElementsAre(Property(&ContentSuggestion::url, GURL(kUrl1)),
+ Property(&ContentSuggestion::url, GURL(kUrl2)),
+ Property(&ContentSuggestion::url, GURL(kUrl3)),
+ Property(&ContentSuggestion::url, GURL(kUrl4)),
+ Property(&ContentSuggestion::url, GURL(kUrl5)),
+ Property(&ContentSuggestion::url, GURL(kUrl6)),
+ Property(&ContentSuggestion::url, GURL(kUrl7)),
+ Property(&ContentSuggestion::url, GURL(kUrl8)),
+ Property(&ContentSuggestion::url, GURL(kUrl9)),
+ Property(&ContentSuggestion::url, GURL(kUrl10)))));
+ AddTab(0, 0, kUrl1, TimeDelta::FromMinutes(1));
+ AddTab(0, 0, kUrl2, TimeDelta::FromMinutes(2));
+ AddTab(0, 0, kUrl3, TimeDelta::FromMinutes(3));
+ AddTab(1, 0, kUrl4, TimeDelta::FromMinutes(4));
+ AddTab(1, 0, kUrl5, TimeDelta::FromMinutes(5));
+ AddTab(1, 0, kUrl6, TimeDelta::FromMinutes(6));
+ AddTab(2, 0, kUrl7, TimeDelta::FromMinutes(7));
+ AddTab(2, 0, kUrl8, TimeDelta::FromMinutes(8));
+ AddTab(2, 0, kUrl9, TimeDelta::FromMinutes(9));
+ AddTab(3, 0, kUrl10, TimeDelta::FromMinutes(10));
+ AddTab(3, 0, kUrl11, TimeDelta::FromMinutes(11));
+ TriggerOnChange();
+}
+
+TEST_F(ForeignSessionsSuggestionsProviderTest, Duplicates) {
+ // The same url is never suggested more than once at a time. All the session
+ // data has the same url so only expect a single suggestion.
+ EXPECT_CALL(*observer(),
+ OnNewSuggestions(
+ _, category(),
+ ElementsAre(Property(&ContentSuggestion::url, GURL(kUrl1)))));
+ AddTab(0, 0, kUrl1, TimeDelta::FromMinutes(1));
+ AddTab(0, 1, kUrl1, TimeDelta::FromMinutes(2));
+ AddTab(1, 1, kUrl1, TimeDelta::FromMinutes(3));
+ TriggerOnChange();
+}
+
+TEST_F(ForeignSessionsSuggestionsProviderTest, DuplicatesChangingOtherSession) {
+ // Normally |kUrl4| wouldn't show up, because session_id=0 already has 3
+ // younger tabs, but session_id=1 has a younger |kUrl3| which gives |kUrl4| a
+ // spot.
+ EXPECT_CALL(*observer(),
+ OnNewSuggestions(
+ _, category(),
+ ElementsAre(Property(&ContentSuggestion::url, GURL(kUrl3)),
+ Property(&ContentSuggestion::url, GURL(kUrl1)),
+ Property(&ContentSuggestion::url, GURL(kUrl2)),
+ Property(&ContentSuggestion::url, GURL(kUrl4)))));
+ AddTab(0, 0, kUrl1, TimeDelta::FromMinutes(1));
+ AddTab(0, 0, kUrl2, TimeDelta::FromMinutes(2));
+ AddTab(0, 0, kUrl3, TimeDelta::FromMinutes(3));
+ AddTab(0, 0, kUrl4, TimeDelta::FromMinutes(4));
+ AddTab(1, 0, kUrl3, TimeDelta::FromMinutes(0));
+ TriggerOnChange();
+}
+
+TEST_F(ForeignSessionsSuggestionsProviderTest, Dismissed) {
+ // Dimissed urls should not be suggested.
+ EXPECT_CALL(*observer(), OnNewSuggestions(_, category(), IsEmpty()));
+ Dismiss(kUrl1);
+ AddTab(0, 0, kUrl1, TimeDelta::FromMinutes(1));
+ TriggerOnChange();
+}
+
+TEST_F(ForeignSessionsSuggestionsProviderTest, DismissedChangingOwnSession) {
+ // Similar to DuplicatesChangingOtherSession, without dismissals we would
+ // expect urls 1-3. However, because of dismissals we reach all the down to
+ // |kUrl5| before the per device cutoff is hit.
+ EXPECT_CALL(*observer(),
+ OnNewSuggestions(
+ _, category(),
+ ElementsAre(Property(&ContentSuggestion::url, GURL(kUrl2)),
+ Property(&ContentSuggestion::url, GURL(kUrl3)),
+ Property(&ContentSuggestion::url, GURL(kUrl5)))));
+ Dismiss(kUrl1);
+ Dismiss(kUrl4);
+ AddTab(0, 0, kUrl1, TimeDelta::FromMinutes(1));
+ AddTab(0, 0, kUrl2, TimeDelta::FromMinutes(2));
+ AddTab(0, 0, kUrl3, TimeDelta::FromMinutes(3));
+ AddTab(0, 0, kUrl4, TimeDelta::FromMinutes(4));
+ AddTab(0, 0, kUrl5, TimeDelta::FromMinutes(5));
+ AddTab(0, 0, kUrl6, TimeDelta::FromMinutes(6));
+ TriggerOnChange();
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/sessions/tab_delegate_sync_adapter.cc b/chromium/components/ntp_snippets/sessions/tab_delegate_sync_adapter.cc
new file mode 100644
index 00000000000..aa0626cbfd4
--- /dev/null
+++ b/chromium/components/ntp_snippets/sessions/tab_delegate_sync_adapter.cc
@@ -0,0 +1,64 @@
+// 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 "components/ntp_snippets/sessions/tab_delegate_sync_adapter.h"
+
+#include "components/sync/driver/sync_service.h"
+#include "components/sync_sessions/open_tabs_ui_delegate.h"
+
+using syncer::SyncService;
+using sync_sessions::OpenTabsUIDelegate;
+
+namespace ntp_snippets {
+
+TabDelegateSyncAdapter::TabDelegateSyncAdapter(SyncService* sync_service)
+ : sync_service_(sync_service) {
+ sync_service_->AddObserver(this);
+}
+
+TabDelegateSyncAdapter::~TabDelegateSyncAdapter() {
+ sync_service_->RemoveObserver(this);
+}
+
+bool TabDelegateSyncAdapter::HasSessionsData() {
+ // GetOpenTabsUIDelegate will be a nullptr if sync has not started, or if the
+ // sessions data type is not enabled.
+ return sync_service_->GetOpenTabsUIDelegate() != nullptr;
+}
+
+std::vector<const sync_sessions::SyncedSession*>
+TabDelegateSyncAdapter::GetAllForeignSessions() {
+ std::vector<const sync_sessions::SyncedSession*> sessions;
+ OpenTabsUIDelegate* delegate = sync_service_->GetOpenTabsUIDelegate();
+ if (delegate != nullptr) {
+ // The return bool from GetAllForeignSessions(...) is ignored.
+ delegate->GetAllForeignSessions(&sessions);
+ }
+ return sessions;
+}
+
+void TabDelegateSyncAdapter::SubscribeForForeignTabChange(
+ const base::Closure& change_callback) {
+ DCHECK(change_callback_.is_null());
+ change_callback_ = change_callback;
+}
+
+void TabDelegateSyncAdapter::OnStateChanged() {
+ // Ignored.
+}
+
+void TabDelegateSyncAdapter::OnSyncConfigurationCompleted() {
+ InvokeCallback();
+}
+
+void TabDelegateSyncAdapter::OnForeignSessionUpdated() {
+ InvokeCallback();
+}
+
+void TabDelegateSyncAdapter::InvokeCallback() {
+ if (!change_callback_.is_null())
+ change_callback_.Run();
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/sessions/tab_delegate_sync_adapter.h b/chromium/components/ntp_snippets/sessions/tab_delegate_sync_adapter.h
new file mode 100644
index 00000000000..8796444c6fe
--- /dev/null
+++ b/chromium/components/ntp_snippets/sessions/tab_delegate_sync_adapter.h
@@ -0,0 +1,53 @@
+// 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 COMPONENTS_NTP_SNIPPETS_SESSIONS_TAB_DELEGATE_SYNC_ADAPTER_H_
+#define COMPONENTS_NTP_SNIPPETS_SESSIONS_TAB_DELEGATE_SYNC_ADAPTER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h"
+#include "components/sync/driver/sync_service_observer.h"
+
+namespace syncer {
+class SyncService;
+} // namespace syncer
+
+namespace ntp_snippets {
+
+// Adapter that sits on top of SyncService and OpenTabsUIDelegate and provides
+// simplified notifications and accessors for foreign tabs data.
+class TabDelegateSyncAdapter : public syncer::SyncServiceObserver,
+ public ForeignSessionsProvider {
+ public:
+ explicit TabDelegateSyncAdapter(syncer::SyncService* sync_service);
+ ~TabDelegateSyncAdapter() override;
+
+ // ForeignSessionsProvider implementation.
+ bool HasSessionsData() override;
+ std::vector<const sync_sessions::SyncedSession*> GetAllForeignSessions()
+ override;
+ void SubscribeForForeignTabChange(
+ const base::Closure& change_callback) override;
+
+ private:
+ // syncer::SyncServiceObserver implementation.
+ void OnStateChanged() override;
+ void OnSyncConfigurationCompleted() override;
+ void OnForeignSessionUpdated() override;
+
+ void InvokeCallback();
+
+ syncer::SyncService* sync_service_;
+ base::Closure change_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabDelegateSyncAdapter);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_SESSIONS_TAB_DELEGATE_SYNC_ADAPTER_H_
diff --git a/chromium/components/ntp_snippets/switches.cc b/chromium/components/ntp_snippets/switches.cc
index ee5f979e112..e34431c934b 100644
--- a/chromium/components/ntp_snippets/switches.cc
+++ b/chromium/components/ntp_snippets/switches.cc
@@ -7,17 +7,6 @@
namespace ntp_snippets {
namespace switches {
-const char kFetchingIntervalWifiChargingSeconds[] =
- "ntp-snippets-fetching-interval-wifi-charging";
-const char kFetchingIntervalWifiSeconds[] =
- "ntp-snippets-fetching-interval-wifi";
-const char kFetchingIntervalFallbackSeconds[] =
- "ntp-snippets-fetching-interval-fallback";
-
-// If this flag is set, the snippets won't be restricted to the user's NTP
-// suggestions.
-const char kDontRestrict[] = "ntp-snippets-dont-restrict";
-
// If this flag is set, we will add downloaded snippets that are missing some
// critical data to the list.
const char kAddIncompleteSnippets[] = "ntp-snippets-add-incomplete";
diff --git a/chromium/components/ntp_snippets/switches.h b/chromium/components/ntp_snippets/switches.h
index 4897f136ec8..a48e8aff680 100644
--- a/chromium/components/ntp_snippets/switches.h
+++ b/chromium/components/ntp_snippets/switches.h
@@ -8,11 +8,6 @@
namespace ntp_snippets {
namespace switches {
-extern const char kFetchingIntervalWifiChargingSeconds[];
-extern const char kFetchingIntervalWifiSeconds[];
-extern const char kFetchingIntervalFallbackSeconds[];
-
-extern const char kDontRestrict[];
extern const char kAddIncompleteSnippets[];
} // namespace switches
diff --git a/chromium/components/ntp_snippets/user_classifier.cc b/chromium/components/ntp_snippets/user_classifier.cc
new file mode 100644
index 00000000000..a9122343a1e
--- /dev/null
+++ b/chromium/components/ntp_snippets/user_classifier.cc
@@ -0,0 +1,373 @@
+// 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 "components/ntp_snippets/user_classifier.h"
+
+#include <algorithm>
+#include <cfloat>
+#include <string>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/ntp_snippets/features.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/variations/variations_associated_data.h"
+
+namespace ntp_snippets {
+
+namespace {
+
+// The discount rate for computing the discounted-average metrics. Must be
+// strictly larger than 0 and strictly smaller than 1!
+const double kDiscountRatePerDay = 0.25;
+const char kDiscountRatePerDayParam[] =
+ "user_classifier_discount_rate_per_day";
+
+// Never consider any larger interval than this (so that extreme situations such
+// as losing your phone or going for a long offline vacation do not skew the
+// average too much).
+// When everriding via variation parameters, it is better to use smaller values
+// than |kMaxHours| as this it the maximum value reported in the histograms.
+const double kMaxHours = 7 * 24;
+const char kMaxHoursParam[] = "user_classifier_max_hours";
+
+// Ignore events within |kMinHours| hours since the last event (|kMinHours| is
+// the length of the browsing session where subsequent events of the same type
+// do not count again).
+const double kMinHours = 0.5;
+const char kMinHoursParam[] = "user_classifier_min_hours";
+
+// Classification constants.
+const double kActiveConsumerScrollsAtLeastOncePerHours = 24;
+const char kActiveConsumerScrollsAtLeastOncePerHoursParam[] =
+ "user_classifier_active_consumer_scrolls_at_least_once_per_hours";
+
+const double kRareUserOpensNTPAtMostOncePerHours = 72;
+const char kRareUserOpensNTPAtMostOncePerHoursParam[] =
+ "user_classifier_rare_user_opens_ntp_at_most_once_per_hours";
+
+// Histograms for logging the estimated average hours to next event.
+const char kHistogramAverageHoursToOpenNTP[] =
+ "NewTabPage.UserClassifier.AverageHoursToOpenNTP";
+const char kHistogramAverageHoursToShowSuggestions[] =
+ "NewTabPage.UserClassifier.AverageHoursToShowSuggestions";
+const char kHistogramAverageHoursToUseSuggestions[] =
+ "NewTabPage.UserClassifier.AverageHoursToUseSuggestions";
+
+// The enum used for iteration.
+const UserClassifier::Metric kMetrics[] = {
+ UserClassifier::Metric::NTP_OPENED,
+ UserClassifier::Metric::SUGGESTIONS_SHOWN,
+ UserClassifier::Metric::SUGGESTIONS_USED};
+
+// The summary of the prefs.
+const char* kMetricKeys[] = {
+ prefs::kUserClassifierAverageNTPOpenedPerHour,
+ prefs::kUserClassifierAverageSuggestionsShownPerHour,
+ prefs::kUserClassifierAverageSuggestionsUsedPerHour};
+const char* kLastTimeKeys[] = {prefs::kUserClassifierLastTimeToOpenNTP,
+ prefs::kUserClassifierLastTimeToShowSuggestions,
+ prefs::kUserClassifierLastTimeToUseSuggestions};
+
+// Default lengths of the intervals for new users for the metrics.
+const double kInitialHoursBetweenEvents[] = {24, 36, 48};
+const char* kInitialHoursBetweenEventsParams[] = {
+ "user_classifier_default_interval_ntp_opened",
+ "user_classifier_default_interval_suggestions_shown",
+ "user_classifier_default_interval_suggestions_used"};
+
+static_assert(arraysize(kMetrics) ==
+ static_cast<int>(UserClassifier::Metric::COUNT) &&
+ arraysize(kMetricKeys) ==
+ static_cast<int>(UserClassifier::Metric::COUNT) &&
+ arraysize(kLastTimeKeys) ==
+ static_cast<int>(UserClassifier::Metric::COUNT) &&
+ arraysize(kInitialHoursBetweenEvents) ==
+ static_cast<int>(UserClassifier::Metric::COUNT) &&
+ arraysize(kInitialHoursBetweenEventsParams) ==
+ static_cast<int>(UserClassifier::Metric::COUNT),
+ "Fill in info for all metrics.");
+
+double GetParamValue(const char* param_name, double default_value) {
+ std::string param_value_str = variations::GetVariationParamValueByFeature(
+ kArticleSuggestionsFeature, param_name);
+ double param_value = 0;
+ if (!base::StringToDouble(param_value_str, &param_value)) {
+ LOG_IF(WARNING, !param_value_str.empty())
+ << "Invalid variation parameter for " << param_name;
+ return default_value;
+ }
+ return param_value;
+}
+
+// Computes the discount rate.
+double GetDiscountRatePerHour() {
+ double discount_rate_per_day =
+ GetParamValue(kDiscountRatePerDayParam, kDiscountRatePerDay);
+ // Check for illegal values.
+ if (discount_rate_per_day <= 0 || discount_rate_per_day >= 1) {
+ DLOG(WARNING) << "Illegal value " << discount_rate_per_day
+ << " for the parameter " << kDiscountRatePerDayParam
+ << " (must be strictly between 0 and 1; the default "
+ << kDiscountRatePerDay << " is used, instead).";
+ discount_rate_per_day = kDiscountRatePerDay;
+ }
+ // Compute discount_rate_per_hour such that
+ // discount_rate_per_day = 1 - e^{-discount_rate_per_hour * 24}.
+ return std::log(1.0 / (1.0 - discount_rate_per_day)) / 24.0;
+}
+
+double GetInitialHoursBetweenEvents(UserClassifier::Metric metric) {
+ return GetParamValue(
+ kInitialHoursBetweenEventsParams[static_cast<int>(metric)],
+ kInitialHoursBetweenEvents[static_cast<int>(metric)]);
+}
+
+double GetMinHours() {
+ return GetParamValue(kMinHoursParam, kMinHours);
+}
+
+double GetMaxHours() {
+ return GetParamValue(kMaxHoursParam, kMaxHours);
+}
+
+// Returns the new value of the metric using its |old_value|, assuming
+// |hours_since_last_time| hours have passed since it was last discounted.
+double DiscountMetric(double old_value,
+ double hours_since_last_time,
+ double discount_rate_per_hour) {
+ // Compute the new discounted average according to the formula
+ // avg_events := e^{-discount_rate_per_hour * hours_since} * avg_events
+ return std::exp(-discount_rate_per_hour * hours_since_last_time) * old_value;
+}
+
+// Compute the number of hours between two events for the given metric value
+// assuming the events were equally distributed.
+double GetEstimateHoursBetweenEvents(double metric_value,
+ double discount_rate_per_hour,
+ double min_hours,
+ double max_hours) {
+ // The computation below is well-defined only for |metric_value| > 1 (log of
+ // negative value or division by zero). When |metric_value| -> 1, the estimate
+ // below -> infinity, so max_hours is a natural result, here.
+ if (metric_value <= 1)
+ return max_hours;
+
+ // This is the estimate with the assumption that last event happened right
+ // now and the system is in the steady-state. Solve estimate_hours in the
+ // steady-state equation:
+ // metric_value = 1 + e^{-discount_rate * estimate_hours} * metric_value,
+ // i.e.
+ // -discount_rate * estimate_hours = log((metric_value - 1) / metric_value),
+ // discount_rate * estimate_hours = log(metric_value / (metric_value - 1)),
+ // estimate_hours = log(metric_value / (metric_value - 1)) / discount_rate.
+ double estimate_hours =
+ std::log(metric_value / (metric_value - 1)) / discount_rate_per_hour;
+ return std::max(min_hours, std::min(max_hours, estimate_hours));
+}
+
+// The inverse of GetEstimateHoursBetweenEvents().
+double GetMetricValueForEstimateHoursBetweenEvents(
+ double estimate_hours,
+ double discount_rate_per_hour,
+ double min_hours,
+ double max_hours) {
+ // Keep the input value within [min_hours, max_hours].
+ estimate_hours = std::max(min_hours, std::min(max_hours, estimate_hours));
+ // Return |metric_value| such that GetEstimateHoursBetweenEvents for
+ // |metric_value| returns |estimate_hours|. Thus, solve |metric_value| in
+ // metric_value = 1 + e^{-discount_rate * estimate_hours} * metric_value,
+ // i.e.
+ // metric_value * (1 - e^{-discount_rate * estimate_hours}) = 1,
+ // metric_value = 1 / (1 - e^{-discount_rate * estimate_hours}).
+ return 1.0 / (1.0 - std::exp(-discount_rate_per_hour * estimate_hours));
+}
+
+} // namespace
+
+UserClassifier::UserClassifier(PrefService* pref_service)
+ : pref_service_(pref_service),
+ discount_rate_per_hour_(GetDiscountRatePerHour()),
+ min_hours_(GetMinHours()),
+ max_hours_(GetMaxHours()),
+ active_consumer_scrolls_at_least_once_per_hours_(
+ GetParamValue(kActiveConsumerScrollsAtLeastOncePerHoursParam,
+ kActiveConsumerScrollsAtLeastOncePerHours)),
+ rare_user_opens_ntp_at_most_once_per_hours_(
+ GetParamValue(kRareUserOpensNTPAtMostOncePerHoursParam,
+ kRareUserOpensNTPAtMostOncePerHours)) {
+ // The pref_service_ can be null in tests.
+ if (!pref_service_)
+ return;
+
+ // TODO(jkrcal): Store the current discount rate per hour into prefs. If it
+ // differs from the previous value, rescale the metric values so that the
+ // expectation does not change abruptly!
+
+ // Initialize the prefs storing the last time: the counter has just started!
+ for (const Metric metric : kMetrics) {
+ if (!HasLastTime(metric))
+ SetLastTimeToNow(metric);
+ }
+}
+
+UserClassifier::~UserClassifier() = default;
+
+// static
+void UserClassifier::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+ double discount_rate = GetDiscountRatePerHour();
+ double min_hours = GetMinHours();
+ double max_hours = GetMaxHours();
+
+ for (Metric metric : kMetrics) {
+ double default_metric_value = GetMetricValueForEstimateHoursBetweenEvents(
+ GetInitialHoursBetweenEvents(metric), discount_rate, min_hours,
+ max_hours);
+ registry->RegisterDoublePref(kMetricKeys[static_cast<int>(metric)],
+ default_metric_value);
+ registry->RegisterInt64Pref(kLastTimeKeys[static_cast<int>(metric)], 0);
+ }
+}
+
+void UserClassifier::OnEvent(Metric metric) {
+ DCHECK_NE(metric, Metric::COUNT);
+ double metric_value = UpdateMetricOnEvent(metric);
+
+ double avg = GetEstimateHoursBetweenEvents(
+ metric_value, discount_rate_per_hour_, min_hours_, max_hours_);
+ // We use kMaxHours as the max value below as the maximum value for the
+ // histograms must be constant.
+ switch (metric) {
+ case Metric::NTP_OPENED:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToOpenNTP, avg, 1,
+ kMaxHours, 50);
+ break;
+ case Metric::SUGGESTIONS_SHOWN:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToShowSuggestions, avg,
+ 1, kMaxHours, 50);
+ break;
+ case Metric::SUGGESTIONS_USED:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToUseSuggestions, avg,
+ 1, kMaxHours, 50);
+ break;
+ case Metric::COUNT:
+ NOTREACHED();
+ break;
+ }
+}
+
+double UserClassifier::GetEstimatedAvgTime(Metric metric) const {
+ DCHECK_NE(metric, Metric::COUNT);
+ double metric_value = GetUpToDateMetricValue(metric);
+ return GetEstimateHoursBetweenEvents(metric_value, discount_rate_per_hour_,
+ min_hours_, max_hours_);
+}
+
+UserClassifier::UserClass UserClassifier::GetUserClass() const {
+ if (GetEstimatedAvgTime(Metric::NTP_OPENED) >=
+ rare_user_opens_ntp_at_most_once_per_hours_) {
+ return UserClass::RARE_NTP_USER;
+ }
+
+ if (GetEstimatedAvgTime(Metric::SUGGESTIONS_SHOWN) <=
+ active_consumer_scrolls_at_least_once_per_hours_) {
+ return UserClass::ACTIVE_SUGGESTIONS_CONSUMER;
+ }
+
+ return UserClass::ACTIVE_NTP_USER;
+}
+
+std::string UserClassifier::GetUserClassDescriptionForDebugging() const {
+ switch (GetUserClass()) {
+ case UserClass::RARE_NTP_USER:
+ return "Rare user of the NTP";
+ case UserClass::ACTIVE_NTP_USER:
+ return "Active user of the NTP";
+ case UserClass::ACTIVE_SUGGESTIONS_CONSUMER:
+ return "Active consumer of NTP suggestions";
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+void UserClassifier::ClearClassificationForDebugging() {
+ // The pref_service_ can be null in tests.
+ if (!pref_service_)
+ return;
+
+ for (const Metric& metric : kMetrics) {
+ ClearMetricValue(metric);
+ SetLastTimeToNow(metric);
+ }
+}
+
+double UserClassifier::UpdateMetricOnEvent(Metric metric) {
+ // The pref_service_ can be null in tests.
+ if (!pref_service_)
+ return 0;
+
+ double hours_since_last_time =
+ std::min(max_hours_, GetHoursSinceLastTime(metric));
+ // Ignore events within the same "browsing session".
+ if (hours_since_last_time < min_hours_)
+ return GetUpToDateMetricValue(metric);
+
+ SetLastTimeToNow(metric);
+
+ double metric_value = GetMetricValue(metric);
+ // Add 1 to the discounted metric as the event has happened right now.
+ double new_metric_value =
+ 1 + DiscountMetric(metric_value, hours_since_last_time,
+ discount_rate_per_hour_);
+ SetMetricValue(metric, new_metric_value);
+ return new_metric_value;
+}
+
+double UserClassifier::GetUpToDateMetricValue(Metric metric) const {
+ // The pref_service_ can be null in tests.
+ if (!pref_service_)
+ return 0;
+
+ double hours_since_last_time =
+ std::min(max_hours_, GetHoursSinceLastTime(metric));
+
+ double metric_value = GetMetricValue(metric);
+ return DiscountMetric(metric_value, hours_since_last_time,
+ discount_rate_per_hour_);
+}
+
+double UserClassifier::GetHoursSinceLastTime(Metric metric) const {
+ if (!HasLastTime(metric))
+ return 0;
+
+ base::TimeDelta since_last_time =
+ base::Time::Now() - base::Time::FromInternalValue(pref_service_->GetInt64(
+ kLastTimeKeys[static_cast<int>(metric)]));
+ return since_last_time.InSecondsF() / 3600;
+}
+
+bool UserClassifier::HasLastTime(Metric metric) const {
+ return pref_service_->HasPrefPath(kLastTimeKeys[static_cast<int>(metric)]);
+}
+
+void UserClassifier::SetLastTimeToNow(Metric metric) {
+ pref_service_->SetInt64(kLastTimeKeys[static_cast<int>(metric)],
+ base::Time::Now().ToInternalValue());
+}
+
+double UserClassifier::GetMetricValue(Metric metric) const {
+ return pref_service_->GetDouble(kMetricKeys[static_cast<int>(metric)]);
+}
+
+void UserClassifier::SetMetricValue(Metric metric, double metric_value) {
+ pref_service_->SetDouble(kMetricKeys[static_cast<int>(metric)], metric_value);
+}
+
+void UserClassifier::ClearMetricValue(Metric metric) {
+ pref_service_->ClearPref(kMetricKeys[static_cast<int>(metric)]);
+}
+
+} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/user_classifier.h b/chromium/components/ntp_snippets/user_classifier.h
new file mode 100644
index 00000000000..4f8c9848d62
--- /dev/null
+++ b/chromium/components/ntp_snippets/user_classifier.h
@@ -0,0 +1,109 @@
+// 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 COMPONENTS_NTP_SNIPPETS_USER_CLASSIFIER_H_
+#define COMPONENTS_NTP_SNIPPETS_USER_CLASSIFIER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace ntp_snippets {
+
+// Collects data about user usage patterns of content suggestions, computes
+// long-term user metrics locally using pref, and reports the metrics to UMA.
+// Based on these long-term user metrics, it classifies the user in a UserClass.
+class UserClassifier {
+ public:
+ // Enumeration listing user classes
+ enum class UserClass {
+ RARE_NTP_USER,
+ ACTIVE_NTP_USER,
+ ACTIVE_SUGGESTIONS_CONSUMER,
+ };
+
+ // For estimating the average length of the intervals between two successive
+ // events, we keep a simple frequency model, a single value that we call
+ // "metric" below.
+ // We track exponentially-discounted rate of the given event per hour where
+ // the continuous utility function between two successive events (e.g. opening
+ // a NTP) at times t1 < t2 is 1 / (t2-t1), i.e. intuitively the rate of this
+ // event in this time interval.
+ // See https://en.wikipedia.org/wiki/Exponential_discounting for more details.
+ // We keep track of the following events.
+ // NOTE: if you add any element, add it also in the static arrays in .cc and
+ // create another histogram.
+ enum class Metric {
+ NTP_OPENED, // When the user opens a new NTP - this indicates potential
+ // use of content suggestions.
+ SUGGESTIONS_SHOWN, // When the content suggestions are shown to the user -
+ // in the current implementation when the user scrolls
+ // below the fold.
+ SUGGESTIONS_USED, // When the user clicks on some suggestions or on some
+ // "More" button.
+ COUNT // Keep this as the last element.
+ };
+
+ // The provided |pref_service| may be nullptr in unit-tests.
+ explicit UserClassifier(PrefService* pref_service);
+ ~UserClassifier();
+
+ // Registers profile prefs for all metrics. Called from browser_prefs.cc.
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ // Informs the UserClassifier about a new event for |metric|. The
+ // classification is based on these calls.
+ void OnEvent(Metric metric);
+
+ // Get the estimate average length of the interval between two successive
+ // events of the given type.
+ double GetEstimatedAvgTime(Metric metric) const;
+
+ // Return the classification of the current user.
+ UserClass GetUserClass() const;
+ std::string GetUserClassDescriptionForDebugging() const;
+
+ // Resets the classification (emulates a fresh upgrade / install).
+ void ClearClassificationForDebugging();
+
+ private:
+ // The event has happened, recompute the metric accordingly. Then store and
+ // return the new value.
+ double UpdateMetricOnEvent(Metric metric);
+ // No event has happened but we need to get up-to-date metric, recompute and
+ // return the new value. This function does not store the recomputed metric.
+ double GetUpToDateMetricValue(Metric metric) const;
+
+ // Returns the number of hours since the last event of the same type.
+ // If there is no last event of that type, assume it happened just now and
+ // return 0.
+ double GetHoursSinceLastTime(Metric metric) const;
+ bool HasLastTime(Metric metric) const;
+ void SetLastTimeToNow(Metric metric);
+
+ double GetMetricValue(Metric metric) const;
+ void SetMetricValue(Metric metric, double metric_value);
+ void ClearMetricValue(Metric metric);
+
+ PrefService* pref_service_;
+
+ // Params of the metric.
+ const double discount_rate_per_hour_;
+ const double min_hours_;
+ const double max_hours_;
+
+ // Params of the classification.
+ const double active_consumer_scrolls_at_least_once_per_hours_;
+ const double rare_user_opens_ntp_at_most_once_per_hours_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserClassifier);
+};
+
+} // namespace ntp_snippets
+
+#endif // COMPONENTS_NTP_SNIPPETS_USER_CLASSIFIER_H_
diff --git a/chromium/components/ntp_snippets_strings.grdp b/chromium/components/ntp_snippets_strings.grdp
index a7425c11007..1323e786f22 100644
--- a/chromium/components/ntp_snippets_strings.grdp
+++ b/chromium/components/ntp_snippets_strings.grdp
@@ -2,27 +2,41 @@
<grit-part>
<if expr="is_android">
- <message name="IDS_SNIPPETS_DISABLED_SIGNED_OUT_INSTRUCTIONS" desc="Body of the card explaining the status of the NTP suggested content, when the user is signed out." formatter_data="android_java">
+ <message name="IDS_SNIPPETS_DISABLED_SIGNED_OUT_INSTRUCTIONS" desc="Body of the card explaining the status of the content suggestions on the New Tab Page, when the user is signed out." formatter_data="android_java">
To get personalized content suggested by Google, sign in to Chrome.
</message>
- <message name="IDS_SNIPPETS_DISABLED_GENERIC_PROMPT" desc="Title of the card explaining what action the user can take to get suggested content on the NTP." formatter_data="android_java">
+ <message name="IDS_SNIPPETS_DISABLED_GENERIC_PROMPT" desc="Title of the card explaining what action the user can take to get content suggestions on the New Tab Page." formatter_data="android_java">
Get suggested content
</message>
- <message name="IDS_SNIPPETS_DISABLED_SYNC_INSTRUCTIONS" desc="Body of the card explaining the status of the NTP suggested content, when sync is disabled." formatter_data="android_java">
- To get personalized content suggested by Google, turn on sync.
+ <message name="IDS_NTP_STATUS_CARD_TITLE_NO_SUGGESTIONS" desc="On the New Tab Page, title of the status card explaining that there is no new content available in the section." formatter_data="android_java">
+ Done for now
</message>
- <message name="IDS_SNIPPETS_DISABLED_SYNC_ACTION" desc="Label of the action button for the card explaining the status of the NTP suggested content, when sync is disabled." formatter_data="android_java">
- Turn on sync
+ <message name="IDS_NTP_STATUS_CARD_NO_BOOKMARKS" desc="On the New Tab Page, text of the card explaining to the user that they can expect to see bookmarks in this area in the future." formatter_data="android_java">
+ Your recently visited bookmarks will appear here.
</message>
- <message name="IDS_SNIPPETS_DISABLED_HISTORY_SYNC_INSTRUCTIONS" desc="Body of the card explaining the status of the NTP suggested content, when history sync is disabled." formatter_data="android_java">
- To get personalized content suggested by Google, turn on history sync.
- </message>
- <message name="IDS_SNIPPETS_DISABLED_HISTORY_SYNC_ACTION" desc="Label of the action button for the card explaining the status of the NTP suggested content, when history sync is disabled." formatter_data="android_java">
- Turn on history sync
- </message>
- <message name="IDS_SNIPPETS_DISABLED_PASSPHRASE_INSTRUCTIONS" desc="Body of the card explaining the status of the NTP suggested content, when passphrase encryption is enabled." formatter_data="android_java">
- Personalized content suggestions are currently disabled, because your synced data is protected with a custom passphrase.
+ <message name="IDS_NTP_STATUS_CARD_NO_ARTICLES" desc="On the New Tab Page, text of the card explaining to the user that they can expect to see suggested articles in this area in the future." formatter_data="android_java">
+ More articles will appear when the time is right.
</message>
</if>
+ <message name="IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER" desc="Header of the articles section, which is a list of news articles displayed as cards on the New Tab Page.">
+ Articles for you
+ </message>
+
+ <message name="IDS_NTP_RECENT_TAB_SUGGESTIONS_SECTION_HEADER" desc="Header of the recent tabs section, which is a list of pages that the user recently viewed, displayed as cards on the New Tab Page.">
+ Recent tabs
+ </message>
+
+ <message name="IDS_NTP_DOWNLOAD_SUGGESTIONS_SECTION_HEADER" desc="Header of the downloads section, which is a list of pages (or files) that the user downloaded, displayed as cards on the New Tab Page.">
+ Downloads
+ </message>
+
+ <message name="IDS_NTP_BOOKMARK_SUGGESTIONS_SECTION_HEADER" desc="Header of the bookmarks section, which is a list of the user's most recently used bookmarks displayed as cards on the New Tab Page.">
+ Recent bookmarks
+ </message>
+
+ <message name="IDS_NTP_FOREIGN_SESSIONS_SUGGESTIONS_SECTION_HEADER" desc="Header of the foreign sessions, which is a list of the user's most recently visited tabs on other devices displayed as cards on the New Tab Page.">
+ Continue from another device
+ </message>
+
</grit-part>
diff --git a/chromium/components/ntp_tiles.gypi b/chromium/components/ntp_tiles.gypi
deleted file mode 100644
index f146a7fe431..00000000000
--- a/chromium/components/ntp_tiles.gypi
+++ /dev/null
@@ -1,90 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/ntp_tiles
- 'target_name': 'ntp_tiles',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'history_core_browser',
- 'pref_registry',
- 'search_engines',
- 'suggestions',
- 'variations',
- ],
- 'sources': [
- 'ntp_tiles/constants.cc',
- 'ntp_tiles/constants.h',
- 'ntp_tiles/most_visited_sites.cc',
- 'ntp_tiles/most_visited_sites.h',
- 'ntp_tiles/popular_sites.cc',
- 'ntp_tiles/popular_sites.h',
- 'ntp_tiles/pref_names.h',
- 'ntp_tiles/pref_names.cc',
- 'ntp_tiles/switches.h',
- 'ntp_tiles/switches.cc',
- ],
- 'conditions': [
- ['OS != "ios"', {
- 'dependencies': [
- 'safe_json',
- ],
- }],
- ['OS == "android"', {
- 'dependencies': [
- 'ntp_tiles_jni_headers',
- ],
- }],
- ],
- },
- ],
-
- 'conditions': [
- ['OS == "android"', {
- 'targets': [
- {
- # GN: //components/ntp_tiles:ntp_tiles_enums_java
- 'target_name': 'ntp_tiles_enums_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'ntp_tiles/most_visited_sites.h',
- },
- 'includes': [
- '../build/android/java_cpp_enum.gypi'
- ],
- },
- {
- # GN version: //components/ntp_tiles/android:ntp_tiles_java
- 'target_name': 'ntp_tiles_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'variables': {
- 'java_in_dir': 'ntp_tiles/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN version: //components/ntp_tiles:jni
- 'target_name': 'ntp_tiles_jni_headers',
- 'type': 'none',
- 'sources': [
- 'ntp_tiles/android/java/src/org/chromium/components/ntptiles/MostVisitedSites.java',
- ],
- 'variables': {
- 'jni_gen_package': 'ntp_tiles',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/ntp_tiles/BUILD.gn b/chromium/components/ntp_tiles/BUILD.gn
index dc95cd619eb..e51074fe2d0 100644
--- a/chromium/components/ntp_tiles/BUILD.gn
+++ b/chromium/components/ntp_tiles/BUILD.gn
@@ -2,19 +2,18 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-assert(!is_ios) # TODO(sfiera): support iOS http://crbug.com/617966
-
if (is_android) {
import("//build/config/android/rules.gni")
}
-# GYP version: components/ntp_tiles.gypi:ntp_tiles
-source_set("ntp_tiles") {
+static_library("ntp_tiles") {
sources = [
"constants.cc",
"constants.h",
"most_visited_sites.cc",
"most_visited_sites.h",
+ "ntp_tile.cc",
+ "ntp_tile.h",
"popular_sites.cc",
"popular_sites.h",
"pref_names.cc",
@@ -29,10 +28,10 @@ source_set("ntp_tiles") {
"//components/suggestions",
]
deps = [
+ "//components/data_use_measurement/core",
"//components/google/core/browser",
"//components/pref_registry",
"//components/prefs",
- "//components/safe_json",
"//components/search_engines",
"//components/variations",
"//components/variations/service",
@@ -59,6 +58,7 @@ if (is_android) {
java_cpp_enum("ntp_tiles_enums_java") {
sources = [
"most_visited_sites.h",
+ "ntp_tile.h",
]
}
}
diff --git a/chromium/components/ntp_tiles/DEPS b/chromium/components/ntp_tiles/DEPS
index a01a8e32056..fdb9b3d1e59 100644
--- a/chromium/components/ntp_tiles/DEPS
+++ b/chromium/components/ntp_tiles/DEPS
@@ -1,9 +1,9 @@
include_rules = [
+ "+components/data_use_measurement/core",
"+components/google/core/browser",
"+components/history/core/browser",
"+components/pref_registry",
"+components/prefs",
- "+components/safe_json",
"+components/search_engines",
"+components/suggestions",
"+components/variations",
diff --git a/chromium/components/ntp_tiles/OWNERS b/chromium/components/ntp_tiles/OWNERS
index f0b684fb2d5..7078b1cafd0 100644
--- a/chromium/components/ntp_tiles/OWNERS
+++ b/chromium/components/ntp_tiles/OWNERS
@@ -1,2 +1,3 @@
bauerb@chromium.org
treib@chromium.org
+sfiera@chromium.org
diff --git a/chromium/components/ntp_tiles/android/BUILD.gn b/chromium/components/ntp_tiles/android/BUILD.gn
index cf6c2cf970f..e125f19af9b 100644
--- a/chromium/components/ntp_tiles/android/BUILD.gn
+++ b/chromium/components/ntp_tiles/android/BUILD.gn
@@ -7,13 +7,11 @@ import("//build/config/android/rules.gni")
_jni_sources =
[ "java/src/org/chromium/components/ntptiles/MostVisitedSites.java" ]
-# GYP: //components/ntp_tiles.gypi:ntp_tiles_jni_headers
generate_jni("ntp_tiles_jni_headers") {
sources = _jni_sources
jni_package = "ntp_tiles"
}
-# GYP: //components/ntp_tiles.gypi:ntp_tiles_java
android_library("ntp_tiles_java") {
deps = [
"//base:base_java",
diff --git a/chromium/components/ntp_tiles/most_visited_sites.cc b/chromium/components/ntp_tiles/most_visited_sites.cc
index 14468a66a3b..309a0b48d15 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <set>
+#include <string>
#include <utility>
#if defined(OS_ANDROID)
@@ -17,20 +18,18 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
#include "components/history/core/browser/top_sites.h"
#include "components/ntp_tiles/constants.h"
#include "components/ntp_tiles/pref_names.h"
#include "components/ntp_tiles/switches.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
-#include "ui/gfx/codec/jpeg_codec.h"
-#include "url/gurl.h"
#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
@@ -49,7 +48,6 @@ namespace {
// Identifiers for the various tile sources.
const char kHistogramClientName[] = "client";
const char kHistogramServerName[] = "server";
-const char kHistogramServerFormat[] = "server%d";
const char kHistogramPopularName[] = "popular";
const char kHistogramWhitelistName[] = "whitelist";
@@ -79,9 +77,10 @@ bool ShouldShowPopularSites() {
base::FieldTrialList::FindFullName(kPopularSitesFieldTrialName);
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
- if (cmd_line->HasSwitch(ntp_tiles::switches::kDisableNTPPopularSites))
+ if (cmd_line->HasSwitch(switches::kDisableNTPPopularSites))
return false;
- if (cmd_line->HasSwitch(ntp_tiles::switches::kEnableNTPPopularSites))
+
+ if (cmd_line->HasSwitch(switches::kEnableNTPPopularSites))
return true;
#if defined(OS_ANDROID)
@@ -95,24 +94,28 @@ bool ShouldShowPopularSites() {
base::CompareCase::INSENSITIVE_ASCII);
}
-// Determine whether we need any popular suggestions to fill up a grid of
+// Determine whether we need any tiles from PopularSites to fill up a grid of
// |num_tiles| tiles.
-bool NeedPopularSites(const PrefService* prefs, size_t num_tiles) {
+bool NeedPopularSites(const PrefService* prefs, int num_tiles) {
+ if (num_tiles <= prefs->GetInteger(prefs::kNumPersonalTiles))
+ return false;
+
+ // TODO(treib): Remove after M55.
const base::ListValue* source_list =
- prefs->GetList(ntp_tiles::prefs::kNTPSuggestionsIsPersonal);
- // If there aren't enough previous suggestions to fill the grid, we need
- // popular suggestions.
- if (source_list->GetSize() < num_tiles)
+ prefs->GetList(prefs::kDeprecatedNTPTilesIsPersonal);
+ // If there aren't enough previous tiles to fill the grid, we need tiles from
+ // PopularSites.
+ if (static_cast<int>(source_list->GetSize()) < num_tiles)
return true;
- // Otherwise, if any of the previous suggestions is not personal, then also
- // get popular suggestions.
- for (size_t i = 0; i < num_tiles; ++i) {
+ // Otherwise, if any of the previous tiles are not personal, then also
+ // get tiles from PopularSites.
+ for (int i = 0; i < num_tiles; ++i) {
bool is_personal = false;
if (source_list->GetBoolean(i, &is_personal) && !is_personal)
return true;
}
- // The whole grid is already filled with personal suggestions, no point in
- // bothering with popular ones.
+ // The whole grid is already filled with personal tiles, no point in bothering
+ // with popular ones.
return false;
}
@@ -120,88 +123,53 @@ bool AreURLsEquivalent(const GURL& url1, const GURL& url2) {
return url1.host() == url2.host() && url1.path() == url2.path();
}
-std::string GetSourceHistogramName(int source, int provider_index) {
+std::string GetSourceHistogramName(NTPTileSource source) {
switch (source) {
- case MostVisitedSites::TOP_SITES:
+ case NTPTileSource::TOP_SITES:
return kHistogramClientName;
- case MostVisitedSites::POPULAR:
+ case NTPTileSource::POPULAR:
return kHistogramPopularName;
- case MostVisitedSites::WHITELIST:
+ case NTPTileSource::WHITELIST:
return kHistogramWhitelistName;
- case MostVisitedSites::SUGGESTIONS_SERVICE:
- return provider_index >= 0
- ? base::StringPrintf(kHistogramServerFormat, provider_index)
- : kHistogramServerName;
+ case NTPTileSource::SUGGESTIONS_SERVICE:
+ return kHistogramServerName;
}
NOTREACHED();
return std::string();
}
-std::string GetSourceHistogramNameFromSuggestion(
- const MostVisitedSites::Suggestion& suggestion) {
- return GetSourceHistogramName(suggestion.source, suggestion.provider_index);
-}
-
-void AppendSuggestions(MostVisitedSites::SuggestionsVector src,
- MostVisitedSites::SuggestionsVector* dst) {
- dst->insert(dst->end(),
- std::make_move_iterator(src.begin()),
- std::make_move_iterator(src.end()));
-}
-
} // namespace
-MostVisitedSites::Suggestion::Suggestion() : provider_index(-1) {}
-
-MostVisitedSites::Suggestion::~Suggestion() {}
-
-MostVisitedSites::Suggestion::Suggestion(Suggestion&&) = default;
-MostVisitedSites::Suggestion&
-MostVisitedSites::Suggestion::operator=(Suggestion&&) = default;
-
-MostVisitedSites::MostVisitedSites(
- scoped_refptr<base::SequencedWorkerPool> blocking_pool,
- PrefService* prefs,
- const TemplateURLService* template_url_service,
- variations::VariationsService* variations_service,
- net::URLRequestContextGetter* download_context,
- const base::FilePath& popular_sites_directory,
- scoped_refptr<history::TopSites> top_sites,
- SuggestionsService* suggestions,
- MostVisitedSitesSupervisor* supervisor)
+MostVisitedSites::MostVisitedSites(PrefService* prefs,
+ scoped_refptr<history::TopSites> top_sites,
+ SuggestionsService* suggestions,
+ std::unique_ptr<PopularSites> popular_sites,
+ MostVisitedSitesSupervisor* supervisor)
: prefs_(prefs),
- template_url_service_(template_url_service),
- variations_service_(variations_service),
- download_context_(download_context),
- popular_sites_directory_(popular_sites_directory),
top_sites_(top_sites),
suggestions_service_(suggestions),
+ popular_sites_(std::move(popular_sites)),
supervisor_(supervisor),
observer_(nullptr),
num_sites_(0),
- received_most_visited_sites_(false),
- received_popular_sites_(false),
+ waiting_for_most_visited_sites_(true),
+ waiting_for_popular_sites_(true),
recorded_uma_(false),
- scoped_observer_(this),
- mv_source_(SUGGESTIONS_SERVICE),
- blocking_pool_(std::move(blocking_pool)),
- blocking_runner_(blocking_pool_->GetTaskRunnerWithShutdownBehavior(
- base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)),
+ top_sites_observer_(this),
+ mv_source_(NTPTileSource::SUGGESTIONS_SERVICE),
weak_ptr_factory_(this) {
+ DCHECK(prefs_);
+ // top_sites_ can be null in tests.
+ // TODO(sfiera): have iOS use a dummy TopSites in its tests.
DCHECK(suggestions_service_);
- supervisor_->SetObserver(this);
+ if (supervisor_)
+ supervisor_->SetObserver(this);
}
MostVisitedSites::~MostVisitedSites() {
- supervisor_->SetObserver(nullptr);
-}
-
-#if defined(OS_ANDROID)
-// static
-bool MostVisitedSites::Register(JNIEnv* env) {
- return RegisterNativesImpl(env);
+ if (supervisor_)
+ supervisor_->SetObserver(nullptr);
}
-#endif
void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
int num_sites) {
@@ -209,15 +177,13 @@ void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
observer_ = observer;
num_sites_ = num_sites;
- if (ShouldShowPopularSites() &&
+ if (popular_sites_ && ShouldShowPopularSites() &&
NeedPopularSites(prefs_, num_sites_)) {
- popular_sites_.reset(new PopularSites(
- blocking_pool_, prefs_, template_url_service_, variations_service_,
- download_context_, popular_sites_directory_, false,
- base::Bind(&MostVisitedSites::OnPopularSitesAvailable,
- base::Unretained(this))));
+ popular_sites_->StartFetch(
+ false, base::Bind(&MostVisitedSites::OnPopularSitesAvailable,
+ base::Unretained(this)));
} else {
- received_popular_sites_ = true;
+ waiting_for_popular_sites_ = false;
}
if (top_sites_) {
@@ -227,16 +193,16 @@ void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
// Register as TopSitesObserver so that we can update ourselves when the
// TopSites changes.
- scoped_observer_.Add(top_sites_.get());
+ top_sites_observer_.Add(top_sites_.get());
}
suggestions_subscription_ = suggestions_service_->AddCallback(
base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable,
base::Unretained(this)));
- // Immediately build the current suggestions, getting personal suggestions
- // from the SuggestionsService's cache or, if that is empty, from TopSites.
- BuildCurrentSuggestions();
+ // Immediately build the current set of tiles, getting suggestions from the
+ // SuggestionsService's cache or, if that is empty, sites from TopSites.
+ BuildCurrentTiles();
// Also start a request for fresh suggestions.
suggestions_service_->FetchSuggestionsData();
}
@@ -252,7 +218,7 @@ void MostVisitedSites::AddOrRemoveBlacklistedUrl(const GURL& url,
}
// Only blacklist in the server-side suggestions service if it's active.
- if (mv_source_ == SUGGESTIONS_SERVICE) {
+ if (mv_source_ == NTPTileSource::SUGGESTIONS_SERVICE) {
if (add_url)
suggestions_service_->BlacklistURL(url);
else
@@ -261,16 +227,18 @@ void MostVisitedSites::AddOrRemoveBlacklistedUrl(const GURL& url,
}
void MostVisitedSites::RecordTileTypeMetrics(
- const std::vector<int>& tile_types,
- const std::vector<int>& sources,
- const std::vector<int>& provider_indices) {
+ const std::vector<MostVisitedTileType>& tile_types,
+ const std::vector<NTPTileSource>& sources) {
int counts_per_type[NUM_TILE_TYPES] = {0};
for (size_t i = 0; i < tile_types.size(); ++i) {
- int tile_type = tile_types[i];
+ MostVisitedTileType tile_type = tile_types[i];
++counts_per_type[tile_type];
+
+ UMA_HISTOGRAM_ENUMERATION("NewTabPage.TileType", tile_type, NUM_TILE_TYPES);
+
std::string histogram = base::StringPrintf(
"NewTabPage.TileType.%s",
- GetSourceHistogramName(sources[i], provider_indices[i]).c_str());
+ GetSourceHistogramName(sources[i]).c_str());
LogHistogramEvent(histogram, tile_type, NUM_TILE_TYPES);
}
@@ -282,42 +250,38 @@ void MostVisitedSites::RecordTileTypeMetrics(
counts_per_type[ICON_DEFAULT]);
}
-void MostVisitedSites::RecordOpenedMostVisitedItem(int index, int tile_type) {
- // TODO(treib): |current_suggestions_| could be updated before this function
- // is called, leading to DCHECKs and/or memory corruption. Adjust this
- // function to work with asynchronous UI.
- DCHECK_GE(index, 0);
- DCHECK_LT(index, static_cast<int>(current_suggestions_.size()));
+void MostVisitedSites::RecordOpenedMostVisitedItem(
+ int index,
+ MostVisitedTileType tile_type,
+ NTPTileSource source) {
+ UMA_HISTOGRAM_ENUMERATION("NewTabPage.MostVisited", index, num_sites_);
+
std::string histogram = base::StringPrintf(
- "NewTabPage.MostVisited.%s",
- GetSourceHistogramNameFromSuggestion(current_suggestions_[index])
- .c_str());
+ "NewTabPage.MostVisited.%s", GetSourceHistogramName(source).c_str());
LogHistogramEvent(histogram, index, num_sites_);
- histogram = base::StringPrintf(
- "NewTabPage.TileTypeClicked.%s",
- GetSourceHistogramNameFromSuggestion(current_suggestions_[index])
- .c_str());
+ UMA_HISTOGRAM_ENUMERATION(
+ "NewTabPage.TileTypeClicked", tile_type, NUM_TILE_TYPES);
+
+ histogram = base::StringPrintf("NewTabPage.TileTypeClicked.%s",
+ GetSourceHistogramName(source).c_str());
LogHistogramEvent(histogram, tile_type, NUM_TILE_TYPES);
}
void MostVisitedSites::OnBlockedSitesChanged() {
- BuildCurrentSuggestions();
+ BuildCurrentTiles();
}
// static
void MostVisitedSites::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
- // TODO(treib): Remove this, it's unused. Do we need migration code to clean
- // up existing entries?
- registry->RegisterListPref(ntp_tiles::prefs::kNTPSuggestionsURL);
- // TODO(treib): Remove this. It's only used to determine if we need
- // PopularSites at all. Find a way to do that without prefs, or failing that,
- // replace this list pref by a simple bool.
- registry->RegisterListPref(ntp_tiles::prefs::kNTPSuggestionsIsPersonal);
+ registry->RegisterIntegerPref(prefs::kNumPersonalTiles, 0);
+ // TODO(treib): Remove after M55.
+ registry->RegisterListPref(prefs::kDeprecatedNTPTilesURL);
+ registry->RegisterListPref(prefs::kDeprecatedNTPTilesIsPersonal);
}
-void MostVisitedSites::BuildCurrentSuggestions() {
+void MostVisitedSites::BuildCurrentTiles() {
// Get the current suggestions from cache. If the cache is empty, this will
// fall back to TopSites.
OnSuggestionsProfileAvailable(
@@ -334,16 +298,18 @@ void MostVisitedSites::InitiateTopSitesQuery() {
}
base::FilePath MostVisitedSites::GetWhitelistLargeIconPath(const GURL& url) {
- for (const auto& whitelist : supervisor_->whitelists()) {
- if (AreURLsEquivalent(whitelist.entry_point, url))
- return whitelist.large_icon_path;
+ if (supervisor_) {
+ for (const auto& whitelist : supervisor_->whitelists()) {
+ if (AreURLsEquivalent(whitelist.entry_point, url))
+ return whitelist.large_icon_path;
+ }
}
return base::FilePath();
}
void MostVisitedSites::OnMostVisitedURLsAvailable(
const history::MostVisitedURLList& visited_list) {
- SuggestionsVector suggestions;
+ NTPTilesVector tiles;
size_t num_tiles =
std::min(visited_list.size(), static_cast<size_t>(num_sites_));
for (size_t i = 0; i < num_tiles; ++i) {
@@ -352,21 +318,21 @@ void MostVisitedSites::OnMostVisitedURLsAvailable(
num_tiles = i;
break; // This is the signal that there are no more real visited sites.
}
- if (supervisor_->IsBlocked(visited.url))
+ if (supervisor_ && supervisor_->IsBlocked(visited.url))
continue;
- Suggestion suggestion;
- suggestion.title = visited.title;
- suggestion.url = visited.url;
- suggestion.source = TOP_SITES;
- suggestion.whitelist_icon_path = GetWhitelistLargeIconPath(visited.url);
+ NTPTile tile;
+ tile.title = visited.title;
+ tile.url = visited.url;
+ tile.source = NTPTileSource::TOP_SITES;
+ tile.whitelist_icon_path = GetWhitelistLargeIconPath(visited.url);
- suggestions.push_back(std::move(suggestion));
+ tiles.push_back(std::move(tile));
}
- received_most_visited_sites_ = true;
- mv_source_ = TOP_SITES;
- SaveNewSuggestions(std::move(suggestions));
+ waiting_for_most_visited_sites_ = false;
+ mv_source_ = NTPTileSource::TOP_SITES;
+ SaveNewTiles(std::move(tiles));
NotifyMostVisitedURLsObserver();
}
@@ -382,49 +348,50 @@ void MostVisitedSites::OnSuggestionsProfileAvailable(
if (num_sites_ < num_tiles)
num_tiles = num_sites_;
- SuggestionsVector suggestions;
+ NTPTilesVector tiles;
for (int i = 0; i < num_tiles; ++i) {
- const ChromeSuggestion& suggestion = suggestions_profile.suggestions(i);
- if (supervisor_->IsBlocked(GURL(suggestion.url())))
+ const ChromeSuggestion& suggestion_pb = suggestions_profile.suggestions(i);
+ GURL url(suggestion_pb.url());
+ if (supervisor_ && supervisor_->IsBlocked(url))
continue;
- Suggestion generated_suggestion;
- generated_suggestion.title = base::UTF8ToUTF16(suggestion.title());
- generated_suggestion.url = GURL(suggestion.url());
- generated_suggestion.source = SUGGESTIONS_SERVICE;
- generated_suggestion.whitelist_icon_path =
- GetWhitelistLargeIconPath(GURL(suggestion.url()));
- if (suggestion.providers_size() > 0)
- generated_suggestion.provider_index = suggestion.providers(0);
+ NTPTile tile;
+ tile.title = base::UTF8ToUTF16(suggestion_pb.title());
+ tile.url = url;
+ tile.source = NTPTileSource::SUGGESTIONS_SERVICE;
+ tile.whitelist_icon_path = GetWhitelistLargeIconPath(url);
- suggestions.push_back(std::move(generated_suggestion));
+ tiles.push_back(std::move(tile));
}
- received_most_visited_sites_ = true;
- mv_source_ = SUGGESTIONS_SERVICE;
- SaveNewSuggestions(std::move(suggestions));
+ waiting_for_most_visited_sites_ = false;
+ mv_source_ = NTPTileSource::SUGGESTIONS_SERVICE;
+ SaveNewTiles(std::move(tiles));
NotifyMostVisitedURLsObserver();
}
-MostVisitedSites::SuggestionsVector
-MostVisitedSites::CreateWhitelistEntryPointSuggestions(
- const SuggestionsVector& personal_suggestions) {
- size_t num_personal_suggestions = personal_suggestions.size();
- DCHECK_LE(num_personal_suggestions, static_cast<size_t>(num_sites_));
+NTPTilesVector MostVisitedSites::CreateWhitelistEntryPointTiles(
+ const NTPTilesVector& personal_tiles) {
+ if (!supervisor_) {
+ return NTPTilesVector();
+ }
+
+ size_t num_personal_tiles = personal_tiles.size();
+ DCHECK_LE(num_personal_tiles, static_cast<size_t>(num_sites_));
- size_t num_whitelist_suggestions = num_sites_ - num_personal_suggestions;
- SuggestionsVector whitelist_suggestions;
+ size_t num_whitelist_tiles = num_sites_ - num_personal_tiles;
+ NTPTilesVector whitelist_tiles;
std::set<std::string> personal_hosts;
- for (const auto& suggestion : personal_suggestions)
- personal_hosts.insert(suggestion.url.host());
+ for (const auto& tile : personal_tiles)
+ personal_hosts.insert(tile.url.host());
for (const auto& whitelist : supervisor_->whitelists()) {
// Skip blacklisted sites.
if (top_sites_ && top_sites_->IsBlacklisted(whitelist.entry_point))
continue;
- // Skip suggestions already present.
+ // Skip tiles already present.
if (personal_hosts.find(whitelist.entry_point.host()) !=
personal_hosts.end())
continue;
@@ -433,127 +400,118 @@ MostVisitedSites::CreateWhitelistEntryPointSuggestions(
if (supervisor_->IsBlocked(whitelist.entry_point))
continue;
- Suggestion suggestion;
- suggestion.title = whitelist.title;
- suggestion.url = whitelist.entry_point;
- suggestion.source = WHITELIST;
- suggestion.whitelist_icon_path = whitelist.large_icon_path;
+ NTPTile tile;
+ tile.title = whitelist.title;
+ tile.url = whitelist.entry_point;
+ tile.source = NTPTileSource::WHITELIST;
+ tile.whitelist_icon_path = whitelist.large_icon_path;
- whitelist_suggestions.push_back(std::move(suggestion));
- if (whitelist_suggestions.size() >= num_whitelist_suggestions)
+ whitelist_tiles.push_back(std::move(tile));
+ if (whitelist_tiles.size() >= num_whitelist_tiles)
break;
}
- return whitelist_suggestions;
+ return whitelist_tiles;
}
-MostVisitedSites::SuggestionsVector
-MostVisitedSites::CreatePopularSitesSuggestions(
- const SuggestionsVector& personal_suggestions,
- const SuggestionsVector& whitelist_suggestions) {
- // For child accounts popular sites suggestions will not be added.
- if (supervisor_->IsChildProfile())
- return SuggestionsVector();
+NTPTilesVector MostVisitedSites::CreatePopularSitesTiles(
+ const NTPTilesVector& personal_tiles,
+ const NTPTilesVector& whitelist_tiles) {
+ // For child accounts popular sites tiles will not be added.
+ if (supervisor_ && supervisor_->IsChildProfile())
+ return NTPTilesVector();
- size_t num_suggestions =
- personal_suggestions.size() + whitelist_suggestions.size();
- DCHECK_LE(num_suggestions, static_cast<size_t>(num_sites_));
+ size_t num_tiles = personal_tiles.size() + whitelist_tiles.size();
+ DCHECK_LE(num_tiles, static_cast<size_t>(num_sites_));
// Collect non-blacklisted popular suggestions, skipping those already present
// in the personal suggestions.
- size_t num_popular_sites_suggestions = num_sites_ - num_suggestions;
- SuggestionsVector popular_sites_suggestions;
+ size_t num_popular_sites_tiles = num_sites_ - num_tiles;
+ NTPTilesVector popular_sites_tiles;
- if (num_popular_sites_suggestions > 0 && popular_sites_) {
+ if (num_popular_sites_tiles > 0 && popular_sites_) {
std::set<std::string> hosts;
- for (const auto& suggestion : personal_suggestions)
- hosts.insert(suggestion.url.host());
- for (const auto& suggestion : whitelist_suggestions)
- hosts.insert(suggestion.url.host());
+ for (const auto& tile : personal_tiles)
+ hosts.insert(tile.url.host());
+ for (const auto& tile : whitelist_tiles)
+ hosts.insert(tile.url.host());
for (const PopularSites::Site& popular_site : popular_sites_->sites()) {
// Skip blacklisted sites.
if (top_sites_ && top_sites_->IsBlacklisted(popular_site.url))
continue;
std::string host = popular_site.url.host();
- // Skip suggestions already present in personal or whitelists.
+ // Skip tiles already present in personal or whitelists.
if (hosts.find(host) != hosts.end())
continue;
- Suggestion suggestion;
- suggestion.title = popular_site.title;
- suggestion.url = GURL(popular_site.url);
- suggestion.source = POPULAR;
+ NTPTile tile;
+ tile.title = popular_site.title;
+ tile.url = GURL(popular_site.url);
+ tile.source = NTPTileSource::POPULAR;
- popular_sites_suggestions.push_back(std::move(suggestion));
- if (popular_sites_suggestions.size() >= num_popular_sites_suggestions)
+ popular_sites_tiles.push_back(std::move(tile));
+ if (popular_sites_tiles.size() >= num_popular_sites_tiles)
break;
}
}
- return popular_sites_suggestions;
+ return popular_sites_tiles;
}
-void MostVisitedSites::SaveNewSuggestions(
- SuggestionsVector personal_suggestions) {
- SuggestionsVector whitelist_suggestions =
- CreateWhitelistEntryPointSuggestions(personal_suggestions);
- SuggestionsVector popular_sites_suggestions =
- CreatePopularSitesSuggestions(personal_suggestions,
- whitelist_suggestions);
-
- size_t num_actual_tiles = personal_suggestions.size() +
- whitelist_suggestions.size() +
- popular_sites_suggestions.size();
+void MostVisitedSites::SaveNewTiles(NTPTilesVector personal_tiles) {
+ NTPTilesVector whitelist_tiles =
+ CreateWhitelistEntryPointTiles(personal_tiles);
+ NTPTilesVector popular_sites_tiles =
+ CreatePopularSitesTiles(personal_tiles, whitelist_tiles);
+
+ size_t num_actual_tiles = personal_tiles.size() + whitelist_tiles.size() +
+ popular_sites_tiles.size();
DCHECK_LE(num_actual_tiles, static_cast<size_t>(num_sites_));
- current_suggestions_ = MergeSuggestions(std::move(personal_suggestions),
- std::move(whitelist_suggestions),
- std::move(popular_sites_suggestions));
- DCHECK_EQ(num_actual_tiles, current_suggestions_.size());
+ current_tiles_ =
+ MergeTiles(std::move(personal_tiles), std::move(whitelist_tiles),
+ std::move(popular_sites_tiles));
+ DCHECK_EQ(num_actual_tiles, current_tiles_.size());
- if (received_popular_sites_)
- SaveCurrentSuggestionsToPrefs();
+ int num_personal_tiles = 0;
+ for (const auto& tile : current_tiles_) {
+ if (tile.source != NTPTileSource::POPULAR)
+ num_personal_tiles++;
+ }
+ prefs_->SetInteger(prefs::kNumPersonalTiles, num_personal_tiles);
+ // TODO(treib): Remove after M55.
+ prefs_->ClearPref(prefs::kDeprecatedNTPTilesIsPersonal);
+ prefs_->ClearPref(prefs::kDeprecatedNTPTilesURL);
}
// static
-MostVisitedSites::SuggestionsVector MostVisitedSites::MergeSuggestions(
- SuggestionsVector personal_suggestions,
- SuggestionsVector whitelist_suggestions,
- SuggestionsVector popular_suggestions) {
- SuggestionsVector merged_suggestions;
- AppendSuggestions(std::move(personal_suggestions), &merged_suggestions);
- AppendSuggestions(std::move(whitelist_suggestions), &merged_suggestions);
- AppendSuggestions(std::move(popular_suggestions), &merged_suggestions);
- return merged_suggestions;
-}
-
-void MostVisitedSites::SaveCurrentSuggestionsToPrefs() {
- base::ListValue url_list;
- base::ListValue source_list;
- for (const auto& suggestion : current_suggestions_) {
- url_list.AppendString(suggestion.url.spec());
- source_list.AppendBoolean(suggestion.source != POPULAR);
- }
- prefs_->Set(ntp_tiles::prefs::kNTPSuggestionsIsPersonal, source_list);
- prefs_->Set(ntp_tiles::prefs::kNTPSuggestionsURL, url_list);
+NTPTilesVector MostVisitedSites::MergeTiles(NTPTilesVector personal_tiles,
+ NTPTilesVector whitelist_tiles,
+ NTPTilesVector popular_tiles) {
+ NTPTilesVector merged_tiles;
+ std::move(personal_tiles.begin(), personal_tiles.end(),
+ std::back_inserter(merged_tiles));
+ std::move(whitelist_tiles.begin(), whitelist_tiles.end(),
+ std::back_inserter(merged_tiles));
+ std::move(popular_tiles.begin(), popular_tiles.end(),
+ std::back_inserter(merged_tiles));
+ return merged_tiles;
}
void MostVisitedSites::NotifyMostVisitedURLsObserver() {
- if (received_most_visited_sites_ && received_popular_sites_ &&
+ if (!waiting_for_most_visited_sites_ && !waiting_for_popular_sites_ &&
!recorded_uma_) {
RecordImpressionUMAMetrics();
- UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfTiles",
- current_suggestions_.size());
recorded_uma_ = true;
}
if (!observer_)
return;
- observer_->OnMostVisitedURLsAvailable(current_suggestions_);
+ observer_->OnMostVisitedURLsAvailable(current_tiles_);
}
void MostVisitedSites::OnPopularSitesAvailable(bool success) {
- received_popular_sites_ = true;
+ waiting_for_popular_sites_ = false;
if (!success) {
LOG(WARNING) << "Download of popular sites failed";
@@ -564,15 +522,21 @@ void MostVisitedSites::OnPopularSitesAvailable(bool success) {
// missing icons, but will *not* cause it to display the popular sites.
observer_->OnPopularURLsAvailable(popular_sites_->sites());
- // Re-build the suggestions list. Once done, this will notify the observer.
- BuildCurrentSuggestions();
+ // Re-build the tile list. Once done, this will notify the observer.
+ BuildCurrentTiles();
}
void MostVisitedSites::RecordImpressionUMAMetrics() {
- for (size_t i = 0; i < current_suggestions_.size(); i++) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfTiles",
+ current_tiles_.size());
+
+ for (size_t i = 0; i < current_tiles_.size(); i++) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "NewTabPage.SuggestionsImpression", static_cast<int>(i), num_sites_);
+
std::string histogram = base::StringPrintf(
"NewTabPage.SuggestionsImpression.%s",
- GetSourceHistogramNameFromSuggestion(current_suggestions_[i]).c_str());
+ GetSourceHistogramName(current_tiles_[i].source).c_str());
LogHistogramEvent(histogram, static_cast<int>(i), num_sites_);
}
}
@@ -581,8 +545,8 @@ void MostVisitedSites::TopSitesLoaded(TopSites* top_sites) {}
void MostVisitedSites::TopSitesChanged(TopSites* top_sites,
ChangeReason change_reason) {
- if (mv_source_ == TOP_SITES) {
- // The displayed suggestions are invalidated.
+ if (mv_source_ == NTPTileSource::TOP_SITES) {
+ // The displayed tiles are invalidated.
InitiateTopSitesQuery();
}
}
diff --git a/chromium/components/ntp_tiles/most_visited_sites.h b/chromium/components/ntp_tiles/most_visited_sites.h
index efbae53ff45..28f9b070df0 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.h
+++ b/chromium/components/ntp_tiles/most_visited_sites.h
@@ -8,7 +8,6 @@
#include <stddef.h>
#include <memory>
-#include <string>
#include <vector>
#include "base/compiler_specific.h"
@@ -16,33 +15,23 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
+#include "base/strings/string16.h"
#include "components/history/core/browser/history_types.h"
#include "components/history/core/browser/top_sites_observer.h"
+#include "components/ntp_tiles/ntp_tile.h"
#include "components/ntp_tiles/popular_sites.h"
#include "components/suggestions/proto/suggestions.pb.h"
#include "components/suggestions/suggestions_service.h"
#include "url/gurl.h"
-namespace gfx {
-class Image;
-}
-
namespace history {
class TopSites;
}
-namespace suggestions {
-class SuggestionsService;
-}
-
namespace user_prefs {
class PrefRegistrySyncable;
}
-namespace variations {
-class VariationsService;
-}
-
namespace ntp_tiles {
// Shim interface for SupervisedUserService.
@@ -71,7 +60,7 @@ class MostVisitedSitesSupervisor {
// If true, |url| should not be shown on the NTP.
virtual bool IsBlocked(const GURL& url) = 0;
- // Explicit suggestions for sites to show on NTP.
+ // Explicitly-specified sites to show on NTP.
virtual std::vector<Whitelist> whitelists() = 0;
// If true, be conservative about suggesting sites from outside sources.
@@ -91,8 +80,6 @@ class MostVisitedSitesSupervisor {
class MostVisitedSites : public history::TopSitesObserver,
public MostVisitedSitesSupervisor::Observer {
public:
- struct Suggestion;
- using SuggestionsVector = std::vector<Suggestion>;
using PopularSitesVector = std::vector<PopularSites::Site>;
// The visual type of a most visited tile.
@@ -114,79 +101,39 @@ class MostVisitedSites : public history::TopSitesObserver,
NUM_TILE_TYPES,
};
- // The source of the Most Visited sites.
- // A Java counterpart will be generated for this enum.
- // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp
- enum MostVisitedSource {
- // Item comes from the personal top sites list.
- TOP_SITES,
- // Item comes from the suggestions service.
- SUGGESTIONS_SERVICE,
- // Item is regionally popular.
- POPULAR,
- // Item is on an custodian-managed whitelist.
- WHITELIST
- };
-
// The observer to be notified when the list of most visited sites changes.
class Observer {
public:
- virtual void OnMostVisitedURLsAvailable(
- const SuggestionsVector& suggestions) = 0;
- virtual void OnPopularURLsAvailable(const PopularSitesVector& sites) = 0;
+ virtual void OnMostVisitedURLsAvailable(const NTPTilesVector& tiles) = 0;
+ virtual void OnPopularURLsAvailable(const PopularSitesVector& sites) {}
protected:
virtual ~Observer() {}
};
- struct Suggestion {
- base::string16 title;
- GURL url;
- MostVisitedSource source;
-
- // Only valid for source == WHITELIST (empty otherwise).
- base::FilePath whitelist_icon_path;
-
- // Only valid for source == SUGGESTIONS_SERVICE (-1 otherwise).
- int provider_index;
-
- Suggestion();
- ~Suggestion();
-
- Suggestion(Suggestion&&);
- Suggestion& operator=(Suggestion&&);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Suggestion);
- };
-
- MostVisitedSites(scoped_refptr<base::SequencedWorkerPool> blocking_pool,
- PrefService* prefs,
- const TemplateURLService* template_url_service,
- variations::VariationsService* variations_service,
- net::URLRequestContextGetter* download_context,
- const base::FilePath& popular_sites_directory,
+ // Construct a MostVisitedSites instance.
+ //
+ // |prefs| and |suggestions| are required and may not be null. |top_sites|,
+ // |popular_sites|, and |supervisor| are optional and if null the associated
+ // features will be disabled.
+ MostVisitedSites(PrefService* prefs,
scoped_refptr<history::TopSites> top_sites,
suggestions::SuggestionsService* suggestions,
+ std::unique_ptr<PopularSites> popular_sites,
MostVisitedSitesSupervisor* supervisor);
~MostVisitedSites() override;
-#if defined(OS_ANDROID)
- static bool Register(JNIEnv* env);
-#endif
-
// Does not take ownership of |observer|, which must outlive this object and
// must not be null.
void SetMostVisitedURLsObserver(Observer* observer, int num_sites);
- using ThumbnailCallback = base::Callback<
- void(bool /* is_local_thumbnail */, const SkBitmap* /* bitmap */)>;
void AddOrRemoveBlacklistedUrl(const GURL& url, bool add_url);
- void RecordTileTypeMetrics(const std::vector<int>& tile_types,
- const std::vector<int>& sources,
- const std::vector<int>& provider_indices);
- void RecordOpenedMostVisitedItem(int index, int tile_type);
+ void RecordTileTypeMetrics(const std::vector<MostVisitedTileType>& tile_types,
+ const std::vector<NTPTileSource>& sources);
+ void RecordOpenedMostVisitedItem(int index,
+ MostVisitedTileType tile_type,
+ NTPTileSource source);
// MostVisitedSitesSupervisor::Observer implementation.
void OnBlockedSitesChanged() override;
@@ -196,7 +143,7 @@ class MostVisitedSites : public history::TopSitesObserver,
private:
friend class MostVisitedSitesTest;
- void BuildCurrentSuggestions();
+ void BuildCurrentTiles();
// Initialize the query to Top Sites. Called if the SuggestionsService
// returned no data.
@@ -215,37 +162,30 @@ class MostVisitedSites : public history::TopSitesObserver,
// Takes the personal suggestions and creates whitelist entry point
// suggestions if necessary.
- SuggestionsVector CreateWhitelistEntryPointSuggestions(
- const SuggestionsVector& personal_suggestions);
-
- // Takes the personal and whitelist suggestions and creates popular
- // suggestions if necessary.
- SuggestionsVector CreatePopularSitesSuggestions(
- const SuggestionsVector& personal_suggestions,
- const SuggestionsVector& whitelist_suggestions);
+ NTPTilesVector CreateWhitelistEntryPointTiles(
+ const NTPTilesVector& personal_tiles);
- // Takes the personal suggestions, creates and merges in whitelist and popular
- // suggestions if appropriate, and saves the new suggestions.
- void SaveNewSuggestions(SuggestionsVector personal_suggestions);
+ // Takes the personal and whitelist tiles and creates popular tiles if
+ // necessary.
+ NTPTilesVector CreatePopularSitesTiles(const NTPTilesVector& personal_tiles,
+ const NTPTilesVector& whitelist_tiles);
- // Workhorse for SaveNewSuggestions above. Implemented as a separate static
- // method for ease of testing.
- static SuggestionsVector MergeSuggestions(
- SuggestionsVector personal_suggestions,
- SuggestionsVector whitelist_suggestions,
- SuggestionsVector popular_suggestions);
+ // Takes the personal tiles, creates and merges in whitelist and popular tiles
+ // if appropriate, and saves the new tiles.
+ void SaveNewTiles(NTPTilesVector personal_tiles);
- void SaveCurrentSuggestionsToPrefs();
+ // Workhorse for SaveNewTiles above. Implemented as a separate static method
+ // for ease of testing.
+ static NTPTilesVector MergeTiles(NTPTilesVector personal_tiles,
+ NTPTilesVector whitelist_tiles,
+ NTPTilesVector popular_tiles);
- // Notifies the observer about the availability of suggestions.
+ // Notifies the observer about the availability of tiles.
// Also records impressions UMA if not done already.
void NotifyMostVisitedURLsObserver();
void OnPopularSitesAvailable(bool success);
- // Records thumbnail-related UMA histogram metrics.
- void RecordThumbnailUMAMetrics();
-
// Records UMA histogram metrics related to the number of impressions.
void RecordImpressionUMAMetrics();
@@ -255,12 +195,9 @@ class MostVisitedSites : public history::TopSitesObserver,
ChangeReason change_reason) override;
PrefService* prefs_;
- const TemplateURLService* template_url_service_;
- variations::VariationsService* variations_service_;
- net::URLRequestContextGetter* download_context_;
- base::FilePath popular_sites_directory_;
scoped_refptr<history::TopSites> top_sites_;
suggestions::SuggestionsService* suggestions_service_;
+ std::unique_ptr<PopularSites> const popular_sites_;
MostVisitedSitesSupervisor* supervisor_;
Observer* observer_;
@@ -268,15 +205,15 @@ class MostVisitedSites : public history::TopSitesObserver,
// The maximum number of most visited sites to return.
int num_sites_;
- // Whether we have received an initial set of most visited sites (from either
- // TopSites or the SuggestionsService).
- bool received_most_visited_sites_;
+ // True if we are still waiting for an initial set of most visited sites (from
+ // either TopSites or the SuggestionsService).
+ bool waiting_for_most_visited_sites_;
- // Whether we have received the set of popular sites. Immediately set to true
- // if popular sites are disabled.
- bool received_popular_sites_;
+ // True if we are still waiting for the set of popular sites. Immediately set
+ // to false if popular sites are disabled, or are not required.
+ bool waiting_for_popular_sites_;
- // Whether we have recorded one-shot UMA metrics such as impressions. They are
+ // True if we have recorded one-shot UMA metrics such as impressions. They are
// recorded once both the previous flags are true.
bool recorded_uma_;
@@ -284,17 +221,13 @@ class MostVisitedSites : public history::TopSitesObserver,
suggestions::SuggestionsService::ResponseCallbackList::Subscription>
suggestions_subscription_;
- ScopedObserver<history::TopSites, history::TopSitesObserver> scoped_observer_;
-
- MostVisitedSource mv_source_;
-
- std::unique_ptr<PopularSites> popular_sites_;
+ ScopedObserver<history::TopSites, history::TopSitesObserver>
+ top_sites_observer_;
- SuggestionsVector current_suggestions_;
+ // The main source of personal tiles - either TOP_SITES or SUGGESTIONS_SEVICE.
+ NTPTileSource mv_source_;
- base::ThreadChecker thread_checker_;
- scoped_refptr<base::SequencedWorkerPool> blocking_pool_;
- scoped_refptr<base::TaskRunner> blocking_runner_;
+ NTPTilesVector current_tiles_;
// For callbacks may be run after destruction.
base::WeakPtrFactory<MostVisitedSites> weak_ptr_factory_;
diff --git a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
index e88f518f648..6fbc9dcd087 100644
--- a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -36,13 +36,13 @@ static const size_t kNumSites = 4;
} // namespace
-// This a test for MostVisitedSites::MergeSuggestions(...) method, and thus has
-// the same scope as the method itself. This tests merging popular suggestions
-// with personal suggestions.
+// This a test for MostVisitedSites::MergeTiles(...) method, and thus has the
+// same scope as the method itself. This tests merging popular sites with
+// personal tiles.
// More important things out of the scope of testing presently:
-// - Removing blacklisted suggestions.
+// - Removing blacklisted tiles.
// - Correct host extraction from the URL.
-// - Ensuring personal suggestions are not duplicated in popular suggestions.
+// - Ensuring personal tiles are not duplicated in popular tiles.
class MostVisitedSitesTest : public testing::Test {
protected:
void Check(const std::vector<TitleURL>& popular_sites,
@@ -50,42 +50,39 @@ class MostVisitedSitesTest : public testing::Test {
const std::vector<TitleURL>& personal_sites,
const std::vector<bool>& expected_sites_is_personal,
const std::vector<TitleURL>& expected_sites) {
- MostVisitedSites::SuggestionsVector personal_suggestions;
+ NTPTilesVector personal_tiles;
for (const TitleURL& site : personal_sites)
- personal_suggestions.push_back(MakeSuggestionFrom(site, true, false));
- MostVisitedSites::SuggestionsVector whitelist_suggestions;
+ personal_tiles.push_back(MakeTileFrom(site, true, false));
+ NTPTilesVector whitelist_tiles;
for (const TitleURL& site : whitelist_entry_points)
- whitelist_suggestions.push_back(MakeSuggestionFrom(site, false, true));
- MostVisitedSites::SuggestionsVector popular_suggestions;
+ whitelist_tiles.push_back(MakeTileFrom(site, false, true));
+ NTPTilesVector popular_tiles;
for (const TitleURL& site : popular_sites)
- popular_suggestions.push_back(MakeSuggestionFrom(site, false, false));
- MostVisitedSites::SuggestionsVector result_suggestions =
- MostVisitedSites::MergeSuggestions(std::move(personal_suggestions),
- std::move(whitelist_suggestions),
- std::move(popular_suggestions));
+ popular_tiles.push_back(MakeTileFrom(site, false, false));
+ NTPTilesVector result_tiles = MostVisitedSites::MergeTiles(
+ std::move(personal_tiles), std::move(whitelist_tiles),
+ std::move(popular_tiles));
std::vector<TitleURL> result_sites;
std::vector<bool> result_is_personal;
- result_sites.reserve(result_suggestions.size());
- result_is_personal.reserve(result_suggestions.size());
- for (const auto& suggestion : result_suggestions) {
- result_sites.push_back(TitleURL(suggestion.title, suggestion.url.spec()));
- result_is_personal.push_back(suggestion.source !=
- MostVisitedSites::POPULAR);
+ result_sites.reserve(result_tiles.size());
+ result_is_personal.reserve(result_tiles.size());
+ for (const auto& tile : result_tiles) {
+ result_sites.push_back(TitleURL(tile.title, tile.url.spec()));
+ result_is_personal.push_back(tile.source != NTPTileSource::POPULAR);
}
EXPECT_EQ(expected_sites_is_personal, result_is_personal);
EXPECT_EQ(expected_sites, result_sites);
}
- static MostVisitedSites::Suggestion MakeSuggestionFrom(
- const TitleURL& title_url,
- bool is_personal,
- bool whitelist) {
- MostVisitedSites::Suggestion suggestion;
- suggestion.title = title_url.title;
- suggestion.url = GURL(title_url.url);
- suggestion.source = whitelist ? MostVisitedSites::WHITELIST
- : (is_personal ? MostVisitedSites::TOP_SITES
- : MostVisitedSites::POPULAR);
- return suggestion;
+ static NTPTile MakeTileFrom(const TitleURL& title_url,
+ bool is_personal,
+ bool whitelist) {
+ NTPTile tile;
+ tile.title = title_url.title;
+ tile.url = GURL(title_url.url);
+ tile.source = whitelist ? NTPTileSource::WHITELIST
+ : (is_personal ? NTPTileSource::TOP_SITES
+ : NTPTileSource::POPULAR);
+ return tile;
}
};
@@ -96,8 +93,8 @@ TEST_F(MostVisitedSitesTest, PersonalSites) {
TitleURL("Site 3", "https://www.site3.com/"),
TitleURL("Site 4", "https://www.site4.com/"),
};
- // Without any popular suggestions, the result after merge should be the
- // personal suggestions.
+ // Without any popular tiles, the result after merge should be the personal
+ // tiles.
std::vector<bool> expected_sites_source(kNumSites, true /*personal source*/);
Check(std::vector<TitleURL>(), std::vector<TitleURL>(), personal_sites,
expected_sites_source, personal_sites);
@@ -110,8 +107,8 @@ TEST_F(MostVisitedSitesTest, PopularSites) {
TitleURL("Site 3", "https://www.site3.com/"),
TitleURL("Site 4", "https://www.site4.com/"),
};
- // Without any personal suggestions, the result after merge should be the
- // popular suggestions.
+ // Without any personal tiles, the result after merge should be the popular
+ // tiles.
std::vector<bool> expected_sites_source(kNumSites, false /*popular source*/);
Check(popular_sites, std::vector<TitleURL>(), std::vector<TitleURL>(),
expected_sites_source, popular_sites);
@@ -126,7 +123,7 @@ TEST_F(MostVisitedSitesTest, PersonalPrecedePopularSites) {
TitleURL("Site 3", "https://www.site3.com/"),
TitleURL("Site 4", "https://www.site4.com/"),
};
- // Personal suggestions should precede popular suggestions.
+ // Personal tiles should precede popular tiles.
std::vector<TitleURL> expected_sites{
TitleURL("Site 3", "https://www.site3.com/"),
TitleURL("Site 4", "https://www.site4.com/"),
diff --git a/chromium/components/ntp_tiles/ntp_tile.cc b/chromium/components/ntp_tiles/ntp_tile.cc
new file mode 100644
index 00000000000..ece28625aa4
--- /dev/null
+++ b/chromium/components/ntp_tiles/ntp_tile.cc
@@ -0,0 +1,15 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/ntp_tiles/ntp_tile.h"
+
+namespace ntp_tiles {
+
+NTPTile::NTPTile() : source(NTPTileSource::TOP_SITES) {}
+
+NTPTile::NTPTile(const NTPTile&) = default;
+
+NTPTile::~NTPTile() {}
+
+} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/ntp_tile.h b/chromium/components/ntp_tiles/ntp_tile.h
new file mode 100644
index 00000000000..ef228b54b38
--- /dev/null
+++ b/chromium/components/ntp_tiles/ntp_tile.h
@@ -0,0 +1,49 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NTP_TILES_NTP_TILE_H_
+#define COMPONENTS_NTP_TILES_NTP_TILE_H_
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "url/gurl.h"
+
+namespace ntp_tiles {
+
+// The source of an NTP tile.
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp
+enum class NTPTileSource {
+ // Tile comes from the personal top sites list, based on local history.
+ TOP_SITES,
+ // Tile comes from the suggestions service, based on synced history.
+ SUGGESTIONS_SERVICE,
+ // Tile is regionally popular.
+ POPULAR,
+ // Tile is on an custodian-managed whitelist.
+ WHITELIST
+};
+
+// A suggested site shown on the New Tab Page.
+struct NTPTile {
+ base::string16 title;
+ GURL url;
+ NTPTileSource source;
+
+ // Only valid for source == WHITELIST (empty otherwise).
+ base::FilePath whitelist_icon_path;
+
+ NTPTile();
+ NTPTile(const NTPTile&);
+ ~NTPTile();
+};
+
+using NTPTilesVector = std::vector<NTPTile>;
+
+} // namespace ntp_tiles
+
+#endif // COMPONENTS_NTP_TILES_NTP_TILE_H_
diff --git a/chromium/components/ntp_tiles/popular_sites.cc b/chromium/components/ntp_tiles/popular_sites.cc
index 88cccff2876..a24b7aa4eb3 100644
--- a/chromium/components/ntp_tiles/popular_sites.cc
+++ b/chromium/components/ntp_tiles/popular_sites.cc
@@ -19,13 +19,13 @@
#include "base/task_runner_util.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/google/core/browser/google_util.h"
#include "components/ntp_tiles/constants.h"
#include "components/ntp_tiles/pref_names.h"
#include "components/ntp_tiles/switches.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
-#include "components/safe_json/safe_json_parser.h"
#include "components/search_engines/search_engine_type.h"
#include "components/search_engines/template_url_service.h"
#include "components/variations/service/variations_service.h"
@@ -177,18 +177,27 @@ PopularSites::PopularSites(
VariationsService* variations_service,
net::URLRequestContextGetter* download_context,
const base::FilePath& directory,
- bool force_download,
- const FinishedCallback& callback)
- : callback_(callback),
- is_fallback_(false),
+ ParseJSONCallback parse_json)
+ : blocking_runner_(blocking_pool->GetTaskRunnerWithShutdownBehavior(
+ base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)),
+ prefs_(prefs),
+ template_url_service_(template_url_service),
+ variations_(variations_service),
+ download_context_(download_context),
local_path_(directory.empty()
? base::FilePath()
: directory.AppendASCII(kPopularSitesLocalFilename)),
- prefs_(prefs),
- download_context_(download_context),
- blocking_runner_(blocking_pool->GetTaskRunnerWithShutdownBehavior(
- base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)),
- weak_ptr_factory_(this) {
+ parse_json_(std::move(parse_json)),
+ is_fallback_(false),
+ weak_ptr_factory_(this) {}
+
+PopularSites::~PopularSites() {}
+
+void PopularSites::StartFetch(bool force_download,
+ const FinishedCallback& callback) {
+ DCHECK(!callback_);
+ callback_ = callback;
+
const base::Time last_download_time = base::Time::FromInternalValue(
prefs_->GetInt64(kPopularSitesLastDownloadPref));
const base::TimeDelta time_since_last_download =
@@ -198,11 +207,11 @@ PopularSites::PopularSites(
const bool download_time_is_future = base::Time::Now() < last_download_time;
const std::string country =
- GetCountryToUse(prefs, template_url_service, variations_service);
- const std::string version = GetVersionToUse(prefs);
+ GetCountryToUse(prefs_, template_url_service_, variations_);
+ const std::string version = GetVersionToUse(prefs_);
const GURL override_url =
- GURL(prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideURL));
+ GURL(prefs_->GetString(ntp_tiles::prefs::kPopularSitesOverrideURL));
pending_url_ = override_url.is_valid() ? override_url
: GetPopularSitesURL(country, version);
const bool url_changed =
@@ -231,8 +240,6 @@ PopularSites::PopularSites(
base::Passed(std::move(file_data))));
}
-PopularSites::~PopularSites() {}
-
GURL PopularSites::LastURL() const {
return GURL(prefs_->GetString(kPopularSitesURLPref));
}
@@ -272,6 +279,9 @@ void PopularSites::OnReadFileDone(std::unique_ptr<std::string> data,
void PopularSites::FetchPopularSites() {
fetcher_ = URLFetcher::Create(pending_url_, URLFetcher::GET, this);
+ // TODO(sfiera): Count the downloaded bytes of icons fetched by popular sites.
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ fetcher_.get(), data_use_measurement::DataUseUserData::NTP_TILES);
fetcher_->SetRequestContext(download_context_);
fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SAVE_COOKIES);
@@ -291,7 +301,7 @@ void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) {
return;
}
- safe_json::SafeJsonParser::Parse(
+ parse_json_.Run(
json_string,
base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr()),
base::Bind(&PopularSites::OnJsonParseFailed,
diff --git a/chromium/components/ntp_tiles/popular_sites.h b/chromium/components/ntp_tiles/popular_sites.h
index 36237a391ab..639aedf4046 100644
--- a/chromium/components/ntp_tiles/popular_sites.h
+++ b/chromium/components/ntp_tiles/popular_sites.h
@@ -38,9 +38,14 @@ class TemplateURLService;
namespace ntp_tiles {
+using ParseJSONCallback = base::Callback<void(
+ const std::string& unsafe_json,
+ const base::Callback<void(std::unique_ptr<base::Value>)>& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback)>;
+
// Downloads and provides a list of suggested popular sites, for display on
-// the NTP when there are not enough personalized suggestions. Caches the
-// downloaded file on disk to avoid re-downloading on every startup.
+// the NTP when there are not enough personalized tiles. Caches the downloaded
+// file on disk to avoid re-downloading on every startup.
class PopularSites : public net::URLFetcherDelegate {
public:
struct Site {
@@ -61,19 +66,24 @@ class PopularSites : public net::URLFetcherDelegate {
using FinishedCallback = base::Callback<void(bool /* success */)>;
- // When the suggestions have been fetched (from cache or URL) and parsed,
- // invokes |callback|, on the same thread as the caller.
- //
- // Set |force_download| to enforce re-downloading the suggestions file, even
- // if it already exists on disk.
PopularSites(const scoped_refptr<base::SequencedWorkerPool>& blocking_pool,
PrefService* prefs,
const TemplateURLService* template_url_service,
variations::VariationsService* variations_service,
net::URLRequestContextGetter* download_context,
const base::FilePath& directory,
- bool force_download,
- const FinishedCallback& callback);
+ ParseJSONCallback parse_json);
+
+ // Starts the process of retrieving popular sites. When they are available,
+ // invokes |callback| with the result, on the same thread as the caller. Never
+ // invokes |callback| before returning control to the caller, even if the
+ // result is immediately known.
+ //
+ // Set |force_download| to enforce re-downloading the popular sites file, even
+ // if it already exists on disk.
+ //
+ // Must be called at most once on a given PopularSites object.
+ void StartFetch(bool force_download, const FinishedCallback& callback);
~PopularSites() override;
@@ -104,19 +114,23 @@ class PopularSites : public net::URLFetcherDelegate {
void ParseSiteList(std::unique_ptr<base::Value> json);
void OnDownloadFailed();
+ // Parameters set from constructor.
+ scoped_refptr<base::TaskRunner> const blocking_runner_;
+ PrefService* const prefs_;
+ const TemplateURLService* const template_url_service_;
+ variations::VariationsService* const variations_;
+ net::URLRequestContextGetter* const download_context_;
+ base::FilePath const local_path_;
+ ParseJSONCallback parse_json_;
+
+ // Set by StartFetch() and called after fetch completes.
FinishedCallback callback_;
+
std::unique_ptr<net::URLFetcher> fetcher_;
bool is_fallback_;
std::vector<Site> sites_;
GURL pending_url_;
- base::FilePath local_path_;
-
- PrefService* prefs_;
- net::URLRequestContextGetter* download_context_;
-
- scoped_refptr<base::TaskRunner> blocking_runner_;
-
base::WeakPtrFactory<PopularSites> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PopularSites);
diff --git a/chromium/components/ntp_tiles/pref_names.cc b/chromium/components/ntp_tiles/pref_names.cc
index dd72edbf8f6..1ec52196efa 100644
--- a/chromium/components/ntp_tiles/pref_names.cc
+++ b/chromium/components/ntp_tiles/pref_names.cc
@@ -7,12 +7,12 @@
namespace ntp_tiles {
namespace prefs {
-// Ordered list of website suggestions shown on the new tab page that will allow
-// retaining the order even if the suggestions change over time.
-const char kNTPSuggestionsURL[] = "ntp.suggestions_url";
+const char kDeprecatedNTPTilesURL[] = "ntp.suggestions_url";
+const char kDeprecatedNTPTilesIsPersonal[] = "ntp.suggestions_is_personal";
-// Whether the suggestion was derived from personal data.
-const char kNTPSuggestionsIsPersonal[] = "ntp.suggestions_is_personal";
+// The number of personal tiles we had previously. Used to figure out
+// whether we need popular sites.
+const char kNumPersonalTiles[] = "ntp.num_personal_suggestions";
// If set, overrides the URL for popular sites, including the individual
// overrides for country and version below.
diff --git a/chromium/components/ntp_tiles/pref_names.h b/chromium/components/ntp_tiles/pref_names.h
index d1ca404f734..243a5fa1e4b 100644
--- a/chromium/components/ntp_tiles/pref_names.h
+++ b/chromium/components/ntp_tiles/pref_names.h
@@ -8,8 +8,11 @@
namespace ntp_tiles {
namespace prefs {
-extern const char kNTPSuggestionsURL[];
-extern const char kNTPSuggestionsIsPersonal[];
+// TODO(treib): Remove after M55.
+extern const char kDeprecatedNTPTilesURL[];
+extern const char kDeprecatedNTPTilesIsPersonal[];
+
+extern const char kNumPersonalTiles[];
extern const char kPopularSitesOverrideURL[];
extern const char kPopularSitesOverrideCountry[];
diff --git a/chromium/components/offline_pages.gypi b/chromium/components/offline_pages.gypi
deleted file mode 100644
index 523d4fd83c3..00000000000
--- a/chromium/components/offline_pages.gypi
+++ /dev/null
@@ -1,126 +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.
-
-{
- 'targets': [
- {
- # GN: //components/offline_pages:offline_pages
- 'target_name': 'offline_pages',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- '../sql/sql.gyp:sql',
- 'keyed_service_core',
- ],
- 'sources': [
- 'offline_pages/archive_manager.cc',
- 'offline_pages/archive_manager.h',
- 'offline_pages/client_namespace_constants.cc',
- 'offline_pages/client_namespace_constants.h',
- 'offline_pages/client_policy_controller.cc',
- 'offline_pages/client_policy_controller.h',
- 'offline_pages/offline_event_logger.cc',
- 'offline_pages/offline_event_logger.h',
- 'offline_pages/offline_page_archiver.h',
- 'offline_pages/offline_page_client_policy.h',
- 'offline_pages/offline_page_feature.cc',
- 'offline_pages/offline_page_feature.h',
- 'offline_pages/offline_page_item.cc',
- 'offline_pages/offline_page_item.h',
- 'offline_pages/offline_page_metadata_store.cc',
- 'offline_pages/offline_page_metadata_store.h',
- 'offline_pages/offline_page_metadata_store_sql.cc',
- 'offline_pages/offline_page_metadata_store_sql.h',
- 'offline_pages/offline_page_model.cc',
- 'offline_pages/offline_page_model.h',
- 'offline_pages/offline_page_model_event_logger.cc',
- 'offline_pages/offline_page_model_event_logger.h',
- 'offline_pages/offline_page_model_impl.cc',
- 'offline_pages/offline_page_model_impl.h',
- 'offline_pages/offline_page_storage_manager.cc',
- 'offline_pages/offline_page_storage_manager.h',
- 'offline_pages/offline_page_types.h',
- 'offline_pages/snapshot_controller.cc',
- 'offline_pages/snapshot_controller.h',
- ],
- },
- {
- # GN: //components/offline_pages/background:background_offliner
- 'target_name': 'offline_pages_background_offliner',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- '../..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../sql/sql.gyp:sql',
- '../url/url.gyp:url_lib',
- 'keyed_service_core',
- ],
- 'sources': [
- 'offline_pages/background/device_conditions.h',
- 'offline_pages/background/offliner.h',
- 'offline_pages/background/offliner_factory.h',
- 'offline_pages/background/offliner_policy.h',
- 'offline_pages/background/request_coordinator.cc',
- 'offline_pages/background/request_coordinator.h',
- 'offline_pages/background/request_coordinator_event_logger.cc',
- 'offline_pages/background/request_coordinator_event_logger.h',
- 'offline_pages/background/request_picker.cc',
- 'offline_pages/background/request_picker.h',
- 'offline_pages/background/request_queue.cc',
- 'offline_pages/background/request_queue.h',
- 'offline_pages/background/request_queue_in_memory_store.cc',
- 'offline_pages/background/request_queue_in_memory_store.h',
- 'offline_pages/background/request_queue_store.h',
- 'offline_pages/background/request_queue_store_sql.cc',
- 'offline_pages/background/request_queue_store_sql.h',
- 'offline_pages/background/save_page_request.cc',
- 'offline_pages/background/save_page_request.h',
- 'offline_pages/background/scheduler.h',
- ],
- },
- {
- # GN version: //components/offline_pages:test_support
- 'target_name': 'offline_pages_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../testing/gtest.gyp:gtest',
- '../url/url.gyp:url_lib',
- 'offline_pages',
- ],
- 'sources': [
- 'offline_pages/offline_page_test_archiver.cc',
- 'offline_pages/offline_page_test_archiver.h',
- 'offline_pages/offline_page_test_store.cc',
- 'offline_pages/offline_page_test_store.h',
- 'offline_pages/stub_offline_page_model.cc',
- 'offline_pages/stub_offline_page_model.h',
- ],
- },
- ],
- 'conditions': [
- ['OS == "android"', {
- 'targets': [
- {
- # GN: //components/offline_pages:offline_page_model_enums_java
- 'target_name': 'offline_page_model_enums_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'offline_pages/offline_page_types.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/offline_pages/BUILD.gn b/chromium/components/offline_pages/BUILD.gn
index 4730d5376e6..c1bf7929616 100644
--- a/chromium/components/offline_pages/BUILD.gn
+++ b/chromium/components/offline_pages/BUILD.gn
@@ -6,7 +6,6 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-# GYP: //components/offline_pages.gypi:offline_pages
static_library("offline_pages") {
sources = [
"archive_manager.cc",
@@ -34,6 +33,7 @@ static_library("offline_pages") {
"offline_page_storage_manager.cc",
"offline_page_storage_manager.h",
"offline_page_types.h",
+ "offline_store_types.h",
"snapshot_controller.cc",
"snapshot_controller.h",
]
@@ -41,7 +41,6 @@ static_library("offline_pages") {
deps = [
":switches",
"//base",
- "//components/bookmarks/browser",
"//components/keyed_service/core",
"//net",
"//sql:sql",
@@ -64,12 +63,13 @@ static_library("test_support") {
":offline_pages",
":switches",
"//base",
+ "//components/keyed_service/core",
"//testing/gtest",
"//url",
]
}
-source_set("switches") {
+static_library("switches") {
sources = [
"offline_page_feature.cc",
"offline_page_feature.h",
@@ -108,7 +108,10 @@ source_set("unit_tests") {
if (is_android) {
java_cpp_enum("offline_page_model_enums_java") {
sources = [
+ "background/request_queue.h",
+ "background/save_page_request.h",
"offline_page_types.h",
+ "offline_store_types.h",
]
}
}
diff --git a/chromium/components/offline_pages/archive_manager_unittest.cc b/chromium/components/offline_pages/archive_manager_unittest.cc
index 5b5e59efd67..bc50b4f4175 100644
--- a/chromium/components/offline_pages/archive_manager_unittest.cc
+++ b/chromium/components/offline_pages/archive_manager_unittest.cc
@@ -45,7 +45,7 @@ class ArchiveManagerTest : public testing::Test {
const ArchiveManager::StorageStats& storage_sizes);
ArchiveManager* manager() { return manager_.get(); }
- const base::FilePath& temp_path() const { return temp_dir_.path(); }
+ const base::FilePath& temp_path() const { return temp_dir_.GetPath(); }
CallbackStatus callback_status() const { return callback_status_; }
const std::set<base::FilePath>& last_archive_paths() const {
return last_archvie_paths_;
@@ -73,7 +73,7 @@ ArchiveManagerTest::ArchiveManagerTest()
void ArchiveManagerTest::SetUp() {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- ResetManager(temp_dir_.path());
+ ResetManager(temp_dir_.GetPath());
}
void ArchiveManagerTest::PumpLoop() {
diff --git a/chromium/components/offline_pages/background/BUILD.gn b/chromium/components/offline_pages/background/BUILD.gn
index 338bcef4050..4e41c857340 100644
--- a/chromium/components/offline_pages/background/BUILD.gn
+++ b/chromium/components/offline_pages/background/BUILD.gn
@@ -6,13 +6,16 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-# GYP: //components/offline_pages/offline_pages.gypi:background_offliner
static_library("background_offliner") {
sources = [
+ "change_requests_state_task.cc",
+ "change_requests_state_task.h",
"device_conditions.h",
"offliner.h",
"offliner_factory.h",
"offliner_policy.h",
+ "remove_requests_task.cc",
+ "remove_requests_task.h",
"request_coordinator.cc",
"request_coordinator.h",
"request_coordinator_event_logger.cc",
@@ -35,6 +38,7 @@ static_library("background_offliner") {
"//base",
"//components/keyed_service/core",
"//components/offline_pages:offline_pages",
+ "//components/offline_pages/core",
"//net",
"//sql:sql",
"//url",
@@ -44,6 +48,8 @@ static_library("background_offliner") {
source_set("unit_tests") {
testonly = true
sources = [
+ "change_requests_state_task_unittest.cc",
+ "remove_requests_task_unittest.cc",
"request_coordinator_event_logger_unittest.cc",
"request_coordinator_unittest.cc",
"request_picker_unittest.cc",
diff --git a/chromium/components/offline_pages/background/change_requests_state_task.cc b/chromium/components/offline_pages/background/change_requests_state_task.cc
new file mode 100644
index 00000000000..f78665aa82d
--- /dev/null
+++ b/chromium/components/offline_pages/background/change_requests_state_task.cc
@@ -0,0 +1,90 @@
+// 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 "components/offline_pages/background/change_requests_state_task.h"
+
+#include "base/bind.h"
+
+namespace offline_pages {
+
+ChangeRequestsStateTask::ChangeRequestsStateTask(
+ RequestQueueStore* store,
+ const std::vector<int64_t>& request_ids,
+ const SavePageRequest::RequestState new_state,
+ const RequestQueueStore::UpdateCallback& callback)
+ : store_(store),
+ request_ids_(request_ids.begin(), request_ids.end()),
+ new_state_(new_state),
+ callback_(callback),
+ weak_ptr_factory_(this) {}
+
+ChangeRequestsStateTask::~ChangeRequestsStateTask() {}
+
+void ChangeRequestsStateTask::Run() {
+ ReadRequests();
+}
+
+void ChangeRequestsStateTask::ReadRequests() {
+ if (request_ids_.empty()) {
+ CompleteEarly(ItemActionStatus::NOT_FOUND);
+ return;
+ }
+
+ store_->GetRequests(base::Bind(&ChangeRequestsStateTask::SelectItemsToUpdate,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ChangeRequestsStateTask::SelectItemsToUpdate(
+ bool success,
+ std::vector<std::unique_ptr<SavePageRequest>> requests) {
+ if (!success) {
+ CompleteEarly(ItemActionStatus::STORE_ERROR);
+ return;
+ }
+
+ std::vector<SavePageRequest> items_to_update;
+ for (const auto& request : requests) {
+ // If this request is in our list, update it.
+ if (request_ids_.count(request->request_id()) > 0) {
+ request->set_request_state(new_state_);
+ items_to_update.push_back(*request);
+ // Items that are missing before the update will be marked as not found
+ // before the callback.
+ request_ids_.erase(request->request_id());
+ }
+ }
+
+ if (items_to_update.empty()) {
+ CompleteEarly(ItemActionStatus::NOT_FOUND);
+ return;
+ }
+
+ store_->UpdateRequests(items_to_update,
+ base::Bind(&ChangeRequestsStateTask::UpdateCompleted,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ChangeRequestsStateTask::UpdateCompleted(
+ std::unique_ptr<UpdateRequestsResult> update_result) {
+ CompleteWithStatus(std::move(update_result), ItemActionStatus::NOT_FOUND);
+}
+
+void ChangeRequestsStateTask::CompleteEarly(ItemActionStatus status) {
+ // TODO(fgorski): store_->state() once implemented
+ std::unique_ptr<UpdateRequestsResult> result(
+ new UpdateRequestsResult(StoreState::LOADED));
+ CompleteWithStatus(std::move(result), status);
+}
+
+void ChangeRequestsStateTask::CompleteWithStatus(
+ std::unique_ptr<UpdateRequestsResult> result,
+ ItemActionStatus status) {
+ // Mark items as not found, if they are still in the request IDs set.
+ for (int64_t request_id : request_ids_)
+ result->item_statuses.push_back(std::make_pair(request_id, status));
+ callback_.Run(std::move(result));
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/change_requests_state_task.h b/chromium/components/offline_pages/background/change_requests_state_task.h
new file mode 100644
index 00000000000..2213c687948
--- /dev/null
+++ b/chromium/components/offline_pages/background/change_requests_state_task.h
@@ -0,0 +1,63 @@
+// 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 COMPONENTS_OFFLINE_PAGES_BACKGROUND_CHANGE_REQUESTS_STATE_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_CHANGE_REQUESTS_STATE_TASK_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <unordered_set>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/background/request_queue_store.h"
+#include "components/offline_pages/background/save_page_request.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+
+class ChangeRequestsStateTask : public Task {
+ public:
+ ChangeRequestsStateTask(RequestQueueStore* store,
+ const std::vector<int64_t>& request_ids,
+ const SavePageRequest::RequestState new_state,
+ const RequestQueueStore::UpdateCallback& callback);
+ ~ChangeRequestsStateTask() override;
+
+ // TaskQueue::Task implementation.
+ void Run() override;
+
+ private:
+ // Step 1. Reading the requests.
+ void ReadRequests();
+ // Step 2. Selecting requests to be updated. Calls update.
+ void SelectItemsToUpdate(
+ bool success,
+ std::vector<std::unique_ptr<SavePageRequest>> requests);
+ // Step 3. Processes update result, calls callback.
+ void UpdateCompleted(std::unique_ptr<UpdateRequestsResult> update_result);
+
+ // Completions.
+ void CompleteEarly(ItemActionStatus status);
+ void CompleteWithStatus(std::unique_ptr<UpdateRequestsResult> result,
+ ItemActionStatus status);
+
+ // Store that this task updates.
+ RequestQueueStore* store_;
+ // Request IDs to be updated.
+ std::unordered_set<int64_t> request_ids_;
+ // New state to be set on all entries.
+ SavePageRequest::RequestState new_state_;
+ // Callback to complete the task.
+ RequestQueueStore::UpdateCallback callback_;
+
+ base::WeakPtrFactory<ChangeRequestsStateTask> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChangeRequestsStateTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_BACKGROUND_CHANGE_REQUESTS_STATE_TASK_H_
diff --git a/chromium/components/offline_pages/background/change_requests_state_task_unittest.cc b/chromium/components/offline_pages/background/change_requests_state_task_unittest.cc
new file mode 100644
index 00000000000..c878655ef3c
--- /dev/null
+++ b/chromium/components/offline_pages/background/change_requests_state_task_unittest.cc
@@ -0,0 +1,183 @@
+// 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 "components/offline_pages/background/change_requests_state_task.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/background/request_queue_in_memory_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+namespace {
+const int64_t kRequestId1 = 42;
+const int64_t kRequestId2 = 43;
+const int64_t kRequestId3 = 44;
+const GURL kUrl1("http://example.com");
+const GURL kUrl2("http://another-example.com");
+const ClientId kClientId1("bookmark", "1234");
+const ClientId kClientId2("async", "5678");
+} // namespace
+
+class ChangeRequestsStateTaskTest : public testing::Test {
+ public:
+ ChangeRequestsStateTaskTest();
+ ~ChangeRequestsStateTaskTest() override;
+
+ void PumpLoop();
+
+ void SetUpStore(RequestQueueStore* store);
+
+ void AddRequestDone(ItemActionStatus status);
+
+ void ChangeRequestsStateCallback(
+ std::unique_ptr<UpdateRequestsResult> result);
+
+ UpdateRequestsResult* last_result() const { return result_.get(); }
+
+ private:
+ std::unique_ptr<UpdateRequestsResult> result_;
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle task_runner_handle_;
+};
+
+ChangeRequestsStateTaskTest::ChangeRequestsStateTaskTest()
+ : task_runner_(new base::TestSimpleTaskRunner),
+ task_runner_handle_(task_runner_) {}
+
+ChangeRequestsStateTaskTest::~ChangeRequestsStateTaskTest() {}
+
+void ChangeRequestsStateTaskTest::PumpLoop() {
+ task_runner_->RunUntilIdle();
+}
+
+void ChangeRequestsStateTaskTest::SetUpStore(RequestQueueStore* store) {
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time,
+ true);
+ store->AddRequest(request_1,
+ base::Bind(&ChangeRequestsStateTaskTest::AddRequestDone,
+ base::Unretained(this)));
+ SavePageRequest request_2(kRequestId2, kUrl2, kClientId2, creation_time,
+ true);
+ store->AddRequest(request_2,
+ base::Bind(&ChangeRequestsStateTaskTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+}
+
+void ChangeRequestsStateTaskTest::AddRequestDone(ItemActionStatus status) {
+ ASSERT_EQ(ItemActionStatus::SUCCESS, status);
+}
+
+void ChangeRequestsStateTaskTest::ChangeRequestsStateCallback(
+ std::unique_ptr<UpdateRequestsResult> result) {
+ result_ = std::move(result);
+}
+
+TEST_F(ChangeRequestsStateTaskTest, UpdateWhenStoreEmpty) {
+ RequestQueueInMemoryStore store;
+ std::vector<int64_t> request_ids{kRequestId1};
+ ChangeRequestsStateTask task(
+ &store, request_ids, SavePageRequest::RequestState::PAUSED,
+ base::Bind(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
+ task.Run();
+ PumpLoop();
+ ASSERT_TRUE(last_result());
+ EXPECT_EQ(1UL, last_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId1, last_result()->item_statuses.at(0).first);
+ EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+ last_result()->item_statuses.at(0).second);
+ EXPECT_EQ(0UL, last_result()->updated_items.size());
+}
+
+TEST_F(ChangeRequestsStateTaskTest, UpdateSingleItem) {
+ RequestQueueInMemoryStore store;
+ SetUpStore(&store);
+ std::vector<int64_t> request_ids{kRequestId1};
+ ChangeRequestsStateTask task(
+ &store, request_ids, SavePageRequest::RequestState::PAUSED,
+ base::Bind(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
+ task.Run();
+ PumpLoop();
+ ASSERT_TRUE(last_result());
+ EXPECT_EQ(1UL, last_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId1, last_result()->item_statuses.at(0).first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_result()->item_statuses.at(0).second);
+ EXPECT_EQ(1UL, last_result()->updated_items.size());
+ EXPECT_EQ(SavePageRequest::RequestState::PAUSED,
+ last_result()->updated_items.at(0).request_state());
+}
+
+TEST_F(ChangeRequestsStateTaskTest, UpdateMultipleItems) {
+ RequestQueueInMemoryStore store;
+ SetUpStore(&store);
+ std::vector<int64_t> request_ids{kRequestId1, kRequestId2};
+ ChangeRequestsStateTask task(
+ &store, request_ids, SavePageRequest::RequestState::PAUSED,
+ base::Bind(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
+ task.Run();
+ PumpLoop();
+ ASSERT_TRUE(last_result());
+ EXPECT_EQ(2UL, last_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId1, last_result()->item_statuses.at(0).first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_result()->item_statuses.at(0).second);
+ EXPECT_EQ(kRequestId2, last_result()->item_statuses.at(1).first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_result()->item_statuses.at(1).second);
+ EXPECT_EQ(2UL, last_result()->updated_items.size());
+ EXPECT_EQ(kRequestId1, last_result()->updated_items.at(0).request_id());
+ EXPECT_EQ(SavePageRequest::RequestState::PAUSED,
+ last_result()->updated_items.at(0).request_state());
+ EXPECT_EQ(kRequestId2, last_result()->updated_items.at(1).request_id());
+ EXPECT_EQ(SavePageRequest::RequestState::PAUSED,
+ last_result()->updated_items.at(1).request_state());
+}
+
+TEST_F(ChangeRequestsStateTaskTest, EmptyRequestsList) {
+ RequestQueueInMemoryStore store;
+ std::vector<int64_t> request_ids;
+ ChangeRequestsStateTask task(
+ &store, request_ids, SavePageRequest::RequestState::PAUSED,
+ base::Bind(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
+ task.Run();
+ PumpLoop();
+ ASSERT_TRUE(last_result());
+ EXPECT_EQ(0UL, last_result()->item_statuses.size());
+ EXPECT_EQ(0UL, last_result()->updated_items.size());
+}
+
+TEST_F(ChangeRequestsStateTaskTest, UpdateMissingItem) {
+ RequestQueueInMemoryStore store;
+ SetUpStore(&store);
+ std::vector<int64_t> request_ids{kRequestId1, kRequestId3};
+ ChangeRequestsStateTask task(
+ &store, request_ids, SavePageRequest::RequestState::PAUSED,
+ base::Bind(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
+ task.Run();
+ PumpLoop();
+ ASSERT_TRUE(last_result());
+ EXPECT_EQ(2UL, last_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId1, last_result()->item_statuses.at(0).first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_result()->item_statuses.at(0).second);
+ EXPECT_EQ(kRequestId3, last_result()->item_statuses.at(1).first);
+ EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+ last_result()->item_statuses.at(1).second);
+ EXPECT_EQ(1UL, last_result()->updated_items.size());
+ EXPECT_EQ(SavePageRequest::RequestState::PAUSED,
+ last_result()->updated_items.at(0).request_state());
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/device_conditions.h b/chromium/components/offline_pages/background/device_conditions.h
index e26c7d1289b..b96306a4d4b 100644
--- a/chromium/components/offline_pages/background/device_conditions.h
+++ b/chromium/components/offline_pages/background/device_conditions.h
@@ -20,6 +20,10 @@ class DeviceConditions {
battery_percentage_(battery_percentage),
net_connection_type_(net_connection_type) {}
+ DeviceConditions()
+ : power_connected_(true), battery_percentage_(75),
+ net_connection_type_(net::NetworkChangeNotifier::CONNECTION_WIFI) {}
+
// Returns whether power is connected.
bool IsPowerConnected() const { return power_connected_; }
@@ -35,6 +39,8 @@ class DeviceConditions {
const bool power_connected_;
const int battery_percentage_;
const net::NetworkChangeNotifier::ConnectionType net_connection_type_;
+
+ // NOTE: We intentionally allow the default copy constructor and assignment.
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/offliner.h b/chromium/components/offline_pages/background/offliner.h
index 745fc6181b6..cafd068634d 100644
--- a/chromium/components/offline_pages/background/offliner.h
+++ b/chromium/components/offline_pages/background/offliner.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_OFFLINER_H_
#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_OFFLINER_H_
+#include <string>
+
#include "base/callback.h"
namespace offline_pages {
@@ -16,14 +18,34 @@ class SavePageRequest;
class Offliner {
public:
// Status of processing an offline page request.
- enum class RequestStatus {
- UNKNOWN, // No status determined/reported yet.
- LOADED, // Page loaded but not (yet) saved.
- SAVED, // Offline page snapshot saved.
- CANCELED, // Request was canceled.
- FAILED, // Failed to load page.
- FAILED_SAVE, // Failed to save loaded page.
- // TODO(dougarnett): Define a retry-able failure status.
+ // WARNING: You must update histograms.xml to match any changes made to
+ // this enum (ie, OfflinePagesBackgroundOfflinerRequestStatus histogram enum).
+ // Also update related switch code in RequestCoordinatorEventLogger.
+ enum RequestStatus {
+ // No status determined/reported yet. Interim status, not sent in callback.
+ UNKNOWN = 0,
+ // Page loaded but not (yet) saved. Interim status, not sent in callback.
+ LOADED = 1,
+ // Offline page snapshot saved.
+ SAVED = 2,
+ // RequestCoordinator canceled request.
+ REQUEST_COORDINATOR_CANCELED = 3,
+ // Prerendering was canceled.
+ PRERENDERING_CANCELED = 4,
+ // Prerendering failed to load page.
+ PRERENDERING_FAILED = 5,
+ // Failed to save loaded page.
+ SAVE_FAILED = 6,
+ // Foreground transition canceled request.
+ FOREGROUND_CANCELED = 7,
+ // RequestCoordinator canceled request attempt per time limit.
+ REQUEST_COORDINATOR_TIMED_OUT = 8,
+ // The loader did not accept/start the request.
+ PRERENDERING_NOT_STARTED = 9,
+ // Prerendering failed with hard error so should not retry the request.
+ PRERENDERING_FAILED_NO_RETRY = 10,
+ // NOTE: insert new values above this line and update histogram enum too.
+ STATUS_COUNT
};
// Reports the completion status of a request.
@@ -41,7 +63,8 @@ class Offliner {
const SavePageRequest& request,
const CompletionCallback& callback) = 0;
- // Clears the currently processing request, if any.
+ // Clears the currently processing request, if any, and skips running its
+ // CompletionCallback.
virtual void Cancel() = 0;
// TODO(dougarnett): add policy support methods.
diff --git a/chromium/components/offline_pages/background/offliner_policy.h b/chromium/components/offline_pages/background/offliner_policy.h
index 04e7f8443d1..83abd4a4e05 100644
--- a/chromium/components/offline_pages/background/offliner_policy.h
+++ b/chromium/components/offline_pages/background/offliner_policy.h
@@ -5,16 +5,103 @@
#ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_OFFLINER_POLICY_H_
#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_OFFLINER_POLICY_H_
+namespace {
+const int kMaxStartedTries = 4;
+const int kMaxCompletedTries = 1;
+const int kBackgroundProcessingTimeBudgetSeconds = 170;
+const int kSinglePageTimeLimitSeconds = 120;
+const int kRequestExpirationTimeInSeconds = 60 * 60 * 24 * 7;
+} // namespace
+
namespace offline_pages {
// Policy for the Background Offlining system. Some policy will belong to the
// RequestCoordinator, some to the RequestQueue, and some to the Offliner.
class OfflinerPolicy {
public:
- OfflinerPolicy(){};
+ OfflinerPolicy()
+ : prefer_untried_requests_(false),
+ prefer_earlier_requests_(true),
+ retry_count_is_more_important_than_recency_(false),
+ max_started_tries_(kMaxStartedTries),
+ max_completed_tries_(kMaxCompletedTries) {}
+
+ // Constructor for unit tests.
+ OfflinerPolicy(bool prefer_untried,
+ bool prefer_earlier,
+ bool prefer_retry_count,
+ int max_started_tries,
+ int max_completed_tries)
+ : prefer_untried_requests_(prefer_untried),
+ prefer_earlier_requests_(prefer_earlier),
+ retry_count_is_more_important_than_recency_(prefer_retry_count),
+ max_started_tries_(max_started_tries),
+ max_completed_tries_(max_completed_tries) {}
+
+ // TODO(petewil): Numbers here are chosen arbitrarily, do the proper studies
+ // to get good policy numbers. Eventually this should get data from a finch
+ // experiment.
+
+ // Returns true if we should prefer retrying lesser tried requests.
+ bool ShouldPreferUntriedRequests() const { return prefer_untried_requests_; }
+
+ // Returns true if we should prefer older requests of equal number of tries.
+ bool ShouldPreferEarlierRequests() const { return prefer_earlier_requests_; }
+
+ // Returns true if retry count is considered more important than recency in
+ // picking which request to try next.
+ bool RetryCountIsMoreImportantThanRecency() const {
+ return retry_count_is_more_important_than_recency_;
+ }
+
+ // The max number of times we will start a request. Not all started attempts
+ // will complete. This may be caused by prerenderer issues or chromium being
+ // swapped out of memory.
+ int GetMaxStartedTries() const { return max_started_tries_; }
+
+ // The max number of times we will retry a request when the attempt
+ // completed, but failed.
+ int GetMaxCompletedTries() const { return max_completed_tries_; }
+
+ bool PowerRequired(bool user_requested) const {
+ return (!user_requested);
+ }
+
+ bool UnmeteredNetworkRequired(bool user_requested) const {
+ return !(user_requested);
+ }
+
+ int BatteryPercentageRequired(bool user_requested) const {
+ if (user_requested)
+ return 0;
+ // This is so low because we require the device to be plugged in and
+ // charging. If we decide to allow non-user requested pages when not
+ // plugged in, we should raise this somewhat higher.
+ return 25;
+ }
+
+ // How many seconds to keep trying new pages for, before we give up, and
+ // return to the scheduler.
+ int GetBackgroundProcessingTimeBudgetSeconds() const {
+ return kBackgroundProcessingTimeBudgetSeconds;
+ }
+
+ // How long do we allow a page to load before giving up on it
+ int GetSinglePageTimeLimitInSeconds() const {
+ return kSinglePageTimeLimitSeconds;
+ }
+
+ // How long we allow requests to remain in the system before giving up.
+ int GetRequestExpirationTimeInSeconds() const {
+ return kRequestExpirationTimeInSeconds;
+ }
- // TODO(petewil): Implement and add a .cc file.
- // Eventually this should get data from a finch experiment.
+ private:
+ bool prefer_untried_requests_;
+ bool prefer_earlier_requests_;
+ bool retry_count_is_more_important_than_recency_;
+ int max_started_tries_;
+ int max_completed_tries_;
};
}
diff --git a/chromium/components/offline_pages/background/remove_requests_task.cc b/chromium/components/offline_pages/background/remove_requests_task.cc
new file mode 100644
index 00000000000..15d45fe6acf
--- /dev/null
+++ b/chromium/components/offline_pages/background/remove_requests_task.cc
@@ -0,0 +1,52 @@
+// 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 "components/offline_pages/background/remove_requests_task.h"
+
+#include "base/bind.h"
+
+namespace offline_pages {
+
+RemoveRequestsTask::RemoveRequestsTask(
+ RequestQueueStore* store,
+ const std::vector<int64_t>& request_ids,
+ const RequestQueueStore::UpdateCallback& callback)
+ : store_(store),
+ request_ids_(request_ids),
+ callback_(callback),
+ weak_ptr_factory_(this) {}
+
+RemoveRequestsTask::~RemoveRequestsTask() {}
+
+void RemoveRequestsTask::Run() {
+ RemoveRequests();
+}
+
+void RemoveRequestsTask::RemoveRequests() {
+ if (request_ids_.empty()) {
+ CompleteEarly(ItemActionStatus::NOT_FOUND);
+ return;
+ }
+
+ store_->RemoveRequests(request_ids_,
+ base::Bind(&RemoveRequestsTask::CompleteWithResult,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void RemoveRequestsTask::CompleteEarly(ItemActionStatus status) {
+ // TODO(fgorski): store_->state() once implemented
+ std::unique_ptr<UpdateRequestsResult> result(
+ new UpdateRequestsResult(StoreState::LOADED));
+ for (int64_t request_id : request_ids_)
+ result->item_statuses.push_back(std::make_pair(request_id, status));
+ CompleteWithResult(std::move(result));
+}
+
+void RemoveRequestsTask::CompleteWithResult(
+ std::unique_ptr<UpdateRequestsResult> result) {
+ callback_.Run(std::move(result));
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/remove_requests_task.h b/chromium/components/offline_pages/background/remove_requests_task.h
new file mode 100644
index 00000000000..a110134e7ea
--- /dev/null
+++ b/chromium/components/offline_pages/background/remove_requests_task.h
@@ -0,0 +1,53 @@
+// 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 COMPONENTS_OFFLINE_PAGES_BACKGROUND_REMOVE_REQUESTS_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_REMOVE_REQUESTS_TASK_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/background/request_queue_store.h"
+#include "components/offline_pages/background/save_page_request.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+
+class RemoveRequestsTask : public Task {
+ public:
+ RemoveRequestsTask(RequestQueueStore* store,
+ const std::vector<int64_t>& request_ids,
+ const RequestQueueStore::UpdateCallback& callback);
+ ~RemoveRequestsTask() override;
+
+ // TaskQueue::Task implementation.
+ void Run() override;
+
+ private:
+ // Step 1. Removes requests from the store.
+ void RemoveRequests();
+ // Step for early termination, that builds failure result.
+ void CompleteEarly(ItemActionStatus status);
+ // Step 2. Processes update result, calls callback.
+ void CompleteWithResult(std::unique_ptr<UpdateRequestsResult> result);
+
+ // Store that this task updates.
+ RequestQueueStore* store_;
+ // Request IDs to be updated.
+ // TODO(fgorski): perhaps convert to unique_ptr to a vector.
+ std::vector<int64_t> request_ids_;
+ // Callback to complete the task.
+ RequestQueueStore::UpdateCallback callback_;
+
+ base::WeakPtrFactory<RemoveRequestsTask> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoveRequestsTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_BACKGROUND_REMOVE_REQUESTS_TASK_H_
diff --git a/chromium/components/offline_pages/background/remove_requests_task_unittest.cc b/chromium/components/offline_pages/background/remove_requests_task_unittest.cc
new file mode 100644
index 00000000000..f83ed8ac89a
--- /dev/null
+++ b/chromium/components/offline_pages/background/remove_requests_task_unittest.cc
@@ -0,0 +1,176 @@
+// 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 "components/offline_pages/background/remove_requests_task.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/background/request_queue_in_memory_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+namespace {
+const int64_t kRequestId1 = 42;
+const int64_t kRequestId2 = 43;
+const int64_t kRequestId3 = 44;
+const GURL kUrl1("http://example.com");
+const GURL kUrl2("http://another-example.com");
+const ClientId kClientId1("bookmark", "1234");
+const ClientId kClientId2("async", "5678");
+} // namespace
+
+class RemoveRequestsTaskTest : public testing::Test {
+ public:
+ RemoveRequestsTaskTest();
+ ~RemoveRequestsTaskTest() override;
+
+ void PumpLoop();
+
+ void AddRequestsToStore(RequestQueueStore* store);
+
+ void AddRequestDone(ItemActionStatus status);
+
+ void RemoveRequestsCallback(std::unique_ptr<UpdateRequestsResult> result);
+
+ UpdateRequestsResult* last_result() const { return result_.get(); }
+
+ private:
+ std::unique_ptr<UpdateRequestsResult> result_;
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle task_runner_handle_;
+};
+
+RemoveRequestsTaskTest::RemoveRequestsTaskTest()
+ : task_runner_(new base::TestSimpleTaskRunner),
+ task_runner_handle_(task_runner_) {}
+
+RemoveRequestsTaskTest::~RemoveRequestsTaskTest() {}
+
+void RemoveRequestsTaskTest::PumpLoop() {
+ task_runner_->RunUntilIdle();
+}
+
+void RemoveRequestsTaskTest::AddRequestsToStore(RequestQueueStore* store) {
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time,
+ true);
+ store->AddRequest(request_1,
+ base::Bind(&RemoveRequestsTaskTest::AddRequestDone,
+ base::Unretained(this)));
+ SavePageRequest request_2(kRequestId2, kUrl2, kClientId2, creation_time,
+ true);
+ store->AddRequest(request_2,
+ base::Bind(&RemoveRequestsTaskTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+}
+
+void RemoveRequestsTaskTest::AddRequestDone(ItemActionStatus status) {
+ ASSERT_EQ(ItemActionStatus::SUCCESS, status);
+}
+
+void RemoveRequestsTaskTest::RemoveRequestsCallback(
+ std::unique_ptr<UpdateRequestsResult> result) {
+ result_ = std::move(result);
+}
+
+TEST_F(RemoveRequestsTaskTest, RemoveWhenStoreEmpty) {
+ RequestQueueInMemoryStore store;
+ std::vector<int64_t> request_ids{kRequestId1};
+ RemoveRequestsTask task(
+ &store, request_ids,
+ base::Bind(&RemoveRequestsTaskTest::RemoveRequestsCallback,
+ base::Unretained(this)));
+ task.Run();
+ PumpLoop();
+ ASSERT_TRUE(last_result());
+ EXPECT_EQ(1UL, last_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId1, last_result()->item_statuses.at(0).first);
+ EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+ last_result()->item_statuses.at(0).second);
+ EXPECT_EQ(0UL, last_result()->updated_items.size());
+}
+
+TEST_F(RemoveRequestsTaskTest, RemoveSingleItem) {
+ RequestQueueInMemoryStore store;
+ AddRequestsToStore(&store);
+ std::vector<int64_t> request_ids{kRequestId1};
+ RemoveRequestsTask task(
+ &store, request_ids,
+ base::Bind(&RemoveRequestsTaskTest::RemoveRequestsCallback,
+ base::Unretained(this)));
+ task.Run();
+ PumpLoop();
+ ASSERT_TRUE(last_result());
+ EXPECT_EQ(1UL, last_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId1, last_result()->item_statuses.at(0).first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_result()->item_statuses.at(0).second);
+ EXPECT_EQ(1UL, last_result()->updated_items.size());
+ EXPECT_EQ(kRequestId1, last_result()->updated_items.at(0).request_id());
+}
+
+TEST_F(RemoveRequestsTaskTest, RemoveMultipleItems) {
+ RequestQueueInMemoryStore store;
+ AddRequestsToStore(&store);
+ std::vector<int64_t> request_ids{kRequestId1, kRequestId2};
+ RemoveRequestsTask task(
+ &store, request_ids,
+ base::Bind(&RemoveRequestsTaskTest::RemoveRequestsCallback,
+ base::Unretained(this)));
+ task.Run();
+ PumpLoop();
+ ASSERT_TRUE(last_result());
+ EXPECT_EQ(2UL, last_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId1, last_result()->item_statuses.at(0).first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_result()->item_statuses.at(0).second);
+ EXPECT_EQ(kRequestId2, last_result()->item_statuses.at(1).first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_result()->item_statuses.at(1).second);
+ EXPECT_EQ(2UL, last_result()->updated_items.size());
+ EXPECT_EQ(kRequestId1, last_result()->updated_items.at(0).request_id());
+ EXPECT_EQ(kRequestId2, last_result()->updated_items.at(1).request_id());
+}
+
+TEST_F(RemoveRequestsTaskTest, DeleteWithEmptyIdList) {
+ RequestQueueInMemoryStore store;
+ std::vector<int64_t> request_ids;
+ RemoveRequestsTask task(
+ &store, request_ids,
+ base::Bind(&RemoveRequestsTaskTest::RemoveRequestsCallback,
+ base::Unretained(this)));
+ task.Run();
+ PumpLoop();
+ ASSERT_TRUE(last_result());
+ EXPECT_EQ(0UL, last_result()->item_statuses.size());
+ EXPECT_EQ(0UL, last_result()->updated_items.size());
+}
+
+TEST_F(RemoveRequestsTaskTest, RemoveMissingItem) {
+ RequestQueueInMemoryStore store;
+ AddRequestsToStore(&store);
+ std::vector<int64_t> request_ids{kRequestId1, kRequestId3};
+ RemoveRequestsTask task(
+ &store, request_ids,
+ base::Bind(&RemoveRequestsTaskTest::RemoveRequestsCallback,
+ base::Unretained(this)));
+ task.Run();
+ PumpLoop();
+ ASSERT_TRUE(last_result());
+ EXPECT_EQ(2UL, last_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId1, last_result()->item_statuses.at(0).first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_result()->item_statuses.at(0).second);
+ EXPECT_EQ(kRequestId3, last_result()->item_statuses.at(1).first);
+ EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+ last_result()->item_statuses.at(1).second);
+ EXPECT_EQ(1UL, last_result()->updated_items.size());
+ EXPECT_EQ(kRequestId1, last_result()->updated_items.at(0).request_id());
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/request_coordinator.cc b/chromium/components/offline_pages/background/request_coordinator.cc
index d7798c4c5b2..7bc0b64b408 100644
--- a/chromium/components/offline_pages/background/request_coordinator.cc
+++ b/chromium/components/offline_pages/background/request_coordinator.cc
@@ -9,78 +9,400 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
+#include "base/sys_info.h"
+#include "base/time/time.h"
#include "components/offline_pages/background/offliner_factory.h"
#include "components/offline_pages/background/offliner_policy.h"
#include "components/offline_pages/background/request_picker.h"
#include "components/offline_pages/background/save_page_request.h"
+#include "components/offline_pages/client_policy_controller.h"
#include "components/offline_pages/offline_page_item.h"
+#include "components/offline_pages/offline_page_model.h"
namespace offline_pages {
namespace {
-// TODO(dougarnett/petewil): Move to Policy object. Also consider lower minimum
-// battery percentage once there is some processing time limits in place.
-const Scheduler::TriggerConditions kUserRequestTriggerConditions(
- false /* require_power_connected */,
- 50 /* minimum_battery_percentage */,
- false /* require_unmetered_network */);
+const bool kUserRequest = true;
+const int kMinDurationSeconds = 1;
+const int kMaxDurationSeconds = 7 * 24 * 60 * 60; // 7 days
+const int kDurationBuckets = 50;
+const int kDisabledTaskRecheckSeconds = 5;
+
+// TODO(dougarnett): Move to util location and share with model impl.
+std::string AddHistogramSuffix(const ClientId& client_id,
+ const char* histogram_name) {
+ if (client_id.name_space.empty()) {
+ NOTREACHED();
+ return histogram_name;
+ }
+ std::string adjusted_histogram_name(histogram_name);
+ adjusted_histogram_name += "." + client_id.name_space;
+ return adjusted_histogram_name;
+}
+
+// Records the final request status UMA for an offlining request. This should
+// only be called once per Offliner::LoadAndSave request.
+void RecordOfflinerResultUMA(const ClientId& client_id,
+ const base::Time& request_creation_time,
+ Offliner::RequestStatus request_status) {
+ // The histogram below is an expansion of the UMA_HISTOGRAM_ENUMERATION
+ // macro adapted to allow for a dynamically suffixed histogram name.
+ // Note: The factory creates and owns the histogram.
+ base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
+ AddHistogramSuffix(client_id,
+ "OfflinePages.Background.OfflinerRequestStatus"),
+ 1, static_cast<int>(Offliner::RequestStatus::STATUS_COUNT),
+ static_cast<int>(Offliner::RequestStatus::STATUS_COUNT) + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(static_cast<int>(request_status));
+
+ // For successful requests also record time from request to save.
+ if (request_status == Offliner::RequestStatus::SAVED) {
+ // Using regular histogram (with dynamic suffix) rather than time-oriented
+ // one to record samples in seconds rather than milliseconds.
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ AddHistogramSuffix(client_id, "OfflinePages.Background.TimeToSaved"),
+ kMinDurationSeconds, kMaxDurationSeconds, kDurationBuckets,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ base::TimeDelta duration = base::Time::Now() - request_creation_time;
+ histogram->Add(duration.InSeconds());
+ }
+}
+
+void RecordCancelTimeUMA(const SavePageRequest& canceled_request) {
+ // Using regular histogram (with dynamic suffix) rather than time-oriented
+ // one to record samples in seconds rather than milliseconds.
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ AddHistogramSuffix(canceled_request.client_id(),
+ "OfflinePages.Background.TimeToCanceled"),
+ kMinDurationSeconds, kMaxDurationSeconds, kDurationBuckets,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ base::TimeDelta duration =
+ base::Time::Now() - canceled_request.creation_time();
+ histogram->Add(duration.InSeconds());
+}
+
+// Records the number of started attempts for completed requests (whether
+// successful or not).
+void RecordAttemptCount(const SavePageRequest& request,
+ RequestNotifier::BackgroundSavePageResult status) {
+ if (status == RequestNotifier::BackgroundSavePageResult::SUCCESS) {
+ // TODO(dougarnett): Also record UMA for completed attempts here.
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "OfflinePages.Background.RequestSuccess.StartedAttemptCount",
+ request.started_attempt_count(), 1, 10, 11);
+ } else {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "OfflinePages.Background.RequestFailure.StartedAttemptCount",
+ request.started_attempt_count(), 1, 10, 11);
+ }
+}
+
+// This should use the same algorithm as we use for OfflinePageItem, so the IDs
+// are similar.
+int64_t GenerateOfflineId() {
+ return base::RandGenerator(std::numeric_limits<int64_t>::max()) + 1;
+}
+
+// In case we start processing from SavePageLater, we need a callback, but there
+// is nothing for it to do.
+void EmptySchedulerCallback(bool started) {}
+
} // namespace
-RequestCoordinator::RequestCoordinator(std::unique_ptr<OfflinerPolicy> policy,
- std::unique_ptr<OfflinerFactory> factory,
- std::unique_ptr<RequestQueue> queue,
- std::unique_ptr<Scheduler> scheduler)
+RequestCoordinator::RequestCoordinator(
+ std::unique_ptr<OfflinerPolicy> policy,
+ std::unique_ptr<OfflinerFactory> factory,
+ std::unique_ptr<RequestQueue> queue,
+ std::unique_ptr<Scheduler> scheduler,
+ net::NetworkQualityEstimator::NetworkQualityProvider*
+ network_quality_estimator)
: is_busy_(false),
- is_canceled_(false),
+ is_starting_(false),
+ is_stopped_(false),
+ use_test_connection_type_(false),
+ test_connection_type_(),
offliner_(nullptr),
policy_(std::move(policy)),
factory_(std::move(factory)),
queue_(std::move(queue)),
scheduler_(std::move(scheduler)),
+ policy_controller_(new ClientPolicyController()),
+ network_quality_estimator_(network_quality_estimator),
+ active_request_(nullptr),
last_offlining_status_(Offliner::RequestStatus::UNKNOWN),
+ scheduler_callback_(base::Bind(&EmptySchedulerCallback)),
+ offliner_timeout_(base::TimeDelta::FromSeconds(
+ policy_->GetSinglePageTimeLimitInSeconds())),
weak_ptr_factory_(this) {
DCHECK(policy_ != nullptr);
- picker_.reset(new RequestPicker(queue_.get()));
+ picker_.reset(
+ new RequestPicker(queue_.get(), policy_.get(), this, &event_logger_));
}
RequestCoordinator::~RequestCoordinator() {}
-bool RequestCoordinator::SavePageLater(
- const GURL& url, const ClientId& client_id) {
- DVLOG(2) << "URL is " << url << " " << __FUNCTION__;
+int64_t RequestCoordinator::SavePageLater(const GURL& url,
+ const ClientId& client_id,
+ bool user_requested,
+ RequestAvailability availability) {
+ DVLOG(2) << "URL is " << url << " " << __func__;
+
+ if (!OfflinePageModel::CanSaveURL(url)) {
+ DVLOG(1) << "Not able to save page for requested url: " << url;
+ return 0L;
+ }
- // TODO(petewil): We need a robust scheme for allocating new IDs.
- static int64_t id = 0;
+ int64_t id = GenerateOfflineId();
// Build a SavePageRequest.
- // TODO(petewil): Use something like base::Clock to help in testing.
- offline_pages::SavePageRequest request(
- id++, url, client_id, base::Time::Now());
+ offline_pages::SavePageRequest request(id, url, client_id, base::Time::Now(),
+ user_requested);
+
+ // If the download manager is not done with the request, put it on the
+ // disabled list.
+ if (availability == RequestAvailability::DISABLED_FOR_OFFLINER)
+ disabled_requests_.insert(id);
// Put the request on the request queue.
queue_->AddRequest(request,
base::Bind(&RequestCoordinator::AddRequestResultCallback,
weak_ptr_factory_.GetWeakPtr()));
- return true;
+ return id;
+}
+void RequestCoordinator::GetAllRequests(const GetRequestsCallback& callback) {
+ // Get all matching requests from the request queue, send them to our
+ // callback. We bind the namespace and callback to the front of the callback
+ // param set.
+ queue_->GetRequests(base::Bind(&RequestCoordinator::GetQueuedRequestsCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void RequestCoordinator::GetQueuedRequestsCallback(
+ const GetRequestsCallback& callback,
+ RequestQueue::GetRequestsResult result,
+ std::vector<std::unique_ptr<SavePageRequest>> requests) {
+ callback.Run(std::move(requests));
+}
+
+void RequestCoordinator::StopPrerendering(Offliner::RequestStatus stop_status) {
+ if (offliner_ && is_busy_) {
+ DCHECK(active_request_.get());
+ offliner_->Cancel();
+ AbortRequestAttempt(active_request_.get());
+ }
+
+ // Stopping offliner means it will not call callback so set last status.
+ last_offlining_status_ = stop_status;
+
+ if (active_request_) {
+ event_logger_.RecordOfflinerResult(active_request_->client_id().name_space,
+ last_offlining_status_,
+ active_request_->request_id());
+ RecordOfflinerResultUMA(active_request_->client_id(),
+ active_request_->creation_time(),
+ last_offlining_status_);
+ is_busy_ = false;
+ active_request_.reset();
+ }
+
+}
+
+void RequestCoordinator::GetRequestsForSchedulingCallback(
+ RequestQueue::GetRequestsResult result,
+ std::vector<std::unique_ptr<SavePageRequest>> requests) {
+ bool user_requested = false;
+
+ // Examine all requests, if we find a user requested one, we will use the less
+ // restrictive conditions for user_requested requests. Otherwise we will use
+ // the more restrictive non-user-requested conditions.
+ for (const auto& request : requests) {
+ if (request->user_requested()) {
+ user_requested = true;
+ break;
+ }
+ }
+
+ // In the get callback, determine the least restrictive, and call
+ // GetTriggerConditions based on that.
+ scheduler_->Schedule(GetTriggerConditions(user_requested));
+}
+
+bool RequestCoordinator::CancelActiveRequestIfItMatches(
+ const std::vector<int64_t>& request_ids) {
+ // If we have a request in progress and need to cancel it, call the
+ // pre-renderer to cancel. TODO Make sure we remove any page created by the
+ // prerenderer if it doesn't get the cancel in time.
+ if (active_request_ != nullptr) {
+ if (request_ids.end() != std::find(request_ids.begin(), request_ids.end(),
+ active_request_->request_id())) {
+ StopPrerendering(Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED);
+ active_request_.reset(nullptr);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void RequestCoordinator::AbortRequestAttempt(SavePageRequest* request) {
+ request->MarkAttemptAborted();
+ if (request->started_attempt_count() >= policy_->GetMaxStartedTries()) {
+ const BackgroundSavePageResult result(
+ BackgroundSavePageResult::START_COUNT_EXCEEDED);
+ event_logger_.RecordDroppedSavePageRequest(request->client_id().name_space,
+ result, request->request_id());
+ RemoveAttemptedRequest(*request, result);
+ } else {
+ queue_->UpdateRequest(
+ *request,
+ base::Bind(&RequestCoordinator::UpdateRequestCallback,
+ weak_ptr_factory_.GetWeakPtr(), request->client_id()));
+ }
+}
+
+void RequestCoordinator::RemoveAttemptedRequest(
+ const SavePageRequest& request,
+ BackgroundSavePageResult result) {
+ std::vector<int64_t> remove_requests;
+ remove_requests.push_back(request.request_id());
+ queue_->RemoveRequests(remove_requests,
+ base::Bind(&RequestCoordinator::HandleRemovedRequests,
+ weak_ptr_factory_.GetWeakPtr(), result));
+ RecordAttemptCount(request, result);
+}
+
+void RequestCoordinator::RemoveRequests(
+ const std::vector<int64_t>& request_ids,
+ const RemoveRequestsCallback& callback) {
+ bool canceled = CancelActiveRequestIfItMatches(request_ids);
+ queue_->RemoveRequests(
+ request_ids,
+ base::Bind(&RequestCoordinator::HandleRemovedRequestsAndCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback,
+ BackgroundSavePageResult::REMOVED));
+ if (canceled)
+ TryNextRequest();
+}
+
+void RequestCoordinator::PauseRequests(
+ const std::vector<int64_t>& request_ids) {
+ bool canceled = CancelActiveRequestIfItMatches(request_ids);
+ queue_->ChangeRequestsState(
+ request_ids, SavePageRequest::RequestState::PAUSED,
+ base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ if (canceled)
+ TryNextRequest();
+}
+
+void RequestCoordinator::ResumeRequests(
+ const std::vector<int64_t>& request_ids) {
+ queue_->ChangeRequestsState(
+ request_ids, SavePageRequest::RequestState::AVAILABLE,
+ base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+ // Schedule a task, in case there is not one scheduled.
+ ScheduleAsNeeded();
+}
+
+net::NetworkChangeNotifier::ConnectionType
+RequestCoordinator::GetConnectionType() {
+ // If we have a connection type set for test, use that.
+ if (use_test_connection_type_)
+ return test_connection_type_;
+
+ return net::NetworkChangeNotifier::GetConnectionType();
}
void RequestCoordinator::AddRequestResultCallback(
RequestQueue::AddRequestResult result,
const SavePageRequest& request) {
-
+ NotifyAdded(request);
// Inform the scheduler that we have an outstanding task.
- // TODO(petewil): Determine trigger conditions from policy.
- scheduler_->Schedule(GetTriggerConditionsForUserRequest());
+ scheduler_->Schedule(GetTriggerConditions(kUserRequest));
+
+ if (request.user_requested())
+ StartProcessingIfConnected();
}
// Called in response to updating a request in the request queue.
void RequestCoordinator::UpdateRequestCallback(
- RequestQueue::UpdateRequestResult result) {}
+ const ClientId& client_id,
+ RequestQueue::UpdateRequestResult result) {
+ // If the request succeeded, nothing to do. If it failed, we can't really do
+ // much, so just log it.
+ if (result != RequestQueue::UpdateRequestResult::SUCCESS) {
+ DVLOG(1) << "Failed to update request attempt details. "
+ << static_cast<int>(result);
+ event_logger_.RecordUpdateRequestFailed(client_id.name_space, result);
+ }
+}
-void RequestCoordinator::StopProcessing() {
- is_canceled_ = true;
- if (offliner_ && is_busy_)
- offliner_->Cancel();
+void RequestCoordinator::UpdateMultipleRequestsCallback(
+ std::unique_ptr<UpdateRequestsResult> result) {
+ for (const auto& request : result->updated_items)
+ NotifyChanged(request);
+
+ bool available_user_request = false;
+ for (const auto& request : result->updated_items) {
+ if (!available_user_request && request.user_requested() &&
+ request.request_state() == SavePageRequest::RequestState::AVAILABLE) {
+ available_user_request = true;
+ }
+ }
+
+ if (available_user_request)
+ StartProcessingIfConnected();
+}
+
+// When we successfully remove a request that completed successfully, move on to
+// the next request.
+void RequestCoordinator::CompletedRequestCallback(
+ const MultipleItemStatuses& status) {
+ TryNextRequest();
+}
+
+void RequestCoordinator::HandleRemovedRequestsAndCallback(
+ const RemoveRequestsCallback& callback,
+ BackgroundSavePageResult status,
+ std::unique_ptr<UpdateRequestsResult> result) {
+ // TODO(dougarnett): Define status code for user/api cancel and use here
+ // to determine whether to record cancel time UMA.
+ for (const auto& request : result->updated_items)
+ RecordCancelTimeUMA(request);
+ callback.Run(result->item_statuses);
+ HandleRemovedRequests(status, std::move(result));
+}
+
+void RequestCoordinator::HandleRemovedRequests(
+ BackgroundSavePageResult status,
+ std::unique_ptr<UpdateRequestsResult> result) {
+ for (const auto& request : result->updated_items)
+ NotifyCompleted(request, status);
+}
+
+void RequestCoordinator::ScheduleAsNeeded() {
+ // Get all requests from queue (there is no filtering mechanism).
+ queue_->GetRequests(
+ base::Bind(&RequestCoordinator::GetRequestsForSchedulingCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void RequestCoordinator::StopProcessing(
+ Offliner::RequestStatus stop_status) {
+ is_stopped_ = true;
+ StopPrerendering(stop_status);
+
+ // Let the scheduler know we are done processing.
+ scheduler_callback_.Run(true);
+}
+
+void RequestCoordinator::HandleWatchdogTimeout() {
+ StopProcessing(Offliner::REQUEST_COORDINATOR_TIMED_OUT);
}
// Returns true if the caller should expect a callback, false otherwise. For
@@ -88,45 +410,124 @@ void RequestCoordinator::StopProcessing() {
bool RequestCoordinator::StartProcessing(
const DeviceConditions& device_conditions,
const base::Callback<void(bool)>& callback) {
- if (is_busy_) return false;
+ current_conditions_.reset(new DeviceConditions(device_conditions));
+ if (is_starting_ || is_busy_)
+ return false;
+ is_starting_ = true;
+
+ // Mark the time at which we started processing so we can check our time
+ // budget.
+ operation_start_time_ = base::Time::Now();
- is_canceled_ = false;
+ is_stopped_ = false;
scheduler_callback_ = callback;
- // TODO(petewil): Check existing conditions (should be passed down from
- // BackgroundTask)
TryNextRequest();
return true;
}
+void RequestCoordinator::StartProcessingIfConnected() {
+ OfflinerImmediateStartStatus immediate_start_status = TryImmediateStart();
+ UMA_HISTOGRAM_ENUMERATION(
+ "OfflinePages.Background.ImmediateStartStatus", immediate_start_status,
+ RequestCoordinator::OfflinerImmediateStartStatus::STATUS_COUNT);
+}
+
+RequestCoordinator::OfflinerImmediateStartStatus
+RequestCoordinator::TryImmediateStart() {
+ // Make sure not already busy processing.
+ if (is_busy_)
+ return OfflinerImmediateStartStatus::BUSY;
+
+ // Make sure we are not on svelte device to start immediately.
+ if (base::SysInfo::IsLowEndDevice())
+ return OfflinerImmediateStartStatus::NOT_STARTED_ON_SVELTE;
+
+ // Make sure we have reasonable network quality (or at least a connection).
+ if (network_quality_estimator_) {
+ // TODO(dougarnett): Add UMA for quality type experienced.
+ net::EffectiveConnectionType quality =
+ network_quality_estimator_->GetEffectiveConnectionType();
+ if (quality < net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_2G)
+ return OfflinerImmediateStartStatus::WEAK_CONNECTION;
+ } else if (GetConnectionType() ==
+ net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE) {
+ return OfflinerImmediateStartStatus::NO_CONNECTION;
+ }
+
+ // Start processing with manufactured conservative battery conditions
+ // (i.e., assume no battery).
+ // TODO(dougarnett): Obtain actual battery conditions (from Android/Java).
+ DeviceConditions device_conditions(false, 0, GetConnectionType());
+ if (StartProcessing(device_conditions, base::Bind(&EmptySchedulerCallback)))
+ return OfflinerImmediateStartStatus::STARTED;
+ else
+ return OfflinerImmediateStartStatus::NOT_ACCEPTED;
+}
+
void RequestCoordinator::TryNextRequest() {
+ // If there is no time left in the budget, return to the scheduler.
+ // We do not remove the pending task that was set up earlier in case
+ // we run out of time, so the background scheduler will return to us
+ // at the next opportunity to run background tasks.
+ if (base::Time::Now() - operation_start_time_ >
+ base::TimeDelta::FromSeconds(
+ policy_->GetBackgroundProcessingTimeBudgetSeconds())) {
+ is_starting_ = false;
+
+ // Let the scheduler know we are done processing.
+ // TODO: Make sure the scheduler callback is valid before running it.
+ scheduler_callback_.Run(true);
+
+ return;
+ }
+
// Choose a request to process that meets the available conditions.
// This is an async call, and returns right away.
- picker_->ChooseNextRequest(
- base::Bind(&RequestCoordinator::RequestPicked,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&RequestCoordinator::RequestQueueEmpty,
- weak_ptr_factory_.GetWeakPtr()));
+ picker_->ChooseNextRequest(base::Bind(&RequestCoordinator::RequestPicked,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&RequestCoordinator::RequestNotPicked,
+ weak_ptr_factory_.GetWeakPtr()),
+ current_conditions_.get(),
+ disabled_requests_);
}
// Called by the request picker when a request has been picked.
void RequestCoordinator::RequestPicked(const SavePageRequest& request) {
- // Send the request on to the offliner.
- SendRequestToOffliner(request);
+ is_starting_ = false;
+
+ // Make sure we were not stopped while picking.
+ if (!is_stopped_) {
+ // Send the request on to the offliner.
+ SendRequestToOffliner(request);
+ }
}
-void RequestCoordinator::RequestQueueEmpty() {
+void RequestCoordinator::RequestNotPicked(
+ bool non_user_requested_tasks_remaining) {
+ is_starting_ = false;
+
// Clear the outstanding "safety" task in the scheduler.
scheduler_->Unschedule();
- // Return control to the scheduler when there is no more to do.
+
+ // If disabled tasks remain, post a new safety task for 5 sec from now.
+ if (disabled_requests_.size() > 0) {
+ scheduler_->BackupSchedule(GetTriggerConditions(kUserRequest),
+ kDisabledTaskRecheckSeconds);
+ } else if (non_user_requested_tasks_remaining) {
+ // If we don't have any of those, check for non-user-requested tasks.
+ scheduler_->Schedule(GetTriggerConditions(!kUserRequest));
+ }
+
+ // Let the scheduler know we are done processing.
scheduler_callback_.Run(true);
}
void RequestCoordinator::SendRequestToOffliner(const SavePageRequest& request) {
// Check that offlining didn't get cancelled while performing some async
// steps.
- if (is_canceled_)
+ if (is_stopped_)
return;
GetOffliner();
@@ -139,42 +540,162 @@ void RequestCoordinator::SendRequestToOffliner(const SavePageRequest& request) {
DCHECK(!is_busy_);
is_busy_ = true;
+ // Update the request for this attempt to start it.
+ SavePageRequest updated_request(request);
+ updated_request.MarkAttemptStarted(base::Time::Now());
+ queue_->UpdateRequest(
+ updated_request,
+ base::Bind(&RequestCoordinator::UpdateRequestCallback,
+ weak_ptr_factory_.GetWeakPtr(), updated_request.client_id()));
+ active_request_.reset(new SavePageRequest(updated_request));
+
// Start the load and save process in the offliner (Async).
- offliner_->LoadAndSave(request,
- base::Bind(&RequestCoordinator::OfflinerDoneCallback,
- weak_ptr_factory_.GetWeakPtr()));
+ if (offliner_->LoadAndSave(
+ updated_request, base::Bind(&RequestCoordinator::OfflinerDoneCallback,
+ weak_ptr_factory_.GetWeakPtr()))) {
+ // Start a watchdog timer to catch pre-renders running too long
+ watchdog_timer_.Start(FROM_HERE, offliner_timeout_, this,
+ &RequestCoordinator::HandleWatchdogTimeout);
+ } else {
+ is_busy_ = false;
+ DVLOG(0) << "Unable to start LoadAndSave";
+ StopProcessing(Offliner::PRERENDERING_NOT_STARTED);
+ }
}
void RequestCoordinator::OfflinerDoneCallback(const SavePageRequest& request,
Offliner::RequestStatus status) {
DVLOG(2) << "offliner finished, saved: "
- << (status == Offliner::RequestStatus::SAVED) << ", status: "
- << (int) status << ", " << __FUNCTION__;
- event_logger_.RecordSavePageRequestUpdated(
- request.client_id().name_space,
- "Saved",
- request.request_id());
+ << (status == Offliner::RequestStatus::SAVED)
+ << ", status: " << static_cast<int>(status) << ", " << __func__;
+ DCHECK_NE(status, Offliner::RequestStatus::UNKNOWN);
+ DCHECK_NE(status, Offliner::RequestStatus::LOADED);
+ event_logger_.RecordOfflinerResult(request.client_id().name_space, status,
+ request.request_id());
last_offlining_status_ = status;
+ RecordOfflinerResultUMA(request.client_id(), request.creation_time(),
+ last_offlining_status_);
+ watchdog_timer_.Stop();
is_busy_ = false;
-
- // If the request succeeded, remove it from the Queue and maybe schedule
- // another one.
- if (status == Offliner::RequestStatus::SAVED) {
- queue_->RemoveRequest(request.request_id(),
+ active_request_.reset(nullptr);
+
+ if (status == Offliner::RequestStatus::FOREGROUND_CANCELED ||
+ status == Offliner::RequestStatus::PRERENDERING_CANCELED) {
+ // Update the request for the canceled attempt.
+ // TODO(dougarnett): See if we can conclusively identify other attempt
+ // aborted cases to treat this way (eg, for Render Process Killed).
+ SavePageRequest updated_request(request);
+ AbortRequestAttempt(&updated_request);
+ NotifyChanged(updated_request);
+ } else if (status == Offliner::RequestStatus::SAVED) {
+ // Remove the request from the queue if it succeeded.
+ RemoveAttemptedRequest(request, BackgroundSavePageResult::SUCCESS);
+ } else if (status == Offliner::RequestStatus::PRERENDERING_FAILED_NO_RETRY) {
+ RemoveAttemptedRequest(request,
+ BackgroundSavePageResult::PRERENDER_FAILURE);
+ } else if (request.completed_attempt_count() + 1 >=
+ policy_->GetMaxCompletedTries()) {
+ // Remove from the request queue if we exceeded max retries. The +1
+ // represents the request that just completed. Since we call
+ // MarkAttemptCompleted within the if branches, the completed_attempt_count
+ // has not yet been updated when we are checking the if condition.
+ const BackgroundSavePageResult result(
+ BackgroundSavePageResult::RETRY_COUNT_EXCEEDED);
+ event_logger_.RecordDroppedSavePageRequest(request.client_id().name_space,
+ result, request.request_id());
+ RemoveAttemptedRequest(request, result);
+ } else {
+ // If we failed, but are not over the limit, update the request in the
+ // queue.
+ SavePageRequest updated_request(request);
+ updated_request.MarkAttemptCompleted();
+ queue_->UpdateRequest(updated_request,
base::Bind(&RequestCoordinator::UpdateRequestCallback,
- weak_ptr_factory_.GetWeakPtr()));
-
- // TODO(petewil): Check time budget. Return to the scheduler if we are out.
+ weak_ptr_factory_.GetWeakPtr(),
+ updated_request.client_id()));
+ NotifyChanged(updated_request);
+ }
- // Start another request if we have time.
- TryNextRequest();
+ // Determine whether we might try another request in this
+ // processing window based on how the previous request completed.
+ switch (status) {
+ case Offliner::RequestStatus::SAVED:
+ case Offliner::RequestStatus::SAVE_FAILED:
+ case Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED:
+ case Offliner::RequestStatus::REQUEST_COORDINATOR_TIMED_OUT:
+ case Offliner::RequestStatus::PRERENDERING_FAILED_NO_RETRY:
+ // Consider processing another request in this service window.
+ TryNextRequest();
+ break;
+ case Offliner::RequestStatus::FOREGROUND_CANCELED:
+ case Offliner::RequestStatus::PRERENDERING_CANCELED:
+ case Offliner::RequestStatus::PRERENDERING_FAILED:
+ // No further processing in this service window.
+ break;
+ default:
+ // Make explicit choice about new status codes that actually reach here.
+ // Their default is no further processing in this service window.
+ NOTREACHED();
}
}
-const Scheduler::TriggerConditions&
-RequestCoordinator::GetTriggerConditionsForUserRequest() {
- return kUserRequestTriggerConditions;
+void RequestCoordinator::EnableForOffliner(int64_t request_id) {
+ // Since the recent tab helper might call multiple times, ignore subsequent
+ // calls for a particular request_id.
+ if (disabled_requests_.find(request_id) == disabled_requests_.end())
+ return;
+ disabled_requests_.erase(request_id);
+ // If we are not busy, start processing right away.
+ StartProcessingIfConnected();
+}
+
+void RequestCoordinator::MarkRequestCompleted(int64_t request_id) {
+ // Since the recent tab helper might call multiple times, ignore subsequent
+ // calls for a particular request_id.
+ if (disabled_requests_.find(request_id) == disabled_requests_.end())
+ return;
+ disabled_requests_.erase(request_id);
+
+ // Remove the request, but send out SUCCEEDED instead of removed.
+ std::vector<int64_t> request_ids { request_id };
+ queue_->RemoveRequests(
+ request_ids,
+ base::Bind(&RequestCoordinator::HandleRemovedRequestsAndCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Bind(&RequestCoordinator::CompletedRequestCallback,
+ weak_ptr_factory_.GetWeakPtr()),
+ BackgroundSavePageResult::SUCCESS));
+}
+
+const Scheduler::TriggerConditions RequestCoordinator::GetTriggerConditions(
+ const bool user_requested) {
+ return Scheduler::TriggerConditions(
+ policy_->PowerRequired(user_requested),
+ policy_->BatteryPercentageRequired(user_requested),
+ policy_->UnmeteredNetworkRequired(user_requested));
+}
+
+void RequestCoordinator::AddObserver(Observer* observer) {
+ DCHECK(observer);
+ observers_.AddObserver(observer);
+}
+
+void RequestCoordinator::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void RequestCoordinator::NotifyAdded(const SavePageRequest& request) {
+ FOR_EACH_OBSERVER(Observer, observers_, OnAdded(request));
+}
+
+void RequestCoordinator::NotifyCompleted(const SavePageRequest& request,
+ BackgroundSavePageResult status) {
+ FOR_EACH_OBSERVER(Observer, observers_, OnCompleted(request, status));
+}
+
+void RequestCoordinator::NotifyChanged(const SavePageRequest& request) {
+ FOR_EACH_OBSERVER(Observer, observers_, OnChanged(request));
}
void RequestCoordinator::GetOffliner() {
@@ -183,4 +704,12 @@ void RequestCoordinator::GetOffliner() {
}
}
+ClientPolicyController* RequestCoordinator::GetPolicyController() {
+ return policy_controller_.get();
+}
+
+void RequestCoordinator::Shutdown() {
+ network_quality_estimator_ = nullptr;
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/request_coordinator.h b/chromium/components/offline_pages/background/request_coordinator.h
index 624808c3962..e4970a0ba3a 100644
--- a/chromium/components/offline_pages/background/request_coordinator.h
+++ b/chromium/components/offline_pages/background/request_coordinator.h
@@ -6,16 +6,23 @@
#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_COORDINATOR_H_
#include <memory>
+#include <set>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/supports_user_data.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/offline_pages/background/device_conditions.h"
#include "components/offline_pages/background/offliner.h"
#include "components/offline_pages/background/request_coordinator_event_logger.h"
+#include "components/offline_pages/background/request_notifier.h"
#include "components/offline_pages/background/request_queue.h"
#include "components/offline_pages/background/scheduler.h"
+#include "net/nqe/network_quality_estimator.h"
#include "url/gurl.h"
namespace offline_pages {
@@ -27,25 +34,79 @@ class Offliner;
class RequestPicker;
class SavePageRequest;
class Scheduler;
+class ClientPolicyController;
// Coordinates queueing and processing save page later requests.
-class RequestCoordinator : public KeyedService {
+class RequestCoordinator : public KeyedService,
+ public RequestNotifier,
+ public base::SupportsUserData {
public:
- // Callback to report when the processing of a triggered task is complete.
+
+ // Nested observer class. To make sure that no events are missed, the client
+ // code should first register for notifications, then |GetAllRequests|, and
+ // ignore all events before the return from |GetAllRequests|, and consume
+ // events after the return callback from |GetAllRequests|.
+ class Observer {
+ public:
+ virtual ~Observer() = default;
+
+ virtual void OnAdded(const SavePageRequest& request) = 0;
+ virtual void OnCompleted(
+ const SavePageRequest& request,
+ RequestNotifier::BackgroundSavePageResult status) = 0;
+ virtual void OnChanged(const SavePageRequest& request) = 0;
+ };
+
+ enum class RequestAvailability {
+ ENABLED_FOR_OFFLINER,
+ DISABLED_FOR_OFFLINER,
+ };
+
+ // Callback to report when a request was available.
typedef base::Callback<void(const SavePageRequest& request)>
RequestPickedCallback;
- typedef base::Callback<void()> RequestQueueEmptyCallback;
+
+ // Callback to report when no request was available.
+ typedef base::Callback<void(bool)> RequestNotPickedCallback;
+
+ // Callback specifying which request IDs were actually removed.
+ typedef base::Callback<void(const MultipleItemStatuses&)>
+ RemoveRequestsCallback;
+
+ // Callback that receives the response for GetAllRequests.
+ typedef base::Callback<void(std::vector<std::unique_ptr<SavePageRequest>>)>
+ GetRequestsCallback;
RequestCoordinator(std::unique_ptr<OfflinerPolicy> policy,
std::unique_ptr<OfflinerFactory> factory,
std::unique_ptr<RequestQueue> queue,
- std::unique_ptr<Scheduler> scheduler);
+ std::unique_ptr<Scheduler> scheduler,
+ net::NetworkQualityEstimator::NetworkQualityProvider*
+ network_quality_estimator);
~RequestCoordinator() override;
// Queues |request| to later load and save when system conditions allow.
- // Returns true if the page could be queued successfully.
- bool SavePageLater(const GURL& url, const ClientId& client_id);
+ // Returns an id if the page could be queued successfully, 0L otherwise.
+ int64_t SavePageLater(const GURL& url,
+ const ClientId& client_id,
+ bool user_requested,
+ RequestAvailability availability);
+
+ // Remove a list of requests by |request_id|. This removes requests from the
+ // request queue, and cancels an in-progress prerender.
+ void RemoveRequests(const std::vector<int64_t>& request_ids,
+ const RemoveRequestsCallback& callback);
+
+ // Pause a list of requests by |request_id|. This will change the state
+ // in the request queue so the request cannot be started.
+ void PauseRequests(const std::vector<int64_t>& request_ids);
+
+ // Resume a list of previously paused requests, making them available.
+ void ResumeRequests(const std::vector<int64_t>& request_ids);
+
+ // Get all save page request items in the callback.
+ void GetAllRequests(const GetRequestsCallback& callback);
// Starts processing of one or more queued save page later requests.
// Returns whether processing was started and that caller should expect
@@ -57,22 +118,50 @@ class RequestCoordinator : public KeyedService {
// caller to abort processing; otherwise, processing will complete on
// its own. In either case, the callback will be called when processing
// is stopped or complete.
- void StopProcessing();
+ void StopProcessing(Offliner::RequestStatus stop_status);
+
+ // Used to denote that the foreground thread is ready for the offliner
+ // to start work on a previously entered, but unavailable request.
+ void EnableForOffliner(int64_t request_id);
- // TODO(dougarnett): Move to OfflinerPolicy in some form.
- const Scheduler::TriggerConditions& GetTriggerConditionsForUserRequest();
+ // If a request that is unavailable to the offliner is finished elsewhere,
+ // (by the tab helper synchronous download), send a notificaiton that it
+ // succeeded through our notificaiton system.
+ void MarkRequestCompleted(int64_t request_id);
+
+ const Scheduler::TriggerConditions GetTriggerConditions(
+ const bool user_requested);
// A way for tests to set the callback in use when an operation is over.
void SetProcessingCallbackForTest(const base::Callback<void(bool)> callback) {
scheduler_callback_ = callback;
}
+ // Observers implementing the RequestCoordinator::Observer interface can
+ // register here to get notifications of changes to request state. This
+ // pointer is not owned, and it is the callers responsibility to remove the
+ // observer before the observer is deleted.
+ void AddObserver(RequestCoordinator::Observer* observer);
+
+ void RemoveObserver(RequestCoordinator::Observer* observer);
+
+ // Implement RequestNotifier
+ void NotifyAdded(const SavePageRequest& request) override;
+ void NotifyCompleted(
+ const SavePageRequest& request,
+ RequestNotifier::BackgroundSavePageResult status) override;
+ void NotifyChanged(const SavePageRequest& request) override;
+
// Returns the request queue used for requests. Coordinator keeps ownership.
RequestQueue* queue() { return queue_.get(); }
// Return an unowned pointer to the Scheduler.
Scheduler* scheduler() { return scheduler_.get(); }
+ OfflinerPolicy* policy() { return policy_.get(); }
+
+ ClientPolicyController* GetPolicyController();
+
// Returns the status of the most recent offlining.
Offliner::RequestStatus last_offlining_status() {
return last_offlining_status_;
@@ -82,10 +171,14 @@ class RequestCoordinator : public KeyedService {
return is_busy_;
}
+ // Returns whether processing is starting (before it is decided to actually
+ // process a request (is_busy()) at this time or not.
+ bool is_starting() { return is_starting_; }
+
// Tracks whether the last offlining attempt got canceled. This is reset by
// the next StartProcessing() call.
bool is_canceled() {
- return is_canceled_;
+ return is_stopped_;
}
OfflineEventLogger* GetLogger() {
@@ -93,16 +186,82 @@ class RequestCoordinator : public KeyedService {
}
private:
+ // Immediate start attempt status code for UMA.
+ // For any changes, also update corresponding histogram in histograms.xml.
+ enum OfflinerImmediateStartStatus {
+ // Did start processing request.
+ STARTED = 0,
+ // Already busy processing a request.
+ BUSY = 1,
+ // The Offliner did not accept processing the request.
+ NOT_ACCEPTED = 2,
+ // No current network connection.
+ NO_CONNECTION = 3,
+ // Weak network connection (worse than 2G speed)
+ // according to network quality estimator.
+ WEAK_CONNECTION = 4,
+ // Did not start because this is svelte device.
+ NOT_STARTED_ON_SVELTE = 5,
+ // NOTE: insert new values above this line and update histogram enum too.
+ STATUS_COUNT = 6,
+ };
+
+ // Receives the results of a get from the request queue, and turns that into
+ // SavePageRequest objects for the caller of GetQueuedRequests.
+ void GetQueuedRequestsCallback(
+ const GetRequestsCallback& callback,
+ RequestQueue::GetRequestsResult result,
+ std::vector<std::unique_ptr<SavePageRequest>> requests);
+
+ // Receives the results of a get from the request queue, and turns that into
+ // SavePageRequest objects for the caller of GetQueuedRequests.
+ void GetRequestsForSchedulingCallback(
+ RequestQueue::GetRequestsResult result,
+ std::vector<std::unique_ptr<SavePageRequest>> requests);
+
+ // Receives the result of add requests to the request queue.
void AddRequestResultCallback(RequestQueue::AddRequestResult result,
const SavePageRequest& request);
- void UpdateRequestCallback(RequestQueue::UpdateRequestResult result);
+ // Receives the result of update and delete requests to the request queue.
+ void UpdateRequestCallback(const ClientId& client_id,
+ RequestQueue::UpdateRequestResult result);
+
+ void UpdateMultipleRequestsCallback(
+ std::unique_ptr<UpdateRequestsResult> result);
+
+ void CompletedRequestCallback(const MultipleItemStatuses& status);
+
+ void HandleRemovedRequestsAndCallback(
+ const RemoveRequestsCallback& callback,
+ BackgroundSavePageResult status,
+ std::unique_ptr<UpdateRequestsResult> result);
+
+ void HandleRemovedRequests(BackgroundSavePageResult status,
+ std::unique_ptr<UpdateRequestsResult> result);
+
+ // Start processing now if connected (but with conservative assumption
+ // as to other device conditions).
+ void StartProcessingIfConnected();
+
+ OfflinerImmediateStartStatus TryImmediateStart();
+
+ // Check the request queue, and schedule a task corresponding
+ // to the least restrictive type of request in the queue.
+ void ScheduleAsNeeded();
// Callback from the request picker when it has chosen our next request.
void RequestPicked(const SavePageRequest& request);
// Callback from the request picker when no more requests are in the queue.
- void RequestQueueEmpty();
+ // The parameter is a signal for what (if any) conditions to schedule future
+ // processing for.
+ void RequestNotPicked(bool non_user_requested_tasks_remaining);
+
+ void HandleWatchdogTimeout();
+
+ // Cancels an in progress pre-rendering, and updates state appropriately.
+ void StopPrerendering(Offliner::RequestStatus stop_status);
void SendRequestToOffliner(const SavePageRequest& request);
@@ -113,20 +272,65 @@ class RequestCoordinator : public KeyedService {
void TryNextRequest();
+ // If there is an active request in the list, cancel that request.
+ bool CancelActiveRequestIfItMatches(const std::vector<int64_t>& request_ids);
+
+ // Records an aborted attempt for the request and update it in the queue
+ // (possibly removing it). Returns the updated copy.
+ void AbortRequestAttempt(SavePageRequest* request);
+
+ // Remove the attempted request from the queue with status to pass through to
+ // any observers and UMA histogram.
+ void RemoveAttemptedRequest(const SavePageRequest& request,
+ BackgroundSavePageResult status);
+
// Returns the appropriate offliner to use, getting a new one from the factory
// if needed.
void GetOffliner();
+ // Method to wrap calls to getting the connection type so it can be
+ // changed for tests.
+ net::NetworkChangeNotifier::ConnectionType GetConnectionType();
+
+ void SetNetworkConditionsForTest(
+ net::NetworkChangeNotifier::ConnectionType connection) {
+ use_test_connection_type_ = true;
+ test_connection_type_ = connection;
+ }
+
+ void SetOfflinerTimeoutForTest(const base::TimeDelta& timeout) {
+ offliner_timeout_ = timeout;
+ }
+
+ void SetDeviceConditionsForTest(DeviceConditions& current_conditions) {
+ current_conditions_.reset(new DeviceConditions(current_conditions));
+ }
+
+ // KeyedService implementation:
+ void Shutdown() override;
+
friend class RequestCoordinatorTest;
// The offliner can only handle one request at a time - if the offliner is
// busy, prevent other requests. This flag marks whether the offliner is in
// use.
bool is_busy_;
- // True if the current request has been canceled.
- bool is_canceled_;
+ // There is more than one path to start processing so this flag is used
+ // to avoid race conditions before is_busy_ is established.
+ bool is_starting_;
+ // True if the current processing window has been canceled.
+ bool is_stopped_;
+ // True if we should use the test connection type instead of the actual type.
+ bool use_test_connection_type_;
+ // For use by tests, a fake network connection type
+ net::NetworkChangeNotifier::ConnectionType test_connection_type_;
// Unowned pointer to the current offliner, if any.
Offliner* offliner_;
+ base::Time operation_start_time_;
+ // The observers.
+ base::ObserverList<Observer> observers_;
+ // Last known conditions for network, battery
+ std::unique_ptr<DeviceConditions> current_conditions_;
// RequestCoordinator takes over ownership of the policy
std::unique_ptr<OfflinerPolicy> policy_;
// OfflinerFactory. Used to create offline pages. Owned.
@@ -135,14 +339,28 @@ class RequestCoordinator : public KeyedService {
std::unique_ptr<RequestQueue> queue_;
// Scheduler. Used to request a callback when network is available. Owned.
std::unique_ptr<Scheduler> scheduler_;
+ // Controller of client policies. Owned.
+ std::unique_ptr<ClientPolicyController> policy_controller_;
+ // Unowned pointer to the Network Quality Estimator.
+ net::NetworkQualityEstimator::NetworkQualityProvider*
+ network_quality_estimator_;
+ // Holds copy of the active request, if any.
+ std::unique_ptr<SavePageRequest> active_request_;
// Status of the most recent offlining.
Offliner::RequestStatus last_offlining_status_;
// Class to choose which request to schedule next
std::unique_ptr<RequestPicker> picker_;
+ // A set of request_ids that we are holding off until the download manager is
+ // done with them.
+ std::set<int64_t> disabled_requests_;
// Calling this returns to the scheduler across the JNI bridge.
base::Callback<void(bool)> scheduler_callback_;
// Logger to record events.
RequestCoordinatorEventLogger event_logger_;
+ // Timer to watch for pre-render attempts running too long.
+ base::OneShotTimer watchdog_timer_;
+ // How long to wait for an offliner request before giving up.
+ base::TimeDelta offliner_timeout_;
// Allows us to pass a weak pointer to callbacks.
base::WeakPtrFactory<RequestCoordinator> weak_ptr_factory_;
diff --git a/chromium/components/offline_pages/background/request_coordinator_event_logger.cc b/chromium/components/offline_pages/background/request_coordinator_event_logger.cc
index 12ddf8c2fa1..acdf8f769a9 100644
--- a/chromium/components/offline_pages/background/request_coordinator_event_logger.cc
+++ b/chromium/components/offline_pages/background/request_coordinator_event_logger.cc
@@ -2,19 +2,110 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <string>
-
#include "components/offline_pages/background/request_coordinator_event_logger.h"
namespace offline_pages {
-void RequestCoordinatorEventLogger::RecordSavePageRequestUpdated(
+namespace {
+
+static std::string OfflinerRequestStatusToString(
+ Offliner::RequestStatus request_status) {
+ switch (request_status) {
+ case Offliner::UNKNOWN:
+ return "UNKNOWN";
+ case Offliner::LOADED:
+ return "LOADED";
+ case Offliner::SAVED:
+ return "SAVED";
+ case Offliner::REQUEST_COORDINATOR_CANCELED:
+ return "REQUEST_COORDINATOR_CANCELED";
+ case Offliner::PRERENDERING_CANCELED:
+ return "PRERENDERING_CANCELED";
+ case Offliner::PRERENDERING_FAILED:
+ return "PRERENDERING_FAILED";
+ case Offliner::SAVE_FAILED:
+ return "SAVE_FAILED";
+ case Offliner::FOREGROUND_CANCELED:
+ return "FOREGROUND_CANCELED";
+ case Offliner::REQUEST_COORDINATOR_TIMED_OUT:
+ return "REQUEST_COORDINATOR_TIMED_OUT";
+ case Offliner::PRERENDERING_NOT_STARTED:
+ return "PRERENDERING_NOT_STARTED";
+ case Offliner::PRERENDERING_FAILED_NO_RETRY:
+ return "PRERENDERING_FAILED_NO_RETRY";
+ default:
+ NOTREACHED();
+ return std::to_string(static_cast<int>(request_status));
+ }
+}
+
+static std::string BackgroundSavePageResultToString(
+ RequestNotifier::BackgroundSavePageResult result) {
+ switch (result) {
+ case RequestNotifier::BackgroundSavePageResult::SUCCESS:
+ return "SUCCESS";
+ case RequestNotifier::BackgroundSavePageResult::PRERENDER_FAILURE:
+ return "PRERENDER_FAILURE";
+ case RequestNotifier::BackgroundSavePageResult::PRERENDER_CANCELED:
+ return "PRERENDER_CANCELED";
+ case RequestNotifier::BackgroundSavePageResult::FOREGROUND_CANCELED:
+ return "FOREGROUND_CANCELED";
+ case RequestNotifier::BackgroundSavePageResult::SAVE_FAILED:
+ return "SAVE_FAILED";
+ case RequestNotifier::BackgroundSavePageResult::EXPIRED:
+ return "EXPIRED";
+ case RequestNotifier::BackgroundSavePageResult::RETRY_COUNT_EXCEEDED:
+ return "RETRY_COUNT_EXCEEDED";
+ case RequestNotifier::BackgroundSavePageResult::START_COUNT_EXCEEDED:
+ return "START_COUNT_EXCEEDED";
+ case RequestNotifier::BackgroundSavePageResult::REMOVED:
+ return "REMOVED";
+ default:
+ NOTREACHED();
+ return std::to_string(static_cast<int>(result));
+ }
+}
+
+static std::string UpdateRequestResultToString(
+ RequestQueue::UpdateRequestResult result) {
+ switch (result) {
+ case RequestQueue::UpdateRequestResult::SUCCESS:
+ return "SUCCESS";
+ case RequestQueue::UpdateRequestResult::STORE_FAILURE:
+ return "STORE_FAILURE";
+ case RequestQueue::UpdateRequestResult::REQUEST_DOES_NOT_EXIST:
+ return "REQUEST_DOES_NOT_EXIST";
+ default:
+ NOTREACHED();
+ return std::to_string(static_cast<int>(result));
+ }
+}
+
+} // namespace
+
+void RequestCoordinatorEventLogger::RecordOfflinerResult(
+ const std::string& name_space,
+ Offliner::RequestStatus new_status,
+ int64_t request_id) {
+ RecordActivity("Background save attempt for " + name_space + ":" +
+ std::to_string(request_id) + " - " +
+ OfflinerRequestStatusToString(new_status));
+}
+
+void RequestCoordinatorEventLogger::RecordDroppedSavePageRequest(
+ const std::string& name_space,
+ RequestNotifier::BackgroundSavePageResult result,
+ int64_t request_id) {
+ RecordActivity("Background save request removed " + name_space + ":" +
+ std::to_string(request_id) + " - " +
+ BackgroundSavePageResultToString(result));
+}
+
+void RequestCoordinatorEventLogger::RecordUpdateRequestFailed(
const std::string& name_space,
- const std::string& new_status,
- int64_t id) {
- RecordActivity("Save page request for ID: " + std::to_string(id) +
- " and namespace: " + name_space +
- " has been updated with status " + new_status);
+ RequestQueue::UpdateRequestResult result) {
+ RecordActivity("Updating queued request for " + name_space + " failed - " +
+ UpdateRequestResultToString(result));
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/request_coordinator_event_logger.h b/chromium/components/offline_pages/background/request_coordinator_event_logger.h
index 0e047643589..61a7beb9459 100644
--- a/chromium/components/offline_pages/background/request_coordinator_event_logger.h
+++ b/chromium/components/offline_pages/background/request_coordinator_event_logger.h
@@ -6,18 +6,31 @@
#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_COORDINATOR_EVENT_LOGGER_H_
#include <stdint.h>
+#include <string>
+#include "components/offline_pages/background/offliner.h"
+#include "components/offline_pages/background/request_notifier.h"
+#include "components/offline_pages/background/request_queue.h"
#include "components/offline_pages/offline_event_logger.h"
namespace offline_pages {
class RequestCoordinatorEventLogger : public OfflineEventLogger {
public:
- // Records that a background task with SavePageRequest |request_id|
- // has been updated.
- void RecordSavePageRequestUpdated(const std::string& name_space,
- const std::string& new_status,
- int64_t request_id);
+ // Records the result of a background task attempt for SavePageRequest
+ // |request_id|.
+ void RecordOfflinerResult(const std::string& name_space,
+ Offliner::RequestStatus new_status,
+ int64_t request_id);
+
+ // Records the reason for dropped SavePageRequest |request_id|.
+ void RecordDroppedSavePageRequest(
+ const std::string& name_space,
+ RequestNotifier::BackgroundSavePageResult result,
+ int64_t request_id);
+
+ void RecordUpdateRequestFailed(const std::string& name_space,
+ RequestQueue::UpdateRequestResult result);
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/request_coordinator_event_logger_unittest.cc b/chromium/components/offline_pages/background/request_coordinator_event_logger_unittest.cc
index a8189a95c71..e41702b49fb 100644
--- a/chromium/components/offline_pages/background/request_coordinator_event_logger_unittest.cc
+++ b/chromium/components/offline_pages/background/request_coordinator_event_logger_unittest.cc
@@ -11,11 +11,19 @@ namespace offline_pages {
namespace {
const char kNamespace[] = "last_n";
-const char kStatus[] = "pending";
+const Offliner::RequestStatus kOfflinerStatus = Offliner::SAVED;
+const RequestNotifier::BackgroundSavePageResult kDroppedResult =
+ RequestNotifier::BackgroundSavePageResult::START_COUNT_EXCEEDED;
const int64_t kId = 1234;
-const char kLogString[] =
- "Save page request for ID: 1234 and namespace: "
- "last_n has been updated with status pending";
+const RequestQueue::UpdateRequestResult kQueueUpdateResult =
+ RequestQueue::UpdateRequestResult::STORE_FAILURE;
+
+const char kOfflinerStatusLogString[] =
+ "Background save attempt for last_n:1234 - SAVED";
+const char kDroppedResultLogString[] =
+ "Background save request removed last_n:1234 - START_COUNT_EXCEEDED";
+const char kQueueUpdateResultLogString[] =
+ "Updating queued request for last_n failed - STORE_FAILURE";
const int kTimeLength = 21;
} // namespace
@@ -25,11 +33,16 @@ TEST(RequestCoordinatorEventLoggerTest, RecordsWhenLoggingIsOn) {
std::vector<std::string> log;
logger.SetIsLogging(true);
- logger.RecordSavePageRequestUpdated(kNamespace, kStatus, kId);
+ logger.RecordOfflinerResult(kNamespace, kOfflinerStatus, kId);
+ logger.RecordDroppedSavePageRequest(kNamespace, kDroppedResult, kId);
+ logger.RecordUpdateRequestFailed(kNamespace, kQueueUpdateResult);
logger.GetLogs(&log);
- EXPECT_EQ(1u, log.size());
- EXPECT_EQ(std::string(kLogString), log[0].substr(kTimeLength));
+ EXPECT_EQ(3u, log.size());
+ EXPECT_EQ(std::string(kQueueUpdateResultLogString),
+ log[0].substr(kTimeLength));
+ EXPECT_EQ(std::string(kDroppedResultLogString), log[1].substr(kTimeLength));
+ EXPECT_EQ(std::string(kOfflinerStatusLogString), log[2].substr(kTimeLength));
}
TEST(RequestCoordinatorEventLoggerTest, RecordsWhenLoggingIsOff) {
@@ -37,7 +50,7 @@ TEST(RequestCoordinatorEventLoggerTest, RecordsWhenLoggingIsOff) {
std::vector<std::string> log;
logger.SetIsLogging(false);
- logger.RecordSavePageRequestUpdated(kNamespace, kStatus, kId);
+ logger.RecordOfflinerResult(kNamespace, kOfflinerStatus, kId);
logger.GetLogs(&log);
EXPECT_EQ(0u, log.size());
@@ -49,7 +62,7 @@ TEST(RequestCoordinatorEventLoggerTest, DoesNotExceedMaxSize) {
logger.SetIsLogging(true);
for (size_t i = 0; i < kMaxLogCount + 1; ++i) {
- logger.RecordSavePageRequestUpdated(kNamespace, kStatus, kId);
+ logger.RecordOfflinerResult(kNamespace, kOfflinerStatus, kId);
}
logger.GetLogs(&log);
diff --git a/chromium/components/offline_pages/background/request_coordinator_unittest.cc b/chromium/components/offline_pages/background/request_coordinator_unittest.cc
index 314ea0693be..06614b0d240 100644
--- a/chromium/components/offline_pages/background/request_coordinator_unittest.cc
+++ b/chromium/components/offline_pages/background/request_coordinator_unittest.cc
@@ -11,8 +11,11 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/test/test_simple_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/sys_info.h"
+#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "components/offline_pages/background/device_conditions.h"
#include "components/offline_pages/background/offliner.h"
#include "components/offline_pages/background/offliner_factory.h"
@@ -27,16 +30,30 @@ namespace offline_pages {
namespace {
// put test constants here
-const GURL kUrl("http://universe.com/everything");
-const ClientId kClientId("bookmark", "42");
-const int kRequestId(1);
+const GURL kUrl1("http://universe.com/everything");
+const GURL kUrl2("http://universe.com/toinfinityandbeyond");
+const std::string kClientNamespace("bookmark");
+const std::string kId1("42");
+const std::string kId2("life*universe+everything");
+const ClientId kClientId1(kClientNamespace, kId1);
+const ClientId kClientId2(kClientNamespace, kId2);
+const int kRequestId1(1);
+const int kRequestId2(2);
+const long kTestTimeoutSeconds = 1;
+const long kTestTimeBudgetSeconds = 200;
+const int kBatteryPercentageHigh = 75;
+const bool kPowerRequired = true;
+const bool kUserRequested = true;
+const int kAttemptCount = 1;
} // namespace
class SchedulerStub : public Scheduler {
public:
SchedulerStub()
: schedule_called_(false),
+ backup_schedule_called_(false),
unschedule_called_(false),
+ schedule_delay_(0L),
conditions_(false, 0, false) {}
void Schedule(const TriggerConditions& trigger_conditions) override {
@@ -44,6 +61,14 @@ class SchedulerStub : public Scheduler {
conditions_ = trigger_conditions;
}
+ void BackupSchedule(const TriggerConditions& trigger_conditions,
+ long delay_in_seconds) override {
+ backup_schedule_called_ = true;
+ schedule_delay_ = delay_in_seconds;
+ conditions_ = trigger_conditions;
+ }
+
+
// Unschedules the currently scheduled task, if any.
void Unschedule() override {
unschedule_called_ = true;
@@ -51,23 +76,34 @@ class SchedulerStub : public Scheduler {
bool schedule_called() const { return schedule_called_; }
+ bool backup_schedule_called() const { return backup_schedule_called_;}
+
bool unschedule_called() const { return unschedule_called_; }
TriggerConditions const* conditions() const { return &conditions_; }
private:
bool schedule_called_;
+ bool backup_schedule_called_;
bool unschedule_called_;
+ long schedule_delay_;
TriggerConditions conditions_;
};
class OfflinerStub : public Offliner {
public:
- OfflinerStub() : request_(kRequestId, kUrl, kClientId, base::Time::Now()),
- enable_callback_(false) {}
+ OfflinerStub()
+ : request_(kRequestId1, kUrl1, kClientId1, base::Time::Now(),
+ kUserRequested),
+ disable_loading_(false),
+ enable_callback_(false),
+ cancel_called_(false) {}
bool LoadAndSave(const SavePageRequest& request,
const CompletionCallback& callback) override {
+ if (disable_loading_)
+ return false;
+
callback_ = callback;
request_ = request;
// Post the callback on the run loop.
@@ -79,28 +115,28 @@ class OfflinerStub : public Offliner {
return true;
}
- // Clears the currently processing request, if any. Must have called
- // LoadAndSave first to set the callback and request.
- // Clears the currently processing request, if any.
- void Cancel() override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(callback_, request_, Offliner::RequestStatus::CANCELED));
+ void Cancel() override { cancel_called_ = true; }
+
+ void disable_loading() {
+ disable_loading_ = true;
}
void enable_callback(bool enable) {
enable_callback_ = enable;
}
+ bool cancel_called() { return cancel_called_; }
+
private:
CompletionCallback callback_;
SavePageRequest request_;
+ bool disable_loading_;
bool enable_callback_;
+ bool cancel_called_;
};
class OfflinerFactoryStub : public OfflinerFactory {
public:
-
OfflinerFactoryStub() : offliner_(nullptr) {}
Offliner* GetOffliner(const OfflinerPolicy* policy) override {
@@ -114,6 +150,74 @@ class OfflinerFactoryStub : public OfflinerFactory {
std::unique_ptr<OfflinerStub> offliner_;
};
+class NetworkQualityEstimatorStub
+ : public net::NetworkQualityEstimator::NetworkQualityProvider {
+ public:
+ NetworkQualityEstimatorStub()
+ : connection_type_(
+ net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_3G) {}
+
+ net::EffectiveConnectionType GetEffectiveConnectionType() const override {
+ return connection_type_;
+ }
+
+ void SetEffectiveConnectionTypeForTest(net::EffectiveConnectionType type) {
+ connection_type_ = type;
+ }
+
+ private:
+ net::EffectiveConnectionType connection_type_;
+};
+
+class ObserverStub : public RequestCoordinator::Observer {
+ public:
+ ObserverStub()
+ : added_called_(false),
+ completed_called_(false),
+ changed_called_(false),
+ last_status_(RequestCoordinator::BackgroundSavePageResult::SUCCESS),
+ state_(SavePageRequest::RequestState::PRERENDERING) {}
+
+ void Clear() {
+ added_called_ = false;
+ completed_called_ = false;
+ changed_called_ = false;
+ state_ = SavePageRequest::RequestState::PRERENDERING;
+ last_status_ = RequestCoordinator::BackgroundSavePageResult::SUCCESS;
+ }
+
+ void OnAdded(const SavePageRequest& request) override {
+ added_called_ = true;
+ }
+
+ void OnCompleted(
+ const SavePageRequest& request,
+ RequestCoordinator::BackgroundSavePageResult status) override {
+ completed_called_ = true;
+ last_status_ = status;
+ }
+
+ void OnChanged(const SavePageRequest& request) override {
+ changed_called_ = true;
+ state_ = request.request_state();
+ }
+
+ bool added_called() { return added_called_; }
+ bool completed_called() { return completed_called_; }
+ bool changed_called() { return changed_called_; }
+ RequestCoordinator::BackgroundSavePageResult last_status() {
+ return last_status_;
+ }
+ SavePageRequest::RequestState state() { return state_; }
+
+ private:
+ bool added_called_;
+ bool completed_called_;
+ bool changed_called_;
+ RequestCoordinator::BackgroundSavePageResult last_status_;
+ SavePageRequest::RequestState state_;
+};
+
class RequestCoordinatorTest
: public testing::Test {
public:
@@ -132,21 +236,31 @@ class RequestCoordinatorTest
return coordinator_->is_busy();
}
- void SendRequestToOffliner(SavePageRequest& request) {
- coordinator_->SendRequestToOffliner(request);
- }
+ bool is_starting() { return coordinator_->is_starting(); }
- // Empty callback function
+ // Empty callback function.
void EmptyCallbackFunction(bool result) {
}
- // Callback for Add requests
+ // Callback function which releases a wait for it.
+ void WaitingCallbackFunction(bool result) {
+ waiter_.Signal();
+ }
+
+ // Callback for Add requests.
void AddRequestDone(RequestQueue::AddRequestResult result,
const SavePageRequest& request);
// Callback for getting requests.
void GetRequestsDone(RequestQueue::GetRequestsResult result,
- const std::vector<SavePageRequest>& requests);
+ std::vector<std::unique_ptr<SavePageRequest>> requests);
+
+ // Callback for removing requests.
+ void RemoveRequestsDone(const MultipleItemStatuses& results);
+
+ // Callback for getting request statuses.
+ void GetQueuedRequestsDone(
+ std::vector<std::unique_ptr<SavePageRequest>> requests);
void SendOfflinerDoneCallback(const SavePageRequest& request,
Offliner::RequestStatus status);
@@ -155,32 +269,87 @@ class RequestCoordinatorTest
return last_get_requests_result_;
}
- const std::vector<SavePageRequest>& last_requests() const {
+ const std::vector<std::unique_ptr<SavePageRequest>>& last_requests() const {
return last_requests_;
}
+ const MultipleItemStatuses& last_remove_results() const {
+ return last_remove_results_;
+ }
+
+ void DisableLoading() {
+ offliner_->disable_loading();
+ }
+
void EnableOfflinerCallback(bool enable) {
offliner_->enable_callback(enable);
}
+ void SetNetworkConditionsForTest(
+ net::NetworkChangeNotifier::ConnectionType connection) {
+ coordinator()->SetNetworkConditionsForTest(connection);
+ }
+
+ void SetEffectiveConnectionTypeForTest(net::EffectiveConnectionType type) {
+ network_quality_estimator_->SetEffectiveConnectionTypeForTest(type);
+ }
+
+ void ScheduleForTest() { coordinator_->ScheduleAsNeeded(); }
+
+ void CallRequestNotPicked(bool non_user_requested_tasks_remaining,
+ bool disabled_tasks_remaining) {
+ if (disabled_tasks_remaining)
+ coordinator_->disabled_requests_.insert(kRequestId1);
+ else
+ coordinator_->disabled_requests_.clear();
+
+ coordinator_->RequestNotPicked(non_user_requested_tasks_remaining);
+ }
+
+ void SetOfflinerTimeoutForTest(const base::TimeDelta& timeout) {
+ coordinator_->SetOfflinerTimeoutForTest(timeout);
+ }
+
+ void SetDeviceConditionsForTest(DeviceConditions device_conditions) {
+ coordinator_->SetDeviceConditionsForTest(device_conditions);
+ }
+
+ void WaitForCallback() {
+ waiter_.Wait();
+ }
+
+ void AdvanceClockBy(base::TimeDelta delta) {
+ task_runner_->FastForwardBy(delta);
+ }
+
Offliner::RequestStatus last_offlining_status() const {
return coordinator_->last_offlining_status_;
}
+ bool OfflinerWasCanceled() const { return offliner_->cancel_called(); }
+
+ ObserverStub observer() { return observer_; }
+
private:
RequestQueue::GetRequestsResult last_get_requests_result_;
- std::vector<SavePageRequest> last_requests_;
- scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ MultipleItemStatuses last_remove_results_;
+ std::vector<std::unique_ptr<SavePageRequest>> last_requests_;
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
+ std::unique_ptr<NetworkQualityEstimatorStub> network_quality_estimator_;
std::unique_ptr<RequestCoordinator> coordinator_;
OfflinerStub* offliner_;
+ base::WaitableEvent waiter_;
+ ObserverStub observer_;
};
RequestCoordinatorTest::RequestCoordinatorTest()
: last_get_requests_result_(RequestQueue::GetRequestsResult::STORE_FAILURE),
- task_runner_(new base::TestSimpleTaskRunner),
+ task_runner_(new base::TestMockTimeTaskRunner),
task_runner_handle_(task_runner_),
- offliner_(nullptr) {}
+ offliner_(nullptr),
+ waiter_(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED) {}
RequestCoordinatorTest::~RequestCoordinatorTest() {}
@@ -194,9 +363,15 @@ void RequestCoordinatorTest::SetUp() {
store(new RequestQueueInMemoryStore());
std::unique_ptr<RequestQueue> queue(new RequestQueue(std::move(store)));
std::unique_ptr<Scheduler> scheduler_stub(new SchedulerStub());
+ network_quality_estimator_.reset(new NetworkQualityEstimatorStub());
coordinator_.reset(new RequestCoordinator(
std::move(policy), std::move(factory), std::move(queue),
- std::move(scheduler_stub)));
+ std::move(scheduler_stub), network_quality_estimator_.get()));
+ coordinator_->AddObserver(&observer_);
+ SetEffectiveConnectionTypeForTest(
+ net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+ SetNetworkConditionsForTest(
+ net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE);
}
void RequestCoordinatorTest::PumpLoop() {
@@ -205,9 +380,21 @@ void RequestCoordinatorTest::PumpLoop() {
void RequestCoordinatorTest::GetRequestsDone(
RequestQueue::GetRequestsResult result,
- const std::vector<SavePageRequest>& requests) {
+ std::vector<std::unique_ptr<SavePageRequest>> requests) {
last_get_requests_result_ = result;
- last_requests_ = requests;
+ last_requests_ = std::move(requests);
+}
+
+void RequestCoordinatorTest::RemoveRequestsDone(
+ const MultipleItemStatuses& results) {
+ last_remove_results_ = results;
+ waiter_.Signal();
+}
+
+void RequestCoordinatorTest::GetQueuedRequestsDone(
+ std::vector<std::unique_ptr<SavePageRequest>> requests) {
+ last_requests_ = std::move(requests);
+ waiter_.Signal();
}
void RequestCoordinatorTest::AddRequestDone(
@@ -232,11 +419,14 @@ TEST_F(RequestCoordinatorTest, StartProcessingWithNoRequests) {
TEST_F(RequestCoordinatorTest, StartProcessingWithRequestInProgress) {
// Put the request on the queue.
- EXPECT_TRUE(coordinator()->SavePageLater(kUrl, kClientId));
+ EXPECT_TRUE(
+ coordinator()->SavePageLater(
+ kUrl1, kClientId1, kUserRequested,
+ RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER) != 0);
// Set up for the call to StartProcessing by building arguments.
- DeviceConditions device_conditions(false, 75,
- net::NetworkChangeNotifier::CONNECTION_3G);
+ DeviceConditions device_conditions(
+ false, 75, net::NetworkChangeNotifier::CONNECTION_3G);
base::Callback<void(bool)> callback =
base::Bind(&RequestCoordinatorTest::EmptyCallbackFunction,
base::Unretained(this));
@@ -255,7 +445,10 @@ TEST_F(RequestCoordinatorTest, StartProcessingWithRequestInProgress) {
}
TEST_F(RequestCoordinatorTest, SavePageLater) {
- EXPECT_TRUE(coordinator()->SavePageLater(kUrl, kClientId));
+ EXPECT_TRUE(
+ coordinator()->SavePageLater(
+ kUrl1, kClientId1, kUserRequested,
+ RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER) != 0);
// Expect that a request got placed on the queue.
coordinator()->queue()->GetRequests(
@@ -267,23 +460,27 @@ TEST_F(RequestCoordinatorTest, SavePageLater) {
// Check the request queue is as expected.
EXPECT_EQ(1UL, last_requests().size());
- EXPECT_EQ(kUrl, last_requests()[0].url());
- EXPECT_EQ(kClientId, last_requests()[0].client_id());
+ EXPECT_EQ(kUrl1, last_requests().at(0)->url());
+ EXPECT_EQ(kClientId1, last_requests().at(0)->client_id());
// Expect that the scheduler got notified.
SchedulerStub* scheduler_stub = reinterpret_cast<SchedulerStub*>(
coordinator()->scheduler());
EXPECT_TRUE(scheduler_stub->schedule_called());
EXPECT_EQ(coordinator()
- ->GetTriggerConditionsForUserRequest()
+ ->GetTriggerConditions(last_requests()[0]->user_requested())
.minimum_battery_percentage,
scheduler_stub->conditions()->minimum_battery_percentage);
+
+ // Check that the observer got the notification that a page is available
+ EXPECT_TRUE(observer().added_called());
}
TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) {
// Add a request to the queue, wait for callbacks to finish.
offline_pages::SavePageRequest request(
- kRequestId, kUrl, kClientId, base::Time::Now());
+ kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
+ request.MarkAttemptStarted(base::Time::Now());
coordinator()->queue()->AddRequest(
request,
base::Bind(&RequestCoordinatorTest::AddRequestDone,
@@ -297,9 +494,13 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) {
base::Unretained(this));
coordinator()->SetProcessingCallbackForTest(callback);
+ // Set up device conditions for the test.
+ DeviceConditions device_conditions(
+ false, 75, net::NetworkChangeNotifier::CONNECTION_3G);
+ SetDeviceConditionsForTest(device_conditions);
+
// Call the OfflinerDoneCallback to simulate the page being completed, wait
// for callbacks.
- EnableOfflinerCallback(true);
SendOfflinerDoneCallback(request, Offliner::RequestStatus::SAVED);
PumpLoop();
@@ -313,18 +514,33 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) {
// RequestPicker should *not* have tried to start an additional job,
// because the request queue is empty now.
EXPECT_EQ(0UL, last_requests().size());
+ // Check that the observer got the notification that we succeeded, and that
+ // the request got removed from the queue.
+ EXPECT_TRUE(observer().completed_called());
+ EXPECT_EQ(RequestCoordinator::BackgroundSavePageResult::SUCCESS,
+ observer().last_status());
}
TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) {
// Add a request to the queue, wait for callbacks to finish.
offline_pages::SavePageRequest request(
- kRequestId, kUrl, kClientId, base::Time::Now());
+ kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
+ request.MarkAttemptStarted(base::Time::Now());
coordinator()->queue()->AddRequest(
request,
base::Bind(&RequestCoordinatorTest::AddRequestDone,
base::Unretained(this)));
PumpLoop();
+ // Add second request to the queue to check handling when first fails.
+ offline_pages::SavePageRequest request2(
+ kRequestId2, kUrl2, kClientId2, base::Time::Now(), kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request2,
+ base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
// We need to give a callback to the request.
base::Callback<void(bool)> callback =
base::Bind(
@@ -332,21 +548,279 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) {
base::Unretained(this));
coordinator()->SetProcessingCallbackForTest(callback);
+ // Set up device conditions for the test.
+ DeviceConditions device_conditions(
+ false, 75, net::NetworkChangeNotifier::CONNECTION_3G);
+ SetDeviceConditionsForTest(device_conditions);
+
// Call the OfflinerDoneCallback to simulate the request failed, wait
// for callbacks.
- EnableOfflinerCallback(true);
- SendOfflinerDoneCallback(request, Offliner::RequestStatus::FAILED);
+ SendOfflinerDoneCallback(request,
+ Offliner::RequestStatus::PRERENDERING_FAILED);
PumpLoop();
- // Verify the request is not removed from the queue, and wait for callbacks.
+ // TODO(dougarnett): Consider injecting mock RequestPicker for this test
+ // and verifying that there is no attempt to pick another request following
+ // this failure code.
+
coordinator()->queue()->GetRequests(
base::Bind(&RequestCoordinatorTest::GetRequestsDone,
base::Unretained(this)));
PumpLoop();
- // Still one request in the queue.
+ // Now just one request in the queue since failed request removed
+ // (for single attempt policy).
EXPECT_EQ(1UL, last_requests().size());
- // TODO(dougarnett): Verify retry count gets incremented.
+ // Check that the observer got the notification that we failed (and the
+ // subsequent notification that the request was removed).
+ EXPECT_TRUE(observer().completed_called());
+ EXPECT_EQ(RequestCoordinator::BackgroundSavePageResult::RETRY_COUNT_EXCEEDED,
+ observer().last_status());
+}
+
+TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailedNoRetryFailure) {
+ // Add a request to the queue, wait for callbacks to finish.
+ offline_pages::SavePageRequest request(kRequestId1, kUrl1, kClientId1,
+ base::Time::Now(), kUserRequested);
+ request.MarkAttemptStarted(base::Time::Now());
+ coordinator()->queue()->AddRequest(
+ request, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // Add second request to the queue to check handling when first fails.
+ offline_pages::SavePageRequest request2(kRequestId2, kUrl2, kClientId2,
+ base::Time::Now(), kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request2, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // We need to give a callback to the request.
+ base::Callback<void(bool)> callback = base::Bind(
+ &RequestCoordinatorTest::EmptyCallbackFunction, base::Unretained(this));
+ coordinator()->SetProcessingCallbackForTest(callback);
+
+ // Set up device conditions for the test.
+ DeviceConditions device_conditions(false, 75,
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ SetDeviceConditionsForTest(device_conditions);
+
+ // Call the OfflinerDoneCallback to simulate the request failed, wait
+ // for callbacks.
+ SendOfflinerDoneCallback(
+ request, Offliner::RequestStatus::PRERENDERING_FAILED_NO_RETRY);
+ PumpLoop();
+
+ // TODO(dougarnett): Consider injecting mock RequestPicker for this test
+ // and verifying that there is as attempt to pick another request following
+ // this non-retryable failure code.
+
+ coordinator()->queue()->GetRequests(base::Bind(
+ &RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
+ PumpLoop();
+
+ // Now just one request in the queue since non-retryable failure.
+ EXPECT_EQ(1UL, last_requests().size());
+ // Check that the observer got the notification that we failed (and the
+ // subsequent notification that the request was removed).
+ EXPECT_TRUE(observer().completed_called());
+ EXPECT_EQ(RequestCoordinator::BackgroundSavePageResult::PRERENDER_FAILURE,
+ observer().last_status());
+}
+
+TEST_F(RequestCoordinatorTest, OfflinerDoneForegroundCancel) {
+ // Add a request to the queue, wait for callbacks to finish.
+ offline_pages::SavePageRequest request(
+ kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
+ request.MarkAttemptStarted(base::Time::Now());
+ coordinator()->queue()->AddRequest(
+ request, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // We need to give a callback to the request.
+ base::Callback<void(bool)> callback = base::Bind(
+ &RequestCoordinatorTest::EmptyCallbackFunction, base::Unretained(this));
+ coordinator()->SetProcessingCallbackForTest(callback);
+
+ // Set up device conditions for the test.
+ DeviceConditions device_conditions(false, 75,
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ SetDeviceConditionsForTest(device_conditions);
+
+ // Call the OfflinerDoneCallback to simulate the request failed, wait
+ // for callbacks.
+ SendOfflinerDoneCallback(request,
+ Offliner::RequestStatus::FOREGROUND_CANCELED);
+ PumpLoop();
+
+ // Verify the request is not removed from the queue, and wait for callbacks.
+ coordinator()->queue()->GetRequests(base::Bind(
+ &RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
+ PumpLoop();
+
+ // Request no longer in the queue (for single attempt policy).
+ EXPECT_EQ(1UL, last_requests().size());
+ // Verify foreground cancel not counted as an attempt after all.
+ EXPECT_EQ(0L, last_requests().at(0)->completed_attempt_count());
+}
+
+TEST_F(RequestCoordinatorTest, OfflinerDonePrerenderingCancel) {
+ // Add a request to the queue, wait for callbacks to finish.
+ offline_pages::SavePageRequest request(kRequestId1, kUrl1, kClientId1,
+ base::Time::Now(), kUserRequested);
+ request.MarkAttemptStarted(base::Time::Now());
+ coordinator()->queue()->AddRequest(
+ request, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // We need to give a callback to the request.
+ base::Callback<void(bool)> callback = base::Bind(
+ &RequestCoordinatorTest::EmptyCallbackFunction, base::Unretained(this));
+ coordinator()->SetProcessingCallbackForTest(callback);
+
+ // Set up device conditions for the test.
+ DeviceConditions device_conditions(false, 75,
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ SetDeviceConditionsForTest(device_conditions);
+
+ // Call the OfflinerDoneCallback to simulate the request failed, wait
+ // for callbacks.
+ SendOfflinerDoneCallback(request,
+ Offliner::RequestStatus::PRERENDERING_CANCELED);
+ PumpLoop();
+
+ // Verify the request is not removed from the queue, and wait for callbacks.
+ coordinator()->queue()->GetRequests(base::Bind(
+ &RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
+ PumpLoop();
+
+ // Request still in the queue.
+ EXPECT_EQ(1UL, last_requests().size());
+ // Verify prerendering cancel not counted as an attempt after all.
+ const std::unique_ptr<SavePageRequest>& found_request =
+ last_requests().front();
+ EXPECT_EQ(0L, found_request->completed_attempt_count());
+}
+
+// If one item completes, and there are no more user requeted items left,
+// we should make a scheduler entry for a non-user requested item.
+TEST_F(RequestCoordinatorTest, RequestNotPickedDisabledItemsRemain) {
+ // Call start processing just to set up a scheduler callback.
+ DeviceConditions device_conditions(false, 75,
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ base::Callback<void(bool)> callback = base::Bind(
+ &RequestCoordinatorTest::EmptyCallbackFunction, base::Unretained(this));
+ coordinator()->StartProcessing(device_conditions, callback);
+ EXPECT_TRUE(is_starting());
+
+ // Call RequestNotPicked, simulating a request on the disabled list.
+ CallRequestNotPicked(false, true);
+ PumpLoop();
+
+ EXPECT_FALSE(is_starting());
+
+ // The scheduler should have been called to schedule the disabled task for
+ // 5 minutes from now.
+ SchedulerStub* scheduler_stub =
+ reinterpret_cast<SchedulerStub*>(coordinator()->scheduler());
+ EXPECT_TRUE(scheduler_stub->backup_schedule_called());
+ EXPECT_TRUE(scheduler_stub->unschedule_called());
+}
+
+// If one item completes, and there are no more user requeted items left,
+// we should make a scheduler entry for a non-user requested item.
+TEST_F(RequestCoordinatorTest, RequestNotPickedNonUserRequestedItemsRemain) {
+ // Call start processing just to set up a scheduler callback.
+ DeviceConditions device_conditions(false, 75,
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ base::Callback<void(bool)> callback = base::Bind(
+ &RequestCoordinatorTest::EmptyCallbackFunction, base::Unretained(this));
+ coordinator()->StartProcessing(device_conditions, callback);
+ EXPECT_TRUE(is_starting());
+
+ // Call RequestNotPicked, and make sure we pick schedule a task for non user
+ // requested conditions, with no tasks on the disabled list.
+ CallRequestNotPicked(true, false);
+ PumpLoop();
+
+ EXPECT_FALSE(is_starting());
+
+ // The scheduler should have been called to schedule the non-user requested
+ // task.
+ SchedulerStub* scheduler_stub =
+ reinterpret_cast<SchedulerStub*>(coordinator()->scheduler());
+ EXPECT_TRUE(scheduler_stub->schedule_called());
+ EXPECT_TRUE(scheduler_stub->unschedule_called());
+ const Scheduler::TriggerConditions* conditions = scheduler_stub->conditions();
+ EXPECT_EQ(conditions->require_power_connected,
+ coordinator()->policy()->PowerRequired(!kUserRequested));
+ EXPECT_EQ(
+ conditions->minimum_battery_percentage,
+ coordinator()->policy()->BatteryPercentageRequired(!kUserRequested));
+ EXPECT_EQ(conditions->require_unmetered_network,
+ coordinator()->policy()->UnmeteredNetworkRequired(!kUserRequested));
+}
+
+TEST_F(RequestCoordinatorTest, SchedulerGetsLeastRestrictiveConditions) {
+ // Put two requests on the queue - The first is user requested, and
+ // the second is not user requested.
+ offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1,
+ base::Time::Now(), kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request1, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ offline_pages::SavePageRequest request2(kRequestId2, kUrl2, kClientId2,
+ base::Time::Now(), !kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request2, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // Trigger the scheduler to schedule for the least restrictive condition.
+ ScheduleForTest();
+ PumpLoop();
+
+ // Expect that the scheduler got notified, and it is at user_requested
+ // priority.
+ SchedulerStub* scheduler_stub =
+ reinterpret_cast<SchedulerStub*>(coordinator()->scheduler());
+ const Scheduler::TriggerConditions* conditions = scheduler_stub->conditions();
+ EXPECT_TRUE(scheduler_stub->schedule_called());
+ EXPECT_EQ(conditions->require_power_connected,
+ coordinator()->policy()->PowerRequired(kUserRequested));
+ EXPECT_EQ(conditions->minimum_battery_percentage,
+ coordinator()->policy()->BatteryPercentageRequired(kUserRequested));
+ EXPECT_EQ(conditions->require_unmetered_network,
+ coordinator()->policy()->UnmeteredNetworkRequired(kUserRequested));
+}
+
+TEST_F(RequestCoordinatorTest, StartProcessingWithLoadingDisabled) {
+ // Add a request to the queue, wait for callbacks to finish.
+ offline_pages::SavePageRequest request(
+ kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request,
+ base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ DeviceConditions device_conditions(false, 75,
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ DisableLoading();
+ base::Callback<void(bool)> callback =
+ base::Bind(
+ &RequestCoordinatorTest::EmptyCallbackFunction,
+ base::Unretained(this));
+ EXPECT_TRUE(coordinator()->StartProcessing(device_conditions, callback));
+
+ // Let the async callbacks in the request coordinator run.
+ PumpLoop();
+
+ EXPECT_FALSE(is_starting());
+ EXPECT_EQ(Offliner::PRERENDERING_NOT_STARTED, last_offlining_status());
}
// This tests a StopProcessing call before we have actually started the
@@ -354,7 +828,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) {
TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingImmediately) {
// Add a request to the queue, wait for callbacks to finish.
offline_pages::SavePageRequest request(
- kRequestId, kUrl, kClientId, base::Time::Now());
+ kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
coordinator()->queue()->AddRequest(
request,
base::Bind(&RequestCoordinatorTest::AddRequestDone,
@@ -368,23 +842,30 @@ TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingImmediately) {
&RequestCoordinatorTest::EmptyCallbackFunction,
base::Unretained(this));
EXPECT_TRUE(coordinator()->StartProcessing(device_conditions, callback));
+ EXPECT_TRUE(is_starting());
// Now, quick, before it can do much (we haven't called PumpLoop), cancel it.
- coordinator()->StopProcessing();
+ coordinator()->StopProcessing(Offliner::REQUEST_COORDINATOR_CANCELED);
// Let the async callbacks in the request coordinator run.
PumpLoop();
+ EXPECT_FALSE(is_starting());
+
// OfflinerDoneCallback will not end up getting called with status SAVED,
- // Since we cancelled the event before it called offliner_->LoadAndSave().
- EXPECT_NE(Offliner::RequestStatus::SAVED, last_offlining_status());
+ // since we cancelled the event before it called offliner_->LoadAndSave().
+ EXPECT_EQ(Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED,
+ last_offlining_status());
+
+ // Since offliner was not started, it will not have seen cancel call.
+ EXPECT_FALSE(OfflinerWasCanceled());
}
// This tests a StopProcessing call after the prerenderer has been started.
TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingLater) {
// Add a request to the queue, wait for callbacks to finish.
offline_pages::SavePageRequest request(
- kRequestId, kUrl, kClientId, base::Time::Now());
+ kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
coordinator()->queue()->AddRequest(
request,
base::Bind(&RequestCoordinatorTest::AddRequestDone,
@@ -401,19 +882,357 @@ TEST_F(RequestCoordinatorTest, StartProcessingThenStopProcessingLater) {
&RequestCoordinatorTest::EmptyCallbackFunction,
base::Unretained(this));
EXPECT_TRUE(coordinator()->StartProcessing(device_conditions, callback));
+ EXPECT_TRUE(is_starting());
// Let all the async parts of the start processing pipeline run to completion.
PumpLoop();
+ // Coordinator should now be busy.
+ EXPECT_TRUE(is_busy());
+ EXPECT_FALSE(is_starting());
+
// Now we cancel it while the prerenderer is busy.
- coordinator()->StopProcessing();
+ coordinator()->StopProcessing(Offliner::REQUEST_COORDINATOR_CANCELED);
// Let the async callbacks in the cancel run.
PumpLoop();
+ EXPECT_FALSE(is_busy());
+
// OfflinerDoneCallback will not end up getting called with status SAVED,
- // Since we cancelled the event before it called offliner_->LoadAndSave().
- EXPECT_EQ(Offliner::RequestStatus::CANCELED, last_offlining_status());
+ // since we cancelled the event before the LoadAndSave completed.
+ EXPECT_EQ(Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED,
+ last_offlining_status());
+
+ // Since offliner was started, it will have seen cancel call.
+ EXPECT_TRUE(OfflinerWasCanceled());
+}
+
+// This tests that canceling a request will result in TryNextRequest() getting
+// called.
+TEST_F(RequestCoordinatorTest, RemoveInflightRequest) {
+ // Add a request to the queue, wait for callbacks to finish.
+ offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1,
+ base::Time::Now(), kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request1, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // Ensure the start processing request stops before the completion callback.
+ EnableOfflinerCallback(false);
+
+ DeviceConditions device_conditions(false, 75,
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ base::Callback<void(bool)> callback = base::Bind(
+ &RequestCoordinatorTest::EmptyCallbackFunction, base::Unretained(this));
+ EXPECT_TRUE(coordinator()->StartProcessing(device_conditions, callback));
+
+ // Let all the async parts of the start processing pipeline run to completion.
+ PumpLoop();
+
+ // Remove the request while it is processing.
+ std::vector<int64_t> request_ids{kRequestId1};
+ coordinator()->RemoveRequests(
+ request_ids, base::Bind(&RequestCoordinatorTest::RemoveRequestsDone,
+ base::Unretained(this)));
+
+ // Let the async callbacks in the cancel run.
+ PumpLoop();
+
+ // Since offliner was started, it will have seen cancel call.
+ EXPECT_TRUE(OfflinerWasCanceled());
+}
+
+TEST_F(RequestCoordinatorTest, MarkRequestCompleted) {
+ // Add a request to the queue.
+ offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1,
+ base::Time::Now(), kUserRequested);
+ int64_t request_id = coordinator()->SavePageLater(
+ kUrl1, kClientId1, kUserRequested,
+ RequestCoordinator::RequestAvailability::DISABLED_FOR_OFFLINER);
+ PumpLoop();
+ EXPECT_NE(request_id, 0l);
+
+ // Ensure the start processing request stops before the completion callback.
+ EnableOfflinerCallback(false);
+
+ DeviceConditions device_conditions(false, 75,
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ base::Callback<void(bool)> callback = base::Bind(
+ &RequestCoordinatorTest::EmptyCallbackFunction, base::Unretained(this));
+ EXPECT_TRUE(coordinator()->StartProcessing(device_conditions, callback));
+
+ // Call the method under test, making sure we send SUCCESS to the observer.
+ coordinator()->MarkRequestCompleted(request_id);
+ PumpLoop();
+
+ // Our observer should have seen SUCCESS instead of REMOVED.
+ EXPECT_EQ(RequestCoordinator::BackgroundSavePageResult::SUCCESS,
+ observer().last_status());
+ EXPECT_TRUE(observer().completed_called());
+}
+
+TEST_F(RequestCoordinatorTest, WatchdogTimeout) {
+ // Build a request to use with the pre-renderer, and put it on the queue.
+ offline_pages::SavePageRequest request(
+ kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request,
+ base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // Set up for the call to StartProcessing.
+ DeviceConditions device_conditions(
+ !kPowerRequired, kBatteryPercentageHigh,
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ base::Callback<void(bool)> callback =
+ base::Bind(&RequestCoordinatorTest::WaitingCallbackFunction,
+ base::Unretained(this));
+
+ // Ensure that the new request does not finish - we simulate it being
+ // in progress by asking it to skip making the completion callback.
+ EnableOfflinerCallback(false);
+
+ // Ask RequestCoordinator to stop waiting for the offliner after this many
+ // seconds.
+ SetOfflinerTimeoutForTest(base::TimeDelta::FromSeconds(kTestTimeoutSeconds));
+
+ // Sending the request to the offliner.
+ EXPECT_TRUE(coordinator()->StartProcessing(device_conditions, callback));
+ PumpLoop();
+
+ // Advance the mock clock far enough to cause a watchdog timeout
+ AdvanceClockBy(base::TimeDelta::FromSeconds(kTestTimeoutSeconds + 1));
+ PumpLoop();
+
+ // Wait for timeout to expire. Use a TaskRunner with a DelayedTaskRunner
+ // which won't time out immediately, so the watchdog thread doesn't kill valid
+ // tasks too soon.
+ WaitForCallback();
+ PumpLoop();
+
+ EXPECT_FALSE(is_starting());
+ EXPECT_TRUE(OfflinerWasCanceled());
+ EXPECT_EQ(Offliner::RequestStatus::REQUEST_COORDINATOR_TIMED_OUT,
+ last_offlining_status());
+}
+
+TEST_F(RequestCoordinatorTest, TimeBudgetExceeded) {
+ // Build two requests to use with the pre-renderer, and put it on the queue.
+ offline_pages::SavePageRequest request1(
+ kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
+ offline_pages::SavePageRequest request2(
+ kRequestId1 + 1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
+ request2.set_completed_attempt_count(kAttemptCount);
+ coordinator()->queue()->AddRequest(
+ request1,
+ base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ coordinator()->queue()->AddRequest(
+ request1, // TODO(petewil): This is a bug, should be request2.
+ base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // Set up for the call to StartProcessing.
+ DeviceConditions device_conditions(
+ !kPowerRequired, kBatteryPercentageHigh,
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ base::Callback<void(bool)> callback =
+ base::Bind(&RequestCoordinatorTest::WaitingCallbackFunction,
+ base::Unretained(this));
+
+ // Sending the request to the offliner.
+ EXPECT_TRUE(coordinator()->StartProcessing(device_conditions, callback));
+ PumpLoop();
+
+ // Advance the mock clock far enough to exceed our time budget.
+ AdvanceClockBy(base::TimeDelta::FromSeconds(kTestTimeBudgetSeconds));
+ PumpLoop();
+
+ // TryNextRequest should decide that there is no more work to be done,
+ // and call back to the scheduler, even though there is another request in the
+ // queue. There should be one request left in the queue.
+ // Verify the request gets removed from the queue, and wait for callbacks.
+ coordinator()->queue()->GetRequests(
+ base::Bind(&RequestCoordinatorTest::GetRequestsDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // We should find one request in the queue.
+ EXPECT_EQ(1UL, last_requests().size());
+}
+
+TEST_F(RequestCoordinatorTest, GetAllRequests) {
+ // Add two requests to the queue.
+ offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1,
+ base::Time::Now(), kUserRequested);
+ offline_pages::SavePageRequest request2(kRequestId1 + 1, kUrl2, kClientId2,
+ base::Time::Now(), kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request1, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ coordinator()->queue()->AddRequest(
+ request2, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // Start the async status fetching.
+ coordinator()->GetAllRequests(base::Bind(
+ &RequestCoordinatorTest::GetQueuedRequestsDone, base::Unretained(this)));
+ PumpLoop();
+
+ // Wait for async get to finish.
+ WaitForCallback();
+ PumpLoop();
+
+ // Check that the statuses found in the callback match what we expect.
+ EXPECT_EQ(2UL, last_requests().size());
+ EXPECT_EQ(kRequestId1, last_requests().at(0)->request_id());
+ EXPECT_EQ(kRequestId2, last_requests().at(1)->request_id());
+}
+
+TEST_F(RequestCoordinatorTest, PauseAndResumeObserver) {
+ // Add a request to the queue.
+ offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1,
+ base::Time::Now(), kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request1, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // Pause the request.
+ std::vector<int64_t> request_ids;
+ request_ids.push_back(kRequestId1);
+ coordinator()->PauseRequests(request_ids);
+ PumpLoop();
+
+ EXPECT_TRUE(observer().changed_called());
+ EXPECT_EQ(SavePageRequest::RequestState::PAUSED, observer().state());
+
+ // Clear out the observer before the next call.
+ observer().Clear();
+
+ // Resume the request.
+ coordinator()->ResumeRequests(request_ids);
+ PumpLoop();
+
+ EXPECT_TRUE(observer().changed_called());
+ EXPECT_EQ(SavePageRequest::RequestState::AVAILABLE, observer().state());
+}
+
+TEST_F(RequestCoordinatorTest, RemoveRequest) {
+ // Add a request to the queue.
+ offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1,
+ base::Time::Now(), kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request1, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // Remove the request.
+ std::vector<int64_t> request_ids;
+ request_ids.push_back(kRequestId1);
+ coordinator()->RemoveRequests(
+ request_ids, base::Bind(&RequestCoordinatorTest::RemoveRequestsDone,
+ base::Unretained(this)));
+
+ PumpLoop();
+ WaitForCallback();
+ PumpLoop();
+
+ EXPECT_TRUE(observer().completed_called());
+ EXPECT_EQ(RequestCoordinator::BackgroundSavePageResult::REMOVED,
+ observer().last_status());
+ EXPECT_EQ(1UL, last_remove_results().size());
+ EXPECT_EQ(kRequestId1, std::get<0>(last_remove_results().at(0)));
+}
+
+TEST_F(RequestCoordinatorTest,
+ SavePageStartsProcessingWhenConnectedAndNotLowEndDevice) {
+ SetEffectiveConnectionTypeForTest(
+ net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_3G);
+ EXPECT_TRUE(
+ coordinator()->SavePageLater(
+ kUrl1, kClientId1, kUserRequested,
+ RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER) != 0);
+ PumpLoop();
+
+ // Now whether processing triggered immediately depends on whether test
+ // is run on svelte device or not.
+ if (base::SysInfo::IsLowEndDevice()) {
+ EXPECT_FALSE(is_busy());
+ } else {
+ EXPECT_TRUE(is_busy());
+ }
+}
+
+TEST_F(RequestCoordinatorTest, SavePageDoesntStartProcessingWhenDisconnected) {
+ EXPECT_TRUE(
+ coordinator()->SavePageLater(
+ kUrl1, kClientId1, kUserRequested,
+ RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER) != 0);
+ PumpLoop();
+ EXPECT_FALSE(is_busy());
+}
+
+TEST_F(RequestCoordinatorTest,
+ SavePageDoesntStartProcessingWhenPoorlyConnected) {
+ SetEffectiveConnectionTypeForTest(
+ net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ EXPECT_TRUE(
+ coordinator()->SavePageLater(
+ kUrl1, kClientId1, kUserRequested,
+ RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER) != 0);
+ PumpLoop();
+ EXPECT_FALSE(is_busy());
+}
+
+TEST_F(RequestCoordinatorTest,
+ ResumeStartsProcessingWhenConnectedAndNotLowEndDevice) {
+
+ // Add a request to the queue.
+ offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1,
+ base::Time::Now(), kUserRequested);
+ coordinator()->queue()->AddRequest(
+ request1, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_FALSE(is_busy());
+
+ // Pause the request.
+ std::vector<int64_t> request_ids;
+ request_ids.push_back(kRequestId1);
+ coordinator()->PauseRequests(request_ids);
+ PumpLoop();
+
+ // Resume the request while disconnected.
+ coordinator()->ResumeRequests(request_ids);
+ PumpLoop();
+ EXPECT_FALSE(is_busy());
+
+ // Pause the request again.
+ coordinator()->PauseRequests(request_ids);
+ PumpLoop();
+
+ // Now simulate reasonable connection.
+ SetEffectiveConnectionTypeForTest(
+ net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_3G);
+
+ // Resume the request while connected.
+ coordinator()->ResumeRequests(request_ids);
+ EXPECT_FALSE(is_busy());
+ PumpLoop();
+
+ // Now whether processing triggered immediately depends on whether test
+ // is run on svelte device or not.
+ if (base::SysInfo::IsLowEndDevice()) {
+ EXPECT_FALSE(is_busy());
+ } else {
+ EXPECT_TRUE(is_busy());
+ }
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/request_notifier.h b/chromium/components/offline_pages/background/request_notifier.h
new file mode 100644
index 00000000000..7ed907dec95
--- /dev/null
+++ b/chromium/components/offline_pages/background/request_notifier.h
@@ -0,0 +1,44 @@
+// 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 COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_NOTIFIER_H_
+#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_NOTIFIER_H_
+
+namespace offline_pages {
+
+class SavePageRequest;
+
+class RequestNotifier {
+ public:
+ // Status to return for failed notifications.
+ // NOTE: for any changes to the enum, please also update related switch code
+ // in RequestCoordinatorEventLogger.
+ enum class BackgroundSavePageResult {
+ SUCCESS,
+ PRERENDER_FAILURE,
+ PRERENDER_CANCELED,
+ FOREGROUND_CANCELED,
+ SAVE_FAILED,
+ EXPIRED,
+ RETRY_COUNT_EXCEEDED,
+ START_COUNT_EXCEEDED,
+ REMOVED,
+ };
+
+ virtual ~RequestNotifier() = default;
+
+ // Notifies observers that |request| has been added.
+ virtual void NotifyAdded(const SavePageRequest& request) = 0;
+
+ // Notifies observers that |request| has been completed with |status|.
+ virtual void NotifyCompleted(const SavePageRequest& request,
+ BackgroundSavePageResult status) = 0;
+
+ // Notifies observers that |request| has been changed.
+ virtual void NotifyChanged(const SavePageRequest& request) = 0;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_NOTIFIER_H_
diff --git a/chromium/components/offline_pages/background/request_picker.cc b/chromium/components/offline_pages/background/request_picker.cc
index 665b39fee53..c1d27838165 100644
--- a/chromium/components/offline_pages/background/request_picker.cc
+++ b/chromium/components/offline_pages/background/request_picker.cc
@@ -8,40 +8,269 @@
#include "base/logging.h"
#include "components/offline_pages/background/save_page_request.h"
+namespace {
+template <typename T>
+int signum(T t) {
+ return (T(0) < t) - (t < T(0));
+}
+
+#define CALL_MEMBER_FUNCTION(object, ptrToMember) ((object)->*(ptrToMember))
+} // namespace
+
namespace offline_pages {
-RequestPicker::RequestPicker(
- RequestQueue* requestQueue)
+RequestPicker::RequestPicker(RequestQueue* requestQueue,
+ OfflinerPolicy* policy,
+ RequestNotifier* notifier,
+ RequestCoordinatorEventLogger* event_logger)
: queue_(requestQueue),
+ policy_(policy),
+ notifier_(notifier),
+ event_logger_(event_logger),
+ fewer_retries_better_(false),
+ earlier_requests_better_(false),
weak_ptr_factory_(this) {}
RequestPicker::~RequestPicker() {}
+// Entry point for the async operation to choose the next request.
void RequestPicker::ChooseNextRequest(
RequestCoordinator::RequestPickedCallback picked_callback,
- RequestCoordinator::RequestQueueEmptyCallback empty_callback) {
+ RequestCoordinator::RequestNotPickedCallback not_picked_callback,
+ DeviceConditions* device_conditions,
+ const std::set<int64_t>& disabled_requests) {
picked_callback_ = picked_callback;
- empty_callback_ = empty_callback;
+ not_picked_callback_ = not_picked_callback;
+ fewer_retries_better_ = policy_->ShouldPreferUntriedRequests();
+ earlier_requests_better_ = policy_->ShouldPreferEarlierRequests();
+ current_conditions_.reset(new DeviceConditions(*device_conditions));
// Get all requests from queue (there is no filtering mechanism).
queue_->GetRequests(base::Bind(&RequestPicker::GetRequestResultCallback,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(),
+ disabled_requests));
}
+// When we get contents from the queue, use them to pick the next
+// request to operate on (if any).
void RequestPicker::GetRequestResultCallback(
+ const std::set<int64_t>& disabled_requests,
RequestQueue::GetRequestsResult,
- const std::vector<SavePageRequest>& requests) {
+ std::vector<std::unique_ptr<SavePageRequest>> requests) {
// If there is nothing to do, return right away.
if (requests.size() == 0) {
- empty_callback_.Run();
+ not_picked_callback_.Run(false);
return;
}
+ // Get the expired requests to be removed from the queue, and the valid ones
+ // from which to pick the next request.
+ std::vector<std::unique_ptr<SavePageRequest>> valid_requests;
+ std::vector<std::unique_ptr<SavePageRequest>> expired_requests;
+ SplitRequests(std::move(requests), &valid_requests, &expired_requests);
+ std::vector<int64_t> expired_request_ids;
+ for (const auto& request : expired_requests)
+ expired_request_ids.push_back(request->request_id());
+
+ queue_->RemoveRequests(expired_request_ids,
+ base::Bind(&RequestPicker::OnRequestExpired,
+ weak_ptr_factory_.GetWeakPtr()));
+
// Pick the most deserving request for our conditions.
- const SavePageRequest& picked_request = requests[0];
+ const SavePageRequest* picked_request = nullptr;
+
+ RequestCompareFunction comparator = nullptr;
+
+ // Choose which comparison function to use based on policy.
+ if (policy_->RetryCountIsMoreImportantThanRecency())
+ comparator = &RequestPicker::RetryCountFirstCompareFunction;
+ else
+ comparator = &RequestPicker::RecencyFirstCompareFunction;
+
+ // Iterate once through the requests, keeping track of best candidate.
+ bool non_user_requested_tasks_remaining = false;
+ for (unsigned i = 0; i < valid_requests.size(); ++i) {
+ // If the request is on the disabled list, skip it.
+ auto search = disabled_requests.find(valid_requests[i]->request_id());
+ if (search != disabled_requests.end()) {
+ continue;
+ }
+ if (!valid_requests[i]->user_requested())
+ non_user_requested_tasks_remaining = true;
+ if (!RequestConditionsSatisfied(valid_requests[i].get()))
+ continue;
+ if (IsNewRequestBetter(picked_request, valid_requests[i].get(), comparator))
+ picked_request = valid_requests[i].get();
+ }
+
+ // If we have a best request to try next, get the request coodinator to
+ // start it. Otherwise return that we have no candidates.
+ if (picked_request != nullptr) {
+ picked_callback_.Run(*picked_request);
+ } else {
+ not_picked_callback_.Run(non_user_requested_tasks_remaining);
+ }
+}
+
+// Filter out requests that don't meet the current conditions. For instance, if
+// this is a predictive request, and we are not on WiFi, it should be ignored
+// this round.
+bool RequestPicker::RequestConditionsSatisfied(const SavePageRequest* request) {
+ // If the user did not request the page directly, make sure we are connected
+ // to power and have WiFi and sufficient battery remaining before we take this
+ // request.
+
+ if (!current_conditions_->IsPowerConnected() &&
+ policy_->PowerRequired(request->user_requested())) {
+ return false;
+ }
+
+ if (current_conditions_->GetNetConnectionType() !=
+ net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI &&
+ policy_->UnmeteredNetworkRequired(request->user_requested())) {
+ return false;
+ }
+
+ if (current_conditions_->GetBatteryPercentage() <
+ policy_->BatteryPercentageRequired(request->user_requested())) {
+ return false;
+ }
+
+ // If we have already started this page the max number of times, it is not
+ // eligible to try again.
+ if (request->started_attempt_count() >= policy_->GetMaxStartedTries())
+ return false;
+
+ // If we have already completed trying this page the max number of times, it
+ // is not eligible to try again.
+ if (request->completed_attempt_count() >= policy_->GetMaxCompletedTries())
+ return false;
+
+ // If the request is paused, do not consider it.
+ if (request->request_state() == SavePageRequest::RequestState::PAUSED)
+ return false;
+
+ // If the request is expired, do not consider it.
+ base::TimeDelta requestAge = base::Time::Now() - request->creation_time();
+ if (requestAge >
+ base::TimeDelta::FromSeconds(
+ policy_->GetRequestExpirationTimeInSeconds()))
+ return false;
+
+ // If this request is not active yet, return false.
+ // TODO(petewil): If the only reason we return nothing to do is that we have
+ // inactive requests, we still want to try again later after their activation
+ // time elapses, we shouldn't take ourselves completely off the scheduler.
+ if (request->activation_time() > base::Time::Now())
+ return false;
+
+ return true;
+}
+
+// Look at policies to decide which requests to prefer.
+bool RequestPicker::IsNewRequestBetter(const SavePageRequest* oldRequest,
+ const SavePageRequest* newRequest,
+ RequestCompareFunction comparator) {
- // When we have a best request to try next, get the request coodinator to
- // start it.
- picked_callback_.Run(picked_request);
+ // If there is no old request, the new one is better.
+ if (oldRequest == nullptr)
+ return true;
+
+ // User requested pages get priority.
+ if (newRequest->user_requested() && !oldRequest->user_requested())
+ return true;
+
+ // Otherwise, use the comparison function for the current policy, which
+ // returns true if the older request is better.
+ return !(CALL_MEMBER_FUNCTION(this, comparator)(oldRequest, newRequest));
+}
+
+// Compare the results, checking request count before recency. Returns true if
+// left hand side is better, false otherwise.
+bool RequestPicker::RetryCountFirstCompareFunction(
+ const SavePageRequest* left, const SavePageRequest* right) {
+ // Check the attempt count.
+ int result = CompareRetryCount(left, right);
+
+ if (result != 0)
+ return (result > 0);
+
+ // If we get here, the attempt counts were the same, so check recency.
+ result = CompareCreationTime(left, right);
+
+ return (result > 0);
+}
+
+// Compare the results, checking recency before request count. Returns true if
+// left hand side is better, false otherwise.
+bool RequestPicker::RecencyFirstCompareFunction(
+ const SavePageRequest* left, const SavePageRequest* right) {
+ // Check the recency.
+ int result = CompareCreationTime(left, right);
+
+ if (result != 0)
+ return (result > 0);
+
+ // If we get here, the recency was the same, so check the attempt count.
+ result = CompareRetryCount(left, right);
+
+ return (result > 0);
+}
+
+// Compare left and right side, returning 1 if the left side is better
+// (preferred by policy), 0 if the same, and -1 if the right side is better.
+int RequestPicker::CompareRetryCount(
+ const SavePageRequest* left, const SavePageRequest* right) {
+ // Check the attempt count.
+ int result = signum(left->completed_attempt_count() -
+ right->completed_attempt_count());
+
+ // Flip the direction of comparison if policy prefers fewer retries.
+ if (fewer_retries_better_)
+ result *= -1;
+
+ return result;
+}
+
+// Compare left and right side, returning 1 if the left side is better
+// (preferred by policy), 0 if the same, and -1 if the right side is better.
+int RequestPicker::CompareCreationTime(
+ const SavePageRequest* left, const SavePageRequest* right) {
+ // Check the recency.
+ base::TimeDelta difference = left->creation_time() - right->creation_time();
+ int result = signum(difference.InMilliseconds());
+
+ // Flip the direction of comparison if policy prefers fewer retries.
+ if (earlier_requests_better_)
+ result *= -1;
+
+ return result;
+}
+
+void RequestPicker::SplitRequests(
+ std::vector<std::unique_ptr<SavePageRequest>> requests,
+ std::vector<std::unique_ptr<SavePageRequest>>* valid_requests,
+ std::vector<std::unique_ptr<SavePageRequest>>* expired_requests) {
+ for (auto& request : requests) {
+ if (base::Time::Now() - request->creation_time() >=
+ base::TimeDelta::FromSeconds(kRequestExpirationTimeInSeconds)) {
+ expired_requests->push_back(std::move(request));
+ } else {
+ valid_requests->push_back(std::move(request));
+ }
+ }
+}
+
+// Callback used after expired requests are deleted from the queue and notifies
+// the coordinator.
+void RequestPicker::OnRequestExpired(
+ std::unique_ptr<UpdateRequestsResult> result) {
+ const RequestCoordinator::BackgroundSavePageResult save_page_result(
+ RequestCoordinator::BackgroundSavePageResult::EXPIRED);
+ for (const auto& request : result->updated_items) {
+ event_logger_->RecordDroppedSavePageRequest(
+ request.client_id().name_space, save_page_result, request.request_id());
+ notifier_->NotifyCompleted(request, save_page_result);
+ }
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/request_picker.h b/chromium/components/offline_pages/background/request_picker.h
index dd2b7ff295a..d07dd80be6f 100644
--- a/chromium/components/offline_pages/background/request_picker.h
+++ b/chromium/components/offline_pages/background/request_picker.h
@@ -5,14 +5,29 @@
#ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_PICKER_H_
#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_PICKER_H_
+#include <memory>
+#include <set>
+
#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/background/device_conditions.h"
+#include "components/offline_pages/background/offliner_policy.h"
#include "components/offline_pages/background/request_coordinator.h"
+#include "components/offline_pages/background/request_coordinator_event_logger.h"
#include "components/offline_pages/background/request_queue.h"
namespace offline_pages {
+
+class RequestNotifier;
+
+typedef bool (RequestPicker::*RequestCompareFunction)(
+ const SavePageRequest* left, const SavePageRequest* right);
+
class RequestPicker {
public:
- RequestPicker(RequestQueue* requestQueue);
+ RequestPicker(RequestQueue* requestQueue,
+ OfflinerPolicy* policy,
+ RequestNotifier* notifier,
+ RequestCoordinatorEventLogger* event_logger);
~RequestPicker();
@@ -20,19 +35,72 @@ class RequestPicker {
// conditions, and call back to the RequestCoordinator when we have one.
void ChooseNextRequest(
RequestCoordinator::RequestPickedCallback picked_callback,
- RequestCoordinator::RequestQueueEmptyCallback empty_callback);
+ RequestCoordinator::RequestNotPickedCallback not_picked_callback,
+ DeviceConditions* device_conditions,
+ const std::set<int64_t>& disabled_requests);
private:
// Callback for the GetRequest results to be delivered.
- void GetRequestResultCallback(RequestQueue::GetRequestsResult result,
- const std::vector<SavePageRequest>& results);
+ void GetRequestResultCallback(
+ const std::set<int64_t>& disabled_requests,
+ RequestQueue::GetRequestsResult result,
+ std::vector<std::unique_ptr<SavePageRequest>> results);
+
+ // Filter out requests that don't meet the current conditions. For instance,
+ // if this is a predictive request, and we are not on WiFi, it should be
+ // ignored this round.
+ bool RequestConditionsSatisfied(const SavePageRequest* request);
+
+ // Using policies, decide if the new request is preferable to the best we have
+ // so far.
+ bool IsNewRequestBetter(const SavePageRequest* oldRequest,
+ const SavePageRequest* newRequest,
+ RequestCompareFunction comparator);
+
+ // Is the new request preferable from the retry count first standpoint?
+ bool RetryCountFirstCompareFunction(const SavePageRequest* left,
+ const SavePageRequest* right);
+
+ // Is the new request better from the recency first standpoint?
+ bool RecencyFirstCompareFunction(const SavePageRequest* left,
+ const SavePageRequest* right);
+
+ // Does the new request have better retry count?
+ int CompareRetryCount(const SavePageRequest* left,
+ const SavePageRequest* right);
+
+ // Does the new request have better creation time?
+ int CompareCreationTime(const SavePageRequest* left,
+ const SavePageRequest* right);
+
+ // Split all requests into expired ones and still valid ones. Takes ownership
+ // of the requests, and moves them into either valid or expired requests.
+ void SplitRequests(
+ std::vector<std::unique_ptr<SavePageRequest>> requests,
+ std::vector<std::unique_ptr<SavePageRequest>>* valid_requests,
+ std::vector<std::unique_ptr<SavePageRequest>>* expired_requests);
+
+ // Callback used after requests get expired.
+ void OnRequestExpired(std::unique_ptr<UpdateRequestsResult> result);
- // unowned pointer to the request queue.
+ // Unowned pointer to the request queue.
RequestQueue* queue_;
+ // Unowned pointer to the policy object.
+ OfflinerPolicy* policy_;
+ // Unowned pointer to the request coordinator.
+ RequestNotifier* notifier_;
+ // Unowned pointer to the event logger.
+ RequestCoordinatorEventLogger* event_logger_;
+ // Current conditions on the device
+ std::unique_ptr<DeviceConditions> current_conditions_;
+ // True if we prefer less-tried requests
+ bool fewer_retries_better_;
+ // True if we prefer requests submitted more recently
+ bool earlier_requests_better_;
// Callback for when we are done picking a request to do next.
RequestCoordinator::RequestPickedCallback picked_callback_;
// Callback for when there are no more reqeusts to pick.
- RequestCoordinator::RequestQueueEmptyCallback empty_callback_;
+ RequestCoordinator::RequestNotPickedCallback not_picked_callback_;
// Allows us to pass a weak pointer to callbacks.
base::WeakPtrFactory<RequestPicker> weak_ptr_factory_;
};
diff --git a/chromium/components/offline_pages/background/request_picker_unittest.cc b/chromium/components/offline_pages/background/request_picker_unittest.cc
index 10824507d75..f71b406460e 100644
--- a/chromium/components/offline_pages/background/request_picker_unittest.cc
+++ b/chromium/components/offline_pages/background/request_picker_unittest.cc
@@ -8,6 +8,10 @@
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "components/offline_pages/background/device_conditions.h"
+#include "components/offline_pages/background/offliner_factory.h"
+#include "components/offline_pages/background/offliner_policy.h"
+#include "components/offline_pages/background/request_notifier.h"
#include "components/offline_pages/background/request_queue.h"
#include "components/offline_pages/background/request_queue_in_memory_store.h"
#include "components/offline_pages/background/save_page_request.h"
@@ -25,8 +29,56 @@ const ClientId kClientId1("bookmark", "1234");
const int64_t kRequestId2 = 42;
const GURL kUrl2("http://nytimes.com");
const ClientId kClientId2("bookmark", "5678");
+const bool kUserRequested = true;
+const int kAttemptCount = 1;
+const int kMaxStartedTries = 5;
+const int kMaxCompletedTries = 1;
+
+// Constants for policy values - These settings represent the default values.
+const bool kPreferUntried = false;
+const bool kPreferEarlier = true;
+const bool kPreferRetryCount = true;
+
+// Default request
+const SavePageRequest kEmptyRequest(0UL,
+ GURL(""),
+ ClientId("", ""),
+ base::Time(),
+ true);
} // namespace
+class RequestNotifierStub : public RequestNotifier {
+ public:
+ RequestNotifierStub()
+ : last_expired_request_(kEmptyRequest), total_expired_requests_(0) {}
+
+ void NotifyAdded(const SavePageRequest& request) override {}
+ void NotifyChanged(const SavePageRequest& request) override {}
+
+ void NotifyCompleted(const SavePageRequest& request,
+ BackgroundSavePageResult status) override {
+ last_expired_request_ = request;
+ last_request_expiration_status_ = status;
+ total_expired_requests_++;
+ }
+
+ const SavePageRequest& last_expired_request() {
+ return last_expired_request_;
+ }
+
+ RequestCoordinator::BackgroundSavePageResult
+ last_request_expiration_status() {
+ return last_request_expiration_status_;
+ }
+
+ int32_t total_expired_requests() { return total_expired_requests_; }
+
+ private:
+ BackgroundSavePageResult last_request_expiration_status_;
+ SavePageRequest last_expired_request_;
+ int32_t total_expired_requests_;
+};
+
class RequestPickerTest : public testing::Test {
public:
RequestPickerTest();
@@ -42,15 +94,23 @@ class RequestPickerTest : public testing::Test {
void RequestPicked(const SavePageRequest& request);
- void RequestQueueEmpty();
+ void RequestNotPicked(const bool non_user_requested_tasks_remaining);
+
+ void QueueRequestsAndChooseOne(const SavePageRequest& request1,
+ const SavePageRequest& request2);
+
+ RequestNotifierStub* GetNotifier() { return notifier_.get(); }
protected:
// The request queue is simple enough we will use a real queue with a memory
// store instead of a stub.
std::unique_ptr<RequestQueue> queue_;
std::unique_ptr<RequestPicker> picker_;
+ std::unique_ptr<RequestNotifierStub> notifier_;
std::unique_ptr<SavePageRequest> last_picked_;
- bool request_queue_empty_called_;
+ std::unique_ptr<OfflinerPolicy> policy_;
+ RequestCoordinatorEventLogger event_logger_;
+ bool request_queue_not_picked_called_;
private:
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
@@ -67,8 +127,11 @@ void RequestPickerTest::SetUp() {
std::unique_ptr<RequestQueueInMemoryStore> store(
new RequestQueueInMemoryStore());
queue_.reset(new RequestQueue(std::move(store)));
- picker_.reset(new RequestPicker(queue_.get()));
- request_queue_empty_called_ = false;
+ policy_.reset(new OfflinerPolicy());
+ notifier_.reset(new RequestNotifierStub());
+ picker_.reset(new RequestPicker(queue_.get(), policy_.get(), notifier_.get(),
+ &event_logger_));
+ request_queue_not_picked_called_ = false;
}
void RequestPickerTest::PumpLoop() {
@@ -82,15 +145,18 @@ void RequestPickerTest::RequestPicked(const SavePageRequest& request) {
last_picked_.reset(new SavePageRequest(request));
}
-void RequestPickerTest::RequestQueueEmpty() {
- request_queue_empty_called_ = true;
+void RequestPickerTest::RequestNotPicked(
+ const bool non_user_requested_tasks_remaining) {
+ request_queue_not_picked_called_ = true;
}
-TEST_F(RequestPickerTest, ChooseNextRequest) {
- base::Time creation_time = base::Time::Now();
- SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time);
- SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time);
- // Put some test requests on the Queue.
+// Test helper to queue the two given requests and then pick one of them per
+// configured policy.
+void RequestPickerTest::QueueRequestsAndChooseOne(
+ const SavePageRequest& request1, const SavePageRequest& request2) {
+ DeviceConditions conditions;
+ std::set<int64_t> disabled_requests;
+ // Add test requests on the Queue.
queue_->AddRequest(request1, base::Bind(&RequestPickerTest::AddRequestDone,
base::Unretained(this)));
queue_->AddRequest(request2, base::Bind(&RequestPickerTest::AddRequestDone,
@@ -99,32 +165,257 @@ TEST_F(RequestPickerTest, ChooseNextRequest) {
// Pump the loop to give the async queue the opportunity to do the adds.
PumpLoop();
+ // Call the method under test.
picker_->ChooseNextRequest(
base::Bind(&RequestPickerTest::RequestPicked, base::Unretained(this)),
- base::Bind(&RequestPickerTest::RequestQueueEmpty,
- base::Unretained(this)));
+ base::Bind(&RequestPickerTest::RequestNotPicked, base::Unretained(this)),
+ &conditions, disabled_requests);
// Pump the loop again to give the async queue the opportunity to return
// results from the Get operation, and for the picker to call the "picked"
// callback.
PumpLoop();
-
- EXPECT_EQ(kRequestId1, last_picked_->request_id());
- EXPECT_FALSE(request_queue_empty_called_);
}
TEST_F(RequestPickerTest, PickFromEmptyQueue) {
+ DeviceConditions conditions;
+ std::set<int64_t> disabled_requests;
picker_->ChooseNextRequest(
base::Bind(&RequestPickerTest::RequestPicked, base::Unretained(this)),
- base::Bind(&RequestPickerTest::RequestQueueEmpty,
- base::Unretained(this)));
+ base::Bind(&RequestPickerTest::RequestNotPicked, base::Unretained(this)),
+ &conditions, disabled_requests);
// Pump the loop again to give the async queue the opportunity to return
// results from the Get operation, and for the picker to call the "QueueEmpty"
// callback.
PumpLoop();
- EXPECT_TRUE(request_queue_empty_called_);
+ EXPECT_TRUE(request_queue_not_picked_called_);
+}
+
+TEST_F(RequestPickerTest, ChooseRequestWithHigherRetryCount) {
+ policy_.reset(new OfflinerPolicy(kPreferUntried, kPreferEarlier,
+ kPreferRetryCount, kMaxStartedTries,
+ kMaxCompletedTries + 1));
+ picker_.reset(new RequestPicker(queue_.get(), policy_.get(), notifier_.get(),
+ &event_logger_));
+
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request1(
+ kRequestId1, kUrl1, kClientId1, creation_time, kUserRequested);
+ SavePageRequest request2(
+ kRequestId2, kUrl2, kClientId2, creation_time, kUserRequested);
+ request2.set_completed_attempt_count(kAttemptCount);
+
+ QueueRequestsAndChooseOne(request1, request2);
+
+ EXPECT_EQ(kRequestId2, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+}
+
+TEST_F(RequestPickerTest, ChooseRequestWithSameRetryCountButEarlier) {
+ base::Time creation_time1 =
+ base::Time::Now() - base::TimeDelta::FromSeconds(10);
+ base::Time creation_time2 = base::Time::Now();
+ SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time1,
+ kUserRequested);
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time2,
+ kUserRequested);
+
+ QueueRequestsAndChooseOne(request1, request2);
+
+ EXPECT_EQ(kRequestId1, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+}
+
+TEST_F(RequestPickerTest, ChooseEarlierRequest) {
+ // We need a custom policy object prefering recency to retry count.
+ policy_.reset(new OfflinerPolicy(kPreferUntried, kPreferEarlier,
+ !kPreferRetryCount, kMaxStartedTries,
+ kMaxCompletedTries));
+ picker_.reset(new RequestPicker(queue_.get(), policy_.get(), notifier_.get(),
+ &event_logger_));
+
+ base::Time creation_time1 =
+ base::Time::Now() - base::TimeDelta::FromSeconds(10);
+ base::Time creation_time2 = base::Time::Now();
+ SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time1,
+ kUserRequested);
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time2,
+ kUserRequested);
+ request2.set_completed_attempt_count(kAttemptCount);
+
+ QueueRequestsAndChooseOne(request1, request2);
+
+ EXPECT_EQ(kRequestId1, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+}
+
+TEST_F(RequestPickerTest, ChooseSameTimeRequestWithHigherRetryCount) {
+ // We need a custom policy object preferring recency to retry count.
+ policy_.reset(new OfflinerPolicy(kPreferUntried, kPreferEarlier,
+ !kPreferRetryCount, kMaxStartedTries,
+ kMaxCompletedTries + 1));
+ picker_.reset(new RequestPicker(queue_.get(), policy_.get(), notifier_.get(),
+ &event_logger_));
+
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time,
+ kUserRequested);
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
+ kUserRequested);
+ request2.set_completed_attempt_count(kAttemptCount);
+
+ QueueRequestsAndChooseOne(request1, request2);
+
+ EXPECT_EQ(kRequestId2, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+}
+
+TEST_F(RequestPickerTest, ChooseRequestWithLowerRetryCount) {
+ // We need a custom policy object preferring lower retry count.
+ policy_.reset(new OfflinerPolicy(!kPreferUntried, kPreferEarlier,
+ kPreferRetryCount, kMaxStartedTries,
+ kMaxCompletedTries + 1));
+ picker_.reset(new RequestPicker(queue_.get(), policy_.get(), notifier_.get(),
+ &event_logger_));
+
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time,
+ kUserRequested);
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
+ kUserRequested);
+ request2.set_completed_attempt_count(kAttemptCount);
+
+ QueueRequestsAndChooseOne(request1, request2);
+
+ EXPECT_EQ(kRequestId1, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
}
+TEST_F(RequestPickerTest, ChooseLaterRequest) {
+ // We need a custom policy preferring recency over retry, and later requests.
+ policy_.reset(new OfflinerPolicy(kPreferUntried, !kPreferEarlier,
+ !kPreferRetryCount, kMaxStartedTries,
+ kMaxCompletedTries));
+ picker_.reset(new RequestPicker(queue_.get(), policy_.get(), notifier_.get(),
+ &event_logger_));
+
+ base::Time creation_time1 =
+ base::Time::Now() - base::TimeDelta::FromSeconds(10);
+ base::Time creation_time2 = base::Time::Now();
+ SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time1,
+ kUserRequested);
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time2,
+ kUserRequested);
+
+ QueueRequestsAndChooseOne(request1, request2);
+
+ EXPECT_EQ(kRequestId2, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+}
+
+TEST_F(RequestPickerTest, ChooseNonExpiredRequest) {
+ base::Time creation_time = base::Time::Now();
+ base::Time expired_time =
+ creation_time - base::TimeDelta::FromSeconds(
+ policy_->GetRequestExpirationTimeInSeconds() + 60);
+ SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time,
+ kUserRequested);
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, expired_time,
+ kUserRequested);
+
+ QueueRequestsAndChooseOne(request1, request2);
+
+ PumpLoop();
+
+ EXPECT_EQ(kRequestId1, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+ EXPECT_EQ(kRequestId2, GetNotifier()->last_expired_request().request_id());
+ EXPECT_EQ(RequestNotifier::BackgroundSavePageResult::EXPIRED,
+ GetNotifier()->last_request_expiration_status());
+ EXPECT_EQ(1, GetNotifier()->total_expired_requests());
+}
+
+TEST_F(RequestPickerTest, ChooseRequestThatHasNotExceededStartLimit) {
+ base::Time creation_time1 =
+ base::Time::Now() - base::TimeDelta::FromSeconds(1);
+ base::Time creation_time2 = base::Time::Now();
+ SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time1,
+ kUserRequested);
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time2,
+ kUserRequested);
+
+ // With default policy settings, we should choose the earlier request.
+ // However, we will make the earlier reqeust exceed the limit.
+ request1.set_started_attempt_count(policy_->GetMaxStartedTries());
+
+ QueueRequestsAndChooseOne(request1, request2);
+
+ EXPECT_EQ(kRequestId2, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+}
+
+TEST_F(RequestPickerTest, ChooseRequestThatHasNotExceededCompletionLimit) {
+ base::Time creation_time1 =
+ base::Time::Now() - base::TimeDelta::FromSeconds(1);
+ base::Time creation_time2 = base::Time::Now();
+ SavePageRequest request1(kRequestId1, kUrl1, kClientId1, creation_time1,
+ kUserRequested);
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time2,
+ kUserRequested);
+
+ // With default policy settings, we should choose the earlier request.
+ // However, we will make the earlier reqeust exceed the limit.
+ request1.set_completed_attempt_count(policy_->GetMaxCompletedTries());
+
+ QueueRequestsAndChooseOne(request1, request2);
+
+ EXPECT_EQ(kRequestId2, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+}
+
+
+TEST_F(RequestPickerTest, ChooseRequestThatIsNotDisabled) {
+ policy_.reset(new OfflinerPolicy(kPreferUntried, kPreferEarlier,
+ kPreferRetryCount, kMaxStartedTries,
+ kMaxCompletedTries + 1));
+ picker_.reset(new RequestPicker(queue_.get(), policy_.get(), notifier_.get(),
+ &event_logger_));
+
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request1(
+ kRequestId1, kUrl1, kClientId1, creation_time, kUserRequested);
+ SavePageRequest request2(
+ kRequestId2, kUrl2, kClientId2, creation_time, kUserRequested);
+ request2.set_completed_attempt_count(kAttemptCount);
+
+ // put request 2 on disabled list, ensure request1 picked instead,
+ // even though policy would prefer 2.
+ std::set<int64_t> disabled_requests {kRequestId2};
+ DeviceConditions conditions;
+
+ // Add test requests on the Queue.
+ queue_->AddRequest(request1, base::Bind(&RequestPickerTest::AddRequestDone,
+ base::Unretained(this)));
+ queue_->AddRequest(request2, base::Bind(&RequestPickerTest::AddRequestDone,
+ base::Unretained(this)));
+
+ // Pump the loop to give the async queue the opportunity to do the adds.
+ PumpLoop();
+
+ // Call the method under test.
+ picker_->ChooseNextRequest(
+ base::Bind(&RequestPickerTest::RequestPicked, base::Unretained(this)),
+ base::Bind(&RequestPickerTest::RequestNotPicked, base::Unretained(this)),
+ &conditions, disabled_requests);
+
+ // Pump the loop again to give the async queue the opportunity to return
+ // results from the Get operation, and for the picker to call the "picked"
+ // callback.
+ PumpLoop();
+
+ EXPECT_EQ(kRequestId1, last_picked_->request_id());
+ EXPECT_FALSE(request_queue_not_picked_called_);
+}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/request_queue.cc b/chromium/components/offline_pages/background/request_queue.cc
index 5fbd0baeda5..b491824edeb 100644
--- a/chromium/components/offline_pages/background/request_queue.cc
+++ b/chromium/components/offline_pages/background/request_queue.cc
@@ -7,6 +7,8 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/background/change_requests_state_task.h"
+#include "components/offline_pages/background/remove_requests_task.h"
#include "components/offline_pages/background/request_queue_store.h"
#include "components/offline_pages/background/save_page_request.h"
@@ -16,7 +18,7 @@ namespace {
// Completes the get requests call.
void GetRequestsDone(const RequestQueue::GetRequestsCallback& callback,
bool success,
- const std::vector<SavePageRequest>& requests) {
+ std::vector<std::unique_ptr<SavePageRequest>> requests) {
RequestQueue::GetRequestsResult result =
success ? RequestQueue::GetRequestsResult::SUCCESS
: RequestQueue::GetRequestsResult::STORE_FAILURE;
@@ -24,34 +26,58 @@ void GetRequestsDone(const RequestQueue::GetRequestsCallback& callback,
// This may trigger the purging if necessary.
// Also this may be turned into a method on the request queue or add a policy
// parameter in the process.
- callback.Run(result, requests);
+ callback.Run(result, std::move(requests));
}
// Completes the add request call.
void AddRequestDone(const RequestQueue::AddRequestCallback& callback,
const SavePageRequest& request,
- RequestQueueStore::UpdateStatus status) {
- RequestQueue::AddRequestResult result =
- (status == RequestQueueStore::UpdateStatus::UPDATED)
- ? RequestQueue::AddRequestResult::SUCCESS
- : RequestQueue::AddRequestResult::STORE_FAILURE;
+ ItemActionStatus status) {
+ RequestQueue::AddRequestResult result;
+ switch (status) {
+ case ItemActionStatus::SUCCESS:
+ result = RequestQueue::AddRequestResult::SUCCESS;
+ break;
+ case ItemActionStatus::ALREADY_EXISTS:
+ result = RequestQueue::AddRequestResult::ALREADY_EXISTS;
+ break;
+ case ItemActionStatus::STORE_ERROR:
+ result = RequestQueue::AddRequestResult::STORE_FAILURE;
+ break;
+ case ItemActionStatus::NOT_FOUND:
+ default:
+ NOTREACHED();
+ return;
+ }
callback.Run(result, request);
}
-// Completes the remove request call.
-void RemoveRequestDone(const RequestQueue::UpdateRequestCallback& callback,
- bool success,
- int deleted_requests_count) {
- DCHECK_EQ(1, deleted_requests_count);
- RequestQueue::UpdateRequestResult result =
- success ? RequestQueue::UpdateRequestResult::SUCCESS
- : RequestQueue::UpdateRequestResult::STORE_FAILURE;
+// Completes the update request call.
+// TODO(fgorski): For specific cases, check that appropriate items were updated.
+void UpdateRequestsDone(const RequestQueue::UpdateRequestCallback& callback,
+ std::unique_ptr<UpdateRequestsResult> store_result) {
+ RequestQueue::UpdateRequestResult result;
+ if (store_result->store_state != StoreState::LOADED) {
+ result = RequestQueue::UpdateRequestResult::STORE_FAILURE;
+ } else if (store_result->item_statuses.size() == 0) {
+ result = RequestQueue::UpdateRequestResult::REQUEST_DOES_NOT_EXIST;
+ } else {
+ ItemActionStatus status = store_result->item_statuses.begin()->second;
+ if (status == ItemActionStatus::STORE_ERROR)
+ result = RequestQueue::UpdateRequestResult::STORE_FAILURE;
+ else if (status == ItemActionStatus::NOT_FOUND)
+ result = RequestQueue::UpdateRequestResult::REQUEST_DOES_NOT_EXIST;
+ else
+ result = RequestQueue::UpdateRequestResult::SUCCESS;
+ }
+
callback.Run(result);
}
+
} // namespace
RequestQueue::RequestQueue(std::unique_ptr<RequestQueueStore> store)
- : store_(std::move(store)) {}
+ : store_(std::move(store)), weak_ptr_factory_(this) {}
RequestQueue::~RequestQueue() {}
@@ -63,17 +89,74 @@ void RequestQueue::AddRequest(const SavePageRequest& request,
const AddRequestCallback& callback) {
// TODO(fgorski): check that request makes sense.
// TODO(fgorski): check that request does not violate policy.
- store_->AddOrUpdateRequest(request,
- base::Bind(&AddRequestDone, callback, request));
+ store_->AddRequest(request, base::Bind(&AddRequestDone, callback, request));
+}
+
+void RequestQueue::UpdateRequest(const SavePageRequest& update_request,
+ const UpdateRequestCallback& update_callback) {
+ // We have to pass the update_callback *through* the get callback. We do this
+ // by currying the update_callback as a parameter to be used when calling
+ // GetForUpdateDone. The actual request queue store get operation will not
+ // see this bound parameter, but just pass it along. GetForUpdateDone then
+ // passes it into the UpdateRequests method, where it ends up calling back
+ // to the request queue client.
+ // TODO(petewil): This would be more efficient if the store supported a call
+ // to get a single item by ID. Change this code to use that API when added.
+ // crbug.com/630657.
+ store_->GetRequests(base::Bind(
+ &RequestQueue::GetForUpdateDone, weak_ptr_factory_.GetWeakPtr(),
+ update_callback, update_request));
}
-void RequestQueue::UpdateRequest(const SavePageRequest& request,
- const UpdateRequestCallback& callback) {}
+// We need a different version of the GetCallback that can take the curried
+// update_callback as a parameter, and call back into the request queue store
+// implementation. This must be a member function because we need access to
+// the store pointer to call UpdateRequests.
+void RequestQueue::GetForUpdateDone(
+ const UpdateRequestCallback& update_callback,
+ const SavePageRequest& update_request,
+ bool success,
+ std::vector<std::unique_ptr<SavePageRequest>> found_requests) {
+ // If the result was not found, return now.
+ if (!success) {
+ update_callback.Run(
+ RequestQueue::UpdateRequestResult::REQUEST_DOES_NOT_EXIST);
+ return;
+ }
+ // If the found result does not contain the request we are looking for, return
+ // now.
+ bool found = false;
+ std::vector<std::unique_ptr<SavePageRequest>>::const_iterator iter;
+ for (iter = found_requests.begin(); iter != found_requests.end(); ++iter) {
+ if ((*iter)->request_id() == update_request.request_id())
+ found = true;
+ }
+ if (!found) {
+ update_callback.Run(
+ RequestQueue::UpdateRequestResult::REQUEST_DOES_NOT_EXIST);
+ return;
+ }
+
+ // Since the request exists, update it.
+ std::vector<SavePageRequest> update_requests{update_request};
+ store_->UpdateRequests(update_requests,
+ base::Bind(&UpdateRequestsDone, update_callback));
+}
+
+void RequestQueue::RemoveRequests(const std::vector<int64_t>& request_ids,
+ const UpdateCallback& callback) {
+ std::unique_ptr<Task> task(
+ new RemoveRequestsTask(store_.get(), request_ids, callback));
+ task_queue_.AddTask(std::move(task));
+}
-void RequestQueue::RemoveRequest(int64_t request_id,
- const UpdateRequestCallback& callback) {
- std::vector<int64_t> request_ids{request_id};
- store_->RemoveRequests(request_ids, base::Bind(RemoveRequestDone, callback));
+void RequestQueue::ChangeRequestsState(
+ const std::vector<int64_t>& request_ids,
+ const SavePageRequest::RequestState new_state,
+ const RequestQueue::UpdateCallback& callback) {
+ std::unique_ptr<Task> task(new ChangeRequestsStateTask(
+ store_.get(), request_ids, new_state, callback));
+ task_queue_.AddTask(std::move(task));
}
void RequestQueue::PurgeRequests(const PurgeRequestsCallback& callback) {}
diff --git a/chromium/components/offline_pages/background/request_queue.h b/chromium/components/offline_pages/background/request_queue.h
index 4aed02cab75..988038fc6aa 100644
--- a/chromium/components/offline_pages/background/request_queue.h
+++ b/chromium/components/offline_pages/background/request_queue.h
@@ -8,15 +8,21 @@
#include <stdint.h>
#include <memory>
+#include <string>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/background/save_page_request.h"
+#include "components/offline_pages/core/task_queue.h"
+#include "components/offline_pages/offline_page_item.h"
+#include "components/offline_pages/offline_store_types.h"
namespace offline_pages {
class RequestQueueStore;
-class SavePageRequest;
+typedef StoreUpdateResult<SavePageRequest> UpdateRequestsResult;
// Class responsible for managing save page requests.
class RequestQueue {
@@ -29,10 +35,12 @@ class RequestQueue {
enum class AddRequestResult {
SUCCESS,
STORE_FAILURE,
+ ALREADY_EXISTS,
REQUEST_QUOTA_HIT, // Cannot add a request with this namespace, as it has
// reached a quota of active requests.
};
+ // GENERATED_JAVA_ENUM_PACKAGE:org.chromium.components.offlinepages.background
enum class UpdateRequestResult {
SUCCESS,
STORE_FAILURE,
@@ -42,14 +50,18 @@ class RequestQueue {
// Callback used for |GetRequests|.
typedef base::Callback<void(GetRequestsResult,
- const std::vector<SavePageRequest>&)>
+ std::vector<std::unique_ptr<SavePageRequest>>)>
GetRequestsCallback;
// Callback used for |AddRequest|.
typedef base::Callback<void(AddRequestResult, const SavePageRequest& request)>
AddRequestCallback;
- // Callback used by |UdpateRequest| and |RemoveRequest|.
+ // Callback used by |ChangeRequestsState|.
+ typedef base::Callback<void(std::unique_ptr<UpdateRequestsResult>)>
+ UpdateCallback;
+
+ // Callback used by |UdpateRequest|.
typedef base::Callback<void(UpdateRequestResult)> UpdateRequestCallback;
explicit RequestQueue(std::unique_ptr<RequestQueueStore> store);
@@ -71,9 +83,23 @@ class RequestQueue {
void UpdateRequest(const SavePageRequest& request,
const UpdateRequestCallback& callback);
- // Removes the request matching the |request_id|. Result is returned through
- // |callback|.
- void RemoveRequest(int64_t request_id, const UpdateRequestCallback& callback);
+ // Removes the requests matching the |request_ids|. Result is returned through
+ // |callback|. If a request id cannot be removed, this will still remove the
+ // others.
+ void RemoveRequests(const std::vector<int64_t>& request_ids,
+ const UpdateCallback& callback);
+
+ // Changes the state to |new_state| for requests matching the
+ // |request_ids|. Results are returned through |callback|.
+ void ChangeRequestsState(const std::vector<int64_t>& request_ids,
+ const SavePageRequest::RequestState new_state,
+ const UpdateCallback& callback);
+
+ void GetForUpdateDone(
+ const RequestQueue::UpdateRequestCallback& update_callback,
+ const SavePageRequest& update_request,
+ bool success,
+ std::vector<std::unique_ptr<SavePageRequest>> requests);
private:
// Callback used by |PurgeRequests|.
@@ -88,6 +114,12 @@ class RequestQueue {
std::unique_ptr<RequestQueueStore> store_;
+ // Task queue to serialize store access.
+ TaskQueue task_queue_;
+
+ // Allows us to pass a weak pointer to callbacks.
+ base::WeakPtrFactory<RequestQueue> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(RequestQueue);
};
diff --git a/chromium/components/offline_pages/background/request_queue_in_memory_store.cc b/chromium/components/offline_pages/background/request_queue_in_memory_store.cc
index defb87e311f..e2d79ed2e8f 100644
--- a/chromium/components/offline_pages/background/request_queue_in_memory_store.cc
+++ b/chromium/components/offline_pages/background/request_queue_in_memory_store.cc
@@ -17,41 +17,79 @@ RequestQueueInMemoryStore::~RequestQueueInMemoryStore() {}
void RequestQueueInMemoryStore::GetRequests(
const GetRequestsCallback& callback) {
- std::vector<SavePageRequest> result_requests;
- for (const auto& id_request_pair : requests_)
- result_requests.push_back(id_request_pair.second);
+ std::vector<std::unique_ptr<SavePageRequest>> result_requests;
+ for (const auto& id_request_pair : requests_) {
+ std::unique_ptr<SavePageRequest> request(
+ new SavePageRequest(id_request_pair.second));
+ result_requests.push_back(std::move(request));
+ }
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, true, result_requests));
+ FROM_HERE,
+ base::Bind(callback, true, base::Passed(std::move(result_requests))));
}
-void RequestQueueInMemoryStore::AddOrUpdateRequest(
- const SavePageRequest& request,
- const UpdateCallback& callback) {
+void RequestQueueInMemoryStore::AddRequest(const SavePageRequest& request,
+ const AddCallback& callback) {
RequestsMap::iterator iter = requests_.find(request.request_id());
- if (iter != requests_.end())
- requests_.erase(iter);
- requests_.insert(std::make_pair(request.request_id(), request));
+ ItemActionStatus status;
+ if (iter == requests_.end()) {
+ requests_.insert(iter, std::make_pair(request.request_id(), request));
+ status = ItemActionStatus::SUCCESS;
+ } else {
+ status = ItemActionStatus::ALREADY_EXISTS;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ base::Bind(callback, status));
+}
+
+void RequestQueueInMemoryStore::UpdateRequests(
+ const std::vector<SavePageRequest>& requests,
+ const RequestQueue::UpdateCallback& callback) {
+ std::unique_ptr<UpdateRequestsResult> result(
+ new UpdateRequestsResult(state()));
+
+ ItemActionStatus status;
+ for (const auto& request : requests) {
+ RequestsMap::iterator iter = requests_.find(request.request_id());
+ if (iter != requests_.end()) {
+ status = ItemActionStatus::SUCCESS;
+ iter->second = request;
+ result->updated_items.push_back(request);
+ } else {
+ status = ItemActionStatus::NOT_FOUND;
+ }
+ result->item_statuses.push_back(
+ std::make_pair(request.request_id(), status));
+ }
+
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, UpdateStatus::UPDATED));
+ FROM_HERE, base::Bind(callback, base::Passed(&result)));
}
void RequestQueueInMemoryStore::RemoveRequests(
const std::vector<int64_t>& request_ids,
- const RemoveCallback& callback) {
- // In case the |request_ids| is empty, the result will be true, but the count
- // of deleted pages will be empty.
- int count = 0;
- RequestsMap::iterator iter;
+ const UpdateCallback& callback) {
+ std::unique_ptr<UpdateRequestsResult> result(
+ new UpdateRequestsResult(StoreState::LOADED));
+
+ ItemActionStatus status;
+ // If we find a request, mark it as succeeded, and put it in the request list.
+ // Otherwise mark it as failed.
for (auto request_id : request_ids) {
- iter = requests_.find(request_id);
+ RequestsMap::iterator iter = requests_.find(request_id);
if (iter != requests_.end()) {
+ status = ItemActionStatus::SUCCESS;
+ result->updated_items.push_back(iter->second);
requests_.erase(iter);
- ++count;
+ } else {
+ status = ItemActionStatus::NOT_FOUND;
}
+ result->item_statuses.push_back(std::make_pair(request_id, status));
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, true, count));
+ FROM_HERE, base::Bind(callback, base::Passed(&result)));
}
void RequestQueueInMemoryStore::Reset(const ResetCallback& callback) {
@@ -60,4 +98,8 @@ void RequestQueueInMemoryStore::Reset(const ResetCallback& callback) {
base::Bind(callback, true));
}
+StoreState RequestQueueInMemoryStore::state() const {
+ return StoreState::LOADED;
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/request_queue_in_memory_store.h b/chromium/components/offline_pages/background/request_queue_in_memory_store.h
index 0a9b8bdb323..7c8b138dcd5 100644
--- a/chromium/components/offline_pages/background/request_queue_in_memory_store.h
+++ b/chromium/components/offline_pages/background/request_queue_in_memory_store.h
@@ -11,11 +11,10 @@
#include "base/macros.h"
#include "components/offline_pages/background/request_queue_store.h"
+#include "components/offline_pages/background/save_page_request.h"
namespace offline_pages {
-class SavePageRequest;
-
// Interface for classes storing save page requests.
class RequestQueueInMemoryStore : public RequestQueueStore {
public:
@@ -24,11 +23,15 @@ class RequestQueueInMemoryStore : public RequestQueueStore {
// RequestQueueStore implementaiton.
void GetRequests(const GetRequestsCallback& callback) override;
- void AddOrUpdateRequest(const SavePageRequest& request,
- const UpdateCallback& callback) override;
+ void AddRequest(const SavePageRequest& offline_page,
+ const AddCallback& callback) override;
+ void UpdateRequests(const std::vector<SavePageRequest>& requests,
+ const UpdateCallback& callback) override;
void RemoveRequests(const std::vector<int64_t>& request_ids,
- const RemoveCallback& callback) override;
+ const UpdateCallback& callback) override;
+
void Reset(const ResetCallback& callback) override;
+ StoreState state() const override;
private:
typedef std::map<int64_t, SavePageRequest> RequestsMap;
diff --git a/chromium/components/offline_pages/background/request_queue_store.h b/chromium/components/offline_pages/background/request_queue_store.h
index 0fd34a32aed..b661ea0faae 100644
--- a/chromium/components/offline_pages/background/request_queue_store.h
+++ b/chromium/components/offline_pages/background/request_queue_store.h
@@ -9,11 +9,12 @@
#include <vector>
#include "base/callback.h"
+#include "components/offline_pages/background/request_queue.h"
+#include "components/offline_pages/background/save_page_request.h"
+#include "components/offline_pages/offline_store_types.h"
namespace offline_pages {
-class SavePageRequest;
-
// Interface for classes storing save page requests.
class RequestQueueStore {
public:
@@ -23,14 +24,13 @@ class RequestQueueStore {
FAILED, // Add or update attempt failed.
};
+ using UpdateCallback = RequestQueue::UpdateCallback;
+
typedef base::Callback<void(
bool /* success */,
- const std::vector<SavePageRequest>& /* requests */)>
+ std::vector<std::unique_ptr<SavePageRequest>> /* requests */)>
GetRequestsCallback;
- typedef base::Callback<void(UpdateStatus)> UpdateCallback;
- typedef base::Callback<void(bool /* success */,
- int /* number of deleted requests */)>
- RemoveCallback;
+ typedef base::Callback<void(ItemActionStatus)> AddCallback;
typedef base::Callback<void(bool /* success */)> ResetCallback;
virtual ~RequestQueueStore(){};
@@ -38,10 +38,14 @@ class RequestQueueStore {
// Gets all of the requests from the store.
virtual void GetRequests(const GetRequestsCallback& callback) = 0;
- // Asynchronously adds or updates request in store.
- // Result of the update is passed in the callback.
- virtual void AddOrUpdateRequest(const SavePageRequest& request,
- const UpdateCallback& callback) = 0;
+ // Asynchronously adds request in store. Fails if request with the same
+ // offline ID already exists.
+ virtual void AddRequest(const SavePageRequest& offline_page,
+ const AddCallback& callback) = 0;
+
+ // Asynchronously updates requests in store.
+ virtual void UpdateRequests(const std::vector<SavePageRequest>& requests,
+ const UpdateCallback& callback) = 0;
// Asynchronously removes requests from the store using their IDs.
// Result of the update, and a number of removed pages is passed in the
@@ -49,10 +53,13 @@ class RequestQueueStore {
// Result of remove should be false, when one of the provided items couldn't
// be deleted, e.g. because it was missing.
virtual void RemoveRequests(const std::vector<int64_t>& request_ids,
- const RemoveCallback& callback) = 0;
+ const UpdateCallback& callback) = 0;
// Resets the store.
virtual void Reset(const ResetCallback& callback) = 0;
+
+ // Gets the store state.
+ virtual StoreState state() const = 0;
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/request_queue_store_sql.cc b/chromium/components/offline_pages/background/request_queue_store_sql.cc
index 79a1fe519ca..f88872be361 100644
--- a/chromium/components/offline_pages/background/request_queue_store_sql.cc
+++ b/chromium/components/offline_pages/background/request_queue_store_sql.cc
@@ -8,6 +8,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/background/save_page_request.h"
@@ -17,11 +18,17 @@
namespace offline_pages {
+template class StoreUpdateResult<SavePageRequest>;
+
namespace {
+using UpdateStatus = RequestQueueStore::UpdateStatus;
+using StoreStateCallback = base::Callback<void(StoreState)>;
+
// This is a macro instead of a const so that
// it can be used inline in other SQL statements below.
#define REQUEST_QUEUE_TABLE_NAME "request_queue_v1"
+const bool kUserRequested = true;
bool CreateRequestQueueTable(sql::Connection* db) {
const char kSql[] = "CREATE TABLE IF NOT EXISTS " REQUEST_QUEUE_TABLE_NAME
@@ -29,7 +36,9 @@ bool CreateRequestQueueTable(sql::Connection* db) {
" creation_time INTEGER NOT NULL,"
" activation_time INTEGER NOT NULL DEFAULT 0,"
" last_attempt_time INTEGER NOT NULL DEFAULT 0,"
- " attempt_count INTEGER NOT NULL,"
+ " started_attempt_count INTEGER NOT NULL,"
+ " completed_attempt_count INTEGER NOT NULL,"
+ " state INTEGER NOT NULL DEFAULT 0,"
" url VARCHAR NOT NULL,"
" client_namespace VARCHAR NOT NULL,"
" client_id VARCHAR NOT NULL"
@@ -38,49 +47,27 @@ bool CreateRequestQueueTable(sql::Connection* db) {
}
bool CreateSchema(sql::Connection* db) {
- // TODO(fgorski): Upgrade code goes here and requires transaction.
- if (!CreateRequestQueueTable(db))
- return false;
-
- // TODO(fgorski): Add indices here.
- return true;
-}
-
-bool DeleteRequestById(sql::Connection* db, int64_t request_id) {
- const char kSql[] =
- "DELETE FROM " REQUEST_QUEUE_TABLE_NAME " WHERE request_id=?";
- sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
- statement.BindInt64(0, request_id);
- return statement.Run();
-}
-
-bool DeleteRequestsByIds(sql::Connection* db,
- const std::vector<int64_t>& request_ids,
- int* count) {
- DCHECK(count);
- // If you create a transaction but don't Commit() it is automatically
- // rolled back by its destructor when it falls out of scope.
- sql::Transaction transaction(db);
- if (!transaction.Begin())
- return false;
-
- *count = 0;
- for (auto request_id : request_ids) {
- if (!DeleteRequestById(db, request_id))
+ // If there is not already a state column, we need to drop the old table. We
+ // are choosing to drop instead of upgrade since the feature is not yet
+ // released, so we don't use a transaction to protect existing data, or try to
+ // migrate it.
+ if (!db->DoesColumnExist(REQUEST_QUEUE_TABLE_NAME, "state")) {
+ if (!db->Execute("DROP TABLE IF EXISTS " REQUEST_QUEUE_TABLE_NAME))
return false;
- *count += db->GetLastChangeCount();
}
- if (!transaction.Commit())
+ if (!CreateRequestQueueTable(db))
return false;
+ // TODO(fgorski): Add indices here.
return true;
}
// Create a save page request from a SQL result. Expects complete rows with
// all columns present. Columns are in order they are defined in select query
-// in |RequestQueueStore::RequestSync| method.
-SavePageRequest MakeSavePageRequest(const sql::Statement& statement) {
+// in |GetOneRequest| method.
+std::unique_ptr<SavePageRequest> MakeSavePageRequest(
+ const sql::Statement& statement) {
const int64_t id = statement.ColumnInt64(0);
const base::Time creation_time =
base::Time::FromInternalValue(statement.ColumnInt64(1));
@@ -88,43 +75,141 @@ SavePageRequest MakeSavePageRequest(const sql::Statement& statement) {
base::Time::FromInternalValue(statement.ColumnInt64(2));
const base::Time last_attempt_time =
base::Time::FromInternalValue(statement.ColumnInt64(3));
- const int64_t last_attempt_count = statement.ColumnInt64(4);
- const GURL url(statement.ColumnString(5));
- const ClientId client_id(statement.ColumnString(6),
- statement.ColumnString(7));
-
- SavePageRequest request(id, url, client_id, creation_time, activation_time);
- request.set_last_attempt_time(last_attempt_time);
- request.set_attempt_count(last_attempt_count);
+ const int64_t started_attempt_count = statement.ColumnInt64(4);
+ const int64_t completed_attempt_count = statement.ColumnInt64(5);
+ const SavePageRequest::RequestState state =
+ static_cast<SavePageRequest::RequestState>(statement.ColumnInt64(6));
+ const GURL url(statement.ColumnString(7));
+ const ClientId client_id(statement.ColumnString(8),
+ statement.ColumnString(9));
+
+ DVLOG(2) << "making save page request - id " << id << " url " << url
+ << " client_id " << client_id.name_space << "-" << client_id.id
+ << " creation time " << creation_time << " user requested "
+ << kUserRequested;
+
+ std::unique_ptr<SavePageRequest> request(new SavePageRequest(
+ id, url, client_id, creation_time, activation_time, kUserRequested));
+ request->set_last_attempt_time(last_attempt_time);
+ request->set_started_attempt_count(started_attempt_count);
+ request->set_completed_attempt_count(completed_attempt_count);
+ request->set_request_state(state);
return request;
}
-RequestQueueStore::UpdateStatus InsertOrReplace(
- sql::Connection* db,
- const SavePageRequest& request) {
- // In order to use the enums in the Bind* methods, keep the order of fields
- // the same as in the definition/select query.
- const char kInsertSql[] =
- "INSERT OR REPLACE INTO " REQUEST_QUEUE_TABLE_NAME
- " (request_id, creation_time, activation_time, last_attempt_time, "
- " attempt_count, url, client_namespace, client_id) "
+// Get a request for a specific id.
+std::unique_ptr<SavePageRequest> GetOneRequest(sql::Connection* db,
+ const int64_t request_id) {
+ const char kSql[] =
+ "SELECT request_id, creation_time, activation_time,"
+ " last_attempt_time, started_attempt_count, completed_attempt_count,"
+ " state, url, client_namespace, client_id"
+ " FROM " REQUEST_QUEUE_TABLE_NAME " WHERE request_id=?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, request_id);
+
+ statement.Run();
+ return MakeSavePageRequest(statement);
+}
+
+ItemActionStatus DeleteRequestById(sql::Connection* db, int64_t request_id) {
+ const char kSql[] =
+ "DELETE FROM " REQUEST_QUEUE_TABLE_NAME " WHERE request_id=?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, request_id);
+ if (!statement.Run())
+ return ItemActionStatus::STORE_ERROR;
+ else if (db->GetLastChangeCount() == 0)
+ return ItemActionStatus::NOT_FOUND;
+ return ItemActionStatus::SUCCESS;
+}
+
+ItemActionStatus Insert(sql::Connection* db, const SavePageRequest& request) {
+ const char kSql[] =
+ "INSERT OR IGNORE INTO " REQUEST_QUEUE_TABLE_NAME
+ " (request_id, creation_time, activation_time,"
+ " last_attempt_time, started_attempt_count, completed_attempt_count,"
+ " state, url, client_namespace, client_id)"
" VALUES "
- " (?, ?, ?, ?, ?, ?, ?, ?)";
+ " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
- sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kInsertSql));
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindInt64(0, request.request_id());
statement.BindInt64(1, request.creation_time().ToInternalValue());
statement.BindInt64(2, request.activation_time().ToInternalValue());
statement.BindInt64(3, request.last_attempt_time().ToInternalValue());
- statement.BindInt64(4, request.attempt_count());
- statement.BindString(5, request.url().spec());
- statement.BindString(6, request.client_id().name_space);
- statement.BindString(7, request.client_id().id);
-
- // TODO(fgorski): Replace the UpdateStatus with boolean in the
- // RequestQueueStore interface and update this code.
- return statement.Run() ? RequestQueueStore::UpdateStatus::UPDATED
- : RequestQueueStore::UpdateStatus::FAILED;
+ statement.BindInt64(4, request.started_attempt_count());
+ statement.BindInt64(5, request.completed_attempt_count());
+ statement.BindInt64(6, static_cast<int64_t>(request.request_state()));
+ statement.BindString(7, request.url().spec());
+ statement.BindString(8, request.client_id().name_space);
+ statement.BindString(9, request.client_id().id);
+
+ if (!statement.Run())
+ return ItemActionStatus::STORE_ERROR;
+ if (db->GetLastChangeCount() == 0)
+ return ItemActionStatus::ALREADY_EXISTS;
+ return ItemActionStatus::SUCCESS;
+}
+
+ItemActionStatus Update(sql::Connection* db, const SavePageRequest& request) {
+ const char kSql[] =
+ "UPDATE OR IGNORE " REQUEST_QUEUE_TABLE_NAME
+ " SET creation_time = ?, activation_time = ?, last_attempt_time = ?,"
+ " started_attempt_count = ?, completed_attempt_count = ?, state = ?,"
+ " url = ?, client_namespace = ?, client_id = ?"
+ " WHERE request_id = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, request.creation_time().ToInternalValue());
+ statement.BindInt64(1, request.activation_time().ToInternalValue());
+ statement.BindInt64(2, request.last_attempt_time().ToInternalValue());
+ statement.BindInt64(3, request.started_attempt_count());
+ statement.BindInt64(4, request.completed_attempt_count());
+ statement.BindInt64(5, static_cast<int64_t>(request.request_state()));
+ statement.BindString(6, request.url().spec());
+ statement.BindString(7, request.client_id().name_space);
+ statement.BindString(8, request.client_id().id);
+ statement.BindInt64(9, request.request_id());
+
+ if (!statement.Run())
+ return ItemActionStatus::STORE_ERROR;
+ if (db->GetLastChangeCount() == 0)
+ return ItemActionStatus::NOT_FOUND;
+ return ItemActionStatus::SUCCESS;
+}
+
+void PostStoreUpdateResultForIds(
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ StoreState store_state,
+ const std::vector<int64_t>& item_ids,
+ ItemActionStatus action_status,
+ const RequestQueueStore::UpdateCallback& callback) {
+ std::unique_ptr<UpdateRequestsResult> result(
+ new UpdateRequestsResult(store_state));
+ for (const auto& item_id : item_ids)
+ result->item_statuses.push_back(std::make_pair(item_id, action_status));
+ runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
+}
+
+void PostStoreErrorForAllRequests(
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const std::vector<SavePageRequest>& items,
+ const RequestQueueStore::UpdateCallback& callback) {
+ std::vector<int64_t> item_ids;
+ for (const auto& item : items)
+ item_ids.push_back(item.request_id());
+ PostStoreUpdateResultForIds(runner, StoreState::LOADED, item_ids,
+ ItemActionStatus::STORE_ERROR, callback);
+}
+
+void PostStoreErrorForAllIds(
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const std::vector<int64_t>& item_ids,
+ const RequestQueueStore::UpdateCallback& callback) {
+ PostStoreUpdateResultForIds(runner, StoreState::LOADED, item_ids,
+ ItemActionStatus::STORE_ERROR, callback);
}
bool InitDatabase(sql::Connection* db, const base::FilePath& path) {
@@ -143,154 +228,212 @@ bool InitDatabase(sql::Connection* db, const base::FilePath& path) {
return CreateSchema(db);
}
-} // anonymous namespace
-
-RequestQueueStoreSQL::RequestQueueStoreSQL(
- scoped_refptr<base::SequencedTaskRunner> background_task_runner,
- const base::FilePath& path)
- : background_task_runner_(std::move(background_task_runner)),
- db_file_path_(path.AppendASCII("RequestQueue.db")),
- weak_ptr_factory_(this) {
- OpenConnection();
-}
-
-RequestQueueStoreSQL::~RequestQueueStoreSQL() {
- if (db_.get())
- background_task_runner_->DeleteSoon(FROM_HERE, db_.release());
-}
-
-// static
-void RequestQueueStoreSQL::OpenConnectionSync(
- sql::Connection* db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const base::FilePath& path,
- const base::Callback<void(bool)>& callback) {
- bool success = InitDatabase(db, path);
- runner->PostTask(FROM_HERE, base::Bind(callback, success));
-}
-
-// static
-void RequestQueueStoreSQL::GetRequestsSync(
- sql::Connection* db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const GetRequestsCallback& callback) {
+void GetRequestsSync(sql::Connection* db,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const RequestQueueStore::GetRequestsCallback& callback) {
const char kSql[] =
"SELECT request_id, creation_time, activation_time,"
- " last_attempt_time, attempt_count, url, client_namespace, client_id"
+ " last_attempt_time, started_attempt_count, completed_attempt_count,"
+ " state, url, client_namespace, client_id"
" FROM " REQUEST_QUEUE_TABLE_NAME;
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
- std::vector<SavePageRequest> result;
+ std::vector<std::unique_ptr<SavePageRequest>> requests;
while (statement.Step())
- result.push_back(MakeSavePageRequest(statement));
+ requests.push_back(MakeSavePageRequest(statement));
- runner->PostTask(FROM_HERE,
- base::Bind(callback, statement.Succeeded(), result));
+ runner->PostTask(FROM_HERE, base::Bind(callback, statement.Succeeded(),
+ base::Passed(&requests)));
}
-// static
-void RequestQueueStoreSQL::AddOrUpdateRequestSync(
- sql::Connection* db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const SavePageRequest& request,
- const UpdateCallback& callback) {
+void AddRequestSync(sql::Connection* db,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const SavePageRequest& request,
+ const RequestQueueStore::AddCallback& callback) {
// TODO(fgorski): add UMA metrics here.
- RequestQueueStore::UpdateStatus status = InsertOrReplace(db, request);
+ ItemActionStatus status = Insert(db, request);
runner->PostTask(FROM_HERE, base::Bind(callback, status));
}
-// static
-void RequestQueueStoreSQL::RemoveRequestsSync(
- sql::Connection* db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const std::vector<int64_t>& request_ids,
- const RemoveCallback& callback) {
+void UpdateRequestsSync(sql::Connection* db,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const std::vector<SavePageRequest>& requests,
+ const RequestQueueStore::UpdateCallback& callback) {
// TODO(fgorski): add UMA metrics here.
- int count = 0;
- if (DeleteRequestsByIds(db, request_ids, &count))
- runner->PostTask(FROM_HERE, base::Bind(callback, true, count));
- else
- runner->PostTask(FROM_HERE, base::Bind(callback, false, 0));
+ std::unique_ptr<UpdateRequestsResult> result(
+ new UpdateRequestsResult(StoreState::LOADED));
+
+ sql::Transaction transaction(db);
+ if (!transaction.Begin()) {
+ PostStoreErrorForAllRequests(runner, requests, callback);
+ return;
+ }
+
+ for (const auto& request : requests) {
+ ItemActionStatus status = Update(db, request);
+ result->item_statuses.push_back(
+ std::make_pair(request.request_id(), status));
+ if (status == ItemActionStatus::SUCCESS)
+ result->updated_items.push_back(request);
+ }
+
+ if (!transaction.Commit()) {
+ PostStoreErrorForAllRequests(runner, requests, callback);
+ return;
+ }
+
+ runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
}
-// static
-void RequestQueueStoreSQL::ResetSync(
- sql::Connection* db,
- const base::FilePath& db_file_path,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const ResetCallback& callback) {
+void RemoveRequestsSync(sql::Connection* db,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const std::vector<int64_t>& request_ids,
+ const RequestQueueStore::UpdateCallback& callback) {
+ // TODO(fgorski): Perhaps add metrics here.
+ std::unique_ptr<UpdateRequestsResult> result(
+ new UpdateRequestsResult(StoreState::LOADED));
+
+ // If you create a transaction but don't Commit() it is automatically
+ // rolled back by its destructor when it falls out of scope.
+ sql::Transaction transaction(db);
+ if (!transaction.Begin()) {
+ PostStoreErrorForAllIds(runner, request_ids, callback);
+ return;
+ }
+
+ // Read the request before we delete it, and if the delete worked, put it on
+ // the queue of requests that got deleted.
+ for (int64_t request_id : request_ids) {
+ std::unique_ptr<SavePageRequest> request = GetOneRequest(db, request_id);
+ ItemActionStatus status = DeleteRequestById(db, request_id);
+ result->item_statuses.push_back(std::make_pair(request_id, status));
+ if (status == ItemActionStatus::SUCCESS)
+ result->updated_items.push_back(*request);
+ }
+
+ if (!transaction.Commit()) {
+ PostStoreErrorForAllIds(runner, request_ids, callback);
+ return;
+ }
+
+ runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
+}
+
+void OpenConnectionSync(sql::Connection* db,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const base::FilePath& path,
+ const StoreStateCallback& callback) {
+ StoreState state =
+ InitDatabase(db, path) ? StoreState::LOADED : StoreState::FAILED_LOADING;
+ runner->PostTask(FROM_HERE, base::Bind(callback, state));
+}
+
+void ResetSync(sql::Connection* db,
+ const base::FilePath& db_file_path,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const StoreStateCallback& callback) {
// This method deletes the content of the whole store and reinitializes it.
bool success = db->Raze();
db->Close();
- if (success)
- success = InitDatabase(db, db_file_path);
- runner->PostTask(FROM_HERE, base::Bind(callback, success));
+ StoreState state;
+ if (!success)
+ state = StoreState::FAILED_RESET;
+ if (InitDatabase(db, db_file_path))
+ state = StoreState::LOADED;
+ else
+ state = StoreState::FAILED_LOADING;
+
+ runner->PostTask(FROM_HERE, base::Bind(callback, state));
}
-void RequestQueueStoreSQL::GetRequests(const GetRequestsCallback& callback) {
+} // anonymous namespace
+
+RequestQueueStoreSQL::RequestQueueStoreSQL(
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner,
+ const base::FilePath& path)
+ : background_task_runner_(std::move(background_task_runner)),
+ db_file_path_(path.AppendASCII("RequestQueue.db")),
+ weak_ptr_factory_(this) {
+ OpenConnection();
+}
+
+RequestQueueStoreSQL::~RequestQueueStoreSQL() {
+ if (db_.get())
+ background_task_runner_->DeleteSoon(FROM_HERE, db_.release());
+}
+
+bool RequestQueueStoreSQL::CheckDb(const base::Closure& callback) {
DCHECK(db_.get());
if (!db_.get()) {
// Nothing to do, but post a callback instead of calling directly
// to preserve the async style behavior to prevent bugs.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, false, std::vector<SavePageRequest>()));
- return;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
+ return false;
}
+ return true;
+}
+
+void RequestQueueStoreSQL::GetRequests(const GetRequestsCallback& callback) {
+ DCHECK(db_.get());
+ std::vector<std::unique_ptr<SavePageRequest>> requests;
+ if (!CheckDb(base::Bind(callback, false, base::Passed(&requests))))
+ return;
background_task_runner_->PostTask(
- FROM_HERE, base::Bind(&RequestQueueStoreSQL::GetRequestsSync, db_.get(),
+ FROM_HERE, base::Bind(&GetRequestsSync, db_.get(),
base::ThreadTaskRunnerHandle::Get(), callback));
}
-void RequestQueueStoreSQL::AddOrUpdateRequest(const SavePageRequest& request,
- const UpdateCallback& callback) {
- DCHECK(db_.get());
+void RequestQueueStoreSQL::AddRequest(const SavePageRequest& request,
+ const AddCallback& callback) {
+ if (!CheckDb(base::Bind(callback, ItemActionStatus::STORE_ERROR)))
+ return;
+
+ background_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AddRequestSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(), request, callback));
+}
+
+void RequestQueueStoreSQL::UpdateRequests(
+ const std::vector<SavePageRequest>& requests,
+ const UpdateCallback& callback) {
if (!db_.get()) {
- // Nothing to do, but post a callback instead of calling directly
- // to preserve the async style behavior to prevent bugs.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, UpdateStatus::FAILED));
+ PostStoreErrorForAllRequests(base::ThreadTaskRunnerHandle::Get(), requests,
+ callback);
return;
}
background_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&RequestQueueStoreSQL::AddOrUpdateRequestSync, db_.get(),
- base::ThreadTaskRunnerHandle::Get(), request, callback));
+ base::Bind(&UpdateRequestsSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(), requests, callback));
}
void RequestQueueStoreSQL::RemoveRequests(
const std::vector<int64_t>& request_ids,
- const RemoveCallback& callback) {
- DCHECK(db_.get());
+ const UpdateCallback& callback) {
if (!db_.get()) {
- // Nothing to do, but post a callback instead of calling directly
- // to preserve the async style behavior to prevent bugs.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, false, 0));
+ PostStoreErrorForAllIds(base::ThreadTaskRunnerHandle::Get(), request_ids,
+ callback);
return;
}
background_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&RequestQueueStoreSQL::RemoveRequestsSync, db_.get(),
+ base::Bind(&RemoveRequestsSync, db_.get(),
base::ThreadTaskRunnerHandle::Get(), request_ids, callback));
}
void RequestQueueStoreSQL::Reset(const ResetCallback& callback) {
DCHECK(db_.get());
- if (!db_.get()) {
- // Nothing to do, but post a callback instead of calling directly
- // to preserve the async style behavior to prevent bugs.
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- base::Bind(callback, false));
+ if (!CheckDb(base::Bind(callback, false)))
return;
- }
background_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&RequestQueueStoreSQL::ResetSync, db_.get(), db_file_path_,
+ base::Bind(&ResetSync, db_.get(), db_file_path_,
base::ThreadTaskRunnerHandle::Get(),
base::Bind(&RequestQueueStoreSQL::OnResetDone,
weak_ptr_factory_.GetWeakPtr(), callback)));
@@ -301,25 +444,31 @@ void RequestQueueStoreSQL::OpenConnection() {
db_.reset(new sql::Connection());
background_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&RequestQueueStoreSQL::OpenConnectionSync, db_.get(),
+ base::Bind(&OpenConnectionSync, db_.get(),
base::ThreadTaskRunnerHandle::Get(), db_file_path_,
base::Bind(&RequestQueueStoreSQL::OnOpenConnectionDone,
weak_ptr_factory_.GetWeakPtr())));
}
-void RequestQueueStoreSQL::OnOpenConnectionDone(bool success) {
+void RequestQueueStoreSQL::OnOpenConnectionDone(StoreState state) {
DCHECK(db_.get());
+ state_ = state;
+
// Unfortunately we were not able to open DB connection.
- if (!success)
+ if (state_ != StoreState::LOADED)
db_.reset();
}
void RequestQueueStoreSQL::OnResetDone(const ResetCallback& callback,
- bool success) {
+ StoreState state) {
// Complete connection initialization post reset.
- OnOpenConnectionDone(success);
- callback.Run(success);
+ OnOpenConnectionDone(state);
+ callback.Run(state == StoreState::LOADED);
+}
+
+StoreState RequestQueueStoreSQL::state() const {
+ return state_;
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/request_queue_store_sql.h b/chromium/components/offline_pages/background/request_queue_store_sql.h
index 92dd09f45c6..d67d14f348b 100644
--- a/chromium/components/offline_pages/background/request_queue_store_sql.h
+++ b/chromium/components/offline_pages/background/request_queue_store_sql.h
@@ -6,7 +6,6 @@
#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_QUEUE_STORE_SQL_H_
#include <stdint.h>
-
#include <memory>
#include <vector>
@@ -34,47 +33,25 @@ class RequestQueueStoreSQL : public RequestQueueStore {
// RequestQueueStore implementation.
void GetRequests(const GetRequestsCallback& callback) override;
- void AddOrUpdateRequest(const SavePageRequest& offline_page,
- const UpdateCallback& callback) override;
+ void AddRequest(const SavePageRequest& offline_page,
+ const AddCallback& callback) override;
+ void UpdateRequests(const std::vector<SavePageRequest>& requests,
+ const UpdateCallback& callback) override;
void RemoveRequests(const std::vector<int64_t>& request_ids,
- const RemoveCallback& callback) override;
+ const UpdateCallback& callback) override;
void Reset(const ResetCallback& callback) override;
+ StoreState state() const override;
private:
- // Synchronous implementations, these are run on the background thread
- // and actually do the work to access SQL. The implementations above
- // simply dispatch to the corresponding *Sync method on the background thread.
- // 'runner' is where to run the callback.
- static void GetRequestsSync(
- sql::Connection* db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const GetRequestsCallback& callback);
- static void AddOrUpdateRequestSync(
- sql::Connection* db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const SavePageRequest& offline_page,
- const UpdateCallback& callback);
- static void RemoveRequestsSync(
- sql::Connection* db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const std::vector<int64_t>& request_ids,
- const RemoveCallback& callback);
- static void ResetSync(sql::Connection* db,
- const base::FilePath& db_file_path,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const ResetCallback& callback);
+ // Helper functions to return immediately if no database is found.
+ bool CheckDb(const base::Closure& callback);
// Used to initialize DB connection.
- static void OpenConnectionSync(
- sql::Connection* db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const base::FilePath& path,
- const base::Callback<void(bool)>& callback);
void OpenConnection();
- void OnOpenConnectionDone(bool success);
+ void OnOpenConnectionDone(StoreState state);
// Used to finalize connection reset.
- void OnResetDone(const ResetCallback& callback, bool success);
+ void OnResetDone(const ResetCallback& callback, StoreState state);
// Background thread where all SQL access should be run.
scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
@@ -85,6 +62,9 @@ class RequestQueueStoreSQL : public RequestQueueStore {
// Database connection.
std::unique_ptr<sql::Connection> db_;
+ // State of the store.
+ StoreState state_;
+
base::WeakPtrFactory<RequestQueueStoreSQL> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RequestQueueStoreSQL);
};
diff --git a/chromium/components/offline_pages/background/request_queue_store_unittest.cc b/chromium/components/offline_pages/background/request_queue_store_unittest.cc
index 32c6ab649fd..0a20dfb4747 100644
--- a/chromium/components/offline_pages/background/request_queue_store_unittest.cc
+++ b/chromium/components/offline_pages/background/request_queue_store_unittest.cc
@@ -11,6 +11,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/background/request_queue.h"
#include "components/offline_pages/background/request_queue_in_memory_store.h"
#include "components/offline_pages/background/request_queue_store_sql.h"
#include "components/offline_pages/background/save_page_request.h"
@@ -22,8 +23,12 @@ using UpdateStatus = RequestQueueStore::UpdateStatus;
namespace {
const int64_t kRequestId = 42;
+const int64_t kRequestId2 = 44;
const GURL kUrl("http://example.com");
+const GURL kUrl2("http://another-example.com");
const ClientId kClientId("bookmark", "1234");
+const ClientId kClientId2("async", "5678");
+const bool kUserRequested = true;
enum class LastResult {
kNone,
@@ -31,15 +36,6 @@ enum class LastResult {
kTrue,
};
-bool operator==(const SavePageRequest& lhs, const SavePageRequest& rhs) {
- return lhs.request_id() == rhs.request_id() && lhs.url() == rhs.url() &&
- lhs.client_id() == rhs.client_id() &&
- lhs.creation_time() == rhs.creation_time() &&
- lhs.activation_time() == rhs.activation_time() &&
- lhs.attempt_count() == rhs.attempt_count() &&
- lhs.last_attempt_time() == rhs.last_attempt_time();
-}
-
} // namespace
// Class that serves as a base for testing different implementations of the
@@ -57,20 +53,24 @@ class RequestQueueStoreTestBase : public testing::Test {
// Callback used for get requests.
void GetRequestsDone(bool result,
- const std::vector<SavePageRequest>& requests);
+ std::vector<std::unique_ptr<SavePageRequest>> requests);
// Callback used for add/update request.
void AddOrUpdateDone(UpdateStatus result);
- // Callback used for remove requests.
- void RemoveDone(bool result, int count);
+ void AddRequestDone(ItemActionStatus status);
+ void UpdateRequestDone(std::unique_ptr<UpdateRequestsResult> result);
// Callback used for reset.
void ResetDone(bool result);
LastResult last_result() const { return last_result_; }
UpdateStatus last_update_status() const { return last_update_status_; }
- int last_remove_count() const { return last_remove_count_; }
- const std::vector<SavePageRequest>& last_requests() const {
+ const std::vector<std::unique_ptr<SavePageRequest>>& last_requests() const {
return last_requests_;
}
+ ItemActionStatus last_add_status() const { return last_add_status_; }
+
+ UpdateRequestsResult* last_update_result() const {
+ return last_update_result_.get();
+ }
protected:
base::ScopedTempDir temp_directory_;
@@ -78,8 +78,9 @@ class RequestQueueStoreTestBase : public testing::Test {
private:
LastResult last_result_;
UpdateStatus last_update_status_;
- int last_remove_count_;
- std::vector<SavePageRequest> last_requests_;
+ ItemActionStatus last_add_status_;
+ std::unique_ptr<UpdateRequestsResult> last_update_result_;
+ std::vector<std::unique_ptr<SavePageRequest>> last_requests_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
@@ -88,7 +89,7 @@ class RequestQueueStoreTestBase : public testing::Test {
RequestQueueStoreTestBase::RequestQueueStoreTestBase()
: last_result_(LastResult::kNone),
last_update_status_(UpdateStatus::FAILED),
- last_remove_count_(0),
+ last_add_status_(ItemActionStatus::NOT_FOUND),
task_runner_(new base::TestSimpleTaskRunner),
task_runner_handle_(task_runner_) {
EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
@@ -106,24 +107,29 @@ void RequestQueueStoreTestBase::PumpLoop() {
void RequestQueueStoreTestBase::ClearResults() {
last_result_ = LastResult::kNone;
last_update_status_ = UpdateStatus::FAILED;
- last_remove_count_ = 0;
+ last_add_status_ = ItemActionStatus::NOT_FOUND;
last_requests_.clear();
+ last_update_result_.reset(nullptr);
}
void RequestQueueStoreTestBase::GetRequestsDone(
bool result,
- const std::vector<SavePageRequest>& requests) {
+ std::vector<std::unique_ptr<SavePageRequest>> requests) {
last_result_ = result ? LastResult::kTrue : LastResult::kFalse;
- last_requests_ = requests;
+ last_requests_ = std::move(requests);
}
void RequestQueueStoreTestBase::AddOrUpdateDone(UpdateStatus status) {
last_update_status_ = status;
}
-void RequestQueueStoreTestBase::RemoveDone(bool result, int count) {
- last_result_ = result ? LastResult::kTrue : LastResult::kFalse;
- last_remove_count_ = count;
+void RequestQueueStoreTestBase::AddRequestDone(ItemActionStatus status) {
+ last_add_status_ = status;
+}
+
+void RequestQueueStoreTestBase::UpdateRequestDone(
+ std::unique_ptr<UpdateRequestsResult> result) {
+ last_update_result_ = std::move(result);
}
void RequestQueueStoreTestBase::ResetDone(bool result) {
@@ -168,7 +174,7 @@ class RequestQueueStoreTest : public RequestQueueStoreTestBase {
template <typename T>
std::unique_ptr<RequestQueueStore> RequestQueueStoreTest<T>::BuildStore() {
std::unique_ptr<RequestQueueStore> store(
- factory_.BuildStore(temp_directory_.path()));
+ factory_.BuildStore(temp_directory_.GetPath()));
return store;
}
@@ -195,14 +201,15 @@ TYPED_TEST(RequestQueueStoreTest, GetRequestsEmpty) {
TYPED_TEST(RequestQueueStoreTest, AddRequest) {
std::unique_ptr<RequestQueueStore> store(this->BuildStore());
base::Time creation_time = base::Time::Now();
- SavePageRequest request(kRequestId, kUrl, kClientId, creation_time);
+ SavePageRequest request(
+ kRequestId, kUrl, kClientId, creation_time, kUserRequested);
- store->AddOrUpdateRequest(
- request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
- base::Unretained(this)));
- ASSERT_EQ(UpdateStatus::FAILED, this->last_update_status());
+ store->AddRequest(request,
+ base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
+ ASSERT_EQ(ItemActionStatus::NOT_FOUND, this->last_add_status());
this->PumpLoop();
- ASSERT_EQ(UpdateStatus::UPDATED, this->last_update_status());
+ ASSERT_EQ(ItemActionStatus::SUCCESS, this->last_add_status());
// Verifying get reqeust results after a request was added.
this->ClearResults();
@@ -212,30 +219,68 @@ TYPED_TEST(RequestQueueStoreTest, AddRequest) {
this->PumpLoop();
ASSERT_EQ(LastResult::kTrue, this->last_result());
ASSERT_EQ(1ul, this->last_requests().size());
- ASSERT_TRUE(request == this->last_requests()[0]);
+ ASSERT_EQ(request, *(this->last_requests()[0].get()));
+
+ // Verify it is not possible to add the same request twice.
+ this->ClearResults();
+ store->AddRequest(request,
+ base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
+ ASSERT_EQ(ItemActionStatus::NOT_FOUND, this->last_add_status());
+ this->PumpLoop();
+ ASSERT_EQ(ItemActionStatus::ALREADY_EXISTS, this->last_add_status());
+
+ // Check that there is still only one item in the store.
+ this->ClearResults();
+ store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
+ ASSERT_EQ(LastResult::kNone, this->last_result());
+ this->PumpLoop();
+ ASSERT_EQ(LastResult::kTrue, this->last_result());
+ ASSERT_EQ(1ul, this->last_requests().size());
}
TYPED_TEST(RequestQueueStoreTest, UpdateRequest) {
std::unique_ptr<RequestQueueStore> store(this->BuildStore());
base::Time creation_time = base::Time::Now();
- SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time);
- store->AddOrUpdateRequest(
- original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
- base::Unretained(this)));
+ SavePageRequest original_request(
+ kRequestId, kUrl, kClientId, creation_time, kUserRequested);
+ store->AddRequest(original_request,
+ base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
this->PumpLoop();
this->ClearResults();
base::Time new_creation_time =
creation_time + base::TimeDelta::FromMinutes(1);
base::Time activation_time = creation_time + base::TimeDelta::FromHours(6);
+ // Try updating an existing request.
SavePageRequest updated_request(kRequestId, kUrl, kClientId,
- new_creation_time, activation_time);
- store->AddOrUpdateRequest(
- updated_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
- base::Unretained(this)));
- ASSERT_EQ(UpdateStatus::FAILED, this->last_update_status());
+ new_creation_time, activation_time,
+ kUserRequested);
+ // Try to update a non-existing request.
+ SavePageRequest updated_request2(kRequestId2, kUrl, kClientId,
+ new_creation_time, activation_time,
+ kUserRequested);
+ std::vector<SavePageRequest> requests_to_update{updated_request,
+ updated_request2};
+ store->UpdateRequests(
+ requests_to_update,
+ base::Bind(&RequestQueueStoreTestBase::UpdateRequestDone,
+ base::Unretained(this)));
+ ASSERT_FALSE(this->last_update_result());
this->PumpLoop();
- ASSERT_EQ(UpdateStatus::UPDATED, this->last_update_status());
+ ASSERT_TRUE(this->last_update_result());
+ EXPECT_EQ(2UL, this->last_update_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId, this->last_update_result()->item_statuses[0].first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ this->last_update_result()->item_statuses[0].second);
+ EXPECT_EQ(kRequestId2, this->last_update_result()->item_statuses[1].first);
+ EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+ this->last_update_result()->item_statuses[1].second);
+ EXPECT_EQ(1UL, this->last_update_result()->updated_items.size());
+ EXPECT_EQ(updated_request,
+ *(this->last_update_result()->updated_items.begin()));
// Verifying get reqeust results after a request was updated.
this->ClearResults();
@@ -245,28 +290,43 @@ TYPED_TEST(RequestQueueStoreTest, UpdateRequest) {
this->PumpLoop();
ASSERT_EQ(LastResult::kTrue, this->last_result());
ASSERT_EQ(1ul, this->last_requests().size());
- ASSERT_TRUE(updated_request == this->last_requests()[0]);
+ ASSERT_EQ(updated_request, *(this->last_requests()[0].get()));
}
-TYPED_TEST(RequestQueueStoreTest, RemoveRequest) {
+TYPED_TEST(RequestQueueStoreTest, RemoveRequests) {
std::unique_ptr<RequestQueueStore> store(this->BuildStore());
base::Time creation_time = base::Time::Now();
- SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time);
- store->AddOrUpdateRequest(
- original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
- base::Unretained(this)));
+ SavePageRequest request1(kRequestId, kUrl, kClientId, creation_time,
+ kUserRequested);
+ store->AddRequest(request1,
+ base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
+ kUserRequested);
+ store->AddRequest(request2,
+ base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
this->PumpLoop();
this->ClearResults();
- std::vector<int64_t> request_ids{kRequestId};
- store->RemoveRequests(request_ids,
- base::Bind(&RequestQueueStoreTestBase::RemoveDone,
- base::Unretained(this)));
- ASSERT_EQ(LastResult::kNone, this->last_result());
- ASSERT_EQ(0, this->last_remove_count());
+ std::vector<int64_t> request_ids{kRequestId, kRequestId2};
+ store->RemoveRequests(
+ request_ids, base::Bind(&RequestQueueStoreTestBase::UpdateRequestDone,
+ base::Unretained(this)));
+
+ ASSERT_FALSE(this->last_update_result());
this->PumpLoop();
- ASSERT_EQ(LastResult::kTrue, this->last_result());
- ASSERT_EQ(1, this->last_remove_count());
+ ASSERT_TRUE(this->last_update_result());
+ EXPECT_EQ(2UL, this->last_update_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId, this->last_update_result()->item_statuses[0].first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ this->last_update_result()->item_statuses[0].second);
+ EXPECT_EQ(kRequestId2, this->last_update_result()->item_statuses[1].first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ this->last_update_result()->item_statuses[1].second);
+ EXPECT_EQ(2UL, this->last_update_result()->updated_items.size());
+ EXPECT_EQ(request1, this->last_update_result()->updated_items.at(0));
+ EXPECT_EQ(request2, this->last_update_result()->updated_items.at(1));
this->ClearResults();
store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
@@ -276,24 +336,33 @@ TYPED_TEST(RequestQueueStoreTest, RemoveRequest) {
ASSERT_TRUE(this->last_requests().empty());
this->ClearResults();
- // Removing a request that is missing fails.
- store->RemoveRequests(request_ids,
- base::Bind(&RequestQueueStoreTestBase::RemoveDone,
- base::Unretained(this)));
- ASSERT_EQ(LastResult::kNone, this->last_result());
- ASSERT_EQ(0, this->last_remove_count());
+ // Try to remove a request that is not in the queue.
+ store->RemoveRequests(
+ request_ids, base::Bind(&RequestQueueStoreTestBase::UpdateRequestDone,
+ base::Unretained(this)));
+ ASSERT_FALSE(this->last_update_result());
this->PumpLoop();
- ASSERT_EQ(LastResult::kTrue, this->last_result());
- ASSERT_EQ(0, this->last_remove_count());
+ ASSERT_TRUE(this->last_update_result());
+ // When requests are missing, we expect the results to say so, but since they
+ // are missing, no requests should have been returned.
+ EXPECT_EQ(2UL, this->last_update_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId, this->last_update_result()->item_statuses[0].first);
+ EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+ this->last_update_result()->item_statuses[0].second);
+ EXPECT_EQ(kRequestId2, this->last_update_result()->item_statuses[1].first);
+ EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+ this->last_update_result()->item_statuses[1].second);
+ EXPECT_EQ(0UL, this->last_update_result()->updated_items.size());
}
TYPED_TEST(RequestQueueStoreTest, ResetStore) {
std::unique_ptr<RequestQueueStore> store(this->BuildStore());
base::Time creation_time = base::Time::Now();
- SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time);
- store->AddOrUpdateRequest(
- original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
- base::Unretained(this)));
+ SavePageRequest original_request(
+ kRequestId, kUrl, kClientId, creation_time, kUserRequested);
+ store->AddRequest(original_request,
+ base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
this->PumpLoop();
this->ClearResults();
@@ -319,10 +388,11 @@ class RequestQueueStoreSQLTest
TEST_F(RequestQueueStoreSQLTest, SaveCloseReopenRead) {
std::unique_ptr<RequestQueueStore> store(BuildStore());
base::Time creation_time = base::Time::Now();
- SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time);
- store->AddOrUpdateRequest(
- original_request, base::Bind(&RequestQueueStoreTestBase::AddOrUpdateDone,
- base::Unretained(this)));
+ SavePageRequest original_request(
+ kRequestId, kUrl, kClientId, creation_time, kUserRequested);
+ store->AddRequest(original_request,
+ base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
ClearResults();
@@ -336,7 +406,7 @@ TEST_F(RequestQueueStoreSQLTest, SaveCloseReopenRead) {
this->PumpLoop();
ASSERT_EQ(LastResult::kTrue, this->last_result());
ASSERT_EQ(1ul, this->last_requests().size());
- ASSERT_TRUE(original_request == this->last_requests()[0]);
+ ASSERT_TRUE(original_request == *(this->last_requests().at(0).get()));
}
} // offline_pages
diff --git a/chromium/components/offline_pages/background/request_queue_unittest.cc b/chromium/components/offline_pages/background/request_queue_unittest.cc
index 85628d1ee55..9358a34d1f5 100644
--- a/chromium/components/offline_pages/background/request_queue_unittest.cc
+++ b/chromium/components/offline_pages/background/request_queue_unittest.cc
@@ -24,10 +24,13 @@ namespace {
const int64_t kRequestId = 42;
const GURL kUrl("http://example.com");
const ClientId kClientId("bookmark", "1234");
+const int64_t kRetryCount = 2;
// Data for request 2.
const int64_t kRequestId2 = 77;
const GURL kUrl2("http://test.com");
const ClientId kClientId2("bookmark", "567");
+const bool kUserRequested = true;
+const int64_t kRequestId3 = 99;
} // namespace
// TODO(fgorski): Add tests for store failures in add/remove/get.
@@ -45,9 +48,10 @@ class RequestQueueTest : public testing::Test {
void AddRequestDone(AddRequestResult result, const SavePageRequest& request);
// Callback for getting requests.
void GetRequestsDone(GetRequestsResult result,
- const std::vector<SavePageRequest>& requests);
- // Callback for removing request.
- void RemoveRequestDone(UpdateRequestResult result);
+ std::vector<std::unique_ptr<SavePageRequest>> requests);
+
+ void UpdateRequestDone(UpdateRequestResult result);
+ void UpdateRequestsDone(std::unique_ptr<UpdateRequestsResult> result);
RequestQueue* queue() { return queue_.get(); }
@@ -56,23 +60,28 @@ class RequestQueueTest : public testing::Test {
return last_added_request_.get();
}
- UpdateRequestResult last_remove_result() const { return last_remove_result_; }
+ UpdateRequestResult last_update_result() const { return last_update_result_; }
GetRequestsResult last_get_requests_result() const {
return last_get_requests_result_;
}
- const std::vector<SavePageRequest>& last_requests() const {
+
+ const std::vector<std::unique_ptr<SavePageRequest>>& last_requests() const {
return last_requests_;
}
+ UpdateRequestsResult* update_requests_result() const {
+ return update_requests_result_.get();
+ }
+
private:
AddRequestResult last_add_result_;
std::unique_ptr<SavePageRequest> last_added_request_;
-
- UpdateRequestResult last_remove_result_;
+ std::unique_ptr<UpdateRequestsResult> update_requests_result_;
+ UpdateRequestResult last_update_result_;
GetRequestsResult last_get_requests_result_;
- std::vector<SavePageRequest> last_requests_;
+ std::vector<std::unique_ptr<SavePageRequest>> last_requests_;
std::unique_ptr<RequestQueue> queue_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
@@ -81,7 +90,7 @@ class RequestQueueTest : public testing::Test {
RequestQueueTest::RequestQueueTest()
: last_add_result_(AddRequestResult::STORE_FAILURE),
- last_remove_result_(UpdateRequestResult::STORE_FAILURE),
+ last_update_result_(UpdateRequestResult::STORE_FAILURE),
last_get_requests_result_(GetRequestsResult::STORE_FAILURE),
task_runner_(new base::TestSimpleTaskRunner),
task_runner_handle_(task_runner_) {}
@@ -106,13 +115,18 @@ void RequestQueueTest::AddRequestDone(AddRequestResult result,
void RequestQueueTest::GetRequestsDone(
GetRequestsResult result,
- const std::vector<SavePageRequest>& requests) {
+ std::vector<std::unique_ptr<SavePageRequest>> requests) {
last_get_requests_result_ = result;
- last_requests_ = requests;
+ last_requests_ = std::move(requests);
}
-void RequestQueueTest::RemoveRequestDone(UpdateRequestResult result) {
- last_remove_result_ = result;
+void RequestQueueTest::UpdateRequestDone(UpdateRequestResult result) {
+ last_update_result_ = result;
+}
+
+void RequestQueueTest::UpdateRequestsDone(
+ std::unique_ptr<UpdateRequestsResult> result) {
+ update_requests_result_ = std::move(result);
}
TEST_F(RequestQueueTest, GetRequestsEmpty) {
@@ -125,7 +139,8 @@ TEST_F(RequestQueueTest, GetRequestsEmpty) {
TEST_F(RequestQueueTest, AddRequest) {
base::Time creation_time = base::Time::Now();
- SavePageRequest request(kRequestId, kUrl, kClientId, creation_time);
+ SavePageRequest request(
+ kRequestId, kUrl, kClientId, creation_time, kUserRequested);
queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
base::Unretained(this)));
PumpLoop();
@@ -142,17 +157,24 @@ TEST_F(RequestQueueTest, AddRequest) {
TEST_F(RequestQueueTest, RemoveRequest) {
base::Time creation_time = base::Time::Now();
- SavePageRequest request(kRequestId, kUrl, kClientId, creation_time);
+ SavePageRequest request(
+ kRequestId, kUrl, kClientId, creation_time, kUserRequested);
queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
base::Unretained(this)));
PumpLoop();
ASSERT_EQ(kRequestId, last_added_request()->request_id());
- queue()->RemoveRequest(
- kRequestId,
- base::Bind(&RequestQueueTest::RemoveRequestDone, base::Unretained(this)));
+ std::vector<int64_t> remove_requests{kRequestId};
+ queue()->RemoveRequests(remove_requests,
+ base::Bind(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
- ASSERT_EQ(UpdateRequestResult::SUCCESS, last_remove_result());
+ EXPECT_EQ(1ul, update_requests_result()->item_statuses.size());
+ EXPECT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ update_requests_result()->item_statuses.at(0).second);
+ EXPECT_EQ(1UL, update_requests_result()->updated_items.size());
+ EXPECT_EQ(request, update_requests_result()->updated_items.at(0));
queue()->GetRequests(
base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
@@ -161,16 +183,132 @@ TEST_F(RequestQueueTest, RemoveRequest) {
ASSERT_EQ(0ul, last_requests().size());
}
+TEST_F(RequestQueueTest, RemoveSeveralRequests) {
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
+ kUserRequested);
+ queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+ ASSERT_EQ(kRequestId, last_added_request()->request_id());
+
+ SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
+ kUserRequested);
+ queue()->AddRequest(request2, base::Bind(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+ ASSERT_EQ(kRequestId2, last_added_request()->request_id());
+
+ std::vector<int64_t> remove_requests;
+ remove_requests.push_back(kRequestId);
+ remove_requests.push_back(kRequestId2);
+ remove_requests.push_back(kRequestId3);
+ queue()->RemoveRequests(remove_requests,
+ base::Bind(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
+ PumpLoop();
+ ASSERT_EQ(3ul, update_requests_result()->item_statuses.size());
+ ASSERT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
+ ASSERT_EQ(ItemActionStatus::SUCCESS,
+ update_requests_result()->item_statuses.at(0).second);
+ ASSERT_EQ(kRequestId2, update_requests_result()->item_statuses.at(1).first);
+ ASSERT_EQ(ItemActionStatus::SUCCESS,
+ update_requests_result()->item_statuses.at(1).second);
+ ASSERT_EQ(kRequestId3, update_requests_result()->item_statuses.at(2).first);
+ ASSERT_EQ(ItemActionStatus::NOT_FOUND,
+ update_requests_result()->item_statuses.at(2).second);
+ EXPECT_EQ(2UL, update_requests_result()->updated_items.size());
+ EXPECT_EQ(request, update_requests_result()->updated_items.at(0));
+ EXPECT_EQ(request2, update_requests_result()->updated_items.at(1));
+
+ queue()->GetRequests(
+ base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ PumpLoop();
+
+ // Verify both requests are no longer in the queue.
+ ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
+ ASSERT_EQ(0ul, last_requests().size());
+}
+
+TEST_F(RequestQueueTest, PauseAndResume) {
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
+ kUserRequested);
+ queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+ ASSERT_EQ(kRequestId, last_added_request()->request_id());
+
+ queue()->GetRequests(
+ base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ PumpLoop();
+ ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
+ ASSERT_EQ(1ul, last_requests().size());
+
+ std::vector<int64_t> request_ids;
+ request_ids.push_back(kRequestId);
+
+ // Pause the request.
+ queue()->ChangeRequestsState(request_ids,
+ SavePageRequest::RequestState::PAUSED,
+ base::Bind(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
+ PumpLoop();
+ ASSERT_EQ(1ul, update_requests_result()->item_statuses.size());
+ ASSERT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
+ ASSERT_EQ(ItemActionStatus::SUCCESS,
+ update_requests_result()->item_statuses.at(0).second);
+ ASSERT_EQ(1ul, update_requests_result()->updated_items.size());
+ ASSERT_EQ(SavePageRequest::RequestState::PAUSED,
+ update_requests_result()->updated_items.at(0).request_state());
+
+ queue()->GetRequests(
+ base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ PumpLoop();
+
+ // Verify the request is paused.
+ ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
+ ASSERT_EQ(1ul, last_requests().size());
+ ASSERT_EQ(SavePageRequest::RequestState::PAUSED,
+ last_requests().at(0)->request_state());
+
+ // Resume the request.
+ queue()->ChangeRequestsState(request_ids,
+ SavePageRequest::RequestState::AVAILABLE,
+ base::Bind(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
+ PumpLoop();
+ ASSERT_EQ(1ul, update_requests_result()->item_statuses.size());
+ ASSERT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
+ ASSERT_EQ(ItemActionStatus::SUCCESS,
+ update_requests_result()->item_statuses.at(0).second);
+ ASSERT_EQ(1ul, update_requests_result()->updated_items.size());
+ ASSERT_EQ(SavePageRequest::RequestState::AVAILABLE,
+ update_requests_result()->updated_items.at(0).request_state());
+
+ queue()->GetRequests(
+ base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ PumpLoop();
+
+ // Verify the request is no longer paused.
+ ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
+ ASSERT_EQ(1ul, last_requests().size());
+ ASSERT_EQ(SavePageRequest::RequestState::AVAILABLE,
+ last_requests().at(0)->request_state());
+}
+
// A longer test populating the request queue with more than one item, properly
// listing multiple items and removing the right item.
TEST_F(RequestQueueTest, MultipleRequestsAddGetRemove) {
base::Time creation_time = base::Time::Now();
- SavePageRequest request1(kRequestId, kUrl, kClientId, creation_time);
+ SavePageRequest request1(
+ kRequestId, kUrl, kClientId, creation_time, kUserRequested);
queue()->AddRequest(request1, base::Bind(&RequestQueueTest::AddRequestDone,
base::Unretained(this)));
PumpLoop();
ASSERT_EQ(request1.request_id(), last_added_request()->request_id());
- SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time);
+ SavePageRequest request2(
+ kRequestId2, kUrl2, kClientId2, creation_time, kUserRequested);
queue()->AddRequest(request2, base::Bind(&RequestQueueTest::AddRequestDone,
base::Unretained(this)));
PumpLoop();
@@ -182,18 +320,68 @@ TEST_F(RequestQueueTest, MultipleRequestsAddGetRemove) {
ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
ASSERT_EQ(2ul, last_requests().size());
- queue()->RemoveRequest(
- request1.request_id(),
- base::Bind(&RequestQueueTest::RemoveRequestDone, base::Unretained(this)));
+ std::vector<int64_t> remove_requests;
+ remove_requests.push_back(request1.request_id());
+ queue()->RemoveRequests(remove_requests,
+ base::Bind(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
- ASSERT_EQ(UpdateRequestResult::SUCCESS, last_remove_result());
+ ASSERT_EQ(1ul, update_requests_result()->item_statuses.size());
+ ASSERT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
+ ASSERT_EQ(ItemActionStatus::SUCCESS,
+ update_requests_result()->item_statuses.at(0).second);
queue()->GetRequests(
base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
PumpLoop();
ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
ASSERT_EQ(1ul, last_requests().size());
- ASSERT_EQ(request2.request_id(), last_requests()[0].request_id());
+ ASSERT_EQ(request2.request_id(), last_requests().at(0)->request_id());
+}
+
+TEST_F(RequestQueueTest, UpdateRequest) {
+ // First add a request. Retry count will be set to 0.
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request(
+ kRequestId, kUrl, kClientId, creation_time, kUserRequested);
+ queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // Update the request, ensure it succeeded.
+ request.set_completed_attempt_count(kRetryCount);
+ queue()->UpdateRequest(
+ request,
+ base::Bind(&RequestQueueTest::UpdateRequestDone, base::Unretained(this)));
+ PumpLoop();
+ ASSERT_EQ(UpdateRequestResult::SUCCESS, last_update_result());
+
+ // Get the request, and verify the update took effect.
+ queue()->GetRequests(
+ base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ PumpLoop();
+ ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
+ ASSERT_EQ(1ul, last_requests().size());
+ ASSERT_EQ(kRetryCount, last_requests().at(0)->completed_attempt_count());
+}
+
+TEST_F(RequestQueueTest, UpdateRequestNotPresent) {
+ // First add a request. Retry count will be set to 0.
+ base::Time creation_time = base::Time::Now();
+ SavePageRequest request1(
+ kRequestId, kUrl, kClientId, creation_time, kUserRequested);
+ SavePageRequest request2(
+ kRequestId2, kUrl2, kClientId2, creation_time, kUserRequested);
+ queue()->AddRequest(request2, base::Bind(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
+ PumpLoop();
+
+ // Try to update request1 when only request2 is in the queue.
+ queue()->UpdateRequest(
+ request1,
+ base::Bind(&RequestQueueTest::UpdateRequestDone, base::Unretained(this)));
+ PumpLoop();
+ ASSERT_EQ(UpdateRequestResult::REQUEST_DOES_NOT_EXIST, last_update_result());
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/save_page_request.cc b/chromium/components/offline_pages/background/save_page_request.cc
index fba16e6c100..77bc85ff1d8 100644
--- a/chromium/components/offline_pages/background/save_page_request.cc
+++ b/chromium/components/offline_pages/background/save_page_request.cc
@@ -9,25 +9,33 @@ namespace offline_pages {
SavePageRequest::SavePageRequest(int64_t request_id,
const GURL& url,
const ClientId& client_id,
- const base::Time& creation_time)
+ const base::Time& creation_time,
+ const bool user_requested)
: request_id_(request_id),
url_(url),
client_id_(client_id),
creation_time_(creation_time),
activation_time_(creation_time),
- attempt_count_(0) {}
+ started_attempt_count_(0),
+ completed_attempt_count_(0),
+ user_requested_(user_requested),
+ state_(RequestState::AVAILABLE) {}
SavePageRequest::SavePageRequest(int64_t request_id,
const GURL& url,
const ClientId& client_id,
const base::Time& creation_time,
- const base::Time& activation_time)
+ const base::Time& activation_time,
+ const bool user_requested)
: request_id_(request_id),
url_(url),
client_id_(client_id),
creation_time_(creation_time),
activation_time_(activation_time),
- attempt_count_(0) {}
+ started_attempt_count_(0),
+ completed_attempt_count_(0),
+ user_requested_(user_requested),
+ state_(RequestState::AVAILABLE) {}
SavePageRequest::SavePageRequest(const SavePageRequest& other)
: request_id_(other.request_id_),
@@ -35,29 +43,24 @@ SavePageRequest::SavePageRequest(const SavePageRequest& other)
client_id_(other.client_id_),
creation_time_(other.creation_time_),
activation_time_(other.activation_time_),
- attempt_count_(other.attempt_count_),
- last_attempt_time_(other.last_attempt_time_) {}
+ started_attempt_count_(other.started_attempt_count_),
+ completed_attempt_count_(other.completed_attempt_count_),
+ last_attempt_time_(other.last_attempt_time_),
+ user_requested_(other.user_requested_),
+ state_(other.state_) {}
SavePageRequest::~SavePageRequest() {}
-// TODO(fgorski): Introduce policy parameter, once policy is available.
-SavePageRequest::Status SavePageRequest::GetStatus(
- const base::Time& now) const {
- if (now < activation_time_)
- return Status::NOT_READY;
-
- // TODO(fgorski): enable check once policy available.
- // if (attempt_count_ >= policy.max_attempt_count)
- // return Status::FAILED;
-
- // TODO(fgorski): enable check once policy available.
- // if (activation_time_+ policy.page_expiration_interval < now)
- // return Status::EXPIRED;
-
- if (creation_time_ < last_attempt_time_)
- return Status::STARTED;
-
- return Status::PENDING;
+bool SavePageRequest::operator==(const SavePageRequest& other) const {
+ return request_id_ == other.request_id_ &&
+ url_ == other.url_ &&
+ client_id_ == other.client_id_ &&
+ creation_time_ == other.creation_time_ &&
+ activation_time_ == other.activation_time_ &&
+ started_attempt_count_ == other.started_attempt_count_ &&
+ completed_attempt_count_ == other.completed_attempt_count_ &&
+ last_attempt_time_ == other.last_attempt_time_ &&
+ state_ == other.state_;
}
void SavePageRequest::MarkAttemptStarted(const base::Time& start_time) {
@@ -66,11 +69,25 @@ void SavePageRequest::MarkAttemptStarted(const base::Time& start_time) {
// check here to ensure we only start tasks in status pending, and bail out in
// other cases.
last_attempt_time_ = start_time;
- ++attempt_count_;
+ ++started_attempt_count_;
+ state_ = RequestState::PRERENDERING;
}
void SavePageRequest::MarkAttemptCompleted() {
- last_attempt_time_ = base::Time();
+ ++completed_attempt_count_;
+ state_ = RequestState::AVAILABLE;
+}
+
+void SavePageRequest::MarkAttemptAborted() {
+ DCHECK_GT(started_attempt_count_, 0);
+ // We intentinally do not increment the completed_attempt_count_, since this
+ // was killed before it completed, so we could use the phone or browser for
+ // other things.
+ state_ = RequestState::AVAILABLE;
+}
+
+void SavePageRequest::MarkAttemptPaused() {
+ state_ = RequestState::PAUSED;
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/save_page_request.h b/chromium/components/offline_pages/background/save_page_request.h
index afc6bd7ee39..8af97d9baf5 100644
--- a/chromium/components/offline_pages/background/save_page_request.h
+++ b/chromium/components/offline_pages/background/save_page_request.h
@@ -16,31 +16,28 @@ namespace offline_pages {
// Class representing a request to save page.
class SavePageRequest {
public:
- enum class Status {
- NOT_READY, // Component requested a page be saved, but not until
- // |activation_time_|.
- PENDING, // Page request is pending, and coordinator can attempt it
- // when it gets a chance to.
- STARTED, // The request is currently being processed.
- FAILED, // Page request failed many times and will no longer be
- // retried.
- EXPIRED, // Save page request expired without being fulfilled.
+ // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.offlinepages
+ enum class RequestState {
+ AVAILABLE = 0, // Request can be scheduled when preconditions are met.
+ PAUSED = 1, // Request is not available until it is unpaused
+ PRERENDERING = 2, // Request is active in the pre-renderer
};
SavePageRequest(int64_t request_id,
const GURL& url,
const ClientId& client_id,
- const base::Time& creation_time);
+ const base::Time& creation_time,
+ const bool user_requested);
SavePageRequest(int64_t request_id,
const GURL& url,
const ClientId& client_id,
const base::Time& creation_time,
- const base::Time& activation_time);
+ const base::Time& activation_time,
+ const bool user_requested);
SavePageRequest(const SavePageRequest& other);
~SavePageRequest();
- // Status of this request.
- Status GetStatus(const base::Time& now) const;
+ bool operator==(const SavePageRequest& other) const;
// Updates the |last_attempt_time_| and increments |attempt_count_|.
void MarkAttemptStarted(const base::Time& start_time);
@@ -48,19 +45,35 @@ class SavePageRequest {
// Marks attempt as completed and clears |last_attempt_time_|.
void MarkAttemptCompleted();
+ // Marks attempt as aborted. Specifically it clears |last_attempt_time_|
+ // and decrements |attempt_count_|.
+ void MarkAttemptAborted();
+
+ // Mark the attempt as paused. It is not available for future prerendering
+ // until it has been explicitly unpaused.
+ void MarkAttemptPaused();
+
int64_t request_id() const { return request_id_; }
const GURL& url() const { return url_; }
const ClientId& client_id() const { return client_id_; }
+ RequestState request_state() const { return state_; }
+ void set_request_state(RequestState new_state) { state_ = new_state; }
+
const base::Time& creation_time() const { return creation_time_; }
const base::Time& activation_time() const { return activation_time_; }
- int64_t attempt_count() const { return attempt_count_; }
- void set_attempt_count(int64_t attempt_count) {
- attempt_count_ = attempt_count;
+ int64_t started_attempt_count() const { return started_attempt_count_; }
+ void set_started_attempt_count(int64_t started_attempt_count) {
+ started_attempt_count_ = started_attempt_count;
+ }
+
+ int64_t completed_attempt_count() const { return completed_attempt_count_; }
+ void set_completed_attempt_count(int64_t completed_attempt_count) {
+ completed_attempt_count_ = completed_attempt_count;
}
const base::Time& last_attempt_time() const { return last_attempt_time_; }
@@ -68,6 +81,12 @@ class SavePageRequest {
last_attempt_time_ = last_attempt_time;
}
+ bool user_requested() const { return user_requested_; }
+
+ void set_user_requested(bool user_requested) {
+ user_requested_ = user_requested;
+ }
+
private:
// ID of this request.
int64_t request_id_;
@@ -85,11 +104,22 @@ class SavePageRequest {
// Time when this request will become active.
base::Time activation_time_;
- // Number of attempts made to get the page.
- int attempt_count_;
+ // Number of attempts started to get the page. This may be different than the
+ // number of attempts completed because we could crash.
+ int started_attempt_count_;
+
+ // Number of attempts we actually completed to get the page.
+ int completed_attempt_count_;
// Timestamp of the last request starting.
base::Time last_attempt_time_;
+
+ // Whether the user specifically requested this page (as opposed to a client
+ // like AGSA or Now.)
+ bool user_requested_;
+
+ // The current state of this request
+ RequestState state_;
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/save_page_request_unittest.cc b/chromium/components/offline_pages/background/save_page_request_unittest.cc
index bec07f295d6..0f31d4e07a9 100644
--- a/chromium/components/offline_pages/background/save_page_request_unittest.cc
+++ b/chromium/components/offline_pages/background/save_page_request_unittest.cc
@@ -12,6 +12,7 @@ namespace {
const int64_t kRequestId = 42;
const GURL kUrl("http://example.com");
const ClientId kClientId("bookmark", "1234");
+const bool kUserRequested = true;
} // namespace
class SavePageRequestTest : public testing::Test {
@@ -23,49 +24,62 @@ SavePageRequestTest::~SavePageRequestTest() {}
TEST_F(SavePageRequestTest, CreatePendingReqeust) {
base::Time creation_time = base::Time::Now();
- SavePageRequest request(kRequestId, kUrl, kClientId, creation_time);
+ SavePageRequest request(
+ kRequestId, kUrl, kClientId, creation_time, kUserRequested);
ASSERT_EQ(kRequestId, request.request_id());
ASSERT_EQ(kUrl, request.url());
ASSERT_EQ(kClientId, request.client_id());
ASSERT_EQ(creation_time, request.creation_time());
ASSERT_EQ(creation_time, request.activation_time());
ASSERT_EQ(base::Time(), request.last_attempt_time());
- ASSERT_EQ(0, request.attempt_count());
-
- base::Time after_creation = creation_time + base::TimeDelta::FromHours(6);
- ASSERT_EQ(SavePageRequest::Status::PENDING,
- request.GetStatus(after_creation));
+ ASSERT_EQ(0, request.completed_attempt_count());
+ ASSERT_EQ(SavePageRequest::RequestState::AVAILABLE, request.request_state());
+ ASSERT_EQ(0, request.started_attempt_count());
+ ASSERT_EQ(0, request.completed_attempt_count());
}
-TEST_F(SavePageRequestTest, CreateNotReadyRequest) {
+TEST_F(SavePageRequestTest, StartAndCompleteRequest) {
base::Time creation_time = base::Time::Now();
base::Time activation_time = creation_time + base::TimeDelta::FromHours(6);
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
- activation_time);
+ activation_time, kUserRequested);
+ base::Time start_time = activation_time + base::TimeDelta::FromHours(3);
+ request.MarkAttemptStarted(start_time);
+
+ // Most things don't change about the request.
ASSERT_EQ(kRequestId, request.request_id());
ASSERT_EQ(kUrl, request.url());
ASSERT_EQ(kClientId, request.client_id());
ASSERT_EQ(creation_time, request.creation_time());
ASSERT_EQ(activation_time, request.activation_time());
- ASSERT_EQ(base::Time(), request.last_attempt_time());
- ASSERT_EQ(0, request.attempt_count());
- base::Time not_ready_time = activation_time - base::TimeDelta::FromHours(3);
- ASSERT_EQ(SavePageRequest::Status::NOT_READY,
- request.GetStatus(not_ready_time));
+ // Attempt time, attempt count and status will though.
+ ASSERT_EQ(start_time, request.last_attempt_time());
+ ASSERT_EQ(1, request.started_attempt_count());
+ ASSERT_EQ(SavePageRequest::RequestState::PRERENDERING,
+ request.request_state());
+
+ request.MarkAttemptCompleted();
- base::Time ready_time = activation_time + base::TimeDelta::FromHours(3);
- ASSERT_EQ(SavePageRequest::Status::PENDING, request.GetStatus(ready_time));
+ // Again, most things don't change about the request.
+ ASSERT_EQ(kRequestId, request.request_id());
+ ASSERT_EQ(kUrl, request.url());
+ ASSERT_EQ(kClientId, request.client_id());
+ ASSERT_EQ(creation_time, request.creation_time());
+ ASSERT_EQ(activation_time, request.activation_time());
+
+ // Last attempt time and status are updated.
+ ASSERT_EQ(1, request.completed_attempt_count());
+ ASSERT_EQ(SavePageRequest::RequestState::AVAILABLE, request.request_state());
}
-TEST_F(SavePageRequestTest, StartAndCompleteRequest) {
+TEST_F(SavePageRequestTest, StartAndAbortRequest) {
base::Time creation_time = base::Time::Now();
- base::Time activation_time = creation_time + base::TimeDelta::FromHours(6);
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
- activation_time);
+ kUserRequested);
- base::Time start_time = activation_time + base::TimeDelta::FromHours(3);
+ base::Time start_time = creation_time + base::TimeDelta::FromHours(3);
request.MarkAttemptStarted(start_time);
// Most things don't change about the request.
@@ -73,27 +87,24 @@ TEST_F(SavePageRequestTest, StartAndCompleteRequest) {
ASSERT_EQ(kUrl, request.url());
ASSERT_EQ(kClientId, request.client_id());
ASSERT_EQ(creation_time, request.creation_time());
- ASSERT_EQ(activation_time, request.activation_time());
- // Attempt time, attempt count and status will though.
+ // Attempt time and attempt count will though.
ASSERT_EQ(start_time, request.last_attempt_time());
- ASSERT_EQ(1, request.attempt_count());
-
- ASSERT_EQ(SavePageRequest::Status::STARTED, request.GetStatus(start_time));
+ ASSERT_EQ(1, request.started_attempt_count());
+ ASSERT_EQ(SavePageRequest::RequestState::PRERENDERING,
+ request.request_state());
- request.MarkAttemptCompleted();
+ request.MarkAttemptAborted();
// Again, most things don't change about the request.
ASSERT_EQ(kRequestId, request.request_id());
ASSERT_EQ(kUrl, request.url());
ASSERT_EQ(kClientId, request.client_id());
ASSERT_EQ(creation_time, request.creation_time());
- ASSERT_EQ(activation_time, request.activation_time());
- // Last attempt time, status and attempt count are updated.
- ASSERT_EQ(base::Time(), request.last_attempt_time());
- ASSERT_EQ(1, request.attempt_count());
- ASSERT_EQ(SavePageRequest::Status::PENDING, request.GetStatus(start_time));
+ // Last attempt time is updated and completed attempt count did not rise.
+ ASSERT_EQ(0, request.completed_attempt_count());
+ ASSERT_EQ(SavePageRequest::RequestState::AVAILABLE, request.request_state());
}
-} // offline_pages
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/background/scheduler.h b/chromium/components/offline_pages/background/scheduler.h
index 3344aebf1b3..b4a36fed4ae 100644
--- a/chromium/components/offline_pages/background/scheduler.h
+++ b/chromium/components/offline_pages/background/scheduler.h
@@ -30,7 +30,13 @@ class Scheduler {
// This may overwrite any previous scheduled task with a new one for
// these conditions. That is, only one set of triggering conditions
// is scheduled at a time.
- virtual void Schedule(const TriggerConditions& trigger_condition) = 0;
+ virtual void Schedule(const TriggerConditions& trigger_conditions) = 0;
+
+ // Schedules the triggering of a task in case Chromium is killed,
+ // so we can continue processing background download requests. This will
+ // not overwrite existing tasks.
+ virtual void BackupSchedule(const TriggerConditions& trigger_conditions,
+ long delay_in_seconds) = 0;
// Unschedules the currently scheduled task, if any.
virtual void Unschedule() = 0;
diff --git a/chromium/components/offline_pages/client_namespace_constants.cc b/chromium/components/offline_pages/client_namespace_constants.cc
index 508db279a45..d2f11bef2e6 100644
--- a/chromium/components/offline_pages/client_namespace_constants.cc
+++ b/chromium/components/offline_pages/client_namespace_constants.cc
@@ -8,6 +8,10 @@ namespace offline_pages {
const char kBookmarkNamespace[] = "bookmark";
const char kLastNNamespace[] = "last_n";
+const char kAsyncNamespace[] = "async_loading";
+const char kCCTNamespace[] = "custom_tabs";
+const char kDownloadNamespace[] = "download";
+const char kNTPSuggestionsNamespace[] = "ntp_suggestions";
const char kDefaultNamespace[] = "default";
diff --git a/chromium/components/offline_pages/client_namespace_constants.h b/chromium/components/offline_pages/client_namespace_constants.h
index 108e031516d..823af09cc00 100644
--- a/chromium/components/offline_pages/client_namespace_constants.h
+++ b/chromium/components/offline_pages/client_namespace_constants.h
@@ -13,6 +13,10 @@ namespace offline_pages {
// OfflinePagesNamespace (histograms.xml) for consistency.
extern const char kBookmarkNamespace[];
extern const char kLastNNamespace[];
+extern const char kAsyncNamespace[];
+extern const char kCCTNamespace[];
+extern const char kDownloadNamespace[];
+extern const char kNTPSuggestionsNamespace[];
// Currently used for fallbacks like tests.
extern const char kDefaultNamespace[];
diff --git a/chromium/components/offline_pages/client_policy_controller.cc b/chromium/components/offline_pages/client_policy_controller.cc
index 6f379dbecfc..e8742df441e 100644
--- a/chromium/components/offline_pages/client_policy_controller.cc
+++ b/chromium/components/offline_pages/client_policy_controller.cc
@@ -24,6 +24,32 @@ ClientPolicyController::ClientPolicyController() {
kLastNNamespace, MakePolicy(kLastNNamespace, LifetimeType::TEMPORARY,
base::TimeDelta::FromDays(2), kUnlimitedPages,
kUnlimitedPages)));
+ policies_.insert(std::make_pair(
+ kAsyncNamespace,
+ OfflinePageClientPolicyBuilder(kAsyncNamespace, LifetimeType::PERSISTENT,
+ kUnlimitedPages, kUnlimitedPages)
+ .SetIsSupportedByDownload(true)
+ .SetIsRemovedOnCacheReset(false)
+ .Build()));
+ policies_.insert(std::make_pair(
+ kCCTNamespace,
+ MakePolicy(kCCTNamespace, LifetimeType::TEMPORARY,
+ base::TimeDelta::FromDays(2), kUnlimitedPages, 1)));
+ policies_.insert(std::make_pair(
+ kDownloadNamespace, OfflinePageClientPolicyBuilder(
+ kDownloadNamespace, LifetimeType::PERSISTENT,
+ kUnlimitedPages, kUnlimitedPages)
+ .SetIsRemovedOnCacheReset(false)
+ .SetIsSupportedByDownload(true)
+ .Build()));
+ policies_.insert(std::make_pair(
+ kNTPSuggestionsNamespace,
+ OfflinePageClientPolicyBuilder(kNTPSuggestionsNamespace,
+ LifetimeType::PERSISTENT, kUnlimitedPages,
+ kUnlimitedPages)
+ .SetIsSupportedByDownload(true)
+ .Build()));
+
// Fallback policy.
policies_.insert(std::make_pair(
kDefaultNamespace, MakePolicy(kDefaultNamespace, LifetimeType::TEMPORARY,
@@ -39,10 +65,10 @@ const OfflinePageClientPolicy ClientPolicyController::MakePolicy(
const base::TimeDelta& expire_period,
size_t page_limit,
size_t pages_allowed_per_url) {
- OfflinePageClientPolicy policy({name_space,
- {lifetime_type, expire_period, page_limit},
- pages_allowed_per_url});
- return policy;
+ return OfflinePageClientPolicyBuilder(name_space, lifetime_type, page_limit,
+ pages_allowed_per_url)
+ .SetExpirePeriod(expire_period)
+ .Build();
}
const OfflinePageClientPolicy& ClientPolicyController::GetPolicy(
@@ -54,4 +80,14 @@ const OfflinePageClientPolicy& ClientPolicyController::GetPolicy(
return policies_.at(kDefaultNamespace);
}
+bool ClientPolicyController::IsRemovedOnCacheReset(
+ const std::string& name_space) const {
+ return GetPolicy(name_space).feature_policy.is_removed_on_cache_reset;
+}
+
+bool ClientPolicyController::IsSupportedByDownload(
+ const std::string& name_space) const {
+ return GetPolicy(name_space).feature_policy.is_supported_by_download;
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/client_policy_controller.h b/chromium/components/offline_pages/client_policy_controller.h
index 231d028d4a6..55da43d5965 100644
--- a/chromium/components/offline_pages/client_policy_controller.h
+++ b/chromium/components/offline_pages/client_policy_controller.h
@@ -33,6 +33,12 @@ class ClientPolicyController {
// Get the client policy for |name_space|.
const OfflinePageClientPolicy& GetPolicy(const std::string& name_space) const;
+ // Returns whether pages for |name_space| should be removed on cache reset.
+ bool IsRemovedOnCacheReset(const std::string& name_space) const;
+
+ // Returns whether pages for |name_space| are shown in Download UI.
+ bool IsSupportedByDownload(const std::string& name_space) const;
+
private:
// The map from name_space to a client policy. Will be generated
// as pre-defined values for now.
diff --git a/chromium/components/offline_pages/client_policy_controller_unittest.cc b/chromium/components/offline_pages/client_policy_controller_unittest.cc
index 918de56d593..787c4eca69f 100644
--- a/chromium/components/offline_pages/client_policy_controller_unittest.cc
+++ b/chromium/components/offline_pages/client_policy_controller_unittest.cc
@@ -17,12 +17,8 @@ namespace {
const char kUndefinedNamespace[] = "undefined";
bool isTemporary(const OfflinePageClientPolicy& policy) {
- // Check if policy has a expire period > 0 or a limited number
- // of pages allowed.
- return (policy.lifetime_policy.page_limit > kUnlimitedPages ||
- !policy.lifetime_policy.expiration_period.is_zero());
+ return policy.lifetime_policy.lifetime_type == LifetimeType::TEMPORARY;
}
-
} // namespace
class ClientPolicyControllerTest : public testing::Test {
@@ -49,18 +45,57 @@ TEST_F(ClientPolicyControllerTest, FallbackTest) {
OfflinePageClientPolicy policy = controller()->GetPolicy(kUndefinedNamespace);
EXPECT_EQ(policy.name_space, kDefaultNamespace);
EXPECT_TRUE(isTemporary(policy));
+ EXPECT_TRUE(controller()->IsRemovedOnCacheReset(kUndefinedNamespace));
+ EXPECT_FALSE(controller()->IsSupportedByDownload(kUndefinedNamespace));
}
TEST_F(ClientPolicyControllerTest, CheckBookmarkDefined) {
OfflinePageClientPolicy policy = controller()->GetPolicy(kBookmarkNamespace);
EXPECT_EQ(policy.name_space, kBookmarkNamespace);
EXPECT_TRUE(isTemporary(policy));
+ EXPECT_TRUE(controller()->IsRemovedOnCacheReset(kBookmarkNamespace));
+ EXPECT_FALSE(controller()->IsSupportedByDownload(kBookmarkNamespace));
}
TEST_F(ClientPolicyControllerTest, CheckLastNDefined) {
OfflinePageClientPolicy policy = controller()->GetPolicy(kLastNNamespace);
EXPECT_EQ(policy.name_space, kLastNNamespace);
EXPECT_TRUE(isTemporary(policy));
+ EXPECT_TRUE(controller()->IsRemovedOnCacheReset(kLastNNamespace));
+ EXPECT_FALSE(controller()->IsSupportedByDownload(kLastNNamespace));
+}
+
+TEST_F(ClientPolicyControllerTest, CheckAsyncDefined) {
+ OfflinePageClientPolicy policy = controller()->GetPolicy(kAsyncNamespace);
+ EXPECT_EQ(policy.name_space, kAsyncNamespace);
+ EXPECT_FALSE(isTemporary(policy));
+ EXPECT_FALSE(controller()->IsRemovedOnCacheReset(kAsyncNamespace));
+ EXPECT_TRUE(controller()->IsSupportedByDownload(kAsyncNamespace));
+}
+
+TEST_F(ClientPolicyControllerTest, CheckCCTDefined) {
+ OfflinePageClientPolicy policy = controller()->GetPolicy(kCCTNamespace);
+ EXPECT_EQ(policy.name_space, kCCTNamespace);
+ EXPECT_TRUE(isTemporary(policy));
+ EXPECT_TRUE(controller()->IsRemovedOnCacheReset(kCCTNamespace));
+ EXPECT_FALSE(controller()->IsSupportedByDownload(kCCTNamespace));
+}
+
+TEST_F(ClientPolicyControllerTest, CheckDownloadDefined) {
+ OfflinePageClientPolicy policy = controller()->GetPolicy(kDownloadNamespace);
+ EXPECT_EQ(policy.name_space, kDownloadNamespace);
+ EXPECT_FALSE(isTemporary(policy));
+ EXPECT_FALSE(controller()->IsRemovedOnCacheReset(kDownloadNamespace));
+ EXPECT_TRUE(controller()->IsSupportedByDownload(kDownloadNamespace));
+}
+
+TEST_F(ClientPolicyControllerTest, CheckNTPSuggestionsDefined) {
+ OfflinePageClientPolicy policy =
+ controller()->GetPolicy(kNTPSuggestionsNamespace);
+ EXPECT_EQ(policy.name_space, kNTPSuggestionsNamespace);
+ EXPECT_FALSE(isTemporary(policy));
+ EXPECT_TRUE(controller()->IsRemovedOnCacheReset(kNTPSuggestionsNamespace));
+ EXPECT_TRUE(controller()->IsSupportedByDownload(kNTPSuggestionsNamespace));
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/BUILD.gn b/chromium/components/offline_pages/core/BUILD.gn
new file mode 100644
index 00000000000..d84ddee4082
--- /dev/null
+++ b/chromium/components/offline_pages/core/BUILD.gn
@@ -0,0 +1,49 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
+static_library("core") {
+ sources = [
+ "task.cc",
+ "task.h",
+ "task_queue.cc",
+ "task_queue.h",
+ ]
+
+ deps = [
+ "//base",
+ ]
+}
+
+static_library("test_support") {
+ testonly = true
+ sources = [
+ "test_task.cc",
+ "test_task.h",
+ ]
+
+ deps = [
+ ":core",
+ "//base",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "task_queue_unittest.cc",
+ "task_unittest.cc",
+ ]
+
+ deps = [
+ ":core",
+ ":test_support",
+ "//base",
+ "//base/test:test_support",
+ "//testing/gtest:gtest",
+ ]
+}
diff --git a/chromium/components/offline_pages/core/task.cc b/chromium/components/offline_pages/core/task.cc
new file mode 100644
index 00000000000..1bf7a7d5503
--- /dev/null
+++ b/chromium/components/offline_pages/core/task.cc
@@ -0,0 +1,43 @@
+// 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 "components/offline_pages/core/task.h"
+
+#include "base/bind.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace offline_pages {
+
+Task::Task() {}
+
+Task::~Task() {}
+
+void Task::SetTaskCompletionCallbackForTesting(
+ scoped_refptr<base::SingleThreadTaskRunner> task_completion_runner,
+ const TaskCompletionCallback& task_completion_callback) {
+ SetTaskCompletionCallback(task_completion_runner, task_completion_callback);
+}
+
+void Task::SetTaskCompletionCallback(
+ scoped_refptr<base::SingleThreadTaskRunner> task_completion_runner,
+ const TaskCompletionCallback& task_completion_callback) {
+ // Attempts to enforce that SetTaskCompletionCallback is at most called once
+ // and enforces that reasonable values are set once that happens.
+ DCHECK(!task_completion_runner_);
+ DCHECK(task_completion_runner);
+ DCHECK(task_completion_callback_.is_null());
+ DCHECK(!task_completion_callback.is_null());
+ task_completion_runner_ = task_completion_runner;
+ task_completion_callback_ = task_completion_callback;
+}
+
+void Task::TaskComplete() {
+ if (task_completion_callback_.is_null() || !task_completion_runner_)
+ return;
+
+ task_completion_runner_->PostTask(
+ FROM_HERE, base::Bind(task_completion_callback_, this));
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/task.h b/chromium/components/offline_pages/core/task.h
new file mode 100644
index 00000000000..4d77679ce07
--- /dev/null
+++ b/chromium/components/offline_pages/core/task.h
@@ -0,0 +1,82 @@
+// 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 COMPONENTS_OFFLINE_PAGES_CORE_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_TASK_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+
+namespace offline_pages {
+
+// Task interface for consumers of the TaskQueue. Implements a mechanism for
+// task completion.
+//
+// To create your own Task:
+// * Derive your new task from offline_pages::Task.
+// * Implement your task with as many async operations on the controlled
+// resource as is required. (In general the smaller the task the better.)
+// * Whenever the task is terminated, call |Complete|.
+// * To schedule task for execution call |TaskQueue::AddTask|.
+//
+// If there is a chance that a task callback will come after the task is
+// destroyed, it is up to the task to actually implement mechanism to deal with
+// that, such as using a |base::WeakPtrFactory|.
+class Task {
+ public:
+ // Signature of the method to be called by a task, when its work is done.
+ typedef base::Callback<void(Task*)> TaskCompletionCallback;
+
+ Task();
+ virtual ~Task();
+
+ // Entry point to the task. This is used by the queue to start the task, and
+ // first step of the task should be implemented by overloading this method.
+ // The task should define an additional method for every asynchronous step,
+ // with each step setting up the next step as a callback.
+ // TODO(fgorski): Consider alternative: protected RunImpl(), so that we can
+ // add things like UMA in the Run method.
+ virtual void Run() = 0;
+
+ // Sets the callback normally used by |TaskQueue| for testing. See
+ // |SetTaskCompletionCallback| for details.
+ void SetTaskCompletionCallbackForTesting(
+ scoped_refptr<base::SingleThreadTaskRunner> task_completion_runner,
+ const TaskCompletionCallback& task_completion_callback);
+
+ protected:
+ // Call |TaskComplete| as the last call, before the task is terminated. This
+ // ensures that |TaskQueue| can pick up another task.
+ // |task_completion_callback_| will be scheduled on the provided
+ // |task_completion_runner_|, which means task code is no longer going to be
+ // on stack, when the next call is made.
+ void TaskComplete();
+
+ private:
+ friend class TaskQueue;
+
+ // Allows task queue to Set the |task_completion_callback| and single thread
+ // task |task_completion_runner| that will be used to inform the |TaskQueue|
+ // when the task is done.
+ //
+ // If the task is run outside of the |TaskQueue| and completion callback is
+ // not set, it will also work.
+ void SetTaskCompletionCallback(
+ scoped_refptr<base::SingleThreadTaskRunner> task_completion_runner,
+ const TaskCompletionCallback& task_completion_callback);
+
+ // Completion callback for this task set by |SetTaskCompletionCallback|.
+ TaskCompletionCallback task_completion_callback_;
+ // Task runner for calling completion callback. Set by
+ // |SetTaskCompletionCallback|.
+ scoped_refptr<base::SingleThreadTaskRunner> task_completion_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(Task);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_TASK_H_
diff --git a/chromium/components/offline_pages/core/task_queue.cc b/chromium/components/offline_pages/core/task_queue.cc
new file mode 100644
index 00000000000..115c509af1a
--- /dev/null
+++ b/chromium/components/offline_pages/core/task_queue.cc
@@ -0,0 +1,49 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/task_queue.h"
+
+#include "base/bind.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace offline_pages {
+
+TaskQueue::TaskQueue() : weak_ptr_factory_(this) {}
+
+TaskQueue::~TaskQueue() {}
+
+void TaskQueue::AddTask(std::unique_ptr<Task> task) {
+ task->SetTaskCompletionCallback(
+ base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&TaskQueue::TaskCompleted, weak_ptr_factory_.GetWeakPtr()));
+ tasks_.push(std::move(task));
+ MaybeStartTask();
+}
+
+bool TaskQueue::HasPendingTasks() const {
+ return !tasks_.empty() || HasRunningTask();
+}
+
+bool TaskQueue::HasRunningTask() const {
+ return current_task_.get() != nullptr;
+}
+
+void TaskQueue::MaybeStartTask() {
+ if (HasRunningTask() || !HasPendingTasks())
+ return;
+
+ current_task_ = std::move(tasks_.front());
+ tasks_.pop();
+ current_task_->Run();
+}
+
+void TaskQueue::TaskCompleted(Task* task) {
+ DCHECK_EQ(task, current_task_.get());
+ if (task == current_task_.get()) {
+ current_task_.reset(nullptr);
+ MaybeStartTask();
+ }
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/task_queue.h b/chromium/components/offline_pages/core/task_queue.h
new file mode 100644
index 00000000000..941c47632a9
--- /dev/null
+++ b/chromium/components/offline_pages/core/task_queue.h
@@ -0,0 +1,64 @@
+// 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 COMPONENTS_OFFLINE_PAGES_CORE_TASK_QUEUE_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_TASK_QUEUE_H_
+
+#include <memory>
+#include <queue>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+
+// Class for coordinating |Task|s in relation to access to a specific resource.
+// As a task, we understand a set of asynchronous operations (possibly switching
+// threads) that access a set of sensitive resource(s). Because the resource
+// state is modified and individual steps of a task are asynchronous, allowing
+// certain tasks to run in parallel may lead to incorrect results. This class
+// allows for ordering of tasks in a FIFO manner, to ensure two tasks modifying
+// a resources are not run at the same time.
+//
+// Consumers of this class should create an instance of TaskQueue and implement
+// tasks that need to be run sequentially. New task will only be started when
+// the previous one calls |Task::TaskComplete|.
+class TaskQueue {
+ public:
+ TaskQueue();
+ ~TaskQueue();
+
+ // Adds a task to the queue. Queue takes ownership of the task.
+ void AddTask(std::unique_ptr<Task> task);
+ // Whether the task queue has any pending (not-running) tasks.
+ bool HasPendingTasks() const;
+ // Whether there is a task currently running.
+ bool HasRunningTask() const;
+
+ private:
+ // Checks whether there are any tasks to run, as well as whether no task is
+ // currently running. When both are met, it will start the next task in the
+ // queue.
+ void MaybeStartTask();
+
+ // Callback for informing the queue that a task was completed.
+ void TaskCompleted(Task* task);
+
+ // Currently running tasks.
+ std::unique_ptr<Task> current_task_;
+
+ // A FIFO queue of tasks that will be run using this task queue.
+ std::queue<std::unique_ptr<Task>> tasks_;
+
+ base::WeakPtrFactory<TaskQueue> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskQueue);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_TASK_QUEUE_H_
diff --git a/chromium/components/offline_pages/core/task_queue_unittest.cc b/chromium/components/offline_pages/core/task_queue_unittest.cc
new file mode 100644
index 00000000000..426e55efaf0
--- /dev/null
+++ b/chromium/components/offline_pages/core/task_queue_unittest.cc
@@ -0,0 +1,123 @@
+// 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 "components/offline_pages/core/task_queue.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/test_task.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+using TaskState = TestTask::TaskState;
+
+class OfflineTaskQueueTest : public testing::Test {
+ public:
+ OfflineTaskQueueTest();
+
+ void TaskCompleted(Task* task);
+ void PumpLoop();
+
+ Task* completed_task() const { return completed_task_; }
+
+ private:
+ Task* completed_task_;
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle task_runner_handle_;
+};
+
+OfflineTaskQueueTest::OfflineTaskQueueTest()
+ : completed_task_(nullptr),
+ task_runner_(new base::TestSimpleTaskRunner),
+ task_runner_handle_(task_runner_) {}
+
+void OfflineTaskQueueTest::PumpLoop() {
+ task_runner_->RunUntilIdle();
+}
+
+void OfflineTaskQueueTest::TaskCompleted(Task* task) {
+ completed_task_ = task;
+}
+
+TEST_F(OfflineTaskQueueTest, AddAndRunSingleTask) {
+ ConsumedResource resource;
+ std::unique_ptr<TestTask> task(new TestTask(&resource));
+ TestTask* task_ptr = task.get();
+ TaskQueue queue;
+ EXPECT_EQ(TaskState::NOT_STARTED, task_ptr->state());
+ queue.AddTask(std::move(task));
+ EXPECT_TRUE(queue.HasPendingTasks());
+ EXPECT_TRUE(queue.HasRunningTask());
+ EXPECT_EQ(TaskState::STEP_1, task_ptr->state());
+ EXPECT_TRUE(resource.HasNextStep());
+ resource.CompleteStep();
+
+ EXPECT_EQ(TaskState::STEP_2, task_ptr->state());
+ EXPECT_TRUE(resource.HasNextStep());
+ resource.CompleteStep();
+
+ EXPECT_EQ(TaskState::COMPLETED, task_ptr->state());
+ EXPECT_FALSE(resource.HasNextStep());
+ PumpLoop(); // Deletes task, task_ptr is invalid after that.
+
+ EXPECT_FALSE(queue.HasRunningTask());
+ EXPECT_FALSE(queue.HasPendingTasks());
+}
+
+TEST_F(OfflineTaskQueueTest, AddAndRunMultipleTasks) {
+ ConsumedResource resource;
+ std::unique_ptr<TestTask> task_1(new TestTask(&resource));
+ TestTask* task_1_ptr = task_1.get();
+ std::unique_ptr<TestTask> task_2(new TestTask(&resource));
+ TestTask* task_2_ptr = task_2.get();
+
+ TaskQueue queue;
+ EXPECT_EQ(TaskState::NOT_STARTED, task_1_ptr->state());
+ EXPECT_EQ(TaskState::NOT_STARTED, task_2_ptr->state());
+ queue.AddTask(std::move(task_1));
+ queue.AddTask(std::move(task_2));
+ EXPECT_TRUE(queue.HasPendingTasks());
+ EXPECT_TRUE(queue.HasRunningTask());
+ EXPECT_EQ(TaskState::STEP_1, task_1_ptr->state());
+ EXPECT_EQ(TaskState::NOT_STARTED, task_2_ptr->state());
+ resource.CompleteStep();
+
+ EXPECT_EQ(TaskState::STEP_2, task_1_ptr->state());
+ EXPECT_EQ(TaskState::NOT_STARTED, task_2_ptr->state());
+ resource.CompleteStep();
+
+ EXPECT_EQ(TaskState::COMPLETED, task_1_ptr->state());
+ EXPECT_EQ(TaskState::NOT_STARTED, task_2_ptr->state());
+ PumpLoop(); // Deletes task_1, task_1_ptr is invalid after that.
+ EXPECT_EQ(TaskState::STEP_1, task_2_ptr->state());
+}
+
+TEST_F(OfflineTaskQueueTest, LeaveEarly) {
+ ConsumedResource resource;
+ std::unique_ptr<TestTask> task(
+ new TestTask(&resource, true /* leave early */));
+ TestTask* task_ptr = task.get();
+ TaskQueue queue;
+ EXPECT_EQ(TaskState::NOT_STARTED, task_ptr->state());
+ queue.AddTask(std::move(task));
+ EXPECT_TRUE(queue.HasPendingTasks());
+ EXPECT_TRUE(queue.HasRunningTask());
+ EXPECT_EQ(TaskState::STEP_1, task_ptr->state());
+ EXPECT_TRUE(resource.HasNextStep());
+ resource.CompleteStep();
+
+ // Notice STEP_2 was omitted and task went from STEP_1 to completed.
+ EXPECT_EQ(TaskState::COMPLETED, task_ptr->state());
+ EXPECT_FALSE(resource.HasNextStep());
+ PumpLoop(); // Deletes task, task_ptr is invalid after that.
+
+ EXPECT_FALSE(queue.HasPendingTasks());
+ EXPECT_FALSE(queue.HasRunningTask());
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/task_unittest.cc b/chromium/components/offline_pages/core/task_unittest.cc
new file mode 100644
index 00000000000..0574a7933cb
--- /dev/null
+++ b/chromium/components/offline_pages/core/task_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/task.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/test_task.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+using TaskState = TestTask::TaskState;
+
+class OfflineTaskTest : public testing::Test {
+ public:
+ OfflineTaskTest();
+
+ void TaskCompleted(Task* task);
+ void PumpLoop();
+
+ Task* completed_task() const { return completed_task_; }
+
+ private:
+ Task* completed_task_;
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ base::ThreadTaskRunnerHandle task_runner_handle_;
+};
+
+OfflineTaskTest::OfflineTaskTest()
+ : completed_task_(nullptr),
+ task_runner_(new base::TestSimpleTaskRunner),
+ task_runner_handle_(task_runner_) {}
+
+void OfflineTaskTest::PumpLoop() {
+ task_runner_->RunUntilIdle();
+}
+
+void OfflineTaskTest::TaskCompleted(Task* task) {
+ completed_task_ = task;
+}
+
+TEST_F(OfflineTaskTest, RunTaskStepByStep) {
+ ConsumedResource resource;
+ TestTask task(&resource);
+ task.SetTaskCompletionCallbackForTesting(
+ base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&OfflineTaskTest::TaskCompleted, base::Unretained(this)));
+
+ EXPECT_EQ(TaskState::NOT_STARTED, task.state());
+ task.Run();
+ EXPECT_EQ(TaskState::STEP_1, task.state());
+ EXPECT_TRUE(resource.HasNextStep());
+ resource.CompleteStep();
+ EXPECT_EQ(TaskState::STEP_2, task.state());
+ EXPECT_TRUE(resource.HasNextStep());
+ resource.CompleteStep();
+ EXPECT_EQ(TaskState::COMPLETED, task.state());
+ PumpLoop();
+ EXPECT_EQ(completed_task(), &task);
+}
+
+TEST_F(OfflineTaskTest, LeaveEarly) {
+ ConsumedResource resource;
+ TestTask task(&resource, true /* leave early */);
+ EXPECT_EQ(TaskState::NOT_STARTED, task.state());
+ task.Run();
+ EXPECT_EQ(TaskState::STEP_1, task.state());
+ EXPECT_TRUE(resource.HasNextStep());
+ resource.CompleteStep();
+
+ // Notice STEP_2 was omitted and task went from STEP_1 to completed.
+ EXPECT_EQ(TaskState::COMPLETED, task.state());
+ EXPECT_FALSE(resource.HasNextStep());
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/test_task.cc b/chromium/components/offline_pages/core/test_task.cc
new file mode 100644
index 00000000000..cd0ade91ffb
--- /dev/null
+++ b/chromium/components/offline_pages/core/test_task.cc
@@ -0,0 +1,58 @@
+// 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 "components/offline_pages/core/test_task.h"
+
+#include "base/bind.h"
+
+namespace offline_pages {
+
+ConsumedResource::ConsumedResource() {}
+
+ConsumedResource::~ConsumedResource() {}
+
+void ConsumedResource::Step(const base::Closure& step_callback) {
+ next_step_ = step_callback;
+}
+
+void ConsumedResource::CompleteStep() {
+ base::Closure temp_ = next_step_;
+ next_step_.Reset();
+ temp_.Run();
+}
+
+TestTask::TestTask(ConsumedResource* resource)
+ : resource_(resource),
+ state_(TaskState::NOT_STARTED),
+ leave_early_(false) {}
+
+TestTask::TestTask(ConsumedResource* resource, bool leave_early)
+ : resource_(resource),
+ state_(TaskState::NOT_STARTED),
+ leave_early_(leave_early) {}
+
+TestTask::~TestTask() {}
+
+// Run is Step 1 in our case.
+void TestTask::Run() {
+ state_ = TaskState::STEP_1;
+ resource_->Step(base::Bind(&TestTask::Step2, base::Unretained(this)));
+}
+
+void TestTask::Step2() {
+ if (leave_early_) {
+ LastStep();
+ return;
+ }
+ state_ = TaskState::STEP_2;
+ resource_->Step(base::Bind(&TestTask::LastStep, base::Unretained(this)));
+}
+
+// This is step 3, but we conclude here.
+void TestTask::LastStep() {
+ state_ = TaskState::COMPLETED;
+ TaskComplete();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/test_task.h b/chromium/components/offline_pages/core/test_task.h
new file mode 100644
index 00000000000..01e517f5592
--- /dev/null
+++ b/chromium/components/offline_pages/core/test_task.h
@@ -0,0 +1,59 @@
+// 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 COMPONENTS_OFFLINE_PAGES_CORE_TEST_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_TEST_TASK_H_
+
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+
+// Sample resource consumed by the task during execution. In this set of tests
+// used to provide the capability to continue the task.
+class ConsumedResource {
+ public:
+ ConsumedResource();
+ ~ConsumedResource();
+
+ void Step(const base::Closure& step_callback);
+ void CompleteStep();
+ bool HasNextStep() const { return !next_step_.is_null(); }
+
+ private:
+ base::Closure next_step_;
+};
+
+// Sample test task. This should not be used as a example of task implementation
+// with respect to callback safety. Otherwise it captures the idea of splitting
+// the work into multiple steps separated by potentially asynchronous calls
+// spanning multiple threads.
+//
+// For an implementation example of a task that covers problems better is
+// |offline_pages::ChangeRequestsStateTask|.
+class TestTask : public Task {
+ public:
+ enum class TaskState { NOT_STARTED, STEP_1, STEP_2, COMPLETED };
+
+ explicit TestTask(ConsumedResource* resource);
+ TestTask(ConsumedResource* resource, bool leave_early);
+ ~TestTask() override;
+
+ // Run is Step 1 in our case.
+ void Run() override;
+
+ void Step2();
+
+ void LastStep();
+
+ TaskState state() const { return state_; }
+
+ private:
+ ConsumedResource* resource_;
+ TaskState state_;
+ bool leave_early_;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_TEST_TASK_H_
diff --git a/chromium/components/offline_pages/downloads/BUILD.gn b/chromium/components/offline_pages/downloads/BUILD.gn
new file mode 100644
index 00000000000..41f709f7d93
--- /dev/null
+++ b/chromium/components/offline_pages/downloads/BUILD.gn
@@ -0,0 +1,44 @@
+# 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.
+
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
+static_library("offline_pages_ui_adapter") {
+ sources = [
+ "download_notifying_observer.cc",
+ "download_notifying_observer.h",
+ "download_ui_adapter.cc",
+ "download_ui_adapter.h",
+ "download_ui_item.cc",
+ "download_ui_item.h",
+ "offline_page_download_notifier.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/offline_pages:offline_pages",
+ "//components/offline_pages/background:background_offliner",
+ "//url",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "download_notifying_observer_unittest.cc",
+ "download_ui_adapter_unittest.cc",
+ ]
+
+ deps = [
+ ":offline_pages_ui_adapter",
+ "//base",
+ "//base/test:test_support",
+ "//components/offline_pages:offline_pages",
+ "//components/offline_pages:test_support",
+ "//components/offline_pages/background:background_offliner",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/offline_pages/downloads/download_notifying_observer.cc b/chromium/components/offline_pages/downloads/download_notifying_observer.cc
new file mode 100644
index 00000000000..397bcc975a8
--- /dev/null
+++ b/chromium/components/offline_pages/downloads/download_notifying_observer.cc
@@ -0,0 +1,82 @@
+// 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 "components/offline_pages/downloads/download_notifying_observer.h"
+
+#include "components/offline_pages/background/request_coordinator.h"
+#include "components/offline_pages/background/save_page_request.h"
+#include "components/offline_pages/client_policy_controller.h"
+#include "components/offline_pages/downloads/download_ui_adapter.h"
+#include "components/offline_pages/downloads/offline_page_download_notifier.h"
+
+namespace offline_pages {
+namespace {
+int kUserDataKey; // Only address is used.
+} // namespace
+
+DownloadNotifyingObserver::DownloadNotifyingObserver(
+ std::unique_ptr<OfflinePageDownloadNotifier> notifier,
+ ClientPolicyController* policy_controller)
+ : notifier_(std::move(notifier)), policy_controller_(policy_controller) {}
+
+DownloadNotifyingObserver::~DownloadNotifyingObserver() {}
+
+// static
+DownloadNotifyingObserver* DownloadNotifyingObserver::GetFromRequestCoordinator(
+ RequestCoordinator* request_coordinator) {
+ DCHECK(request_coordinator);
+ return static_cast<DownloadNotifyingObserver*>(
+ request_coordinator->GetUserData(&kUserDataKey));
+}
+
+// static
+void DownloadNotifyingObserver::CreateAndStartObserving(
+ RequestCoordinator* request_coordinator,
+ std::unique_ptr<OfflinePageDownloadNotifier> notifier) {
+ DCHECK(request_coordinator);
+ DCHECK(notifier.get());
+ DownloadNotifyingObserver* observer = new DownloadNotifyingObserver(
+ std::move(notifier), request_coordinator->GetPolicyController());
+ request_coordinator->AddObserver(observer);
+ // |request_coordinator| takes ownership of observer here.
+ request_coordinator->SetUserData(&kUserDataKey, observer);
+}
+
+void DownloadNotifyingObserver::OnAdded(const SavePageRequest& request) {
+ DCHECK(notifier_.get());
+ if (!IsVisibleInUI(request.client_id()))
+ return;
+ notifier_->NotifyDownloadProgress(DownloadUIItem(request));
+}
+
+void DownloadNotifyingObserver::OnChanged(const SavePageRequest& request) {
+ DCHECK(notifier_.get());
+ if (!IsVisibleInUI(request.client_id()))
+ return;
+ if (request.request_state() == SavePageRequest::RequestState::PAUSED)
+ notifier_->NotifyDownloadPaused(DownloadUIItem(request));
+ else
+ notifier_->NotifyDownloadProgress(DownloadUIItem(request));
+}
+
+void DownloadNotifyingObserver::OnCompleted(
+ const SavePageRequest& request,
+ RequestCoordinator::BackgroundSavePageResult status) {
+ DCHECK(notifier_.get());
+ if (!IsVisibleInUI(request.client_id()))
+ return;
+ if (status == RequestCoordinator::BackgroundSavePageResult::SUCCESS)
+ notifier_->NotifyDownloadSuccessful(DownloadUIItem(request));
+ else if (status == RequestCoordinator::BackgroundSavePageResult::REMOVED)
+ notifier_->NotifyDownloadCanceled(DownloadUIItem(request));
+ else
+ notifier_->NotifyDownloadFailed(DownloadUIItem(request));
+}
+
+bool DownloadNotifyingObserver::IsVisibleInUI(const ClientId& page) {
+ return policy_controller_->IsSupportedByDownload(page.name_space) &&
+ base::IsValidGUID(page.id);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/downloads/download_notifying_observer.h b/chromium/components/offline_pages/downloads/download_notifying_observer.h
new file mode 100644
index 00000000000..844373e5d3e
--- /dev/null
+++ b/chromium/components/offline_pages/downloads/download_notifying_observer.h
@@ -0,0 +1,61 @@
+// 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 COMPONENTS_OFFLINE_PAGES_DOWNLOADS_DOWNLOAD_NOTIFYING_OBSERVER_H_
+#define COMPONENTS_OFFLINE_PAGES_DOWNLOADS_DOWNLOAD_NOTIFYING_OBSERVER_H_
+
+#include <memory>
+
+#include "base/guid.h"
+#include "base/macros.h"
+#include "components/offline_pages/background/request_coordinator.h"
+#include "components/offline_pages/client_policy_controller.h"
+
+namespace offline_pages {
+
+struct ClientId;
+struct OfflinePageDownloadNotifier;
+class ClientPolicyController;
+class SavePageRequest;
+
+// Class observing the save page requests and issuing corresponding user
+// notifications as requests are added or updated.
+class DownloadNotifyingObserver : public RequestCoordinator::Observer,
+ public base::SupportsUserData::Data {
+ public:
+ ~DownloadNotifyingObserver() override;
+
+ static DownloadNotifyingObserver* GetFromRequestCoordinator(
+ RequestCoordinator* request_coordinator);
+ static void CreateAndStartObserving(
+ RequestCoordinator* request_coordinator,
+ std::unique_ptr<OfflinePageDownloadNotifier> notifier);
+
+ // RequestCoordinator::Observer implementation:
+ void OnAdded(const SavePageRequest& request) override;
+ void OnChanged(const SavePageRequest& request) override;
+ void OnCompleted(
+ const SavePageRequest& request,
+ RequestCoordinator::BackgroundSavePageResult status) override;
+
+ private:
+ friend class DownloadNotifyingObserverTest;
+
+ DownloadNotifyingObserver(
+ std::unique_ptr<OfflinePageDownloadNotifier> notifier,
+ ClientPolicyController* policy_controller);
+
+ bool IsVisibleInUI(const ClientId& id);
+
+ // Used to issue notifications related to save page requests.
+ std::unique_ptr<OfflinePageDownloadNotifier> notifier_;
+ // Used to determine policy-related permissions. Not owned.
+ ClientPolicyController* policy_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadNotifyingObserver);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_DOWNLOADS_DOWNLOAD_NOTIFYING_OBSERVER_H_
diff --git a/chromium/components/offline_pages/downloads/download_notifying_observer_unittest.cc b/chromium/components/offline_pages/downloads/download_notifying_observer_unittest.cc
new file mode 100644
index 00000000000..7d6f66117ad
--- /dev/null
+++ b/chromium/components/offline_pages/downloads/download_notifying_observer_unittest.cc
@@ -0,0 +1,251 @@
+// 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 "components/offline_pages/downloads/download_notifying_observer.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/offline_pages/background/save_page_request.h"
+#include "components/offline_pages/client_namespace_constants.h"
+#include "components/offline_pages/client_policy_controller.h"
+#include "components/offline_pages/downloads/offline_page_download_notifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+namespace {
+static const int64_t kTestOfflineId = 42L;
+static const char kTestUrl[] = "http://foo.com/bar";
+static const char kTestGuid[] = "cccccccc-cccc-4ccc-0ccc-ccccccccccc1";
+static const ClientId kTestClientId(kDownloadNamespace, kTestGuid);
+static const base::Time kTestCreationTime = base::Time::Now();
+static const bool kTestUserRequested = true;
+
+enum class LastNotificationType {
+ NONE,
+ DOWNLOAD_SUCCESSFUL,
+ DOWNLOAD_FAILED,
+ DOWNLOAD_PROGRESS,
+ DOWNLOAD_PAUSED,
+ DOWNLOAD_INTERRUPTED,
+ DOWNLOAD_CANCELED,
+};
+
+class TestNotifier : public OfflinePageDownloadNotifier {
+ public:
+ TestNotifier();
+ ~TestNotifier() override;
+
+ // OfflinePageDownloadNotifier implementation:
+ void NotifyDownloadSuccessful(const DownloadUIItem& item) override;
+ void NotifyDownloadFailed(const DownloadUIItem& item) override;
+ void NotifyDownloadProgress(const DownloadUIItem& item) override;
+ void NotifyDownloadPaused(const DownloadUIItem& item) override;
+ void NotifyDownloadInterrupted(const DownloadUIItem& item) override;
+ void NotifyDownloadCanceled(const DownloadUIItem& item) override;
+
+ void Reset();
+
+ LastNotificationType last_notification_type() const {
+ return last_notification_type_;
+ }
+
+ DownloadUIItem* download_item() const { return download_item_.get(); }
+
+ private:
+ LastNotificationType last_notification_type_;
+ std::unique_ptr<DownloadUIItem> download_item_;
+};
+
+TestNotifier::TestNotifier()
+ : last_notification_type_(LastNotificationType::NONE) {}
+
+TestNotifier::~TestNotifier() {}
+
+void TestNotifier::NotifyDownloadSuccessful(const DownloadUIItem& item) {
+ last_notification_type_ = LastNotificationType::DOWNLOAD_SUCCESSFUL;
+ download_item_.reset(new DownloadUIItem(item));
+}
+
+void TestNotifier::NotifyDownloadFailed(const DownloadUIItem& item) {
+ last_notification_type_ = LastNotificationType::DOWNLOAD_FAILED;
+ download_item_.reset(new DownloadUIItem(item));
+}
+
+void TestNotifier::NotifyDownloadProgress(const DownloadUIItem& item) {
+ last_notification_type_ = LastNotificationType::DOWNLOAD_PROGRESS;
+ download_item_.reset(new DownloadUIItem(item));
+}
+
+void TestNotifier::NotifyDownloadPaused(const DownloadUIItem& item) {
+ last_notification_type_ = LastNotificationType::DOWNLOAD_PAUSED;
+ download_item_.reset(new DownloadUIItem(item));
+}
+
+void TestNotifier::NotifyDownloadInterrupted(const DownloadUIItem& item) {
+ last_notification_type_ = LastNotificationType::DOWNLOAD_INTERRUPTED;
+ download_item_.reset(new DownloadUIItem(item));
+}
+
+void TestNotifier::NotifyDownloadCanceled(const DownloadUIItem& item) {
+ last_notification_type_ = LastNotificationType::DOWNLOAD_CANCELED;
+ download_item_.reset(new DownloadUIItem(item));
+}
+
+void TestNotifier::Reset() {
+ last_notification_type_ = LastNotificationType::NONE;
+ download_item_.reset(nullptr);
+}
+
+} // namespace
+
+class DownloadNotifyingObserverTest : public testing::Test {
+ public:
+ DownloadNotifyingObserverTest();
+ ~DownloadNotifyingObserverTest() override;
+
+ // testing::Test implementation:
+ void SetUp() override;
+
+ TestNotifier* notifier() const { return notifier_; }
+ DownloadNotifyingObserver* observer() { return observer_.get(); }
+
+ private:
+ TestNotifier* notifier_;
+ std::unique_ptr<DownloadNotifyingObserver> observer_;
+ std::unique_ptr<ClientPolicyController> policy_controller_;
+};
+
+DownloadNotifyingObserverTest::DownloadNotifyingObserverTest() {}
+
+DownloadNotifyingObserverTest::~DownloadNotifyingObserverTest() {}
+
+void DownloadNotifyingObserverTest::SetUp() {
+ std::unique_ptr<TestNotifier> notifier(new TestNotifier);
+ policy_controller_.reset(new ClientPolicyController());
+ notifier_ = notifier.get();
+ observer_.reset(new DownloadNotifyingObserver(std::move(notifier),
+ policy_controller_.get()));
+}
+
+TEST_F(DownloadNotifyingObserverTest, OnAdded) {
+ SavePageRequest request(kTestOfflineId, GURL(kTestUrl), kTestClientId,
+ kTestCreationTime, kTestUserRequested);
+ observer()->OnAdded(request);
+ EXPECT_EQ(LastNotificationType::DOWNLOAD_PROGRESS,
+ notifier()->last_notification_type());
+ EXPECT_EQ(kTestGuid, notifier()->download_item()->guid);
+ EXPECT_EQ(GURL(kTestUrl), notifier()->download_item()->url);
+ EXPECT_EQ(kTestCreationTime, notifier()->download_item()->start_time);
+}
+
+TEST_F(DownloadNotifyingObserverTest, OnChangedToPaused) {
+ SavePageRequest request(kTestOfflineId, GURL(kTestUrl), kTestClientId,
+ kTestCreationTime, kTestUserRequested);
+ request.set_request_state(SavePageRequest::RequestState::PAUSED);
+ observer()->OnChanged(request);
+ EXPECT_EQ(LastNotificationType::DOWNLOAD_PAUSED,
+ notifier()->last_notification_type());
+ EXPECT_EQ(kTestGuid, notifier()->download_item()->guid);
+ EXPECT_EQ(GURL(kTestUrl), notifier()->download_item()->url);
+ EXPECT_EQ(kTestCreationTime, notifier()->download_item()->start_time);
+}
+
+TEST_F(DownloadNotifyingObserverTest, OnChangedToAvailable) {
+ SavePageRequest request(kTestOfflineId, GURL(kTestUrl), kTestClientId,
+ kTestCreationTime, kTestUserRequested);
+ request.set_request_state(SavePageRequest::RequestState::AVAILABLE);
+ observer()->OnChanged(request);
+ EXPECT_EQ(LastNotificationType::DOWNLOAD_PROGRESS,
+ notifier()->last_notification_type());
+ EXPECT_EQ(kTestGuid, notifier()->download_item()->guid);
+ EXPECT_EQ(GURL(kTestUrl), notifier()->download_item()->url);
+ EXPECT_EQ(kTestCreationTime, notifier()->download_item()->start_time);
+}
+
+TEST_F(DownloadNotifyingObserverTest, OnCompletedSuccess) {
+ SavePageRequest request(kTestOfflineId, GURL(kTestUrl), kTestClientId,
+ kTestCreationTime, kTestUserRequested);
+ observer()->OnCompleted(request,
+ RequestNotifier::BackgroundSavePageResult::SUCCESS);
+ EXPECT_EQ(LastNotificationType::DOWNLOAD_SUCCESSFUL,
+ notifier()->last_notification_type());
+ EXPECT_EQ(kTestGuid, notifier()->download_item()->guid);
+ EXPECT_EQ(GURL(kTestUrl), notifier()->download_item()->url);
+ EXPECT_EQ(kTestCreationTime, notifier()->download_item()->start_time);
+}
+
+TEST_F(DownloadNotifyingObserverTest, OnCompletedCanceled) {
+ SavePageRequest request(kTestOfflineId, GURL(kTestUrl), kTestClientId,
+ kTestCreationTime, kTestUserRequested);
+ observer()->OnCompleted(request,
+ RequestNotifier::BackgroundSavePageResult::REMOVED);
+ EXPECT_EQ(LastNotificationType::DOWNLOAD_CANCELED,
+ notifier()->last_notification_type());
+ EXPECT_EQ(kTestGuid, notifier()->download_item()->guid);
+ EXPECT_EQ(GURL(kTestUrl), notifier()->download_item()->url);
+ EXPECT_EQ(kTestCreationTime, notifier()->download_item()->start_time);
+}
+
+TEST_F(DownloadNotifyingObserverTest, OnCompletedFailure) {
+ SavePageRequest request(kTestOfflineId, GURL(kTestUrl), kTestClientId,
+ kTestCreationTime, kTestUserRequested);
+ observer()->OnCompleted(
+ request, RequestNotifier::BackgroundSavePageResult::PRERENDER_FAILURE);
+ EXPECT_EQ(LastNotificationType::DOWNLOAD_FAILED,
+ notifier()->last_notification_type());
+ EXPECT_EQ(kTestGuid, notifier()->download_item()->guid);
+ EXPECT_EQ(GURL(kTestUrl), notifier()->download_item()->url);
+ EXPECT_EQ(kTestCreationTime, notifier()->download_item()->start_time);
+
+ notifier()->Reset();
+ observer()->OnCompleted(
+ request, RequestNotifier::BackgroundSavePageResult::FOREGROUND_CANCELED);
+ EXPECT_EQ(LastNotificationType::DOWNLOAD_FAILED,
+ notifier()->last_notification_type());
+ EXPECT_EQ(kTestGuid, notifier()->download_item()->guid);
+ EXPECT_EQ(GURL(kTestUrl), notifier()->download_item()->url);
+ EXPECT_EQ(kTestCreationTime, notifier()->download_item()->start_time);
+
+ notifier()->Reset();
+ observer()->OnCompleted(
+ request, RequestNotifier::BackgroundSavePageResult::SAVE_FAILED);
+ EXPECT_EQ(LastNotificationType::DOWNLOAD_FAILED,
+ notifier()->last_notification_type());
+ EXPECT_EQ(kTestGuid, notifier()->download_item()->guid);
+ EXPECT_EQ(GURL(kTestUrl), notifier()->download_item()->url);
+ EXPECT_EQ(kTestCreationTime, notifier()->download_item()->start_time);
+
+ notifier()->Reset();
+ observer()->OnCompleted(request,
+ RequestNotifier::BackgroundSavePageResult::EXPIRED);
+ EXPECT_EQ(LastNotificationType::DOWNLOAD_FAILED,
+ notifier()->last_notification_type());
+ EXPECT_EQ(kTestGuid, notifier()->download_item()->guid);
+ EXPECT_EQ(GURL(kTestUrl), notifier()->download_item()->url);
+ EXPECT_EQ(kTestCreationTime, notifier()->download_item()->start_time);
+
+ notifier()->Reset();
+ observer()->OnCompleted(
+ request, RequestNotifier::BackgroundSavePageResult::RETRY_COUNT_EXCEEDED);
+ EXPECT_EQ(LastNotificationType::DOWNLOAD_FAILED,
+ notifier()->last_notification_type());
+ EXPECT_EQ(kTestGuid, notifier()->download_item()->guid);
+ EXPECT_EQ(GURL(kTestUrl), notifier()->download_item()->url);
+ EXPECT_EQ(kTestCreationTime, notifier()->download_item()->start_time);
+}
+
+TEST_F(DownloadNotifyingObserverTest, NamespacesNotVisibleInUI) {
+ std::vector<std::string> name_spaces = {kBookmarkNamespace, kLastNNamespace,
+ kCCTNamespace, kDefaultNamespace};
+
+ for (auto name_space : name_spaces) {
+ ClientId invisible_client_id(name_space, kTestGuid);
+ SavePageRequest request(kTestOfflineId, GURL(kTestUrl), invisible_client_id,
+ kTestCreationTime, kTestUserRequested);
+ observer()->OnAdded(request);
+ EXPECT_EQ(LastNotificationType::NONE, notifier()->last_notification_type());
+ }
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/downloads/download_ui_adapter.cc b/chromium/components/offline_pages/downloads/download_ui_adapter.cc
new file mode 100644
index 00000000000..d095ec33e81
--- /dev/null
+++ b/chromium/components/offline_pages/downloads/download_ui_adapter.cc
@@ -0,0 +1,217 @@
+// 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 "components/offline_pages/downloads/download_ui_adapter.h"
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/client_namespace_constants.h"
+#include "components/offline_pages/client_policy_controller.h"
+#include "components/offline_pages/downloads/download_ui_item.h"
+#include "components/offline_pages/offline_page_model.h"
+
+namespace offline_pages {
+
+namespace {
+const char kDownloadUIAdapterKey[] = "download-ui-adapter";
+}
+
+DownloadUIAdapter::ItemInfo::ItemInfo(const OfflinePageItem& page)
+ : ui_item(base::MakeUnique<DownloadUIItem>(page)),
+ offline_id(page.offline_id) {}
+
+DownloadUIAdapter::ItemInfo::~ItemInfo() {}
+
+DownloadUIAdapter::DownloadUIAdapter(OfflinePageModel* model)
+ : model_(model),
+ state_(State::NOT_LOADED),
+ observers_count_(0),
+ weak_ptr_factory_(this) {
+}
+
+DownloadUIAdapter::~DownloadUIAdapter() { }
+
+// static
+DownloadUIAdapter* DownloadUIAdapter::FromOfflinePageModel(
+ OfflinePageModel* offline_page_model) {
+ DownloadUIAdapter* adapter = static_cast<DownloadUIAdapter*>(
+ offline_page_model->GetUserData(kDownloadUIAdapterKey));
+ if (!adapter) {
+ adapter = new DownloadUIAdapter(offline_page_model);
+ offline_page_model->SetUserData(kDownloadUIAdapterKey, adapter);
+ }
+ return adapter;
+}
+
+void DownloadUIAdapter::AddObserver(Observer* observer) {
+ DCHECK(observer);
+ if (observers_.HasObserver(observer))
+ return;
+ if (observers_count_ == 0)
+ LoadCache();
+ observers_.AddObserver(observer);
+ ++observers_count_;
+ // If the items are already loaded, post the notification right away.
+ // Don't just invoke it from here to avoid reentrancy in the client.
+ if (state_ == State::LOADED) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&DownloadUIAdapter::NotifyItemsLoaded,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Unretained(observer)));
+ }
+}
+
+void DownloadUIAdapter::RemoveObserver(Observer* observer) {
+ DCHECK(observer);
+ if (!observers_.HasObserver(observer))
+ return;
+ observers_.RemoveObserver(observer);
+ --observers_count_;
+ // Once the last observer is gone, clear cached data.
+ if (observers_count_ == 0)
+ ClearCache();
+}
+
+void DownloadUIAdapter::OfflinePageModelLoaded(OfflinePageModel* model) {
+ // This signal is not used here.
+}
+
+void DownloadUIAdapter::OfflinePageModelChanged(OfflinePageModel* model) {
+ DCHECK(model == model_);
+ model_->GetAllPages(
+ base::Bind(&DownloadUIAdapter::OnOfflinePagesChanged,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DownloadUIAdapter::OfflinePageDeleted(
+ int64_t offline_id, const ClientId& client_id) {
+ if (!IsVisibleInUI(client_id))
+ return;
+ std::string guid = client_id.id;
+ DownloadUIItems::const_iterator it = items_.find(guid);
+ if (it == items_.end())
+ return;
+ items_.erase(it);
+ FOR_EACH_OBSERVER(Observer, observers_, ItemDeleted(guid));
+}
+
+std::vector<const DownloadUIItem*> DownloadUIAdapter::GetAllItems() const {
+ std::vector<const DownloadUIItem*> result;
+ for (const auto& item : items_)
+ result.push_back(item.second->ui_item.get());
+ return result;
+}
+
+const DownloadUIItem*
+ DownloadUIAdapter::GetItem(const std::string& guid) const {
+ DownloadUIItems::const_iterator it = items_.find(guid);
+ if (it == items_.end())
+ return nullptr;
+ return it->second->ui_item.get();
+}
+
+void DownloadUIAdapter::DeleteItem(const std::string& guid) {
+ // TODO(dimich): Also remove pending request from RequestQueue.
+ DownloadUIItems::const_iterator it = items_.find(guid);
+ if (it == items_.end())
+ return;
+
+ std::vector<int64_t> page_ids;
+ page_ids.push_back(it->second->offline_id);
+ // TODO(dimich): This should be ExpirePages(...Now()..) when Expire is
+ // firing Observer method. The resulting Observer notification will update
+ // local cache.
+ model_->DeletePagesByOfflineId(
+ page_ids, base::Bind(&DownloadUIAdapter::OnDeletePagesDone,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+int64_t DownloadUIAdapter::GetOfflineIdByGuid(
+ const std::string& guid) const {
+ // TODO(dimich): when requests are also in the cache, filter them out.
+ // Requests do not yet have offline ID.
+ DownloadUIItems::const_iterator it = items_.find(guid);
+ if (it != items_.end())
+ return it->second->offline_id;
+ return 0;
+}
+
+// Note that several LoadCache calls may be issued before the async GetAllPages
+// comes back.
+void DownloadUIAdapter::LoadCache() {
+ // TODO(dimich): Add fetching from RequestQueue as well.
+ state_ = State::LOADING;
+ model_->GetAllPages(
+ base::Bind(&DownloadUIAdapter::OnOfflinePagesLoaded,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DownloadUIAdapter::ClearCache() {
+ // Once loaded, this class starts to observe the model. Only remove observer
+ // if it was added.
+ if (state_ == State::LOADED)
+ model_->RemoveObserver(this);
+ items_.clear();
+ state_ = State::NOT_LOADED;
+}
+
+void DownloadUIAdapter::OnOfflinePagesLoaded(
+ const MultipleOfflinePageItemResult& pages) {
+ // If multiple observers register quickly, the cache might be already loaded
+ // by the previous LoadCache call. At the same time, if all observers already
+ // left, there is no reason to populate the cache.
+ if (state_ != State::LOADING)
+ return;
+ for (const auto& page : pages) {
+ if (IsVisibleInUI(page.client_id)) {
+ std::string guid = page.client_id.id;
+ DCHECK(items_.find(guid) == items_.end());
+ items_[guid] = base::MakeUnique<ItemInfo>(page);
+ }
+ }
+ model_->AddObserver(this);
+ state_ = State::LOADED;
+ FOR_EACH_OBSERVER(Observer, observers_, ItemsLoaded());
+}
+
+void DownloadUIAdapter::NotifyItemsLoaded(Observer* observer) {
+ if (observer && observers_.HasObserver(observer))
+ observer->ItemsLoaded();
+}
+
+// This method is only called by OPM when a single item added.
+// TODO(dimich): change OPM to have real OnPageAdded/OnPageUpdated and
+// simplify this code.
+void DownloadUIAdapter::OnOfflinePagesChanged(
+ const MultipleOfflinePageItemResult& pages) {
+ std::vector<std::string> added_guids;
+ for (const auto& page : pages) {
+ if (!IsVisibleInUI(page.client_id)) // Item should be filtered out.
+ continue;
+ const std::string& guid = page.client_id.id;
+ if (items_.find(guid) != items_.end()) // Item already exists.
+ continue;
+ items_[guid] = base::MakeUnique<ItemInfo>(page);
+ added_guids.push_back(guid);
+ }
+ for (auto& guid : added_guids) {
+ const DownloadUIItem& item = *(items_.find(guid)->second->ui_item.get());
+ FOR_EACH_OBSERVER(Observer, observers_, ItemAdded(item));
+ }
+}
+
+void DownloadUIAdapter::OnDeletePagesDone(DeletePageResult result) {
+ // TODO(dimich): Consider adding UMA to record user actions.
+}
+
+bool DownloadUIAdapter::IsVisibleInUI(const ClientId& client_id) {
+ const std::string& name_space = client_id.name_space;
+ return model_->GetPolicyController()->IsSupportedByDownload(name_space) &&
+ base::IsValidGUID(client_id.id);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/downloads/download_ui_adapter.h b/chromium/components/offline_pages/downloads/download_ui_adapter.h
new file mode 100644
index 00000000000..a8835fe039f
--- /dev/null
+++ b/chromium/components/offline_pages/downloads/download_ui_adapter.h
@@ -0,0 +1,136 @@
+// 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 COMPONENTS_OFFLINE_PAGE_DOWNLOADS_DOWNLOAD_UI_ADAPTER_H_
+#define COMPONENTS_OFFLINE_PAGE_DOWNLOADS_DOWNLOAD_UI_ADAPTER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/observer_list.h"
+#include "base/supports_user_data.h"
+#include "components/offline_pages/downloads/download_ui_item.h"
+#include "components/offline_pages/offline_page_model.h"
+#include "components/offline_pages/offline_page_types.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+// C++ side of the UI Adapter. Mimics DownloadManager/Item/History (since we
+// share UI with Downloads).
+// An instance of this class is owned by OfflinePageModel and is shared between
+// UI components if needed. It manages the cache of DownloadUIItems, so after
+// initial load the UI components can synchronously pull the whoel list or any
+// item by its guid.
+class DownloadUIAdapter : public OfflinePageModel::Observer,
+ public base::SupportsUserData::Data {
+ public:
+ // Observer, normally implemented by UI or a Bridge.
+ class Observer {
+ public:
+ // Invoked when UI items are loaded. GetAllItems/GetItem can now be used.
+ // Must be listened for in order to start getting the items.
+ // If the items are already loaded by the time observer is added, this
+ // callback will be posted right away.
+ virtual void ItemsLoaded() = 0;
+
+ // Invoked when the UI Item was added, usually as a request to download.
+ virtual void ItemAdded(const DownloadUIItem& item) = 0;
+
+ // Invoked when the UI Item was updated. Only guid of the item is guaranteed
+ // to survive the update, all other fields can change.
+ virtual void ItemUpdated(const DownloadUIItem& item) = 0;
+
+ // Invoked when the UI Item was deleted. At this point, only guid remains.
+ virtual void ItemDeleted(const std::string& guid) = 0;
+
+ protected:
+ virtual ~Observer() = default;
+ };
+
+ explicit DownloadUIAdapter(OfflinePageModel* model);
+ ~DownloadUIAdapter() override;
+
+ static DownloadUIAdapter* FromOfflinePageModel(
+ OfflinePageModel* offline_page_model);
+
+ // Checks a client ID for proper namespace and ID format to be shown in the
+ // Downloads Home UI.
+ bool IsVisibleInUI(const ClientId& page);
+
+ // This adapter is potentially shared by UI elements, each of which adds
+ // itself as an observer.
+ // When the last observer si removed, cached list of items is destroyed and
+ // next time the initial loading will take longer.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Returns all UI items. The list contains references to items in the cache
+ // and has to be used synchronously.
+ std::vector<const DownloadUIItem*> GetAllItems() const;
+ // May return nullptr if item with specified guid does not exist.
+ const DownloadUIItem* GetItem(const std::string& guid) const;
+
+ // Commands from UI. Start async operations, result is observable
+ // via Observer or directly by the user (as in 'open').
+ void DeleteItem(const std::string& guid);
+ int64_t GetOfflineIdByGuid(const std::string& guid) const;
+
+ // OfflinePageModel::Observer
+ void OfflinePageModelLoaded(OfflinePageModel* model) override;
+ void OfflinePageModelChanged(OfflinePageModel* model) override;
+ void OfflinePageDeleted(int64_t offline_id,
+ const ClientId& client_id) override;
+
+ private:
+ enum class State {
+ NOT_LOADED,
+ LOADING,
+ LOADED
+ };
+
+ struct ItemInfo {
+ explicit ItemInfo(const OfflinePageItem& page);
+ ~ItemInfo();
+
+ std::unique_ptr<DownloadUIItem> ui_item;
+ // Additional cached data, not exposed to UI through DownloadUIItem.
+ int64_t offline_id;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ItemInfo);
+ };
+
+ typedef std::map<std::string, std::unique_ptr<ItemInfo>> DownloadUIItems;
+
+ void LoadCache();
+ void ClearCache();
+
+ // Task callbacks.
+ void OnOfflinePagesLoaded(const MultipleOfflinePageItemResult& pages);
+ void NotifyItemsLoaded(Observer* observer);
+ void OnOfflinePagesChanged(const MultipleOfflinePageItemResult& pages);
+ void OnDeletePagesDone(DeletePageResult result);
+
+ // Always valid, this class is a member of the model.
+ OfflinePageModel* model_;
+
+ State state_;
+
+ // The cache of UI items. The key is DownloadUIItem.guid.
+ DownloadUIItems items_;
+
+ // The observers.
+ base::ObserverList<Observer> observers_;
+ int observers_count_;
+
+ base::WeakPtrFactory<DownloadUIAdapter> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadUIAdapter);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGE_DOWNLOADS_DOWNLOAD_UI_ADAPTER_H_
diff --git a/chromium/components/offline_pages/downloads/download_ui_adapter_unittest.cc b/chromium/components/offline_pages/downloads/download_ui_adapter_unittest.cc
new file mode 100644
index 00000000000..ef21b922942
--- /dev/null
+++ b/chromium/components/offline_pages/downloads/download_ui_adapter_unittest.cc
@@ -0,0 +1,305 @@
+// 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 "components/offline_pages/downloads/download_ui_adapter.h"
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/offline_pages/client_namespace_constants.h"
+#include "components/offline_pages/client_policy_controller.h"
+#include "components/offline_pages/stub_offline_page_model.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+namespace {
+// Constants for a test OfflinePageItem.
+static const int kTestOfflineId1 = 1;
+static const int kTestOfflineId2 = 2;
+static const int kTestOfflineId3 = 3;
+static const char kTestUrl[] = "http://foo.com/bar.mhtml";
+static const char kTestGuid1[] = "cccccccc-cccc-4ccc-0ccc-ccccccccccc1";
+static const char kTestGuid2[] = "cccccccc-cccc-4ccc-0ccc-ccccccccccc2";
+static const char kTestBadGuid[] = "ccccccc-cccc-0ccc-0ccc-ccccccccccc0";
+static const ClientId kTestClientIdOtherNamespace(kLastNNamespace, kTestGuid1);
+static const ClientId kTestClientIdOtherGuid(kLastNNamespace, kTestBadGuid);
+static const ClientId kTestClientId1(kAsyncNamespace, kTestGuid1);
+static const ClientId kTestClientId2(kAsyncNamespace, kTestGuid2);
+static const base::FilePath kTestFilePath =
+ base::FilePath(FILE_PATH_LITERAL("foo/bar.mhtml"));
+static const int kFileSize = 1000;
+static const base::Time kTestCreationTime = base::Time::Now();
+static const base::string16 kTestTitle = base::ASCIIToUTF16("test title");
+} // namespace
+
+// Mock OfflinePageModel for testing the SavePage calls.
+class MockOfflinePageModel : public StubOfflinePageModel {
+ public:
+ MockOfflinePageModel(base::TestMockTimeTaskRunner* task_runner)
+ : observer_(nullptr),
+ task_runner_(task_runner),
+ policy_controller_(new ClientPolicyController()) {
+ adapter.reset(new DownloadUIAdapter(this));
+ // Add one page.
+ OfflinePageItem page(GURL(kTestUrl),
+ kTestOfflineId1,
+ kTestClientId1,
+ kTestFilePath,
+ kFileSize,
+ kTestCreationTime);
+ page.title = kTestTitle;
+ pages[kTestOfflineId1] = page;
+ }
+
+ ~MockOfflinePageModel() override {}
+
+ // OfflinePageModel overrides.
+ void AddObserver(Observer* observer) override {
+ EXPECT_TRUE(observer != nullptr);
+ observer_ = observer;
+ }
+
+ void RemoveObserver(Observer* observer) override {
+ EXPECT_TRUE(observer != nullptr);
+ EXPECT_EQ(observer, observer_);
+ observer_ = nullptr;
+ }
+
+ // PostTask instead of just running callback to simpulate the real class.
+ void GetAllPages(const MultipleOfflinePageItemCallback& callback) override {
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&MockOfflinePageModel::GetAllPagesImpl,
+ base::Unretained(this), callback));
+ }
+
+ void GetAllPagesImpl(const MultipleOfflinePageItemCallback& callback) {
+ std::vector<OfflinePageItem> result;
+ for (const auto& page : pages)
+ result.push_back(page.second);
+ callback.Run(result);
+ }
+
+ void DeletePageAndNotifyAdapter(const std::string& guid) {
+ for(const auto& page : pages) {
+ if (page.second.client_id.id == guid) {
+ observer_->OfflinePageDeleted(page.second.offline_id,
+ page.second.client_id);
+ pages.erase(page.first);
+ return;
+ }
+ }
+ }
+
+ void AddPageAndNotifyAdapter(const OfflinePageItem& page) {
+ EXPECT_EQ(pages.end(), pages.find(page.offline_id));
+ pages[page.offline_id] = page;
+ observer_->OfflinePageModelChanged(this);
+ }
+
+ ClientPolicyController* GetPolicyController() override {
+ return policy_controller_.get();
+ }
+
+ // Normally, OfflinePageModel owns this adapter, so lets test it this way.
+ std::unique_ptr<DownloadUIAdapter> adapter;
+
+ std::map<int64_t, OfflinePageItem> pages;
+
+ private:
+ OfflinePageModel::Observer* observer_;
+ base::TestMockTimeTaskRunner* task_runner_;
+ // Normally owned by OfflinePageModel.
+ std::unique_ptr<ClientPolicyController> policy_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockOfflinePageModel);
+};
+
+class DownloadUIAdapterTest
+ : public testing::Test,
+ public DownloadUIAdapter::Observer {
+ public:
+ DownloadUIAdapterTest();
+ ~DownloadUIAdapterTest() override;
+
+ // testing::Test
+ void SetUp() override;
+
+ // DownloadUIAdapter::Observer
+ void ItemsLoaded() override;
+ void ItemAdded(const DownloadUIItem& item) override;
+ void ItemUpdated(const DownloadUIItem& item) override;
+ void ItemDeleted(const std::string& guid) override;
+
+ // Runs until all of the tasks that are not delayed are gone from the task
+ // queue.
+ void PumpLoop();
+
+ bool items_loaded;
+ std::vector<std::string> added_guids, updated_guids, deleted_guids;
+ std::unique_ptr<MockOfflinePageModel> model;
+
+ private:
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+};
+
+DownloadUIAdapterTest::DownloadUIAdapterTest()
+ : items_loaded(false),
+ task_runner_(new base::TestMockTimeTaskRunner) {
+}
+
+DownloadUIAdapterTest::~DownloadUIAdapterTest() {
+}
+
+void DownloadUIAdapterTest::SetUp() {
+ model.reset(new MockOfflinePageModel(task_runner_.get()));
+ model->adapter->AddObserver(this);
+}
+
+void DownloadUIAdapterTest::ItemsLoaded() {
+ items_loaded = true;
+}
+
+void DownloadUIAdapterTest::ItemAdded(const DownloadUIItem& item) {
+ added_guids.push_back(item.guid);
+}
+
+void DownloadUIAdapterTest::ItemUpdated(const DownloadUIItem& item) {
+ updated_guids.push_back(item.guid);
+}
+
+void DownloadUIAdapterTest::ItemDeleted(const std::string& guid) {
+ deleted_guids.push_back(guid);
+}
+
+void DownloadUIAdapterTest::PumpLoop() {
+ task_runner_->RunUntilIdle();
+}
+
+TEST_F(DownloadUIAdapterTest, InitialLoad) {
+ EXPECT_NE(nullptr, model->adapter);
+ EXPECT_FALSE(items_loaded);
+ PumpLoop();
+ EXPECT_TRUE(items_loaded);
+ const DownloadUIItem* item = model->adapter->GetItem(kTestGuid1);
+ EXPECT_NE(nullptr, item);
+}
+
+TEST_F(DownloadUIAdapterTest, InitialItemConversion) {
+ EXPECT_EQ(1UL, model->pages.size());
+ EXPECT_EQ(kTestGuid1, model->pages[kTestOfflineId1].client_id.id);
+ PumpLoop();
+ const DownloadUIItem* item = model->adapter->GetItem(kTestGuid1);
+ EXPECT_EQ(kTestGuid1, item->guid);
+ EXPECT_EQ(kTestUrl, item->url.spec());
+ EXPECT_EQ(kTestFilePath, item->target_path);
+ EXPECT_EQ(kTestCreationTime, item->start_time);
+ EXPECT_EQ(kFileSize, item->total_bytes);
+ EXPECT_EQ(kTestTitle, item->title);
+}
+
+TEST_F(DownloadUIAdapterTest, ItemDeletedAdded) {
+ PumpLoop();
+ // Add page, notify adapter.
+ OfflinePageItem page(GURL(kTestUrl),
+ kTestOfflineId2,
+ kTestClientId2,
+ base::FilePath(kTestFilePath),
+ kFileSize,
+ kTestCreationTime);
+ model->AddPageAndNotifyAdapter(page);
+ PumpLoop();
+ EXPECT_EQ(1UL, added_guids.size());
+ EXPECT_EQ(kTestGuid2, added_guids[0]);
+ // Remove pages, notify adapter.
+ model->DeletePageAndNotifyAdapter(kTestGuid1);
+ model->DeletePageAndNotifyAdapter(kTestGuid2);
+ PumpLoop();
+ EXPECT_EQ(2UL, deleted_guids.size());
+ EXPECT_EQ(kTestGuid1, deleted_guids[0]);
+ EXPECT_EQ(kTestGuid2, deleted_guids[1]);
+}
+
+TEST_F(DownloadUIAdapterTest, ItemWithWrongNamespace) {
+ PumpLoop();
+ OfflinePageItem page1(GURL(kTestUrl),
+ kTestOfflineId2,
+ kTestClientIdOtherNamespace,
+ base::FilePath(kTestFilePath),
+ kFileSize,
+ kTestCreationTime);
+ model->AddPageAndNotifyAdapter(page1);
+ PumpLoop();
+ // Should not add the page with wrong namespace.
+ EXPECT_EQ(0UL, added_guids.size());
+
+ OfflinePageItem page2(GURL(kTestUrl),
+ kTestOfflineId3,
+ kTestClientIdOtherGuid,
+ base::FilePath(kTestFilePath),
+ kFileSize,
+ kTestCreationTime);
+ model->AddPageAndNotifyAdapter(page2);
+ PumpLoop();
+ // Should not add the page with wrong guid.
+ EXPECT_EQ(0UL, added_guids.size());
+}
+
+TEST_F(DownloadUIAdapterTest, ItemUpdated) {
+ PumpLoop();
+ // Clear the initial page and replace it with updated one.
+ model->pages.clear();
+ // Add page with the same offline_id/guid, notify adapter.
+ // This should generate 'updated' notification.
+ OfflinePageItem page1(GURL(kTestUrl),
+ kTestOfflineId1,
+ kTestClientId1,
+ base::FilePath(kTestFilePath),
+ kFileSize,
+ kTestCreationTime);
+ // Add a new page which did not exist before.
+ OfflinePageItem page2(GURL(kTestUrl),
+ kTestOfflineId2,
+ kTestClientId2,
+ base::FilePath(kTestFilePath),
+ kFileSize,
+ kTestCreationTime);
+ model->AddPageAndNotifyAdapter(page1);
+ model->AddPageAndNotifyAdapter(page2);
+ PumpLoop();
+ EXPECT_EQ(1UL, added_guids.size());
+ EXPECT_EQ(kTestGuid2, added_guids[0]);
+ // TODO(dimich): we currently don't report updated items since OPM doesn't
+ // have support for that. Add as needed, this will have to be updated when
+ // support is added.
+ EXPECT_EQ(0UL, updated_guids.size());
+}
+
+TEST_F(DownloadUIAdapterTest, NoHangingLoad) {
+ EXPECT_NE(nullptr, model->adapter);
+ EXPECT_FALSE(items_loaded);
+ // Removal of last observer causes cache unload of not-yet-loaded cache.
+ model->adapter->RemoveObserver(this);
+ // This will complete async fetch of items, but...
+ PumpLoop();
+ // items should not be loaded when there is no observers!
+ EXPECT_FALSE(items_loaded);
+ // This should not crash.
+ model->adapter->AddObserver(this);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/downloads/download_ui_item.cc b/chromium/components/offline_pages/downloads/download_ui_item.cc
new file mode 100644
index 00000000000..13af20ba27c
--- /dev/null
+++ b/chromium/components/offline_pages/downloads/download_ui_item.cc
@@ -0,0 +1,41 @@
+// 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 "components/offline_pages/downloads/download_ui_item.h"
+
+#include "components/offline_pages/background/save_page_request.h"
+#include "components/offline_pages/offline_page_item.h"
+
+namespace offline_pages {
+
+DownloadUIItem::DownloadUIItem()
+ : total_bytes(0) {
+}
+
+DownloadUIItem::DownloadUIItem(const OfflinePageItem& page)
+ : guid(page.client_id.id),
+ url(page.url),
+ title(page.title),
+ target_path(page.file_path),
+ start_time(page.creation_time),
+ total_bytes(page.file_size) {}
+
+DownloadUIItem::DownloadUIItem(const SavePageRequest& request)
+ : guid(request.client_id().id),
+ url(request.url()),
+ start_time(request.creation_time()),
+ total_bytes(-1L) {}
+
+DownloadUIItem::DownloadUIItem(const DownloadUIItem& other)
+ : guid(other.guid),
+ url(other.url),
+ title(other.title),
+ target_path(other.target_path),
+ start_time(other.start_time),
+ total_bytes(other.total_bytes) {}
+
+DownloadUIItem::~DownloadUIItem() {
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/downloads/download_ui_item.h b/chromium/components/offline_pages/downloads/download_ui_item.h
new file mode 100644
index 00000000000..801c1ef8e10
--- /dev/null
+++ b/chromium/components/offline_pages/downloads/download_ui_item.h
@@ -0,0 +1,51 @@
+// 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 COMPONENTS_OFFLINE_PAGES_DOWNLOADS_DOWNLOAD_UI_ITEM_H_
+#define COMPONENTS_OFFLINE_PAGES_DOWNLOADS_DOWNLOAD_UI_ITEM_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/time/time.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+struct OfflinePageItem;
+class SavePageRequest;
+
+struct DownloadUIItem {
+ public:
+ DownloadUIItem();
+ explicit DownloadUIItem(const OfflinePageItem& page);
+ explicit DownloadUIItem(const SavePageRequest& request);
+ DownloadUIItem(const DownloadUIItem& other);
+ ~DownloadUIItem();
+
+ // Unique id.
+ std::string guid;
+
+ // The URL of the captured page.
+ GURL url;
+
+ // The Title of the captured page, if any. It can be empty string either
+ // because the page is not yet fully loaded, or because it doesn't have any.
+ base::string16 title;
+
+ // The file path to the archive with a local copy of the page.
+ base::FilePath target_path;
+
+ // The time when the offline archive was created.
+ base::Time start_time;
+
+ // The size of the offline copy.
+ int64_t total_bytes;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_DOWNLOADS_DOWNLOAD_UI_ITEM_H_
diff --git a/chromium/components/offline_pages/downloads/offline_page_download_notifier.h b/chromium/components/offline_pages/downloads/offline_page_download_notifier.h
new file mode 100644
index 00000000000..c35c80d86b4
--- /dev/null
+++ b/chromium/components/offline_pages/downloads/offline_page_download_notifier.h
@@ -0,0 +1,26 @@
+// 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 COMPONENTS_OFFLINE_PAGES_DOWNLOADS_OFFLINE_PAGE_DOWNLOAD_NOTIFIER_H_
+#define COMPONENTS_OFFLINE_PAGES_DOWNLOADS_OFFLINE_PAGE_DOWNLOAD_NOTIFIER_H_
+
+#include "components/offline_pages/downloads/download_ui_item.h"
+
+namespace offline_pages {
+
+struct OfflinePageDownloadNotifier {
+ public:
+ virtual ~OfflinePageDownloadNotifier() = default;
+
+ virtual void NotifyDownloadSuccessful(const DownloadUIItem& item) = 0;
+ virtual void NotifyDownloadFailed(const DownloadUIItem& item) = 0;
+ virtual void NotifyDownloadProgress(const DownloadUIItem& item) = 0;
+ virtual void NotifyDownloadPaused(const DownloadUIItem& item) = 0;
+ virtual void NotifyDownloadInterrupted(const DownloadUIItem& item) = 0;
+ virtual void NotifyDownloadCanceled(const DownloadUIItem& item) = 0;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_DOWNLOADS_OFFLINE_PAGE_DOWNLOAD_NOTIFIER_H_
diff --git a/chromium/components/offline_pages/offline_page_archiver.h b/chromium/components/offline_pages/offline_page_archiver.h
index 50cb5a14c1a..ca605bef35c 100644
--- a/chromium/components/offline_pages/offline_page_archiver.h
+++ b/chromium/components/offline_pages/offline_page_archiver.h
@@ -62,7 +62,9 @@ class OfflinePageArchiver {
ArchiverResult /* result */,
const GURL& /* url */,
const base::FilePath& /* file_path */,
- int64_t /* file_size */)> CreateArchiveCallback;
+ const base::string16& /* title */,
+ int64_t /* file_size */)>
+ CreateArchiveCallback;
virtual ~OfflinePageArchiver() {}
diff --git a/chromium/components/offline_pages/offline_page_client_policy.h b/chromium/components/offline_pages/offline_page_client_policy.h
index de7ae526b00..20fd564ecb9 100644
--- a/chromium/components/offline_pages/offline_page_client_policy.h
+++ b/chromium/components/offline_pages/offline_page_client_policy.h
@@ -32,11 +32,28 @@ struct LifetimePolicy {
LifetimeType lifetime_type;
// The time after which the page expires.
+ // A TimeDelta of 0 means no expiration.
base::TimeDelta expiration_period;
// The maximum number of pages allowed to be saved by the namespace.
// kUnlimitedPages (defined above) means no limit set.
size_t page_limit;
+
+ LifetimePolicy(LifetimeType init_lifetime_type, size_t init_page_limit)
+ : lifetime_type(init_lifetime_type),
+ expiration_period(base::TimeDelta::FromDays(0)),
+ page_limit(init_page_limit){};
+};
+
+// The struct describing feature set of the offline pages.
+struct FeaturePolicy {
+ // Whether pages are shown in download ui.
+ bool is_supported_by_download;
+ // Whether pages are removed on user-initiated cache reset. Defaults to true.
+ bool is_removed_on_cache_reset;
+
+ FeaturePolicy()
+ : is_supported_by_download(false), is_removed_on_cache_reset(true){};
};
// The struct describing policies for various namespaces (Bookmark, Last-N etc.)
@@ -52,6 +69,65 @@ struct OfflinePageClientPolicy {
// How many pages for the same online URL can be stored at any time.
// kUnlimitedPages means there's no limit.
size_t pages_allowed_per_url;
+
+ FeaturePolicy feature_policy;
+
+ OfflinePageClientPolicy(std::string namespace_val,
+ LifetimePolicy lifetime_policy_val,
+ size_t pages_allowed_per_url_val,
+ FeaturePolicy feature_policy_val)
+ : name_space(namespace_val),
+ lifetime_policy(lifetime_policy_val),
+ pages_allowed_per_url(pages_allowed_per_url_val),
+ feature_policy(feature_policy_val){};
+
+ OfflinePageClientPolicy(std::string namespace_val,
+ LifetimePolicy lifetime_policy_val,
+ size_t pages_allowed_per_url_val)
+ : OfflinePageClientPolicy(namespace_val,
+ lifetime_policy_val,
+ pages_allowed_per_url_val,
+ FeaturePolicy()){};
+};
+
+class OfflinePageClientPolicyBuilder {
+ public:
+ OfflinePageClientPolicyBuilder(const std::string& name_space,
+ LifetimePolicy::LifetimeType lifetime_type,
+ size_t page_limit,
+ size_t pages_allowed_per_url)
+ : policy_(
+ OfflinePageClientPolicy(name_space,
+ LifetimePolicy(lifetime_type, page_limit),
+ pages_allowed_per_url)){};
+
+ ~OfflinePageClientPolicyBuilder() {}
+
+ // Calling build does not reset the object inside.
+ const OfflinePageClientPolicy Build() const { return policy_; }
+
+ OfflinePageClientPolicyBuilder& SetExpirePeriod(
+ const base::TimeDelta& expire_period) {
+ policy_.lifetime_policy.expiration_period = expire_period;
+ return *this;
+ }
+
+ OfflinePageClientPolicyBuilder& SetIsSupportedByDownload(
+ const bool is_downloaded) {
+ policy_.feature_policy.is_supported_by_download = is_downloaded;
+ return *this;
+ }
+
+ OfflinePageClientPolicyBuilder& SetIsRemovedOnCacheReset(
+ const bool removed_on_cache_reset) {
+ policy_.feature_policy.is_removed_on_cache_reset = removed_on_cache_reset;
+ return *this;
+ }
+
+ private:
+ OfflinePageClientPolicy policy_;
+
+ DISALLOW_COPY_AND_ASSIGN(OfflinePageClientPolicyBuilder);
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/offline_page_feature.cc b/chromium/components/offline_pages/offline_page_feature.cc
index d522bc96586..c469846124d 100644
--- a/chromium/components/offline_pages/offline_page_feature.cc
+++ b/chromium/components/offline_pages/offline_page_feature.cc
@@ -23,13 +23,14 @@ const base::Feature kOfflinePagesBackgroundLoadingFeature {
};
const base::Feature kOfflinePagesCTFeature {
- "OfflinePagesCT", base::FEATURE_DISABLED_BY_DEFAULT
+ "OfflinePagesCT", base::FEATURE_ENABLED_BY_DEFAULT
};
-bool IsOfflinePagesEnabled() {
- return IsOfflineBookmarksEnabled() || IsOffliningRecentPagesEnabled() ||
- IsOfflinePagesBackgroundLoadingEnabled() || IsOfflinePagesCTEnabled();
-}
+const base::Feature kOfflinePagesSharingFeature{
+ "OfflinePagesSharing", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kBackgroundLoaderForDownloadsFeature{
+ "BackgroundLoadingForDownloads", base::FEATURE_ENABLED_BY_DEFAULT};
bool IsOfflineBookmarksEnabled() {
return base::FeatureList::IsEnabled(kOfflineBookmarksFeature);
@@ -47,4 +48,12 @@ bool IsOfflinePagesCTEnabled() {
return base::FeatureList::IsEnabled(kOfflinePagesCTFeature);
}
+bool IsOfflinePagesSharingEnabled() {
+ return base::FeatureList::IsEnabled(kOfflinePagesSharingFeature);
+}
+
+bool IsBackgroundLoaderForDownloadsEnabled() {
+ return base::FeatureList::IsEnabled(kBackgroundLoaderForDownloadsFeature);
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/offline_page_feature.h b/chromium/components/offline_pages/offline_page_feature.h
index bdfefaf2996..98c1b27e911 100644
--- a/chromium/components/offline_pages/offline_page_feature.h
+++ b/chromium/components/offline_pages/offline_page_feature.h
@@ -14,10 +14,8 @@ extern const base::Feature kOfflineBookmarksFeature;
extern const base::Feature kOffliningRecentPagesFeature;
extern const base::Feature kOfflinePagesBackgroundLoadingFeature;
extern const base::Feature kOfflinePagesCTFeature;
-
-// Returns true if offline pages, as result of one or more offline features
-// being enabled, is enabled.
-bool IsOfflinePagesEnabled();
+extern const base::Feature kOfflinePagesSharingFeature;
+extern const base::Feature kBackgroundLoaderForDownloadsFeature;
// Returns true if saving bookmarked pages for offline viewing is enabled.
bool IsOfflineBookmarksEnabled();
@@ -31,6 +29,12 @@ bool IsOfflinePagesBackgroundLoadingEnabled();
// Returns true if offline CT features are enabled. See crbug.com/620421.
bool IsOfflinePagesCTEnabled();
+// Returns true if offline page sharing is enabled.
+bool IsOfflinePagesSharingEnabled();
+
+bool IsBackgroundLoaderForDownloadsEnabled();
+
} // namespace offline_pages
-#endif // COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_FEATURE_H_
+#endif // COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_FEATURE_H_>>>> Flag for Offline
+ // Page Sharing
diff --git a/chromium/components/offline_pages/offline_page_item.cc b/chromium/components/offline_pages/offline_page_item.cc
index 3fca9fcd47e..41b96e0e919 100644
--- a/chromium/components/offline_pages/offline_page_item.cc
+++ b/chromium/components/offline_pages/offline_page_item.cc
@@ -4,14 +4,8 @@
#include "components/offline_pages/offline_page_item.h"
-#include "net/base/filename_util.h"
-
namespace offline_pages {
-namespace {
-const int kCurrentVersion = 1;
-}
-
ClientId::ClientId() : name_space(""), id("") {}
ClientId::ClientId(std::string name_space, std::string id)
@@ -21,13 +15,16 @@ bool ClientId::operator==(const ClientId& client_id) const {
return name_space == client_id.name_space && id == client_id.id;
}
-OfflinePageItem::OfflinePageItem()
- : version(kCurrentVersion),
- file_size(0),
- access_count(0),
- flags(NO_FLAG) {
+bool ClientId::operator<(const ClientId& client_id) const {
+ if (name_space == client_id.name_space)
+ return (id < client_id.id);
+
+ return name_space < client_id.name_space;
}
+OfflinePageItem::OfflinePageItem()
+ : file_size(0), access_count(0), flags(NO_FLAG) {}
+
OfflinePageItem::OfflinePageItem(const GURL& url,
int64_t offline_id,
const ClientId& client_id,
@@ -36,7 +33,6 @@ OfflinePageItem::OfflinePageItem(const GURL& url,
: url(url),
offline_id(offline_id),
client_id(client_id),
- version(kCurrentVersion),
file_path(file_path),
file_size(file_size),
access_count(0),
@@ -51,7 +47,6 @@ OfflinePageItem::OfflinePageItem(const GURL& url,
: url(url),
offline_id(offline_id),
client_id(client_id),
- version(kCurrentVersion),
file_path(file_path),
file_size(file_size),
creation_time(creation_time),
@@ -64,8 +59,17 @@ OfflinePageItem::OfflinePageItem(const OfflinePageItem& other) = default;
OfflinePageItem::~OfflinePageItem() {
}
-GURL OfflinePageItem::GetOfflineURL() const {
- return net::FilePathToFileURL(file_path);
+bool OfflinePageItem::operator==(const OfflinePageItem& other) const {
+ return url == other.url &&
+ offline_id == other.offline_id &&
+ client_id == other.client_id &&
+ file_path == other.file_path &&
+ creation_time == other.creation_time &&
+ last_access_time == other.last_access_time &&
+ expiration_time == other.expiration_time &&
+ access_count == other.access_count &&
+ title == other.title &&
+ flags == other.flags;
}
bool OfflinePageItem::IsExpired() const {
diff --git a/chromium/components/offline_pages/offline_page_item.h b/chromium/components/offline_pages/offline_page_item.h
index 469c822212d..72f43626aff 100644
--- a/chromium/components/offline_pages/offline_page_item.h
+++ b/chromium/components/offline_pages/offline_page_item.h
@@ -26,6 +26,8 @@ struct ClientId {
ClientId(std::string name_space, std::string id);
bool operator==(const ClientId& client_id) const;
+
+ bool operator<(const ClientId& client_id) const;
};
// Metadata of the offline page.
@@ -52,8 +54,7 @@ struct OfflinePageItem {
OfflinePageItem(const OfflinePageItem& other);
~OfflinePageItem();
- // Gets a URL of the file under |file_path|.
- GURL GetOfflineURL() const;
+ bool operator==(const OfflinePageItem& other) const;
// Returns whether the offline page is expired.
bool IsExpired() const;
@@ -68,8 +69,6 @@ struct OfflinePageItem {
// their ids to our saved pages.
ClientId client_id;
- // Version of the offline page item.
- int version;
// The file path to the archive with a local copy of the page.
base::FilePath file_path;
// The size of the offline copy.
@@ -82,6 +81,8 @@ struct OfflinePageItem {
base::Time expiration_time;
// Number of times that the offline archive has been accessed.
int access_count;
+ // The title of the page at the time it was saved.
+ base::string16 title;
// Flags about the state and behavior of the offline page.
Flags flags;
};
diff --git a/chromium/components/offline_pages/offline_page_metadata_store.cc b/chromium/components/offline_pages/offline_page_metadata_store.cc
index e5cf0581652..24af10b37a3 100644
--- a/chromium/components/offline_pages/offline_page_metadata_store.cc
+++ b/chromium/components/offline_pages/offline_page_metadata_store.cc
@@ -6,6 +6,8 @@
namespace offline_pages {
+template class StoreUpdateResult<OfflinePageItem>;
+
OfflinePageMetadataStore::OfflinePageMetadataStore() {
}
diff --git a/chromium/components/offline_pages/offline_page_metadata_store.h b/chromium/components/offline_pages/offline_page_metadata_store.h
index e4c57c5fc41..26314804bdc 100644
--- a/chromium/components/offline_pages/offline_page_metadata_store.h
+++ b/chromium/components/offline_pages/offline_page_metadata_store.h
@@ -10,12 +10,14 @@
#include <vector>
#include "base/callback.h"
+#include "components/offline_pages/offline_page_item.h"
+#include "components/offline_pages/offline_store_types.h"
class GURL;
namespace offline_pages {
-struct OfflinePageItem;
+typedef StoreUpdateResult<OfflinePageItem> OfflinePagesUpdateResult;
// OfflinePageMetadataStore keeps metadata for the offline pages.
// Ability to create multiple instances of the store as well as behavior of
@@ -38,19 +40,24 @@ class OfflinePageMetadataStore {
typedef base::Callback<void(LoadStatus, const std::vector<OfflinePageItem>&)>
LoadCallback;
- typedef base::Callback<void(bool)> UpdateCallback;
+ typedef base::Callback<void(ItemActionStatus)> AddCallback;
+ typedef base::Callback<void(std::unique_ptr<OfflinePagesUpdateResult>)>
+ UpdateCallback;
typedef base::Callback<void(bool)> ResetCallback;
OfflinePageMetadataStore();
virtual ~OfflinePageMetadataStore();
// Get all of the offline pages from the store.
- virtual void Load(const LoadCallback& callback) = 0;
+ virtual void GetOfflinePages(const LoadCallback& callback) = 0;
- // Asynchronously adds or updates offline page metadata to the store.
- // Result of the update is passed in callback.
- virtual void AddOrUpdateOfflinePage(const OfflinePageItem& offline_page,
- const UpdateCallback& callback) = 0;
+ // Asynchronously adds an offline page item metadata to the store.
+ virtual void AddOfflinePage(const OfflinePageItem& offline_page,
+ const AddCallback& callback) = 0;
+
+ // Asynchronously updates a set of offline page items in the store.
+ virtual void UpdateOfflinePages(const std::vector<OfflinePageItem>& pages,
+ const UpdateCallback& callback) = 0;
// Asynchronously removes offline page metadata from the store.
// Result of the update is passed in callback.
@@ -59,6 +66,9 @@ class OfflinePageMetadataStore {
// Resets the store.
virtual void Reset(const ResetCallback& callback) = 0;
+
+ // Gets the store state.
+ virtual StoreState state() const = 0;
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/offline_page_metadata_store_impl_unittest.cc b/chromium/components/offline_pages/offline_page_metadata_store_impl_unittest.cc
index f698d01d694..fd89194257f 100644
--- a/chromium/components/offline_pages/offline_page_metadata_store_impl_unittest.cc
+++ b/chromium/components/offline_pages/offline_page_metadata_store_impl_unittest.cc
@@ -39,7 +39,7 @@ int64_t kOfflineId = 12345LL;
// Build a store with outdated schema to simulate the upgrading process.
// TODO(romax): move it to sql_unittests.
-void BuildTestStoreWithOutdatedSchema(const base::FilePath& file) {
+void BuildTestStoreWithSchemaFromM52(const base::FilePath& file) {
sql::Connection connection;
ASSERT_TRUE(
connection.Open(file.Append(FILE_PATH_LITERAL("OfflinePages.db"))));
@@ -83,37 +83,140 @@ void BuildTestStoreWithOutdatedSchema(const base::FilePath& file) {
connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "expiration_time"));
}
+void BuildTestStoreWithSchemaFromM53(const base::FilePath& file) {
+ sql::Connection connection;
+ ASSERT_TRUE(
+ connection.Open(file.Append(FILE_PATH_LITERAL("OfflinePages.db"))));
+ ASSERT_TRUE(connection.is_open());
+ ASSERT_TRUE(connection.BeginTransaction());
+ ASSERT_TRUE(connection.Execute("CREATE TABLE " OFFLINE_PAGES_TABLE_V1
+ "(offline_id INTEGER PRIMARY KEY NOT NULL, "
+ "creation_time INTEGER NOT NULL, "
+ "file_size INTEGER NOT NULL, "
+ "version INTEGER NOT NULL, "
+ "last_access_time INTEGER NOT NULL, "
+ "access_count INTEGER NOT NULL, "
+ "status INTEGER NOT NULL DEFAULT 0, "
+ "user_initiated INTEGER, "
+ "expiration_time INTEGER NOT NULL DEFAULT 0, "
+ "client_namespace VARCHAR NOT NULL, "
+ "client_id VARCHAR NOT NULL, "
+ "online_url VARCHAR NOT NULL, "
+ "offline_url VARCHAR NOT NULL DEFAULT '', "
+ "file_path VARCHAR NOT NULL "
+ ")"));
+ ASSERT_TRUE(connection.CommitTransaction());
+ sql::Statement statement(connection.GetUniqueStatement(
+ "INSERT INTO " OFFLINE_PAGES_TABLE_V1
+ "(offline_id, creation_time, file_size, version, "
+ "last_access_time, access_count, client_namespace, "
+ "client_id, online_url, file_path, expiration_time) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+ statement.BindInt64(0, kOfflineId);
+ statement.BindInt(1, 0);
+ statement.BindInt64(2, kFileSize);
+ statement.BindInt(3, 0);
+ statement.BindInt(4, 0);
+ statement.BindInt(5, 1);
+ statement.BindCString(6, kTestClientNamespace);
+ statement.BindString(7, kTestClientId2.id);
+ statement.BindCString(8, kTestURL);
+ statement.BindString(9, base::FilePath(kFilePath).MaybeAsASCII());
+ statement.BindInt64(10, base::Time::Now().ToInternalValue());
+ ASSERT_TRUE(statement.Run());
+ ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1));
+ ASSERT_FALSE(connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "title"));
+}
+
+void BuildTestStoreWithSchemaFromM54(const base::FilePath& file) {
+ sql::Connection connection;
+ ASSERT_TRUE(
+ connection.Open(file.Append(FILE_PATH_LITERAL("OfflinePages.db"))));
+ ASSERT_TRUE(connection.is_open());
+ ASSERT_TRUE(connection.BeginTransaction());
+ ASSERT_TRUE(connection.Execute("CREATE TABLE " OFFLINE_PAGES_TABLE_V1
+ "(offline_id INTEGER PRIMARY KEY NOT NULL, "
+ "creation_time INTEGER NOT NULL, "
+ "file_size INTEGER NOT NULL, "
+ "version INTEGER NOT NULL, "
+ "last_access_time INTEGER NOT NULL, "
+ "access_count INTEGER NOT NULL, "
+ "status INTEGER NOT NULL DEFAULT 0, "
+ "user_initiated INTEGER, "
+ "expiration_time INTEGER NOT NULL DEFAULT 0, "
+ "client_namespace VARCHAR NOT NULL, "
+ "client_id VARCHAR NOT NULL, "
+ "online_url VARCHAR NOT NULL, "
+ "offline_url VARCHAR NOT NULL DEFAULT '', "
+ "file_path VARCHAR NOT NULL "
+ "title VARCHAR NOT NULL DEFAULT ''"
+ ")"));
+ ASSERT_TRUE(connection.CommitTransaction());
+ sql::Statement statement(connection.GetUniqueStatement(
+ "INSERT INTO " OFFLINE_PAGES_TABLE_V1
+ "(offline_id, creation_time, file_size, version, "
+ "last_access_time, access_count, client_namespace, "
+ "client_id, online_url, file_path, expiration_time, title) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+ statement.BindInt64(0, kOfflineId);
+ statement.BindInt(1, 0);
+ statement.BindInt64(2, kFileSize);
+ statement.BindInt(3, 0);
+ statement.BindInt(4, 0);
+ statement.BindInt(5, 1);
+ statement.BindCString(6, kTestClientNamespace);
+ statement.BindString(7, kTestClientId2.id);
+ statement.BindCString(8, kTestURL);
+ statement.BindString(9, base::FilePath(kFilePath).MaybeAsASCII());
+ statement.BindInt64(10, base::Time::Now().ToInternalValue());
+ statement.BindString16(11, base::UTF8ToUTF16("Test title"));
+ ASSERT_TRUE(statement.Run());
+ ASSERT_TRUE(connection.DoesTableExist(OFFLINE_PAGES_TABLE_V1));
+ ASSERT_TRUE(connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "version"));
+ ASSERT_TRUE(connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "status"));
+ ASSERT_TRUE(
+ connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "user_initiated"));
+ ASSERT_TRUE(
+ connection.DoesColumnExist(OFFLINE_PAGES_TABLE_V1, "offline_url"));
+}
+
class OfflinePageMetadataStoreFactory {
public:
- virtual OfflinePageMetadataStore* BuildStore(const base::FilePath& file) = 0;
- virtual OfflinePageMetadataStore* BuildStoreV1(
- const base::FilePath& file) = 0;
-};
+ OfflinePageMetadataStore* BuildStore(const base::FilePath& file_path) {
+ OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
+ base::ThreadTaskRunnerHandle::Get(), file_path);
+ return store;
+ }
-class OfflinePageMetadataStoreSQLFactory
- : public OfflinePageMetadataStoreFactory {
- public:
- OfflinePageMetadataStore* BuildStore(const base::FilePath& file) override {
+ OfflinePageMetadataStore* BuildStoreM52(const base::FilePath& file_path) {
+ BuildTestStoreWithSchemaFromM52(file_path);
+ OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
+ base::ThreadTaskRunnerHandle::Get(), file_path);
+ return store;
+ }
+
+ OfflinePageMetadataStore* BuildStoreM53(const base::FilePath& file_path) {
+ BuildTestStoreWithSchemaFromM53(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
- base::ThreadTaskRunnerHandle::Get(), file);
+ base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
- OfflinePageMetadataStore* BuildStoreV1(const base::FilePath& file) override {
- BuildTestStoreWithOutdatedSchema(file);
+ OfflinePageMetadataStore* BuildStoreM54(const base::FilePath& file_path) {
+ BuildTestStoreWithSchemaFromM54(file_path);
OfflinePageMetadataStoreSQL* store = new OfflinePageMetadataStoreSQL(
- base::ThreadTaskRunnerHandle::Get(), file);
+ base::ThreadTaskRunnerHandle::Get(), file_path);
return store;
}
};
-enum CalledCallback { NONE, LOAD, ADD, REMOVE, RESET };
+enum CalledCallback { NONE, LOAD, ADD, UPDATE, REMOVE, RESET };
enum Status { STATUS_NONE, STATUS_TRUE, STATUS_FALSE };
-class OfflinePageMetadataStoreTestBase : public testing::Test {
+class OfflinePageMetadataStoreTest : public testing::Test {
public:
- OfflinePageMetadataStoreTestBase();
- ~OfflinePageMetadataStoreTestBase() override;
+ OfflinePageMetadataStoreTest();
+ ~OfflinePageMetadataStoreTest() override;
void TearDown() override {
// Wait for all the pieces of the store to delete itself properly.
@@ -121,25 +224,43 @@ class OfflinePageMetadataStoreTestBase : public testing::Test {
}
std::unique_ptr<OfflinePageMetadataStore> BuildStore();
+ std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM52();
+ std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM53();
+ std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM54();
+
void PumpLoop();
- void LoadCallback(OfflinePageMetadataStore::LoadStatus load_status,
- const std::vector<OfflinePageItem>& offline_pages);
- void UpdateCallback(CalledCallback called_callback, bool success);
+ void GetOfflinePagesCallback(
+ OfflinePageMetadataStore::LoadStatus load_status,
+ const std::vector<OfflinePageItem>& offline_pages);
+ void AddCallback(ItemActionStatus status);
+ void UpdateCallback(CalledCallback called_callback,
+ std::unique_ptr<OfflinePagesUpdateResult> result);
+ void ResetCallback(bool status);
void ClearResults();
+ OfflinePageItem CheckThatStoreHasOneItem();
+ void CheckThatOfflinePageCanBeSaved(
+ std::unique_ptr<OfflinePageMetadataStore> store);
+
+ OfflinePagesUpdateResult* last_update_result() {
+ return last_update_result_.get();
+ }
+
protected:
CalledCallback last_called_callback_;
Status last_status_;
+ std::unique_ptr<OfflinePagesUpdateResult> last_update_result_;
std::vector<OfflinePageItem> offline_pages_;
+ OfflinePageMetadataStoreFactory factory_;
base::ScopedTempDir temp_directory_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
};
-OfflinePageMetadataStoreTestBase::OfflinePageMetadataStoreTestBase()
+OfflinePageMetadataStoreTest::OfflinePageMetadataStoreTest()
: last_called_callback_(NONE),
last_status_(STATUS_NONE),
task_runner_(new base::TestSimpleTaskRunner),
@@ -147,13 +268,13 @@ OfflinePageMetadataStoreTestBase::OfflinePageMetadataStoreTestBase()
EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
}
-OfflinePageMetadataStoreTestBase::~OfflinePageMetadataStoreTestBase() {}
+OfflinePageMetadataStoreTest::~OfflinePageMetadataStoreTest() {}
-void OfflinePageMetadataStoreTestBase::PumpLoop() {
+void OfflinePageMetadataStoreTest::PumpLoop() {
task_runner_->RunUntilIdle();
}
-void OfflinePageMetadataStoreTestBase::LoadCallback(
+void OfflinePageMetadataStoreTest::GetOfflinePagesCallback(
OfflinePageMetadataStore::LoadStatus load_status,
const std::vector<OfflinePageItem>& offline_pages) {
last_called_callback_ = LOAD;
@@ -162,207 +283,337 @@ void OfflinePageMetadataStoreTestBase::LoadCallback(
offline_pages_.swap(const_cast<std::vector<OfflinePageItem>&>(offline_pages));
}
-void OfflinePageMetadataStoreTestBase::UpdateCallback(
+void OfflinePageMetadataStoreTest::AddCallback(ItemActionStatus status) {
+ last_called_callback_ = ADD;
+ // TODO(fgorski): Add specific add status.
+ // last_item_status_ = status;
+ last_status_ =
+ status == ItemActionStatus::SUCCESS ? STATUS_TRUE : STATUS_FALSE;
+}
+
+void OfflinePageMetadataStoreTest::UpdateCallback(
CalledCallback called_callback,
- bool status) {
+ std::unique_ptr<OfflinePagesUpdateResult> result) {
last_called_callback_ = called_callback;
+ last_status_ = result->updated_items.size() > 0 ? STATUS_TRUE : STATUS_FALSE;
+ last_update_result_ = std::move(result);
+}
+
+void OfflinePageMetadataStoreTest::ResetCallback(bool status) {
+ last_called_callback_ = RESET;
last_status_ = status ? STATUS_TRUE : STATUS_FALSE;
}
-void OfflinePageMetadataStoreTestBase::ClearResults() {
+void OfflinePageMetadataStoreTest::ClearResults() {
last_called_callback_ = NONE;
last_status_ = STATUS_NONE;
offline_pages_.clear();
+ last_update_result_.reset(nullptr);
}
-template <typename T>
-class OfflinePageMetadataStoreTest : public OfflinePageMetadataStoreTestBase {
- public:
- std::unique_ptr<OfflinePageMetadataStore> BuildStore();
- std::unique_ptr<OfflinePageMetadataStore>
- BuildStoreWithUpgradeFromOutdatedSchema();
+OfflinePageItem OfflinePageMetadataStoreTest::CheckThatStoreHasOneItem() {
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ EXPECT_EQ(1U, offline_pages_.size());
- protected:
- T factory_;
-};
+ return offline_pages_[0];
+}
+
+void OfflinePageMetadataStoreTest::CheckThatOfflinePageCanBeSaved(
+ std::unique_ptr<OfflinePageMetadataStore> store) {
+ size_t store_size = offline_pages_.size();
+ OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
+ base::FilePath(kFilePath), kFileSize);
+ offline_page.title = base::UTF8ToUTF16("a title");
+ base::Time expiration_time = base::Time::Now();
+ offline_page.expiration_time = expiration_time;
+
+ store->AddOfflinePage(offline_page,
+ base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(ADD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ ClearResults();
+
+ // Close the store first to ensure file lock is removed.
+ store.reset();
+ store = BuildStore();
+ PumpLoop();
+
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ ASSERT_EQ(store_size + 1, offline_pages_.size());
+ if (store_size > 0 &&
+ offline_pages_[0].offline_id != offline_page.offline_id) {
+ std::swap(offline_pages_[0], offline_pages_[1]);
+ }
+ EXPECT_EQ(offline_page, offline_pages_[0]);
+}
-template <typename T>
std::unique_ptr<OfflinePageMetadataStore>
-OfflinePageMetadataStoreTest<T>::BuildStore() {
+OfflinePageMetadataStoreTest::BuildStore() {
std::unique_ptr<OfflinePageMetadataStore> store(
- factory_.BuildStore(temp_directory_.path()));
- store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
- base::Unretained(this)));
+ factory_.BuildStore(temp_directory_.GetPath()));
+ PumpLoop();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
PumpLoop();
return store;
}
-template <typename T>
std::unique_ptr<OfflinePageMetadataStore>
-OfflinePageMetadataStoreTest<T>::BuildStoreWithUpgradeFromOutdatedSchema() {
+OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM52() {
std::unique_ptr<OfflinePageMetadataStore> store(
- factory_.BuildStoreV1(temp_directory_.path()));
- store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
- base::Unretained(this)));
+ factory_.BuildStoreM52(temp_directory_.GetPath()));
+ PumpLoop();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
PumpLoop();
return store;
}
-typedef testing::Types<OfflinePageMetadataStoreSQLFactory> MyTypes;
-TYPED_TEST_CASE(OfflinePageMetadataStoreTest, MyTypes);
+std::unique_ptr<OfflinePageMetadataStore>
+OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM53() {
+ std::unique_ptr<OfflinePageMetadataStore> store(
+ factory_.BuildStoreM53(temp_directory_.GetPath()));
+ PumpLoop();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ return store;
+}
+
+std::unique_ptr<OfflinePageMetadataStore>
+OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM54() {
+ std::unique_ptr<OfflinePageMetadataStore> store(
+ factory_.BuildStoreM53(temp_directory_.GetPath()));
+ PumpLoop();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ return store;
+}
// Loads empty store and makes sure that there are no offline pages stored in
// it.
-TYPED_TEST(OfflinePageMetadataStoreTest, LoadEmptyStore) {
- std::unique_ptr<OfflinePageMetadataStore> store(this->BuildStore());
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- EXPECT_EQ(0U, this->offline_pages_.size());
+TEST_F(OfflinePageMetadataStoreTest, LoadEmptyStore) {
+ std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ EXPECT_EQ(0U, offline_pages_.size());
+}
+
+TEST_F(OfflinePageMetadataStoreTest, GetOfflinePagesFromInvalidStore) {
+ std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
+ OfflinePageMetadataStoreSQL* sql_store =
+ static_cast<OfflinePageMetadataStoreSQL*>(store.get());
+
+ sql_store->SetStateForTesting(StoreState::NOT_LOADED, false);
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(0UL, offline_pages_.size());
+ EXPECT_EQ(STATUS_FALSE, last_status_);
+
+ sql_store->SetStateForTesting(StoreState::FAILED_LOADING, false);
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(0UL, offline_pages_.size());
+ EXPECT_EQ(STATUS_FALSE, last_status_);
+
+ sql_store->SetStateForTesting(StoreState::FAILED_RESET, false);
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(0UL, offline_pages_.size());
+ EXPECT_EQ(STATUS_FALSE, last_status_);
+
+ sql_store->SetStateForTesting(StoreState::LOADED, true);
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(0UL, offline_pages_.size());
+ EXPECT_EQ(STATUS_FALSE, last_status_);
+
+ sql_store->SetStateForTesting(StoreState::NOT_LOADED, true);
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(0UL, offline_pages_.size());
+ EXPECT_EQ(STATUS_FALSE, last_status_);
+
+ sql_store->SetStateForTesting(StoreState::FAILED_LOADING, false);
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(0UL, offline_pages_.size());
+ EXPECT_EQ(STATUS_FALSE, last_status_);
+
+ sql_store->SetStateForTesting(StoreState::FAILED_RESET, false);
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(0UL, offline_pages_.size());
+ EXPECT_EQ(STATUS_FALSE, last_status_);
+
}
// Loads a store which has an outdated schema.
// This test case would crash if it's not handling correctly when we're loading
// old version stores.
// TODO(romax): Move this to sql_unittest.
-TYPED_TEST(OfflinePageMetadataStoreTest, LoadPreviousVersionStore) {
+TEST_F(OfflinePageMetadataStoreTest, LoadVersion52Store) {
std::unique_ptr<OfflinePageMetadataStore> store(
- this->BuildStoreWithUpgradeFromOutdatedSchema());
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- EXPECT_EQ(1U, this->offline_pages_.size());
- OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
- base::FilePath(kFilePath), kFileSize);
- base::Time expiration_time = base::Time::Now();
- offline_page.expiration_time = expiration_time;
- store->AddOrUpdateOfflinePage(
- offline_page,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), ADD));
- this->PumpLoop();
- EXPECT_EQ(ADD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- this->ClearResults();
+ BuildStoreWithSchemaFromM52());
- // Close the store first to ensure file lock is removed.
- store.reset();
- store = this->BuildStore();
- this->PumpLoop();
-
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- ASSERT_EQ(2U, this->offline_pages_.size());
- if (this->offline_pages_[0].offline_id != offline_page.offline_id) {
- std::swap(this->offline_pages_[0], this->offline_pages_[1]);
- }
- EXPECT_EQ(offline_page.url, this->offline_pages_[0].url);
- EXPECT_EQ(offline_page.offline_id, this->offline_pages_[0].offline_id);
- EXPECT_EQ(offline_page.file_path, this->offline_pages_[0].file_path);
- EXPECT_EQ(offline_page.last_access_time,
- this->offline_pages_[0].last_access_time);
- EXPECT_EQ(offline_page.expiration_time,
- this->offline_pages_[0].expiration_time);
- EXPECT_EQ(offline_page.client_id, this->offline_pages_[0].client_id);
- EXPECT_EQ(kOfflineId, this->offline_pages_[1].offline_id);
- EXPECT_EQ(kFileSize, this->offline_pages_[1].file_size);
- EXPECT_EQ(kTestClientId2, this->offline_pages_[1].client_id);
+ CheckThatStoreHasOneItem();
+ CheckThatOfflinePageCanBeSaved(std::move(store));
+}
+
+// Loads a store which has an outdated schema.
+// This test case would crash if it's not handling correctly when we're loading
+// old version stores.
+// TODO(romax): Move this to sql_unittest.
+TEST_F(OfflinePageMetadataStoreTest, LoadVersion53Store) {
+ std::unique_ptr<OfflinePageMetadataStore> store(
+ BuildStoreWithSchemaFromM53());
+
+ OfflinePageItem item = CheckThatStoreHasOneItem();
+ // We should have a valid expiration time after upgrade.
+ EXPECT_NE(base::Time::FromInternalValue(0),
+ offline_pages_[0].expiration_time);
+
+ CheckThatOfflinePageCanBeSaved(std::move(store));
+}
+
+// Loads a string with schema from M54.
+// Because for now we only reduce the number of fields it just makes sure there
+// are no crashes in the process.
+// TODO(romax): Move this to sql_unittest.
+TEST_F(OfflinePageMetadataStoreTest, LoadVersion54Store) {
+ std::unique_ptr<OfflinePageMetadataStore> store(
+ BuildStoreWithSchemaFromM54());
+
+ OfflinePageItem item = CheckThatStoreHasOneItem();
+
+ CheckThatOfflinePageCanBeSaved(std::move(store));
}
// Adds metadata of an offline page into a store and then opens the store
// again to make sure that stored metadata survives store restarts.
-TYPED_TEST(OfflinePageMetadataStoreTest, AddOfflinePage) {
- std::unique_ptr<OfflinePageMetadataStore> store(this->BuildStore());
+TEST_F(OfflinePageMetadataStoreTest, AddOfflinePage) {
+ CheckThatOfflinePageCanBeSaved(BuildStore());
+}
+
+TEST_F(OfflinePageMetadataStoreTest, AddSameOfflinePageTwice) {
+ std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
+
OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
base::FilePath(kFilePath), kFileSize);
- store->AddOrUpdateOfflinePage(
- offline_page,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), ADD));
- this->PumpLoop();
- EXPECT_EQ(ADD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
+ offline_page.title = base::UTF8ToUTF16("a title");
+ base::Time expiration_time = base::Time::Now();
+ offline_page.expiration_time = expiration_time;
- this->ClearResults();
+ store->AddOfflinePage(offline_page,
+ base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(ADD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ ClearResults();
- // Close the store first to ensure file lock is removed.
- store.reset();
- store = this->BuildStore();
- this->PumpLoop();
-
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- ASSERT_EQ(1U, this->offline_pages_.size());
- EXPECT_EQ(offline_page.url, this->offline_pages_[0].url);
- EXPECT_EQ(offline_page.offline_id, this->offline_pages_[0].offline_id);
- EXPECT_EQ(offline_page.version, this->offline_pages_[0].version);
- EXPECT_EQ(offline_page.file_path, this->offline_pages_[0].file_path);
- EXPECT_EQ(offline_page.file_size, this->offline_pages_[0].file_size);
- EXPECT_EQ(offline_page.creation_time, this->offline_pages_[0].creation_time);
- EXPECT_EQ(offline_page.last_access_time,
- this->offline_pages_[0].last_access_time);
- EXPECT_EQ(offline_page.expiration_time,
- this->offline_pages_[0].expiration_time);
- EXPECT_EQ(offline_page.access_count, this->offline_pages_[0].access_count);
- EXPECT_EQ(offline_page.client_id, this->offline_pages_[0].client_id);
+ store->AddOfflinePage(offline_page,
+ base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(ADD, last_called_callback_);
+ EXPECT_EQ(STATUS_FALSE, last_status_);
}
// Tests removing offline page metadata from the store, for which it first adds
// metadata of an offline page.
-TYPED_TEST(OfflinePageMetadataStoreTest, RemoveOfflinePage) {
- std::unique_ptr<OfflinePageMetadataStore> store(this->BuildStore());
+TEST_F(OfflinePageMetadataStoreTest, RemoveOfflinePage) {
+ std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
// Add an offline page.
OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
base::FilePath(kFilePath), kFileSize);
- store->AddOrUpdateOfflinePage(
- offline_page,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), ADD));
- this->PumpLoop();
- EXPECT_EQ(ADD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
+ store->AddOfflinePage(offline_page,
+ base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(ADD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
- this->ClearResults();
+ ClearResults();
// Load the store.
- store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
- base::Unretained(this)));
- this->PumpLoop();
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(1U, this->offline_pages_.size());
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(1U, offline_pages_.size());
// Remove the offline page.
std::vector<int64_t> ids_to_remove;
ids_to_remove.push_back(offline_page.offline_id);
store->RemoveOfflinePages(
- ids_to_remove,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), REMOVE));
- this->PumpLoop();
- EXPECT_EQ(REMOVE, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
+ ids_to_remove, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback,
+ base::Unretained(this), REMOVE));
+ PumpLoop();
+ EXPECT_EQ(REMOVE, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ ASSERT_TRUE(last_update_result() != nullptr);
+ EXPECT_EQ(1UL, last_update_result()->item_statuses.size());
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_update_result()->item_statuses.begin()->second);
+ EXPECT_EQ(1UL, last_update_result()->updated_items.size());
+ EXPECT_EQ(offline_page, *(last_update_result()->updated_items.begin()));
- this->ClearResults();
+ ClearResults();
// Load the store.
- store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
- base::Unretained(this)));
- this->PumpLoop();
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(0U, this->offline_pages_.size());
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(0U, offline_pages_.size());
- this->ClearResults();
+ ClearResults();
// Close and reload the store.
store.reset();
- store = this->BuildStore();
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- EXPECT_EQ(0U, this->offline_pages_.size());
+ store = BuildStore();
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ EXPECT_EQ(0U, offline_pages_.size());
}
// Adds metadata of multiple offline pages into a store and removes some.
-TYPED_TEST(OfflinePageMetadataStoreTest, AddRemoveMultipleOfflinePages) {
- std::unique_ptr<OfflinePageMetadataStore> store(this->BuildStore());
+TEST_F(OfflinePageMetadataStoreTest, AddRemoveMultipleOfflinePages) {
+ std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
// Add an offline page.
OfflinePageItem offline_page_1(GURL(kTestURL), 12345LL, kTestClientId1,
@@ -373,196 +624,184 @@ TYPED_TEST(OfflinePageMetadataStoreTest, AddRemoveMultipleOfflinePages) {
kTestClientId2, file_path_2, 12345,
base::Time::Now());
offline_page_2.expiration_time = base::Time::Now();
- store->AddOrUpdateOfflinePage(
- offline_page_1,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), ADD));
- this->PumpLoop();
- EXPECT_EQ(ADD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
+ store->AddOfflinePage(offline_page_1,
+ base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(ADD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
- this->ClearResults();
+ ClearResults();
// Add anther offline page.
- store->AddOrUpdateOfflinePage(
- offline_page_2,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), ADD));
- this->PumpLoop();
- EXPECT_EQ(ADD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
+ store->AddOfflinePage(offline_page_2,
+ base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(ADD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
- this->ClearResults();
+ ClearResults();
// Load the store.
- store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
- base::Unretained(this)));
- this->PumpLoop();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- EXPECT_EQ(2U, this->offline_pages_.size());
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ EXPECT_EQ(2U, offline_pages_.size());
// Remove the offline page.
std::vector<int64_t> ids_to_remove;
ids_to_remove.push_back(offline_page_1.offline_id);
store->RemoveOfflinePages(
- ids_to_remove,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), REMOVE));
- this->PumpLoop();
- EXPECT_EQ(REMOVE, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
+ ids_to_remove, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback,
+ base::Unretained(this), REMOVE));
+ PumpLoop();
+ EXPECT_EQ(REMOVE, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ ASSERT_TRUE(last_update_result() != nullptr);
+ EXPECT_EQ(1UL, last_update_result()->item_statuses.size());
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_update_result()->item_statuses.begin()->second);
+ EXPECT_EQ(1UL, last_update_result()->updated_items.size());
+ EXPECT_EQ(offline_page_1, *(last_update_result()->updated_items.begin()));
- this->ClearResults();
+ ClearResults();
// Close and reload the store.
store.reset();
- store = this->BuildStore();
- store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
- base::Unretained(this)));
- this->PumpLoop();
-
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- ASSERT_EQ(1U, this->offline_pages_.size());
- EXPECT_EQ(offline_page_2.url, this->offline_pages_[0].url);
- EXPECT_EQ(offline_page_2.offline_id, this->offline_pages_[0].offline_id);
- EXPECT_EQ(offline_page_2.version, this->offline_pages_[0].version);
- EXPECT_EQ(offline_page_2.file_path, this->offline_pages_[0].file_path);
- EXPECT_EQ(offline_page_2.file_size, this->offline_pages_[0].file_size);
- EXPECT_EQ(offline_page_2.creation_time,
- this->offline_pages_[0].creation_time);
+ store = BuildStore();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ ASSERT_EQ(1U, offline_pages_.size());
+ EXPECT_EQ(offline_page_2.url, offline_pages_[0].url);
+ EXPECT_EQ(offline_page_2.offline_id, offline_pages_[0].offline_id);
+ EXPECT_EQ(offline_page_2.file_path, offline_pages_[0].file_path);
+ EXPECT_EQ(offline_page_2.file_size, offline_pages_[0].file_size);
+ EXPECT_EQ(offline_page_2.creation_time, offline_pages_[0].creation_time);
EXPECT_EQ(offline_page_2.last_access_time,
- this->offline_pages_[0].last_access_time);
- EXPECT_EQ(offline_page_2.expiration_time,
- this->offline_pages_[0].expiration_time);
- EXPECT_EQ(offline_page_2.access_count, this->offline_pages_[0].access_count);
- EXPECT_EQ(offline_page_2.client_id, this->offline_pages_[0].client_id);
+ offline_pages_[0].last_access_time);
+ EXPECT_EQ(offline_page_2.expiration_time, offline_pages_[0].expiration_time);
+ EXPECT_EQ(offline_page_2.access_count, offline_pages_[0].access_count);
+ EXPECT_EQ(offline_page_2.client_id, offline_pages_[0].client_id);
}
// Tests updating offline page metadata from the store.
-TYPED_TEST(OfflinePageMetadataStoreTest, UpdateOfflinePage) {
- std::unique_ptr<OfflinePageMetadataStore> store(this->BuildStore());
+TEST_F(OfflinePageMetadataStoreTest, UpdateOfflinePage) {
+ std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
// First, adds a fresh page.
OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
base::FilePath(kFilePath), kFileSize);
- store->AddOrUpdateOfflinePage(
- offline_page,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), ADD));
- this->PumpLoop();
- EXPECT_EQ(ADD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
-
- this->ClearResults();
- store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
- base::Unretained(this)));
- this->PumpLoop();
-
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- ASSERT_EQ(1U, this->offline_pages_.size());
- EXPECT_EQ(offline_page.url, this->offline_pages_[0].url);
- EXPECT_EQ(offline_page.offline_id, this->offline_pages_[0].offline_id);
- EXPECT_EQ(offline_page.version, this->offline_pages_[0].version);
- EXPECT_EQ(offline_page.file_path, this->offline_pages_[0].file_path);
- EXPECT_EQ(offline_page.file_size, this->offline_pages_[0].file_size);
- EXPECT_EQ(offline_page.creation_time, this->offline_pages_[0].creation_time);
- EXPECT_EQ(offline_page.last_access_time,
- this->offline_pages_[0].last_access_time);
- EXPECT_EQ(offline_page.expiration_time,
- this->offline_pages_[0].expiration_time);
- EXPECT_EQ(offline_page.access_count, this->offline_pages_[0].access_count);
- EXPECT_EQ(offline_page.client_id, this->offline_pages_[0].client_id);
+ store->AddOfflinePage(offline_page,
+ base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(ADD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+
+ ClearResults();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ ASSERT_EQ(1U, offline_pages_.size());
+ EXPECT_EQ(offline_page, offline_pages_[0]);
// Then update some data.
offline_page.file_size = kFileSize + 1;
offline_page.access_count++;
offline_page.expiration_time = base::Time::Now();
- store->AddOrUpdateOfflinePage(
- offline_page,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), ADD));
- this->PumpLoop();
- EXPECT_EQ(ADD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
-
- this->ClearResults();
- store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
- base::Unretained(this)));
- this->PumpLoop();
-
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- ASSERT_EQ(1U, this->offline_pages_.size());
- EXPECT_EQ(offline_page.url, this->offline_pages_[0].url);
- EXPECT_EQ(offline_page.offline_id, this->offline_pages_[0].offline_id);
- EXPECT_EQ(offline_page.version, this->offline_pages_[0].version);
- EXPECT_EQ(offline_page.file_path, this->offline_pages_[0].file_path);
- EXPECT_EQ(offline_page.file_size, this->offline_pages_[0].file_size);
- EXPECT_EQ(offline_page.creation_time, this->offline_pages_[0].creation_time);
- EXPECT_EQ(offline_page.last_access_time,
- this->offline_pages_[0].last_access_time);
- EXPECT_EQ(offline_page.expiration_time,
- this->offline_pages_[0].expiration_time);
- EXPECT_EQ(offline_page.access_count, this->offline_pages_[0].access_count);
- EXPECT_EQ(offline_page.client_id, this->offline_pages_[0].client_id);
+ std::vector<OfflinePageItem> items_to_update;
+ items_to_update.push_back(offline_page);
+ store->UpdateOfflinePages(
+ items_to_update, base::Bind(&OfflinePageMetadataStoreTest::UpdateCallback,
+ base::Unretained(this), UPDATE));
+ PumpLoop();
+ EXPECT_EQ(UPDATE, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ ASSERT_TRUE(last_update_result() != nullptr);
+ EXPECT_EQ(1UL, last_update_result()->item_statuses.size());
+ EXPECT_EQ(ItemActionStatus::SUCCESS,
+ last_update_result()->item_statuses.begin()->second);
+ EXPECT_EQ(1UL, last_update_result()->updated_items.size());
+ EXPECT_EQ(offline_page, *(last_update_result()->updated_items.begin()));
+
+ ClearResults();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
+
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ ASSERT_EQ(1U, offline_pages_.size());
+ EXPECT_EQ(offline_page, offline_pages_[0]);
}
-TYPED_TEST(OfflinePageMetadataStoreTest, ClearAllOfflinePages) {
- std::unique_ptr<OfflinePageMetadataStore> store(this->BuildStore());
+TEST_F(OfflinePageMetadataStoreTest, ClearAllOfflinePages) {
+ std::unique_ptr<OfflinePageMetadataStore> store(BuildStore());
// Add 2 offline pages.
OfflinePageItem offline_page(GURL(kTestURL), 1234LL, kTestClientId1,
base::FilePath(kFilePath), kFileSize);
- store->AddOrUpdateOfflinePage(
- offline_page,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), ADD));
- this->PumpLoop();
- EXPECT_EQ(ADD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
+ store->AddOfflinePage(offline_page,
+ base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(ADD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
- this->ClearResults();
+ ClearResults();
OfflinePageItem offline_page2(GURL("http://test.com"), 5678LL, kTestClientId2,
base::FilePath(kFilePath), kFileSize);
- store->AddOrUpdateOfflinePage(
- offline_page2,
- base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), ADD));
- this->PumpLoop();
- EXPECT_EQ(ADD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
+ store->AddOfflinePage(offline_page2,
+ base::Bind(&OfflinePageMetadataStoreTest::AddCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(ADD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
- this->ClearResults();
+ ClearResults();
// Load the store.
- store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
- base::Unretained(this)));
- this->PumpLoop();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- EXPECT_EQ(2U, this->offline_pages_.size());
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ EXPECT_EQ(2U, offline_pages_.size());
// Clear all records from the store.
- store->Reset(base::Bind(&OfflinePageMetadataStoreTestBase::UpdateCallback,
- base::Unretained(this), RESET));
- this->PumpLoop();
- EXPECT_EQ(RESET, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
+ store->Reset(base::Bind(&OfflinePageMetadataStoreTest::ResetCallback,
+ base::Unretained(this)));
+ PumpLoop();
+ EXPECT_EQ(RESET, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
// Load the store.
- store->Load(base::Bind(&OfflinePageMetadataStoreTestBase::LoadCallback,
- base::Unretained(this)));
- this->PumpLoop();
+ store->GetOfflinePages(
+ base::Bind(&OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+ base::Unretained(this)));
+ PumpLoop();
- EXPECT_EQ(LOAD, this->last_called_callback_);
- EXPECT_EQ(STATUS_TRUE, this->last_status_);
- ASSERT_EQ(0U, this->offline_pages_.size());
+ EXPECT_EQ(LOAD, last_called_callback_);
+ EXPECT_EQ(STATUS_TRUE, last_status_);
+ ASSERT_EQ(0U, offline_pages_.size());
}
} // namespace
diff --git a/chromium/components/offline_pages/offline_page_metadata_store_sql.cc b/chromium/components/offline_pages/offline_page_metadata_store_sql.cc
index 3d7cdcf8117..7e22cd17639 100644
--- a/chromium/components/offline_pages/offline_page_metadata_store_sql.cc
+++ b/chromium/components/offline_pages/offline_page_metadata_store_sql.cc
@@ -26,88 +26,79 @@ namespace {
// it can be used inline in other SQL statements below.
#define OFFLINE_PAGES_TABLE_NAME "offlinepages_v1"
-// New columns should be added at the end of the list in order to avoid
-// complicated table upgrade.
-const char kOfflinePagesColumns[] =
- "(offline_id INTEGER PRIMARY KEY NOT NULL,"
- " creation_time INTEGER NOT NULL,"
- " file_size INTEGER NOT NULL,"
- " version INTEGER NOT NULL,"
- " last_access_time INTEGER NOT NULL,"
- " access_count INTEGER NOT NULL,"
- " status INTEGER NOT NULL DEFAULT 0,"
- // A note on this field: It will be NULL for now and is reserved for
- // later use. We will treat NULL as "Unknown" in any subsequent queries
- // for user_initiated values.
- " user_initiated INTEGER," // this is actually a boolean
- " expiration_time INTEGER NOT NULL DEFAULT 0,"
- " client_namespace VARCHAR NOT NULL,"
- " client_id VARCHAR NOT NULL,"
- " online_url VARCHAR NOT NULL,"
- " offline_url VARCHAR NOT NULL DEFAULT '',"
- " file_path VARCHAR NOT NULL"
- ")";
-
-// This is cloned from //content/browser/appcache/appcache_database.cc
-struct TableInfo {
- const char* table_name;
- const char* columns;
-};
-
-const TableInfo kOfflinePagesTable{OFFLINE_PAGES_TABLE_NAME,
- kOfflinePagesColumns};
-
-// This enum is used to define the indices for the columns in each row
-// that hold the different pieces of offline page.
-enum : int {
- OP_OFFLINE_ID = 0,
- OP_CREATION_TIME,
- OP_FILE_SIZE,
- OP_VERSION,
- OP_LAST_ACCESS_TIME,
- OP_ACCESS_COUNT,
- OP_STATUS,
- OP_USER_INITIATED,
- OP_EXPIRATION_TIME,
- OP_CLIENT_NAMESPACE,
- OP_CLIENT_ID,
- OP_ONLINE_URL,
- OP_OFFLINE_URL,
- OP_FILE_PATH,
-};
-
-bool CreateTable(sql::Connection* db, const TableInfo& table_info) {
- std::string sql("CREATE TABLE ");
- sql += table_info.table_name;
- sql += table_info.columns;
- return db->Execute(sql.c_str());
-}
-
-bool RefreshColumns(sql::Connection* db) {
+bool CreateOfflinePagesTable(sql::Connection* db) {
+ const char kSql[] = "CREATE TABLE IF NOT EXISTS " OFFLINE_PAGES_TABLE_NAME
+ "(offline_id INTEGER PRIMARY KEY NOT NULL,"
+ " creation_time INTEGER NOT NULL,"
+ " file_size INTEGER NOT NULL,"
+ " last_access_time INTEGER NOT NULL,"
+ " access_count INTEGER NOT NULL,"
+ " expiration_time INTEGER NOT NULL DEFAULT 0,"
+ " client_namespace VARCHAR NOT NULL,"
+ " client_id VARCHAR NOT NULL,"
+ " online_url VARCHAR NOT NULL,"
+ " file_path VARCHAR NOT NULL,"
+ " title VARCHAR NOT NULL DEFAULT ''"
+ ")";
+ return db->Execute(kSql);
+}
+
+bool UpgradeWithQuery(sql::Connection* db, const char* upgrade_sql) {
if (!db->Execute("ALTER TABLE " OFFLINE_PAGES_TABLE_NAME
" RENAME TO temp_" OFFLINE_PAGES_TABLE_NAME)) {
return false;
}
- if (!CreateTable(db, kOfflinePagesTable))
+ if (!CreateOfflinePagesTable(db))
return false;
- if (!db->Execute(
- "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
- " (offline_id, creation_time, file_size, version, last_access_time, "
- "access_count, status, user_initiated, client_namespace, client_id, "
- "online_url, offline_url, file_path) "
- "SELECT offline_id, creation_time, file_size, version, "
- "last_access_time, "
- "access_count, status, user_initiated, client_namespace, client_id, "
- "online_url, offline_url, file_path "
- "FROM temp_" OFFLINE_PAGES_TABLE_NAME)) {
+ if (!db->Execute(upgrade_sql))
return false;
- }
if (!db->Execute("DROP TABLE IF EXISTS temp_" OFFLINE_PAGES_TABLE_NAME))
return false;
-
return true;
}
+bool UpgradeFrom52(sql::Connection* db) {
+ const char kSql[] =
+ "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
+ " (offline_id, creation_time, file_size, last_access_time, "
+ "access_count, client_namespace, client_id, "
+ "online_url, file_path) "
+ "SELECT "
+ "offline_id, creation_time, file_size, last_access_time, "
+ "access_count, client_namespace, client_id, "
+ "online_url, file_path "
+ "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
+ return UpgradeWithQuery(db, kSql);
+}
+
+bool UpgradeFrom53(sql::Connection* db) {
+ const char kSql[] =
+ "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
+ " (offline_id, creation_time, file_size, last_access_time, "
+ "access_count, expiration_time, client_namespace, client_id, "
+ "online_url, file_path) "
+ "SELECT "
+ "offline_id, creation_time, file_size, last_access_time, "
+ "access_count, expiration_time, client_namespace, client_id, "
+ "online_url, file_path "
+ "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
+ return UpgradeWithQuery(db, kSql);
+}
+
+bool UpgradeFrom54(sql::Connection* db) {
+ const char kSql[] =
+ "INSERT INTO " OFFLINE_PAGES_TABLE_NAME
+ " (offline_id, creation_time, file_size, last_access_time, "
+ "access_count, expiration_time, client_namespace, client_id, "
+ "online_url, file_path, title) "
+ "SELECT "
+ "offline_id, creation_time, file_size, last_access_time, "
+ "access_count, expiration_time, client_namespace, client_id, "
+ "online_url, file_path, title "
+ "FROM temp_" OFFLINE_PAGES_TABLE_NAME;
+ return UpgradeWithQuery(db, kSql);
+}
+
bool CreateSchema(sql::Connection* db) {
// If you create a transaction but don't Commit() it is automatically
// rolled back by its destructor when it falls out of scope.
@@ -115,13 +106,20 @@ bool CreateSchema(sql::Connection* db) {
if (!transaction.Begin())
return false;
- if (!db->DoesTableExist(kOfflinePagesTable.table_name)) {
- if (!CreateTable(db, kOfflinePagesTable))
+ if (!db->DoesTableExist(OFFLINE_PAGES_TABLE_NAME)) {
+ if (!CreateOfflinePagesTable(db))
return false;
}
- if (!db->DoesColumnExist(kOfflinePagesTable.table_name, "expiration_time")) {
- if (!RefreshColumns(db))
+ // Upgrade section. Details are described in the header file.
+ if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "expiration_time")) {
+ if (!UpgradeFrom52(db))
+ return false;
+ } else if (!db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "title")) {
+ if (!UpgradeFrom53(db))
+ return false;
+ } else if (db->DoesColumnExist(OFFLINE_PAGES_TABLE_NAME, "offline_url")) {
+ if (!UpgradeFrom54(db))
return false;
}
@@ -137,40 +135,59 @@ bool DeleteByOfflineId(sql::Connection* db, int64_t offline_id) {
return statement.Run();
}
-// Create an offline page item from a SQL result. Expects complete rows with
-// all columns present.
-OfflinePageItem MakeOfflinePageItem(sql::Statement* statement) {
- int64_t id = statement->ColumnInt64(OP_OFFLINE_ID);
- GURL url(statement->ColumnString(OP_ONLINE_URL));
- ClientId client_id(statement->ColumnString(OP_CLIENT_NAMESPACE),
- statement->ColumnString(OP_CLIENT_ID));
+base::FilePath GetPathFromUTF8String(const std::string& path_string) {
#if defined(OS_POSIX)
- base::FilePath path(statement->ColumnString(OP_FILE_PATH));
+ return base::FilePath(path_string);
#elif defined(OS_WIN)
- base::FilePath path(base::UTF8ToWide(statement->ColumnString(OP_FILE_PATH)));
+ return base::FilePath(base::UTF8ToWide(path_string));
#else
#error Unknown OS
#endif
- int64_t file_size = statement->ColumnInt64(OP_FILE_SIZE);
+}
+
+std::string GetUTF8StringFromPath(const base::FilePath& path) {
+#if defined(OS_POSIX)
+ return path.value();
+#elif defined(OS_WIN)
+ return base::WideToUTF8(path.value());
+#else
+#error Unknown OS
+#endif
+}
+
+// Create an offline page item from a SQL result. Expects complete rows with
+// all columns present.
+OfflinePageItem MakeOfflinePageItem(sql::Statement* statement) {
+ int64_t id = statement->ColumnInt64(0);
base::Time creation_time =
- base::Time::FromInternalValue(statement->ColumnInt64(OP_CREATION_TIME));
+ base::Time::FromInternalValue(statement->ColumnInt64(1));
+ int64_t file_size = statement->ColumnInt64(2);
+ base::Time last_access_time =
+ base::Time::FromInternalValue(statement->ColumnInt64(3));
+ int access_count = statement->ColumnInt(4);
+ base::Time expiration_time =
+ base::Time::FromInternalValue(statement->ColumnInt64(5));
+ ClientId client_id(statement->ColumnString(6), statement->ColumnString(7));
+ GURL url(statement->ColumnString(8));
+ base::FilePath path(GetPathFromUTF8String(statement->ColumnString(9)));
+ base::string16 title = statement->ColumnString16(10);
OfflinePageItem item(url, id, client_id, path, file_size, creation_time);
- item.last_access_time = base::Time::FromInternalValue(
- statement->ColumnInt64(OP_LAST_ACCESS_TIME));
- item.version = statement->ColumnInt(OP_VERSION);
- item.access_count = statement->ColumnInt(OP_ACCESS_COUNT);
- item.expiration_time =
- base::Time::FromInternalValue(statement->ColumnInt64(OP_EXPIRATION_TIME));
+ item.last_access_time = last_access_time;
+ item.access_count = access_count;
+ item.expiration_time = expiration_time;
+ item.title = title;
return item;
}
-bool InsertOrReplace(sql::Connection* db, const OfflinePageItem& item) {
+ItemActionStatus Insert(sql::Connection* db, const OfflinePageItem& item) {
+ // Using 'INSERT OR FAIL' or 'INSERT OR ABORT' in the query below causes debug
+ // builds to DLOG.
const char kSql[] =
- "INSERT OR REPLACE INTO " OFFLINE_PAGES_TABLE_NAME
+ "INSERT OR IGNORE INTO " OFFLINE_PAGES_TABLE_NAME
" (offline_id, online_url, client_namespace, client_id, file_path, "
- "file_size, creation_time, last_access_time, version, access_count, "
- "expiration_time)"
+ "file_size, creation_time, last_access_time, access_count, "
+ "expiration_time, title)"
" VALUES "
" (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
@@ -179,21 +196,41 @@ bool InsertOrReplace(sql::Connection* db, const OfflinePageItem& item) {
statement.BindString(1, item.url.spec());
statement.BindString(2, item.client_id.name_space);
statement.BindString(3, item.client_id.id);
-#if defined(OS_POSIX)
- std::string path_string = item.file_path.value();
-#elif defined(OS_WIN)
- std::string path_string = base::WideToUTF8(item.file_path.value());
-#else
-#error Unknown OS
-#endif
- statement.BindString(4, path_string);
+ statement.BindString(4, GetUTF8StringFromPath(item.file_path));
statement.BindInt64(5, item.file_size);
statement.BindInt64(6, item.creation_time.ToInternalValue());
statement.BindInt64(7, item.last_access_time.ToInternalValue());
- statement.BindInt(8, item.version);
- statement.BindInt(9, item.access_count);
- statement.BindInt64(10, item.expiration_time.ToInternalValue());
- return statement.Run();
+ statement.BindInt(8, item.access_count);
+ statement.BindInt64(9, item.expiration_time.ToInternalValue());
+ statement.BindString16(10, item.title);
+ if (!statement.Run())
+ return ItemActionStatus::STORE_ERROR;
+ if (db->GetLastChangeCount() == 0)
+ return ItemActionStatus::ALREADY_EXISTS;
+ return ItemActionStatus::SUCCESS;
+}
+
+bool Update(sql::Connection* db, const OfflinePageItem& item) {
+ const char kSql[] =
+ "UPDATE OR IGNORE " OFFLINE_PAGES_TABLE_NAME
+ " SET online_url = ?, client_namespace = ?, client_id = ?, file_path = ?,"
+ " file_size = ?, creation_time = ?, last_access_time = ?,"
+ " access_count = ?, expiration_time = ?, title = ?"
+ " WHERE offline_id = ?";
+
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindString(0, item.url.spec());
+ statement.BindString(1, item.client_id.name_space);
+ statement.BindString(2, item.client_id.id);
+ statement.BindString(3, GetUTF8StringFromPath(item.file_path));
+ statement.BindInt64(4, item.file_size);
+ statement.BindInt64(5, item.creation_time.ToInternalValue());
+ statement.BindInt64(6, item.last_access_time.ToInternalValue());
+ statement.BindInt(7, item.access_count);
+ statement.BindInt64(8, item.expiration_time.ToInternalValue());
+ statement.BindString16(9, item.title);
+ statement.BindInt64(10, item.offline_id);
+ return statement.Run() && db->GetLastChangeCount() > 0;
}
bool InitDatabase(sql::Connection* db, base::FilePath path) {
@@ -217,127 +254,254 @@ bool InitDatabase(sql::Connection* db, base::FilePath path) {
return CreateSchema(db);
}
-} // anonymous namespace
+void NotifyLoadResult(scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const OfflinePageMetadataStore::LoadCallback& callback,
+ OfflinePageMetadataStore::LoadStatus status,
+ const std::vector<OfflinePageItem>& result) {
+ // TODO(bburns): Switch to SQL specific UMA metrics.
+ UMA_HISTOGRAM_ENUMERATION("OfflinePages.LoadStatus", status,
+ OfflinePageMetadataStore::LOAD_STATUS_COUNT);
+ if (status == OfflinePageMetadataStore::LOAD_SUCCEEDED) {
+ UMA_HISTOGRAM_COUNTS("OfflinePages.SavedPageCount",
+ static_cast<int32_t>(result.size()));
+ } else {
+ DVLOG(1) << "Offline pages database loading failed: " << status;
+ }
+ runner->PostTask(FROM_HERE, base::Bind(callback, status, result));
+}
-OfflinePageMetadataStoreSQL::OfflinePageMetadataStoreSQL(
- scoped_refptr<base::SequencedTaskRunner> background_task_runner,
- const base::FilePath& path)
- : background_task_runner_(std::move(background_task_runner)),
- db_file_path_(path.AppendASCII("OfflinePages.db")) {}
+void OpenConnectionSync(sql::Connection* db,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const base::FilePath& path,
+ const base::Callback<void(StoreState)>& callback) {
+ StoreState state =
+ InitDatabase(db, path) ? StoreState::LOADED : StoreState::FAILED_LOADING;
+ runner->PostTask(FROM_HERE, base::Bind(callback, state));
+}
-OfflinePageMetadataStoreSQL::~OfflinePageMetadataStoreSQL() {
- if (db_.get() &&
- !background_task_runner_->DeleteSoon(FROM_HERE, db_.release())) {
- DLOG(WARNING) << "SQL database will not be deleted.";
+bool GetPageByOfflineIdSync(sql::Connection* db,
+ int64_t offline_id,
+ OfflinePageItem* item) {
+ const char kSql[] =
+ "SELECT * FROM " OFFLINE_PAGES_TABLE_NAME " WHERE offline_id = ?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, offline_id);
+
+ if (statement.Step()) {
+ *item = MakeOfflinePageItem(&statement);
+ return true;
}
+
+ return false;
}
-void OfflinePageMetadataStoreSQL::LoadSync(
+void GetOfflinePagesSync(
sql::Connection* db,
- const base::FilePath& path,
scoped_refptr<base::SingleThreadTaskRunner> runner,
- const LoadCallback& callback) {
- if (!InitDatabase(db, path)) {
- NotifyLoadResult(runner, callback, STORE_INIT_FAILED,
- std::vector<OfflinePageItem>());
- return;
- }
-
+ const OfflinePageMetadataStore::LoadCallback& callback) {
const char kSql[] = "SELECT * FROM " OFFLINE_PAGES_TABLE_NAME;
sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
std::vector<OfflinePageItem> result;
- while (statement.Step()) {
+ while (statement.Step())
result.push_back(MakeOfflinePageItem(&statement));
- }
if (statement.Succeeded()) {
- NotifyLoadResult(runner, callback, LOAD_SUCCEEDED, result);
+ NotifyLoadResult(runner, callback, OfflinePageMetadataStore::LOAD_SUCCEEDED,
+ result);
} else {
- NotifyLoadResult(runner, callback, STORE_LOAD_FAILED,
- std::vector<OfflinePageItem>());
+ result.clear();
+ NotifyLoadResult(runner, callback,
+ OfflinePageMetadataStore::STORE_LOAD_FAILED, result);
}
}
-void OfflinePageMetadataStoreSQL::AddOrUpdateOfflinePageSync(
- const OfflinePageItem& offline_page,
+void AddOfflinePageSync(sql::Connection* db,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const OfflinePageItem& offline_page,
+ const OfflinePageMetadataStore::AddCallback& callback) {
+ ItemActionStatus status = Insert(db, offline_page);
+ runner->PostTask(FROM_HERE, base::Bind(callback, status));
+}
+
+void PostStoreUpdateResultForIds(
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ StoreState store_state,
+ const std::vector<int64_t>& offline_ids,
+ ItemActionStatus action_status,
+ const OfflinePageMetadataStore::UpdateCallback& callback) {
+ std::unique_ptr<OfflinePagesUpdateResult> result(
+ new OfflinePagesUpdateResult(store_state));
+ for (const auto& offline_id : offline_ids)
+ result->item_statuses.push_back(std::make_pair(offline_id, action_status));
+ runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
+}
+
+void PostStoreErrorForAllPages(
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const std::vector<OfflinePageItem>& pages,
+ const OfflinePageMetadataStore::UpdateCallback& callback) {
+ std::vector<int64_t> offline_ids;
+ for (const auto& page : pages)
+ offline_ids.push_back(page.offline_id);
+ PostStoreUpdateResultForIds(runner, StoreState::LOADED, offline_ids,
+ ItemActionStatus::STORE_ERROR, callback);
+}
+
+void PostStoreErrorForAllIds(
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const std::vector<int64_t>& offline_ids,
+ const OfflinePageMetadataStore::UpdateCallback& callback) {
+ PostStoreUpdateResultForIds(runner, StoreState::LOADED, offline_ids,
+ ItemActionStatus::STORE_ERROR, callback);
+}
+
+void UpdateOfflinePagesSync(
sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
- const UpdateCallback& callback) {
- // TODO(bburns): add UMA metrics here (and for levelDB).
- bool ok = InsertOrReplace(db, offline_page);
- runner->PostTask(FROM_HERE, base::Bind(callback, ok));
+ const std::vector<OfflinePageItem>& pages,
+ const OfflinePageMetadataStore::UpdateCallback& callback) {
+ std::unique_ptr<OfflinePagesUpdateResult> result(
+ new OfflinePagesUpdateResult(StoreState::LOADED));
+
+ sql::Transaction transaction(db);
+ if (!transaction.Begin()) {
+ PostStoreErrorForAllPages(runner, pages, callback);
+ return;
+ }
+
+ for (const auto& page : pages) {
+ if (Update(db, page)) {
+ result->updated_items.push_back(page);
+ result->item_statuses.push_back(
+ std::make_pair(page.offline_id, ItemActionStatus::SUCCESS));
+ } else {
+ result->item_statuses.push_back(
+ std::make_pair(page.offline_id, ItemActionStatus::NOT_FOUND));
+ }
+ }
+
+ if (!transaction.Commit()) {
+ PostStoreErrorForAllPages(runner, pages, callback);
+ return;
+ }
+ runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
}
-void OfflinePageMetadataStoreSQL::RemoveOfflinePagesSync(
+void RemoveOfflinePagesSync(
const std::vector<int64_t>& offline_ids,
sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
- const UpdateCallback& callback) {
- // TODO(bburns): add UMA metrics here (and for levelDB).
+ const OfflinePageMetadataStore::UpdateCallback& callback) {
+ // TODO(fgorski): Perhaps add metrics here.
+ std::unique_ptr<OfflinePagesUpdateResult> result(
+ new OfflinePagesUpdateResult(StoreState::LOADED));
// If you create a transaction but don't Commit() it is automatically
// rolled back by its destructor when it falls out of scope.
sql::Transaction transaction(db);
if (!transaction.Begin()) {
- runner->PostTask(FROM_HERE, base::Bind(callback, false));
+ PostStoreErrorForAllIds(runner, offline_ids, callback);
return;
}
- for (auto offline_id : offline_ids) {
- if (!DeleteByOfflineId(db, offline_id)) {
- runner->PostTask(FROM_HERE, base::Bind(callback, false));
- return;
+
+ for (int64_t offline_id : offline_ids) {
+ OfflinePageItem page;
+ ItemActionStatus status;
+ if (!GetPageByOfflineIdSync(db, offline_id, &page)) {
+ status = ItemActionStatus::NOT_FOUND;
+ } else if (!DeleteByOfflineId(db, offline_id)) {
+ status = ItemActionStatus::STORE_ERROR;
+ } else {
+ status = ItemActionStatus::SUCCESS;
+ result->updated_items.push_back(page);
}
+
+ result->item_statuses.push_back(std::make_pair(offline_id, status));
}
- bool success = transaction.Commit();
- runner->PostTask(FROM_HERE, base::Bind(callback, success));
-}
+ if (!transaction.Commit()) {
+ PostStoreErrorForAllIds(runner, offline_ids, callback);
+ return;
+ }
-void OfflinePageMetadataStoreSQL::ResetSync(
- std::unique_ptr<sql::Connection> db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const ResetCallback& callback) {
- const char kSql[] = "DELETE FROM " OFFLINE_PAGES_TABLE_NAME;
- sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
- runner->PostTask(FROM_HERE, base::Bind(callback, statement.Run()));
+ runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
}
-void OfflinePageMetadataStoreSQL::NotifyLoadResult(
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const LoadCallback& callback,
- LoadStatus status,
- const std::vector<OfflinePageItem>& result) {
- // TODO(bburns): Switch to SQL specific UMA metrics.
- UMA_HISTOGRAM_ENUMERATION("OfflinePages.LoadStatus", status,
- OfflinePageMetadataStore::LOAD_STATUS_COUNT);
- if (status == LOAD_SUCCEEDED) {
- UMA_HISTOGRAM_COUNTS("OfflinePages.SavedPageCount",
- static_cast<int32_t>(result.size()));
+void ResetSync(sql::Connection* db,
+ const base::FilePath& db_file_path,
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const base::Callback<void(StoreState)>& callback) {
+ // This method deletes the content of the whole store and reinitializes it.
+ bool success = db->Raze();
+ db->Close();
+ StoreState state;
+ if (success) {
+ state = InitDatabase(db, db_file_path) ? StoreState::LOADED
+ : StoreState::FAILED_LOADING;
} else {
- DVLOG(1) << "Offline pages database loading failed: " << status;
+ state = StoreState::FAILED_RESET;
}
- runner->PostTask(FROM_HERE, base::Bind(callback, status, result));
+ runner->PostTask(FROM_HERE, base::Bind(callback, state));
}
-void OfflinePageMetadataStoreSQL::Load(const LoadCallback& callback) {
- db_.reset(new sql::Connection());
+} // anonymous namespace
+
+OfflinePageMetadataStoreSQL::OfflinePageMetadataStoreSQL(
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner,
+ const base::FilePath& path)
+ : background_task_runner_(std::move(background_task_runner)),
+ db_file_path_(path.AppendASCII("OfflinePages.db")),
+ state_(StoreState::NOT_LOADED),
+ weak_ptr_factory_(this) {
+ OpenConnection();
+}
+
+OfflinePageMetadataStoreSQL::~OfflinePageMetadataStoreSQL() {
+ if (db_.get() &&
+ !background_task_runner_->DeleteSoon(FROM_HERE, db_.release())) {
+ DLOG(WARNING) << "SQL database will not be deleted.";
+ }
+}
+
+void OfflinePageMetadataStoreSQL::GetOfflinePages(
+ const LoadCallback& callback) {
+ if (!CheckDb(base::Bind(
+ callback, STORE_INIT_FAILED, std::vector<OfflinePageItem>()))) {
+ return;
+ }
+
background_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&OfflinePageMetadataStoreSQL::LoadSync, db_.get(),
- db_file_path_, base::ThreadTaskRunnerHandle::Get(), callback));
+ FROM_HERE, base::Bind(&GetOfflinePagesSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(), callback));
}
-void OfflinePageMetadataStoreSQL::AddOrUpdateOfflinePage(
+void OfflinePageMetadataStoreSQL::AddOfflinePage(
const OfflinePageItem& offline_page,
+ const AddCallback& callback) {
+ if (!CheckDb(base::Bind(callback, ItemActionStatus::STORE_ERROR)))
+ return;
+
+ background_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AddOfflinePageSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(), offline_page, callback));
+}
+
+void OfflinePageMetadataStoreSQL::UpdateOfflinePages(
+ const std::vector<OfflinePageItem>& pages,
const UpdateCallback& callback) {
- DCHECK(db_.get());
+ if (!db_.get()) {
+ PostStoreErrorForAllPages(base::ThreadTaskRunnerHandle::Get(), pages,
+ callback);
+ return;
+ }
+
background_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&OfflinePageMetadataStoreSQL::AddOrUpdateOfflinePageSync,
- offline_page, db_.get(), base::ThreadTaskRunnerHandle::Get(),
- callback));
+ base::Bind(&UpdateOfflinePagesSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(), pages, callback));
}
void OfflinePageMetadataStoreSQL::RemoveOfflinePages(
@@ -348,23 +512,76 @@ void OfflinePageMetadataStoreSQL::RemoveOfflinePages(
if (offline_ids.empty()) {
// Nothing to do, but post a callback instead of calling directly
// to preserve the async style behavior to prevent bugs.
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- base::Bind(callback, true));
+ PostStoreUpdateResultForIds(
+ base::ThreadTaskRunnerHandle::Get(), state(), offline_ids,
+ ItemActionStatus::NOT_FOUND /* will be ignored */, callback);
return;
}
background_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&OfflinePageMetadataStoreSQL::RemoveOfflinePagesSync,
- offline_ids, db_.get(), base::ThreadTaskRunnerHandle::Get(),
- callback));
+ FROM_HERE, base::Bind(&RemoveOfflinePagesSync, offline_ids, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(), callback));
}
void OfflinePageMetadataStoreSQL::Reset(const ResetCallback& callback) {
+ if (!CheckDb(base::Bind(callback, false)))
+ return;
+
+ background_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ResetSync, db_.get(), db_file_path_,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&OfflinePageMetadataStoreSQL::OnResetDone,
+ weak_ptr_factory_.GetWeakPtr(), callback)));
+}
+
+StoreState OfflinePageMetadataStoreSQL::state() const {
+ return state_;
+}
+
+void OfflinePageMetadataStoreSQL::SetStateForTesting(StoreState state,
+ bool reset_db) {
+ state_ = state;
+ if (reset_db)
+ db_.reset(nullptr);
+}
+
+void OfflinePageMetadataStoreSQL::OpenConnection() {
+ DCHECK(!db_);
+ db_.reset(new sql::Connection());
background_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&OfflinePageMetadataStoreSQL::ResetSync, base::Passed(&db_),
- base::ThreadTaskRunnerHandle::Get(), callback));
+ base::Bind(&OpenConnectionSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(), db_file_path_,
+ base::Bind(&OfflinePageMetadataStoreSQL::OnOpenConnectionDone,
+ weak_ptr_factory_.GetWeakPtr())));
+}
+
+void OfflinePageMetadataStoreSQL::OnOpenConnectionDone(StoreState state) {
+ DCHECK(db_.get());
+
+ state_ = state;
+
+ // Unfortunately we were not able to open DB connection.
+ if (state != StoreState::LOADED)
+ db_.reset();
+
+ // TODO(fgorski): This might be a place to start store recovery. Alternatively
+ // that can be attempted in the OfflinePageModel.
+}
+
+void OfflinePageMetadataStoreSQL::OnResetDone(const ResetCallback& callback,
+ StoreState state) {
+ OnOpenConnectionDone(state);
+ callback.Run(state == StoreState::LOADED);
+}
+
+bool OfflinePageMetadataStoreSQL::CheckDb(const base::Closure& callback) {
+ if (!db_.get() || state_ != StoreState::LOADED) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
+ return false;
+ }
+ return true;
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/offline_page_metadata_store_sql.h b/chromium/components/offline_pages/offline_page_metadata_store_sql.h
index 8a480293f90..c26cae8fb3e 100644
--- a/chromium/components/offline_pages/offline_page_metadata_store_sql.h
+++ b/chromium/components/offline_pages/offline_page_metadata_store_sql.h
@@ -26,6 +26,30 @@ namespace offline_pages {
// OfflinePageMetadataStoreSQL is an instance of OfflinePageMetadataStore
// which is implemented using a SQLite database.
+//
+// This store has a history of schema updates in pretty much every release.
+// Original schema was delivered in M52. Since then, the following changes
+// happened:
+// * In M53 expiration_time was added,
+// * In M54 title was added,
+// * In M55 we dropped the following fields (never used): version, status,
+// offline_url, user_initiated.
+//
+// Here is a procedure to update the schema for this store:
+// * Decide how to detect that the store is on a particular version, which
+// typically means that a certain field exists or is missing. This happens in
+// Upgrade section of |CreateSchema|
+// * Work out appropriate change and apply it to all existing upgrade paths. In
+// the interest of performing a single update of the store, it upgrades from a
+// detected version to the current one. This means that when making a change,
+// more than a single query may have to be updated (in case of fields being
+// removed or needed to be initialized to a specific, non-default value).
+// Such approach is preferred to doing N updates for every changed version on
+// a startup after browser update.
+// * New upgrade method should specify which version it is upgrading from, e.g.
+// |UpgradeFrom54|.
+// * Upgrade should use |UpgradeWithQuery| and simply specify SQL command to
+// move data from old table (prefixed by temp_) to the new one.
class OfflinePageMetadataStoreSQL : public OfflinePageMetadataStore {
public:
OfflinePageMetadataStoreSQL(
@@ -34,49 +58,46 @@ class OfflinePageMetadataStoreSQL : public OfflinePageMetadataStore {
~OfflinePageMetadataStoreSQL() override;
// Implementation methods.
- void Load(const LoadCallback& callback) override;
- void AddOrUpdateOfflinePage(const OfflinePageItem& offline_page,
- const UpdateCallback& callback) override;
+ void GetOfflinePages(const LoadCallback& callback) override;
+ void AddOfflinePage(const OfflinePageItem& offline_page,
+ const AddCallback& callback) override;
+ void UpdateOfflinePages(const std::vector<OfflinePageItem>& pages,
+ const UpdateCallback& callback) override;
void RemoveOfflinePages(const std::vector<int64_t>& offline_ids,
const UpdateCallback& callback) override;
void Reset(const ResetCallback& callback) override;
+ StoreState state() const override;
+
+ // Helper function used to force incorrect state for testing purposes.
+ void SetStateForTesting(StoreState state, bool reset_db);
private:
- // Synchronous implementations, these are run on the background thread
- // and actually do the work to access SQL. The implementations above
- // simply dispatch to the corresponding *Sync method on the background thread.
- // 'runner' is where to run the callback.
- static void LoadSync(sql::Connection* db,
- const base::FilePath& path,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const LoadCallback& callback);
- static void AddOrUpdateOfflinePageSync(
- const OfflinePageItem& offline_page,
- sql::Connection* db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const UpdateCallback& callback);
- static void RemoveOfflinePagesSync(
- const std::vector<int64_t>& offline_ids,
- sql::Connection* db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const UpdateCallback& callback);
- static void ResetSync(std::unique_ptr<sql::Connection> db,
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const ResetCallback& callback);
-
- static void NotifyLoadResult(
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const LoadCallback& callback,
- LoadStatus status,
- const std::vector<OfflinePageItem>& result);
+ // Used to initialize DB connection.
+ void OpenConnection();
+ void OnOpenConnectionDone(StoreState state);
+
+ // Used to reset DB connection.
+ void OnResetDone(const ResetCallback& callback, StoreState state);
+
+ // Helper function that checks whether a valid DB connection is present.
+ // Returns true if valid connection is present, otherwise it returns false and
+ // calls the provided callback as a shortcut.
+ bool CheckDb(const base::Closure& callback);
// Background thread where all SQL access should be run.
scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
// Path to the database on disk.
base::FilePath db_file_path_;
+
+ // Database connection.
std::unique_ptr<sql::Connection> db_;
+ // State of the store.
+ StoreState state_;
+
+ base::WeakPtrFactory<OfflinePageMetadataStoreSQL> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(OfflinePageMetadataStoreSQL);
};
diff --git a/chromium/components/offline_pages/offline_page_model.h b/chromium/components/offline_pages/offline_page_model.h
index c7ea6b0220c..cf6ef741774 100644
--- a/chromium/components/offline_pages/offline_page_model.h
+++ b/chromium/components/offline_pages/offline_page_model.h
@@ -81,10 +81,16 @@ class OfflinePageModel : public base::SupportsUserData {
virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
+ static const int64_t kInvalidOfflineId = 0;
+
// Attempts to save a page addressed by |url| offline. Requires that the model
- // is loaded. Generates a new offline id and returns it.
+ // is loaded. Generates a new offline id and returns
+ // it. |proposed_offline_id| is used for the offline_id for the saved file if
+ // it is non-zero. If it is kInvalidOfflineId, a new, random ID will be
+ // generated.
virtual void SavePage(const GURL& url,
const ClientId& client_id,
+ int64_t proposed_offline_id,
std::unique_ptr<OfflinePageArchiver> archiver,
const SavePageCallback& callback) = 0;
@@ -93,23 +99,15 @@ class OfflinePageModel : public base::SupportsUserData {
// will be updated. Requires that the model is loaded.
virtual void MarkPageAccessed(int64_t offline_id) = 0;
- // Wipes out all the data by deleting all saved files and clearing the store.
- virtual void ClearAll(const base::Closure& callback) = 0;
-
// Deletes pages based on |offline_ids|.
virtual void DeletePagesByOfflineId(const std::vector<int64_t>& offline_ids,
const DeletePageCallback& callback) = 0;
- // Deletes offline pages matching the URL predicate.
- virtual void DeletePagesByURLPredicate(
+ // Deletes cached offline pages matching the URL predicate.
+ virtual void DeleteCachedPagesByURLPredicate(
const UrlPredicate& predicate,
const DeletePageCallback& callback) = 0;
- // Returns true via callback if there are offline pages in the given
- // |name_space|.
- virtual void HasPages(const std::string& name_space,
- const HasPagesCallback& callback) = 0;
-
// Returns via callback all GURLs in |urls| that are equal to the online URL
// of any offline page.
virtual void CheckPagesExistOffline(
@@ -119,6 +117,10 @@ class OfflinePageModel : public base::SupportsUserData {
// Gets all offline pages.
virtual void GetAllPages(const MultipleOfflinePageItemCallback& callback) = 0;
+ // Gets all offline pages including expired ones.
+ virtual void GetAllPagesWithExpired(
+ const MultipleOfflinePageItemCallback& callback) = 0;
+
// Gets all offline ids where the offline page has the matching client id.
virtual void GetOfflineIdsForClientId(
const ClientId& client_id,
@@ -142,47 +144,16 @@ class OfflinePageModel : public base::SupportsUserData {
virtual const OfflinePageItem* MaybeGetPageByOfflineId(
int64_t offline_id) const = 0;
- // Returns the offline page that is stored under |offline_url|, if any.
- virtual void GetPageByOfflineURL(
- const GURL& offline_url,
- const SingleOfflinePageItemCallback& callback) = 0;
-
- // Returns an offline page that is stored as |offline_url|. A nullptr is
- // returned if not found.
- //
- // This function is deprecated, and may return |nullptr| even if a page
- // exists, depending on the implementation details of OfflinePageModel.
- // Use |GetPageByOfflineURL| instead.
- virtual const OfflinePageItem* MaybeGetPageByOfflineURL(
- const GURL& offline_url) const = 0;
-
// Returns the offline pages that are stored under |online_url|.
virtual void GetPagesByOnlineURL(
const GURL& online_url,
const MultipleOfflinePageItemCallback& callback) = 0;
- // Returns via callback an offline page saved for |online_url|, if any. The
- // best page is chosen based on creation date; a more recently created offline
- // page will be preferred over an older one. This API function does not
- // respect namespaces, as it is used to choose which page is rendered in a
- // tab. Today all namespaces are treated equally for the purposes of this
- // selection.
- virtual void GetBestPageForOnlineURL(
- const GURL& online_url,
- const SingleOfflinePageItemCallback callback) = 0;
-
// Returns an offline page saved for |online_url|. A nullptr is returned if
// not found. See |GetBestPageForOnlineURL| for selection criteria.
virtual const OfflinePageItem* MaybeGetBestPageForOnlineURL(
const GURL& online_url) const = 0;
- // Checks that all of the offline pages have corresponding offline copies,
- // and all archived files have offline pages pointing to them.
- // If a page is discovered to be missing an offline copy, its offline page
- // metadata will be expired. If an archive file is discovered missing its
- // offline page, it will be deleted.
- virtual void CheckMetadataConsistency() = 0;
-
// Marks pages with |offline_ids| as expired and deletes the associated
// archive files.
virtual void ExpirePages(const std::vector<int64_t>& offline_ids,
diff --git a/chromium/components/offline_pages/offline_page_model_event_logger.cc b/chromium/components/offline_pages/offline_page_model_event_logger.cc
index 2f3181d45b2..0ca9d95d110 100644
--- a/chromium/components/offline_pages/offline_page_model_event_logger.cc
+++ b/chromium/components/offline_pages/offline_page_model_event_logger.cc
@@ -16,6 +16,10 @@ void OfflinePageModelEventLogger::RecordPageDeleted(const std::string& id) {
RecordActivity("Page with ID " + id + " has been deleted");
}
+void OfflinePageModelEventLogger::RecordPageExpired(const std::string& id) {
+ RecordActivity("Page with ID " + id + " has been expired");
+}
+
void OfflinePageModelEventLogger::RecordStoreClearError() {
RecordActivity("Offline store clear failed");
}
diff --git a/chromium/components/offline_pages/offline_page_model_event_logger.h b/chromium/components/offline_pages/offline_page_model_event_logger.h
index 9f118c02c82..f472ca0b355 100644
--- a/chromium/components/offline_pages/offline_page_model_event_logger.h
+++ b/chromium/components/offline_pages/offline_page_model_event_logger.h
@@ -20,6 +20,9 @@ class OfflinePageModelEventLogger : public OfflineEventLogger {
// Records that a page with |offline_id| has been deleted.
void RecordPageDeleted(const std::string& offline_id);
+ // Records that a page with |offline_id| has been expired.
+ void RecordPageExpired(const std::string& offline_id);
+
// Records that the offline store has been cleared.
void RecordStoreCleared();
diff --git a/chromium/components/offline_pages/offline_page_model_event_logger_unittest.cc b/chromium/components/offline_pages/offline_page_model_event_logger_unittest.cc
index c5510d42e21..1cc6fa26862 100644
--- a/chromium/components/offline_pages/offline_page_model_event_logger_unittest.cc
+++ b/chromium/components/offline_pages/offline_page_model_event_logger_unittest.cc
@@ -17,6 +17,7 @@ const int kTimeLength = 21;
const char kPageSaved[] =
"http://www.wikipedia.org is saved at last_n with id foobar";
const char kPageDeleted[] = "Page with ID foobar has been deleted";
+const char kPageExpired[] = "Page with ID foobar has been expired";
const char kRecordStoreClearError[] = "Offline store clear failed";
const char kRecordStoreCleared[] = "Offline store cleared";
const char kRecordStoreReloadError[] =
@@ -32,14 +33,16 @@ TEST(OfflinePageModelEventLoggerTest, RecordsWhenLoggingIsOn) {
logger.RecordStoreCleared();
logger.RecordPageSaved(kNamespace, kUrl, kOfflineId);
logger.RecordPageDeleted(kOfflineId);
+ logger.RecordPageExpired(kOfflineId);
logger.RecordStoreClearError();
logger.RecordStoreReloadError();
logger.GetLogs(&log);
- EXPECT_EQ(5u, log.size());
- EXPECT_EQ(std::string(kRecordStoreCleared), log[4].substr(kTimeLength));
- EXPECT_EQ(std::string(kPageSaved), log[3].substr(kTimeLength));
- EXPECT_EQ(std::string(kPageDeleted), log[2].substr(kTimeLength));
+ EXPECT_EQ(6u, log.size());
+ EXPECT_EQ(std::string(kRecordStoreCleared), log[5].substr(kTimeLength));
+ EXPECT_EQ(std::string(kPageSaved), log[4].substr(kTimeLength));
+ EXPECT_EQ(std::string(kPageDeleted), log[3].substr(kTimeLength));
+ EXPECT_EQ(std::string(kPageExpired), log[2].substr(kTimeLength));
EXPECT_EQ(std::string(kRecordStoreClearError), log[1].substr(kTimeLength));
EXPECT_EQ(std::string(kRecordStoreReloadError), log[0].substr(kTimeLength));
}
@@ -52,6 +55,7 @@ TEST(OfflinePageModelEventLoggerTest, DoesNotRecordWhenLoggingIsOff) {
logger.RecordStoreCleared();
logger.RecordPageSaved(kNamespace, kUrl, kOfflineId);
logger.RecordPageDeleted(kOfflineId);
+ logger.RecordPageExpired(kOfflineId);
logger.RecordStoreClearError();
logger.RecordStoreReloadError();
logger.GetLogs(&log);
diff --git a/chromium/components/offline_pages/offline_page_model_impl.cc b/chromium/components/offline_pages/offline_page_model_impl.cc
index 78cf6ebe4db..0a5094fb876 100644
--- a/chromium/components/offline_pages/offline_page_model_impl.cc
+++ b/chromium/components/offline_pages/offline_page_model_impl.cc
@@ -14,8 +14,10 @@
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/sequenced_task_runner.h"
+#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/clock.h"
#include "base/time/time.h"
#include "components/offline_pages/archive_manager.h"
#include "components/offline_pages/client_namespace_constants.h"
@@ -39,17 +41,6 @@ namespace {
const base::TimeDelta kStorageManagerStartingDelay =
base::TimeDelta::FromSeconds(20);
-// This enum is used in an UMA histogram. Hence the entries here shouldn't
-// be deleted or re-ordered and new ones should be added to the end.
-enum ClearAllStatus {
- CLEAR_ALL_SUCCEEDED,
- STORE_RESET_FAILED,
- STORE_RELOAD_FAILED,
-
- // NOTE: always keep this entry at the end.
- CLEAR_ALL_STATUS_COUNT
-};
-
int64_t GenerateOfflineId() {
return base::RandGenerator(std::numeric_limits<int64_t>::max()) + 1;
}
@@ -149,7 +140,51 @@ void ReportSavePageResultHistogramAfterSave(const ClientId& client_id,
histogram->Add(static_cast<int>(result));
}
-void ReportPageHistogramAfterSave(const OfflinePageItem& offline_page) {
+// Goes through the list of offline pages, compiling the following two metrics:
+// - a count of the pages with the same URL
+// - The difference between the |created_before| time and the creation time of
+// the page with the closest creation time before |created_before|.
+// Returns true if there was a page that was saved before |created_before| with
+// a matching URL.
+bool GetMatchingURLCountAndMostRecentCreationTime(
+ const std::map<int64_t, OfflinePageItem>& offline_pages,
+ std::string name_space,
+ const GURL& url,
+ base::Time created_before,
+ int* matching_url_count,
+ base::TimeDelta* most_recent_creation_time) {
+ int count = 0;
+
+ // Create a time that is very old, so that any valid time will be newer than
+ // it.
+ base::Time latest_time;
+ bool matching_page = false;
+
+ for (auto& id_page_pair : offline_pages) {
+ if (id_page_pair.second.client_id.name_space == name_space &&
+ url == id_page_pair.second.url) {
+ count++;
+ base::Time page_creation_time = id_page_pair.second.creation_time;
+ if (page_creation_time < created_before &&
+ page_creation_time > latest_time) {
+ latest_time = page_creation_time;
+ matching_page = true;
+ }
+ }
+ }
+
+ if (matching_url_count != nullptr)
+ *matching_url_count = count;
+ if (most_recent_creation_time != nullptr && latest_time != base::Time())
+ *most_recent_creation_time = created_before - latest_time;
+
+ return matching_page;
+}
+
+void ReportPageHistogramAfterSave(
+ const std::map<int64_t, OfflinePageItem>& offline_pages,
+ const OfflinePageItem& offline_page,
+ const base::Time& save_time) {
// The histogram below is an expansion of the UMA_HISTOGRAM_TIMES
// macro adapted to allow for a dynamically suffixed histogram name.
// Note: The factory creates and owns the histogram.
@@ -157,7 +192,7 @@ void ReportPageHistogramAfterSave(const OfflinePageItem& offline_page) {
AddHistogramSuffix(offline_page.client_id, "OfflinePages.SavePageTime"),
base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(10),
50, base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->AddTime(base::Time::Now() - offline_page.creation_time);
+ histogram->AddTime(save_time - offline_page.creation_time);
// The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
// macro adapted to allow for a dynamically suffixed histogram name.
@@ -167,20 +202,47 @@ void ReportPageHistogramAfterSave(const OfflinePageItem& offline_page) {
AddHistogramSuffix(offline_page.client_id, "OfflinePages.PageSize"),
1, 10000, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
histogram->Add(offline_page.file_size / 1024);
+
+ if (offline_page.client_id.name_space == kDownloadNamespace) {
+ int matching_url_count;
+ base::TimeDelta time_since_most_recent_duplicate;
+ if (GetMatchingURLCountAndMostRecentCreationTime(
+ offline_pages, offline_page.client_id.name_space, offline_page.url,
+ offline_page.creation_time, &matching_url_count,
+ &time_since_most_recent_duplicate)) {
+ // Using CUSTOM_COUNTS instead of time-oriented histogram to record
+ // samples in seconds rather than milliseconds.
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "OfflinePages.DownloadSavedPageTimeSinceDuplicateSaved",
+ time_since_most_recent_duplicate.InSeconds(),
+ base::TimeDelta::FromSeconds(1).InSeconds(),
+ base::TimeDelta::FromDays(7).InSeconds(), 50);
+ }
+ UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.DownloadSavedPageDuplicateCount",
+ matching_url_count, 1, 20, 10);
+ }
}
void ReportPageHistogramsAfterDelete(
const std::map<int64_t, OfflinePageItem>& offline_pages,
- const std::vector<int64_t>& deleted_offline_ids) {
+ const std::vector<OfflinePageItem>& deleted_pages,
+ const base::Time& delete_time) {
const int max_minutes = base::TimeDelta::FromDays(365).InMinutes();
- base::Time now = base::Time::Now();
int64_t total_size = 0;
- for (int64_t offline_id : deleted_offline_ids) {
- auto iter = offline_pages.find(offline_id);
- if (iter == offline_pages.end())
- continue;
- total_size += iter->second.file_size;
- ClientId client_id = iter->second.client_id;
+
+ for (const auto& page : deleted_pages) {
+ total_size += page.file_size;
+ ClientId client_id = page.client_id;
+
+ if (client_id.name_space == kDownloadNamespace) {
+ int remaining_pages_with_url;
+ GetMatchingURLCountAndMostRecentCreationTime(
+ offline_pages, page.client_id.name_space, page.url, base::Time::Max(),
+ &remaining_pages_with_url, nullptr);
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "OfflinePages.DownloadDeletedPageDuplicateCount",
+ remaining_pages_with_url, 1, 20, 10);
+ }
// The histograms below are an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
// macro adapted to allow for a dynamically suffixed histogram name.
@@ -188,43 +250,42 @@ void ReportPageHistogramsAfterDelete(
base::HistogramBase* histogram = base::Histogram::FactoryGet(
AddHistogramSuffix(client_id, "OfflinePages.PageLifetime"),
1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add((now - iter->second.creation_time).InMinutes());
+ histogram->Add((delete_time - page.creation_time).InMinutes());
histogram = base::Histogram::FactoryGet(
AddHistogramSuffix(
client_id, "OfflinePages.DeletePage.TimeSinceLastOpen"),
1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add((now - iter->second.last_access_time).InMinutes());
+ histogram->Add((delete_time - page.last_access_time).InMinutes());
histogram = base::Histogram::FactoryGet(
AddHistogramSuffix(
client_id, "OfflinePages.DeletePage.LastOpenToCreated"),
1, max_minutes, 100, base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(
- (iter->second.last_access_time - iter->second.creation_time).
- InMinutes());
+ histogram->Add((page.last_access_time - page.creation_time).InMinutes());
// Reported as Kb between 1Kb and 10Mb.
histogram = base::Histogram::FactoryGet(
AddHistogramSuffix(client_id, "OfflinePages.DeletePage.PageSize"),
1, 10000, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(iter->second.file_size / 1024);
+ histogram->Add(page.file_size / 1024);
histogram = base::Histogram::FactoryGet(
AddHistogramSuffix(client_id, "OfflinePages.DeletePage.AccessCount"),
1, 1000000, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(iter->second.access_count);
+ histogram->Add(page.access_count);
}
- if (deleted_offline_ids.size() > 1) {
+ if (deleted_pages.size() > 1) {
UMA_HISTOGRAM_COUNTS("OfflinePages.BatchDelete.Count",
- static_cast<int32_t>(deleted_offline_ids.size()));
+ static_cast<int32_t>(deleted_pages.size()));
UMA_HISTOGRAM_MEMORY_KB(
"OfflinePages.BatchDelete.TotalPageSize", total_size / 1024);
}
}
-void ReportPageHistogramsAfterAccess(const OfflinePageItem& offline_page_item) {
+void ReportPageHistogramsAfterAccess(const OfflinePageItem& offline_page_item,
+ const base::Time& access_time) {
// The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
// macro adapted to allow for a dynamically suffixed histogram name.
// Note: The factory creates and owns the histogram.
@@ -237,7 +298,7 @@ void ReportPageHistogramsAfterAccess(const OfflinePageItem& offline_page_item) {
1, kMaxOpenedPageHistogramBucket.InMinutes(), 50,
base::HistogramBase::kUmaTargetedHistogramFlag);
histogram->Add(
- (base::Time::Now() - offline_page_item.last_access_time).InMinutes());
+ (access_time - offline_page_item.last_access_time).InMinutes());
}
} // namespace
@@ -255,6 +316,7 @@ OfflinePageModelImpl::OfflinePageModelImpl(
is_loaded_(false),
policy_controller_(new ClientPolicyController()),
archive_manager_(new ArchiveManager(archives_dir, task_runner)),
+ testing_clock_(nullptr),
weak_ptr_factory_(this) {
archive_manager_->EnsureArchivesDirCreated(
base::Bind(&OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone,
@@ -274,6 +336,7 @@ void OfflinePageModelImpl::RemoveObserver(Observer* observer) {
void OfflinePageModelImpl::SavePage(
const GURL& url,
const ClientId& client_id,
+ int64_t proposed_offline_id,
std::unique_ptr<OfflinePageArchiver> archiver,
const SavePageCallback& callback) {
DCHECK(is_loaded_);
@@ -293,13 +356,15 @@ void OfflinePageModelImpl::SavePage(
return;
}
- int64_t offline_id = GenerateOfflineId();
+ // If we already have an offline id, use it. If not, generate one.
+ if (proposed_offline_id == kInvalidOfflineId)
+ proposed_offline_id = GenerateOfflineId();
archiver->CreateArchive(
- archives_dir_, offline_id,
+ archives_dir_, proposed_offline_id,
base::Bind(&OfflinePageModelImpl::OnCreateArchiveDone,
- weak_ptr_factory_.GetWeakPtr(), url, offline_id, client_id,
- base::Time::Now(), callback));
+ weak_ptr_factory_.GetWeakPtr(), url, proposed_offline_id,
+ client_id, GetCurrentTime(), callback));
pending_archivers_.push_back(std::move(archiver));
}
@@ -319,15 +384,15 @@ void OfflinePageModelImpl::MarkPageAccessedWhenLoadDone(int64_t offline_id) {
// be updated upon the successful store operation.
OfflinePageItem offline_page_item = iter->second;
- ReportPageHistogramsAfterAccess(offline_page_item);
+ ReportPageHistogramsAfterAccess(offline_page_item, GetCurrentTime());
- offline_page_item.last_access_time = base::Time::Now();
+ offline_page_item.last_access_time = GetCurrentTime();
offline_page_item.access_count++;
- store_->AddOrUpdateOfflinePage(
- offline_page_item,
- base::Bind(&OfflinePageModelImpl::OnMarkPageAccesseDone,
- weak_ptr_factory_.GetWeakPtr(), offline_page_item));
+ std::vector<OfflinePageItem> items = { offline_page_item };
+ store_->UpdateOfflinePages(
+ items, base::Bind(&OfflinePageModelImpl::OnMarkPageAccesseDone,
+ weak_ptr_factory_.GetWeakPtr(), offline_page_item));
}
void OfflinePageModelImpl::DeletePagesByOfflineId(
@@ -363,62 +428,27 @@ void OfflinePageModelImpl::DoDeletePagesByOfflineId(
weak_ptr_factory_.GetWeakPtr(), offline_ids, callback));
}
-void OfflinePageModelImpl::ClearAll(const base::Closure& callback) {
- DCHECK(is_loaded_);
-
- std::vector<int64_t> offline_ids;
- for (const auto& id_page_pair : offline_pages_)
- offline_ids.push_back(id_page_pair.first);
- DeletePagesByOfflineId(
- offline_ids,
- base::Bind(&OfflinePageModelImpl::OnRemoveAllFilesDoneForClearAll,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void OfflinePageModelImpl::DeletePagesByURLPredicate(
+void OfflinePageModelImpl::DeleteCachedPagesByURLPredicate(
const UrlPredicate& predicate,
const DeletePageCallback& callback) {
- RunWhenLoaded(base::Bind(&OfflinePageModelImpl::DoDeletePagesByURLPredicate,
- weak_ptr_factory_.GetWeakPtr(), predicate,
- callback));
+ RunWhenLoaded(
+ base::Bind(&OfflinePageModelImpl::DoDeleteCachedPagesByURLPredicate,
+ weak_ptr_factory_.GetWeakPtr(), predicate, callback));
}
-void OfflinePageModelImpl::DoDeletePagesByURLPredicate(
+void OfflinePageModelImpl::DoDeleteCachedPagesByURLPredicate(
const UrlPredicate& predicate,
const DeletePageCallback& callback) {
DCHECK(is_loaded_);
std::vector<int64_t> offline_ids;
for (const auto& id_page_pair : offline_pages_) {
- if (predicate.Run(id_page_pair.second.url))
+ if (IsRemovedOnCacheReset(id_page_pair.second) &&
+ predicate.Run(id_page_pair.second.url)) {
offline_ids.push_back(id_page_pair.first);
- }
- DoDeletePagesByOfflineId(offline_ids, callback);
-}
-
-void OfflinePageModelImpl::HasPages(const std::string& name_space,
- const HasPagesCallback& callback) {
- RunWhenLoaded(base::Bind(&OfflinePageModelImpl::HasPagesAfterLoadDone,
- weak_ptr_factory_.GetWeakPtr(), name_space,
- callback));
-}
-
-void OfflinePageModelImpl::HasPagesAfterLoadDone(
- const std::string& name_space,
- const HasPagesCallback& callback) const {
- DCHECK(is_loaded_);
-
- bool has_pages = false;
-
- for (const auto& id_page_pair : offline_pages_) {
- if (id_page_pair.second.client_id.name_space == name_space &&
- !id_page_pair.second.IsExpired()) {
- has_pages = true;
- break;
}
}
-
- callback.Run(has_pages);
+ DoDeletePagesByOfflineId(offline_ids, callback);
}
void OfflinePageModelImpl::CheckPagesExistOffline(
@@ -450,16 +480,26 @@ void OfflinePageModelImpl::CheckPagesExistOfflineAfterLoadDone(
void OfflinePageModelImpl::GetAllPages(
const MultipleOfflinePageItemCallback& callback) {
RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetAllPagesAfterLoadDone,
- weak_ptr_factory_.GetWeakPtr(), callback));
+ weak_ptr_factory_.GetWeakPtr(), GetAllPageMode::ALL,
+ callback));
+}
+
+void OfflinePageModelImpl::GetAllPagesWithExpired(
+ const MultipleOfflinePageItemCallback& callback) {
+ RunWhenLoaded(base::Bind(&OfflinePageModelImpl::GetAllPagesAfterLoadDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ GetAllPageMode::ALL_WITH_EXPIRED, callback));
}
void OfflinePageModelImpl::GetAllPagesAfterLoadDone(
+ GetAllPageMode mode,
const MultipleOfflinePageItemCallback& callback) const {
DCHECK(is_loaded_);
MultipleOfflinePageItemResult offline_pages;
for (const auto& id_page_pair : offline_pages_) {
- if (!id_page_pair.second.IsExpired())
+ if (mode == GetAllPageMode::ALL_WITH_EXPIRED ||
+ !id_page_pair.second.IsExpired())
offline_pages.push_back(id_page_pair.second);
}
@@ -518,58 +558,6 @@ const OfflinePageItem* OfflinePageModelImpl::MaybeGetPageByOfflineId(
: nullptr;
}
-void OfflinePageModelImpl::GetPageByOfflineURL(
- const GURL& offline_url,
- const SingleOfflinePageItemCallback& callback) {
- RunWhenLoaded(
- base::Bind(&OfflinePageModelImpl::GetPageByOfflineURLWhenLoadDone,
- weak_ptr_factory_.GetWeakPtr(), offline_url, callback));
-}
-
-void OfflinePageModelImpl::GetPageByOfflineURLWhenLoadDone(
- const GURL& offline_url,
- const SingleOfflinePageItemCallback& callback) const {
- // Getting pages by offline URL does not exclude expired pages, as the caller
- // already holds the offline URL and simply needs to look up a corresponding
- // online URL.
- const OfflinePageItem* result = nullptr;
-
- for (const auto& id_page_pair : offline_pages_) {
- if (id_page_pair.second.GetOfflineURL() == offline_url) {
- result = &id_page_pair.second;
- break;
- }
- }
-
- callback.Run(result);
-}
-
-const OfflinePageItem* OfflinePageModelImpl::MaybeGetPageByOfflineURL(
- const GURL& offline_url) const {
- // Getting pages by offline URL does not exclude expired pages, as the caller
- // already holds the offline URL and simply needs to look up a corresponding
- // online URL.
- for (const auto& id_page_pair : offline_pages_) {
- if (id_page_pair.second.GetOfflineURL() == offline_url)
- return &(id_page_pair.second);
- }
- return nullptr;
-}
-
-void OfflinePageModelImpl::GetBestPageForOnlineURL(
- const GURL& online_url,
- const SingleOfflinePageItemCallback callback) {
- RunWhenLoaded(
- base::Bind(&OfflinePageModelImpl::GetBestPageForOnlineURLWhenLoadDone,
- weak_ptr_factory_.GetWeakPtr(), online_url, callback));
-}
-
-void OfflinePageModelImpl::GetBestPageForOnlineURLWhenLoadDone(
- const GURL& online_url,
- const SingleOfflinePageItemCallback& callback) const {
- callback.Run(MaybeGetBestPageForOnlineURL(online_url));
-}
-
void OfflinePageModelImpl::GetPagesByOnlineURL(
const GURL& online_url,
const MultipleOfflinePageItemCallback& callback) {
@@ -583,9 +571,23 @@ void OfflinePageModelImpl::GetPagesByOnlineURLWhenLoadDone(
const MultipleOfflinePageItemCallback& callback) const {
std::vector<OfflinePageItem> result;
+ GURL::Replacements remove_params;
+ remove_params.ClearRef();
+
+ GURL online_url_without_fragment =
+ online_url.ReplaceComponents(remove_params);
+
for (const auto& id_page_pair : offline_pages_) {
- if (id_page_pair.second.url == online_url &&
- !id_page_pair.second.IsExpired()) {
+ if (id_page_pair.second.IsExpired())
+ continue;
+ if (online_url == id_page_pair.second.url) {
+ result.push_back(id_page_pair.second);
+ continue;
+ }
+ // If the full URL does not match, try with the fragment identifier
+ // stripped.
+ if (online_url_without_fragment ==
+ id_page_pair.second.url.ReplaceComponents(remove_params)) {
result.push_back(id_page_pair.second);
}
}
@@ -607,12 +609,7 @@ const OfflinePageItem* OfflinePageModelImpl::MaybeGetBestPageForOnlineURL(
}
void OfflinePageModelImpl::CheckMetadataConsistency() {
- RunWhenLoaded(
- base::Bind(&OfflinePageModelImpl::CheckMetadataConsistencyWhenLoadDone,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void OfflinePageModelImpl::CheckMetadataConsistencyWhenLoadDone() {
+ DCHECK(is_loaded_);
archive_manager_->GetAllArchives(
base::Bind(&OfflinePageModelImpl::CheckMetadataConsistencyForArchivePaths,
weak_ptr_factory_.GetWeakPtr()));
@@ -623,6 +620,7 @@ void OfflinePageModelImpl::ExpirePages(
const base::Time& expiration_time,
const base::Callback<void(bool)>& callback) {
std::vector<base::FilePath> paths_to_delete;
+ std::vector<OfflinePageItem> items_to_update;
for (int64_t offline_id : offline_ids) {
auto iter = offline_pages_.find(offline_id);
if (iter == offline_pages_.end())
@@ -632,11 +630,14 @@ void OfflinePageModelImpl::ExpirePages(
paths_to_delete.push_back(offline_page.file_path);
offline_page.expiration_time = expiration_time;
- store_->AddOrUpdateOfflinePage(
- offline_page, base::Bind(&OfflinePageModelImpl::OnExpirePageDone,
- weak_ptr_factory_.GetWeakPtr(), offline_id,
- expiration_time));
+ items_to_update.push_back(offline_page);
}
+
+ store_->UpdateOfflinePages(
+ items_to_update,
+ base::Bind(&OfflinePageModelImpl::OnExpirePageDone,
+ weak_ptr_factory_.GetWeakPtr(), expiration_time));
+
if (paths_to_delete.empty()) {
callback.Run(true);
return;
@@ -644,27 +645,32 @@ void OfflinePageModelImpl::ExpirePages(
archive_manager_->DeleteMultipleArchives(paths_to_delete, callback);
}
-void OfflinePageModelImpl::OnExpirePageDone(int64_t offline_id,
- const base::Time& expiration_time,
- bool success) {
- UMA_HISTOGRAM_BOOLEAN("OfflinePages.ExpirePage.StoreUpdateResult", success);
- if (!success)
- return;
- const auto& iter = offline_pages_.find(offline_id);
- if (iter != offline_pages_.end()) {
+void OfflinePageModelImpl::OnExpirePageDone(
+ const base::Time& expiration_time,
+ std::unique_ptr<OfflinePagesUpdateResult> result) {
+ UMA_HISTOGRAM_BOOLEAN("OfflinePages.ExpirePage.StoreUpdateResult",
+ result->updated_items.size() > 0);
+ for (const auto& expired_page : result->updated_items) {
+ const auto& iter = offline_pages_.find(expired_page.offline_id);
+ if (iter == offline_pages_.end())
+ continue;
+
iter->second.expiration_time = expiration_time;
ClientId client_id = iter->second.client_id;
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- AddHistogramSuffix(client_id, "OfflinePages.ExpirePage.PageLifetime")
- .c_str(),
- (expiration_time - iter->second.creation_time).InMinutes(), 1,
- base::TimeDelta::FromDays(30).InMinutes(), 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
+ offline_event_logger_.RecordPageExpired(
+ std::to_string(expired_page.offline_id));
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ AddHistogramSuffix(client_id, "OfflinePages.ExpirePage.PageLifetime"),
+ 1, base::TimeDelta::FromDays(30).InMinutes(), 50,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add((expiration_time - iter->second.creation_time).InMinutes());
+ histogram = base::Histogram::FactoryGet(
AddHistogramSuffix(client_id,
- "OfflinePages.ExpirePage.TimeSinceLastAccess")
- .c_str(),
- (expiration_time - iter->second.last_access_time).InMinutes(), 1,
- base::TimeDelta::FromDays(30).InMinutes(), 50);
+ "OfflinePages.ExpirePage.TimeSinceLastAccess"),
+ 1, base::TimeDelta::FromDays(30).InMinutes(), 50,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(
+ (expiration_time - iter->second.last_access_time).InMinutes());
}
}
@@ -697,6 +703,7 @@ void OfflinePageModelImpl::OnCreateArchiveDone(const GURL& requested_url,
ArchiverResult archiver_result,
const GURL& url,
const base::FilePath& file_path,
+ const base::string16& title,
int64_t file_size) {
if (requested_url != url) {
DVLOG(1) << "Saved URL does not match requested URL.";
@@ -716,8 +723,9 @@ void OfflinePageModelImpl::OnCreateArchiveDone(const GURL& requested_url,
}
OfflinePageItem offline_page_item(url, offline_id, client_id, file_path,
file_size, start_time);
- store_->AddOrUpdateOfflinePage(
- offline_page_item, base::Bind(&OfflinePageModelImpl::OnAddOfflinePageDone,
+ offline_page_item.title = title;
+ store_->AddOfflinePage(offline_page_item,
+ base::Bind(&OfflinePageModelImpl::OnAddOfflinePageDone,
weak_ptr_factory_.GetWeakPtr(), archiver,
callback, offline_page_item));
}
@@ -726,30 +734,38 @@ void OfflinePageModelImpl::OnAddOfflinePageDone(
OfflinePageArchiver* archiver,
const SavePageCallback& callback,
const OfflinePageItem& offline_page,
- bool success) {
+ ItemActionStatus status) {
SavePageResult result;
- if (success) {
+ if (status == ItemActionStatus::SUCCESS) {
offline_pages_[offline_page.offline_id] = offline_page;
result = SavePageResult::SUCCESS;
- ReportPageHistogramAfterSave(offline_page);
+ ReportPageHistogramAfterSave(offline_pages_, offline_page,
+ GetCurrentTime());
offline_event_logger_.RecordPageSaved(
offline_page.client_id.name_space, offline_page.url.spec(),
std::to_string(offline_page.offline_id));
+ } else if (status == ItemActionStatus::ALREADY_EXISTS) {
+ result = SavePageResult::ALREADY_EXISTS;
} else {
result = SavePageResult::STORE_FAILURE;
}
InformSavePageDone(callback, result, offline_page.client_id,
offline_page.offline_id);
- DeletePendingArchiver(archiver);
+ if (result == SavePageResult::SUCCESS) {
+ DeleteExistingPagesWithSameURL(offline_page);
+ } else {
+ PostClearStorageIfNeededTask();
+ }
+ DeletePendingArchiver(archiver);
FOR_EACH_OBSERVER(Observer, observers_, OfflinePageModelChanged(this));
}
void OfflinePageModelImpl::OnMarkPageAccesseDone(
const OfflinePageItem& offline_page_item,
- bool success) {
+ std::unique_ptr<OfflinePagesUpdateResult> result) {
// Update the item in the cache only upon success.
- if (success)
+ if (result->updated_items.size() > 0)
offline_pages_[offline_page_item.offline_id] = offline_page_item;
// No need to fire OfflinePageModelChanged event since updating access info
@@ -761,8 +777,9 @@ void OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone(
UMA_HISTOGRAM_TIMES("OfflinePages.Model.ArchiveDirCreationTime",
base::TimeTicks::Now() - start_time);
- store_->Load(base::Bind(&OfflinePageModelImpl::OnLoadDone,
- weak_ptr_factory_.GetWeakPtr(), start_time));
+ store_->GetOfflinePages(base::Bind(&OfflinePageModelImpl::OnLoadDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ start_time));
}
void OfflinePageModelImpl::OnLoadDone(
@@ -808,30 +825,31 @@ void OfflinePageModelImpl::InformSavePageDone(const SavePageCallback& callback,
ReportSavePageResultHistogramAfterSave(client_id, result);
archive_manager_->GetStorageStats(
base::Bind(&ReportStorageHistogramsAfterSave));
+ callback.Run(result, offline_id);
+}
+
+void OfflinePageModelImpl::DeleteExistingPagesWithSameURL(
+ const OfflinePageItem& offline_page) {
// Remove existing pages generated by the same policy and with same url.
size_t pages_allowed =
- policy_controller_->GetPolicy(client_id.name_space).pages_allowed_per_url;
- if (result == SavePageResult::SUCCESS && pages_allowed != kUnlimitedPages) {
- GetPagesByOnlineURL(
- offline_pages_[offline_id].url,
- base::Bind(&OfflinePageModelImpl::OnPagesFoundWithSameURL,
- weak_ptr_factory_.GetWeakPtr(), client_id, offline_id,
- pages_allowed));
- } else {
- PostClearStorageIfNeededTask();
- }
- callback.Run(result, offline_id);
+ policy_controller_->GetPolicy(offline_page.client_id.name_space)
+ .pages_allowed_per_url;
+ if (pages_allowed == kUnlimitedPages)
+ return;
+ GetPagesByOnlineURL(
+ offline_page.url,
+ base::Bind(&OfflinePageModelImpl::OnPagesFoundWithSameURL,
+ weak_ptr_factory_.GetWeakPtr(), offline_page, pages_allowed));
}
void OfflinePageModelImpl::OnPagesFoundWithSameURL(
- const ClientId& client_id,
- int64_t offline_id,
+ const OfflinePageItem& offline_page,
size_t pages_allowed,
const MultipleOfflinePageItemResult& items) {
std::vector<OfflinePageItem> pages_to_delete;
for (const auto& item : items) {
- if (item.offline_id != offline_id &&
- item.client_id.name_space == client_id.name_space) {
+ if (item.offline_id != offline_page.offline_id &&
+ item.client_id.name_space == offline_page.client_id.name_space) {
pages_to_delete.push_back(item);
}
}
@@ -875,32 +893,43 @@ void OfflinePageModelImpl::OnDeleteArchiveFilesDone(
}
store_->RemoveOfflinePages(
- offline_ids,
- base::Bind(&OfflinePageModelImpl::OnRemoveOfflinePagesDone,
- weak_ptr_factory_.GetWeakPtr(), offline_ids, callback));
+ offline_ids, base::Bind(&OfflinePageModelImpl::OnRemoveOfflinePagesDone,
+ weak_ptr_factory_.GetWeakPtr(), callback));
}
void OfflinePageModelImpl::OnRemoveOfflinePagesDone(
- const std::vector<int64_t>& offline_ids,
const DeletePageCallback& callback,
- bool success) {
- ReportPageHistogramsAfterDelete(offline_pages_, offline_ids);
-
- for (int64_t offline_id : offline_ids) {
+ std::unique_ptr<OfflinePagesUpdateResult> result) {
+ ReportPageHistogramsAfterDelete(offline_pages_, result->updated_items,
+ GetCurrentTime());
+
+ // This part of the loop is explicitly broken out, as it should be gone in
+ // fully asynchronous code.
+ for (const auto& page : result->updated_items) {
+ int64_t offline_id = page.offline_id;
offline_event_logger_.RecordPageDeleted(std::to_string(offline_id));
auto iter = offline_pages_.find(offline_id);
if (iter == offline_pages_.end())
continue;
- FOR_EACH_OBSERVER(
- Observer, observers_,
- OfflinePageDeleted(iter->second.offline_id, iter->second.client_id));
offline_pages_.erase(iter);
}
- // Deleting multiple pages always succeeds when it gets to this point.
- InformDeletePageDone(callback, (success || offline_ids.size() > 1)
- ? DeletePageResult::SUCCESS
- : DeletePageResult::STORE_FAILURE);
+ for (const auto& page : result->updated_items) {
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OfflinePageDeleted(page.offline_id, page.client_id));
+ }
+
+ // TODO(fgorski): React the FAILED_INITIALIZATION, FAILED_RESET here.
+ // TODO(fgorski): We need a better callback interface for the Remove action on
+ // the this class. Currently removing an item that does not exist is
+ // considered a success, but not called out as such to the caller.
+ DeletePageResult delete_result;
+ if (result->store_state == StoreState::LOADED)
+ delete_result = DeletePageResult::SUCCESS;
+ else
+ delete_result = DeletePageResult::STORE_FAILURE;
+
+ InformDeletePageDone(callback, delete_result);
}
void OfflinePageModelImpl::InformDeletePageDone(
@@ -933,7 +962,7 @@ void OfflinePageModelImpl::ExpirePagesMissingArchiveFile(
return;
ExpirePages(
- ids_of_pages_missing_archive_file, base::Time::Now(),
+ ids_of_pages_missing_archive_file, GetCurrentTime(),
base::Bind(&OfflinePageModelImpl::OnExpirePagesMissingArchiveFileDone,
weak_ptr_factory_.GetWeakPtr(),
ids_of_pages_missing_archive_file));
@@ -975,50 +1004,6 @@ void OfflinePageModelImpl::OnDeleteOrphanedArchivesDone(
success);
}
-void OfflinePageModelImpl::OnRemoveAllFilesDoneForClearAll(
- const base::Closure& callback,
- DeletePageResult result) {
- store_->Reset(base::Bind(&OfflinePageModelImpl::OnResetStoreDoneForClearAll,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void OfflinePageModelImpl::OnResetStoreDoneForClearAll(
- const base::Closure& callback,
- bool success) {
- DCHECK(success);
- if (!success) {
- offline_event_logger_.RecordStoreClearError();
- UMA_HISTOGRAM_ENUMERATION("OfflinePages.ClearAllStatus2",
- STORE_RESET_FAILED, CLEAR_ALL_STATUS_COUNT);
- }
-
- offline_pages_.clear();
- store_->Load(base::Bind(&OfflinePageModelImpl::OnReloadStoreDoneForClearAll,
- weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void OfflinePageModelImpl::OnReloadStoreDoneForClearAll(
- const base::Closure& callback,
- OfflinePageMetadataStore::LoadStatus load_status,
- const std::vector<OfflinePageItem>& offline_pages) {
- DCHECK_EQ(OfflinePageMetadataStore::LOAD_SUCCEEDED, load_status);
- UMA_HISTOGRAM_ENUMERATION(
- "OfflinePages.ClearAllStatus2",
- load_status == OfflinePageMetadataStore::LOAD_SUCCEEDED
- ? CLEAR_ALL_SUCCEEDED
- : STORE_RELOAD_FAILED,
- CLEAR_ALL_STATUS_COUNT);
-
- if (load_status == OfflinePageMetadataStore::LOAD_SUCCEEDED) {
- offline_event_logger_.RecordStoreCleared();
- } else {
- offline_event_logger_.RecordStoreReloadError();
- }
-
- CacheLoadedData(offline_pages);
- callback.Run();
-}
-
void OfflinePageModelImpl::CacheLoadedData(
const std::vector<OfflinePageItem>& offline_pages) {
offline_pages_.clear();
@@ -1050,6 +1035,12 @@ void OfflinePageModelImpl::PostClearStorageIfNeededTask() {
weak_ptr_factory_.GetWeakPtr())));
}
+bool OfflinePageModelImpl::IsRemovedOnCacheReset(
+ const OfflinePageItem& offline_page) const {
+ return policy_controller_->IsRemovedOnCacheReset(
+ offline_page.client_id.name_space);
+}
+
void OfflinePageModelImpl::RunWhenLoaded(const base::Closure& task) {
if (!is_loaded_) {
delayed_tasks_.push_back(task);
@@ -1059,4 +1050,8 @@ void OfflinePageModelImpl::RunWhenLoaded(const base::Closure& task) {
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
}
+base::Time OfflinePageModelImpl::GetCurrentTime() const {
+ return testing_clock_ ? testing_clock_->Now() : base::Time::Now();
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/offline_page_model_impl.h b/chromium/components/offline_pages/offline_page_model_impl.h
index afda58cb95f..a805f1bab2d 100644
--- a/chromium/components/offline_pages/offline_page_model_impl.h
+++ b/chromium/components/offline_pages/offline_page_model_impl.h
@@ -23,6 +23,8 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/offline_pages/offline_page_archiver.h"
#include "components/offline_pages/offline_page_metadata_store.h"
@@ -30,25 +32,23 @@
#include "components/offline_pages/offline_page_model_event_logger.h"
#include "components/offline_pages/offline_page_storage_manager.h"
#include "components/offline_pages/offline_page_types.h"
+#include "components/offline_pages/offline_store_types.h"
class GURL;
namespace base {
+class Clock;
class SequencedTaskRunner;
-class Time;
class TimeDelta;
class TimeTicks;
} // namespace base
namespace offline_pages {
-static const int64_t kInvalidOfflineId = 0;
-
struct ClientId;
struct OfflinePageItem;
class ArchiveManager;
class ClientPolicyController;
-class OfflinePageMetadataStore;
class OfflinePageStorageManager;
// Implementation of service for saving pages offline, storing the offline
@@ -67,20 +67,21 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
void RemoveObserver(Observer* observer) override;
void SavePage(const GURL& url,
const ClientId& client_id,
+ int64_t proposed_offline_id,
std::unique_ptr<OfflinePageArchiver> archiver,
const SavePageCallback& callback) override;
void MarkPageAccessed(int64_t offline_id) override;
- void ClearAll(const base::Closure& callback) override;
void DeletePagesByOfflineId(const std::vector<int64_t>& offline_ids,
const DeletePageCallback& callback) override;
- void DeletePagesByURLPredicate(const UrlPredicate& predicate,
- const DeletePageCallback& callback) override;
- void HasPages(const std::string& name_space,
- const HasPagesCallback& callback) override;
+ void DeleteCachedPagesByURLPredicate(
+ const UrlPredicate& predicate,
+ const DeletePageCallback& callback) override;
void CheckPagesExistOffline(
const std::set<GURL>& urls,
const CheckPagesExistOfflineCallback& callback) override;
void GetAllPages(const MultipleOfflinePageItemCallback& callback) override;
+ void GetAllPagesWithExpired(
+ const MultipleOfflinePageItemCallback& callback) override;
void GetOfflineIdsForClientId(
const ClientId& client_id,
const MultipleOfflineIdCallback& callback) override;
@@ -91,20 +92,11 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
const SingleOfflinePageItemCallback& callback) override;
const OfflinePageItem* MaybeGetPageByOfflineId(
int64_t offline_id) const override;
- void GetPageByOfflineURL(
- const GURL& offline_url,
- const SingleOfflinePageItemCallback& callback) override;
- const OfflinePageItem* MaybeGetPageByOfflineURL(
- const GURL& offline_url) const override;
void GetPagesByOnlineURL(
const GURL& online_url,
const MultipleOfflinePageItemCallback& callback) override;
- void GetBestPageForOnlineURL(
- const GURL& online_url,
- const SingleOfflinePageItemCallback callback) override;
const OfflinePageItem* MaybeGetBestPageForOnlineURL(
const GURL& online_url) const override;
- void CheckMetadataConsistency() override;
void ExpirePages(const std::vector<int64_t>& offline_ids,
const base::Time& expiration_time,
const base::Callback<void(bool)>& callback) override;
@@ -112,6 +104,7 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
// Methods for testing only:
OfflinePageMetadataStore* GetStoreForTesting();
+ void set_testing_clock(base::Clock* clock) { testing_clock_ = clock; }
OfflinePageStorageManager* GetStorageManager();
@@ -127,12 +120,18 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
private:
FRIEND_TEST_ALL_PREFIXES(OfflinePageModelImplTest, MarkPageForDeletion);
+ enum class GetAllPageMode {
+ ALL, // Get all active page entries.
+ ALL_WITH_EXPIRED, // Get all pages entries including expired ones.
+ };
+
typedef ScopedVector<OfflinePageArchiver> PendingArchivers;
// Callback for ensuring archive directory is created.
void OnEnsureArchivesDirCreatedDone(const base::TimeTicks& start_time);
void GetAllPagesAfterLoadDone(
+ GetAllPageMode mode,
const MultipleOfflinePageItemCallback& callback) const;
void CheckPagesExistOfflineAfterLoadDone(
const std::set<GURL>& urls,
@@ -144,20 +143,11 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
int64_t offline_id,
const SingleOfflinePageItemCallback& callback) const;
void GetPagesByOnlineURLWhenLoadDone(
- const GURL& offline_url,
- const MultipleOfflinePageItemCallback& callback) const;
- void GetPageByOfflineURLWhenLoadDone(
- const GURL& offline_url,
- const SingleOfflinePageItemCallback& callback) const;
- void GetBestPageForOnlineURLWhenLoadDone(
const GURL& online_url,
- const SingleOfflinePageItemCallback& callback) const;
+ const MultipleOfflinePageItemCallback& callback) const;
void MarkPageAccessedWhenLoadDone(int64_t offline_id);
- void CheckMetadataConsistencyWhenLoadDone();
- // Callback for checking whether we have offline pages.
- void HasPagesAfterLoadDone(const std::string& name_space,
- const HasPagesCallback& callback) const;
+ void CheckMetadataConsistency();
// Callback for loading pages from the offline page metadata store.
void OnLoadDone(const base::TimeTicks& start_time,
@@ -174,11 +164,12 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
OfflinePageArchiver::ArchiverResult result,
const GURL& url,
const base::FilePath& file_path,
+ const base::string16& title,
int64_t file_size);
void OnAddOfflinePageDone(OfflinePageArchiver* archiver,
const SavePageCallback& callback,
const OfflinePageItem& offline_page,
- bool success);
+ ItemActionStatus status);
void InformSavePageDone(const SavePageCallback& callback,
SavePageResult result,
const ClientId& client_id,
@@ -189,14 +180,14 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
void OnDeleteArchiveFilesDone(const std::vector<int64_t>& offline_ids,
const DeletePageCallback& callback,
bool success);
- void OnRemoveOfflinePagesDone(const std::vector<int64_t>& offline_ids,
- const DeletePageCallback& callback,
- bool success);
+ void OnRemoveOfflinePagesDone(
+ const DeletePageCallback& callback,
+ std::unique_ptr<OfflinePagesUpdateResult> result);
void InformDeletePageDone(const DeletePageCallback& callback,
DeletePageResult result);
void OnMarkPageAccesseDone(const OfflinePageItem& offline_page_item,
- bool success);
+ std::unique_ptr<OfflinePagesUpdateResult> result);
// Callbacks for checking metadata consistency.
void CheckMetadataConsistencyForArchivePaths(
@@ -214,21 +205,12 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
bool success);
// Callbacks for deleting pages with same URL when saving pages.
- void OnPagesFoundWithSameURL(const ClientId& client_id,
- int64_t offline_id,
+ void DeleteExistingPagesWithSameURL(const OfflinePageItem& offline_page);
+ void OnPagesFoundWithSameURL(const OfflinePageItem& offline_page,
size_t pages_allowed,
const MultipleOfflinePageItemResult& items);
void OnDeleteOldPagesWithSameURL(DeletePageResult result);
- // Steps for clearing all.
- void OnRemoveAllFilesDoneForClearAll(const base::Closure& callback,
- DeletePageResult result);
- void OnResetStoreDoneForClearAll(const base::Closure& callback, bool success);
- void OnReloadStoreDoneForClearAll(
- const base::Closure& callback,
- OfflinePageMetadataStore::LoadStatus load_status,
- const std::vector<OfflinePageItem>& offline_pages);
-
void CacheLoadedData(const std::vector<OfflinePageItem>& offline_pages);
// Actually does the work of deleting, requires the model is loaded.
@@ -237,13 +219,12 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
// Similar to DoDeletePagesByOfflineId, does actual work of deleting, and
// requires that the model is loaded.
- void DoDeletePagesByURLPredicate(const UrlPredicate& predicate,
- const DeletePageCallback& callback);
+ void DoDeleteCachedPagesByURLPredicate(const UrlPredicate& predicate,
+ const DeletePageCallback& callback);
// Callback completing page expiration.
- void OnExpirePageDone(int64_t offline_id,
- const base::Time& expiration_time,
- bool success);
+ void OnExpirePageDone(const base::Time& expiration_time,
+ std::unique_ptr<OfflinePagesUpdateResult> result);
// Clears expired pages if there are any.
void ClearStorageIfNeeded(
@@ -256,8 +237,13 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
// Post task to clear storage.
void PostClearStorageIfNeededTask();
+ // Check if |offline_page| should be removed on cache reset by user.
+ bool IsRemovedOnCacheReset(const OfflinePageItem& offline_page) const;
+
void RunWhenLoaded(const base::Closure& job);
+ base::Time GetCurrentTime() const;
+
// Persistent store for offline page metadata.
std::unique_ptr<OfflinePageMetadataStore> store_;
@@ -269,7 +255,7 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
bool is_loaded_;
- // In memory copy of the offline page metadata, keyed by bookmark IDs.
+ // In memory copy of the offline page metadata, keyed by offline IDs.
std::map<int64_t, OfflinePageItem> offline_pages_;
// Pending archivers owned by this model.
@@ -291,6 +277,10 @@ class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
// Logger to facilitate recording of events.
OfflinePageModelEventLogger offline_event_logger_;
+ // Clock for getting time in testing code. The setter is responsible to reset
+ // it once it is not longer needed.
+ base::Clock* testing_clock_;
+
base::WeakPtrFactory<OfflinePageModelImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(OfflinePageModelImpl);
diff --git a/chromium/components/offline_pages/offline_page_model_impl_unittest.cc b/chromium/components/offline_pages/offline_page_model_impl_unittest.cc
index 0be40257c37..a65ef23c02b 100644
--- a/chromium/components/offline_pages/offline_page_model_impl_unittest.cc
+++ b/chromium/components/offline_pages/offline_page_model_impl_unittest.cc
@@ -13,10 +13,13 @@
#include "base/feature_list.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/metrics/statistics_recorder.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -36,15 +39,21 @@ namespace offline_pages {
namespace {
const char kTestClientNamespace[] = "CLIENT_NAMESPACE";
+const char kUserRequestedNamespace[] = "download";
const GURL kTestUrl("http://example.com");
const GURL kTestUrl2("http://other.page.com");
const GURL kTestUrl3("http://test.xyz");
const GURL kTestUrl4("http://page.net");
const GURL kFileUrl("file:///foo");
+const GURL kTestUrlWithFragment("http://example.com#frag");
+const GURL kTestUrl2WithFragment("http://other.page.com#frag");
+const GURL kTestUrl2WithFragment2("http://other.page.com#frag2");
const ClientId kTestClientId1(kTestClientNamespace, "1234");
const ClientId kTestClientId2(kTestClientNamespace, "5678");
const ClientId kTestClientId3(kTestClientNamespace, "42");
+const ClientId kTestUserRequestedClientId(kUserRequestedNamespace, "714");
const int64_t kTestFileSize = 876543LL;
+const base::string16 kTestTitle = base::UTF8ToUTF16("a title");
bool URLSpecContains(std::string contains_value, const GURL& url) {
std::string spec = url.spec();
@@ -77,9 +86,7 @@ class OfflinePageModelImplTest
// OfflinePageModel callbacks.
void OnSavePageDone(SavePageResult result, int64_t offline_id);
void OnDeletePageDone(DeletePageResult result);
- void OnHasPagesDone(bool result);
void OnCheckPagesExistOfflineDone(const CheckPagesExistOfflineResult& result);
- void OnClearAllDone();
void OnGetOfflineIdsForClientIdDone(MultipleOfflineIdResult* storage,
const MultipleOfflineIdResult& result);
void OnGetSingleOfflinePageItemResult(const OfflinePageItem** storage,
@@ -135,9 +142,7 @@ class OfflinePageModelImplTest
const OfflinePageItem* GetPageByOfflineId(int64_t offline_id);
- MultipleOfflinePageItemResult GetPagesByOnlineURL(const GURL& offline_url);
-
- const OfflinePageItem* GetPageByOfflineURL(const GURL& offline_url);
+ MultipleOfflinePageItemResult GetPagesByOnlineURL(const GURL& online_url);
OfflinePageModelImpl* model() { return model_.get(); }
@@ -161,6 +166,8 @@ class OfflinePageModelImplTest
bool last_expire_page_result() const { return last_expire_page_result_; }
+ const base::HistogramTester& histograms() const { return histogram_tester_; }
+
private:
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
@@ -173,11 +180,12 @@ class OfflinePageModelImplTest
base::FilePath last_archiver_path_;
int64_t last_deleted_offline_id_;
ClientId last_deleted_client_id_;
- bool last_has_pages_result_;
CheckPagesExistOfflineResult last_pages_exist_result_;
int last_cleared_pages_count_;
DeletePageResult last_clear_page_result_;
bool last_expire_page_result_;
+
+ base::HistogramTester histogram_tester_;
};
OfflinePageModelImplTest::OfflinePageModelImplTest()
@@ -233,19 +241,11 @@ void OfflinePageModelImplTest::OnDeletePageDone(DeletePageResult result) {
last_delete_result_ = result;
}
-void OfflinePageModelImplTest::OnHasPagesDone(bool result) {
- last_has_pages_result_ = result;
-}
-
void OfflinePageModelImplTest::OnCheckPagesExistOfflineDone(
const CheckPagesExistOfflineResult& result) {
last_pages_exist_result_ = result;
}
-void OfflinePageModelImplTest::OnClearAllDone() {
- PumpLoop();
-}
-
void OfflinePageModelImplTest::OnStoreUpdateDone(bool /* success - ignored */) {
}
@@ -253,8 +253,9 @@ std::unique_ptr<OfflinePageTestArchiver>
OfflinePageModelImplTest::BuildArchiver(
const GURL& url,
OfflinePageArchiver::ArchiverResult result) {
- return std::unique_ptr<OfflinePageTestArchiver>(new OfflinePageTestArchiver(
- this, url, result, kTestFileSize, base::ThreadTaskRunnerHandle::Get()));
+ return std::unique_ptr<OfflinePageTestArchiver>(
+ new OfflinePageTestArchiver(this, url, result, kTestTitle, kTestFileSize,
+ base::ThreadTaskRunnerHandle::Get()));
}
std::unique_ptr<OfflinePageMetadataStore>
@@ -265,8 +266,9 @@ OfflinePageModelImplTest::BuildStore() {
std::unique_ptr<OfflinePageModelImpl> OfflinePageModelImplTest::BuildModel(
std::unique_ptr<OfflinePageMetadataStore> store) {
- return std::unique_ptr<OfflinePageModelImpl>(new OfflinePageModelImpl(
- std::move(store), temp_dir_.path(), base::ThreadTaskRunnerHandle::Get()));
+ return std::unique_ptr<OfflinePageModelImpl>(
+ new OfflinePageModelImpl(std::move(store), temp_dir_.GetPath(),
+ base::ThreadTaskRunnerHandle::Get()));
}
void OfflinePageModelImplTest::ResetModel() {
@@ -314,7 +316,7 @@ void OfflinePageModelImplTest::SavePageWithArchiverResult(
OfflinePageArchiver::ArchiverResult result) {
std::unique_ptr<OfflinePageTestArchiver> archiver(BuildArchiver(url, result));
model()->SavePage(
- url, client_id, std::move(archiver),
+ url, client_id, 0l, std::move(archiver),
base::Bind(&OfflinePageModelImplTest::OnSavePageDone, AsWeakPtr()));
PumpLoop();
}
@@ -365,17 +367,6 @@ const OfflinePageItem* OfflinePageModelImplTest::GetPageByOfflineId(
return result;
}
-const OfflinePageItem* OfflinePageModelImplTest::GetPageByOfflineURL(
- const GURL& offline_url) {
- const OfflinePageItem* result = nullptr;
- model()->GetPageByOfflineURL(
- offline_url,
- base::Bind(&OfflinePageModelImplTest::OnGetSingleOfflinePageItemResult,
- AsWeakPtr(), base::Unretained(&result)));
- PumpLoop();
- return result;
-}
-
void OfflinePageModelImplTest::OnGetSingleOfflinePageItemResult(
const OfflinePageItem** storage,
const OfflinePageItem* result) {
@@ -404,11 +395,13 @@ MultipleOfflinePageItemResult OfflinePageModelImplTest::GetPagesByOnlineURL(
}
bool OfflinePageModelImplTest::HasPages(std::string name_space) {
- model()->HasPages(
- name_space,
- base::Bind(&OfflinePageModelImplTest::OnHasPagesDone, AsWeakPtr()));
- PumpLoop();
- return last_has_pages_result_;
+ MultipleOfflinePageItemResult all_pages = GetAllPages();
+ for (const auto& page : all_pages) {
+ if (page.client_id.name_space == name_space)
+ return true;
+ }
+
+ return false;
}
TEST_F(OfflinePageModelImplTest, SavePageSuccessful) {
@@ -438,6 +431,7 @@ TEST_F(OfflinePageModelImplTest, SavePageSuccessful) {
EXPECT_EQ(kTestFileSize, offline_pages[0].file_size);
EXPECT_EQ(0, offline_pages[0].access_count);
EXPECT_EQ(0, offline_pages[0].flags);
+ EXPECT_EQ(kTestTitle, offline_pages[0].title);
}
TEST_F(OfflinePageModelImplTest, SavePageOfflineArchiverCancelled) {
@@ -473,7 +467,7 @@ TEST_F(OfflinePageModelImplTest, SavePageOfflineArchiverReturnedWrongUrl) {
BuildArchiver(GURL("http://other.random.url.com"),
OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED));
model()->SavePage(
- kTestUrl, kTestClientId1, std::move(archiver),
+ kTestUrl, kTestClientId1, 0l, std::move(archiver),
base::Bind(&OfflinePageModelImplTest::OnSavePageDone, AsWeakPtr()));
PumpLoop();
EXPECT_EQ(SavePageResult::ARCHIVE_CREATION_FAILED, last_save_result());
@@ -490,7 +484,7 @@ TEST_F(OfflinePageModelImplTest, SavePageLocalFileFailed) {
// Don't create archiver since it will not be needed for pages that are not
// going to be saved.
model()->SavePage(
- kFileUrl, kTestClientId1, std::unique_ptr<OfflinePageTestArchiver>(),
+ kFileUrl, kTestClientId1, 0l, std::unique_ptr<OfflinePageTestArchiver>(),
base::Bind(&OfflinePageModelImplTest::OnSavePageDone, AsWeakPtr()));
PumpLoop();
EXPECT_EQ(SavePageResult::SKIPPED, last_save_result());
@@ -504,7 +498,7 @@ TEST_F(OfflinePageModelImplTest, SavePageOfflineArchiverTwoPages) {
OfflinePageTestArchiver* archiver_ptr = archiver.get();
archiver_ptr->set_delayed(true);
model()->SavePage(
- kTestUrl, kTestClientId1, std::move(archiver),
+ kTestUrl, kTestClientId1, 0l, std::move(archiver),
base::Bind(&OfflinePageModelImplTest::OnSavePageDone, AsWeakPtr()));
EXPECT_TRUE(archiver_ptr->create_archive_called());
@@ -639,7 +633,41 @@ TEST_F(OfflinePageModelImplTest, DeletePageSuccessful) {
EXPECT_EQ(0u, store->GetAllPages().size());
}
-TEST_F(OfflinePageModelImplTest, DeletePageByPredicate) {
+TEST_F(OfflinePageModelImplTest, DeleteCachedPageByPredicateUserRequested) {
+ OfflinePageTestStore* store = GetStore();
+
+ // Save one page.
+ SavePage(kTestUrl, kTestClientId1);
+ int64_t offline1 = last_save_offline_id();
+ EXPECT_EQ(SavePageResult::SUCCESS, last_save_result());
+ EXPECT_EQ(1u, store->GetAllPages().size());
+
+ ResetResults();
+
+ // Save an user-requested page in same domain.
+ SavePage(kTestUrl, kTestUserRequestedClientId);
+ int64_t offline2 = last_save_offline_id();
+ EXPECT_EQ(SavePageResult::SUCCESS, last_save_result());
+ EXPECT_EQ(2u, store->GetAllPages().size());
+
+ ResetResults();
+
+ // Delete the second page.
+ model()->DeleteCachedPagesByURLPredicate(
+ base::Bind(&URLSpecContains, "example.com"),
+ base::Bind(&OfflinePageModelImplTest::OnDeletePageDone, AsWeakPtr()));
+
+ PumpLoop();
+
+ EXPECT_EQ(last_deleted_offline_id(), offline1);
+ EXPECT_EQ(last_deleted_client_id(), kTestClientId1);
+ EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_result());
+ ASSERT_EQ(1u, store->GetAllPages().size());
+ EXPECT_EQ(kTestUrl, store->GetAllPages()[0].url);
+ EXPECT_EQ(offline2, store->GetAllPages()[0].offline_id);
+}
+
+TEST_F(OfflinePageModelImplTest, DeleteCachedPageByPredicate) {
OfflinePageTestStore* store = GetStore();
// Save one page.
@@ -659,7 +687,7 @@ TEST_F(OfflinePageModelImplTest, DeletePageByPredicate) {
ResetResults();
// Delete the second page.
- model()->DeletePagesByURLPredicate(
+ model()->DeleteCachedPagesByURLPredicate(
base::Bind(&URLSpecContains, "page.com"),
base::Bind(&OfflinePageModelImplTest::OnDeletePageDone, AsWeakPtr()));
@@ -674,7 +702,7 @@ TEST_F(OfflinePageModelImplTest, DeletePageByPredicate) {
ResetResults();
// Delete the first page.
- model()->DeletePagesByURLPredicate(
+ model()->DeleteCachedPagesByURLPredicate(
base::Bind(&URLSpecContains, "example.com"),
base::Bind(&OfflinePageModelImplTest::OnDeletePageDone, AsWeakPtr()));
@@ -695,7 +723,7 @@ TEST_F(OfflinePageModelImplTest, DeletePageNotFound) {
ResetResults();
- model()->DeletePagesByURLPredicate(
+ model()->DeleteCachedPagesByURLPredicate(
base::Bind(&URLSpecContains, "page.com"),
base::Bind(&OfflinePageModelImplTest::OnDeletePageDone, AsWeakPtr()));
PumpLoop();
@@ -727,9 +755,12 @@ TEST_F(OfflinePageModelImplTest, DetectThatOfflineCopyIsMissing) {
const OfflinePageItem* page = GetPageByOfflineId(offline_id);
- // Delete the offline copy of the page and check the metadata.
+ // Delete the offline copy of the page.
base::DeleteFile(page->file_path, false);
- model()->CheckMetadataConsistency();
+
+ // Resetting the model will cause a consistency check.
+ ResetModel();
+
PumpLoop();
// Check if the page has been expired.
@@ -785,7 +816,7 @@ TEST_F(OfflinePageModelImplTest, DeleteMultiplePages) {
std::unique_ptr<OfflinePageTestArchiver> archiver(BuildArchiver(
kTestUrl, OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED));
model()->SavePage(
- kTestUrl, kTestClientId1, std::move(archiver),
+ kTestUrl, kTestClientId1, 0l, std::move(archiver),
base::Bind(&OfflinePageModelImplTest::OnSavePageDone, AsWeakPtr()));
PumpLoop();
int64_t offline1 = last_save_offline_id();
@@ -793,7 +824,7 @@ TEST_F(OfflinePageModelImplTest, DeleteMultiplePages) {
std::unique_ptr<OfflinePageTestArchiver> archiver2(BuildArchiver(
kTestUrl2, OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED));
model()->SavePage(
- kTestUrl2, kTestClientId2, std::move(archiver2),
+ kTestUrl2, kTestClientId2, 0l, std::move(archiver2),
base::Bind(&OfflinePageModelImplTest::OnSavePageDone, AsWeakPtr()));
PumpLoop();
int64_t offline2 = last_save_offline_id();
@@ -801,7 +832,7 @@ TEST_F(OfflinePageModelImplTest, DeleteMultiplePages) {
std::unique_ptr<OfflinePageTestArchiver> archiver3(BuildArchiver(
kTestUrl3, OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED));
model()->SavePage(
- kTestUrl3, kTestClientId3, std::move(archiver3),
+ kTestUrl3, kTestClientId3, 0l, std::move(archiver3),
base::Bind(&OfflinePageModelImplTest::OnSavePageDone, AsWeakPtr()));
PumpLoop();
@@ -844,34 +875,6 @@ TEST_F(OfflinePageModelImplTest, GetPageByOfflineId) {
EXPECT_FALSE(page);
}
-TEST_F(OfflinePageModelImplTest, GetPageByOfflineURL) {
- SavePage(kTestUrl, kTestClientId1);
- int64_t offline1 = last_save_offline_id();
-
- OfflinePageTestStore* store = GetStore();
- GURL offline_url = store->last_saved_page().GetOfflineURL();
-
- SavePage(kTestUrl2, kTestClientId2);
-
- GURL offline_url2 = store->last_saved_page().GetOfflineURL();
- int64_t offline2 = last_save_offline_id();
-
- const OfflinePageItem* page = GetPageByOfflineURL(offline_url2);
- EXPECT_TRUE(page);
- EXPECT_EQ(kTestUrl2, page->url);
- EXPECT_EQ(kTestClientId2, page->client_id);
- EXPECT_EQ(offline2, page->offline_id);
-
- page = GetPageByOfflineURL(offline_url);
- EXPECT_TRUE(page);
- EXPECT_EQ(kTestUrl, page->url);
- EXPECT_EQ(kTestClientId1, page->client_id);
- EXPECT_EQ(offline1, page->offline_id);
-
- page = GetPageByOfflineURL(GURL("http://foo"));
- EXPECT_FALSE(page);
-}
-
TEST_F(OfflinePageModelImplTest, GetPagesByOnlineURL) {
SavePage(kTestUrl, kTestClientId1);
SavePage(kTestUrl2, kTestClientId2);
@@ -890,6 +893,27 @@ TEST_F(OfflinePageModelImplTest, GetPagesByOnlineURL) {
EXPECT_EQ(0U, pages.size());
}
+TEST_F(OfflinePageModelImplTest, GetPagesByOnlineURLWithFragment) {
+ SavePage(kTestUrl, kTestClientId1);
+ SavePage(kTestUrl2WithFragment, kTestClientId2);
+
+ MultipleOfflinePageItemResult pages =
+ GetPagesByOnlineURL(kTestUrlWithFragment);
+ EXPECT_EQ(1U, pages.size());
+ EXPECT_EQ(kTestUrl, pages[0].url);
+ EXPECT_EQ(kTestClientId1, pages[0].client_id);
+
+ pages = GetPagesByOnlineURL(kTestUrl2);
+ EXPECT_EQ(1U, pages.size());
+ EXPECT_EQ(kTestUrl2WithFragment, pages[0].url);
+ EXPECT_EQ(kTestClientId2, pages[0].client_id);
+
+ pages = GetPagesByOnlineURL(kTestUrl2WithFragment2);
+ EXPECT_EQ(1U, pages.size());
+ EXPECT_EQ(kTestUrl2WithFragment, pages[0].url);
+ EXPECT_EQ(kTestClientId2, pages[0].client_id);
+}
+
TEST_F(OfflinePageModelImplTest, CheckPagesExistOffline) {
SavePage(kTestUrl, kTestClientId1);
SavePage(kTestUrl2, kTestClientId2);
@@ -923,31 +947,6 @@ TEST_F(OfflinePageModelImplTest, CanSaveURL) {
EXPECT_FALSE(OfflinePageModel::CanSaveURL(GURL("/invalid/url.mhtml")));
}
-TEST_F(OfflinePageModelImplTest, ClearAll) {
- SavePage(kTestUrl, kTestClientId1);
- SavePage(kTestUrl2, kTestClientId2);
-
- const std::vector<OfflinePageItem>& offline_pages = GetAllPages();
- EXPECT_EQ(2UL, offline_pages.size());
- EXPECT_EQ(2UL, GetStore()->GetAllPages().size());
- base::FilePath archiver_path = offline_pages[0].file_path;
- EXPECT_TRUE(base::PathExists(archiver_path));
-
- // ClearAll should delete all the files and wipe out both cache and store.
- model()->ClearAll(
- base::Bind(&OfflinePageModelImplTest::OnClearAllDone, AsWeakPtr()));
- PumpLoop();
- EXPECT_EQ(0UL, GetAllPages().size());
- EXPECT_EQ(0UL, GetStore()->GetAllPages().size());
- EXPECT_FALSE(base::PathExists(archiver_path));
-
- // The model should reload the store after the reset. All model operations
- // should continue to work.
- SavePage(kTestUrl2, kTestClientId2);
- EXPECT_EQ(1UL, GetAllPages().size());
- EXPECT_EQ(1UL, GetStore()->GetAllPages().size());
-}
-
TEST_F(OfflinePageModelImplTest, SaveRetrieveMultipleClientIds) {
EXPECT_FALSE(HasPages(kTestClientNamespace));
SavePage(kTestUrl, kTestClientId1);
@@ -995,6 +994,48 @@ TEST_F(OfflinePageModelImplTest, SaveMultiplePagesWithSameURLBySameClientId) {
EXPECT_TRUE(id_set.find(offline2) != id_set.end());
}
+TEST_F(OfflinePageModelImplTest, DownloadMetrics) {
+ EXPECT_FALSE(HasPages(kUserRequestedNamespace));
+ SavePage(kTestUrl, kTestUserRequestedClientId);
+ histograms().ExpectUniqueSample(
+ "OfflinePages.DownloadSavedPageDuplicateCount", 1, 1);
+ FastForwardBy(base::TimeDelta::FromMinutes(1));
+ histograms().ExpectTotalCount(
+ "OfflinePages.DownloadSavedPageTimeSinceDuplicateSaved", 0);
+ SavePage(kTestUrl, kTestUserRequestedClientId);
+ histograms().ExpectTotalCount("OfflinePages.DownloadSavedPageDuplicateCount",
+ 2);
+ histograms().ExpectBucketCount("OfflinePages.DownloadSavedPageDuplicateCount",
+ 2, 1);
+ histograms().ExpectBucketCount("OfflinePages.DownloadSavedPageDuplicateCount",
+ 1, 1);
+ histograms().ExpectTotalCount(
+ "OfflinePages.DownloadSavedPageTimeSinceDuplicateSaved", 1);
+ histograms().ExpectTotalCount(
+ "OfflinePages.DownloadDeletedPageDuplicateCount", 0);
+
+ // void DeletePage(int64_t offline_id, const DeletePageCallback& callback) {
+ const std::vector<int64_t> ids =
+ GetOfflineIdsForClientId(kTestUserRequestedClientId);
+ ASSERT_EQ(2U, ids.size());
+
+ DeletePage(ids[0], base::Bind(&OfflinePageModelImplTest::OnDeletePageDone,
+ AsWeakPtr()));
+ PumpLoop();
+ histograms().ExpectUniqueSample(
+ "OfflinePages.DownloadDeletedPageDuplicateCount", 2, 1);
+ DeletePage(ids[1], base::Bind(&OfflinePageModelImplTest::OnDeletePageDone,
+ AsWeakPtr()));
+ PumpLoop();
+ // No change when we delete the last page.
+ histograms().ExpectTotalCount(
+ "OfflinePages.DownloadDeletedPageDuplicateCount", 2);
+ histograms().ExpectBucketCount(
+ "OfflinePages.DownloadDeletedPageDuplicateCount", 1, 1);
+ histograms().ExpectBucketCount(
+ "OfflinePages.DownloadDeletedPageDuplicateCount", 2, 1);
+}
+
TEST_F(OfflinePageModelImplTest, GetBestPage) {
// We will save 3 pages - two for the same URL, and one for a different URL.
// Correct behavior will pick the most recently saved page for the correct
@@ -1054,63 +1095,98 @@ TEST_F(OfflinePageModelImplTest, ExpirePages) {
EXPECT_TRUE(last_expire_page_result());
}
+TEST_F(OfflinePageModelImplTest, CustomTabsNamespace) {
+ SavePage(kTestUrl, ClientId(kCCTNamespace, "123"));
+ std::string histogram_name = "OfflinePages.SavePageResult.";
+ histogram_name += kCCTNamespace;
+
+ histograms().ExpectUniqueSample(histogram_name,
+ static_cast<int>(SavePageResult::SUCCESS), 1);
+}
+
+TEST_F(OfflinePageModelImplTest, DownloadNamespace) {
+ SavePage(kTestUrl, ClientId(kDownloadNamespace, "123"));
+ std::string histogram_name = "OfflinePages.SavePageResult.";
+ histogram_name += kDownloadNamespace;
+
+ histograms().ExpectUniqueSample(histogram_name,
+ static_cast<int>(SavePageResult::SUCCESS), 1);
+}
+
+TEST_F(OfflinePageModelImplTest, NewTabPageNamespace) {
+ SavePage(kTestUrl, ClientId(kNTPSuggestionsNamespace, "123"));
+ std::string histogram_name = "OfflinePages.SavePageResult.";
+ histogram_name += kNTPSuggestionsNamespace;
+
+ histograms().ExpectUniqueSample(histogram_name,
+ static_cast<int>(SavePageResult::SUCCESS), 1);
+}
+
TEST(CommandLineFlagsTest, OfflineBookmarks) {
// Disabled by default.
EXPECT_FALSE(offline_pages::IsOfflineBookmarksEnabled());
// Check if feature is correctly enabled by command-line flag.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- offline_pages::kOfflineBookmarksFeature.name, "");
- base::FeatureList::SetInstance(std::move(feature_list));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(kOfflineBookmarksFeature);
EXPECT_TRUE(offline_pages::IsOfflineBookmarksEnabled());
}
TEST(CommandLineFlagsTest, OffliningRecentPages) {
// Enable offline bookmarks feature first.
// TODO(dimich): once offline pages are enabled by default, remove this.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- offline_pages::kOfflineBookmarksFeature.name, "");
- base::FeatureList::SetInstance(std::move(feature_list));
+ std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list(
+ new base::test::ScopedFeatureList);
+ scoped_feature_list->InitAndEnableFeature(kOfflineBookmarksFeature);
// This feature is still disabled by default.
EXPECT_FALSE(offline_pages::IsOffliningRecentPagesEnabled());
// Check if feature is correctly enabled by command-line flag.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
- feature_list2->InitializeFromCommandLine(
- std::string(offline_pages::kOfflineBookmarksFeature.name) + "," +
- offline_pages::kOffliningRecentPagesFeature.name,
+ scoped_feature_list.reset(new base::test::ScopedFeatureList);
+ scoped_feature_list->InitFromCommandLine(
+ std::string(kOfflineBookmarksFeature.name) + "," +
+ kOffliningRecentPagesFeature.name,
"");
- base::FeatureList::SetInstance(std::move(feature_list2));
EXPECT_TRUE(offline_pages::IsOffliningRecentPagesEnabled());
}
TEST(CommandLineFlagsTest, OfflinePagesBackgroundLoading) {
// Enable offline bookmarks feature first.
// TODO(dimich): once offline pages are enabled by default, remove this.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- offline_pages::kOfflineBookmarksFeature.name, "");
- base::FeatureList::SetInstance(std::move(feature_list));
+ std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list(
+ new base::test::ScopedFeatureList);
+ scoped_feature_list->InitAndEnableFeature(kOfflineBookmarksFeature);
// This feature is still disabled by default.
EXPECT_FALSE(offline_pages::IsOfflinePagesBackgroundLoadingEnabled());
// Check if feature is correctly enabled by command-line flag.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
- feature_list2->InitializeFromCommandLine(
- std::string(offline_pages::kOfflineBookmarksFeature.name) + "," +
- offline_pages::kOfflinePagesBackgroundLoadingFeature.name,
+ scoped_feature_list.reset(new base::test::ScopedFeatureList);
+ scoped_feature_list->InitFromCommandLine(
+ std::string(kOfflineBookmarksFeature.name) + "," +
+ kOfflinePagesBackgroundLoadingFeature.name,
"");
- base::FeatureList::SetInstance(std::move(feature_list2));
EXPECT_TRUE(offline_pages::IsOfflinePagesBackgroundLoadingEnabled());
}
+TEST(CommandLineFlagsTest, OfflinePagesSharing) {
+ // Enable offline bookmarks feature first.
+ // TODO(dimich): once offline pages are enabled by default, remove this.
+ std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list(
+ new base::test::ScopedFeatureList);
+ scoped_feature_list->InitAndEnableFeature(kOfflineBookmarksFeature);
+
+ // This feature is still disabled by default.
+ EXPECT_FALSE(offline_pages::IsOfflinePagesSharingEnabled());
+
+ // Check if feature is correctly enabled by command-line flag.
+ scoped_feature_list.reset(new base::test::ScopedFeatureList);
+ scoped_feature_list->InitFromCommandLine(
+ std::string(kOfflineBookmarksFeature.name) + "," +
+ kOfflinePagesSharingFeature.name,
+ "");
+ EXPECT_TRUE(offline_pages::IsOfflinePagesSharingEnabled());
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/offline_page_storage_manager.cc b/chromium/components/offline_pages/offline_page_storage_manager.cc
index 4a23269e261..cc3fd4cd5b7 100644
--- a/chromium/components/offline_pages/offline_page_storage_manager.cc
+++ b/chromium/components/offline_pages/offline_page_storage_manager.cc
@@ -14,6 +14,8 @@
#include "components/offline_pages/offline_page_item.h"
#include "components/offline_pages/offline_page_model.h"
+using LifetimeType = offline_pages::LifetimePolicy::LifetimeType;
+
namespace offline_pages {
OfflinePageStorageManager::OfflinePageStorageManager(
@@ -108,6 +110,7 @@ void OfflinePageStorageManager::GetPageIdsToClear(
const ArchiveManager::StorageStats& stats,
std::vector<int64_t>* page_ids_to_expire,
std::vector<int64_t>* page_ids_to_remove) {
+ // TODO(romax): See how persistent should be considered here.
// Creating a map from namespace to a vector of page items.
// Sort each vector based on last accessed time and all pages after index
// min{size(), page_limit} should be expired. And then start iterating
@@ -200,7 +203,8 @@ bool OfflinePageStorageManager::ShouldBeExpired(
const OfflinePageItem& page) const {
const LifetimePolicy& policy =
policy_controller_->GetPolicy(page.client_id.name_space).lifetime_policy;
- return clear_time_ - page.last_access_time >= policy.expiration_period;
+ return policy.lifetime_type == LifetimeType::TEMPORARY &&
+ clear_time_ - page.last_access_time >= policy.expiration_period;
}
bool OfflinePageStorageManager::IsInProgress() const {
diff --git a/chromium/components/offline_pages/offline_page_storage_manager_unittest.cc b/chromium/components/offline_pages/offline_page_storage_manager_unittest.cc
index 75bda82b8fa..69c132525d9 100644
--- a/chromium/components/offline_pages/offline_page_storage_manager_unittest.cc
+++ b/chromium/components/offline_pages/offline_page_storage_manager_unittest.cc
@@ -300,6 +300,16 @@ TEST_F(OfflinePageStorageManagerTest, TestClearPagesMoreFreshPages) {
EXPECT_EQ(0, static_cast<int>(model()->GetRemovedPages().size()));
}
+TEST_F(OfflinePageStorageManagerTest, TestDeleteAsyncPages) {
+ Initialize(std::vector<PageSettings>({{kAsyncNamespace, 20, 0}}));
+ clock()->Advance(base::TimeDelta::FromDays(367));
+ TryClearPages();
+ EXPECT_EQ(0, last_cleared_page_count());
+ EXPECT_EQ(1, total_cleared_times());
+ EXPECT_EQ(ClearStorageResult::SUCCESS, last_clear_storage_result());
+ EXPECT_EQ(0, static_cast<int>(model()->GetRemovedPages().size()));
+}
+
TEST_F(OfflinePageStorageManagerTest, TestDeletionFailed) {
Initialize(std::vector<PageSettings>(
{{kBookmarkNamespace, 10, 10}, {kLastNNamespace, 10, 10}}),
@@ -376,8 +386,9 @@ TEST_F(OfflinePageStorageManagerTest, TestTwoStepExpiration) {
}
TEST_F(OfflinePageStorageManagerTest, TestClearMultipleTimes) {
- Initialize(std::vector<PageSettings>(
- {{kBookmarkNamespace, 30, 0}, {kLastNNamespace, 100, 1}}),
+ Initialize(std::vector<PageSettings>({{kBookmarkNamespace, 30, 0},
+ {kLastNNamespace, 100, 1},
+ {kAsyncNamespace, 40, 0}}),
{1000 * (1 << 20), 0});
clock()->Advance(base::TimeDelta::FromMinutes(30));
LifetimePolicy policy =
diff --git a/chromium/components/offline_pages/offline_page_test_archiver.cc b/chromium/components/offline_pages/offline_page_test_archiver.cc
index a4b73ee0f6b..8ee7f37cd2c 100644
--- a/chromium/components/offline_pages/offline_page_test_archiver.cc
+++ b/chromium/components/offline_pages/offline_page_test_archiver.cc
@@ -16,6 +16,7 @@ OfflinePageTestArchiver::OfflinePageTestArchiver(
Observer* observer,
const GURL& url,
ArchiverResult result,
+ const base::string16& result_title,
int64_t size_to_report,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
: observer_(observer),
@@ -24,6 +25,7 @@ OfflinePageTestArchiver::OfflinePageTestArchiver(
size_to_report_(size_to_report),
create_archive_called_(false),
delayed_(false),
+ result_title_(result_title),
task_runner_(task_runner) {}
OfflinePageTestArchiver::~OfflinePageTestArchiver() {
@@ -52,8 +54,9 @@ void OfflinePageTestArchiver::CompleteCreateArchive() {
base::File file(archive_path, base::File::FLAG_OPEN_ALWAYS);
}
observer_->SetLastPathCreatedByArchiver(archive_path);
- task_runner_->PostTask(FROM_HERE, base::Bind(callback_, this, result_, url_,
- archive_path, size_to_report_));
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(callback_, this, result_, url_, archive_path,
+ result_title_, size_to_report_));
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/offline_page_test_archiver.h b/chromium/components/offline_pages/offline_page_test_archiver.h
index bd985f43864..97ba2af7607 100644
--- a/chromium/components/offline_pages/offline_page_test_archiver.h
+++ b/chromium/components/offline_pages/offline_page_test_archiver.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
+#include "base/strings/string16.h"
#include "components/offline_pages/offline_page_archiver.h"
class GURL;
@@ -38,6 +39,7 @@ class OfflinePageTestArchiver : public OfflinePageArchiver {
Observer* observer,
const GURL& url,
ArchiverResult result,
+ const base::string16& result_title,
int64_t size_to_report,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
~OfflinePageTestArchiver() override;
@@ -72,6 +74,7 @@ class OfflinePageTestArchiver : public OfflinePageArchiver {
int64_t size_to_report_;
bool create_archive_called_;
bool delayed_;
+ base::string16 result_title_;
CreateArchiveCallback callback_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/chromium/components/offline_pages/offline_page_test_store.cc b/chromium/components/offline_pages/offline_page_test_store.cc
index 617387975cb..70b91c4e011 100644
--- a/chromium/components/offline_pages/offline_page_test_store.cc
+++ b/chromium/components/offline_pages/offline_page_test_store.cc
@@ -4,6 +4,8 @@
#include "components/offline_pages/offline_page_test_store.h"
+#include <map>
+
#include "base/bind.h"
#include "base/location.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,7 +24,7 @@ OfflinePageTestStore::OfflinePageTestStore(
OfflinePageTestStore::~OfflinePageTestStore() {}
-void OfflinePageTestStore::Load(const LoadCallback& callback) {
+void OfflinePageTestStore::GetOfflinePages(const LoadCallback& callback) {
OfflinePageMetadataStore::LoadStatus load_status;
if (scenario_ == TestScenario::LOAD_FAILED) {
load_status = OfflinePageMetadataStore::STORE_LOAD_FAILED;
@@ -34,33 +36,79 @@ void OfflinePageTestStore::Load(const LoadCallback& callback) {
base::Bind(callback, load_status, GetAllPages()));
}
-void OfflinePageTestStore::AddOrUpdateOfflinePage(
- const OfflinePageItem& offline_page,
- const UpdateCallback& callback) {
- last_saved_page_ = offline_page;
- bool result = scenario_ != TestScenario::WRITE_FAILED;
- if (result)
+void OfflinePageTestStore::AddOfflinePage(const OfflinePageItem& offline_page,
+ const AddCallback& callback) {
+ // TODO(fgorski): Add and cover scenario with existing item.
+ ItemActionStatus result;
+ if (scenario_ == TestScenario::SUCCESSFUL) {
offline_pages_[offline_page.offline_id] = offline_page;
+ last_saved_page_ = offline_page;
+ result = ItemActionStatus::SUCCESS;
+ } else if (scenario_ == TestScenario::WRITE_FAILED) {
+ result = ItemActionStatus::STORE_ERROR;
+ }
if (!callback.is_null())
task_runner_->PostTask(FROM_HERE, base::Bind(callback, result));
}
+void OfflinePageTestStore::UpdateOfflinePages(
+ const std::vector<OfflinePageItem>& pages,
+ const UpdateCallback& callback) {
+ // TODO(fgorski): Cover scenario where new items are being created while they
+ // shouldn't.
+ std::unique_ptr<OfflinePagesUpdateResult> result(
+ new OfflinePagesUpdateResult(StoreState::LOADED));
+ if (scenario_ == TestScenario::WRITE_FAILED) {
+ for (const auto& page : pages) {
+ result->item_statuses.push_back(
+ std::make_pair(page.offline_id, ItemActionStatus::STORE_ERROR));
+ }
+ } else {
+ for (const auto& page : pages) {
+ offline_pages_[page.offline_id] = page;
+ last_saved_page_ = page;
+ result->item_statuses.push_back(
+ std::make_pair(page.offline_id, ItemActionStatus::SUCCESS));
+ }
+ result->updated_items.insert(result->updated_items.begin(), pages.begin(),
+ pages.end());
+ }
+ if (!callback.is_null())
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(callback, base::Passed(&result)));
+}
+
void OfflinePageTestStore::RemoveOfflinePages(
const std::vector<int64_t>& offline_ids,
const UpdateCallback& callback) {
+ std::unique_ptr<OfflinePagesUpdateResult> result(
+ new OfflinePagesUpdateResult(StoreState::LOADED));
+
ASSERT_FALSE(offline_ids.empty());
- bool result = false;
- if (scenario_ != TestScenario::REMOVE_FAILED) {
+ if (scenario_ == TestScenario::REMOVE_FAILED) {
+ for (const auto& offline_id : offline_ids) {
+ result->item_statuses.push_back(
+ std::make_pair(offline_id, ItemActionStatus::STORE_ERROR));
+ }
+ // Anything different that LOADED is good here.
+ result->store_state = StoreState::FAILED_LOADING;
+ } else {
for (const auto& offline_id : offline_ids) {
auto iter = offline_pages_.find(offline_id);
+ ItemActionStatus status;
if (iter != offline_pages_.end()) {
+ result->updated_items.push_back(iter->second);
+ status = ItemActionStatus::SUCCESS;
offline_pages_.erase(iter);
- result = true;
+ } else {
+ status = ItemActionStatus::NOT_FOUND;
}
+ result->item_statuses.push_back(std::make_pair(offline_id, status));
}
}
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, result));
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(callback, base::Passed(&result)));
}
void OfflinePageTestStore::Reset(const ResetCallback& callback) {
@@ -68,6 +116,10 @@ void OfflinePageTestStore::Reset(const ResetCallback& callback) {
task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
}
+StoreState OfflinePageTestStore::state() const {
+ return StoreState::LOADED;
+}
+
void OfflinePageTestStore::UpdateLastAccessTime(
int64_t offline_id,
const base::Time& last_access_time) {
diff --git a/chromium/components/offline_pages/offline_page_test_store.h b/chromium/components/offline_pages/offline_page_test_store.h
index 42947eb6215..7464bdd15e0 100644
--- a/chromium/components/offline_pages/offline_page_test_store.h
+++ b/chromium/components/offline_pages/offline_page_test_store.h
@@ -36,12 +36,15 @@ class OfflinePageTestStore : public OfflinePageMetadataStore {
~OfflinePageTestStore() override;
// OfflinePageMetadataStore overrides:
- void Load(const LoadCallback& callback) override;
- void AddOrUpdateOfflinePage(const OfflinePageItem& offline_page,
- const UpdateCallback& callback) override;
+ void GetOfflinePages(const LoadCallback& callback) override;
+ void AddOfflinePage(const OfflinePageItem& offline_page,
+ const AddCallback& callback) override;
+ void UpdateOfflinePages(const std::vector<OfflinePageItem>& pages,
+ const UpdateCallback& callback) override;
void RemoveOfflinePages(const std::vector<int64_t>& offline_ids,
const UpdateCallback& callback) override;
void Reset(const ResetCallback& callback) override;
+ StoreState state() const override;
void UpdateLastAccessTime(int64_t offline_id,
const base::Time& last_access_time);
diff --git a/chromium/components/offline_pages/offline_page_types.h b/chromium/components/offline_pages/offline_page_types.h
index 20d0d998371..8dbfa3d3f62 100644
--- a/chromium/components/offline_pages/offline_page_types.h
+++ b/chromium/components/offline_pages/offline_page_types.h
@@ -57,13 +57,6 @@ enum class DeletePageResult {
RESULT_COUNT,
};
-// Result of loading all pages.
-enum class LoadResult {
- SUCCESS,
- CANCELLED,
- STORE_FAILURE,
-};
-
typedef std::set<GURL> CheckPagesExistOfflineResult;
typedef std::vector<int64_t> MultipleOfflineIdResult;
typedef std::vector<OfflinePageItem> MultipleOfflinePageItemResult;
diff --git a/chromium/components/offline_pages/offline_store_types.h b/chromium/components/offline_pages/offline_store_types.h
new file mode 100644
index 00000000000..9002c9d243f
--- /dev/null
+++ b/chromium/components/offline_pages/offline_store_types.h
@@ -0,0 +1,62 @@
+// 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 COMPONENTS_OFFLINE_PAGES_OFFLINE_STORE_TYPES_H_
+#define COMPONENTS_OFFLINE_PAGES_OFFLINE_STORE_TYPES_H_
+
+#include <stdint.h>
+
+#include <set>
+#include <utility>
+#include <vector>
+
+// This file contains common types and callbacks used by storage of various
+// offline page related components.
+namespace offline_pages {
+
+// TODO(fgorski): This enum is meant to replace |LoadStatus|.
+// Current store state. When LOADED, the store is operational. When
+// loading or reset fails, it is reflected appropriately.
+enum class StoreState {
+ NOT_LOADED, // Store is not loaded yet.
+ LOADED, // Store is properly loaded and operational.
+ FAILED_LOADING, // Store initialization failed.
+ FAILED_RESET, // Resetting the store failed.
+};
+
+// Statuses referring to actions taken on items in the stores.
+// GENERATED_JAVA_ENUM_PACKAGE:org.chromium.components.offlinepages
+enum class ItemActionStatus {
+ SUCCESS,
+ ALREADY_EXISTS,
+ NOT_FOUND,
+ STORE_ERROR,
+};
+
+// List of item action statuses mapped to item ID.
+typedef std::vector<std::pair<int64_t, ItemActionStatus>> MultipleItemStatuses;
+
+// Collective result for store update.
+template <typename T>
+class StoreUpdateResult {
+ public:
+ explicit StoreUpdateResult(StoreState state)
+ : store_state(state) {}
+ ~StoreUpdateResult() {}
+
+ // List of Offline ID to item action status mappings.
+ // It is meant to be consumed by the original caller of the operation.
+ MultipleItemStatuses item_statuses;
+
+ // List of successfully updated offline page items as seen after operation
+ // concludes. It is meant to be used when passing to the observers.
+ std::vector<T> updated_items;
+
+ // State of the store after the operation is done.
+ StoreState store_state;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_OFFLINE_STORE_TYPES_H_
diff --git a/chromium/components/offline_pages/request_header/BUILD.gn b/chromium/components/offline_pages/request_header/BUILD.gn
new file mode 100644
index 00000000000..711623cc348
--- /dev/null
+++ b/chromium/components/offline_pages/request_header/BUILD.gn
@@ -0,0 +1,32 @@
+# 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.
+
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
+static_library("request_header") {
+ sources = [
+ "offline_page_header.cc",
+ "offline_page_header.h",
+ ]
+
+ deps = [
+ "//base",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "offline_page_header_unittest.cc",
+ ]
+
+ deps = [
+ ":request_header",
+ "//base",
+ "//base/test:test_support",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/offline_pages/request_header/offline_page_header.cc b/chromium/components/offline_pages/request_header/offline_page_header.cc
new file mode 100644
index 00000000000..db7b7c9e56d
--- /dev/null
+++ b/chromium/components/offline_pages/request_header/offline_page_header.cc
@@ -0,0 +1,132 @@
+// 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 "components/offline_pages/request_header/offline_page_header.h"
+
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+
+namespace offline_pages {
+
+const char kOfflinePageHeader[] = "X-Chrome-offline";
+const char kOfflinePageHeaderReasonKey[] = "reason";
+const char kOfflinePageHeaderReasonValueDueToNetError[] = "error";
+const char kOfflinePageHeaderReasonValueFromDownload[] = "download";
+const char kOfflinePageHeaderReasonValueReload[] = "reload";
+const char kOfflinePageHeaderPersistKey[] = "persist";
+const char kOfflinePageHeaderIDKey[] = "id";
+
+namespace {
+
+bool ParseOfflineHeaderValue(const std::string& header_value,
+ bool* need_to_persist,
+ OfflinePageHeader::Reason* reason,
+ std::string* id) {
+ // If the offline header is not present, treat it as not parsed successfully.
+ if (header_value.empty())
+ return false;
+
+ bool token_found = false;
+ base::StringTokenizer tokenizer(header_value, ", ");
+ while (tokenizer.GetNext()) {
+ token_found = true;
+ std::string pair = tokenizer.token();
+ std::size_t pos = pair.find('=');
+ if (pos == std::string::npos)
+ return false;
+ std::string key = base::ToLowerASCII(pair.substr(0, pos));
+ std::string value = base::ToLowerASCII(pair.substr(pos + 1));
+ if (key == kOfflinePageHeaderPersistKey) {
+ if (value == "1")
+ *need_to_persist = true;
+ else if (value == "0")
+ *need_to_persist = false;
+ else
+ return false;
+ } else if (key == kOfflinePageHeaderReasonKey) {
+ if (value == kOfflinePageHeaderReasonValueDueToNetError)
+ *reason = OfflinePageHeader::Reason::NET_ERROR;
+ else if (value == kOfflinePageHeaderReasonValueFromDownload)
+ *reason = OfflinePageHeader::Reason::DOWNLOAD;
+ else if (value == kOfflinePageHeaderReasonValueReload)
+ *reason = OfflinePageHeader::Reason::RELOAD;
+ else
+ return false;
+ } else if (key == kOfflinePageHeaderIDKey) {
+ *id = value;
+ } else {
+ return false;
+ }
+ }
+
+ return token_found;
+}
+
+std::string ReasonToString(OfflinePageHeader::Reason reason) {
+ switch (reason) {
+ case OfflinePageHeader::Reason::NET_ERROR:
+ return kOfflinePageHeaderReasonValueDueToNetError;
+ case OfflinePageHeader::Reason::DOWNLOAD:
+ return kOfflinePageHeaderReasonValueFromDownload;
+ case OfflinePageHeader::Reason::RELOAD:
+ return kOfflinePageHeaderReasonValueReload;
+ default:
+ NOTREACHED();
+ return "";
+ }
+}
+
+} // namespace
+
+OfflinePageHeader::OfflinePageHeader()
+ : did_fail_parsing_for_test(false),
+ need_to_persist(false),
+ reason(Reason::NONE) {
+}
+
+OfflinePageHeader::OfflinePageHeader(const std::string& header_value)
+ : did_fail_parsing_for_test(false),
+ need_to_persist(false),
+ reason(Reason::NONE) {
+ if (!ParseOfflineHeaderValue(header_value, &need_to_persist, &reason, &id)) {
+ did_fail_parsing_for_test = true;
+ Clear();
+ }
+}
+
+OfflinePageHeader::~OfflinePageHeader() {}
+
+std::string OfflinePageHeader::GetCompleteHeaderString() const {
+ if (reason == Reason::NONE)
+ return std::string();
+
+ std::string value(kOfflinePageHeader);
+ value += ": ";
+
+ value += kOfflinePageHeaderPersistKey;
+ value += "=";
+ value += need_to_persist ? "1" : "0";
+
+ value += " " ;
+ value += kOfflinePageHeaderReasonKey;
+ value += "=";
+ value += ReasonToString(reason);
+
+ if (!id.empty()) {
+ value += " " ;
+ value += kOfflinePageHeaderIDKey;
+ value += "=";
+ value += id;
+ }
+
+ return value;
+}
+
+void OfflinePageHeader::Clear() {
+ reason = Reason::NONE;
+ need_to_persist = false;
+ id.clear();
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/request_header/offline_page_header.h b/chromium/components/offline_pages/request_header/offline_page_header.h
new file mode 100644
index 00000000000..370fe667817
--- /dev/null
+++ b/chromium/components/offline_pages/request_header/offline_page_header.h
@@ -0,0 +1,80 @@
+// 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 COMPONENTS_OFFLINE_PAGES_REQUEST_HEADER_OFFLINE_PAGE_HEADER_H_
+#define COMPONENTS_OFFLINE_PAGES_REQUEST_HEADER_OFFLINE_PAGE_HEADER_H_
+
+#include <string>
+
+namespace offline_pages {
+
+// Header that defines the custom behavior to load offline pages. Its value is a
+// comma/space separated name-value pair.
+extern const char kOfflinePageHeader[];
+
+// The name used in name-value pair of kOfflinePageHeader to tell if the offline
+// info in this header should be persisted across session restore.
+extern const char kOfflinePageHeaderPersistKey[];
+
+// The name used in name-value pair of kOfflinePageHeader to denote the reason
+// for loading offline page.
+extern const char kOfflinePageHeaderReasonKey[];
+// Possible values in name-value pair that denote the reason for loading offline
+// page.
+// The offline page should be loaded even when the network is connected. This is
+// because the live version failed to load due to certain net error.
+extern const char kOfflinePageHeaderReasonValueDueToNetError[];
+// The offline page should be loaded because the user clicks to open the
+// downloaded page explicitly.
+extern const char kOfflinePageHeaderReasonValueFromDownload[];
+// This only happens after the offline page is loaded due to above reason and
+// then the user reload current page. The network condition should be checked
+// this time to decide if a live version should be tried again.
+extern const char kOfflinePageHeaderReasonValueReload[];
+
+// The name used in name-value pair of kOfflinePageHeader to denote the offline
+// ID of the offline page to load.
+extern const char kOfflinePageHeaderIDKey[];
+
+// Used to parse the extra request header string that defines offline page
+// loading behaviors.
+struct OfflinePageHeader {
+ public:
+ enum class Reason {
+ NONE,
+ NET_ERROR,
+ DOWNLOAD,
+ RELOAD
+ };
+
+ OfflinePageHeader();
+
+ // Constructed from a request header value string.
+ // The struct members will be cleared if the parsing failed.
+ explicit OfflinePageHeader(const std::string& header_value);
+
+ ~OfflinePageHeader();
+
+ // Returns the full header string, including both key and value, that could be
+ // passed to set extra request header.
+ std::string GetCompleteHeaderString() const;
+
+ void Clear();
+
+ // Set if failed to parse a request header value string. For testing only.
+ bool did_fail_parsing_for_test;
+
+ // Flag to indicate if the header should be persisted across session restore.
+ bool need_to_persist;
+
+ // Describes the reason to load offline page.
+ Reason reason;
+
+ // The offline ID of the page to load.
+ std::string id;
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_REQUEST_HEADER_OFFLINE_PAGE_HEADER_H_
diff --git a/chromium/components/offline_pages/request_header/offline_page_header_unittest.cc b/chromium/components/offline_pages/request_header/offline_page_header_unittest.cc
new file mode 100644
index 00000000000..744a66f66f5
--- /dev/null
+++ b/chromium/components/offline_pages/request_header/offline_page_header_unittest.cc
@@ -0,0 +1,82 @@
+// 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 "components/offline_pages/request_header/offline_page_header.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+
+class OfflinePageHeaderTest : public testing::Test {
+ public:
+ OfflinePageHeaderTest() {}
+ ~OfflinePageHeaderTest() override {}
+
+ bool ParseFromHeaderValue(const std::string& header_value,
+ bool* need_to_persist,
+ OfflinePageHeader::Reason* reason,
+ std::string* id) {
+ OfflinePageHeader header(header_value);
+ *need_to_persist = header.need_to_persist;
+ *reason = header.reason;
+ *id = header.id;
+ return !header.did_fail_parsing_for_test;
+ }
+};
+
+TEST_F(OfflinePageHeaderTest, Parse) {
+ bool need_to_persist;
+ OfflinePageHeader::Reason reason;
+ std::string id;
+
+ EXPECT_FALSE(ParseFromHeaderValue("", &need_to_persist, &reason, &id));
+ EXPECT_FALSE(ParseFromHeaderValue(" ", &need_to_persist, &reason, &id));
+ EXPECT_FALSE(ParseFromHeaderValue(" , ", &need_to_persist, &reason, &id));
+ EXPECT_FALSE(ParseFromHeaderValue("reason", &need_to_persist, &reason, &id));
+ EXPECT_FALSE(ParseFromHeaderValue("a b c", &need_to_persist, &reason, &id));
+
+ EXPECT_FALSE(
+ ParseFromHeaderValue("persist=aa", &need_to_persist, &reason, &id));
+
+ EXPECT_TRUE(
+ ParseFromHeaderValue("persist=1", &need_to_persist, &reason, &id));
+ EXPECT_TRUE(need_to_persist);
+
+ EXPECT_TRUE(
+ ParseFromHeaderValue("persist=0", &need_to_persist, &reason, &id));
+ EXPECT_FALSE(need_to_persist);
+ EXPECT_EQ(OfflinePageHeader::Reason::NONE, reason);
+ EXPECT_EQ("", id);
+
+ EXPECT_FALSE(
+ ParseFromHeaderValue("reason=foo", &need_to_persist, &reason, &id));
+
+ EXPECT_TRUE(
+ ParseFromHeaderValue("reason=error", &need_to_persist, &reason, &id));
+ EXPECT_FALSE(need_to_persist);
+ EXPECT_EQ(OfflinePageHeader::Reason::NET_ERROR, reason);
+ EXPECT_EQ("", id);
+
+ EXPECT_TRUE(ParseFromHeaderValue("id=a1b2", &need_to_persist, &reason, &id));
+ EXPECT_FALSE(need_to_persist);
+ EXPECT_EQ(OfflinePageHeader::Reason::NONE, reason);
+ EXPECT_EQ("a1b2", id);
+
+ EXPECT_TRUE(ParseFromHeaderValue("persist=1 reason=download id=a1b2",
+ &need_to_persist, &reason, &id));
+ EXPECT_TRUE(need_to_persist);
+ EXPECT_EQ(OfflinePageHeader::Reason::DOWNLOAD, reason);
+ EXPECT_EQ("a1b2", id);
+}
+
+TEST_F(OfflinePageHeaderTest, ToString) {
+ OfflinePageHeader header;
+ header.need_to_persist = true;
+ header.reason = OfflinePageHeader::Reason::DOWNLOAD;
+ header.id = "a1b2";
+ EXPECT_EQ("X-Chrome-offline: persist=1 reason=download id=a1b2",
+ header.GetCompleteHeaderString());
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/stub_offline_page_model.cc b/chromium/components/offline_pages/stub_offline_page_model.cc
index 3c17ad31493..aff22ddd092 100644
--- a/chromium/components/offline_pages/stub_offline_page_model.cc
+++ b/chromium/components/offline_pages/stub_offline_page_model.cc
@@ -14,23 +14,23 @@ void StubOfflinePageModel::RemoveObserver(Observer* observer) {}
void StubOfflinePageModel::SavePage(
const GURL& url,
const ClientId& client_id,
+ int64_t proposed_offline_id,
std::unique_ptr<OfflinePageArchiver> archiver,
const SavePageCallback& callback) {}
void StubOfflinePageModel::MarkPageAccessed(int64_t offline_id) {}
-void StubOfflinePageModel::ClearAll(const base::Closure& callback) {}
void StubOfflinePageModel::DeletePagesByOfflineId(
const std::vector<int64_t>& offline_ids,
const DeletePageCallback& callback) {}
-void StubOfflinePageModel::DeletePagesByURLPredicate(
+void StubOfflinePageModel::DeleteCachedPagesByURLPredicate(
const UrlPredicate& predicate,
const DeletePageCallback& callback) {}
-void StubOfflinePageModel::HasPages(const std::string& name_space,
- const HasPagesCallback& callback) {}
void StubOfflinePageModel::CheckPagesExistOffline(
const std::set<GURL>& urls,
const CheckPagesExistOfflineCallback& callback) {}
void StubOfflinePageModel::GetAllPages(
const MultipleOfflinePageItemCallback& callback) {}
+void StubOfflinePageModel::GetAllPagesWithExpired(
+ const MultipleOfflinePageItemCallback& callback) {}
void StubOfflinePageModel::GetOfflineIdsForClientId(
const ClientId& client_id,
const MultipleOfflineIdCallback& callback) {}
@@ -46,24 +46,13 @@ const OfflinePageItem* StubOfflinePageModel::MaybeGetPageByOfflineId(
int64_t offline_id) const {
return nullptr;
}
-void StubOfflinePageModel::GetPageByOfflineURL(
- const GURL& offline_url,
- const SingleOfflinePageItemCallback& callback) {}
-const OfflinePageItem* StubOfflinePageModel::MaybeGetPageByOfflineURL(
- const GURL& offline_url) const {
- return nullptr;
-}
void StubOfflinePageModel::GetPagesByOnlineURL(
const GURL& online_url,
const MultipleOfflinePageItemCallback& callback) {}
-void StubOfflinePageModel::GetBestPageForOnlineURL(
- const GURL& online_url,
- const SingleOfflinePageItemCallback callback) {}
const OfflinePageItem* StubOfflinePageModel::MaybeGetBestPageForOnlineURL(
const GURL& online_url) const {
return nullptr;
}
-void StubOfflinePageModel::CheckMetadataConsistency() {}
void StubOfflinePageModel::ExpirePages(
const std::vector<int64_t>& offline_ids,
const base::Time& expiration_time,
diff --git a/chromium/components/offline_pages/stub_offline_page_model.h b/chromium/components/offline_pages/stub_offline_page_model.h
index c851588349e..09925f8af08 100644
--- a/chromium/components/offline_pages/stub_offline_page_model.h
+++ b/chromium/components/offline_pages/stub_offline_page_model.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "components/keyed_service/core/keyed_service.h"
#include "components/offline_pages/offline_page_model.h"
namespace offline_pages {
@@ -16,7 +17,7 @@ namespace offline_pages {
// Stub implementation of OfflinePageModel interface for testing. Besides using
// as a stub for tests, it may also be subclassed to mock specific methods
// needed for a set of tests.
-class StubOfflinePageModel : public OfflinePageModel {
+class StubOfflinePageModel : public OfflinePageModel, public KeyedService {
public:
StubOfflinePageModel();
~StubOfflinePageModel() override;
@@ -25,20 +26,21 @@ class StubOfflinePageModel : public OfflinePageModel {
void RemoveObserver(Observer* observer) override;
void SavePage(const GURL& url,
const ClientId& client_id,
+ int64_t proposed_offline_id,
std::unique_ptr<OfflinePageArchiver> archiver,
const SavePageCallback& callback) override;
void MarkPageAccessed(int64_t offline_id) override;
- void ClearAll(const base::Closure& callback) override;
void DeletePagesByOfflineId(const std::vector<int64_t>& offline_ids,
const DeletePageCallback& callback) override;
- void DeletePagesByURLPredicate(const UrlPredicate& predicate,
- const DeletePageCallback& callback) override;
- void HasPages(const std::string& name_space,
- const HasPagesCallback& callback) override;
+ void DeleteCachedPagesByURLPredicate(
+ const UrlPredicate& predicate,
+ const DeletePageCallback& callback) override;
void CheckPagesExistOffline(
const std::set<GURL>& urls,
const CheckPagesExistOfflineCallback& callback) override;
void GetAllPages(const MultipleOfflinePageItemCallback& callback) override;
+ void GetAllPagesWithExpired(
+ const MultipleOfflinePageItemCallback& callback) override;
void GetOfflineIdsForClientId(
const ClientId& client_id,
const MultipleOfflineIdCallback& callback) override;
@@ -49,20 +51,11 @@ class StubOfflinePageModel : public OfflinePageModel {
const SingleOfflinePageItemCallback& callback) override;
const OfflinePageItem* MaybeGetPageByOfflineId(
int64_t offline_id) const override;
- void GetPageByOfflineURL(
- const GURL& offline_url,
- const SingleOfflinePageItemCallback& callback) override;
- const OfflinePageItem* MaybeGetPageByOfflineURL(
- const GURL& offline_url) const override;
void GetPagesByOnlineURL(
const GURL& online_url,
const MultipleOfflinePageItemCallback& callback) override;
- void GetBestPageForOnlineURL(
- const GURL& online_url,
- const SingleOfflinePageItemCallback callback) override;
const OfflinePageItem* MaybeGetBestPageForOnlineURL(
const GURL& online_url) const override;
- void CheckMetadataConsistency() override;
void ExpirePages(const std::vector<int64_t>& offline_ids,
const base::Time& expiration_time,
const base::Callback<void(bool)>& callback) override;
diff --git a/chromium/components/omnibox.gypi b/chromium/components/omnibox.gypi
deleted file mode 100644
index 78dd7929315..00000000000
--- a/chromium/components/omnibox.gypi
+++ /dev/null
@@ -1,222 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/omnibox/browser
- 'target_name': 'omnibox_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../sql/sql.gyp:sql',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/gfx.gyp:gfx_vector_icons',
- '../url/url.gyp:url_lib',
- 'bookmarks_browser',
- 'metrics',
- 'component_metrics_proto',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- 'data_use_measurement_core',
- 'history_core_browser',
- 'keyed_service_core',
- 'omnibox_common',
- 'omnibox_in_memory_url_index_cache_proto',
- 'open_from_clipboard',
- 'pref_registry',
- 'query_parser',
- 'search',
- 'search_engines',
- 'toolbar',
- 'url_formatter/url_formatter.gyp:url_formatter',
- 'variations_net',
- ],
- 'export_dependent_settings': [
- 'component_metrics_proto',
- 'history_core_browser',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'omnibox/browser/answers_cache.cc',
- 'omnibox/browser/answers_cache.h',
- 'omnibox/browser/autocomplete_classifier.cc',
- 'omnibox/browser/autocomplete_classifier.h',
- 'omnibox/browser/autocomplete_controller.cc',
- 'omnibox/browser/autocomplete_controller.h',
- 'omnibox/browser/autocomplete_controller_delegate.h',
- 'omnibox/browser/autocomplete_input.cc',
- 'omnibox/browser/autocomplete_input.h',
- 'omnibox/browser/autocomplete_match.cc',
- 'omnibox/browser/autocomplete_match.h',
- 'omnibox/browser/autocomplete_match_type.cc',
- 'omnibox/browser/autocomplete_match_type.h',
- 'omnibox/browser/autocomplete_provider.cc',
- 'omnibox/browser/autocomplete_provider.h',
- 'omnibox/browser/autocomplete_provider_client.h',
- 'omnibox/browser/autocomplete_provider_listener.h',
- 'omnibox/browser/autocomplete_result.cc',
- 'omnibox/browser/autocomplete_result.h',
- 'omnibox/browser/autocomplete_scheme_classifier.h',
- 'omnibox/browser/base_search_provider.cc',
- 'omnibox/browser/base_search_provider.h',
- 'omnibox/browser/bookmark_provider.cc',
- 'omnibox/browser/bookmark_provider.h',
- 'omnibox/browser/builtin_provider.cc',
- 'omnibox/browser/builtin_provider.h',
- 'omnibox/browser/clipboard_url_provider.cc',
- 'omnibox/browser/clipboard_url_provider.h',
- 'omnibox/browser/history_provider.cc',
- 'omnibox/browser/history_provider.h',
- 'omnibox/browser/history_quick_provider.cc',
- 'omnibox/browser/history_quick_provider.h',
- 'omnibox/browser/history_url_provider.cc',
- 'omnibox/browser/history_url_provider.h',
- 'omnibox/browser/in_memory_url_index.cc',
- 'omnibox/browser/in_memory_url_index.h',
- 'omnibox/browser/in_memory_url_index_types.cc',
- 'omnibox/browser/in_memory_url_index_types.h',
- 'omnibox/browser/keyword_extensions_delegate.cc',
- 'omnibox/browser/keyword_extensions_delegate.h',
- 'omnibox/browser/keyword_provider.cc',
- 'omnibox/browser/keyword_provider.h',
- 'omnibox/browser/match_compare.h',
- 'omnibox/browser/omnibox_client.h',
- 'omnibox/browser/omnibox_controller.cc',
- 'omnibox/browser/omnibox_controller.h',
- 'omnibox/browser/omnibox_edit_controller.cc',
- 'omnibox/browser/omnibox_edit_controller.h',
- 'omnibox/browser/omnibox_edit_model.cc',
- 'omnibox/browser/omnibox_edit_model.h',
- 'omnibox/browser/omnibox_event_global_tracker.cc',
- 'omnibox/browser/omnibox_event_global_tracker.h',
- 'omnibox/browser/omnibox_field_trial.cc',
- 'omnibox/browser/omnibox_field_trial.h',
- 'omnibox/browser/omnibox_log.cc',
- 'omnibox/browser/omnibox_log.h',
- 'omnibox/browser/omnibox_metrics_provider.cc',
- 'omnibox/browser/omnibox_metrics_provider.h',
- 'omnibox/browser/omnibox_navigation_observer.h',
- 'omnibox/browser/omnibox_popup_model.cc',
- 'omnibox/browser/omnibox_popup_model.h',
- 'omnibox/browser/omnibox_popup_model_observer.h',
- 'omnibox/browser/omnibox_popup_view.h',
- 'omnibox/browser/omnibox_pref_names.cc',
- 'omnibox/browser/omnibox_pref_names.h',
- 'omnibox/browser/omnibox_switches.cc',
- 'omnibox/browser/omnibox_switches.h',
- 'omnibox/browser/omnibox_view.cc',
- 'omnibox/browser/omnibox_view.h',
- 'omnibox/browser/scored_history_match.cc',
- 'omnibox/browser/scored_history_match.h',
- 'omnibox/browser/search_provider.cc',
- 'omnibox/browser/search_provider.h',
- 'omnibox/browser/search_suggestion_parser.cc',
- 'omnibox/browser/search_suggestion_parser.h',
- 'omnibox/browser/shortcuts_backend.cc',
- 'omnibox/browser/shortcuts_backend.h',
- 'omnibox/browser/shortcuts_constants.cc',
- 'omnibox/browser/shortcuts_constants.h',
- 'omnibox/browser/shortcuts_database.cc',
- 'omnibox/browser/shortcuts_database.h',
- 'omnibox/browser/shortcuts_provider.cc',
- 'omnibox/browser/shortcuts_provider.h',
- 'omnibox/browser/suggestion_answer.cc',
- 'omnibox/browser/suggestion_answer.h',
- 'omnibox/browser/url_index_private_data.cc',
- 'omnibox/browser/url_index_private_data.h',
- 'omnibox/browser/url_prefix.cc',
- 'omnibox/browser/url_prefix.h',
- 'omnibox/browser/verbatim_match.cc',
- 'omnibox/browser/verbatim_match.h',
- 'omnibox/browser/zero_suggest_provider.cc',
- 'omnibox/browser/zero_suggest_provider.h',
- ],
- },
- {
- # GN version: //components/omnibox/common
- 'target_name': 'omnibox_common',
- 'type': 'none',
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'omnibox/common/omnibox_focus_state.h',
- ],
- },
- {
- # Protobuf compiler / generator for the InMemoryURLIndex caching
- # protocol buffer.
- # GN version: //components/omnibox:in_memory_url_index_cache_proto
- 'target_name': 'omnibox_in_memory_url_index_cache_proto',
- 'type': 'static_library',
- 'sources': [ 'omnibox/browser/in_memory_url_index_cache.proto', ],
- 'variables': {
- 'proto_in_dir': 'omnibox/browser',
- 'proto_out_dir': 'components/omnibox/browser',
- },
- 'includes': [ '../build/protoc.gypi', ],
- },
- {
- # GN version: //components/omnibox:test_support
- 'target_name': 'omnibox_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../testing/gmock.gyp:gmock',
- 'omnibox_browser',
- 'component_metrics_proto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'omnibox/browser/history_index_restore_observer.cc',
- 'omnibox/browser/history_index_restore_observer.h',
- 'omnibox/browser/in_memory_url_index_test_util.cc',
- 'omnibox/browser/in_memory_url_index_test_util.h',
- 'omnibox/browser/mock_autocomplete_provider_client.cc',
- 'omnibox/browser/mock_autocomplete_provider_client.h',
- 'omnibox/browser/shortcuts_provider_test_util.cc',
- 'omnibox/browser/shortcuts_provider_test_util.h',
- 'omnibox/browser/test_scheme_classifier.cc',
- 'omnibox/browser/test_scheme_classifier.h',
- ],
- },
- ],
- 'conditions': [
- ['OS == "android"', {
- 'targets': [
- {
- # GN: //components/omnibox:autocomplete_match_javagen
- 'target_name': 'autocomplete_match_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'omnibox/browser/autocomplete_match.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- # GN: //components/omnibox:autocomplete_match_type_javagen
- 'target_name': 'autocomplete_match_type_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'omnibox/browser/autocomplete_match_type.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/omnibox/browser/BUILD.gn b/chromium/components/omnibox/browser/BUILD.gn
index c5d59b1c643..91cb430d941 100644
--- a/chromium/components/omnibox/browser/BUILD.gn
+++ b/chromium/components/omnibox/browser/BUILD.gn
@@ -8,7 +8,7 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-source_set("browser") {
+static_library("browser") {
sources = [
"answers_cache.cc",
"answers_cache.h",
@@ -77,6 +77,8 @@ source_set("browser") {
"omnibox_switches.h",
"omnibox_view.cc",
"omnibox_view.h",
+ "physical_web_provider.cc",
+ "physical_web_provider.h",
"scored_history_match.cc",
"scored_history_match.h",
"search_provider.cc",
@@ -117,6 +119,7 @@ source_set("browser") {
"//components/keyed_service/core",
"//components/metrics",
"//components/open_from_clipboard",
+ "//components/physical_web/data_source",
"//components/pref_registry",
"//components/prefs",
"//components/query_parser",
@@ -143,14 +146,12 @@ source_set("browser") {
}
if (is_android) {
- # GYP: //component/omnibox.gypi:autocomplete_match_java
java_cpp_enum("autocomplete_match_javagen") {
sources = [
"autocomplete_match.h",
]
}
- # GYP: //component/omnibox.gypi:autocomplete_match_type_java
java_cpp_enum("autocomplete_match_type_javagen") {
sources = [
"autocomplete_match_type.h",
@@ -227,6 +228,7 @@ source_set("unit_tests") {
"omnibox_field_trial_unittest.cc",
"omnibox_popup_model_unittest.cc",
"omnibox_view_unittest.cc",
+ "physical_web_provider_unittest.cc",
"scored_history_match_unittest.cc",
"shortcuts_backend_unittest.cc",
"shortcuts_database_unittest.cc",
@@ -246,10 +248,12 @@ source_set("unit_tests") {
"//components/bookmarks/test",
"//components/history/core/test",
"//components/open_from_clipboard:test_support",
+ "//components/physical_web/data_source",
"//components/prefs:test_support",
"//components/search",
"//components/search_engines",
"//components/sessions",
+ "//components/strings",
"//components/toolbar:test_support",
"//components/url_formatter",
"//components/variations",
diff --git a/chromium/components/omnibox_strings.grdp b/chromium/components/omnibox_strings.grdp
index 8e9c7d2b403..a5d080db523 100644
--- a/chromium/components/omnibox_strings.grdp
+++ b/chromium/components/omnibox_strings.grdp
@@ -13,9 +13,28 @@
<message name="IDS_SECURE_CONNECTION_EV" desc="Short text shown in the location bar when the connection is secure with an EV cert.">
<ph name="ORGANIZATION">$1<ex>Paypal Inc.</ex></ph> [<ph name="COUNTRY">$2<ex>US</ex></ph>]
</message>
+
+ <message name="IDS_SECURE_VERBOSE_STATE" desc="An adjective or short adjective phrase shown next to the green lock icon in the omnibox to describe a secure site (valid HTTPS connection). Note that 'secure' in this case primarily refers to HTTPS connection security, so prefer translations with a connotation of 'private' (no one can intercept your communication with the site) rather than 'trustworthy' (which would be a judgment of site reputation). This phrase takes away space from the URL in the omnibox, so it should ideally be as short as possible while staying accurate. This phrase should also make sense compared to the companion phrase 'Not Secure'." meaning="Omnibox phrase to describe a secure site.">
+ Secure
+ </message>
+ <message name="IDS_NOT_SECURE_VERBOSE_STATE" desc="An adjective or short adjective phrase shown next to the security indicator icon in the omnibox to describe a site that is not secure (unencrypted HTTP or invalid HTTPS connection). Note that 'not secure' in this case primarily refers to HTTPS connection security, so prefer translations with a connotation of 'not private' (someone can intercept your communication with the site) rather than 'not trustworthy' (which would be a judgment of site reputation). This phrase takes away space from the URL in the omnibox, so it should ideally be as short as possible while staying accurate. This phrase should also make sense compared to the companion phrase 'Secure'." meaning="Omnibox phrase to describe a site that is not secure.">
+ Not Secure
+ </message>
+ <message name="IDS_DANGEROUS_VERBOSE_STATE" desc="Text for the Dangerous Omnibox Verbose State. Displayed when the current page fails the malware check.">
+ Dangerous
+ </message>
<if expr="is_ios">
<message name="IDS_OMNIBOX_EMPTY_HINT" desc="The text displayed in the omnibox when it is empty.">
Search or type URL
</message>
</if>
+ <message name="IDS_PHYSICAL_WEB_OVERFLOW_DESCRIPTION" desc="The description in the omnibox dropdown indicating that multiple nearby devices are broadcasting URLs.">
+ Physical Web suggestions
+ </message>
+ <message name="IDS_PHYSICAL_WEB_OVERFLOW" desc="A label in the omnibox dropdown indicating the number of additional nearby devices broadcasting URLs.">
+ {URL_count, plural, =1 {and 1 more web page} other {and # more web pages}}
+ </message>
+ <message name="IDS_PHYSICAL_WEB_OVERFLOW_EMPTY_TITLE" desc="A label in the omnibox dropdown indicating the number of additional nearby devices broadcasting URLs. This version is used when the title of the top result is empty.">
+ {URL_count, plural, =1 {1 web page nearby} other {# web pages nearby}}
+ </message>
</grit-part>
diff --git a/chromium/components/onc.gypi b/chromium/components/onc.gypi
deleted file mode 100644
index 5d1a5a0e93c..00000000000
--- a/chromium/components/onc.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/onc
- 'target_name': 'onc_component',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'ONC_IMPLEMENTATION',
- ],
- 'sources': [
- 'onc/onc_constants.cc',
- 'onc/onc_constants.h',
- 'onc/onc_export.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/onc/BUILD.gn b/chromium/components/onc/BUILD.gn
index 04e3564ae09..f0822332870 100644
--- a/chromium/components/onc/BUILD.gn
+++ b/chromium/components/onc/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/onc.gypi:onc_component
component("onc") {
sources = [
"onc_constants.cc",
diff --git a/chromium/components/open_from_clipboard.gypi b/chromium/components/open_from_clipboard.gypi
deleted file mode 100644
index d9901477b4c..00000000000
--- a/chromium/components/open_from_clipboard.gypi
+++ /dev/null
@@ -1,43 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/open_from_clipboard
- 'target_name': 'open_from_clipboard',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'open_from_clipboard/clipboard_recent_content.cc',
- 'open_from_clipboard/clipboard_recent_content.h',
- 'open_from_clipboard/clipboard_recent_content_ios.h',
- 'open_from_clipboard/clipboard_recent_content_ios.mm',
- ],
- },
- {
- # GN version: //components/open_from_clipboard:test_support
- 'target_name': 'open_from_clipboard_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'open_from_clipboard',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'open_from_clipboard/fake_clipboard_recent_content.cc',
- 'open_from_clipboard/fake_clipboard_recent_content.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/open_from_clipboard/BUILD.gn b/chromium/components/open_from_clipboard/BUILD.gn
index adb5aa18fd3..fe46837a69a 100644
--- a/chromium/components/open_from_clipboard/BUILD.gn
+++ b/chromium/components/open_from_clipboard/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("open_from_clipboard") {
+static_library("open_from_clipboard") {
sources = [
"clipboard_recent_content.cc",
"clipboard_recent_content.h",
@@ -16,7 +16,7 @@ source_set("open_from_clipboard") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"fake_clipboard_recent_content.cc",
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content.h b/chromium/components/open_from_clipboard/clipboard_recent_content.h
index 2aee470615d..46e3449c305 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content.h
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content.h
@@ -31,10 +31,7 @@ class ClipboardRecentContent {
// Returns true if the clipboard contains a recent URL that has not been
// supressed, and copies it in |url|. Otherwise, returns false. |url| must not
// be null.
- virtual bool GetRecentURLFromClipboard(GURL* url) const = 0;
-
- // Reports that the URL contained in the pasteboard was displayed.
- virtual void RecentURLDisplayed() = 0;
+ virtual bool GetRecentURLFromClipboard(GURL* url) = 0;
// Returns how old the content of the clipboard is.
virtual base::TimeDelta GetClipboardContentAge() const = 0;
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_ios.h b/chromium/components/open_from_clipboard/clipboard_recent_content_ios.h
index 19e40ed975d..d4b7d7ec831 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content_ios.h
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_ios.h
@@ -13,7 +13,7 @@
@class NSDate;
@class NSUserDefaults;
-@class PasteboardNotificationListenerBridge;
+@class ApplicationDidBecomeActiveNotificationListenerBridge;
class ClipboardRecentContentIOSTest;
@@ -30,39 +30,29 @@ class ClipboardRecentContentIOS : public ClipboardRecentContent {
NSUserDefaults* group_user_defaults);
~ClipboardRecentContentIOS() override;
- // Notifies that the content of the pasteboard may have changed.
- void PasteboardChanged();
+ // If the content of the pasteboard has changed, updates the change count,
+ // change date, and md5 of the latest pasteboard entry if necessary.
+ void UpdateIfNeeded();
- // Checks if pasteboard changed since last time a pasteboard change was
- // registered.
- bool HasPasteboardChanged(base::TimeDelta uptime);
-
- // Gets the current URL in the clipboard. If the cache is out of date, updates
- // it.
- bool GetCurrentURLFromClipboard(GURL* url);
+ // Returns whether the pasteboard changed since the last time a pasteboard
+ // change was detected.
+ bool HasPasteboardChanged() const;
// Loads information from the user defaults about the latest pasteboard entry.
void LoadFromUserDefaults();
// ClipboardRecentContent implementation.
- bool GetRecentURLFromClipboard(GURL* url) const override;
-
+ bool GetRecentURLFromClipboard(GURL* url) override;
base::TimeDelta GetClipboardContentAge() const override;
void SuppressClipboardContent() override;
- void RecentURLDisplayed() override;
+
+ protected:
+ // Returns the uptime. Override in tests to return custom value.
+ virtual base::TimeDelta Uptime() const;
private:
friend class ClipboardRecentContentIOSTest;
- // Helper constructor for testing. |uptime| is how long ago the device has
- // started, while |application_scheme| has the same meaning as the public
- // constructor.
- ClipboardRecentContentIOS(const std::string& application_scheme,
- base::TimeDelta uptime);
-
- // Initializes the object. |uptime| is how long ago the device has started.
- void Init(base::TimeDelta uptime);
-
// Saves information to the user defaults about the latest pasteboard entry.
void SaveToUserDefaults();
@@ -75,14 +65,10 @@ class ClipboardRecentContentIOS : public ClipboardRecentContent {
NSInteger last_pasteboard_change_count_;
// Estimation of the date when the pasteboard changed.
base::scoped_nsobject<NSDate> last_pasteboard_change_date_;
- // Estimation of the copy date of the last displayed URL.
- base::scoped_nsobject<NSDate> last_displayed_pasteboard_entry_;
// MD5 hash of the last registered pasteboard entry.
base::scoped_nsobject<NSData> last_pasteboard_entry_md5_;
- // Cache of the GURL contained in the pasteboard (if any).
- GURL url_from_pasteboard_cache_;
- // Bridge to receive notification when the pasteboard changes.
- base::scoped_nsobject<PasteboardNotificationListenerBridge>
+ // Bridge to receive notifications when the application becomes active.
+ base::scoped_nsobject<ApplicationDidBecomeActiveNotificationListenerBridge>
notification_bridge_;
// The user defaults from the app group used to optimize the pasteboard change
// detection.
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_ios.mm b/chromium/components/open_from_clipboard/clipboard_recent_content_ios.mm
index 4b6efd2eacd..0ef8e97124d 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content_ios.mm
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_ios.mm
@@ -18,11 +18,12 @@
#include "url/gurl.h"
#include "url/url_constants.h"
-// Bridge that forwards pasteboard change notifications to its delegate.
-@interface PasteboardNotificationListenerBridge : NSObject
+// Bridge that forwards UIApplicationDidBecomeActiveNotification notifications
+// to its delegate.
+@interface ApplicationDidBecomeActiveNotificationListenerBridge : NSObject
-// Initialize the PasteboardNotificationListenerBridge with |delegate| which
-// must not be null.
+// Initialize the ApplicationDidBecomeActiveNotificationListenerBridge with
+// |delegate| which must not be null.
- (instancetype)initWithDelegate:(ClipboardRecentContentIOS*)delegate
NS_DESIGNATED_INITIALIZER;
@@ -30,7 +31,7 @@
@end
-@implementation PasteboardNotificationListenerBridge {
+@implementation ApplicationDidBecomeActiveNotificationListenerBridge {
ClipboardRecentContentIOS* _delegate;
}
@@ -46,11 +47,6 @@
_delegate = delegate;
[[NSNotificationCenter defaultCenter]
addObserver:self
- selector:@selector(pasteboardChangedNotification:)
- name:UIPasteboardChangedNotification
- object:[UIPasteboard generalPasteboard]];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
selector:@selector(didBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
@@ -63,18 +59,10 @@
[super dealloc];
}
-- (void)pasteboardChangedNotification:(NSNotification*)notification {
- if (_delegate) {
- _delegate->PasteboardChanged();
- }
-}
-
- (void)didBecomeActive:(NSNotification*)notification {
if (_delegate) {
_delegate->LoadFromUserDefaults();
- if (_delegate->HasPasteboardChanged(base::SysInfo::Uptime())) {
- _delegate->PasteboardChanged();
- }
+ _delegate->UpdateIfNeeded();
}
}
@@ -95,9 +83,6 @@ NSString* kPasteboardChangeDateKey = @"PasteboardChangeDate";
// Key used to store the hash of the content of the pasteboard. Whenever the
// hash changed, the pasteboard content is considered to have changed.
NSString* kPasteboardEntryMD5Key = @"PasteboardEntryMD5";
-// Key used to store the date of the latest pasteboard entry displayed in the
-// omnibox. This is used to report metrics on pasteboard change.
-NSString* kLastDisplayedPasteboardEntryKey = @"LastDisplayedPasteboardEntry";
base::TimeDelta kMaximumAgeOfClipboard = base::TimeDelta::FromHours(3);
// Schemes accepted by the ClipboardRecentContentIOS.
const char* kAuthorizedSchemes[] = {
@@ -113,7 +98,8 @@ const char* kAuthorizedSchemes[] = {
// having copied a given string.
NSData* WeakMD5FromNSString(NSString* string) {
unsigned char hash[CC_MD5_DIGEST_LENGTH];
- const char* c_string = [string UTF8String];
+ const std::string clipboard = base::SysNSStringToUTF8(string);
+ const char* c_string = clipboard.c_str();
CC_MD5(c_string, strlen(c_string), hash);
NSData* data = [NSData dataWithBytes:hash length:4];
return data;
@@ -121,14 +107,16 @@ NSData* WeakMD5FromNSString(NSString* string) {
} // namespace
-bool ClipboardRecentContentIOS::GetRecentURLFromClipboard(GURL* url) const {
+bool ClipboardRecentContentIOS::GetRecentURLFromClipboard(GURL* url) {
DCHECK(url);
+ UpdateIfNeeded();
if (GetClipboardContentAge() > kMaximumAgeOfClipboard) {
return false;
}
- if (url_from_pasteboard_cache_.is_valid()) {
- *url = url_from_pasteboard_cache_;
+ GURL url_from_pasteboard = URLFromPasteboard();
+ if (url_from_pasteboard.is_valid()) {
+ *url = url_from_pasteboard;
return true;
}
return false;
@@ -147,12 +135,13 @@ void ClipboardRecentContentIOS::SuppressClipboardContent() {
SaveToUserDefaults();
}
-void ClipboardRecentContentIOS::PasteboardChanged() {
- url_from_pasteboard_cache_ = URLFromPasteboard();
- if (!url_from_pasteboard_cache_.is_empty()) {
- base::RecordAction(
- base::UserMetricsAction("MobileOmniboxClipboardChanged"));
- }
+void ClipboardRecentContentIOS::UpdateIfNeeded() {
+ if (!HasPasteboardChanged())
+ return;
+
+ base::RecordAction(base::UserMetricsAction("MobileOmniboxClipboardChanged"));
+
+ GURL url_from_pasteboard = URLFromPasteboard();
last_pasteboard_change_date_.reset([[NSDate date] retain]);
last_pasteboard_change_count_ = [UIPasteboard generalPasteboard].changeCount;
NSString* pasteboard_string = [[UIPasteboard generalPasteboard] string];
@@ -169,18 +158,19 @@ ClipboardRecentContentIOS::ClipboardRecentContentIOS(
NSUserDefaults* group_user_defaults)
: application_scheme_(application_scheme),
shared_user_defaults_([group_user_defaults retain]) {
- Init(base::SysInfo::Uptime());
-}
+ last_pasteboard_change_count_ = NSIntegerMax;
+ LoadFromUserDefaults();
-ClipboardRecentContentIOS::ClipboardRecentContentIOS(
- const std::string& application_scheme,
- base::TimeDelta uptime)
- : application_scheme_(application_scheme),
- shared_user_defaults_([[NSUserDefaults standardUserDefaults] retain]) {
- Init(uptime);
+ UpdateIfNeeded();
+
+ // Makes sure |last_pasteboard_change_count_| was properly initialized.
+ DCHECK_NE(last_pasteboard_change_count_, NSIntegerMax);
+ notification_bridge_.reset(
+ [[ApplicationDidBecomeActiveNotificationListenerBridge alloc]
+ initWithDelegate:this]);
}
-bool ClipboardRecentContentIOS::HasPasteboardChanged(base::TimeDelta uptime) {
+bool ClipboardRecentContentIOS::HasPasteboardChanged() const {
// If |MD5Changed|, we know for sure there has been at least one pasteboard
// copy since last time it was checked.
// If the pasteboard content is still the same but the device was not
@@ -192,7 +182,7 @@ bool ClipboardRecentContentIOS::HasPasteboardChanged(base::TimeDelta uptime) {
NSInteger change_count = [UIPasteboard generalPasteboard].changeCount;
bool change_count_changed = change_count != last_pasteboard_change_count_;
- bool not_rebooted = uptime > GetClipboardContentAge();
+ bool not_rebooted = Uptime() > GetClipboardContentAge();
if (not_rebooted)
return change_count_changed;
@@ -206,27 +196,6 @@ bool ClipboardRecentContentIOS::HasPasteboardChanged(base::TimeDelta uptime) {
return md5_changed;
}
-bool ClipboardRecentContentIOS::GetCurrentURLFromClipboard(GURL* url) {
- if (HasPasteboardChanged(base::SysInfo::Uptime())) {
- PasteboardChanged();
- }
- return GetRecentURLFromClipboard(url);
-}
-
-void ClipboardRecentContentIOS::Init(base::TimeDelta uptime) {
- last_pasteboard_change_count_ = NSIntegerMax;
- url_from_pasteboard_cache_ = URLFromPasteboard();
- LoadFromUserDefaults();
-
- if (HasPasteboardChanged(uptime))
- PasteboardChanged();
-
- // Makes sure |last_pasteboard_change_count_| was properly initialized.
- DCHECK_NE(last_pasteboard_change_count_, NSIntegerMax);
- notification_bridge_.reset(
- [[PasteboardNotificationListenerBridge alloc] initWithDelegate:this]);
-}
-
ClipboardRecentContentIOS::~ClipboardRecentContentIOS() {
[notification_bridge_ disconnect];
}
@@ -252,16 +221,6 @@ GURL ClipboardRecentContentIOS::URLFromPasteboard() {
return GURL::EmptyGURL();
}
-void ClipboardRecentContentIOS::RecentURLDisplayed() {
- if ([last_pasteboard_change_date_
- isEqualToDate:last_displayed_pasteboard_entry_.get()]) {
- return;
- }
- base::RecordAction(base::UserMetricsAction("MobileOmniboxClipboardChanged"));
- last_pasteboard_change_date_ = last_displayed_pasteboard_entry_;
- SaveToUserDefaults();
-}
-
void ClipboardRecentContentIOS::LoadFromUserDefaults() {
last_pasteboard_change_count_ =
[shared_user_defaults_ integerForKey:kPasteboardChangeCountKey];
@@ -269,8 +228,6 @@ void ClipboardRecentContentIOS::LoadFromUserDefaults() {
[[shared_user_defaults_ objectForKey:kPasteboardChangeDateKey] retain]);
last_pasteboard_entry_md5_.reset(
[[shared_user_defaults_ objectForKey:kPasteboardEntryMD5Key] retain]);
- last_displayed_pasteboard_entry_.reset([[shared_user_defaults_
- objectForKey:kLastDisplayedPasteboardEntryKey] retain]);
DCHECK(!last_pasteboard_change_date_ ||
[last_pasteboard_change_date_ isKindOfClass:[NSDate class]]);
@@ -283,6 +240,8 @@ void ClipboardRecentContentIOS::SaveToUserDefaults() {
forKey:kPasteboardChangeDateKey];
[shared_user_defaults_ setObject:last_pasteboard_entry_md5_
forKey:kPasteboardEntryMD5Key];
- [shared_user_defaults_ setObject:last_displayed_pasteboard_entry_
- forKey:kLastDisplayedPasteboardEntryKey];
+}
+
+base::TimeDelta ClipboardRecentContentIOS::Uptime() const {
+ return base::SysInfo::Uptime();
}
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm b/chromium/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm
index 8f47b4513c3..670a92354c0 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm
@@ -4,6 +4,7 @@
#include "components/open_from_clipboard/clipboard_recent_content_ios.h"
+#import <CoreGraphics/CoreGraphics.h>
#import <UIKit/UIKit.h>
#include <memory>
@@ -13,6 +14,20 @@
namespace {
+UIImage* TestUIImage() {
+ CGRect frame = CGRectMake(0, 0, 1.0, 1.0);
+ UIGraphicsBeginImageContext(frame.size);
+
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
+ CGContextFillRect(context, frame);
+
+ UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ return image;
+}
+
void SetPasteboardImage(UIImage* image) {
[[UIPasteboard generalPasteboard] setImage:image];
}
@@ -24,11 +39,28 @@ void SetPasteboardContent(const char* data) {
}
const char kUnrecognizedURL[] = "ftp://foo/";
const char kRecognizedURL[] = "http://bar/";
+const char kRecognizedURL2[] = "http://bar/2";
const char kAppSpecificURL[] = "test://qux/";
const char kAppSpecificScheme[] = "test";
NSTimeInterval kSevenHours = 60 * 60 * 7;
} // namespace
+class ClipboardRecentContentIOSWithFakeUptime
+ : public ClipboardRecentContentIOS {
+ public:
+ ClipboardRecentContentIOSWithFakeUptime(const std::string& application_scheme,
+ NSUserDefaults* group_user_defaults)
+ : ClipboardRecentContentIOS(application_scheme, group_user_defaults) {}
+ // Sets the uptime.
+ void SetUptime(base::TimeDelta uptime) { uptime_ = uptime; }
+
+ protected:
+ base::TimeDelta Uptime() const override { return uptime_; }
+
+ private:
+ base::TimeDelta uptime_;
+};
+
class ClipboardRecentContentIOSTest : public ::testing::Test {
protected:
ClipboardRecentContentIOSTest() {
@@ -44,8 +76,9 @@ class ClipboardRecentContentIOSTest : public ::testing::Test {
void ResetClipboardRecentContent(const std::string& application_scheme,
base::TimeDelta time_delta) {
- clipboard_content_.reset(
- new ClipboardRecentContentIOS(application_scheme, time_delta));
+ clipboard_content_.reset(new ClipboardRecentContentIOSWithFakeUptime(
+ application_scheme, [NSUserDefaults standardUserDefaults]));
+ clipboard_content_->SetUptime(time_delta);
}
void SetStoredPasteboardChangeDate(NSDate* changeDate) {
@@ -59,7 +92,7 @@ class ClipboardRecentContentIOSTest : public ::testing::Test {
}
protected:
- std::unique_ptr<ClipboardRecentContentIOS> clipboard_content_;
+ std::unique_ptr<ClipboardRecentContentIOSWithFakeUptime> clipboard_content_;
};
TEST_F(ClipboardRecentContentIOSTest, SchemeFiltering) {
@@ -138,7 +171,7 @@ TEST_F(ClipboardRecentContentIOSTest, SupressedPasteboard) {
// Check that if the pasteboard changes, the new content is not
// supressed anymore.
- SetPasteboardContent(kRecognizedURL);
+ SetPasteboardContent(kRecognizedURL2);
EXPECT_TRUE(clipboard_content_->GetRecentURLFromClipboard(&gurl));
}
@@ -154,7 +187,7 @@ TEST_F(ClipboardRecentContentIOSTest, AddingNonStringRemovesCachedString) {
// Overwrite pasteboard with an image.
base::scoped_nsobject<UIImage> image([[UIImage alloc] init]);
- SetPasteboardImage(image);
+ SetPasteboardImage(TestUIImage());
// Pasteboard should appear empty.
EXPECT_FALSE(clipboard_content_->GetRecentURLFromClipboard(&gurl));
diff --git a/chromium/components/open_from_clipboard/fake_clipboard_recent_content.cc b/chromium/components/open_from_clipboard/fake_clipboard_recent_content.cc
index 9a77fd9b084..87e5627b731 100644
--- a/chromium/components/open_from_clipboard/fake_clipboard_recent_content.cc
+++ b/chromium/components/open_from_clipboard/fake_clipboard_recent_content.cc
@@ -9,7 +9,7 @@ FakeClipboardRecentContent::FakeClipboardRecentContent()
FakeClipboardRecentContent::~FakeClipboardRecentContent() {}
-bool FakeClipboardRecentContent::GetRecentURLFromClipboard(GURL* url) const {
+bool FakeClipboardRecentContent::GetRecentURLFromClipboard(GURL* url) {
if (suppress_content_)
return false;
@@ -28,8 +28,6 @@ void FakeClipboardRecentContent::SuppressClipboardContent() {
suppress_content_ = true;
}
-void FakeClipboardRecentContent::RecentURLDisplayed() {}
-
void FakeClipboardRecentContent::SetClipboardContent(
const GURL& url,
base::TimeDelta content_age) {
diff --git a/chromium/components/open_from_clipboard/fake_clipboard_recent_content.h b/chromium/components/open_from_clipboard/fake_clipboard_recent_content.h
index f628a892970..05c8a3fd9c5 100644
--- a/chromium/components/open_from_clipboard/fake_clipboard_recent_content.h
+++ b/chromium/components/open_from_clipboard/fake_clipboard_recent_content.h
@@ -18,10 +18,9 @@ class FakeClipboardRecentContent : public ClipboardRecentContent {
~FakeClipboardRecentContent() override;
// ClipboardRecentContent implementation.
- bool GetRecentURLFromClipboard(GURL* url) const override;
+ bool GetRecentURLFromClipboard(GURL* url) override;
base::TimeDelta GetClipboardContentAge() const override;
void SuppressClipboardContent() override;
- void RecentURLDisplayed() override;
// Sets the URL and clipboard content age.
void SetClipboardContent(const GURL& url, base::TimeDelta content_age);
diff --git a/chromium/components/os_crypt.gypi b/chromium/components/os_crypt.gypi
deleted file mode 100644
index 1d61f6b1b63..00000000000
--- a/chromium/components/os_crypt.gypi
+++ /dev/null
@@ -1,138 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'os_crypt',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- ],
- 'sources': [
- 'os_crypt/ie7_password_win.cc',
- 'os_crypt/ie7_password_win.h',
- 'os_crypt/keychain_password_mac.h',
- 'os_crypt/keychain_password_mac.mm',
- 'os_crypt/os_crypt.h',
- 'os_crypt/os_crypt_mac.mm',
- 'os_crypt/os_crypt_posix.cc',
- 'os_crypt/os_crypt_switches.cc',
- 'os_crypt/os_crypt_switches.h',
- 'os_crypt/os_crypt_win.cc',
- ],
- 'conditions': [
- ['OS=="mac"', {
- 'sources!': [
- 'os_crypt/os_crypt_posix.cc',
- ],
- }],
- ['OS=="win"', {
- 'all_dependent_settings': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'crypt32.lib',
- ],
- },
- },
- },
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'crypt32.lib',
- ],
- },
- },
- }],
- ['OS=="linux" and chromeos!=1', {
- 'sources': [
- 'os_crypt/key_storage_linux.cc',
- 'os_crypt/key_storage_linux.h',
- 'os_crypt/os_crypt_linux.cc',
- ],
- 'sources!': [
- 'os_crypt/os_crypt_posix.cc',
- ],
- 'conditions': [
- ['use_glib==1', {
- 'sources': [
- 'os_crypt/key_storage_libsecret.cc',
- 'os_crypt/key_storage_libsecret.h',
- 'os_crypt/libsecret_util_linux.cc',
- 'os_crypt/libsecret_util_linux.h',
- ],
- 'defines': [
- 'USE_LIBSECRET',
- ],
- 'include_dirs' : [
- '../third_party/libsecret/'
- ],
- 'dependencies': [
- '../build/linux/system.gyp:glib',
- ],
- }],
- ['use_dbus==1', {
- 'sources': [
- 'os_crypt/kwallet_dbus.cc',
- 'os_crypt/kwallet_dbus.h',
- ],
- 'defines': [
- 'USE_KWALLET',
- ],
- 'dependencies': [
- '../build/linux/system.gyp:dbus',
- '../dbus/dbus.gyp:dbus',
- ],
- 'include_dirs': [
- '..',
- ],
- }]
- ],
- }],
- ],
- 'target_conditions': [
- ['OS=="ios"', {
- 'sources/': [
- ['include', '^os_crypt/keychain_password_mac\\.mm$'],
- ['include', '^os_crypt/os_crypt_mac\\.mm$'],
- ],
- }],
- ],
- },
- {
- 'target_name': 'os_crypt_test_support',
- 'type': 'static_library',
- 'sources': [
- 'os_crypt/os_crypt_mocker.cc',
- 'os_crypt/os_crypt_mocker.h',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../testing/gtest.gyp:gtest',
- ],
- 'conditions': [
- ['OS=="linux" and chromeos!=1', {
- 'sources': [
- 'os_crypt/os_crypt_mocker_linux.cc',
- 'os_crypt/os_crypt_mocker_linux.h',
- ],
- 'defines': [
- 'USE_LIBSECRET',
- ],
- 'include_dirs' : [
- '../third_party/libsecret/'
- ],
- 'dependencies': [
- '../build/linux/system.gyp:glib',
- ],
- }],
- ]
- }
- ],
-}
diff --git a/chromium/components/os_crypt/BUILD.gn b/chromium/components/os_crypt/BUILD.gn
index 4dc731bc1cb..19aa93eeafd 100644
--- a/chromium/components/os_crypt/BUILD.gn
+++ b/chromium/components/os_crypt/BUILD.gn
@@ -4,8 +4,32 @@
import("//build/config/features.gni")
import("//build/config/ui.gni")
+import("//build/config/linux/pkg_config.gni")
+import("//components/os_crypt/features.gni")
-source_set("os_crypt") {
+if (use_gnome_keyring) {
+ # Gnome-keyring is normally dynamically loaded. The gnome_keyring config
+ # will set this up.
+ pkg_config("gnome_keyring") {
+ packages = [ "gnome-keyring-1" ]
+ defines = [ "USE_GNOME_KEYRING" ]
+ ignore_libs = true
+ }
+
+ # If you want to link gnome-keyring directly (use only for unit tests)
+ # ADDITIONALLY add this config on top of ":gnome_keyring". pkg-config is a
+ # bit slow, so prefer not to run it again. In practice, gnome-keyring's libs
+ # are just itself and common gnome ones we link already, so we can get away
+ # with additionally just coding the library name here.
+ # TODO(cfroussios): This is only used by
+ # chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
+ # We should deprecate both.
+ config("gnome_keyring_direct") {
+ libs = [ "gnome-keyring" ]
+ }
+}
+
+static_library("os_crypt") {
sources = [
"ie7_password_win.cc",
"ie7_password_win.h",
@@ -49,10 +73,22 @@ source_set("os_crypt") {
sources += [
"key_storage_linux.cc",
"key_storage_linux.h",
+ "key_storage_util_linux.cc",
+ "key_storage_util_linux.h",
"os_crypt_linux.cc",
]
defines = []
+ if (use_gnome_keyring) {
+ sources += [
+ "key_storage_keyring.cc",
+ "key_storage_keyring.h",
+ "keyring_util_linux.cc",
+ "keyring_util_linux.h",
+ ]
+ configs += [ ":gnome_keyring" ]
+ defines += [ "USE_KEYRING" ]
+ }
if (use_glib) {
sources += [
"key_storage_libsecret.cc",
@@ -66,6 +102,8 @@ source_set("os_crypt") {
}
if (use_dbus) {
sources += [
+ "key_storage_kwallet.cc",
+ "key_storage_kwallet.h",
"kwallet_dbus.cc",
"kwallet_dbus.h",
]
@@ -75,7 +113,7 @@ source_set("os_crypt") {
}
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"os_crypt_mocker.cc",
@@ -91,8 +129,16 @@ source_set("test_support") {
"os_crypt_mocker_linux.cc",
"os_crypt_mocker_linux.h",
]
- deps += [ "//third_party/libsecret" ]
- defines = [ "USE_LIBSECRET" ]
+ defines = []
+ if (use_gnome_keyring) {
+ defines += [ "USE_KEYRING" ]
+ }
+ if (use_glib) {
+ defines += [ "USE_LIBSECRET" ]
+ }
+ if (use_dbus) {
+ defines += [ "USE_KWALLET" ]
+ }
}
}
@@ -116,17 +162,23 @@ source_set("unit_tests") {
sources += [ "os_crypt_linux_unittest.cc" ]
defines = []
+ if (use_gnome_keyring) {
+ sources += [ "key_storage_keyring_unittest.cc" ]
+ configs += [ ":gnome_keyring" ]
+ deps += [ "//base/test:test_support" ]
+ defines += [ "USE_KEYRING" ]
+ }
if (use_glib) {
- sources += [ "os_crypt_util_linux_unittest.cc" ]
+ sources += [ "key_storage_libsecret_unittest.cc" ]
deps += [ "//third_party/libsecret" ]
defines += [ "USE_LIBSECRET" ]
}
if (use_dbus) {
- sources += [ "kwallet_dbus_unittest.cc" ]
- deps += [
- "//dbus",
- "//dbus:test_support",
+ sources += [
+ "key_storage_kwallet_unittest.cc",
+ "kwallet_dbus_unittest.cc",
]
+ deps += [ "//dbus:test_support" ]
defines += [ "USE_KWALLET" ]
}
}
diff --git a/chromium/components/os_crypt/OWNERS b/chromium/components/os_crypt/OWNERS
index 1967bf567e8..6de8c4eb13e 100644
--- a/chromium/components/os_crypt/OWNERS
+++ b/chromium/components/os_crypt/OWNERS
@@ -1 +1,2 @@
+cfroussios@chromium.org
thestig@chromium.org
diff --git a/chromium/components/os_crypt/features.gni b/chromium/components/os_crypt/features.gni
new file mode 100644
index 00000000000..f67c8b9728d
--- /dev/null
+++ b/chromium/components/os_crypt/features.gni
@@ -0,0 +1,11 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+declare_args() {
+ # Whether to use libgnome-keyring (deprecated by libsecret).
+ # See http://crbug.com/466975 and http://crbug.com/355223.
+ use_gnome_keyring = is_desktop_linux && use_glib
+}
diff --git a/chromium/components/os_crypt/key_storage_keyring.cc b/chromium/components/os_crypt/key_storage_keyring.cc
new file mode 100644
index 00000000000..c039af9616b
--- /dev/null
+++ b/chromium/components/os_crypt/key_storage_keyring.cc
@@ -0,0 +1,98 @@
+// 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 "components/os_crypt/key_storage_keyring.h"
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "components/os_crypt/keyring_util_linux.h"
+
+namespace {
+
+#if defined(GOOGLE_CHROME_BUILD)
+const char kApplicationName[] = "chrome";
+#else
+const char kApplicationName[] = "chromium";
+#endif
+
+const GnomeKeyringPasswordSchema kSchema = {
+ GNOME_KEYRING_ITEM_GENERIC_SECRET,
+ {{"application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, {nullptr}}};
+
+} // namespace
+
+KeyStorageKeyring::KeyStorageKeyring(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner)
+ : main_thread_runner_(main_thread_runner) {}
+
+KeyStorageKeyring::~KeyStorageKeyring() {}
+
+bool KeyStorageKeyring::Init() {
+ return GnomeKeyringLoader::LoadGnomeKeyring();
+}
+
+std::string KeyStorageKeyring::GetKey() {
+ std::string password;
+
+ // Ensure GetKeyDelegate() is executed on the main thread.
+ if (main_thread_runner_->BelongsToCurrentThread()) {
+ GetKeyDelegate(&password, nullptr);
+ } else {
+ base::WaitableEvent password_loaded(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ main_thread_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&KeyStorageKeyring::GetKeyDelegate, base::Unretained(this),
+ &password, &password_loaded));
+ password_loaded.Wait();
+ }
+
+ return password;
+}
+
+void KeyStorageKeyring::GetKeyDelegate(
+ std::string* password_ptr,
+ base::WaitableEvent* password_loaded_ptr) {
+ gchar* password = nullptr;
+ GnomeKeyringResult result =
+ GnomeKeyringLoader::gnome_keyring_find_password_sync_ptr(
+ &kSchema, &password, "application", kApplicationName, nullptr);
+ if (result == GNOME_KEYRING_RESULT_OK) {
+ *password_ptr = password;
+ GnomeKeyringLoader::gnome_keyring_free_password_ptr(password);
+ } else if (result == GNOME_KEYRING_RESULT_NO_MATCH) {
+ *password_ptr = KeyStorageKeyring::AddRandomPasswordInKeyring();
+ VLOG(1) << "OSCrypt generated a new password";
+ } else {
+ password_ptr->clear();
+ VLOG(1) << "OSCrypt failed to use gnome-keyring";
+ }
+
+ if (password_loaded_ptr)
+ password_loaded_ptr->Signal();
+}
+
+std::string KeyStorageKeyring::AddRandomPasswordInKeyring() {
+ // Generate password
+ std::string password;
+ base::Base64Encode(base::RandBytesAsString(16), &password);
+
+ // Store generated password
+ GnomeKeyringResult result =
+ GnomeKeyringLoader::gnome_keyring_store_password_sync_ptr(
+ &kSchema, nullptr /* default keyring */, KeyStorageLinux::kKey,
+ password.c_str(), "application", kApplicationName, nullptr);
+ if (result != GNOME_KEYRING_RESULT_OK) {
+ VLOG(1) << "Failed to store generated password to gnome-keyring";
+ return std::string();
+ }
+
+ return password;
+}
diff --git a/chromium/components/os_crypt/key_storage_keyring.h b/chromium/components/os_crypt/key_storage_keyring.h
new file mode 100644
index 00000000000..9e9c32747e1
--- /dev/null
+++ b/chromium/components/os_crypt/key_storage_keyring.h
@@ -0,0 +1,49 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OS_CRYPT_KEY_STORAGE_KEYRING_H_
+#define COMPONENTS_OS_CRYPT_KEY_STORAGE_KEYRING_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "components/os_crypt/key_storage_linux.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+class WaitableEvent;
+} // namespace base
+
+// Specialisation of KeyStorageLinux that uses Libsecret.
+class KeyStorageKeyring : public KeyStorageLinux {
+ public:
+ explicit KeyStorageKeyring(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner);
+ ~KeyStorageKeyring() override;
+
+ // KeyStorageLinux
+ std::string GetKey() override;
+
+ protected:
+ // KeyStorageLinux
+ bool Init() override;
+
+ private:
+ // Gnome keyring requires calls to originate from the main thread.
+ // This is the part of GetKey() that gets dispatched to the main thread.
+ // The password is stored in |password_ptr|. If |password_loaded_ptr| is not
+ // null, it will be signaled when |password_ptr| is safe to read.
+ void GetKeyDelegate(std::string* password_ptr,
+ base::WaitableEvent* password_loaded_ptr);
+
+ // Generate a random string and store it as OScrypt's new password.
+ std::string AddRandomPasswordInKeyring();
+
+ // Keyring calls need to originate from the main thread.
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyStorageKeyring);
+};
+
+#endif // COMPONENTS_OS_CRYPT_KEY_STORAGE_KEYRING_H_
diff --git a/chromium/components/os_crypt/key_storage_keyring_unittest.cc b/chromium/components/os_crypt/key_storage_keyring_unittest.cc
new file mode 100644
index 00000000000..f7d8067ab47
--- /dev/null
+++ b/chromium/components/os_crypt/key_storage_keyring_unittest.cc
@@ -0,0 +1,153 @@
+// 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 <cstdarg> // Needed to mock ellipsis
+#include <string>
+
+#include "base/macros.h"
+#include "base/test/test_simple_task_runner.h"
+#include "components/os_crypt/key_storage_keyring.h"
+#include "components/os_crypt/keyring_util_linux.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+#if defined(GOOGLE_CHROME_BUILD)
+const char kApplicationName[] = "chrome";
+#else
+const char kApplicationName[] = "chromium";
+#endif
+
+// Replaces some of GnomeKeyringLoader's methods with mocked ones.
+class MockGnomeKeyringLoader : public GnomeKeyringLoader {
+ public:
+ static void ResetForOSCrypt() {
+ GnomeKeyringLoader::gnome_keyring_find_password_sync_ptr =
+ &mock_gnome_keyring_find_password_sync;
+ GnomeKeyringLoader::gnome_keyring_store_password_sync_ptr =
+ &mock_gnome_keyring_store_password_sync;
+ GnomeKeyringLoader::gnome_keyring_free_password_ptr =
+ &mock_gnome_keyring_free_password;
+
+ delete s_password_ptr_;
+ s_password_ptr_ = nullptr;
+
+ // GnomeKeyringLoader does not (re)load keyring is this is true.
+ GnomeKeyringLoader::keyring_loaded = true;
+ }
+
+ static void SetOSCryptPassword(const char* password) {
+ delete s_password_ptr_;
+ s_password_ptr_ = new std::string(password);
+ }
+
+ static void TearDown() {
+ delete s_password_ptr_;
+ s_password_ptr_ = nullptr;
+ // Function pointers will be reset the next time loading is requested.
+ GnomeKeyringLoader::keyring_loaded = false;
+ }
+
+ private:
+ // These methods are used to redirect calls through GnomeKeyringLoader.
+ static GnomeKeyringResult mock_gnome_keyring_find_password_sync(
+ const GnomeKeyringPasswordSchema* schema,
+ gchar** password,
+ ...);
+
+ static GnomeKeyringResult mock_gnome_keyring_store_password_sync(
+ const GnomeKeyringPasswordSchema* schema,
+ const gchar* keyring,
+ const gchar* display_name,
+ const gchar* password,
+ ...);
+
+ static void mock_gnome_keyring_free_password(gchar* password);
+
+ static std::string* s_password_ptr_;
+};
+
+std::string* MockGnomeKeyringLoader::s_password_ptr_ = nullptr;
+
+// static
+GnomeKeyringResult
+MockGnomeKeyringLoader::mock_gnome_keyring_find_password_sync(
+ const GnomeKeyringPasswordSchema* schema,
+ gchar** password,
+ ...) {
+ va_list attrs;
+ va_start(attrs, password);
+ EXPECT_STREQ("application", va_arg(attrs, const char*));
+ EXPECT_STREQ(kApplicationName, va_arg(attrs, const char*));
+ EXPECT_EQ(nullptr, va_arg(attrs, const char*));
+ va_end(attrs);
+
+ if (!s_password_ptr_)
+ return GNOME_KEYRING_RESULT_NO_MATCH;
+ *password = strdup(s_password_ptr_->c_str());
+ return GNOME_KEYRING_RESULT_OK;
+}
+
+// static
+GnomeKeyringResult
+MockGnomeKeyringLoader::mock_gnome_keyring_store_password_sync(
+ const GnomeKeyringPasswordSchema* schema,
+ const gchar* keyring,
+ const gchar* display_name,
+ const gchar* password,
+ ...) {
+ va_list attrs;
+ va_start(attrs, password);
+ EXPECT_STREQ("application", va_arg(attrs, const char*));
+ EXPECT_STREQ(kApplicationName, va_arg(attrs, const char*));
+ EXPECT_EQ(nullptr, va_arg(attrs, const char*));
+ va_end(attrs);
+
+ delete s_password_ptr_;
+ s_password_ptr_ = new std::string(password);
+ return GNOME_KEYRING_RESULT_OK;
+}
+
+// static
+void MockGnomeKeyringLoader::mock_gnome_keyring_free_password(gchar* password) {
+ free(password); // We are mocking a C function.
+}
+
+class GnomeKeyringTest : public testing::Test {
+ public:
+ GnomeKeyringTest();
+ ~GnomeKeyringTest() override;
+
+ protected:
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ KeyStorageKeyring keyring_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GnomeKeyringTest);
+};
+
+GnomeKeyringTest::GnomeKeyringTest()
+ : task_runner_(new base::TestSimpleTaskRunner()), keyring_(task_runner_) {
+ MockGnomeKeyringLoader::ResetForOSCrypt();
+}
+
+GnomeKeyringTest::~GnomeKeyringTest() {
+ MockGnomeKeyringLoader::TearDown();
+}
+
+TEST_F(GnomeKeyringTest, KeyringRepeats) {
+ std::string password = keyring_.GetKey();
+ EXPECT_FALSE(password.empty());
+ std::string password_repeat = keyring_.GetKey();
+ EXPECT_EQ(password, password_repeat);
+}
+
+TEST_F(GnomeKeyringTest, KeyringCreatesRandomised) {
+ std::string password = keyring_.GetKey();
+ MockGnomeKeyringLoader::ResetForOSCrypt();
+ std::string password_new = keyring_.GetKey();
+ EXPECT_NE(password, password_new);
+}
+
+} // namespace
diff --git a/chromium/components/os_crypt/key_storage_kwallet.cc b/chromium/components/os_crypt/key_storage_kwallet.cc
new file mode 100644
index 00000000000..b1d34cc5a97
--- /dev/null
+++ b/chromium/components/os_crypt/key_storage_kwallet.cc
@@ -0,0 +1,131 @@
+// 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 "components/os_crypt/key_storage_kwallet.h"
+
+#include <utility>
+
+#include "base/base64.h"
+#include "base/rand_util.h"
+#include "components/os_crypt/kwallet_dbus.h"
+#include "dbus/bus.h"
+
+KeyStorageKWallet::KeyStorageKWallet(base::nix::DesktopEnvironment desktop_env,
+ std::string app_name)
+ : desktop_env_(desktop_env), handle_(-1), app_name_(std::move(app_name)) {}
+
+KeyStorageKWallet::~KeyStorageKWallet() {
+ // The handle is shared between programs that are using the same wallet.
+ // Closing the wallet is a nop in the typical case.
+ bool success = true;
+ ignore_result(kwallet_dbus_->Close(handle_, false, app_name_, &success));
+ kwallet_dbus_->GetSessionBus()->ShutdownAndBlock();
+}
+
+bool KeyStorageKWallet::Init() {
+ // Initialize using the production KWalletDBus.
+ return InitWithKWalletDBus(nullptr);
+}
+
+bool KeyStorageKWallet::InitWithKWalletDBus(
+ std::unique_ptr<KWalletDBus> optional_kwallet_dbus_ptr) {
+ if (optional_kwallet_dbus_ptr) {
+ kwallet_dbus_ = std::move(optional_kwallet_dbus_ptr);
+ } else {
+ // Initializing with production KWalletDBus
+ kwallet_dbus_.reset(new KWalletDBus(desktop_env_));
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SESSION;
+ options.connection_type = dbus::Bus::PRIVATE;
+ kwallet_dbus_->SetSessionBus(new dbus::Bus(options));
+ }
+
+ InitResult result = InitWallet();
+ // If KWallet might not have started, attempt to start it and retry.
+ if (result == InitResult::TEMPORARY_FAIL && kwallet_dbus_->StartKWalletd())
+ result = InitWallet();
+
+ return result == InitResult::SUCCESS;
+}
+
+KeyStorageKWallet::InitResult KeyStorageKWallet::InitWallet() {
+ // Check that KWallet is enabled.
+ bool enabled = false;
+ KWalletDBus::Error error = kwallet_dbus_->IsEnabled(&enabled);
+ switch (error) {
+ case KWalletDBus::Error::CANNOT_CONTACT:
+ return InitResult::TEMPORARY_FAIL;
+ case KWalletDBus::Error::CANNOT_READ:
+ return InitResult::PERMANENT_FAIL;
+ case KWalletDBus::Error::SUCCESS:
+ break;
+ }
+ if (!enabled)
+ return InitResult::PERMANENT_FAIL;
+
+ // Get the wallet name.
+ error = kwallet_dbus_->NetworkWallet(&wallet_name_);
+ switch (error) {
+ case KWalletDBus::Error::CANNOT_CONTACT:
+ return InitResult::TEMPORARY_FAIL;
+ case KWalletDBus::Error::CANNOT_READ:
+ return InitResult::PERMANENT_FAIL;
+ case KWalletDBus::Error::SUCCESS:
+ return InitResult::SUCCESS;
+ }
+
+ NOTREACHED();
+ return InitResult::PERMANENT_FAIL;
+}
+
+std::string KeyStorageKWallet::GetKey() {
+ // Get handle
+ KWalletDBus::Error error =
+ kwallet_dbus_->Open(wallet_name_, app_name_, &handle_);
+ if (error || handle_ == -1)
+ return std::string();
+
+ // Create folder
+ if (!InitFolder())
+ return std::string();
+
+ // Read password
+ std::string password;
+ error =
+ kwallet_dbus_->ReadPassword(handle_, KeyStorageLinux::kFolderName,
+ KeyStorageLinux::kKey, app_name_, &password);
+ if (error)
+ return std::string();
+
+ // If there is no entry, generate and write a new password.
+ if (password.empty()) {
+ base::Base64Encode(base::RandBytesAsString(16), &password);
+ bool success;
+ error = kwallet_dbus_->WritePassword(handle_, KeyStorageLinux::kFolderName,
+ KeyStorageLinux::kKey, password,
+ app_name_, &success);
+ if (error || !success)
+ return std::string();
+ }
+
+ return password;
+}
+
+bool KeyStorageKWallet::InitFolder() {
+ bool has_folder = false;
+ KWalletDBus::Error error = kwallet_dbus_->HasFolder(
+ handle_, KeyStorageLinux::kFolderName, app_name_, &has_folder);
+ if (error)
+ return false;
+
+ if (!has_folder) {
+ bool success = false;
+ error = kwallet_dbus_->CreateFolder(handle_, KeyStorageLinux::kFolderName,
+ app_name_, &success);
+ if (error || !success)
+ return false;
+ }
+
+ return true;
+}
diff --git a/chromium/components/os_crypt/key_storage_kwallet.h b/chromium/components/os_crypt/key_storage_kwallet.h
new file mode 100644
index 00000000000..35edcf2fd1c
--- /dev/null
+++ b/chromium/components/os_crypt/key_storage_kwallet.h
@@ -0,0 +1,55 @@
+// 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 COMPONENTS_OS_CRYPT_KEY_STORAGE_KWALLET_H_
+#define COMPONENTS_OS_CRYPT_KEY_STORAGE_KWALLET_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "components/os_crypt/key_storage_linux.h"
+#include "components/os_crypt/kwallet_dbus.h"
+
+class KeyStorageKWallet : public KeyStorageLinux {
+ public:
+ KeyStorageKWallet(base::nix::DesktopEnvironment desktop_env,
+ std::string app_name);
+ ~KeyStorageKWallet() override;
+
+ // KeyStorageLinux
+ std::string GetKey() override;
+
+ // Initialize using an optional KWalletDBus mock.
+ // A DBus session will not be created if a mock is provided.
+ bool InitWithKWalletDBus(
+ std::unique_ptr<KWalletDBus> optional_kwallet_dbus_ptr);
+
+ protected:
+ // KeyStorageLinux
+ bool Init() override;
+
+ private:
+ enum class InitResult {
+ SUCCESS,
+ TEMPORARY_FAIL,
+ PERMANENT_FAIL,
+ };
+
+ // Check whether KWallet is enabled and set |wallet_name_|
+ InitResult InitWallet();
+
+ // Create Chrome's folder in the wallet, if it doesn't exist.
+ bool InitFolder();
+
+ const base::nix::DesktopEnvironment desktop_env_;
+ int32_t handle_;
+ std::string wallet_name_;
+ const std::string app_name_;
+ std::unique_ptr<KWalletDBus> kwallet_dbus_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyStorageKWallet);
+};
+
+#endif // COMPONENTS_OS_CRYPT_KEY_STORAGE_KWALLET_H_
diff --git a/chromium/components/os_crypt/key_storage_kwallet_unittest.cc b/chromium/components/os_crypt/key_storage_kwallet_unittest.cc
new file mode 100644
index 00000000000..9f9b7da6d44
--- /dev/null
+++ b/chromium/components/os_crypt/key_storage_kwallet_unittest.cc
@@ -0,0 +1,319 @@
+// 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 "components/os_crypt/key_storage_kwallet.h"
+
+#include "base/logging.h"
+#include "base/nix/xdg_util.h"
+#include "dbus/message.h"
+#include "dbus/mock_bus.h"
+#include "dbus/mock_object_proxy.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using testing::_;
+using testing::DoAll;
+using testing::Return;
+using testing::SaveArg;
+using testing::SetArgPointee;
+using testing::StrictMock;
+
+constexpr KWalletDBus::Error SUCCESS = KWalletDBus::Error::SUCCESS;
+constexpr KWalletDBus::Error CANNOT_READ = KWalletDBus::Error::CANNOT_READ;
+constexpr KWalletDBus::Error CANNOT_CONTACT =
+ KWalletDBus::Error::CANNOT_CONTACT;
+
+// These names are not allowed to change in prod, unless we intentionally
+// migrate.
+#if defined(GOOGLE_CHROME_BUILD)
+const char kExpectedFolderName[] = "Chrome Keys";
+const char kExpectedEntryName[] = "Chrome Safe Storage";
+#else
+const char kExpectedFolderName[] = "Chromium Keys";
+const char kExpectedEntryName[] = "Chromium Safe Storage";
+#endif
+
+// Environment-specific behavior is handled and tested with KWalletDBus, not
+// here, but we still need a value to instantiate.
+const base::nix::DesktopEnvironment kDesktopEnv =
+ base::nix::DesktopEnvironment::DESKTOP_ENVIRONMENT_KDE5;
+
+class MockKWalletDBus : public KWalletDBus {
+ public:
+ MockKWalletDBus() : KWalletDBus(kDesktopEnv) {
+ // On destruction, GetSessionBus() is called to get the bus and shut it
+ // down. Here we create a mock to be returned by GetSessionBus().
+ mock_session_bus_ = new dbus::MockBus(dbus::Bus::Options());
+ }
+
+ dbus::MockBus* GetSessionBus() override { return mock_session_bus_.get(); }
+
+ MOCK_METHOD0(StartKWalletd, bool());
+
+ MOCK_METHOD1(IsEnabled, KWalletDBus::Error(bool*));
+
+ MOCK_METHOD1(NetworkWallet, KWalletDBus::Error(std::string*));
+
+ MOCK_METHOD3(Open,
+ KWalletDBus::Error(const std::string&,
+ const std::string&,
+ int*));
+
+ MOCK_METHOD4(
+ HasFolder,
+ KWalletDBus::Error(int, const std::string&, const std::string&, bool*));
+
+ MOCK_METHOD4(
+ CreateFolder,
+ KWalletDBus::Error(int, const std::string&, const std::string&, bool*));
+
+ MOCK_METHOD5(ReadPassword,
+ KWalletDBus::Error(int,
+ const std::string&,
+ const std::string&,
+ const std::string&,
+ std::string*));
+
+ MOCK_METHOD6(WritePassword,
+ KWalletDBus::Error(int,
+ const std::string&,
+ const std::string&,
+ const std::string&,
+ const std::string&,
+ bool*));
+
+ MOCK_METHOD4(Close, KWalletDBus::Error(int, bool, const std::string&, bool*));
+
+ private:
+ scoped_refptr<dbus::MockBus> mock_session_bus_;
+};
+
+class KeyStorageKWalletTest : public testing::Test {
+ public:
+ KeyStorageKWalletTest() : key_storage_kwallet_(kDesktopEnv, "test-app") {}
+
+ void SetUp() override {
+ kwallet_dbus_mock_ = new StrictMock<MockKWalletDBus>();
+
+ // Calls from |key_storage_kwallet_|'s destructor
+ EXPECT_CALL(*kwallet_dbus_mock_, Close(_, false, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_->GetSessionBus(), ShutdownAndBlock())
+ .Times(1);
+ }
+
+ void SuccessfulInit() {
+ EXPECT_CALL(*kwallet_dbus_mock_, IsEnabled(_))
+ .WillOnce(DoAll(SetArgPointee<0>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, NetworkWallet(_))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(std::string("mollet")), Return(SUCCESS)));
+
+ EXPECT_TRUE(key_storage_kwallet_.InitWithKWalletDBus(
+ std::unique_ptr<MockKWalletDBus>(kwallet_dbus_mock_)));
+ }
+
+ protected:
+ StrictMock<MockKWalletDBus>* kwallet_dbus_mock_;
+ KeyStorageKWallet key_storage_kwallet_;
+ const std::string wallet_name_ = "mollet";
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(KeyStorageKWalletTest);
+};
+
+TEST_F(KeyStorageKWalletTest, InitializeFolder) {
+ SuccessfulInit();
+ EXPECT_CALL(*kwallet_dbus_mock_, Open(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(123), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, HasFolder(123, kExpectedFolderName, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(false), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, CreateFolder(123, kExpectedFolderName, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_,
+ ReadPassword(123, kExpectedFolderName, kExpectedEntryName, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>("butter"), Return(SUCCESS)));
+
+ EXPECT_EQ("butter", key_storage_kwallet_.GetKey());
+}
+
+TEST_F(KeyStorageKWalletTest, ExistingPassword) {
+ SuccessfulInit();
+ EXPECT_CALL(*kwallet_dbus_mock_, Open(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(123), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, HasFolder(123, kExpectedFolderName, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_,
+ ReadPassword(123, kExpectedFolderName, kExpectedEntryName, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>("butter"), Return(SUCCESS)));
+
+ EXPECT_EQ("butter", key_storage_kwallet_.GetKey());
+}
+
+TEST_F(KeyStorageKWalletTest, GenerateNewPassword) {
+ SuccessfulInit();
+ std::string generated_password;
+ EXPECT_CALL(*kwallet_dbus_mock_, Open(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(123), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, HasFolder(123, kExpectedFolderName, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_,
+ ReadPassword(123, kExpectedFolderName, kExpectedEntryName, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(""), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, WritePassword(123, kExpectedFolderName,
+ kExpectedEntryName, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&generated_password), SetArgPointee<5>(true),
+ Return(SUCCESS)));
+
+ EXPECT_EQ(generated_password, key_storage_kwallet_.GetKey());
+}
+
+TEST_F(KeyStorageKWalletTest, InitKWalletNotEnabled) {
+ EXPECT_CALL(*kwallet_dbus_mock_, IsEnabled(_))
+ .WillOnce(DoAll(SetArgPointee<0>(false), Return(SUCCESS)));
+
+ EXPECT_FALSE(key_storage_kwallet_.InitWithKWalletDBus(
+ std::unique_ptr<MockKWalletDBus>(kwallet_dbus_mock_)));
+}
+
+TEST_F(KeyStorageKWalletTest, InitCannotStart) {
+ EXPECT_CALL(*kwallet_dbus_mock_, IsEnabled(_))
+ .WillOnce(Return(CANNOT_CONTACT));
+ EXPECT_CALL(*kwallet_dbus_mock_, StartKWalletd()).WillOnce(Return(false));
+
+ EXPECT_FALSE(key_storage_kwallet_.InitWithKWalletDBus(
+ std::unique_ptr<MockKWalletDBus>(kwallet_dbus_mock_)));
+}
+
+TEST_F(KeyStorageKWalletTest, InitFailTwice) {
+ EXPECT_CALL(*kwallet_dbus_mock_, IsEnabled(_))
+ .WillOnce(Return(CANNOT_CONTACT))
+ .WillOnce(Return(CANNOT_CONTACT));
+ EXPECT_CALL(*kwallet_dbus_mock_, StartKWalletd()).WillOnce(Return(true));
+
+ EXPECT_FALSE(key_storage_kwallet_.InitWithKWalletDBus(
+ std::unique_ptr<MockKWalletDBus>(kwallet_dbus_mock_)));
+}
+
+TEST_F(KeyStorageKWalletTest, InitTryTwiceAndFail) {
+ EXPECT_CALL(*kwallet_dbus_mock_, IsEnabled(_))
+ .WillOnce(Return(CANNOT_CONTACT))
+ .WillOnce(DoAll(SetArgPointee<0>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, StartKWalletd()).WillOnce(Return(true));
+ EXPECT_CALL(*kwallet_dbus_mock_, NetworkWallet(_))
+ .WillOnce(Return(CANNOT_CONTACT));
+
+ EXPECT_FALSE(key_storage_kwallet_.InitWithKWalletDBus(
+ std::unique_ptr<MockKWalletDBus>(kwallet_dbus_mock_)));
+}
+
+TEST_F(KeyStorageKWalletTest, InitTryTwiceAndSuccess) {
+ EXPECT_CALL(*kwallet_dbus_mock_, IsEnabled(_))
+ .WillOnce(Return(CANNOT_CONTACT))
+ .WillOnce(DoAll(SetArgPointee<0>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, StartKWalletd()).WillOnce(Return(true));
+ EXPECT_CALL(*kwallet_dbus_mock_, NetworkWallet(_))
+ .WillOnce(DoAll(SetArgPointee<0>(wallet_name_), Return(SUCCESS)));
+
+ EXPECT_TRUE(key_storage_kwallet_.InitWithKWalletDBus(
+ std::unique_ptr<MockKWalletDBus>(kwallet_dbus_mock_)));
+}
+
+// Tests for a dbus connection that fails after initialization.
+// Any error is expected to return an empty password.
+class KeyStorageKWalletFailuresTest
+ : public testing::TestWithParam<KWalletDBus::Error> {
+ public:
+ KeyStorageKWalletFailuresTest()
+ : key_storage_kwallet_(kDesktopEnv, "test-app") {}
+
+ void SetUp() override {
+ // |key_storage_kwallet_| will take ownership of |kwallet_dbus_mock_|.
+ kwallet_dbus_mock_ = new StrictMock<MockKWalletDBus>();
+
+ // Successful initialization.
+ EXPECT_CALL(*kwallet_dbus_mock_, IsEnabled(_))
+ .WillOnce(DoAll(SetArgPointee<0>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, NetworkWallet(_))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(std::string("mollet")), Return(SUCCESS)));
+
+ EXPECT_TRUE(key_storage_kwallet_.InitWithKWalletDBus(
+ std::unique_ptr<MockKWalletDBus>(kwallet_dbus_mock_)));
+
+ // Calls from |key_storage_kwallet_|'s destructor.
+ EXPECT_CALL(*kwallet_dbus_mock_, Close(_, false, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_->GetSessionBus(), ShutdownAndBlock())
+ .Times(1);
+ }
+
+ protected:
+ StrictMock<MockKWalletDBus>* kwallet_dbus_mock_;
+ KeyStorageKWallet key_storage_kwallet_;
+ const std::string wallet_name_ = "mollet";
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(KeyStorageKWalletFailuresTest);
+};
+
+INSTANTIATE_TEST_CASE_P(,
+ KeyStorageKWalletFailuresTest,
+ ::testing::Values(CANNOT_READ, CANNOT_CONTACT));
+
+TEST_P(KeyStorageKWalletFailuresTest, PostInitFailureOpen) {
+ EXPECT_CALL(*kwallet_dbus_mock_, Open(_, _, _)).WillOnce(Return(GetParam()));
+
+ EXPECT_EQ("", key_storage_kwallet_.GetKey());
+}
+
+TEST_P(KeyStorageKWalletFailuresTest, PostInitFailureHasFolder) {
+ EXPECT_CALL(*kwallet_dbus_mock_, Open(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(123), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, HasFolder(123, _, _, _))
+ .WillOnce(Return(GetParam()));
+
+ EXPECT_EQ("", key_storage_kwallet_.GetKey());
+}
+
+TEST_P(KeyStorageKWalletFailuresTest, PostInitFailureCreateFolder) {
+ EXPECT_CALL(*kwallet_dbus_mock_, Open(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(123), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, HasFolder(123, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(false), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, CreateFolder(123, _, _, _))
+ .WillOnce(Return(GetParam()));
+
+ EXPECT_EQ("", key_storage_kwallet_.GetKey());
+}
+
+TEST_P(KeyStorageKWalletFailuresTest, PostInitFailureReadPassword) {
+ EXPECT_CALL(*kwallet_dbus_mock_, Open(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(123), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, HasFolder(123, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, ReadPassword(123, _, _, _, _))
+ .WillOnce(Return(GetParam()));
+
+ EXPECT_EQ("", key_storage_kwallet_.GetKey());
+}
+
+TEST_P(KeyStorageKWalletFailuresTest, PostInitFailureWritePassword) {
+ EXPECT_CALL(*kwallet_dbus_mock_, Open(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(123), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, HasFolder(123, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(true), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, ReadPassword(123, _, _, _, _))
+ .WillOnce(DoAll(SetArgPointee<4>(""), Return(SUCCESS)));
+ EXPECT_CALL(*kwallet_dbus_mock_, WritePassword(123, _, _, _, _, _))
+ .WillOnce(Return(GetParam()));
+
+ EXPECT_EQ("", key_storage_kwallet_.GetKey());
+}
+
+} // namespace
diff --git a/chromium/components/os_crypt/key_storage_libsecret.cc b/chromium/components/os_crypt/key_storage_libsecret.cc
index 839ecdc189a..ea034fd48c0 100644
--- a/chromium/components/os_crypt/key_storage_libsecret.cc
+++ b/chromium/components/os_crypt/key_storage_libsecret.cc
@@ -12,47 +12,85 @@
namespace {
#if defined(GOOGLE_CHROME_BUILD)
-const char kKeyStorageEntryName[] = "Chrome Safe Storage";
+const char kApplicationName[] = "chrome";
#else
-const char kKeyStorageEntryName[] = "Chromium Safe Storage";
+const char kApplicationName[] = "chromium";
#endif
-const SecretSchema kKeystoreSchema = {
+// Deprecated in M55 (crbug.com/639298)
+const SecretSchema kKeystoreSchemaV1 = {
"chrome_libsecret_os_crypt_password",
SECRET_SCHEMA_NONE,
{
{nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
}};
-std::string AddRandomPasswordInLibsecret() {
+const SecretSchema kKeystoreSchemaV2 = {
+ "chrome_libsecret_os_crypt_password_v2",
+ SECRET_SCHEMA_DONT_MATCH_NAME,
+ {
+ {"application", SECRET_SCHEMA_ATTRIBUTE_STRING},
+ {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
+ }};
+
+// From a search result, extracts a SecretValue, asserting that there was at
+// most one result. Returns nullptr if there are no results.
+SecretValue* ToSingleSecret(GList* secret_items) {
+ GList* first = g_list_first(secret_items);
+ if (first == nullptr)
+ return nullptr;
+ if (g_list_next(first) != nullptr) {
+ VLOG(1) << "OSCrypt found more than one encryption keys.";
+ }
+ SecretItem* secret_item = static_cast<SecretItem*>(first->data);
+ SecretValue* secret_value =
+ LibsecretLoader::secret_item_get_secret(secret_item);
+ g_list_free(secret_items);
+ return secret_value;
+}
+
+} // namespace
+
+std::string KeyStorageLibsecret::AddRandomPasswordInLibsecret() {
std::string password;
base::Base64Encode(base::RandBytesAsString(16), &password);
GError* error = nullptr;
- LibsecretLoader::secret_password_store_sync(
- &kKeystoreSchema, nullptr, kKeyStorageEntryName, password.c_str(),
- nullptr, &error, nullptr);
-
+ bool success = LibsecretLoader::secret_password_store_sync(
+ &kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(),
+ nullptr, &error, "application", kApplicationName, nullptr);
if (error) {
VLOG(1) << "Libsecret lookup failed: " << error->message;
+ g_error_free(error);
return std::string();
}
+ if (!success) {
+ VLOG(1) << "Libsecret lookup failed.";
+ return std::string();
+ }
+
+ VLOG(1) << "OSCrypt generated a new password.";
return password;
}
-} // namespace
-
std::string KeyStorageLibsecret::GetKey() {
GError* error = nullptr;
LibsecretAttributesBuilder attrs;
- SecretValue* password_libsecret = LibsecretLoader::secret_service_lookup_sync(
- nullptr, &kKeystoreSchema, attrs.Get(), nullptr, &error);
-
+ attrs.Append("application", kApplicationName);
+ GList* search_results = LibsecretLoader::secret_service_search_sync(
+ nullptr /* default secret service */, &kKeystoreSchemaV2, attrs.Get(),
+ static_cast<SecretSearchFlags>(SECRET_SEARCH_UNLOCK |
+ SECRET_SEARCH_LOAD_SECRETS),
+ nullptr, &error);
if (error) {
VLOG(1) << "Libsecret lookup failed: " << error->message;
g_error_free(error);
return std::string();
}
+ SecretValue* password_libsecret = ToSingleSecret(search_results);
if (!password_libsecret) {
+ std::string password = Migrate();
+ if (!password.empty())
+ return password;
return AddRandomPasswordInLibsecret();
}
std::string password(
@@ -62,5 +100,61 @@ std::string KeyStorageLibsecret::GetKey() {
}
bool KeyStorageLibsecret::Init() {
- return LibsecretLoader::EnsureLibsecretLoaded();
+ bool loaded = LibsecretLoader::EnsureLibsecretLoaded();
+ if (loaded)
+ LibsecretLoader::EnsureKeyringUnlocked();
+ return loaded;
+}
+
+std::string KeyStorageLibsecret::Migrate() {
+ GError* error = nullptr;
+ LibsecretAttributesBuilder attrs;
+
+ // Detect old entry.
+ GList* search_results = LibsecretLoader::secret_service_search_sync(
+ nullptr /* default secret service */, &kKeystoreSchemaV1, attrs.Get(),
+ static_cast<SecretSearchFlags>(SECRET_SEARCH_UNLOCK |
+ SECRET_SEARCH_LOAD_SECRETS),
+ nullptr, &error);
+ if (error) {
+ g_error_free(error);
+ g_list_free(search_results);
+ return std::string();
+ }
+ SecretValue* password_libsecret = ToSingleSecret(search_results);
+ if (!password_libsecret)
+ return std::string();
+
+ VLOG(1) << "OSCrypt detected a deprecated password in Libsecret.";
+ std::string password(
+ LibsecretLoader::secret_value_get_text(password_libsecret));
+ LibsecretLoader::secret_value_unref(password_libsecret);
+
+ // Create new entry.
+ bool success = LibsecretLoader::secret_password_store_sync(
+ &kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(),
+ nullptr, &error, "application", kApplicationName, nullptr);
+ if (error) {
+ VLOG(1) << "Failed to store migrated password. " << error->message;
+ g_error_free(error);
+ return std::string();
+ }
+ if (!success) {
+ VLOG(1) << "Failed to store migrated password.";
+ return std::string();
+ }
+
+ // Delete old entry.
+ // Even if deletion failed, we have to use the password that we created.
+ success = LibsecretLoader::secret_password_clear_sync(
+ &kKeystoreSchemaV1, nullptr, &error, nullptr);
+ if (error) {
+ VLOG(1) << "OSCrypt failed to delete deprecated password. "
+ << error->message;
+ g_error_free(error);
+ }
+
+ VLOG(1) << "OSCrypt migrated from deprecated password.";
+
+ return password;
}
diff --git a/chromium/components/os_crypt/key_storage_libsecret.h b/chromium/components/os_crypt/key_storage_libsecret.h
index 4899be8205b..18f7ad34de6 100644
--- a/chromium/components/os_crypt/key_storage_libsecret.h
+++ b/chromium/components/os_crypt/key_storage_libsecret.h
@@ -24,6 +24,14 @@ class KeyStorageLibsecret : public KeyStorageLinux {
bool Init() override;
private:
+ std::string AddRandomPasswordInLibsecret();
+
+ // TODO(crbug.com/639298) Older Chromium releases stored passwords with a
+ // problematic schema. Detect password entries with the old schema and migrate
+ // them to the new schema. Returns the migrated password or an empty string if
+ // none we migrated.
+ std::string Migrate();
+
DISALLOW_COPY_AND_ASSIGN(KeyStorageLibsecret);
};
diff --git a/chromium/components/os_crypt/key_storage_libsecret_unittest.cc b/chromium/components/os_crypt/key_storage_libsecret_unittest.cc
new file mode 100644
index 00000000000..aa1953a92a0
--- /dev/null
+++ b/chromium/components/os_crypt/key_storage_libsecret_unittest.cc
@@ -0,0 +1,245 @@
+// 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 <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "components/os_crypt/key_storage_libsecret.h"
+#include "components/os_crypt/libsecret_util_linux.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Mock functions use MockSecretValue, where SecretValue would appear, and are
+// cast to the correct signature. We can reduce SecretValue to an std::string,
+// because we don't use anything else from it.
+using MockSecretValue = std::string;
+// Likewise, we only need a SecretValue from SecretItem.
+using MockSecretItem = MockSecretValue;
+
+const SecretSchema kKeystoreSchemaV1 = {
+ "chrome_libsecret_os_crypt_password",
+ SECRET_SCHEMA_NONE,
+ {
+ {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
+ }};
+
+const SecretSchema kKeystoreSchemaV2 = {
+ "chrome_libsecret_os_crypt_password_v2",
+ SECRET_SCHEMA_DONT_MATCH_NAME,
+ {
+ {"application", SECRET_SCHEMA_ATTRIBUTE_STRING},
+ {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
+ }};
+
+// Replaces some of LibsecretLoader's methods with mocked ones.
+class MockLibsecretLoader : public LibsecretLoader {
+ public:
+ // Sets up the minimum mock implementation necessary for OSCrypt to work
+ // with Libsecret. Also resets the state to mock a clean database.
+ static bool ResetForOSCrypt();
+
+ // Sets OSCrypt's password in the libsecret mock to a specific value
+ static void SetOSCryptPassword(const char*);
+
+ // Releases memory and restores LibsecretLoader to an uninitialized state.
+ static void TearDown();
+
+ // Set whether there is an old password that needs to be migrated from the
+ // deprecated schema. Null means no such password. See crbug.com/639298
+ static void SetDeprecatedOSCryptPassword(const char* value);
+
+ private:
+ // These methods are used to redirect calls through LibsecretLoader
+ static const gchar* mock_secret_value_get_text(MockSecretValue* value);
+
+ static gboolean mock_secret_password_store_sync(const SecretSchema* schema,
+ const gchar* collection,
+ const gchar* label,
+ const gchar* password,
+ GCancellable* cancellable,
+ GError** error,
+ ...);
+
+ static void mock_secret_value_unref(gpointer value);
+
+ static GList* mock_secret_service_search_sync(SecretService* service,
+ const SecretSchema* schema,
+ GHashTable* attributes,
+ SecretSearchFlags flags,
+ GCancellable* cancellable,
+ GError** error);
+
+ static gboolean mock_secret_password_clear_sync(const SecretSchema* schema,
+ GCancellable* cancellable,
+ GError** error,
+ ...);
+
+ static MockSecretValue* mock_secret_item_get_secret(MockSecretItem* item);
+
+ // MockLibsecretLoader owns these objects.
+ static MockSecretValue* stored_password_mock_ptr_;
+ static MockSecretValue* deprecated_password_mock_ptr_;
+};
+
+MockSecretValue* MockLibsecretLoader::stored_password_mock_ptr_ = nullptr;
+MockSecretValue* MockLibsecretLoader::deprecated_password_mock_ptr_ = nullptr;
+
+const gchar* MockLibsecretLoader::mock_secret_value_get_text(
+ MockSecretValue* value) {
+ return value->c_str();
+}
+
+// static
+gboolean MockLibsecretLoader::mock_secret_password_store_sync(
+ const SecretSchema* schema,
+ const gchar* collection,
+ const gchar* label,
+ const gchar* password,
+ GCancellable* cancellable,
+ GError** error,
+ ...) {
+ // TODO(crbug.com/660005) We don't read the dummy we store to unlock keyring.
+ if (strcmp("_chrome_dummy_schema_for_unlocking", schema->name) == 0)
+ return true;
+
+ EXPECT_STREQ(kKeystoreSchemaV2.name, schema->name);
+ delete stored_password_mock_ptr_;
+ stored_password_mock_ptr_ = new MockSecretValue(password);
+ return true;
+}
+
+// static
+void MockLibsecretLoader::mock_secret_value_unref(gpointer value) {}
+
+// static
+GList* MockLibsecretLoader::mock_secret_service_search_sync(
+ SecretService* service,
+ const SecretSchema* schema,
+ GHashTable* attributes,
+ SecretSearchFlags flags,
+ GCancellable* cancellable,
+ GError** error) {
+ bool is_known_schema = strcmp(schema->name, kKeystoreSchemaV2.name) == 0 ||
+ strcmp(schema->name, kKeystoreSchemaV1.name) == 0;
+ EXPECT_TRUE(is_known_schema);
+
+ EXPECT_TRUE(flags & SECRET_SEARCH_UNLOCK);
+ EXPECT_TRUE(flags & SECRET_SEARCH_LOAD_SECRETS);
+
+ MockSecretItem* item = nullptr;
+ if (strcmp(schema->name, kKeystoreSchemaV2.name) == 0)
+ item = stored_password_mock_ptr_;
+ else if (strcmp(schema->name, kKeystoreSchemaV1.name) == 0)
+ item = deprecated_password_mock_ptr_;
+
+ GList* result = nullptr;
+ result = g_list_append(result, item);
+ g_clear_error(error);
+ return result;
+}
+
+// static
+gboolean MockLibsecretLoader::mock_secret_password_clear_sync(
+ const SecretSchema* schema,
+ GCancellable* cancellable,
+ GError** error,
+ ...) {
+ // We would only delete entries in the deprecated schema.
+ EXPECT_STREQ(kKeystoreSchemaV1.name, schema->name);
+ delete deprecated_password_mock_ptr_;
+ deprecated_password_mock_ptr_ = nullptr;
+ return true;
+}
+
+// static
+MockSecretValue* MockLibsecretLoader::mock_secret_item_get_secret(
+ MockSecretItem* item) {
+ return item;
+}
+
+// static
+bool MockLibsecretLoader::ResetForOSCrypt() {
+ // Methods used by KeyStorageLibsecret
+ secret_password_store_sync =
+ &MockLibsecretLoader::mock_secret_password_store_sync;
+ secret_value_get_text = (decltype(&::secret_value_get_text)) &
+ MockLibsecretLoader::mock_secret_value_get_text;
+ secret_value_unref = &MockLibsecretLoader::mock_secret_value_unref;
+ secret_service_search_sync =
+ &MockLibsecretLoader::mock_secret_service_search_sync;
+ secret_item_get_secret =
+ (decltype(&::secret_item_get_secret))mock_secret_item_get_secret;
+ // Used by Migrate()
+ secret_password_clear_sync =
+ &MockLibsecretLoader::mock_secret_password_clear_sync;
+
+ delete stored_password_mock_ptr_;
+ stored_password_mock_ptr_ = nullptr;
+ libsecret_loaded_ = true;
+
+ return true;
+}
+
+// static
+void MockLibsecretLoader::SetOSCryptPassword(const char* value) {
+ delete stored_password_mock_ptr_;
+ stored_password_mock_ptr_ = new MockSecretValue(value);
+}
+
+// static
+void MockLibsecretLoader::SetDeprecatedOSCryptPassword(const char* value) {
+ delete deprecated_password_mock_ptr_;
+ deprecated_password_mock_ptr_ = new MockSecretValue(value);
+}
+
+// static
+void MockLibsecretLoader::TearDown() {
+ delete stored_password_mock_ptr_;
+ stored_password_mock_ptr_ = nullptr;
+ libsecret_loaded_ =
+ false; // Function pointers will be restored when loading.
+}
+
+class LibsecretTest : public testing::Test {
+ public:
+ LibsecretTest() = default;
+ ~LibsecretTest() override = default;
+
+ void SetUp() override { MockLibsecretLoader::ResetForOSCrypt(); }
+
+ void TearDown() override { MockLibsecretLoader::TearDown(); }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LibsecretTest);
+};
+
+TEST_F(LibsecretTest, LibsecretRepeats) {
+ KeyStorageLibsecret libsecret;
+ MockLibsecretLoader::ResetForOSCrypt();
+ std::string password = libsecret.GetKey();
+ EXPECT_FALSE(password.empty());
+ std::string password_repeat = libsecret.GetKey();
+ EXPECT_EQ(password, password_repeat);
+}
+
+TEST_F(LibsecretTest, LibsecretCreatesRandomised) {
+ KeyStorageLibsecret libsecret;
+ MockLibsecretLoader::ResetForOSCrypt();
+ std::string password = libsecret.GetKey();
+ MockLibsecretLoader::ResetForOSCrypt();
+ std::string password_new = libsecret.GetKey();
+ EXPECT_NE(password, password_new);
+}
+
+TEST_F(LibsecretTest, LibsecretMigratesFromSchemaV1ToV2) {
+ KeyStorageLibsecret libsecret;
+ MockLibsecretLoader::ResetForOSCrypt();
+ MockLibsecretLoader::SetDeprecatedOSCryptPassword("swallow");
+ std::string password = libsecret.GetKey();
+ EXPECT_EQ("swallow", password);
+}
+
+} // namespace
diff --git a/chromium/components/os_crypt/key_storage_linux.cc b/chromium/components/os_crypt/key_storage_linux.cc
index e54bb9e6719..b54fe0d2155 100644
--- a/chromium/components/os_crypt/key_storage_linux.cc
+++ b/chromium/components/os_crypt/key_storage_linux.cc
@@ -4,54 +4,116 @@
#include "components/os_crypt/key_storage_linux.h"
-#include <string.h>
-
#include "base/environment.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/nix/xdg_util.h"
+#include "base/single_thread_task_runner.h"
+#include "components/os_crypt/key_storage_util_linux.h"
#if defined(USE_LIBSECRET)
#include "components/os_crypt/key_storage_libsecret.h"
#endif
+#if defined(USE_KEYRING)
+#include "components/os_crypt/key_storage_keyring.h"
+#endif
+#if defined(USE_KWALLET)
+#include "components/os_crypt/key_storage_kwallet.h"
+#endif
+
+#if defined(GOOGLE_CHROME_BUILD)
+const char KeyStorageLinux::kFolderName[] = "Chrome Keys";
+const char KeyStorageLinux::kKey[] = "Chrome Safe Storage";
+#else
+const char KeyStorageLinux::kFolderName[] = "Chromium Keys";
+const char KeyStorageLinux::kKey[] = "Chromium Safe Storage";
+#endif
+
+namespace {
+
+// Parameters to OSCrypt, which are set before the first call to OSCrypt, are
+// stored here.
+struct Configuration {
+ std::string store;
+ std::string product_name;
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner;
+};
-base::LazyInstance<std::string> g_store_ = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<Configuration> g_config = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
// static
void KeyStorageLinux::SetStore(const std::string& store_type) {
- g_store_.Get() = store_type;
+ g_config.Get().store = store_type;
VLOG(1) << "OSCrypt store set to " << store_type;
}
// static
+void KeyStorageLinux::SetProductName(const std::string& product_name) {
+ g_config.Get().product_name = product_name;
+}
+
+// static
+void KeyStorageLinux::SetMainThreadRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner) {
+ g_config.Get().main_thread_runner = main_thread_runner;
+}
+
+// static
std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateService() {
- base::nix::DesktopEnvironment used_desktop_env;
- if (g_store_.Get() == "kwallet") {
- used_desktop_env = base::nix::DESKTOP_ENVIRONMENT_KDE4;
- } else if (g_store_.Get() == "kwallet5") {
- used_desktop_env = base::nix::DESKTOP_ENVIRONMENT_KDE5;
- } else if (g_store_.Get() == "gnome") {
- used_desktop_env = base::nix::DESKTOP_ENVIRONMENT_GNOME;
- } else if (g_store_.Get() == "basic") {
- used_desktop_env = base::nix::DESKTOP_ENVIRONMENT_OTHER;
- } else {
- std::unique_ptr<base::Environment> env(base::Environment::Create());
- used_desktop_env = base::nix::GetDesktopEnvironment(env.get());
- }
+#if defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
+ // Select a backend.
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ base::nix::DesktopEnvironment desktop_env =
+ base::nix::GetDesktopEnvironment(env.get());
+ os_crypt::SelectedLinuxBackend selected_backend =
+ os_crypt::SelectBackend(g_config.Get().store, desktop_env);
- // Try initializing the appropriate store for our environment.
+ // Try initializing the selected backend.
+ // In case of GNOME_ANY, prefer Libsecret
std::unique_ptr<KeyStorageLinux> key_storage;
- if (used_desktop_env == base::nix::DESKTOP_ENVIRONMENT_GNOME ||
- used_desktop_env == base::nix::DESKTOP_ENVIRONMENT_UNITY ||
- used_desktop_env == base::nix::DESKTOP_ENVIRONMENT_XFCE) {
+
#if defined(USE_LIBSECRET)
+ if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
+ selected_backend == os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET) {
key_storage.reset(new KeyStorageLibsecret());
if (key_storage->Init()) {
VLOG(1) << "OSCrypt using Libsecret as backend.";
return key_storage;
}
-#endif
}
+#endif // defined(USE_LIBSECRET)
+
+#if defined(USE_KEYRING)
+ if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
+ selected_backend == os_crypt::SelectedLinuxBackend::GNOME_KEYRING) {
+ key_storage.reset(new KeyStorageKeyring(g_config.Get().main_thread_runner));
+ if (key_storage->Init()) {
+ VLOG(1) << "OSCrypt using Keyring as backend.";
+ return key_storage;
+ }
+ }
+#endif // defined(USE_KEYRING)
+
+#if defined(USE_KWALLET)
+ if (selected_backend == os_crypt::SelectedLinuxBackend::KWALLET ||
+ selected_backend == os_crypt::SelectedLinuxBackend::KWALLET5) {
+ DCHECK(!g_config.Get().product_name.empty());
+ base::nix::DesktopEnvironment used_desktop_env =
+ selected_backend == os_crypt::SelectedLinuxBackend::KWALLET
+ ? base::nix::DESKTOP_ENVIRONMENT_KDE4
+ : base::nix::DESKTOP_ENVIRONMENT_KDE5;
+ key_storage.reset(
+ new KeyStorageKWallet(used_desktop_env, g_config.Get().product_name));
+ if (key_storage->Init()) {
+ VLOG(1) << "OSCrypt using KWallet as backend.";
+ return key_storage;
+ }
+ }
+#endif // defined(USE_KWALLET)
+#endif // defined(USE_LIBSECRET) || defined(USE_KEYRING) ||
+ // defined(USE_KWALLET)
// The appropriate store was not available.
VLOG(1) << "OSCrypt could not initialize a backend.";
diff --git a/chromium/components/os_crypt/key_storage_linux.h b/chromium/components/os_crypt/key_storage_linux.h
index b8ef53bcf1c..394b6b38173 100644
--- a/chromium/components/os_crypt/key_storage_linux.h
+++ b/chromium/components/os_crypt/key_storage_linux.h
@@ -9,6 +9,11 @@
#include <string>
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
// An API for retrieving OSCrypt's password from the system's password storage
// service.
@@ -20,6 +25,15 @@ class KeyStorageLinux {
// Force OSCrypt to use a specific linux password store.
static void SetStore(const std::string& store_type);
+ // The product name to use for permission prompts.
+ static void SetProductName(const std::string& product_name);
+
+ // A runner on the main thread for gnome-keyring to be called from.
+ // TODO(crbug/466975): Libsecret and KWallet don't need this. We can remove
+ // this when we stop supporting keyring.
+ static void SetMainThreadRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner);
+
// Tries to load the appropriate key storage. Returns null if none succeed.
static std::unique_ptr<KeyStorageLinux> CreateService();
@@ -31,6 +45,11 @@ class KeyStorageLinux {
// Loads the key storage. Returns false if the service is not available.
virtual bool Init() = 0;
+ // The name of the group, if any, containing the key.
+ static const char kFolderName[];
+ // The name of the entry with the encryption key.
+ static const char kKey[];
+
private:
DISALLOW_COPY_AND_ASSIGN(KeyStorageLinux);
};
diff --git a/chromium/components/os_crypt/key_storage_util_linux.cc b/chromium/components/os_crypt/key_storage_util_linux.cc
new file mode 100644
index 00000000000..5be4252e58c
--- /dev/null
+++ b/chromium/components/os_crypt/key_storage_util_linux.cc
@@ -0,0 +1,50 @@
+// 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 "components/os_crypt/key_storage_util_linux.h"
+
+#include "base/logging.h"
+
+namespace os_crypt {
+
+SelectedLinuxBackend SelectBackend(const std::string& type,
+ base::nix::DesktopEnvironment desktop_env) {
+ if (type == "kwallet")
+ return SelectedLinuxBackend::KWALLET;
+ if (type == "kwallet5")
+ return SelectedLinuxBackend::KWALLET5;
+ if (type == "gnome")
+ return SelectedLinuxBackend::GNOME_ANY;
+ if (type == "gnome-keyring")
+ return SelectedLinuxBackend::GNOME_KEYRING;
+ if (type == "gnome-libsecret")
+ return SelectedLinuxBackend::GNOME_LIBSECRET;
+ if (type == "basic")
+ return SelectedLinuxBackend::BASIC_TEXT;
+
+ const char* name = base::nix::GetDesktopEnvironmentName(desktop_env);
+ VLOG(1) << "Password storage detected desktop environment: "
+ << (name ? name : "(unknown)");
+
+ // Detect the store to use automatically.
+ switch (desktop_env) {
+ case base::nix::DESKTOP_ENVIRONMENT_KDE4:
+ return SelectedLinuxBackend::KWALLET;
+ case base::nix::DESKTOP_ENVIRONMENT_KDE5:
+ return SelectedLinuxBackend::KWALLET5;
+ case base::nix::DESKTOP_ENVIRONMENT_GNOME:
+ case base::nix::DESKTOP_ENVIRONMENT_UNITY:
+ case base::nix::DESKTOP_ENVIRONMENT_XFCE:
+ return SelectedLinuxBackend::GNOME_ANY;
+ // KDE3 didn't use DBus, which our KWallet store uses.
+ case base::nix::DESKTOP_ENVIRONMENT_KDE3:
+ case base::nix::DESKTOP_ENVIRONMENT_OTHER:
+ return SelectedLinuxBackend::BASIC_TEXT;
+ }
+
+ NOTREACHED();
+ return SelectedLinuxBackend::BASIC_TEXT;
+}
+
+} // namespace os_crypt
diff --git a/chromium/components/os_crypt/key_storage_util_linux.h b/chromium/components/os_crypt/key_storage_util_linux.h
new file mode 100644
index 00000000000..d5c04b6e70b
--- /dev/null
+++ b/chromium/components/os_crypt/key_storage_util_linux.h
@@ -0,0 +1,35 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OS_CRYPT_KEY_STORAGE_UTIL_LINUX_H_
+#define COMPONENTS_OS_CRYPT_KEY_STORAGE_UTIL_LINUX_H_
+
+#include <string>
+
+#include "base/nix/xdg_util.h"
+
+namespace os_crypt {
+
+// The supported Linux backends for storing passwords.
+enum class SelectedLinuxBackend {
+ DEFER, // No selection
+ BASIC_TEXT,
+ GNOME_ANY, // GNOME_KEYRING or GNOME_LIBSECRET, whichever is available.
+ GNOME_KEYRING,
+ GNOME_LIBSECRET,
+ KWALLET,
+ KWALLET5,
+};
+
+// Decide which backend to target. |type| is checked first. If it does not
+// match a supported backend, |desktop_env| will be used to decide.
+// TODO(crbug/571003): This is exposed as a utility only for password manager to
+// use. It should be merged into key_storage_linux, once no longer needed in
+// password manager.
+SelectedLinuxBackend SelectBackend(const std::string& type,
+ base::nix::DesktopEnvironment desktop_env);
+
+} // namespace os_crypt
+
+#endif // COMPONENTS_OS_CRYPT_KEY_STORAGE_UTIL_LINUX_H_
diff --git a/chromium/components/os_crypt/keychain_password_mac.mm b/chromium/components/os_crypt/keychain_password_mac.mm
index 2ce10cde443..1f60b9f0572 100644
--- a/chromium/components/os_crypt/keychain_password_mac.mm
+++ b/chromium/components/os_crypt/keychain_password_mac.mm
@@ -51,7 +51,7 @@ std::string KeychainPassword::GetPassword() const {
// These two strings ARE indeed user facing. But they are used to access
// the encryption keyword. So as to not lose encrypted data when system
// locale changes we DO NOT LOCALIZE.
-#if defined(OFFICIAL_BUILD)
+#if defined(GOOGLE_CHROME_BUILD)
const std::string service_name = "Chrome Safe Storage";
const std::string account_name = "Chrome";
#else
diff --git a/chromium/components/os_crypt/keyring_util_linux.cc b/chromium/components/os_crypt/keyring_util_linux.cc
new file mode 100644
index 00000000000..aa67be03fd9
--- /dev/null
+++ b/chromium/components/os_crypt/keyring_util_linux.cc
@@ -0,0 +1,95 @@
+// 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 "components/os_crypt/keyring_util_linux.h"
+
+#include <dlfcn.h>
+
+#include "base/logging.h"
+
+decltype(&::gnome_keyring_is_available)
+ GnomeKeyringLoader::gnome_keyring_is_available_ptr;
+decltype(&::gnome_keyring_store_password)
+ GnomeKeyringLoader::gnome_keyring_store_password_ptr;
+decltype(&::gnome_keyring_delete_password)
+ GnomeKeyringLoader::gnome_keyring_delete_password_ptr;
+decltype(&::gnome_keyring_find_items)
+ GnomeKeyringLoader::gnome_keyring_find_items_ptr;
+decltype(&::gnome_keyring_find_password_sync)
+ GnomeKeyringLoader::gnome_keyring_find_password_sync_ptr;
+decltype(&::gnome_keyring_store_password_sync)
+ GnomeKeyringLoader::gnome_keyring_store_password_sync_ptr;
+
+decltype(&::gnome_keyring_result_to_message)
+ GnomeKeyringLoader::gnome_keyring_result_to_message_ptr;
+decltype(&::gnome_keyring_attribute_list_free)
+ GnomeKeyringLoader::gnome_keyring_attribute_list_free_ptr;
+decltype(&::gnome_keyring_attribute_list_new)
+ GnomeKeyringLoader::gnome_keyring_attribute_list_new_ptr;
+decltype(&::gnome_keyring_attribute_list_append_string)
+ GnomeKeyringLoader::gnome_keyring_attribute_list_append_string_ptr;
+decltype(&::gnome_keyring_attribute_list_append_uint32)
+ GnomeKeyringLoader::gnome_keyring_attribute_list_append_uint32_ptr;
+decltype(&::gnome_keyring_free_password)
+ GnomeKeyringLoader::gnome_keyring_free_password_ptr;
+
+bool GnomeKeyringLoader::keyring_loaded = false;
+
+const GnomeKeyringLoader::FunctionInfo GnomeKeyringLoader::functions[] = {
+ {"gnome_keyring_is_available",
+ reinterpret_cast<void**>(&gnome_keyring_is_available_ptr)},
+ {"gnome_keyring_store_password",
+ reinterpret_cast<void**>(&gnome_keyring_store_password_ptr)},
+ {"gnome_keyring_delete_password",
+ reinterpret_cast<void**>(&gnome_keyring_delete_password_ptr)},
+ {"gnome_keyring_find_items",
+ reinterpret_cast<void**>(&gnome_keyring_find_items_ptr)},
+ {"gnome_keyring_find_password_sync",
+ reinterpret_cast<void**>(&gnome_keyring_find_password_sync_ptr)},
+ {"gnome_keyring_store_password_sync",
+ reinterpret_cast<void**>(&gnome_keyring_store_password_sync_ptr)},
+
+ {"gnome_keyring_result_to_message",
+ reinterpret_cast<void**>(&gnome_keyring_result_to_message_ptr)},
+ {"gnome_keyring_attribute_list_free",
+ reinterpret_cast<void**>(&gnome_keyring_attribute_list_free_ptr)},
+ {"gnome_keyring_attribute_list_new",
+ reinterpret_cast<void**>(&gnome_keyring_attribute_list_new_ptr)},
+ {"gnome_keyring_attribute_list_append_string",
+ reinterpret_cast<void**>(&gnome_keyring_attribute_list_append_string_ptr)},
+ {"gnome_keyring_attribute_list_append_uint32",
+ reinterpret_cast<void**>(&gnome_keyring_attribute_list_append_uint32_ptr)},
+ {"gnome_keyring_free_password",
+ reinterpret_cast<void**>(&gnome_keyring_free_password_ptr)}};
+
+/* Load the library and initialize the function pointers. */
+bool GnomeKeyringLoader::LoadGnomeKeyring() {
+ if (keyring_loaded)
+ return true;
+
+ void* handle = dlopen("libgnome-keyring.so.0", RTLD_NOW | RTLD_GLOBAL);
+ if (!handle) {
+ // We wanted to use GNOME Keyring, but we couldn't load it. Warn, because
+ // either the user asked for this, or we autodetected it incorrectly. (Or
+ // the system has broken libraries, which is also good to warn about.)
+ LOG(WARNING) << "Could not load libgnome-keyring.so.0: " << dlerror();
+ return false;
+ }
+
+ for (size_t i = 0; i < arraysize(functions); ++i) {
+ dlerror();
+ *functions[i].pointer = dlsym(handle, functions[i].name);
+ const char* error = dlerror();
+ if (error) {
+ LOG(ERROR) << "Unable to load symbol " << functions[i].name << ": "
+ << error;
+ dlclose(handle);
+ return false;
+ }
+ }
+
+ keyring_loaded = true;
+ // We leak the library handle. That's OK: this function is called only once.
+ return true;
+}
diff --git a/chromium/components/os_crypt/keyring_util_linux.h b/chromium/components/os_crypt/keyring_util_linux.h
new file mode 100644
index 00000000000..fccde49f43e
--- /dev/null
+++ b/chromium/components/os_crypt/keyring_util_linux.h
@@ -0,0 +1,76 @@
+// 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 COMPONENTS_OS_CRYPT_KEYRING_UTIL_LINUX_H_
+#define COMPONENTS_OS_CRYPT_KEYRING_UTIL_LINUX_H_
+
+// libgnome-keyring has been deprecated in favor of libsecret.
+// See: https://mail.gnome.org/archives/commits-list/2013-October/msg08876.html
+//
+// The define below turns off the deprecations, in order to avoid build
+// failures with Gnome 3.12. When we move to libsecret, the define can be
+// removed, together with the include below it.
+//
+// The porting is tracked in http://crbug.com/355223
+#define GNOME_KEYRING_DEPRECATED
+#define GNOME_KEYRING_DEPRECATED_FOR(x)
+#include <gnome-keyring.h>
+
+#include "base/macros.h"
+
+// Many of the gnome_keyring_* functions use variable arguments, which makes
+// them difficult if not impossible to truly wrap in C. Therefore, we use
+// appropriately-typed function pointers and scoping to make the fact that we
+// might be dynamically loading the library almost invisible. As a bonus, we
+// also get a simple way to mock the library for testing. Classes that inherit
+// from GnomeKeyringLoader will use its versions of the gnome_keyring_*
+// functions. Note that it has only static fields.
+class GnomeKeyringLoader {
+ public:
+ static bool LoadGnomeKeyring();
+
+ // Declare the actual function pointers that we'll use in client code.
+ // These functions will contact the service.
+ static decltype(&::gnome_keyring_is_available) gnome_keyring_is_available_ptr;
+ static decltype(
+ &::gnome_keyring_store_password) gnome_keyring_store_password_ptr;
+ static decltype(
+ &::gnome_keyring_delete_password) gnome_keyring_delete_password_ptr;
+ static decltype(&::gnome_keyring_find_items) gnome_keyring_find_items_ptr;
+ static decltype(
+ &::gnome_keyring_find_password_sync) gnome_keyring_find_password_sync_ptr;
+ static decltype(&::gnome_keyring_store_password_sync)
+ gnome_keyring_store_password_sync_ptr;
+
+ // These functions do not contact the service.
+ static decltype(
+ &::gnome_keyring_result_to_message) gnome_keyring_result_to_message_ptr;
+ static decltype(&::gnome_keyring_attribute_list_free)
+ gnome_keyring_attribute_list_free_ptr;
+ static decltype(
+ &::gnome_keyring_attribute_list_new) gnome_keyring_attribute_list_new_ptr;
+ static decltype(&::gnome_keyring_attribute_list_append_string)
+ gnome_keyring_attribute_list_append_string_ptr;
+ static decltype(&::gnome_keyring_attribute_list_append_uint32)
+ gnome_keyring_attribute_list_append_uint32_ptr;
+ static decltype(
+ &::gnome_keyring_free_password) gnome_keyring_free_password_ptr;
+ // We also use gnome_keyring_attribute_list_index(), which is a macro and
+ // can't be referenced.
+
+ protected:
+ // Set to true if LoadGnomeKeyring() has already succeeded.
+ static bool keyring_loaded;
+
+ private:
+ struct FunctionInfo {
+ const char* name;
+ void** pointer;
+ };
+
+ // Make it easy to initialize the function pointers in LoadGnomeKeyring().
+ static const FunctionInfo functions[];
+};
+
+#endif // COMPONENTS_OS_CRYPT_KEYRING_UTIL_LINUX_H_
diff --git a/chromium/components/os_crypt/kwallet_dbus.cc b/chromium/components/os_crypt/kwallet_dbus.cc
index f6ec2a1fcec..eb057e63e7e 100644
--- a/chromium/components/os_crypt/kwallet_dbus.cc
+++ b/chromium/components/os_crypt/kwallet_dbus.cc
@@ -68,7 +68,7 @@ bool KWalletDBus::StartKWalletd() {
builder.AppendBool(false); // blind
std::unique_ptr<dbus::Response> response(klauncher->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
+ if (!response) {
LOG(ERROR) << "Error contacting klauncher to start " << kwalletd_name_;
return false;
}
@@ -96,7 +96,7 @@ KWalletDBus::Error KWalletDBus::IsEnabled(bool* enabled) {
dbus::MethodCall method_call(kKWalletInterface, "isEnabled");
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
+ if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (isEnabled)";
return CANNOT_CONTACT;
}
@@ -119,7 +119,7 @@ KWalletDBus::Error KWalletDBus::NetworkWallet(std::string* wallet_name) {
dbus::MethodCall method_call(kKWalletInterface, "networkWallet");
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
+ if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (networkWallet)";
return CANNOT_CONTACT;
}
@@ -143,7 +143,7 @@ KWalletDBus::Error KWalletDBus::Open(const std::string& wallet_name,
builder.AppendString(app_name); // appid
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
+ if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (open)";
return CANNOT_CONTACT;
}
@@ -169,7 +169,7 @@ KWalletDBus::Error KWalletDBus::HasEntry(const int wallet_handle,
builder.AppendString(app_name); // appid
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
+ if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (hasEntry)";
return CANNOT_CONTACT;
}
@@ -195,7 +195,7 @@ KWalletDBus::Error KWalletDBus::ReadEntry(const int wallet_handle,
builder.AppendString(app_name); // appid
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
+ if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (readEntry)";
return CANNOT_CONTACT;
}
@@ -227,7 +227,7 @@ KWalletDBus::Error KWalletDBus::EntryList(
builder.AppendString(app_name); // appid
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
+ if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (entryList)";
return CANNOT_CONTACT;
}
@@ -253,7 +253,7 @@ KWalletDBus::Error KWalletDBus::RemoveEntry(const int wallet_handle,
builder.AppendString(app_name); // appid
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
+ if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (removeEntry)";
return CANNOT_CONTACT;
}
@@ -282,7 +282,7 @@ KWalletDBus::Error KWalletDBus::WriteEntry(const int wallet_handle,
builder.AppendString(app_name); // appid
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
+ if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (writeEntry)";
return CANNOT_CONTACT;
}
@@ -306,7 +306,7 @@ KWalletDBus::Error KWalletDBus::HasFolder(const int handle,
builder.AppendString(app_name); // appid
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
+ if (!response) {
LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (hasFolder)";
return CANNOT_CONTACT;
}
@@ -330,8 +330,8 @@ KWalletDBus::Error KWalletDBus::CreateFolder(const int handle,
builder.AppendString(app_name); // appid
std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
- if (!response.get()) {
- LOG(ERROR) << "Error contacting << " << kwalletd_name_ << " (createFolder)";
+ if (!response) {
+ LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (createFolder)";
return CANNOT_CONTACT;
}
dbus::MessageReader reader(response.get());
@@ -342,3 +342,85 @@ KWalletDBus::Error KWalletDBus::CreateFolder(const int handle,
}
return SUCCESS;
}
+
+KWalletDBus::Error KWalletDBus::WritePassword(const int handle,
+ const std::string& folder_name,
+ const std::string& key,
+ const std::string& password,
+ const std::string& app_name,
+ bool* const write_success_ptr) {
+ dbus::MethodCall method_call(kKWalletInterface, "writePassword");
+ dbus::MessageWriter builder(&method_call);
+ builder.AppendInt32(handle);
+ builder.AppendString(folder_name);
+ builder.AppendString(key);
+ builder.AppendString(password);
+ builder.AppendString(app_name);
+ std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+ if (!response) {
+ LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (writePassword)";
+ return CANNOT_CONTACT;
+ }
+ dbus::MessageReader reader(response.get());
+ int return_code;
+ if (!reader.PopInt32(&return_code)) {
+ LOG(ERROR) << "Error reading response from " << kwalletd_name_
+ << " (writePassword): " << response->ToString();
+ return CANNOT_READ;
+ }
+ *write_success_ptr = return_code == 0;
+ return SUCCESS;
+}
+
+KWalletDBus::Error KWalletDBus::ReadPassword(const int handle,
+ const std::string& folder_name,
+ const std::string& key,
+ const std::string& app_name,
+ std::string* const password_ptr) {
+ dbus::MethodCall method_call(kKWalletInterface, "readPassword");
+ dbus::MessageWriter builder(&method_call);
+ builder.AppendInt32(handle);
+ builder.AppendString(folder_name);
+ builder.AppendString(key);
+ builder.AppendString(app_name);
+ std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+ if (!response) {
+ LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (readPassword)";
+ return CANNOT_CONTACT;
+ }
+ dbus::MessageReader reader(response.get());
+ if (!reader.PopString(password_ptr)) {
+ LOG(ERROR) << "Error reading response from " << kwalletd_name_
+ << " (readPassword): " << response->ToString();
+ return CANNOT_READ;
+ }
+ return SUCCESS;
+}
+
+KWalletDBus::Error KWalletDBus::Close(const int handle,
+ const bool force,
+ const std::string& app_name,
+ bool* success_ptr) {
+ dbus::MethodCall method_call(kKWalletInterface, "close");
+ dbus::MessageWriter builder(&method_call);
+ builder.AppendInt32(handle);
+ builder.AppendBool(force);
+ builder.AppendString(app_name);
+ std::unique_ptr<dbus::Response> response(kwallet_proxy_->CallMethodAndBlock(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+ if (!response) {
+ LOG(ERROR) << "Error contacting " << kwalletd_name_ << " (close)";
+ return CANNOT_CONTACT;
+ }
+ dbus::MessageReader reader(response.get());
+ int return_code = 1;
+ if (!reader.PopInt32(&return_code)) {
+ LOG(ERROR) << "Error reading response from " << kwalletd_name_
+ << " (close): " << response->ToString();
+ return CANNOT_READ;
+ }
+ *success_ptr = return_code == 0;
+ return SUCCESS;
+}
diff --git a/chromium/components/os_crypt/kwallet_dbus.h b/chromium/components/os_crypt/kwallet_dbus.h
index e0412c514b0..e5366ecbf5a 100644
--- a/chromium/components/os_crypt/kwallet_dbus.h
+++ b/chromium/components/os_crypt/kwallet_dbus.h
@@ -24,17 +24,17 @@ class KWalletDBus {
enum Error { SUCCESS = 0, CANNOT_CONTACT, CANNOT_READ };
explicit KWalletDBus(base::nix::DesktopEnvironment desktop_env);
- ~KWalletDBus();
+ virtual ~KWalletDBus();
// Set the bus that we will use. Required before any other operation.
// The owner of KWalletDBus is responsible for killing the bus.
- void SetSessionBus(scoped_refptr<dbus::Bus> session_bus);
+ virtual void SetSessionBus(scoped_refptr<dbus::Bus> session_bus);
// Expose the bus so that shutdown can be scheduled asynchronously.
- dbus::Bus* GetSessionBus();
+ virtual dbus::Bus* GetSessionBus();
// Use KLauncher to start the KWallet service. Returns true if successful.
- bool StartKWalletd() WARN_UNUSED_RESULT;
+ virtual bool StartKWalletd() WARN_UNUSED_RESULT;
// The functions below are wrappers for calling the eponymous KWallet dbus
// methods. They take pointers to locations where the return values will be
@@ -42,65 +42,89 @@ class KWalletDBus {
// https://api.kde.org/4.12-api/kdelibs-apidocs/kdeui/html/classKWallet_1_1Wallet.html
// Determine if the KDE wallet is enabled.
- Error IsEnabled(bool* enabled) WARN_UNUSED_RESULT;
+ virtual Error IsEnabled(bool* enabled) WARN_UNUSED_RESULT;
// Get the name of the wallet used to store network passwords.
- Error NetworkWallet(std::string* wallet_name_ptr) WARN_UNUSED_RESULT;
+ virtual Error NetworkWallet(std::string* wallet_name_ptr) WARN_UNUSED_RESULT;
// Open the |wallet_name| wallet for use.
- Error Open(const std::string& wallet_name,
- const std::string& app_name,
- int* handle_ptr) WARN_UNUSED_RESULT;
+ virtual Error Open(const std::string& wallet_name,
+ const std::string& app_name,
+ int* handle_ptr) WARN_UNUSED_RESULT;
// Determine if the current folder has they entry key.
- Error HasEntry(int wallet_handle,
- const std::string& folder_name,
- const std::string& signon_realm,
- const std::string& app_name,
- bool* has_entry_ptr) WARN_UNUSED_RESULT;
+ virtual Error HasEntry(int wallet_handle,
+ const std::string& folder_name,
+ const std::string& signon_realm,
+ const std::string& app_name,
+ bool* has_entry_ptr) WARN_UNUSED_RESULT;
// Read the entry key from the current folder.
- Error ReadEntry(int wallet_handle,
- const std::string& folder_name,
- const std::string& signon_realm,
- const std::string& app_name,
- std::vector<uint8_t>* bytes_ptr) WARN_UNUSED_RESULT;
+ virtual Error ReadEntry(int wallet_handle,
+ const std::string& folder_name,
+ const std::string& signon_realm,
+ const std::string& app_name,
+ std::vector<uint8_t>* bytes_ptr) WARN_UNUSED_RESULT;
// Return the list of keys of all entries in this folder.
- Error EntryList(int wallet_handle,
- const std::string& folder_name,
- const std::string& app_name,
- std::vector<std::string>* entry_list_ptr) WARN_UNUSED_RESULT;
+ virtual Error EntryList(int wallet_handle,
+ const std::string& folder_name,
+ const std::string& app_name,
+ std::vector<std::string>* entry_list_ptr)
+ WARN_UNUSED_RESULT;
// Remove the entry key from the current folder.
// |*return_code_ptr| is 0 on success.
- Error RemoveEntry(int wallet_handle,
- const std::string& folder_name,
- const std::string& signon_realm,
- const std::string& app_name,
- int* return_code_ptr) WARN_UNUSED_RESULT;
+ virtual Error RemoveEntry(int wallet_handle,
+ const std::string& folder_name,
+ const std::string& signon_realm,
+ const std::string& app_name,
+ int* return_code_ptr) WARN_UNUSED_RESULT;
// Write a binary entry to the current folder.
// |*return_code_ptr| is 0 on success.
- Error WriteEntry(int wallet_handle,
- const std::string& folder_name,
- const std::string& signon_realm,
- const std::string& app_name,
- const uint8_t* data,
- size_t length,
- int* return_code_ptr) WARN_UNUSED_RESULT;
+ virtual Error WriteEntry(int wallet_handle,
+ const std::string& folder_name,
+ const std::string& signon_realm,
+ const std::string& app_name,
+ const uint8_t* data,
+ size_t length,
+ int* return_code_ptr) WARN_UNUSED_RESULT;
// Determine if the folder |folder_name| exists in the wallet.
- Error HasFolder(int handle,
- const std::string& folder_name,
- const std::string& app_name,
- bool* has_folder_ptr) WARN_UNUSED_RESULT;
-
- // Created the folder |folder_name|.
- Error CreateFolder(int handle,
- const std::string& folder_name,
- const std::string& app_name,
- bool* success_ptr) WARN_UNUSED_RESULT;
+ virtual Error HasFolder(int handle,
+ const std::string& folder_name,
+ const std::string& app_name,
+ bool* has_folder_ptr) WARN_UNUSED_RESULT;
+
+ // Create the folder |folder_name|.
+ virtual Error CreateFolder(int handle,
+ const std::string& folder_name,
+ const std::string& app_name,
+ bool* success_ptr) WARN_UNUSED_RESULT;
+
+ // Write a password to the current folder.
+ virtual Error WritePassword(int handle,
+ const std::string& folder_name,
+ const std::string& key,
+ const std::string& password,
+ const std::string& app_name,
+ bool* write_success_ptr) WARN_UNUSED_RESULT;
+
+ // Read the password for |key| from |folder_name|.
+ // Clear |password_ptr| if no such password exists.
+ virtual Error ReadPassword(int handle,
+ const std::string& folder_name,
+ const std::string& key,
+ const std::string& app_name,
+ std::string* password_ptr) WARN_UNUSED_RESULT;
+
+ // Close the wallet. The wallet will only be closed if it is open but not in
+ // use (rare), or if it is forced closed.
+ virtual Error Close(int handle,
+ bool force,
+ const std::string& app_name,
+ bool* success_ptr) WARN_UNUSED_RESULT;
private:
// DBus handle for communication with klauncher and kwalletd.
diff --git a/chromium/components/os_crypt/kwallet_dbus_unittest.cc b/chromium/components/os_crypt/kwallet_dbus_unittest.cc
index 24d6b8e81d1..bc494f161d4 100644
--- a/chromium/components/os_crypt/kwallet_dbus_unittest.cc
+++ b/chromium/components/os_crypt/kwallet_dbus_unittest.cc
@@ -272,6 +272,61 @@ MATCHER_P5(ArgumentsAreStringStringsStringsStringBool,
return true;
}
+MATCHER_P5(ArgumentsAreIntStringStringStringString,
+ int_1,
+ str_2,
+ str_3,
+ str_4,
+ str_5,
+ "") {
+ dbus::MessageReader reader(arg);
+
+ int32_t i;
+ EXPECT_TRUE(reader.PopInt32(&i));
+ if (int_1 != i)
+ return false;
+
+ std::string str;
+ EXPECT_TRUE(reader.PopString(&str));
+ if (str_2 != str)
+ return false;
+
+ EXPECT_TRUE(reader.PopString(&str));
+ if (str_3 != str)
+ return false;
+
+ EXPECT_TRUE(reader.PopString(&str));
+ if (str_4 != str)
+ return false;
+
+ EXPECT_TRUE(reader.PopString(&str));
+ if (str_5 != str)
+ return false;
+
+ return true;
+}
+
+MATCHER_P3(ArgumentsAreIntBoolString, int_1, bool_2, str_3, "") {
+ dbus::MessageReader reader(arg);
+
+ int32_t i;
+ EXPECT_TRUE(reader.PopInt32(&i));
+ if (int_1 != i)
+ return false;
+
+ bool b;
+ EXPECT_TRUE(reader.PopBool(&b));
+ if (bool_2 != b)
+ return false;
+
+ std::string str;
+ EXPECT_TRUE(reader.PopString(&str));
+ if (str_3 != str)
+ return false;
+
+ return true;
+}
+
TEST_P(KWalletDBusTest, StartWalletd) {
// The receiver of the message takes ownership of the response object.
dbus::Response* response_success = RespondEmpty();
@@ -693,4 +748,145 @@ TEST_P(KWalletDBusTest, CreateFolderErrorContact) {
kwallet_dbus_.CreateFolder(123, "folder", "app", &created_folder));
}
+TEST_P(KWalletDBusTest, WritePassword) {
+ EXPECT_CALL(*mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(
+ AllOf(Calls(kKWalletInterface, "writePassword"),
+ ArgumentsAreIntStringStringStringString(
+ 123, "folder", "key", "password", "app")),
+ _))
+ .WillOnce(Return(RespondInt32(0)));
+
+ bool write_success = false;
+ EXPECT_EQ(KWalletDBus::Error::SUCCESS,
+ kwallet_dbus_.WritePassword(123, "folder", "key", "password", "app",
+ &write_success));
+ EXPECT_TRUE(write_success);
+}
+
+TEST_P(KWalletDBusTest, WritePasswordRejected) {
+ EXPECT_CALL(*mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(
+ AllOf(Calls(kKWalletInterface, "writePassword"),
+ ArgumentsAreIntStringStringStringString(
+ 123, "folder", "key", "password", "app")),
+ _))
+ .WillOnce(Return(RespondInt32(-1)));
+
+ bool write_success = true;
+ EXPECT_EQ(KWalletDBus::Error::SUCCESS,
+ kwallet_dbus_.WritePassword(123, "folder", "key", "password", "app",
+ &write_success));
+ EXPECT_FALSE(write_success);
+}
+
+TEST_P(KWalletDBusTest, WritePasswordErrorRead) {
+ EXPECT_CALL(
+ *mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(Calls(kKWalletInterface, "writePassword"), _))
+ .WillOnce(Return(RespondEmpty()));
+
+ bool write_success = false;
+ EXPECT_EQ(KWalletDBus::Error::CANNOT_READ,
+ kwallet_dbus_.WritePassword(123, "folder", "key", "password", "app",
+ &write_success));
+}
+
+TEST_P(KWalletDBusTest, WritePasswordErrorContact) {
+ EXPECT_CALL(
+ *mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(Calls(kKWalletInterface, "writePassword"), _))
+ .WillOnce(Return(nullptr));
+
+ bool write_success = false;
+ EXPECT_EQ(KWalletDBus::Error::CANNOT_CONTACT,
+ kwallet_dbus_.WritePassword(123, "folder", "key", "password", "app",
+ &write_success));
+}
+
+TEST_P(KWalletDBusTest, ReadPassword) {
+ EXPECT_CALL(
+ *mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(
+ AllOf(Calls(kKWalletInterface, "readPassword"),
+ ArgumentsAreIntStringStringString(123, "folder", "key", "app")),
+ _))
+ .WillOnce(Return(RespondString("password")));
+
+ std::string password;
+ EXPECT_EQ(KWalletDBus::Error::SUCCESS,
+ kwallet_dbus_.ReadPassword(123, "folder", "key", "app", &password));
+ EXPECT_EQ("password", password);
+}
+
+TEST_P(KWalletDBusTest, ReadPasswordErrorRead) {
+ EXPECT_CALL(
+ *mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(Calls(kKWalletInterface, "readPassword"), _))
+ .WillOnce(Return(RespondEmpty()));
+
+ std::string password;
+ EXPECT_EQ(KWalletDBus::Error::CANNOT_READ,
+ kwallet_dbus_.ReadPassword(123, "folder", "key", "app", &password));
+}
+
+TEST_P(KWalletDBusTest, ReadPasswordErrorContact) {
+ EXPECT_CALL(
+ *mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(Calls(kKWalletInterface, "readPassword"), _))
+ .WillOnce(Return(nullptr));
+
+ std::string password;
+ EXPECT_EQ(KWalletDBus::Error::CANNOT_CONTACT,
+ kwallet_dbus_.ReadPassword(123, "folder", "key", "app", &password));
+}
+
+TEST_P(KWalletDBusTest, CloseSuccess) {
+ EXPECT_CALL(*mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(
+ AllOf(Calls(kKWalletInterface, "close"),
+ ArgumentsAreIntBoolString(123, false, "app")),
+ _))
+ .WillOnce(Return(RespondInt32(0)));
+
+ bool success = false;
+ EXPECT_EQ(KWalletDBus::Error::SUCCESS,
+ kwallet_dbus_.Close(123, false, "app", &success));
+ EXPECT_TRUE(success);
+}
+
+TEST_P(KWalletDBusTest, CloseUnsuccessful) {
+ EXPECT_CALL(*mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(
+ AllOf(Calls(kKWalletInterface, "close"),
+ ArgumentsAreIntBoolString(123, false, "app")),
+ _))
+ .WillOnce(Return(RespondInt32(1)));
+
+ bool success = true;
+ EXPECT_EQ(KWalletDBus::Error::SUCCESS,
+ kwallet_dbus_.Close(123, false, "app", &success));
+ EXPECT_FALSE(success);
+}
+
+TEST_P(KWalletDBusTest, CloseErrorRead) {
+ EXPECT_CALL(*mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(Calls(kKWalletInterface, "close"), _))
+ .WillOnce(Return(RespondEmpty()));
+
+ bool success = true;
+ EXPECT_EQ(KWalletDBus::Error::CANNOT_READ,
+ kwallet_dbus_.Close(123, false, "app", &success));
+}
+
+TEST_P(KWalletDBusTest, CloseErrorContact) {
+ EXPECT_CALL(*mock_kwallet_proxy_.get(),
+ MockCallMethodAndBlock(Calls(kKWalletInterface, "close"), _))
+ .WillOnce(Return(nullptr));
+
+ bool success = true;
+ EXPECT_EQ(KWalletDBus::Error::CANNOT_CONTACT,
+ kwallet_dbus_.Close(123, false, "app", &success));
+}
+
} // namespace
diff --git a/chromium/components/os_crypt/libsecret_util_linux.cc b/chromium/components/os_crypt/libsecret_util_linux.cc
index 0e01aef05b5..890b68262da 100644
--- a/chromium/components/os_crypt/libsecret_util_linux.cc
+++ b/chromium/components/os_crypt/libsecret_util_linux.cc
@@ -13,6 +13,17 @@
// LibsecretLoader
//
+namespace {
+
+// TODO(crbug.com/660005) A message that is attached to useless entries that we
+// create, to explain its existence.
+const char kExplanationMessage[] =
+ "Because of quirks in the gnome libsecret API, Chrome needs to store a "
+ "dummy entry to quarantee that this keyring was properly unlocked. More "
+ "details at http://crbug.com/660005.";
+
+} // namespace
+
decltype(
&::secret_password_store_sync) LibsecretLoader::secret_password_store_sync;
decltype(
@@ -26,8 +37,6 @@ decltype(
decltype(&::secret_item_load_secret_sync)
LibsecretLoader::secret_item_load_secret_sync;
decltype(&::secret_value_unref) LibsecretLoader::secret_value_unref;
-decltype(
- &::secret_service_lookup_sync) LibsecretLoader::secret_service_lookup_sync;
bool LibsecretLoader::libsecret_loaded_ = false;
@@ -42,8 +51,6 @@ const LibsecretLoader::FunctionInfo LibsecretLoader::kFunctions[] = {
reinterpret_cast<void**>(&secret_password_clear_sync)},
{"secret_password_store_sync",
reinterpret_cast<void**>(&secret_password_store_sync)},
- {"secret_service_lookup_sync",
- reinterpret_cast<void**>(&secret_service_lookup_sync)},
{"secret_service_search_sync",
reinterpret_cast<void**>(&secret_service_search_sync)},
{"secret_value_get_text", reinterpret_cast<void**>(&secret_value_get_text)},
@@ -102,11 +109,12 @@ bool LibsecretLoader::LibsecretIsAvailable() {
{nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING}}};
GError* error = nullptr;
- GList* found =
- secret_service_search_sync(nullptr, // default secret service
- &kDummySchema, attrs.Get(), SECRET_SEARCH_ALL,
- nullptr, // no cancellable ojbect
- &error);
+ GList* found = secret_service_search_sync(
+ nullptr, // default secret service
+ &kDummySchema, attrs.Get(),
+ static_cast<SecretSearchFlags>(SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK),
+ nullptr, // no cancellable ojbect
+ &error);
bool success = (error == nullptr);
if (error)
g_error_free(error);
@@ -116,6 +124,31 @@ bool LibsecretLoader::LibsecretIsAvailable() {
return success;
}
+// TODO(crbug.com/660005) This is needed to properly unlock the default keyring.
+// We don't need to ever read it.
+void LibsecretLoader::EnsureKeyringUnlocked() {
+ const SecretSchema kDummySchema = {
+ "_chrome_dummy_schema_for_unlocking",
+ SECRET_SCHEMA_NONE,
+ {{"explanation", SECRET_SCHEMA_ATTRIBUTE_STRING},
+ {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING}}};
+
+ GError* error = nullptr;
+ bool success = LibsecretLoader::secret_password_store_sync(
+ &kDummySchema, nullptr /* default keyring */,
+ "Chrome Safe Storage Control" /* entry title */,
+ "The meaning of life" /* password */, nullptr, &error, "explanation",
+ kExplanationMessage,
+ nullptr /* null-terminated variable argument list */);
+ if (error) {
+ VLOG(1) << "Dummy store to unlock the default keyring failed: "
+ << error->message;
+ g_error_free(error);
+ } else if (!success) {
+ VLOG(1) << "Dummy store to unlock the default keyring failed.";
+ }
+}
+
//
// LibsecretAttributesBuilder
//
diff --git a/chromium/components/os_crypt/libsecret_util_linux.h b/chromium/components/os_crypt/libsecret_util_linux.h
index 1adc3072eb1..96f6b17d56e 100644
--- a/chromium/components/os_crypt/libsecret_util_linux.h
+++ b/chromium/components/os_crypt/libsecret_util_linux.h
@@ -20,7 +20,6 @@ class LibsecretLoader {
static decltype(&::secret_item_load_secret_sync) secret_item_load_secret_sync;
static decltype(&::secret_password_clear_sync) secret_password_clear_sync;
static decltype(&::secret_password_store_sync) secret_password_store_sync;
- static decltype(&::secret_service_lookup_sync) secret_service_lookup_sync;
static decltype(&::secret_service_search_sync) secret_service_search_sync;
static decltype(&::secret_value_get_text) secret_value_get_text;
static decltype(&::secret_value_unref) secret_value_unref;
@@ -31,6 +30,10 @@ class LibsecretLoader {
// the library again if already successful.
static bool EnsureLibsecretLoaded();
+ // Ensure that the default keyring is accessible. This won't prevent the user
+ // from locking their keyring while Chrome is running.
+ static void EnsureKeyringUnlocked();
+
protected:
static bool libsecret_loaded_;
diff --git a/chromium/components/os_crypt/os_crypt.h b/chromium/components/os_crypt/os_crypt.h
index 287a28d7a73..b62aca48365 100644
--- a/chromium/components/os_crypt/os_crypt.h
+++ b/chromium/components/os_crypt/os_crypt.h
@@ -8,6 +8,8 @@
#include <string>
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
@@ -26,6 +28,16 @@ class OSCrypt {
// In any other case, we default to auto-detecting the store.
// This should not be changed after OSCrypt has been used.
static void SetStore(const std::string& store_type);
+
+ // Some password stores may prompt the user for permission and show the
+ // application name.
+ static void SetProductName(const std::string& product_name);
+
+ // The gnome-keyring implementation requires calls from the main thread.
+ // TODO(crbug/466975): Libsecret and KWallet don't need this. We can remove
+ // this when we stop supporting keyring.
+ static void SetMainThreadRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner);
#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
// Encrypt a string16. The output (second argument) is really an array of
@@ -64,7 +76,8 @@ class OSCrypt {
// |get_key_storage_mock| provides the desired |KeyStorage| implementation.
// If the provider returns |nullptr|, a hardcoded password will be used.
// |get_password_v11_mock| provides a password to derive the encryption key from
-// If both parameters are |nullptr|, the real implementation is restored.
+// If one parameter is |nullptr|, the function will be not be replaced.
+// If all parameters are |nullptr|, the real implementation is restored.
void UseMockKeyStorageForTesting(KeyStorageLinux* (*get_key_storage_mock)(),
std::string* (*get_password_v11_mock)());
#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(UNIT_TEST)
diff --git a/chromium/components/os_crypt/os_crypt_linux.cc b/chromium/components/os_crypt/os_crypt_linux.cc
index 2104d25047f..496d9716ea4 100644
--- a/chromium/components/os_crypt/os_crypt_linux.cc
+++ b/chromium/components/os_crypt/os_crypt_linux.cc
@@ -14,6 +14,7 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
#include "components/os_crypt/key_storage_linux.h"
#include "crypto/encryptor.h"
#include "crypto/symmetric_key.h"
@@ -54,6 +55,9 @@ struct Cache {
std::unique_ptr<std::string> password_v11_cache;
bool is_key_storage_cached;
bool is_password_v11_cached;
+ // Guards access to |g_cache|, making lazy initialization of individual parts
+ // thread safe.
+ base::Lock lock;
};
base::LazyInstance<Cache>::Leaky g_cache = LAZY_INSTANCE_INITIALIZER;
@@ -68,28 +72,33 @@ KeyStorageLinux* GetKeyStorage() {
return g_cache.Get().key_storage_cache.get();
}
-// Returns a cached string of "peanuts".
+// Pointer to a function that creates and returns the |KeyStorage| instance to
+// be used. The function maintains ownership of the pointer.
+KeyStorageLinux* (*g_key_storage_provider)() = &GetKeyStorage;
+
+// Returns a cached string of "peanuts". Is thread-safe.
std::string* GetPasswordV10() {
- if (!g_cache.Get().password_v10_cache.get())
+ base::AutoLock auto_lock(g_cache.Get().lock);
+ if (!g_cache.Get().password_v10_cache.get()) {
g_cache.Get().password_v10_cache.reset(new std::string("peanuts"));
+ }
return g_cache.Get().password_v10_cache.get();
}
// Caches and returns the password from the KeyStorage or null if there is no
-// service.
+// service. Is thread-safe.
std::string* GetPasswordV11() {
+ base::AutoLock auto_lock(g_cache.Get().lock);
if (!g_cache.Get().is_password_v11_cached) {
- g_cache.Get().is_password_v11_cached = true;
g_cache.Get().password_v11_cache.reset(
- GetKeyStorage() ? new std::string(GetKeyStorage()->GetKey()) : nullptr);
+ g_key_storage_provider()
+ ? new std::string(g_key_storage_provider()->GetKey())
+ : nullptr);
+ g_cache.Get().is_password_v11_cached = true;
}
return g_cache.Get().password_v11_cache.get();
}
-// Pointer to a function that creates and returns the |KeyStorage| instance to
-// be used. The function maintains ownership of the pointer.
-KeyStorageLinux* (*g_key_storage_provider)() = &GetKeyStorage;
-
// Pointers to functions that return a password for deriving the encryption key.
// One function for each supported password version (see Version enum).
std::string* (*g_get_password[])() = {
@@ -143,12 +152,16 @@ bool OSCrypt::EncryptString(const std::string& plaintext,
return true;
}
- // If a |KeyStorage| is available, use a password backed by the |KeyStorage|.
- // Otherwise use the hardcoded password.
- Version version = g_key_storage_provider() ? Version::V11 : Version::V10;
-
+ // If we are able to create a V11 key (i.e. a KeyStorage was available), then
+ // we'll use it. If not, we'll use V10.
+ Version version = Version::V11;
std::unique_ptr<crypto::SymmetricKey> encryption_key(
GetEncryptionKey(version));
+ if (!encryption_key) {
+ version = Version::V10;
+ encryption_key = GetEncryptionKey(version);
+ }
+
if (!encryption_key)
return false;
@@ -218,6 +231,23 @@ void OSCrypt::SetStore(const std::string& store_type) {
KeyStorageLinux::SetStore(store_type);
}
+// static
+void OSCrypt::SetProductName(const std::string& product_name) {
+ // Setting the product name makes no sense after initializing.
+ DCHECK(!g_cache.Get().is_key_storage_cached);
+
+ KeyStorageLinux::SetProductName(product_name);
+}
+
+// static
+void OSCrypt::SetMainThreadRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner) {
+ // Setting the task runner makes no sense after initializing.
+ DCHECK(!g_cache.Get().is_key_storage_cached);
+
+ KeyStorageLinux::SetMainThreadRunner(main_thread_runner);
+}
+
void UseMockKeyStorageForTesting(KeyStorageLinux* (*get_key_storage_mock)(),
std::string* (*get_password_v11_mock)()) {
// Save the real implementation to restore it later.
@@ -231,13 +261,16 @@ void UseMockKeyStorageForTesting(KeyStorageLinux* (*get_key_storage_mock)(),
if (get_key_storage_mock && get_password_v11_mock) {
// Bypass calling KeyStorage::CreateService and caching of the key for V11
- g_get_password[Version::V11] = get_password_v11_mock;
+ if (get_password_v11_mock)
+ g_get_password[Version::V11] = get_password_v11_mock;
// OSCrypt will determine the encryption version by checking if a
// |KeyStorage| instance can be created. Enable V11 by returning the mock.
- g_key_storage_provider = get_key_storage_mock;
+ if (get_key_storage_mock)
+ g_key_storage_provider = get_key_storage_mock;
} else {
// Restore real implementation
std::copy(std::begin(get_password_save), std::end(get_password_save),
std::begin(g_get_password));
+ g_key_storage_provider = &GetKeyStorage;
}
}
diff --git a/chromium/components/os_crypt/os_crypt_mocker.cc b/chromium/components/os_crypt/os_crypt_mocker.cc
index dd160cbaf53..3e676c95a4f 100644
--- a/chromium/components/os_crypt/os_crypt_mocker.cc
+++ b/chromium/components/os_crypt/os_crypt_mocker.cc
@@ -14,7 +14,7 @@
void OSCryptMocker::SetUpWithSingleton() {
#if defined(OS_MACOSX)
OSCrypt::UseMockKeychain(true);
-#elif defined(USE_LIBSECRET)
+#elif defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
OSCryptMockerLinux::SetUpWithSingleton();
#endif
}
@@ -23,7 +23,7 @@ void OSCryptMocker::SetUpWithSingleton() {
void OSCryptMocker::TearDown() {
#if defined(OS_MACOSX)
OSCrypt::UseMockKeychain(false);
-#elif defined(USE_LIBSECRET)
+#elif defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
OSCryptMockerLinux::TearDown();
#endif
}
diff --git a/chromium/components/os_crypt/os_crypt_posix.cc b/chromium/components/os_crypt/os_crypt_posix.cc
index 44f04b3801f..24a411e9bd6 100644
--- a/chromium/components/os_crypt/os_crypt_posix.cc
+++ b/chromium/components/os_crypt/os_crypt_posix.cc
@@ -9,6 +9,7 @@
#include <memory>
#include "base/logging.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "crypto/encryptor.h"
#include "crypto/symmetric_key.h"
@@ -118,7 +119,8 @@ bool OSCrypt::DecryptString(const std::string& ciphertext,
// old data saved as clear text and we'll return it directly.
// Credit card numbers are current legacy data, so false match with prefix
// won't happen.
- if (ciphertext.find(kObfuscationPrefix) != 0) {
+ if (!base::StartsWith(ciphertext, kObfuscationPrefix,
+ base::CompareCase::SENSITIVE)) {
*plaintext = ciphertext;
return true;
}
diff --git a/chromium/components/os_crypt/os_crypt_unittest.cc b/chromium/components/os_crypt/os_crypt_unittest.cc
index d3861d10c40..b5abfc91db7 100644
--- a/chromium/components/os_crypt/os_crypt_unittest.cc
+++ b/chromium/components/os_crypt/os_crypt_unittest.cc
@@ -5,15 +5,23 @@
#include "components/os_crypt/os_crypt.h"
#include <string>
+#include <vector>
+#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread.h"
#include "build/build_config.h"
#include "components/os_crypt/os_crypt_mocker.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "components/os_crypt/os_crypt_mocker_linux.h"
+#endif
+
namespace {
class OSCryptTest : public testing::Test {
@@ -140,4 +148,51 @@ TEST_F(OSCryptTest, DecryptError) {
EXPECT_TRUE(result.empty());
}
+class OSCryptConcurrencyTest : public testing::Test {
+ public:
+ OSCryptConcurrencyTest() {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // Mock the key storage, but not the process of getting the passwords.
+ UseMockKeyStorageForTesting(
+ []() -> KeyStorageLinux* { return OSCryptMockerLinux::GetInstance(); },
+ nullptr);
+#else
+ OSCryptMocker::SetUpWithSingleton();
+#endif
+ }
+
+ ~OSCryptConcurrencyTest() override { OSCryptMocker::TearDown(); };
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OSCryptConcurrencyTest);
+};
+
+TEST_F(OSCryptConcurrencyTest, ConcurrentInitialization) {
+ // Launch multiple threads
+ base::Thread thread1("thread1");
+ base::Thread thread2("thread2");
+ std::vector<base::Thread*> threads = {&thread1, &thread2};
+ for (base::Thread* thread : threads) {
+ ASSERT_TRUE(thread->Start());
+ }
+
+ // Make calls.
+ for (base::Thread* thread : threads) {
+ ASSERT_TRUE(thread->task_runner()->PostTask(
+ FROM_HERE, base::Bind([]() -> void {
+ std::string plaintext = "secrets";
+ std::string encrypted;
+ std::string decrypted;
+ ASSERT_TRUE(OSCrypt::EncryptString(plaintext, &encrypted));
+ ASSERT_TRUE(OSCrypt::DecryptString(encrypted, &decrypted));
+ ASSERT_EQ(plaintext, decrypted);
+ })));
+ }
+
+ // Cleanup
+ for (base::Thread* thread : threads) {
+ thread->Stop();
+ }
+}
+
} // namespace
diff --git a/chromium/components/os_crypt/os_crypt_util_linux_unittest.cc b/chromium/components/os_crypt/os_crypt_util_linux_unittest.cc
deleted file mode 100644
index 61cf9b2dca9..00000000000
--- a/chromium/components/os_crypt/os_crypt_util_linux_unittest.cc
+++ /dev/null
@@ -1,177 +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 <string>
-
-#include "base/macros.h"
-#include "components/os_crypt/key_storage_libsecret.h"
-#include "components/os_crypt/libsecret_util_linux.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-// Mock functions use MockSecretValue, where SecretValue would appear, and are
-// cast to the correct signature. We can reduce SecretValue to an std::string,
-// because we don't use anything else from it.
-using MockSecretValue = std::string;
-
-// Replaces some of LibsecretLoader's methods with mocked ones.
-class MockLibsecretLoader : public LibsecretLoader {
- public:
- // Sets up the minimum mock implementation necessary for OSCrypt to work
- // with Libsecret. Also resets the state to mock a clean database.
- static bool ResetForOSCrypt();
-
- // Sets OSCrypt's password in the libsecret mock to a specific value
- static void SetOSCryptPassword(const char*);
-
- // Releases memory and restores LibsecretLoader to an uninitialized state.
- static void TearDown();
-
- private:
- // These methods are used to redirect calls through LibsecretLoader
- static const gchar* mock_secret_value_get_text(MockSecretValue* value);
-
- static gboolean mock_secret_password_store_sync(const SecretSchema* schema,
- const gchar* collection,
- const gchar* label,
- const gchar* password,
- GCancellable* cancellable,
- GError** error,
- ...);
-
- static MockSecretValue* mock_secret_service_lookup_sync(
- SecretService* service,
- const SecretSchema* schema,
- GHashTable* attributes,
- GCancellable* cancellable,
- GError** error);
-
- static void mock_secret_value_unref(gpointer value);
-
- static GList* mock_secret_service_search_sync(SecretService* service,
- const SecretSchema* schema,
- GHashTable* attributes,
- SecretSearchFlags flags,
- GCancellable* cancellable,
- GError** error);
-
- // MockLibsecretLoader owns this object.
- static MockSecretValue* stored_password_mock_ptr_;
-};
-
-MockSecretValue* MockLibsecretLoader::stored_password_mock_ptr_ = nullptr;
-
-const gchar* MockLibsecretLoader::mock_secret_value_get_text(
- MockSecretValue* value) {
- return value->c_str();
-}
-
-// static
-gboolean MockLibsecretLoader::mock_secret_password_store_sync(
- const SecretSchema* schema,
- const gchar* collection,
- const gchar* label,
- const gchar* password,
- GCancellable* cancellable,
- GError** error,
- ...) {
- delete stored_password_mock_ptr_;
- stored_password_mock_ptr_ = new MockSecretValue(password);
- return true;
-}
-
-// static
-MockSecretValue* MockLibsecretLoader::mock_secret_service_lookup_sync(
- SecretService* service,
- const SecretSchema* schema,
- GHashTable* attributes,
- GCancellable* cancellable,
- GError** error) {
- return stored_password_mock_ptr_;
-}
-
-// static
-void MockLibsecretLoader::mock_secret_value_unref(gpointer value) {}
-
-// static
-GList* MockLibsecretLoader::mock_secret_service_search_sync(
- SecretService* service,
- const SecretSchema* schema,
- GHashTable* attributes,
- SecretSearchFlags flags,
- GCancellable* cancellable,
- GError** error) {
- *error = nullptr;
- return nullptr;
-}
-
-// static
-bool MockLibsecretLoader::ResetForOSCrypt() {
- // 4 methods used by KeyStorageLibsecret::GetKey()
- secret_password_store_sync =
- &MockLibsecretLoader::mock_secret_password_store_sync;
- secret_value_get_text = (decltype(&::secret_value_get_text)) &
- MockLibsecretLoader::mock_secret_value_get_text;
- secret_value_unref = &MockLibsecretLoader::mock_secret_value_unref;
- secret_service_lookup_sync =
- (decltype(&::secret_service_lookup_sync)) &
- MockLibsecretLoader::mock_secret_service_lookup_sync;
- // 1 method used by LibsecretLoader::EnsureLibsecretLoaded()
- secret_service_search_sync =
- &MockLibsecretLoader::mock_secret_service_search_sync;
-
- delete stored_password_mock_ptr_;
- stored_password_mock_ptr_ = nullptr;
- libsecret_loaded_ = true;
-
- return true;
-}
-
-// static
-void MockLibsecretLoader::SetOSCryptPassword(const char* value) {
- delete stored_password_mock_ptr_;
- stored_password_mock_ptr_ = new MockSecretValue(value);
-}
-
-// static
-void MockLibsecretLoader::TearDown() {
- delete stored_password_mock_ptr_;
- stored_password_mock_ptr_ = nullptr;
- libsecret_loaded_ =
- false; // Function pointers will be restored when loading.
-}
-
-class LibsecretTest : public testing::Test {
- public:
- LibsecretTest() = default;
- ~LibsecretTest() override = default;
-
- void SetUp() override { MockLibsecretLoader::ResetForOSCrypt(); }
-
- void TearDown() override { MockLibsecretLoader::TearDown(); }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LibsecretTest);
-};
-
-TEST_F(LibsecretTest, LibsecretRepeats) {
- KeyStorageLibsecret libsecret;
- MockLibsecretLoader::ResetForOSCrypt();
- std::string password = libsecret.GetKey();
- EXPECT_FALSE(password.empty());
- std::string password_repeat = libsecret.GetKey();
- EXPECT_EQ(password, password_repeat);
-}
-
-TEST_F(LibsecretTest, LibsecretCreatesRandomised) {
- KeyStorageLibsecret libsecret;
- MockLibsecretLoader::ResetForOSCrypt();
- std::string password = libsecret.GetKey();
- MockLibsecretLoader::ResetForOSCrypt();
- std::string password_new = libsecret.GetKey();
- EXPECT_NE(password, password_new);
-}
-
-} // namespace
diff --git a/chromium/components/ownership.gypi b/chromium/components/ownership.gypi
deleted file mode 100644
index 1c369d36f93..00000000000
--- a/chromium/components/ownership.gypi
+++ /dev/null
@@ -1,49 +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.
-
-{
- 'conditions': [
- ['chromeos==1', {
- 'targets': [{
- 'target_name': 'ownership',
- 'type': '<(component)',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/components/components.gyp:keyed_service_core',
- '<(DEPTH)/components/components.gyp:policy_component_common',
- '<(DEPTH)/crypto/crypto.gyp:crypto',
- ],
- 'defines': [
- 'OWNERSHIP_IMPLEMENTATION',
- ],
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)',
- ],
- 'sources': [
- 'ownership/mock_owner_key_util.cc',
- 'ownership/mock_owner_key_util.h',
- 'ownership/owner_key_util.cc',
- 'ownership/owner_key_util.h',
- 'ownership/owner_key_util_impl.cc',
- 'ownership/owner_key_util_impl.h',
- 'ownership/owner_settings_service.cc',
- 'ownership/owner_settings_service.h',
- ],
- 'conditions': [
- ['configuration_policy==1', {
- 'dependencies': [
- '<(DEPTH)/components/components.gyp:cloud_policy_proto',
- '<(DEPTH)/components/components.gyp:policy',
- ],
- }],
- ['use_nss_certs==1', {
- 'dependencies': [
- '../build/linux/system.gyp:nss',
- ],
- }],
- ],
- }],
- }],
- ],
-}
diff --git a/chromium/components/ownership/BUILD.gn b/chromium/components/ownership/BUILD.gn
index 8a9eed29c34..53b02fb9b05 100644
--- a/chromium/components/ownership/BUILD.gn
+++ b/chromium/components/ownership/BUILD.gn
@@ -23,8 +23,8 @@ if (is_chromeos) {
deps = [
"//base",
"//components/keyed_service/core",
- "//components/policy",
- "//components/policy:policy_component_common",
+ "//components/policy:generated",
+ "//components/policy/core/common",
"//components/policy/proto",
"//crypto",
]
diff --git a/chromium/components/ownership/DEPS b/chromium/components/ownership/DEPS
index a169ab852fc..edf11c2e364 100644
--- a/chromium/components/ownership/DEPS
+++ b/chromium/components/ownership/DEPS
@@ -1,7 +1,5 @@
include_rules = [
"+components/keyed_service",
+"+components/policy/proto/device_management_backend.pb.h",
"+crypto",
-
-# This is generated from components/policy/proto
-"+policy/proto/device_management_backend.pb.h",
]
diff --git a/chromium/components/ownership/owner_key_util_impl_unittest.cc b/chromium/components/ownership/owner_key_util_impl_unittest.cc
index 1441766b2fa..32731d2f70f 100644
--- a/chromium/components/ownership/owner_key_util_impl_unittest.cc
+++ b/chromium/components/ownership/owner_key_util_impl_unittest.cc
@@ -54,7 +54,7 @@ class OwnerKeyUtilImplTest : public testing::Test {
void SetUp() override {
ASSERT_TRUE(tmpdir_.CreateUniqueTempDir());
- key_file_ = tmpdir_.path().Append(FILE_PATH_LITERAL("key"));
+ key_file_ = tmpdir_.GetPath().Append(FILE_PATH_LITERAL("key"));
util_ = new OwnerKeyUtilImpl(key_file_);
}
diff --git a/chromium/components/ownership/owner_settings_service.h b/chromium/components/ownership/owner_settings_service.h
index e26642d6534..ea4d6f98c61 100644
--- a/chromium/components/ownership/owner_settings_service.h
+++ b/chromium/components/ownership/owner_settings_service.h
@@ -17,7 +17,7 @@
#include "base/threading/thread_checker.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/ownership/ownership_export.h"
-#include "policy/proto/device_management_backend.pb.h"
+#include "components/policy/proto/device_management_backend.pb.h"
namespace base {
class TaskRunner;
diff --git a/chromium/components/packed_ct_ev_whitelist.gypi b/chromium/components/packed_ct_ev_whitelist.gypi
deleted file mode 100644
index e58129c6b92..00000000000
--- a/chromium/components/packed_ct_ev_whitelist.gypi
+++ /dev/null
@@ -1,30 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/packed_ct_ev_whitelist
- 'target_name': 'packed_ct_ev_whitelist',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../net/net.gyp:net',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'packed_ct_ev_whitelist/bit_stream_reader.cc',
- 'packed_ct_ev_whitelist/bit_stream_reader.h',
- 'packed_ct_ev_whitelist/packed_ct_ev_whitelist.cc',
- 'packed_ct_ev_whitelist/packed_ct_ev_whitelist.h',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- ],
-}
diff --git a/chromium/components/page_load_metrics.gypi b/chromium/components/page_load_metrics.gypi
deleted file mode 100644
index 53ec8c2e142..00000000000
--- a/chromium/components/page_load_metrics.gypi
+++ /dev/null
@@ -1,70 +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.
-
-{
- 'conditions': [
- ['OS != "ios"', {
- 'targets': [
- {
- 'target_name': 'page_load_metrics_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../ipc/ipc.gyp:ipc',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'page_load_metrics/common/page_load_metrics_messages.cc',
- 'page_load_metrics/common/page_load_metrics_messages.h',
- 'page_load_metrics/common/page_load_timing.cc',
- 'page_load_metrics/common/page_load_timing.h',
- ],
- },
- {
- 'target_name': 'page_load_metrics_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../ipc/ipc.gyp:ipc',
- 'page_load_metrics_common',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'page_load_metrics/browser/metrics_web_contents_observer.cc',
- 'page_load_metrics/browser/metrics_web_contents_observer.h',
- 'page_load_metrics/browser/page_load_metrics_observer.cc',
- 'page_load_metrics/browser/page_load_metrics_observer.h',
- 'page_load_metrics/browser/page_load_metrics_util.cc',
- 'page_load_metrics/browser/page_load_metrics_util.h',
- ],
- },
- {
- 'target_name': 'page_load_metrics_renderer',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_renderer',
- '../third_party/WebKit/public/blink.gyp:blink',
- '../url/url.gyp:url_lib',
- 'page_load_metrics_common',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'page_load_metrics/renderer/metrics_render_frame_observer.cc',
- 'page_load_metrics/renderer/metrics_render_frame_observer.h',
- 'page_load_metrics/renderer/page_timing_metrics_sender.cc',
- 'page_load_metrics/renderer/page_timing_metrics_sender.h',
- ],
- },
- ],
- }]
- ]
-}
diff --git a/chromium/components/page_load_metrics/DEPS b/chromium/components/page_load_metrics/DEPS
deleted file mode 100644
index 8b0287077ad..00000000000
--- a/chromium/components/page_load_metrics/DEPS
+++ /dev/null
@@ -1,11 +0,0 @@
-include_rules = [
- "+content/public/test",
- "+ipc",
-
- "-components/page_load_metrics",
- "+components/page_load_metrics/common",
-
- # No inclusion of WebKit from the browser, other than strictly enum/POD, header-only types.
- "-third_party/WebKit",
- "+third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h",
-]
diff --git a/chromium/components/page_load_metrics/OWNERS b/chromium/components/page_load_metrics/OWNERS
deleted file mode 100644
index 1b911f3c3bf..00000000000
--- a/chromium/components/page_load_metrics/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-csharrison@chromium.org
-bmcquade@chromium.org
-kinuko@chromium.org
-rdsmith@chromium.org
diff --git a/chromium/components/page_load_metrics/README b/chromium/components/page_load_metrics/README
deleted file mode 100644
index d5f08d5b598..00000000000
--- a/chromium/components/page_load_metrics/README
+++ /dev/null
@@ -1,15 +0,0 @@
-The page load metrics component captures and records UMA metrics related to
-page loading. This may include page timing metrics, such as time to first
-paint, as well as page interaction metrics, such as number of page loads
-aborted before first paint.
-
-This component is not supported on iOS, as it requires hooks into Blink for
-page timing metrics that are unavailable on iOS.
-
-This component has the following structure:
-- browser/: browser process code
-- common/: code shared by browser and renderer, such as IPC messages
-- renderer/ : renderer process code
-
-For additional information on this component, see
-https://docs.google.com/document/d/1HJsJ5W2H_3qRdqPAUgAEo10AF8gXPTXZLUET4X4_sII/edit \ No newline at end of file
diff --git a/chromium/components/page_load_metrics/browser/BUILD.gn b/chromium/components/page_load_metrics/browser/BUILD.gn
deleted file mode 100644
index 232af6b24d0..00000000000
--- a/chromium/components/page_load_metrics/browser/BUILD.gn
+++ /dev/null
@@ -1,45 +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.
-
-# GYP version: components/page_load_metrics.gypi:page_load_metrics_browser
-static_library("browser") {
- sources = [
- "metrics_web_contents_observer.cc",
- "metrics_web_contents_observer.h",
- "page_load_metrics_observer.cc",
- "page_load_metrics_observer.h",
- "page_load_metrics_util.cc",
- "page_load_metrics_util.h",
- ]
- public_deps = [
- "//content/public/browser",
- ]
- deps = [
- "//base",
- "//components/page_load_metrics/common",
- "//components/rappor",
- "//ipc",
- "//net",
- "//third_party/WebKit/public:blink_headers",
- "//ui/base",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "metrics_web_contents_observer_unittest.cc",
- ]
- deps = [
- ":browser",
- "//base",
- "//base/test:test_support",
- "//components/page_load_metrics/common",
- "//components/rappor:test_support",
- "//content/test:test_support",
- "//net",
- "//testing/gtest",
- "//third_party/WebKit/public:blink_headers",
- ]
-}
diff --git a/chromium/components/page_load_metrics/browser/DEPS b/chromium/components/page_load_metrics/browser/DEPS
deleted file mode 100644
index ef2882ddf0e..00000000000
--- a/chromium/components/page_load_metrics/browser/DEPS
+++ /dev/null
@@ -1,8 +0,0 @@
-include_rules = [
- "+content/public/browser",
- "+components/page_load_metrics/browser",
- "+components/rappor",
- "+net/base",
- "+third_party/WebKit/public/web/WebInputEvent.h",
- "+ui/base/page_transition_types.h",
-]
diff --git a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc
deleted file mode 100644
index 617d7d6d211..00000000000
--- a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ /dev/null
@@ -1,921 +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 "components/page_load_metrics/browser/metrics_web_contents_observer.h"
-
-#include <algorithm>
-#include <string>
-#include <utility>
-
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/user_metrics.h"
-#include "components/page_load_metrics/browser/page_load_metrics_util.h"
-#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/navigation_details.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_message_macros.h"
-#include "ui/base/page_transition_types.h"
-
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(
- page_load_metrics::MetricsWebContentsObserver);
-
-namespace page_load_metrics {
-
-namespace internal {
-
-const char kErrorEvents[] = "PageLoad.Events.InternalError";
-const char kAbortChainSizeReload[] =
- "PageLoad.Internal.ProvisionalAbortChainSize.Reload";
-const char kAbortChainSizeForwardBack[] =
- "PageLoad.Internal.ProvisionalAbortChainSize.ForwardBack";
-const char kAbortChainSizeNewNavigation[] =
- "PageLoad.Internal.ProvisionalAbortChainSize.NewNavigation";
-const char kAbortChainSizeSameURL[] =
- "PageLoad.Internal.ProvisionalAbortChainSize.SameURL";
-const char kAbortChainSizeNoCommit[] =
- "PageLoad.Internal.ProvisionalAbortChainSize.NoCommit";
-const char kClientRedirectDelayAfterPaint[] =
- "PageLoad.Internal.ClientRedirectDelayAfterPaint";
-
-} // namespace internal
-
-namespace {
-
-// The url we see from the renderer side is not always the same as what
-// we see from the browser side (e.g. chrome://newtab). We want to be
-// sure here that we aren't logging UMA for internal pages.
-bool IsRelevantNavigation(content::NavigationHandle* navigation_handle,
- const GURL& browser_url,
- const std::string& mime_type) {
- DCHECK(navigation_handle->HasCommitted());
- return navigation_handle->IsInMainFrame() &&
- !navigation_handle->IsSamePage() &&
- !navigation_handle->IsErrorPage() &&
- navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() &&
- browser_url.SchemeIsHTTPOrHTTPS() &&
- (mime_type == "text/html" || mime_type == "application/xhtml+xml");
-}
-
-// If second is non-zero, first must also be non-zero and less than or equal to
-// second.
-bool EventsInOrder(base::TimeDelta first, base::TimeDelta second) {
- if (second.is_zero()) {
- return true;
- }
- return !first.is_zero() && first <= second;
-}
-
-bool IsValidPageLoadTiming(const PageLoadTiming& timing) {
- if (timing.IsEmpty())
- return false;
-
- // If we have a non-empty timing, it should always have a navigation start.
- if (timing.navigation_start.is_null()) {
- NOTREACHED() << "Received null navigation_start.";
- return false;
- }
-
- // Verify proper ordering between the various timings.
-
- if (!EventsInOrder(timing.response_start, timing.dom_loading)) {
- // We sometimes get a zero response_start with a non-zero DOM loading. See
- // crbug.com/590212.
- DLOG(ERROR) << "Invalid response_start " << timing.response_start
- << " for dom_loading " << timing.dom_loading;
- return false;
- }
-
- if (!EventsInOrder(timing.response_start, timing.parse_start)) {
- // We sometimes get a zero response_start with a non-zero parse start. See
- // crbug.com/590212.
- DLOG(ERROR) << "Invalid response_start " << timing.response_start
- << " for parse_start " << timing.parse_start;
- return false;
- }
-
- if (!EventsInOrder(timing.parse_start, timing.parse_stop)) {
- NOTREACHED() << "Invalid parse_start " << timing.parse_start
- << " for parse_stop " << timing.parse_stop;
- return false;
- }
-
- if (!timing.parse_stop.is_zero()) {
- const base::TimeDelta parse_duration =
- timing.parse_stop - timing.parse_start;
- if (timing.parse_blocked_on_script_load_duration > parse_duration) {
- NOTREACHED() << "Invalid parse_blocked_on_script_load_duration "
- << timing.parse_blocked_on_script_load_duration
- << " for parse duration " << parse_duration;
- return false;
- }
- }
-
- if (timing.parse_blocked_on_script_load_from_document_write_duration >
- timing.parse_blocked_on_script_load_duration) {
- NOTREACHED()
- << "Invalid parse_blocked_on_script_load_from_document_write_duration "
- << timing.parse_blocked_on_script_load_from_document_write_duration
- << " for parse_blocked_on_script_load_duration "
- << timing.parse_blocked_on_script_load_duration;
- return false;
- }
-
- if (!EventsInOrder(timing.dom_loading,
- timing.dom_content_loaded_event_start)) {
- NOTREACHED() << "Invalid dom_loading " << timing.dom_loading
- << " for dom_content_loaded_event_start "
- << timing.dom_content_loaded_event_start;
- return false;
- }
-
- if (!EventsInOrder(timing.dom_content_loaded_event_start,
- timing.load_event_start)) {
- NOTREACHED() << "Invalid dom_content_loaded_event_start "
- << timing.dom_content_loaded_event_start
- << " for load_event_start " << timing.load_event_start;
- return false;
- }
-
- if (!EventsInOrder(timing.dom_loading, timing.first_layout)) {
- NOTREACHED() << "Invalid dom_loading " << timing.dom_loading
- << " for first_layout " << timing.first_layout;
- return false;
- }
-
- if (!EventsInOrder(timing.first_layout, timing.first_paint)) {
- NOTREACHED() << "Invalid first_layout " << timing.first_layout
- << " for first_paint " << timing.first_paint;
- return false;
- }
-
- if (!EventsInOrder(timing.first_paint, timing.first_text_paint)) {
- NOTREACHED() << "Invalid first_paint " << timing.first_paint
- << " for first_text_paint " << timing.first_text_paint;
- return false;
- }
-
- if (!EventsInOrder(timing.first_paint, timing.first_image_paint)) {
- NOTREACHED() << "Invalid first_paint " << timing.first_paint
- << " for first_image_paint " << timing.first_image_paint;
- return false;
- }
-
- if (!EventsInOrder(timing.first_paint, timing.first_contentful_paint)) {
- NOTREACHED() << "Invalid first_paint " << timing.first_paint
- << " for first_contentful_paint "
- << timing.first_contentful_paint;
- return false;
- }
-
- return true;
-}
-
-void RecordInternalError(InternalErrorLoadEvent event) {
- UMA_HISTOGRAM_ENUMERATION(internal::kErrorEvents, event, ERR_LAST_ENTRY);
-}
-
-UserAbortType AbortTypeForPageTransition(ui::PageTransition transition) {
- if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD))
- return ABORT_RELOAD;
- if (transition & ui::PAGE_TRANSITION_FORWARD_BACK)
- return ABORT_FORWARD_BACK;
- if (ui::PageTransitionIsNewNavigation(transition))
- return ABORT_NEW_NAVIGATION;
- NOTREACHED()
- << "AbortTypeForPageTransition received unexpected ui::PageTransition: "
- << transition;
- return ABORT_OTHER;
-}
-
-void LogAbortChainSameURLHistogram(int aborted_chain_size_same_url) {
- if (aborted_chain_size_same_url > 0) {
- UMA_HISTOGRAM_COUNTS(internal::kAbortChainSizeSameURL,
- aborted_chain_size_same_url);
- }
-}
-
-void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer,
- const PageLoadTiming& last_timing,
- const PageLoadTiming& new_timing,
- const PageLoadMetadata& last_metadata,
- const PageLoadExtraInfo& extra_info) {
- observer->OnTimingUpdate(new_timing, extra_info);
- if (!new_timing.dom_content_loaded_event_start.is_zero() &&
- last_timing.dom_content_loaded_event_start.is_zero())
- observer->OnDomContentLoadedEventStart(new_timing, extra_info);
- if (!new_timing.load_event_start.is_zero() &&
- last_timing.load_event_start.is_zero())
- observer->OnLoadEventStart(new_timing, extra_info);
- if (!new_timing.first_layout.is_zero() && last_timing.first_layout.is_zero())
- observer->OnFirstLayout(new_timing, extra_info);
- if (!new_timing.first_paint.is_zero() && last_timing.first_paint.is_zero())
- observer->OnFirstPaint(new_timing, extra_info);
- if (!new_timing.first_text_paint.is_zero() &&
- last_timing.first_text_paint.is_zero())
- observer->OnFirstTextPaint(new_timing, extra_info);
- if (!new_timing.first_image_paint.is_zero() &&
- last_timing.first_image_paint.is_zero())
- observer->OnFirstImagePaint(new_timing, extra_info);
- if (!new_timing.first_contentful_paint.is_zero() &&
- last_timing.first_contentful_paint.is_zero())
- observer->OnFirstContentfulPaint(new_timing, extra_info);
- if (!new_timing.parse_start.is_zero() && last_timing.parse_start.is_zero())
- observer->OnParseStart(new_timing, extra_info);
- if (!new_timing.parse_stop.is_zero() && last_timing.parse_stop.is_zero())
- observer->OnParseStop(new_timing, extra_info);
- if (extra_info.metadata.behavior_flags != last_metadata.behavior_flags)
- observer->OnLoadingBehaviorObserved(extra_info);
-}
-
-} // namespace
-
-PageLoadTracker::PageLoadTracker(
- bool in_foreground,
- PageLoadMetricsEmbedderInterface* embedder_interface,
- const GURL& currently_committed_url,
- content::NavigationHandle* navigation_handle,
- int aborted_chain_size,
- int aborted_chain_size_same_url)
- : renderer_tracked_(false),
- navigation_start_(navigation_handle->NavigationStart()),
- url_(navigation_handle->GetURL()),
- abort_type_(ABORT_NONE),
- started_in_foreground_(in_foreground),
- aborted_chain_size_(aborted_chain_size),
- aborted_chain_size_same_url_(aborted_chain_size_same_url),
- embedder_interface_(embedder_interface) {
- DCHECK(!navigation_handle->HasCommitted());
- embedder_interface_->RegisterObservers(this);
- for (const auto& observer : observers_) {
- observer->OnStart(navigation_handle, currently_committed_url,
- started_in_foreground_);
- }
-}
-
-PageLoadTracker::~PageLoadTracker() {
- const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
-
- if (info.time_to_commit && renderer_tracked() && timing_.IsEmpty()) {
- RecordInternalError(ERR_NO_IPCS_RECEIVED);
- }
- // Recall that trackers that are given ABORT_UNKNOWN_NAVIGATION have their
- // chain length added to the next navigation. Take care not to double count
- // them. Also do not double count committed loads, which call this already.
- if (commit_time_.is_null() && abort_type_ != ABORT_UNKNOWN_NAVIGATION)
- LogAbortChainHistograms(nullptr);
-
- for (const auto& observer : observers_) {
- observer->OnComplete(timing_, info);
- }
-}
-
-void PageLoadTracker::LogAbortChainHistograms(
- content::NavigationHandle* final_navigation) {
- if (aborted_chain_size_ == 0)
- return;
- // Note that this could be broken out by this navigation's abort type, if more
- // granularity is needed. Add one to the chain size to count the current
- // navigation. In the other cases, the current navigation is the final
- // navigation (which commits).
- if (!final_navigation) {
- UMA_HISTOGRAM_COUNTS(internal::kAbortChainSizeNoCommit,
- aborted_chain_size_ + 1);
- LogAbortChainSameURLHistogram(aborted_chain_size_same_url_ + 1);
- return;
- }
-
- // The following is only executed for committing trackers.
- DCHECK(!commit_time_.is_null());
-
- // Note that histograms could be separated out by this commit's transition
- // type, but for simplicity they will all be bucketed together.
- LogAbortChainSameURLHistogram(aborted_chain_size_same_url_);
-
- ui::PageTransition committed_transition =
- final_navigation->GetPageTransition();
- switch (AbortTypeForPageTransition(committed_transition)) {
- case ABORT_RELOAD:
- UMA_HISTOGRAM_COUNTS(internal::kAbortChainSizeReload,
- aborted_chain_size_);
- return;
- case ABORT_FORWARD_BACK:
- UMA_HISTOGRAM_COUNTS(internal::kAbortChainSizeForwardBack,
- aborted_chain_size_);
- return;
- case ABORT_NEW_NAVIGATION:
- UMA_HISTOGRAM_COUNTS(internal::kAbortChainSizeNewNavigation,
- aborted_chain_size_);
- return;
- default:
- NOTREACHED()
- << "LogAbortChainHistograms received unexpected ui::PageTransition: "
- << committed_transition;
- return;
- }
-}
-
-void PageLoadTracker::WebContentsHidden() {
- // Only log the first time we background in a given page load.
- if (background_time_.is_null()) {
- // Make sure we either started in the foreground and haven't been
- // foregrounded yet, or started in the background and have already been
- // foregrounded.
- DCHECK_EQ(started_in_foreground_, foreground_time_.is_null());
- background_time_ = base::TimeTicks::Now();
- ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_);
- }
-
- for (const auto& observer : observers_)
- observer->OnHidden();
-}
-
-void PageLoadTracker::WebContentsShown() {
- // Only log the first time we foreground in a given page load.
- if (foreground_time_.is_null()) {
- // Make sure we either started in the background and haven't been
- // backgrounded yet, or started in the foreground and have already been
- // backgrounded.
- DCHECK_NE(started_in_foreground_, background_time_.is_null());
- foreground_time_ = base::TimeTicks::Now();
- ClampBrowserTimestampIfInterProcessTimeTickSkew(&foreground_time_);
- }
-
- for (const auto& observer : observers_)
- observer->OnShown();
-}
-
-void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) {
- // TODO(bmcquade): To improve accuracy, consider adding commit time to
- // NavigationHandle. Taking a timestamp here should be close enough for now.
- commit_time_ = base::TimeTicks::Now();
- ClampBrowserTimestampIfInterProcessTimeTickSkew(&commit_time_);
- url_ = navigation_handle->GetURL();
- for (const auto& observer : observers_) {
- observer->OnCommit(navigation_handle);
- }
- LogAbortChainHistograms(navigation_handle);
-}
-
-void PageLoadTracker::FailedProvisionalLoad(
- content::NavigationHandle* navigation_handle) {
- for (const auto& observer : observers_) {
- observer->OnFailedProvisionalLoad(navigation_handle);
- }
-}
-
-void PageLoadTracker::Redirect(content::NavigationHandle* navigation_handle) {
- for (const auto& observer : observers_) {
- observer->OnRedirect(navigation_handle);
- }
-}
-
-void PageLoadTracker::OnInputEvent(const blink::WebInputEvent& event) {
- for (const auto& observer : observers_) {
- observer->OnUserInput(event);
- }
-}
-
-void PageLoadTracker::NotifyClientRedirectTo(
- const PageLoadTracker& destination) {
- base::TimeDelta redirect_delay_after_paint;
- if (!timing_.first_paint.is_zero()) {
- base::TimeTicks first_paint_time = navigation_start() + timing_.first_paint;
- if (destination.navigation_start() > first_paint_time)
- redirect_delay_after_paint =
- destination.navigation_start() - first_paint_time;
- }
- PAGE_LOAD_HISTOGRAM(internal::kClientRedirectDelayAfterPaint,
- redirect_delay_after_paint);
-}
-
-bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing,
- const PageLoadMetadata& new_metadata) {
- // Throw away IPCs that are not relevant to the current navigation.
- // Two timing structures cannot refer to the same navigation if they indicate
- // that a navigation started at different times, so a new timing struct with a
- // different start time from an earlier struct is considered invalid.
- bool valid_timing_descendent =
- timing_.navigation_start.is_null() ||
- timing_.navigation_start == new_timing.navigation_start;
- // Ensure flags sent previously are still present in the new metadata fields.
- bool valid_behavior_descendent =
- (metadata_.behavior_flags & new_metadata.behavior_flags) ==
- metadata_.behavior_flags;
- if (IsValidPageLoadTiming(new_timing) && valid_timing_descendent &&
- valid_behavior_descendent) {
- // There are some subtle ordering constraints here. GetPageLoadMetricsInfo()
- // must be called before DispatchObserverTimingCallbacks, but its
- // implementation depends on the state of metadata_, so we need to update
- // metadata_ before calling GetPageLoadMetricsInfo. Thus, we make a copy of
- // timing here, update timing_ and metadata_, and then proceed to dispatch
- // the observer timing callbacks.
- const PageLoadTiming last_timing = timing_;
- timing_ = new_timing;
-
- const PageLoadMetadata last_metadata = metadata_;
- metadata_ = new_metadata;
- const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
- for (const auto& observer : observers_) {
- DispatchObserverTimingCallbacks(observer.get(), last_timing, new_timing,
- last_metadata, info);
- }
- return true;
- }
- return false;
-}
-
-void PageLoadTracker::set_renderer_tracked(bool renderer_tracked) {
- renderer_tracked_ = renderer_tracked;
-}
-
-void PageLoadTracker::AddObserver(
- std::unique_ptr<PageLoadMetricsObserver> observer) {
- observers_.push_back(std::move(observer));
-}
-
-void PageLoadTracker::ClampBrowserTimestampIfInterProcessTimeTickSkew(
- base::TimeTicks* event_time) {
- DCHECK(event_time != nullptr);
- // Windows 10 GCE bot non-deterministically failed because TimeTicks::Now()
- // called in the browser process e.g. commit_time was less than
- // navigation_start_ that was populated in the renderer process because the
- // clock was not system-wide monotonic.
- // Note that navigation_start_ can also be set in the browser process in
- // some cases and in those cases event_time should never be <
- // navigation_start_. If it is due to a code error and it gets clamped in this
- // function, on high resolution systems it should lead to a dcheck failure.
-
- // TODO (shivanisha) Currently IsHighResolution is the best way to check
- // if the clock is system-wide monotonic. However IsHighResolution
- // does a broader check to see if the clock in use is high resolution
- // which also implies it is system-wide monotonic (on Windows).
- if (base::TimeTicks::IsHighResolution()) {
- DCHECK(event_time->is_null() || *event_time >= navigation_start_);
- return;
- }
-
- if (!event_time->is_null() && *event_time < navigation_start_) {
- RecordInternalError(ERR_INTER_PROCESS_TIME_TICK_SKEW);
- *event_time = navigation_start_;
- }
-}
-
-PageLoadExtraInfo PageLoadTracker::ComputePageLoadExtraInfo() {
- base::Optional<base::TimeDelta> first_background_time;
- base::Optional<base::TimeDelta> first_foreground_time;
- base::Optional<base::TimeDelta> time_to_abort;
- base::Optional<base::TimeDelta> time_to_commit;
-
- if (!background_time_.is_null()) {
- DCHECK_GE(background_time_, navigation_start_);
- first_background_time = background_time_ - navigation_start_;
- }
-
- if (!foreground_time_.is_null()) {
- DCHECK_GE(foreground_time_, navigation_start_);
- first_foreground_time = foreground_time_ - navigation_start_;
- }
-
- if (abort_type_ != ABORT_NONE) {
- DCHECK_GE(abort_time_, navigation_start_);
- time_to_abort = abort_time_ - navigation_start_;
- } else {
- DCHECK(abort_time_.is_null());
- }
-
- if (!commit_time_.is_null()) {
- DCHECK_GE(commit_time_, navigation_start_);
- time_to_commit = commit_time_ - navigation_start_;
- }
-
- return PageLoadExtraInfo(
- first_background_time, first_foreground_time, started_in_foreground_,
- commit_time_.is_null() ? GURL() : url_, time_to_commit, abort_type_,
- time_to_abort, metadata_);
-}
-
-void PageLoadTracker::NotifyAbort(UserAbortType abort_type,
- base::TimeTicks timestamp,
- bool is_certainly_browser_timestamp) {
- DCHECK_NE(abort_type, ABORT_NONE);
- // Use UpdateAbort to update an already notified PageLoadTracker.
- if (abort_type_ != ABORT_NONE)
- return;
-
- UpdateAbortInternal(abort_type, timestamp, is_certainly_browser_timestamp);
-}
-
-void PageLoadTracker::UpdateAbort(UserAbortType abort_type,
- base::TimeTicks timestamp,
- bool is_certainly_browser_timestamp) {
- DCHECK_NE(abort_type, ABORT_NONE);
- DCHECK_NE(abort_type, ABORT_OTHER);
- DCHECK_EQ(abort_type_, ABORT_OTHER);
-
- // For some aborts (e.g. navigations), the initiated timestamp can be earlier
- // than the timestamp that aborted the load. Taking the minimum gives the
- // closest user initiated time known.
- UpdateAbortInternal(abort_type, std::min(abort_time_, timestamp),
- is_certainly_browser_timestamp);
-}
-
-bool PageLoadTracker::IsLikelyProvisionalAbort(
- base::TimeTicks abort_cause_time) {
- // Note that |abort_cause_time - abort_time| can be negative.
- return abort_type_ == ABORT_OTHER &&
- (abort_cause_time - abort_time_).InMilliseconds() < 100;
-}
-
-bool PageLoadTracker::MatchesOriginalNavigation(
- content::NavigationHandle* navigation_handle) {
- // Neither navigation should have committed.
- DCHECK(!navigation_handle->HasCommitted());
- DCHECK(commit_time_.is_null());
- return navigation_handle->GetURL() == url_;
-}
-
-void PageLoadTracker::UpdateAbortInternal(UserAbortType abort_type,
- base::TimeTicks timestamp,
- bool is_certainly_browser_timestamp) {
- // When a provisional navigation commits, that navigation's start time is
- // interpreted as the abort time for other provisional loads in the tab.
- // However, this only makes sense if the committed load started after the
- // aborted provisional loads started. Thus we ignore cases where the committed
- // load started before the aborted provisional load, as this would result in
- // recording a negative time-to-abort. The real issue here is that we have to
- // infer the cause of aborts. It would be better if the navigation code could
- // instead report the actual cause of an aborted navigation. See crbug/571647
- // for details.
- if (timestamp < navigation_start_) {
- RecordInternalError(ERR_ABORT_BEFORE_NAVIGATION_START);
- abort_type_ = ABORT_NONE;
- abort_time_ = base::TimeTicks();
- return;
- }
- abort_type_ = abort_type;
- abort_time_ = timestamp;
-
- if (is_certainly_browser_timestamp) {
- ClampBrowserTimestampIfInterProcessTimeTickSkew(&abort_time_);
- }
-}
-
-// static
-MetricsWebContentsObserver::MetricsWebContentsObserver(
- content::WebContents* web_contents,
- std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface)
- : content::WebContentsObserver(web_contents),
- in_foreground_(false),
- embedder_interface_(std::move(embedder_interface)),
- has_navigated_(false) {
- RegisterInputEventObserver(web_contents->GetRenderViewHost());
-}
-
-MetricsWebContentsObserver* MetricsWebContentsObserver::CreateForWebContents(
- content::WebContents* web_contents,
- std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface) {
- DCHECK(web_contents);
-
- MetricsWebContentsObserver* metrics = FromWebContents(web_contents);
- if (!metrics) {
- metrics = new MetricsWebContentsObserver(web_contents,
- std::move(embedder_interface));
- web_contents->SetUserData(UserDataKey(), metrics);
- }
- return metrics;
-}
-
-MetricsWebContentsObserver::~MetricsWebContentsObserver() {
- NotifyAbortAllLoads(ABORT_CLOSE);
-}
-
-void MetricsWebContentsObserver::RegisterInputEventObserver(
- content::RenderViewHost* host) {
- if (host != nullptr)
- host->GetWidget()->AddInputEventObserver(this);
-}
-
-void MetricsWebContentsObserver::UnregisterInputEventObserver(
- content::RenderViewHost* host) {
- if (host != nullptr)
- host->GetWidget()->RemoveInputEventObserver(this);
-}
-
-void MetricsWebContentsObserver::RenderViewHostChanged(
- content::RenderViewHost* old_host,
- content::RenderViewHost* new_host) {
- UnregisterInputEventObserver(old_host);
- RegisterInputEventObserver(new_host);
-}
-
-bool MetricsWebContentsObserver::OnMessageReceived(
- const IPC::Message& message,
- content::RenderFrameHost* render_frame_host) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MetricsWebContentsObserver, message,
- render_frame_host)
- IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void MetricsWebContentsObserver::DidStartNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsInMainFrame())
- return;
- if (embedder_interface_->IsPrerendering(web_contents()))
- return;
- if (navigation_handle->GetURL().spec().compare(url::kAboutBlankURL) == 0)
- return;
-
- std::unique_ptr<PageLoadTracker> last_aborted =
- NotifyAbortedProvisionalLoadsNewNavigation(navigation_handle);
-
- int chain_size_same_url = 0;
- int chain_size = 0;
- if (last_aborted) {
- if (last_aborted->MatchesOriginalNavigation(navigation_handle)) {
- chain_size_same_url = last_aborted->aborted_chain_size_same_url() + 1;
- } else if (last_aborted->aborted_chain_size_same_url() > 0) {
- LogAbortChainSameURLHistogram(
- last_aborted->aborted_chain_size_same_url());
- }
- chain_size = last_aborted->aborted_chain_size() + 1;
- }
-
- // Pass in the last committed url to the PageLoadTracker. If the MWCO has
- // never observed a committed load, use the last committed url from this
- // WebContent's opener. This is more accurate than using referrers due to
- // referrer sanitizing and origin referrers. Note that this could potentially
- // be inaccurate if the opener has since navigated.
- content::WebContents* opener = web_contents()->GetOpener();
- const GURL& opener_url =
- !has_navigated_ && opener
- ? web_contents()->GetOpener()->GetLastCommittedURL()
- : GURL::EmptyGURL();
- const GURL& currently_committed_url =
- committed_load_ ? committed_load_->committed_url() : opener_url;
- has_navigated_ = true;
-
- // We can have two provisional loads in some cases. E.g. a same-site
- // navigation can have a concurrent cross-process navigation started
- // from the omnibox.
- DCHECK_GT(2ul, provisional_loads_.size());
- // Passing raw pointers to observers_ and embedder_interface_ is safe because
- // the MetricsWebContentsObserver owns them both list and they are torn down
- // after the PageLoadTracker. The PageLoadTracker does not hold on to
- // committed_load_ or navigation_handle beyond the scope of the constructor.
- provisional_loads_.insert(std::make_pair(
- navigation_handle,
- base::WrapUnique(new PageLoadTracker(
- in_foreground_, embedder_interface_.get(), currently_committed_url,
- navigation_handle, chain_size, chain_size_same_url))));
-}
-
-const PageLoadExtraInfo
-MetricsWebContentsObserver::GetPageLoadExtraInfoForCommittedLoad() {
- DCHECK(committed_load_);
- return committed_load_->ComputePageLoadExtraInfo();
-}
-
-void MetricsWebContentsObserver::DidFinishNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsInMainFrame())
- return;
-
- std::unique_ptr<PageLoadTracker> finished_nav(
- std::move(provisional_loads_[navigation_handle]));
- provisional_loads_.erase(navigation_handle);
-
- // There's a chance a navigation could have started before we were added to a
- // tab. Bail out early if this is the case.
- if (!finished_nav)
- return;
-
- // Handle a pre-commit error here. Navigations that result in an error page
- // will be ignored. Note that downloads/204s will result in HasCommitted()
- // returning false.
- // TODO(csharrison): Track changes to NavigationHandle for signals when this
- // is the case (HTTP response headers).
- if (!navigation_handle->HasCommitted()) {
- finished_nav->FailedProvisionalLoad(navigation_handle);
-
- net::Error error = navigation_handle->GetNetErrorCode();
-
- // net::OK: This case occurs when the NavigationHandle finishes and reports
- // !HasCommitted(), but reports no net::Error. This should not occur
- // pre-PlzNavigate, but afterwards it should represent the navigation
- // stopped by the user before it was ready to commit.
- // net::ERR_ABORTED: An aborted provisional load has error net::ERR_ABORTED.
- // Note that this can come from some non user-initiated errors, such as
- // downloads, or 204 responses. See crbug.com/542369.
- if ((error == net::OK) || (error == net::ERR_ABORTED)) {
- finished_nav->NotifyAbort(ABORT_OTHER, base::TimeTicks::Now(), true);
- aborted_provisional_loads_.push_back(std::move(finished_nav));
- }
-
- return;
- }
-
- // Don't treat a same-page nav as a new page load.
- if (navigation_handle->IsSamePage())
- return;
-
- if (!navigation_handle->HasUserGesture() &&
- (navigation_handle->GetPageTransition() &
- ui::PAGE_TRANSITION_CLIENT_REDIRECT) != 0 &&
- committed_load_)
- committed_load_->NotifyClientRedirectTo(*finished_nav);
-
- // Notify other loads that they may have been aborted by this committed load.
- // Note that by using the committed navigation start as the abort cause, we
- // lose data on provisional loads that were aborted by other provisional
- // loads. Those will either be listed as ABORT_OTHER or as being aborted by
- // this load.
- // is_certainly_browser_timestamp is set to false because NavigationStart()
- // could be set in either the renderer or browser process.
- NotifyAbortAllLoadsWithTimestamp(
- AbortTypeForPageTransition(navigation_handle->GetPageTransition()),
- navigation_handle->NavigationStart(), false);
-
- committed_load_ = std::move(finished_nav);
- aborted_provisional_loads_.clear();
-
- const GURL& browser_url = web_contents()->GetLastCommittedURL();
- const std::string& mime_type = web_contents()->GetContentsMimeType();
- DCHECK(!browser_url.is_empty());
- DCHECK(!mime_type.empty());
- committed_load_->set_renderer_tracked(
- IsRelevantNavigation(navigation_handle, browser_url, mime_type));
-
- committed_load_->Commit(navigation_handle);
-}
-
-void MetricsWebContentsObserver::NavigationStopped() {
- NotifyAbortAllLoads(ABORT_STOP);
-}
-
-void MetricsWebContentsObserver::OnInputEvent(
- const blink::WebInputEvent& event) {
- // Ignore browser navigation or reload which comes with type Undefined.
- if (event.type == blink::WebInputEvent::Type::Undefined)
- return;
-
- if (!committed_load_) {
- RecordInternalError(ERR_USER_INPUT_WITH_NO_RELEVANT_LOAD);
- return;
- }
-
- committed_load_->OnInputEvent(event);
-}
-
-void MetricsWebContentsObserver::DidRedirectNavigation(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsInMainFrame())
- return;
- auto it = provisional_loads_.find(navigation_handle);
- if (it == provisional_loads_.end())
- return;
- it->second->Redirect(navigation_handle);
-}
-
-void MetricsWebContentsObserver::WasShown() {
- if (in_foreground_)
- return;
- in_foreground_ = true;
- if (committed_load_)
- committed_load_->WebContentsShown();
- for (const auto& kv : provisional_loads_) {
- kv.second->WebContentsShown();
- }
-}
-
-void MetricsWebContentsObserver::WasHidden() {
- if (!in_foreground_)
- return;
- in_foreground_ = false;
- if (committed_load_)
- committed_load_->WebContentsHidden();
- for (const auto& kv : provisional_loads_) {
- kv.second->WebContentsHidden();
- }
-}
-
-// This will occur when the process for the main RenderFrameHost exits, either
-// normally or from a crash. We eagerly log data from the last committed load if
-// we have one. Don't notify aborts here because this is probably not user
-// initiated. If it is (e.g. browser shutdown), other code paths will take care
-// of notifying.
-void MetricsWebContentsObserver::RenderProcessGone(
- base::TerminationStatus status) {
- // Other code paths will be run for normal renderer shutdown. Note that we
- // sometimes get the STILL_RUNNING value on fast shutdown.
- if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION ||
- status == base::TERMINATION_STATUS_STILL_RUNNING) {
- return;
- }
-
- // If this is a crash, eagerly log the aborted provisional loads and the
- // committed load. |provisional_loads_| don't need to be destroyed here
- // because their lifetime is tied to the NavigationHandle.
- committed_load_.reset();
- aborted_provisional_loads_.clear();
-}
-
-void MetricsWebContentsObserver::NotifyAbortAllLoads(UserAbortType abort_type) {
- NotifyAbortAllLoadsWithTimestamp(abort_type, base::TimeTicks::Now(), true);
-}
-
-void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp(
- UserAbortType abort_type,
- base::TimeTicks timestamp,
- bool is_certainly_browser_timestamp) {
- if (committed_load_)
- committed_load_->NotifyAbort(abort_type, timestamp,
- is_certainly_browser_timestamp);
- for (const auto& kv : provisional_loads_) {
- kv.second->NotifyAbort(abort_type, timestamp,
- is_certainly_browser_timestamp);
- }
- for (const auto& tracker : aborted_provisional_loads_) {
- if (tracker->IsLikelyProvisionalAbort(timestamp))
- tracker->UpdateAbort(abort_type, timestamp,
- is_certainly_browser_timestamp);
- }
- aborted_provisional_loads_.clear();
-}
-
-std::unique_ptr<PageLoadTracker>
-MetricsWebContentsObserver::NotifyAbortedProvisionalLoadsNewNavigation(
- content::NavigationHandle* new_navigation) {
- // If there are multiple aborted loads that can be attributed to this one,
- // just count the latest one for simplicity. Other loads will fall into the
- // OTHER bucket, though there shouldn't be very many.
- if (aborted_provisional_loads_.size() == 0)
- return nullptr;
- if (aborted_provisional_loads_.size() > 1)
- RecordInternalError(ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS);
-
- std::unique_ptr<PageLoadTracker> last_aborted_load =
- std::move(aborted_provisional_loads_.back());
- aborted_provisional_loads_.pop_back();
-
- base::TimeTicks timestamp = new_navigation->NavigationStart();
- if (last_aborted_load->IsLikelyProvisionalAbort(timestamp))
- last_aborted_load->UpdateAbort(ABORT_UNKNOWN_NAVIGATION, timestamp, false);
-
- aborted_provisional_loads_.clear();
- return last_aborted_load;
-}
-
-void MetricsWebContentsObserver::OnTimingUpdated(
- content::RenderFrameHost* render_frame_host,
- const PageLoadTiming& timing,
- const PageLoadMetadata& metadata) {
- bool error = false;
- if (!committed_load_ || !committed_load_->renderer_tracked()) {
- RecordInternalError(ERR_IPC_WITH_NO_RELEVANT_LOAD);
- error = true;
- }
-
- // We may receive notifications from frames that have been navigated away
- // from. We simply ignore them.
- if (render_frame_host != web_contents()->GetMainFrame()) {
- RecordInternalError(ERR_IPC_FROM_WRONG_FRAME);
- error = true;
- }
-
- // For urls like chrome://newtab, the renderer and browser disagree,
- // so we have to double check that the renderer isn't sending data from a
- // bad url like https://www.google.com/_/chrome/newtab.
- if (!web_contents()->GetLastCommittedURL().SchemeIsHTTPOrHTTPS()) {
- RecordInternalError(ERR_IPC_FROM_BAD_URL_SCHEME);
- error = true;
- }
-
- if (error)
- return;
-
- if (!committed_load_->UpdateTiming(timing, metadata)) {
- // If the page load tracker cannot update its timing, something is wrong
- // with the IPC (it's from another load, or it's invalid in some other way).
- // We expect this to be a rare occurrence.
- RecordInternalError(ERR_BAD_TIMING_IPC);
- }
-}
-
-} // namespace page_load_metrics
diff --git a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.h b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.h
deleted file mode 100644
index 2334223f46a..00000000000
--- a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.h
+++ /dev/null
@@ -1,350 +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 COMPONENTS_PAGE_LOAD_METRICS_BROWSER_METRICS_WEB_CONTENTS_OBSERVER_H_
-#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_METRICS_WEB_CONTENTS_OBSERVER_H_
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-#include "net/base/net_errors.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-
-namespace content {
-class NavigationHandle;
-class RenderFrameHost;
-} // namespace content
-
-namespace IPC {
-class Message;
-} // namespace IPC
-
-namespace page_load_metrics {
-
-class PageLoadTracker;
-
-namespace internal {
-
-extern const char kErrorEvents[];
-extern const char kAbortChainSizeReload[];
-extern const char kAbortChainSizeForwardBack[];
-extern const char kAbortChainSizeNewNavigation[];
-extern const char kAbortChainSizeNoCommit[];
-extern const char kAbortChainSizeSameURL[];
-
-} // namespace internal
-
-// These errors are internal to the page_load_metrics subsystem and do not
-// reflect actual errors that occur during a page load.
-//
-// If you add elements to this enum, make sure you update the enum
-// value in histograms.xml. Only add elements to the end to prevent
-// inconsistencies between versions.
-enum InternalErrorLoadEvent {
- // A timing IPC was sent from the renderer that did not line up with previous
- // data we've received (i.e. navigation start is different or the timing
- // struct is somehow invalid). This error can only occur once the IPC is
- // vetted in other ways (see other errors).
- ERR_BAD_TIMING_IPC,
-
- // The following IPCs are not mutually exclusive.
- //
- // We received an IPC when we weren't tracking a committed load. This will
- // often happen if we get an IPC from a bad URL scheme (that is, the renderer
- // sent us an IPC from a navigation we don't care about).
- ERR_IPC_WITH_NO_RELEVANT_LOAD,
-
- // Received a notification from a frame that has been navigated away from.
- ERR_IPC_FROM_WRONG_FRAME,
-
- // We received an IPC even through the last committed url from the browser
- // was not http/s. This can happen with the renderer sending IPCs for the
- // new tab page. This will often come paired with
- // ERR_IPC_WITH_NO_RELEVANT_LOAD.
- ERR_IPC_FROM_BAD_URL_SCHEME,
-
- // If we track a navigation, but the renderer sends us no IPCs. This could
- // occur if the browser filters loads less aggressively than the renderer.
- ERR_NO_IPCS_RECEIVED,
-
- // Tracks frequency with which we record an abort time that occurred before
- // navigation start. This is expected to happen in some cases (see comments in
- // cc file for details). We use this error counter to understand how often it
- // happens.
- ERR_ABORT_BEFORE_NAVIGATION_START,
-
- // A new navigation triggers abort updates in multiple trackers in
- // |aborted_provisional_loads_|, when usually there should only be one (the
- // navigation that just aborted because of this one). If this happens, the
- // latest aborted load is used to track the chain size.
- ERR_NAVIGATION_SIGNALS_MULIPLE_ABORTED_LOADS,
-
- // Receives user input before navigation start
- ERR_USER_INPUT_WITH_NO_RELEVANT_LOAD,
-
- // A TimeTicks value in the browser process has value less than
- // navigation_start_. This could happen if navigation_start_ was computed in
- // renderer process and the system clock has inter process time tick skew.
- ERR_INTER_PROCESS_TIME_TICK_SKEW,
-
- // Add values before this final count.
- ERR_LAST_ENTRY,
-};
-
-// This class serves as a functional interface to various chrome// features.
-// Impl version is defined in chrome/browser/page_load_metrics.
-class PageLoadMetricsEmbedderInterface {
- public:
- virtual ~PageLoadMetricsEmbedderInterface() {}
- virtual bool IsPrerendering(content::WebContents* web_contents) = 0;
- virtual void RegisterObservers(PageLoadTracker* metrics) = 0;
-};
-
-// This class tracks a given page load, starting from navigation start /
-// provisional load, until a new navigation commits or the navigation fails.
-// MetricsWebContentsObserver manages a set of provisional PageLoadTrackers, as
-// well as a committed PageLoadTracker.
-class PageLoadTracker {
- public:
- // Caller must guarantee that the embedder_interface pointer outlives this
- // class. The PageLoadTracker must not hold on to
- // currently_committed_load_or_null or navigation_handle beyond the scope of
- // the constructor.
- PageLoadTracker(bool in_foreground,
- PageLoadMetricsEmbedderInterface* embedder_interface,
- const GURL& currently_committed_url,
- content::NavigationHandle* navigation_handle,
- int aborted_chain_size,
- int aborted_chain_size_same_url);
- ~PageLoadTracker();
- void Redirect(content::NavigationHandle* navigation_handle);
- void Commit(content::NavigationHandle* navigation_handle);
- void FailedProvisionalLoad(content::NavigationHandle* navigation_handle);
- void WebContentsHidden();
- void WebContentsShown();
-
- void OnInputEvent(const blink::WebInputEvent& event);
-
- void NotifyClientRedirectTo(const PageLoadTracker& destination);
-
- // Returns true if the timing was successfully updated.
- bool UpdateTiming(const PageLoadTiming& timing,
- const PageLoadMetadata& metadata);
-
- void set_renderer_tracked(bool renderer_tracked);
- bool renderer_tracked() const { return renderer_tracked_; }
-
- int aborted_chain_size() const { return aborted_chain_size_; }
- int aborted_chain_size_same_url() const {
- return aborted_chain_size_same_url_;
- }
-
- UserAbortType abort_type() const { return abort_type_; }
- base::TimeTicks abort_time() const { return abort_time_; }
-
- void AddObserver(std::unique_ptr<PageLoadMetricsObserver> observer);
-
- // If the user performs some abort-like action while we are tracking this page
- // load, notify the tracker. Note that we may not classify this as an abort if
- // we've already performed a first paint.
- // is_certainly_browser_timestamp signifies if the timestamp passed is taken
- // in the
- // browser process or not. We need this to possibly clamp browser timestamp on
- // a machine with inter process time tick skew.
- void NotifyAbort(UserAbortType abort_type,
- base::TimeTicks timestamp,
- bool is_certainly_browser_timestamp);
- void UpdateAbort(UserAbortType abort_type,
- base::TimeTicks timestamp,
- bool is_certainly_browser_timestamp);
-
- // This method returns true if this page load has been aborted with type of
- // ABORT_OTHER, and the |abort_cause_time| is within a sufficiently close
- // delta to when it was aborted. Note that only provisional loads can be
- // aborted with ABORT_OTHER. While this heuristic is coarse, it works better
- // and is simpler than other feasible methods. See https://goo.gl/WKRG98.
- bool IsLikelyProvisionalAbort(base::TimeTicks abort_cause_time);
-
- bool MatchesOriginalNavigation(content::NavigationHandle* navigation_handle);
-
- // Only valid to call post-commit.
- const GURL& committed_url() const {
- DCHECK(!commit_time_.is_null());
- return url_;
- }
-
- base::TimeTicks navigation_start() const { return navigation_start_; }
-
- PageLoadExtraInfo ComputePageLoadExtraInfo();
-
- private:
- // This function converts a TimeTicks value taken in the browser process
- // to navigation_start_ if:
- // - base::TimeTicks is not comparable across processes because the clock
- // is not system wide monotonic.
- // - *event_time < navigation_start_
- void ClampBrowserTimestampIfInterProcessTimeTickSkew(
- base::TimeTicks* event_time);
-
- void UpdateAbortInternal(UserAbortType abort_type,
- base::TimeTicks timestamp,
- bool is_certainly_browser_timestamp);
-
- // If |final_navigation| is null, then this is an "unparented" abort chain,
- // and represents a sequence of provisional aborts that never ends with a
- // committed load.
- void LogAbortChainHistograms(content::NavigationHandle* final_navigation);
-
- // Whether the renderer should be sending timing IPCs to this page load.
- bool renderer_tracked_;
-
- // The navigation start in TimeTicks, not the wall time reported by Blink.
- const base::TimeTicks navigation_start_;
-
- // Time this page load was committed. If this page load hasn't committed,
- // |commit_time_| will be zero.
- base::TimeTicks commit_time_;
-
- // The URL of this page load. This is the provisional url before commit
- // (before redirects), and the committed url after commit.
- GURL url_;
-
- // Will be ABORT_NONE if we have not aborted this load yet. Otherwise will
- // be the first abort action the user performed.
- UserAbortType abort_type_;
- base::TimeTicks abort_time_;
-
- // We record separate metrics for events that occur after a background,
- // because metrics like layout/paint are delayed artificially
- // when they occur in the background.
- base::TimeTicks background_time_;
- base::TimeTicks foreground_time_;
- bool started_in_foreground_;
-
- PageLoadTiming timing_;
- PageLoadMetadata metadata_;
-
- // This is a subtle member. If a provisional load A gets aborted by
- // provisional load B, which gets aborted by C that eventually commits, then
- // there exists an abort chain of length 2, starting at A's navigation_start.
- // This is useful because it allows histograming abort chain lengths based on
- // what the last load's transition type is. i.e. holding down F-5 to spam
- // reload will produce a long chain with the RELOAD transition.
- const int aborted_chain_size_;
-
- // This member counts consecutive provisional aborts that share a url. It will
- // always be less than or equal to |aborted_chain_size_|.
- const int aborted_chain_size_same_url_;
-
- // Interface to chrome features. Must outlive the class.
- PageLoadMetricsEmbedderInterface* const embedder_interface_;
-
- std::vector<std::unique_ptr<PageLoadMetricsObserver>> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(PageLoadTracker);
-};
-
-// MetricsWebContentsObserver tracks page loads and loading metrics
-// related data based on IPC messages received from a
-// MetricsRenderFrameObserver.
-class MetricsWebContentsObserver
- : public content::WebContentsObserver,
- public content::WebContentsUserData<MetricsWebContentsObserver>,
- public content::RenderWidgetHost::InputEventObserver {
- public:
- // Note that the returned metrics is owned by the web contents.
- static MetricsWebContentsObserver* CreateForWebContents(
- content::WebContents* web_contents,
- std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface);
- MetricsWebContentsObserver(
- content::WebContents* web_contents,
- std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface);
- ~MetricsWebContentsObserver() override;
-
- // content::WebContentsObserver implementation:
- bool OnMessageReceived(const IPC::Message& message,
- content::RenderFrameHost* render_frame_host) override;
- void DidStartNavigation(
- content::NavigationHandle* navigation_handle) override;
- void DidFinishNavigation(
- content::NavigationHandle* navigation_handle) override;
- void DidRedirectNavigation(
- content::NavigationHandle* navigation_handle) override;
- void NavigationStopped() override;
- void OnInputEvent(const blink::WebInputEvent& event) override;
- void WasShown() override;
- void WasHidden() override;
- void RenderProcessGone(base::TerminationStatus status) override;
- void RenderViewHostChanged(content::RenderViewHost* old_host,
- content::RenderViewHost* new_host) override;
-
- // This getter function is required for testing.
- const PageLoadExtraInfo GetPageLoadExtraInfoForCommittedLoad();
-
- private:
- friend class content::WebContentsUserData<MetricsWebContentsObserver>;
-
- // Notify all loads, provisional and committed, that we performed an action
- // that might abort them.
- void NotifyAbortAllLoads(UserAbortType abort_type);
- void NotifyAbortAllLoadsWithTimestamp(UserAbortType abort_type,
- base::TimeTicks timestamp,
- bool is_certainly_browser_timestamp);
-
- // Register / Unregister input event callback to given RenderViewHost
- void RegisterInputEventObserver(content::RenderViewHost* host);
- void UnregisterInputEventObserver(content::RenderViewHost* host);
-
- // Notify aborted provisional loads that a new navigation occurred. This is
- // used for more consistent attribution tracking for aborted provisional
- // loads. This method returns the provisional load that was likely aborted
- // by this navigation, to help instantiate the new PageLoadTracker.
- std::unique_ptr<PageLoadTracker> NotifyAbortedProvisionalLoadsNewNavigation(
- content::NavigationHandle* new_navigation);
-
- void OnTimingUpdated(content::RenderFrameHost*,
- const PageLoadTiming& timing,
- const PageLoadMetadata& metadata);
-
- // True if the web contents is currently in the foreground.
- bool in_foreground_;
-
- // The PageLoadTrackers must be deleted before the |embedded_interface_|,
- // because they hold a pointer to the |embedder_interface_|.
- std::unique_ptr<PageLoadMetricsEmbedderInterface> embedder_interface_;
-
- // This map tracks all of the navigations ongoing that are not committed
- // yet. Once a navigation is committed, it moves from the map to
- // committed_load_. Note that a PageLoadTrackers NavigationHandle is only
- // valid until commit time, when we remove it from the map.
- std::map<content::NavigationHandle*, std::unique_ptr<PageLoadTracker>>
- provisional_loads_;
-
- // Tracks aborted provisional loads for a little bit longer than usual (one
- // more navigation commit at the max), in order to better understand how the
- // navigation failed. This is because most provisional loads are destroyed
- // and vanish before we get signal about what caused the abort (new
- // navigation, stop button, etc.).
- std::vector<std::unique_ptr<PageLoadTracker>> aborted_provisional_loads_;
-
- std::unique_ptr<PageLoadTracker> committed_load_;
-
- // Has the MWCO observed at least one navigation?
- bool has_navigated_;
-
- DISALLOW_COPY_AND_ASSIGN(MetricsWebContentsObserver);
-};
-
-} // namespace page_load_metrics
-
-#endif // COMPONENTS_PAGE_LOAD_METRICS_BROWSER_METRICS_WEB_CONTENTS_OBSERVER_H_
diff --git a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
deleted file mode 100644
index 993a0f2fc4e..00000000000
--- a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ /dev/null
@@ -1,451 +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 "components/page_load_metrics/browser/metrics_web_contents_observer.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/process/kill.h"
-#include "base/test/histogram_tester.h"
-#include "base/time/time.h"
-#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
-#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/test/test_renderer_host.h"
-#include "content/public/test/web_contents_tester.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace page_load_metrics {
-
-namespace {
-
-const char kDefaultTestUrl[] = "https://google.com/";
-const char kDefaultTestUrlAnchor[] = "https://google.com/#samepage";
-const char kDefaultTestUrl2[] = "https://whatever.com/";
-
-// Simple PageLoadMetricsObserver that copies observed PageLoadTimings into the
-// provided std::vector, so they can be analyzed by unit tests.
-class TestPageLoadMetricsObserver : public PageLoadMetricsObserver {
- public:
- explicit TestPageLoadMetricsObserver(
- std::vector<PageLoadTiming>* updated_timings,
- std::vector<PageLoadTiming>* complete_timings,
- std::vector<GURL>* observed_committed_urls)
- : updated_timings_(updated_timings),
- complete_timings_(complete_timings),
- observed_committed_urls_(observed_committed_urls) {}
-
- void OnStart(content::NavigationHandle* navigation_handle,
- const GURL& currently_committed_url,
- bool started_in_foreground) override {
- observed_committed_urls_->push_back(currently_committed_url);
- }
-
- void OnTimingUpdate(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) override {
- updated_timings_->push_back(timing);
- }
-
- void OnComplete(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) override {
- complete_timings_->push_back(timing);
- }
-
- private:
- std::vector<PageLoadTiming>* const updated_timings_;
- std::vector<PageLoadTiming>* const complete_timings_;
- std::vector<GURL>* const observed_committed_urls_;
-};
-
-class TestPageLoadMetricsEmbedderInterface
- : public PageLoadMetricsEmbedderInterface {
- public:
- TestPageLoadMetricsEmbedderInterface() : is_prerendering_(false) {}
-
- bool IsPrerendering(content::WebContents* web_contents) override {
- return is_prerendering_;
- }
- void set_is_prerendering(bool is_prerendering) {
- is_prerendering_ = is_prerendering;
- }
- void RegisterObservers(PageLoadTracker* tracker) override {
- tracker->AddObserver(base::WrapUnique(new TestPageLoadMetricsObserver(
- &updated_timings_, &complete_timings_, &observed_committed_urls_)));
- }
- const std::vector<PageLoadTiming>& updated_timings() const {
- return updated_timings_;
- }
- const std::vector<PageLoadTiming>& complete_timings() const {
- return complete_timings_;
- }
-
- // currently_committed_urls passed to OnStart().
- const std::vector<GURL>& observed_committed_urls_from_on_start() const {
- return observed_committed_urls_;
- }
-
- private:
- std::vector<PageLoadTiming> updated_timings_;
- std::vector<PageLoadTiming> complete_timings_;
- std::vector<GURL> observed_committed_urls_;
- bool is_prerendering_;
-};
-
-} // namespace
-
-class MetricsWebContentsObserverTest
- : public content::RenderViewHostTestHarness {
- public:
- MetricsWebContentsObserverTest() : num_errors_(0) {}
-
- void SetUp() override {
- RenderViewHostTestHarness::SetUp();
- AttachObserver();
- }
-
- void SimulateTimingUpdate(const PageLoadTiming& timing) {
- SimulateTimingUpdate(timing, web_contents()->GetMainFrame());
- }
-
- void SimulateTimingUpdate(const PageLoadTiming& timing,
- content::RenderFrameHost* render_frame_host) {
- ASSERT_TRUE(observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing,
- PageLoadMetadata()),
- render_frame_host));
- }
-
- void AttachObserver() {
- embedder_interface_ = new TestPageLoadMetricsEmbedderInterface();
- observer_.reset(new MetricsWebContentsObserver(
- web_contents(), base::WrapUnique(embedder_interface_)));
- observer_->WasShown();
- }
-
- void CheckErrorEvent(InternalErrorLoadEvent error, int count) {
- histogram_tester_.ExpectBucketCount(internal::kErrorEvents, error, count);
- num_errors_ += count;
- }
-
- void CheckTotalErrorEvents() {
- histogram_tester_.ExpectTotalCount(internal::kErrorEvents, num_errors_);
- }
-
- void CheckNoErrorEvents() {
- histogram_tester_.ExpectTotalCount(internal::kErrorEvents, 0);
- }
-
- void AssertNoNonEmptyTimingReported() {
- ASSERT_FALSE(embedder_interface_->complete_timings().empty());
- for (const auto& timing : embedder_interface_->complete_timings()) {
- ASSERT_TRUE(timing.IsEmpty());
- }
- }
-
- void AssertNonEmptyTimingsReported(size_t expected_non_empty_timings) {
- ASSERT_GE(embedder_interface_->complete_timings().size(),
- expected_non_empty_timings);
- size_t actual_non_empty_timings = 0;
- for (const auto& timing : embedder_interface_->complete_timings()) {
- if (!timing.IsEmpty()) {
- ++actual_non_empty_timings;
- }
- }
- ASSERT_EQ(expected_non_empty_timings, actual_non_empty_timings);
- ASSERT_GE(embedder_interface_->updated_timings().size(),
- actual_non_empty_timings);
- }
-
- int CountCompleteTimingReported() {
- return embedder_interface_->complete_timings().size();
- }
- int CountUpdatedTimingReported() {
- return embedder_interface_->updated_timings().size();
- }
-
- const std::vector<GURL>& observed_committed_urls_from_on_start() const {
- return embedder_interface_->observed_committed_urls_from_on_start();
- }
-
- protected:
- base::HistogramTester histogram_tester_;
- TestPageLoadMetricsEmbedderInterface* embedder_interface_;
- std::unique_ptr<MetricsWebContentsObserver> observer_;
-
- private:
- int num_errors_;
-
- DISALLOW_COPY_AND_ASSIGN(MetricsWebContentsObserverTest);
-};
-
-TEST_F(MetricsWebContentsObserverTest, SuccessfulMainFrameNavigation) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
- timing.response_start = base::TimeDelta::FromMilliseconds(2);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
-
- ASSERT_TRUE(observed_committed_urls_from_on_start().empty());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
- ASSERT_EQ(1u, observed_committed_urls_from_on_start().size());
- ASSERT_TRUE(observed_committed_urls_from_on_start().at(0).is_empty());
-
- ASSERT_EQ(0, CountUpdatedTimingReported());
- SimulateTimingUpdate(timing);
- ASSERT_EQ(1, CountUpdatedTimingReported());
- ASSERT_EQ(0, CountCompleteTimingReported());
-
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
- AssertNonEmptyTimingsReported(1);
- ASSERT_EQ(2u, observed_committed_urls_from_on_start().size());
- ASSERT_EQ(kDefaultTestUrl,
- observed_committed_urls_from_on_start().at(1).spec());
- ASSERT_EQ(1, CountUpdatedTimingReported());
-
- CheckNoErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, NotInMainFrame) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- content::RenderFrameHostTester* rfh_tester =
- content::RenderFrameHostTester::For(main_rfh());
- content::RenderFrameHost* subframe = rfh_tester->AppendChild("subframe");
-
- content::RenderFrameHostTester* subframe_tester =
- content::RenderFrameHostTester::For(subframe);
- subframe_tester->SimulateNavigationStart(GURL(kDefaultTestUrl2));
- subframe_tester->SimulateNavigationCommit(GURL(kDefaultTestUrl2));
- SimulateTimingUpdate(timing, subframe);
- subframe_tester->SimulateNavigationStop();
-
- // Navigate again to see if the timing updated for a subframe message.
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- ASSERT_EQ(0, CountUpdatedTimingReported());
- AssertNoNonEmptyTimingReported();
- CheckErrorEvent(ERR_IPC_FROM_WRONG_FRAME, 1);
- CheckTotalErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, SamePageNoTrigger) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
- ASSERT_EQ(0, CountUpdatedTimingReported());
- SimulateTimingUpdate(timing);
- ASSERT_EQ(1, CountUpdatedTimingReported());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrlAnchor));
- // A same page navigation shouldn't trigger logging UMA for the original.
- ASSERT_EQ(1, CountUpdatedTimingReported());
- AssertNoNonEmptyTimingReported();
- CheckNoErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, DontLogPrerender) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- embedder_interface_->set_is_prerendering(true);
-
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
- SimulateTimingUpdate(timing);
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
- ASSERT_EQ(0, CountUpdatedTimingReported());
- ASSERT_EQ(0, CountCompleteTimingReported());
- CheckErrorEvent(ERR_IPC_WITH_NO_RELEVANT_LOAD, 1);
- CheckTotalErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, DontLogIrrelevantNavigation) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(10);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
-
- GURL about_blank_url = GURL("about:blank");
- web_contents_tester->NavigateAndCommit(about_blank_url);
- SimulateTimingUpdate(timing);
- ASSERT_EQ(0, CountUpdatedTimingReported());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
- ASSERT_EQ(0, CountUpdatedTimingReported());
- ASSERT_EQ(0, CountCompleteTimingReported());
-
- CheckErrorEvent(ERR_IPC_FROM_BAD_URL_SCHEME, 1);
- CheckErrorEvent(ERR_IPC_WITH_NO_RELEVANT_LOAD, 1);
- CheckTotalErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, NotInMainError) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- content::RenderFrameHostTester* rfh_tester =
- content::RenderFrameHostTester::For(main_rfh());
- content::RenderFrameHost* subframe = rfh_tester->AppendChild("subframe");
-
- content::RenderFrameHostTester* subframe_tester =
- content::RenderFrameHostTester::For(subframe);
- subframe_tester->SimulateNavigationStart(GURL(kDefaultTestUrl2));
- subframe_tester->SimulateNavigationCommit(GURL(kDefaultTestUrl2));
- SimulateTimingUpdate(timing, subframe);
- CheckErrorEvent(ERR_IPC_FROM_WRONG_FRAME, 1);
- CheckTotalErrorEvents();
- ASSERT_EQ(0, CountUpdatedTimingReported());
- ASSERT_EQ(0, CountCompleteTimingReported());
-}
-
-TEST_F(MetricsWebContentsObserverTest, BadIPC) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(10);
- PageLoadTiming timing2;
- timing2.navigation_start = base::Time::FromDoubleT(100);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- SimulateTimingUpdate(timing);
- ASSERT_EQ(1, CountUpdatedTimingReported());
- SimulateTimingUpdate(timing2);
- ASSERT_EQ(1, CountUpdatedTimingReported());
-
- CheckErrorEvent(ERR_BAD_TIMING_IPC, 1);
- CheckTotalErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, ObservePartialNavigation) {
- // Delete the observer for this test, add it once the navigation has started.
- observer_.reset();
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(10);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- content::RenderFrameHostTester* rfh_tester =
- content::RenderFrameHostTester::For(main_rfh());
-
- // Start the navigation, then start observing the web contents. This used to
- // crash us. Make sure we bail out and don't log histograms.
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl));
- AttachObserver();
- rfh_tester->SimulateNavigationCommit(GURL(kDefaultTestUrl));
-
- SimulateTimingUpdate(timing);
-
- // Navigate again to force histogram logging.
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
- ASSERT_EQ(0, CountCompleteTimingReported());
- ASSERT_EQ(0, CountUpdatedTimingReported());
- CheckErrorEvent(ERR_IPC_WITH_NO_RELEVANT_LOAD, 1);
- CheckTotalErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, DontLogAbortChains) {
- NavigateAndCommit(GURL(kDefaultTestUrl));
- NavigateAndCommit(GURL(kDefaultTestUrl2));
- NavigateAndCommit(GURL(kDefaultTestUrl));
- histogram_tester_.ExpectTotalCount(internal::kAbortChainSizeNewNavigation, 0);
- CheckErrorEvent(ERR_NO_IPCS_RECEIVED, 2);
- CheckTotalErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, LogAbortChains) {
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- content::RenderFrameHostTester* rfh_tester =
- content::RenderFrameHostTester::For(main_rfh());
- // Start and abort three loads before one finally commits.
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl));
- rfh_tester->SimulateNavigationError(GURL(kDefaultTestUrl), net::ERR_ABORTED);
- rfh_tester->SimulateNavigationStop();
-
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl2));
- rfh_tester->SimulateNavigationError(GURL(kDefaultTestUrl2), net::ERR_ABORTED);
- rfh_tester->SimulateNavigationStop();
-
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl));
- rfh_tester->SimulateNavigationError(GURL(kDefaultTestUrl), net::ERR_ABORTED);
- rfh_tester->SimulateNavigationStop();
-
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
- histogram_tester_.ExpectTotalCount(internal::kAbortChainSizeNewNavigation, 1);
- histogram_tester_.ExpectBucketCount(internal::kAbortChainSizeNewNavigation, 3,
- 1);
- CheckNoErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, LogAbortChainsSameURL) {
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- content::RenderFrameHostTester* rfh_tester =
- content::RenderFrameHostTester::For(main_rfh());
- // Start and abort three loads before one finally commits.
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl));
- rfh_tester->SimulateNavigationError(GURL(kDefaultTestUrl), net::ERR_ABORTED);
- rfh_tester->SimulateNavigationStop();
-
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl));
- rfh_tester->SimulateNavigationError(GURL(kDefaultTestUrl), net::ERR_ABORTED);
- rfh_tester->SimulateNavigationStop();
-
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl));
- rfh_tester->SimulateNavigationError(GURL(kDefaultTestUrl), net::ERR_ABORTED);
- rfh_tester->SimulateNavigationStop();
-
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
- histogram_tester_.ExpectTotalCount(internal::kAbortChainSizeNewNavigation, 1);
- histogram_tester_.ExpectBucketCount(internal::kAbortChainSizeNewNavigation, 3,
- 1);
- histogram_tester_.ExpectTotalCount(internal::kAbortChainSizeSameURL, 1);
- histogram_tester_.ExpectBucketCount(internal::kAbortChainSizeSameURL, 3, 1);
-}
-
-TEST_F(MetricsWebContentsObserverTest, LogAbortChainsNoCommit) {
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- content::RenderFrameHostTester* rfh_tester =
- content::RenderFrameHostTester::For(main_rfh());
- // Start and abort three loads before one finally commits.
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl));
- rfh_tester->SimulateNavigationError(GURL(kDefaultTestUrl), net::ERR_ABORTED);
- rfh_tester->SimulateNavigationStop();
-
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl2));
- rfh_tester->SimulateNavigationError(GURL(kDefaultTestUrl2), net::ERR_ABORTED);
- rfh_tester->SimulateNavigationStop();
-
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl));
- rfh_tester->SimulateNavigationError(GURL(kDefaultTestUrl), net::ERR_ABORTED);
- rfh_tester->SimulateNavigationStop();
-
- web_contents()->Stop();
-
- histogram_tester_.ExpectTotalCount(internal::kAbortChainSizeNoCommit, 1);
- histogram_tester_.ExpectBucketCount(internal::kAbortChainSizeNoCommit, 3,
- 1);
-}
-
-} // namespace page_load_metrics
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_observer.cc b/chromium/components/page_load_metrics/browser/page_load_metrics_observer.cc
deleted file mode 100644
index 98ffef5cdf6..00000000000
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_observer.cc
+++ /dev/null
@@ -1,30 +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 "components/page_load_metrics/browser/page_load_metrics_observer.h"
-
-namespace page_load_metrics {
-
-PageLoadExtraInfo::PageLoadExtraInfo(
- const base::Optional<base::TimeDelta>& first_background_time,
- const base::Optional<base::TimeDelta>& first_foreground_time,
- bool started_in_foreground,
- const GURL& committed_url,
- const base::Optional<base::TimeDelta>& time_to_commit,
- UserAbortType abort_type,
- const base::Optional<base::TimeDelta>& time_to_abort,
- const PageLoadMetadata& metadata)
- : first_background_time(first_background_time),
- first_foreground_time(first_foreground_time),
- started_in_foreground(started_in_foreground),
- committed_url(committed_url),
- time_to_commit(time_to_commit),
- abort_type(abort_type),
- time_to_abort(time_to_abort),
- metadata(metadata) {}
-
-PageLoadExtraInfo::PageLoadExtraInfo(const PageLoadExtraInfo& other) = default;
-
-PageLoadExtraInfo::~PageLoadExtraInfo() {}
-} // namespace page_load_metrics
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h b/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h
deleted file mode 100644
index 3b486dcfb5f..00000000000
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h
+++ /dev/null
@@ -1,192 +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 COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_OBSERVER_H_
-#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_OBSERVER_H_
-
-#include "base/macros.h"
-#include "base/optional.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "content/public/browser/navigation_handle.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "url/gurl.h"
-
-namespace page_load_metrics {
-
-// This enum represents how a page load ends. If the action occurs before the
-// page load finishes (or reaches some point like first paint), then we consider
-// the load to be aborted.
-enum UserAbortType {
- // Represents no abort.
- ABORT_NONE,
-
- // If the user presses reload or shift-reload.
- ABORT_RELOAD,
-
- // The user presses the back/forward button.
- ABORT_FORWARD_BACK,
-
- // If the navigation is replaced by a new navigation. This includes link
- // clicks, typing in the omnibox (not a reload), and form submissions.
- ABORT_NEW_NAVIGATION,
-
- // If the user presses the stop X button.
- ABORT_STOP,
-
- // If the navigation is aborted by closing the tab or browser.
- ABORT_CLOSE,
-
- // We don't know why the navigation aborted. This is the value we assign to an
- // aborted load if the only signal we get is a provisional load finishing
- // without committing, either without error or with net::ERR_ABORTED.
- ABORT_OTHER,
-
- // The load aborted due to another navigation, but it isn't clear what type of
- // navigation it was.
- ABORT_UNKNOWN_NAVIGATION,
-
- // Add values before this final count.
- ABORT_LAST_ENTRY
-};
-
-struct PageLoadExtraInfo {
- PageLoadExtraInfo(
- const base::Optional<base::TimeDelta>& first_background_time,
- const base::Optional<base::TimeDelta>& first_foreground_time,
- bool started_in_foreground,
- const GURL& committed_url,
- const base::Optional<base::TimeDelta>& time_to_commit,
- UserAbortType abort_type,
- const base::Optional<base::TimeDelta>& time_to_abort,
- const PageLoadMetadata& metadata);
-
- PageLoadExtraInfo(const PageLoadExtraInfo& other);
-
- ~PageLoadExtraInfo();
-
- // The first time that the page was backgrounded since the navigation started.
- const base::Optional<base::TimeDelta> first_background_time;
-
- // The first time that the page was foregrounded since the navigation started.
- const base::Optional<base::TimeDelta> first_foreground_time;
-
- // True if the page load started in the foreground.
- const bool started_in_foreground;
-
- // Committed URL. If the page load did not commit, |committed_url| will be
- // empty.
- const GURL committed_url;
-
- // Time from navigation start until commit.
- const base::Optional<base::TimeDelta> time_to_commit;
-
- // The abort time and time to abort for this page load. If the page was not
- // aborted, |abort_type| will be |ABORT_NONE|.
- const UserAbortType abort_type;
- const base::Optional<base::TimeDelta> time_to_abort;
-
- // Extra information supplied to the page load metrics system from the
- // renderer.
- const PageLoadMetadata metadata;
-};
-
-// Interface for PageLoadMetrics observers. All instances of this class are
-// owned by the PageLoadTracker tracking a page load. They will be deleted after
-// calling OnComplete.
-class PageLoadMetricsObserver {
- public:
- virtual ~PageLoadMetricsObserver() {}
-
- // The page load started, with the given navigation handle. Note that OnStart
- // is called for same-page navigations. Implementers of OnStart that only want
- // to process non-same-page navigations should also check to see that the page
- // load committed via OnCommit or committed_url in
- // PageLoadExtraInfo. currently_committed_url contains the URL of the
- // committed page load at the time the navigation for navigation_handle was
- // initiated, or the empty URL if there was no committed page load at the time
- // the navigation was initiated.
- virtual void OnStart(content::NavigationHandle* navigation_handle,
- const GURL& currently_committed_url,
- bool started_in_foreground) {}
-
- // OnRedirect is triggered when a page load redirects to another URL.
- // The navigation handle holds relevant data for the navigation, but will
- // be destroyed soon after this call. Don't hold a reference to it. This can
- // be called multiple times.
- virtual void OnRedirect(content::NavigationHandle* navigation_handle) {}
-
- // OnCommit is triggered when a page load commits, i.e. when we receive the
- // first data for the request. The navigation handle holds relevant data for
- // the navigation, but will be destroyed soon after this call. Don't hold a
- // reference to it.
- // Note that this does not get called for same page navigations.
- virtual void OnCommit(content::NavigationHandle* navigation_handle) {}
-
- // OnFailedProvisionalLoad is triggered when a provisional load failed and did
- // not commit. Note that provisional loads that result in downloads or 204s
- // are aborted by the system, and thus considered failed provisional loads.
- virtual void OnFailedProvisionalLoad(
- content::NavigationHandle* navigation_handle) {}
-
- // OnTimingUpdate is triggered when an updated PageLoadTiming is
- // available. This method may be called multiple times over the course of the
- // page load. Note that this is currently an experimental API which may be
- // removed in the future. Please email loading-dev@chromium.org if you intend
- // to override this method.
- virtual void OnTimingUpdate(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
-
- // OnHidden is triggered when a page leaves the foreground. It does not fire
- // when a foreground page is permanently closed; for that, listen to
- // OnComplete instead.
- virtual void OnHidden() {}
-
- // OnShown is triggered when a page is brought to the foreground. It does not
- // fire when the page first loads; for that, listen for OnStart instead.
- virtual void OnShown() {}
-
- // OnComplete is triggered when we are ready to record metrics for this page
- // load. This will happen some time after commit. The PageLoadTiming struct
- // contains timing data and the PageLoadExtraInfo struct contains other useful
- // data collected over the course of the page load. If the load did not
- // receive any timing information, |timing.IsEmpty()| will be true.
- // After this call, the object will be deleted.
- virtual void OnComplete(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
-
- // OnUserInput is triggered when a new user input is passed in to
- // web_contents. Contains a TimeDelta from navigation start.
- virtual void OnUserInput(const blink::WebInputEvent& event) {}
-
- // The following methods are invoked at most once, when the timing for the
- // associated event first becomes available.
- virtual void OnDomContentLoadedEventStart(
- const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
- virtual void OnLoadEventStart(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
- virtual void OnFirstLayout(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
- virtual void OnFirstPaint(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
- virtual void OnFirstTextPaint(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
- virtual void OnFirstImagePaint(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
- virtual void OnFirstContentfulPaint(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
- virtual void OnParseStart(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
- virtual void OnParseStop(const PageLoadTiming& timing,
- const PageLoadExtraInfo& extra_info) {}
-
- // Observer method to be invoked when there is a change in PageLoadMetadata's
- // behavior_flags.
- virtual void OnLoadingBehaviorObserved(
- const page_load_metrics::PageLoadExtraInfo& extra_info) {}
-};
-
-} // namespace page_load_metrics
-
-#endif // COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_util.cc b/chromium/components/page_load_metrics/browser/page_load_metrics_util.cc
deleted file mode 100644
index 96217bf00cd..00000000000
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_util.cc
+++ /dev/null
@@ -1,45 +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 "components/page_load_metrics/browser/page_load_metrics_util.h"
-
-#include <algorithm>
-
-#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-
-namespace page_load_metrics {
-
-bool WasStartedInForegroundEventInForeground(base::TimeDelta event,
- const PageLoadExtraInfo& info) {
- return info.started_in_foreground && !event.is_zero() &&
- (!info.first_background_time ||
- event <= info.first_background_time.value());
-}
-
-// TODO (shivanisha) The above function is used for TimeDeltas coming over IPC.
-// Merge these two when page_load_metrics only handles Optional TimeDelta
-// values in the browser process.
-bool WasStartedInForegroundOptionalEventInForeground(
- const base::Optional<base::TimeDelta>& event,
- const PageLoadExtraInfo& info) {
- return info.started_in_foreground && event &&
- (!info.first_background_time ||
- event.value() <= info.first_background_time.value());
-}
-
-bool WasParseInForeground(base::TimeDelta parse_start,
- base::TimeDelta parse_stop,
- const PageLoadExtraInfo& info) {
- if (parse_start.is_zero()) {
- return false;
- }
- const bool incomplete_parse_in_foreground = parse_stop.is_zero() &&
- info.started_in_foreground &&
- !info.first_background_time;
-
- return incomplete_parse_in_foreground ||
- WasStartedInForegroundEventInForeground(parse_stop, info);
-}
-} // namespace page_load_metrics
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_util.h b/chromium/components/page_load_metrics/browser/page_load_metrics_util.h
deleted file mode 100644
index 66dc3aa7119..00000000000
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_util.h
+++ /dev/null
@@ -1,48 +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 COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_UTIL_H_
-#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_UTIL_H_
-
-#include "base/metrics/histogram_macros.h"
-#include "base/optional.h"
-#include "base/time/time.h"
-
-#define PAGE_LOAD_HISTOGRAM(name, sample) \
- UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \
- base::TimeDelta::FromMilliseconds(10), \
- base::TimeDelta::FromMinutes(10), 100)
-
-namespace page_load_metrics {
-
-struct PageLoadExtraInfo;
-struct PageLoadTiming;
-
-// Returns true if:
-// - We have timing information for the event.
-// - The page load started while the page was in the foreground.
-// - The event occurred prior to the page being moved to the background.
-// When a page is backgrounded, some events (e.g. paint) are delayed. Since
-// these data points can skew the mean, they should not be mixed with timing
-// events that occurred in the foreground.
-// If the event time delta and background time delta are equal, we still
-// consider the event to be logged in the foreground histogram since any
-// background specific handling would not yet have been applied to that event.
-bool WasStartedInForegroundEventInForeground(base::TimeDelta event,
- const PageLoadExtraInfo& info);
-
-bool WasStartedInForegroundOptionalEventInForeground(
- const base::Optional<base::TimeDelta>& event,
- const PageLoadExtraInfo& info);
-
-// Returns true if:
-// - Parse started and did not complete but the entire page load duration
-// happened in the foreground.
-// - Parse completed and happened entirely in the foreground.
-bool WasParseInForeground(base::TimeDelta parse_start,
- base::TimeDelta parse_stop,
- const PageLoadExtraInfo& info);
-} // namespace page_load_metrics
-
-#endif // COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_UTIL_H_
diff --git a/chromium/components/page_load_metrics/common/BUILD.gn b/chromium/components/page_load_metrics/common/BUILD.gn
deleted file mode 100644
index 8ba2aad4599..00000000000
--- a/chromium/components/page_load_metrics/common/BUILD.gn
+++ /dev/null
@@ -1,17 +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.
-
-# GYP version: components/page_load_metrics.gypi:page_load_metrics_common
-static_library("common") {
- sources = [
- "page_load_metrics_messages.cc",
- "page_load_metrics_messages.h",
- "page_load_timing.cc",
- "page_load_timing.h",
- ]
- deps = [
- "//base",
- "//ipc",
- ]
-}
diff --git a/chromium/components/page_load_metrics/common/page_load_metrics_messages.cc b/chromium/components/page_load_metrics/common/page_load_metrics_messages.cc
deleted file mode 100644
index 07bdd98ff65..00000000000
--- a/chromium/components/page_load_metrics/common/page_load_metrics_messages.cc
+++ /dev/null
@@ -1,39 +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.
-
-// Get basic type definitions.
-#define IPC_MESSAGE_IMPL
-#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-
-// Generate constructors.
-#include "ipc/struct_constructor_macros.h"
-#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-
-// Generate destructors.
-#include "ipc/struct_destructor_macros.h"
-#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-
-// Generate param traits size methods.
-#include "ipc/param_traits_size_macros.h"
-namespace IPC {
-#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-}
-
-// Generate param traits write methods.
-#include "ipc/param_traits_write_macros.h"
-namespace IPC {
-#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-} // namespace IPC
-
-// Generate param traits read methods.
-#include "ipc/param_traits_read_macros.h"
-namespace IPC {
-#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-} // namespace IPC
-
-// Generate param traits log methods.
-#include "ipc/param_traits_log_macros.h"
-namespace IPC {
-#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-} // namespace IPC
diff --git a/chromium/components/page_load_metrics/common/page_load_metrics_messages.h b/chromium/components/page_load_metrics/common/page_load_metrics_messages.h
deleted file mode 100644
index d71a3763a0c..00000000000
--- a/chromium/components/page_load_metrics/common/page_load_metrics_messages.h
+++ /dev/null
@@ -1,41 +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.
-
-// IPC messages for page load metrics.
-// Multiply-included message file, hence no include guard.
-
-#include "base/time/time.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "ipc/ipc_message_macros.h"
-
-#define IPC_MESSAGE_START PageLoadMetricsMsgStart
-
-// See comments in page_load_timing.h for details on each field.
-IPC_STRUCT_TRAITS_BEGIN(page_load_metrics::PageLoadTiming)
- IPC_STRUCT_TRAITS_MEMBER(navigation_start)
- IPC_STRUCT_TRAITS_MEMBER(response_start)
- IPC_STRUCT_TRAITS_MEMBER(dom_loading)
- IPC_STRUCT_TRAITS_MEMBER(dom_content_loaded_event_start)
- IPC_STRUCT_TRAITS_MEMBER(load_event_start)
- IPC_STRUCT_TRAITS_MEMBER(first_layout)
- IPC_STRUCT_TRAITS_MEMBER(first_paint)
- IPC_STRUCT_TRAITS_MEMBER(first_text_paint)
- IPC_STRUCT_TRAITS_MEMBER(first_image_paint)
- IPC_STRUCT_TRAITS_MEMBER(first_contentful_paint)
- IPC_STRUCT_TRAITS_MEMBER(parse_start)
- IPC_STRUCT_TRAITS_MEMBER(parse_stop)
- IPC_STRUCT_TRAITS_MEMBER(parse_blocked_on_script_load_duration)
- IPC_STRUCT_TRAITS_MEMBER(
- parse_blocked_on_script_load_from_document_write_duration)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(page_load_metrics::PageLoadMetadata)
- IPC_STRUCT_TRAITS_MEMBER(behavior_flags)
-IPC_STRUCT_TRAITS_END()
-
-// Sent from renderer to browser process when the PageLoadTiming for the
-// associated frame changed.
-IPC_MESSAGE_ROUTED2(PageLoadMetricsMsg_TimingUpdated,
- page_load_metrics::PageLoadTiming,
- page_load_metrics::PageLoadMetadata)
diff --git a/chromium/components/page_load_metrics/common/page_load_timing.cc b/chromium/components/page_load_metrics/common/page_load_timing.cc
deleted file mode 100644
index b46632d1f7d..00000000000
--- a/chromium/components/page_load_metrics/common/page_load_timing.cc
+++ /dev/null
@@ -1,51 +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 "components/page_load_metrics/common/page_load_timing.h"
-
-namespace page_load_metrics {
-
-PageLoadTiming::PageLoadTiming() {}
-
-PageLoadTiming::PageLoadTiming(const PageLoadTiming& other) = default;
-
-PageLoadTiming::~PageLoadTiming() {}
-
-bool PageLoadTiming::operator==(const PageLoadTiming& other) const {
- return navigation_start == other.navigation_start &&
- response_start == other.response_start &&
- dom_loading == other.dom_loading &&
- dom_content_loaded_event_start ==
- other.dom_content_loaded_event_start &&
- load_event_start == other.load_event_start &&
- first_layout == other.first_layout &&
- first_paint == other.first_paint &&
- first_text_paint == other.first_text_paint &&
- first_image_paint == other.first_image_paint &&
- first_contentful_paint == other.first_contentful_paint &&
- parse_start == other.parse_start && parse_stop == other.parse_stop &&
- parse_blocked_on_script_load_duration ==
- other.parse_blocked_on_script_load_duration &&
- parse_blocked_on_script_load_from_document_write_duration ==
- other.parse_blocked_on_script_load_from_document_write_duration;
-}
-
-bool PageLoadTiming::IsEmpty() const {
- return navigation_start.is_null() && response_start.is_zero() &&
- dom_loading.is_zero() && dom_content_loaded_event_start.is_zero() &&
- load_event_start.is_zero() && first_layout.is_zero() &&
- first_paint.is_zero() && first_text_paint.is_zero() &&
- first_image_paint.is_zero() && first_contentful_paint.is_zero() &&
- parse_start.is_zero() && parse_stop.is_zero() &&
- parse_blocked_on_script_load_duration.is_zero() &&
- parse_blocked_on_script_load_from_document_write_duration.is_zero();
-}
-
-PageLoadMetadata::PageLoadMetadata() {}
-
-bool PageLoadMetadata::operator==(const PageLoadMetadata& other) const {
- return behavior_flags == other.behavior_flags;
-}
-
-} // namespace page_load_metrics
diff --git a/chromium/components/page_load_metrics/common/page_load_timing.h b/chromium/components/page_load_metrics/common/page_load_timing.h
deleted file mode 100644
index a61551d4a40..00000000000
--- a/chromium/components/page_load_metrics/common/page_load_timing.h
+++ /dev/null
@@ -1,92 +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 COMPONENTS_PAGE_LOAD_METRICS_COMMON_PAGE_LOAD_TIMING_H_
-#define COMPONENTS_PAGE_LOAD_METRICS_COMMON_PAGE_LOAD_TIMING_H_
-
-#include "base/time/time.h"
-#include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h"
-
-namespace page_load_metrics {
-
-// PageLoadTiming contains timing metrics associated with a page load. Many of
-// the metrics here are based on the Navigation Timing spec:
-// http://www.w3.org/TR/navigation-timing/.
-struct PageLoadTiming {
- public:
- PageLoadTiming();
- PageLoadTiming(const PageLoadTiming& other);
- ~PageLoadTiming();
-
- bool operator==(const PageLoadTiming& other) const;
-
- bool IsEmpty() const;
-
- // Time that the navigation for the associated page was initiated.
- base::Time navigation_start;
-
- // All TimeDeltas are relative to navigation_start
-
- // TODO(shivanisha): Issue 596367 shows that it is possible for a valid
- // TimeDelta value to be 0 (2 TimeTicks can have the same value even if they
- // were assigned in separate instructions if the clock speed is less
- // granular). The solution there was to use base::Optional for those values.
- // Consider changing the below values to Optional as well.
-
- // Time that the first byte of the response is received.
- base::TimeDelta response_start;
-
- // Time that the document transitions to the 'loading' state. This is roughly
- // the time that the HTML parser begins parsing the main HTML resource.
- base::TimeDelta dom_loading;
-
- // Time immediately before the DOMContentLoaded event is fired.
- base::TimeDelta dom_content_loaded_event_start;
-
- // Time immediately before the load event is fired.
- base::TimeDelta load_event_start;
-
- // Time when the first layout is completed.
- base::TimeDelta first_layout;
-
- // Time when the first paint is performed.
- base::TimeDelta first_paint;
- // Time when the first non-blank text is painted.
- base::TimeDelta first_text_paint;
- // Time when the first image is painted.
- base::TimeDelta first_image_paint;
- // Time when the first contentful thing (image, text, etc.) is painted.
- base::TimeDelta first_contentful_paint;
-
- // Time that the document's parser started and stopped parsing main resource
- // content.
- base::TimeDelta parse_start;
- base::TimeDelta parse_stop;
-
- // Sum of times when the parser is blocked waiting on the load of a script.
- // This duration takes place between parser_start and parser_stop, and thus
- // must be less than or equal to parser_stop - parser_start.
- base::TimeDelta parse_blocked_on_script_load_duration;
-
- // Sum of times when the parser is blocked waiting on the load of a script
- // that was inserted from document.write. This duration must be less than or
- // equal to parse_blocked_on_script_load_duration. Note that some uncommon
- // cases where scripts are loaded via document.write are not currently covered
- // by this field. See crbug/600711 for details.
- base::TimeDelta parse_blocked_on_script_load_from_document_write_duration;
-
- // If you add additional members, also be sure to update operator==,
- // page_load_metrics_messages.h, and IsEmpty().
-};
-
-struct PageLoadMetadata {
- PageLoadMetadata();
- bool operator==(const PageLoadMetadata& other) const;
- // These are packed blink::WebLoadingBehaviorFlag enums.
- int behavior_flags = blink::WebLoadingBehaviorNone;
-};
-
-} // namespace page_load_metrics
-
-#endif // COMPONENTS_PAGE_LOAD_METRICS_COMMON_PAGE_LOAD_TIMING_H_
diff --git a/chromium/components/page_load_metrics/renderer/BUILD.gn b/chromium/components/page_load_metrics/renderer/BUILD.gn
deleted file mode 100644
index 0ebfda1fa9a..00000000000
--- a/chromium/components/page_load_metrics/renderer/BUILD.gn
+++ /dev/null
@@ -1,41 +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.
-
-# GYP version: components/page_load_metrics.gypi:page_load_metrics_renderer
-static_library("renderer") {
- sources = [
- "metrics_render_frame_observer.cc",
- "metrics_render_frame_observer.h",
- "page_timing_metrics_sender.cc",
- "page_timing_metrics_sender.h",
- ]
- public_deps = [
- "//content/public/renderer",
- ]
- deps = [
- "//base",
- "//components/page_load_metrics/common",
- "//ipc",
- "//third_party/WebKit/public:blink",
- "//url",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "fake_page_timing_metrics_ipc_sender.cc",
- "fake_page_timing_metrics_ipc_sender.h",
- "metrics_render_frame_observer_unittest.cc",
- "page_timing_metrics_sender_unittest.cc",
- ]
- deps = [
- ":renderer",
- "//base",
- "//components/page_load_metrics/common",
- "//ipc",
- "//testing/gmock",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/page_load_metrics/renderer/DEPS b/chromium/components/page_load_metrics/renderer/DEPS
deleted file mode 100644
index 1be396119fe..00000000000
--- a/chromium/components/page_load_metrics/renderer/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
- "+content/public/renderer",
- "+components/page_load_metrics/renderer",
- "+third_party/WebKit/public",
-]
diff --git a/chromium/components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.cc b/chromium/components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.cc
deleted file mode 100644
index e1e8e54ecdb..00000000000
--- a/chromium/components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.cc
+++ /dev/null
@@ -1,54 +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 "components/page_load_metrics/common/page_load_metrics_messages.h"
-#include "components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.h"
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_message_macros.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace page_load_metrics {
-
-FakePageTimingMetricsIPCSender::FakePageTimingMetricsIPCSender() {}
-
-FakePageTimingMetricsIPCSender::~FakePageTimingMetricsIPCSender() {
- VerifyExpectedTimings();
-}
-
-void FakePageTimingMetricsIPCSender::ExpectPageLoadTiming(
- const PageLoadTiming& timing) {
- VerifyExpectedTimings();
- expected_timings_.push_back(timing);
-}
-
-void FakePageTimingMetricsIPCSender::VerifyExpectedTimings() const {
- // Ideally we'd just call ASSERT_EQ(actual_timings_, expected_timings_) here,
- // but this causes the generated gtest code to fail to build on Windows. See
- // the comments in the header file for additional details.
- ASSERT_EQ(actual_timings_.size(), expected_timings_.size());
- for (size_t i = 0; i < actual_timings_.size(); ++i) {
- if (actual_timings_.at(i) == expected_timings_.at(i))
- continue;
- ADD_FAILURE() << "Actual timing != expected timing at index " << i;
- }
-}
-
-bool FakePageTimingMetricsIPCSender::Send(IPC::Message* message) {
- IPC_BEGIN_MESSAGE_MAP(FakePageTimingMetricsIPCSender, *message)
- IPC_MESSAGE_HANDLER(PageLoadMetricsMsg_TimingUpdated, OnTimingUpdated)
- IPC_MESSAGE_UNHANDLED(ADD_FAILURE())
- IPC_END_MESSAGE_MAP()
-
- delete message;
- return true;
-}
-
-void FakePageTimingMetricsIPCSender::OnTimingUpdated(
- const PageLoadTiming& timing,
- PageLoadMetadata metadata) {
- actual_timings_.push_back(timing);
- VerifyExpectedTimings();
-}
-
-} // namespace page_load_metrics
diff --git a/chromium/components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.h b/chromium/components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.h
deleted file mode 100644
index 44e1e672a7c..00000000000
--- a/chromium/components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.h
+++ /dev/null
@@ -1,72 +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.
-
-#ifndef COMPONENTS_PAGE_LOAD_METRICS_RENDERER_FAKE_PAGE_TIMING_METRICS_IPC_SENDER_H_
-#define COMPONENTS_PAGE_LOAD_METRICS_RENDERER_FAKE_PAGE_TIMING_METRICS_IPC_SENDER_H_
-
-#include <vector>
-
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "ipc/ipc_sender.h"
-
-namespace IPC {
-class Message;
-}
-
-namespace page_load_metrics {
-
-// IPC::Sender implementation for use in tests. Allows for setting and verifying
-// basic expectations when sending PageLoadTiming IPCs. By default,
-// FakePageTimingMetricsIPCSender will verify that expected and actual
-// PageLoadTimings match on each invocation to ExpectPageLoadTiming() and
-// Send(), as well as in the destructor. Tests can force additional validations
-// by calling VerifyExpectedTimings.
-//
-// Expected PageLoadTimings are specified via ExpectPageLoadTiming, and actual
-// PageLoadTimings are dispatched through Send(). When Send() is called, we
-// verify that the actual PageLoadTimings dipatched through Send() match the
-// expected PageLoadTimings provided via ExpectPageLoadTiming.
-//
-// Normally, gmock would be used in place of this class, but gmock is not
-// compatible with structures that use aligned memory, and PageLoadTiming will
-// soon use base::Optional which uses aligned memory, so we're forced to roll
-// our own implementation here. See
-// https://groups.google.com/forum/#!topic/googletestframework/W-Hud3j_c6I for
-// more details.
-class FakePageTimingMetricsIPCSender : public IPC::Sender {
- public:
- FakePageTimingMetricsIPCSender();
- ~FakePageTimingMetricsIPCSender() override;
-
- // Implementation of IPC::Sender. PageLoadMetricsMsg_TimingUpdated IPCs that
- // send updated PageLoadTimings should be dispatched through this method. This
- // method will verify that all PageLoadTiming update IPCs dispatched so far
- // match with the expected PageLoadTimings passed to ExpectPageLoadTiming.
- bool Send(IPC::Message* message) override;
-
- // PageLoadTimings that are expected to be sent through Send() should be
- // passed to ExpectPageLoadTiming.
- void ExpectPageLoadTiming(const PageLoadTiming& timing);
-
- // Forces verification that actual timings sent through Send match
- // expected timings provided via ExpectPageLoadTiming.
- void VerifyExpectedTimings() const;
-
- const std::vector<PageLoadTiming>& expected_timings() const {
- return expected_timings_;
- }
- const std::vector<PageLoadTiming>& actual_timings() const {
- return actual_timings_;
- }
-
- private:
- void OnTimingUpdated(const PageLoadTiming& timing, PageLoadMetadata metadata);
-
- std::vector<PageLoadTiming> expected_timings_;
- std::vector<PageLoadTiming> actual_timings_;
-};
-
-} // namespace page_load_metrics
-
-#endif // COMPONENTS_PAGE_LOAD_METRICS_RENDERER_FAKE_PAGE_TIMING_METRICS_IPC_SENDER_H_
diff --git a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
deleted file mode 100644
index 0be2caded59..00000000000
--- a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
+++ /dev/null
@@ -1,156 +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 "components/page_load_metrics/renderer/metrics_render_frame_observer.h"
-
-#include <string>
-
-#include "base/memory/ptr_util.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "components/page_load_metrics/renderer/page_timing_metrics_sender.h"
-#include "content/public/renderer/render_frame.h"
-#include "third_party/WebKit/public/platform/WebURLResponse.h"
-#include "third_party/WebKit/public/web/WebDataSource.h"
-#include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebLocalFrame.h"
-#include "third_party/WebKit/public/web/WebPerformance.h"
-#include "url/gurl.h"
-
-namespace page_load_metrics {
-
-namespace {
-
-base::TimeDelta ClampDelta(double event, double start) {
- if (event - start < 0)
- event = start;
- return base::Time::FromDoubleT(event) - base::Time::FromDoubleT(start);
-}
-
-} // namespace
-
-MetricsRenderFrameObserver::MetricsRenderFrameObserver(
- content::RenderFrame* render_frame)
- : content::RenderFrameObserver(render_frame) {}
-
-MetricsRenderFrameObserver::~MetricsRenderFrameObserver() {}
-
-void MetricsRenderFrameObserver::DidChangePerformanceTiming() {
- SendMetrics();
-}
-
-void MetricsRenderFrameObserver::DidObserveLoadingBehavior(
- blink::WebLoadingBehaviorFlag behavior) {
- if (page_timing_metrics_sender_)
- page_timing_metrics_sender_->DidObserveLoadingBehavior(behavior);
-}
-
-void MetricsRenderFrameObserver::DidCommitProvisionalLoad(
- bool is_new_navigation,
- bool is_same_page_navigation) {
- // Same-page navigations (e.g. an in-document navigation from a fragment
- // link) aren't full page loads, since they don't go to network to load the
- // main HTML resource. DidStartProvisionalLoad doesn't get invoked for same
- // page navigations, so we may still have an active
- // page_timing_metrics_sender_ at this point.
- if (is_same_page_navigation)
- return;
-
- // Make sure to release the sender for a previous navigation, if we have one.
- page_timing_metrics_sender_.reset();
-
- // We only create a PageTimingMetricsSender if the page meets the criteria for
- // sending and recording metrics. Once page_timing_metrics_sender_ is
- // non-null, we will send metrics for the current page at some later time, as
- // those metrics become available.
- if (ShouldSendMetrics()) {
- PageLoadTiming timing(GetTiming());
- DCHECK(!timing.navigation_start.is_null());
- page_timing_metrics_sender_.reset(
- new PageTimingMetricsSender(this, routing_id(), CreateTimer(), timing));
- }
-}
-
-void MetricsRenderFrameObserver::SendMetrics() {
- if (!page_timing_metrics_sender_)
- return;
- if (HasNoRenderFrame())
- return;
- PageLoadTiming timing(GetTiming());
- page_timing_metrics_sender_->Send(timing);
-}
-
-bool MetricsRenderFrameObserver::ShouldSendMetrics() const {
- if (HasNoRenderFrame())
- return false;
- const blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
- // We only generate historgrams for main frames.
- if (frame->parent())
- return false;
-
- const blink::WebDocument& document = frame->document();
- // Ignore non-HTTP schemes (e.g. chrome://).
- const GURL& url = document.url();
- if (!url.SchemeIsHTTPOrHTTPS())
- return false;
-
- const blink::WebURLResponse& url_response = frame->dataSource()->response();
-
- // Ignore non-HTML documents (e.g. SVG). Note that images are treated by
- // Blink as HTML documents, so to exclude images, we must perform
- // additional mime type checking below.
- if (!document.isHTMLDocument() && !document.isXHTMLDocument())
- return false;
-
- // Ignore non-HTML mime types (e.g. images).
- std::string mime_type = url_response.mimeType().utf8();
- if (mime_type != "text/html" && mime_type != "application/xhtml+xml")
- return false;
-
- return true;
-}
-
-PageLoadTiming MetricsRenderFrameObserver::GetTiming() const {
- const blink::WebPerformance& perf =
- render_frame()->GetWebFrame()->performance();
-
- PageLoadTiming timing;
- double start = perf.navigationStart();
- timing.navigation_start = base::Time::FromDoubleT(start);
- timing.response_start = ClampDelta(perf.responseStart(), start);
- timing.dom_loading = ClampDelta(perf.domLoading(), start);
- timing.dom_content_loaded_event_start =
- ClampDelta(perf.domContentLoadedEventStart(), start);
- timing.load_event_start = ClampDelta(perf.loadEventStart(), start);
- timing.first_layout = ClampDelta(perf.firstLayout(), start);
- timing.first_paint = ClampDelta(perf.firstPaint(), start);
- timing.first_text_paint = ClampDelta(perf.firstTextPaint(), start);
- timing.first_image_paint = ClampDelta(perf.firstImagePaint(), start);
- timing.first_contentful_paint =
- ClampDelta(perf.firstContentfulPaint(), start);
- timing.parse_start = ClampDelta(perf.parseStart(), start);
- timing.parse_stop = ClampDelta(perf.parseStop(), start);
- timing.parse_blocked_on_script_load_duration =
- base::TimeDelta::FromSecondsD(perf.parseBlockedOnScriptLoadDuration());
- timing.parse_blocked_on_script_load_from_document_write_duration =
- base::TimeDelta::FromSecondsD(
- perf.parseBlockedOnScriptLoadFromDocumentWriteDuration());
- return timing;
-}
-
-std::unique_ptr<base::Timer> MetricsRenderFrameObserver::CreateTimer() const {
- return base::WrapUnique(new base::OneShotTimer);
-}
-
-bool MetricsRenderFrameObserver::HasNoRenderFrame() const {
- bool no_frame = !render_frame() || !render_frame()->GetWebFrame();
- DCHECK(!no_frame);
- return no_frame;
-}
-
-void MetricsRenderFrameObserver::OnDestruct() {
- delete this;
-}
-
-} // namespace page_load_metrics
diff --git a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h
deleted file mode 100644
index 3648c805c8f..00000000000
--- a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h
+++ /dev/null
@@ -1,53 +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 COMPONENTS_PAGE_LOAD_METRICS_RENDERER_PAGE_LOAD_METRICS_RENDER_FRAME_OBSERVER_H_
-#define COMPONENTS_PAGE_LOAD_METRICS_RENDERER_PAGE_LOAD_METRICS_RENDER_FRAME_OBSERVER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h"
-
-namespace base {
-class Timer;
-} // namespace base
-
-namespace page_load_metrics {
-
-class PageTimingMetricsSender;
-
-// MetricsRenderFrameObserver observes RenderFrame notifications, and
-// sends page load timing information to the browser process over IPC.
-class MetricsRenderFrameObserver : public content::RenderFrameObserver {
- public:
- explicit MetricsRenderFrameObserver(content::RenderFrame* render_frame);
- ~MetricsRenderFrameObserver() override;
-
- // RenderFrameObserver implementation
- void DidChangePerformanceTiming() override;
- void DidObserveLoadingBehavior(
- blink::WebLoadingBehaviorFlag behavior) override;
- void DidCommitProvisionalLoad(bool is_new_navigation,
- bool is_same_page_navigation) override;
- void OnDestruct() override;
-
- private:
- // Will be null when we're not actively sending metrics.
- std::unique_ptr<PageTimingMetricsSender> page_timing_metrics_sender_;
-
- void SendMetrics();
- virtual bool ShouldSendMetrics() const;
- virtual PageLoadTiming GetTiming() const;
- virtual std::unique_ptr<base::Timer> CreateTimer() const;
- virtual bool HasNoRenderFrame() const;
-
- DISALLOW_COPY_AND_ASSIGN(MetricsRenderFrameObserver);
-};
-
-} // namespace page_load_metrics
-
-#endif // COMPONENTS_PAGE_LOAD_METRICS_RENDERER_PAGE_LOAD_METRICS_RENDER_FRAME_OBSERVER_H_
diff --git a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc
deleted file mode 100644
index 7ef1d392236..00000000000
--- a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc
+++ /dev/null
@@ -1,195 +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 "components/page_load_metrics/renderer/metrics_render_frame_observer.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "base/time/time.h"
-#include "base/timer/mock_timer.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace page_load_metrics {
-
-// Implementation of the MetricsRenderFrameObserver class we're testing,
-// with the GetTiming() and ShouldSendMetrics() methods stubbed out to make
-// the rest of the class more testable.
-class TestMetricsRenderFrameObserver : public MetricsRenderFrameObserver {
- public:
- TestMetricsRenderFrameObserver() : MetricsRenderFrameObserver(nullptr) {}
-
- std::unique_ptr<base::Timer> CreateTimer() const override {
- if (!mock_timer_)
- ADD_FAILURE() << "CreateTimer() called, but no MockTimer available.";
- return std::move(mock_timer_);
- }
-
- // We intercept sent messages and dispatch them to our
- // FakePageTimingMetricsIPCSender, which we use to verify that the expected
- // IPC messages get sent.
- bool Send(IPC::Message* message) override {
- return fake_timing_ipc_sender_.Send(message);
- }
-
- void set_mock_timer(std::unique_ptr<base::Timer> timer) {
- ASSERT_EQ(nullptr, mock_timer_);
- mock_timer_ = std::move(timer);
- }
-
- void ExpectPageLoadTiming(const PageLoadTiming& timing) {
- fake_timing_ipc_sender_.ExpectPageLoadTiming(timing);
- }
-
- PageLoadTiming GetTiming() const override {
- return fake_timing_ipc_sender_.expected_timings().empty()
- ? PageLoadTiming()
- : fake_timing_ipc_sender_.expected_timings().back();
- }
-
- void VerifyExpectedTimings() const {
- fake_timing_ipc_sender_.VerifyExpectedTimings();
- }
-
- bool ShouldSendMetrics() const override { return true; }
- bool HasNoRenderFrame() const override { return false; }
-
- private:
- FakePageTimingMetricsIPCSender fake_timing_ipc_sender_;
- mutable std::unique_ptr<base::Timer> mock_timer_;
-};
-
-typedef testing::Test MetricsRenderFrameObserverTest;
-
-TEST_F(MetricsRenderFrameObserverTest, NoMetrics) {
- TestMetricsRenderFrameObserver observer;
- base::MockTimer* mock_timer = new base::MockTimer(false, false);
- observer.set_mock_timer(base::WrapUnique(mock_timer));
-
- observer.DidChangePerformanceTiming();
- ASSERT_FALSE(mock_timer->IsRunning());
-}
-
-TEST_F(MetricsRenderFrameObserverTest, SingleMetric) {
- base::Time nav_start = base::Time::FromDoubleT(10);
- base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(10);
-
- TestMetricsRenderFrameObserver observer;
- base::MockTimer* mock_timer = new base::MockTimer(false, false);
- observer.set_mock_timer(base::WrapUnique(mock_timer));
-
- PageLoadTiming timing;
- timing.navigation_start = nav_start;
- observer.ExpectPageLoadTiming(timing);
- observer.DidCommitProvisionalLoad(true, false);
- mock_timer->Fire();
-
- timing.first_layout = first_layout;
- observer.ExpectPageLoadTiming(timing);
-
- observer.DidChangePerformanceTiming();
- mock_timer->Fire();
-}
-
-TEST_F(MetricsRenderFrameObserverTest, MultipleMetrics) {
- base::Time nav_start = base::Time::FromDoubleT(10);
- base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(2);
- base::TimeDelta dom_event = base::TimeDelta::FromMillisecondsD(2);
- base::TimeDelta load_event = base::TimeDelta::FromMillisecondsD(2);
-
- TestMetricsRenderFrameObserver observer;
- base::MockTimer* mock_timer = new base::MockTimer(false, false);
- observer.set_mock_timer(base::WrapUnique(mock_timer));
-
- PageLoadTiming timing;
- timing.navigation_start = nav_start;
- observer.ExpectPageLoadTiming(timing);
- observer.DidCommitProvisionalLoad(true, false);
- mock_timer->Fire();
-
- timing.first_layout = first_layout;
- timing.dom_content_loaded_event_start = dom_event;
- observer.ExpectPageLoadTiming(timing);
-
- observer.DidChangePerformanceTiming();
- mock_timer->Fire();
-
- // At this point, we should have triggered the generation of two metrics.
- // Verify and reset the observer's expectations before moving on to the next
- // part of the test.
- observer.VerifyExpectedTimings();
-
- timing.load_event_start = load_event;
- observer.ExpectPageLoadTiming(timing);
-
- observer.DidChangePerformanceTiming();
- mock_timer->Fire();
-
- // Verify and reset the observer's expectations before moving on to the next
- // part of the test.
- observer.VerifyExpectedTimings();
-
- // The PageLoadTiming above includes timing information for the first layout,
- // dom content, and load metrics. However, since we've already generated
- // timing information for all of these metrics previously, we do not expect
- // this invocation to generate any additional metrics.
- observer.DidChangePerformanceTiming();
- ASSERT_FALSE(mock_timer->IsRunning());
-}
-
-TEST_F(MetricsRenderFrameObserverTest, MultipleNavigations) {
- base::Time nav_start = base::Time::FromDoubleT(10);
- base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(2);
- base::TimeDelta dom_event = base::TimeDelta::FromMillisecondsD(2);
- base::TimeDelta load_event = base::TimeDelta::FromMillisecondsD(2);
-
- TestMetricsRenderFrameObserver observer;
- base::MockTimer* mock_timer = new base::MockTimer(false, false);
- observer.set_mock_timer(base::WrapUnique(mock_timer));
-
- PageLoadTiming timing;
- timing.navigation_start = nav_start;
- observer.ExpectPageLoadTiming(timing);
- observer.DidCommitProvisionalLoad(true, false);
- mock_timer->Fire();
-
- timing.first_layout = first_layout;
- timing.dom_content_loaded_event_start = dom_event;
- timing.load_event_start = load_event;
- observer.ExpectPageLoadTiming(timing);
- observer.DidChangePerformanceTiming();
- mock_timer->Fire();
-
- // At this point, we should have triggered the generation of two metrics.
- // Verify and reset the observer's expectations before moving on to the next
- // part of the test.
- observer.VerifyExpectedTimings();
-
- base::Time nav_start_2 = base::Time::FromDoubleT(100);
- base::TimeDelta first_layout_2 = base::TimeDelta::FromMillisecondsD(20);
- base::TimeDelta dom_event_2 = base::TimeDelta::FromMillisecondsD(20);
- base::TimeDelta load_event_2 = base::TimeDelta::FromMillisecondsD(20);
- PageLoadTiming timing_2;
- timing_2.navigation_start = nav_start_2;
-
- base::MockTimer* mock_timer2 = new base::MockTimer(false, false);
- observer.set_mock_timer(base::WrapUnique(mock_timer2));
-
- observer.ExpectPageLoadTiming(timing_2);
- observer.DidCommitProvisionalLoad(true, false);
- mock_timer2->Fire();
-
- timing_2.first_layout = first_layout_2;
- timing_2.dom_content_loaded_event_start = dom_event_2;
- timing_2.load_event_start = load_event_2;
- observer.ExpectPageLoadTiming(timing_2);
-
- observer.DidChangePerformanceTiming();
- mock_timer2->Fire();
-}
-
-} // namespace page_load_metrics
diff --git a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
deleted file mode 100644
index 5572461683b..00000000000
--- a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
+++ /dev/null
@@ -1,81 +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 "components/page_load_metrics/renderer/page_timing_metrics_sender.h"
-
-#include <utility>
-
-#include "base/callback.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-#include "ipc/ipc_sender.h"
-
-namespace page_load_metrics {
-
-namespace {
-const int kInitialTimerDelayMillis = 50;
-const int kTimerDelayMillis = 1000;
-} // namespace
-
-PageTimingMetricsSender::PageTimingMetricsSender(
- IPC::Sender* ipc_sender,
- int routing_id,
- std::unique_ptr<base::Timer> timer,
- const PageLoadTiming& initial_timing)
- : ipc_sender_(ipc_sender),
- routing_id_(routing_id),
- timer_(std::move(timer)),
- last_timing_(initial_timing),
- metadata_(PageLoadMetadata()) {
- // Send an initial IPC relatively early to help track aborts.
- EnsureSendTimer(kInitialTimerDelayMillis);
-}
-
-// On destruction, we want to send any data we have if we have a timer
-// currently running (and thus are talking to a browser process)
-PageTimingMetricsSender::~PageTimingMetricsSender() {
- if (timer_->IsRunning()) {
- timer_->Stop();
- SendNow();
- }
-}
-
-void PageTimingMetricsSender::DidObserveLoadingBehavior(
- blink::WebLoadingBehaviorFlag behavior) {
- if (behavior & metadata_.behavior_flags)
- return;
- metadata_.behavior_flags |= behavior;
- EnsureSendTimer(kTimerDelayMillis);
-}
-
-void PageTimingMetricsSender::Send(const PageLoadTiming& timing) {
- if (timing == last_timing_)
- return;
-
- // We want to make sure that each PageTimingMetricsSender is associated
- // with a distinct page navigation. Because we reset the object on commit,
- // we can trash last_timing_ on a provisional load before SendNow() fires.
- if (!last_timing_.navigation_start.is_null() &&
- last_timing_.navigation_start != timing.navigation_start) {
- return;
- }
-
- last_timing_ = timing;
- EnsureSendTimer(kTimerDelayMillis);
-}
-
-void PageTimingMetricsSender::EnsureSendTimer(int delay) {
- if (!timer_->IsRunning())
- timer_->Start(
- FROM_HERE, base::TimeDelta::FromMilliseconds(delay),
- base::Bind(&PageTimingMetricsSender::SendNow, base::Unretained(this)));
-}
-
-void PageTimingMetricsSender::SendNow() {
- ipc_sender_->Send(new PageLoadMetricsMsg_TimingUpdated(
- routing_id_, last_timing_, metadata_));
-}
-
-} // namespace page_load_metrics
diff --git a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h
deleted file mode 100644
index 1cdfb735be0..00000000000
--- a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h
+++ /dev/null
@@ -1,59 +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 COMPONENTS_PAGE_LOAD_METRICS_RENDERER_PAGE_TIMING_METRICS_SENDER_H_
-#define COMPONENTS_PAGE_LOAD_METRICS_RENDERER_PAGE_TIMING_METRICS_SENDER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h"
-
-namespace base {
-class Timer;
-} // namespace base
-
-namespace IPC {
-class Sender;
-} // namespace IPC
-
-namespace page_load_metrics {
-
-// PageTimingMetricsSender is responsible for sending page load timing metrics
-// over IPC. PageTimingMetricsSender may coalesce sent IPCs in order to
-// minimize IPC contention.
-class PageTimingMetricsSender {
- public:
- PageTimingMetricsSender(IPC::Sender* ipc_sender,
- int routing_id,
- std::unique_ptr<base::Timer> timer,
- const PageLoadTiming& initial_timing);
- ~PageTimingMetricsSender();
-
- void DidObserveLoadingBehavior(blink::WebLoadingBehaviorFlag behavior);
- void Send(const PageLoadTiming& timing);
-
- protected:
- base::Timer* timer() const { return timer_.get(); }
-
- private:
- void EnsureSendTimer(int delay);
- void SendNow();
-
- IPC::Sender* const ipc_sender_;
- const int routing_id_;
- std::unique_ptr<base::Timer> timer_;
- PageLoadTiming last_timing_;
-
- // The the sender keep track of metadata as it comes in, because the sender is
- // scoped to a single committed load.
- PageLoadMetadata metadata_;
-
- DISALLOW_COPY_AND_ASSIGN(PageTimingMetricsSender);
-};
-
-} // namespace page_load_metrics
-
-#endif // COMPONENTS_PAGE_LOAD_METRICS_RENDERER_PAGE_TIMING_METRICS_SENDER_H_
diff --git a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
deleted file mode 100644
index 2aca12557a8..00000000000
--- a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
+++ /dev/null
@@ -1,135 +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 "components/page_load_metrics/renderer/page_timing_metrics_sender.h"
-
-#include "base/time/time.h"
-#include "base/timer/mock_timer.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "components/page_load_metrics/renderer/fake_page_timing_metrics_ipc_sender.h"
-#include "ipc/ipc_message.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace page_load_metrics {
-
-// Thin wrapper around PageTimingMetricsSender that provides access to the
-// MockTimer instance.
-class TestPageTimingMetricsSender : public PageTimingMetricsSender {
- public:
- explicit TestPageTimingMetricsSender(IPC::Sender* ipc_sender,
- const PageLoadTiming& initial_timing)
- : PageTimingMetricsSender(
- ipc_sender,
- MSG_ROUTING_NONE,
- std::unique_ptr<base::Timer>(new base::MockTimer(false, false)),
- initial_timing) {}
-
- base::MockTimer* mock_timer() const {
- return reinterpret_cast<base::MockTimer*>(timer());
- }
-};
-
-class PageTimingMetricsSenderTest : public testing::Test {
- public:
- PageTimingMetricsSenderTest()
- : metrics_sender_(new TestPageTimingMetricsSender(&fake_ipc_sender_,
- PageLoadTiming())) {}
-
- protected:
- FakePageTimingMetricsIPCSender fake_ipc_sender_;
- std::unique_ptr<TestPageTimingMetricsSender> metrics_sender_;
-};
-
-TEST_F(PageTimingMetricsSenderTest, Basic) {
- base::Time nav_start = base::Time::FromDoubleT(10);
- base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(2);
-
- PageLoadTiming timing;
- timing.navigation_start = nav_start;
- timing.first_layout = first_layout;
-
- metrics_sender_->Send(timing);
-
- // Firing the timer should trigger sending of an OnTimingUpdated IPC.
- fake_ipc_sender_.ExpectPageLoadTiming(timing);
- ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
- metrics_sender_->mock_timer()->Fire();
- EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
-
- // At this point, we should have triggered the send of the PageLoadTiming IPC.
- fake_ipc_sender_.VerifyExpectedTimings();
-
- // Attempt to send the same timing instance again. The send should be
- // suppressed, since the timing instance hasn't changed since the last send.
- metrics_sender_->Send(timing);
- EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
-}
-
-TEST_F(PageTimingMetricsSenderTest, CoalesceMultipleIPCs) {
- base::Time nav_start = base::Time::FromDoubleT(10);
- base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(2);
- base::TimeDelta load_event = base::TimeDelta::FromMillisecondsD(4);
-
- PageLoadTiming timing;
- timing.navigation_start = nav_start;
- timing.first_layout = first_layout;
-
- metrics_sender_->Send(timing);
- ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
-
- // Send an updated PageLoadTiming before the timer has fired. When the timer
- // fires, the updated PageLoadTiming should be sent.
- timing.load_event_start = load_event;
- metrics_sender_->Send(timing);
-
- // Firing the timer should trigger sending of the OnTimingUpdated IPC with
- // the most recently provided PageLoadTiming instance.
- fake_ipc_sender_.ExpectPageLoadTiming(timing);
- metrics_sender_->mock_timer()->Fire();
- EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
-}
-
-TEST_F(PageTimingMetricsSenderTest, MultipleIPCs) {
- base::Time nav_start = base::Time::FromDoubleT(10);
- base::TimeDelta first_layout = base::TimeDelta::FromMillisecondsD(2);
- base::TimeDelta load_event = base::TimeDelta::FromMillisecondsD(4);
-
- PageLoadTiming timing;
- timing.navigation_start = nav_start;
- timing.first_layout = first_layout;
-
- metrics_sender_->Send(timing);
- ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
- fake_ipc_sender_.ExpectPageLoadTiming(timing);
- metrics_sender_->mock_timer()->Fire();
- EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
- fake_ipc_sender_.VerifyExpectedTimings();
-
- // Send an updated PageLoadTiming after the timer for the first send request
- // has fired, and verify that a second IPC is sent.
- timing.load_event_start = load_event;
- metrics_sender_->Send(timing);
- ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
- fake_ipc_sender_.ExpectPageLoadTiming(timing);
- metrics_sender_->mock_timer()->Fire();
- EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
-}
-
-TEST_F(PageTimingMetricsSenderTest, SendIPCOnDestructor) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(10);
- timing.first_layout = base::TimeDelta::FromMilliseconds(10);
-
- // This test wants to verify behavior in the PageTimingMetricsSender
- // destructor. The EXPECT_CALL will be satisfied when the |metrics_sender_|
- // is destroyed below.
- metrics_sender_->Send(timing);
- fake_ipc_sender_.ExpectPageLoadTiming(timing);
- ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
-
- // Destroy |metrics_sender_|, in order to force its destructor to run.
- metrics_sender_.reset();
-}
-
-} // namespace page_load_metrics
diff --git a/chromium/components/pageinfo_strings.grdp b/chromium/components/pageinfo_strings.grdp
index 57d23a9da64..36e825733e1 100644
--- a/chromium/components/pageinfo_strings.grdp
+++ b/chromium/components/pageinfo_strings.grdp
@@ -27,9 +27,6 @@
<message name="IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS_AEAD" desc="This message gives details of the cryptographic primitives used to protect the HTTPS connection. It should be translated in a similar manner as IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS">
The connection is encrypted and authenticated using <ph name="CIPHER">$1<ex>AES_128_GCM</ex></ph> and uses <ph name="KX">$2<ex>RSA</ex></ph> as the key exchange mechanism.
</message>
- <message name="IDS_PAGE_INFO_SECURITY_TAB_FALLBACK_MESSAGE" desc="This message is displayed when the first secure connection to a site failed and Chrome retried with an older protocol.">
- The connection had to be retried using an older version of the TLS or SSL protocol. This typically means that the server is using very old software and may have other security issues.
- </message>
<message name="IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY" desc="The text of the identity section when the page is not secure.">
The identity of this website has not been verified.
</message>
diff --git a/chromium/components/pairing.gypi b/chromium/components/pairing.gypi
deleted file mode 100644
index 6fea47c4b19..00000000000
--- a/chromium/components/pairing.gypi
+++ /dev/null
@@ -1,54 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'pairing',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'pairing_api_proto',
- '../base/base.gyp:base',
- '../device/bluetooth/bluetooth.gyp:device_bluetooth',
- '../net/net.gyp:net',
- ],
- 'sources': [
- 'pairing/bluetooth_controller_pairing_controller.cc',
- 'pairing/bluetooth_controller_pairing_controller.h',
- 'pairing/bluetooth_host_pairing_controller.cc',
- 'pairing/bluetooth_host_pairing_controller.h',
- 'pairing/bluetooth_pairing_constants.cc',
- 'pairing/bluetooth_pairing_constants.h',
- 'pairing/controller_pairing_controller.cc',
- 'pairing/controller_pairing_controller.h',
- 'pairing/fake_controller_pairing_controller.cc',
- 'pairing/fake_controller_pairing_controller.h',
- 'pairing/fake_host_pairing_controller.cc',
- 'pairing/fake_host_pairing_controller.h',
- 'pairing/host_pairing_controller.cc',
- 'pairing/host_pairing_controller.h',
- 'pairing/message_buffer.cc',
- 'pairing/message_buffer.h',
- 'pairing/proto_decoder.cc',
- 'pairing/proto_decoder.h',
- 'pairing/shark_connection_listener.cc',
- 'pairing/shark_connection_listener.h',
- ],
- },
- {
- # Protobuf compiler / generator for the pairing api protocol buffer.
- 'target_name': 'pairing_api_proto',
- 'type': 'static_library',
- 'sources': [ 'pairing/pairing_api.proto' ],
- 'variables': {
- 'proto_in_dir': 'pairing',
- 'proto_out_dir': 'components/pairing',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
- ],
-}
diff --git a/chromium/components/pairing/OWNERS b/chromium/components/pairing/OWNERS
index 14942e3dc0c..022d75b5375 100644
--- a/chromium/components/pairing/OWNERS
+++ b/chromium/components/pairing/OWNERS
@@ -1,3 +1,2 @@
achuith@chromium.org
-dzhioev@chromium.org
zork@chromium.org
diff --git a/chromium/components/pairing/bluetooth_controller_pairing_controller.cc b/chromium/components/pairing/bluetooth_controller_pairing_controller.cc
index 8750de39aef..84efee00b9e 100644
--- a/chromium/components/pairing/bluetooth_controller_pairing_controller.cc
+++ b/chromium/components/pairing/bluetooth_controller_pairing_controller.cc
@@ -138,7 +138,7 @@ void BluetoothControllerPairingController::OnStartDiscoverySession(
discovery_session_ = std::move(discovery_session);
ChangeStage(STAGE_DEVICES_DISCOVERY);
- for (const auto& device : adapter_->GetDevices())
+ for (auto* device : adapter_->GetDevices())
DeviceFound(device);
}
diff --git a/chromium/components/password_manager.gypi b/chromium/components/password_manager.gypi
deleted file mode 100644
index 38d6a78bd99..00000000000
--- a/chromium/components/password_manager.gypi
+++ /dev/null
@@ -1,365 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/password_manager/core/browser
- 'target_name': 'password_manager_core_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../sql/sql.gyp:sql',
- '../sync/sync.gyp:sync',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- '../url/url.gyp:url_lib',
- 'autofill_core_common',
- 'components_strings.gyp:components_strings',
- 'keyed_service_core',
- 'os_crypt',
- '../third_party/re2/re2.gyp:re2',
- 'password_manager_core_common',
- 'password_manager_core_browser_proto',
- 'sync_driver',
- 'url_formatter/url_formatter.gyp:url_formatter',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'password_manager/core/browser/affiliated_match_helper.cc',
- 'password_manager/core/browser/affiliated_match_helper.h',
- 'password_manager/core/browser/affiliation_backend.cc',
- 'password_manager/core/browser/affiliation_backend.h',
- 'password_manager/core/browser/affiliation_database.cc',
- 'password_manager/core/browser/affiliation_database.h',
- 'password_manager/core/browser/affiliation_fetch_throttler.cc',
- 'password_manager/core/browser/affiliation_fetch_throttler.h',
- 'password_manager/core/browser/affiliation_fetch_throttler_delegate.h',
- 'password_manager/core/browser/affiliation_fetcher.cc',
- 'password_manager/core/browser/affiliation_fetcher.h',
- 'password_manager/core/browser/affiliation_fetcher_delegate.h',
- 'password_manager/core/browser/affiliation_service.cc',
- 'password_manager/core/browser/affiliation_service.h',
- 'password_manager/core/browser/affiliation_utils.cc',
- 'password_manager/core/browser/affiliation_utils.h',
- 'password_manager/core/browser/browser_save_password_progress_logger.cc',
- 'password_manager/core/browser/browser_save_password_progress_logger.h',
- 'password_manager/core/browser/credential_manager_password_form_manager.cc',
- 'password_manager/core/browser/credential_manager_password_form_manager.h',
- 'password_manager/core/browser/credential_manager_pending_request_task.cc',
- 'password_manager/core/browser/credential_manager_pending_request_task.h',
- 'password_manager/core/browser/credential_manager_pending_require_user_mediation_task.cc',
- 'password_manager/core/browser/credential_manager_pending_require_user_mediation_task.h',
- 'password_manager/core/browser/credentials_filter.h',
- 'password_manager/core/browser/export/csv_writer.cc',
- 'password_manager/core/browser/export/csv_writer.h',
- 'password_manager/core/browser/export/password_csv_writer.cc',
- 'password_manager/core/browser/export/password_csv_writer.h',
- 'password_manager/core/browser/export/password_exporter.cc',
- 'password_manager/core/browser/export/password_exporter.h',
- 'password_manager/core/browser/facet_manager.cc',
- 'password_manager/core/browser/facet_manager.h',
- 'password_manager/core/browser/facet_manager_host.h',
- 'password_manager/core/browser/form_saver.h',
- 'password_manager/core/browser/form_saver_impl.cc',
- 'password_manager/core/browser/form_saver_impl.h',
- 'password_manager/core/browser/import/csv_reader.cc',
- 'password_manager/core/browser/import/csv_reader.h',
- 'password_manager/core/browser/import/password_csv_reader.cc',
- 'password_manager/core/browser/import/password_csv_reader.h',
- 'password_manager/core/browser/import/password_importer.cc',
- 'password_manager/core/browser/import/password_importer.h',
- 'password_manager/core/browser/keychain_migration_status_mac.h',
- 'password_manager/core/browser/log_manager.cc',
- 'password_manager/core/browser/log_manager.h',
- 'password_manager/core/browser/log_receiver.h',
- 'password_manager/core/browser/log_router.cc',
- 'password_manager/core/browser/log_router.h',
- 'password_manager/core/browser/login_database.cc',
- 'password_manager/core/browser/login_database.h',
- 'password_manager/core/browser/login_database_ios.cc',
- 'password_manager/core/browser/login_database_mac.cc',
- 'password_manager/core/browser/login_database_posix.cc',
- 'password_manager/core/browser/login_database_win.cc',
- 'password_manager/core/browser/login_model.cc',
- 'password_manager/core/browser/login_model.h',
- 'password_manager/core/browser/password_autofill_manager.cc',
- 'password_manager/core/browser/password_autofill_manager.h',
- 'password_manager/core/browser/password_bubble_experiment.cc',
- 'password_manager/core/browser/password_bubble_experiment.h',
- 'password_manager/core/browser/password_form_manager.cc',
- 'password_manager/core/browser/password_form_manager.h',
- 'password_manager/core/browser/password_generation_manager.cc',
- 'password_manager/core/browser/password_generation_manager.h',
- 'password_manager/core/browser/password_manager.cc',
- 'password_manager/core/browser/password_manager.h',
- 'password_manager/core/browser/password_manager_client.cc',
- 'password_manager/core/browser/password_manager_client.h',
- 'password_manager/core/browser/password_manager_constants.cc',
- 'password_manager/core/browser/password_manager_constants.h',
- 'password_manager/core/browser/password_manager_driver.h',
- 'password_manager/core/browser/password_manager_internals_service.cc',
- 'password_manager/core/browser/password_manager_internals_service.h',
- 'password_manager/core/browser/password_manager_metrics_util.cc',
- 'password_manager/core/browser/password_manager_metrics_util.h',
- 'password_manager/core/browser/password_manager_settings_migration_experiment.cc',
- 'password_manager/core/browser/password_manager_settings_migration_experiment.h',
- 'password_manager/core/browser/password_manager_util.cc',
- 'password_manager/core/browser/password_manager_util.h',
- 'password_manager/core/browser/password_store.cc',
- 'password_manager/core/browser/password_store.h',
- 'password_manager/core/browser/password_store_change.cc',
- 'password_manager/core/browser/password_store_change.h',
- 'password_manager/core/browser/password_store_consumer.cc',
- 'password_manager/core/browser/password_store_consumer.h',
- 'password_manager/core/browser/password_store_default.cc',
- 'password_manager/core/browser/password_store_default.h',
- 'password_manager/core/browser/password_store_factory_util.cc',
- 'password_manager/core/browser/password_store_factory_util.h',
- 'password_manager/core/browser/password_store_sync.cc',
- 'password_manager/core/browser/password_store_sync.h',
- 'password_manager/core/browser/password_syncable_service.cc',
- 'password_manager/core/browser/password_syncable_service.h',
- 'password_manager/core/browser/password_ui_utils.cc',
- 'password_manager/core/browser/password_ui_utils.h',
- 'password_manager/core/browser/psl_matching_helper.cc',
- 'password_manager/core/browser/psl_matching_helper.h',
- 'password_manager/core/browser/statistics_table.cc',
- 'password_manager/core/browser/statistics_table.h',
- 'password_manager/core/browser/test_affiliation_fetcher_factory.h',
- 'password_manager/core/browser/types.h',
- 'password_manager/core/browser/webdata/logins_table.cc',
- 'password_manager/core/browser/webdata/logins_table.h',
- 'password_manager/core/browser/webdata/logins_table_win.cc',
- 'password_manager/core/browser/webdata/password_web_data_service_win.cc',
- 'password_manager/core/browser/webdata/password_web_data_service_win.h',
- ],
- 'conditions': [
- ['OS=="ios"', {
- 'sources!': [
- 'password_manager/core/browser/login_database_posix.cc',
- ],
- }],
- ['OS=="mac"', {
- 'sources!': [
- 'password_manager/core/browser/login_database_posix.cc',
- ],
- }],
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- },
- {
- # GN version: //components/password_manager/core/browser:proto
- 'target_name': 'password_manager_core_browser_proto',
- 'type': 'static_library',
- 'sources': [
- 'password_manager/core/browser/affiliation_api.proto'
- ],
- 'variables': {
- 'proto_in_dir': 'password_manager/core/browser',
- 'proto_out_dir': 'components/password_manager/core/browser',
- },
- 'includes': ['../build/protoc.gypi'],
- },
- {
- # GN version: //components/password_manager/core/browser:test_support
- 'target_name': 'password_manager_core_browser_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'autofill_core_common',
- '../base/base.gyp:base',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- 'autofill_server_proto',
- ],
- 'export_dependent_settings': [
- '../testing/gmock.gyp:gmock',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'password_manager/core/browser/fake_affiliation_api.cc',
- 'password_manager/core/browser/fake_affiliation_api.h',
- 'password_manager/core/browser/fake_affiliation_fetcher.cc',
- 'password_manager/core/browser/fake_affiliation_fetcher.h',
- 'password_manager/core/browser/mock_affiliation_consumer.cc',
- 'password_manager/core/browser/mock_affiliation_consumer.h',
- 'password_manager/core/browser/mock_password_store.cc',
- 'password_manager/core/browser/mock_password_store.h',
- 'password_manager/core/browser/password_manager_test_utils.cc',
- 'password_manager/core/browser/password_manager_test_utils.h',
- # Note: sources list duplicated in GN build.
- 'password_manager/core/browser/stub_form_saver.h',
- 'password_manager/core/browser/stub_log_manager.cc',
- 'password_manager/core/browser/stub_log_manager.h',
- 'password_manager/core/browser/stub_password_manager_client.cc',
- 'password_manager/core/browser/stub_password_manager_client.h',
- 'password_manager/core/browser/stub_password_manager_driver.cc',
- 'password_manager/core/browser/stub_password_manager_driver.h',
- 'password_manager/core/browser/test_password_store.cc',
- 'password_manager/core/browser/test_password_store.h',
- ],
- },
- {
- # GN version: //components/password_manager/core/common
- 'target_name': 'password_manager_core_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'password_manager/core/common/credential_manager_types.cc',
- 'password_manager/core/common/credential_manager_types.h',
- 'password_manager/core/common/experiments.cc',
- 'password_manager/core/common/experiments.h',
- 'password_manager/core/common/password_manager_features.cc',
- 'password_manager/core/common/password_manager_features.h',
- 'password_manager/core/common/password_manager_pref_names.cc',
- 'password_manager/core/common/password_manager_pref_names.h',
- 'password_manager/core/common/password_manager_ui.h',
- ],
- },
- {
- # GN version: //components/password_manager/sync/browser
- 'target_name': 'password_manager_sync_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../sync/sync.gyp:sync',
- 'autofill_core_common',
- 'password_manager_core_browser',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'password_manager/sync/browser/password_data_type_controller.cc',
- 'password_manager/sync/browser/password_data_type_controller.h',
- 'password_manager/sync/browser/password_manager_setting_migrator_service.cc',
- 'password_manager/sync/browser/password_manager_setting_migrator_service.h',
- 'password_manager/sync/browser/password_model_worker.cc',
- 'password_manager/sync/browser/password_model_worker.h',
- 'password_manager/sync/browser/password_sync_util.cc',
- 'password_manager/sync/browser/password_sync_util.h',
- 'password_manager/sync/browser/sync_credentials_filter.cc',
- 'password_manager/sync/browser/sync_credentials_filter.h',
- ],
- },
- ],
- 'conditions': [
- ['OS != "ios"', {
- 'targets': [
- {
- # GN version: //components/password_manager/content/public/interfaces
- 'target_name': 'password_manager_content_mojo_bindings_mojom',
- 'type': 'none',
- 'variables': {
- 'mojom_files': [
- 'password_manager/content/public/interfaces/credential_manager.mojom',
- ],
- 'mojom_typemaps': [
- '<(DEPTH)/url/mojo/gurl.typemap',
- '<(DEPTH)/url/mojo/origin.typemap',
- ],
- },
- 'include_dirs': [
- '..',
- ],
- 'includes': [
- '../mojo/mojom_bindings_generator_explicit.gypi',
- ],
- },
- {
- # GN version: //components/password_manager/content/public/cpp
- 'target_name': 'password_manager_content_mojo_bindings',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../mojo/mojo_base.gyp:mojo_common_lib',
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
- '../third_party/WebKit/public/blink.gyp:blink',
- '../url/url.gyp:url_mojom',
- 'password_manager_content_mojo_bindings_mojom',
- 'password_manager_core_common',
- ],
- 'export_dependent_settings': [
- '../url/url.gyp:url_mojom',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'password_manager/content/public/cpp/type_converters.cc',
- 'password_manager/content/public/cpp/type_converters.h',
- ],
- },
- {
- # GN version: //components/password_manager/content/renderer
- 'target_name': 'password_manager_content_renderer',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../third_party/WebKit/public/blink.gyp:blink',
- 'password_manager_content_mojo_bindings',
- 'password_manager_core_common',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'password_manager/content/renderer/credential_manager_client.cc',
- 'password_manager/content/renderer/credential_manager_client.h',
- ],
- },
- {
- # GN version: //components/password_manager/content/browser
- 'target_name': 'password_manager_content_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../ipc/ipc.gyp:ipc',
- '../net/net.gyp:net',
- 'autofill_content_browser',
- 'autofill_content_common',
- 'autofill_core_common',
- 'keyed_service_content',
- 'password_manager_content_mojo_bindings',
- 'password_manager_core_browser',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'password_manager/content/browser/bad_message.cc',
- 'password_manager/content/browser/bad_message.h',
- 'password_manager/content/browser/content_password_manager_driver.cc',
- 'password_manager/content/browser/content_password_manager_driver.h',
- 'password_manager/content/browser/content_password_manager_driver_factory.cc',
- 'password_manager/content/browser/content_password_manager_driver_factory.h',
- 'password_manager/content/browser/credential_manager_impl.cc',
- 'password_manager/content/browser/credential_manager_impl.h',
- 'password_manager/content/browser/password_manager_internals_service_factory.cc',
- 'password_manager/content/browser/password_manager_internals_service_factory.h',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/password_manager/DEPS b/chromium/components/password_manager/DEPS
index 273714ca3aa..5aa1cf79ab5 100644
--- a/chromium/components/password_manager/DEPS
+++ b/chromium/components/password_manager/DEPS
@@ -4,12 +4,12 @@ include_rules = [
"+components/password_manager/core",
"+components/prefs",
"+components/strings/grit",
+ "+components/sync/api",
+ "+components/sync/protocol",
"+net/base",
"+net/http/http_status_code.h",
"+net/url_request",
"+sql",
- "+sync/api",
- "+sync/protocol",
"+third_party/re2",
"+third_party/sqlite/sqlite3.h",
"+ui",
diff --git a/chromium/components/password_manager/content/DEPS b/chromium/components/password_manager/content/DEPS
index 6a69bf3ee44..41895a00ad5 100644
--- a/chromium/components/password_manager/content/DEPS
+++ b/chromium/components/password_manager/content/DEPS
@@ -3,6 +3,7 @@ include_rules = [
"+components/autofill/core/common",
"+content/public/common",
"+mojo/common",
+ "+mojo/public",
# Allow inclusion of WebKit API files.
"+third_party/WebKit/public/platform",
"+third_party/WebKit/public/web",
diff --git a/chromium/components/password_manager/content/browser/BUILD.gn b/chromium/components/password_manager/content/browser/BUILD.gn
index d9787f478d3..55e313dacbb 100644
--- a/chromium/components/password_manager/content/browser/BUILD.gn
+++ b/chromium/components/password_manager/content/browser/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser") {
+static_library("browser") {
sources = [
"bad_message.cc",
"bad_message.h",
@@ -19,17 +19,16 @@ source_set("browser") {
public_deps = [
"//base",
"//components/autofill/content/browser",
- "//components/autofill/content/common",
+ "//components/autofill/content/public/interfaces",
"//components/autofill/core/common",
"//components/keyed_service/content",
- "//components/password_manager/content/public/cpp",
"//components/password_manager/content/public/interfaces",
"//components/password_manager/core/browser",
"//components/password_manager/core/common",
"//components/prefs",
"//content/public/browser",
"//content/public/common",
- "//ipc",
+ "//mojo/common:common_base",
"//net",
]
}
diff --git a/chromium/components/password_manager/content/browser/DEPS b/chromium/components/password_manager/content/browser/DEPS
index 4bab70e24b4..cdef6b9073e 100644
--- a/chromium/components/password_manager/content/browser/DEPS
+++ b/chromium/components/password_manager/content/browser/DEPS
@@ -1,9 +1,9 @@
include_rules = [
"+components/autofill/core/browser",
"+components/autofill/content/browser",
+ "+components/autofill/content/public/interfaces",
"+components/keyed_service/content",
"+content/public/browser",
- "+ipc",
- "+mojo/public",
"+net",
+ "+services/shell/public/cpp",
]
diff --git a/chromium/components/password_manager/content/browser/bad_message.cc b/chromium/components/password_manager/content/browser/bad_message.cc
index 74c35273571..ddc51e260c9 100644
--- a/chromium/components/password_manager/content/browser/bad_message.cc
+++ b/chromium/components/password_manager/content/browser/bad_message.cc
@@ -18,7 +18,8 @@ void ReceivedBadMessage(content::RenderProcessHost* host,
<< static_cast<int>(reason);
UMA_HISTOGRAM_SPARSE_SLOWLY("Stability.BadMessageTerminated.PasswordManager",
static_cast<int>(reason));
- host->ShutdownForBadMessage();
+ host->ShutdownForBadMessage(
+ content::RenderProcessHost::CrashReportMode::GENERATE_CRASH_DUMP);
}
} // namespace bad_message
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
index 0a7769436f0..722416e5ef1 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -4,7 +4,7 @@
#include "components/password_manager/content/browser/content_password_manager_driver.h"
-#include "components/autofill/content/common/autofill_messages.h"
+#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/content/browser/bad_message.h"
@@ -20,10 +20,10 @@
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/site_instance.h"
+#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/ssl_status.h"
-#include "ipc/ipc_message_macros.h"
#include "net/cert/cert_status_flags.h"
+#include "services/shell/public/cpp/interface_provider.h"
namespace password_manager {
@@ -35,7 +35,9 @@ ContentPasswordManagerDriver::ContentPasswordManagerDriver(
client_(client),
password_generation_manager_(client, this),
password_autofill_manager_(this, autofill_client),
- next_free_key_(0) {}
+ next_free_key_(0),
+ binding_(this),
+ weak_factory_(this) {}
ContentPasswordManagerDriver::~ContentPasswordManagerDriver() {
}
@@ -50,95 +52,82 @@ ContentPasswordManagerDriver::GetForRenderFrameHost(
return factory ? factory->GetDriverForFrame(render_frame_host) : nullptr;
}
+void ContentPasswordManagerDriver::BindRequest(
+ autofill::mojom::PasswordManagerDriverRequest request) {
+ binding_.Bind(std::move(request));
+}
+
void ContentPasswordManagerDriver::FillPasswordForm(
const autofill::PasswordFormFillData& form_data) {
const int key = next_free_key_++;
password_autofill_manager_.OnAddPasswordFormMapping(key, form_data);
- render_frame_host_->Send(new AutofillMsg_FillPasswordForm(
- render_frame_host_->GetRoutingID(), key, form_data));
+ GetPasswordAutofillAgent()->FillPasswordForm(key, form_data);
}
void ContentPasswordManagerDriver::AllowPasswordGenerationForForm(
const autofill::PasswordForm& form) {
if (!GetPasswordGenerationManager()->IsGenerationEnabled())
return;
- content::RenderFrameHost* host = render_frame_host_;
- host->Send(new AutofillMsg_FormNotBlacklisted(host->GetRoutingID(), form));
+ GetPasswordGenerationAgent()->FormNotBlacklisted(form);
}
void ContentPasswordManagerDriver::FormsEligibleForGenerationFound(
const std::vector<autofill::PasswordFormGenerationData>& forms) {
- content::RenderFrameHost* host = render_frame_host_;
- host->Send(new AutofillMsg_FoundFormsEligibleForGeneration(
- host->GetRoutingID(), forms));
+ GetPasswordGenerationAgent()->FoundFormsEligibleForGeneration(forms);
}
void ContentPasswordManagerDriver::AutofillDataReceived(
const std::map<autofill::FormData,
autofill::PasswordFormFieldPredictionMap>& predictions) {
- content::RenderFrameHost* host = render_frame_host_;
- host->Send(new AutofillMsg_AutofillUsernameAndPasswordDataReceived(
- host->GetRoutingID(),
- predictions));
+ GetPasswordAutofillAgent()->AutofillUsernameAndPasswordDataReceived(
+ predictions);
}
void ContentPasswordManagerDriver::GeneratedPasswordAccepted(
const base::string16& password) {
- content::RenderFrameHost* host = render_frame_host_;
- host->Send(new AutofillMsg_GeneratedPasswordAccepted(host->GetRoutingID(),
- password));
+ GetPasswordGenerationAgent()->GeneratedPasswordAccepted(password);
}
void ContentPasswordManagerDriver::FillSuggestion(
const base::string16& username,
const base::string16& password) {
- content::RenderFrameHost* host = render_frame_host_;
- host->Send(new AutofillMsg_FillPasswordSuggestion(host->GetRoutingID(),
- username, password));
+ GetAutofillAgent()->FillPasswordSuggestion(username, password);
}
void ContentPasswordManagerDriver::PreviewSuggestion(
const base::string16& username,
const base::string16& password) {
- content::RenderFrameHost* host = render_frame_host_;
- host->Send(new AutofillMsg_PreviewPasswordSuggestion(host->GetRoutingID(),
- username, password));
+ GetAutofillAgent()->PreviewPasswordSuggestion(username, password);
}
void ContentPasswordManagerDriver::ShowInitialPasswordAccountSuggestions(
const autofill::PasswordFormFillData& form_data) {
const int key = next_free_key_++;
password_autofill_manager_.OnAddPasswordFormMapping(key, form_data);
- render_frame_host_->Send(
- new AutofillMsg_ShowInitialPasswordAccountSuggestions(
- render_frame_host_->GetRoutingID(), key, form_data));
+ GetAutofillAgent()->ShowInitialPasswordAccountSuggestions(key, form_data);
}
void ContentPasswordManagerDriver::ClearPreviewedForm() {
- content::RenderFrameHost* host = render_frame_host_;
- host->Send(new AutofillMsg_ClearPreviewedForm(host->GetRoutingID()));
+ GetAutofillAgent()->ClearPreviewedForm();
}
void ContentPasswordManagerDriver::ForceSavePassword() {
- content::RenderFrameHost* host = render_frame_host_;
- host->Send(new AutofillMsg_FindFocusedPasswordForm(host->GetRoutingID()));
+ GetPasswordAutofillAgent()->FindFocusedPasswordForm(
+ base::Bind(&ContentPasswordManagerDriver::OnFocusedPasswordFormFound,
+ weak_factory_.GetWeakPtr()));
}
void ContentPasswordManagerDriver::GeneratePassword() {
- content::RenderFrameHost* host = render_frame_host_;
- host->Send(
- new AutofillMsg_UserTriggeredGeneratePassword(host->GetRoutingID()));
+ GetPasswordGenerationAgent()->UserTriggeredGeneratePassword();
}
void ContentPasswordManagerDriver::SendLoggingAvailability() {
- render_frame_host_->Send(new AutofillMsg_SetLoggingState(
- render_frame_host_->GetRoutingID(),
- client_->GetLogManager()->IsLoggingActive()));
+ GetPasswordAutofillAgent()->SetLoggingState(
+ client_->GetLogManager()->IsLoggingActive());
}
void ContentPasswordManagerDriver::AllowToRunFormClassifier() {
- render_frame_host_->Send(new AutofillMsg_AllowToRunFormClassifier(
- render_frame_host_->GetRoutingID()));
+ GetPasswordGenerationAgent()->AllowToRunFormClassifier();
}
PasswordGenerationManager*
@@ -155,38 +144,7 @@ ContentPasswordManagerDriver::GetPasswordAutofillManager() {
return &password_autofill_manager_;
}
-bool ContentPasswordManagerDriver::HandleMessage(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(ContentPasswordManagerDriver, message)
- IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsParsed,
- OnPasswordFormsParsed)
- IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsRendered,
- OnPasswordFormsRendered)
- IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormSubmitted,
- OnPasswordFormSubmitted)
- IPC_MESSAGE_HANDLER(AutofillHostMsg_InPageNavigation, OnInPageNavigation)
- IPC_MESSAGE_HANDLER(AutofillHostMsg_PresaveGeneratedPassword,
- OnPresaveGeneratedPassword)
- IPC_MESSAGE_HANDLER(AutofillHostMsg_SaveGenerationFieldDetectedByClassifier,
- OnSaveGenerationFieldDetectedByClassifier)
- IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordNoLongerGenerated,
- OnPasswordNoLongerGenerated)
- IPC_MESSAGE_HANDLER(AutofillHostMsg_FocusedPasswordFormFound,
- OnFocusedPasswordFormFound)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_ShowPasswordSuggestions,
- &password_autofill_manager_,
- PasswordAutofillManager::OnShowPasswordSuggestions)
- IPC_MESSAGE_FORWARD(AutofillHostMsg_RecordSavePasswordProgress,
- client_->GetLogManager(),
- LogManager::LogSavePasswordProgress)
- IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordAutofillAgentConstructed,
- SendLoggingAvailability)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void ContentPasswordManagerDriver::OnPasswordFormsParsed(
+void ContentPasswordManagerDriver::PasswordFormsParsed(
const std::vector<autofill::PasswordForm>& forms) {
for (const auto& form : forms)
if (!CheckChildProcessSecurityPolicy(
@@ -202,7 +160,7 @@ void ContentPasswordManagerDriver::OnPasswordFormsParsedNoRenderCheck(
GetPasswordGenerationManager()->CheckIfFormClassifierShouldRun();
}
-void ContentPasswordManagerDriver::OnPasswordFormsRendered(
+void ContentPasswordManagerDriver::PasswordFormsRendered(
const std::vector<autofill::PasswordForm>& visible_forms,
bool did_stop_loading) {
for (const auto& form : visible_forms)
@@ -213,7 +171,7 @@ void ContentPasswordManagerDriver::OnPasswordFormsRendered(
did_stop_loading);
}
-void ContentPasswordManagerDriver::OnPasswordFormSubmitted(
+void ContentPasswordManagerDriver::PasswordFormSubmitted(
const autofill::PasswordForm& password_form) {
if (!CheckChildProcessSecurityPolicy(
password_form.origin,
@@ -241,7 +199,7 @@ void ContentPasswordManagerDriver::DidNavigateFrame(
}
}
-void ContentPasswordManagerDriver::OnInPageNavigation(
+void ContentPasswordManagerDriver::InPageNavigation(
const autofill::PasswordForm& password_form) {
if (!CheckChildProcessSecurityPolicy(
password_form.origin,
@@ -250,7 +208,7 @@ void ContentPasswordManagerDriver::OnInPageNavigation(
GetPasswordManager()->OnInPageNavigation(this, password_form);
}
-void ContentPasswordManagerDriver::OnPresaveGeneratedPassword(
+void ContentPasswordManagerDriver::PresaveGeneratedPassword(
const autofill::PasswordForm& password_form) {
if (!CheckChildProcessSecurityPolicy(
password_form.origin,
@@ -259,7 +217,7 @@ void ContentPasswordManagerDriver::OnPresaveGeneratedPassword(
GetPasswordManager()->OnPresaveGeneratedPassword(password_form);
}
-void ContentPasswordManagerDriver::OnPasswordNoLongerGenerated(
+void ContentPasswordManagerDriver::PasswordNoLongerGenerated(
const autofill::PasswordForm& password_form) {
if (!CheckChildProcessSecurityPolicy(
password_form.origin,
@@ -269,7 +227,7 @@ void ContentPasswordManagerDriver::OnPasswordNoLongerGenerated(
false);
}
-void ContentPasswordManagerDriver::OnSaveGenerationFieldDetectedByClassifier(
+void ContentPasswordManagerDriver::SaveGenerationFieldDetectedByClassifier(
const autofill::PasswordForm& password_form,
const base::string16& generation_field) {
if (!CheckChildProcessSecurityPolicy(
@@ -281,6 +239,25 @@ void ContentPasswordManagerDriver::OnSaveGenerationFieldDetectedByClassifier(
password_form, generation_field);
}
+void ContentPasswordManagerDriver::ShowPasswordSuggestions(
+ int key,
+ base::i18n::TextDirection text_direction,
+ const base::string16& typed_username,
+ int options,
+ const gfx::RectF& bounds) {
+ password_autofill_manager_.OnShowPasswordSuggestions(
+ key, text_direction, typed_username, options, bounds);
+}
+
+void ContentPasswordManagerDriver::PasswordAutofillAgentConstructed() {
+ SendLoggingAvailability();
+}
+
+void ContentPasswordManagerDriver::RecordSavePasswordProgress(
+ const std::string& log) {
+ client_->GetLogManager()->LogSavePasswordProgress(log);
+}
+
bool ContentPasswordManagerDriver::CheckChildProcessSecurityPolicy(
const GURL& url,
BadMessageReason reason) {
@@ -295,4 +272,38 @@ bool ContentPasswordManagerDriver::CheckChildProcessSecurityPolicy(
return true;
}
+const autofill::mojom::AutofillAgentPtr&
+ContentPasswordManagerDriver::GetAutofillAgent() {
+ autofill::ContentAutofillDriver* autofill_driver =
+ autofill::ContentAutofillDriver::GetForRenderFrameHost(
+ render_frame_host_);
+ DCHECK(autofill_driver);
+ return autofill_driver->GetAutofillAgent();
+}
+
+const autofill::mojom::PasswordAutofillAgentPtr&
+ContentPasswordManagerDriver::GetPasswordAutofillAgent() {
+ if (!password_autofill_agent_) {
+ autofill::mojom::PasswordAutofillAgentRequest request =
+ mojo::GetProxy(&password_autofill_agent_);
+ // Some test codes may have no initialized remote interfaces.
+ if (render_frame_host_->GetRemoteInterfaces()) {
+ render_frame_host_->GetRemoteInterfaces()->GetInterface(
+ std::move(request));
+ }
+ }
+
+ return password_autofill_agent_;
+}
+
+const autofill::mojom::PasswordGenerationAgentPtr&
+ContentPasswordManagerDriver::GetPasswordGenerationAgent() {
+ if (!password_gen_agent_) {
+ render_frame_host_->GetRemoteInterfaces()->GetInterface(
+ mojo::GetProxy(&password_gen_agent_));
+ }
+
+ return password_gen_agent_;
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.h b/chromium/components/password_manager/content/browser/content_password_manager_driver.h
index 28678cb6aab..e4ed94cd121 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver.h
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.h
@@ -10,12 +10,15 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "components/autofill/content/public/interfaces/autofill_agent.mojom.h"
+#include "components/autofill/content/public/interfaces/autofill_driver.mojom.h"
#include "components/autofill/core/common/password_form_field_prediction_map.h"
#include "components/autofill/core/common/password_form_generation_data.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_generation_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
+#include "mojo/public/cpp/bindings/binding.h"
namespace autofill {
class AutofillManager;
@@ -38,7 +41,9 @@ enum class BadMessageReason;
// There is one ContentPasswordManagerDriver per RenderFrameHost.
// The lifetime is managed by the ContentPasswordManagerDriverFactory.
-class ContentPasswordManagerDriver : public PasswordManagerDriver {
+class ContentPasswordManagerDriver
+ : public PasswordManagerDriver,
+ public autofill::mojom::PasswordManagerDriver {
public:
ContentPasswordManagerDriver(content::RenderFrameHost* render_frame_host,
PasswordManagerClient* client,
@@ -49,6 +54,8 @@ class ContentPasswordManagerDriver : public PasswordManagerDriver {
static ContentPasswordManagerDriver* GetForRenderFrameHost(
content::RenderFrameHost* render_frame_host);
+ void BindRequest(autofill::mojom::PasswordManagerDriverRequest request);
+
// PasswordManagerDriver implementation.
void FillPasswordForm(
const autofill::PasswordFormFillData& form_data) override;
@@ -77,30 +84,48 @@ class ContentPasswordManagerDriver : public PasswordManagerDriver {
PasswordManager* GetPasswordManager() override;
PasswordAutofillManager* GetPasswordAutofillManager() override;
- bool HandleMessage(const IPC::Message& message);
void DidNavigateFrame(const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params);
- // Pass-throughs to PasswordManager.
- void OnPasswordFormsParsed(const std::vector<autofill::PasswordForm>& forms);
+ // autofill::mojom::PasswordManagerDriver:
+ void PasswordFormsParsed(
+ const std::vector<autofill::PasswordForm>& forms) override;
+ void PasswordFormsRendered(
+ const std::vector<autofill::PasswordForm>& visible_forms,
+ bool did_stop_loading) override;
+ void PasswordFormSubmitted(
+ const autofill::PasswordForm& password_form) override;
+ void InPageNavigation(const autofill::PasswordForm& password_form) override;
+ void PresaveGeneratedPassword(
+ const autofill::PasswordForm& password_form) override;
+ void PasswordNoLongerGenerated(
+ const autofill::PasswordForm& password_form) override;
+ void ShowPasswordSuggestions(int key,
+ base::i18n::TextDirection text_direction,
+ const base::string16& typed_username,
+ int options,
+ const gfx::RectF& bounds) override;
+ void PasswordAutofillAgentConstructed() override;
+ void RecordSavePasswordProgress(const std::string& log) override;
+ void SaveGenerationFieldDetectedByClassifier(
+ const autofill::PasswordForm& password_form,
+ const base::string16& generation_field) override;
+
void OnPasswordFormsParsedNoRenderCheck(
const std::vector<autofill::PasswordForm>& forms);
- void OnPasswordFormsRendered(
- const std::vector<autofill::PasswordForm>& visible_forms,
- bool did_stop_loading);
- void OnPasswordFormSubmitted(const autofill::PasswordForm& password_form);
- void OnInPageNavigation(const autofill::PasswordForm& password_form);
- void OnPresaveGeneratedPassword(const autofill::PasswordForm& password_form);
- void OnPasswordNoLongerGenerated(const autofill::PasswordForm& password_form);
void OnFocusedPasswordFormFound(const autofill::PasswordForm& password_form);
- void OnSaveGenerationFieldDetectedByClassifier(
- const autofill::PasswordForm& password_form,
- const base::string16& generation_field);
private:
bool CheckChildProcessSecurityPolicy(const GURL& url,
BadMessageReason reason);
+ const autofill::mojom::AutofillAgentPtr& GetAutofillAgent();
+
+ const autofill::mojom::PasswordAutofillAgentPtr& GetPasswordAutofillAgent();
+
+ const autofill::mojom::PasswordGenerationAgentPtr&
+ GetPasswordGenerationAgent();
+
content::RenderFrameHost* render_frame_host_;
PasswordManagerClient* client_;
PasswordGenerationManager password_generation_manager_;
@@ -112,6 +137,14 @@ class ContentPasswordManagerDriver : public PasswordManagerDriver {
// it to each other over IPC. The counter below is used to generate new IDs.
int next_free_key_;
+ autofill::mojom::PasswordAutofillAgentPtr password_autofill_agent_;
+
+ autofill::mojom::PasswordGenerationAgentPtr password_gen_agent_;
+
+ mojo::Binding<autofill::mojom::PasswordManagerDriver> binding_;
+
+ base::WeakPtrFactory<ContentPasswordManagerDriver> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ContentPasswordManagerDriver);
};
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
index ad8d203fc7c..53b47140bbd 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
@@ -11,7 +11,6 @@
#include "base/stl_util.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
-#include "components/autofill/content/common/autofill_messages.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/content/browser/content_password_manager_driver.h"
@@ -21,9 +20,8 @@
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/ssl_status.h"
-#include "ipc/ipc_message_macros.h"
#include "net/cert/cert_status_flags.h"
namespace password_manager {
@@ -75,6 +73,30 @@ ContentPasswordManagerDriverFactory::FromWebContents(
kContentPasswordManagerDriverFactoryWebContentsUserDataKey));
}
+// static
+void ContentPasswordManagerDriverFactory::BindPasswordManagerDriver(
+ content::RenderFrameHost* render_frame_host,
+ autofill::mojom::PasswordManagerDriverRequest request) {
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(render_frame_host);
+ if (!web_contents)
+ return;
+
+ ContentPasswordManagerDriverFactory* factory =
+ ContentPasswordManagerDriverFactory::FromWebContents(web_contents);
+ // We try to bind to the driver, but if driver is not ready for now or totally
+ // not available for this render frame host, the request will be just dropped.
+ // This would cause the message pipe to be closed, which will raise a
+ // connection error on the peer side.
+ if (!factory)
+ return;
+
+ ContentPasswordManagerDriver* driver =
+ factory->GetDriverForFrame(render_frame_host);
+ if (driver)
+ driver->BindRequest(std::move(request));
+}
+
ContentPasswordManagerDriver*
ContentPasswordManagerDriverFactory::GetDriverForFrame(
content::RenderFrameHost* render_frame_host) {
@@ -89,8 +111,8 @@ void ContentPasswordManagerDriverFactory::RenderFrameCreated(
// This is called twice for the main frame.
if (insertion_result.second) { // This was the first time.
insertion_result.first->second =
- base::WrapUnique(new ContentPasswordManagerDriver(
- render_frame_host, password_client_, autofill_client_));
+ base::MakeUnique<ContentPasswordManagerDriver>(
+ render_frame_host, password_client_, autofill_client_);
}
}
@@ -99,13 +121,6 @@ void ContentPasswordManagerDriverFactory::RenderFrameDeleted(
frame_driver_map_.erase(render_frame_host);
}
-bool ContentPasswordManagerDriverFactory::OnMessageReceived(
- const IPC::Message& message,
- content::RenderFrameHost* render_frame_host) {
- return frame_driver_map_.find(render_frame_host)
- ->second->HandleMessage(message);
-}
-
void ContentPasswordManagerDriverFactory::DidNavigateAnyFrame(
content::RenderFrameHost* render_frame_host,
const content::LoadCommittedDetails& details,
@@ -114,12 +129,6 @@ void ContentPasswordManagerDriverFactory::DidNavigateAnyFrame(
->second->DidNavigateFrame(details, params);
}
-void ContentPasswordManagerDriverFactory::TestingSetDriverForFrame(
- content::RenderFrameHost* render_frame_host,
- std::unique_ptr<ContentPasswordManagerDriver> driver) {
- frame_driver_map_[render_frame_host] = std::move(driver);
-}
-
void ContentPasswordManagerDriverFactory::RequestSendLoggingAvailability() {
for (const auto& key_val_iterator : frame_driver_map_) {
key_val_iterator.second->SendLoggingAvailability();
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.h b/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.h
index 9b1335bd590..dcfe5a376b9 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.h
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.h
@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/supports_user_data.h"
+#include "components/autofill/content/public/interfaces/autofill_driver.mojom.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_generation_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
@@ -44,20 +45,18 @@ class ContentPasswordManagerDriverFactory
static ContentPasswordManagerDriverFactory* FromWebContents(
content::WebContents* web_contents);
+ static void BindPasswordManagerDriver(
+ content::RenderFrameHost* render_frame_host,
+ autofill::mojom::PasswordManagerDriverRequest request);
+
ContentPasswordManagerDriver* GetDriverForFrame(
content::RenderFrameHost* render_frame_host);
- void TestingSetDriverForFrame(
- content::RenderFrameHost* render_frame_host,
- std::unique_ptr<ContentPasswordManagerDriver> driver);
-
// Requests all drivers to inform their renderers whether
// chrome://password-manager-internals is available.
void RequestSendLoggingAvailability();
// content::WebContentsObserver:
- bool OnMessageReceived(const IPC::Message& message,
- content::RenderFrameHost* render_frame_host) override;
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host,
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
index 267aa3797ac..06e21b397de 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
@@ -4,17 +4,16 @@
#include "components/password_manager/content/browser/content_password_manager_driver.h"
-#include <stdint.h>
-
-#include <tuple>
-
#include "base/macros.h"
-#include "components/autofill/content/common/autofill_messages.h"
+#include "base/run_loop.h"
+#include "components/autofill/content/public/interfaces/autofill_agent.mojom.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/password_manager/core/browser/stub_log_manager.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
-#include "content/public/test/mock_render_process_host.h"
+#include "content/public/browser/web_contents.h"
#include "content/public/test/test_renderer_host.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/shell/public/cpp/interface_provider.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -40,6 +39,55 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient);
};
+class FakePasswordAutofillAgent
+ : public autofill::mojom::PasswordAutofillAgent {
+ public:
+ FakePasswordAutofillAgent()
+ : called_set_logging_state_(false),
+ logging_state_active_(false),
+ binding_(this) {}
+
+ ~FakePasswordAutofillAgent() override {}
+
+ void BindRequest(mojo::ScopedMessagePipeHandle handle) {
+ binding_.Bind(mojo::MakeRequest<autofill::mojom::PasswordAutofillAgent>(
+ std::move(handle)));
+ }
+
+ bool called_set_logging_state() { return called_set_logging_state_; }
+
+ bool logging_state_active() { return logging_state_active_; }
+
+ void reset_data() {
+ called_set_logging_state_ = false;
+ logging_state_active_ = false;
+ }
+
+ private:
+ // autofill::mojom::PasswordAutofillAgent:
+ void FillPasswordForm(
+ int key,
+ const autofill::PasswordFormFillData& form_data) override {}
+
+ void SetLoggingState(bool active) override {
+ called_set_logging_state_ = true;
+ logging_state_active_ = active;
+ }
+
+ void AutofillUsernameAndPasswordDataReceived(
+ const autofill::FormsPredictionsMap& predictions) override {}
+
+ void FindFocusedPasswordForm(
+ const FindFocusedPasswordFormCallback& callback) override {}
+
+ // Records whether SetLoggingState() gets called.
+ bool called_set_logging_state_;
+ // Records data received via SetLoggingState() call.
+ bool logging_state_active_;
+
+ mojo::Binding<autofill::mojom::PasswordAutofillAgent> binding_;
+};
+
} // namespace
class ContentPasswordManagerDriverTest
@@ -50,18 +98,24 @@ class ContentPasswordManagerDriverTest
content::RenderViewHostTestHarness::SetUp();
ON_CALL(password_manager_client_, GetLogManager())
.WillByDefault(Return(&log_manager_));
+
+ shell::InterfaceProvider* remote_interfaces =
+ web_contents()->GetMainFrame()->GetRemoteInterfaces();
+ shell::InterfaceProvider::TestApi test_api(remote_interfaces);
+ test_api.SetBinderForName(
+ autofill::mojom::PasswordAutofillAgent::Name_,
+ base::Bind(&FakePasswordAutofillAgent::BindRequest,
+ base::Unretained(&fake_agent_)));
}
bool WasLoggingActivationMessageSent(bool* activation_flag) {
- const uint32_t kMsgID = AutofillMsg_SetLoggingState::ID;
- const IPC::Message* message =
- process()->sink().GetFirstMessageMatching(kMsgID);
- if (!message)
+ base::RunLoop().RunUntilIdle();
+ if (!fake_agent_.called_set_logging_state())
return false;
- std::tuple<bool> param;
- AutofillMsg_SetLoggingState::Read(message, &param);
- *activation_flag = std::get<0>(param);
- process()->sink().ClearMessages();
+
+ if (activation_flag)
+ *activation_flag = fake_agent_.logging_state_active();
+ fake_agent_.reset_data();
return true;
}
@@ -69,6 +123,8 @@ class ContentPasswordManagerDriverTest
MockLogManager log_manager_;
MockPasswordManagerClient password_manager_client_;
autofill::TestAutofillClient autofill_client_;
+
+ FakePasswordAutofillAgent fake_agent_;
};
TEST_P(ContentPasswordManagerDriverTest,
@@ -77,7 +133,6 @@ TEST_P(ContentPasswordManagerDriverTest,
std::unique_ptr<ContentPasswordManagerDriver> driver(
new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
&autofill_client_));
- process()->sink().ClearMessages();
EXPECT_CALL(log_manager_, IsLoggingActive())
.WillRepeatedly(Return(should_allow_logging));
@@ -102,11 +157,10 @@ TEST_P(ContentPasswordManagerDriverTest, AnswerToIPCPingsAboutLoggingState) {
EXPECT_CALL(log_manager_, IsLoggingActive())
.WillRepeatedly(Return(should_allow_logging));
driver->SendLoggingAvailability();
- process()->sink().ClearMessages();
+ WasLoggingActivationMessageSent(nullptr);
// Ping the driver for logging activity update.
- AutofillHostMsg_PasswordAutofillAgentConstructed msg(0);
- driver->HandleMessage(msg);
+ driver->PasswordAutofillAgentConstructed();
bool logging_activated = false;
EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_activated));
diff --git a/chromium/components/password_manager/content/browser/credential_manager_impl.cc b/chromium/components/password_manager/content/browser/credential_manager_impl.cc
index ba0cf7dda22..66a457b8e0d 100644
--- a/chromium/components/password_manager/content/browser/credential_manager_impl.cc
+++ b/chromium/components/password_manager/content/browser/credential_manager_impl.cc
@@ -7,14 +7,16 @@
#include <utility>
#include "base/bind.h"
+#include "base/metrics/user_metrics.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/content/browser/content_password_manager_driver.h"
#include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
-#include "components/password_manager/content/public/cpp/type_converters.h"
#include "components/password_manager/core/browser/affiliated_match_helper.h"
+#include "components/password_manager/core/browser/credential_manager_logger.h"
#include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/common/credential_manager_types.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
@@ -26,8 +28,7 @@ namespace {
void RunMojoGetCallback(const mojom::CredentialManager::GetCallback& callback,
const CredentialInfo& info) {
- mojom::CredentialInfoPtr credential = mojom::CredentialInfo::From(info);
- callback.Run(mojom::CredentialManagerError::SUCCESS, std::move(credential));
+ callback.Run(mojom::CredentialManagerError::SUCCESS, info);
}
} // namespace
@@ -49,10 +50,15 @@ void CredentialManagerImpl::BindRequest(
bindings_.AddBinding(this, std::move(request));
}
-void CredentialManagerImpl::Store(mojom::CredentialInfoPtr credential,
+void CredentialManagerImpl::Store(const CredentialInfo& credential,
const StoreCallback& callback) {
- CredentialInfo info = credential.To<CredentialInfo>();
- DCHECK_NE(CredentialType::CREDENTIAL_TYPE_EMPTY, info.type);
+ DCHECK_NE(CredentialType::CREDENTIAL_TYPE_EMPTY, credential.type);
+
+ if (password_manager_util::IsLoggingActive(client_)) {
+ CredentialManagerLogger(client_->GetLogManager())
+ .LogStoreCredential(web_contents()->GetLastCommittedURL(),
+ credential.type);
+ }
// Send acknowledge response back.
callback.Run();
@@ -64,8 +70,7 @@ void CredentialManagerImpl::Store(mojom::CredentialInfoPtr credential,
GURL origin = web_contents()->GetLastCommittedURL().GetOrigin();
std::unique_ptr<autofill::PasswordForm> form(
- CreatePasswordFormFromCredentialInfo(info, origin));
- form->skip_zero_click = !IsZeroClickAllowed();
+ CreatePasswordFormFromCredentialInfo(credential, origin));
form_manager_.reset(new CredentialManagerPasswordFormManager(
client_, GetDriver(), *CreateObservedPasswordFormFromOrigin(origin),
@@ -81,7 +86,8 @@ void CredentialManagerImpl::OnProvisionalSaveComplete() {
// If this is a federated credential, check it against the federated matches
// produced by the PasswordFormManager. If a match is found, update it and
// return.
- for (const auto& match : form_manager_->federated_matches()) {
+ for (const auto& match :
+ form_manager_->form_fetcher()->GetFederatedMatches()) {
if (match->username_value == form.username_value &&
match->federation_origin.IsSameOriginWith(form.federation_origin)) {
form_manager_->Update(*match);
@@ -106,6 +112,10 @@ void CredentialManagerImpl::OnProvisionalSaveComplete() {
void CredentialManagerImpl::RequireUserMediation(
const RequireUserMediationCallback& callback) {
+ if (password_manager_util::IsLoggingActive(client_)) {
+ CredentialManagerLogger(client_->GetLogManager())
+ .LogRequireUserMediation(web_contents()->GetLastCommittedURL());
+ }
PasswordStore* store = GetPasswordStore();
if (!store || !IsUpdatingCredentialAllowed()) {
callback.Run();
@@ -149,15 +159,20 @@ void CredentialManagerImpl::ScheduleRequireMediationTask(
void CredentialManagerImpl::Get(bool zero_click_only,
bool include_passwords,
- mojo::Array<GURL> federations,
+ const std::vector<GURL>& federations,
const GetCallback& callback) {
PasswordStore* store = GetPasswordStore();
+ if (password_manager_util::IsLoggingActive(client_)) {
+ CredentialManagerLogger(client_->GetLogManager())
+ .LogRequestCredential(web_contents()->GetLastCommittedURL(),
+ zero_click_only, federations);
+ }
if (pending_request_ || !store) {
// Callback error.
callback.Run(pending_request_
? mojom::CredentialManagerError::PENDINGREQUEST
: mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE,
- nullptr);
+ base::nullopt);
return;
}
@@ -166,8 +181,7 @@ void CredentialManagerImpl::Get(bool zero_click_only,
if ((zero_click_only && !IsZeroClickAllowed()) ||
client_->DidLastPageLoadEncounterSSLErrors()) {
// Callback with empty credential info.
- callback.Run(mojom::CredentialManagerError::SUCCESS,
- mojom::CredentialInfo::New());
+ callback.Run(mojom::CredentialManagerError::SUCCESS, CredentialInfo());
return;
}
@@ -176,11 +190,11 @@ void CredentialManagerImpl::Get(bool zero_click_only,
GetSynthesizedFormForOrigin(),
base::Bind(&CredentialManagerImpl::ScheduleRequestTask,
weak_factory_.GetWeakPtr(), callback, zero_click_only,
- include_passwords, federations.PassStorage()));
+ include_passwords, federations));
} else {
std::vector<std::string> no_affiliated_realms;
ScheduleRequestTask(callback, zero_click_only, include_passwords,
- federations.PassStorage(), no_affiliated_realms);
+ federations, no_affiliated_realms);
}
}
@@ -228,6 +242,10 @@ void CredentialManagerImpl::SendCredential(
DCHECK(pending_request_);
DCHECK(send_callback.Equals(pending_request_->send_callback()));
+ if (password_manager_util::IsLoggingActive(client_)) {
+ CredentialManagerLogger(client_->GetLogManager())
+ .LogSendCredential(web_contents()->GetLastCommittedURL(), info.type);
+ }
send_callback.Run(info);
pending_request_.reset();
}
@@ -250,6 +268,11 @@ void CredentialManagerImpl::SendPasswordForm(
store->UpdateLogin(update_form);
}
}
+ base::RecordAction(
+ base::UserMetricsAction("CredentialManager_AccountChooser_Accepted"));
+ } else {
+ base::RecordAction(
+ base::UserMetricsAction("CredentialManager_AccountChooser_Dismissed"));
}
SendCredential(send_callback, info);
}
@@ -258,15 +281,13 @@ PasswordManagerClient* CredentialManagerImpl::client() const {
return client_;
}
-autofill::PasswordForm CredentialManagerImpl::GetSynthesizedFormForOrigin()
+PasswordStore::FormDigest CredentialManagerImpl::GetSynthesizedFormForOrigin()
const {
- autofill::PasswordForm synthetic_form;
- synthetic_form.origin = web_contents()->GetLastCommittedURL().GetOrigin();
- synthetic_form.signon_realm = synthetic_form.origin.spec();
- synthetic_form.scheme = autofill::PasswordForm::SCHEME_HTML;
- synthetic_form.ssl_valid = synthetic_form.origin.SchemeIsCryptographic() &&
- !client_->DidLastPageLoadEncounterSSLErrors();
- return synthetic_form;
+ PasswordStore::FormDigest digest = {
+ autofill::PasswordForm::SCHEME_HTML, std::string(),
+ web_contents()->GetLastCommittedURL().GetOrigin()};
+ digest.signon_realm = digest.origin.spec();
+ return digest;
}
void CredentialManagerImpl::DoneRequiringUserMediation() {
diff --git a/chromium/components/password_manager/content/browser/credential_manager_impl.h b/chromium/components/password_manager/content/browser/credential_manager_impl.h
index 2603293aa9e..a72a1b0a1e7 100644
--- a/chromium/components/password_manager/content/browser/credential_manager_impl.h
+++ b/chromium/components/password_manager/content/browser/credential_manager_impl.h
@@ -50,13 +50,13 @@ class CredentialManagerImpl
void BindRequest(mojom::CredentialManagerRequest request);
// mojom::CredentialManager methods:
- void Store(mojom::CredentialInfoPtr credential,
+ void Store(const CredentialInfo& credential,
const StoreCallback& callback) override;
void RequireUserMediation(
const RequireUserMediationCallback& callback) override;
void Get(bool zero_click_only,
bool include_passwords,
- mojo::Array<GURL> federations,
+ const std::vector<GURL>& federations,
const GetCallback& callback) override;
// CredentialManagerPendingRequestTaskDelegate:
@@ -67,7 +67,7 @@ class CredentialManagerImpl
void SendPasswordForm(const SendCredentialCallback& send_callback,
const autofill::PasswordForm* form) override;
PasswordManagerClient* client() const override;
- autofill::PasswordForm GetSynthesizedFormForOrigin() const override;
+ PasswordStore::FormDigest GetSynthesizedFormForOrigin() const override;
// CredentialManagerPendingSignedOutTaskDelegate:
PasswordStore* GetPasswordStore() override;
diff --git a/chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc b/chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc
index 60448a4999b..20fa985f5b6 100644
--- a/chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc
+++ b/chromium/components/password_manager/content/browser/credential_manager_impl_unittest.cc
@@ -20,7 +20,6 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/password_manager/content/public/cpp/type_converters.h"
#include "components/password_manager/core/browser/credential_manager_password_form_manager.h"
#include "components/password_manager/core/browser/mock_affiliated_match_helper.h"
#include "components/password_manager/core/browser/password_manager.h"
@@ -41,6 +40,9 @@ using content::BrowserContext;
using content::WebContents;
using testing::_;
+using testing::ElementsAre;
+using testing::Pointee;
+using testing::UnorderedElementsAre;
namespace password_manager {
@@ -98,7 +100,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
ScopedVector<autofill::PasswordForm> local_forms,
ScopedVector<autofill::PasswordForm> federated_forms,
const GURL& origin,
- const CredentialsCallback& callback) {
+ const CredentialsCallback& callback) override {
EXPECT_FALSE(local_forms.empty() && federated_forms.empty());
const autofill::PasswordForm* form =
local_forms.empty() ? federated_forms[0] : local_forms[0];
@@ -185,12 +187,12 @@ void RespondCallback(bool* called) {
void GetCredentialCallback(bool* called,
mojom::CredentialManagerError* out_error,
- mojom::CredentialInfoPtr* out_info,
+ base::Optional<CredentialInfo>* out_info,
mojom::CredentialManagerError error,
- mojom::CredentialInfoPtr info) {
+ const base::Optional<CredentialInfo>& info) {
*called = true;
*out_error = error;
- *out_info = std::move(info);
+ *out_info = info;
}
} // namespace
@@ -224,7 +226,6 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
form_.signon_realm = form_.origin.spec();
form_.scheme = autofill::PasswordForm::SCHEME_HTML;
form_.skip_zero_click = false;
- form_.ssl_valid = true;
affiliated_form1_.username_value = base::ASCIIToUTF16("Affiliated 1");
affiliated_form1_.display_name = base::ASCIIToUTF16("Display Name");
@@ -233,7 +234,6 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
affiliated_form1_.signon_realm = kTestAndroidRealm1;
affiliated_form1_.scheme = autofill::PasswordForm::SCHEME_HTML;
affiliated_form1_.skip_zero_click = false;
- affiliated_form1_.ssl_valid = true;
affiliated_form2_.username_value = base::ASCIIToUTF16("Affiliated 2");
affiliated_form2_.display_name = base::ASCIIToUTF16("Display Name");
@@ -242,7 +242,6 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
affiliated_form2_.signon_realm = kTestAndroidRealm2;
affiliated_form2_.scheme = autofill::PasswordForm::SCHEME_HTML;
affiliated_form2_.skip_zero_click = false;
- affiliated_form2_.ssl_valid = true;
origin_path_form_.username_value = base::ASCIIToUTF16("Username 2");
origin_path_form_.display_name = base::ASCIIToUTF16("Display Name 2");
@@ -284,7 +283,7 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
const std::vector<GURL>& federations) {
bool called = false;
mojom::CredentialManagerError error;
- mojom::CredentialInfoPtr credential;
+ base::Optional<CredentialInfo> credential;
CallGet(zero_click_only, include_passwords, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _, _))
@@ -296,16 +295,16 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
EXPECT_TRUE(called);
EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
- EXPECT_EQ(mojom::CredentialType::EMPTY, credential->type);
+ EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY, credential->type);
}
void ExpectZeroClickSignInSuccess(bool zero_click_only,
bool include_passwords,
const std::vector<GURL>& federations,
- mojom::CredentialType type) {
+ CredentialType type) {
bool called = false;
mojom::CredentialManagerError error;
- mojom::CredentialInfoPtr credential;
+ base::Optional<CredentialInfo> credential;
CallGet(zero_click_only, include_passwords, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _, _))
@@ -323,10 +322,10 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
void ExpectCredentialType(bool zero_click_only,
bool include_passwords,
const std::vector<GURL>& federations,
- mojom::CredentialType type) {
+ CredentialType type) {
bool called = false;
mojom::CredentialManagerError error;
- mojom::CredentialInfoPtr credential;
+ base::Optional<CredentialInfo> credential;
CallGet(zero_click_only, include_passwords, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -342,8 +341,7 @@ class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
// Helpers for testing CredentialManagerImpl methods.
void CallStore(const CredentialInfo& info,
const CredentialManagerImpl::StoreCallback& callback) {
- mojom::CredentialInfoPtr credential = mojom::CredentialInfo::From(info);
- cm_service_impl_->Store(std::move(credential), callback);
+ cm_service_impl_->Store(info, callback);
}
void CallRequireUserMediation(
@@ -417,6 +415,7 @@ TEST_F(CredentialManagerImplTest, CredentialManagerOnStore) {
EXPECT_EQ(form_.signon_realm, new_form.signon_realm);
EXPECT_TRUE(new_form.federation_origin.unique());
EXPECT_EQ(form_.icon_url, new_form.icon_url);
+ EXPECT_FALSE(form_.skip_zero_click);
EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, new_form.scheme);
}
@@ -449,9 +448,45 @@ TEST_F(CredentialManagerImplTest, CredentialManagerOnStoreFederated) {
EXPECT_EQ(form_.signon_realm, new_form.signon_realm);
EXPECT_EQ(form_.federation_origin, new_form.federation_origin);
EXPECT_EQ(form_.icon_url, new_form.icon_url);
+ EXPECT_FALSE(form_.skip_zero_click);
EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, new_form.scheme);
}
+TEST_F(CredentialManagerImplTest, StoreFederatedAfterPassword) {
+ // Populate the PasswordStore with a form.
+ store_->AddLogin(form_);
+
+ autofill::PasswordForm federated = form_;
+ federated.password_value.clear();
+ federated.type = autofill::PasswordForm::TYPE_API;
+ federated.preferred = true;
+ federated.federation_origin = url::Origin(GURL("https://google.com/"));
+ federated.signon_realm = "federation://example.com/google.com";
+ CredentialInfo info(federated, CredentialType::CREDENTIAL_TYPE_FEDERATED);
+ EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
+ _, CredentialSourceType::CREDENTIAL_SOURCE_API));
+ EXPECT_CALL(*client_, NotifyStorePasswordCalled());
+
+ bool called = false;
+ CallStore(info, base::Bind(&RespondCallback, &called));
+
+ // Allow the PasswordFormManager to talk to the password store, determine
+ // that the form is new, and set it as pending.
+ RunAllPendingTasks();
+
+ EXPECT_TRUE(called);
+ EXPECT_TRUE(client_->pending_manager()->HasCompletedMatching());
+ client_->pending_manager()->Save();
+
+ RunAllPendingTasks();
+ TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
+ EXPECT_THAT(passwords["https://example.com/"], ElementsAre(form_));
+ federated.date_created =
+ passwords["federation://example.com/google.com"][0].date_created;
+ EXPECT_THAT(passwords["federation://example.com/google.com"],
+ ElementsAre(federated));
+}
+
TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwrite) {
// Populate the PasswordStore with a form.
store_->AddLogin(form_);
@@ -480,10 +515,6 @@ TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwrite) {
}
TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwriteZeroClick) {
- // Set the global zero click flag on, and populate the PasswordStore with a
- // form that's set to skip zero click.
- client_->set_zero_click_enabled(true);
- client_->set_first_run_seen(true);
form_.skip_zero_click = true;
store_->AddLogin(form_);
RunAllPendingTasks();
@@ -506,10 +537,6 @@ TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwriteZeroClick) {
TEST_F(CredentialManagerImplTest,
CredentialManagerFederatedStoreOverwriteZeroClick) {
- // Set the global zero click flag on, and populate the PasswordStore with a
- // form that's set to skip zero click.
- client_->set_zero_click_enabled(true);
- client_->set_first_run_seen(true);
form_.federation_origin = url::Origin(GURL("https://example.com/"));
form_.password_value = base::string16();
form_.skip_zero_click = true;
@@ -553,7 +580,7 @@ TEST_F(CredentialManagerImplTest, CredentialManagerGetOverwriteZeroClick) {
bool called = false;
mojom::CredentialManagerError error;
- mojom::CredentialInfoPtr credential;
+ base::Optional<CredentialInfo> credential;
CallGet(false, true, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -688,7 +715,8 @@ TEST_F(CredentialManagerImplTest,
.Times(testing::Exactly(0));
EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
- ExpectCredentialType(false, true, federations, mojom::CredentialType::EMPTY);
+ ExpectCredentialType(false, true, federations,
+ CredentialType::CREDENTIAL_TYPE_EMPTY);
}
TEST_F(CredentialManagerImplTest,
@@ -700,19 +728,76 @@ TEST_F(CredentialManagerImplTest,
EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
std::vector<GURL> federations;
- ExpectCredentialType(false, true, federations, mojom::CredentialType::EMPTY);
+ ExpectCredentialType(false, true, federations,
+ CredentialType::CREDENTIAL_TYPE_EMPTY);
}
TEST_F(CredentialManagerImplTest,
- CredentialManagerOnRequestCredentialWithEmptyAndNonUsernames) {
+ CredentialManagerOnRequestCredentialWithEmptyAndNonemptyUsernames) {
store_->AddLogin(form_);
autofill::PasswordForm empty = form_;
empty.username_value.clear();
store_->AddLogin(empty);
+ autofill::PasswordForm duplicate = form_;
+ duplicate.username_element = base::ASCIIToUTF16("different_username_element");
+ store_->AddLogin(duplicate);
std::vector<GURL> federations;
ExpectZeroClickSignInSuccess(false, true, federations,
- mojom::CredentialType::PASSWORD);
+ CredentialType::CREDENTIAL_TYPE_PASSWORD);
+}
+
+TEST_F(CredentialManagerImplTest,
+ CredentialManagerOnRequestCredentialWithDuplicates) {
+ // Add 8 credentials. Two buckets of duplicates, one empty username and one
+ // federated one. There should be just 3 in the account chooser.
+ form_.preferred = true;
+ form_.username_element = base::ASCIIToUTF16("username_element");
+ store_->AddLogin(form_);
+ autofill::PasswordForm empty = form_;
+ empty.username_value.clear();
+ store_->AddLogin(empty);
+ autofill::PasswordForm duplicate = form_;
+ duplicate.username_element = base::ASCIIToUTF16("username_element1");
+ duplicate.is_public_suffix_match = true;
+ store_->AddLogin(duplicate);
+ duplicate = form_;
+ duplicate.username_element = base::ASCIIToUTF16("username_element2");
+ duplicate.preferred = false;
+ store_->AddLogin(duplicate);
+
+ origin_path_form_.preferred = true;
+ store_->AddLogin(origin_path_form_);
+ duplicate = origin_path_form_;
+ duplicate.username_element = base::ASCIIToUTF16("username_element3");
+ duplicate.is_public_suffix_match = true;
+ store_->AddLogin(duplicate);
+ duplicate = origin_path_form_;
+ duplicate.username_element = base::ASCIIToUTF16("username_element4");
+ duplicate.preferred = false;
+ store_->AddLogin(duplicate);
+ autofill::PasswordForm federated = origin_path_form_;
+ federated.password_value.clear();
+ federated.federation_origin = url::Origin(GURL("https://google.com/"));
+ federated.signon_realm =
+ "federation://" + federated.origin.host() + "/google.com";
+ store_->AddLogin(federated);
+
+ EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(
+ UnorderedElementsAre(Pointee(form_),
+ Pointee(origin_path_form_),
+ Pointee(federated)),
+ testing::IsEmpty(), _, _));
+
+ bool called = false;
+ mojom::CredentialManagerError error;
+ base::Optional<CredentialInfo> credential;
+ std::vector<GURL> federations;
+ federations.push_back(GURL("https://google.com/"));
+ CallGet(false, true, federations,
+ base::Bind(&GetCredentialCallback, &called, &error, &credential));
+
+ RunAllPendingTasks();
}
TEST_F(CredentialManagerImplTest,
@@ -727,7 +812,8 @@ TEST_F(CredentialManagerImplTest,
.Times(testing::Exactly(0));
EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
- ExpectCredentialType(false, true, federations, mojom::CredentialType::EMPTY);
+ ExpectCredentialType(false, true, federations,
+ CredentialType::CREDENTIAL_TYPE_EMPTY);
}
TEST_F(CredentialManagerImplTest,
@@ -742,7 +828,7 @@ TEST_F(CredentialManagerImplTest,
bool called = false;
mojom::CredentialManagerError error;
- mojom::CredentialInfoPtr credential;
+ base::Optional<CredentialInfo> credential;
CallGet(false, true, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -762,7 +848,7 @@ TEST_F(
bool called = false;
mojom::CredentialManagerError error;
- mojom::CredentialInfoPtr credential;
+ base::Optional<CredentialInfo> credential;
CallGet(true, true, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -782,7 +868,7 @@ TEST_F(CredentialManagerImplTest,
EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
ExpectZeroClickSignInSuccess(true, true, federations,
- mojom::CredentialType::PASSWORD);
+ CredentialType::CREDENTIAL_TYPE_PASSWORD);
}
TEST_F(CredentialManagerImplTest,
@@ -810,7 +896,7 @@ TEST_F(CredentialManagerImplTest,
EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
ExpectZeroClickSignInSuccess(true, true, federations,
- mojom::CredentialType::FEDERATED);
+ CredentialType::CREDENTIAL_TYPE_FEDERATED);
}
TEST_F(CredentialManagerImplTest,
@@ -845,7 +931,7 @@ TEST_F(CredentialManagerImplTest,
// We pass in 'true' for the 'include_passwords' argument to ensure that
// password-type credentials are included as potential matches.
ExpectZeroClickSignInSuccess(true, true, federations,
- mojom::CredentialType::PASSWORD);
+ CredentialType::CREDENTIAL_TYPE_PASSWORD);
}
TEST_F(CredentialManagerImplTest,
@@ -887,7 +973,7 @@ TEST_F(CredentialManagerImplTest,
cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
ExpectZeroClickSignInSuccess(true, true, federations,
- mojom::CredentialType::FEDERATED);
+ CredentialType::CREDENTIAL_TYPE_FEDERATED);
}
TEST_F(CredentialManagerImplTest,
@@ -962,7 +1048,8 @@ TEST_F(CredentialManagerImplTest,
EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
// With two items in the password store, we shouldn't get credentials back.
- ExpectCredentialType(true, true, federations, mojom::CredentialType::EMPTY);
+ ExpectCredentialType(true, true, federations,
+ CredentialType::CREDENTIAL_TYPE_EMPTY);
}
TEST_F(CredentialManagerImplTest,
@@ -978,7 +1065,8 @@ TEST_F(CredentialManagerImplTest,
// With two items in the password store, we shouldn't get credentials back,
// even though only one item has |skip_zero_click| set |false|.
- ExpectCredentialType(true, true, federations, mojom::CredentialType::EMPTY);
+ ExpectCredentialType(true, true, federations,
+ CredentialType::CREDENTIAL_TYPE_EMPTY);
}
TEST_F(CredentialManagerImplTest,
@@ -995,7 +1083,8 @@ TEST_F(CredentialManagerImplTest,
// We only have cross-origin zero-click credentials; they should not be
// returned.
- ExpectCredentialType(true, true, federations, mojom::CredentialType::EMPTY);
+ ExpectCredentialType(true, true, federations,
+ CredentialType::CREDENTIAL_TYPE_EMPTY);
}
TEST_F(CredentialManagerImplTest,
@@ -1011,14 +1100,14 @@ TEST_F(CredentialManagerImplTest,
// 1st request.
bool called_1 = false;
mojom::CredentialManagerError error_1;
- mojom::CredentialInfoPtr credential_1;
+ base::Optional<CredentialInfo> credential_1;
CallGet(
false, true, federations,
base::Bind(&GetCredentialCallback, &called_1, &error_1, &credential_1));
// 2nd request.
bool called_2 = false;
mojom::CredentialManagerError error_2;
- mojom::CredentialInfoPtr credential_2;
+ base::Optional<CredentialInfo> credential_2;
CallGet(
false, true, federations,
base::Bind(&GetCredentialCallback, &called_2, &error_2, &credential_2));
@@ -1033,12 +1122,12 @@ TEST_F(CredentialManagerImplTest,
// Check that the second request triggered a rejection.
EXPECT_TRUE(called_2);
EXPECT_EQ(mojom::CredentialManagerError::PENDINGREQUEST, error_2);
- EXPECT_TRUE(credential_2.is_null());
+ EXPECT_FALSE(credential_2);
// Check that the first request resolves.
EXPECT_TRUE(called_1);
EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error_1);
- EXPECT_NE(mojom::CredentialType::EMPTY, credential_1->type);
+ EXPECT_NE(CredentialType::CREDENTIAL_TYPE_EMPTY, credential_1->type);
}
TEST_F(CredentialManagerImplTest, ResetSkipZeroClickAfterPrompt) {
@@ -1076,7 +1165,7 @@ TEST_F(CredentialManagerImplTest, ResetSkipZeroClickAfterPrompt) {
bool called = false;
mojom::CredentialManagerError error;
- mojom::CredentialInfoPtr credential;
+ base::Optional<CredentialInfo> credential;
CallGet(false, true, federations,
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -1112,7 +1201,7 @@ TEST_F(CredentialManagerImplTest, NoResetSkipZeroClickAfterPromptInIncognito) {
bool called = false;
mojom::CredentialManagerError error;
- mojom::CredentialInfoPtr credential;
+ base::Optional<CredentialInfo> credential;
CallGet(false, true, std::vector<GURL>(),
base::Bind(&GetCredentialCallback, &called, &error, &credential));
@@ -1134,7 +1223,8 @@ TEST_F(CredentialManagerImplTest, IncognitoZeroClickRequestCredential) {
.Times(testing::Exactly(0));
EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
- ExpectCredentialType(true, true, federations, mojom::CredentialType::EMPTY);
+ ExpectCredentialType(true, true, federations,
+ CredentialType::CREDENTIAL_TYPE_EMPTY);
}
TEST_F(CredentialManagerImplTest, ZeroClickWithAffiliatedFormInPasswordStore) {
@@ -1154,7 +1244,7 @@ TEST_F(CredentialManagerImplTest, ZeroClickWithAffiliatedFormInPasswordStore) {
cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
ExpectZeroClickSignInSuccess(true, true, federations,
- mojom::CredentialType::PASSWORD);
+ CredentialType::CREDENTIAL_TYPE_PASSWORD);
}
TEST_F(CredentialManagerImplTest,
@@ -1215,16 +1305,15 @@ TEST_F(CredentialManagerImplTest,
cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
ExpectZeroClickSignInSuccess(true, true, federations,
- mojom::CredentialType::PASSWORD);
+ CredentialType::CREDENTIAL_TYPE_PASSWORD);
}
TEST_F(CredentialManagerImplTest, GetSynthesizedFormForOrigin) {
- autofill::PasswordForm synthesized =
+ PasswordStore::FormDigest synthesized =
cm_service_impl_->GetSynthesizedFormForOrigin();
EXPECT_EQ(kTestWebOrigin, synthesized.origin.spec());
EXPECT_EQ(kTestWebOrigin, synthesized.signon_realm);
EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, synthesized.scheme);
- EXPECT_TRUE(synthesized.ssl_valid);
}
TEST_F(CredentialManagerImplTest, BlacklistPasswordCredential) {
@@ -1249,7 +1338,6 @@ TEST_F(CredentialManagerImplTest, BlacklistPasswordCredential) {
blacklisted.origin = form_.origin;
blacklisted.signon_realm = form_.signon_realm;
blacklisted.type = autofill::PasswordForm::TYPE_API;
- blacklisted.ssl_valid = true;
blacklisted.date_created = passwords[form_.signon_realm][0].date_created;
EXPECT_THAT(passwords[form_.signon_realm], testing::ElementsAre(blacklisted));
}
@@ -1280,7 +1368,6 @@ TEST_F(CredentialManagerImplTest, BlacklistFederatedCredential) {
blacklisted.origin = form_.origin;
blacklisted.signon_realm = blacklisted.origin.spec();
blacklisted.type = autofill::PasswordForm::TYPE_API;
- blacklisted.ssl_valid = true;
blacklisted.date_created =
passwords[blacklisted.signon_realm][0].date_created;
EXPECT_THAT(passwords[blacklisted.signon_realm],
@@ -1292,7 +1379,6 @@ TEST_F(CredentialManagerImplTest, RespectBlacklistingPasswordCredential) {
blacklisted.blacklisted_by_user = true;
blacklisted.origin = form_.origin;
blacklisted.signon_realm = blacklisted.origin.spec();
- blacklisted.ssl_valid = true;
store_->AddLogin(blacklisted);
CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
@@ -1312,7 +1398,6 @@ TEST_F(CredentialManagerImplTest, RespectBlacklistingFederatedCredential) {
blacklisted.blacklisted_by_user = true;
blacklisted.origin = form_.origin;
blacklisted.signon_realm = blacklisted.origin.spec();
- blacklisted.ssl_valid = true;
store_->AddLogin(blacklisted);
form_.federation_origin = url::Origin(GURL("https://example.com/"));
diff --git a/chromium/components/password_manager/content/public/cpp/BUILD.gn b/chromium/components/password_manager/content/public/cpp/BUILD.gn
deleted file mode 100644
index 4b0f814dfd4..00000000000
--- a/chromium/components/password_manager/content/public/cpp/BUILD.gn
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("cpp") {
- sources = [
- "type_converters.cc",
- "type_converters.h",
- ]
-
- public_deps = [
- "../interfaces",
- ]
-
- deps = [
- "//base",
- "//components/password_manager/core/common",
- "//mojo/common:common_base",
- "//mojo/public/cpp/bindings",
- "//third_party/WebKit/public:blink_headers",
- ]
-}
diff --git a/chromium/components/password_manager/content/public/cpp/OWNERS b/chromium/components/password_manager/content/public/cpp/OWNERS
new file mode 100644
index 00000000000..bb6511619b7
--- /dev/null
+++ b/chromium/components/password_manager/content/public/cpp/OWNERS
@@ -0,0 +1,2 @@
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/password_manager/content/public/cpp/credential_manager.typemap b/chromium/components/password_manager/content/public/cpp/credential_manager.typemap
new file mode 100644
index 00000000000..19d3c474545
--- /dev/null
+++ b/chromium/components/password_manager/content/public/cpp/credential_manager.typemap
@@ -0,0 +1,20 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//components/password_manager/content/public/interfaces/credential_manager.mojom"
+public_headers =
+ [ "//components/password_manager/core/common/credential_manager_types.h" ]
+traits_headers = [ "//components/password_manager/content/public/cpp/credential_manager_struct_traits.h" ]
+sources = [
+ "//components/password_manager/content/public/cpp/credential_manager_struct_traits.cc",
+]
+deps = [
+ "//base",
+ "//components/password_manager/core/common",
+]
+
+type_mappings = [
+ "password_manager.mojom.CredentialType=password_manager::CredentialType",
+ "password_manager.mojom.CredentialInfo=password_manager::CredentialInfo",
+]
diff --git a/chromium/components/password_manager/content/public/cpp/credential_manager_struct_traits.cc b/chromium/components/password_manager/content/public/cpp/credential_manager_struct_traits.cc
new file mode 100644
index 00000000000..1b780069f4a
--- /dev/null
+++ b/chromium/components/password_manager/content/public/cpp/credential_manager_struct_traits.cc
@@ -0,0 +1,64 @@
+// 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 "components/password_manager/content/public/cpp/credential_manager_struct_traits.h"
+
+#include "url/mojo/origin_struct_traits.h"
+#include "url/mojo/url_gurl_struct_traits.h"
+
+using namespace password_manager;
+
+namespace mojo {
+
+// static
+mojom::CredentialType
+EnumTraits<mojom::CredentialType, CredentialType>::ToMojom(
+ CredentialType input) {
+ switch (input) {
+ case CredentialType::CREDENTIAL_TYPE_EMPTY:
+ return mojom::CredentialType::EMPTY;
+ case CredentialType::CREDENTIAL_TYPE_PASSWORD:
+ return mojom::CredentialType::PASSWORD;
+ case CredentialType::CREDENTIAL_TYPE_FEDERATED:
+ return mojom::CredentialType::FEDERATED;
+ }
+
+ NOTREACHED();
+ return mojom::CredentialType::EMPTY;
+}
+
+// static
+bool EnumTraits<mojom::CredentialType, CredentialType>::FromMojom(
+ mojom::CredentialType input,
+ CredentialType* output) {
+ switch (input) {
+ case mojom::CredentialType::EMPTY:
+ *output = CredentialType::CREDENTIAL_TYPE_EMPTY;
+ return true;
+ case mojom::CredentialType::PASSWORD:
+ *output = CredentialType::CREDENTIAL_TYPE_PASSWORD;
+ return true;
+ case mojom::CredentialType::FEDERATED:
+ *output = CredentialType::CREDENTIAL_TYPE_FEDERATED;
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+// static
+bool StructTraits<mojom::CredentialInfoDataView, CredentialInfo>::Read(
+ mojom::CredentialInfoDataView data,
+ CredentialInfo* out) {
+ if (data.ReadType(&out->type) && data.ReadId(&out->id) &&
+ data.ReadName(&out->name) && data.ReadIcon(&out->icon) &&
+ data.ReadPassword(&out->password) &&
+ data.ReadFederation(&out->federation))
+ return true;
+
+ return false;
+}
+
+} // namespace mojo
diff --git a/chromium/components/password_manager/content/public/cpp/credential_manager_struct_traits.h b/chromium/components/password_manager/content/public/cpp/credential_manager_struct_traits.h
new file mode 100644
index 00000000000..b8415b26ca5
--- /dev/null
+++ b/chromium/components/password_manager/content/public/cpp/credential_manager_struct_traits.h
@@ -0,0 +1,60 @@
+// 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 COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_CREDENTIAL_MANAGER_STRUCT_TRAITS_H_
+#define COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_CREDENTIAL_MANAGER_STRUCT_TRAITS_H_
+
+#include "base/strings/string16.h"
+#include "components/password_manager/content/public/interfaces/credential_manager.mojom.h"
+#include "components/password_manager/core/common/credential_manager_types.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<password_manager::mojom::CredentialType,
+ password_manager::CredentialType> {
+ static password_manager::mojom::CredentialType ToMojom(
+ password_manager::CredentialType input);
+ static bool FromMojom(password_manager::mojom::CredentialType input,
+ password_manager::CredentialType* output);
+};
+
+template <>
+struct StructTraits<password_manager::mojom::CredentialInfoDataView,
+ password_manager::CredentialInfo> {
+ static password_manager::CredentialType type(
+ const password_manager::CredentialInfo& r) {
+ return r.type;
+ }
+
+ static const base::string16& id(const password_manager::CredentialInfo& r) {
+ return r.id;
+ }
+
+ static const base::string16& name(const password_manager::CredentialInfo& r) {
+ return r.name;
+ }
+
+ static const GURL& icon(const password_manager::CredentialInfo& r) {
+ return r.icon;
+ }
+
+ static const base::string16& password(
+ const password_manager::CredentialInfo& r) {
+ return r.password;
+ }
+
+ static const url::Origin& federation(
+ const password_manager::CredentialInfo& r) {
+ return r.federation;
+ }
+
+ static bool Read(password_manager::mojom::CredentialInfoDataView data,
+ password_manager::CredentialInfo* out);
+};
+
+} // namespace mojo
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_CREDENTIAL_MANAGER_STRUCT_TRAITS_H_
diff --git a/chromium/components/password_manager/content/public/cpp/type_converters.cc b/chromium/components/password_manager/content/public/cpp/type_converters.cc
deleted file mode 100644
index 3c4b2af4cfc..00000000000
--- a/chromium/components/password_manager/content/public/cpp/type_converters.cc
+++ /dev/null
@@ -1,127 +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 "components/password_manager/content/public/cpp/type_converters.h"
-
-#include "base/logging.h"
-#include "components/password_manager/core/common/credential_manager_types.h"
-#include "mojo/common/common_type_converters.h"
-#include "third_party/WebKit/public/platform/WebCredential.h"
-#include "third_party/WebKit/public/platform/WebFederatedCredential.h"
-#include "third_party/WebKit/public/platform/WebPasswordCredential.h"
-
-using namespace password_manager;
-
-namespace mojo {
-
-namespace {
-
-mojom::CredentialType CMCredentialTypeToMojo(CredentialType type) {
- switch (type) {
- case CredentialType::CREDENTIAL_TYPE_EMPTY:
- return mojom::CredentialType::EMPTY;
- case CredentialType::CREDENTIAL_TYPE_PASSWORD:
- return mojom::CredentialType::PASSWORD;
- case CredentialType::CREDENTIAL_TYPE_FEDERATED:
- return mojom::CredentialType::FEDERATED;
- }
-
- NOTREACHED();
- return mojom::CredentialType::EMPTY;
-}
-
-CredentialType MojoCredentialTypeToCM(mojom::CredentialType type) {
- switch (type) {
- case mojom::CredentialType::EMPTY:
- return CredentialType::CREDENTIAL_TYPE_EMPTY;
- case mojom::CredentialType::PASSWORD:
- return CredentialType::CREDENTIAL_TYPE_PASSWORD;
- case mojom::CredentialType::FEDERATED:
- return CredentialType::CREDENTIAL_TYPE_FEDERATED;
- }
-
- NOTREACHED();
- return CredentialType::CREDENTIAL_TYPE_EMPTY;
-}
-
-} // namespace
-
-mojom::CredentialInfoPtr
-TypeConverter<mojom::CredentialInfoPtr, CredentialInfo>::Convert(
- const CredentialInfo& input) {
- mojom::CredentialInfoPtr output(mojom::CredentialInfo::New());
- output->type = CMCredentialTypeToMojo(input.type);
- output->id = mojo::String::From(input.id);
- output->name = mojo::String::From(input.name);
- output->icon = input.icon;
- output->password = mojo::String::From(input.password);
- output->federation = input.federation;
-
- return output;
-}
-
-CredentialInfo TypeConverter<CredentialInfo, mojom::CredentialInfoPtr>::Convert(
- const mojom::CredentialInfoPtr& input) {
- CredentialInfo output;
- output.type = MojoCredentialTypeToCM(input->type);
- output.id = input->id.To<base::string16>();
- output.name = input->name.To<base::string16>();
- output.icon = input->icon;
- output.password = input->password.To<base::string16>();
- output.federation = input->federation;
-
- return output;
-}
-
-mojom::CredentialInfoPtr
-TypeConverter<mojom::CredentialInfoPtr, blink::WebCredential>::Convert(
- const blink::WebCredential& input) {
- mojom::CredentialInfoPtr output(mojom::CredentialInfo::New());
-
- if (input.isPasswordCredential()) {
- // blink::WebPasswordCredential
- output->type = mojom::CredentialType::PASSWORD;
- output->password = mojo::String::From(base::string16(
- static_cast<const blink::WebPasswordCredential&>(input).password()));
- } else {
- DCHECK(input.isFederatedCredential());
- // blink::WebFederatedCredential
- output->type = mojom::CredentialType::FEDERATED;
- output->federation =
- static_cast<const blink::WebFederatedCredential&>(input).provider();
- }
- output->id = mojo::String::From(base::string16(input.id()));
- output->name = mojo::String::From(base::string16(input.name()));
- output->icon = input.iconURL();
-
- return output;
-}
-
-std::unique_ptr<blink::WebCredential> TypeConverter<
- std::unique_ptr<blink::WebCredential>,
- mojom::CredentialInfoPtr>::Convert(const mojom::CredentialInfoPtr& input) {
- std::unique_ptr<blink::WebCredential> output;
-
- switch (input->type) {
- case mojom::CredentialType::PASSWORD:
- output.reset(new blink::WebPasswordCredential(
- input->id.To<base::string16>(), input->password.To<base::string16>(),
- input->name.To<base::string16>(), input->icon));
- break;
- case mojom::CredentialType::FEDERATED:
- output.reset(new blink::WebFederatedCredential(
- input->id.To<base::string16>(), input->federation,
- input->name.To<base::string16>(), input->icon));
- break;
- case mojom::CredentialType::EMPTY:
- // Intentionally empty, return nullptr.
- break;
- default:
- NOTREACHED();
- }
-
- return output;
-}
-
-} // namespace mojo
diff --git a/chromium/components/password_manager/content/public/cpp/type_converters.h b/chromium/components/password_manager/content/public/cpp/type_converters.h
deleted file mode 100644
index 4ac7d563f9b..00000000000
--- a/chromium/components/password_manager/content/public/cpp/type_converters.h
+++ /dev/null
@@ -1,52 +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 COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_TYPE_CONVERTERS_IMPL_H_
-#define COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_TYPE_CONVERTERS_IMPL_H_
-
-#include <memory>
-
-#include "components/password_manager/content/public/interfaces/credential_manager.mojom.h"
-
-namespace blink {
-class WebCredential;
-}
-
-namespace password_manager {
-struct CredentialInfo;
-}
-
-namespace mojo {
-
-template <>
-struct TypeConverter<password_manager::mojom::CredentialInfoPtr,
- password_manager::CredentialInfo> {
- static password_manager::mojom::CredentialInfoPtr Convert(
- const password_manager::CredentialInfo& input);
-};
-
-template <>
-struct TypeConverter<password_manager::CredentialInfo,
- password_manager::mojom::CredentialInfoPtr> {
- static password_manager::CredentialInfo Convert(
- const password_manager::mojom::CredentialInfoPtr& input);
-};
-
-template <>
-struct TypeConverter<password_manager::mojom::CredentialInfoPtr,
- blink::WebCredential> {
- static password_manager::mojom::CredentialInfoPtr Convert(
- const blink::WebCredential& input);
-};
-
-template <>
-struct TypeConverter<std::unique_ptr<blink::WebCredential>,
- password_manager::mojom::CredentialInfoPtr> {
- static std::unique_ptr<blink::WebCredential> Convert(
- const password_manager::mojom::CredentialInfoPtr& input);
-};
-
-} // namespace mojo
-
-#endif // COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_TYPE_CONVERTERS_IMPL_H_
diff --git a/chromium/components/password_manager/content/public/interfaces/credential_manager.mojom b/chromium/components/password_manager/content/public/interfaces/credential_manager.mojom
index 6b4fe3ee01d..cc4981d8bc8 100644
--- a/chromium/components/password_manager/content/public/interfaces/credential_manager.mojom
+++ b/chromium/components/password_manager/content/public/interfaces/credential_manager.mojom
@@ -22,11 +22,11 @@ enum CredentialManagerError {
};
struct CredentialInfo {
- CredentialType type = EMPTY;
- string id = "";
- string name = "";
+ CredentialType type;
+ string id;
+ string name;
url.mojom.Url icon;
- string password = "";
+ string password;
url.mojom.Origin federation;
};
diff --git a/chromium/components/password_manager/content/renderer/BUILD.gn b/chromium/components/password_manager/content/renderer/BUILD.gn
index f4e0e50a33b..ea5534db9b0 100644
--- a/chromium/components/password_manager/content/renderer/BUILD.gn
+++ b/chromium/components/password_manager/content/renderer/BUILD.gn
@@ -10,7 +10,7 @@ static_library("renderer") {
deps = [
"//base",
- "//components/password_manager/content/public/cpp",
+ "//components/password_manager/content/public/interfaces",
"//components/password_manager/core/common",
"//components/strings",
"//content/public/common",
diff --git a/chromium/components/password_manager/content/renderer/DEPS b/chromium/components/password_manager/content/renderer/DEPS
index f22d849fc8e..30989a177f6 100644
--- a/chromium/components/password_manager/content/renderer/DEPS
+++ b/chromium/components/password_manager/content/renderer/DEPS
@@ -2,7 +2,6 @@ include_rules = [
"+content/public/common",
"+content/public/renderer",
"+content/test",
- "+mojo/public",
"+services/shell/public/cpp",
"+third_party/WebKit/public/platform",
"+third_party/WebKit/public/web",
diff --git a/chromium/components/password_manager/content/renderer/credential_manager_client.cc b/chromium/components/password_manager/content/renderer/credential_manager_client.cc
index 5aa87be8726..3d0c250d669 100644
--- a/chromium/components/password_manager/content/renderer/credential_manager_client.cc
+++ b/chromium/components/password_manager/content/renderer/credential_manager_client.cc
@@ -11,7 +11,7 @@
#include "base/bind.h"
#include "base/logging.h"
-#include "components/password_manager/content/public/cpp/type_converters.h"
+#include "base/memory/ptr_util.h"
#include "components/password_manager/core/common/credential_manager_types.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
@@ -26,6 +26,41 @@ namespace password_manager {
namespace {
+void WebCredentialToCredentialInfo(const blink::WebCredential& credential,
+ CredentialInfo* out) {
+ out->id = credential.id();
+ out->name = credential.name();
+ out->icon = credential.iconURL();
+ if (credential.isPasswordCredential()) {
+ out->type = CredentialType::CREDENTIAL_TYPE_PASSWORD;
+ out->password =
+ static_cast<const blink::WebPasswordCredential&>(credential).password();
+ } else {
+ DCHECK(credential.isFederatedCredential());
+ out->type = CredentialType::CREDENTIAL_TYPE_FEDERATED;
+ out->federation =
+ static_cast<const blink::WebFederatedCredential&>(credential)
+ .provider();
+ }
+}
+
+std::unique_ptr<blink::WebCredential> CredentialInfoToWebCredential(
+ const CredentialInfo& info) {
+ switch (info.type) {
+ case CredentialType::CREDENTIAL_TYPE_FEDERATED:
+ return base::MakeUnique<blink::WebFederatedCredential>(
+ info.id, info.federation, info.name, info.icon);
+ case CredentialType::CREDENTIAL_TYPE_PASSWORD:
+ return base::MakeUnique<blink::WebPasswordCredential>(
+ info.id, info.password, info.name, info.icon);
+ case CredentialType::CREDENTIAL_TYPE_EMPTY:
+ return nullptr;
+ }
+
+ NOTREACHED();
+ return nullptr;
+}
+
blink::WebCredentialManagerError GetWebCredentialManagerErrorFromMojo(
mojom::CredentialManagerError error) {
switch (error) {
@@ -96,7 +131,7 @@ class RequestCallbacksWrapper {
~RequestCallbacksWrapper();
- void NotifySuccess(mojom::CredentialInfoPtr info);
+ void NotifySuccess(const CredentialInfo& info);
void NotifyError(mojom::CredentialManagerError error);
@@ -116,13 +151,11 @@ RequestCallbacksWrapper::~RequestCallbacksWrapper() {
callbacks_->onError(blink::WebCredentialManagerUnknownError);
}
-void RequestCallbacksWrapper::NotifySuccess(mojom::CredentialInfoPtr info) {
+void RequestCallbacksWrapper::NotifySuccess(const CredentialInfo& info) {
// Call onSuccess() and reset callbacks to avoid calling onError() in
// destructor.
if (callbacks_) {
- std::unique_ptr<blink::WebCredential> credential =
- info.To<std::unique_ptr<blink::WebCredential>>();
- callbacks_->onSuccess(std::move(credential));
+ callbacks_->onSuccess(CredentialInfoToWebCredential(info));
callbacks_.reset();
}
}
@@ -141,12 +174,12 @@ void RespondToNotificationCallback(
void RespondToRequestCallback(RequestCallbacksWrapper* callbacks_wrapper,
mojom::CredentialManagerError error,
- mojom::CredentialInfoPtr info) {
+ const base::Optional<CredentialInfo>& info) {
if (error == mojom::CredentialManagerError::SUCCESS) {
- DCHECK(!info.is_null());
- callbacks_wrapper->NotifySuccess(std::move(info));
+ DCHECK(info);
+ callbacks_wrapper->NotifySuccess(*info);
} else {
- DCHECK(info.is_null());
+ DCHECK(!info);
callbacks_wrapper->NotifyError(error);
}
}
@@ -170,9 +203,10 @@ void CredentialManagerClient::dispatchStore(
DCHECK(callbacks);
ConnectToMojoCMIfNeeded();
- mojom::CredentialInfoPtr info = mojom::CredentialInfo::From(credential);
+ CredentialInfo info;
+ WebCredentialToCredentialInfo(credential, &info);
mojo_cm_service_->Store(
- std::move(info),
+ info,
base::Bind(&RespondToNotificationCallback,
base::Owned(new NotificationCallbacksWrapper(callbacks))));
}
@@ -200,7 +234,7 @@ void CredentialManagerClient::dispatchGet(
federation_vector.push_back(federations[i]);
mojo_cm_service_->Get(
- zero_click_only, include_passwords, std::move(federation_vector),
+ zero_click_only, include_passwords, federation_vector,
base::Bind(&RespondToRequestCallback,
base::Owned(new RequestCallbacksWrapper(callbacks))));
}
diff --git a/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc b/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
index 83c54441bf0..1ef52813e05 100644
--- a/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
+++ b/chromium/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
@@ -42,7 +42,7 @@ class FakeCredentialManager : public mojom::CredentialManager {
private:
// mojom::CredentialManager methods:
- void Store(mojom::CredentialInfoPtr credential,
+ void Store(const CredentialInfo& credential,
const StoreCallback& callback) override {
callback.Run();
}
@@ -54,20 +54,19 @@ class FakeCredentialManager : public mojom::CredentialManager {
void Get(bool zero_click_only,
bool include_passwords,
- mojo::Array<GURL> federations,
+ const std::vector<GURL>& federations,
const GetCallback& callback) override {
const std::string& url = federations[0].spec();
if (url == kTestCredentialPassword) {
- mojom::CredentialInfoPtr info = mojom::CredentialInfo::New();
- info->type = mojom::CredentialType::PASSWORD;
- callback.Run(mojom::CredentialManagerError::SUCCESS, std::move(info));
+ CredentialInfo info;
+ info.type = CredentialType::CREDENTIAL_TYPE_PASSWORD;
+ callback.Run(mojom::CredentialManagerError::SUCCESS, info);
} else if (url == kTestCredentialEmpty) {
- callback.Run(mojom::CredentialManagerError::SUCCESS,
- mojom::CredentialInfo::New());
+ callback.Run(mojom::CredentialManagerError::SUCCESS, CredentialInfo());
} else if (url == kTestCredentialReject) {
callback.Run(mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE,
- nullptr);
+ base::nullopt);
}
}
diff --git a/chromium/components/password_manager/core/browser/BUILD.gn b/chromium/components/password_manager/core/browser/BUILD.gn
index 145ad672543..fdc195891f3 100644
--- a/chromium/components/password_manager/core/browser/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/BUILD.gn
@@ -8,7 +8,7 @@ if (is_android) {
import("//build/config/android/config.gni")
}
-source_set("browser") {
+static_library("browser") {
sources = [
"affiliated_match_helper.cc",
"affiliated_match_helper.h",
@@ -28,6 +28,8 @@ source_set("browser") {
"affiliation_utils.h",
"browser_save_password_progress_logger.cc",
"browser_save_password_progress_logger.h",
+ "credential_manager_logger.cc",
+ "credential_manager_logger.h",
"credential_manager_password_form_manager.cc",
"credential_manager_password_form_manager.h",
"credential_manager_pending_request_task.cc",
@@ -44,6 +46,9 @@ source_set("browser") {
"facet_manager.cc",
"facet_manager.h",
"facet_manager_host.h",
+ "form_fetcher.h",
+ "form_fetcher_impl.cc",
+ "form_fetcher_impl.h",
"form_saver.h",
"form_saver_impl.cc",
"form_saver_impl.h",
@@ -108,6 +113,8 @@ source_set("browser") {
"password_ui_utils.h",
"psl_matching_helper.cc",
"psl_matching_helper.h",
+ "sql_table_builder.cc",
+ "sql_table_builder.h",
"statistics_table.cc",
"statistics_table.h",
"test_affiliation_fetcher_factory.h",
@@ -120,7 +127,7 @@ source_set("browser") {
public_deps = [
"//base",
- "//sync",
+ "//components/sync",
]
deps = [
":proto",
@@ -135,7 +142,7 @@ source_set("browser") {
"//components/pref_registry",
"//components/prefs",
"//components/strings",
- "//components/sync_driver",
+ "//components/sync",
"//components/url_formatter",
"//components/variations",
"//components/webdata/common",
@@ -163,7 +170,7 @@ proto_library("proto") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"fake_affiliation_api.cc",
@@ -178,6 +185,8 @@ source_set("test_support") {
"mock_password_store.h",
"password_manager_test_utils.cc",
"password_manager_test_utils.h",
+ "stub_credentials_filter.cc",
+ "stub_credentials_filter.h",
"stub_form_saver.h",
"stub_log_manager.cc",
"stub_log_manager.h",
@@ -214,6 +223,7 @@ bundle_data("unit_tests_bundle_data") {
"//components/test/data/password_manager/login_db_v15.sql",
"//components/test/data/password_manager/login_db_v16.sql",
"//components/test/data/password_manager/login_db_v17.sql",
+ "//components/test/data/password_manager/login_db_v18.sql",
"//components/test/data/password_manager/login_db_v1_broken.sql",
"//components/test/data/password_manager/login_db_v2.sql",
"//components/test/data/password_manager/login_db_v2_broken.sql",
@@ -244,10 +254,12 @@ source_set("unit_tests") {
"affiliation_service_unittest.cc",
"affiliation_utils_unittest.cc",
"browser_save_password_progress_logger_unittest.cc",
+ "credential_manager_logger_unittest.cc",
"export/csv_writer_unittest.cc",
"export/password_csv_writer_unittest.cc",
"export/password_exporter_unittest.cc",
"facet_manager_unittest.cc",
+ "form_fetcher_impl_unittest.cc",
"form_saver_impl_unittest.cc",
"import/csv_reader_unittest.cc",
"import/password_csv_reader_unittest.cc",
@@ -269,6 +281,7 @@ source_set("unit_tests") {
"password_syncable_service_unittest.cc",
"password_ui_utils_unittest.cc",
"psl_matching_helper_unittest.cc",
+ "sql_table_builder_unittest.cc",
"statistics_table_unittest.cc",
]
if (is_mac) {
@@ -286,11 +299,11 @@ source_set("unit_tests") {
"//components/password_manager/core/common",
"//components/prefs:test_support",
"//components/strings",
- "//components/sync_driver:test_support",
+ "//components/sync:test_support_sync_api",
+ "//components/sync:test_support_sync_driver",
"//components/variations",
"//net:test_support",
"//sql:test_support",
- "//sync:test_support_sync_api",
"//testing/gmock",
"//testing/gtest",
"//ui/base",
diff --git a/chromium/components/password_manager/core/browser/DEPS b/chromium/components/password_manager/core/browser/DEPS
index 593c27c2ac4..b95f832fbfc 100644
--- a/chromium/components/password_manager/core/browser/DEPS
+++ b/chromium/components/password_manager/core/browser/DEPS
@@ -2,7 +2,7 @@ include_rules = [
"+components/autofill/core/browser",
"+components/keyed_service/core",
"+components/pref_registry",
- "+components/sync_driver",
+ "+components/sync/driver",
"+components/url_formatter",
"+components/variations",
"+components/webdata/common",
diff --git a/chromium/components/password_manager/core/browser/affiliated_match_helper.cc b/chromium/components/password_manager/core/browser/affiliated_match_helper.cc
index dc56945a33c..191edb36d95 100644
--- a/chromium/components/password_manager/core/browser/affiliated_match_helper.cc
+++ b/chromium/components/password_manager/core/browser/affiliated_match_helper.cc
@@ -58,7 +58,7 @@ void AffiliatedMatchHelper::Initialize() {
}
void AffiliatedMatchHelper::GetAffiliatedAndroidRealms(
- const autofill::PasswordForm& observed_form,
+ const PasswordStore::FormDigest& observed_form,
const AffiliatedRealmsCallback& result_callback) {
if (IsValidWebCredential(observed_form)) {
FacetURI facet_uri(
@@ -73,7 +73,7 @@ void AffiliatedMatchHelper::GetAffiliatedAndroidRealms(
}
void AffiliatedMatchHelper::GetAffiliatedWebRealms(
- const autofill::PasswordForm& android_form,
+ const PasswordStore::FormDigest& android_form,
const AffiliatedRealmsCallback& result_callback) {
if (IsValidAndroidCredential(android_form)) {
affiliation_service_->GetAffiliations(
@@ -87,12 +87,12 @@ void AffiliatedMatchHelper::GetAffiliatedWebRealms(
}
void AffiliatedMatchHelper::InjectAffiliatedWebRealms(
- ScopedVector<autofill::PasswordForm> forms,
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
const PasswordFormsCallback& result_callback) {
std::vector<autofill::PasswordForm*> android_credentials;
- for (auto* form : forms) {
- if (IsValidAndroidCredential(*form))
- android_credentials.push_back(form);
+ for (const auto& form : forms) {
+ if (IsValidAndroidCredential(PasswordStore::FormDigest(*form)))
+ android_credentials.push_back(form.get());
}
base::Closure on_get_all_realms(
base::Bind(result_callback, base::Passed(&forms)));
@@ -131,16 +131,16 @@ void AffiliatedMatchHelper::TrimAffiliationCache() {
// static
bool AffiliatedMatchHelper::IsValidAndroidCredential(
- const autofill::PasswordForm& form) {
+ const PasswordStore::FormDigest& form) {
return form.scheme == autofill::PasswordForm::SCHEME_HTML &&
IsValidAndroidFacetURI(form.signon_realm);
}
// static
bool AffiliatedMatchHelper::IsValidWebCredential(
- const autofill::PasswordForm& form) {
+ const PasswordStore::FormDigest& form) {
FacetURI facet_uri(FacetURI::FromPotentiallyInvalidSpec(form.signon_realm));
- return form.scheme == autofill::PasswordForm::SCHEME_HTML && form.ssl_valid &&
+ return form.scheme == autofill::PasswordForm::SCHEME_HTML &&
facet_uri.IsValidWebFacetURI();
}
@@ -217,8 +217,8 @@ void AffiliatedMatchHelper::OnLoginsChanged(
}
void AffiliatedMatchHelper::OnGetPasswordStoreResults(
- ScopedVector<autofill::PasswordForm> results) {
- for (autofill::PasswordForm* form : results) {
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+ for (const auto& form : results) {
FacetURI facet_uri;
if (IsAndroidApplicationCredential(*form, &facet_uri))
affiliation_service_->Prefetch(facet_uri, base::Time::Max());
diff --git a/chromium/components/password_manager/core/browser/affiliated_match_helper.h b/chromium/components/password_manager/core/browser/affiliated_match_helper.h
index a72268f8636..35d31a6256f 100644
--- a/chromium/components/password_manager/core/browser/affiliated_match_helper.h
+++ b/chromium/components/password_manager/core/browser/affiliated_match_helper.h
@@ -14,7 +14,6 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
#include "components/password_manager/core/browser/affiliation_utils.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
@@ -54,7 +53,8 @@ class AffiliatedMatchHelper : public PasswordStore::Observer,
typedef base::Callback<void(const std::vector<std::string>&)>
AffiliatedRealmsCallback;
- typedef base::Callback<void(ScopedVector<autofill::PasswordForm>)>
+ typedef base::Callback<void(
+ std::vector<std::unique_ptr<autofill::PasswordForm>>)>
PasswordFormsCallback;
// The |password_store| must outlive |this|. Both arguments must be non-NULL,
@@ -71,7 +71,7 @@ class AffiliatedMatchHelper : public PasswordStore::Observer,
// |observed_form| if it is web-based. Otherwise, yields the empty list. The
// |result_callback| will be invoked in both cases, on the same thread.
virtual void GetAffiliatedAndroidRealms(
- const autofill::PasswordForm& observed_form,
+ const PasswordStore::FormDigest& observed_form,
const AffiliatedRealmsCallback& result_callback);
// Retrieves realms of web sites affiliated with the Android application that
@@ -82,7 +82,7 @@ class AffiliatedMatchHelper : public PasswordStore::Observer,
// long as the |android_form| is from the PasswordStore, this should rarely
// happen as affiliation information for those applications are prefetched.
virtual void GetAffiliatedWebRealms(
- const autofill::PasswordForm& android_form,
+ const PasswordStore::FormDigest& android_form,
const AffiliatedRealmsCallback& result_callback);
// Retrieves realms of web sites affiliated with the Android credentials in
@@ -91,18 +91,18 @@ class AffiliatedMatchHelper : public PasswordStore::Observer,
// NOTE: This will not issue an on-demand network request. If a request to
// cache fails, no web realm will be injected into corresponding form.
virtual void InjectAffiliatedWebRealms(
- ScopedVector<autofill::PasswordForm> forms,
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
const PasswordFormsCallback& result_callback);
// Removes cached affiliation data that is no longer needed.
void TrimAffiliationCache();
// Returns whether or not |form| represents an Android credential.
- static bool IsValidAndroidCredential(const autofill::PasswordForm& form);
+ static bool IsValidAndroidCredential(const PasswordStore::FormDigest& form);
// Returns whether or not |form| represents a valid Web credential for the
// purposes of affiliation-based matching.
- static bool IsValidWebCredential(const autofill::PasswordForm& form);
+ static bool IsValidWebCredential(const PasswordStore::FormDigest& form);
// Sets the task runner to be used to delay I/O heavy initialization. Should
// be called before Initialize(). Used only for testing.
@@ -151,7 +151,7 @@ class AffiliatedMatchHelper : public PasswordStore::Observer,
// PasswordStoreConsumer:
void OnGetPasswordStoreResults(
- ScopedVector<autofill::PasswordForm> results) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
PasswordStore* const password_store_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_waiting_;
diff --git a/chromium/components/password_manager/core/browser/affiliated_match_helper_unittest.cc b/chromium/components/password_manager/core/browser/affiliated_match_helper_unittest.cc
index 79694ffc16b..acca937aeed 100644
--- a/chromium/components/password_manager/core/browser/affiliated_match_helper_unittest.cc
+++ b/chromium/components/password_manager/core/browser/affiliated_match_helper_unittest.cc
@@ -10,6 +10,7 @@
#include <utility>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -144,7 +145,6 @@ autofill::PasswordForm GetTestAndroidCredentials(const char* signon_realm) {
form.signon_realm = signon_realm;
form.username_value = base::ASCIIToUTF16(kTestUsername);
form.password_value = base::ASCIIToUTF16(kTestPassword);
- form.ssl_valid = true;
return form;
}
@@ -155,15 +155,10 @@ autofill::PasswordForm GetTestBlacklistedAndroidCredentials(
return form;
}
-autofill::PasswordForm GetTestObservedWebForm(const char* signon_realm,
- const char* origin) {
- autofill::PasswordForm form;
- form.scheme = autofill::PasswordForm::SCHEME_HTML;
- form.signon_realm = signon_realm;
- if (origin)
- form.origin = GURL(origin);
- form.ssl_valid = true;
- return form;
+PasswordStore::FormDigest GetTestObservedWebForm(const char* signon_realm,
+ const char* origin) {
+ return {autofill::PasswordForm::SCHEME_HTML, signon_realm,
+ origin ? GURL(origin) : GURL()};
}
} // namespace
@@ -255,7 +250,7 @@ class AffiliatedMatchHelperTest : public testing::Test {
}
std::vector<std::string> GetAffiliatedAndroidRealms(
- const autofill::PasswordForm& observed_form) {
+ const PasswordStore::FormDigest& observed_form) {
expecting_result_callback_ = true;
match_helper()->GetAffiliatedAndroidRealms(
observed_form,
@@ -267,7 +262,7 @@ class AffiliatedMatchHelperTest : public testing::Test {
}
std::vector<std::string> GetAffiliatedWebRealms(
- const autofill::PasswordForm& android_form) {
+ const PasswordStore::FormDigest& android_form) {
expecting_result_callback_ = true;
match_helper()->GetAffiliatedWebRealms(
android_form,
@@ -278,8 +273,9 @@ class AffiliatedMatchHelperTest : public testing::Test {
return last_result_realms_;
}
- ScopedVector<autofill::PasswordForm> InjectAffiliatedWebRealms(
- ScopedVector<autofill::PasswordForm> forms) {
+ std::vector<std::unique_ptr<autofill::PasswordForm>>
+ InjectAffiliatedWebRealms(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
expecting_result_callback_ = true;
match_helper()->InjectAffiliatedWebRealms(
std::move(forms),
@@ -312,7 +308,8 @@ class AffiliatedMatchHelperTest : public testing::Test {
last_result_realms_ = affiliated_realms;
}
- void OnFormsCallback(ScopedVector<autofill::PasswordForm> forms) {
+ void OnFormsCallback(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
EXPECT_TRUE(expecting_result_callback_);
expecting_result_callback_ = false;
last_result_forms_.swap(forms);
@@ -340,7 +337,7 @@ class AffiliatedMatchHelperTest : public testing::Test {
scoped_refptr<base::TestSimpleTaskRunner> waiting_task_runner_;
base::MessageLoop message_loop_;
std::vector<std::string> last_result_realms_;
- ScopedVector<autofill::PasswordForm> last_result_forms_;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> last_result_forms_;
bool expecting_result_callback_;
scoped_refptr<TestPasswordStore> password_store_;
@@ -360,9 +357,8 @@ TEST_F(AffiliatedMatchHelperTest, GetAffiliatedAndroidRealmsYieldsResults) {
mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
FacetURI::FromCanonicalSpec(kTestWebFacetURIBeta1),
StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
- autofill::PasswordForm web_observed_form(
- GetTestObservedWebForm(kTestWebRealmBeta1, nullptr));
- EXPECT_THAT(GetAffiliatedAndroidRealms(web_observed_form),
+ EXPECT_THAT(GetAffiliatedAndroidRealms(
+ GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)),
testing::UnorderedElementsAre(kTestAndroidRealmBeta2,
kTestAndroidRealmBeta3));
}
@@ -372,25 +368,15 @@ TEST_F(AffiliatedMatchHelperTest,
mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1),
StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha());
- autofill::PasswordForm web_observed_form(
- GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr));
// This verifies that |kTestWebRealmAlpha2| is not returned.
- EXPECT_THAT(GetAffiliatedAndroidRealms(web_observed_form),
+ EXPECT_THAT(GetAffiliatedAndroidRealms(
+ GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr)),
testing::UnorderedElementsAre(kTestAndroidRealmAlpha3));
}
TEST_F(AffiliatedMatchHelperTest,
- GetAffiliatedAndroidRealmsYieldsEmptyResultsForInsecureForms) {
- autofill::PasswordForm insecure_observed_form(
- GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr));
- insecure_observed_form.ssl_valid = false;
- EXPECT_THAT(GetAffiliatedAndroidRealms(insecure_observed_form),
- testing::IsEmpty());
-}
-
-TEST_F(AffiliatedMatchHelperTest,
GetAffiliatedAndroidRealmsYieldsEmptyResultsForHTTPBasicAuthForms) {
- autofill::PasswordForm http_auth_observed_form(
+ PasswordStore::FormDigest http_auth_observed_form(
GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr));
http_auth_observed_form.scheme = autofill::PasswordForm::SCHEME_BASIC;
EXPECT_THAT(GetAffiliatedAndroidRealms(http_auth_observed_form),
@@ -399,7 +385,7 @@ TEST_F(AffiliatedMatchHelperTest,
TEST_F(AffiliatedMatchHelperTest,
GetAffiliatedAndroidRealmsYieldsEmptyResultsForHTTPDigestAuthForms) {
- autofill::PasswordForm http_auth_observed_form(
+ PasswordStore::FormDigest http_auth_observed_form(
GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr));
http_auth_observed_form.scheme = autofill::PasswordForm::SCHEME_DIGEST;
EXPECT_THAT(GetAffiliatedAndroidRealms(http_auth_observed_form),
@@ -408,7 +394,7 @@ TEST_F(AffiliatedMatchHelperTest,
TEST_F(AffiliatedMatchHelperTest,
GetAffiliatedAndroidRealmsYieldsEmptyResultsForAndroidKeyedForms) {
- autofill::PasswordForm android_observed_form(
+ PasswordStore::FormDigest android_observed_form(
GetTestAndroidCredentials(kTestAndroidRealmBeta2));
EXPECT_THAT(GetAffiliatedAndroidRealms(android_observed_form),
testing::IsEmpty());
@@ -419,9 +405,8 @@ TEST_F(AffiliatedMatchHelperTest,
mock_affiliation_service()->ExpectCallToGetAffiliationsAndEmulateFailure(
FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1),
StrategyOnCacheMiss::FAIL);
- autofill::PasswordForm web_observed_form(
- GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr));
- EXPECT_THAT(GetAffiliatedAndroidRealms(web_observed_form),
+ EXPECT_THAT(GetAffiliatedAndroidRealms(
+ GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr)),
testing::IsEmpty());
}
@@ -433,7 +418,7 @@ TEST_F(AffiliatedMatchHelperTest, GetAffiliatedWebRealmsYieldsResults) {
mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
StrategyOnCacheMiss::FETCH_OVER_NETWORK, GetTestEquivalenceClassAlpha());
- autofill::PasswordForm android_form(
+ PasswordStore::FormDigest android_form(
GetTestAndroidCredentials(kTestAndroidRealmAlpha3));
EXPECT_THAT(
GetAffiliatedWebRealms(android_form),
@@ -444,7 +429,7 @@ TEST_F(AffiliatedMatchHelperTest, GetAffiliatedWebRealmsYieldsOnlyWebsites) {
mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
StrategyOnCacheMiss::FETCH_OVER_NETWORK, GetTestEquivalenceClassBeta());
- autofill::PasswordForm android_form(
+ PasswordStore::FormDigest android_form(
GetTestAndroidCredentials(kTestAndroidRealmBeta2));
// This verifies that |kTestAndroidRealmBeta3| is not returned.
EXPECT_THAT(GetAffiliatedWebRealms(android_form),
@@ -453,39 +438,44 @@ TEST_F(AffiliatedMatchHelperTest, GetAffiliatedWebRealmsYieldsOnlyWebsites) {
TEST_F(AffiliatedMatchHelperTest,
GetAffiliatedWebRealmsYieldsEmptyResultsForWebKeyedForms) {
- autofill::PasswordForm web_form(
- GetTestObservedWebForm(kTestWebRealmBeta1, nullptr));
- EXPECT_THAT(GetAffiliatedWebRealms(web_form), testing::IsEmpty());
+ EXPECT_THAT(GetAffiliatedWebRealms(
+ GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)),
+ testing::IsEmpty());
}
// Verifies that InjectAffiliatedWebRealms() injects the realms of web sites
// affiliated with the given Android application into password forms, if any.
TEST_F(AffiliatedMatchHelperTest, InjectAffiliatedWebRealms) {
- ScopedVector<autofill::PasswordForm> forms;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms;
- forms.push_back(new autofill::PasswordForm(
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>(
GetTestAndroidCredentials(kTestAndroidRealmAlpha3)));
mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha());
- forms.push_back(new autofill::PasswordForm(
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>(
GetTestAndroidCredentials(kTestAndroidRealmBeta2)));
mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
- forms.push_back(new autofill::PasswordForm(
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>(
GetTestAndroidCredentials(kTestAndroidRealmGamma)));
mock_affiliation_service()->ExpectCallToGetAffiliationsAndEmulateFailure(
FacetURI::FromCanonicalSpec(kTestAndroidFacetURIGamma),
StrategyOnCacheMiss::FAIL);
- forms.push_back(new autofill::PasswordForm(
- GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)));
+ PasswordStore::FormDigest digest =
+ GetTestObservedWebForm(kTestWebRealmBeta1, nullptr);
+ autofill::PasswordForm web_form;
+ web_form.scheme = digest.scheme;
+ web_form.signon_realm = digest.signon_realm;
+ web_form.origin = digest.origin;
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>(web_form));
size_t expected_form_count = forms.size();
- ScopedVector<autofill::PasswordForm> results(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results(
InjectAffiliatedWebRealms(std::move(forms)));
ASSERT_EQ(expected_form_count, results.size());
EXPECT_THAT(results[0]->affiliated_web_realm,
@@ -499,10 +489,9 @@ TEST_F(AffiliatedMatchHelperTest, InjectAffiliatedWebRealms) {
// Note: IsValidWebCredential() is tested as part of GetAffiliatedAndroidRealms
// tests above.
TEST_F(AffiliatedMatchHelperTest, IsValidAndroidCredential) {
- autofill::PasswordForm web_credential(
- GetTestObservedWebForm(kTestWebRealmBeta1, nullptr));
- EXPECT_FALSE(AffiliatedMatchHelper::IsValidAndroidCredential(web_credential));
- autofill::PasswordForm android_credential(
+ EXPECT_FALSE(AffiliatedMatchHelper::IsValidAndroidCredential(
+ GetTestObservedWebForm(kTestWebRealmBeta1, nullptr)));
+ PasswordStore::FormDigest android_credential(
GetTestAndroidCredentials(kTestAndroidRealmBeta2));
EXPECT_TRUE(
AffiliatedMatchHelper::IsValidAndroidCredential(android_credential));
diff --git a/chromium/components/password_manager/core/browser/affiliation_database_unittest.cc b/chromium/components/password_manager/core/browser/affiliation_database_unittest.cc
index 916494883c1..939a5bdb108 100644
--- a/chromium/components/password_manager/core/browser/affiliation_database_unittest.cc
+++ b/chromium/components/password_manager/core/browser/affiliation_database_unittest.cc
@@ -93,7 +93,7 @@ class AffiliationDatabaseTest : public testing::Test {
AffiliationDatabase& db() { return *db_; }
base::FilePath db_path() {
- return temp_directory_.path().Append(
+ return temp_directory_.GetPath().Append(
FILE_PATH_LITERAL("Test Affiliation Database"));
}
diff --git a/chromium/components/password_manager/core/browser/affiliation_fetch_throttler_unittest.cc b/chromium/components/password_manager/core/browser/affiliation_fetch_throttler_unittest.cc
index 41e6293b5bb..9d15f5a07b6 100644
--- a/chromium/components/password_manager/core/browser/affiliation_fetch_throttler_unittest.cc
+++ b/chromium/components/password_manager/core/browser/affiliation_fetch_throttler_unittest.cc
@@ -73,8 +73,8 @@ class AffiliationFetchThrottlerTest : public testing::Test {
~AffiliationFetchThrottlerTest() override {}
std::unique_ptr<AffiliationFetchThrottler> CreateThrottler() {
- return base::WrapUnique(new AffiliationFetchThrottler(
- &mock_delegate_, task_runner_, mock_tick_clock_.get()));
+ return base::MakeUnique<AffiliationFetchThrottler>(
+ &mock_delegate_, task_runner_, mock_tick_clock_.get());
}
void SimulateHasNetworkConnectivity(bool has_connectivity) {
diff --git a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
index dc5eda6ab79..c15455e0c58 100644
--- a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
+++ b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
@@ -5,6 +5,7 @@
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/password_form.h"
@@ -34,18 +35,32 @@ void BrowserSavePasswordProgressLogger::LogFormSignatures(
SavePasswordProgressLogger::StringID label,
const autofill::PasswordForm& form) {
autofill::FormStructure form_structure(form.form_data);
- base::DictionaryValue log;
- log.SetString(GetStringFromID(STRING_FORM_SIGNATURE),
- ScrubNonDigit(form_structure.FormSignature()));
+ std::string message = GetStringFromID(label) + ": {\n";
+ message += GetStringFromID(STRING_FORM_SIGNATURE) + ": " +
+ ScrubNonDigit(form_structure.FormSignatureAsStr()) + "\n";
+ message += GetStringFromID(STRING_SIGNON_REALM) + ": " +
+ ScrubURL(GURL(form.signon_realm)) + "\n";
+ message +=
+ GetStringFromID(STRING_ORIGIN) + ": " + ScrubURL(form.origin) + "\n";
+ message +=
+ GetStringFromID(STRING_ACTION) + ": " + ScrubURL(form.action) + "\n";
+ message += GetStringFromID(STRING_FORM_NAME) + ": " +
+ ScrubElementID(form.form_data.name) + "\n";
+ message += GetStringFromID(STRING_FIELDS) + ": " + "\n";
+
for (const autofill::AutofillField* field : form_structure) {
- log.SetString(ScrubElementID(field->name),
- ScrubNonDigit(field->FieldSignature()));
+ std::string field_info = ScrubElementID(field->name) + ": " +
+ ScrubNonDigit(field->FieldSignatureAsStr()) +
+ ", " + ScrubElementID(field->form_control_type);
+ if (!field->autocomplete_attribute.empty())
+ field_info += ", " + ScrubElementID(field->autocomplete_attribute);
+ message += field_info + "\n";
}
- LogValue(label, log);
+ message += "}";
+ SendLog(message);
}
-BrowserSavePasswordProgressLogger::~BrowserSavePasswordProgressLogger() {
-}
+BrowserSavePasswordProgressLogger::~BrowserSavePasswordProgressLogger() {}
void BrowserSavePasswordProgressLogger::SendLog(const std::string& log) {
log_manager_->LogSavePasswordProgress(log);
diff --git a/chromium/components/password_manager/core/browser/credential_manager_logger.cc b/chromium/components/password_manager/core/browser/credential_manager_logger.cc
new file mode 100644
index 00000000000..f5173c1868a
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/credential_manager_logger.cc
@@ -0,0 +1,58 @@
+// 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 "components/password_manager/core/browser/credential_manager_logger.h"
+
+#include <string>
+
+#include "base/strings/string_number_conversions.h"
+#include "components/autofill/core/common/save_password_progress_logger.h"
+#include "components/password_manager/core/browser/log_manager.h"
+
+using autofill::SavePasswordProgressLogger;
+
+namespace password_manager {
+
+CredentialManagerLogger::CredentialManagerLogger(const LogManager* log_manager)
+ : log_manager_(log_manager) {}
+
+CredentialManagerLogger::~CredentialManagerLogger() = default;
+
+void CredentialManagerLogger::LogRequestCredential(
+ const GURL& url,
+ bool zero_click_only,
+ const std::vector<GURL>& federations) {
+ std::string s("CM API get credentials: origin=" +
+ SavePasswordProgressLogger::ScrubURL(url));
+ s += ", zero_click_only=" + base::IntToString(zero_click_only);
+ s += ", federations=";
+ for (const GURL& federation_provider : federations)
+ s += SavePasswordProgressLogger::ScrubURL(federation_provider) + ", ";
+
+ log_manager_->LogSavePasswordProgress(s);
+}
+
+void CredentialManagerLogger::LogSendCredential(const GURL& url,
+ CredentialType type) {
+ std::string s("CM API send a credential: origin=" +
+ SavePasswordProgressLogger::ScrubURL(url));
+ s += ", CredentialType=" + CredentialTypeToString(type);
+ log_manager_->LogSavePasswordProgress(s);
+}
+
+void CredentialManagerLogger::LogStoreCredential(const GURL& url,
+ CredentialType type) {
+ std::string s("CM API save a credential: origin=" +
+ SavePasswordProgressLogger::ScrubURL(url));
+ s += ", CredentialType=" + CredentialTypeToString(type);
+ log_manager_->LogSavePasswordProgress(s);
+}
+
+void CredentialManagerLogger::LogRequireUserMediation(const GURL& url) {
+ std::string s("CM API sign out: origin=" +
+ SavePasswordProgressLogger::ScrubURL(url));
+ log_manager_->LogSavePasswordProgress(s);
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/credential_manager_logger.h b/chromium/components/password_manager/core/browser/credential_manager_logger.h
new file mode 100644
index 00000000000..c99f7f692a3
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/credential_manager_logger.h
@@ -0,0 +1,41 @@
+// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_LOGGER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_LOGGER_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "components/password_manager/core/common/credential_manager_types.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+
+class LogManager;
+
+// A helper for logging Credential Manager API calls to
+// chrome://password-manager-internals.
+class CredentialManagerLogger {
+ public:
+ explicit CredentialManagerLogger(const LogManager*);
+ ~CredentialManagerLogger();
+
+ void LogRequestCredential(const GURL& url,
+ bool zero_click_only,
+ const std::vector<GURL>& federations);
+ void LogSendCredential(const GURL& url, CredentialType type);
+ void LogStoreCredential(const GURL& url, CredentialType type);
+ void LogRequireUserMediation(const GURL& url);
+
+ private:
+ // The LogManager to which logs can be sent for display.
+ const LogManager* const log_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(CredentialManagerLogger);
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_LOGGER_H_
diff --git a/chromium/components/password_manager/core/browser/credential_manager_logger_unittest.cc b/chromium/components/password_manager/core/browser/credential_manager_logger_unittest.cc
new file mode 100644
index 00000000000..af6a98faba5
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/credential_manager_logger_unittest.cc
@@ -0,0 +1,78 @@
+// 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 "components/password_manager/core/browser/credential_manager_logger.h"
+
+#include "components/password_manager/core/browser/stub_log_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+namespace {
+
+using ::testing::AllOf;
+using ::testing::HasSubstr;
+using ::testing::Return;
+
+const char kSiteOrigin[] = "https://example.com";
+const char kFederationOrigin[] = "https://google.com";
+
+class MockLogManager : public StubLogManager {
+ public:
+ MockLogManager() = default;
+ ~MockLogManager() override = default;
+
+ MOCK_CONST_METHOD1(LogSavePasswordProgress, void(const std::string& text));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockLogManager);
+};
+
+class CredentialManagerLoggerTest : public testing::Test {
+ public:
+ CredentialManagerLoggerTest();
+ ~CredentialManagerLoggerTest() override;
+
+ MockLogManager& log_manager() { return log_manager_; }
+ CredentialManagerLogger& logger() { return logger_; }
+
+ private:
+ MockLogManager log_manager_;
+ CredentialManagerLogger logger_;
+
+ DISALLOW_COPY_AND_ASSIGN(CredentialManagerLoggerTest);
+};
+
+CredentialManagerLoggerTest::CredentialManagerLoggerTest()
+ : logger_(&log_manager_) {}
+
+CredentialManagerLoggerTest::~CredentialManagerLoggerTest() = default;
+
+TEST_F(CredentialManagerLoggerTest, LogRequestCredential) {
+ EXPECT_CALL(log_manager(),
+ LogSavePasswordProgress(
+ AllOf(HasSubstr(kSiteOrigin), HasSubstr(kFederationOrigin))));
+ logger().LogRequestCredential(GURL(kSiteOrigin), true,
+ {GURL(kFederationOrigin)});
+}
+
+TEST_F(CredentialManagerLoggerTest, LogSendCredential) {
+ EXPECT_CALL(log_manager(), LogSavePasswordProgress(HasSubstr(kSiteOrigin)));
+ logger().LogSendCredential(GURL(kSiteOrigin),
+ CredentialType::CREDENTIAL_TYPE_PASSWORD);
+}
+
+TEST_F(CredentialManagerLoggerTest, LogStoreCredential) {
+ EXPECT_CALL(log_manager(), LogSavePasswordProgress(HasSubstr(kSiteOrigin)));
+ logger().LogStoreCredential(GURL(kSiteOrigin),
+ CredentialType::CREDENTIAL_TYPE_PASSWORD);
+}
+
+TEST_F(CredentialManagerLoggerTest, LogRequireUserMediation) {
+ EXPECT_CALL(log_manager(), LogSavePasswordProgress(HasSubstr(kSiteOrigin)));
+ logger().LogRequireUserMediation(GURL(kSiteOrigin));
+}
+
+} // namespace
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
index a23a38ab0fa..e26a6883abb 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
@@ -28,19 +28,17 @@ CredentialManagerPasswordFormManager::CredentialManagerPasswordFormManager(
client,
driver,
observed_form,
- true,
base::WrapUnique(new FormSaverImpl(client->GetPasswordStore()))),
delegate_(delegate),
saved_form_(std::move(saved_form)) {
DCHECK(saved_form_);
- FetchDataFromPasswordStore();
}
CredentialManagerPasswordFormManager::~CredentialManagerPasswordFormManager() {
}
void CredentialManagerPasswordFormManager::OnGetPasswordStoreResults(
- ScopedVector<autofill::PasswordForm> results) {
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
PasswordFormManager::OnGetPasswordStoreResults(std::move(results));
// Mark the form as "preferred", as we've been told by the API that this is
diff --git a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h
index 7e979efd0b9..141f7769cc7 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h
@@ -46,7 +46,7 @@ class CredentialManagerPasswordFormManager : public PasswordFormManager {
~CredentialManagerPasswordFormManager() override;
void OnGetPasswordStoreResults(
- ScopedVector<autofill::PasswordForm> results) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
private:
CredentialManagerPasswordFormManagerDelegate* delegate_;
diff --git a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index dc995b0ad2a..d986c63075f 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -5,8 +5,11 @@
#include "components/password_manager/core/browser/credential_manager_pending_request_task.h"
#include <algorithm>
+#include <map>
#include <utility>
+#include "base/memory/ptr_util.h"
+#include "base/metrics/user_metrics.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/affiliated_match_helper.h"
#include "components/password_manager/core/browser/password_bubble_experiment.h"
@@ -22,27 +25,53 @@ namespace {
// Send a UMA histogram about if |local_results| has empty or duplicate
// usernames.
-void ReportAccountChooserMetrics(
- const ScopedVector<autofill::PasswordForm>& local_results,
- bool had_empty_username) {
- std::vector<base::string16> usernames;
- for (const auto& form : local_results)
- usernames.push_back(form->username_value);
- std::sort(usernames.begin(), usernames.end());
- bool has_duplicates =
- std::adjacent_find(usernames.begin(), usernames.end()) != usernames.end();
+void ReportAccountChooserMetrics(bool had_duplicates, bool had_empty_username) {
metrics_util::AccountChooserUsabilityMetric metric;
- if (had_empty_username && has_duplicates)
+ if (had_empty_username && had_duplicates)
metric = metrics_util::ACCOUNT_CHOOSER_EMPTY_USERNAME_AND_DUPLICATES;
else if (had_empty_username)
metric = metrics_util::ACCOUNT_CHOOSER_EMPTY_USERNAME;
- else if (has_duplicates)
+ else if (had_duplicates)
metric = metrics_util::ACCOUNT_CHOOSER_DUPLICATES;
else
metric = metrics_util::ACCOUNT_CHOOSER_LOOKS_OK;
metrics_util::LogAccountChooserUsability(metric);
}
+// Returns true iff |form1| is better suitable for showing in the account
+// chooser than |form2|. Inspired by PasswordFormManager::ScoreResult.
+bool IsBetterMatch(const autofill::PasswordForm& form1,
+ const autofill::PasswordForm& form2) {
+ if (!form1.is_public_suffix_match && form2.is_public_suffix_match)
+ return true;
+ if (form1.preferred && !form2.preferred)
+ return true;
+ return form1.date_created > form2.date_created;
+}
+
+// Remove duplicates in |forms| before displaying them in the account chooser.
+void FilterDuplicates(ScopedVector<autofill::PasswordForm>* forms) {
+ ScopedVector<autofill::PasswordForm> federated_forms;
+ std::map<base::string16, std::unique_ptr<autofill::PasswordForm>> credentials;
+ for (auto& form : *forms) {
+ if (!form->federation_origin.unique()) {
+ federated_forms.push_back(form);
+ form = nullptr;
+ } else {
+ auto it = credentials.find(form->username_value);
+ if (it == credentials.end() || IsBetterMatch(*form, *it->second)) {
+ credentials[form->username_value] = base::WrapUnique(form);
+ form = nullptr;
+ }
+ }
+ }
+ forms->clear();
+ for (auto& form_pair : credentials)
+ forms->push_back(std::move(form_pair.second));
+ forms->insert(forms->end(), federated_forms.begin(), federated_forms.end());
+ federated_forms.weak_clear();
+}
+
} // namespace
CredentialManagerPendingRequestTask::CredentialManagerPendingRequestTask(
@@ -68,14 +97,14 @@ CredentialManagerPendingRequestTask::~CredentialManagerPendingRequestTask() =
default;
void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
- ScopedVector<autofill::PasswordForm> results) {
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
if (delegate_->GetOrigin() != origin_) {
delegate_->SendCredential(send_callback_, CredentialInfo());
return;
}
ScopedVector<autofill::PasswordForm> local_results;
- ScopedVector<autofill::PasswordForm> affiliated_results;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> affiliated_results;
ScopedVector<autofill::PasswordForm> federated_results;
for (auto& form : results) {
// Ensure that the form we're looking at matches the password and
@@ -91,13 +120,12 @@ void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
// GURL definition: scheme, host, and port.
// So we can't compare them directly.
if (form->origin.GetOrigin() == origin_.GetOrigin()) {
- local_results.push_back(form);
- form = nullptr;
+ local_results.push_back(form.release());
} else if (affiliated_realms_.count(form->signon_realm) &&
- AffiliatedMatchHelper::IsValidAndroidCredential(*form)) {
+ AffiliatedMatchHelper::IsValidAndroidCredential(
+ PasswordStore::FormDigest(*form))) {
form->is_affiliation_based_match = true;
- affiliated_results.push_back(form);
- form = nullptr;
+ affiliated_results.push_back(std::move(form));
}
// TODO(mkwst): We're debating whether or not federations ought to be
@@ -110,9 +138,11 @@ void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
if (!affiliated_results.empty()) {
password_manager_util::TrimUsernameOnlyCredentials(&affiliated_results);
- local_results.insert(local_results.end(), affiliated_results.begin(),
- affiliated_results.end());
- affiliated_results.weak_clear();
+ size_t local_count = local_results.size();
+ local_results.resize(local_count + affiliated_results.size());
+ for (auto& affiliated : affiliated_results) {
+ local_results[local_count++] = affiliated.release();
+ }
}
// Remove empty usernames from the list.
@@ -123,6 +153,10 @@ void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
const bool has_empty_username = (begin_empty != local_results.end());
local_results.erase(begin_empty, local_results.end());
+ const size_t local_results_size = local_results.size();
+ FilterDuplicates(&local_results);
+ const bool has_duplicates = (local_results_size != local_results.size());
+
if ((local_results.empty() && federated_results.empty())) {
delegate_->SendCredential(send_callback_, CredentialInfo());
return;
@@ -145,6 +179,7 @@ void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
: CredentialType::CREDENTIAL_TYPE_FEDERATED);
delegate_->client()->NotifyUserAutoSignin(std::move(local_results),
origin_);
+ base::RecordAction(base::UserMetricsAction("CredentialManager_Autosignin"));
delegate_->SendCredential(send_callback_, info);
return;
}
@@ -153,9 +188,10 @@ void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
// or if the user chooses not to return a credential, and the credential the
// user chooses if they pick one.
std::unique_ptr<autofill::PasswordForm> potential_autosignin_form(
- new autofill::PasswordForm(*local_results[0]));
+ can_use_autosignin ? new autofill::PasswordForm(*local_results[0])
+ : nullptr);
if (!zero_click_only_)
- ReportAccountChooserMetrics(local_results, has_empty_username);
+ ReportAccountChooserMetrics(has_duplicates, has_empty_username);
if (zero_click_only_ ||
!delegate_->client()->PromptUserToChooseCredentials(
std::move(local_results), std::move(federated_results), origin_,
diff --git a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
index 1cafaf1bd43..78311468b24 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
@@ -12,6 +12,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/scoped_vector.h"
+#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "url/gurl.h"
@@ -38,7 +39,7 @@ class CredentialManagerPendingRequestTaskDelegate {
virtual GURL GetOrigin() const = 0;
// Retrieves a synthetic PasswordForm for the current page origin.
- virtual autofill::PasswordForm GetSynthesizedFormForOrigin() const = 0;
+ virtual PasswordStore::FormDigest GetSynthesizedFormForOrigin() const = 0;
// Returns the PasswordManagerClient.
virtual PasswordManagerClient* client() const = 0;
@@ -71,7 +72,7 @@ class CredentialManagerPendingRequestTask : public PasswordStoreConsumer {
// PasswordStoreConsumer implementation.
void OnGetPasswordStoreResults(
- ScopedVector<autofill::PasswordForm> results) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
private:
CredentialManagerPendingRequestTaskDelegate* delegate_; // Weak;
diff --git a/chromium/components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.cc b/chromium/components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.cc
index 8cf5b31bf42..85294376828 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.cc
@@ -37,16 +37,18 @@ void CredentialManagerPendingRequireUserMediationTask::AddOrigin(
}
void CredentialManagerPendingRequireUserMediationTask::
- OnGetPasswordStoreResults(ScopedVector<autofill::PasswordForm> results) {
+ OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
PasswordStore* store = delegate_->GetPasswordStore();
- for (autofill::PasswordForm* form : results) {
+ for (const auto& form : results) {
std::string form_registrable_domain =
net::registry_controlled_domains::GetDomainAndRegistry(
form->origin,
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
if (registrable_domains_.count(form_registrable_domain) ||
(affiliated_realms_.count(form->signon_realm) &&
- AffiliatedMatchHelper::IsValidAndroidCredential(*form))) {
+ AffiliatedMatchHelper::IsValidAndroidCredential(
+ PasswordStore::FormDigest(*form)))) {
form->skip_zero_click = true;
// Note that UpdateLogin ends up copying the form while posting a task to
// update the PasswordStore, so it's fine to let |results| delete the
diff --git a/chromium/components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.h b/chromium/components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.h
index a5deeacac39..300160cdabc 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.h
@@ -47,7 +47,7 @@ class CredentialManagerPendingRequireUserMediationTask
// PasswordStoreConsumer implementation.
void OnGetPasswordStoreResults(
- ScopedVector<autofill::PasswordForm> results) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
private:
CredentialManagerPendingRequireUserMediationTaskDelegate* const
diff --git a/chromium/components/password_manager/core/browser/credentials_filter.h b/chromium/components/password_manager/core/browser/credentials_filter.h
index 2b336de6456..aec30291a22 100644
--- a/chromium/components/password_manager/core/browser/credentials_filter.h
+++ b/chromium/components/password_manager/core/browser/credentials_filter.h
@@ -6,11 +6,12 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIALS_FILTER_H_
#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
#include "components/autofill/core/common/password_form.h"
namespace password_manager {
+class PasswordFormManager;
+
// This interface is used to filter credentials during saving, retrieval from
// PasswordStore, etc.
class CredentialsFilter {
@@ -20,15 +21,16 @@ class CredentialsFilter {
// Removes from |results| all forms which should be ignored for any password
// manager-related purposes, and returns the rest.
- virtual ScopedVector<autofill::PasswordForm> FilterResults(
- ScopedVector<autofill::PasswordForm> results) const = 0;
+ virtual std::vector<std::unique_ptr<autofill::PasswordForm>> FilterResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) const = 0;
// Should |form| be offered to be saved?
virtual bool ShouldSave(const autofill::PasswordForm& form) const = 0;
- // Call this if |form| was filled, and the subsequent sign-in looked like a
- // success. Calling is optional, used only for statistics.
- virtual void ReportFormUsed(const autofill::PasswordForm& form) const {}
+ // Call this if the form associated with |form_manager| was filled, and the
+ // subsequent sign-in looked like a success.
+ virtual void ReportFormLoginSuccess(
+ const PasswordFormManager& form_manager) const {}
private:
DISALLOW_COPY_AND_ASSIGN(CredentialsFilter);
diff --git a/chromium/components/password_manager/core/browser/export/password_csv_writer_unittest.cc b/chromium/components/password_manager/core/browser/export/password_csv_writer_unittest.cc
index fc231b8df7e..384940fbe12 100644
--- a/chromium/components/password_manager/core/browser/export/password_csv_writer_unittest.cc
+++ b/chromium/components/password_manager/core/browser/export/password_csv_writer_unittest.cc
@@ -39,7 +39,7 @@ TEST(PasswordCSVWriterTest, SerializePasswords_SinglePassword) {
form.origin = GURL("http://example.com");
form.username_value = base::UTF8ToUTF16("Someone");
form.password_value = base::UTF8ToUTF16("Secret");
- passwords.push_back(base::WrapUnique(new PasswordForm(form)));
+ passwords.push_back(base::MakeUnique<PasswordForm>(form));
std::vector<std::string> column_names;
std::vector<std::map<std::string, std::string>> records;
@@ -60,11 +60,11 @@ TEST(PasswordCSVWriterTest, SerializePasswords_TwoPasswords) {
form.origin = GURL("http://example.com");
form.username_value = base::UTF8ToUTF16("Someone");
form.password_value = base::UTF8ToUTF16("Secret");
- passwords.push_back(base::WrapUnique(new PasswordForm(form)));
+ passwords.push_back(base::MakeUnique<PasswordForm>(form));
form.origin = GURL("http://other.org");
form.username_value = base::UTF8ToUTF16("Anyone");
form.password_value = base::UTF8ToUTF16("None");
- passwords.push_back(base::WrapUnique(new PasswordForm(form)));
+ passwords.push_back(base::MakeUnique<PasswordForm>(form));
std::vector<std::string> column_names;
std::vector<std::map<std::string, std::string>> records;
diff --git a/chromium/components/password_manager/core/browser/export/password_exporter.cc b/chromium/components/password_manager/core/browser/export/password_exporter.cc
index 01a4e019587..e95fd85d173 100644
--- a/chromium/components/password_manager/core/browser/export/password_exporter.cc
+++ b/chromium/components/password_manager/core/browser/export/password_exporter.cc
@@ -33,8 +33,8 @@ void PasswordExporter::Export(
blocking_task_runner->PostTask(
FROM_HERE,
base::Bind(&WriteToFile, path,
- base::Passed(base::WrapUnique(new std::string(
- PasswordCSVWriter::SerializePasswords(passwords))))));
+ base::Passed(base::MakeUnique<std::string>(
+ PasswordCSVWriter::SerializePasswords(passwords)))));
}
// static
diff --git a/chromium/components/password_manager/core/browser/form_fetcher.h b/chromium/components/password_manager/core/browser/form_fetcher.h
new file mode 100644
index 00000000000..24ca598ea60
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/form_fetcher.h
@@ -0,0 +1,77 @@
+// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_FETCHER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_FETCHER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+
+namespace autofill {
+struct PasswordForm;
+}
+
+namespace password_manager {
+
+struct InteractionsStats;
+
+// This is an API for providing stored credentials to PasswordFormManager (PFM),
+// so that PFM instances do not have to talk to PasswordStore directly. This
+// indirection allows caching of identical requests from PFM on the same origin,
+// as well as easier testing (no need to mock the whole PasswordStore when
+// testing a PFM).
+// TODO(crbug.com/621355): Actually modify the API to support fetching in the
+// FormFetcher instance.
+class FormFetcher {
+ public:
+ // State of waiting for a response from a PasswordStore. There might be
+ // multiple transitions between these states.
+ enum class State { WAITING, NOT_WAITING };
+
+ // API to be implemented by classes which want the results from FormFetcher.
+ class Consumer {
+ public:
+ virtual ~Consumer() = default;
+
+ // FormFetcher calls this method every time the state changes from WAITING
+ // to UP_TO_DATE. It fills |non_federated| with pointers to non-federated
+ // matches (pointees stay owned by FormFetcher). To access the federated
+ // matches, the consumer can simply call GetFederatedMatches().
+ // |filtered_count| is the number of non-federated forms which were
+ // filtered out by CredentialsFilter and not included in |non_federated|.
+ virtual void ProcessMatches(
+ const std::vector<const autofill::PasswordForm*>& non_federated,
+ size_t filtered_count) = 0;
+ };
+
+ FormFetcher() = default;
+
+ virtual ~FormFetcher() = default;
+
+ // Adds |consumer|, which must not be null. If the current state is
+ // UP_TO_DATE, calls ProcessMatches on the consumer immediately. Assumes that
+ // |consumer| outlives |this|.
+ virtual void AddConsumer(Consumer* consumer) = 0;
+
+ // Returns the current state of the FormFetcher
+ virtual State GetState() const = 0;
+
+ // Statistics for recent password bubble usage.
+ virtual const std::vector<const InteractionsStats*>& GetInteractionsStats()
+ const = 0;
+
+ // Federated matches obtained from the backend. Valid only if GetState()
+ // returns NOT_WAITING.
+ virtual const std::vector<const autofill::PasswordForm*>&
+ GetFederatedMatches() const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FormFetcher);
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_FETCHER_H_
diff --git a/chromium/components/password_manager/core/browser/form_fetcher_impl.cc b/chromium/components/password_manager/core/browser/form_fetcher_impl.cc
new file mode 100644
index 00000000000..0266bd1966f
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -0,0 +1,111 @@
+// 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 "components/password_manager/core/browser/form_fetcher_impl.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "build/build_config.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/credentials_filter.h"
+#include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/browser/statistics_table.h"
+
+using autofill::PasswordForm;
+
+namespace password_manager {
+
+namespace {
+
+// Splits |store_results| into a vector of non-federated and federated matches.
+// Returns the federated matches and keeps the non-federated in |store_results|.
+std::vector<std::unique_ptr<PasswordForm>> SplitFederatedMatches(
+ std::vector<std::unique_ptr<PasswordForm>>* store_results) {
+ const auto first_federated = std::partition(
+ store_results->begin(), store_results->end(),
+ [](const std::unique_ptr<PasswordForm>& form) {
+ return form->federation_origin.unique(); // False means federated.
+ });
+
+ // Move out federated matches.
+ std::vector<std::unique_ptr<PasswordForm>> federated_matches;
+ federated_matches.resize(store_results->end() - first_federated);
+ std::move(first_federated, store_results->end(), federated_matches.begin());
+
+ store_results->erase(first_federated, store_results->end());
+ return federated_matches;
+}
+
+// Create a vector of const T* from a vector of unique_ptr<T>.
+template <typename T>
+std::vector<const T*> MakeWeakCopies(
+ const std::vector<std::unique_ptr<T>>& owning) {
+ std::vector<const T*> result;
+ result.resize(owning.size());
+ std::transform(owning.begin(), owning.end(), result.begin(),
+ [](const std::unique_ptr<T>& ptr) { return ptr.get(); });
+ return result;
+}
+
+} // namespace
+
+FormFetcherImpl::FormFetcherImpl(const PasswordManagerClient* client)
+ : client_(client) {}
+
+FormFetcherImpl::~FormFetcherImpl() = default;
+
+void FormFetcherImpl::AddConsumer(Consumer* consumer) {
+ DCHECK(consumer);
+ consumers_.insert(consumer);
+ if (state_ == State::NOT_WAITING)
+ consumer->ProcessMatches(weak_non_federated_, filtered_count_);
+}
+
+FormFetcherImpl::State FormFetcherImpl::GetState() const {
+ return state_;
+}
+
+const std::vector<const InteractionsStats*>&
+FormFetcherImpl::GetInteractionsStats() const {
+ return weak_interactions_stats_;
+}
+
+const std::vector<const autofill::PasswordForm*>&
+FormFetcherImpl::GetFederatedMatches() const {
+ return weak_federated_;
+}
+
+void FormFetcherImpl::SetResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+ DCHECK_EQ(State::WAITING, state_);
+
+ federated_ = SplitFederatedMatches(&results);
+ non_federated_ = std::move(results);
+
+ const size_t original_count = non_federated_.size();
+
+ non_federated_ =
+ client_->GetStoreResultFilter()->FilterResults(std::move(non_federated_));
+
+ filtered_count_ = original_count - non_federated_.size();
+
+ weak_non_federated_ = MakeWeakCopies(non_federated_);
+ weak_federated_ = MakeWeakCopies(federated_);
+
+ state_ = State::NOT_WAITING;
+
+ for (Consumer* consumer : consumers_)
+ consumer->ProcessMatches(weak_non_federated_, filtered_count_);
+}
+
+void FormFetcherImpl::SetStats(
+ std::vector<std::unique_ptr<InteractionsStats>> stats) {
+ interactions_stats_ = std::move(stats);
+ weak_interactions_stats_ = MakeWeakCopies(interactions_stats_);
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/form_fetcher_impl.h b/chromium/components/password_manager/core/browser/form_fetcher_impl.h
new file mode 100644
index 00000000000..e46438697bd
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl.h
@@ -0,0 +1,86 @@
+// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_FETCHER_IMPL_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_FETCHER_IMPL_H_
+
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/password_manager/core/browser/form_fetcher.h"
+
+namespace password_manager {
+
+class PasswordManagerClient;
+
+// Production implementation of FormFetcher. Fetches credentials associated
+// with a particular origin.
+// TODO(crbug.com/621355): This class should ultimately work with PasswordStore.
+class FormFetcherImpl : public FormFetcher {
+ public:
+ explicit FormFetcherImpl(const PasswordManagerClient* client);
+
+ ~FormFetcherImpl() override;
+
+ // FormFetcher:
+ void AddConsumer(Consumer* consumer) override;
+ State GetState() const override;
+ const std::vector<const InteractionsStats*>& GetInteractionsStats()
+ const override;
+ const std::vector<const autofill::PasswordForm*>& GetFederatedMatches()
+ const override;
+
+ // TODO(crbug.com/621355): Remove this once FormFetcher becomes a
+ // PasswordStoreConsumer.
+ void set_state(State state) { state_ = state; }
+
+ // TODO(crbug.com/621355): Remove this once FormFetcher becomes a
+ // PasswordStoreConsumer.
+ // Resets the results owned by |this| with new results from PasswordStore and
+ // sets the state to NOT_WAITING.
+ void SetResults(std::vector<std::unique_ptr<autofill::PasswordForm>> results);
+
+ // TODO(crbug.com/621355): Remove this once FormFetcher becomes a
+ // PasswordStoreConsumer.
+ // Resets the stats owned by |this| with new stats from PasswordStore.
+ void SetStats(std::vector<std::unique_ptr<InteractionsStats>> stats);
+
+ private:
+ // Results obtained from PasswordStore:
+ std::vector<std::unique_ptr<autofill::PasswordForm>> non_federated_;
+
+ // Federated credentials relevant to the observed form. They are neither
+ // filled not saved by PasswordFormManager, so they are kept separately from
+ // non-federated matches.
+ std::vector<std::unique_ptr<autofill::PasswordForm>> federated_;
+
+ // Statistics for the current domain.
+ std::vector<std::unique_ptr<InteractionsStats>> interactions_stats_;
+
+ // Non-owning copies of the vectors above.
+ std::vector<const autofill::PasswordForm*> weak_non_federated_;
+ std::vector<const autofill::PasswordForm*> weak_federated_;
+ std::vector<const InteractionsStats*> weak_interactions_stats_;
+
+ // Consumers of the fetcher, all are assumed to outlive |this|.
+ std::set<Consumer*> consumers_;
+
+ // Client used to obtain a CredentialFilter.
+ const PasswordManagerClient* const client_;
+
+ // The number of non-federated forms which were filtered out by
+ // CredentialsFilter and not included in |non_federated_|.
+ size_t filtered_count_ = 0;
+
+ // State of the fetcher.
+ State state_ = State::NOT_WAITING;
+
+ DISALLOW_COPY_AND_ASSIGN(FormFetcherImpl);
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_FETCHER_IMPL_H_
diff --git a/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc b/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
new file mode 100644
index 00000000000..7876c0179a0
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
@@ -0,0 +1,247 @@
+// 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 "components/password_manager/core/browser/form_fetcher_impl.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/statistics_table.h"
+#include "components/password_manager/core/browser/stub_credentials_filter.h"
+#include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+using autofill::PasswordForm;
+using base::ASCIIToUTF16;
+using base::StringPiece;
+using testing::_;
+using testing::IsEmpty;
+using testing::Pointee;
+using testing::UnorderedElementsAre;
+
+namespace password_manager {
+
+namespace {
+
+class MockConsumer : public FormFetcher::Consumer {
+ public:
+ MOCK_METHOD2(ProcessMatches,
+ void(const std::vector<const PasswordForm*>& non_federated,
+ size_t filtered_count));
+};
+
+class NameFilter : public StubCredentialsFilter {
+ public:
+ // This class filters out all credentials which have |name| as
+ // |username_value|.
+ explicit NameFilter(StringPiece name) : name_(ASCIIToUTF16(name)) {}
+
+ ~NameFilter() override = default;
+
+ std::vector<std::unique_ptr<PasswordForm>> FilterResults(
+ std::vector<std::unique_ptr<PasswordForm>> results) const override {
+ results.erase(
+ std::remove_if(results.begin(), results.end(),
+ [this](const std::unique_ptr<PasswordForm>& form) {
+ return !ShouldSave(*form);
+ }),
+ results.end());
+ return results;
+ }
+
+ bool ShouldSave(const PasswordForm& form) const override {
+ return form.username_value != name_;
+ }
+
+ private:
+ const base::string16 name_; // |username_value| to filter
+
+ DISALLOW_COPY_AND_ASSIGN(NameFilter);
+};
+
+class FakePasswordManagerClient : public StubPasswordManagerClient {
+ public:
+ FakePasswordManagerClient() = default;
+ ~FakePasswordManagerClient() override = default;
+
+ void set_filter(std::unique_ptr<CredentialsFilter> filter) {
+ filter_ = std::move(filter);
+ }
+
+ private:
+ const CredentialsFilter* GetStoreResultFilter() const override {
+ return filter_ ? filter_.get()
+ : StubPasswordManagerClient::GetStoreResultFilter();
+ }
+
+ std::unique_ptr<CredentialsFilter> filter_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakePasswordManagerClient);
+};
+
+// Creates a dummy non-federated form with some basic arbitrary values.
+PasswordForm CreateNonFederated() {
+ PasswordForm form;
+ form.origin = GURL("https://example.in");
+ form.signon_realm = form.origin.spec();
+ form.action = GURL("https://login.example.org");
+ form.username_value = ASCIIToUTF16("user");
+ form.password_value = ASCIIToUTF16("password");
+ return form;
+}
+
+// Creates a dummy federated form with some basic arbitrary values.
+PasswordForm CreateFederated() {
+ PasswordForm form = CreateNonFederated();
+ form.password_value.clear();
+ form.federation_origin = url::Origin(GURL("https://accounts.google.com/"));
+ return form;
+}
+
+} // namespace
+
+class FormFetcherImplTest : public testing::Test {
+ public:
+ FormFetcherImplTest() : form_fetcher_(&client_) {}
+
+ ~FormFetcherImplTest() override = default;
+
+ protected:
+ FakePasswordManagerClient client_;
+ FormFetcherImpl form_fetcher_;
+ testing::NiceMock<MockConsumer> consumer_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FormFetcherImplTest);
+};
+
+// Check that no PasswordStore results are handled correctly.
+TEST_F(FormFetcherImplTest, NoStoreResults) {
+ EXPECT_CALL(consumer_, ProcessMatches(_, _)).Times(0);
+ form_fetcher_.set_state(FormFetcher::State::WAITING);
+ form_fetcher_.AddConsumer(&consumer_);
+ EXPECT_EQ(FormFetcher::State::WAITING, form_fetcher_.GetState());
+}
+
+// Check that empty PasswordStore results are handled correctly.
+TEST_F(FormFetcherImplTest, Empty) {
+ form_fetcher_.AddConsumer(&consumer_);
+ form_fetcher_.set_state(FormFetcher::State::WAITING);
+ EXPECT_CALL(consumer_, ProcessMatches(IsEmpty(), 0u));
+ form_fetcher_.SetResults(std::vector<std::unique_ptr<PasswordForm>>());
+ EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_.GetState());
+ EXPECT_THAT(form_fetcher_.GetFederatedMatches(), IsEmpty());
+}
+
+// Check that non-federated PasswordStore results are handled correctly.
+TEST_F(FormFetcherImplTest, NonFederated) {
+ PasswordForm non_federated = CreateNonFederated();
+ form_fetcher_.AddConsumer(&consumer_);
+ form_fetcher_.set_state(FormFetcher::State::WAITING);
+ std::vector<std::unique_ptr<PasswordForm>> results;
+ results.push_back(base::MakeUnique<PasswordForm>(non_federated));
+ EXPECT_CALL(consumer_,
+ ProcessMatches(UnorderedElementsAre(Pointee(non_federated)), 0u));
+ form_fetcher_.SetResults(std::move(results));
+ EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_.GetState());
+ EXPECT_THAT(form_fetcher_.GetFederatedMatches(), IsEmpty());
+}
+
+// Check that federated PasswordStore results are handled correctly.
+TEST_F(FormFetcherImplTest, Federated) {
+ PasswordForm federated = CreateFederated();
+ form_fetcher_.AddConsumer(&consumer_);
+ form_fetcher_.set_state(FormFetcher::State::WAITING);
+ std::vector<std::unique_ptr<PasswordForm>> results;
+ results.push_back(base::MakeUnique<PasswordForm>(federated));
+ EXPECT_CALL(consumer_, ProcessMatches(IsEmpty(), 0u));
+ form_fetcher_.SetResults(std::move(results));
+ EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_.GetState());
+ EXPECT_THAT(form_fetcher_.GetFederatedMatches(),
+ UnorderedElementsAre(Pointee(federated)));
+}
+
+// Check that mixed PasswordStore results are handled correctly.
+TEST_F(FormFetcherImplTest, Mixed) {
+ PasswordForm federated1 = CreateFederated();
+ federated1.username_value = ASCIIToUTF16("user");
+ PasswordForm federated2 = CreateFederated();
+ federated2.username_value = ASCIIToUTF16("user_B");
+ PasswordForm non_federated1 = CreateNonFederated();
+ non_federated1.username_value = ASCIIToUTF16("user");
+ PasswordForm non_federated2 = CreateNonFederated();
+ non_federated2.username_value = ASCIIToUTF16("user_C");
+ PasswordForm non_federated3 = CreateNonFederated();
+ non_federated3.username_value = ASCIIToUTF16("user_D");
+
+ form_fetcher_.AddConsumer(&consumer_);
+ form_fetcher_.set_state(FormFetcher::State::WAITING);
+ std::vector<std::unique_ptr<PasswordForm>> results;
+ results.push_back(base::MakeUnique<PasswordForm>(federated1));
+ results.push_back(base::MakeUnique<PasswordForm>(federated2));
+ results.push_back(base::MakeUnique<PasswordForm>(non_federated1));
+ results.push_back(base::MakeUnique<PasswordForm>(non_federated2));
+ results.push_back(base::MakeUnique<PasswordForm>(non_federated3));
+ EXPECT_CALL(consumer_,
+ ProcessMatches(UnorderedElementsAre(Pointee(non_federated1),
+ Pointee(non_federated2),
+ Pointee(non_federated3)),
+ 0u));
+ form_fetcher_.SetResults(std::move(results));
+ EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_.GetState());
+ EXPECT_THAT(form_fetcher_.GetFederatedMatches(),
+ UnorderedElementsAre(Pointee(federated1), Pointee(federated2)));
+}
+
+// Check that PasswordStore results are filtered correctly.
+TEST_F(FormFetcherImplTest, Filtered) {
+ PasswordForm federated = CreateFederated();
+ federated.username_value = ASCIIToUTF16("user");
+ PasswordForm non_federated1 = CreateNonFederated();
+ non_federated1.username_value = ASCIIToUTF16("user");
+ PasswordForm non_federated2 = CreateNonFederated();
+ non_federated2.username_value = ASCIIToUTF16("user_C");
+
+ // Set up a filter to remove all credentials with the username "user".
+ client_.set_filter(base::MakeUnique<NameFilter>("user"));
+
+ form_fetcher_.AddConsumer(&consumer_);
+ form_fetcher_.set_state(FormFetcher::State::WAITING);
+ std::vector<std::unique_ptr<PasswordForm>> results;
+ results.push_back(base::MakeUnique<PasswordForm>(federated));
+ results.push_back(base::MakeUnique<PasswordForm>(non_federated1));
+ results.push_back(base::MakeUnique<PasswordForm>(non_federated2));
+ // Non-federated results should have been filtered: no "user" here.
+ constexpr size_t kNumFiltered = 1u;
+ EXPECT_CALL(consumer_,
+ ProcessMatches(UnorderedElementsAre(Pointee(non_federated2)),
+ kNumFiltered));
+ form_fetcher_.SetResults(std::move(results));
+ EXPECT_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_.GetState());
+ // However, federated results should not be filtered.
+ EXPECT_THAT(form_fetcher_.GetFederatedMatches(),
+ UnorderedElementsAre(Pointee(federated)));
+}
+
+// Check that stats from PasswordStore are handled correctly.
+TEST_F(FormFetcherImplTest, Stats) {
+ form_fetcher_.AddConsumer(&consumer_);
+ std::vector<std::unique_ptr<InteractionsStats>> stats;
+ stats.push_back(base::MakeUnique<InteractionsStats>());
+ form_fetcher_.SetStats(std::move(stats));
+ EXPECT_EQ(1u, form_fetcher_.GetInteractionsStats().size());
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/form_saver.h b/chromium/components/password_manager/core/browser/form_saver.h
index 825dddc5685..5c82c374e23 100644
--- a/chromium/components/password_manager/core/browser/form_saver.h
+++ b/chromium/components/password_manager/core/browser/form_saver.h
@@ -5,10 +5,13 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_SAVER_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_SAVER_H_
+#include <map>
+#include <memory>
#include <vector>
#include "base/macros.h"
#include "base/optional.h"
+#include "base/strings/string16.h"
#include "components/autofill/core/common/password_form.h"
namespace password_manager {
@@ -26,10 +29,10 @@ class FormSaver {
// Saves the |pending| form and updates the stored preference on
// |best_matches|. If |old_primary_key| is given, uses it for saving
- // |pending|. It also updates the password store with all
- // |credentials_to_update|.
+ // |pending|.
virtual void Save(const autofill::PasswordForm& pending,
- const autofill::PasswordFormMap& best_matches,
+ const std::map<base::string16,
+ const autofill::PasswordForm*>& best_matches,
const autofill::PasswordForm* old_primary_key) = 0;
// Updates the |pending| form and updates the stored preference on
@@ -38,8 +41,9 @@ class FormSaver {
// |credentials_to_update|.
virtual void Update(
const autofill::PasswordForm& pending,
- const autofill::PasswordFormMap& best_matches,
- const std::vector<const autofill::PasswordForm*>* credentials_to_update,
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches,
+ const std::vector<autofill::PasswordForm>* credentials_to_update,
const autofill::PasswordForm* old_primary_key) = 0;
// Ensures that |generated| is saved in the store. This is in ideal case
@@ -62,7 +66,7 @@ class FormSaver {
// account.
virtual void WipeOutdatedCopies(
const autofill::PasswordForm& pending,
- autofill::PasswordFormMap* best_matches,
+ std::map<base::string16, const autofill::PasswordForm*>* best_matches,
const autofill::PasswordForm** preferred_match) = 0;
private:
diff --git a/chromium/components/password_manager/core/browser/form_saver_impl.cc b/chromium/components/password_manager/core/browser/form_saver_impl.cc
index aaf509455ef..c64b7a0fd60 100644
--- a/chromium/components/password_manager/core/browser/form_saver_impl.cc
+++ b/chromium/components/password_manager/core/browser/form_saver_impl.cc
@@ -18,7 +18,6 @@
#include "url/origin.h"
using autofill::PasswordForm;
-using autofill::PasswordFormMap;
namespace password_manager {
@@ -37,16 +36,17 @@ void FormSaverImpl::PermanentlyBlacklist(PasswordForm* observed) {
store_->AddLogin(*observed);
}
-void FormSaverImpl::Save(const PasswordForm& pending,
- const autofill::PasswordFormMap& best_matches,
- const PasswordForm* old_primary_key) {
+void FormSaverImpl::Save(
+ const PasswordForm& pending,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
+ const PasswordForm* old_primary_key) {
SaveImpl(pending, true, best_matches, nullptr, old_primary_key);
}
void FormSaverImpl::Update(
const PasswordForm& pending,
- const autofill::PasswordFormMap& best_matches,
- const std::vector<const PasswordForm*>* credentials_to_update,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
+ const std::vector<PasswordForm>* credentials_to_update,
const PasswordForm* old_primary_key) {
SaveImpl(pending, false, best_matches, credentials_to_update,
old_primary_key);
@@ -68,9 +68,10 @@ void FormSaverImpl::RemovePresavedPassword() {
presaved_ = nullptr;
}
-void FormSaverImpl::WipeOutdatedCopies(const PasswordForm& pending,
- PasswordFormMap* best_matches,
- const PasswordForm** preferred_match) {
+void FormSaverImpl::WipeOutdatedCopies(
+ const PasswordForm& pending,
+ std::map<base::string16, const PasswordForm*>* best_matches,
+ const PasswordForm** preferred_match) {
DCHECK(preferred_match); // Note: *preferred_match may still be null.
DCHECK(url::Origin(GURL(pending.signon_realm))
.IsSameOriginWith(
@@ -82,7 +83,7 @@ void FormSaverImpl::WipeOutdatedCopies(const PasswordForm& pending,
if ((pending.password_value != it->second->password_value) &&
gaia::AreEmailsSame(base::UTF16ToUTF8(pending.username_value),
base::UTF16ToUTF8(it->second->username_value))) {
- if (it->second.get() == *preferred_match)
+ if (it->second == *preferred_match)
*preferred_match = nullptr;
store_->RemoveLogin(*it->second);
it = best_matches->erase(it);
@@ -95,19 +96,14 @@ void FormSaverImpl::WipeOutdatedCopies(const PasswordForm& pending,
void FormSaverImpl::SaveImpl(
const PasswordForm& pending,
bool is_new_login,
- const PasswordFormMap& best_matches,
- const std::vector<const PasswordForm*>* credentials_to_update,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
+ const std::vector<PasswordForm>* credentials_to_update,
const PasswordForm* old_primary_key) {
- // Empty and null |credentials_to_update| mean the same, having a canonical
- // representation as nullptr makes the code simpler.
- if (credentials_to_update && credentials_to_update->empty())
- credentials_to_update = nullptr;
-
DCHECK(pending.preferred);
DCHECK(!pending.blacklisted_by_user);
- base::AutoReset<const autofill::PasswordFormMap*> ar1(&best_matches_,
- &best_matches);
+ base::AutoReset<const std::map<base::string16, const PasswordForm*>*> ar1(
+ &best_matches_, &best_matches);
base::AutoReset<const PasswordForm*> ar2(&pending_, &pending);
UpdatePreferredLoginState();
@@ -126,8 +122,8 @@ void FormSaverImpl::SaveImpl(
}
if (credentials_to_update) {
- for (const PasswordForm* credential : *credentials_to_update) {
- store_->UpdateLogin(*credential);
+ for (const PasswordForm& credential : *credentials_to_update) {
+ store_->UpdateLogin(credential);
}
}
}
@@ -135,12 +131,13 @@ void FormSaverImpl::SaveImpl(
void FormSaverImpl::UpdatePreferredLoginState() {
const base::string16& preferred_username = pending_->username_value;
for (const auto& key_value_pair : *best_matches_) {
- const auto& form = key_value_pair.second;
- if (form->preferred && !form->is_public_suffix_match &&
- form->username_value != preferred_username) {
+ const PasswordForm& form = *key_value_pair.second;
+ if (form.preferred && !form.is_public_suffix_match &&
+ form.username_value != preferred_username) {
// This wasn't the selected login but it used to be preferred.
- form->preferred = false;
- store_->UpdateLogin(*form);
+ PasswordForm update(form);
+ update.preferred = false;
+ store_->UpdateLogin(update);
}
}
}
@@ -149,7 +146,7 @@ void FormSaverImpl::DeleteEmptyUsernameCredentials() {
DCHECK(!pending_->username_value.empty());
for (const auto& match : *best_matches_) {
- const PasswordForm* form = match.second.get();
+ const PasswordForm* form = match.second;
if (!form->is_public_suffix_match && form->username_value.empty() &&
form->password_value == pending_->password_value) {
store_->RemoveLogin(*form);
diff --git a/chromium/components/password_manager/core/browser/form_saver_impl.h b/chromium/components/password_manager/core/browser/form_saver_impl.h
index 7fac37f38d6..c881c4f219c 100644
--- a/chromium/components/password_manager/core/browser/form_saver_impl.h
+++ b/chromium/components/password_manager/core/browser/form_saver_impl.h
@@ -26,19 +26,20 @@ class FormSaverImpl : public FormSaver {
// FormSaver:
void PermanentlyBlacklist(autofill::PasswordForm* observed) override;
void Save(const autofill::PasswordForm& pending,
- const autofill::PasswordFormMap& best_matches,
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches,
const autofill::PasswordForm* old_primary_key) override;
- void Update(
- const autofill::PasswordForm& pending,
- const autofill::PasswordFormMap& best_matches,
- const std::vector<const autofill::PasswordForm*>* credentials_to_update,
- const autofill::PasswordForm* old_primary_key) override;
+ void Update(const autofill::PasswordForm& pending,
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches,
+ const std::vector<autofill::PasswordForm>* credentials_to_update,
+ const autofill::PasswordForm* old_primary_key) override;
void PresaveGeneratedPassword(
const autofill::PasswordForm& generated) override;
void RemovePresavedPassword() override;
void WipeOutdatedCopies(
const autofill::PasswordForm& pending,
- autofill::PasswordFormMap* best_matches,
+ std::map<base::string16, const autofill::PasswordForm*>* best_matches,
const autofill::PasswordForm** preferred_match) override;
private:
@@ -47,8 +48,9 @@ class FormSaverImpl : public FormSaver {
void SaveImpl(
const autofill::PasswordForm& pending,
bool is_new_login,
- const autofill::PasswordFormMap& best_matches,
- const std::vector<const autofill::PasswordForm*>* credentials_to_update,
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches,
+ const std::vector<autofill::PasswordForm>* credentials_to_update,
const autofill::PasswordForm* old_primary_key);
// Marks all of |best_matches_| as not preferred unless the username is
@@ -64,7 +66,8 @@ class FormSaverImpl : public FormSaver {
PasswordStore* const store_;
// Caches the best matches during a call to Save() or Update().
- const autofill::PasswordFormMap* best_matches_ = nullptr;
+ const std::map<base::string16, const autofill::PasswordForm*>* best_matches_ =
+ nullptr;
// Caches the pending credential during a call to Save() or Update().
const autofill::PasswordForm* pending_ = nullptr;
diff --git a/chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc b/chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc
index 3a1d9756200..d626697ddcd 100644
--- a/chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/form_saver_impl_unittest.cc
@@ -4,12 +4,14 @@
#include "components/password_manager/core/browser/form_saver_impl.h"
+#include <map>
+#include <memory>
#include <set>
#include <vector>
-#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
+#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/common/password_form.h"
@@ -19,10 +21,8 @@
#include "url/gurl.h"
using autofill::PasswordForm;
-using autofill::PasswordFormMap;
using base::ASCIIToUTF16;
using base::StringPiece;
-using base::WrapUnique;
using testing::_;
using testing::DoAll;
using testing::SaveArg;
@@ -107,7 +107,8 @@ TEST_F(FormSaverImplTest, Save_AsNew) {
EXPECT_CALL(*mock_store_, AddLogin(_)).WillOnce(SaveArg<0>(&saved));
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
- form_saver_.Save(pending, PasswordFormMap(), nullptr);
+ form_saver_.Save(pending, std::map<base::string16, const PasswordForm*>(),
+ nullptr);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved.username_value);
EXPECT_EQ(ASCIIToUTF16("wordToP4a55"), saved.password_value);
}
@@ -121,7 +122,8 @@ TEST_F(FormSaverImplTest, Save_Update) {
EXPECT_CALL(*mock_store_, AddLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLogin(_)).WillOnce(SaveArg<0>(&saved));
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
- form_saver_.Update(pending, PasswordFormMap(), nullptr, nullptr);
+ form_saver_.Update(pending, std::map<base::string16, const PasswordForm*>(),
+ nullptr, nullptr);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved.username_value);
EXPECT_EQ(ASCIIToUTF16("wordToP4a55"), saved.password_value);
}
@@ -137,8 +139,7 @@ TEST_F(FormSaverImplTest, Save_UpdateAlsoOtherCredentials) {
PasswordForm related2 = pending;
related2.origin = GURL("http://complete.example.net");
related2.signon_realm = related2.origin.spec();
- std::vector<const autofill::PasswordForm*> credentials_to_update = {
- &related1, &related2};
+ std::vector<PasswordForm> credentials_to_update = {related1, related2};
pending.password_value = ASCIIToUTF16("abcd");
PasswordForm saved[3];
@@ -149,8 +150,8 @@ TEST_F(FormSaverImplTest, Save_UpdateAlsoOtherCredentials) {
.WillOnce(SaveArg<0>(&saved[1]))
.WillOnce(SaveArg<0>(&saved[2]));
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
- form_saver_.Update(pending, PasswordFormMap(), &credentials_to_update,
- nullptr);
+ form_saver_.Update(pending, std::map<base::string16, const PasswordForm*>(),
+ &credentials_to_update, nullptr);
std::set<GURL> different_origins;
for (const PasswordForm& form : saved) {
different_origins.insert(form.origin);
@@ -173,7 +174,8 @@ TEST_F(FormSaverImplTest, Save_UpdateWithPrimaryKey) {
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _))
.WillOnce(DoAll(SaveArg<0>(&saved_new), SaveArg<1>(&saved_old)));
- form_saver_.Update(pending, PasswordFormMap(), nullptr, &old_key);
+ form_saver_.Update(pending, std::map<base::string16, const PasswordForm*>(),
+ nullptr, &old_key);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved_new.username_value);
EXPECT_EQ(ASCIIToUTF16("wordToP4a55"), saved_new.password_value);
EXPECT_EQ(ASCIIToUTF16("old username"), saved_old.username_value);
@@ -190,14 +192,13 @@ TEST_F(FormSaverImplTest, Save_AndUpdatePreferredLoginState) {
// as the pending one, both marked as "preferred". FormSaver should ignore
// the pending and PSL-matched one, but should update the non-PSL matched
// form (with different username) to no longer be preferred.
- PasswordFormMap best_matches;
+ std::map<base::string16, const PasswordForm*> best_matches;
PasswordForm other = pending;
other.username_value = ASCIIToUTF16("othername");
- best_matches[other.username_value] = WrapUnique(new PasswordForm(other));
+ best_matches[other.username_value] = &other;
PasswordForm psl_match = pending;
psl_match.is_public_suffix_match = true;
- best_matches[psl_match.username_value] =
- WrapUnique(new PasswordForm(psl_match));
+ best_matches[psl_match.username_value] = &psl_match;
PasswordForm saved;
PasswordForm updated;
@@ -222,13 +223,12 @@ TEST_F(FormSaverImplTest, Save_AndUpdatePreferredLoginState) {
TEST_F(FormSaverImplTest, Save_AndDeleteEmptyUsernameCredentials) {
PasswordForm pending = CreatePending("nameofuser", "wordToP4a55");
- PasswordFormMap best_matches;
- best_matches[pending.username_value] = WrapUnique(new PasswordForm(pending));
+ std::map<base::string16, const PasswordForm*> best_matches;
+ best_matches[pending.username_value] = &pending;
PasswordForm no_username = pending;
no_username.username_value.clear();
no_username.preferred = false;
- best_matches[no_username.username_value] =
- WrapUnique(new PasswordForm(no_username));
+ best_matches[no_username.username_value] = &no_username;
PasswordForm saved;
PasswordForm removed;
@@ -251,14 +251,13 @@ TEST_F(FormSaverImplTest,
Save_AndDoNotDeleteEmptyUsernameCredentialsWithDifferentPassword) {
PasswordForm pending = CreatePending("nameofuser", "wordToP4a55");
- PasswordFormMap best_matches;
- best_matches[pending.username_value] = WrapUnique(new PasswordForm(pending));
+ std::map<base::string16, const PasswordForm*> best_matches;
+ best_matches[pending.username_value] = &pending;
PasswordForm no_username = pending;
no_username.username_value.clear();
no_username.preferred = false;
no_username.password_value = ASCIIToUTF16("abcd");
- best_matches[no_username.username_value] =
- WrapUnique(new PasswordForm(no_username));
+ best_matches[no_username.username_value] = &no_username;
PasswordForm saved;
@@ -277,13 +276,12 @@ TEST_F(FormSaverImplTest,
Save_DoNotDeleteUsernamelessOnUpdatingPasswordWithUsername) {
PasswordForm pending = CreatePending("abc", "pwd");
- PasswordFormMap best_matches;
- best_matches[pending.username_value] = WrapUnique(new PasswordForm(pending));
+ std::map<base::string16, const PasswordForm*> best_matches;
+ best_matches[pending.username_value] = &pending;
PasswordForm no_username = pending;
no_username.username_value.clear();
no_username.preferred = false;
- best_matches[no_username.username_value] =
- WrapUnique(new PasswordForm(no_username));
+ best_matches[no_username.username_value] = &no_username;
pending.password_value = ASCIIToUTF16("def");
@@ -304,12 +302,11 @@ TEST_F(FormSaverImplTest,
TEST_F(FormSaverImplTest, Save_EmptyUsernameWillNotCauseDeletion) {
PasswordForm pending = CreatePending("", "wordToP4a55");
- PasswordFormMap best_matches;
+ std::map<base::string16, const PasswordForm*> best_matches;
PasswordForm with_username = pending;
with_username.username_value = ASCIIToUTF16("nameofuser");
with_username.preferred = false;
- best_matches[with_username.username_value] =
- WrapUnique(new PasswordForm(with_username));
+ best_matches[with_username.username_value] = &with_username;
PasswordForm saved;
@@ -328,13 +325,12 @@ TEST_F(FormSaverImplTest, Save_EmptyUsernameWillNotCauseDeletion) {
TEST_F(FormSaverImplTest, Save_AndDoNotDeleteEmptyUsernamePSLCredentials) {
PasswordForm pending = CreatePending("nameofuser", "wordToP4a55");
- PasswordFormMap best_matches;
- best_matches[pending.username_value] = WrapUnique(new PasswordForm(pending));
+ std::map<base::string16, const PasswordForm*> best_matches;
+ best_matches[pending.username_value] = &pending;
PasswordForm no_username_psl = pending;
no_username_psl.username_value.clear();
no_username_psl.is_public_suffix_match = true;
- best_matches[no_username_psl.username_value] =
- WrapUnique(new PasswordForm(no_username_psl));
+ best_matches[no_username_psl.username_value] = &no_username_psl;
PasswordForm saved;
@@ -352,13 +348,12 @@ TEST_F(FormSaverImplTest, Save_AndDoNotDeleteEmptyUsernamePSLCredentials) {
TEST_F(FormSaverImplTest, Save_AndDoNotDeleteNonEmptyUsernameCredentials) {
PasswordForm pending = CreatePending("nameofuser", "wordToP4a55");
- PasswordFormMap best_matches;
- best_matches[pending.username_value] = WrapUnique(new PasswordForm(pending));
+ std::map<base::string16, const PasswordForm*> best_matches;
+ best_matches[pending.username_value] = &pending;
PasswordForm other_username = pending;
other_username.username_value = ASCIIToUTF16("other username");
other_username.preferred = false;
- best_matches[other_username.username_value] =
- WrapUnique(new PasswordForm(other_username));
+ best_matches[other_username.username_value] = &other_username;
PasswordForm saved;
@@ -421,7 +416,8 @@ TEST_F(FormSaverImplTest, PresaveGeneratedPassword_ThenSaveAsNew) {
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _))
.WillOnce(DoAll(SaveArg<0>(&saved_new), SaveArg<1>(&saved_old)));
- form_saver_.Save(pending, PasswordFormMap(), nullptr);
+ form_saver_.Save(pending, std::map<base::string16, const PasswordForm*>(),
+ nullptr);
EXPECT_EQ(ASCIIToUTF16("generatedU"), saved_old.username_value);
EXPECT_EQ(ASCIIToUTF16("generatedP"), saved_old.password_value);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved_new.username_value);
@@ -444,7 +440,8 @@ TEST_F(FormSaverImplTest, PresaveGeneratedPassword_ThenUpdate) {
EXPECT_CALL(*mock_store_, UpdateLogin(_)).Times(0);
EXPECT_CALL(*mock_store_, UpdateLoginWithPrimaryKey(_, _))
.WillOnce(DoAll(SaveArg<0>(&saved_new), SaveArg<1>(&saved_old)));
- form_saver_.Update(pending, PasswordFormMap(), nullptr, nullptr);
+ form_saver_.Update(pending, std::map<base::string16, const PasswordForm*>(),
+ nullptr, nullptr);
EXPECT_EQ(ASCIIToUTF16("generatedU"), saved_old.username_value);
EXPECT_EQ(ASCIIToUTF16("generatedP"), saved_old.password_value);
EXPECT_EQ(ASCIIToUTF16("nameofuser"), saved_new.username_value);
@@ -520,12 +517,12 @@ TEST_F(FormSaverImplTest, RemovePresavedPassword_AndPresaveAgain) {
TEST_F(FormSaverImplTest, WipeOutdatedCopies_Preferred) {
PasswordForm pending = CreatePendingGAIA("nameofuser", "wordToP4a55");
- PasswordFormMap best_matches;
+ std::map<base::string16, const PasswordForm*> best_matches;
PasswordForm other = pending;
other.password_value = ASCIIToUTF16("oldpwd");
- best_matches[other.username_value] = WrapUnique(new PasswordForm(other));
+ best_matches[other.username_value] = &other;
- const PasswordForm* preferred = best_matches[other.username_value].get();
+ const PasswordForm* preferred = best_matches[other.username_value];
EXPECT_CALL(*mock_store_, RemoveLogin(other));
form_saver_.WipeOutdatedCopies(pending, &best_matches, &preferred);
@@ -536,10 +533,10 @@ TEST_F(FormSaverImplTest, WipeOutdatedCopies_Preferred) {
TEST_F(FormSaverImplTest, WipeOutdatedCopies_NullPreferred) {
PasswordForm pending = CreatePendingGAIA("nameofuser", "wordToP4a55");
- PasswordFormMap best_matches;
+ std::map<base::string16, const PasswordForm*> best_matches;
PasswordForm other = pending;
other.password_value = ASCIIToUTF16("oldpwd");
- best_matches[other.username_value] = WrapUnique(new PasswordForm(other));
+ best_matches[other.username_value] = &other;
const PasswordForm* preferred = nullptr;
@@ -551,21 +548,21 @@ TEST_F(FormSaverImplTest, WipeOutdatedCopies_NullPreferred) {
TEST_F(FormSaverImplTest, WipeOutdatedCopies_EquivalentNames) {
PasswordForm pending = CreatePendingGAIA("nameofuser", "wordToP4a55");
- PasswordFormMap best_matches;
+ std::map<base::string16, const PasswordForm*> best_matches;
PasswordForm old = pending;
old.password_value = ASCIIToUTF16("oldpwd");
- best_matches[old.username_value] = WrapUnique(new PasswordForm(old));
+ best_matches[old.username_value] = &old;
// For GAIA authentication, the first two other usernames are equivalent to
// |pending| but the third is not.
PasswordForm eq1 = old;
eq1.username_value = ASCIIToUTF16("nameofuser@gmail.com");
- best_matches[eq1.username_value] = WrapUnique(new PasswordForm(eq1));
+ best_matches[eq1.username_value] = &eq1;
PasswordForm eq2 = old;
eq2.username_value = ASCIIToUTF16("name.of.user");
- best_matches[eq2.username_value] = WrapUnique(new PasswordForm(eq2));
+ best_matches[eq2.username_value] = &eq2;
PasswordForm non_eq = old;
non_eq.username_value = ASCIIToUTF16("other.user");
- best_matches[non_eq.username_value] = WrapUnique(new PasswordForm(non_eq));
+ best_matches[non_eq.username_value] = &non_eq;
const PasswordForm* preferred = nullptr;
@@ -579,14 +576,14 @@ TEST_F(FormSaverImplTest, WipeOutdatedCopies_EquivalentNames) {
TEST_F(FormSaverImplTest, WipeOutdatedCopies_NotOutdated) {
PasswordForm pending = CreatePendingGAIA("nameofuser", "wordToP4a55");
- PasswordFormMap best_matches;
- best_matches[pending.username_value] = WrapUnique(new PasswordForm(pending));
+ std::map<base::string16, const PasswordForm*> best_matches;
+ best_matches[pending.username_value] = &pending;
PasswordForm eq1 = pending;
eq1.username_value = ASCIIToUTF16("nameofuser@gmail.com");
- best_matches[eq1.username_value] = WrapUnique(new PasswordForm(eq1));
+ best_matches[eq1.username_value] = &eq1;
PasswordForm eq2 = pending;
eq2.username_value = ASCIIToUTF16("name.of.user");
- best_matches[eq2.username_value] = WrapUnique(new PasswordForm(eq2));
+ best_matches[eq2.username_value] = &eq2;
const PasswordForm* preferred = nullptr;
diff --git a/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc b/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
index 90d7ca9deb8..24ff2dce5bc 100644
--- a/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
+++ b/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
@@ -76,7 +76,8 @@ TEST_F(PasswordImporterTest, CSVImport) {
"Url,Username,Password\n"
"http://accounts.google.com/a/LoginAuth,test@gmail.com,test1\n";
- base::FilePath input_path = temp_directory_.path().AppendASCII(kTestFileName);
+ base::FilePath input_path =
+ temp_directory_.GetPath().AppendASCII(kTestFileName);
ASSERT_TRUE(
base::WriteFile(input_path, kTestCSVInput, strlen(kTestCSVInput)));
ASSERT_NO_FATAL_FAILURE(StartImportAndWaitForCompletion(input_path));
diff --git a/chromium/components/password_manager/core/browser/keychain_migration_status_mac.h b/chromium/components/password_manager/core/browser/keychain_migration_status_mac.h
index 23c2b18e2f6..70f25f246c6 100644
--- a/chromium/components/password_manager/core/browser/keychain_migration_status_mac.h
+++ b/chromium/components/password_manager/core/browser/keychain_migration_status_mac.h
@@ -23,6 +23,12 @@ enum class MigrationStatus {
// Migration failed twice. It should not be tried again.
FAILED_TWICE,
+ // Migration finished successfully. The Keychain was cleaned up.
+ MIGRATED_DELETED,
+
+ // Best effort migration happened. Some passwords were inaccessible.
+ MIGRATED_PARTIALLY,
+
MIGRATION_STATUS_COUNT,
};
diff --git a/chromium/components/password_manager/core/browser/login_database.cc b/chromium/components/password_manager/core/browser/login_database.cc
index d4e913cd768..b7950ad3284 100644
--- a/chromium/components/password_manager/core/browser/login_database.cc
+++ b/chromium/components/password_manager/core/browser/login_database.cc
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <algorithm>
#include <limits>
+#include <map>
#include <utility>
#include "base/bind.h"
@@ -16,6 +17,7 @@
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
+#include "base/numerics/safe_conversions.h"
#include "base/pickle.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -26,6 +28,8 @@
#include "components/password_manager/core/browser/affiliation_utils.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
+#include "components/password_manager/core/browser/sql_table_builder.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_urls.h"
#include "sql/connection.h"
@@ -39,10 +43,10 @@ using autofill::PasswordForm;
namespace password_manager {
// The current version number of the login database schema.
-const int kCurrentVersionNumber = 17;
+const int kCurrentVersionNumber = 18;
// The oldest version of the schema such that a legacy Chrome client using that
// version can still read/write the current database.
-const int kCompatibleVersionNumber = 14;
+const int kCompatibleVersionNumber = 18;
base::Pickle SerializeVector(const std::vector<base::string16>& vec) {
base::Pickle p;
@@ -75,7 +79,6 @@ enum LoginTableColumns {
COLUMN_PASSWORD_VALUE,
COLUMN_SUBMIT_ELEMENT,
COLUMN_SIGNON_REALM,
- COLUMN_SSL_VALID,
COLUMN_PREFERRED,
COLUMN_DATE_CREATED,
COLUMN_BLACKLISTED_BY_USER,
@@ -90,6 +93,7 @@ enum LoginTableColumns {
COLUMN_FEDERATION_URL,
COLUMN_SKIP_ZERO_CLICK,
COLUMN_GENERATION_UPLOAD_STATUS,
+ COLUMN_NUM // Keep this last.
};
enum class HistogramSize { SMALL, LARGE };
@@ -121,7 +125,6 @@ void BindAddStatement(const PasswordForm& form,
static_cast<int>(encrypted_password.length()));
s->BindString16(COLUMN_SUBMIT_ELEMENT, form.submit_element);
s->BindString(COLUMN_SIGNON_REALM, form.signon_realm);
- s->BindInt(COLUMN_SSL_VALID, form.ssl_valid);
s->BindInt(COLUMN_PREFERRED, form.preferred);
s->BindInt64(COLUMN_DATE_CREATED, form.date_created.ToInternalValue());
s->BindInt(COLUMN_BLACKLISTED_BY_USER, form.blacklisted_by_user);
@@ -334,45 +337,171 @@ void LogPasswordReuseMetrics(const std::vector<std::string>& signon_realms) {
}
}
-// Creates a table named |table_name| using our current schema.
-bool CreateNewTable(sql::Connection* db,
- const char* table_name,
- const char* extra_columns) {
- std::string query = base::StringPrintf(
- "CREATE TABLE %s ("
- "origin_url VARCHAR NOT NULL, "
- "action_url VARCHAR, "
- "username_element VARCHAR, "
- "username_value VARCHAR, "
- "password_element VARCHAR, "
- "password_value BLOB, "
- "submit_element VARCHAR, "
- "signon_realm VARCHAR NOT NULL,"
- "ssl_valid INTEGER NOT NULL,"
- "preferred INTEGER NOT NULL,"
- "date_created INTEGER NOT NULL,"
- "blacklisted_by_user INTEGER NOT NULL,"
- "scheme INTEGER NOT NULL,"
- "password_type INTEGER,"
- "possible_usernames BLOB,"
- "times_used INTEGER,"
- "form_data BLOB,"
- "date_synced INTEGER,"
- "display_name VARCHAR,"
- "icon_url VARCHAR,"
- "federation_url VARCHAR,"
- "skip_zero_click INTEGER,"
- "%s"
- "UNIQUE (origin_url, username_element, username_value, "
- "password_element, signon_realm))",
- table_name, extra_columns);
- return db->Execute(query.c_str());
+// Teaches |builder| about the different DB schemes in different versions.
+void InitializeBuilder(SQLTableBuilder* builder) {
+ // Versions 0 and 1, which are the same.
+ builder->AddColumnToUniqueKey("origin_url", "VARCHAR NOT NULL");
+ builder->AddColumn("action_url", "VARCHAR");
+ builder->AddColumnToUniqueKey("username_element", "VARCHAR");
+ builder->AddColumnToUniqueKey("username_value", "VARCHAR");
+ builder->AddColumnToUniqueKey("password_element", "VARCHAR");
+ builder->AddColumn("password_value", "BLOB");
+ builder->AddColumn("submit_element", "VARCHAR");
+ builder->AddColumnToUniqueKey("signon_realm", "VARCHAR NOT NULL");
+ builder->AddColumn("ssl_valid", "INTEGER NOT NULL");
+ builder->AddColumn("preferred", "INTEGER NOT NULL");
+ builder->AddColumn("date_created", "INTEGER NOT NULL");
+ builder->AddColumn("blacklisted_by_user", "INTEGER NOT NULL");
+ builder->AddColumn("scheme", "INTEGER NOT NULL");
+ builder->SealVersion();
+ unsigned version = builder->SealVersion();
+ DCHECK_EQ(1u, version);
+
+ // Version 2.
+ builder->AddColumn("password_type", "INTEGER");
+ builder->AddColumn("possible_usernames", "BLOB");
+ version = builder->SealVersion();
+ DCHECK_EQ(2u, version);
+
+ // Version 3.
+ builder->AddColumn("times_used", "INTEGER");
+ version = builder->SealVersion();
+ DCHECK_EQ(3u, version);
+
+ // Version 4.
+ builder->AddColumn("form_data", "BLOB");
+ version = builder->SealVersion();
+ DCHECK_EQ(4u, version);
+
+ // Version 5.
+ builder->AddColumn("use_additional_auth", "INTEGER");
+ version = builder->SealVersion();
+ DCHECK_EQ(5u, version);
+
+ // Version 6.
+ builder->AddColumn("date_synced", "INTEGER");
+ version = builder->SealVersion();
+ DCHECK_EQ(6u, version);
+
+ // Version 7.
+ builder->AddColumn("display_name", "VARCHAR");
+ builder->AddColumn("avatar_url", "VARCHAR");
+ builder->AddColumn("federation_url", "VARCHAR");
+ builder->AddColumn("is_zero_click", "INTEGER");
+ version = builder->SealVersion();
+ DCHECK_EQ(7u, version);
+
+ // Version 8.
+ builder->SealVersion();
+ // Version 9.
+ version = builder->SealVersion();
+ // Version 10.
+ builder->DropColumn("use_additional_auth");
+ version = builder->SealVersion();
+ DCHECK_EQ(10u, version);
+
+ // Version 11.
+ builder->RenameColumn("is_zero_click", "skip_zero_click");
+ version = builder->SealVersion();
+ DCHECK_EQ(11u, version);
+
+ // Version 12.
+ builder->AddColumn("generation_upload_status", "INTEGER");
+ version = builder->SealVersion();
+ DCHECK_EQ(12u, version);
+
+ // Version 13.
+ builder->SealVersion();
+ // Version 14.
+ builder->RenameColumn("avatar_url", "icon_url");
+ version = builder->SealVersion();
+ DCHECK_EQ(14u, version);
+
+ // Version 15.
+ builder->SealVersion();
+ // Version 16.
+ builder->SealVersion();
+ // Version 17.
+ version = builder->SealVersion();
+ DCHECK_EQ(17u, version);
+
+ // Version 18.
+ builder->DropColumn("ssl_valid");
+ version = builder->SealVersion();
+ DCHECK_EQ(18u, version);
+
+ DCHECK_EQ(static_cast<size_t>(COLUMN_NUM), builder->NumberOfColumns())
+ << "Adjust LoginTableColumns if you change column definitions here.";
}
-bool CreateIndexOnSignonRealm(sql::Connection* db, const char* table_name) {
- std::string query = base::StringPrintf(
- "CREATE INDEX logins_signon ON %s (signon_realm)", table_name);
- return db->Execute(query.c_str());
+// Call this after having called InitializeBuilder, to migrate the database from
+// the current version to kCurrentVersionNumber.
+bool MigrateLogins(unsigned current_version,
+ SQLTableBuilder* builder,
+ sql::Connection* db) {
+ if (!builder->MigrateFrom(current_version, db))
+ return false;
+
+ // Data changes, not covered by the schema migration above.
+ if (current_version <= 8) {
+ sql::Statement fix_time_format;
+ fix_time_format.Assign(db->GetCachedStatement(
+ SQL_FROM_HERE,
+ "UPDATE logins SET date_created = (date_created * ?) + ?"));
+ fix_time_format.BindInt64(0, base::Time::kMicrosecondsPerSecond);
+ fix_time_format.BindInt64(1, base::Time::kTimeTToMicrosecondsOffset);
+ if (!fix_time_format.Run())
+ return false;
+ }
+
+ if (current_version <= 16) {
+ sql::Statement reset_zero_click;
+ reset_zero_click.Assign(db->GetCachedStatement(
+ SQL_FROM_HERE, "UPDATE logins SET skip_zero_click = 1"));
+ if (!reset_zero_click.Run())
+ return false;
+ }
+
+ return true;
+}
+
+// Because of https://crbug.com/295851, some early version numbers might be
+// wrong. This function detects that and fixes the version.
+bool FixVersionIfNeeded(sql::Connection* db, int* current_version) {
+ if (*current_version == 1) {
+ int extra_columns = 0;
+ if (db->DoesColumnExist("logins", "password_type"))
+ ++extra_columns;
+ if (db->DoesColumnExist("logins", "possible_usernames"))
+ ++extra_columns;
+ if (extra_columns == 2) {
+ *current_version = 2;
+ } else if (extra_columns == 1) {
+ // If this is https://crbug.com/295851 then either both columns exist
+ // or none.
+ return false;
+ }
+ }
+ if (*current_version == 2) {
+ if (db->DoesColumnExist("logins", "times_used"))
+ *current_version = 3;
+ }
+ if (*current_version == 3) {
+ if (db->DoesColumnExist("logins", "form_data"))
+ *current_version = 4;
+ }
+ return true;
+}
+
+// Generates the string "(?,?,...,?)" with |count| repetitions of "?".
+std::string GeneratePlaceholders(size_t count) {
+ std::string result(2 * count + 1, ',');
+ result.front() = '(';
+ result.back() = ')';
+ for (size_t i = 1; i < 2 * count + 1; i += 2) {
+ result[i] = '?';
+ }
+ return result;
}
} // namespace
@@ -411,6 +540,7 @@ bool LoginDatabase::Init() {
kCompatibleVersionNumber)) {
LogDatabaseInitError(META_TABLE_INIT_ERROR);
LOG(ERROR) << "Unable to create the meta table.";
+ transaction.Rollback();
db_.Close();
return false;
}
@@ -419,28 +549,49 @@ bool LoginDatabase::Init() {
LOG(ERROR) << "Password store database is too new, kCurrentVersionNumber="
<< kCurrentVersionNumber << ", GetCompatibleVersionNumber="
<< meta_table_.GetCompatibleVersionNumber();
+ transaction.Rollback();
db_.Close();
return false;
}
- // Initialize the tables.
- if (!InitLoginsTable()) {
- LogDatabaseInitError(INIT_LOGINS_ERROR);
- LOG(ERROR) << "Unable to initialize the logins table.";
- db_.Close();
- return false;
+ SQLTableBuilder builder;
+ InitializeBuilder(&builder);
+ InitializeStatementStrings(builder);
+
+ if (!db_.DoesTableExist("logins")) {
+ if (!builder.CreateTable(&db_)) {
+ VLOG(0) << "Failed to create the 'logins' table";
+ transaction.Rollback();
+ db_.Close();
+ return false;
+ }
}
+
stats_table_.Init(&db_);
+ int current_version = meta_table_.GetVersionNumber();
+ bool migration_success = FixVersionIfNeeded(&db_, &current_version);
+ DCHECK_LE(current_version, kCurrentVersionNumber);
+
// If the file on disk is an older database version, bring it up to date.
- if (meta_table_.GetVersionNumber() < kCurrentVersionNumber &&
- !MigrateOldVersionsAsNeeded()) {
+ if (migration_success && current_version < kCurrentVersionNumber) {
+ migration_success = MigrateLogins(
+ base::checked_cast<unsigned>(current_version), &builder, &db_);
+ }
+ if (migration_success && current_version <= 15) {
+ migration_success = stats_table_.MigrateToVersion(16);
+ }
+ if (migration_success) {
+ meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber);
+ meta_table_.SetVersionNumber(kCurrentVersionNumber);
+ } else {
LogDatabaseInitError(MIGRATION_ERROR);
UMA_HISTOGRAM_SPARSE_SLOWLY("PasswordManager.LoginDatabaseFailedVersion",
meta_table_.GetVersionNumber());
LOG(ERROR) << "Unable to migrate database from "
<< meta_table_.GetVersionNumber() << " to "
<< kCurrentVersionNumber;
+ transaction.Rollback();
db_.Close();
return false;
}
@@ -448,6 +599,7 @@ bool LoginDatabase::Init() {
if (!stats_table_.CreateTableIfNecessary()) {
LogDatabaseInitError(INIT_STATS_ERROR);
LOG(ERROR) << "Unable to create the stats table.";
+ transaction.Rollback();
db_.Close();
return false;
}
@@ -463,204 +615,6 @@ bool LoginDatabase::Init() {
return true;
}
-bool LoginDatabase::MigrateOldVersionsAsNeeded() {
- const int original_version = meta_table_.GetVersionNumber();
- switch (original_version) {
- case 1:
- // Column could exist because of https://crbug.com/295851
- if (!db_.DoesColumnExist("logins", "password_type") &&
- !db_.Execute("ALTER TABLE logins "
- "ADD COLUMN password_type INTEGER")) {
- return false;
- }
- if (!db_.DoesColumnExist("logins", "possible_usernames") &&
- !db_.Execute("ALTER TABLE logins "
- "ADD COLUMN possible_usernames BLOB")) {
- return false;
- }
- // Fall through.
- case 2:
- // Column could exist because of https://crbug.com/295851
- if (!db_.DoesColumnExist("logins", "times_used") &&
- !db_.Execute("ALTER TABLE logins ADD COLUMN times_used INTEGER")) {
- return false;
- }
- // Fall through.
- case 3:
- // Column could exist because of https://crbug.com/295851
- if (!db_.DoesColumnExist("logins", "form_data") &&
- !db_.Execute("ALTER TABLE logins ADD COLUMN form_data BLOB")) {
- return false;
- }
- // Fall through.
- case 4:
- if (!db_.Execute(
- "ALTER TABLE logins ADD COLUMN use_additional_auth INTEGER")) {
- return false;
- }
- // Fall through.
- case 5:
- if (!db_.Execute("ALTER TABLE logins ADD COLUMN date_synced INTEGER")) {
- return false;
- }
- // Fall through.
- case 6:
- if (!db_.Execute("ALTER TABLE logins ADD COLUMN display_name VARCHAR") ||
- !db_.Execute("ALTER TABLE logins ADD COLUMN avatar_url VARCHAR") ||
- !db_.Execute("ALTER TABLE logins "
- "ADD COLUMN federation_url VARCHAR") ||
- !db_.Execute("ALTER TABLE logins ADD COLUMN is_zero_click INTEGER")) {
- return false;
- }
- // Fall through.
- case 7: {
- // Keep version 8 around even though no changes are made. See
- // crbug.com/423716 for context.
- // Fall through.
- }
- case 8: {
- sql::Statement s;
- s.Assign(db_.GetCachedStatement(SQL_FROM_HERE,
- "UPDATE logins SET "
- "date_created = "
- "(date_created * ?) + ?"));
- s.BindInt64(0, base::Time::kMicrosecondsPerSecond);
- s.BindInt64(1, base::Time::kTimeTToMicrosecondsOffset);
- if (!s.Run())
- return false;
- // Fall through.
- }
- case 9: {
- // Remove use_additional_auth column from database schema
- // crbug.com/423716 for context.
- std::string fields_to_copy =
- "origin_url, action_url, username_element, username_value, "
- "password_element, password_value, submit_element, "
- "signon_realm, ssl_valid, preferred, date_created, "
- "blacklisted_by_user, scheme, password_type, possible_usernames, "
- "times_used, form_data, date_synced, display_name, avatar_url, "
- "federation_url, is_zero_click";
- auto copy_data_query =
- [&fields_to_copy](const std::string& from, const std::string& to) {
- return "INSERT INTO " + to + " SELECT " + fields_to_copy + " FROM " +
- from;
- };
-
- if (!db_.Execute(("CREATE TEMPORARY TABLE logins_data(" + fields_to_copy +
- ")").c_str()) ||
- !db_.Execute(copy_data_query("logins", "logins_data").c_str()) ||
- !db_.Execute("DROP TABLE logins") ||
- !db_.Execute(
- ("CREATE TABLE logins(" + fields_to_copy + ")").c_str()) ||
- !db_.Execute(copy_data_query("logins_data", "logins").c_str()) ||
- !db_.Execute("DROP TABLE logins_data") ||
- !CreateIndexOnSignonRealm(&db_, "logins")) {
- return false;
- }
- // Fall through.
- }
- case 10: {
- // Rename is_zero_click -> skip_zero_click. Note that previous versions
- // may have incorrectly used a 6-column key (origin_url, username_element,
- // username_value, password_element, signon_realm, submit_element).
- // In that case, this step also restores the correct 5-column key;
- // that is, the above without "submit_element".
- const char copy_query[] = "INSERT OR REPLACE INTO logins_new SELECT "
- "origin_url, action_url, username_element, username_value, "
- "password_element, password_value, submit_element, signon_realm, "
- "ssl_valid, preferred, date_created, blacklisted_by_user, scheme, "
- "password_type, possible_usernames, times_used, form_data, "
- "date_synced, display_name, avatar_url, federation_url, is_zero_click"
- " FROM logins";
- if (!CreateNewTable(&db_, "logins_new", "") ||
- !db_.Execute(copy_query) ||
- !db_.Execute("DROP TABLE logins") ||
- !db_.Execute("ALTER TABLE logins_new RENAME TO logins") ||
- !CreateIndexOnSignonRealm(&db_, "logins")) {
- return false;
- }
- // Fall through.
- }
- case 11:
- if (!db_.Execute(
- "ALTER TABLE logins ADD COLUMN "
- "generation_upload_status INTEGER"))
- return false;
- // Fall through.
- case 12:
- // The stats table was added. Nothing to do really.
- // Fall through.
- case 13: {
- // Rename avatar_url -> icon_url. Note that if the original version was
- // at most 10, this renaming would have already happened in step 10,
- // as |CreateNewTable| would create a table with the new column name.
- if (original_version > 10) {
- const char copy_query[] = "INSERT OR REPLACE INTO logins_new SELECT "
- "origin_url, action_url, username_element, username_value, "
- "password_element, password_value, submit_element, signon_realm, "
- "ssl_valid, preferred, date_created, blacklisted_by_user, scheme, "
- "password_type, possible_usernames, times_used, form_data, "
- "date_synced, display_name, avatar_url, federation_url, "
- "skip_zero_click, generation_upload_status FROM logins";
- if (!CreateNewTable(
- &db_, "logins_new", "generation_upload_status INTEGER,") ||
- !db_.Execute(copy_query) ||
- !db_.Execute("DROP TABLE logins") ||
- !db_.Execute("ALTER TABLE logins_new RENAME TO logins") ||
- !CreateIndexOnSignonRealm(&db_, "logins")) {
- return false;
- }
- }
- // Fall through.
- }
- case 14:
- // No change of schema. Version 15 was introduced to force all databases
- // through an otherwise no-op migration process that will, however, now
- // correctly set the 'compatible version number'. Previously, it was
- // always being set to (and forever left at) version 1.
- meta_table_.SetCompatibleVersionNumber(kCompatibleVersionNumber);
- case 15:
- // Recreate the statistics.
- if (!stats_table_.MigrateToVersion(16))
- return false;
- case 16: {
- // No change in scheme: just disable auto sign-in by default in
- // preparation to launch the credential management API.
- if (!db_.Execute("UPDATE logins SET skip_zero_click = 1"))
- return false;
- // Fall through.
- }
-
- // -------------------------------------------------------------------------
- // DO NOT FORGET to update |kCompatibleVersionNumber| if you add a migration
- // step that is a breaking change. This is needed so that an older version
- // of the browser can fail with a meaningful error when opening a newer
- // database, as opposed to failing on the first database operation.
- // -------------------------------------------------------------------------
- case kCurrentVersionNumber:
- // Already up to date.
- meta_table_.SetVersionNumber(kCurrentVersionNumber);
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool LoginDatabase::InitLoginsTable() {
- if (!db_.DoesTableExist("logins")) {
- if (!CreateNewTable(&db_, "logins", "generation_upload_status INTEGER,")) {
- NOTREACHED();
- return false;
- }
- if (!CreateIndexOnSignonRealm(&db_, "logins")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
void LoginDatabase::ReportMetrics(const std::string& sync_username,
bool custom_passphrase_sync_enabled) {
sql::Statement s(db_.GetCachedStatement(
@@ -783,8 +737,7 @@ void LoginDatabase::ReportMetrics(const std::string& sync_username,
}
sql::Statement logins_with_schemes_statement(db_.GetUniqueStatement(
- "SELECT signon_realm, origin_url, ssl_valid, blacklisted_by_user "
- "FROM logins;"));
+ "SELECT signon_realm, origin_url, blacklisted_by_user FROM logins;"));
if (!logins_with_schemes_statement.is_valid())
return;
@@ -798,8 +751,7 @@ void LoginDatabase::ReportMetrics(const std::string& sync_username,
while (logins_with_schemes_statement.Step()) {
std::string signon_realm = logins_with_schemes_statement.ColumnString(0);
GURL origin_url = GURL(logins_with_schemes_statement.ColumnString(1));
- bool ssl_valid = !!logins_with_schemes_statement.ColumnInt(2);
- bool blacklisted_by_user = !!logins_with_schemes_statement.ColumnInt(3);
+ bool blacklisted_by_user = !!logins_with_schemes_statement.ColumnInt(2);
if (blacklisted_by_user)
continue;
@@ -807,8 +759,6 @@ void LoginDatabase::ReportMetrics(const std::string& sync_username,
++android_logins;
} else if (origin_url.SchemeIs(url::kHttpsScheme)) {
++https_logins;
- metrics_util::LogUMAHistogramBoolean(
- "PasswordManager.UserStoredPasswordWithInvalidSSLCert", !ssl_valid);
} else if (origin_url.SchemeIs(url::kHttpScheme)) {
++http_logins;
} else if (origin_url.SchemeIs(url::kFtpScheme)) {
@@ -855,17 +805,9 @@ PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form) {
&encrypted_password) != ENCRYPTION_RESULT_SUCCESS)
return list;
- // You *must* change LoginTableColumns if this query changes.
- sql::Statement s(db_.GetCachedStatement(
- SQL_FROM_HERE,
- "INSERT INTO logins "
- "(origin_url, action_url, username_element, username_value, "
- " password_element, password_value, submit_element, "
- " signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
- " scheme, password_type, possible_usernames, times_used, form_data, "
- " date_synced, display_name, icon_url,"
- " federation_url, skip_zero_click, generation_upload_status) VALUES "
- "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+ DCHECK(!add_statement_.empty());
+ sql::Statement s(
+ db_.GetCachedStatement(SQL_FROM_HERE, add_statement_.c_str()));
BindAddStatement(form, encrypted_password, &s);
db_.set_error_callback(base::Bind(&AddCallback));
const bool success = s.Run();
@@ -875,16 +817,9 @@ PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form) {
return list;
}
// Repeat the same statement but with REPLACE semantic.
- s.Assign(db_.GetCachedStatement(
- SQL_FROM_HERE,
- "INSERT OR REPLACE INTO logins "
- "(origin_url, action_url, username_element, username_value, "
- " password_element, password_value, submit_element, "
- " signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
- " scheme, password_type, possible_usernames, times_used, form_data, "
- " date_synced, display_name, icon_url,"
- " federation_url, skip_zero_click, generation_upload_status) VALUES "
- "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+ DCHECK(!add_replace_statement_.empty());
+ s.Assign(
+ db_.GetCachedStatement(SQL_FROM_HERE, add_replace_statement_.c_str()));
BindAddStatement(form, encrypted_password, &s);
if (s.Run()) {
list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
@@ -905,44 +840,25 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) {
#endif
// Replacement is necessary to deal with updating imported credentials. See
// crbug.com/349138 for details.
- sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
- "UPDATE OR REPLACE logins SET "
- "action_url = ?, "
- "password_value = ?, "
- "ssl_valid = ?, "
- "preferred = ?, "
- "possible_usernames = ?, "
- "times_used = ?, "
- "submit_element = ?, "
- "date_synced = ?, "
- "date_created = ?, "
- "blacklisted_by_user = ?, "
- "scheme = ?, "
- "password_type = ?, "
- "display_name = ?, "
- "icon_url = ?, "
- "federation_url = ?, "
- "skip_zero_click = ?, "
- "generation_upload_status = ? "
- "WHERE origin_url = ? AND "
- "username_element = ? AND "
- "username_value = ? AND "
- "password_element = ? AND "
- "signon_realm = ?"));
+ DCHECK(!update_statement_.empty());
+ sql::Statement s(
+ db_.GetCachedStatement(SQL_FROM_HERE, update_statement_.c_str()));
s.BindString(0, form.action.spec());
s.BindBlob(1, encrypted_password.data(),
static_cast<int>(encrypted_password.length()));
- s.BindInt(2, form.ssl_valid);
+ s.BindString16(2, form.submit_element);
s.BindInt(3, form.preferred);
+ s.BindInt64(4, form.date_created.ToInternalValue());
+ s.BindInt(5, form.blacklisted_by_user);
+ s.BindInt(6, form.scheme);
+ s.BindInt(7, form.type);
base::Pickle pickle = SerializeVector(form.other_possible_usernames);
- s.BindBlob(4, pickle.data(), pickle.size());
- s.BindInt(5, form.times_used);
- s.BindString16(6, form.submit_element);
- s.BindInt64(7, form.date_synced.ToInternalValue());
- s.BindInt64(8, form.date_created.ToInternalValue());
- s.BindInt(9, form.blacklisted_by_user);
- s.BindInt(10, form.scheme);
- s.BindInt(11, form.type);
+ s.BindBlob(8, pickle.data(), pickle.size());
+ s.BindInt(9, form.times_used);
+ base::Pickle form_data_pickle;
+ autofill::SerializeFormData(form.form_data, &form_data_pickle);
+ s.BindBlob(10, form_data_pickle.data(), form_data_pickle.size());
+ s.BindInt64(11, form.date_synced.ToInternalValue());
s.BindString16(12, form.display_name);
s.BindString(13, form.icon_url.spec());
// An empty Origin serializes as "null" which would be strange to store here.
@@ -979,20 +895,14 @@ bool LoginDatabase::RemoveLogin(const PasswordForm& form) {
DeleteEncryptedPassword(form);
#endif
// Remove a login by UNIQUE-constrained fields.
- sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
- "DELETE FROM logins WHERE "
- "origin_url = ? AND "
- "username_element = ? AND "
- "username_value = ? AND "
- "password_element = ? AND "
- "submit_element = ? AND "
- "signon_realm = ? "));
+ DCHECK(!delete_statement_.empty());
+ sql::Statement s(
+ db_.GetCachedStatement(SQL_FROM_HERE, delete_statement_.c_str()));
s.BindString(0, form.origin.spec());
s.BindString16(1, form.username_element);
s.BindString16(2, form.username_value);
s.BindString16(3, form.password_element);
- s.BindString16(4, form.submit_element);
- s.BindString(5, form.signon_realm);
+ s.BindString(4, form.signon_realm);
return s.Run() && db_.GetLastChangeCount() > 0;
}
@@ -1034,22 +944,18 @@ bool LoginDatabase::RemoveLoginsSyncedBetween(base::Time delete_begin,
bool LoginDatabase::GetAutoSignInLogins(
ScopedVector<autofill::PasswordForm>* forms) const {
DCHECK(forms);
- sql::Statement s(db_.GetCachedStatement(
- SQL_FROM_HERE,
- "SELECT origin_url, action_url, username_element, username_value, "
- "password_element, password_value, submit_element, signon_realm, "
- "ssl_valid, preferred, date_created, blacklisted_by_user, "
- "scheme, password_type, possible_usernames, times_used, form_data, "
- "date_synced, display_name, icon_url, "
- "federation_url, skip_zero_click, generation_upload_status FROM logins "
- "WHERE skip_zero_click = 0 ORDER BY origin_url"));
+ DCHECK(!autosignin_statement_.empty());
+ sql::Statement s(
+ db_.GetCachedStatement(SQL_FROM_HERE, autosignin_statement_.c_str()));
return StatementToForms(&s, nullptr, forms);
}
-bool LoginDatabase::DisableAutoSignInForAllLogins() {
+bool LoginDatabase::DisableAutoSignInForOrigin(const GURL& origin) {
sql::Statement s(db_.GetCachedStatement(
- SQL_FROM_HERE, "UPDATE logins SET skip_zero_click = 1;"));
+ SQL_FROM_HERE,
+ "UPDATE logins SET skip_zero_click = 1 WHERE origin_url = ?;"));
+ s.BindString(0, origin.spec());
return s.Run();
}
@@ -1057,7 +963,7 @@ bool LoginDatabase::DisableAutoSignInForAllLogins() {
// static
LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
PasswordForm* form,
- sql::Statement& s) {
+ const sql::Statement& s) {
std::string encrypted_password;
s.ColumnBlobAsString(COLUMN_PASSWORD_VALUE, &encrypted_password);
base::string16 decrypted_password;
@@ -1080,7 +986,6 @@ LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
form->submit_element = s.ColumnString16(COLUMN_SUBMIT_ELEMENT);
tmp = s.ColumnString(COLUMN_SIGNON_REALM);
form->signon_realm = tmp;
- form->ssl_valid = (s.ColumnInt(COLUMN_SSL_VALID) > 0);
form->preferred = (s.ColumnInt(COLUMN_PREFERRED) > 0);
form->date_created =
base::Time::FromInternalValue(s.ColumnInt64(COLUMN_DATE_CREATED));
@@ -1129,33 +1034,30 @@ LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
}
bool LoginDatabase::GetLogins(
- const PasswordForm& form,
- ScopedVector<autofill::PasswordForm>* forms) const {
+ const PasswordStore::FormDigest& form,
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) const {
DCHECK(forms);
- // You *must* change LoginTableColumns if this query changes.
- std::string sql_query =
- "SELECT origin_url, action_url, "
- "username_element, username_value, "
- "password_element, password_value, submit_element, "
- "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
- "scheme, password_type, possible_usernames, times_used, form_data, "
- "date_synced, display_name, icon_url, "
- "federation_url, skip_zero_click, generation_upload_status "
- "FROM logins WHERE signon_realm == ? ";
const GURL signon_realm(form.signon_realm);
std::string registered_domain = GetRegistryControlledDomain(signon_realm);
const bool should_PSL_matching_apply =
form.scheme == PasswordForm::SCHEME_HTML &&
ShouldPSLDomainMatchingApply(registered_domain);
const bool should_federated_apply = form.scheme == PasswordForm::SCHEME_HTML;
- if (should_PSL_matching_apply)
- sql_query += "OR signon_realm REGEXP ? ";
- if (should_federated_apply)
- sql_query += "OR (signon_realm LIKE ? AND password_type == 2) ";
+ DCHECK(!get_statement_.empty());
+ DCHECK(!get_statement_psl_.empty());
+ DCHECK(!get_statement_federated_.empty());
+ DCHECK(!get_statement_psl_federated_.empty());
+ const std::string* sql_query = &get_statement_;
+ if (should_PSL_matching_apply && should_federated_apply)
+ sql_query = &get_statement_psl_federated_;
+ else if (should_PSL_matching_apply)
+ sql_query = &get_statement_psl_;
+ else if (should_federated_apply)
+ sql_query = &get_statement_federated_;
// TODO(nyquist) Consider usage of GetCachedStatement when
// http://crbug.com/248608 is fixed.
- sql::Statement s(db_.GetUniqueStatement(sql_query.c_str()));
+ sql::Statement s(db_.GetUniqueStatement(sql_query->c_str()));
s.BindString(0, form.signon_realm);
int placeholder = 1;
@@ -1197,9 +1099,17 @@ bool LoginDatabase::GetLogins(
PSL_DOMAIN_MATCH_COUNT);
}
- return StatementToForms(
+ ScopedVector<autofill::PasswordForm> forms_scopedvector;
+ bool success = StatementToForms(
&s, should_PSL_matching_apply || should_federated_apply ? &form : nullptr,
- forms);
+ &forms_scopedvector);
+ if (success) {
+ *forms = password_manager_util::ConvertScopedVector(
+ std::move(forms_scopedvector));
+ return true;
+ }
+ forms->clear();
+ return false;
}
bool LoginDatabase::GetLoginsCreatedBetween(
@@ -1207,17 +1117,9 @@ bool LoginDatabase::GetLoginsCreatedBetween(
const base::Time end,
ScopedVector<autofill::PasswordForm>* forms) const {
DCHECK(forms);
- sql::Statement s(db_.GetCachedStatement(
- SQL_FROM_HERE,
- "SELECT origin_url, action_url, "
- "username_element, username_value, "
- "password_element, password_value, submit_element, "
- "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
- "scheme, password_type, possible_usernames, times_used, form_data, "
- "date_synced, display_name, icon_url, "
- "federation_url, skip_zero_click, generation_upload_status FROM logins "
- "WHERE date_created >= ? AND date_created < ?"
- "ORDER BY origin_url"));
+ DCHECK(!created_statement_.empty());
+ sql::Statement s(
+ db_.GetCachedStatement(SQL_FROM_HERE, created_statement_.c_str()));
s.BindInt64(0, begin.ToInternalValue());
s.BindInt64(1, end.is_null() ? std::numeric_limits<int64_t>::max()
: end.ToInternalValue());
@@ -1230,16 +1132,9 @@ bool LoginDatabase::GetLoginsSyncedBetween(
const base::Time end,
ScopedVector<autofill::PasswordForm>* forms) const {
DCHECK(forms);
- sql::Statement s(db_.GetCachedStatement(
- SQL_FROM_HERE,
- "SELECT origin_url, action_url, username_element, username_value, "
- "password_element, password_value, submit_element, signon_realm, "
- "ssl_valid, preferred, date_created, blacklisted_by_user, "
- "scheme, password_type, possible_usernames, times_used, form_data, "
- "date_synced, display_name, icon_url, "
- "federation_url, skip_zero_click, generation_upload_status FROM logins "
- "WHERE date_synced >= ? AND date_synced < ?"
- "ORDER BY origin_url"));
+ DCHECK(!synced_statement_.empty());
+ sql::Statement s(
+ db_.GetCachedStatement(SQL_FROM_HERE, synced_statement_.c_str()));
s.BindInt64(0, begin.ToInternalValue());
s.BindInt64(1,
end.is_null() ? base::Time::Max().ToInternalValue()
@@ -1249,33 +1144,33 @@ bool LoginDatabase::GetLoginsSyncedBetween(
}
bool LoginDatabase::GetAutofillableLogins(
- ScopedVector<autofill::PasswordForm>* forms) const {
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) const {
return GetAllLoginsWithBlacklistSetting(false, forms);
}
bool LoginDatabase::GetBlacklistLogins(
- ScopedVector<autofill::PasswordForm>* forms) const {
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) const {
return GetAllLoginsWithBlacklistSetting(true, forms);
}
bool LoginDatabase::GetAllLoginsWithBlacklistSetting(
bool blacklisted,
- ScopedVector<autofill::PasswordForm>* forms) const {
+ std::vector<std::unique_ptr<PasswordForm>>* forms) const {
DCHECK(forms);
- // You *must* change LoginTableColumns if this query changes.
- sql::Statement s(db_.GetCachedStatement(
- SQL_FROM_HERE,
- "SELECT origin_url, action_url, "
- "username_element, username_value, "
- "password_element, password_value, submit_element, "
- "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
- "scheme, password_type, possible_usernames, times_used, form_data, "
- "date_synced, display_name, icon_url, "
- "federation_url, skip_zero_click, generation_upload_status FROM logins "
- "WHERE blacklisted_by_user == ? ORDER BY origin_url"));
+ DCHECK(!blacklisted_statement_.empty());
+ sql::Statement s(
+ db_.GetCachedStatement(SQL_FROM_HERE, blacklisted_statement_.c_str()));
s.BindInt(0, blacklisted ? 1 : 0);
- return StatementToForms(&s, nullptr, forms);
+ ScopedVector<autofill::PasswordForm> forms_scopedvector;
+ bool success = StatementToForms(&s, nullptr, &forms_scopedvector);
+ if (success) {
+ *forms = password_manager_util::ConvertScopedVector(
+ std::move(forms_scopedvector));
+ return true;
+ }
+ forms->clear();
+ return false;
}
bool LoginDatabase::DeleteAndRecreateDatabaseFile() {
@@ -1288,22 +1183,15 @@ bool LoginDatabase::DeleteAndRecreateDatabaseFile() {
std::string LoginDatabase::GetEncryptedPassword(
const autofill::PasswordForm& form) const {
+ DCHECK(!encrypted_statement_.empty());
sql::Statement s(
- db_.GetCachedStatement(SQL_FROM_HERE,
- "SELECT password_value FROM logins WHERE "
- "origin_url = ? AND "
- "username_element = ? AND "
- "username_value = ? AND "
- "password_element = ? AND "
- "submit_element = ? AND "
- "signon_realm = ? "));
+ db_.GetCachedStatement(SQL_FROM_HERE, encrypted_statement_.c_str()));
s.BindString(0, form.origin.spec());
s.BindString16(1, form.username_element);
s.BindString16(2, form.username_value);
s.BindString16(3, form.password_element);
- s.BindString16(4, form.submit_element);
- s.BindString(5, form.signon_realm);
+ s.BindString(4, form.signon_realm);
std::string encrypted_password;
if (s.Step()) {
@@ -1315,7 +1203,7 @@ std::string LoginDatabase::GetEncryptedPassword(
// static
bool LoginDatabase::StatementToForms(
sql::Statement* statement,
- const autofill::PasswordForm* matched_form,
+ const PasswordStore::FormDigest* matched_form,
ScopedVector<autofill::PasswordForm>* forms) {
PSLDomainMatchMetric psl_domain_match_metric = PSL_DOMAIN_MATCH_NONE;
@@ -1357,4 +1245,68 @@ bool LoginDatabase::StatementToForms(
return true;
}
+void LoginDatabase::InitializeStatementStrings(const SQLTableBuilder& builder) {
+ // This method may be called multiple times, if Chrome switches backends and
+ // LoginDatabase::DeleteAndRecreateDatabaseFile ends up being called. In those
+ // case do not recompute the SQL statements, because they would end up the
+ // same.
+ if (!add_statement_.empty())
+ return;
+
+ // Initialize the cached strings.
+ std::string all_column_names = builder.ListAllColumnNames();
+ std::string right_amount_of_placeholders =
+ GeneratePlaceholders(builder.NumberOfColumns());
+ std::string all_unique_key_column_names = builder.ListAllUniqueKeyNames();
+ std::string all_nonunique_key_column_names =
+ builder.ListAllNonuniqueKeyNames();
+
+ add_statement_ = "INSERT INTO logins (" + all_column_names + ") VALUES " +
+ right_amount_of_placeholders;
+ DCHECK(add_replace_statement_.empty());
+ add_replace_statement_ = "INSERT OR REPLACE INTO logins (" +
+ all_column_names + ") VALUES " +
+ right_amount_of_placeholders;
+ DCHECK(update_statement_.empty());
+ update_statement_ = "UPDATE OR REPLACE logins SET " +
+ all_nonunique_key_column_names + " WHERE " +
+ all_unique_key_column_names;
+ DCHECK(delete_statement_.empty());
+ delete_statement_ = "DELETE FROM logins WHERE " + all_unique_key_column_names;
+ DCHECK(autosignin_statement_.empty());
+ autosignin_statement_ = "SELECT " + all_column_names +
+ " FROM logins "
+ "WHERE skip_zero_click = 0 ORDER BY origin_url";
+ DCHECK(get_statement_.empty());
+ get_statement_ = "SELECT " + all_column_names +
+ " FROM logins "
+ "WHERE signon_realm == ?";
+ std::string psl_statement = "OR signon_realm REGEXP ? ";
+ std::string federated_statement =
+ "OR (signon_realm LIKE ? AND password_type == 2) ";
+ DCHECK(get_statement_psl_.empty());
+ get_statement_psl_ = get_statement_ + psl_statement;
+ DCHECK(get_statement_federated_.empty());
+ get_statement_federated_ = get_statement_ + federated_statement;
+ DCHECK(get_statement_psl_federated_.empty());
+ get_statement_psl_federated_ =
+ get_statement_ + psl_statement + federated_statement;
+ DCHECK(created_statement_.empty());
+ created_statement_ =
+ "SELECT " + all_column_names +
+ " FROM logins WHERE date_created >= ? AND date_created < "
+ "? ORDER BY origin_url";
+ DCHECK(synced_statement_.empty());
+ synced_statement_ = "SELECT " + all_column_names +
+ " FROM logins WHERE date_synced >= ? AND date_synced < "
+ "? ORDER BY origin_url";
+ DCHECK(blacklisted_statement_.empty());
+ blacklisted_statement_ =
+ "SELECT " + all_column_names +
+ " FROM logins WHERE blacklisted_by_user == ? ORDER BY origin_url";
+ DCHECK(encrypted_statement_.empty());
+ encrypted_statement_ =
+ "SELECT password_value FROM logins WHERE " + all_unique_key_column_names;
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/login_database.h b/chromium/components/password_manager/core/browser/login_database.h
index c992f3eb159..4be14f0248e 100644
--- a/chromium/components/password_manager/core/browser/login_database.h
+++ b/chromium/components/password_manager/core/browser/login_database.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LOGIN_DATABASE_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LOGIN_DATABASE_H_
+#include <memory>
#include <string>
#include <vector>
@@ -28,6 +29,8 @@
namespace password_manager {
+class SQLTableBuilder;
+
extern const int kCurrentVersionNumber;
extern const int kCompatibleVersionNumber;
@@ -36,7 +39,7 @@ extern const int kCompatibleVersionNumber;
// the login information.
class LoginDatabase {
public:
- LoginDatabase(const base::FilePath& db_path);
+ explicit LoginDatabase(const base::FilePath& db_path);
virtual ~LoginDatabase();
// Actually creates/opens the database. If false is returned, no other method
@@ -77,17 +80,17 @@ class LoginDatabase {
bool RemoveLoginsSyncedBetween(base::Time delete_begin,
base::Time delete_end);
- // Sets the 'skip_zero_click' flag to 'true' for all logins.
- bool DisableAutoSignInForAllLogins();
+ // Sets the 'skip_zero_click' flag on all forms on |origin| to 'true'.
+ bool DisableAutoSignInForOrigin(const GURL& origin);
// All Get* methods below overwrite |forms| with the returned credentials. On
// success, those methods return true.
// Gets a list of credentials matching |form|, including blacklisted matches
// and federated credentials.
- bool GetLogins(const autofill::PasswordForm& form,
- ScopedVector<autofill::PasswordForm>* forms) const
- WARN_UNUSED_RESULT;
+ bool GetLogins(const PasswordStore::FormDigest& form,
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms)
+ const WARN_UNUSED_RESULT;
// Gets all logins created from |begin| onwards (inclusive) and before |end|.
// You may use a null Time value to do an unbounded search in either
@@ -106,12 +109,13 @@ class LoginDatabase {
WARN_UNUSED_RESULT;
// Gets the complete list of not blacklisted credentials.
- bool GetAutofillableLogins(ScopedVector<autofill::PasswordForm>* forms) const
+ bool GetAutofillableLogins(
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) const
WARN_UNUSED_RESULT;
// Gets the complete list of blacklisted credentials.
- bool GetBlacklistLogins(ScopedVector<autofill::PasswordForm>* forms) const
- WARN_UNUSED_RESULT;
+ bool GetBlacklistLogins(std::vector<std::unique_ptr<autofill::PasswordForm>>*
+ forms) const WARN_UNUSED_RESULT;
// Gets the list of auto-sign-inable credentials.
bool GetAutoSignInLogins(ScopedVector<autofill::PasswordForm>* forms) const
@@ -170,31 +174,32 @@ class LoginDatabase {
static EncryptionResult DecryptedString(const std::string& cipher_text,
base::string16* plain_text);
- bool InitLoginsTable();
- bool MigrateOldVersionsAsNeeded();
-
// Fills |form| from the values in the given statement (which is assumed to
// be of the form used by the Get*Logins methods).
// Returns the EncryptionResult from decrypting the password in |s|; if not
// ENCRYPTION_RESULT_SUCCESS, |form| is not filled.
static EncryptionResult InitPasswordFormFromStatement(
autofill::PasswordForm* form,
- sql::Statement& s);
+ const sql::Statement& s);
// Gets all blacklisted or all non-blacklisted (depending on |blacklisted|)
// credentials. On success returns true and overwrites |forms| with the
// result.
bool GetAllLoginsWithBlacklistSetting(
bool blacklisted,
- ScopedVector<autofill::PasswordForm>* forms) const;
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) const;
// Overwrites |forms| with credentials retrieved from |statement|. If
// |matched_form| is not null, filters out all results but those PSL-matching
// |*matched_form| or federated credentials for it. On success returns true.
static bool StatementToForms(sql::Statement* statement,
- const autofill::PasswordForm* matched_form,
+ const PasswordStore::FormDigest* matched_form,
ScopedVector<autofill::PasswordForm>* forms);
+ // Initializes all the *_statement_ data members with appropriate SQL
+ // fragments based on |builder|.
+ void InitializeStatementStrings(const SQLTableBuilder& builder);
+
base::FilePath db_path_;
mutable sql::Connection db_;
sql::MetaTable meta_table_;
@@ -207,6 +212,21 @@ class LoginDatabase {
// crbug.com/466638
bool clear_password_values_;
+ // These cached strings are used to build SQL statements.
+ std::string add_statement_;
+ std::string add_replace_statement_;
+ std::string update_statement_;
+ std::string delete_statement_;
+ std::string autosignin_statement_;
+ std::string get_statement_;
+ std::string get_statement_psl_;
+ std::string get_statement_federated_;
+ std::string get_statement_psl_federated_;
+ std::string created_statement_;
+ std::string synced_statement_;
+ std::string blacklisted_statement_;
+ std::string encrypted_statement_;
+
DISALLOW_COPY_AND_ASSIGN(LoginDatabase);
};
diff --git a/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc b/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
index 856cf9f28ff..b604d673e0e 100644
--- a/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
@@ -27,7 +27,7 @@ class LoginDatabaseIOSTest : public PlatformTest {
ClearKeychain();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath login_db_path =
- temp_dir_.path().AppendASCII("temp_login.db");
+ temp_dir_.GetPath().AppendASCII("temp_login.db");
login_db_.reset(new password_manager::LoginDatabase(login_db_path));
login_db_->Init();
}
@@ -116,10 +116,8 @@ TEST_F(LoginDatabaseIOSTest, UpdateLogin) {
login_db_->UpdateLogin(form);
ASSERT_EQ(1u, changes.size());
- form.password_value = base::string16();
-
ScopedVector<PasswordForm> forms;
- EXPECT_TRUE(login_db_->GetLogins(form, &forms));
+ EXPECT_TRUE(login_db_->GetLogins(PasswordStore::FormDigest(form), &forms));
ASSERT_EQ(1U, forms.size());
EXPECT_STREQ("secret", UTF16ToUTF8(forms[0]->password_value).c_str());
@@ -138,7 +136,7 @@ TEST_F(LoginDatabaseIOSTest, RemoveLogin) {
ignore_result(login_db_->RemoveLogin(form));
ScopedVector<PasswordForm> forms;
- EXPECT_TRUE(login_db_->GetLogins(form, &forms));
+ EXPECT_TRUE(login_db_->GetLogins(PasswordStore::FormDigest(form), &forms));
ASSERT_EQ(0U, forms.size());
ASSERT_EQ(0U, GetKeychainSize());
@@ -171,8 +169,8 @@ TEST_F(LoginDatabaseIOSTest, RemoveLoginsCreatedBetween) {
login_db_->RemoveLoginsCreatedBetween(base::Time::FromDoubleT(150),
base::Time::FromDoubleT(250));
- PasswordForm form;
- form.signon_realm = "http://www.example.com";
+ PasswordStore::FormDigest form = {PasswordForm::SCHEME_HTML,
+ "http://www.example.com", GURL()};
ScopedVector<PasswordForm> logins;
EXPECT_TRUE(login_db_->GetLogins(form, &logins));
diff --git a/chromium/components/password_manager/core/browser/login_database_unittest.cc b/chromium/components/password_manager/core/browser/login_database_unittest.cc
index abf7ab0350e..757e82e1b90 100644
--- a/chromium/components/password_manager/core/browser/login_database_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_unittest.cc
@@ -33,9 +33,12 @@
using autofill::PasswordForm;
using base::ASCIIToUTF16;
using ::testing::Eq;
+using ::testing::Pointee;
+using ::testing::UnorderedElementsAre;
namespace password_manager {
namespace {
+
PasswordStoreChangeList AddChangeForForm(const PasswordForm& form) {
return PasswordStoreChangeList(
1, PasswordStoreChange(PasswordStoreChange::ADD, form));
@@ -55,7 +58,6 @@ void GenerateExamplePasswordForm(PasswordForm* form) {
form->password_value = ASCIIToUTF16("test");
form->submit_element = ASCIIToUTF16("signIn");
form->signon_realm = "http://www.google.com/";
- form->ssl_valid = false;
form->preferred = false;
form->scheme = PasswordForm::SCHEME_HTML;
form->times_used = 1;
@@ -88,18 +90,19 @@ template<> std::string GetFirstColumn(const sql::Statement& s) {
}
bool AddZeroClickableLogin(LoginDatabase* db,
- const std::string& unique_string) {
+ const std::string& unique_string,
+ const GURL& origin) {
// Example password form.
PasswordForm form;
- form.origin = GURL("https://example.com/");
+ form.origin = origin;
form.username_element = ASCIIToUTF16(unique_string);
form.username_value = ASCIIToUTF16(unique_string);
form.password_element = ASCIIToUTF16(unique_string);
form.submit_element = ASCIIToUTF16("signIn");
form.signon_realm = form.origin.spec();
form.display_name = ASCIIToUTF16(unique_string);
- form.icon_url = GURL("https://example.com/");
- form.federation_origin = url::Origin(GURL("https://example.com/"));
+ form.icon_url = origin;
+ form.federation_origin = url::Origin(origin);
form.date_created = base::Time::Now();
form.skip_zero_click = false;
@@ -107,6 +110,24 @@ bool AddZeroClickableLogin(LoginDatabase* db,
return db->AddLogin(form) == AddChangeForForm(form);
}
+MATCHER(IsGoogle1Account, "") {
+ return arg.origin.spec() == "https://accounts.google.com/ServiceLogin" &&
+ arg.action.spec() == "https://accounts.google.com/ServiceLoginAuth" &&
+ arg.username_value == ASCIIToUTF16("theerikchen") &&
+ arg.scheme == PasswordForm::SCHEME_HTML;
+}
+
+MATCHER(IsGoogle2Account, "") {
+ return arg.origin.spec() == "https://accounts.google.com/ServiceLogin" &&
+ arg.action.spec() == "https://accounts.google.com/ServiceLoginAuth" &&
+ arg.username_value == ASCIIToUTF16("theerikchen2") &&
+ arg.scheme == PasswordForm::SCHEME_HTML;
+}
+
+MATCHER(IsBasicAuthAccount, "") {
+ return arg.scheme == PasswordForm::SCHEME_BASIC;
+}
+
} // namespace
// Serialization routines for vectors implemented in login_database.cc.
@@ -117,7 +138,7 @@ class LoginDatabaseTest : public testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- file_ = temp_dir_.path().AppendASCII("TestMetadataStoreMacDatabase");
+ file_ = temp_dir_.GetPath().AppendASCII("TestMetadataStoreMacDatabase");
OSCryptMocker::SetUpWithSingleton();
db_.reset(new LoginDatabase(file_));
@@ -129,7 +150,7 @@ class LoginDatabaseTest : public testing::Test {
LoginDatabase& db() { return *db_; }
void TestNonHTMLFormPSLMatching(const PasswordForm::Scheme& scheme) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
base::Time now = base::Time::Now();
@@ -160,16 +181,17 @@ class LoginDatabaseTest : public testing::Test {
EXPECT_EQ(2U, result.size());
result.clear();
- PasswordForm second_non_html_auth(non_html_auth);
- second_non_html_auth.origin = GURL("http://second.example.com");
- second_non_html_auth.signon_realm = "http://second.example.com/Realm";
+ PasswordStore::FormDigest second_non_html_auth = {
+ scheme, "http://second.example.com/Realm",
+ GURL("http://second.example.com")};
// This shouldn't match anything.
EXPECT_TRUE(db().GetLogins(second_non_html_auth, &result));
EXPECT_EQ(0U, result.size());
// non-html auth still matches against itself.
- EXPECT_TRUE(db().GetLogins(non_html_auth, &result));
+ EXPECT_TRUE(
+ db().GetLogins(PasswordStore::FormDigest(non_html_auth), &result));
ASSERT_EQ(1U, result.size());
EXPECT_EQ(result[0]->signon_realm, "http://example.com/Realm");
@@ -181,7 +203,7 @@ class LoginDatabaseTest : public testing::Test {
// retrieved from the database.
void TestRetrievingIPAddress(const PasswordForm::Scheme& scheme) {
SCOPED_TRACE(testing::Message() << "scheme = " << scheme);
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
base::Time now = base::Time::Now();
std::string origin("http://56.7.8.90");
@@ -195,7 +217,7 @@ class LoginDatabaseTest : public testing::Test {
ip_form.date_created = now;
EXPECT_EQ(AddChangeForForm(ip_form), db().AddLogin(ip_form));
- EXPECT_TRUE(db().GetLogins(ip_form, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(ip_form), &result));
ASSERT_EQ(1U, result.size());
EXPECT_EQ(result[0]->signon_realm, origin);
@@ -209,7 +231,7 @@ class LoginDatabaseTest : public testing::Test {
};
TEST_F(LoginDatabaseTest, Logins) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
// Verify the database is empty.
EXPECT_TRUE(db().GetAutofillableLogins(&result));
@@ -228,7 +250,7 @@ TEST_F(LoginDatabaseTest, Logins) {
result.clear();
// Match against an exact copy.
- EXPECT_TRUE(db().GetLogins(form, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
ASSERT_EQ(1U, result.size());
EXPECT_EQ(form, *result[0]);
result.clear();
@@ -239,7 +261,7 @@ TEST_F(LoginDatabaseTest, Logins) {
form2.submit_element = ASCIIToUTF16("reallySignIn");
// Match against an inexact copy
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(1U, result.size());
result.clear();
@@ -248,17 +270,16 @@ TEST_F(LoginDatabaseTest, Logins) {
form3.action = GURL("http://www.google.com/new/accounts/Login");
// signon_realm is the same, should match.
- EXPECT_TRUE(db().GetLogins(form3, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form3), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// Imagine the site moves to a secure server for login.
PasswordForm form4(form3);
form4.signon_realm = "https://www.google.com/";
- form4.ssl_valid = true;
// We have only an http record, so no match for this.
- EXPECT_TRUE(db().GetLogins(form4, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form4), &result));
EXPECT_EQ(0U, result.size());
// Let's imagine the user logs into the secure site.
@@ -268,7 +289,7 @@ TEST_F(LoginDatabaseTest, Logins) {
result.clear();
// Now the match works
- EXPECT_TRUE(db().GetLogins(form4, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form4), &result));
EXPECT_EQ(1U, result.size());
result.clear();
@@ -279,38 +300,28 @@ TEST_F(LoginDatabaseTest, Logins) {
result.clear();
// The old form wont match the new site (http vs https).
- EXPECT_TRUE(db().GetLogins(form, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
EXPECT_EQ(0U, result.size());
- // The user's request for the HTTPS site is intercepted
- // by an attacker who presents an invalid SSL cert.
- PasswordForm form5(form4);
- form5.ssl_valid = 0;
-
- // It will match in this case.
- EXPECT_TRUE(db().GetLogins(form5, &result));
- EXPECT_EQ(1U, result.size());
- result.clear();
-
// User changes their password.
- PasswordForm form6(form5);
- form6.password_value = ASCIIToUTF16("test6");
- form6.preferred = true;
+ PasswordForm form5(form4);
+ form5.password_value = ASCIIToUTF16("test6");
+ form5.preferred = true;
// We update, and check to make sure it matches the
// old form, and there is only one record.
- EXPECT_EQ(UpdateChangeForForm(form6), db().UpdateLogin(form6));
+ EXPECT_EQ(UpdateChangeForForm(form5), db().UpdateLogin(form5));
// matches
- EXPECT_TRUE(db().GetLogins(form5, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form5), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// Only one record.
EXPECT_TRUE(db().GetAutofillableLogins(&result));
EXPECT_EQ(1U, result.size());
// Password element was updated.
- EXPECT_EQ(form6.password_value, result[0]->password_value);
+ EXPECT_EQ(form5.password_value, result[0]->password_value);
// Preferred login.
- EXPECT_TRUE(form6.preferred);
+ EXPECT_TRUE(form5.preferred);
result.clear();
// Make sure everything can disappear.
@@ -320,7 +331,7 @@ TEST_F(LoginDatabaseTest, Logins) {
}
TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
// Verify the database is empty.
EXPECT_TRUE(db().GetAutofillableLogins(&result));
@@ -336,7 +347,6 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) {
form.password_value = ASCIIToUTF16("test");
form.submit_element = ASCIIToUTF16("");
form.signon_realm = "https://foo.com/";
- form.ssl_valid = true;
form.preferred = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -347,7 +357,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) {
result.clear();
// Match against an exact copy.
- EXPECT_TRUE(db().GetLogins(form, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
EXPECT_EQ(1U, result.size());
result.clear();
@@ -358,7 +368,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) {
form2.signon_realm = "https://mobile.foo.com/";
// Match against the mobile site.
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(1U, result.size());
EXPECT_EQ("https://foo.com/", result[0]->signon_realm);
EXPECT_TRUE(result[0]->is_public_suffix_match);
@@ -367,13 +377,13 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) {
EXPECT_FALSE(db().RemoveLogin(*result[0]));
result.clear();
// Ensure that the original form is still there
- EXPECT_TRUE(db().GetLogins(form, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
EXPECT_EQ(1U, result.size());
result.clear();
}
TEST_F(LoginDatabaseTest, TestFederatedMatching) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
// Example password form.
PasswordForm form;
@@ -382,7 +392,6 @@ TEST_F(LoginDatabaseTest, TestFederatedMatching) {
form.username_value = ASCIIToUTF16("test@gmail.com");
form.password_value = ASCIIToUTF16("test");
form.signon_realm = "https://foo.com/";
- form.ssl_valid = true;
form.preferred = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -402,20 +411,17 @@ TEST_F(LoginDatabaseTest, TestFederatedMatching) {
EXPECT_EQ(2U, result.size());
// Match against desktop.
- PasswordForm form_request;
- form_request.origin = GURL("https://foo.com/");
- form_request.signon_realm = "https://foo.com/";
- form_request.scheme = PasswordForm::SCHEME_HTML;
+ PasswordStore::FormDigest form_request = {
+ PasswordForm::SCHEME_HTML, "https://foo.com/", GURL("https://foo.com/")};
EXPECT_TRUE(db().GetLogins(form_request, &result));
- EXPECT_THAT(result, testing::ElementsAre(testing::Pointee(form)));
+ EXPECT_THAT(result, testing::ElementsAre(Pointee(form)));
// Match against the mobile site.
form_request.origin = GURL("https://mobile.foo.com/");
form_request.signon_realm = "https://mobile.foo.com/";
EXPECT_TRUE(db().GetLogins(form_request, &result));
form.is_public_suffix_match = true;
- EXPECT_THAT(result, testing::UnorderedElementsAre(testing::Pointee(form),
- testing::Pointee(form2)));
+ EXPECT_THAT(result, UnorderedElementsAre(Pointee(form), Pointee(form2)));
}
TEST_F(LoginDatabaseTest, TestPublicSuffixDisabledForNonHTMLForms) {
@@ -441,7 +447,7 @@ TEST_F(LoginDatabaseTest, TestIPAddressMatches_other) {
}
TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
// Verify the database is empty.
EXPECT_TRUE(db().GetAutofillableLogins(&result));
@@ -457,7 +463,6 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) {
form.password_value = ASCIIToUTF16("test");
form.submit_element = ASCIIToUTF16("");
form.signon_realm = "https://accounts.google.com/";
- form.ssl_valid = true;
form.preferred = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -468,15 +473,14 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) {
result.clear();
// Match against an exact copy.
- EXPECT_TRUE(db().GetLogins(form, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// We go to a different site on the same domain where feature is not needed.
- PasswordForm form2(form);
- form2.origin = GURL("https://some.other.google.com/");
- form2.action = GURL("https://some.other.google.com/login");
- form2.signon_realm = "https://some.other.google.com/";
+ PasswordStore::FormDigest form2 = {PasswordForm::SCHEME_HTML,
+ "https://some.other.google.com/",
+ GURL("https://some.other.google.com/")};
// Match against the other site. Should not match since feature should not be
// enabled for this domain.
@@ -488,7 +492,7 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) {
}
TEST_F(LoginDatabaseTest, TestFederatedMatchingWithoutPSLMatching) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
// Example password form.
PasswordForm form;
@@ -497,7 +501,6 @@ TEST_F(LoginDatabaseTest, TestFederatedMatchingWithoutPSLMatching) {
form.username_value = ASCIIToUTF16("test@gmail.com");
form.password_value = ASCIIToUTF16("test");
form.signon_realm = "https://accounts.google.com/";
- form.ssl_valid = true;
form.preferred = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -517,12 +520,10 @@ TEST_F(LoginDatabaseTest, TestFederatedMatchingWithoutPSLMatching) {
EXPECT_EQ(2U, result.size());
// Match against the first one.
- PasswordForm form_request;
- form_request.origin = form.origin;
- form_request.signon_realm = form.signon_realm;
- form_request.scheme = PasswordForm::SCHEME_HTML;
+ PasswordStore::FormDigest form_request = {PasswordForm::SCHEME_HTML,
+ form.signon_realm, form.origin};
EXPECT_TRUE(db().GetLogins(form_request, &result));
- EXPECT_THAT(result, testing::ElementsAre(testing::Pointee(form)));
+ EXPECT_THAT(result, testing::ElementsAre(Pointee(form)));
// Match against the second one.
ASSERT_FALSE(ShouldPSLDomainMatchingApply(
@@ -531,14 +532,14 @@ TEST_F(LoginDatabaseTest, TestFederatedMatchingWithoutPSLMatching) {
form_request.signon_realm = form2.signon_realm;
EXPECT_TRUE(db().GetLogins(form_request, &result));
form.is_public_suffix_match = true;
- EXPECT_THAT(result, testing::ElementsAre(testing::Pointee(form2)));
+ EXPECT_THAT(result, testing::ElementsAre(Pointee(form2)));
}
// This test fails if the implementation of GetLogins uses GetCachedStatement
// instead of GetUniqueStatement, since REGEXP is in use. See
// http://crbug.com/248608.
TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
// Verify the database is empty.
EXPECT_TRUE(db().GetAutofillableLogins(&result));
@@ -554,7 +555,6 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
form.password_value = ASCIIToUTF16("test");
form.submit_element = ASCIIToUTF16("");
form.signon_realm = "https://foo.com/";
- form.ssl_valid = true;
form.preferred = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -565,14 +565,13 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
result.clear();
// Match against an exact copy.
- EXPECT_TRUE(db().GetLogins(form, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// We go to the mobile site.
- PasswordForm form2(form);
+ PasswordStore::FormDigest form2(form);
form2.origin = GURL("https://mobile.foo.com/");
- form2.action = GURL("https://mobile.foo.com/login");
form2.signon_realm = "https://mobile.foo.com/";
// Match against the mobile site.
@@ -591,7 +590,6 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
form.password_value = ASCIIToUTF16("test");
form.submit_element = ASCIIToUTF16("");
form.signon_realm = "https://baz.com/";
- form.ssl_valid = true;
form.preferred = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -602,9 +600,8 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
result.clear();
// We go to the mobile site of baz.com.
- PasswordForm form3(form);
+ PasswordStore::FormDigest form3(form);
form3.origin = GURL("https://m.baz.com/login/");
- form3.action = GURL("https://m.baz.com/login/");
form3.signon_realm = "https://m.baz.com/";
// Match against the mobile site of baz.com.
@@ -625,7 +622,7 @@ PasswordForm GetFormWithNewSignonRealm(PasswordForm form,
}
TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
// Verify the database is empty.
EXPECT_TRUE(db().GetAutofillableLogins(&result));
@@ -641,7 +638,6 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) {
form.password_value = ASCIIToUTF16("test");
form.submit_element = ASCIIToUTF16("");
form.signon_realm = "http://foo.com/";
- form.ssl_valid = false;
form.preferred = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -662,75 +658,75 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) {
result.clear();
// Match against an exact copy.
- EXPECT_TRUE(db().GetLogins(form, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// www.foo.com should match.
PasswordForm form2 = GetFormWithNewSignonRealm(form, "http://www.foo.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// a.b.foo.com should match.
form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// a-b.foo.com should match.
form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// foo-bar.com should match.
form2 = GetFormWithNewSignonRealm(form, "http://foo-bar.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// www.foo-bar.com should match.
form2 = GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// a.b.foo-bar.com should match.
form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo-bar.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// a-b.foo-bar.com should match.
form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo-bar.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(1U, result.size());
result.clear();
// foo.com with port 1337 should not match.
form2 = GetFormWithNewSignonRealm(form, "http://foo.com:1337/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(0U, result.size());
// http://foo.com should not match since the scheme is wrong.
form2 = GetFormWithNewSignonRealm(form, "https://foo.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(0U, result.size());
// notfoo.com should not match.
form2 = GetFormWithNewSignonRealm(form, "http://notfoo.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(0U, result.size());
// baz.com should not match.
form2 = GetFormWithNewSignonRealm(form, "http://baz.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(0U, result.size());
// foo-baz.com should not match.
form2 = GetFormWithNewSignonRealm(form, "http://foo-baz.com/");
- EXPECT_TRUE(db().GetLogins(form2, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form2), &result));
EXPECT_EQ(0U, result.size());
}
@@ -760,7 +756,7 @@ static bool AddTimestampedLogin(LoginDatabase* db,
}
TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
// Verify the database is empty.
EXPECT_TRUE(db().GetAutofillableLogins(&result));
@@ -784,10 +780,13 @@ TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) {
EXPECT_EQ(4U, result.size());
result.clear();
+ // TODO(crbug.com/555132) Replace |result_scopedvector| back with |result|.
+ ScopedVector<PasswordForm> result_scopedvector;
// Get everything from today's date and on.
- EXPECT_TRUE(db().GetLoginsCreatedBetween(now, base::Time(), &result));
- EXPECT_EQ(2U, result.size());
- result.clear();
+ EXPECT_TRUE(
+ db().GetLoginsCreatedBetween(now, base::Time(), &result_scopedvector));
+ EXPECT_EQ(2U, result_scopedvector.size());
+ result_scopedvector.clear();
// Delete everything from today's date and on.
db().RemoveLoginsCreatedBetween(now, base::Time());
@@ -806,7 +805,7 @@ TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) {
}
TEST_F(LoginDatabaseTest, RemoveLoginsSyncedBetween) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
base::Time now = base::Time::Now();
base::TimeDelta one_day = base::TimeDelta::FromDays(1);
@@ -826,12 +825,15 @@ TEST_F(LoginDatabaseTest, RemoveLoginsSyncedBetween) {
EXPECT_EQ(4U, result.size());
result.clear();
+ // TODO(crbug.com/555132) Replace |result_scopedvector| back with |result|.
+ ScopedVector<PasswordForm> result_scopedvector;
// Get everything from today's date and on.
- EXPECT_TRUE(db().GetLoginsSyncedBetween(now, base::Time(), &result));
- ASSERT_EQ(2U, result.size());
- EXPECT_EQ("http://3.com", result[0]->signon_realm);
- EXPECT_EQ("http://4.com", result[1]->signon_realm);
- result.clear();
+ EXPECT_TRUE(
+ db().GetLoginsSyncedBetween(now, base::Time(), &result_scopedvector));
+ ASSERT_EQ(2U, result_scopedvector.size());
+ EXPECT_EQ("http://3.com", result_scopedvector[0]->signon_realm);
+ EXPECT_EQ("http://4.com", result_scopedvector[1]->signon_realm);
+ result_scopedvector.clear();
// Delete everything from today's date and on.
db().RemoveLoginsSyncedBetween(now, base::Time());
@@ -852,43 +854,53 @@ TEST_F(LoginDatabaseTest, RemoveLoginsSyncedBetween) {
}
TEST_F(LoginDatabaseTest, GetAutoSignInLogins) {
- ScopedVector<autofill::PasswordForm> result;
+ ScopedVector<PasswordForm> result;
- EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo1"));
- EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo2"));
- EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo3"));
- EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo4"));
+ GURL origin("https://example.com");
+ EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo1", origin));
+ EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo2", origin));
+ EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo3", origin));
+ EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo4", origin));
EXPECT_TRUE(db().GetAutoSignInLogins(&result));
EXPECT_EQ(4U, result.size());
- for (const auto& form : result)
+ for (const auto* form : result)
EXPECT_FALSE(form->skip_zero_click);
- EXPECT_TRUE(db().DisableAutoSignInForAllLogins());
+ EXPECT_TRUE(db().DisableAutoSignInForOrigin(origin));
EXPECT_TRUE(db().GetAutoSignInLogins(&result));
EXPECT_EQ(0U, result.size());
}
-TEST_F(LoginDatabaseTest, DisableAutoSignInForAllLogins) {
- ScopedVector<autofill::PasswordForm> result;
+TEST_F(LoginDatabaseTest, DisableAutoSignInForOrigin) {
+ std::vector<std::unique_ptr<PasswordForm>> result;
- EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo1"));
- EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo2"));
- EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo3"));
- EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo4"));
+ GURL origin1("https://google.com");
+ GURL origin2("https://chrome.com");
+ GURL origin3("http://example.com");
+ GURL origin4("http://localhost");
+ EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo1", origin1));
+ EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo2", origin2));
+ EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo3", origin3));
+ EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo4", origin4));
EXPECT_TRUE(db().GetAutofillableLogins(&result));
for (const auto& form : result)
EXPECT_FALSE(form->skip_zero_click);
- EXPECT_TRUE(db().DisableAutoSignInForAllLogins());
+ EXPECT_TRUE(db().DisableAutoSignInForOrigin(origin1));
+ EXPECT_TRUE(db().DisableAutoSignInForOrigin(origin3));
EXPECT_TRUE(db().GetAutofillableLogins(&result));
- for (const auto& form : result)
- EXPECT_TRUE(form->skip_zero_click);
+ for (const auto& form : result) {
+ if (form->origin == origin1 || form->origin == origin3)
+ EXPECT_TRUE(form->skip_zero_click);
+ else
+ EXPECT_FALSE(form->skip_zero_click);
+ }
}
TEST_F(LoginDatabaseTest, BlacklistedLogins) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
// Verify the database is empty.
EXPECT_TRUE(db().GetBlacklistLogins(&result));
@@ -902,7 +914,6 @@ TEST_F(LoginDatabaseTest, BlacklistedLogins) {
form.password_element = ASCIIToUTF16("Passwd");
form.submit_element = ASCIIToUTF16("signIn");
form.signon_realm = "http://www.google.com/";
- form.ssl_valid = false;
form.preferred = true;
form.blacklisted_by_user = true;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -918,12 +929,12 @@ TEST_F(LoginDatabaseTest, BlacklistedLogins) {
ASSERT_EQ(0U, result.size());
// GetLogins should give the blacklisted result.
- EXPECT_TRUE(db().GetLogins(form, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
ASSERT_EQ(1U, result.size());
EXPECT_EQ(form, *result[0]);
result.clear();
- // So should GetAllBlacklistedLogins.
+ // So should GetBlacklistedLogins.
EXPECT_TRUE(db().GetBlacklistLogins(&result));
ASSERT_EQ(1U, result.size());
EXPECT_EQ(form, *result[0]);
@@ -948,7 +959,7 @@ TEST_F(LoginDatabaseTest, VectorSerialization) {
}
TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) {
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
// Verify the database is empty.
EXPECT_TRUE(db().GetAutofillableLogins(&result));
ASSERT_EQ(0U, result.size());
@@ -962,7 +973,6 @@ TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) {
incomplete_form.signon_realm = "http://accounts.google.com/";
incomplete_form.username_value = ASCIIToUTF16("my_username");
incomplete_form.password_value = ASCIIToUTF16("my_password");
- incomplete_form.ssl_valid = false;
incomplete_form.preferred = true;
incomplete_form.blacklisted_by_user = false;
incomplete_form.scheme = PasswordForm::SCHEME_HTML;
@@ -978,14 +988,14 @@ TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) {
encountered_form.submit_element = ASCIIToUTF16("signIn");
// Get matches for encountered_form.
- EXPECT_TRUE(db().GetLogins(encountered_form, &result));
+ EXPECT_TRUE(
+ db().GetLogins(PasswordStore::FormDigest(encountered_form), &result));
ASSERT_EQ(1U, result.size());
EXPECT_EQ(incomplete_form.origin, result[0]->origin);
EXPECT_EQ(incomplete_form.signon_realm, result[0]->signon_realm);
EXPECT_EQ(incomplete_form.username_value, result[0]->username_value);
EXPECT_EQ(incomplete_form.password_value, result[0]->password_value);
EXPECT_TRUE(result[0]->preferred);
- EXPECT_FALSE(result[0]->ssl_valid);
// We should return empty 'action', 'username_element', 'password_element'
// and 'submit_element' as we can't be sure if the credentials were entered
@@ -1008,7 +1018,8 @@ TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) {
EXPECT_TRUE(db().RemoveLogin(incomplete_form));
// Get matches for encountered_form again.
- EXPECT_TRUE(db().GetLogins(encountered_form, &result));
+ EXPECT_TRUE(
+ db().GetLogins(PasswordStore::FormDigest(encountered_form), &result));
ASSERT_EQ(1U, result.size());
// This time we should have all the info available.
@@ -1027,7 +1038,6 @@ TEST_F(LoginDatabaseTest, UpdateOverlappingCredentials) {
incomplete_form.signon_realm = "http://accounts.google.com/";
incomplete_form.username_value = ASCIIToUTF16("my_username");
incomplete_form.password_value = ASCIIToUTF16("my_password");
- incomplete_form.ssl_valid = false;
incomplete_form.preferred = true;
incomplete_form.blacklisted_by_user = false;
incomplete_form.scheme = PasswordForm::SCHEME_HTML;
@@ -1047,7 +1057,7 @@ TEST_F(LoginDatabaseTest, UpdateOverlappingCredentials) {
EXPECT_EQ(AddChangeForForm(complete_form), db().AddLogin(complete_form));
// Make sure both passwords exist.
- ScopedVector<autofill::PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
EXPECT_TRUE(db().GetAutofillableLogins(&result));
ASSERT_EQ(2U, result.size());
result.clear();
@@ -1074,7 +1084,6 @@ TEST_F(LoginDatabaseTest, DoubleAdd) {
form.signon_realm = "http://accounts.google.com/";
form.username_value = ASCIIToUTF16("my_username");
form.password_value = ASCIIToUTF16("my_password");
- form.ssl_valid = false;
form.preferred = true;
form.blacklisted_by_user = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -1095,7 +1104,6 @@ TEST_F(LoginDatabaseTest, AddWrongForm) {
form.signon_realm = "http://accounts.google.com/";
form.username_value = ASCIIToUTF16("my_username");
form.password_value = ASCIIToUTF16("my_password");
- form.ssl_valid = false;
form.preferred = true;
form.blacklisted_by_user = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -1113,7 +1121,6 @@ TEST_F(LoginDatabaseTest, UpdateLogin) {
form.signon_realm = "http://accounts.google.com/";
form.username_value = ASCIIToUTF16("my_username");
form.password_value = ASCIIToUTF16("my_password");
- form.ssl_valid = false;
form.preferred = true;
form.blacklisted_by_user = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -1121,7 +1128,6 @@ TEST_F(LoginDatabaseTest, UpdateLogin) {
form.action = GURL("http://accounts.google.com/login");
form.password_value = ASCIIToUTF16("my_new_password");
- form.ssl_valid = true;
form.preferred = false;
form.other_possible_usernames.push_back(ASCIIToUTF16("my_new_username"));
form.times_used = 20;
@@ -1137,8 +1143,8 @@ TEST_F(LoginDatabaseTest, UpdateLogin) {
form.skip_zero_click = true;
EXPECT_EQ(UpdateChangeForForm(form), db().UpdateLogin(form));
- ScopedVector<autofill::PasswordForm> result;
- EXPECT_TRUE(db().GetLogins(form, &result));
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
ASSERT_EQ(1U, result.size());
EXPECT_EQ(form, *result[0]);
}
@@ -1150,7 +1156,6 @@ TEST_F(LoginDatabaseTest, RemoveWrongForm) {
form.signon_realm = "http://accounts.google.com/";
form.username_value = ASCIIToUTF16("my_username");
form.password_value = ASCIIToUTF16("my_password");
- form.ssl_valid = false;
form.preferred = true;
form.blacklisted_by_user = false;
form.scheme = PasswordForm::SCHEME_HTML;
@@ -1459,8 +1464,8 @@ TEST_F(LoginDatabaseTest, ClearPasswordValues) {
form.password_value = ASCIIToUTF16("12345");
EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
- ScopedVector<autofill::PasswordForm> result;
- EXPECT_TRUE(db().GetLogins(form, &result));
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
ASSERT_EQ(1U, result.size());
PasswordForm expected_form = form;
expected_form.password_value.clear();
@@ -1469,7 +1474,7 @@ TEST_F(LoginDatabaseTest, ClearPasswordValues) {
// Update the password, it should stay empty.
form.password_value = ASCIIToUTF16("password");
EXPECT_EQ(UpdateChangeForForm(form), db().UpdateLogin(form));
- EXPECT_TRUE(db().GetLogins(form, &result));
+ EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form), &result));
ASSERT_EQ(1U, result.size());
EXPECT_EQ(expected_form, *result[0]);
@@ -1491,6 +1496,30 @@ TEST_F(LoginDatabaseTest, FilePermissions) {
}
#endif // defined(OS_POSIX)
+// If the database initialisation fails, the initialisation transaction should
+// roll back without crashing.
+TEST(LoginDatabaseFailureTest, Init_NoCrashOnFailedRollback) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath database_path = temp_dir.GetPath().AppendASCII("test.db");
+
+ // To cause an init failure, set the compatible version to be higher than the
+ // current version (in reality, this could happen if, e.g., someone opened a
+ // Canary-created profile with Chrome Stable.
+ {
+ sql::Connection connection;
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(connection.Open(database_path));
+ ASSERT_TRUE(meta_table.Init(&connection, kCurrentVersionNumber + 1,
+ kCompatibleVersionNumber + 1));
+ }
+
+ // Now try to init the database with the file. The test succeeds if it does
+ // not crash.
+ LoginDatabase db(database_path);
+ EXPECT_FALSE(db.Init());
+}
+
// Test the migration from GetParam() version to kCurrentVersionNumber.
class LoginDatabaseMigrationTest : public testing::TestWithParam<int> {
protected:
@@ -1500,7 +1529,7 @@ class LoginDatabaseMigrationTest : public testing::TestWithParam<int> {
.AppendASCII("test")
.AppendASCII("data")
.AppendASCII("password_manager");
- database_path_ = temp_dir_.path().AppendASCII("test.db");
+ database_path_ = temp_dir_.GetPath().AppendASCII("test.db");
OSCryptMocker::SetUpWithSingleton();
}
@@ -1567,16 +1596,21 @@ void LoginDatabaseMigrationTest::MigrationToVCurrent(
CreateDatabase(sql_file);
// Original date, in seconds since UTC epoch.
std::vector<int64_t> date_created(GetValues<int64_t>("date_created"));
- ASSERT_EQ(2U, date_created.size());
+ if (version() == 10) // Version 10 has a duplicate entry.
+ ASSERT_EQ(4U, date_created.size());
+ else
+ ASSERT_EQ(3U, date_created.size());
// Migration to version 8 performs changes dates to the new format.
// So for versions less of equal to 8 create date should be in old
// format before migration and in new format after.
if (version() <= 8) {
ASSERT_EQ(1402955745, date_created[0]);
ASSERT_EQ(1402950000, date_created[1]);
+ ASSERT_EQ(1402950000, date_created[2]);
} else {
ASSERT_EQ(13047429345000000, date_created[0]);
ASSERT_EQ(13047423600000000, date_created[1]);
+ ASSERT_EQ(13047423600000000, date_created[2]);
}
{
@@ -1584,6 +1618,14 @@ void LoginDatabaseMigrationTest::MigrationToVCurrent(
// to current version.
LoginDatabase db(database_path_);
ASSERT_TRUE(db.Init());
+
+ // Check that the contents was preserved.
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ EXPECT_TRUE(db.GetAutofillableLogins(&result));
+ EXPECT_THAT(result, UnorderedElementsAre(Pointee(IsGoogle1Account()),
+ Pointee(IsGoogle2Account()),
+ Pointee(IsBasicAuthAccount())));
+
// Verifies that the final version can save all the appropriate fields.
PasswordForm form;
GenerateExamplePasswordForm(&form);
@@ -1594,28 +1636,25 @@ void LoginDatabaseMigrationTest::MigrationToVCurrent(
list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
EXPECT_EQ(list, db.AddLogin(form));
- ScopedVector<autofill::PasswordForm> result;
- EXPECT_TRUE(db.GetLogins(form, &result));
+ result.clear();
+ EXPECT_TRUE(db.GetLogins(PasswordStore::FormDigest(form), &result));
ASSERT_EQ(1U, result.size());
EXPECT_EQ(form, *result[0]);
EXPECT_TRUE(db.RemoveLogin(form));
}
// New date, in microseconds since platform independent epoch.
std::vector<int64_t> new_date_created(GetValues<int64_t>("date_created"));
+ ASSERT_EQ(3U, new_date_created.size());
if (version() <= 8) {
- ASSERT_EQ(2U, new_date_created.size());
// Check that the two dates match up.
for (size_t i = 0; i < date_created.size(); ++i) {
EXPECT_EQ(base::Time::FromInternalValue(new_date_created[i]),
base::Time::FromTimeT(date_created[i]));
}
- } else if (version() == 10) {
- // The test data is setup on this version to cause a unique key collision.
- EXPECT_EQ(1U, new_date_created.size());
} else {
- ASSERT_EQ(2U, new_date_created.size());
ASSERT_EQ(13047429345000000, new_date_created[0]);
ASSERT_EQ(13047423600000000, new_date_created[1]);
+ ASSERT_EQ(13047423600000000, new_date_created[2]);
}
if (version() >= 7 && version() <= 13) {
@@ -1624,15 +1663,8 @@ void LoginDatabaseMigrationTest::MigrationToVCurrent(
// to >= 14 should not break theses URLs.
std::vector<std::string> urls(GetValues<std::string>("icon_url"));
- if (version() == 10) {
- // The testcase for version 10 tests duplicate entries, so we only expect
- // one URL.
- EXPECT_THAT(urls, testing::ElementsAre("https://www.google.com/icon"));
- } else {
- // Otherwise, we expect one empty and one valid URL.
- EXPECT_THAT(
- urls, testing::ElementsAre("", "https://www.google.com/icon"));
- }
+ EXPECT_THAT(urls, UnorderedElementsAre("", "https://www.google.com/icon",
+ "https://www.google.com/icon"));
}
{
diff --git a/chromium/components/password_manager/core/browser/login_database_win.cc b/chromium/components/password_manager/core/browser/login_database_win.cc
index 2b2b2725573..6cf9c2188e7 100644
--- a/chromium/components/password_manager/core/browser/login_database_win.cc
+++ b/chromium/components/password_manager/core/browser/login_database_win.cc
@@ -22,6 +22,19 @@ LoginDatabase::EncryptionResult LoginDatabase::EncryptedString(
LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
const std::string& cipher_text,
base::string16* plain_text) {
+ // Unittests need to read sample database entries. If these entries had real
+ // passwords, their encoding would need to be different for every platform.
+ // To avoid the need for that, the entries have empty passwords. OSCrypt on
+ // Windows does not recognise the empty string as a valid encrypted string.
+ // Changing that for all clients of OSCrypt could have too broad an impact,
+ // therefore to allow platform-independent data files for LoginDatabase
+ // tests, the special handling of the empty string is added below instead.
+ // See also https://codereview.chromium.org/2291123008/#msg14 for a
+ // discussion.
+ if (cipher_text.empty()) {
+ plain_text->clear();
+ return ENCRYPTION_RESULT_SUCCESS;
+ }
if (OSCrypt::DecryptString16(cipher_text, plain_text))
return ENCRYPTION_RESULT_SUCCESS;
return ENCRYPTION_RESULT_ITEM_FAILURE;
diff --git a/chromium/components/password_manager/core/browser/mock_affiliated_match_helper.cc b/chromium/components/password_manager/core/browser/mock_affiliated_match_helper.cc
index 466793624b2..aaf1c997e98 100644
--- a/chromium/components/password_manager/core/browser/mock_affiliated_match_helper.cc
+++ b/chromium/components/password_manager/core/browser/mock_affiliated_match_helper.cc
@@ -19,14 +19,14 @@ MockAffiliatedMatchHelper::MockAffiliatedMatchHelper()
MockAffiliatedMatchHelper::~MockAffiliatedMatchHelper() {}
void MockAffiliatedMatchHelper::ExpectCallToGetAffiliatedAndroidRealms(
- const autofill::PasswordForm& expected_observed_form,
+ const PasswordStore::FormDigest& expected_observed_form,
const std::vector<std::string>& results_to_return) {
EXPECT_CALL(*this, OnGetAffiliatedAndroidRealmsCalled(expected_observed_form))
.WillOnce(testing::Return(results_to_return));
}
void MockAffiliatedMatchHelper::ExpectCallToGetAffiliatedWebRealms(
- const autofill::PasswordForm& expected_android_form,
+ const PasswordStore::FormDigest& expected_android_form,
const std::vector<std::string>& results_to_return) {
EXPECT_CALL(*this, OnGetAffiliatedWebRealmsCalled(expected_android_form))
.WillOnce(testing::Return(results_to_return));
@@ -39,7 +39,7 @@ void MockAffiliatedMatchHelper::ExpectCallToInjectAffiliatedWebRealms(
}
void MockAffiliatedMatchHelper::GetAffiliatedAndroidRealms(
- const autofill::PasswordForm& observed_form,
+ const PasswordStore::FormDigest& observed_form,
const AffiliatedRealmsCallback& result_callback) {
std::vector<std::string> affiliated_android_realms =
OnGetAffiliatedAndroidRealmsCalled(observed_form);
@@ -47,7 +47,7 @@ void MockAffiliatedMatchHelper::GetAffiliatedAndroidRealms(
}
void MockAffiliatedMatchHelper::GetAffiliatedWebRealms(
- const autofill::PasswordForm& android_form,
+ const PasswordStore::FormDigest& android_form,
const AffiliatedRealmsCallback& result_callback) {
std::vector<std::string> affiliated_web_realms =
OnGetAffiliatedWebRealmsCalled(android_form);
@@ -55,7 +55,7 @@ void MockAffiliatedMatchHelper::GetAffiliatedWebRealms(
}
void MockAffiliatedMatchHelper::InjectAffiliatedWebRealms(
- ScopedVector<autofill::PasswordForm> forms,
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
const PasswordFormsCallback& result_callback) {
std::vector<std::string> affiliated_web_realms =
OnInjectAffiliatedWebRealmsCalled();
diff --git a/chromium/components/password_manager/core/browser/mock_affiliated_match_helper.h b/chromium/components/password_manager/core/browser/mock_affiliated_match_helper.h
index c0cc814e573..cd843ce9dd4 100644
--- a/chromium/components/password_manager/core/browser/mock_affiliated_match_helper.h
+++ b/chromium/components/password_manager/core/browser/mock_affiliated_match_helper.h
@@ -25,14 +25,14 @@ class MockAffiliatedMatchHelper : public AffiliatedMatchHelper {
// |expected_observed_form|, and will cause the result callback supplied to
// GetAffiliatedAndroidRealms() to be invoked with |results_to_return|.
void ExpectCallToGetAffiliatedAndroidRealms(
- const autofill::PasswordForm& expected_observed_form,
+ const PasswordStore::FormDigest& expected_observed_form,
const std::vector<std::string>& results_to_return);
// Expects GetAffiliatedWebRealms() to be called with the
// |expected_android_form|, and will cause the result callback supplied to
// GetAffiliatedWebRealms() to be invoked with |results_to_return|.
void ExpectCallToGetAffiliatedWebRealms(
- const autofill::PasswordForm& expected_android_form,
+ const PasswordStore::FormDigest& expected_android_form,
const std::vector<std::string>& results_to_return);
void ExpectCallToInjectAffiliatedWebRealms(
@@ -40,20 +40,20 @@ class MockAffiliatedMatchHelper : public AffiliatedMatchHelper {
private:
MOCK_METHOD1(OnGetAffiliatedAndroidRealmsCalled,
- std::vector<std::string>(const autofill::PasswordForm&));
+ std::vector<std::string>(const PasswordStore::FormDigest&));
MOCK_METHOD1(OnGetAffiliatedWebRealmsCalled,
- std::vector<std::string>(const autofill::PasswordForm&));
+ std::vector<std::string>(const PasswordStore::FormDigest&));
MOCK_METHOD0(OnInjectAffiliatedWebRealmsCalled, std::vector<std::string>());
void GetAffiliatedAndroidRealms(
- const autofill::PasswordForm& observed_form,
+ const PasswordStore::FormDigest& observed_form,
const AffiliatedRealmsCallback& result_callback) override;
void GetAffiliatedWebRealms(
- const autofill::PasswordForm& android_form,
+ const PasswordStore::FormDigest& android_form,
const AffiliatedRealmsCallback& result_callback) override;
void InjectAffiliatedWebRealms(
- ScopedVector<autofill::PasswordForm> forms,
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
const PasswordFormsCallback& result_callback) override;
DISALLOW_COPY_AND_ASSIGN(MockAffiliatedMatchHelper);
diff --git a/chromium/components/password_manager/core/browser/mock_password_store.h b/chromium/components/password_manager/core/browser/mock_password_store.h
index 0c127f70ea8..9975a2cbcb9 100644
--- a/chromium/components/password_manager/core/browser/mock_password_store.h
+++ b/chromium/components/password_manager/core/browser/mock_password_store.h
@@ -21,7 +21,7 @@ class MockPasswordStore : public PasswordStore {
MOCK_METHOD1(RemoveLogin, void(const autofill::PasswordForm&));
MOCK_METHOD2(GetLogins,
- void(const autofill::PasswordForm&, PasswordStoreConsumer*));
+ void(const PasswordStore::FormDigest&, PasswordStoreConsumer*));
MOCK_METHOD1(AddLogin, void(const autofill::PasswordForm&));
MOCK_METHOD1(UpdateLogin, void(const autofill::PasswordForm&));
MOCK_METHOD2(UpdateLoginWithPrimaryKey,
@@ -43,17 +43,21 @@ class MockPasswordStore : public PasswordStore {
PasswordStoreChangeList(base::Time, base::Time));
MOCK_METHOD2(RemoveLoginsSyncedBetweenImpl,
PasswordStoreChangeList(base::Time, base::Time));
- MOCK_METHOD2(RemoveStatisticsCreatedBetweenImpl,
- bool(base::Time, base::Time));
- MOCK_METHOD0(DisableAutoSignInForAllLoginsImpl, PasswordStoreChangeList());
- ScopedVector<autofill::PasswordForm> FillMatchingLogins(
- const autofill::PasswordForm& form) override {
- return ScopedVector<autofill::PasswordForm>();
+ MOCK_METHOD3(RemoveStatisticsByOriginAndTimeImpl,
+ bool(const base::Callback<bool(const GURL&)>&,
+ base::Time,
+ base::Time));
+ MOCK_METHOD1(
+ DisableAutoSignInForOriginsImpl,
+ PasswordStoreChangeList(const base::Callback<bool(const GURL&)>&));
+ std::vector<std::unique_ptr<autofill::PasswordForm>> FillMatchingLogins(
+ const PasswordStore::FormDigest& form) override {
+ return std::vector<std::unique_ptr<autofill::PasswordForm>>();
}
MOCK_METHOD1(FillAutofillableLogins,
- bool(ScopedVector<autofill::PasswordForm>*));
+ bool(std::vector<std::unique_ptr<autofill::PasswordForm>>*));
MOCK_METHOD1(FillBlacklistLogins,
- bool(ScopedVector<autofill::PasswordForm>*));
+ bool(std::vector<std::unique_ptr<autofill::PasswordForm>>*));
MOCK_METHOD1(NotifyLoginsChanged, void(const PasswordStoreChangeList&));
// GMock doesn't allow to return noncopyable types.
std::vector<std::unique_ptr<InteractionsStats>> GetSiteStatsImpl(
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.h b/chromium/components/password_manager/core/browser/password_autofill_manager.h
index 5bdaac74b61..c1075c324df 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager.h
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager.h
@@ -66,6 +66,11 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
// A public version of PreviewSuggestion(), only for use in tests.
bool PreviewSuggestionForTest(int key, const base::string16& username);
+ // Only use in tests.
+ void set_autofill_client(autofill::AutofillClient* autofill_client) {
+ autofill_client_ = autofill_client;
+ }
+
private:
typedef std::map<int, autofill::PasswordFormFillData> LoginToPasswordInfoMap;
@@ -101,7 +106,7 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
// The driver that owns |this|.
PasswordManagerDriver* password_manager_driver_;
- autofill::AutofillClient* const autofill_client_; // weak
+ autofill::AutofillClient* autofill_client_; // weak
base::WeakPtrFactory<PasswordAutofillManager> weak_ptr_factory_;
diff --git a/chromium/components/password_manager/core/browser/password_bubble_experiment.cc b/chromium/components/password_manager/core/browser/password_bubble_experiment.cc
index 9b41bde9c2a..a0e5c88d13b 100644
--- a/chromium/components/password_manager/core/browser/password_bubble_experiment.cc
+++ b/chromium/components/password_manager/core/browser/password_bubble_experiment.cc
@@ -13,7 +13,7 @@
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_service.h"
#include "components/variations/variations_associated_data.h"
namespace password_bubble_experiment {
@@ -46,16 +46,17 @@ int GetSmartBubbleDismissalThreshold() {
std::string param = variations::GetVariationParamValue(
kSmartBubbleExperimentName, kSmartBubbleThresholdParam);
int threshold = 0;
- return base::StringToInt(param, &threshold) ? threshold : 0;
+ // 3 is the default magic number that proved to show the best result.
+ return base::StringToInt(param, &threshold) ? threshold : 3;
}
-bool IsSmartLockUser(const sync_driver::SyncService* sync_service) {
+bool IsSmartLockUser(const syncer::SyncService* sync_service) {
return password_manager_util::GetPasswordSyncState(sync_service) ==
password_manager::SYNCING_NORMAL_ENCRYPTION;
}
SmartLockBranding GetSmartLockBrandingState(
- const sync_driver::SyncService* sync_service) {
+ const syncer::SyncService* sync_service) {
// Query the group first for correct UMA reporting.
std::string group_name =
base::FieldTrialList::FindFullName(kBrandingExperimentName);
@@ -68,17 +69,17 @@ SmartLockBranding GetSmartLockBrandingState(
return SmartLockBranding::NONE;
}
-bool IsSmartLockBrandingEnabled(const sync_driver::SyncService* sync_service) {
+bool IsSmartLockBrandingEnabled(const syncer::SyncService* sync_service) {
return GetSmartLockBrandingState(sync_service) == SmartLockBranding::FULL;
}
bool IsSmartLockBrandingSavePromptEnabled(
- const sync_driver::SyncService* sync_service) {
+ const syncer::SyncService* sync_service) {
return GetSmartLockBrandingState(sync_service) != SmartLockBranding::NONE;
}
bool ShouldShowSavePromptFirstRunExperience(
- const sync_driver::SyncService* sync_service,
+ const syncer::SyncService* sync_service,
PrefService* prefs) {
return false;
}
@@ -105,7 +106,7 @@ void TurnOffAutoSignin(PrefService* prefs) {
bool ShouldShowChromeSignInPasswordPromo(
PrefService* prefs,
- const sync_driver::SyncService* sync_service) {
+ const syncer::SyncService* sync_service) {
// Query the group first for correct UMA reporting.
std::string param = variations::GetVariationParamValue(
kChromeSignInPasswordPromoExperimentName,
diff --git a/chromium/components/password_manager/core/browser/password_bubble_experiment.h b/chromium/components/password_manager/core/browser/password_bubble_experiment.h
index f2ce04eed34..cfb1ac6d3a5 100644
--- a/chromium/components/password_manager/core/browser/password_bubble_experiment.h
+++ b/chromium/components/password_manager/core/browser/password_bubble_experiment.h
@@ -8,7 +8,7 @@
class PrefRegistrySimple;
class PrefService;
-namespace sync_driver {
+namespace syncer {
class SyncService;
}
@@ -32,7 +32,7 @@ void RegisterPrefs(PrefRegistrySimple* registry);
int GetSmartBubbleDismissalThreshold();
// A Smart Lock user is a sync user without a custom passphrase.
-bool IsSmartLockUser(const sync_driver::SyncService* sync_service);
+bool IsSmartLockUser(const syncer::SyncService* sync_service);
enum class SmartLockBranding { NONE, FULL, SAVE_PROMPT_ONLY };
@@ -43,20 +43,20 @@ enum class SmartLockBranding { NONE, FULL, SAVE_PROMPT_ONLY };
// * returns SAVE_PROMPT_ONLY if it only should be referred to as Smart Lock in
// the save password bubble.
SmartLockBranding GetSmartLockBrandingState(
- const sync_driver::SyncService* sync_service);
+ const syncer::SyncService* sync_service);
// Convenience function for checking whether the result of
// GetSmartLockBrandingState is SmartLockBranding::FULL.
-bool IsSmartLockBrandingEnabled(const sync_driver::SyncService* sync_service);
+bool IsSmartLockBrandingEnabled(const syncer::SyncService* sync_service);
// Convenience function for checking whether the result of
// GetSmartLockBrandingState is not equal to SmartLockBranding::NONE.
bool IsSmartLockBrandingSavePromptEnabled(
- const sync_driver::SyncService* sync_service);
+ const syncer::SyncService* sync_service);
// Returns true if save prompt should contain first run experience.
bool ShouldShowSavePromptFirstRunExperience(
- const sync_driver::SyncService* sync_service,
+ const syncer::SyncService* sync_service,
PrefService* prefs);
// Sets appropriate value to the preference which controls appearance of the
@@ -76,7 +76,7 @@ void TurnOffAutoSignin(PrefService* prefs);
// Returns true if the Chrome Sign In promo should be shown.
bool ShouldShowChromeSignInPasswordPromo(
PrefService* prefs,
- const sync_driver::SyncService* sync_service);
+ const syncer::SyncService* sync_service);
} // namespace password_bubble_experiment
diff --git a/chromium/components/password_manager/core/browser/password_bubble_experiment_unittest.cc b/chromium/components/password_manager/core/browser/password_bubble_experiment_unittest.cc
index 823fbc9c33e..4f4baa8cd4f 100644
--- a/chromium/components/password_manager/core/browser/password_bubble_experiment_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_bubble_experiment_unittest.cc
@@ -12,7 +12,7 @@
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/testing_pref_service.h"
-#include "components/sync_driver/fake_sync_service.h"
+#include "components/sync/driver/fake_sync_service.h"
#include "components/variations/variations_associated_data.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -65,7 +65,7 @@ struct ShouldShowSavePromptFirstRunExperienceTestcase {
SavePromptFirstRunExperience first_run_experience;
};
-class TestSyncService : public sync_driver::FakeSyncService {
+class TestSyncService : public syncer::FakeSyncService {
public:
// FakeSyncService overrides.
bool IsSyncAllowed() const override { return is_sync_allowed_; }
diff --git a/chromium/components/password_manager/core/browser/password_form_manager.cc b/chromium/components/password_manager/core/browser/password_form_manager.cc
index f018d34ad6b..919f1713356 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager.cc
@@ -10,11 +10,10 @@
#include <map>
#include <utility>
-#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
-#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
#include "base/strings/string16.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -23,11 +22,9 @@
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/proto/server.pb.h"
#include "components/autofill/core/browser/validation.h"
-#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/affiliation_utils.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
-#include "components/password_manager/core/browser/credentials_filter.h"
#include "components/password_manager/core/browser/form_saver.h"
#include "components/password_manager/core/browser/log_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
@@ -41,7 +38,6 @@
using autofill::FormStructure;
using autofill::PasswordForm;
-using autofill::PasswordFormMap;
using base::Time;
// Shorten the name to spare line breaks. The code provides enough context
@@ -52,19 +48,12 @@ namespace password_manager {
namespace {
-PasswordForm CopyAndModifySSLValidity(const PasswordForm& orig,
- bool ssl_valid) {
- PasswordForm result(orig);
- result.ssl_valid = ssl_valid;
- return result;
-}
-
// Returns true if user-typed username and password field values match with one
// of the password form within |credentials| map; otherwise false.
bool DoesUsenameAndPasswordMatchCredentials(
const base::string16& typed_username,
const base::string16& typed_password,
- const autofill::PasswordFormMap& credentials) {
+ const std::map<base::string16, const PasswordForm*>& credentials) {
for (const auto& match : credentials) {
if (match.second->username_value == typed_username &&
match.second->password_value == typed_password)
@@ -97,27 +86,6 @@ bool IsProbablyNotUsername(const base::string16& s) {
return !s.empty() && DoesStringContainOnlyDigits(s) && s.size() < 3;
}
-// Splits federated matches from |store_results| into a separate vector and
-// returns that.
-std::vector<std::unique_ptr<autofill::PasswordForm>> SplitFederatedMatches(
- ScopedVector<PasswordForm>* store_results) {
- auto first_federated =
- std::partition(store_results->begin(), store_results->end(),
- [](const PasswordForm* form) {
- return form->federation_origin.unique();
- });
-
- std::vector<std::unique_ptr<autofill::PasswordForm>> federated_matches;
- federated_matches.reserve(store_results->end() - first_federated);
- for (auto federated = first_federated; federated != store_results->end();
- ++federated) {
- federated_matches.push_back(base::WrapUnique(*federated));
- *federated = nullptr;
- }
- store_results->weak_erase(first_federated, store_results->end());
- return federated_matches;
-}
-
bool ShouldShowInitialPasswordAccountSuggestions() {
return base::FeatureList::IsEnabled(
password_manager::features::kFillOnAccountSelect);
@@ -134,12 +102,13 @@ void UpdateMetadataForUsage(PasswordForm* credential) {
// Returns true iff |best_matches| contain a preferred credential with a
// username other than |preferred_username|.
-bool DidPreferenceChange(const autofill::PasswordFormMap& best_matches,
- const base::string16& preferred_username) {
+bool DidPreferenceChange(
+ const std::map<base::string16, const PasswordForm*>& best_matches,
+ const base::string16& preferred_username) {
for (const auto& key_value_pair : best_matches) {
- const auto& form = key_value_pair.second;
- if (form->preferred && !form->is_public_suffix_match &&
- form->username_value != preferred_username) {
+ const PasswordForm& form = *key_value_pair.second;
+ if (form.preferred && !form.is_public_suffix_match &&
+ form.username_value != preferred_username) {
return true;
}
}
@@ -165,6 +134,20 @@ void SanitizePossibleUsernames(PasswordForm* form) {
usernames.erase(new_end, usernames.end());
}
+// Copies field properties masks from the form |from| to the form |to|.
+void CopyFieldPropertiesMasks(const PasswordForm& from, PasswordForm* to) {
+ // Skip copying if the number of fields is different.
+ if (from.form_data.fields.size() != to->form_data.fields.size())
+ return;
+
+ for (size_t i = 0; i < from.form_data.fields.size(); ++i) {
+ to->form_data.fields[i].properties_mask =
+ to->form_data.fields[i].name == from.form_data.fields[i].name
+ ? from.form_data.fields[i].properties_mask
+ : autofill::FieldPropertiesFlags::ERROR_OCCURRED;
+ }
+}
+
} // namespace
PasswordFormManager::PasswordFormManager(
@@ -172,9 +155,8 @@ PasswordFormManager::PasswordFormManager(
PasswordManagerClient* client,
const base::WeakPtr<PasswordManagerDriver>& driver,
const PasswordForm& observed_form,
- bool ssl_valid,
std::unique_ptr<FormSaver> form_saver)
- : observed_form_(CopyAndModifySSLValidity(observed_form, ssl_valid)),
+ : observed_form_(observed_form),
provisionally_saved_form_(nullptr),
other_possible_username_action_(
PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES),
@@ -195,18 +177,21 @@ PasswordFormManager::PasswordFormManager(
is_ignorable_change_password_form_(false),
is_possible_change_password_form_without_username_(
observed_form.IsPossibleChangePasswordFormWithoutUsername()),
- state_(PRE_MATCHING_PHASE),
client_(client),
manager_action_(kManagerActionNone),
user_action_(kUserActionNone),
submit_result_(kSubmitResultNotSubmitted),
form_type_(kFormTypeUnspecified),
need_to_refetch_(false),
- form_saver_(std::move(form_saver)) {
+ form_saver_(std::move(form_saver)),
+ form_fetcher_impl_(client),
+ form_fetcher_(&form_fetcher_impl_) {
DCHECK_EQ(observed_form.scheme == PasswordForm::SCHEME_HTML,
driver != nullptr);
if (driver)
drivers_.push_back(driver);
+ FetchDataFromPasswordStore();
+ form_fetcher_->AddConsumer(this);
}
PasswordFormManager::~PasswordFormManager() {
@@ -298,21 +283,23 @@ PasswordFormManager::MatchResultMask PasswordFormManager::DoesManage(
}
bool PasswordFormManager::IsBlacklisted() const {
- DCHECK_EQ(state_, POST_MATCHING_PHASE);
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
return !blacklisted_matches_.empty();
}
void PasswordFormManager::PermanentlyBlacklist() {
- DCHECK_EQ(state_, POST_MATCHING_PHASE);
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
DCHECK(!client_->IsOffTheRecord());
- blacklisted_matches_.push_back(
- base::WrapUnique(new autofill::PasswordForm(observed_form_)));
- form_saver_->PermanentlyBlacklist(blacklisted_matches_.back().get());
+ if (!new_blacklisted_) {
+ new_blacklisted_ = base::MakeUnique<PasswordForm>(observed_form_);
+ blacklisted_matches_.push_back(new_blacklisted_.get());
+ }
+ form_saver_->PermanentlyBlacklist(new_blacklisted_.get());
}
bool PasswordFormManager::IsNewLogin() const {
- DCHECK_EQ(state_, POST_MATCHING_PHASE);
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
return is_new_login_;
}
@@ -323,7 +310,6 @@ bool PasswordFormManager::IsPendingCredentialsPublicSuffixMatch() const {
void PasswordFormManager::ProvisionallySave(
const PasswordForm& credentials,
OtherPossibleUsernamesAction action) {
- DCHECK(state_ == MATCHING_PHASE || state_ == POST_MATCHING_PHASE) << state_;
DCHECK_NE(RESULT_NO_MATCH, DoesManage(credentials));
std::unique_ptr<autofill::PasswordForm> mutable_provisionally_saved_form(
@@ -344,12 +330,12 @@ void PasswordFormManager::ProvisionallySave(
}
void PasswordFormManager::Save() {
- DCHECK_EQ(state_, POST_MATCHING_PHASE);
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
DCHECK(!client_->IsOffTheRecord());
if ((user_action_ == kUserActionNone) &&
DidPreferenceChange(best_matches_, pending_credentials_.username_value)) {
- user_action_ = kUserActionChoose;
+ SetUserAction(kUserActionChoose);
}
base::Optional<PasswordForm> old_primary_key;
if (is_new_login_) {
@@ -360,7 +346,7 @@ void PasswordFormManager::Save() {
old_primary_key ? &old_primary_key.value() : nullptr);
} else {
ProcessUpdate();
- std::vector<const PasswordForm*> credentials_to_update;
+ std::vector<PasswordForm> credentials_to_update;
old_primary_key = UpdatePendingAndGetOldKey(&credentials_to_update);
form_saver_->Update(pending_credentials_, best_matches_,
&credentials_to_update,
@@ -382,7 +368,7 @@ void PasswordFormManager::Update(
if (observed_form_.IsPossibleChangePasswordForm()) {
FormStructure form_structure(credentials_to_update.form_data);
UploadChangePasswordForm(autofill::NEW_PASSWORD,
- form_structure.FormSignature());
+ form_structure.FormSignatureAsStr());
}
base::string16 password_to_save = pending_credentials_.password_value;
bool skip_zero_click = pending_credentials_.skip_zero_click;
@@ -392,7 +378,7 @@ void PasswordFormManager::Update(
pending_credentials_.preferred = true;
is_new_login_ = false;
ProcessUpdate();
- std::vector<const PasswordForm*> more_credentials_to_update;
+ std::vector<PasswordForm> more_credentials_to_update;
base::Optional<PasswordForm> old_primary_key =
UpdatePendingAndGetOldKey(&more_credentials_to_update);
form_saver_->Update(pending_credentials_, best_matches_,
@@ -401,7 +387,7 @@ void PasswordFormManager::Update(
}
void PasswordFormManager::FetchDataFromPasswordStore() {
- if (state_ == MATCHING_PHASE) {
+ if (form_fetcher_->GetState() == FormFetcher::State::WAITING) {
// There is currently a password store query in progress, need to re-fetch
// store results later.
need_to_refetch_ = true;
@@ -413,20 +399,23 @@ void PasswordFormManager::FetchDataFromPasswordStore() {
logger.reset(
new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
logger->LogMessage(Logger::STRING_FETCH_LOGINS_METHOD);
- logger->LogNumber(Logger::STRING_FORM_MANAGER_STATE, state_);
+ logger->LogNumber(Logger::STRING_FORM_MANAGER_STATE,
+ static_cast<int>(form_fetcher_->GetState()));
}
provisionally_saved_form_.reset();
- state_ = MATCHING_PHASE;
+ form_fetcher_impl_.set_state(FormFetcher::State::WAITING);
PasswordStore* password_store = client_->GetPasswordStore();
if (!password_store) {
if (logger)
logger->LogMessage(Logger::STRING_NO_STORE);
- NOTREACHED();
+ // TODO(crbug.com/621355): The store might be empty in some tests. Start
+ // enforcing the presence of a (non-null) PasswordStore once FormFetcher is
+ // fetching the credentials instead of PasswordFormManager.
return;
}
- password_store->GetLogins(observed_form_, this);
+ password_store->GetLogins(PasswordStore::FormDigest(observed_form_), this);
// The statistics isn't needed on mobile, only on desktop. Let's save some
// processor cycles.
@@ -437,7 +426,7 @@ void PasswordFormManager::FetchDataFromPasswordStore() {
}
bool PasswordFormManager::HasCompletedMatching() const {
- return state_ == POST_MATCHING_PHASE;
+ return form_fetcher_->GetState() == FormFetcher::State::NOT_WAITING;
}
void PasswordFormManager::SetSubmittedForm(const autofill::PasswordForm& form) {
@@ -473,91 +462,109 @@ void PasswordFormManager::SetSubmittedForm(const autofill::PasswordForm& form) {
}
}
-void PasswordFormManager::OnRequestDone(
- ScopedVector<PasswordForm> logins_result) {
+void PasswordFormManager::ScoreMatches(
+ const std::vector<const PasswordForm*>& matches) {
+ DCHECK(std::all_of(
+ matches.begin(), matches.end(),
+ [](const PasswordForm* match) { return !match->blacklisted_by_user; }));
+
preferred_match_ = nullptr;
best_matches_.clear();
- blacklisted_matches_.clear();
- const size_t logins_result_size = logins_result.size();
+ not_best_matches_.clear();
- std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
- if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
- logger->LogMessage(Logger::STRING_ON_REQUEST_DONE_METHOD);
- }
-
- // Remove credentials which need to be ignored from |logins_result|.
- if (!observed_form_.ssl_valid) {
- logins_result.erase(
- std::partition(logins_result.begin(), logins_result.end(),
- [](PasswordForm* form) { return !form->ssl_valid; }),
- logins_result.end());
- }
- logins_result =
- client_->GetStoreResultFilter()->FilterResults(std::move(logins_result));
-
- // Deal with blacklisted forms.
- auto begin_blacklisted = std::partition(
- logins_result.begin(), logins_result.end(),
- [](PasswordForm* form) { return !form->blacklisted_by_user; });
- for (auto it = begin_blacklisted; it != logins_result.end(); ++it) {
- if (IsBlacklistMatch(**it)) {
- blacklisted_matches_.push_back(base::WrapUnique(*it));
- *it = nullptr;
- }
- }
- logins_result.erase(begin_blacklisted, logins_result.end());
- if (logins_result.empty())
+ if (matches.empty())
return;
- // Now compute scores for the remaining credentials in |login_result|.
- std::vector<uint32_t> credential_scores;
- credential_scores.reserve(logins_result.size());
- uint32_t best_score = 0;
- std::map<base::string16, uint32_t> best_scores;
- for (const PasswordForm* login : logins_result) {
- uint32_t current_score = ScoreResult(*login);
- best_score = std::max(best_score, current_score);
- best_scores[login->username_value] =
- std::max(best_scores[login->username_value], current_score);
- credential_scores.push_back(current_score);
+ // Compute scores.
+ std::vector<uint32_t> credential_scores(matches.size());
+ std::transform(
+ matches.begin(), matches.end(), credential_scores.begin(),
+ [this](const PasswordForm* match) { return ScoreResult(*match); });
+
+ const uint32_t best_score =
+ *std::max_element(credential_scores.begin(), credential_scores.end());
+
+ std::map<base::string16, uint32_t> best_scores; // best scores for usernames
+
+ for (size_t i = 0; i < matches.size(); ++i) {
+ uint32_t& score = best_scores[matches[i]->username_value];
+ score = std::max(score, credential_scores[i]);
}
+ // Assign best, non-best and preferred matches.
+ not_best_matches_.reserve(matches.size() - best_scores.size());
// Fill |best_matches_| with the best-scoring credentials for each username.
- for (size_t i = 0; i < logins_result.size(); ++i) {
- // Take ownership of the PasswordForm from the ScopedVector.
- std::unique_ptr<PasswordForm> login(logins_result[i]);
- logins_result[i] = nullptr;
- DCHECK(!login->blacklisted_by_user);
- const base::string16& username = login->username_value;
+ for (size_t i = 0; i < matches.size(); ++i) {
+ const PasswordForm* const match = matches[i];
+ const base::string16& username = match->username_value;
if (credential_scores[i] < best_scores[username]) {
- not_best_matches_.push_back(std::move(login));
+ not_best_matches_.push_back(match);
continue;
}
if (!preferred_match_ && credential_scores[i] == best_score)
- preferred_match_ = login.get();
+ preferred_match_ = match;
// If there is another best-score match for the same username then leave it
// and add the current form to |not_best_matches_|.
auto best_match_username = best_matches_.find(username);
if (best_match_username == best_matches_.end()) {
- best_matches_.insert(std::make_pair(username, std::move(login)));
+ best_matches_.insert(std::make_pair(username, match));
} else {
- not_best_matches_.push_back(std::move(login));
+ not_best_matches_.push_back(match);
}
}
+}
+
+void PasswordFormManager::ProcessMatches(
+ const std::vector<const PasswordForm*>& non_federated,
+ size_t filtered_count) {
+ blacklisted_matches_.clear();
+ new_blacklisted_.reset();
- UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown",
- logins_result_size - best_matches_.size());
+ std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
+ if (password_manager_util::IsLoggingActive(client_)) {
+ logger.reset(
+ new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+ logger->LogMessage(Logger::STRING_PROCESS_MATCHES_METHOD);
+ }
+
+ // Copy out and score non-blacklisted matches.
+ std::vector<const PasswordForm*> matches(std::count_if(
+ non_federated.begin(), non_federated.end(),
+ [this](const PasswordForm* form) { return IsMatch(*form); }));
+ std::copy_if(non_federated.begin(), non_federated.end(), matches.begin(),
+ [this](const PasswordForm* form) { return IsMatch(*form); });
+ ScoreMatches(matches);
+
+ // Copy out blacklisted matches.
+ blacklisted_matches_.resize(std::count_if(
+ non_federated.begin(), non_federated.end(),
+ [this](const PasswordForm* form) { return IsBlacklistMatch(*form); }));
+ std::copy_if(
+ non_federated.begin(), non_federated.end(), blacklisted_matches_.begin(),
+ [this](const PasswordForm* form) { return IsBlacklistMatch(*form); });
+
+ UMA_HISTOGRAM_COUNTS(
+ "PasswordManager.NumPasswordsNotShown",
+ non_federated.size() + filtered_count - best_matches_.size());
+
+ // If password store was slow and provisionally saved form is already here
+ // then create pending credentials (see http://crbug.com/470322).
+ if (provisionally_saved_form_)
+ CreatePendingCredentials();
+
+ for (auto const& driver : drivers_)
+ ProcessFrameInternal(driver);
+ if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
+ ProcessLoginPrompt();
}
void PasswordFormManager::ProcessFrame(
const base::WeakPtr<PasswordManagerDriver>& driver) {
DCHECK_EQ(PasswordForm::SCHEME_HTML, observed_form_.scheme);
- if (state_ == POST_MATCHING_PHASE)
+ if (form_fetcher_->GetState() == FormFetcher::State::NOT_WAITING)
ProcessFrameInternal(driver);
for (auto const& old_driver : drivers_) {
@@ -573,10 +580,9 @@ void PasswordFormManager::ProcessFrame(
void PasswordFormManager::ProcessFrameInternal(
const base::WeakPtr<PasswordManagerDriver>& driver) {
DCHECK_EQ(PasswordForm::SCHEME_HTML, observed_form_.scheme);
- if (!driver || manager_action_ == kManagerActionBlacklisted)
+ if (!driver)
return;
- // Allow generation for any non-blacklisted form.
driver->AllowPasswordGenerationForForm(observed_form_);
if (best_matches_.empty())
@@ -597,24 +603,26 @@ void PasswordFormManager::ProcessFrameInternal(
preferred_match_->action.GetWithEmptyPath() ||
preferred_match_->is_public_suffix_match ||
observed_form_.IsPossibleChangePasswordForm()));
- if (wait_for_username)
+ if (wait_for_username) {
manager_action_ = kManagerActionNone;
- else
+ } else {
manager_action_ = kManagerActionAutofilled;
+ base::RecordAction(base::UserMetricsAction("PasswordManager_Autofilled"));
+ }
if (ShouldShowInitialPasswordAccountSuggestions()) {
// This is for the fill-on-account-select experiment. Instead of autofilling
// found usernames and passwords on load, this instructs the renderer to
// return with any found password forms so a list of password account
// suggestions can be drawn.
password_manager_->ShowInitialPasswordAccountSuggestions(
- driver.get(), observed_form_, best_matches_, federated_matches_,
- *preferred_match_, wait_for_username);
+ driver.get(), observed_form_, best_matches_, *preferred_match_,
+ wait_for_username);
} else {
// If fill-on-account-select is not enabled, continue with autofilling any
// password forms as traditionally has been done.
password_manager_->Autofill(driver.get(), observed_form_, best_matches_,
- federated_matches_, *preferred_match_,
- wait_for_username);
+ form_fetcher_->GetFederatedMatches(),
+ *preferred_match_, wait_for_username);
}
}
@@ -628,12 +636,12 @@ void PasswordFormManager::ProcessLoginPrompt() {
}
void PasswordFormManager::OnGetPasswordStoreResults(
- ScopedVector<PasswordForm> results) {
- DCHECK_EQ(state_, MATCHING_PHASE);
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+ DCHECK_EQ(FormFetcher::State::WAITING, form_fetcher_->GetState());
if (need_to_refetch_) {
// The received results are no longer up to date, need to re-request.
- state_ = PRE_MATCHING_PHASE;
+ form_fetcher_impl_.set_state(FormFetcher::State::NOT_WAITING);
FetchDataFromPasswordStore();
need_to_refetch_ = false;
return;
@@ -647,34 +655,18 @@ void PasswordFormManager::OnGetPasswordStoreResults(
logger->LogNumber(Logger::STRING_NUMBER_RESULTS, results.size());
}
- federated_matches_ = SplitFederatedMatches(&results);
- if (!results.empty())
- OnRequestDone(std::move(results));
- state_ = POST_MATCHING_PHASE;
-
- // If password store was slow and provisionally saved form is already here
- // then create pending credentials (see http://crbug.com/470322).
- if (provisionally_saved_form_)
- CreatePendingCredentials();
-
- if (manager_action_ != kManagerActionBlacklisted) {
- for (auto const& driver : drivers_)
- ProcessFrameInternal(driver);
- if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
- ProcessLoginPrompt();
- }
+ form_fetcher_impl_.SetResults(std::move(results));
}
void PasswordFormManager::OnGetSiteStatistics(
- std::unique_ptr<std::vector<std::unique_ptr<InteractionsStats>>> stats) {
+ std::vector<std::unique_ptr<InteractionsStats>> stats) {
// On Windows the password request may be resolved after the statistics due to
// importing from IE.
- DCHECK(state_ == MATCHING_PHASE || state_ == POST_MATCHING_PHASE) << state_;
- interactions_stats_.swap(*stats);
+ form_fetcher_impl_.SetStats(std::move(stats));
}
void PasswordFormManager::ProcessUpdate() {
- DCHECK_EQ(state_, POST_MATCHING_PHASE);
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
DCHECK(preferred_match_ || !pending_credentials_.federation_origin.unique());
// If we're doing an Update, we either autofilled correctly and need to
// update the stats, or the user typed in a new password for autofilled
@@ -685,7 +677,8 @@ void PasswordFormManager::ProcessUpdate() {
UpdateMetadataForUsage(&pending_credentials_);
- client_->GetStoreResultFilter()->ReportFormUsed(pending_credentials_);
+ base::RecordAction(
+ base::UserMetricsAction("PasswordManager_LoginFollowingAutofill"));
// Check to see if this form is a candidate for password generation.
// Do not send votes on change password forms, since they were already sent in
@@ -696,11 +689,11 @@ void PasswordFormManager::ProcessUpdate() {
bool PasswordFormManager::UpdatePendingCredentialsIfOtherPossibleUsername(
const base::string16& username) {
- for (PasswordFormMap::const_iterator it = best_matches_.begin();
- it != best_matches_.end(); ++it) {
- for (size_t i = 0; i < it->second->other_possible_usernames.size(); ++i) {
- if (it->second->other_possible_usernames[i] == username) {
- pending_credentials_ = *it->second;
+ for (const auto& key_value : best_matches_) {
+ const PasswordForm& match = *key_value.second;
+ for (size_t i = 0; i < match.other_possible_usernames.size(); ++i) {
+ if (match.other_possible_usernames[i] == username) {
+ pending_credentials_ = match;
return true;
}
}
@@ -722,7 +715,8 @@ void PasswordFormManager::SendAutofillVotes(
// to PasswordForm. Even without this check, these FormStructure's won't
// be uploaded, but it makes it hard to see if we are encountering
// unexpected errors.
- if (pending_structure.FormSignature() != observed_structure.FormSignature()) {
+ if (pending_structure.FormSignatureAsStr() !=
+ observed_structure.FormSignatureAsStr()) {
// Only upload if this is the first time the password has been used.
// Otherwise the credentials have been used on the same field before so
// they aren't from an account creation form.
@@ -732,7 +726,7 @@ void PasswordFormManager::SendAutofillVotes(
if (pending->times_used == 1 && selected_username_.empty()) {
if (UploadPasswordForm(pending->form_data, pending->username_element,
autofill::ACCOUNT_CREATION_PASSWORD,
- observed_structure.FormSignature())) {
+ observed_structure.FormSignatureAsStr())) {
pending->generation_upload_status =
autofill::PasswordForm::POSITIVE_SIGNAL_SENT;
}
@@ -960,7 +954,7 @@ void PasswordFormManager::CreatePendingCredentials() {
// autofilled ones, as they may have changed if the user experienced a login
// failure.
// Look for these credentials in the list containing auto-fill entries.
- PasswordForm* saved_form =
+ const PasswordForm* saved_form =
FindBestSavedMatch(provisionally_saved_form_.get());
if (saved_form != nullptr) {
// The user signed in with a login we autofilled.
@@ -972,8 +966,8 @@ void PasswordFormManager::CreatePendingCredentials() {
// from Android apps store a copy with the current origin and signon
// realm. This ensures that on the next visit, a precise match is found.
is_new_login_ = true;
- user_action_ = password_overridden_ ? kUserActionOverridePassword
- : kUserActionChoosePslMatch;
+ SetUserAction(password_overridden_ ? kUserActionOverridePassword
+ : kUserActionChoosePslMatch);
// Since this credential will not overwrite a previously saved credential,
// username_value can be updated now.
@@ -1024,7 +1018,7 @@ void PasswordFormManager::CreatePendingCredentials() {
} else { // Not a PSL match.
is_new_login_ = false;
if (password_overridden_)
- user_action_ = kUserActionOverridePassword;
+ SetUserAction(kUserActionOverridePassword);
}
} else if (other_possible_username_action_ ==
ALLOW_OTHER_POSSIBLE_USERNAMES &&
@@ -1042,7 +1036,7 @@ void PasswordFormManager::CreatePendingCredentials() {
(provisionally_saved_form_
->IsPossibleChangePasswordFormWithoutUsername() ||
provisionally_saved_form_->username_element.empty())) {
- PasswordForm* best_update_match = FindBestMatchForUpdatePassword(
+ const PasswordForm* best_update_match = FindBestMatchForUpdatePassword(
provisionally_saved_form_->password_value);
retry_password_form_password_update_ =
@@ -1077,6 +1071,7 @@ void PasswordFormManager::CreatePendingCredentials() {
pending_credentials_.password_value = password_to_save;
pending_credentials_.preferred = provisionally_saved_form_->preferred;
+ CopyFieldPropertiesMasks(*provisionally_saved_form_, &pending_credentials_);
// If we're dealing with an API-driven provisionally saved form, then take
// the server provided values. We don't do this for non-API forms, as
@@ -1113,7 +1108,6 @@ void PasswordFormManager::CreatePendingCredentials() {
}
uint32_t PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
- DCHECK_EQ(state_, MATCHING_PHASE);
DCHECK(!candidate.blacklisted_by_user);
// For scoring of candidate login data:
// The most important element that should match is the signon_realm followed
@@ -1179,14 +1173,20 @@ uint32_t PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
return score;
}
+bool PasswordFormManager::IsMatch(const autofill::PasswordForm& form) const {
+ return !form.blacklisted_by_user && form.scheme == observed_form_.scheme;
+}
+
bool PasswordFormManager::IsBlacklistMatch(
const autofill::PasswordForm& blacklisted_form) const {
- DCHECK(blacklisted_form.blacklisted_by_user);
-
- if (blacklisted_form.is_public_suffix_match)
- return false;
- if (blacklisted_form.origin.GetOrigin() != observed_form_.origin.GetOrigin())
+ if (!blacklisted_form.blacklisted_by_user ||
+ blacklisted_form.is_public_suffix_match ||
+ blacklisted_form.scheme != observed_form_.scheme ||
+ blacklisted_form.origin.GetOrigin() !=
+ observed_form_.origin.GetOrigin()) {
return false;
+ }
+
if (observed_form_.scheme == PasswordForm::SCHEME_HTML) {
return (blacklisted_form.origin.path() == observed_form_.origin.path()) ||
(AreStringsEqualOrEmpty(blacklisted_form.submit_element,
@@ -1199,28 +1199,30 @@ bool PasswordFormManager::IsBlacklistMatch(
return true;
}
-PasswordForm* PasswordFormManager::FindBestMatchForUpdatePassword(
+const PasswordForm* PasswordFormManager::FindBestMatchForUpdatePassword(
const base::string16& password) const {
if (best_matches_.size() == 1 && !has_generated_password_) {
// In case when the user has only one credential and the current password is
// not generated, consider it the same as is being saved.
- return best_matches_.begin()->second.get();
+ return best_matches_.begin()->second;
}
if (password.empty())
return nullptr;
- for (auto it = best_matches_.begin(); it != best_matches_.end(); ++it) {
- if (it->second->password_value == password)
- return it->second.get();
+ for (const auto& key_value : best_matches_) {
+ if (key_value.second->password_value == password)
+ return key_value.second;
}
return nullptr;
}
-PasswordForm* PasswordFormManager::FindBestSavedMatch(
+const PasswordForm* PasswordFormManager::FindBestSavedMatch(
const PasswordForm* form) const {
- PasswordFormMap::const_iterator it = best_matches_.find(form->username_value);
+ if (!form->federation_origin.unique())
+ return nullptr;
+ auto it = best_matches_.find(form->username_value);
if (it != best_matches_.end())
- return it->second.get();
+ return it->second;
if (form->type == autofill::PasswordForm::TYPE_API)
// Match Credential API forms only by username.
return nullptr;
@@ -1228,14 +1230,14 @@ PasswordForm* PasswordFormManager::FindBestSavedMatch(
return nullptr;
for (const auto& stored_match : best_matches_) {
if (stored_match.second->password_value == form->password_value)
- return stored_match.second.get();
+ return stored_match.second;
}
return nullptr;
}
void PasswordFormManager::CreatePendingCredentialsForNewCredentials() {
// User typed in a new, unknown username.
- user_action_ = kUserActionOverrideUsernameAndPassword;
+ SetUserAction(kUserActionOverrideUsernameAndPassword);
pending_credentials_ = observed_form_;
if (provisionally_saved_form_->was_parsed_using_autofill_predictions)
pending_credentials_.username_element =
@@ -1276,6 +1278,7 @@ void PasswordFormManager::LogSubmitPassed() {
metrics_util::PASSWORD_SUBMITTED);
}
}
+ base::RecordAction(base::UserMetricsAction("PasswordManager_LoginPassed"));
submit_result_ = kSubmitResultPassed;
}
@@ -1287,12 +1290,11 @@ void PasswordFormManager::LogSubmitFailed() {
metrics_util::LogPasswordGenerationAvailableSubmissionEvent(
metrics_util::PASSWORD_SUBMISSION_FAILED);
}
+ base::RecordAction(base::UserMetricsAction("PasswordManager_LoginFailed"));
submit_result_ = kSubmitResultFailed;
}
void PasswordFormManager::WipeStoreCopyIfOutdated() {
- DCHECK_NE(PRE_MATCHING_PHASE, state_);
-
UMA_HISTOGRAM_BOOLEAN("PasswordManager.StoreReadyWhenWiping",
HasCompletedMatching());
@@ -1329,8 +1331,27 @@ void PasswordFormManager::SendVotesOnSave() {
}
}
+void PasswordFormManager::SetUserAction(UserAction user_action) {
+ if (user_action == kUserActionChoose) {
+ base::RecordAction(
+ base::UserMetricsAction("PasswordManager_UsedNonDefaultUsername"));
+ } else if (user_action == kUserActionChoosePslMatch) {
+ base::RecordAction(
+ base::UserMetricsAction("PasswordManager_ChoseSubdomainPassword"));
+ } else if (user_action == kUserActionOverridePassword) {
+ base::RecordAction(
+ base::UserMetricsAction("PasswordManager_LoggedInWithNewPassword"));
+ } else if (user_action == kUserActionOverrideUsernameAndPassword) {
+ base::RecordAction(
+ base::UserMetricsAction("PasswordManager_LoggedInWithNewUsername"));
+ } else {
+ NOTREACHED();
+ }
+ user_action_ = user_action;
+}
+
base::Optional<PasswordForm> PasswordFormManager::UpdatePendingAndGetOldKey(
- std::vector<const PasswordForm*>* credentials_to_update) {
+ std::vector<PasswordForm>* credentials_to_update) {
base::Optional<PasswordForm> old_primary_key;
bool update_related_credentials = false;
@@ -1368,7 +1389,7 @@ base::Optional<PasswordForm> PasswordFormManager::UpdatePendingAndGetOldKey(
// If this was a password update, then update all non-best matches entries
// with the same username and the same old password.
if (update_related_credentials) {
- PasswordFormMap::const_iterator updated_password_it =
+ auto updated_password_it =
best_matches_.find(pending_credentials_.username_value);
DCHECK(best_matches_.end() != updated_password_it);
const base::string16& old_password =
@@ -1377,8 +1398,9 @@ base::Optional<PasswordForm> PasswordFormManager::UpdatePendingAndGetOldKey(
if (not_best_match->username_value ==
pending_credentials_.username_value &&
not_best_match->password_value == old_password) {
- not_best_match->password_value = pending_credentials_.password_value;
- credentials_to_update->push_back(not_best_match.get());
+ credentials_to_update->push_back(*not_best_match);
+ credentials_to_update->back().password_value =
+ pending_credentials_.password_value;
}
}
}
diff --git a/chromium/components/password_manager/core/browser/password_form_manager.h b/chromium/components/password_manager/core/browser/password_form_manager.h
index faaa9cee916..3be0c704519 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/password_form_manager.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -15,10 +16,13 @@
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
+#include "base/strings/string16.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/form_fetcher.h"
+#include "components/password_manager/core/browser/form_fetcher_impl.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
@@ -31,17 +35,15 @@ class PasswordManagerClient;
// Per-password-form-{on-page, dialog} class responsible for interactions
// between a given form, the per-tab PasswordManager, and the PasswordStore.
-class PasswordFormManager : public PasswordStoreConsumer {
+class PasswordFormManager : public PasswordStoreConsumer,
+ public FormFetcher::Consumer {
public:
// |password_manager| owns this object
// |form_on_page| is the form that may be submitted and could need login data.
- // |ssl_valid| represents the security of the page containing observed_form,
- // used to filter login results from database.
PasswordFormManager(PasswordManager* password_manager,
PasswordManagerClient* client,
const base::WeakPtr<PasswordManagerDriver>& driver,
const autofill::PasswordForm& observed_form,
- bool ssl_valid,
std::unique_ptr<FormSaver> form_saver);
~PasswordFormManager() override;
@@ -80,7 +82,9 @@ class PasswordFormManager : public PasswordStoreConsumer {
MatchResultMask DoesManage(const autofill::PasswordForm& form) const;
// Retrieves potential matching logins from the database. In addition the
- // statistics is retrived on platforms with the password bubble.
+ // statistics is retrived on platforms with the password bubble. This is
+ // called automatically during construction and can be called manually later
+ // as well to cause an update of the cached credentials.
void FetchDataFromPasswordStore();
// Simple state-check to verify whether this object as received a callback
@@ -123,10 +127,9 @@ class PasswordFormManager : public PasswordStoreConsumer {
// PasswordStoreConsumer:
void OnGetPasswordStoreResults(
- ScopedVector<autofill::PasswordForm> results) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
void OnGetSiteStatistics(
- std::unique_ptr<std::vector<std::unique_ptr<InteractionsStats>>> stats)
- override;
+ std::vector<std::unique_ptr<InteractionsStats>> stats) override;
// A user opted to 'never remember' passwords for this form.
// Blacklist it so that from now on when it is seen we ignore it.
@@ -214,7 +217,8 @@ class PasswordFormManager : public PasswordStoreConsumer {
}
// Returns the best matches.
- const autofill::PasswordFormMap& best_matches() const {
+ const std::map<base::string16, const autofill::PasswordForm*>& best_matches()
+ const {
return best_matches_;
}
@@ -222,21 +226,9 @@ class PasswordFormManager : public PasswordStoreConsumer {
return preferred_match_;
}
- const std::vector<std::unique_ptr<autofill::PasswordForm>>&
- blacklisted_matches() const {
- return blacklisted_matches_;
- }
-
-#if defined(UNIT_TEST)
- void SimulateFetchMatchingLoginsFromPasswordStore() {
- // Just need to update the internal states.
- state_ = MATCHING_PHASE;
- }
-#endif
-
- const std::vector<std::unique_ptr<InteractionsStats>>& interactions_stats()
+ const std::vector<const autofill::PasswordForm*>& blacklisted_matches()
const {
- return interactions_stats_;
+ return blacklisted_matches_;
}
const autofill::PasswordForm& observed_form() const { return observed_form_; }
@@ -245,10 +237,7 @@ class PasswordFormManager : public PasswordStoreConsumer {
return is_possible_change_password_form_without_username_;
}
- const std::vector<std::unique_ptr<autofill::PasswordForm>>&
- federated_matches() {
- return federated_matches_;
- }
+ const FormFetcher* form_fetcher() { return form_fetcher_; }
// Use this to wipe copies of |pending_credentials_| from the password store
// (and |best_matches_| as well. It will only wipe if:
@@ -275,14 +264,13 @@ class PasswordFormManager : public PasswordStoreConsumer {
private:
// ManagerAction - What does the manager do with this form? Either it
// fills it, or it doesn't. If it doesn't fill it, that's either
- // because it has no match, or it is blacklisted, or it is disabled
- // via the AUTOCOMPLETE=off attribute. Note that if we don't have
- // an exact match, we still provide candidates that the user may
- // end up choosing.
+ // because it has no match or it is disabled via the AUTOCOMPLETE=off
+ // attribute. Note that if we don't have an exact match, we still provide
+ // candidates that the user may end up choosing.
enum ManagerAction {
kManagerActionNone = 0,
kManagerActionAutofilled,
- kManagerActionBlacklisted,
+ kManagerActionBlacklisted_Obsolete,
kManagerActionMax
};
@@ -345,9 +333,14 @@ class PasswordFormManager : public PasswordStoreConsumer {
// Trigger filling of HTTP auth dialog and update |manager_action_|.
void ProcessLoginPrompt();
- // Determines if we need to autofill given the results of the query.
- // Takes ownership of the elements in |result|.
- void OnRequestDone(ScopedVector<autofill::PasswordForm> result);
+ // Given all non-blacklisted |matches|, computes their score and populates
+ // |best_matches_|, |preferred_match_| and |non_best_matches_| accordingly.
+ void ScoreMatches(const std::vector<const autofill::PasswordForm*>& matches);
+
+ // FormFetcher::Consumer:
+ void ProcessMatches(
+ const std::vector<const autofill::PasswordForm*>& non_federated,
+ size_t filtered_count) override;
// Helper for Save in the case that best_matches.size() == 0, meaning
// we have no prior record of this form/username/password and the user
@@ -359,7 +352,10 @@ class PasswordFormManager : public PasswordStoreConsumer {
// against the observed_form_.
uint32_t ScoreResult(const autofill::PasswordForm& candidate) const;
- // For the blacklisted |form| returns true iff it blacklists |observed_form_|.
+ // Returns true iff |form| is a non-blacklisted match for |observed_form_|.
+ bool IsMatch(const autofill::PasswordForm& form) const;
+
+ // Returns true iff |form| blacklists |observed_form_|.
bool IsBlacklistMatch(const autofill::PasswordForm& form) const;
// Helper for Save in the case there is at least one match for the pending
@@ -444,7 +440,7 @@ class PasswordFormManager : public PasswordStoreConsumer {
// for empty |password| return nullptr and for non-empty |password| returns
// the unique entry in |best_matches_| with the same password, if it exists,
// and nullptr otherwise.
- autofill::PasswordForm* FindBestMatchForUpdatePassword(
+ const autofill::PasswordForm* FindBestMatchForUpdatePassword(
const base::string16& password) const;
// Try to find best matched to |form| from |best_matches_| by the rules:
@@ -456,47 +452,52 @@ class PasswordFormManager : public PasswordStoreConsumer {
// a form contains only one field which is a password) and there is an element
// from |best_matches_| with the same password as in |form| then return it;
// 4. Otherwise return nullptr.
- autofill::PasswordForm* FindBestSavedMatch(
+ const autofill::PasswordForm* FindBestSavedMatch(
const autofill::PasswordForm* form) const;
// Send appropriate votes based on what is currently being saved.
void SendVotesOnSave();
+ // Sets |user_action_| and records some metrics.
+ void SetUserAction(UserAction user_action);
+
// Edits some fields in |pending_credentials_| before it can be used to
// update the password store. It also goes through |not_best_matches|,
// updates the password of those which share the old password and username
// with |pending_credentials_| to the new password of |pending_credentials_|,
- // and adds pointers to all such modified credentials to
+ // and adds copies of all such modified credentials to
// |credentials_to_update|. If needed, this also returns a PasswordForm to be
// used as the old primary key during the store update.
base::Optional<autofill::PasswordForm> UpdatePendingAndGetOldKey(
- std::vector<const autofill::PasswordForm*>* credentials_to_update);
+ std::vector<autofill::PasswordForm>* credentials_to_update);
// Set of nonblacklisted PasswordForms from the DB that best match the form
- // being managed by this. Use a map instead of vector, because we most
- // frequently require lookups by username value in IsNewLogin.
- autofill::PasswordFormMap best_matches_;
+ // being managed by |this|, indexed by username. They are owned by
+ // |form_fetcher_|.
+ std::map<base::string16, const autofill::PasswordForm*> best_matches_;
// Set of forms from PasswordStore that correspond to the current site and
- // that are not in |best_matches_|.
- std::vector<std::unique_ptr<autofill::PasswordForm>> not_best_matches_;
-
- // Federated credentials relevant to the observed form. They are neither
- // filled not saved by this PasswordFormManager, so they are kept separately
- // from |best_matches_|. The PasswordFormManager passes them further to
- // PasswordManager to show them in the UI.
- std::vector<std::unique_ptr<autofill::PasswordForm>> federated_matches_;
+ // that are not in |best_matches_|. They are owned by |form_fetcher_|.
+ std::vector<const autofill::PasswordForm*> not_best_matches_;
// Set of blacklisted forms from the PasswordStore that best match the current
- // form.
- std::vector<std::unique_ptr<autofill::PasswordForm>> blacklisted_matches_;
+ // form. They are owned by |form_fetcher_|, with the exception that if
+ // |new_blacklisted_| is not null, the address of that form is also inside
+ // |blacklisted_matches_|..
+ std::vector<const autofill::PasswordForm*> blacklisted_matches_;
+
+ // If the observed form gets blacklisted through |this|, the blacklist entry
+ // gets stored in |new_blacklisted_| until data is potentially refreshed by
+ // reading from PasswordStore again. |blacklisted_matches_| will contain
+ // |new_blacklisted_.get()| in that case. The PasswordForm will usually get
+ // accessed via |blacklisted_matches_|, this unique_ptr is only used to store
+ // it (unlike the rest of forms being pointed to in |blacklisted_matches_|,
+ // which are owned by |form_fetcher_|.
+ std::unique_ptr<autofill::PasswordForm> new_blacklisted_;
// The PasswordForm from the page or dialog managed by |this|.
const autofill::PasswordForm observed_form_;
- // Statistics for the current domain.
- std::vector<std::unique_ptr<InteractionsStats>> interactions_stats_;
-
// Stores a submitted form.
std::unique_ptr<const autofill::PasswordForm> provisionally_saved_form_;
@@ -581,20 +582,6 @@ class PasswordFormManager : public PasswordStoreConsumer {
// local heuristics.
bool does_look_like_signup_form_ = false;
- typedef enum {
- PRE_MATCHING_PHASE, // Have not yet invoked a GetLogins query to find
- // matching login information from password store.
- MATCHING_PHASE, // We've made a GetLogins request, but
- // haven't received or finished processing result.
- POST_MATCHING_PHASE // We've queried the DB and processed matching
- // login results.
- } PasswordFormManagerState;
-
- // State of matching process, used to verify that we don't call methods
- // assuming we've already processed the request for matching logins,
- // when we actually haven't.
- PasswordFormManagerState state_;
-
// The client which implements embedder-specific PasswordManager operations.
PasswordManagerClient* client_;
@@ -625,6 +612,14 @@ class PasswordFormManager : public PasswordStoreConsumer {
// credentials.
std::unique_ptr<FormSaver> form_saver_;
+ // TODO(crbug.com/621355) Remove this, ultimately the form fetcher will not be
+ // owned by PasswordFormManager. Temporarily, this is the object which
+ // |form_fetcher_| points to.
+ FormFetcherImpl form_fetcher_impl_;
+
+ // FormFetcher instance which owns the login data from PasswordStore.
+ FormFetcher* const form_fetcher_;
+
DISALLOW_COPY_AND_ASSIGN(PasswordFormManager);
};
diff --git a/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
index e6c0b934031..df0a437ef56 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -14,6 +14,8 @@
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/user_action_tester.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/proto/server.pb.h"
@@ -22,7 +24,6 @@
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/browser/credentials_filter.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
@@ -30,6 +31,7 @@
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/statistics_table.h"
+#include "components/password_manager/core/browser/stub_credentials_filter.h"
#include "components/password_manager/core/browser/stub_form_saver.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/browser/stub_password_manager_driver.h"
@@ -43,6 +45,8 @@
#include "url/gurl.h"
#include "url/origin.h"
+using autofill::FieldPropertiesFlags;
+using autofill::FieldPropertiesMask;
using autofill::PasswordForm;
using base::ASCIIToUTF16;
using ::testing::_;
@@ -68,19 +72,20 @@ class MockFormSaver : public StubFormSaver {
// FormSaver:
MOCK_METHOD1(PermanentlyBlacklist, void(autofill::PasswordForm* observed));
- MOCK_METHOD3(Save,
- void(const autofill::PasswordForm& pending,
- const autofill::PasswordFormMap& best_matches,
- const autofill::PasswordForm* old_primary_key));
- MOCK_METHOD4(Update,
- void(const autofill::PasswordForm& pending,
- const autofill::PasswordFormMap& best_matches,
- const std::vector<const autofill::PasswordForm*>*
- credentials_to_update,
- const autofill::PasswordForm* old_primary_key));
+ MOCK_METHOD3(
+ Save,
+ void(const autofill::PasswordForm& pending,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
+ const autofill::PasswordForm* old_primary_key));
+ MOCK_METHOD4(
+ Update,
+ void(const autofill::PasswordForm& pending,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
+ const std::vector<autofill::PasswordForm>* credentials_to_update,
+ const autofill::PasswordForm* old_primary_key));
MOCK_METHOD3(WipeOutdatedCopies,
void(const autofill::PasswordForm& pending,
- autofill::PasswordFormMap* best_matches,
+ std::map<base::string16, const PasswordForm*>* best_matches,
const autofill::PasswordForm** preferred_match));
// Convenience downcasting method.
@@ -94,11 +99,11 @@ class MockFormSaver : public StubFormSaver {
// Invokes the password store consumer with a copy of all forms.
ACTION_P4(InvokeConsumer, form1, form2, form3, form4) {
- ScopedVector<PasswordForm> result;
- result.push_back(base::WrapUnique(new PasswordForm(form1)));
- result.push_back(base::WrapUnique(new PasswordForm(form2)));
- result.push_back(base::WrapUnique(new PasswordForm(form3)));
- result.push_back(base::WrapUnique(new PasswordForm(form4)));
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ result.push_back(base::MakeUnique<PasswordForm>(form1));
+ result.push_back(base::MakeUnique<PasswordForm>(form2));
+ result.push_back(base::MakeUnique<PasswordForm>(form3));
+ result.push_back(base::MakeUnique<PasswordForm>(form4));
arg0->OnGetPasswordStoreResults(std::move(result));
}
@@ -114,7 +119,7 @@ MATCHER_P2(CheckUploadedAutofillTypesAndSignature,
form_signature,
expected_types,
"Unexpected autofill types or form signature") {
- if (form_signature != arg.FormSignature()) {
+ if (form_signature != arg.FormSignatureAsStr()) {
// An unexpected form is uploaded.
return false;
}
@@ -151,10 +156,10 @@ MATCHER_P2(CheckUploadedGenerationTypesAndSignature,
form_signature,
expected_generation_types,
"Unexpected generation types or form signature") {
- if (form_signature != arg.FormSignature()) {
+ if (form_signature != arg.FormSignatureAsStr()) {
// Unexpected form's signature.
ADD_FAILURE() << "Expected form signature is " << form_signature
- << ", but found " << arg.FormSignature();
+ << ", but found " << arg.FormSignatureAsStr();
return false;
}
for (const autofill::AutofillField* field : arg) {
@@ -200,7 +205,26 @@ MATCHER_P2(CheckUploadedFormClassifierVote,
return true;
}
-void ClearVector(ScopedVector<PasswordForm>* results) {
+MATCHER_P(CheckFieldPropertiesMasksUpload,
+ expected_field_properties,
+ "Wrong field properties flags") {
+ for (const autofill::AutofillField* field : arg) {
+ autofill::FieldPropertiesMask expected_mask =
+ expected_field_properties.find(field->name) !=
+ expected_field_properties.end()
+ ? FieldPropertiesFlags::USER_TYPED
+ : 0;
+ if (field->properties_mask != expected_mask) {
+ ADD_FAILURE() << "Wrong field properties flags for field " << field->name
+ << ": expected mask " << expected_mask << ", but found "
+ << field->properties_mask;
+ return false;
+ }
+ }
+ return true;
+}
+
+void ClearVector(std::vector<std::unique_ptr<PasswordForm>>* results) {
results->clear();
}
@@ -279,20 +303,11 @@ class MockPasswordManagerDriver : public StubPasswordManagerDriver {
NiceMock<MockAutofillManager> mock_autofill_manager_;
};
-class MockStoreResultFilter : public CredentialsFilter {
+class MockStoreResultFilter : public StubCredentialsFilter {
public:
+ // This method is called by StubCredentialsFilter::FilterResults.
MOCK_CONST_METHOD1(FilterResultsPtr,
- void(ScopedVector<autofill::PasswordForm>* results));
-
- // This method is not relevant here.
- MOCK_CONST_METHOD1(ShouldSave, bool(const autofill::PasswordForm& form));
-
- // GMock cannot handle move-only arguments.
- ScopedVector<autofill::PasswordForm> FilterResults(
- ScopedVector<autofill::PasswordForm> results) const override {
- FilterResultsPtr(&results);
- return results;
- }
+ void(std::vector<std::unique_ptr<PasswordForm>>* results));
};
class TestPasswordManagerClient : public StubPasswordManagerClient {
@@ -414,9 +429,12 @@ class PasswordFormManagerTest : public testing::Test {
.WillByDefault(Return(std::vector<InteractionsStats*>()));
client_.reset(new TestPasswordManagerClient(mock_store_.get()));
password_manager_.reset(new PasswordManager(client_.get()));
+ EXPECT_CALL(*mock_store_,
+ GetLogins(PasswordStore::FormDigest(observed_form_), _));
form_manager_.reset(new PasswordFormManager(
password_manager_.get(), client_.get(), client_.get()->driver(),
- observed_form_, false, base::WrapUnique(new MockFormSaver())));
+ observed_form_, base::MakeUnique<NiceMock<MockFormSaver>>()));
+ Mock::VerifyAndClearExpectations(mock_store_.get());
}
void TearDown() override {
@@ -428,19 +446,18 @@ class PasswordFormManagerTest : public testing::Test {
void SimulateMatchingPhase(PasswordFormManager* p,
ResultOfSimulatedMatchingMask result) {
- EXPECT_CALL(*mock_store(), GetLogins(p->observed_form(), p));
- p->FetchDataFromPasswordStore();
if (result == RESULT_NO_MATCH) {
- p->OnGetPasswordStoreResults(ScopedVector<PasswordForm>());
+ p->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
return;
}
- ScopedVector<PasswordForm> result_form;
+ std::vector<std::unique_ptr<PasswordForm>> result_form;
if (result & RESULT_SAVED_MATCH) {
- result_form.push_back(new PasswordForm(saved_match_));
+ result_form.push_back(base::MakeUnique<PasswordForm>(saved_match_));
}
if (result & RESULT_PSL_MATCH) {
- result_form.push_back(new PasswordForm(psl_saved_match_));
+ result_form.push_back(base::MakeUnique<PasswordForm>(psl_saved_match_));
}
p->OnGetPasswordStoreResults(std::move(result_form));
}
@@ -457,10 +474,10 @@ class PasswordFormManagerTest : public testing::Test {
form.form_data = observed_form_data;
- PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), form, false,
- base::WrapUnique(new MockFormSaver()));
- ScopedVector<PasswordForm> result;
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), form,
+ base::MakeUnique<NiceMock<MockFormSaver>>());
+ std::vector<std::unique_ptr<PasswordForm>> result;
result.push_back(CreateSavedMatch(false));
result[0]->generation_upload_status = status;
result[0]->times_used = times_used;
@@ -478,15 +495,14 @@ class PasswordFormManagerTest : public testing::Test {
? result[0]->username_element
: base::string16();
- form_manager.SimulateFetchMatchingLoginsFromPasswordStore();
form_manager.OnGetPasswordStoreResults(std::move(result));
std::string expected_login_signature;
autofill::FormStructure observed_structure(observed_form_data);
autofill::FormStructure pending_structure(saved_match()->form_data);
- if (observed_structure.FormSignature() !=
- pending_structure.FormSignature() &&
+ if (observed_structure.FormSignatureAsStr() !=
+ pending_structure.FormSignatureAsStr() &&
times_used == 0) {
- expected_login_signature = observed_structure.FormSignature();
+ expected_login_signature = observed_structure.FormSignatureAsStr();
}
autofill::ServerFieldTypeSet expected_available_field_types;
expected_available_field_types.insert(autofill::USERNAME);
@@ -506,11 +522,11 @@ class PasswordFormManagerTest : public testing::Test {
if (field_type) {
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(
- CheckUploadedAutofillTypesAndSignature(
- pending_structure.FormSignature(), expected_types),
- false, expected_available_field_types,
- expected_login_signature, true));
+ StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
+ pending_structure.FormSignatureAsStr(),
+ expected_types),
+ false, expected_available_field_types,
+ expected_login_signature, true));
} else {
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(_, _, _, _, _))
@@ -537,7 +553,7 @@ class PasswordFormManagerTest : public testing::Test {
client()->set_is_update_password_ui_enabled(true);
PasswordFormManager form_manager(
password_manager(), client(), client()->driver(), *observed_form(),
- false, base::WrapUnique(new MockFormSaver()));
+ base::MakeUnique<NiceMock<MockFormSaver>>());
SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH);
@@ -576,12 +592,13 @@ class PasswordFormManagerTest : public testing::Test {
expected_available_field_types.insert(field_type);
std::string observed_form_signature =
- autofill::FormStructure(observed_form()->form_data).FormSignature();
+ autofill::FormStructure(observed_form()->form_data)
+ .FormSignatureAsStr();
std::string expected_login_signature;
if (field_type == autofill::NEW_PASSWORD) {
autofill::FormStructure pending_structure(saved_match()->form_data);
- expected_login_signature = pending_structure.FormSignature();
+ expected_login_signature = pending_structure.FormSignatureAsStr();
}
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
@@ -664,12 +681,11 @@ class PasswordFormManagerTest : public testing::Test {
saved_match()->password_value + ASCIIToUTF16("1");
}
- PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), form, false,
- base::WrapUnique(new MockFormSaver()));
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), form,
+ base::MakeUnique<NiceMock<MockFormSaver>>());
- ScopedVector<PasswordForm> result;
- form_manager.SimulateFetchMatchingLoginsFromPasswordStore();
+ std::vector<std::unique_ptr<PasswordForm>> result;
form_manager.OnGetPasswordStoreResults(std::move(result));
autofill::ServerFieldTypeSet expected_available_field_types;
@@ -700,7 +716,7 @@ class PasswordFormManagerTest : public testing::Test {
*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(
CheckUploadedGenerationTypesAndSignature(
- form_structure.FormSignature(), expected_generation_types),
+ form_structure.FormSignatureAsStr(), expected_generation_types),
false, expected_available_field_types, std::string(), true));
form_manager.ProvisionallySave(
@@ -711,9 +727,9 @@ class PasswordFormManagerTest : public testing::Test {
PasswordForm* observed_form() { return &observed_form_; }
PasswordForm* saved_match() { return &saved_match_; }
PasswordForm* psl_saved_match() { return &psl_saved_match_; }
- PasswordForm* CreateSavedMatch(bool blacklisted) {
+ std::unique_ptr<PasswordForm> CreateSavedMatch(bool blacklisted) {
// Owned by the caller of this method.
- PasswordForm* match = new PasswordForm(saved_match_);
+ auto match = base::MakeUnique<PasswordForm>(saved_match_);
match->blacklisted_by_user = blacklisted;
return match;
}
@@ -743,16 +759,11 @@ class PasswordFormManagerTest : public testing::Test {
class PasswordFormManagerFillOnAccountSelectTest
: public PasswordFormManagerTest {
public:
- PasswordFormManagerFillOnAccountSelectTest() {}
-
- void SetUp() override {
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- std::vector<const base::Feature*> enabled_features;
- std::vector<const base::Feature*> disabled_features;
- enabled_features.push_back(&features::kFillOnAccountSelect);
- SetFeatures(enabled_features, disabled_features, std::move(feature_list));
- PasswordFormManagerTest::SetUp();
+ PasswordFormManagerFillOnAccountSelectTest() {
+ scoped_feature_list_.InitAndEnableFeature(features::kFillOnAccountSelect);
}
+
+ base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(PasswordFormManagerTest, TestNewLogin) {
@@ -852,9 +863,8 @@ TEST_F(PasswordFormManagerTest, TestBlacklistMatching) {
observed_form()->action = GURL("http://accounts.google.com/a/Login");
observed_form()->signon_realm = "http://accounts.google.com";
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
- form_manager.SimulateFetchMatchingLoginsFromPasswordStore();
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
// Doesn't match because of PSL.
PasswordForm blacklisted_psl = *observed_form();
@@ -873,6 +883,10 @@ TEST_F(PasswordFormManagerTest, TestBlacklistMatching) {
blacklisted_not_match2.username_element = ASCIIToUTF16("Element");
blacklisted_not_match2.blacklisted_by_user = true;
+ // Doesn't match because of different PasswordForm::Scheme.
+ PasswordForm blacklisted_not_match3 = *observed_form();
+ blacklisted_not_match3.scheme = PasswordForm::SCHEME_BASIC;
+
// Matches because of same element names, despite different page
PasswordForm blacklisted_match = *observed_form();
blacklisted_match.origin = GURL("http://accounts.google.com/a/LoginAuth1234");
@@ -884,18 +898,19 @@ TEST_F(PasswordFormManagerTest, TestBlacklistMatching) {
blacklisted_match2.username_element = ASCIIToUTF16("Element");
blacklisted_match2.blacklisted_by_user = true;
- ScopedVector<PasswordForm> result;
- result.push_back(new PasswordForm(blacklisted_psl));
- result.push_back(new PasswordForm(blacklisted_not_match));
- result.push_back(new PasswordForm(blacklisted_not_match2));
- result.push_back(new PasswordForm(blacklisted_match));
- result.push_back(new PasswordForm(blacklisted_match2));
- result.push_back(new PasswordForm(*saved_match()));
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ result.push_back(base::MakeUnique<PasswordForm>(blacklisted_psl));
+ result.push_back(base::MakeUnique<PasswordForm>(blacklisted_not_match));
+ result.push_back(base::MakeUnique<PasswordForm>(blacklisted_not_match2));
+ result.push_back(base::MakeUnique<PasswordForm>(blacklisted_not_match3));
+ result.push_back(base::MakeUnique<PasswordForm>(blacklisted_match));
+ result.push_back(base::MakeUnique<PasswordForm>(blacklisted_match2));
+ result.push_back(base::MakeUnique<PasswordForm>(*saved_match()));
form_manager.OnGetPasswordStoreResults(std::move(result));
EXPECT_TRUE(form_manager.IsBlacklisted());
- EXPECT_THAT(
- form_manager.blacklisted_matches(),
- ElementsAre(Pointee(blacklisted_match), Pointee(blacklisted_match2)));
+ EXPECT_THAT(form_manager.blacklisted_matches(),
+ UnorderedElementsAre(Pointee(blacklisted_match),
+ Pointee(blacklisted_match2)));
EXPECT_EQ(1u, form_manager.best_matches().size());
EXPECT_EQ(*saved_match(), *form_manager.preferred_match());
}
@@ -911,11 +926,9 @@ TEST_F(PasswordFormManagerTest, AutofillBlacklisted) {
blacklisted.blacklisted_by_user = true;
blacklisted.username_value.clear();
- ScopedVector<PasswordForm> result;
- result.push_back(new PasswordForm(saved_form));
- result.push_back(new PasswordForm(blacklisted));
-
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ result.push_back(base::MakeUnique<PasswordForm>(saved_form));
+ result.push_back(base::MakeUnique<PasswordForm>(blacklisted));
autofill::PasswordFormFillData fill_data;
EXPECT_CALL(*client()->mock_driver(), FillPasswordForm(_))
@@ -991,8 +1004,8 @@ TEST_F(PasswordFormManagerTest, TestNewLoginFromNewPasswordElement) {
observed_form()->username_marked_by_site = true;
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
SimulateMatchingPhase(&form_manager, RESULT_NO_MATCH);
// User enters current and new credentials to the observed form.
@@ -1072,8 +1085,8 @@ TEST_F(PasswordFormManagerTest, TestUpdatePasswordFromNewPasswordElement) {
saved_match()->submit_element.clear();
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH);
// User submits current and new credentials to the observed form.
@@ -1113,31 +1126,6 @@ TEST_F(PasswordFormManagerTest, TestUpdatePasswordFromNewPasswordElement) {
EXPECT_EQ(saved_match()->submit_element, new_credentials.submit_element);
}
-TEST_F(PasswordFormManagerTest, TestIgnoreResult_SSL) {
- const bool kObservedFormSSLValid = false;
- PasswordFormManager form_manager(
- password_manager(), client(), client()->driver(), *observed_form(),
- kObservedFormSSLValid, base::WrapUnique(new MockFormSaver()));
-
- PasswordForm saved_form = *observed_form();
- saved_form.ssl_valid = !kObservedFormSSLValid;
- saved_form.username_value = ASCIIToUTF16("test1@gmail.com");
- ScopedVector<PasswordForm> result;
- result.push_back(new PasswordForm(saved_form));
- saved_form.username_value = ASCIIToUTF16("test2@gmail.com");
- result.push_back(new PasswordForm(saved_form));
- saved_form.username_value = ASCIIToUTF16("test3@gmail.com");
- saved_form.ssl_valid = kObservedFormSSLValid;
- result.push_back(new PasswordForm(saved_form));
- form_manager.SimulateFetchMatchingLoginsFromPasswordStore();
- form_manager.OnGetPasswordStoreResults(std::move(result));
-
- // Make sure we don't match a PasswordForm if it was originally saved on
- // an SSL-valid page and we are now on a page with invalid certificate.
- EXPECT_EQ(1u, form_manager.best_matches().count(saved_form.username_value));
- EXPECT_EQ(1u, form_manager.best_matches().size());
-}
-
TEST_F(PasswordFormManagerTest, TestIgnoreResult_Paths) {
PasswordForm observed(*observed_form());
observed.origin = GURL("https://accounts.google.com/a/LoginAuth");
@@ -1145,15 +1133,14 @@ TEST_F(PasswordFormManagerTest, TestIgnoreResult_Paths) {
observed.signon_realm = "https://accounts.google.com";
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), observed, false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), observed,
+ base::MakeUnique<MockFormSaver>());
PasswordForm saved_form = observed;
saved_form.origin = GURL("https://accounts.google.com/a/OtherLoginAuth");
saved_form.action = GURL("https://accounts.google.com/a/OtherLogin");
- ScopedVector<PasswordForm> result;
- result.push_back(new PasswordForm(saved_form));
- form_manager.SimulateFetchMatchingLoginsFromPasswordStore();
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ result.push_back(base::MakeUnique<PasswordForm>(saved_form));
form_manager.OnGetPasswordStoreResults(std::move(result));
// Different paths for action / origin are okay.
@@ -1167,14 +1154,13 @@ TEST_F(PasswordFormManagerTest, TestIgnoreResult_IgnoredCredentials) {
observed.signon_realm = "https://accounts.google.com";
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), observed, false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), observed,
+ base::MakeUnique<MockFormSaver>());
client()->FilterAllResults();
PasswordForm saved_form = observed;
- ScopedVector<PasswordForm> result;
- result.push_back(new PasswordForm(saved_form));
- form_manager.SimulateFetchMatchingLoginsFromPasswordStore();
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ result.push_back(base::MakeUnique<PasswordForm>(saved_form));
form_manager.OnGetPasswordStoreResults(std::move(result));
// Results should be ignored if the client requests it.
@@ -1235,9 +1221,8 @@ TEST_F(PasswordFormManagerTest, TestAlternateUsername_NoChange) {
PasswordForm saved_form = *saved_match();
ASSERT_FALSE(saved_form.other_possible_usernames.empty());
- ScopedVector<PasswordForm> result;
- result.push_back(new PasswordForm(saved_form));
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ result.push_back(base::MakeUnique<PasswordForm>(saved_form));
form_manager()->OnGetPasswordStoreResults(std::move(result));
// The saved match has the right username already.
@@ -1272,9 +1257,8 @@ TEST_F(PasswordFormManagerTest, TestAlternateUsername_OtherUsername) {
PasswordForm saved_form = *saved_match();
ASSERT_FALSE(saved_form.other_possible_usernames.empty());
- ScopedVector<PasswordForm> result;
- result.push_back(new PasswordForm(saved_form));
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
+ std::vector<std::unique_ptr<autofill::PasswordForm>> result;
+ result.push_back(base::MakeUnique<PasswordForm>(saved_form));
form_manager()->OnGetPasswordStoreResults(std::move(result));
// The saved match has the right username already.
@@ -1309,8 +1293,8 @@ TEST_F(PasswordFormManagerTest, TestSendNotBlacklistedMessage_NoCredentials) {
// "not blacklisted" message.
EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_))
.Times(1);
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
- form_manager()->OnGetPasswordStoreResults(ScopedVector<PasswordForm>());
+ form_manager()->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
}
TEST_F(PasswordFormManagerTest, TestSendNotBlacklistedMessage_Credentials) {
@@ -1319,8 +1303,7 @@ TEST_F(PasswordFormManagerTest, TestSendNotBlacklistedMessage_Credentials) {
// should be called to send the "not blacklisted" message.
EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_))
.Times(1);
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
simulated_results.push_back(CreateSavedMatch(false));
form_manager()->OnGetPasswordStoreResults(std::move(simulated_results));
}
@@ -1334,12 +1317,11 @@ TEST_F(PasswordFormManagerTest,
signup_form.new_password_element = base::ASCIIToUTF16("new_password_field");
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), signup_form, false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), signup_form,
+ base::MakeUnique<MockFormSaver>());
EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_))
.Times(1);
- form_manager.SimulateFetchMatchingLoginsFromPasswordStore();
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
simulated_results.push_back(CreateSavedMatch(false));
form_manager.OnGetPasswordStoreResults(std::move(simulated_results));
}
@@ -1350,8 +1332,7 @@ TEST_F(PasswordFormManagerTest,
// password store, but they are blacklisted. AllowPasswordGenerationForForm
// is still called.
EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_));
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
simulated_results.push_back(CreateSavedMatch(true));
form_manager()->OnGetPasswordStoreResults(std::move(simulated_results));
}
@@ -1359,37 +1340,37 @@ TEST_F(PasswordFormManagerTest,
TEST_F(PasswordFormManagerTest, TestBestCredentialsByEachUsernameAreIncluded) {
// Simulate having several matches, with 3 different usernames. Some of the
// matches are PSL matches. One match for each username should be chosen.
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
// Add a best scoring match. It should be in |best_matches| and chosen as a
// prefferred match.
- simulated_results.push_back(new PasswordForm(*saved_match()));
+ simulated_results.push_back(base::MakeUnique<PasswordForm>(*saved_match()));
// Add a match saved on another form, it has lower score. It should not be in
// |best_matches|.
- simulated_results.push_back(new PasswordForm(*saved_match()));
+ simulated_results.push_back(base::MakeUnique<PasswordForm>(*saved_match()));
simulated_results[1]->password_element = ASCIIToUTF16("signup_password");
simulated_results[1]->username_element = ASCIIToUTF16("signup_username");
// Add a match saved on another form with a different username. It should be
// in |best_matches|.
- simulated_results.push_back(new PasswordForm(*saved_match()));
+ simulated_results.push_back(base::MakeUnique<PasswordForm>(*saved_match()));
auto username1 = simulated_results[0]->username_value + ASCIIToUTF16("1");
simulated_results[2]->username_value = username1;
simulated_results[2]->password_element = ASCIIToUTF16("signup_password");
simulated_results[2]->username_element = ASCIIToUTF16("signup_username");
// Add a PSL match, it should not be in |best_matches|.
- simulated_results.push_back(new PasswordForm(*psl_saved_match()));
+ simulated_results.push_back(
+ base::MakeUnique<PasswordForm>(*psl_saved_match()));
// Add a PSL match with a different username. It should be in |best_matches|.
- simulated_results.push_back(new PasswordForm(*psl_saved_match()));
+ simulated_results.push_back(
+ base::MakeUnique<PasswordForm>(*psl_saved_match()));
auto username2 = simulated_results[0]->username_value + ASCIIToUTF16("2");
simulated_results[4]->username_value = username2;
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
-
autofill::PasswordFormFillData fill_data;
EXPECT_CALL(*client()->mock_driver(), FillPasswordForm(_))
.WillOnce(SaveArg<0>(&fill_data));
form_manager()->OnGetPasswordStoreResults(std::move(simulated_results));
- const autofill::PasswordFormMap& best_matches =
+ const std::map<base::string16, const PasswordForm*>& best_matches =
form_manager()->best_matches();
EXPECT_EQ(3u, best_matches.size());
EXPECT_NE(best_matches.end(),
@@ -1403,35 +1384,11 @@ TEST_F(PasswordFormManagerTest, TestBestCredentialsByEachUsernameAreIncluded) {
EXPECT_EQ(2u, fill_data.additional_logins.size());
}
-TEST_F(PasswordFormManagerTest,
- TestForceInclusionOfGeneratedPasswords_NoMatch) {
- // Same thing, except this time the credentials that don't match quite as
- // well are generated. They should now be sent to Autofill().
- EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_));
-
- ScopedVector<PasswordForm> simulated_results;
- simulated_results.push_back(CreateSavedMatch(false));
- simulated_results.push_back(CreateSavedMatch(false));
- simulated_results[0]->username_value = ASCIIToUTF16("other@gmail.com");
- simulated_results[0]->password_element = ASCIIToUTF16("signup_password");
- simulated_results[0]->username_element = ASCIIToUTF16("signup_username");
- simulated_results[0]->type = PasswordForm::TYPE_GENERATED;
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
-
- autofill::PasswordFormFillData fill_data;
- EXPECT_CALL(*client()->mock_driver(), FillPasswordForm(_))
- .WillOnce(SaveArg<0>(&fill_data));
-
- form_manager()->OnGetPasswordStoreResults(std::move(simulated_results));
- EXPECT_EQ(2u, form_manager()->best_matches().size());
- EXPECT_EQ(1u, fill_data.additional_logins.size());
-}
-
TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernames) {
const base::string16 kUsernameOther = ASCIIToUTF16("other username");
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
- form_manager()->OnGetPasswordStoreResults(ScopedVector<PasswordForm>());
+ form_manager()->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
PasswordForm credentials(*observed_form());
credentials.other_possible_usernames.push_back(ASCIIToUTF16("543-43-1234"));
@@ -1461,8 +1418,8 @@ TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernamesDuplicates) {
const base::string16 kUsernameDuplicate = ASCIIToUTF16("duplicate");
const base::string16 kUsernameRandom = ASCIIToUTF16("random");
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
- form_manager()->OnGetPasswordStoreResults(ScopedVector<PasswordForm>());
+ form_manager()->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
PasswordForm credentials(*observed_form());
credentials.other_possible_usernames.push_back(ASCIIToUTF16("511-32-9830"));
@@ -1502,11 +1459,8 @@ TEST_F(PasswordFormManagerTest, TestUpdateIncompleteCredentials) {
EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_));
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), encountered_form, false,
- base::WrapUnique(new MockFormSaver()));
-
- EXPECT_CALL(*mock_store(), GetLogins(encountered_form, &form_manager));
- form_manager.FetchDataFromPasswordStore();
+ client()->driver(), encountered_form,
+ base::MakeUnique<MockFormSaver>());
// Password store only has these incomplete credentials.
std::unique_ptr<PasswordForm> incomplete_form(new PasswordForm());
@@ -1515,7 +1469,6 @@ TEST_F(PasswordFormManagerTest, TestUpdateIncompleteCredentials) {
incomplete_form->password_value = ASCIIToUTF16("my_password");
incomplete_form->username_value = ASCIIToUTF16("my_username");
incomplete_form->preferred = true;
- incomplete_form->ssl_valid = false;
incomplete_form->scheme = PasswordForm::SCHEME_HTML;
// We expect to see this form eventually sent to the Password store. It
@@ -1532,7 +1485,7 @@ TEST_F(PasswordFormManagerTest, TestUpdateIncompleteCredentials) {
obsolete_form.action = encountered_form.action;
// Feed the incomplete credentials to the manager.
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
simulated_results.push_back(std::move(incomplete_form));
form_manager.OnGetPasswordStoreResults(std::move(simulated_results));
@@ -1556,7 +1509,7 @@ TEST_F(PasswordFormManagerTest, TestScoringPublicSuffixMatch) {
// Second candidate has the same signon realm as the form, but has a different
// origin and action. Public suffix match is the most important criterion so
// the second candidate should be selected.
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
simulated_results.push_back(CreateSavedMatch(false));
simulated_results.push_back(CreateSavedMatch(false));
simulated_results[0]->is_public_suffix_match = true;
@@ -1564,7 +1517,6 @@ TEST_F(PasswordFormManagerTest, TestScoringPublicSuffixMatch) {
GURL("http://accounts.google.com/a/ServiceLoginAuth2");
simulated_results[1]->action =
GURL("http://accounts.google.com/a/ServiceLogin2");
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
autofill::PasswordFormFillData fill_data;
EXPECT_CALL(*client()->mock_driver(), FillPasswordForm(_))
@@ -1596,9 +1548,8 @@ TEST_F(PasswordFormManagerTest, AndroidCredentialsAreAutofilled) {
EXPECT_CALL(*client()->mock_driver(), FillPasswordForm(_))
.WillOnce(SaveArg<0>(&fill_data));
- ScopedVector<PasswordForm> simulated_results;
- simulated_results.push_back(new PasswordForm(android_login));
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
+ simulated_results.push_back(base::MakeUnique<PasswordForm>(android_login));
form_manager()->OnGetPasswordStoreResults(std::move(simulated_results));
EXPECT_TRUE(fill_data.additional_logins.empty());
EXPECT_FALSE(fill_data.wait_for_username);
@@ -1646,37 +1597,40 @@ TEST_F(PasswordFormManagerTest, AndroidCredentialsAreProtected) {
// from Android: the first has the same username as the web-based credential,
// so it should be suppressed, but the second has a different username, so it
// should be shown.
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
simulated_results.push_back(CreateSavedMatch(false));
simulated_results[0]->username_value = ASCIIToUTF16(kTestUsername1);
simulated_results[0]->password_value = ASCIIToUTF16(kTestWebPassword);
- simulated_results.push_back(new PasswordForm);
+ simulated_results.push_back(base::MakeUnique<PasswordForm>());
simulated_results[1]->signon_realm = "android://hash@com.google.android";
simulated_results[1]->origin = GURL("android://hash@com.google.android/");
simulated_results[1]->username_value = ASCIIToUTF16(kTestUsername1);
simulated_results[1]->password_value = ASCIIToUTF16(kTestAndroidPassword1);
- simulated_results.push_back(new PasswordForm(*simulated_results[1]));
+ simulated_results.push_back(
+ base::MakeUnique<PasswordForm>(*simulated_results[1]));
simulated_results[2]->username_value = ASCIIToUTF16(kTestUsername2);
simulated_results[2]->password_value = ASCIIToUTF16(kTestAndroidPassword2);
- ScopedVector<PasswordForm> expected_matches;
- expected_matches.push_back(new PasswordForm(*simulated_results[0]));
- expected_matches.push_back(new PasswordForm(*simulated_results[2]));
+ std::vector<std::unique_ptr<PasswordForm>> expected_matches;
+ expected_matches.push_back(
+ base::MakeUnique<PasswordForm>(*simulated_results[0]));
+ expected_matches.push_back(
+ base::MakeUnique<PasswordForm>(*simulated_results[2]));
autofill::PasswordFormFillData fill_data;
EXPECT_CALL(*client()->mock_driver(), FillPasswordForm(_))
.WillOnce(SaveArg<0>(&fill_data));
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
form_manager()->OnGetPasswordStoreResults(std::move(simulated_results));
EXPECT_FALSE(fill_data.wait_for_username);
EXPECT_EQ(1u, fill_data.additional_logins.size());
- std::vector<PasswordForm*> actual_matches;
+ std::vector<std::unique_ptr<PasswordForm>> actual_matches;
for (const auto& username_match_pair : form_manager()->best_matches())
- actual_matches.push_back(username_match_pair.second.get());
+ actual_matches.push_back(
+ base::MakeUnique<PasswordForm>(*username_match_pair.second));
EXPECT_THAT(actual_matches,
- UnorderedPasswordFormElementsAre(expected_matches.get()));
+ UnorderedPasswordFormElementsAre(&expected_matches));
}
TEST_F(PasswordFormManagerTest, InvalidActionURLsDoNotMatch) {
@@ -1690,9 +1644,9 @@ TEST_F(PasswordFormManagerTest, InvalidActionURLsDoNotMatch) {
PasswordFormManager::RESULT_ACTION_MATCH);
// Then when the observed form has an invalid URL:
PasswordForm valid_action_form(*observed_form());
- PasswordFormManager invalid_manager(
- password_manager(), client(), client()->driver(), invalid_action_form,
- false, base::WrapUnique(new MockFormSaver()));
+ PasswordFormManager invalid_manager(password_manager(), client(),
+ client()->driver(), invalid_action_form,
+ base::MakeUnique<MockFormSaver>());
EXPECT_EQ(0,
invalid_manager.DoesManage(valid_action_form) &
PasswordFormManager::RESULT_ACTION_MATCH);
@@ -1710,7 +1664,7 @@ TEST_F(PasswordFormManagerTest, EmptyActionURLsDoNotMatchNonEmpty) {
PasswordForm valid_action_form(*observed_form());
PasswordFormManager empty_action_manager(
password_manager(), client(), client()->driver(), empty_action_form,
- false, base::WrapUnique(new MockFormSaver()));
+ base::MakeUnique<MockFormSaver>());
EXPECT_EQ(0,
empty_action_manager.DoesManage(valid_action_form) &
PasswordFormManager::RESULT_ACTION_MATCH);
@@ -1726,8 +1680,8 @@ TEST_F(PasswordFormManagerTest, NonHTMLFormsDoNotMatchHTMLForms) {
// The other way round: observing a non-HTML form, don't match a HTML form.
PasswordForm html_form(*observed_form());
PasswordFormManager non_html_manager(password_manager(), client(), kNoDriver,
- non_html_form, false,
- base::WrapUnique(new MockFormSaver()));
+ non_html_form,
+ base::MakeUnique<MockFormSaver>());
EXPECT_EQ(0, non_html_manager.DoesManage(html_form) &
PasswordFormManager::RESULT_HTML_ATTRIBUTES_MATCH);
}
@@ -1762,9 +1716,9 @@ TEST_F(PasswordFormManagerTest,
PasswordForm secure_observed_form(*observed_form());
secure_observed_form.origin = GURL("https://accounts.google.com/a/LoginAuth");
- PasswordFormManager secure_manager(
- password_manager(), client(), client()->driver(), secure_observed_form,
- true, base::WrapUnique(new MockFormSaver()));
+ PasswordFormManager secure_manager(password_manager(), client(),
+ client()->driver(), secure_observed_form,
+ base::MakeUnique<MockFormSaver>());
// Also for HTTPS in the observed form, and HTTP in the compared form, an
// exact path match is expected.
EXPECT_EQ(0, secure_manager.DoesManage(form_longer_path) &
@@ -1790,28 +1744,40 @@ TEST_F(PasswordFormManagerTest, OriginCheck_OnlyOriginsMatch) {
PasswordFormManager::RESULT_ORIGINS_MATCH);
}
+// Test that if multiple credentials with the same username are stored, and the
+// user updates the password, then all of the stored passwords get updated as
+// long as they have the same password value.
TEST_F(PasswordFormManagerTest, CorrectlyUpdatePasswordsWithSameUsername) {
EXPECT_CALL(*client()->mock_driver(), AllowPasswordGenerationForForm(_));
- // Add two credentials with the same username. Both should score the same
- // and be seen as candidates to autofill.
PasswordForm first(*saved_match());
first.action = observed_form()->action;
first.password_value = ASCIIToUTF16("first");
first.preferred = true;
+ // The second credential has the same password value, but it has a different
+ // |username_element| to make a different unique key for the database
+ // (otherwise the two credentials could not be stored at the same time). The
+ // different unique key results in a slightly lower score than for |first|.
PasswordForm second(first);
- second.password_value = ASCIIToUTF16("second");
+ second.username_element.clear();
second.preferred = false;
- ScopedVector<PasswordForm> result;
- result.push_back(new PasswordForm(first));
- result.push_back(new PasswordForm(second));
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
+ // The third credential has a different password value. It also has a
+ // different |password_element| to make a different unique key for the
+ // database again.
+ PasswordForm third(first);
+ third.password_element.clear();
+ third.password_value = ASCIIToUTF16("second");
+ third.preferred = false;
+
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ result.push_back(base::MakeUnique<PasswordForm>(first));
+ result.push_back(base::MakeUnique<PasswordForm>(second));
+ result.push_back(base::MakeUnique<PasswordForm>(third));
form_manager()->OnGetPasswordStoreResults(std::move(result));
- // We always take the first credential with a particular username, regardless
- // of which ones are labeled preferred.
+ // |first| scored slightly higher.
EXPECT_EQ(ASCIIToUTF16("first"),
form_manager()->preferred_match()->password_value);
@@ -1825,23 +1791,33 @@ TEST_F(PasswordFormManagerTest, CorrectlyUpdatePasswordsWithSameUsername) {
EXPECT_FALSE(form_manager()->IsNewLogin());
PasswordForm saved_result;
+ std::vector<PasswordForm> credentials_to_update;
EXPECT_CALL(MockFormSaver::Get(form_manager()), Update(_, _, _, nullptr))
- .WillOnce(testing::SaveArg<0>(&saved_result));
+ .WillOnce(testing::DoAll(SaveArg<0>(&saved_result),
+ SaveArgPointee<2>(&credentials_to_update)));
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(_, false, _, _, true));
form_manager()->Save();
- // Make sure that the password is updated appropriately.
+ // What was |first| above should be the main credential updated.
EXPECT_EQ(ASCIIToUTF16("third"), saved_result.password_value);
+ EXPECT_FALSE(saved_result.password_element.empty());
+ EXPECT_FALSE(saved_result.username_element.empty());
+
+ // What was |second| above should be another credential updated.
+ ASSERT_EQ(1u, credentials_to_update.size());
+ EXPECT_EQ(ASCIIToUTF16("third"), credentials_to_update[0].password_value);
+ EXPECT_FALSE(credentials_to_update[0].password_element.empty());
+ EXPECT_TRUE(credentials_to_update[0].username_element.empty());
}
TEST_F(PasswordFormManagerTest, UploadFormData_NewPassword) {
// For newly saved passwords, upload a password vote for autofill::PASSWORD.
// Don't vote for the username field yet.
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *saved_match(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *saved_match(),
+ base::MakeUnique<NiceMock<MockFormSaver>>());
SimulateMatchingPhase(&form_manager, RESULT_NO_MATCH);
PasswordForm form_to_save(*saved_match());
@@ -1862,8 +1838,8 @@ TEST_F(PasswordFormManagerTest, UploadFormData_NewPassword) {
// Do not upload a vote if the user is blacklisting the form.
PasswordFormManager blacklist_form_manager(
- password_manager(), client(), client()->driver(), *saved_match(), false,
- base::WrapUnique(new MockFormSaver()));
+ password_manager(), client(), client()->driver(), *saved_match(),
+ base::MakeUnique<NiceMock<MockFormSaver>>());
SimulateMatchingPhase(&blacklist_form_manager, RESULT_NO_MATCH);
expected_available_field_types.clear();
@@ -1917,8 +1893,8 @@ TEST_F(PasswordFormManagerTest, UploadPasswordForm) {
TEST_F(PasswordFormManagerTest, CorrectlySavePasswordWithoutUsernameFields) {
EXPECT_CALL(*client()->mock_driver(), AllowPasswordGenerationForForm(_));
- form_manager()->SimulateFetchMatchingLoginsFromPasswordStore();
- form_manager()->OnGetPasswordStoreResults(ScopedVector<PasswordForm>());
+ form_manager()->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
PasswordForm login(*observed_form());
login.username_element.clear();
@@ -1958,26 +1934,20 @@ TEST_F(PasswordFormManagerTest, DriverDeletedBeforeStoreDone) {
form->submit_element = ASCIIToUTF16("s");
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *form, false,
- base::WrapUnique(new MockFormSaver()));
-
- EXPECT_CALL(*mock_store(), GetLogins(*form, &form_manager));
- form_manager.FetchDataFromPasswordStore();
+ client()->driver(), *form,
+ base::MakeUnique<MockFormSaver>());
// Suddenly, the frame and its driver disappear.
client()->KillDriver();
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
simulated_results.push_back(std::move(form));
form_manager.OnGetPasswordStoreResults(std::move(simulated_results));
}
TEST_F(PasswordFormManagerTest, PreferredMatchIsUpToDate) {
// Check that preferred_match() is always a member of best_matches().
- EXPECT_CALL(*mock_store(), GetLogins(*observed_form(), form_manager()));
- form_manager()->FetchDataFromPasswordStore();
-
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
std::unique_ptr<PasswordForm> form(new PasswordForm(*observed_form()));
form->username_value = ASCIIToUTF16("username");
form->password_value = ASCIIToUTF16("password1");
@@ -1994,7 +1964,7 @@ TEST_F(PasswordFormManagerTest, PreferredMatchIsUpToDate) {
form_manager()->OnGetPasswordStoreResults(std::move(simulated_results));
EXPECT_EQ(1u, form_manager()->best_matches().size());
EXPECT_EQ(form_manager()->preferred_match(),
- form_manager()->best_matches().begin()->second.get());
+ form_manager()->best_matches().begin()->second);
// Make sure to access all fields of preferred_match; this way if it was
// deleted, ASAN might notice it.
PasswordForm dummy(*form_manager()->preferred_match());
@@ -2006,8 +1976,8 @@ TEST_F(PasswordFormManagerTest,
base::ASCIIToUTF16("new_password_field");
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH);
// The user submits a password on a change-password form, which does not use
@@ -2103,12 +2073,10 @@ TEST_F(PasswordFormManagerTest, TestSuggestingPasswordChangeForms) {
PasswordForm observed_change_password_form = *observed_form();
observed_change_password_form.new_password_element =
base::ASCIIToUTF16("new_pwd");
- PasswordFormManager manager_creds(password_manager(), client(),
- client()->driver(),
- observed_change_password_form, false,
- base::WrapUnique(new MockFormSaver()));
- manager_creds.SimulateFetchMatchingLoginsFromPasswordStore();
- ScopedVector<PasswordForm> simulated_results;
+ PasswordFormManager manager_creds(
+ password_manager(), client(), client()->driver(),
+ observed_change_password_form, base::MakeUnique<MockFormSaver>());
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
simulated_results.push_back(CreateSavedMatch(false));
autofill::PasswordFormFillData fill_data;
@@ -2142,8 +2110,8 @@ TEST_F(PasswordFormManagerTest, TestUpdateMethod) {
client()->set_is_update_password_ui_enabled(true);
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH);
// User submits current and new credentials to the observed form.
@@ -2205,8 +2173,8 @@ TEST_F(PasswordFormManagerTest, TestUpdateNoUsernameTextfieldPresent) {
client()->set_is_update_password_ui_enabled(true);
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH);
// User submits current and new credentials to the observed form.
@@ -2255,12 +2223,10 @@ TEST_F(PasswordFormManagerTest, WipeStoreCopyIfOutdated_BeforeStoreCallback) {
ASSERT_FALSE(form.password_value.empty());
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), form, false,
- base::WrapUnique(new MockFormSaver()));
-
- // Do not notify the store observer after this GetLogins call.
- EXPECT_CALL(*mock_store(), GetLogins(_, _));
- form_manager.FetchDataFromPasswordStore();
+ client()->driver(), form,
+ base::MakeUnique<MockFormSaver>());
+ // The creation of |form_manager| caused a GetLogins call. This test does not
+ // provide the callback for that call back to |form_manager| on purpose.
PasswordForm submitted_form(form);
submitted_form.password_value += ASCIIToUTF16("add stuff, make it different");
@@ -2276,9 +2242,6 @@ TEST_F(PasswordFormManagerTest, WipeStoreCopyIfOutdated_BeforeStoreCallback) {
}
TEST_F(PasswordFormManagerTest, GenerationStatusChangedWithPassword) {
- EXPECT_CALL(*mock_store(), GetLogins(*observed_form(), form_manager()));
- form_manager()->FetchDataFromPasswordStore();
-
std::unique_ptr<PasswordForm> generated_form(
new PasswordForm(*observed_form()));
generated_form->type = PasswordForm::TYPE_GENERATED;
@@ -2289,7 +2252,7 @@ TEST_F(PasswordFormManagerTest, GenerationStatusChangedWithPassword) {
PasswordForm submitted_form(*generated_form);
submitted_form.password_value = ASCIIToUTF16("password3");
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
simulated_results.push_back(std::move(generated_form));
form_manager()->OnGetPasswordStoreResults(std::move(simulated_results));
@@ -2307,9 +2270,6 @@ TEST_F(PasswordFormManagerTest, GenerationStatusChangedWithPassword) {
TEST_F(PasswordFormManagerTest, GenerationStatusNotUpdatedIfPasswordUnchanged) {
base::HistogramTester histogram_tester;
- EXPECT_CALL(*mock_store(), GetLogins(*observed_form(), form_manager()));
- form_manager()->FetchDataFromPasswordStore();
-
std::unique_ptr<PasswordForm> generated_form(
new PasswordForm(*observed_form()));
generated_form->type = PasswordForm::TYPE_GENERATED;
@@ -2319,7 +2279,7 @@ TEST_F(PasswordFormManagerTest, GenerationStatusNotUpdatedIfPasswordUnchanged) {
PasswordForm submitted_form(*generated_form);
- ScopedVector<PasswordForm> simulated_results;
+ std::vector<std::unique_ptr<PasswordForm>> simulated_results;
simulated_results.push_back(std::move(generated_form));
form_manager()->OnGetPasswordStoreResults(std::move(simulated_results));
@@ -2338,17 +2298,19 @@ TEST_F(PasswordFormManagerTest, GenerationStatusNotUpdatedIfPasswordUnchanged) {
TEST_F(PasswordFormManagerTest,
FetchMatchingLoginsFromPasswordStore_Reentrance) {
- EXPECT_CALL(*mock_store(),
- GetLogins(form_manager()->observed_form(), form_manager()))
- .Times(2);
form_manager()->FetchDataFromPasswordStore();
form_manager()->FetchDataFromPasswordStore();
// First response from the store, should be ignored.
std::unique_ptr<PasswordForm> saved_form(new PasswordForm(*saved_match()));
saved_form->username_value = ASCIIToUTF16("a@gmail.com");
- ScopedVector<PasswordForm> results;
+ std::vector<std::unique_ptr<PasswordForm>> results;
results.push_back(std::move(saved_form));
+ // Expect the additional call for GetLogins after the first response arrives.
+ EXPECT_CALL(
+ *mock_store(),
+ GetLogins(PasswordStore::FormDigest(form_manager()->observed_form()),
+ form_manager()));
form_manager()->OnGetPasswordStoreResults(std::move(results));
EXPECT_TRUE(form_manager()->best_matches().empty());
@@ -2388,17 +2350,15 @@ TEST_F(PasswordFormManagerTest, ProcessFrame_DriverBeforeMatching) {
EXPECT_CALL(extra_driver, FillPasswordForm(_));
- // Ask store for logins, but store should not respond yet.
- EXPECT_CALL(*mock_store(),
- GetLogins(form_manager()->observed_form(), form_manager()));
- form_manager()->FetchDataFromPasswordStore();
+ // The PasswordStore was asked store for logins when |form_manager()| was
+ // created, but should not respond yet.
// Now add the extra driver.
form_manager()->ProcessFrame(extra_driver.AsWeakPtr());
// Password store responds.
std::unique_ptr<PasswordForm> match(new PasswordForm(*saved_match()));
- ScopedVector<PasswordForm> result_form;
+ std::vector<std::unique_ptr<PasswordForm>> result_form;
result_form.push_back(std::move(match));
form_manager()->OnGetPasswordStoreResults(std::move(result_form));
}
@@ -2406,6 +2366,7 @@ TEST_F(PasswordFormManagerTest, ProcessFrame_DriverBeforeMatching) {
TEST_F(PasswordFormManagerTest, ProcessFrame_StoreUpdatesCausesAutofill) {
EXPECT_CALL(*client()->mock_driver(), FillPasswordForm(_)).Times(2);
SimulateMatchingPhase(form_manager(), RESULT_SAVED_MATCH);
+ form_manager()->FetchDataFromPasswordStore();
SimulateMatchingPhase(form_manager(), RESULT_SAVED_MATCH);
}
@@ -2419,7 +2380,8 @@ TEST_F(PasswordFormManagerTest, UpdateFormManagers_IsCalled) {
password_manager()->OnPasswordFormsParsed(client()->mock_driver(), observed);
// Make sure that the additional PFM is in POST_MATCHING phase.
ASSERT_TRUE(consumer);
- consumer->OnGetPasswordStoreResults(ScopedVector<PasswordForm>());
+ consumer->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
// Now prepare |form_manager()| for saving.
SimulateMatchingPhase(form_manager(), RESULT_NO_MATCH);
@@ -2449,8 +2411,8 @@ TEST_F(PasswordFormManagerTest, UploadChangePasswordForm_NOT_NEW_PASSWORD) {
TEST_F(PasswordFormManagerTest, TestUpdatePSLMatchedCredentials) {
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH | RESULT_PSL_MATCH);
// User submits a credentials with an old username and a new password.
@@ -2468,7 +2430,7 @@ TEST_F(PasswordFormManagerTest, TestUpdatePSLMatchedCredentials) {
// Trigger saving to exercise some special case handling during updating.
PasswordForm new_credentials;
- std::vector<const autofill::PasswordForm*> credentials_to_update;
+ std::vector<autofill::PasswordForm> credentials_to_update;
EXPECT_CALL(MockFormSaver::Get(&form_manager), Update(_, _, _, nullptr))
.WillOnce(testing::DoAll(SaveArg<0>(&new_credentials),
SaveArgPointee<2>(&credentials_to_update)));
@@ -2487,21 +2449,21 @@ TEST_F(PasswordFormManagerTest, TestUpdatePSLMatchedCredentials) {
ASSERT_EQ(1u, credentials_to_update.size());
EXPECT_EQ(credentials.password_value,
- credentials_to_update[0]->password_value);
+ credentials_to_update[0].password_value);
EXPECT_EQ(psl_saved_match()->username_element,
- credentials_to_update[0]->username_element);
+ credentials_to_update[0].username_element);
EXPECT_EQ(psl_saved_match()->username_element,
- credentials_to_update[0]->username_element);
+ credentials_to_update[0].username_element);
EXPECT_EQ(psl_saved_match()->password_element,
- credentials_to_update[0]->password_element);
- EXPECT_EQ(psl_saved_match()->origin, credentials_to_update[0]->origin);
+ credentials_to_update[0].password_element);
+ EXPECT_EQ(psl_saved_match()->origin, credentials_to_update[0].origin);
}
TEST_F(PasswordFormManagerTest,
TestNotUpdatePSLMatchedCredentialsWithAnotherUsername) {
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
psl_saved_match()->username_value += ASCIIToUTF16("1");
SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH | RESULT_PSL_MATCH);
@@ -2540,8 +2502,8 @@ TEST_F(PasswordFormManagerTest,
TEST_F(PasswordFormManagerTest,
TestNotUpdatePSLMatchedCredentialsWithAnotherPassword) {
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
psl_saved_match()->password_value += ASCIIToUTF16("1");
SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH | RESULT_PSL_MATCH);
@@ -2579,8 +2541,8 @@ TEST_F(PasswordFormManagerTest,
TEST_F(PasswordFormManagerTest, TestNotUpdateWhenOnlyPSLMatched) {
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
SimulateMatchingPhase(&form_manager, RESULT_PSL_MATCH);
// User submits a credentials with an old username and a new password.
@@ -2615,7 +2577,6 @@ TEST_F(PasswordFormManagerTest, FetchStatistics) {
stats.origin_domain = observed_form()->origin.GetOrigin();
stats.username_value = saved_match()->username_value;
stats.dismissal_count = 5;
- EXPECT_CALL(*mock_store(), GetLogins(*observed_form(), form_manager()));
std::vector<InteractionsStats*> db_stats;
db_stats.push_back(new InteractionsStats(stats));
EXPECT_CALL(*mock_store(), GetSiteStatsMock(stats.origin_domain))
@@ -2623,12 +2584,19 @@ TEST_F(PasswordFormManagerTest, FetchStatistics) {
form_manager()->FetchDataFromPasswordStore();
base::RunLoop().RunUntilIdle();
- EXPECT_THAT(form_manager()->interactions_stats(),
+ EXPECT_THAT(form_manager()->form_fetcher()->GetInteractionsStats(),
ElementsAre(Pointee(stats)));
}
#else
TEST_F(PasswordFormManagerTest, DontFetchStatistics) {
- EXPECT_CALL(*mock_store(), GetLogins(*observed_form(), form_manager()));
+ // Because |form_manager()| is currently waiting for a PasswordStore response,
+ // the response needs to be faked in order to be able to re-request another
+ // one below.
+ form_manager()->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
+ EXPECT_CALL(
+ *mock_store(),
+ GetLogins(PasswordStore::FormDigest(*observed_form()), form_manager()));
EXPECT_CALL(*mock_store(), GetSiteStatsMock(_)).Times(0);
form_manager()->FetchDataFromPasswordStore();
base::RunLoop().RunUntilIdle();
@@ -2764,8 +2732,8 @@ TEST_F(PasswordFormManagerTest,
client()->set_is_update_password_ui_enabled(true);
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH);
@@ -2799,10 +2767,10 @@ TEST_F(PasswordFormManagerTest,
expected_available_field_types.insert(autofill::NEW_PASSWORD);
std::string observed_form_signature =
- autofill::FormStructure(observed_form()->form_data).FormSignature();
+ autofill::FormStructure(observed_form()->form_data).FormSignatureAsStr();
std::string expected_login_signature =
- autofill::FormStructure(saved_match()->form_data).FormSignature();
+ autofill::FormStructure(saved_match()->form_data).FormSignatureAsStr();
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
@@ -2840,17 +2808,16 @@ TEST_F(PasswordFormManagerTest, FormClassifierVoteUpload) {
submitted_form.username_value = saved_match()->username_value;
submitted_form.password_value = saved_match()->password_value;
- PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), form, false,
- base::WrapUnique(new MockFormSaver()));
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), form,
+ base::MakeUnique<NiceMock<MockFormSaver>>());
base::string16 generation_element = form.password_element;
if (found_generation_element)
form_manager.SaveGenerationFieldDetectedByClassifier(generation_element);
else
form_manager.SaveGenerationFieldDetectedByClassifier(base::string16());
- ScopedVector<PasswordForm> result;
- form_manager.SimulateFetchMatchingLoginsFromPasswordStore();
+ std::vector<std::unique_ptr<PasswordForm>> result;
form_manager.OnGetPasswordStoreResults(std::move(result));
autofill::FormStructure form_structure(submitted_form.form_data);
@@ -2867,6 +2834,43 @@ TEST_F(PasswordFormManagerTest, FormClassifierVoteUpload) {
}
}
+TEST_F(PasswordFormManagerTest, FieldPropertiesMasksUpload) {
+ PasswordForm form(*observed_form());
+ form.form_data = saved_match()->form_data;
+
+ // Create submitted form.
+ PasswordForm submitted_form(form);
+ submitted_form.preferred = true;
+ submitted_form.username_value = saved_match()->username_value;
+ submitted_form.password_value = saved_match()->password_value;
+
+ PasswordFormManager form_manager(password_manager(), client(),
+ client()->driver(), form,
+ base::MakeUnique<NiceMock<MockFormSaver>>());
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ form_manager.OnGetPasswordStoreResults(std::move(result));
+
+ DCHECK_EQ(3U, form.form_data.fields.size());
+ submitted_form.form_data.fields[1].properties_mask =
+ FieldPropertiesFlags::USER_TYPED;
+ submitted_form.form_data.fields[2].properties_mask =
+ FieldPropertiesFlags::USER_TYPED;
+
+ std::map<base::string16, autofill::FieldPropertiesMask>
+ expected_field_properties;
+ for (const autofill::FormFieldData& field : submitted_form.form_data.fields)
+ if (field.properties_mask)
+ expected_field_properties[field.name] = field.properties_mask;
+
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ CheckFieldPropertiesMasksUpload(expected_field_properties),
+ false, _, _, true));
+ form_manager.ProvisionallySave(
+ submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.Save();
+}
+
TEST_F(PasswordFormManagerTest, TestSavingAPIFormsWithSamePassword) {
// Turn |observed_form| and |saved_match| to API created forms.
observed_form()->username_element.clear();
@@ -2875,8 +2879,8 @@ TEST_F(PasswordFormManagerTest, TestSavingAPIFormsWithSamePassword) {
saved_match()->type = autofill::PasswordForm::TYPE_API;
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), *observed_form(), false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), *observed_form(),
+ base::MakeUnique<MockFormSaver>());
SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH);
// User submits new credentials with the same password as in already saved
@@ -2906,23 +2910,49 @@ TEST_F(PasswordFormManagerTest, TestSavingAPIFormsWithSamePassword) {
EXPECT_EQ(autofill::PasswordForm::TYPE_API, new_credentials.type);
}
+TEST_F(PasswordFormManagerTest, SkipZeroClickIntact) {
+ saved_match()->skip_zero_click = true;
+ psl_saved_match()->skip_zero_click = true;
+ SimulateMatchingPhase(form_manager(), RESULT_SAVED_MATCH | RESULT_PSL_MATCH);
+ EXPECT_EQ(1u, form_manager()->best_matches().size());
+
+ // User submits a credentials with an old username and a new password.
+ PasswordForm credentials(*observed_form());
+ credentials.username_value = saved_match()->username_value;
+ credentials.password_value = ASCIIToUTF16("new_password");
+ credentials.preferred = true;
+ form_manager()->ProvisionallySave(
+ credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+
+ // Trigger saving to exercise some special case handling during updating.
+ PasswordForm new_credentials;
+ std::vector<autofill::PasswordForm> credentials_to_update;
+ EXPECT_CALL(MockFormSaver::Get(form_manager()), Update(_, _, _, nullptr))
+ .WillOnce(testing::DoAll(SaveArg<0>(&new_credentials),
+ SaveArgPointee<2>(&credentials_to_update)));
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(_, false, _, _, true));
+ form_manager()->Save();
+
+ EXPECT_TRUE(new_credentials.skip_zero_click);
+ ASSERT_EQ(1u, credentials_to_update.size());
+ EXPECT_TRUE(credentials_to_update[0].skip_zero_click);
+}
+
TEST_F(PasswordFormManagerTest, FederatedCredentialsFiltered) {
PasswordForm federated(*saved_match());
federated.password_value.clear();
federated.federation_origin =
url::Origin(GURL("https://accounts.google.com"));
- EXPECT_CALL(*mock_store(),
- GetLogins(form_manager()->observed_form(), form_manager()));
- form_manager()->FetchDataFromPasswordStore();
-
- ScopedVector<PasswordForm> results;
- results.push_back(new PasswordForm(federated));
- results.push_back(new PasswordForm(*saved_match()));
+ std::vector<std::unique_ptr<PasswordForm>> results;
+ results.push_back(base::MakeUnique<PasswordForm>(federated));
+ results.push_back(base::MakeUnique<PasswordForm>(*saved_match()));
form_manager()->OnGetPasswordStoreResults(std::move(results));
- EXPECT_EQ(1u, form_manager()->federated_matches().size());
- EXPECT_EQ(*form_manager()->federated_matches()[0], federated);
+ EXPECT_EQ(1u, form_manager()->form_fetcher()->GetFederatedMatches().size());
+ EXPECT_EQ(*form_manager()->form_fetcher()->GetFederatedMatches()[0],
+ federated);
EXPECT_EQ(1u, form_manager()->best_matches().size());
EXPECT_EQ(*(form_manager()->best_matches().begin()->second), *saved_match());
}
@@ -2932,8 +2962,8 @@ TEST_F(PasswordFormManagerTest, ProbablyAccountCreationUpload) {
form.form_data = saved_match()->form_data;
PasswordFormManager form_manager(password_manager(), client(),
- client()->driver(), form, false,
- base::WrapUnique(new MockFormSaver()));
+ client()->driver(), form,
+ base::MakeUnique<NiceMock<MockFormSaver>>());
PasswordForm form_to_save(form);
form_to_save.preferred = true;
@@ -2942,8 +2972,7 @@ TEST_F(PasswordFormManagerTest, ProbablyAccountCreationUpload) {
form_to_save.password_value = saved_match()->password_value;
form_to_save.does_look_like_signup_form = true;
- form_manager.SimulateFetchMatchingLoginsFromPasswordStore();
- ScopedVector<PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
form_manager.OnGetPasswordStoreResults(std::move(result));
autofill::FormStructure pending_structure(form_to_save.form_data);
@@ -2960,7 +2989,7 @@ TEST_F(PasswordFormManagerTest, ProbablyAccountCreationUpload) {
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(
CheckUploadedAutofillTypesAndSignature(
- pending_structure.FormSignature(), expected_types),
+ pending_structure.FormSignatureAsStr(), expected_types),
false, expected_available_field_types, std::string(), true));
form_manager.ProvisionallySave(
@@ -2974,4 +3003,80 @@ TEST_F(PasswordFormManagerFillOnAccountSelectTest, ProcessFrame) {
SimulateMatchingPhase(form_manager(), RESULT_SAVED_MATCH);
}
+// Check that PasswordFormManager records
+// PasswordManager_LoginFollowingAutofill as part of processing a credential
+// update.
+TEST_F(PasswordFormManagerTest, ReportProcessingUpdate) {
+ SimulateMatchingPhase(form_manager(), RESULT_SAVED_MATCH);
+ PasswordForm pending = *observed_form();
+ pending.username_value = saved_match()->username_value;
+ pending.password_value = saved_match()->password_value;
+ form_manager()->ProvisionallySave(
+ pending, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+
+ EXPECT_FALSE(form_manager()->IsNewLogin());
+
+ base::UserActionTester tester;
+ EXPECT_EQ(0, tester.GetActionCount("PasswordManager_LoginFollowingAutofill"));
+ form_manager()->Update(*saved_match());
+ EXPECT_EQ(1, tester.GetActionCount("PasswordManager_LoginFollowingAutofill"));
+}
+
+// Sanity check for calling ProcessMatches with empty vector. Should not crash
+// or make sanitizers scream.
+TEST_F(PasswordFormManagerTest, ProcessMatches_Empty) {
+ static_cast<FormFetcher::Consumer*>(form_manager())
+ ->ProcessMatches(std::vector<const PasswordForm*>(), 0u);
+}
+
+// For all combinations of PasswordForm schemes, test that ProcessMatches
+// filters out forms with schemes not matching the observed form.
+TEST_F(PasswordFormManagerTest, RemoveResultsWithWrongScheme_ObservingHTML) {
+ for (int correct = 0; correct <= PasswordForm::SCHEME_LAST; ++correct) {
+ for (int wrong = 0; wrong <= PasswordForm::SCHEME_LAST; ++wrong) {
+ if (correct == wrong)
+ continue;
+
+ const PasswordForm::Scheme kCorrectScheme =
+ static_cast<PasswordForm::Scheme>(correct);
+ const PasswordForm::Scheme kWrongScheme =
+ static_cast<PasswordForm::Scheme>(wrong);
+ SCOPED_TRACE(testing::Message() << "Correct scheme = " << kCorrectScheme
+ << ", wrong scheme = " << kWrongScheme);
+
+ PasswordForm observed = *observed_form();
+ observed.scheme = kCorrectScheme;
+ PasswordFormManager form_manager(
+ password_manager(), client(),
+ (kCorrectScheme == PasswordForm::SCHEME_HTML ? client()->driver()
+ : nullptr),
+ observed, base::MakeUnique<NiceMock<MockFormSaver>>());
+
+ PasswordForm match = *saved_match();
+ match.scheme = kCorrectScheme;
+
+ PasswordForm non_match = match;
+ non_match.scheme = kWrongScheme;
+
+ // First try putting the correct scheme first in returned matches.
+ std::vector<const PasswordForm*> all_matches = {&match, &non_match};
+ static_cast<FormFetcher::Consumer*>(&form_manager)
+ ->ProcessMatches(all_matches, 0u);
+
+ EXPECT_EQ(1u, form_manager.best_matches().size());
+ EXPECT_EQ(kCorrectScheme,
+ form_manager.best_matches().begin()->second->scheme);
+
+ // Now try putting the correct scheme last in returned matches.
+ all_matches = {&non_match, &match};
+ static_cast<FormFetcher::Consumer*>(&form_manager)
+ ->ProcessMatches(all_matches, 0u);
+
+ EXPECT_EQ(1u, form_manager.best_matches().size());
+ EXPECT_EQ(kCorrectScheme,
+ form_manager.best_matches().begin()->second->scheme);
+ }
+ }
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_generation_manager.cc b/chromium/components/password_manager/core/browser/password_generation_manager.cc
index d1b36412792..d33425534a6 100644
--- a/chromium/components/password_manager/core/browser/password_generation_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_manager.cc
@@ -41,8 +41,8 @@ void PasswordGenerationManager::DetectFormsEligibleForGeneration(
if (field->server_type() == autofill::ACCOUNT_CREATION_PASSWORD ||
field->server_type() == autofill::NEW_PASSWORD) {
forms_eligible_for_generation.push_back(
- autofill::PasswordFormGenerationData{form->form_name(),
- form->target_url(), *field});
+ autofill::PasswordFormGenerationData{form->form_signature(),
+ field->GetFieldSignature()});
break;
}
}
diff --git a/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
index 5a3aedc684e..f8095609c5f 100644
--- a/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_manager_unittest.cc
@@ -8,6 +8,7 @@
#include <utility>
#include <vector>
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/strings/utf_string_conversions.h"
@@ -17,6 +18,7 @@
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/password_form_generation_data.h"
+#include "components/autofill/core/common/signatures_util.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
@@ -31,6 +33,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using autofill::FormStructure;
using base::ASCIIToUTF16;
using testing::_;
@@ -189,6 +192,7 @@ TEST_F(PasswordGenerationManagerTest, DetectFormsEligibleForGeneration) {
autofill::FormStructure form1(login_form);
std::vector<autofill::FormStructure*> forms;
forms.push_back(&form1);
+
autofill::FormData account_creation_form;
account_creation_form.origin = GURL("http://accounts.yahoo.com/");
account_creation_form.action = GURL("http://accounts.yahoo.com/signup");
@@ -200,8 +204,13 @@ TEST_F(PasswordGenerationManagerTest, DetectFormsEligibleForGeneration) {
confirm_password.name = ASCIIToUTF16("password");
confirm_password.form_control_type = "password";
account_creation_form.fields.push_back(confirm_password);
+ autofill::FormSignature account_creation_form_signature =
+ autofill::CalculateFormSignature(account_creation_form);
+ autofill::FieldSignature account_creation_field_signature =
+ autofill::CalculateFieldSignatureForField(password);
autofill::FormStructure form2(account_creation_form);
forms.push_back(&form2);
+
autofill::FormData change_password_form;
change_password_form.origin = GURL("http://accounts.yahoo.com/");
change_password_form.action = GURL("http://accounts.yahoo.com/change");
@@ -210,6 +219,10 @@ TEST_F(PasswordGenerationManagerTest, DetectFormsEligibleForGeneration) {
change_password_form.fields[0].name = ASCIIToUTF16("new_password");
change_password_form.fields.push_back(confirm_password);
autofill::FormStructure form3(change_password_form);
+ autofill::FormSignature change_password_form_signature =
+ autofill::CalculateFormSignature(change_password_form);
+ autofill::FieldSignature change_password_field_signature =
+ autofill::CalculateFieldSignatureForField(change_password_form.fields[0]);
forms.push_back(&form3);
// Simulate the server response to set the field types.
@@ -233,21 +246,19 @@ TEST_F(PasswordGenerationManagerTest, DetectFormsEligibleForGeneration) {
DetectFormsEligibleForGeneration(forms);
EXPECT_EQ(2u, GetTestDriver()->GetFoundEligibleForGenerationForms().size());
- EXPECT_EQ(GURL("http://accounts.yahoo.com/signup"),
- GetTestDriver()->GetFoundEligibleForGenerationForms()[0].action);
- EXPECT_EQ(account_creation_form.name,
- GetTestDriver()->GetFoundEligibleForGenerationForms()[0].name);
- EXPECT_EQ(password.name, GetTestDriver()
- ->GetFoundEligibleForGenerationForms()[0]
- .generation_field.name);
- EXPECT_EQ(GURL("http://accounts.yahoo.com/change"),
- GetTestDriver()->GetFoundEligibleForGenerationForms()[1].action);
- EXPECT_EQ(ASCIIToUTF16("new_password"),
- GetTestDriver()
- ->GetFoundEligibleForGenerationForms()[1]
- .generation_field.name);
- EXPECT_EQ(change_password_form.name,
- GetTestDriver()->GetFoundEligibleForGenerationForms()[1].name);
+ EXPECT_EQ(
+ account_creation_form_signature,
+ GetTestDriver()->GetFoundEligibleForGenerationForms()[0].form_signature);
+ EXPECT_EQ(
+ account_creation_field_signature,
+ GetTestDriver()->GetFoundEligibleForGenerationForms()[0].field_signature);
+
+ EXPECT_EQ(
+ change_password_form_signature,
+ GetTestDriver()->GetFoundEligibleForGenerationForms()[1].form_signature);
+ EXPECT_EQ(
+ change_password_field_signature,
+ GetTestDriver()->GetFoundEligibleForGenerationForms()[1].field_signature);
}
TEST_F(PasswordGenerationManagerTest, UpdatePasswordSyncStateIncognito) {
@@ -271,8 +282,8 @@ TEST_F(PasswordGenerationManagerTest, CheckIfFormClassifierShouldRun) {
std::unique_ptr<base::FieldTrialList> field_trial_list;
scoped_refptr<base::FieldTrial> field_trial;
if (is_autofill_field_metadata_enabled) {
- field_trial_list.reset(
- new base::FieldTrialList(new metrics::SHA1EntropyProvider("foo")));
+ field_trial_list.reset(new base::FieldTrialList(
+ base::MakeUnique<metrics::SHA1EntropyProvider>("foo")));
field_trial = base::FieldTrialList::CreateFieldTrial(
"AutofillFieldMetadata", "Enabled");
EXPECT_CALL(*GetTestDriver(), AllowToRunFormClassifier())
diff --git a/chromium/components/password_manager/core/browser/password_manager.cc b/chromium/components/password_manager/core/browser/password_manager.cc
index 3783547769d..1f9577f6067 100644
--- a/chromium/components/password_manager/core/browser/password_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_manager.cc
@@ -41,7 +41,6 @@
#endif
using autofill::PasswordForm;
-using autofill::PasswordFormMap;
namespace password_manager {
@@ -151,8 +150,9 @@ void PasswordManager::RegisterProfilePrefs(
prefs::kCredentialsEnableAutosignin, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
#if defined(OS_MACOSX)
- registry->RegisterIntegerPref(prefs::kKeychainMigrationStatus,
- static_cast<int>(MigrationStatus::NOT_STARTED));
+ registry->RegisterIntegerPref(
+ prefs::kKeychainMigrationStatus,
+ static_cast<int>(MigrationStatus::MIGRATED_DELETED));
#endif
}
@@ -229,12 +229,10 @@ void PasswordManager::SetGenerationElementAndReasonForForm(
// If there is no corresponding PasswordFormManager, we create one. This is
// not the common case, and should only happen when there is a bug in our
// ability to detect forms.
- bool ssl_valid = form.origin.SchemeIsCryptographic();
- PasswordFormManager* manager = new PasswordFormManager(
- this, client_, driver->AsWeakPtr(), form, ssl_valid,
+ auto manager = base::MakeUnique<PasswordFormManager>(
+ this, client_, driver->AsWeakPtr(), form,
base::WrapUnique(new FormSaverImpl(client_->GetPasswordStore())));
- pending_login_managers_.push_back(manager);
- manager->FetchDataFromPasswordStore();
+ pending_login_managers_.push_back(std::move(manager));
}
void PasswordManager::SaveGenerationFieldDetectedByClassifier(
@@ -271,16 +269,13 @@ void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
return;
}
- std::unique_ptr<PasswordFormManager> manager;
- ScopedVector<PasswordFormManager>::iterator matched_manager_it =
- pending_login_managers_.end();
+ auto matched_manager_it = pending_login_managers_.end();
PasswordFormManager::MatchResultMask current_match_result =
PasswordFormManager::RESULT_NO_MATCH;
// Below, "matching" is in DoesManage-sense and "not ready" in
// !HasCompletedMatching sense. We keep track of such PasswordFormManager
// instances for UMA.
- for (ScopedVector<PasswordFormManager>::iterator iter =
- pending_login_managers_.begin();
+ for (auto iter = pending_login_managers_.begin();
iter != pending_login_managers_.end(); ++iter) {
PasswordFormManager::MatchResultMask result = (*iter)->DoesManage(form);
@@ -331,20 +326,18 @@ void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
// If we didn't find a manager, this means a form was submitted without
// first loading the page containing the form. Don't offer to save
// passwords in this case.
- if (matched_manager_it != pending_login_managers_.end()) {
- // Transfer ownership of the manager from |pending_login_managers_| to
- // |manager|.
- manager.reset(*matched_manager_it);
- pending_login_managers_.weak_erase(matched_manager_it);
- } else {
+ if (matched_manager_it == pending_login_managers_.end()) {
RecordFailure(NO_MATCHING_FORM, form.origin, logger.get());
return;
}
+ std::unique_ptr<PasswordFormManager> manager;
+ // Transfer ownership of the manager from |pending_login_managers_| to
+ // |manager|.
+ manager.swap(*matched_manager_it);
+ pending_login_managers_.erase(matched_manager_it);
+
PasswordForm provisionally_saved_form(form);
- provisionally_saved_form.ssl_valid =
- form.origin.SchemeIsCryptographic() &&
- !client_->DidLastPageLoadEncounterSSLErrors();
provisionally_saved_form.preferred = true;
if (logger) {
logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM,
@@ -369,7 +362,7 @@ void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
}
void PasswordManager::UpdateFormManagers() {
- for (PasswordFormManager* form_manager : pending_login_managers_) {
+ for (const auto& form_manager : pending_login_managers_) {
form_manager->FetchDataFromPasswordStore();
}
}
@@ -483,6 +476,9 @@ void PasswordManager::CreatePendingLoginManagers(
logger->LogMessage(Logger::STRING_CREATE_LOGIN_MANAGERS_METHOD);
}
+ // Record whether or not this top-level URL has at least one password field.
+ client_->AnnotateNavigationEntry(!forms.empty());
+
if (!client_->IsFillingEnabledForCurrentPage())
return;
@@ -491,10 +487,6 @@ void PasswordManager::CreatePendingLoginManagers(
pending_login_managers_.size());
}
- // Copy the weak pointers to the currently known login managers for comparison
- // against the newly added.
- std::vector<PasswordFormManager*> old_login_managers(
- pending_login_managers_.get());
for (std::vector<PasswordForm>::const_iterator iter = forms.begin();
iter != forms.end(); ++iter) {
// Don't involve the password manager if this form corresponds to
@@ -503,7 +495,7 @@ void PasswordManager::CreatePendingLoginManagers(
base::CompareCase::SENSITIVE))
continue;
bool old_manager_found = false;
- for (const auto& old_manager : old_login_managers) {
+ for (const auto& old_manager : pending_login_managers_) {
if (old_manager->DoesManage(*iter) !=
PasswordFormManager::RESULT_COMPLETE_MATCH) {
continue;
@@ -530,15 +522,12 @@ void PasswordManager::CreatePendingLoginManagers(
if (logger)
logger->LogFormSignatures(Logger::STRING_ADDING_SIGNATURE, *iter);
- bool ssl_valid = iter->origin.SchemeIsCryptographic();
- PasswordFormManager* manager = new PasswordFormManager(
+ auto manager = base::MakeUnique<PasswordFormManager>(
this, client_,
(driver ? driver->AsWeakPtr() : base::WeakPtr<PasswordManagerDriver>()),
- *iter, ssl_valid,
+ *iter,
base::WrapUnique(new FormSaverImpl(client_->GetPasswordStore())));
- pending_login_managers_.push_back(manager);
-
- manager->FetchDataFromPasswordStore();
+ pending_login_managers_.push_back(std::move(manager));
}
if (logger) {
@@ -582,7 +571,9 @@ bool PasswordManager::ShouldPromptUserToSavePassword() const {
provisional_save_manager_->retry_password_form_password_update() ||
(provisional_save_manager_->password_overridden() &&
client_->IsUpdatePasswordUIEnabled())) &&
- !provisional_save_manager_->has_generated_password() &&
+ !(provisional_save_manager_->has_generated_password() &&
+ (provisional_save_manager_->IsNewLogin() ||
+ !client_->IsUpdatePasswordUIEnabled())) &&
!provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch();
}
@@ -688,6 +679,9 @@ void PasswordManager::OnLoginSuccessful() {
logger->LogMessage(Logger::STRING_ON_ASK_USER_OR_SAVE_PASSWORD);
}
+ client_->GetStoreResultFilter()->ReportFormLoginSuccess(
+ *provisional_save_manager_);
+
if (base::FeatureList::IsEnabled(features::kDropSyncCredential) &&
!client_->GetStoreResultFilter()->ShouldSave(
provisional_save_manager_->pending_credentials())) {
@@ -748,8 +742,8 @@ bool PasswordManager::OtherPossibleUsernamesEnabled() const {
void PasswordManager::Autofill(
password_manager::PasswordManagerDriver* driver,
const PasswordForm& form_for_autofill,
- const PasswordFormMap& best_matches,
- const std::vector<std::unique_ptr<PasswordForm>>& federated_matches,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
+ const std::vector<const PasswordForm*>& federated_matches,
const PasswordForm& preferred_match,
bool wait_for_username) const {
DCHECK_EQ(PasswordForm::SCHEME_HTML, preferred_match.scheme);
@@ -781,8 +775,7 @@ void PasswordManager::Autofill(
void PasswordManager::ShowInitialPasswordAccountSuggestions(
password_manager::PasswordManagerDriver* driver,
const PasswordForm& form_for_autofill,
- const PasswordFormMap& best_matches,
- const std::vector<std::unique_ptr<PasswordForm>>& federated_matches,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
const PasswordForm& preferred_match,
bool wait_for_username) const {
DCHECK_EQ(PasswordForm::SCHEME_HTML, preferred_match.scheme);
@@ -805,7 +798,7 @@ void PasswordManager::ShowInitialPasswordAccountSuggestions(
}
void PasswordManager::AutofillHttpAuth(
- const PasswordFormMap& best_matches,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
const PasswordForm& preferred_match) const {
DCHECK_NE(PasswordForm::SCHEME_HTML, preferred_match.scheme);
@@ -856,13 +849,13 @@ void PasswordManager::ProcessAutofillPredictions(
PasswordFormManager* PasswordManager::GetMatchingPendingManager(
const PasswordForm& form) {
- auto matched_manager_it = pending_login_managers_.end();
+ PasswordFormManager* matched_manager = nullptr;
PasswordFormManager::MatchResultMask current_match_result =
PasswordFormManager::RESULT_NO_MATCH;
- for (auto iter = pending_login_managers_.begin();
- iter != pending_login_managers_.end(); ++iter) {
- PasswordFormManager::MatchResultMask result = (*iter)->DoesManage(form);
+ for (auto& login_manager : pending_login_managers_) {
+ PasswordFormManager::MatchResultMask result =
+ login_manager->DoesManage(form);
if (result == PasswordFormManager::RESULT_NO_MATCH)
continue;
@@ -870,7 +863,7 @@ PasswordFormManager* PasswordManager::GetMatchingPendingManager(
if (result == PasswordFormManager::RESULT_COMPLETE_MATCH) {
// If we find a manager that exactly matches the submitted form including
// the action URL, exit the loop.
- matched_manager_it = iter;
+ matched_manager = login_manager.get();
break;
} else if (result == (PasswordFormManager::RESULT_COMPLETE_MATCH &
~PasswordFormManager::RESULT_ACTION_MATCH) &&
@@ -879,16 +872,14 @@ PasswordFormManager* PasswordManager::GetMatchingPendingManager(
// URL, remember it as a candidate and continue searching for an exact
// match. See http://crbug.com/27246 for an example where actions can
// change.
- matched_manager_it = iter;
+ matched_manager = login_manager.get();
current_match_result = result;
} else if (result > current_match_result) {
- matched_manager_it = iter;
+ matched_manager = login_manager.get();
current_match_result = result;
}
}
- if (matched_manager_it != pending_login_managers_.end())
- return *matched_manager_it;
- return nullptr;
+ return matched_manager;
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager.h b/chromium/components/password_manager/core/browser/password_manager.h
index 1a2764271f5..f617cb0ef07 100644
--- a/chromium/components/password_manager/core/browser/password_manager.h
+++ b/chromium/components/password_manager/core/browser/password_manager.h
@@ -5,15 +5,15 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_H_
+#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
#include "base/observer_list.h"
-#include "base/stl_util.h"
+#include "base/strings/string16.h"
#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_fill_data.h"
@@ -60,13 +60,14 @@ class PasswordManager : public LoginModel {
// Called by a PasswordFormManager when it decides a form can be autofilled
// on the page.
- void Autofill(password_manager::PasswordManagerDriver* driver,
- const autofill::PasswordForm& form_for_autofill,
- const autofill::PasswordFormMap& best_matches,
- const std::vector<std::unique_ptr<autofill::PasswordForm>>&
- federated_matches,
- const autofill::PasswordForm& preferred_match,
- bool wait_for_username) const;
+ void Autofill(
+ password_manager::PasswordManagerDriver* driver,
+ const autofill::PasswordForm& form_for_autofill,
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches,
+ const std::vector<const autofill::PasswordForm*>& federated_matches,
+ const autofill::PasswordForm& preferred_match,
+ bool wait_for_username) const;
// Called by a PasswordFormManager when a page initially loads and it decides
// that a form can be autofilled on the page, but a menu of account options
@@ -78,16 +79,17 @@ class PasswordManager : public LoginModel {
void ShowInitialPasswordAccountSuggestions(
password_manager::PasswordManagerDriver* driver,
const autofill::PasswordForm& form_for_autofill,
- const autofill::PasswordFormMap& best_matches,
- const std::vector<std::unique_ptr<autofill::PasswordForm>>&
- federated_matches,
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches,
const autofill::PasswordForm& preferred_match,
bool wait_for_username) const;
// Called by a PasswordFormManager when it decides a HTTP auth dialog can be
// autofilled.
- void AutofillHttpAuth(const autofill::PasswordFormMap& best_matches,
- const autofill::PasswordForm& preferred_match) const;
+ void AutofillHttpAuth(
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches,
+ const autofill::PasswordForm& preferred_match) const;
// LoginModel implementation.
void AddObserverAndDeliverCredentials(
@@ -236,7 +238,7 @@ class PasswordManager : public LoginModel {
// When a form is "seen" on a page, a PasswordFormManager is created
// and stored in this collection until user navigates away from page.
- ScopedVector<PasswordFormManager> pending_login_managers_;
+ std::vector<std::unique_ptr<PasswordFormManager>> pending_login_managers_;
// When the user submits a password/credential, this contains the
// PasswordFormManager for the form in question until we deem the login
diff --git a/chromium/components/password_manager/core/browser/password_manager_client.cc b/chromium/components/password_manager/core/browser/password_manager_client.cc
index a2ea65c68ad..732bed5a7ec 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_client.cc
@@ -25,10 +25,10 @@ void PasswordManagerClient::ForceSavePassword() {
void PasswordManagerClient::GeneratePassword() {}
void PasswordManagerClient::PasswordWasAutofilled(
- const autofill::PasswordFormMap& best_matches,
+ const std::map<base::string16, const autofill::PasswordForm*>& best_matches,
const GURL& origin,
- const std::vector<std::unique_ptr<autofill::PasswordForm>>*
- federated_matches) const {}
+ const std::vector<const autofill::PasswordForm*>* federated_matches) const {
+}
PasswordSyncState PasswordManagerClient::GetPasswordSyncState() const {
return NOT_SYNCING_PASSWORDS;
@@ -72,4 +72,6 @@ const LogManager* PasswordManagerClient::GetLogManager() const {
return nullptr;
}
+void PasswordManagerClient::AnnotateNavigationEntry(bool has_password_field) {}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_client.h b/chromium/components/password_manager/core/browser/password_manager_client.h
index 3ea1499f5d4..e1fd470a163 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/password_manager_client.h
@@ -141,10 +141,11 @@ class PasswordManagerClient {
// They are never filled, but might be needed in the UI, for example. Default
// implementation is a noop.
virtual void PasswordWasAutofilled(
- const autofill::PasswordFormMap& best_matches,
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches,
const GURL& origin,
- const std::vector<std::unique_ptr<autofill::PasswordForm>>*
- federated_matches) const;
+ const std::vector<const autofill::PasswordForm*>* federated_matches)
+ const;
// Gets prefs associated with this embedder.
virtual PrefService* GetPrefs() = 0;
@@ -189,6 +190,9 @@ class PasswordManagerClient {
// Returns a LogManager instance.
virtual const LogManager* GetLogManager() const;
+ // Record that we saw a password field on this page.
+ virtual void AnnotateNavigationEntry(bool has_password_field);
+
private:
DISALLOW_COPY_AND_ASSIGN(PasswordManagerClient);
};
diff --git a/chromium/components/password_manager/core/browser/password_manager_test_utils.cc b/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
index 73f28571a64..3e0817df574 100644
--- a/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
@@ -16,18 +16,6 @@ using autofill::PasswordForm;
namespace password_manager {
-namespace {
-
-void GetFeatureOverridesAsCSV(const std::vector<const base::Feature*>& features,
- std::string* overrides) {
- for (const base::Feature* feature : features) {
- overrides->append(feature->name);
- overrides->push_back(',');
- }
-}
-
-} // namespace
-
const char kTestingIconUrlSpec[] = "https://accounts.google.com/Icon";
const char kTestingFederationUrlSpec[] = "https://accounts.google.com/login";
const int kTestingDaysAfterPasswordsAreSynced = 1;
@@ -38,7 +26,6 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromDataForTesting(
std::unique_ptr<PasswordForm> form(new PasswordForm());
form->scheme = form_data.scheme;
form->preferred = form_data.preferred;
- form->ssl_valid = form_data.ssl_valid;
form->date_created = base::Time::FromDoubleT(form_data.creation_time);
form->date_synced =
form->date_created +
@@ -73,16 +60,21 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromDataForTesting(
}
bool ContainsEqualPasswordFormsUnordered(
- const std::vector<PasswordForm*>& expectations,
- const std::vector<PasswordForm*>& actual_values,
+ const std::vector<std::unique_ptr<PasswordForm>>& expectations,
+ const std::vector<std::unique_ptr<PasswordForm>>& actual_values,
std::ostream* mismatch_output) {
- std::vector<PasswordForm*> remaining_expectations(expectations.begin(),
- expectations.end());
+ std::vector<PasswordForm*> remaining_expectations(expectations.size());
+ std::transform(
+ expectations.begin(), expectations.end(), remaining_expectations.begin(),
+ [](const std::unique_ptr<PasswordForm>& form) { return form.get(); });
+
bool had_mismatched_actual_form = false;
- for (const PasswordForm* actual : actual_values) {
+ for (const auto& actual : actual_values) {
auto it_matching_expectation = std::find_if(
remaining_expectations.begin(), remaining_expectations.end(),
- [actual](PasswordForm* expected) { return *expected == *actual; });
+ [&actual](const PasswordForm* expected) {
+ return *expected == *actual;
+ });
if (it_matching_expectation != remaining_expectations.end()) {
// Erase the matched expectation by moving the last element to its place.
*it_matching_expectation = remaining_expectations.back();
@@ -108,20 +100,6 @@ bool ContainsEqualPasswordFormsUnordered(
return !had_mismatched_actual_form && remaining_expectations.empty();
}
-void SetFeatures(const std::vector<const base::Feature*>& enable_features,
- const std::vector<const base::Feature*>& disable_features,
- std::unique_ptr<base::FeatureList> feature_list) {
- std::string enable_overrides;
- std::string disable_overrides;
-
- GetFeatureOverridesAsCSV(enable_features, &enable_overrides);
- GetFeatureOverridesAsCSV(disable_features, &disable_overrides);
-
- base::FeatureList::ClearInstanceForTesting();
- feature_list->InitializeFromCommandLine(enable_overrides, disable_overrides);
- base::FeatureList::SetInstance(std::move(feature_list));
-}
-
MockPasswordStoreObserver::MockPasswordStoreObserver() {}
MockPasswordStoreObserver::~MockPasswordStoreObserver() {}
diff --git a/chromium/components/password_manager/core/browser/password_manager_test_utils.h b/chromium/components/password_manager/core/browser/password_manager_test_utils.h
index 9a75e12f62e..4f49d562ab2 100644
--- a/chromium/components/password_manager/core/browser/password_manager_test_utils.h
+++ b/chromium/components/password_manager/core/browser/password_manager_test_utils.h
@@ -52,7 +52,6 @@ struct PasswordFormData {
const wchar_t* username_value; // Set to NULL for a blacklist entry.
const wchar_t* password_value;
const bool preferred;
- const bool ssl_valid;
const double creation_time;
};
@@ -63,24 +62,19 @@ std::unique_ptr<autofill::PasswordForm> CreatePasswordFormFromDataForTesting(
// Checks whether the PasswordForms pointed to in |actual_values| are in some
// permutation pairwise equal to those in |expectations|. Returns true in case
// of a perfect match; otherwise returns false and writes details of mismatches
-// in human readable format to |mismatches_output| unless it is null.
+// in human readable format to |mismatch_output| unless it is null.
+// Note: |expectations| should be a const ref, but needs to be a const pointer,
+// because GMock tried to copy the reference by value.
bool ContainsEqualPasswordFormsUnordered(
- const std::vector<autofill::PasswordForm*>& expectations,
- const std::vector<autofill::PasswordForm*>& actual_values,
- std::ostream* mismatches_output);
+ const std::vector<std::unique_ptr<autofill::PasswordForm>>& expectations,
+ const std::vector<std::unique_ptr<autofill::PasswordForm>>& actual_values,
+ std::ostream* mismatch_output);
MATCHER_P(UnorderedPasswordFormElementsAre, expectations, "") {
- return ContainsEqualPasswordFormsUnordered(expectations, arg,
+ return ContainsEqualPasswordFormsUnordered(*expectations, arg,
result_listener->stream());
}
-// Helper function to initialize feature overrides via command-line flags
-// supplied as |enable_features| and |disable_features| using the
-// |feature_list|.
-void SetFeatures(const std::vector<const base::Feature*>& enable_features,
- const std::vector<const base::Feature*>& disable_features,
- std::unique_ptr<base::FeatureList> feature_list);
-
class MockPasswordStoreObserver : public PasswordStore::Observer {
public:
MockPasswordStoreObserver();
diff --git a/chromium/components/password_manager/core/browser/password_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
index ae4886df88f..d1143bdeb6f 100644
--- a/chromium/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
@@ -14,11 +14,13 @@
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/statistics_table.h"
+#include "components/password_manager/core/browser/stub_credentials_filter.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/browser/stub_password_manager_driver.h"
#include "components/password_manager/core/common/password_manager_features.h"
@@ -38,18 +40,11 @@ namespace password_manager {
namespace {
-class MockStoreResultFilter : public CredentialsFilter {
+class MockStoreResultFilter : public StubCredentialsFilter {
public:
- MOCK_CONST_METHOD1(FilterResultsPtr,
- void(ScopedVector<autofill::PasswordForm>* results));
MOCK_CONST_METHOD1(ShouldSave, bool(const autofill::PasswordForm& form));
-
- // GMock cannot handle move-only arguments.
- ScopedVector<autofill::PasswordForm> FilterResults(
- ScopedVector<autofill::PasswordForm> results) const override {
- FilterResultsPtr(&results);
- return results;
- }
+ MOCK_CONST_METHOD1(ReportFormLoginSuccess,
+ void(const PasswordFormManager& form_manager));
};
class MockPasswordManagerClient : public StubPasswordManagerClient {
@@ -77,7 +72,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
MOCK_METHOD0(GetPrefs, PrefService*());
MOCK_METHOD0(GetDriver, PasswordManagerDriver*());
MOCK_CONST_METHOD0(IsUpdatePasswordUIEnabled, bool());
- MOCK_CONST_METHOD0(GetStoreResultFilter, const CredentialsFilter*());
+ MOCK_CONST_METHOD0(GetStoreResultFilter, const MockStoreResultFilter*());
// Workaround for std::unique_ptr<> lacking a copy constructor.
bool PromptUserToSaveOrUpdatePassword(
@@ -109,13 +104,13 @@ class MockPasswordManagerDriver : public StubPasswordManagerDriver {
// Invokes the password store consumer with a single copy of |form|.
ACTION_P(InvokeConsumer, form) {
- ScopedVector<PasswordForm> result;
- result.push_back(base::WrapUnique(new PasswordForm(form)));
+ std::vector<std::unique_ptr<PasswordForm>> result;
+ result.push_back(base::MakeUnique<PasswordForm>(form));
arg0->OnGetPasswordStoreResults(std::move(result));
}
ACTION(InvokeEmptyConsumerWithForms) {
- arg0->OnGetPasswordStoreResults(ScopedVector<PasswordForm>());
+ arg0->OnGetPasswordStoreResults(std::vector<std::unique_ptr<PasswordForm>>());
}
ACTION_P(SaveToScopedPtr, scoped) { scoped->reset(arg0); }
@@ -125,18 +120,6 @@ ACTION_P(SaveToScopedPtr, scoped) { scoped->reset(arg0); }
class PasswordManagerTest : public testing::Test {
protected:
void SetUp() override {
- // TODO(jww): The following FeatureList clear can be removed once
- // https://crbug.com/620435 is resolved. This cleanup is needed because on
- // some platforms (e.g. iOS), the base::FeatureList is not reset betwen
- // test runs, so if these unit tests are run right after some other unit
- // tests that turn on a feature, that might affect these tests. In
- // particular, the earlier fill-on-account-select unit tests turned on
- // their respective Feature and that was incorrectly left on for these
- // tests.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- base::FeatureList::SetInstance(std::move(feature_list));
-
store_ = new testing::StrictMock<MockPasswordStore>;
EXPECT_CALL(*store_, ReportMetrics(_, _)).Times(AnyNumber());
CHECK(store_->Init(syncer::SyncableService::StartSyncFlare()));
@@ -251,7 +234,7 @@ class PasswordManagerTest : public testing::Test {
base::MessageLoop message_loop_;
scoped_refptr<MockPasswordStore> store_;
- MockPasswordManagerClient client_;
+ testing::NiceMock<MockPasswordManagerClient> client_;
MockPasswordManagerDriver driver_;
std::unique_ptr<PasswordAutofillManager> password_autofill_manager_;
std::unique_ptr<PasswordManager> manager_;
@@ -349,7 +332,7 @@ TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) {
// When the password store already contains credentials for a given form, new
// credentials get still added, as long as they differ in username from the
// stored ones.
- ScopedVector<PasswordForm> result;
+ std::vector<std::unique_ptr<PasswordForm>> result;
PasswordForm existing_different(MakeSimpleForm());
existing_different.username_value = ASCIIToUTF16("google2");
@@ -608,6 +591,35 @@ TEST_F(PasswordManagerTest, SyncCredentialsNotSaved) {
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
+// On a successful login with an updated password,
+// CredentialsFilter::ReportFormLoginSuccess should be called.
+TEST_F(PasswordManagerTest, ReportFormLoginSuccessCalled) {
+ PasswordForm form(MakeSimpleForm());
+
+ std::vector<PasswordForm> observed;
+ observed.push_back(form);
+ EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
+ // Simulate that |form| is already in the store, making this an update.
+ EXPECT_CALL(*store_, GetLogins(_, _))
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ // Submit form and finish navigation.
+ EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
+ manager()->ProvisionallySavePassword(form);
+
+ // Chrome should recognise the successful login and call
+ // ReportFormLoginSuccess.
+ EXPECT_CALL(*client_.GetStoreResultFilter(), ReportFormLoginSuccess(_));
+ EXPECT_CALL(*store_, UpdateLogin(_));
+ observed.clear();
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+}
+
// When there is a sync password saved, and the user successfully uses the
// stored version of it, PasswordManager should not drop that password.
TEST_F(PasswordManagerTest, SyncCredentialsNotDroppedIfUpToDate) {
@@ -1089,7 +1101,8 @@ TEST_F(PasswordManagerTest, SaveFormFetchedAfterSubmit) {
// Emulate fetching password form from PasswordStore after submission but
// before post-navigation load.
ASSERT_TRUE(form_manager);
- form_manager->OnGetPasswordStoreResults(ScopedVector<PasswordForm>());
+ form_manager->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
std::unique_ptr<PasswordFormManager> form_manager_to_save;
EXPECT_CALL(client_,
@@ -1299,24 +1312,32 @@ TEST_F(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
.WillRepeatedly(Return(true));
const bool kFalseTrue[] = {false, true};
- for (bool foundMatchedLoginsInStore : kFalseTrue) {
- SCOPED_TRACE(testing::Message("foundMatchedLoginsInStore = ")
- << foundMatchedLoginsInStore);
+ for (bool found_matched_logins_in_store : kFalseTrue) {
+ SCOPED_TRACE(testing::Message("found_matched_logins_in_store = ")
+ << found_matched_logins_in_store);
std::vector<PasswordForm> observed;
PasswordForm form(MakeFormWithOnlyNewPasswordField());
observed.push_back(form);
- if (foundMatchedLoginsInStore) {
+ if (found_matched_logins_in_store) {
EXPECT_CALL(*store_, GetLogins(_, _))
.WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
- EXPECT_CALL(client_, NotifySuccessfulLoginWithExistingPassword(_))
- .Times(1);
} else {
EXPECT_CALL(*store_, GetLogins(_, _))
.WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
}
- EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
- EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(1);
+ std::unique_ptr<PasswordFormManager> form_manager;
+ if (found_matched_logins_in_store) {
+ EXPECT_CALL(
+ client_,
+ PromptUserToSaveOrUpdatePasswordPtr(
+ _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER))
+ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager)));
+ } else {
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0);
+ }
+ EXPECT_CALL(client_, AutomaticPasswordSaveIndicator())
+ .Times(found_matched_logins_in_store ? 0 : 1);
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1326,11 +1347,20 @@ TEST_F(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
manager()->SetHasGeneratedPasswordForForm(&driver_, form, true);
::testing::Mock::VerifyAndClearExpectations(store_.get());
- EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, form)).WillOnce(Return());
+ if (!found_matched_logins_in_store)
+ EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, form));
OnPasswordFormSubmitted(form);
observed.clear();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ ::testing::Mock::VerifyAndClearExpectations(store_.get());
+ if (found_matched_logins_in_store) {
+ // Credentials should be updated only when the user explicitly chooses.
+ ASSERT_TRUE(form_manager);
+ EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, form));
+ form_manager->Update(form_manager->pending_credentials());
+ }
}
}
@@ -1348,7 +1378,8 @@ TEST_F(PasswordManagerTest,
manager()->OnPasswordFormsRendered(&driver_, observed, true);
PasswordStoreConsumer* consumer = nullptr;
- EXPECT_CALL(*store_, GetLogins(form, _)).WillOnce(SaveArg<1>(&consumer));
+ EXPECT_CALL(*store_, GetLogins(PasswordStore::FormDigest(form), _))
+ .WillOnce(SaveArg<1>(&consumer));
manager()->SetGenerationElementAndReasonForForm(&driver_, form,
base::string16(), false);
PasswordFormManager* form_manager =
@@ -1358,11 +1389,9 @@ TEST_F(PasswordManagerTest,
TEST_F(PasswordManagerTest, ForceSavingPasswords) {
// Add the enable-password-force-saving feature.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- password_manager::features::kEnablePasswordForceSaving.name, "");
- base::FeatureList::SetInstance(std::move(feature_list));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kEnablePasswordForceSaving);
PasswordForm form(MakeSimpleForm());
std::vector<PasswordForm> observed;
@@ -1389,11 +1418,9 @@ TEST_F(PasswordManagerTest, ForceSavingPasswords) {
// Forcing Chrome to save an empty passwords should fail without a crash.
TEST_F(PasswordManagerTest, ForceSavingPasswords_Empty) {
// Add the enable-password-force-saving feature.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- password_manager::features::kEnablePasswordForceSaving.name, "");
- base::FeatureList::SetInstance(std::move(feature_list));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kEnablePasswordForceSaving);
PasswordForm empty_password_form;
std::vector<PasswordForm> observed;
@@ -1424,7 +1451,8 @@ TEST_F(PasswordManagerTest, UpdateFormManagers) {
// The first GetLogins should have fired, but to unblock the second, we need
// to first send a response from the store (to be ignored).
ASSERT_TRUE(consumer);
- consumer->OnGetPasswordStoreResults(ScopedVector<PasswordForm>());
+ consumer->OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>>());
EXPECT_CALL(*store_, GetLogins(_, _));
manager()->UpdateFormManagers();
}
diff --git a/chromium/components/password_manager/core/browser/password_manager_util.cc b/chromium/components/password_manager/core/browser/password_manager_util.cc
index e8804193aff..6383418df27 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util.cc
@@ -9,12 +9,12 @@
#include "base/memory/ptr_util.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/log_manager.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_service.h"
namespace password_manager_util {
password_manager::PasswordSyncState GetPasswordSyncState(
- const sync_driver::SyncService* sync_service) {
+ const syncer::SyncService* sync_service) {
if (sync_service && sync_service->IsFirstSetupComplete() &&
sync_service->IsSyncActive() &&
sync_service->GetActiveDataTypes().Has(syncer::PASSWORDS)) {
@@ -61,19 +61,25 @@ void FindDuplicates(
}
void TrimUsernameOnlyCredentials(
- ScopedVector<autofill::PasswordForm>* android_credentials) {
- ScopedVector<autofill::PasswordForm> result;
- for (auto& form : *android_credentials) {
- if (form->scheme == autofill::PasswordForm::SCHEME_USERNAME_ONLY) {
- if (form->federation_origin.unique())
- continue;
- else
- form->skip_zero_click = true;
- }
- result.push_back(form);
- form = nullptr;
- }
- android_credentials->swap(result);
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* android_credentials) {
+ // Remove username-only credentials which are not federated.
+ android_credentials->erase(
+ std::remove_if(
+ android_credentials->begin(), android_credentials->end(),
+ [](const std::unique_ptr<autofill::PasswordForm>& form) {
+ return form->scheme ==
+ autofill::PasswordForm::SCHEME_USERNAME_ONLY &&
+ form->federation_origin.unique();
+ }),
+ android_credentials->end());
+
+ // Set "skip_zero_click" on federated credentials.
+ std::for_each(
+ android_credentials->begin(), android_credentials->end(),
+ [](const std::unique_ptr<autofill::PasswordForm>& form) {
+ if (form->scheme == autofill::PasswordForm::SCHEME_USERNAME_ONLY)
+ form->skip_zero_click = true;
+ });
}
std::vector<std::unique_ptr<autofill::PasswordForm>> ConvertScopedVector(
diff --git a/chromium/components/password_manager/core/browser/password_manager_util.h b/chromium/components/password_manager/core/browser/password_manager_util.h
index 3e7465c1098..8a1365c78bf 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.h
+++ b/chromium/components/password_manager/core/browser/password_manager_util.h
@@ -17,7 +17,7 @@ namespace autofill {
struct PasswordForm;
}
-namespace sync_driver {
+namespace syncer {
class SyncService;
}
@@ -26,7 +26,7 @@ namespace password_manager_util {
// Reports whether and how passwords are currently synced. In particular, for a
// null |sync_service| returns NOT_SYNCING_PASSWORDS.
password_manager::PasswordSyncState GetPasswordSyncState(
- const sync_driver::SyncService* sync_service);
+ const syncer::SyncService* sync_service);
// Finds the forms with a duplicate sync tags in |forms|. The first one of
// the duplicated entries stays in |forms|, the others are moved to
@@ -42,7 +42,7 @@ void FindDuplicates(
// Removes Android username-only credentials from |android_credentials|.
// Transforms federated credentials into non zero-click ones.
void TrimUsernameOnlyCredentials(
- ScopedVector<autofill::PasswordForm>* android_credentials);
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* android_credentials);
// TODO(crbug.com/555132): Remove this when the migration from ScopedVector is
// finished for PasswordForm.
diff --git a/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
index bb963cc5cda..de4cffb10bf 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -4,6 +4,7 @@
#include "components/password_manager/core/browser/password_manager_util.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -23,7 +24,6 @@ autofill::PasswordForm GetTestAndroidCredentials(const char* signon_realm) {
form.signon_realm = signon_realm;
form.username_value = base::ASCIIToUTF16(kTestUsername);
form.password_value = base::ASCIIToUTF16(kTestPassword);
- form.ssl_valid = true;
return form;
}
@@ -32,26 +32,27 @@ autofill::PasswordForm GetTestAndroidCredentials(const char* signon_realm) {
using password_manager::UnorderedPasswordFormElementsAre;
TEST(PasswordManagerUtil, TrimUsernameOnlyCredentials) {
- ScopedVector<autofill::PasswordForm> forms, expected_forms;
- forms.push_back(
- new autofill::PasswordForm(GetTestAndroidCredentials(kTestAndroidRealm)));
- expected_forms.push_back(
- new autofill::PasswordForm(GetTestAndroidCredentials(kTestAndroidRealm)));
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> expected_forms;
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>(
+ GetTestAndroidCredentials(kTestAndroidRealm)));
+ expected_forms.push_back(base::MakeUnique<autofill::PasswordForm>(
+ GetTestAndroidCredentials(kTestAndroidRealm)));
autofill::PasswordForm username_only;
username_only.scheme = autofill::PasswordForm::SCHEME_USERNAME_ONLY;
username_only.signon_realm = kTestAndroidRealm;
username_only.username_value = base::ASCIIToUTF16(kTestUsername2);
- forms.push_back(new autofill::PasswordForm(username_only));
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>(username_only));
username_only.federation_origin = url::Origin(GURL(kTestFederationURL));
username_only.skip_zero_click = false;
- forms.push_back(new autofill::PasswordForm(username_only));
+ forms.push_back(base::MakeUnique<autofill::PasswordForm>(username_only));
username_only.skip_zero_click = true;
- expected_forms.push_back(new autofill::PasswordForm(username_only));
+ expected_forms.push_back(
+ base::MakeUnique<autofill::PasswordForm>(username_only));
password_manager_util::TrimUsernameOnlyCredentials(&forms);
- EXPECT_THAT(forms.get(),
- UnorderedPasswordFormElementsAre(expected_forms.get()));
+ EXPECT_THAT(forms, UnorderedPasswordFormElementsAre(&expected_forms));
}
diff --git a/chromium/components/password_manager/core/browser/password_store.cc b/chromium/components/password_manager/core/browser/password_store.cc
index 9842dc2b545..314c1eb26f5 100644
--- a/chromium/components/password_manager/core/browser/password_store.cc
+++ b/chromium/components/password_manager/core/browser/password_store.cc
@@ -4,6 +4,7 @@
#include "components/password_manager/core/browser/password_store.h"
+#include <algorithm>
#include <utility>
#include "base/bind.h"
@@ -47,17 +48,15 @@ PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
}
void PasswordStore::GetLoginsRequest::NotifyConsumerWithResults(
- ScopedVector<autofill::PasswordForm> results) {
+ std::vector<std::unique_ptr<PasswordForm>> results) {
if (!ignore_logins_cutoff_.is_null()) {
- ScopedVector<autofill::PasswordForm> remaining_logins;
- remaining_logins.reserve(results.size());
- for (auto& login : results) {
- if (login->date_created >= ignore_logins_cutoff_) {
- remaining_logins.push_back(login);
- login = nullptr;
- }
- }
- results = std::move(remaining_logins);
+ results.erase(
+ std::remove_if(results.begin(), results.end(),
+ [this](const std::unique_ptr<PasswordForm>& credential) {
+ return (credential->date_created <
+ ignore_logins_cutoff_);
+ }),
+ results.end());
}
origin_task_runner_->PostTask(
@@ -67,11 +66,24 @@ void PasswordStore::GetLoginsRequest::NotifyConsumerWithResults(
void PasswordStore::GetLoginsRequest::NotifyWithSiteStatistics(
std::vector<std::unique_ptr<InteractionsStats>> stats) {
- auto passed_stats(base::WrapUnique(
- new std::vector<std::unique_ptr<InteractionsStats>>(std::move(stats))));
origin_task_runner_->PostTask(
FROM_HERE, base::Bind(&PasswordStoreConsumer::OnGetSiteStatistics,
- consumer_weak_, base::Passed(&passed_stats)));
+ consumer_weak_, base::Passed(&stats)));
+}
+
+PasswordStore::FormDigest::FormDigest(autofill::PasswordForm::Scheme new_scheme,
+ const std::string& new_signon_realm,
+ const GURL& new_origin)
+ : scheme(new_scheme), signon_realm(new_signon_realm), origin(new_origin) {}
+
+PasswordStore::FormDigest::FormDigest(const PasswordForm& form)
+ : scheme(form.scheme),
+ signon_realm(form.signon_realm),
+ origin(form.origin) {}
+
+bool PasswordStore::FormDigest::operator==(const FormDigest& other) const {
+ return scheme == other.scheme && signon_realm == other.signon_realm &&
+ origin == other.origin;
}
PasswordStore::PasswordStore(
@@ -140,19 +152,22 @@ void PasswordStore::RemoveLoginsSyncedBetween(base::Time delete_begin,
this, delete_begin, delete_end));
}
-void PasswordStore::RemoveStatisticsCreatedBetween(
+void PasswordStore::RemoveStatisticsByOriginAndTime(
+ const base::Callback<bool(const GURL&)>& origin_filter,
base::Time delete_begin,
base::Time delete_end,
const base::Closure& completion) {
ScheduleTask(
- base::Bind(&PasswordStore::RemoveStatisticsCreatedBetweenInternal, this,
- delete_begin, delete_end, completion));
+ base::Bind(&PasswordStore::RemoveStatisticsByOriginAndTimeInternal, this,
+ origin_filter, delete_begin, delete_end, completion));
}
-void PasswordStore::DisableAutoSignInForAllLogins(
+void PasswordStore::DisableAutoSignInForOrigins(
+ const base::Callback<bool(const GURL&)>& origin_filter,
const base::Closure& completion) {
- ScheduleTask(base::Bind(&PasswordStore::DisableAutoSignInForAllLoginsInternal,
- this, completion));
+ ScheduleTask(
+ base::Bind(&PasswordStore::DisableAutoSignInForOriginsInternal, this,
+ base::Callback<bool(const GURL&)>(origin_filter), completion));
}
void PasswordStore::TrimAffiliationCache() {
@@ -160,7 +175,7 @@ void PasswordStore::TrimAffiliationCache() {
affiliated_match_helper_->TrimAffiliationCache();
}
-void PasswordStore::GetLogins(const PasswordForm& form,
+void PasswordStore::GetLogins(const FormDigest& form,
PasswordStoreConsumer* consumer) {
// Per http://crbug.com/121738, we deliberately ignore saved logins for
// http*://www.google.com/ that were stored prior to 2012. (Google now uses
@@ -177,7 +192,11 @@ void PasswordStore::GetLogins(const PasswordForm& form,
form.signon_realm == "https://www.google.com/")) {
static const base::Time::Exploded exploded_cutoff =
{ 2012, 1, 0, 1, 0, 0, 0, 0 }; // 00:00 Jan 1 2012
- ignore_logins_cutoff = base::Time::FromUTCExploded(exploded_cutoff);
+ base::Time out_time;
+ bool conversion_success =
+ base::Time::FromUTCExploded(exploded_cutoff, &out_time);
+ DCHECK(conversion_success);
+ ignore_logins_cutoff = out_time;
}
std::unique_ptr<GetLoginsRequest> request(new GetLoginsRequest(consumer));
request->set_ignore_logins_cutoff(ignore_logins_cutoff);
@@ -280,7 +299,7 @@ PasswordStore::GetBackgroundTaskRunner() {
return db_thread_runner_;
}
-void PasswordStore::GetLoginsImpl(const autofill::PasswordForm& form,
+void PasswordStore::GetLoginsImpl(const FormDigest& form,
std::unique_ptr<GetLoginsRequest> request) {
request->NotifyConsumerWithResults(FillMatchingLogins(form));
}
@@ -299,14 +318,16 @@ void PasswordStore::LogStatsForBulkDeletionDuringRollback(int num_deletions) {
PasswordStoreChangeList PasswordStore::AddLoginSync(const PasswordForm& form) {
// There is no good way to check if the password is actually up to date, or
// at least to check if it was actually changed. Assume it is.
- if (AffiliatedMatchHelper::IsValidAndroidCredential(form))
+ if (AffiliatedMatchHelper::IsValidAndroidCredential(
+ PasswordStore::FormDigest(form)))
ScheduleFindAndUpdateAffiliatedWebLogins(form);
return AddLoginImpl(form);
}
PasswordStoreChangeList PasswordStore::UpdateLoginSync(
const PasswordForm& form) {
- if (AffiliatedMatchHelper::IsValidAndroidCredential(form)) {
+ if (AffiliatedMatchHelper::IsValidAndroidCredential(
+ PasswordStore::FormDigest(form))) {
// Ideally, a |form| would not be updated in any way unless it was ensured
// that it, as a whole, can be used for a successful login. This, sadly, can
// not be guaranteed. It might be that |form| just contains updates to some
@@ -404,25 +425,27 @@ void PasswordStore::RemoveLoginsSyncedBetweenInternal(base::Time delete_begin,
NotifyLoginsChanged(changes);
}
-void PasswordStore::RemoveStatisticsCreatedBetweenInternal(
+void PasswordStore::RemoveStatisticsByOriginAndTimeInternal(
+ const base::Callback<bool(const GURL&)>& origin_filter,
base::Time delete_begin,
base::Time delete_end,
const base::Closure& completion) {
- RemoveStatisticsCreatedBetweenImpl(delete_begin, delete_end);
+ RemoveStatisticsByOriginAndTimeImpl(origin_filter, delete_begin, delete_end);
if (!completion.is_null())
main_thread_runner_->PostTask(FROM_HERE, completion);
}
-void PasswordStore::DisableAutoSignInForAllLoginsInternal(
+void PasswordStore::DisableAutoSignInForOriginsInternal(
+ const base::Callback<bool(const GURL&)>& origin_filter,
const base::Closure& completion) {
- DisableAutoSignInForAllLoginsImpl();
+ DisableAutoSignInForOriginsImpl(origin_filter);
if (!completion.is_null())
main_thread_runner_->PostTask(FROM_HERE, completion);
}
void PasswordStore::GetAutofillableLoginsImpl(
std::unique_ptr<GetLoginsRequest> request) {
- ScopedVector<PasswordForm> obtained_forms;
+ std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
if (!FillAutofillableLogins(&obtained_forms))
obtained_forms.clear();
request->NotifyConsumerWithResults(std::move(obtained_forms));
@@ -430,7 +453,7 @@ void PasswordStore::GetAutofillableLoginsImpl(
void PasswordStore::GetAutofillableLoginsWithAffiliatedRealmsImpl(
std::unique_ptr<GetLoginsRequest> request) {
- ScopedVector<PasswordForm> obtained_forms;
+ std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
if (!FillAutofillableLogins(&obtained_forms))
obtained_forms.clear();
// Since AffiliatedMatchHelper's requests should be sent from UI thread,
@@ -443,13 +466,13 @@ void PasswordStore::GetAutofillableLoginsWithAffiliatedRealmsImpl(
void PasswordStore::NotifyLoginsWithAffiliatedRealms(
std::unique_ptr<GetLoginsRequest> request,
- ScopedVector<PasswordForm> obtained_forms) {
+ std::vector<std::unique_ptr<PasswordForm>> obtained_forms) {
request->NotifyConsumerWithResults(std::move(obtained_forms));
}
void PasswordStore::GetBlacklistLoginsImpl(
std::unique_ptr<GetLoginsRequest> request) {
- ScopedVector<PasswordForm> obtained_forms;
+ std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
if (!FillBlacklistLogins(&obtained_forms))
obtained_forms.clear();
request->NotifyConsumerWithResults(std::move(obtained_forms));
@@ -457,7 +480,7 @@ void PasswordStore::GetBlacklistLoginsImpl(
void PasswordStore::GetBlacklistLoginsWithAffiliatedRealmsImpl(
std::unique_ptr<GetLoginsRequest> request) {
- ScopedVector<PasswordForm> obtained_forms;
+ std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
if (!FillBlacklistLogins(&obtained_forms))
obtained_forms.clear();
// Since AffiliatedMatchHelper's requests should be sent from UI thread,
@@ -474,31 +497,33 @@ void PasswordStore::NotifySiteStats(const GURL& origin_domain,
}
void PasswordStore::GetLoginsWithAffiliationsImpl(
- const PasswordForm& form,
+ const FormDigest& form,
std::unique_ptr<GetLoginsRequest> request,
const std::vector<std::string>& additional_android_realms) {
DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- ScopedVector<PasswordForm> results(FillMatchingLogins(form));
+ std::vector<std::unique_ptr<PasswordForm>> results(FillMatchingLogins(form));
for (const std::string& realm : additional_android_realms) {
- PasswordForm android_form;
- android_form.scheme = PasswordForm::SCHEME_HTML;
- android_form.signon_realm = realm;
- ScopedVector<PasswordForm> more_results(FillMatchingLogins(android_form));
- for (PasswordForm* form : more_results)
- form->is_affiliation_based_match = true;
- ScopedVector<PasswordForm>::iterator it_first_federated = std::partition(
- more_results.begin(), more_results.end(),
- [](PasswordForm* form) { return form->federation_origin.unique(); });
- more_results.erase(it_first_federated, more_results.end());
+ std::vector<std::unique_ptr<PasswordForm>> more_results(
+ FillMatchingLogins({PasswordForm::SCHEME_HTML, realm, GURL()}));
+ for (auto& result : more_results)
+ result->is_affiliation_based_match = true;
+ more_results.erase(
+ std::remove_if(more_results.begin(), more_results.end(),
+ [](const std::unique_ptr<PasswordForm>& result) {
+ return !result->federation_origin.unique();
+ }),
+ more_results.end());
password_manager_util::TrimUsernameOnlyCredentials(&more_results);
- results.insert(results.end(), more_results.begin(), more_results.end());
- more_results.weak_clear();
+ const size_t results_count = results.size();
+ results.resize(results_count + more_results.size());
+ std::move(more_results.begin(), more_results.end(),
+ results.begin() + results_count);
}
request->NotifyConsumerWithResults(std::move(results));
}
void PasswordStore::InjectAffiliatedWebRealms(
- ScopedVector<PasswordForm> forms,
+ std::vector<std::unique_ptr<PasswordForm>> forms,
std::unique_ptr<GetLoginsRequest> request) {
if (affiliated_match_helper_) {
affiliated_match_helper_->InjectAffiliatedWebRealms(
@@ -511,7 +536,7 @@ void PasswordStore::InjectAffiliatedWebRealms(
}
void PasswordStore::ScheduleGetLoginsWithAffiliations(
- const PasswordForm& form,
+ const FormDigest& form,
std::unique_ptr<GetLoginsRequest> request,
const std::vector<std::string>& additional_android_realms) {
ScheduleTask(base::Bind(&PasswordStore::GetLoginsWithAffiliationsImpl, this,
@@ -522,13 +547,12 @@ void PasswordStore::ScheduleGetLoginsWithAffiliations(
std::unique_ptr<PasswordForm> PasswordStore::GetLoginImpl(
const PasswordForm& primary_key) {
DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- ScopedVector<PasswordForm> candidates(FillMatchingLogins(primary_key));
- for (PasswordForm*& candidate : candidates) {
+ std::vector<std::unique_ptr<PasswordForm>> candidates(
+ FillMatchingLogins(FormDigest(primary_key)));
+ for (auto& candidate : candidates) {
if (ArePasswordFormUniqueKeyEqual(*candidate, primary_key) &&
!candidate->is_public_suffix_match) {
- std::unique_ptr<PasswordForm> result(candidate);
- candidate = nullptr;
- return result;
+ return std::move(candidate);
}
}
return base::WrapUnique<PasswordForm>(nullptr);
@@ -541,7 +565,7 @@ void PasswordStore::FindAndUpdateAffiliatedWebLogins(
return;
}
affiliated_match_helper_->GetAffiliatedWebRealms(
- added_or_updated_android_form,
+ PasswordStore::FormDigest(added_or_updated_android_form),
base::Bind(&PasswordStore::ScheduleUpdateAffiliatedWebLoginsImpl, this,
added_or_updated_android_form));
}
@@ -559,16 +583,14 @@ void PasswordStore::UpdateAffiliatedWebLoginsImpl(
DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
PasswordStoreChangeList all_changes;
for (const std::string& affiliated_web_realm : affiliated_web_realms) {
- PasswordForm web_form_template;
- web_form_template.scheme = PasswordForm::SCHEME_HTML;
- web_form_template.signon_realm = affiliated_web_realm;
- ScopedVector<PasswordForm> web_logins(
- FillMatchingLogins(web_form_template));
- for (PasswordForm* web_login : web_logins) {
+ std::vector<std::unique_ptr<PasswordForm>> web_logins(FillMatchingLogins(
+ {PasswordForm::SCHEME_HTML, affiliated_web_realm, GURL()}));
+ for (auto& web_login : web_logins) {
// Do not update HTTP logins, logins saved under insecure conditions, and
// non-HTML login forms; PSL matches; logins with a different username;
// and logins with the same password (to avoid generating no-op updates).
- if (!AffiliatedMatchHelper::IsValidWebCredential(*web_login) ||
+ if (!AffiliatedMatchHelper::IsValidWebCredential(
+ FormDigest(*web_login)) ||
web_login->is_public_suffix_match ||
web_login->username_value != updated_android_form.username_value ||
web_login->password_value == updated_android_form.password_value)
@@ -655,4 +677,11 @@ void PasswordStore::DestroySyncableService() {
syncable_service_.reset();
}
+std::ostream& operator<<(std::ostream& os,
+ const PasswordStore::FormDigest& digest) {
+ return os << "FormDigest(scheme: " << digest.scheme
+ << ", signon_realm: " << digest.signon_realm
+ << ", origin: " << digest.origin << ")";
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store.h b/chromium/components/password_manager/core/browser/password_store.h
index 7a36fdf616c..a4b2b377290 100644
--- a/chromium/components/password_manager/core/browser/password_store.h
+++ b/chromium/components/password_manager/core/browser/password_store.h
@@ -6,20 +6,22 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_H_
#include <memory>
+#include <ostream>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
#include "base/observer_list_threadsafe.h"
#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "components/keyed_service/core/refcounted_keyed_service.h"
#include "components/password_manager/core/browser/password_store_change.h"
#include "components/password_manager/core/browser/password_store_sync.h"
-#include "sync/api/syncable_service.h"
+#include "components/sync/api/syncable_service.h"
+
+class PasswordStoreProxyMac;
namespace autofill {
struct PasswordForm;
@@ -29,8 +31,6 @@ namespace syncer {
class SyncableService;
}
-class PasswordStoreProxyMac;
-
namespace password_manager {
class AffiliatedMatchHelper;
@@ -64,6 +64,20 @@ class PasswordStore : protected PasswordStoreSync,
virtual ~Observer() {}
};
+ // Represents a subset of autofill::PasswordForm needed for credential
+ // retrievals.
+ struct FormDigest {
+ FormDigest(autofill::PasswordForm::Scheme scheme,
+ const std::string& signon_realm,
+ const GURL& origin);
+ explicit FormDigest(const autofill::PasswordForm& form);
+ bool operator==(const FormDigest& other) const;
+
+ autofill::PasswordForm::Scheme scheme;
+ std::string signon_realm;
+ GURL origin;
+ };
+
PasswordStore(scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner);
@@ -128,18 +142,24 @@ class PasswordStore : protected PasswordStoreSync,
void RemoveLoginsSyncedBetween(base::Time delete_begin,
base::Time delete_end);
- // Removes all the stats created in the given date range. If |completion| is
- // not null, it will be posted to the |main_thread_runner_| after deletions
- // have been completed.
+ // Removes all the stats created in the given date range.
+ // If |origin_filter| is not null, only statistics for matching origins are
+ // removed. If |completion| is not null, it will be posted to the
+ // |main_thread_runner_| after deletions have been completed.
// Should be called on the UI thread.
- void RemoveStatisticsCreatedBetween(base::Time delete_begin,
- base::Time delete_end,
- const base::Closure& completion);
+ void RemoveStatisticsByOriginAndTime(
+ const base::Callback<bool(const GURL&)>& origin_filter,
+ base::Time delete_begin,
+ base::Time delete_end,
+ const base::Closure& completion);
- // Sets the 'skip_zero_click' flag for all logins in the database to 'true'.
- // |completion| will be posted to the |main_thread_runner_| after these
- // modifications are completed and notifications are sent out.
- void DisableAutoSignInForAllLogins(const base::Closure& completion);
+ // Sets the 'skip_zero_click' flag for all logins in the database that match
+ // |origin_filter| to 'true'. |completion| will be posted to
+ // the |main_thread_runner_| after these modifications are completed
+ // and notifications are sent out.
+ void DisableAutoSignInForOrigins(
+ const base::Callback<bool(const GURL&)>& origin_filter,
+ const base::Closure& completion);
// Removes cached affiliation data that is no longer needed; provided that
// affiliation-based matching is enabled.
@@ -150,7 +170,7 @@ class PasswordStore : protected PasswordStoreSync,
// TODO(engedy): Currently, this will not return federated logins saved from
// Android applications that are affiliated with the realm of |form|. Need to
// decide if this is the desired behavior. See: https://crbug.com/539844.
- virtual void GetLogins(const autofill::PasswordForm& form,
+ virtual void GetLogins(const FormDigest& form,
PasswordStoreConsumer* consumer);
// Gets the complete list of PasswordForms that are not blacklist entries--and
@@ -217,7 +237,7 @@ class PasswordStore : protected PasswordStoreSync,
// Note that if this method is not called before destruction, the consumer
// will not be notified.
void NotifyConsumerWithResults(
- ScopedVector<autofill::PasswordForm> results);
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results);
void NotifyWithSiteStatistics(
std::vector<std::unique_ptr<InteractionsStats>> stats);
@@ -265,11 +285,14 @@ class PasswordStore : protected PasswordStoreSync,
base::Time delete_end) = 0;
// Synchronous implementation to remove the statistics.
- virtual bool RemoveStatisticsCreatedBetweenImpl(base::Time delete_begin,
- base::Time delete_end) = 0;
+ virtual bool RemoveStatisticsByOriginAndTimeImpl(
+ const base::Callback<bool(const GURL&)>& origin_filter,
+ base::Time delete_begin,
+ base::Time delete_end) = 0;
// Synchronous implementation to disable auto sign-in.
- virtual PasswordStoreChangeList DisableAutoSignInForAllLoginsImpl() = 0;
+ virtual PasswordStoreChangeList DisableAutoSignInForOriginsImpl(
+ const base::Callback<bool(const GURL&)>& origin_filter) = 0;
// Finds all PasswordForms with a signon_realm that is equal to, or is a
// PSL-match to that of |form|, and takes care of notifying the consumer with
@@ -277,7 +300,7 @@ class PasswordStore : protected PasswordStoreSync,
// Note: subclasses should implement FillMatchingLogins() instead. This needs
// to be virtual only because asynchronous behavior in PasswordStoreWin.
// TODO(engedy): Make this non-virtual once https://crbug.com/78830 is fixed.
- virtual void GetLoginsImpl(const autofill::PasswordForm& form,
+ virtual void GetLoginsImpl(const FormDigest& form,
std::unique_ptr<GetLoginsRequest> request);
// Synchronous implementation provided by subclasses to add the given login.
@@ -296,8 +319,8 @@ class PasswordStore : protected PasswordStoreSync,
// Finds and returns all PasswordForms with the same signon_realm as |form|,
// or with a signon_realm that is a PSL-match to that of |form|.
- virtual ScopedVector<autofill::PasswordForm> FillMatchingLogins(
- const autofill::PasswordForm& form) = 0;
+ virtual std::vector<std::unique_ptr<autofill::PasswordForm>>
+ FillMatchingLogins(const FormDigest& form) = 0;
// Synchronous implementation for manipulating with statistics.
virtual void AddSiteStatsImpl(const InteractionsStats& stats) = 0;
@@ -368,10 +391,14 @@ class PasswordStore : protected PasswordStoreSync,
const base::Closure& completion);
void RemoveLoginsSyncedBetweenInternal(base::Time delete_begin,
base::Time delete_end);
- void RemoveStatisticsCreatedBetweenInternal(base::Time delete_begin,
- base::Time delete_end,
- const base::Closure& completion);
- void DisableAutoSignInForAllLoginsInternal(const base::Closure& completion);
+ void RemoveStatisticsByOriginAndTimeInternal(
+ const base::Callback<bool(const GURL&)>& origin_filter,
+ base::Time delete_begin,
+ base::Time delete_end,
+ const base::Closure& completion);
+ void DisableAutoSignInForOriginsInternal(
+ const base::Callback<bool(const GURL&)>& origin_filter,
+ const base::Closure& completion);
// Finds all non-blacklist PasswordForms, and notifies the consumer.
void GetAutofillableLoginsImpl(std::unique_ptr<GetLoginsRequest> request);
@@ -397,7 +424,7 @@ class PasswordStore : protected PasswordStoreSync,
// realms for Android credentials.
void NotifyLoginsWithAffiliatedRealms(
std::unique_ptr<GetLoginsRequest> request,
- ScopedVector<autofill::PasswordForm> obtained_forms);
+ std::vector<std::unique_ptr<autofill::PasswordForm>> obtained_forms);
// Extended version of GetLoginsImpl that also returns credentials stored for
// the specified affiliated Android applications. That is, it finds all
@@ -407,18 +434,19 @@ class PasswordStore : protected PasswordStoreSync,
// * is one of those in |additional_android_realms|,
// and takes care of notifying the consumer with the results when done.
void GetLoginsWithAffiliationsImpl(
- const autofill::PasswordForm& form,
+ const FormDigest& form,
std::unique_ptr<GetLoginsRequest> request,
const std::vector<std::string>& additional_android_realms);
// Retrieves and fills in |affiliated_web_realm| values for Android
// credentials in |forms|. Called on the main thread.
- void InjectAffiliatedWebRealms(ScopedVector<autofill::PasswordForm> forms,
- std::unique_ptr<GetLoginsRequest> request);
+ void InjectAffiliatedWebRealms(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
+ std::unique_ptr<GetLoginsRequest> request);
// Schedules GetLoginsWithAffiliationsImpl() to be run on the DB thread.
void ScheduleGetLoginsWithAffiliations(
- const autofill::PasswordForm& form,
+ const FormDigest& form,
std::unique_ptr<GetLoginsRequest> request,
const std::vector<std::string>& additional_android_realms);
@@ -473,6 +501,10 @@ class PasswordStore : protected PasswordStoreSync,
DISALLOW_COPY_AND_ASSIGN(PasswordStore);
};
+// For logging only.
+std::ostream& operator<<(std::ostream& os,
+ const PasswordStore::FormDigest& digest);
+
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_H_
diff --git a/chromium/components/password_manager/core/browser/password_store_change.cc b/chromium/components/password_manager/core/browser/password_store_change.cc
index 950f55ce94f..c5c82e080ca 100644
--- a/chromium/components/password_manager/core/browser/password_store_change.cc
+++ b/chromium/components/password_manager/core/browser/password_store_change.cc
@@ -9,7 +9,7 @@ namespace password_manager {
std::ostream& operator<<(std::ostream& os,
const PasswordStoreChange& password_store_change) {
return os << "type: " << password_store_change.type()
- << "password form: " << password_store_change.form();
+ << ", password form: " << password_store_change.form();
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_change.h b/chromium/components/password_manager/core/browser/password_store_change.h
index 90211ef72b4..18f103c894a 100644
--- a/chromium/components/password_manager/core/browser/password_store_change.h
+++ b/chromium/components/password_manager/core/browser/password_store_change.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_CHANGE_H__
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_CHANGE_H__
+#include <ostream>
#include <vector>
#include "components/autofill/core/common/password_form.h"
@@ -38,7 +39,6 @@ class PasswordStoreChange {
form().password_value == other.form().password_value &&
form().new_password_element == other.form().new_password_element &&
form().new_password_value == other.form().new_password_value &&
- form().ssl_valid == other.form().ssl_valid &&
form().preferred == other.form().preferred &&
form().date_created == other.form().date_created &&
form().blacklisted_by_user == other.form().blacklisted_by_user;
diff --git a/chromium/components/password_manager/core/browser/password_store_consumer.cc b/chromium/components/password_manager/core/browser/password_store_consumer.cc
index a261210e357..eef0bf96fe8 100644
--- a/chromium/components/password_manager/core/browser/password_store_consumer.cc
+++ b/chromium/components/password_manager/core/browser/password_store_consumer.cc
@@ -15,6 +15,6 @@ PasswordStoreConsumer::~PasswordStoreConsumer() {
}
void PasswordStoreConsumer::OnGetSiteStatistics(
- std::unique_ptr<std::vector<std::unique_ptr<InteractionsStats>>> stats) {}
+ std::vector<std::unique_ptr<InteractionsStats>> stats) {}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_consumer.h b/chromium/components/password_manager/core/browser/password_store_consumer.h
index 264cafaabaf..f137225be67 100644
--- a/chromium/components/password_manager/core/browser/password_store_consumer.h
+++ b/chromium/components/password_manager/core/browser/password_store_consumer.h
@@ -8,7 +8,6 @@
#include <memory>
#include <vector>
-#include "base/memory/scoped_vector.h"
#include "base/task/cancelable_task_tracker.h"
namespace autofill {
@@ -31,13 +30,12 @@ class PasswordStoreConsumer {
// Called when the GetLogins() request is finished, with the associated
// |results|.
virtual void OnGetPasswordStoreResults(
- ScopedVector<autofill::PasswordForm> results) = 0;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) = 0;
- // TODO(crbug.com/561749): The argument's type would ideally be just
- // std::vector<std::unique_ptr<InteractionsStats>>, but currently it is not
- // possible to pass that into a callback.
+ // Called when the GetLogins() request is finished, with the associated site
+ // statistics.
virtual void OnGetSiteStatistics(
- std::unique_ptr<std::vector<std::unique_ptr<InteractionsStats>>> stats);
+ std::vector<std::unique_ptr<InteractionsStats>> stats);
// The base::CancelableTaskTracker can be used for cancelling the
// tasks associated with the consumer.
diff --git a/chromium/components/password_manager/core/browser/password_store_default.cc b/chromium/components/password_manager/core/browser/password_store_default.cc
index 79cae2a78be..12b98d53aa6 100644
--- a/chromium/components/password_manager/core/browser/password_store_default.cc
+++ b/chromium/components/password_manager/core/browser/password_store_default.cc
@@ -135,44 +135,60 @@ PasswordStoreChangeList PasswordStoreDefault::RemoveLoginsSyncedBetweenImpl(
return changes;
}
-PasswordStoreChangeList
-PasswordStoreDefault::DisableAutoSignInForAllLoginsImpl() {
+PasswordStoreChangeList PasswordStoreDefault::DisableAutoSignInForOriginsImpl(
+ const base::Callback<bool(const GURL&)>& origin_filter) {
ScopedVector<autofill::PasswordForm> forms;
PasswordStoreChangeList changes;
- if (login_db_ && login_db_->GetAutoSignInLogins(&forms)) {
- if (login_db_->DisableAutoSignInForAllLogins()) {
- for (const auto* form : forms) {
- changes.push_back(
- PasswordStoreChange(PasswordStoreChange::UPDATE, *form));
- }
+ if (!login_db_ || !login_db_->GetAutoSignInLogins(&forms))
+ return changes;
+
+ std::set<GURL> origins_to_update;
+ for (const auto* form : forms) {
+ if (origin_filter.Run(form->origin))
+ origins_to_update.insert(form->origin);
+ }
+
+ std::set<GURL> origins_updated;
+ for (const GURL& origin : origins_to_update) {
+ if (login_db_->DisableAutoSignInForOrigin(origin))
+ origins_updated.insert(origin);
+ }
+
+ for (const auto* form : forms) {
+ if (origins_updated.count(form->origin)) {
+ changes.push_back(
+ PasswordStoreChange(PasswordStoreChange::UPDATE, *form));
}
}
+
return changes;
}
-bool PasswordStoreDefault::RemoveStatisticsCreatedBetweenImpl(
+bool PasswordStoreDefault::RemoveStatisticsByOriginAndTimeImpl(
+ const base::Callback<bool(const GURL&)>& origin_filter,
base::Time delete_begin,
base::Time delete_end) {
return login_db_ &&
- login_db_->stats_table().RemoveStatsBetween(delete_begin, delete_end);
+ login_db_->stats_table().RemoveStatsByOriginAndTime(
+ origin_filter, delete_begin, delete_end);
}
-ScopedVector<autofill::PasswordForm> PasswordStoreDefault::FillMatchingLogins(
- const autofill::PasswordForm& form) {
- ScopedVector<autofill::PasswordForm> matched_forms;
+std::vector<std::unique_ptr<PasswordForm>>
+PasswordStoreDefault::FillMatchingLogins(const FormDigest& form) {
+ std::vector<std::unique_ptr<PasswordForm>> matched_forms;
if (login_db_ && !login_db_->GetLogins(form, &matched_forms))
- return ScopedVector<autofill::PasswordForm>();
+ return std::vector<std::unique_ptr<PasswordForm>>();
return matched_forms;
}
bool PasswordStoreDefault::FillAutofillableLogins(
- ScopedVector<PasswordForm>* forms) {
+ std::vector<std::unique_ptr<PasswordForm>>* forms) {
DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
return login_db_ && login_db_->GetAutofillableLogins(forms);
}
bool PasswordStoreDefault::FillBlacklistLogins(
- ScopedVector<PasswordForm>* forms) {
+ std::vector<std::unique_ptr<PasswordForm>>* forms) {
DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
return login_db_ && login_db_->GetBlacklistLogins(forms);
}
diff --git a/chromium/components/password_manager/core/browser/password_store_default.h b/chromium/components/password_manager/core/browser/password_store_default.h
index 9ebcea09bd6..9381067b3d4 100644
--- a/chromium/components/password_manager/core/browser/password_store_default.h
+++ b/chromium/components/password_manager/core/browser/password_store_default.h
@@ -58,15 +58,18 @@ class PasswordStoreDefault : public PasswordStore {
PasswordStoreChangeList RemoveLoginsSyncedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) override;
- PasswordStoreChangeList DisableAutoSignInForAllLoginsImpl() override;
- bool RemoveStatisticsCreatedBetweenImpl(base::Time delete_begin,
- base::Time delete_end) override;
- ScopedVector<autofill::PasswordForm> FillMatchingLogins(
- const autofill::PasswordForm& form) override;
+ PasswordStoreChangeList DisableAutoSignInForOriginsImpl(
+ const base::Callback<bool(const GURL&)>& origin_filter) override;
+ bool RemoveStatisticsByOriginAndTimeImpl(
+ const base::Callback<bool(const GURL&)>& origin_filter,
+ base::Time delete_begin,
+ base::Time delete_end) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> FillMatchingLogins(
+ const FormDigest& form) override;
bool FillAutofillableLogins(
- ScopedVector<autofill::PasswordForm>* forms) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override;
bool FillBlacklistLogins(
- ScopedVector<autofill::PasswordForm>* forms) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override;
void AddSiteStatsImpl(const InteractionsStats& stats) override;
void RemoveSiteStatsImpl(const GURL& origin_domain) override;
std::vector<std::unique_ptr<InteractionsStats>> GetSiteStatsImpl(
diff --git a/chromium/components/password_manager/core/browser/password_store_default_unittest.cc b/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
index 9648d2accd4..10156f0009b 100644
--- a/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -39,11 +39,12 @@ namespace {
class MockPasswordStoreConsumer : public PasswordStoreConsumer {
public:
MOCK_METHOD1(OnGetPasswordStoreResultsConstRef,
- void(const std::vector<PasswordForm*>&));
+ void(const std::vector<std::unique_ptr<PasswordForm>>&));
// GMock cannot mock methods with move-only args.
- void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override {
- OnGetPasswordStoreResultsConstRef(results.get());
+ void OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>> results) override {
+ OnGetPasswordStoreResultsConstRef(results);
}
};
@@ -61,20 +62,17 @@ class BadLoginDatabase : public LoginDatabase {
};
PasswordFormData CreateTestPasswordFormData() {
- PasswordFormData data = {
- PasswordForm::SCHEME_HTML,
- "http://bar.example.com",
- "http://bar.example.com/origin",
- "http://bar.example.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- L"username_value",
- L"password_value",
- true,
- false,
- 1
- };
+ PasswordFormData data = {PasswordForm::SCHEME_HTML,
+ "http://bar.example.com",
+ "http://bar.example.com/origin",
+ "http://bar.example.com/action",
+ L"submit_element",
+ L"username_element",
+ L"password_element",
+ L"username_value",
+ L"password_value",
+ true,
+ 1};
return data;
}
@@ -109,7 +107,7 @@ class PasswordStoreDefaultTestDelegate {
PasswordStoreDefaultTestDelegate::PasswordStoreDefaultTestDelegate() {
SetupTempDir();
store_ = CreateInitializedStore(
- base::WrapUnique(new LoginDatabase(test_login_db_file_path())));
+ base::MakeUnique<LoginDatabase>(test_login_db_file_path()));
}
PasswordStoreDefaultTestDelegate::PasswordStoreDefaultTestDelegate(
@@ -149,7 +147,7 @@ PasswordStoreDefaultTestDelegate::CreateInitializedStore(
base::FilePath PasswordStoreDefaultTestDelegate::test_login_db_file_path()
const {
- return temp_dir_.path().Append(FILE_PATH_LITERAL("login_test"));
+ return temp_dir_.GetPath().Append(FILE_PATH_LITERAL("login_test"));
}
} // anonymous namespace
@@ -159,7 +157,7 @@ INSTANTIATE_TYPED_TEST_CASE_P(Default,
PasswordStoreDefaultTestDelegate);
ACTION(STLDeleteElements0) {
- STLDeleteContainerPointers(arg0.begin(), arg0.end());
+ base::STLDeleteContainerPointers(arg0.begin(), arg0.end());
}
TEST(PasswordStoreDefaultTest, NonASCIIData) {
@@ -168,20 +166,13 @@ TEST(PasswordStoreDefaultTest, NonASCIIData) {
// Some non-ASCII password form data.
static const PasswordFormData form_data[] = {
- { PasswordForm::SCHEME_HTML,
- "http://foo.example.com",
- "http://foo.example.com/origin",
- "http://foo.example.com/action",
- L"มีสีสัน",
- L"ă元気ă§ă™ă‹?",
- L"盆栽",
- L"أحب كرة",
- L"Â£Ă©Ă¤êµ­́ˆ˜Ă§Ă ",
- true, false, 1 },
+ {PasswordForm::SCHEME_HTML, "http://foo.example.com",
+ "http://foo.example.com/origin", "http://foo.example.com/action",
+ L"มีสีสัน", L"ă元気ă§ă™ă‹?", L"盆栽", L"أحب كرة", L"Â£Ă©Ă¤êµ­́ˆ˜Ă§Ă ", true, 1},
};
// Build the expected forms vector and add the forms to the store.
- ScopedVector<PasswordForm> expected_forms;
+ std::vector<std::unique_ptr<PasswordForm>> expected_forms;
for (unsigned int i = 0; i < arraysize(form_data); ++i) {
expected_forms.push_back(
CreatePasswordFormFromDataForTesting(form_data[i]));
@@ -193,9 +184,10 @@ TEST(PasswordStoreDefaultTest, NonASCIIData) {
MockPasswordStoreConsumer consumer;
// We expect to get the same data back, even though it's not all ASCII.
- EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef(
- password_manager::UnorderedPasswordFormElementsAre(
- expected_forms.get())));
+ EXPECT_CALL(
+ consumer,
+ OnGetPasswordStoreResultsConstRef(
+ password_manager::UnorderedPasswordFormElementsAre(&expected_forms)));
store->GetAutofillableLogins(&consumer);
base::RunLoop().RunUntilIdle();
@@ -212,7 +204,7 @@ TEST(PasswordStoreDefaultTest, Notifications) {
store->AddObserver(&observer);
const PasswordStoreChange expected_add_changes[] = {
- PasswordStoreChange(PasswordStoreChange::ADD, *form),
+ PasswordStoreChange(PasswordStoreChange::ADD, *form),
};
EXPECT_CALL(observer,
@@ -226,7 +218,7 @@ TEST(PasswordStoreDefaultTest, Notifications) {
form->password_value = base::ASCIIToUTF16("a different password");
const PasswordStoreChange expected_update_changes[] = {
- PasswordStoreChange(PasswordStoreChange::UPDATE, *form),
+ PasswordStoreChange(PasswordStoreChange::UPDATE, *form),
};
EXPECT_CALL(observer,
@@ -237,7 +229,7 @@ TEST(PasswordStoreDefaultTest, Notifications) {
base::RunLoop().RunUntilIdle();
const PasswordStoreChange expected_delete_changes[] = {
- PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
+ PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
};
EXPECT_CALL(observer,
@@ -278,7 +270,7 @@ TEST(PasswordStoreDefaultTest, OperationsOnABadDatabaseSilentlyFail) {
// Get all logins; autofillable logins; blacklisted logins.
testing::StrictMock<MockPasswordStoreConsumer> mock_consumer;
EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
- bad_store->GetLogins(*form, &mock_consumer);
+ bad_store->GetLogins(PasswordStore::FormDigest(*form), &mock_consumer);
base::RunLoop().RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(&mock_consumer);
EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
diff --git a/chromium/components/password_manager/core/browser/password_store_factory_util.cc b/chromium/components/password_manager/core/browser/password_store_factory_util.cc
index 4c73f481468..f4c93150afc 100644
--- a/chromium/components/password_manager/core/browser/password_store_factory_util.cc
+++ b/chromium/components/password_manager/core/browser/password_store_factory_util.cc
@@ -17,8 +17,7 @@ namespace password_manager {
namespace {
-bool ShouldAffiliationBasedMatchingBeActive(
- sync_driver::SyncService* sync_service) {
+bool ShouldAffiliationBasedMatchingBeActive(syncer::SyncService* sync_service) {
return base::FeatureList::IsEnabled(features::kAffiliationBasedMatching) &&
sync_service && sync_service->CanSyncStart() &&
sync_service->IsSyncActive() &&
@@ -55,7 +54,7 @@ base::FilePath GetAffiliationDatabasePath(const base::FilePath& profile_path) {
void ToggleAffiliationBasedMatchingBasedOnPasswordSyncedState(
PasswordStore* password_store,
- sync_driver::SyncService* sync_service,
+ syncer::SyncService* sync_service,
net::URLRequestContextGetter* request_context_getter,
const base::FilePath& profile_path,
scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner) {
@@ -91,7 +90,7 @@ void TrimOrDeleteAffiliationCacheForStoreAndPath(
std::unique_ptr<LoginDatabase> CreateLoginDatabase(
const base::FilePath& profile_path) {
base::FilePath login_db_file_path = profile_path.Append(kLoginDataFileName);
- return base::WrapUnique(new LoginDatabase(login_db_file_path));
+ return base::MakeUnique<LoginDatabase>(login_db_file_path);
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_factory_util.h b/chromium/components/password_manager/core/browser/password_store_factory_util.h
index 94b9957c111..692be1a9d3a 100644
--- a/chromium/components/password_manager/core/browser/password_store_factory_util.h
+++ b/chromium/components/password_manager/core/browser/password_store_factory_util.h
@@ -14,9 +14,9 @@
#include "components/keyed_service/core/service_access_type.h"
#include "components/password_manager/core/browser/login_database.h"
#include "components/password_manager/core/browser/password_store.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/api/syncable_service.h"
+#include "components/sync/driver/sync_service.h"
#include "net/url_request/url_request_context_getter.h"
-#include "sync/api/syncable_service.h"
namespace password_manager {
@@ -28,7 +28,7 @@ namespace password_manager {
// passwords has just started or ended.
void ToggleAffiliationBasedMatchingBasedOnPasswordSyncedState(
PasswordStore* password_store,
- sync_driver::SyncService* sync_service,
+ syncer::SyncService* sync_service,
net::URLRequestContextGetter* request_context_getter,
const base::FilePath& profile_path,
scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner);
diff --git a/chromium/components/password_manager/core/browser/password_store_origin_unittest.h b/chromium/components/password_manager/core/browser/password_store_origin_unittest.h
index e8ff255d063..a5358d7693e 100644
--- a/chromium/components/password_manager/core/browser/password_store_origin_unittest.h
+++ b/chromium/components/password_manager/core/browser/password_store_origin_unittest.h
@@ -39,7 +39,6 @@ PasswordFormData CreateTestPasswordFormDataByOrigin(const char* origin_url) {
L"username_value",
L"password_value",
true,
- false,
1};
return data;
}
diff --git a/chromium/components/password_manager/core/browser/password_store_sync.h b/chromium/components/password_manager/core/browser/password_store_sync.h
index 4a1e26095c9..4d1b171c02b 100644
--- a/chromium/components/password_manager/core/browser/password_store_sync.h
+++ b/chromium/components/password_manager/core/browser/password_store_sync.h
@@ -5,11 +5,18 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_SYNC_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_SYNC_H_
+#include <memory>
+#include <vector>
+
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/scoped_vector.h"
#include "components/password_manager/core/browser/password_store_change.h"
+namespace autofill {
+struct PasswordForm;
+}
+
namespace password_manager {
// PasswordStore interface for PasswordSyncableService. It provides access to
@@ -23,11 +30,13 @@ class PasswordStoreSync {
// Overwrites |forms| with all stored non-blacklisted credentials. Returns
// true on success.
virtual bool FillAutofillableLogins(
- ScopedVector<autofill::PasswordForm>* forms) WARN_UNUSED_RESULT = 0;
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms)
+ WARN_UNUSED_RESULT = 0;
// Overwrites |forms| with all stored blacklisted credentials. Returns true on
// success.
- virtual bool FillBlacklistLogins(ScopedVector<autofill::PasswordForm>* forms)
+ virtual bool FillBlacklistLogins(
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms)
WARN_UNUSED_RESULT = 0;
// Synchronous implementation to add the given login.
diff --git a/chromium/components/password_manager/core/browser/password_store_unittest.cc b/chromium/components/password_manager/core/browser/password_store_unittest.cc
index c2b44a4b05c..daa27d4c31b 100644
--- a/chromium/components/password_manager/core/browser/password_store_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_unittest.cc
@@ -48,8 +48,6 @@ const char kTestWebRealm2[] = "https://two.example.com/";
const char kTestWebOrigin2[] = "https://two.example.com/origin";
const char kTestWebRealm3[] = "https://three.example.com/";
const char kTestWebOrigin3[] = "https://three.example.com/origin";
-const char kTestWebRealm4[] = "https://four.example.com/";
-const char kTestWebOrigin4[] = "https://four.example.com/origin";
const char kTestWebRealm5[] = "https://five.example.com/";
const char kTestWebOrigin5[] = "https://five.example.com/origin";
const char kTestPSLMatchingWebRealm[] = "https://psl.example.com/";
@@ -67,11 +65,12 @@ const char kTestUnrelatedAndroidRealm[] =
class MockPasswordStoreConsumer : public PasswordStoreConsumer {
public:
MOCK_METHOD1(OnGetPasswordStoreResultsConstRef,
- void(const std::vector<PasswordForm*>&));
+ void(const std::vector<std::unique_ptr<PasswordForm>>&));
// GMock cannot mock methods with move-only args.
- void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override {
- OnGetPasswordStoreResultsConstRef(results.get());
+ void OnGetPasswordStoreResults(
+ std::vector<std::unique_ptr<PasswordForm>> results) override {
+ OnGetPasswordStoreResultsConstRef(results);
}
};
@@ -87,14 +86,12 @@ class StartSyncFlareMock {
class PasswordStoreTest : public testing::Test {
protected:
- void SetUp() override {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- }
+ void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
void TearDown() override { ASSERT_TRUE(temp_dir_.Delete()); }
base::FilePath test_login_db_file_path() const {
- return temp_dir_.path().Append(FILE_PATH_LITERAL("login_test"));
+ return temp_dir_.GetPath().Append(FILE_PATH_LITERAL("login_test"));
}
base::MessageLoopForUI message_loop_;
@@ -102,72 +99,45 @@ class PasswordStoreTest : public testing::Test {
};
ACTION(STLDeleteElements0) {
- STLDeleteContainerPointers(arg0.begin(), arg0.end());
+ base::STLDeleteContainerPointers(arg0.begin(), arg0.end());
}
TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
- base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
+ base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
store->Init(syncer::SyncableService::StartSyncFlare());
const time_t cutoff = 1325376000; // 00:00 Jan 1 2012 UTC
static const PasswordFormData form_data[] = {
- // A form on https://www.google.com/ older than the cutoff. Will be ignored.
- { PasswordForm::SCHEME_HTML,
- "https://www.google.com",
- "https://www.google.com/origin",
- "https://www.google.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- L"username_value_1",
- L"",
- true, true, cutoff - 1 },
- // A form on https://www.google.com/ older than the cutoff. Will be ignored.
- { PasswordForm::SCHEME_HTML,
- "https://www.google.com",
- "https://www.google.com/origin",
- "https://www.google.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- L"username_value_2",
- L"",
- true, true, cutoff - 1 },
- // A form on https://www.google.com/ newer than the cutoff.
- { PasswordForm::SCHEME_HTML,
- "https://www.google.com",
- "https://www.google.com/origin",
- "https://www.google.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- L"username_value_3",
- L"",
- true, true, cutoff + 1 },
- // A form on https://accounts.google.com/ older than the cutoff.
- { PasswordForm::SCHEME_HTML,
- "https://accounts.google.com",
- "https://accounts.google.com/origin",
- "https://accounts.google.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- L"username_value",
- L"",
- true, true, cutoff - 1 },
- // A form on http://bar.example.com/ older than the cutoff.
- { PasswordForm::SCHEME_HTML,
- "http://bar.example.com",
- "http://bar.example.com/origin",
- "http://bar.example.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- L"username_value",
- L"",
- true, false, cutoff - 1 },
+ // A form on https://www.google.com/ older than the cutoff. Will be
+ // ignored.
+ {PasswordForm::SCHEME_HTML, "https://www.google.com",
+ "https://www.google.com/origin", "https://www.google.com/action",
+ L"submit_element", L"username_element", L"password_element",
+ L"username_value_1", L"", true, cutoff - 1},
+ // A form on https://www.google.com/ older than the cutoff. Will be
+ // ignored.
+ {PasswordForm::SCHEME_HTML, "https://www.google.com",
+ "https://www.google.com/origin", "https://www.google.com/action",
+ L"submit_element", L"username_element", L"password_element",
+ L"username_value_2", L"", true, cutoff - 1},
+ // A form on https://www.google.com/ newer than the cutoff.
+ {PasswordForm::SCHEME_HTML, "https://www.google.com",
+ "https://www.google.com/origin", "https://www.google.com/action",
+ L"submit_element", L"username_element", L"password_element",
+ L"username_value_3", L"", true, cutoff + 1},
+ // A form on https://accounts.google.com/ older than the cutoff.
+ {PasswordForm::SCHEME_HTML, "https://accounts.google.com",
+ "https://accounts.google.com/origin",
+ "https://accounts.google.com/action", L"submit_element",
+ L"username_element", L"password_element", L"username_value", L"", true,
+ cutoff - 1},
+ // A form on http://bar.example.com/ older than the cutoff.
+ {PasswordForm::SCHEME_HTML, "http://bar.example.com",
+ "http://bar.example.com/origin", "http://bar.example.com/action",
+ L"submit_element", L"username_element", L"password_element",
+ L"username_value", L"", true, cutoff - 1},
};
// Build the forms vector and add the forms to the store.
@@ -182,40 +152,38 @@ TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
// Theoretically these should never actually exist since there are no longer
// any login forms on www.google.com to save, but we technically allow them.
// We should not get back the older saved password though.
- PasswordForm www_google;
- www_google.scheme = PasswordForm::SCHEME_HTML;
- www_google.signon_realm = "https://www.google.com";
- std::vector<PasswordForm*> www_google_expected;
- www_google_expected.push_back(all_forms[2]);
+ const PasswordStore::FormDigest www_google = {
+ PasswordForm::SCHEME_HTML, "https://www.google.com", GURL()};
+ std::vector<std::unique_ptr<PasswordForm>> www_google_expected;
+ www_google_expected.push_back(base::MakeUnique<PasswordForm>(*all_forms[2]));
// We should still get the accounts.google.com login even though it's older
// than our cutoff - this is the new location of all Google login forms.
- PasswordForm accounts_google;
- accounts_google.scheme = PasswordForm::SCHEME_HTML;
- accounts_google.signon_realm = "https://accounts.google.com";
- std::vector<PasswordForm*> accounts_google_expected;
- accounts_google_expected.push_back(all_forms[3]);
+ const PasswordStore::FormDigest accounts_google = {
+ PasswordForm::SCHEME_HTML, "https://accounts.google.com", GURL()};
+ std::vector<std::unique_ptr<PasswordForm>> accounts_google_expected;
+ accounts_google_expected.push_back(
+ base::MakeUnique<PasswordForm>(*all_forms[3]));
// Same thing for a generic saved login.
- PasswordForm bar_example;
- bar_example.scheme = PasswordForm::SCHEME_HTML;
- bar_example.signon_realm = "http://bar.example.com";
- std::vector<PasswordForm*> bar_example_expected;
- bar_example_expected.push_back(all_forms[4]);
+ const PasswordStore::FormDigest bar_example = {
+ PasswordForm::SCHEME_HTML, "http://bar.example.com", GURL()};
+ std::vector<std::unique_ptr<PasswordForm>> bar_example_expected;
+ bar_example_expected.push_back(base::MakeUnique<PasswordForm>(*all_forms[4]));
MockPasswordStoreConsumer consumer;
testing::InSequence s;
EXPECT_CALL(consumer,
OnGetPasswordStoreResultsConstRef(
- UnorderedPasswordFormElementsAre(www_google_expected)))
+ UnorderedPasswordFormElementsAre(&www_google_expected)))
.RetiresOnSaturation();
EXPECT_CALL(consumer,
OnGetPasswordStoreResultsConstRef(
- UnorderedPasswordFormElementsAre(accounts_google_expected)))
+ UnorderedPasswordFormElementsAre(&accounts_google_expected)))
.RetiresOnSaturation();
EXPECT_CALL(consumer,
OnGetPasswordStoreResultsConstRef(
- UnorderedPasswordFormElementsAre(bar_example_expected)))
+ UnorderedPasswordFormElementsAre(&bar_example_expected)))
.RetiresOnSaturation();
store->GetLogins(www_google, &consumer);
@@ -231,7 +199,7 @@ TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
TEST_F(PasswordStoreTest, StartSyncFlare) {
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
- base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
+ base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
StartSyncFlareMock mock;
store->Init(
base::Bind(&StartSyncFlareMock::StartSyncFlare, base::Unretained(&mock)));
@@ -255,12 +223,12 @@ TEST_F(PasswordStoreTest, GetLoginImpl) {
kTestWebOrigin1,
"", L"", L"username_element", L"password_element",
L"username_value",
- L"", true, true, 1};
+ L"", true, 1};
/* clang-format on */
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
- base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
+ base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
store->Init(syncer::SyncableService::StartSyncFlare());
// For each attribute in the primary key, create one form that mismatches on
@@ -311,19 +279,19 @@ TEST_F(PasswordStoreTest, UpdateLoginPrimaryKeyFields) {
kTestWebOrigin1,
"", L"", L"username_element_1", L"password_element_1",
L"username_value_1",
- L"", true, true, 1},
+ L"", true, 1},
// The new credential with different values for all primary key fields.
{PasswordForm::SCHEME_HTML,
kTestWebRealm2,
kTestWebOrigin2,
"", L"", L"username_element_2", L"password_element_2",
L"username_value_2",
- L"", true, true, 1}};
+ L"", true, 1}};
/* clang-format on */
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(),
- base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
+ base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
store->Init(syncer::SyncableService::StartSyncFlare());
std::unique_ptr<PasswordForm> old_form(
@@ -347,11 +315,11 @@ TEST_F(PasswordStoreTest, UpdateLoginPrimaryKeyFields) {
base::RunLoop().RunUntilIdle();
MockPasswordStoreConsumer mock_consumer;
- ScopedVector<autofill::PasswordForm> expected_forms;
+ std::vector<std::unique_ptr<PasswordForm>> expected_forms;
expected_forms.push_back(std::move(new_form));
EXPECT_CALL(mock_consumer,
OnGetPasswordStoreResultsConstRef(
- UnorderedPasswordFormElementsAre(expected_forms.get())));
+ UnorderedPasswordFormElementsAre(&expected_forms)));
store->GetAutofillableLogins(&mock_consumer);
base::RunLoop().RunUntilIdle();
@@ -371,7 +339,7 @@ TEST_F(PasswordStoreTest, RemoveLoginsCreatedBetweenCallbackIsCalled) {
kTestWebOrigin1,
"", L"", L"username_element_1", L"password_element_1",
L"username_value_1",
- L"", true, true, 1};
+ L"", true, 1};
/* clang-format on */
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
@@ -411,20 +379,20 @@ TEST_F(PasswordStoreTest, GetLoginsWithoutAffiliations) {
kTestWebOrigin1,
"", L"", L"", L"",
L"username_value_1",
- L"", true, true, 1},
+ L"", true, 1},
// Credential that is a PSL match of the observed form.
{PasswordForm::SCHEME_HTML,
kTestPSLMatchingWebRealm,
kTestPSLMatchingWebOrigin,
"", L"", L"", L"",
L"username_value_2",
- L"", true, true, 1},
+ L"", true, 1},
// Credential for an unrelated Android application.
{PasswordForm::SCHEME_HTML,
kTestUnrelatedAndroidRealm,
"", "", L"", L"", L"",
L"username_value_3",
- L"", true, true, 1}};
+ L"", true, 1}};
/* clang-format on */
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
@@ -443,17 +411,16 @@ TEST_F(PasswordStoreTest, GetLoginsWithoutAffiliations) {
base::RunLoop().RunUntilIdle();
}
- PasswordForm observed_form;
- observed_form.scheme = PasswordForm::SCHEME_HTML;
- observed_form.origin = GURL(kTestWebOrigin1);
- observed_form.ssl_valid = true;
- observed_form.signon_realm = kTestWebRealm1;
+ PasswordStore::FormDigest observed_form = {
+ PasswordForm::SCHEME_HTML, kTestWebRealm1, GURL(kTestWebOrigin1)};
MockPasswordStoreConsumer mock_consumer;
- ScopedVector<PasswordForm> expected_results;
- expected_results.push_back(new PasswordForm(*all_credentials[0]));
- expected_results.push_back(new PasswordForm(*all_credentials[1]));
- for (PasswordForm* result : expected_results) {
+ std::vector<std::unique_ptr<PasswordForm>> expected_results;
+ expected_results.push_back(
+ base::MakeUnique<PasswordForm>(*all_credentials[0]));
+ expected_results.push_back(
+ base::MakeUnique<PasswordForm>(*all_credentials[1]));
+ for (const auto& result : expected_results) {
if (result->signon_realm != observed_form.signon_realm)
result->is_public_suffix_match = true;
}
@@ -464,7 +431,7 @@ TEST_F(PasswordStoreTest, GetLoginsWithoutAffiliations) {
EXPECT_CALL(mock_consumer,
OnGetPasswordStoreResultsConstRef(
- UnorderedPasswordFormElementsAre(expected_results.get())));
+ UnorderedPasswordFormElementsAre(&expected_results)));
store->GetLogins(observed_form, &mock_consumer);
store->ShutdownOnUIThread();
base::RunLoop().RunUntilIdle();
@@ -484,53 +451,53 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliations) {
kTestWebOrigin1,
"", L"", L"", L"",
L"username_value_1",
- L"", true, true, 1},
+ L"", true, 1},
// Credential that is a PSL match of the observed form.
{PasswordForm::SCHEME_HTML,
kTestPSLMatchingWebRealm,
kTestPSLMatchingWebOrigin,
"", L"", L"", L"",
L"username_value_2",
- L"", true, true, 1},
+ L"", true, 1},
// Credential for an Android application affiliated with the realm of the
// observed from.
{PasswordForm::SCHEME_HTML,
kTestAndroidRealm1,
"", "", L"", L"", L"",
L"username_value_3",
- L"", true, true, 1},
+ L"", true, 1},
// Second credential for the same Android application.
{PasswordForm::SCHEME_HTML,
kTestAndroidRealm1,
"", "", L"", L"", L"",
L"username_value_3b",
- L"", true, true, 1},
+ L"", true, 1},
// Third credential for the same application which is username-only.
{PasswordForm::SCHEME_USERNAME_ONLY,
kTestAndroidRealm1,
"", "", L"", L"", L"",
L"username_value_3c",
- L"", true, true, 1},
+ L"", true, 1},
// Credential for another Android application affiliated with the realm
// of the observed from.
{PasswordForm::SCHEME_HTML,
kTestAndroidRealm2,
"", "", L"", L"", L"",
L"username_value_4",
- L"", true, true, 1},
+ L"", true, 1},
// Federated credential for this second Android application; this should
// not be returned.
{PasswordForm::SCHEME_HTML,
kTestAndroidRealm2,
"", "", L"", L"", L"",
L"username_value_4b",
- kTestingFederatedLoginMarker, true, true, 1},
+ kTestingFederatedLoginMarker, true, 1},
// Credential for an unrelated Android application.
{PasswordForm::SCHEME_HTML,
kTestUnrelatedAndroidRealm,
"", "", L"", L"", L"",
L"username_value_5",
- L"", true, true, 1}
+ L"", true, 1}
};
/* clang-format on */
@@ -550,21 +517,23 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliations) {
base::RunLoop().RunUntilIdle();
}
- PasswordForm observed_form;
- observed_form.scheme = PasswordForm::SCHEME_HTML;
- observed_form.origin = GURL(kTestWebOrigin1);
- observed_form.ssl_valid = true;
- observed_form.signon_realm = kTestWebRealm1;
+ PasswordStore::FormDigest observed_form = {
+ PasswordForm::SCHEME_HTML, kTestWebRealm1, GURL(kTestWebOrigin1)};
MockPasswordStoreConsumer mock_consumer;
- ScopedVector<PasswordForm> expected_results;
- expected_results.push_back(new PasswordForm(*all_credentials[0]));
- expected_results.push_back(new PasswordForm(*all_credentials[1]));
- expected_results.push_back(new PasswordForm(*all_credentials[2]));
- expected_results.push_back(new PasswordForm(*all_credentials[3]));
- expected_results.push_back(new PasswordForm(*all_credentials[5]));
-
- for (PasswordForm* result : expected_results) {
+ std::vector<std::unique_ptr<PasswordForm>> expected_results;
+ expected_results.push_back(
+ base::MakeUnique<PasswordForm>(*all_credentials[0]));
+ expected_results.push_back(
+ base::MakeUnique<PasswordForm>(*all_credentials[1]));
+ expected_results.push_back(
+ base::MakeUnique<PasswordForm>(*all_credentials[2]));
+ expected_results.push_back(
+ base::MakeUnique<PasswordForm>(*all_credentials[3]));
+ expected_results.push_back(
+ base::MakeUnique<PasswordForm>(*all_credentials[5]));
+
+ for (const auto& result : expected_results) {
if (result->signon_realm != observed_form.signon_realm &&
!IsValidAndroidFacetURI(result->signon_realm))
result->is_public_suffix_match = true;
@@ -581,7 +550,7 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliations) {
EXPECT_CALL(mock_consumer,
OnGetPasswordStoreResultsConstRef(
- UnorderedPasswordFormElementsAre(expected_results.get())));
+ UnorderedPasswordFormElementsAre(&expected_results)));
store->GetLogins(observed_form, &mock_consumer);
store->ShutdownOnUIThread();
@@ -618,7 +587,7 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
kTestAndroidRealm1,
"", "", L"", L"", L"",
kTestUsername,
- kTestOldPassword, true, true, 2},
+ kTestOldPassword, true, 2},
// --- Positive samples --- Credentials that the password update should be
// automatically propagated to.
@@ -629,7 +598,7 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
kTestWebOrigin1,
"", L"", L"", L"",
kTestUsername,
- kTestOldPassword, true, true, 1},
+ kTestOldPassword, true, 1},
// Credential for another affiliated web site with the same username.
// Although the password is different than the current/old password for
// the Android application, it should be updated regardless.
@@ -638,7 +607,7 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
kTestWebOrigin2,
"", L"", L"", L"",
kTestUsername,
- kTestOtherPassword, true, true, 1},
+ kTestOtherPassword, true, 1},
// --- Negative samples --- Credentials that the password update should
// not be propagated to.
@@ -650,29 +619,21 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
kTestWebOrigin3,
"", L"", L"", L"",
kTestUsername,
- kTestNewPassword, true, true, 1},
- // Credential for another affiliated web site, but one that was saved
- // under insecure conditions.
- {PasswordForm::SCHEME_HTML,
- kTestWebRealm4,
- kTestWebOrigin4,
- "", L"", L"", L"",
- kTestUsername,
- kTestOldPassword, true, false, 1},
+ kTestNewPassword, true, 1},
// Credential for the HTTP version of an affiliated web site.
{PasswordForm::SCHEME_HTML,
kTestInsecureWebRealm,
kTestInsecureWebOrigin,
"", L"", L"", L"",
kTestUsername,
- kTestOldPassword, true, false, 1},
+ kTestOldPassword, true, 1},
// Credential for an affiliated web site, but with a different username.
{PasswordForm::SCHEME_HTML,
kTestWebRealm1,
kTestWebOrigin1,
"", L"", L"", L"",
kTestOtherUsername,
- kTestOldPassword, true, true, 1},
+ kTestOldPassword, true, 1},
// Credential for a web site that is a PSL match to a web sites affiliated
// with the Android application.
{PasswordForm::SCHEME_HTML,
@@ -680,26 +641,26 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
kTestPSLMatchingWebOrigin,
"poisoned", L"poisoned", L"", L"",
kTestUsername,
- kTestOldPassword, true, true, 1},
+ kTestOldPassword, true, 1},
// Credential for an unrelated web site.
{PasswordForm::SCHEME_HTML,
kTestUnrelatedWebRealm,
kTestUnrelatedWebOrigin,
"", L"", L"", L"",
kTestUsername,
- kTestOldPassword, true, true, 1},
+ kTestOldPassword, true, 1},
// Credential for an affiliated Android application.
{PasswordForm::SCHEME_HTML,
kTestAndroidRealm2,
"", "", L"", L"", L"",
kTestUsername,
- kTestOldPassword, true, true, 1},
+ kTestOldPassword, true, 1},
// Credential for an unrelated Android application.
{PasswordForm::SCHEME_HTML,
kTestUnrelatedAndroidRealm,
"", "", L"", L"", L"",
kTestUsername,
- kTestOldPassword, true, true, 1},
+ kTestOldPassword, true, 1},
// Credential for an affiliated web site with the same username, but one
// that was updated at the same time via Sync as the Android credential.
{PasswordForm::SCHEME_HTML,
@@ -707,7 +668,7 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
kTestWebOrigin5,
"", L"", L"", L"",
kTestUsername,
- kTestOtherPassword, true, true, 2}};
+ kTestOtherPassword, true, 2}};
/* clang-format on */
// The number of positive samples in |kTestCredentials|.
@@ -751,10 +712,11 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
// Calculate how the correctly updated test data set should look like.
size_t expected_number_of_propageted_updates =
propagation_enabled ? kExpectedNumberOfPropagatedUpdates : 0u;
- ScopedVector<PasswordForm> expected_credentials_after_update;
+ std::vector<std::unique_ptr<PasswordForm>>
+ expected_credentials_after_update;
for (size_t i = 0; i < all_credentials.size(); ++i) {
expected_credentials_after_update.push_back(
- new autofill::PasswordForm(*all_credentials[i]));
+ base::MakeUnique<PasswordForm>(*all_credentials[i]));
if (i < 1 + expected_number_of_propageted_updates) {
expected_credentials_after_update.back()->password_value =
base::WideToUTF16(kTestNewPassword);
@@ -766,10 +728,10 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
affiliated_web_realms.push_back(kTestWebRealm1);
affiliated_web_realms.push_back(kTestWebRealm2);
affiliated_web_realms.push_back(kTestWebRealm3);
- affiliated_web_realms.push_back(kTestWebRealm4);
affiliated_web_realms.push_back(kTestWebRealm5);
mock_helper->ExpectCallToGetAffiliatedWebRealms(
- *expected_credentials_after_update[0], affiliated_web_realms);
+ PasswordStore::FormDigest(*expected_credentials_after_update[0]),
+ affiliated_web_realms);
}
// Explicitly update the Android credential, wait until things calm down,
@@ -796,10 +758,9 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
store->RemoveObserver(&mock_observer);
MockPasswordStoreConsumer mock_consumer;
- EXPECT_CALL(
- mock_consumer,
- OnGetPasswordStoreResultsConstRef(UnorderedPasswordFormElementsAre(
- expected_credentials_after_update.get())));
+ EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef(
+ UnorderedPasswordFormElementsAre(
+ &expected_credentials_after_update)));
store->GetAutofillableLogins(&mock_consumer);
store->ShutdownOnUIThread();
base::RunLoop().RunUntilIdle();
@@ -814,17 +775,17 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliatedRealms) {
kTestAndroidRealm1,
"", "", L"", L"", L"",
L"username_value_1",
- L"", true, true, 1},
+ L"", true, 1},
{PasswordForm::SCHEME_HTML,
kTestAndroidRealm2,
"", "", L"", L"", L"",
L"username_value_2",
- L"", true, true, 1},
+ L"", true, 1},
{PasswordForm::SCHEME_HTML,
kTestAndroidRealm3,
"", "", L"", L"", L"",
L"username_value_3",
- L"", true, true, 1}};
+ L"", true, 1}};
/* clang-format on */
const bool kFalseTrue[] = {false, true};
@@ -833,7 +794,7 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliatedRealms) {
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
base::ThreadTaskRunnerHandle::Get(),
base::ThreadTaskRunnerHandle::Get(),
- base::WrapUnique(new LoginDatabase(test_login_db_file_path()))));
+ base::MakeUnique<LoginDatabase>(test_login_db_file_path())));
store->Init(syncer::SyncableService::StartSyncFlare());
store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
base::Closure());
@@ -849,9 +810,11 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliatedRealms) {
}
MockPasswordStoreConsumer mock_consumer;
- ScopedVector<PasswordForm> expected_results;
- for (size_t i = 0; i < arraysize(kTestCredentials); ++i)
- expected_results.push_back(new PasswordForm(*all_credentials[i]));
+ std::vector<std::unique_ptr<PasswordForm>> expected_results;
+ for (size_t i = 0; i < arraysize(kTestCredentials); ++i) {
+ expected_results.push_back(
+ base::MakeUnique<PasswordForm>(*all_credentials[i]));
+ }
MockAffiliatedMatchHelper* mock_helper = new MockAffiliatedMatchHelper;
store->SetAffiliatedMatchHelper(base::WrapUnique(mock_helper));
@@ -866,7 +829,7 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliatedRealms) {
EXPECT_CALL(mock_consumer,
OnGetPasswordStoreResultsConstRef(
- UnorderedPasswordFormElementsAre(expected_results.get())));
+ UnorderedPasswordFormElementsAre(&expected_results)));
if (blacklisted)
store->GetBlacklistLoginsWithAffiliatedRealms(&mock_consumer);
else
diff --git a/chromium/components/password_manager/core/browser/password_syncable_service.cc b/chromium/components/password_manager/core/browser/password_syncable_service.cc
index 5eda9433b43..951dfeffea7 100644
--- a/chromium/components/password_manager/core/browser/password_syncable_service.cc
+++ b/chromium/components/password_manager/core/browser/password_syncable_service.cc
@@ -14,8 +14,8 @@
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_store_sync.h"
+#include "components/sync/api/sync_error_factory.h"
#include "net/base/escape.h"
-#include "sync/api/sync_error_factory.h"
namespace password_manager {
@@ -50,7 +50,6 @@ bool AreLocalAndSyncPasswordsEqual(
password_specifics.username_value() &&
base::UTF16ToUTF8(password_form.password_value) ==
password_specifics.password_value() &&
- password_form.ssl_valid == password_specifics.ssl_valid() &&
password_form.preferred == password_specifics.preferred() &&
password_form.date_created.ToInternalValue() ==
password_specifics.date_created() &&
@@ -314,8 +313,9 @@ bool PasswordSyncableService::ReadFromPasswordStore(
ScopedVector<autofill::PasswordForm>* password_entries,
PasswordEntryMap* passwords_entry_map) const {
DCHECK(password_entries);
- ScopedVector<autofill::PasswordForm> blacklist_entries;
- if (!password_store_->FillAutofillableLogins(password_entries) ||
+ std::vector<std::unique_ptr<autofill::PasswordForm>> autofillable_entries;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> blacklist_entries;
+ if (!password_store_->FillAutofillableLogins(&autofillable_entries) ||
!password_store_->FillBlacklistLogins(&blacklist_entries)) {
// Password store often fails to load passwords. Track failures with UMA.
// (http://crbug.com/249000)
@@ -324,12 +324,16 @@ bool PasswordSyncableService::ReadFromPasswordStore(
syncer::MODEL_TYPE_COUNT);
return false;
}
- // Move |blacklist_entries| to |password_entries|.
- password_entries->reserve(password_entries->size() +
- blacklist_entries.size());
- password_entries->insert(password_entries->end(), blacklist_entries.begin(),
- blacklist_entries.end());
- blacklist_entries.weak_clear();
+ password_entries->clear();
+ password_entries->resize(autofillable_entries.size() +
+ blacklist_entries.size());
+ auto next = password_entries->begin();
+ for (auto& autofillable : autofillable_entries) {
+ *next++ = autofillable.release();
+ }
+ for (auto& blacklisted : blacklist_entries) {
+ *next++ = blacklisted.release();
+ }
if (!passwords_entry_map)
return true;
@@ -454,7 +458,6 @@ syncer::SyncData SyncDataFromPassword(
CopyStringField(password_element);
CopyStringField(username_value);
CopyStringField(password_value);
- CopyField(ssl_valid);
CopyField(preferred);
password_specifics->set_date_created(
password_form.date_created.ToInternalValue());
@@ -488,7 +491,6 @@ autofill::PasswordForm PasswordFromSpecifics(
base::UTF8ToUTF16(password.password_element());
new_password.username_value = base::UTF8ToUTF16(password.username_value());
new_password.password_value = base::UTF8ToUTF16(password.password_value());
- new_password.ssl_valid = password.ssl_valid();
new_password.preferred = password.preferred();
new_password.date_created =
base::Time::FromInternalValue(password.date_created());
diff --git a/chromium/components/password_manager/core/browser/password_syncable_service.h b/chromium/components/password_manager/core/browser/password_syncable_service.h
index 78d4ef62038..344ab486ed2 100644
--- a/chromium/components/password_manager/core/browser/password_syncable_service.h
+++ b/chromium/components/password_manager/core/browser/password_syncable_service.h
@@ -12,12 +12,12 @@
#include "base/macros.h"
#include "base/threading/non_thread_safe.h"
#include "components/password_manager/core/browser/password_store_change.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/syncable_service.h"
-#include "sync/protocol/password_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/syncable_service.h"
+#include "components/sync/protocol/password_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
template <typename T>
class ScopedVector;
diff --git a/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc b/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc
index df7f280a3c2..c482ab30fd4 100644
--- a/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_syncable_service_unittest.cc
@@ -12,13 +12,14 @@
#include "base/location.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "components/password_manager/core/browser/mock_password_store.h"
-#include "sync/api/sync_change_processor.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_error_factory_mock.h"
+#include "components/sync/api/sync_change_processor.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_error_factory_mock.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -88,7 +89,6 @@ MATCHER_P(PasswordIs, form, "") {
actual_password.password_element() &&
expected_password.username_value() == actual_password.username_value() &&
expected_password.password_value() == actual_password.password_value() &&
- expected_password.ssl_valid() == actual_password.ssl_valid() &&
expected_password.preferred() == actual_password.preferred() &&
expected_password.date_created() == actual_password.date_created() &&
expected_password.blacklisted() == actual_password.blacklisted() &&
@@ -120,7 +120,7 @@ MATCHER_P2(SyncChangeIs, change_type, password, "") {
// The argument is std::vector<autofill::PasswordForm*>*. The caller is
// responsible for the lifetime of all the password forms.
ACTION_P(AppendForm, form) {
- arg0->push_back(new autofill::PasswordForm(form));
+ arg0->push_back(base::MakeUnique<autofill::PasswordForm>(form));
return true;
}
@@ -630,8 +630,6 @@ TEST_F(PasswordSyncableServiceTest, SerializeEmptyPasswordForm) {
EXPECT_EQ("", specifics.password_element());
EXPECT_TRUE(specifics.has_password_value());
EXPECT_EQ("", specifics.password_value());
- EXPECT_TRUE(specifics.has_ssl_valid());
- EXPECT_FALSE(specifics.ssl_valid());
EXPECT_TRUE(specifics.has_preferred());
EXPECT_FALSE(specifics.preferred());
EXPECT_TRUE(specifics.has_date_created());
@@ -662,7 +660,6 @@ TEST_F(PasswordSyncableServiceTest, SerializeNonEmptyPasswordForm) {
form.username_value = base::ASCIIToUTF16("god@google.com");
form.password_element = base::ASCIIToUTF16("password_element");
form.password_value = base::ASCIIToUTF16("!@#$%^&*()");
- form.ssl_valid = true;
form.preferred = true;
form.date_created = base::Time::FromInternalValue(100);
form.blacklisted_by_user = true;
@@ -690,8 +687,6 @@ TEST_F(PasswordSyncableServiceTest, SerializeNonEmptyPasswordForm) {
EXPECT_EQ("password_element", specifics.password_element());
EXPECT_TRUE(specifics.has_password_value());
EXPECT_EQ("!@#$%^&*()", specifics.password_value());
- EXPECT_TRUE(specifics.has_ssl_valid());
- EXPECT_TRUE(specifics.ssl_valid());
EXPECT_TRUE(specifics.has_preferred());
EXPECT_TRUE(specifics.preferred());
EXPECT_TRUE(specifics.has_date_created());
diff --git a/chromium/components/password_manager/core/browser/sql_table_builder.cc b/chromium/components/password_manager/core/browser/sql_table_builder.cc
new file mode 100644
index 00000000000..3c11742188e
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/sql_table_builder.cc
@@ -0,0 +1,319 @@
+// 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 "components/password_manager/core/browser/sql_table_builder.h"
+
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+#include "base/numerics/safe_conversions.h"
+#include "sql/connection.h"
+#include "sql/transaction.h"
+
+namespace password_manager {
+
+namespace {
+
+// Appends |name| to |list_of_names|, separating items with ", ".
+void Append(const std::string& name, std::string* list_of_names) {
+ if (list_of_names->empty())
+ *list_of_names = name;
+ else
+ *list_of_names += ", " + name;
+}
+
+} // namespace
+
+struct SQLTableBuilder::Column {
+ std::string name;
+ std::string type;
+ bool part_of_unique_key;
+ // The first version this column is part of.
+ unsigned min_version;
+ // The last version this column is part of. The value of kInvalidVersion
+ // means that it is part of all versions since |min_version|.
+ unsigned max_version;
+ // Renaming of a column is stored as a sequence of one removed and one added
+ // column in |columns_|. To distinguish it from an unrelated removal and
+ // addition, the following bit is set to true for the added columns which
+ // are part of renaming. Those columns will get the data of their
+ // predecessors. If the bit is false, the column will be filled with the
+ // default value on creation.
+ bool gets_previous_data;
+};
+
+SQLTableBuilder::SQLTableBuilder() = default;
+
+SQLTableBuilder::~SQLTableBuilder() = default;
+
+void SQLTableBuilder::AddColumn(const std::string& name,
+ const std::string& type) {
+ DCHECK(FindLastByName(name) == columns_.rend());
+ Column column = {name, type, false, sealed_version_ + 1, kInvalidVersion,
+ false};
+ columns_.push_back(std::move(column));
+}
+
+void SQLTableBuilder::AddColumnToUniqueKey(const std::string& name,
+ const std::string& type) {
+ AddColumn(name, type);
+ columns_.back().part_of_unique_key = true;
+}
+
+void SQLTableBuilder::RenameColumn(const std::string& old_name,
+ const std::string& new_name) {
+ auto old_column = FindLastByName(old_name);
+ DCHECK(old_column != columns_.rend());
+
+ if (old_name == new_name) // The easy case.
+ return;
+
+ DCHECK_NE("signon_realm", old_name);
+ if (sealed_version_ != kInvalidVersion &&
+ old_column->min_version <= sealed_version_) {
+ // This column exists in the last sealed version. Therefore it cannot be
+ // just replaced, it needs to be kept for generating the migration code.
+ Column new_column = {new_name,
+ old_column->type,
+ old_column->part_of_unique_key,
+ sealed_version_ + 1,
+ kInvalidVersion,
+ true};
+ old_column->max_version = sealed_version_;
+ auto past_old =
+ old_column.base(); // Points one element after |old_column|.
+ columns_.insert(past_old, std::move(new_column));
+ } else {
+ // This column was just introduced in the currently unsealed version. To
+ // rename it, it is enough just to modify the entry in columns_.
+ old_column->name = new_name;
+ }
+}
+
+// Removes column |name|. |name| must have been added in the past.
+void SQLTableBuilder::DropColumn(const std::string& name) {
+ auto column = FindLastByName(name);
+ DCHECK(column != columns_.rend());
+ DCHECK_NE("signon_realm", name);
+ if (sealed_version_ != kInvalidVersion &&
+ column->min_version <= sealed_version_) {
+ // This column exists in the last sealed version. Therefore it cannot be
+ // just deleted, it needs to be kept for generating the migration code.
+ column->max_version = sealed_version_;
+ } else {
+ // This column was just introduced in the currently unsealed version. It
+ // can be just erased from |columns_|.
+ columns_.erase(
+ --(column.base())); // base() points one element after |column|.
+ }
+}
+
+unsigned SQLTableBuilder::SealVersion() {
+ DCHECK(FindLastByName("signon_realm") != columns_.rend());
+ if (sealed_version_ == kInvalidVersion) {
+ DCHECK_EQ(std::string(), unique_constraint_);
+ // First sealed version, time to compute the UNIQUE string.
+ std::string unique_key;
+ for (const Column& column : columns_) {
+ if (column.part_of_unique_key)
+ Append(column.name, &unique_key);
+ }
+ DCHECK(!unique_key.empty());
+ unique_constraint_ = "UNIQUE (" + unique_key + ")";
+ }
+ DCHECK(!unique_constraint_.empty());
+ return ++sealed_version_;
+}
+
+bool SQLTableBuilder::MigrateFrom(unsigned old_version, sql::Connection* db) {
+ for (; old_version < sealed_version_; ++old_version) {
+ if (!MigrateToNextFrom(old_version, db))
+ return false;
+ }
+
+ return true;
+}
+
+bool SQLTableBuilder::CreateTable(sql::Connection* db) {
+ DCHECK(IsVersionLastAndSealed(sealed_version_));
+ DCHECK(!unique_constraint_.empty());
+
+ if (db->DoesTableExist("logins"))
+ return true;
+
+ std::string names; // Names and types of the current columns.
+ for (const Column& column : columns_) {
+ if (IsInLastVersion(column))
+ Append(column.name + " " + column.type, &names);
+ }
+
+ sql::Transaction transaction(db);
+ return transaction.Begin() &&
+ db->Execute(
+ ("CREATE TABLE logins (" + names + ", " + unique_constraint_ + ")")
+ .c_str()) &&
+ db->Execute("CREATE INDEX logins_signon ON logins (signon_realm)") &&
+ transaction.Commit();
+}
+
+std::string SQLTableBuilder::ListAllColumnNames() const {
+ DCHECK(IsVersionLastAndSealed(sealed_version_));
+ std::string result;
+ for (const Column& column : columns_) {
+ if (IsInLastVersion(column))
+ Append(column.name, &result);
+ }
+ return result;
+}
+
+std::string SQLTableBuilder::ListAllNonuniqueKeyNames() const {
+ DCHECK(IsVersionLastAndSealed(sealed_version_));
+ std::string result;
+ for (const Column& column : columns_) {
+ if (IsInLastVersion(column) && !column.part_of_unique_key)
+ Append(column.name + "=?", &result);
+ }
+ return result;
+}
+
+std::string SQLTableBuilder::ListAllUniqueKeyNames() const {
+ DCHECK(IsVersionLastAndSealed(sealed_version_));
+ std::string result;
+ for (const Column& column : columns_) {
+ if (IsInLastVersion(column) && column.part_of_unique_key) {
+ if (!result.empty())
+ result += " AND ";
+ result += column.name + "=?";
+ }
+ }
+ return result;
+}
+
+size_t SQLTableBuilder::NumberOfColumns() const {
+ DCHECK(IsVersionLastAndSealed(sealed_version_));
+ return base::checked_cast<size_t>(std::count_if(
+ columns_.begin(), columns_.end(),
+ [this](const Column& column) { return (IsInLastVersion(column)); }));
+}
+
+bool SQLTableBuilder::MigrateToNextFrom(unsigned old_version,
+ sql::Connection* db) {
+ DCHECK_LT(old_version, sealed_version_);
+ DCHECK_GE(old_version, 0u);
+ DCHECK(IsVersionLastAndSealed(sealed_version_));
+ DCHECK(!unique_constraint_.empty());
+
+ // Names of columns from old version, values of which are copied.
+ std::string old_names;
+ // Names of columns in new version, except for added ones.
+ std::string new_names;
+ std::vector<std::string> added_names; // Names of added columns.
+
+ // A temporary table will be needed if some columns are dropped or renamed,
+ // because that is not supported by a single SQLite command.
+ bool needs_temp_table = false;
+
+ for (auto column = columns_.begin(); column != columns_.end(); ++column) {
+ if (column->max_version == old_version) {
+ DCHECK(!column->part_of_unique_key);
+ // This column was deleted after |old_version|. It can have two reasons:
+ needs_temp_table = true;
+ auto next_column = column;
+ ++next_column;
+ if (next_column != columns_.end() && next_column->gets_previous_data) {
+ // (1) The column is being renamed.
+ DCHECK_EQ(column->type, next_column->type);
+ DCHECK_NE(column->name, next_column->name);
+ Append(column->name, &old_names);
+ Append(next_column->name + " " + next_column->type, &new_names);
+ ++column; // Avoid processing next_column in the next loop.
+ } else {
+ // (2) The column is being dropped.
+ }
+ } else if (column->min_version == old_version + 1) {
+ // This column was added after old_version.
+ DCHECK(!column->part_of_unique_key);
+ added_names.push_back(column->name + " " + column->type);
+ } else if (column->min_version <= old_version &&
+ (column->max_version == kInvalidVersion ||
+ column->max_version > old_version)) {
+ // This column stays.
+ Append(column->name, &old_names);
+ Append(column->name + " " + column->type, &new_names);
+ }
+ }
+
+ if (needs_temp_table) {
+ // Following the instructions from
+ // https://www.sqlite.org/lang_altertable.html#otheralter, this code works
+ // around the fact that SQLite does not allow dropping or renaming
+ // columns. Instead, a new table is constructed, with the new column
+ // names, and data from all but dropped columns from the current table are
+ // copied into it. After that, the new table is renamed to the current
+ // one.
+
+ // Foreign key constraints are not enabled for the login database, so no
+ // PRAGMA foreign_keys=off needed.
+ sql::Transaction transaction(db);
+ if (!transaction.Begin() ||
+ !db->Execute(("CREATE TABLE temp_logins (" + new_names + ", " +
+ unique_constraint_ + ")")
+ .c_str()) ||
+ !db->Execute(("INSERT OR REPLACE INTO temp_logins SELECT " + old_names +
+ " FROM logins")
+ .c_str()) ||
+ !db->Execute("DROP TABLE logins") ||
+ !db->Execute("ALTER TABLE temp_logins RENAME TO logins") ||
+ !db->Execute("CREATE INDEX logins_signon ON logins (signon_realm)") ||
+ !transaction.Commit()) {
+ return false;
+ }
+ }
+
+ if (!added_names.empty()) {
+ sql::Transaction transaction(db);
+ if (!transaction.Begin())
+ return false;
+ for (const std::string& name : added_names) {
+ if (!db->Execute(("ALTER TABLE logins ADD COLUMN " + name).c_str()))
+ return false;
+ }
+ if (!transaction.Commit())
+ return false;
+ }
+
+ return true;
+}
+
+std::list<SQLTableBuilder::Column>::reverse_iterator
+SQLTableBuilder::FindLastByName(const std::string& name) {
+ return std::find_if(
+ columns_.rbegin(), columns_.rend(),
+ [&name](const Column& column) { return name == column.name; });
+}
+
+bool SQLTableBuilder::IsVersionLastAndSealed(unsigned version) const {
+ // Is |version| the last sealed one?
+ if (sealed_version_ != version)
+ return false;
+ // Is the current version the last sealed one? In other words, is there
+ // either a column added past the sealed version (min_version > sealed) or
+ // deleted one version after the sealed (max_version == sealed)?
+ return columns_.end() ==
+ std::find_if(columns_.begin(), columns_.end(),
+ [this](const Column& column) {
+ return column.min_version > sealed_version_ ||
+ column.max_version == sealed_version_;
+ });
+}
+
+bool SQLTableBuilder::IsInLastVersion(const Column& column) const {
+ DCHECK(IsVersionLastAndSealed(sealed_version_));
+ return (column.min_version <= sealed_version_ &&
+ (column.max_version == kInvalidVersion ||
+ column.max_version >= sealed_version_));
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/sql_table_builder.h b/chromium/components/password_manager/core/browser/sql_table_builder.h
new file mode 100644
index 00000000000..bac1394f123
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/sql_table_builder.h
@@ -0,0 +1,149 @@
+// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SQL_TABLE_BUILDER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SQL_TABLE_BUILDER_H_
+
+#include <limits>
+#include <list>
+#include <string>
+
+#include "base/macros.h"
+
+namespace sql {
+class Connection;
+}
+
+namespace password_manager {
+
+// Use this class to represent the versioned evolution of a SQLite table
+// structure and generate creating and migrating statements for it.
+//
+// Two values are currently hard-coded, because they are the same in the
+// current use-cases:
+// * The table name is hard-coded as "logins".
+// * The index is built for column "signon_realm" which is expected to exist.
+//
+// Usage example:
+//
+// SQLTableBuilder builder;
+//
+// // First describe a couple of versions:
+// builder.AddColumn("name", "VARCHAR");
+// builder.AddColumn("icon", "VARCHAR");
+// builder.AddColumn("password", "VARCHAR NOT NULL");
+// unsigned version = builder.SealVersion(); // Version 0 is sealed.
+// DCHECK_EQ(0u, version);
+// builder.RenameColumn("icon", "avatar");
+// version = builder.SealVersion(); // Version 1 is sealed.
+// DCHECK_EQ(1u, version);
+//
+// // Now, assuming that |db| has a table "logins" in a state corresponding
+// // version 0, this will migrate it to version 1:
+// sql::Connection* db = ...;
+// builder.MigrateToNextFrom(0, db);
+//
+// // And assuming |db| has no table called "logins", this will create one
+// // in a state corresponding the latest sealed version:
+// builder.CreateTable(db);
+class SQLTableBuilder {
+ public:
+ // Create the builder for "logins".
+ SQLTableBuilder();
+
+ ~SQLTableBuilder();
+
+ // Adds a column in the table description, with |name| and |type|. |name|
+ // must not have been added to the table in this version before.
+ void AddColumn(const std::string& name, const std::string& type);
+
+ // As AddColumn but also adds column |name| to the unique key of the table.
+ // SealVersion must not have been called yet (the builder does not currently
+ // support migration code for changing the unique key between versions).
+ void AddColumnToUniqueKey(const std::string& name, const std::string& type);
+
+ // Renames column |old_name| to |new_name|. |old_name| must have been added in
+ // the past. The column "signon_realm" must not be renamed.
+ void RenameColumn(const std::string& old_name, const std::string& new_name);
+
+ // Removes column |name|. |name| must have been added in the past. The column
+ // "signon_realm" must not be renamed.
+ void DropColumn(const std::string& name);
+
+ // Increments the internal version counter and marks the current state of the
+ // table as that version. Returns the sealed version. Calling any of the
+ // *Column* methods above will result in starting a new version which is not
+ // considered sealed. The first version is 0. The column "signon_realm" must
+ // be present in |columns_| every time this is called, and at least one call
+ // to AddColumnToUniqueKey must have been done before this is called the first
+ // time.
+ unsigned SealVersion();
+
+ // Assuming that the database connected through |db| contains a table called
+ // "logins" in a state described by version |old_version|, migrates it to
+ // the current version, which must be sealed. Returns true on success.
+ bool MigrateFrom(unsigned old_version, sql::Connection* db);
+
+ // If |db| connects to a database where table "logins" already exists,
+ // this is a no-op and returns true. Otherwise, "logins" is created in a
+ // state described by the current version known to the builder. The current
+ // version must be sealed. Returns true on success.
+ bool CreateTable(sql::Connection* db);
+
+ // Returns the comma-separated list of all column names present in the last
+ // version. The last version must be sealed.
+ std::string ListAllColumnNames() const;
+
+ // Same as ListAllColumnNames, but for non-unique key names only, and with
+ // names followed by " = ?".
+ std::string ListAllNonuniqueKeyNames() const;
+
+ // Same as ListAllNonuniqueKeyNames, but for unique key names and separated by
+ // " AND ".
+ std::string ListAllUniqueKeyNames() const;
+
+ // Returns the number of all columns present in the last version. The last
+ // version must be sealed.
+ size_t NumberOfColumns() const;
+
+ private:
+ // Stores the information about one column (name, type, etc.).
+ struct Column;
+
+ static unsigned constexpr kInvalidVersion =
+ std::numeric_limits<unsigned>::max();
+
+ // Assuming that the database connected through |db| contains a table called
+ // "logins" in a state described by version |old_version|, migrates it to
+ // version |old_version + 1|. The current version known to the builder must be
+ // at least |old_version + 1| and sealed. Returns true on success.
+ bool MigrateToNextFrom(unsigned old_version, sql::Connection* db);
+
+ // Looks up column named |name| in |columns_|. If present, returns the last
+ // one.
+ std::list<Column>::reverse_iterator FindLastByName(const std::string& name);
+
+ // Returns whether the last version is |version| and whether it was sealed
+ // (by calling SealVersion with no table modifications afterwards).
+ bool IsVersionLastAndSealed(unsigned version) const;
+
+ // Whether |column| is present in the last version. The last version must be
+ // sealed.
+ bool IsInLastVersion(const Column& column) const;
+
+ // Last sealed version, kInvalidVersion means "none".
+ unsigned sealed_version_ = kInvalidVersion;
+
+ std::list<Column> columns_; // Columns of the table, across all versions.
+
+ // The "UNIQUE" part of an SQL CREATE TABLE constraint. This value is
+ // computed dring sealing the first version (0).
+ std::string unique_constraint_;
+
+ DISALLOW_COPY_AND_ASSIGN(SQLTableBuilder);
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SQL_TABLE_BUILDER_H_
diff --git a/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc b/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc
new file mode 100644
index 00000000000..a15cf932c93
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc
@@ -0,0 +1,253 @@
+// 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 "components/password_manager/core/browser/sql_table_builder.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/macros.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+class SQLTableBuilderTest : public testing::Test {
+ public:
+ SQLTableBuilderTest() { Init(); }
+
+ ~SQLTableBuilderTest() override = default;
+
+ protected:
+ // Checks whether a column with a given |name| is listed with the given
+ // |type| in the database.
+ bool IsColumnOfType(const std::string& name, const std::string& type);
+
+ sql::Connection* db() { return &db_; }
+
+ SQLTableBuilder* builder() { return &builder_; }
+
+ private:
+ // Part of constructor, needs to be a void-returning function to use ASSERTs.
+ void Init();
+
+ // Error handler for the SQL connection, prints the error code and the
+ // statement details.
+ void PrintDBError(int code, sql::Statement* statement);
+
+ sql::Connection db_;
+ SQLTableBuilder builder_;
+
+ DISALLOW_COPY_AND_ASSIGN(SQLTableBuilderTest);
+};
+
+bool SQLTableBuilderTest::IsColumnOfType(const std::string& name,
+ const std::string& type) {
+ return db()->GetSchema().find(name + " " + type) != std::string::npos;
+}
+
+void SQLTableBuilderTest::Init() {
+ db_.set_error_callback(
+ base::Bind(&SQLTableBuilderTest::PrintDBError, base::Unretained(this)));
+ ASSERT_TRUE(db_.OpenInMemory());
+ // The following column must always be present, so let's add it here.
+ builder_.AddColumnToUniqueKey("signon_realm", "VARCHAR NOT NULL");
+}
+
+void SQLTableBuilderTest::PrintDBError(int code, sql::Statement* statement) {
+ VLOG(0) << "DB error encountered, code = " << code;
+ if (statement) {
+ VLOG(0) << "statement string = " << statement->GetSQLStatement();
+ VLOG(0) << "statement is " << (statement->is_valid() ? "valid" : "invalid");
+ }
+}
+
+TEST_F(SQLTableBuilderTest, SealVersion_0) {
+ EXPECT_EQ(0u, builder()->SealVersion());
+ EXPECT_TRUE(builder()->MigrateFrom(0, db()));
+ EXPECT_TRUE(builder()->CreateTable(db()));
+ EXPECT_TRUE(db()->DoesTableExist("logins"));
+ EXPECT_TRUE(db()->DoesIndexExist("logins_signon"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "signon_realm"));
+ EXPECT_TRUE(IsColumnOfType("signon_realm", "VARCHAR NOT NULL"));
+}
+
+TEST_F(SQLTableBuilderTest, AddColumn) {
+ builder()->AddColumn("password_value", "BLOB");
+ EXPECT_EQ(0u, builder()->SealVersion());
+ EXPECT_TRUE(builder()->MigrateFrom(0, db()));
+ EXPECT_TRUE(builder()->CreateTable(db()));
+ EXPECT_TRUE(db()->DoesTableExist("logins"));
+ EXPECT_TRUE(db()->DoesIndexExist("logins_signon"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "signon_realm"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "password_value"));
+ EXPECT_TRUE(IsColumnOfType("password_value", "BLOB"));
+}
+
+TEST_F(SQLTableBuilderTest, RenameColumn_InSameVersion) {
+ builder()->AddColumn("old_name", "BLOB");
+ builder()->RenameColumn("old_name", "password_value");
+ EXPECT_EQ(0u, builder()->SealVersion());
+ EXPECT_TRUE(builder()->CreateTable(db()));
+ EXPECT_TRUE(db()->DoesTableExist("logins"));
+ EXPECT_FALSE(db()->DoesColumnExist("logins", "old_name"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "password_value"));
+ EXPECT_TRUE(IsColumnOfType("password_value", "BLOB"));
+}
+
+TEST_F(SQLTableBuilderTest, RenameColumn_InNextVersion) {
+ builder()->AddColumn("old_name", "BLOB");
+ EXPECT_EQ(0u, builder()->SealVersion());
+ builder()->RenameColumn("old_name", "password_value");
+ EXPECT_EQ(1u, builder()->SealVersion());
+ EXPECT_TRUE(builder()->CreateTable(db()));
+ EXPECT_TRUE(db()->DoesTableExist("logins"));
+ EXPECT_FALSE(db()->DoesColumnExist("logins", "old_name"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "password_value"));
+ EXPECT_TRUE(IsColumnOfType("password_value", "BLOB"));
+}
+
+TEST_F(SQLTableBuilderTest, RenameColumn_SameNameInSameVersion) {
+ builder()->AddColumn("name", "BLOB");
+ builder()->RenameColumn("name", "name");
+ EXPECT_EQ(0u, builder()->SealVersion());
+ EXPECT_TRUE(builder()->CreateTable(db()));
+ EXPECT_TRUE(db()->DoesTableExist("logins"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "name"));
+ EXPECT_TRUE(IsColumnOfType("name", "BLOB"));
+}
+
+TEST_F(SQLTableBuilderTest, RenameColumn_SameNameInNextVersion) {
+ builder()->AddColumn("name", "BLOB");
+ EXPECT_EQ(0u, builder()->SealVersion());
+ builder()->RenameColumn("name", "name");
+ EXPECT_EQ(1u, builder()->SealVersion());
+ EXPECT_TRUE(builder()->CreateTable(db()));
+ EXPECT_TRUE(db()->DoesTableExist("logins"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "name"));
+ EXPECT_TRUE(IsColumnOfType("name", "BLOB"));
+}
+
+TEST_F(SQLTableBuilderTest, DropColumn_InSameVersion) {
+ builder()->AddColumn("password_value", "BLOB");
+ builder()->DropColumn("password_value");
+ EXPECT_EQ(0u, builder()->SealVersion());
+ EXPECT_TRUE(builder()->CreateTable(db()));
+ EXPECT_TRUE(db()->DoesTableExist("logins"));
+ EXPECT_FALSE(db()->DoesColumnExist("logins", "password_value"));
+}
+
+TEST_F(SQLTableBuilderTest, DropColumn_InNextVersion) {
+ builder()->AddColumn("password_value", "BLOB");
+ EXPECT_EQ(0u, builder()->SealVersion());
+ builder()->DropColumn("password_value");
+ EXPECT_EQ(1u, builder()->SealVersion());
+ EXPECT_TRUE(builder()->CreateTable(db()));
+ EXPECT_TRUE(db()->DoesTableExist("logins"));
+ EXPECT_FALSE(db()->DoesColumnExist("logins", "password_value"));
+}
+
+TEST_F(SQLTableBuilderTest, MigrateFrom) {
+ // First, create a table at version 0, with some columns.
+ builder()->AddColumn("for_renaming", "INTEGER DEFAULT 100");
+ builder()->AddColumn("for_deletion", "INTEGER");
+ EXPECT_EQ(0u, builder()->SealVersion());
+ EXPECT_TRUE(builder()->CreateTable(db()));
+ EXPECT_TRUE(db()->DoesTableExist("logins"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "for_renaming"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "for_deletion"));
+ EXPECT_TRUE(
+ db()->Execute("INSERT INTO logins (signon_realm, for_renaming, "
+ "for_deletion) VALUES ('abc', 123, 456)"));
+ const char retrieval[] = "SELECT * FROM logins";
+ sql::Statement first_check(
+ db()->GetCachedStatement(SQL_FROM_HERE, retrieval));
+ EXPECT_TRUE(first_check.Step());
+ EXPECT_EQ(3, first_check.ColumnCount());
+ EXPECT_EQ("abc", first_check.ColumnString(0));
+ EXPECT_EQ(123, first_check.ColumnInt(1));
+ EXPECT_EQ(456, first_check.ColumnInt(2));
+ EXPECT_FALSE(first_check.Step());
+ EXPECT_TRUE(first_check.Succeeded());
+
+ // Now, specify some modifications for version 1.
+ builder()->RenameColumn("for_renaming", "renamed");
+ builder()->DropColumn("for_deletion");
+ builder()->AddColumn("new_column", "INTEGER DEFAULT 789");
+ EXPECT_EQ(1u, builder()->SealVersion());
+
+ // The migration should have the following effect:
+ // * The renamed column should keep its non-default value.
+ // * The succession of column removal and addition should not result in the
+ // values from the deleted column to be copied to the added one.
+ EXPECT_TRUE(builder()->MigrateFrom(0, db()));
+ EXPECT_FALSE(db()->DoesColumnExist("logins", "for_renaming"));
+ EXPECT_FALSE(db()->DoesColumnExist("logins", "for_deletion"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "renamed"));
+ EXPECT_TRUE(IsColumnOfType("renamed", "INTEGER"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "new_column"));
+ sql::Statement second_check(
+ db()->GetCachedStatement(SQL_FROM_HERE, retrieval));
+ EXPECT_TRUE(second_check.Step());
+ EXPECT_EQ(3, second_check.ColumnCount());
+ EXPECT_EQ("abc", second_check.ColumnString(0));
+ EXPECT_EQ(123, second_check.ColumnInt(1));
+ EXPECT_EQ(789, second_check.ColumnInt(2));
+ EXPECT_FALSE(second_check.Step());
+ EXPECT_TRUE(second_check.Succeeded());
+}
+
+TEST_F(SQLTableBuilderTest, MigrateFrom_RenameAndAdd) {
+ builder()->AddColumn("old_name", "INTEGER");
+ EXPECT_EQ(0u, builder()->SealVersion());
+
+ EXPECT_TRUE(builder()->CreateTable(db()));
+
+ builder()->RenameColumn("old_name", "new_name");
+ EXPECT_EQ(1u, builder()->SealVersion());
+
+ builder()->AddColumn("added", "VARCHAR");
+ EXPECT_EQ(2u, builder()->SealVersion());
+
+ EXPECT_TRUE(builder()->MigrateFrom(0, db()));
+ EXPECT_FALSE(db()->DoesColumnExist("logins", "old_name"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "added"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "new_name"));
+ EXPECT_TRUE(IsColumnOfType("added", "VARCHAR"));
+ EXPECT_TRUE(IsColumnOfType("new_name", "INTEGER"));
+ EXPECT_EQ(3u, builder()->NumberOfColumns());
+ EXPECT_EQ("signon_realm, new_name, added", builder()->ListAllColumnNames());
+ EXPECT_EQ("new_name=?, added=?", builder()->ListAllNonuniqueKeyNames());
+ EXPECT_EQ("signon_realm=?", builder()->ListAllUniqueKeyNames());
+}
+
+TEST_F(SQLTableBuilderTest, MigrateFrom_RenameAndAddAndDrop) {
+ builder()->AddColumnToUniqueKey("uni", "VARCHAR NOT NULL");
+ builder()->AddColumn("old_name", "INTEGER");
+ EXPECT_EQ(0u, builder()->SealVersion());
+
+ EXPECT_TRUE(builder()->CreateTable(db()));
+
+ builder()->RenameColumn("old_name", "new_name");
+ EXPECT_EQ(1u, builder()->SealVersion());
+
+ builder()->AddColumn("added", "VARCHAR");
+ EXPECT_EQ(2u, builder()->SealVersion());
+
+ builder()->DropColumn("added");
+ EXPECT_EQ(3u, builder()->SealVersion());
+
+ EXPECT_TRUE(builder()->MigrateFrom(0, db()));
+ EXPECT_FALSE(db()->DoesColumnExist("logins", "old_name"));
+ EXPECT_FALSE(db()->DoesColumnExist("logins", "added"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "uni"));
+ EXPECT_TRUE(db()->DoesColumnExist("logins", "new_name"));
+ EXPECT_TRUE(IsColumnOfType("new_name", "INTEGER"));
+ EXPECT_EQ(3u, builder()->NumberOfColumns());
+ EXPECT_EQ("signon_realm, uni, new_name", builder()->ListAllColumnNames());
+ EXPECT_EQ("new_name=?", builder()->ListAllNonuniqueKeyNames());
+ EXPECT_EQ("signon_realm=? AND uni=?", builder()->ListAllUniqueKeyNames());
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/statistics_table.cc b/chromium/components/password_manager/core/browser/statistics_table.cc
index 23522a9a8db..0b6cc2cc0c4 100644
--- a/chromium/components/password_manager/core/browser/statistics_table.cc
+++ b/chromium/components/password_manager/core/browser/statistics_table.cc
@@ -8,6 +8,7 @@
#include <algorithm>
#include <limits>
+#include <set>
#include "base/memory/ptr_util.h"
#include "sql/connection.h"
@@ -35,15 +36,14 @@ bool operator==(const InteractionsStats& lhs, const InteractionsStats& rhs) {
lhs.update_time == rhs.update_time;
}
-InteractionsStats* FindStatsByUsername(
- const std::vector<std::unique_ptr<InteractionsStats>>& stats,
+const InteractionsStats* FindStatsByUsername(
+ const std::vector<const InteractionsStats*>& stats,
const base::string16& username) {
- auto it = std::find_if(
- stats.begin(), stats.end(),
- [&username](const std::unique_ptr<InteractionsStats>& element) {
- return username == element->username_value;
- });
- return it == stats.end() ? nullptr : it->get();
+ auto it = std::find_if(stats.begin(), stats.end(),
+ [&username](const InteractionsStats* element) {
+ return username == element->username_value;
+ });
+ return it == stats.end() ? nullptr : *it;
}
StatisticsTable::StatisticsTable() : db_(nullptr) {
@@ -127,15 +127,54 @@ std::vector<std::unique_ptr<InteractionsStats>> StatisticsTable::GetRows(
return result;
}
-bool StatisticsTable::RemoveStatsBetween(base::Time delete_begin,
- base::Time delete_end) {
- sql::Statement s(db_->GetCachedStatement(
- SQL_FROM_HERE,
- "DELETE FROM stats WHERE update_time >= ? AND update_time < ?"));
- s.BindInt64(0, delete_begin.ToInternalValue());
- s.BindInt64(1, delete_end.is_null() ? std::numeric_limits<int64_t>::max()
- : delete_end.ToInternalValue());
- return s.Run();
+bool StatisticsTable::RemoveStatsByOriginAndTime(
+ const base::Callback<bool(const GURL&)>& origin_filter,
+ base::Time delete_begin,
+ base::Time delete_end) {
+ if (delete_end.is_null())
+ delete_end = base::Time::Max();
+
+ // All origins.
+ if (origin_filter.is_null()) {
+ sql::Statement delete_statement(db_->GetCachedStatement(
+ SQL_FROM_HERE,
+ "DELETE FROM stats WHERE update_time >= ? AND update_time < ?"));
+ delete_statement.BindInt64(0, delete_begin.ToInternalValue());
+ delete_statement.BindInt64(1, delete_end.ToInternalValue());
+
+ return delete_statement.Run();
+ }
+
+ // Origin filtering.
+ sql::Statement select_statement(
+ db_->GetCachedStatement(SQL_FROM_HERE,
+ "SELECT origin_domain FROM stats "
+ "WHERE update_time >= ? AND update_time < ?"));
+ select_statement.BindInt64(0, delete_begin.ToInternalValue());
+ select_statement.BindInt64(1, delete_end.ToInternalValue());
+
+ std::set<std::string> origins;
+ while (select_statement.Step()) {
+ if (!origin_filter.Run(GURL(select_statement.ColumnString(0))))
+ continue;
+
+ origins.insert(select_statement.ColumnString(0));
+ }
+
+ bool success = true;
+
+ for (const std::string& origin : origins) {
+ sql::Statement origin_delete_statement(db_->GetCachedStatement(
+ SQL_FROM_HERE,
+ "DELETE FROM stats "
+ "WHERE origin_domain = ? AND update_time >= ? AND update_time < ?"));
+ origin_delete_statement.BindString(0, origin);
+ origin_delete_statement.BindInt64(1, delete_begin.ToInternalValue());
+ origin_delete_statement.BindInt64(2, delete_end.ToInternalValue());
+ success = success && origin_delete_statement.Run();
+ }
+
+ return success;
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/statistics_table.h b/chromium/components/password_manager/core/browser/statistics_table.h
index d53c849106e..eefa3b45a7d 100644
--- a/chromium/components/password_manager/core/browser/statistics_table.h
+++ b/chromium/components/password_manager/core/browser/statistics_table.h
@@ -8,6 +8,7 @@
#include <memory>
#include <vector>
+#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/scoped_vector.h"
#include "base/time/time.h"
@@ -39,8 +40,8 @@ struct InteractionsStats {
bool operator==(const InteractionsStats& lhs, const InteractionsStats& rhs);
// Returns an element from |stats| with |username| or nullptr if not found.
-InteractionsStats* FindStatsByUsername(
- const std::vector<std::unique_ptr<InteractionsStats>>& stats,
+const InteractionsStats* FindStatsByUsername(
+ const std::vector<const InteractionsStats*>& stats,
const base::string16& username);
// Represents the 'stats' table in the Login Database.
@@ -71,9 +72,13 @@ class StatisticsTable {
// Returns the statistics for |domain| if it exists.
std::vector<std::unique_ptr<InteractionsStats>> GetRows(const GURL& domain);
- // Removes the statistics between the dates. Returns true if the SQL completed
- // successfully.
- bool RemoveStatsBetween(base::Time delete_begin, base::Time delete_end);
+ // Removes the statistics between the dates. If |origin_filter| is not null,
+ // only statistics for matching origins are removed. Returns true if the SQL
+ // completed successfully.
+ bool RemoveStatsByOriginAndTime(
+ const base::Callback<bool(const GURL&)>& origin_filter,
+ base::Time delete_begin,
+ base::Time delete_end);
private:
sql::Connection* db_;
diff --git a/chromium/components/password_manager/core/browser/statistics_table_unittest.cc b/chromium/components/password_manager/core/browser/statistics_table_unittest.cc
index 8e348a05e0b..adf1f0c7fef 100644
--- a/chromium/components/password_manager/core/browser/statistics_table_unittest.cc
+++ b/chromium/components/password_manager/core/browser/statistics_table_unittest.cc
@@ -4,6 +4,8 @@
#include "components/password_manager/core/browser/statistics_table.h"
+#include "base/bind.h"
+#include "base/callback.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/utf_string_conversions.h"
#include "sql/connection.h"
@@ -15,6 +17,8 @@ namespace {
const char kTestDomain[] = "http://google.com";
const char kTestDomain2[] = "http://example.com";
+const char kTestDomain3[] = "https://example.org";
+const char kTestDomain4[] = "http://localhost";
const char kUsername1[] = "user1";
const char kUsername2[] = "user2";
@@ -36,7 +40,7 @@ class StatisticsTableTest : public testing::Test {
}
void ReloadDatabase() {
- base::FilePath file = temp_dir_.path().AppendASCII("TestDatabase");
+ base::FilePath file = temp_dir_.GetPath().AppendASCII("TestDatabase");
db_.reset(new StatisticsTable);
connection_.reset(new sql::Connection);
connection_->set_exclusive_locking();
@@ -98,30 +102,64 @@ TEST_F(StatisticsTableTest, DifferentUsernames) {
EXPECT_THAT(db()->GetRows(test_data().origin_domain), IsEmpty());
}
-TEST_F(StatisticsTableTest, RemoveBetween) {
+TEST_F(StatisticsTableTest, RemoveStatsByOriginAndTime) {
InteractionsStats stats1 = test_data();
stats1.update_time = base::Time::FromTimeT(1);
InteractionsStats stats2 = test_data();
stats2.update_time = base::Time::FromTimeT(2);
stats2.origin_domain = GURL(kTestDomain2);
+ InteractionsStats stats3 = test_data();
+ stats3.update_time = base::Time::FromTimeT(2);
+ stats3.origin_domain = GURL(kTestDomain3);
+ InteractionsStats stats4 = test_data();
+ stats4.update_time = base::Time::FromTimeT(2);
+ stats4.origin_domain = GURL(kTestDomain4);
EXPECT_TRUE(db()->AddRow(stats1));
EXPECT_TRUE(db()->AddRow(stats2));
+ EXPECT_TRUE(db()->AddRow(stats3));
+ EXPECT_TRUE(db()->AddRow(stats4));
EXPECT_THAT(db()->GetRows(stats1.origin_domain),
ElementsAre(Pointee(stats1)));
EXPECT_THAT(db()->GetRows(stats2.origin_domain),
ElementsAre(Pointee(stats2)));
-
- // Remove the first one only.
- EXPECT_TRUE(db()->RemoveStatsBetween(base::Time(), base::Time::FromTimeT(2)));
+ EXPECT_THAT(db()->GetRows(stats3.origin_domain),
+ ElementsAre(Pointee(stats3)));
+ EXPECT_THAT(db()->GetRows(stats4.origin_domain),
+ ElementsAre(Pointee(stats4)));
+
+ // Remove the entry with the timestamp 1 with no origin filter.
+ EXPECT_TRUE(
+ db()->RemoveStatsByOriginAndTime(base::Callback<bool(const GURL&)>(),
+ base::Time(), base::Time::FromTimeT(2)));
EXPECT_THAT(db()->GetRows(stats1.origin_domain), IsEmpty());
EXPECT_THAT(db()->GetRows(stats2.origin_domain),
ElementsAre(Pointee(stats2)));
-
- // Remove the second one only.
- EXPECT_TRUE(db()->RemoveStatsBetween(base::Time::FromTimeT(2), base::Time()));
+ EXPECT_THAT(db()->GetRows(stats3.origin_domain),
+ ElementsAre(Pointee(stats3)));
+ EXPECT_THAT(db()->GetRows(stats4.origin_domain),
+ ElementsAre(Pointee(stats4)));
+
+ // Remove the entries with the timestamp 2 that are NOT matching
+ // |kTestDomain3|.
+ EXPECT_TRUE(db()->RemoveStatsByOriginAndTime(
+ base::Bind(&GURL::operator!=, base::Unretained(&stats3.origin_domain)),
+ base::Time::FromTimeT(2), base::Time()));
+ EXPECT_THAT(db()->GetRows(stats1.origin_domain), IsEmpty());
+ EXPECT_THAT(db()->GetRows(stats2.origin_domain), IsEmpty());
+ EXPECT_THAT(db()->GetRows(stats3.origin_domain),
+ ElementsAre(Pointee(stats3)));
+ EXPECT_THAT(db()->GetRows(stats4.origin_domain), IsEmpty());
+
+ // Remove the entries with the timestamp 2 with no origin filter.
+ // This should delete the remaining entry.
+ EXPECT_TRUE(
+ db()->RemoveStatsByOriginAndTime(base::Callback<bool(const GURL&)>(),
+ base::Time::FromTimeT(2), base::Time()));
EXPECT_THAT(db()->GetRows(stats1.origin_domain), IsEmpty());
EXPECT_THAT(db()->GetRows(stats2.origin_domain), IsEmpty());
+ EXPECT_THAT(db()->GetRows(stats3.origin_domain), IsEmpty());
+ EXPECT_THAT(db()->GetRows(stats4.origin_domain), IsEmpty());
}
TEST_F(StatisticsTableTest, BadURL) {
diff --git a/chromium/components/password_manager/core/browser/stub_credentials_filter.cc b/chromium/components/password_manager/core/browser/stub_credentials_filter.cc
new file mode 100644
index 00000000000..8782cc324f9
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/stub_credentials_filter.cc
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/stub_credentials_filter.h"
+
+namespace password_manager {
+
+StubCredentialsFilter::StubCredentialsFilter() = default;
+
+StubCredentialsFilter::~StubCredentialsFilter() = default;
+
+std::vector<std::unique_ptr<autofill::PasswordForm>>
+StubCredentialsFilter::FilterResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results) const {
+ FilterResultsPtr(&results);
+ return results;
+}
+
+bool StubCredentialsFilter::ShouldSave(
+ const autofill::PasswordForm& form) const {
+ return true;
+}
+
+void StubCredentialsFilter::ReportFormLoginSuccess(
+ const PasswordFormManager& form_manager) const {}
+
+void StubCredentialsFilter::FilterResultsPtr(
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* results) const {}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/stub_credentials_filter.h b/chromium/components/password_manager/core/browser/stub_credentials_filter.h
new file mode 100644
index 00000000000..03fcd34c671
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/stub_credentials_filter.h
@@ -0,0 +1,41 @@
+// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STUB_CREDENTIALS_FILTER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STUB_CREDENTIALS_FILTER_H_
+
+#include "base/macros.h"
+#include "components/password_manager/core/browser/credentials_filter.h"
+
+namespace password_manager {
+
+// Stub of the CredentialsFilter API, to be used in tests. This filter does
+// not filter out anything.
+class StubCredentialsFilter : public CredentialsFilter {
+ public:
+ StubCredentialsFilter();
+
+ ~StubCredentialsFilter() override;
+
+ // CredentialsFilter
+ std::vector<std::unique_ptr<autofill::PasswordForm>> FilterResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results)
+ const override;
+ bool ShouldSave(const autofill::PasswordForm& form) const override;
+ void ReportFormLoginSuccess(
+ const PasswordFormManager& form_manager) const override;
+
+ // A version of FilterResult without moveable arguments, which cannot be
+ // mocked in GMock. StubCredentialsFilter::FilterResults(arg) calls
+ // FilterResultsPtr(&arg).
+ virtual void FilterResultsPtr(
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* results) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StubCredentialsFilter);
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STUB_CREDENTIALS_FILTER_H_
diff --git a/chromium/components/password_manager/core/browser/stub_form_saver.h b/chromium/components/password_manager/core/browser/stub_form_saver.h
index 6f5178ef84b..5efa6834424 100644
--- a/chromium/components/password_manager/core/browser/stub_form_saver.h
+++ b/chromium/components/password_manager/core/browser/stub_form_saver.h
@@ -20,19 +20,20 @@ class StubFormSaver : public FormSaver {
// FormSaver:
void PermanentlyBlacklist(autofill::PasswordForm* observed) override {}
void Save(const autofill::PasswordForm& pending,
- const autofill::PasswordFormMap& best_matches,
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches,
const autofill::PasswordForm* old_primary_key) override {}
- void Update(
- const autofill::PasswordForm& pending,
- const autofill::PasswordFormMap& best_matches,
- const std::vector<const autofill::PasswordForm*>* credentials_to_update,
- const autofill::PasswordForm* old_primary_key) override {}
+ void Update(const autofill::PasswordForm& pending,
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ best_matches,
+ const std::vector<autofill::PasswordForm>* credentials_to_update,
+ const autofill::PasswordForm* old_primary_key) override {}
void PresaveGeneratedPassword(
const autofill::PasswordForm& generated) override {}
void RemovePresavedPassword() override {}
void WipeOutdatedCopies(
const autofill::PasswordForm& pending,
- autofill::PasswordFormMap* best_matches,
+ std::map<base::string16, const autofill::PasswordForm*>* best_matches,
const autofill::PasswordForm** preferred_match) override {}
private:
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_client.cc b/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
index 6c1cf911141..fd44b2ca024 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -12,17 +12,6 @@
namespace password_manager {
-ScopedVector<autofill::PasswordForm>
-StubPasswordManagerClient::PassThroughCredentialsFilter::FilterResults(
- ScopedVector<autofill::PasswordForm> results) const {
- return results;
-}
-
-bool StubPasswordManagerClient::PassThroughCredentialsFilter::ShouldSave(
- const autofill::PasswordForm& form) const {
- return true;
-}
-
StubPasswordManagerClient::StubPasswordManagerClient() {}
StubPasswordManagerClient::~StubPasswordManagerClient() {}
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_client.h b/chromium/components/password_manager/core/browser/stub_password_manager_client.h
index abb2c7dd114..be0ef050cf7 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_client.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/password_manager/core/browser/stub_credentials_filter.h"
#include "components/password_manager/core/browser/stub_log_manager.h"
namespace password_manager {
@@ -45,19 +46,7 @@ class StubPasswordManagerClient : public PasswordManagerClient {
const LogManager* GetLogManager() const override;
private:
- // This filter does not filter out anything, it is a dummy implementation of
- // the filter interface.
- class PassThroughCredentialsFilter : public CredentialsFilter {
- public:
- PassThroughCredentialsFilter() {}
-
- // CredentialsFilter:
- ScopedVector<autofill::PasswordForm> FilterResults(
- ScopedVector<autofill::PasswordForm> results) const override;
- bool ShouldSave(const autofill::PasswordForm& form) const override;
- };
-
- const PassThroughCredentialsFilter credentials_filter_;
+ const StubCredentialsFilter credentials_filter_;
StubLogManager log_manager_;
DISALLOW_COPY_AND_ASSIGN(StubPasswordManagerClient);
diff --git a/chromium/components/password_manager/core/browser/test_password_store.cc b/chromium/components/password_manager/core/browser/test_password_store.cc
index f4a0f6f525f..4d4f823f472 100644
--- a/chromium/components/password_manager/core/browser/test_password_store.cc
+++ b/chromium/components/password_manager/core/browser/test_password_store.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/psl_matching_helper.h"
@@ -81,15 +82,16 @@ PasswordStoreChangeList TestPasswordStore::RemoveLoginImpl(
return changes;
}
-ScopedVector<autofill::PasswordForm> TestPasswordStore::FillMatchingLogins(
- const autofill::PasswordForm& form) {
- ScopedVector<autofill::PasswordForm> matched_forms;
+std::vector<std::unique_ptr<autofill::PasswordForm>>
+TestPasswordStore::FillMatchingLogins(const FormDigest& form) {
+ std::vector<std::unique_ptr<autofill::PasswordForm>> matched_forms;
for (const auto& elements : stored_passwords_) {
if (elements.first == form.signon_realm ||
(form.scheme == autofill::PasswordForm::SCHEME_HTML &&
password_manager::IsFederatedMatch(elements.first, form.origin))) {
for (const auto& stored_form : elements.second)
- matched_forms.push_back(new autofill::PasswordForm(stored_form));
+ matched_forms.push_back(
+ base::MakeUnique<autofill::PasswordForm>(stored_form));
}
}
return matched_forms;
@@ -118,33 +120,35 @@ PasswordStoreChangeList TestPasswordStore::RemoveLoginsSyncedBetweenImpl(
return PasswordStoreChangeList();
}
-PasswordStoreChangeList TestPasswordStore::DisableAutoSignInForAllLoginsImpl() {
+PasswordStoreChangeList TestPasswordStore::DisableAutoSignInForOriginsImpl(
+ const base::Callback<bool(const GURL&)>& origin_filter) {
return PasswordStoreChangeList();
}
-bool TestPasswordStore::RemoveStatisticsCreatedBetweenImpl(
+bool TestPasswordStore::RemoveStatisticsByOriginAndTimeImpl(
+ const base::Callback<bool(const GURL&)>& origin_filter,
base::Time delete_begin,
base::Time delete_end) {
return false;
}
bool TestPasswordStore::FillAutofillableLogins(
- ScopedVector<autofill::PasswordForm>* forms) {
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) {
for (const auto& forms_for_realm : stored_passwords_) {
for (const autofill::PasswordForm& form : forms_for_realm.second) {
if (!form.blacklisted_by_user)
- forms->push_back(new autofill::PasswordForm(form));
+ forms->push_back(base::MakeUnique<autofill::PasswordForm>(form));
}
}
return true;
}
bool TestPasswordStore::FillBlacklistLogins(
- ScopedVector<autofill::PasswordForm>* forms) {
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) {
for (const auto& forms_for_realm : stored_passwords_) {
for (const autofill::PasswordForm& form : forms_for_realm.second) {
if (form.blacklisted_by_user)
- forms->push_back(new autofill::PasswordForm(form));
+ forms->push_back(base::MakeUnique<autofill::PasswordForm>(form));
}
}
return true;
diff --git a/chromium/components/password_manager/core/browser/test_password_store.h b/chromium/components/password_manager/core/browser/test_password_store.h
index 1e76e305ed7..891d88c12cb 100644
--- a/chromium/components/password_manager/core/browser/test_password_store.h
+++ b/chromium/components/password_manager/core/browser/test_password_store.h
@@ -44,8 +44,8 @@ class TestPasswordStore : public PasswordStore {
const autofill::PasswordForm& form) override;
PasswordStoreChangeList RemoveLoginImpl(
const autofill::PasswordForm& form) override;
- ScopedVector<autofill::PasswordForm> FillMatchingLogins(
- const autofill::PasswordForm& form) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> FillMatchingLogins(
+ const FormDigest& form) override;
// Unused portions of PasswordStore interface
void ReportMetricsImpl(const std::string& sync_username,
@@ -60,13 +60,16 @@ class TestPasswordStore : public PasswordStore {
PasswordStoreChangeList RemoveLoginsSyncedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) override;
- PasswordStoreChangeList DisableAutoSignInForAllLoginsImpl() override;
- bool RemoveStatisticsCreatedBetweenImpl(base::Time delete_begin,
- base::Time delete_end) override;
+ PasswordStoreChangeList DisableAutoSignInForOriginsImpl(
+ const base::Callback<bool(const GURL&)>& origin_filter) override;
+ bool RemoveStatisticsByOriginAndTimeImpl(
+ const base::Callback<bool(const GURL&)>& origin_filter,
+ base::Time delete_begin,
+ base::Time delete_end) override;
bool FillAutofillableLogins(
- ScopedVector<autofill::PasswordForm>* forms) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override;
bool FillBlacklistLogins(
- ScopedVector<autofill::PasswordForm>* forms) override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override;
void AddSiteStatsImpl(const InteractionsStats& stats) override;
void RemoveSiteStatsImpl(const GURL& origin_domain) override;
std::vector<std::unique_ptr<InteractionsStats>> GetSiteStatsImpl(
diff --git a/chromium/components/password_manager/core/common/BUILD.gn b/chromium/components/password_manager/core/common/BUILD.gn
index 80229d9d124..47976880d50 100644
--- a/chromium/components/password_manager/core/common/BUILD.gn
+++ b/chromium/components/password_manager/core/common/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("common") {
+static_library("common") {
sources = [
"credential_manager_types.cc",
"credential_manager_types.h",
diff --git a/chromium/components/password_manager/core/common/credential_manager_types.cc b/chromium/components/password_manager/core/common/credential_manager_types.cc
index 484b2be7858..068d3ac7bfb 100644
--- a/chromium/components/password_manager/core/common/credential_manager_types.cc
+++ b/chromium/components/password_manager/core/common/credential_manager_types.cc
@@ -5,20 +5,26 @@
#include "components/password_manager/core/common/credential_manager_types.h"
#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
#include "components/autofill/core/common/password_form.h"
namespace password_manager {
-std::ostream& operator<<(std::ostream& os, CredentialType value) {
+std::string CredentialTypeToString(CredentialType value) {
switch (value) {
case CredentialType::CREDENTIAL_TYPE_EMPTY:
- return os << "CredentialType::CREDENTIAL_TYPE_EMPTY";
+ return "CredentialType::CREDENTIAL_TYPE_EMPTY";
case CredentialType::CREDENTIAL_TYPE_PASSWORD:
- return os << "CredentialType::CREDENTIAL_TYPE_PASSWORD";
+ return "CredentialType::CREDENTIAL_TYPE_PASSWORD";
case CredentialType::CREDENTIAL_TYPE_FEDERATED:
- return os << "CredentialType::CREDENTIAL_TYPE_FEDERATED";
+ return "CredentialType::CREDENTIAL_TYPE_FEDERATED";
}
- return os << "Unknown CredentialType value: " << static_cast<int32_t>(value);
+ return "Unknown CredentialType value: " +
+ base::IntToString(static_cast<int>(value));
+}
+
+std::ostream& operator<<(std::ostream& os, CredentialType value) {
+ return os << CredentialTypeToString(value);
}
CredentialInfo::CredentialInfo() : type(CredentialType::CREDENTIAL_TYPE_EMPTY) {
diff --git a/chromium/components/password_manager/core/common/credential_manager_types.h b/chromium/components/password_manager/core/common/credential_manager_types.h
index 9bbb9000f6f..06e7f0096ce 100644
--- a/chromium/components/password_manager/core/common/credential_manager_types.h
+++ b/chromium/components/password_manager/core/common/credential_manager_types.h
@@ -33,6 +33,7 @@ enum class CredentialType {
CREDENTIAL_TYPE_LAST = CREDENTIAL_TYPE_FEDERATED
};
+std::string CredentialTypeToString(CredentialType value);
std::ostream& operator<<(std::ostream& os, CredentialType value);
struct CredentialInfo {
diff --git a/chromium/components/password_manager/sync/browser/BUILD.gn b/chromium/components/password_manager/sync/browser/BUILD.gn
index 6aacc170071..82acc7d277b 100644
--- a/chromium/components/password_manager/sync/browser/BUILD.gn
+++ b/chromium/components/password_manager/sync/browser/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser") {
+static_library("browser") {
sources = [
"password_data_type_controller.cc",
"password_data_type_controller.h",
@@ -24,7 +24,7 @@ source_set("browser") {
"//components/password_manager/core/common",
"//components/prefs",
"//components/signin/core/browser",
- "//components/sync_driver",
+ "//components/sync",
"//components/syncable_prefs",
"//google_apis",
"//net",
@@ -52,10 +52,10 @@ source_set("unit_tests") {
"//components/prefs",
"//components/signin/core/browser:test_support",
"//components/signin/core/common",
- "//components/sync_driver:test_support",
+ "//components/sync:test_support_sync_api",
+ "//components/sync:test_support_sync_driver",
"//components/syncable_prefs",
"//components/syncable_prefs:test_support",
- "//sync:test_support_sync_api",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/components/password_manager/sync/browser/DEPS b/chromium/components/password_manager/sync/browser/DEPS
index e57a4e1c9a1..f209e86da5d 100644
--- a/chromium/components/password_manager/sync/browser/DEPS
+++ b/chromium/components/password_manager/sync/browser/DEPS
@@ -3,8 +3,10 @@ include_rules = [
"+components/pref_registry",
"+components/signin/core/browser",
"+components/signin/core/common",
- "+components/sync_driver",
+ "+components/sync/base",
+ "+components/sync/core",
+ "+components/sync/driver",
+ "+components/sync/engine",
"+components/syncable_prefs",
"+google_apis/gaia",
- "+sync/internal_api/public",
]
diff --git a/chromium/components/password_manager/sync/browser/password_data_type_controller.cc b/chromium/components/password_manager/sync/browser/password_data_type_controller.cc
index 5ee4f0bc5d8..76db1ffce8b 100644
--- a/chromium/components/password_manager/sync/browser/password_data_type_controller.cc
+++ b/chromium/components/password_manager/sync/browser/password_data_type_controller.cc
@@ -7,26 +7,21 @@
#include "base/bind.h"
#include "base/metrics/histogram.h"
#include "components/password_manager/core/browser/password_store.h"
-#include "components/sync_driver/sync_client.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_client.h"
+#include "components/sync/driver/sync_service.h"
namespace browser_sync {
PasswordDataTypeController::PasswordDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
const base::Closure& state_changed_callback,
const scoped_refptr<password_manager::PasswordStore>& password_store)
- : NonUIDataTypeController(ui_thread, error_callback, sync_client),
+ : NonUIDataTypeController(syncer::PASSWORDS, dump_stack, sync_client),
sync_client_(sync_client),
state_changed_callback_(state_changed_callback),
password_store_(password_store) {}
-syncer::ModelType PasswordDataTypeController::type() const {
- return syncer::PASSWORDS;
-}
-
syncer::ModelSafeGroup PasswordDataTypeController::model_safe_group() const {
return syncer::GROUP_PASSWORD;
}
@@ -36,14 +31,14 @@ PasswordDataTypeController::~PasswordDataTypeController() {}
bool PasswordDataTypeController::PostTaskOnBackendThread(
const tracked_objects::Location& from_here,
const base::Closure& task) {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
if (!password_store_.get())
return false;
return password_store_->ScheduleTask(task);
}
bool PasswordDataTypeController::StartModels() {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
DCHECK_EQ(MODEL_STARTING, state());
sync_client_->GetSyncService()->AddObserver(this);
@@ -54,11 +49,12 @@ bool PasswordDataTypeController::StartModels() {
}
void PasswordDataTypeController::StopModels() {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
sync_client_->GetSyncService()->RemoveObserver(this);
}
void PasswordDataTypeController::OnStateChanged() {
+ DCHECK(CalledOnValidThread());
state_changed_callback_.Run();
}
diff --git a/chromium/components/password_manager/sync/browser/password_data_type_controller.h b/chromium/components/password_manager/sync/browser/password_data_type_controller.h
index 6205d90a757..732da941c57 100644
--- a/chromium/components/password_manager/sync/browser/password_data_type_controller.h
+++ b/chromium/components/password_manager/sync/browser/password_data_type_controller.h
@@ -8,49 +8,46 @@
#include <string>
#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "components/sync_driver/non_ui_data_type_controller.h"
-#include "components/sync_driver/sync_service_observer.h"
+#include "components/sync/driver/non_ui_data_type_controller.h"
+#include "components/sync/driver/sync_service_observer.h"
namespace password_manager {
class PasswordStore;
}
-namespace sync_driver {
+namespace syncer {
class SyncClient;
}
namespace browser_sync {
// A class that manages the startup and shutdown of password sync.
-class PasswordDataTypeController : public sync_driver::NonUIDataTypeController,
- public sync_driver::SyncServiceObserver {
+class PasswordDataTypeController : public syncer::NonUIDataTypeController,
+ public syncer::SyncServiceObserver {
public:
+ // |dump_stack| is called when an unrecoverable error occurs.
PasswordDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
const base::Closure& state_changed_callback,
const scoped_refptr<password_manager::PasswordStore>& password_store);
+ ~PasswordDataTypeController() override;
// NonFrontendDataTypeController implementation
- syncer::ModelType type() const override;
syncer::ModelSafeGroup model_safe_group() const override;
protected:
- ~PasswordDataTypeController() override;
-
// NonUIDataTypeController interface.
bool PostTaskOnBackendThread(const tracked_objects::Location& from_here,
const base::Closure& task) override;
bool StartModels() override;
void StopModels() override;
- // sync_driver::SyncServiceObserver:
+ // syncer::SyncServiceObserver:
void OnStateChanged() override;
private:
- sync_driver::SyncClient* const sync_client_;
+ syncer::SyncClient* const sync_client_;
const base::Closure state_changed_callback_;
scoped_refptr<password_manager::PasswordStore> password_store_;
diff --git a/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service.cc b/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service.cc
index 091f2168cd0..4885215c3dd 100644
--- a/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service.cc
+++ b/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service.cc
@@ -10,7 +10,7 @@
#include "build/build_config.h"
#include "components/password_manager/core/browser/password_manager_settings_migration_experiment.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_service.h"
#include "components/syncable_prefs/pref_service_syncable.h"
namespace {
@@ -97,7 +97,7 @@ PasswordManagerSettingMigratorService::
~PasswordManagerSettingMigratorService() {}
void PasswordManagerSettingMigratorService::InitializeMigration(
- sync_driver::SyncService* sync_service) {
+ syncer::SyncService* sync_service) {
if (force_disabled_for_testing_)
return;
SaveCurrentPrefState(prefs_, &initial_new_pref_value_,
diff --git a/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service.h b/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service.h
index 4f35a064160..14d35ce0680 100644
--- a/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service.h
+++ b/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_MANAGER_SETTING_MIGRATOR_SERVICE_H_
#define COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_MANAGER_SETTING_MIGRATOR_SERVICE_H_
+#include <string>
#include <vector>
#include "base/macros.h"
@@ -13,7 +14,7 @@
#include "components/prefs/pref_change_registrar.h"
#include "components/syncable_prefs/pref_service_syncable_observer.h"
-namespace sync_driver {
+namespace syncer {
class SyncService;
}
@@ -87,7 +88,7 @@ class PasswordManagerSettingMigratorService
// PrefServiceSyncableObserver:
void OnIsSyncingChanged() override;
- void InitializeMigration(sync_driver::SyncService* sync_service);
+ void InitializeMigration(syncer::SyncService* sync_service);
// Only use for testing.
static void set_force_disabled_for_testing(bool force_disabled) {
@@ -147,7 +148,7 @@ class PasswordManagerSettingMigratorService
bool initial_legacy_pref_value_;
syncable_prefs::PrefServiceSyncable* prefs_;
- sync_driver::SyncService* sync_service_;
+ syncer::SyncService* sync_service_;
PrefChangeRegistrar pref_change_registrar_;
diff --git a/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc b/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc
index c91203223d9..a844b7d7839 100644
--- a/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc
+++ b/chromium/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc
@@ -13,15 +13,15 @@
#include "components/password_manager/sync/browser/password_manager_setting_migrator_service.h"
#include "components/pref_registry/testing_pref_service_syncable.h"
#include "components/prefs/pref_service.h"
-#include "components/sync_driver/fake_sync_service.h"
+#include "components/sync/api/fake_sync_change_processor.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/api/sync_error_factory_mock.h"
+#include "components/sync/core/attachments/attachment_service_proxy_for_test.h"
+#include "components/sync/driver/fake_sync_service.h"
+#include "components/sync/protocol/sync.pb.h"
#include "components/syncable_prefs/pref_model_associator_client.h"
#include "components/syncable_prefs/pref_service_mock_factory.h"
#include "components/syncable_prefs/pref_service_syncable.h"
-#include "sync/api/fake_sync_change_processor.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/api/sync_error_factory_mock.h"
-#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
-#include "sync/protocol/sync.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -123,7 +123,7 @@ void StartSyncingPref(syncable_prefs::PrefServiceSyncable* prefs,
new syncer::SyncErrorFactoryMock));
}
-class SyncServiceMock : public sync_driver::FakeSyncService {
+class SyncServiceMock : public syncer::FakeSyncService {
public:
bool IsFirstSetupComplete() const override { return true; }
diff --git a/chromium/components/password_manager/sync/browser/password_model_worker.h b/chromium/components/password_manager/sync/browser/password_model_worker.h
index 5a721d56641..996f5bb9cb1 100644
--- a/chromium/components/password_manager/sync/browser/password_model_worker.h
+++ b/chromium/components/password_manager/sync/browser/password_model_worker.h
@@ -9,7 +9,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "sync/internal_api/public/engine/model_safe_worker.h"
+#include "components/sync/engine/model_safe_worker.h"
namespace base {
class WaitableEvent;
diff --git a/chromium/components/password_manager/sync/browser/password_sync_util.cc b/chromium/components/password_manager/sync/browser/password_sync_util.cc
index 19292c5811c..34841d40fea 100644
--- a/chromium/components/password_manager/sync/browser/password_sync_util.cc
+++ b/chromium/components/password_manager/sync/browser/password_sync_util.cc
@@ -17,7 +17,7 @@ namespace password_manager {
namespace sync_util {
std::string GetSyncUsernameIfSyncingPasswords(
- const sync_driver::SyncService* sync_service,
+ const syncer::SyncService* sync_service,
const SigninManagerBase* signin_manager) {
if (!signin_manager)
return std::string();
@@ -32,13 +32,19 @@ std::string GetSyncUsernameIfSyncingPasswords(
}
bool IsSyncAccountCredential(const autofill::PasswordForm& form,
- const sync_driver::SyncService* sync_service,
+ const syncer::SyncService* sync_service,
const SigninManagerBase* signin_manager) {
const Origin gaia_origin(GaiaUrls::GetInstance()->gaia_url().GetOrigin());
if (!Origin(GURL(form.signon_realm)).IsSameOriginWith(gaia_origin)) {
return false;
}
+ // The empty username can mean that Chrome did not detect it correctly. For
+ // reasons described in http://crbug.com/636292#c1, the username is suspected
+ // to be the sync username unless proven otherwise.
+ if (form.username_value.empty())
+ return true;
+
return gaia::AreEmailsSame(
base::UTF16ToUTF8(form.username_value),
GetSyncUsernameIfSyncingPasswords(sync_service, signin_manager));
diff --git a/chromium/components/password_manager/sync/browser/password_sync_util.h b/chromium/components/password_manager/sync/browser/password_sync_util.h
index 6123e401498..3a60b3b75e6 100644
--- a/chromium/components/password_manager/sync/browser/password_sync_util.h
+++ b/chromium/components/password_manager/sync/browser/password_sync_util.h
@@ -9,7 +9,7 @@
#include "components/autofill/core/common/password_form.h"
#include "components/signin/core/browser/signin_manager.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_service.h"
namespace password_manager {
namespace sync_util {
@@ -20,14 +20,14 @@ namespace sync_util {
// always possible to determine since this code can be called during sync setup
// (http://crbug.com/393626).
std::string GetSyncUsernameIfSyncingPasswords(
- const sync_driver::SyncService* sync_service,
+ const syncer::SyncService* sync_service,
const SigninManagerBase* signin_manager);
// Returns true if |form| corresponds to the account specified by
// GetSyncUsernameIfSyncingPasswords. Returns false if
// GetSyncUsernameIfSyncingPasswords does not specify any account.
bool IsSyncAccountCredential(const autofill::PasswordForm& form,
- const sync_driver::SyncService* sync_service,
+ const syncer::SyncService* sync_service,
const SigninManagerBase* signin_manager);
} // namespace sync_util
diff --git a/chromium/components/password_manager/sync/browser/password_sync_util_unittest.cc b/chromium/components/password_manager/sync/browser/password_sync_util_unittest.cc
index d1bfc448677..8d4254a13d5 100644
--- a/chromium/components/password_manager/sync/browser/password_sync_util_unittest.cc
+++ b/chromium/components/password_manager/sync/browser/password_sync_util_unittest.cc
@@ -23,7 +23,7 @@ TEST_F(PasswordSyncUtilTest, GetSyncUsernameIfSyncingPasswords) {
enum { SYNCING_PASSWORDS, NOT_SYNCING_PASSWORDS } password_sync;
std::string fake_sync_username;
std::string expected_result;
- const sync_driver::SyncService* sync_service;
+ const syncer::SyncService* sync_service;
const SigninManagerBase* signin_manager;
} kTestCases[] = {
{TestCase::NOT_SYNCING_PASSWORDS, "a@example.org", std::string(),
@@ -66,6 +66,8 @@ TEST_F(PasswordSyncUtilTest, IsSyncAccountCredential) {
false},
{SimpleNonGaiaForm("sync_user@example.org"), "sync_user@example.org",
false},
+ {SimpleGaiaForm(""), "sync_user@example.org", true},
+ {SimpleNonGaiaForm(""), "sync_user@example.org", false},
};
for (size_t i = 0; i < arraysize(kTestCases); ++i) {
diff --git a/chromium/components/password_manager/sync/browser/sync_credentials_filter.cc b/chromium/components/password_manager/sync/browser/sync_credentials_filter.cc
index 5632331d963..7a1d01e5f9c 100644
--- a/chromium/components/password_manager/sync/browser/sync_credentials_filter.cc
+++ b/chromium/components/password_manager/sync/browser/sync_credentials_filter.cc
@@ -10,6 +10,7 @@
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
+#include "components/password_manager/core/browser/password_form_manager.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/sync/browser/password_sync_util.h"
@@ -48,8 +49,8 @@ SyncCredentialsFilter::SyncCredentialsFilter(
SyncCredentialsFilter::~SyncCredentialsFilter() {}
-ScopedVector<PasswordForm> SyncCredentialsFilter::FilterResults(
- ScopedVector<PasswordForm> results) const {
+std::vector<std::unique_ptr<PasswordForm>> SyncCredentialsFilter::FilterResults(
+ std::vector<std::unique_ptr<PasswordForm>> results) const {
const AutofillForSyncCredentialsState autofill_sync_state =
GetAutofillForSyncCredentialsState();
@@ -62,7 +63,9 @@ ScopedVector<PasswordForm> SyncCredentialsFilter::FilterResults(
auto begin_of_removed =
std::partition(results.begin(), results.end(),
- [this](PasswordForm* form) { return ShouldSave(*form); });
+ [this](const std::unique_ptr<PasswordForm>& form) {
+ return ShouldSave(*form);
+ });
UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered",
begin_of_removed != results.end());
@@ -79,10 +82,16 @@ bool SyncCredentialsFilter::ShouldSave(
signin_manager_factory_function_.Run());
}
-void SyncCredentialsFilter::ReportFormUsed(
- const autofill::PasswordForm& form) const {
- base::RecordAction(
- base::UserMetricsAction("PasswordManager_SyncCredentialUsed"));
+void SyncCredentialsFilter::ReportFormLoginSuccess(
+ const PasswordFormManager& form_manager) const {
+ if (!form_manager.IsNewLogin() &&
+ sync_util::IsSyncAccountCredential(
+ form_manager.pending_credentials(),
+ sync_service_factory_function_.Run(),
+ signin_manager_factory_function_.Run())) {
+ base::RecordAction(base::UserMetricsAction(
+ "PasswordManager_SyncCredentialFilledAndLoginSuccessfull"));
+ }
}
// static
diff --git a/chromium/components/password_manager/sync/browser/sync_credentials_filter.h b/chromium/components/password_manager/sync/browser/sync_credentials_filter.h
index 019a28c2c31..ecabd5e0ae4 100644
--- a/chromium/components/password_manager/sync/browser/sync_credentials_filter.h
+++ b/chromium/components/password_manager/sync/browser/sync_credentials_filter.h
@@ -5,7 +5,9 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_SYNC_CREDENTIALS_FILTER_H_
#define COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_SYNC_CREDENTIALS_FILTER_H_
+#include <memory>
#include <string>
+#include <vector>
#include "base/callback.h"
#include "base/macros.h"
@@ -13,14 +15,14 @@
#include "components/password_manager/core/browser/credentials_filter.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/signin/core/browser/signin_manager.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_service.h"
namespace password_manager {
// The sync- and GAIA- aware implementation of the filter.
class SyncCredentialsFilter : public CredentialsFilter {
public:
- typedef base::Callback<const sync_driver::SyncService*(void)>
+ typedef base::Callback<const syncer::SyncService*(void)>
SyncServiceFactoryFunction;
typedef base::Callback<const SigninManagerBase*(void)>
SigninManagerFactoryFunction;
@@ -38,10 +40,12 @@ class SyncCredentialsFilter : public CredentialsFilter {
~SyncCredentialsFilter() override;
// CredentialsFilter
- ScopedVector<autofill::PasswordForm> FilterResults(
- ScopedVector<autofill::PasswordForm> results) const override;
+ std::vector<std::unique_ptr<autofill::PasswordForm>> FilterResults(
+ std::vector<std::unique_ptr<autofill::PasswordForm>> results)
+ const override;
bool ShouldSave(const autofill::PasswordForm& form) const override;
- void ReportFormUsed(const autofill::PasswordForm& form) const override;
+ void ReportFormLoginSuccess(
+ const PasswordFormManager& form_manager) const override;
private:
enum AutofillForSyncCredentialsState {
diff --git a/chromium/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc b/chromium/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
index 843fde9d528..bb43bdc65df 100644
--- a/chromium/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
+++ b/chromium/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
@@ -5,19 +5,30 @@
#include "components/password_manager/sync/browser/sync_credentials_filter.h"
#include <stddef.h>
+
+#include <memory>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
#include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/user_action_tester.h"
#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/mock_password_store.h"
+#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "components/password_manager/core/browser/stub_form_saver.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "components/password_manager/core/browser/stub_password_manager_driver.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/sync/browser/sync_username_test_base.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using autofill::PasswordForm;
@@ -26,25 +37,41 @@ namespace password_manager {
namespace {
+const char kFilledAndLoginActionName[] =
+ "PasswordManager_SyncCredentialFilledAndLoginSuccessfull";
+
class FakePasswordManagerClient : public StubPasswordManagerClient {
public:
- ~FakePasswordManagerClient() override {}
+ FakePasswordManagerClient()
+ : password_store_(new testing::NiceMock<MockPasswordStore>) {}
+
+ ~FakePasswordManagerClient() override {
+ password_store_->ShutdownOnUIThread();
+ }
// PasswordManagerClient:
const GURL& GetLastCommittedEntryURL() const override {
return last_committed_entry_url_;
}
+ MockPasswordStore* GetPasswordStore() const override {
+ return password_store_.get();
+ }
void set_last_committed_entry_url(const char* url_spec) {
last_committed_entry_url_ = GURL(url_spec);
}
+ private:
+ base::MessageLoop message_loop_; // For |password_store_|.
GURL last_committed_entry_url_;
+ scoped_refptr<testing::NiceMock<MockPasswordStore>> password_store_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakePasswordManagerClient);
};
bool IsFormFiltered(const CredentialsFilter* filter, const PasswordForm& form) {
- ScopedVector<PasswordForm> vector;
- vector.push_back(new PasswordForm(form));
+ std::vector<std::unique_ptr<PasswordForm>> vector;
+ vector.push_back(base::MakeUnique<PasswordForm>(form));
vector = filter->FilterResults(std::move(vector));
return vector.empty();
}
@@ -62,8 +89,12 @@ class CredentialsFilterTest : public SyncUsernameTestBase {
enum { NO_HISTOGRAM, HISTOGRAM_REPORTED } histogram_reported;
};
+ // Flag for creating a PasswordFormManager, deciding its IsNewLogin() value.
+ enum class LoginState { NEW, EXISTING };
+
CredentialsFilterTest()
- : filter_(&client_,
+ : password_manager_(&client_),
+ filter_(&client_,
base::Bind(&SyncUsernameTestBase::sync_service,
base::Unretained(this)),
base::Bind(&SyncUsernameTestBase::signin_manager,
@@ -87,12 +118,36 @@ class CredentialsFilterTest : public SyncUsernameTestBase {
FakeSignout();
}
+ // Creates a PasswordFormManager for the |pending| form and provisionally
+ // saves it. Ensures that the created manager's IsNewLogin responds according
+ // to |login_state|.
+ std::unique_ptr<PasswordFormManager> CreateFormManager(
+ LoginState login_state,
+ const PasswordForm& pending) {
+ auto form_manager = base::MakeUnique<PasswordFormManager>(
+ &password_manager_, &client_, driver_.AsWeakPtr(), pending,
+ base::MakeUnique<StubFormSaver>());
+
+ std::vector<std::unique_ptr<PasswordForm>> saved_forms;
+ if (login_state == LoginState::EXISTING) {
+ saved_forms.push_back(base::MakeUnique<PasswordForm>(pending));
+ }
+ form_manager->OnGetPasswordStoreResults(std::move(saved_forms));
+
+ form_manager->ProvisionallySave(
+ pending, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+
+ return form_manager;
+ }
+
SyncCredentialsFilter* filter() { return &filter_; }
FakePasswordManagerClient* client() { return &client_; }
private:
FakePasswordManagerClient client_;
+ PasswordManager password_manager_;
+ StubPasswordManagerDriver driver_;
SyncCredentialsFilter filter_;
};
@@ -138,12 +193,10 @@ TEST_F(CredentialsFilterTest, FilterResults_AllowAll) {
TEST_F(CredentialsFilterTest, FilterResults_DisallowSyncOnReauth) {
// Only 'protect-sync-credential-on-reauth' feature is kept enabled, fill the
// sync credential everywhere but on reauth.
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- std::vector<const base::Feature*> enabled_features;
- std::vector<const base::Feature*> disabled_features;
- disabled_features.push_back(&features::kProtectSyncCredential);
- enabled_features.push_back(&features::kProtectSyncCredentialOnReauth);
- SetFeatures(enabled_features, disabled_features, std::move(feature_list));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(
+ features::kProtectSyncCredentialOnReauth.name,
+ features::kProtectSyncCredential.name);
const TestCase kTestCases[] = {
// Reauth URL, not sync username.
@@ -184,12 +237,11 @@ TEST_F(CredentialsFilterTest, FilterResults_DisallowSyncOnReauth) {
TEST_F(CredentialsFilterTest, FilterResults_DisallowSync) {
// Both features are kept enabled, should cause sync credential to be
// filtered.
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- std::vector<const base::Feature*> enabled_features;
- std::vector<const base::Feature*> disabled_features;
- enabled_features.push_back(&features::kProtectSyncCredential);
- enabled_features.push_back(&features::kProtectSyncCredentialOnReauth);
- SetFeatures(enabled_features, disabled_features, std::move(feature_list));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(
+ features::kProtectSyncCredential.name + std::string(",") +
+ features::kProtectSyncCredentialOnReauth.name,
+ std::string());
const TestCase kTestCases[] = {
// Reauth URL, not sync username.
@@ -227,11 +279,59 @@ TEST_F(CredentialsFilterTest, FilterResults_DisallowSync) {
}
}
-TEST_F(CredentialsFilterTest, ReportFormUsed) {
+TEST_F(CredentialsFilterTest, ReportFormLoginSuccess_ExistingSyncCredentials) {
+ PasswordForm pending = SimpleGaiaForm("user@gmail.com");
+ FakeSigninAs("user@gmail.com");
+ SetSyncingPasswords(true);
+
+ base::UserActionTester tester;
+ auto form_manager = CreateFormManager(LoginState::EXISTING, pending);
+ filter()->ReportFormLoginSuccess(*form_manager);
+ EXPECT_EQ(1, tester.GetActionCount(kFilledAndLoginActionName));
+}
+
+TEST_F(CredentialsFilterTest, ReportFormLoginSuccess_NewSyncCredentials) {
+ PasswordForm pending = SimpleGaiaForm("user@gmail.com");
+ FakeSigninAs("user@gmail.com");
+ SetSyncingPasswords(true);
+
+ base::UserActionTester tester;
+ auto form_manager = CreateFormManager(LoginState::NEW, pending);
+ filter()->ReportFormLoginSuccess(*form_manager);
+ EXPECT_EQ(0, tester.GetActionCount(kFilledAndLoginActionName));
+}
+
+TEST_F(CredentialsFilterTest, ReportFormLoginSuccess_GAIANotSyncCredentials) {
+ PasswordForm pending = SimpleGaiaForm("user@gmail.com");
+ FakeSigninAs("other_user@gmail.com");
+ SetSyncingPasswords(true);
+
+ base::UserActionTester tester;
+ auto form_manager = CreateFormManager(LoginState::EXISTING, pending);
+ filter()->ReportFormLoginSuccess(*form_manager);
+ EXPECT_EQ(0, tester.GetActionCount(kFilledAndLoginActionName));
+}
+
+TEST_F(CredentialsFilterTest, ReportFormLoginSuccess_NotGAIACredentials) {
+ PasswordForm pending = SimpleNonGaiaForm("user@gmail.com");
+ FakeSigninAs("user@gmail.com");
+ SetSyncingPasswords(true);
+
+ base::UserActionTester tester;
+ auto form_manager = CreateFormManager(LoginState::EXISTING, pending);
+ filter()->ReportFormLoginSuccess(*form_manager);
+ EXPECT_EQ(0, tester.GetActionCount(kFilledAndLoginActionName));
+}
+
+TEST_F(CredentialsFilterTest, ReportFormLoginSuccess_NotSyncing) {
+ PasswordForm pending = SimpleGaiaForm("user@gmail.com");
+ FakeSigninAs("user@gmail.com");
+ SetSyncingPasswords(false);
+
base::UserActionTester tester;
- ASSERT_EQ(0, tester.GetActionCount("PasswordManager_SyncCredentialUsed"));
- filter()->ReportFormUsed(PasswordForm());
- EXPECT_EQ(1, tester.GetActionCount("PasswordManager_SyncCredentialUsed"));
+ auto form_manager = CreateFormManager(LoginState::EXISTING, pending);
+ filter()->ReportFormLoginSuccess(*form_manager);
+ EXPECT_EQ(0, tester.GetActionCount(kFilledAndLoginActionName));
}
TEST_F(CredentialsFilterTest, ShouldSave_NotSyncCredential) {
@@ -262,16 +362,17 @@ TEST_F(CredentialsFilterTest, ShouldSave_SyncCredential_NotSyncingPasswords) {
TEST_F(CredentialsFilterTest, ShouldFilterOneForm) {
// Both features are kept enabled, should cause sync credential to be
// filtered.
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- std::vector<const base::Feature*> enabled_features;
- std::vector<const base::Feature*> disabled_features;
- enabled_features.push_back(&features::kProtectSyncCredential);
- enabled_features.push_back(&features::kProtectSyncCredentialOnReauth);
- SetFeatures(enabled_features, disabled_features, std::move(feature_list));
-
- ScopedVector<autofill::PasswordForm> results;
- results.push_back(new PasswordForm(SimpleGaiaForm("test1@gmail.com")));
- results.push_back(new PasswordForm(SimpleGaiaForm("test2@gmail.com")));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(
+ features::kProtectSyncCredential.name + std::string(",") +
+ features::kProtectSyncCredentialOnReauth.name,
+ std::string());
+
+ std::vector<std::unique_ptr<PasswordForm>> results;
+ results.push_back(
+ base::MakeUnique<PasswordForm>(SimpleGaiaForm("test1@gmail.com")));
+ results.push_back(
+ base::MakeUnique<PasswordForm>(SimpleGaiaForm("test2@gmail.com")));
FakeSigninAs("test1@gmail.com");
diff --git a/chromium/components/password_manager/sync/browser/sync_username_test_base.h b/chromium/components/password_manager/sync/browser/sync_username_test_base.h
index b039b1dd825..6c5835c8f54 100644
--- a/chromium/components/password_manager/sync/browser/sync_username_test_base.h
+++ b/chromium/components/password_manager/sync/browser/sync_username_test_base.h
@@ -8,13 +8,15 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_SYNC_USERNAME_TEST_BASE_H_
#define COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_SYNC_USERNAME_TEST_BASE_H_
+#include <string>
+
#include "components/autofill/core/common/password_form.h"
#include "components/pref_registry/testing_pref_service_syncable.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/signin_manager_base.h"
#include "components/signin/core/browser/test_signin_client.h"
-#include "components/sync_driver/fake_sync_service.h"
-#include "sync/internal_api/public/base/model_type.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/driver/fake_sync_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace password_manager {
@@ -36,19 +38,17 @@ class SyncUsernameTestBase : public testing::Test {
// passwords.
void SetSyncingPasswords(bool syncing_passwords);
- const sync_driver::SyncService* sync_service() const {
- return &sync_service_;
- }
+ const syncer::SyncService* sync_service() const { return &sync_service_; }
const SigninManagerBase* signin_manager() { return &signin_manager_; }
private:
- class LocalFakeSyncService : public sync_driver::FakeSyncService {
+ class LocalFakeSyncService : public syncer::FakeSyncService {
public:
LocalFakeSyncService();
~LocalFakeSyncService() override;
- // sync_driver::SyncService:
+ // syncer::SyncService:
syncer::ModelTypeSet GetPreferredDataTypes() const override;
void set_syncing_passwords(bool syncing_passwords) {
diff --git a/chromium/components/pdf.gypi b/chromium/components/pdf.gypi
deleted file mode 100644
index 89c126d724a..00000000000
--- a/chromium/components/pdf.gypi
+++ /dev/null
@@ -1,66 +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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [{
- 'target_name': 'pdf_common',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/content/content.gyp:content_common',
- '<(DEPTH)/ipc/ipc.gyp:ipc',
- '<(DEPTH)/url/url.gyp:url_lib',
- '<(DEPTH)/url/ipc/url_ipc.gyp:url_ipc',
- ],
- 'sources': [
- 'pdf/common/pdf_message_generator.cc',
- 'pdf/common/pdf_message_generator.h',
- 'pdf/common/pdf_messages.h',
- ],
- }, {
- 'target_name': 'pdf_browser',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/content/content.gyp:content_browser',
- 'pdf_common',
- ],
- 'sources': [
- 'pdf/browser/open_pdf_in_reader_prompt_client.h',
- 'pdf/browser/pdf_web_contents_helper.cc',
- 'pdf/browser/pdf_web_contents_helper.h',
- 'pdf/browser/pdf_web_contents_helper_client.h',
- ],
- }, {
- 'target_name': 'pdf_renderer',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/content/content.gyp:content_renderer',
- '<(DEPTH)/gin/gin.gyp:gin',
- '<(DEPTH)/ppapi/ppapi_internal.gyp:ppapi_shared',
- '<(DEPTH)/third_party/icu/icu.gyp:icuuc',
- '<(DEPTH)/third_party/icu/icu.gyp:icui18n',
- '<(DEPTH)/v8/src/v8.gyp:v8',
- '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- 'pdf_common',
- ],
- 'sources': [
- 'pdf/renderer/pdf_accessibility_tree.cc',
- 'pdf/renderer/pdf_accessibility_tree.h',
- 'pdf/renderer/pepper_pdf_host.cc',
- 'pdf/renderer/pepper_pdf_host.h',
- ],
- 'conditions': [
- ['OS=="win"', {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- ],
- ],
- }],
-}
diff --git a/chromium/components/pdf/browser/pdf_web_contents_helper.cc b/chromium/components/pdf/browser/pdf_web_contents_helper.cc
index c3f7db4a13e..ae931d4eae7 100644
--- a/chromium/components/pdf/browser/pdf_web_contents_helper.cc
+++ b/chromium/components/pdf/browser/pdf_web_contents_helper.cc
@@ -41,7 +41,9 @@ void PDFWebContentsHelper::ShowOpenInReaderPrompt(
UpdateLocationBar();
}
-bool PDFWebContentsHelper::OnMessageReceived(const IPC::Message& message) {
+bool PDFWebContentsHelper::OnMessageReceived(
+ const IPC::Message& message,
+ content::RenderFrameHost* render_frame_host) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PDFWebContentsHelper, message)
IPC_MESSAGE_HANDLER(PDFHostMsg_PDFHasUnsupportedFeature,
diff --git a/chromium/components/pdf/browser/pdf_web_contents_helper.h b/chromium/components/pdf/browser/pdf_web_contents_helper.h
index c8b7a7820da..85d7d02a396 100644
--- a/chromium/components/pdf/browser/pdf_web_contents_helper.h
+++ b/chromium/components/pdf/browser/pdf_web_contents_helper.h
@@ -45,7 +45,8 @@ class PDFWebContentsHelper
~PDFWebContentsHelper() override;
// content::WebContentsObserver overrides:
- bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message,
+ content::RenderFrameHost* render_frame_host) override;
void DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) override;
diff --git a/chromium/components/pdf/renderer/pdf_accessibility_tree.cc b/chromium/components/pdf/renderer/pdf_accessibility_tree.cc
index 276168f2ce2..28170905257 100644
--- a/chromium/components/pdf/renderer/pdf_accessibility_tree.cc
+++ b/chromium/components/pdf/renderer/pdf_accessibility_tree.cc
@@ -11,9 +11,11 @@
#include "content/public/renderer/render_accessibility.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
+#include "content/public/renderer/renderer_ppapi_host.h"
#include "grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/transform.h"
namespace pdf {
@@ -42,12 +44,11 @@ gfx::RectF ToGfxRectF(const PP_FloatRect& r) {
}
PdfAccessibilityTree::PdfAccessibilityTree(
- content::RenderView* render_view)
- : render_view_(render_view),
- render_accessibility_(nullptr),
+ content::RendererPpapiHost* host,
+ PP_Instance instance)
+ : host_(host),
+ instance_(instance),
zoom_(1.0) {
- content::RenderFrame* render_frame = render_view->GetMainRenderFrame();
- render_accessibility_ = render_frame->GetRenderAccessibility();
}
PdfAccessibilityTree::~PdfAccessibilityTree() {
@@ -61,18 +62,40 @@ void PdfAccessibilityTree::SetAccessibilityViewportInfo(
scroll_.Scale(1.0 / zoom_);
offset_ = ToVector2dF(viewport_info.offset);
offset_.Scale(1.0 / zoom_);
+
+ content::RenderAccessibility* render_accessibility = GetRenderAccessibility();
+ if (render_accessibility && tree_.size() > 1) {
+ ui::AXNode* root = tree_.root();
+ ui::AXNodeData root_data = root->data();
+ root_data.transform = base::WrapUnique(MakeTransformFromViewInfo());
+ root->SetData(root_data);
+ render_accessibility->OnPluginRootNodeUpdated();
+ }
}
void PdfAccessibilityTree::SetAccessibilityDocInfo(
const PP_PrivateAccessibilityDocInfo& doc_info) {
+ if (!GetRenderAccessibility())
+ return;
+
doc_info_ = doc_info;
doc_node_ = CreateNode(ui::AX_ROLE_GROUP);
+
+ // Because all of the coordinates are expressed relative to the
+ // doc's coordinates, the origin of the doc must be (0, 0). Its
+ // width and height will be updated as we add each page so that the
+ // doc's bounding box surrounds all pages.
+ doc_node_->location = gfx::RectF(0, 0, 1, 1);
}
void PdfAccessibilityTree::SetAccessibilityPageInfo(
const PP_PrivateAccessibilityPageInfo& page_info,
const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs,
const std::vector<PP_PrivateAccessibilityCharInfo>& chars) {
+ content::RenderAccessibility* render_accessibility = GetRenderAccessibility();
+ if (!render_accessibility)
+ return;
+
uint32_t page_index = page_info.page_index;
CHECK_GE(page_index, 0U);
CHECK_LT(page_index, doc_info_.page_count);
@@ -84,10 +107,7 @@ void PdfAccessibilityTree::SetAccessibilityPageInfo(
IDS_PDF_PAGE_INDEX, page_index + 1));
gfx::RectF page_bounds = ToRectF(page_info.bounds);
- page_bounds += offset_;
- page_bounds -= scroll_;
- page_bounds.Scale(zoom_ / GetDeviceScaleFactor());
- page_node->location = gfx::ToEnclosingRect(page_bounds);
+ page_node->location = page_bounds;
doc_node_->location.Union(page_node->location);
doc_node_->child_ids.push_back(page_node->id);
@@ -119,6 +139,7 @@ void PdfAccessibilityTree::SetAccessibilityPageInfo(
text_run.font_size > heading_font_size_threshold) {
para_node->role = ui::AX_ROLE_HEADING;
para_node->AddIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL, 2);
+ para_node->AddStringAttribute(ui::AX_ATTR_HTML_TAG, "h2");
}
// This node is for the text inside the paragraph, it includes
@@ -134,9 +155,8 @@ void PdfAccessibilityTree::SetAccessibilityPageInfo(
inline_text_box_node->AddStringAttribute(ui::AX_ATTR_NAME, chars_utf8);
gfx::RectF text_run_bounds = ToGfxRectF(text_run.bounds);
- text_run_bounds.Scale(zoom_ / GetDeviceScaleFactor());
text_run_bounds += page_bounds.OffsetFromOrigin();
- inline_text_box_node->location = gfx::ToEnclosingRect(text_run_bounds);
+ inline_text_box_node->location = text_run_bounds;
inline_text_box_node->AddIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS,
char_offsets);
@@ -165,13 +185,17 @@ void PdfAccessibilityTree::SetAccessibilityPageInfo(
}
void PdfAccessibilityTree::Finish() {
+ doc_node_->transform = base::WrapUnique(MakeTransformFromViewInfo());
+
ui::AXTreeUpdate update;
update.root_id = doc_node_->id;
for (const auto& node : nodes_)
update.nodes.push_back(*node);
CHECK(tree_.Unserialize(update)) << update.ToString() << tree_.error();
- render_accessibility_->SetPdfTreeSource(this);
+ content::RenderAccessibility* render_accessibility = GetRenderAccessibility();
+ if (render_accessibility)
+ render_accessibility->SetPluginTreeSource(this);
}
void PdfAccessibilityTree::ComputeParagraphAndHeadingThresholds(
@@ -231,7 +255,7 @@ std::vector<int32_t> PdfAccessibilityTree::GetTextRunCharOffsets(
double offset = 0.0;
for (uint32_t j = 0; j < text_run.len; ++j) {
offset += chars[char_index + j].char_width;
- char_offsets[j] = floor(offset * zoom_ / GetDeviceScaleFactor());
+ char_offsets[j] = floor(offset);
}
return char_offsets;
}
@@ -245,16 +269,44 @@ gfx::RectF PdfAccessibilityTree::ToRectF(const PP_Rect& r) {
}
ui::AXNodeData* PdfAccessibilityTree::CreateNode(ui::AXRole role) {
+ content::RenderAccessibility* render_accessibility = GetRenderAccessibility();
+ DCHECK(render_accessibility);
+
ui::AXNodeData* node = new ui::AXNodeData();
- node->id = render_accessibility_->GenerateAXID();
+ node->id = render_accessibility->GenerateAXID();
node->role = role;
- node->state = 1 << ui::AX_STATE_ENABLED | 1 << ui::AX_STATE_READ_ONLY;
+ node->state = 1 << ui::AX_STATE_READ_ONLY;
+
+ // All nodes other than the first one have coordinates relative to
+ // the first node.
+ if (nodes_.size() > 0)
+ node->offset_container_id = nodes_[0]->id;
+
nodes_.push_back(base::WrapUnique(node));
+
return node;
}
float PdfAccessibilityTree::GetDeviceScaleFactor() const {
- return render_view_->GetDeviceScaleFactor();
+ content::RenderFrame* render_frame =
+ host_->GetRenderFrameForInstance(instance_);
+ DCHECK(render_frame);
+ return render_frame->GetRenderView()->GetDeviceScaleFactor();
+}
+
+content::RenderAccessibility* PdfAccessibilityTree::GetRenderAccessibility() {
+ content::RenderFrame* render_frame =
+ host_->GetRenderFrameForInstance(instance_);
+ return render_frame ? render_frame->GetRenderAccessibility() : nullptr;
+}
+
+gfx::Transform* PdfAccessibilityTree::MakeTransformFromViewInfo() {
+ gfx::Transform* transform = new gfx::Transform();
+ float scale_factor = zoom_ / GetDeviceScaleFactor();
+ transform->Scale(scale_factor, scale_factor);
+ transform->Translate(offset_);
+ transform->Translate(-scroll_);
+ return transform;
}
//
diff --git a/chromium/components/pdf/renderer/pdf_accessibility_tree.h b/chromium/components/pdf/renderer/pdf_accessibility_tree.h
index c0673dcaf3a..954b7d928a8 100644
--- a/chromium/components/pdf/renderer/pdf_accessibility_tree.h
+++ b/chromium/components/pdf/renderer/pdf_accessibility_tree.h
@@ -18,9 +18,14 @@
namespace content {
class RenderAccessibility;
-class RenderView;
+class RenderFrame;
+class RendererPpapiHost;
}
+namespace gfx {
+class Transform;
+};
+
namespace pdf {
class PdfAccessibilityTree
@@ -28,7 +33,8 @@ class PdfAccessibilityTree
ui::AXNodeData,
ui::AXTreeData> {
public:
- explicit PdfAccessibilityTree(content::RenderView* render_view);
+ PdfAccessibilityTree(content::RendererPpapiHost* host,
+ PP_Instance instance);
~PdfAccessibilityTree() override;
void SetAccessibilityViewportInfo(
@@ -73,10 +79,12 @@ class PdfAccessibilityTree
gfx::RectF ToRectF(const PP_Rect& r);
ui::AXNodeData* CreateNode(ui::AXRole role);
float GetDeviceScaleFactor() const;
+ content::RenderAccessibility* GetRenderAccessibility();
+ gfx::Transform* MakeTransformFromViewInfo();
ui::AXTree tree_;
- content::RenderView* render_view_;
- content::RenderAccessibility* render_accessibility_;
+ content::RendererPpapiHost* host_;
+ PP_Instance instance_;
double zoom_;
gfx::Vector2dF scroll_;
gfx::Vector2dF offset_;
diff --git a/chromium/components/pdf/renderer/pepper_pdf_host.cc b/chromium/components/pdf/renderer/pepper_pdf_host.cc
index ab9418b33db..c56d78e97ca 100644
--- a/chromium/components/pdf/renderer/pepper_pdf_host.cc
+++ b/chromium/components/pdf/renderer/pepper_pdf_host.cc
@@ -4,13 +4,13 @@
#include "components/pdf/renderer/pepper_pdf_host.h"
+#include "base/memory/ptr_util.h"
#include "components/pdf/common/pdf_messages.h"
#include "components/pdf/renderer/pdf_accessibility_tree.h"
#include "content/public/common/referrer.h"
#include "content/public/renderer/pepper_plugin_instance.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
-#include "content/public/renderer/render_view.h"
#include "content/public/renderer/renderer_ppapi_host.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/host_message_context.h"
@@ -30,6 +30,7 @@
namespace pdf {
namespace {
+
// --single-process model may fail in CHECK(!g_print_client) if there exist
// more than two RenderThreads, so here we use TLS for g_print_client.
// See http://crbug.com/457580.
@@ -96,33 +97,33 @@ int32_t PepperPDFHost::OnResourceMessageReceived(
int32_t PepperPDFHost::OnHostMsgDidStartLoading(
ppapi::host::HostMessageContext* context) {
- content::PepperPluginInstance* instance =
- host_->GetPluginInstance(pp_instance());
- if (!instance)
+ content::RenderFrame* render_frame = GetRenderFrame();
+ if (!render_frame)
return PP_ERROR_FAILED;
- instance->GetRenderView()->DidStartLoading();
+
+ render_frame->DidStartLoading();
return PP_OK;
}
int32_t PepperPDFHost::OnHostMsgDidStopLoading(
ppapi::host::HostMessageContext* context) {
- content::PepperPluginInstance* instance =
- host_->GetPluginInstance(pp_instance());
- if (!instance)
+ content::RenderFrame* render_frame = GetRenderFrame();
+ if (!render_frame)
return PP_ERROR_FAILED;
- instance->GetRenderView()->DidStopLoading();
+
+ render_frame->DidStopLoading();
return PP_OK;
}
int32_t PepperPDFHost::OnHostMsgSetContentRestriction(
ppapi::host::HostMessageContext* context,
int restrictions) {
- content::PepperPluginInstance* instance =
- host_->GetPluginInstance(pp_instance());
- if (!instance)
+ content::RenderFrame* render_frame = GetRenderFrame();
+ if (!render_frame)
return PP_ERROR_FAILED;
- instance->GetRenderView()->Send(new PDFHostMsg_PDFUpdateContentRestrictions(
- instance->GetRenderView()->GetRoutingID(), restrictions));
+
+ render_frame->Send(new PDFHostMsg_PDFUpdateContentRestrictions(
+ render_frame->GetRoutingID(), restrictions));
return PP_OK;
}
@@ -137,16 +138,12 @@ int32_t PepperPDFHost::OnHostMsgUserMetricsRecordAction(
int32_t PepperPDFHost::OnHostMsgHasUnsupportedFeature(
ppapi::host::HostMessageContext* context) {
- content::PepperPluginInstance* instance =
- host_->GetPluginInstance(pp_instance());
- if (!instance)
+ content::RenderFrame* render_frame = GetRenderFrame();
+ if (!render_frame)
return PP_ERROR_FAILED;
- blink::WebView* view =
- instance->GetContainer()->document().frame()->view();
- content::RenderView* render_view = content::RenderView::FromWebView(view);
- render_view->Send(
- new PDFHostMsg_PDFHasUnsupportedFeature(render_view->GetRoutingID()));
+ render_frame->Send(
+ new PDFHostMsg_PDFHasUnsupportedFeature(render_frame->GetRoutingID()));
return PP_OK;
}
@@ -161,14 +158,18 @@ int32_t PepperPDFHost::OnHostMsgSaveAs(
host_->GetPluginInstance(pp_instance());
if (!instance)
return PP_ERROR_FAILED;
+
+ content::RenderFrame* render_frame = instance->GetRenderFrame();
+ if (!render_frame)
+ return PP_ERROR_FAILED;
+
GURL url = instance->GetPluginURL();
- content::RenderView* render_view = instance->GetRenderView();
content::Referrer referrer;
referrer.url = url;
referrer.policy = blink::WebReferrerPolicyDefault;
referrer = content::Referrer::SanitizeForRequest(url, referrer);
- render_view->Send(
- new PDFHostMsg_PDFSaveURLAs(render_view->GetRoutingID(), url, referrer));
+ render_frame->Send(
+ new PDFHostMsg_PDFSaveURLAs(render_frame->GetRoutingID(), url, referrer));
return PP_OK;
}
@@ -197,11 +198,9 @@ int32_t PepperPDFHost::OnHostMsgSetLinkUnderCursor(
int32_t PepperPDFHost::OnHostMsgSetAccessibilityViewportInfo(
ppapi::host::HostMessageContext* context,
const PP_PrivateAccessibilityViewportInfo& viewport_info) {
- content::PepperPluginInstance* instance =
- host_->GetPluginInstance(pp_instance());
- if (!instance)
+ if (!host_->GetPluginInstance(pp_instance()))
return PP_ERROR_FAILED;
- CreatePdfAccessibilityTreeIfNeeded(instance);
+ CreatePdfAccessibilityTreeIfNeeded();
pdf_accessibility_tree_->SetAccessibilityViewportInfo(viewport_info);
return PP_OK;
}
@@ -209,11 +208,9 @@ int32_t PepperPDFHost::OnHostMsgSetAccessibilityViewportInfo(
int32_t PepperPDFHost::OnHostMsgSetAccessibilityDocInfo(
ppapi::host::HostMessageContext* context,
const PP_PrivateAccessibilityDocInfo& doc_info) {
- content::PepperPluginInstance* instance =
- host_->GetPluginInstance(pp_instance());
- if (!instance)
+ if (!host_->GetPluginInstance(pp_instance()))
return PP_ERROR_FAILED;
- CreatePdfAccessibilityTreeIfNeeded(instance);
+ CreatePdfAccessibilityTreeIfNeeded();
pdf_accessibility_tree_->SetAccessibilityDocInfo(doc_info);
return PP_OK;
}
@@ -223,22 +220,25 @@ int32_t PepperPDFHost::OnHostMsgSetAccessibilityPageInfo(
const PP_PrivateAccessibilityPageInfo& page_info,
const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_run_info,
const std::vector<PP_PrivateAccessibilityCharInfo>& chars) {
- content::PepperPluginInstance* instance =
- host_->GetPluginInstance(pp_instance());
- if (!instance)
+ if (!host_->GetPluginInstance(pp_instance()))
return PP_ERROR_FAILED;
- CreatePdfAccessibilityTreeIfNeeded(instance);
+ CreatePdfAccessibilityTreeIfNeeded();
pdf_accessibility_tree_->SetAccessibilityPageInfo(
page_info, text_run_info, chars);
return PP_OK;
}
-void PepperPDFHost::CreatePdfAccessibilityTreeIfNeeded(
- content::PepperPluginInstance* instance) {
+void PepperPDFHost::CreatePdfAccessibilityTreeIfNeeded() {
if (!pdf_accessibility_tree_) {
- pdf_accessibility_tree_.reset(
- new PdfAccessibilityTree(instance->GetRenderView()));
+ pdf_accessibility_tree_ =
+ base::MakeUnique<PdfAccessibilityTree>(host_, pp_instance());
}
}
+content::RenderFrame* PepperPDFHost::GetRenderFrame() {
+ content::PepperPluginInstance* instance =
+ host_->GetPluginInstance(pp_instance());
+ return instance ? instance->GetRenderFrame() : nullptr;
+}
+
} // namespace pdf
diff --git a/chromium/components/pdf/renderer/pepper_pdf_host.h b/chromium/components/pdf/renderer/pepper_pdf_host.h
index 89d786f224e..5e838c9e34b 100644
--- a/chromium/components/pdf/renderer/pepper_pdf_host.h
+++ b/chromium/components/pdf/renderer/pepper_pdf_host.h
@@ -7,7 +7,9 @@
#include <stdint.h>
+#include <memory>
#include <string>
+#include <vector>
#include "base/compiler_specific.h"
#include "base/macros.h"
@@ -24,18 +26,17 @@ class SkBitmap;
namespace content {
class PepperPluginInstance;
+class RenderFrame;
class RendererPpapiHost;
}
namespace ppapi {
class HostResource;
-}
-namespace ppapi {
namespace host {
struct HostMessageContext;
-}
-}
+} // namespace host
+} // namespace ppapi
namespace pdf {
@@ -71,6 +72,7 @@ class PepperPDFHost : public ppapi::host::ResourceHost {
// PPB_PDF_Impl instance.
static void SetPrintClient(PrintClient* print_client);
+ // ppapi::host::ResourceHost:
int32_t OnResourceMessageReceived(
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) override;
@@ -104,12 +106,13 @@ class PepperPDFHost : public ppapi::host::ResourceHost {
const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs,
const std::vector<PP_PrivateAccessibilityCharInfo>& chars);
- void CreatePdfAccessibilityTreeIfNeeded(
- content::PepperPluginInstance* instance);
+ void CreatePdfAccessibilityTreeIfNeeded();
+
+ content::RenderFrame* GetRenderFrame();
std::unique_ptr<PdfAccessibilityTree> pdf_accessibility_tree_;
- content::RendererPpapiHost* host_;
+ content::RendererPpapiHost* const host_;
DISALLOW_COPY_AND_ASSIGN(PepperPDFHost);
};
diff --git a/chromium/components/physical_web/OWNERS b/chromium/components/physical_web/OWNERS
new file mode 100644
index 00000000000..2f1afa43365
--- /dev/null
+++ b/chromium/components/physical_web/OWNERS
@@ -0,0 +1,2 @@
+mattreynolds@chromium.org
+olivierrobin@chromium.org
diff --git a/chromium/components/physical_web/data_source/BUILD.gn b/chromium/components/physical_web/data_source/BUILD.gn
new file mode 100644
index 00000000000..4236cf08bd4
--- /dev/null
+++ b/chromium/components/physical_web/data_source/BUILD.gn
@@ -0,0 +1,29 @@
+# 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.
+
+source_set("data_source") {
+ sources = [
+ "physical_web_data_source.h",
+ "physical_web_data_source_impl.cc",
+ "physical_web_data_source_impl.h",
+ "physical_web_listener.h",
+ ]
+
+ deps = [
+ "//base",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "physical_web_data_source_impl_unittest.cc",
+ ]
+
+ deps = [
+ ":data_source",
+ "//base",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source.h b/chromium/components/physical_web/data_source/physical_web_data_source.h
new file mode 100644
index 00000000000..6225b7aab99
--- /dev/null
+++ b/chromium/components/physical_web/data_source/physical_web_data_source.h
@@ -0,0 +1,49 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_H_
+#define COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_H_
+
+#include <memory>
+
+namespace base {
+class ListValue;
+}
+
+class PhysicalWebListener;
+
+// Helper class for accessing Physical Web metadata and controlling the scanner.
+class PhysicalWebDataSource {
+ public:
+ virtual ~PhysicalWebDataSource() {}
+
+ // Starts scanning for Physical Web URLs. If |network_request_enabled| is
+ // true, discovered URLs will be sent to a resolution service.
+ virtual void StartDiscovery(bool network_request_enabled) = 0;
+
+ // Stops scanning for Physical Web URLs and clears cached URL content.
+ virtual void StopDiscovery() = 0;
+
+ // Returns a list of resolved URLs and associated page metadata. If network
+ // requests are disabled or if discovery is not active, the list will be
+ // empty. The method can be called at any time to receive the current metadata
+ // list.
+ virtual std::unique_ptr<base::ListValue> GetMetadata() = 0;
+
+ // Returns boolean |true| if network requests are disabled and there are one
+ // or more discovered URLs that have not been sent to the resolution service.
+ // The method can be called at any time to check for unresolved discoveries.
+ // If discovery is inactive or network requests are enabled, it will always
+ // return false.
+ virtual bool HasUnresolvedDiscoveries() = 0;
+
+ // Register for changes to Physical Web URLs and associated page metadata.
+ virtual void RegisterListener(PhysicalWebListener* physical_web_listener) = 0;
+
+ // Unregister for changes to Physical Web URLs and associated page metadata.
+ virtual void UnregisterListener(
+ PhysicalWebListener* physical_web_listener) = 0;
+};
+
+#endif // COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_H_
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source_impl.cc b/chromium/components/physical_web/data_source/physical_web_data_source_impl.cc
new file mode 100644
index 00000000000..744afcc60d2
--- /dev/null
+++ b/chromium/components/physical_web/data_source/physical_web_data_source_impl.cc
@@ -0,0 +1,37 @@
+// 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 "base/observer_list.h"
+#include "components/physical_web/data_source/physical_web_data_source.h"
+#include "components/physical_web/data_source/physical_web_data_source_impl.h"
+#include "components/physical_web/data_source/physical_web_listener.h"
+
+PhysicalWebDataSourceImpl::PhysicalWebDataSourceImpl() {}
+
+PhysicalWebDataSourceImpl::~PhysicalWebDataSourceImpl() {}
+
+void PhysicalWebDataSourceImpl::RegisterListener(
+ PhysicalWebListener* physical_web_listener) {
+ observer_list_.AddObserver(physical_web_listener);
+}
+
+void PhysicalWebDataSourceImpl::UnregisterListener(
+ PhysicalWebListener* physical_web_listener) {
+ observer_list_.RemoveObserver(physical_web_listener);
+}
+
+void PhysicalWebDataSourceImpl::NotifyOnFound(const std::string& url) {
+ FOR_EACH_OBSERVER(PhysicalWebListener, observer_list_, OnFound(url));
+}
+
+void PhysicalWebDataSourceImpl::NotifyOnLost(const std::string& url) {
+ FOR_EACH_OBSERVER(PhysicalWebListener, observer_list_, OnLost(url));
+}
+
+void PhysicalWebDataSourceImpl::NotifyOnDistanceChanged(
+ const std::string& url,
+ double distance_estimate) {
+ FOR_EACH_OBSERVER(PhysicalWebListener, observer_list_,
+ OnDistanceChanged(url, distance_estimate));
+}
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source_impl.h b/chromium/components/physical_web/data_source/physical_web_data_source_impl.h
new file mode 100644
index 00000000000..df23be3c7ec
--- /dev/null
+++ b/chromium/components/physical_web/data_source/physical_web_data_source_impl.h
@@ -0,0 +1,37 @@
+// 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 COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_IMPL_H_
+#define COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_IMPL_H_
+
+#include "base/observer_list.h"
+#include "components/physical_web/data_source/physical_web_data_source.h"
+
+class PhysicalWebListener;
+
+class PhysicalWebDataSourceImpl : public PhysicalWebDataSource {
+ public:
+ PhysicalWebDataSourceImpl();
+ ~PhysicalWebDataSourceImpl() override;
+
+ // Register for changes to Physical Web URLs and associated page metadata.
+ void RegisterListener(PhysicalWebListener* physical_web_listener) override;
+
+ // Unregister for changes to Physical Web URLs and associated page metadata.
+ void UnregisterListener(PhysicalWebListener* physical_web_listener) override;
+
+ // Notify all registered listeners that a URL has been found.
+ void NotifyOnFound(const std::string& url);
+
+ // Notify all registered listeners that a URL has been lost.
+ void NotifyOnLost(const std::string& url);
+
+ // Notify all registered listeners that a distance has changed for a URL.
+ void NotifyOnDistanceChanged(const std::string& url,
+ double distance_estimate);
+
+ private:
+ base::ObserverList<PhysicalWebListener> observer_list_;
+};
+
+#endif // COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_IMPL_H_
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc b/chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc
new file mode 100644
index 00000000000..3ba18f0d880
--- /dev/null
+++ b/chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc
@@ -0,0 +1,158 @@
+// 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 "base/values.h"
+#include "components/physical_web/data_source/physical_web_data_source_impl.h"
+#include "components/physical_web/data_source/physical_web_listener.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace physical_web {
+
+// Test Values ----------------------------------------------------------------
+const char kUrl[] = "https://www.google.com";
+
+// TestPhysicalWebDataSource --------------------------------------------------
+
+class TestPhysicalWebDataSource : public PhysicalWebDataSourceImpl {
+ public:
+ TestPhysicalWebDataSource() {}
+ ~TestPhysicalWebDataSource() override {}
+
+ void StartDiscovery(bool network_request_enabled) override;
+ void StopDiscovery() override;
+ std::unique_ptr<base::ListValue> GetMetadata() override;
+ bool HasUnresolvedDiscoveries() override;
+};
+void TestPhysicalWebDataSource::StartDiscovery(bool network_request_enabled) {}
+
+void TestPhysicalWebDataSource::StopDiscovery() {}
+
+std::unique_ptr<base::ListValue> TestPhysicalWebDataSource::GetMetadata() {
+ return NULL;
+}
+
+bool TestPhysicalWebDataSource::HasUnresolvedDiscoveries() {
+ return false;
+}
+
+// TestPhysicalWebListener ----------------------------------------------------
+
+class TestPhysicalWebListener : public PhysicalWebListener {
+ public:
+ TestPhysicalWebListener()
+ : on_found_notified_(false),
+ on_lost_notified_(false),
+ on_distance_changed_notified_(false) {}
+
+ ~TestPhysicalWebListener() {}
+
+ void OnFound(const std::string& url) override {
+ on_found_notified_ = true;
+ last_event_url_ = url;
+ }
+
+ void OnLost(const std::string& url) override {
+ on_lost_notified_ = true;
+ last_event_url_ = url;
+ }
+
+ void OnDistanceChanged(const std::string& url,
+ double distance_estimate) override {
+ on_distance_changed_notified_ = true;
+ last_event_url_ = url;
+ }
+
+ bool OnFoundNotified() { return on_found_notified_; }
+
+ bool OnLostNotified() { return on_lost_notified_; }
+
+ bool OnDistanceChangedNotified() { return on_distance_changed_notified_; }
+
+ std::string LastEventUrl() { return last_event_url_; }
+
+ private:
+ bool on_found_notified_;
+ bool on_lost_notified_;
+ bool on_distance_changed_notified_;
+ std::string last_event_url_;
+};
+
+// PhysicalWebDataSourceImplTest ----------------------------------------------
+
+class PhysicalWebDataSourceImplTest : public ::testing::Test {
+ public:
+ PhysicalWebDataSourceImplTest() {}
+ ~PhysicalWebDataSourceImplTest() override {}
+
+ // testing::Test
+ void SetUp() override;
+ void TearDown() override;
+
+ protected:
+ TestPhysicalWebDataSource data_source_;
+ TestPhysicalWebListener listener_;
+};
+
+void PhysicalWebDataSourceImplTest::SetUp() {
+ data_source_.RegisterListener(&listener_);
+}
+
+void PhysicalWebDataSourceImplTest::TearDown() {
+ data_source_.UnregisterListener(&listener_);
+}
+
+// Tests ----------------------------------------------------------------------
+
+TEST_F(PhysicalWebDataSourceImplTest, OnFound) {
+ data_source_.NotifyOnFound(kUrl);
+ EXPECT_TRUE(listener_.OnFoundNotified());
+ EXPECT_FALSE(listener_.OnLostNotified());
+ EXPECT_FALSE(listener_.OnDistanceChangedNotified());
+ EXPECT_EQ(kUrl, listener_.LastEventUrl());
+}
+
+TEST_F(PhysicalWebDataSourceImplTest, OnLost) {
+ data_source_.NotifyOnLost(kUrl);
+ EXPECT_FALSE(listener_.OnFoundNotified());
+ EXPECT_TRUE(listener_.OnLostNotified());
+ EXPECT_FALSE(listener_.OnDistanceChangedNotified());
+ EXPECT_EQ(kUrl, listener_.LastEventUrl());
+}
+
+TEST_F(PhysicalWebDataSourceImplTest, OnDistanceChanged) {
+ data_source_.NotifyOnDistanceChanged(kUrl, 0.0);
+ EXPECT_FALSE(listener_.OnFoundNotified());
+ EXPECT_FALSE(listener_.OnLostNotified());
+ EXPECT_TRUE(listener_.OnDistanceChangedNotified());
+ EXPECT_EQ(kUrl, listener_.LastEventUrl());
+}
+
+TEST_F(PhysicalWebDataSourceImplTest, OnFoundNotRegistered) {
+ data_source_.UnregisterListener(&listener_);
+ data_source_.NotifyOnFound(kUrl);
+ EXPECT_FALSE(listener_.OnFoundNotified());
+ EXPECT_FALSE(listener_.OnLostNotified());
+ EXPECT_FALSE(listener_.OnDistanceChangedNotified());
+ EXPECT_TRUE(listener_.LastEventUrl().empty());
+}
+
+TEST_F(PhysicalWebDataSourceImplTest, OnLostNotRegistered) {
+ data_source_.UnregisterListener(&listener_);
+ data_source_.NotifyOnLost(kUrl);
+ EXPECT_FALSE(listener_.OnFoundNotified());
+ EXPECT_FALSE(listener_.OnLostNotified());
+ EXPECT_FALSE(listener_.OnDistanceChangedNotified());
+ EXPECT_TRUE(listener_.LastEventUrl().empty());
+}
+
+TEST_F(PhysicalWebDataSourceImplTest, OnDistanceChangedNotRegistered) {
+ data_source_.UnregisterListener(&listener_);
+ data_source_.NotifyOnDistanceChanged(kUrl, 0.0);
+ EXPECT_FALSE(listener_.OnFoundNotified());
+ EXPECT_FALSE(listener_.OnLostNotified());
+ EXPECT_FALSE(listener_.OnDistanceChangedNotified());
+ EXPECT_TRUE(listener_.LastEventUrl().empty());
+}
+} // namespace physical_web
diff --git a/chromium/components/physical_web/data_source/physical_web_listener.h b/chromium/components/physical_web/data_source/physical_web_listener.h
new file mode 100644
index 00000000000..eb338872f9a
--- /dev/null
+++ b/chromium/components/physical_web/data_source/physical_web_listener.h
@@ -0,0 +1,26 @@
+// 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 COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_LISTENER_H_
+#define COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_LISTENER_H_
+
+#include <string>
+
+// Class for being notified when Physical Web data changes.
+class PhysicalWebListener {
+ public:
+
+ // OnFound(url) will be called when a new URL has been found.
+ virtual void OnFound(const std::string& url) = 0;
+
+ // OnLost(url) will be called when a URL can no longer be seen.
+ virtual void OnLost(const std::string& url) = 0;
+
+ // OnDistanceChagned(url, distance_estimate) will be called when the distance
+ // estimate is changed for the URL.
+ virtual void OnDistanceChanged(const std::string& url,
+ double distance_estimate) = 0;
+};
+
+#endif // COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_LISTENER_H_
diff --git a/chromium/components/physical_web/webui/BUILD.gn b/chromium/components/physical_web/webui/BUILD.gn
new file mode 100644
index 00000000000..f3d6432dd2b
--- /dev/null
+++ b/chromium/components/physical_web/webui/BUILD.gn
@@ -0,0 +1,14 @@
+# 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.
+
+source_set("webui") {
+ sources = [
+ "physical_web_ui_constants.cc",
+ "physical_web_ui_constants.h",
+ ]
+
+ deps = [
+ "//base",
+ ]
+}
diff --git a/chromium/components/physical_web/webui/physical_web_ui_constants.cc b/chromium/components/physical_web/webui/physical_web_ui_constants.cc
new file mode 100644
index 00000000000..b16c4a9bda5
--- /dev/null
+++ b/chromium/components/physical_web/webui/physical_web_ui_constants.cc
@@ -0,0 +1,27 @@
+// 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 "components/physical_web/webui/physical_web_ui_constants.h"
+
+namespace physical_web_ui {
+
+// Resource paths.
+const char kPhysicalWebJS[] = "physical_web.js";
+const char kPhysicalWebCSS[] = "physical_web.css";
+
+// Message handlers.
+const char kRequestNearbyUrls[] = "requestNearbyURLs";
+
+// Strings.
+const char kTitle[] = "title";
+const char kPageInfo[] = "pageInfo";
+const char kPageInfoDescription[] = "pageInfoDescription";
+const char kPageInfoIcon[] = "pageInfoIcon";
+const char kPageInfoTitle[] = "pageInfoTitle";
+const char kResolvedUrl[] = "resolvedUrl";
+const char kScannedUrl[] = "scannedUrl";
+const char kReturnNearbyUrls[] = "returnNearbyURLs";
+const char kMetadata[] = "metadata";
+
+} // namespace physical_web_ui
diff --git a/chromium/components/physical_web/webui/physical_web_ui_constants.h b/chromium/components/physical_web/webui/physical_web_ui_constants.h
new file mode 100644
index 00000000000..8319801eb72
--- /dev/null
+++ b/chromium/components/physical_web/webui/physical_web_ui_constants.h
@@ -0,0 +1,33 @@
+// 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 COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_UI_CONSTANTS_H_
+#define COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_UI_CONSTANTS_H_
+
+namespace physical_web_ui {
+
+// Resource paths.
+// Must match the resource file names.
+extern const char kPhysicalWebJS[];
+extern const char kPhysicalWebCSS[];
+
+// Message handlers.
+// Must match the constants used in the resource files.
+extern const char kRequestNearbyUrls[];
+
+// Strings.
+// Must match the constants used in the resource files.
+extern const char kTitle[];
+extern const char kPageInfo[];
+extern const char kPageInfoDescription[];
+extern const char kPageInfoIcon[];
+extern const char kPageInfoTitle[];
+extern const char kResolvedUrl[];
+extern const char kScannedUrl[];
+extern const char kReturnNearbyUrls[];
+extern const char kMetadata[];
+
+} // namespace physical_web_ui
+
+#endif // COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_UI_CONSTANTS_H_
diff --git a/chromium/components/physical_web/webui/resources/physical_web.css b/chromium/components/physical_web/webui/resources/physical_web.css
new file mode 100644
index 00000000000..9c5e888c2ef
--- /dev/null
+++ b/chromium/components/physical_web/webui/resources/physical_web.css
@@ -0,0 +1,50 @@
+/* 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. */
+
+body {
+ font-family: Sans-Serif;
+ font-size: 12px;
+}
+.physicalWebTemplate {
+ display: flex;
+ width: 290px;
+ margin-bottom: 15px;
+ text-decoration: none;
+}
+
+.physicalWebIcon {
+ width: 32px;
+}
+.physicalWebText {
+ flex: 1;
+}
+.physicalWebIcon img {
+ padding-top: 1px;
+ width: 75%;
+}
+.physicalWebTemplate .title {
+ display: block;
+ color: #222;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin-bottom: 3px;
+}
+.physicalWebTemplate .resolvedUrl {
+ display: block;
+ font-size: 80%;
+ color: #888;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin-bottom: 4px;
+}
+.physicalWebTemplate .description {
+ display: block;
+ height: 2.5em;
+ font-size: 90%;
+ color: #444;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
diff --git a/chromium/components/physical_web/webui/resources/physical_web.html b/chromium/components/physical_web/webui/resources/physical_web.html
new file mode 100644
index 00000000000..61e848812b4
--- /dev/null
+++ b/chromium/components/physical_web/webui/resources/physical_web.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<html i18n-values="dir:textdirection;lang:language">
+<head>
+<meta charset="utf-8">
+<title i18n-content="title"></title>
+<if expr="is_android or is_ios">
+<meta name="viewport" content="width=device-width, user-scalable=no">
+</if>
+<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+<link rel="stylesheet" href="chrome://physical-web/physical_web.css">
+
+<if expr="is_ios">
+<!-- TODO(crbug.com/487000): Remove this once injected by web. -->
+<script src="chrome://resources/js/ios/web_ui.js"></script>
+</if>
+
+<script src="chrome://resources/js/load_time_data.js"></script>
+<script src="chrome://resources/js/util.js"></script>
+<script src="chrome://physical-web/physical_web.js"></script>
+<script src="chrome://physical-web/strings.js"></script>
+</head>
+<body>
+<div id="body-container" style="visibility:visible">
+
+ <h1 i18n-content="title"></h1>
+
+ <a class="physicalWebTemplate" id="physicalWebTemplate" jsvalues="href:resolvedUrl" jsselect="metadata">
+ <div class="physicalWebIcon">
+ <img jsvalues="src:icon" />
+ </div>
+ <div class="physicalWebText">
+ <div class="title" jscontent="title"></div>
+ <div class="resolvedUrl" jscontent="resolvedUrl"></div>
+ <div class="description" jscontent="description"></div>
+ </div>
+ </a>
+
+</div>
+
+<script src="chrome://resources/js/i18n_template.js"></script>
+<script src="chrome://resources/js/jstemplate_compiled.js"></script>
+</body>
+</html>
diff --git a/chromium/components/physical_web/webui/resources/physical_web.js b/chromium/components/physical_web/webui/resources/physical_web.js
new file mode 100644
index 00000000000..459fb181b5b
--- /dev/null
+++ b/chromium/components/physical_web/webui/resources/physical_web.js
@@ -0,0 +1,31 @@
+// 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.
+
+/**
+ * Takes the |nearbyUrlsData| input argument which holds metadata for web pages
+ * broadcast by nearby devices.
+ * @param {Object} nearbyUrlsData Information about web pages broadcast by
+ * nearby devices
+ */
+function renderTemplate(nearbyUrlsData) {
+ // This is the javascript code that processes the template:
+ jstProcess(new JsEvalContext(nearbyUrlsData), $('physicalWebTemplate'));
+}
+
+function requestNearbyURLs() {
+ chrome.send('requestNearbyURLs');
+}
+
+function handleClickPhysicalWebItem(node) {
+ // do something
+}
+
+function returnNearbyURLs(nearbyUrlsData) {
+ var bodyContainer = $('body-container');
+ renderTemplate(nearbyUrlsData);
+
+ bodyContainer.style.visibility = 'visible';
+}
+
+document.addEventListener('DOMContentLoaded', requestNearbyURLs);
diff --git a/chromium/components/physical_web_ui_strings.grdp b/chromium/components/physical_web_ui_strings.grdp
new file mode 100644
index 00000000000..cc34d512cc4
--- /dev/null
+++ b/chromium/components/physical_web_ui_strings.grdp
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <message name="IDS_PHYSICAL_WEB_UI_TITLE" desc="Title of a built-in page that displays a list of Physical Web URLs (URLs broadcast by nearby devices).">
+ Physical Web
+ </message>
+</grit-part>
diff --git a/chromium/components/plugins.gypi b/chromium/components/plugins.gypi
deleted file mode 100644
index ed37c649ce4..00000000000
--- a/chromium/components/plugins.gypi
+++ /dev/null
@@ -1,50 +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.
-
-{
- 'conditions': [
- ['OS!="ios"', {
- 'targets': [
- {
- # GN version: //components/plugins/renderer
- 'target_name': 'plugins_renderer',
- 'type': 'static_library',
- 'dependencies': [
- '../gin/gin.gyp:gin',
- '../skia/skia.gyp:skia',
- '../third_party/WebKit/public/blink.gyp:blink',
- '../third_party/re2/re2.gyp:re2',
- '../v8/src/v8.gyp:v8',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'plugins/renderer/plugin_placeholder.cc',
- 'plugins/renderer/plugin_placeholder.h',
- 'plugins/renderer/webview_plugin.cc',
- 'plugins/renderer/webview_plugin.h',
- ],
- 'conditions' : [
- ['enable_plugins==1', {
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'plugins/renderer/loadable_plugin_placeholder.cc',
- 'plugins/renderer/loadable_plugin_placeholder.h',
- ]
- }],
- ['OS=="android"', {
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'plugins/renderer/mobile_youtube_plugin.cc',
- 'plugins/renderer/mobile_youtube_plugin.h',
- ]
- }],
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc b/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
index a8c6d71abf1..9bc0478ac0e 100644
--- a/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
+++ b/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
@@ -32,6 +32,7 @@
using base::UserMetricsAction;
using content::PluginInstanceThrottler;
+using content::RenderFrame;
using content::RenderThread;
namespace plugins {
@@ -51,15 +52,17 @@ void LoadablePluginPlaceholder::SetPremadePlugin(
content::PluginInstanceThrottler* throttler) {
DCHECK(throttler);
DCHECK(!premade_throttler_);
+ heuristic_run_before_ = true;
premade_throttler_ = throttler;
}
LoadablePluginPlaceholder::LoadablePluginPlaceholder(
- content::RenderFrame* render_frame,
+ RenderFrame* render_frame,
blink::WebLocalFrame* frame,
const blink::WebPluginParams& params,
const std::string& html_data)
: PluginPlaceholderBase(render_frame, frame, params, html_data),
+ heuristic_run_before_(false),
is_blocked_for_tinyness_(false),
is_blocked_for_background_tab_(false),
is_blocked_for_prerendering_(false),
@@ -68,7 +71,6 @@ LoadablePluginPlaceholder::LoadablePluginPlaceholder(
premade_throttler_(nullptr),
allow_loading_(false),
finished_loading_(false),
- heuristic_run_before_(premade_throttler_ != nullptr),
weak_factory_(this) {}
LoadablePluginPlaceholder::~LoadablePluginPlaceholder() {
@@ -125,10 +127,11 @@ void LoadablePluginPlaceholder::ReplacePlugin(blink::WebPlugin* new_plugin) {
// this point.
new_plugin = container->plugin();
- plugin()->RestoreTitleText();
container->invalidate();
container->reportGeometry();
- plugin()->ReplayReceivedData(new_plugin);
+ if (plugin()->focused())
+ new_plugin->updateFocus(true, blink::WebFocusTypeNone);
+ container->element().setAttribute("title", plugin()->old_title());
plugin()->destroy();
}
@@ -199,27 +202,27 @@ void LoadablePluginPlaceholder::OnUnobscuredRectUpdate(
// On a size update check if we now qualify as a essential plugin.
url::Origin content_origin = url::Origin(GetPluginParams().url);
- content::RenderFrame::PeripheralContentStatus status =
+ RenderFrame::PeripheralContentStatus status =
render_frame()->GetPeripheralContentStatus(
render_frame()->GetWebFrame()->top()->getSecurityOrigin(),
- content_origin, gfx::Size(width, height));
+ content_origin, gfx::Size(width, height),
+ heuristic_run_before_ ? RenderFrame::DONT_RECORD_DECISION
+ : RenderFrame::RECORD_DECISION);
bool plugin_is_tiny_and_blocked =
is_blocked_for_tinyness_ &&
- status ==
- content::RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_TINY;
+ status == RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_TINY;
// Early exit for plugins that we've discovered to be essential.
if (!plugin_is_tiny_and_blocked &&
- status != content::RenderFrame::CONTENT_STATUS_PERIPHERAL) {
+ status != RenderFrame::CONTENT_STATUS_PERIPHERAL) {
MarkPluginEssential(
heuristic_run_before_
? PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_SIZE_CHANGE
: PluginInstanceThrottler::UNTHROTTLE_METHOD_DO_NOT_RECORD);
if (!heuristic_run_before_ &&
- status ==
- content::RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_BIG) {
+ status == RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_BIG) {
render_frame()->WhitelistContentOrigin(content_origin);
}
diff --git a/chromium/components/plugins/renderer/loadable_plugin_placeholder.h b/chromium/components/plugins/renderer/loadable_plugin_placeholder.h
index 0d7d8d961ff..ea52ae9e5d6 100644
--- a/chromium/components/plugins/renderer/loadable_plugin_placeholder.h
+++ b/chromium/components/plugins/renderer/loadable_plugin_placeholder.h
@@ -82,6 +82,9 @@ class LoadablePluginPlaceholder : public PluginPlaceholderBase {
void DidFinishLoadingCallback();
void DidFinishIconRepositionForTestingCallback();
+ // True if the power saver heuristic has already been run on this content.
+ bool heuristic_run_before_;
+
private:
// WebViewPlugin::Delegate methods:
void PluginDestroyed() override;
@@ -135,9 +138,6 @@ class LoadablePluginPlaceholder : public PluginPlaceholderBase {
gfx::Rect unobscured_rect_;
- // True if the power saver heuristic has already been run on this content.
- bool heuristic_run_before_;
-
base::WeakPtrFactory<LoadablePluginPlaceholder> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(LoadablePluginPlaceholder);
diff --git a/chromium/components/plugins/renderer/mobile_youtube_plugin.cc b/chromium/components/plugins/renderer/mobile_youtube_plugin.cc
index 4b77abd52a6..455640b0fbc 100644
--- a/chromium/components/plugins/renderer/mobile_youtube_plugin.cc
+++ b/chromium/components/plugins/renderer/mobile_youtube_plugin.cc
@@ -106,7 +106,6 @@ void MobileYouTubePlugin::OpenYoutubeUrlCallback() {
std::string youtube("vnd.youtube:");
GURL url(youtube.append(GetYoutubeVideoId(GetPluginParams())));
WebURLRequest request;
- request.initialize();
request.setURL(url);
render_frame()->LoadURLExternally(request,
blink::WebNavigationPolicyNewForegroundTab);
diff --git a/chromium/components/plugins/renderer/webview_plugin.cc b/chromium/components/plugins/renderer/webview_plugin.cc
index 7992f78bc5e..af1d9199bf4 100644
--- a/chromium/components/plugins/renderer/webview_plugin.cc
+++ b/chromium/components/plugins/renderer/webview_plugin.cc
@@ -17,9 +17,7 @@
#include "content/public/renderer/render_view.h"
#include "gin/converter.h"
#include "skia/ext/platform_canvas.h"
-#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
@@ -42,10 +40,8 @@ using blink::WebPlugin;
using blink::WebPluginContainer;
using blink::WebPoint;
using blink::WebRect;
-using blink::WebSize;
using blink::WebString;
using blink::WebURLError;
-using blink::WebURLRequest;
using blink::WebURLResponse;
using blink::WebVector;
using blink::WebView;
@@ -58,21 +54,20 @@ WebViewPlugin::WebViewPlugin(content::RenderView* render_view,
delegate_(delegate),
container_(nullptr),
web_view_(WebView::create(this, blink::WebPageVisibilityStateVisible)),
- finished_loading_(false),
focused_(false),
is_painting_(false),
is_resizing_(false),
+ web_frame_client_(this),
weak_factory_(this) {
// ApplyWebPreferences before making a WebLocalFrame so that the frame sees a
// consistent view of our preferences.
content::RenderView::ApplyWebPreferences(preferences, web_view_);
- WebLocalFrame* web_local_frame =
- WebLocalFrame::create(blink::WebTreeScopeType::Document, this);
- web_frame_ = web_local_frame;
- web_view_->setMainFrame(web_frame_);
+ WebLocalFrame* web_frame = WebLocalFrame::create(
+ blink::WebTreeScopeType::Document, &web_frame_client_);
+ web_view_->setMainFrame(web_frame);
// TODO(dcheng): The main frame widget currently has a special case.
// Eliminate this once WebView is no longer a WebWidget.
- web_frame_widget_ = WebFrameWidget::create(this, web_view_, web_local_frame);
+ WebFrameWidget::create(this, web_view_, web_frame);
}
// static
@@ -89,43 +84,7 @@ WebViewPlugin* WebViewPlugin::Create(content::RenderView* render_view,
WebViewPlugin::~WebViewPlugin() {
DCHECK(!weak_factory_.HasWeakPtrs());
- web_frame_widget_->close();
web_view_->close();
- web_frame_->close();
-}
-
-void WebViewPlugin::ReplayReceivedData(WebPlugin* plugin) {
- if (!response_.isNull()) {
- plugin->didReceiveResponse(response_);
- size_t total_bytes = 0;
- for (std::list<std::string>::iterator it = data_.begin(); it != data_.end();
- ++it) {
- plugin->didReceiveData(
- it->c_str(), base::checked_cast<int, size_t>(it->length()));
- total_bytes += it->length();
- }
- UMA_HISTOGRAM_MEMORY_KB(
- "PluginDocument.Memory",
- (base::checked_cast<int, size_t>(total_bytes / 1024)));
- UMA_HISTOGRAM_COUNTS(
- "PluginDocument.NumChunks",
- (base::checked_cast<int, size_t>(data_.size())));
- }
- // We need to transfer the |focused_| to new plugin after it loaded.
- if (focused_) {
- plugin->updateFocus(true, blink::WebFocusTypeNone);
- }
- if (finished_loading_) {
- plugin->didFinishLoading();
- }
- if (error_) {
- plugin->didFailLoading(*error_);
- }
-}
-
-void WebViewPlugin::RestoreTitleText() {
- if (container_)
- container_->element().setAttribute("title", old_title_);
}
WebPluginContainer* WebViewPlugin::container() const { return container_; }
@@ -257,22 +216,19 @@ blink::WebInputEventResult WebViewPlugin::handleInputEvent(
}
void WebViewPlugin::didReceiveResponse(const WebURLResponse& response) {
- DCHECK(response_.isNull());
- response_ = response;
+ NOTREACHED();
}
void WebViewPlugin::didReceiveData(const char* data, int data_length) {
- data_.push_back(std::string(data, data_length));
+ NOTREACHED();
}
void WebViewPlugin::didFinishLoading() {
- DCHECK(!finished_loading_);
- finished_loading_ = true;
+ NOTREACHED();
}
void WebViewPlugin::didFailLoading(const WebURLError& error) {
- DCHECK(!error_.get());
- error_.reset(new WebURLError(error));
+ NOTREACHED();
}
bool WebViewPlugin::acceptsLoadDrops() { return false; }
@@ -321,8 +277,9 @@ void WebViewPlugin::scheduleAnimation() {
}
}
-void WebViewPlugin::didClearWindowObject(WebLocalFrame* frame) {
- if (!delegate_)
+void WebViewPlugin::PluginWebFrameClient::didClearWindowObject(
+ WebLocalFrame* frame) {
+ if (!plugin_->delegate_)
return;
v8::Isolate* isolate = blink::mainThreadIsolate();
@@ -334,12 +291,7 @@ void WebViewPlugin::didClearWindowObject(WebLocalFrame* frame) {
v8::Local<v8::Object> global = context->Global();
global->Set(gin::StringToV8(isolate, "plugin"),
- delegate_->GetV8Handle(isolate));
-}
-
-void WebViewPlugin::didReceiveResponse(unsigned identifier,
- const WebURLResponse& response) {
- WebFrameClient::didReceiveResponse(identifier, response);
+ plugin_->delegate_->GetV8Handle(isolate));
}
void WebViewPlugin::OnDestruct() {}
diff --git a/chromium/components/plugins/renderer/webview_plugin.h b/chromium/components/plugins/renderer/webview_plugin.h
index c4625e9f11d..086fa6db3a1 100644
--- a/chromium/components/plugins/renderer/webview_plugin.h
+++ b/chromium/components/plugins/renderer/webview_plugin.h
@@ -42,7 +42,6 @@ class Size;
class WebViewPlugin : public blink::WebPlugin,
public blink::WebViewClient,
- public blink::WebFrameClient,
public content::RenderViewObserver {
public:
class Delegate {
@@ -75,12 +74,8 @@ class WebViewPlugin : public blink::WebPlugin,
blink::WebView* web_view() { return web_view_; }
- // When loading a plugin document (i.e. a full page plugin not embedded in
- // another page), we save all data that has been received, and replay it with
- // this method on the actual plugin.
- void ReplayReceivedData(blink::WebPlugin* plugin);
-
- void RestoreTitleText();
+ bool focused() const { return focused_; }
+ const blink::WebString& old_title() const { return old_title_; }
// WebPlugin methods:
blink::WebPluginContainer* container() const override;
@@ -134,16 +129,6 @@ class WebViewPlugin : public blink::WebPlugin,
void didChangeCursor(const blink::WebCursorInfo& cursor) override;
void scheduleAnimation() override;
- // WebFrameClient methods:
- void didClearWindowObject(blink::WebLocalFrame* frame) override;
-
- // This method is defined in WebPlugin as well as in WebFrameClient, but with
- // different parameters. We only care about implementing the WebPlugin
- // version, so we implement this method and call the default in WebFrameClient
- // (which does nothing) to correctly overload it.
- void didReceiveResponse(unsigned identifier,
- const blink::WebURLResponse& response) override;
-
private:
friend class base::DeleteHelper<WebViewPlugin>;
WebViewPlugin(content::RenderView* render_view,
@@ -169,22 +154,25 @@ class WebViewPlugin : public blink::WebPlugin,
// Owned by us, deleted via |close()|.
blink::WebView* web_view_;
- // Owned by us, deleted via |close()|.
- blink::WebFrameWidget* web_frame_widget_;
-
- // Owned by us, deleted via |close()|.
- blink::WebFrame* web_frame_;
gfx::Rect rect_;
- blink::WebURLResponse response_;
- std::list<std::string> data_;
- std::unique_ptr<blink::WebURLError> error_;
blink::WebString old_title_;
- bool finished_loading_;
bool focused_;
bool is_painting_;
bool is_resizing_;
+ // A helper needed to create a WebLocalFrame.
+ class PluginWebFrameClient : public blink::WebFrameClient {
+ public:
+ PluginWebFrameClient(WebViewPlugin* plugin) : plugin_(plugin) {}
+ ~PluginWebFrameClient() override {}
+ void didClearWindowObject(blink::WebLocalFrame* frame) override;
+
+ private:
+ WebViewPlugin* plugin_;
+ };
+ PluginWebFrameClient web_frame_client_;
+
// Should be invalidated when destroy() is called.
base::WeakPtrFactory<WebViewPlugin> weak_factory_;
};
diff --git a/chromium/components/policy.gypi b/chromium/components/policy.gypi
deleted file mode 100644
index 92504487507..00000000000
--- a/chromium/components/policy.gypi
+++ /dev/null
@@ -1,598 +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.
-
-{
- 'includes': [
- # Included to get 'mac_bundle_id' and other variables.
- '../build/chrome_settings.gypi',
- ],
- 'variables': {
- 'chromium_code': 1,
- 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/chrome',
- 'policy_out_dir': '<(SHARED_INTERMEDIATE_DIR)/policy',
- 'protoc_out_dir': '<(SHARED_INTERMEDIATE_DIR)/protoc_out',
- 'generate_policy_source_script_path':
- 'policy/tools/generate_policy_source.py',
- 'policy_constant_header_path':
- '<(policy_out_dir)/policy/policy_constants.h',
- 'policy_constant_source_path':
- '<(policy_out_dir)/policy/policy_constants.cc',
- 'protobuf_decoder_path':
- '<(policy_out_dir)/policy/cloud_policy_generated.cc',
- 'app_restrictions_path':
- '<(policy_out_dir)/app_restrictions.xml',
- 'risk_tag_header_path':
- '<(policy_out_dir)/risk_tag.h',
- # This is the "full" protobuf, which defines one protobuf message per
- # policy. It is also the format currently used by the server.
- 'chrome_settings_proto_path':
- '<(policy_out_dir)/policy/chrome_settings.proto',
- # This protobuf is equivalent to chrome_settings.proto but shares messages
- # for policies of the same type, so that less classes have to be generated
- # and compiled.
- 'cloud_policy_proto_path':
- '<(policy_out_dir)/policy/cloud_policy.proto',
- },
- 'conditions': [
- ['component=="static_library"', {
- 'targets': [
- {
- # GN version: //components/policy:policy_component
- 'target_name': 'policy_component',
- 'type': 'none',
- 'dependencies': [
- 'policy_component_common',
- 'policy_component_browser',
- ],
- },
- {
- # GN version: //components/policy:policy_component_common
- 'target_name': 'policy_component_common',
- 'type': 'static_library',
- 'includes': [
- 'policy/policy_common.gypi',
- ],
- },
- {
- # GN version: //components/policy:policy_component_browser
- 'target_name': 'policy_component_browser',
- 'type': 'static_library',
- 'dependencies': [
- 'policy_component_common',
- ],
- 'includes': [
- 'policy/policy_browser.gypi',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'dependencies': ['policy_jni_headers']},
- ],
- ],
- },
- ],
- }, { # component=="shared_library"
- 'targets': [
- {
- # GN version: //components/policy:policy_component
- 'target_name': 'policy_component',
- 'type': 'shared_library',
- 'includes': [
- 'policy/policy_common.gypi',
- 'policy/policy_browser.gypi',
- ],
- },
- {
- # GN version: //components/policy:policy_component_common
- 'target_name': 'policy_component_common',
- 'type': 'none',
- 'dependencies': [
- 'policy_component',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'dependencies': ['policy_jni_headers']},
- ],
- ],
- },
- {
- # GN version: //components/policy:policy_component_browser
- 'target_name': 'policy_component_browser',
- 'type': 'none',
- 'dependencies': [
- 'policy_component',
- ],
- },
- ],
- }],
- ['configuration_policy==1', {
- 'targets': [
- {
- # GN version: //components/policy:cloud_policy_code_generate
- 'target_name': 'cloud_policy_code_generate',
- 'type': 'none',
- 'actions': [
- {
- 'inputs': [
- 'policy/resources/policy_templates.json',
- '<(DEPTH)/chrome/VERSION',
- '<(generate_policy_source_script_path)',
- ],
- 'outputs': [
- '<(policy_constant_header_path)',
- '<(policy_constant_source_path)',
- '<(protobuf_decoder_path)',
- '<(chrome_settings_proto_path)',
- '<(cloud_policy_proto_path)',
- '<(app_restrictions_path)',
- '<(risk_tag_header_path)',
- ],
- 'action_name': 'generate_policy_source',
- 'action': [
- 'python',
- '<@(generate_policy_source_script_path)',
- '--policy-constants-header=<(policy_constant_header_path)',
- '--policy-constants-source=<(policy_constant_source_path)',
- '--chrome-settings-protobuf=<(chrome_settings_proto_path)',
- '--cloud-policy-protobuf=<(cloud_policy_proto_path)',
- '--cloud-policy-decoder=<(protobuf_decoder_path)',
- '--app-restrictions-definition=<(app_restrictions_path)',
- '--risk-tag-header=<(risk_tag_header_path)',
- '<(DEPTH)/chrome/VERSION',
- '<(OS)',
- '<(chromeos)',
- 'policy/resources/policy_templates.json',
- ],
- 'message': 'Generating policy source',
- 'conditions': [
- ['OS!="android"', {
- 'outputs!': [
- '<(app_restrictions_path)',
- ],
- }],
- ],
- },
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(policy_out_dir)',
- '<(protoc_out_dir)',
- ],
- },
- },
- {
- # GN version: //components/policy:cloud_policy_proto_generated_compile
- 'target_name': 'cloud_policy_proto_generated_compile',
- 'type': '<(component)',
- 'sources': [
- '<(cloud_policy_proto_path)',
- ],
- 'variables': {
- 'proto_in_dir': '<(policy_out_dir)/policy',
- 'proto_out_dir': 'policy/proto',
- 'cc_generator_options': 'dllexport_decl=POLICY_PROTO_EXPORT:',
- 'cc_include': 'components/policy/policy_proto_export.h',
- },
- 'dependencies': [
- 'cloud_policy_code_generate',
- ],
- 'includes': [
- '../build/protoc.gypi',
- ],
- 'defines': [
- 'POLICY_PROTO_COMPILATION',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- # This target builds the "full" protobuf, used for tests only.
- # GN version: //components/policy:chrome_settings_proto_generated_compile
- 'target_name': 'chrome_settings_proto_generated_compile',
- 'type': 'static_library',
- 'sources': [
- '<(chrome_settings_proto_path)',
- ],
- 'variables': {
- 'proto_in_dir': '<(policy_out_dir)/policy',
- 'proto_out_dir': 'policy/proto',
- },
- 'dependencies': [
- 'cloud_policy_code_generate',
- 'cloud_policy_proto_generated_compile',
- ],
- 'includes': [
- '../build/protoc.gypi',
- ],
- },
- {
- # GN version: //components/policy
- 'target_name': 'policy',
- 'type': 'static_library',
- 'hard_dependency': 1,
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(policy_out_dir)',
- '<(protoc_out_dir)',
- ],
- },
- 'sources': [
- '<(policy_constant_header_path)',
- '<(policy_constant_source_path)',
- '<(risk_tag_header_path)',
- '<(protobuf_decoder_path)',
- ],
- 'include_dirs': [
- '<(DEPTH)',
- ],
- 'dependencies': [
- 'cloud_policy_code_generate',
- 'cloud_policy_proto_generated_compile',
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite',
- ],
- 'defines': [
- 'POLICY_COMPONENT_IMPLEMENTATION',
- ],
- },
- {
- # GN version: //components/policy/proto
- 'target_name': 'cloud_policy_proto',
- 'type': '<(component)',
- 'sources': [
- 'policy/proto/chrome_extension_policy.proto',
- 'policy/proto/device_management_backend.proto',
- 'policy/proto/device_management_local.proto',
- 'policy/proto/policy_signing_key.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'policy/proto',
- 'proto_out_dir': 'policy/proto',
- 'cc_generator_options': 'dllexport_decl=POLICY_PROTO_EXPORT:',
- 'cc_include': 'components/policy/policy_proto_export.h',
- },
- 'includes': [
- '../build/protoc.gypi',
- ],
- 'conditions': [
- ['OS=="android" or OS=="ios"', {
- 'sources!': [
- 'policy/proto/chrome_extension_policy.proto',
- ],
- }],
- ['chromeos==0', {
- 'sources!': [
- 'policy/proto/device_management_local.proto',
- ],
- }],
- ],
- 'defines': [
- 'POLICY_PROTO_COMPILATION',
- ],
- },
- {
- # GN version: //components/policy:test_support
- 'target_name': 'policy_test_support',
- 'type': 'none',
- 'hard_dependency': 1,
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(policy_out_dir)',
- '<(protoc_out_dir)',
- ],
- },
- 'dependencies': [
- 'chrome_settings_proto_generated_compile',
- 'policy',
- ],
- },
- {
- # GN version: //components/policy:policy_component_test_support
- 'target_name': 'policy_component_test_support',
- 'type': 'static_library',
- # This must be undefined so that POLICY_EXPORT works correctly in
- # the static_library build.
- 'defines!': [
- 'POLICY_COMPONENT_IMPLEMENTATION',
- ],
- 'dependencies': [
- 'cloud_policy_proto',
- 'policy_component',
- 'policy_test_support',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'policy/core/browser/configuration_policy_pref_store_test.cc',
- 'policy/core/browser/configuration_policy_pref_store_test.h',
- 'policy/core/common/cloud/mock_cloud_external_data_manager.cc',
- 'policy/core/common/cloud/mock_cloud_external_data_manager.h',
- 'policy/core/common/cloud/mock_cloud_policy_client.cc',
- 'policy/core/common/cloud/mock_cloud_policy_client.h',
- 'policy/core/common/cloud/mock_cloud_policy_store.cc',
- 'policy/core/common/cloud/mock_cloud_policy_store.h',
- 'policy/core/common/cloud/mock_device_management_service.cc',
- 'policy/core/common/cloud/mock_device_management_service.h',
- 'policy/core/common/cloud/mock_user_cloud_policy_store.cc',
- 'policy/core/common/cloud/mock_user_cloud_policy_store.h',
- 'policy/core/common/cloud/policy_builder.cc',
- 'policy/core/common/cloud/policy_builder.h',
- 'policy/core/common/configuration_policy_provider_test.cc',
- 'policy/core/common/configuration_policy_provider_test.h',
- 'policy/core/common/fake_async_policy_loader.cc',
- 'policy/core/common/fake_async_policy_loader.h',
- 'policy/core/common/mock_configuration_policy_provider.cc',
- 'policy/core/common/mock_configuration_policy_provider.h',
- 'policy/core/common/mock_policy_service.cc',
- 'policy/core/common/mock_policy_service.h',
- 'policy/core/common/policy_test_utils.cc',
- 'policy/core/common/policy_test_utils.h',
- 'policy/core/common/preferences_mock_mac.cc',
- 'policy/core/common/preferences_mock_mac.h',
- 'policy/core/common/remote_commands/test_remote_command_job.cc',
- 'policy/core/common/remote_commands/test_remote_command_job.h',
- 'policy/core/common/remote_commands/testing_remote_commands_server.cc',
- 'policy/core/common/remote_commands/testing_remote_commands_server.h',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'sources!': [
- 'policy/core/common/fake_async_policy_loader.cc',
- 'policy/core/common/fake_async_policy_loader.h',
- ],
- }],
- ['chromeos==1', {
- 'sources!': [
- 'policy/core/common/cloud/mock_user_cloud_policy_store.cc',
- 'policy/core/common/cloud/mock_user_cloud_policy_store.h',
- ],
- }],
- ],
- },
- ],
- }],
- ['OS=="android"',
- {
- 'targets' : [
- {
- 'target_name' : 'policy_jni_headers',
- 'type': 'none',
- 'sources': [
- 'policy/android/java/src/org/chromium/policy/CombinedPolicyProvider.java',
- 'policy/android/java/src/org/chromium/policy/PolicyConverter.java',
- ],
- 'variables': {
- 'jni_gen_package': 'policy',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- 'target_name': 'components_policy_junit_tests',
- 'type': 'none',
- 'dependencies': [
- '../testing/android/junit/junit_test.gyp:junit_test_support',
- ],
- 'variables': {
- 'main_class': 'org.chromium.testing.local.JunitTestMain',
- 'src_paths': [
- '../testing/android/junit/DummyTest.java',
- ],
- 'wrapper_script_name': 'helper/<(_target_name)',
- },
- 'includes': [ '../build/host_jar.gypi' ],
- },
- ],
- }],
- ['OS=="android" and configuration_policy==1', {
- 'targets': [
- {
- 'target_name': 'app_restrictions_resources',
- 'type': 'none',
- 'variables': {
- 'resources_zip': '<(PRODUCT_DIR)/res.java/<(_target_name).zip',
- 'input_resources_dir':
- '<(SHARED_INTERMEDIATE_DIR)/chrome/app/policy/android',
- 'create_zip_script': '../build/android/gyp/zip.py',
- },
- 'copies': [
- {
- 'destination': '<(input_resources_dir)/xml-v21/',
- 'files': [
- '<(SHARED_INTERMEDIATE_DIR)/policy/app_restrictions.xml'
- ],
- },
- ],
- 'actions': [
- {
- 'action_name': 'create_resources_zip',
- 'inputs': [
- '<(create_zip_script)',
- '<(input_resources_dir)/xml-v21/app_restrictions.xml',
- '<(input_resources_dir)/values-v21/restriction_values.xml',
- ],
- 'outputs': [
- '<(resources_zip)'
- ],
- 'action': [
- 'python', '<(create_zip_script)',
- '--input-dir', '<(input_resources_dir)',
- '--output', '<(resources_zip)',
- ],
- }
- ],
- 'all_dependent_settings': {
- 'variables': {
- 'additional_input_paths': ['<(resources_zip)'],
- 'dependencies_res_zip_paths': ['<(resources_zip)'],
- },
- },
- },
- {
- # GN: //components/policy/android:policy_java
- 'target_name': 'policy_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base_java',
- ],
- 'variables': {
- 'java_in_dir': 'policy/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN: //components/policy/android:policy_java_test_support
- 'target_name': 'policy_java_test_support',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base_java',
- '../base/base.gyp:base_java_test_support',
- 'policy_java'
- ],
- 'variables': {
- 'java_in_dir': 'policy/android/javatests',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- ],
- }],
- ['OS=="win" and target_arch=="ia32" and configuration_policy==1', {
- 'targets': [
- {
- 'target_name': 'policy_win64',
- 'type': 'static_library',
- 'hard_dependency': 1,
- 'sources': [
- '<(policy_constant_header_path)',
- '<(policy_constant_source_path)',
- '<(risk_tag_header_path)',
- ],
- 'include_dirs': [
- '<(DEPTH)',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(policy_out_dir)'
- ],
- },
- 'dependencies': [
- 'cloud_policy_code_generate',
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- ],
- }],
- ['OS!="ios"', {
- 'targets': [
- {
- # policy_templates has different inputs and outputs, so it can't use
- # the rules of chrome_strings
- 'target_name': 'policy_templates',
- 'type': 'none',
- 'variables': {
- 'grit_grd_file': 'policy/resources/policy_templates.grd',
- 'grit_info_cmd': [
- 'python',
- '<(DEPTH)/tools/grit/grit_info.py',
- '<@(grit_defines)',
- ],
- },
- 'includes': [
- '../build/grit_target.gypi',
- ],
- 'actions': [
- {
- 'action_name': 'policy_templates',
- 'includes': [
- '../build/grit_action.gypi',
- ],
- },
- ],
- },
- ],
- }],
- ['OS=="mac"', {
- 'targets': [
- {
- # This is the bundle of the manifest file of Chrome.
- # It contains the manifest file and its string tables.
- 'target_name': 'chrome_manifest_bundle',
- 'type': 'loadable_module',
- 'mac_bundle': 1,
- 'product_extension': 'manifest',
- 'product_name': '<(mac_bundle_id)',
- 'variables': {
- # This avoids stripping debugging symbols from the target, which
- # would fail because there is no binary code here.
- 'mac_strip': 0,
- },
- 'dependencies': [
- # Provides app-Manifest.plist and its string tables:
- 'policy_templates',
- ],
- 'actions': [
- {
- 'action_name': 'Copy MCX manifest file to manifest bundle',
- 'inputs': [
- '<(grit_out_dir)/app/policy/mac/app-Manifest.plist',
- ],
- 'outputs': [
- '<(INTERMEDIATE_DIR)/app_manifest/<(mac_bundle_id).manifest',
- ],
- 'action': [
- # Use plutil -convert xml1 to put the plist into Apple's
- # canonical format. As a side effect, this ensures that the
- # plist is well-formed.
- 'plutil',
- '-convert',
- 'xml1',
- '<@(_inputs)',
- '-o',
- '<@(_outputs)',
- ],
- 'message':
- 'Copying the MCX policy manifest file to the manifest bundle',
- 'process_outputs_as_mac_bundle_resources': 1,
- },
- {
- 'action_name':
- 'Copy Localizable.strings files to manifest bundle',
- 'variables': {
- 'input_path': '<(grit_out_dir)/app/policy/mac/strings',
- # Directory to collect the Localizable.strings files before
- # they are copied to the bundle.
- 'output_path': '<(INTERMEDIATE_DIR)/app_manifest',
- # The reason we are not enumerating all the locales is that
- # the translations would eat up 3.5MB disk space in the
- # application bundle:
- 'available_locales': 'en',
- },
- 'inputs': [
- # TODO: remove this helper when we have loops in GYP
- '>!@(<(apply_locales_cmd) -d \'<(input_path)/ZZLOCALE.lproj/Localizable.strings\' <(available_locales))',
- ],
- 'outputs': [
- # TODO: remove this helper when we have loops in GYP
- '>!@(<(apply_locales_cmd) -d \'<(output_path)/ZZLOCALE.lproj/Localizable.strings\' <(available_locales))',
- ],
- 'action': [
- 'cp', '-R',
- '<(input_path)/',
- '<(output_path)',
- ],
- 'message':
- 'Copy the Localizable.strings files to the manifest bundle',
- 'process_outputs_as_mac_bundle_resources': 1,
- },
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/policy/BUILD.gn b/chromium/components/policy/BUILD.gn
index c2c7ea51c8c..9a23038433e 100644
--- a/chromium/components/policy/BUILD.gn
+++ b/chromium/components/policy/BUILD.gn
@@ -4,6 +4,7 @@
import("//build/config/chrome_build.gni")
import("//build/config/features.gni")
+import("//build/toolchain/toolchain.gni")
import("//components/policy/resources/policy_templates.gni")
import("//third_party/protobuf/proto_library.gni")
import("//tools/grit/grit_rule.gni")
@@ -12,76 +13,42 @@ if (is_mac) {
import("//build/util/branding.gni")
}
-# About the policy component:
-#
-# There should really be two components. One called "policy" that includes all
-# generated code, and one "policy/proto" like we have now. The proto needs to
-# be separate for cases like SesssionManagerClient which uses the protos to
-# communicate with the Chrome OS system layer, but doesn't need the rest of the
-# policy stuff).
-#
-# The reason the rest of the targets exist are artifacts of the way the GYP
-# build works. The current "policy" target which is really just some generated
-# code (which should be folded into the new "policy" component described above)
-# exists so code outside which depends on the generated headers can depend on
-# the hard policy target without having to make all policy targets hard
-# dependencies (GN will do the right thing without this extra target).
if (is_component_build) {
- component("policy_component") {
- public_deps = [
+ # External code should depend on either //components/policy/core/browser or
+ # .../common depending on what code it needs.
+ component("policy") {
+ output_name = "policy_component"
+ visibility = [
"//components/policy/core/browser",
"//components/policy/core/common",
]
- }
- group("policy_component_browser") {
- public_deps = [
- ":policy_component",
- ]
- }
- group("policy_component_common") {
- public_deps = [
- ":policy_component",
- ]
- }
-} else { # Compile to separate libraries.
- group("policy_component") {
- public_deps = [
- ":policy_component_browser",
- ":policy_component_common",
- ]
- }
- component("policy_component_browser") {
- public_deps = [
- "//components/policy/core/browser",
- ]
- }
- component("policy_component_common") {
public_deps = [
- "//components/policy/core/common",
+ "//components/policy/core/browser:internal",
+ "//components/policy/core/common:internal",
]
}
}
-if (enable_configuration_policy) {
- # TODO(GYP_GONE) this component should use target_gen_dir instead but the GYP
- # build puts everything into the following directory. We do the same for now.
- # Fix when GYP is gone.
- policy_gen_dir = "$root_gen_dir/policy"
+# Used by taregts that compile into the implementation.
+config("component_implementation") {
+ defines = [ "POLICY_COMPONENT_IMPLEMENTATION" ]
+}
+if (enable_configuration_policy) {
# This protobuf is equivalent to chrome_settings.proto but shares messages
# for policies of the same type, so that less classes have to be generated
# and compiled.
- cloud_policy_proto_path = "$policy_gen_dir/cloud_policy.proto"
+ cloud_policy_proto_path = "$target_gen_dir/proto/cloud_policy.proto"
# This is the "full" protobuf, which defines one protobuf message per
# policy. It is also the format currently used by the server.
- chrome_settings_proto_path = "$policy_gen_dir/chrome_settings.proto"
+ chrome_settings_proto_path = "$target_gen_dir/proto/chrome_settings.proto"
- constants_header_path = "$policy_gen_dir/policy_constants.h"
- constants_source_path = "$policy_gen_dir/policy_constants.cc"
- protobuf_decoder_path = "$policy_gen_dir/cloud_policy_generated.cc"
- app_restrictions_path = "$policy_gen_dir/app_restrictions.xml"
- risk_tag_header_path = "$policy_gen_dir/risk_tag.h"
+ constants_header_path = "$target_gen_dir/policy_constants.h"
+ constants_source_path = "$target_gen_dir/policy_constants.cc"
+ protobuf_decoder_path = "$target_gen_dir/cloud_policy_generated.cc"
+ app_restrictions_path = "$target_gen_dir/app_restrictions.xml"
+ risk_tag_header_path = "$target_gen_dir/risk_tag.h"
action("cloud_policy_code_generate") {
script = "tools/generate_policy_source.py"
@@ -167,9 +134,9 @@ if (enable_configuration_policy) {
cloud_policy_proto_path,
]
- proto_out_dir = "policy/proto"
+ proto_out_dir = "components/policy/proto"
cc_generator_options = "dllexport_decl=POLICY_PROTO_EXPORT:"
- cc_include = "components/policy/policy_proto_export.h"
+ cc_include = "components/policy/proto/policy_proto_export.h"
component_build_force_source_set = true
defines = [ "POLICY_PROTO_COMPILATION" ]
@@ -179,11 +146,12 @@ if (enable_configuration_policy) {
}
# This target builds the "full" protobuf, used for tests only.
- proto_library("chrome_settings_proto_generated_compile") {
+ proto_library("chrome_settings_proto") {
+ testonly = true
sources = [
chrome_settings_proto_path,
]
- proto_out_dir = "policy/proto"
+ proto_out_dir = "components/policy/proto"
deps = [
":cloud_policy_code_generate",
@@ -191,20 +159,7 @@ if (enable_configuration_policy) {
]
}
- # The dependencies here are kind of messed up.
- #
- # //components/policy/core/browser and .../common depend on this target,
- # and require it to be compiled with POLICY_COMPONENT_IMPLEMENTATION to
- # export the necessary symbols in a component build. But other targets like
- # //chrome/browser also depend on this target, which in component build
- # ends up in another shared library, but with the IMPLEMENTATION flag set
- # incorrectly.
- #
- # This only reason this works is that this target is a shared library and
- # the compilation units that this depends on in policy/core/common happen to
- # not be brought in in the "bad" case. This needs serious untangling, maybe
- # these files can just be put into policy/core/common?
- static_library("policy") {
+ static_library("generated") {
sources = [
constants_header_path,
constants_source_path,
@@ -213,7 +168,6 @@ if (enable_configuration_policy) {
]
defines = [ "POLICY_COMPONENT_IMPLEMENTATION" ]
-
public_deps = [
":cloud_policy_code_generate",
":cloud_policy_proto_generated_compile",
@@ -222,68 +176,6 @@ if (enable_configuration_policy) {
]
}
- group("test_support") {
- public_deps = [
- ":chrome_settings_proto_generated_compile",
- ":policy_component",
- ]
- }
-
- source_set("policy_component_test_support") {
- testonly = true
- sources = [
- "core/browser/configuration_policy_pref_store_test.cc",
- "core/browser/configuration_policy_pref_store_test.h",
- "core/common/cloud/mock_cloud_external_data_manager.cc",
- "core/common/cloud/mock_cloud_external_data_manager.h",
- "core/common/cloud/mock_cloud_policy_client.cc",
- "core/common/cloud/mock_cloud_policy_client.h",
- "core/common/cloud/mock_cloud_policy_store.cc",
- "core/common/cloud/mock_cloud_policy_store.h",
- "core/common/cloud/mock_device_management_service.cc",
- "core/common/cloud/mock_device_management_service.h",
- "core/common/cloud/mock_user_cloud_policy_store.cc",
- "core/common/cloud/mock_user_cloud_policy_store.h",
- "core/common/cloud/policy_builder.cc",
- "core/common/cloud/policy_builder.h",
- "core/common/configuration_policy_provider_test.cc",
- "core/common/configuration_policy_provider_test.h",
- "core/common/fake_async_policy_loader.cc",
- "core/common/fake_async_policy_loader.h",
- "core/common/mock_configuration_policy_provider.cc",
- "core/common/mock_configuration_policy_provider.h",
- "core/common/mock_policy_service.cc",
- "core/common/mock_policy_service.h",
- "core/common/policy_test_utils.cc",
- "core/common/policy_test_utils.h",
- "core/common/preferences_mock_mac.cc",
- "core/common/preferences_mock_mac.h",
- "core/common/remote_commands/test_remote_command_job.cc",
- "core/common/remote_commands/test_remote_command_job.h",
- "core/common/remote_commands/testing_remote_commands_server.cc",
- "core/common/remote_commands/testing_remote_commands_server.h",
- ]
-
- if (is_chromeos) {
- sources -= [
- "core/common/cloud/mock_user_cloud_policy_store.cc",
- "core/common/cloud/mock_user_cloud_policy_store.h",
- ]
- }
-
- public_deps = [
- ":policy",
- ":policy_component",
- ":test_support",
- "//base",
- "//components/policy/proto",
- "//crypto",
- "//net",
- "//testing/gmock",
- "//testing/gtest",
- ]
- }
-
if (is_android) {
import("//build/config/android/rules.gni")
@@ -329,13 +221,20 @@ if (enable_configuration_policy) {
"$target_gen_dir/$chrome_mac_bundle_id.manifest",
]
- args = [
- "xcrun",
- "plutil",
- "-convert",
- "xml1",
- ] + rebase_path(sources, root_out_dir) + [ "-o" ] +
- rebase_path(outputs, root_out_dir)
+ if (use_system_xcode) {
+ args = []
+ } else {
+ args = [
+ "--developer_dir",
+ hermetic_xcode_path,
+ ]
+ }
+ args += [
+ "plutil",
+ "-convert",
+ "xml1",
+ ] + rebase_path(sources, root_out_dir) + [ "-o" ] +
+ rebase_path(outputs, root_out_dir)
deps = [
":policy_templates",
diff --git a/chromium/components/policy/android/BUILD.gn b/chromium/components/policy/android/BUILD.gn
index 7399ba209fc..38cfe5ee81f 100644
--- a/chromium/components/policy/android/BUILD.gn
+++ b/chromium/components/policy/android/BUILD.gn
@@ -9,7 +9,6 @@ _jni_sources = [
"java/src/org/chromium/policy/CombinedPolicyProvider.java",
]
-# GYP: //components/components.gyp:policy_java
android_library("policy_java") {
deps = [
"//base:base_java",
@@ -22,7 +21,6 @@ android_library("policy_java") {
]
}
-# GYP: //components/components.gyp:policy_test_support_java
android_library("policy_java_test_support") {
testonly = true
deps = [
@@ -36,14 +34,12 @@ android_library("policy_java_test_support") {
]
}
-# GYP: //components/components.gyp:policy_jni_headers
generate_jni("jni_headers") {
visibility = [ "//components/policy/*" ]
sources = _jni_sources
jni_package = "policy"
}
-# GYP: //components/components_test.gyp:components_junit_tests
junit_binary("components_policy_junit_tests") {
java_files = [
"junit/src/org/chromium/policy/AbstractAppRestrictionsProviderTest.java",
@@ -54,6 +50,6 @@ junit_binary("components_policy_junit_tests") {
":policy_java",
":policy_java_test_support",
"//base:base_java",
- "//third_party/junit:hamcrest",
+ "//third_party/hamcrest:hamcrest_java",
]
}
diff --git a/chromium/components/policy/core/browser/BUILD.gn b/chromium/components/policy/core/browser/BUILD.gn
index 6ca6451c922..98a06e876e1 100644
--- a/chromium/components/policy/core/browser/BUILD.gn
+++ b/chromium/components/policy/core/browser/BUILD.gn
@@ -4,8 +4,19 @@
import("//build/config/features.gni")
-# GYP version: components/policy.gypi:policy_component_core_browser
-source_set("browser") {
+group("browser") {
+ if (is_component_build) {
+ public_deps = [
+ "//components/policy",
+ ]
+ } else {
+ public_deps = [
+ ":internal",
+ ]
+ }
+}
+
+source_set("internal") {
visibility = [ "//components/policy/*" ]
sources = [
# Note that these sources are always included, even for builds that disable
@@ -15,14 +26,15 @@ source_set("browser") {
"url_blacklist_manager.h",
]
- defines = [ "POLICY_COMPONENT_IMPLEMENTATION" ]
+ configs += [ "//components/policy:component_implementation" ]
- deps = [
+ public_deps = [
"//base",
+ ]
+ deps = [
"//base/third_party/dynamic_annotations",
"//components/bookmarks/managed",
"//components/keyed_service/core",
- "//components/policy/core/common",
"//components/pref_registry",
"//components/prefs",
"//components/strings",
@@ -69,10 +81,9 @@ source_set("browser") {
"url_blacklist_policy_handler.h",
]
+ public_deps += [ "//components/policy/core/common:internal" ]
deps += [
"//components/autofill/core/common",
- "//components/policy",
- "//components/policy/proto",
"//components/proxy_config",
"//google_apis",
"//net",
@@ -82,6 +93,28 @@ source_set("browser") {
}
if (enable_configuration_policy) {
+ static_library("test_support") {
+ testonly = true
+ sources = [
+ "configuration_policy_pref_store_test.cc",
+ "configuration_policy_pref_store_test.h",
+ ]
+
+ public_deps = [
+ ":browser",
+ "//base",
+
+ # Explicitly link in the generated policy target into the test support
+ # so it will be linked to dependent targets. Otherwise in component
+ # build, it will be hidden inside the policy component.
+ "//components/policy:generated",
+ "//components/policy/core/common:test_support",
+ ]
+ deps = [
+ "//testing/gtest",
+ ]
+ }
+
source_set("unit_tests") {
testonly = true
sources = [
@@ -96,10 +129,10 @@ if (enable_configuration_policy) {
"url_blacklist_policy_handler_unittest.cc",
]
deps = [
+ ":test_support",
"//base",
"//components/autofill/core/common",
- "//components/policy",
- "//components/policy:policy_component_test_support",
+ "//components/policy:generated",
"//components/prefs:test_support",
"//components/proxy_config",
"//components/url_formatter",
diff --git a/chromium/components/policy/core/common/BUILD.gn b/chromium/components/policy/core/common/BUILD.gn
index 76471377150..d288700513f 100644
--- a/chromium/components/policy/core/common/BUILD.gn
+++ b/chromium/components/policy/core/common/BUILD.gn
@@ -4,13 +4,22 @@
import("//build/config/features.gni")
-source_set("common") {
- visibility = [
- "//components/policy/*",
- "//components/syncable_prefs/*",
- ]
+group("common") {
+ if (is_component_build) {
+ public_deps = [
+ "//components/policy",
+ ]
+ } else {
+ public_deps = [
+ ":internal",
+ ]
+ }
+}
- defines = [ "POLICY_COMPONENT_IMPLEMENTATION" ]
+source_set("internal") {
+ visibility = [ "//components/policy/*" ]
+
+ configs += [ "//components/policy:component_implementation" ]
if (enable_configuration_policy) {
sources = [
@@ -59,6 +68,7 @@ source_set("common") {
"cloud/policy_header_service.h",
"cloud/resource_cache.cc",
"cloud/resource_cache.h",
+ "cloud/signing_service.h",
"cloud/user_cloud_policy_manager.cc",
"cloud/user_cloud_policy_manager.h",
"cloud/user_cloud_policy_store.cc",
@@ -128,6 +138,7 @@ source_set("common") {
configs += [ "//build/config:precompiled_headers" ]
public_deps = [
+ "//components/policy:generated",
"//components/policy/proto",
]
deps = [
@@ -135,7 +146,6 @@ source_set("common") {
"//base/third_party/dynamic_annotations",
"//components/data_use_measurement/core",
"//components/json_schema",
- "//components/policy",
"//components/prefs",
"//google_apis",
"//net",
@@ -219,11 +229,68 @@ source_set("common") {
}
if (enable_configuration_policy) {
+ static_library("test_support") {
+ testonly = true
+ sources = [
+ "cloud/mock_cloud_external_data_manager.cc",
+ "cloud/mock_cloud_external_data_manager.h",
+ "cloud/mock_cloud_policy_client.cc",
+ "cloud/mock_cloud_policy_client.h",
+ "cloud/mock_cloud_policy_store.cc",
+ "cloud/mock_cloud_policy_store.h",
+ "cloud/mock_device_management_service.cc",
+ "cloud/mock_device_management_service.h",
+ "cloud/mock_signing_service.cc",
+ "cloud/mock_signing_service.h",
+ "cloud/mock_user_cloud_policy_store.cc",
+ "cloud/mock_user_cloud_policy_store.h",
+ "cloud/policy_builder.cc",
+ "cloud/policy_builder.h",
+ "configuration_policy_provider_test.cc",
+ "configuration_policy_provider_test.h",
+ "fake_async_policy_loader.cc",
+ "fake_async_policy_loader.h",
+ "mock_configuration_policy_provider.cc",
+ "mock_configuration_policy_provider.h",
+ "mock_policy_service.cc",
+ "mock_policy_service.h",
+ "policy_test_utils.cc",
+ "policy_test_utils.h",
+ "preferences_mock_mac.cc",
+ "preferences_mock_mac.h",
+ "remote_commands/test_remote_command_job.cc",
+ "remote_commands/test_remote_command_job.h",
+ "remote_commands/testing_remote_commands_server.cc",
+ "remote_commands/testing_remote_commands_server.h",
+ ]
+
+ if (is_chromeos) {
+ sources -= [
+ "cloud/mock_user_cloud_policy_store.cc",
+ "cloud/mock_user_cloud_policy_store.h",
+ ]
+ }
+
+ public_deps = [
+ ":common",
+ "//base",
+
+ # Explicitly link in the generated policy target into the test support
+ # so it will be linked to dependent targets. Otherwise in component
+ # build, it will be hidden inside the policy component.
+ "//components/policy:generated",
+ "//components/policy/proto",
+ "//crypto",
+ "//net",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+ }
+
source_set("unit_tests") {
testonly = true
sources = [
"cloud/cloud_policy_client_unittest.cc",
- "cloud/cloud_policy_constants_unittest.cc",
"cloud/cloud_policy_core_unittest.cc",
"cloud/cloud_policy_manager_unittest.cc",
"cloud/cloud_policy_refresh_scheduler_unittest.cc",
@@ -284,10 +351,10 @@ if (enable_configuration_policy) {
}
deps = [
+ ":test_support",
"//base",
"//base/test:test_support",
- "//components/policy",
- "//components/policy:policy_component_test_support",
+ "//components/policy:generated",
"//components/prefs:test_support",
"//components/prefs:test_support",
"//google_apis",
diff --git a/chromium/components/policy/policy_browser.gypi b/chromium/components/policy/policy_browser.gypi
deleted file mode 100644
index 6b2b6c04634..00000000000
--- a/chromium/components/policy/policy_browser.gypi
+++ /dev/null
@@ -1,84 +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.
-
-{
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../net/net.gyp:net',
- '../ui/base/ui_base.gyp:ui_base',
- '../url/url.gyp:url_lib',
- 'bookmarks_browser',
- 'bookmarks_managed',
- 'components_strings.gyp:components_strings',
- 'keyed_service_core',
- 'pref_registry',
- 'prefs/prefs.gyp:prefs',
- 'url_matcher',
- ],
- 'defines': [
- 'POLICY_COMPONENT_IMPLEMENTATION',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note that these sources are always included, even for builds that
- # disable policy. Most source files should go in the conditional
- # sources list below.
- # url_blacklist_manager.h is used by managed mode.
- 'core/browser/url_blacklist_manager.cc',
- 'core/browser/url_blacklist_manager.h',
- ],
- 'conditions': [
- # GN version: //components/policy/core/browser
- ['configuration_policy==1', {
- 'dependencies': [
- '../third_party/icu/icu.gyp:icui18n',
- '../third_party/icu/icu.gyp:icuuc',
- 'autofill_core_common',
- 'cloud_policy_proto',
- 'policy',
- 'proxy_config',
- ],
- 'sources': [
- 'core/browser/autofill_policy_handler.cc',
- 'core/browser/autofill_policy_handler.h',
- 'core/browser/browser_policy_connector.cc',
- 'core/browser/browser_policy_connector.h',
- 'core/browser/browser_policy_connector_base.cc',
- 'core/browser/browser_policy_connector_base.h',
- 'core/browser/browser_policy_connector_ios.h',
- 'core/browser/browser_policy_connector_ios.mm',
- 'core/browser/cloud/message_util.cc',
- 'core/browser/cloud/message_util.h',
- 'core/browser/configuration_policy_handler.cc',
- 'core/browser/configuration_policy_handler.h',
- 'core/browser/configuration_policy_handler_list.cc',
- 'core/browser/configuration_policy_handler_list.h',
- 'core/browser/configuration_policy_pref_store.cc',
- 'core/browser/configuration_policy_pref_store.h',
- 'core/browser/policy_error_map.cc',
- 'core/browser/policy_error_map.h',
- 'core/browser/proxy_policy_handler.cc',
- 'core/browser/proxy_policy_handler.h',
- 'core/browser/url_blacklist_policy_handler.cc',
- 'core/browser/url_blacklist_policy_handler.h',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'sources': [
- 'core/browser/android/android_combined_policy_provider.cc',
- 'core/browser/android/android_combined_policy_provider.h',
- 'core/browser/android/component_jni_registrar.cc',
- 'core/browser/android/component_jni_registrar.h',
- 'core/browser/android/policy_converter.cc',
- 'core/browser/android/policy_converter.h',
- ],
- 'dependencies': [ 'policy_jni_headers' ]
- }]
- ]
- }],
- ],
-}
diff --git a/chromium/components/policy/policy_common.gypi b/chromium/components/policy/policy_common.gypi
deleted file mode 100644
index e808ab9ac48..00000000000
--- a/chromium/components/policy/policy_common.gypi
+++ /dev/null
@@ -1,238 +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.
-
-{
- # GN version: //components/policy/core/common
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'defines': [
- 'POLICY_COMPONENT_IMPLEMENTATION',
- ],
- 'include_dirs': [
- '..',
- ],
- 'conditions': [
- ['configuration_policy==1', {
- 'dependencies': [
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../third_party/re2/re2.gyp:re2',
- '../url/url.gyp:url_lib',
- 'cloud_policy_proto',
- 'data_use_measurement_core',
- 'json_schema',
- 'policy',
- 'prefs/prefs.gyp:prefs',
- ],
- 'sources': [
- 'core/common/async_policy_loader.cc',
- 'core/common/async_policy_loader.h',
- 'core/common/async_policy_provider.cc',
- 'core/common/async_policy_provider.h',
- 'core/common/cloud/cloud_external_data_manager.cc',
- 'core/common/cloud/cloud_external_data_manager.h',
- 'core/common/cloud/cloud_policy_client.cc',
- 'core/common/cloud/cloud_policy_client.h',
- 'core/common/cloud/cloud_policy_client_registration_helper.cc',
- 'core/common/cloud/cloud_policy_client_registration_helper.h',
- 'core/common/cloud/cloud_policy_constants.cc',
- 'core/common/cloud/cloud_policy_constants.h',
- 'core/common/cloud/cloud_policy_core.cc',
- 'core/common/cloud/cloud_policy_core.h',
- 'core/common/cloud/cloud_policy_manager.cc',
- 'core/common/cloud/cloud_policy_manager.h',
- 'core/common/cloud/cloud_policy_refresh_scheduler.cc',
- 'core/common/cloud/cloud_policy_refresh_scheduler.h',
- 'core/common/cloud/cloud_policy_service.cc',
- 'core/common/cloud/cloud_policy_service.h',
- 'core/common/cloud/cloud_policy_store.cc',
- 'core/common/cloud/cloud_policy_store.h',
- 'core/common/cloud/cloud_policy_validator.cc',
- 'core/common/cloud/cloud_policy_validator.h',
- 'core/common/cloud/component_cloud_policy_service.cc',
- 'core/common/cloud/component_cloud_policy_service.h',
- 'core/common/cloud/component_cloud_policy_store.cc',
- 'core/common/cloud/component_cloud_policy_store.h',
- 'core/common/cloud/component_cloud_policy_updater.cc',
- 'core/common/cloud/component_cloud_policy_updater.h',
- 'core/common/cloud/device_management_service.cc',
- 'core/common/cloud/device_management_service.h',
- 'core/common/cloud/enterprise_metrics.cc',
- 'core/common/cloud/enterprise_metrics.h',
- 'core/common/cloud/external_policy_data_fetcher.cc',
- 'core/common/cloud/external_policy_data_fetcher.h',
- 'core/common/cloud/external_policy_data_updater.cc',
- 'core/common/cloud/external_policy_data_updater.h',
- 'core/common/cloud/policy_header_io_helper.cc',
- 'core/common/cloud/policy_header_io_helper.h',
- 'core/common/cloud/policy_header_service.cc',
- 'core/common/cloud/policy_header_service.h',
- 'core/common/cloud/resource_cache.cc',
- 'core/common/cloud/resource_cache.h',
- 'core/common/cloud/user_cloud_policy_manager.cc',
- 'core/common/cloud/user_cloud_policy_manager.h',
- 'core/common/cloud/user_cloud_policy_store.cc',
- 'core/common/cloud/user_cloud_policy_store.h',
- 'core/common/cloud/user_cloud_policy_store_base.cc',
- 'core/common/cloud/user_cloud_policy_store_base.h',
- 'core/common/cloud/user_info_fetcher.cc',
- 'core/common/cloud/user_info_fetcher.h',
- 'core/common/config_dir_policy_loader.cc',
- 'core/common/config_dir_policy_loader.h',
- 'core/common/configuration_policy_provider.cc',
- 'core/common/configuration_policy_provider.h',
- 'core/common/external_data_fetcher.cc',
- 'core/common/external_data_fetcher.h',
- 'core/common/external_data_manager.h',
- 'core/common/mac_util.cc',
- 'core/common/mac_util.h',
- 'core/common/policy_bundle.cc',
- 'core/common/policy_bundle.h',
- 'core/common/policy_details.h',
- 'core/common/policy_load_status.cc',
- 'core/common/policy_load_status.h',
- 'core/common/policy_loader_ios.h',
- 'core/common/policy_loader_ios.mm',
- 'core/common/policy_loader_mac.h',
- 'core/common/policy_loader_mac.mm',
- 'core/common/policy_loader_win.cc',
- 'core/common/policy_loader_win.h',
- 'core/common/policy_map.cc',
- 'core/common/policy_map.h',
- 'core/common/policy_namespace.cc',
- 'core/common/policy_namespace.h',
- 'core/common/policy_pref_names.cc',
- 'core/common/policy_pref_names.h',
- 'core/common/policy_service.cc',
- 'core/common/policy_service.h',
- 'core/common/policy_service_impl.cc',
- 'core/common/policy_service_impl.h',
- 'core/common/policy_statistics_collector.cc',
- 'core/common/policy_statistics_collector.h',
- 'core/common/policy_switches.cc',
- 'core/common/policy_switches.h',
- 'core/common/policy_types.h',
- 'core/common/preferences_mac.cc',
- 'core/common/preferences_mac.h',
- 'core/common/preg_parser_win.cc',
- 'core/common/preg_parser_win.h',
- 'core/common/registry_dict_win.cc',
- 'core/common/registry_dict_win.h',
- 'core/common/remote_commands/remote_command_job.cc',
- 'core/common/remote_commands/remote_command_job.h',
- 'core/common/remote_commands/remote_commands_factory.cc',
- 'core/common/remote_commands/remote_commands_factory.h',
- 'core/common/remote_commands/remote_commands_queue.cc',
- 'core/common/remote_commands/remote_commands_queue.h',
- 'core/common/remote_commands/remote_commands_service.cc',
- 'core/common/remote_commands/remote_commands_service.h',
- 'core/common/schema.cc',
- 'core/common/schema.h',
- 'core/common/schema_internal.h',
- 'core/common/schema_map.cc',
- 'core/common/schema_map.h',
- 'core/common/schema_registry.cc',
- 'core/common/schema_registry.h',
- 'core/common/schema_registry_tracking_policy_provider.cc',
- 'core/common/schema_registry_tracking_policy_provider.h',
- 'policy_export.h',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'sources!': [
- 'core/common/async_policy_loader.cc',
- 'core/common/async_policy_loader.h',
- 'core/common/async_policy_provider.cc',
- 'core/common/async_policy_provider.h',
- ],
- }],
- ['OS=="android" or OS=="ios"', {
- 'sources': [
- 'core/common/cloud/component_cloud_policy_service_stub.cc',
- ],
- 'sources!': [
- 'core/common/cloud/component_cloud_policy_service.cc',
- 'core/common/cloud/component_cloud_policy_store.cc',
- 'core/common/cloud/component_cloud_policy_store.h',
- 'core/common/cloud/component_cloud_policy_updater.cc',
- 'core/common/cloud/component_cloud_policy_updater.h',
- 'core/common/cloud/external_policy_data_fetcher.cc',
- 'core/common/cloud/external_policy_data_fetcher.h',
- 'core/common/cloud/external_policy_data_updater.cc',
- 'core/common/cloud/external_policy_data_updater.h',
- 'core/common/cloud/resource_cache.cc',
- 'core/common/cloud/resource_cache.h',
- 'core/common/config_dir_policy_loader.cc',
- 'core/common/config_dir_policy_loader.h',
- 'core/common/policy_load_status.cc',
- 'core/common/policy_load_status.h',
- ],
- }],
- ['chromeos==1', {
- 'sources': [
- 'core/common/proxy_policy_provider.cc',
- 'core/common/proxy_policy_provider.h',
- ],
- 'sources!': [
- 'core/common/cloud/cloud_policy_client_registration_helper.cc',
- 'core/common/cloud/cloud_policy_client_registration_helper.h',
- 'core/common/cloud/user_cloud_policy_manager.cc',
- 'core/common/cloud/user_cloud_policy_manager.h',
- 'core/common/cloud/user_cloud_policy_store.cc',
- 'core/common/cloud/user_cloud_policy_store.h',
- ],
- }],
- ['OS!="ios" and OS!="mac"', {
- 'sources!': [
- 'core/common/mac_util.cc',
- 'core/common/mac_util.h',
- ],
- }],
- ['OS=="win"', {
- 'all_dependent_settings': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'shlwapi.lib',
- 'userenv.lib',
- 'ntdsapi.lib',
- ],
- },
- },
- },
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'shlwapi.lib',
- 'userenv.lib',
- 'ntdsapi.lib',
- ],
- },
- },
- }],
- ],
- }, { # configuration_policy==0
- # Some of the policy code is always enabled, so that other parts of
- # Chrome can always interface with the PolicyService without having
- # to #ifdef.
- 'sources': [
- 'core/common/external_data_fetcher.cc',
- 'core/common/external_data_fetcher.h',
- 'core/common/external_data_manager.h',
- 'core/common/policy_map.cc',
- 'core/common/policy_map.h',
- 'core/common/policy_namespace.cc',
- 'core/common/policy_namespace.h',
- 'core/common/policy_pref_names.cc',
- 'core/common/policy_pref_names.h',
- 'core/common/policy_service.cc',
- 'core/common/policy_service.h',
- 'core/common/policy_service_stub.cc',
- 'core/common/policy_service_stub.h',
- ],
- }],
- ],
-}
diff --git a/chromium/components/policy/proto/BUILD.gn b/chromium/components/policy/proto/BUILD.gn
index c1b56c7798f..0fc12e082d0 100644
--- a/chromium/components/policy/proto/BUILD.gn
+++ b/chromium/components/policy/proto/BUILD.gn
@@ -28,9 +28,8 @@ proto_library("proto_internal") {
sources += [ "device_management_local.proto" ]
}
- proto_out_dir = "policy/proto"
cc_generator_options = "dllexport_decl=POLICY_PROTO_EXPORT:"
- cc_include = "components/policy/policy_proto_export.h"
+ cc_include = "components/policy/proto/policy_proto_export.h"
component_build_force_source_set = true
defines = [ "POLICY_PROTO_COMPILATION" ]
}
diff --git a/chromium/components/policy_strings.grdp b/chromium/components/policy_strings.grdp
index 1876a68c60e..973ff0923aa 100644
--- a/chromium/components/policy_strings.grdp
+++ b/chromium/components/policy_strings.grdp
@@ -52,12 +52,15 @@
<message name="IDS_POLICY_DM_STATUS_SERVICE_DOMAIN_MISMATCH" desc="Message indicating this client cannot be registered with the specified domain.">
Domain mismatch
</message>
+ <message name="IDS_POLICY_DM_STATUS_CANNOT_SIGN_REQUEST" desc="Message indicating a failure to sign a request.">
+ Request could not be signed
+ </message>
<message name="IDS_POLICY_VALIDATION_OK" desc="Message indicating successful policy validation.">
Validation successful
</message>
<message name="IDS_POLICY_VALIDATION_BAD_INITIAL_SIGNATURE" desc="Message indicating a bad signature on policy validation using the initial key.">
- Bad intial signature
+ Bad initial signature
</message>
<message name="IDS_POLICY_VALIDATION_BAD_SIGNATURE" desc="Message indicating a bad signature on policy validation.">
Bad signature
@@ -77,8 +80,11 @@
<message name="IDS_POLICY_VALIDATION_BAD_TIMESTAMP" desc="Message indicating the policy timestamp is bad.">
Bad policy timestamp
</message>
- <message name="IDS_POLICY_VALIDATION_WRONG_TOKEN" desc="Message indicating the policy token is different from the one expected.">
- Returned policy token doesn't match current token
+ <message name="IDS_POLICY_VALIDATION_BAD_DM_TOKEN" desc="Message indicating the policy token is empty or different from the one expected.">
+ Returned policy token is empty or doesn't match current token
+ </message>
+ <message name="IDS_POLICY_VALIDATION_BAD_DEVICE_ID" desc="Message indicating the policy device id is empty or different from the one expected.">
+ Returned policy device id is empty or doesn't match current device id
</message>
<message name="IDS_POLICY_VALIDATION_BAD_USERNAME" desc="Message indicating policy validation failed due to bad username/domain.">
Wrong policy subject
@@ -228,6 +234,9 @@
<message name="IDS_POLICY_RELOAD_POLICIES" desc="Label for the button that reloads policies.">
Reload policies
</message>
+ <message name="IDS_POLICY_CHROME_FOR_WORK" desc="Title of the link to the chrome for work website.">
+ Using Chrome at work? Businesses can manage Chrome settings for their employees. Learn more
+ </message>
<message name="IDS_POLICY_STATUS" desc="Title of the status section.">
Status
</message>
diff --git a/chromium/components/power.gypi b/chromium/components/power.gypi
deleted file mode 100644
index a1757a0cd0f..00000000000
--- a/chromium/components/power.gypi
+++ /dev/null
@@ -1,25 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'power',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- 'keyed_service_content',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'power/origin_power_map.cc',
- 'power/origin_power_map.h',
- 'power/origin_power_map_factory.cc',
- 'power/origin_power_map_factory.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/power/BUILD.gn b/chromium/components/power/BUILD.gn
index c0aa6514aba..e8c347ec75d 100644
--- a/chromium/components/power/BUILD.gn
+++ b/chromium/components/power/BUILD.gn
@@ -26,6 +26,7 @@ source_set("unit_tests") {
]
deps = [
":power",
+ "//base",
"//testing/gtest",
]
}
diff --git a/chromium/components/power/origin_power_map.cc b/chromium/components/power/origin_power_map.cc
index c4b895fa539..10502e9d6db 100644
--- a/chromium/components/power/origin_power_map.cc
+++ b/chromium/components/power/origin_power_map.cc
@@ -4,6 +4,8 @@
#include "components/power/origin_power_map.h"
+#include <algorithm>
+
#include "base/logging.h"
#include "content/public/common/url_constants.h"
#include "url/gurl.h"
@@ -59,9 +61,27 @@ void OriginPowerMap::OnAllOriginsUpdated() {
callback_list_.Notify();
}
-void OriginPowerMap::ClearOriginMap() {
- origin_map_.clear();
- total_consumed_ = 0;
+void OriginPowerMap::ClearOriginMap(
+ const base::Callback<bool(const GURL&)> url_filter) {
+ if (url_filter.is_null()) {
+ origin_map_.clear();
+ } else {
+ for (auto it = origin_map_.begin(); it != origin_map_.end();) {
+ auto next_it = std::next(it);
+
+ if (url_filter.Run(it->first)) {
+ total_consumed_ -= it->second;
+ origin_map_.erase(it);
+ }
+
+ it = next_it;
+ }
+ }
+
+ // Handle the empty case separately to avoid reporting nonzero power usage
+ // for zero origins in case of double rounding errors.
+ if (origin_map_.empty())
+ total_consumed_ = 0;
}
} // namespace power
diff --git a/chromium/components/power/origin_power_map.h b/chromium/components/power/origin_power_map.h
index 514e5b28400..362c023b239 100644
--- a/chromium/components/power/origin_power_map.h
+++ b/chromium/components/power/origin_power_map.h
@@ -45,8 +45,9 @@ class OriginPowerMap : public KeyedService {
// updating for all origins this cycle.
void OnAllOriginsUpdated();
- // Clears all URLs out of the map.
- void ClearOriginMap();
+ // Clears URLs out of the map. If |url_filter| is not null, only clears those
+ // URLs that are matched by it.
+ void ClearOriginMap(const base::Callback<bool(const GURL&)> url_filter);
private:
// OriginMap maps a URL to the amount of power consumed by the URL using the
diff --git a/chromium/components/power/origin_power_map_unittest.cc b/chromium/components/power/origin_power_map_unittest.cc
index fad9490f63e..15899682b00 100644
--- a/chromium/components/power/origin_power_map_unittest.cc
+++ b/chromium/components/power/origin_power_map_unittest.cc
@@ -6,8 +6,17 @@
#include <stddef.h>
+#include "base/bind.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace {
+
+bool HostFilter(const std::string& host, const GURL& url) {
+ return url.host() == host;
+}
+
+} // namespace
+
namespace power {
TEST(OriginPowerMapTest, StartEmpty) {
@@ -67,4 +76,58 @@ TEST(OriginPowerMapTest, EmptyPercentOriginMapWhenZeroConsumed) {
EXPECT_EQ(size_t(0), origin_power_map.GetPercentOriginMap().size());
}
+TEST(OriginPowerMapTest, ClearOriginMap) {
+ GURL url1("https://www.google.com");
+ GURL url2("https://www.chrome.com");
+ GURL url3("https://www.example.com");
+ GURL url4("http://www.chrome.com");
+ GURL url5("http://www.example.com");
+
+ // Add all 5 URLs to the map.
+ OriginPowerMap origin_power_map;
+ origin_power_map.AddPowerForOrigin(url1, 50);
+ origin_power_map.AddPowerForOrigin(url2, 20);
+ origin_power_map.AddPowerForOrigin(url3, 15);
+ origin_power_map.AddPowerForOrigin(url4, 5);
+ origin_power_map.AddPowerForOrigin(url5, 10);
+ EXPECT_DOUBLE_EQ(50, origin_power_map.GetPowerForOrigin(url1));
+ EXPECT_DOUBLE_EQ(20, origin_power_map.GetPowerForOrigin(url2));
+ EXPECT_DOUBLE_EQ(15, origin_power_map.GetPowerForOrigin(url3));
+ EXPECT_DOUBLE_EQ(5, origin_power_map.GetPowerForOrigin(url4));
+ EXPECT_DOUBLE_EQ(10, origin_power_map.GetPowerForOrigin(url5));
+
+ // Delete |url1|.
+ origin_power_map.ClearOriginMap(
+ base::Bind(&GURL::operator==, base::Unretained(&url1)));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url1));
+ EXPECT_DOUBLE_EQ(40, origin_power_map.GetPowerForOrigin(url2));
+ EXPECT_DOUBLE_EQ(30, origin_power_map.GetPowerForOrigin(url3));
+ EXPECT_DOUBLE_EQ(10, origin_power_map.GetPowerForOrigin(url4));
+ EXPECT_DOUBLE_EQ(20, origin_power_map.GetPowerForOrigin(url5));
+
+ // Delete every URL with the host "www.chrome.com", i.e. |url2| and |url4|.
+ origin_power_map.ClearOriginMap(base::Bind(&HostFilter, "www.chrome.com"));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url1));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url2));
+ EXPECT_DOUBLE_EQ(60, origin_power_map.GetPowerForOrigin(url3));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url4));
+ EXPECT_DOUBLE_EQ(40, origin_power_map.GetPowerForOrigin(url5));
+
+ // Delete every URL with the host "www.example.org". There should be none.
+ origin_power_map.ClearOriginMap(base::Bind(&HostFilter, "www.example.org"));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url1));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url2));
+ EXPECT_DOUBLE_EQ(60, origin_power_map.GetPowerForOrigin(url3));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url4));
+ EXPECT_DOUBLE_EQ(40, origin_power_map.GetPowerForOrigin(url5));
+
+ // Null callback means complete deletion.
+ origin_power_map.ClearOriginMap(base::Callback<bool(const GURL&)>());
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url1));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url2));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url3));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url4));
+ EXPECT_DOUBLE_EQ(0, origin_power_map.GetPowerForOrigin(url5));
+}
+
} // namespace power
diff --git a/chromium/components/precache.gypi b/chromium/components/precache.gypi
deleted file mode 100644
index fd3298ba080..00000000000
--- a/chromium/components/precache.gypi
+++ /dev/null
@@ -1,107 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/precache/core
- 'target_name': 'precache_core',
- 'type': 'static_library',
- 'dependencies': [
- 'precache_core_proto',
- '../base/base.gyp:base',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'precache/core/fetcher_pool.h',
- 'precache/core/precache_database.cc',
- 'precache/core/precache_database.h',
- 'precache/core/precache_fetcher.cc',
- 'precache/core/precache_fetcher.h',
- 'precache/core/precache_switches.cc',
- 'precache/core/precache_switches.h',
- 'precache/core/precache_session_table.cc',
- 'precache/core/precache_session_table.h',
- 'precache/core/precache_url_table.cc',
- 'precache/core/precache_url_table.h',
- ],
- 'includes': [ 'precache/precache_defines.gypi', ],
- 'direct_dependent_settings': {
- # Make direct dependents also include the precache defines. This allows
- # the unit tests to use these defines.
- 'includes': [ 'precache/precache_defines.gypi', ],
- },
- },
- {
- # GN version: //components/precache/core:proto
- 'target_name': 'precache_core_proto',
- 'type': 'static_library',
- 'sources': [
- 'precache/core/proto/precache.proto',
- 'precache/core/proto/unfinished_work.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'precache/core/proto',
- 'proto_out_dir': 'components/precache/core/proto',
- },
- 'includes': [ '../build/protoc.gypi', ],
- },
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'targets': [
- {
- # GN Version: //components/precache/content
- 'target_name': 'precache_content',
- 'type': 'static_library',
- 'dependencies': [
- 'precache_core',
- 'precache_core_proto',
- '../base/base.gyp:base',
- '../components/components.gyp:sync_driver',
- '../content/content.gyp:content_browser',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'precache/content/precache_manager.cc',
- 'precache/content/precache_manager.h',
- ],
- },
- ],
- }],
- ['OS=="android"', {
- 'targets': [{
- 'target_name': 'precache_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_java',
- ],
- 'variables': {
- 'java_in_dir': 'precache/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- }, {
- 'target_name': 'precache_javatests',
- 'type': 'none',
- 'dependencies': [
- 'precache_java',
- '../base/base.gyp:base_java_test_support',
- ],
- 'variables': {
- 'java_in_dir': 'precache/android/javatests',
- },
- 'includes': [ '../build/java.gypi' ],
- }],
- }],
- ],
-}
diff --git a/chromium/components/precache/DEPS b/chromium/components/precache/DEPS
index 81775b5e6f0..975943c97a9 100644
--- a/chromium/components/precache/DEPS
+++ b/chromium/components/precache/DEPS
@@ -2,6 +2,7 @@ include_rules = [
# Precache is a layered component; subdirectories must introduce the ability
# to use the content layer explicitly as appropriate.
# http://www.chromium.org/developers/design-documents/layered-components-design
+ "+components/data_use_measurement/core",
"-components/precache",
"+components/precache/core",
diff --git a/chromium/components/precache/OWNERS b/chromium/components/precache/OWNERS
index ced90566ffb..2916ba21371 100644
--- a/chromium/components/precache/OWNERS
+++ b/chromium/components/precache/OWNERS
@@ -1,3 +1,4 @@
bengr@chromium.org
+rajendrant@chromium.org
sclittle@chromium.org
twifkak@chromium.org
diff --git a/chromium/components/precache/android/BUILD.gn b/chromium/components/precache/android/BUILD.gn
index 27a5b8d412b..d0becc03248 100644
--- a/chromium/components/precache/android/BUILD.gn
+++ b/chromium/components/precache/android/BUILD.gn
@@ -4,7 +4,6 @@
import("//build/config/android/rules.gni")
-# GYP: //components/precache.gypi:precache_java
android_library("precache_java") {
deps = [
"//base:base_java",
@@ -17,6 +16,7 @@ android_library("precache_java") {
}
android_library("precache_javatests") {
+ testonly = true
deps = [
":precache_java",
"//base:base_java_test_support",
diff --git a/chromium/components/precache/content/BUILD.gn b/chromium/components/precache/content/BUILD.gn
index f3cc0a7a97c..53f9b519e36 100644
--- a/chromium/components/precache/content/BUILD.gn
+++ b/chromium/components/precache/content/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("content") {
+static_library("content") {
sources = [
"precache_manager.cc",
"precache_manager.h",
@@ -17,7 +17,7 @@ source_set("content") {
"//components/precache/core",
"//components/precache/core:proto",
"//components/prefs",
- "//components/sync_driver",
+ "//components/sync",
"//components/variations",
"//content/public/browser",
"//net",
diff --git a/chromium/components/precache/content/DEPS b/chromium/components/precache/content/DEPS
index 235cc527d15..25f55a1ece6 100644
--- a/chromium/components/precache/content/DEPS
+++ b/chromium/components/precache/content/DEPS
@@ -1,6 +1,6 @@
include_rules = [
"+components/keyed_service",
- "+components/sync_driver",
+ "+components/sync/driver",
"+components/variations",
"+content/public/browser",
"+net/base",
diff --git a/chromium/components/precache/content/precache_manager.cc b/chromium/components/precache/content/precache_manager.cc
index ac1f5a6fce5..f4333c12d64 100644
--- a/chromium/components/precache/content/precache_manager.cc
+++ b/chromium/components/precache/content/precache_manager.cc
@@ -19,7 +19,7 @@
#include "components/precache/core/precache_switches.h"
#include "components/precache/core/proto/unfinished_work.pb.h"
#include "components/prefs/pref_service.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_service.h"
#include "components/variations/metrics_util.h"
#include "components/variations/variations_associated_data.h"
#include "content/public/browser/browser_context.h"
@@ -48,7 +48,7 @@ size_t NumTopHosts() {
PrecacheManager::PrecacheManager(
content::BrowserContext* browser_context,
- const sync_driver::SyncService* const sync_service,
+ const syncer::SyncService* const sync_service,
const history::HistoryService* const history_service,
const base::FilePath& db_path,
std::unique_ptr<PrecacheDatabase> precache_database)
@@ -123,6 +123,11 @@ void PrecacheManager::StartPrecaching(
precache_completion_callback_ = precache_completion_callback;
is_precaching_ = true;
+ BrowserThread::PostTask(
+ BrowserThread::DB, FROM_HERE,
+ base::Bind(&PrecacheDatabase::SetLastPrecacheTimestamp,
+ base::Unretained(precache_database_.get()),
+ base::Time::Now()));
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::DB,
FROM_HERE,
@@ -133,16 +138,19 @@ void PrecacheManager::StartPrecaching(
void PrecacheManager::OnGetUnfinishedWorkDone(
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work) {
- if (!unfinished_work->has_start_time() ||
- base::Time::Now() - base::Time::FromInternalValue(
- unfinished_work->start_time()) > base::TimeDelta::FromHours(6)) {
+ // Reset progress on a prefetch that has taken too long to complete.
+ if (unfinished_work->has_start_time() &&
+ base::Time::Now() -
+ base::Time::FromInternalValue(unfinished_work->start_time()) >
+ base::TimeDelta::FromHours(6)) {
PrecacheFetcher::RecordCompletionStatistics(
- *unfinished_work,
- unfinished_work->manifest_size(),
+ *unfinished_work, unfinished_work->top_host_size(),
unfinished_work->resource_size());
- unfinished_work.reset(new PrecacheUnfinishedWork());
- unfinished_work->set_start_time(base::Time::Now().ToInternalValue());
+ unfinished_work.reset(new PrecacheUnfinishedWork);
}
+ // If this prefetch is new, set the start time.
+ if (!unfinished_work->has_start_time())
+ unfinished_work->set_start_time(base::Time::Now().ToInternalValue());
unfinished_work_ = std::move(unfinished_work);
bool needs_top_hosts = unfinished_work_->top_host_size() == 0;
@@ -246,12 +254,14 @@ void PrecacheManager::RecordStatsForFetch(const GURL& url,
return;
history_service_->HostRankIfAvailable(
- referrer, base::Bind(&PrecacheManager::RecordStatsForFetchInternal,
- AsWeakPtr(), url, latency, fetch_time, info, size));
+ referrer,
+ base::Bind(&PrecacheManager::RecordStatsForFetchInternal, AsWeakPtr(),
+ url, referrer.host(), latency, fetch_time, info, size));
}
void PrecacheManager::RecordStatsForFetchInternal(
const GURL& url,
+ const std::string& referrer_host,
const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
@@ -265,9 +275,8 @@ void PrecacheManager::RecordStatsForFetchInternal(
// by precaching.
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
- base::Bind(&PrecacheDatabase::RecordURLPrefetch,
- base::Unretained(precache_database_.get()), url, latency,
- fetch_time, info, size));
+ base::Bind(&PrecacheDatabase::RecordURLPrefetchMetrics,
+ base::Unretained(precache_database_.get()), info, latency));
} else {
bool is_connection_cellular =
net::NetworkChangeNotifier::IsConnectionCellular(
@@ -315,9 +324,11 @@ void PrecacheManager::OnHostsReceived(
const history::TopHostsList& host_counts) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- std::vector<std::string> hosts;
- for (const auto& host_count : host_counts)
- unfinished_work_->add_top_host()->set_hostname(host_count.first);
+ for (const auto& host_count : host_counts) {
+ TopHost* top_host = unfinished_work_->add_top_host();
+ top_host->set_hostname(host_count.first);
+ top_host->set_visits(host_count.second);
+ }
InitializeAndStartFetcher();
}
@@ -338,6 +349,9 @@ void PrecacheManager::InitializeAndStartFetcher() {
std::move(unfinished_work_),
metrics::HashName(
base::FieldTrialList::FindFullName(kPrecacheFieldTrialName)),
+ precache_database_->GetWeakPtr(),
+ content::BrowserThread::GetTaskRunnerForThread(
+ content::BrowserThread::DB),
this));
precache_fetcher_->Start();
}
diff --git a/chromium/components/precache/content/precache_manager.h b/chromium/components/precache/content/precache_manager.h
index 0c1dc18e753..e6bcc8094ab 100644
--- a/chromium/components/precache/content/precache_manager.h
+++ b/chromium/components/precache/content/precache_manager.h
@@ -41,7 +41,7 @@ namespace net {
class HttpResponseInfo;
}
-namespace sync_driver {
+namespace syncer {
class SyncService;
}
@@ -67,7 +67,7 @@ class PrecacheManager : public KeyedService,
typedef base::Callback<void(bool)> PrecacheCompletionCallback;
PrecacheManager(content::BrowserContext* browser_context,
- const sync_driver::SyncService* const sync_service,
+ const syncer::SyncService* const sync_service,
const history::HistoryService* const history_service,
const base::FilePath& db_path,
std::unique_ptr<PrecacheDatabase> precache_database);
@@ -117,6 +117,7 @@ class PrecacheManager : public KeyedService,
bool is_user_traffic);
private:
+ friend class PrecacheManagerTest;
FRIEND_TEST_ALL_PREFIXES(PrecacheManagerTest, DeleteExpiredPrecacheHistory);
FRIEND_TEST_ALL_PREFIXES(PrecacheManagerTest,
RecordStatsForFetchDuringPrecaching);
@@ -169,6 +170,7 @@ class PrecacheManager : public KeyedService,
// Update precache-related metrics in response to a URL being fetched. Called
// by RecordStatsForFetch() by way of an asynchronous HistoryService callback.
void RecordStatsForFetchInternal(const GURL& url,
+ const std::string& referrer_host,
const base::TimeDelta& latency,
const base::Time& fetch_time,
const net::HttpResponseInfo& info,
@@ -180,7 +182,7 @@ class PrecacheManager : public KeyedService,
// The sync service corresponding to the browser context. Used to determine
// whether precache can run. May be null.
- const sync_driver::SyncService* const sync_service_;
+ const syncer::SyncService* const sync_service_;
// The history service corresponding to the browser context. Used to determine
// the list of top hosts. May be null.
diff --git a/chromium/components/precache/content/precache_manager_unittest.cc b/chromium/components/precache/content/precache_manager_unittest.cc
index b13b7aea3cc..b35d1c0c3a3 100644
--- a/chromium/components/precache/content/precache_manager_unittest.cc
+++ b/chromium/components/precache/content/precache_manager_unittest.cc
@@ -127,17 +127,17 @@ class TestPrecacheCompletionCallback {
class PrecacheManagerUnderTest : public PrecacheManager {
public:
- PrecacheManagerUnderTest(
- content::BrowserContext* browser_context,
- const sync_driver::SyncService* const sync_service,
- const history::HistoryService* const history_service,
- const base::FilePath& db_path,
- std::unique_ptr<PrecacheDatabase> precache_database)
- : PrecacheManager(
- browser_context, sync_service, history_service,
- db_path, std::move(precache_database)),
- control_group_(false) {
- }
+ PrecacheManagerUnderTest(content::BrowserContext* browser_context,
+ const syncer::SyncService* const sync_service,
+ const history::HistoryService* const history_service,
+ const base::FilePath& db_path,
+ std::unique_ptr<PrecacheDatabase> precache_database)
+ : PrecacheManager(browser_context,
+ sync_service,
+ history_service,
+ db_path,
+ std::move(precache_database)),
+ control_group_(false) {}
bool IsInExperimentGroup() const override { return !control_group_; }
bool IsInControlGroup() const override { return control_group_; }
bool IsPrecachingAllowed() const override { return true; }
@@ -178,7 +178,7 @@ class PrecacheManagerTest : public testing::Test {
precache_database_ = precache_database.get();
ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
- base::FilePath db_path = scoped_temp_dir_.path().Append(
+ base::FilePath db_path = scoped_temp_dir_.GetPath().Append(
base::FilePath(FILE_PATH_LITERAL("precache_database")));
// Make the fetch of the precache configuration settings fail. Precaching
@@ -195,6 +195,18 @@ class PrecacheManagerTest : public testing::Test {
info_.headers = new net::HttpResponseHeaders("");
}
+ void RecordStatsForPrecacheFetch(const GURL& url,
+ const std::string& referrer_host,
+ const base::TimeDelta& latency,
+ const base::Time& fetch_time,
+ const net::HttpResponseInfo& info,
+ int64_t size) {
+ precache_manager_->RecordStatsForFetch(url, GURL(referrer_host), latency,
+ fetch_time, info, size);
+ precache_database_->RecordURLPrefetch(url, referrer_host, fetch_time,
+ info.was_cached, size);
+ }
+
// Must be declared first so that it is destroyed last.
content::TestBrowserThreadBundle test_browser_thread_bundle_;
base::ScopedTempDir scoped_temp_dir_;
@@ -216,6 +228,8 @@ TEST_F(PrecacheManagerTest, StartAndFinishPrecaching) {
EXPECT_CALL(history_service_, TopHosts(NumTopHosts(), _))
.WillOnce(SaveArg<1>(&top_hosts_callback));
+ factory_.SetFakeResponse(GURL(kConfigURL), "", net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
factory_.SetFakeResponse(GURL(kGoodManifestURL), "", net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
@@ -244,10 +258,14 @@ TEST_F(PrecacheManagerTest, StartAndFinishPrecachingWithUnfinishedHosts) {
EXPECT_FALSE(precache_manager_->IsPrecaching());
+ factory_.SetFakeResponse(GURL(kConfigURL), "", net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
factory_.SetFakeResponse(
GURL(kEvilManifestURL), "",
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ ASSERT_TRUE(precache_database_->GetLastPrecacheTimestamp().is_null());
+
precache_manager_->StartPrecaching(precache_callback_.GetCallback());
EXPECT_TRUE(precache_manager_->IsPrecaching());
@@ -255,6 +273,9 @@ TEST_F(PrecacheManagerTest, StartAndFinishPrecachingWithUnfinishedHosts) {
EXPECT_FALSE(precache_manager_->IsPrecaching());
EXPECT_TRUE(precache_callback_.was_on_done_called());
+ // The LastPrecacheTimestamp has been set.
+ EXPECT_FALSE(precache_database_->GetLastPrecacheTimestamp().is_null());
+
std::multiset<GURL> expected_requested_urls;
expected_requested_urls.insert(GURL(kConfigURL));
expected_requested_urls.insert(GURL(kEvilManifestURL));
@@ -384,9 +405,8 @@ TEST_F(PrecacheManagerTest, RecordStatsForFetchDuringPrecaching) {
precache_manager_->StartPrecaching(precache_callback_.GetCallback());
EXPECT_TRUE(precache_manager_->IsPrecaching());
- precache_manager_->RecordStatsForFetch(GURL("http://url.com"), GURL(),
- base::TimeDelta(), base::Time(), info_,
- 1000);
+ RecordStatsForPrecacheFetch(GURL("http://url.com"), std::string(),
+ base::TimeDelta(), base::Time(), info_, 1000);
base::RunLoop().RunUntilIdle();
precache_manager_->CancelPrecaching();
@@ -465,14 +485,14 @@ TEST_F(PrecacheManagerTest, DeleteExpiredPrecacheHistory) {
EXPECT_TRUE(precache_manager_->IsPrecaching());
// Precache a bunch of URLs, with different fetch times.
- precache_manager_->RecordStatsForFetch(
- GURL("http://old-fetch.com"), GURL(), base::TimeDelta(),
+ RecordStatsForPrecacheFetch(
+ GURL("http://old-fetch.com"), std::string(), base::TimeDelta(),
kCurrentTime - base::TimeDelta::FromDays(61), info_, 1000);
- precache_manager_->RecordStatsForFetch(
- GURL("http://recent-fetch.com"), GURL(), base::TimeDelta(),
+ RecordStatsForPrecacheFetch(
+ GURL("http://recent-fetch.com"), std::string(), base::TimeDelta(),
kCurrentTime - base::TimeDelta::FromDays(59), info_, 1000);
- precache_manager_->RecordStatsForFetch(
- GURL("http://yesterday-fetch.com"), GURL(), base::TimeDelta(),
+ RecordStatsForPrecacheFetch(
+ GURL("http://yesterday-fetch.com"), std::string(), base::TimeDelta(),
kCurrentTime - base::TimeDelta::FromDays(1), info_, 1000);
expected_histogram_count_map["Precache.DownloadedPrecacheMotivated"] += 3;
expected_histogram_count_map["Precache.Fetch.PercentCompleted"]++;
@@ -521,6 +541,7 @@ TEST_F(PrecacheManagerTest, DeleteExpiredPrecacheHistory) {
expected_histogram_count_map["Precache.CacheStatus.NonPrefetch"]++;
expected_histogram_count_map["Precache.Latency.NonPrefetch"]++;
expected_histogram_count_map["Precache.Latency.NonPrefetch.NonTopHosts"]++;
+ expected_histogram_count_map["Precache.TimeSinceLastPrecache"] += 1;
base::RunLoop().RunUntilIdle();
EXPECT_THAT(histograms_.GetTotalCountsForPrefix("Precache."),
@@ -535,9 +556,12 @@ TEST_F(PrecacheManagerTest, DeleteExpiredPrecacheHistory) {
GURL(), base::TimeDelta(),
kCurrentTime, info_, 1000);
expected_histogram_count_map["Precache.CacheStatus.NonPrefetch"] += 2;
+ expected_histogram_count_map
+ ["Precache.CacheStatus.NonPrefetch.FromPrecache"] += 2;
expected_histogram_count_map["Precache.Latency.NonPrefetch"] += 2;
expected_histogram_count_map["Precache.Latency.NonPrefetch.NonTopHosts"] += 2;
expected_histogram_count_map["Precache.Saved"] += 2;
+ expected_histogram_count_map["Precache.TimeSinceLastPrecache"] += 2;
expected_histogram_count_map["Precache.Saved.Freshness"] = 2;
base::RunLoop().RunUntilIdle();
diff --git a/chromium/components/precache/core/BUILD.gn b/chromium/components/precache/core/BUILD.gn
index bc0fbdcbb86..92f29ac11fe 100644
--- a/chromium/components/precache/core/BUILD.gn
+++ b/chromium/components/precache/core/BUILD.gn
@@ -18,13 +18,15 @@ config("precache_config") {
]
}
-source_set("core") {
+static_library("core") {
sources = [
"fetcher_pool.h",
"precache_database.cc",
"precache_database.h",
"precache_fetcher.cc",
"precache_fetcher.h",
+ "precache_referrer_host_table.cc",
+ "precache_referrer_host_table.h",
"precache_session_table.cc",
"precache_session_table.h",
"precache_switches.cc",
@@ -41,6 +43,7 @@ source_set("core") {
deps = [
":proto",
"//base",
+ "//components/data_use_measurement/core",
"//components/history/core/browser",
"//components/prefs",
"//net",
@@ -52,6 +55,8 @@ source_set("core") {
proto_library("proto") {
sources = [
"proto/precache.proto",
+ "proto/quota.proto",
+ "proto/timestamp.proto",
"proto/unfinished_work.proto",
]
}
@@ -62,6 +67,7 @@ source_set("unit_tests") {
"fetcher_pool_unittest.cc",
"precache_database_unittest.cc",
"precache_fetcher_unittest.cc",
+ "precache_referrer_host_table_unittest.cc",
"precache_session_table_unittest.cc",
"precache_url_table_unittest.cc",
]
diff --git a/chromium/components/precache/core/DEPS b/chromium/components/precache/core/DEPS
index 3c3e604bfc9..952a6db9da3 100644
--- a/chromium/components/precache/core/DEPS
+++ b/chromium/components/precache/core/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/data_use_measurement/core",
"+net/base",
"+net/http",
"+net/url_request",
diff --git a/chromium/components/precache/core/fetcher_pool_unittest.cc b/chromium/components/precache/core/fetcher_pool_unittest.cc
index 09296a17d7a..f3d9de48076 100644
--- a/chromium/components/precache/core/fetcher_pool_unittest.cc
+++ b/chromium/components/precache/core/fetcher_pool_unittest.cc
@@ -39,8 +39,11 @@ class MockURLFetcherDelegate : public net::URLFetcherDelegate {
virtual ~MockURLFetcherDelegate() {};
MOCK_METHOD1(OnURLFetchComplete, void(const URLFetcher*));
- MOCK_METHOD3(OnURLFetchDownloadProgress,
- void(const URLFetcher* source, int64_t current, int64_t total));
+ MOCK_METHOD4(OnURLFetchDownloadProgress,
+ void(const URLFetcher* source,
+ int64_t current,
+ int64_t total,
+ int64_t current_network_bytes));
MOCK_METHOD3(OnURLFetchUploadProgress,
void(const URLFetcher* source, int64_t current, int64_t total));
};
diff --git a/chromium/components/precache/core/precache_database.cc b/chromium/components/precache/core/precache_database.cc
index 0ee64d8d4c8..8650262a405 100644
--- a/chromium/components/precache/core/precache_database.cc
+++ b/chromium/components/precache/core/precache_database.cc
@@ -25,6 +25,9 @@ namespace {
// it is considered "old" and is removed from the table.
const int kPrecacheHistoryExpiryPeriodDays = 60;
+const int kSecondsInMinute = 60;
+const int kSecondsInHour = kSecondsInMinute * 60;
+
} // namespace
namespace precache {
@@ -55,6 +58,7 @@ bool PrecacheDatabase::Init(const base::FilePath& db_path) {
}
if (!precache_url_table_.Init(db_.get()) ||
+ !precache_referrer_host_table_.Init(db_.get()) ||
!precache_session_table_.Init(db_.get())) {
// Raze and close the database connection to indicate that it's not usable,
// and so that the database will be created anew next time, in case it's
@@ -78,6 +82,9 @@ void PrecacheDatabase::DeleteExpiredPrecacheHistory(
buffered_writes_.push_back(
base::Bind(&PrecacheURLTable::DeleteAllPrecachedBefore,
base::Unretained(&precache_url_table_), delete_end));
+ buffered_writes_.push_back(
+ base::Bind(&PrecacheReferrerHostTable::DeleteAllEntriesBefore,
+ base::Unretained(&precache_referrer_host_table_), delete_end));
Flush();
}
@@ -89,26 +96,60 @@ void PrecacheDatabase::ClearHistory() {
buffered_writes_.push_back(base::Bind(
&PrecacheURLTable::DeleteAll, base::Unretained(&precache_url_table_)));
+ buffered_writes_.push_back(
+ base::Bind(&PrecacheReferrerHostTable::DeleteAll,
+ base::Unretained(&precache_referrer_host_table_)));
Flush();
}
-void PrecacheDatabase::RecordURLPrefetch(const GURL& url,
- const base::TimeDelta& latency,
- const base::Time& fetch_time,
- const net::HttpResponseInfo& info,
- int64_t size) {
- UMA_HISTOGRAM_TIMES("Precache.Latency.Prefetch", latency);
+void PrecacheDatabase::SetLastPrecacheTimestamp(const base::Time& time) {
+ last_precache_timestamp_ = time;
if (!IsDatabaseAccessible()) {
- // Don't track anything if unable to access the database.
+ // Do nothing if unable to access the database.
return;
}
- if (buffered_urls_.find(url.spec()) != buffered_urls_.end()) {
- // If the URL for this fetch is in the write buffer, then flush the write
- // buffer.
- Flush();
+ buffered_writes_.push_back(
+ base::Bind(&PrecacheSessionTable::SetLastPrecacheTimestamp,
+ base::Unretained(&precache_session_table_), time));
+ MaybePostFlush();
+}
+
+base::Time PrecacheDatabase::GetLastPrecacheTimestamp() {
+ if (last_precache_timestamp_.is_null() && IsDatabaseAccessible()) {
+ last_precache_timestamp_ =
+ precache_session_table_.GetLastPrecacheTimestamp();
}
+ return last_precache_timestamp_;
+}
+
+PrecacheReferrerHostEntry PrecacheDatabase::GetReferrerHost(
+ const std::string& referrer_host) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return precache_referrer_host_table_.GetReferrerHost(referrer_host);
+}
+
+void PrecacheDatabase::GetURLListForReferrerHost(
+ int64_t referrer_host_id,
+ std::vector<GURL>* used_urls,
+ std::vector<GURL>* unused_urls) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_NE(PrecacheReferrerHostEntry::kInvalidId, referrer_host_id);
+
+ // Flush any pending writes to the URL and referrer host tables.
+ Flush();
+
+ precache_url_table_.GetURLListForReferrerHost(referrer_host_id, used_urls,
+ unused_urls);
+}
+
+void PrecacheDatabase::RecordURLPrefetchMetrics(
+ const net::HttpResponseInfo& info,
+ const base::TimeDelta& latency) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ UMA_HISTOGRAM_TIMES("Precache.Latency.Prefetch", latency);
DCHECK(info.headers) << "The headers are required to get the freshness.";
if (info.headers) {
@@ -120,33 +161,65 @@ void PrecacheDatabase::RecordURLPrefetch(const GURL& url,
base::TimeDelta::FromDays(356).InSeconds() /* max */,
100 /* bucket_count */);
}
+}
- if (info.was_cached && !precache_url_table_.HasURL(url)) {
- // Since the precache came from the cache, and there's no entry in the URL
- // table for the URL, this means that the resource was already in the cache
- // because of user browsing. Therefore, this precache won't be considered as
- // precache-motivated since it had no significant effect (besides a possible
- // revalidation and a change in the cache LRU priority).
+void PrecacheDatabase::RecordURLPrefetch(const GURL& url,
+ const std::string& referrer_host,
+ const base::Time& fetch_time,
+ bool was_cached,
+ int64_t size) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!IsDatabaseAccessible()) {
+ // Don't track anything if unable to access the database.
return;
}
- if (!info.was_cached) {
+ if (buffered_urls_.find(url.spec()) != buffered_urls_.end()) {
+ // If the URL for this fetch is in the write buffer, then flush the write
+ // buffer.
+ Flush();
+ }
+
+ if (!was_cached) {
// The precache only counts as overhead if it was downloaded over the
// network.
UMA_HISTOGRAM_COUNTS("Precache.DownloadedPrecacheMotivated",
static_cast<base::HistogramBase::Sample>(size));
}
- // Use the URL table to keep track of URLs that are in the cache thanks to
- // precaching. If a row for the URL already exists, than update the timestamp
- // to |fetch_time|.
- buffered_writes_.push_back(
- base::Bind(&PrecacheURLTable::AddURL,
- base::Unretained(&precache_url_table_), url, fetch_time));
+ // Use the URL table to keep track of URLs. URLs that are fetched via network
+ // or already in the cache due to prior precaching are recorded as
+ // precache-motivated. URLs that came from the cache and not recorded as
+ // precached previously, were already in the cache because of user browsing.
+ // Therefore, this precache will not be considered as precache-motivated,
+ // since it had no significant effect (besides a possible revalidation and a
+ // change in the cache LRU priority). If a row for the URL already exists,
+ // then the timestamp is updated.
+ buffered_writes_.push_back(base::Bind(
+ &PrecacheDatabase::RecordURLPrefetchInternal, GetWeakPtr(), url,
+ referrer_host,
+ !was_cached || precache_url_table_.GetURLInfo(url).is_precached,
+ fetch_time));
buffered_urls_.insert(url.spec());
MaybePostFlush();
}
+void PrecacheDatabase::RecordURLPrefetchInternal(
+ const GURL& url,
+ const std::string& referrer_host,
+ bool is_precached,
+ const base::Time& fetch_time) {
+ int64_t referrer_host_id =
+ precache_referrer_host_table_.GetReferrerHost(referrer_host).id;
+ if (referrer_host_id == PrecacheReferrerHostEntry::kInvalidId) {
+ referrer_host_id = precache_referrer_host_table_.UpdateReferrerHost(
+ referrer_host, 0, fetch_time);
+ }
+ DCHECK_NE(referrer_host_id, PrecacheReferrerHostEntry::kInvalidId);
+ precache_url_table_.AddURL(url, referrer_host_id, is_precached, fetch_time);
+}
+
void PrecacheDatabase::RecordURLNonPrefetch(const GURL& url,
const base::TimeDelta& latency,
const base::Time& fetch_time,
@@ -174,15 +247,21 @@ void PrecacheDatabase::RecordURLNonPrefetch(const GURL& url,
return;
}
+ RecordTimeSinceLastPrecache(fetch_time);
+
if (buffered_urls_.find(url.spec()) != buffered_urls_.end()) {
// If the URL for this fetch is in the write buffer, then flush the write
// buffer.
Flush();
}
- if (info.was_cached && !precache_url_table_.HasURL(url)) {
- // Ignore cache hits that precache can't take credit for.
- return;
+ const PrecacheURLInfo url_info = precache_url_table_.GetURLInfo(url);
+
+ if (url_info.was_precached) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Precache.CacheStatus.NonPrefetch.FromPrecache",
+ info.cache_entry_status,
+ net::HttpResponseInfo::CacheEntryStatus::ENTRY_MAX);
}
base::HistogramBase::Sample size_sample =
@@ -195,7 +274,17 @@ void PrecacheDatabase::RecordURLNonPrefetch(const GURL& url,
UMA_HISTOGRAM_COUNTS("Precache.DownloadedNonPrecache.Cellular",
size_sample);
}
- } else { // info.was_cached.
+ // Since the resource has been fetched during user browsing, mark the URL as
+ // used in the precache URL table, if any exists. The current fetch would
+ // have put this resource in the cache regardless of whether or not it was
+ // previously precached, so mark the URL as used.
+ buffered_writes_.push_back(
+ base::Bind(&PrecacheURLTable::SetURLAsNotPrecached,
+ base::Unretained(&precache_url_table_), url));
+ buffered_urls_.insert(url.spec());
+ MaybePostFlush();
+ } else if (/* info.was_cached && */ url_info.is_precached &&
+ !url_info.was_used) {
// The fetch was served from the cache, and since there's an entry for this
// URL in the URL table, this means that the resource was served from the
// cache only because precaching put it there. Thus, precaching was helpful,
@@ -216,20 +305,62 @@ void PrecacheDatabase::RecordURLNonPrefetch(const GURL& url,
base::TimeDelta::FromDays(356).InSeconds() /* max */,
100 /* bucket_count */);
}
+
+ buffered_writes_.push_back(
+ base::Bind(&PrecacheURLTable::SetPrecachedURLAsUsed,
+ base::Unretained(&precache_url_table_), url));
+ buffered_urls_.insert(url.spec());
+ MaybePostFlush();
+ }
+}
+
+void PrecacheDatabase::UpdatePrecacheReferrerHost(
+ const std::string& hostname,
+ int64_t manifest_id,
+ const base::Time& fetch_time) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!IsDatabaseAccessible()) {
+ // Don't track anything if unable to access the database.
+ return;
}
- // Since the resource has been fetched during user browsing, remove any record
- // of that URL having been precached from the URL table, if any exists.
- // The current fetch would have put this resource in the cache regardless of
- // whether or not it was previously precached, so delete any record of that
- // URL having been precached from the URL table.
buffered_writes_.push_back(
- base::Bind(&PrecacheURLTable::DeleteURL,
- base::Unretained(&precache_url_table_), url));
- buffered_urls_.insert(url.spec());
+ base::Bind(&PrecacheDatabase::UpdatePrecacheReferrerHostInternal,
+ GetWeakPtr(), hostname, manifest_id, fetch_time));
MaybePostFlush();
}
+void PrecacheDatabase::UpdatePrecacheReferrerHostInternal(
+ const std::string& hostname,
+ int64_t manifest_id,
+ const base::Time& fetch_time) {
+ int64_t referrer_host_id = precache_referrer_host_table_.UpdateReferrerHost(
+ hostname, manifest_id, fetch_time);
+ if (referrer_host_id != PrecacheReferrerHostEntry::kInvalidId) {
+ precache_url_table_.ClearAllForReferrerHost(referrer_host_id);
+ }
+}
+
+void PrecacheDatabase::RecordTimeSinceLastPrecache(
+ const base::Time& fetch_time) {
+ const base::Time& last_precache_timestamp = GetLastPrecacheTimestamp();
+ // It could still be null if the DB was not accessible.
+ if (!last_precache_timestamp.is_null()) {
+ // This is the timespan (in seconds) between the last call to
+ // PrecacheManager::StartPrecaching and the fetch time of a non-precache
+ // URL. Please note that the session started by that call to
+ // PrecacheManager::StartPrecaching may not have precached this particular
+ // URL or even any URL for that matter.
+ // The range was estimated to have the 95 percentile within the last bounded
+ // bucket.
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Precache.TimeSinceLastPrecache",
+ (fetch_time - last_precache_timestamp).InSeconds(), kSecondsInMinute,
+ kSecondsInHour * 36, 100);
+ }
+}
+
bool PrecacheDatabase::IsDatabaseAccessible() const {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(db_);
@@ -308,6 +439,14 @@ void PrecacheDatabase::DeleteUnfinishedWork() {
precache_session_table_.DeleteUnfinishedWork();
}
+void PrecacheDatabase::SaveQuota(const PrecacheQuota& quota) {
+ precache_session_table_.SaveQuota(quota);
+}
+
+PrecacheQuota PrecacheDatabase::GetQuota() {
+ return precache_session_table_.GetQuota();
+}
+
base::WeakPtr<PrecacheDatabase> PrecacheDatabase::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
diff --git a/chromium/components/precache/core/precache_database.h b/chromium/components/precache/core/precache_database.h
index da13a82a8ab..e610ac48c32 100644
--- a/chromium/components/precache/core/precache_database.h
+++ b/chromium/components/precache/core/precache_database.h
@@ -7,7 +7,6 @@
#include <stdint.h>
-#include <list>
#include <memory>
#include <string>
#include <vector>
@@ -18,7 +17,9 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
#include "components/precache/core/precache_fetcher.h"
+#include "components/precache/core/precache_referrer_host_table.h"
#include "components/precache/core/precache_session_table.h"
#include "components/precache/core/precache_url_table.h"
@@ -26,7 +27,6 @@ class GURL;
namespace base {
class FilePath;
-class Time;
}
namespace net {
@@ -62,12 +62,20 @@ class PrecacheDatabase {
// Delete all history entries from the database.
void ClearHistory();
+ // Setter and getter for the last precache timestamp.
+ void SetLastPrecacheTimestamp(const base::Time& time);
+ base::Time GetLastPrecacheTimestamp();
+
// Report precache-related metrics in response to a URL being fetched, where
// the fetch was motivated by precaching.
+ void RecordURLPrefetchMetrics(const net::HttpResponseInfo& info,
+ const base::TimeDelta& latency);
+
+ // Records the precache of an url |url| for top host |referrer_host|.
void RecordURLPrefetch(const GURL& url,
- const base::TimeDelta& latency,
+ const std::string& referrer_host,
const base::Time& fetch_time,
- const net::HttpResponseInfo& info,
+ bool was_cached,
int64_t size);
// Report precache-related metrics in response to a URL being fetched, where
@@ -81,6 +89,21 @@ class PrecacheDatabase {
int host_rank,
bool is_connection_cellular);
+ // Returns the referrer host entry for the |referrer_host|.
+ PrecacheReferrerHostEntry GetReferrerHost(const std::string& referrer_host);
+
+ // Populates the list of used and unused resources for referrer host with id
+ // |referrer_host_id|.
+ void GetURLListForReferrerHost(int64_t referrer_host_id,
+ std::vector<GURL>* used_urls,
+ std::vector<GURL>* unused_urls);
+
+ // Updates the |manifest_id| and |fetch_time| for the referrer host
+ // |hostname|, and deletes the precached subresource URLs for this top host.
+ void UpdatePrecacheReferrerHost(const std::string& hostname,
+ int64_t manifest_id,
+ const base::Time& fetch_time);
+
// Gets the state required to continue a precache session.
std::unique_ptr<PrecacheUnfinishedWork> GetUnfinishedWork();
@@ -92,6 +115,10 @@ class PrecacheDatabase {
// Deletes unfinished work from the database.
void DeleteUnfinishedWork();
+ // Precache quota.
+ void SaveQuota(const PrecacheQuota& quota);
+ PrecacheQuota GetQuota();
+
base::WeakPtr<PrecacheDatabase> GetWeakPtr();
private:
@@ -113,6 +140,18 @@ class PrecacheDatabase {
// posted.
void MaybePostFlush();
+ // Records the time since the last precache.
+ void RecordTimeSinceLastPrecache(const base::Time& fetch_time);
+
+ void RecordURLPrefetchInternal(const GURL& url,
+ const std::string& referrer_host,
+ bool is_precached,
+ const base::Time& fetch_time);
+
+ void UpdatePrecacheReferrerHostInternal(const std::string& hostname,
+ int64_t manifest_id,
+ const base::Time& fetch_time);
+
std::unique_ptr<sql::Connection> db_;
// Table that keeps track of URLs that are in the cache because of precaching,
@@ -120,6 +159,10 @@ class PrecacheDatabase {
// then this table will not be up to date until the next call to Flush().
PrecacheURLTable precache_url_table_;
+ // If |buffered_writes_| is non-empty,
+ // then this table will not be up to date until the next call to Flush().
+ PrecacheReferrerHostTable precache_referrer_host_table_;
+
// Table that persists state related to a precache session, including
// unfinished work to be done.
PrecacheSessionTable precache_session_table_;
@@ -139,6 +182,11 @@ class PrecacheDatabase {
// or destructor are called on the same thread.
base::ThreadChecker thread_checker_;
+ // Time of the last precache. This is a cached copy of
+ // precache_session_table_.GetLastPrecacheTimestamp.
+ base::Time last_precache_timestamp_;
+
+ // This must be the last member of this class.
base::WeakPtrFactory<PrecacheDatabase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PrecacheDatabase);
diff --git a/chromium/components/precache/core/precache_database_unittest.cc b/chromium/components/precache/core/precache_database_unittest.cc
index 98cd2252355..8d00c79f6f6 100644
--- a/chromium/components/precache/core/precache_database_unittest.cc
+++ b/chromium/components/precache/core/precache_database_unittest.cc
@@ -32,9 +32,14 @@ using base::Bucket;
using net::HttpResponseInfo;
const GURL kURL("http://url.com");
+const int kReferrerID = 1;
const base::TimeDelta kLatency = base::TimeDelta::FromMilliseconds(5);
const base::Time kFetchTime = base::Time() + base::TimeDelta::FromHours(1000);
const base::Time kOldFetchTime = kFetchTime - base::TimeDelta::FromDays(1);
+const base::Time kNewFetchTime =
+ base::Time() + base::TimeDelta::FromHours(2000);
+const base::Time kPrecacheTime =
+ base::Time() + base::TimeDelta::FromHours(3000);
const int64_t kSize = 5000;
const int64_t kFreshnessBucket10K = 9089;
// One of the possible CacheEntryStatus for when the fetch was served from the
@@ -91,11 +96,13 @@ class PrecacheDatabaseTest : public testing::Test {
precache_database_.reset(new PrecacheDatabase());
ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
- base::FilePath db_path = scoped_temp_dir_.path().Append(
+ base::FilePath db_path = scoped_temp_dir_.GetPath().Append(
base::FilePath(FILE_PATH_LITERAL("precache_database")));
- precache_database_->Init(db_path);
+ ASSERT_TRUE(precache_database_->Init(db_path));
}
+ void TearDown() override { precache_url_table()->DeleteAll(); }
+
std::map<GURL, base::Time> GetActualURLTableMap() {
// Flush any buffered writes so that the URL table will be up to date.
precache_database_->Flush();
@@ -109,6 +116,8 @@ class PrecacheDatabaseTest : public testing::Test {
return &precache_database_->precache_url_table_;
}
+ void Flush() { precache_database_->Flush(); }
+
// Convenience methods for recording different types of URL fetches. These
// exist to improve the readability of the tests.
void RecordPrecacheFromNetwork(const GURL& url,
@@ -168,7 +177,9 @@ void PrecacheDatabaseTest::RecordPrecacheFromNetwork(
int64_t size) {
const HttpResponseInfo info = CreateHttpResponseInfo(
false /* was_cached */, false /* network_accessed */);
- precache_database_->RecordURLPrefetch(url, latency, fetch_time, info, size);
+ precache_database_->RecordURLPrefetchMetrics(info, latency);
+ precache_database_->RecordURLPrefetch(url, std::string(), fetch_time,
+ info.was_cached, size);
}
void PrecacheDatabaseTest::RecordPrecacheFromCache(const GURL& url,
@@ -176,8 +187,10 @@ void PrecacheDatabaseTest::RecordPrecacheFromCache(const GURL& url,
int64_t size) {
const HttpResponseInfo info = CreateHttpResponseInfo(
true /* was_cached */, false /* network_accessed */);
- precache_database_->RecordURLPrefetch(url, base::TimeDelta() /* latency */,
- fetch_time, info, size);
+ precache_database_->RecordURLPrefetchMetrics(info,
+ base::TimeDelta() /* latency */);
+ precache_database_->RecordURLPrefetch(url, std::string(), fetch_time,
+ info.was_cached, size);
}
void PrecacheDatabaseTest::RecordFetchFromNetwork(const GURL& url,
@@ -250,7 +263,7 @@ TEST_F(PrecacheDatabaseTest, PrecacheOverNetwork) {
}
TEST_F(PrecacheDatabaseTest, PrecacheFromCacheWithURLTableEntry) {
- precache_url_table()->AddURL(kURL, kOldFetchTime);
+ precache_url_table()->AddURL(kURL, kReferrerID, true, kOldFetchTime);
RecordPrecacheFromCache(kURL, kFetchTime, kSize);
// The URL table entry should have been updated to have |kFetchTime| as the
@@ -313,7 +326,7 @@ TEST_F(PrecacheDatabaseTest, FetchOverNetwork_Cellular) {
}
TEST_F(PrecacheDatabaseTest, FetchOverNetworkWithURLTableEntry) {
- precache_url_table()->AddURL(kURL, kOldFetchTime);
+ precache_url_table()->AddURL(kURL, kReferrerID, true, kOldFetchTime);
RecordFetchFromNetwork(kURL, kLatency, kFetchTime, kSize);
// The URL table entry should have been deleted.
@@ -324,11 +337,13 @@ TEST_F(PrecacheDatabaseTest, FetchOverNetworkWithURLTableEntry) {
ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts",
kLatency.InMilliseconds());
ExpectNewSample("Precache.CacheStatus.NonPrefetch", kFromNetwork);
+ ExpectNewSample("Precache.CacheStatus.NonPrefetch.FromPrecache",
+ kFromNetwork);
ExpectNoOtherSamples();
}
TEST_F(PrecacheDatabaseTest, FetchFromCacheWithURLTableEntry_NonCellular) {
- precache_url_table()->AddURL(kURL, kOldFetchTime);
+ precache_url_table()->AddURL(kURL, kReferrerID, true, kOldFetchTime);
RecordFetchFromCache(kURL, kFetchTime, kSize);
// The URL table entry should have been deleted.
@@ -338,13 +353,15 @@ TEST_F(PrecacheDatabaseTest, FetchFromCacheWithURLTableEntry_NonCellular) {
ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts", 0);
ExpectNewSample("Precache.CacheStatus.NonPrefetch",
HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
+ ExpectNewSample("Precache.CacheStatus.NonPrefetch.FromPrecache",
+ HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
ExpectNewSample("Precache.Saved", kSize);
ExpectNewSample("Precache.Saved.Freshness", kFreshnessBucket10K);
ExpectNoOtherSamples();
}
TEST_F(PrecacheDatabaseTest, FetchFromCacheWithURLTableEntry_Cellular) {
- precache_url_table()->AddURL(kURL, kOldFetchTime);
+ precache_url_table()->AddURL(kURL, kReferrerID, true, kOldFetchTime);
RecordFetchFromCacheCellular(kURL, kFetchTime, kSize);
// The URL table entry should have been deleted.
@@ -354,6 +371,8 @@ TEST_F(PrecacheDatabaseTest, FetchFromCacheWithURLTableEntry_Cellular) {
ExpectNewSample("Precache.Latency.NonPrefetch.NonTopHosts", 0);
ExpectNewSample("Precache.CacheStatus.NonPrefetch",
HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
+ ExpectNewSample("Precache.CacheStatus.NonPrefetch.FromPrecache",
+ HttpResponseInfo::CacheEntryStatus::ENTRY_USED);
ExpectNewSample("Precache.Saved", kSize);
ExpectNewSample("Precache.Saved.Cellular", kSize);
ExpectNewSample("Precache.Saved.Freshness", kFreshnessBucket10K);
@@ -377,8 +396,10 @@ TEST_F(PrecacheDatabaseTest, DeleteExpiredPrecacheHistory) {
const base::Time k59DaysAgo = kToday - base::TimeDelta::FromDays(59);
const base::Time k61DaysAgo = kToday - base::TimeDelta::FromDays(61);
- precache_url_table()->AddURL(GURL("http://expired-precache.com"), k61DaysAgo);
- precache_url_table()->AddURL(GURL("http://old-precache.com"), k59DaysAgo);
+ precache_url_table()->AddURL(GURL("http://expired-precache.com"), kReferrerID,
+ true, k61DaysAgo);
+ precache_url_table()->AddURL(GURL("http://old-precache.com"), kReferrerID,
+ true, k59DaysAgo);
precache_database_->DeleteExpiredPrecacheHistory(kToday);
@@ -443,6 +464,35 @@ TEST_F(PrecacheDatabaseTest, SampleInteraction) {
ElementsAre(Bucket(kSize1, 1)));
}
+TEST_F(PrecacheDatabaseTest, LastPrecacheTimestamp) {
+ // So that it starts recording TimeSinceLastPrecache.
+ const base::Time kStartTime =
+ base::Time() + base::TimeDelta::FromSeconds(100);
+ precache_database_->SetLastPrecacheTimestamp(kStartTime);
+
+ RecordPrecacheFromNetwork(kURL, kLatency, kStartTime, kSize);
+ RecordPrecacheFromNetwork(kURL, kLatency, kStartTime, kSize);
+ RecordPrecacheFromNetwork(kURL, kLatency, kStartTime, kSize);
+ RecordPrecacheFromNetwork(kURL, kLatency, kStartTime, kSize);
+
+ EXPECT_THAT(histograms_.GetAllSamples("Precache.TimeSinceLastPrecache"),
+ ElementsAre());
+
+ const base::Time kTimeA = kStartTime + base::TimeDelta::FromSeconds(7);
+ const base::Time kTimeB = kStartTime + base::TimeDelta::FromMinutes(42);
+ const base::Time kTimeC = kStartTime + base::TimeDelta::FromHours(20);
+
+ RecordFetchFromCacheCellular(kURL, kTimeA, kSize);
+ RecordFetchFromCacheCellular(kURL, kTimeA, kSize);
+ RecordFetchFromNetworkCellular(kURL, kLatency, kTimeB, kSize);
+ RecordFetchFromNetworkCellular(kURL, kLatency, kTimeB, kSize);
+ RecordFetchFromCacheCellular(kURL, kTimeB, kSize);
+ RecordFetchFromCacheCellular(kURL, kTimeC, kSize);
+
+ EXPECT_THAT(histograms_.GetAllSamples("Precache.TimeSinceLastPrecache"),
+ ElementsAre(Bucket(0, 2), Bucket(2406, 3), Bucket(69347, 1)));
+}
+
TEST_F(PrecacheDatabaseTest, PrecacheFreshnessPrefetch) {
auto info = CreateHttpResponseInfo(false /* was_cached */,
false /* network_accessed */);
@@ -452,6 +502,147 @@ TEST_F(PrecacheDatabaseTest, PrecacheFreshnessPrefetch) {
ElementsAre(Bucket(kFreshnessBucket10K, 1)));
}
+TEST_F(PrecacheDatabaseTest, UpdateAndGetReferrerHost) {
+ // Invalid ID should be returned for referrer host that does not exist.
+ EXPECT_EQ(PrecacheReferrerHostEntry::kInvalidId,
+ precache_database_->GetReferrerHost(std::string()).id);
+ EXPECT_EQ(PrecacheReferrerHostEntry::kInvalidId,
+ precache_database_->GetReferrerHost("not_created_host.com").id);
+
+ // Create a new entry.
+ precache_database_->UpdatePrecacheReferrerHost("foo.com", 1, kFetchTime);
+ Flush();
+ auto actual_entry = precache_database_->GetReferrerHost("foo.com");
+ EXPECT_EQ("foo.com", actual_entry.referrer_host);
+ EXPECT_EQ(1, actual_entry.manifest_id);
+ EXPECT_EQ(kFetchTime, actual_entry.time);
+
+ // Update the existing entry.
+ precache_database_->UpdatePrecacheReferrerHost("foo.com", 2, kNewFetchTime);
+ Flush();
+ actual_entry = precache_database_->GetReferrerHost("foo.com");
+ EXPECT_EQ("foo.com", actual_entry.referrer_host);
+ EXPECT_EQ(2, actual_entry.manifest_id);
+ EXPECT_EQ(kNewFetchTime, actual_entry.time);
+}
+
+TEST_F(PrecacheDatabaseTest, GetURLListForReferrerHost) {
+ precache_database_->UpdatePrecacheReferrerHost("foo.com", 1, kFetchTime);
+ precache_database_->UpdatePrecacheReferrerHost("bar.com", 2, kNewFetchTime);
+ precache_database_->UpdatePrecacheReferrerHost("foobar.com", 3,
+ kNewFetchTime);
+ precache_database_->UpdatePrecacheReferrerHost("empty.com", 3, kNewFetchTime);
+
+ struct test_resource_info {
+ std::string url;
+ bool is_user_browsed;
+ bool is_network_fetched;
+ bool is_cellular_fetched;
+ bool expected_in_used;
+ };
+
+ const struct {
+ std::string hostname;
+ std::vector<test_resource_info> resource_info;
+ } tests[] = {
+ {
+ "foo.com",
+ {
+ {"http://foo.com/from-cache.js", true, false, false, true},
+ {"http://some-cdn.com/from-network.js", true, true, false, false},
+ {"http://foo.com/from-cache-cellular.js", true, false, true,
+ true},
+ {"http://foo.com/from-network-cellular.js", true, true, true,
+ false},
+ {"http://foo.com/not-browsed.js", false, false, false, false},
+ },
+ },
+ {
+ "bar.com",
+ {
+ {"http://bar.com/a.js", true, false, false, true},
+ {"http://some-cdn.com/b.js", true, false, true, true},
+ {"http://bar.com/not-browsed.js", false, false, false, false},
+ },
+ },
+ {
+ "foobar.com",
+ {
+ {"http://some-cdn.com/not-used.js", true, true, true, false},
+ },
+ },
+ {
+ "empty.com", std::vector<test_resource_info>{},
+ },
+ };
+ // Add precached resources.
+ for (const auto& test : tests) {
+ for (const auto& resource : test.resource_info) {
+ precache_database_->RecordURLPrefetch(GURL(resource.url), test.hostname,
+ kPrecacheTime, false, kSize);
+ }
+ }
+ // Update some resources as used due to user browsing.
+ for (const auto& test : tests) {
+ for (const auto& resource : test.resource_info) {
+ if (!resource.is_user_browsed)
+ continue;
+ if (!resource.is_network_fetched && !resource.is_cellular_fetched) {
+ RecordFetchFromCache(GURL(resource.url), kFetchTime, kSize);
+ } else if (!resource.is_network_fetched && resource.is_cellular_fetched) {
+ RecordFetchFromCacheCellular(GURL(resource.url), kFetchTime, kSize);
+ } else if (resource.is_network_fetched && !resource.is_cellular_fetched) {
+ RecordFetchFromNetwork(GURL(resource.url), kLatency, kFetchTime, kSize);
+ } else if (resource.is_network_fetched && resource.is_cellular_fetched) {
+ RecordFetchFromNetworkCellular(GURL(resource.url), kLatency, kFetchTime,
+ kSize);
+ }
+ }
+ }
+ Flush();
+ // Verify the used and unused resources.
+ for (const auto& test : tests) {
+ std::vector<GURL> expected_used_urls, expected_unused_urls;
+ for (const auto& resource : test.resource_info) {
+ if (resource.expected_in_used) {
+ expected_used_urls.push_back(GURL(resource.url));
+ } else {
+ expected_unused_urls.push_back(GURL(resource.url));
+ }
+ }
+ std::vector<GURL> actual_used_urls, actual_unused_urls;
+ auto referrer_id = precache_database_->GetReferrerHost(test.hostname).id;
+ EXPECT_NE(PrecacheReferrerHostEntry::kInvalidId, referrer_id);
+ precache_database_->GetURLListForReferrerHost(
+ referrer_id, &actual_used_urls, &actual_unused_urls);
+ EXPECT_THAT(expected_used_urls, ::testing::ContainerEq(actual_used_urls));
+ EXPECT_THAT(expected_unused_urls,
+ ::testing::ContainerEq(actual_unused_urls));
+ }
+ // Subsequent manifest updates should clear the used and unused resources.
+ for (const auto& test : tests) {
+ precache_database_->UpdatePrecacheReferrerHost(test.hostname, 100,
+ kNewFetchTime);
+ Flush();
+ std::vector<GURL> actual_used_urls, actual_unused_urls;
+ auto referrer_id = precache_database_->GetReferrerHost(test.hostname).id;
+ EXPECT_NE(PrecacheReferrerHostEntry::kInvalidId, referrer_id);
+ precache_database_->GetURLListForReferrerHost(
+ referrer_id, &actual_used_urls, &actual_unused_urls);
+ EXPECT_TRUE(actual_used_urls.empty());
+ }
+ // Resources that were precached previously and not seen in user browsing
+ // should be still marked as precached.
+ std::map<GURL, base::Time> expected_url_table_map;
+ for (const auto& test : tests) {
+ for (const auto& resource : test.resource_info) {
+ if (!resource.is_user_browsed)
+ expected_url_table_map[GURL(resource.url)] = kPrecacheTime;
+ }
+ }
+ EXPECT_EQ(expected_url_table_map, GetActualURLTableMap());
+}
+
} // namespace
} // namespace precache
diff --git a/chromium/components/precache/core/precache_fetcher.cc b/chromium/components/precache/core/precache_fetcher.cc
index a5cf65086d2..fb45ac19772 100644
--- a/chromium/components/precache/core/precache_fetcher.cc
+++ b/chromium/components/precache/core/precache_fetcher.cc
@@ -6,10 +6,11 @@
#include <algorithm>
#include <limits>
-#include <string>
+#include <set>
#include <utility>
#include <vector>
+#include "base/base64.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
@@ -21,14 +22,21 @@
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram_macros.h"
+#include "base/sha1.h"
+#include "base/strings/string_piece.h"
+#include "base/task_runner_util.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/precache/core/precache_database.h"
#include "components/precache/core/precache_switches.h"
#include "components/precache/core/proto/precache.pb.h"
+#include "components/precache/core/proto/quota.pb.h"
#include "components/precache/core/proto/unfinished_work.pb.h"
#include "net/base/completion_callback.h"
#include "net/base/escape.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
+#include "net/base/url_util.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_fetcher_response_writer.h"
#include "net/url_request/url_request_context_getter.h"
@@ -46,11 +54,14 @@ const int kNoTracking =
net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SEND_AUTH_DATA;
-namespace {
-
-// The maximum number of URLFetcher requests that can be on flight in parallel.
+// The maximum number of URLFetcher requests that can be in flight in parallel.
+// Note that OnManifestFetchComplete and OnResourceFetchComplete perform
+// remove_if operations which are O(kMaxParallelFetches). Those should be
+// optimized before increasing this value significantly.
const int kMaxParallelFetches = 10;
+namespace {
+
// The maximum for the Precache.Fetch.ResponseBytes.* histograms. We set this to
// a number we expect to be in the 99th percentile for the histogram, give or
// take.
@@ -90,15 +101,6 @@ std::string GetDefaultManifestURLPrefix() {
#endif
}
-// Construct the URL of the precache manifest for the given name (either host or
-// URL). The server is expecting a request for a URL consisting of the manifest
-// URL prefix followed by the doubly escaped name.
-std::string ConstructManifestURL(const std::string& prefix,
- const std::string& name) {
- return prefix + net::EscapeQueryParamValue(
- net::EscapeQueryParamValue(name, false), false);
-}
-
// Attempts to parse a protobuf message from the response string of a
// URLFetcher. If parsing is successful, the message parameter will contain the
// parsed protobuf and this function will return true. Otherwise, returns false.
@@ -154,23 +156,81 @@ class URLFetcherNullWriter : public net::URLFetcherResponseWriter {
return num_bytes;
}
- int Finish(const net::CompletionCallback& callback) override {
+ int Finish(int net_error, const net::CompletionCallback& callback) override {
return net::OK;
}
};
-void AppendManifestURLIfValidAndNew(
- const std::string& prefix,
- const std::string& name,
- base::hash_set<std::string>* seen_manifest_urls,
- std::list<GURL>* unique_manifest_urls) {
- const std::string manifest_url = ConstructManifestURL(prefix, name);
- bool first_seen = seen_manifest_urls->insert(manifest_url).second;
- if (first_seen) {
- GURL url(manifest_url);
- if (url.is_valid())
- unique_manifest_urls->push_back(url);
+// Returns the base64 encoded resource URL hashes. The resource URLs are hashed
+// individually, and 8 bytes of each hash is appended together, which is then
+// encoded to base64.
+std::string GetResourceURLBase64Hash(const std::vector<GURL>& urls) {
+ // Each resource hash uses 8 bytes, instead of the 20 bytes of sha1 hash, as a
+ // tradeoff between sending more bytes and reducing hash collisions.
+ const size_t kHashBytesSize = 8;
+ std::string hashes;
+ hashes.reserve(urls.size() * kHashBytesSize);
+
+ for (const auto& url : urls) {
+ const std::string& url_spec = url.spec();
+ unsigned char sha1_hash[base::kSHA1Length];
+ base::SHA1HashBytes(
+ reinterpret_cast<const unsigned char*>(url_spec.c_str()),
+ url_spec.size(), sha1_hash);
+ hashes.append(reinterpret_cast<const char*>(sha1_hash), kHashBytesSize);
}
+ base::Base64Encode(hashes, &hashes);
+ return hashes;
+}
+
+// Retrieves the manifest info on the DB thread. Manifest info for each of the
+// hosts in |hosts_to_fetch|, is added to |hosts_info|.
+std::deque<ManifestHostInfo> RetrieveManifestInfo(
+ const base::WeakPtr<PrecacheDatabase>& precache_database,
+ std::vector<std::pair<std::string, int64_t>> hosts_to_fetch) {
+ std::deque<ManifestHostInfo> hosts_info;
+ if (!precache_database)
+ return hosts_info;
+
+ for (const auto& host : hosts_to_fetch) {
+ auto referrer_host_info = precache_database->GetReferrerHost(host.first);
+ if (referrer_host_info.id != PrecacheReferrerHostEntry::kInvalidId) {
+ std::vector<GURL> used_urls, unused_urls;
+ precache_database->GetURLListForReferrerHost(referrer_host_info.id,
+ &used_urls, &unused_urls);
+ hosts_info.push_back(
+ ManifestHostInfo(referrer_host_info.manifest_id, host.first,
+ host.second, GetResourceURLBase64Hash(used_urls),
+ GetResourceURLBase64Hash(unused_urls)));
+ } else {
+ hosts_info.push_back(
+ ManifestHostInfo(PrecacheReferrerHostEntry::kInvalidId, host.first,
+ host.second, std::string(), std::string()));
+ }
+ }
+ return hosts_info;
+}
+
+PrecacheQuota RetrieveQuotaInfo(
+ const base::WeakPtr<PrecacheDatabase>& precache_database) {
+ PrecacheQuota quota;
+ if (precache_database) {
+ quota = precache_database->GetQuota();
+ }
+ return quota;
+}
+
+// Returns true if the |quota| time has expired.
+bool IsQuotaTimeExpired(const PrecacheQuota& quota,
+ const base::Time& time_now) {
+ // Quota expires one day after the start time.
+ base::Time start_time = base::Time::FromInternalValue(quota.start_time());
+ return start_time > time_now ||
+ start_time + base::TimeDelta::FromDays(1) < time_now;
+}
+
+double ResourceWeight(const PrecacheResource& resource, int64_t host_visits) {
+ return resource.weight_ratio() * host_visits;
}
} // namespace
@@ -178,16 +238,20 @@ void AppendManifestURLIfValidAndNew(
PrecacheFetcher::Fetcher::Fetcher(
net::URLRequestContextGetter* request_context,
const GURL& url,
+ const std::string& referrer,
const base::Callback<void(const Fetcher&)>& callback,
bool is_resource_request,
size_t max_bytes)
: request_context_(request_context),
url_(url),
+ referrer_(referrer),
callback_(callback),
is_resource_request_(is_resource_request),
max_bytes_(max_bytes),
response_bytes_(0),
- network_response_bytes_(0) {
+ network_response_bytes_(0),
+ was_cached_(false) {
+ DCHECK(url.is_valid());
if (is_resource_request_)
LoadFromCache();
else
@@ -200,6 +264,9 @@ void PrecacheFetcher::Fetcher::LoadFromCache() {
fetch_stage_ = FetchStage::CACHE;
cache_url_fetcher_ =
net::URLFetcher::Create(url_, net::URLFetcher::GET, this);
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ cache_url_fetcher_.get(),
+ data_use_measurement::DataUseUserData::PRECACHE);
cache_url_fetcher_->SetRequestContext(request_context_);
cache_url_fetcher_->SetLoadFlags(net::LOAD_ONLY_FROM_CACHE | kNoTracking);
std::unique_ptr<URLFetcherNullWriter> null_writer(new URLFetcherNullWriter);
@@ -211,6 +278,9 @@ void PrecacheFetcher::Fetcher::LoadFromNetwork() {
fetch_stage_ = FetchStage::NETWORK;
network_url_fetcher_ =
net::URLFetcher::Create(url_, net::URLFetcher::GET, this);
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ network_url_fetcher_.get(),
+ data_use_measurement::DataUseUserData::PRECACHE);
network_url_fetcher_->SetRequestContext(request_context_);
if (is_resource_request_) {
// LOAD_VALIDATE_CACHE allows us to refresh Date headers for resources
@@ -232,21 +302,24 @@ void PrecacheFetcher::Fetcher::LoadFromNetwork() {
void PrecacheFetcher::Fetcher::OnURLFetchDownloadProgress(
const net::URLFetcher* source,
int64_t current,
- int64_t total) {
- // If going over the per-resource download cap.
+ int64_t total,
+ int64_t current_network_bytes) {
+ // If network bytes going over the per-resource download cap.
if (fetch_stage_ == FetchStage::NETWORK &&
- // |current| is guaranteed to be non-negative, so this cast is safe.
- static_cast<size_t>(std::max(current, total)) > max_bytes_) {
- VLOG(1) << "Cancelling " << url_ << ": (" << current << "/" << total
- << ") is over " << max_bytes_;
-
- // Cancel the download.
- network_url_fetcher_.reset();
-
+ // |current_network_bytes| is guaranteed to be non-negative, so this cast
+ // is safe.
+ static_cast<size_t>(current_network_bytes) > max_bytes_) {
// Call the completion callback, to attempt the next download, or to trigger
// cleanup in precache_delegate_->OnDone().
- response_bytes_ = network_response_bytes_ = current;
+ response_bytes_ = current;
+ network_response_bytes_ = current_network_bytes;
+ was_cached_ = source->WasCached();
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Precache.Fetch.ResponseBytes.NetworkWasted",
+ network_response_bytes_, 1,
+ 1024 * 1024 /* 1 MB */, 100);
+ // Cancel the download.
+ network_url_fetcher_.reset();
callback_.Run(*this);
}
}
@@ -276,6 +349,7 @@ void PrecacheFetcher::Fetcher::OnURLFetchComplete(
// Then Fetcher is done with this URL and can return control to the caller.
response_bytes_ = source->GetReceivedResponseContentLength();
network_response_bytes_ = source->GetTotalReceivedBytes();
+ was_cached_ = source->WasCached();
callback_.Run(*this);
}
@@ -294,30 +368,28 @@ void PrecacheFetcher::RecordCompletionStatistics(
base::TimeDelta::FromSeconds(1),
base::TimeDelta::FromHours(4), 50);
- // Number of manifests for which we have downloaded all resources.
- int manifests_completed =
- unfinished_work.num_manifest_urls() - remaining_manifest_urls_to_fetch;
-
- // If there are resource URLs left to fetch, the last manifest is not yet
- // completed.
- if (remaining_resource_urls_to_fetch > 0)
- --manifests_completed;
-
- DCHECK_GE(manifests_completed, 0);
- int percent_completed = unfinished_work.num_manifest_urls() == 0
- ? 0
- : (static_cast<double>(manifests_completed) /
- unfinished_work.num_manifest_urls() * 100);
+ int num_total_resources = unfinished_work.num_resource_urls();
+ int percent_completed =
+ num_total_resources == 0
+ ? 101 // Overflow bucket.
+ : (100 * (static_cast<double>(num_total_resources -
+ remaining_resource_urls_to_fetch) /
+ num_total_resources));
UMA_HISTOGRAM_PERCENTAGE("Precache.Fetch.PercentCompleted",
percent_completed);
- UMA_HISTOGRAM_CUSTOM_COUNTS("Precache.Fetch.ResponseBytes.Total",
- unfinished_work.total_bytes(),
- 1, kMaxResponseBytes, 100);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Precache.Fetch.ResponseBytes.Total",
+ unfinished_work.total_bytes(), 1,
+ kMaxResponseBytes, 100);
UMA_HISTOGRAM_CUSTOM_COUNTS("Precache.Fetch.ResponseBytes.Network",
- unfinished_work.network_bytes(),
- 1, kMaxResponseBytes,
- 100);
+ unfinished_work.network_bytes(), 1,
+ kMaxResponseBytes, 100);
+}
+
+// static
+std::string PrecacheFetcher::GetResourceURLBase64HashForTesting(
+ const std::vector<GURL>& urls) {
+ return GetResourceURLBase64Hash(urls);
}
PrecacheFetcher::PrecacheFetcher(
@@ -326,10 +398,14 @@ PrecacheFetcher::PrecacheFetcher(
const std::string& manifest_url_prefix,
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work,
uint32_t experiment_id,
+ const base::WeakPtr<PrecacheDatabase>& precache_database,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner,
PrecacheFetcher::PrecacheDelegate* precache_delegate)
: request_context_(request_context),
config_url_(config_url),
manifest_url_prefix_(manifest_url_prefix),
+ precache_database_(precache_database),
+ db_task_runner_(std::move(db_task_runner)),
precache_delegate_(precache_delegate),
pool_(kMaxParallelFetches),
experiment_id_(experiment_id) {
@@ -342,15 +418,16 @@ PrecacheFetcher::PrecacheFetcher(
<< "Could not determine the default precache manifest URL prefix.";
DCHECK(unfinished_work);
- // Copy manifests and resources to member variables as a convenience.
- // TODO(bengr): Consider accessing these directly from the proto.
- for (const auto& manifest : unfinished_work->manifest()) {
- if (manifest.has_url())
- manifest_urls_to_fetch_.push_back(GURL(manifest.url()));
- }
+ // Copy resources to member variable as a convenience.
+ // TODO(rajendrant): Consider accessing these directly from the proto, by
+ // keeping track of the current resource index.
for (const auto& resource : unfinished_work->resource()) {
- if (resource.has_url())
- resource_urls_to_fetch_.push_back(GURL(resource.url()));
+ if (resource.has_url() && resource.has_top_host_name()) {
+ // Weight doesn't matter, as the resources have already been sorted by
+ // this point.
+ resources_to_fetch_.emplace_back(GURL(resource.url()),
+ resource.top_host_name(), 0);
+ }
}
unfinished_work_ = std::move(unfinished_work);
}
@@ -363,21 +440,30 @@ std::unique_ptr<PrecacheUnfinishedWork> PrecacheFetcher::CancelPrecaching() {
if (!unfinished_work_)
return nullptr;
- unfinished_work_->clear_manifest();
unfinished_work_->clear_resource();
- for (const auto& manifest : manifest_urls_to_fetch_)
- unfinished_work_->add_manifest()->set_url(manifest.spec());
- for (const auto& resource : resource_urls_to_fetch_)
- unfinished_work_->add_resource()->set_url(resource.spec());
- for (const auto& it : pool_.elements()) {
- const Fetcher* fetcher = it.first;
- if (fetcher->is_resource_request())
- unfinished_work_->add_resource()->set_url(fetcher->url().spec());
- else if (fetcher->url() != config_url_)
- unfinished_work_->add_manifest()->set_url(fetcher->url().spec());
- }
- manifest_urls_to_fetch_.clear();
- resource_urls_to_fetch_.clear();
+ if (unfinished_work_->has_config_settings()) {
+ // If config fetch is incomplete, |top_hosts_to_fetch_| will be empty and
+ // top hosts should be left as is in |unfinished_work_|.
+ unfinished_work_->clear_top_host();
+ for (const auto& top_host : top_hosts_fetching_)
+ unfinished_work_->add_top_host()->set_hostname(top_host.hostname);
+ for (const auto& top_host : top_hosts_to_fetch_)
+ unfinished_work_->add_top_host()->set_hostname(top_host.hostname);
+ }
+ for (const auto& resource : resources_fetching_) {
+ auto new_resource = unfinished_work_->add_resource();
+ new_resource->set_url(resource.url.spec());
+ new_resource->set_top_host_name(resource.referrer);
+ }
+ for (const auto& resource : resources_to_fetch_) {
+ auto new_resource = unfinished_work_->add_resource();
+ new_resource->set_url(resource.url.spec());
+ new_resource->set_top_host_name(resource.referrer);
+ }
+ top_hosts_fetching_.clear();
+ top_hosts_to_fetch_.clear();
+ resources_fetching_.clear();
+ resources_to_fetch_.clear();
pool_.DeleteAll();
return std::move(unfinished_work_);
}
@@ -397,46 +483,44 @@ void PrecacheFetcher::Start() {
// Fetch the precache configuration settings from the server.
DCHECK(pool_.IsEmpty()) << "All parallel requests should be available";
- VLOG(3) << "Fetching " << config_url;
- pool_.Add(base::WrapUnique(new Fetcher(
- request_context_.get(), config_url,
- base::Bind(&PrecacheFetcher::OnConfigFetchComplete,
- base::Unretained(this)),
- false /* is_resource_request */, std::numeric_limits<int32_t>::max())));
+ pool_.Add(base::MakeUnique<Fetcher>(
+ request_context_.get(), config_url, std::string(),
+ base::Bind(&PrecacheFetcher::OnConfigFetchComplete, AsWeakPtr()),
+ false /* is_resource_request */, std::numeric_limits<int32_t>::max()));
}
void PrecacheFetcher::StartNextResourceFetch() {
DCHECK(unfinished_work_->has_config_settings());
- while (!resource_urls_to_fetch_.empty() && pool_.IsAvailable()) {
- const size_t max_bytes =
+ while (!resources_to_fetch_.empty() && pool_.IsAvailable()) {
+ ResourceInfo& resource = resources_to_fetch_.front();
+ const size_t max_bytes = std::min(
+ quota_.remaining(),
std::min(unfinished_work_->config_settings().max_bytes_per_resource(),
unfinished_work_->config_settings().max_bytes_total() -
- unfinished_work_->total_bytes());
- VLOG(3) << "Fetching " << resource_urls_to_fetch_.front();
- pool_.Add(base::WrapUnique(
- new Fetcher(request_context_.get(), resource_urls_to_fetch_.front(),
- base::Bind(&PrecacheFetcher::OnResourceFetchComplete,
- base::Unretained(this)),
- true /* is_resource_request */, max_bytes)));
-
- resource_urls_to_fetch_.pop_front();
+ unfinished_work_->total_bytes()));
+ pool_.Add(base::MakeUnique<Fetcher>(
+ request_context_.get(), resource.url, resource.referrer,
+ base::Bind(&PrecacheFetcher::OnResourceFetchComplete, AsWeakPtr()),
+ true /* is_resource_request */, max_bytes));
+
+ resources_fetching_.push_back(std::move(resource));
+ resources_to_fetch_.pop_front();
}
}
-void PrecacheFetcher::StartNextManifestFetch() {
- if (manifest_urls_to_fetch_.empty() || !pool_.IsAvailable())
- return;
-
- // We only fetch one manifest at a time to keep the size of
- // resource_urls_to_fetch_ as small as possible.
- VLOG(3) << "Fetching " << manifest_urls_to_fetch_.front();
- pool_.Add(base::WrapUnique(new Fetcher(
- request_context_.get(), manifest_urls_to_fetch_.front(),
- base::Bind(&PrecacheFetcher::OnManifestFetchComplete,
- base::Unretained(this)),
- false /* is_resource_request */, std::numeric_limits<int32_t>::max())));
-
- manifest_urls_to_fetch_.pop_front();
+void PrecacheFetcher::StartNextManifestFetches() {
+ // We fetch as many manifests at a time as possible, as we need all resource
+ // URLs in memory in order to rank them.
+ while (!top_hosts_to_fetch_.empty() && pool_.IsAvailable()) {
+ ManifestHostInfo& top_host = top_hosts_to_fetch_.front();
+ pool_.Add(base::MakeUnique<Fetcher>(
+ request_context_.get(), top_host.manifest_url, top_host.hostname,
+ base::Bind(&PrecacheFetcher::OnManifestFetchComplete, AsWeakPtr(),
+ top_host.visits),
+ false /* is_resource_request */, std::numeric_limits<int32_t>::max()));
+ top_hosts_fetching_.push_back(std::move(top_host));
+ top_hosts_to_fetch_.pop_front();
+ }
}
void PrecacheFetcher::NotifyDone(
@@ -450,27 +534,21 @@ void PrecacheFetcher::NotifyDone(
void PrecacheFetcher::StartNextFetch() {
DCHECK(unfinished_work_->has_config_settings());
- // If over the precache total size cap, then stop prefetching.
- if (unfinished_work_->total_bytes() >
- unfinished_work_->config_settings().max_bytes_total()) {
- size_t pending_manifests_in_pool = 0;
- size_t pending_resources_in_pool = 0;
- for (const auto& element_pair : pool_.elements()) {
- const Fetcher* fetcher = element_pair.first;
- if (fetcher->is_resource_request())
- pending_resources_in_pool++;
- else if (fetcher->url() != config_url_)
- pending_manifests_in_pool++;
- }
+
+ // If over the precache total size cap or daily quota, then stop prefetching.
+ if ((unfinished_work_->total_bytes() >
+ unfinished_work_->config_settings().max_bytes_total()) ||
+ quota_.remaining() == 0) {
pool_.DeleteAll();
- NotifyDone(manifest_urls_to_fetch_.size() + pending_manifests_in_pool,
- resource_urls_to_fetch_.size() + pending_resources_in_pool);
+ NotifyDone(top_hosts_to_fetch_.size() + top_hosts_fetching_.size(),
+ resources_to_fetch_.size() + resources_fetching_.size());
return;
}
StartNextResourceFetch();
- StartNextManifestFetch();
- if (pool_.IsEmpty()) {
+ StartNextManifestFetches();
+ if (top_hosts_to_fetch_.empty() && resources_to_fetch_.empty() &&
+ pool_.IsEmpty()) {
// There are no more URLs to fetch, so end the precache cycle.
NotifyDone(0, 0);
// OnDone may have deleted this PrecacheFetcher, so don't do anything after
@@ -495,44 +573,130 @@ void PrecacheFetcher::OnConfigFetchComplete(const Fetcher& source) {
void PrecacheFetcher::DetermineManifests() {
DCHECK(unfinished_work_->has_config_settings());
- std::string prefix = manifest_url_prefix_.empty()
- ? GetDefaultManifestURLPrefix()
- : manifest_url_prefix_;
- DCHECK_NE(std::string(), prefix)
- << "Could not determine the precache manifest URL prefix.";
-
- // Keep track of manifest URLs that are being fetched, in order to elide
- // duplicates.
- base::hash_set<std::string> seen_manifest_urls;
-
- // Attempt to fetch manifests for starting hosts up to the maximum top sites
- // count. If a manifest does not exist for a particular starting host, then
- // the fetch will fail, and that starting host will be ignored. Starting
- // hosts are not added if this is a continuation from a previous precache
- // session.
- if (manifest_urls_to_fetch_.empty() &&
- resource_urls_to_fetch_.empty()) {
- int64_t rank = 0;
- for (const auto& host : unfinished_work_->top_host()) {
- ++rank;
- if (rank > unfinished_work_->config_settings().top_sites_count())
- break;
- AppendManifestURLIfValidAndNew(prefix, host.hostname(),
- &seen_manifest_urls,
- &manifest_urls_to_fetch_);
- }
- for (const std::string& host
- : unfinished_work_->config_settings().forced_site()) {
- AppendManifestURLIfValidAndNew(prefix, host, &seen_manifest_urls,
- &manifest_urls_to_fetch_);
- }
+ std::vector<std::pair<std::string, int64_t>> top_hosts_to_fetch;
+ // Keep track of manifest URLs that are being fetched, in order to elide
+ // duplicates.
+ std::set<base::StringPiece> seen_top_hosts;
+ int64_t rank = 0;
+
+ for (const auto& host : unfinished_work_->top_host()) {
+ ++rank;
+ if (rank > unfinished_work_->config_settings().top_sites_count())
+ break;
+ if (seen_top_hosts.insert(host.hostname()).second)
+ top_hosts_to_fetch.emplace_back(host.hostname(), host.visits());
+ }
+
+ // Attempt to fetch manifests for starting hosts up to the maximum top sites
+ // count. If a manifest does not exist for a particular starting host, then
+ // the fetch will fail, and that starting host will be ignored. Starting
+ // hosts are not added if this is a continuation from a previous precache
+ // session.
+ if (resources_to_fetch_.empty()) {
+ for (const std::string& host :
+ unfinished_work_->config_settings().forced_site()) {
+ // We add a forced site with visits == 0, which means its resources will
+ // be downloaded last. TODO(twifkak): Consider removing support for
+ // forced_site.
+ if (seen_top_hosts.insert(host).second)
+ top_hosts_to_fetch.emplace_back(host, 0);
+ }
+ }
+ // We retrieve manifest usage and quota info from the local database before
+ // fetching the manifests.
+ PostTaskAndReplyWithResult(
+ db_task_runner_.get(), FROM_HERE,
+ base::Bind(&RetrieveManifestInfo, precache_database_,
+ std::move(top_hosts_to_fetch)),
+ base::Bind(&PrecacheFetcher::OnManifestInfoRetrieved, AsWeakPtr()));
+}
+
+void PrecacheFetcher::OnManifestInfoRetrieved(
+ std::deque<ManifestHostInfo> manifests_info) {
+ const std::string prefix = manifest_url_prefix_.empty()
+ ? GetDefaultManifestURLPrefix()
+ : manifest_url_prefix_;
+ if (!GURL(prefix).is_valid()) {
+ // Don't attempt to fetch any manifests if the manifest URL prefix
+ // is invalid.
+ top_hosts_to_fetch_.clear();
+ unfinished_work_->set_num_manifest_urls(manifests_info.size());
+ NotifyDone(manifests_info.size(), resources_to_rank_.size());
+ return;
+ }
+
+ top_hosts_to_fetch_ = std::move(manifests_info);
+ for (auto& manifest : top_hosts_to_fetch_) {
+ manifest.manifest_url =
+ GURL(prefix +
+ net::EscapeQueryParamValue(
+ net::EscapeQueryParamValue(manifest.hostname, false), false));
+ if (manifest.manifest_id != PrecacheReferrerHostEntry::kInvalidId) {
+ manifest.manifest_url = net::AppendOrReplaceQueryParameter(
+ manifest.manifest_url, "manifest",
+ std::to_string(manifest.manifest_id));
+ manifest.manifest_url = net::AppendOrReplaceQueryParameter(
+ manifest.manifest_url, "used_resources", manifest.used_url_hash);
+ manifest.manifest_url = net::AppendOrReplaceQueryParameter(
+ manifest.manifest_url, "unused_resources", manifest.unused_url_hash);
+ DCHECK(manifest.manifest_url.is_valid());
}
- unfinished_work_->set_num_manifest_urls(manifest_urls_to_fetch_.size());
- StartNextFetch();
+ }
+ unfinished_work_->set_num_manifest_urls(top_hosts_to_fetch_.size());
+
+ PostTaskAndReplyWithResult(
+ db_task_runner_.get(), FROM_HERE,
+ base::Bind(&RetrieveQuotaInfo, precache_database_),
+ base::Bind(&PrecacheFetcher::OnQuotaInfoRetrieved, AsWeakPtr()));
+}
+
+void PrecacheFetcher::OnQuotaInfoRetrieved(const PrecacheQuota& quota) {
+ quota_ = quota;
+ base::Time time_now = base::Time::Now();
+ if (IsQuotaTimeExpired(quota_, time_now)) {
+ // This is a new day. Update daily quota, that starts today and expires by
+ // end of today.
+ quota_.set_start_time(time_now.LocalMidnight().ToInternalValue());
+ quota_.set_remaining(
+ unfinished_work_->config_settings().daily_quota_total());
+ db_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&PrecacheDatabase::SaveQuota, precache_database_, quota_));
+ }
+ StartNextFetch();
}
-void PrecacheFetcher::OnManifestFetchComplete(const Fetcher& source) {
+ManifestHostInfo::ManifestHostInfo(int64_t manifest_id,
+ const std::string& hostname,
+ int64_t visits,
+ const std::string& used_url_hash,
+ const std::string& unused_url_hash)
+ : manifest_id(manifest_id),
+ hostname(hostname),
+ visits(visits),
+ used_url_hash(used_url_hash),
+ unused_url_hash(unused_url_hash) {}
+
+ManifestHostInfo::~ManifestHostInfo() {}
+
+ManifestHostInfo::ManifestHostInfo(ManifestHostInfo&&) = default;
+
+ManifestHostInfo& ManifestHostInfo::operator=(ManifestHostInfo&&) = default;
+
+ResourceInfo::ResourceInfo(const GURL& url,
+ const std::string& referrer,
+ double weight)
+ : url(url), referrer(referrer), weight(weight) {}
+
+ResourceInfo::~ResourceInfo() {}
+
+ResourceInfo::ResourceInfo(ResourceInfo&&) = default;
+
+ResourceInfo& ResourceInfo::operator=(ResourceInfo&&) = default;
+
+void PrecacheFetcher::OnManifestFetchComplete(int64_t host_visits,
+ const Fetcher& source) {
DCHECK(unfinished_work_->has_config_settings());
UpdateStats(source.response_bytes(), source.network_response_bytes());
if (source.network_url_fetcher() == nullptr) {
@@ -550,20 +714,72 @@ void PrecacheFetcher::OnManifestFetchComplete(const Fetcher& source) {
if (((0x1ULL << i) & resource_bitset) &&
manifest.resource(i).has_url()) {
GURL url(manifest.resource(i).url());
- if (url.is_valid())
- resource_urls_to_fetch_.push_back(url);
+ if (url.is_valid()) {
+ double weight = ResourceWeight(manifest.resource(i), host_visits);
+ if (weight >= unfinished_work_->config_settings().min_weight())
+ resources_to_rank_.emplace_back(url, source.referrer(), weight);
+ }
}
}
+ db_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&PrecacheDatabase::UpdatePrecacheReferrerHost,
+ precache_database_, source.referrer(),
+ manifest.id().id(), base::Time::Now()));
}
}
+ top_hosts_fetching_.remove_if([&source](const ManifestHostInfo& top_host) {
+ return top_host.manifest_url == source.url();
+ });
+
pool_.Delete(source);
+
+ if (top_hosts_to_fetch_.empty() && top_hosts_fetching_.empty())
+ QueueResourcesForFetch();
+
StartNextFetch();
}
+void PrecacheFetcher::QueueResourcesForFetch() {
+ // Done fetching manifests. Now move resources_to_rank_ into
+ // resources_to_fetch_, so that StartNextFetch will begin fetching resources.
+ resources_to_fetch_ = std::move(resources_to_rank_);
+
+ if (unfinished_work_->config_settings().global_ranking()) {
+ // Sort resources_to_fetch_ by descending weight.
+ std::stable_sort(resources_to_fetch_.begin(), resources_to_fetch_.end(),
+ [](const ResourceInfo& first, const ResourceInfo& second) {
+ return first.weight > second.weight;
+ });
+ }
+
+ // Truncate to size |total_resources_count|.
+ const size_t num_resources = std::min(
+ resources_to_fetch_.size(),
+ static_cast<size_t>(
+ unfinished_work_->config_settings().total_resources_count()));
+ resources_to_fetch_.erase(resources_to_fetch_.begin() + num_resources,
+ resources_to_fetch_.end());
+
+ // Save denominator for PercentCompleted UMA.
+ unfinished_work_->set_num_resource_urls(resources_to_fetch_.size());
+}
+
void PrecacheFetcher::OnResourceFetchComplete(const Fetcher& source) {
UpdateStats(source.response_bytes(), source.network_response_bytes());
+
+ db_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&PrecacheDatabase::RecordURLPrefetch, precache_database_,
+ source.url(), source.referrer(), base::Time::Now(),
+ source.was_cached(), source.response_bytes()));
+
+ resources_fetching_.remove_if([&source](const ResourceInfo& resource) {
+ return resource.url == source.url();
+ });
+
pool_.Delete(source);
+
// The resource has already been put in the cache during the fetch process, so
// nothing more needs to be done for the resource.
StartNextFetch();
@@ -571,10 +787,26 @@ void PrecacheFetcher::OnResourceFetchComplete(const Fetcher& source) {
void PrecacheFetcher::UpdateStats(int64_t response_bytes,
int64_t network_response_bytes) {
+ DCHECK_LE(0, response_bytes);
+ DCHECK_LE(0, network_response_bytes);
+
unfinished_work_->set_total_bytes(
unfinished_work_->total_bytes() + response_bytes);
unfinished_work_->set_network_bytes(
unfinished_work_->network_bytes() + network_response_bytes);
+
+ if (!IsQuotaTimeExpired(quota_, base::Time::Now())) {
+ uint64_t used_bytes = static_cast<uint64_t>(network_response_bytes);
+ int64_t remaining =
+ static_cast<int64_t>(quota_.remaining()) - network_response_bytes;
+ if (remaining < 0)
+ remaining = 0;
+ quota_.set_remaining(
+ used_bytes > quota_.remaining() ? 0U : quota_.remaining() - used_bytes);
+ db_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&PrecacheDatabase::SaveQuota, precache_database_, quota_));
+ }
}
} // namespace precache
diff --git a/chromium/components/precache/core/precache_fetcher.h b/chromium/components/precache/core/precache_fetcher.h
index 24307b2a02f..33c9a97adf2 100644
--- a/chromium/components/precache/core/precache_fetcher.h
+++ b/chromium/components/precache/core/precache_fetcher.h
@@ -7,7 +7,7 @@
#include <stdint.h>
-#include <algorithm>
+#include <deque>
#include <list>
#include <memory>
#include <string>
@@ -15,10 +15,12 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "components/precache/core/fetcher_pool.h"
+#include "components/precache/core/proto/quota.pb.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "url/gurl.h"
@@ -34,10 +36,45 @@ class URLRequestContextGetter;
namespace precache {
class PrecacheConfigurationSettings;
+class PrecacheDatabase;
class PrecacheUnfinishedWork;
// Visible for testing.
extern const int kNoTracking;
+extern const int kMaxParallelFetches;
+
+// Information about the manifest for a host.
+struct ManifestHostInfo {
+ ManifestHostInfo(int64_t manifest_id,
+ const std::string& hostname,
+ int64_t visits,
+ const std::string& used_url_hash,
+ const std::string& unused_url_hash);
+ ~ManifestHostInfo();
+ ManifestHostInfo(ManifestHostInfo&&);
+ ManifestHostInfo& operator=(ManifestHostInfo&&);
+ // Copy constructor and assignment operator are implicitly deleted.
+
+ int64_t manifest_id;
+ std::string hostname;
+ GURL manifest_url;
+ int64_t visits;
+ std::string used_url_hash;
+ std::string unused_url_hash;
+};
+
+// Information about a resource to be downloaded.
+struct ResourceInfo {
+ ResourceInfo(const GURL& url, const std::string& referrer, double weight);
+ ~ResourceInfo();
+ ResourceInfo(ResourceInfo&&);
+ ResourceInfo& operator=(ResourceInfo&&);
+ // Copy constructor and assignment operator are implicitly deleted.
+
+ GURL url; // The resource being requested.
+ std::string referrer; // The host of the manifest requesting this resource.
+ double weight; // Estimate of the expected utility of this resource.
+};
// Public interface to code that fetches resources that the user is likely to
// want to fetch in the future, putting them in the network stack disk cache.
@@ -90,7 +127,6 @@ class PrecacheFetcher : public base::SupportsWeakPtr<PrecacheFetcher> {
// were fetched or not. If the PrecacheFetcher is destroyed before OnDone is
// called, then precaching will be canceled and OnDone will not be called.
virtual void OnDone() = 0;
-
};
// Visible for testing.
@@ -101,16 +137,23 @@ class PrecacheFetcher : public base::SupportsWeakPtr<PrecacheFetcher> {
size_t remaining_manifest_urls_to_fetch,
size_t remaining_resource_urls_to_fetch);
- // Constructs a new PrecacheFetcher. The |starting_hosts| parameter is a
+ static std::string GetResourceURLBase64HashForTesting(
+ const std::vector<GURL>& urls);
+
+ // Constructs a new PrecacheFetcher. The |unfinished_work| contains the
// prioritized list of hosts that the user commonly visits. These hosts are
// used by a server side component to construct a list of resource URLs that
// the user is likely to fetch. Takes ownership of |unfinished_work|.
- PrecacheFetcher(net::URLRequestContextGetter* request_context,
- const GURL& config_url,
- const std::string& manifest_url_prefix,
- std::unique_ptr<PrecacheUnfinishedWork> unfinished_work,
- uint32_t experiment_id,
- PrecacheDelegate* precache_delegate);
+ // |precache_database| should be accessed only in |db_task_runner|.
+ PrecacheFetcher(
+ net::URLRequestContextGetter* request_context,
+ const GURL& config_url,
+ const std::string& manifest_url_prefix,
+ std::unique_ptr<PrecacheUnfinishedWork> unfinished_work,
+ uint32_t experiment_id,
+ const base::WeakPtr<PrecacheDatabase>& precache_database,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner,
+ PrecacheDelegate* precache_delegate);
virtual ~PrecacheFetcher();
@@ -125,7 +168,12 @@ class PrecacheFetcher : public base::SupportsWeakPtr<PrecacheFetcher> {
private:
friend class PrecacheFetcherTest;
+ FRIEND_TEST_ALL_PREFIXES(PrecacheFetcherTest,
+ GloballyRankResourcesAfterPauseResume);
FRIEND_TEST_ALL_PREFIXES(PrecacheFetcherTest, FetcherPoolMaxLimitReached);
+ FRIEND_TEST_ALL_PREFIXES(PrecacheFetcherTest,
+ CancelPrecachingAfterAllManifestFetch);
+ FRIEND_TEST_ALL_PREFIXES(PrecacheFetcherTest, DailyQuota);
// Notifies the precache delete that precaching is done, and report
// completion statistics.
@@ -138,7 +186,7 @@ class PrecacheFetcher : public base::SupportsWeakPtr<PrecacheFetcher> {
// the |resource_urls_to_fetch_| list, reducing the memory usage.
void StartNextFetch();
- void StartNextManifestFetch();
+ void StartNextManifestFetches();
void StartNextResourceFetch();
// Called when the precache configuration settings have been fetched.
@@ -153,7 +201,13 @@ class PrecacheFetcher : public base::SupportsWeakPtr<PrecacheFetcher> {
// Called when a precache manifest has been fetched. Builds the list of
// resource URLs to fetch according to the URLs in the manifest. If the fetch
// of a manifest fails, then it skips to the next manifest.
- void OnManifestFetchComplete(const Fetcher& source);
+ void OnManifestFetchComplete(int64_t host_visits, const Fetcher& source);
+
+ // Moves the pending resource URLs into the to-be-fetched queue, and sorts and
+ // truncates if specified by the PrecacheConfigurationSettings. Called by
+ // OnManifestFetchComplete after the last manifest is fetched, so that
+ // StartNextFetch will begin fetching resource URLs.
+ void QueueResourcesForFetch();
// Called when a resource has been fetched.
void OnResourceFetchComplete(const Fetcher& source);
@@ -161,6 +215,12 @@ class PrecacheFetcher : public base::SupportsWeakPtr<PrecacheFetcher> {
// Adds up the response sizes.
void UpdateStats(int64_t response_bytes, int64_t network_response_bytes);
+ // Callback invoked when the manifest info for all the top hosts is retrieved.
+ void OnManifestInfoRetrieved(std::deque<ManifestHostInfo> manifests_info);
+
+ // Callback invoked when the quota is retrieved.
+ void OnQuotaInfoRetrieved(const PrecacheQuota& quota);
+
// The request context used when fetching URLs.
const scoped_refptr<net::URLRequestContextGetter> request_context_;
@@ -172,16 +232,38 @@ class PrecacheFetcher : public base::SupportsWeakPtr<PrecacheFetcher> {
// default flag-specified prefix will be used.
const std::string manifest_url_prefix_;
+ // PrecacheDatabase should be accessed on the DB thread.
+ base::WeakPtr<PrecacheDatabase> precache_database_;
+ scoped_refptr<base::SingleThreadTaskRunner> db_task_runner_;
+
// Non-owning pointer. Should not be NULL.
PrecacheDelegate* precache_delegate_;
- std::list<GURL> manifest_urls_to_fetch_;
- std::list<GURL> resource_urls_to_fetch_;
+ // Top hosts for which manifests still need to be fetched (i.e. no Fetcher has
+ // been created yet).
+ std::deque<ManifestHostInfo> top_hosts_to_fetch_;
+
+ // Top hosts for which manifests are currently being fetched.
+ std::list<ManifestHostInfo> top_hosts_fetching_;
+
+ // Resources to be fetched, in desired fetch order. Populated only after
+ // manifest fetching is complete.
+ std::deque<ResourceInfo> resources_to_fetch_;
+
+ // Resources currently being fetched, in the order requested.
+ std::list<ResourceInfo> resources_fetching_;
+
+ // Resources to be fetched, not yet ranked. Valid until manifest fetching is
+ // done, after which resources are sorted and places in resources_to_fetch_.
+ std::deque<ResourceInfo> resources_to_rank_;
FetcherPool<Fetcher> pool_;
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work_;
+ // Daily quota.
+ PrecacheQuota quota_;
+
// The fieldtrial experiment ID.
uint32_t experiment_id_;
@@ -214,13 +296,15 @@ class PrecacheFetcher::Fetcher : public net::URLFetcherDelegate {
// the specified URL using the specified request context.
Fetcher(net::URLRequestContextGetter* request_context,
const GURL& url,
+ const std::string& referrer,
const base::Callback<void(const Fetcher&)>& callback,
bool is_resource_request,
size_t max_bytes);
~Fetcher() override;
void OnURLFetchDownloadProgress(const net::URLFetcher* source,
int64_t current,
- int64_t total) override;
+ int64_t total,
+ int64_t current_network_bytes) override;
void OnURLFetchComplete(const net::URLFetcher* source) override;
int64_t response_bytes() const { return response_bytes_; }
int64_t network_response_bytes() const { return network_response_bytes_; }
@@ -228,7 +312,9 @@ class PrecacheFetcher::Fetcher : public net::URLFetcherDelegate {
return network_url_fetcher_.get();
}
const GURL& url() const { return url_; }
+ const std::string& referrer() const { return referrer_; }
bool is_resource_request() const { return is_resource_request_; }
+ bool was_cached() const { return was_cached_; }
private:
enum class FetchStage { CACHE, NETWORK };
@@ -238,6 +324,7 @@ class PrecacheFetcher::Fetcher : public net::URLFetcherDelegate {
net::URLRequestContextGetter* const request_context_;
const GURL url_;
+ const std::string referrer_;
const base::Callback<void(const Fetcher&)> callback_;
const bool is_resource_request_;
const size_t max_bytes_;
@@ -248,6 +335,7 @@ class PrecacheFetcher::Fetcher : public net::URLFetcherDelegate {
std::unique_ptr<net::URLFetcher> network_url_fetcher_;
int64_t response_bytes_;
int64_t network_response_bytes_;
+ bool was_cached_;
DISALLOW_COPY_AND_ASSIGN(Fetcher);
};
diff --git a/chromium/components/precache/core/precache_fetcher_unittest.cc b/chromium/components/precache/core/precache_fetcher_unittest.cc
index d4e96c3ee37..66d8e3de2e8 100644
--- a/chromium/components/precache/core/precache_fetcher_unittest.cc
+++ b/chromium/components/precache/core/precache_fetcher_unittest.cc
@@ -10,24 +10,31 @@
#include <memory>
#include <set>
#include <string>
+#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/test/histogram_tester.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/precache/core/precache_database.h"
#include "components/precache/core/precache_switches.h"
#include "components/precache/core/proto/precache.pb.h"
#include "components/precache/core/proto/unfinished_work.pb.h"
+#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
+#include "net/http/http_response_info.h"
#include "net/http/http_status_code.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_status.h"
@@ -84,20 +91,19 @@ class TestURLFetcherCallback {
url, delegate, response_data, response_code, status));
total_response_bytes_ += response_data.size();
- requested_urls_.insert(url);
+ requested_urls_.push_back(url);
return fetcher;
}
- const std::multiset<GURL>& requested_urls() const {
- return requested_urls_;
- }
+ const std::vector<GURL>& requested_urls() const { return requested_urls_; }
+
+ void clear_requested_urls() { requested_urls_.clear(); }
int total_response_bytes() const { return total_response_bytes_; }
private:
- // Multiset with one entry for each URL requested.
- std::multiset<GURL> requested_urls_;
+ std::vector<GURL> requested_urls_;
int total_response_bytes_;
};
@@ -106,7 +112,10 @@ class TestPrecacheDelegate : public PrecacheFetcher::PrecacheDelegate {
TestPrecacheDelegate()
: on_done_was_called_(false) {}
- void OnDone() override { on_done_was_called_ = true; }
+ void OnDone() override {
+ LOG(INFO) << "OnDone";
+ on_done_was_called_ = true;
+ }
bool was_on_done_called() const {
return on_done_was_called_;
@@ -172,7 +181,7 @@ class MockURLFetcherFactory : public net::URLFetcherFactory {
const GURL&,
net::URLFetcher::RequestType,
net::URLFetcherDelegate*>& args) {
- auto fetcher = new net::FakeURLFetcher(
+ auto* fetcher = new net::FakeURLFetcher(
testing::get<1>(args), testing::get<3>(args), body_, net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
modifier_(fetcher);
@@ -229,10 +238,10 @@ TEST_F(PrecacheFetcherFetcherTest, Config) {
NotNull())));
PrecacheFetcher::Fetcher precache_fetcher(
- request_context_.get(), url, callback_, false /* is_resource_request */,
- SIZE_MAX);
+ request_context_.get(), url, url.host(), callback_,
+ false /* is_resource_request */, SIZE_MAX);
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
ASSERT_NE(nullptr, fetcher);
EXPECT_EQ(kNoTracking, fetcher->GetLoadFlags());
@@ -251,10 +260,10 @@ TEST_F(PrecacheFetcherFetcherTest, ResourceNotInCache) {
.Times(1);
PrecacheFetcher::Fetcher precache_fetcher(
- request_context_.get(), url, callback_, true /* is_resource_request */,
- SIZE_MAX);
+ request_context_.get(), url, url.host(), callback_,
+ true /* is_resource_request */, SIZE_MAX);
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
ASSERT_NE(nullptr, fetcher1);
EXPECT_EQ(net::LOAD_ONLY_FROM_CACHE | kNoTracking, fetcher1->GetLoadFlags());
@@ -274,10 +283,10 @@ TEST_F(PrecacheFetcherFetcherTest, ResourceHasValidators) {
NotNull())));
PrecacheFetcher::Fetcher precache_fetcher(
- request_context_.get(), url, callback_, true /* is_resource_request */,
- SIZE_MAX);
+ request_context_.get(), url, url.host(), callback_,
+ true /* is_resource_request */, SIZE_MAX);
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
ASSERT_NE(nullptr, fetcher1);
EXPECT_EQ(net::LOAD_ONLY_FROM_CACHE | kNoTracking, fetcher1->GetLoadFlags());
@@ -296,10 +305,10 @@ TEST_F(PrecacheFetcherFetcherTest, ResourceHasNoValidators) {
nullptr))); // It never reached the network.
PrecacheFetcher::Fetcher precache_fetcher(
- request_context_.get(), url, callback_, true /* is_resource_request */,
- SIZE_MAX);
+ request_context_.get(), url, url.host(), callback_,
+ true /* is_resource_request */, SIZE_MAX);
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(net::LOAD_ONLY_FROM_CACHE | kNoTracking, fetcher->GetLoadFlags());
}
@@ -323,16 +332,17 @@ TEST_F(PrecacheFetcherFetcherTest, ResourceTooBig) {
nullptr)));
PrecacheFetcher::Fetcher precache_fetcher(
- request_context_.get(), url, callback_, true /* is_resource_request */,
- 99 /* max_bytes */);
+ request_context_.get(), url, url.host(), callback_,
+ true /* is_resource_request */, 99 /* max_bytes */);
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
class PrecacheFetcherTest : public testing::Test {
public:
PrecacheFetcherTest()
- : request_context_(new net::TestURLRequestContextGetter(
+ : task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ request_context_(new net::TestURLRequestContextGetter(
base::ThreadTaskRunnerHandle::Get())),
factory_(NULL,
base::Bind(&TestURLFetcherCallback::CreateURLFetcher,
@@ -340,7 +350,34 @@ class PrecacheFetcherTest : public testing::Test {
expected_total_response_bytes_(0),
parallel_fetches_beyond_capacity_(false) {}
+ void UpdatePrecacheReferrerHost(const std::string& hostname,
+ int64_t manifest_id) {
+ precache_database_.UpdatePrecacheReferrerHost(hostname, manifest_id,
+ base::Time());
+ }
+
+ void RecordURLPrefetch(const GURL& url, const std::string& referrer_host) {
+ precache_database_.RecordURLPrefetch(url, referrer_host, base::Time::Now(),
+ false /* was_cached */,
+ 1000 /* size */);
+ }
+
+ void RecordURLNonPrefetch(const GURL& url) {
+ net::HttpResponseInfo info;
+ info.was_cached = true;
+ info.headers = new net::HttpResponseHeaders(std::string());
+ precache_database_.RecordURLNonPrefetch(
+ url, base::TimeDelta(), base::Time::Now(), info, 1000 /* size */,
+ 0 /* host_rank */, false /* is_connection_cellular */);
+ }
+
protected:
+ void SetUp() override {
+ ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
+ base::FilePath db_path = scoped_temp_dir_.GetPath().Append(
+ base::FilePath(FILE_PATH_LITERAL("precache_database")));
+ precache_database_.Init(db_path);
+ }
void SetDefaultFlags() {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kPrecacheConfigSettingsURL, kConfigURL);
@@ -354,25 +391,33 @@ class PrecacheFetcherTest : public testing::Test {
void CheckUntilParallelFetchesBeyondCapacity(
const PrecacheFetcher* precache_fetcher) {
if (!precache_fetcher->pool_.IsAvailable() &&
- !precache_fetcher->resource_urls_to_fetch_.empty() &&
- !precache_fetcher->manifest_urls_to_fetch_.empty()) {
+ (!precache_fetcher->top_hosts_to_fetch_.empty() ||
+ !precache_fetcher->resources_to_fetch_.empty())) {
parallel_fetches_beyond_capacity_ = true;
return;
}
// Check again after allowing the message loop to process some messages.
- loop_.PostTask(
+ loop_.task_runner()->PostTask(
FROM_HERE,
base::Bind(
&PrecacheFetcherTest::CheckUntilParallelFetchesBeyondCapacity,
base::Unretained(this), precache_fetcher));
}
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner() const {
+ return task_runner_;
+ }
+
+ // Must be declared first so that it is destroyed last.
base::MessageLoopForUI loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
scoped_refptr<net::TestURLRequestContextGetter> request_context_;
TestURLFetcherCallback url_callback_;
net::FakeURLFetcherFactory factory_;
TestPrecacheDelegate precache_delegate_;
+ base::ScopedTempDir scoped_temp_dir_;
+ PrecacheDatabase precache_database_;
int expected_total_response_bytes_;
// True if more parallel fetches were attempted beyond the fetcher pool
@@ -424,24 +469,25 @@ TEST_F(PrecacheFetcherTest, FullPrecache) {
base::HistogramTester histogram;
{
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Destroy the PrecacheFetcher after it has finished, to record metrics.
}
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(kConfigURL));
- expected_requested_urls.insert(GURL(kManifestFetchFailureURL));
- expected_requested_urls.insert(GURL(kBadManifestURL));
- expected_requested_urls.insert(GURL(kGoodManifestURL));
- expected_requested_urls.insert(GURL(kResourceFetchFailureURL));
- expected_requested_urls.insert(GURL(kGoodResourceURL));
- expected_requested_urls.insert(GURL(kForcedStartingURLManifestURL));
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kConfigURL);
+ expected_requested_urls.emplace_back(kManifestFetchFailureURL);
+ expected_requested_urls.emplace_back(kBadManifestURL);
+ expected_requested_urls.emplace_back(kGoodManifestURL);
+ expected_requested_urls.emplace_back(kForcedStartingURLManifestURL);
+ expected_requested_urls.emplace_back(kResourceFetchFailureURL);
+ expected_requested_urls.emplace_back(kGoodResourceURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
@@ -492,22 +538,23 @@ TEST_F(PrecacheFetcherTest, PrecacheResourceSelection) {
base::HistogramTester histogram;
{
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Destroy the PrecacheFetcher after it has finished, to record metrics.
}
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(kConfigURL));
- expected_requested_urls.insert(GURL(kGoodManifestURL));
- expected_requested_urls.insert(GURL(kGoodResourceURL));
- expected_requested_urls.insert(GURL(kGoodResourceURLB));
- expected_requested_urls.insert(GURL(kGoodResourceURLD));
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kConfigURL);
+ expected_requested_urls.emplace_back(kGoodManifestURL);
+ expected_requested_urls.emplace_back(kGoodResourceURL);
+ expected_requested_urls.emplace_back(kGoodResourceURLB);
+ expected_requested_urls.emplace_back(kGoodResourceURLD);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
@@ -564,24 +611,25 @@ TEST_F(PrecacheFetcherTest, PrecacheResourceSelectionMissingBitset) {
base::HistogramTester histogram;
{
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Destroy the PrecacheFetcher after it has finished, to record metrics.
}
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(kConfigURL));
- expected_requested_urls.insert(GURL(kGoodManifestURL));
- expected_requested_urls.insert(GURL(kGoodResourceURL));
- expected_requested_urls.insert(GURL(kGoodResourceURLA));
- expected_requested_urls.insert(GURL(kGoodResourceURLB));
- expected_requested_urls.insert(GURL(kGoodResourceURLC));
- expected_requested_urls.insert(GURL(kGoodResourceURLD));
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kConfigURL);
+ expected_requested_urls.emplace_back(kGoodManifestURL);
+ expected_requested_urls.emplace_back(kGoodResourceURL);
+ expected_requested_urls.emplace_back(kGoodResourceURLA);
+ expected_requested_urls.emplace_back(kGoodResourceURLB);
+ expected_requested_urls.emplace_back(kGoodResourceURLC);
+ expected_requested_urls.emplace_back(kGoodResourceURLD);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
@@ -601,23 +649,23 @@ TEST_F(PrecacheFetcherTest, PrecachePauseResume) {
std::unique_ptr<PrecacheUnfinishedWork> initial_work(
new PrecacheUnfinishedWork());
- initial_work->add_manifest()->set_url(
- "http://manifest-url-prefix.com/manifest1.com");
- initial_work->add_manifest()->set_url(
- "http://manifest-url-prefix.com/manifest2.com");
- initial_work->add_resource()->set_url(kGoodResourceURL);
+ initial_work->add_top_host()->set_hostname("manifest1.com");
+ initial_work->add_top_host()->set_hostname("manifest2.com");
initial_work->set_start_time(
(base::Time::Now() - base::TimeDelta::FromHours(1)).ToInternalValue());
PrecacheFetcher first_fetcher(request_context_.get(), GURL(), std::string(),
std::move(initial_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(),
&precache_delegate_);
-
- loop_.RunUntilIdle();
+ factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ first_fetcher.Start();
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work =
first_fetcher.CancelPrecaching();
- std::multiset<GURL> expected_requested_urls;
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kConfigURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
@@ -632,19 +680,18 @@ TEST_F(PrecacheFetcherTest, PrecachePauseResume) {
net::URLRequestStatus::SUCCESS);
factory_.SetFakeResponse(GURL(kGoodResourceURL), "good", net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
- // Starting hosts should not be fetched.
- unfinished_work->add_top_host()->set_hostname("bad-manifest.com");
+
+ url_callback_.clear_requested_urls();
PrecacheFetcher second_fetcher(request_context_.get(), GURL(), std::string(),
std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(),
&precache_delegate_);
second_fetcher.Start();
- loop_.RunUntilIdle();
- expected_requested_urls.insert(GURL(kConfigURL));
- expected_requested_urls.insert(
- GURL("http://manifest-url-prefix.com/manifest1.com"));
- expected_requested_urls.insert(
- GURL("http://manifest-url-prefix.com/manifest2.com"));
- expected_requested_urls.insert(GURL(kGoodResourceURL));
+ base::RunLoop().RunUntilIdle();
+ expected_requested_urls.emplace_back(
+ "http://manifest-url-prefix.com/manifest1.com");
+ expected_requested_urls.emplace_back(
+ "http://manifest-url-prefix.com/manifest2.com");
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
}
@@ -665,21 +712,21 @@ TEST_F(PrecacheFetcherTest, ResumeWithConfigOnly) {
factory_.SetFakeResponse(GURL(kGoodResourceURL), "good", net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
{
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(kGoodManifestURL));
- expected_requested_urls.insert(GURL(kGoodResourceURL));
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kGoodManifestURL);
+ expected_requested_urls.emplace_back(kGoodResourceURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
-
}
@@ -705,15 +752,16 @@ TEST_F(PrecacheFetcherTest, CustomURLs) {
PrecacheFetcher precache_fetcher(
request_context_.get(), GURL(kCustomConfigURL), kCustomManifestURLPrefix,
- std::move(unfinished_work), kExperimentID, &precache_delegate_);
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(kCustomConfigURL));
- expected_requested_urls.insert(GURL(kCustomGoodManifestURL));
- expected_requested_urls.insert(GURL(kGoodResourceURL));
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kCustomConfigURL);
+ expected_requested_urls.emplace_back(kCustomGoodManifestURL);
+ expected_requested_urls.emplace_back(kGoodResourceURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
@@ -733,16 +781,17 @@ TEST_F(PrecacheFetcherTest, ConfigFetchFailure) {
factory_.SetFakeResponse(GURL(kGoodManifestURL), "", net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(), std::move(unfinished_work),
+ kExperimentID, precache_database_.GetWeakPtr(), task_runner(),
+ &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(kConfigURL));
- expected_requested_urls.insert(GURL(kGoodManifestURL));
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kConfigURL);
+ expected_requested_urls.emplace_back(kGoodManifestURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
@@ -760,16 +809,17 @@ TEST_F(PrecacheFetcherTest, BadConfig) {
factory_.SetFakeResponse(GURL(kGoodManifestURL), "", net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(), std::move(unfinished_work),
+ kExperimentID, precache_database_.GetWeakPtr(), task_runner(),
+ &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(kConfigURL));
- expected_requested_urls.insert(GURL(kGoodManifestURL));
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kConfigURL);
+ expected_requested_urls.emplace_back(kGoodManifestURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
@@ -791,9 +841,10 @@ TEST_F(PrecacheFetcherTest, Cancel) {
base::HistogramTester histogram;
{
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
// Destroy the PrecacheFetcher, to cancel precaching. No metrics
@@ -801,10 +852,10 @@ TEST_F(PrecacheFetcherTest, Cancel) {
// called on the precache delegate.
}
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(kConfigURL));
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kConfigURL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
EXPECT_FALSE(precache_delegate_.was_on_done_called());
@@ -828,15 +879,16 @@ TEST_F(PrecacheFetcherTest, PrecacheUsingDefaultConfigSettingsURL) {
config.SerializeAsString(), net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(), std::move(unfinished_work),
+ kExperimentID, precache_database_.GetWeakPtr(), task_runner(),
+ &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(PRECACHE_CONFIG_SETTINGS_URL));
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(PRECACHE_CONFIG_SETTINGS_URL);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
@@ -866,16 +918,17 @@ TEST_F(PrecacheFetcherTest, PrecacheUsingDefaultManifestURLPrefix) {
factory_.SetFakeResponse(manifest_url, PrecacheManifest().SerializeAsString(),
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(), std::move(unfinished_work),
+ kExperimentID, precache_database_.GetWeakPtr(), task_runner(),
+ &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(kConfigURL));
- expected_requested_urls.insert(manifest_url);
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kConfigURL);
+ expected_requested_urls.push_back(manifest_url);
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
@@ -912,22 +965,23 @@ TEST_F(PrecacheFetcherTest, TopResourcesCount) {
base::HistogramTester histogram;
{
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Destroy the PrecacheFetcher after it has finished, to record metrics.
}
- std::multiset<GURL> expected_requested_urls;
- expected_requested_urls.insert(GURL(kConfigURL));
- expected_requested_urls.insert(GURL(kGoodManifestURL));
- expected_requested_urls.insert(GURL("http://good-manifest.com/retrieved"));
- expected_requested_urls.insert(GURL("http://good-manifest.com/retrieved"));
- expected_requested_urls.insert(GURL("http://good-manifest.com/retrieved"));
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kConfigURL);
+ expected_requested_urls.emplace_back(kGoodManifestURL);
+ expected_requested_urls.emplace_back("http://good-manifest.com/retrieved");
+ expected_requested_urls.emplace_back("http://good-manifest.com/retrieved");
+ expected_requested_urls.emplace_back("http://good-manifest.com/retrieved");
EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
@@ -963,10 +1017,19 @@ TEST_F(PrecacheFetcherTest, MaxBytesTotal) {
unfinished_work->add_top_host()->set_hostname("good-manifest.com");
unfinished_work->set_start_time(base::Time::UnixEpoch().ToInternalValue());
- const size_t kNumResources = 15; // > kMaxParallelFetches.
- const size_t kMaxBytesTotal = 1000;
- const size_t kBytesPerResource = kMaxBytesTotal / 3;
- // kBytesPerResource * kMaxParallelFeches > kMaxBytesTotal.
+ // Should be greater than kMaxParallelFetches, so that we can observe
+ // PrecacheFetcher not fetching the remaining resources after max bytes is
+ // exceeded.
+ const size_t kNumResources = kMaxParallelFetches + 5;
+ // Should be smaller than kNumResources - kMaxParallelFetches, such that the
+ // max bytes is guaranteed to be exceeded before all fetches have been
+ // requested. In this case, after 3 fetches have been completed, 3 more are
+ // added to the fetcher pool, but 2 out of 5 still remain.
+ const size_t kResourcesWithinMax = 3;
+ // Should be big enough that the size of the config, manifest, and HTTP
+ // headers are negligible for max bytes computation.
+ const size_t kBytesPerResource = 500;
+ const size_t kMaxBytesTotal = kResourcesWithinMax * kBytesPerResource;
PrecacheConfigurationSettings config;
config.set_max_bytes_total(kMaxBytesTotal);
@@ -989,23 +1052,23 @@ TEST_F(PrecacheFetcherTest, MaxBytesTotal) {
base::HistogramTester histogram;
{
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
- // We don't know which will make it and which won't due to the parallelism in
- // the pool of Fetchers.
- EXPECT_GT(kNumResources, url_callback_.requested_urls().size());
+ // Fetcher should request config, manifest, and all but 3 resources.
+ // TODO(twifkak): I expected all but 2 resources; this result is surprising.
+ // Figure it out and explain it here.
+ EXPECT_EQ(kNumResources - 1, url_callback_.requested_urls().size());
EXPECT_TRUE(precache_delegate_.was_on_done_called());
- // good-manifest.com will not have been completed.
- EXPECT_THAT(histogram.GetAllSamples("Precache.Fetch.PercentCompleted"),
- ElementsAre(base::Bucket(0, 1)));
+ histogram.ExpectTotalCount("Precache.Fetch.PercentCompleted", 1);
histogram.ExpectTotalCount("Precache.Fetch.TimeToComplete", 1);
}
@@ -1015,16 +1078,15 @@ TEST_F(PrecacheFetcherTest, FetcherPoolMaxLimitReached) {
SetDefaultFlags();
const size_t kNumTopHosts = 5;
- const size_t kNumResources = 15;
+ const size_t kNumResources = kMaxParallelFetches + 5;
PrecacheConfigurationSettings config;
- PrecacheManifest top_host_manifest[kNumTopHosts];
- std::multiset<GURL> expected_requested_urls;
+ std::vector<GURL> expected_requested_urls;
config.set_top_sites_count(kNumTopHosts);
factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
- expected_requested_urls.insert(GURL(kConfigURL));
+ expected_requested_urls.emplace_back(kConfigURL);
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
new PrecacheUnfinishedWork());
@@ -1032,34 +1094,40 @@ TEST_F(PrecacheFetcherTest, FetcherPoolMaxLimitReached) {
for (size_t i = 0; i < kNumTopHosts; ++i) {
const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
+ expected_requested_urls.emplace_back(kManifestURLPrefix + top_host_url);
+ }
+
+ for (size_t i = 0; i < kNumTopHosts; ++i) {
+ const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
unfinished_work->add_top_host()->set_hostname(top_host_url);
+ PrecacheManifest manifest;
for (size_t j = 0; j < kNumResources; ++j) {
const std::string resource_url =
base::StringPrintf("http://top-host-%zu.com/resource-%zu", i, j);
- top_host_manifest[i].add_resource()->set_url(resource_url);
+ manifest.add_resource()->set_url(resource_url);
factory_.SetFakeResponse(GURL(resource_url), "good", net::HTTP_OK,
net::URLRequestStatus::SUCCESS);
- expected_requested_urls.insert(GURL(resource_url));
+ expected_requested_urls.emplace_back(resource_url);
}
factory_.SetFakeResponse(GURL(kManifestURLPrefix + top_host_url),
- top_host_manifest[i].SerializeAsString(),
- net::HTTP_OK, net::URLRequestStatus::SUCCESS);
- expected_requested_urls.insert(GURL(kManifestURLPrefix + top_host_url));
+ manifest.SerializeAsString(), net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
}
base::HistogramTester histogram;
{
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
EXPECT_GT(kNumResources, precache_fetcher.pool_.max_size());
CheckUntilParallelFetchesBeyondCapacity(&precache_fetcher);
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Destroy the PrecacheFetcher after it has finished, to record metrics.
}
@@ -1092,12 +1160,13 @@ TEST_F(PrecacheFetcherTest, FilterInvalidManifestUrls) {
base::HistogramTester histogram;
{
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
// The config is fetched, but not the invalid manifest URL.
@@ -1107,7 +1176,7 @@ TEST_F(PrecacheFetcherTest, FilterInvalidManifestUrls) {
// manifest.com will have been failed to complete, in this case.
EXPECT_THAT(histogram.GetAllSamples("Precache.Fetch.PercentCompleted"),
- ElementsAre(base::Bucket(0, 1)));
+ ElementsAre(base::Bucket(101, 1)));
histogram.ExpectTotalCount("Precache.Fetch.TimeToComplete", 1);
}
@@ -1131,12 +1200,13 @@ TEST_F(PrecacheFetcherTest, FilterInvalidResourceUrls) {
base::HistogramTester histogram;
{
- PrecacheFetcher precache_fetcher(request_context_.get(), GURL(),
- std::string(), std::move(unfinished_work),
- kExperimentID, &precache_delegate_);
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
precache_fetcher.Start();
- loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
// The config and manifest are fetched, but not the invalid resource URL.
@@ -1146,8 +1216,581 @@ TEST_F(PrecacheFetcherTest, FilterInvalidResourceUrls) {
// bad-manifest.com will have been completed.
EXPECT_THAT(histogram.GetAllSamples("Precache.Fetch.PercentCompleted"),
- ElementsAre(base::Bucket(100, 1)));
+ ElementsAre(base::Bucket(101, 1)));
+ histogram.ExpectTotalCount("Precache.Fetch.TimeToComplete", 1);
+}
+
+TEST(PrecacheFetcherStandaloneTest, GetResourceURLBase64Hash) {
+ // Expected base64 hash for some selected URLs.
+ EXPECT_EQ("dVSI/sC1cGk=", PrecacheFetcher::GetResourceURLBase64HashForTesting(
+ {GURL("http://used-resource-1/a.js")}));
+ EXPECT_EQ("B/Jc6JvusZQ=", PrecacheFetcher::GetResourceURLBase64HashForTesting(
+ {GURL("http://used-resource-1/b.js")}));
+ EXPECT_EQ("CmvACGJ4k08=", PrecacheFetcher::GetResourceURLBase64HashForTesting(
+ {GURL("http://used-resource-1/c.js")}));
+
+ EXPECT_EQ("dVSI/sC1cGkH8lzom+6xlA==",
+ PrecacheFetcher::GetResourceURLBase64HashForTesting(
+ {GURL("http://used-resource-1/a.js"),
+ GURL("http://used-resource-1/b.js")}));
+}
+
+TEST_F(PrecacheFetcherTest, SendUsedUnusedResourceHash) {
+ SetDefaultFlags();
+
+ std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
+ new PrecacheUnfinishedWork());
+ unfinished_work->set_start_time(base::Time::UnixEpoch().ToInternalValue());
+ unfinished_work->add_top_host()->set_hostname("top-host-1.com");
+ unfinished_work->add_top_host()->set_hostname("top-host-2.com");
+ unfinished_work->add_top_host()->set_hostname("top-host-3.com");
+
+ UpdatePrecacheReferrerHost("top-host-1.com", 1001);
+ UpdatePrecacheReferrerHost("top-host-2.com", 1002);
+ UpdatePrecacheReferrerHost("top-host-3.com", 1003);
+
+ // Mark some resources as precached.
+ RecordURLPrefetch(GURL("http://used-resource-1/a.js"), "top-host-1.com");
+ RecordURLPrefetch(GURL("http://used-resource-1/b.js"), "top-host-1.com");
+ RecordURLPrefetch(GURL("http://unused-resource-1/c.js"), "top-host-1.com");
+ RecordURLPrefetch(GURL("http://unused-resource-2/a.js"), "top-host-2.com");
+ RecordURLPrefetch(GURL("http://unused-resource-2/b.js"), "top-host-2.com");
+ base::RunLoop().RunUntilIdle();
+
+ // Mark some resources as used during user browsing.
+ RecordURLNonPrefetch(GURL("http://used-resource-1/a.js"));
+ RecordURLNonPrefetch(GURL("http://used-resource-1/b.js"));
+ base::RunLoop().RunUntilIdle();
+
+ factory_.SetFakeResponse(GURL(kConfigURL), std::string(), net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ factory_.SetFakeResponse(
+ GURL(std::string(kManifestURLPrefix) +
+ "top-host-1.com?manifest=1001&used_resources=" +
+ net::EscapeQueryParamValue(
+ PrecacheFetcher::GetResourceURLBase64HashForTesting(
+ {GURL("http://used-resource-1/a.js"),
+ GURL("http://used-resource-1/b.js")}),
+ true) +
+ "&unused_resources=" +
+ net::EscapeQueryParamValue(
+ PrecacheFetcher::GetResourceURLBase64HashForTesting(
+ {GURL("http://unused-resource-1/c.js")}),
+ true)),
+ std::string(), net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ factory_.SetFakeResponse(
+ GURL(std::string(kManifestURLPrefix) +
+ "top-host-2.com?manifest=1002&used_resources=&unused_resources=" +
+ net::EscapeQueryParamValue(
+ PrecacheFetcher::GetResourceURLBase64HashForTesting(
+ {GURL("http://unused-resource-2/a.js"),
+ GURL("http://unused-resource-2/b.js")}),
+ true)),
+ std::string(), net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ factory_.SetFakeResponse(
+ GURL(std::string(kManifestURLPrefix) +
+ "top-host-3.com?manifest=1003&used_resources=&unused_resources="),
+ std::string(), net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+
+ {
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
+ precache_fetcher.Start();
+
+ base::RunLoop().RunUntilIdle();
+ }
+}
+
+TEST_F(PrecacheFetcherTest, GloballyRankResources) {
+ SetDefaultFlags();
+
+ const size_t kNumTopHosts = 5;
+ const size_t kNumResources = 5;
+
+ std::vector<GURL> expected_requested_urls;
+
+ PrecacheConfigurationSettings config;
+ config.set_top_sites_count(kNumTopHosts);
+ config.set_global_ranking(true);
+ factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ expected_requested_urls.emplace_back(kConfigURL);
+
+ std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
+ new PrecacheUnfinishedWork());
+ unfinished_work->set_start_time(base::Time::UnixEpoch().ToInternalValue());
+
+ for (size_t i = 0; i < kNumTopHosts; ++i) {
+ const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
+ expected_requested_urls.emplace_back(kManifestURLPrefix + top_host_url);
+ }
+
+ // Visit counts and weights are chosen in such a way that resource requests
+ // between different hosts will be interleaved.
+ std::vector<std::pair<std::string, float>> resources;
+ for (size_t i = 0; i < kNumTopHosts; ++i) {
+ const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
+ TopHost* top_host = unfinished_work->add_top_host();
+ top_host->set_hostname(top_host_url);
+ top_host->set_visits(kNumTopHosts - i);
+
+ PrecacheManifest manifest;
+ for (size_t j = 0; j < kNumResources; ++j) {
+ const float weight = 1 - static_cast<float>(j) / kNumResources;
+ const std::string resource_url =
+ base::StringPrintf("http://top-host-%zu.com/resource-%zu-weight-%.1f",
+ i, j, top_host->visits() * weight);
+ PrecacheResource* resource = manifest.add_resource();
+ resource->set_url(resource_url);
+ resource->set_weight_ratio(weight);
+ factory_.SetFakeResponse(GURL(resource_url), "good", net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ resources.emplace_back(resource_url,
+ top_host->visits() * resource->weight_ratio());
+ }
+ factory_.SetFakeResponse(GURL(kManifestURLPrefix + top_host_url),
+ manifest.SerializeAsString(), net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ }
+ // Sort by descending weight.
+ std::stable_sort(resources.begin(), resources.end(),
+ [](const std::pair<std::string, float>& a,
+ const std::pair<std::string, float>& b) {
+ return a.second > b.second;
+ });
+ for (const auto& resource : resources)
+ expected_requested_urls.emplace_back(resource.first);
+
+ {
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
+ precache_fetcher.Start();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_TRUE(precache_delegate_.was_on_done_called());
+}
+
+TEST_F(PrecacheFetcherTest, GloballyRankResourcesAfterPauseResume) {
+ SetDefaultFlags();
+
+ const size_t kNumTopHosts = 5;
+ const size_t kNumResources = 5;
+
+ std::vector<GURL> expected_requested_urls;
+
+ PrecacheConfigurationSettings config;
+ config.set_top_sites_count(kNumTopHosts);
+ config.set_global_ranking(true);
+ factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+
+ std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
+ new PrecacheUnfinishedWork());
+ unfinished_work->set_start_time(base::Time::UnixEpoch().ToInternalValue());
+
+ // Visit counts and weights are chosen in such a way that resource requests
+ // between different hosts will be interleaved.
+ std::vector<std::pair<std::string, float>> resources;
+ for (size_t i = 0; i < kNumTopHosts; ++i) {
+ const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
+ TopHost* top_host = unfinished_work->add_top_host();
+ top_host->set_hostname(top_host_url);
+ top_host->set_visits(kNumTopHosts - i);
+
+ PrecacheManifest manifest;
+ for (size_t j = 0; j < kNumResources; ++j) {
+ const float weight = 1 - static_cast<float>(j) / kNumResources;
+ const std::string resource_url =
+ base::StringPrintf("http://top-host-%zu.com/resource-%zu-weight-%.1f",
+ i, j, top_host->visits() * weight);
+ PrecacheResource* resource = manifest.add_resource();
+ resource->set_url(resource_url);
+ resource->set_weight_ratio(weight);
+ factory_.SetFakeResponse(GURL(resource_url), "good", net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ resources.emplace_back(resource_url,
+ top_host->visits() * resource->weight_ratio());
+ }
+ factory_.SetFakeResponse(GURL(kManifestURLPrefix + top_host_url),
+ manifest.SerializeAsString(), net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ }
+ // Sort by descending weight.
+ std::stable_sort(resources.begin(), resources.end(),
+ [](const std::pair<std::string, float>& a,
+ const std::pair<std::string, float>& b) {
+ return a.second > b.second;
+ });
+ for (const auto& resource : resources)
+ expected_requested_urls.emplace_back(resource.first);
+
+ std::unique_ptr<PrecacheUnfinishedWork> cancelled_work;
+ {
+ uint32_t remaining_tries = 100;
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
+ precache_fetcher.Start();
+
+ // Run the loop until all tophost manifest fetches are complete, but some
+ // resource fetches are pending.
+ while (--remaining_tries != 0 &&
+ (!precache_fetcher.top_hosts_to_fetch_.empty() ||
+ !precache_fetcher.top_hosts_fetching_.empty() ||
+ !precache_fetcher.unfinished_work_->has_config_settings() ||
+ precache_fetcher.resources_to_fetch_.empty())) {
+ LOG(INFO) << "remaining_tries: " << remaining_tries;
+ base::RunLoop run_loop;
+ loop_.task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
+ // Cancel precaching.
+ cancelled_work = precache_fetcher.CancelPrecaching();
+ EXPECT_TRUE(precache_fetcher.top_hosts_to_fetch_.empty());
+ EXPECT_TRUE(precache_fetcher.resources_to_fetch_.empty());
+ }
+ EXPECT_NE(cancelled_work, nullptr);
+ EXPECT_TRUE(cancelled_work->top_host().empty());
+ EXPECT_EQ(kNumTopHosts * kNumResources,
+ static_cast<size_t>(cancelled_work->resource().size()));
+ EXPECT_FALSE(precache_delegate_.was_on_done_called());
+
+ url_callback_.clear_requested_urls();
+
+ // Continuing with the precache should fetch all resources, as the previous
+ // run was cancelled before any finished. They should be fetched in global
+ // ranking order.
+ {
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(cancelled_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
+ LOG(INFO) << "Resuming prefetch.";
+ precache_fetcher.Start();
+ base::RunLoop().RunUntilIdle();
+ }
+ EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_TRUE(precache_delegate_.was_on_done_called());
+}
+
+TEST_F(PrecacheFetcherTest, MaxTotalResources) {
+ SetDefaultFlags();
+
+ const size_t kNumResources = 5;
+
+ std::vector<GURL> expected_requested_urls;
+
+ PrecacheConfigurationSettings config;
+ config.set_total_resources_count(2);
+ config.set_global_ranking(true);
+ factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ expected_requested_urls.emplace_back(kConfigURL);
+
+ std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
+ new PrecacheUnfinishedWork());
+ unfinished_work->set_start_time(base::Time::UnixEpoch().ToInternalValue());
+
+ TopHost* top_host = unfinished_work->add_top_host();
+ top_host->set_hostname("top-host.com");
+ top_host->set_visits(1);
+
+ expected_requested_urls.emplace_back(kManifestURLPrefix +
+ top_host->hostname());
+
+ PrecacheManifest manifest;
+ for (size_t i = 0; i < kNumResources; ++i) {
+ const float weight = 1 - static_cast<float>(i) / kNumResources;
+ const std::string resource_url =
+ base::StringPrintf("http://top-host.com/resource-%zu-weight-%.1f", i,
+ top_host->visits() * weight);
+ PrecacheResource* resource = manifest.add_resource();
+ resource->set_url(resource_url);
+ resource->set_weight_ratio(weight);
+ factory_.SetFakeResponse(GURL(resource_url), "good", net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ if (i < config.total_resources_count())
+ expected_requested_urls.emplace_back(resource_url);
+ }
+ factory_.SetFakeResponse(GURL(kManifestURLPrefix + top_host->hostname()),
+ manifest.SerializeAsString(), net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+
+ {
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
+ precache_fetcher.Start();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_TRUE(precache_delegate_.was_on_done_called());
+}
+
+TEST_F(PrecacheFetcherTest, MinWeight) {
+ SetDefaultFlags();
+
+ const size_t kNumResources = 5;
+
+ std::vector<GURL> expected_requested_urls;
+
+ PrecacheConfigurationSettings config;
+ config.set_min_weight(3);
+ config.set_global_ranking(true);
+ factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ expected_requested_urls.emplace_back(kConfigURL);
+
+ std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
+ new PrecacheUnfinishedWork());
+ unfinished_work->set_start_time(base::Time::UnixEpoch().ToInternalValue());
+
+ TopHost* top_host = unfinished_work->add_top_host();
+ top_host->set_hostname("top-host.com");
+ top_host->set_visits(5);
+
+ expected_requested_urls.emplace_back(kManifestURLPrefix +
+ top_host->hostname());
+
+ PrecacheManifest manifest;
+ for (size_t i = 0; i < kNumResources; ++i) {
+ const float weight = 1 - static_cast<float>(i) / kNumResources;
+ const std::string resource_url =
+ base::StringPrintf("http://top-host.com/resource-%zu-weight-%.1f", i,
+ top_host->visits() * weight);
+ PrecacheResource* resource = manifest.add_resource();
+ resource->set_url(resource_url);
+ resource->set_weight_ratio(weight);
+ factory_.SetFakeResponse(GURL(resource_url), "good", net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ // If top_host->visits() * weight > config.min_weight():
+ if (i < 3)
+ expected_requested_urls.emplace_back(resource_url);
+ }
+ factory_.SetFakeResponse(GURL(kManifestURLPrefix + top_host->hostname()),
+ manifest.SerializeAsString(), net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+
+ {
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
+ precache_fetcher.Start();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_TRUE(precache_delegate_.was_on_done_called());
+}
+
+// Tests cancel precaching when all tophost manifests are fetched, but some
+// resource fetches are pending.
+TEST_F(PrecacheFetcherTest, CancelPrecachingAfterAllManifestFetch) {
+ SetDefaultFlags();
+
+ const size_t kNumTopHosts = 5;
+ const size_t kNumResources = 5;
+
+ PrecacheConfigurationSettings config;
+ std::vector<GURL> expected_requested_urls;
+ std::unique_ptr<PrecacheUnfinishedWork> cancelled_work;
+
+ config.set_top_sites_count(kNumTopHosts);
+ factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ expected_requested_urls.emplace_back(kConfigURL);
+
+ std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
+ new PrecacheUnfinishedWork());
+ unfinished_work->set_start_time(base::Time::UnixEpoch().ToInternalValue());
+
+ for (size_t i = 0; i < kNumTopHosts; ++i) {
+ const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
+ expected_requested_urls.emplace_back(kManifestURLPrefix + top_host_url);
+ }
+
+ int num_resources = 0;
+ for (size_t i = 0; i < kNumTopHosts; ++i) {
+ const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
+ TopHost* top_host = unfinished_work->add_top_host();
+ top_host->set_hostname(top_host_url);
+ top_host->set_visits(kNumTopHosts - i);
+
+ PrecacheManifest manifest;
+ for (size_t j = 0; j < kNumResources; ++j) {
+ const std::string resource_url =
+ base::StringPrintf("http://top-host-%zu.com/resource-%zu", i, j);
+ PrecacheResource* resource = manifest.add_resource();
+ resource->set_url(resource_url);
+ resource->set_weight_ratio(1);
+ factory_.SetFakeResponse(GURL(resource_url), "good", net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ if (++num_resources <= kMaxParallelFetches)
+ expected_requested_urls.emplace_back(resource_url);
+ }
+ factory_.SetFakeResponse(GURL(kManifestURLPrefix + top_host_url),
+ manifest.SerializeAsString(), net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ }
+
+ {
+ uint32_t remaining_tries = 100;
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
+ precache_fetcher.Start();
+
+ // Run the loop until all tophost manifest fetches are complete, but some
+ // resource fetches are pending.
+ while (--remaining_tries != 0 &&
+ (!precache_fetcher.top_hosts_to_fetch_.empty() ||
+ !precache_fetcher.top_hosts_fetching_.empty() ||
+ !precache_fetcher.unfinished_work_->has_config_settings() ||
+ precache_fetcher.resources_to_fetch_.empty())) {
+ LOG(INFO) << "remaining_tries: " << remaining_tries;
+ base::RunLoop run_loop;
+ loop_.task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
+ // Cancel precaching.
+ cancelled_work = precache_fetcher.CancelPrecaching();
+ EXPECT_TRUE(precache_fetcher.top_hosts_to_fetch_.empty());
+ EXPECT_TRUE(precache_fetcher.resources_to_fetch_.empty());
+ }
+ ASSERT_NE(nullptr, cancelled_work);
+ EXPECT_TRUE(cancelled_work->top_host().empty());
+ EXPECT_EQ(kNumTopHosts * kNumResources,
+ static_cast<size_t>(cancelled_work->resource().size()));
+
+ EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+
+ EXPECT_FALSE(precache_delegate_.was_on_done_called());
+
+ // Continuing with the precache should fetch all resources, as the previous
+ // run was cancelled before any finished.
+ expected_requested_urls.clear();
+ url_callback_.clear_requested_urls();
+ for (size_t i = 0; i < kNumTopHosts; ++i) {
+ for (size_t j = 0; j < kNumResources; ++j) {
+ expected_requested_urls.emplace_back(
+ base::StringPrintf("http://top-host-%zu.com/resource-%zu", i, j));
+ }
+ }
+ {
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(cancelled_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
+ LOG(INFO) << "Resuming prefetch.";
+ precache_fetcher.Start();
+ base::RunLoop().RunUntilIdle();
+ }
+ EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+ EXPECT_TRUE(precache_delegate_.was_on_done_called());
+}
+
+TEST_F(PrecacheFetcherTest, DailyQuota) {
+ SetDefaultFlags();
+
+ const size_t kNumTopHosts = 3;
+
+ std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
+ new PrecacheUnfinishedWork());
+ unfinished_work->set_start_time(base::Time::UnixEpoch().ToInternalValue());
+
+ PrecacheConfigurationSettings config;
+ config.set_top_sites_count(kNumTopHosts);
+ config.set_daily_quota_total(10000);
+ factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ std::vector<GURL> expected_requested_urls;
+ expected_requested_urls.emplace_back(kConfigURL);
+
+ for (size_t i = 0; i < kNumTopHosts; ++i) {
+ const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
+ expected_requested_urls.emplace_back(std::string(kManifestURLPrefix) +
+ top_host_url);
+ }
+
+ for (size_t i = 0; i < kNumTopHosts; ++i) {
+ const std::string top_host_url = base::StringPrintf("top-host-%zu.com", i);
+ const std::string resource_url =
+ base::StringPrintf("http://top-host-%zu.com/resource.html", i);
+ PrecacheManifest manifest;
+ manifest.add_resource()->set_url(resource_url);
+
+ unfinished_work->add_top_host()->set_hostname(top_host_url);
+ factory_.SetFakeResponse(
+ GURL(std::string(kManifestURLPrefix) + top_host_url),
+ manifest.SerializeAsString(), net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ // Set a 5000 byte resource.
+ factory_.SetFakeResponse(GURL(resource_url), std::string(5000, 'a'),
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+
+ expected_requested_urls.emplace_back(resource_url);
+ }
+
+ base::HistogramTester histogram;
+
+ {
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
+ precache_fetcher.Start();
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0U, precache_fetcher.quota_.remaining());
+ unfinished_work = precache_fetcher.CancelPrecaching();
+ }
+
+ EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+
+ EXPECT_TRUE(precache_delegate_.was_on_done_called());
+
+ EXPECT_EQ(0, unfinished_work->top_host_size());
+ EXPECT_EQ(1, unfinished_work->resource_size());
+
+ histogram.ExpectTotalCount("Precache.Fetch.PercentCompleted", 1);
+ histogram.ExpectTotalCount("Precache.Fetch.ResponseBytes.Total", 1);
histogram.ExpectTotalCount("Precache.Fetch.TimeToComplete", 1);
+
+ // Continuing with the precache when quota limit is reached, will not fetch
+ // any resources.
+ expected_requested_urls.clear();
+ url_callback_.clear_requested_urls();
+ {
+ PrecacheFetcher precache_fetcher(
+ request_context_.get(), GURL(), std::string(),
+ std::move(unfinished_work), kExperimentID,
+ precache_database_.GetWeakPtr(), task_runner(), &precache_delegate_);
+ precache_fetcher.Start();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0U, precache_fetcher.quota_.remaining());
+ }
+ EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
+
+ EXPECT_TRUE(precache_delegate_.was_on_done_called());
+
+ histogram.ExpectTotalCount("Precache.Fetch.PercentCompleted", 2);
+ histogram.ExpectTotalCount("Precache.Fetch.ResponseBytes.Total", 2);
+ histogram.ExpectTotalCount("Precache.Fetch.TimeToComplete", 2);
}
} // namespace precache
diff --git a/chromium/components/precache/core/precache_referrer_host_table.cc b/chromium/components/precache/core/precache_referrer_host_table.cc
new file mode 100644
index 00000000000..e6acbbad8aa
--- /dev/null
+++ b/chromium/components/precache/core/precache_referrer_host_table.cc
@@ -0,0 +1,123 @@
+// 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 "components/precache/core/precache_referrer_host_table.h"
+
+#include "sql/connection.h"
+#include "sql/statement.h"
+
+using sql::Statement;
+
+namespace precache {
+
+const int64_t PrecacheReferrerHostEntry::kInvalidId = -1;
+
+bool PrecacheReferrerHostEntry::operator==(
+ const PrecacheReferrerHostEntry& entry) const {
+ return id == entry.id && referrer_host == entry.referrer_host &&
+ manifest_id == entry.manifest_id && time == entry.time;
+}
+
+PrecacheReferrerHostTable::PrecacheReferrerHostTable() : db_(NULL) {}
+
+PrecacheReferrerHostTable::~PrecacheReferrerHostTable() {}
+
+bool PrecacheReferrerHostTable::Init(sql::Connection* db) {
+ DCHECK(!db_); // Init must only be called once.
+ DCHECK(db); // The database connection must be non-NULL.
+ db_ = db;
+ return CreateTableIfNonExistent();
+}
+
+PrecacheReferrerHostEntry PrecacheReferrerHostTable::GetReferrerHost(
+ const std::string& referrer_host) {
+ Statement statement(db_->GetCachedStatement(
+ SQL_FROM_HERE,
+ "SELECT id, referrer_host, manifest_id, time "
+ "FROM precache_referrer_hosts WHERE referrer_host=?"));
+
+ statement.BindString(0, referrer_host);
+ if (statement.Step()) {
+ return PrecacheReferrerHostEntry(
+ statement.ColumnInt64(0), statement.ColumnString(1),
+ statement.ColumnInt64(2),
+ base::Time::FromInternalValue(statement.ColumnInt64(3)));
+ }
+ return PrecacheReferrerHostEntry(PrecacheReferrerHostEntry::kInvalidId,
+ std::string(), 0, base::Time());
+}
+
+int64_t PrecacheReferrerHostTable::UpdateReferrerHost(
+ const std::string& referrer_host,
+ int64_t manifest_id,
+ const base::Time& time) {
+ int64_t referrer_host_id = GetReferrerHost(referrer_host).id;
+ if (referrer_host_id == PrecacheReferrerHostEntry::kInvalidId) {
+ Statement statement(
+ db_->GetCachedStatement(SQL_FROM_HERE,
+ "INSERT INTO precache_referrer_hosts "
+ "(id, referrer_host, manifest_id, time) "
+ "VALUES(NULL, ?, ?, ?)"));
+
+ statement.BindString(0, referrer_host);
+ statement.BindInt64(1, manifest_id);
+ statement.BindInt64(2, time.ToInternalValue());
+ if (statement.Run())
+ return db_->GetLastInsertRowId();
+ } else {
+ Statement statement(
+ db_->GetCachedStatement(SQL_FROM_HERE,
+ "UPDATE precache_referrer_hosts "
+ "SET manifest_id=?, time=? "
+ "WHERE id=?"));
+
+ statement.BindInt64(0, manifest_id);
+ statement.BindInt64(1, time.ToInternalValue());
+ ;
+ statement.BindInt64(2, referrer_host_id);
+ if (statement.Run())
+ return referrer_host_id;
+ }
+ return -1;
+}
+
+void PrecacheReferrerHostTable::DeleteAllEntriesBefore(
+ const base::Time& delete_end) {
+ Statement statement(db_->GetCachedStatement(
+ SQL_FROM_HERE, "DELETE FROM precache_referrer_hosts WHERE time < ?"));
+ statement.BindInt64(0, delete_end.ToInternalValue());
+ statement.Run();
+}
+
+void PrecacheReferrerHostTable::DeleteAll() {
+ Statement statement(db_->GetCachedStatement(
+ SQL_FROM_HERE, "DELETE FROM precache_referrer_hosts"));
+
+ statement.Run();
+}
+
+bool PrecacheReferrerHostTable::CreateTableIfNonExistent() {
+ return db_->Execute(
+ "CREATE TABLE IF NOT EXISTS precache_referrer_hosts "
+ "(id INTEGER PRIMARY KEY, referrer_host TEXT KEY, manifest_id INTEGER, "
+ "time INTEGER)");
+}
+
+std::map<std::string, PrecacheReferrerHostEntry>
+PrecacheReferrerHostTable::GetAllDataForTesting() {
+ std::map<std::string, PrecacheReferrerHostEntry> all_data;
+ Statement statement(
+ db_->GetCachedStatement(SQL_FROM_HERE,
+ "SELECT id, referrer_host, manifest_id, time "
+ "FROM precache_referrer_hosts"));
+ while (statement.Step()) {
+ all_data[statement.ColumnString(1)] = PrecacheReferrerHostEntry(
+ statement.ColumnInt64(0), statement.ColumnString(1),
+ statement.ColumnInt64(2),
+ base::Time::FromInternalValue(statement.ColumnInt64(3)));
+ }
+ return all_data;
+}
+
+} // namespace precache
diff --git a/chromium/components/precache/core/precache_referrer_host_table.h b/chromium/components/precache/core/precache_referrer_host_table.h
new file mode 100644
index 00000000000..e95624551ab
--- /dev/null
+++ b/chromium/components/precache/core/precache_referrer_host_table.h
@@ -0,0 +1,82 @@
+// 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 COMPONENTS_PRECACHE_CORE_PRECACHE_REFERRER_HOST_TABLE_H_
+#define COMPONENTS_PRECACHE_CORE_PRECACHE_REFERRER_HOST_TABLE_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <string>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+
+namespace sql {
+class Connection;
+}
+
+namespace precache {
+
+struct PrecacheReferrerHostEntry {
+ static const int64_t kInvalidId;
+
+ PrecacheReferrerHostEntry() : id(kInvalidId) {}
+ PrecacheReferrerHostEntry(int64_t id,
+ const std::string& referrer_host,
+ int64_t manifest_id,
+ const base::Time& time)
+ : id(id),
+ referrer_host(referrer_host),
+ manifest_id(manifest_id),
+ time(time) {}
+
+ // Comparison for testing.
+ bool operator==(const PrecacheReferrerHostEntry& entry) const;
+
+ int64_t id;
+ std::string referrer_host;
+ int64_t manifest_id;
+ base::Time time;
+};
+
+class PrecacheReferrerHostTable {
+ public:
+ PrecacheReferrerHostTable();
+ ~PrecacheReferrerHostTable();
+
+ // Initialize the precache referrer host table for use with the specified
+ // database connection. The caller keeps ownership of |db|, and |db| must not
+ // be NULL. Init must be called before any other methods.
+ bool Init(sql::Connection* db);
+
+ // Returns the referrer host information about |referrer_host|.
+ PrecacheReferrerHostEntry GetReferrerHost(const std::string& referrer_host);
+
+ // Updates the referrer host information about |referrer_host|.
+ int64_t UpdateReferrerHost(const std::string& referrer_host,
+ int64_t manifest_id,
+ const base::Time& time);
+
+ // Deletes entries that were created before the time of |delete_end|.
+ void DeleteAllEntriesBefore(const base::Time& delete_end);
+
+ // Delete all entries.
+ void DeleteAll();
+
+ // Used by tests to get the contents of the table.
+ std::map<std::string, PrecacheReferrerHostEntry> GetAllDataForTesting();
+
+ private:
+ bool CreateTableIfNonExistent();
+
+ // Not owned by |this|.
+ sql::Connection* db_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrecacheReferrerHostTable);
+};
+
+} // namespace precache
+
+#endif // COMPONENTS_PRECACHE_CORE_PRECACHE_REFERRER_HOST_TABLE_H_
diff --git a/chromium/components/precache/core/precache_referrer_host_table_unittest.cc b/chromium/components/precache/core/precache_referrer_host_table_unittest.cc
new file mode 100644
index 00000000000..624f1e26b9d
--- /dev/null
+++ b/chromium/components/precache/core/precache_referrer_host_table_unittest.cc
@@ -0,0 +1,154 @@
+// 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 "components/precache/core/precache_referrer_host_table.h"
+
+#include <map>
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/time/time.h"
+#include "sql/connection.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace precache {
+
+namespace {
+
+const char* kReffererHostFoo = "foo.com";
+const char* kReffererHostBar = "bar.com";
+const int64_t kManifestIdFoo = 1001;
+const int64_t kManifestIdBar = 1002;
+
+class PrecacheReferrerHostTableTest : public testing::Test {
+ public:
+ PrecacheReferrerHostTableTest() {}
+ ~PrecacheReferrerHostTableTest() override {}
+
+ protected:
+ void SetUp() override {
+ precache_referrer_host_table_.reset(new PrecacheReferrerHostTable());
+ db_.reset(new sql::Connection());
+ ASSERT_TRUE(db_->OpenInMemory());
+ precache_referrer_host_table_->Init(db_.get());
+ }
+
+ std::unique_ptr<PrecacheReferrerHostTable> precache_referrer_host_table_;
+ std::unique_ptr<sql::Connection> db_;
+};
+
+TEST_F(PrecacheReferrerHostTableTest, GetReferrerHost) {
+ const base::Time kTimeFoo = base::Time::FromInternalValue(100);
+ const base::Time kTimeBar = base::Time::FromInternalValue(200);
+ std::map<std::string, PrecacheReferrerHostEntry> expected_entries;
+
+ // Add new referrer hosts.
+ int64_t foo_id = precache_referrer_host_table_->UpdateReferrerHost(
+ kReffererHostFoo, kManifestIdFoo, kTimeFoo);
+ int64_t bar_id = precache_referrer_host_table_->UpdateReferrerHost(
+ kReffererHostBar, kManifestIdBar, kTimeBar);
+
+ EXPECT_NE(-1, foo_id);
+ EXPECT_NE(-1, bar_id);
+
+ EXPECT_EQ(PrecacheReferrerHostEntry(foo_id, kReffererHostFoo, kManifestIdFoo,
+ kTimeFoo),
+ precache_referrer_host_table_->GetReferrerHost(kReffererHostFoo));
+ EXPECT_EQ(PrecacheReferrerHostEntry(bar_id, kReffererHostBar, kManifestIdBar,
+ kTimeBar),
+ precache_referrer_host_table_->GetReferrerHost(kReffererHostBar));
+
+ expected_entries[kReffererHostFoo] = PrecacheReferrerHostEntry(
+ foo_id, kReffererHostFoo, kManifestIdFoo, kTimeFoo);
+ expected_entries[kReffererHostBar] = PrecacheReferrerHostEntry(
+ bar_id, kReffererHostBar, kManifestIdBar, kTimeBar);
+ EXPECT_THAT(expected_entries,
+ ::testing::ContainerEq(
+ precache_referrer_host_table_->GetAllDataForTesting()));
+}
+
+TEST_F(PrecacheReferrerHostTableTest, UpdateReferrerHost) {
+ const base::Time kTimeFoo = base::Time::FromInternalValue(100);
+ const base::Time kTimeBar = base::Time::FromInternalValue(200);
+ std::map<std::string, PrecacheReferrerHostEntry> expected_entries;
+
+ // Add new referrer hosts.
+ int64_t foo_id = precache_referrer_host_table_->UpdateReferrerHost(
+ kReffererHostFoo, kManifestIdFoo, kTimeFoo);
+ int64_t bar_id = precache_referrer_host_table_->UpdateReferrerHost(
+ kReffererHostBar, kManifestIdBar, kTimeBar);
+
+ EXPECT_NE(-1, foo_id);
+ EXPECT_NE(-1, bar_id);
+
+ expected_entries[kReffererHostFoo] = PrecacheReferrerHostEntry(
+ foo_id, kReffererHostFoo, kManifestIdFoo, kTimeFoo);
+ expected_entries[kReffererHostBar] = PrecacheReferrerHostEntry(
+ bar_id, kReffererHostBar, kManifestIdBar, kTimeBar);
+ EXPECT_THAT(expected_entries,
+ ::testing::ContainerEq(
+ precache_referrer_host_table_->GetAllDataForTesting()));
+
+ // Updating referrer hosts should return the same ID.
+ EXPECT_EQ(foo_id, precache_referrer_host_table_->UpdateReferrerHost(
+ kReffererHostFoo, kManifestIdFoo, kTimeFoo));
+ EXPECT_EQ(bar_id, precache_referrer_host_table_->UpdateReferrerHost(
+ kReffererHostBar, kManifestIdBar, kTimeBar));
+ EXPECT_THAT(expected_entries,
+ ::testing::ContainerEq(
+ precache_referrer_host_table_->GetAllDataForTesting()));
+}
+
+TEST_F(PrecacheReferrerHostTableTest, DeleteAll) {
+ const base::Time kTimeFoo = base::Time::FromInternalValue(100);
+ const base::Time kTimeBar = base::Time::FromInternalValue(200);
+ std::map<std::string, PrecacheReferrerHostEntry> expected_entries;
+
+ // Add new referrer hosts.
+ int64_t foo_id = precache_referrer_host_table_->UpdateReferrerHost(
+ kReffererHostFoo, kManifestIdFoo, kTimeFoo);
+ int64_t bar_id = precache_referrer_host_table_->UpdateReferrerHost(
+ kReffererHostBar, kManifestIdBar, kTimeBar);
+
+ EXPECT_NE(-1, foo_id);
+ EXPECT_NE(-1, bar_id);
+
+ expected_entries[kReffererHostFoo] = PrecacheReferrerHostEntry(
+ foo_id, kReffererHostFoo, kManifestIdFoo, kTimeFoo);
+ expected_entries[kReffererHostBar] = PrecacheReferrerHostEntry(
+ bar_id, kReffererHostBar, kManifestIdBar, kTimeBar);
+ EXPECT_THAT(expected_entries,
+ ::testing::ContainerEq(
+ precache_referrer_host_table_->GetAllDataForTesting()));
+
+ precache_referrer_host_table_->DeleteAll();
+
+ EXPECT_EQ(0UL, precache_referrer_host_table_->GetAllDataForTesting().size());
+}
+
+TEST_F(PrecacheReferrerHostTableTest, DeleteAllEntriesBefore) {
+ const base::Time kOldTime = base::Time::FromInternalValue(10);
+ const base::Time kBeforeTime = base::Time::FromInternalValue(20);
+ const base::Time kEndTime = base::Time::FromInternalValue(30);
+ const base::Time kAfterTime = base::Time::FromInternalValue(40);
+
+ precache_referrer_host_table_->UpdateReferrerHost("old.com", 1, kOldTime);
+ precache_referrer_host_table_->UpdateReferrerHost("before.com", 2,
+ kBeforeTime);
+ precache_referrer_host_table_->UpdateReferrerHost("end.com", 3, kEndTime);
+ precache_referrer_host_table_->UpdateReferrerHost("after.com", 4, kAfterTime);
+
+ precache_referrer_host_table_->DeleteAllEntriesBefore(kEndTime);
+
+ const auto actual_entries =
+ precache_referrer_host_table_->GetAllDataForTesting();
+ EXPECT_EQ(2UL, actual_entries.size());
+ EXPECT_NE(actual_entries.end(), actual_entries.find("end.com"));
+ EXPECT_NE(actual_entries.end(), actual_entries.find("after.com"));
+}
+
+} // namespace
+
+} // namespace precache
diff --git a/chromium/components/precache/core/precache_session_table.cc b/chromium/components/precache/core/precache_session_table.cc
index 8537b199025..f7ac55c7a0e 100644
--- a/chromium/components/precache/core/precache_session_table.cc
+++ b/chromium/components/precache/core/precache_session_table.cc
@@ -4,10 +4,12 @@
#include "components/precache/core/precache_session_table.h"
+#include <stdint.h>
#include <string>
#include "base/logging.h"
#include "base/time/time.h"
+#include "components/precache/core/proto/timestamp.pb.h"
#include "components/precache/core/proto/unfinished_work.pb.h"
#include "sql/connection.h"
#include "sql/statement.h"
@@ -27,40 +29,89 @@ bool PrecacheSessionTable::Init(sql::Connection* db) {
return CreateTableIfNonExistent();
}
-// Store unfinished work.
-void PrecacheSessionTable::SaveUnfinishedWork(
- std::unique_ptr<PrecacheUnfinishedWork> unfinished_work) {
+void PrecacheSessionTable::SetSessionDataType(SessionDataType id,
+ const std::string& data) {
Statement statement(db_->GetCachedStatement(
SQL_FROM_HERE,
"INSERT OR REPLACE INTO precache_session (type, value) VALUES(?,?)"));
- statement.BindInt(0, static_cast<int>(UNFINISHED_WORK));
- statement.BindString(1, unfinished_work->SerializeAsString());
+ statement.BindInt(0, static_cast<int>(id));
+ statement.BindString(1, data);
+ statement.Run();
+}
+
+std::string PrecacheSessionTable::GetSessionDataType(SessionDataType id) {
+ Statement statement(db_->GetCachedStatement(
+ SQL_FROM_HERE, "SELECT value from precache_session where type=?"));
+ statement.BindInt(0, static_cast<int>(id));
+ return statement.Step() ? statement.ColumnString(0) : std::string();
+}
+
+void PrecacheSessionTable::SetLastPrecacheTimestamp(const base::Time& time) {
+ DCHECK(!time.is_null());
+ Timestamp timestamp;
+ timestamp.set_seconds((time - base::Time::UnixEpoch()).InSeconds());
+ SetSessionDataType(SessionDataType::LAST_PRECACHE_TIMESTAMP,
+ timestamp.SerializeAsString());
+}
+
+base::Time PrecacheSessionTable::GetLastPrecacheTimestamp() {
+ Timestamp timestamp;
+ const std::string data =
+ GetSessionDataType(SessionDataType::LAST_PRECACHE_TIMESTAMP);
+ if (!data.empty())
+ timestamp.ParseFromString(data);
+ return timestamp.has_seconds()
+ ? base::Time::UnixEpoch() +
+ base::TimeDelta::FromSeconds(timestamp.seconds())
+ : base::Time();
+}
+
+void PrecacheSessionTable::DeleteLastPrecacheTimestamp() {
+ Statement statement(db_->GetCachedStatement(
+ SQL_FROM_HERE, "DELETE FROM precache_session where type=?"));
+ statement.BindInt(0,
+ static_cast<int>(SessionDataType::LAST_PRECACHE_TIMESTAMP));
statement.Run();
}
+// Store unfinished work.
+void PrecacheSessionTable::SaveUnfinishedWork(
+ std::unique_ptr<PrecacheUnfinishedWork> unfinished_work) {
+ SetSessionDataType(SessionDataType::UNFINISHED_WORK,
+ unfinished_work->SerializeAsString());
+}
+
// Retrieve unfinished work.
std::unique_ptr<PrecacheUnfinishedWork>
PrecacheSessionTable::GetUnfinishedWork() {
- Statement statement(db_->GetCachedStatement(
- SQL_FROM_HERE, "SELECT value from precache_session where type=?"));
- statement.BindInt(0, static_cast<int>(UNFINISHED_WORK));
+ const std::string data = GetSessionDataType(SessionDataType::UNFINISHED_WORK);
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
new PrecacheUnfinishedWork());
- if (statement.Step())
- unfinished_work->ParseFromString(statement.ColumnString(0));
+ if (!data.empty())
+ unfinished_work->ParseFromString(data);
return unfinished_work;
}
-
-
void PrecacheSessionTable::DeleteUnfinishedWork() {
Statement statement(
db_->GetCachedStatement(
SQL_FROM_HERE, "DELETE FROM precache_session where type=?"));
- statement.BindInt(0, static_cast<int>(UNFINISHED_WORK));
+ statement.BindInt(0, static_cast<int>(SessionDataType::UNFINISHED_WORK));
statement.Run();
}
+void PrecacheSessionTable::SaveQuota(const PrecacheQuota& quota) {
+ SetSessionDataType(SessionDataType::QUOTA, quota.SerializeAsString());
+}
+
+PrecacheQuota PrecacheSessionTable::GetQuota() {
+ PrecacheQuota quota;
+ const std::string data = GetSessionDataType(SessionDataType::QUOTA);
+ if (!data.empty())
+ quota.ParseFromString(data);
+ return quota;
+}
+
bool PrecacheSessionTable::CreateTableIfNonExistent() {
return db_->Execute(
"CREATE TABLE IF NOT EXISTS precache_session (type INTEGER PRIMARY KEY, "
diff --git a/chromium/components/precache/core/precache_session_table.h b/chromium/components/precache/core/precache_session_table.h
index e4be3238107..4ddeda91ce8 100644
--- a/chromium/components/precache/core/precache_session_table.h
+++ b/chromium/components/precache/core/precache_session_table.h
@@ -5,17 +5,11 @@
#ifndef COMPONENTS_PRECACHE_CORE_PRECACHE_SESSION_TABLE_H_
#define COMPONENTS_PRECACHE_CORE_PRECACHE_SESSION_TABLE_H_
-#include <list>
-#include <map>
#include <memory>
#include "base/macros.h"
#include "base/time/time.h"
-#include "url/gurl.h"
-
-namespace base {
-class TimeTicks;
-}
+#include "components/precache/core/proto/quota.pb.h"
namespace sql {
class Connection;
@@ -26,9 +20,15 @@ namespace precache {
class PrecacheUnfinishedWork;
// Denotes the type of session information being stored.
-enum SessionDataType {
+enum class SessionDataType {
// Unfinished work to do sometime later.
UNFINISHED_WORK = 0,
+
+ // Timestamp of the last precache.
+ LAST_PRECACHE_TIMESTAMP = 1,
+
+ // Remaining quota limits.
+ QUOTA = 2,
};
class PrecacheSessionTable {
@@ -41,6 +41,22 @@ class PrecacheSessionTable {
// Init must be called before any other methods.
bool Init(sql::Connection* db);
+ // -- Time since last precache --
+
+ void SetLastPrecacheTimestamp(const base::Time& time);
+
+ // If none present, it will return base::Time(), so it can be checked via
+ // is_null().
+ base::Time GetLastPrecacheTimestamp();
+
+ void DeleteLastPrecacheTimestamp();
+
+ // Precache quota.
+ void SaveQuota(const PrecacheQuota& quota);
+ PrecacheQuota GetQuota();
+
+ // -- Unfinished work --
+
// Stores unfinished work.
void SaveUnfinishedWork(
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work);
@@ -54,6 +70,9 @@ class PrecacheSessionTable {
private:
bool CreateTableIfNonExistent();
+ void SetSessionDataType(SessionDataType id, const std::string& data);
+ std::string GetSessionDataType(SessionDataType id);
+
// Non-owned pointer.
sql::Connection* db_;
diff --git a/chromium/components/precache/core/precache_session_table_unittest.cc b/chromium/components/precache/core/precache_session_table_unittest.cc
index c0d37d50273..dee5c0995d9 100644
--- a/chromium/components/precache/core/precache_session_table_unittest.cc
+++ b/chromium/components/precache/core/precache_session_table_unittest.cc
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stdint.h>
+
#include "base/compiler_specific.h"
#include "base/time/time.h"
#include "components/precache/core/precache_session_table.h"
+#include "components/precache/core/proto/quota.pb.h"
#include "components/precache/core/proto/unfinished_work.pb.h"
#include "sql/connection.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -31,20 +34,29 @@ class PrecacheSessionTableTest : public testing::Test {
std::unique_ptr<sql::Connection> db_;
};
+TEST_F(PrecacheSessionTableTest, LastPrecacheTimestamp) {
+ const base::Time sometime = base::Time::FromDoubleT(42);
+
+ precache_session_table_->SetLastPrecacheTimestamp(sometime);
+
+ EXPECT_EQ(sometime, precache_session_table_->GetLastPrecacheTimestamp());
+
+ precache_session_table_->DeleteLastPrecacheTimestamp();
+
+ EXPECT_EQ(base::Time(), precache_session_table_->GetLastPrecacheTimestamp());
+}
+
TEST_F(PrecacheSessionTableTest, SaveAndGetUnfinishedWork) {
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
new PrecacheUnfinishedWork());
unfinished_work->add_top_host()->set_hostname("foo.com");
unfinished_work->add_top_host()->set_hostname("bar.com");
- auto s = unfinished_work->mutable_config_settings();
+ auto* s = unfinished_work->mutable_config_settings();
s->set_top_sites_count(11);
s->add_forced_site("baz.com");
s->set_top_resources_count(12);
s->set_max_bytes_per_resource(501);
s->set_max_bytes_total(1001);
- unfinished_work->add_manifest()->set_url("http://a.com/");
- unfinished_work->add_manifest()->set_url("http://b.com/");
- unfinished_work->add_manifest()->set_url("http://c.com/");
unfinished_work->add_resource()->set_url("http://x.com/");
unfinished_work->add_resource()->set_url("http://y.com/");
unfinished_work->add_resource()->set_url("http://z.com/");
@@ -58,6 +70,7 @@ TEST_F(PrecacheSessionTableTest, SaveAndGetUnfinishedWork) {
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work2 =
precache_session_table_->GetUnfinishedWork();
+ EXPECT_EQ(2, unfinished_work2->top_host_size());
EXPECT_EQ("foo.com", unfinished_work2->top_host(0).hostname());
EXPECT_EQ("bar.com", unfinished_work2->top_host(1).hostname());
EXPECT_EQ(11, unfinished_work2->config_settings().top_sites_count());
@@ -67,10 +80,6 @@ TEST_F(PrecacheSessionTableTest, SaveAndGetUnfinishedWork) {
EXPECT_EQ(501ul,
unfinished_work2->config_settings().max_bytes_per_resource());
EXPECT_EQ(1001ul, unfinished_work2->config_settings().max_bytes_total());
- EXPECT_EQ(3, unfinished_work2->manifest_size());
- EXPECT_EQ("http://a.com/", unfinished_work2->manifest(0).url());
- EXPECT_EQ("http://b.com/", unfinished_work2->manifest(1).url());
- EXPECT_EQ("http://c.com/", unfinished_work2->manifest(2).url());
EXPECT_EQ(3, unfinished_work2->resource_size());
EXPECT_EQ("http://x.com/", unfinished_work2->resource(0).url());
EXPECT_EQ("http://y.com/", unfinished_work2->resource(1).url());
@@ -86,24 +95,24 @@ TEST_F(PrecacheSessionTableTest, SaveAndGetUnfinishedWork) {
TEST_F(PrecacheSessionTableTest, SaveAgainAndGet) {
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
new PrecacheUnfinishedWork());
- unfinished_work->add_manifest()->set_url("http://a.com/");
+ unfinished_work->add_top_host()->set_hostname("a.com");
precache_session_table_->SaveUnfinishedWork(std::move(unfinished_work));
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work2(
new PrecacheUnfinishedWork());
- unfinished_work2->add_manifest()->set_url("http://b.com/");
+ unfinished_work2->add_top_host()->set_hostname("b.com");
precache_session_table_->SaveUnfinishedWork(std::move(unfinished_work2));
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work3 =
precache_session_table_->GetUnfinishedWork();
- EXPECT_EQ("http://b.com/", unfinished_work3->manifest(0).url());
+ EXPECT_EQ("b.com", unfinished_work3->top_host(0).hostname());
}
// Test that reading does not remove unfinished work from storage.
TEST_F(PrecacheSessionTableTest, SaveAndGetAgain) {
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
new PrecacheUnfinishedWork());
- unfinished_work->add_manifest()->set_url("http://a.com/");
+ unfinished_work->add_top_host()->set_hostname("a.com");
precache_session_table_->SaveUnfinishedWork(std::move(unfinished_work));
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work2 =
@@ -112,7 +121,7 @@ TEST_F(PrecacheSessionTableTest, SaveAndGetAgain) {
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work3 =
precache_session_table_->GetUnfinishedWork();
- EXPECT_EQ("http://a.com/", unfinished_work3->manifest(0).url());
+ EXPECT_EQ("a.com", unfinished_work3->top_host(0).hostname());
}
// Test that storing a large proto works.
@@ -120,29 +129,47 @@ TEST_F(PrecacheSessionTableTest, SaveManyURLs) {
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
new PrecacheUnfinishedWork());
for (int i = 0; i < 1000; ++i)
- unfinished_work->add_manifest()->set_url("http://a.com/");
+ unfinished_work->add_top_host()->set_hostname("a.com");
precache_session_table_->SaveUnfinishedWork(std::move(unfinished_work));
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work2 =
precache_session_table_->GetUnfinishedWork();
- EXPECT_EQ(1000, unfinished_work2->manifest_size());
+ EXPECT_EQ(1000, unfinished_work2->top_host_size());
for (int i = 0; i < 1000; ++i)
- EXPECT_EQ("http://a.com/", unfinished_work2->manifest(i).url());
+ EXPECT_EQ("a.com", unfinished_work2->top_host(i).hostname());
}
// Test that reading after deletion returns no unfinished work.
TEST_F(PrecacheSessionTableTest, SaveDeleteGet) {
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work(
new PrecacheUnfinishedWork());
- unfinished_work->add_manifest()->set_url("http://a.com/");
+ unfinished_work->add_top_host()->set_hostname("a.com");
precache_session_table_->SaveUnfinishedWork(std::move(unfinished_work));
precache_session_table_->DeleteUnfinishedWork();
std::unique_ptr<PrecacheUnfinishedWork> unfinished_work2 =
precache_session_table_->GetUnfinishedWork();
- EXPECT_EQ(0, unfinished_work2->manifest_size());
+ EXPECT_EQ(0, unfinished_work2->top_host_size());
+}
+
+TEST_F(PrecacheSessionTableTest, SaveAndGetQuota) {
+ // Initial quota, should have expired.
+ EXPECT_LT(base::Time::FromInternalValue(
+ precache_session_table_->GetQuota().start_time()),
+ base::Time::Now());
+
+ PrecacheQuota quota;
+ quota.set_start_time(base::Time::Now().ToInternalValue());
+ quota.set_remaining(1000U);
+
+ PrecacheQuota expected_quota = quota;
+ precache_session_table_->SaveQuota(quota);
+ EXPECT_EQ(expected_quota.start_time(),
+ precache_session_table_->GetQuota().start_time());
+ EXPECT_EQ(expected_quota.remaining(),
+ precache_session_table_->GetQuota().remaining());
}
} // namespace
diff --git a/chromium/components/precache/core/precache_url_table.cc b/chromium/components/precache/core/precache_url_table.cc
index 3c39b9e5e0d..830ef892af9 100644
--- a/chromium/components/precache/core/precache_url_table.cc
+++ b/chromium/components/precache/core/precache_url_table.cc
@@ -23,6 +23,11 @@ std::string GetKey(const GURL& url) {
namespace precache {
+bool PrecacheURLInfo::operator==(const PrecacheURLInfo& other) const {
+ return was_precached == other.was_precached &&
+ is_precached == other.is_precached && was_used == other.was_used;
+}
+
PrecacheURLTable::PrecacheURLTable() : db_(NULL) {}
PrecacheURLTable::~PrecacheURLTable() {}
@@ -35,32 +40,90 @@ bool PrecacheURLTable::Init(sql::Connection* db) {
}
void PrecacheURLTable::AddURL(const GURL& url,
+ int64_t referrer_host_id,
+ bool is_precached,
const base::Time& precache_time) {
- Statement statement(db_->GetCachedStatement(
- SQL_FROM_HERE,
- "INSERT OR REPLACE INTO precache_urls (url, time) VALUES(?,?)"));
+ Statement statement(
+ db_->GetCachedStatement(SQL_FROM_HERE,
+ "INSERT OR REPLACE INTO precache_urls (url, "
+ "referrer_host_id, was_used, is_precached, time) "
+ "VALUES(?,?,0,?,?)"));
statement.BindString(0, GetKey(url));
- statement.BindInt64(1, precache_time.ToInternalValue());
+ statement.BindInt64(1, referrer_host_id);
+ statement.BindInt64(2, is_precached ? 1 : 0);
+ statement.BindInt64(3, precache_time.ToInternalValue());
statement.Run();
}
-bool PrecacheURLTable::HasURL(const GURL& url) {
+PrecacheURLInfo PrecacheURLTable::GetURLInfo(const GURL& url) {
Statement statement(db_->GetCachedStatement(
- SQL_FROM_HERE, "SELECT time FROM precache_urls WHERE url=?"));
-
+ SQL_FROM_HERE,
+ "SELECT is_precached, was_used FROM precache_urls WHERE url=?"));
statement.BindString(0, GetKey(url));
- return statement.Step();
+
+ if (statement.Step()) {
+ return {/*present=*/true, /*is_precached=*/statement.ColumnBool(0),
+ /*was_used==*/statement.ColumnBool(1)};
+ } else {
+ return {/*present=*/false, /*is_precached=*/false, /*was_used=*/false};
+ }
}
-void PrecacheURLTable::DeleteURL(const GURL& url) {
- Statement statement(db_->GetCachedStatement(
- SQL_FROM_HERE, "DELETE FROM precache_urls WHERE url=?"));
+void PrecacheURLTable::SetPrecachedURLAsUsed(const GURL& url) {
+ Statement statement(
+ db_->GetCachedStatement(SQL_FROM_HERE,
+ "UPDATE precache_urls SET was_used=1, "
+ "is_precached=0 "
+ "WHERE url=? and was_used=0 and is_precached=1"));
statement.BindString(0, GetKey(url));
statement.Run();
}
+void PrecacheURLTable::SetURLAsNotPrecached(const GURL& url) {
+ Statement statement(
+ db_->GetCachedStatement(SQL_FROM_HERE,
+ "UPDATE precache_urls SET is_precached=0 "
+ "WHERE url=? and is_precached=1"));
+ statement.BindString(0, GetKey(url));
+ statement.Run();
+}
+
+void PrecacheURLTable::GetURLListForReferrerHost(
+ int64_t referrer_host_id,
+ std::vector<GURL>* used_urls,
+ std::vector<GURL>* unused_urls) {
+ Statement statement(db_->GetCachedStatement(
+ SQL_FROM_HERE,
+ "SELECT url, was_used from precache_urls where referrer_host_id=?"));
+ statement.BindInt64(0, referrer_host_id);
+ while (statement.Step()) {
+ GURL url(statement.ColumnString(0));
+ if (statement.ColumnInt(1))
+ used_urls->push_back(url);
+ else
+ unused_urls->push_back(url);
+ }
+}
+
+void PrecacheURLTable::ClearAllForReferrerHost(int64_t referrer_host_id) {
+ // Delete the URLs that are not precached.
+ Statement delete_statement(
+ db_->GetCachedStatement(SQL_FROM_HERE,
+ "DELETE FROM precache_urls WHERE "
+ "referrer_host_id=? AND is_precached=0"));
+ delete_statement.BindInt64(0, referrer_host_id);
+ delete_statement.Run();
+
+ // Clear was_used for precached URLs.
+ Statement update_statement(db_->GetCachedStatement(
+ SQL_FROM_HERE,
+ "UPDATE precache_urls SET was_used=0 WHERE referrer_host_id=?"));
+ update_statement.BindInt64(0, referrer_host_id);
+ update_statement.Run();
+}
+
void PrecacheURLTable::DeleteAllPrecachedBefore(const base::Time& delete_end) {
Statement statement(db_->GetCachedStatement(
SQL_FROM_HERE, "DELETE FROM precache_urls WHERE time < ?"));
@@ -80,7 +143,8 @@ void PrecacheURLTable::GetAllDataForTesting(std::map<GURL, base::Time>* map) {
map->clear();
Statement statement(db_->GetCachedStatement(
- SQL_FROM_HERE, "SELECT url, time FROM precache_urls"));
+ SQL_FROM_HERE,
+ "SELECT url, time FROM precache_urls where is_precached=1"));
while (statement.Step()) {
GURL url = GURL(statement.ColumnString(0));
@@ -89,9 +153,28 @@ void PrecacheURLTable::GetAllDataForTesting(std::map<GURL, base::Time>* map) {
}
bool PrecacheURLTable::CreateTableIfNonExistent() {
- return db_->Execute(
- "CREATE TABLE IF NOT EXISTS precache_urls (url TEXT PRIMARY KEY, time "
- "INTEGER)");
+ if (!db_->DoesTableExist("precache_urls")) {
+ return db_->Execute(
+ "CREATE TABLE precache_urls "
+ "(url TEXT PRIMARY KEY, referrer_host_id INTEGER, was_used INTEGER, "
+ "is_precached INTEGER, "
+ "time INTEGER)");
+ } else {
+ // Migrate the table by creating the missing columns.
+ if (!db_->DoesColumnExist("precache_urls", "was_used") &&
+ !db_->Execute("ALTER TABLE precache_urls ADD COLUMN was_used INTEGER"))
+ return false;
+ if (!db_->DoesColumnExist("precache_urls", "is_precached") &&
+ !db_->Execute(
+ "ALTER TABLE precache_urls ADD COLUMN is_precached "
+ "INTEGER default 1"))
+ return false;
+ if (!db_->DoesColumnExist("precache_urls", "referrer_host_id") &&
+ !db_->Execute(
+ "ALTER TABLE precache_urls ADD COLUMN referrer_host_id INTEGER"))
+ return false;
+ }
+ return true;
}
} // namespace precache
diff --git a/chromium/components/precache/core/precache_url_table.h b/chromium/components/precache/core/precache_url_table.h
index 2fcdc146109..4ddbb61e13a 100644
--- a/chromium/components/precache/core/precache_url_table.h
+++ b/chromium/components/precache/core/precache_url_table.h
@@ -5,7 +5,10 @@
#ifndef COMPONENTS_PRECACHE_CORE_PRECACHE_URL_TABLE_H_
#define COMPONENTS_PRECACHE_CORE_PRECACHE_URL_TABLE_H_
+#include <stdint.h>
+
#include <map>
+#include <vector>
#include "base/macros.h"
#include "base/time/time.h"
@@ -17,6 +20,23 @@ class Connection;
namespace precache {
+// Information about a given URL with respect to the PrecacheURLTable.
+struct PrecacheURLInfo {
+ // The url has been prefetched in the past 60 days. (This number comes from
+ // kPrecacheHistoryExpiryPeriodDays in precache_database.cc.)
+ bool was_precached;
+
+ // True if the cache entry is the one fetched by PrecacheFetcher. False if a
+ // new network fetch overwrote the cache entry since the prefetch.
+ bool is_precached;
+
+ // The prefetched copy of the URL was used in browsing (i.e. while
+ // is_precached was true).
+ bool was_used;
+
+ bool operator==(const PrecacheURLInfo& other) const;
+};
+
// Interface for database table that keeps track of the URLs that have been
// precached but not used. This table is used to count how many bytes were saved
// by precached resources.
@@ -33,15 +53,31 @@ class PrecacheURLTable {
// Init must be called before any other methods.
bool Init(sql::Connection* db);
- // Adds a precached URL to the table, using the current time as the
- // precache timestamp. Replaces the row if one already exists.
- void AddURL(const GURL& url, const base::Time& precache_time);
+ // Adds an URL to the table, |referrer_host_id| is the id of the referrer host
+ // in PrecacheReferrerHostTable, |is_precached| indicates if the URL is
+ // precached, |time| is the timestamp. Replaces the row if one already exists.
+ void AddURL(const GURL& url,
+ int64_t referrer_host_id,
+ bool is_precached,
+ const base::Time& precache_time);
+
+ // Returns information about the URL's status with respect to prefetching.
+ PrecacheURLInfo GetURLInfo(const GURL& url);
+
+ // Sets the precached URL as used.
+ void SetPrecachedURLAsUsed(const GURL& url);
+
+ // Set the previously precached URL as not precached, during user browsing.
+ void SetURLAsNotPrecached(const GURL& url);
- // Returns true if this URL exists in the table.
- bool HasURL(const GURL& url);
+ // Populates the used and unused resource URLs for the referrer host with id
+ // |referrer_host_id|.
+ void GetURLListForReferrerHost(int64_t referrer_host_id,
+ std::vector<GURL>* used_urls,
+ std::vector<GURL>* unused_urls);
- // Deletes the row from the table that has the given URL, if it exists.
- void DeleteURL(const GURL& url);
+ // Clears all URL entries for the referrer host |referrer_host_id|.
+ void ClearAllForReferrerHost(int64_t referrer_host_id);
// Deletes entries that were precached before the time of |delete_end|.
void DeleteAllPrecachedBefore(const base::Time& delete_end);
diff --git a/chromium/components/precache/core/precache_url_table_unittest.cc b/chromium/components/precache/core/precache_url_table_unittest.cc
index 9053e58a96d..6a764e30b2f 100644
--- a/chromium/components/precache/core/precache_url_table_unittest.cc
+++ b/chromium/components/precache/core/precache_url_table_unittest.cc
@@ -6,14 +6,22 @@
#include <map>
#include <memory>
+#include <set>
#include "base/compiler_specific.h"
#include "base/time/time.h"
#include "sql/connection.h"
+#include "sql/statement.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace precache {
+void PrintTo(const PrecacheURLInfo& url_info, ::std::ostream* os) {
+ *os << "{" << url_info.was_precached << ", " << url_info.is_precached << ", "
+ << url_info.was_used << "}";
+}
+
namespace {
class PrecacheURLTableTest : public testing::Test {
@@ -26,7 +34,7 @@ class PrecacheURLTableTest : public testing::Test {
precache_url_table_.reset(new PrecacheURLTable());
db_.reset(new sql::Connection());
ASSERT_TRUE(db_->OpenInMemory());
- precache_url_table_->Init(db_.get());
+ ASSERT_TRUE(precache_url_table_->Init(db_.get()));
}
std::unique_ptr<PrecacheURLTable> precache_url_table_;
@@ -35,7 +43,7 @@ class PrecacheURLTableTest : public testing::Test {
TEST_F(PrecacheURLTableTest, AddURLWithNoExistingRow) {
const base::Time kTime = base::Time::FromInternalValue(100);
- precache_url_table_->AddURL(GURL("http://url.com"), kTime);
+ precache_url_table_->AddURL(GURL("http://url.com"), 1, true, kTime);
std::map<GURL, base::Time> expected_map;
expected_map[GURL("http://url.com")] = kTime;
@@ -48,8 +56,8 @@ TEST_F(PrecacheURLTableTest, AddURLWithNoExistingRow) {
TEST_F(PrecacheURLTableTest, AddURLWithExistingRow) {
const base::Time kOldTime = base::Time::FromInternalValue(50);
const base::Time kNewTime = base::Time::FromInternalValue(100);
- precache_url_table_->AddURL(GURL("http://url.com"), kOldTime);
- precache_url_table_->AddURL(GURL("http://url.com"), kNewTime);
+ precache_url_table_->AddURL(GURL("http://url.com"), 1, true, kOldTime);
+ precache_url_table_->AddURL(GURL("http://url.com"), 1, true, kNewTime);
std::map<GURL, base::Time> expected_map;
expected_map[GURL("http://url.com")] = kNewTime;
@@ -59,14 +67,15 @@ TEST_F(PrecacheURLTableTest, AddURLWithExistingRow) {
EXPECT_EQ(expected_map, actual_map);
}
-TEST_F(PrecacheURLTableTest, DeleteURL) {
+TEST_F(PrecacheURLTableTest, SetURLAsNotPrecached) {
const base::Time kStaysTime = base::Time::FromInternalValue(50);
const base::Time kDeletedTime = base::Time::FromInternalValue(100);
- precache_url_table_->AddURL(GURL("http://stays.com"), kStaysTime);
- precache_url_table_->AddURL(GURL("http://deleted.com"), kDeletedTime);
+ precache_url_table_->AddURL(GURL("http://stays.com"), 1, true, kStaysTime);
+ precache_url_table_->AddURL(GURL("http://deleted.com"), 1, true,
+ kDeletedTime);
- precache_url_table_->DeleteURL(GURL("http://deleted.com"));
+ precache_url_table_->SetURLAsNotPrecached(GURL("http://deleted.com"));
std::map<GURL, base::Time> expected_map;
expected_map[GURL("http://stays.com")] = kStaysTime;
@@ -76,17 +85,31 @@ TEST_F(PrecacheURLTableTest, DeleteURL) {
EXPECT_EQ(expected_map, actual_map);
}
-TEST_F(PrecacheURLTableTest, HasURL) {
- EXPECT_FALSE(precache_url_table_->HasURL(GURL("http://url.com")));
+TEST_F(PrecacheURLTableTest, GetURLInfo) {
+ const GURL url("http://url.com");
+
+ EXPECT_EQ((PrecacheURLInfo{false, false, false}),
+ precache_url_table_->GetURLInfo(url));
+
+ precache_url_table_->AddURL(url, 1, true, base::Time::FromInternalValue(100));
+
+ EXPECT_EQ((PrecacheURLInfo{true, true, false}),
+ precache_url_table_->GetURLInfo(url));
+
+ precache_url_table_->SetPrecachedURLAsUsed(url);
- precache_url_table_->AddURL(GURL("http://url.com"),
- base::Time::FromInternalValue(100));
+ EXPECT_EQ((PrecacheURLInfo{true, false, true}),
+ precache_url_table_->GetURLInfo(url));
- EXPECT_TRUE(precache_url_table_->HasURL(GURL("http://url.com")));
+ precache_url_table_->AddURL(url, 1, true, base::Time::FromInternalValue(100));
- precache_url_table_->DeleteURL(GURL("http://url.com"));
+ EXPECT_EQ((PrecacheURLInfo{true, true, false}),
+ precache_url_table_->GetURLInfo(url));
- EXPECT_FALSE(precache_url_table_->HasURL(GURL("http://url.com")));
+ precache_url_table_->SetURLAsNotPrecached(url);
+
+ EXPECT_EQ((PrecacheURLInfo{true, false, false}),
+ precache_url_table_->GetURLInfo(url));
}
TEST_F(PrecacheURLTableTest, DeleteAllPrecachedBefore) {
@@ -95,10 +118,10 @@ TEST_F(PrecacheURLTableTest, DeleteAllPrecachedBefore) {
const base::Time kEndTime = base::Time::FromInternalValue(30);
const base::Time kAfterTime = base::Time::FromInternalValue(40);
- precache_url_table_->AddURL(GURL("http://old.com"), kOldTime);
- precache_url_table_->AddURL(GURL("http://before.com"), kBeforeTime);
- precache_url_table_->AddURL(GURL("http://end.com"), kEndTime);
- precache_url_table_->AddURL(GURL("http://after.com"), kAfterTime);
+ precache_url_table_->AddURL(GURL("http://old.com"), 1, true, kOldTime);
+ precache_url_table_->AddURL(GURL("http://before.com"), 1, true, kBeforeTime);
+ precache_url_table_->AddURL(GURL("http://end.com"), 1, true, kEndTime);
+ precache_url_table_->AddURL(GURL("http://after.com"), 1, true, kAfterTime);
precache_url_table_->DeleteAllPrecachedBefore(kEndTime);
@@ -111,6 +134,46 @@ TEST_F(PrecacheURLTableTest, DeleteAllPrecachedBefore) {
EXPECT_EQ(expected_map, actual_map);
}
+TEST_F(PrecacheURLTableTest, TableMigration) {
+ // Create the previous version of the URL table.
+ precache_url_table_.reset(new PrecacheURLTable());
+ db_.reset(new sql::Connection());
+ ASSERT_TRUE(db_->OpenInMemory());
+ ASSERT_TRUE(db_->Execute(
+ "CREATE TABLE IF NOT EXISTS precache_urls (url TEXT PRIMARY KEY, time "
+ "INTEGER)"));
+
+ // Populate data for the previous version.
+ const std::string old_urls[] = {"http://foo.com", "http://bar.com",
+ "http://foobar.com"};
+ for (const auto& url : old_urls) {
+ sql::Statement statement(db_->GetCachedStatement(
+ SQL_FROM_HERE, "INSERT INTO precache_urls (url, time) VALUES(?,100)"));
+ statement.BindString(0, url);
+ statement.Run();
+ }
+
+ // Verify the migration.
+ ASSERT_TRUE(precache_url_table_->Init(db_.get()));
+ EXPECT_TRUE(db_->DoesColumnExist("precache_urls", "was_used"));
+ EXPECT_TRUE(db_->DoesColumnExist("precache_urls", "is_precached"));
+ EXPECT_TRUE(db_->DoesColumnExist("precache_urls", "referrer_host_id"));
+
+ std::set<std::string> actual_urls;
+ sql::Statement statement(
+ db_->GetCachedStatement(SQL_FROM_HERE,
+ "select url, referrer_host_id, was_used, "
+ "is_precached from precache_urls"));
+ while (statement.Step()) {
+ actual_urls.insert(statement.ColumnString(0));
+ EXPECT_EQ(0, statement.ColumnInt(1));
+ EXPECT_EQ(0, statement.ColumnInt(2));
+ EXPECT_EQ(1, statement.ColumnInt(3));
+ }
+ EXPECT_THAT(std::set<std::string>(begin(old_urls), end(old_urls)),
+ ::testing::ContainerEq(actual_urls));
+}
+
} // namespace
} // namespace precache
diff --git a/chromium/components/precache/core/proto/precache.proto b/chromium/components/precache/core/proto/precache.proto
index 9bdd7af9b5c..81a37531d60 100644
--- a/chromium/components/precache/core/proto/precache.proto
+++ b/chromium/components/precache/core/proto/precache.proto
@@ -13,6 +13,17 @@ option optimize_for = LITE_RUNTIME;
message PrecacheResource {
// The URL of the resource. This field must always be present.
optional string url = 1;
+
+ // The tophost this resource corresponds to.
+ optional string top_host_name = 2;
+
+ // How important this resource is for the host. It ranges from 0.0 to 1.0.
+ // Higher values mean more important.
+ optional double weight_ratio = 3;
+};
+
+message PrecacheManifestId {
+ optional int64 id = 1;
};
// A manifest of cacheable resources to be precached for a specific host.
@@ -23,13 +34,16 @@ message PrecacheManifest {
// Experiments running on this manifest.
optional PrecacheExperiments experiments = 2;
+
+ // Identifier for the manifest sent by the server.
+ optional PrecacheManifestId id = 3;
};
message PrecacheExperiments {
// A mapping between experiment groups and the resources that should be
// considered for the experiment.
map<fixed32, PrecacheResourceSelection> resources_by_experiment_group = 1;
-}
+};
message PrecacheResourceSelection {
// Select the resources as a std::bitset over the resources listed in the
@@ -42,7 +56,7 @@ message PrecacheResourceSelection {
//
// A missing bitset means that the experiment applies to all the resources.
optional fixed64 bitset = 1 [default = 0xFFFFFFFFFFFFFFFF];
-}
+};
message PrecacheConfigurationSettings {
// The maximum rank of the user's most visited hosts to consider precaching
@@ -74,4 +88,21 @@ message PrecacheConfigurationSettings {
// downloads as well as cached resources. After this limit is reached, no
// other resources will be downloaded.
optional uint64 max_bytes_total = 5 [default = 10000000 /* 10 MB */];
+
+ // The maximum number of bytes that can be fetched by precache on a single
+ // day. After this limit is reached, no more resources will be downloaded,
+ // until the quota gets replenished the next day.
+ optional uint64 daily_quota_total = 6 [default = 40000000 /* 10 MB */];
+
+ // The number of resources to fetch per precache run. Only the first
+ // |total_resources_count| resource URLs are fetched.
+ optional uint32 total_resources_count = 7 [default = 999999];
+
+ // The minimum visit-adjusted weight for which a resource will be downloaded.
+ optional double min_weight = 8 [default = 0];
+
+ // Whether to sort resources by weight, descending, before fetching. This
+ // affects the fetcher's behavior with respect to max_bytes_total and
+ // total_resources_count.
+ optional bool global_ranking = 9 [default = false];
};
diff --git a/chromium/components/precache/core/proto/quota.proto b/chromium/components/precache/core/proto/quota.proto
new file mode 100644
index 00000000000..effb895e75c
--- /dev/null
+++ b/chromium/components/precache/core/proto/quota.proto
@@ -0,0 +1,20 @@
+// 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.
+
+syntax = "proto2";
+
+package precache;
+
+// Chrome requires this.
+option optimize_for = LITE_RUNTIME;
+
+// Quota limit and expiry time. This is stored in a database, and not
+// transferred via network.
+message PrecacheQuota {
+ // Represents the start time of this quota.
+ optional int64 start_time = 1;
+
+ // Maximum number of bytes that can be fetched until this quota expires.
+ optional uint64 remaining = 2;
+}; \ No newline at end of file
diff --git a/chromium/components/precache/core/proto/timestamp.proto b/chromium/components/precache/core/proto/timestamp.proto
new file mode 100644
index 00000000000..7d7efaf3e9c
--- /dev/null
+++ b/chromium/components/precache/core/proto/timestamp.proto
@@ -0,0 +1,17 @@
+// 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.
+
+syntax = "proto2";
+
+package precache;
+
+// Chrome requires this.
+option optimize_for = LITE_RUNTIME;
+
+message Timestamp {
+ // Represents seconds of UTC time since Unix epoch
+ // 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
+ // 9999-12-31T23:59:59Z inclusive.
+ optional int64 seconds = 1;
+}
diff --git a/chromium/components/precache/core/proto/unfinished_work.proto b/chromium/components/precache/core/proto/unfinished_work.proto
index deb6329bbf6..67c5eb042c5 100644
--- a/chromium/components/precache/core/proto/unfinished_work.proto
+++ b/chromium/components/precache/core/proto/unfinished_work.proto
@@ -14,11 +14,9 @@ option optimize_for = LITE_RUNTIME;
message TopHost {
// The host name of a top host.
optional string hostname = 1;
-};
-message PrecacheManifestURL {
- // The URL that provides a manifest.
- optional string url = 1;
+ // The number of visits it had by this user.
+ optional int64 visits = 2;
};
// Information about the precache work that needs to be completed.
@@ -28,8 +26,9 @@ message PrecacheUnfinishedWork {
optional PrecacheConfigurationSettings config_settings = 2;
- // Manifest URLs remaining to be fetched.
- repeated PrecacheManifestURL manifest = 3;
+ // DEPRECATED: Manifest URLs remaining to be fetched.
+ // repeated DeprecatedPrecacheManifestURL deprecated_manifest = 3
+ // [deprecated = true];
// Resource URLs remaining to be fetched.
repeated PrecacheResource resource = 4;
@@ -47,8 +46,12 @@ message PrecacheUnfinishedWork {
// The total number of manifest URLs that the precache session started with.
optional uint64 num_manifest_urls = 7;
+ // The total number of resource URLs that the precache session gathered from
+ // the manifests.
+ optional uint64 num_resource_urls = 9;
+
// The internal value of a base::Time object representing the precache
// session start time. The start time is the time just before when top hosts
// are requested.
optional int64 start_time = 8;
-}; \ No newline at end of file
+};
diff --git a/chromium/components/precache/precache_defines.gypi b/chromium/components/precache/precache_defines.gypi
deleted file mode 100644
index a7868e7756c..00000000000
--- a/chromium/components/precache/precache_defines.gypi
+++ /dev/null
@@ -1,24 +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.
-
-{
- 'variables': {
- # These values are duplicated in the GN build in:
- # //components/precache/core:precache_config
- 'precache_config_settings_url%': 'https://www.gstatic.com/chrome/wifiprefetch/precache_config',
- 'precache_manifest_url_prefix%': 'https://www.gstatic.com/chrome/wifiprefetch/hosts/',
- },
- 'conditions': [
- ['precache_config_settings_url != ""', {
- 'defines': [
- 'PRECACHE_CONFIG_SETTINGS_URL="<(precache_config_settings_url)"',
- ],
- }],
- ['precache_manifest_url_prefix != ""', {
- 'defines': [
- 'PRECACHE_MANIFEST_URL_PREFIX="<(precache_manifest_url_prefix)"',
- ],
- }],
- ],
-}
diff --git a/chromium/components/pref_registry.gypi b/chromium/components/pref_registry.gypi
deleted file mode 100644
index 0499e19c3f0..00000000000
--- a/chromium/components/pref_registry.gypi
+++ /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.
-
-{
- 'targets': [
- {
- # GN version: //components/pref_registry
- 'target_name': 'pref_registry',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- 'prefs/prefs.gyp:prefs',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'pref_registry/pref_registry_syncable.cc',
- 'pref_registry/pref_registry_syncable.h',
- ],
- },
- {
- # GN version: //components/pref_registry:test_support
- 'target_name': 'pref_registry_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'pref_registry',
- 'prefs/prefs.gyp:prefs_test_support',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'pref_registry/testing_pref_service_syncable.cc',
- 'pref_registry/testing_pref_service_syncable.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/pref_registry/BUILD.gn b/chromium/components/pref_registry/BUILD.gn
index 8a3ef8b2e89..4a32f9a4b22 100644
--- a/chromium/components/pref_registry/BUILD.gn
+++ b/chromium/components/pref_registry/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("pref_registry") {
+static_library("pref_registry") {
sources = [
"pref_registry_syncable.cc",
"pref_registry_syncable.h",
@@ -15,7 +15,7 @@ source_set("pref_registry") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"testing_pref_service_syncable.cc",
diff --git a/chromium/components/prefs/BUILD.gn b/chromium/components/prefs/BUILD.gn
index 032ed18e172..ff4e1f2cb83 100644
--- a/chromium/components/prefs/BUILD.gn
+++ b/chromium/components/prefs/BUILD.gn
@@ -55,7 +55,7 @@ component("prefs") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"mock_pref_change_callback.cc",
diff --git a/chromium/components/prefs/in_memory_pref_store_unittest.cc b/chromium/components/prefs/in_memory_pref_store_unittest.cc
index d8467945611..a31757d796a 100644
--- a/chromium/components/prefs/in_memory_pref_store_unittest.cc
+++ b/chromium/components/prefs/in_memory_pref_store_unittest.cc
@@ -28,7 +28,7 @@ TEST_F(InMemoryPrefStoreTest, SetGetValue) {
EXPECT_FALSE(store_->GetValue(kTestPref, &value));
EXPECT_FALSE(store_->GetMutableValue(kTestPref, &mutable_value));
- store_->SetValue(kTestPref, base::WrapUnique(new base::FundamentalValue(42)),
+ store_->SetValue(kTestPref, base::MakeUnique<base::FundamentalValue>(42),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(store_->GetValue(kTestPref, &value));
EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
@@ -58,7 +58,7 @@ TEST_F(InMemoryPrefStoreTest, CallObserver) {
store_->AddObserver(&observer_);
// Triggers on SetValue.
- store_->SetValue(kTestPref, base::WrapUnique(new base::FundamentalValue(42)),
+ store_->SetValue(kTestPref, base::MakeUnique<base::FundamentalValue>(42),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
observer_.VerifyAndResetChangedKey(kTestPref);
@@ -68,7 +68,7 @@ TEST_F(InMemoryPrefStoreTest, CallObserver) {
// But not SetValueSilently.
store_->SetValueSilently(kTestPref,
- base::WrapUnique(new base::FundamentalValue(42)),
+ base::MakeUnique<base::FundamentalValue>(42),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_EQ(0u, observer_.changed_keys.size());
@@ -80,7 +80,7 @@ TEST_F(InMemoryPrefStoreTest, CallObserver) {
// Doesn't make call on removed observers.
store_->RemoveObserver(&observer_);
- store_->SetValue(kTestPref, base::WrapUnique(new base::FundamentalValue(42)),
+ store_->SetValue(kTestPref, base::MakeUnique<base::FundamentalValue>(42),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
store_->RemoveValue(kTestPref, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_EQ(0u, observer_.changed_keys.size());
diff --git a/chromium/components/prefs/json_pref_store.cc b/chromium/components/prefs/json_pref_store.cc
index 779c2009730..811d2be0787 100644
--- a/chromium/components/prefs/json_pref_store.cc
+++ b/chromium/components/prefs/json_pref_store.cc
@@ -22,6 +22,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/task_runner_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/time/default_clock.h"
#include "base/values.h"
@@ -171,6 +172,7 @@ JsonPrefStore::JsonPrefStore(
filtering_in_progress_(false),
pending_lossy_write_(false),
read_error_(PREF_READ_ERROR_NONE),
+ has_pending_write_reply_(false),
write_count_histogram_(writer_.commit_interval(), path_) {
DCHECK(!path_.empty());
}
@@ -323,11 +325,72 @@ void JsonPrefStore::ReportValueChanged(const std::string& key, uint32_t flags) {
ScheduleWrite(flags);
}
-void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback(
- const base::Closure& on_next_successful_write) {
+void JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback(
+ bool write_success) {
DCHECK(CalledOnValidThread());
- writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write);
+ has_pending_write_reply_ = false;
+ if (!on_next_successful_write_reply_.is_null()) {
+ base::Closure on_successful_write =
+ std::move(on_next_successful_write_reply_);
+ if (write_success) {
+ on_successful_write.Run();
+ } else {
+ RegisterOnNextSuccessfulWriteReply(on_successful_write);
+ }
+ }
+}
+
+// static
+void JsonPrefStore::PostWriteCallback(
+ const base::Callback<void(bool success)>& on_next_write_callback,
+ const base::Callback<void(bool success)>& on_next_write_reply,
+ scoped_refptr<base::SequencedTaskRunner> reply_task_runner,
+ bool write_success) {
+ if (!on_next_write_callback.is_null())
+ on_next_write_callback.Run(write_success);
+
+ // We can't run |on_next_write_reply| on the current thread. Bounce back to
+ // the |reply_task_runner| which is the correct sequenced thread.
+ reply_task_runner->PostTask(FROM_HERE,
+ base::Bind(on_next_write_reply, write_success));
+}
+
+void JsonPrefStore::RegisterOnNextSuccessfulWriteReply(
+ const base::Closure& on_next_successful_write_reply) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(on_next_successful_write_reply_.is_null());
+
+ on_next_successful_write_reply_ = on_next_successful_write_reply;
+
+ // If there are pending callbacks, avoid erasing them; the reply will be used
+ // as we set |on_next_successful_write_reply_|. Otherwise, setup a reply with
+ // an empty callback.
+ if (!has_pending_write_reply_) {
+ has_pending_write_reply_ = true;
+ writer_.RegisterOnNextWriteCallbacks(
+ base::Closure(),
+ base::Bind(
+ &PostWriteCallback, base::Callback<void(bool success)>(),
+ base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
+ AsWeakPtr()),
+ base::SequencedTaskRunnerHandle::Get()));
+ }
+}
+
+void JsonPrefStore::RegisterOnNextWriteSynchronousCallbacks(
+ OnWriteCallbackPair callbacks) {
+ DCHECK(CalledOnValidThread());
+
+ has_pending_write_reply_ = true;
+
+ writer_.RegisterOnNextWriteCallbacks(
+ callbacks.first,
+ base::Bind(
+ &PostWriteCallback, callbacks.second,
+ base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
+ AsWeakPtr()),
+ base::SequencedTaskRunnerHandle::Get()));
}
void JsonPrefStore::ClearMutableValues() {
@@ -401,8 +464,12 @@ bool JsonPrefStore::SerializeData(std::string* output) {
write_count_histogram_.RecordWriteOccured();
- if (pref_filter_)
- pref_filter_->FilterSerializeData(prefs_.get());
+ if (pref_filter_) {
+ OnWriteCallbackPair callbacks =
+ pref_filter_->FilterSerializeData(prefs_.get());
+ if (!callbacks.first.is_null() || !callbacks.second.is_null())
+ RegisterOnNextWriteSynchronousCallbacks(callbacks);
+ }
JSONStringValueSerializer serializer(output);
// Not pretty-printing prefs shrinks pref file size by ~30%. To obtain
diff --git a/chromium/components/prefs/json_pref_store.h b/chromium/components/prefs/json_pref_store.h
index 047fe74abcd..170ccb1161d 100644
--- a/chromium/components/prefs/json_pref_store.h
+++ b/chromium/components/prefs/json_pref_store.h
@@ -30,9 +30,11 @@ class Clock;
class DictionaryValue;
class FilePath;
class HistogramBase;
+class JsonPrefStoreCallbackTest;
class JsonPrefStoreLossyWriteTest;
class SequencedTaskRunner;
class SequencedWorkerPool;
+class WriteCallbacksObserver;
class Value;
FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestBasic);
FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod);
@@ -49,6 +51,11 @@ class COMPONENTS_PREFS_EXPORT JsonPrefStore
public:
struct ReadResult;
+ // A pair of callbacks to call before and after the preference file is written
+ // to disk.
+ using OnWriteCallbackPair =
+ std::pair<base::Closure, base::Callback<void(bool success)>>;
+
// Returns instance of SequencedTaskRunner which guarantees that file
// operations on the same file will be executed in sequenced order.
static scoped_refptr<base::SequencedTaskRunner> GetTaskRunnerForFile(
@@ -106,10 +113,12 @@ class COMPONENTS_PREFS_EXPORT JsonPrefStore
// cleanup that shouldn't otherwise alert observers.
void RemoveValueSilently(const std::string& key, uint32_t flags);
- // Registers |on_next_successful_write| to be called once, on the next
+ // Registers |on_next_successful_write_reply| to be called once, on the next
// successful write event of |writer_|.
- void RegisterOnNextSuccessfulWriteCallback(
- const base::Closure& on_next_successful_write);
+ // |on_next_successful_write_reply| will be called on the thread from which
+ // this method is called and does not need to be thread safe.
+ void RegisterOnNextSuccessfulWriteReply(
+ const base::Closure& on_next_successful_write_reply);
void ClearMutableValues() override;
@@ -170,10 +179,30 @@ class COMPONENTS_PREFS_EXPORT JsonPrefStore
WriteCountHistogramTestMultiplePeriods);
FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
WriteCountHistogramTestPeriodWithGaps);
+ friend class base::JsonPrefStoreCallbackTest;
friend class base::JsonPrefStoreLossyWriteTest;
+ friend class base::WriteCallbacksObserver;
~JsonPrefStore() override;
+ // If |write_success| is true, runs |on_next_successful_write_|.
+ // Otherwise, re-registers |on_next_successful_write_|.
+ void RunOrScheduleNextSuccessfulWriteCallback(bool write_success);
+
+ // Handles the result of a write with result |write_success|. Runs
+ // |on_next_write_callback| on the current thread and posts
+ // |on_next_write_reply| on |reply_task_runner|.
+ static void PostWriteCallback(
+ const base::Callback<void(bool success)>& on_next_write_callback,
+ const base::Callback<void(bool success)>& on_next_write_reply,
+ scoped_refptr<base::SequencedTaskRunner> reply_task_runner,
+ bool write_success);
+
+ // Registers the |callbacks| pair to be called once synchronously before and
+ // after, respectively, the next write event of |writer_|.
+ // Both callbacks must be thread-safe.
+ void RegisterOnNextWriteSynchronousCallbacks(OnWriteCallbackPair callbacks);
+
// This method is called after the JSON file has been read. It then hands
// |value| (or an empty dictionary in some read error cases) to the
// |pref_filter| if one is set. It also gives a callback pointing at
@@ -223,6 +252,9 @@ class COMPONENTS_PREFS_EXPORT JsonPrefStore
std::set<std::string> keys_need_empty_value_;
+ bool has_pending_write_reply_ = true;
+ base::Closure on_next_successful_write_reply_;
+
WriteCountHistogram write_count_histogram_;
DISALLOW_COPY_AND_ASSIGN(JsonPrefStore);
diff --git a/chromium/components/prefs/json_pref_store_unittest.cc b/chromium/components/prefs/json_pref_store_unittest.cc
index 18299e24ddb..99f12a73ac6 100644
--- a/chromium/components/prefs/json_pref_store_unittest.cc
+++ b/chromium/components/prefs/json_pref_store_unittest.cc
@@ -26,6 +26,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
#include "base/test/simple_test_clock.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread.h"
#include "base/values.h"
@@ -68,6 +69,7 @@ void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
class InterceptingPrefFilter : public PrefFilter {
public:
InterceptingPrefFilter();
+ InterceptingPrefFilter(OnWriteCallbackPair callback_pair);
~InterceptingPrefFilter() override;
// PrefFilter implementation:
@@ -75,8 +77,10 @@ class InterceptingPrefFilter : public PrefFilter {
const PostFilterOnLoadCallback& post_filter_on_load_callback,
std::unique_ptr<base::DictionaryValue> pref_store_contents) override;
void FilterUpdate(const std::string& path) override {}
- void FilterSerializeData(
- base::DictionaryValue* pref_store_contents) override {}
+ OnWriteCallbackPair FilterSerializeData(
+ base::DictionaryValue* pref_store_contents) override {
+ return on_write_callback_pair_;
+ }
bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; }
@@ -87,11 +91,18 @@ class InterceptingPrefFilter : public PrefFilter {
private:
PostFilterOnLoadCallback post_filter_on_load_callback_;
std::unique_ptr<base::DictionaryValue> intercepted_prefs_;
+ OnWriteCallbackPair on_write_callback_pair_;
DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter);
};
InterceptingPrefFilter::InterceptingPrefFilter() {}
+
+InterceptingPrefFilter::InterceptingPrefFilter(
+ OnWriteCallbackPair callback_pair) {
+ on_write_callback_pair_ = callback_pair;
+}
+
InterceptingPrefFilter::~InterceptingPrefFilter() {}
void InterceptingPrefFilter::FilterOnLoad(
@@ -121,6 +132,9 @@ class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
} // namespace
class JsonPrefStoreTest : public testing::Test {
+ public:
+ JsonPrefStoreTest() = default;
+
protected:
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -136,11 +150,13 @@ class JsonPrefStoreTest : public testing::Test {
base::ScopedTempDir temp_dir_;
// A message loop that we can use as the file thread message loop.
MessageLoop message_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreTest);
};
// Test fallback behavior for a nonexistent file.
TEST_F(JsonPrefStoreTest, NonExistentFile) {
- base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
+ base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
ASSERT_FALSE(PathExists(bogus_input_file));
scoped_refptr<JsonPrefStore> pref_store =
new JsonPrefStore(bogus_input_file, message_loop_.task_runner(),
@@ -152,9 +168,9 @@ TEST_F(JsonPrefStoreTest, NonExistentFile) {
// Test fallback behavior for a nonexistent file and alternate file.
TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
- base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
+ base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
base::FilePath bogus_alternate_input_file =
- temp_dir_.path().AppendASCII("read_alternate.txt");
+ temp_dir_.GetPath().AppendASCII("read_alternate.txt");
ASSERT_FALSE(PathExists(bogus_input_file));
ASSERT_FALSE(PathExists(bogus_alternate_input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
@@ -167,7 +183,7 @@ TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
// Test fallback behavior for an invalid file.
TEST_F(JsonPrefStoreTest, InvalidFile) {
- base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
+ base::FilePath invalid_file = temp_dir_.GetPath().AppendASCII("invalid.json");
ASSERT_LT(0, base::WriteFile(invalid_file,
kInvalidJson, arraysize(kInvalidJson) - 1));
@@ -179,7 +195,7 @@ TEST_F(JsonPrefStoreTest, InvalidFile) {
// The file should have been moved aside.
EXPECT_FALSE(PathExists(invalid_file));
- base::FilePath moved_aside = temp_dir_.path().AppendASCII("invalid.bad");
+ base::FilePath moved_aside = temp_dir_.GetPath().AppendASCII("invalid.bad");
EXPECT_TRUE(PathExists(moved_aside));
std::string moved_aside_contents;
@@ -213,7 +229,7 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
pref_store->SetValue(kSomeDirectory,
- base::WrapUnique(new StringValue(some_path.value())),
+ base::MakeUnique<StringValue>(some_path.value()),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
EXPECT_TRUE(actual->GetAsString(&path));
@@ -226,7 +242,7 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
EXPECT_TRUE(boolean);
pref_store->SetValue(kNewWindowsInTabs,
- base::WrapUnique(new FundamentalValue(false)),
+ base::MakeUnique<FundamentalValue>(false),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
EXPECT_TRUE(actual->GetAsBoolean(&boolean));
@@ -236,16 +252,15 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
int integer = 0;
EXPECT_TRUE(actual->GetAsInteger(&integer));
EXPECT_EQ(20, integer);
- pref_store->SetValue(kMaxTabs, base::WrapUnique(new FundamentalValue(10)),
+ pref_store->SetValue(kMaxTabs, base::MakeUnique<FundamentalValue>(10),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
EXPECT_TRUE(actual->GetAsInteger(&integer));
EXPECT_EQ(10, integer);
- pref_store->SetValue(
- kLongIntPref,
- base::WrapUnique(new StringValue(base::Int64ToString(214748364842LL))),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ pref_store->SetValue(kLongIntPref, base::MakeUnique<StringValue>(
+ base::Int64ToString(214748364842LL)),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
EXPECT_TRUE(actual->GetAsString(&string_value));
int64_t value;
@@ -263,7 +278,7 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
}
TEST_F(JsonPrefStoreTest, Basic) {
- base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+ base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
ASSERT_LT(0, base::WriteFile(input_file,
kReadJson, arraysize(kReadJson) - 1));
@@ -289,7 +304,7 @@ TEST_F(JsonPrefStoreTest, Basic) {
}
TEST_F(JsonPrefStoreTest, BasicAsync) {
- base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+ base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
ASSERT_LT(0, base::WriteFile(input_file,
kReadJson, arraysize(kReadJson) - 1));
@@ -328,7 +343,7 @@ TEST_F(JsonPrefStoreTest, BasicAsync) {
}
TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
- FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
+ FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
pref_file, message_loop_.task_runner(), std::unique_ptr<PrefFilter>());
@@ -360,7 +375,7 @@ TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
// This test is just documenting some potentially non-obvious behavior. It
// shouldn't be taken as normative.
TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
- FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
+ FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
pref_file, message_loop_.task_runner(), std::unique_ptr<PrefFilter>());
@@ -380,7 +395,7 @@ TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
// Tests asynchronous reading of the file when there is no file.
TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
- base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
+ base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
ASSERT_FALSE(PathExists(bogus_input_file));
scoped_refptr<JsonPrefStore> pref_store =
new JsonPrefStore(bogus_input_file, message_loop_.task_runner(),
@@ -401,7 +416,7 @@ TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
}
TEST_F(JsonPrefStoreTest, ReadWithInterceptor) {
- base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+ base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
ASSERT_LT(0, base::WriteFile(input_file,
kReadJson, arraysize(kReadJson) - 1));
@@ -443,7 +458,7 @@ TEST_F(JsonPrefStoreTest, ReadWithInterceptor) {
}
TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
- base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+ base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
ASSERT_LT(0, base::WriteFile(input_file,
kReadJson, arraysize(kReadJson) - 1));
@@ -505,13 +520,13 @@ TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
TEST_F(JsonPrefStoreTest, AlternateFile) {
base::FilePath alternate_input_file =
- temp_dir_.path().AppendASCII("alternate.json");
+ temp_dir_.GetPath().AppendASCII("alternate.json");
ASSERT_LT(0, base::WriteFile(alternate_input_file,
kReadJson, arraysize(kReadJson) - 1));
// Test that the alternate file is moved to the main file and read as-is from
// there.
- base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+ base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
ASSERT_FALSE(PathExists(input_file));
ASSERT_TRUE(PathExists(alternate_input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
@@ -542,12 +557,12 @@ TEST_F(JsonPrefStoreTest, AlternateFile) {
}
TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
- base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+ base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
ASSERT_LT(0, base::WriteFile(input_file,
kReadJson, arraysize(kReadJson) - 1));
base::FilePath alternate_input_file =
- temp_dir_.path().AppendASCII("alternate.json");
+ temp_dir_.GetPath().AppendASCII("alternate.json");
ASSERT_LT(0, base::WriteFile(alternate_input_file,
kInvalidJson, arraysize(kInvalidJson) - 1));
@@ -582,14 +597,14 @@ TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
}
TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
- base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+ base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
ASSERT_LT(0, base::WriteFile(input_file,
kReadJson, arraysize(kReadJson) - 1));
// Test that the basic read works fine when an alternate file is specified but
// does not exist.
base::FilePath alternate_input_file =
- temp_dir_.path().AppendASCII("alternate.json");
+ temp_dir_.GetPath().AppendASCII("alternate.json");
ASSERT_TRUE(PathExists(input_file));
ASSERT_FALSE(PathExists(alternate_input_file));
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
@@ -621,13 +636,13 @@ TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
base::FilePath alternate_input_file =
- temp_dir_.path().AppendASCII("alternate.json");
+ temp_dir_.GetPath().AppendASCII("alternate.json");
ASSERT_LT(0, base::WriteFile(alternate_input_file,
kReadJson, arraysize(kReadJson) - 1));
// Test that the alternate file is moved to the main file and read as-is from
// there even when the read is made asynchronously.
- base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+ base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
input_file, alternate_input_file, message_loop_.task_runner(),
std::unique_ptr<PrefFilter>());
@@ -818,21 +833,22 @@ TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
}
class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
+ public:
+ JsonPrefStoreLossyWriteTest() = default;
+
protected:
void SetUp() override {
JsonPrefStoreTest::SetUp();
- test_file_ = temp_dir_.path().AppendASCII("test.json");
+ test_file_ = temp_dir_.GetPath().AppendASCII("test.json");
}
- // Creates a JsonPrefStore with the given |file_writer|.
scoped_refptr<JsonPrefStore> CreatePrefStore() {
return new JsonPrefStore(test_file_, message_loop_.task_runner(),
std::unique_ptr<PrefFilter>());
}
// Return the ImportantFileWriter for a given JsonPrefStore.
- ImportantFileWriter* GetImportantFileWriter(
- scoped_refptr<JsonPrefStore> pref_store) {
+ ImportantFileWriter* GetImportantFileWriter(JsonPrefStore* pref_store) {
return &(pref_store->writer_);
}
@@ -847,16 +863,17 @@ class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
private:
base::FilePath test_file_;
+
+ DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreLossyWriteTest);
};
TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
- ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+ ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
// Set a normal pref and check that it gets scheduled to be written.
ASSERT_FALSE(file_writer->HasPendingWrite());
- pref_store->SetValue("normal",
- base::WrapUnique(new base::StringValue("normal")),
+ pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
ASSERT_TRUE(file_writer->HasPendingWrite());
file_writer->DoScheduledWrite();
@@ -865,8 +882,7 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
// Set a lossy pref and check that it is not scheduled to be written.
// SetValue/RemoveValue.
- pref_store->SetValue("lossy",
- base::WrapUnique(new base::StringValue("lossy")),
+ pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
@@ -874,7 +890,7 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
// SetValueSilently/RemoveValueSilently.
pref_store->SetValueSilently("lossy",
- base::WrapUnique(new base::StringValue("lossy")),
+ base::MakeUnique<base::StringValue>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
pref_store->RemoveValueSilently("lossy",
@@ -882,8 +898,7 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
ASSERT_FALSE(file_writer->HasPendingWrite());
// ReportValueChanged.
- pref_store->SetValue("lossy",
- base::WrapUnique(new base::StringValue("lossy")),
+ pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
pref_store->ReportValueChanged("lossy",
@@ -900,18 +915,16 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
- ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+ ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
// Set a lossy pref and check that it is not scheduled to be written.
ASSERT_FALSE(file_writer->HasPendingWrite());
- pref_store->SetValue("lossy",
- base::WrapUnique(new base::StringValue("lossy")),
+ pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
// Set a normal pref and check that it is scheduled to be written.
- pref_store->SetValue("normal",
- base::WrapUnique(new base::StringValue("normal")),
+ pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
ASSERT_TRUE(file_writer->HasPendingWrite());
@@ -924,18 +937,16 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
- ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+ ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
// Set a normal pref and check that it is scheduled to be written.
ASSERT_FALSE(file_writer->HasPendingWrite());
- pref_store->SetValue("normal",
- base::WrapUnique(new base::StringValue("normal")),
+ pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
ASSERT_TRUE(file_writer->HasPendingWrite());
// Set a lossy pref and check that the write is still scheduled.
- pref_store->SetValue("lossy",
- base::WrapUnique(new base::StringValue("lossy")),
+ pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_TRUE(file_writer->HasPendingWrite());
@@ -948,11 +959,10 @@ TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
TEST_F(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
- ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+ ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
// Set a lossy pref and check that it is not scheduled to be written.
- pref_store->SetValue("lossy",
- base::WrapUnique(new base::StringValue("lossy")),
+ pref_store->SetValue("lossy", base::MakeUnique<base::StringValue>("lossy"),
WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
ASSERT_FALSE(file_writer->HasPendingWrite());
@@ -967,4 +977,278 @@ TEST_F(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
ASSERT_EQ("{\"lossy\":\"lossy\"}", GetTestFileContents());
}
+class SuccessfulWriteReplyObserver {
+ public:
+ SuccessfulWriteReplyObserver() = default;
+
+ // Returns true if a successful write was observed via on_successful_write()
+ // and resets the observation state to false regardless.
+ bool GetAndResetObservationState() {
+ bool was_successful_write_observed = successful_write_reply_observed_;
+ successful_write_reply_observed_ = false;
+ return was_successful_write_observed;
+ }
+
+ // Register OnWrite() to be called on the next write of |json_pref_store|.
+ void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
+
+ void OnSuccessfulWrite() {
+ EXPECT_FALSE(successful_write_reply_observed_);
+ successful_write_reply_observed_ = true;
+ }
+
+ private:
+ bool successful_write_reply_observed_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(SuccessfulWriteReplyObserver);
+};
+
+void SuccessfulWriteReplyObserver::ObserveNextWriteCallback(
+ JsonPrefStore* json_pref_store) {
+ json_pref_store->RegisterOnNextSuccessfulWriteReply(
+ base::Bind(&SuccessfulWriteReplyObserver::OnSuccessfulWrite,
+ base::Unretained(this)));
+}
+
+enum WriteCallbackObservationState {
+ NOT_CALLED,
+ CALLED_WITH_ERROR,
+ CALLED_WITH_SUCCESS,
+};
+
+class WriteCallbacksObserver {
+ public:
+ WriteCallbacksObserver() = default;
+
+ // Register OnWrite() to be called on the next write of |json_pref_store|.
+ void ObserveNextWriteCallback(JsonPrefStore* json_pref_store);
+
+ // Returns whether OnPreWrite() was called, and resets the observation state
+ // to false.
+ bool GetAndResetPreWriteObservationState();
+
+ // Returns the |WriteCallbackObservationState| which was observed, then resets
+ // it to |NOT_CALLED|.
+ WriteCallbackObservationState GetAndResetPostWriteObservationState();
+
+ JsonPrefStore::OnWriteCallbackPair GetCallbackPair() {
+ return std::make_pair(
+ base::Bind(&WriteCallbacksObserver::OnPreWrite, base::Unretained(this)),
+ base::Bind(&WriteCallbacksObserver::OnPostWrite,
+ base::Unretained(this)));
+ }
+
+ void OnPreWrite() {
+ EXPECT_FALSE(pre_write_called_);
+ pre_write_called_ = true;
+ }
+
+ void OnPostWrite(bool success) {
+ EXPECT_EQ(NOT_CALLED, post_write_observation_state_);
+ post_write_observation_state_ =
+ success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
+ }
+
+ private:
+ bool pre_write_called_ = false;
+ WriteCallbackObservationState post_write_observation_state_ = NOT_CALLED;
+
+ DISALLOW_COPY_AND_ASSIGN(WriteCallbacksObserver);
+};
+
+void WriteCallbacksObserver::ObserveNextWriteCallback(JsonPrefStore* writer) {
+ writer->RegisterOnNextWriteSynchronousCallbacks(GetCallbackPair());
+}
+
+bool WriteCallbacksObserver::GetAndResetPreWriteObservationState() {
+ bool observation_state = pre_write_called_;
+ pre_write_called_ = false;
+ return observation_state;
+}
+
+WriteCallbackObservationState
+WriteCallbacksObserver::GetAndResetPostWriteObservationState() {
+ WriteCallbackObservationState state = post_write_observation_state_;
+ pre_write_called_ = false;
+ post_write_observation_state_ = NOT_CALLED;
+ return state;
+}
+
+class JsonPrefStoreCallbackTest : public JsonPrefStoreTest {
+ public:
+ JsonPrefStoreCallbackTest() = default;
+
+ protected:
+ void SetUp() override {
+ JsonPrefStoreTest::SetUp();
+ test_file_ = temp_dir_.GetPath().AppendASCII("test.json");
+ }
+
+ scoped_refptr<JsonPrefStore> CreatePrefStore() {
+ return new JsonPrefStore(test_file_, message_loop_.task_runner(),
+ std::unique_ptr<PrefFilter>());
+ }
+
+ // Return the ImportantFileWriter for a given JsonPrefStore.
+ ImportantFileWriter* GetImportantFileWriter(JsonPrefStore* pref_store) {
+ return &(pref_store->writer_);
+ }
+
+ void TriggerFakeWriteForCallback(JsonPrefStore* pref_store, bool success) {
+ JsonPrefStore::PostWriteCallback(
+ base::Bind(&JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
+ pref_store->AsWeakPtr()),
+ base::Bind(&WriteCallbacksObserver::OnPostWrite,
+ base::Unretained(&write_callback_observer_)),
+ base::SequencedTaskRunnerHandle::Get(), success);
+ }
+
+ SuccessfulWriteReplyObserver successful_write_reply_observer_;
+ WriteCallbacksObserver write_callback_observer_;
+
+ private:
+ base::FilePath test_file_;
+
+ DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreCallbackTest);
+};
+
+TEST_F(JsonPrefStoreCallbackTest, TestSerializeDataCallbacks) {
+ base::FilePath input_file = temp_dir_.GetPath().AppendASCII("write.json");
+ ASSERT_LT(0,
+ base::WriteFile(input_file, kReadJson, arraysize(kReadJson) - 1));
+
+ std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
+ new InterceptingPrefFilter(write_callback_observer_.GetCallbackPair()));
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, message_loop_.task_runner(),
+ std::move(intercepting_pref_filter));
+ ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
+
+ EXPECT_EQ(NOT_CALLED,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+ pref_store->SetValue("normal", base::MakeUnique<base::StringValue>("normal"),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ file_writer->DoScheduledWrite();
+
+ // The observer should not be invoked right away.
+ EXPECT_FALSE(write_callback_observer_.GetAndResetPreWriteObservationState());
+ EXPECT_EQ(NOT_CALLED,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+
+ RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
+ EXPECT_EQ(CALLED_WITH_SUCCESS,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+}
+
+TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacks) {
+ scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
+ ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
+
+ // Test RegisterOnNextWriteSynchronousCallbacks after
+ // RegisterOnNextSuccessfulWriteReply.
+ successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
+ write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
+ file_writer->WriteNow(MakeUnique<std::string>("foo"));
+ RunLoop().RunUntilIdle();
+ EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
+ EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
+ EXPECT_EQ(CALLED_WITH_SUCCESS,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+
+ // Test RegisterOnNextSuccessfulWriteReply after
+ // RegisterOnNextWriteSynchronousCallbacks.
+ successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
+ write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
+ file_writer->WriteNow(MakeUnique<std::string>("foo"));
+ RunLoop().RunUntilIdle();
+ EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
+ EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
+ EXPECT_EQ(CALLED_WITH_SUCCESS,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+
+ // Test RegisterOnNextSuccessfulWriteReply only.
+ successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
+ file_writer->WriteNow(MakeUnique<std::string>("foo"));
+ RunLoop().RunUntilIdle();
+ EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
+ EXPECT_FALSE(write_callback_observer_.GetAndResetPreWriteObservationState());
+ EXPECT_EQ(NOT_CALLED,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+
+ // Test RegisterOnNextWriteSynchronousCallbacks only.
+ write_callback_observer_.ObserveNextWriteCallback(pref_store.get());
+ file_writer->WriteNow(MakeUnique<std::string>("foo"));
+ RunLoop().RunUntilIdle();
+ EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
+ EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
+ EXPECT_EQ(CALLED_WITH_SUCCESS,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+}
+
+TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacksWithFakeFailure) {
+ scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
+
+ // Confirm that the observers are invoked.
+ successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
+ TriggerFakeWriteForCallback(pref_store.get(), true);
+ RunLoop().RunUntilIdle();
+ EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
+ EXPECT_EQ(CALLED_WITH_SUCCESS,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+
+ // Confirm that the observation states were reset.
+ EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
+ EXPECT_EQ(NOT_CALLED,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+
+ // Confirm that re-installing the observers works for another write.
+ successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
+ TriggerFakeWriteForCallback(pref_store.get(), true);
+ RunLoop().RunUntilIdle();
+ EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
+ EXPECT_EQ(CALLED_WITH_SUCCESS,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+
+ // Confirm that the successful observer is not invoked by an unsuccessful
+ // write, and that the synchronous observer is invoked.
+ successful_write_reply_observer_.ObserveNextWriteCallback(pref_store.get());
+ TriggerFakeWriteForCallback(pref_store.get(), false);
+ RunLoop().RunUntilIdle();
+ EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
+ EXPECT_EQ(CALLED_WITH_ERROR,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+
+ // Do a real write, and confirm that the successful observer was invoked after
+ // being set by |PostWriteCallback| by the last TriggerFakeWriteCallback.
+ ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
+ file_writer->WriteNow(MakeUnique<std::string>("foo"));
+ RunLoop().RunUntilIdle();
+ EXPECT_TRUE(successful_write_reply_observer_.GetAndResetObservationState());
+ EXPECT_EQ(NOT_CALLED,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+}
+
+TEST_F(JsonPrefStoreCallbackTest, TestPostWriteCallbacksDuringProfileDeath) {
+ // Create a JsonPrefStore and attach observers to it, then delete it by making
+ // it go out of scope to simulate profile switch or Chrome shutdown.
+ {
+ scoped_refptr<JsonPrefStore> soon_out_of_scope_pref_store =
+ CreatePrefStore();
+ ImportantFileWriter* file_writer =
+ GetImportantFileWriter(soon_out_of_scope_pref_store.get());
+ successful_write_reply_observer_.ObserveNextWriteCallback(
+ soon_out_of_scope_pref_store.get());
+ write_callback_observer_.ObserveNextWriteCallback(
+ soon_out_of_scope_pref_store.get());
+ file_writer->WriteNow(MakeUnique<std::string>("foo"));
+ }
+ RunLoop().RunUntilIdle();
+ EXPECT_FALSE(successful_write_reply_observer_.GetAndResetObservationState());
+ EXPECT_TRUE(write_callback_observer_.GetAndResetPreWriteObservationState());
+ EXPECT_EQ(CALLED_WITH_SUCCESS,
+ write_callback_observer_.GetAndResetPostWriteObservationState());
+}
+
} // namespace base
diff --git a/chromium/components/prefs/overlay_user_pref_store_unittest.cc b/chromium/components/prefs/overlay_user_pref_store_unittest.cc
index 1f8916a2c51..ae320815973 100644
--- a/chromium/components/prefs/overlay_user_pref_store_unittest.cc
+++ b/chromium/components/prefs/overlay_user_pref_store_unittest.cc
@@ -49,22 +49,22 @@ TEST_F(OverlayUserPrefStoreTest, Observer) {
overlay_->AddObserver(&obs);
// Check that underlay first value is reported.
- underlay_->SetValue(overlay_key, base::WrapUnique(new FundamentalValue(42)),
+ underlay_->SetValue(overlay_key, base::MakeUnique<FundamentalValue>(42),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(overlay_key);
// Check that underlay overwriting is reported.
- underlay_->SetValue(overlay_key, base::WrapUnique(new FundamentalValue(43)),
+ underlay_->SetValue(overlay_key, base::MakeUnique<FundamentalValue>(43),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(overlay_key);
// Check that overwriting change in overlay is reported.
- overlay_->SetValue(overlay_key, base::WrapUnique(new FundamentalValue(44)),
+ overlay_->SetValue(overlay_key, base::MakeUnique<FundamentalValue>(44),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
obs.VerifyAndResetChangedKey(overlay_key);
// Check that hidden underlay change is not reported.
- underlay_->SetValue(overlay_key, base::WrapUnique(new FundamentalValue(45)),
+ underlay_->SetValue(overlay_key, base::MakeUnique<FundamentalValue>(45),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
@@ -80,16 +80,16 @@ TEST_F(OverlayUserPrefStoreTest, Observer) {
// Check respecting of silence.
overlay_->SetValueSilently(overlay_key,
- base::WrapUnique(new FundamentalValue(46)),
+ base::MakeUnique<FundamentalValue>(46),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
overlay_->RemoveObserver(&obs);
// Check successful unsubscription.
- underlay_->SetValue(overlay_key, base::WrapUnique(new FundamentalValue(47)),
+ underlay_->SetValue(overlay_key, base::MakeUnique<FundamentalValue>(47),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- overlay_->SetValue(overlay_key, base::WrapUnique(new FundamentalValue(48)),
+ overlay_->SetValue(overlay_key, base::MakeUnique<FundamentalValue>(48),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(obs.changed_keys.empty());
}
@@ -99,7 +99,7 @@ TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
EXPECT_FALSE(overlay_->GetValue(overlay_key, &value));
EXPECT_FALSE(underlay_->GetValue(overlay_key, &value));
- underlay_->SetValue(overlay_key, base::WrapUnique(new FundamentalValue(42)),
+ underlay_->SetValue(overlay_key, base::MakeUnique<FundamentalValue>(42),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
// Value shines through:
@@ -109,7 +109,7 @@ TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
- overlay_->SetValue(overlay_key, base::WrapUnique(new FundamentalValue(43)),
+ overlay_->SetValue(overlay_key, base::MakeUnique<FundamentalValue>(43),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
diff --git a/chromium/components/prefs/pref_filter.h b/chromium/components/prefs/pref_filter.h
index 6ca21976183..82be63e0aee 100644
--- a/chromium/components/prefs/pref_filter.h
+++ b/chromium/components/prefs/pref_filter.h
@@ -7,6 +7,7 @@
#include <memory>
#include <string>
+#include <utility>
#include "base/callback_forward.h"
#include "components/prefs/base_prefs_export.h"
@@ -20,13 +21,17 @@ class Value;
// Currently supported only by JsonPrefStore.
class COMPONENTS_PREFS_EXPORT PrefFilter {
public:
+ // A pair of pre-write and post-write callbacks.
+ using OnWriteCallbackPair =
+ std::pair<base::Closure, base::Callback<void(bool success)>>;
+
// A callback to be invoked when |prefs| have been read (and possibly
// pre-modified) and are now ready to be handed back to this callback's
// builder. |schedule_write| indicates whether a write should be immediately
// scheduled (typically because the |prefs| were pre-modified).
- typedef base::Callback<void(std::unique_ptr<base::DictionaryValue> prefs,
- bool schedule_write)>
- PostFilterOnLoadCallback;
+ using PostFilterOnLoadCallback =
+ base::Callback<void(std::unique_ptr<base::DictionaryValue> prefs,
+ bool schedule_write)>;
virtual ~PrefFilter() {}
@@ -49,7 +54,10 @@ class COMPONENTS_PREFS_EXPORT PrefFilter {
// contained in |pref_store_contents| to a string. Modifications to
// |pref_store_contents| will be persisted to disk and also affect the
// in-memory state.
- virtual void FilterSerializeData(
+ // If the returned callbacks are non-null, they will be registered to be
+ // invoked synchronously after the next write (from the I/O TaskRunner so they
+ // must not be bound to thread-unsafe member state).
+ virtual OnWriteCallbackPair FilterSerializeData(
base::DictionaryValue* pref_store_contents) = 0;
};
diff --git a/chromium/components/prefs/pref_notifier_impl.cc b/chromium/components/prefs/pref_notifier_impl.cc
index b3d566003c6..48dd57c22d2 100644
--- a/chromium/components/prefs/pref_notifier_impl.cc
+++ b/chromium/components/prefs/pref_notifier_impl.cc
@@ -5,12 +5,10 @@
#include "components/prefs/pref_notifier_impl.h"
#include "base/logging.h"
-#include "base/stl_util.h"
+#include "base/memory/ptr_util.h"
#include "components/prefs/pref_service.h"
-PrefNotifierImpl::PrefNotifierImpl()
- : pref_service_(NULL) {
-}
+PrefNotifierImpl::PrefNotifierImpl() : pref_service_(nullptr) {}
PrefNotifierImpl::PrefNotifierImpl(PrefService* service)
: pref_service_(service) {
@@ -20,11 +18,10 @@ PrefNotifierImpl::~PrefNotifierImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
// Verify that there are no pref observers when we shut down.
- for (PrefObserverMap::iterator it = pref_observers_.begin();
- it != pref_observers_.end(); ++it) {
- PrefObserverList::Iterator obs_iterator(it->second);
+ for (const auto& observer_list : pref_observers_) {
+ PrefObserverList::Iterator obs_iterator(observer_list.second.get());
if (obs_iterator.GetNext()) {
- LOG(WARNING) << "pref observer found at shutdown " << it->first;
+ LOG(WARNING) << "Pref observer found at shutdown.";
}
}
@@ -32,8 +29,6 @@ PrefNotifierImpl::~PrefNotifierImpl() {
if (!init_observers_.empty())
LOG(WARNING) << "Init observer found at shutdown.";
- STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
- pref_observers_.end());
pref_observers_.clear();
init_observers_.clear();
}
@@ -41,14 +36,13 @@ PrefNotifierImpl::~PrefNotifierImpl() {
void PrefNotifierImpl::AddPrefObserver(const std::string& path,
PrefObserver* obs) {
// Get the pref observer list associated with the path.
- PrefObserverList* observer_list = NULL;
- const PrefObserverMap::iterator observer_iterator =
- pref_observers_.find(path);
+ PrefObserverList* observer_list = nullptr;
+ auto observer_iterator = pref_observers_.find(path);
if (observer_iterator == pref_observers_.end()) {
observer_list = new PrefObserverList;
- pref_observers_[path] = observer_list;
+ pref_observers_[path] = base::WrapUnique(observer_list);
} else {
- observer_list = observer_iterator->second;
+ observer_list = observer_iterator->second.get();
}
// Add the pref observer. ObserverList will DCHECK if it already is
@@ -60,13 +54,12 @@ void PrefNotifierImpl::RemovePrefObserver(const std::string& path,
PrefObserver* obs) {
DCHECK(thread_checker_.CalledOnValidThread());
- const PrefObserverMap::iterator observer_iterator =
- pref_observers_.find(path);
+ auto observer_iterator = pref_observers_.find(path);
if (observer_iterator == pref_observers_.end()) {
return;
}
- PrefObserverList* observer_list = observer_iterator->second;
+ PrefObserverList* observer_list = observer_iterator->second.get();
observer_list->RemoveObserver(obs);
}
@@ -87,11 +80,8 @@ void PrefNotifierImpl::OnInitializationCompleted(bool succeeded) {
PrefInitObserverList observers(init_observers_);
init_observers_.clear();
- for (PrefInitObserverList::iterator it = observers.begin();
- it != observers.end();
- ++it) {
- it->Run(succeeded);
- }
+ for (auto& observer : observers)
+ observer.Run(succeeded);
}
void PrefNotifierImpl::FireObservers(const std::string& path) {
@@ -101,8 +91,7 @@ void PrefNotifierImpl::FireObservers(const std::string& path) {
if (!pref_service_->FindPreference(path))
return;
- const PrefObserverMap::iterator observer_iterator =
- pref_observers_.find(path);
+ auto observer_iterator = pref_observers_.find(path);
if (observer_iterator == pref_observers_.end())
return;
@@ -112,6 +101,6 @@ void PrefNotifierImpl::FireObservers(const std::string& path) {
}
void PrefNotifierImpl::SetPrefService(PrefService* pref_service) {
- DCHECK(pref_service_ == NULL);
+ DCHECK(pref_service_ == nullptr);
pref_service_ = pref_service;
}
diff --git a/chromium/components/prefs/pref_notifier_impl.h b/chromium/components/prefs/pref_notifier_impl.h
index e0da264ac3a..c5448d3b53e 100644
--- a/chromium/components/prefs/pref_notifier_impl.h
+++ b/chromium/components/prefs/pref_notifier_impl.h
@@ -6,6 +6,7 @@
#define COMPONENTS_PREFS_PREF_NOTIFIER_IMPL_H_
#include <list>
+#include <memory>
#include <string>
#include "base/callback.h"
@@ -49,7 +50,8 @@ class COMPONENTS_PREFS_EXPORT PrefNotifierImpl
// order they are added. These should only be accessed externally for unit
// testing.
typedef base::ObserverList<PrefObserver> PrefObserverList;
- typedef base::hash_map<std::string, PrefObserverList*> PrefObserverMap;
+ typedef base::hash_map<std::string, std::unique_ptr<PrefObserverList>>
+ PrefObserverMap;
typedef std::list<base::Callback<void(bool)>> PrefInitObserverList;
diff --git a/chromium/components/prefs/pref_notifier_impl_unittest.cc b/chromium/components/prefs/pref_notifier_impl_unittest.cc
index a3f12349b9f..517a403936a 100644
--- a/chromium/components/prefs/pref_notifier_impl_unittest.cc
+++ b/chromium/components/prefs/pref_notifier_impl_unittest.cc
@@ -59,7 +59,7 @@ class MockPrefNotifier : public PrefNotifierImpl {
if (observer_iterator == pref_observers()->end())
return false;
- PrefObserverList* observer_list = observer_iterator->second;
+ PrefObserverList* observer_list = observer_iterator->second.get();
PrefObserverList::Iterator it(observer_list);
PrefObserver* existing_obs;
size_t count = 0;
diff --git a/chromium/components/prefs/pref_registry.cc b/chromium/components/prefs/pref_registry.cc
index 92d161e8b04..c42e77f74aa 100644
--- a/chromium/components/prefs/pref_registry.cc
+++ b/chromium/components/prefs/pref_registry.cc
@@ -59,8 +59,8 @@ void PrefRegistry::RegisterPreference(const std::string& path,
"invalid preference type: " << orig_type;
DCHECK(!defaults_->GetValue(path, NULL)) <<
"Trying to register a previously registered pref: " << path;
- DCHECK(!ContainsKey(registration_flags_, path)) <<
- "Trying to register a previously registered pref: " << path;
+ DCHECK(!base::ContainsKey(registration_flags_, path))
+ << "Trying to register a previously registered pref: " << path;
defaults_->SetDefaultValue(path, base::WrapUnique(default_value));
if (flags != NO_REGISTRATION_FLAGS)
diff --git a/chromium/components/prefs/pref_service.cc b/chromium/components/prefs/pref_service.cc
index 4891ff59c66..e909d58be7e 100644
--- a/chromium/components/prefs/pref_service.cc
+++ b/chromium/components/prefs/pref_service.cc
@@ -98,7 +98,7 @@ void PrefService::InitFromStorage(bool async) {
// Guarantee that initialization happens after this function returned.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&PersistentPrefStore::ReadPrefsAsync, user_pref_store_.get(),
+ base::Bind(&PersistentPrefStore::ReadPrefsAsync, user_pref_store_,
new ReadErrorHandler(read_error_callback_)));
}
}
diff --git a/chromium/components/prefs/pref_value_map.cc b/chromium/components/prefs/pref_value_map.cc
index aba82e08adc..c146918e238 100644
--- a/chromium/components/prefs/pref_value_map.cc
+++ b/chromium/components/prefs/pref_value_map.cc
@@ -74,6 +74,10 @@ PrefValueMap::const_iterator PrefValueMap::end() const {
return prefs_.end();
}
+bool PrefValueMap::empty() const {
+ return prefs_.empty();
+}
+
bool PrefValueMap::GetBoolean(const std::string& key,
bool* value) const {
const base::Value* stored_value = nullptr;
@@ -81,7 +85,7 @@ bool PrefValueMap::GetBoolean(const std::string& key,
}
void PrefValueMap::SetBoolean(const std::string& key, bool value) {
- SetValue(key, base::WrapUnique(new base::FundamentalValue(value)));
+ SetValue(key, base::MakeUnique<base::FundamentalValue>(value));
}
bool PrefValueMap::GetString(const std::string& key,
@@ -92,7 +96,7 @@ bool PrefValueMap::GetString(const std::string& key,
void PrefValueMap::SetString(const std::string& key,
const std::string& value) {
- SetValue(key, base::WrapUnique(new base::StringValue(value)));
+ SetValue(key, base::MakeUnique<base::StringValue>(value));
}
bool PrefValueMap::GetInteger(const std::string& key, int* value) const {
@@ -101,11 +105,11 @@ bool PrefValueMap::GetInteger(const std::string& key, int* value) const {
}
void PrefValueMap::SetInteger(const std::string& key, const int value) {
- SetValue(key, base::WrapUnique(new base::FundamentalValue(value)));
+ SetValue(key, base::MakeUnique<base::FundamentalValue>(value));
}
void PrefValueMap::SetDouble(const std::string& key, const double value) {
- SetValue(key, base::WrapUnique(new base::FundamentalValue(value)));
+ SetValue(key, base::MakeUnique<base::FundamentalValue>(value));
}
void PrefValueMap::GetDifferingKeys(
diff --git a/chromium/components/prefs/pref_value_map.h b/chromium/components/prefs/pref_value_map.h
index a3b4aad6d7c..011b2a47268 100644
--- a/chromium/components/prefs/pref_value_map.h
+++ b/chromium/components/prefs/pref_value_map.h
@@ -51,6 +51,7 @@ class COMPONENTS_PREFS_EXPORT PrefValueMap {
iterator end();
const_iterator begin() const;
const_iterator end() const;
+ bool empty() const;
// Gets a boolean value for |key| and stores it in |value|. Returns true if
// the value was found and of the proper type.
diff --git a/chromium/components/prefs/pref_value_map_unittest.cc b/chromium/components/prefs/pref_value_map_unittest.cc
index 087e239f001..a0004090287 100644
--- a/chromium/components/prefs/pref_value_map_unittest.cc
+++ b/chromium/components/prefs/pref_value_map_unittest.cc
@@ -17,10 +17,9 @@ TEST(PrefValueMapTest, SetValue) {
EXPECT_FALSE(map.GetValue("key", &result));
EXPECT_FALSE(result);
- EXPECT_TRUE(map.SetValue("key", base::WrapUnique(new StringValue("test"))));
- EXPECT_FALSE(map.SetValue("key", base::WrapUnique(new StringValue("test"))));
- EXPECT_TRUE(
- map.SetValue("key", base::WrapUnique(new StringValue("hi mom!"))));
+ EXPECT_TRUE(map.SetValue("key", base::MakeUnique<StringValue>("test")));
+ EXPECT_FALSE(map.SetValue("key", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(map.SetValue("key", base::MakeUnique<StringValue>("hi mom!")));
EXPECT_TRUE(map.GetValue("key", &result));
EXPECT_TRUE(StringValue("hi mom!").Equals(result));
@@ -28,7 +27,7 @@ TEST(PrefValueMapTest, SetValue) {
TEST(PrefValueMapTest, GetAndSetIntegerValue) {
PrefValueMap map;
- ASSERT_TRUE(map.SetValue("key", base::WrapUnique(new FundamentalValue(5))));
+ ASSERT_TRUE(map.SetValue("key", base::MakeUnique<FundamentalValue>(5)));
int int_value = 0;
EXPECT_TRUE(map.GetInteger("key", &int_value));
@@ -41,7 +40,7 @@ TEST(PrefValueMapTest, GetAndSetIntegerValue) {
TEST(PrefValueMapTest, SetDoubleValue) {
PrefValueMap map;
- ASSERT_TRUE(map.SetValue("key", base::WrapUnique(new FundamentalValue(5.5))));
+ ASSERT_TRUE(map.SetValue("key", base::MakeUnique<FundamentalValue>(5.5)));
const Value* result = NULL;
ASSERT_TRUE(map.GetValue("key", &result));
@@ -54,7 +53,7 @@ TEST(PrefValueMapTest, RemoveValue) {
PrefValueMap map;
EXPECT_FALSE(map.RemoveValue("key"));
- EXPECT_TRUE(map.SetValue("key", base::WrapUnique(new StringValue("test"))));
+ EXPECT_TRUE(map.SetValue("key", base::MakeUnique<StringValue>("test")));
EXPECT_TRUE(map.GetValue("key", NULL));
EXPECT_TRUE(map.RemoveValue("key"));
@@ -65,7 +64,7 @@ TEST(PrefValueMapTest, RemoveValue) {
TEST(PrefValueMapTest, Clear) {
PrefValueMap map;
- EXPECT_TRUE(map.SetValue("key", base::WrapUnique(new StringValue("test"))));
+ EXPECT_TRUE(map.SetValue("key", base::MakeUnique<StringValue>("test")));
EXPECT_TRUE(map.GetValue("key", NULL));
map.Clear();
@@ -75,12 +74,9 @@ TEST(PrefValueMapTest, Clear) {
TEST(PrefValueMapTest, GetDifferingKeys) {
PrefValueMap reference;
- EXPECT_TRUE(
- reference.SetValue("b", base::WrapUnique(new StringValue("test"))));
- EXPECT_TRUE(
- reference.SetValue("c", base::WrapUnique(new StringValue("test"))));
- EXPECT_TRUE(
- reference.SetValue("e", base::WrapUnique(new StringValue("test"))));
+ EXPECT_TRUE(reference.SetValue("b", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(reference.SetValue("c", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(reference.SetValue("e", base::MakeUnique<StringValue>("test")));
PrefValueMap check;
std::vector<std::string> differing_paths;
@@ -92,9 +88,9 @@ TEST(PrefValueMapTest, GetDifferingKeys) {
expected_differing_paths.push_back("e");
EXPECT_EQ(expected_differing_paths, differing_paths);
- EXPECT_TRUE(check.SetValue("a", base::WrapUnique(new StringValue("test"))));
- EXPECT_TRUE(check.SetValue("c", base::WrapUnique(new StringValue("test"))));
- EXPECT_TRUE(check.SetValue("d", base::WrapUnique(new StringValue("test"))));
+ EXPECT_TRUE(check.SetValue("a", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(check.SetValue("c", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(check.SetValue("d", base::MakeUnique<StringValue>("test")));
reference.GetDifferingKeys(&check, &differing_paths);
expected_differing_paths.clear();
@@ -107,20 +103,14 @@ TEST(PrefValueMapTest, GetDifferingKeys) {
TEST(PrefValueMapTest, SwapTwoMaps) {
PrefValueMap first_map;
- EXPECT_TRUE(
- first_map.SetValue("a", base::WrapUnique(new StringValue("test"))));
- EXPECT_TRUE(
- first_map.SetValue("b", base::WrapUnique(new StringValue("test"))));
- EXPECT_TRUE(
- first_map.SetValue("c", base::WrapUnique(new StringValue("test"))));
+ EXPECT_TRUE(first_map.SetValue("a", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(first_map.SetValue("b", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(first_map.SetValue("c", base::MakeUnique<StringValue>("test")));
PrefValueMap second_map;
- EXPECT_TRUE(
- second_map.SetValue("d", base::WrapUnique(new StringValue("test"))));
- EXPECT_TRUE(
- second_map.SetValue("e", base::WrapUnique(new StringValue("test"))));
- EXPECT_TRUE(
- second_map.SetValue("f", base::WrapUnique(new StringValue("test"))));
+ EXPECT_TRUE(second_map.SetValue("d", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(second_map.SetValue("e", base::MakeUnique<StringValue>("test")));
+ EXPECT_TRUE(second_map.SetValue("f", base::MakeUnique<StringValue>("test")));
first_map.Swap(&second_map);
diff --git a/chromium/components/prefs/prefs.gyp b/chromium/components/prefs/prefs.gyp
deleted file mode 100644
index 3897576f9ce..00000000000
--- a/chromium/components/prefs/prefs.gyp
+++ /dev/null
@@ -1,89 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'prefs',
- 'type': '<(component)',
- 'dependencies': [
- '../../base/base.gyp:base',
- ],
- 'include_dirs': [
- '../..',
- ],
- 'defines': [
- 'COMPONENTS_PREFS_IMPLEMENTATION',
- ],
- 'sources': [
- 'default_pref_store.cc',
- 'default_pref_store.h',
- 'in_memory_pref_store.cc',
- 'in_memory_pref_store.h',
- 'json_pref_store.cc',
- 'json_pref_store.h',
- 'overlay_user_pref_store.cc',
- 'overlay_user_pref_store.h',
- 'pref_change_registrar.cc',
- 'pref_change_registrar.h',
- 'pref_member.cc',
- 'pref_member.h',
- 'pref_notifier_impl.cc',
- 'pref_notifier_impl.h',
- 'pref_registry.cc',
- 'pref_registry.h',
- 'pref_registry_simple.cc',
- 'pref_registry_simple.h',
- 'pref_service.cc',
- 'pref_service.h',
- 'pref_service_factory.cc',
- 'pref_service_factory.h',
- 'pref_store.cc',
- 'pref_store.h',
- 'pref_value_map.cc',
- 'pref_value_map.h',
- 'pref_value_store.cc',
- 'pref_value_store.h',
- 'scoped_user_pref_update.cc',
- 'scoped_user_pref_update.h',
- 'value_map_pref_store.cc',
- 'value_map_pref_store.h',
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'sources': [
- 'base_prefs_export.h',
- 'persistent_pref_store.h',
- 'pref_filter.h',
- 'pref_notifier.h',
- 'pref_observer.h',
- 'writeable_pref_store.h',
- ]
- }]
- ],
- },
- {
- 'target_name': 'prefs_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '../..',
- ],
- 'dependencies': [
- 'prefs',
- '<(DEPTH)/testing/gmock.gyp:gmock',
- '<(DEPTH)/testing/gtest.gyp:gtest',
- ],
- 'sources': [
- 'mock_pref_change_callback.cc',
- 'mock_pref_change_callback.h',
- 'pref_store_observer_mock.cc',
- 'pref_store_observer_mock.h',
- 'testing_pref_service.cc',
- 'testing_pref_service.h',
- 'testing_pref_store.cc',
- 'testing_pref_store.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/prefs/testing_pref_store.cc b/chromium/components/prefs/testing_pref_store.cc
index 426bd643f36..2060c9fdcec 100644
--- a/chromium/components/prefs/testing_pref_store.cc
+++ b/chromium/components/prefs/testing_pref_store.cc
@@ -118,17 +118,17 @@ void TestingPrefStore::ReportValueChanged(const std::string& key,
void TestingPrefStore::SetString(const std::string& key,
const std::string& value) {
- SetValue(key, base::WrapUnique(new base::StringValue(value)),
+ SetValue(key, base::MakeUnique<base::StringValue>(value),
DEFAULT_PREF_WRITE_FLAGS);
}
void TestingPrefStore::SetInteger(const std::string& key, int value) {
- SetValue(key, base::WrapUnique(new base::FundamentalValue(value)),
+ SetValue(key, base::MakeUnique<base::FundamentalValue>(value),
DEFAULT_PREF_WRITE_FLAGS);
}
void TestingPrefStore::SetBoolean(const std::string& key, bool value) {
- SetValue(key, base::WrapUnique(new base::FundamentalValue(value)),
+ SetValue(key, base::MakeUnique<base::FundamentalValue>(value),
DEFAULT_PREF_WRITE_FLAGS);
}
diff --git a/chromium/components/previews/OWNERS b/chromium/components/previews/OWNERS
new file mode 100644
index 00000000000..2783dea1c6e
--- /dev/null
+++ b/chromium/components/previews/OWNERS
@@ -0,0 +1 @@
+file://components/data_reduction_proxy/OWNERS
diff --git a/chromium/components/previews/PRESUBMIT.py b/chromium/components/previews/PRESUBMIT.py
new file mode 100644
index 00000000000..e23e2abf791
--- /dev/null
+++ b/chromium/components/previews/PRESUBMIT.py
@@ -0,0 +1,12 @@
+# 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.
+
+"""Top-level presubmit script for the previews component.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+ return input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
diff --git a/chromium/components/previews/README b/chromium/components/previews/README
new file mode 100644
index 00000000000..f7f0e5fad7d
--- /dev/null
+++ b/chromium/components/previews/README
@@ -0,0 +1,2 @@
+The Previews component contains code for changing the format and content of
+web pages to improve data savings and/or performance. \ No newline at end of file
diff --git a/chromium/components/previews/core/BUILD.gn b/chromium/components/previews/core/BUILD.gn
new file mode 100644
index 00000000000..7bf8b5eca77
--- /dev/null
+++ b/chromium/components/previews/core/BUILD.gn
@@ -0,0 +1,52 @@
+# 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.
+
+static_library("core") {
+ sources = [
+ "previews_black_list.cc",
+ "previews_black_list.h",
+ "previews_black_list_item.cc",
+ "previews_black_list_item.h",
+ "previews_data_savings.cc",
+ "previews_data_savings.h",
+ "previews_decider.h",
+ "previews_experiments.cc",
+ "previews_experiments.h",
+ "previews_io_data.cc",
+ "previews_io_data.h",
+ "previews_opt_out_store.h",
+ "previews_ui_service.cc",
+ "previews_ui_service.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/data_reduction_proxy/core/common",
+ "//components/variations",
+ "//net",
+ "//url:url",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "previews_black_list_item_unittest.cc",
+ "previews_black_list_unittest.cc",
+ "previews_data_savings_unittest.cc",
+ "previews_experiments_unittest.cc",
+ "previews_io_data_unittest.cc",
+ "previews_ui_service_unittest.cc",
+ ]
+
+ deps = [
+ ":core",
+ "//base",
+ "//base/test:test_support",
+ "//components/data_reduction_proxy/core/common",
+ "//components/variations",
+ "//testing/gtest",
+ "//url:url",
+ ]
+}
diff --git a/chromium/components/previews/core/DEPS b/chromium/components/previews/core/DEPS
new file mode 100644
index 00000000000..05208d98b19
--- /dev/null
+++ b/chromium/components/previews/core/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+components/variations",
+ "+components/data_reduction_proxy/core/common",
+ "+net",
+]
diff --git a/chromium/components/previews/core/previews_black_list.cc b/chromium/components/previews/core/previews_black_list.cc
new file mode 100644
index 00000000000..b391e04e571
--- /dev/null
+++ b/chromium/components/previews/core/previews_black_list.cc
@@ -0,0 +1,182 @@
+// 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 "components/previews/core/previews_black_list.h"
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+#include "components/previews/core/previews_black_list_item.h"
+#include "components/previews/core/previews_experiments.h"
+#include "url/gurl.h"
+
+namespace previews {
+
+PreviewsBlackList::PreviewsBlackList(
+ std::unique_ptr<PreviewsOptOutStore> opt_out_store,
+ std::unique_ptr<base::Clock> clock)
+ : loaded_(false),
+ opt_out_store_(std::move(opt_out_store)),
+ clock_(std::move(clock)),
+ weak_factory_(this) {
+ if (opt_out_store_) {
+ opt_out_store_->LoadBlackList(base::Bind(
+ &PreviewsBlackList::LoadBlackListDone, weak_factory_.GetWeakPtr()));
+ } else {
+ LoadBlackListDone(base::MakeUnique<BlackListItemMap>());
+ }
+}
+
+PreviewsBlackList::~PreviewsBlackList() {}
+
+void PreviewsBlackList::AddPreviewNavigation(const GURL& url,
+ bool opt_out,
+ PreviewsType type) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(url.has_host());
+ // If the |black_list_item_map_| has been loaded from |opt_out_store_|,
+ // synchronous operations will be accurate. Otherwise, queue the task to run
+ // asynchronously.
+ if (loaded_) {
+ AddPreviewNavigationSync(url, opt_out, type);
+ } else {
+ QueuePendingTask(base::Bind(&PreviewsBlackList::AddPreviewNavigationSync,
+ base::Unretained(this), url, opt_out, type));
+ }
+}
+
+void PreviewsBlackList::AddPreviewNavigationSync(const GURL& url,
+ bool opt_out,
+ PreviewsType type) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(url.has_host());
+ DCHECK(loaded_);
+ std::string host_name = url.host();
+ base::Time now = clock_->Now();
+ PreviewsBlackListItem* item = GetBlackListItem(host_name);
+ if (!item) {
+ item = CreateBlackListItem(host_name);
+ }
+ item->AddPreviewNavigation(opt_out, now);
+ DCHECK_LE(black_list_item_map_->size(),
+ params::MaxInMemoryHostsInBlackList());
+ if (!opt_out_store_)
+ return;
+ opt_out_store_->AddPreviewNavigation(opt_out, host_name, type, now);
+}
+
+bool PreviewsBlackList::IsLoadedAndAllowed(const GURL& url,
+ PreviewsType type) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(url.has_host());
+ if (!loaded_)
+ return false;
+ PreviewsBlackListItem* black_list_item = GetBlackListItem(url.host());
+ return !black_list_item || !black_list_item->IsBlackListed(clock_->Now());
+}
+
+void PreviewsBlackList::ClearBlackList(base::Time begin_time,
+ base::Time end_time) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_LE(begin_time, end_time);
+ // If the |black_list_item_map_| has been loaded from |opt_out_store_|,
+ // synchronous operations will be accurate. Otherwise, queue the task to run
+ // asynchronously.
+ if (loaded_) {
+ ClearBlackListSync(begin_time, end_time);
+ } else {
+ QueuePendingTask(base::Bind(&PreviewsBlackList::ClearBlackListSync,
+ base::Unretained(this), begin_time, end_time));
+ }
+}
+
+void PreviewsBlackList::ClearBlackListSync(base::Time begin_time,
+ base::Time end_time) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(loaded_);
+ DCHECK_LE(begin_time, end_time);
+ black_list_item_map_.reset(nullptr);
+ loaded_ = false;
+ // Delete relevant entries and reload the blacklist into memory.
+ if (opt_out_store_) {
+ opt_out_store_->ClearBlackList(begin_time, end_time);
+ opt_out_store_->LoadBlackList(base::Bind(
+ &PreviewsBlackList::LoadBlackListDone, weak_factory_.GetWeakPtr()));
+ } else {
+ LoadBlackListDone(base::MakeUnique<BlackListItemMap>());
+ }
+}
+
+void PreviewsBlackList::QueuePendingTask(base::Closure callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!loaded_);
+ DCHECK(!callback.is_null());
+ pending_callbacks_.emplace(callback);
+}
+
+void PreviewsBlackList::LoadBlackListDone(
+ std::unique_ptr<BlackListItemMap> black_list_item_map) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_LE(black_list_item_map->size(), params::MaxInMemoryHostsInBlackList());
+ loaded_ = true;
+ black_list_item_map_ = std::move(black_list_item_map);
+
+ // Run all pending tasks. |loaded_| may change if ClearBlackList is queued.
+ while (pending_callbacks_.size() > 0 && loaded_) {
+ pending_callbacks_.front().Run();
+ pending_callbacks_.pop();
+ }
+}
+
+PreviewsBlackListItem* PreviewsBlackList::GetBlackListItem(
+ const std::string& host_name) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(loaded_);
+ BlackListItemMap::iterator iter = black_list_item_map_->find(host_name);
+ if (iter != black_list_item_map_->end())
+ return iter->second.get();
+ return nullptr;
+}
+
+PreviewsBlackListItem* PreviewsBlackList::CreateBlackListItem(
+ const std::string& host_name) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(loaded_);
+ DCHECK(!GetBlackListItem(host_name));
+ if (black_list_item_map_->size() >= params::MaxInMemoryHostsInBlackList())
+ EvictOldestOptOut();
+ DCHECK_LT(black_list_item_map_->size(),
+ params::MaxInMemoryHostsInBlackList());
+ PreviewsBlackListItem* black_list_item = new PreviewsBlackListItem(
+ params::MaxStoredHistoryLengthForBlackList(),
+ params::BlackListOptOutThreshold(), params::BlackListDuration());
+ black_list_item_map_->operator[](host_name) =
+ base::WrapUnique(black_list_item);
+ return black_list_item;
+}
+
+void PreviewsBlackList::EvictOldestOptOut() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(loaded_);
+ // TODO(ryansturm): Add UMA. crbug.com/647717
+ BlackListItemMap::iterator item_to_delete = black_list_item_map_->end();
+ base::Time oldest_opt_out = clock_->Now();
+ for (BlackListItemMap::iterator iter = black_list_item_map_->begin();
+ iter != black_list_item_map_->end(); ++iter) {
+ if (!iter->second->most_recent_opt_out_time()) {
+ // If there is no opt out time, this is a good choice to evict.
+ item_to_delete = iter;
+ break;
+ }
+ if (iter->second->most_recent_opt_out_time().value() < oldest_opt_out) {
+ oldest_opt_out = iter->second->most_recent_opt_out_time().value();
+ item_to_delete = iter;
+ }
+ }
+ black_list_item_map_->erase(item_to_delete);
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_black_list.h b/chromium/components/previews/core/previews_black_list.h
new file mode 100644
index 00000000000..e7e9c66a8ba
--- /dev/null
+++ b/chromium/components/previews/core/previews_black_list.h
@@ -0,0 +1,124 @@
+// 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 COMPONENTS_PREVIEWS_CORE_PREVIEWS_BLACK_LIST_H_
+#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_BLACK_LIST_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "components/previews/core/previews_opt_out_store.h"
+
+class GURL;
+
+namespace base {
+class Clock;
+}
+
+namespace previews {
+class PreviewsBlackListItem;
+
+// Manages the state of black listed domains for the previews experiment. Loads
+// the stored black list from |opt_out_store| and manages an in memory black
+// list on the IO thread. Updates to the black list are stored in memory and
+// pushed to the store. Asynchronous modifications are stored in a queue and
+// executed in order. Reading from the black list is always synchronous, and if
+// the black list is not currently loaded (e.g., at startup, after clearing
+// browsing history), domains are reported as black listed. The list stores no
+// more than previews::params::MaxInMemoryHostsInBlackList hosts in-memory,
+// which defaults to 100.
+class PreviewsBlackList {
+ public:
+ // |opt_out_store| is the backing store to retrieve and store black list
+ // information, and can be null. When |opt_out_store| is null, the in-memory
+ // map will be immediately loaded to empty. If |opt_out_store| is non-null,
+ // it will be used to load the in-memory map asynchronously.
+ PreviewsBlackList(std::unique_ptr<PreviewsOptOutStore> opt_out_store,
+ std::unique_ptr<base::Clock> clock);
+ ~PreviewsBlackList();
+
+ // Asynchronously adds a new navigation to to the in-memory black list and
+ // backing store. |opt_out| is whether the user opted out of the preview or
+ // navigated away from the page without opting out. |type| is only passed to
+ // the backing store. If the in memory map has reached the max number of hosts
+ // allowed, and |url| is a new host, a host will be evicted based on recency
+ // of the hosts most recent opt out.
+ void AddPreviewNavigation(const GURL& url, bool opt_out, PreviewsType type);
+
+ // Synchronously determines if |host_name| should be allowed to show previews.
+ // If the black list has loaded yet, this will always return false. |type| is
+ // not used to make this decision.
+ bool IsLoadedAndAllowed(const GURL& url, PreviewsType type) const;
+
+ // Asynchronously deletes all entries in the in-memory black list. Informs
+ // the backing store to delete entries between |begin_time| and |end_time|,
+ // and reloads entries into memory from the backing store. If the embedder
+ // passed in a null store, resets all history in the in-memory black list.
+ void ClearBlackList(base::Time begin_time, base::Time end_time);
+
+ private:
+ // Synchronous version of AddPreviewNavigation method.
+ void AddPreviewNavigationSync(const GURL& host_name,
+ bool opt_out,
+ PreviewsType type);
+
+ // Returns the PreviewsBlackListItem representing |host_name|. If there is no
+ // item for |host_name|, returns null.
+ PreviewsBlackListItem* GetBlackListItem(const std::string& host_name) const;
+
+ // Synchronous version of ClearBlackList method.
+ void ClearBlackListSync(base::Time begin_time, base::Time end_time);
+
+ // Returns a new PreviewsBlackListItem representing |host_name|. Adds the new
+ // item to the in-memory map.
+ PreviewsBlackListItem* CreateBlackListItem(const std::string& host_name);
+
+ // Callback passed to the backing store when loading black list information.
+ // Moves the returned map into the in-memory black list and runs any
+ // outstanding tasks.
+ void LoadBlackListDone(std::unique_ptr<BlackListItemMap> black_list_item_map);
+
+ // Called while waiting for the black list to be loaded from the backing
+ // store.
+ // Enqueues a task to run when when loading black list information has
+ // completed. Maintains the order that tasks were called in.
+ void QueuePendingTask(base::Closure callback);
+
+ // Evicts one entry from the in-memory black list based on recency of a hosts
+ // most recent opt out time.
+ void EvictOldestOptOut();
+
+ // Map maintaining the in-memory black list.
+ std::unique_ptr<BlackListItemMap> black_list_item_map_;
+
+ // Whether the black list is done being loaded from the backing store.
+ bool loaded_;
+
+ // The backing store of the black list information.
+ std::unique_ptr<PreviewsOptOutStore> opt_out_store_;
+
+ // Callbacks to be run after loading information from the backing store has
+ // completed.
+ std::queue<base::Closure> pending_callbacks_;
+
+ std::unique_ptr<base::Clock> clock_;
+
+ base::ThreadChecker thread_checker_;
+
+ base::WeakPtrFactory<PreviewsBlackList> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreviewsBlackList);
+};
+
+} // namespace previews
+
+#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_BLACK_LIST_H_
diff --git a/chromium/components/previews/core/previews_black_list_item.cc b/chromium/components/previews/core/previews_black_list_item.cc
new file mode 100644
index 00000000000..9fd3286772c
--- /dev/null
+++ b/chromium/components/previews/core/previews_black_list_item.cc
@@ -0,0 +1,60 @@
+// 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 "components/previews/core/previews_black_list_item.h"
+
+#include <algorithm>
+
+#include "components/previews/core/previews_opt_out_store.h"
+
+namespace previews {
+
+PreviewsBlackListItem::OptOutRecord::OptOutRecord(base::Time entry_time,
+ bool opt_out)
+ : entry_time(entry_time), opt_out(opt_out) {}
+
+PreviewsBlackListItem::PreviewsBlackListItem(
+ size_t stored_history_length,
+ int opt_out_black_list_threshold,
+ base::TimeDelta black_list_duration)
+ : max_stored_history_length_(stored_history_length),
+ opt_out_black_list_threshold_(opt_out_black_list_threshold),
+ max_black_list_duration_(black_list_duration),
+ total_opt_out_(0) {}
+
+PreviewsBlackListItem::~PreviewsBlackListItem() {}
+
+void PreviewsBlackListItem::AddPreviewNavigation(bool opt_out,
+ base::Time entry_time) {
+ DCHECK_LE(opt_out_records_.size(), max_stored_history_length_);
+ if (opt_out && (!most_recent_opt_out_time_ ||
+ entry_time > most_recent_opt_out_time_.value())) {
+ most_recent_opt_out_time_ = entry_time;
+ }
+ total_opt_out_ += opt_out ? 1 : 0;
+
+ // Find insert postion to keep the list sorted. Typically, this will be at the
+ // end of the list, but for systems with clocks that are not non-decreasing
+ // with time, this may not be the end. Linearly search from end to begin.
+ auto iter = opt_out_records_.rbegin();
+ while (iter != opt_out_records_.rend() && iter->entry_time > entry_time)
+ iter++;
+ opt_out_records_.emplace(iter.base(), entry_time, opt_out);
+
+ // Remove the oldest entry if the size exceeds the history size.
+ if (opt_out_records_.size() > max_stored_history_length_) {
+ total_opt_out_ -= opt_out_records_.front().opt_out ? 1 : 0;
+ opt_out_records_.pop_front();
+ }
+ DCHECK_LE(opt_out_records_.size(), max_stored_history_length_);
+}
+
+bool PreviewsBlackListItem::IsBlackListed(base::Time now) const {
+ DCHECK_LE(opt_out_records_.size(), max_stored_history_length_);
+ return most_recent_opt_out_time_ &&
+ now - most_recent_opt_out_time_.value() < max_black_list_duration_ &&
+ total_opt_out_ >= opt_out_black_list_threshold_;
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_black_list_item.h b/chromium/components/previews/core/previews_black_list_item.h
new file mode 100644
index 00000000000..462e61d1c4a
--- /dev/null
+++ b/chromium/components/previews/core/previews_black_list_item.h
@@ -0,0 +1,80 @@
+// 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 COMPONENTS_PREVIEWS_CORE_PREVIEWS_BLACK_LIST_ITEM_H_
+#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_BLACK_LIST_ITEM_H_
+
+#include <stdint.h>
+
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/time/time.h"
+
+namespace previews {
+
+// Stores the recent black list history for a single host. Stores
+// |stored_history_length| of the most recent previews navigations. To determine
+// previews eligiblity fewer than |opt_out_black_list_threshold| out of the past
+// |stored_history_length| navigations must be opt outs. |black_list_duration|
+// is the amount of time that elapses until the host is no longer on the black
+// list.
+class PreviewsBlackListItem {
+ public:
+ PreviewsBlackListItem(size_t stored_history_length,
+ int opt_out_black_list_threshold,
+ base::TimeDelta black_list_duration);
+
+ ~PreviewsBlackListItem();
+
+ // Adds a new navigation at the specified |entry_time|.
+ void AddPreviewNavigation(bool opt_out, base::Time entry_time);
+
+ // Whether the host name corresponding to |this| should be disallowed from
+ // showing previews.
+ bool IsBlackListed(base::Time now) const;
+
+ base::Optional<base::Time> most_recent_opt_out_time() const {
+ return most_recent_opt_out_time_;
+ }
+
+ private:
+ // A previews navigation to this host is represented by time and whether the
+ // navigation was an opt out.
+ struct OptOutRecord {
+ OptOutRecord(base::Time entry_time, bool opt_out);
+ ~OptOutRecord() {}
+ const base::Time
+ entry_time; // The time that the opt out state was determined.
+ const bool opt_out; // Whether the user opt out of the preview.
+ };
+
+ // The number of entries to store to determine preview eligibility.
+ const size_t max_stored_history_length_;
+ // The number opt outs in recent history that will trigger blacklisting.
+ const int opt_out_black_list_threshold_;
+ // The amount of time to black list a domain after the most recent opt out.
+ const base::TimeDelta max_black_list_duration_;
+
+ // The |max_stored_history_length_| most recent previews navigation. Is
+ // maintained as a list sorted by entry_time (earliest to latest).
+ std::list<OptOutRecord> opt_out_records_;
+
+ // Time of the most recent opt out.
+ base::Optional<base::Time> most_recent_opt_out_time_;
+
+ // The total number of opt outs currently in |opt_out_records_|.
+ int total_opt_out_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreviewsBlackListItem);
+};
+
+} // namespace previews
+
+#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_BLACK_LIST_ITEM_H_
diff --git a/chromium/components/previews/core/previews_black_list_item_unittest.cc b/chromium/components/previews/core/previews_black_list_item_unittest.cc
new file mode 100644
index 00000000000..fb9be62b4e6
--- /dev/null
+++ b/chromium/components/previews/core/previews_black_list_item_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/previews/core/previews_black_list_item.h"
+
+#include <memory>
+
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using PreviewsBlackListItemTest = testing::Test;
+
+} // namespace
+
+namespace previews {
+
+TEST_F(PreviewsBlackListItemTest, BlackListState) {
+ const int history = 4;
+ const int threshold = 2;
+ const base::TimeDelta max_blacklist_duration =
+ base::TimeDelta::FromSeconds(30);
+ const base::Time now = base::Time::UnixEpoch();
+ const base::TimeDelta delay_between_entries = base::TimeDelta::FromSeconds(1);
+ const base::Time later =
+ now + max_blacklist_duration + (delay_between_entries * 3);
+
+ PreviewsBlackListItem black_list_item(history, threshold,
+ max_blacklist_duration);
+
+ // Empty black list item should report that the host is allowed.
+ EXPECT_FALSE(black_list_item.IsBlackListed(now));
+ EXPECT_FALSE(black_list_item.IsBlackListed(later));
+
+ EXPECT_FALSE(black_list_item.most_recent_opt_out_time());
+ black_list_item.AddPreviewNavigation(false, now);
+ EXPECT_FALSE(black_list_item.most_recent_opt_out_time());
+
+ black_list_item.AddPreviewNavigation(true, now);
+ EXPECT_TRUE(black_list_item.most_recent_opt_out_time());
+ EXPECT_EQ(now, black_list_item.most_recent_opt_out_time().value());
+ // Black list item of size less that |threshold| should report that the host
+ // is allowed.
+ EXPECT_FALSE(black_list_item.IsBlackListed(now));
+ EXPECT_FALSE(black_list_item.IsBlackListed(later));
+
+ black_list_item.AddPreviewNavigation(true, now + delay_between_entries);
+ // Black list item with |threshold| fresh entries should report the host as
+ // disallowed.
+ EXPECT_TRUE(black_list_item.IsBlackListed(now));
+ // Black list item with only entries from longer than |duration| ago should
+ // report the host is allowed.
+ EXPECT_FALSE(black_list_item.IsBlackListed(later));
+ black_list_item.AddPreviewNavigation(true,
+ later - (delay_between_entries * 2));
+ // Black list item with a fresh opt out and total number of opt outs larger
+ // than |threshold| should report the host is disallowed.
+ EXPECT_TRUE(black_list_item.IsBlackListed(later));
+
+ // The black list item should maintain entries based on time, so adding
+ // |history| entries should not push out newer entries.
+ black_list_item.AddPreviewNavigation(true, later - delay_between_entries * 2);
+ black_list_item.AddPreviewNavigation(false,
+ later - delay_between_entries * 3);
+ black_list_item.AddPreviewNavigation(false,
+ later - delay_between_entries * 3);
+ black_list_item.AddPreviewNavigation(false,
+ later - delay_between_entries * 3);
+ black_list_item.AddPreviewNavigation(false,
+ later - delay_between_entries * 3);
+ EXPECT_TRUE(black_list_item.IsBlackListed(later));
+
+ // The black list item should maintain entries based on time, so adding
+ // |history| newer entries should push out older entries.
+ black_list_item.AddPreviewNavigation(false,
+ later - delay_between_entries * 1);
+ black_list_item.AddPreviewNavigation(false,
+ later - delay_between_entries * 1);
+ black_list_item.AddPreviewNavigation(false,
+ later - delay_between_entries * 1);
+ black_list_item.AddPreviewNavigation(false,
+ later - delay_between_entries * 1);
+ EXPECT_FALSE(black_list_item.IsBlackListed(later));
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_black_list_unittest.cc b/chromium/components/previews/core/previews_black_list_unittest.cc
new file mode 100644
index 00000000000..6f98c122b01
--- /dev/null
+++ b/chromium/components/previews/core/previews_black_list_unittest.cc
@@ -0,0 +1,318 @@
+// 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 "components/previews/core/previews_black_list.h"
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/simple_test_clock.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/previews/core/previews_black_list_item.h"
+#include "components/previews/core/previews_experiments.h"
+#include "components/previews/core/previews_opt_out_store.h"
+#include "components/variations/variations_associated_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+
+using PreviewsBlackListTest = testing::Test;
+
+} // namespace
+
+namespace previews {
+
+namespace {
+
+void RunLoadCallback(LoadBlackListCallback callback,
+ std::unique_ptr<BlackListItemMap> black_list_item_map) {
+ callback.Run(std::move(black_list_item_map));
+}
+
+class TestPreviewsOptOutStore : public PreviewsOptOutStore {
+ public:
+ TestPreviewsOptOutStore() : clear_blacklist_count_(0) {}
+ ~TestPreviewsOptOutStore() override {}
+
+ int clear_blacklist_count() { return clear_blacklist_count_; }
+
+ private:
+ // PreviewsOptOutStore implementation:
+ void AddPreviewNavigation(bool opt_out,
+ const std::string& host_name,
+ PreviewsType type,
+ base::Time now) override {}
+
+ void LoadBlackList(LoadBlackListCallback callback) override {
+ std::unique_ptr<BlackListItemMap> black_list_item_map(
+ new BlackListItemMap());
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&RunLoadCallback, callback,
+ base::Passed(&black_list_item_map)));
+ }
+
+ void ClearBlackList(base::Time begin_time, base::Time end_time) override {
+ ++clear_blacklist_count_;
+ }
+
+ int clear_blacklist_count_;
+};
+
+} // namespace
+
+TEST_F(PreviewsBlackListTest, BlackListNoStore) {
+ // Tests the black list behavior when a null OptOutSture is passed in.
+ const GURL url_a("http://www.url_a.com");
+ const GURL url_b("http://www.url_b.com");
+ const size_t history = 4;
+ const int threshold = 2;
+ const int duration_in_days = 365;
+ base::FieldTrialList field_trial_list(nullptr);
+ std::map<std::string, std::string> params;
+ params["stored_history_length"] = base::SizeTToString(history);
+ params["opt_out_threshold"] = base::IntToString(threshold);
+ params["black_list_duration_in_days"] = base::IntToString(duration_in_days);
+ ASSERT_TRUE(
+ variations::AssociateVariationParams("ClientSidePreviews", "Enabled",
+ params) &&
+ base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
+
+ base::SimpleTestClock* test_clock = new base::SimpleTestClock();
+ base::Time start = test_clock->Now();
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+
+ std::unique_ptr<PreviewsBlackList> black_list(
+ new PreviewsBlackList(nullptr, base::WrapUnique(test_clock)));
+
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_a, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ black_list->AddPreviewNavigation(url_a, true, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url_a, true, PreviewsType::OFFLINE);
+
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ black_list->AddPreviewNavigation(url_b, true, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url_b, true, PreviewsType::OFFLINE);
+
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ black_list->AddPreviewNavigation(url_b, false, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url_b, false, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url_b, false, PreviewsType::OFFLINE);
+
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+ black_list->ClearBlackList(start, test_clock->Now());
+
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_a, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ variations::testing::ClearAllVariationParams();
+}
+
+TEST_F(PreviewsBlackListTest, BlackListWithStore) {
+ // Tests the black list behavior when a non-null OptOutSture is passed in.
+ const GURL url_a1("http://www.url_a.com/a1");
+ const GURL url_a2("http://www.url_a.com/a2");
+ const GURL url_b("http://www.url_b.com");
+ const size_t history = 4;
+ const int threshold = 2;
+ const int duration_in_days = 365;
+ base::FieldTrialList field_trial_list(nullptr);
+ std::map<std::string, std::string> params;
+ params["stored_history_length"] = base::SizeTToString(history);
+ params["opt_out_threshold"] = base::IntToString(threshold);
+ params["black_list_duration_in_days"] = base::IntToString(duration_in_days);
+ ASSERT_TRUE(
+ variations::AssociateVariationParams("ClientSidePreviews", "Enabled",
+ params) &&
+ base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
+
+ base::MessageLoop loop;
+
+ base::SimpleTestClock* test_clock = new base::SimpleTestClock();
+ base::Time start = test_clock->Now();
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+
+ TestPreviewsOptOutStore* opt_out_store = new TestPreviewsOptOutStore();
+
+ std::unique_ptr<PreviewsBlackList> black_list(new PreviewsBlackList(
+ base::WrapUnique(opt_out_store), base::WrapUnique(test_clock)));
+
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a1, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a2, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_a1, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_a2, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ black_list->AddPreviewNavigation(url_a1, true, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url_a1, true, PreviewsType::OFFLINE);
+
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a1, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a2, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ black_list->AddPreviewNavigation(url_b, true, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url_b, true, PreviewsType::OFFLINE);
+
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a1, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a2, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ black_list->AddPreviewNavigation(url_b, false, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url_b, false, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url_b, false, PreviewsType::OFFLINE);
+
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a1, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a2, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(0, opt_out_store->clear_blacklist_count());
+ black_list->ClearBlackList(start, base::Time::Now());
+ EXPECT_EQ(1, opt_out_store->clear_blacklist_count());
+
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a1, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a2, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, opt_out_store->clear_blacklist_count());
+
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_a1, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_a1, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+
+ variations::testing::ClearAllVariationParams();
+}
+
+TEST_F(PreviewsBlackListTest, QueueBehavior) {
+ // Tests the black list asynchronous queue behavior. Methods called while
+ // loading are queued and should run in the order they were queued.
+ const GURL url("http://www.url.com");
+ const GURL url2("http://www.url2.com");
+ const int duration_in_days = 365;
+ base::FieldTrialList field_trial_list(nullptr);
+ std::map<std::string, std::string> params;
+ params["black_list_duration_in_days"] = base::IntToString(duration_in_days);
+ ASSERT_TRUE(
+ variations::AssociateVariationParams("ClientSidePreviews", "Enabled",
+ params) &&
+ base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
+
+ base::MessageLoop loop;
+
+ std::vector<bool> test_opt_out{true, false};
+
+ for (auto opt_out : test_opt_out) {
+ base::SimpleTestClock* test_clock = new base::SimpleTestClock();
+
+ TestPreviewsOptOutStore* opt_out_store = new TestPreviewsOptOutStore();
+
+ std::unique_ptr<PreviewsBlackList> black_list(new PreviewsBlackList(
+ base::WrapUnique(opt_out_store), base::WrapUnique(test_clock)));
+
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url, PreviewsType::OFFLINE));
+ black_list->AddPreviewNavigation(url, opt_out, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url, opt_out, PreviewsType::OFFLINE);
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url, PreviewsType::OFFLINE));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(!opt_out,
+ black_list->IsLoadedAndAllowed(url, PreviewsType::OFFLINE));
+
+ base::Time start = test_clock->Now();
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+ black_list->AddPreviewNavigation(url, opt_out, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url, opt_out, PreviewsType::OFFLINE);
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(0, opt_out_store->clear_blacklist_count());
+ black_list->ClearBlackList(
+ start, test_clock->Now() + base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(1, opt_out_store->clear_blacklist_count());
+ black_list->AddPreviewNavigation(url2, opt_out, PreviewsType::OFFLINE);
+ black_list->AddPreviewNavigation(url2, opt_out, PreviewsType::OFFLINE);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, opt_out_store->clear_blacklist_count());
+
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url, PreviewsType::OFFLINE));
+ EXPECT_EQ(!opt_out,
+ black_list->IsLoadedAndAllowed(url2, PreviewsType::OFFLINE));
+ }
+
+ variations::testing::ClearAllVariationParams();
+}
+
+TEST_F(PreviewsBlackListTest, MaxHosts) {
+ // Test that the black list only stores n hosts, and it stores the correct n
+ // hosts.
+ const GURL url_a("http://www.url_a.com");
+ const GURL url_b("http://www.url_b.com");
+ const GURL url_c("http://www.url_c.com");
+ const GURL url_d("http://www.url_d.com");
+ const GURL url_e("http://www.url_e.com");
+ const size_t stored_history_length = 1;
+ const int opt_out_threshold = 1;
+ const int black_list_duration_in_days = 365;
+ const size_t max_hosts_in_blacklist = 2;
+ base::FieldTrialList field_trial_list(nullptr);
+ std::map<std::string, std::string> params;
+ params["stored_history_length"] = base::SizeTToString(stored_history_length);
+ params["opt_out_threshold"] = base::IntToString(opt_out_threshold);
+ params["black_list_duration_in_days"] =
+ base::IntToString(black_list_duration_in_days);
+ params["max_hosts_in_blacklist"] =
+ base::SizeTToString(max_hosts_in_blacklist);
+ ASSERT_TRUE(
+ variations::AssociateVariationParams("ClientSidePreviews", "Enabled",
+ params) &&
+ base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
+
+ base::MessageLoop loop;
+
+ base::SimpleTestClock* test_clock = new base::SimpleTestClock();
+
+ std::unique_ptr<PreviewsBlackList> black_list(
+ new PreviewsBlackList(nullptr, base::WrapUnique(test_clock)));
+
+ black_list->AddPreviewNavigation(url_a, true, PreviewsType::OFFLINE);
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+ black_list->AddPreviewNavigation(url_b, false, PreviewsType::OFFLINE);
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+ black_list->AddPreviewNavigation(url_c, false, PreviewsType::OFFLINE);
+ // url_a should stay in the map, since it has an opt out time.
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_a, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_b, PreviewsType::OFFLINE));
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_c, PreviewsType::OFFLINE));
+
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+ black_list->AddPreviewNavigation(url_d, true, PreviewsType::OFFLINE);
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+ black_list->AddPreviewNavigation(url_e, true, PreviewsType::OFFLINE);
+ // url_d and url_e should remain in the map, but url_a should be evicted.
+ EXPECT_TRUE(black_list->IsLoadedAndAllowed(url_a, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_d, PreviewsType::OFFLINE));
+ EXPECT_FALSE(black_list->IsLoadedAndAllowed(url_e, PreviewsType::OFFLINE));
+
+ variations::testing::ClearAllVariationParams();
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_data_savings.cc b/chromium/components/previews/core/previews_data_savings.cc
new file mode 100644
index 00000000000..267f44b12c7
--- /dev/null
+++ b/chromium/components/previews/core/previews_data_savings.cc
@@ -0,0 +1,71 @@
+// 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 "components/previews/core/previews_data_savings.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "components/data_reduction_proxy/core/common/data_savings_recorder.h"
+
+namespace previews {
+
+PreviewsDataSavings::PreviewsDataSavings(
+ data_reduction_proxy::DataSavingsRecorder* data_savings_recorder)
+ : data_savings_recorder_(data_savings_recorder) {
+ DCHECK(data_savings_recorder);
+}
+
+PreviewsDataSavings::~PreviewsDataSavings() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void PreviewsDataSavings::RecordDataSavings(
+ const std::string& fully_qualified_domain_name,
+ int64_t data_used,
+ int64_t original_size) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Only record savings when data saver is enabled.
+ if (!data_savings_recorder_->UpdateDataSavings(fully_qualified_domain_name,
+ data_used, original_size)) {
+ // Record metrics in KB for previews with data saver disabled.
+ UMA_HISTOGRAM_COUNTS("Previews.OriginalContentLength.DataSaverDisabled",
+ original_size >> 10);
+ UMA_HISTOGRAM_COUNTS("Previews.ContentLength.DataSaverDisabled",
+ data_used >> 10);
+ if (original_size >= data_used) {
+ UMA_HISTOGRAM_COUNTS("Previews.DataSavings.DataSaverDisabled",
+ (original_size - data_used) >> 10);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Previews.DataSavingsPercent.DataSaverDisabled",
+ (original_size - data_used) * 100 / original_size);
+ } else {
+ UMA_HISTOGRAM_COUNTS("Previews.DataInflation.DataSaverDisabled",
+ (data_used - original_size) >> 10);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Previews.DataInflationPercent.DataSaverDisabled",
+ (data_used - original_size) * 100 / data_used);
+ }
+ return;
+ }
+
+ // Record metrics in KB for previews with data saver enabled.
+ UMA_HISTOGRAM_COUNTS("Previews.OriginalContentLength.DataSaverEnabled",
+ original_size >> 10);
+ UMA_HISTOGRAM_COUNTS("Previews.ContentLength.DataSaverEnabled",
+ data_used >> 10);
+ if (original_size >= data_used) {
+ UMA_HISTOGRAM_COUNTS("Previews.DataSavings.DataSaverEnabled",
+ (original_size - data_used) >> 10);
+ UMA_HISTOGRAM_PERCENTAGE("Previews.DataSavingsPercent.DataSaverEnabled",
+ (original_size - data_used) * 100 / original_size);
+ } else {
+ UMA_HISTOGRAM_COUNTS("Previews.DataInflation.DataSaverEnabled",
+ (data_used - original_size) >> 10);
+ UMA_HISTOGRAM_PERCENTAGE("Previews.DataInflationPercent.DataSaverEnabled",
+ (data_used - original_size) * 100 / data_used);
+ }
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_data_savings.h b/chromium/components/previews/core/previews_data_savings.h
new file mode 100644
index 00000000000..ce37cf168e9
--- /dev/null
+++ b/chromium/components/previews/core/previews_data_savings.h
@@ -0,0 +1,51 @@
+// 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 COMPONENTS_PREVIEWS_CORE_PREVIEWS_DATA_SAVINGS_H_
+#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_DATA_SAVINGS_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+
+namespace data_reduction_proxy {
+class DataSavingsRecorder;
+}
+
+namespace previews {
+
+// Provides an interface for previews to report data savings.
+class PreviewsDataSavings {
+ public:
+ // Embedder must guarantee that |data_savings_recorder| and
+ // |data_reduction_proxy_settings| outlive this instance.
+ PreviewsDataSavings(
+ data_reduction_proxy::DataSavingsRecorder* data_savings_recorder);
+ ~PreviewsDataSavings();
+
+ // Records the amount of data used by the preview, and the amount of data
+ // that would have been used if the original page had been loaded instead of
+ // the preview. |fully_qualified_domain_name| is the full host name to
+ // attribute the data savings to (e.g., codereview.chromium.org).
+ void RecordDataSavings(const std::string& fully_qualified_domain_name,
+ int64_t data_used,
+ int64_t original_size);
+
+ private:
+ // Owned by the embedder, must be valid for the lifetime of |this|.
+ // Provides a method to record data savings.
+ data_reduction_proxy::DataSavingsRecorder* data_savings_recorder_;
+
+ // Enforce usage on the UI thread.
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreviewsDataSavings);
+};
+
+} // namespace previews
+
+#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_DATA_SAVINGS_H_
diff --git a/chromium/components/previews/core/previews_data_savings_unittest.cc b/chromium/components/previews/core/previews_data_savings_unittest.cc
new file mode 100644
index 00000000000..bd749248547
--- /dev/null
+++ b/chromium/components/previews/core/previews_data_savings_unittest.cc
@@ -0,0 +1,166 @@
+// 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 "components/previews/core/previews_data_savings.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/test/histogram_tester.h"
+#include "components/data_reduction_proxy/core/common/data_savings_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace previews {
+
+namespace {
+
+class TestDataSavingsRecorder
+ : public data_reduction_proxy::DataSavingsRecorder {
+ public:
+ TestDataSavingsRecorder()
+ : data_saver_enabled_(false), data_used_(0), original_size_(0) {}
+ ~TestDataSavingsRecorder() {}
+
+ // data_reduction_proxy::DataSavingsRecorder implementation:
+ bool UpdateDataSavings(const std::string& host,
+ int64_t data_used,
+ int64_t original_size) override {
+ if (!data_saver_enabled_) {
+ return false;
+ }
+ last_host_ = host;
+ data_used_ += data_used;
+ original_size_ += original_size;
+ return true;
+ }
+
+ void set_data_saver_enabled(bool data_saver_enabled) {
+ data_saver_enabled_ = data_saver_enabled;
+ }
+
+ std::string last_host() const { return last_host_; }
+
+ int64_t data_used() const { return data_used_; }
+
+ int64_t original_size() const { return original_size_; }
+
+ private:
+ bool data_saver_enabled_;
+ std::string last_host_;
+ int64_t data_used_;
+ int64_t original_size_;
+};
+
+} // namespace
+
+class PreviewsDataSavingsTest : public testing::Test {
+ public:
+ PreviewsDataSavingsTest()
+ : test_data_savings_recorder_(new TestDataSavingsRecorder()),
+ data_savings_(
+ new PreviewsDataSavings(test_data_savings_recorder_.get())) {}
+ ~PreviewsDataSavingsTest() override {}
+
+ PreviewsDataSavings* data_savings() const { return data_savings_.get(); }
+
+ TestDataSavingsRecorder* test_data_savings_recorder() const {
+ return test_data_savings_recorder_.get();
+ }
+
+ base::HistogramTester* histogram_tester() { return &histogram_tester_; }
+
+ private:
+ base::HistogramTester histogram_tester_;
+
+ std::unique_ptr<TestDataSavingsRecorder> test_data_savings_recorder_;
+ std::unique_ptr<PreviewsDataSavings> data_savings_;
+};
+
+TEST_F(PreviewsDataSavingsTest, RecordDataSavings) {
+ int64_t original_size = 200;
+ int64_t data_used = 100;
+ std::string host = "host";
+
+ EXPECT_EQ(0, test_data_savings_recorder()->data_used());
+ EXPECT_EQ(0, test_data_savings_recorder()->original_size());
+ test_data_savings_recorder()->set_data_saver_enabled(false);
+ data_savings()->RecordDataSavings(host, data_used, original_size);
+
+ EXPECT_EQ(0, test_data_savings_recorder()->data_used());
+ EXPECT_EQ(0, test_data_savings_recorder()->original_size());
+ EXPECT_EQ(std::string(), test_data_savings_recorder()->last_host());
+
+ test_data_savings_recorder()->set_data_saver_enabled(true);
+ data_savings()->RecordDataSavings(host, data_used, original_size);
+
+ EXPECT_EQ(data_used, test_data_savings_recorder()->data_used());
+ EXPECT_EQ(original_size, test_data_savings_recorder()->original_size());
+ EXPECT_EQ(host, test_data_savings_recorder()->last_host());
+}
+
+TEST_F(PreviewsDataSavingsTest, RecordDataSavingsHistograms) {
+ int64_t twenty_kb = 20480;
+ int64_t twenty = twenty_kb >> 10;
+ int64_t ten_kb = 10240;
+ int64_t ten = ten_kb >> 10;
+ std::string host = "host";
+
+ test_data_savings_recorder()->set_data_saver_enabled(false);
+ data_savings()->RecordDataSavings(host, ten_kb, twenty_kb);
+
+ // The histograms record bytes in KB.
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.OriginalContentLength.DataSaverDisabled", twenty, 1);
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.ContentLength.DataSaverDisabled", ten, 1);
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.DataSavings.DataSaverDisabled", twenty - ten, 1);
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.DataSavingsPercent.DataSaverDisabled",
+ (twenty_kb - ten_kb) * 100 / twenty_kb, 1);
+
+ data_savings()->RecordDataSavings(host, twenty_kb, ten_kb);
+
+ // The histograms record bytes in KB.
+ histogram_tester()->ExpectBucketCount(
+ "Previews.OriginalContentLength.DataSaverDisabled", ten, 1);
+ histogram_tester()->ExpectBucketCount(
+ "Previews.ContentLength.DataSaverDisabled", twenty, 1);
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.DataInflation.DataSaverDisabled", twenty - ten, 1);
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.DataInflationPercent.DataSaverDisabled",
+ (twenty_kb - ten_kb) * 100 / twenty_kb, 1);
+
+ test_data_savings_recorder()->set_data_saver_enabled(true);
+ data_savings()->RecordDataSavings(host, ten_kb, twenty_kb);
+
+ // The histograms record bytes in KB.
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.OriginalContentLength.DataSaverEnabled", twenty, 1);
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.ContentLength.DataSaverEnabled", ten, 1);
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.DataSavings.DataSaverEnabled", twenty - ten, 1);
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.DataSavingsPercent.DataSaverEnabled",
+ (twenty_kb - ten_kb) * 100 / twenty_kb, 1);
+
+ data_savings()->RecordDataSavings(host, twenty_kb, ten_kb);
+
+ // The histograms record bytes in KB.
+ histogram_tester()->ExpectBucketCount(
+ "Previews.OriginalContentLength.DataSaverEnabled", ten, 1);
+ histogram_tester()->ExpectBucketCount(
+ "Previews.ContentLength.DataSaverEnabled", twenty, 1);
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.DataInflation.DataSaverEnabled", twenty - ten, 1);
+ histogram_tester()->ExpectUniqueSample(
+ "Previews.DataInflationPercent.DataSaverEnabled",
+ (twenty_kb - ten_kb) * 100 / twenty_kb, 1);
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_decider.h b/chromium/components/previews/core/previews_decider.h
new file mode 100644
index 00000000000..2df561611e9
--- /dev/null
+++ b/chromium/components/previews/core/previews_decider.h
@@ -0,0 +1,29 @@
+// 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 COMPONENTS_PREVIEWS_CORE_PREVIEWS_DECIDER_H_
+#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_DECIDER_H_
+
+#include "components/previews/core/previews_opt_out_store.h"
+
+namespace net {
+class URLRequest;
+}
+
+namespace previews {
+
+class PreviewsDecider {
+ public:
+ // Whether |request| is allowed to show a preview of |type|.
+ virtual bool ShouldAllowPreview(const net::URLRequest& request,
+ PreviewsType type) const = 0;
+
+ protected:
+ PreviewsDecider() {}
+ virtual ~PreviewsDecider() {}
+};
+
+} // namespace previews
+
+#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_DECIDER_H_
diff --git a/chromium/components/previews/core/previews_experiments.cc b/chromium/components/previews/core/previews_experiments.cc
new file mode 100644
index 00000000000..afd1fff87f1
--- /dev/null
+++ b/chromium/components/previews/core/previews_experiments.cc
@@ -0,0 +1,126 @@
+// 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 "components/previews/core/previews_experiments.h"
+
+#include <map>
+#include <string>
+
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "components/variations/variations_associated_data.h"
+
+namespace previews {
+
+namespace {
+
+// The group of client-side previews experiments.
+const char kClientSidePreviewsFieldTrial[] = "ClientSidePreviews";
+
+const char kEnabled[] = "Enabled";
+
+// Allow offline pages to show for prohibitively slow networks.
+const char kOfflinePagesSlowNetwork[] = "show_offline_pages";
+
+// The maximum number of recent previews navigations the black list looks at to
+// determine if a host is blacklisted.
+const char kMaxStoredHistoryLength[] = "stored_history_length";
+
+// The maximum number of hosts allowed in the in memory black list.
+const char kMaxHostsInBlackList[] = "max_hosts_in_blacklist";
+
+// The number of recent navigations that were opted out of that would trigger
+// the host to be blacklisted.
+const char kOptOutThreshold[] = "opt_out_threshold";
+
+// The amount of time a host remains blacklisted due to opt outs.
+const char kBlackListDurationInDays[] = "black_list_duration_in_days";
+
+// The string that corresponds to enabled for the variation param experiments.
+const char kExperimentEnabled[] = "true";
+
+// In seconds. Hosts are blacklisted for 30 days.
+constexpr int kDefaultBlackListDurationInDays = 30;
+
+// Returns the parameter value of |param| as a string. If there is no value for
+// |param|, returns an empty string.
+std::string ParamValue(const std::string& param) {
+ if (!IsIncludedInClientSidePreviewsExperimentsFieldTrial())
+ return std::string();
+ std::map<std::string, std::string> experiment_params;
+ if (!variations::GetVariationParams(kClientSidePreviewsFieldTrial,
+ &experiment_params)) {
+ return std::string();
+ }
+ std::map<std::string, std::string>::const_iterator it =
+ experiment_params.find(param);
+ return it == experiment_params.end() ? std::string() : it->second;
+}
+
+} // namespace
+
+namespace params {
+
+size_t MaxStoredHistoryLengthForBlackList() {
+ std::string param_value = ParamValue(kMaxStoredHistoryLength);
+ size_t history_length;
+ if (!base::StringToSizeT(param_value, &history_length)) {
+ return 4;
+ }
+ return history_length;
+}
+
+size_t MaxInMemoryHostsInBlackList() {
+ std::string param_value = ParamValue(kMaxHostsInBlackList);
+ size_t max_hosts;
+ if (!base::StringToSizeT(param_value, &max_hosts)) {
+ return 100;
+ }
+ return max_hosts;
+}
+
+int BlackListOptOutThreshold() {
+ std::string param_value = ParamValue(kOptOutThreshold);
+ int opt_out_threshold;
+ if (!base::StringToInt(param_value, &opt_out_threshold)) {
+ return 2;
+ }
+ return opt_out_threshold;
+}
+
+base::TimeDelta BlackListDuration() {
+ std::string param_value = ParamValue(kBlackListDurationInDays);
+ int duration;
+ if (!base::StringToInt(param_value, &duration)) {
+ return base::TimeDelta::FromDays(kDefaultBlackListDurationInDays);
+ }
+ return base::TimeDelta::FromDays(duration);
+}
+
+} // namespace params
+
+bool IsIncludedInClientSidePreviewsExperimentsFieldTrial() {
+ // By convention, an experiment in the client-side previews study enables use
+ // of at least one client-side previews optimization if its name begins with
+ // "Enabled."
+ return base::StartsWith(
+ base::FieldTrialList::FindFullName(kClientSidePreviewsFieldTrial),
+ kEnabled, base::CompareCase::SENSITIVE);
+}
+
+bool IsOfflinePreviewsEnabled() {
+ return ParamValue(kOfflinePagesSlowNetwork) == kExperimentEnabled;
+}
+
+bool EnableOfflinePreviewsForTesting() {
+ std::map<std::string, std::string> params;
+ params[kOfflinePagesSlowNetwork] = kExperimentEnabled;
+ return variations::AssociateVariationParams(kClientSidePreviewsFieldTrial,
+ kEnabled, params) &&
+ base::FieldTrialList::CreateFieldTrial(kClientSidePreviewsFieldTrial,
+ kEnabled);
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_experiments.h b/chromium/components/previews/core/previews_experiments.h
new file mode 100644
index 00000000000..9c8d7add057
--- /dev/null
+++ b/chromium/components/previews/core/previews_experiments.h
@@ -0,0 +1,43 @@
+// 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 COMPONENTS_PREVIEWS_CORE_PREVIEWS_EXPERIMENTS_H_
+#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_EXPERIMENTS_H_
+
+#include "base/time/time.h"
+
+namespace previews {
+
+namespace params {
+
+// The maximum number of recent previews navigations the black list looks at to
+// determine if a host is blacklisted.
+size_t MaxStoredHistoryLengthForBlackList();
+
+// The maximum number of hosts allowed in the in memory black list.
+size_t MaxInMemoryHostsInBlackList();
+
+// The number of recent navigations that were opted out of that would trigger
+// the host to be blacklisted.
+int BlackListOptOutThreshold();
+
+// The amount of time a host remains blacklisted due to opt outs.
+base::TimeDelta BlackListDuration();
+
+} // namespace params
+
+// Returns true if any client-side previews experiment is active.
+bool IsIncludedInClientSidePreviewsExperimentsFieldTrial();
+
+// Returns true if the field trial that should enable offline pages for
+// prohibitvely slow networks is active.
+bool IsOfflinePreviewsEnabled();
+
+// Sets the appropriate state for field trial and variations to imitate the
+// offline pages field trial.
+bool EnableOfflinePreviewsForTesting();
+
+} // namespace previews
+
+#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_EXPERIMENTS_H_
diff --git a/chromium/components/previews/core/previews_experiments_unittest.cc b/chromium/components/previews/core/previews_experiments_unittest.cc
new file mode 100644
index 00000000000..1ceb4c6a9ed
--- /dev/null
+++ b/chromium/components/previews/core/previews_experiments_unittest.cc
@@ -0,0 +1,29 @@
+// 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 "components/previews/core/previews_experiments.h"
+
+#include "base/metrics/field_trial.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using PreviewsExperimentsTest = testing::Test;
+
+} // namespace
+
+namespace previews {
+
+TEST_F(PreviewsExperimentsTest, TestFieldTrialOfflinePage) {
+ EXPECT_FALSE(IsIncludedInClientSidePreviewsExperimentsFieldTrial());
+ EXPECT_FALSE(IsOfflinePreviewsEnabled());
+
+ base::FieldTrialList field_trial_list(nullptr);
+ ASSERT_TRUE(EnableOfflinePreviewsForTesting());
+
+ EXPECT_TRUE(IsIncludedInClientSidePreviewsExperimentsFieldTrial());
+ EXPECT_TRUE(IsOfflinePreviewsEnabled());
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_io_data.cc b/chromium/components/previews/core/previews_io_data.cc
new file mode 100644
index 00000000000..740e18f9e01
--- /dev/null
+++ b/chromium/components/previews/core/previews_io_data.cc
@@ -0,0 +1,92 @@
+// 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 "components/previews/core/previews_io_data.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_path.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/sequenced_task_runner.h"
+#include "base/time/default_clock.h"
+#include "components/previews/core/previews_black_list.h"
+#include "components/previews/core/previews_experiments.h"
+#include "components/previews/core/previews_opt_out_store.h"
+#include "components/previews/core/previews_ui_service.h"
+#include "net/nqe/network_quality_estimator.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "url/gurl.h"
+
+namespace previews {
+
+PreviewsIOData::PreviewsIOData(
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
+ : ui_task_runner_(ui_task_runner),
+ io_task_runner_(io_task_runner),
+ weak_factory_(this) {}
+
+PreviewsIOData::~PreviewsIOData() {}
+
+void PreviewsIOData::Initialize(
+ base::WeakPtr<PreviewsUIService> previews_ui_service,
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store) {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+ previews_ui_service_ = previews_ui_service;
+
+ // Set up the IO thread portion of |this|.
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&PreviewsIOData::InitializeOnIOThread, base::Unretained(this),
+ base::Passed(&previews_opt_out_store)));
+}
+
+void PreviewsIOData::InitializeOnIOThread(
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+ previews_black_list_.reset(
+ new PreviewsBlackList(std::move(previews_opt_out_store),
+ base::MakeUnique<base::DefaultClock>()));
+ ui_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&PreviewsUIService::SetIOData, previews_ui_service_,
+ weak_factory_.GetWeakPtr()));
+}
+
+void PreviewsIOData::AddPreviewNavigation(const GURL& url,
+ bool opt_out,
+ PreviewsType type) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+ previews_black_list_->AddPreviewNavigation(url, opt_out, type);
+}
+
+void PreviewsIOData::ClearBlackList(base::Time begin_time,
+ base::Time end_time) {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+ previews_black_list_->ClearBlackList(begin_time, end_time);
+}
+
+bool PreviewsIOData::ShouldAllowPreview(const net::URLRequest& request,
+ PreviewsType type) const {
+ if (!IsOfflinePreviewsEnabled())
+ return false;
+ // The blacklist will disallow certain hosts for periods of time based on
+ // user's opting out of the preview
+ if (!previews_black_list_ ||
+ !previews_black_list_->IsLoadedAndAllowed(request.url(), type)) {
+ return false;
+ }
+ net::NetworkQualityEstimator* network_quality_estimator =
+ request.context()->network_quality_estimator();
+ if (!network_quality_estimator)
+ return false;
+
+ net::EffectiveConnectionType effective_connection_type =
+ network_quality_estimator->GetEffectiveConnectionType();
+ return effective_connection_type >= net::EFFECTIVE_CONNECTION_TYPE_OFFLINE &&
+ effective_connection_type <= net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_io_data.h b/chromium/components/previews/core/previews_io_data.h
new file mode 100644
index 00000000000..5dbf65c9fd4
--- /dev/null
+++ b/chromium/components/previews/core/previews_io_data.h
@@ -0,0 +1,84 @@
+// 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 COMPONENTS_PREVIEWS_CORE_PREVIEWS_IO_DATA_H_
+#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_IO_DATA_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/time/time.h"
+#include "components/previews/core/previews_decider.h"
+#include "components/previews/core/previews_opt_out_store.h"
+
+class GURL;
+
+namespace net {
+class URLRequest;
+}
+
+namespace previews {
+class PreviewsBlackList;
+class PreviewsUIService;
+
+// A class to manage the IO portion of inter-thread communication between
+// previews/ objects. Created on the UI thread, but used only on the IO thread
+// after initialization.
+class PreviewsIOData : public PreviewsDecider {
+ public:
+ PreviewsIOData(
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
+ ~PreviewsIOData() override;
+
+ // Stores |previews_ui_service| as |previews_ui_service_| and posts a task to
+ // InitializeOnIOThread on the IO thread.
+ void Initialize(base::WeakPtr<PreviewsUIService> previews_ui_service,
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store);
+
+ // Adds a navigation to |url| to the black list with result |opt_out|.
+ void AddPreviewNavigation(const GURL& url, bool opt_out, PreviewsType type);
+
+ // Clears the history of the black list between |begin_time| and |end_time|,
+ // both inclusive.
+ void ClearBlackList(base::Time begin_time, base::Time end_time);
+
+ // The previews black list that decides whether a navigation can use previews.
+ PreviewsBlackList* black_list() const { return previews_black_list_.get(); }
+
+ // PreviewsDecider implementation:
+ bool ShouldAllowPreview(const net::URLRequest& request,
+ PreviewsType type) const override;
+
+ protected:
+ // Posts a task to SetIOData for |previews_ui_service_| on the UI thread with
+ // a weak pointer to |this|. Virtualized for testing.
+ virtual void InitializeOnIOThread(
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store);
+
+ private:
+ // The UI thread portion of the inter-thread communication for previews.
+ base::WeakPtr<PreviewsUIService> previews_ui_service_;
+
+ std::unique_ptr<PreviewsBlackList> previews_black_list_;
+
+ // The UI and IO thread task runners. |ui_task_runner_| is used to post
+ // tasks to |previews_ui_service_|, and |io_task_runner_| is used to post from
+ // Initialize to InitializeOnIOThread as well as verify that execution is
+ // happening on the IO thread.
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ base::WeakPtrFactory<PreviewsIOData> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreviewsIOData);
+};
+
+} // namespace previews
+
+#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_IO_DATA_H_
diff --git a/chromium/components/previews/core/previews_io_data_unittest.cc b/chromium/components/previews/core/previews_io_data_unittest.cc
new file mode 100644
index 00000000000..7021a5a2663
--- /dev/null
+++ b/chromium/components/previews/core/previews_io_data_unittest.cc
@@ -0,0 +1,82 @@
+// 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 "components/previews/core/previews_io_data.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "components/previews/core/previews_ui_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace previews {
+
+namespace {
+
+class TestPreviewsIOData : public PreviewsIOData {
+ public:
+ TestPreviewsIOData(
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
+ : PreviewsIOData(io_task_runner, ui_task_runner), initialized_(false) {}
+ ~TestPreviewsIOData() override {}
+
+ // Whether Initialize was called.
+ bool initialized() { return initialized_; }
+
+ private:
+ // Set |initialized_| to true and use base class functionality.
+ void InitializeOnIOThread(
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store) override {
+ initialized_ = true;
+ PreviewsIOData::InitializeOnIOThread(std::move(previews_opt_out_store));
+ }
+
+ // Whether Initialize was called.
+ bool initialized_;
+};
+
+class PreviewsIODataTest : public testing::Test {
+ public:
+ PreviewsIODataTest() {}
+
+ ~PreviewsIODataTest() override {}
+
+ void set_io_data(std::unique_ptr<TestPreviewsIOData> io_data) {
+ io_data_ = std::move(io_data);
+ }
+
+ TestPreviewsIOData* io_data() { return io_data_.get(); }
+
+ void set_ui_service(std::unique_ptr<PreviewsUIService> ui_service) {
+ ui_service_ = std::move(ui_service);
+ }
+
+ protected:
+ // Run this test on a single thread.
+ base::MessageLoopForIO loop_;
+
+ private:
+ std::unique_ptr<TestPreviewsIOData> io_data_;
+ std::unique_ptr<PreviewsUIService> ui_service_;
+};
+
+} // namespace
+
+TEST_F(PreviewsIODataTest, TestInitialization) {
+ set_io_data(base::WrapUnique(
+ new TestPreviewsIOData(loop_.task_runner(), loop_.task_runner())));
+ set_ui_service(base::WrapUnique(
+ new PreviewsUIService(io_data(), loop_.task_runner(), nullptr)));
+ base::RunLoop().RunUntilIdle();
+ // After the outstanding posted tasks have run, |io_data_| should be fully
+ // initialized.
+ EXPECT_TRUE(io_data()->initialized());
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_opt_out_store.h b/chromium/components/previews/core/previews_opt_out_store.h
new file mode 100644
index 00000000000..15aa73f3f9c
--- /dev/null
+++ b/chromium/components/previews/core/previews_opt_out_store.h
@@ -0,0 +1,61 @@
+// 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 COMPONENTS_PREVIEWS_CORE_PREVIEWS_OPT_OUT_STORE_H_
+#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_OPT_OUT_STORE_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/time/time.h"
+#include "components/previews/core/previews_black_list_item.h"
+
+class GURL;
+
+namespace previews {
+
+enum class PreviewsType {
+ NONE = 0,
+ OFFLINE = 1,
+ LAST = 2,
+};
+
+typedef std::unordered_map<std::string, std::unique_ptr<PreviewsBlackListItem>>
+ BlackListItemMap;
+
+typedef base::Callback<void(std::unique_ptr<BlackListItemMap>)>
+ LoadBlackListCallback;
+
+// PreviewsOptOutStore keeps opt out information for the previews.
+// Ability to create multiple instances of the store as well as behavior of
+// asynchronous operations when the object is being destroyed, before such
+// operation finishes will depend on implementation. It is possible to issue
+// multiple asynchronous operations in parallel and maintain ordering.
+class PreviewsOptOutStore {
+ public:
+ virtual ~PreviewsOptOutStore() {}
+
+ // Adds a new navigation to the store. |opt_out| is whether the user opted out
+ // of the preview.
+ virtual void AddPreviewNavigation(bool opt_out,
+ const std::string& host_name,
+ PreviewsType type,
+ base::Time now) = 0;
+
+ // Asynchronously loads a map of host names to PreviewsBlackListItem for that
+ // host from the store. And runs |callback| once loading is finished.
+ virtual void LoadBlackList(LoadBlackListCallback callback) = 0;
+
+ // Deletes all history in the store between |begin_time| and |end_time|.
+ virtual void ClearBlackList(base::Time begin_time, base::Time end_time) = 0;
+};
+
+} // namespace previews
+
+#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_OPT_OUT_STORE_H_
diff --git a/chromium/components/previews/core/previews_ui_service.cc b/chromium/components/previews/core/previews_ui_service.cc
new file mode 100644
index 00000000000..af146cc81f1
--- /dev/null
+++ b/chromium/components/previews/core/previews_ui_service.cc
@@ -0,0 +1,49 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/previews/core/previews_ui_service.h"
+
+#include "base/bind.h"
+#include "base/single_thread_task_runner.h"
+#include "components/previews/core/previews_io_data.h"
+#include "url/gurl.h"
+
+namespace previews {
+
+PreviewsUIService::PreviewsUIService(
+ PreviewsIOData* previews_io_data,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store)
+ : io_task_runner_(io_task_runner), weak_factory_(this) {
+ previews_io_data->Initialize(weak_factory_.GetWeakPtr(),
+ std::move(previews_opt_out_store));
+}
+
+PreviewsUIService::~PreviewsUIService() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void PreviewsUIService::SetIOData(base::WeakPtr<PreviewsIOData> io_data) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ io_data_ = io_data;
+}
+
+void PreviewsUIService::AddPreviewNavigation(const GURL& url,
+ PreviewsType type,
+ bool opt_out) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&PreviewsIOData::AddPreviewNavigation, io_data_,
+ url, opt_out, type));
+}
+
+void PreviewsUIService::ClearBlackList(base::Time begin_time,
+ base::Time end_time) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&PreviewsIOData::ClearBlackList, io_data_,
+ begin_time, end_time));
+}
+
+} // namespace previews
diff --git a/chromium/components/previews/core/previews_ui_service.h b/chromium/components/previews/core/previews_ui_service.h
new file mode 100644
index 00000000000..74b9512ba00
--- /dev/null
+++ b/chromium/components/previews/core/previews_ui_service.h
@@ -0,0 +1,62 @@
+// 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 COMPONENTS_PREVIEWS_CORE_PREVIEWS_UI_SERVICE_H_
+#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_UI_SERVICE_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "components/previews/core/previews_opt_out_store.h"
+
+class GURL;
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace previews {
+class PreviewsIOData;
+
+// A class to manage the UI portion of inter-thread communication between
+// previews/ objects. Created and used on the UI thread.
+class PreviewsUIService {
+ public:
+ PreviewsUIService(
+ PreviewsIOData* previews_io_data,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store);
+ virtual ~PreviewsUIService();
+
+ // Sets |io_data_| to |io_data| to allow calls from the UI thread to the IO
+ // thread. Virtualized in testing.
+ virtual void SetIOData(base::WeakPtr<PreviewsIOData> io_data);
+
+ // Adds a navigation to |url| to the black list with result |opt_out|.
+ void AddPreviewNavigation(const GURL& url, PreviewsType type, bool opt_out);
+
+ // Clears the history of the black list between |begin_time| and |end_time|.
+ void ClearBlackList(base::Time begin_time, base::Time end_time);
+
+ private:
+ // The IO thread portion of the inter-thread communication for previews/.
+ base::WeakPtr<previews::PreviewsIOData> io_data_;
+
+ base::ThreadChecker thread_checker_;
+
+ // The IO thread task runner. Used to post tasks to |io_data_|.
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ base::WeakPtrFactory<PreviewsUIService> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreviewsUIService);
+};
+
+} // namespace previews
+
+#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_UI_SERVICE_H_
diff --git a/chromium/components/previews/core/previews_ui_service_unittest.cc b/chromium/components/previews/core/previews_ui_service_unittest.cc
new file mode 100644
index 00000000000..57a1bbd8aef
--- /dev/null
+++ b/chromium/components/previews/core/previews_ui_service_unittest.cc
@@ -0,0 +1,87 @@
+// 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 "components/previews/core/previews_ui_service.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "components/previews/core/previews_io_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace previews {
+
+namespace {
+
+class TestPreviewsUIService : public PreviewsUIService {
+ public:
+ TestPreviewsUIService(
+ PreviewsIOData* previews_io_data,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
+ std::unique_ptr<PreviewsOptOutStore> previews_opt_out_store)
+ : PreviewsUIService(previews_io_data,
+ io_task_runner,
+ std::move(previews_opt_out_store)),
+ io_data_set_(false) {}
+ ~TestPreviewsUIService() override {}
+
+ // Set |io_data_set_| to true and use base class functionality.
+ void SetIOData(base::WeakPtr<PreviewsIOData> previews_io_data) override {
+ io_data_set_ = true;
+ PreviewsUIService::SetIOData(previews_io_data);
+ }
+
+ // Whether SetIOData was called.
+ bool io_data_set() { return io_data_set_; }
+
+ private:
+ // Whether SetIOData was called.
+ bool io_data_set_;
+};
+
+class PreviewsUIServiceTest : public testing::Test {
+ public:
+ PreviewsUIServiceTest() {}
+
+ ~PreviewsUIServiceTest() override {}
+
+ void set_io_data(std::unique_ptr<PreviewsIOData> io_data) {
+ io_data_ = std::move(io_data);
+ }
+
+ PreviewsIOData* io_data() { return io_data_.get(); }
+
+ void set_ui_service(std::unique_ptr<TestPreviewsUIService> ui_service) {
+ ui_service_ = std::move(ui_service);
+ }
+
+ TestPreviewsUIService* ui_service() { return ui_service_.get(); }
+
+ protected:
+ // Run this test on a single thread.
+ base::MessageLoopForIO loop_;
+
+ private:
+ std::unique_ptr<PreviewsIOData> io_data_;
+ std::unique_ptr<TestPreviewsUIService> ui_service_;
+};
+
+} // namespace
+
+TEST_F(PreviewsUIServiceTest, TestInitialization) {
+ set_io_data(base::WrapUnique(
+ new PreviewsIOData(loop_.task_runner(), loop_.task_runner())));
+ set_ui_service(base::WrapUnique(
+ new TestPreviewsUIService(io_data(), loop_.task_runner(), nullptr)));
+ base::RunLoop().RunUntilIdle();
+ // After the outstanding posted tasks have run, SetIOData should have been
+ // called for |ui_service_|.
+ EXPECT_TRUE(ui_service()->io_data_set());
+}
+
+} // namespace previews
diff --git a/chromium/components/printing.gypi b/chromium/components/printing.gypi
deleted file mode 100644
index 3409644e1a3..00000000000
--- a/chromium/components/printing.gypi
+++ /dev/null
@@ -1,82 +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.
-
-{
- 'targets': [
- {
- # GN: //components/printing/common:printing_common
- 'target_name': 'printing_common',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/ipc/ipc.gyp:ipc',
- '<(DEPTH)/printing/printing.gyp:printing',
- '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
- '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
- ],
- 'sources': [
- "printing/common/print_messages.cc",
- "printing/common/print_messages.h",
- "printing/common/printing_param_traits_macros.h",
- ],
- },{
- # GN: //components/printing/common:printing_renderer
- 'target_name': 'printing_renderer',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/content/content.gyp:content_common',
- '<(DEPTH)/content/content.gyp:content_renderer',
- '<(DEPTH)/net/net.gyp:net',
- '<(DEPTH)/printing/printing.gyp:printing',
- '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
- '<(DEPTH)/ui/base/ui_base.gyp:ui_base',
- 'components_resources.gyp:components_resources',
- 'printing_common',
- ],
- 'sources': [
- 'printing/renderer/print_web_view_helper.cc',
- 'printing/renderer/print_web_view_helper.h',
- 'printing/renderer/print_web_view_helper_android.cc',
- 'printing/renderer/print_web_view_helper_linux.cc',
- 'printing/renderer/print_web_view_helper_mac.mm',
- 'printing/renderer/print_web_view_helper_pdf_win.cc',
- ],
- # TODO(dgn): C4267: http://crbug.com/167187 size_t -> int
- 'msvs_disabled_warnings': [ 4267 ],
- },{
- # GN: //components/printing/browser:printing_browser
- 'target_name': 'printing_browser',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/printing/printing.gyp:printing',
- '<(DEPTH)/skia/skia.gyp:skia',
- ],
- 'sources': [
- 'printing/browser/print_manager.cc',
- 'printing/browser/print_manager.h',
- 'printing/browser/print_manager_utils.cc',
- 'printing/browser/print_manager_utils.h',
- ],
- },{
- # GN: //components/printing/test:printing_test_support
- 'target_name': 'printing_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../content/content_shell_and_tests.gyp:test_support_content',
- '../skia/skia.gyp:skia',
- '<(DEPTH)/testing/gtest.gyp:gtest',
- 'printing_renderer',
- ],
- 'sources': [
- 'printing/test/mock_printer.cc',
- 'printing/test/mock_printer.h',
- 'printing/test/print_mock_render_thread.cc',
- 'printing/test/print_mock_render_thread.h',
- 'printing/test/print_test_content_renderer_client.cc',
- 'printing/test/print_test_content_renderer_client.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/printing/browser/BUILD.gn b/chromium/components/printing/browser/BUILD.gn
index ed4fdd4a655..bddd3a67d52 100644
--- a/chromium/components/printing/browser/BUILD.gn
+++ b/chromium/components/printing/browser/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser") {
+static_library("browser") {
sources = [
"print_manager.cc",
"print_manager.h",
diff --git a/chromium/components/printing/common/BUILD.gn b/chromium/components/printing/common/BUILD.gn
index bcefed51f3c..e3f8e731441 100644
--- a/chromium/components/printing/common/BUILD.gn
+++ b/chromium/components/printing/common/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("common") {
+static_library("common") {
sources = [
"print_messages.cc",
"print_messages.h",
diff --git a/chromium/components/printing/common/print_messages.h b/chromium/components/printing/common/print_messages.h
index 705211bd5fa..a0191448ccf 100644
--- a/chromium/components/printing/common/print_messages.h
+++ b/chromium/components/printing/common/print_messages.h
@@ -304,6 +304,7 @@ IPC_STRUCT_BEGIN(PrintHostMsg_ScriptedPrint_Params)
IPC_STRUCT_MEMBER(int, expected_pages_count)
IPC_STRUCT_MEMBER(bool, has_selection)
IPC_STRUCT_MEMBER(bool, is_scripted)
+ IPC_STRUCT_MEMBER(bool, is_modifiable)
IPC_STRUCT_MEMBER(printing::MarginType, margin_type)
IPC_STRUCT_END()
diff --git a/chromium/components/printing/renderer/BUILD.gn b/chromium/components/printing/renderer/BUILD.gn
index 92670027d77..bea33696892 100644
--- a/chromium/components/printing/renderer/BUILD.gn
+++ b/chromium/components/printing/renderer/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("renderer") {
+static_library("renderer") {
sources = [
"print_web_view_helper.cc",
"print_web_view_helper.h",
diff --git a/chromium/components/printing/renderer/print_web_view_helper.cc b/chromium/components/printing/renderer/print_web_view_helper.cc
index b25340caef3..7e9df81aac5 100644
--- a/chromium/components/printing/renderer/print_web_view_helper.cc
+++ b/chromium/components/printing/renderer/print_web_view_helper.cc
@@ -32,6 +32,8 @@
#include "printing/metafile_skia_wrapper.h"
#include "printing/pdf_metafile_skia.h"
#include "printing/units.h"
+#include "third_party/WebKit/public/platform/WebDoubleSize.h"
+#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/web/WebConsoleMessage.h"
@@ -39,6 +41,7 @@
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebFrameClient.h"
#include "third_party/WebKit/public/web/WebFrameOwnerProperties.h"
+#include "third_party/WebKit/public/web/WebFrameWidget.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebPlugin.h"
#include "third_party/WebKit/public/web/WebPluginDocument.h"
@@ -120,15 +123,15 @@ bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params& params) {
}
PrintMsg_Print_Params GetCssPrintParams(
- blink::WebFrame* frame,
+ blink::WebLocalFrame* frame,
int page_index,
const PrintMsg_Print_Params& page_params) {
PrintMsg_Print_Params page_css_params = page_params;
int dpi = GetDPI(&page_params);
- blink::WebSize page_size_in_pixels(
- ConvertUnit(page_params.page_size.width(), dpi, kPixelsPerInch),
- ConvertUnit(page_params.page_size.height(), dpi, kPixelsPerInch));
+ blink::WebDoubleSize page_size_in_pixels(
+ ConvertUnitDouble(page_params.page_size.width(), dpi, kPixelsPerInch),
+ ConvertUnitDouble(page_params.page_size.height(), dpi, kPixelsPerInch));
int margin_top_in_pixels =
ConvertUnit(page_params.margin_top, dpi, kPixelsPerInch);
int margin_right_in_pixels = ConvertUnit(
@@ -143,8 +146,6 @@ PrintMsg_Print_Params GetCssPrintParams(
page_params.margin_left,
dpi, kPixelsPerInch);
- blink::WebSize original_page_size_in_pixels = page_size_in_pixels;
-
if (frame) {
frame->pageSizeAndMarginsInPixels(page_index,
page_size_in_pixels,
@@ -154,9 +155,9 @@ PrintMsg_Print_Params GetCssPrintParams(
margin_left_in_pixels);
}
- int new_content_width = page_size_in_pixels.width -
+ double new_content_width = page_size_in_pixels.width() -
margin_left_in_pixels - margin_right_in_pixels;
- int new_content_height = page_size_in_pixels.height -
+ double new_content_height = page_size_in_pixels.height() -
margin_top_in_pixels - margin_bottom_in_pixels;
// Invalid page size and/or margins. We just use the default setting.
@@ -166,20 +167,12 @@ PrintMsg_Print_Params GetCssPrintParams(
return page_css_params;
}
+ page_css_params.page_size =
+ gfx::Size(ConvertUnit(page_size_in_pixels.width(), kPixelsPerInch, dpi),
+ ConvertUnit(page_size_in_pixels.height(), kPixelsPerInch, dpi));
page_css_params.content_size =
gfx::Size(ConvertUnit(new_content_width, kPixelsPerInch, dpi),
- ConvertUnit(new_content_height, kPixelsPerInch, dpi));
-
- if (original_page_size_in_pixels != page_size_in_pixels) {
- page_css_params.page_size =
- gfx::Size(ConvertUnit(page_size_in_pixels.width, kPixelsPerInch, dpi),
- ConvertUnit(page_size_in_pixels.height, kPixelsPerInch, dpi));
- } else {
- // Printing frame doesn't have any page size css. Pixels to dpi conversion
- // causes rounding off errors. Therefore use the default page size values
- // directly.
- page_css_params.page_size = page_params.page_size;
- }
+ ConvertUnit(new_content_height, kPixelsPerInch, dpi));
page_css_params.margin_top =
ConvertUnit(margin_top_in_pixels, kPixelsPerInch, dpi);
@@ -318,7 +311,7 @@ bool IsPrintToPdfRequested(const base::DictionaryValue& job_settings) {
return print_to_pdf;
}
-bool PrintingFrameHasPageSizeStyle(blink::WebFrame* frame,
+bool PrintingFrameHasPageSizeStyle(blink::WebLocalFrame* frame,
int total_page_count) {
if (!frame)
return false;
@@ -335,11 +328,13 @@ bool PrintingFrameHasPageSizeStyle(blink::WebFrame* frame,
// Disable scaling when either:
// - The PDF specifies disabling scaling.
-// - All the pages in the PDF are the same size, and that size is the same as
-// the paper size.
+// - All the pages in the PDF are the same size,
+// - |ignore_page_size| is false and the uniform size is the same as the paper
+// size.
bool PDFShouldDisableScalingBasedOnPreset(
const blink::WebPrintPresetOptions& options,
- const PrintMsg_Print_Params& params) {
+ const PrintMsg_Print_Params& params,
+ bool ignore_page_size) {
if (options.isScalingDisabled)
return true;
@@ -353,6 +348,9 @@ bool PDFShouldDisableScalingBasedOnPreset(
return true;
}
+ if (ignore_page_size)
+ return false;
+
blink::WebSize page_size(
ConvertUnit(params.page_size.width(), dpi, kPointsPerInch),
ConvertUnit(params.page_size.height(), dpi, kPointsPerInch));
@@ -361,19 +359,21 @@ bool PDFShouldDisableScalingBasedOnPreset(
bool PDFShouldDisableScaling(blink::WebLocalFrame* frame,
const blink::WebNode& node,
- const PrintMsg_Print_Params& params) {
+ const PrintMsg_Print_Params& params,
+ bool ignore_page_size) {
const bool kDefaultPDFShouldDisableScalingSetting = true;
blink::WebPrintPresetOptions preset_options;
if (!frame->getPrintPresetOptionsForPlugin(node, &preset_options))
return kDefaultPDFShouldDisableScalingSetting;
- return PDFShouldDisableScalingBasedOnPreset(preset_options, params);
+ return PDFShouldDisableScalingBasedOnPreset(preset_options, params,
+ ignore_page_size);
}
#if defined(ENABLE_BASIC_PRINTING)
MarginType GetMarginsForPdf(blink::WebLocalFrame* frame,
const blink::WebNode& node,
const PrintMsg_Print_Params& params) {
- return PDFShouldDisableScaling(frame, node, params) ?
+ return PDFShouldDisableScaling(frame, node, params, false) ?
NO_MARGINS : PRINTABLE_AREA_MARGINS;
}
#endif
@@ -414,7 +414,8 @@ blink::WebPrintScalingOption GetPrintScalingOption(
if (!FitToPageEnabled(job_settings))
return blink::WebPrintScalingOptionNone;
- bool no_plugin_scaling = PDFShouldDisableScaling(frame, node, params);
+ bool no_plugin_scaling = PDFShouldDisableScaling(frame, node, params,
+ true);
if (params.is_first_request && no_plugin_scaling)
return blink::WebPrintScalingOptionNone;
}
@@ -423,7 +424,7 @@ blink::WebPrintScalingOption GetPrintScalingOption(
#endif // defined(ENABLE_PRINT_PREVIEW)
PrintMsg_Print_Params CalculatePrintParamsForCss(
- blink::WebFrame* frame,
+ blink::WebLocalFrame* frame,
int page_index,
const PrintMsg_Print_Params& page_params,
bool ignore_css_margins,
@@ -526,9 +527,11 @@ void PrintWebViewHelper::PrintHeaderAndFooter(
blink::WebView::create(nullptr, blink::WebPageVisibilityStateVisible);
web_view->settings()->setJavaScriptEnabled(true);
- blink::WebLocalFrame* frame =
- blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, NULL);
+ blink::WebFrameClient frame_client;
+ blink::WebLocalFrame* frame = blink::WebLocalFrame::create(
+ blink::WebTreeScopeType::Document, &frame_client);
web_view->setMainFrame(frame);
+ blink::WebFrameWidget::create(nullptr, web_view, frame);
base::StringValue html(ResourceBundle::GetSharedInstance().GetLocalizedString(
IDR_PRINT_PREVIEW_PAGE));
@@ -559,7 +562,6 @@ void PrintWebViewHelper::PrintHeaderAndFooter(
frame->printEnd();
web_view->close();
- frame->close();
}
#endif // defined(ENABLE_PRINT_PREVIEW)
@@ -616,14 +618,13 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient,
bool allowsBrokenNullLayerTreeView() const override;
// blink::WebFrameClient:
- blink::WebFrame* createChildFrame(
+ blink::WebLocalFrame* createChildFrame(
blink::WebLocalFrame* parent,
blink::WebTreeScopeType scope,
const blink::WebString& name,
const blink::WebString& unique_name,
blink::WebSandboxFlags sandbox_flags,
const blink::WebFrameOwnerProperties& frame_owner_properties) override;
- void frameDetached(blink::WebFrame* frame, DetachType type) override;
void CallOnReady();
void ResizeForPrinting();
@@ -707,11 +708,11 @@ void PrepareFrameAndViewForPrint::ResizeForPrinting() {
}
void PrepareFrameAndViewForPrint::StartPrinting() {
- ResizeForPrinting();
blink::WebView* web_view = frame_.view();
web_view->settings()->setShouldPrintBackgrounds(should_print_backgrounds_);
expected_pages_count_ =
frame()->printBegin(web_print_params_, node_to_print_);
+ ResizeForPrinting();
is_printing_started_ = true;
}
@@ -744,14 +745,18 @@ void PrepareFrameAndViewForPrint::CopySelection(
blink::WebView::create(this, blink::WebPageVisibilityStateVisible);
owns_web_view_ = true;
content::RenderView::ApplyWebPreferences(prefs, web_view);
- web_view->setMainFrame(
- blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, this));
+ blink::WebLocalFrame* main_frame =
+ blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, this);
+ web_view->setMainFrame(main_frame);
+ blink::WebFrameWidget::create(this, web_view, main_frame);
frame_.Reset(web_view->mainFrame()->toWebLocalFrame());
node_to_print_.reset();
// When loading is done this will call didStopLoading() and that will do the
// actual printing.
- frame()->loadRequest(blink::WebURLRequest(GURL(url_str)));
+ blink::WebURLRequest request = blink::WebURLRequest(GURL(url_str));
+ request.setRequestorOrigin(blink::WebSecurityOrigin::createUnique());
+ frame()->loadRequest(request);
}
bool PrepareFrameAndViewForPrint::allowsBrokenNullLayerTreeView() const {
@@ -767,26 +772,18 @@ void PrepareFrameAndViewForPrint::didStopLoading() {
weak_ptr_factory_.GetWeakPtr()));
}
-blink::WebFrame* PrepareFrameAndViewForPrint::createChildFrame(
+blink::WebLocalFrame* PrepareFrameAndViewForPrint::createChildFrame(
blink::WebLocalFrame* parent,
blink::WebTreeScopeType scope,
const blink::WebString& name,
const blink::WebString& unique_name,
blink::WebSandboxFlags sandbox_flags,
const blink::WebFrameOwnerProperties& frame_owner_properties) {
- blink::WebFrame* frame = blink::WebLocalFrame::create(scope, this);
+ blink::WebLocalFrame* frame = blink::WebLocalFrame::create(scope, this);
parent->appendChild(frame);
return frame;
}
-void PrepareFrameAndViewForPrint::frameDetached(blink::WebFrame* frame,
- DetachType type) {
- DCHECK(type == DetachType::Remove);
- if (frame->parent())
- frame->parent()->removeChild(frame);
- frame->close();
-}
-
void PrepareFrameAndViewForPrint::CallOnReady() {
return on_ready_.Run(); // Can delete |this|.
}
@@ -815,6 +812,7 @@ void PrepareFrameAndViewForPrint::FinishPrinting() {
if (owns_web_view_) {
DCHECK(!frame->isLoading());
owns_web_view_ = false;
+ frame->frameWidget()->close();
web_view->close();
}
}
@@ -957,8 +955,7 @@ bool PrintWebViewHelper::GetPrintFrame(blink::WebLocalFrame** frame) {
// If the user has selected text in the currently focused frame we print
// only that frame (this makes print selection work for multiple frames).
- blink::WebLocalFrame* focusedFrame =
- webView->focusedFrame()->toWebLocalFrame();
+ blink::WebLocalFrame* focusedFrame = webView->focusedFrame();
*frame = focusedFrame->hasSelection()
? focusedFrame
: webView->mainFrame()->toWebLocalFrame();
@@ -1498,7 +1495,7 @@ void PrintWebViewHelper::FinishFramePrinting() {
// static - Not anonymous so that platform implementations can use it.
void PrintWebViewHelper::ComputePageLayoutInPointsForCss(
- blink::WebFrame* frame,
+ blink::WebLocalFrame* frame,
int page_index,
const PrintMsg_Print_Params& page_params,
bool ignore_css_margins,
@@ -1588,7 +1585,7 @@ bool PrintWebViewHelper::SetOptionsFromPdfDocument(
}
options->is_scaling_disabled = PDFShouldDisableScalingBasedOnPreset(
- preset_options, print_pages_params_->params);
+ preset_options, print_pages_params_->params, false);
options->copies = preset_options.copies;
// TODO(thestig) This should be a straight pass-through, but print preview
@@ -1704,6 +1701,7 @@ bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebLocalFrame* frame,
}
params.margin_type = margin_type;
params.is_scripted = is_scripted;
+ params.is_modifiable = !PrintingNodeOrPdfFrame(frame, node);
Send(new PrintHostMsg_DidShowPrintDialog(routing_id()));
@@ -1744,7 +1742,7 @@ bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
#if !defined(OS_MACOSX)
void PrintWebViewHelper::PrintPageInternal(
const PrintMsg_PrintPage_Params& params,
- blink::WebFrame* frame,
+ blink::WebLocalFrame* frame,
PdfMetafileSkia* metafile,
gfx::Size* page_size_in_dpi,
gfx::Rect* content_area_in_dpi) {
diff --git a/chromium/components/printing/renderer/print_web_view_helper.h b/chromium/components/printing/renderer/print_web_view_helper.h
index fe33d5e6374..dd8d24d5b42 100644
--- a/chromium/components/printing/renderer/print_web_view_helper.h
+++ b/chromium/components/printing/renderer/print_web_view_helper.h
@@ -45,6 +45,7 @@ class DictionaryValue;
namespace blink {
class WebFrame;
+class WebLocalFrame;
class WebView;
}
@@ -261,7 +262,7 @@ class PrintWebViewHelper
#if defined(ENABLE_BASIC_PRINTING)
void OnFramePreparedForPrintPages();
void PrintPages();
- bool PrintPagesNative(blink::WebFrame* frame, int page_count);
+ bool PrintPagesNative(blink::WebLocalFrame* frame, int page_count);
void FinishFramePrinting();
// Render the frame for printing.
bool RenderPagesForPrint(blink::WebLocalFrame* frame,
@@ -271,10 +272,10 @@ class PrintWebViewHelper
// Prints the page listed in |params|.
#if defined(OS_MACOSX)
void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
- blink::WebFrame* frame);
+ blink::WebLocalFrame* frame);
#else
void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
- blink::WebFrame* frame,
+ blink::WebLocalFrame* frame,
PdfMetafileSkia* metafile,
gfx::Size* page_size_in_dpi,
gfx::Rect* content_area_in_dpi);
@@ -284,7 +285,7 @@ class PrintWebViewHelper
#if defined(OS_MACOSX)
void RenderPage(const PrintMsg_Print_Params& params,
int page_number,
- blink::WebFrame* frame,
+ blink::WebLocalFrame* frame,
bool is_preview,
PdfMetafileSkia* metafile,
gfx::Size* page_size,
@@ -309,7 +310,7 @@ class PrintWebViewHelper
// Helper method to get page layout in points and fit to page if needed.
static void ComputePageLayoutInPointsForCss(
- blink::WebFrame* frame,
+ blink::WebLocalFrame* frame,
int page_index,
const PrintMsg_Print_Params& default_params,
bool ignore_css_margins,
diff --git a/chromium/components/printing/renderer/print_web_view_helper_linux.cc b/chromium/components/printing/renderer/print_web_view_helper_linux.cc
index 330dd33e95b..5f6cdd540dc 100644
--- a/chromium/components/printing/renderer/print_web_view_helper_linux.cc
+++ b/chromium/components/printing/renderer/print_web_view_helper_linux.cc
@@ -43,7 +43,7 @@ bool SaveToFD(const printing::Metafile& metafile,
namespace printing {
#if defined(ENABLE_BASIC_PRINTING)
-bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
+bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
int page_count) {
PdfMetafileSkia metafile(PDF_SKIA_DOCUMENT_TYPE);
CHECK(metafile.Init());
diff --git a/chromium/components/printing/renderer/print_web_view_helper_mac.mm b/chromium/components/printing/renderer/print_web_view_helper_mac.mm
index d227c5e1ffa..0b134745863 100644
--- a/chromium/components/printing/renderer/print_web_view_helper_mac.mm
+++ b/chromium/components/printing/renderer/print_web_view_helper_mac.mm
@@ -19,7 +19,7 @@
namespace printing {
#if defined(ENABLE_BASIC_PRINTING)
-bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
+bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
int page_count) {
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
const PrintMsg_Print_Params& print_params = params.params;
@@ -40,7 +40,7 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
void PrintWebViewHelper::PrintPageInternal(
const PrintMsg_PrintPage_Params& params,
- blink::WebFrame* frame) {
+ blink::WebLocalFrame* frame) {
PdfMetafileSkia metafile(PDF_SKIA_DOCUMENT_TYPE);
CHECK(metafile.Init());
@@ -109,7 +109,7 @@ bool PrintWebViewHelper::RenderPreviewPage(
void PrintWebViewHelper::RenderPage(const PrintMsg_Print_Params& params,
int page_number,
- blink::WebFrame* frame,
+ blink::WebLocalFrame* frame,
bool is_preview,
PdfMetafileSkia* metafile,
gfx::Size* page_size,
diff --git a/chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc b/chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc
index 1c1c2213e24..dad2aaa05a4 100644
--- a/chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc
+++ b/chromium/components/printing/renderer/print_web_view_helper_pdf_win.cc
@@ -14,7 +14,7 @@
namespace printing {
#if defined(ENABLE_BASIC_PRINTING)
-bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
+bool PrintWebViewHelper::PrintPagesNative(blink::WebLocalFrame* frame,
int page_count) {
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
std::vector<int> printed_pages = GetPrintedPages(params, page_count);
@@ -60,10 +60,9 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
printed_page_params.content_area = content_area_in_dpi[i];
Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params));
// Send the rest of the pages with an invalid metafile handle.
- if (printed_page_params.metafile_data_handle.IsValid()) {
- printed_page_params.metafile_data_handle.Close();
+ // TODO(erikchen): Fix semantics. See https://crbug.com/640840
+ if (printed_page_params.metafile_data_handle.IsValid())
printed_page_params.metafile_data_handle = base::SharedMemoryHandle();
- }
}
return true;
}
diff --git a/chromium/components/printing/test/BUILD.gn b/chromium/components/printing/test/BUILD.gn
index 9b698386cd5..aad77158159 100644
--- a/chromium/components/printing/test/BUILD.gn
+++ b/chromium/components/printing/test/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
diff --git a/chromium/components/profile_metrics.gypi b/chromium/components/profile_metrics.gypi
deleted file mode 100644
index 49e713ada4c..00000000000
--- a/chromium/components/profile_metrics.gypi
+++ /dev/null
@@ -1,24 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/profile_metrics
- 'target_name': 'profile_metrics',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'profile_metrics/counts.cc',
- 'profile_metrics/counts.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/profile_metrics/BUILD.gn b/chromium/components/profile_metrics/BUILD.gn
index 8adf08bb883..fe85cf61ab1 100644
--- a/chromium/components/profile_metrics/BUILD.gn
+++ b/chromium/components/profile_metrics/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/profile_metrics.gypi:profile_metrics
static_library("profile_metrics") {
sources = [
"counts.cc",
diff --git a/chromium/components/proximity_auth.gypi b/chromium/components/proximity_auth.gypi
deleted file mode 100644
index f8f1a5ad654..00000000000
--- a/chromium/components/proximity_auth.gypi
+++ /dev/null
@@ -1,268 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/proximity_auth and
- # //components/proximity_auth/ble.
- 'target_name': 'proximity_auth',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- ':cryptauth',
- ':cryptauth_proto',
- ':proximity_auth_logging',
- '../base/base.gyp:base',
- '../device/bluetooth/bluetooth.gyp:device_bluetooth',
- '../net/net.gyp:net',
- 'prefs/prefs.gyp:prefs',
- ],
- 'sources': [
- "proximity_auth/authenticator.h",
- "proximity_auth/ble/bluetooth_low_energy_characteristics_finder.cc",
- "proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h",
- "proximity_auth/ble/bluetooth_low_energy_connection.cc",
- "proximity_auth/ble/bluetooth_low_energy_connection.h",
- "proximity_auth/ble/bluetooth_low_energy_connection_finder.cc",
- "proximity_auth/ble/bluetooth_low_energy_connection_finder.h",
- "proximity_auth/ble/bluetooth_low_energy_device_whitelist.cc",
- "proximity_auth/ble/bluetooth_low_energy_device_whitelist.h",
- "proximity_auth/ble/bluetooth_low_energy_weave_defines.h",
- "proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.cc",
- "proximity_auth/ble/bluetooth_low_energy_weave_packet_generator.h",
- "proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.cc",
- "proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.h",
- "proximity_auth/ble/remote_attribute.h",
- "proximity_auth/ble/fake_wire_message.cc",
- "proximity_auth/ble/fake_wire_message.h",
- "proximity_auth/ble/pref_names.cc",
- "proximity_auth/ble/pref_names.h",
- "proximity_auth/bluetooth_connection.cc",
- "proximity_auth/bluetooth_connection.h",
- "proximity_auth/bluetooth_connection_finder.cc",
- "proximity_auth/bluetooth_connection_finder.h",
- "proximity_auth/bluetooth_throttler.h",
- "proximity_auth/bluetooth_throttler_impl.cc",
- "proximity_auth/bluetooth_throttler_impl.h",
- "proximity_auth/bluetooth_util.cc",
- "proximity_auth/bluetooth_util.h",
- "proximity_auth/bluetooth_util_chromeos.cc",
- "proximity_auth/cryptauth_enroller_factory_impl.cc",
- "proximity_auth/cryptauth_enroller_factory_impl.h",
- "proximity_auth/connection.cc",
- "proximity_auth/connection.h",
- "proximity_auth/connection_finder.h",
- "proximity_auth/connection_observer.h",
- "proximity_auth/device_to_device_authenticator.cc",
- "proximity_auth/device_to_device_authenticator.h",
- "proximity_auth/device_to_device_initiator_operations.cc",
- "proximity_auth/device_to_device_initiator_operations.h",
- "proximity_auth/device_to_device_secure_context.cc",
- "proximity_auth/device_to_device_secure_context.h",
- "proximity_auth/messenger.h",
- "proximity_auth/messenger_impl.cc",
- "proximity_auth/messenger_impl.h",
- "proximity_auth/messenger_observer.h",
- "proximity_auth/metrics.cc",
- "proximity_auth/metrics.h",
- "proximity_auth/proximity_auth_client.h",
- "proximity_auth/proximity_auth_pref_manager.cc",
- "proximity_auth/proximity_auth_pref_manager.h",
- "proximity_auth/proximity_auth_pref_names.cc",
- "proximity_auth/proximity_auth_pref_names.h",
- "proximity_auth/proximity_auth_system.cc",
- "proximity_auth/proximity_auth_system.h",
- "proximity_auth/proximity_monitor.h",
- "proximity_auth/proximity_monitor_impl.cc",
- "proximity_auth/proximity_monitor_impl.h",
- "proximity_auth/proximity_monitor_observer.h",
- "proximity_auth/remote_device.cc",
- "proximity_auth/remote_device.h",
- "proximity_auth/remote_device_loader.cc",
- "proximity_auth/remote_device_loader.h",
- "proximity_auth/remote_device_life_cycle.h",
- "proximity_auth/remote_device_life_cycle_impl.h",
- "proximity_auth/remote_device_life_cycle_impl.cc",
- "proximity_auth/remote_status_update.cc",
- "proximity_auth/remote_status_update.h",
- "proximity_auth/screenlock_bridge.cc",
- "proximity_auth/screenlock_bridge.h",
- "proximity_auth/screenlock_state.h",
- "proximity_auth/secure_context.h",
- "proximity_auth/switches.cc",
- "proximity_auth/switches.h",
- "proximity_auth/throttled_bluetooth_connection_finder.cc",
- "proximity_auth/throttled_bluetooth_connection_finder.h",
- "proximity_auth/unlock_manager.cc",
- "proximity_auth/unlock_manager.h",
- "proximity_auth/wire_message.cc",
- "proximity_auth/wire_message.h",
- ],
-
- 'export_dependent_settings': [
- 'cryptauth_proto',
- ],
- },
- {
- 'target_name': 'proximity_auth_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- ':cryptauth_test_support',
- '../base/base.gyp:base',
- '../testing/gmock.gyp:gmock',
- ],
- 'sources': [
- "proximity_auth/device_to_device_responder_operations.cc",
- "proximity_auth/device_to_device_responder_operations.h",
- "proximity_auth/fake_connection.cc",
- "proximity_auth/fake_connection.h",
- "proximity_auth/fake_secure_context.cc",
- "proximity_auth/fake_secure_context.h",
- "proximity_auth/mock_proximity_auth_client.cc",
- "proximity_auth/mock_proximity_auth_client.h",
- "proximity_auth/proximity_auth_test_util.cc",
- "proximity_auth/proximity_auth_test_util.h",
- ],
- },
- {
- # GN version: //components/proximity_auth/logging
- 'target_name': 'proximity_auth_logging',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- "proximity_auth/logging/log_buffer.cc",
- "proximity_auth/logging/log_buffer.h",
- "proximity_auth/logging/logging.h",
- "proximity_auth/logging/logging.cc",
- ]
- },
- {
- # GN version: //components/proximity_auth/cryptauth/proto
- 'target_name': 'cryptauth_proto',
- 'type': 'static_library',
- 'sources': [
- 'proximity_auth/cryptauth/proto/cryptauth_api.proto',
- 'proximity_auth/cryptauth/proto/securemessage.proto',
- ],
- 'variables': {
- 'proto_in_dir': 'proximity_auth/cryptauth/proto',
- 'proto_out_dir': 'components/proximity_auth/cryptauth/proto',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
- {
- 'target_name': 'cryptauth',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'cryptauth_proto',
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- '../components/components.gyp:gcm_driver',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- ],
- 'sources': [
- "proximity_auth/cryptauth/cryptauth_access_token_fetcher.h",
- "proximity_auth/cryptauth/cryptauth_access_token_fetcher_impl.cc",
- "proximity_auth/cryptauth/cryptauth_access_token_fetcher_impl.h",
- "proximity_auth/cryptauth/cryptauth_api_call_flow.cc",
- "proximity_auth/cryptauth/cryptauth_api_call_flow.h",
- "proximity_auth/cryptauth/cryptauth_client.h",
- "proximity_auth/cryptauth/cryptauth_client_impl.cc",
- "proximity_auth/cryptauth/cryptauth_client_impl.h",
- "proximity_auth/cryptauth/cryptauth_device_manager.cc",
- "proximity_auth/cryptauth/cryptauth_device_manager.h",
- "proximity_auth/cryptauth/cryptauth_enroller.h",
- "proximity_auth/cryptauth/cryptauth_enroller_impl.cc",
- "proximity_auth/cryptauth/cryptauth_enroller_impl.h",
- "proximity_auth/cryptauth/cryptauth_enrollment_manager.cc",
- "proximity_auth/cryptauth/cryptauth_enrollment_manager.h",
- "proximity_auth/cryptauth/cryptauth_enrollment_utils.cc",
- "proximity_auth/cryptauth/cryptauth_gcm_manager.cc",
- "proximity_auth/cryptauth/cryptauth_gcm_manager.h",
- "proximity_auth/cryptauth/cryptauth_gcm_manager_impl.cc",
- "proximity_auth/cryptauth/cryptauth_gcm_manager_impl.h",
- "proximity_auth/cryptauth/pref_names.cc",
- "proximity_auth/cryptauth/pref_names.h",
- "proximity_auth/cryptauth/secure_message_delegate.cc",
- "proximity_auth/cryptauth/secure_message_delegate.h",
- "proximity_auth/cryptauth/switches.cc",
- "proximity_auth/cryptauth/switches.h",
- "proximity_auth/cryptauth/sync_scheduler.cc",
- "proximity_auth/cryptauth/sync_scheduler.h",
- "proximity_auth/cryptauth/sync_scheduler_impl.cc",
- "proximity_auth/cryptauth/sync_scheduler_impl.h",
- ],
- 'export_dependent_settings': [
- 'cryptauth_proto',
- ],
- },
- {
- 'target_name': 'cryptauth_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'cryptauth_proto',
- '../base/base.gyp:base',
- '../testing/gmock.gyp:gmock',
- ],
- 'sources': [
- "proximity_auth/cryptauth/fake_cryptauth_gcm_manager.cc",
- "proximity_auth/cryptauth/fake_cryptauth_gcm_manager.h",
- "proximity_auth/cryptauth/fake_secure_message_delegate.cc",
- "proximity_auth/cryptauth/fake_secure_message_delegate.h",
- "proximity_auth/cryptauth/mock_cryptauth_client.cc",
- "proximity_auth/cryptauth/mock_cryptauth_client.h",
- "proximity_auth/cryptauth/mock_sync_scheduler.cc",
- "proximity_auth/cryptauth/mock_sync_scheduler.h",
- ],
- 'export_dependent_settings': [
- 'cryptauth_proto',
- ],
- },
- {
- # GN version: //components/proximity_auth/webui
- 'target_name': 'proximity_auth_webui',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../ui/resources/ui_resources.gyp:ui_resources',
- 'components_resources.gyp:components_resources',
- 'cryptauth',
- 'cryptauth_proto',
- 'proximity_auth',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'proximity_auth/webui/proximity_auth_ui.cc',
- 'proximity_auth/webui/proximity_auth_ui.h',
- 'proximity_auth/webui/proximity_auth_webui_handler.cc',
- 'proximity_auth/webui/proximity_auth_webui_handler.h',
- 'proximity_auth/webui/reachable_phone_flow.cc',
- 'proximity_auth/webui/reachable_phone_flow.h',
- 'proximity_auth/webui/url_constants.cc',
- 'proximity_auth/webui/url_constants.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/proximity_auth/BUILD.gn b/chromium/components/proximity_auth/BUILD.gn
index a19418d88e6..2476b344d31 100644
--- a/chromium/components/proximity_auth/BUILD.gn
+++ b/chromium/components/proximity_auth/BUILD.gn
@@ -4,7 +4,7 @@
import("//testing/test.gni")
-source_set("proximity_auth") {
+static_library("proximity_auth") {
sources = [
"authenticator.h",
"bluetooth_connection.cc",
@@ -93,7 +93,7 @@ source_set("proximity_auth") {
}
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
diff --git a/chromium/components/proximity_auth/ble/BUILD.gn b/chromium/components/proximity_auth/ble/BUILD.gn
index 05e8bb3921d..cb96bb9c850 100644
--- a/chromium/components/proximity_auth/ble/BUILD.gn
+++ b/chromium/components/proximity_auth/ble/BUILD.gn
@@ -4,7 +4,7 @@
import("//testing/test.gni")
-source_set("ble") {
+static_library("ble") {
sources = [
"bluetooth_low_energy_characteristics_finder.cc",
"bluetooth_low_energy_characteristics_finder.h",
@@ -14,6 +14,8 @@ source_set("ble") {
"bluetooth_low_energy_connection_finder.h",
"bluetooth_low_energy_device_whitelist.cc",
"bluetooth_low_energy_device_whitelist.h",
+ "bluetooth_low_energy_weave_client_connection.cc",
+ "bluetooth_low_energy_weave_client_connection.h",
"bluetooth_low_energy_weave_defines.h",
"bluetooth_low_energy_weave_packet_generator.cc",
"bluetooth_low_energy_weave_packet_generator.h",
@@ -51,6 +53,7 @@ source_set("unit_tests") {
"bluetooth_low_energy_connection_finder_unittest.cc",
"bluetooth_low_energy_connection_unittest.cc",
"bluetooth_low_energy_device_whitelist_unittest.cc",
+ "bluetooth_low_energy_weave_client_connection_unittest.cc",
"bluetooth_low_energy_weave_packet_generator_unittest.cc",
"bluetooth_low_energy_weave_packet_receiver_unittest.cc",
]
diff --git a/chromium/components/proximity_auth/cryptauth/BUILD.gn b/chromium/components/proximity_auth/cryptauth/BUILD.gn
index fc7d40e4731..6791187ea8b 100644
--- a/chromium/components/proximity_auth/cryptauth/BUILD.gn
+++ b/chromium/components/proximity_auth/cryptauth/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("cryptauth") {
+static_library("cryptauth") {
sources = [
"cryptauth_access_token_fetcher.h",
"cryptauth_access_token_fetcher_impl.cc",
@@ -53,7 +53,7 @@ source_set("cryptauth") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
diff --git a/chromium/components/proximity_auth/cryptauth/proto/BUILD.gn b/chromium/components/proximity_auth/cryptauth/proto/BUILD.gn
index 813d594ed47..9affa372285 100644
--- a/chromium/components/proximity_auth/cryptauth/proto/BUILD.gn
+++ b/chromium/components/proximity_auth/cryptauth/proto/BUILD.gn
@@ -4,7 +4,6 @@
import("//third_party/protobuf/proto_library.gni")
-# GYP version: //components/proximity_auth.gypi:cryptauth_proto
proto_library("proto") {
sources = [
"cryptauth_api.proto",
diff --git a/chromium/components/proximity_auth/logging/BUILD.gn b/chromium/components/proximity_auth/logging/BUILD.gn
index 6a3233e2609..fc9f9937e7d 100644
--- a/chromium/components/proximity_auth/logging/BUILD.gn
+++ b/chromium/components/proximity_auth/logging/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("logging") {
+static_library("logging") {
sources = [
"log_buffer.cc",
"log_buffer.h",
diff --git a/chromium/components/proximity_auth/webui/BUILD.gn b/chromium/components/proximity_auth/webui/BUILD.gn
index e3cb0b6ea04..69b5253a086 100644
--- a/chromium/components/proximity_auth/webui/BUILD.gn
+++ b/chromium/components/proximity_auth/webui/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/proximity_auth.gypi:proximity_auth_webui
static_library("webui") {
sources = [
"proximity_auth_ui.cc",
diff --git a/chromium/components/proxy_config.gypi b/chromium/components/proxy_config.gypi
deleted file mode 100644
index f30b9f80968..00000000000
--- a/chromium/components/proxy_config.gypi
+++ /dev/null
@@ -1,41 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/proxy_config
- 'target_name': 'proxy_config',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- 'pref_registry',
- 'prefs/prefs.gyp:prefs',
- ],
- 'include_dirs': [
- '..',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- 'defines': [
- 'PROXY_CONFIG_IMPLEMENTATION',
- ],
- 'sources': [
- 'proxy_config/pref_proxy_config_tracker.cc',
- 'proxy_config/pref_proxy_config_tracker.h',
- 'proxy_config/pref_proxy_config_tracker_impl.cc',
- 'proxy_config/pref_proxy_config_tracker_impl.h',
- 'proxy_config/proxy_config_dictionary.cc',
- 'proxy_config/proxy_config_dictionary.h',
- 'proxy_config/proxy_config_export.h',
- 'proxy_config/proxy_config_pref_names.cc',
- 'proxy_config/proxy_config_pref_names.h',
- 'proxy_config/proxy_prefs.cc',
- 'proxy_config/proxy_prefs.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/proxy_config/BUILD.gn b/chromium/components/proxy_config/BUILD.gn
index 3243526fe71..f9541afc11d 100644
--- a/chromium/components/proxy_config/BUILD.gn
+++ b/chromium/components/proxy_config/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/proxy_config.gypi:proxy_config
component("proxy_config") {
sources = [
"pref_proxy_config_tracker.cc",
diff --git a/chromium/components/query_parser.gypi b/chromium/components/query_parser.gypi
deleted file mode 100644
index 0b7f189f8ae..00000000000
--- a/chromium/components/query_parser.gypi
+++ /dev/null
@@ -1,26 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'query_parser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../third_party/icu/icu.gyp:icuuc',
- ],
- 'sources': [
- 'query_parser/query_parser.cc',
- 'query_parser/query_parser.h',
- 'query_parser/snippet.cc',
- 'query_parser/snippet.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/query_parser/query_parser.cc b/chromium/components/query_parser/query_parser.cc
index 7b5e4eeb13e..260a75afd9f 100644
--- a/chromium/components/query_parser/query_parser.cc
+++ b/chromium/components/query_parser/query_parser.cc
@@ -184,7 +184,7 @@ class QueryNodeList : public QueryNode {
QueryNodeList::QueryNodeList() {}
QueryNodeList::~QueryNodeList() {
- STLDeleteElements(&children_);
+ base::STLDeleteElements(&children_);
}
void QueryNodeList::AddChild(QueryNode* node) {
diff --git a/chromium/components/quirks.gypi b/chromium/components/quirks.gypi
deleted file mode 100644
index 1e2c8e7f445..00000000000
--- a/chromium/components/quirks.gypi
+++ /dev/null
@@ -1,36 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/quirks
- 'target_name': 'quirks',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../components/prefs/prefs.gyp:prefs',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- 'version_info',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'QUIRKS_IMPLEMENTATION',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'quirks/pref_names.cc',
- 'quirks/pref_names.h',
- 'quirks/quirks_client.cc',
- 'quirks/quirks_client.h',
- 'quirks/quirks_export.h',
- 'quirks/quirks_manager.cc',
- 'quirks/quirks_manager.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/quirks/quirks_manager.cc b/chromium/components/quirks/quirks_manager.cc
index 2ab3c75cbfe..df84c8f691f 100644
--- a/chromium/components/quirks/quirks_manager.cc
+++ b/chromium/components/quirks/quirks_manager.cc
@@ -10,7 +10,6 @@
#include "base/format_macros.h"
#include "base/memory/ptr_util.h"
#include "base/path_service.h"
-#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/task_runner_util.h"
#include "components/prefs/pref_registry_simple.h"
@@ -46,7 +45,6 @@ base::FilePath CheckForIccFile(base::FilePath built_in_path,
bool quirks_enabled) {
// First, look for icc file in old read-only location. If there, we don't use
// the Quirks server.
- // TODO(glevin): Awaiting final decision on how to handle old read-only files.
if (CheckAndLogFile(built_in_path))
return built_in_path;
@@ -139,6 +137,12 @@ void QuirksManager::RequestIccProfilePath(
const RequestFinishedCallback& on_request_finished) {
DCHECK(thread_checker_.CalledOnValidThread());
+ if (!product_id) {
+ VLOG(1) << "Could not determine display information (product id = 0)";
+ on_request_finished.Run(base::FilePath(), false);
+ return;
+ }
+
std::string name = IdToFileName(product_id);
base::PostTaskAndReplyWithResult(
blocking_pool_.get(), FROM_HERE,
@@ -189,14 +193,6 @@ void QuirksManager::OnIccFilePathRequestCompleted(
local_state_->GetDictionary(prefs::kQuirksClientLastServerCheck)
->GetDouble(IdToHexString(product_id), &last_check);
- // If never checked server before, need to check for new device.
- if (last_check == 0.0) {
- delegate_->GetDaysSinceOobe(base::Bind(
- &QuirksManager::OnDaysSinceOobeReceived, weak_ptr_factory_.GetWeakPtr(),
- product_id, on_request_finished));
- return;
- }
-
const base::TimeDelta time_since =
base::Time::Now() - base::Time::FromDoubleT(last_check);
@@ -209,38 +205,7 @@ void QuirksManager::OnIccFilePathRequestCompleted(
return;
}
- CreateClient(product_id, on_request_finished);
-}
-
-void QuirksManager::OnDaysSinceOobeReceived(
- int64_t product_id,
- const RequestFinishedCallback& on_request_finished,
- int days_since_oobe) {
- DCHECK(thread_checker_.CalledOnValidThread());
- // On newer devices, we want to check server immediately (after OOBE/login).
- if (days_since_oobe <= kDaysBetweenServerChecks) {
- CreateClient(product_id, on_request_finished);
- return;
- }
-
- // Otherwise, for the first check on an older device, we want to stagger
- // it over 30 days, so artificially set last check accordingly.
- // TODO(glevin): I believe that it makes sense to remove this random delay
- // in the next Chrome release.
- const int rand_days = base::RandInt(0, kDaysBetweenServerChecks);
- const base::Time fake_last_check =
- base::Time::Now() - base::TimeDelta::FromDays(rand_days);
- SetLastServerCheck(product_id, fake_last_check);
- VLOG(2) << "Delaying first Quirks Server check by "
- << kDaysBetweenServerChecks - rand_days << " days.";
-
- on_request_finished.Run(base::FilePath(), false);
-}
-
-void QuirksManager::CreateClient(
- int64_t product_id,
- const RequestFinishedCallback& on_request_finished) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ // Create and start a client to download file.
QuirksClient* client =
new QuirksClient(product_id, on_request_finished, this);
clients_.insert(base::WrapUnique(client));
diff --git a/chromium/components/quirks/quirks_manager.h b/chromium/components/quirks/quirks_manager.h
index 1cfd91cd961..68759eba0f4 100644
--- a/chromium/components/quirks/quirks_manager.h
+++ b/chromium/components/quirks/quirks_manager.h
@@ -57,10 +57,6 @@ class QUIRKS_EXPORT QuirksManager {
using FakeQuirksFetcherCreator = base::Callback<
std::unique_ptr<net::URLFetcher>(const GURL&, net::URLFetcherDelegate*)>;
- // Callback after getting days since OOBE on blocking pool.
- // Parameter is returned number of days.
- using DaysSinceOobeCallback = base::Callback<void(int)>;
-
// Delegate class, so implementation can access browser functionality.
class Delegate {
public:
@@ -80,9 +76,6 @@ class QUIRKS_EXPORT QuirksManager {
// Whether downloads are allowed by enterprise device policy.
virtual bool DevicePolicyEnabled() const = 0;
- // Gets days since first login, returned via callback.
- virtual void GetDaysSinceOobe(DaysSinceOobeCallback callback) const = 0;
-
private:
DISALLOW_ASSIGN(Delegate);
};
@@ -139,16 +132,6 @@ class QUIRKS_EXPORT QuirksManager {
const RequestFinishedCallback& on_request_finished,
base::FilePath path);
- // Callback after checking OOBE date; launch client if appropriate.
- void OnDaysSinceOobeReceived(
- int64_t product_id,
- const RequestFinishedCallback& on_request_finished,
- int days_since_oobe);
-
- // Create and start a client to download file.
- void CreateClient(int64_t product_id,
- const RequestFinishedCallback& on_request_finished);
-
// Whether downloads allowed by cmd line flag and device policy.
bool QuirksEnabled();
diff --git a/chromium/components/rappor.gypi b/chromium/components/rappor.gypi
deleted file mode 100644
index 8dd2dcf3641..00000000000
--- a/chromium/components/rappor.gypi
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'targets': [
- {
- # GN version: //components/rappor
- 'target_name': 'rappor',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- '../net/net.gyp:net',
- '../third_party/smhasher/smhasher.gyp:cityhash',
- 'data_use_measurement_core',
- 'metrics',
- 'variations',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'rappor/bloom_filter.cc',
- 'rappor/bloom_filter.h',
- 'rappor/byte_vector_utils.cc',
- 'rappor/byte_vector_utils.h',
- 'rappor/log_uploader.cc',
- 'rappor/log_uploader.h',
- 'rappor/log_uploader_interface.h',
- 'rappor/proto/rappor_metric.proto',
- 'rappor/rappor_metric.cc',
- 'rappor/rappor_metric.h',
- 'rappor/rappor_parameters.cc',
- 'rappor/rappor_parameters.h',
- 'rappor/rappor_pref_names.cc',
- 'rappor/rappor_pref_names.h',
- 'rappor/rappor_prefs.cc',
- 'rappor/rappor_prefs.h',
- 'rappor/rappor_service.cc',
- 'rappor/rappor_service.h',
- 'rappor/rappor_utils.cc',
- 'rappor/rappor_utils.h',
- 'rappor/reports.cc',
- 'rappor/reports.h',
- 'rappor/sample.cc',
- 'rappor/sample.h',
- 'rappor/sampler.cc',
- 'rappor/sampler.h',
- ],
- 'variables': {
- 'proto_in_dir': 'rappor/proto',
- 'proto_out_dir': 'components/rappor/proto',
- },
- 'includes': [ '../build/protoc.gypi' ],
- },
- {
- # GN version: //components/rappor:test_support
- 'target_name': 'rappor_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'rappor',
- ],
- 'sources': [
- 'rappor/test_log_uploader.cc',
- 'rappor/test_log_uploader.h',
- 'rappor/test_rappor_service.cc',
- 'rappor/test_rappor_service.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/rappor/BUILD.gn b/chromium/components/rappor/BUILD.gn
index ebfb8c117a6..5b9e11dacea 100644
--- a/chromium/components/rappor/BUILD.gn
+++ b/chromium/components/rappor/BUILD.gn
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/rappor.gypi:rappor
-source_set("rappor") {
+static_library("rappor") {
sources = [
"bloom_filter.cc",
"bloom_filter.h",
@@ -48,7 +47,6 @@ source_set("rappor") {
]
}
-# GYP version: components/rappor.gypi:rappor_test_support
static_library("test_support") {
testonly = true
sources = [
diff --git a/chromium/components/rappor/byte_vector_utils.cc b/chromium/components/rappor/byte_vector_utils.cc
index e9e58b6614c..03d4786cc82 100644
--- a/chromium/components/rappor/byte_vector_utils.cc
+++ b/chromium/components/rappor/byte_vector_utils.cc
@@ -22,8 +22,11 @@ base::StringPiece ByteVectorAsStringPiece(const ByteVector& lhs) {
}
// Concatenates parameters together as a string.
-std::string Concat(const ByteVector& value, char c, const std::string& data) {
- return std::string(value.begin(), value.end()) + c + data;
+std::string Concat(const ByteVector& value, char c, base::StringPiece data) {
+ std::string result(value.begin(), value.end());
+ result += c;
+ data.AppendToString(&result);
+ return result;
}
// Performs the operation: K = HMAC(K, data)
@@ -54,7 +57,7 @@ bool HMAC_Rehash(const crypto::HMAC& hmac, ByteVector* value) {
// The input "Key" is passed by initializing |hmac1| with it.
// The output "Key" is returned by initializing |out_hmac| with it.
// Returns false on an error.
-bool HMAC_DRBG_Update(const std::string& provided_data,
+bool HMAC_DRBG_Update(base::StringPiece provided_data,
const crypto::HMAC& hmac1,
ByteVector* value,
crypto::HMAC* out_hmac) {
@@ -164,7 +167,7 @@ ByteVector ByteVectorGenerator::GetWeightedRandomByteVector(
HmacByteVectorGenerator::HmacByteVectorGenerator(
size_t byte_count,
const std::string& entropy_input,
- const std::string& personalization_string)
+ base::StringPiece personalization_string)
: ByteVectorGenerator(byte_count),
hmac_(crypto::HMAC::SHA256),
value_(hmac_.DigestLength(), 0x01),
@@ -175,7 +178,8 @@ HmacByteVectorGenerator::HmacByteVectorGenerator(
// Note: We are using the 8.6.7 interpretation, where the entropy_input and
// nonce are acquired at the same time from the same source.
DCHECK_EQ(kEntropyInputSize, entropy_input.size());
- std::string seed_material(entropy_input + personalization_string);
+ std::string seed_material(entropy_input);
+ personalization_string.AppendToString(&seed_material);
// 2. Key = 0x00 00...00
crypto::HMAC hmac1(crypto::HMAC::SHA256);
if (!hmac1.Init(std::string(hmac_.DigestLength(), 0x00)))
diff --git a/chromium/components/rappor/byte_vector_utils.h b/chromium/components/rappor/byte_vector_utils.h
index 73775528044..71ce88f4943 100644
--- a/chromium/components/rappor/byte_vector_utils.h
+++ b/chromium/components/rappor/byte_vector_utils.h
@@ -11,6 +11,7 @@
#include <vector>
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "components/rappor/rappor_parameters.h"
#include "crypto/hmac.h"
@@ -83,7 +84,7 @@ class HmacByteVectorGenerator : public ByteVectorGenerator {
// number generator. The string parameters are treated as byte arrays.
HmacByteVectorGenerator(size_t byte_count,
const std::string& entropy_input,
- const std::string& personalization_string);
+ base::StringPiece personalization_string);
~HmacByteVectorGenerator() override;
diff --git a/chromium/components/rappor/rappor_service.cc b/chromium/components/rappor/rappor_service.cc
index f8bbdd6e3bc..40bae451a9f 100644
--- a/chromium/components/rappor/rappor_service.cc
+++ b/chromium/components/rappor/rappor_service.cc
@@ -65,7 +65,7 @@ RapporService::RapporService(
}
RapporService::~RapporService() {
- STLDeleteValues(&metrics_map_);
+ base::STLDeleteValues(&metrics_map_);
}
void RapporService::AddDailyObserver(
@@ -84,7 +84,7 @@ void RapporService::Initialize(net::URLRequestContextGetter* request_context) {
}
DVLOG(1) << "RapporService reporting to " << server_url.spec();
InitializeInternal(
- base::WrapUnique(new LogUploader(server_url, kMimeType, request_context)),
+ base::MakeUnique<LogUploader>(server_url, kMimeType, request_context),
internal::LoadCohort(pref_service_), internal::LoadSecret(pref_service_));
}
@@ -136,7 +136,7 @@ void RapporService::InitializeInternal(
void RapporService::CancelNextLogRotation() {
DCHECK(thread_checker_.CalledOnValidThread());
- STLDeleteValues(&metrics_map_);
+ base::STLDeleteValues(&metrics_map_);
log_rotation_timer_.Stop();
}
@@ -177,7 +177,7 @@ bool RapporService::ExportMetrics(RapporReports* reports) {
report->set_bits(std::string(bytes.begin(), bytes.end()));
DVLOG(2) << "Exporting metric " << kv.first;
}
- STLDeleteValues(&metrics_map_);
+ base::STLDeleteValues(&metrics_map_);
sampler_.ExportMetrics(secret_, reports);
diff --git a/chromium/components/rappor/reports.cc b/chromium/components/rappor/reports.cc
index 45d73b693e3..2f0f13206d2 100644
--- a/chromium/components/rappor/reports.cc
+++ b/chromium/components/rappor/reports.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/rand_util.h"
+#include "base/strings/string_piece.h"
#include "components/rappor/byte_vector_utils.h"
#include "components/rappor/rappor_parameters.h"
@@ -20,8 +21,8 @@ ByteVector GenerateReport(const std::string& secret,
// client's secret key + real data as a seed. The inclusion of the secret
// in the seed avoids correlations between real and fake data.
// The seed isn't a human-readable string.
- const std::string personalization_string =
- std::string(value.begin(), value.end());
+ const base::StringPiece personalization_string(
+ reinterpret_cast<const char*>(&value[0]), value.size());
HmacByteVectorGenerator hmac_generator(value.size(), secret,
personalization_string);
const ByteVector fake_mask =
diff --git a/chromium/components/renderer_context_menu.gypi b/chromium/components/renderer_context_menu.gypi
deleted file mode 100644
index 4e516d20be4..00000000000
--- a/chromium/components/renderer_context_menu.gypi
+++ /dev/null
@@ -1,32 +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.
-{
- 'targets': [
- {
- 'target_name': 'renderer_context_menu',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../components/components.gyp:search_engines',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'renderer_context_menu/context_menu_content_type.cc',
- 'renderer_context_menu/context_menu_content_type.h',
- 'renderer_context_menu/context_menu_delegate.cc',
- 'renderer_context_menu/context_menu_delegate.h',
- 'renderer_context_menu/render_view_context_menu_base.cc',
- 'renderer_context_menu/render_view_context_menu_base.h',
- 'renderer_context_menu/render_view_context_menu_observer.cc',
- 'renderer_context_menu/render_view_context_menu_observer.h',
- 'renderer_context_menu/render_view_context_menu_proxy.h',
- 'renderer_context_menu/views/toolkit_delegate_views.cc',
- 'renderer_context_menu/views/toolkit_delegate_views.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/renderer_context_menu/render_view_context_menu_base.cc b/chromium/components/renderer_context_menu/render_view_context_menu_base.cc
index 9965772e416..912932ab16e 100644
--- a/chromium/components/renderer_context_menu/render_view_context_menu_base.cc
+++ b/chromium/components/renderer_context_menu/render_view_context_menu_base.cc
@@ -161,9 +161,8 @@ RenderViewContextMenuBase::RenderViewContextMenuBase(
browser_context_(source_web_contents_->GetBrowserContext()),
menu_model_(this),
render_frame_id_(render_frame_host->GetRoutingID()),
- command_executed_(false),
- render_process_id_(render_frame_host->GetProcess()->GetID()) {
-}
+ render_process_id_(render_frame_host->GetProcess()->GetID()),
+ command_executed_(false) {}
RenderViewContextMenuBase::~RenderViewContextMenuBase() {
}
@@ -373,11 +372,12 @@ RenderFrameHost* RenderViewContextMenuBase::GetRenderFrameHost() {
// Controller functions --------------------------------------------------------
-void RenderViewContextMenuBase::OpenURL(
- const GURL& url, const GURL& referring_url,
- WindowOpenDisposition disposition,
- ui::PageTransition transition) {
- OpenURLWithExtraHeaders(url, referring_url, disposition, transition, "");
+void RenderViewContextMenuBase::OpenURL(const GURL& url,
+ const GURL& referring_url,
+ WindowOpenDisposition disposition,
+ ui::PageTransition transition) {
+ OpenURLWithExtraHeaders(url, referring_url, disposition, transition, "",
+ false);
}
void RenderViewContextMenuBase::OpenURLWithExtraHeaders(
@@ -385,16 +385,19 @@ void RenderViewContextMenuBase::OpenURLWithExtraHeaders(
const GURL& referring_url,
WindowOpenDisposition disposition,
ui::PageTransition transition,
- const std::string& extra_headers) {
+ const std::string& extra_headers,
+ bool started_from_context_menu) {
content::Referrer referrer = content::Referrer::SanitizeForRequest(
url,
content::Referrer(referring_url.GetAsReferrer(),
params_.referrer_policy));
- if (params_.link_url == url && disposition != OFF_THE_RECORD)
+ if (params_.link_url == url &&
+ disposition != WindowOpenDisposition::OFF_THE_RECORD)
params_.custom_context.link_followed = url;
- OpenURLParams open_url_params(url, referrer, disposition, transition, false);
+ OpenURLParams open_url_params(url, referrer, disposition, transition, false,
+ started_from_context_menu);
if (!extra_headers.empty())
open_url_params.extra_headers = extra_headers;
diff --git a/chromium/components/renderer_context_menu/render_view_context_menu_base.h b/chromium/components/renderer_context_menu/render_view_context_menu_base.h
index 82792dd1af2..5ea257c9976 100644
--- a/chromium/components/renderer_context_menu/render_view_context_menu_base.h
+++ b/chromium/components/renderer_context_menu/render_view_context_menu_base.h
@@ -148,10 +148,6 @@ class RenderViewContextMenuBase : public ui::SimpleMenuModel::Delegate,
virtual void HandleAuthorizeAllPlugins() = 0;
#endif
- // Returns the accelerator for given |command_id|.
- bool GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) override = 0;
-
// Subclasses should send notification.
virtual void NotifyMenuShown() = 0;
virtual void NotifyURLOpened(const GURL& url,
@@ -167,7 +163,8 @@ class RenderViewContextMenuBase : public ui::SimpleMenuModel::Delegate,
bool IsCustomItemEnabled(int id) const;
// Opens the specified URL string in a new tab.
- void OpenURL(const GURL& url, const GURL& referrer,
+ void OpenURL(const GURL& url,
+ const GURL& referrer,
WindowOpenDisposition disposition,
ui::PageTransition transition);
@@ -176,7 +173,8 @@ class RenderViewContextMenuBase : public ui::SimpleMenuModel::Delegate,
const GURL& referrer,
WindowOpenDisposition disposition,
ui::PageTransition transition,
- const std::string& extra_headers);
+ const std::string& extra_headers,
+ bool started_from_context_menu);
content::ContextMenuParams params_;
content::WebContents* const source_web_contents_;
@@ -187,6 +185,9 @@ class RenderViewContextMenuBase : public ui::SimpleMenuModel::Delegate,
// Renderer's frame id.
const int render_frame_id_;
+ // The RenderFrameHost's IDs.
+ const int render_process_id_;
+
// Our observers.
mutable base::ObserverList<RenderViewContextMenuObserver> observers_;
@@ -199,9 +200,6 @@ class RenderViewContextMenuBase : public ui::SimpleMenuModel::Delegate,
private:
bool AppendCustomItems();
- // The RenderFrameHost's IDs.
- const int render_process_id_;
-
std::unique_ptr<ToolkitDelegate> toolkit_delegate_;
ScopedVector<ui::SimpleMenuModel> custom_submenus_;
diff --git a/chromium/components/renderer_context_menu/views/toolkit_delegate_views.cc b/chromium/components/renderer_context_menu/views/toolkit_delegate_views.cc
index 6cb0f189917..81dfe55f560 100644
--- a/chromium/components/renderer_context_menu/views/toolkit_delegate_views.cc
+++ b/chromium/components/renderer_context_menu/views/toolkit_delegate_views.cc
@@ -29,9 +29,10 @@ void ToolkitDelegateViews::RunMenuAt(views::Widget* parent,
void ToolkitDelegateViews::Init(ui::SimpleMenuModel* menu_model) {
menu_adapter_.reset(new views::MenuModelAdapter(menu_model));
menu_view_ = menu_adapter_->CreateMenu();
- menu_runner_.reset(new views::MenuRunner(
- menu_view_,
- views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
+ menu_runner_.reset(
+ new views::MenuRunner(menu_view_, views::MenuRunner::HAS_MNEMONICS |
+ views::MenuRunner::CONTEXT_MENU |
+ views::MenuRunner::ASYNC));
}
void ToolkitDelegateViews::Cancel() {
diff --git a/chromium/components/resources/BUILD.gn b/chromium/components/resources/BUILD.gn
index 6f2f2a109cd..93d9f9ae0f5 100644
--- a/chromium/components/resources/BUILD.gn
+++ b/chromium/components/resources/BUILD.gn
@@ -8,7 +8,6 @@ import("//third_party/brotli/brotli.gni")
about_credits_file = "$target_gen_dir/about_credits.html"
about_credits_file_bro = "$target_gen_dir/about_credits.bro"
-# GYP version: components/components_resources.gyp:components_resources
group("resources") {
public_deps = [
":components_resources",
@@ -16,8 +15,6 @@ group("resources") {
]
}
-# GYP version: components/components_resources.gyp
-# (generate_components_resources action)
grit("components_resources") {
source = "components_resources.grd"
@@ -39,8 +36,6 @@ grit("components_resources") {
]
}
-# GYP version: components/components_resources.gyp
-# (generate_scaled_components_resources action)
grit("components_scaled_resources") {
source = "components_scaled_resources.grd"
@@ -65,7 +60,6 @@ compress_file_brotli("compressed_about_credits") {
]
}
-# GYP version: components/components_resources.gyp:about_credits
action("about_credits") {
script = "//tools/licenses.py"
diff --git a/chromium/components/resources/OWNERS b/chromium/components/resources/OWNERS
index 7ebdb56dc93..806568dd8a3 100644
--- a/chromium/components/resources/OWNERS
+++ b/chromium/components/resources/OWNERS
@@ -8,6 +8,7 @@ per-file crash_*=thestig@chromium.org
per-file data_reduction_proxy*=bengr@chromium.org
per-file data_reduction_proxy*=kundaji@chromium.org
per-file data_reduction_proxy*=megjablon@chromium.org
+per-file data_reduction_proxy*=ryansturm@chromium.org
per-file data_reduction_proxy*=sclittle@chromium.org
per-file data_reduction_proxy*=tbansal@chromium.org
per-file dom_distiller*=mdjones@chromium.org
diff --git a/chromium/components/resources/autofill_scaled_resources.grdp b/chromium/components/resources/autofill_scaled_resources.grdp
index d76b16918e2..c07f1d5ba93 100644
--- a/chromium/components/resources/autofill_scaled_resources.grdp
+++ b/chromium/components/resources/autofill_scaled_resources.grdp
@@ -6,28 +6,33 @@
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_MASTERCARD" file="autofill/mastercard.png" />
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_VISA" file="autofill/visa.png" />
+ <!-- These are not used on desktop, only Android, so use a placeholder file.
+ TODO(rouslan): Remove non-keyboard-accessory icon when keyboard
+ accessory becomes default on Android. -->
<if expr="is_android">
- <!-- These are not used on desktop, only Android, so use a placeholder file.
- TODO(rouslan): Remove non-keyboard-accessory icon when keyboard
- accessory becomes default on Android. -->
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_SCAN_NEW" file="autofill/cc-generic.png" />
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_SCAN_NEW_KEYBOARD_ACCESSORY" file="autofill/cc-generic.png" />
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_SETTINGS" file="autofill/cc-generic.png" />
-
- <!-- PaymentRequest image variants -->
- <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_AMEX" file="autofill/cc-generic.png" />
- <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_DINERS" file="autofill/cc-generic.png" />
- <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_DISCOVER" file="autofill/cc-generic.png" />
- <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_GENERIC" file="autofill/cc-generic.png" />
- <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_JCB" file="autofill/cc-generic.png" />
- <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_MASTERCARD" file="autofill/cc-generic.png" />
- <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_UNIONPAY" file="autofill/cc-generic.png" />
- <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_VISA" file="autofill/cc-generic.png" />
</if>
+ <!-- PaymentRequest image variants.
+ TODO(crbug.com/602666): Move the credit card icons into
+ components/resources and refer to them here instead of the placeholder
+ files so they can be used on platforms other than Android. -->
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_AMEX" file="autofill/cc-generic.png" />
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_DINERS" file="autofill/cc-generic.png" />
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_DISCOVER" file="autofill/cc-generic.png" />
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_GENERIC" file="autofill/cc-generic.png" />
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_JCB" file="autofill/cc-generic.png" />
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_MASTERCARD" file="autofill/cc-generic.png" />
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_UNIONPAY" file="autofill/cc-generic.png" />
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_PR_VISA" file="autofill/cc-generic.png" />
+
<structure type="chrome_scaled_image" name="IDR_CREDIT_CARD_CVC_HINT" file="autofill/credit_card_cvc_hint.png" />
<structure type="chrome_scaled_image" name="IDR_CREDIT_CARD_CVC_HINT_AMEX" file="autofill/credit_card_cvc_hint_amex.png" />
- <structure type="chrome_scaled_image" name="IDR_INFOBAR_AUTOFILL_CC" file="autofill/infobar_autofill_cc.png" />
+ <if expr="is_ios or is_android">
+ <structure type="chrome_scaled_image" name="IDR_INFOBAR_AUTOFILL_CC" file="autofill/infobar_autofill_cc.png" />
+ </if>
<if expr="is_macosx or is_ios">
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON" file="autofill/autofill_tooltip_icon.png" />
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON_H" file="autofill/autofill_tooltip_icon_hover.png" />
diff --git a/chromium/components/resources/components_resources.grd b/chromium/components/resources/components_resources.grd
index ba428ecb3ab..4a7e4df347b 100644
--- a/chromium/components/resources/components_resources.grd
+++ b/chromium/components/resources/components_resources.grd
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1">
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
<outputs>
<output filename="grit/components_resources.h" type="rc_header">
<emit emit_type='prepend'></emit>
@@ -15,6 +15,7 @@
<part file="gcm_driver_resources.grdp" />
<part file="net_log_resources.grdp" />
<part file="neterror_resources.grdp" />
+ <part file="physical_web_ui_resources.grdp" />
<part file="printing_resources.grdp" />
<part file="proximity_auth_resources.grdp" />
<part file="security_interstitials_resources.grdp" />
diff --git a/chromium/components/resources/components_scaled_resources.grd b/chromium/components/resources/components_scaled_resources.grd
index 90bfd15177b..ace356f01eb 100644
--- a/chromium/components/resources/components_scaled_resources.grd
+++ b/chromium/components/resources/components_scaled_resources.grd
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1">
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
<outputs>
<output filename="grit/components_scaled_resources.h" type="rc_header" context="default_100_percent">
<emit emit_type='prepend'></emit>
diff --git a/chromium/components/resources/default_100_percent/omnibox/ios/location_bar_http.png b/chromium/components/resources/default_100_percent/omnibox/ios/location_bar_http.png
deleted file mode 100644
index 46a2b64d403..00000000000
--- a/chromium/components/resources/default_100_percent/omnibox/ios/location_bar_http.png
+++ /dev/null
Binary files differ
diff --git a/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_http.png b/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_http.png
index f88ad367bf7..8de583e19ec 100644
--- a/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_http.png
+++ b/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_http.png
Binary files differ
diff --git a/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_https_invalid.png b/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_https_invalid.png
index c0365070278..ba50e5ed4f7 100644
--- a/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_https_invalid.png
+++ b/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_https_invalid.png
Binary files differ
diff --git a/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_https_valid.png b/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_https_valid.png
index 4bd8c5bce5b..9337d655876 100644
--- a/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_https_valid.png
+++ b/chromium/components/resources/default_100_percent/omnibox/ios/omnibox_https_valid.png
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/omnibox/ios/location_bar_http.png b/chromium/components/resources/default_200_percent/omnibox/ios/location_bar_http.png
deleted file mode 100644
index da5ee69ea17..00000000000
--- a/chromium/components/resources/default_200_percent/omnibox/ios/location_bar_http.png
+++ /dev/null
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_http.png b/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_http.png
index 9c4eda0be6a..cf21532d1eb 100644
--- a/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_http.png
+++ b/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_http.png
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_https_invalid.png b/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_https_invalid.png
index fcf859c90d6..f797139c638 100644
--- a/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_https_invalid.png
+++ b/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_https_invalid.png
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_https_valid.png b/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_https_valid.png
index 3813c73fddd..092bf9b6be2 100644
--- a/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_https_valid.png
+++ b/chromium/components/resources/default_200_percent/omnibox/ios/omnibox_https_valid.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/omnibox/ios/location_bar_http.png b/chromium/components/resources/default_300_percent/omnibox/ios/location_bar_http.png
deleted file mode 100644
index bb5a541840d..00000000000
--- a/chromium/components/resources/default_300_percent/omnibox/ios/location_bar_http.png
+++ /dev/null
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_http.png b/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_http.png
index 298d9e59eee..28301841b6e 100644
--- a/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_http.png
+++ b/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_http.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_https_invalid.png b/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_https_invalid.png
index 784f632c1e3..2b6326183fb 100644
--- a/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_https_invalid.png
+++ b/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_https_invalid.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_https_valid.png b/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_https_valid.png
index e5dcf751e97..c4511c636c9 100644
--- a/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_https_valid.png
+++ b/chromium/components/resources/default_300_percent/omnibox/ios/omnibox_https_valid.png
Binary files differ
diff --git a/chromium/components/resources/omnibox_scaled_resources.grdp b/chromium/components/resources/omnibox_scaled_resources.grdp
index 46a18f3b46b..1c69a1f6a97 100644
--- a/chromium/components/resources/omnibox_scaled_resources.grdp
+++ b/chromium/components/resources/omnibox_scaled_resources.grdp
@@ -5,7 +5,7 @@
<structure type="chrome_scaled_image" name="IDR_OMNIBOX_HTTPS_POLICY_WARNING" file="omnibox/controlled_setting_mandatory.png" />
<structure type="chrome_scaled_image" name="IDR_OMNIBOX_SEARCH_BUTTON_LOUPE" file="omnibox/omnibox_search_button_loupe.png" />
<if expr="is_ios">
- <structure type="chrome_scaled_image" name="IDR_LOCATION_BAR_HTTP" file="omnibox/ios/location_bar_http.png" />
+ <structure type="chrome_scaled_image" name="IDR_LOCATION_BAR_HTTP" file="omnibox/ios/omnibox_http.png" />
<structure type="chrome_scaled_image" name="IDR_OMNIBOX_HISTORY" file="omnibox/ios/omnibox_history.png" />
<structure type="chrome_scaled_image" name="IDR_OMNIBOX_HISTORY_INCOGNITO" file="omnibox/ios/omnibox_history_incognito.png" />
<structure type="chrome_scaled_image" name="IDR_OMNIBOX_HTTP" file="omnibox/ios/omnibox_http.png" />
diff --git a/chromium/components/resources/physical_web_ui_resources.grdp b/chromium/components/resources/physical_web_ui_resources.grdp
new file mode 100644
index 00000000000..0da84164a18
--- /dev/null
+++ b/chromium/components/resources/physical_web_ui_resources.grdp
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <include name="IDR_PHYSICAL_WEB_UI_HTML" file="../physical_web/webui/resources/physical_web.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+ <include name="IDR_PHYSICAL_WEB_UI_JS" file="../physical_web/webui/resources/physical_web.js" type="BINDATA" />
+ <include name="IDR_PHYSICAL_WEB_UI_CSS" file="../physical_web/webui/resources/physical_web.css" type="BINDATA" />
+</grit-part> \ No newline at end of file
diff --git a/chromium/components/resources/sync_driver_resources.grdp b/chromium/components/resources/sync_driver_resources.grdp
index bb0caa33546..50c111814c0 100644
--- a/chromium/components/resources/sync_driver_resources.grdp
+++ b/chromium/components/resources/sync_driver_resources.grdp
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_INDEX_HTML" file="../sync_driver/resources/index.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_INDEX_JS" file="../sync_driver/resources/sync_index.js" type="BINDATA" />
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_CHROME_SYNC_JS" file="../sync_driver/resources/chrome_sync.js" type="BINDATA" />
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_TYPES_JS" file="../sync_driver/resources/types.js" type="BINDATA" />
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_LOG_JS" file="../sync_driver/resources/sync_log.js" type="BINDATA" />
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_NODE_BROWSER_JS" file="../sync_driver/resources/sync_node_browser.js" type="BINDATA" />
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_SEARCH_JS" file="../sync_driver/resources/sync_search.js" type="BINDATA" />
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_ABOUT_JS" file="../sync_driver/resources/about.js" type="BINDATA" />
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_DATA_JS" file="../sync_driver/resources/data.js" type="BINDATA" />
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_EVENTS_JS" file="../sync_driver/resources/events.js" type="BINDATA" />
- <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SEARCH_JS" file="../sync_driver/resources/search.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_INDEX_HTML" file="../sync/driver/resources/index.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_INDEX_JS" file="../sync/driver/resources/sync_index.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_CHROME_SYNC_JS" file="../sync/driver/resources/chrome_sync.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_TYPES_JS" file="../sync/driver/resources/types.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_LOG_JS" file="../sync/driver/resources/sync_log.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_NODE_BROWSER_JS" file="../sync/driver/resources/sync_node_browser.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_SEARCH_JS" file="../sync/driver/resources/sync_search.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_ABOUT_JS" file="../sync/driver/resources/about.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_DATA_JS" file="../sync/driver/resources/data.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_EVENTS_JS" file="../sync/driver/resources/events.js" type="BINDATA" />
+ <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SEARCH_JS" file="../sync/driver/resources/search.js" type="BINDATA" />
</grit-part>
diff --git a/chromium/components/rlz.gypi b/chromium/components/rlz.gypi
deleted file mode 100644
index 9030258d66f..00000000000
--- a/chromium/components/rlz.gypi
+++ /dev/null
@@ -1,38 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/rlz
- 'target_name': 'rlz',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../rlz/rlz.gyp:rlz_lib',
- 'google_core_browser',
- ],
- 'sources': [
- 'rlz/rlz_tracker.cc',
- 'rlz/rlz_tracker.h',
- 'rlz/rlz_tracker_chromeos.cc',
- 'rlz/rlz_tracker_delegate.h',
- 'rlz/rlz_tracker_ios.cc',
- 'rlz/rlz_tracker_mac.cc',
- 'rlz/rlz_tracker_win.cc',
- ],
- 'conditions': [
- ['OS == "ios"', {
- 'dependencies': [
- '../ui/base/ui_base.gyp:ui_base',
- ],
- }],
- ],
- },
- ],
-}
diff --git a/chromium/components/rlz/BUILD.gn b/chromium/components/rlz/BUILD.gn
index 72e0efb6ab5..9514a46bafa 100644
--- a/chromium/components/rlz/BUILD.gn
+++ b/chromium/components/rlz/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("rlz") {
+static_library("rlz") {
sources = [
"rlz_tracker.cc",
"rlz_tracker.h",
diff --git a/chromium/components/safe_browsing_db.gypi b/chromium/components/safe_browsing_db.gypi
deleted file mode 100644
index 94f4af09b34..00000000000
--- a/chromium/components/safe_browsing_db.gypi
+++ /dev/null
@@ -1,144 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/safe_browsing_db:safe_browsing_db_shared
- 'target_name': 'safe_browsing_db_shared',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../components/components.gyp:metrics',
- '../crypto/crypto.gyp:crypto',
- ':safebrowsing_proto',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'safe_browsing_db/database_manager.h',
- 'safe_browsing_db/database_manager.cc',
- 'safe_browsing_db/hit_report.h',
- 'safe_browsing_db/hit_report.cc',
- 'safe_browsing_db/prefix_set.h',
- 'safe_browsing_db/prefix_set.cc',
- 'safe_browsing_db/util.h',
- 'safe_browsing_db/util.cc',
- 'safe_browsing_db/v4_protocol_manager_util.h',
- 'safe_browsing_db/v4_protocol_manager_util.cc',
- 'safe_browsing_db/v4_get_hash_protocol_manager.h',
- 'safe_browsing_db/v4_get_hash_protocol_manager.cc',
- ],
- 'include_dirs': [
- '..',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- # GN version: //components/safe_browsing_db
- 'target_name': 'safe_browsing_db',
- 'type': 'static_library',
- 'dependencies': [
- ':safe_browsing_db_shared',
- ':v4_store_proto',
- ],
- 'sources': [
- 'safe_browsing_db/v4_database.h',
- 'safe_browsing_db/v4_database.cc',
- 'safe_browsing_db/v4_local_database_manager.h',
- 'safe_browsing_db/v4_local_database_manager.cc',
- 'safe_browsing_db/v4_store.h',
- 'safe_browsing_db/v4_store.cc',
- 'safe_browsing_db/v4_update_protocol_manager.h',
- 'safe_browsing_db/v4_update_protocol_manager.cc',
- ],
- 'include_dirs': [
- '..',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- # GN version: //components/safe_browsing_db:safe_browsing_db_mobile
- 'target_name': 'safe_browsing_db_mobile',
- 'type': 'static_library',
- 'dependencies': [
- ':safe_browsing_db_shared',
- ':safe_browsing_metadata_proto',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'safe_browsing_db/remote_database_manager.h',
- 'safe_browsing_db/remote_database_manager.cc',
- 'safe_browsing_db/safe_browsing_api_handler.h',
- 'safe_browsing_db/safe_browsing_api_handler.cc',
- 'safe_browsing_db/safe_browsing_api_handler_util.h',
- 'safe_browsing_db/safe_browsing_api_handler_util.cc',
- ],
- 'include_dirs': [
- '..',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- # GN version: //components/safe_browsing_db:safebrowsing_proto
- # Protobuf compiler / generator for the Safe Browsing protocol buffer.
- 'target_name': 'safebrowsing_proto',
- 'type': 'static_library',
- 'sources': [ 'safe_browsing_db/safebrowsing.proto' ],
- 'variables': {
- 'proto_in_dir': 'safe_browsing_db',
- 'proto_out_dir': 'components/safe_browsing_db',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
- {
- # Protobuf compiler / generator for the safebrowsing full hash metadata
- # protocol buffer.
- # GN version: //components/safe_browsing_db:metadata_proto
- 'target_name': 'safe_browsing_metadata_proto',
- 'type': 'static_library',
- 'sources': [ 'safe_browsing_db/metadata.proto' ],
- 'variables': {
- 'proto_in_dir': 'safe_browsing_db',
- 'proto_out_dir': 'components/safe_browsing_db',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
- {
- # GN version: //components/safe_browsing_db:v4_store_proto
- # Protobuf compiler / generator for the Safe Browsing protocol buffer for
- # storing hash-prefixes on disk.
- 'target_name': 'v4_store_proto',
- 'type': 'static_library',
- 'dependencies': [
- ':safebrowsing_proto',
- ],
- 'sources': [ 'safe_browsing_db/v4_store.proto' ],
- 'variables': {
- 'proto_in_dir': 'safe_browsing_db',
- 'proto_out_dir': 'components/safe_browsing_db',
- },
- 'includes': [ '../build/protoc.gypi' ]
- },
- {
- # GN version: //components/safe_browsing_db:test_database_manager
- 'target_name': 'test_database_manager',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- ':safe_browsing_db',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'safe_browsing_db/test_database_manager.h',
- 'safe_browsing_db/test_database_manager.cc',
- ],
- 'include_dirs': [
- '..',
- ],
- },
- ],
-}
diff --git a/chromium/components/safe_browsing_db/BUILD.gn b/chromium/components/safe_browsing_db/BUILD.gn
index 39bcb413d2f..e14da2e5b0c 100644
--- a/chromium/components/safe_browsing_db/BUILD.gn
+++ b/chromium/components/safe_browsing_db/BUILD.gn
@@ -19,7 +19,6 @@ proto_library("v4_store_proto") {
]
}
-# GYP version: components/safe_browsing_db.gypi:safe_browsing_metadata_proto
proto_library("metadata_proto") {
sources = [
"metadata.proto",
@@ -42,7 +41,6 @@ group("safe_browsing_db") {
deps = [
":safe_browsing_db_shared",
":v4_local_database_manager",
- ":v4_update_protocol_manager",
]
}
@@ -56,7 +54,7 @@ group("safe_browsing_db_mobile") {
]
}
-source_set("database_manager") {
+static_library("database_manager") {
sources = [
"database_manager.cc",
"database_manager.h",
@@ -65,27 +63,28 @@ source_set("database_manager") {
":hit_report",
":util",
":v4_get_hash_protocol_manager",
- "//base:base",
+ ":v4_protocol_manager_util",
+ "//base",
"//content/public/browser",
"//content/public/common",
"//net",
- "//url:url",
+ "//url",
]
}
-source_set("hit_report") {
+static_library("hit_report") {
sources = [
"hit_report.cc",
"hit_report.h",
]
deps = [
":util",
- "//components/metrics:metrics",
- "//url:url",
+ "//components/metrics",
+ "//url",
]
}
-source_set("prefix_set") {
+static_library("prefix_set") {
sources = [
"prefix_set.cc",
"prefix_set.h",
@@ -96,7 +95,7 @@ source_set("prefix_set") {
]
}
-source_set("remote_database_manager") {
+static_library("remote_database_manager") {
sources = [
"remote_database_manager.cc",
"remote_database_manager.h",
@@ -109,7 +108,7 @@ source_set("remote_database_manager") {
"//components/variations",
"//content/public/browser",
"//net",
- "//url:url",
+ "//url",
]
}
@@ -120,12 +119,12 @@ source_set("safe_browsing_api_handler") {
]
deps = [
":util",
- "//base:base",
- "//url:url",
+ "//base",
+ "//url",
]
}
-source_set("safe_browsing_api_handler_util") {
+static_library("safe_browsing_api_handler_util") {
sources = [
"safe_browsing_api_handler_util.cc",
"safe_browsing_api_handler_util.h",
@@ -133,11 +132,11 @@ source_set("safe_browsing_api_handler_util") {
deps = [
":metadata_proto",
":util",
- "//base:base",
+ "//base",
]
}
-source_set("test_database_manager") {
+static_library("test_database_manager") {
sources = [
"test_database_manager.cc",
"test_database_manager.h",
@@ -149,17 +148,19 @@ source_set("test_database_manager") {
]
}
-source_set("util") {
+static_library("util") {
sources = [
"util.cc",
"util.h",
]
+ public_deps = [
+ ":v4_protocol_manager_util",
+ ]
deps = [
"//base",
- "//base:base",
"//crypto",
"//net",
- "//url:url",
+ "//url",
]
if (is_win) {
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
@@ -167,7 +168,7 @@ source_set("util") {
}
}
-source_set("v4_database") {
+static_library("v4_database") {
sources = [
"v4_database.cc",
"v4_database.h",
@@ -183,7 +184,17 @@ source_set("v4_database") {
]
}
-source_set("v4_get_hash_protocol_manager") {
+static_library("v4_feature_list") {
+ sources = [
+ "v4_feature_list.cc",
+ "v4_feature_list.h",
+ ]
+ deps = [
+ "//base",
+ ]
+}
+
+static_library("v4_get_hash_protocol_manager") {
sources = [
"v4_get_hash_protocol_manager.cc",
"v4_get_hash_protocol_manager.h",
@@ -195,12 +206,13 @@ source_set("v4_get_hash_protocol_manager") {
":util",
":v4_protocol_manager_util",
"//base",
+ "//content/public/browser",
"//net",
- "//url:url",
+ "//url",
]
}
-source_set("v4_local_database_manager") {
+static_library("v4_local_database_manager") {
sources = [
"v4_local_database_manager.cc",
"v4_local_database_manager.h",
@@ -210,12 +222,14 @@ source_set("v4_local_database_manager") {
":hit_report",
":safebrowsing_proto",
":v4_database",
+ ":v4_feature_list",
+ ":v4_get_hash_protocol_manager",
":v4_protocol_manager_util",
":v4_update_protocol_manager",
"//base",
"//content/public/browser",
"//net",
- "//url:url",
+ "//url",
]
}
@@ -224,11 +238,24 @@ source_set("v4_protocol_manager_util") {
"v4_protocol_manager_util.cc",
"v4_protocol_manager_util.h",
]
- deps = [
+ public_deps = [
":safebrowsing_proto",
+ ]
+ deps = [
"//base",
"//net",
- "//url:url",
+ "//url",
+ ]
+}
+
+source_set("v4_rice") {
+ sources = [
+ "v4_rice.cc",
+ "v4_rice.h",
+ ]
+ deps = [
+ "//base",
+ "//third_party/protobuf:protobuf_lite",
]
}
@@ -243,11 +270,13 @@ source_set("v4_store") {
]
deps = [
":v4_protocol_manager_util",
+ ":v4_rice",
"//base",
+ "//crypto",
]
}
-source_set("v4_update_protocol_manager") {
+static_library("v4_update_protocol_manager") {
sources = [
"v4_update_protocol_manager.cc",
"v4_update_protocol_manager.h",
@@ -257,8 +286,61 @@ source_set("v4_update_protocol_manager") {
":util",
":v4_protocol_manager_util",
"//base",
+ "//components/data_use_measurement/core",
+ "//net",
+ "//url",
+ ]
+}
+
+source_set("v4_database_unittest") {
+ testonly = true
+ sources = [
+ "v4_database_unittest.cc",
+ ]
+ deps = [
+ ":v4_database",
+ ":v4_store",
+ "//base",
+ "//base/test:test_support",
+ "//content/test:test_support",
+ "//testing/gtest",
+ ]
+}
+
+source_set("v4_get_hash_protocol_manager_unittest") {
+ testonly = true
+ sources = [
+ "v4_get_hash_protocol_manager_unittest.cc",
+ ]
+ deps = [
+ ":safebrowsing_proto",
+ ":util",
+ ":v4_database",
+ ":v4_get_hash_protocol_manager",
+ ":v4_local_database_manager",
+ "//base",
+ "//base/test:test_support",
+ "//content/test:test_support",
+ "//net",
+ "//net:test_support",
+ "//testing/gtest",
+ ]
+}
+
+source_set("v4_local_database_manager_unittest") {
+ testonly = true
+ sources = [
+ "v4_local_database_manager_unittest.cc",
+ ]
+ deps = [
+ ":v4_database",
+ ":v4_local_database_manager",
+ "//base",
+ "//base/test:test_support",
+ "//content/test:test_support",
"//net",
- "//url:url",
+ "//net:test_support",
+ "//testing/gtest",
]
}
@@ -270,7 +352,9 @@ source_set("unit_tests") {
"util_unittest.cc",
"v4_database_unittest.cc",
"v4_get_hash_protocol_manager_unittest.cc",
+ "v4_local_database_manager_unittest.cc",
"v4_protocol_manager_util_unittest.cc",
+ "v4_rice_unittest.cc",
"v4_store_unittest.cc",
"v4_update_protocol_manager_unittest.cc",
]
@@ -284,11 +368,13 @@ source_set("unit_tests") {
":v4_get_hash_protocol_manager",
":v4_local_database_manager",
":v4_protocol_manager_util",
+ ":v4_rice",
":v4_store",
":v4_store_proto",
":v4_update_protocol_manager",
"//base",
"//content/test:test_support",
+ "//crypto",
"//net",
"//net:test_support",
"//testing/gtest",
diff --git a/chromium/components/safe_browsing_db/DEPS b/chromium/components/safe_browsing_db/DEPS
index 2130e6f111b..9d835a18bfe 100644
--- a/chromium/components/safe_browsing_db/DEPS
+++ b/chromium/components/safe_browsing_db/DEPS
@@ -1,8 +1,10 @@
include_rules = [
+ "+components/data_use_measurement/core",
"+components/variations",
"+content/public/browser",
"+content/public/common",
"+content/public/test",
"+crypto",
+ "+third_party/protobuf/src/google",
"+net",
]
diff --git a/chromium/components/safe_browsing_db/database_manager.cc b/chromium/components/safe_browsing_db/database_manager.cc
index c9821b1a794..91e4d7b6bbd 100644
--- a/chromium/components/safe_browsing_db/database_manager.cc
+++ b/chromium/components/safe_browsing_db/database_manager.cc
@@ -4,7 +4,9 @@
#include "components/safe_browsing_db/database_manager.h"
+#include "base/metrics/histogram_macros.h"
#include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
+#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
@@ -13,61 +15,16 @@ using content::BrowserThread;
namespace safe_browsing {
-SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager()
- : v4_get_hash_protocol_manager_(NULL) {
-}
+SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager() {}
SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
- DCHECK(v4_get_hash_protocol_manager_ == NULL);
-}
-
-void SafeBrowsingDatabaseManager::StartOnIOThread(
- net::URLRequestContextGetter* request_context_getter,
- const V4ProtocolConfig& config) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- v4_get_hash_protocol_manager_ = V4GetHashProtocolManager::Create(
- request_context_getter, config);
-}
-
-// |shutdown| not used. Destroys the v4 protocol managers. This may be called
-// multiple times during the life of the DatabaseManager.
-// Must be called on IO thread.
-void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // This cancels all in-flight GetHash requests.
- if (v4_get_hash_protocol_manager_) {
- delete v4_get_hash_protocol_manager_;
- v4_get_hash_protocol_manager_ = NULL;
- }
-
- // Delete pending checks, calling back any clients with empty metadata.
- for (auto check : api_checks_) {
- if (check->client()) {
- check->client()->
- OnCheckApiBlacklistUrlResult(check->url(), ThreatMetadata());
- }
- }
- STLDeleteElements(&api_checks_);
-}
-
-SafeBrowsingDatabaseManager::ApiCheckSet::iterator
-SafeBrowsingDatabaseManager::FindClientApiCheck(Client* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- for (ApiCheckSet::iterator it = api_checks_.begin();
- it != api_checks_.end(); ++it) {
- if ((*it)->client() == client) {
- return it;
- }
- }
- return api_checks_.end();
+ DCHECK(!v4_get_hash_protocol_manager_);
}
bool SafeBrowsingDatabaseManager::CancelApiCheck(Client* client) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
ApiCheckSet::iterator it = FindClientApiCheck(client);
if (it != api_checks_.end()) {
- delete *it;
api_checks_.erase(it);
return true;
}
@@ -88,214 +45,80 @@ bool SafeBrowsingDatabaseManager::CheckApiBlacklistUrl(const GURL& url,
// There can only be one in-progress check for the same client at a time.
DCHECK(FindClientApiCheck(client) == api_checks_.end());
- // Compute a list of hashes for this url.
- std::vector<SBFullHash> full_hashes;
- UrlToFullHashes(url, false, &full_hashes);
- if (full_hashes.empty())
- return true;
-
- // First check the cache.
-
- // Used to determine cache expiration.
- base::Time now = base::Time::Now();
-
- std::vector<SBFullHashResult> cached_results;
- std::vector<SBPrefix> prefixes_needing_reqs;
- GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE,
- full_hashes, now, &prefixes_needing_reqs, &cached_results);
-
- if (prefixes_needing_reqs.empty() && cached_results.empty())
- return true;
-
- SafeBrowsingApiCheck* check =
- new SafeBrowsingApiCheck(url, prefixes_needing_reqs, full_hashes,
- cached_results, client);
- api_checks_.insert(check);
-
- if (prefixes_needing_reqs.empty()) {
- // We can call the callback immediately if no prefixes require a request.
- // The |full_hash_results| representing the results fromt eh SB server will
- // be empty.
- std::vector<SBFullHashResult> full_hash_results;
- HandleGetHashesWithApisResults(check, full_hash_results, base::Time());
- return false;
- }
-
- v4_get_hash_protocol_manager_->GetFullHashesWithApis(prefixes_needing_reqs,
- base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashesWithApisResults,
- base::Unretained(this), check));
+ std::unique_ptr<SafeBrowsingApiCheck> check(
+ new SafeBrowsingApiCheck(url, client));
+ api_checks_.insert(check.get());
+ v4_get_hash_protocol_manager_->GetFullHashesWithApis(
+ url, base::Bind(&SafeBrowsingDatabaseManager::OnThreatMetadataResponse,
+ base::Unretained(this), base::Passed(std::move(check))));
return false;
}
-void SafeBrowsingDatabaseManager::GetFullHashCachedResults(
- const SBThreatType& threat_type,
- const std::vector<SBFullHash>& full_hashes,
- base::Time now,
- std::vector<SBPrefix>* prefixes_needing_reqs,
- std::vector<SBFullHashResult>* cached_results) {
- DCHECK(prefixes_needing_reqs);
- prefixes_needing_reqs->clear();
- DCHECK(cached_results);
- cached_results->clear();
-
- // Caching behavior is documented here:
- // https://developers.google.com/safe-browsing/v4/caching#about-caching
- //
- // The cache operates as follows:
- // Lookup:
- // Case 1: The prefix is in the cache.
- // Case a: The full hash is in the cache.
- // Case i : The positive full hash result has not expired.
- // The result is unsafe and we do not need to send a new
- // request.
- // Case ii: The positive full hash result has expired.
- // We need to send a request for full hashes.
- // Case b: The full hash is not in the cache.
- // Case i : The negative cache entry has not expired.
- // The result is still safe and we do not need to send a
- // new request.
- // Case ii: The negative cache entry has expired.
- // We need to send a request for full hashes.
- // Case 2: The prefix is not in the cache.
- // We need to send a request for full hashes.
- //
- // Eviction:
- // SBCachedFullHashResult entries can be removed from the cache only when
- // the negative cache expire time and the cache expire time of all full
- // hash results for that prefix have expired.
- // Individual full hash results can be removed from the prefix's
- // cache entry if they expire AND their expire time is after the negative
- // cache expire time.
- for (const SBFullHash& full_hash : full_hashes) {
- auto entry = v4_full_hash_cache_[threat_type].find(full_hash.prefix);
- if (entry != v4_full_hash_cache_[threat_type].end()) {
- // Case 1.
- SBCachedFullHashResult& cache_result = entry->second;
-
- const SBFullHashResult* found_full_hash = nullptr;
- size_t matched_idx = 0;
- for (const SBFullHashResult& hash_result : cache_result.full_hashes) {
- if (SBFullHashEqual(full_hash, hash_result.hash)) {
- found_full_hash = &hash_result;
- break;
- }
- ++matched_idx;
- }
-
- if (found_full_hash) {
- // Case a.
- if (found_full_hash->cache_expire_after > now) {
- // Case i.
- cached_results->push_back(*found_full_hash);
- } else {
- // Case ii.
- prefixes_needing_reqs->push_back(full_hash.prefix);
- // If the negative cache expire time has passed, evict this full hash
- // result from the cache.
- if (cache_result.expire_after <= now) {
- cache_result.full_hashes.erase(
- cache_result.full_hashes.begin() + matched_idx);
- // If there are no more full hashes, we can evict the entire entry.
- if (cache_result.full_hashes.empty()) {
- v4_full_hash_cache_[threat_type].erase(entry);
- }
- }
- }
- } else {
- // Case b.
- if (cache_result.expire_after > now) {
- // Case i.
- } else {
- // Case ii.
- prefixes_needing_reqs->push_back(full_hash.prefix);
- }
- }
- } else {
- // Case 2.
- prefixes_needing_reqs->push_back(full_hash.prefix);
+SafeBrowsingDatabaseManager::ApiCheckSet::iterator
+SafeBrowsingDatabaseManager::FindClientApiCheck(Client* client) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ for (ApiCheckSet::iterator it = api_checks_.begin(); it != api_checks_.end();
+ ++it) {
+ if ((*it)->client() == client) {
+ return it;
}
}
+ return api_checks_.end();
+}
- // Multiple full hashes could share a prefix, remove duplicates.
- // TODO(kcarattini): Make |prefixes_needing_reqs| a set.
- std::sort(prefixes_needing_reqs->begin(), prefixes_needing_reqs->end());
- prefixes_needing_reqs->erase(std::unique(prefixes_needing_reqs->begin(),
- prefixes_needing_reqs->end()), prefixes_needing_reqs->end());
+StoresToCheck SafeBrowsingDatabaseManager::GetStoresForFullHashRequests() {
+ return StoresToCheck({GetChromeUrlApiId()});
}
-void SafeBrowsingDatabaseManager::HandleGetHashesWithApisResults(
- SafeBrowsingApiCheck* check,
- const std::vector<SBFullHashResult>& full_hash_results,
- const base::Time& negative_cache_expire) {
+void SafeBrowsingDatabaseManager::OnThreatMetadataResponse(
+ std::unique_ptr<SafeBrowsingApiCheck> check,
+ const ThreatMetadata& md) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(check);
- // If the time is uninitialized, don't cache the results.
- if (!negative_cache_expire.is_null()) {
- // Cache the results.
- // Create or reset all cached results for this prefix.
- for (const SBPrefix& prefix : check->prefixes()) {
- v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE][prefix] =
- SBCachedFullHashResult(negative_cache_expire);
- }
- // Insert any full hash hits. Note that there may be one, multiple, or no
- // full hashes for any given prefix.
- for (const SBFullHashResult& result : full_hash_results) {
- v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE][result.hash.prefix].
- full_hashes.push_back(result);
- }
- }
-
// If the check is not in |api_checks_| then the request was cancelled by the
// client.
- ApiCheckSet::iterator it = api_checks_.find(check);
+ ApiCheckSet::iterator it = api_checks_.find(check.get());
if (it == api_checks_.end())
return;
- ThreatMetadata md;
- // Merge the metadata from all matching results.
- // Note: A full hash may have a result in both the cached results (from
- // its own cache lookup) and in the server results (if another full hash
- // with the same prefix needed to request results from the server). In this
- // unlikely case, the two results' metadata will be merged.
- PopulateApiMetadataResult(full_hash_results, check->full_hashes(), &md);
- PopulateApiMetadataResult(check->cached_results(), check->full_hashes(), &md);
-
check->client()->OnCheckApiBlacklistUrlResult(check->url(), md);
api_checks_.erase(it);
- delete check;
}
-// TODO(kcarattini): This is O(N^2). Look at improving performance by
-// using a map, sorting or doing binary search etc..
-void SafeBrowsingDatabaseManager::PopulateApiMetadataResult(
- const std::vector<SBFullHashResult>& results,
- const std::vector<SBFullHash>& full_hashes,
- ThreatMetadata* md) {
- DCHECK(md);
- for (const SBFullHashResult& result : results) {
- for (const SBFullHash& full_hash : full_hashes) {
- if (SBFullHashEqual(full_hash, result.hash)) {
- md->api_permissions.insert(result.metadata.api_permissions.begin(),
- result.metadata.api_permissions.end());
- break;
- }
+void SafeBrowsingDatabaseManager::StartOnIOThread(
+ net::URLRequestContextGetter* request_context_getter,
+ const V4ProtocolConfig& config) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ v4_get_hash_protocol_manager_ = V4GetHashProtocolManager::Create(
+ request_context_getter, GetStoresForFullHashRequests(), config);
+}
+
+// |shutdown| not used. Destroys the v4 protocol managers. This may be called
+// multiple times during the life of the DatabaseManager.
+// Must be called on IO thread.
+void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Delete pending checks, calling back any clients with empty metadata.
+ for (const SafeBrowsingApiCheck* check : api_checks_) {
+ if (check->client()) {
+ check->client()->OnCheckApiBlacklistUrlResult(check->url(),
+ ThreatMetadata());
}
}
+
+ // This cancels all in-flight GetHash requests.
+ v4_get_hash_protocol_manager_.reset();
}
SafeBrowsingDatabaseManager::SafeBrowsingApiCheck::SafeBrowsingApiCheck(
const GURL& url,
- const std::vector<SBPrefix>& prefixes,
- const std::vector<SBFullHash>& full_hashes,
- const std::vector<SBFullHashResult>& cached_results,
Client* client)
- : url_(url), prefixes_(prefixes), full_hashes_(full_hashes),
- cached_results_(cached_results), client_(client) {
-}
+ : url_(url), client_(client) {}
-SafeBrowsingDatabaseManager::SafeBrowsingApiCheck::~SafeBrowsingApiCheck() {
-}
+SafeBrowsingDatabaseManager::SafeBrowsingApiCheck::~SafeBrowsingApiCheck() {}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/database_manager.h b/chromium/components/safe_browsing_db/database_manager.h
index d6f5f2c82e6..0d24b8bf3f4 100644
--- a/chromium/components/safe_browsing_db/database_manager.h
+++ b/chromium/components/safe_browsing_db/database_manager.h
@@ -8,10 +8,9 @@
#ifndef COMPONENTS_SAFE_BROWSING_DB_DATABASE_MANAGER_H_
#define COMPONENTS_SAFE_BROWSING_DB_DATABASE_MANAGER_H_
-#include <deque>
-#include <map>
#include <set>
#include <string>
+#include <unordered_set>
#include <vector>
#include "base/gtest_prod_util.h"
@@ -28,6 +27,7 @@ class URLRequestContextGetter;
namespace safe_browsing {
+struct ListIdentifier;
struct V4ProtocolConfig;
class V4GetHashProtocolManager;
@@ -42,6 +42,11 @@ class SafeBrowsingDatabaseManager
public:
virtual ~Client() {}
+ // Called when the result of checking the API blacklist is known.
+ // TODO(kcarattini): Consider if we need |url| passed here, remove if not.
+ virtual void OnCheckApiBlacklistUrlResult(const GURL& url,
+ const ThreatMetadata& metadata) {}
+
// Called when the result of checking a browse URL is known.
virtual void OnCheckBrowseUrlResult(const GURL& url,
SBThreatType threat_type,
@@ -55,27 +60,29 @@ class SafeBrowsingDatabaseManager
virtual void OnCheckExtensionsResult(
const std::set<std::string>& threats) {}
- // Called when the result of checking the API blacklist is known.
- // TODO(kcarattini): Consider if we need |url| passed here, remove if not.
- virtual void OnCheckApiBlacklistUrlResult(const GURL& url,
- const ThreatMetadata& metadata) {}
-
// Called when the result of checking the resource blacklist is known.
virtual void OnCheckResourceUrlResult(const GURL& url,
SBThreatType threat_type,
const std::string& threat_hash) {}
};
- // Returns true if URL-checking is supported on this build+device.
- // If false, calls to CheckBrowseUrl may dcheck-fail.
- virtual bool IsSupported() const = 0;
+ //
+ // Methods called by the client to cancel pending checks.
+ //
- // Returns the ThreatSource for this implementation.
- virtual ThreatSource GetThreatSource() const = 0;
+ // Called on the IO thread to cancel a pending API check if the result is no
+ // longer needed. Returns true if the client was found and the check
+ // successfully cancelled.
+ virtual bool CancelApiCheck(Client* client);
- // Returns true if checks are never done synchronously, and therefore
- // always have some latency.
- virtual bool ChecksAreAlwaysAsync() const = 0;
+ // Called on the IO thread to cancel a pending check if the result is no
+ // longer needed. Also called after the result has been handled. Api checks
+ // are handled separately. To cancel an API check use CancelApiCheck.
+ virtual void CancelCheck(Client* client) = 0;
+
+ //
+ // Methods to check whether the database manager supports a certain feature.
+ //
// Returns true if this resource type should be checked.
virtual bool CanCheckResourceType(
@@ -84,8 +91,26 @@ class SafeBrowsingDatabaseManager
// Returns true if the url's scheme can be checked.
virtual bool CanCheckUrl(const GURL& url) const = 0;
- // Returns whether download protection is enabled.
- virtual bool IsDownloadProtectionEnabled() const = 0;
+ // Returns true if checks are never done synchronously, and therefore
+ // always have some latency.
+ virtual bool ChecksAreAlwaysAsync() const = 0;
+
+ //
+ // Methods to check (possibly asynchronously) whether a given resource is
+ // safe. If the database manager can't determine it synchronously, the
+ // appropriate method on the |client| is called back when the reputation of
+ // the resource is known.
+ //
+
+ // Called on the IO thread to check if the given url has blacklisted APIs.
+ // "client" is called asynchronously with the result when it is ready. Callers
+ // should wait for results before calling this method a second time with the
+ // same client. This method has the same implementation for both the local and
+ // remote database managers since it pings Safe Browsing servers directly
+ // without accessing the database at all. Returns true if we can
+ // synchronously determine that the url is safe. Otherwise it returns false,
+ // and "client" is called asynchronously with the result when it is ready.
+ virtual bool CheckApiBlacklistUrl(const GURL& url, Client* client);
// Called on the IO thread to check if the given url is safe or not. If we
// can synchronously determine that the url is safe, CheckUrl returns true.
@@ -109,27 +134,32 @@ class SafeBrowsingDatabaseManager
// to callback in |client|.
virtual bool CheckResourceUrl(const GURL& url, Client* client) = 0;
+ //
+ // Methods to synchronously check whether a URL, or full hash, or IP address
+ // or a DLL file is safe.
+ //
+
// Check if the |url| matches any of the full-length hashes from the client-
// side phishing detection whitelist. Returns true if there was a match and
// false otherwise. To make sure we are conservative we will return true if
// an error occurs. This method must be called on the IO thread.
virtual bool MatchCsdWhitelistUrl(const GURL& url) = 0;
- // Check if the given IP address (either IPv4 or IPv6) matches the malware
- // IP blacklist.
- virtual bool MatchMalwareIP(const std::string& ip_address) = 0;
-
- // Check if the |url| matches any of the full-length hashes from the download
+ // Check if |str| matches any of the full-length hashes from the download
// whitelist. Returns true if there was a match and false otherwise. To make
// sure we are conservative we will return true if an error occurs. This
// method must be called on the IO thread.
- virtual bool MatchDownloadWhitelistUrl(const GURL& url) = 0;
+ virtual bool MatchDownloadWhitelistString(const std::string& str) = 0;
- // Check if |str| matches any of the full-length hashes from the download
+ // Check if the |url| matches any of the full-length hashes from the download
// whitelist. Returns true if there was a match and false otherwise. To make
// sure we are conservative we will return true if an error occurs. This
// method must be called on the IO thread.
- virtual bool MatchDownloadWhitelistString(const std::string& str) = 0;
+ virtual bool MatchDownloadWhitelistUrl(const GURL& url) = 0;
+
+ // Check if the given IP address (either IPv4 or IPv6) matches the malware
+ // IP blacklist.
+ virtual bool MatchMalwareIP(const std::string& ip_address) = 0;
// Check if |str|, a lowercase DLL file name, matches any of the full-length
// hashes from the module whitelist. Returns true if there was a match and
@@ -137,31 +167,33 @@ class SafeBrowsingDatabaseManager
// an error occurs. This method must be called on the IO thread.
virtual bool MatchModuleWhitelistString(const std::string& str) = 0;
- // Check if the CSD malware IP matching kill switch is turned on.
- virtual bool IsMalwareKillSwitchOn() = 0;
+ //
+ // Methods to check the config of the DatabaseManager.
+ //
+
+ // Returns the lists that this DatabaseManager should get full hashes for.
+ virtual StoresToCheck GetStoresForFullHashRequests();
+
+ // Returns the ThreatSource for this implementation.
+ virtual ThreatSource GetThreatSource() const = 0;
// Check if the CSD whitelist kill switch is turned on.
virtual bool IsCsdWhitelistKillSwitchOn() = 0;
- // Called on the IO thread to cancel a pending check if the result is no
- // longer needed. Also called after the result has been handled. Api checks
- // are handled separately. To cancel an API check use CancelApiCheck.
- virtual void CancelCheck(Client* client) = 0;
+ // Returns whether download protection is enabled.
+ virtual bool IsDownloadProtectionEnabled() const = 0;
- // Called on the IO thread to cancel a pending API check if the result is no
- // longer needed. Returns true if the client was found and the check
- // successfully cancelled.
- virtual bool CancelApiCheck(Client* client);
+ // Check if the CSD malware IP matching kill switch is turned on.
+ virtual bool IsMalwareKillSwitchOn() = 0;
- // Called on the IO thread to check if the given url has blacklisted APIs.
- // "client" is called asynchronously with the result when it is ready. Callers
- // should wait for results before calling this method a second time with the
- // same client. This method has the same implementation for both the local and
- // remote database managers since it pings Safe Browsing servers directly
- // without accessing the database at all. Returns true if we can
- // synchronously determine that the url is safe. Otherwise it returns false,
- // and "client" is called asynchronously with the result when it is ready.
- virtual bool CheckApiBlacklistUrl(const GURL& url, Client* client);
+ // Returns true if URL-checking is supported on this build+device.
+ // If false, calls to CheckBrowseUrl may dcheck-fail.
+ virtual bool IsSupported() const = 0;
+
+ //
+ // Methods to indicate when to start or suspend the SafeBrowsing operations.
+ // These functions are always called on the IO thread.
+ //
// Called to initialize objects that are used on the io_thread, such as the
// v4 protocol manager. This may be called multiple times during the life of
@@ -177,35 +209,17 @@ class SafeBrowsingDatabaseManager
// Bundled client info for an API abuse hash prefix check.
class SafeBrowsingApiCheck {
public:
- SafeBrowsingApiCheck(const GURL& url,
- const std::vector<SBPrefix>& prefixes,
- const std::vector<SBFullHash>& full_hashes,
- const std::vector<SBFullHashResult>& cached_results,
- Client* client);
+ SafeBrowsingApiCheck(const GURL& url, Client* client);
~SafeBrowsingApiCheck();
- const GURL& url() {return url_;}
- const std::vector<SBPrefix>& prefixes() {return prefixes_;}
- const std::vector<SBFullHash>& full_hashes() {return full_hashes_;}
- const std::vector<SBFullHashResult>& cached_results() {
- return cached_results_;
- }
- SafeBrowsingDatabaseManager::Client* client() {return client_;}
+ const GURL& url() const { return url_; }
+ Client* client() const { return client_; }
private:
GURL url_;
- // Prefixes that were requested in this check.
- std::vector<SBPrefix> prefixes_;
-
- // Full hashes for this check.
- std::vector<SBFullHash> full_hashes_;
-
- // Cached results for this check.
- std::vector<SBFullHashResult> cached_results_;
-
// Not owned.
- SafeBrowsingDatabaseManager::Client* client_;
+ Client* client_;
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingApiCheck);
};
@@ -237,45 +251,20 @@ class SafeBrowsingDatabaseManager
FRIEND_TEST_ALL_PREFIXES(SafeBrowsingDatabaseManagerTest,
CachedResultsAreEvicted);
- typedef std::set<SafeBrowsingApiCheck*> ApiCheckSet;
- typedef std::map<SBPrefix, SBCachedFullHashResult> PrefixToFullHashResultsMap;
- typedef std::map<SBThreatType, PrefixToFullHashResultsMap>
- ThreatTypeToResultsMap;
-
- // Called on the IO thread wheh the SafeBrowsingProtocolManager has received
+ // Called on the IO thread when the SafeBrowsingProtocolManager has received
// the full hash and api results for prefixes of the |url| argument in
// CheckApiBlacklistUrl.
- virtual void HandleGetHashesWithApisResults(
- SafeBrowsingApiCheck* check,
- const std::vector<SBFullHashResult>& full_hash_results,
- const base::Time& negative_cache_expire);
-
- // Looks up the cached results for |threat_type|. Fills |prefixes| with the
- // prefixes that need a request. Fills |cached_results| with the cached
- // results.
- void GetFullHashCachedResults(const SBThreatType& threat_type,
- const std::vector<SBFullHash>& full_hashes,
- base::Time now,
- std::vector<SBPrefix>* prefixes,
- std::vector<SBFullHashResult>* cached_results);
-
- // Populates |md| with permission api metadata from all results that have a
- // match in |full_hashes|.
- void PopulateApiMetadataResult(const std::vector<SBFullHashResult>& results,
- const std::vector<SBFullHash>& full_hashes,
- ThreatMetadata* md);
+ void OnThreatMetadataResponse(std::unique_ptr<SafeBrowsingApiCheck> check,
+ const ThreatMetadata& md);
+
+ typedef std::set<SafeBrowsingApiCheck*> ApiCheckSet;
// In-progress checks. This set owns the SafeBrowsingApiCheck pointers and is
// responsible for deleting them when removing from the set.
ApiCheckSet api_checks_;
- // A cache of V4 full hash results for api checks.
- // TODO(kcarattini): Look into moving all caching logic to
- // V4GetHashProtocolManager.
- ThreatTypeToResultsMap v4_full_hash_cache_;
-
// Created and destroyed via StartOnIOThread/StopOnIOThread.
- V4GetHashProtocolManager* v4_get_hash_protocol_manager_;
+ std::unique_ptr<V4GetHashProtocolManager> v4_get_hash_protocol_manager_;
private:
// Returns an iterator to the pending API check with the given |client|.
diff --git a/chromium/components/safe_browsing_db/database_manager_unittest.cc b/chromium/components/safe_browsing_db/database_manager_unittest.cc
index 3c862e65bb8..21338b86012 100644
--- a/chromium/components/safe_browsing_db/database_manager_unittest.cc
+++ b/chromium/components/safe_browsing_db/database_manager_unittest.cc
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
+#include "base/base64.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -18,9 +19,12 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/safe_browsing_db/test_database_manager.h"
-#include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
+#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "crypto/sha2.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_fetcher_delegate.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -30,79 +34,6 @@ namespace safe_browsing {
namespace {
-void InvokeFullHashCallback(
- V4GetHashProtocolManager::FullHashCallback callback,
- const std::vector<SBFullHashResult>& full_hashes,
- base::Time negative_cache_expire) {
- callback.Run(full_hashes, negative_cache_expire);
-}
-
-// A TestV4GetHashProtocolManager that returns fixed responses from the
-// Safe Browsing server for testing purpose.
-class TestV4GetHashProtocolManager : public V4GetHashProtocolManager {
- public:
- TestV4GetHashProtocolManager(
- net::URLRequestContextGetter* request_context_getter,
- const V4ProtocolConfig& config)
- : V4GetHashProtocolManager(request_context_getter, config),
- negative_cache_expire_(base::Time()), delay_seconds_(0) {}
-
- ~TestV4GetHashProtocolManager() override {}
-
- void GetFullHashesWithApis(const std::vector<SBPrefix>& prefixes,
- FullHashCallback callback) override {
- prefixes_ = prefixes;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(InvokeFullHashCallback, callback, full_hashes_,
- negative_cache_expire_),
- base::TimeDelta::FromSeconds(delay_seconds_));
- }
-
- void SetDelaySeconds(int delay) {
- delay_seconds_ = delay;
- }
-
- void SetNegativeCacheDurationMins(base::Time now,
- int negative_cache_duration_mins) {
- // Don't add a TimeDelta to the maximum time to avoid undefined behavior.
- negative_cache_expire_ = now.is_max() ? now :
- now + base::TimeDelta::FromMinutes(negative_cache_duration_mins);
- }
-
- // Prepare the GetFullHash results for the next request.
- void AddGetFullHashResponse(const SBFullHashResult& full_hash_result) {
- full_hashes_.push_back(full_hash_result);
- }
-
- // Clear the GetFullHash results for the next request.
- void ClearFullHashResponse() {
- full_hashes_.clear();
- }
-
- // Returns the prefixes that were sent in the last request.
- const std::vector<SBPrefix>& GetRequestPrefixes() { return prefixes_; }
-
- private:
- std::vector<SBPrefix> prefixes_;
- std::vector<SBFullHashResult> full_hashes_;
- base::Time negative_cache_expire_;
- int delay_seconds_;
-};
-
-// Factory that creates test protocol manager instances.
-class TestV4GetHashProtocolManagerFactory :
- public V4GetHashProtocolManagerFactory {
- public:
- TestV4GetHashProtocolManagerFactory() {}
- ~TestV4GetHashProtocolManagerFactory() override {}
-
- V4GetHashProtocolManager* CreateProtocolManager(
- net::URLRequestContextGetter* request_context_getter,
- const V4ProtocolConfig& config) override {
- return new TestV4GetHashProtocolManager(request_context_getter, config);
- }
-};
-
class TestClient : public SafeBrowsingDatabaseManager::Client {
public:
TestClient() : callback_invoked_(false) {}
@@ -131,9 +62,6 @@ class TestClient : public SafeBrowsingDatabaseManager::Client {
class SafeBrowsingDatabaseManagerTest : public testing::Test {
protected:
void SetUp() override {
- V4GetHashProtocolManager::RegisterFactory(
- base::WrapUnique(new TestV4GetHashProtocolManagerFactory()));
-
db_manager_ = new TestSafeBrowsingDatabaseManager();
db_manager_->StartOnIOThread(NULL, V4ProtocolConfig());
}
@@ -141,7 +69,29 @@ class SafeBrowsingDatabaseManagerTest : public testing::Test {
void TearDown() override {
base::RunLoop().RunUntilIdle();
db_manager_->StopOnIOThread(false);
- V4GetHashProtocolManager::RegisterFactory(nullptr);
+ }
+
+ std::string GetStockV4GetHashResponse() {
+ ListIdentifier list_id = GetChromeUrlApiId();
+ FullHash full_hash = crypto::SHA256HashString("example.com/");
+
+ FindFullHashesResponse response;
+ response.mutable_negative_cache_duration()->set_seconds(600);
+ ThreatMatch* m = response.add_matches();
+ m->set_platform_type(list_id.platform_type());
+ m->set_threat_entry_type(list_id.threat_entry_type());
+ m->set_threat_type(list_id.threat_type());
+ m->mutable_threat()->set_hash(full_hash);
+ m->mutable_cache_duration()->set_seconds(300);
+
+ ThreatEntryMetadata::MetadataEntry* e =
+ m->mutable_threat_entry_metadata()->add_entries();
+ e->set_key("permission");
+ e->set_value("GEOLOCATION");
+
+ std::string res_data;
+ response.SerializeToString(&res_data);
+ return res_data;
}
scoped_refptr<SafeBrowsingDatabaseManager> db_manager_;
@@ -151,390 +101,50 @@ class SafeBrowsingDatabaseManagerTest : public testing::Test {
};
TEST_F(SafeBrowsingDatabaseManagerTest, CheckApiBlacklistUrlWrongScheme) {
- TestClient client;
- const GURL url("file://example.txt");
- EXPECT_TRUE(db_manager_->CheckApiBlacklistUrl(url, &client));
-}
-
-TEST_F(SafeBrowsingDatabaseManagerTest, CheckApiBlacklistUrlPrefixes) {
- TestClient client;
- const GURL url("https://www.example.com/more");
- // Generated from the sorted output of UrlToFullHashes in util.h.
- std::vector<SBPrefix> expected_prefixes =
- {1237562338, 2871045197, 3553205461, 3766933875};
-
- TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>(
- db_manager_->v4_get_hash_protocol_manager_);
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
- base::RunLoop().RunUntilIdle();
- std::vector<SBPrefix> prefixes = pm->GetRequestPrefixes();
- EXPECT_EQ(expected_prefixes.size(), prefixes.size());
- for (unsigned int i = 0; i < prefixes.size(); ++i) {
- EXPECT_EQ(expected_prefixes[i], prefixes[i]);
- }
-}
-
-TEST_F(SafeBrowsingDatabaseManagerTest, HandleGetHashesWithApisResults) {
- TestClient client;
- const GURL url("https://www.example.com/more");
- TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>(
- db_manager_->v4_get_hash_protocol_manager_);
- SBFullHashResult full_hash_result;
- full_hash_result.hash = SBFullHashForString("example.com/");
- full_hash_result.metadata.api_permissions.insert("GEOLOCATION");
- pm->AddGetFullHashResponse(full_hash_result);
-
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(client.callback_invoked());
- const std::set<std::string>& permissions = client.GetBlockedPermissions();
- EXPECT_EQ(1ul, permissions.size());
- EXPECT_EQ(1ul, permissions.count("GEOLOCATION"));
-}
-
-TEST_F(SafeBrowsingDatabaseManagerTest, HandleGetHashesWithApisResultsNoMatch) {
- TestClient client;
- const GURL url("https://www.example.com/more");
- TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>(
- db_manager_->v4_get_hash_protocol_manager_);
- SBFullHashResult full_hash_result;
- full_hash_result.hash = SBFullHashForString("wrongexample.com/");
- full_hash_result.metadata.api_permissions.insert("GEOLOCATION");
- pm->AddGetFullHashResponse(full_hash_result);
-
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(client.callback_invoked());
- const std::set<std::string>& permissions = client.GetBlockedPermissions();
- EXPECT_EQ(0ul, permissions.size());
-}
-
-TEST_F(SafeBrowsingDatabaseManagerTest, HandleGetHashesWithApisResultsMatches) {
- TestClient client;
- const GURL url("https://www.example.com/more");
- TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>(
- db_manager_->v4_get_hash_protocol_manager_);
- SBFullHashResult full_hash_result;
- full_hash_result.hash = SBFullHashForString("example.com/");
- full_hash_result.metadata.api_permissions.insert("GEOLOCATION");
- pm->AddGetFullHashResponse(full_hash_result);
- SBFullHashResult full_hash_result2;
- full_hash_result2.hash = SBFullHashForString("example.com/more");
- full_hash_result2.metadata.api_permissions.insert("NOTIFICATIONS");
- pm->AddGetFullHashResponse(full_hash_result2);
- SBFullHashResult full_hash_result3;
- full_hash_result3.hash = SBFullHashForString("wrongexample.com/");
- full_hash_result3.metadata.api_permissions.insert("AUDIO_CAPTURE");
- pm->AddGetFullHashResponse(full_hash_result3);
-
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(client.callback_invoked());
- const std::set<std::string>& permissions = client.GetBlockedPermissions();
- EXPECT_EQ(2ul, permissions.size());
- EXPECT_EQ(1ul, permissions.count("GEOLOCATION"));
- EXPECT_EQ(1ul, permissions.count("NOTIFICATIONS"));
+ EXPECT_TRUE(
+ db_manager_->CheckApiBlacklistUrl(GURL("file://example.txt"), nullptr));
}
TEST_F(SafeBrowsingDatabaseManagerTest, CancelApiCheck) {
+ net::TestURLFetcherFactory factory;
TestClient client;
const GURL url("https://www.example.com/more");
- TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>(
- db_manager_->v4_get_hash_protocol_manager_);
- SBFullHashResult full_hash_result;
- full_hash_result.hash = SBFullHashForString("example.com/");
- full_hash_result.metadata.api_permissions.insert("GEOLOCATION");
- pm->AddGetFullHashResponse(full_hash_result);
- pm->SetDelaySeconds(100);
EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
EXPECT_TRUE(db_manager_->CancelApiCheck(&client));
- base::RunLoop().RunUntilIdle();
- const std::set<std::string>& permissions = client.GetBlockedPermissions();
- EXPECT_EQ(0ul, permissions.size());
- EXPECT_FALSE(client.callback_invoked());
-}
+ net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
+ DCHECK(fetcher);
+ fetcher->set_status(net::URLRequestStatus());
+ fetcher->set_response_code(200);
+ fetcher->SetResponseString(GetStockV4GetHashResponse());
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
-TEST_F(SafeBrowsingDatabaseManagerTest, ResultsAreCached) {
- TestClient client;
- const GURL url("https://www.example.com/more");
- TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>(
- db_manager_->v4_get_hash_protocol_manager_);
- base::Time now = base::Time::UnixEpoch();
- SBFullHashResult full_hash_result;
- full_hash_result.hash = SBFullHashForString("example.com/");
- full_hash_result.metadata.api_permissions.insert("GEOLOCATION");
- full_hash_result.cache_expire_after = now + base::TimeDelta::FromMinutes(3);
- pm->AddGetFullHashResponse(full_hash_result);
- pm->SetNegativeCacheDurationMins(now, 5);
-
- EXPECT_TRUE(db_manager_->v4_full_hash_cache_.empty());
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(client.callback_invoked());
- const std::set<std::string>& permissions = client.GetBlockedPermissions();
- EXPECT_EQ(1ul, permissions.size());
- EXPECT_EQ(1ul, permissions.count("GEOLOCATION"));
-
- // Check the cache.
- const SafeBrowsingDatabaseManager::PrefixToFullHashResultsMap& cache =
- db_manager_->v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE];
- // Generated from the sorted output of UrlToFullHashes in util.h.
- std::vector<SBPrefix> expected_prefixes =
- {1237562338, 2871045197, 3553205461, 3766933875};
- EXPECT_EQ(expected_prefixes.size(),
- db_manager_->v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE].size());
-
- auto entry = cache.find(expected_prefixes[0]);
- EXPECT_NE(cache.end(), entry);
- EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after);
- EXPECT_EQ(0ul, entry->second.full_hashes.size());
-
- entry = cache.find(expected_prefixes[1]);
- EXPECT_NE(cache.end(), entry);
- EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after);
- EXPECT_EQ(0ul, entry->second.full_hashes.size());
-
- entry = cache.find(expected_prefixes[2]);
- EXPECT_NE(cache.end(), entry);
- EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after);
- EXPECT_EQ(0ul, entry->second.full_hashes.size());
-
- entry = cache.find(expected_prefixes[3]);
- EXPECT_NE(cache.end(), entry);
- EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after);
- EXPECT_EQ(1ul, entry->second.full_hashes.size());
- EXPECT_TRUE(SBFullHashEqual(full_hash_result.hash,
- entry->second.full_hashes[0].hash));
- EXPECT_EQ(1ul, entry->second.full_hashes[0].metadata.api_permissions.size());
- EXPECT_EQ(1ul, entry->second.full_hashes[0].metadata.api_permissions.
- count("GEOLOCATION"));
- EXPECT_EQ(full_hash_result.cache_expire_after,
- entry->second.full_hashes[0].cache_expire_after);
-}
-
-// An uninitialized value for negative cache expire does not cache results.
-TEST_F(SafeBrowsingDatabaseManagerTest, ResultsAreNotCachedOnNull) {
- TestClient client;
- const GURL url("https://www.example.com/more");
- TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>(
- db_manager_->v4_get_hash_protocol_manager_);
- base::Time now = base::Time::UnixEpoch();
- SBFullHashResult full_hash_result;
- full_hash_result.hash = SBFullHashForString("example.com/");
- full_hash_result.cache_expire_after = now + base::TimeDelta::FromMinutes(3);
- pm->AddGetFullHashResponse(full_hash_result);
-
- EXPECT_TRUE(db_manager_->v4_full_hash_cache_.empty());
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(client.callback_invoked());
- EXPECT_TRUE(
- db_manager_->v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE].empty());
-}
-
-// Checks that results are looked up correctly in the cache.
-TEST_F(SafeBrowsingDatabaseManagerTest, GetCachedResults) {
- base::Time now = base::Time::UnixEpoch();
- std::vector<SBFullHash> full_hashes;
- SBFullHash full_hash = SBFullHashForString("example.com/");
- full_hashes.push_back(full_hash);
- std::vector<SBFullHashResult> cached_results;
- std::vector<SBPrefix> prefixes;
- db_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE,
- full_hashes, now, &prefixes, &cached_results);
-
- // The cache is empty.
- EXPECT_TRUE(cached_results.empty());
- EXPECT_EQ(1ul, prefixes.size());
- EXPECT_EQ(full_hash.prefix, prefixes[0]);
-
- // Prefix has a cache entry but full hash is not there.
- SBCachedFullHashResult& entry = db_manager_->
- v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE][full_hash.prefix] =
- SBCachedFullHashResult(now + base::TimeDelta::FromMinutes(5));
- db_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE,
- full_hashes, now, &prefixes, &cached_results);
-
- EXPECT_TRUE(prefixes.empty());
- EXPECT_TRUE(cached_results.empty());
-
- // Expired negative cache entry.
- entry.expire_after = now - base::TimeDelta::FromMinutes(5);
- db_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE,
- full_hashes, now, &prefixes, &cached_results);
-
- EXPECT_TRUE(cached_results.empty());
- EXPECT_EQ(1ul, prefixes.size());
- EXPECT_EQ(full_hash.prefix, prefixes[0]);
-
- // Now put the full hash in the cache.
- SBFullHashResult full_hash_result;
- full_hash_result.hash = full_hash;
- full_hash_result.cache_expire_after = now + base::TimeDelta::FromMinutes(3);
- entry.full_hashes.push_back(full_hash_result);
- db_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE,
- full_hashes, now, &prefixes, &cached_results);
-
- EXPECT_TRUE(prefixes.empty());
- EXPECT_EQ(1ul, cached_results.size());
- EXPECT_TRUE(SBFullHashEqual(full_hash, cached_results[0].hash));
-
- // Expired full hash in cache.
- entry.full_hashes.clear();
- full_hash_result.cache_expire_after = now - base::TimeDelta::FromMinutes(3);
- entry.full_hashes.push_back(full_hash_result);
- db_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE,
- full_hashes, now, &prefixes, &cached_results);
-
- EXPECT_TRUE(cached_results.empty());
- EXPECT_EQ(1ul, prefixes.size());
- EXPECT_EQ(full_hash.prefix, prefixes[0]);
-}
-
-// Checks that the cached results and request results are merged.
-TEST_F(SafeBrowsingDatabaseManagerTest, CachedResultsMerged) {
- TestClient client;
- const GURL url("https://www.example.com/more");
- TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>(
- db_manager_->v4_get_hash_protocol_manager_);
- // Set now to max time so the cache expire times are in the future.
- SBFullHashResult full_hash_result;
- full_hash_result.hash = SBFullHashForString("example.com/");
- full_hash_result.metadata.api_permissions.insert("GEOLOCATION");
- full_hash_result.cache_expire_after = base::Time::Max();
- pm->AddGetFullHashResponse(full_hash_result);
- pm->SetNegativeCacheDurationMins(base::Time::Max(), 0);
-
- EXPECT_TRUE(db_manager_->v4_full_hash_cache_.empty());
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(client.callback_invoked());
- const std::set<std::string>& permissions = client.GetBlockedPermissions();
- EXPECT_EQ(1ul, permissions.size());
- EXPECT_EQ(1ul, permissions.count("GEOLOCATION"));
-
- // The results should be cached, so remove them from the protocol manager
- // response.
- TestClient client2;
- pm->ClearFullHashResponse();
- pm->SetNegativeCacheDurationMins(base::Time(), 0);
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client2));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(client2.callback_invoked());
- const std::set<std::string>& permissions2 =
- client2.GetBlockedPermissions();
- EXPECT_EQ(1ul, permissions2.size());
- EXPECT_EQ(1ul, permissions2.count("GEOLOCATION"));
-
- // Add a different result to the protocol manager response and ensure it is
- // merged with the cached result in the metadata.
- TestClient client3;
- const GURL url2("https://m.example.com/more");
- full_hash_result.hash = SBFullHashForString("m.example.com/");
- full_hash_result.metadata.api_permissions.insert("NOTIFICATIONS");
- pm->AddGetFullHashResponse(full_hash_result);
- pm->SetNegativeCacheDurationMins(base::Time::Max(), 0);
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url2, &client3));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(client3.callback_invoked());
- const std::set<std::string>& permissions3 =
- client3.GetBlockedPermissions();
- EXPECT_EQ(2ul, permissions3.size());
- EXPECT_EQ(1ul, permissions3.count("GEOLOCATION"));
- EXPECT_EQ(1ul, permissions3.count("NOTIFICATIONS"));
+ EXPECT_FALSE(client.callback_invoked());
+ EXPECT_EQ(0ul, client.GetBlockedPermissions().size());
}
-TEST_F(SafeBrowsingDatabaseManagerTest, CachedResultsAreEvicted) {
- base::Time epoch = base::Time::UnixEpoch();
- SBFullHashResult full_hash_result;
- full_hash_result.hash = SBFullHashForString("example.com/");
- full_hash_result.cache_expire_after = epoch;
-
- SafeBrowsingDatabaseManager::PrefixToFullHashResultsMap& cache =
- db_manager_->v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE];
-
- // Fill the cache with some expired entries.
- // Both negative cache and full hash expired.
- cache[full_hash_result.hash.prefix] = SBCachedFullHashResult(epoch);
- cache[full_hash_result.hash.prefix].full_hashes.push_back(full_hash_result);
-
+TEST_F(SafeBrowsingDatabaseManagerTest, GetApiCheckResponse) {
+ net::TestURLFetcherFactory factory;
TestClient client;
const GURL url("https://www.example.com/more");
- EXPECT_EQ(1ul, cache.size());
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
- base::RunLoop().RunUntilIdle();
-
- // Cache should be empty.
- EXPECT_TRUE(client.callback_invoked());
- EXPECT_TRUE(cache.empty());
-
- // Negative cache still valid and full hash expired.
- cache[full_hash_result.hash.prefix] =
- SBCachedFullHashResult(base::Time::Max());
- cache[full_hash_result.hash.prefix].full_hashes.push_back(full_hash_result);
-
- EXPECT_EQ(1ul, cache.size());
EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
- base::RunLoop().RunUntilIdle();
- // Cache entry should still be there.
- EXPECT_EQ(1ul, cache.size());
- auto entry = cache.find(full_hash_result.hash.prefix);
- EXPECT_NE(cache.end(), entry);
- EXPECT_EQ(base::Time::Max(), entry->second.expire_after);
- EXPECT_EQ(1ul, entry->second.full_hashes.size());
- EXPECT_TRUE(SBFullHashEqual(full_hash_result.hash,
- entry->second.full_hashes[0].hash));
- EXPECT_EQ(full_hash_result.cache_expire_after,
- entry->second.full_hashes[0].cache_expire_after);
-
- // Negative cache still valid and full hash still valid.
- cache[full_hash_result.hash.prefix].full_hashes[0].
- cache_expire_after = base::Time::Max();
-
- EXPECT_EQ(1ul, cache.size());
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
- base::RunLoop().RunUntilIdle();
+ net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
+ DCHECK(fetcher);
+ fetcher->set_status(net::URLRequestStatus());
+ fetcher->set_response_code(200);
+ fetcher->SetResponseString(GetStockV4GetHashResponse());
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
- // Cache entry should still be there.
- EXPECT_EQ(1ul, cache.size());
- entry = cache.find(full_hash_result.hash.prefix);
- EXPECT_NE(cache.end(), entry);
- EXPECT_EQ(base::Time::Max(), entry->second.expire_after);
- EXPECT_EQ(1ul, entry->second.full_hashes.size());
- EXPECT_TRUE(SBFullHashEqual(full_hash_result.hash,
- entry->second.full_hashes[0].hash));
- EXPECT_EQ(base::Time::Max(),
- entry->second.full_hashes[0].cache_expire_after);
-
- // Negative cache expired and full hash still valid.
- cache[full_hash_result.hash.prefix].expire_after = epoch;
-
- EXPECT_EQ(1ul, cache.size());
- EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client));
base::RunLoop().RunUntilIdle();
- // Cache entry should still be there.
- EXPECT_EQ(1ul, cache.size());
- entry = cache.find(full_hash_result.hash.prefix);
- EXPECT_NE(cache.end(), entry);
- EXPECT_EQ(epoch, entry->second.expire_after);
- EXPECT_EQ(1ul, entry->second.full_hashes.size());
- EXPECT_TRUE(SBFullHashEqual(full_hash_result.hash,
- entry->second.full_hashes[0].hash));
- EXPECT_EQ(base::Time::Max(),
- entry->second.full_hashes[0].cache_expire_after);
+ ASSERT_TRUE(client.callback_invoked());
+ ASSERT_EQ(1ul, client.GetBlockedPermissions().size());
+ EXPECT_EQ("GEOLOCATION", *(client.GetBlockedPermissions().begin()));
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/prefix_set_unittest.cc b/chromium/components/safe_browsing_db/prefix_set_unittest.cc
index 47e6934e0f1..72eb410593b 100644
--- a/chromium/components/safe_browsing_db/prefix_set_unittest.cc
+++ b/chromium/components/safe_browsing_db/prefix_set_unittest.cc
@@ -110,7 +110,7 @@ class PrefixSetTest : public PlatformTest {
if (!temp_dir_.IsValid() && !temp_dir_.CreateUniqueTempDir())
return false;
- base::FilePath filename = temp_dir_.path().AppendASCII("PrefixSetTest");
+ base::FilePath filename = temp_dir_.GetPath().AppendASCII("PrefixSetTest");
PrefixSetBuilder builder(shared_prefixes_);
if (!builder.GetPrefixSetNoHashes()->WriteFile(filename))
diff --git a/chromium/components/safe_browsing_db/remote_database_manager.cc b/chromium/components/safe_browsing_db/remote_database_manager.cc
index 472cffc8d09..87f3c4167ad 100644
--- a/chromium/components/safe_browsing_db/remote_database_manager.cc
+++ b/chromium/components/safe_browsing_db/remote_database_manager.cc
@@ -143,17 +143,19 @@ RemoteSafeBrowsingDatabaseManager::~RemoteSafeBrowsingDatabaseManager() {
DCHECK(!enabled_);
}
-bool RemoteSafeBrowsingDatabaseManager::IsSupported() const {
- return SafeBrowsingApiHandler::GetInstance() != nullptr;
-}
-
-safe_browsing::ThreatSource RemoteSafeBrowsingDatabaseManager::GetThreatSource()
- const {
- return safe_browsing::ThreatSource::REMOTE;
-}
-
-bool RemoteSafeBrowsingDatabaseManager::ChecksAreAlwaysAsync() const {
- return true;
+void RemoteSafeBrowsingDatabaseManager::CancelCheck(Client* client) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(enabled_);
+ for (auto itr = current_requests_.begin(); itr != current_requests_.end();
+ ++itr) {
+ if ((*itr)->client() == client) {
+ DVLOG(2) << "Canceling check for URL " << (*itr)->url();
+ delete *itr;
+ current_requests_.erase(itr);
+ return;
+ }
+ }
+ NOTREACHED();
}
bool RemoteSafeBrowsingDatabaseManager::CanCheckResourceType(
@@ -166,7 +168,38 @@ bool RemoteSafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const {
url.SchemeIs(url::kFtpScheme);
}
-bool RemoteSafeBrowsingDatabaseManager::IsDownloadProtectionEnabled() const {
+bool RemoteSafeBrowsingDatabaseManager::ChecksAreAlwaysAsync() const {
+ return true;
+}
+
+bool RemoteSafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
+ Client* client) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!enabled_)
+ return true;
+
+ bool can_check_url = CanCheckUrl(url);
+ UMA_HISTOGRAM_BOOLEAN("SB2.RemoteCall.CanCheckUrl", can_check_url);
+ if (!can_check_url)
+ return true; // Safe, continue right away.
+
+ std::unique_ptr<ClientRequest> req(new ClientRequest(client, this, url));
+ std::vector<SBThreatType> threat_types; // Not currently used.
+
+ DVLOG(1) << "Checking for client " << client << " and URL " << url;
+ SafeBrowsingApiHandler* api_handler = SafeBrowsingApiHandler::GetInstance();
+ // This shouldn't happen since SafeBrowsingResourceThrottle checks
+ // IsSupported() earlier.
+ DCHECK(api_handler) << "SafeBrowsingApiHandler was never constructed";
+ api_handler->StartURLCheck(
+ base::Bind(&ClientRequest::OnRequestDoneWeak, req->GetWeakPtr()), url,
+ threat_types);
+
+ UMA_HISTOGRAM_COUNTS_10000("SB2.RemoteCall.ChecksPending",
+ current_requests_.size());
+ current_requests_.push_back(req.release());
+
+ // Defer the resource load.
return false;
}
@@ -184,19 +217,13 @@ bool RemoteSafeBrowsingDatabaseManager::CheckExtensionIDs(
return true;
}
-bool RemoteSafeBrowsingDatabaseManager::MatchMalwareIP(
- const std::string& ip_address) {
- NOTREACHED();
- return false;
-}
-
-bool RemoteSafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
+bool RemoteSafeBrowsingDatabaseManager::CheckResourceUrl(const GURL& url,
+ Client* client) {
NOTREACHED();
return true;
}
-bool RemoteSafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(
- const GURL& url) {
+bool RemoteSafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
NOTREACHED();
return true;
}
@@ -207,72 +234,45 @@ bool RemoteSafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
return true;
}
-bool RemoteSafeBrowsingDatabaseManager::MatchModuleWhitelistString(
- const std::string& str) {
+bool RemoteSafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(
+ const GURL& url) {
NOTREACHED();
return true;
}
-bool RemoteSafeBrowsingDatabaseManager::CheckResourceUrl(const GURL& url,
- Client* client) {
+bool RemoteSafeBrowsingDatabaseManager::MatchMalwareIP(
+ const std::string& ip_address) {
NOTREACHED();
- return true;
+ return false;
}
-bool RemoteSafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
+bool RemoteSafeBrowsingDatabaseManager::MatchModuleWhitelistString(
+ const std::string& str) {
NOTREACHED();
return true;
}
+safe_browsing::ThreatSource RemoteSafeBrowsingDatabaseManager::GetThreatSource()
+ const {
+ return safe_browsing::ThreatSource::REMOTE;
+}
+
bool RemoteSafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() {
NOTREACHED();
return true;
}
-bool RemoteSafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
- Client* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_)
- return true;
-
- bool can_check_url = CanCheckUrl(url);
- UMA_HISTOGRAM_BOOLEAN("SB2.RemoteCall.CanCheckUrl", can_check_url);
- if (!can_check_url)
- return true; // Safe, continue right away.
-
- std::unique_ptr<ClientRequest> req(new ClientRequest(client, this, url));
- std::vector<SBThreatType> threat_types; // Not currently used.
-
- DVLOG(1) << "Checking for client " << client << " and URL " << url;
- SafeBrowsingApiHandler* api_handler = SafeBrowsingApiHandler::GetInstance();
- // This shouldn't happen since SafeBrowsingResourceThrottle checks
- // IsSupported() earlier.
- DCHECK(api_handler) << "SafeBrowsingApiHandler was never constructed";
- api_handler->StartURLCheck(
- base::Bind(&ClientRequest::OnRequestDoneWeak, req->GetWeakPtr()), url,
- threat_types);
-
- UMA_HISTOGRAM_COUNTS_10000("SB2.RemoteCall.ChecksPending",
- current_requests_.size());
- current_requests_.push_back(req.release());
-
- // Defer the resource load.
+bool RemoteSafeBrowsingDatabaseManager::IsDownloadProtectionEnabled() const {
return false;
}
-void RemoteSafeBrowsingDatabaseManager::CancelCheck(Client* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(enabled_);
- for (auto itr = current_requests_.begin(); itr != current_requests_.end();
- ++itr) {
- if ((*itr)->client() == client) {
- DVLOG(2) << "Canceling check for URL " << (*itr)->url();
- delete *itr;
- current_requests_.erase(itr);
- return;
- }
- }
+bool RemoteSafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
NOTREACHED();
+ return true;
+}
+
+bool RemoteSafeBrowsingDatabaseManager::IsSupported() const {
+ return SafeBrowsingApiHandler::GetInstance() != nullptr;
}
void RemoteSafeBrowsingDatabaseManager::StartOnIOThread(
@@ -291,7 +291,7 @@ void RemoteSafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
// Call back and delete any remaining clients. OnRequestDone() modifies
// |current_requests_|, so we make a copy first.
std::vector<ClientRequest*> to_callback(current_requests_);
- for (auto req : to_callback) {
+ for (auto* req : to_callback) {
DVLOG(1) << "Stopping: Invoking unfinished req for URL " << req->url();
req->OnRequestDone(SB_THREAT_TYPE_SAFE, ThreatMetadata());
}
diff --git a/chromium/components/safe_browsing_db/remote_database_manager.h b/chromium/components/safe_browsing_db/remote_database_manager.h
index 17ce3011a66..8ae6663b419 100644
--- a/chromium/components/safe_browsing_db/remote_database_manager.h
+++ b/chromium/components/safe_browsing_db/remote_database_manager.h
@@ -38,33 +38,29 @@ class RemoteSafeBrowsingDatabaseManager : public SafeBrowsingDatabaseManager {
// SafeBrowsingDatabaseManager implementation
//
- bool IsSupported() const override;
- safe_browsing::ThreatSource GetThreatSource() const override;
- bool ChecksAreAlwaysAsync() const override;
+ void CancelCheck(Client* client) override;
bool CanCheckResourceType(content::ResourceType resource_type) const override;
bool CanCheckUrl(const GURL& url) const override;
- bool IsDownloadProtectionEnabled() const override;
+ bool ChecksAreAlwaysAsync() const override;
bool CheckBrowseUrl(const GURL& url, Client* client) override;
- void CancelCheck(Client* client) override;
- void StartOnIOThread(
- net::URLRequestContextGetter* request_context_getter,
- const V4ProtocolConfig& config) override;
- void StopOnIOThread(bool shutdown) override;
-
- // These will fail with DCHECK() since their functionality isn't implemented.
- // We may later add support for a subset of them.
bool CheckDownloadUrl(const std::vector<GURL>& url_chain,
Client* client) override;
bool CheckExtensionIDs(const std::set<std::string>& extension_ids,
Client* client) override;
+ bool CheckResourceUrl(const GURL& url, Client* client) override;
bool MatchCsdWhitelistUrl(const GURL& url) override;
- bool MatchMalwareIP(const std::string& ip_address) override;
- bool MatchDownloadWhitelistUrl(const GURL& url) override;
bool MatchDownloadWhitelistString(const std::string& str) override;
+ bool MatchDownloadWhitelistUrl(const GURL& url) override;
+ bool MatchMalwareIP(const std::string& ip_address) override;
bool MatchModuleWhitelistString(const std::string& str) override;
- bool CheckResourceUrl(const GURL& url, Client* client) override;
- bool IsMalwareKillSwitchOn() override;
+ safe_browsing::ThreatSource GetThreatSource() const override;
bool IsCsdWhitelistKillSwitchOn() override;
+ bool IsDownloadProtectionEnabled() const override;
+ bool IsMalwareKillSwitchOn() override;
+ bool IsSupported() const override;
+ void StartOnIOThread(net::URLRequestContextGetter* request_context_getter,
+ const V4ProtocolConfig& config) override;
+ void StopOnIOThread(bool shutdown) override;
//
// RemoteSafeBrowsingDatabaseManager implementation
diff --git a/chromium/components/safe_browsing_db/remote_database_manager_unittest.cc b/chromium/components/safe_browsing_db/remote_database_manager_unittest.cc
index b6e337935bb..284b3358c88 100644
--- a/chromium/components/safe_browsing_db/remote_database_manager_unittest.cc
+++ b/chromium/components/safe_browsing_db/remote_database_manager_unittest.cc
@@ -29,7 +29,8 @@ class TestSafeBrowsingApiHandler : public SafeBrowsingApiHandler {
class RemoteDatabaseManagerTest : public testing::Test {
protected:
- RemoteDatabaseManagerTest() : field_trials_(new base::FieldTrialList(NULL)) {}
+ RemoteDatabaseManagerTest()
+ : field_trials_(new base::FieldTrialList(nullptr)) {}
void SetUp() override {
SafeBrowsingApiHandler::SetInstance(&api_handler_);
@@ -41,7 +42,7 @@ class RemoteDatabaseManagerTest : public testing::Test {
// Destroy the existing FieldTrialList before creating a new one to avoid
// a DCHECK.
field_trials_.reset();
- field_trials_.reset(new base::FieldTrialList(NULL));
+ field_trials_.reset(new base::FieldTrialList(nullptr));
variations::testing::ClearAllVariationIDs();
variations::testing::ClearAllVariationParams();
diff --git a/chromium/components/safe_browsing_db/safebrowsing.proto b/chromium/components/safe_browsing_db/safebrowsing.proto
index d5338920688..c9c24deb953 100644
--- a/chromium/components/safe_browsing_db/safebrowsing.proto
+++ b/chromium/components/safe_browsing_db/safebrowsing.proto
@@ -149,8 +149,8 @@ message FetchThreatListUpdatesResponse {
// response.
repeated ThreatEntrySet additions = 5;
- // A set of entries to remove from a local threat type's list. Repeated for
- // the same reason as above.
+ // A set of entries to remove from a local threat type's list. In practice,
+ // this field is empty or contains exactly one ThreatEntrySet.
repeated ThreatEntrySet removals = 6;
// The new client state, in encrypted format. Opaque to clients.
diff --git a/chromium/components/safe_browsing_db/test_database_manager.cc b/chromium/components/safe_browsing_db/test_database_manager.cc
index 0e47fe1d80e..3209bb3984d 100644
--- a/chromium/components/safe_browsing_db/test_database_manager.cc
+++ b/chromium/components/safe_browsing_db/test_database_manager.cc
@@ -13,20 +13,8 @@
namespace safe_browsing {
-bool TestSafeBrowsingDatabaseManager::IsSupported() const {
- NOTIMPLEMENTED();
- return false;
-}
-
-safe_browsing::ThreatSource TestSafeBrowsingDatabaseManager::GetThreatSource()
- const {
- NOTIMPLEMENTED();
- return safe_browsing::ThreatSource::UNKNOWN;
-}
-
-bool TestSafeBrowsingDatabaseManager::ChecksAreAlwaysAsync() const {
+void TestSafeBrowsingDatabaseManager::CancelCheck(Client* client) {
NOTIMPLEMENTED();
- return false;
}
bool TestSafeBrowsingDatabaseManager::CanCheckResourceType(
@@ -40,7 +28,7 @@ bool TestSafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const {
return false;
}
-bool TestSafeBrowsingDatabaseManager::IsDownloadProtectionEnabled() const {
+bool TestSafeBrowsingDatabaseManager::ChecksAreAlwaysAsync() const {
NOTIMPLEMENTED();
return false;
}
@@ -76,8 +64,8 @@ bool TestSafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
return true;
}
-bool TestSafeBrowsingDatabaseManager::MatchMalwareIP(
- const std::string& ip_address) {
+bool TestSafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
+ const std::string& str) {
NOTIMPLEMENTED();
return true;
}
@@ -88,8 +76,8 @@ bool TestSafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(
return true;
}
-bool TestSafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
- const std::string& str) {
+bool TestSafeBrowsingDatabaseManager::MatchMalwareIP(
+ const std::string& ip_address) {
NOTIMPLEMENTED();
return true;
}
@@ -100,9 +88,10 @@ bool TestSafeBrowsingDatabaseManager::MatchModuleWhitelistString(
return true;
}
-bool TestSafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
+safe_browsing::ThreatSource TestSafeBrowsingDatabaseManager::GetThreatSource()
+ const {
NOTIMPLEMENTED();
- return false;
+ return safe_browsing::ThreatSource::UNKNOWN;
}
bool TestSafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() {
@@ -110,8 +99,19 @@ bool TestSafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() {
return false;
}
-void TestSafeBrowsingDatabaseManager::CancelCheck(Client* client) {
+bool TestSafeBrowsingDatabaseManager::IsDownloadProtectionEnabled() const {
NOTIMPLEMENTED();
+ return false;
+}
+
+bool TestSafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool TestSafeBrowsingDatabaseManager::IsSupported() const {
+ NOTIMPLEMENTED();
+ return false;
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/test_database_manager.h b/chromium/components/safe_browsing_db/test_database_manager.h
index ec8f818efab..22239d94539 100644
--- a/chromium/components/safe_browsing_db/test_database_manager.h
+++ b/chromium/components/safe_browsing_db/test_database_manager.h
@@ -27,12 +27,10 @@ class TestSafeBrowsingDatabaseManager
: public SafeBrowsingDatabaseManager {
public:
// SafeBrowsingDatabaseManager implementation:
- bool IsSupported() const override;
- safe_browsing::ThreatSource GetThreatSource() const override;
- bool ChecksAreAlwaysAsync() const override;
+ void CancelCheck(Client* client) override;
bool CanCheckResourceType(content::ResourceType resource_type) const override;
bool CanCheckUrl(const GURL& url) const override;
- bool IsDownloadProtectionEnabled() const override;
+ bool ChecksAreAlwaysAsync() const override;
bool CheckBrowseUrl(const GURL& url, Client* client) override;
bool CheckDownloadUrl(const std::vector<GURL>& url_chain,
Client* client) override;
@@ -40,13 +38,15 @@ class TestSafeBrowsingDatabaseManager
Client* client) override;
bool CheckResourceUrl(const GURL& url, Client* client) override;
bool MatchCsdWhitelistUrl(const GURL& url) override;
- bool MatchMalwareIP(const std::string& ip_address) override;
- bool MatchDownloadWhitelistUrl(const GURL& url) override;
bool MatchDownloadWhitelistString(const std::string& str) override;
+ bool MatchDownloadWhitelistUrl(const GURL& url) override;
+ bool MatchMalwareIP(const std::string& ip_address) override;
bool MatchModuleWhitelistString(const std::string& str) override;
- bool IsMalwareKillSwitchOn() override;
+ safe_browsing::ThreatSource GetThreatSource() const override;
bool IsCsdWhitelistKillSwitchOn() override;
- void CancelCheck(Client* client) override;
+ bool IsDownloadProtectionEnabled() const override;
+ bool IsMalwareKillSwitchOn() override;
+ bool IsSupported() const override;
protected:
~TestSafeBrowsingDatabaseManager() override {};
diff --git a/chromium/components/safe_browsing_db/testing_util.h b/chromium/components/safe_browsing_db/testing_util.h
index 76b319464c4..8447162681c 100644
--- a/chromium/components/safe_browsing_db/testing_util.h
+++ b/chromium/components/safe_browsing_db/testing_util.h
@@ -13,22 +13,12 @@
namespace safe_browsing {
-inline bool operator==(const ThreatMetadata& lhs, const ThreatMetadata& rhs) {
- return lhs.threat_pattern_type == rhs.threat_pattern_type &&
- lhs.api_permissions == rhs.api_permissions &&
- lhs.population_id == rhs.population_id;
-}
-
-inline bool operator!=(const ThreatMetadata& lhs, const ThreatMetadata& rhs) {
- return !(lhs == rhs);
-}
-
inline std::ostream& operator<<(std::ostream& os, const ThreatMetadata& meta) {
os << "{threat_pattern_type=" << static_cast<int>(meta.threat_pattern_type)
<< ", api_permissions=[";
for (auto p : meta.api_permissions)
os << p << ",";
- return os << "], population_id=" << meta.population_id;
+ return os << "], population_id=" << meta.population_id << "}";
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/util.cc b/chromium/components/safe_browsing_db/util.cc
index 3289aaae5bd..3f34fe5fb09 100644
--- a/chromium/components/safe_browsing_db/util.cc
+++ b/chromium/components/safe_browsing_db/util.cc
@@ -7,12 +7,10 @@
#include <stddef.h>
#include "base/macros.h"
-#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
#include "crypto/sha2.h"
#include "net/base/escape.h"
#include "url/gurl.h"
-#include "url/url_util.h"
namespace safe_browsing {
@@ -29,67 +27,6 @@ bool IsKnownList(const std::string& name) {
return false;
}
-void GenerateHostVariantsToCheck(const std::string& host,
- std::vector<std::string>* hosts) {
- hosts->clear();
-
- if (host.empty())
- return;
-
- // Per the Safe Browsing Protocol v2 spec, we try the host, and also up to 4
- // hostnames formed by starting with the last 5 components and successively
- // removing the leading component. The last component isn't examined alone,
- // since it's the TLD or a subcomponent thereof.
- //
- // Note that we don't need to be clever about stopping at the "real" eTLD --
- // the data on the server side has been filtered to ensure it will not
- // blacklist a whole TLD, and it's not significantly slower on our side to
- // just check too much.
- //
- // Also note that because we have a simple blacklist, not some sort of complex
- // whitelist-in-blacklist or vice versa, it doesn't matter what order we check
- // these in.
- const size_t kMaxHostsToCheck = 4;
- bool skipped_last_component = false;
- for (std::string::const_reverse_iterator i(host.rbegin());
- i != host.rend() && hosts->size() < kMaxHostsToCheck; ++i) {
- if (*i == '.') {
- if (skipped_last_component)
- hosts->push_back(std::string(i.base(), host.end()));
- else
- skipped_last_component = true;
- }
- }
- hosts->push_back(host);
-}
-
-void GeneratePathVariantsToCheck(const std::string& path,
- const std::string& query,
- std::vector<std::string>* paths) {
- paths->clear();
-
- if (path.empty())
- return;
-
- // Per the Safe Browsing Protocol v2 spec, we try the exact path with/without
- // the query parameters, and also up to 4 paths formed by starting at the root
- // and adding more path components.
- //
- // As with the hosts above, it doesn't matter what order we check these in.
- const size_t kMaxPathsToCheck = 4;
- for (std::string::const_iterator i(path.begin());
- i != path.end() && paths->size() < kMaxPathsToCheck; ++i) {
- if (*i == '/')
- paths->push_back(std::string(path.begin(), i + 1));
- }
-
- if (!paths->empty() && paths->back() != path)
- paths->push_back(path);
-
- if (!query.empty())
- paths->push_back(path + "?" + query);
-}
-
} // namespace
// ThreatMetadata ------------------------------------------------------------
@@ -100,6 +37,16 @@ ThreatMetadata::ThreatMetadata(const ThreatMetadata& other) = default;
ThreatMetadata::~ThreatMetadata() {}
+bool ThreatMetadata::operator==(const ThreatMetadata& other) const {
+ return threat_pattern_type == other.threat_pattern_type &&
+ api_permissions == other.api_permissions &&
+ population_id == other.population_id;
+}
+
+bool ThreatMetadata::operator!=(const ThreatMetadata& other) const {
+ return !operator==(other);
+}
+
// SBCachedFullHashResult ------------------------------------------------------
SBCachedFullHashResult::SBCachedFullHashResult() {}
@@ -216,163 +163,6 @@ std::string SBFullHashToString(const SBFullHash& hash) {
return std::string(hash.full_hash, sizeof(hash.full_hash));
}
-
-std::string Unescape(const std::string& url) {
- std::string unescaped_str(url);
- const int kMaxLoopIterations = 1024;
- size_t old_size = 0;
- int loop_var = 0;
- do {
- old_size = unescaped_str.size();
- unescaped_str = net::UnescapeURLComponent(
- unescaped_str,
- net::UnescapeRule::SPOOFING_AND_CONTROL_CHARS |
- net::UnescapeRule::SPACES | net::UnescapeRule::PATH_SEPARATORS |
- net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
- } while (old_size != unescaped_str.size() &&
- ++loop_var <= kMaxLoopIterations);
-
- return unescaped_str;
-}
-
-std::string Escape(const std::string& url) {
- std::string escaped_str;
- // The escaped string is larger so allocate double the length to reduce the
- // chance of the string being grown.
- escaped_str.reserve(url.length() * 2);
- const char* kHexString = "0123456789ABCDEF";
- for (size_t i = 0; i < url.length(); i++) {
- unsigned char c = static_cast<unsigned char>(url[i]);
- if (c <= ' ' || c > '~' || c == '#' || c == '%') {
- escaped_str += '%';
- escaped_str += kHexString[c >> 4];
- escaped_str += kHexString[c & 0xf];
- } else {
- escaped_str += c;
- }
- }
-
- return escaped_str;
-}
-
-std::string RemoveConsecutiveChars(base::StringPiece str, const char c) {
- std::string output;
- // Output is at most the length of the original string.
- output.reserve(str.size());
-
- size_t i = 0;
- while (i < str.size()) {
- output.append(1, str[i++]);
- if (str[i - 1] == c) {
- while (i < str.size() && str[i] == c) {
- i++;
- }
- }
- }
-
- return output;
-}
-
-// Canonicalizes url as per Google Safe Browsing Specification.
-// See section 6.1 in
-// http://code.google.com/p/google-safe-browsing/wiki/Protocolv2Spec.
-void CanonicalizeUrl(const GURL& url,
- std::string* canonicalized_hostname,
- std::string* canonicalized_path,
- std::string* canonicalized_query) {
- DCHECK(url.is_valid());
-
- // We only canonicalize "normal" URLs.
- if (!url.IsStandard())
- return;
-
- // Following canonicalization steps are excluded since url parsing takes care
- // of those :-
- // 1. Remove any tab (0x09), CR (0x0d), and LF (0x0a) chars from url.
- // (Exclude escaped version of these chars).
- // 2. Normalize hostname to 4 dot-seperated decimal values.
- // 3. Lowercase hostname.
- // 4. Resolve path sequences "/../" and "/./".
-
- // That leaves us with the following :-
- // 1. Remove fragment in URL.
- GURL url_without_fragment;
- GURL::Replacements f_replacements;
- f_replacements.ClearRef();
- f_replacements.ClearUsername();
- f_replacements.ClearPassword();
- url_without_fragment = url.ReplaceComponents(f_replacements);
-
- // 2. Do URL unescaping until no more hex encoded characters exist.
- std::string url_unescaped_str(Unescape(url_without_fragment.spec()));
- url::Parsed parsed;
- url::ParseStandardURL(url_unescaped_str.data(), url_unescaped_str.length(),
- &parsed);
-
- // 3. In hostname, remove all leading and trailing dots.
- base::StringPiece host;
- if (parsed.host.len > 0)
- host.set(url_unescaped_str.data() + parsed.host.begin, parsed.host.len);
-
- base::StringPiece host_without_end_dots =
- base::TrimString(host, ".", base::TrimPositions::TRIM_ALL);
-
- // 4. In hostname, replace consecutive dots with a single dot.
- std::string host_without_consecutive_dots(RemoveConsecutiveChars(
- host_without_end_dots, '.'));
-
- // 5. In path, replace runs of consecutive slashes with a single slash.
- base::StringPiece path;
- if (parsed.path.len > 0)
- path.set(url_unescaped_str.data() + parsed.path.begin, parsed.path.len);
- std::string path_without_consecutive_slash(RemoveConsecutiveChars(path, '/'));
-
- url::Replacements<char> hp_replacements;
- hp_replacements.SetHost(
- host_without_consecutive_dots.data(),
- url::Component(0, host_without_consecutive_dots.length()));
- hp_replacements.SetPath(
- path_without_consecutive_slash.data(),
- url::Component(0, path_without_consecutive_slash.length()));
-
- std::string url_unescaped_with_can_hostpath;
- url::StdStringCanonOutput output(&url_unescaped_with_can_hostpath);
- url::Parsed temp_parsed;
- url::ReplaceComponents(url_unescaped_str.data(),
- url_unescaped_str.length(),
- parsed,
- hp_replacements,
- NULL,
- &output,
- &temp_parsed);
- output.Complete();
-
- // 6. Step needed to revert escaping done in url::ReplaceComponents.
- url_unescaped_with_can_hostpath = Unescape(url_unescaped_with_can_hostpath);
-
- // 7. After performing all above steps, percent-escape all chars in url which
- // are <= ASCII 32, >= 127, #, %. Escapes must be uppercase hex characters.
- std::string escaped_canon_url_str(Escape(url_unescaped_with_can_hostpath));
- url::Parsed final_parsed;
- url::ParseStandardURL(escaped_canon_url_str.data(),
- escaped_canon_url_str.length(),
- &final_parsed);
-
- if (canonicalized_hostname && final_parsed.host.len > 0) {
- *canonicalized_hostname =
- escaped_canon_url_str.substr(final_parsed.host.begin,
- final_parsed.host.len);
- }
- if (canonicalized_path && final_parsed.path.len > 0) {
- *canonicalized_path = escaped_canon_url_str.substr(final_parsed.path.begin,
- final_parsed.path.len);
- }
- if (canonicalized_query && final_parsed.query.len > 0) {
- *canonicalized_query = escaped_canon_url_str.substr(
- final_parsed.query.begin, final_parsed.query.len);
- }
-}
-
void UrlToFullHashes(const GURL& url,
bool include_whitelist_hashes,
std::vector<SBFullHash>* full_hashes) {
@@ -383,17 +173,19 @@ void UrlToFullHashes(const GURL& url,
std::string canon_host;
std::string canon_path;
std::string canon_query;
- CanonicalizeUrl(url, &canon_host, &canon_path, &canon_query);
+ V4ProtocolManagerUtil::CanonicalizeUrl(url, &canon_host, &canon_path,
+ &canon_query);
std::vector<std::string> hosts;
if (url.HostIsIPAddress()) {
hosts.push_back(url.host());
} else {
- GenerateHostVariantsToCheck(canon_host, &hosts);
+ V4ProtocolManagerUtil::GenerateHostVariantsToCheck(canon_host, &hosts);
}
std::vector<std::string> paths;
- GeneratePathVariantsToCheck(canon_path, canon_query, &paths);
+ V4ProtocolManagerUtil::GeneratePathVariantsToCheck(canon_path, canon_query,
+ &paths);
for (const std::string& host : hosts) {
for (const std::string& path : paths) {
@@ -403,8 +195,7 @@ void UrlToFullHashes(const GURL& url,
// We may have /foo as path-prefix in the whitelist which should
// also match with /foo/bar and /foo?bar. Hence, for every path
// that ends in '/' we also add the path without the slash.
- if (include_whitelist_hashes && path.size() > 1 &&
- path[path.size() - 1] == '/') {
+ if (include_whitelist_hashes && path.size() > 1 && path.back() == '/') {
full_hashes->push_back(SBFullHashForString(
host + path.substr(0, path.size() - 1)));
}
@@ -412,33 +203,4 @@ void UrlToFullHashes(const GURL& url,
}
}
-void GenerateHostsToCheck(const GURL& url, std::vector<std::string>* hosts) {
- std::string canon_host;
- CanonicalizeUrl(url, &canon_host, NULL, NULL);
- GenerateHostVariantsToCheck(canon_host, hosts);
-}
-
-void GeneratePathsToCheck(const GURL& url, std::vector<std::string>* paths) {
- std::string canon_path;
- std::string canon_query;
- CanonicalizeUrl(url, NULL, &canon_path, &canon_query);
- GeneratePathVariantsToCheck(canon_path, canon_query, paths);
-}
-
-void GeneratePatternsToCheck(const GURL& url, std::vector<std::string>* urls) {
- std::string canon_host;
- std::string canon_path;
- std::string canon_query;
- CanonicalizeUrl(url, &canon_host, &canon_path, &canon_query);
-
- std::vector<std::string> hosts, paths;
- GenerateHostVariantsToCheck(canon_host, &hosts);
- GeneratePathVariantsToCheck(canon_path, canon_query, &paths);
- for (size_t h = 0; h < hosts.size(); ++h) {
- for (size_t p = 0; p < paths.size(); ++p) {
- urls->push_back(hosts[h] + paths[p]);
- }
- }
-}
-
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/util.h b/chromium/components/safe_browsing_db/util.h
index 2e72b2595e6..0d805a01b2f 100644
--- a/chromium/components/safe_browsing_db/util.h
+++ b/chromium/components/safe_browsing_db/util.h
@@ -16,47 +16,12 @@
#include "base/strings/string_piece.h"
#include "base/time/time.h"
+#include "components/safe_browsing_db/v4_protocol_manager_util.h"
class GURL;
namespace safe_browsing {
-// Different types of threats that SafeBrowsing protects against.
-enum SBThreatType {
- // No threat at all.
- SB_THREAT_TYPE_SAFE,
-
- // The URL is being used for phishing.
- SB_THREAT_TYPE_URL_PHISHING,
-
- // The URL hosts malware.
- SB_THREAT_TYPE_URL_MALWARE,
-
- // The URL hosts unwanted programs.
- SB_THREAT_TYPE_URL_UNWANTED,
-
- // The download URL is malware.
- SB_THREAT_TYPE_BINARY_MALWARE_URL,
-
- // Url detected by the client-side phishing model. Note that unlike the
- // above values, this does not correspond to a downloaded list.
- SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL,
-
- // The Chrome extension or app (given by its ID) is malware.
- SB_THREAT_TYPE_EXTENSION,
-
- // Url detected by the client-side malware IP list. This IP list is part
- // of the client side detection model.
- SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL,
-
- // Url leads to a blacklisted resource script. Note that no warnings should be
- // shown on this threat type, but an incident report might be sent.
- SB_THREAT_TYPE_BLACKLISTED_RESOURCE,
-
- // Url abuses a permission API.
- SB_THREAT_TYPE_API_ABUSE,
-};
-
// Metadata that indicates what kind of URL match this is.
enum class ThreatPatternType {
NONE = 0, // Pattern type didn't appear in the metadata
@@ -77,6 +42,9 @@ struct ThreatMetadata {
ThreatMetadata(const ThreatMetadata& other);
~ThreatMetadata();
+ bool operator==(const ThreatMetadata& other) const;
+ bool operator!=(const ThreatMetadata& other) const;
+
// Type of blacklisted page. Used on malware and UwS lists.
// This will be NONE if it wasn't present in the reponse.
ThreatPatternType threat_pattern_type;
@@ -191,14 +159,6 @@ ListType GetListId(const base::StringPiece& name);
// Maps a ListId to list name. Return false if fails.
bool GetListName(ListType list_id, std::string* list);
-// Canonicalizes url as per Google Safe Browsing Specification.
-// See section 6.1 in
-// http://code.google.com/p/google-safe-browsing/wiki/Protocolv2Spec.
-void CanonicalizeUrl(const GURL& url, std::string* canonicalized_hostname,
- std::string* canonicalized_path,
- std::string* canonicalized_query);
-
-
// Generate the set of full hashes to check for |url|. If
// |include_whitelist_hashes| is true we will generate additional path-prefixes
// to match against the csd whitelist. E.g., if the path-prefix /foo is on the
@@ -206,17 +166,6 @@ void CanonicalizeUrl(const GURL& url, std::string* canonicalized_hostname,
// other lists. We'll also always add a pattern for the empty path.
void UrlToFullHashes(const GURL& url, bool include_whitelist_hashes,
std::vector<SBFullHash>* full_hashes);
-
-// Given a URL, returns all the hosts we need to check. They are returned
-// in order of size (i.e. b.c is first, then a.b.c).
-void GenerateHostsToCheck(const GURL& url, std::vector<std::string>* hosts);
-
-// Given a URL, returns all the paths we need to check.
-void GeneratePathsToCheck(const GURL& url, std::vector<std::string>* paths);
-
-// Given a URL, returns all the patterns we need to check.
-void GeneratePatternsToCheck(const GURL& url, std::vector<std::string>* urls);
-
} // namespace safe_browsing
#endif // COMPONENTS_SAFE_BROWSING_DB_UTIL_H_
diff --git a/chromium/components/safe_browsing_db/util_unittest.cc b/chromium/components/safe_browsing_db/util_unittest.cc
index 85f32a9146d..c105c4a27e3 100644
--- a/chromium/components/safe_browsing_db/util_unittest.cc
+++ b/chromium/components/safe_browsing_db/util_unittest.cc
@@ -14,273 +14,6 @@
namespace safe_browsing {
-namespace {
-
-bool VectorContains(const std::vector<std::string>& data,
- const std::string& str) {
- return std::find(data.begin(), data.end(), str) != data.end();
-}
-
-} // namespace
-
-// Tests that we generate the required host/path combinations for testing
-// according to the Safe Browsing spec.
-// See section 6.2 in
-// http://code.google.com/p/google-safe-browsing/wiki/Protocolv2Spec.
-TEST(SafeBrowsingDbUtilTest, UrlParsing) {
- std::vector<std::string> hosts, paths;
-
- GURL url("http://a.b.c/1/2.html?param=1");
- GenerateHostsToCheck(url, &hosts);
- GeneratePathsToCheck(url, &paths);
- EXPECT_EQ(hosts.size(), static_cast<size_t>(2));
- EXPECT_EQ(paths.size(), static_cast<size_t>(4));
- EXPECT_EQ(hosts[0], "b.c");
- EXPECT_EQ(hosts[1], "a.b.c");
-
- EXPECT_TRUE(VectorContains(paths, "/1/2.html?param=1"));
- EXPECT_TRUE(VectorContains(paths, "/1/2.html"));
- EXPECT_TRUE(VectorContains(paths, "/1/"));
- EXPECT_TRUE(VectorContains(paths, "/"));
-
- url = GURL("http://a.b.c.d.e.f.g/1.html");
- GenerateHostsToCheck(url, &hosts);
- GeneratePathsToCheck(url, &paths);
- EXPECT_EQ(hosts.size(), static_cast<size_t>(5));
- EXPECT_EQ(paths.size(), static_cast<size_t>(2));
- EXPECT_EQ(hosts[0], "f.g");
- EXPECT_EQ(hosts[1], "e.f.g");
- EXPECT_EQ(hosts[2], "d.e.f.g");
- EXPECT_EQ(hosts[3], "c.d.e.f.g");
- EXPECT_EQ(hosts[4], "a.b.c.d.e.f.g");
- EXPECT_TRUE(VectorContains(paths, "/1.html"));
- EXPECT_TRUE(VectorContains(paths, "/"));
-
- url = GURL("http://a.b/saw-cgi/eBayISAPI.dll/");
- GeneratePathsToCheck(url, &paths);
- EXPECT_EQ(paths.size(), static_cast<size_t>(3));
- EXPECT_TRUE(VectorContains(paths, "/saw-cgi/eBayISAPI.dll/"));
- EXPECT_TRUE(VectorContains(paths, "/saw-cgi/"));
- EXPECT_TRUE(VectorContains(paths, "/"));
-}
-
-// Tests the url canonicalization according to the Safe Browsing spec.
-// See section 6.1 in
-// http://code.google.com/p/google-safe-browsing/wiki/Protocolv2Spec.
-TEST(SafeBrowsingDbUtilTest, CanonicalizeUrl) {
- struct {
- const char* input_url;
- const char* expected_canonicalized_hostname;
- const char* expected_canonicalized_path;
- const char* expected_canonicalized_query;
- } tests[] = {
- {
- "http://host/%25%32%35",
- "host",
- "/%25",
- ""
- }, {
- "http://host/%25%32%35%25%32%35",
- "host",
- "/%25%25",
- ""
- }, {
- "http://host/%2525252525252525",
- "host",
- "/%25",
- ""
- }, {
- "http://host/asdf%25%32%35asd",
- "host",
- "/asdf%25asd",
- ""
- }, {
- "http://host/%%%25%32%35asd%%",
- "host",
- "/%25%25%25asd%25%25",
- ""
- }, {
- "http://host/%%%25%32%35asd%%",
- "host",
- "/%25%25%25asd%25%25",
- ""
- }, {
- "http://www.google.com/",
- "www.google.com",
- "/",
- ""
- }, {
- "http://%31%36%38%2e%31%38%38%2e%39%39%2e%32%36/%2E%73%65%63%75%72%65/%77"
- "%77%77%2E%65%62%61%79%2E%63%6F%6D/",
- "168.188.99.26",
- "/.secure/www.ebay.com/",
- ""
- }, {
- "http://195.127.0.11/uploads/%20%20%20%20/.verify/.eBaysecure=updateuserd"
- "ataxplimnbqmn-xplmvalidateinfoswqpcmlx=hgplmcx/",
- "195.127.0.11",
- "/uploads/%20%20%20%20/.verify/.eBaysecure=updateuserdataxplimnbqmn-xplmv"
- "alidateinfoswqpcmlx=hgplmcx/",
- ""
- }, {
- "http://host.com/%257Ea%2521b%2540c%2523d%2524e%25f%255E00%252611%252A"
- "22%252833%252944_55%252B",
- "host.com",
- "/~a!b@c%23d$e%25f^00&11*22(33)44_55+",
- ""
- }, {
- "http://3279880203/blah",
- "195.127.0.11",
- "/blah",
- ""
- }, {
- "http://www.google.com/blah/..",
- "www.google.com",
- "/",
- ""
- }, {
- "http://www.google.com/blah#fraq",
- "www.google.com",
- "/blah",
- ""
- }, {
- "http://www.GOOgle.com/",
- "www.google.com",
- "/",
- ""
- }, {
- "http://www.google.com.../",
- "www.google.com",
- "/",
- ""
- }, {
- "http://www.google.com/q?",
- "www.google.com",
- "/q",
- ""
- }, {
- "http://www.google.com/q?r?",
- "www.google.com",
- "/q",
- "r?"
- }, {
- "http://www.google.com/q?r?s",
- "www.google.com",
- "/q",
- "r?s"
- }, {
- "http://evil.com/foo#bar#baz",
- "evil.com",
- "/foo",
- ""
- }, {
- "http://evil.com/foo;",
- "evil.com",
- "/foo;",
- ""
- }, {
- "http://evil.com/foo?bar;",
- "evil.com",
- "/foo",
- "bar;"
- }, {
- "http://notrailingslash.com",
- "notrailingslash.com",
- "/",
- ""
- }, {
- "http://www.gotaport.com:1234/",
- "www.gotaport.com",
- "/",
- ""
- }, {
- " http://www.google.com/ ",
- "www.google.com",
- "/",
- ""
- }, {
- "http:// leadingspace.com/",
- "%20leadingspace.com",
- "/",
- ""
- }, {
- "http://%20leadingspace.com/",
- "%20leadingspace.com",
- "/",
- ""
- }, {
- "https://www.securesite.com/",
- "www.securesite.com",
- "/",
- ""
- }, {
- "http://host.com/ab%23cd",
- "host.com",
- "/ab%23cd",
- ""
- }, {
- "http://host%3e.com//twoslashes?more//slashes",
- "host>.com",
- "/twoslashes",
- "more//slashes"
- }, {
- "http://host.com/abc?val=xyz#anything",
- "host.com",
- "/abc",
- "val=xyz"
- }, {
- "http://abc:def@host.com/xyz",
- "host.com",
- "/xyz",
- ""
- }, {
- "http://host%3e.com/abc/%2e%2e%2fdef",
- "host>.com",
- "/def",
- ""
- }, {
- "http://.......host...com.....//abc/////def%2F%2F%2Fxyz",
- "host.com",
- "/abc/def/xyz",
- ""
- }, {
- "ftp://host.com/foo?bar",
- "host.com",
- "/foo",
- "bar"
- }, {
- "data:text/html;charset=utf-8,%0D%0A",
- "",
- "",
- ""
- }, {
- "javascript:alert()",
- "",
- "",
- ""
- }, {
- "mailto:abc@example.com",
- "",
- "",
- ""
- },
- };
- for (size_t i = 0; i < arraysize(tests); ++i) {
- SCOPED_TRACE(base::StringPrintf("Test: %s", tests[i].input_url));
- GURL url(tests[i].input_url);
-
- std::string canonicalized_hostname;
- std::string canonicalized_path;
- std::string canonicalized_query;
- CanonicalizeUrl(url, &canonicalized_hostname, &canonicalized_path,
- &canonicalized_query);
-
- EXPECT_EQ(tests[i].expected_canonicalized_hostname, canonicalized_hostname);
- EXPECT_EQ(tests[i].expected_canonicalized_path, canonicalized_path);
- EXPECT_EQ(tests[i].expected_canonicalized_query, canonicalized_query);
- }
-}
-
TEST(SafeBrowsingDbUtilTest, UrlToFullHashes) {
std::vector<SBFullHash> results;
GURL url("http://www.evil.com/evil1/evilness.html");
diff --git a/chromium/components/safe_browsing_db/v4_database.cc b/chromium/components/safe_browsing_db/v4_database.cc
index c54cdbc1ad2..6e14e5f099d 100644
--- a/chromium/components/safe_browsing_db/v4_database.cc
+++ b/chromium/components/safe_browsing_db/v4_database.cc
@@ -8,7 +8,7 @@
#include "base/debug/leak_annotations.h"
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "components/safe_browsing_db/v4_database.h"
#include "content/public/browser/browser_thread.h"
@@ -23,24 +23,24 @@ V4StoreFactory* V4Database::factory_ = NULL;
void V4Database::Create(
const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
const base::FilePath& base_path,
- const StoreFileNameMap& store_file_name_map,
+ const ListInfos& list_infos,
NewDatabaseReadyCallback new_db_callback) {
DCHECK(base_path.IsAbsolute());
- DCHECK(!store_file_name_map.empty());
+ DCHECK(!list_infos.empty());
- const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner =
- base::MessageLoop::current()->task_runner();
+ const scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner =
+ base::ThreadTaskRunnerHandle::Get();
db_task_runner->PostTask(
FROM_HERE,
base::Bind(&V4Database::CreateOnTaskRunner, db_task_runner, base_path,
- store_file_name_map, callback_task_runner, new_db_callback));
+ list_infos, callback_task_runner, new_db_callback));
}
// static
void V4Database::CreateOnTaskRunner(
const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
const base::FilePath& base_path,
- const StoreFileNameMap& store_file_name_map,
+ const ListInfos& list_infos,
const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
NewDatabaseReadyCallback new_db_callback) {
DCHECK(db_task_runner->RunsTasksOnCurrentThread());
@@ -55,10 +55,14 @@ void V4Database::CreateOnTaskRunner(
}
std::unique_ptr<StoreMap> store_map = base::MakeUnique<StoreMap>();
- for (const auto& store_info : store_file_name_map) {
- const UpdateListIdentifier& update_list_identifier = store_info.first;
- const base::FilePath store_path = base_path.AppendASCII(store_info.second);
- (*store_map)[update_list_identifier].reset(
+ for (const auto& it : list_infos) {
+ if (!it.fetch_updates()) {
+ // This list doesn't need to be fetched or stored on disk.
+ continue;
+ }
+
+ const base::FilePath store_path = base_path.AppendASCII(it.filename());
+ (*store_map)[it.list_id()].reset(
factory_->CreateV4Store(db_task_runner, store_path));
}
std::unique_ptr<V4Database> v4_database(
@@ -103,11 +107,11 @@ void V4Database::ApplyUpdate(
// Post the V4Store update task on the task runner but get the callback on the
// current thread.
- const scoped_refptr<base::SingleThreadTaskRunner>& current_task_runner =
- base::MessageLoop::current()->task_runner();
+ const scoped_refptr<base::SingleThreadTaskRunner> current_task_runner =
+ base::ThreadTaskRunnerHandle::Get();
for (std::unique_ptr<ListUpdateResponse>& response :
*parsed_server_response) {
- UpdateListIdentifier identifier(*response);
+ ListIdentifier identifier(*response);
StoreMap::const_iterator iter = store_map_->find(identifier);
if (iter != store_map_->end()) {
const std::unique_ptr<V4Store>& old_store = iter->second;
@@ -133,11 +137,13 @@ void V4Database::ApplyUpdate(
}
}
-void V4Database::UpdatedStoreReady(UpdateListIdentifier identifier,
+void V4Database::UpdatedStoreReady(ListIdentifier identifier,
std::unique_ptr<V4Store> new_store) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(pending_store_updates_);
- (*store_map_)[identifier] = std::move(new_store);
+ if (new_store) {
+ (*store_map_)[identifier] = std::move(new_store);
+ }
pending_store_updates_--;
if (!pending_store_updates_) {
@@ -166,4 +172,35 @@ std::unique_ptr<StoreStateMap> V4Database::GetStoreStateMap() {
return store_state_map;
}
+void V4Database::GetStoresMatchingFullHash(
+ const FullHash& full_hash,
+ const StoresToCheck& stores_to_check,
+ StoreAndHashPrefixes* matched_store_and_hash_prefixes) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ matched_store_and_hash_prefixes->clear();
+ for (const ListIdentifier& identifier : stores_to_check) {
+ const auto& store_pair = store_map_->find(identifier);
+ DCHECK(store_pair != store_map_->end());
+ const std::unique_ptr<V4Store>& store = store_pair->second;
+ HashPrefix hash_prefix = store->GetMatchingHashPrefix(full_hash);
+ if (!hash_prefix.empty()) {
+ matched_store_and_hash_prefixes->emplace_back(identifier, hash_prefix);
+ }
+ }
+}
+
+ListInfo::ListInfo(const bool fetch_updates,
+ const std::string& filename,
+ const ListIdentifier& list_id,
+ const SBThreatType sb_threat_type)
+ : fetch_updates_(fetch_updates),
+ filename_(filename),
+ list_id_(list_id),
+ sb_threat_type_(sb_threat_type) {
+ DCHECK(!fetch_updates_ || !filename_.empty());
+ DCHECK_NE(SB_THREAT_TYPE_SAFE, sb_threat_type_);
+}
+
+ListInfo::~ListInfo() {}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_database.h b/chromium/components/safe_browsing_db/v4_database.h
index ceacfc10fe4..bddba598850 100644
--- a/chromium/components/safe_browsing_db/v4_database.h
+++ b/chromium/components/safe_browsing_db/v4_database.h
@@ -25,10 +25,44 @@ typedef base::Callback<void(std::unique_ptr<V4Database>)>
// requests.
typedef base::Callback<void()> DatabaseUpdatedCallback;
-// This hash_map maps the UpdateListIdentifiers to their corresponding in-memory
-// stores, which contain the hash prefixes for that UpdateListIdentifier as well
-// as manage their storage on disk.
-typedef base::hash_map<UpdateListIdentifier, std::unique_ptr<V4Store>> StoreMap;
+// Maps the ListIdentifiers to their corresponding in-memory stores, which
+// contain the hash prefixes for that ListIdentifier as well as manage their
+// storage on disk.
+typedef base::hash_map<ListIdentifier, std::unique_ptr<V4Store>> StoreMap;
+
+// Associates metadata for a list with its ListIdentifier.
+struct ListInfo {
+ ListInfo(const bool fetch_updates,
+ const std::string& filename,
+ const ListIdentifier& list_id,
+ const SBThreatType sb_threat_type);
+ ~ListInfo();
+
+ ListIdentifier list_id() const { return list_id_; }
+ std::string filename() const { return filename_; }
+ SBThreatType sb_threat_type() const { return sb_threat_type_; }
+ bool fetch_updates() const { return fetch_updates_; }
+
+ private:
+ // Whether to fetch and store updates for this list.
+ bool fetch_updates_;
+
+ // The ASCII name of the file on disk. This file is created inside the
+ // user-data directory. For instance, the ListIdentifier could be for URL
+ // expressions for UwS on Windows platform, and the corresponding file on disk
+ // could be named: "UrlUws.store"
+ std::string filename_;
+
+ // The list being read from/written to the disk.
+ ListIdentifier list_id_;
+
+ // The threat type enum value for this store.
+ SBThreatType sb_threat_type_;
+
+ ListInfo();
+};
+
+typedef std::vector<ListInfo> ListInfos;
// Factory for creating V4Database. Tests implement this factory to create fake
// databases for testing.
@@ -38,7 +72,7 @@ class V4DatabaseFactory {
virtual V4Database* CreateV4Database(
const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
const base::FilePath& base_dir_path,
- const StoreFileNameMap& store_file_name_map) = 0;
+ const ListInfos& list_infos) = 0;
};
// The on-disk databases are shared among all profiles, as it doesn't contain
@@ -57,7 +91,7 @@ class V4Database {
static void Create(
const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
const base::FilePath& base_path,
- const StoreFileNameMap& store_file_name_map,
+ const ListInfos& list_infos,
NewDatabaseReadyCallback callback);
// Destroys the provided v4_database on its task_runner since this may be a
@@ -74,6 +108,14 @@ class V4Database {
// Returns the current state of each of the stores being managed.
std::unique_ptr<StoreStateMap> GetStoreStateMap();
+ // Searches for a hash prefix matching the |full_hash| in stores in the
+ // database, filtered by |stores_to_check|, and returns the identifier of the
+ // store along with the matching hash prefix in |matched_hash_prefix_map|.
+ virtual void GetStoresMatchingFullHash(
+ const FullHash& full_hash,
+ const StoresToCheck& stores_to_check,
+ StoreAndHashPrefixes* matched_store_and_full_hashes);
+
// Deletes the current database and creates a new one.
virtual bool ResetDatabase();
@@ -89,6 +131,8 @@ class V4Database {
FRIEND_TEST_ALL_PREFIXES(V4DatabaseTest, TestApplyUpdateWithNewStates);
FRIEND_TEST_ALL_PREFIXES(V4DatabaseTest, TestApplyUpdateWithNoNewState);
FRIEND_TEST_ALL_PREFIXES(V4DatabaseTest, TestApplyUpdateWithEmptyUpdate);
+ FRIEND_TEST_ALL_PREFIXES(V4DatabaseTest, TestApplyUpdateWithInvalidUpdate);
+ FRIEND_TEST_ALL_PREFIXES(V4DatabaseTest, TestSomeStoresMatchFullHash);
// Makes the passed |factory| the factory used to instantiate a V4Store. Only
// for tests.
@@ -101,19 +145,19 @@ class V4Database {
static void CreateOnTaskRunner(
const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
const base::FilePath& base_path,
- const StoreFileNameMap& store_file_name_map,
+ const ListInfos& list_infos,
const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
NewDatabaseReadyCallback callback);
// Callback called when a new store has been created and is ready to be used.
// This method updates the store_map_ to point to the new store, which causes
// the old store to get deleted.
- void UpdatedStoreReady(UpdateListIdentifier identifier,
+ void UpdatedStoreReady(ListIdentifier identifier,
std::unique_ptr<V4Store> store);
const scoped_refptr<base::SequencedTaskRunner> db_task_runner_;
- // Map of UpdateListIdentifier to the V4Store.
+ // Map of ListIdentifier to the V4Store.
const std::unique_ptr<StoreMap> store_map_;
DatabaseUpdatedCallback db_updated_callback_;
diff --git a/chromium/components/safe_browsing_db/v4_database_unittest.cc b/chromium/components/safe_browsing_db/v4_database_unittest.cc
index 2dee2a6628d..2ce05ee3ec1 100644
--- a/chromium/components/safe_browsing_db/v4_database_unittest.cc
+++ b/chromium/components/safe_browsing_db/v4_database_unittest.cc
@@ -19,15 +19,26 @@ class FakeV4Store : public V4Store {
public:
FakeV4Store(const scoped_refptr<base::SequencedTaskRunner>& task_runner,
const base::FilePath& store_path,
- const bool reset_succeeds)
+ const bool reset_succeeds,
+ const bool hash_prefix_matches)
: V4Store(
task_runner,
base::FilePath(store_path.value() + FILE_PATH_LITERAL(".fake"))),
+ hash_prefix_should_match_(hash_prefix_matches),
reset_succeeds_(reset_succeeds) {}
bool Reset() override { return reset_succeeds_; }
+ HashPrefix GetMatchingHashPrefix(const FullHash& full_hash) override {
+ return hash_prefix_should_match_ ? full_hash : HashPrefix();
+ }
+
+ void set_hash_prefix_matches(bool hash_prefix_matches) {
+ hash_prefix_should_match_ = hash_prefix_matches;
+ }
+
private:
+ bool hash_prefix_should_match_;
bool reset_succeeds_;
};
@@ -36,31 +47,37 @@ class FakeV4Store : public V4Store {
// always return true. This is used to test the Reset() method in V4Database.
class FakeV4StoreFactory : public V4StoreFactory {
public:
- FakeV4StoreFactory(bool next_store_reset_fails)
- : next_store_reset_fails_(next_store_reset_fails) {}
+ FakeV4StoreFactory(bool next_store_reset_fails, bool hash_prefix_matches)
+ : hash_prefix_should_match_(hash_prefix_matches),
+ next_store_reset_fails_(next_store_reset_fails) {}
V4Store* CreateV4Store(
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
const base::FilePath& store_path) override {
bool reset_succeeds = !next_store_reset_fails_;
next_store_reset_fails_ = false;
- return new FakeV4Store(task_runner, store_path, reset_succeeds);
+ return new FakeV4Store(task_runner, store_path, reset_succeeds,
+ hash_prefix_should_match_);
}
private:
+ bool hash_prefix_should_match_;
bool next_store_reset_fails_;
};
class V4DatabaseTest : public PlatformTest {
public:
- V4DatabaseTest() : task_runner_(new base::TestSimpleTaskRunner) {}
+ V4DatabaseTest()
+ : task_runner_(new base::TestSimpleTaskRunner),
+ linux_malware_id_(LINUX_PLATFORM, URL, MALWARE_THREAT),
+ win_malware_id_(WINDOWS_PLATFORM, URL, MALWARE_THREAT) {}
void SetUp() override {
PlatformTest::SetUp();
// Setup a database in a temporary directory.
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- database_dirname_ = temp_dir_.path().AppendASCII("V4DatabaseTest");
+ database_dirname_ = temp_dir_.GetPath().AppendASCII("V4DatabaseTest");
created_but_not_called_back_ = false;
created_and_called_back_ = false;
@@ -80,21 +97,23 @@ class V4DatabaseTest : public PlatformTest {
PlatformTest::TearDown();
}
- void RegisterFactory(bool fails_first_reset) {
- factory_.reset(new FakeV4StoreFactory(fails_first_reset));
+ void RegisterFactory(bool fails_first_reset,
+ bool hash_prefix_matches = true) {
+ factory_.reset(
+ new FakeV4StoreFactory(fails_first_reset, hash_prefix_matches));
V4Database::RegisterStoreFactoryForTest(factory_.get());
}
void SetupInfoMapAndExpectedState() {
- UpdateListIdentifier win_malware_id(WINDOWS_PLATFORM, URL, MALWARE_THREAT);
- store_file_name_map_[win_malware_id] = "win_url_malware";
- expected_identifiers_.push_back(win_malware_id);
+ list_infos_.emplace_back(true, "win_url_malware", win_malware_id_,
+ SB_THREAT_TYPE_URL_MALWARE);
+ expected_identifiers_.push_back(win_malware_id_);
expected_store_paths_.push_back(
database_dirname_.AppendASCII("win_url_malware.fake"));
- UpdateListIdentifier linux_malware_id(LINUX_PLATFORM, URL, MALWARE_THREAT);
- store_file_name_map_[linux_malware_id] = "linux_url_malware";
- expected_identifiers_.push_back(linux_malware_id);
+ list_infos_.emplace_back(true, "linux_url_malware", linux_malware_id_,
+ SB_THREAT_TYPE_URL_MALWARE);
+ expected_identifiers_.push_back(linux_malware_id_);
expected_store_paths_.push_back(
database_dirname_.AppendASCII("linux_url_malware.fake"));
}
@@ -127,17 +146,23 @@ class V4DatabaseTest : public PlatformTest {
}
std::unique_ptr<ParsedServerResponse> CreateFakeServerResponse(
- StoreStateMap store_state_map) {
+ StoreStateMap store_state_map,
+ bool use_valid_response_type) {
std::unique_ptr<ParsedServerResponse> parsed_server_response(
new ParsedServerResponse);
for (const auto& store_state_iter : store_state_map) {
- UpdateListIdentifier identifier = store_state_iter.first;
- ListUpdateResponse* list_update_response = new ListUpdateResponse;
- list_update_response->set_platform_type(identifier.platform_type);
- list_update_response->set_threat_entry_type(identifier.threat_entry_type);
- list_update_response->set_threat_type(identifier.threat_type);
- list_update_response->set_new_client_state(store_state_iter.second);
- parsed_server_response->push_back(base::WrapUnique(list_update_response));
+ ListIdentifier identifier = store_state_iter.first;
+ ListUpdateResponse* lur = new ListUpdateResponse;
+ lur->set_platform_type(identifier.platform_type());
+ lur->set_threat_entry_type(identifier.threat_entry_type());
+ lur->set_threat_type(identifier.threat_type());
+ lur->set_new_client_state(store_state_iter.second);
+ if (use_valid_response_type) {
+ lur->set_response_type(ListUpdateResponse::FULL_UPDATE);
+ } else {
+ lur->set_response_type(ListUpdateResponse::RESPONSE_TYPE_UNSPECIFIED);
+ }
+ parsed_server_response->push_back(base::WrapUnique(lur));
}
return parsed_server_response;
}
@@ -149,7 +174,7 @@ class V4DatabaseTest : public PlatformTest {
EXPECT_EQ(expected_store_state_map_.size(), new_store_map->size());
EXPECT_EQ(expected_store_state_map_.size(), new_store_state_map->size());
for (const auto& expected_iter : expected_store_state_map_) {
- const UpdateListIdentifier& identifier = expected_iter.first;
+ const ListIdentifier& identifier = expected_iter.first;
const std::string& state = expected_iter.second;
ASSERT_EQ(1u, new_store_map->count(identifier));
ASSERT_EQ(1u, new_store_state_map->count(identifier));
@@ -177,15 +202,16 @@ class V4DatabaseTest : public PlatformTest {
content::TestBrowserThreadBundle thread_bundle_;
bool created_but_not_called_back_;
bool created_and_called_back_;
- StoreFileNameMap store_file_name_map_;
- std::vector<UpdateListIdentifier> expected_identifiers_;
+ ListInfos list_infos_;
+ std::vector<ListIdentifier> expected_identifiers_;
std::vector<base::FilePath> expected_store_paths_;
bool expected_resets_successfully_;
std::unique_ptr<FakeV4StoreFactory> factory_;
DatabaseUpdatedCallback callback_db_updated_;
NewDatabaseReadyCallback callback_db_ready_;
StoreStateMap expected_store_state_map_;
- base::hash_map<UpdateListIdentifier, V4Store*> old_stores_map_;
+ base::hash_map<ListIdentifier, V4Store*> old_stores_map_;
+ const ListIdentifier linux_malware_id_, win_malware_id_;
};
// Test to set up the database with fake stores.
@@ -193,7 +219,7 @@ TEST_F(V4DatabaseTest, TestSetupDatabaseWithFakeStores) {
expected_resets_successfully_ = true;
RegisterFactory(!expected_resets_successfully_);
- V4Database::Create(task_runner_, database_dirname_, store_file_name_map_,
+ V4Database::Create(task_runner_, database_dirname_, list_infos_,
callback_db_ready_);
created_but_not_called_back_ = true;
task_runner_->RunPendingTasks();
@@ -207,7 +233,7 @@ TEST_F(V4DatabaseTest, TestSetupDatabaseWithFakeStoresFailsReset) {
expected_resets_successfully_ = false;
RegisterFactory(!expected_resets_successfully_);
- V4Database::Create(task_runner_, database_dirname_, store_file_name_map_,
+ V4Database::Create(task_runner_, database_dirname_, list_infos_,
callback_db_ready_);
created_but_not_called_back_ = true;
task_runner_->RunPendingTasks();
@@ -221,7 +247,7 @@ TEST_F(V4DatabaseTest, TestApplyUpdateWithNewStates) {
expected_resets_successfully_ = true;
RegisterFactory(!expected_resets_successfully_);
- V4Database::Create(task_runner_, database_dirname_, store_file_name_map_,
+ V4Database::Create(task_runner_, database_dirname_, list_infos_,
callback_db_ready_);
created_but_not_called_back_ = true;
task_runner_->RunPendingTasks();
@@ -237,8 +263,9 @@ TEST_F(V4DatabaseTest, TestApplyUpdateWithNewStates) {
old_stores_map_[store_iter.first] = store;
}
- v4_database_->ApplyUpdate(CreateFakeServerResponse(expected_store_state_map_),
- callback_db_updated_);
+ v4_database_->ApplyUpdate(
+ CreateFakeServerResponse(expected_store_state_map_, true),
+ callback_db_updated_);
task_runner_->RunPendingTasks();
base::RunLoop().RunUntilIdle();
@@ -251,7 +278,7 @@ TEST_F(V4DatabaseTest, TestApplyUpdateWithNoNewState) {
expected_resets_successfully_ = true;
RegisterFactory(!expected_resets_successfully_);
- V4Database::Create(task_runner_, database_dirname_, store_file_name_map_,
+ V4Database::Create(task_runner_, database_dirname_, list_infos_,
callback_db_ready_);
created_but_not_called_back_ = true;
task_runner_->RunPendingTasks();
@@ -267,8 +294,9 @@ TEST_F(V4DatabaseTest, TestApplyUpdateWithNoNewState) {
old_stores_map_[store_iter.first] = store;
}
- v4_database_->ApplyUpdate(CreateFakeServerResponse(expected_store_state_map_),
- callback_db_updated_);
+ v4_database_->ApplyUpdate(
+ CreateFakeServerResponse(expected_store_state_map_, true),
+ callback_db_updated_);
task_runner_->RunPendingTasks();
base::RunLoop().RunUntilIdle();
@@ -281,7 +309,7 @@ TEST_F(V4DatabaseTest, TestApplyUpdateWithEmptyUpdate) {
expected_resets_successfully_ = true;
RegisterFactory(!expected_resets_successfully_);
- V4Database::Create(task_runner_, database_dirname_, store_file_name_map_,
+ V4Database::Create(task_runner_, database_dirname_, list_infos_,
callback_db_ready_);
created_but_not_called_back_ = true;
task_runner_->RunPendingTasks();
@@ -308,4 +336,135 @@ TEST_F(V4DatabaseTest, TestApplyUpdateWithEmptyUpdate) {
VerifyExpectedStoresState(false);
}
+// Test to ensure invalid update leads to no store changes.
+TEST_F(V4DatabaseTest, TestApplyUpdateWithInvalidUpdate) {
+ expected_resets_successfully_ = true;
+ RegisterFactory(!expected_resets_successfully_);
+
+ V4Database::Create(task_runner_, database_dirname_, list_infos_,
+ callback_db_ready_);
+ created_but_not_called_back_ = true;
+ task_runner_->RunPendingTasks();
+ base::RunLoop().RunUntilIdle();
+
+ // The database has now been created. Time to try to update it.
+ EXPECT_TRUE(v4_database_);
+ const StoreMap* db_stores = v4_database_->store_map_.get();
+ EXPECT_EQ(expected_store_paths_.size(), db_stores->size());
+ for (const auto& store_iter : *db_stores) {
+ V4Store* store = store_iter.second.get();
+ expected_store_state_map_[store_iter.first] = store->state();
+ old_stores_map_[store_iter.first] = store;
+ }
+
+ v4_database_->ApplyUpdate(
+ CreateFakeServerResponse(expected_store_state_map_, false),
+ callback_db_updated_);
+ task_runner_->RunPendingTasks();
+ base::RunLoop().RunUntilIdle();
+
+ VerifyExpectedStoresState(false);
+}
+
+// Test to ensure the case that all stores match a given full hash.
+TEST_F(V4DatabaseTest, TestAllStoresMatchFullHash) {
+ bool hash_prefix_matches = true;
+ expected_resets_successfully_ = true;
+ RegisterFactory(!expected_resets_successfully_, hash_prefix_matches);
+
+ V4Database::Create(task_runner_, database_dirname_, list_infos_,
+ callback_db_ready_);
+ created_but_not_called_back_ = true;
+ task_runner_->RunPendingTasks();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(true, created_and_called_back_);
+
+ StoresToCheck stores_to_check({linux_malware_id_, win_malware_id_});
+ StoreAndHashPrefixes store_and_hash_prefixes;
+ v4_database_->GetStoresMatchingFullHash("anything", stores_to_check,
+ &store_and_hash_prefixes);
+ EXPECT_EQ(2u, store_and_hash_prefixes.size());
+ StoresToCheck stores_found;
+ for (const auto& it : store_and_hash_prefixes) {
+ stores_found.insert(it.list_id);
+ }
+ EXPECT_EQ(stores_to_check, stores_found);
+}
+
+// Test to ensure the case that no stores match a given full hash.
+TEST_F(V4DatabaseTest, TestNoStoreMatchesFullHash) {
+ bool hash_prefix_matches = false;
+ expected_resets_successfully_ = true;
+ RegisterFactory(!expected_resets_successfully_, hash_prefix_matches);
+
+ V4Database::Create(task_runner_, database_dirname_, list_infos_,
+ callback_db_ready_);
+ created_but_not_called_back_ = true;
+ task_runner_->RunPendingTasks();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(true, created_and_called_back_);
+
+ StoreAndHashPrefixes store_and_hash_prefixes;
+ v4_database_->GetStoresMatchingFullHash(
+ "anything", StoresToCheck({linux_malware_id_, win_malware_id_}),
+ &store_and_hash_prefixes);
+ EXPECT_TRUE(store_and_hash_prefixes.empty());
+}
+
+// Test to ensure the case that some stores match a given full hash.
+TEST_F(V4DatabaseTest, TestSomeStoresMatchFullHash) {
+ // Setup stores to not match the full hash.
+ bool hash_prefix_matches = false;
+ expected_resets_successfully_ = true;
+ RegisterFactory(!expected_resets_successfully_, hash_prefix_matches);
+
+ V4Database::Create(task_runner_, database_dirname_, list_infos_,
+ callback_db_ready_);
+ created_but_not_called_back_ = true;
+ task_runner_->RunPendingTasks();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(true, created_and_called_back_);
+
+ // Set the store corresponding to linux_malware_id_ to match the full hash.
+ FakeV4Store* store = static_cast<FakeV4Store*>(
+ v4_database_->store_map_->at(win_malware_id_).get());
+ store->set_hash_prefix_matches(true);
+
+ StoreAndHashPrefixes store_and_hash_prefixes;
+ v4_database_->GetStoresMatchingFullHash(
+ "anything", StoresToCheck({linux_malware_id_, win_malware_id_}),
+ &store_and_hash_prefixes);
+ EXPECT_EQ(1u, store_and_hash_prefixes.size());
+ EXPECT_EQ(store_and_hash_prefixes.begin()->list_id, win_malware_id_);
+ EXPECT_FALSE(store_and_hash_prefixes.begin()->hash_prefix.empty());
+}
+
+// Test to ensure the case that only some stores are reported to match a given
+// full hash because of StoresToCheck.
+TEST_F(V4DatabaseTest, TestSomeStoresMatchFullHashBecauseOfStoresToMatch) {
+ // Setup all stores to match the full hash.
+ bool hash_prefix_matches = true;
+ expected_resets_successfully_ = true;
+ RegisterFactory(!expected_resets_successfully_, hash_prefix_matches);
+
+ V4Database::Create(task_runner_, database_dirname_, list_infos_,
+ callback_db_ready_);
+ created_but_not_called_back_ = true;
+ task_runner_->RunPendingTasks();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(true, created_and_called_back_);
+
+ // Don't add win_malware_id_ to the StoresToCheck.
+ StoreAndHashPrefixes store_and_hash_prefixes;
+ v4_database_->GetStoresMatchingFullHash(
+ "anything", StoresToCheck({linux_malware_id_}), &store_and_hash_prefixes);
+ EXPECT_EQ(1u, store_and_hash_prefixes.size());
+ EXPECT_EQ(store_and_hash_prefixes.begin()->list_id, linux_malware_id_);
+ EXPECT_FALSE(store_and_hash_prefixes.begin()->hash_prefix.empty());
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_feature_list.cc b/chromium/components/safe_browsing_db/v4_feature_list.cc
new file mode 100644
index 00000000000..a8435edf051
--- /dev/null
+++ b/chromium/components/safe_browsing_db/v4_feature_list.cc
@@ -0,0 +1,32 @@
+// 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 "base/feature_list.h"
+#include "components/safe_browsing_db/v4_feature_list.h"
+
+namespace safe_browsing {
+
+namespace V4FeatureList {
+
+namespace {
+const base::Feature kLocalDatabaseManagerEnabled{
+ "SafeBrowsingV4LocalDatabaseManagerEnabled",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kParallelCheckEnabled{"SafeBrowingV4ParallelCheckEnabled",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+} // namespace
+
+bool IsLocalDatabaseManagerEnabled() {
+ return IsParallelCheckEnabled() ||
+ base::FeatureList::IsEnabled(kLocalDatabaseManagerEnabled);
+}
+
+bool IsParallelCheckEnabled() {
+ return base::FeatureList::IsEnabled(kParallelCheckEnabled);
+}
+
+} // namespace V4FeatureList
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_feature_list.h b/chromium/components/safe_browsing_db/v4_feature_list.h
new file mode 100644
index 00000000000..b30554143a1
--- /dev/null
+++ b/chromium/components/safe_browsing_db/v4_feature_list.h
@@ -0,0 +1,24 @@
+// 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 COMPONENTS_SAFE_BROWSING_DB_V4_FEATURE_LIST_H_
+#define COMPONENTS_SAFE_BROWSING_DB_V4_FEATURE_LIST_H_
+
+namespace safe_browsing {
+
+// Exposes methods to check whether a particular feature has been enabled
+// through Finch.
+namespace V4FeatureList {
+
+// Is the Pver4 database manager enabled?
+bool IsLocalDatabaseManagerEnabled();
+
+// Is the Pver4 database manager doing resource checks in paralled with PVer3?
+bool IsParallelCheckEnabled();
+
+} // namespace V4FeatureList
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_DB_V4_FEATURE_LIST_H_
diff --git a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.cc b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
index 4b5f911d3ae..96bafa951e3 100644
--- a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
+++ b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
@@ -8,8 +8,10 @@
#include "base/base64url.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/timer/timer.h"
+#include "content/public/browser/browser_thread.h"
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
@@ -18,9 +20,17 @@
using base::Time;
using base::TimeDelta;
+using content::BrowserThread;
namespace {
+// Record a GetHash result.
+void RecordGetHashResult(safe_browsing::V4OperationResult result) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "SafeBrowsing.GetV4HashResult", result,
+ safe_browsing::V4OperationResult::OPERATION_RESULT_MAX);
+}
+
// Enumerate parsing failures for histogramming purposes. DO NOT CHANGE
// THE ORDERING OF THESE VALUES.
enum ParseResultType {
@@ -47,9 +57,12 @@ enum ParseResultType {
// A match in the response contained a metadata, but the metadata is invalid.
UNEXPECTED_METADATA_VALUE_ERROR = 6,
+ // A match in the response had no information in the threat field.
+ NO_THREAT_ERROR = 7,
+
// Memory space for histograms is determined by the max. ALWAYS
// ADD NEW VALUES BEFORE THIS ONE.
- PARSE_RESULT_TYPE_MAX = 7,
+ PARSE_RESULT_TYPE_MAX = 8,
};
// Record parsing errors of a GetHash result.
@@ -58,13 +71,62 @@ void RecordParseGetHashResult(ParseResultType result_type) {
PARSE_RESULT_TYPE_MAX);
}
-// Record a GetHash result.
-void RecordGetHashResult(safe_browsing::V4OperationResult result) {
- UMA_HISTOGRAM_ENUMERATION(
- "SafeBrowsing.GetV4HashResult", result,
- safe_browsing::V4OperationResult::OPERATION_RESULT_MAX);
+// Enumerate full hash cache hits/misses for histogramming purposes.
+// DO NOT CHANGE THE ORDERING OF THESE VALUES.
+enum V4FullHashCacheResultType {
+ // Full hashes for which there is no cache hit.
+ FULL_HASH_CACHE_MISS = 0,
+
+ // Full hashes with a cache hit.
+ FULL_HASH_CACHE_HIT = 1,
+
+ // Full hashes with a negative cache hit.
+ FULL_HASH_NEGATIVE_CACHE_HIT = 2,
+
+ // Memory space for histograms is determined by the max. ALWAYS
+ // ADD NEW VALUES BEFORE THIS ONE.
+ FULL_HASH_CACHE_RESULT_MAX
+};
+
+// Record a full hash cache hit result.
+void RecordV4FullHashCacheResult(V4FullHashCacheResultType result_type) {
+ UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4FullHashCacheResult", result_type,
+ FULL_HASH_CACHE_RESULT_MAX);
}
+// Enumerate GetHash hits/misses for histogramming purposes. DO NOT CHANGE THE
+// ORDERING OF THESE VALUES.
+enum V4GetHashCheckResultType {
+ // Successful responses which returned no full hashes.
+ GET_HASH_CHECK_EMPTY = 0,
+
+ // Successful responses for which one or more of the full hashes matched.
+ GET_HASH_CHECK_HIT = 1,
+
+ // Successful responses which weren't empty but have no matches.
+ GET_HASH_CHECK_MISS = 2,
+
+ // Memory space for histograms is determined by the max. ALWAYS
+ // ADD NEW VALUES BEFORE THIS ONE.
+ GET_HASH_CHECK_RESULT_MAX
+};
+
+// Record a GetHash hit result.
+void RecordV4GetHashCheckResult(V4GetHashCheckResultType result_type) {
+ UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4GetHashCheckResult", result_type,
+ GET_HASH_CHECK_RESULT_MAX);
+}
+
+const char kPermission[] = "permission";
+const char kPhaPatternType[] = "pha_pattern_type";
+const char kMalwarePatternType[] = "malware_pattern_type";
+const char kSePatternType[] = "se_pattern_type";
+const char kLanding[] = "LANDING";
+const char kDistribution[] = "DISTRIBUTION";
+const char kSocialEngineeringAds[] = "SOCIAL_ENGINEERING_ADS";
+const char kSocialEngineeringLanding[] = "SOCIAL_ENGINEERING_LANDING";
+const char kPhishing[] = "PHISHING";
+
} // namespace
namespace safe_browsing {
@@ -78,37 +140,96 @@ class V4GetHashProtocolManagerFactoryImpl
public:
V4GetHashProtocolManagerFactoryImpl() {}
~V4GetHashProtocolManagerFactoryImpl() override {}
- V4GetHashProtocolManager* CreateProtocolManager(
+ std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager(
net::URLRequestContextGetter* request_context_getter,
+ const StoresToCheck& stores_to_check,
const V4ProtocolConfig& config) override {
- return new V4GetHashProtocolManager(request_context_getter, config);
+ return base::WrapUnique(new V4GetHashProtocolManager(
+ request_context_getter, stores_to_check, config));
}
private:
DISALLOW_COPY_AND_ASSIGN(V4GetHashProtocolManagerFactoryImpl);
};
+// ----------------------------------------------------------------
+
+CachedHashPrefixInfo::CachedHashPrefixInfo() {}
+
+CachedHashPrefixInfo::CachedHashPrefixInfo(const CachedHashPrefixInfo& other) =
+ default;
+
+CachedHashPrefixInfo::~CachedHashPrefixInfo() {}
+
+// ----------------------------------------------------------------
+
+FullHashCallbackInfo::FullHashCallbackInfo() {}
+
+FullHashCallbackInfo::FullHashCallbackInfo(
+ const std::vector<FullHashInfo>& cached_full_hash_infos,
+ const std::vector<HashPrefix>& prefixes_requested,
+ std::unique_ptr<net::URLFetcher> fetcher,
+ const FullHashToStoreAndHashPrefixesMap&
+ full_hash_to_store_and_hash_prefixes,
+ const FullHashCallback& callback)
+ : cached_full_hash_infos(cached_full_hash_infos),
+ callback(callback),
+ fetcher(std::move(fetcher)),
+ full_hash_to_store_and_hash_prefixes(
+ full_hash_to_store_and_hash_prefixes),
+ prefixes_requested(prefixes_requested) {}
+
+FullHashCallbackInfo::~FullHashCallbackInfo() {}
+
+// ----------------------------------------------------------------
+
+FullHashInfo::FullHashInfo(const FullHash& full_hash,
+ const ListIdentifier& list_id,
+ const base::Time& positive_expiry)
+ : full_hash(full_hash),
+ list_id(list_id),
+ positive_expiry(positive_expiry) {}
+
+FullHashInfo::FullHashInfo(const FullHashInfo& other) = default;
+
+FullHashInfo::~FullHashInfo() {}
+
+bool FullHashInfo::operator==(const FullHashInfo& other) const {
+ return full_hash == other.full_hash && list_id == other.list_id &&
+ positive_expiry == other.positive_expiry && metadata == other.metadata;
+}
+
+bool FullHashInfo::operator!=(const FullHashInfo& other) const {
+ return !operator==(other);
+}
+
// V4GetHashProtocolManager implementation --------------------------------
// static
V4GetHashProtocolManagerFactory* V4GetHashProtocolManager::factory_ = NULL;
// static
-V4GetHashProtocolManager* V4GetHashProtocolManager::Create(
+std::unique_ptr<V4GetHashProtocolManager> V4GetHashProtocolManager::Create(
net::URLRequestContextGetter* request_context_getter,
+ const StoresToCheck& stores_to_check,
const V4ProtocolConfig& config) {
if (!factory_)
factory_ = new V4GetHashProtocolManagerFactoryImpl();
- return factory_->CreateProtocolManager(request_context_getter, config);
+ return factory_->CreateProtocolManager(request_context_getter,
+ stores_to_check, config);
}
-void V4GetHashProtocolManager::ResetGetHashErrors() {
- gethash_error_count_ = 0;
- gethash_back_off_mult_ = 1;
+// static
+void V4GetHashProtocolManager::RegisterFactory(
+ std::unique_ptr<V4GetHashProtocolManagerFactory> factory) {
+ if (factory_)
+ delete factory_;
+ factory_ = factory.release();
}
V4GetHashProtocolManager::V4GetHashProtocolManager(
net::URLRequestContextGetter* request_context_getter,
+ const StoresToCheck& stores_to_check,
const V4ProtocolConfig& config)
: gethash_error_count_(0),
gethash_back_off_mult_(1),
@@ -116,40 +237,213 @@ V4GetHashProtocolManager::V4GetHashProtocolManager(
config_(config),
request_context_getter_(request_context_getter),
url_fetcher_id_(0),
- clock_(new base::DefaultClock()) {}
+ clock_(new base::DefaultClock()) {
+ DCHECK(!stores_to_check.empty());
+ for (const ListIdentifier& store : stores_to_check) {
+ platform_types_.insert(store.platform_type());
+ threat_entry_types_.insert(store.threat_entry_type());
+ threat_types_.insert(store.threat_type());
+ }
+}
-V4GetHashProtocolManager::~V4GetHashProtocolManager() {
- // Delete in-progress SafeBrowsing requests.
- STLDeleteContainerPairFirstPointers(hash_requests_.begin(),
- hash_requests_.end());
- hash_requests_.clear();
+V4GetHashProtocolManager::~V4GetHashProtocolManager() {}
+
+void V4GetHashProtocolManager::ClearCache() {
+ DCHECK(CalledOnValidThread());
+ full_hash_cache_.clear();
}
-// static
-void V4GetHashProtocolManager::RegisterFactory(
- std::unique_ptr<V4GetHashProtocolManagerFactory> factory) {
- if (factory_)
- delete factory_;
- factory_ = factory.release();
+void V4GetHashProtocolManager::GetFullHashes(
+ const FullHashToStoreAndHashPrefixesMap&
+ full_hash_to_store_and_hash_prefixes,
+ FullHashCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(CalledOnValidThread());
+ DCHECK(!full_hash_to_store_and_hash_prefixes.empty());
+
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ GetFullHashCachedResults(full_hash_to_store_and_hash_prefixes, Time::Now(),
+ &prefixes_to_request, &cached_full_hash_infos);
+
+ if (prefixes_to_request.empty()) {
+ // 100% cache hits (positive or negative) so we can call the callback right
+ // away.
+ callback.Run(cached_full_hash_infos);
+ return;
+ }
+
+ // We need to wait the minimum waiting duration, and if we are in backoff,
+ // we need to check if we're past the next allowed time. If we are, we can
+ // proceed with the request. If not, we are required to return empty results
+ // (i.e. just use the results from cache and potentially report an unsafe
+ // resource as safe).
+ if (clock_->Now() <= next_gethash_time_) {
+ if (gethash_error_count_) {
+ RecordGetHashResult(V4OperationResult::BACKOFF_ERROR);
+ } else {
+ RecordGetHashResult(V4OperationResult::MIN_WAIT_DURATION_ERROR);
+ }
+ callback.Run(cached_full_hash_infos);
+ return;
+ }
+
+ std::string req_base64 = GetHashRequest(prefixes_to_request);
+ GURL gethash_url;
+ net::HttpRequestHeaders headers;
+ GetHashUrlAndHeaders(req_base64, &gethash_url, &headers);
+
+ std::unique_ptr<net::URLFetcher> owned_fetcher = net::URLFetcher::Create(
+ url_fetcher_id_++, gethash_url, net::URLFetcher::GET, this);
+ net::URLFetcher* fetcher = owned_fetcher.get();
+ pending_hash_requests_[fetcher].reset(new FullHashCallbackInfo(
+ cached_full_hash_infos, prefixes_to_request, std::move(owned_fetcher),
+ full_hash_to_store_and_hash_prefixes, callback));
+
+ fetcher->SetExtraRequestHeaders(headers.ToString());
+ fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE);
+ fetcher->SetRequestContext(request_context_getter_.get());
+ fetcher->Start();
+}
+
+void V4GetHashProtocolManager::GetFullHashesWithApis(
+ const GURL& url,
+ ThreatMetadataForApiCallback api_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kHttpsScheme));
+
+ std::unordered_set<FullHash> full_hashes;
+ V4ProtocolManagerUtil::UrlToFullHashes(url.GetOrigin(), &full_hashes);
+
+ FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
+ for (const FullHash& full_hash : full_hashes) {
+ HashPrefix prefix;
+ bool result =
+ V4ProtocolManagerUtil::FullHashToSmallestHashPrefix(full_hash, &prefix);
+ DCHECK(result);
+ full_hash_to_store_and_hash_prefixes[full_hash].emplace_back(
+ GetChromeUrlApiId(), prefix);
+ }
+
+ GetFullHashes(full_hash_to_store_and_hash_prefixes,
+ base::Bind(&V4GetHashProtocolManager::OnFullHashForApi,
+ base::Unretained(this), api_callback, full_hashes));
+}
+
+void V4GetHashProtocolManager::GetFullHashCachedResults(
+ const FullHashToStoreAndHashPrefixesMap&
+ full_hash_to_store_and_hash_prefixes,
+ const Time& now,
+ std::vector<HashPrefix>* prefixes_to_request,
+ std::vector<FullHashInfo>* cached_full_hash_infos) const {
+ DCHECK(!full_hash_to_store_and_hash_prefixes.empty());
+ DCHECK(prefixes_to_request->empty());
+ DCHECK(cached_full_hash_infos->empty());
+
+ // Caching behavior is documented here:
+ // https://developers.google.com/safe-browsing/v4/caching#about-caching
+ //
+ // The cache operates as follows:
+ // Lookup:
+ // Case 1: The prefix is in the cache.
+ // Case a: The full hash is in the cache.
+ // Case i : The positive full hash result has not expired.
+ // The result is unsafe and we do not need to send a new
+ // request.
+ // Case ii: The positive full hash result has expired.
+ // We need to send a request for full hashes.
+ // Case b: The full hash is not in the cache.
+ // Case i : The negative cache entry has not expired.
+ // The result is still safe and we do not need to send a
+ // new request.
+ // Case ii: The negative cache entry has expired.
+ // We need to send a request for full hashes.
+ // Case 2: The prefix is not in the cache.
+ // We need to send a request for full hashes.
+ //
+ // Note on eviction:
+ // CachedHashPrefixInfo entries can be removed from the cache only when
+ // the negative cache expire time and the cache expire time of all full
+ // hash results for that prefix have expired.
+ // Individual full hash results can be removed from the prefix's
+ // cache entry if they expire AND their expire time is after the negative
+ // cache expire time.
+
+ std::unordered_set<HashPrefix> unique_prefixes_to_request;
+ for (const auto& it : full_hash_to_store_and_hash_prefixes) {
+ const FullHash& full_hash = it.first;
+ const StoreAndHashPrefixes& matched = it.second;
+ for (const StoreAndHashPrefix& matched_it : matched) {
+ const ListIdentifier& list_id = matched_it.list_id;
+ const HashPrefix& prefix = matched_it.hash_prefix;
+ auto prefix_entry = full_hash_cache_.find(prefix);
+ if (prefix_entry != full_hash_cache_.end()) {
+ // Case 1.
+ const CachedHashPrefixInfo& cached_prefix_info = prefix_entry->second;
+ bool found_full_hash = false;
+ for (const FullHashInfo& full_hash_info :
+ cached_prefix_info.full_hash_infos) {
+ if (full_hash_info.full_hash == full_hash &&
+ full_hash_info.list_id == list_id) {
+ // Case a.
+ found_full_hash = true;
+ if (full_hash_info.positive_expiry > now) {
+ // Case i.
+ cached_full_hash_infos->push_back(full_hash_info);
+ RecordV4FullHashCacheResult(FULL_HASH_CACHE_HIT);
+ } else {
+ // Case ii.
+ unique_prefixes_to_request.insert(prefix);
+ RecordV4FullHashCacheResult(FULL_HASH_CACHE_MISS);
+ }
+ break;
+ }
+ }
+
+ if (!found_full_hash) {
+ // Case b.
+ if (cached_prefix_info.negative_expiry > now) {
+ // Case i.
+ RecordV4FullHashCacheResult(FULL_HASH_NEGATIVE_CACHE_HIT);
+ } else {
+ // Case ii.
+ unique_prefixes_to_request.insert(prefix);
+ RecordV4FullHashCacheResult(FULL_HASH_CACHE_MISS);
+ }
+ }
+ } else {
+ // Case 2.
+ unique_prefixes_to_request.insert(prefix);
+ RecordV4FullHashCacheResult(FULL_HASH_CACHE_MISS);
+ }
+ }
+ }
+
+ prefixes_to_request->insert(prefixes_to_request->begin(),
+ unique_prefixes_to_request.begin(),
+ unique_prefixes_to_request.end());
}
std::string V4GetHashProtocolManager::GetHashRequest(
- const std::vector<SBPrefix>& prefixes,
- const std::vector<PlatformType>& platforms,
- ThreatType threat_type) {
- // Build the request. Client info and client states are not added to the
- // request protocol buffer. Client info is passed as params in the url.
+ const std::vector<HashPrefix>& prefixes_to_request) {
+ DCHECK(!prefixes_to_request.empty());
+
FindFullHashesRequest req;
ThreatInfo* info = req.mutable_threat_info();
- info->add_threat_types(threat_type);
- info->add_threat_entry_types(URL);
- for (const PlatformType p : platforms) {
+ for (const PlatformType p : platform_types_) {
info->add_platform_types(p);
}
- for (const SBPrefix& prefix : prefixes) {
- std::string hash(reinterpret_cast<const char*>(&prefix), sizeof(SBPrefix));
- info->add_threat_entries()->set_hash(hash);
+ for (const ThreatEntryType tet : threat_entry_types_) {
+ info->add_threat_entry_types(tet);
+ }
+ for (const ThreatType tt : threat_types_) {
+ info->add_threat_types(tt);
}
+ for (const HashPrefix& prefix : prefixes_to_request) {
+ info->add_threat_entries()->set_hash(prefix);
+ }
+
+ V4ProtocolManagerUtil::SetClientInfoFromConfig(req.mutable_client(), config_);
// Serialize and Base64 encode.
std::string req_data, req_base64;
@@ -159,192 +453,235 @@ std::string V4GetHashProtocolManager::GetHashRequest(
return req_base64;
}
+void V4GetHashProtocolManager::GetHashUrlAndHeaders(
+ const std::string& req_base64,
+ GURL* gurl,
+ net::HttpRequestHeaders* headers) const {
+ V4ProtocolManagerUtil::GetRequestUrlAndHeaders(req_base64, "fullHashes:find",
+ config_, gurl, headers);
+}
+
+void V4GetHashProtocolManager::HandleGetHashError(const Time& now) {
+ DCHECK(CalledOnValidThread());
+ TimeDelta next = V4ProtocolManagerUtil::GetNextBackOffInterval(
+ &gethash_error_count_, &gethash_back_off_mult_);
+ next_gethash_time_ = now + next;
+}
+
+void V4GetHashProtocolManager::OnFullHashForApi(
+ const ThreatMetadataForApiCallback& api_callback,
+ const std::unordered_set<FullHash>& full_hashes,
+ const std::vector<FullHashInfo>& full_hash_infos) {
+ ThreatMetadata md;
+ for (const FullHashInfo& full_hash_info : full_hash_infos) {
+ DCHECK_EQ(GetChromeUrlApiId(), full_hash_info.list_id);
+ DCHECK(full_hashes.find(full_hash_info.full_hash) != full_hashes.end());
+ md.api_permissions.insert(full_hash_info.metadata.api_permissions.begin(),
+ full_hash_info.metadata.api_permissions.end());
+ }
+
+ api_callback.Run(md);
+}
+
bool V4GetHashProtocolManager::ParseHashResponse(
- const std::string& data,
- std::vector<SBFullHashResult>* full_hashes,
- base::Time* negative_cache_expire) {
+ const std::string& response_data,
+ std::vector<FullHashInfo>* full_hash_infos,
+ Time* negative_cache_expire) {
FindFullHashesResponse response;
- if (!response.ParseFromString(data)) {
+ if (!response.ParseFromString(response_data)) {
RecordParseGetHashResult(PARSE_FROM_STRING_ERROR);
return false;
}
// negative_cache_duration should always be set.
DCHECK(response.has_negative_cache_duration());
+
// Seconds resolution is good enough so we ignore the nanos field.
*negative_cache_expire =
- clock_->Now() + base::TimeDelta::FromSeconds(
- response.negative_cache_duration().seconds());
+ clock_->Now() +
+ TimeDelta::FromSeconds(response.negative_cache_duration().seconds());
if (response.has_minimum_wait_duration()) {
// Seconds resolution is good enough so we ignore the nanos field.
next_gethash_time_ =
- clock_->Now() + base::TimeDelta::FromSeconds(
- response.minimum_wait_duration().seconds());
+ clock_->Now() +
+ TimeDelta::FromSeconds(response.minimum_wait_duration().seconds());
}
- // We only expect one threat type per request, so we make sure
- // the threat types are consistent between matches.
- ThreatType expected_threat_type = THREAT_TYPE_UNSPECIFIED;
-
- // Loop over the threat matches and fill in full_hashes.
for (const ThreatMatch& match : response.matches()) {
- // Make sure the platform and threat entry type match.
- if (!(match.has_threat_entry_type() && match.threat_entry_type() == URL &&
- match.has_threat())) {
+ if (!match.has_platform_type()) {
+ RecordParseGetHashResult(UNEXPECTED_PLATFORM_TYPE_ERROR);
+ return false;
+ }
+ if (!match.has_threat_entry_type()) {
RecordParseGetHashResult(UNEXPECTED_THREAT_ENTRY_TYPE_ERROR);
return false;
}
-
if (!match.has_threat_type()) {
RecordParseGetHashResult(UNEXPECTED_THREAT_TYPE_ERROR);
return false;
}
-
- if (expected_threat_type == THREAT_TYPE_UNSPECIFIED) {
- expected_threat_type = match.threat_type();
- } else if (match.threat_type() != expected_threat_type) {
- RecordParseGetHashResult(INCONSISTENT_THREAT_TYPE_ERROR);
+ if (!match.has_threat()) {
+ RecordParseGetHashResult(NO_THREAT_ERROR);
return false;
}
- // Fill in the full hash.
- SBFullHashResult result;
- result.hash = StringToSBFullHash(match.threat().hash());
-
+ ListIdentifier list_id(match.platform_type(), match.threat_entry_type(),
+ match.threat_type());
+ base::Time positive_expiry;
if (match.has_cache_duration()) {
// Seconds resolution is good enough so we ignore the nanos field.
- result.cache_expire_after =
- clock_->Now() +
- base::TimeDelta::FromSeconds(match.cache_duration().seconds());
+ positive_expiry = clock_->Now() + TimeDelta::FromSeconds(
+ match.cache_duration().seconds());
} else {
- result.cache_expire_after = clock_->Now();
+ positive_expiry = clock_->Now() - base::TimeDelta::FromSeconds(1);
+ }
+ FullHashInfo full_hash_info(match.threat().hash(), list_id,
+ positive_expiry);
+ if (!ParseMetadata(match, &full_hash_info.metadata)) {
+ return false;
}
- // Different threat types will handle the metadata differently.
- if (match.threat_type() == API_ABUSE) {
- if (match.has_platform_type() &&
- match.platform_type() == CHROME_PLATFORM) {
- if (match.has_threat_entry_metadata()) {
- // For API Abuse, store a list of the returned permissions.
- for (const ThreatEntryMetadata::MetadataEntry& m :
- match.threat_entry_metadata().entries()) {
- if (m.key() == "permission") {
- result.metadata.api_permissions.insert(m.value());
- } else {
- RecordParseGetHashResult(UNEXPECTED_METADATA_VALUE_ERROR);
- return false;
- }
- }
- } else {
- RecordParseGetHashResult(NO_METADATA_ERROR);
- return false;
- }
- } else {
- RecordParseGetHashResult(UNEXPECTED_PLATFORM_TYPE_ERROR);
+ full_hash_infos->push_back(full_hash_info);
+ }
+ return true;
+}
+
+bool V4GetHashProtocolManager::ParseMetadata(const ThreatMatch& match,
+ ThreatMetadata* metadata) {
+ // Different threat types will handle the metadata differently.
+ if (match.threat_type() == API_ABUSE) {
+ if (!match.has_platform_type() ||
+ match.platform_type() != CHROME_PLATFORM) {
+ RecordParseGetHashResult(UNEXPECTED_PLATFORM_TYPE_ERROR);
+ return false;
+ }
+
+ if (!match.has_threat_entry_metadata()) {
+ RecordParseGetHashResult(NO_METADATA_ERROR);
+ return false;
+ }
+ // For API Abuse, store a list of the returned permissions.
+ for (const ThreatEntryMetadata::MetadataEntry& m :
+ match.threat_entry_metadata().entries()) {
+ if (m.key() != kPermission) {
+ RecordParseGetHashResult(UNEXPECTED_METADATA_VALUE_ERROR);
return false;
}
- } else if (match.threat_type() == MALWARE_THREAT ||
- match.threat_type() == POTENTIALLY_HARMFUL_APPLICATION) {
- for (const ThreatEntryMetadata::MetadataEntry& m :
- match.threat_entry_metadata().entries()) {
- // TODO: Need to confirm the below key/value pairs with CSD backend.
- if (m.key() == "pha_pattern_type" ||
- m.key() == "malware_pattern_type") {
- if (m.value() == "LANDING") {
- result.metadata.threat_pattern_type =
- ThreatPatternType::MALWARE_LANDING;
- break;
- } else if (m.value() == "DISTRIBUTION") {
- result.metadata.threat_pattern_type =
- ThreatPatternType::MALWARE_DISTRIBUTION;
- break;
- } else {
- RecordParseGetHashResult(UNEXPECTED_METADATA_VALUE_ERROR);
- return false;
- }
+ metadata->api_permissions.insert(m.value());
+ }
+ } else if (match.threat_type() == MALWARE_THREAT ||
+ match.threat_type() == POTENTIALLY_HARMFUL_APPLICATION) {
+ for (const ThreatEntryMetadata::MetadataEntry& m :
+ match.threat_entry_metadata().entries()) {
+ // TODO: Need to confirm the below key/value pairs with CSD backend.
+ if (m.key() == kPhaPatternType || m.key() == kMalwarePatternType) {
+ if (m.value() == kLanding) {
+ metadata->threat_pattern_type = ThreatPatternType::MALWARE_LANDING;
+ break;
+ } else if (m.value() == kDistribution) {
+ metadata->threat_pattern_type =
+ ThreatPatternType::MALWARE_DISTRIBUTION;
+ break;
+ } else {
+ RecordParseGetHashResult(UNEXPECTED_METADATA_VALUE_ERROR);
+ return false;
}
}
- } else if (match.threat_type() == SOCIAL_ENGINEERING_PUBLIC) {
- for (const ThreatEntryMetadata::MetadataEntry& m :
- match.threat_entry_metadata().entries()) {
- if (m.key() == "se_pattern_type") {
- if (m.value() == "SOCIAL_ENGINEERING_ADS") {
- result.metadata.threat_pattern_type =
- ThreatPatternType::SOCIAL_ENGINEERING_ADS;
- break;
- } else if (m.value() == "SOCIAL_ENGINEERING_LANDING") {
- result.metadata.threat_pattern_type =
- ThreatPatternType::SOCIAL_ENGINEERING_LANDING;
- break;
- } else if (m.value() == "PHISHING") {
- result.metadata.threat_pattern_type = ThreatPatternType::PHISHING;
- break;
- } else {
- RecordParseGetHashResult(UNEXPECTED_METADATA_VALUE_ERROR);
- return false;
- }
+ }
+ } else if (match.threat_type() == SOCIAL_ENGINEERING_PUBLIC) {
+ for (const ThreatEntryMetadata::MetadataEntry& m :
+ match.threat_entry_metadata().entries()) {
+ if (m.key() == kSePatternType) {
+ if (m.value() == kSocialEngineeringAds) {
+ metadata->threat_pattern_type =
+ ThreatPatternType::SOCIAL_ENGINEERING_ADS;
+ break;
+ } else if (m.value() == kSocialEngineeringLanding) {
+ metadata->threat_pattern_type =
+ ThreatPatternType::SOCIAL_ENGINEERING_LANDING;
+ break;
+ } else if (m.value() == kPhishing) {
+ metadata->threat_pattern_type = ThreatPatternType::PHISHING;
+ break;
+ } else {
+ RecordParseGetHashResult(UNEXPECTED_METADATA_VALUE_ERROR);
+ return false;
}
}
- } else {
- RecordParseGetHashResult(UNEXPECTED_THREAT_TYPE_ERROR);
- return false;
}
-
- full_hashes->push_back(result);
+ } else {
+ RecordParseGetHashResult(UNEXPECTED_THREAT_TYPE_ERROR);
+ return false;
}
+
return true;
}
-void V4GetHashProtocolManager::GetFullHashes(
- const std::vector<SBPrefix>& prefixes,
- const std::vector<PlatformType>& platforms,
- ThreatType threat_type,
- FullHashCallback callback) {
- DCHECK(CalledOnValidThread());
- // We need to wait the minimum waiting duration, and if we are in backoff,
- // we need to check if we're past the next allowed time. If we are, we can
- // proceed with the request. If not, we are required to return empty results
- // (i.e. treat the page as safe).
- if (clock_->Now() <= next_gethash_time_) {
- if (gethash_error_count_) {
- RecordGetHashResult(V4OperationResult::BACKOFF_ERROR);
- } else {
- RecordGetHashResult(V4OperationResult::MIN_WAIT_DURATION_ERROR);
- }
- std::vector<SBFullHashResult> full_hashes;
- callback.Run(full_hashes, base::Time());
+void V4GetHashProtocolManager::ResetGetHashErrors() {
+ gethash_error_count_ = 0;
+ gethash_back_off_mult_ = 1;
+}
+
+void V4GetHashProtocolManager::SetClockForTests(
+ std::unique_ptr<base::Clock> clock) {
+ clock_ = std::move(clock);
+}
+
+void V4GetHashProtocolManager::UpdateCache(
+ const std::vector<HashPrefix>& prefixes_requested,
+ const std::vector<FullHashInfo>& full_hash_infos,
+ const Time& negative_cache_expire) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // If negative_cache_expire is null, don't cache the results since it's not
+ // clear till what time they should be considered valid.
+ if (negative_cache_expire.is_null()) {
return;
}
- std::string req_base64 = GetHashRequest(prefixes, platforms, threat_type);
- GURL gethash_url;
- net::HttpRequestHeaders headers;
- GetHashUrlAndHeaders(req_base64, &gethash_url, &headers);
-
- net::URLFetcher* fetcher =
- net::URLFetcher::Create(url_fetcher_id_++, gethash_url,
- net::URLFetcher::GET, this)
- .release();
- fetcher->SetExtraRequestHeaders(headers.ToString());
- hash_requests_[fetcher] = callback;
+ for (const HashPrefix& prefix : prefixes_requested) {
+ // Create or reset the cached result for this prefix.
+ CachedHashPrefixInfo& chpi = full_hash_cache_[prefix];
+ chpi.full_hash_infos.clear();
+ chpi.negative_expiry = negative_cache_expire;
- fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE);
- fetcher->SetRequestContext(request_context_getter_.get());
- fetcher->Start();
+ for (const FullHashInfo& full_hash_info : full_hash_infos) {
+ if (V4ProtocolManagerUtil::FullHashMatchesHashPrefix(
+ full_hash_info.full_hash, prefix)) {
+ chpi.full_hash_infos.push_back(full_hash_info);
+ }
+ }
+ }
}
-void V4GetHashProtocolManager::GetFullHashesWithApis(
- const std::vector<SBPrefix>& prefixes,
- FullHashCallback callback) {
- std::vector<PlatformType> platform = {CHROME_PLATFORM};
- GetFullHashes(prefixes, platform, API_ABUSE, callback);
-}
+void V4GetHashProtocolManager::MergeResults(
+ const FullHashToStoreAndHashPrefixesMap&
+ full_hash_to_store_and_hash_prefixes,
+ const std::vector<FullHashInfo>& full_hash_infos,
+ std::vector<FullHashInfo>* merged_full_hash_infos) {
+ bool get_hash_hit = false;
+ for (const FullHashInfo& fhi : full_hash_infos) {
+ auto it = full_hash_to_store_and_hash_prefixes.find(fhi.full_hash);
+ if (full_hash_to_store_and_hash_prefixes.end() != it) {
+ for (const StoreAndHashPrefix& sahp : it->second) {
+ if (fhi.list_id == sahp.list_id) {
+ merged_full_hash_infos->push_back(fhi);
+ get_hash_hit = true;
+ break;
+ }
+ }
+ }
+ }
-void V4GetHashProtocolManager::SetClockForTests(
- std::unique_ptr<base::Clock> clock) {
- clock_ = std::move(clock);
+ if (get_hash_hit) {
+ RecordV4GetHashCheckResult(GET_HASH_CHECK_HIT);
+ } else if (full_hash_infos.empty()) {
+ RecordV4GetHashCheckResult(GET_HASH_CHECK_EMPTY);
+ } else {
+ RecordV4GetHashCheckResult(GET_HASH_CHECK_MISS);
+ }
}
// net::URLFetcherDelegate implementation ----------------------------------
@@ -353,29 +690,25 @@ void V4GetHashProtocolManager::SetClockForTests(
void V4GetHashProtocolManager::OnURLFetchComplete(
const net::URLFetcher* source) {
DCHECK(CalledOnValidThread());
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
- HashRequests::iterator it = hash_requests_.find(source);
- DCHECK(it != hash_requests_.end()) << "Request not found";
-
- // FindFullHashes response.
- // Reset the scoped pointer so the fetcher gets destroyed properly.
- std::unique_ptr<const net::URLFetcher> fetcher(it->first);
+ PendingHashRequests::iterator it = pending_hash_requests_.find(source);
+ DCHECK(it != pending_hash_requests_.end()) << "Request not found";
int response_code = source->GetResponseCode();
net::URLRequestStatus status = source->GetStatus();
V4ProtocolManagerUtil::RecordHttpResponseOrErrorCode(
kUmaV4HashResponseMetricName, status, response_code);
- const FullHashCallback& callback = it->second;
- std::vector<SBFullHashResult> full_hashes;
- base::Time negative_cache_expire;
+ std::vector<FullHashInfo> full_hash_infos;
+ Time negative_cache_expire;
if (status.is_success() && response_code == net::HTTP_OK) {
RecordGetHashResult(V4OperationResult::STATUS_200);
ResetGetHashErrors();
std::string data;
source->GetResponseAsString(&data);
- if (!ParseHashResponse(data, &full_hashes, &negative_cache_expire)) {
- full_hashes.clear();
+ if (!ParseHashResponse(data, &full_hash_infos, &negative_cache_expire)) {
+ full_hash_infos.clear();
RecordGetHashResult(V4OperationResult::PARSE_ERROR);
}
} else {
@@ -392,27 +725,24 @@ void V4GetHashProtocolManager::OnURLFetchComplete(
}
}
- // Invoke the callback with full_hashes, even if there was a parse error or
- // an error response code (in which case full_hashes will be empty). The
- // caller can't be blocked indefinitely.
- callback.Run(full_hashes, negative_cache_expire);
+ const std::unique_ptr<FullHashCallbackInfo>& fhci = it->second;
+ UpdateCache(fhci->prefixes_requested, full_hash_infos, negative_cache_expire);
+ MergeResults(fhci->full_hash_to_store_and_hash_prefixes, full_hash_infos,
+ &fhci->cached_full_hash_infos);
- hash_requests_.erase(it);
-}
+ fhci->callback.Run(fhci->cached_full_hash_infos);
-void V4GetHashProtocolManager::HandleGetHashError(const Time& now) {
- DCHECK(CalledOnValidThread());
- base::TimeDelta next = V4ProtocolManagerUtil::GetNextBackOffInterval(
- &gethash_error_count_, &gethash_back_off_mult_);
- next_gethash_time_ = now + next;
+ pending_hash_requests_.erase(it);
}
-void V4GetHashProtocolManager::GetHashUrlAndHeaders(
- const std::string& req_base64,
- GURL* gurl,
- net::HttpRequestHeaders* headers) const {
- V4ProtocolManagerUtil::GetRequestUrlAndHeaders(req_base64, "fullHashes:find",
- config_, gurl, headers);
+#ifndef DEBUG
+std::ostream& operator<<(std::ostream& os, const FullHashInfo& fhi) {
+ os << "{full_hash: " << fhi.full_hash << "; list_id: " << fhi.list_id
+ << "; positive_expiry: " << fhi.positive_expiry
+ << "; metadata.api_permissions.size(): "
+ << fhi.metadata.api_permissions.size() << "}";
+ return os;
}
+#endif
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.h b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.h
index c80f2da773f..720e09684cb 100644
--- a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.h
+++ b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager.h
@@ -14,6 +14,7 @@
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include "base/gtest_prod_util.h"
@@ -36,109 +37,257 @@ class URLRequestContextGetter;
namespace safe_browsing {
+// The matching hash prefixes and corresponding stores, for each full hash
+// generated for a given URL.
+typedef base::hash_map<FullHash, StoreAndHashPrefixes>
+ FullHashToStoreAndHashPrefixesMap;
+
+// ----------------------------------------------------------------
+
+// All information about a particular full hash i.e. negative TTL, store for
+// which it is valid, and metadata associated with that store.
+struct FullHashInfo {
+ public:
+ FullHash full_hash;
+
+ // The list for which this full hash is applicable.
+ ListIdentifier list_id;
+
+ // The expiration time of the full hash for a particular store.
+ base::Time positive_expiry;
+
+ // Any metadata for this full hash for a particular store.
+ ThreatMetadata metadata;
+
+ FullHashInfo(const FullHash& full_hash,
+ const ListIdentifier& list_id,
+ const base::Time& positive_expiry);
+ FullHashInfo(const FullHashInfo& other);
+ ~FullHashInfo();
+
+ bool operator==(const FullHashInfo& other) const;
+ bool operator!=(const FullHashInfo& other) const;
+
+ private:
+ FullHashInfo();
+};
+
+// Caches individual response from GETHASH response.
+struct CachedHashPrefixInfo {
+ // The negative TTL for the hash prefix that leads to this
+ // CachedHashPrefixInfo. The client should not send any more requests for that
+ // hash prefix until this time.
+ base::Time negative_expiry;
+
+ // The list of all full hashes (and related info) that start with a
+ // particular hash prefix and are known to be unsafe.
+ std::vector<FullHashInfo> full_hash_infos;
+
+ CachedHashPrefixInfo();
+ CachedHashPrefixInfo(const CachedHashPrefixInfo& other);
+ ~CachedHashPrefixInfo();
+};
+
+// Cached full hashes received from the server for the corresponding hash
+// prefixes.
+typedef base::hash_map<HashPrefix, CachedHashPrefixInfo> FullHashCache;
+
+// FullHashCallback is invoked when GetFullHashes completes. The parameter is
+// the vector of full hash results. If empty, indicates that there were no
+// matches, and that the resource is safe.
+typedef base::Callback<void(const std::vector<FullHashInfo>&)> FullHashCallback;
+
+// Information needed to update the cache and call the callback to post the
+// results.
+struct FullHashCallbackInfo {
+ FullHashCallbackInfo();
+ FullHashCallbackInfo(const std::vector<FullHashInfo>& cached_full_hash_infos,
+ const std::vector<HashPrefix>& prefixes_requested,
+ std::unique_ptr<net::URLFetcher> fetcher,
+ const FullHashToStoreAndHashPrefixesMap&
+ full_hash_to_store_and_hash_prefixes,
+ const FullHashCallback& callback);
+ ~FullHashCallbackInfo();
+
+ // The FullHashInfo objects retrieved from cache. These are merged with the
+ // results received from the server before invoking the callback.
+ std::vector<FullHashInfo> cached_full_hash_infos;
+
+ // The callback method to call after collecting the full hashes for given
+ // hash prefixes.
+ FullHashCallback callback;
+
+ // The fetcher that will return the response from the server. This is stored
+ // here as a unique pointer to be able to reason about its lifetime easily.
+ std::unique_ptr<net::URLFetcher> fetcher;
+
+ // The generated full hashes and the corresponding prefixes and the stores in
+ // which to look for a full hash match.
+ FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
+
+ // The prefixes that were requested from the server.
+ std::vector<HashPrefix> prefixes_requested;
+};
+
+// ----------------------------------------------------------------
+
class V4GetHashProtocolManagerFactory;
class V4GetHashProtocolManager : public net::URLFetcherDelegate,
public base::NonThreadSafe {
public:
- // FullHashCallback is invoked when GetFullHashes completes.
+ // Invoked when GetFullHashesWithApis completes.
// Parameters:
- // - The vector of full hash results. If empty, indicates that there
- // were no matches, and that the resource is safe.
- // - The negative cache expire time of the result. This value may be
- // uninitialized, and the results should not be cached in this case.
- typedef base::Callback<void(const std::vector<SBFullHashResult>&,
- const base::Time&)>
- FullHashCallback;
+ // - The API threat metadata for the given URL.
+ typedef base::Callback<void(const ThreatMetadata& md)>
+ ThreatMetadataForApiCallback;
~V4GetHashProtocolManager() override;
+ // Create an instance of the safe browsing v4 protocol manager.
+ static std::unique_ptr<V4GetHashProtocolManager> Create(
+ net::URLRequestContextGetter* request_context_getter,
+ const StoresToCheck& stores_to_check,
+ const V4ProtocolConfig& config);
+
// Makes the passed |factory| the factory used to instantiate
// a V4GetHashProtocolManager. Useful for tests.
static void RegisterFactory(
std::unique_ptr<V4GetHashProtocolManagerFactory> factory);
- // Create an instance of the safe browsing v4 protocol manager.
- static V4GetHashProtocolManager* Create(
- net::URLRequestContextGetter* request_context_getter,
- const V4ProtocolConfig& config);
-
- // net::URLFetcherDelegate interface.
- void OnURLFetchComplete(const net::URLFetcher* source) override;
+ // Empties the cache.
+ void ClearCache();
// Retrieve the full hash for a set of prefixes, and invoke the callback
// argument when the results are retrieved. The callback may be invoked
// synchronously.
- virtual void GetFullHashes(const std::vector<SBPrefix>& prefixes,
- const std::vector<PlatformType>& platforms,
- ThreatType threat_type,
+ virtual void GetFullHashes(const FullHashToStoreAndHashPrefixesMap&
+ full_hash_to_matching_hash_prefixes,
FullHashCallback callback);
- // Retrieve the full hash and API metadata for a set of prefixes, and invoke
+ // Retrieve the full hash and API metadata for the origin of |url|, and invoke
// the callback argument when the results are retrieved. The callback may be
// invoked synchronously.
- virtual void GetFullHashesWithApis(const std::vector<SBPrefix>& prefixes,
- FullHashCallback callback);
+ // GetFullHashesWithApis is a special case of GetFullHashes. It is here
+ // primarily for legacy reasons: so that DatabaseManager, which speaks PVer3,
+ // and V4LocalDatabaseManager, which speaks PVer4, can both use this class to
+ // perform API lookups. Once PVer4 migration is complete, DatabaseManager
+ // should be deleted and then this method can be moved to the
+ // V4LocalDatabaseManager class.
+ // TODO(vakh): Move this method to V4LocalDatabaseManager after launching
+ // PVer4 in Chromium.
+ virtual void GetFullHashesWithApis(const GURL& url,
+ ThreatMetadataForApiCallback api_callback);
- // Overrides the clock used to check the time.
- void SetClockForTests(std::unique_ptr<base::Clock> clock);
+ // net::URLFetcherDelegate interface.
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
protected:
- // Constructs a V4GetHashProtocolManager that issues
- // network requests using |request_context_getter|.
+ // Constructs a V4GetHashProtocolManager that issues network requests using
+ // |request_context_getter|.
V4GetHashProtocolManager(net::URLRequestContextGetter* request_context_getter,
+ const StoresToCheck& stores_to_check,
const V4ProtocolConfig& config);
private:
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest,
- TestGetHashRequest);
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest,
- TestParseHashResponse);
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest,
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest, TestGetHashRequest);
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest, TestParseHashResponse);
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
TestParseHashResponseWrongThreatEntryType);
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest,
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
TestParseHashThreatPatternType);
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest,
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
TestParseHashResponseNonPermissionMetadata);
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest,
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
TestParseHashResponseInconsistentThreatTypes);
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest,
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
TestGetHashErrorHandlingOK);
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest,
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
+ TestResultsNotCachedForNegativeCacheDuration);
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
TestGetHashErrorHandlingNetwork);
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest,
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest,
TestGetHashErrorHandlingResponseCode);
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest, GetCachedResults);
+ FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest, TestUpdatesAreMerged);
+ friend class V4GetHashProtocolManagerTest;
friend class V4GetHashProtocolManagerFactoryImpl;
+ FullHashCache* full_hash_cache_for_tests() { return &full_hash_cache_; }
+
+ // Looks up the cached results for full hashes in
+ // |full_hash_to_store_and_hash_prefixes|. Fills |prefixes_to_request| with
+ // the prefixes that need to be requested. Fills |cached_full_hash_infos|
+ // with the cached results.
+ // Note: It is valid for both |prefixes_to_request| and
+ // |cached_full_hash_infos| to be empty after this function finishes.
+ void GetFullHashCachedResults(
+ const FullHashToStoreAndHashPrefixesMap&
+ full_hash_to_store_and_hash_prefixes,
+ const base::Time& now,
+ std::vector<HashPrefix>* prefixes_to_request,
+ std::vector<FullHashInfo>* cached_full_hash_infos) const;
+
+ // Fills a FindFullHashesRequest protocol buffer for a request.
+ // Returns the serialized and base 64 encoded request as a string.
+ std::string GetHashRequest(
+ const std::vector<HashPrefix>& prefixes_to_request);
+
void GetHashUrlAndHeaders(const std::string& request_base64,
GURL* gurl,
net::HttpRequestHeaders* headers) const;
- // Fills a FindFullHashesRequest protocol buffer for a request.
- // Returns the serialized and base 64 encoded request as a string.
- std::string GetHashRequest(const std::vector<SBPrefix>& prefixes,
- const std::vector<PlatformType>& platforms,
- ThreatType threat_type);
+ // Updates internal state for each GetHash response error, assuming that
+ // the current time is |now|.
+ void HandleGetHashError(const base::Time& now);
+
+ // Merges the results from the cache and the results from the server. The
+ // response from the server may include information for full hashes from
+ // stores other than those required by this client so it filters out those
+ // results that the client did not ask for.
+ void MergeResults(const FullHashToStoreAndHashPrefixesMap&
+ full_hash_to_store_and_hash_prefixes,
+ const std::vector<FullHashInfo>& full_hash_infos,
+ std::vector<FullHashInfo>* merged_full_hash_infos);
+
+ // Calls |api_callback| with an object of ThreatMetadata that contains
+ // permission API metadata for full hashes in those |full_hash_infos| that
+ // have a full hash in |full_hashes|.
+ void OnFullHashForApi(const ThreatMetadataForApiCallback& api_callback,
+ const std::unordered_set<FullHash>& full_hashes,
+ const std::vector<FullHashInfo>& full_hash_infos);
// Parses a FindFullHashesResponse protocol buffer and fills the results in
- // |full_hashes| and |negative_cache_expire|. |data| is a serialized
- // FindFullHashes protocol buffer. |negative_cache_expire| is the cache expiry
- // time of the response for entities that did not match the threat list.
- // Returns true if parsing is successful, false otherwise.
- bool ParseHashResponse(const std::string& data_base64,
- std::vector<SBFullHashResult>* full_hashes,
+ // |full_hash_infos| and |negative_cache_expire|. |response_data| is a
+ // serialized FindFullHashes protocol buffer. |negative_cache_expire| is the
+ // cache expiry time of the hash prefixes that were requested. Returns true if
+ // parsing is successful; false otherwise.
+ bool ParseHashResponse(const std::string& response_data,
+ std::vector<FullHashInfo>* full_hash_infos,
base::Time* negative_cache_expire);
+ // Parses the store specific |metadata| information from |match|. Returns
+ // true if the metadata information was parsed correctly and was consistent
+ // with what's expected from that corresponding store; false otherwise.
+ bool ParseMetadata(const ThreatMatch& match, ThreatMetadata* metadata);
+
// Resets the gethash error counter and multiplier.
void ResetGetHashErrors();
- // Updates internal state for each GetHash response error, assuming that
- // the current time is |now|.
- void HandleGetHashError(const base::Time& now);
+ // Overrides the clock used to check the time.
+ void SetClockForTests(std::unique_ptr<base::Clock> clock);
+
+ // Updates the state of the full hash cache upon receiving a valid response
+ // from the server.
+ void UpdateCache(const std::vector<HashPrefix>& prefixes_requested,
+ const std::vector<FullHashInfo>& full_hash_infos,
+ const base::Time& negative_cache_expire);
private:
// Map of GetHash requests to parameters which created it.
- typedef base::hash_map<const net::URLFetcher*, FullHashCallback> HashRequests;
+ using PendingHashRequests =
+ base::hash_map<const net::URLFetcher*,
+ std::unique_ptr<FullHashCallbackInfo>>;
// The factory that controls the creation of V4GetHashProtocolManager.
// This is used by tests.
@@ -156,7 +305,7 @@ class V4GetHashProtocolManager : public net::URLFetcherDelegate,
// Multiplier for the backoff error after the second.
size_t gethash_back_off_mult_;
- HashRequests hash_requests_;
+ PendingHashRequests pending_hash_requests_;
// For v4, the next gethash time is set to the backoff time is the last
// response was an error, or the minimum wait time if the last response was
@@ -175,6 +324,16 @@ class V4GetHashProtocolManager : public net::URLFetcherDelegate,
// The clock used to vend times.
std::unique_ptr<base::Clock> clock_;
+ // A cache of full hash results.
+ FullHashCache full_hash_cache_;
+
+ // The following sets represent the combination of lists that we would always
+ // request from the server, irrespective of which list we found the hash
+ // prefix match in.
+ std::unordered_set<PlatformType> platform_types_;
+ std::unordered_set<ThreatEntryType> threat_entry_types_;
+ std::unordered_set<ThreatType> threat_types_;
+
DISALLOW_COPY_AND_ASSIGN(V4GetHashProtocolManager);
};
@@ -183,14 +342,19 @@ class V4GetHashProtocolManagerFactory {
public:
V4GetHashProtocolManagerFactory() {}
virtual ~V4GetHashProtocolManagerFactory() {}
- virtual V4GetHashProtocolManager* CreateProtocolManager(
+ virtual std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager(
net::URLRequestContextGetter* request_context_getter,
+ const StoresToCheck& stores_to_check,
const V4ProtocolConfig& config) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(V4GetHashProtocolManagerFactory);
};
+#ifndef NDEBUG
+std::ostream& operator<<(std::ostream& os, const FullHashInfo& id);
+#endif
+
} // namespace safe_browsing
#endif // COMPONENTS_SAFE_BROWSING_DB_V4_GET_HASH_PROTOCOL_MANAGER_H_
diff --git a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
index edf130ac9dc..fa37e0622f3 100644
--- a/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
+++ b/chromium/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
@@ -9,17 +9,19 @@
#include "base/base64.h"
#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/simple_test_clock.h"
#include "base/time/time.h"
#include "components/safe_browsing_db/safebrowsing.pb.h"
#include "components/safe_browsing_db/testing_util.h"
#include "components/safe_browsing_db/util.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/url_request/test_url_fetcher_factory.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
using base::Time;
using base::TimeDelta;
@@ -34,37 +36,76 @@ const char kKeyParam[] = "test_key_param";
namespace safe_browsing {
-class SafeBrowsingV4GetHashProtocolManagerTest : public testing::Test {
- protected:
+namespace {
+
+struct KeyValue {
+ std::string key;
+ std::string value;
+
+ explicit KeyValue(const std::string key, const std::string value)
+ : key(key), value(value){};
+ explicit KeyValue(const KeyValue& other) = default;
+
+ private:
+ KeyValue();
+};
+
+struct ResponseInfo {
+ FullHash full_hash;
+ ListIdentifier list_id;
+ std::vector<KeyValue> key_values;
+
+ explicit ResponseInfo(FullHash full_hash, ListIdentifier list_id)
+ : full_hash(full_hash), list_id(list_id){};
+ explicit ResponseInfo(const ResponseInfo& other)
+ : full_hash(other.full_hash),
+ list_id(other.list_id),
+ key_values(other.key_values){};
+
+ private:
+ ResponseInfo();
+};
+
+} // namespace
+
+class V4GetHashProtocolManagerTest : public PlatformTest {
+ public:
+ void SetUp() override {
+ PlatformTest::SetUp();
+ callback_called_ = false;
+ }
+
std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager() {
V4ProtocolConfig config;
config.client_name = kClient;
config.version = kAppVer;
config.key_param = kKeyParam;
- return std::unique_ptr<V4GetHashProtocolManager>(
- V4GetHashProtocolManager::Create(NULL, config));
+ StoresToCheck stores_to_check({GetUrlMalwareId(), GetChromeUrlApiId()});
+ return V4GetHashProtocolManager::Create(NULL, stores_to_check, config);
}
- std::string GetStockV4HashResponse() {
- FindFullHashesResponse res;
- res.mutable_negative_cache_duration()->set_seconds(600);
- ThreatMatch* m = res.add_matches();
- m->set_threat_type(API_ABUSE);
- m->set_platform_type(CHROME_PLATFORM);
- m->set_threat_entry_type(URL);
- m->mutable_cache_duration()->set_seconds(300);
- m->mutable_threat()->set_hash(
- SBFullHashToString(SBFullHashForString("Everything's shiny, Cap'n.")));
- ThreatEntryMetadata::MetadataEntry* e =
- m->mutable_threat_entry_metadata()->add_entries();
- e->set_key("permission");
- e->set_value("NOTIFICATIONS");
+ static void SetupFetcherToReturnOKResponse(
+ const net::TestURLFetcherFactory& factory,
+ const std::vector<ResponseInfo>& infos) {
+ net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
+ DCHECK(fetcher);
+ fetcher->set_status(net::URLRequestStatus());
+ fetcher->set_response_code(200);
+ fetcher->SetResponseString(GetV4HashResponse(infos));
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ }
- // Serialize.
- std::string res_data;
- res.SerializeToString(&res_data);
+ static std::vector<ResponseInfo> GetStockV4HashResponseInfos() {
+ ResponseInfo info(FullHash("Everything's shiny, Cap'n."),
+ GetChromeUrlApiId());
+ info.key_values.emplace_back("permission", "NOTIFICATIONS");
+ std::vector<ResponseInfo> infos;
+ infos.push_back(info);
+ return infos;
+ }
- return res_data;
+ static std::string GetStockV4HashResponse() {
+ return GetV4HashResponse(GetStockV4HashResponseInfos());
}
void SetTestClock(base::Time now, V4GetHashProtocolManager* pm) {
@@ -72,37 +113,69 @@ class SafeBrowsingV4GetHashProtocolManagerTest : public testing::Test {
clock->SetNow(now);
pm->SetClockForTests(base::WrapUnique(clock));
}
-};
-void ValidateGetV4HashResults(
- const std::vector<SBFullHashResult>& expected_full_hashes,
- const base::Time& expected_cache_expire,
- const std::vector<SBFullHashResult>& full_hashes,
- const base::Time& cache_expire) {
- EXPECT_EQ(expected_cache_expire, cache_expire);
- ASSERT_EQ(expected_full_hashes.size(), full_hashes.size());
-
- for (unsigned int i = 0; i < expected_full_hashes.size(); ++i) {
- const SBFullHashResult& expected = expected_full_hashes[i];
- const SBFullHashResult& actual = full_hashes[i];
- EXPECT_TRUE(SBFullHashEqual(expected.hash, actual.hash));
- EXPECT_EQ(expected.metadata, actual.metadata);
- EXPECT_EQ(expected.cache_expire_after, actual.cache_expire_after);
+ void ValidateGetV4ApiResults(const ThreatMetadata& expected_md,
+ const ThreatMetadata& actual_md) {
+ EXPECT_EQ(expected_md, actual_md);
+ callback_called_ = true;
+ }
+
+ void ValidateGetV4HashResults(
+ const std::vector<FullHashInfo>& expected_results,
+ const std::vector<FullHashInfo>& actual_results) {
+ EXPECT_EQ(expected_results.size(), actual_results.size());
+ for (size_t i = 0; i < actual_results.size(); i++) {
+ EXPECT_TRUE(expected_results[i] == actual_results[i]);
+ }
+ callback_called_ = true;
}
-}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
- TestGetHashErrorHandlingNetwork) {
+ bool callback_called() { return callback_called_; }
+
+ private:
+ static std::string GetV4HashResponse(
+ std::vector<ResponseInfo> response_infos) {
+ FindFullHashesResponse res;
+ res.mutable_negative_cache_duration()->set_seconds(600);
+ for (const ResponseInfo& info : response_infos) {
+ ThreatMatch* m = res.add_matches();
+ m->set_platform_type(info.list_id.platform_type());
+ m->set_threat_entry_type(info.list_id.threat_entry_type());
+ m->set_threat_type(info.list_id.threat_type());
+ m->mutable_cache_duration()->set_seconds(300);
+ m->mutable_threat()->set_hash(info.full_hash);
+
+ for (const KeyValue& key_value : info.key_values) {
+ ThreatEntryMetadata::MetadataEntry* e =
+ m->mutable_threat_entry_metadata()->add_entries();
+ e->set_key(key_value.key);
+ e->set_value(key_value.value);
+ }
+ }
+
+ // Serialize.
+ std::string res_data;
+ res.SerializeToString(&res_data);
+
+ return res_data;
+ }
+
+ bool callback_called_;
+ content::TestBrowserThreadBundle thread_bundle_;
+};
+
+TEST_F(V4GetHashProtocolManagerTest, TestGetHashErrorHandlingNetwork) {
net::TestURLFetcherFactory factory;
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
- std::vector<SBPrefix> prefixes;
- std::vector<SBFullHashResult> expected_full_hashes;
- base::Time expected_cache_expire;
-
- pm->GetFullHashesWithApis(
- prefixes, base::Bind(&ValidateGetV4HashResults, expected_full_hashes,
- expected_cache_expire));
+ FullHashToStoreAndHashPrefixesMap matched_locally;
+ matched_locally[FullHash("AHashFull")].emplace_back(GetUrlSocEngId(),
+ HashPrefix("AHash"));
+ std::vector<FullHashInfo> expected_results;
+ pm->GetFullHashes(
+ matched_locally,
+ base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults,
+ base::Unretained(this), expected_results));
net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
DCHECK(fetcher);
@@ -116,20 +189,21 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
// Should have recorded one error, but back off multiplier is unchanged.
EXPECT_EQ(1ul, pm->gethash_error_count_);
EXPECT_EQ(1ul, pm->gethash_back_off_mult_);
+ EXPECT_TRUE(callback_called());
}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
- TestGetHashErrorHandlingResponseCode) {
+TEST_F(V4GetHashProtocolManagerTest, TestGetHashErrorHandlingResponseCode) {
net::TestURLFetcherFactory factory;
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
- std::vector<SBPrefix> prefixes;
- std::vector<SBFullHashResult> expected_full_hashes;
- base::Time expected_cache_expire;
-
- pm->GetFullHashesWithApis(
- prefixes, base::Bind(&ValidateGetV4HashResults, expected_full_hashes,
- expected_cache_expire));
+ FullHashToStoreAndHashPrefixesMap matched_locally;
+ matched_locally[FullHash("AHashFull")].emplace_back(GetUrlSocEngId(),
+ HashPrefix("AHash"));
+ std::vector<FullHashInfo> expected_results;
+ pm->GetFullHashes(
+ matched_locally,
+ base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults,
+ base::Unretained(this), expected_results));
net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
DCHECK(fetcher);
@@ -142,81 +216,108 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
// Should have recorded one error, but back off multiplier is unchanged.
EXPECT_EQ(1ul, pm->gethash_error_count_);
EXPECT_EQ(1ul, pm->gethash_back_off_mult_);
+ EXPECT_TRUE(callback_called());
}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashErrorHandlingOK) {
+TEST_F(V4GetHashProtocolManagerTest, TestGetHashErrorHandlingOK) {
net::TestURLFetcherFactory factory;
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
base::Time now = base::Time::UnixEpoch();
SetTestClock(now, pm.get());
- std::vector<SBPrefix> prefixes;
- std::vector<SBFullHashResult> expected_full_hashes;
- SBFullHashResult hash_result;
- hash_result.hash = SBFullHashForString("Everything's shiny, Cap'n.");
- hash_result.metadata.api_permissions.insert("NOTIFICATIONS");
- hash_result.cache_expire_after = now + base::TimeDelta::FromSeconds(300);
- expected_full_hashes.push_back(hash_result);
- base::Time expected_cache_expire = now + base::TimeDelta::FromSeconds(600);
+ HashPrefix prefix("Everything");
+ FullHash full_hash("Everything's shiny, Cap'n.");
+ FullHashToStoreAndHashPrefixesMap matched_locally;
+ matched_locally[full_hash].push_back(
+ StoreAndHashPrefix(GetChromeUrlApiId(), prefix));
+ std::vector<FullHashInfo> expected_results;
+ FullHashInfo fhi(full_hash, GetChromeUrlApiId(),
+ now + base::TimeDelta::FromSeconds(300));
+ fhi.metadata.api_permissions.insert("NOTIFICATIONS");
+ expected_results.push_back(fhi);
- pm->GetFullHashesWithApis(
- prefixes, base::Bind(&ValidateGetV4HashResults, expected_full_hashes,
- expected_cache_expire));
+ pm->GetFullHashes(
+ matched_locally,
+ base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults,
+ base::Unretained(this), expected_results));
- net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
- DCHECK(fetcher);
- fetcher->set_status(net::URLRequestStatus());
- fetcher->set_response_code(200);
- fetcher->SetResponseString(GetStockV4HashResponse());
- fetcher->delegate()->OnURLFetchComplete(fetcher);
+ SetupFetcherToReturnOKResponse(factory, GetStockV4HashResponseInfos());
// No error, back off multiplier is unchanged.
EXPECT_EQ(0ul, pm->gethash_error_count_);
EXPECT_EQ(1ul, pm->gethash_back_off_mult_);
+
+ // Verify the state of the cache.
+ const FullHashCache* cache = pm->full_hash_cache_for_tests();
+ // Check the cache.
+ ASSERT_EQ(1u, cache->size());
+ EXPECT_EQ(1u, cache->count(prefix));
+ const CachedHashPrefixInfo& cached_result = cache->at(prefix);
+ EXPECT_EQ(cached_result.negative_expiry,
+ now + base::TimeDelta::FromSeconds(600));
+ ASSERT_EQ(1u, cached_result.full_hash_infos.size());
+ EXPECT_EQ(FullHash("Everything's shiny, Cap'n."),
+ cached_result.full_hash_infos[0].full_hash);
+ EXPECT_TRUE(callback_called());
}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashRequest) {
+TEST_F(V4GetHashProtocolManagerTest,
+ TestResultsNotCachedForNegativeCacheDuration) {
+ net::TestURLFetcherFactory factory;
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+ HashPrefix prefix("Everything");
+ std::vector<HashPrefix> prefixes_requested({prefix});
+ base::Time negative_cache_expire;
+ FullHash full_hash("Everything's shiny, Cap'n.");
+ std::vector<FullHashInfo> fhis;
+ fhis.emplace_back(full_hash, GetChromeUrlApiId(), base::Time::UnixEpoch());
+
+ pm->UpdateCache(prefixes_requested, fhis, negative_cache_expire);
+
+ // Verify the state of the cache.
+ const FullHashCache* cache = pm->full_hash_cache_for_tests();
+ // Check the cache.
+ EXPECT_EQ(0u, cache->size());
+}
+
+TEST_F(V4GetHashProtocolManagerTest, TestGetHashRequest) {
FindFullHashesRequest req;
ThreatInfo* info = req.mutable_threat_info();
- info->add_threat_types(API_ABUSE);
+ info->add_platform_types(GetCurrentPlatformType());
info->add_platform_types(CHROME_PLATFORM);
+
info->add_threat_entry_types(URL);
- SBPrefix one = 1u;
- SBPrefix two = 2u;
- SBPrefix three = 3u;
- std::string hash(reinterpret_cast<const char*>(&one), sizeof(SBPrefix));
- info->add_threat_entries()->set_hash(hash);
- hash.clear();
- hash.append(reinterpret_cast<const char*>(&two), sizeof(SBPrefix));
- info->add_threat_entries()->set_hash(hash);
- hash.clear();
- hash.append(reinterpret_cast<const char*>(&three), sizeof(SBPrefix));
- info->add_threat_entries()->set_hash(hash);
+ info->add_threat_types(MALWARE_THREAT);
+ info->add_threat_types(API_ABUSE);
+
+ HashPrefix one = "hashone";
+ HashPrefix two = "hashtwo";
+ info->add_threat_entries()->set_hash(one);
+ info->add_threat_entries()->set_hash(two);
+
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+ req.mutable_client()->set_client_id(pm->config_.client_name);
+ req.mutable_client()->set_client_version(pm->config_.version);
// Serialize and Base64 encode.
std::string req_data, req_base64;
req.SerializeToString(&req_data);
base::Base64Encode(req_data, &req_base64);
- std::vector<PlatformType> platform;
- platform.push_back(CHROME_PLATFORM);
- std::vector<SBPrefix> prefixes;
- prefixes.push_back(one);
- prefixes.push_back(two);
- prefixes.push_back(three);
- EXPECT_EQ(req_base64, pm->GetHashRequest(prefixes, platform, API_ABUSE));
+ std::vector<HashPrefix> prefixes_to_request = {one, two};
+ EXPECT_EQ(req_base64, pm->GetHashRequest(prefixes_to_request));
}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponse) {
+TEST_F(V4GetHashProtocolManagerTest, TestParseHashResponse) {
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
base::Time now = base::Time::UnixEpoch();
SetTestClock(now, pm.get());
+ FullHash full_hash("Everything's shiny, Cap'n.");
FindFullHashesResponse res;
res.mutable_negative_cache_duration()->set_seconds(600);
res.mutable_minimum_wait_duration()->set_seconds(400);
@@ -225,8 +326,7 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponse) {
m->set_platform_type(CHROME_PLATFORM);
m->set_threat_entry_type(URL);
m->mutable_cache_duration()->set_seconds(300);
- m->mutable_threat()->set_hash(
- SBFullHashToString(SBFullHashForString("Everything's shiny, Cap'n.")));
+ m->mutable_threat()->set_hash(full_hash);
ThreatEntryMetadata::MetadataEntry* e =
m->mutable_threat_entry_metadata()->add_entries();
e->set_key("permission");
@@ -236,24 +336,23 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponse) {
std::string res_data;
res.SerializeToString(&res_data);
- std::vector<SBFullHashResult> full_hashes;
+ std::vector<FullHashInfo> full_hash_infos;
base::Time cache_expire;
- EXPECT_TRUE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire));
+ EXPECT_TRUE(pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire));
EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
- EXPECT_EQ(1ul, full_hashes.size());
- EXPECT_TRUE(SBFullHashEqual(SBFullHashForString("Everything's shiny, Cap'n."),
- full_hashes[0].hash));
- EXPECT_EQ(1ul, full_hashes[0].metadata.api_permissions.size());
- EXPECT_EQ(1ul,
- full_hashes[0].metadata.api_permissions.count("NOTIFICATIONS"));
- EXPECT_EQ(now +
- base::TimeDelta::FromSeconds(300), full_hashes[0].cache_expire_after);
+ ASSERT_EQ(1ul, full_hash_infos.size());
+ const FullHashInfo& fhi = full_hash_infos[0];
+ EXPECT_EQ(full_hash, fhi.full_hash);
+ EXPECT_EQ(GetChromeUrlApiId(), fhi.list_id);
+ EXPECT_EQ(1ul, fhi.metadata.api_permissions.size());
+ EXPECT_EQ(1ul, fhi.metadata.api_permissions.count("NOTIFICATIONS"));
+ EXPECT_EQ(now + base::TimeDelta::FromSeconds(300), fhi.positive_expiry);
EXPECT_EQ(now + base::TimeDelta::FromSeconds(400), pm->next_gethash_time_);
}
// Adds an entry with an ignored ThreatEntryType.
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
+TEST_F(V4GetHashProtocolManagerTest,
TestParseHashResponseWrongThreatEntryType) {
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
@@ -268,96 +367,117 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
std::string res_data;
res.SerializeToString(&res_data);
- std::vector<SBFullHashResult> full_hashes;
+ std::vector<FullHashInfo> full_hash_infos;
base::Time cache_expire;
- EXPECT_FALSE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire));
+ EXPECT_FALSE(
+ pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire));
EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
// There should be no hash results.
- EXPECT_EQ(0ul, full_hashes.size());
+ EXPECT_EQ(0ul, full_hash_infos.size());
}
// Adds entries with a ThreatPatternType metadata.
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
- TestParseHashThreatPatternType) {
+TEST_F(V4GetHashProtocolManagerTest, TestParseHashThreatPatternType) {
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
base::Time now = base::Time::UnixEpoch();
SetTestClock(now, pm.get());
- // Test social engineering pattern type.
- FindFullHashesResponse se_res;
- se_res.mutable_negative_cache_duration()->set_seconds(600);
- ThreatMatch* se = se_res.add_matches();
- se->set_threat_type(SOCIAL_ENGINEERING_PUBLIC);
- se->set_platform_type(CHROME_PLATFORM);
- se->set_threat_entry_type(URL);
- SBFullHash hash_string = SBFullHashForString("Everything's shiny, Cap'n.");
- se->mutable_threat()->set_hash(SBFullHashToString(hash_string));
- ThreatEntryMetadata::MetadataEntry* se_meta =
- se->mutable_threat_entry_metadata()->add_entries();
- se_meta->set_key("se_pattern_type");
- se_meta->set_value("SOCIAL_ENGINEERING_LANDING");
-
- std::string se_data;
- se_res.SerializeToString(&se_data);
-
- std::vector<SBFullHashResult> full_hashes;
- base::Time cache_expire;
- EXPECT_TRUE(pm->ParseHashResponse(se_data, &full_hashes, &cache_expire));
+ {
+ // Test social engineering pattern type.
+ FindFullHashesResponse se_res;
+ se_res.mutable_negative_cache_duration()->set_seconds(600);
+ ThreatMatch* se = se_res.add_matches();
+ se->set_threat_type(SOCIAL_ENGINEERING_PUBLIC);
+ se->set_platform_type(CHROME_PLATFORM);
+ se->set_threat_entry_type(URL);
+ FullHash full_hash("Everything's shiny, Cap'n.");
+ se->mutable_threat()->set_hash(full_hash);
+ ThreatEntryMetadata::MetadataEntry* se_meta =
+ se->mutable_threat_entry_metadata()->add_entries();
+ se_meta->set_key("se_pattern_type");
+ se_meta->set_value("SOCIAL_ENGINEERING_LANDING");
+
+ std::string se_data;
+ se_res.SerializeToString(&se_data);
+
+ std::vector<FullHashInfo> full_hash_infos;
+ base::Time cache_expire;
+ EXPECT_TRUE(
+ pm->ParseHashResponse(se_data, &full_hash_infos, &cache_expire));
+ EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
+
+ ASSERT_EQ(1ul, full_hash_infos.size());
+ const FullHashInfo& fhi = full_hash_infos[0];
+ EXPECT_EQ(full_hash, fhi.full_hash);
+ const ListIdentifier list_id(CHROME_PLATFORM, URL,
+ SOCIAL_ENGINEERING_PUBLIC);
+ EXPECT_EQ(list_id, fhi.list_id);
+ EXPECT_EQ(ThreatPatternType::SOCIAL_ENGINEERING_LANDING,
+ fhi.metadata.threat_pattern_type);
+ }
- EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
- EXPECT_EQ(1ul, full_hashes.size());
- EXPECT_TRUE(SBFullHashEqual(hash_string, full_hashes[0].hash));
- EXPECT_EQ(ThreatPatternType::SOCIAL_ENGINEERING_LANDING,
- full_hashes[0].metadata.threat_pattern_type);
-
- // Test potentially harmful application pattern type.
- FindFullHashesResponse pha_res;
- pha_res.mutable_negative_cache_duration()->set_seconds(600);
- ThreatMatch* pha = pha_res.add_matches();
- pha->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION);
- pha->set_threat_entry_type(URL);
- pha->set_platform_type(CHROME_PLATFORM);
- hash_string = SBFullHashForString("Not to fret.");
- pha->mutable_threat()->set_hash(SBFullHashToString(hash_string));
- ThreatEntryMetadata::MetadataEntry* pha_meta =
- pha->mutable_threat_entry_metadata()->add_entries();
- pha_meta->set_key("pha_pattern_type");
- pha_meta->set_value("LANDING");
-
- std::string pha_data;
- pha_res.SerializeToString(&pha_data);
- full_hashes.clear();
- EXPECT_TRUE(pm->ParseHashResponse(pha_data, &full_hashes, &cache_expire));
- EXPECT_EQ(1ul, full_hashes.size());
- EXPECT_TRUE(SBFullHashEqual(hash_string, full_hashes[0].hash));
- EXPECT_EQ(ThreatPatternType::MALWARE_LANDING,
- full_hashes[0].metadata.threat_pattern_type);
-
- // Test invalid pattern type.
- FindFullHashesResponse invalid_res;
- invalid_res.mutable_negative_cache_duration()->set_seconds(600);
- ThreatMatch* invalid = invalid_res.add_matches();
- invalid->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION);
- invalid->set_threat_entry_type(URL);
- invalid->set_platform_type(CHROME_PLATFORM);
- invalid->mutable_threat()->set_hash(SBFullHashToString(hash_string));
- ThreatEntryMetadata::MetadataEntry* invalid_meta =
- invalid->mutable_threat_entry_metadata()->add_entries();
- invalid_meta->set_key("pha_pattern_type");
- invalid_meta->set_value("INVALIDE_VALUE");
-
- std::string invalid_data;
- invalid_res.SerializeToString(&invalid_data);
- full_hashes.clear();
- EXPECT_FALSE(
- pm->ParseHashResponse(invalid_data, &full_hashes, &cache_expire));
- EXPECT_EQ(0ul, full_hashes.size());
+ {
+ // Test potentially harmful application pattern type.
+ FindFullHashesResponse pha_res;
+ pha_res.mutable_negative_cache_duration()->set_seconds(600);
+ ThreatMatch* pha = pha_res.add_matches();
+ pha->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION);
+ pha->set_threat_entry_type(URL);
+ pha->set_platform_type(CHROME_PLATFORM);
+ FullHash full_hash("Not to fret.");
+ pha->mutable_threat()->set_hash(full_hash);
+ ThreatEntryMetadata::MetadataEntry* pha_meta =
+ pha->mutable_threat_entry_metadata()->add_entries();
+ pha_meta->set_key("pha_pattern_type");
+ pha_meta->set_value("LANDING");
+
+ std::string pha_data;
+ pha_res.SerializeToString(&pha_data);
+ std::vector<FullHashInfo> full_hash_infos;
+ base::Time cache_expire;
+ EXPECT_TRUE(
+ pm->ParseHashResponse(pha_data, &full_hash_infos, &cache_expire));
+ EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
+
+ ASSERT_EQ(1ul, full_hash_infos.size());
+ const FullHashInfo& fhi = full_hash_infos[0];
+ EXPECT_EQ(full_hash, fhi.full_hash);
+ const ListIdentifier list_id(CHROME_PLATFORM, URL,
+ POTENTIALLY_HARMFUL_APPLICATION);
+ EXPECT_EQ(list_id, fhi.list_id);
+ EXPECT_EQ(ThreatPatternType::MALWARE_LANDING,
+ fhi.metadata.threat_pattern_type);
+ }
+
+ {
+ // Test invalid pattern type.
+ FullHash full_hash("Not to fret.");
+ FindFullHashesResponse invalid_res;
+ invalid_res.mutable_negative_cache_duration()->set_seconds(600);
+ ThreatMatch* invalid = invalid_res.add_matches();
+ invalid->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION);
+ invalid->set_threat_entry_type(URL);
+ invalid->set_platform_type(CHROME_PLATFORM);
+ invalid->mutable_threat()->set_hash(full_hash);
+ ThreatEntryMetadata::MetadataEntry* invalid_meta =
+ invalid->mutable_threat_entry_metadata()->add_entries();
+ invalid_meta->set_key("pha_pattern_type");
+ invalid_meta->set_value("INVALIDE_VALUE");
+
+ std::string invalid_data;
+ invalid_res.SerializeToString(&invalid_data);
+ std::vector<FullHashInfo> full_hash_infos;
+ base::Time cache_expire;
+ EXPECT_FALSE(
+ pm->ParseHashResponse(invalid_data, &full_hash_infos, &cache_expire));
+ EXPECT_EQ(0ul, full_hash_infos.size());
+ }
}
// Adds metadata with a key value that is not "permission".
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
+TEST_F(V4GetHashProtocolManagerTest,
TestParseHashResponseNonPermissionMetadata) {
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
@@ -370,8 +490,7 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
m->set_threat_type(API_ABUSE);
m->set_platform_type(CHROME_PLATFORM);
m->set_threat_entry_type(URL);
- m->mutable_threat()->set_hash(
- SBFullHashToString(SBFullHashForString("Not to fret.")));
+ m->mutable_threat()->set_hash(FullHash("Not to fret."));
ThreatEntryMetadata::MetadataEntry* e =
m->mutable_threat_entry_metadata()->add_entries();
e->set_key("notpermission");
@@ -381,15 +500,16 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
std::string res_data;
res.SerializeToString(&res_data);
- std::vector<SBFullHashResult> full_hashes;
+ std::vector<FullHashInfo> full_hash_infos;
base::Time cache_expire;
- EXPECT_FALSE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire));
+ EXPECT_FALSE(
+ pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire));
EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
- EXPECT_EQ(0ul, full_hashes.size());
+ EXPECT_EQ(0ul, full_hash_infos.size());
}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
+TEST_F(V4GetHashProtocolManagerTest,
TestParseHashResponseInconsistentThreatTypes) {
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
@@ -399,22 +519,217 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
m1->set_threat_type(API_ABUSE);
m1->set_platform_type(CHROME_PLATFORM);
m1->set_threat_entry_type(URL);
- m1->mutable_threat()->set_hash(
- SBFullHashToString(SBFullHashForString("Everything's shiny, Cap'n.")));
+ m1->mutable_threat()->set_hash(FullHash("Everything's shiny, Cap'n."));
m1->mutable_threat_entry_metadata()->add_entries();
ThreatMatch* m2 = res.add_matches();
m2->set_threat_type(MALWARE_THREAT);
m2->set_threat_entry_type(URL);
- m2->mutable_threat()->set_hash(
- SBFullHashToString(SBFullHashForString("Not to fret.")));
+ m2->mutable_threat()->set_hash(FullHash("Not to fret."));
// Serialize.
std::string res_data;
res.SerializeToString(&res_data);
- std::vector<SBFullHashResult> full_hashes;
+ std::vector<FullHashInfo> full_hash_infos;
base::Time cache_expire;
- EXPECT_FALSE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire));
+ EXPECT_FALSE(
+ pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire));
+}
+
+// Checks that results are looked up correctly in the cache.
+TEST_F(V4GetHashProtocolManagerTest, GetCachedResults) {
+ base::Time now = base::Time::UnixEpoch();
+ FullHash full_hash("example");
+ HashPrefix prefix("exam");
+ FullHashToStoreAndHashPrefixesMap matched_locally;
+ matched_locally[full_hash].emplace_back(GetUrlMalwareId(), prefix);
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+ FullHashCache* cache = pm->full_hash_cache_for_tests();
+
+ {
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ cache->clear();
+
+ // Test with an empty cache. (Case: 2)
+ pm->GetFullHashCachedResults(matched_locally, now, &prefixes_to_request,
+ &cached_full_hash_infos);
+ EXPECT_TRUE(cache->empty());
+ ASSERT_EQ(1ul, prefixes_to_request.size());
+ EXPECT_EQ(prefix, prefixes_to_request[0]);
+ EXPECT_TRUE(cached_full_hash_infos.empty());
+ }
+
+ {
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ cache->clear();
+
+ // Prefix has a cache entry but full hash is not there. (Case: 1-b-i)
+ CachedHashPrefixInfo* entry = &(*cache)[prefix];
+ entry->negative_expiry = now + base::TimeDelta::FromMinutes(5);
+ pm->GetFullHashCachedResults(matched_locally, now, &prefixes_to_request,
+ &cached_full_hash_infos);
+ EXPECT_TRUE(prefixes_to_request.empty());
+ EXPECT_TRUE(cached_full_hash_infos.empty());
+ }
+
+ {
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ cache->clear();
+
+ // Expired negative cache entry. (Case: 1-b-ii)
+ CachedHashPrefixInfo* entry = &(*cache)[prefix];
+ entry->negative_expiry = now - base::TimeDelta::FromMinutes(5);
+ pm->GetFullHashCachedResults(matched_locally, now, &prefixes_to_request,
+ &cached_full_hash_infos);
+ ASSERT_EQ(1ul, prefixes_to_request.size());
+ EXPECT_EQ(prefix, prefixes_to_request[0]);
+ EXPECT_TRUE(cached_full_hash_infos.empty());
+ }
+
+ {
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ cache->clear();
+
+ // Now put unexpired full hash in the cache. (Case: 1-a-i)
+ CachedHashPrefixInfo* entry = &(*cache)[prefix];
+ entry->negative_expiry = now + base::TimeDelta::FromMinutes(5);
+ entry->full_hash_infos.emplace_back(full_hash, GetUrlMalwareId(),
+ now + base::TimeDelta::FromMinutes(3));
+ pm->GetFullHashCachedResults(matched_locally, now, &prefixes_to_request,
+ &cached_full_hash_infos);
+ EXPECT_TRUE(prefixes_to_request.empty());
+ ASSERT_EQ(1ul, cached_full_hash_infos.size());
+ EXPECT_EQ(full_hash, cached_full_hash_infos[0].full_hash);
+ }
+
+ {
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ cache->clear();
+
+ // Expire the full hash in the cache. (Case: 1-a-ii)
+ CachedHashPrefixInfo* entry = &(*cache)[prefix];
+ entry->negative_expiry = now + base::TimeDelta::FromMinutes(5);
+ entry->full_hash_infos.emplace_back(full_hash, GetUrlMalwareId(),
+ now - base::TimeDelta::FromMinutes(3));
+ pm->GetFullHashCachedResults(matched_locally, now, &prefixes_to_request,
+ &cached_full_hash_infos);
+ ASSERT_EQ(1ul, prefixes_to_request.size());
+ EXPECT_EQ(prefix, prefixes_to_request[0]);
+ EXPECT_TRUE(cached_full_hash_infos.empty());
+ }
+}
+
+TEST_F(V4GetHashProtocolManagerTest, TestUpdatesAreMerged) {
+ // We'll add one of the requested FullHashInfo objects into the cache, and
+ // inject the other one as a response from the server. The result should
+ // include both FullHashInfo objects.
+
+ net::TestURLFetcherFactory factory;
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+ HashPrefix prefix_1("exam");
+ FullHash full_hash_1("example");
+ HashPrefix prefix_2("Everything");
+ FullHash full_hash_2("Everything's shiny, Cap'n.");
+
+ base::Time now = Time::Now();
+ SetTestClock(now, pm.get());
+
+ FullHashCache* cache = pm->full_hash_cache_for_tests();
+ CachedHashPrefixInfo* entry = &(*cache)[prefix_1];
+ entry->negative_expiry = now + base::TimeDelta::FromMinutes(100);
+ // Put one unexpired full hash in the cache for a store we'll look in.
+ entry->full_hash_infos.emplace_back(full_hash_1, GetUrlMalwareId(),
+ now + base::TimeDelta::FromSeconds(200));
+ // Put one unexpired full hash in the cache for a store we'll not look in.
+ entry->full_hash_infos.emplace_back(full_hash_1, GetUrlSocEngId(),
+ now + base::TimeDelta::FromSeconds(200));
+
+ // Request full hash information from two stores.
+ FullHashToStoreAndHashPrefixesMap matched_locally;
+ matched_locally[full_hash_1].push_back(
+ StoreAndHashPrefix(GetUrlMalwareId(), prefix_1));
+ matched_locally[full_hash_2].push_back(
+ StoreAndHashPrefix(GetChromeUrlApiId(), prefix_2));
+
+ // Expect full hash information from both stores.
+ std::vector<FullHashInfo> expected_results;
+ expected_results.emplace_back(full_hash_1, GetUrlMalwareId(),
+ now + base::TimeDelta::FromSeconds(200));
+ expected_results.emplace_back(full_hash_2, GetChromeUrlApiId(),
+ now + base::TimeDelta::FromSeconds(300));
+ expected_results[1].metadata.api_permissions.insert("NOTIFICATIONS");
+
+ pm->GetFullHashes(
+ matched_locally,
+ base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults,
+ base::Unretained(this), expected_results));
+
+ SetupFetcherToReturnOKResponse(factory, GetStockV4HashResponseInfos());
+
+ // No error, back off multiplier is unchanged.
+ EXPECT_EQ(0ul, pm->gethash_error_count_);
+ EXPECT_EQ(1ul, pm->gethash_back_off_mult_);
+
+ // Verify the state of the cache.
+ ASSERT_EQ(2u, cache->size());
+ const CachedHashPrefixInfo& cached_result_1 = cache->at(prefix_1);
+ EXPECT_EQ(cached_result_1.negative_expiry,
+ now + base::TimeDelta::FromMinutes(100));
+ ASSERT_EQ(2u, cached_result_1.full_hash_infos.size());
+ EXPECT_EQ(full_hash_1, cached_result_1.full_hash_infos[0].full_hash);
+ EXPECT_EQ(GetUrlMalwareId(), cached_result_1.full_hash_infos[0].list_id);
+
+ const CachedHashPrefixInfo& cached_result_2 = cache->at(prefix_2);
+ EXPECT_EQ(cached_result_2.negative_expiry,
+ now + base::TimeDelta::FromSeconds(600));
+ ASSERT_EQ(1u, cached_result_2.full_hash_infos.size());
+ EXPECT_EQ(full_hash_2, cached_result_2.full_hash_infos[0].full_hash);
+ EXPECT_EQ(GetChromeUrlApiId(), cached_result_2.full_hash_infos[0].list_id);
+ EXPECT_TRUE(callback_called());
+}
+
+// The server responds back with full hash information containing metadata
+// information for one of the full hashes for the URL in test.
+TEST_F(V4GetHashProtocolManagerTest, TestGetFullHashesWithApisMergesMetadata) {
+ net::TestURLFetcherFactory factory;
+ const GURL url("https://www.example.com/more");
+ ThreatMetadata expected_md;
+ expected_md.api_permissions.insert("NOTIFICATIONS");
+ expected_md.api_permissions.insert("AUDIO_CAPTURE");
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+ pm->GetFullHashesWithApis(
+ url, base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4ApiResults,
+ base::Unretained(this), expected_md));
+
+ // The following two random looking strings value are two of the full hashes
+ // produced by UrlToFullHashes in v4_protocol_manager_util.h for the URL:
+ // "https://www.example.com"
+ std::vector<ResponseInfo> infos;
+ FullHash full_hash;
+ base::Base64Decode("1ZzJ0/7NjPkg6t0DAS8L5Jf7jA48Pn7opQcP4UXYeXc=",
+ &full_hash);
+ ResponseInfo info(full_hash, GetChromeUrlApiId());
+ info.key_values.emplace_back("permission", "NOTIFICATIONS");
+ infos.push_back(info);
+
+ base::Base64Decode("c9mG4AkGXxgsELy2pF2z1u2pSY-JMGVK8mU_ipOM2AE=",
+ &full_hash);
+ info = ResponseInfo(full_hash, GetChromeUrlApiId());
+ info.key_values.emplace_back("permission", "AUDIO_CAPTURE");
+ infos.push_back(info);
+
+ full_hash = FullHash("Everything's shiny, Cap'n.");
+ info = ResponseInfo(full_hash, GetChromeUrlApiId());
+ info.key_values.emplace_back("permission", "GEOLOCATION");
+ infos.push_back(info);
+ SetupFetcherToReturnOKResponse(factory, infos);
+
+ EXPECT_TRUE(callback_called());
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_local_database_manager.cc b/chromium/components/safe_browsing_db/v4_local_database_manager.cc
index 3f6fb3c268d..1a81f7fcda2 100644
--- a/chromium/components/safe_browsing_db/v4_local_database_manager.cc
+++ b/chromium/components/safe_browsing_db/v4_local_database_manager.cc
@@ -9,8 +9,11 @@
#include <vector>
+#include "base/bind_helpers.h"
#include "base/callback.h"
-#include "components/safe_browsing_db/safebrowsing.pb.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "components/safe_browsing_db/v4_feature_list.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
@@ -18,36 +21,69 @@ using content::BrowserThread;
namespace safe_browsing {
namespace {
-#if defined(OS_WIN)
-#define PLATFORM_TYPE WINDOWS_PLATFORM
-#elif defined(OS_LINUX)
-#define PLATFORM_TYPE LINUX_PLATFORM
-#elif defined(OS_MACOSX)
-#define PLATFORM_TYPE OSX_PLATFORM
-#else
-// This should ideally never compile but it is getting compiled on Android.
-// See: https://bugs.chromium.org/p/chromium/issues/detail?id=621647
-// TODO(vakh): Once that bug is fixed, this should be removed. If we leave
-// the platform_type empty, the server won't recognize the request and
-// return an error response which will pollute our UMA metrics.
-#define PLATFORM_TYPE LINUX_PLATFORM
-#endif
-
-// TODO(vakh): Implement this to populate the map appopriately.
-// Filed as http://crbug.com/608075
-StoreFileNameMap GetStoreFileNameMap() {
- return StoreFileNameMap(
- {{UpdateListIdentifier(PLATFORM_TYPE, URL, MALWARE_THREAT),
- "UrlMalware.store"},
- {UpdateListIdentifier(PLATFORM_TYPE, URL, SOCIAL_ENGINEERING_PUBLIC),
- "UrlSoceng.store"}});
+
+const ThreatSeverity kLeastSeverity =
+ std::numeric_limits<ThreatSeverity>::max();
+
+ListInfos GetListInfos() {
+ return ListInfos(
+ {ListInfo(true, "UrlMalware.store", GetUrlMalwareId(),
+ SB_THREAT_TYPE_URL_MALWARE),
+ ListInfo(true, "UrlSoceng.store", GetUrlSocEngId(),
+ SB_THREAT_TYPE_URL_PHISHING),
+ ListInfo(false, "", GetChromeUrlApiId(), SB_THREAT_TYPE_API_ABUSE)});
+}
+
+// Returns the severity information about a given SafeBrowsing list. The lowest
+// value is 0, which represents the most severe list.
+ThreatSeverity GetThreatSeverity(const ListIdentifier& list_id) {
+ switch (list_id.threat_type()) {
+ case MALWARE_THREAT:
+ case SOCIAL_ENGINEERING_PUBLIC:
+ return 0;
+ case API_ABUSE:
+ return 1;
+ default:
+ NOTREACHED() << "Unexpected ThreatType encountered in GetThreatSeverity";
+ return kLeastSeverity;
+ }
}
} // namespace
+V4LocalDatabaseManager::PendingCheck::PendingCheck(
+ Client* client,
+ ClientCallbackType client_callback_type,
+ const StoresToCheck& stores_to_check,
+ const GURL& url)
+ : client(client),
+ client_callback_type(client_callback_type),
+ result_threat_type(SB_THREAT_TYPE_SAFE),
+ stores_to_check(stores_to_check),
+ url(url) {
+ DCHECK_GT(ClientCallbackType::CHECK_MAX, client_callback_type);
+}
+
+V4LocalDatabaseManager::PendingCheck::~PendingCheck() {}
+
+// static
+scoped_refptr<V4LocalDatabaseManager> V4LocalDatabaseManager::Create(
+ const base::FilePath& base_path) {
+ if (!V4FeatureList::IsLocalDatabaseManagerEnabled()) {
+ return nullptr;
+ }
+
+ return make_scoped_refptr(new V4LocalDatabaseManager(base_path));
+}
+
V4LocalDatabaseManager::V4LocalDatabaseManager(const base::FilePath& base_path)
- : base_path_(base_path), enabled_(false) {
+ : base_path_(base_path),
+ enabled_(false),
+ list_infos_(GetListInfos()),
+ weak_factory_(this) {
DCHECK(!base_path_.empty());
+ DCHECK(!list_infos_.empty());
+
DVLOG(1) << "V4LocalDatabaseManager::V4LocalDatabaseManager: "
<< "base_path_: " << base_path_.AsUTF8Unsafe();
}
@@ -56,16 +92,27 @@ V4LocalDatabaseManager::~V4LocalDatabaseManager() {
DCHECK(!enabled_);
}
-bool V4LocalDatabaseManager::IsSupported() const {
- return true;
-}
+//
+// Start: SafeBrowsingDatabaseManager implementation
+//
-safe_browsing::ThreatSource V4LocalDatabaseManager::GetThreatSource() const {
- return safe_browsing::ThreatSource::LOCAL_PVER4;
-}
+void V4LocalDatabaseManager::CancelCheck(Client* client) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(enabled_);
-bool V4LocalDatabaseManager::ChecksAreAlwaysAsync() const {
- return false;
+ auto it = pending_clients_.find(client);
+ if (it != pending_clients_.end()) {
+ pending_clients_.erase(it);
+ }
+
+ auto queued_it =
+ std::find_if(std::begin(queued_checks_), std::end(queued_checks_),
+ [&client](const std::unique_ptr<PendingCheck>& check) {
+ return check->client == client;
+ });
+ if (queued_it != queued_checks_.end()) {
+ queued_checks_.erase(queued_it);
+ }
}
bool V4LocalDatabaseManager::CanCheckResourceType(
@@ -79,10 +126,32 @@ bool V4LocalDatabaseManager::CanCheckUrl(const GURL& url) const {
url.SchemeIs(url::kFtpScheme);
}
-bool V4LocalDatabaseManager::IsDownloadProtectionEnabled() const {
- // TODO(vakh): Investigate the possibility of using a command line switch for
- // this instead.
- return true;
+bool V4LocalDatabaseManager::ChecksAreAlwaysAsync() const {
+ return false;
+}
+
+bool V4LocalDatabaseManager::CheckBrowseUrl(const GURL& url, Client* client) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!enabled_ || !CanCheckUrl(url)) {
+ return true;
+ }
+
+ std::unique_ptr<PendingCheck> check = base::MakeUnique<PendingCheck>(
+ client, ClientCallbackType::CHECK_BROWSE_URL,
+ StoresToCheck({GetUrlMalwareId(), GetUrlSocEngId()}), url);
+ if (!v4_database_) {
+ queued_checks_.push_back(std::move(check));
+ return false;
+ }
+
+ FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
+ if (!GetPrefixMatches(check, &full_hash_to_store_and_hash_prefixes)) {
+ return true;
+ }
+
+ PerformFullHashCheck(std::move(check), full_hash_to_store_and_hash_prefixes);
+ return false;
}
bool V4LocalDatabaseManager::CheckDownloadUrl(
@@ -101,19 +170,13 @@ bool V4LocalDatabaseManager::CheckExtensionIDs(
return true;
}
-bool V4LocalDatabaseManager::MatchMalwareIP(const std::string& ip_address) {
- // TODO(vakh): Implement this skeleton.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- return false;
-}
-
-bool V4LocalDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
+bool V4LocalDatabaseManager::CheckResourceUrl(const GURL& url, Client* client) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
-bool V4LocalDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
+bool V4LocalDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
@@ -126,46 +189,49 @@ bool V4LocalDatabaseManager::MatchDownloadWhitelistString(
return true;
}
-bool V4LocalDatabaseManager::MatchModuleWhitelistString(
- const std::string& str) {
+bool V4LocalDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
-bool V4LocalDatabaseManager::CheckResourceUrl(const GURL& url, Client* client) {
+bool V4LocalDatabaseManager::MatchMalwareIP(const std::string& ip_address) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- return true;
+ return false;
}
-bool V4LocalDatabaseManager::IsMalwareKillSwitchOn() {
+bool V4LocalDatabaseManager::MatchModuleWhitelistString(
+ const std::string& str) {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
+ThreatSource V4LocalDatabaseManager::GetThreatSource() const {
+ return ThreatSource::LOCAL_PVER4;
+}
+
bool V4LocalDatabaseManager::IsCsdWhitelistKillSwitchOn() {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return true;
}
-bool V4LocalDatabaseManager::CheckBrowseUrl(const GURL& url, Client* client) {
- // TODO(vakh): Implement this skeleton.
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_) {
- return true;
- }
-
- // Don't defer the resource load.
+bool V4LocalDatabaseManager::IsDownloadProtectionEnabled() const {
+ // TODO(vakh): Investigate the possibility of using a command line switch for
+ // this instead.
return true;
}
-void V4LocalDatabaseManager::CancelCheck(Client* client) {
+bool V4LocalDatabaseManager::IsMalwareKillSwitchOn() {
// TODO(vakh): Implement this skeleton.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(enabled_);
+ return true;
+}
+
+bool V4LocalDatabaseManager::IsSupported() const {
+ return true;
}
void V4LocalDatabaseManager::StartOnIOThread(
@@ -174,48 +240,41 @@ void V4LocalDatabaseManager::StartOnIOThread(
SafeBrowsingDatabaseManager::StartOnIOThread(request_context_getter, config);
db_updated_callback_ = base::Bind(&V4LocalDatabaseManager::DatabaseUpdated,
- base::Unretained(this));
+ weak_factory_.GetWeakPtr());
SetupUpdateProtocolManager(request_context_getter, config);
-
SetupDatabase();
enabled_ = true;
}
-void V4LocalDatabaseManager::SetupUpdateProtocolManager(
- net::URLRequestContextGetter* request_context_getter,
- const V4ProtocolConfig& config) {
- V4UpdateCallback callback = base::Bind(
- &V4LocalDatabaseManager::UpdateRequestCompleted, base::Unretained(this));
+void V4LocalDatabaseManager::StopOnIOThread(bool shutdown) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
- v4_update_protocol_manager_ =
- V4UpdateProtocolManager::Create(request_context_getter, config, callback);
-}
+ enabled_ = false;
-void V4LocalDatabaseManager::SetupDatabase() {
- DCHECK(!base_path_.empty());
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ pending_clients_.clear();
- // Only get a new task runner if there isn't one already. If the service has
- // previously been started and stopped, a task runner could already exist.
- if (!task_runner_) {
- base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
- task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior(
- pool->GetSequenceToken(), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
- }
+ RespondSafeToQueuedChecks();
- // Do not create the database on the IO thread since this may be an expensive
- // operation. Instead, do that on the task_runner and when the new database
- // has been created, swap it out on the IO thread.
- StoreFileNameMap store_file_name_map = GetStoreFileNameMap();
- DCHECK(!store_file_name_map.empty());
- NewDatabaseReadyCallback db_ready_callback = base::Bind(
- &V4LocalDatabaseManager::DatabaseReady, base::Unretained(this));
- V4Database::Create(task_runner_, base_path_, store_file_name_map,
- db_ready_callback);
+ // Delete the V4Database. Any pending writes to disk are completed.
+ // This operation happens on the task_runner on which v4_database_ operates
+ // and doesn't block the IO thread.
+ V4Database::Destroy(std::move(v4_database_));
+
+ // Delete the V4UpdateProtocolManager.
+ // This cancels any in-flight update request.
+ v4_update_protocol_manager_.reset();
+
+ db_updated_callback_.Reset();
+
+ SafeBrowsingDatabaseManager::StopOnIOThread(shutdown);
}
+//
+// End: SafeBrowsingDatabaseManager implementation
+//
+
void V4LocalDatabaseManager::DatabaseReady(
std::unique_ptr<V4Database> v4_database) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -228,29 +287,191 @@ void V4LocalDatabaseManager::DatabaseReady(
// The database is in place. Start fetching updates now.
v4_update_protocol_manager_->ScheduleNextUpdate(
v4_database_->GetStoreStateMap());
+
+ ProcessQueuedChecks();
} else {
// Schedule the deletion of v4_database off IO thread.
V4Database::Destroy(std::move(v4_database));
}
}
-void V4LocalDatabaseManager::StopOnIOThread(bool shutdown) {
+void V4LocalDatabaseManager::DatabaseUpdated() {
+ if (enabled_) {
+ v4_update_protocol_manager_->ScheduleNextUpdate(
+ v4_database_->GetStoreStateMap());
+ }
+}
+
+bool V4LocalDatabaseManager::GetPrefixMatches(
+ const std::unique_ptr<PendingCheck>& check,
+ FullHashToStoreAndHashPrefixesMap* full_hash_to_store_and_hash_prefixes) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- enabled_ = false;
+ DCHECK(enabled_);
+ DCHECK(v4_database_);
+ DCHECK_GT(ClientCallbackType::CHECK_MAX, check->client_callback_type);
+
+ if (check->client_callback_type == ClientCallbackType::CHECK_BROWSE_URL) {
+ std::unordered_set<FullHash> full_hashes;
+ V4ProtocolManagerUtil::UrlToFullHashes(check->url, &full_hashes);
+
+ StoreAndHashPrefixes matched_store_and_hash_prefixes;
+ for (const auto& full_hash : full_hashes) {
+ matched_store_and_hash_prefixes.clear();
+ v4_database_->GetStoresMatchingFullHash(full_hash, check->stores_to_check,
+ &matched_store_and_hash_prefixes);
+ if (!matched_store_and_hash_prefixes.empty()) {
+ (*full_hash_to_store_and_hash_prefixes)[full_hash] =
+ matched_store_and_hash_prefixes;
+ }
+ }
+
+ // No hash prefixes found in the local database so that resource must be
+ // safe.
+ return !full_hash_to_store_and_hash_prefixes->empty();
+ }
- // Delete the V4Database. Any pending writes to disk are completed.
- // This operation happens on the task_runner on which v4_database_ operates
- // and doesn't block the IO thread.
- V4Database::Destroy(std::move(v4_database_));
+ NOTREACHED() << "Unexpected client_callback_type encountered";
+ return false;
+}
- // Delete the V4UpdateProtocolManager.
- // This cancels any in-flight update request.
- v4_update_protocol_manager_.reset();
+void V4LocalDatabaseManager::GetSeverestThreatTypeAndMetadata(
+ SBThreatType* result_threat_type,
+ ThreatMetadata* metadata,
+ const std::vector<FullHashInfo>& full_hash_infos) {
+ DCHECK(result_threat_type);
+ DCHECK(metadata);
+
+ ThreatSeverity most_severe_yet = kLeastSeverity;
+ for (const FullHashInfo& fhi : full_hash_infos) {
+ ThreatSeverity severity = GetThreatSeverity(fhi.list_id);
+ if (severity < most_severe_yet) {
+ most_severe_yet = severity;
+ *result_threat_type = GetSBThreatTypeForList(fhi.list_id);
+ *metadata = fhi.metadata;
+ }
+ }
+}
- db_updated_callback_.Reset();
+StoresToCheck V4LocalDatabaseManager::GetStoresForFullHashRequests() {
+ StoresToCheck stores_for_full_hash;
+ for (auto it : list_infos_) {
+ stores_for_full_hash.insert(it.list_id());
+ }
+ return stores_for_full_hash;
+}
- SafeBrowsingDatabaseManager::StopOnIOThread(shutdown);
+// Returns the SBThreatType corresponding to a given SafeBrowsing list.
+SBThreatType V4LocalDatabaseManager::GetSBThreatTypeForList(
+ const ListIdentifier& list_id) {
+ auto it = std::find_if(
+ std::begin(list_infos_), std::end(list_infos_),
+ [&list_id](ListInfo const& li) { return li.list_id() == list_id; });
+ DCHECK(list_infos_.end() != it);
+ DCHECK_NE(SB_THREAT_TYPE_SAFE, it->sb_threat_type());
+ return it->sb_threat_type();
+}
+
+void V4LocalDatabaseManager::OnFullHashResponse(
+ std::unique_ptr<PendingCheck> pending_check,
+ const std::vector<FullHashInfo>& full_hash_infos) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!enabled_) {
+ DCHECK(pending_clients_.empty());
+ return;
+ }
+
+ auto it = pending_clients_.find(pending_check->client);
+ if (it == pending_clients_.end()) {
+ // The check has since been cancelled.
+ return;
+ }
+
+ // Find out the most severe threat, if any, to report to the client.
+ GetSeverestThreatTypeAndMetadata(&pending_check->result_threat_type,
+ &pending_check->url_metadata,
+ full_hash_infos);
+ pending_clients_.erase(it);
+ RespondToClient(std::move(pending_check));
+}
+
+void V4LocalDatabaseManager::PerformFullHashCheck(
+ std::unique_ptr<PendingCheck> check,
+ const FullHashToStoreAndHashPrefixesMap&
+ full_hash_to_store_and_hash_prefixes) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ DCHECK(enabled_);
+ DCHECK(!full_hash_to_store_and_hash_prefixes.empty());
+
+ pending_clients_.insert(check->client);
+
+ v4_get_hash_protocol_manager_->GetFullHashes(
+ full_hash_to_store_and_hash_prefixes,
+ base::Bind(&V4LocalDatabaseManager::OnFullHashResponse,
+ weak_factory_.GetWeakPtr(), base::Passed(std::move(check))));
+}
+
+void V4LocalDatabaseManager::ProcessQueuedChecks() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ for (auto& it : queued_checks_) {
+ FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
+ if (!GetPrefixMatches(it, &full_hash_to_store_and_hash_prefixes)) {
+ RespondToClient(std::move(it));
+ } else {
+ PerformFullHashCheck(std::move(it), full_hash_to_store_and_hash_prefixes);
+ }
+ }
+ queued_checks_.clear();
+}
+
+void V4LocalDatabaseManager::RespondSafeToQueuedChecks() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ for (std::unique_ptr<PendingCheck>& it : queued_checks_) {
+ RespondToClient(std::move(it));
+ }
+ queued_checks_.clear();
+}
+
+void V4LocalDatabaseManager::RespondToClient(
+ std::unique_ptr<PendingCheck> pending_check) {
+ DCHECK(pending_check.get());
+ DCHECK_EQ(ClientCallbackType::CHECK_BROWSE_URL,
+ pending_check->client_callback_type);
+ // TODO(vakh): Implement this skeleton.
+}
+
+void V4LocalDatabaseManager::SetupDatabase() {
+ DCHECK(!base_path_.empty());
+ DCHECK(!list_infos_.empty());
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Only get a new task runner if there isn't one already. If the service has
+ // previously been started and stopped, a task runner could already exist.
+ if (!task_runner_) {
+ base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
+ task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ pool->GetSequenceToken(), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+ }
+
+ // Do not create the database on the IO thread since this may be an expensive
+ // operation. Instead, do that on the task_runner and when the new database
+ // has been created, swap it out on the IO thread.
+ NewDatabaseReadyCallback db_ready_callback = base::Bind(
+ &V4LocalDatabaseManager::DatabaseReady, weak_factory_.GetWeakPtr());
+ V4Database::Create(task_runner_, base_path_, list_infos_, db_ready_callback);
+}
+
+void V4LocalDatabaseManager::SetupUpdateProtocolManager(
+ net::URLRequestContextGetter* request_context_getter,
+ const V4ProtocolConfig& config) {
+ V4UpdateCallback callback =
+ base::Bind(&V4LocalDatabaseManager::UpdateRequestCompleted,
+ weak_factory_.GetWeakPtr());
+
+ v4_update_protocol_manager_ =
+ V4UpdateProtocolManager::Create(request_context_getter, config, callback);
}
void V4LocalDatabaseManager::UpdateRequestCompleted(
@@ -260,9 +481,4 @@ void V4LocalDatabaseManager::UpdateRequestCompleted(
db_updated_callback_);
}
-void V4LocalDatabaseManager::DatabaseUpdated() {
- v4_update_protocol_manager_->ScheduleNextUpdate(
- v4_database_->GetStoreStateMap());
-}
-
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_local_database_manager.h b/chromium/components/safe_browsing_db/v4_local_database_manager.h
index 0bc033f0381..0449b8c5ac5 100644
--- a/chromium/components/safe_browsing_db/v4_local_database_manager.h
+++ b/chromium/components/safe_browsing_db/v4_local_database_manager.h
@@ -10,9 +10,11 @@
#include <memory>
+#include "base/memory/weak_ptr.h"
#include "components/safe_browsing_db/database_manager.h"
#include "components/safe_browsing_db/hit_report.h"
#include "components/safe_browsing_db/v4_database.h"
+#include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
#include "components/safe_browsing_db/v4_protocol_manager_util.h"
#include "components/safe_browsing_db/v4_update_protocol_manager.h"
#include "url/gurl.h"
@@ -21,86 +23,212 @@ using content::ResourceType;
namespace safe_browsing {
+typedef unsigned ThreatSeverity;
+
// Manages the local, on-disk database of updates downloaded from the
// SafeBrowsing service and interfaces with the protocol manager.
class V4LocalDatabaseManager : public SafeBrowsingDatabaseManager {
public:
- // Construct V4LocalDatabaseManager.
- // Must be initialized by calling StartOnIOThread() before using.
- V4LocalDatabaseManager(const base::FilePath& base_path);
+ // Create and return an instance of V4LocalDatabaseManager, if Finch trial
+ // allows it; nullptr otherwise.
+ static scoped_refptr<V4LocalDatabaseManager> Create(
+ const base::FilePath& base_path);
//
// SafeBrowsingDatabaseManager implementation
//
- bool IsSupported() const override;
- safe_browsing::ThreatSource GetThreatSource() const override;
- bool ChecksAreAlwaysAsync() const override;
+ void CancelCheck(Client* client) override;
bool CanCheckResourceType(content::ResourceType resource_type) const override;
bool CanCheckUrl(const GURL& url) const override;
- bool IsDownloadProtectionEnabled() const override;
+ bool ChecksAreAlwaysAsync() const override;
bool CheckBrowseUrl(const GURL& url, Client* client) override;
- void CancelCheck(Client* client) override;
- void StartOnIOThread(net::URLRequestContextGetter* request_context_getter,
- const V4ProtocolConfig& config) override;
- void StopOnIOThread(bool shutdown) override;
bool CheckDownloadUrl(const std::vector<GURL>& url_chain,
Client* client) override;
bool CheckExtensionIDs(const std::set<std::string>& extension_ids,
Client* client) override;
+ bool CheckResourceUrl(const GURL& url, Client* client) override;
bool MatchCsdWhitelistUrl(const GURL& url) override;
- bool MatchMalwareIP(const std::string& ip_address) override;
- bool MatchDownloadWhitelistUrl(const GURL& url) override;
bool MatchDownloadWhitelistString(const std::string& str) override;
+ bool MatchDownloadWhitelistUrl(const GURL& url) override;
+ bool MatchMalwareIP(const std::string& ip_address) override;
bool MatchModuleWhitelistString(const std::string& str) override;
- bool CheckResourceUrl(const GURL& url, Client* client) override;
- bool IsMalwareKillSwitchOn() override;
+ safe_browsing::ThreatSource GetThreatSource() const override;
bool IsCsdWhitelistKillSwitchOn() override;
+ bool IsDownloadProtectionEnabled() const override;
+ bool IsMalwareKillSwitchOn() override;
+ bool IsSupported() const override;
+ void StartOnIOThread(net::URLRequestContextGetter* request_context_getter,
+ const V4ProtocolConfig& config) override;
+ void StopOnIOThread(bool shutdown) override;
- private:
- ~V4LocalDatabaseManager() override;
+ //
+ // End: SafeBrowsingDatabaseManager implementation
+ //
- // The callback called each time the protocol manager downloads updates
- // successfully.
- void UpdateRequestCompleted(
- std::unique_ptr<ParsedServerResponse> parsed_server_response);
+ protected:
+ // Construct V4LocalDatabaseManager.
+ // Must be initialized by calling StartOnIOThread() before using.
+ V4LocalDatabaseManager(const base::FilePath& base_path);
- void SetupUpdateProtocolManager(
- net::URLRequestContextGetter* request_context_getter,
- const V4ProtocolConfig& config);
+ enum class ClientCallbackType {
+ // This represents the case when we're trying to determine if a URL is
+ // unsafe from the following perspectives: Malware, Phishing, UwS.
+ CHECK_BROWSE_URL = 0,
- void SetupDatabase();
+ // This should always be the last value.
+ CHECK_MAX
+ };
+ // The information we need to process a URL safety reputation request and
+ // respond to the SafeBrowsing client that asked for it.
+ // TODO(vakh): In its current form, it only includes information for
+ // |CheckBrowseUrl| method. Extend it to serve other methods on |client|.
+ struct PendingCheck {
+ PendingCheck(Client* client,
+ ClientCallbackType client_callback_type,
+ const StoresToCheck& stores_to_check,
+ const GURL& url);
+
+ ~PendingCheck();
+
+ // The SafeBrowsing client that's waiting for the safe/unsafe verdict.
+ Client* client;
+
+ // Determines which funtion from the |client| needs to be called once we
+ // know whether the URL in |url| is safe or unsafe.
+ ClientCallbackType client_callback_type;
+
+ // The threat verdict for the URL being checked.
+ SBThreatType result_threat_type;
+
+ // The SafeBrowsing lists to check hash prefixes in.
+ StoresToCheck stores_to_check;
+
+ // The URL that is being checked for being unsafe.
+ GURL url;
+
+ // The metadata associated with the full hash of the severest match found
+ // for that URL.
+ ThreatMetadata url_metadata;
+ };
+
+ typedef std::vector<std::unique_ptr<PendingCheck>> QueuedChecks;
+
+ // The stores/lists to always get full hashes for, regardless of which store
+ // the hash prefix matched.
+ StoresToCheck GetStoresForFullHashRequests() override;
+
+ private:
+ friend class V4LocalDatabaseManagerTest;
+ void SetTaskRunnerForTest(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+ task_runner_ = task_runner;
+ }
+ FRIEND_TEST_ALL_PREFIXES(V4LocalDatabaseManagerTest,
+ TestGetSeverestThreatTypeAndMetadata);
+
+ // The set of clients awaiting a full hash response. It is used for tracking
+ // which clients have cancelled their outstanding request.
+ typedef std::unordered_set<Client*> PendingClients;
+
+ ~V4LocalDatabaseManager() override;
+
+ // Called when all the stores managed by the database have been read from
+ // disk after startup and the database is ready for use.
void DatabaseReady(std::unique_ptr<V4Database> v4_database);
// Called when the database has been updated and schedules the next update.
void DatabaseUpdated();
+ // Return the prefixes and the store they matched in, for a given URL. Returns
+ // true if a hash prefix match is found; false otherwise.
+ bool GetPrefixMatches(
+ const std::unique_ptr<PendingCheck>& check,
+ FullHashToStoreAndHashPrefixesMap* full_hash_to_store_and_hash_prefixes);
+
+ // Finds the most severe |SBThreatType| and the corresponding |metadata| from
+ // |full_hash_infos|.
+ void GetSeverestThreatTypeAndMetadata(
+ SBThreatType* result_threat_type,
+ ThreatMetadata* metadata,
+ const std::vector<FullHashInfo>& full_hash_infos);
+
+ // Returns the SBThreatType for a given ListIdentifier.
+ SBThreatType GetSBThreatTypeForList(const ListIdentifier& list_id);
+
+ // Called when the |v4_get_hash_protocol_manager_| has the full hash response
+ // available for the URL that we requested. It determines the severest
+ // threat type and responds to the |client| with that information.
+ void OnFullHashResponse(std::unique_ptr<PendingCheck> pending_check,
+ const std::vector<FullHashInfo>& full_hash_infos);
+
+ // Performs the full hash checking of the URL in |check|.
+ void PerformFullHashCheck(std::unique_ptr<PendingCheck> check,
+ const FullHashToStoreAndHashPrefixesMap&
+ full_hash_to_store_and_hash_prefixes);
+
+ // When the database is ready to use, process the checks that were queued
+ // while the database was loading from disk.
+ void ProcessQueuedChecks();
+
+ // Called on StopOnIOThread, it responds to the clients that are waiting for
+ // the database to become available with the verdict as SAFE.
+ void RespondSafeToQueuedChecks();
+
+ // Calls the appopriate method on the |client| object, based on the contents
+ // of |pending_check|.
+ void RespondToClient(std::unique_ptr<PendingCheck> pending_check);
+
+ // Instantiates and initializes |v4_database_| on the task runner. Sets up the
+ // callback for |DatabaseReady| when the database is ready for use.
+ void SetupDatabase();
+
+ // Instantiates and initializes |v4_update_protocol_manager_|.
+ void SetupUpdateProtocolManager(
+ net::URLRequestContextGetter* request_context_getter,
+ const V4ProtocolConfig& config);
+
+ // The callback called each time the protocol manager downloads updates
+ // successfully.
+ void UpdateRequestCompleted(
+ std::unique_ptr<ParsedServerResponse> parsed_server_response);
+
// The base directory under which to create the files that contain hashes.
const base::FilePath base_path_;
+ // Called when the V4Database has finished applying the latest update and is
+ // ready to process next update.
+ DatabaseUpdatedCallback db_updated_callback_;
+
// Whether the service is running.
bool enabled_;
- // Stores the current status of the lists to download from the SafeBrowsing
- // servers.
- // TODO(vakh): current_list_states_ doesn't really belong here.
- // It should come through the database, from the various V4Stores.
- base::hash_map<UpdateListIdentifier, std::string> current_list_states_;
+ // The list of stores to manage (for hash prefixes and full hashes). Each
+ // element contains the identifier for the store, the corresponding
+ // SBThreatType, whether to fetch hash prefixes for that store, and the
+ // name of the file on disk that would contain the prefixes, if applicable.
+ ListInfos list_infos_;
- // The protocol manager that downloads the hash prefix updates.
- std::unique_ptr<V4UpdateProtocolManager> v4_update_protocol_manager_;
+ // The set of clients that are waiting for a full hash response from the
+ // SafeBrowsing service.
+ PendingClients pending_clients_;
+
+ // The checks that need to be scheduled when the database becomes ready for
+ // use.
+ QueuedChecks queued_checks_;
+
+ // The sequenced task runner for running safe browsing database operations.
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
// The database that manages the stores containing the hash prefix updates.
// All writes to this variable must happen on the IO thread only.
std::unique_ptr<V4Database> v4_database_;
- // Called when the V4Database has finished applying the latest update and is
- // ready to process next update.
- DatabaseUpdatedCallback db_updated_callback_;
+ // The protocol manager that downloads the hash prefix updates.
+ std::unique_ptr<V4UpdateProtocolManager> v4_update_protocol_manager_;
- // The sequenced task runner for running safe browsing database operations.
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ base::WeakPtrFactory<V4LocalDatabaseManager> weak_factory_;
friend class base::RefCountedThreadSafe<V4LocalDatabaseManager>;
DISALLOW_COPY_AND_ASSIGN(V4LocalDatabaseManager);
diff --git a/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc b/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc
new file mode 100644
index 00000000000..6574a9515d0
--- /dev/null
+++ b/chromium/components/safe_browsing_db/v4_local_database_manager_unittest.cc
@@ -0,0 +1,220 @@
+// 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 "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/test/test_simple_task_runner.h"
+#include "components/safe_browsing_db/v4_database.h"
+#include "components/safe_browsing_db/v4_local_database_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "testing/platform_test.h"
+
+namespace safe_browsing {
+
+class FakeV4Database : public V4Database {
+ public:
+ FakeV4Database(const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
+ std::unique_ptr<StoreMap> store_map,
+ const StoreAndHashPrefixes& store_and_hash_prefixes)
+ : V4Database(db_task_runner, std::move(store_map)),
+ store_and_hash_prefixes_(store_and_hash_prefixes) {}
+
+ void GetStoresMatchingFullHash(
+ const FullHash& full_hash,
+ const StoresToCheck& stores_to_check,
+ StoreAndHashPrefixes* store_and_hash_prefixes) override {
+ *store_and_hash_prefixes = store_and_hash_prefixes_;
+ }
+
+ private:
+ const StoreAndHashPrefixes& store_and_hash_prefixes_;
+};
+
+class TestClient : public SafeBrowsingDatabaseManager::Client {
+ public:
+ TestClient(SBThreatType sb_threat_type, const GURL& url)
+ : expected_sb_threat_type(sb_threat_type), expected_url(url) {}
+
+ void OnCheckBrowseUrlResult(const GURL& url,
+ SBThreatType threat_type,
+ const ThreatMetadata& metadata) override {
+ DCHECK_EQ(expected_url, url);
+ DCHECK_EQ(expected_sb_threat_type, threat_type);
+ }
+
+ SBThreatType expected_sb_threat_type;
+ GURL expected_url;
+};
+
+class V4LocalDatabaseManagerTest : public PlatformTest {
+ public:
+ V4LocalDatabaseManagerTest() : task_runner_(new base::TestSimpleTaskRunner) {}
+
+ void SetUp() override {
+ PlatformTest::SetUp();
+
+ ASSERT_TRUE(base_dir_.CreateUniqueTempDir());
+ DVLOG(1) << "base_dir_: " << base_dir_.GetPath().value();
+
+ v4_local_database_manager_ =
+ make_scoped_refptr(new V4LocalDatabaseManager(base_dir_.GetPath()));
+ v4_local_database_manager_->SetTaskRunnerForTest(task_runner_);
+
+ StartLocalDatabaseManager();
+ }
+
+ void TearDown() override {
+ StopLocalDatabaseManager();
+
+ PlatformTest::TearDown();
+ }
+
+ void ForceDisableLocalDatabaseManager() {
+ v4_local_database_manager_->enabled_ = false;
+ }
+
+ const V4LocalDatabaseManager::QueuedChecks& GetQueuedChecks() {
+ return v4_local_database_manager_->queued_checks_;
+ }
+
+ void ReplaceV4Database(const StoreAndHashPrefixes& store_and_hash_prefixes) {
+ v4_local_database_manager_->v4_database_.reset(new FakeV4Database(
+ task_runner_, base::MakeUnique<StoreMap>(), store_and_hash_prefixes));
+ }
+
+ void ResetV4Database() { v4_local_database_manager_->v4_database_.reset(); }
+
+ void StartLocalDatabaseManager() {
+ v4_local_database_manager_->StartOnIOThread(NULL, V4ProtocolConfig());
+
+ task_runner_->RunPendingTasks();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void StopLocalDatabaseManager() {
+ if (v4_local_database_manager_) {
+ v4_local_database_manager_->StopOnIOThread(true);
+ }
+
+ // Force destruction of the database.
+ task_runner_->RunPendingTasks();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ base::ScopedTempDir base_dir_;
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ content::TestBrowserThreadBundle thread_bundle_;
+ scoped_refptr<V4LocalDatabaseManager> v4_local_database_manager_;
+};
+
+TEST_F(V4LocalDatabaseManagerTest, TestGetThreatSource) {
+ EXPECT_EQ(ThreatSource::LOCAL_PVER4,
+ v4_local_database_manager_->GetThreatSource());
+}
+
+TEST_F(V4LocalDatabaseManagerTest, TestIsSupported) {
+ EXPECT_TRUE(v4_local_database_manager_->IsSupported());
+}
+
+TEST_F(V4LocalDatabaseManagerTest, TestCanCheckUrl) {
+ EXPECT_TRUE(
+ v4_local_database_manager_->CanCheckUrl(GURL("http://example.com/a/")));
+ EXPECT_TRUE(
+ v4_local_database_manager_->CanCheckUrl(GURL("https://example.com/a/")));
+ EXPECT_TRUE(
+ v4_local_database_manager_->CanCheckUrl(GURL("ftp://example.com/a/")));
+ EXPECT_FALSE(
+ v4_local_database_manager_->CanCheckUrl(GURL("adp://example.com/a/")));
+}
+
+TEST_F(V4LocalDatabaseManagerTest,
+ TestCheckBrowseUrlWithEmptyStoresReturnsNoMatch) {
+ // Both the stores are empty right now so CheckBrowseUrl should return true.
+ EXPECT_TRUE(v4_local_database_manager_->CheckBrowseUrl(
+ GURL("http://example.com/a/"), nullptr));
+}
+
+TEST_F(V4LocalDatabaseManagerTest, TestCheckBrowseUrlWithFakeDbReturnsMatch) {
+ net::TestURLFetcherFactory factory;
+
+ StoreAndHashPrefixes store_and_hash_prefixes;
+ store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), HashPrefix("aaaa"));
+ ReplaceV4Database(store_and_hash_prefixes);
+
+ // The fake database returns a matched hash prefix.
+ EXPECT_FALSE(v4_local_database_manager_->CheckBrowseUrl(
+ GURL("http://example.com/a/"), nullptr));
+}
+
+TEST_F(V4LocalDatabaseManagerTest,
+ TestCheckBrowseUrlReturnsNoMatchWhenDisabled) {
+ StoreAndHashPrefixes store_and_hash_prefixes;
+ store_and_hash_prefixes.emplace_back(GetUrlMalwareId(), HashPrefix("aaaa"));
+ ReplaceV4Database(store_and_hash_prefixes);
+
+ // The same URL returns |false| in the previous test because
+ // v4_local_database_manager_ is enabled.
+ ForceDisableLocalDatabaseManager();
+
+ EXPECT_TRUE(v4_local_database_manager_->CheckBrowseUrl(
+ GURL("http://example.com/a/"), nullptr));
+}
+
+TEST_F(V4LocalDatabaseManagerTest, TestGetSeverestThreatTypeAndMetadata) {
+ FullHashInfo fhi_malware(FullHash("Malware"), GetUrlMalwareId(),
+ base::Time::Now());
+ fhi_malware.metadata.population_id = "malware_popid";
+
+ FullHashInfo fhi_api(FullHash("api"), GetChromeUrlApiId(), base::Time::Now());
+ fhi_api.metadata.population_id = "api_popid";
+
+ std::vector<FullHashInfo> fhis({fhi_malware, fhi_api});
+
+ SBThreatType result_threat_type;
+ ThreatMetadata metadata;
+
+ v4_local_database_manager_->GetSeverestThreatTypeAndMetadata(
+ &result_threat_type, &metadata, fhis);
+ EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, result_threat_type);
+ EXPECT_EQ("malware_popid", metadata.population_id);
+
+ // Reversing the list has no effect.
+ std::reverse(std::begin(fhis), std::end(fhis));
+ v4_local_database_manager_->GetSeverestThreatTypeAndMetadata(
+ &result_threat_type, &metadata, fhis);
+ EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, result_threat_type);
+ EXPECT_EQ("malware_popid", metadata.population_id);
+}
+
+TEST_F(V4LocalDatabaseManagerTest, TestChecksAreQueued) {
+ const GURL url("https://www.example.com/");
+ TestClient client(SB_THREAT_TYPE_SAFE, url);
+ EXPECT_TRUE(GetQueuedChecks().empty());
+ v4_local_database_manager_->CheckBrowseUrl(url, &client);
+ // The database is available so the check shouldn't get queued.
+ EXPECT_TRUE(GetQueuedChecks().empty());
+
+ ResetV4Database();
+ v4_local_database_manager_->CheckBrowseUrl(url, &client);
+ // The database is unavailable so the check should get queued.
+ EXPECT_EQ(1ul, GetQueuedChecks().size());
+
+ // The following function calls StartOnIOThread which should load the
+ // database from disk and cause the queued check to be performed.
+ StartLocalDatabaseManager();
+ EXPECT_TRUE(GetQueuedChecks().empty());
+
+ ResetV4Database();
+ v4_local_database_manager_->CheckBrowseUrl(url, &client);
+ // The database is unavailable so the check should get queued.
+ EXPECT_EQ(1ul, GetQueuedChecks().size());
+
+ StopLocalDatabaseManager();
+ EXPECT_TRUE(GetQueuedChecks().empty());
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_protocol_manager_util.cc b/chromium/components/safe_browsing_db/v4_protocol_manager_util.cc
index e5e4f01255b..c349b6b9d8f 100644
--- a/chromium/components/safe_browsing_db/v4_protocol_manager_util.cc
+++ b/chromium/components/safe_browsing_db/v4_protocol_manager_util.cc
@@ -7,61 +7,157 @@
#include "base/base64.h"
#include "base/metrics/sparse_histogram.h"
#include "base/rand_util.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "crypto/sha2.h"
#include "net/base/escape.h"
#include "net/http/http_request_headers.h"
+#include "url/url_util.h"
using base::Time;
using base::TimeDelta;
namespace safe_browsing {
-std::ostream& operator<<(std::ostream& os, const UpdateListIdentifier& id) {
- os << "{hash: " << id.hash() << "; platform_type: " << id.platform_type
- << "; threat_entry_type: " << id.threat_entry_type
- << "; threat_type: " << id.threat_type << "}";
+namespace {
+
+std::string Unescape(const std::string& url) {
+ std::string unescaped_str(url);
+ const int kMaxLoopIterations = 1024;
+ size_t old_size = 0;
+ int loop_var = 0;
+ do {
+ old_size = unescaped_str.size();
+ unescaped_str = net::UnescapeURLComponent(
+ unescaped_str,
+ net::UnescapeRule::SPOOFING_AND_CONTROL_CHARS |
+ net::UnescapeRule::SPACES | net::UnescapeRule::PATH_SEPARATORS |
+ net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
+ } while (old_size != unescaped_str.size() &&
+ ++loop_var <= kMaxLoopIterations);
+
+ return unescaped_str;
+}
+
+std::string Escape(const std::string& url) {
+ std::string escaped_str;
+ // The escaped string is larger so allocate double the length to reduce the
+ // chance of the string being grown.
+ escaped_str.reserve(url.length() * 2);
+ const char* kHexString = "0123456789ABCDEF";
+ for (size_t i = 0; i < url.length(); i++) {
+ unsigned char c = static_cast<unsigned char>(url[i]);
+ if (c <= ' ' || c > '~' || c == '#' || c == '%') {
+ escaped_str += '%';
+ escaped_str += kHexString[c >> 4];
+ escaped_str += kHexString[c & 0xf];
+ } else {
+ escaped_str += c;
+ }
+ }
+
+ return escaped_str;
+}
+
+} // namespace
+
+std::ostream& operator<<(std::ostream& os, const ListIdentifier& id) {
+ os << "{hash: " << id.hash() << "; platform_type: " << id.platform_type()
+ << "; threat_entry_type: " << id.threat_entry_type()
+ << "; threat_type: " << id.threat_type() << "}";
return os;
}
+PlatformType GetCurrentPlatformType() {
+#if defined(OS_WIN)
+ return WINDOWS_PLATFORM;
+#elif defined(OS_LINUX)
+ return LINUX_PLATFORM;
+#elif defined(OS_MACOSX)
+ return OSX_PLATFORM;
+#else
+// This should ideally never compile but it is getting compiled on Android.
+// See: https://bugs.chromium.org/p/chromium/issues/detail?id=621647
+// TODO(vakh): Once that bug is fixed, this should be removed. If we leave
+// the platform_type empty, the server won't recognize the request and
+// return an error response which will pollute our UMA metrics.
+return LINUX_PLATFORM;
+#endif
+}
+
+const ListIdentifier GetChromeUrlApiId() {
+ return ListIdentifier(CHROME_PLATFORM, URL, API_ABUSE);
+}
+
+const ListIdentifier GetUrlMalwareId() {
+ return ListIdentifier(GetCurrentPlatformType(), URL, MALWARE_THREAT);
+}
+
+const ListIdentifier GetUrlSocEngId() {
+ return ListIdentifier(GetCurrentPlatformType(), URL,
+ SOCIAL_ENGINEERING_PUBLIC);
+}
+
// The Safe Browsing V4 server URL prefix.
const char kSbV4UrlPrefix[] = "https://safebrowsing.googleapis.com/v4";
-bool UpdateListIdentifier::operator==(const UpdateListIdentifier& other) const {
- return platform_type == other.platform_type &&
- threat_entry_type == other.threat_entry_type &&
- threat_type == other.threat_type;
+StoreAndHashPrefix::StoreAndHashPrefix(ListIdentifier list_id,
+ HashPrefix hash_prefix)
+ : list_id(list_id), hash_prefix(hash_prefix) {}
+
+StoreAndHashPrefix::~StoreAndHashPrefix() {}
+
+bool StoreAndHashPrefix::operator==(const StoreAndHashPrefix& other) const {
+ return list_id == other.list_id && hash_prefix == other.hash_prefix;
}
-bool UpdateListIdentifier::operator!=(const UpdateListIdentifier& other) const {
+bool StoreAndHashPrefix::operator!=(const StoreAndHashPrefix& other) const {
return !operator==(other);
}
-size_t UpdateListIdentifier::hash() const {
- std::size_t first = std::hash<unsigned int>()(platform_type);
- std::size_t second = std::hash<unsigned int>()(threat_entry_type);
- std::size_t third = std::hash<unsigned int>()(threat_type);
+size_t StoreAndHashPrefix::hash() const {
+ std::size_t first = list_id.hash();
+ std::size_t second = std::hash<std::string>()(hash_prefix);
+
+ return base::HashInts(first, second);
+}
+
+bool ListIdentifier::operator==(const ListIdentifier& other) const {
+ return platform_type_ == other.platform_type_ &&
+ threat_entry_type_ == other.threat_entry_type_ &&
+ threat_type_ == other.threat_type_;
+}
+
+bool ListIdentifier::operator!=(const ListIdentifier& other) const {
+ return !operator==(other);
+}
+
+size_t ListIdentifier::hash() const {
+ std::size_t first = std::hash<unsigned int>()(platform_type_);
+ std::size_t second = std::hash<unsigned int>()(threat_entry_type_);
+ std::size_t third = std::hash<unsigned int>()(threat_type_);
std::size_t interim = base::HashInts(first, second);
return base::HashInts(interim, third);
}
-UpdateListIdentifier::UpdateListIdentifier() {}
+ListIdentifier::ListIdentifier() {}
-UpdateListIdentifier::UpdateListIdentifier(PlatformType platform_type,
- ThreatEntryType threat_entry_type,
- ThreatType threat_type)
- : platform_type(platform_type),
- threat_entry_type(threat_entry_type),
- threat_type(threat_type) {
+ListIdentifier::ListIdentifier(PlatformType platform_type,
+ ThreatEntryType threat_entry_type,
+ ThreatType threat_type)
+ : platform_type_(platform_type),
+ threat_entry_type_(threat_entry_type),
+ threat_type_(threat_type) {
DCHECK(PlatformType_IsValid(platform_type));
DCHECK(ThreatEntryType_IsValid(threat_entry_type));
DCHECK(ThreatType_IsValid(threat_type));
}
-UpdateListIdentifier::UpdateListIdentifier(const ListUpdateResponse& response)
- : UpdateListIdentifier(response.platform_type(),
- response.threat_entry_type(),
- response.threat_type()) {}
+ListIdentifier::ListIdentifier(const ListUpdateResponse& response)
+ : ListIdentifier(response.platform_type(),
+ response.threat_entry_type(),
+ response.threat_type()) {}
V4ProtocolConfig::V4ProtocolConfig() : disable_auto_update(false) {}
@@ -138,4 +234,275 @@ void V4ProtocolManagerUtil::UpdateHeaders(net::HttpRequestHeaders* headers) {
headers->SetHeaderIfMissing("X-HTTP-Method-Override", "POST");
}
+// static
+void V4ProtocolManagerUtil::UrlToFullHashes(
+ const GURL& url,
+ std::unordered_set<FullHash>* full_hashes) {
+ std::string canon_host, canon_path, canon_query;
+ CanonicalizeUrl(url, &canon_host, &canon_path, &canon_query);
+
+ std::vector<std::string> hosts;
+ if (url.HostIsIPAddress()) {
+ hosts.push_back(url.host());
+ } else {
+ GenerateHostVariantsToCheck(canon_host, &hosts);
+ }
+
+ std::vector<std::string> paths;
+ GeneratePathVariantsToCheck(canon_path, canon_query, &paths);
+ for (const std::string& host : hosts) {
+ for (const std::string& path : paths) {
+ full_hashes->insert(crypto::SHA256HashString(host + path));
+ }
+ }
+}
+
+// static
+bool V4ProtocolManagerUtil::FullHashToHashPrefix(const FullHash& full_hash,
+ PrefixSize prefix_size,
+ HashPrefix* hash_prefix) {
+ if (full_hash.size() < prefix_size) {
+ return false;
+ }
+ *hash_prefix = full_hash.substr(prefix_size);
+ return true;
+}
+
+// static
+bool V4ProtocolManagerUtil::FullHashToSmallestHashPrefix(
+ const FullHash& full_hash,
+ HashPrefix* hash_prefix) {
+ return FullHashToHashPrefix(full_hash, kMinHashPrefixLength, hash_prefix);
+}
+
+// static
+bool V4ProtocolManagerUtil::FullHashMatchesHashPrefix(
+ const FullHash& full_hash,
+ const HashPrefix& hash_prefix) {
+ return full_hash.compare(0, hash_prefix.length(), hash_prefix) == 0;
+}
+
+// static
+void V4ProtocolManagerUtil::GenerateHostsToCheck(
+ const GURL& url,
+ std::vector<std::string>* hosts) {
+ std::string canon_host;
+ CanonicalizeUrl(url, &canon_host, NULL, NULL);
+ GenerateHostVariantsToCheck(canon_host, hosts);
+}
+
+// static
+void V4ProtocolManagerUtil::GeneratePathsToCheck(
+ const GURL& url,
+ std::vector<std::string>* paths) {
+ std::string canon_path;
+ std::string canon_query;
+ CanonicalizeUrl(url, NULL, &canon_path, &canon_query);
+ GeneratePathVariantsToCheck(canon_path, canon_query, paths);
+}
+
+// static
+void V4ProtocolManagerUtil::GeneratePatternsToCheck(
+ const GURL& url,
+ std::vector<std::string>* urls) {
+ std::string canon_host;
+ std::string canon_path;
+ std::string canon_query;
+ CanonicalizeUrl(url, &canon_host, &canon_path, &canon_query);
+
+ std::vector<std::string> hosts, paths;
+ GenerateHostVariantsToCheck(canon_host, &hosts);
+ GeneratePathVariantsToCheck(canon_path, canon_query, &paths);
+ for (size_t h = 0; h < hosts.size(); ++h) {
+ for (size_t p = 0; p < paths.size(); ++p) {
+ urls->push_back(hosts[h] + paths[p]);
+ }
+ }
+}
+
+// static
+void V4ProtocolManagerUtil::CanonicalizeUrl(const GURL& url,
+ std::string* canonicalized_hostname,
+ std::string* canonicalized_path,
+ std::string* canonicalized_query) {
+ DCHECK(url.is_valid());
+
+ // We only canonicalize "normal" URLs.
+ if (!url.IsStandard())
+ return;
+
+ // Following canonicalization steps are excluded since url parsing takes care
+ // of those :-
+ // 1. Remove any tab (0x09), CR (0x0d), and LF (0x0a) chars from url.
+ // (Exclude escaped version of these chars).
+ // 2. Normalize hostname to 4 dot-seperated decimal values.
+ // 3. Lowercase hostname.
+ // 4. Resolve path sequences "/../" and "/./".
+
+ // That leaves us with the following :-
+ // 1. Remove fragment in URL.
+ GURL url_without_fragment;
+ GURL::Replacements f_replacements;
+ f_replacements.ClearRef();
+ f_replacements.ClearUsername();
+ f_replacements.ClearPassword();
+ url_without_fragment = url.ReplaceComponents(f_replacements);
+
+ // 2. Do URL unescaping until no more hex encoded characters exist.
+ std::string url_unescaped_str(Unescape(url_without_fragment.spec()));
+ url::Parsed parsed;
+ url::ParseStandardURL(url_unescaped_str.data(), url_unescaped_str.length(),
+ &parsed);
+
+ // 3. In hostname, remove all leading and trailing dots.
+ base::StringPiece host;
+ if (parsed.host.len > 0)
+ host.set(url_unescaped_str.data() + parsed.host.begin, parsed.host.len);
+
+ base::StringPiece host_without_end_dots =
+ base::TrimString(host, ".", base::TrimPositions::TRIM_ALL);
+
+ // 4. In hostname, replace consecutive dots with a single dot.
+ std::string host_without_consecutive_dots(
+ RemoveConsecutiveChars(host_without_end_dots, '.'));
+
+ // 5. In path, replace runs of consecutive slashes with a single slash.
+ base::StringPiece path;
+ if (parsed.path.len > 0)
+ path.set(url_unescaped_str.data() + parsed.path.begin, parsed.path.len);
+ std::string path_without_consecutive_slash(RemoveConsecutiveChars(path, '/'));
+
+ url::Replacements<char> hp_replacements;
+ hp_replacements.SetHost(
+ host_without_consecutive_dots.data(),
+ url::Component(0, host_without_consecutive_dots.length()));
+ hp_replacements.SetPath(
+ path_without_consecutive_slash.data(),
+ url::Component(0, path_without_consecutive_slash.length()));
+
+ std::string url_unescaped_with_can_hostpath;
+ url::StdStringCanonOutput output(&url_unescaped_with_can_hostpath);
+ url::Parsed temp_parsed;
+ url::ReplaceComponents(url_unescaped_str.data(), url_unescaped_str.length(),
+ parsed, hp_replacements, NULL, &output, &temp_parsed);
+ output.Complete();
+
+ // 6. Step needed to revert escaping done in url::ReplaceComponents.
+ url_unescaped_with_can_hostpath = Unescape(url_unescaped_with_can_hostpath);
+
+ // 7. After performing all above steps, percent-escape all chars in url which
+ // are <= ASCII 32, >= 127, #, %. Escapes must be uppercase hex characters.
+ std::string escaped_canon_url_str(Escape(url_unescaped_with_can_hostpath));
+ url::Parsed final_parsed;
+ url::ParseStandardURL(escaped_canon_url_str.data(),
+ escaped_canon_url_str.length(), &final_parsed);
+
+ if (canonicalized_hostname && final_parsed.host.len > 0) {
+ *canonicalized_hostname = escaped_canon_url_str.substr(
+ final_parsed.host.begin, final_parsed.host.len);
+ }
+ if (canonicalized_path && final_parsed.path.len > 0) {
+ *canonicalized_path = escaped_canon_url_str.substr(final_parsed.path.begin,
+ final_parsed.path.len);
+ }
+ if (canonicalized_query && final_parsed.query.len > 0) {
+ *canonicalized_query = escaped_canon_url_str.substr(
+ final_parsed.query.begin, final_parsed.query.len);
+ }
+}
+
+// static
+std::string V4ProtocolManagerUtil::RemoveConsecutiveChars(base::StringPiece str,
+ const char c) {
+ std::string output;
+ // Output is at most the length of the original string.
+ output.reserve(str.size());
+
+ size_t i = 0;
+ while (i < str.size()) {
+ output.append(1, str[i++]);
+ if (str[i - 1] == c) {
+ while (i < str.size() && str[i] == c) {
+ i++;
+ }
+ }
+ }
+
+ return output;
+}
+
+// static
+void V4ProtocolManagerUtil::GenerateHostVariantsToCheck(
+ const std::string& host,
+ std::vector<std::string>* hosts) {
+ hosts->clear();
+
+ if (host.empty())
+ return;
+
+ // Per the Safe Browsing Protocol v2 spec, we try the host, and also up to 4
+ // hostnames formed by starting with the last 5 components and successively
+ // removing the leading component. The last component isn't examined alone,
+ // since it's the TLD or a subcomponent thereof.
+ //
+ // Note that we don't need to be clever about stopping at the "real" eTLD --
+ // the data on the server side has been filtered to ensure it will not
+ // blacklist a whole TLD, and it's not significantly slower on our side to
+ // just check too much.
+ //
+ // Also note that because we have a simple blacklist, not some sort of complex
+ // whitelist-in-blacklist or vice versa, it doesn't matter what order we check
+ // these in.
+ const size_t kMaxHostsToCheck = 4;
+ bool skipped_last_component = false;
+ for (std::string::const_reverse_iterator i(host.rbegin());
+ i != host.rend() && hosts->size() < kMaxHostsToCheck; ++i) {
+ if (*i == '.') {
+ if (skipped_last_component)
+ hosts->push_back(std::string(i.base(), host.end()));
+ else
+ skipped_last_component = true;
+ }
+ }
+ hosts->push_back(host);
+}
+
+// static
+void V4ProtocolManagerUtil::GeneratePathVariantsToCheck(
+ const std::string& path,
+ const std::string& query,
+ std::vector<std::string>* paths) {
+ paths->clear();
+
+ if (path.empty())
+ return;
+
+ // Per the Safe Browsing Protocol v2 spec, we try the exact path with/without
+ // the query parameters, and also up to 4 paths formed by starting at the root
+ // and adding more path components.
+ //
+ // As with the hosts above, it doesn't matter what order we check these in.
+ const size_t kMaxPathsToCheck = 4;
+ for (std::string::const_iterator i(path.begin());
+ i != path.end() && paths->size() < kMaxPathsToCheck; ++i) {
+ if (*i == '/')
+ paths->push_back(std::string(path.begin(), i + 1));
+ }
+
+ if (!paths->empty() && paths->back() != path)
+ paths->push_back(path);
+
+ if (!query.empty())
+ paths->push_back(path + "?" + query);
+}
+
+// static
+void V4ProtocolManagerUtil::SetClientInfoFromConfig(
+ ClientInfo* client_info,
+ const V4ProtocolConfig& config) {
+ DCHECK(client_info);
+ client_info->set_client_id(config.client_name);
+ client_info->set_client_version(config.version);
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_protocol_manager_util.h b/chromium/components/safe_browsing_db/v4_protocol_manager_util.h
index 6b81e8b5c0b..34e24125d7e 100644
--- a/chromium/components/safe_browsing_db/v4_protocol_manager_util.h
+++ b/chromium/components/safe_browsing_db/v4_protocol_manager_util.h
@@ -13,6 +13,7 @@
#include "base/gtest_prod_util.h"
#include "base/hash.h"
+#include "base/strings/string_piece.h"
#include "components/safe_browsing_db/safebrowsing.pb.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"
@@ -23,6 +24,23 @@ class HttpRequestHeaders;
namespace safe_browsing {
+// The size of the hash prefix, in bytes. It should be between 4 to 32 (full
+// hash).
+typedef size_t PrefixSize;
+
+// The minimum expected size (in bytes) of a hash-prefix.
+const PrefixSize kMinHashPrefixLength = 4;
+
+// The maximum expected size (in bytes) of a hash-prefix. This represents the
+// length of a SHA256 hash.
+const PrefixSize kMaxHashPrefixLength = 32;
+
+// A hash prefix sent by the SafeBrowsing PVer4 service.
+typedef std::string HashPrefix;
+
+// A full SHA256 hash.
+typedef HashPrefix FullHash;
+
typedef FetchThreatListUpdatesRequest::ListUpdateRequest ListUpdateRequest;
typedef FetchThreatListUpdatesResponse::ListUpdateResponse ListUpdateResponse;
@@ -45,46 +63,105 @@ struct V4ProtocolConfig {
~V4ProtocolConfig();
};
+// Different types of threats that SafeBrowsing protects against. This is the
+// type that's returned to the clients of SafeBrowsing in Chromium.
+enum SBThreatType {
+ // No threat at all.
+ SB_THREAT_TYPE_SAFE,
+
+ // The URL is being used for phishing.
+ SB_THREAT_TYPE_URL_PHISHING,
+
+ // The URL hosts malware.
+ SB_THREAT_TYPE_URL_MALWARE,
+
+ // The URL hosts unwanted programs.
+ SB_THREAT_TYPE_URL_UNWANTED,
+
+ // The download URL is malware.
+ SB_THREAT_TYPE_BINARY_MALWARE_URL,
+
+ // Url detected by the client-side phishing model. Note that unlike the
+ // above values, this does not correspond to a downloaded list.
+ SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL,
+
+ // The Chrome extension or app (given by its ID) is malware.
+ SB_THREAT_TYPE_EXTENSION,
+
+ // Url detected by the client-side malware IP list. This IP list is part
+ // of the client side detection model.
+ SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL,
+
+ // Url leads to a blacklisted resource script. Note that no warnings should be
+ // shown on this threat type, but an incident report might be sent.
+ SB_THREAT_TYPE_BLACKLISTED_RESOURCE,
+
+ // Url abuses a permission API.
+ SB_THREAT_TYPE_API_ABUSE,
+};
+
// The information required to uniquely identify each list the client is
// interested in maintaining and downloading from the SafeBrowsing servers.
// For example, for digests of Malware binaries on Windows:
// platform_type = WINDOWS,
// threat_entry_type = EXECUTABLE,
// threat_type = MALWARE
-struct UpdateListIdentifier {
+struct ListIdentifier {
public:
- PlatformType platform_type;
- ThreatEntryType threat_entry_type;
- ThreatType threat_type;
-
- UpdateListIdentifier(PlatformType, ThreatEntryType, ThreatType);
- explicit UpdateListIdentifier(const ListUpdateResponse&);
+ ListIdentifier(PlatformType, ThreatEntryType, ThreatType);
+ explicit ListIdentifier(const ListUpdateResponse&);
- bool operator==(const UpdateListIdentifier& other) const;
- bool operator!=(const UpdateListIdentifier& other) const;
+ bool operator==(const ListIdentifier& other) const;
+ bool operator!=(const ListIdentifier& other) const;
size_t hash() const;
+ PlatformType platform_type() const { return platform_type_; }
+ ThreatEntryType threat_entry_type() const { return threat_entry_type_; }
+ ThreatType threat_type() const { return threat_type_; }
+
private:
- UpdateListIdentifier();
+ PlatformType platform_type_;
+ ThreatEntryType threat_entry_type_;
+ ThreatType threat_type_;
+
+ ListIdentifier();
};
-std::ostream& operator<<(std::ostream& os, const UpdateListIdentifier& id);
+std::ostream& operator<<(std::ostream& os, const ListIdentifier& id);
-// The set of interesting lists and ASCII filenames for their hash prefix
-// stores. The stores are created inside the user-data directory.
-// For instance, the UpdateListIdentifier could be for URL expressions for UwS
-// on Windows platform, and the corresponding file on disk could be named:
-// "uws_win_url.store"
-// TODO(vakh): Find the canonical place where these are defined and update the
-// comment to point to that place.
-typedef base::hash_map<UpdateListIdentifier, std::string> StoreFileNameMap;
+PlatformType GetCurrentPlatformType();
+const ListIdentifier GetChromeUrlApiId();
+const ListIdentifier GetUrlMalwareId();
+const ListIdentifier GetUrlSocEngId();
// Represents the state of each store.
-typedef base::hash_map<UpdateListIdentifier, std::string> StoreStateMap;
+typedef base::hash_map<ListIdentifier, std::string> StoreStateMap;
// Sever response, parsed in vector form.
typedef std::vector<std::unique_ptr<ListUpdateResponse>> ParsedServerResponse;
+// TODO(vakh): Consider using a std::pair for this.
+// Holds the hash prefix and the store that it matched in.
+struct StoreAndHashPrefix {
+ public:
+ ListIdentifier list_id;
+ HashPrefix hash_prefix;
+
+ explicit StoreAndHashPrefix(ListIdentifier, HashPrefix);
+ ~StoreAndHashPrefix();
+
+ bool operator==(const StoreAndHashPrefix& other) const;
+ bool operator!=(const StoreAndHashPrefix& other) const;
+ size_t hash() const;
+
+ private:
+ StoreAndHashPrefix();
+};
+
+// Used to track the hash prefix and the store in which a full hash's prefix
+// matched.
+typedef std::vector<StoreAndHashPrefix> StoreAndHashPrefixes;
+
// Enumerate failures for histogramming purposes. DO NOT CHANGE THE
// ORDERING OF THESE VALUES.
enum V4OperationResult {
@@ -117,14 +194,29 @@ enum V4OperationResult {
// A class that provides static methods related to the Pver4 protocol.
class V4ProtocolManagerUtil {
public:
- // Record HTTP response code when there's no error in fetching an HTTP
- // request, and the error code, when there is.
- // |metric_name| is the name of the UMA metric to record the response code or
- // error code against, |status| represents the status of the HTTP request, and
- // |response code| represents the HTTP response code received from the server.
- static void RecordHttpResponseOrErrorCode(const char* metric_name,
- const net::URLRequestStatus& status,
- int response_code);
+ // Canonicalizes url as per Google Safe Browsing Specification.
+ // See: https://developers.google.com/safe-browsing/v4/urls-hashing
+ static void CanonicalizeUrl(const GURL& url,
+ std::string* canonicalized_hostname,
+ std::string* canonicalized_path,
+ std::string* canonicalized_query);
+
+ // This method returns the host suffix combinations from the hostname in the
+ // URL, as described here:
+ // https://developers.google.com/safe-browsing/v4/urls-hashing
+ static void GenerateHostVariantsToCheck(const std::string& host,
+ std::vector<std::string>* hosts);
+
+ // This method returns the path prefix combinations from the path in the
+ // URL, as described here:
+ // https://developers.google.com/safe-browsing/v4/urls-hashing
+ static void GeneratePathVariantsToCheck(const std::string& path,
+ const std::string& query,
+ std::vector<std::string>* paths);
+
+ // Given a URL, returns all the patterns we need to check.
+ static void GeneratePatternsToCheck(const GURL& url,
+ std::vector<std::string>* urls);
// Generates a Pver4 request URL and sets the appropriate header values.
// |request_base64| is the serialized request protocol buffer encoded in
@@ -145,12 +237,39 @@ class V4ProtocolManagerUtil {
static base::TimeDelta GetNextBackOffInterval(size_t* error_count,
size_t* multiplier);
+ // Record HTTP response code when there's no error in fetching an HTTP
+ // request, and the error code, when there is.
+ // |metric_name| is the name of the UMA metric to record the response code or
+ // error code against, |status| represents the status of the HTTP request, and
+ // |response code| represents the HTTP response code received from the server.
+ static void RecordHttpResponseOrErrorCode(const char* metric_name,
+ const net::URLRequestStatus& status,
+ int response_code);
+
+ // Generate the set of FullHashes to check for |url|.
+ static void UrlToFullHashes(const GURL& url,
+ std::unordered_set<FullHash>* full_hashes);
+
+ static bool FullHashToHashPrefix(const FullHash& full_hash,
+ PrefixSize prefix_size,
+ HashPrefix* hash_prefix);
+
+ static bool FullHashToSmallestHashPrefix(const FullHash& full_hash,
+ HashPrefix* hash_prefix);
+
+ static bool FullHashMatchesHashPrefix(const FullHash& full_hash,
+ const HashPrefix& hash_prefix);
+
+ static void SetClientInfoFromConfig(ClientInfo* client_info,
+ const V4ProtocolConfig& config);
+
private:
V4ProtocolManagerUtil(){};
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4ProtocolManagerUtilTest,
- TestBackOffLogic);
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4ProtocolManagerUtilTest,
+ FRIEND_TEST_ALL_PREFIXES(V4ProtocolManagerUtilTest, TestBackOffLogic);
+ FRIEND_TEST_ALL_PREFIXES(V4ProtocolManagerUtilTest,
TestGetRequestUrlAndUpdateHeaders);
+ FRIEND_TEST_ALL_PREFIXES(V4ProtocolManagerUtilTest, UrlParsing);
+ FRIEND_TEST_ALL_PREFIXES(V4ProtocolManagerUtilTest, CanonicalizeUrl);
// Composes a URL using |prefix|, |method| (e.g.: encodedFullHashes).
// |request_base64|, |client_id|, |version| and |key_param|. |prefix|
@@ -163,16 +282,51 @@ class V4ProtocolManagerUtil {
// Sets the HTTP headers expected by a standard PVer4 request.
static void UpdateHeaders(net::HttpRequestHeaders* headers);
+ // Given a URL, returns all the hosts we need to check. They are returned
+ // in order of size (i.e. b.c is first, then a.b.c).
+ static void GenerateHostsToCheck(const GURL& url,
+ std::vector<std::string>* hosts);
+
+ // Given a URL, returns all the paths we need to check.
+ static void GeneratePathsToCheck(const GURL& url,
+ std::vector<std::string>* paths);
+
+ static std::string RemoveConsecutiveChars(base::StringPiece str,
+ const char c);
+
DISALLOW_COPY_AND_ASSIGN(V4ProtocolManagerUtil);
};
+typedef std::unordered_set<ListIdentifier> StoresToCheck;
+
} // namespace safe_browsing
namespace std {
template <>
-struct hash<safe_browsing::UpdateListIdentifier> {
- std::size_t operator()(const safe_browsing::UpdateListIdentifier& s) const {
- return s.hash();
+struct hash<safe_browsing::PlatformType> {
+ std::size_t operator()(const safe_browsing::PlatformType& p) const {
+ return std::hash<unsigned int>()(p);
+ }
+};
+
+template <>
+struct hash<safe_browsing::ThreatEntryType> {
+ std::size_t operator()(const safe_browsing::ThreatEntryType& tet) const {
+ return std::hash<unsigned int>()(tet);
+ }
+};
+
+template <>
+struct hash<safe_browsing::ThreatType> {
+ std::size_t operator()(const safe_browsing::ThreatType& tt) const {
+ return std::hash<unsigned int>()(tt);
+ }
+};
+
+template <>
+struct hash<safe_browsing::ListIdentifier> {
+ std::size_t operator()(const safe_browsing::ListIdentifier& id) const {
+ return id.hash();
}
};
}
diff --git a/chromium/components/safe_browsing_db/v4_protocol_manager_util_unittest.cc b/chromium/components/safe_browsing_db/v4_protocol_manager_util_unittest.cc
index f118c7f5950..20e808576bd 100644
--- a/chromium/components/safe_browsing_db/v4_protocol_manager_util_unittest.cc
+++ b/chromium/components/safe_browsing_db/v4_protocol_manager_util_unittest.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/base64.h"
+#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "net/base/escape.h"
#include "net/http/http_request_headers.h"
@@ -21,11 +22,16 @@ const char kClient[] = "unittest";
const char kAppVer[] = "1.0";
const char kKeyParam[] = "test_key_param";
+bool VectorContains(const std::vector<std::string>& data,
+ const std::string& str) {
+ return std::find(data.begin(), data.end(), str) != data.end();
+}
+
} // namespace
namespace safe_browsing {
-class SafeBrowsingV4ProtocolManagerUtilTest : public testing::Test {
+class V4ProtocolManagerUtilTest : public testing::Test {
protected:
void PopulateV4ProtocolConfig(V4ProtocolConfig* config) {
config->client_name = kClient;
@@ -34,7 +40,7 @@ class SafeBrowsingV4ProtocolManagerUtilTest : public testing::Test {
}
};
-TEST_F(SafeBrowsingV4ProtocolManagerUtilTest, TestBackOffLogic) {
+TEST_F(V4ProtocolManagerUtilTest, TestBackOffLogic) {
size_t error_count = 0, back_off_multiplier = 1;
// 1 error.
@@ -108,8 +114,7 @@ TEST_F(SafeBrowsingV4ProtocolManagerUtilTest, TestBackOffLogic) {
EXPECT_EQ(TimeDelta::FromHours(24), next);
}
-TEST_F(SafeBrowsingV4ProtocolManagerUtilTest,
- TestGetRequestUrlAndUpdateHeaders) {
+TEST_F(V4ProtocolManagerUtilTest, TestGetRequestUrlAndUpdateHeaders) {
V4ProtocolConfig config;
PopulateV4ProtocolConfig(&config);
@@ -126,4 +131,122 @@ TEST_F(SafeBrowsingV4ProtocolManagerUtilTest,
EXPECT_EQ("POST", header_value);
}
+// Tests that we generate the required host/path combinations for testing
+// according to the Safe Browsing spec.
+// See: https://developers.google.com/safe-browsing/v4/urls-hashing
+TEST_F(V4ProtocolManagerUtilTest, UrlParsing) {
+ std::vector<std::string> hosts, paths;
+
+ GURL url("http://a.b.c/1/2.html?param=1");
+ V4ProtocolManagerUtil::GenerateHostsToCheck(url, &hosts);
+ V4ProtocolManagerUtil::GeneratePathsToCheck(url, &paths);
+ EXPECT_EQ(hosts.size(), static_cast<size_t>(2));
+ EXPECT_EQ(paths.size(), static_cast<size_t>(4));
+ EXPECT_EQ(hosts[0], "b.c");
+ EXPECT_EQ(hosts[1], "a.b.c");
+
+ EXPECT_TRUE(VectorContains(paths, "/1/2.html?param=1"));
+ EXPECT_TRUE(VectorContains(paths, "/1/2.html"));
+ EXPECT_TRUE(VectorContains(paths, "/1/"));
+ EXPECT_TRUE(VectorContains(paths, "/"));
+
+ url = GURL("http://a.b.c.d.e.f.g/1.html");
+ V4ProtocolManagerUtil::GenerateHostsToCheck(url, &hosts);
+ V4ProtocolManagerUtil::GeneratePathsToCheck(url, &paths);
+ EXPECT_EQ(hosts.size(), static_cast<size_t>(5));
+ EXPECT_EQ(paths.size(), static_cast<size_t>(2));
+ EXPECT_EQ(hosts[0], "f.g");
+ EXPECT_EQ(hosts[1], "e.f.g");
+ EXPECT_EQ(hosts[2], "d.e.f.g");
+ EXPECT_EQ(hosts[3], "c.d.e.f.g");
+ EXPECT_EQ(hosts[4], "a.b.c.d.e.f.g");
+ EXPECT_TRUE(VectorContains(paths, "/1.html"));
+ EXPECT_TRUE(VectorContains(paths, "/"));
+
+ url = GURL("http://a.b/saw-cgi/eBayISAPI.dll/");
+ V4ProtocolManagerUtil::GeneratePathsToCheck(url, &paths);
+ EXPECT_EQ(paths.size(), static_cast<size_t>(3));
+ EXPECT_TRUE(VectorContains(paths, "/saw-cgi/eBayISAPI.dll/"));
+ EXPECT_TRUE(VectorContains(paths, "/saw-cgi/"));
+ EXPECT_TRUE(VectorContains(paths, "/"));
+}
+
+// Tests the url canonicalization according to the Safe Browsing spec.
+// See: https://developers.google.com/safe-browsing/v4/urls-hashing
+TEST_F(V4ProtocolManagerUtilTest, CanonicalizeUrl) {
+ struct {
+ const char* input_url;
+ const char* expected_canonicalized_hostname;
+ const char* expected_canonicalized_path;
+ const char* expected_canonicalized_query;
+ } tests[] = {
+ {"http://host/%25%32%35", "host", "/%25", ""},
+ {"http://host/%25%32%35%25%32%35", "host", "/%25%25", ""},
+ {"http://host/%2525252525252525", "host", "/%25", ""},
+ {"http://host/asdf%25%32%35asd", "host", "/asdf%25asd", ""},
+ {"http://host/%%%25%32%35asd%%", "host", "/%25%25%25asd%25%25", ""},
+ {"http://host/%%%25%32%35asd%%", "host", "/%25%25%25asd%25%25", ""},
+ {"http://www.google.com/", "www.google.com", "/", ""},
+ {"http://%31%36%38%2e%31%38%38%2e%39%39%2e%32%36/%2E%73%65%63%75%72%65/"
+ "%77"
+ "%77%77%2E%65%62%61%79%2E%63%6F%6D/",
+ "168.188.99.26", "/.secure/www.ebay.com/", ""},
+ {"http://195.127.0.11/uploads/%20%20%20%20/.verify/"
+ ".eBaysecure=updateuserd"
+ "ataxplimnbqmn-xplmvalidateinfoswqpcmlx=hgplmcx/",
+ "195.127.0.11",
+ "/uploads/%20%20%20%20/.verify/"
+ ".eBaysecure=updateuserdataxplimnbqmn-xplmv"
+ "alidateinfoswqpcmlx=hgplmcx/",
+ ""},
+ {"http://host.com/%257Ea%2521b%2540c%2523d%2524e%25f%255E00%252611%252A"
+ "22%252833%252944_55%252B",
+ "host.com", "/~a!b@c%23d$e%25f^00&11*22(33)44_55+", ""},
+ {"http://3279880203/blah", "195.127.0.11", "/blah", ""},
+ {"http://www.google.com/blah/..", "www.google.com", "/", ""},
+ {"http://www.google.com/blah#fraq", "www.google.com", "/blah", ""},
+ {"http://www.GOOgle.com/", "www.google.com", "/", ""},
+ {"http://www.google.com.../", "www.google.com", "/", ""},
+ {"http://www.google.com/q?", "www.google.com", "/q", ""},
+ {"http://www.google.com/q?r?", "www.google.com", "/q", "r?"},
+ {"http://www.google.com/q?r?s", "www.google.com", "/q", "r?s"},
+ {"http://evil.com/foo#bar#baz", "evil.com", "/foo", ""},
+ {"http://evil.com/foo;", "evil.com", "/foo;", ""},
+ {"http://evil.com/foo?bar;", "evil.com", "/foo", "bar;"},
+ {"http://notrailingslash.com", "notrailingslash.com", "/", ""},
+ {"http://www.gotaport.com:1234/", "www.gotaport.com", "/", ""},
+ {" http://www.google.com/ ", "www.google.com", "/", ""},
+ {"http:// leadingspace.com/", "%20leadingspace.com", "/", ""},
+ {"http://%20leadingspace.com/", "%20leadingspace.com", "/", ""},
+ {"https://www.securesite.com/", "www.securesite.com", "/", ""},
+ {"http://host.com/ab%23cd", "host.com", "/ab%23cd", ""},
+ {"http://host%3e.com//twoslashes?more//slashes", "host>.com",
+ "/twoslashes", "more//slashes"},
+ {"http://host.com/abc?val=xyz#anything", "host.com", "/abc", "val=xyz"},
+ {"http://abc:def@host.com/xyz", "host.com", "/xyz", ""},
+ {"http://host%3e.com/abc/%2e%2e%2fdef", "host>.com", "/def", ""},
+ {"http://.......host...com.....//abc/////def%2F%2F%2Fxyz", "host.com",
+ "/abc/def/xyz", ""},
+ {"ftp://host.com/foo?bar", "host.com", "/foo", "bar"},
+ {"data:text/html;charset=utf-8,%0D%0A", "", "", ""},
+ {"javascript:alert()", "", "", ""},
+ {"mailto:abc@example.com", "", "", ""},
+ };
+ for (size_t i = 0; i < arraysize(tests); ++i) {
+ SCOPED_TRACE(base::StringPrintf("Test: %s", tests[i].input_url));
+ GURL url(tests[i].input_url);
+
+ std::string canonicalized_hostname;
+ std::string canonicalized_path;
+ std::string canonicalized_query;
+ V4ProtocolManagerUtil::CanonicalizeUrl(url, &canonicalized_hostname,
+ &canonicalized_path,
+ &canonicalized_query);
+
+ EXPECT_EQ(tests[i].expected_canonicalized_hostname, canonicalized_hostname);
+ EXPECT_EQ(tests[i].expected_canonicalized_path, canonicalized_path);
+ EXPECT_EQ(tests[i].expected_canonicalized_query, canonicalized_query);
+ }
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_rice.cc b/chromium/components/safe_browsing_db/v4_rice.cc
new file mode 100644
index 00000000000..c8376ae97fa
--- /dev/null
+++ b/chromium/components/safe_browsing_db/v4_rice.cc
@@ -0,0 +1,296 @@
+// 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 <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+#include "components/safe_browsing_db/v4_rice.h"
+
+#if defined(OS_WIN)
+#include <winsock2.h>
+#elif defined(OS_POSIX)
+#include <arpa/inet.h>
+#endif
+
+using ::google::protobuf::RepeatedField;
+using ::google::protobuf::int32;
+using ::google::protobuf::int64;
+
+#if !defined(ARCH_CPU_LITTLE_ENDIAN) || (ARCH_CPU_LITTLE_ENDIAN != 1)
+#error The code below assumes little-endianness.
+#endif
+
+namespace safe_browsing {
+
+namespace {
+
+const int kBitsPerByte = 8;
+const unsigned int kMaxBitIndex = kBitsPerByte * sizeof(uint32_t);
+
+} // namespace
+
+// static
+V4DecodeResult V4RiceDecoder::ValidateInput(const int32 rice_parameter,
+ const int32 num_entries,
+ const std::string& encoded_data) {
+ if (num_entries < 0) {
+ NOTREACHED();
+ return NUM_ENTRIES_NEGATIVE_FAILURE;
+ }
+
+ if (num_entries == 0) {
+ return DECODE_SUCCESS;
+ }
+
+ if (rice_parameter <= 0) {
+ NOTREACHED();
+ return RICE_PARAMETER_NON_POSITIVE_FAILURE;
+ }
+
+ if (encoded_data.empty()) {
+ NOTREACHED();
+ return ENCODED_DATA_UNEXPECTED_EMPTY_FAILURE;
+ }
+
+ return DECODE_SUCCESS;
+}
+
+// static
+V4DecodeResult V4RiceDecoder::DecodeIntegers(const int64 first_value,
+ const int32 rice_parameter,
+ const int32 num_entries,
+ const std::string& encoded_data,
+ RepeatedField<int32>* out) {
+ DCHECK(out);
+
+ V4DecodeResult result =
+ ValidateInput(rice_parameter, num_entries, encoded_data);
+ if (result != DECODE_SUCCESS) {
+ return result;
+ }
+
+ out->Reserve(num_entries + 1);
+ base::CheckedNumeric<int32> last_value(first_value);
+ out->Add(last_value.ValueOrDie());
+ if (num_entries == 0) {
+ return DECODE_SUCCESS;
+ }
+
+ V4RiceDecoder decoder(rice_parameter, num_entries, encoded_data);
+ while (decoder.HasAnotherValue()) {
+ uint32_t offset;
+ result = decoder.GetNextValue(&offset);
+ if (result != DECODE_SUCCESS) {
+ return result;
+ }
+
+ last_value += offset;
+ if (!last_value.IsValid()) {
+ NOTREACHED();
+ return DECODED_INTEGER_OVERFLOW_FAILURE;
+ }
+
+ out->Add(last_value.ValueOrDie());
+ }
+
+ return DECODE_SUCCESS;
+}
+
+// static
+V4DecodeResult V4RiceDecoder::DecodePrefixes(const int64 first_value,
+ const int32 rice_parameter,
+ const int32 num_entries,
+ const std::string& encoded_data,
+ std::vector<uint32_t>* out) {
+ DCHECK(out);
+
+ V4DecodeResult result =
+ ValidateInput(rice_parameter, num_entries, encoded_data);
+ if (result != DECODE_SUCCESS) {
+ return result;
+ }
+ out->reserve((num_entries + 1));
+
+ base::CheckedNumeric<uint32_t> last_value(first_value);
+ out->push_back(htonl(last_value.ValueOrDie()));
+
+ if (num_entries > 0) {
+ V4RiceDecoder decoder(rice_parameter, num_entries, encoded_data);
+ while (decoder.HasAnotherValue()) {
+ uint32_t offset;
+ result = decoder.GetNextValue(&offset);
+ if (result != DECODE_SUCCESS) {
+ return result;
+ }
+
+ last_value += offset;
+ if (!last_value.IsValid()) {
+ NOTREACHED();
+ return DECODED_INTEGER_OVERFLOW_FAILURE;
+ }
+
+ // This flipping is done so that the decoded uint32 is interpreted
+ // correcly as a string of 4 bytes.
+ out->push_back(htonl(last_value.ValueOrDie()));
+ }
+ }
+
+ // Flipping the bytes, as done above, destroys the sort order. Sort the
+ // values back.
+ std::sort(out->begin(), out->end());
+
+ // This flipping is done so that when the vector is interpreted as a string,
+ // the bytes are in the correct order.
+ for (size_t i = 0; i < out->size(); i++) {
+ (*out)[i] = ntohl((*out)[i]);
+ }
+
+ return DECODE_SUCCESS;
+}
+
+V4RiceDecoder::V4RiceDecoder(const int rice_parameter,
+ const int num_entries,
+ const std::string& encoded_data)
+ : rice_parameter_(rice_parameter),
+ num_entries_(num_entries),
+ data_(encoded_data),
+ current_word_(0) {
+ DCHECK_LE(0, num_entries_);
+ DCHECK_LE(2u, rice_parameter_);
+ DCHECK_GE(28u, rice_parameter_);
+
+ data_byte_index_ = 0;
+ current_word_bit_index_ = kMaxBitIndex;
+}
+
+V4RiceDecoder::~V4RiceDecoder() {}
+
+bool V4RiceDecoder::HasAnotherValue() const {
+ return num_entries_ > 0;
+}
+
+V4DecodeResult V4RiceDecoder::GetNextValue(uint32_t* value) {
+ if (!HasAnotherValue()) {
+ return DECODE_NO_MORE_ENTRIES_FAILURE;
+ }
+
+ V4DecodeResult result;
+ uint32_t q = 0;
+ uint32_t bit;
+ do {
+ result = GetNextBits(1, &bit);
+ if (result != DECODE_SUCCESS) {
+ return result;
+ }
+ q += bit;
+ } while (bit);
+ uint32_t r = 0;
+ result = GetNextBits(rice_parameter_, &r);
+ if (result != DECODE_SUCCESS) {
+ return result;
+ }
+
+ *value = (q << rice_parameter_) + r;
+ num_entries_--;
+ return DECODE_SUCCESS;
+}
+
+V4DecodeResult V4RiceDecoder::GetNextWord(uint32_t* word) {
+ if (data_byte_index_ >= data_.size()) {
+ return DECODE_RAN_OUT_OF_BITS_FAILURE;
+ }
+
+ const size_t mask = 0xFF;
+ *word = (data_[data_byte_index_] & mask);
+ data_byte_index_++;
+ current_word_bit_index_ = 0;
+
+ if (data_byte_index_ < data_.size()) {
+ *word |= ((data_[data_byte_index_] & mask) << 8);
+ data_byte_index_++;
+
+ if (data_byte_index_ < data_.size()) {
+ *word |= ((data_[data_byte_index_] & mask) << 16);
+ data_byte_index_++;
+
+ if (data_byte_index_ < data_.size()) {
+ *word |= ((data_[data_byte_index_] & mask) << 24);
+ data_byte_index_++;
+ }
+ }
+ }
+
+ return DECODE_SUCCESS;
+}
+
+V4DecodeResult V4RiceDecoder::GetNextBits(unsigned int num_requested_bits,
+ uint32_t* x) {
+ if (num_requested_bits > kMaxBitIndex) {
+ NOTREACHED();
+ return DECODE_REQUESTED_TOO_MANY_BITS_FAILURE;
+ }
+
+ if (current_word_bit_index_ == kMaxBitIndex) {
+ V4DecodeResult result = GetNextWord(&current_word_);
+ if (result != DECODE_SUCCESS) {
+ return result;
+ }
+ }
+
+ unsigned int num_bits_left_in_current_word =
+ kMaxBitIndex - current_word_bit_index_;
+ if (num_bits_left_in_current_word >= num_requested_bits) {
+ // All the bits that we need are in |current_word_|.
+ *x = GetBitsFromCurrentWord(num_requested_bits);
+ } else {
+ // |current_word_| contains fewer bits than we need so read the remaining
+ // bits from |current_word_| into |lower|, and then call GetNextBits on the
+ // remaining number of bits, which will read in a new word into
+ // |current_word_|.
+ uint32_t lower = GetBitsFromCurrentWord(num_bits_left_in_current_word);
+
+ unsigned int num_bits_from_next_word =
+ num_requested_bits - num_bits_left_in_current_word;
+ uint32_t upper;
+ V4DecodeResult result = GetNextBits(num_bits_from_next_word, &upper);
+ if (result != DECODE_SUCCESS) {
+ return result;
+ }
+ *x = (upper << num_bits_left_in_current_word) | lower;
+ }
+ return DECODE_SUCCESS;
+}
+
+uint32_t V4RiceDecoder::GetBitsFromCurrentWord(
+ unsigned int num_requested_bits) {
+ uint32_t mask = 0xFFFFFFFF >> (kMaxBitIndex - num_requested_bits);
+ uint32_t x = current_word_ & mask;
+ current_word_ = current_word_ >> num_requested_bits;
+ current_word_bit_index_ += num_requested_bits;
+ return x;
+};
+
+std::string V4RiceDecoder::DebugString() const {
+ // Calculates the total number of bits that we have read from the buffer,
+ // excluding those that have been read into current_word_ but not yet
+ // consumed byt GetNextBits().
+ unsigned bits_read = (data_byte_index_ - sizeof(uint32_t)) * kBitsPerByte +
+ current_word_bit_index_;
+ return base::StringPrintf(
+ "bits_read: %x; current_word_: %x; data_byte_index_; %x, "
+ "current_word_bit_index_: %x; rice_parameter_: %x",
+ bits_read, current_word_, data_byte_index_, current_word_bit_index_,
+ rice_parameter_);
+}
+
+std::ostream& operator<<(std::ostream& os, const V4RiceDecoder& rice_decoder) {
+ os << rice_decoder.DebugString();
+ return os;
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_rice.h b/chromium/components/safe_browsing_db/v4_rice.h
new file mode 100644
index 00000000000..4f095ca16ee
--- /dev/null
+++ b/chromium/components/safe_browsing_db/v4_rice.h
@@ -0,0 +1,169 @@
+// 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.
+
+// Rice-Golomb decoder for blacklist updates.
+// Details at: https://en.wikipedia.org/wiki/Golomb_coding
+
+#ifndef COMPONENTS_SAFE_BROWSING_DB_V4_RICE_H_
+#define COMPONENTS_SAFE_BROWSING_DB_V4_RICE_H_
+
+#include <ostream>
+#include <string>
+#include <vector>
+#include "base/gtest_prod_util.h"
+
+#if defined(USE_SYSTEM_PROTOBUF)
+#include <google/protobuf/repeated_field.h>
+#else
+#include "third_party/protobuf/src/google/protobuf/repeated_field.h"
+#endif
+
+namespace safe_browsing {
+
+// Enumerate different failure events while decoding the Rice-encoded string
+// sent by the server for histogramming purposes. DO NOT CHANGE THE ORDERING OF
+// THESE VALUES.
+enum V4DecodeResult {
+ // No error.
+ DECODE_SUCCESS = 0,
+
+ // Exceeded the number of entries to expect.
+ DECODE_NO_MORE_ENTRIES_FAILURE = 1,
+
+ // Requested to decode >32 bits.
+ DECODE_REQUESTED_TOO_MANY_BITS_FAILURE = 2,
+
+ // All bits had already been read and interpreted in the encoded string.
+ DECODE_RAN_OUT_OF_BITS_FAILURE = 3,
+
+ // The num_entries argument to DecodePrefixes or DecodeIntegers was negative.
+ NUM_ENTRIES_NEGATIVE_FAILURE = 4,
+
+ // Rice-encoding parameter was non-positive when the number of encoded entries
+ // was > 0.
+ RICE_PARAMETER_NON_POSITIVE_FAILURE = 5,
+
+ // |encoded_data| was empty when the number of encoded entries was > 0.
+ ENCODED_DATA_UNEXPECTED_EMPTY_FAILURE = 6,
+
+ // decoded value had an integer overflow, which is unexpected.
+ DECODED_INTEGER_OVERFLOW_FAILURE = 7,
+
+ // Memory space for histograms is determined by the max. ALWAYS
+ // ADD NEW VALUES BEFORE THIS ONE.
+ DECODE_RESULT_MAX
+};
+
+class V4RiceDecoder {
+ public:
+ // Decodes the Rice-encoded string in |encoded_data| as a list of integers
+ // and stores them in |out|. |rice_parameter| is the exponent of 2 for
+ // calculating 'M', |first_value| is the first value in the output sequence,
+ // |num_entries| is the number of subsequent encoded entries. Each decoded
+ // value is a positive offset from the previous value.
+ // So, for instance, if the unencoded sequence is: [3, 7, 25], then
+ // |first_value| = 3, |num_entries| = 2 and decoding the |encoded_data| will
+ // produce the offsets: [4, 18].
+ static V4DecodeResult DecodeIntegers(
+ const ::google::protobuf::int64 first_value,
+ const ::google::protobuf::int32 rice_parameter,
+ const ::google::protobuf::int32 num_entries,
+ const std::string& encoded_data,
+ ::google::protobuf::RepeatedField<::google::protobuf::int32>* out);
+
+ // Decodes the Rice-encoded string in |encoded_data| as a string of 4-byte
+ // hash prefixes and stores them in |out|. The rest of the arguments are the
+ // same as for |DecodeIntegers|.
+ // Important: |out| is only meant to be used as a concatenated list of sorted
+ // 4-byte hash prefixes, not as a vector of uint32_t values.
+ // This method does the following:
+ // 1. Rice-decode the |encoded_data| as a list of uint32_t values.
+ // 2. Flip the endianness (on little-endian machines) of each of these
+ // values. This is done because when a hash prefix is represented as a
+ // uint32_t, the bytes get reordered. This generates the hash prefix that
+ // the server would have sent in the absence of Rice-encoding.
+ // 3. Sort the resulting list of uint32_t values.
+ // 4. Flip the endianness once again since the uint32_t are expected to be
+ // consumed as a concatenated list of 4-byte hash prefixes, when merging
+ // the
+ // update with the existing state.
+ static V4DecodeResult DecodePrefixes(
+ const ::google::protobuf::int64 first_value,
+ const ::google::protobuf::int32 rice_parameter,
+ const ::google::protobuf::int32 num_entries,
+ const std::string& encoded_data,
+ std::vector<uint32_t>* out);
+
+ virtual ~V4RiceDecoder();
+
+ std::string DebugString() const;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(V4RiceTest, TestDecoderGetNextWordWithNoData);
+ FRIEND_TEST_ALL_PREFIXES(V4RiceTest, TestDecoderGetNextBitsWithNoData);
+ FRIEND_TEST_ALL_PREFIXES(V4RiceTest, TestDecoderGetNextValueWithNoData);
+ FRIEND_TEST_ALL_PREFIXES(V4RiceTest, TestDecoderGetNextValueWithNoEntries);
+ friend class V4RiceTest;
+
+ // Validate some of the parameters passed to the decode methods.
+ static V4DecodeResult ValidateInput(
+ const ::google::protobuf::int32 rice_parameter,
+ const ::google::protobuf::int32 num_entries,
+ const std::string& encoded_data);
+
+ // The |rice_parameter| is the exponent of 2 for calculating 'M',
+ // |num_entries| is the number of encoded entries in the |encoded_data| and
+ // |encoded_data| is the Rice-encoded string to decode.
+ V4RiceDecoder(const ::google::protobuf::int32 rice_parameter,
+ const ::google::protobuf::int32 num_entries,
+ const std::string& encoded_data);
+
+ // Returns true until |num_entries| entries have been decoded.
+ bool HasAnotherValue() const;
+
+ // Populates |value| with the next 32-bit unsigned integer decoded from
+ // |encoded_data|.
+ V4DecodeResult GetNextValue(uint32_t* value);
+
+ // Reads in up to 32 bits from |encoded_data| into |word|, from which
+ // subsequent GetNextBits() calls read bits.
+ V4DecodeResult GetNextWord(uint32_t* word);
+
+ // Reads |num_requested_bits| into |x| from |current_word_| and advances it
+ // if needed by calling GetNextWord().
+ V4DecodeResult GetNextBits(unsigned int num_requested_bits, uint32_t* x);
+
+ // Reads |num_requested_bits| from |current_word_|.
+ uint32_t GetBitsFromCurrentWord(unsigned int num_requested_bits);
+
+ // The Rice parameter, which is the exponent of two for calculating 'M'. 'M'
+ // is used as the base to calculate the quotient and remainder in the
+ // algorithm.
+ const unsigned int rice_parameter_;
+
+ // The number of entries encoded in the data stream.
+ ::google::protobuf::int32 num_entries_;
+
+ // The Rice-encoded string.
+ const std::string data_;
+
+ // Represents how many total bytes have we read from |data_| into
+ // |current_word_|.
+ unsigned int data_byte_index_;
+
+ // Represents the number of bits that we have read from |current_word_|. When
+ // this becomes 32, which is the size of |current_word_|, a new
+ // |current_word_| needs to be read from |data_|.
+ unsigned int current_word_bit_index_;
+
+ // The 32-bit value read from |data_|. All bit reading operations operate on
+ // |current_word_|.
+ uint32_t current_word_;
+};
+
+std::ostream& operator<<(std::ostream& os, const V4RiceDecoder& rice_decoder);
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_DB_V4_RICE_H_
diff --git a/chromium/components/safe_browsing_db/v4_rice_unittest.cc b/chromium/components/safe_browsing_db/v4_rice_unittest.cc
new file mode 100644
index 00000000000..7f97bef6d73
--- /dev/null
+++ b/chromium/components/safe_browsing_db/v4_rice_unittest.cc
@@ -0,0 +1,269 @@
+// 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 "base/logging.h"
+#include "components/safe_browsing_db/v4_rice.h"
+#include "testing/platform_test.h"
+
+using ::google::protobuf::RepeatedField;
+using ::google::protobuf::int32;
+
+namespace safe_browsing {
+
+class V4RiceTest : public PlatformTest {
+ public:
+ V4RiceTest() {}
+
+ struct RiceDecodingTestInfo {
+ uint32_t rice_parameter;
+ std::vector<uint32_t> expected_values;
+ std::string encoded_string;
+
+ RiceDecodingTestInfo(const uint32_t in_rice_parameter,
+ const std::vector<uint32_t>& in_expected_values,
+ const std::string& in_encoded_string) {
+ rice_parameter = in_rice_parameter;
+ expected_values = in_expected_values;
+ encoded_string = in_encoded_string;
+ }
+ };
+
+ void VerifyRiceDecoding(const RiceDecodingTestInfo& test_info) {
+ const uint32_t num_entries = test_info.expected_values.size();
+ V4RiceDecoder decoder(test_info.rice_parameter, num_entries,
+ test_info.encoded_string);
+ uint32_t word;
+ for (const auto& expected : test_info.expected_values) {
+ EXPECT_EQ(DECODE_SUCCESS, decoder.GetNextValue(&word));
+ EXPECT_EQ(expected, word);
+ }
+ ASSERT_FALSE(decoder.HasAnotherValue());
+ }
+};
+
+TEST_F(V4RiceTest, TestDecoderGetNextWordWithNoData) {
+ uint32_t word;
+ V4RiceDecoder decoder(5, 1, "");
+ EXPECT_EQ(DECODE_RAN_OUT_OF_BITS_FAILURE, decoder.GetNextWord(&word));
+}
+
+TEST_F(V4RiceTest, TestDecoderGetNextBitsWithNoData) {
+ uint32_t word;
+ V4RiceDecoder decoder(5, 1, "");
+ EXPECT_EQ(DECODE_RAN_OUT_OF_BITS_FAILURE, decoder.GetNextBits(1, &word));
+}
+
+TEST_F(V4RiceTest, TestDecoderGetNextValueWithNoData) {
+ uint32_t word;
+ V4RiceDecoder decoder(5, 1, "");
+ EXPECT_EQ(DECODE_RAN_OUT_OF_BITS_FAILURE, decoder.GetNextValue(&word));
+}
+
+TEST_F(V4RiceTest, TestDecoderGetNextValueWithNoEntries) {
+ uint32_t word;
+ V4RiceDecoder decoder(28, 0, "\xbf\xa8");
+ ASSERT_FALSE(decoder.HasAnotherValue());
+ EXPECT_EQ(DECODE_NO_MORE_ENTRIES_FAILURE, decoder.GetNextValue(&word));
+}
+
+TEST_F(V4RiceTest, TestDecoderGetNextValueWithInterestingValues) {
+ // These values are interesting because they match the unit test
+ // values used within Google to this test this code in other
+ // components, such as the SafeBrowsing service itself.
+
+ std::vector<RiceDecodingTestInfo> test_inputs = {
+ RiceDecodingTestInfo(2, {15, 9}, "\xf7\x2"),
+ RiceDecodingTestInfo(
+ 28, {1777762129, 2093280223, 924369848},
+ "\xbf\xa8\x3f\xfb\xfc\xfb\x5e\x27\xe6\xc3\x1d\xc6\x38"),
+ RiceDecodingTestInfo(
+ 28, {62763050, 1046523781, 192522171, 1800511020, 4442775, 582142548},
+ "\x54\x60\x7b\xe7\x0a\x5f\xc1\xdc\xee\x69\xde"
+ "\xfe\x58\x3c\xa3\xd6\xa5\xf2\x10\x8c\x4a\x59"
+ "\x56\x00"),
+ RiceDecodingTestInfo(
+ 28, {26067715, 344823336, 8420095, 399843890, 95029378, 731622412,
+ 35811335, 1047558127, 1117722715, 78698892},
+ "\x06\x86\x1b\x23\x14\xcb\x46\xf2\xaf\x07\x08\xc9\x88\x54\x1f\x41\x04"
+ "\xd5\x1a\x03\xeb\xe6\x3a\x80\x13\x91\x7b\xbf\x83\xf3\xb7\x85\xf1\x29"
+ "\x18\xb3\x61\x09"),
+ RiceDecodingTestInfo(
+ 27, {225846818, 328287420, 166748623, 29117720, 552397365, 350353215,
+ 558267528, 4738273, 567093445, 28563065, 55077698, 73091685,
+ 339246010, 98242620, 38060941, 63917830, 206319759, 137700744},
+ "\x89\x98\xd8\x75\xbc\x44\x91\xeb\x39\x0c\x3e\x30\x9a\x78\xf3\x6a\xd4"
+ "\xd9\xb1\x9f\xfb\x70\x3e\x44\x3e\xa3\x08\x67\x42\xc2\x2b\x46\x69\x8e"
+ "\x3c\xeb\xd9\x10\x5a\x43\x9a\x32\xa5\x2d\x4e\x77\x0f\x87\x78\x20\xb6"
+ "\xab\x71\x98\x48\x0c\x9e\x9e\xd7\x23\x0c\x13\x43\x2c\xa9\x01"),
+ RiceDecodingTestInfo(
+ 28, {339784008, 263128563, 63871877, 69723256, 826001074, 797300228,
+ 671166008, 207712688},
+ std::string("\x21\xc5\x02\x91\xf9\x82\xd7\x57\xb8\xe9\x3c\xf0\xc8\x4f"
+ "\xe8\x64\x8d\x77\x62\x04\xd6\x85\x3f\x1c\x97\x00\x04\x1b"
+ "\x17\xc6",
+ 30)),
+ RiceDecodingTestInfo(
+ 28, {471820069, 196333855, 855579133, 122737976, 203433838, 85354544,
+ 1307949392, 165938578, 195134475, 553930435, 49231136},
+ "\x95\x9c\x7d\xb0\x8f\xe8\xd9\xbd\xfe\x8c\x7f\x81\x53\x0d\x75\xdc\x4e"
+ "\x40\x18\x0c\x9a\x45\x3d\xa8\xdc\xfa\x26\x59\x40\x9e\x16\x08\x43\x77"
+ "\xc3\x4e\x04\x01\xa4\xe6\x5d\x00"),
+ RiceDecodingTestInfo(
+ 27, {87336845, 129291033, 30906211, 433549264, 30899891, 53207875,
+ 11959529, 354827862, 82919275, 489637251, 53561020, 336722992,
+ 408117728, 204506246, 188216092, 9047110, 479817359, 230317256},
+ "\x1a\x4f\x69\x2a\x63\x9a\xf6\xc6\x2e\xaf\x73\xd0\x6f\xd7\x31\xeb\x77"
+ "\x1d\x43\xe3\x2b\x93\xce\x67\x8b\x59\xf9\x98\xd4\xda\x4f\x3c\x6f\xb0"
+ "\xe8\xa5\x78\x8d\x62\x36\x18\xfe\x08\x1e\x78\xd8\x14\x32\x24\x84\x61"
+ "\x1c\xf3\x37\x63\xc4\xa0\x88\x7b\x74\xcb\x64\xc8\x5c\xba\x05"),
+ RiceDecodingTestInfo(
+ 28, {297968956, 19709657, 259702329, 76998112, 1023176123, 29296013,
+ 1602741145, 393745181, 177326295, 55225536, 75194472},
+ "\xf1\x94\x0a\x87\x6c\x5f\x96\x90\xe3\xab\xf7\xc0\xcb\x2d\xe9\x76\xdb"
+ "\xf8\x59\x63\xc1\x6f\x7c\x99\xe3\x87\x5f\xc7\x04\xde\xb9\x46\x8e\x54"
+ "\xc0\xac\x4a\x03\x0d\x6c\x8f\x00"),
+ RiceDecodingTestInfo(
+ 28, {532220688, 780594691, 436816483, 163436269, 573044456, 1069604,
+ 39629436, 211410997, 227714491, 381562898, 75610008, 196754597,
+ 40310339, 15204118, 99010842},
+ "\x41\x2c\xe4\xfe\x06\xdc\x0d\xbd\x31\xa5\x04\xd5\x6e\xdd\x9b\x43\xb7"
+ "\x3f\x11\x24\x52\x10\x80\x4f\x96\x4b\xd4\x80\x67\xb2\xdd\x52\xc9\x4e"
+ "\x02\xc6\xd7\x60\xde\x06\x92\x52\x1e\xdd\x35\x64\x71\x26\x2c\xfe\xcf"
+ "\x81\x46\xb2\x79\x01"),
+ RiceDecodingTestInfo(
+ 28, {219354713, 389598618, 750263679, 554684211, 87381124, 4523497,
+ 287633354, 801308671, 424169435, 372520475, 277287849},
+ "\xb2\x2c\x26\x3a\xcd\x66\x9c\xdb\x5f\x07\x2e\x6f\xe6\xf9\x21\x10\x52"
+ "\xd5\x94\xf4\x82\x22\x48\xf9\x9d\x24\xf6\xff\x2f\xfc\x6d\x3f\x21\x65"
+ "\x1b\x36\x34\x56\xea\xc4\x21\x00"),
+ };
+
+ for (size_t i = 0; i < test_inputs.size(); i++) {
+ DVLOG(1) << "Running test case: " << i;
+ VerifyRiceDecoding(test_inputs[i]);
+ }
+}
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+// This test hits a NOTREACHED so it is a release mode only test.
+TEST_F(V4RiceTest, TestDecoderIntegersWithNoData) {
+ RepeatedField<int32> out;
+ EXPECT_EQ(ENCODED_DATA_UNEXPECTED_EMPTY_FAILURE,
+ V4RiceDecoder::DecodeIntegers(3, 5, 1, "", &out));
+}
+#endif
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+// This test hits a NOTREACHED so it is a release mode only test.
+TEST_F(V4RiceTest, TestDecoderIntegersWithNegativeNumEntries) {
+ RepeatedField<int32> out;
+ EXPECT_EQ(NUM_ENTRIES_NEGATIVE_FAILURE,
+ V4RiceDecoder::DecodeIntegers(3, 5, -1, "", &out));
+}
+#endif
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+// This test hits a NOTREACHED so it is a release mode only test.
+TEST_F(V4RiceTest, TestDecoderIntegersWithNonPositiveRiceParameter) {
+ RepeatedField<int32> out;
+ EXPECT_EQ(RICE_PARAMETER_NON_POSITIVE_FAILURE,
+ V4RiceDecoder::DecodeIntegers(3, 0, 1, "a", &out));
+
+ EXPECT_EQ(RICE_PARAMETER_NON_POSITIVE_FAILURE,
+ V4RiceDecoder::DecodeIntegers(3, -1, 1, "a", &out));
+}
+#endif
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+// This test hits a NOTREACHED so it is a release mode only test.
+TEST_F(V4RiceTest, TestDecoderIntegersWithOverflowValues) {
+ RepeatedField<int32> out;
+ EXPECT_EQ(DECODED_INTEGER_OVERFLOW_FAILURE,
+ V4RiceDecoder::DecodeIntegers(
+ 5, 28, 3,
+ "\xbf\xa8\x3f\xfb\xfc\xfb\x5e\x27\xe6\xc3\x1d\xc6\x38", &out));
+}
+#endif
+
+TEST_F(V4RiceTest, TestDecoderIntegersWithOneValue) {
+ RepeatedField<int32> out;
+ EXPECT_EQ(DECODE_SUCCESS, V4RiceDecoder::DecodeIntegers(3, 2, 0, "", &out));
+ EXPECT_EQ(1, out.size());
+ EXPECT_EQ(3, out.Get(0));
+}
+
+TEST_F(V4RiceTest, TestDecoderIntegersWithMultipleValues) {
+ RepeatedField<int32> out;
+ EXPECT_EQ(DECODE_SUCCESS,
+ V4RiceDecoder::DecodeIntegers(5, 2, 2, "\xf7\x2", &out));
+ EXPECT_EQ(3, out.size());
+ EXPECT_EQ(5, out.Get(0));
+ EXPECT_EQ(20, out.Get(1));
+ EXPECT_EQ(29, out.Get(2));
+}
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+// This test hits a NOTREACHED so it is a release mode only test.
+TEST_F(V4RiceTest, TestDecoderPrefixesWithNoData) {
+ std::vector<uint32_t> out;
+ EXPECT_EQ(ENCODED_DATA_UNEXPECTED_EMPTY_FAILURE,
+ V4RiceDecoder::DecodePrefixes(3, 5, 1, "", &out));
+}
+#endif
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+// This test hits a NOTREACHED so it is a release mode only test.
+TEST_F(V4RiceTest, TestDecoderPrefixesWithNegativeNumEntries) {
+ std::vector<uint32_t> out;
+ EXPECT_EQ(NUM_ENTRIES_NEGATIVE_FAILURE,
+ V4RiceDecoder::DecodePrefixes(3, 5, -1, "", &out));
+}
+#endif
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+// This test hits a NOTREACHED so it is a release mode only test.
+TEST_F(V4RiceTest, TestDecoderPrefixesWithNonPositiveRiceParameter) {
+ std::vector<uint32_t> out;
+ EXPECT_EQ(RICE_PARAMETER_NON_POSITIVE_FAILURE,
+ V4RiceDecoder::DecodePrefixes(3, 0, 1, "a", &out));
+
+ EXPECT_EQ(RICE_PARAMETER_NON_POSITIVE_FAILURE,
+ V4RiceDecoder::DecodePrefixes(3, -1, 1, "a", &out));
+}
+#endif
+
+TEST_F(V4RiceTest, TestDecoderPrefixesWithOneValue) {
+ std::vector<uint32_t> out;
+ EXPECT_TRUE(out.empty());
+ EXPECT_EQ(DECODE_SUCCESS,
+ V4RiceDecoder::DecodePrefixes(0x69F67F51u, 2, 0, "", &out));
+ EXPECT_EQ(1u, out.size());
+ EXPECT_EQ(0x69F67F51u, out[0]);
+}
+
+TEST_F(V4RiceTest, TestDecoderPrefixesWithMultipleValues) {
+ std::vector<uint32_t> out;
+ EXPECT_EQ(DECODE_SUCCESS,
+ V4RiceDecoder::DecodePrefixes(
+ 5, 28, 3, "\xbf\xa8\x3f\xfb\xf\xf\x5e\x27\xe6\xc3\x1d\xc6\x38",
+ &out));
+ std::vector<uint32_t> expected = {5, 0xad934c0cu, 0x6ff67f56u, 0x81316fceu};
+ EXPECT_EQ(expected.size(), out.size());
+ for (unsigned i = 0; i < expected.size(); i++) {
+ EXPECT_EQ(expected[i], out[i]);
+ }
+}
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+// This test hits a NOTREACHED so it is a release mode only test.
+TEST_F(V4RiceTest, TestDecoderPrefixesWithOverflowValues) {
+ std::vector<uint32_t> out;
+ EXPECT_EQ(DECODED_INTEGER_OVERFLOW_FAILURE,
+ V4RiceDecoder::DecodePrefixes(
+ 5, 28, 3,
+ "\xbf\xa8\x3f\xfb\xfc\xfb\x5e\x27\xe6\xc3\x1d\xc6\x38", &out));
+}
+#endif
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_store.cc b/chromium/components/safe_browsing_db/v4_store.cc
index 0920f2bf3e9..d00573156ef 100644
--- a/chromium/components/safe_browsing_db/v4_store.cc
+++ b/chromium/components/safe_browsing_db/v4_store.cc
@@ -5,19 +5,120 @@
#include "base/base64.h"
#include "base/bind.h"
#include "base/files/file_util.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
+#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
+#include "components/safe_browsing_db/v4_rice.h"
#include "components/safe_browsing_db/v4_store.h"
#include "components/safe_browsing_db/v4_store.pb.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
+
+using base::TimeTicks;
namespace safe_browsing {
namespace {
+
const uint32_t kFileMagic = 0x600D71FE;
const uint32_t kFileVersion = 9;
+std::string GetUmaSuffixForStore(const base::FilePath& file_path) {
+ return base::StringPrintf(
+ ".%" PRIsFP, file_path.BaseName().RemoveExtension().value().c_str());
+}
+
+void RecordTimeWithAndWithoutStore(const std::string& metric,
+ base::TimeDelta time,
+ const base::FilePath& file_path) {
+ std::string suffix = GetUmaSuffixForStore(file_path);
+
+ // The histograms below are a modified expansion of the
+ // UMA_HISTOGRAM_LONG_TIMES macro adapted to allow for a dynamically suffixed
+ // histogram name.
+ // Note: The factory creates and owns the histogram.
+ const int kBucketCount = 100;
+ base::HistogramBase* histogram = base::Histogram::FactoryTimeGet(
+ metric, base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMinutes(1), kBucketCount,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ if (histogram) {
+ histogram->AddTime(time);
+ }
+
+ base::HistogramBase* histogram_suffix = base::Histogram::FactoryTimeGet(
+ metric + suffix, base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMinutes(1), kBucketCount,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ if (histogram_suffix) {
+ histogram_suffix->AddTime(time);
+ }
+}
+
+void RecordAddUnlumpedHashesTime(base::TimeDelta time) {
+ UMA_HISTOGRAM_LONG_TIMES("SafeBrowsing.V4AddUnlumpedHashesTime", time);
+}
+
+void RecordApplyUpdateResult(ApplyUpdateResult result) {
+ UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4ApplyUpdateResult", result,
+ APPLY_UPDATE_RESULT_MAX);
+}
+
+void RecordApplyUpdateResultWhenReadingFromDisk(ApplyUpdateResult result) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "SafeBrowsing.V4ApplyUpdateResultWhenReadingFromDisk", result,
+ APPLY_UPDATE_RESULT_MAX);
+}
+
+void RecordDecodeAdditionsResult(V4DecodeResult result) {
+ UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4DecodeAdditionsResult", result,
+ DECODE_RESULT_MAX);
+}
+
+void RecordDecodeAdditionsTime(base::TimeDelta time,
+ const base::FilePath& file_path) {
+ RecordTimeWithAndWithoutStore("SafeBrowsing.V4DecodeAdditionsTime", time,
+ file_path);
+}
+
+void RecordDecodeRemovalsResult(V4DecodeResult result) {
+ UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4DecodeRemovalsResult", result,
+ DECODE_RESULT_MAX);
+}
+
+void RecordDecodeRemovalsTime(base::TimeDelta time,
+ const base::FilePath& file_path) {
+ RecordTimeWithAndWithoutStore("SafeBrowsing.V4DecodeRemovalsTime", time,
+ file_path);
+}
+
+void RecordMergeUpdateTime(base::TimeDelta time,
+ const base::FilePath& file_path) {
+ RecordTimeWithAndWithoutStore("SafeBrowsing.V4MergeUpdateTime", time,
+ file_path);
+}
+
+void RecordProcessFullUpdateTime(base::TimeDelta time,
+ const base::FilePath& file_path) {
+ RecordTimeWithAndWithoutStore("SafeBrowsing.V4ProcessFullUpdateTime", time,
+ file_path);
+}
+
+void RecordProcessPartialUpdateTime(base::TimeDelta time,
+ const base::FilePath& file_path) {
+ RecordTimeWithAndWithoutStore("SafeBrowsing.V4ProcessPartialUpdateTime", time,
+ file_path);
+}
+
+void RecordReadFromDiskTime(base::TimeDelta time,
+ const base::FilePath& file_path) {
+ RecordTimeWithAndWithoutStore("SafeBrowsing.V4ReadFromDiskTime", time,
+ file_path);
+}
+
void RecordStoreReadResult(StoreReadResult result) {
UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreReadResult", result,
STORE_READ_RESULT_MAX);
@@ -36,6 +137,10 @@ const base::FilePath TemporaryFileForFilename(const base::FilePath& filename) {
} // namespace
+using ::google::protobuf::RepeatedField;
+using ::google::protobuf::RepeatedPtrField;
+using ::google::protobuf::int32;
+
std::ostream& operator<<(std::ostream& os, const V4Store& store) {
os << store.DebugString();
return os;
@@ -67,8 +172,8 @@ std::string V4Store::DebugString() const {
std::string state_base64;
base::Base64Encode(state_, &state_base64);
- return base::StringPrintf("path: %s; state: %s", store_path_.value().c_str(),
- state_base64.c_str());
+ return base::StringPrintf("path: %" PRIsFP "; state: %s",
+ store_path_.value().c_str(), state_base64.c_str());
}
bool V4Store::Reset() {
@@ -77,33 +182,397 @@ bool V4Store::Reset() {
return true;
}
+ApplyUpdateResult V4Store::ProcessPartialUpdateAndWriteToDisk(
+ const HashPrefixMap& hash_prefix_map_old,
+ std::unique_ptr<ListUpdateResponse> response) {
+ DCHECK(response->has_response_type());
+ DCHECK_EQ(ListUpdateResponse::PARTIAL_UPDATE, response->response_type());
+
+ TimeTicks before = TimeTicks::Now();
+ ApplyUpdateResult result = ProcessUpdate(hash_prefix_map_old, response);
+ if (result == APPLY_UPDATE_SUCCESS) {
+ RecordProcessPartialUpdateTime(TimeTicks::Now() - before, store_path_);
+ // TODO(vakh): Create a ListUpdateResponse containing RICE encoded
+ // hash prefixes and response_type as FULL_UPDATE, and write that to disk.
+ }
+ return result;
+}
+
+ApplyUpdateResult V4Store::ProcessFullUpdateAndWriteToDisk(
+ std::unique_ptr<ListUpdateResponse> response) {
+ TimeTicks before = TimeTicks::Now();
+ ApplyUpdateResult result = ProcessFullUpdate(response);
+ if (result == APPLY_UPDATE_SUCCESS) {
+ RecordStoreWriteResult(WriteToDisk(std::move(response)));
+ RecordProcessFullUpdateTime(TimeTicks::Now() - before, store_path_);
+ }
+ return result;
+}
+
+ApplyUpdateResult V4Store::ProcessFullUpdate(
+ const std::unique_ptr<ListUpdateResponse>& response) {
+ DCHECK(response->has_response_type());
+ DCHECK_EQ(ListUpdateResponse::FULL_UPDATE, response->response_type());
+ // TODO(vakh): For a full update, we don't need to process the update in
+ // lexographical order to store it, but we do need to do that for calculating
+ // checksum. It might save some CPU cycles to store the full update as-is and
+ // walk the list of hash prefixes in lexographical order only for checksum
+ // calculation.
+ return ProcessUpdate(HashPrefixMap(), response);
+}
+
+ApplyUpdateResult V4Store::ProcessUpdate(
+ const HashPrefixMap& hash_prefix_map_old,
+ const std::unique_ptr<ListUpdateResponse>& response) {
+ const RepeatedField<int32>* raw_removals = nullptr;
+ RepeatedField<int32> rice_removals;
+ size_t removals_size = response->removals_size();
+ DCHECK_LE(removals_size, 1u);
+ if (removals_size == 1) {
+ const ThreatEntrySet& removal = response->removals().Get(0);
+ const CompressionType compression_type = removal.compression_type();
+ if (compression_type == RAW) {
+ raw_removals = &removal.raw_indices().indices();
+ } else if (compression_type == RICE) {
+ DCHECK(removal.has_rice_indices());
+
+ const RiceDeltaEncoding& rice_indices = removal.rice_indices();
+ TimeTicks before = TimeTicks::Now();
+ V4DecodeResult decode_result = V4RiceDecoder::DecodeIntegers(
+ rice_indices.first_value(), rice_indices.rice_parameter(),
+ rice_indices.num_entries(), rice_indices.encoded_data(),
+ &rice_removals);
+
+ RecordDecodeRemovalsResult(decode_result);
+ if (decode_result != DECODE_SUCCESS) {
+ return RICE_DECODING_FAILURE;
+ }
+ RecordDecodeRemovalsTime(TimeTicks::Now() - before, store_path_);
+ raw_removals = &rice_removals;
+ } else {
+ NOTREACHED() << "Unexpected compression_type type: " << compression_type;
+ return UNEXPECTED_COMPRESSION_TYPE_REMOVALS_FAILURE;
+ }
+ }
+
+ HashPrefixMap hash_prefix_map;
+ ApplyUpdateResult apply_update_result =
+ UpdateHashPrefixMapFromAdditions(response->additions(), &hash_prefix_map);
+ if (apply_update_result != APPLY_UPDATE_SUCCESS) {
+ return apply_update_result;
+ }
+
+ std::string expected_checksum;
+ if (response->has_checksum() && response->checksum().has_sha256()) {
+ expected_checksum = response->checksum().sha256();
+ }
+
+ TimeTicks before = TimeTicks::Now();
+ apply_update_result = MergeUpdate(hash_prefix_map_old, hash_prefix_map,
+ raw_removals, expected_checksum);
+ if (apply_update_result != APPLY_UPDATE_SUCCESS) {
+ return apply_update_result;
+ }
+ RecordMergeUpdateTime(TimeTicks::Now() - before, store_path_);
+
+ state_ = response->new_client_state();
+ return APPLY_UPDATE_SUCCESS;
+}
+
void V4Store::ApplyUpdate(
std::unique_ptr<ListUpdateResponse> response,
const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
UpdatedStoreReadyCallback callback) {
std::unique_ptr<V4Store> new_store(
new V4Store(this->task_runner_, this->store_path_));
+ ApplyUpdateResult apply_update_result;
+ if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) {
+ apply_update_result = new_store->ProcessPartialUpdateAndWriteToDisk(
+ hash_prefix_map_, std::move(response));
+ } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) {
+ apply_update_result =
+ new_store->ProcessFullUpdateAndWriteToDisk(std::move(response));
+ } else {
+ apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE;
+ NOTREACHED() << "Failure: Unexpected response type: "
+ << response->response_type();
+ }
- new_store->state_ = response->new_client_state();
- // TODO(vakh):
- // 1. Merge the old store and the new update in new_store.
- // 2. Create a ListUpdateResponse containing RICE encoded hash-prefixes and
- // response_type as FULL_UPDATE, and write that to disk.
- // 3. Remove this if condition after completing 1. and 2.
- if (response->has_response_type() &&
- response->response_type() == ListUpdateResponse::FULL_UPDATE) {
- StoreWriteResult result = new_store->WriteToDisk(std::move(response));
- RecordStoreWriteResult(result);
+ if (apply_update_result == APPLY_UPDATE_SUCCESS) {
+ // new_store is done updating, pass it to the callback.
+ callback_task_runner->PostTask(
+ FROM_HERE, base::Bind(callback, base::Passed(&new_store)));
+ } else {
+ DVLOG(1) << "Failure: ApplyUpdate: reason: " << apply_update_result
+ << "; store: " << *this;
+ // new_store failed updating. Pass a nullptr to the callback.
+ callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr));
}
- // new_store is done updating, pass it to the callback.
- callback_task_runner->PostTask(
- FROM_HERE, base::Bind(callback, base::Passed(&new_store)));
+ RecordApplyUpdateResult(apply_update_result);
+}
+
+// static
+ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions(
+ const RepeatedPtrField<ThreatEntrySet>& additions,
+ HashPrefixMap* additions_map) {
+ for (const auto& addition : additions) {
+ ApplyUpdateResult apply_update_result = APPLY_UPDATE_SUCCESS;
+ const CompressionType compression_type = addition.compression_type();
+ if (compression_type == RAW) {
+ DCHECK(addition.has_raw_hashes());
+ DCHECK(addition.raw_hashes().has_raw_hashes());
+
+ apply_update_result =
+ AddUnlumpedHashes(addition.raw_hashes().prefix_size(),
+ addition.raw_hashes().raw_hashes(), additions_map);
+ } else if (compression_type == RICE) {
+ DCHECK(addition.has_rice_hashes());
+
+ const RiceDeltaEncoding& rice_hashes = addition.rice_hashes();
+ std::vector<uint32_t> raw_hashes;
+ TimeTicks before = TimeTicks::Now();
+ V4DecodeResult decode_result = V4RiceDecoder::DecodePrefixes(
+ rice_hashes.first_value(), rice_hashes.rice_parameter(),
+ rice_hashes.num_entries(), rice_hashes.encoded_data(), &raw_hashes);
+ RecordDecodeAdditionsResult(decode_result);
+ if (decode_result != DECODE_SUCCESS) {
+ return RICE_DECODING_FAILURE;
+ } else {
+ RecordDecodeAdditionsTime(TimeTicks::Now() - before, store_path_);
+ char* raw_hashes_start = reinterpret_cast<char*>(raw_hashes.data());
+ size_t raw_hashes_size = sizeof(uint32_t) * raw_hashes.size();
+
+ // Rice-Golomb encoding is used to send compressed compressed 4-byte
+ // hash prefixes. Hash prefixes longer than 4 bytes will not be
+ // compressed, and will be served in raw format instead.
+ // Source: https://developers.google.com/safe-browsing/v4/compression
+ const PrefixSize kPrefixSize = 4;
+ apply_update_result = AddUnlumpedHashes(kPrefixSize, raw_hashes_start,
+ raw_hashes_size, additions_map);
+ }
+ } else {
+ NOTREACHED() << "Unexpected compression_type type: " << compression_type;
+ return UNEXPECTED_COMPRESSION_TYPE_ADDITIONS_FAILURE;
+ }
+
+ if (apply_update_result != APPLY_UPDATE_SUCCESS) {
+ // If there was an error in updating the map, discard the update entirely.
+ return apply_update_result;
+ }
+ }
+
+ return APPLY_UPDATE_SUCCESS;
+}
+
+// static
+ApplyUpdateResult V4Store::AddUnlumpedHashes(PrefixSize prefix_size,
+ const std::string& raw_hashes,
+ HashPrefixMap* additions_map) {
+ return AddUnlumpedHashes(prefix_size, raw_hashes.data(), raw_hashes.size(),
+ additions_map);
+}
+
+// static
+ApplyUpdateResult V4Store::AddUnlumpedHashes(PrefixSize prefix_size,
+ const char* raw_hashes_begin,
+ const size_t raw_hashes_length,
+ HashPrefixMap* additions_map) {
+ if (prefix_size < kMinHashPrefixLength) {
+ NOTREACHED();
+ return PREFIX_SIZE_TOO_SMALL_FAILURE;
+ }
+ if (prefix_size > kMaxHashPrefixLength) {
+ NOTREACHED();
+ return PREFIX_SIZE_TOO_LARGE_FAILURE;
+ }
+ if (raw_hashes_length % prefix_size != 0) {
+ return ADDITIONS_SIZE_UNEXPECTED_FAILURE;
+ }
+
+ TimeTicks before = TimeTicks::Now();
+ // TODO(vakh): Figure out a way to avoid the following copy operation.
+ (*additions_map)[prefix_size] =
+ std::string(raw_hashes_begin, raw_hashes_begin + raw_hashes_length);
+ RecordAddUnlumpedHashesTime(TimeTicks::Now() - before);
+ return APPLY_UPDATE_SUCCESS;
+}
+
+// static
+bool V4Store::GetNextSmallestUnmergedPrefix(
+ const HashPrefixMap& hash_prefix_map,
+ const IteratorMap& iterator_map,
+ HashPrefix* smallest_hash_prefix) {
+ HashPrefix current_hash_prefix;
+ bool has_unmerged = false;
+
+ for (const auto& iterator_pair : iterator_map) {
+ PrefixSize prefix_size = iterator_pair.first;
+ HashPrefixes::const_iterator start = iterator_pair.second;
+ const HashPrefixes& hash_prefixes = hash_prefix_map.at(prefix_size);
+ if (prefix_size <=
+ static_cast<PrefixSize>(std::distance(start, hash_prefixes.end()))) {
+ current_hash_prefix = HashPrefix(start, start + prefix_size);
+ if (!has_unmerged || *smallest_hash_prefix > current_hash_prefix) {
+ has_unmerged = true;
+ smallest_hash_prefix->swap(current_hash_prefix);
+ }
+ }
+ }
+ return has_unmerged;
+}
+
+// static
+void V4Store::InitializeIteratorMap(const HashPrefixMap& hash_prefix_map,
+ IteratorMap* iterator_map) {
+ for (const auto& map_pair : hash_prefix_map) {
+ (*iterator_map)[map_pair.first] = map_pair.second.begin();
+ }
+}
+
+// static
+void V4Store::ReserveSpaceInPrefixMap(const HashPrefixMap& other_prefixes_map,
+ HashPrefixMap* prefix_map_to_update) {
+ for (const auto& pair : other_prefixes_map) {
+ PrefixSize prefix_size = pair.first;
+ size_t prefix_length_to_add = pair.second.length();
+
+ const HashPrefixes& existing_prefixes =
+ (*prefix_map_to_update)[prefix_size];
+ size_t existing_capacity = existing_prefixes.capacity();
+
+ (*prefix_map_to_update)[prefix_size].reserve(existing_capacity +
+ prefix_length_to_add);
+ }
+}
+
+ApplyUpdateResult V4Store::MergeUpdate(const HashPrefixMap& old_prefixes_map,
+ const HashPrefixMap& additions_map,
+ const RepeatedField<int32>* raw_removals,
+ const std::string& expected_checksum) {
+ DCHECK(hash_prefix_map_.empty());
+ hash_prefix_map_.clear();
+ ReserveSpaceInPrefixMap(old_prefixes_map, &hash_prefix_map_);
+ ReserveSpaceInPrefixMap(additions_map, &hash_prefix_map_);
+
+ IteratorMap old_iterator_map;
+ HashPrefix next_smallest_prefix_old;
+ InitializeIteratorMap(old_prefixes_map, &old_iterator_map);
+ bool old_has_unmerged = GetNextSmallestUnmergedPrefix(
+ old_prefixes_map, old_iterator_map, &next_smallest_prefix_old);
+
+ IteratorMap additions_iterator_map;
+ HashPrefix next_smallest_prefix_additions;
+ InitializeIteratorMap(additions_map, &additions_iterator_map);
+ bool additions_has_unmerged = GetNextSmallestUnmergedPrefix(
+ additions_map, additions_iterator_map, &next_smallest_prefix_additions);
+
+ // Classical merge sort.
+ // The two constructs to merge are maps: old_prefixes_map, additions_map.
+ // At least one of the maps still has elements that need to be merged into the
+ // new store.
+
+ bool calculate_checksum = !expected_checksum.empty();
+ std::unique_ptr<crypto::SecureHash> checksum_ctx(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+
+ // Keep track of the number of elements picked from the old map. This is used
+ // to determine which elements to drop based on the raw_removals. Note that
+ // picked is not the same as merged. A picked element isn't merged if its
+ // index is on the raw_removals list.
+ int total_picked_from_old = 0;
+ const int* removals_iter = raw_removals ? raw_removals->begin() : nullptr;
+ while (old_has_unmerged || additions_has_unmerged) {
+ // If the same hash prefix appears in the existing store and the additions
+ // list, something is clearly wrong. Discard the update.
+ if (old_has_unmerged && additions_has_unmerged &&
+ next_smallest_prefix_old == next_smallest_prefix_additions) {
+ return ADDITIONS_HAS_EXISTING_PREFIX_FAILURE;
+ }
+
+ // Select which map to pick the next hash prefix from to keep the result in
+ // lexographically sorted order.
+ bool pick_from_old =
+ old_has_unmerged &&
+ (!additions_has_unmerged ||
+ (next_smallest_prefix_old < next_smallest_prefix_additions));
+
+ PrefixSize next_smallest_prefix_size;
+ if (pick_from_old) {
+ next_smallest_prefix_size = next_smallest_prefix_old.size();
+
+ // Update the iterator map, which means that we have merged one hash
+ // prefix of size |next_size_for_old| from the old store.
+ old_iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size;
+
+ if (!raw_removals || removals_iter == raw_removals->end() ||
+ *removals_iter != total_picked_from_old) {
+ // Append the smallest hash to the appropriate list.
+ hash_prefix_map_[next_smallest_prefix_size] += next_smallest_prefix_old;
+
+ if (calculate_checksum) {
+ checksum_ctx->Update(base::string_as_array(&next_smallest_prefix_old),
+ next_smallest_prefix_size);
+ }
+ } else {
+ // Element not added to new map. Move the removals iterator forward.
+ removals_iter++;
+ }
+
+ total_picked_from_old++;
+
+ // Find the next smallest unmerged element in the old store's map.
+ old_has_unmerged = GetNextSmallestUnmergedPrefix(
+ old_prefixes_map, old_iterator_map, &next_smallest_prefix_old);
+ } else {
+ next_smallest_prefix_size = next_smallest_prefix_additions.size();
+
+ // Append the smallest hash to the appropriate list.
+ hash_prefix_map_[next_smallest_prefix_size] +=
+ next_smallest_prefix_additions;
+
+ if (calculate_checksum) {
+ checksum_ctx->Update(
+ base::string_as_array(&next_smallest_prefix_additions),
+ next_smallest_prefix_size);
+ }
+
+ // Update the iterator map, which means that we have merged one hash
+ // prefix of size |next_smallest_prefix_size| from the update.
+ additions_iterator_map[next_smallest_prefix_size] +=
+ next_smallest_prefix_size;
+
+ // Find the next smallest unmerged element in the additions map.
+ additions_has_unmerged =
+ GetNextSmallestUnmergedPrefix(additions_map, additions_iterator_map,
+ &next_smallest_prefix_additions);
+ }
+ }
+
+ if (raw_removals && removals_iter != raw_removals->end()) {
+ return REMOVALS_INDEX_TOO_LARGE_FAILURE;
+ }
+
+ if (calculate_checksum) {
+ std::string checksum(crypto::kSHA256Length, 0);
+ checksum_ctx->Finish(base::string_as_array(&checksum), checksum.size());
+ if (checksum != expected_checksum) {
+ std::string checksum_base64, expected_checksum_base64;
+ base::Base64Encode(checksum, &checksum_base64);
+ base::Base64Encode(expected_checksum, &expected_checksum_base64);
+ DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_base64
+ << " expected: " << expected_checksum_base64;
+ return CHECKSUM_MISMATCH_FAILURE;
+ }
+ }
+
+ return APPLY_UPDATE_SUCCESS;
}
StoreReadResult V4Store::ReadFromDisk() {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ TimeTicks before = TimeTicks::Now();
std::string contents;
bool read_success = base::ReadFileToString(store_path_, &contents);
if (!read_success) {
@@ -120,16 +589,12 @@ StoreReadResult V4Store::ReadFromDisk() {
}
if (file_format.magic_number() != kFileMagic) {
- DVLOG(1) << "Unexpected magic number found in file: "
- << file_format.magic_number();
return UNEXPECTED_MAGIC_NUMBER_FAILURE;
}
UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.V4StoreVersionRead",
file_format.version_number());
if (file_format.version_number() != kFileVersion) {
- DVLOG(1) << "File version incompatible: " << file_format.version_number()
- << "; expected: " << kFileVersion;
return FILE_VERSION_INCOMPATIBLE_FAILURE;
}
@@ -137,9 +602,15 @@ StoreReadResult V4Store::ReadFromDisk() {
return HASH_PREFIX_INFO_MISSING_FAILURE;
}
- ListUpdateResponse list_update_response = file_format.list_update_response();
- state_ = list_update_response.new_client_state();
- // TODO(vakh): Do more with what's read from the disk.
+ std::unique_ptr<ListUpdateResponse> response(new ListUpdateResponse);
+ response->Swap(file_format.mutable_list_update_response());
+ ApplyUpdateResult apply_update_result = ProcessFullUpdate(response);
+ RecordApplyUpdateResultWhenReadingFromDisk(apply_update_result);
+ if (apply_update_result != APPLY_UPDATE_SUCCESS) {
+ hash_prefix_map_.clear();
+ return HASH_PREFIX_MAP_GENERATION_FAILURE;
+ }
+ RecordReadFromDiskTime(TimeTicks::Now() - before, store_path_);
return READ_SUCCESS;
}
@@ -151,9 +622,9 @@ StoreWriteResult V4Store::WriteToDisk(
// should be a FULL_UPDATE.
if (!response->has_response_type() ||
response->response_type() != ListUpdateResponse::FULL_UPDATE) {
- DVLOG(1) << "response->has_response_type(): "
- << response->has_response_type();
- DVLOG(1) << "response->response_type(): " << response->response_type();
+ DVLOG(1) << "Failure: response->has_response_type(): "
+ << response->has_response_type()
+ << " : response->response_type(): " << response->response_type();
return INVALID_RESPONSE_TYPE_FAILURE;
}
@@ -173,11 +644,50 @@ StoreWriteResult V4Store::WriteToDisk(
DCHECK_EQ(file_format_string.size(), written);
if (!base::Move(new_filename, store_path_)) {
- DVLOG(1) << "store_path_: " << store_path_.value();
return UNABLE_TO_RENAME_FAILURE;
}
return WRITE_SUCCESS;
}
+HashPrefix V4Store::GetMatchingHashPrefix(const FullHash& full_hash) {
+ // It should never be the case that more than one hash prefixes match a given
+ // full hash. However, if that happens, this method returns any one of them.
+ // It does not guarantee which one of those will be returned.
+ DCHECK_EQ(32u, full_hash.size());
+ for (const auto& pair : hash_prefix_map_) {
+ const PrefixSize& prefix_size = pair.first;
+ const HashPrefixes& hash_prefixes = pair.second;
+ HashPrefix hash_prefix = full_hash.substr(0, prefix_size);
+ if (HashPrefixMatches(hash_prefix, hash_prefixes.begin(),
+ hash_prefixes.end())) {
+ return hash_prefix;
+ }
+ }
+ return HashPrefix();
+}
+
+// static
+bool V4Store::HashPrefixMatches(const HashPrefix& hash_prefix,
+ const HashPrefixes::const_iterator& begin,
+ const HashPrefixes::const_iterator& end) {
+ if (begin == end) {
+ return false;
+ }
+ size_t distance = std::distance(begin, end);
+ const PrefixSize prefix_size = hash_prefix.length();
+ DCHECK_EQ(0u, distance % prefix_size);
+ size_t mid_prefix_index = ((distance / prefix_size) / 2) * prefix_size;
+ HashPrefixes::const_iterator mid = begin + mid_prefix_index;
+ HashPrefix mid_prefix = HashPrefix(mid, mid + prefix_size);
+ int result = hash_prefix.compare(mid_prefix);
+ if (result == 0) {
+ return true;
+ } else if (result < 0) {
+ return HashPrefixMatches(hash_prefix, begin, mid);
+ } else {
+ return HashPrefixMatches(hash_prefix, mid + prefix_size, end);
+ }
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_store.h b/chromium/components/safe_browsing_db/v4_store.h
index bbafbe73dfa..f0172808c8f 100644
--- a/chromium/components/safe_browsing_db/v4_store.h
+++ b/chromium/components/safe_browsing_db/v4_store.h
@@ -18,6 +18,19 @@ class V4Store;
typedef base::Callback<void(std::unique_ptr<V4Store>)>
UpdatedStoreReadyCallback;
+// The sorted list of hash prefixes.
+typedef std::string HashPrefixes;
+
+// Stores the list of sorted hash prefixes, by size.
+// For instance: {4: ["abcd", "bcde", "cdef", "gggg"], 5: ["fffff"]}
+typedef base::hash_map<PrefixSize, HashPrefixes> HashPrefixMap;
+
+// Stores the iterator to the last element merged from the HashPrefixMap for a
+// given prefix size.
+// For instance: {4:iter(3), 5:iter(1)} means that we have already merged
+// 3 hash prefixes of length 4, and 1 hash prefix of length 5.
+typedef base::hash_map<PrefixSize, HashPrefixes::const_iterator> IteratorMap;
+
// Enumerate different failure events while parsing the file read from disk for
// histogramming purposes. DO NOT CHANGE THE ORDERING OF THESE VALUES.
enum StoreReadResult {
@@ -38,7 +51,7 @@ enum StoreReadResult {
PROTO_PARSING_FAILURE = 4,
// The magic number didn't match. We're most likely trying to read a file
- // that doesn't contain hash-prefixes.
+ // that doesn't contain hash prefixes.
UNEXPECTED_MAGIC_NUMBER_FAILURE = 5,
// The version of the file is different from expected and Chromium doesn't
@@ -50,6 +63,9 @@ enum StoreReadResult {
// disk or if there was disk corruption.
HASH_PREFIX_INFO_MISSING_FAILURE = 7,
+ // Unable to generate the hash prefix map from the updates on disk.
+ HASH_PREFIX_MAP_GENERATION_FAILURE = 8,
+
// Memory space for histograms is determined by the max. ALWAYS
// ADD NEW VALUES BEFORE THIS ONE.
STORE_READ_RESULT_MAX
@@ -79,6 +95,54 @@ enum StoreWriteResult {
STORE_WRITE_RESULT_MAX
};
+// Enumerate different events while applying the update fetched fom the server
+// for histogramming purposes.
+// DO NOT CHANGE THE ORDERING OF THESE VALUES.
+enum ApplyUpdateResult {
+ // No errors.
+ APPLY_UPDATE_SUCCESS = 0,
+
+ // Reserved for errors in parsing this enum.
+ UNEXPECTED_APPLY_UPDATE_FAILURE = 1,
+
+ // Prefix size smaller than 4 (which is the lowest expected).
+ PREFIX_SIZE_TOO_SMALL_FAILURE = 2,
+
+ // Prefix size larger than 32 (length of a full SHA256 hash).
+ PREFIX_SIZE_TOO_LARGE_FAILURE = 3,
+
+ // The number of bytes in additions isn't a multiple of prefix size.
+ ADDITIONS_SIZE_UNEXPECTED_FAILURE = 4,
+
+ // The update received from the server contains a prefix that's already
+ // present in the map.
+ ADDITIONS_HAS_EXISTING_PREFIX_FAILURE = 5,
+
+ // The server sent a response_type that the client did not expect.
+ UNEXPECTED_RESPONSE_TYPE_FAILURE = 6,
+
+ // One of more index(es) in removals field of the response is greater than
+ // the number of hash prefixes currently in the (old) store.
+ REMOVALS_INDEX_TOO_LARGE_FAILURE = 7,
+
+ // Failed to decode the Rice-encoded additions/removals field.
+ RICE_DECODING_FAILURE = 8,
+
+ // Compression type other than RAW and RICE for additions.
+ UNEXPECTED_COMPRESSION_TYPE_ADDITIONS_FAILURE = 9,
+
+ // Compression type other than RAW and RICE for removals.
+ UNEXPECTED_COMPRESSION_TYPE_REMOVALS_FAILURE = 10,
+
+ // The state of the store did not match the expected checksum sent by the
+ // server.
+ CHECKSUM_MISMATCH_FAILURE = 11,
+
+ // Memory space for histograms is determined by the max. ALWAYS
+ // ADD NEW VALUES BEFORE THIS ONE.
+ APPLY_UPDATE_RESULT_MAX
+};
+
// Factory for creating V4Store. Tests implement this factory to create fake
// stores for testing.
class V4StoreFactory {
@@ -106,6 +170,10 @@ class V4Store {
const scoped_refptr<base::SingleThreadTaskRunner>&,
UpdatedStoreReadyCallback);
+ // If a hash prefix in this store matches |full_hash|, returns that hash
+ // prefix; otherwise returns an empty hash prefix.
+ virtual HashPrefix GetMatchingHashPrefix(const FullHash& full_hash);
+
std::string DebugString() const;
// Reads the store file from disk and populates the in-memory representation
@@ -127,11 +195,152 @@ class V4Store {
FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestWritePartialResponseType);
FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestWriteFullResponseType);
FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestReadFromFileWithUnknownProto);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestAddUnlumpedHashesWithInvalidAddition);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestAddUnlumpedHashes);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestAddUnlumpedHashesWithEmptyString);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestGetNextSmallestUnmergedPrefixWithEmptyPrefixMap);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestGetNextSmallestUnmergedPrefix);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestMergeUpdatesWithSameSizesInEachMap);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestMergeUpdatesWithDifferentSizesInEachMap);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestMergeUpdatesOldMapRunsOutFirst);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestMergeUpdatesAdditionsMapRunsOutFirst);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestMergeUpdatesFailsForRepeatedHashPrefix);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestMergeUpdatesFailsWhenRemovalsIndexTooLarge);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestMergeUpdatesRemovesOnlyElement);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestMergeUpdatesRemovesFirstElement);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestMergeUpdatesRemovesMiddleElement);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestMergeUpdatesRemovesLastElement);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestMergeUpdatesRemovesWhenOldHasDifferentSizes);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestMergeUpdatesRemovesMultipleAcrossDifferentSizes);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestReadFullResponseWithValidHashPrefixMap);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestReadFullResponseWithInvalidHashPrefixMap);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestHashPrefixExistsAtTheBeginning);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestHashPrefixExistsInTheMiddle);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestHashPrefixExistsAtTheEnd);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestHashPrefixExistsAtTheBeginningOfEven);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestHashPrefixExistsAtTheEndOfEven);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestHashPrefixDoesNotExistInConcatenatedList);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestFullHashExistsInMapWithSingleSize);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestFullHashExistsInMapWithDifferentSizes);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestHashPrefixExistsInMapWithSingleSize);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestHashPrefixExistsInMapWithDifferentSizes);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestHashPrefixDoesNotExistInMapWithDifferentSizes);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+ TestAdditionsWithRiceEncodingFailsWithInvalidInput);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestAdditionsWithRiceEncodingSucceeds);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestRemovalsWithRiceEncodingSucceeds);
+ FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestMergeUpdatesFailsChecksum);
+ friend class V4StoreTest;
+
+ // If |prefix_size| is within expected range, and |raw_hashes_length| is a
+ // multiple of prefix_size, then it sets the string of length
+ // |raw_hashes_length| starting at |raw_hashes_begin| as the value at key
+ // |prefix_size| in |additions_map|
+ static ApplyUpdateResult AddUnlumpedHashes(PrefixSize prefix_size,
+ const char* raw_hashes_begin,
+ const size_t raw_hashes_length,
+ HashPrefixMap* additions_map);
+
+ // An overloaded version of AddUnlumpedHashes that allows passing in a
+ // std::string object.
+ static ApplyUpdateResult AddUnlumpedHashes(PrefixSize prefix_size,
+ const std::string& raw_hashes,
+ HashPrefixMap* additions_map);
+
+ // Get the next unmerged hash prefix in dictionary order from
+ // |hash_prefix_map|. |iterator_map| is used to determine which hash prefixes
+ // have been merged already. Returns true if there are any unmerged hash
+ // prefixes in the list.
+ static bool GetNextSmallestUnmergedPrefix(
+ const HashPrefixMap& hash_prefix_map,
+ const IteratorMap& iterator_map,
+ HashPrefix* smallest_hash_prefix);
+
+ // Returns true if |hash_prefix| exists between |begin| and |end| iterators.
+ static bool HashPrefixMatches(const HashPrefix& hash_prefix,
+ const HashPrefixes::const_iterator& begin,
+ const HashPrefixes::const_iterator& end);
+
+ // For each key in |hash_prefix_map|, sets the iterator at that key
+ // |iterator_map| to hash_prefix_map[key].begin().
+ static void InitializeIteratorMap(const HashPrefixMap& hash_prefix_map,
+ IteratorMap* iterator_map);
+
+ // Reserve the appropriate string size so that the string size of the merged
+ // list is exact. This ignores the space that would otherwise be released by
+ // deletions specified in the update because it is non-trivial to calculate
+ // those deletions upfront. This isn't so bad since deletions are supposed to
+ // be small and infrequent.
+ static void ReserveSpaceInPrefixMap(const HashPrefixMap& other_prefixes_map,
+ HashPrefixMap* prefix_map_to_update);
+
+ // Merges the prefix map from the old store (|old_hash_prefix_map|) and the
+ // update (additions_map) to populate the prefix map for the current store.
+ // The indices in the |raw_removals| list, which may be NULL, are not merged.
+ // The SHA256 checksum of the final list of hash prefixes, in lexographically
+ // sorted order, must match |expected_checksum| (if it's not empty).
+ ApplyUpdateResult MergeUpdate(const HashPrefixMap& old_hash_prefix_map,
+ const HashPrefixMap& additions_map,
+ const ::google::protobuf::RepeatedField<
+ ::google::protobuf::int32>* raw_removals,
+ const std::string& expected_checksum);
+
+ // Processes the FULL_UPDATE |response| from the server, and writes the
+ // merged V4Store to disk. If processing the |response| succeeds, it returns
+ // APPLY_UPDATE_SUCCESS.
+ // This method is only called when we receive a FULL_UPDATE from the server.
+ ApplyUpdateResult ProcessFullUpdateAndWriteToDisk(
+ std::unique_ptr<ListUpdateResponse> response);
+
+ // Processes a FULL_UPDATE |response| and updates the V4Store. If processing
+ // the |response| succeeds, it returns APPLY_UPDATE_SUCCESS.
+ // This method is called when we receive a FULL_UPDATE from the server, and
+ // when we read a store file from disk on startup.
+ ApplyUpdateResult ProcessFullUpdate(
+ const std::unique_ptr<ListUpdateResponse>& response);
+
+ // Merges the hash prefixes in |hash_prefix_map_old| and |response|, updates
+ // the |hash_prefix_map_| and |state_| in the V4Store, and writes the merged
+ // store to disk. If processing succeeds, it returns APPLY_UPDATE_SUCCESS.
+ // This method is only called when we receive a PARTIAL_UPDATE from the
+ // server.
+ ApplyUpdateResult ProcessPartialUpdateAndWriteToDisk(
+ const HashPrefixMap& hash_prefix_map_old,
+ std::unique_ptr<ListUpdateResponse> response);
+
+ // Merges the hash prefixes in |hash_prefix_map_old| and |response|, and
+ // updates the |hash_prefix_map_| and |state_| in the V4Store. If processing
+ // succeeds, it returns APPLY_UPDATE_SUCCESS.
+ ApplyUpdateResult ProcessUpdate(
+ const HashPrefixMap& hash_prefix_map_old,
+ const std::unique_ptr<ListUpdateResponse>& response);
// Reads the state of the store from the file on disk and returns the reason
// for the failure or reports success.
StoreReadResult ReadFromDisk();
+ // Updates the |additions_map| with the additions received in the partial
+ // update from the server.
+ ApplyUpdateResult UpdateHashPrefixMapFromAdditions(
+ const ::google::protobuf::RepeatedPtrField<ThreatEntrySet>& additions,
+ HashPrefixMap* additions_map);
+
// Writes the FULL_UPDATE |response| to disk as a V4StoreFileFormat proto.
StoreWriteResult WriteToDisk(
std::unique_ptr<ListUpdateResponse> response) const;
@@ -140,6 +349,7 @@ class V4Store {
// update response.
std::string state_;
const base::FilePath store_path_;
+ HashPrefixMap hash_prefix_map_;
const scoped_refptr<base::SequencedTaskRunner> task_runner_;
};
diff --git a/chromium/components/safe_browsing_db/v4_store_unittest.cc b/chromium/components/safe_browsing_db/v4_store_unittest.cc
index ec41208a73e..90c6525fa88 100644
--- a/chromium/components/safe_browsing_db/v4_store_unittest.cc
+++ b/chromium/components/safe_browsing_db/v4_store_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 "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
@@ -11,10 +12,15 @@
#include "components/safe_browsing_db/v4_store.h"
#include "components/safe_browsing_db/v4_store.pb.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "crypto/sha2.h"
#include "testing/platform_test.h"
namespace safe_browsing {
+using ::google::protobuf::RepeatedField;
+using ::google::protobuf::RepeatedPtrField;
+using ::google::protobuf::int32;
+
class V4StoreTest : public PlatformTest {
public:
V4StoreTest() : task_runner_(new base::TestSimpleTaskRunner) {}
@@ -23,7 +29,7 @@ class V4StoreTest : public PlatformTest {
PlatformTest::SetUp();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- store_path_ = temp_dir_.path().AppendASCII("V4StoreTest.store");
+ store_path_ = temp_dir_.GetPath().AppendASCII("V4StoreTest.store");
DVLOG(1) << "store_path_: " << store_path_.value();
}
@@ -50,6 +56,14 @@ class V4StoreTest : public PlatformTest {
file_format_string.size());
}
+ void UpdatedStoreReadyAfterRiceRemovals(bool* called_back,
+ std::unique_ptr<V4Store> new_store) {
+ *called_back = true;
+ EXPECT_EQ(2u, new_store->hash_prefix_map_.size());
+ EXPECT_EQ("22222", new_store->hash_prefix_map_[5]);
+ EXPECT_EQ("abcd", new_store->hash_prefix_map_[4]);
+ }
+
base::ScopedTempDir temp_dir_;
base::FilePath store_path_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
@@ -109,6 +123,7 @@ TEST_F(V4StoreTest, TestReadFromNoHashPrefixInfoFile) {
TEST_F(V4StoreTest, TestReadFromNoHashPrefixesFile) {
ListUpdateResponse list_update_response;
list_update_response.set_platform_type(LINUX_PLATFORM);
+ list_update_response.set_response_type(ListUpdateResponse::FULL_UPDATE);
WriteFileFormatProtoToFile(0x600D71FE, 9, &list_update_response);
EXPECT_EQ(READ_SUCCESS, V4Store(task_runner_, store_path_).ReadFromDisk());
}
@@ -136,9 +151,653 @@ TEST_F(V4StoreTest, TestWriteFullResponseType) {
EXPECT_EQ(WRITE_SUCCESS, V4Store(task_runner_, store_path_)
.WriteToDisk(std::move(list_update_response)));
- std::unique_ptr<V4Store> read_store(new V4Store(task_runner_, store_path_));
- EXPECT_EQ(READ_SUCCESS, read_store->ReadFromDisk());
- EXPECT_EQ("test_client_state", read_store->state_);
+ V4Store read_store(task_runner_, store_path_);
+ EXPECT_EQ(READ_SUCCESS, read_store.ReadFromDisk());
+ EXPECT_EQ("test_client_state", read_store.state_);
+ EXPECT_TRUE(read_store.hash_prefix_map_.empty());
+}
+
+TEST_F(V4StoreTest, TestAddUnlumpedHashesWithInvalidAddition) {
+ HashPrefixMap prefix_map;
+ EXPECT_EQ(ADDITIONS_SIZE_UNEXPECTED_FAILURE,
+ V4Store::AddUnlumpedHashes(5, "a", &prefix_map));
+ EXPECT_TRUE(prefix_map.empty());
+}
+
+TEST_F(V4StoreTest, TestAddUnlumpedHashesWithEmptyString) {
+ HashPrefixMap prefix_map;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "", &prefix_map));
+ EXPECT_TRUE(prefix_map[5].empty());
+}
+
+TEST_F(V4StoreTest, TestAddUnlumpedHashes) {
+ HashPrefixMap prefix_map;
+ PrefixSize prefix_size = 5;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(prefix_size, "abcde5432100000-----",
+ &prefix_map));
+ EXPECT_EQ(1u, prefix_map.size());
+ HashPrefixes hash_prefixes = prefix_map.at(prefix_size);
+ EXPECT_EQ(4 * prefix_size, hash_prefixes.size());
+ EXPECT_EQ("abcde5432100000-----", hash_prefixes);
+
+ prefix_size = 4;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(prefix_size, "abcde5432100000-----",
+ &prefix_map));
+ EXPECT_EQ(2u, prefix_map.size());
+ hash_prefixes = prefix_map.at(prefix_size);
+ EXPECT_EQ(5 * prefix_size, hash_prefixes.size());
+ EXPECT_EQ("abcde5432100000-----", hash_prefixes);
+}
+
+TEST_F(V4StoreTest, TestGetNextSmallestUnmergedPrefixWithEmptyPrefixMap) {
+ HashPrefixMap prefix_map;
+ IteratorMap iterator_map;
+ V4Store::InitializeIteratorMap(prefix_map, &iterator_map);
+
+ HashPrefix prefix;
+ EXPECT_FALSE(V4Store::GetNextSmallestUnmergedPrefix(prefix_map, iterator_map,
+ &prefix));
+}
+
+TEST_F(V4StoreTest, TestGetNextSmallestUnmergedPrefix) {
+ HashPrefixMap prefix_map;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "-----0000054321abcde", &prefix_map));
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "*****0000054321abcde", &prefix_map));
+ IteratorMap iterator_map;
+ V4Store::InitializeIteratorMap(prefix_map, &iterator_map);
+
+ HashPrefix prefix;
+ EXPECT_TRUE(V4Store::GetNextSmallestUnmergedPrefix(prefix_map, iterator_map,
+ &prefix));
+ EXPECT_EQ("****", prefix);
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesWithSameSizesInEachMap) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "abcdefgh", &prefix_map_old));
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "54321abcde", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(
+ APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "----1111bbbb", &prefix_map_additions));
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "22222bcdef", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ // Proof of checksum validity using python:
+ // >>> import hashlib
+ // >>> m = hashlib.sha256()
+ // >>> m.update("----11112222254321abcdabcdebbbbbcdefefgh")
+ // >>> m.digest()
+ // "\xbc\xb3\xedk\xe3x\xd1(\xa9\xedz7]"
+ // "x\x18\xbdn]\xa5\xa8R\xf7\xab\xcf\xc1\xa3\xa3\xc5Z,\xa6o"
+ std::string expected_checksum = std::string(
+ "\xBC\xB3\xEDk\xE3x\xD1(\xA9\xEDz7]x\x18\xBDn]"
+ "\xA5\xA8R\xF7\xAB\xCF\xC1\xA3\xA3\xC5Z,\xA6o",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
+ expected_checksum));
+
+ const HashPrefixMap& prefix_map = store.hash_prefix_map_;
+ EXPECT_EQ(2u, prefix_map.size());
+
+ PrefixSize prefix_size = 4;
+ HashPrefixes hash_prefixes = prefix_map.at(prefix_size);
+ EXPECT_EQ(5 * prefix_size, hash_prefixes.size());
+ EXPECT_EQ("----", hash_prefixes.substr(0 * prefix_size, prefix_size));
+ EXPECT_EQ("1111", hash_prefixes.substr(1 * prefix_size, prefix_size));
+ EXPECT_EQ("abcd", hash_prefixes.substr(2 * prefix_size, prefix_size));
+ EXPECT_EQ("bbbb", hash_prefixes.substr(3 * prefix_size, prefix_size));
+ EXPECT_EQ("efgh", hash_prefixes.substr(4 * prefix_size, prefix_size));
+
+ prefix_size = 5;
+ hash_prefixes = prefix_map.at(prefix_size);
+ EXPECT_EQ(4 * prefix_size, hash_prefixes.size());
+ EXPECT_EQ("22222", hash_prefixes.substr(0 * prefix_size, prefix_size));
+ EXPECT_EQ("54321", hash_prefixes.substr(1 * prefix_size, prefix_size));
+ EXPECT_EQ("abcde", hash_prefixes.substr(2 * prefix_size, prefix_size));
+ EXPECT_EQ("bcdef", hash_prefixes.substr(3 * prefix_size, prefix_size));
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesWithDifferentSizesInEachMap) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "1111abcdefgh", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "22222bcdef", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ std::string expected_checksum = std::string(
+ "\xA5\x8B\xCAsD\xC7\xF9\xCE\xD2\xF4\x4="
+ "\xB2\"\x82\x1A\xC1\xB8\x1F\x10\r\v\x9A\x93\xFD\xE1\xB8"
+ "B\x1Eh\xF7\xB4",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
+ expected_checksum));
+
+ const HashPrefixMap& prefix_map = store.hash_prefix_map_;
+ EXPECT_EQ(2u, prefix_map.size());
+
+ PrefixSize prefix_size = 4;
+ HashPrefixes hash_prefixes = prefix_map.at(prefix_size);
+ EXPECT_EQ(3 * prefix_size, hash_prefixes.size());
+ EXPECT_EQ("1111abcdefgh", hash_prefixes);
+
+ prefix_size = 5;
+ hash_prefixes = prefix_map.at(prefix_size);
+ EXPECT_EQ(2 * prefix_size, hash_prefixes.size());
+ EXPECT_EQ("22222bcdef", hash_prefixes);
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesOldMapRunsOutFirst) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "00001111", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ std::string expected_checksum = std::string(
+ "\x84\x92\xET\xED\xF7\x97"
+ "C\xCE}\xFF"
+ "E\x1\xAB-\b>\xDB\x95\b\xD8H\xD5\x1D\xF9]8x\xA4\xD4\xC2\xFA",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
+ expected_checksum));
+
+ const HashPrefixMap& prefix_map = store.hash_prefix_map_;
+ EXPECT_EQ(1u, prefix_map.size());
+
+ PrefixSize prefix_size = 4;
+ HashPrefixes hash_prefixes = prefix_map.at(prefix_size);
+ EXPECT_EQ(3 * prefix_size, hash_prefixes.size());
+ EXPECT_EQ("0000", hash_prefixes.substr(0 * prefix_size, prefix_size));
+ EXPECT_EQ("1111", hash_prefixes.substr(1 * prefix_size, prefix_size));
+ EXPECT_EQ("2222", hash_prefixes.substr(2 * prefix_size, prefix_size));
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesAdditionsMapRunsOutFirst) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "00001111", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ std::string expected_checksum = std::string(
+ "\x84\x92\xET\xED\xF7\x97"
+ "C\xCE}\xFF"
+ "E\x1\xAB-\b>\xDB\x95\b\xD8H\xD5\x1D\xF9]8x\xA4\xD4\xC2\xFA",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
+ expected_checksum));
+
+ const HashPrefixMap& prefix_map = store.hash_prefix_map_;
+ EXPECT_EQ(1u, prefix_map.size());
+
+ PrefixSize prefix_size = 4;
+ HashPrefixes hash_prefixes = prefix_map.at(prefix_size);
+ EXPECT_EQ(3 * prefix_size, hash_prefixes.size());
+ EXPECT_EQ("0000", hash_prefixes.substr(0 * prefix_size, prefix_size));
+ EXPECT_EQ("1111", hash_prefixes.substr(1 * prefix_size, prefix_size));
+ EXPECT_EQ("2222", hash_prefixes.substr(2 * prefix_size, prefix_size));
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesFailsForRepeatedHashPrefix) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ std::string expected_checksum;
+ EXPECT_EQ(ADDITIONS_HAS_EXISTING_PREFIX_FAILURE,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
+ expected_checksum));
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesFailsWhenRemovalsIndexTooLarge) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "11113333", &prefix_map_additions));
+
+ // Even though the merged map could have size 3 without removals, the
+ // removals index should only count the entries in the old map.
+ V4Store store(task_runner_, store_path_);
+ RepeatedField<int32> raw_removals;
+ // old_store: ["2222"]
+ raw_removals.Add(1);
+ std::string expected_checksum;
+ EXPECT_EQ(REMOVALS_INDEX_TOO_LARGE_FAILURE,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions,
+ &raw_removals, expected_checksum));
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesRemovesOnlyElement) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "1111133333", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ RepeatedField<int32> raw_removals;
+ // old_store: ["2222"]
+ raw_removals.Add(0); // Removes "2222"
+ std::string expected_checksum = std::string(
+ "\xE6\xB0\x1\x12\x89\x83\xF0/"
+ "\xE7\xD2\xE6\xDC\x16\xB9\x8C+\xA2\xB3\x9E\x89<,\x88"
+ "B3\xA5\xB1"
+ "D\x9E\x9E'\x14",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions,
+ &raw_removals, expected_checksum));
+
+ const HashPrefixMap& prefix_map = store.hash_prefix_map_;
+ // The size is 2 since we reserve space anyway.
+ EXPECT_EQ(2u, prefix_map.size());
+ EXPECT_TRUE(prefix_map.at(4).empty());
+ EXPECT_EQ("1111133333", prefix_map.at(5));
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesRemovesFirstElement) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "22224444", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "1111133333", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ RepeatedField<int32> raw_removals;
+ // old_store: ["2222", "4444"]
+ raw_removals.Add(0); // Removes "2222"
+ std::string expected_checksum = std::string(
+ "\x9D\xF3\xF2\x82\0\x1E{\xDF\xCD\xC0V\xBE\xD6<\x85"
+ "D7=\xB5v\xAD\b1\xC9\xB3"
+ "A\xAC"
+ "b\xF1lf\xA4",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions,
+ &raw_removals, expected_checksum));
+
+ const HashPrefixMap& prefix_map = store.hash_prefix_map_;
+ // The size is 2 since we reserve space anyway.
+ EXPECT_EQ(2u, prefix_map.size());
+ EXPECT_EQ("4444", prefix_map.at(4));
+ EXPECT_EQ("1111133333", prefix_map.at(5));
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesRemovesMiddleElement) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "222233334444", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "1111133333", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ RepeatedField<int32> raw_removals;
+ // old_store: ["2222", "3333", 4444"]
+ raw_removals.Add(1); // Removes "3333"
+ std::string expected_checksum = std::string(
+ "\xFA-A\x15{\x17\0>\xAE"
+ "8\xACigR\xD1\x93<\xB2\xC9\xB5\x81\xC0\xFB\xBB\x2\f\xAFpN\xEA"
+ "44",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions,
+ &raw_removals, expected_checksum));
+
+ const HashPrefixMap& prefix_map = store.hash_prefix_map_;
+ // The size is 2 since we reserve space anyway.
+ EXPECT_EQ(2u, prefix_map.size());
+ EXPECT_EQ("22224444", prefix_map.at(4));
+ EXPECT_EQ("1111133333", prefix_map.at(5));
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesRemovesLastElement) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "222233334444", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "1111133333", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ RepeatedField<int32> raw_removals;
+ // old_store: ["2222", "3333", 4444"]
+ raw_removals.Add(2); // Removes "4444"
+ std::string expected_checksum = std::string(
+ "a\xE1\xAD\x96\xFE\xA6"
+ "A\xCA~7W\xF6z\xD8\n\xCA?\x96\x8A\x17U\x5\v\r\x88]\n\xB2JX\xC4S",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions,
+ &raw_removals, expected_checksum));
+
+ const HashPrefixMap& prefix_map = store.hash_prefix_map_;
+ // The size is 2 since we reserve space anyway.
+ EXPECT_EQ(2u, prefix_map.size());
+ EXPECT_EQ("22223333", prefix_map.at(4));
+ EXPECT_EQ("1111133333", prefix_map.at(5));
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesRemovesWhenOldHasDifferentSizes) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "222233334444", &prefix_map_old));
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "aaaaabbbbb", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "1111133333", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ RepeatedField<int32> raw_removals;
+ // old_store: ["2222", "3333", 4444", "aaaaa", "bbbbb"]
+ raw_removals.Add(3); // Removes "aaaaa"
+ std::string expected_checksum = std::string(
+ "\xA7OG\x9D\x83.\x9D-f\x8A\xE\x8B\r&\x19"
+ "6\xE3\xF0\xEFTi\xA7\x5\xEA\xF7"
+ "ej,\xA8\x9D\xAD\x91",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions,
+ &raw_removals, expected_checksum));
+
+ const HashPrefixMap& prefix_map = store.hash_prefix_map_;
+ // The size is 2 since we reserve space anyway.
+ EXPECT_EQ(2u, prefix_map.size());
+ EXPECT_EQ("222233334444", prefix_map.at(4));
+ EXPECT_EQ("1111133333bbbbb", prefix_map.at(5));
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesRemovesMultipleAcrossDifferentSizes) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "22223333aaaa", &prefix_map_old));
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "3333344444bbbbb", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "11111", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ RepeatedField<int32> raw_removals;
+ // old_store: ["2222", "3333", "33333", "44444", "aaaa", "bbbbb"]
+ raw_removals.Add(1); // Removes "3333"
+ raw_removals.Add(3); // Removes "44444"
+ std::string expected_checksum = std::string(
+ "!D\xB7&L\xA7&G0\x85\xB4"
+ "E\xDD\x10\"\x9A\xCA\xF1"
+ "3^\x83w\xBBL\x19n\xAD\xBDM\x9D"
+ "b\x9F",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions,
+ &raw_removals, expected_checksum));
+
+ const HashPrefixMap& prefix_map = store.hash_prefix_map_;
+ // The size is 2 since we reserve space anyway.
+ EXPECT_EQ(2u, prefix_map.size());
+ EXPECT_EQ("2222aaaa", prefix_map.at(4));
+ EXPECT_EQ("1111133333bbbbb", prefix_map.at(5));
+}
+
+TEST_F(V4StoreTest, TestReadFullResponseWithValidHashPrefixMap) {
+ std::unique_ptr<ListUpdateResponse> lur(new ListUpdateResponse);
+ lur->set_response_type(ListUpdateResponse::FULL_UPDATE);
+ lur->set_new_client_state("test_client_state");
+ lur->set_platform_type(WINDOWS_PLATFORM);
+ lur->set_threat_entry_type(URL);
+ lur->set_threat_type(MALWARE_THREAT);
+ ThreatEntrySet* additions = lur->add_additions();
+ additions->set_compression_type(RAW);
+ additions->mutable_raw_hashes()->set_prefix_size(5);
+ additions->mutable_raw_hashes()->set_raw_hashes("00000abcde");
+ additions = lur->add_additions();
+ additions->set_compression_type(RAW);
+ additions->mutable_raw_hashes()->set_prefix_size(4);
+ additions->mutable_raw_hashes()->set_raw_hashes("00000abc");
+ EXPECT_EQ(WRITE_SUCCESS,
+ V4Store(task_runner_, store_path_).WriteToDisk(std::move(lur)));
+
+ V4Store read_store (task_runner_, store_path_);
+ EXPECT_EQ(READ_SUCCESS, read_store.ReadFromDisk());
+ EXPECT_EQ("test_client_state", read_store.state_);
+ ASSERT_EQ(2u, read_store.hash_prefix_map_.size());
+ EXPECT_EQ("00000abc", read_store.hash_prefix_map_[4]);
+ EXPECT_EQ("00000abcde", read_store.hash_prefix_map_[5]);
+}
+
+// This tests fails to read the prefix map from the disk because the file on
+// disk is invalid. The hash prefixes string is 6 bytes long, but the prefix
+// size is 5 so the parser isn't able to split the hash prefixes list
+// completely.
+TEST_F(V4StoreTest, TestReadFullResponseWithInvalidHashPrefixMap) {
+ std::unique_ptr<ListUpdateResponse> lur(new ListUpdateResponse);
+ lur->set_response_type(ListUpdateResponse::FULL_UPDATE);
+ lur->set_new_client_state("test_client_state");
+ lur->set_platform_type(WINDOWS_PLATFORM);
+ lur->set_threat_entry_type(URL);
+ lur->set_threat_type(MALWARE_THREAT);
+ ThreatEntrySet* additions = lur->add_additions();
+ additions->set_compression_type(RAW);
+ additions->mutable_raw_hashes()->set_prefix_size(5);
+ additions->mutable_raw_hashes()->set_raw_hashes("abcdef");
+ EXPECT_EQ(WRITE_SUCCESS,
+ V4Store(task_runner_, store_path_).WriteToDisk(std::move(lur)));
+
+ V4Store read_store(task_runner_, store_path_);
+ EXPECT_EQ(HASH_PREFIX_MAP_GENERATION_FAILURE, read_store.ReadFromDisk());
+ EXPECT_TRUE(read_store.state_.empty());
+ EXPECT_TRUE(read_store.hash_prefix_map_.empty());
+}
+
+TEST_F(V4StoreTest, TestHashPrefixExistsAtTheBeginning) {
+ HashPrefixes hash_prefixes = "abcdebbbbbccccc";
+ HashPrefix hash_prefix = "abcde";
+ EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, std::begin(hash_prefixes),
+ std::end(hash_prefixes)));
+}
+
+TEST_F(V4StoreTest, TestHashPrefixExistsInTheMiddle) {
+ HashPrefixes hash_prefixes = "abcdebbbbbccccc";
+ HashPrefix hash_prefix = "bbbbb";
+ EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, std::begin(hash_prefixes),
+ std::end(hash_prefixes)));
+}
+
+TEST_F(V4StoreTest, TestHashPrefixExistsAtTheEnd) {
+ HashPrefixes hash_prefixes = "abcdebbbbbccccc";
+ HashPrefix hash_prefix = "ccccc";
+ EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, std::begin(hash_prefixes),
+ std::end(hash_prefixes)));
+}
+
+TEST_F(V4StoreTest, TestHashPrefixExistsAtTheBeginningOfEven) {
+ HashPrefixes hash_prefixes = "abcdebbbbb";
+ HashPrefix hash_prefix = "abcde";
+ EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, std::begin(hash_prefixes),
+ std::end(hash_prefixes)));
+}
+
+TEST_F(V4StoreTest, TestHashPrefixExistsAtTheEndOfEven) {
+ HashPrefixes hash_prefixes = "abcdebbbbb";
+ HashPrefix hash_prefix = "bbbbb";
+ EXPECT_TRUE(V4Store::HashPrefixMatches(hash_prefix, std::begin(hash_prefixes),
+ std::end(hash_prefixes)));
+}
+
+TEST_F(V4StoreTest, TestHashPrefixDoesNotExistInConcatenatedList) {
+ HashPrefixes hash_prefixes = "abcdebbbbb";
+ HashPrefix hash_prefix = "bbbbc";
+ EXPECT_FALSE(V4Store::HashPrefixMatches(
+ hash_prefix, std::begin(hash_prefixes), std::end(hash_prefixes)));
+}
+
+TEST_F(V4StoreTest, TestFullHashExistsInMapWithSingleSize) {
+ V4Store store(task_runner_, store_path_);
+ store.hash_prefix_map_[32] =
+ "0111222233334444555566667777888811112222333344445555666677778888";
+ FullHash full_hash = "11112222333344445555666677778888";
+ EXPECT_EQ("11112222333344445555666677778888",
+ store.GetMatchingHashPrefix(full_hash));
+}
+
+TEST_F(V4StoreTest, TestFullHashExistsInMapWithDifferentSizes) {
+ V4Store store(task_runner_, store_path_);
+ store.hash_prefix_map_[4] = "22223333aaaa";
+ store.hash_prefix_map_[32] = "11112222333344445555666677778888";
+ FullHash full_hash = "11112222333344445555666677778888";
+ EXPECT_EQ("11112222333344445555666677778888",
+ store.GetMatchingHashPrefix(full_hash));
+}
+
+TEST_F(V4StoreTest, TestHashPrefixExistsInMapWithSingleSize) {
+ V4Store store(task_runner_, store_path_);
+ store.hash_prefix_map_[4] = "22223333aaaa";
+ FullHash full_hash = "22222222222222222222222222222222";
+ EXPECT_EQ("2222", store.GetMatchingHashPrefix(full_hash));
+}
+
+TEST_F(V4StoreTest, TestHashPrefixExistsInMapWithDifferentSizes) {
+ V4Store store(task_runner_, store_path_);
+ store.hash_prefix_map_[4] = "22223333aaaa";
+ store.hash_prefix_map_[5] = "11111hhhhh";
+ FullHash full_hash = "22222222222222222222222222222222";
+ EXPECT_EQ("2222", store.GetMatchingHashPrefix(full_hash));
+}
+
+TEST_F(V4StoreTest, TestHashPrefixDoesNotExistInMapWithDifferentSizes) {
+ V4Store store(task_runner_, store_path_);
+ store.hash_prefix_map_[4] = "3333aaaa";
+ store.hash_prefix_map_[5] = "11111hhhhh";
+ FullHash full_hash = "22222222222222222222222222222222";
+ EXPECT_TRUE(store.GetMatchingHashPrefix(full_hash).empty());
+}
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+// This test hits a NOTREACHED so it is a release mode only test.
+TEST_F(V4StoreTest, TestAdditionsWithRiceEncodingFailsWithInvalidInput) {
+ RepeatedPtrField<ThreatEntrySet> additions;
+ ThreatEntrySet* addition = additions.Add();
+ addition->set_compression_type(RICE);
+ addition->mutable_rice_hashes()->set_num_entries(-1);
+ HashPrefixMap additions_map;
+ EXPECT_EQ(RICE_DECODING_FAILURE,
+ V4Store(task_runner_, store_path_)
+ .UpdateHashPrefixMapFromAdditions(additions, &additions_map));
+}
+#endif
+
+TEST_F(V4StoreTest, TestAdditionsWithRiceEncodingSucceeds) {
+ RepeatedPtrField<ThreatEntrySet> additions;
+ ThreatEntrySet* addition = additions.Add();
+ addition->set_compression_type(RICE);
+ RiceDeltaEncoding* rice_hashes = addition->mutable_rice_hashes();
+ rice_hashes->set_first_value(5);
+ rice_hashes->set_num_entries(3);
+ rice_hashes->set_rice_parameter(28);
+ // The following value is hand-crafted by getting inspiration from:
+ // https://goto.google.com/testlargenumbersriceencoded
+ // The value listed at that place fails the "integer overflow" check so I
+ // modified it until the decoder parsed it successfully.
+ rice_hashes->set_encoded_data(
+ "\xbf\xa8\x3f\xfb\xf\xf\x5e\x27\xe6\xc3\x1d\xc6\x38");
+ HashPrefixMap additions_map;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store(task_runner_, store_path_)
+ .UpdateHashPrefixMapFromAdditions(additions, &additions_map));
+ EXPECT_EQ(1u, additions_map.size());
+ EXPECT_EQ(std::string("\x5\0\0\0\fL\x93\xADV\x7F\xF6o\xCEo1\x81", 16),
+ additions_map[4]);
+}
+
+TEST_F(V4StoreTest, TestRemovalsWithRiceEncodingSucceeds) {
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "1111abcdefgh", &prefix_map_old));
+ HashPrefixMap prefix_map_additions;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(5, "22222bcdef", &prefix_map_additions));
+
+ V4Store store(task_runner_, store_path_);
+ std::string expected_checksum = std::string(
+ "\xA5\x8B\xCAsD\xC7\xF9\xCE\xD2\xF4\x4="
+ "\xB2\"\x82\x1A\xC1\xB8\x1F\x10\r\v\x9A\x93\xFD\xE1\xB8"
+ "B\x1Eh\xF7\xB4",
+ crypto::kSHA256Length);
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr,
+ expected_checksum));
+
+ // At this point, the store map looks like this:
+ // 4: 1111abcdefgh
+ // 5: 22222bcdef
+ // sorted: 1111, 22222, abcd, bcdef, efgh
+ // We'll now try to delete hashes at indexes 0, 3 and 4 in the sorted list.
+
+ std::unique_ptr<ListUpdateResponse> lur(new ListUpdateResponse);
+ lur->set_response_type(ListUpdateResponse::PARTIAL_UPDATE);
+ ThreatEntrySet* removal = lur->add_removals();
+ removal->set_compression_type(RICE);
+ RiceDeltaEncoding* rice_indices = removal->mutable_rice_indices();
+ rice_indices->set_first_value(0);
+ rice_indices->set_num_entries(2);
+ rice_indices->set_rice_parameter(2);
+ rice_indices->set_encoded_data("\x16");
+
+ bool called_back = false;
+ UpdatedStoreReadyCallback store_ready_callback =
+ base::Bind(&V4StoreTest::UpdatedStoreReadyAfterRiceRemovals,
+ base::Unretained(this), &called_back);
+ store.ApplyUpdate(std::move(lur), task_runner_, store_ready_callback);
+ task_runner_->RunPendingTasks();
+ base::RunLoop().RunUntilIdle();
+
+ // This ensures that the callback was called.
+ EXPECT_TRUE(called_back);
+}
+
+TEST_F(V4StoreTest, TestMergeUpdatesFailsChecksum) {
+ // Proof of checksum mismatch using python:
+ // >>> import hashlib
+ // >>> m = hashlib.sha256()
+ // >>> m.update("2222")
+ // >>> m.digest()
+ // "\xed\xee)\xf8\x82T;\x95f
+ // \xb2m\x0e\xe0\xe7\xe9P9\x9b\x1cB"\xf5\xde\x05\xe0d%\xb4\xc9\x95\xe9"
+
+ HashPrefixMap prefix_map_old;
+ EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+ V4Store::AddUnlumpedHashes(4, "2222", &prefix_map_old));
+ EXPECT_EQ(CHECKSUM_MISMATCH_FAILURE,
+ V4Store(task_runner_, store_path_)
+ .MergeUpdate(prefix_map_old, HashPrefixMap(), nullptr, "aawc"));
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing_db/v4_update_protocol_manager.cc b/chromium/components/safe_browsing_db/v4_update_protocol_manager.cc
index ab2142f6a61..ae43b2e3b40 100644
--- a/chromium/components/safe_browsing_db/v4_update_protocol_manager.cc
+++ b/chromium/components/safe_browsing_db/v4_update_protocol_manager.cc
@@ -12,6 +12,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/timer/timer.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/safe_browsing_db/safebrowsing.pb.h"
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
@@ -192,31 +193,32 @@ void V4UpdateProtocolManager::ScheduleNextUpdateAfterInterval(
&V4UpdateProtocolManager::IssueUpdateRequest);
}
-// static
-std::string V4UpdateProtocolManager::GetBase64SerializedUpdateRequestProto(
- const StoreStateMap& store_state_map) {
- DCHECK(!store_state_map.empty());
+std::string V4UpdateProtocolManager::GetBase64SerializedUpdateRequestProto() {
+ DCHECK(!store_state_map_->empty());
// Build the request. Client info and client states are not added to the
// request protocol buffer. Client info is passed as params in the url.
FetchThreatListUpdatesRequest request;
- for (const auto& entry : store_state_map) {
+ for (const auto& entry : *store_state_map_) {
const auto& list_to_update = entry.first;
const auto& state = entry.second;
ListUpdateRequest* list_update_request = request.add_list_update_requests();
- list_update_request->set_platform_type(list_to_update.platform_type);
+ list_update_request->set_platform_type(list_to_update.platform_type());
list_update_request->set_threat_entry_type(
- list_to_update.threat_entry_type);
- list_update_request->set_threat_type(list_to_update.threat_type);
+ list_to_update.threat_entry_type());
+ list_update_request->set_threat_type(list_to_update.threat_type());
if (!state.empty()) {
list_update_request->set_state(state);
}
- // TODO(vakh): Accept other compression formats also.
- // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567
list_update_request->mutable_constraints()->add_supported_compressions(RAW);
+ list_update_request->mutable_constraints()->add_supported_compressions(
+ RICE);
}
+ V4ProtocolManagerUtil::SetClientInfoFromConfig(request.mutable_client(),
+ config_);
+
// Serialize and Base64 encode.
std::string req_data, req_base64;
request.SerializeToString(&req_data);
@@ -277,8 +279,7 @@ void V4UpdateProtocolManager::IssueUpdateRequest() {
return;
}
- std::string req_base64 =
- GetBase64SerializedUpdateRequestProto(*store_state_map_.get());
+ std::string req_base64 = GetBase64SerializedUpdateRequestProto();
GURL update_url;
net::HttpRequestHeaders headers;
GetUpdateUrlAndHeaders(req_base64, &update_url, &headers);
@@ -286,6 +287,8 @@ void V4UpdateProtocolManager::IssueUpdateRequest() {
std::unique_ptr<net::URLFetcher> fetcher = net::URLFetcher::Create(
url_fetcher_id_++, update_url, net::URLFetcher::GET, this);
fetcher->SetExtraRequestHeaders(headers.ToString());
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ fetcher.get(), data_use_measurement::DataUseUserData::SAFE_BROWSING);
request_.reset(fetcher.release());
diff --git a/chromium/components/safe_browsing_db/v4_update_protocol_manager.h b/chromium/components/safe_browsing_db/v4_update_protocol_manager.h
index a8c1624b82d..7da1667c66f 100644
--- a/chromium/components/safe_browsing_db/v4_update_protocol_manager.h
+++ b/chromium/components/safe_browsing_db/v4_update_protocol_manager.h
@@ -89,6 +89,10 @@ class V4UpdateProtocolManager : public net::URLFetcherDelegate,
TestBase64EncodingUsesUrlEncoding);
friend class V4UpdateProtocolManagerFactoryImpl;
+ // Fills a FetchThreatListUpdatesRequest protocol buffer for a request.
+ // Returns the serialized and base64 URL encoded request as a string.
+ std::string GetBase64SerializedUpdateRequestProto();
+
// The method to populate |gurl| with the URL to be sent to the server.
// |request_base64| is the base64 encoded form of an instance of the protobuf
// FetchThreatListUpdatesRequest. Also sets the appropriate header values for
@@ -97,11 +101,6 @@ class V4UpdateProtocolManager : public net::URLFetcherDelegate,
GURL* gurl,
net::HttpRequestHeaders* headers) const;
- // Fills a FetchThreatListUpdatesRequest protocol buffer for a request.
- // Returns the serialized and base64 URL encoded request as a string.
- static std::string GetBase64SerializedUpdateRequestProto(
- const StoreStateMap& store_state_map);
-
// Parses the base64 encoded response received from the server as a
// FetchThreatListUpdatesResponse protobuf and returns each of the
// ListUpdateResponse protobufs contained in it as a vector.
diff --git a/chromium/components/safe_browsing_db/v4_update_protocol_manager_unittest.cc b/chromium/components/safe_browsing_db/v4_update_protocol_manager_unittest.cc
index fd5389da8e0..e8596e68e89 100644
--- a/chromium/components/safe_browsing_db/v4_update_protocol_manager_unittest.cc
+++ b/chromium/components/safe_browsing_db/v4_update_protocol_manager_unittest.cc
@@ -65,15 +65,19 @@ class V4UpdateProtocolManagerTest : public PlatformTest {
}
}
- std::unique_ptr<V4UpdateProtocolManager> CreateProtocolManager(
- const std::vector<ListUpdateResponse>& expected_lurs) {
+ V4ProtocolConfig GetProtocolConfig() {
V4ProtocolConfig config;
config.client_name = kClient;
config.version = kAppVer;
config.key_param = kKeyParam;
config.disable_auto_update = false;
+ return config;
+ }
+
+ std::unique_ptr<V4UpdateProtocolManager> CreateProtocolManager(
+ const std::vector<ListUpdateResponse>& expected_lurs) {
return V4UpdateProtocolManager::Create(
- NULL, config,
+ NULL, GetProtocolConfig(),
base::Bind(&V4UpdateProtocolManagerTest::ValidateGetUpdatesResults,
base::Unretained(this), expected_lurs));
}
@@ -81,14 +85,13 @@ class V4UpdateProtocolManagerTest : public PlatformTest {
void SetupStoreStates() {
store_state_map_ = base::MakeUnique<StoreStateMap>();
- UpdateListIdentifier win_url_malware(WINDOWS_PLATFORM, URL, MALWARE_THREAT);
+ ListIdentifier win_url_malware(WINDOWS_PLATFORM, URL, MALWARE_THREAT);
store_state_map_->insert({win_url_malware, "initial_state_1"});
- UpdateListIdentifier win_url_uws(WINDOWS_PLATFORM, URL, UNWANTED_SOFTWARE);
+ ListIdentifier win_url_uws(WINDOWS_PLATFORM, URL, UNWANTED_SOFTWARE);
store_state_map_->insert({win_url_uws, "initial_state_2"});
- UpdateListIdentifier win_exe_uws(WINDOWS_PLATFORM, EXECUTABLE,
- UNWANTED_SOFTWARE);
+ ListIdentifier win_exe_uws(WINDOWS_PLATFORM, EXECUTABLE, UNWANTED_SOFTWARE);
store_state_map_->insert({win_exe_uws, "initial_state_3"});
}
@@ -141,7 +144,6 @@ class V4UpdateProtocolManagerTest : public PlatformTest {
std::unique_ptr<StoreStateMap> store_state_map_;
};
-// TODO(vakh): Add many more tests.
TEST_F(V4UpdateProtocolManagerTest, TestGetUpdatesErrorHandlingNetwork) {
scoped_refptr<base::TestSimpleTaskRunner> runner(
new base::TestSimpleTaskRunner());
@@ -302,28 +304,20 @@ TEST_F(V4UpdateProtocolManagerTest, TestBase64EncodingUsesUrlEncoding) {
// NOTE(vakh): I handpicked this value for state by generating random strings
// and picked the one that leads to a '-' in the base64 url encoded request
// output.
- std::string state_minus = "z-R~3ruViQH";
- StoreStateMap store_state_map_minus{
- {UpdateListIdentifier(LINUX_PLATFORM, URL, MALWARE_THREAT), state_minus}};
+ store_state_map_->clear();
+ (*store_state_map_)[ListIdentifier(LINUX_PLATFORM, URL, MALWARE_THREAT)] =
+ "h8xfYqY>:R";
+ std::unique_ptr<V4UpdateProtocolManager> pm(
+ CreateProtocolManager(std::vector<ListUpdateResponse>({})));
+ pm->store_state_map_ = std::move(store_state_map_);
+
std::string encoded_request_with_minus =
- V4UpdateProtocolManager::GetBase64SerializedUpdateRequestProto(
- store_state_map_minus);
- EXPECT_EQ("GhcIARACGgt6LVJ-M3J1VmlRSCICIAEoAQ==", encoded_request_with_minus);
-
- // NOTE(vakh): Same process for chosing this string. I am representing it
- // in base64 encoded form because the actual state value contains non-ASCII
- // characters.
- std::string base64_encoded_state_underscore = "VTFfITBf4lBM";
- std::string state_underscore;
- base::Base64Decode(base64_encoded_state_underscore, &state_underscore);
- StoreStateMap store_state_map_underscore{
- {UpdateListIdentifier(LINUX_PLATFORM, URL, MALWARE_THREAT),
- state_underscore}};
- std::string encoded_request_with_underscore =
- V4UpdateProtocolManager::GetBase64SerializedUpdateRequestProto(
- store_state_map_underscore);
- EXPECT_EQ("GhUIARACGglVMV8hMF_iUEwiAiABKAE=",
- encoded_request_with_underscore);
+ pm->GetBase64SerializedUpdateRequestProto();
+ EXPECT_EQ("Cg8KCHVuaXR0ZXN0EgMxLjAaGAgBEAIaCmg4eGZZcVk-OlIiBCABIAIoAQ==",
+ encoded_request_with_minus);
+
+ // TODO(vakh): Add a similar test for underscore for completeness, although
+ // the '-' case is sufficient to prove that we are using URL encoding.
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_json.gypi b/chromium/components/safe_json.gypi
deleted file mode 100644
index 07e8f51a134..00000000000
--- a/chromium/components/safe_json.gypi
+++ /dev/null
@@ -1,126 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/safe_json
- 'target_name': 'safe_json',
- 'type': 'static_library',
- 'dependencies': [
- 'safe_json_mojo_bindings',
- '../base/base.gyp:base',
- '../components/components_strings.gyp:components_strings',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../ui/base/ui_base.gyp:ui_base',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'safe_json/android/component_jni_registrar.cc',
- 'safe_json/android/component_jni_registrar.h',
- 'safe_json/json_sanitizer.cc',
- 'safe_json/json_sanitizer.h',
- 'safe_json/json_sanitizer_android.cc',
- 'safe_json/safe_json_parser.cc',
- 'safe_json/safe_json_parser.h',
- 'safe_json/safe_json_parser_android.cc',
- 'safe_json/safe_json_parser_android.h',
- 'safe_json/safe_json_parser_impl.cc',
- 'safe_json/safe_json_parser_impl.h',
- ],
- 'conditions': [
- ['OS == "android"', {
- 'dependencies': [
- 'safe_json_jni_headers',
- ],
- 'sources!': [
- 'safe_json/json_sanitizer.cc',
- 'safe_json/safe_json_parser_impl.cc',
- 'safe_json/safe_json_parser_impl.h',
- ],
- }],
- ],
- },
- {
- 'target_name': 'safe_json_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- ':safe_json',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'safe_json/testing_json_parser.cc',
- 'safe_json/testing_json_parser.h',
- ],
- },
- {
- # GN version: //components/safe_json/public/interfaces
- 'target_name': 'safe_json_mojo_bindings',
- 'type': 'static_library',
- 'variables': {
- 'mojom_typemaps': [
- 'safe_json/public/interfaces/safe_json.typemap',
- ],
- },
- 'sources': [
- 'safe_json/public/interfaces/safe_json.mojom',
- ],
- 'includes': [ '../mojo/mojom_bindings_generator.gypi'],
- },
- {
- 'target_name': 'safe_json_parser_mojo',
- 'type': 'static_library',
- 'dependencies': [
- 'safe_json_mojo_bindings',
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../content/content.gyp:content_utility',
- '../ipc/ipc.gyp:ipc',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'safe_json/utility/safe_json_parser_mojo_impl.cc',
- 'safe_json/utility/safe_json_parser_mojo_impl.h',
- ],
- },
- ],
- 'conditions': [
- ['OS=="android"', {
- 'targets': [
- {
- # GN version: //components/safe_json/android:safe_json_java
- 'target_name': 'safe_json_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'variables': {
- 'java_in_dir': 'safe_json/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN version: //components/safe_json:jni
- 'target_name': 'safe_json_jni_headers',
- 'type': 'none',
- 'sources': [
- 'safe_json/android/java/src/org/chromium/components/safejson/JsonSanitizer.java',
- ],
- 'variables': {
- 'jni_gen_package': 'safe_json',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- ],
- }],
- ]
-}
diff --git a/chromium/components/safe_json/BUILD.gn b/chromium/components/safe_json/BUILD.gn
index d611979d47b..3040ba02cbf 100644
--- a/chromium/components/safe_json/BUILD.gn
+++ b/chromium/components/safe_json/BUILD.gn
@@ -6,8 +6,7 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-# GYP version: components/safe_json.gypi:safe_json
-source_set("safe_json") {
+static_library("safe_json") {
sources = [
"android/component_jni_registrar.cc",
"android/component_jni_registrar.h",
@@ -45,7 +44,6 @@ source_set("safe_json") {
}
}
-# GYP version: components/safe_json.gypi:safe_json_unittest_sources
source_set("unit_tests") {
testonly = true
sources = [
@@ -61,8 +59,7 @@ source_set("unit_tests") {
]
}
-# GYP version: components/safe_json.gypi:safe_json_test_support
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"testing_json_parser.cc",
diff --git a/chromium/components/safe_json/android/BUILD.gn b/chromium/components/safe_json/android/BUILD.gn
index bfb462d4cdd..a9f89fe59b3 100644
--- a/chromium/components/safe_json/android/BUILD.gn
+++ b/chromium/components/safe_json/android/BUILD.gn
@@ -7,13 +7,11 @@ import("//build/config/android/rules.gni")
_jni_sources =
[ "java/src/org/chromium/components/safejson/JsonSanitizer.java" ]
-# GYP: //components/safe_json.gypi:safe_json_jni_headers
generate_jni("safe_json_jni_headers") {
sources = _jni_sources
jni_package = "safe_json"
}
-# GYP: //components/safe_json.gypi:safe_json_java
android_library("safe_json_java") {
deps = [
"//base:base_java",
diff --git a/chromium/components/safe_json/json_sanitizer_android.cc b/chromium/components/safe_json/json_sanitizer_android.cc
index f7f007b7b6e..b69b8d2022e 100644
--- a/chromium/components/safe_json/json_sanitizer_android.cc
+++ b/chromium/components/safe_json/json_sanitizer_android.cc
@@ -14,6 +14,8 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "jni/JsonSanitizer_jni.h"
+using base::android::JavaParamRef;
+
namespace safe_json {
namespace {
@@ -71,7 +73,7 @@ void JsonSanitizerAndroid::Sanitize(const std::string& unsafe_json) {
// This will synchronously call either OnSuccess() or OnError().
Java_JsonSanitizer_sanitize(env, reinterpret_cast<jlong>(this),
- unsafe_json_java.obj());
+ unsafe_json_java);
}
void JsonSanitizerAndroid::OnSuccess(const std::string& json) {
diff --git a/chromium/components/safe_json/public/interfaces/BUILD.gn b/chromium/components/safe_json/public/interfaces/BUILD.gn
index 6e8b6de5e09..9596f7a10e7 100644
--- a/chromium/components/safe_json/public/interfaces/BUILD.gn
+++ b/chromium/components/safe_json/public/interfaces/BUILD.gn
@@ -8,4 +8,6 @@ mojom("interfaces") {
sources = [
"safe_json.mojom",
]
+
+ use_new_wrapper_types = false
}
diff --git a/chromium/components/safe_json/utility/BUILD.gn b/chromium/components/safe_json/utility/BUILD.gn
index 15dd59b0465..bc7024d6d64 100644
--- a/chromium/components/safe_json/utility/BUILD.gn
+++ b/chromium/components/safe_json/utility/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("utility") {
+static_library("utility") {
sources = [
"safe_json_parser_mojo_impl.cc",
"safe_json_parser_mojo_impl.h",
diff --git a/chromium/components/safe_json/utility/safe_json_parser_mojo_impl.cc b/chromium/components/safe_json/utility/safe_json_parser_mojo_impl.cc
index 45820757ce8..f3d11aae88e 100644
--- a/chromium/components/safe_json/utility/safe_json_parser_mojo_impl.cc
+++ b/chromium/components/safe_json/utility/safe_json_parser_mojo_impl.cc
@@ -9,20 +9,19 @@
#include "base/json/json_reader.h"
#include "base/values.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
namespace safe_json {
+SafeJsonParserMojoImpl::SafeJsonParserMojoImpl() = default;
+
+SafeJsonParserMojoImpl::~SafeJsonParserMojoImpl() = default;
+
// static
void SafeJsonParserMojoImpl::Create(
mojo::InterfaceRequest<mojom::SafeJsonParser> request) {
- new SafeJsonParserMojoImpl(std::move(request));
-}
-
-SafeJsonParserMojoImpl::SafeJsonParserMojoImpl(
- mojo::InterfaceRequest<mojom::SafeJsonParser> request)
- : binding_(this, std::move(request)) {}
-
-SafeJsonParserMojoImpl::~SafeJsonParserMojoImpl() {
+ mojo::MakeStrongBinding(base::MakeUnique<SafeJsonParserMojoImpl>(),
+ std::move(request));
}
void SafeJsonParserMojoImpl::Parse(const mojo::String& json,
diff --git a/chromium/components/safe_json/utility/safe_json_parser_mojo_impl.h b/chromium/components/safe_json/utility/safe_json_parser_mojo_impl.h
index cb407b7d304..d81c58882ba 100644
--- a/chromium/components/safe_json/utility/safe_json_parser_mojo_impl.h
+++ b/chromium/components/safe_json/utility/safe_json_parser_mojo_impl.h
@@ -9,24 +9,20 @@
#include "base/macros.h"
#include "components/safe_json/public/interfaces/safe_json.mojom.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
namespace safe_json {
class SafeJsonParserMojoImpl : public mojom::SafeJsonParser {
public:
+ SafeJsonParserMojoImpl();
+ ~SafeJsonParserMojoImpl() override;
+
static void Create(mojo::InterfaceRequest<mojom::SafeJsonParser> request);
private:
- explicit SafeJsonParserMojoImpl(
- mojo::InterfaceRequest<mojom::SafeJsonParser> request);
- ~SafeJsonParserMojoImpl() override;
-
// mojom::SafeJsonParser implementation.
void Parse(const mojo::String& json, const ParseCallback& callback) override;
- mojo::StrongBinding<mojom::SafeJsonParser> binding_;
-
DISALLOW_COPY_AND_ASSIGN(SafeJsonParserMojoImpl);
};
diff --git a/chromium/components/scheduler/BUILD.gn b/chromium/components/scheduler/BUILD.gn
deleted file mode 100644
index a66e88284d1..00000000000
--- a/chromium/components/scheduler/BUILD.gn
+++ /dev/null
@@ -1,178 +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.
-
-# GYP version: components/scheduler.gypi:scheduler
-component("scheduler") {
- sources = [
- "base/cancelable_closure_holder.cc",
- "base/cancelable_closure_holder.h",
- "base/enqueue_order.cc",
- "base/enqueue_order.h",
- "base/lazy_now.cc",
- "base/lazy_now.h",
- "base/pollable_thread_safe_flag.cc",
- "base/pollable_thread_safe_flag.h",
- "base/real_time_domain.cc",
- "base/real_time_domain.h",
- "base/task_queue.h",
- "base/task_queue_impl.cc",
- "base/task_queue_impl.h",
- "base/task_queue_manager.cc",
- "base/task_queue_manager.h",
- "base/task_queue_manager_delegate.h",
- "base/task_queue_selector.cc",
- "base/task_queue_selector.h",
- "base/time_domain.cc",
- "base/time_domain.h",
- "base/virtual_time_domain.cc",
- "base/virtual_time_domain.h",
- "base/work_queue.cc",
- "base/work_queue.h",
- "base/work_queue_sets.cc",
- "base/work_queue_sets.h",
- "child/child_scheduler.h",
- "child/compositor_worker_scheduler.cc",
- "child/compositor_worker_scheduler.h",
- "child/idle_helper.cc",
- "child/idle_helper.h",
- "child/scheduler_helper.cc",
- "child/scheduler_helper.h",
- "child/scheduler_tqm_delegate.h",
- "child/scheduler_tqm_delegate_impl.cc",
- "child/scheduler_tqm_delegate_impl.h",
- "child/single_thread_idle_task_runner.cc",
- "child/single_thread_idle_task_runner.h",
- "child/web_scheduler_impl.cc",
- "child/web_scheduler_impl.h",
- "child/web_task_runner_impl.cc",
- "child/web_task_runner_impl.h",
- "child/webthread_base.cc",
- "child/webthread_base.h",
- "child/webthread_impl_for_worker_scheduler.cc",
- "child/webthread_impl_for_worker_scheduler.h",
- "child/worker_scheduler.cc",
- "child/worker_scheduler.h",
- "child/worker_scheduler_impl.cc",
- "child/worker_scheduler_impl.h",
- "renderer/auto_advancing_virtual_time_domain.cc",
- "renderer/auto_advancing_virtual_time_domain.h",
- "renderer/deadline_task_runner.cc",
- "renderer/deadline_task_runner.h",
- "renderer/idle_time_estimator.cc",
- "renderer/idle_time_estimator.h",
- "renderer/render_widget_scheduling_state.cc",
- "renderer/render_widget_scheduling_state.h",
- "renderer/render_widget_signals.cc",
- "renderer/render_widget_signals.h",
- "renderer/renderer_scheduler.cc",
- "renderer/renderer_scheduler.h",
- "renderer/renderer_scheduler_impl.cc",
- "renderer/renderer_scheduler_impl.h",
- "renderer/renderer_web_scheduler_impl.cc",
- "renderer/renderer_web_scheduler_impl.h",
- "renderer/task_cost_estimator.cc",
- "renderer/task_cost_estimator.h",
- "renderer/throttled_time_domain.cc",
- "renderer/throttled_time_domain.h",
- "renderer/throttling_helper.cc",
- "renderer/throttling_helper.h",
- "renderer/user_model.cc",
- "renderer/user_model.h",
- "renderer/web_frame_scheduler_impl.cc",
- "renderer/web_frame_scheduler_impl.h",
- "renderer/web_view_scheduler_impl.cc",
- "renderer/web_view_scheduler_impl.h",
- "renderer/webthread_impl_for_renderer_scheduler.cc",
- "renderer/webthread_impl_for_renderer_scheduler.h",
- "scheduler_export.h",
- ]
-
- defines = [ "SCHEDULER_IMPLEMENTATION" ]
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
- deps = [
- ":common",
- "//base",
- "//cc:cc",
- "//third_party/WebKit/public:blink",
- "//ui/gfx:gfx",
- ]
-
- public_deps = [
- "//third_party/WebKit/public:blink",
- ]
-}
-
-# GYP version: components/scheduler.gypi:scheduler_common
-source_set("common") {
- sources = [
- "common/scheduler_switches.cc",
- "common/scheduler_switches.h",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
-
- sources = [
- "base/task_queue_manager_delegate_for_test.cc",
- "base/task_queue_manager_delegate_for_test.h",
- "base/task_queue_manager_unittest.cc",
- "base/task_queue_selector_unittest.cc",
- "base/test_always_fail_time_source.cc",
- "base/test_always_fail_time_source.h",
- "base/test_time_source.cc",
- "base/test_time_source.h",
- "base/time_domain_unittest.cc",
- "base/work_queue_sets_unittest.cc",
- "child/idle_helper_unittest.cc",
- "child/scheduler_helper_unittest.cc",
- "child/scheduler_tqm_delegate_for_test.cc",
- "child/scheduler_tqm_delegate_for_test.h",
- "child/scheduler_tqm_delegate_impl_unittest.cc",
- "child/webthread_impl_for_worker_scheduler_unittest.cc",
- "child/worker_scheduler_impl_unittest.cc",
- "renderer/auto_advancing_virtual_time_domain_unittest.cc",
- "renderer/deadline_task_runner_unittest.cc",
- "renderer/idle_time_estimator_unittest.cc",
- "renderer/render_widget_signals_unittest.cpp",
- "renderer/renderer_scheduler_impl_unittest.cc",
- "renderer/task_cost_estimator_unittest.cc",
- "renderer/throttling_helper_unittest.cc",
- "renderer/user_model_unittest.cc",
- "renderer/web_view_scheduler_impl_unittest.cc",
- "renderer/webthread_impl_for_renderer_scheduler_unittest.cc",
- ]
-
- deps = [
- ":scheduler",
- "//base/test:test_support",
- "//cc:test_support",
- "//testing/gmock",
- "//testing/gtest",
- ]
-}
-
-# GYP version: components/scheduler.gypi:scheduler_test_support
-source_set("test_support") {
- testonly = true
-
- sources = [
- "test/lazy_scheduler_message_loop_delegate_for_tests.cc",
- "test/lazy_scheduler_message_loop_delegate_for_tests.h",
- "test/renderer_scheduler_test_support.cc",
- "test/renderer_scheduler_test_support.h",
- ]
-
- deps = [
- "//third_party/WebKit/public:blink",
- ]
-
- public_deps = [
- ":scheduler",
- "//base",
- ]
-}
diff --git a/chromium/components/scheduler/DEPS b/chromium/components/scheduler/DEPS
deleted file mode 100644
index a705142778f..00000000000
--- a/chromium/components/scheduler/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "-components/scheduler",
- "+components/scheduler/common",
-]
diff --git a/chromium/components/scheduler/OWNERS b/chromium/components/scheduler/OWNERS
deleted file mode 100644
index 6dc4cb43ab1..00000000000
--- a/chromium/components/scheduler/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-alexclarke@chromium.org
-rmcilroy@chromium.org
-skyostil@chromium.org
diff --git a/chromium/components/scheduler/base/DEPS b/chromium/components/scheduler/base/DEPS
deleted file mode 100644
index 5d86a1bc60e..00000000000
--- a/chromium/components/scheduler/base/DEPS
+++ /dev/null
@@ -1,9 +0,0 @@
-include_rules = [
- "+components/scheduler/scheduler_export.h",
-]
-
-specific_include_rules = {
- "(test_time_source|.*test)\.cc": [
- "+cc/test",
- ],
-}
diff --git a/chromium/components/scheduler/base/cancelable_closure_holder.cc b/chromium/components/scheduler/base/cancelable_closure_holder.cc
deleted file mode 100644
index 54c1462f5d3..00000000000
--- a/chromium/components/scheduler/base/cancelable_closure_holder.cc
+++ /dev/null
@@ -1,28 +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 "components/scheduler/base/cancelable_closure_holder.h"
-
-namespace scheduler {
-
-CancelableClosureHolder::CancelableClosureHolder() {}
-
-CancelableClosureHolder::~CancelableClosureHolder() {}
-
-void CancelableClosureHolder::Reset(const base::Closure& callback) {
- callback_ = callback;
- cancelable_callback_.Reset(callback_);
-}
-
-void CancelableClosureHolder::Cancel() {
- DCHECK(!callback_.is_null());
- cancelable_callback_.Reset(callback_);
-}
-
-const base::Closure& CancelableClosureHolder::callback() const {
- DCHECK(!callback_.is_null());
- return cancelable_callback_.callback();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/cancelable_closure_holder.h b/chromium/components/scheduler/base/cancelable_closure_holder.h
deleted file mode 100644
index 5254cd490a5..00000000000
--- a/chromium/components/scheduler/base/cancelable_closure_holder.h
+++ /dev/null
@@ -1,40 +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 COMPONENTS_SCHEDULER_BASE_CANCELABLE_CLOSURE_HOLDER_H_
-#define COMPONENTS_SCHEDULER_BASE_CANCELABLE_CLOSURE_HOLDER_H_
-
-#include "base/cancelable_callback.h"
-#include "base/macros.h"
-
-namespace scheduler {
-
-// A CancelableClosureHolder is a CancelableCallback which resets its wrapped
-// callback with a cached closure whenever it is canceled.
-class CancelableClosureHolder {
- public:
- CancelableClosureHolder();
- ~CancelableClosureHolder();
-
- // Resets the closure to be wrapped by the cancelable callback. Cancels any
- // outstanding callbacks.
- void Reset(const base::Closure& callback);
-
- // Cancels any outstanding closures returned by callback().
- void Cancel();
-
- // Returns a callback that will be disabled by calling Cancel(). Callback
- // must have been set using Reset() before calling this function.
- const base::Closure& callback() const;
-
- private:
- base::Closure callback_;
- base::CancelableClosure cancelable_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(CancelableClosureHolder);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_CANCELABLE_CLOSURE_HOLDER_H_
diff --git a/chromium/components/scheduler/base/enqueue_order.cc b/chromium/components/scheduler/base/enqueue_order.cc
deleted file mode 100644
index dd04bbd4023..00000000000
--- a/chromium/components/scheduler/base/enqueue_order.cc
+++ /dev/null
@@ -1,20 +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 "components/scheduler/base/enqueue_order.h"
-
-namespace scheduler {
-namespace internal {
-
-EnqueueOrderGenerator::EnqueueOrderGenerator() : enqueue_order_(0) {}
-
-EnqueueOrderGenerator::~EnqueueOrderGenerator() {}
-
-EnqueueOrder EnqueueOrderGenerator::GenerateNext() {
- base::AutoLock lock(lock_);
- return enqueue_order_++;
-}
-
-} // namespace internal
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/enqueue_order.h b/chromium/components/scheduler/base/enqueue_order.h
deleted file mode 100644
index 21001ffc284..00000000000
--- a/chromium/components/scheduler/base/enqueue_order.h
+++ /dev/null
@@ -1,32 +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 COMPONENTS_SCHEDULER_BASE_ENQUEUE_ORDER_H_
-#define COMPONENTS_SCHEDULER_BASE_ENQUEUE_ORDER_H_
-
-#include <stdint.h>
-
-#include "base/synchronization/lock.h"
-
-namespace scheduler {
-namespace internal {
-
-using EnqueueOrder = uint64_t;
-
-class EnqueueOrderGenerator {
- public:
- EnqueueOrderGenerator();
- ~EnqueueOrderGenerator();
-
- EnqueueOrder GenerateNext();
-
- private:
- base::Lock lock_;
- EnqueueOrder enqueue_order_;
-};
-
-} // namespace internal
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_ENQUEUE_ORDER_H_
diff --git a/chromium/components/scheduler/base/lazy_now.cc b/chromium/components/scheduler/base/lazy_now.cc
deleted file mode 100644
index 3492ca6766d..00000000000
--- a/chromium/components/scheduler/base/lazy_now.cc
+++ /dev/null
@@ -1,17 +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 "components/scheduler/base/lazy_now.h"
-
-#include "base/time/tick_clock.h"
-#include "components/scheduler/base/task_queue_manager.h"
-
-namespace scheduler {
-base::TimeTicks LazyNow::Now() {
- if (now_.is_null())
- now_ = tick_clock_->NowTicks();
- return now_;
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/lazy_now.h b/chromium/components/scheduler/base/lazy_now.h
deleted file mode 100644
index 959a2450947..00000000000
--- a/chromium/components/scheduler/base/lazy_now.h
+++ /dev/null
@@ -1,36 +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 COMPONENTS_SCHEDULER_BASE_LAZY_NOW_H_
-#define COMPONENTS_SCHEDULER_BASE_LAZY_NOW_H_
-
-#include "base/time/time.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-class TickClock;
-}
-
-namespace scheduler {
-
-// Now() is somewhat expensive so it makes sense not to call Now() unless we
-// really need to.
-class SCHEDULER_EXPORT LazyNow {
- public:
- explicit LazyNow(base::TimeTicks now) : tick_clock_(nullptr), now_(now) {
- DCHECK(!now.is_null());
- }
-
- explicit LazyNow(base::TickClock* tick_clock) : tick_clock_(tick_clock) {}
-
- base::TimeTicks Now();
-
- private:
- base::TickClock* tick_clock_; // NOT OWNED
- base::TimeTicks now_;
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_LAZY_NOW_H_
diff --git a/chromium/components/scheduler/base/pollable_thread_safe_flag.cc b/chromium/components/scheduler/base/pollable_thread_safe_flag.cc
deleted file mode 100644
index 13d5b6f5ec8..00000000000
--- a/chromium/components/scheduler/base/pollable_thread_safe_flag.cc
+++ /dev/null
@@ -1,19 +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 "components/scheduler/base/pollable_thread_safe_flag.h"
-
-PollableThreadSafeFlag::PollableThreadSafeFlag(base::Lock* write_lock_)
- : flag_(false), write_lock_(write_lock_) {}
-
-PollableThreadSafeFlag::~PollableThreadSafeFlag() {}
-
-void PollableThreadSafeFlag::SetWhileLocked(bool value) {
- write_lock_->AssertAcquired();
- base::subtle::Release_Store(&flag_, value);
-}
-
-bool PollableThreadSafeFlag::IsSet() const {
- return base::subtle::Acquire_Load(&flag_) != false;
-}
diff --git a/chromium/components/scheduler/base/pollable_thread_safe_flag.h b/chromium/components/scheduler/base/pollable_thread_safe_flag.h
deleted file mode 100644
index 8e37b690595..00000000000
--- a/chromium/components/scheduler/base/pollable_thread_safe_flag.h
+++ /dev/null
@@ -1,36 +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 COMPONENTS_SCHEDULER_BASE_POLLABLE_THREAD_SAFE_FLAG_H_
-#define COMPONENTS_SCHEDULER_BASE_POLLABLE_THREAD_SAFE_FLAG_H_
-
-#include "base/atomicops.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-
-// A PollableThreadSafeFlag can be polled without requiring a lock, but can only
-// be updated if a lock is held. This enables lock-free checking as to whether a
-// condition has changed, while protecting operations which update the condition
-// with a lock. You must ensure that the flag is only updated within the same
-// lock-protected critical section as any other variables on which the condition
-// depends.
-class PollableThreadSafeFlag {
- public:
- explicit PollableThreadSafeFlag(base::Lock* write_lock);
- ~PollableThreadSafeFlag();
-
- // Set the flag. May only be called if |write_lock| is held.
- void SetWhileLocked(bool value);
-
- // Returns true iff the flag is set to true.
- bool IsSet() const;
-
- private:
- base::subtle::Atomic32 flag_;
- base::Lock* write_lock_; // Not owned.
-
- DISALLOW_COPY_AND_ASSIGN(PollableThreadSafeFlag);
-};
-
-#endif // COMPONENTS_SCHEDULER_BASE_POLLABLE_THREAD_SAFE_FLAG_H_
diff --git a/chromium/components/scheduler/base/real_time_domain.cc b/chromium/components/scheduler/base/real_time_domain.cc
deleted file mode 100644
index a452b978e91..00000000000
--- a/chromium/components/scheduler/base/real_time_domain.cc
+++ /dev/null
@@ -1,73 +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 "components/scheduler/base/real_time_domain.h"
-
-#include "base/bind.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/task_queue_manager.h"
-#include "components/scheduler/base/task_queue_manager_delegate.h"
-
-namespace scheduler {
-
-RealTimeDomain::RealTimeDomain(const char* tracing_category)
- : TimeDomain(nullptr),
- tracing_category_(tracing_category),
- task_queue_manager_(nullptr) {}
-
-RealTimeDomain::RealTimeDomain(TimeDomain::Observer* observer,
- const char* tracing_category)
- : TimeDomain(observer),
- tracing_category_(tracing_category),
- task_queue_manager_(nullptr) {}
-
-RealTimeDomain::~RealTimeDomain() {}
-
-void RealTimeDomain::OnRegisterWithTaskQueueManager(
- TaskQueueManager* task_queue_manager) {
- task_queue_manager_ = task_queue_manager;
- DCHECK(task_queue_manager_);
-}
-
-LazyNow RealTimeDomain::CreateLazyNow() const {
- return task_queue_manager_->CreateLazyNow();
-}
-
-base::TimeTicks RealTimeDomain::Now() const {
- return task_queue_manager_->delegate()->NowTicks();
-}
-
-void RealTimeDomain::RequestWakeup(base::TimeTicks now, base::TimeDelta delay) {
- // NOTE this is only called if the scheduled runtime is sooner than any
- // previously scheduled runtime, or there is no (outstanding) previously
- // scheduled runtime.
- task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, now, delay);
-}
-
-bool RealTimeDomain::MaybeAdvanceTime() {
- base::TimeTicks next_run_time;
- if (!NextScheduledRunTime(&next_run_time))
- return false;
-
- base::TimeTicks now = Now();
- if (now >= next_run_time)
- return true; // Causes DoWork to post a continuation.
-
- base::TimeDelta delay = next_run_time - now;
- TRACE_EVENT1(tracing_category_, "RealTimeDomain::MaybeAdvanceTime",
- "delay_ms", delay.InMillisecondsF());
-
- // The next task is sometime in the future, make sure we schedule a DoWork to
- // run it.
- task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, now, delay);
- return false;
-}
-
-void RealTimeDomain::AsValueIntoInternal(
- base::trace_event::TracedValue* state) const {}
-
-const char* RealTimeDomain::GetName() const {
- return "RealTimeDomain";
-}
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/real_time_domain.h b/chromium/components/scheduler/base/real_time_domain.h
deleted file mode 100644
index fa20ba7a077..00000000000
--- a/chromium/components/scheduler/base/real_time_domain.h
+++ /dev/null
@@ -1,44 +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 COMPONENTS_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_
-#define COMPONENTS_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "components/scheduler/base/time_domain.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-class SCHEDULER_EXPORT RealTimeDomain : public TimeDomain {
- public:
- explicit RealTimeDomain(const char* tracing_category);
- RealTimeDomain(TimeDomain::Observer* observer, const char* tracing_category);
- ~RealTimeDomain() override;
-
- // TimeDomain implementation:
- LazyNow CreateLazyNow() const override;
- base::TimeTicks Now() const override;
- bool MaybeAdvanceTime() override;
- const char* GetName() const override;
-
- protected:
- void OnRegisterWithTaskQueueManager(
- TaskQueueManager* task_queue_manager) override;
- void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override;
- void AsValueIntoInternal(
- base::trace_event::TracedValue* state) const override;
-
- private:
- const char* tracing_category_; // NOT OWNED
- TaskQueueManager* task_queue_manager_; // NOT OWNED
-
- DISALLOW_COPY_AND_ASSIGN(RealTimeDomain);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_
diff --git a/chromium/components/scheduler/base/task_queue.h b/chromium/components/scheduler/base/task_queue.h
deleted file mode 100644
index b3a316362ce..00000000000
--- a/chromium/components/scheduler/base/task_queue.h
+++ /dev/null
@@ -1,216 +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 COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_H_
-#define COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_H_
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/trace_event/trace_event.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-namespace trace_event {
-class BlameContext;
-}
-}
-
-namespace scheduler {
-class LazyNow;
-class TimeDomain;
-
-class SCHEDULER_EXPORT TaskQueue : public base::SingleThreadTaskRunner {
- public:
- TaskQueue() {}
-
- // Unregisters the task queue after which no tasks posted to it will run and
- // the TaskQueueManager's reference to it will be released soon.
- virtual void UnregisterTaskQueue() = 0;
-
- enum QueuePriority {
- // Queues with control priority will run before any other queue, and will
- // explicitly starve other queues. Typically this should only be used for
- // private queues which perform control operations.
- CONTROL_PRIORITY,
- // Queues with high priority will be selected preferentially over normal or
- // best effort queues. The selector will ensure that high priority queues
- // cannot completely starve normal priority queues.
- HIGH_PRIORITY,
- // Queues with normal priority are the default.
- NORMAL_PRIORITY,
- // Queues with best effort priority will only be run if all other queues are
- // empty. They can be starved by the other queues.
- BEST_EFFORT_PRIORITY,
- // Must be the last entry.
- QUEUE_PRIORITY_COUNT,
- FIRST_QUEUE_PRIORITY = CONTROL_PRIORITY,
- };
-
- // Keep TaskQueue::PumpPolicyToString in sync with this enum.
- enum class PumpPolicy {
- // Tasks posted to an incoming queue with an AUTO pump policy will be
- // automatically scheduled for execution or transferred to the work queue
- // automatically.
- AUTO,
- // Tasks posted to an incoming queue with an AFTER_WAKEUP pump policy
- // will be scheduled for execution or transferred to the work queue
- // automatically but only after another queue has executed a task.
- AFTER_WAKEUP,
- // Tasks posted to an incoming queue with a MANUAL will not be
- // automatically scheduled for execution or transferred to the work queue.
- // Instead, the selector should call PumpQueue() when necessary to bring
- // in new tasks for execution.
- MANUAL,
- // Must be last entry.
- PUMP_POLICY_COUNT,
- FIRST_PUMP_POLICY = AUTO,
- };
-
- // Keep TaskQueue::WakeupPolicyToString in sync with this enum.
- enum class WakeupPolicy {
- // Tasks run on a queue with CAN_WAKE_OTHER_QUEUES wakeup policy can
- // cause queues with the AFTER_WAKEUP PumpPolicy to be woken up.
- CAN_WAKE_OTHER_QUEUES,
- // Tasks run on a queue with DONT_WAKE_OTHER_QUEUES won't cause queues
- // with the AFTER_WAKEUP PumpPolicy to be woken up.
- DONT_WAKE_OTHER_QUEUES,
- // Must be last entry.
- WAKEUP_POLICY_COUNT,
- FIRST_WAKEUP_POLICY = CAN_WAKE_OTHER_QUEUES,
- };
-
- // Options for constructing a TaskQueue. Once set the |name|,
- // |should_monitor_quiescence| and |wakeup_policy| are immutable. The
- // |pump_policy| can be mutated with |SetPumpPolicy()|.
- struct Spec {
- // Note |name| must have application lifetime.
- explicit Spec(const char* name)
- : name(name),
- should_monitor_quiescence(false),
- pump_policy(TaskQueue::PumpPolicy::AUTO),
- wakeup_policy(TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES),
- time_domain(nullptr),
- should_notify_observers(true),
- should_report_when_execution_blocked(false) {}
-
- Spec SetShouldMonitorQuiescence(bool should_monitor) {
- should_monitor_quiescence = should_monitor;
- return *this;
- }
-
- Spec SetPumpPolicy(PumpPolicy policy) {
- pump_policy = policy;
- return *this;
- }
-
- Spec SetWakeupPolicy(WakeupPolicy policy) {
- wakeup_policy = policy;
- return *this;
- }
-
- Spec SetShouldNotifyObservers(bool run_observers) {
- should_notify_observers = run_observers;
- return *this;
- }
-
- Spec SetTimeDomain(TimeDomain* domain) {
- time_domain = domain;
- return *this;
- }
-
- // See TaskQueueManager::Observer::OnTriedToExecuteBlockedTask.
- Spec SetShouldReportWhenExecutionBlocked(bool should_report) {
- should_report_when_execution_blocked = should_report;
- return *this;
- }
-
- const char* name;
- bool should_monitor_quiescence;
- TaskQueue::PumpPolicy pump_policy;
- TaskQueue::WakeupPolicy wakeup_policy;
- TimeDomain* time_domain;
- bool should_notify_observers;
- bool should_report_when_execution_blocked;
- };
-
- // Enable or disable task execution for this queue. NOTE this must be called
- // on the thread this TaskQueue was created by.
- virtual void SetQueueEnabled(bool enabled) = 0;
-
- // NOTE this must be called on the thread this TaskQueue was created by.
- virtual bool IsQueueEnabled() const = 0;
-
- // Returns true if the queue is completely empty.
- virtual bool IsEmpty() const = 0;
-
- // Returns true if the queue has work that's ready to execute now, or if it
- // would have if the queue was pumped. NOTE this must be called on the thread
- // this TaskQueue was created by.
- virtual bool HasPendingImmediateWork() const = 0;
-
- // Returns true if tasks can't run now but could if the queue was pumped.
- virtual bool NeedsPumping() const = 0;
-
- // Can be called on any thread.
- virtual const char* GetName() const = 0;
-
- // Set the priority of the queue to |priority|. NOTE this must be called on
- // the thread this TaskQueue was created by.
- virtual void SetQueuePriority(QueuePriority priority) = 0;
-
- // Returns the current queue priority.
- virtual QueuePriority GetQueuePriority() const = 0;
-
- // Set the pumping policy of the queue to |pump_policy|. NOTE this must be
- // called on the thread this TaskQueue was created by.
- virtual void SetPumpPolicy(PumpPolicy pump_policy) = 0;
-
- // Returns the current PumpPolicy. NOTE this must be called on the thread this
- // TaskQueue was created by.
- virtual PumpPolicy GetPumpPolicy() const = 0;
-
- // Reloads new tasks from the incoming queue into the work queue, regardless
- // of whether the work queue is empty or not. After this, the function ensures
- // that the tasks in the work queue, if any, are scheduled for execution.
- //
- // This function only needs to be called if automatic pumping is disabled.
- // By default automatic pumping is enabled for all queues. NOTE this must be
- // called on the thread this TaskQueue was created by.
- //
- // The |may_post_dowork| parameter controls whether or not PumpQueue calls
- // TaskQueueManager::MaybeScheduleImmediateWork.
- // TODO(alexclarke): Add a base::RunLoop observer so we can get rid of
- // |may_post_dowork|.
- virtual void PumpQueue(LazyNow* lazy_now, bool may_post_dowork) = 0;
-
- // These functions can only be called on the same thread that the task queue
- // manager executes its tasks on.
- virtual void AddTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) = 0;
- virtual void RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) = 0;
-
- // Set the blame context which is entered and left while executing tasks from
- // this task queue. |blame_context| must be null or outlive this task queue.
- // Must be called on the thread this TaskQueue was created by.
- virtual void SetBlameContext(
- base::trace_event::BlameContext* blame_context) = 0;
-
- // Removes the task queue from the previous TimeDomain and adds it to
- // |domain|. This is a moderately expensive operation.
- virtual void SetTimeDomain(TimeDomain* domain) = 0;
-
- // Returns the queue's current TimeDomain. Can be called from any thread.
- virtual TimeDomain* GetTimeDomain() const = 0;
-
- protected:
- ~TaskQueue() override {}
-
- DISALLOW_COPY_AND_ASSIGN(TaskQueue);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_H_
diff --git a/chromium/components/scheduler/base/task_queue_impl.cc b/chromium/components/scheduler/base/task_queue_impl.cc
deleted file mode 100644
index 0dc5f648000..00000000000
--- a/chromium/components/scheduler/base/task_queue_impl.cc
+++ /dev/null
@@ -1,705 +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 "components/scheduler/base/task_queue_impl.h"
-
-#include "base/trace_event/blame_context.h"
-#include "components/scheduler/base/task_queue_manager.h"
-#include "components/scheduler/base/task_queue_manager_delegate.h"
-#include "components/scheduler/base/time_domain.h"
-#include "components/scheduler/base/work_queue.h"
-
-namespace scheduler {
-namespace internal {
-
-TaskQueueImpl::TaskQueueImpl(
- TaskQueueManager* task_queue_manager,
- TimeDomain* time_domain,
- const Spec& spec,
- const char* disabled_by_default_tracing_category,
- const char* disabled_by_default_verbose_tracing_category)
- : thread_id_(base::PlatformThread::CurrentId()),
- any_thread_(task_queue_manager, spec.pump_policy, time_domain),
- name_(spec.name),
- disabled_by_default_tracing_category_(
- disabled_by_default_tracing_category),
- disabled_by_default_verbose_tracing_category_(
- disabled_by_default_verbose_tracing_category),
- main_thread_only_(task_queue_manager,
- spec.pump_policy,
- this,
- time_domain),
- wakeup_policy_(spec.wakeup_policy),
- should_monitor_quiescence_(spec.should_monitor_quiescence),
- should_notify_observers_(spec.should_notify_observers),
- should_report_when_execution_blocked_(
- spec.should_report_when_execution_blocked) {
- DCHECK(time_domain);
- time_domain->RegisterQueue(this);
-}
-
-TaskQueueImpl::~TaskQueueImpl() {
-#if DCHECK_IS_ON()
- base::AutoLock lock(any_thread_lock_);
- // NOTE this check shouldn't fire because |TaskQueueManager::queues_|
- // contains a strong reference to this TaskQueueImpl and the TaskQueueManager
- // destructor calls UnregisterTaskQueue on all task queues.
- DCHECK(any_thread().task_queue_manager == nullptr)
- << "UnregisterTaskQueue must be called first!";
-
-#endif
-}
-
-TaskQueueImpl::Task::Task()
- : PendingTask(tracked_objects::Location(),
- base::Closure(),
- base::TimeTicks(),
- true),
-#ifndef NDEBUG
- enqueue_order_set_(false),
-#endif
- enqueue_order_(0) {
- sequence_num = 0;
-}
-
-TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from,
- const base::Closure& task,
- base::TimeTicks desired_run_time,
- EnqueueOrder sequence_number,
- bool nestable)
- : PendingTask(posted_from, task, desired_run_time, nestable),
-#ifndef NDEBUG
- enqueue_order_set_(false),
-#endif
- enqueue_order_(0) {
- sequence_num = sequence_number;
-}
-
-TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from,
- const base::Closure& task,
- base::TimeTicks desired_run_time,
- EnqueueOrder sequence_number,
- bool nestable,
- EnqueueOrder enqueue_order)
- : PendingTask(posted_from, task, desired_run_time, nestable),
-#ifndef NDEBUG
- enqueue_order_set_(true),
-#endif
- enqueue_order_(enqueue_order) {
- sequence_num = sequence_number;
-}
-
-TaskQueueImpl::AnyThread::AnyThread(TaskQueueManager* task_queue_manager,
- PumpPolicy pump_policy,
- TimeDomain* time_domain)
- : task_queue_manager(task_queue_manager),
- pump_policy(pump_policy),
- time_domain(time_domain) {}
-
-TaskQueueImpl::AnyThread::~AnyThread() {}
-
-TaskQueueImpl::MainThreadOnly::MainThreadOnly(
- TaskQueueManager* task_queue_manager,
- PumpPolicy pump_policy,
- TaskQueueImpl* task_queue,
- TimeDomain* time_domain)
- : task_queue_manager(task_queue_manager),
- pump_policy(pump_policy),
- time_domain(time_domain),
- delayed_work_queue(new WorkQueue(task_queue, "delayed")),
- immediate_work_queue(new WorkQueue(task_queue, "immediate")),
- set_index(0),
- is_enabled(true),
- blame_context(nullptr) {}
-
-TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {}
-
-void TaskQueueImpl::UnregisterTaskQueue() {
- base::AutoLock lock(any_thread_lock_);
- if (main_thread_only().time_domain)
- main_thread_only().time_domain->UnregisterQueue(this);
- if (!any_thread().task_queue_manager)
- return;
- any_thread().time_domain = nullptr;
- main_thread_only().time_domain = nullptr;
- any_thread().task_queue_manager->UnregisterTaskQueue(this);
-
- any_thread().task_queue_manager = nullptr;
- main_thread_only().task_queue_manager = nullptr;
- main_thread_only().delayed_incoming_queue = std::priority_queue<Task>();
- any_thread().immediate_incoming_queue = std::queue<Task>();
- main_thread_only().immediate_work_queue.reset();
- main_thread_only().delayed_work_queue.reset();
-}
-
-bool TaskQueueImpl::RunsTasksOnCurrentThread() const {
- base::AutoLock lock(any_thread_lock_);
- return base::PlatformThread::CurrentId() == thread_id_;
-}
-
-bool TaskQueueImpl::PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- if (delay.is_zero())
- return PostImmediateTaskImpl(from_here, task, TaskType::NORMAL);
-
- return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL);
-}
-
-bool TaskQueueImpl::PostNonNestableDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- if (delay.is_zero())
- return PostImmediateTaskImpl(from_here, task, TaskType::NON_NESTABLE);
-
- return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE);
-}
-
-bool TaskQueueImpl::PostImmediateTaskImpl(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- TaskType task_type) {
- base::AutoLock lock(any_thread_lock_);
- if (!any_thread().task_queue_manager)
- return false;
-
- EnqueueOrder sequence_number =
- any_thread().task_queue_manager->GetNextSequenceNumber();
-
- PushOntoImmediateIncomingQueueLocked(
- Task(from_here, task, base::TimeTicks(), sequence_number,
- task_type != TaskType::NON_NESTABLE, sequence_number));
- return true;
-}
-
-bool TaskQueueImpl::PostDelayedTaskImpl(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay,
- TaskType task_type) {
- DCHECK_GT(delay, base::TimeDelta());
- if (base::PlatformThread::CurrentId() == thread_id_) {
- // Lock-free fast path for delayed tasks posted from the main thread.
- if (!main_thread_only().task_queue_manager)
- return false;
-
- EnqueueOrder sequence_number =
- main_thread_only().task_queue_manager->GetNextSequenceNumber();
-
- base::TimeTicks time_domain_now = main_thread_only().time_domain->Now();
- base::TimeTicks time_domain_delayed_run_time = time_domain_now + delay;
- PushOntoDelayedIncomingQueueFromMainThread(
- Task(from_here, task, time_domain_delayed_run_time, sequence_number,
- task_type != TaskType::NON_NESTABLE),
- time_domain_now);
- } else {
- // NOTE posting a delayed task from a different thread is not expected to
- // be common. This pathway is less optimal than perhaps it could be
- // because it causes two main thread tasks to be run. Should this
- // assumption prove to be false in future, we may need to revisit this.
- base::AutoLock lock(any_thread_lock_);
- if (!any_thread().task_queue_manager)
- return false;
-
- EnqueueOrder sequence_number =
- any_thread().task_queue_manager->GetNextSequenceNumber();
-
- base::TimeTicks time_domain_now = any_thread().time_domain->Now();
- base::TimeTicks time_domain_delayed_run_time = time_domain_now + delay;
- PushOntoDelayedIncomingQueueLocked(
- Task(from_here, task, time_domain_delayed_run_time, sequence_number,
- task_type != TaskType::NON_NESTABLE));
- }
- return true;
-}
-
-void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread(
- const Task& pending_task,
- base::TimeTicks now) {
- main_thread_only().task_queue_manager->DidQueueTask(pending_task);
-
- // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue.
- main_thread_only().delayed_incoming_queue.push(pending_task);
- main_thread_only().time_domain->ScheduleDelayedWork(
- this, pending_task.delayed_run_time, now);
- TraceQueueSize(false);
-}
-
-void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(
- const Task& pending_task) {
- any_thread().task_queue_manager->DidQueueTask(pending_task);
-
- int thread_hop_task_sequence_number =
- any_thread().task_queue_manager->GetNextSequenceNumber();
- PushOntoImmediateIncomingQueueLocked(Task(
- FROM_HERE,
- base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this, pending_task),
- base::TimeTicks(), thread_hop_task_sequence_number, false,
- thread_hop_task_sequence_number));
-}
-
-void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked(
- const Task& pending_task) {
- if (any_thread().immediate_incoming_queue.empty())
- any_thread().time_domain->RegisterAsUpdatableTaskQueue(this);
- if (any_thread().pump_policy == PumpPolicy::AUTO &&
- any_thread().immediate_incoming_queue.empty()) {
- any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE);
- }
- any_thread().task_queue_manager->DidQueueTask(pending_task);
- any_thread().immediate_incoming_queue.push(pending_task);
- TraceQueueSize(true);
-}
-
-void TaskQueueImpl::ScheduleDelayedWorkTask(const Task& pending_task) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- main_thread_only().delayed_incoming_queue.push(pending_task);
- main_thread_only().time_domain->ScheduleDelayedWork(
- this, pending_task.delayed_run_time,
- main_thread_only().time_domain->Now());
-}
-
-void TaskQueueImpl::SetQueueEnabled(bool enabled) {
- if (main_thread_only().is_enabled == enabled)
- return;
- main_thread_only().is_enabled = enabled;
- if (!main_thread_only().task_queue_manager)
- return;
- if (enabled) {
- main_thread_only().task_queue_manager->selector_.EnableQueue(this);
- } else {
- main_thread_only().task_queue_manager->selector_.DisableQueue(this);
- }
-}
-
-bool TaskQueueImpl::IsQueueEnabled() const {
- return main_thread_only().is_enabled;
-}
-
-bool TaskQueueImpl::IsEmpty() const {
- if (!main_thread_only().delayed_work_queue->Empty() ||
- !main_thread_only().immediate_work_queue->Empty()) {
- return false;
- }
-
- base::AutoLock lock(any_thread_lock_);
- return any_thread().immediate_incoming_queue.empty() &&
- main_thread_only().delayed_incoming_queue.empty();
-}
-
-bool TaskQueueImpl::HasPendingImmediateWork() const {
- if (!main_thread_only().delayed_work_queue->Empty() ||
- !main_thread_only().immediate_work_queue->Empty()) {
- return true;
- }
-
- return NeedsPumping();
-}
-
-bool TaskQueueImpl::NeedsPumping() const {
- if (!main_thread_only().immediate_work_queue->Empty())
- return false;
-
- base::AutoLock lock(any_thread_lock_);
- if (!any_thread().immediate_incoming_queue.empty())
- return true;
-
- // If there's no immediate Incoming work then we only need pumping if there
- // is a delayed task that should be running now.
- if (main_thread_only().delayed_incoming_queue.empty())
- return false;
-
- return main_thread_only().delayed_incoming_queue.top().delayed_run_time <=
- main_thread_only().time_domain->CreateLazyNow().Now();
-}
-
-bool TaskQueueImpl::TaskIsOlderThanQueuedImmediateTasksLocked(
- const Task* task) {
- // A null task is passed when UpdateQueue is called before any task is run.
- // In this case we don't want to pump an after_wakeup queue, so return true
- // here.
- if (!task)
- return true;
-
- // Return false if task is newer than the oldest immediate task.
- if (!any_thread().immediate_incoming_queue.empty() &&
- task->enqueue_order() >
- any_thread().immediate_incoming_queue.front().enqueue_order()) {
- return false;
- }
- return true;
-}
-
-bool TaskQueueImpl::TaskIsOlderThanQueuedDelayedTasks(const Task* task) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- // A null task is passed when UpdateQueue is called before any task is run.
- // In this case we don't want to pump an after_wakeup queue, so return true
- // here.
- if (!task)
- return true;
-
- EnqueueOrder enqueue_order;
- if (!main_thread_only().delayed_work_queue->GetFrontTaskEnqueueOrder(
- &enqueue_order)) {
- return true;
- }
-
- return task->enqueue_order() < enqueue_order;
-}
-
-bool TaskQueueImpl::ShouldAutoPumpImmediateQueueLocked(
- bool should_trigger_wakeup,
- const Task* previous_task) {
- if (main_thread_only().pump_policy == PumpPolicy::MANUAL)
- return false;
- if (main_thread_only().pump_policy == PumpPolicy::AFTER_WAKEUP &&
- (!should_trigger_wakeup ||
- TaskIsOlderThanQueuedImmediateTasksLocked(previous_task)))
- return false;
- return true;
-}
-
-bool TaskQueueImpl::ShouldAutoPumpDelayedQueue(bool should_trigger_wakeup,
- const Task* previous_task) {
- if (main_thread_only().pump_policy == PumpPolicy::MANUAL)
- return false;
- if (main_thread_only().pump_policy == PumpPolicy::AFTER_WAKEUP &&
- (!should_trigger_wakeup ||
- TaskIsOlderThanQueuedDelayedTasks(previous_task)))
- return false;
- return true;
-}
-
-void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) {
- // Enqueue all delayed tasks that should be running now.
- while (!main_thread_only().delayed_incoming_queue.empty() &&
- main_thread_only().delayed_incoming_queue.top().delayed_run_time <=
- lazy_now->Now()) {
- // Note: the const_cast is needed because there is no direct way to move
- // elements out of a priority queue. The queue must not be modified between
- // the top() and the pop().
- main_thread_only().delayed_work_queue->PushAndSetEnqueueOrder(
- std::move(
- const_cast<Task&>(main_thread_only().delayed_incoming_queue.top())),
- main_thread_only().task_queue_manager->GetNextSequenceNumber());
- main_thread_only().delayed_incoming_queue.pop();
- }
-}
-
-void TaskQueueImpl::UpdateDelayedWorkQueue(LazyNow* lazy_now,
- bool should_trigger_wakeup,
- const Task* previous_task) {
- if (!main_thread_only().task_queue_manager)
- return;
- if (!ShouldAutoPumpDelayedQueue(should_trigger_wakeup, previous_task))
- return;
- MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now);
- TraceQueueSize(false);
-}
-
-void TaskQueueImpl::UpdateImmediateWorkQueue(bool should_trigger_wakeup,
- const Task* previous_task) {
- DCHECK(main_thread_only().immediate_work_queue->Empty());
- base::AutoLock lock(any_thread_lock_);
- if (!main_thread_only().task_queue_manager)
- return;
- if (!ShouldAutoPumpImmediateQueueLocked(should_trigger_wakeup, previous_task))
- return;
-
- main_thread_only().immediate_work_queue->SwapLocked(
- any_thread().immediate_incoming_queue);
-
- // |any_thread().immediate_incoming_queue| is now empty so
- // TimeDomain::UpdateQueues no longer needs to consider this queue for
- // reloading.
- main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this);
-}
-
-void TaskQueueImpl::TraceQueueSize(bool is_locked) const {
- bool is_tracing;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_,
- &is_tracing);
- if (!is_tracing)
- return;
-
- // It's only safe to access the work queues from the main thread.
- // TODO(alexclarke): We should find another way of tracing this
- if (base::PlatformThread::CurrentId() != thread_id_)
- return;
-
- if (!is_locked)
- any_thread_lock_.Acquire();
- else
- any_thread_lock_.AssertAcquired();
- TRACE_COUNTER1(disabled_by_default_tracing_category_, GetName(),
- any_thread().immediate_incoming_queue.size() +
- main_thread_only().immediate_work_queue->Size() +
- main_thread_only().delayed_work_queue->Size() +
- main_thread_only().delayed_incoming_queue.size());
- if (!is_locked)
- any_thread_lock_.Release();
-}
-
-void TaskQueueImpl::SetPumpPolicy(PumpPolicy pump_policy) {
- base::AutoLock lock(any_thread_lock_);
- if (pump_policy == PumpPolicy::AUTO &&
- any_thread().pump_policy != PumpPolicy::AUTO) {
- LazyNow lazy_now(main_thread_only().time_domain->CreateLazyNow());
- PumpQueueLocked(&lazy_now, true);
- }
- any_thread().pump_policy = pump_policy;
- main_thread_only().pump_policy = pump_policy;
-}
-
-TaskQueue::PumpPolicy TaskQueueImpl::GetPumpPolicy() const {
- return main_thread_only().pump_policy;
-}
-
-void TaskQueueImpl::PumpQueueLocked(LazyNow* lazy_now, bool may_post_dowork) {
- TRACE_EVENT1(disabled_by_default_tracing_category_,
- "TaskQueueImpl::PumpQueueLocked", "queue", name_);
- TaskQueueManager* task_queue_manager = any_thread().task_queue_manager;
- if (!task_queue_manager)
- return;
-
- MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now);
-
- while (!any_thread().immediate_incoming_queue.empty()) {
- main_thread_only().immediate_work_queue->Push(
- std::move(any_thread().immediate_incoming_queue.front()));
- any_thread().immediate_incoming_queue.pop();
- }
-
- // |immediate_incoming_queue| is now empty so TimeDomain::UpdateQueues no
- // longer needs to consider this queue for reloading.
- main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this);
-
- if (main_thread_only().immediate_work_queue->Empty() &&
- main_thread_only().delayed_work_queue->Empty()) {
- return;
- }
-
- if (may_post_dowork)
- task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE);
-}
-
-void TaskQueueImpl::PumpQueue(LazyNow* lazy_now, bool may_post_dowork) {
- base::AutoLock lock(any_thread_lock_);
- PumpQueueLocked(lazy_now, may_post_dowork);
-}
-
-const char* TaskQueueImpl::GetName() const {
- return name_;
-}
-
-void TaskQueueImpl::SetQueuePriority(QueuePriority priority) {
- if (!main_thread_only().task_queue_manager || priority == GetQueuePriority())
- return;
- main_thread_only().task_queue_manager->selector_.SetQueuePriority(this,
- priority);
-}
-
-TaskQueueImpl::QueuePriority TaskQueueImpl::GetQueuePriority() const {
- size_t set_index = immediate_work_queue()->work_queue_set_index();
- DCHECK_EQ(set_index, delayed_work_queue()->work_queue_set_index());
- return static_cast<TaskQueue::QueuePriority>(set_index);
-}
-
-// static
-const char* TaskQueueImpl::PumpPolicyToString(
- TaskQueue::PumpPolicy pump_policy) {
- switch (pump_policy) {
- case TaskQueue::PumpPolicy::AUTO:
- return "auto";
- case TaskQueue::PumpPolicy::AFTER_WAKEUP:
- return "after_wakeup";
- case TaskQueue::PumpPolicy::MANUAL:
- return "manual";
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-
-// static
-const char* TaskQueueImpl::WakeupPolicyToString(
- TaskQueue::WakeupPolicy wakeup_policy) {
- switch (wakeup_policy) {
- case TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES:
- return "can_wake_other_queues";
- case TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES:
- return "dont_wake_other_queues";
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-
-// static
-const char* TaskQueueImpl::PriorityToString(QueuePriority priority) {
- switch (priority) {
- case CONTROL_PRIORITY:
- return "control";
- case HIGH_PRIORITY:
- return "high";
- case NORMAL_PRIORITY:
- return "normal";
- case BEST_EFFORT_PRIORITY:
- return "best_effort";
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-
-void TaskQueueImpl::AsValueInto(base::trace_event::TracedValue* state) const {
- base::AutoLock lock(any_thread_lock_);
- state->BeginDictionary();
- state->SetString("name", GetName());
- state->SetBoolean("enabled", main_thread_only().is_enabled);
- state->SetString("time_domain_name",
- main_thread_only().time_domain->GetName());
- state->SetString("pump_policy", PumpPolicyToString(any_thread().pump_policy));
- state->SetString("wakeup_policy", WakeupPolicyToString(wakeup_policy_));
- bool verbose_tracing_enabled = false;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(
- disabled_by_default_verbose_tracing_category_, &verbose_tracing_enabled);
- state->SetInteger("immediate_incoming_queue_size",
- any_thread().immediate_incoming_queue.size());
- state->SetInteger("delayed_incoming_queue_size",
- main_thread_only().delayed_incoming_queue.size());
- state->SetInteger("immediate_work_queue_size",
- main_thread_only().immediate_work_queue->Size());
- state->SetInteger("delayed_work_queue_size",
- main_thread_only().delayed_work_queue->Size());
- if (!main_thread_only().delayed_incoming_queue.empty()) {
- base::TimeDelta delay_to_next_task =
- (main_thread_only().delayed_incoming_queue.top().delayed_run_time -
- main_thread_only().time_domain->CreateLazyNow().Now());
- state->SetDouble("delay_to_next_task_ms",
- delay_to_next_task.InMillisecondsF());
- }
- if (verbose_tracing_enabled) {
- state->BeginArray("immediate_incoming_queue");
- QueueAsValueInto(any_thread().immediate_incoming_queue, state);
- state->EndArray();
- state->BeginArray("delayed_work_queue");
- main_thread_only().delayed_work_queue->AsValueInto(state);
- state->EndArray();
- state->BeginArray("immediate_work_queue");
- main_thread_only().immediate_work_queue->AsValueInto(state);
- state->EndArray();
- state->BeginArray("delayed_incoming_queue");
- QueueAsValueInto(main_thread_only().delayed_incoming_queue, state);
- state->EndArray();
- }
- state->SetString("priority", PriorityToString(GetQueuePriority()));
- state->EndDictionary();
-}
-
-void TaskQueueImpl::AddTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- main_thread_only().task_observers.AddObserver(task_observer);
-}
-
-void TaskQueueImpl::RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- main_thread_only().task_observers.RemoveObserver(task_observer);
-}
-
-void TaskQueueImpl::NotifyWillProcessTask(
- const base::PendingTask& pending_task) {
- DCHECK(should_notify_observers_);
- if (main_thread_only().blame_context)
- main_thread_only().blame_context->Enter();
- FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver,
- main_thread_only().task_observers,
- WillProcessTask(pending_task));
-}
-
-void TaskQueueImpl::NotifyDidProcessTask(
- const base::PendingTask& pending_task) {
- DCHECK(should_notify_observers_);
- FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver,
- main_thread_only().task_observers,
- DidProcessTask(pending_task));
- if (main_thread_only().blame_context)
- main_thread_only().blame_context->Leave();
-}
-
-void TaskQueueImpl::SetTimeDomain(TimeDomain* time_domain) {
- base::AutoLock lock(any_thread_lock_);
- DCHECK(time_domain);
- // NOTE this is similar to checking |any_thread().task_queue_manager| but the
- // TaskQueueSelectorTests constructs TaskQueueImpl directly with a null
- // task_queue_manager. Instead we check |any_thread().time_domain| which is
- // another way of asserting that UnregisterTaskQueue has not been called.
- DCHECK(any_thread().time_domain);
- if (!any_thread().time_domain)
- return;
- DCHECK(main_thread_checker_.CalledOnValidThread());
- if (time_domain == main_thread_only().time_domain)
- return;
-
- main_thread_only().time_domain->MigrateQueue(this, time_domain);
- main_thread_only().time_domain = time_domain;
- any_thread().time_domain = time_domain;
-}
-
-TimeDomain* TaskQueueImpl::GetTimeDomain() const {
- if (base::PlatformThread::CurrentId() == thread_id_)
- return main_thread_only().time_domain;
-
- base::AutoLock lock(any_thread_lock_);
- return any_thread().time_domain;
-}
-
-void TaskQueueImpl::SetBlameContext(
- base::trace_event::BlameContext* blame_context) {
- main_thread_only().blame_context = blame_context;
-}
-
-// static
-void TaskQueueImpl::QueueAsValueInto(const std::queue<Task>& queue,
- base::trace_event::TracedValue* state) {
- std::queue<Task> queue_copy(queue);
- while (!queue_copy.empty()) {
- TaskAsValueInto(queue_copy.front(), state);
- queue_copy.pop();
- }
-}
-
-// static
-void TaskQueueImpl::QueueAsValueInto(const std::priority_queue<Task>& queue,
- base::trace_event::TracedValue* state) {
- std::priority_queue<Task> queue_copy(queue);
- while (!queue_copy.empty()) {
- TaskAsValueInto(queue_copy.top(), state);
- queue_copy.pop();
- }
-}
-
-// static
-void TaskQueueImpl::TaskAsValueInto(const Task& task,
- base::trace_event::TracedValue* state) {
- state->BeginDictionary();
- state->SetString("posted_from", task.posted_from.ToString());
-#ifndef NDEBUG
- if (task.enqueue_order_set())
- state->SetInteger("enqueue_order", task.enqueue_order());
-#else
- state->SetInteger("enqueue_order", task.enqueue_order());
-#endif
- state->SetInteger("sequence_num", task.sequence_num);
- state->SetBoolean("nestable", task.nestable);
- state->SetBoolean("is_high_res", task.is_high_res);
- state->SetDouble(
- "delayed_run_time",
- (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L);
- state->EndDictionary();
-}
-
-} // namespace internal
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/task_queue_impl.h b/chromium/components/scheduler/base/task_queue_impl.h
deleted file mode 100644
index 0e7f007204a..00000000000
--- a/chromium/components/scheduler/base/task_queue_impl.h
+++ /dev/null
@@ -1,309 +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_RENDERER_SCHEDULER_BASE_TASK_QUEUE_IMPL_H_
-#define CONTENT_RENDERER_SCHEDULER_BASE_TASK_QUEUE_IMPL_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <set>
-
-#include "base/macros.h"
-#include "base/pending_task.h"
-#include "base/threading/thread_checker.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "components/scheduler/base/enqueue_order.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-class LazyNow;
-class TimeDomain;
-class TaskQueueManager;
-
-namespace internal {
-class WorkQueue;
-class WorkQueueSets;
-
-class SCHEDULER_EXPORT TaskQueueImpl final : public TaskQueue {
- public:
- TaskQueueImpl(TaskQueueManager* task_queue_manager,
- TimeDomain* time_domain,
- const Spec& spec,
- const char* disabled_by_default_tracing_category,
- const char* disabled_by_default_verbose_tracing_category);
-
- class SCHEDULER_EXPORT Task : public base::PendingTask {
- public:
- Task();
- Task(const tracked_objects::Location& posted_from,
- const base::Closure& task,
- base::TimeTicks desired_run_time,
- EnqueueOrder sequence_number,
- bool nestable);
-
- Task(const tracked_objects::Location& posted_from,
- const base::Closure& task,
- base::TimeTicks desired_run_time,
- EnqueueOrder sequence_number,
- bool nestable,
- EnqueueOrder enqueue_order);
-
- EnqueueOrder enqueue_order() const {
-#ifndef NDEBUG
- DCHECK(enqueue_order_set_);
-#endif
- return enqueue_order_;
- }
-
- void set_enqueue_order(EnqueueOrder enqueue_order) {
-#ifndef NDEBUG
- DCHECK(!enqueue_order_set_);
- enqueue_order_set_ = true;
-#endif
- enqueue_order_ = enqueue_order;
- }
-
-#ifndef NDEBUG
- bool enqueue_order_set() const { return enqueue_order_set_; }
-#endif
-
- private:
-#ifndef NDEBUG
- bool enqueue_order_set_;
-#endif
- // Similar to sequence number, but the |enqueue_order| is set by
- // EnqueueTasksLocked and is not initially defined for delayed tasks until
- // they are enqueued on the |immediate_incoming_queue_|.
- EnqueueOrder enqueue_order_;
- };
-
- // TaskQueue implementation.
- void UnregisterTaskQueue() override;
- bool RunsTasksOnCurrentThread() const override;
- bool PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override;
- bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override;
-
- void SetQueueEnabled(bool enabled) override;
- bool IsQueueEnabled() const override;
- bool IsEmpty() const override;
- bool HasPendingImmediateWork() const override;
- bool NeedsPumping() const override;
- void SetQueuePriority(QueuePriority priority) override;
- QueuePriority GetQueuePriority() const override;
- void PumpQueue(LazyNow* lazy_now, bool may_post_dowork) override;
- void SetPumpPolicy(PumpPolicy pump_policy) override;
- PumpPolicy GetPumpPolicy() const override;
- void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override;
- void RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) override;
- void SetTimeDomain(TimeDomain* time_domain) override;
- TimeDomain* GetTimeDomain() const override;
- void SetBlameContext(base::trace_event::BlameContext* blame_context) override;
-
- void UpdateImmediateWorkQueue(bool should_trigger_wakeup,
- const Task* previous_task);
- void UpdateDelayedWorkQueue(LazyNow* lazy_now,
- bool should_trigger_wakeup,
- const Task* previous_task);
-
- WakeupPolicy wakeup_policy() const {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- return wakeup_policy_;
- }
-
- const char* GetName() const override;
-
- void AsValueInto(base::trace_event::TracedValue* state) const;
-
- bool GetQuiescenceMonitored() const { return should_monitor_quiescence_; }
- bool GetShouldNotifyObservers() const {
- return should_notify_observers_;
- }
-
- void NotifyWillProcessTask(const base::PendingTask& pending_task);
- void NotifyDidProcessTask(const base::PendingTask& pending_task);
-
- // Can be called on any thread.
- static const char* PumpPolicyToString(TaskQueue::PumpPolicy pump_policy);
-
- // Can be called on any thread.
- static const char* WakeupPolicyToString(
- TaskQueue::WakeupPolicy wakeup_policy);
-
- // Can be called on any thread.
- static const char* PriorityToString(TaskQueue::QueuePriority priority);
-
- WorkQueue* delayed_work_queue() {
- return main_thread_only().delayed_work_queue.get();
- }
-
- const WorkQueue* delayed_work_queue() const {
- return main_thread_only().delayed_work_queue.get();
- }
-
- WorkQueue* immediate_work_queue() {
- return main_thread_only().immediate_work_queue.get();
- }
-
- const WorkQueue* immediate_work_queue() const {
- return main_thread_only().immediate_work_queue.get();
- }
-
- bool should_report_when_execution_blocked() const {
- return should_report_when_execution_blocked_;
- }
-
- private:
- friend class WorkQueue;
-
- enum class TaskType {
- NORMAL,
- NON_NESTABLE,
- };
-
- struct AnyThread {
- AnyThread(TaskQueueManager* task_queue_manager,
- PumpPolicy pump_policy,
- TimeDomain* time_domain);
- ~AnyThread();
-
- // TaskQueueManager, PumpPolicy and TimeDomain are maintained in two copies:
- // inside AnyThread and inside MainThreadOnly. They can be changed only from
- // main thread, so it should be locked before accessing from other threads.
- TaskQueueManager* task_queue_manager;
- PumpPolicy pump_policy;
- TimeDomain* time_domain;
-
- std::queue<Task> immediate_incoming_queue;
- };
-
- struct MainThreadOnly {
- MainThreadOnly(TaskQueueManager* task_queue_manager,
- PumpPolicy pump_policy,
- TaskQueueImpl* task_queue,
- TimeDomain* time_domain);
- ~MainThreadOnly();
-
- // Another copy of TaskQueueManager, PumpPolicy and TimeDomain for lock-free
- // access from the main thread. See description inside struct AnyThread for
- // details.
- TaskQueueManager* task_queue_manager;
- PumpPolicy pump_policy;
- TimeDomain* time_domain;
-
- std::unique_ptr<WorkQueue> delayed_work_queue;
- std::unique_ptr<WorkQueue> immediate_work_queue;
- std::priority_queue<Task> delayed_incoming_queue;
- base::ObserverList<base::MessageLoop::TaskObserver> task_observers;
- size_t set_index;
- bool is_enabled;
- base::trace_event::BlameContext* blame_context; // Not owned.
- };
-
- ~TaskQueueImpl() override;
-
- bool PostImmediateTaskImpl(const tracked_objects::Location& from_here,
- const base::Closure& task,
- TaskType task_type);
- bool PostDelayedTaskImpl(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay,
- TaskType task_type);
-
- // Push the task onto the |delayed_incoming_queue|. Lock-free main thread
- // only fast path.
- void PushOntoDelayedIncomingQueueFromMainThread(const Task& pending_task,
- base::TimeTicks now);
-
- // Push the task onto the |delayed_incoming_queue|. Slow path from other
- // threads.
- void PushOntoDelayedIncomingQueueLocked(const Task& pending_task);
-
- void ScheduleDelayedWorkTask(const Task& pending_task);
-
- // Enqueues any delayed tasks which should be run now on the
- // |delayed_work_queue|. Must be called from the main thread.
- void MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now);
-
- void MoveReadyImmediateTasksToImmediateWorkQueueLocked();
-
- // Note this does nothing if its not called from the main thread.
- void PumpQueueLocked(LazyNow* lazy_now, bool may_post_dowork);
-
- // Returns true if |task| is older than the oldest incoming immediate task.
- // NOTE |any_thread_lock_| must be locked.
- bool TaskIsOlderThanQueuedImmediateTasksLocked(const Task* task);
-
- // Returns true if |task| is older than the oldest delayed task. Must be
- // called from the main thread.
- bool TaskIsOlderThanQueuedDelayedTasks(const Task* task);
-
- // NOTE |any_thread_lock_| must be locked.
- bool ShouldAutoPumpImmediateQueueLocked(bool should_trigger_wakeup,
- const Task* previous_task);
-
- // Must be called from the main thread.
- bool ShouldAutoPumpDelayedQueue(bool should_trigger_wakeup,
- const Task* previous_task);
-
- // Push the task onto the |immediate_incoming_queue| and for auto pumped
- // queues it calls MaybePostDoWorkOnMainRunner if the Incoming queue was
- // empty.
- void PushOntoImmediateIncomingQueueLocked(const Task& pending_task);
-
- void TraceQueueSize(bool is_locked) const;
- static void QueueAsValueInto(const std::queue<Task>& queue,
- base::trace_event::TracedValue* state);
- static void QueueAsValueInto(const std::priority_queue<Task>& queue,
- base::trace_event::TracedValue* state);
- static void TaskAsValueInto(const Task& task,
- base::trace_event::TracedValue* state);
-
- const base::PlatformThreadId thread_id_;
-
- mutable base::Lock any_thread_lock_;
- AnyThread any_thread_;
- struct AnyThread& any_thread() {
- any_thread_lock_.AssertAcquired();
- return any_thread_;
- }
- const struct AnyThread& any_thread() const {
- any_thread_lock_.AssertAcquired();
- return any_thread_;
- }
-
- const char* name_;
- const char* disabled_by_default_tracing_category_;
- const char* disabled_by_default_verbose_tracing_category_;
-
- base::ThreadChecker main_thread_checker_;
- MainThreadOnly main_thread_only_;
- MainThreadOnly& main_thread_only() {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- return main_thread_only_;
- }
- const MainThreadOnly& main_thread_only() const {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- return main_thread_only_;
- }
-
- const WakeupPolicy wakeup_policy_;
- const bool should_monitor_quiescence_;
- const bool should_notify_observers_;
- const bool should_report_when_execution_blocked_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskQueueImpl);
-};
-
-} // namespace internal
-} // namespace scheduler
-
-#endif // CONTENT_RENDERER_SCHEDULER_BASE_TASK_QUEUE_IMPL_H_
diff --git a/chromium/components/scheduler/base/task_queue_manager.cc b/chromium/components/scheduler/base/task_queue_manager.cc
deleted file mode 100644
index 36f08de540f..00000000000
--- a/chromium/components/scheduler/base/task_queue_manager.cc
+++ /dev/null
@@ -1,418 +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 "components/scheduler/base/task_queue_manager.h"
-
-#include <queue>
-#include <set>
-
-#include "base/bind.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/trace_event/trace_event.h"
-#include "components/scheduler/base/real_time_domain.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/task_queue_manager_delegate.h"
-#include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/base/work_queue.h"
-#include "components/scheduler/base/work_queue_sets.h"
-
-namespace scheduler {
-
-namespace {
-const size_t kRecordRecordTaskDelayHistogramsEveryNTasks = 10;
-
-void RecordDelayedTaskLateness(base::TimeDelta lateness) {
- UMA_HISTOGRAM_TIMES("RendererScheduler.TaskQueueManager.DelayedTaskLateness",
- lateness);
-}
-
-void RecordImmediateTaskQueueingDuration(tracked_objects::Duration duration) {
- UMA_HISTOGRAM_TIMES(
- "RendererScheduler.TaskQueueManager.ImmediateTaskQueueingDuration",
- base::TimeDelta::FromMilliseconds(duration.InMilliseconds()));
-}
-}
-
-TaskQueueManager::TaskQueueManager(
- scoped_refptr<TaskQueueManagerDelegate> delegate,
- const char* tracing_category,
- const char* disabled_by_default_tracing_category,
- const char* disabled_by_default_verbose_tracing_category)
- : real_time_domain_(new RealTimeDomain(tracing_category)),
- delegate_(delegate),
- task_was_run_on_quiescence_monitored_queue_(false),
- work_batch_size_(1),
- task_count_(0),
- tracing_category_(tracing_category),
- disabled_by_default_tracing_category_(
- disabled_by_default_tracing_category),
- disabled_by_default_verbose_tracing_category_(
- disabled_by_default_verbose_tracing_category),
- currently_executing_task_queue_(nullptr),
- observer_(nullptr),
- deletion_sentinel_(new DeletionSentinel()),
- weak_factory_(this) {
- DCHECK(delegate->RunsTasksOnCurrentThread());
- TRACE_EVENT_OBJECT_CREATED_WITH_ID(disabled_by_default_tracing_category,
- "TaskQueueManager", this);
- selector_.SetTaskQueueSelectorObserver(this);
-
- from_main_thread_immediate_do_work_closure_ =
- base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(),
- base::TimeTicks(), true);
- from_other_thread_immediate_do_work_closure_ =
- base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(),
- base::TimeTicks(), false);
-
- // TODO(alexclarke): Change this to be a parameter that's passed in.
- RegisterTimeDomain(real_time_domain_.get());
-}
-
-TaskQueueManager::~TaskQueueManager() {
- TRACE_EVENT_OBJECT_DELETED_WITH_ID(disabled_by_default_tracing_category_,
- "TaskQueueManager", this);
-
- while (!queues_.empty())
- (*queues_.begin())->UnregisterTaskQueue();
-
- selector_.SetTaskQueueSelectorObserver(nullptr);
-}
-
-void TaskQueueManager::RegisterTimeDomain(TimeDomain* time_domain) {
- time_domains_.insert(time_domain);
- time_domain->OnRegisterWithTaskQueueManager(this);
-}
-
-void TaskQueueManager::UnregisterTimeDomain(TimeDomain* time_domain) {
- time_domains_.erase(time_domain);
-}
-
-scoped_refptr<internal::TaskQueueImpl> TaskQueueManager::NewTaskQueue(
- const TaskQueue::Spec& spec) {
- TRACE_EVENT1(tracing_category_,
- "TaskQueueManager::NewTaskQueue", "queue_name", spec.name);
- DCHECK(main_thread_checker_.CalledOnValidThread());
- TimeDomain* time_domain =
- spec.time_domain ? spec.time_domain : real_time_domain_.get();
- DCHECK(time_domains_.find(time_domain) != time_domains_.end());
- scoped_refptr<internal::TaskQueueImpl> queue(
- make_scoped_refptr(new internal::TaskQueueImpl(
- this, time_domain, spec, disabled_by_default_tracing_category_,
- disabled_by_default_verbose_tracing_category_)));
- queues_.insert(queue);
- selector_.AddQueue(queue.get());
- return queue;
-}
-
-void TaskQueueManager::SetObserver(Observer* observer) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- observer_ = observer;
-}
-
-void TaskQueueManager::UnregisterTaskQueue(
- scoped_refptr<internal::TaskQueueImpl> task_queue) {
- TRACE_EVENT1(tracing_category_,
- "TaskQueueManager::UnregisterTaskQueue", "queue_name",
- task_queue->GetName());
- DCHECK(main_thread_checker_.CalledOnValidThread());
- if (observer_)
- observer_->OnUnregisterTaskQueue(task_queue);
-
- // Add |task_queue| to |queues_to_delete_| so we can prevent it from being
- // freed while any of our structures hold hold a raw pointer to it.
- queues_to_delete_.insert(task_queue);
- queues_.erase(task_queue);
- selector_.RemoveQueue(task_queue.get());
-}
-
-void TaskQueueManager::UpdateWorkQueues(
- bool should_trigger_wakeup,
- const internal::TaskQueueImpl::Task* previous_task) {
- TRACE_EVENT0(disabled_by_default_tracing_category_,
- "TaskQueueManager::UpdateWorkQueues");
-
- for (TimeDomain* time_domain : time_domains_) {
- time_domain->UpdateWorkQueues(should_trigger_wakeup, previous_task);
- }
-}
-
-void TaskQueueManager::MaybeScheduleImmediateWork(
- const tracked_objects::Location& from_here) {
- bool on_main_thread = delegate_->BelongsToCurrentThread();
- // De-duplicate DoWork posts.
- if (on_main_thread) {
- if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) {
- return;
- }
- delegate_->PostTask(from_here, from_main_thread_immediate_do_work_closure_);
- } else {
- {
- base::AutoLock lock(other_thread_lock_);
- if (!other_thread_pending_wakeups_.insert(base::TimeTicks()).second)
- return;
- }
- delegate_->PostTask(from_here,
- from_other_thread_immediate_do_work_closure_);
- }
-}
-
-void TaskQueueManager::MaybeScheduleDelayedWork(
- const tracked_objects::Location& from_here,
- base::TimeTicks now,
- base::TimeDelta delay) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- DCHECK_GE(delay, base::TimeDelta());
- base::TimeTicks run_time = now + delay;
- // De-duplicate DoWork posts.
- if (!main_thread_pending_wakeups_.insert(run_time).second)
- return;
- delegate_->PostDelayedTask(
- from_here, base::Bind(&TaskQueueManager::DoWork,
- weak_factory_.GetWeakPtr(), run_time, true),
- delay);
-}
-
-void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork",
- "from_main_thread", from_main_thread);
- if (from_main_thread) {
- main_thread_pending_wakeups_.erase(run_time);
- } else {
- base::AutoLock lock(other_thread_lock_);
- other_thread_pending_wakeups_.erase(run_time);
- }
-
- if (!delegate_->IsNested())
- queues_to_delete_.clear();
-
- // Pass false and nullptr to UpdateWorkQueues here to prevent waking up a
- // pump-after-wakeup queue.
- UpdateWorkQueues(false, nullptr);
-
- internal::TaskQueueImpl::Task previous_task;
- for (int i = 0; i < work_batch_size_; i++) {
- internal::WorkQueue* work_queue;
- if (!SelectWorkQueueToService(&work_queue)) {
- break;
- }
-
- bool should_trigger_wakeup = work_queue->task_queue()->wakeup_policy() ==
- TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES;
- switch (ProcessTaskFromWorkQueue(work_queue, &previous_task)) {
- case ProcessTaskResult::DEFERRED:
- // If a task was deferred, try again with another task. Note that this
- // means deferred tasks (i.e. non-nestable tasks) will never trigger
- // queue wake-ups.
- continue;
- case ProcessTaskResult::EXECUTED:
- break;
- case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED:
- return; // The TaskQueueManager got deleted, we must bail out.
- }
- work_queue = nullptr; // The queue may have been unregistered.
-
- UpdateWorkQueues(should_trigger_wakeup, &previous_task);
-
- // Only run a single task per batch in nested run loops so that we can
- // properly exit the nested loop when someone calls RunLoop::Quit().
- if (delegate_->IsNested())
- break;
- }
-
- // TODO(alexclarke): Consider refactoring the above loop to terminate only
- // when there's no more work left to be done, rather than posting a
- // continuation task.
- if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains())
- MaybeScheduleImmediateWork(FROM_HERE);
-}
-
-bool TaskQueueManager::TryAdvanceTimeDomains() {
- bool can_advance = false;
- for (TimeDomain* time_domain : time_domains_) {
- can_advance |= time_domain->MaybeAdvanceTime();
- }
- return can_advance;
-}
-
-bool TaskQueueManager::SelectWorkQueueToService(
- internal::WorkQueue** out_work_queue) {
- bool should_run = selector_.SelectWorkQueueToService(out_work_queue);
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- disabled_by_default_tracing_category_, "TaskQueueManager", this,
- AsValueWithSelectorResult(should_run, *out_work_queue));
- return should_run;
-}
-
-void TaskQueueManager::DidQueueTask(
- const internal::TaskQueueImpl::Task& pending_task) {
- task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task);
-}
-
-TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue(
- internal::WorkQueue* work_queue,
- internal::TaskQueueImpl::Task* out_previous_task) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- scoped_refptr<DeletionSentinel> protect(deletion_sentinel_);
- internal::TaskQueueImpl* queue = work_queue->task_queue();
-
- if (queue->GetQuiescenceMonitored())
- task_was_run_on_quiescence_monitored_queue_ = true;
-
- internal::TaskQueueImpl::Task pending_task =
- work_queue->TakeTaskFromWorkQueue();
- if (!pending_task.nestable && delegate_->IsNested()) {
- // Defer non-nestable work to the main task runner. NOTE these tasks can be
- // arbitrarily delayed so the additional delay should not be a problem.
- // TODO(skyostil): Figure out a way to not forget which task queue the
- // task is associated with. See http://crbug.com/522843.
- delegate_->PostNonNestableTask(pending_task.posted_from, pending_task.task);
- return ProcessTaskResult::DEFERRED;
- }
-
- MaybeRecordTaskDelayHistograms(pending_task, queue);
-
- TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue",
- pending_task);
- if (queue->GetShouldNotifyObservers()) {
- FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_,
- WillProcessTask(pending_task));
- queue->NotifyWillProcessTask(pending_task);
- }
- TRACE_EVENT1(tracing_category_,
- "TaskQueueManager::RunTask", "queue", queue->GetName());
- // NOTE when TaskQueues get unregistered a reference ends up getting retained
- // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means
- // we are OK to use raw pointers here.
- internal::TaskQueueImpl* prev_executing_task_queue =
- currently_executing_task_queue_;
- currently_executing_task_queue_ = queue;
- task_annotator_.RunTask("TaskQueueManager::PostTask", pending_task);
-
- // Detect if the TaskQueueManager just got deleted. If this happens we must
- // not access any member variables after this point.
- if (protect->HasOneRef())
- return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED;
-
- currently_executing_task_queue_ = prev_executing_task_queue;
-
- if (queue->GetShouldNotifyObservers()) {
- FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_,
- DidProcessTask(pending_task));
- queue->NotifyDidProcessTask(pending_task);
- }
-
- pending_task.task.Reset();
- *out_previous_task = pending_task;
- return ProcessTaskResult::EXECUTED;
-}
-
-void TaskQueueManager::MaybeRecordTaskDelayHistograms(
- const internal::TaskQueueImpl::Task& pending_task,
- const internal::TaskQueueImpl* queue) {
- if ((task_count_++ % kRecordRecordTaskDelayHistogramsEveryNTasks) != 0)
- return;
-
- // Record delayed task lateness and immediate task queueing durations, but
- // only for auto-pumped queues. Manually pumped and after wakeup queues can
- // have arbitarially large delayes, which would cloud any analysis.
- if (queue->GetPumpPolicy() == TaskQueue::PumpPolicy::AUTO) {
- if (!pending_task.delayed_run_time.is_null()) {
- RecordDelayedTaskLateness(delegate_->NowTicks() -
- pending_task.delayed_run_time);
- } else if (!pending_task.time_posted.is_null()) {
- RecordImmediateTaskQueueingDuration(tracked_objects::TrackedTime::Now() -
- pending_task.time_posted);
- }
- }
-}
-
-bool TaskQueueManager::RunsTasksOnCurrentThread() const {
- return delegate_->RunsTasksOnCurrentThread();
-}
-
-void TaskQueueManager::SetWorkBatchSize(int work_batch_size) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- DCHECK_GE(work_batch_size, 1);
- work_batch_size_ = work_batch_size;
-}
-
-void TaskQueueManager::AddTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- task_observers_.AddObserver(task_observer);
-}
-
-void TaskQueueManager::RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- task_observers_.RemoveObserver(task_observer);
-}
-
-bool TaskQueueManager::GetAndClearSystemIsQuiescentBit() {
- bool task_was_run = task_was_run_on_quiescence_monitored_queue_;
- task_was_run_on_quiescence_monitored_queue_ = false;
- return !task_was_run;
-}
-
-const scoped_refptr<TaskQueueManagerDelegate>& TaskQueueManager::delegate()
- const {
- return delegate_;
-}
-
-internal::EnqueueOrder TaskQueueManager::GetNextSequenceNumber() {
- return enqueue_order_generator_.GenerateNext();
-}
-
-LazyNow TaskQueueManager::CreateLazyNow() const {
- return LazyNow(delegate_.get());
-}
-
-std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-TaskQueueManager::AsValueWithSelectorResult(
- bool should_run,
- internal::WorkQueue* selected_work_queue) const {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- std::unique_ptr<base::trace_event::TracedValue> state(
- new base::trace_event::TracedValue());
- state->BeginArray("queues");
- for (auto& queue : queues_)
- queue->AsValueInto(state.get());
- state->EndArray();
- state->BeginDictionary("selector");
- selector_.AsValueInto(state.get());
- state->EndDictionary();
- if (should_run) {
- state->SetString("selected_queue",
- selected_work_queue->task_queue()->GetName());
- state->SetString("work_queue_name", selected_work_queue->name());
- }
-
- state->BeginArray("time_domains");
- for (auto& time_domain : time_domains_)
- time_domain->AsValueInto(state.get());
- state->EndArray();
- return std::move(state);
-}
-
-void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- // Only schedule DoWork if there's something to do.
- if (!queue->immediate_work_queue()->Empty() ||
- !queue->delayed_work_queue()->Empty()) {
- MaybeScheduleImmediateWork(FROM_HERE);
- }
-}
-
-void TaskQueueManager::OnTriedToSelectBlockedWorkQueue(
- internal::WorkQueue* work_queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- DCHECK(!work_queue->Empty());
- if (observer_) {
- observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(),
- *work_queue->GetFrontTask());
- }
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/task_queue_manager.h b/chromium/components/scheduler/base/task_queue_manager.h
deleted file mode 100644
index 1e9eef4d281..00000000000
--- a/chromium/components/scheduler/base/task_queue_manager.h
+++ /dev/null
@@ -1,257 +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_RENDERER_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_
-#define CONTENT_RENDERER_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_
-
-#include <map>
-
-#include "base/atomic_sequence_num.h"
-#include "base/debug/task_annotator.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/pending_task.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
-#include "components/scheduler/base/enqueue_order.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-class TickClock;
-
-namespace trace_event {
-class ConvertableToTraceFormat;
-class TracedValue;
-} // namespace trace_event
-} // namespace base
-
-namespace scheduler {
-namespace internal {
-class TaskQueueImpl;
-} // namespace internal
-
-class LazyNow;
-class RealTimeDomain;
-class TimeDomain;
-class TaskQueueManagerDelegate;
-
-// The task queue manager provides N task queues and a selector interface for
-// choosing which task queue to service next. Each task queue consists of two
-// sub queues:
-//
-// 1. Incoming task queue. Tasks that are posted get immediately appended here.
-// When a task is appended into an empty incoming queue, the task manager
-// work function (DoWork) is scheduled to run on the main task runner.
-//
-// 2. Work queue. If a work queue is empty when DoWork() is entered, tasks from
-// the incoming task queue (if any) are moved here. The work queues are
-// registered with the selector as input to the scheduling decision.
-//
-class SCHEDULER_EXPORT TaskQueueManager
- : public internal::TaskQueueSelector::Observer {
- public:
- // Create a task queue manager where |delegate| identifies the thread
- // on which where the tasks are eventually run. Category strings must have
- // application lifetime (statics or literals). They may not include " chars.
- TaskQueueManager(scoped_refptr<TaskQueueManagerDelegate> delegate,
- const char* tracing_category,
- const char* disabled_by_default_tracing_category,
- const char* disabled_by_default_verbose_tracing_category);
- ~TaskQueueManager() override;
-
- // Requests that a task to process work is posted on the main task runner.
- // These tasks are de-duplicated in two buckets: main-thread and all other
- // threads. This distinction is done to reduce the overehead from locks, we
- // assume the main-thread path will be hot.
- void MaybeScheduleImmediateWork(const tracked_objects::Location& from_here);
-
- // Requests that a delayed task to process work is posted on the main task
- // runner. These delayed tasks are de-duplicated. Must be called on the thread
- // this class was created on.
- void MaybeScheduleDelayedWork(const tracked_objects::Location& from_here,
- base::TimeTicks now,
- base::TimeDelta delay);
-
- // Set the number of tasks executed in a single invocation of the task queue
- // manager. Increasing the batch size can reduce the overhead of yielding
- // back to the main message loop -- at the cost of potentially delaying other
- // tasks posted to the main loop. The batch size is 1 by default.
- void SetWorkBatchSize(int work_batch_size);
-
- // These functions can only be called on the same thread that the task queue
- // manager executes its tasks on.
- void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer);
- void RemoveTaskObserver(base::MessageLoop::TaskObserver* task_observer);
-
- // Returns true if any task from a monitored task queue was was run since the
- // last call to GetAndClearSystemIsQuiescentBit.
- bool GetAndClearSystemIsQuiescentBit();
-
- // Creates a task queue with the given |spec|. Must be called on the thread
- // this class was created on.
- scoped_refptr<internal::TaskQueueImpl> NewTaskQueue(
- const TaskQueue::Spec& spec);
-
- class SCHEDULER_EXPORT Observer {
- public:
- virtual ~Observer() {}
-
- // Called when |queue| is unregistered.
- virtual void OnUnregisterTaskQueue(
- const scoped_refptr<TaskQueue>& queue) = 0;
-
- // Called when the manager tried to execute a task from a disabled
- // queue. See TaskQueue::Spec::SetShouldReportWhenExecutionBlocked.
- virtual void OnTriedToExecuteBlockedTask(const TaskQueue& queue,
- const base::PendingTask& task) = 0;
- };
-
- // Called once to set the Observer. This function is called on the main
- // thread. If |observer| is null, then no callbacks will occur.
- // Note |observer| is expected to outlive the SchedulerHelper.
- void SetObserver(Observer* observer);
-
- // Returns the delegate used by the TaskQueueManager.
- const scoped_refptr<TaskQueueManagerDelegate>& delegate() const;
-
- // Time domains must be registered for the task queues to get updated.
- void RegisterTimeDomain(TimeDomain* time_domain);
- void UnregisterTimeDomain(TimeDomain* time_domain);
-
- RealTimeDomain* real_time_domain() const { return real_time_domain_.get(); }
-
- LazyNow CreateLazyNow() const;
-
- // Returns the currently executing TaskQueue if any. Must be called on the
- // thread this class was created on.
- TaskQueue* currently_executing_task_queue() const {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- return currently_executing_task_queue_;
- }
-
- private:
- friend class LazyNow;
- friend class internal::TaskQueueImpl;
- friend class TaskQueueManagerTest;
-
- class DeletionSentinel : public base::RefCounted<DeletionSentinel> {
- private:
- friend class base::RefCounted<DeletionSentinel>;
- ~DeletionSentinel() {}
- };
-
- // Unregisters a TaskQueue previously created by |NewTaskQueue()|.
- // NOTE we have to flush the queue from |newly_updatable_| which means as a
- // side effect MoveNewlyUpdatableQueuesIntoUpdatableQueueSet is called by this
- // function.
- void UnregisterTaskQueue(scoped_refptr<internal::TaskQueueImpl> task_queue);
-
- // TaskQueueSelector::Observer implementation:
- void OnTaskQueueEnabled(internal::TaskQueueImpl* queue) override;
- void OnTriedToSelectBlockedWorkQueue(
- internal::WorkQueue* work_queue) override;
-
- // Called by the task queue to register a new pending task.
- void DidQueueTask(const internal::TaskQueueImpl::Task& pending_task);
-
- // Use the selector to choose a pending task and run it.
- void DoWork(base::TimeTicks run_time, bool from_main_thread);
-
- // Delayed Tasks with run_times <= Now() are enqueued onto the work queue.
- // Reloads any empty work queues which have automatic pumping enabled and
- // which are eligible to be auto pumped based on the |previous_task| which was
- // run and |should_trigger_wakeup|. Call with an empty |previous_task| if no
- // task was just run.
- void UpdateWorkQueues(bool should_trigger_wakeup,
- const internal::TaskQueueImpl::Task* previous_task);
-
- // Chooses the next work queue to service. Returns true if |out_queue|
- // indicates the queue from which the next task should be run, false to
- // avoid running any tasks.
- bool SelectWorkQueueToService(internal::WorkQueue** out_work_queue);
-
- // Runs a single nestable task from the |queue|. On exit, |out_task| will
- // contain the task which was executed. Non-nestable task are reposted on the
- // run loop. The queue must not be empty.
- enum class ProcessTaskResult {
- DEFERRED,
- EXECUTED,
- TASK_QUEUE_MANAGER_DELETED
- };
- ProcessTaskResult ProcessTaskFromWorkQueue(
- internal::WorkQueue* work_queue,
- internal::TaskQueueImpl::Task* out_previous_task);
-
- bool RunsTasksOnCurrentThread() const;
- bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay);
-
- internal::EnqueueOrder GetNextSequenceNumber();
-
- // Calls MaybeAdvanceTime on all time domains and returns true if one of them
- // was able to advance.
- bool TryAdvanceTimeDomains();
-
- void MaybeRecordTaskDelayHistograms(
- const internal::TaskQueueImpl::Task& pending_task,
- const internal::TaskQueueImpl* queue);
-
- std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
- AsValueWithSelectorResult(bool should_run,
- internal::WorkQueue* selected_work_queue) const;
-
- std::set<TimeDomain*> time_domains_;
- std::unique_ptr<RealTimeDomain> real_time_domain_;
-
- std::set<scoped_refptr<internal::TaskQueueImpl>> queues_;
-
- // We have to be careful when deleting a queue because some of the code uses
- // raw pointers and doesn't expect the rug to be pulled out from underneath.
- std::set<scoped_refptr<internal::TaskQueueImpl>> queues_to_delete_;
-
- internal::EnqueueOrderGenerator enqueue_order_generator_;
- base::debug::TaskAnnotator task_annotator_;
-
- base::ThreadChecker main_thread_checker_;
- scoped_refptr<TaskQueueManagerDelegate> delegate_;
- internal::TaskQueueSelector selector_;
-
- base::Closure from_main_thread_immediate_do_work_closure_;
- base::Closure from_other_thread_immediate_do_work_closure_;
-
- bool task_was_run_on_quiescence_monitored_queue_;
-
- // To reduce locking overhead we track pending calls to DoWork seperatly for
- // the main thread and other threads.
- std::set<base::TimeTicks> main_thread_pending_wakeups_;
-
- // Protects |other_thread_pending_wakeups_|.
- mutable base::Lock other_thread_lock_;
- std::set<base::TimeTicks> other_thread_pending_wakeups_;
-
- int work_batch_size_;
- size_t task_count_;
-
- base::ObserverList<base::MessageLoop::TaskObserver> task_observers_;
-
- const char* tracing_category_;
- const char* disabled_by_default_tracing_category_;
- const char* disabled_by_default_verbose_tracing_category_;
-
- internal::TaskQueueImpl* currently_executing_task_queue_; // NOT OWNED
-
- Observer* observer_; // NOT OWNED
- scoped_refptr<DeletionSentinel> deletion_sentinel_;
- base::WeakPtrFactory<TaskQueueManager> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskQueueManager);
-};
-
-} // namespace scheduler
-
-#endif // CONTENT_RENDERER_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_
diff --git a/chromium/components/scheduler/base/task_queue_manager_delegate.h b/chromium/components/scheduler/base/task_queue_manager_delegate.h
deleted file mode 100644
index 1bb405015f4..00000000000
--- a/chromium/components/scheduler/base/task_queue_manager_delegate.h
+++ /dev/null
@@ -1,34 +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 COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_H_
-#define COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_H_
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/time/tick_clock.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-class SCHEDULER_EXPORT TaskQueueManagerDelegate
- : public base::SingleThreadTaskRunner,
- public base::TickClock {
- public:
- TaskQueueManagerDelegate() {}
-
- // Returns true if the task runner is nested (i.e., running a run loop within
- // a nested task).
- virtual bool IsNested() const = 0;
-
- protected:
- ~TaskQueueManagerDelegate() override {}
-
- DISALLOW_COPY_AND_ASSIGN(TaskQueueManagerDelegate);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_H_
diff --git a/chromium/components/scheduler/base/task_queue_manager_delegate_for_test.cc b/chromium/components/scheduler/base/task_queue_manager_delegate_for_test.cc
deleted file mode 100644
index 56380307db4..00000000000
--- a/chromium/components/scheduler/base/task_queue_manager_delegate_for_test.cc
+++ /dev/null
@@ -1,56 +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 "components/scheduler/base/task_queue_manager_delegate_for_test.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-
-namespace scheduler {
-
-// static
-scoped_refptr<TaskQueueManagerDelegateForTest>
-TaskQueueManagerDelegateForTest::Create(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- std::unique_ptr<base::TickClock> time_source) {
- return make_scoped_refptr(
- new TaskQueueManagerDelegateForTest(task_runner, std::move(time_source)));
-}
-
-TaskQueueManagerDelegateForTest::TaskQueueManagerDelegateForTest(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- std::unique_ptr<base::TickClock> time_source)
- : task_runner_(task_runner), time_source_(std::move(time_source)) {}
-
-TaskQueueManagerDelegateForTest::~TaskQueueManagerDelegateForTest() {}
-
-bool TaskQueueManagerDelegateForTest::PostDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- return task_runner_->PostDelayedTask(from_here, task, delay);
-}
-
-bool TaskQueueManagerDelegateForTest::PostNonNestableDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- return task_runner_->PostNonNestableDelayedTask(from_here, task, delay);
-}
-
-bool TaskQueueManagerDelegateForTest::RunsTasksOnCurrentThread() const {
- return task_runner_->RunsTasksOnCurrentThread();
-}
-
-bool TaskQueueManagerDelegateForTest::IsNested() const {
- return false;
-}
-
-base::TimeTicks TaskQueueManagerDelegateForTest::NowTicks() {
- return time_source_->NowTicks();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/task_queue_manager_delegate_for_test.h b/chromium/components/scheduler/base/task_queue_manager_delegate_for_test.h
deleted file mode 100644
index cb97e474e7f..00000000000
--- a/chromium/components/scheduler/base/task_queue_manager_delegate_for_test.h
+++ /dev/null
@@ -1,48 +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 COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_FOR_TEST_H_
-#define COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_FOR_TEST_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/time/tick_clock.h"
-#include "components/scheduler/base/task_queue_manager_delegate.h"
-
-namespace scheduler {
-
-class TaskQueueManagerDelegateForTest : public TaskQueueManagerDelegate {
- public:
- static scoped_refptr<TaskQueueManagerDelegateForTest> Create(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- std::unique_ptr<base::TickClock> time_source);
-
- // NestableSingleThreadTaskRunner implementation
- bool PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override;
- bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override;
- bool RunsTasksOnCurrentThread() const override;
- bool IsNested() const override;
- base::TimeTicks NowTicks() override;
-
- protected:
- ~TaskQueueManagerDelegateForTest() override;
- TaskQueueManagerDelegateForTest(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- std::unique_ptr<base::TickClock> time_source);
-
- private:
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- std::unique_ptr<base::TickClock> time_source_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskQueueManagerDelegateForTest);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_FOR_TEST_H_
diff --git a/chromium/components/scheduler/base/task_queue_manager_perftest.cc b/chromium/components/scheduler/base/task_queue_manager_perftest.cc
deleted file mode 100644
index a81fea329dc..00000000000
--- a/chromium/components/scheduler/base/task_queue_manager_perftest.cc
+++ /dev/null
@@ -1,163 +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 "components/scheduler/base/task_queue_manager.h"
-
-#include <stddef.h>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/threading/thread.h"
-#include "base/time/default_tick_clock.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/task_queue_manager_delegate_for_test.h"
-#include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/base/work_queue_sets.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
-
-namespace scheduler {
-
-class TaskQueueManagerPerfTest : public testing::Test {
- public:
- TaskQueueManagerPerfTest()
- : num_queues_(0),
- max_tasks_in_flight_(0),
- num_tasks_in_flight_(0),
- num_tasks_to_post_(0),
- num_tasks_to_run_(0) {}
-
- void SetUp() override {
- if (base::ThreadTicks::IsSupported())
- base::ThreadTicks::WaitUntilInitialized();
- }
-
- void Initialize(size_t num_queues) {
- num_queues_ = num_queues;
- message_loop_.reset(new base::MessageLoop());
- manager_ = base::WrapUnique(new TaskQueueManager(
- TaskQueueManagerDelegateForTest::Create(
- message_loop_->task_runner(),
- base::WrapUnique(new base::DefaultTickClock())),
- "fake.category", "fake.category", "fake.category.debug"));
- for (size_t i = 0; i < num_queues; i++)
- queues_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test")));
- }
-
- void TestDelayedTask() {
- if (--num_tasks_to_run_ == 0) {
- message_loop_->QuitWhenIdle();
- }
-
- num_tasks_in_flight_--;
- // NOTE there are only up to max_tasks_in_flight_ pending delayed tasks at
- // any one time. Thanks to the lower_num_tasks_to_post going to zero if
- // there are a lot of tasks in flight, the total number of task in flight at
- // any one time is very variable.
- unsigned int lower_num_tasks_to_post =
- num_tasks_in_flight_ < (max_tasks_in_flight_ / 2) ? 1 : 0;
- unsigned int max_tasks_to_post =
- num_tasks_to_post_ % 2 ? lower_num_tasks_to_post : 10;
- for (unsigned int i = 0;
- i < max_tasks_to_post && num_tasks_in_flight_ < max_tasks_in_flight_ &&
- num_tasks_to_post_ > 0;
- i++) {
- // Choose a queue weighted towards queue 0.
- unsigned int queue = num_tasks_to_post_ % (num_queues_ + 1);
- if (queue == num_queues_) {
- queue = 0;
- }
- // Simulate a mix of short and longer delays.
- unsigned int delay =
- num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10);
- queues_[queue]->PostDelayedTask(
- FROM_HERE, base::Bind(&TaskQueueManagerPerfTest::TestDelayedTask,
- base::Unretained(this)),
- base::TimeDelta::FromMicroseconds(delay));
- num_tasks_in_flight_++;
- num_tasks_to_post_--;
- }
- }
-
- void ResetAndCallTestDelayedTask(unsigned int num_tasks_to_run) {
- num_tasks_in_flight_ = 1;
- num_tasks_to_post_ = num_tasks_to_run;
- num_tasks_to_run_ = num_tasks_to_run;
- TestDelayedTask();
- }
-
- void Benchmark(const std::string& trace, const base::Closure& test_task) {
- base::ThreadTicks start = base::ThreadTicks::Now();
- base::ThreadTicks now;
- unsigned long long num_iterations = 0;
- do {
- test_task.Run();
- message_loop_->Run();
- now = base::ThreadTicks::Now();
- num_iterations++;
- } while (now - start < base::TimeDelta::FromSeconds(5));
- perf_test::PrintResult(
- "task", "", trace,
- (now - start).InMicroseconds() / static_cast<double>(num_iterations),
- "us/run", true);
- }
-
- size_t num_queues_;
- unsigned int max_tasks_in_flight_;
- unsigned int num_tasks_in_flight_;
- unsigned int num_tasks_to_post_;
- unsigned int num_tasks_to_run_;
- std::unique_ptr<TaskQueueManager> manager_;
- std::unique_ptr<base::MessageLoop> message_loop_;
- std::vector<scoped_refptr<base::SingleThreadTaskRunner>> queues_;
-};
-
-TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_OneQueue) {
- if (!base::ThreadTicks::IsSupported())
- return;
- Initialize(1u);
-
- max_tasks_in_flight_ = 200;
- Benchmark("run 10000 delayed tasks with one queue",
- base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
- base::Unretained(this), 10000));
-}
-
-TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_FourQueues) {
- if (!base::ThreadTicks::IsSupported())
- return;
- Initialize(4u);
-
- max_tasks_in_flight_ = 200;
- Benchmark("run 10000 delayed tasks with four queues",
- base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
- base::Unretained(this), 10000));
-}
-
-TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_EightQueues) {
- if (!base::ThreadTicks::IsSupported())
- return;
- Initialize(8u);
-
- max_tasks_in_flight_ = 200;
- Benchmark("run 10000 delayed tasks with eight queues",
- base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
- base::Unretained(this), 10000));
-}
-
-TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_ThirtyTwoQueues) {
- if (!base::ThreadTicks::IsSupported())
- return;
- Initialize(32u);
-
- max_tasks_in_flight_ = 200;
- Benchmark("run 10000 delayed tasks with eight queues",
- base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
- base::Unretained(this), 10000));
-}
-
-// TODO(alexclarke): Add additional tests with different mixes of non-delayed vs
-// delayed tasks.
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/task_queue_manager_unittest.cc b/chromium/components/scheduler/base/task_queue_manager_unittest.cc
deleted file mode 100644
index fef14d2fe57..00000000000
--- a/chromium/components/scheduler/base/task_queue_manager_unittest.cc
+++ /dev/null
@@ -1,1929 +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 "components/scheduler/base/task_queue_manager.h"
-
-#include <stddef.h>
-
-#include <utility>
-
-#include "base/location.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "base/test/trace_event_analyzer.h"
-#include "base/threading/thread.h"
-#include "base/trace_event/blame_context.h"
-#include "base/trace_event/trace_buffer.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/real_time_domain.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/task_queue_manager_delegate_for_test.h"
-#include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/base/test_always_fail_time_source.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/base/virtual_time_domain.h"
-#include "components/scheduler/base/work_queue.h"
-#include "components/scheduler/base/work_queue_sets.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using testing::ElementsAre;
-using testing::ElementsAreArray;
-using testing::_;
-using scheduler::internal::EnqueueOrder;
-
-namespace scheduler {
-
-class MessageLoopTaskRunner : public TaskQueueManagerDelegateForTest {
- public:
- static scoped_refptr<MessageLoopTaskRunner> Create(
- std::unique_ptr<base::TickClock> tick_clock) {
- return make_scoped_refptr(new MessageLoopTaskRunner(std::move(tick_clock)));
- }
-
- // NestableTaskRunner implementation.
- bool IsNested() const override {
- return base::MessageLoop::current()->IsNested();
- }
-
- private:
- explicit MessageLoopTaskRunner(std::unique_ptr<base::TickClock> tick_clock)
- : TaskQueueManagerDelegateForTest(
- base::MessageLoop::current()->task_runner(),
- std::move(tick_clock)) {}
- ~MessageLoopTaskRunner() override {}
-};
-
-class TaskQueueManagerTest : public testing::Test {
- public:
- void DeleteTaskQueueManager() { manager_.reset(); }
-
- protected:
- void InitializeWithClock(size_t num_queues,
- std::unique_ptr<base::TickClock> test_time_source) {
- test_task_runner_ = make_scoped_refptr(
- new cc::OrderedSimpleTaskRunner(now_src_.get(), false));
- main_task_runner_ = TaskQueueManagerDelegateForTest::Create(
- test_task_runner_.get(),
- base::WrapUnique(new TestTimeSource(now_src_.get())));
- manager_ = base::WrapUnique(
- new TaskQueueManager(main_task_runner_, "test.scheduler",
- "test.scheduler", "test.scheduler.debug"));
-
- for (size_t i = 0; i < num_queues; i++)
- runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue")));
- }
-
- void Initialize(size_t num_queues) {
- now_src_.reset(new base::SimpleTestTickClock());
- now_src_->Advance(base::TimeDelta::FromMicroseconds(1000));
- InitializeWithClock(num_queues,
- base::WrapUnique(new TestTimeSource(now_src_.get())));
- }
-
- void InitializeWithRealMessageLoop(size_t num_queues) {
- now_src_.reset(new base::SimpleTestTickClock());
- message_loop_.reset(new base::MessageLoop());
- manager_ = base::WrapUnique(new TaskQueueManager(
- MessageLoopTaskRunner::Create(
- base::WrapUnique(new TestTimeSource(now_src_.get()))),
- "test.scheduler", "test.scheduler", "test.scheduler.debug"));
-
- for (size_t i = 0; i < num_queues; i++)
- runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue")));
- }
-
- std::unique_ptr<base::MessageLoop> message_loop_;
- std::unique_ptr<base::SimpleTestTickClock> now_src_;
- scoped_refptr<TaskQueueManagerDelegateForTest> main_task_runner_;
- scoped_refptr<cc::OrderedSimpleTaskRunner> test_task_runner_;
- std::unique_ptr<TaskQueueManager> manager_;
- std::vector<scoped_refptr<internal::TaskQueueImpl>> runners_;
-};
-
-void PostFromNestedRunloop(base::MessageLoop* message_loop,
- base::SingleThreadTaskRunner* runner,
- std::vector<std::pair<base::Closure, bool>>* tasks) {
- base::MessageLoop::ScopedNestableTaskAllower allow(message_loop);
- for (std::pair<base::Closure, bool>& pair : *tasks) {
- if (pair.second) {
- runner->PostTask(FROM_HERE, pair.first);
- } else {
- runner->PostNonNestableTask(FROM_HERE, pair.first);
- }
- }
- base::RunLoop().RunUntilIdle();
-}
-
-void NopTask() {}
-
-TEST_F(TaskQueueManagerTest, NowNotCalledWhenThereAreNoDelayedTasks) {
- message_loop_.reset(new base::MessageLoop());
- manager_ = base::WrapUnique(new TaskQueueManager(
- MessageLoopTaskRunner::Create(
- base::WrapUnique(new TestAlwaysFailTimeSource())),
- "test.scheduler", "test.scheduler", "test.scheduler.debug"));
-
- for (size_t i = 0; i < 3; i++)
- runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue")));
-
- runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask));
- runners_[1]->PostTask(FROM_HERE, base::Bind(&NopTask));
- runners_[1]->PostTask(FROM_HERE, base::Bind(&NopTask));
- runners_[2]->PostTask(FROM_HERE, base::Bind(&NopTask));
- runners_[2]->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- message_loop_->RunUntilIdle();
-}
-
-void NullTask() {}
-
-void TestTask(EnqueueOrder value, std::vector<EnqueueOrder>* out_result) {
- out_result->push_back(value);
-}
-
-TEST_F(TaskQueueManagerTest, SingleQueuePosting) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
-
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1, 2, 3));
-}
-
-TEST_F(TaskQueueManagerTest, MultiQueuePosting) {
- Initialize(3u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order));
- runners_[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 5, &run_order));
- runners_[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 6, &run_order));
-
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4, 5, 6));
-}
-
-TEST_F(TaskQueueManagerTest, NonNestableTaskPosting) {
- InitializeWithRealMessageLoop(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostNonNestableTask(FROM_HERE,
- base::Bind(&TestTask, 1, &run_order));
-
- message_loop_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1));
-}
-
-TEST_F(TaskQueueManagerTest, NonNestableTaskExecutesInExpectedOrder) {
- InitializeWithRealMessageLoop(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order));
- runners_[0]->PostNonNestableTask(FROM_HERE,
- base::Bind(&TestTask, 5, &run_order));
-
- message_loop_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4, 5));
-}
-
-TEST_F(TaskQueueManagerTest, NonNestableTaskDoesntExecuteInNestedLoop) {
- InitializeWithRealMessageLoop(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
-
- std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop;
- tasks_to_post_from_nested_loop.push_back(
- std::make_pair(base::Bind(&TestTask, 3, &run_order), false));
- tasks_to_post_from_nested_loop.push_back(
- std::make_pair(base::Bind(&TestTask, 4, &run_order), true));
- tasks_to_post_from_nested_loop.push_back(
- std::make_pair(base::Bind(&TestTask, 5, &run_order), true));
-
- runners_[0]->PostTask(
- FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(),
- base::RetainedRef(runners_[0]),
- base::Unretained(&tasks_to_post_from_nested_loop)));
-
- message_loop_->RunUntilIdle();
- // Note we expect task 3 to run last because it's non-nestable.
- EXPECT_THAT(run_order, ElementsAre(1, 2, 4, 5, 3));
-}
-
-TEST_F(TaskQueueManagerTest, QueuePolling) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- EXPECT_FALSE(runners_[0]->HasPendingImmediateWork());
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- EXPECT_TRUE(runners_[0]->HasPendingImmediateWork());
-
- test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(runners_[0]->HasPendingImmediateWork());
-}
-
-TEST_F(TaskQueueManagerTest, DelayedTaskPosting) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- delay);
- EXPECT_EQ(delay, test_task_runner_->DelayToNextTaskTime());
- EXPECT_FALSE(runners_[0]->HasPendingImmediateWork());
- EXPECT_TRUE(run_order.empty());
-
- // The task doesn't run before the delay has completed.
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(9));
- EXPECT_TRUE(run_order.empty());
-
- // After the delay has completed, the task runs normally.
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(1));
- EXPECT_THAT(run_order, ElementsAre(1));
- EXPECT_FALSE(runners_[0]->HasPendingImmediateWork());
-}
-
-bool MessageLoopTaskCounter(size_t* count) {
- *count = *count + 1;
- return true;
-}
-
-TEST_F(TaskQueueManagerTest, DelayedTaskExecutedInOneMessageLoopTask) {
- Initialize(1u);
-
- base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay);
-
- size_t task_count = 0;
- test_task_runner_->RunTasksWhile(
- base::Bind(&MessageLoopTaskCounter, &task_count));
- EXPECT_EQ(1u, task_count);
-}
-
-TEST_F(TaskQueueManagerTest, DelayedTaskPosting_MultipleTasks_DecendingOrder) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- base::TimeDelta::FromMilliseconds(10));
-
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
- base::TimeDelta::FromMilliseconds(8));
-
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order),
- base::TimeDelta::FromMilliseconds(5));
-
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(5),
- test_task_runner_->DelayToNextTaskTime());
-
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(5));
- EXPECT_THAT(run_order, ElementsAre(3));
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(3),
- test_task_runner_->DelayToNextTaskTime());
-
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(3));
- EXPECT_THAT(run_order, ElementsAre(3, 2));
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(2),
- test_task_runner_->DelayToNextTaskTime());
-
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(2));
- EXPECT_THAT(run_order, ElementsAre(3, 2, 1));
-}
-
-TEST_F(TaskQueueManagerTest, DelayedTaskPosting_MultipleTasks_AscendingOrder) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- base::TimeDelta::FromMilliseconds(1));
-
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
- base::TimeDelta::FromMilliseconds(5));
-
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order),
- base::TimeDelta::FromMilliseconds(10));
-
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(1),
- test_task_runner_->DelayToNextTaskTime());
-
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(1));
- EXPECT_THAT(run_order, ElementsAre(1));
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(4),
- test_task_runner_->DelayToNextTaskTime());
-
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(4));
- EXPECT_THAT(run_order, ElementsAre(1, 2));
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(5),
- test_task_runner_->DelayToNextTaskTime());
-
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(5));
- EXPECT_THAT(run_order, ElementsAre(1, 2, 3));
-}
-
-TEST_F(TaskQueueManagerTest, PostDelayedTask_SharesUnderlyingDelayedTasks) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- delay);
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
- delay);
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order),
- delay);
-
- EXPECT_EQ(1u, test_task_runner_->NumPendingTasks());
-}
-
-class TestObject {
- public:
- ~TestObject() { destructor_count_++; }
-
- void Run() { FAIL() << "TestObject::Run should not be called"; }
-
- static int destructor_count_;
-};
-
-int TestObject::destructor_count_ = 0;
-
-TEST_F(TaskQueueManagerTest, PendingDelayedTasksRemovedOnShutdown) {
- Initialize(1u);
-
- TestObject::destructor_count_ = 0;
-
- base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
- runners_[0]->PostDelayedTask(
- FROM_HERE, base::Bind(&TestObject::Run, base::Owned(new TestObject())),
- delay);
- runners_[0]->PostTask(
- FROM_HERE, base::Bind(&TestObject::Run, base::Owned(new TestObject())));
-
- manager_.reset();
-
- EXPECT_EQ(2, TestObject::destructor_count_);
-}
-
-TEST_F(TaskQueueManagerTest, ManualPumping) {
- Initialize(1u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
-
- std::vector<EnqueueOrder> run_order;
- // Posting a task when pumping is disabled doesn't result in work getting
- // posted.
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- EXPECT_FALSE(test_task_runner_->HasPendingTasks());
-
- // However polling still works.
- EXPECT_TRUE(runners_[0]->HasPendingImmediateWork());
-
- // After pumping the task runs normally.
- LazyNow lazy_now(now_src_.get());
- runners_[0]->PumpQueue(&lazy_now, true);
- EXPECT_TRUE(test_task_runner_->HasPendingTasks());
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1));
-}
-
-TEST_F(TaskQueueManagerTest, ManualPumpingToggle) {
- Initialize(1u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
-
- std::vector<EnqueueOrder> run_order;
- // Posting a task when pumping is disabled doesn't result in work getting
- // posted.
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- EXPECT_FALSE(test_task_runner_->HasPendingTasks());
-
- // When pumping is enabled the task runs normally.
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
- EXPECT_TRUE(test_task_runner_->HasPendingTasks());
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1));
-}
-
-TEST_F(TaskQueueManagerTest, DenyRunning_BeforePosting) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->SetQueueEnabled(false);
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- runners_[0]->SetQueueEnabled(true);
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1));
-}
-
-TEST_F(TaskQueueManagerTest, DenyRunning_AfterPosting) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[0]->SetQueueEnabled(false);
-
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- runners_[0]->SetQueueEnabled(true);
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1));
-}
-
-TEST_F(TaskQueueManagerTest, DenyRunning_ManuallyPumpedTransitionsToAuto) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
- runners_[0]->SetQueueEnabled(false);
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
- runners_[0]->SetQueueEnabled(true);
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1));
-}
-
-TEST_F(TaskQueueManagerTest, ManualPumpingWithDelayedTask) {
- Initialize(1u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
-
- std::vector<EnqueueOrder> run_order;
- // Posting a delayed task when pumping will apply the delay, but won't cause
- // work to executed afterwards.
- base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- delay);
-
- // After pumping but before the delay period has expired, task does not run.
- LazyNow lazy_now1(now_src_.get());
- runners_[0]->PumpQueue(&lazy_now1, true);
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(5));
- EXPECT_TRUE(run_order.empty());
-
- // Once the delay has expired, pumping causes the task to run.
- now_src_->Advance(base::TimeDelta::FromMilliseconds(5));
- LazyNow lazy_now2(now_src_.get());
- runners_[0]->PumpQueue(&lazy_now2, true);
- EXPECT_TRUE(test_task_runner_->HasPendingTasks());
- test_task_runner_->RunPendingTasks();
- EXPECT_THAT(run_order, ElementsAre(1));
-}
-
-TEST_F(TaskQueueManagerTest, ManualPumpingWithMultipleDelayedTasks) {
- Initialize(1u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
-
- std::vector<EnqueueOrder> run_order;
- // Posting a delayed task when pumping will apply the delay, but won't cause
- // work to executed afterwards.
- base::TimeDelta delay1(base::TimeDelta::FromMilliseconds(1));
- base::TimeDelta delay2(base::TimeDelta::FromMilliseconds(10));
- base::TimeDelta delay3(base::TimeDelta::FromMilliseconds(20));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- delay1);
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
- delay2);
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order),
- delay3);
-
- now_src_->Advance(base::TimeDelta::FromMilliseconds(15));
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- // Once the delay has expired, pumping causes the task to run.
- LazyNow lazy_now(now_src_.get());
- runners_[0]->PumpQueue(&lazy_now, true);
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1, 2));
-}
-
-TEST_F(TaskQueueManagerTest, DelayedTasksDontAutoRunWithManualPumping) {
- Initialize(1u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
-
- std::vector<EnqueueOrder> run_order;
- base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- delay);
-
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(10));
- EXPECT_TRUE(run_order.empty());
-}
-
-TEST_F(TaskQueueManagerTest, ManualPumpingWithNonEmptyWorkQueue) {
- Initialize(1u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
-
- std::vector<EnqueueOrder> run_order;
- // Posting two tasks and pumping twice should result in two tasks in the work
- // queue.
- LazyNow lazy_now(now_src_.get());
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[0]->PumpQueue(&lazy_now, true);
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- runners_[0]->PumpQueue(&lazy_now, true);
-
- EXPECT_EQ(2u, runners_[0]->immediate_work_queue()->Size());
-}
-
-void ReentrantTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner,
- int countdown,
- std::vector<EnqueueOrder>* out_result) {
- out_result->push_back(countdown);
- if (--countdown) {
- runner->PostTask(FROM_HERE,
- Bind(&ReentrantTestTask, runner, countdown, out_result));
- }
-}
-
-TEST_F(TaskQueueManagerTest, ReentrantPosting) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE,
- Bind(&ReentrantTestTask, runners_[0], 3, &run_order));
-
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(3, 2, 1));
-}
-
-TEST_F(TaskQueueManagerTest, NoTasksAfterShutdown) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- manager_.reset();
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-}
-
-void PostTaskToRunner(scoped_refptr<base::SingleThreadTaskRunner> runner,
- std::vector<EnqueueOrder>* run_order) {
- runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, run_order));
-}
-
-TEST_F(TaskQueueManagerTest, PostFromThread) {
- InitializeWithRealMessageLoop(1u);
-
- std::vector<EnqueueOrder> run_order;
- base::Thread thread("TestThread");
- thread.Start();
- thread.task_runner()->PostTask(
- FROM_HERE, base::Bind(&PostTaskToRunner, runners_[0], &run_order));
- thread.Stop();
-
- message_loop_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1));
-}
-
-void RePostingTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner,
- int* run_count) {
- (*run_count)++;
- runner->PostTask(FROM_HERE, Bind(&RePostingTestTask,
- base::Unretained(runner.get()), run_count));
-}
-
-TEST_F(TaskQueueManagerTest, DoWorkCantPostItselfMultipleTimes) {
- Initialize(1u);
-
- int run_count = 0;
- runners_[0]->PostTask(
- FROM_HERE, base::Bind(&RePostingTestTask, runners_[0], &run_count));
-
- test_task_runner_->RunPendingTasks();
- // NOTE without the executing_task_ check in MaybeScheduleDoWork there
- // will be two tasks here.
- EXPECT_EQ(1u, test_task_runner_->NumPendingTasks());
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(TaskQueueManagerTest, PostFromNestedRunloop) {
- InitializeWithRealMessageLoop(1u);
-
- std::vector<EnqueueOrder> run_order;
- std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop;
- tasks_to_post_from_nested_loop.push_back(
- std::make_pair(base::Bind(&TestTask, 1, &run_order), true));
-
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 0, &run_order));
- runners_[0]->PostTask(
- FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(),
- base::RetainedRef(runners_[0]),
- base::Unretained(&tasks_to_post_from_nested_loop)));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
-
- message_loop_->RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(0, 2, 1));
-}
-
-TEST_F(TaskQueueManagerTest, WorkBatching) {
- Initialize(1u);
-
- manager_->SetWorkBatchSize(2);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order));
-
- // Running one task in the host message loop should cause two posted tasks to
- // get executed.
- EXPECT_EQ(test_task_runner_->NumPendingTasks(), 1u);
- test_task_runner_->RunPendingTasks();
- EXPECT_THAT(run_order, ElementsAre(1, 2));
-
- // The second task runs the remaining two posted tasks.
- EXPECT_EQ(test_task_runner_->NumPendingTasks(), 1u);
- test_task_runner_->RunPendingTasks();
- EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4));
-}
-
-TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeup) {
- Initialize(2u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty()); // Shouldn't run - no other task to wake TQM.
-
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty()); // Still shouldn't wake TQM.
-
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
- test_task_runner_->RunUntilIdle();
- // Executing a task on an auto pumped queue should wake the TQM.
- EXPECT_THAT(run_order, ElementsAre(3, 1, 2));
-}
-
-TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupWhenAlreadyAwake) {
- Initialize(2u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(2, 1)); // TQM was already awake.
-}
-
-TEST_F(TaskQueueManagerTest,
- AutoPumpAfterWakeupTriggeredByManuallyPumpedQueue) {
- Initialize(2u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
- runners_[1]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty()); // Shouldn't run - no other task to wake TQM.
-
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- test_task_runner_->RunUntilIdle();
- // This still shouldn't wake TQM as manual queue was not pumped.
- EXPECT_TRUE(run_order.empty());
-
- LazyNow lazy_now(now_src_.get());
- runners_[1]->PumpQueue(&lazy_now, true);
- test_task_runner_->RunUntilIdle();
- // Executing a task on an auto pumped queue should wake the TQM.
- EXPECT_THAT(run_order, ElementsAre(2, 1));
-}
-
-void TestPostingTask(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- base::Closure task) {
- task_runner->PostTask(FROM_HERE, task);
-}
-
-TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupFromTask) {
- Initialize(2u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
-
- std::vector<EnqueueOrder> run_order;
- // Check that a task which posts a task to an auto pump after wakeup queue
- // doesn't cause the queue to wake up.
- base::Closure after_wakeup_task = base::Bind(&TestTask, 1, &run_order);
- runners_[1]->PostTask(
- FROM_HERE, base::Bind(&TestPostingTask, runners_[0], after_wakeup_task));
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- // Wake up the queue.
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(2, 1));
-}
-
-TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupFromMultipleTasks) {
- Initialize(2u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
-
- std::vector<EnqueueOrder> run_order;
- // Check that a task which posts a task to an auto pump after wakeup queue
- // doesn't cause the queue to wake up.
- base::Closure after_wakeup_task_1 = base::Bind(&TestTask, 1, &run_order);
- base::Closure after_wakeup_task_2 = base::Bind(&TestTask, 2, &run_order);
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestPostingTask, runners_[0],
- after_wakeup_task_1));
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestPostingTask, runners_[0],
- after_wakeup_task_2));
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- // Wake up the queue.
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(3, 1, 2));
-}
-
-TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupBecomesQuiescent) {
- Initialize(2u);
- runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
-
- int run_count = 0;
- // Check that if multiple tasks reposts themselves onto a pump-after-wakeup
- // queue they don't wake each other and will eventually stop when no other
- // tasks execute.
- runners_[0]->PostTask(
- FROM_HERE, base::Bind(&RePostingTestTask, runners_[0], &run_count));
- runners_[0]->PostTask(
- FROM_HERE, base::Bind(&RePostingTestTask, runners_[0], &run_count));
- runners_[1]->PostTask(FROM_HERE, base::Bind(&NopTask));
- test_task_runner_->RunUntilIdle();
- // The reposting tasks posted to the after wakeup queue shouldn't have woken
- // each other up.
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupWithDontWakeQueue) {
- Initialize(1u);
-
- scoped_refptr<internal::TaskQueueImpl> queue0 = manager_->NewTaskQueue(
- TaskQueue::Spec("test_queue 0")
- .SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP));
- scoped_refptr<internal::TaskQueueImpl> queue1 = manager_->NewTaskQueue(
- TaskQueue::Spec("test_queue 0")
- .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES));
- scoped_refptr<internal::TaskQueueImpl> queue2 = runners_[0];
-
- std::vector<EnqueueOrder> run_order;
- queue0->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- test_task_runner_->RunUntilIdle();
- // Executing a DONT_WAKE_OTHER_QUEUES queue shouldn't wake the autopump after
- // wakeup queue.
- EXPECT_THAT(run_order, ElementsAre(2));
-
- queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
- test_task_runner_->RunUntilIdle();
- // Executing a CAN_WAKE_OTHER_QUEUES queue should wake the autopump after
- // wakeup queue.
- EXPECT_THAT(run_order, ElementsAre(2, 3, 1));
-}
-
-class MockTaskObserver : public base::MessageLoop::TaskObserver {
- public:
- MOCK_METHOD1(DidProcessTask, void(const base::PendingTask& task));
- MOCK_METHOD1(WillProcessTask, void(const base::PendingTask& task));
-};
-
-TEST_F(TaskQueueManagerTest, TaskObserverAdding) {
- InitializeWithRealMessageLoop(1u);
- MockTaskObserver observer;
-
- manager_->SetWorkBatchSize(2);
- manager_->AddTaskObserver(&observer);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
-
- EXPECT_CALL(observer, WillProcessTask(_)).Times(2);
- EXPECT_CALL(observer, DidProcessTask(_)).Times(2);
- message_loop_->RunUntilIdle();
-}
-
-TEST_F(TaskQueueManagerTest, TaskObserverRemoving) {
- InitializeWithRealMessageLoop(1u);
- MockTaskObserver observer;
- manager_->SetWorkBatchSize(2);
- manager_->AddTaskObserver(&observer);
- manager_->RemoveTaskObserver(&observer);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-
- EXPECT_CALL(observer, WillProcessTask(_)).Times(0);
- EXPECT_CALL(observer, DidProcessTask(_)).Times(0);
-
- message_loop_->RunUntilIdle();
-}
-
-void RemoveObserverTask(TaskQueueManager* manager,
- base::MessageLoop::TaskObserver* observer) {
- manager->RemoveTaskObserver(observer);
-}
-
-TEST_F(TaskQueueManagerTest, TaskObserverRemovingInsideTask) {
- InitializeWithRealMessageLoop(1u);
- MockTaskObserver observer;
- manager_->SetWorkBatchSize(3);
- manager_->AddTaskObserver(&observer);
-
- runners_[0]->PostTask(
- FROM_HERE, base::Bind(&RemoveObserverTask, manager_.get(), &observer));
-
- EXPECT_CALL(observer, WillProcessTask(_)).Times(1);
- EXPECT_CALL(observer, DidProcessTask(_)).Times(0);
- message_loop_->RunUntilIdle();
-}
-
-TEST_F(TaskQueueManagerTest, QueueTaskObserverAdding) {
- InitializeWithRealMessageLoop(2u);
- MockTaskObserver observer;
-
- manager_->SetWorkBatchSize(2);
- runners_[0]->AddTaskObserver(&observer);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
-
- EXPECT_CALL(observer, WillProcessTask(_)).Times(1);
- EXPECT_CALL(observer, DidProcessTask(_)).Times(1);
- message_loop_->RunUntilIdle();
-}
-
-TEST_F(TaskQueueManagerTest, QueueTaskObserverRemoving) {
- InitializeWithRealMessageLoop(1u);
- MockTaskObserver observer;
- manager_->SetWorkBatchSize(2);
- runners_[0]->AddTaskObserver(&observer);
- runners_[0]->RemoveTaskObserver(&observer);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-
- EXPECT_CALL(observer, WillProcessTask(_)).Times(0);
- EXPECT_CALL(observer, DidProcessTask(_)).Times(0);
-
- message_loop_->RunUntilIdle();
-}
-
-void RemoveQueueObserverTask(scoped_refptr<TaskQueue> queue,
- base::MessageLoop::TaskObserver* observer) {
- queue->RemoveTaskObserver(observer);
-}
-
-TEST_F(TaskQueueManagerTest, QueueTaskObserverRemovingInsideTask) {
- InitializeWithRealMessageLoop(1u);
- MockTaskObserver observer;
- runners_[0]->AddTaskObserver(&observer);
-
- runners_[0]->PostTask(
- FROM_HERE, base::Bind(&RemoveQueueObserverTask, runners_[0], &observer));
-
- EXPECT_CALL(observer, WillProcessTask(_)).Times(1);
- EXPECT_CALL(observer, DidProcessTask(_)).Times(0);
- message_loop_->RunUntilIdle();
-}
-
-TEST_F(TaskQueueManagerTest, ThreadCheckAfterTermination) {
- Initialize(1u);
- EXPECT_TRUE(runners_[0]->RunsTasksOnCurrentThread());
- manager_.reset();
- EXPECT_TRUE(runners_[0]->RunsTasksOnCurrentThread());
-}
-
-TEST_F(TaskQueueManagerTest, TimeDomain_NextScheduledRunTime) {
- Initialize(2u);
- now_src_->Advance(base::TimeDelta::FromMicroseconds(10000));
-
- // With no delayed tasks.
- base::TimeTicks run_time;
- EXPECT_FALSE(manager_->real_time_domain()->NextScheduledRunTime(&run_time));
-
- // With a non-delayed task.
- runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask));
- EXPECT_FALSE(manager_->real_time_domain()->NextScheduledRunTime(&run_time));
-
- // With a delayed task.
- base::TimeDelta expected_delay = base::TimeDelta::FromMilliseconds(50);
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), expected_delay);
- EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time));
- EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time);
-
- // With another delayed task in the same queue with a longer delay.
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask),
- base::TimeDelta::FromMilliseconds(100));
- EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time));
- EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time);
-
- // With another delayed task in the same queue with a shorter delay.
- expected_delay = base::TimeDelta::FromMilliseconds(20);
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), expected_delay);
- EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time));
- EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time);
-
- // With another delayed task in a different queue with a shorter delay.
- expected_delay = base::TimeDelta::FromMilliseconds(10);
- runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), expected_delay);
- EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time));
- EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time);
-
- // Test it updates as time progresses
- now_src_->Advance(expected_delay);
- EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time));
- EXPECT_EQ(now_src_->NowTicks(), run_time);
-}
-
-TEST_F(TaskQueueManagerTest, TimeDomain_NextScheduledRunTime_MultipleQueues) {
- Initialize(3u);
-
- base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(50);
- base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(5);
- base::TimeDelta delay3 = base::TimeDelta::FromMilliseconds(10);
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay1);
- runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay2);
- runners_[2]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay3);
- runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- base::TimeTicks run_time;
- EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time));
- EXPECT_EQ(now_src_->NowTicks() + delay2, run_time);
-}
-
-TEST_F(TaskQueueManagerTest, DeleteTaskQueueManagerInsideATask) {
- Initialize(1u);
-
- runners_[0]->PostTask(
- FROM_HERE, base::Bind(&TaskQueueManagerTest::DeleteTaskQueueManager,
- base::Unretained(this)));
-
- // This should not crash, assuming DoWork detects the TaskQueueManager has
- // been deleted.
- test_task_runner_->RunUntilIdle();
-}
-
-TEST_F(TaskQueueManagerTest, GetAndClearSystemIsQuiescentBit) {
- Initialize(3u);
-
- scoped_refptr<internal::TaskQueueImpl> queue0 = manager_->NewTaskQueue(
- TaskQueue::Spec("test_queue 0").SetShouldMonitorQuiescence(true));
- scoped_refptr<internal::TaskQueueImpl> queue1 = manager_->NewTaskQueue(
- TaskQueue::Spec("test_queue 1").SetShouldMonitorQuiescence(true));
- scoped_refptr<internal::TaskQueueImpl> queue2 = manager_->NewTaskQueue(
- TaskQueue::Spec("test_queue 2").SetShouldMonitorQuiescence(false));
-
- EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit());
-
- queue0->PostTask(FROM_HERE, base::Bind(&NopTask));
- test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(manager_->GetAndClearSystemIsQuiescentBit());
- EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit());
-
- queue1->PostTask(FROM_HERE, base::Bind(&NopTask));
- test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(manager_->GetAndClearSystemIsQuiescentBit());
- EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit());
-
- queue2->PostTask(FROM_HERE, base::Bind(&NopTask));
- test_task_runner_->RunUntilIdle();
- EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit());
-
- queue0->PostTask(FROM_HERE, base::Bind(&NopTask));
- queue1->PostTask(FROM_HERE, base::Bind(&NopTask));
- test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(manager_->GetAndClearSystemIsQuiescentBit());
- EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit());
-}
-
-TEST_F(TaskQueueManagerTest, HasPendingImmediateWork) {
- Initialize(2u);
- internal::TaskQueueImpl* queue0 = runners_[0].get();
- internal::TaskQueueImpl* queue1 = runners_[1].get();
- queue0->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
- queue1->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
-
- EXPECT_FALSE(queue0->HasPendingImmediateWork());
- EXPECT_FALSE(queue1->HasPendingImmediateWork());
-
- queue0->PostTask(FROM_HERE, base::Bind(NullTask));
- queue1->PostTask(FROM_HERE, base::Bind(NullTask));
- EXPECT_TRUE(queue0->HasPendingImmediateWork());
- EXPECT_TRUE(queue1->HasPendingImmediateWork());
-
- test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(queue0->HasPendingImmediateWork());
- EXPECT_TRUE(queue1->HasPendingImmediateWork());
-
- LazyNow lazy_now(now_src_.get());
- queue1->PumpQueue(&lazy_now, true);
- EXPECT_FALSE(queue0->HasPendingImmediateWork());
- EXPECT_TRUE(queue1->HasPendingImmediateWork());
-
- test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(queue0->HasPendingImmediateWork());
- EXPECT_FALSE(queue1->HasPendingImmediateWork());
-}
-
-TEST_F(TaskQueueManagerTest, HasPendingImmediateWorkAndNeedsPumping) {
- Initialize(2u);
- internal::TaskQueueImpl* queue0 = runners_[0].get();
- internal::TaskQueueImpl* queue1 = runners_[1].get();
- queue0->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
- queue1->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
-
- EXPECT_FALSE(queue0->HasPendingImmediateWork());
- EXPECT_FALSE(queue0->NeedsPumping());
- EXPECT_FALSE(queue1->HasPendingImmediateWork());
- EXPECT_FALSE(queue1->NeedsPumping());
-
- queue0->PostTask(FROM_HERE, base::Bind(NullTask));
- queue0->PostTask(FROM_HERE, base::Bind(NullTask));
- queue1->PostTask(FROM_HERE, base::Bind(NullTask));
- EXPECT_TRUE(queue0->HasPendingImmediateWork());
- EXPECT_TRUE(queue0->NeedsPumping());
- EXPECT_TRUE(queue1->HasPendingImmediateWork());
- EXPECT_TRUE(queue1->NeedsPumping());
-
- test_task_runner_->SetRunTaskLimit(1);
- test_task_runner_->RunPendingTasks();
- EXPECT_TRUE(queue0->HasPendingImmediateWork());
- EXPECT_FALSE(queue0->NeedsPumping());
- EXPECT_TRUE(queue1->HasPendingImmediateWork());
- EXPECT_TRUE(queue1->NeedsPumping());
-
- test_task_runner_->ClearRunTaskLimit();
- test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(queue0->HasPendingImmediateWork());
- EXPECT_FALSE(queue0->NeedsPumping());
- EXPECT_TRUE(queue1->HasPendingImmediateWork());
- EXPECT_TRUE(queue1->NeedsPumping());
-
- LazyNow lazy_now(now_src_.get());
- queue1->PumpQueue(&lazy_now, true);
- EXPECT_FALSE(queue0->HasPendingImmediateWork());
- EXPECT_FALSE(queue0->NeedsPumping());
- EXPECT_TRUE(queue1->HasPendingImmediateWork());
- EXPECT_FALSE(queue1->NeedsPumping());
-
- test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(queue0->HasPendingImmediateWork());
- EXPECT_FALSE(queue0->NeedsPumping());
- EXPECT_FALSE(queue1->HasPendingImmediateWork());
- EXPECT_FALSE(queue1->NeedsPumping());
-}
-
-void ExpensiveTestTask(int value,
- base::SimpleTestTickClock* clock,
- std::vector<EnqueueOrder>* out_result) {
- out_result->push_back(value);
- clock->Advance(base::TimeDelta::FromMilliseconds(1));
-}
-
-TEST_F(TaskQueueManagerTest, ImmediateAndDelayedTaskInterleaving) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
- for (int i = 10; i < 19; i++) {
- runners_[0]->PostDelayedTask(
- FROM_HERE,
- base::Bind(&ExpensiveTestTask, i, now_src_.get(), &run_order),
- delay);
- }
-
- test_task_runner_->RunForPeriod(delay);
-
- for (int i = 0; i < 9; i++) {
- runners_[0]->PostTask(
- FROM_HERE,
- base::Bind(&ExpensiveTestTask, i, now_src_.get(), &run_order));
- }
-
- test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- test_task_runner_->RunUntilIdle();
-
- // Delayed tasks are not allowed to starve out immediate work which is why
- // some of the immediate tasks run out of order.
- int expected_run_order[] = {
- 10, 11, 12, 13, 0, 14, 15, 16, 1, 17, 18, 2, 3, 4, 5, 6, 7, 8
- };
- EXPECT_THAT(run_order, ElementsAreArray(expected_run_order));
-}
-
-TEST_F(TaskQueueManagerTest,
- DelayedTaskDoesNotSkipAHeadOfNonDelayedTask_SameQueue) {
- Initialize(1u);
-
- std::vector<EnqueueOrder> run_order;
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- delay);
-
- now_src_->Advance(delay * 2);
- test_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(2, 3, 1));
-}
-
-TEST_F(TaskQueueManagerTest,
- DelayedTaskDoesNotSkipAHeadOfNonDelayedTask_DifferentQueues) {
- Initialize(2u);
-
- std::vector<EnqueueOrder> run_order;
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- delay);
-
- now_src_->Advance(delay * 2);
- test_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(2, 3, 1));
-}
-
-TEST_F(TaskQueueManagerTest, DelayedTaskDoesNotSkipAHeadOfShorterDelayedTask) {
- Initialize(2u);
-
- std::vector<EnqueueOrder> run_order;
- base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10);
- base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(5);
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- delay1);
- runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
- delay2);
-
- now_src_->Advance(delay1 * 2);
- test_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(2, 1));
-}
-
-void CheckIsNested(bool* is_nested) {
- *is_nested = base::MessageLoop::current()->IsNested();
-}
-
-void PostAndQuitFromNestedRunloop(base::RunLoop* run_loop,
- base::SingleThreadTaskRunner* runner,
- bool* was_nested) {
- base::MessageLoop::ScopedNestableTaskAllower allow(
- base::MessageLoop::current());
- runner->PostTask(FROM_HERE, run_loop->QuitClosure());
- runner->PostTask(FROM_HERE, base::Bind(&CheckIsNested, was_nested));
- run_loop->Run();
-}
-
-TEST_F(TaskQueueManagerTest, QuitWhileNested) {
- // This test makes sure we don't continue running a work batch after a nested
- // run loop has been exited in the middle of the batch.
- InitializeWithRealMessageLoop(1u);
- manager_->SetWorkBatchSize(2);
-
- bool was_nested = true;
- base::RunLoop run_loop;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&PostAndQuitFromNestedRunloop,
- base::Unretained(&run_loop),
- base::RetainedRef(runners_[0]),
- base::Unretained(&was_nested)));
-
- message_loop_->RunUntilIdle();
- EXPECT_FALSE(was_nested);
-}
-
-class SequenceNumberCapturingTaskObserver
- : public base::MessageLoop::TaskObserver {
- public:
- // MessageLoop::TaskObserver overrides.
- void WillProcessTask(const base::PendingTask& pending_task) override {}
- void DidProcessTask(const base::PendingTask& pending_task) override {
- sequence_numbers_.push_back(pending_task.sequence_num);
- }
-
- const std::vector<EnqueueOrder>& sequence_numbers() const {
- return sequence_numbers_;
- }
-
- private:
- std::vector<EnqueueOrder> sequence_numbers_;
-};
-
-TEST_F(TaskQueueManagerTest, SequenceNumSetWhenTaskIsPosted) {
- Initialize(1u);
-
- SequenceNumberCapturingTaskObserver observer;
- manager_->AddTaskObserver(&observer);
-
- // Register four tasks that will run in reverse order.
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- base::TimeDelta::FromMilliseconds(30));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
- base::TimeDelta::FromMilliseconds(20));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order),
- base::TimeDelta::FromMilliseconds(10));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order));
-
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(40));
- ASSERT_THAT(run_order, ElementsAre(4, 3, 2, 1));
-
- // The sequence numbers are a zero-based monotonically incrememting counter
- // which should be set when the task is posted rather than when it's enqueued
- // onto the Incoming queue.
- EXPECT_THAT(observer.sequence_numbers(), ElementsAre(3, 2, 1, 0));
-
- manager_->RemoveTaskObserver(&observer);
-}
-
-TEST_F(TaskQueueManagerTest, NewTaskQueues) {
- Initialize(1u);
-
- scoped_refptr<internal::TaskQueueImpl> queue1 =
- manager_->NewTaskQueue(TaskQueue::Spec("foo"));
- scoped_refptr<internal::TaskQueueImpl> queue2 =
- manager_->NewTaskQueue(TaskQueue::Spec("bar"));
- scoped_refptr<internal::TaskQueueImpl> queue3 =
- manager_->NewTaskQueue(TaskQueue::Spec("baz"));
-
- ASSERT_NE(queue1, queue2);
- ASSERT_NE(queue1, queue3);
- ASSERT_NE(queue2, queue3);
-
- std::vector<EnqueueOrder> run_order;
- queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- queue3->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
- test_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(1, 2, 3));
-}
-
-TEST_F(TaskQueueManagerTest, UnregisterTaskQueue) {
- Initialize(1u);
-
- scoped_refptr<internal::TaskQueueImpl> queue1 =
- manager_->NewTaskQueue(TaskQueue::Spec("foo"));
- scoped_refptr<internal::TaskQueueImpl> queue2 =
- manager_->NewTaskQueue(TaskQueue::Spec("bar"));
- scoped_refptr<internal::TaskQueueImpl> queue3 =
- manager_->NewTaskQueue(TaskQueue::Spec("baz"));
-
- ASSERT_NE(queue1, queue2);
- ASSERT_NE(queue1, queue3);
- ASSERT_NE(queue2, queue3);
-
- std::vector<EnqueueOrder> run_order;
- queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- queue3->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
-
- queue2->UnregisterTaskQueue();
- test_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(1, 3));
-}
-
-TEST_F(TaskQueueManagerTest, UnregisterTaskQueue_WithDelayedTasks) {
- Initialize(2u);
-
- // Register three delayed tasks
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- base::TimeDelta::FromMilliseconds(10));
- runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
- base::TimeDelta::FromMilliseconds(20));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order),
- base::TimeDelta::FromMilliseconds(30));
-
- runners_[1]->UnregisterTaskQueue();
- test_task_runner_->RunUntilIdle();
-
- test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(40));
- ASSERT_THAT(run_order, ElementsAre(1, 3));
-}
-
-namespace {
-void UnregisterQueue(scoped_refptr<internal::TaskQueueImpl> queue) {
- queue->UnregisterTaskQueue();
-}
-}
-
-TEST_F(TaskQueueManagerTest, UnregisterTaskQueue_InTasks) {
- Initialize(3u);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&UnregisterQueue, runners_[1]));
- runners_[0]->PostTask(FROM_HERE, base::Bind(&UnregisterQueue, runners_[2]));
- runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
- runners_[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
-
- test_task_runner_->RunUntilIdle();
- ASSERT_THAT(run_order, ElementsAre(1));
-}
-
-void PostTestTasksFromNestedMessageLoop(
- base::MessageLoop* message_loop,
- scoped_refptr<base::SingleThreadTaskRunner> main_runner,
- scoped_refptr<base::SingleThreadTaskRunner> wake_up_runner,
- std::vector<EnqueueOrder>* run_order) {
- base::MessageLoop::ScopedNestableTaskAllower allow(message_loop);
- main_runner->PostNonNestableTask(FROM_HERE,
- base::Bind(&TestTask, 1, run_order));
- // The following should never get executed.
- wake_up_runner->PostTask(FROM_HERE, base::Bind(&TestTask, 2, run_order));
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(TaskQueueManagerTest, DeferredNonNestableTaskDoesNotTriggerWakeUp) {
- // This test checks that running (i.e., deferring) a non-nestable task in a
- // nested run loop does not trigger the pumping of an on-wakeup queue.
- InitializeWithRealMessageLoop(2u);
- runners_[1]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP);
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostTask(
- FROM_HERE,
- base::Bind(&PostTestTasksFromNestedMessageLoop, message_loop_.get(),
- runners_[0], runners_[1], base::Unretained(&run_order)));
-
- message_loop_->RunUntilIdle();
- ASSERT_THAT(run_order, ElementsAre(1));
-}
-
-namespace {
-
-class MockObserver : public TaskQueueManager::Observer {
- public:
- MOCK_METHOD1(OnUnregisterTaskQueue,
- void(const scoped_refptr<TaskQueue>& queue));
- MOCK_METHOD2(OnTriedToExecuteBlockedTask,
- void(const TaskQueue& queue, const base::PendingTask& task));
-};
-
-} // namespace
-
-TEST_F(TaskQueueManagerTest, OnUnregisterTaskQueue) {
- Initialize(0u);
-
- MockObserver observer;
- manager_->SetObserver(&observer);
-
- scoped_refptr<internal::TaskQueueImpl> task_queue =
- manager_->NewTaskQueue(TaskQueue::Spec("test_queue"));
-
- EXPECT_CALL(observer, OnUnregisterTaskQueue(_)).Times(1);
- task_queue->UnregisterTaskQueue();
-
- manager_->SetObserver(nullptr);
-}
-
-TEST_F(TaskQueueManagerTest, OnTriedToExecuteBlockedTask) {
- Initialize(0u);
-
- MockObserver observer;
- manager_->SetObserver(&observer);
-
- scoped_refptr<internal::TaskQueueImpl> task_queue = manager_->NewTaskQueue(
- TaskQueue::Spec("test_queue").SetShouldReportWhenExecutionBlocked(true));
- task_queue->SetQueueEnabled(false);
- task_queue->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- EXPECT_CALL(observer, OnTriedToExecuteBlockedTask(_, _)).Times(1);
- test_task_runner_->RunPendingTasks();
-
- manager_->SetObserver(nullptr);
-}
-
-TEST_F(TaskQueueManagerTest, ExecutedNonBlockedTask) {
- Initialize(0u);
-
- MockObserver observer;
- manager_->SetObserver(&observer);
-
- scoped_refptr<internal::TaskQueueImpl> task_queue = manager_->NewTaskQueue(
- TaskQueue::Spec("test_queue").SetShouldReportWhenExecutionBlocked(true));
- task_queue->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- EXPECT_CALL(observer, OnTriedToExecuteBlockedTask(_, _)).Times(0);
- test_task_runner_->RunPendingTasks();
-
- manager_->SetObserver(nullptr);
-}
-
-void HasOneRefTask(std::vector<bool>* log, internal::TaskQueueImpl* tq) {
- log->push_back(tq->HasOneRef());
-}
-
-TEST_F(TaskQueueManagerTest, UnregisterTaskQueueInNestedLoop) {
- InitializeWithRealMessageLoop(1u);
-
- // We retain a reference to the task queue even when the manager has deleted
- // its reference.
- scoped_refptr<internal::TaskQueueImpl> task_queue =
- manager_->NewTaskQueue(TaskQueue::Spec("test_queue"));
-
- std::vector<bool> log;
- std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop;
-
- // Inside a nested run loop, call task_queue->UnregisterTaskQueue, bookended
- // by calls to HasOneRefTask to make sure the manager doesn't release its
- // reference until the nested run loop exits.
- // NB: This first HasOneRefTask is a sanity check.
- tasks_to_post_from_nested_loop.push_back(
- std::make_pair(base::Bind(&HasOneRefTask, base::Unretained(&log),
- base::Unretained(task_queue.get())),
- true));
- tasks_to_post_from_nested_loop.push_back(std::make_pair(
- base::Bind(&internal::TaskQueueImpl::UnregisterTaskQueue,
- base::Unretained(task_queue.get())), true));
- tasks_to_post_from_nested_loop.push_back(
- std::make_pair(base::Bind(&HasOneRefTask, base::Unretained(&log),
- base::Unretained(task_queue.get())),
- true));
- runners_[0]->PostTask(
- FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(),
- base::RetainedRef(runners_[0]),
- base::Unretained(&tasks_to_post_from_nested_loop)));
- message_loop_->RunUntilIdle();
-
- // Add a final call to HasOneRefTask. This gives the manager a chance to
- // release its reference, and checks that it has.
- runners_[0]->PostTask(FROM_HERE,
- base::Bind(&HasOneRefTask, base::Unretained(&log),
- base::Unretained(task_queue.get())));
- message_loop_->RunUntilIdle();
-
- EXPECT_THAT(log, ElementsAre(false, false, true));
-}
-
-TEST_F(TaskQueueManagerTest, TimeDomainsAreIndependant) {
- Initialize(2u);
-
- base::TimeTicks start_time = manager_->delegate()->NowTicks();
- std::unique_ptr<VirtualTimeDomain> domain_a(
- new VirtualTimeDomain(nullptr, start_time));
- std::unique_ptr<VirtualTimeDomain> domain_b(
- new VirtualTimeDomain(nullptr, start_time));
- manager_->RegisterTimeDomain(domain_a.get());
- manager_->RegisterTimeDomain(domain_b.get());
- runners_[0]->SetTimeDomain(domain_a.get());
- runners_[1]->SetTimeDomain(domain_b.get());
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- base::TimeDelta::FromMilliseconds(10));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
- base::TimeDelta::FromMilliseconds(20));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order),
- base::TimeDelta::FromMilliseconds(30));
-
- runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order),
- base::TimeDelta::FromMilliseconds(10));
- runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 5, &run_order),
- base::TimeDelta::FromMilliseconds(20));
- runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 6, &run_order),
- base::TimeDelta::FromMilliseconds(30));
-
- domain_b->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50));
- manager_->MaybeScheduleImmediateWork(FROM_HERE);
-
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(4, 5, 6));
-
- domain_a->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50));
- manager_->MaybeScheduleImmediateWork(FROM_HERE);
-
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(4, 5, 6, 1, 2, 3));
-
- runners_[0]->UnregisterTaskQueue();
- runners_[1]->UnregisterTaskQueue();
-
- manager_->UnregisterTimeDomain(domain_a.get());
- manager_->UnregisterTimeDomain(domain_b.get());
-}
-
-TEST_F(TaskQueueManagerTest, TimeDomainMigration) {
- Initialize(1u);
-
- base::TimeTicks start_time = manager_->delegate()->NowTicks();
- std::unique_ptr<VirtualTimeDomain> domain_a(
- new VirtualTimeDomain(nullptr, start_time));
- manager_->RegisterTimeDomain(domain_a.get());
- runners_[0]->SetTimeDomain(domain_a.get());
-
- std::vector<EnqueueOrder> run_order;
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
- base::TimeDelta::FromMilliseconds(10));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order),
- base::TimeDelta::FromMilliseconds(20));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order),
- base::TimeDelta::FromMilliseconds(30));
- runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order),
- base::TimeDelta::FromMilliseconds(40));
-
- domain_a->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(20));
- manager_->MaybeScheduleImmediateWork(FROM_HERE);
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1, 2));
-
- std::unique_ptr<VirtualTimeDomain> domain_b(
- new VirtualTimeDomain(nullptr, start_time));
- manager_->RegisterTimeDomain(domain_b.get());
- runners_[0]->SetTimeDomain(domain_b.get());
-
- domain_b->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50));
- manager_->MaybeScheduleImmediateWork(FROM_HERE);
-
- test_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4));
-
- runners_[0]->UnregisterTaskQueue();
-
- manager_->UnregisterTimeDomain(domain_a.get());
- manager_->UnregisterTimeDomain(domain_b.get());
-}
-
-namespace {
-void ChromiumRunloopInspectionTask(
- scoped_refptr<cc::OrderedSimpleTaskRunner> test_task_runner) {
- EXPECT_EQ(1u, test_task_runner->NumPendingTasks());
-}
-} // namespace
-
-TEST_F(TaskQueueManagerTest, NumberOfPendingTasksOnChromiumRunLoop) {
- Initialize(1u);
-
- // NOTE because tasks posted to the chromiumrun loop are not cancellable, we
- // will end up with a lot more tasks posted if the delayed tasks were posted
- // in the reverse order.
- // TODO(alexclarke): Consider talking to the message pump directly.
- test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- for (int i = 1; i < 100; i++) {
- runners_[0]->PostDelayedTask(
- FROM_HERE,
- base::Bind(&ChromiumRunloopInspectionTask, test_task_runner_),
- base::TimeDelta::FromMilliseconds(i));
- }
- test_task_runner_->RunUntilIdle();
-}
-
-namespace {
-
-class QuadraticTask {
- public:
- QuadraticTask(scoped_refptr<internal::TaskQueueImpl> task_queue,
- base::TimeDelta delay,
- base::SimpleTestTickClock* now_src)
- : count_(0), task_queue_(task_queue), delay_(delay), now_src_(now_src) {}
-
- void SetShouldExit(base::Callback<bool()> should_exit) {
- should_exit_ = should_exit;
- }
-
- void Run() {
- if (should_exit_.Run())
- return;
- count_++;
- task_queue_->PostDelayedTask(
- FROM_HERE, base::Bind(&QuadraticTask::Run, base::Unretained(this)),
- delay_);
- task_queue_->PostDelayedTask(
- FROM_HERE, base::Bind(&QuadraticTask::Run, base::Unretained(this)),
- delay_);
- now_src_->Advance(base::TimeDelta::FromMilliseconds(5));
- }
-
- int count() const { return count_; }
-
- private:
- int count_;
- scoped_refptr<internal::TaskQueueImpl> task_queue_;
- base::TimeDelta delay_;
- base::Callback<bool()> should_exit_;
- base::SimpleTestTickClock* now_src_;
-};
-
-class LinearTask {
- public:
- LinearTask(scoped_refptr<internal::TaskQueueImpl> task_queue,
- base::TimeDelta delay,
- base::SimpleTestTickClock* now_src)
- : count_(0), task_queue_(task_queue), delay_(delay), now_src_(now_src) {}
-
- void SetShouldExit(base::Callback<bool()> should_exit) {
- should_exit_ = should_exit;
- }
-
- void Run() {
- if (should_exit_.Run())
- return;
- count_++;
- task_queue_->PostDelayedTask(
- FROM_HERE, base::Bind(&LinearTask::Run, base::Unretained(this)),
- delay_);
- now_src_->Advance(base::TimeDelta::FromMilliseconds(5));
- }
-
- int count() const { return count_; }
-
- private:
- int count_;
- scoped_refptr<internal::TaskQueueImpl> task_queue_;
- base::TimeDelta delay_;
- base::Callback<bool()> should_exit_;
- base::SimpleTestTickClock* now_src_;
-};
-
-bool ShouldExit(QuadraticTask* quadratic_task, LinearTask* linear_task) {
- return quadratic_task->count() == 1000 || linear_task->count() == 1000;
-}
-
-} // namespace
-
-TEST_F(TaskQueueManagerTest,
- DelayedTasksDontBadlyStarveNonDelayedWork_SameQueue) {
- Initialize(1u);
-
- QuadraticTask quadratic_delayed_task(
- runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get());
- LinearTask linear_immediate_task(runners_[0], base::TimeDelta(),
- now_src_.get());
- base::Callback<bool()> should_exit =
- base::Bind(ShouldExit, &quadratic_delayed_task, &linear_immediate_task);
- quadratic_delayed_task.SetShouldExit(should_exit);
- linear_immediate_task.SetShouldExit(should_exit);
-
- quadratic_delayed_task.Run();
- linear_immediate_task.Run();
-
- test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- test_task_runner_->RunUntilIdle();
-
- double ratio = static_cast<double>(linear_immediate_task.count()) /
- static_cast<double>(quadratic_delayed_task.count());
-
- EXPECT_GT(ratio, 0.333);
- EXPECT_LT(ratio, 1.1);
-}
-
-TEST_F(TaskQueueManagerTest, ImmediateWorkCanStarveDelayedTasks_SameQueue) {
- Initialize(1u);
-
- QuadraticTask quadratic_immediate_task(runners_[0], base::TimeDelta(),
- now_src_.get());
- LinearTask linear_delayed_task(
- runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get());
- base::Callback<bool()> should_exit =
- base::Bind(&ShouldExit, &quadratic_immediate_task, &linear_delayed_task);
-
- quadratic_immediate_task.SetShouldExit(should_exit);
- linear_delayed_task.SetShouldExit(should_exit);
-
- quadratic_immediate_task.Run();
- linear_delayed_task.Run();
-
- test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- test_task_runner_->RunUntilIdle();
-
- double ratio = static_cast<double>(linear_delayed_task.count()) /
- static_cast<double>(quadratic_immediate_task.count());
-
- // This is by design, we want to enforce a strict ordering in task execution
- // where by delayed tasks can not skip ahead of non-delayed work.
- EXPECT_GT(ratio, 0.0);
- EXPECT_LT(ratio, 0.1);
-}
-
-TEST_F(TaskQueueManagerTest,
- DelayedTasksDontBadlyStarveNonDelayedWork_DifferentQueue) {
- Initialize(2u);
-
- QuadraticTask quadratic_delayed_task(
- runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get());
- LinearTask linear_immediate_task(runners_[1], base::TimeDelta(),
- now_src_.get());
- base::Callback<bool()> should_exit =
- base::Bind(ShouldExit, &quadratic_delayed_task, &linear_immediate_task);
- quadratic_delayed_task.SetShouldExit(should_exit);
- linear_immediate_task.SetShouldExit(should_exit);
-
- quadratic_delayed_task.Run();
- linear_immediate_task.Run();
-
- test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- test_task_runner_->RunUntilIdle();
-
- double ratio = static_cast<double>(linear_immediate_task.count()) /
- static_cast<double>(quadratic_delayed_task.count());
-
- EXPECT_GT(ratio, 0.333);
- EXPECT_LT(ratio, 1.1);
-}
-
-TEST_F(TaskQueueManagerTest,
- ImmediateWorkCanStarveDelayedTasks_DifferentQueue) {
- Initialize(2u);
-
- QuadraticTask quadratic_immediate_task(runners_[0], base::TimeDelta(),
- now_src_.get());
- LinearTask linear_delayed_task(
- runners_[1], base::TimeDelta::FromMilliseconds(10), now_src_.get());
- base::Callback<bool()> should_exit =
- base::Bind(&ShouldExit, &quadratic_immediate_task, &linear_delayed_task);
-
- quadratic_immediate_task.SetShouldExit(should_exit);
- linear_delayed_task.SetShouldExit(should_exit);
-
- quadratic_immediate_task.Run();
- linear_delayed_task.Run();
-
- test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- test_task_runner_->RunUntilIdle();
-
- double ratio = static_cast<double>(linear_delayed_task.count()) /
- static_cast<double>(quadratic_immediate_task.count());
-
- // This is by design, we want to enforce a strict ordering in task execution
- // where by delayed tasks can not skip ahead of non-delayed work.
- EXPECT_GT(ratio, 0.0);
- EXPECT_LT(ratio, 0.1);
-}
-
-TEST_F(TaskQueueManagerTest, CurrentlyExecutingTaskQueue_NoTaskRunning) {
- Initialize(1u);
-
- EXPECT_EQ(nullptr, manager_->currently_executing_task_queue());
-}
-
-namespace {
-void CurrentlyExecutingTaskQueueTestTask(TaskQueueManager* task_queue_manager,
- std::vector<TaskQueue*>* task_sources) {
- task_sources->push_back(task_queue_manager->currently_executing_task_queue());
-}
-}
-
-TEST_F(TaskQueueManagerTest, CurrentlyExecutingTaskQueue_TaskRunning) {
- Initialize(2u);
-
- internal::TaskQueueImpl* queue0 = runners_[0].get();
- internal::TaskQueueImpl* queue1 = runners_[1].get();
-
- std::vector<TaskQueue*> task_sources;
- queue0->PostTask(FROM_HERE, base::Bind(&CurrentlyExecutingTaskQueueTestTask,
- manager_.get(), &task_sources));
- queue1->PostTask(FROM_HERE, base::Bind(&CurrentlyExecutingTaskQueueTestTask,
- manager_.get(), &task_sources));
- test_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(task_sources, ElementsAre(queue0, queue1));
- EXPECT_EQ(nullptr, manager_->currently_executing_task_queue());
-}
-
-namespace {
-void RunloopCurrentlyExecutingTaskQueueTestTask(
- base::MessageLoop* message_loop,
- TaskQueueManager* task_queue_manager,
- std::vector<TaskQueue*>* task_sources,
- std::vector<std::pair<base::Closure, TaskQueue*>>* tasks) {
- base::MessageLoop::ScopedNestableTaskAllower allow(message_loop);
- task_sources->push_back(task_queue_manager->currently_executing_task_queue());
-
- for (std::pair<base::Closure, TaskQueue*>& pair : *tasks) {
- pair.second->PostTask(FROM_HERE, pair.first);
- }
-
- base::RunLoop().RunUntilIdle();
- task_sources->push_back(task_queue_manager->currently_executing_task_queue());
-}
-}
-
-TEST_F(TaskQueueManagerTest, CurrentlyExecutingTaskQueue_NestedLoop) {
- InitializeWithRealMessageLoop(3u);
-
- TaskQueue* queue0 = runners_[0].get();
- TaskQueue* queue1 = runners_[1].get();
- TaskQueue* queue2 = runners_[2].get();
-
- std::vector<TaskQueue*> task_sources;
- std::vector<std::pair<base::Closure, TaskQueue*>>
- tasks_to_post_from_nested_loop;
- tasks_to_post_from_nested_loop.push_back(
- std::make_pair(base::Bind(&CurrentlyExecutingTaskQueueTestTask,
- manager_.get(), &task_sources),
- queue1));
- tasks_to_post_from_nested_loop.push_back(
- std::make_pair(base::Bind(&CurrentlyExecutingTaskQueueTestTask,
- manager_.get(), &task_sources),
- queue2));
-
- queue0->PostTask(
- FROM_HERE, base::Bind(&RunloopCurrentlyExecutingTaskQueueTestTask,
- message_loop_.get(), manager_.get(), &task_sources,
- &tasks_to_post_from_nested_loop));
-
- message_loop_->RunUntilIdle();
- EXPECT_THAT(task_sources, ElementsAre(queue0, queue1, queue2, queue0));
- EXPECT_EQ(nullptr, manager_->currently_executing_task_queue());
-}
-
-void OnTraceDataCollected(base::Closure quit_closure,
- base::trace_event::TraceResultBuffer* buffer,
- const scoped_refptr<base::RefCountedString>& json,
- bool has_more_events) {
- buffer->AddFragment(json->data());
- if (!has_more_events)
- quit_closure.Run();
-}
-
-class TaskQueueManagerTestWithTracing : public TaskQueueManagerTest {
- public:
- void StartTracing();
- void StopTracing();
- std::unique_ptr<trace_analyzer::TraceAnalyzer> CreateTraceAnalyzer();
-};
-
-void TaskQueueManagerTestWithTracing::StartTracing() {
- base::trace_event::TraceLog::GetInstance()->SetEnabled(
- base::trace_event::TraceConfig("*"),
- base::trace_event::TraceLog::RECORDING_MODE);
-}
-
-void TaskQueueManagerTestWithTracing::StopTracing() {
- base::trace_event::TraceLog::GetInstance()->SetDisabled();
-}
-
-std::unique_ptr<trace_analyzer::TraceAnalyzer>
-TaskQueueManagerTestWithTracing::CreateTraceAnalyzer() {
- base::trace_event::TraceResultBuffer buffer;
- base::trace_event::TraceResultBuffer::SimpleOutput trace_output;
- buffer.SetOutputCallback(trace_output.GetCallback());
- base::RunLoop run_loop;
- buffer.Start();
- base::trace_event::TraceLog::GetInstance()->Flush(
- Bind(&OnTraceDataCollected, run_loop.QuitClosure(),
- base::Unretained(&buffer)));
- run_loop.Run();
- buffer.Finish();
-
- return base::WrapUnique(
- trace_analyzer::TraceAnalyzer::Create(trace_output.json_output));
-}
-
-TEST_F(TaskQueueManagerTestWithTracing, BlameContextAttribution) {
- using trace_analyzer::Query;
-
- InitializeWithRealMessageLoop(1u);
- TaskQueue* queue = runners_[0].get();
-
- StartTracing();
- {
- base::trace_event::BlameContext blame_context("cat", "name", "type",
- "scope", 0, nullptr);
- blame_context.Initialize();
- queue->SetBlameContext(&blame_context);
- queue->PostTask(FROM_HERE, base::Bind(&NopTask));
- message_loop_->RunUntilIdle();
- }
- StopTracing();
- std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer =
- CreateTraceAnalyzer();
-
- trace_analyzer::TraceEventVector events;
- Query q = Query::EventPhaseIs(TRACE_EVENT_PHASE_ENTER_CONTEXT) ||
- Query::EventPhaseIs(TRACE_EVENT_PHASE_LEAVE_CONTEXT);
- analyzer->FindEvents(q, &events);
-
- EXPECT_EQ(2u, events.size());
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/task_queue_selector.cc b/chromium/components/scheduler/base/task_queue_selector.cc
deleted file mode 100644
index 9db8ab9c2de..00000000000
--- a/chromium/components/scheduler/base/task_queue_selector.cc
+++ /dev/null
@@ -1,380 +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 "components/scheduler/base/task_queue_selector.h"
-
-#include "base/logging.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/work_queue.h"
-
-namespace scheduler {
-namespace internal {
-
-TaskQueueSelector::TaskQueueSelector()
- : enabled_selector_(this, "enabled"),
- blocked_selector_(this, "blocked"),
- immediate_starvation_count_(0),
- high_priority_starvation_count_(0),
- num_blocked_queues_to_report_(0),
- task_queue_selector_observer_(nullptr) {}
-
-TaskQueueSelector::~TaskQueueSelector() {}
-
-void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- DCHECK(queue->IsQueueEnabled());
- enabled_selector_.AddQueue(queue, TaskQueue::NORMAL_PRIORITY);
-}
-
-void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl* queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- if (queue->IsQueueEnabled()) {
- enabled_selector_.RemoveQueue(queue);
-// The #if DCHECK_IS_ON() shouldn't be necessary but this doesn't compile on
-// chromeos bots without it :(
-#if DCHECK_IS_ON()
- DCHECK(!blocked_selector_.CheckContainsQueueForTest(queue));
-#endif
- } else if (queue->should_report_when_execution_blocked()) {
- DCHECK_GT(num_blocked_queues_to_report_, 0u);
- num_blocked_queues_to_report_--;
- blocked_selector_.RemoveQueue(queue);
-#if DCHECK_IS_ON()
- DCHECK(!enabled_selector_.CheckContainsQueueForTest(queue));
-#endif
- }
-}
-
-void TaskQueueSelector::EnableQueue(internal::TaskQueueImpl* queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- DCHECK(queue->IsQueueEnabled());
- if (queue->should_report_when_execution_blocked()) {
- DCHECK_GT(num_blocked_queues_to_report_, 0u);
- num_blocked_queues_to_report_--;
- blocked_selector_.RemoveQueue(queue);
- }
- enabled_selector_.AddQueue(queue, queue->GetQueuePriority());
- if (task_queue_selector_observer_)
- task_queue_selector_observer_->OnTaskQueueEnabled(queue);
-}
-
-void TaskQueueSelector::DisableQueue(internal::TaskQueueImpl* queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- DCHECK(!queue->IsQueueEnabled());
- enabled_selector_.RemoveQueue(queue);
- if (queue->should_report_when_execution_blocked()) {
- blocked_selector_.AddQueue(queue, queue->GetQueuePriority());
- num_blocked_queues_to_report_++;
- }
-}
-
-void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl* queue,
- TaskQueue::QueuePriority priority) {
- DCHECK_LT(priority, TaskQueue::QUEUE_PRIORITY_COUNT);
- DCHECK(main_thread_checker_.CalledOnValidThread());
- if (queue->IsQueueEnabled()) {
- enabled_selector_.ChangeSetIndex(queue, priority);
- } else if (queue->should_report_when_execution_blocked()) {
- blocked_selector_.ChangeSetIndex(queue, priority);
- } else {
- // Normally blocked_selector_.ChangeSetIndex would assign the queue's
- // priority, however if |queue->should_report_when_execution_blocked()| is
- // false then the disabled queue is not in any set so we need to do it here.
- queue->delayed_work_queue()->AssignSetIndex(priority);
- queue->immediate_work_queue()->AssignSetIndex(priority);
- }
- DCHECK_EQ(priority, queue->GetQueuePriority());
-}
-
-TaskQueue::QueuePriority TaskQueueSelector::NextPriority(
- TaskQueue::QueuePriority priority) {
- DCHECK(priority < TaskQueue::QUEUE_PRIORITY_COUNT);
- return static_cast<TaskQueue::QueuePriority>(static_cast<int>(priority) + 1);
-}
-
-TaskQueueSelector::PrioritizingSelector::PrioritizingSelector(
- TaskQueueSelector* task_queue_selector,
- const char* name)
- : task_queue_selector_(task_queue_selector),
- delayed_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT, name),
- immediate_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT, name) {}
-
-void TaskQueueSelector::PrioritizingSelector::AddQueue(
- internal::TaskQueueImpl* queue,
- TaskQueue::QueuePriority priority) {
-#if DCHECK_IS_ON()
- DCHECK(!CheckContainsQueueForTest(queue));
-#endif
- delayed_work_queue_sets_.AddQueue(queue->delayed_work_queue(), priority);
- immediate_work_queue_sets_.AddQueue(queue->immediate_work_queue(), priority);
-#if DCHECK_IS_ON()
- DCHECK(CheckContainsQueueForTest(queue));
-#endif
-}
-
-void TaskQueueSelector::PrioritizingSelector::ChangeSetIndex(
- internal::TaskQueueImpl* queue,
- TaskQueue::QueuePriority priority) {
-#if DCHECK_IS_ON()
- DCHECK(CheckContainsQueueForTest(queue));
-#endif
- delayed_work_queue_sets_.ChangeSetIndex(queue->delayed_work_queue(),
- priority);
- immediate_work_queue_sets_.ChangeSetIndex(queue->immediate_work_queue(),
- priority);
-#if DCHECK_IS_ON()
- DCHECK(CheckContainsQueueForTest(queue));
-#endif
-}
-
-void TaskQueueSelector::PrioritizingSelector::RemoveQueue(
- internal::TaskQueueImpl* queue) {
-#if DCHECK_IS_ON()
- DCHECK(CheckContainsQueueForTest(queue));
-#endif
- delayed_work_queue_sets_.RemoveQueue(queue->delayed_work_queue());
- immediate_work_queue_sets_.RemoveQueue(queue->immediate_work_queue());
-
-#if DCHECK_IS_ON()
- DCHECK(!CheckContainsQueueForTest(queue));
-#endif
-}
-
-bool TaskQueueSelector::PrioritizingSelector::
- ChooseOldestImmediateTaskWithPriority(TaskQueue::QueuePriority priority,
- WorkQueue** out_work_queue) const {
- return immediate_work_queue_sets_.GetOldestQueueInSet(priority,
- out_work_queue);
-}
-
-bool TaskQueueSelector::PrioritizingSelector::
- ChooseOldestDelayedTaskWithPriority(TaskQueue::QueuePriority priority,
- WorkQueue** out_work_queue) const {
- return delayed_work_queue_sets_.GetOldestQueueInSet(priority, out_work_queue);
-}
-
-bool TaskQueueSelector::PrioritizingSelector::
- ChooseOldestImmediateOrDelayedTaskWithPriority(
- TaskQueue::QueuePriority priority,
- bool* out_chose_delayed_over_immediate,
- WorkQueue** out_work_queue) const {
- WorkQueue* immediate_queue;
- DCHECK_EQ(*out_chose_delayed_over_immediate, false);
- if (immediate_work_queue_sets_.GetOldestQueueInSet(priority,
- &immediate_queue)) {
- WorkQueue* delayed_queue;
- if (delayed_work_queue_sets_.GetOldestQueueInSet(priority,
- &delayed_queue)) {
- if (immediate_queue->ShouldRunBefore(delayed_queue)) {
- *out_work_queue = immediate_queue;
- } else {
- *out_chose_delayed_over_immediate = true;
- *out_work_queue = delayed_queue;
- }
- } else {
- *out_work_queue = immediate_queue;
- }
- return true;
- }
- return delayed_work_queue_sets_.GetOldestQueueInSet(priority, out_work_queue);
-}
-
-bool TaskQueueSelector::PrioritizingSelector::ChooseOldestWithPriority(
- TaskQueue::QueuePriority priority,
- bool* out_chose_delayed_over_immediate,
- WorkQueue** out_work_queue) const {
- // Select an immediate work queue if we are starving immediate tasks.
- if (task_queue_selector_->immediate_starvation_count_ >=
- kMaxDelayedStarvationTasks) {
- if (ChooseOldestImmediateTaskWithPriority(priority, out_work_queue)) {
- return true;
- }
- if (ChooseOldestDelayedTaskWithPriority(priority, out_work_queue)) {
- return true;
- }
- return false;
- }
- return ChooseOldestImmediateOrDelayedTaskWithPriority(
- priority, out_chose_delayed_over_immediate, out_work_queue);
-}
-
-bool TaskQueueSelector::PrioritizingSelector::SelectWorkQueueToService(
- TaskQueue::QueuePriority max_priority,
- WorkQueue** out_work_queue,
- bool* out_chose_delayed_over_immediate) {
- DCHECK(task_queue_selector_->main_thread_checker_.CalledOnValidThread());
- DCHECK_EQ(*out_chose_delayed_over_immediate, false);
-
- // Always service the control queue if it has any work.
- if (max_priority > TaskQueue::CONTROL_PRIORITY &&
- ChooseOldestWithPriority(TaskQueue::CONTROL_PRIORITY,
- out_chose_delayed_over_immediate,
- out_work_queue)) {
- return true;
- }
-
- // Select from the normal priority queue if we are starving it.
- if (max_priority > TaskQueue::NORMAL_PRIORITY &&
- task_queue_selector_->high_priority_starvation_count_ >=
- kMaxHighPriorityStarvationTasks &&
- ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY,
- out_chose_delayed_over_immediate,
- out_work_queue)) {
- return true;
- }
- // Otherwise choose in priority order.
- for (TaskQueue::QueuePriority priority = TaskQueue::HIGH_PRIORITY;
- priority < max_priority; priority = NextPriority(priority)) {
- if (ChooseOldestWithPriority(priority, out_chose_delayed_over_immediate,
- out_work_queue)) {
- return true;
- }
- }
- return false;
-}
-
-#if DCHECK_IS_ON() || !defined(NDEBUG)
-bool
-TaskQueueSelector::PrioritizingSelector::CheckContainsQueueForTest(
- const internal::TaskQueueImpl* queue) const {
- bool contains_delayed_work_queue =
- delayed_work_queue_sets_.ContainsWorkQueueForTest(
- queue->delayed_work_queue());
-
- bool contains_immediate_work_queue =
- immediate_work_queue_sets_.ContainsWorkQueueForTest(
- queue->immediate_work_queue());
-
- DCHECK_EQ(contains_delayed_work_queue, contains_immediate_work_queue);
- return contains_delayed_work_queue;
-}
-#endif
-
-bool TaskQueueSelector::SelectWorkQueueToService(WorkQueue** out_work_queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- bool chose_delayed_over_immediate = false;
- bool found_queue = enabled_selector_.SelectWorkQueueToService(
- TaskQueue::QUEUE_PRIORITY_COUNT, out_work_queue,
- &chose_delayed_over_immediate);
- if (!found_queue) {
- TrySelectingBlockedQueue();
- return false;
- }
-
- TrySelectingBlockedQueueOverEnabledQueue(**out_work_queue);
- DidSelectQueueWithPriority(
- (*out_work_queue)->task_queue()->GetQueuePriority(),
- chose_delayed_over_immediate);
- return true;
-}
-
-void TaskQueueSelector::TrySelectingBlockedQueue() {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_)
- return;
- WorkQueue* chosen_blocked_queue;
- bool chose_delayed_over_immediate = false;
- // There was nothing unblocked to run, see if we could have run a blocked
- // task.
- if (blocked_selector_.SelectWorkQueueToService(
- TaskQueue::QUEUE_PRIORITY_COUNT, &chosen_blocked_queue,
- &chose_delayed_over_immediate)) {
- task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue(
- chosen_blocked_queue);
- }
-}
-
-void TaskQueueSelector::TrySelectingBlockedQueueOverEnabledQueue(
- const WorkQueue& chosen_enabled_queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_)
- return;
-
- TaskQueue::QueuePriority max_priority =
- NextPriority(chosen_enabled_queue.task_queue()->GetQueuePriority());
-
- WorkQueue* chosen_blocked_queue;
- bool chose_delayed_over_immediate = false;
- bool found_queue = blocked_selector_.SelectWorkQueueToService(
- max_priority, &chosen_blocked_queue, &chose_delayed_over_immediate);
- if (!found_queue)
- return;
-
- // Check if the chosen blocked queue has a lower numerical priority than the
- // chosen enabled queue. If so we would have chosen the blocked queue (since
- // zero is the highest priority).
- if (chosen_blocked_queue->task_queue()->GetQueuePriority() <
- chosen_enabled_queue.task_queue()->GetQueuePriority()) {
- task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue(
- chosen_blocked_queue);
- return;
- }
- DCHECK_EQ(chosen_blocked_queue->task_queue()->GetQueuePriority(),
- chosen_enabled_queue.task_queue()->GetQueuePriority());
- // Otherwise there was an enabled and a blocked task with the same priority.
- // The one with the older enqueue order wins.
- if (chosen_blocked_queue->ShouldRunBefore(&chosen_enabled_queue)) {
- task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue(
- chosen_blocked_queue);
- }
-}
-
-void TaskQueueSelector::DidSelectQueueWithPriority(
- TaskQueue::QueuePriority priority,
- bool chose_delayed_over_immediate) {
- switch (priority) {
- case TaskQueue::CONTROL_PRIORITY:
- break;
- case TaskQueue::HIGH_PRIORITY:
- high_priority_starvation_count_++;
- break;
- case TaskQueue::NORMAL_PRIORITY:
- case TaskQueue::BEST_EFFORT_PRIORITY:
- high_priority_starvation_count_ = 0;
- break;
- default:
- NOTREACHED();
- }
- if (chose_delayed_over_immediate) {
- immediate_starvation_count_++;
- } else {
- immediate_starvation_count_ = 0;
- }
-}
-
-void TaskQueueSelector::AsValueInto(
- base::trace_event::TracedValue* state) const {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- state->SetInteger("high_priority_starvation_count",
- high_priority_starvation_count_);
- state->SetInteger("immediate_starvation_count", immediate_starvation_count_);
- state->SetInteger("num_blocked_queues_to_report",
- num_blocked_queues_to_report_);
-}
-
-void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer* observer) {
- task_queue_selector_observer_ = observer;
-}
-
-bool TaskQueueSelector::EnabledWorkQueuesEmpty() const {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- for (TaskQueue::QueuePriority priority = TaskQueue::CONTROL_PRIORITY;
- priority < TaskQueue::QUEUE_PRIORITY_COUNT;
- priority = NextPriority(priority)) {
- if (!enabled_selector_.delayed_work_queue_sets()->IsSetEmpty(priority) ||
- !enabled_selector_.immediate_work_queue_sets()->IsSetEmpty(priority)) {
- return false;
- }
- }
- return true;
-}
-
-void TaskQueueSelector::SetImmediateStarvationCountForTest(
- size_t immediate_starvation_count) {
- immediate_starvation_count_ = immediate_starvation_count;
-}
-
-} // namespace internal
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/task_queue_selector.h b/chromium/components/scheduler/base/task_queue_selector.h
deleted file mode 100644
index 4a82adcfbd3..00000000000
--- a/chromium/components/scheduler/base/task_queue_selector.h
+++ /dev/null
@@ -1,206 +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 COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H_
-#define COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H_
-
-#include <stddef.h>
-
-#include <set>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/pending_task.h"
-#include "base/threading/thread_checker.h"
-#include "components/scheduler/base/work_queue_sets.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-namespace internal {
-
-// TaskQueueSelector is used by the SchedulerHelper to enable prioritization
-// of particular task queues.
-class SCHEDULER_EXPORT TaskQueueSelector {
- public:
- TaskQueueSelector();
- ~TaskQueueSelector();
-
- // Called to register a queue that can be selected. This function is called
- // on the main thread.
- void AddQueue(internal::TaskQueueImpl* queue);
-
- // The specified work will no longer be considered for selection. This
- // function is called on the main thread.
- void RemoveQueue(internal::TaskQueueImpl* queue);
-
- // Make |queue| eligible for selection. This function is called on the main
- // thread. Must only be called if |queue| is disabled.
- void EnableQueue(internal::TaskQueueImpl* queue);
-
- // Disable selection from |queue|. If task blocking is enabled for the queue,
- // Observer::OnTriedToSelectBlockedWorkQueue will be emitted if the
- // SelectWorkQueueToService tries to select this disabled queue for execution.
- // Must only be called if |queue| is enabled.
- void DisableQueue(internal::TaskQueueImpl* queue);
-
- // Called get or set the priority of |queue|.
- void SetQueuePriority(internal::TaskQueueImpl* queue,
- TaskQueue::QueuePriority priority);
-
- // Called to choose the work queue from which the next task should be taken
- // and run. Return true if |out_work_queue| indicates the queue to service or
- // false to avoid running any task.
- //
- // This function is called on the main thread.
- bool SelectWorkQueueToService(WorkQueue** out_work_queue);
-
- // Serialize the selector state for tracing.
- void AsValueInto(base::trace_event::TracedValue* state) const;
-
- class SCHEDULER_EXPORT Observer {
- public:
- virtual ~Observer() {}
-
- // Called when |queue| transitions from disabled to enabled.
- virtual void OnTaskQueueEnabled(internal::TaskQueueImpl* queue) = 0;
-
- // Called when the selector tried to select a task from a disabled work
- // queue. See TaskQueue::Spec::SetShouldReportWhenExecutionBlocked. A single
- // call to SelectWorkQueueToService will only result in up to one
- // blocking notification even if multiple disabled queues could have been
- // selected.
- virtual void OnTriedToSelectBlockedWorkQueue(
- internal::WorkQueue* work_queue) = 0;
- };
-
- // Called once to set the Observer. This function is called
- // on the main thread. If |observer| is null, then no callbacks will occur.
- void SetTaskQueueSelectorObserver(Observer* observer);
-
- // Returns true if all the enabled work queues are empty. Returns false
- // otherwise.
- bool EnabledWorkQueuesEmpty() const;
-
- protected:
- class SCHEDULER_EXPORT PrioritizingSelector {
- public:
- PrioritizingSelector(TaskQueueSelector* task_queue_selector,
- const char* name);
-
- void ChangeSetIndex(internal::TaskQueueImpl* queue,
- TaskQueue::QueuePriority priority);
- void AddQueue(internal::TaskQueueImpl* queue,
- TaskQueue::QueuePriority priority);
- void RemoveQueue(internal::TaskQueueImpl* queue);
-
- bool SelectWorkQueueToService(TaskQueue::QueuePriority max_priority,
- WorkQueue** out_work_queue,
- bool* out_chose_delayed_over_immediate);
-
- WorkQueueSets* delayed_work_queue_sets() {
- return &delayed_work_queue_sets_;
- }
- WorkQueueSets* immediate_work_queue_sets() {
- return &immediate_work_queue_sets_;
- }
-
- const WorkQueueSets* delayed_work_queue_sets() const {
- return &delayed_work_queue_sets_;
- }
- const WorkQueueSets* immediate_work_queue_sets() const {
- return &immediate_work_queue_sets_;
- }
-
- bool ChooseOldestWithPriority(TaskQueue::QueuePriority priority,
- bool* out_chose_delayed_over_immediate,
- WorkQueue** out_work_queue) const;
-
-#if DCHECK_IS_ON() || !defined(NDEBUG)
- bool CheckContainsQueueForTest(const internal::TaskQueueImpl* queue) const;
-#endif
-
- private:
- bool ChooseOldestImmediateTaskWithPriority(
- TaskQueue::QueuePriority priority,
- WorkQueue** out_work_queue) const;
-
- bool ChooseOldestDelayedTaskWithPriority(TaskQueue::QueuePriority priority,
- WorkQueue** out_work_queue) const;
-
- // Return true if |out_queue| contains the queue with the oldest pending
- // task from the set of queues of |priority|, or false if all queues of that
- // priority are empty. In addition |out_chose_delayed_over_immediate| is set
- // to true iff we chose a delayed work queue in favour of an immediate work
- // queue.
- bool ChooseOldestImmediateOrDelayedTaskWithPriority(
- TaskQueue::QueuePriority priority,
- bool* out_chose_delayed_over_immediate,
- WorkQueue** out_work_queue) const;
-
- const TaskQueueSelector* task_queue_selector_;
- WorkQueueSets delayed_work_queue_sets_;
- WorkQueueSets immediate_work_queue_sets_;
-
- DISALLOW_COPY_AND_ASSIGN(PrioritizingSelector);
- };
-
- // Return true if |out_queue| contains the queue with the oldest pending task
- // from the set of queues of |priority|, or false if all queues of that
- // priority are empty. In addition |out_chose_delayed_over_immediate| is set
- // to true iff we chose a delayed work queue in favour of an immediate work
- // queue. This method will force select an immediate task if those are being
- // starved by delayed tasks.
- void SetImmediateStarvationCountForTest(size_t immediate_starvation_count);
-
- PrioritizingSelector* enabled_selector_for_test() {
- return &enabled_selector_;
- }
-
- private:
- // Returns the priority which is next after |priority|.
- static TaskQueue::QueuePriority NextPriority(
- TaskQueue::QueuePriority priority);
-
- bool SelectWorkQueueToServiceInternal(WorkQueue** out_work_queue);
-
- // Called whenever the selector chooses a task queue for execution with the
- // priority |priority|.
- void DidSelectQueueWithPriority(TaskQueue::QueuePriority priority,
- bool chose_delayed_over_immediate);
-
- // No enabled queue could be selected, check if we could have chosen a
- // disabled (blocked) work queue instead.
- void TrySelectingBlockedQueue();
-
- // Check if we could have chosen a disabled (blocked) work queue instead.
- // |chosen_enabled_queue| is the enabled queue that got chosen.
- void TrySelectingBlockedQueueOverEnabledQueue(
- const WorkQueue& chosen_enabled_queue);
-
- // Number of high priority tasks which can be run before a normal priority
- // task should be selected to prevent starvation.
- // TODO(rmcilroy): Check if this is a good value.
- static const size_t kMaxHighPriorityStarvationTasks = 5;
-
- // Maximum number of delayed tasks tasks which can be run while there's a
- // waiting non-delayed task.
- static const size_t kMaxDelayedStarvationTasks = 3;
-
- private:
- base::ThreadChecker main_thread_checker_;
-
- PrioritizingSelector enabled_selector_;
- PrioritizingSelector blocked_selector_;
- size_t immediate_starvation_count_;
- size_t high_priority_starvation_count_;
- size_t num_blocked_queues_to_report_;
-
- Observer* task_queue_selector_observer_; // NOT OWNED
- DISALLOW_COPY_AND_ASSIGN(TaskQueueSelector);
-};
-
-} // namespace internal
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H
diff --git a/chromium/components/scheduler/base/task_queue_selector_unittest.cc b/chromium/components/scheduler/base/task_queue_selector_unittest.cc
deleted file mode 100644
index 1be477d75f7..00000000000
--- a/chromium/components/scheduler/base/task_queue_selector_unittest.cc
+++ /dev/null
@@ -1,494 +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 "components/scheduler/base/task_queue_selector.h"
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/pending_task.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/virtual_time_domain.h"
-#include "components/scheduler/base/work_queue.h"
-#include "components/scheduler/base/work_queue_sets.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-
-namespace scheduler {
-namespace internal {
-
-class MockObserver : public TaskQueueSelector::Observer {
- public:
- MockObserver() {}
- virtual ~MockObserver() {}
-
- MOCK_METHOD1(OnTaskQueueEnabled, void(internal::TaskQueueImpl*));
- MOCK_METHOD1(OnTriedToSelectBlockedWorkQueue, void(internal::WorkQueue*));
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockObserver);
-};
-
-class TaskQueueSelectorForTest : public TaskQueueSelector {
- public:
- using TaskQueueSelector::SetImmediateStarvationCountForTest;
- using TaskQueueSelector::PrioritizingSelector;
- using TaskQueueSelector::enabled_selector_for_test;
-};
-
-class TaskQueueSelectorTest : public testing::Test {
- public:
- TaskQueueSelectorTest()
- : test_closure_(base::Bind(&TaskQueueSelectorTest::TestFunction)) {}
- ~TaskQueueSelectorTest() override {}
-
- TaskQueueSelectorForTest::PrioritizingSelector* enabled_selector() {
- return selector_.enabled_selector_for_test();
- }
-
- WorkQueueSets* delayed_work_queue_sets() {
- return enabled_selector()->delayed_work_queue_sets();
- }
- WorkQueueSets* immediate_work_queue_sets() {
- return enabled_selector()->immediate_work_queue_sets();
- }
-
- void PushTasks(const size_t queue_indices[], size_t num_tasks) {
- std::set<size_t> changed_queue_set;
- for (size_t i = 0; i < num_tasks; i++) {
- changed_queue_set.insert(queue_indices[i]);
- task_queues_[queue_indices[i]]->immediate_work_queue()->Push(
- TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0,
- true, i));
- }
- }
-
- void PushTasksWithEnqueueOrder(const size_t queue_indices[],
- const size_t enqueue_orders[],
- size_t num_tasks) {
- std::set<size_t> changed_queue_set;
- for (size_t i = 0; i < num_tasks; i++) {
- changed_queue_set.insert(queue_indices[i]);
- task_queues_[queue_indices[i]]->immediate_work_queue()->Push(
- TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0,
- true, enqueue_orders[i]));
- }
- }
-
- std::vector<size_t> PopTasks() {
- std::vector<size_t> order;
- WorkQueue* chosen_work_queue;
- while (selector_.SelectWorkQueueToService(&chosen_work_queue)) {
- size_t chosen_queue_index =
- queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
- order.push_back(chosen_queue_index);
- chosen_work_queue->PopTaskForTest();
- immediate_work_queue_sets()->OnPopQueue(chosen_work_queue);
- }
- return order;
- }
-
- static void TestFunction() {}
-
- void EnableQueue(TaskQueueImpl* queue) {
- queue->SetQueueEnabled(true);
- selector_.EnableQueue(queue);
- }
-
- void DisableQueue(TaskQueueImpl* queue) {
- queue->SetQueueEnabled(false);
- selector_.DisableQueue(queue);
- }
-
- protected:
- void SetUp() final {
- virtual_time_domain_ = base::WrapUnique<VirtualTimeDomain>(
- new VirtualTimeDomain(nullptr, base::TimeTicks()));
- for (size_t i = 0; i < kTaskQueueCount; i++) {
- scoped_refptr<TaskQueueImpl> task_queue = make_scoped_refptr(
- new TaskQueueImpl(nullptr, virtual_time_domain_.get(),
- TaskQueue::Spec("test queue"), "test", "test"));
- selector_.AddQueue(task_queue.get());
- task_queues_.push_back(task_queue);
- }
- for (size_t i = 0; i < kTaskQueueCount; i++) {
- EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[i]->GetQueuePriority())
- << i;
- queue_to_index_map_.insert(std::make_pair(task_queues_[i].get(), i));
- }
- }
-
- void TearDown() final {
- for (scoped_refptr<TaskQueueImpl>& task_queue : task_queues_) {
- task_queue->UnregisterTaskQueue();
- // Note since this test doesn't have a TaskQueueManager we need to
- // manually remove |task_queue| from the |selector_|. Normally
- // UnregisterTaskQueue would do that.
- selector_.RemoveQueue(task_queue.get());
- }
- }
-
- scoped_refptr<TaskQueueImpl> NewTaskQueueWithBlockReporting() {
- return make_scoped_refptr(new TaskQueueImpl(
- nullptr, virtual_time_domain_.get(),
- TaskQueue::Spec("test queue").SetShouldReportWhenExecutionBlocked(true),
- "test", "test"));
- }
-
- const size_t kTaskQueueCount = 5;
- base::Closure test_closure_;
- TaskQueueSelectorForTest selector_;
- std::unique_ptr<VirtualTimeDomain> virtual_time_domain_;
- std::vector<scoped_refptr<TaskQueueImpl>> task_queues_;
- std::map<TaskQueueImpl*, size_t> queue_to_index_map_;
-};
-
-TEST_F(TaskQueueSelectorTest, TestDefaultPriority) {
- size_t queue_order[] = {4, 3, 2, 1, 0};
- PushTasks(queue_order, 5);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 3, 2, 1, 0));
-}
-
-TEST_F(TaskQueueSelectorTest, TestHighPriority) {
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasks(queue_order, 5);
- selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 0, 1, 3, 4));
-}
-
-TEST_F(TaskQueueSelectorTest, TestBestEffortPriority) {
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasks(queue_order, 5);
- selector_.SetQueuePriority(task_queues_[0].get(),
- TaskQueue::BEST_EFFORT_PRIORITY);
- selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 1, 3, 4, 0));
-}
-
-TEST_F(TaskQueueSelectorTest, TestControlPriority) {
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasks(queue_order, 5);
- selector_.SetQueuePriority(task_queues_[4].get(),
- TaskQueue::CONTROL_PRIORITY);
- EXPECT_EQ(TaskQueue::CONTROL_PRIORITY, task_queues_[4]->GetQueuePriority());
- selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY);
- EXPECT_EQ(TaskQueue::HIGH_PRIORITY, task_queues_[2]->GetQueuePriority());
- EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 2, 0, 1, 3));
-}
-
-TEST_F(TaskQueueSelectorTest, TestObserverWithEnabledQueue) {
- DisableQueue(task_queues_[1].get());
- MockObserver mock_observer;
- selector_.SetTaskQueueSelectorObserver(&mock_observer);
- EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(1);
- EnableQueue(task_queues_[1].get());
-}
-
-TEST_F(TaskQueueSelectorTest,
- TestObserverWithSetQueuePriorityAndQueueAlreadyEnabled) {
- selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::HIGH_PRIORITY);
- MockObserver mock_observer;
- selector_.SetTaskQueueSelectorObserver(&mock_observer);
- EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(0);
- selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::NORMAL_PRIORITY);
-}
-
-TEST_F(TaskQueueSelectorTest, TestDisableEnable) {
- MockObserver mock_observer;
- selector_.SetTaskQueueSelectorObserver(&mock_observer);
-
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasks(queue_order, 5);
- DisableQueue(task_queues_[2].get());
- DisableQueue(task_queues_[4].get());
- // Disabling a queue should not affect its priority.
- EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[2]->GetQueuePriority());
- EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[4]->GetQueuePriority());
- EXPECT_THAT(PopTasks(), testing::ElementsAre(0, 1, 3));
-
- EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(2);
- EnableQueue(task_queues_[2].get());
- selector_.SetQueuePriority(task_queues_[2].get(),
- TaskQueue::BEST_EFFORT_PRIORITY);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(2));
- EnableQueue(task_queues_[4].get());
- EXPECT_THAT(PopTasks(), testing::ElementsAre(4));
-}
-
-TEST_F(TaskQueueSelectorTest, TestDisableChangePriorityThenEnable) {
- EXPECT_TRUE(task_queues_[2]->delayed_work_queue()->Empty());
- EXPECT_TRUE(task_queues_[2]->immediate_work_queue()->Empty());
-
- DisableQueue(task_queues_[2].get());
- selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY);
-
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasks(queue_order, 5);
-
- EXPECT_TRUE(task_queues_[2]->delayed_work_queue()->Empty());
- EXPECT_FALSE(task_queues_[2]->immediate_work_queue()->Empty());
- EnableQueue(task_queues_[2].get());
-
- EXPECT_EQ(TaskQueue::HIGH_PRIORITY, task_queues_[2]->GetQueuePriority());
- EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 0, 1, 3, 4));
-}
-
-TEST_F(TaskQueueSelectorTest, TestEmptyQueues) {
- WorkQueue* chosen_work_queue = nullptr;
- EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue));
-
- // Test only disabled queues.
- size_t queue_order[] = {0};
- PushTasks(queue_order, 1);
- task_queues_[0]->SetQueueEnabled(false);
- selector_.DisableQueue(task_queues_[0].get());
- EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue));
-}
-
-TEST_F(TaskQueueSelectorTest, TestAge) {
- size_t enqueue_order[] = {10, 1, 2, 9, 4};
- size_t queue_order[] = {0, 1, 2, 3, 4};
- PushTasksWithEnqueueOrder(queue_order, enqueue_order, 5);
- EXPECT_THAT(PopTasks(), testing::ElementsAre(1, 2, 4, 3, 0));
-}
-
-TEST_F(TaskQueueSelectorTest, TestControlStarvesOthers) {
- size_t queue_order[] = {0, 1, 2, 3};
- PushTasks(queue_order, 4);
- selector_.SetQueuePriority(task_queues_[3].get(),
- TaskQueue::CONTROL_PRIORITY);
- selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY);
- selector_.SetQueuePriority(task_queues_[1].get(),
- TaskQueue::BEST_EFFORT_PRIORITY);
- for (int i = 0; i < 100; i++) {
- WorkQueue* chosen_work_queue = nullptr;
- EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
- EXPECT_EQ(task_queues_[3].get(), chosen_work_queue->task_queue());
- // Don't remove task from queue to simulate all queues still being full.
- }
-}
-
-TEST_F(TaskQueueSelectorTest, TestHighPriorityDoesNotStarveNormal) {
- size_t queue_order[] = {0, 1, 2};
- PushTasks(queue_order, 3);
- selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY);
- selector_.SetQueuePriority(task_queues_[1].get(),
- TaskQueue::BEST_EFFORT_PRIORITY);
- size_t counts[] = {0, 0, 0};
- for (int i = 0; i < 100; i++) {
- WorkQueue* chosen_work_queue = nullptr;
- EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
- size_t chosen_queue_index =
- queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
- counts[chosen_queue_index]++;
- // Don't remove task from queue to simulate all queues still being full.
- }
- EXPECT_GT(counts[0], 0ul); // Check high doesn't starve normal.
- EXPECT_GT(counts[2], counts[0]); // Check high gets more chance to run.
- EXPECT_EQ(0ul, counts[1]); // Check best effort is starved.
-}
-
-TEST_F(TaskQueueSelectorTest, TestBestEffortGetsStarved) {
- size_t queue_order[] = {0, 1};
- PushTasks(queue_order, 2);
- selector_.SetQueuePriority(task_queues_[0].get(),
- TaskQueue::BEST_EFFORT_PRIORITY);
- EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[1]->GetQueuePriority());
- WorkQueue* chosen_work_queue = nullptr;
- for (int i = 0; i < 100; i++) {
- EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
- EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
- // Don't remove task from queue to simulate all queues still being full.
- }
- selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::HIGH_PRIORITY);
- for (int i = 0; i < 100; i++) {
- EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
- EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
- // Don't remove task from queue to simulate all queues still being full.
- }
- selector_.SetQueuePriority(task_queues_[1].get(),
- TaskQueue::CONTROL_PRIORITY);
- for (int i = 0; i < 100; i++) {
- EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
- EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
- // Don't remove task from queue to simulate all queues still being full.
- }
-}
-
-TEST_F(TaskQueueSelectorTest, EnabledWorkQueuesEmpty) {
- EXPECT_TRUE(selector_.EnabledWorkQueuesEmpty());
- size_t queue_order[] = {0, 1};
- PushTasks(queue_order, 2);
-
- EXPECT_FALSE(selector_.EnabledWorkQueuesEmpty());
- PopTasks();
- EXPECT_TRUE(selector_.EnabledWorkQueuesEmpty());
-}
-
-TEST_F(TaskQueueSelectorTest, EnabledWorkQueuesEmpty_ControlPriority) {
- size_t queue_order[] = {0};
- PushTasks(queue_order, 1);
-
- selector_.SetQueuePriority(task_queues_[0].get(),
- TaskQueue::CONTROL_PRIORITY);
-
- EXPECT_FALSE(selector_.EnabledWorkQueuesEmpty());
-}
-
-TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_Empty) {
- WorkQueue* chosen_work_queue = nullptr;
- bool chose_delayed_over_immediate = false;
- EXPECT_FALSE(enabled_selector()->ChooseOldestWithPriority(
- TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate,
- &chosen_work_queue));
- EXPECT_FALSE(chose_delayed_over_immediate);
-}
-
-TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyDelayed) {
- task_queues_[0]->delayed_work_queue()->Push(TaskQueueImpl::Task(
- FROM_HERE, test_closure_, base::TimeTicks(), 0, true, 0));
-
- WorkQueue* chosen_work_queue = nullptr;
- bool chose_delayed_over_immediate = false;
- EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority(
- TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate,
- &chosen_work_queue));
- EXPECT_EQ(chosen_work_queue, task_queues_[0]->delayed_work_queue());
- EXPECT_FALSE(chose_delayed_over_immediate);
-}
-
-TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyImmediate) {
- task_queues_[0]->immediate_work_queue()->Push(TaskQueueImpl::Task(
- FROM_HERE, test_closure_, base::TimeTicks(), 0, true, 0));
-
- WorkQueue* chosen_work_queue = nullptr;
- bool chose_delayed_over_immediate = false;
- EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority(
- TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate,
- &chosen_work_queue));
- EXPECT_EQ(chosen_work_queue, task_queues_[0]->immediate_work_queue());
- EXPECT_FALSE(chose_delayed_over_immediate);
-}
-
-TEST_F(TaskQueueSelectorTest, TestObserverWithOneBlockedQueue) {
- TaskQueueSelectorForTest selector;
- MockObserver mock_observer;
- selector.SetTaskQueueSelectorObserver(&mock_observer);
-
- scoped_refptr<TaskQueueImpl> task_queue(NewTaskQueueWithBlockReporting());
- selector.AddQueue(task_queue.get());
- task_queue->SetQueueEnabled(false);
- selector.DisableQueue(task_queue.get());
-
- task_queue->immediate_work_queue()->PushAndSetEnqueueOrder(
- TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true),
- 0);
-
- WorkQueue* chosen_work_queue;
- EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1);
- EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue));
-
- task_queue->UnregisterTaskQueue();
- selector.RemoveQueue(task_queue.get());
-}
-
-TEST_F(TaskQueueSelectorTest, TestObserverWithTwoBlockedQueues) {
- TaskQueueSelectorForTest selector;
- MockObserver mock_observer;
- selector.SetTaskQueueSelectorObserver(&mock_observer);
-
- scoped_refptr<TaskQueueImpl> task_queue(NewTaskQueueWithBlockReporting());
- scoped_refptr<TaskQueueImpl> task_queue2(NewTaskQueueWithBlockReporting());
- selector.AddQueue(task_queue.get());
- selector.AddQueue(task_queue2.get());
- task_queue->SetQueueEnabled(false);
- task_queue2->SetQueueEnabled(false);
- selector.DisableQueue(task_queue.get());
- selector.DisableQueue(task_queue2.get());
- selector.SetQueuePriority(task_queue2.get(), TaskQueue::CONTROL_PRIORITY);
-
- task_queue->immediate_work_queue()->PushAndSetEnqueueOrder(
- TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true),
- 0);
- task_queue2->immediate_work_queue()->PushAndSetEnqueueOrder(
- TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true),
- 0);
-
- // Should still only see one call to OnTriedToSelectBlockedWorkQueue.
- WorkQueue* chosen_work_queue;
- EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1);
- EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue));
- testing::Mock::VerifyAndClearExpectations(&mock_observer);
-
- // Removing the second queue and selecting again should result in another
- // notification.
- task_queue->UnregisterTaskQueue();
- selector.RemoveQueue(task_queue.get());
- EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1);
- EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue));
-
- task_queue2->UnregisterTaskQueue();
- selector.RemoveQueue(task_queue2.get());
-}
-
-struct ChooseOldestWithPriorityTestParam {
- int delayed_task_enqueue_order;
- int immediate_task_enqueue_order;
- int immediate_starvation_count;
- const char* expected_work_queue_name;
- bool expected_did_starve_immediate_queue;
-};
-
-static const ChooseOldestWithPriorityTestParam
- kChooseOldestWithPriorityTestCases[] = {
- {1, 2, 0, "delayed", true},
- {1, 2, 1, "delayed", true},
- {1, 2, 2, "delayed", true},
- {1, 2, 3, "immediate", false},
- {1, 2, 4, "immediate", false},
- {2, 1, 4, "immediate", false},
- {2, 1, 4, "immediate", false},
-};
-
-class ChooseOldestWithPriorityTest
- : public TaskQueueSelectorTest,
- public testing::WithParamInterface<ChooseOldestWithPriorityTestParam> {};
-
-TEST_P(ChooseOldestWithPriorityTest, RoundRobinTest) {
- task_queues_[0]->immediate_work_queue()->Push(
- TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(),
- GetParam().immediate_task_enqueue_order, true,
- GetParam().immediate_task_enqueue_order));
-
- task_queues_[0]->delayed_work_queue()->Push(
- TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(),
- GetParam().delayed_task_enqueue_order, true,
- GetParam().delayed_task_enqueue_order));
-
- selector_.SetImmediateStarvationCountForTest(
- GetParam().immediate_starvation_count);
-
- WorkQueue* chosen_work_queue = nullptr;
- bool chose_delayed_over_immediate = false;
- EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority(
- TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate,
- &chosen_work_queue));
- EXPECT_EQ(chosen_work_queue->task_queue(), task_queues_[0].get());
- EXPECT_STREQ(chosen_work_queue->name(), GetParam().expected_work_queue_name);
- EXPECT_EQ(chose_delayed_over_immediate,
- GetParam().expected_did_starve_immediate_queue);
-}
-
-INSTANTIATE_TEST_CASE_P(ChooseOldestWithPriorityTest,
- ChooseOldestWithPriorityTest,
- testing::ValuesIn(kChooseOldestWithPriorityTestCases));
-
-} // namespace internal
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/test_always_fail_time_source.cc b/chromium/components/scheduler/base/test_always_fail_time_source.cc
deleted file mode 100644
index 254298453f9..00000000000
--- a/chromium/components/scheduler/base/test_always_fail_time_source.cc
+++ /dev/null
@@ -1,21 +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 "components/scheduler/base/test_always_fail_time_source.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace scheduler {
-
-TestAlwaysFailTimeSource::TestAlwaysFailTimeSource() {
-}
-
-TestAlwaysFailTimeSource::~TestAlwaysFailTimeSource() {
-}
-
-base::TimeTicks TestAlwaysFailTimeSource::NowTicks() {
- ADD_FAILURE() << "NowTicks() was called!";
- return base::TimeTicks();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/test_always_fail_time_source.h b/chromium/components/scheduler/base/test_always_fail_time_source.h
deleted file mode 100644
index ec6e73ddf81..00000000000
--- a/chromium/components/scheduler/base/test_always_fail_time_source.h
+++ /dev/null
@@ -1,26 +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 COMPONENTS_SCHEDULER_BASE_TEST_ALWAYS_FAIL_TIME_SOURCE_H_
-#define COMPONENTS_SCHEDULER_BASE_TEST_ALWAYS_FAIL_TIME_SOURCE_H_
-
-#include "base/macros.h"
-#include "base/time/tick_clock.h"
-
-namespace scheduler {
-
-class TestAlwaysFailTimeSource : public base::TickClock {
- public:
- explicit TestAlwaysFailTimeSource();
- ~TestAlwaysFailTimeSource() override;
-
- base::TimeTicks NowTicks() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestAlwaysFailTimeSource);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_TEST_ALWAYS_FAIL_TIME_SOURCE_H_
diff --git a/chromium/components/scheduler/base/test_time_source.cc b/chromium/components/scheduler/base/test_time_source.cc
deleted file mode 100644
index 6bbe83ba2a9..00000000000
--- a/chromium/components/scheduler/base/test_time_source.cc
+++ /dev/null
@@ -1,20 +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 "components/scheduler/base/test_time_source.h"
-
-namespace scheduler {
-
-TestTimeSource::TestTimeSource(base::SimpleTestTickClock* time_source)
- : time_source_(time_source) {
- DCHECK(time_source_);
-}
-
-TestTimeSource::~TestTimeSource() {}
-
-base::TimeTicks TestTimeSource::NowTicks() {
- return time_source_->NowTicks();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/test_time_source.h b/chromium/components/scheduler/base/test_time_source.h
deleted file mode 100644
index 9ff57f0202e..00000000000
--- a/chromium/components/scheduler/base/test_time_source.h
+++ /dev/null
@@ -1,31 +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 COMPONENTS_SCHEDULER_BASE_TEST_TIME_SOURCE_H_
-#define COMPONENTS_SCHEDULER_BASE_TEST_TIME_SOURCE_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "base/time/tick_clock.h"
-
-namespace scheduler {
-
-class TestTimeSource : public base::TickClock {
- public:
- explicit TestTimeSource(base::SimpleTestTickClock* time_source);
- ~TestTimeSource() override;
-
- base::TimeTicks NowTicks() override;
-
- private:
- // Not owned.
- base::SimpleTestTickClock* time_source_;
-
- DISALLOW_COPY_AND_ASSIGN(TestTimeSource);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_TEST_TIME_SOURCE_H_
diff --git a/chromium/components/scheduler/base/time_domain.cc b/chromium/components/scheduler/base/time_domain.cc
deleted file mode 100644
index 61851c533ea..00000000000
--- a/chromium/components/scheduler/base/time_domain.cc
+++ /dev/null
@@ -1,215 +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 "components/scheduler/base/time_domain.h"
-
-#include <set>
-
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/task_queue_manager_delegate.h"
-#include "components/scheduler/base/work_queue.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-TimeDomain::TimeDomain(Observer* observer) : observer_(observer) {}
-
-TimeDomain::~TimeDomain() {
- DCHECK(main_thread_checker_.CalledOnValidThread());
-}
-
-void TimeDomain::RegisterQueue(internal::TaskQueueImpl* queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- DCHECK_EQ(queue->GetTimeDomain(), this);
-}
-
-void TimeDomain::UnregisterQueue(internal::TaskQueueImpl* queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- DCHECK_EQ(queue->GetTimeDomain(), this);
- UnregisterAsUpdatableTaskQueue(queue);
-
- // We need to remove |task_queue| from delayed_wakeup_multimap_ which is a
- // little awkward since it's keyed by time. O(n) running time.
- for (DelayedWakeupMultimap::iterator iter = delayed_wakeup_multimap_.begin();
- iter != delayed_wakeup_multimap_.end();) {
- if (iter->second == queue) {
- // O(1) amortized.
- iter = delayed_wakeup_multimap_.erase(iter);
- } else {
- iter++;
- }
- }
-}
-
-void TimeDomain::MigrateQueue(internal::TaskQueueImpl* queue,
- TimeDomain* destination_time_domain) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- DCHECK_EQ(queue->GetTimeDomain(), this);
- DCHECK(destination_time_domain);
- UnregisterAsUpdatableTaskQueue(queue);
-
- base::TimeTicks destination_now = destination_time_domain->Now();
- // We need to remove |task_queue| from delayed_wakeup_multimap_ which is a
- // little awkward since it's keyed by time. O(n) running time.
- for (DelayedWakeupMultimap::iterator iter = delayed_wakeup_multimap_.begin();
- iter != delayed_wakeup_multimap_.end();) {
- if (iter->second == queue) {
- destination_time_domain->ScheduleDelayedWork(queue, iter->first,
- destination_now);
- // O(1) amortized.
- iter = delayed_wakeup_multimap_.erase(iter);
- } else {
- iter++;
- }
- }
-}
-
-void TimeDomain::ScheduleDelayedWork(internal::TaskQueueImpl* queue,
- base::TimeTicks delayed_run_time,
- base::TimeTicks now) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- if (delayed_wakeup_multimap_.empty() ||
- delayed_run_time < delayed_wakeup_multimap_.begin()->first) {
- base::TimeDelta delay = std::max(base::TimeDelta(), delayed_run_time - now);
- RequestWakeup(now, delay);
- }
-
- delayed_wakeup_multimap_.insert(std::make_pair(delayed_run_time, queue));
- if (observer_)
- observer_->OnTimeDomainHasDelayedWork();
-}
-
-void TimeDomain::RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue) {
- {
- base::AutoLock lock(newly_updatable_lock_);
- newly_updatable_.push_back(queue);
- }
- if (observer_)
- observer_->OnTimeDomainHasImmediateWork();
-}
-
-void TimeDomain::UnregisterAsUpdatableTaskQueue(
- internal::TaskQueueImpl* queue) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
-
- updatable_queue_set_.erase(queue);
-
- base::AutoLock lock(newly_updatable_lock_);
- // Remove all copies of |queue| from |newly_updatable_|.
- for (size_t i = 0; i < newly_updatable_.size();) {
- if (newly_updatable_[i] == queue) {
- // Move last element into slot #i and then compact.
- newly_updatable_[i] = newly_updatable_.back();
- newly_updatable_.pop_back();
- } else {
- i++;
- }
- }
-}
-
-void TimeDomain::UpdateWorkQueues(
- bool should_trigger_wakeup,
- const internal::TaskQueueImpl::Task* previous_task) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- LazyNow lazy_now(CreateLazyNow());
-
- // Move any ready delayed tasks into the Incoming queues.
- WakeupReadyDelayedQueues(&lazy_now, should_trigger_wakeup, previous_task);
-
- MoveNewlyUpdatableQueuesIntoUpdatableQueueSet();
-
- auto iter = updatable_queue_set_.begin();
- while (iter != updatable_queue_set_.end()) {
- internal::TaskQueueImpl* queue = *iter++;
- // NOTE Update work queue may erase itself from |updatable_queue_set_|.
- // This is fine, erasing an element won't invalidate any interator, as long
- // as the iterator isn't the element being delated.
- if (queue->immediate_work_queue()->Empty())
- queue->UpdateImmediateWorkQueue(should_trigger_wakeup, previous_task);
- }
-}
-
-void TimeDomain::MoveNewlyUpdatableQueuesIntoUpdatableQueueSet() {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- base::AutoLock lock(newly_updatable_lock_);
- while (!newly_updatable_.empty()) {
- updatable_queue_set_.insert(newly_updatable_.back());
- newly_updatable_.pop_back();
- }
-}
-
-void TimeDomain::WakeupReadyDelayedQueues(
- LazyNow* lazy_now,
- bool should_trigger_wakeup,
- const internal::TaskQueueImpl::Task* previous_task) {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- // Wake up any queues with pending delayed work. Note std::multipmap stores
- // the elements sorted by key, so the begin() iterator points to the earliest
- // queue to wakeup.
- std::set<internal::TaskQueueImpl*> dedup_set;
- while (!delayed_wakeup_multimap_.empty()) {
- DelayedWakeupMultimap::iterator next_wakeup =
- delayed_wakeup_multimap_.begin();
- if (next_wakeup->first > lazy_now->Now())
- break;
- // A queue could have any number of delayed tasks pending so it's worthwhile
- // deduping calls to UpdateDelayedWorkQueue since it takes a lock.
- // NOTE the order in which these are called matters since the order
- // in which EnqueueTaskLocks is called is respected when choosing which
- // queue to execute a task from.
- if (dedup_set.insert(next_wakeup->second).second) {
- next_wakeup->second->UpdateDelayedWorkQueue(
- lazy_now, should_trigger_wakeup, previous_task);
- }
- delayed_wakeup_multimap_.erase(next_wakeup);
- }
-}
-
-void TimeDomain::ClearExpiredWakeups() {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- LazyNow lazy_now(CreateLazyNow());
- while (!delayed_wakeup_multimap_.empty()) {
- DelayedWakeupMultimap::iterator next_wakeup =
- delayed_wakeup_multimap_.begin();
- if (next_wakeup->first > lazy_now.Now())
- break;
- delayed_wakeup_multimap_.erase(next_wakeup);
- }
-}
-
-bool TimeDomain::NextScheduledRunTime(base::TimeTicks* out_time) const {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- if (delayed_wakeup_multimap_.empty())
- return false;
-
- *out_time = delayed_wakeup_multimap_.begin()->first;
- return true;
-}
-
-bool TimeDomain::NextScheduledTaskQueue(TaskQueue** out_task_queue) const {
- DCHECK(main_thread_checker_.CalledOnValidThread());
- if (delayed_wakeup_multimap_.empty())
- return false;
-
- *out_task_queue = delayed_wakeup_multimap_.begin()->second;
- return true;
-}
-
-void TimeDomain::AsValueInto(base::trace_event::TracedValue* state) const {
- state->BeginDictionary();
- state->SetString("name", GetName());
- state->BeginArray("updatable_queue_set");
- for (auto& queue : updatable_queue_set_)
- state->AppendString(queue->GetName());
- state->EndArray();
- state->SetInteger("registered_delay_count", delayed_wakeup_multimap_.size());
- if (!delayed_wakeup_multimap_.empty()) {
- base::TimeDelta delay = delayed_wakeup_multimap_.begin()->first - Now();
- state->SetDouble("next_delay_ms", delay.InMillisecondsF());
- }
- AsValueIntoInternal(state);
- state->EndDictionary();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/time_domain.h b/chromium/components/scheduler/base/time_domain.h
deleted file mode 100644
index 0f33d811bad..00000000000
--- a/chromium/components/scheduler/base/time_domain.h
+++ /dev/null
@@ -1,156 +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 COMPONENTS_SCHEDULER_BASE_TIME_DOMAIN_H_
-#define COMPONENTS_SCHEDULER_BASE_TIME_DOMAIN_H_
-
-#include <map>
-
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "components/scheduler/base/lazy_now.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-namespace internal {
-class TaskQueueImpl;
-} // internal
-class TaskQueueManager;
-class TaskQueueManagerDelegate;
-
-class SCHEDULER_EXPORT TimeDomain {
- public:
- class SCHEDULER_EXPORT Observer {
- public:
- virtual ~Observer() {}
-
- // Called when an empty TaskQueue registered with this TimeDomain has a task
- // enqueued.
- virtual void OnTimeDomainHasImmediateWork() = 0;
-
- // Called when a TaskQueue registered with this TimeDomain has a delayed
- // task enqueued.
- virtual void OnTimeDomainHasDelayedWork() = 0;
- };
-
- explicit TimeDomain(Observer* observer);
- virtual ~TimeDomain();
-
- // Returns a LazyNow that evaluate this TimeDomain's Now. Can be called from
- // any thread.
- // TODO(alexclarke): Make this main thread only.
- virtual LazyNow CreateLazyNow() const = 0;
-
- // Evaluate this TimeDomain's Now. Can be called from any thread.
- virtual base::TimeTicks Now() const = 0;
-
- // Some TimeDomains support virtual time, this method tells us to advance time
- // if possible and return true if time was advanced.
- virtual bool MaybeAdvanceTime() = 0;
-
- // Returns the name of this time domain for tracing.
- virtual const char* GetName() const = 0;
-
- // If there is a scheduled delayed task, |out_time| is set to the scheduled
- // runtime for the next one and it returns true. Returns false otherwise.
- bool NextScheduledRunTime(base::TimeTicks* out_time) const;
-
- protected:
- friend class internal::TaskQueueImpl;
- friend class TaskQueueManager;
-
- void AsValueInto(base::trace_event::TracedValue* state) const;
-
- // Migrates |queue| from this time domain to |destination_time_domain|.
- void MigrateQueue(internal::TaskQueueImpl* queue,
- TimeDomain* destination_time_domain);
-
- // If there is a scheduled delayed task, |out_task_queue| is set to the queue
- // the next task was posted to and it returns true. Returns false otherwise.
- bool NextScheduledTaskQueue(TaskQueue** out_task_queue) const;
-
- // Adds |queue| to the set of task queues that UpdateWorkQueues calls
- // UpdateWorkQueue on.
- void RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue);
-
- // Schedules a call to TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue
- // when this TimeDomain reaches |delayed_run_time|.
- void ScheduleDelayedWork(internal::TaskQueueImpl* queue,
- base::TimeTicks delayed_run_time,
- base::TimeTicks now);
-
- // Registers the |queue|.
- void RegisterQueue(internal::TaskQueueImpl* queue);
-
- // Removes |queue| from the set of task queues that UpdateWorkQueues calls
- // UpdateWorkQueue on.
- void UnregisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue);
-
- // Removes |queue| from all internal data structures.
- void UnregisterQueue(internal::TaskQueueImpl* queue);
-
- // Updates active queues associated with this TimeDomain.
- void UpdateWorkQueues(bool should_trigger_wakeup,
- const internal::TaskQueueImpl::Task* previous_task);
-
- // Called by the TaskQueueManager when the TimeDomain is registered.
- virtual void OnRegisterWithTaskQueueManager(
- TaskQueueManager* task_queue_manager) = 0;
-
- // The implementaion will secedule task processing to run with |delay| with
- // respect to the TimeDomain's time source. Always called on the main thread.
- // NOTE this is only called by ScheduleDelayedWork if the scheduled runtime
- // is sooner than any previously sheduled work or if there is no other
- // scheduled work.
- virtual void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) = 0;
-
- // For implementation specific tracing.
- virtual void AsValueIntoInternal(
- base::trace_event::TracedValue* state) const = 0;
-
- // Call TaskQueueImpl::UpdateDelayedWorkQueue for each queue where the delay
- // has elapsed.
- void WakeupReadyDelayedQueues(
- LazyNow* lazy_now,
- bool should_trigger_wakeup,
- const internal::TaskQueueImpl::Task* previous_task);
-
- protected:
- // Clears expired entries from |delayed_wakeup_multimap_|. Caution needs to be
- // taken to ensure TaskQueueImpl::UpdateDelayedWorkQueue or
- // TaskQueueImpl::Pump is called on the affected queues.
- void ClearExpiredWakeups();
-
- private:
- void MoveNewlyUpdatableQueuesIntoUpdatableQueueSet();
-
- typedef std::multimap<base::TimeTicks, internal::TaskQueueImpl*>
- DelayedWakeupMultimap;
-
- DelayedWakeupMultimap delayed_wakeup_multimap_;
-
- // This lock guards only |newly_updatable_|. It's not expected to be heavily
- // contended.
- base::Lock newly_updatable_lock_;
- std::vector<internal::TaskQueueImpl*> newly_updatable_;
-
- // Set of task queues with avaliable work on the incoming queue. This should
- // only be accessed from the main thread.
- std::set<internal::TaskQueueImpl*> updatable_queue_set_;
-
- Observer* observer_; // NOT OWNED.
-
- base::ThreadChecker main_thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(TimeDomain);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_TIME_DOMAIN_H_
diff --git a/chromium/components/scheduler/base/time_domain_unittest.cc b/chromium/components/scheduler/base/time_domain_unittest.cc
deleted file mode 100644
index 39fc93997a1..00000000000
--- a/chromium/components/scheduler/base/time_domain_unittest.cc
+++ /dev/null
@@ -1,230 +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 "components/scheduler/base/time_domain.h"
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/task_queue_manager.h"
-#include "components/scheduler/base/task_queue_manager_delegate_for_test.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/base/work_queue.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using testing::_;
-using testing::AnyNumber;
-using testing::Mock;
-
-namespace scheduler {
-
-class MockTimeDomain : public TimeDomain {
- public:
- explicit MockTimeDomain(TimeDomain::Observer* observer)
- : TimeDomain(observer),
- now_(base::TimeTicks() + base::TimeDelta::FromSeconds(1)) {}
-
- ~MockTimeDomain() override {}
-
- using TimeDomain::ClearExpiredWakeups;
- using TimeDomain::NextScheduledRunTime;
- using TimeDomain::NextScheduledTaskQueue;
- using TimeDomain::ScheduleDelayedWork;
- using TimeDomain::UnregisterQueue;
- using TimeDomain::UpdateWorkQueues;
- using TimeDomain::RegisterAsUpdatableTaskQueue;
-
- // TimeSource implementation:
- LazyNow CreateLazyNow() const override { return LazyNow(now_); }
- base::TimeTicks Now() const override { return now_; }
-
- void AsValueIntoInternal(
- base::trace_event::TracedValue* state) const override {}
-
- bool MaybeAdvanceTime() override { return false; }
- const char* GetName() const override { return "Test"; }
- void OnRegisterWithTaskQueueManager(
- TaskQueueManager* task_queue_manager) override {}
-
- MOCK_METHOD2(RequestWakeup, void(base::TimeTicks now, base::TimeDelta delay));
-
- void SetNow(base::TimeTicks now) { now_ = now; }
-
-
- private:
- base::TimeTicks now_;
-
- DISALLOW_COPY_AND_ASSIGN(MockTimeDomain);
-};
-
-class TimeDomainTest : public testing::Test {
- public:
- void SetUp() final {
- time_domain_ = base::WrapUnique(CreateMockTimeDomain());
- task_queue_ = make_scoped_refptr(new internal::TaskQueueImpl(
- nullptr, time_domain_.get(), TaskQueue::Spec("test_queue"),
- "test.category", "test.category"));
- }
-
- void TearDown() final {
- if (task_queue_)
- task_queue_->UnregisterTaskQueue();
- }
-
- virtual MockTimeDomain* CreateMockTimeDomain() {
- return new MockTimeDomain(nullptr);
- }
-
- std::unique_ptr<MockTimeDomain> time_domain_;
- scoped_refptr<internal::TaskQueueImpl> task_queue_;
-};
-
-TEST_F(TimeDomainTest, ScheduleDelayedWork) {
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks delayed_runtime = time_domain_->Now() + delay;
- EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay));
- base::TimeTicks now = time_domain_->Now();
- time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay, now);
-
- base::TimeTicks next_scheduled_runtime;
- EXPECT_TRUE(time_domain_->NextScheduledRunTime(&next_scheduled_runtime));
- EXPECT_EQ(delayed_runtime, next_scheduled_runtime);
-
- TaskQueue* next_task_queue;
- EXPECT_TRUE(time_domain_->NextScheduledTaskQueue(&next_task_queue));
- EXPECT_EQ(task_queue_.get(), next_task_queue);
-}
-
-TEST_F(TimeDomainTest, RequestWakeup_OnlyCalledForEarlierTasks) {
- base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10);
- base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(20);
- base::TimeDelta delay3 = base::TimeDelta::FromMilliseconds(30);
- base::TimeDelta delay4 = base::TimeDelta::FromMilliseconds(1);
-
- // RequestWakeup should always be called if there are no other wakeups.
- EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay1));
- base::TimeTicks now = time_domain_->Now();
- time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay1, now);
-
- Mock::VerifyAndClearExpectations(time_domain_.get());
-
- // RequestWakeup should not be called when scheduling later tasks.
- EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(0);
- time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay2, now);
- time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay3, now);
-
- // RequestWakeup should be called when scheduling earlier tasks.
- Mock::VerifyAndClearExpectations(time_domain_.get());
- EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay4));
- time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay4, now);
-}
-
-TEST_F(TimeDomainTest, UnregisterQueue) {
- scoped_refptr<internal::TaskQueueImpl> task_queue2_ =
- make_scoped_refptr(new internal::TaskQueueImpl(
- nullptr, time_domain_.get(), TaskQueue::Spec("test_queue2"),
- "test.category", "test.category"));
-
- EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(1);
- base::TimeTicks now = time_domain_->Now();
- time_domain_->ScheduleDelayedWork(
- task_queue_.get(), now + base::TimeDelta::FromMilliseconds(10), now);
- time_domain_->ScheduleDelayedWork(
- task_queue2_.get(), now + base::TimeDelta::FromMilliseconds(100), now);
-
- TaskQueue* next_task_queue;
- EXPECT_TRUE(time_domain_->NextScheduledTaskQueue(&next_task_queue));
- EXPECT_EQ(task_queue_.get(), next_task_queue);
-
- time_domain_->UnregisterQueue(task_queue_.get());
- task_queue_ = scoped_refptr<internal::TaskQueueImpl>();
- EXPECT_TRUE(time_domain_->NextScheduledTaskQueue(&next_task_queue));
- EXPECT_EQ(task_queue2_.get(), next_task_queue);
-
- time_domain_->UnregisterQueue(task_queue2_.get());
- EXPECT_FALSE(time_domain_->NextScheduledTaskQueue(&next_task_queue));
-}
-
-TEST_F(TimeDomainTest, UpdateWorkQueues) {
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(50);
- EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay));
- base::TimeTicks now = time_domain_->Now();
- base::TimeTicks delayed_runtime = now + delay;
- time_domain_->ScheduleDelayedWork(task_queue_.get(), delayed_runtime, now);
-
- base::TimeTicks next_run_time;
- ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time));
- EXPECT_EQ(delayed_runtime, next_run_time);
-
- time_domain_->UpdateWorkQueues(false, nullptr);
- ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time));
- EXPECT_EQ(delayed_runtime, next_run_time);
-
- time_domain_->SetNow(delayed_runtime);
- time_domain_->UpdateWorkQueues(false, nullptr);
- ASSERT_FALSE(time_domain_->NextScheduledRunTime(&next_run_time));
-}
-
-TEST_F(TimeDomainTest, ClearExpiredWakeups) {
- base::TimeTicks now = time_domain_->Now();
- base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10);
- base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(20);
- base::TimeTicks run_time1 = now + delay1;
- base::TimeTicks run_time2 = now + delay2;
-
- EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(AnyNumber());
- time_domain_->ScheduleDelayedWork(task_queue_.get(), run_time1, now);
- time_domain_->ScheduleDelayedWork(task_queue_.get(), run_time2, now);
-
- base::TimeTicks next_run_time;
- ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time));
- EXPECT_EQ(run_time1, next_run_time);
-
- time_domain_->SetNow(run_time1);
- time_domain_->ClearExpiredWakeups();
-
- ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time));
- EXPECT_EQ(run_time2, next_run_time);
-
- time_domain_->SetNow(run_time2);
- time_domain_->ClearExpiredWakeups();
- ASSERT_FALSE(time_domain_->NextScheduledRunTime(&next_run_time));
-}
-
-namespace {
-class MockObserver : public TimeDomain::Observer {
- public:
- ~MockObserver() override {}
-
- MOCK_METHOD0(OnTimeDomainHasImmediateWork, void());
- MOCK_METHOD0(OnTimeDomainHasDelayedWork, void());
-};
-} // namespace
-
-class TimeDomainWithObserverTest : public TimeDomainTest {
- public:
- MockTimeDomain* CreateMockTimeDomain() override {
- observer_.reset(new MockObserver());
- return new MockTimeDomain(observer_.get());
- }
-
- std::unique_ptr<MockObserver> observer_;
-};
-
-TEST_F(TimeDomainWithObserverTest, OnTimeDomainHasImmediateWork) {
- EXPECT_CALL(*observer_, OnTimeDomainHasImmediateWork());
- time_domain_->RegisterAsUpdatableTaskQueue(task_queue_.get());
-}
-
-TEST_F(TimeDomainWithObserverTest, OnTimeDomainHasDelayedWork) {
- EXPECT_CALL(*observer_, OnTimeDomainHasDelayedWork());
- EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _));
- base::TimeTicks now = time_domain_->Now();
- time_domain_->ScheduleDelayedWork(
- task_queue_.get(), now + base::TimeDelta::FromMilliseconds(10), now);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/virtual_time_domain.cc b/chromium/components/scheduler/base/virtual_time_domain.cc
deleted file mode 100644
index db9c4035b29..00000000000
--- a/chromium/components/scheduler/base/virtual_time_domain.cc
+++ /dev/null
@@ -1,64 +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 "components/scheduler/base/virtual_time_domain.h"
-
-#include "base/bind.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/task_queue_manager.h"
-#include "components/scheduler/base/task_queue_manager_delegate.h"
-
-namespace scheduler {
-
-VirtualTimeDomain::VirtualTimeDomain(TimeDomain::Observer* observer,
- base::TimeTicks initial_time)
- : TimeDomain(observer), now_(initial_time), task_queue_manager_(nullptr) {}
-
-VirtualTimeDomain::~VirtualTimeDomain() {}
-
-void VirtualTimeDomain::OnRegisterWithTaskQueueManager(
- TaskQueueManager* task_queue_manager) {
- task_queue_manager_ = task_queue_manager;
- DCHECK(task_queue_manager_);
-}
-
-LazyNow VirtualTimeDomain::CreateLazyNow() const {
- base::AutoLock lock(lock_);
- return LazyNow(now_);
-}
-
-base::TimeTicks VirtualTimeDomain::Now() const {
- base::AutoLock lock(lock_);
- return now_;
-}
-
-void VirtualTimeDomain::RequestWakeup(base::TimeTicks now,
- base::TimeDelta delay) {
- // We don't need to do anything here because the caller of AdvanceTo is
- // responsible for calling TaskQueueManager::MaybeScheduleImmediateWork if
- // needed.
-}
-
-bool VirtualTimeDomain::MaybeAdvanceTime() {
- return false;
-}
-
-void VirtualTimeDomain::AsValueIntoInternal(
- base::trace_event::TracedValue* state) const {}
-
-void VirtualTimeDomain::AdvanceTo(base::TimeTicks now) {
- base::AutoLock lock(lock_);
- DCHECK_GE(now, now_);
- now_ = now;
-}
-
-void VirtualTimeDomain::RequestDoWork() {
- task_queue_manager_->MaybeScheduleImmediateWork(FROM_HERE);
-}
-
-const char* VirtualTimeDomain::GetName() const {
- return "VirtualTimeDomain";
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/virtual_time_domain.h b/chromium/components/scheduler/base/virtual_time_domain.h
deleted file mode 100644
index e522533be66..00000000000
--- a/chromium/components/scheduler/base/virtual_time_domain.h
+++ /dev/null
@@ -1,55 +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 COMPONENTS_SCHEDULER_BASE_VIRTUAL_TIME_DOMAIN_H_
-#define COMPONENTS_SCHEDULER_BASE_VIRTUAL_TIME_DOMAIN_H_
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "components/scheduler/base/time_domain.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-class SCHEDULER_EXPORT VirtualTimeDomain : public TimeDomain {
- public:
- VirtualTimeDomain(TimeDomain::Observer* observer,
- base::TimeTicks initial_time);
- ~VirtualTimeDomain() override;
-
- // TimeDomain implementation:
- LazyNow CreateLazyNow() const override;
- base::TimeTicks Now() const override;
- bool MaybeAdvanceTime() override;
- const char* GetName() const override;
-
- // Advances this time domain to |now|. NOTE |now| is supposed to be
- // monotonically increasing. NOTE it's the responsibility of the caller to
- // call TaskQueueManager::MaybeScheduleImmediateWork if needed.
- void AdvanceTo(base::TimeTicks now);
-
- using TimeDomain::ClearExpiredWakeups;
-
- protected:
- void OnRegisterWithTaskQueueManager(
- TaskQueueManager* task_queue_manager) override;
- void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override;
- void AsValueIntoInternal(
- base::trace_event::TracedValue* state) const override;
-
- void RequestDoWork();
-
- private:
- mutable base::Lock lock_; // Protects |now_|.
- base::TimeTicks now_;
-
- TaskQueueManager* task_queue_manager_; // NOT OWNED
- base::Closure do_work_closure_;
-
- DISALLOW_COPY_AND_ASSIGN(VirtualTimeDomain);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_VIRTUAL_TIME_DOMAIN_H_
diff --git a/chromium/components/scheduler/base/work_queue.cc b/chromium/components/scheduler/base/work_queue.cc
deleted file mode 100644
index 313baa9af36..00000000000
--- a/chromium/components/scheduler/base/work_queue.cc
+++ /dev/null
@@ -1,105 +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 "components/scheduler/base/work_queue.h"
-
-#include "components/scheduler/base/work_queue_sets.h"
-
-namespace scheduler {
-namespace internal {
-
-WorkQueue::WorkQueue(TaskQueueImpl* task_queue, const char* name)
- : work_queue_sets_(nullptr),
- task_queue_(task_queue),
- work_queue_set_index_(0),
- name_(name) {}
-
-void WorkQueue::AsValueInto(base::trace_event::TracedValue* state) const {
- std::queue<TaskQueueImpl::Task> queue_copy(work_queue_);
- while (!queue_copy.empty()) {
- TaskQueueImpl::TaskAsValueInto(queue_copy.front(), state);
- queue_copy.pop();
- }
-}
-
-WorkQueue::~WorkQueue() {
- DCHECK(!work_queue_sets_) << task_queue_ ->GetName() << " : "
- << work_queue_sets_->name() << " : " << name_;
-}
-
-const TaskQueueImpl::Task* WorkQueue::GetFrontTask() const {
- if (work_queue_.empty())
- return nullptr;
- return &work_queue_.front();
-}
-
-bool WorkQueue::GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const {
- if (work_queue_.empty())
- return false;
- *enqueue_order = work_queue_.front().enqueue_order();
- return true;
-}
-
-void WorkQueue::Push(const TaskQueueImpl::Task& task) {
- bool was_empty = work_queue_.empty();
- work_queue_.push(task);
- if (was_empty && work_queue_sets_)
- work_queue_sets_->OnPushQueue(this);
-}
-
-void WorkQueue::PushAndSetEnqueueOrder(const TaskQueueImpl::Task& task,
- EnqueueOrder enqueue_order) {
- bool was_empty = work_queue_.empty();
- work_queue_.push(task);
- work_queue_.back().set_enqueue_order(enqueue_order);
-
- if (was_empty && work_queue_sets_)
- work_queue_sets_->OnPushQueue(this);
-}
-
-void WorkQueue::PopTaskForTest() {
- work_queue_.pop();
-}
-
-void WorkQueue::SwapLocked(std::queue<TaskQueueImpl::Task>& incoming_queue) {
- std::swap(work_queue_, incoming_queue);
-
- if (!work_queue_.empty() && work_queue_sets_)
- work_queue_sets_->OnPushQueue(this);
- task_queue_->TraceQueueSize(true);
-}
-
-TaskQueueImpl::Task WorkQueue::TakeTaskFromWorkQueue() {
- DCHECK(work_queue_sets_);
- DCHECK(!work_queue_.empty());
- TaskQueueImpl::Task pending_task = std::move(work_queue_.front());
- work_queue_.pop();
- work_queue_sets_->OnPopQueue(this);
- task_queue_->TraceQueueSize(false);
- return pending_task;
-}
-
-void WorkQueue::AssignToWorkQueueSets(WorkQueueSets* work_queue_sets) {
- work_queue_sets_ = work_queue_sets;
-}
-
-void WorkQueue::AssignSetIndex(size_t work_queue_set_index) {
- work_queue_set_index_ = work_queue_set_index;
-}
-
-bool WorkQueue::ShouldRunBefore(const WorkQueue* other_queue) const {
- DCHECK(!work_queue_.empty());
- DCHECK(!other_queue->work_queue_.empty());
- EnqueueOrder enqueue_order = 0;
- EnqueueOrder other_enqueue_order = 0;
- bool have_task = GetFrontTaskEnqueueOrder(&enqueue_order);
- bool have_other_task =
- other_queue->GetFrontTaskEnqueueOrder(&other_enqueue_order);
- DCHECK(have_task);
- DCHECK(have_other_task);
- return enqueue_order < other_enqueue_order;
-}
-
-} // namespace internal
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/work_queue.h b/chromium/components/scheduler/base/work_queue.h
deleted file mode 100644
index 9ff919d7f7e..00000000000
--- a/chromium/components/scheduler/base/work_queue.h
+++ /dev/null
@@ -1,96 +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_RENDERER_SCHEDULER_BASE_WORK_QUEUE_H_
-#define CONTENT_RENDERER_SCHEDULER_BASE_WORK_QUEUE_H_
-
-#include <stddef.h>
-
-#include <set>
-
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "components/scheduler/base/enqueue_order.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-namespace internal {
-class WorkQueueSets;
-
-class SCHEDULER_EXPORT WorkQueue {
- public:
- WorkQueue(TaskQueueImpl* task_queue, const char* name);
- ~WorkQueue();
-
- // Associates this work queue with the given work queue sets. This must be
- // called before any tasks can be inserted into this work queue.
- void AssignToWorkQueueSets(WorkQueueSets* work_queue_sets);
-
- // Assigns the current set index.
- void AssignSetIndex(size_t work_queue_set_index);
-
- void AsValueInto(base::trace_event::TracedValue* state) const;
-
- // Clears the |work_queue_|.
- void Clear();
-
- // returns true if the |work_queue_| is empty.
- bool Empty() const { return work_queue_.empty(); }
-
- // If the |work_queue_| isn't empty, |enqueue_order| gets set to the enqueue
- // order of the front task and the function returns true. Otherwise the
- // function returns false.
- bool GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const;
-
- // Returns the first task in this queue or null if the queue is empty.
- const TaskQueueImpl::Task* GetFrontTask() const;
-
- // Pushes the task onto the |work_queue_| and informs the WorkQueueSets if
- // the head changed.
- void Push(const TaskQueueImpl::Task& task);
-
- // Pushes the task onto the |work_queue_|, sets the |enqueue_order| and
- // informs the WorkQueueSets if the head changed.
- void PushAndSetEnqueueOrder(const TaskQueueImpl::Task& task,
- EnqueueOrder enqueue_order);
-
- // Swap the |work_queue_| with |incoming_queue| and informs the
- // WorkQueueSets if the head changed. Assumes |task_queue_->any_thread_lock_|
- // is locked.
- void SwapLocked(std::queue<TaskQueueImpl::Task>& incoming_queue);
-
- size_t Size() const { return work_queue_.size(); }
-
- // Pulls a task off the |work_queue_| and informs the WorkQueueSets.
- TaskQueueImpl::Task TakeTaskFromWorkQueue();
-
- const char* name() const { return name_; }
-
- TaskQueueImpl* task_queue() const { return task_queue_; }
-
- WorkQueueSets* work_queue_sets() const { return work_queue_sets_; }
-
- size_t work_queue_set_index() const { return work_queue_set_index_; }
-
- // Test support function. This should not be used in production code.
- void PopTaskForTest();
-
- // Returns true if the front task in this queue has an older enqueue order
- // than the front task of |other_queue|. Both queue are assumed to be
- // non-empty.
- bool ShouldRunBefore(const WorkQueue* other_queue) const;
-
- private:
- std::queue<TaskQueueImpl::Task> work_queue_;
- WorkQueueSets* work_queue_sets_; // NOT OWNED.
- TaskQueueImpl* task_queue_; // NOT OWNED.
- size_t work_queue_set_index_;
- const char* name_;
-};
-
-} // namespace internal
-} // namespace scheduler
-
-#endif // CONTENT_RENDERER_SCHEDULER_BASE_WORK_QUEUE_H_
diff --git a/chromium/components/scheduler/base/work_queue_sets.cc b/chromium/components/scheduler/base/work_queue_sets.cc
deleted file mode 100644
index 96c5da4a01f..00000000000
--- a/chromium/components/scheduler/base/work_queue_sets.cc
+++ /dev/null
@@ -1,146 +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 "components/scheduler/base/work_queue_sets.h"
-
-#include "base/logging.h"
-#include "components/scheduler/base/work_queue.h"
-
-namespace scheduler {
-namespace internal {
-
-WorkQueueSets::WorkQueueSets(size_t num_sets, const char* name)
- : enqueue_order_to_work_queue_maps_(num_sets), name_(name) {}
-
-WorkQueueSets::~WorkQueueSets() {}
-
-void WorkQueueSets::AddQueue(WorkQueue* work_queue, size_t set_index) {
- DCHECK(!work_queue->work_queue_sets());
- DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size());
- EnqueueOrder enqueue_order;
- bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
- work_queue->AssignToWorkQueueSets(this);
- work_queue->AssignSetIndex(set_index);
- if (!has_enqueue_order)
- return;
- enqueue_order_to_work_queue_maps_[set_index].insert(
- std::make_pair(enqueue_order, work_queue));
-}
-
-void WorkQueueSets::RemoveQueue(WorkQueue* work_queue) {
- DCHECK_EQ(this, work_queue->work_queue_sets());
- EnqueueOrder enqueue_order;
- bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
- work_queue->AssignToWorkQueueSets(nullptr);
- if (!has_enqueue_order)
- return;
- size_t set_index = work_queue->work_queue_set_index();
- DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size());
- DCHECK_EQ(
- work_queue,
- enqueue_order_to_work_queue_maps_[set_index].find(enqueue_order)->second);
- enqueue_order_to_work_queue_maps_[set_index].erase(enqueue_order);
-}
-
-void WorkQueueSets::ChangeSetIndex(WorkQueue* work_queue, size_t set_index) {
- DCHECK_EQ(this, work_queue->work_queue_sets());
- DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size());
- EnqueueOrder enqueue_order;
- bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
- size_t old_set = work_queue->work_queue_set_index();
- DCHECK_LT(old_set, enqueue_order_to_work_queue_maps_.size());
- DCHECK_NE(old_set, set_index);
- work_queue->AssignSetIndex(set_index);
- if (!has_enqueue_order)
- return;
- enqueue_order_to_work_queue_maps_[old_set].erase(enqueue_order);
- enqueue_order_to_work_queue_maps_[set_index].insert(
- std::make_pair(enqueue_order, work_queue));
-}
-
-void WorkQueueSets::OnPushQueue(WorkQueue* work_queue) {
- // NOTE if this funciton changes, we need to keep |WorkQueueSets::AddQueue| in
- // sync.
- DCHECK_EQ(this, work_queue->work_queue_sets());
- EnqueueOrder enqueue_order;
- bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
- DCHECK(has_enqueue_order);
- size_t set_index = work_queue->work_queue_set_index();
- DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size())
- << " set_index = " << set_index;
- enqueue_order_to_work_queue_maps_[set_index].insert(
- std::make_pair(enqueue_order, work_queue));
-}
-
-void WorkQueueSets::OnPopQueue(WorkQueue* work_queue) {
- size_t set_index = work_queue->work_queue_set_index();
- DCHECK_EQ(this, work_queue->work_queue_sets());
- DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size());
- DCHECK(!enqueue_order_to_work_queue_maps_[set_index].empty())
- << " set_index = " << set_index;
- DCHECK_EQ(enqueue_order_to_work_queue_maps_[set_index].begin()->second,
- work_queue)
- << " set_index = " << set_index;
- // O(1) amortised.
- enqueue_order_to_work_queue_maps_[set_index].erase(
- enqueue_order_to_work_queue_maps_[set_index].begin());
- EnqueueOrder enqueue_order;
- bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
- if (!has_enqueue_order)
- return;
- enqueue_order_to_work_queue_maps_[set_index].insert(
- std::make_pair(enqueue_order, work_queue));
-}
-
-bool WorkQueueSets::GetOldestQueueInSet(size_t set_index,
- WorkQueue** out_work_queue) const {
- DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size());
- if (enqueue_order_to_work_queue_maps_[set_index].empty())
- return false;
- *out_work_queue =
- enqueue_order_to_work_queue_maps_[set_index].begin()->second;
-#ifndef NDEBUG
- EnqueueOrder enqueue_order;
- DCHECK((*out_work_queue)->GetFrontTaskEnqueueOrder(&enqueue_order));
- DCHECK_EQ(enqueue_order,
- enqueue_order_to_work_queue_maps_[set_index].begin()->first);
-#endif
- return true;
-}
-
-bool WorkQueueSets::IsSetEmpty(size_t set_index) const {
- DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size())
- << " set_index = " << set_index;
- return enqueue_order_to_work_queue_maps_[set_index].empty();
-}
-
-#if DCHECK_IS_ON() || !defined(NDEBUG)
-bool WorkQueueSets::ContainsWorkQueueForTest(
- const WorkQueue* work_queue) const {
- EnqueueOrder enqueue_order;
- bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order);
-
- for (const EnqueueOrderToWorkQueueMap& map :
- enqueue_order_to_work_queue_maps_) {
- for (const EnqueueOrderToWorkQueueMap::value_type& key_value_pair : map) {
- if (key_value_pair.second == work_queue) {
- DCHECK(has_enqueue_order);
- DCHECK_EQ(key_value_pair.first, enqueue_order);
- DCHECK_EQ(this, work_queue->work_queue_sets());
- return true;
- }
- }
- }
-
- if (work_queue->work_queue_sets() == this) {
- DCHECK(!has_enqueue_order);
- return true;
- }
-
- return false;
-}
-#endif
-
-} // namespace internal
-} // namespace scheduler
diff --git a/chromium/components/scheduler/base/work_queue_sets.h b/chromium/components/scheduler/base/work_queue_sets.h
deleted file mode 100644
index 0c2c2dcf2c1..00000000000
--- a/chromium/components/scheduler/base/work_queue_sets.h
+++ /dev/null
@@ -1,68 +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 COMPONENTS_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
-#define COMPONENTS_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
-
-#include <stddef.h>
-
-#include <map>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-namespace internal {
-class TaskQueueImpl;
-
-class SCHEDULER_EXPORT WorkQueueSets {
- public:
- WorkQueueSets(size_t num_sets, const char* name);
- ~WorkQueueSets();
-
- // O(log num queues)
- void AddQueue(WorkQueue* queue, size_t set_index);
-
- // O(log num queues)
- void RemoveQueue(WorkQueue* work_queue);
-
- // O(log num queues)
- void ChangeSetIndex(WorkQueue* queue, size_t set_index);
-
- // O(log num queues)
- void OnPushQueue(WorkQueue* work_queue);
-
- // If empty it's O(1) amortized, otherwise it's O(log num queues)
- void OnPopQueue(WorkQueue* work_queue);
-
- // O(1)
- bool GetOldestQueueInSet(size_t set_index, WorkQueue** out_work_queue) const;
-
- // O(1)
- bool IsSetEmpty(size_t set_index) const;
-
-#if DCHECK_IS_ON() || !defined(NDEBUG)
- // Note this iterates over everything in |enqueue_order_to_work_queue_maps_|.
- // It's intended for use with DCHECKS and for testing
- bool ContainsWorkQueueForTest(const WorkQueue* queue) const;
-#endif
-
- const char* name() const { return name_; }
-
- private:
- typedef std::map<EnqueueOrder, WorkQueue*> EnqueueOrderToWorkQueueMap;
- std::vector<EnqueueOrderToWorkQueueMap> enqueue_order_to_work_queue_maps_;
- const char* name_;
-
- DISALLOW_COPY_AND_ASSIGN(WorkQueueSets);
-};
-
-} // namespace internal
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
diff --git a/chromium/components/scheduler/base/work_queue_sets_unittest.cc b/chromium/components/scheduler/base/work_queue_sets_unittest.cc
deleted file mode 100644
index 4466db1f981..00000000000
--- a/chromium/components/scheduler/base/work_queue_sets_unittest.cc
+++ /dev/null
@@ -1,259 +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 "components/scheduler/base/work_queue_sets.h"
-
-#include <stddef.h>
-
-#include "base/memory/ptr_util.h"
-#include "components/scheduler/base/work_queue.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace scheduler {
-class TimeDomain;
-
-namespace internal {
-
-class WorkQueueSetsTest : public testing::Test {
- public:
- void SetUp() override {
- work_queue_sets_.reset(new WorkQueueSets(kNumSets, "test"));
- }
-
- void TearDown() override {
- for (std::unique_ptr<WorkQueue>& work_queue : work_queues_) {
- if (work_queue->work_queue_sets())
- work_queue_sets_->RemoveQueue(work_queue.get());
- }
- }
-
- protected:
- enum {
- kNumSets = 5 // An arbitary choice.
- };
-
- WorkQueue* NewTaskQueue(const char* queue_name) {
- WorkQueue* queue = new WorkQueue(nullptr, "test");
- work_queues_.push_back(base::WrapUnique(queue));
- work_queue_sets_->AddQueue(queue, TaskQueue::CONTROL_PRIORITY);
- return queue;
- }
-
- TaskQueueImpl::Task FakeTaskWithEnqueueOrder(int enqueue_order) {
- TaskQueueImpl::Task fake_task(FROM_HERE, base::Closure(), base::TimeTicks(),
- 0, true);
- fake_task.set_enqueue_order(enqueue_order);
- return fake_task;
- }
-
- std::vector<std::unique_ptr<WorkQueue>> work_queues_;
- std::unique_ptr<WorkQueueSets> work_queue_sets_;
-};
-
-TEST_F(WorkQueueSetsTest, ChangeSetIndex) {
- WorkQueue* work_queue = NewTaskQueue("queue");
- size_t set = TaskQueue::NORMAL_PRIORITY;
- work_queue_sets_->ChangeSetIndex(work_queue, set);
-
- EXPECT_EQ(set, work_queue->work_queue_set_index());
-}
-
-TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_QueueEmpty) {
- WorkQueue* work_queue = NewTaskQueue("queue");
- size_t set = TaskQueue::NORMAL_PRIORITY;
- work_queue_sets_->ChangeSetIndex(work_queue, set);
-
- WorkQueue* selected_work_queue;
- EXPECT_FALSE(
- work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
-}
-
-TEST_F(WorkQueueSetsTest, OnPushQueue) {
- WorkQueue* work_queue = NewTaskQueue("queue");
- size_t set = TaskQueue::NORMAL_PRIORITY;
- work_queue_sets_->ChangeSetIndex(work_queue, set);
-
- WorkQueue* selected_work_queue;
- EXPECT_FALSE(
- work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
-
- work_queue->Push(FakeTaskWithEnqueueOrder(10));
- work_queue_sets_->OnPushQueue(work_queue);
-
- EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
- EXPECT_EQ(work_queue, selected_work_queue);
-}
-
-TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_SingleTaskInSet) {
- WorkQueue* work_queue = NewTaskQueue("queue");
- work_queue->Push(FakeTaskWithEnqueueOrder(10));
- size_t set = 1;
- work_queue_sets_->ChangeSetIndex(work_queue, set);
-
- WorkQueue* selected_work_queue;
- EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
- EXPECT_EQ(work_queue, selected_work_queue);
-}
-
-TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_MultipleAgesInSet) {
- WorkQueue* queue1 = NewTaskQueue("queue1");
- WorkQueue* queue2 = NewTaskQueue("queue2");
- WorkQueue* queue3 = NewTaskQueue("queue2");
- queue1->Push(FakeTaskWithEnqueueOrder(6));
- queue2->Push(FakeTaskWithEnqueueOrder(5));
- queue3->Push(FakeTaskWithEnqueueOrder(4));
- size_t set = 2;
- work_queue_sets_->ChangeSetIndex(queue1, set);
- work_queue_sets_->ChangeSetIndex(queue2, set);
- work_queue_sets_->ChangeSetIndex(queue3, set);
-
- WorkQueue* selected_work_queue;
- EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
- EXPECT_EQ(queue3, selected_work_queue);
-}
-
-TEST_F(WorkQueueSetsTest, OnPopQueue) {
- WorkQueue* queue1 = NewTaskQueue("queue1");
- WorkQueue* queue2 = NewTaskQueue("queue2");
- WorkQueue* queue3 = NewTaskQueue("queue3");
- queue1->Push(FakeTaskWithEnqueueOrder(6));
- queue2->Push(FakeTaskWithEnqueueOrder(3));
- queue2->Push(FakeTaskWithEnqueueOrder(1));
- queue3->Push(FakeTaskWithEnqueueOrder(4));
- size_t set = 3;
- work_queue_sets_->ChangeSetIndex(queue1, set);
- work_queue_sets_->ChangeSetIndex(queue2, set);
- work_queue_sets_->ChangeSetIndex(queue3, set);
-
- WorkQueue* selected_work_queue;
- EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
- EXPECT_EQ(queue2, selected_work_queue);
-
- queue2->PopTaskForTest();
- work_queue_sets_->OnPopQueue(queue2);
-
- EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
- EXPECT_EQ(queue2, selected_work_queue);
-}
-
-TEST_F(WorkQueueSetsTest, OnPopQueue_QueueBecomesEmpty) {
- WorkQueue* queue1 = NewTaskQueue("queue");
- WorkQueue* queue2 = NewTaskQueue("queue");
- WorkQueue* queue3 = NewTaskQueue("queue");
- queue1->Push(FakeTaskWithEnqueueOrder(6));
- queue2->Push(FakeTaskWithEnqueueOrder(5));
- queue3->Push(FakeTaskWithEnqueueOrder(4));
- size_t set = 4;
- work_queue_sets_->ChangeSetIndex(queue1, set);
- work_queue_sets_->ChangeSetIndex(queue2, set);
- work_queue_sets_->ChangeSetIndex(queue3, set);
-
- WorkQueue* selected_work_queue;
- EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
- EXPECT_EQ(queue3, selected_work_queue);
-
- queue3->PopTaskForTest();
- work_queue_sets_->OnPopQueue(queue3);
-
- EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
- EXPECT_EQ(queue2, selected_work_queue);
-}
-
-TEST_F(WorkQueueSetsTest,
- GetOldestQueueInSet_MultipleAgesInSetIntegerRollover) {
- WorkQueue* queue1 = NewTaskQueue("queue1");
- WorkQueue* queue2 = NewTaskQueue("queue2");
- WorkQueue* queue3 = NewTaskQueue("queue3");
- queue1->Push(FakeTaskWithEnqueueOrder(0x7ffffff1));
- queue2->Push(FakeTaskWithEnqueueOrder(0x7ffffff0));
- queue3->Push(FakeTaskWithEnqueueOrder(-0x7ffffff1));
- size_t set = 1;
- work_queue_sets_->ChangeSetIndex(queue1, set);
- work_queue_sets_->ChangeSetIndex(queue2, set);
- work_queue_sets_->ChangeSetIndex(queue3, set);
-
- WorkQueue* selected_work_queue;
- EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
- EXPECT_EQ(queue2, selected_work_queue);
-}
-
-TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_MultipleAgesInSet_RemoveQueue) {
- WorkQueue* queue1 = NewTaskQueue("queue1");
- WorkQueue* queue2 = NewTaskQueue("queue2");
- WorkQueue* queue3 = NewTaskQueue("queue3");
- queue1->Push(FakeTaskWithEnqueueOrder(6));
- queue2->Push(FakeTaskWithEnqueueOrder(5));
- queue3->Push(FakeTaskWithEnqueueOrder(4));
- size_t set = 1;
- work_queue_sets_->ChangeSetIndex(queue1, set);
- work_queue_sets_->ChangeSetIndex(queue2, set);
- work_queue_sets_->ChangeSetIndex(queue3, set);
- work_queue_sets_->RemoveQueue(queue3);
-
- WorkQueue* selected_work_queue;
- EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue));
- EXPECT_EQ(queue2, selected_work_queue);
-}
-
-TEST_F(WorkQueueSetsTest, ChangeSetIndex_Complex) {
- WorkQueue* queue1 = NewTaskQueue("queue1");
- WorkQueue* queue2 = NewTaskQueue("queue2");
- WorkQueue* queue3 = NewTaskQueue("queue3");
- WorkQueue* queue4 = NewTaskQueue("queue4");
- queue1->Push(FakeTaskWithEnqueueOrder(6));
- queue2->Push(FakeTaskWithEnqueueOrder(5));
- queue3->Push(FakeTaskWithEnqueueOrder(4));
- queue4->Push(FakeTaskWithEnqueueOrder(3));
- size_t set1 = 1;
- size_t set2 = 2;
- work_queue_sets_->ChangeSetIndex(queue1, set1);
- work_queue_sets_->ChangeSetIndex(queue2, set1);
- work_queue_sets_->ChangeSetIndex(queue3, set2);
- work_queue_sets_->ChangeSetIndex(queue4, set2);
-
- WorkQueue* selected_work_queue;
- EXPECT_TRUE(
- work_queue_sets_->GetOldestQueueInSet(set1, &selected_work_queue));
- EXPECT_EQ(queue2, selected_work_queue);
-
- EXPECT_TRUE(
- work_queue_sets_->GetOldestQueueInSet(set2, &selected_work_queue));
- EXPECT_EQ(queue4, selected_work_queue);
-
- work_queue_sets_->ChangeSetIndex(queue4, set1);
-
- EXPECT_TRUE(
- work_queue_sets_->GetOldestQueueInSet(set1, &selected_work_queue));
- EXPECT_EQ(queue4, selected_work_queue);
-
- EXPECT_TRUE(
- work_queue_sets_->GetOldestQueueInSet(set2, &selected_work_queue));
- EXPECT_EQ(queue3, selected_work_queue);
-}
-
-TEST_F(WorkQueueSetsTest, IsSetEmpty_NoWork) {
- size_t set = 2;
- EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set));
-
- WorkQueue* work_queue = NewTaskQueue("queue");
- work_queue_sets_->ChangeSetIndex(work_queue, set);
- EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set));
-}
-
-TEST_F(WorkQueueSetsTest, IsSetEmpty_Work) {
- size_t set = 2;
- EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set));
-
- WorkQueue* work_queue = NewTaskQueue("queue");
- work_queue->Push(FakeTaskWithEnqueueOrder(1));
- work_queue_sets_->ChangeSetIndex(work_queue, set);
- EXPECT_FALSE(work_queue_sets_->IsSetEmpty(set));
-
- work_queue->PopTaskForTest();
- work_queue_sets_->OnPopQueue(work_queue);
- EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set));
-}
-
-} // namespace internal
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/DEPS b/chromium/components/scheduler/child/DEPS
deleted file mode 100644
index 87faf7366db..00000000000
--- a/chromium/components/scheduler/child/DEPS
+++ /dev/null
@@ -1,13 +0,0 @@
-include_rules = [
- "+components/scheduler/base",
- "+components/scheduler/scheduler_export.h",
- "+third_party/WebKit/public/platform",
-]
-
-specific_include_rules = {
- "(test_time_source|.*test)\.cc": [
- "+cc/test",
- "+content/test",
- "+components/scheduler/test",
- ],
-}
diff --git a/chromium/components/scheduler/child/OWNERS b/chromium/components/scheduler/child/OWNERS
deleted file mode 100644
index 6dc4cb43ab1..00000000000
--- a/chromium/components/scheduler/child/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-alexclarke@chromium.org
-rmcilroy@chromium.org
-skyostil@chromium.org
diff --git a/chromium/components/scheduler/child/child_scheduler.h b/chromium/components/scheduler/child/child_scheduler.h
deleted file mode 100644
index 113be648e08..00000000000
--- a/chromium/components/scheduler/child/child_scheduler.h
+++ /dev/null
@@ -1,70 +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 COMPONENTS_SCHEDULER_CHILD_CHILD_SCHEDULER_H_
-#define COMPONENTS_SCHEDULER_CHILD_CHILD_SCHEDULER_H_
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/child/single_thread_idle_task_runner.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-class MessageLoop;
-}
-
-namespace scheduler {
-class TaskQueue;
-
-class SCHEDULER_EXPORT ChildScheduler {
- public:
- virtual ~ChildScheduler() {}
-
- // Returns the default task runner.
- virtual scoped_refptr<TaskQueue> DefaultTaskRunner() = 0;
-
- // Returns the idle task runner. Tasks posted to this runner may be reordered
- // relative to other task types and may be starved for an arbitrarily long
- // time if no idle time is available.
- virtual scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() = 0;
-
- // Returns true if there is high priority work pending on the main thread
- // and the caller should yield to let the scheduler service that work. Note
- // that this is a stricter condition than |IsHighPriorityWorkAnticipated|,
- // restricted to the case where real work is pending.
- // Must be called from the thread this scheduler was created on.
- virtual bool ShouldYieldForHighPriorityWork() = 0;
-
- // Returns true if a currently running idle task could exceed its deadline
- // without impacting user experience too much. This should only be used if
- // there is a task which cannot be pre-empted and is likely to take longer
- // than the largest expected idle task deadline. It should NOT be polled to
- // check whether more work can be performed on the current idle task after
- // its deadline has expired - post a new idle task for the continuation of the
- // work in this case.
- // Must be called from the thread this scheduler was created on.
- virtual bool CanExceedIdleDeadlineIfRequired() const = 0;
-
- // Adds or removes a task observer from the scheduler. The observer will be
- // notified before and after every executed task. These functions can only be
- // called on the thread this scheduler was created on.
- virtual void AddTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) = 0;
- virtual void RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) = 0;
-
- // Shuts down the scheduler by dropping any remaining pending work in the work
- // queues. After this call any work posted to the task runners will be
- // silently dropped.
- virtual void Shutdown() = 0;
-
- protected:
- ChildScheduler() {}
- DISALLOW_COPY_AND_ASSIGN(ChildScheduler);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_CHILD_SCHEDULER_H_
diff --git a/chromium/components/scheduler/child/compositor_worker_scheduler.cc b/chromium/components/scheduler/child/compositor_worker_scheduler.cc
deleted file mode 100644
index fb2f569dbc2..00000000000
--- a/chromium/components/scheduler/child/compositor_worker_scheduler.cc
+++ /dev/null
@@ -1,166 +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 "components/scheduler/child/compositor_worker_scheduler.h"
-
-#include "base/message_loop/message_loop.h"
-#include "base/threading/thread.h"
-
-namespace scheduler {
-
-// TODO(scheduler-dev): Get rid of this asap!
-namespace {
-class CompositorWorkerTaskRunnerWrapper : public TaskQueue {
- public:
- explicit CompositorWorkerTaskRunnerWrapper(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : task_runner_(task_runner) {}
-
- // TaskQueue implementation:
- void UnregisterTaskQueue() override { NOTREACHED(); }
-
- bool RunsTasksOnCurrentThread() const override {
- return task_runner_->RunsTasksOnCurrentThread();
- }
-
- bool PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override {
- return task_runner_->PostDelayedTask(from_here, task, delay);
- }
-
- bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override {
- return task_runner_->PostNonNestableDelayedTask(from_here, task, delay);
- }
-
- void SetQueueEnabled(bool enabled) override { NOTREACHED(); }
-
- bool IsQueueEnabled() const override {
- NOTREACHED();
- return true;
- }
-
- bool IsEmpty() const override {
- NOTREACHED();
- return false;
- };
-
- bool HasPendingImmediateWork() const override {
- NOTREACHED();
- return false;
- };
-
- bool NeedsPumping() const override {
- NOTREACHED();
- return false;
- };
-
- const char* GetName() const override {
- NOTREACHED();
- return nullptr;
- };
-
- void SetQueuePriority(QueuePriority priority) override { NOTREACHED(); }
-
- QueuePriority GetQueuePriority() const override {
- NOTREACHED();
- return QueuePriority::NORMAL_PRIORITY;
- };
-
- void SetPumpPolicy(PumpPolicy pump_policy) override { NOTREACHED(); }
-
- PumpPolicy GetPumpPolicy() const override {
- NOTREACHED();
- return PumpPolicy::AUTO;
- };
-
- void PumpQueue(LazyNow*, bool may_post_dowork) override { NOTREACHED(); }
-
- void AddTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) override {
- NOTREACHED();
- }
-
- void RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) override {
- NOTREACHED();
- }
-
- void SetTimeDomain(TimeDomain* domain) override { NOTREACHED(); }
-
- TimeDomain* GetTimeDomain() const override {
- NOTREACHED();
- return nullptr;
- }
-
- void SetBlameContext(base::trace_event::BlameContext*) override {
- NOTREACHED();
- }
-
- private:
- ~CompositorWorkerTaskRunnerWrapper() override {}
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-};
-} // namespace
-
-CompositorWorkerScheduler::CompositorWorkerScheduler(base::Thread* thread)
- : thread_(thread) {}
-
-CompositorWorkerScheduler::~CompositorWorkerScheduler() {}
-
-void CompositorWorkerScheduler::Init() {}
-
-scoped_refptr<TaskQueue> CompositorWorkerScheduler::DefaultTaskRunner() {
- // TODO(sad): Implement a more robust scheduler that can do idle tasks for GC
- // without regressing performance of the rest of the system.
- return make_scoped_refptr(
- new CompositorWorkerTaskRunnerWrapper(thread_->task_runner()));
-}
-
-scoped_refptr<scheduler::SingleThreadIdleTaskRunner>
-CompositorWorkerScheduler::IdleTaskRunner() {
- // TODO(flackr): This posts idle tasks as regular tasks. We need to create
- // an idle task runner with the semantics we want for the compositor thread
- // which runs them after the current frame has been drawn before the next
- // vsync. https://crbug.com/609532
- return make_scoped_refptr(new SingleThreadIdleTaskRunner(
- thread_->task_runner(), thread_->task_runner(), this,
- "compositor.scheduler"));
-}
-
-bool CompositorWorkerScheduler::CanExceedIdleDeadlineIfRequired() const {
- return false;
-}
-
-bool CompositorWorkerScheduler::ShouldYieldForHighPriorityWork() {
- return false;
-}
-
-void CompositorWorkerScheduler::AddTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- thread_->message_loop()->AddTaskObserver(task_observer);
-}
-
-void CompositorWorkerScheduler::RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- thread_->message_loop()->RemoveTaskObserver(task_observer);
-}
-
-void CompositorWorkerScheduler::Shutdown() {}
-
-void CompositorWorkerScheduler::OnIdleTaskPosted() {}
-
-base::TimeTicks CompositorWorkerScheduler::WillProcessIdleTask() {
- // TODO(flackr): Return the next frame time as the deadline instead.
- // TODO(flackr): Ensure that oilpan GC does happen on the compositor thread
- // even though we will have no long idle periods. https://crbug.com/609531
- return base::TimeTicks::Now() + base::TimeDelta::FromMillisecondsD(16.7);
-}
-
-void CompositorWorkerScheduler::DidProcessIdleTask() {}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/compositor_worker_scheduler.h b/chromium/components/scheduler/child/compositor_worker_scheduler.h
deleted file mode 100644
index 46e70468cf2..00000000000
--- a/chromium/components/scheduler/child/compositor_worker_scheduler.h
+++ /dev/null
@@ -1,53 +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 COMPONENTS_SCHEDULER_CHILD_COMPOSITOR_WORKER_SCHEDULER_H_
-#define COMPONENTS_SCHEDULER_CHILD_COMPOSITOR_WORKER_SCHEDULER_H_
-
-#include "base/macros.h"
-#include "components/scheduler/child/single_thread_idle_task_runner.h"
-#include "components/scheduler/child/worker_scheduler.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-class Thread;
-}
-
-namespace scheduler {
-
-class SCHEDULER_EXPORT CompositorWorkerScheduler
- : public WorkerScheduler,
- public SingleThreadIdleTaskRunner::Delegate {
- public:
- explicit CompositorWorkerScheduler(base::Thread* thread);
- ~CompositorWorkerScheduler() override;
-
- // WorkerScheduler:
- void Init() override;
-
- // ChildScheduler:
- scoped_refptr<TaskQueue> DefaultTaskRunner() override;
- scoped_refptr<scheduler::SingleThreadIdleTaskRunner> IdleTaskRunner()
- override;
- bool ShouldYieldForHighPriorityWork() override;
- bool CanExceedIdleDeadlineIfRequired() const override;
- void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override;
- void RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) override;
- void Shutdown() override;
-
- // SingleThreadIdleTaskRunner::Delegate:
- void OnIdleTaskPosted() override;
- base::TimeTicks WillProcessIdleTask() override;
- void DidProcessIdleTask() override;
-
- private:
- base::Thread* thread_;
-
- DISALLOW_COPY_AND_ASSIGN(CompositorWorkerScheduler);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_COMPOSITOR_WORKER_SCHEDULER_H_
diff --git a/chromium/components/scheduler/child/idle_helper.cc b/chromium/components/scheduler/child/idle_helper.cc
deleted file mode 100644
index 0f6c82f6ac8..00000000000
--- a/chromium/components/scheduler/child/idle_helper.cc
+++ /dev/null
@@ -1,486 +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 "components/scheduler/child/idle_helper.h"
-
-#include "base/time/time.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "components/scheduler/base/real_time_domain.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/base/task_queue_manager.h"
-#include "components/scheduler/child/scheduler_helper.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-
-namespace scheduler {
-
-IdleHelper::IdleHelper(
- SchedulerHelper* helper,
- Delegate* delegate,
- const char* tracing_category,
- const char* disabled_by_default_tracing_category,
- const char* idle_period_tracing_name,
- base::TimeDelta required_quiescence_duration_before_long_idle_period)
- : helper_(helper),
- delegate_(delegate),
- idle_queue_(
- helper_->NewTaskQueue(TaskQueue::Spec("idle_tq").SetPumpPolicy(
- TaskQueue::PumpPolicy::MANUAL))),
- state_(helper,
- delegate,
- tracing_category,
- disabled_by_default_tracing_category,
- idle_period_tracing_name),
- required_quiescence_duration_before_long_idle_period_(
- required_quiescence_duration_before_long_idle_period),
- disabled_by_default_tracing_category_(
- disabled_by_default_tracing_category),
- weak_factory_(this) {
- weak_idle_helper_ptr_ = weak_factory_.GetWeakPtr();
- enable_next_long_idle_period_closure_.Reset(
- base::Bind(&IdleHelper::EnableLongIdlePeriod, weak_idle_helper_ptr_));
- on_idle_task_posted_closure_.Reset(base::Bind(
- &IdleHelper::OnIdleTaskPostedOnMainThread, weak_idle_helper_ptr_));
-
- idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner(
- idle_queue_, helper_->ControlAfterWakeUpTaskRunner(), this,
- tracing_category));
-
- idle_queue_->SetQueueEnabled(false);
- idle_queue_->SetQueuePriority(TaskQueue::BEST_EFFORT_PRIORITY);
-
- helper_->AddTaskObserver(this);
-}
-
-IdleHelper::~IdleHelper() {
- helper_->RemoveTaskObserver(this);
-}
-
-IdleHelper::Delegate::Delegate() {
-}
-
-IdleHelper::Delegate::~Delegate() {
-}
-
-scoped_refptr<SingleThreadIdleTaskRunner> IdleHelper::IdleTaskRunner() {
- helper_->CheckOnValidThread();
- return idle_task_runner_;
-}
-
-IdleHelper::IdlePeriodState IdleHelper::ComputeNewLongIdlePeriodState(
- const base::TimeTicks now,
- base::TimeDelta* next_long_idle_period_delay_out) {
- helper_->CheckOnValidThread();
-
- if (!delegate_->CanEnterLongIdlePeriod(now,
- next_long_idle_period_delay_out)) {
- return IdlePeriodState::NOT_IN_IDLE_PERIOD;
- }
-
- base::TimeTicks next_pending_delayed_task;
- base::TimeDelta max_long_idle_period_duration =
- base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis);
- base::TimeDelta long_idle_period_duration;
- if (helper_->real_time_domain()->NextScheduledRunTime(
- &next_pending_delayed_task)) {
- // Limit the idle period duration to be before the next pending task.
- long_idle_period_duration = std::min(next_pending_delayed_task - now,
- max_long_idle_period_duration);
- } else {
- long_idle_period_duration = max_long_idle_period_duration;
- }
-
- if (long_idle_period_duration >=
- base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) {
- *next_long_idle_period_delay_out = long_idle_period_duration;
- if (!idle_queue_->HasPendingImmediateWork()) {
- return IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED;
- } else if (long_idle_period_duration == max_long_idle_period_duration) {
- return IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE;
- } else {
- return IdlePeriodState::IN_LONG_IDLE_PERIOD;
- }
- } else {
- // If we can't start the idle period yet then try again after wakeup.
- *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds(
- kRetryEnableLongIdlePeriodDelayMillis);
- return IdlePeriodState::NOT_IN_IDLE_PERIOD;
- }
-}
-
-bool IdleHelper::ShouldWaitForQuiescence() {
- helper_->CheckOnValidThread();
-
- if (helper_->IsShutdown())
- return false;
-
- if (required_quiescence_duration_before_long_idle_period_ ==
- base::TimeDelta())
- return false;
-
- bool system_is_quiescent = helper_->GetAndClearSystemIsQuiescentBit();
- TRACE_EVENT1(disabled_by_default_tracing_category_, "ShouldWaitForQuiescence",
- "system_is_quiescent", system_is_quiescent);
- return !system_is_quiescent;
-}
-
-void IdleHelper::EnableLongIdlePeriod() {
- TRACE_EVENT0(disabled_by_default_tracing_category_, "EnableLongIdlePeriod");
- helper_->CheckOnValidThread();
- if (helper_->IsShutdown())
- return;
-
- // End any previous idle period.
- EndIdlePeriod();
-
- if (ShouldWaitForQuiescence()) {
- helper_->ControlTaskRunner()->PostDelayedTask(
- FROM_HERE, enable_next_long_idle_period_closure_.callback(),
- required_quiescence_duration_before_long_idle_period_);
- delegate_->IsNotQuiescent();
- return;
- }
-
- base::TimeTicks now(helper_->scheduler_tqm_delegate()->NowTicks());
- base::TimeDelta next_long_idle_period_delay;
- IdlePeriodState new_idle_period_state =
- ComputeNewLongIdlePeriodState(now, &next_long_idle_period_delay);
- if (IsInIdlePeriod(new_idle_period_state)) {
- StartIdlePeriod(new_idle_period_state, now,
- now + next_long_idle_period_delay);
- } else {
- // Otherwise wait for the next long idle period delay before trying again.
- helper_->ControlTaskRunner()->PostDelayedTask(
- FROM_HERE, enable_next_long_idle_period_closure_.callback(),
- next_long_idle_period_delay);
- }
-}
-
-void IdleHelper::StartIdlePeriod(IdlePeriodState new_state,
- base::TimeTicks now,
- base::TimeTicks idle_period_deadline) {
- DCHECK_GT(idle_period_deadline, now);
- helper_->CheckOnValidThread();
- DCHECK(IsInIdlePeriod(new_state));
-
- base::TimeDelta idle_period_duration(idle_period_deadline - now);
- if (idle_period_duration <
- base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) {
- TRACE_EVENT1(disabled_by_default_tracing_category_,
- "NotStartingIdlePeriodBecauseDeadlineIsTooClose",
- "idle_period_duration_ms",
- idle_period_duration.InMillisecondsF());
- return;
- }
-
- TRACE_EVENT0(disabled_by_default_tracing_category_, "StartIdlePeriod");
- idle_queue_->SetQueueEnabled(true);
- LazyNow lazy_now(now);
- idle_queue_->PumpQueue(&lazy_now, true);
-
- state_.UpdateState(new_state, idle_period_deadline, now);
-}
-
-void IdleHelper::EndIdlePeriod() {
- helper_->CheckOnValidThread();
- TRACE_EVENT0(disabled_by_default_tracing_category_, "EndIdlePeriod");
-
- enable_next_long_idle_period_closure_.Cancel();
- on_idle_task_posted_closure_.Cancel();
-
- // If we weren't already within an idle period then early-out.
- if (!IsInIdlePeriod(state_.idle_period_state()))
- return;
-
- idle_queue_->SetQueueEnabled(false);
- state_.UpdateState(IdlePeriodState::NOT_IN_IDLE_PERIOD, base::TimeTicks(),
- base::TimeTicks());
-}
-
-void IdleHelper::WillProcessTask(const base::PendingTask& pending_task) {
-}
-
-void IdleHelper::DidProcessTask(const base::PendingTask& pending_task) {
- helper_->CheckOnValidThread();
- TRACE_EVENT0(disabled_by_default_tracing_category_, "DidProcessTask");
- if (IsInIdlePeriod(state_.idle_period_state()) &&
- state_.idle_period_state() !=
- IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED &&
- helper_->scheduler_tqm_delegate()->NowTicks() >=
- state_.idle_period_deadline()) {
- // If the idle period deadline has now been reached, either end the idle
- // period or trigger a new long-idle period.
- if (IsInLongIdlePeriod(state_.idle_period_state())) {
- EnableLongIdlePeriod();
- } else {
- DCHECK(IdlePeriodState::IN_SHORT_IDLE_PERIOD ==
- state_.idle_period_state());
- EndIdlePeriod();
- }
- }
-}
-
-void IdleHelper::UpdateLongIdlePeriodStateAfterIdleTask() {
- helper_->CheckOnValidThread();
- DCHECK(IsInLongIdlePeriod(state_.idle_period_state()));
- TRACE_EVENT0(disabled_by_default_tracing_category_,
- "UpdateLongIdlePeriodStateAfterIdleTask");
-
- if (!idle_queue_->HasPendingImmediateWork()) {
- // If there are no more idle tasks then pause long idle period ticks until a
- // new idle task is posted.
- state_.UpdateState(IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED,
- state_.idle_period_deadline(), base::TimeTicks());
- } else if (idle_queue_->NeedsPumping()) {
- // If there is still idle work to do then just start the next idle period.
- base::TimeDelta next_long_idle_period_delay;
- if (state_.idle_period_state() ==
- IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE) {
- // If we are in a max deadline long idle period then start the next
- // idle period immediately.
- next_long_idle_period_delay = base::TimeDelta();
- } else {
- // Otherwise ensure that we kick the scheduler at the right time to
- // initiate the next idle period.
- next_long_idle_period_delay = std::max(
- base::TimeDelta(), state_.idle_period_deadline() -
- helper_->scheduler_tqm_delegate()->NowTicks());
- }
- if (next_long_idle_period_delay.is_zero()) {
- EnableLongIdlePeriod();
- } else {
- helper_->ControlTaskRunner()->PostDelayedTask(
- FROM_HERE, enable_next_long_idle_period_closure_.callback(),
- next_long_idle_period_delay);
- }
- }
-}
-
-base::TimeTicks IdleHelper::CurrentIdleTaskDeadline() const {
- helper_->CheckOnValidThread();
- return state_.idle_period_deadline();
-}
-
-void IdleHelper::OnIdleTaskPosted() {
- TRACE_EVENT0(disabled_by_default_tracing_category_, "OnIdleTaskPosted");
- if (idle_task_runner_->RunsTasksOnCurrentThread()) {
- OnIdleTaskPostedOnMainThread();
- } else {
- helper_->ControlTaskRunner()->PostTask(
- FROM_HERE, on_idle_task_posted_closure_.callback());
- }
-}
-
-void IdleHelper::OnIdleTaskPostedOnMainThread() {
- TRACE_EVENT0(disabled_by_default_tracing_category_,
- "OnIdleTaskPostedOnMainThread");
- if (state_.idle_period_state() ==
- IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) {
- // Restart long idle period ticks.
- helper_->ControlTaskRunner()->PostTask(
- FROM_HERE, enable_next_long_idle_period_closure_.callback());
- }
-}
-
-base::TimeTicks IdleHelper::WillProcessIdleTask() {
- helper_->CheckOnValidThread();
- state_.TraceIdleIdleTaskStart();
- return CurrentIdleTaskDeadline();
-}
-
-void IdleHelper::DidProcessIdleTask() {
- helper_->CheckOnValidThread();
- state_.TraceIdleIdleTaskEnd();
- if (IsInLongIdlePeriod(state_.idle_period_state())) {
- UpdateLongIdlePeriodStateAfterIdleTask();
- }
-}
-
-// static
-bool IdleHelper::IsInIdlePeriod(IdlePeriodState state) {
- return state != IdlePeriodState::NOT_IN_IDLE_PERIOD;
-}
-
-// static
-bool IdleHelper::IsInLongIdlePeriod(IdlePeriodState state) {
- return state == IdlePeriodState::IN_LONG_IDLE_PERIOD ||
- state == IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE ||
- state == IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED;
-}
-
-bool IdleHelper::CanExceedIdleDeadlineIfRequired() const {
- TRACE_EVENT0(disabled_by_default_tracing_category_,
- "CanExceedIdleDeadlineIfRequired");
- helper_->CheckOnValidThread();
- return state_.idle_period_state() ==
- IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE;
-}
-
-IdleHelper::IdlePeriodState IdleHelper::SchedulerIdlePeriodState() const {
- return state_.idle_period_state();
-}
-
-IdleHelper::State::State(SchedulerHelper* helper,
- Delegate* delegate,
- const char* tracing_category,
- const char* disabled_by_default_tracing_category,
- const char* idle_period_tracing_name)
- : helper_(helper),
- delegate_(delegate),
- idle_period_state_(IdlePeriodState::NOT_IN_IDLE_PERIOD),
- idle_period_trace_event_started_(false),
- running_idle_task_for_tracing_(false),
- tracing_category_(tracing_category),
- disabled_by_default_tracing_category_(
- disabled_by_default_tracing_category),
- idle_period_tracing_name_(idle_period_tracing_name) {
-}
-
-IdleHelper::State::~State() {
-}
-
-IdleHelper::IdlePeriodState IdleHelper::State::idle_period_state() const {
- helper_->CheckOnValidThread();
- return idle_period_state_;
-}
-
-base::TimeTicks IdleHelper::State::idle_period_deadline() const {
- helper_->CheckOnValidThread();
- return idle_period_deadline_;
-}
-
-void IdleHelper::State::UpdateState(IdlePeriodState new_state,
- base::TimeTicks new_deadline,
- base::TimeTicks optional_now) {
- IdlePeriodState old_idle_period_state = idle_period_state_;
-
- helper_->CheckOnValidThread();
- if (new_state == idle_period_state_) {
- DCHECK_EQ(new_deadline, idle_period_deadline_);
- return;
- }
-
- bool is_tracing;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing);
- if (is_tracing) {
- base::TimeTicks now(optional_now.is_null()
- ? helper_->scheduler_tqm_delegate()->NowTicks()
- : optional_now);
- TraceEventIdlePeriodStateChange(
- new_state, running_idle_task_for_tracing_, idle_period_deadline_, now);
- }
-
- idle_period_state_ = new_state;
- idle_period_deadline_ = new_deadline;
-
- // Inform the delegate if we are starting or ending an idle period.
- if (IsInIdlePeriod(new_state) && !IsInIdlePeriod(old_idle_period_state)) {
- delegate_->OnIdlePeriodStarted();
- } else if (!IsInIdlePeriod(new_state) &&
- IsInIdlePeriod(old_idle_period_state)) {
- delegate_->OnIdlePeriodEnded();
- }
-}
-
-void IdleHelper::State::TraceIdleIdleTaskStart() {
- helper_->CheckOnValidThread();
-
- bool is_tracing;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing);
- if (is_tracing) {
- TraceEventIdlePeriodStateChange(
- idle_period_state_, true, idle_period_deadline_,
- base::TimeTicks::Now());
- }
-}
-
-void IdleHelper::State::TraceIdleIdleTaskEnd() {
- helper_->CheckOnValidThread();
-
- bool is_tracing;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing);
- if (is_tracing) {
- TraceEventIdlePeriodStateChange(
- idle_period_state_, false, idle_period_deadline_,
- base::TimeTicks::Now());
- }
-}
-
-void IdleHelper::State::TraceEventIdlePeriodStateChange(
- IdlePeriodState new_state,
- bool new_running_idle_task,
- base::TimeTicks new_deadline,
- base::TimeTicks now) {
- TRACE_EVENT2(disabled_by_default_tracing_category_, "SetIdlePeriodState",
- "old_state",
- IdleHelper::IdlePeriodStateToString(idle_period_state_),
- "new_state", IdleHelper::IdlePeriodStateToString(new_state));
-
- if (idle_period_trace_event_started_ && running_idle_task_for_tracing_ &&
- !new_running_idle_task) {
- running_idle_task_for_tracing_ = false;
- if (!idle_period_deadline_.is_null() && now > idle_period_deadline_) {
- TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(
- tracing_category_, idle_period_tracing_name_, this,
- "DeadlineOverrun",
- std::max(idle_period_deadline_,
- last_idle_task_trace_time_).ToInternalValue());
- }
- }
-
- if (IsInIdlePeriod(new_state)) {
- if (!idle_period_trace_event_started_) {
- idle_period_trace_event_started_ = true;
- TRACE_EVENT_ASYNC_BEGIN1(
- tracing_category_, idle_period_tracing_name_, this,
- "idle_period_length_ms", (new_deadline - now).ToInternalValue());
- }
-
- if (new_running_idle_task) {
- last_idle_task_trace_time_ = now;
- running_idle_task_for_tracing_ = true;
- TRACE_EVENT_ASYNC_STEP_INTO0(
- tracing_category_, idle_period_tracing_name_, this,
- "RunningIdleTask");
- } else if (new_state == IdlePeriodState::IN_SHORT_IDLE_PERIOD) {
- TRACE_EVENT_ASYNC_STEP_INTO0(
- tracing_category_, idle_period_tracing_name_, this,
- "ShortIdlePeriod");
- } else if (IsInLongIdlePeriod(new_state) &&
- new_state != IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) {
- TRACE_EVENT_ASYNC_STEP_INTO0(
- tracing_category_, idle_period_tracing_name_, this,
- "LongIdlePeriod");
- } else if (new_state == IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) {
- TRACE_EVENT_ASYNC_STEP_INTO0(
- tracing_category_, idle_period_tracing_name_, this,
- "LongIdlePeriodPaused");
- }
- } else if (idle_period_trace_event_started_) {
- idle_period_trace_event_started_ = false;
- TRACE_EVENT_ASYNC_END0(tracing_category_, idle_period_tracing_name_, this);
- }
-}
-
-// static
-const char* IdleHelper::IdlePeriodStateToString(
- IdlePeriodState idle_period_state) {
- switch (idle_period_state) {
- case IdlePeriodState::NOT_IN_IDLE_PERIOD:
- return "not_in_idle_period";
- case IdlePeriodState::IN_SHORT_IDLE_PERIOD:
- return "in_short_idle_period";
- case IdlePeriodState::IN_LONG_IDLE_PERIOD:
- return "in_long_idle_period";
- case IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE:
- return "in_long_idle_period_with_max_deadline";
- case IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED:
- return "in_long_idle_period_paused";
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/idle_helper.h b/chromium/components/scheduler/child/idle_helper.h
deleted file mode 100644
index 333c8674a36..00000000000
--- a/chromium/components/scheduler/child/idle_helper.h
+++ /dev/null
@@ -1,221 +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 COMPONENTS_SCHEDULER_CHILD_IDLE_HELPER_H_
-#define COMPONENTS_SCHEDULER_CHILD_IDLE_HELPER_H_
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "components/scheduler/base/cancelable_closure_holder.h"
-#include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/child/scheduler_helper.h"
-#include "components/scheduler/child/single_thread_idle_task_runner.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-class SchedulerHelper;
-
-// Common scheduler functionality for Idle tasks.
-class SCHEDULER_EXPORT IdleHelper
- : public base::MessageLoop::TaskObserver,
- public SingleThreadIdleTaskRunner::Delegate {
- public:
- // Used to by scheduler implementations to customize idle behaviour.
- class SCHEDULER_EXPORT Delegate {
- public:
- Delegate();
- virtual ~Delegate();
-
- // If it's ok to enter a long idle period, return true. Otherwise return
- // false and set next_long_idle_period_delay_out so we know when to try
- // again.
- virtual bool CanEnterLongIdlePeriod(
- base::TimeTicks now,
- base::TimeDelta* next_long_idle_period_delay_out) = 0;
-
- // Signals that the Long Idle Period hasn't started yet because the system
- // isn't quiescent.
- virtual void IsNotQuiescent() = 0;
-
- // Signals that we have started an Idle Period.
- virtual void OnIdlePeriodStarted() = 0;
-
- // Signals that we have finished an Idle Period.
- virtual void OnIdlePeriodEnded() = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Delegate);
- };
-
- // Keep IdleHelper::IdlePeriodStateToString in sync with this enum.
- enum class IdlePeriodState {
- NOT_IN_IDLE_PERIOD,
- IN_SHORT_IDLE_PERIOD,
- IN_LONG_IDLE_PERIOD,
- IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE,
- IN_LONG_IDLE_PERIOD_PAUSED,
- // Must be the last entry.
- IDLE_PERIOD_STATE_COUNT,
- FIRST_IDLE_PERIOD_STATE = NOT_IN_IDLE_PERIOD,
- };
-
- // The maximum length of an idle period.
- static const int kMaximumIdlePeriodMillis = 50;
-
- // |helper| and |delegate| are not owned by IdleHelper object and must
- // outlive it.
- IdleHelper(
- SchedulerHelper* helper,
- Delegate* delegate,
- const char* tracing_category,
- const char* disabled_by_default_tracing_category,
- const char* idle_period_tracing_name,
- base::TimeDelta required_quiescence_duration_before_long_idle_period);
- ~IdleHelper() override;
-
- // Returns the idle task runner. Tasks posted to this runner may be reordered
- // relative to other task types and may be starved for an arbitrarily long
- // time if no idle time is available.
- scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner();
-
- // If |required_quiescence_duration_before_long_idle_period_| is zero then
- // immediately initiate a long idle period, otherwise check if any tasks have
- // run recently and if so, check again after a delay of
- // |required_quiescence_duration_before_long_idle_period_|.
- // Calling this function will end any previous idle period immediately, and
- // potentially again later if
- // |required_quiescence_duration_before_long_idle_period_| is non-zero.
- // NOTE EndIdlePeriod will disable the long idle periods.
- void EnableLongIdlePeriod();
-
- // Start an idle period with a given idle period deadline.
- void StartIdlePeriod(IdlePeriodState new_idle_period_state,
- base::TimeTicks now,
- base::TimeTicks idle_period_deadline);
-
- // This will end an idle period either started with StartIdlePeriod or
- // EnableLongIdlePeriod.
- void EndIdlePeriod();
-
- // Returns true if a currently running idle task could exceed its deadline
- // without impacting user experience too much. This should only be used if
- // there is a task which cannot be pre-empted and is likely to take longer
- // than the largest expected idle task deadline. It should NOT be polled to
- // check whether more work can be performed on the current idle task after
- // its deadline has expired - post a new idle task for the continuation of the
- // work in this case.
- // Must be called from the thread this class was created on.
- bool CanExceedIdleDeadlineIfRequired() const;
-
- // Returns the deadline for the current idle task.
- base::TimeTicks CurrentIdleTaskDeadline() const;
-
- // SingleThreadIdleTaskRunner::Delegate implementation:
- void OnIdleTaskPosted() override;
- base::TimeTicks WillProcessIdleTask() override;
- void DidProcessIdleTask() override;
-
- // base::MessageLoop::TaskObserver implementation:
- void WillProcessTask(const base::PendingTask& pending_task) override;
- void DidProcessTask(const base::PendingTask& pending_task) override;
-
- IdlePeriodState SchedulerIdlePeriodState() const;
- static const char* IdlePeriodStateToString(IdlePeriodState state);
-
- private:
- friend class BaseIdleHelperTest;
- friend class IdleHelperTest;
-
- class State {
- public:
- State(SchedulerHelper* helper,
- Delegate* delegate,
- const char* tracing_category,
- const char* disabled_by_default_tracing_category,
- const char* idle_period_tracing_name);
- virtual ~State();
-
- void UpdateState(IdlePeriodState new_state,
- base::TimeTicks new_deadline,
- base::TimeTicks optional_now);
- bool IsIdlePeriodPaused() const;
-
- IdlePeriodState idle_period_state() const;
- base::TimeTicks idle_period_deadline() const;
-
- void TraceIdleIdleTaskStart();
- void TraceIdleIdleTaskEnd();
-
- private:
- void TraceEventIdlePeriodStateChange(IdlePeriodState new_state,
- bool new_running_idle_task,
- base::TimeTicks new_deadline,
- base::TimeTicks optional_now);
-
- SchedulerHelper* helper_; // NOT OWNED
- Delegate* delegate_; // NOT OWNED
-
- IdlePeriodState idle_period_state_;
- base::TimeTicks idle_period_deadline_;
-
- base::TimeTicks last_idle_task_trace_time_;
- bool idle_period_trace_event_started_;
- bool running_idle_task_for_tracing_;
- const char* tracing_category_;
- const char* disabled_by_default_tracing_category_;
- const char* idle_period_tracing_name_;
-
- DISALLOW_COPY_AND_ASSIGN(State);
- };
-
- // The minimum duration of an idle period.
- static const int kMinimumIdlePeriodDurationMillis = 1;
-
- // The minimum delay to wait between retrying to initiate a long idle time.
- static const int kRetryEnableLongIdlePeriodDelayMillis = 1;
-
- // Returns the new idle period state for the next long idle period. Fills in
- // |next_long_idle_period_delay_out| with the next time we should try to
- // initiate the next idle period.
- IdlePeriodState ComputeNewLongIdlePeriodState(
- const base::TimeTicks now,
- base::TimeDelta* next_long_idle_period_delay_out);
-
- bool ShouldWaitForQuiescence();
- void OnIdleTaskPostedOnMainThread();
- void UpdateLongIdlePeriodStateAfterIdleTask();
-
- void SetIdlePeriodState(IdlePeriodState new_state,
- base::TimeTicks new_deadline,
- base::TimeTicks optional_now);
-
- // Returns true if |state| represents being within an idle period state.
- static bool IsInIdlePeriod(IdlePeriodState state);
- // Returns true if |state| represents being within a long idle period state.
- static bool IsInLongIdlePeriod(IdlePeriodState state);
-
- SchedulerHelper* helper_; // NOT OWNED
- Delegate* delegate_; // NOT OWNED
- scoped_refptr<TaskQueue> idle_queue_;
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
-
- CancelableClosureHolder enable_next_long_idle_period_closure_;
- CancelableClosureHolder on_idle_task_posted_closure_;
-
- State state_;
-
- base::TimeDelta required_quiescence_duration_before_long_idle_period_;
-
- const char* disabled_by_default_tracing_category_;
-
- base::WeakPtr<IdleHelper> weak_idle_helper_ptr_;
- base::WeakPtrFactory<IdleHelper> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(IdleHelper);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_IDLE_HELPER_H_
diff --git a/chromium/components/scheduler/child/idle_helper_unittest.cc b/chromium/components/scheduler/child/idle_helper_unittest.cc
deleted file mode 100644
index 3624ba0fe95..00000000000
--- a/chromium/components/scheduler/child/idle_helper_unittest.cc
+++ /dev/null
@@ -1,1159 +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 "components/scheduler/child/idle_helper.h"
-
-#include <utility>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/real_time_domain.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/base/task_queue_manager.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/child/scheduler_helper.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_impl.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::AnyNumber;
-using testing::AtLeast;
-using testing::Exactly;
-using testing::Invoke;
-using testing::Return;
-
-namespace scheduler {
-
-namespace {
-void AppendToVectorTestTask(std::vector<std::string>* vector,
- std::string value) {
- vector->push_back(value);
-}
-
-void AppendToVectorIdleTestTask(std::vector<std::string>* vector,
- std::string value,
- base::TimeTicks deadline) {
- AppendToVectorTestTask(vector, value);
-}
-
-void NullTask() {
-}
-
-void NullIdleTask(base::TimeTicks deadline) {
-}
-
-void AppendToVectorReentrantTask(base::SingleThreadTaskRunner* task_runner,
- std::vector<int>* vector,
- int* reentrant_count,
- int max_reentrant_count) {
- vector->push_back((*reentrant_count)++);
- if (*reentrant_count < max_reentrant_count) {
- task_runner->PostTask(
- FROM_HERE,
- base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner),
- vector, reentrant_count, max_reentrant_count));
- }
-}
-
-void IdleTestTask(int* run_count,
- base::TimeTicks* deadline_out,
- base::TimeTicks deadline) {
- (*run_count)++;
- *deadline_out = deadline;
-}
-
-int max_idle_task_reposts = 2;
-
-void RepostingIdleTestTask(SingleThreadIdleTaskRunner* idle_task_runner,
- int* run_count,
- base::TimeTicks* deadline_out,
- base::TimeTicks deadline) {
- if ((*run_count + 1) < max_idle_task_reposts) {
- idle_task_runner->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingIdleTestTask, base::Unretained(idle_task_runner),
- run_count, deadline_out));
- }
- *deadline_out = deadline;
- (*run_count)++;
-}
-
-void RepostingUpdateClockIdleTestTask(
- SingleThreadIdleTaskRunner* idle_task_runner,
- int* run_count,
- base::SimpleTestTickClock* clock,
- base::TimeDelta advance_time,
- std::vector<base::TimeTicks>* deadlines,
- base::TimeTicks deadline) {
- if ((*run_count + 1) < max_idle_task_reposts) {
- idle_task_runner->PostIdleTask(
- FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask,
- base::Unretained(idle_task_runner), run_count,
- clock, advance_time, deadlines));
- }
- deadlines->push_back(deadline);
- (*run_count)++;
- clock->Advance(advance_time);
-}
-
-void RepeatingTask(base::SingleThreadTaskRunner* task_runner,
- int num_repeats,
- base::TimeDelta delay) {
- if (num_repeats > 1) {
- task_runner->PostDelayedTask(
- FROM_HERE, base::Bind(&RepeatingTask, base::Unretained(task_runner),
- num_repeats - 1, delay),
- delay);
- }
-}
-
-void UpdateClockIdleTestTask(base::SimpleTestTickClock* clock,
- int* run_count,
- base::TimeTicks set_time,
- base::TimeTicks deadline) {
- clock->Advance(set_time - clock->NowTicks());
- (*run_count)++;
-}
-
-void UpdateClockToDeadlineIdleTestTask(base::SimpleTestTickClock* clock,
- int* run_count,
- base::TimeTicks deadline) {
- UpdateClockIdleTestTask(clock, run_count, deadline, deadline);
-}
-
-void EndIdlePeriodIdleTask(IdleHelper* idle_helper, base::TimeTicks deadline) {
- idle_helper->EndIdlePeriod();
-}
-
-scoped_refptr<SchedulerTqmDelegate> CreateTaskRunnerDelegate(
- base::MessageLoop* message_loop,
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner,
- std::unique_ptr<TestTimeSource> test_time_source) {
- if (message_loop)
- return SchedulerTqmDelegateImpl::Create(message_loop,
- std::move(test_time_source));
-
- return SchedulerTqmDelegateForTest::Create(mock_task_runner,
- std::move(test_time_source));
-}
-
-}; // namespace
-
-class IdleHelperForTest : public IdleHelper, public IdleHelper::Delegate {
- public:
- explicit IdleHelperForTest(
- SchedulerHelper* scheduler_helper,
- base::TimeDelta required_quiescence_duration_before_long_idle_period)
- : IdleHelper(scheduler_helper,
- this,
- "test.idle",
- TRACE_DISABLED_BY_DEFAULT("test.idle"),
- "TestSchedulerIdlePeriod",
- required_quiescence_duration_before_long_idle_period) {}
-
- ~IdleHelperForTest() override {}
-
- // SchedulerHelperDelegate implementation:
- MOCK_METHOD2(CanEnterLongIdlePeriod,
- bool(base::TimeTicks now,
- base::TimeDelta* next_long_idle_period_delay_out));
-
- MOCK_METHOD0(IsNotQuiescent, void());
- MOCK_METHOD0(OnIdlePeriodStarted, void());
- MOCK_METHOD0(OnIdlePeriodEnded, void());
-};
-
-class BaseIdleHelperTest : public testing::Test {
- public:
- BaseIdleHelperTest(
- base::MessageLoop* message_loop,
- base::TimeDelta required_quiescence_duration_before_long_idle_period)
- : clock_(new base::SimpleTestTickClock()),
- mock_task_runner_(
- message_loop
- ? nullptr
- : new cc::OrderedSimpleTaskRunner(clock_.get(), false)),
- message_loop_(message_loop),
- main_task_runner_(CreateTaskRunnerDelegate(
- message_loop,
- mock_task_runner_,
- base::WrapUnique(new TestTimeSource(clock_.get())))),
- scheduler_helper_(
- new SchedulerHelper(main_task_runner_,
- "test.idle",
- TRACE_DISABLED_BY_DEFAULT("test.idle"),
- TRACE_DISABLED_BY_DEFAULT("test.idle.debug"))),
- idle_helper_(new IdleHelperForTest(
- scheduler_helper_.get(),
- required_quiescence_duration_before_long_idle_period)),
- default_task_runner_(scheduler_helper_->DefaultTaskRunner()),
- idle_task_runner_(idle_helper_->IdleTaskRunner()) {
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- }
-
- ~BaseIdleHelperTest() override {}
-
- void SetUp() override {
- EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber());
- EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(AnyNumber());
- EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _))
- .Times(AnyNumber())
- .WillRepeatedly(Return(true));
- }
-
- void TearDown() override {
- DCHECK(!mock_task_runner_.get() || !message_loop_.get());
- if (mock_task_runner_.get()) {
- // Check that all tests stop posting tasks.
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- while (mock_task_runner_->RunUntilIdle()) {
- }
- } else {
- message_loop_->RunUntilIdle();
- }
- }
-
- void RunUntilIdle() {
- // Only one of mock_task_runner_ or message_loop_ should be set.
- DCHECK(!mock_task_runner_.get() || !message_loop_.get());
- if (mock_task_runner_.get())
- mock_task_runner_->RunUntilIdle();
- else
- message_loop_->RunUntilIdle();
- }
-
- template <typename E>
- static void CallForEachEnumValue(E first,
- E last,
- const char* (*function)(E)) {
- for (E val = first; val < last;
- val = static_cast<E>(static_cast<int>(val) + 1)) {
- (*function)(val);
- }
- }
-
- static void CheckAllTaskQueueIdToString() {
- CallForEachEnumValue<IdleHelper::IdlePeriodState>(
- IdleHelper::IdlePeriodState::FIRST_IDLE_PERIOD_STATE,
- IdleHelper::IdlePeriodState::IDLE_PERIOD_STATE_COUNT,
- &IdleHelper::IdlePeriodStateToString);
- }
-
- bool IsInIdlePeriod() const {
- return idle_helper_->IsInIdlePeriod(
- idle_helper_->SchedulerIdlePeriodState());
- }
-
- protected:
- static base::TimeDelta maximum_idle_period_duration() {
- return base::TimeDelta::FromMilliseconds(
- IdleHelper::kMaximumIdlePeriodMillis);
- }
-
- static base::TimeDelta retry_enable_long_idle_period_delay() {
- return base::TimeDelta::FromMilliseconds(
- IdleHelper::kRetryEnableLongIdlePeriodDelayMillis);
- }
-
- static base::TimeDelta minimum_idle_period_duration() {
- return base::TimeDelta::FromMilliseconds(
- IdleHelper::kMinimumIdlePeriodDurationMillis);
- }
-
- base::TimeTicks CurrentIdleTaskDeadline() {
- return idle_helper_->CurrentIdleTaskDeadline();
- }
-
- void CheckIdlePeriodStateIs(const char* expected) {
- EXPECT_STREQ(expected, IdleHelper::IdlePeriodStateToString(
- idle_helper_->SchedulerIdlePeriodState()));
- }
-
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- // Only one of mock_task_runner_ or message_loop_ will be set.
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
- std::unique_ptr<base::MessageLoop> message_loop_;
-
- scoped_refptr<SchedulerTqmDelegate> main_task_runner_;
- std::unique_ptr<SchedulerHelper> scheduler_helper_;
- std::unique_ptr<IdleHelperForTest> idle_helper_;
- scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(BaseIdleHelperTest);
-};
-
-class IdleHelperTest : public BaseIdleHelperTest {
- public:
- IdleHelperTest() : BaseIdleHelperTest(nullptr, base::TimeDelta()) {}
-
- ~IdleHelperTest() override {}
-
- TaskQueueManager* task_queue_manager() const {
- return scheduler_helper_->GetTaskQueueManagerForTesting();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(IdleHelperTest);
-};
-
-TEST_F(IdleHelperTest, TestPostIdleTask) {
- int run_count = 0;
- base::TimeTicks expected_deadline =
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(2300);
- base::TimeTicks deadline_in_task;
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(100));
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- expected_deadline);
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
- EXPECT_EQ(expected_deadline, deadline_in_task);
-}
-
-TEST_F(IdleHelperTest, TestPostIdleTask_EndIdlePeriod) {
- int run_count = 0;
- base::TimeTicks deadline_in_task;
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(100));
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- idle_helper_->EndIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-}
-
-TEST_F(IdleHelperTest, TestRepostingIdleTask) {
- base::TimeTicks actual_deadline;
- int run_count = 0;
-
- max_idle_task_reposts = 2;
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_),
- &run_count, &actual_deadline));
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-
- // Reposted tasks shouldn't run until next idle period.
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(IdleHelperTest, TestIdleTaskExceedsDeadline) {
- int run_count = 0;
-
- // Post two UpdateClockToDeadlineIdleTestTask tasks.
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count));
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count));
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- // Only the first idle task should execute since it's used up the deadline.
- EXPECT_EQ(1, run_count);
-
- idle_helper_->EndIdlePeriod();
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- // Second task should be run on the next idle period.
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(IdleHelperTest, TestPostIdleTaskAfterWakeup) {
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- // Shouldn't run yet as no other task woke up the scheduler.
- EXPECT_EQ(0, run_count);
-
- // Must start a new idle period before idle task runs.
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- // Another after wakeup idle task shouldn't wake the scheduler.
- EXPECT_EQ(0, run_count);
-
- default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
-
- RunUntilIdle();
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- // Execution of default task queue task should trigger execution of idle task.
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(IdleHelperTest, TestPostIdleTaskAfterWakeupWhileAwake) {
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
-
- RunUntilIdle();
- // Must start a new idle period before idle task runs.
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- // Should run as the scheduler was already awakened by the normal task.
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(IdleHelperTest, TestPostIdleTaskWakesAfterWakeupIdleTask) {
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- // Must start a new idle period before after-wakeup idle task runs.
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- // Normal idle task should wake up after-wakeup idle task.
- EXPECT_EQ(2, run_count);
-}
-
-class IdleHelperTestWithIdlePeriodObserver : public BaseIdleHelperTest {
- public:
- IdleHelperTestWithIdlePeriodObserver()
- : BaseIdleHelperTest(nullptr, base::TimeDelta()) {}
-
- ~IdleHelperTestWithIdlePeriodObserver() override {}
-
- void SetUp() override {
- // Don't set expectations on IdleHelper::Delegate.
- }
-
- TaskQueueManager* task_queue_manager() const {
- return scheduler_helper_->GetTaskQueueManagerForTesting();
- }
-
- void ExpectIdlePeriodStartsButNeverEnds() {
- EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(1);
- EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(0);
- }
-
- void ExpectIdlePeriodStartsAndEnds(const testing::Cardinality& cardinality) {
- EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(cardinality);
- EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(cardinality);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(IdleHelperTestWithIdlePeriodObserver);
-};
-
-TEST_F(IdleHelperTestWithIdlePeriodObserver, TestEnterButNotExitIdlePeriod) {
- ExpectIdlePeriodStartsButNeverEnds();
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
-}
-
-TEST_F(IdleHelperTestWithIdlePeriodObserver, TestEnterAndExitIdlePeriod) {
- BaseIdleHelperTest* fixture = this;
- ON_CALL(*idle_helper_, OnIdlePeriodStarted())
- .WillByDefault(
- Invoke([fixture]() { EXPECT_TRUE(fixture->IsInIdlePeriod()); }));
- ON_CALL(*idle_helper_, OnIdlePeriodEnded())
- .WillByDefault(
- Invoke([fixture]() { EXPECT_FALSE(fixture->IsInIdlePeriod()); }));
-
- ExpectIdlePeriodStartsAndEnds(Exactly(1));
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- idle_helper_->EndIdlePeriod();
-}
-
-class IdleHelperWithMessageLoopTest : public BaseIdleHelperTest {
- public:
- IdleHelperWithMessageLoopTest()
- : BaseIdleHelperTest(new base::MessageLoop(), base::TimeDelta()) {}
- ~IdleHelperWithMessageLoopTest() override {}
-
- void PostFromNestedRunloop(std::vector<
- std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>* tasks) {
- base::MessageLoop::ScopedNestableTaskAllower allow(message_loop_.get());
- for (std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>& pair : *tasks) {
- if (pair.second) {
- idle_task_runner_->PostIdleTask(FROM_HERE, pair.first);
- } else {
- idle_task_runner_->PostNonNestableIdleTask(FROM_HERE, pair.first);
- }
- }
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- message_loop_->RunUntilIdle();
- }
-
- void SetUp() override {
- EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber());
- EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(AnyNumber());
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(IdleHelperWithMessageLoopTest);
-};
-
-TEST_F(IdleHelperWithMessageLoopTest,
- NonNestableIdleTaskDoesntExecuteInNestedLoop) {
- std::vector<std::string> order;
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("1")));
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("2")));
-
- std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>
- tasks_to_post_from_nested_loop;
- tasks_to_post_from_nested_loop.push_back(std::make_pair(
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("3")),
- false));
- tasks_to_post_from_nested_loop.push_back(std::make_pair(
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("4")), true));
- tasks_to_post_from_nested_loop.push_back(std::make_pair(
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("5")), true));
-
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&IdleHelperWithMessageLoopTest::PostFromNestedRunloop,
- base::Unretained(this),
- base::Unretained(&tasks_to_post_from_nested_loop)));
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- // Note we expect task 3 to run last because it's non-nestable.
- EXPECT_THAT(order, testing::ElementsAre(std::string("1"), std::string("2"),
- std::string("4"), std::string("5"),
- std::string("3")));
-}
-
-TEST_F(IdleHelperTestWithIdlePeriodObserver, TestLongIdlePeriod) {
- base::TimeTicks expected_deadline =
- clock_->NowTicks() + maximum_idle_period_duration();
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _))
- .Times(1)
- .WillRepeatedly(Return(true));
- ExpectIdlePeriodStartsButNeverEnds();
-
- RunUntilIdle();
- EXPECT_EQ(0, run_count); // Shouldn't run yet as no idle period.
-
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(1, run_count); // Should have run in a long idle time.
- EXPECT_EQ(expected_deadline, deadline_in_task);
-}
-
-TEST_F(IdleHelperTest, TestLongIdlePeriodWithPendingDelayedTask) {
- base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(30);
- base::TimeTicks expected_deadline = clock_->NowTicks() + pending_task_delay;
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
- pending_task_delay);
-
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(1, run_count); // Should have run in a long idle time.
- EXPECT_EQ(expected_deadline, deadline_in_task);
-}
-
-TEST_F(IdleHelperTest, TestLongIdlePeriodWithLatePendingDelayedTask) {
- base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
- pending_task_delay);
-
- // Advance clock until after delayed task was meant to be run.
- clock_->Advance(base::TimeDelta::FromMilliseconds(20));
-
- // Post an idle task and then EnableLongIdlePeriod. Since there is a late
- // pending delayed task this shouldn't actually start an idle period.
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- // After the delayed task has been run we should trigger an idle period.
- clock_->Advance(maximum_idle_period_duration());
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(IdleHelperTestWithIdlePeriodObserver, TestLongIdlePeriodRepeating) {
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- std::vector<base::TimeTicks> actual_deadlines;
- int run_count = 0;
-
- EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _))
- .Times(4)
- .WillRepeatedly(Return(true));
- ExpectIdlePeriodStartsAndEnds(AtLeast(2));
-
- max_idle_task_reposts = 3;
- base::TimeTicks clock_before(clock_->NowTicks());
- base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10));
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingUpdateClockIdleTestTask,
- base::RetainedRef(idle_task_runner_), &run_count, clock_.get(),
- idle_task_runtime, &actual_deadlines));
-
- // Check each idle task runs in their own idle period.
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(3, run_count);
- EXPECT_THAT(
- actual_deadlines,
- testing::ElementsAre(
- clock_before + maximum_idle_period_duration(),
- clock_before + idle_task_runtime + maximum_idle_period_duration(),
- clock_before + (2 * idle_task_runtime) +
- maximum_idle_period_duration()));
-
- max_idle_task_reposts = 5;
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingUpdateClockIdleTestTask,
- base::RetainedRef(idle_task_runner_), &run_count, clock_.get(),
- idle_task_runtime, &actual_deadlines));
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&EndIdlePeriodIdleTask, base::Unretained(idle_helper_.get())));
-
- // Ensure that reposting tasks stop after EndIdlePeriod is called.
- RunUntilIdle();
- EXPECT_EQ(4, run_count);
-}
-
-TEST_F(IdleHelperTest, TestLongIdlePeriodDoesNotWakeScheduler) {
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- // Start a long idle period and get the time it should end.
- idle_helper_->EnableLongIdlePeriod();
- // The scheduler should not run the enable_next_long_idle_period task if
- // there are no idle tasks and no other task woke up the scheduler, thus
- // the idle period deadline shouldn't update at the end of the current long
- // idle period.
- base::TimeTicks idle_period_deadline = CurrentIdleTaskDeadline();
- clock_->Advance(maximum_idle_period_duration());
- RunUntilIdle();
-
- base::TimeTicks new_idle_period_deadline = CurrentIdleTaskDeadline();
- EXPECT_EQ(idle_period_deadline, new_idle_period_deadline);
-
- // Posting a after-wakeup idle task also shouldn't wake the scheduler or
- // initiate the next long idle period.
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- RunUntilIdle();
- new_idle_period_deadline = CurrentIdleTaskDeadline();
- EXPECT_EQ(idle_period_deadline, new_idle_period_deadline);
- EXPECT_EQ(0, run_count);
-
- // Running a normal task should initiate a new long idle period though.
- default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
- RunUntilIdle();
- new_idle_period_deadline = CurrentIdleTaskDeadline();
- EXPECT_EQ(idle_period_deadline + maximum_idle_period_duration(),
- new_idle_period_deadline);
-
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(IdleHelperTestWithIdlePeriodObserver,
- TestLongIdlePeriodWhenNotCanEnterLongIdlePeriod) {
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(1000);
- base::TimeDelta halfDelay = base::TimeDelta::FromMilliseconds(500);
- base::TimeTicks delayOver = clock_->NowTicks() + delay;
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- ON_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _))
- .WillByDefault(Invoke(
- [delay, delayOver](base::TimeTicks now,
- base::TimeDelta* next_long_idle_period_delay_out) {
- if (now >= delayOver)
- return true;
- *next_long_idle_period_delay_out = delay;
- return false;
- }));
-
- EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)).Times(2);
- EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber());
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- // Make sure Idle tasks don't run until the delay has occurred.
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- clock_->Advance(halfDelay);
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- // Delay is finished, idle task should run.
- clock_->Advance(halfDelay);
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(IdleHelperTest, TestLongIdlePeriodImmediatelyRestartsIfMaxDeadline) {
- std::vector<base::TimeTicks> actual_deadlines;
- int run_count = 0;
-
- base::TimeTicks clock_before(clock_->NowTicks());
- base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10));
-
- // The second idle period should happen immediately after the first the
- // they have max deadlines.
- max_idle_task_reposts = 2;
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingUpdateClockIdleTestTask,
- base::RetainedRef(idle_task_runner_), &run_count, clock_.get(),
- idle_task_runtime, &actual_deadlines));
-
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(2, run_count);
- EXPECT_THAT(
- actual_deadlines,
- testing::ElementsAre(
- clock_before + maximum_idle_period_duration(),
- clock_before + idle_task_runtime + maximum_idle_period_duration()));
-}
-
-TEST_F(IdleHelperTest, TestLongIdlePeriodRestartWaitsIfNotMaxDeadline) {
- base::TimeTicks actual_deadline;
- int run_count = 0;
-
- base::TimeDelta pending_task_delay(base::TimeDelta::FromMilliseconds(20));
- base::TimeDelta idle_task_duration(base::TimeDelta::FromMilliseconds(10));
- base::TimeTicks expected_deadline(clock_->NowTicks() + pending_task_delay +
- maximum_idle_period_duration() +
- retry_enable_long_idle_period_delay());
-
- // Post delayed task to ensure idle period doesn't have a max deadline.
- default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
- pending_task_delay);
-
- max_idle_task_reposts = 2;
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_),
- &run_count, &actual_deadline));
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
- clock_->Advance(idle_task_duration);
-
- // Next idle period shouldn't happen until the pending task has been run.
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-
- // Once the pending task is run the new idle period should start.
- clock_->Advance(pending_task_delay - idle_task_duration);
-
- // Since the idle period tried to start before the pending task ran we have to
- // wait for the idle helper to retry starting the long idle period.
- clock_->Advance(retry_enable_long_idle_period_delay());
- RunUntilIdle();
-
- EXPECT_EQ(2, run_count);
- EXPECT_EQ(expected_deadline, actual_deadline);
-}
-
-TEST_F(IdleHelperTest, TestLongIdlePeriodPaused) {
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- std::vector<base::TimeTicks> actual_deadlines;
- int run_count = 0;
-
- // If there are no idle tasks posted we should start in the paused state.
- idle_helper_->EnableLongIdlePeriod();
- CheckIdlePeriodStateIs("in_long_idle_period_paused");
- // There shouldn't be any delayed tasks posted by the idle helper when paused.
- base::TimeTicks next_pending_delayed_task;
- EXPECT_FALSE(scheduler_helper_->real_time_domain()->NextScheduledRunTime(
- &next_pending_delayed_task));
-
- // Posting a task should transition us to the an active state.
- max_idle_task_reposts = 2;
- base::TimeTicks clock_before(clock_->NowTicks());
- base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10));
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingUpdateClockIdleTestTask,
- base::RetainedRef(idle_task_runner_), &run_count, clock_.get(),
- idle_task_runtime, &actual_deadlines));
- RunUntilIdle();
- EXPECT_EQ(2, run_count);
- EXPECT_THAT(
- actual_deadlines,
- testing::ElementsAre(
- clock_before + maximum_idle_period_duration(),
- clock_before + idle_task_runtime + maximum_idle_period_duration()));
-
- // Once all task have been run we should go back to the paused state.
- CheckIdlePeriodStateIs("in_long_idle_period_paused");
- EXPECT_FALSE(scheduler_helper_->real_time_domain()->NextScheduledRunTime(
- &next_pending_delayed_task));
-
- idle_helper_->EndIdlePeriod();
- CheckIdlePeriodStateIs("not_in_idle_period");
-}
-
-TEST_F(IdleHelperTest, TestLongIdlePeriodWhenShutdown) {
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- scheduler_helper_->Shutdown();
-
- // We shouldn't be able to enter a long idle period when shutdown
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- CheckIdlePeriodStateIs("not_in_idle_period");
- EXPECT_EQ(0, run_count);
-}
-
-void TestCanExceedIdleDeadlineIfRequiredTask(IdleHelperForTest* idle_helper,
- bool* can_exceed_idle_deadline_out,
- int* run_count,
- base::TimeTicks deadline) {
- *can_exceed_idle_deadline_out =
- idle_helper->CanExceedIdleDeadlineIfRequired();
- (*run_count)++;
-}
-
-TEST_F(IdleHelperTest, CanExceedIdleDeadlineIfRequired) {
- int run_count = 0;
- bool can_exceed_idle_deadline = false;
-
- // Should return false if not in an idle period.
- EXPECT_FALSE(idle_helper_->CanExceedIdleDeadlineIfRequired());
-
- // Should return false for short idle periods.
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(),
- &can_exceed_idle_deadline, &run_count));
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
- EXPECT_FALSE(can_exceed_idle_deadline);
-
- // Should return false for a long idle period which is shortened due to a
- // pending delayed task.
- default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
- base::TimeDelta::FromMilliseconds(10));
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(),
- &can_exceed_idle_deadline, &run_count));
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(2, run_count);
- EXPECT_FALSE(can_exceed_idle_deadline);
-
- // Next long idle period will be for the maximum time, so
- // CanExceedIdleDeadlineIfRequired should return true.
- clock_->Advance(maximum_idle_period_duration());
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(),
- &can_exceed_idle_deadline, &run_count));
- RunUntilIdle();
- EXPECT_EQ(3, run_count);
- EXPECT_TRUE(can_exceed_idle_deadline);
-}
-
-class IdleHelperWithQuiescencePeriodTest : public BaseIdleHelperTest {
- public:
- enum {
- kQuiescenceDelayMs = 100,
- kLongIdlePeriodMs = 50,
- };
-
- IdleHelperWithQuiescencePeriodTest()
- : BaseIdleHelperTest(
- nullptr,
- base::TimeDelta::FromMilliseconds(kQuiescenceDelayMs)) {}
-
- ~IdleHelperWithQuiescencePeriodTest() override {}
-
- void SetUp() override {
- EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber());
- EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(AnyNumber());
- EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _))
- .Times(AnyNumber())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(*idle_helper_, IsNotQuiescent()).Times(AnyNumber());
- }
-
- void MakeNonQuiescent() {
- // Run an arbitrary task so we're deemed to be not quiescent.
- default_task_runner_->PostTask(FROM_HERE, base::Bind(NullTask));
- RunUntilIdle();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(IdleHelperWithQuiescencePeriodTest);
-};
-
-class IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver :
- public IdleHelperWithQuiescencePeriodTest {
- public:
-
- IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver()
- : IdleHelperWithQuiescencePeriodTest() {}
-
- ~IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver() override {}
-
- void SetUp() override {
- // Don't set expectations on IdleHelper::Delegate.
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(
- IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver);
-};
-
-
-TEST_F(IdleHelperWithQuiescencePeriodTest,
- LongIdlePeriodStartsImmediatelyIfQuiescent) {
- base::TimeTicks actual_deadline;
- int run_count = 0;
- max_idle_task_reposts = 1;
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_),
- &run_count, &actual_deadline));
-
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
-
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver,
- LongIdlePeriodDoesNotStartsImmediatelyIfBusy) {
- MakeNonQuiescent();
- EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(0);
- EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(0);
- EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)).Times(0);
- EXPECT_CALL(*idle_helper_, IsNotQuiescent()).Times(AtLeast(1));
-
- base::TimeTicks actual_deadline;
- int run_count = 0;
- max_idle_task_reposts = 1;
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_),
- &run_count, &actual_deadline));
-
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
-
- EXPECT_EQ(0, run_count);
-
- scheduler_helper_->Shutdown();
-}
-
-TEST_F(IdleHelperWithQuiescencePeriodTest,
- LongIdlePeriodStartsAfterQuiescence) {
- MakeNonQuiescent();
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
-
- // Run a repeating task so we're deemed to be busy for the next 400ms.
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RepeatingTask, base::Unretained(default_task_runner_.get()),
- 10, base::TimeDelta::FromMilliseconds(40)));
-
- int run_count = 0;
- // In this scenario EnableLongIdlePeriod deems us not to be quiescent 5x in
- // a row.
- base::TimeTicks expected_deadline =
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(
- 5 * kQuiescenceDelayMs + kLongIdlePeriodMs);
- base::TimeTicks deadline_in_task;
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
- EXPECT_EQ(expected_deadline, deadline_in_task);
-}
-
-TEST_F(IdleHelperWithQuiescencePeriodTest,
- QuescienceCheckedForAfterLongIdlePeriodEnds) {
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
-
- idle_task_runner_->PostIdleTask(FROM_HERE, base::Bind(&NullIdleTask));
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
-
- // Post a normal task to make the scheduler non-quiescent.
- default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
- RunUntilIdle();
-
- // Post an idle task. The idle task won't run initially because the system is
- // not judged to be quiescent, but should be run after the quiescence delay.
- int run_count = 0;
- base::TimeTicks deadline_in_task;
- base::TimeTicks expected_deadline =
- clock_->NowTicks() +
- base::TimeDelta::FromMilliseconds(kQuiescenceDelayMs + kLongIdlePeriodMs);
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
-
- EXPECT_EQ(1, run_count);
- EXPECT_EQ(expected_deadline, deadline_in_task);
-}
-
-TEST_F(IdleHelperTest, NoShortIdlePeriodWhenDeadlineTooClose) {
- int run_count = 0;
- base::TimeTicks deadline_in_task;
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- base::TimeDelta half_a_ms(base::TimeDelta::FromMicroseconds(50));
- base::TimeTicks less_than_min_deadline(
- clock_->NowTicks() + minimum_idle_period_duration() - half_a_ms);
- base::TimeTicks more_than_min_deadline(
- clock_->NowTicks() + minimum_idle_period_duration() + half_a_ms);
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- less_than_min_deadline);
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- idle_helper_->StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(),
- more_than_min_deadline);
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(IdleHelperTest, NoLongIdlePeriodWhenDeadlineTooClose) {
- int run_count = 0;
- base::TimeTicks deadline_in_task;
-
- base::TimeDelta half_a_ms(base::TimeDelta::FromMicroseconds(50));
- base::TimeDelta less_than_min_deadline_duration(
- minimum_idle_period_duration() - half_a_ms);
- base::TimeDelta more_than_min_deadline_duration(
- minimum_idle_period_duration() + half_a_ms);
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
- less_than_min_deadline_duration);
-
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- idle_helper_->EndIdlePeriod();
- clock_->Advance(maximum_idle_period_duration());
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
- more_than_min_deadline_duration);
- idle_helper_->EnableLongIdlePeriod();
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/scheduler_helper.cc b/chromium/components/scheduler/child/scheduler_helper.cc
deleted file mode 100644
index 43944359e04..00000000000
--- a/chromium/components/scheduler/child/scheduler_helper.cc
+++ /dev/null
@@ -1,164 +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 "components/scheduler/child/scheduler_helper.h"
-
-#include "base/time/default_tick_clock.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-
-namespace scheduler {
-
-SchedulerHelper::SchedulerHelper(
- scoped_refptr<SchedulerTqmDelegate> task_queue_manager_delegate,
- const char* tracing_category,
- const char* disabled_by_default_tracing_category,
- const char* disabled_by_default_verbose_tracing_category)
- : task_queue_manager_delegate_(task_queue_manager_delegate),
- task_queue_manager_(
- new TaskQueueManager(task_queue_manager_delegate,
- tracing_category,
- disabled_by_default_tracing_category,
- disabled_by_default_verbose_tracing_category)),
- control_task_runner_(NewTaskQueue(
- TaskQueue::Spec("control_tq")
- .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES)
- .SetShouldNotifyObservers(false))),
- control_after_wakeup_task_runner_(NewTaskQueue(
- TaskQueue::Spec("control_after_wakeup_tq")
- .SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP)
- .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES)
- .SetShouldNotifyObservers(false))),
- default_task_runner_(NewTaskQueue(TaskQueue::Spec("default_tq")
- .SetShouldMonitorQuiescence(true))),
- observer_(nullptr),
- tracing_category_(tracing_category),
- disabled_by_default_tracing_category_(
- disabled_by_default_tracing_category) {
- control_task_runner_->SetQueuePriority(TaskQueue::CONTROL_PRIORITY);
- control_after_wakeup_task_runner_->SetQueuePriority(
- TaskQueue::CONTROL_PRIORITY);
-
- task_queue_manager_->SetWorkBatchSize(4);
-
- DCHECK(task_queue_manager_delegate_);
- task_queue_manager_delegate_->SetDefaultTaskRunner(
- default_task_runner_.get());
-}
-
-SchedulerHelper::~SchedulerHelper() {
- Shutdown();
-}
-
-void SchedulerHelper::Shutdown() {
- CheckOnValidThread();
- if (task_queue_manager_)
- task_queue_manager_->SetObserver(nullptr);
- task_queue_manager_.reset();
- task_queue_manager_delegate_->RestoreDefaultTaskRunner();
-}
-
-scoped_refptr<TaskQueue> SchedulerHelper::NewTaskQueue(
- const TaskQueue::Spec& spec) {
- DCHECK(task_queue_manager_.get());
- return task_queue_manager_->NewTaskQueue(spec);
-}
-
-scoped_refptr<TaskQueue> SchedulerHelper::DefaultTaskRunner() {
- CheckOnValidThread();
- return default_task_runner_;
-}
-
-scoped_refptr<TaskQueue> SchedulerHelper::ControlTaskRunner() {
- return control_task_runner_;
-}
-
-scoped_refptr<TaskQueue> SchedulerHelper::ControlAfterWakeUpTaskRunner() {
- return control_after_wakeup_task_runner_;
-}
-
-void SchedulerHelper::SetWorkBatchSizeForTesting(size_t work_batch_size) {
- CheckOnValidThread();
- DCHECK(task_queue_manager_.get());
- task_queue_manager_->SetWorkBatchSize(work_batch_size);
-}
-
-TaskQueueManager* SchedulerHelper::GetTaskQueueManagerForTesting() {
- CheckOnValidThread();
- return task_queue_manager_.get();
-}
-
-const scoped_refptr<SchedulerTqmDelegate>&
-SchedulerHelper::scheduler_tqm_delegate() const {
- return task_queue_manager_delegate_;
-}
-
-
-bool SchedulerHelper::GetAndClearSystemIsQuiescentBit() {
- CheckOnValidThread();
- DCHECK(task_queue_manager_.get());
- return task_queue_manager_->GetAndClearSystemIsQuiescentBit();
-}
-
-void SchedulerHelper::AddTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- CheckOnValidThread();
- if (task_queue_manager_)
- task_queue_manager_->AddTaskObserver(task_observer);
-}
-
-void SchedulerHelper::RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- CheckOnValidThread();
- if (task_queue_manager_)
- task_queue_manager_->RemoveTaskObserver(task_observer);
-}
-
-void SchedulerHelper::SetObserver(Observer* observer) {
- CheckOnValidThread();
- observer_ = observer;
- DCHECK(task_queue_manager_);
- task_queue_manager_->SetObserver(this);
-}
-
-RealTimeDomain* SchedulerHelper::real_time_domain() const {
- CheckOnValidThread();
- DCHECK(task_queue_manager_);
- return task_queue_manager_->real_time_domain();
-}
-
-void SchedulerHelper::RegisterTimeDomain(TimeDomain* time_domain) {
- CheckOnValidThread();
- DCHECK(task_queue_manager_);
- task_queue_manager_->RegisterTimeDomain(time_domain);
-}
-
-void SchedulerHelper::UnregisterTimeDomain(TimeDomain* time_domain) {
- CheckOnValidThread();
- if (task_queue_manager_)
- task_queue_manager_->UnregisterTimeDomain(time_domain);
-}
-
-void SchedulerHelper::OnUnregisterTaskQueue(
- const scoped_refptr<TaskQueue>& queue) {
- if (observer_)
- observer_->OnUnregisterTaskQueue(queue);
-}
-
-void SchedulerHelper::OnTriedToExecuteBlockedTask(
- const TaskQueue& queue,
- const base::PendingTask& task) {
- if (observer_)
- observer_->OnTriedToExecuteBlockedTask(queue, task);
-}
-
-TaskQueue* SchedulerHelper::CurrentlyExecutingTaskQueue() const {
- if (!task_queue_manager_)
- return nullptr;
- return task_queue_manager_->currently_executing_task_queue();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/scheduler_helper.h b/chromium/components/scheduler/child/scheduler_helper.h
deleted file mode 100644
index 0348a680879..00000000000
--- a/chromium/components/scheduler/child/scheduler_helper.h
+++ /dev/null
@@ -1,125 +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 COMPONENTS_SCHEDULER_CHILD_SCHEDULER_HELPER_H_
-#define COMPONENTS_SCHEDULER_CHILD_SCHEDULER_HELPER_H_
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "base/time/tick_clock.h"
-#include "components/scheduler/base/task_queue_manager.h"
-#include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-class TickClock;
-}
-
-namespace scheduler {
-
-class SchedulerTqmDelegate;
-
-// Common scheduler functionality for default tasks.
-class SCHEDULER_EXPORT SchedulerHelper : public TaskQueueManager::Observer {
- public:
- // Category strings must have application lifetime (statics or
- // literals). They may not include " chars.
- SchedulerHelper(
- scoped_refptr<SchedulerTqmDelegate> task_queue_manager_delegate,
- const char* tracing_category,
- const char* disabled_by_default_tracing_category,
- const char* disabled_by_default_verbose_tracing_category);
- ~SchedulerHelper() override;
-
- // TaskQueueManager::Observer implementation:
- void OnUnregisterTaskQueue(const scoped_refptr<TaskQueue>& queue) override;
- void OnTriedToExecuteBlockedTask(const TaskQueue& queue,
- const base::PendingTask& task) override;
-
- // Returns the default task runner.
- scoped_refptr<TaskQueue> DefaultTaskRunner();
-
- // Returns the control task runner. Tasks posted to this runner are executed
- // with the highest priority. Care must be taken to avoid starvation of other
- // task queues.
- scoped_refptr<TaskQueue> ControlTaskRunner();
-
- // Returns the control task after wakeup runner. Tasks posted to this runner
- // are executed with the highest priority but do not cause the scheduler to
- // wake up. Care must be taken to avoid starvation of other task queues.
- scoped_refptr<TaskQueue> ControlAfterWakeUpTaskRunner();
-
- // Adds or removes a task observer from the scheduler. The observer will be
- // notified before and after every executed task. These functions can only be
- // called on the thread this class was created on.
- void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer);
- void RemoveTaskObserver(base::MessageLoop::TaskObserver* task_observer);
-
- // Shuts down the scheduler by dropping any remaining pending work in the work
- // queues. After this call any work posted to the task runners will be
- // silently dropped.
- void Shutdown();
-
- // Returns true if Shutdown() has been called. Otherwise returns false.
- bool IsShutdown() const { return !task_queue_manager_.get(); }
-
- void CheckOnValidThread() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- }
-
- // Creates a new TaskQueue with the given |spec|.
- scoped_refptr<TaskQueue> NewTaskQueue(const TaskQueue::Spec& spec);
-
- class SCHEDULER_EXPORT Observer {
- public:
- virtual ~Observer() {}
-
- // Called when |queue| is unregistered.
- virtual void OnUnregisterTaskQueue(
- const scoped_refptr<TaskQueue>& queue) = 0;
-
- // Called when the scheduler tried to execute a task from a disabled
- // queue. See TaskQueue::Spec::SetShouldReportWhenExecutionBlocked.
- virtual void OnTriedToExecuteBlockedTask(const TaskQueue& queue,
- const base::PendingTask& task) = 0;
- };
-
- // Called once to set the Observer. This function is called on the main
- // thread. If |observer| is null, then no callbacks will occur.
- // Note |observer| is expected to outlive the SchedulerHelper.
- void SetObserver(Observer* observer);
-
- // Accessor methods.
- RealTimeDomain* real_time_domain() const;
- void RegisterTimeDomain(TimeDomain* time_domain);
- void UnregisterTimeDomain(TimeDomain* time_domain);
- const scoped_refptr<SchedulerTqmDelegate>& scheduler_tqm_delegate() const;
- bool GetAndClearSystemIsQuiescentBit();
- TaskQueue* CurrentlyExecutingTaskQueue() const;
-
- // Test helpers.
- void SetWorkBatchSizeForTesting(size_t work_batch_size);
- TaskQueueManager* GetTaskQueueManagerForTesting();
-
- private:
- friend class SchedulerHelperTest;
-
- base::ThreadChecker thread_checker_;
- scoped_refptr<SchedulerTqmDelegate> task_queue_manager_delegate_;
- std::unique_ptr<TaskQueueManager> task_queue_manager_;
- scoped_refptr<TaskQueue> control_task_runner_;
- scoped_refptr<TaskQueue> control_after_wakeup_task_runner_;
- scoped_refptr<TaskQueue> default_task_runner_;
-
- Observer* observer_; // NOT OWNED
- const char* tracing_category_;
- const char* disabled_by_default_tracing_category_;
-
- DISALLOW_COPY_AND_ASSIGN(SchedulerHelper);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_SCHEDULER_HELPER_H_
diff --git a/chromium/components/scheduler/child/scheduler_helper_unittest.cc b/chromium/components/scheduler/child/scheduler_helper_unittest.cc
deleted file mode 100644
index 73cbbdc4649..00000000000
--- a/chromium/components/scheduler/child/scheduler_helper_unittest.cc
+++ /dev/null
@@ -1,228 +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 "components/scheduler/child/scheduler_helper.h"
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/lazy_now.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::AnyNumber;
-using testing::Invoke;
-using testing::Return;
-
-namespace scheduler {
-
-namespace {
-void AppendToVectorTestTask(std::vector<std::string>* vector,
- std::string value) {
- vector->push_back(value);
-}
-
-void AppendToVectorReentrantTask(base::SingleThreadTaskRunner* task_runner,
- std::vector<int>* vector,
- int* reentrant_count,
- int max_reentrant_count) {
- vector->push_back((*reentrant_count)++);
- if (*reentrant_count < max_reentrant_count) {
- task_runner->PostTask(
- FROM_HERE,
- base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner),
- vector, reentrant_count, max_reentrant_count));
- }
-}
-
-}; // namespace
-
-class SchedulerHelperTest : public testing::Test {
- public:
- SchedulerHelperTest()
- : clock_(new base::SimpleTestTickClock()),
- mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_.get(), false)),
- main_task_runner_(SchedulerTqmDelegateForTest::Create(
- mock_task_runner_,
- base::WrapUnique(new TestTimeSource(clock_.get())))),
- scheduler_helper_(new SchedulerHelper(
- main_task_runner_,
- "test.scheduler",
- TRACE_DISABLED_BY_DEFAULT("test.scheduler"),
- TRACE_DISABLED_BY_DEFAULT("test.scheduler.dbg"))),
- default_task_runner_(scheduler_helper_->DefaultTaskRunner()) {
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- }
-
- ~SchedulerHelperTest() override {}
-
- void TearDown() override {
- // Check that all tests stop posting tasks.
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- while (mock_task_runner_->RunUntilIdle()) {
- }
- }
-
- void RunUntilIdle() { mock_task_runner_->RunUntilIdle(); }
-
- template <typename E>
- static void CallForEachEnumValue(E first,
- E last,
- const char* (*function)(E)) {
- for (E val = first; val < last;
- val = static_cast<E>(static_cast<int>(val) + 1)) {
- (*function)(val);
- }
- }
-
- protected:
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
-
- scoped_refptr<SchedulerTqmDelegateForTest> main_task_runner_;
- std::unique_ptr<SchedulerHelper> scheduler_helper_;
- scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(SchedulerHelperTest);
-};
-
-TEST_F(SchedulerHelperTest, TestPostDefaultTask) {
- std::vector<std::string> run_order;
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D1"));
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D2"));
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D3"));
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D4"));
-
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D1"), std::string("D2"),
- std::string("D3"), std::string("D4")));
-}
-
-TEST_F(SchedulerHelperTest, TestRentrantTask) {
- int count = 0;
- std::vector<int> run_order;
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(AppendToVectorReentrantTask,
- base::RetainedRef(default_task_runner_), &run_order,
- &count, 5));
- RunUntilIdle();
-
- EXPECT_THAT(run_order, testing::ElementsAre(0, 1, 2, 3, 4));
-}
-
-TEST_F(SchedulerHelperTest, IsShutdown) {
- EXPECT_FALSE(scheduler_helper_->IsShutdown());
-
- scheduler_helper_->Shutdown();
- EXPECT_TRUE(scheduler_helper_->IsShutdown());
-}
-
-TEST_F(SchedulerHelperTest, DefaultTaskRunnerRegistration) {
- EXPECT_EQ(main_task_runner_->default_task_runner(),
- scheduler_helper_->DefaultTaskRunner());
- scheduler_helper_->Shutdown();
- EXPECT_EQ(nullptr, main_task_runner_->default_task_runner());
-}
-
-namespace {
-class MockTaskObserver : public base::MessageLoop::TaskObserver {
- public:
- MOCK_METHOD1(DidProcessTask, void(const base::PendingTask& task));
- MOCK_METHOD1(WillProcessTask, void(const base::PendingTask& task));
-};
-
-void NopTask() {}
-} // namespace
-
-TEST_F(SchedulerHelperTest, ObserversNotifiedFor_DefaultTaskRunner) {
- MockTaskObserver observer;
- scheduler_helper_->AddTaskObserver(&observer);
-
- scheduler_helper_->DefaultTaskRunner()->PostTask(FROM_HERE,
- base::Bind(&NopTask));
-
- EXPECT_CALL(observer, WillProcessTask(_)).Times(1);
- EXPECT_CALL(observer, DidProcessTask(_)).Times(1);
- RunUntilIdle();
-}
-
-TEST_F(SchedulerHelperTest, ObserversNotNotifiedFor_ControlTaskRunner) {
- MockTaskObserver observer;
- scheduler_helper_->AddTaskObserver(&observer);
-
- scheduler_helper_->ControlTaskRunner()->PostTask(FROM_HERE,
- base::Bind(&NopTask));
-
- EXPECT_CALL(observer, WillProcessTask(_)).Times(0);
- EXPECT_CALL(observer, DidProcessTask(_)).Times(0);
- RunUntilIdle();
-}
-
-TEST_F(SchedulerHelperTest,
- ObserversNotNotifiedFor_ControlAfterWakeUpTaskRunner) {
- MockTaskObserver observer;
- scheduler_helper_->AddTaskObserver(&observer);
-
- scheduler_helper_->ControlAfterWakeUpTaskRunner()->PostTask(
- FROM_HERE, base::Bind(&NopTask));
-
- EXPECT_CALL(observer, WillProcessTask(_)).Times(0);
- EXPECT_CALL(observer, DidProcessTask(_)).Times(0);
- LazyNow lazy_now(clock_.get());
- scheduler_helper_->ControlAfterWakeUpTaskRunner()->PumpQueue(&lazy_now, true);
- RunUntilIdle();
-}
-
-namespace {
-
-class MockObserver : public SchedulerHelper::Observer {
- public:
- MOCK_METHOD1(OnUnregisterTaskQueue,
- void(const scoped_refptr<TaskQueue>& queue));
- MOCK_METHOD2(OnTriedToExecuteBlockedTask,
- void(const TaskQueue& queue, const base::PendingTask& task));
-};
-
-} // namespace
-
-TEST_F(SchedulerHelperTest, OnUnregisterTaskQueue) {
- MockObserver observer;
- scheduler_helper_->SetObserver(&observer);
-
- scoped_refptr<TaskQueue> task_queue =
- scheduler_helper_->NewTaskQueue(TaskQueue::Spec("test_queue"));
-
- EXPECT_CALL(observer, OnUnregisterTaskQueue(_)).Times(1);
- task_queue->UnregisterTaskQueue();
-
- scheduler_helper_->SetObserver(nullptr);
-}
-
-TEST_F(SchedulerHelperTest, OnTriedToExecuteBlockedTask) {
- MockObserver observer;
- scheduler_helper_->SetObserver(&observer);
-
- scoped_refptr<TaskQueue> task_queue = scheduler_helper_->NewTaskQueue(
- TaskQueue::Spec("test_queue").SetShouldReportWhenExecutionBlocked(true));
- task_queue->SetQueueEnabled(false);
- task_queue->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- EXPECT_CALL(observer, OnTriedToExecuteBlockedTask(_, _)).Times(1);
- RunUntilIdle();
-
- scheduler_helper_->SetObserver(nullptr);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/scheduler_tqm_delegate.h b/chromium/components/scheduler/child/scheduler_tqm_delegate.h
deleted file mode 100644
index bb294450571..00000000000
--- a/chromium/components/scheduler/child/scheduler_tqm_delegate.h
+++ /dev/null
@@ -1,37 +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 COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_H_
-#define COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_H_
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "components/scheduler/base/task_queue_manager_delegate.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-class SCHEDULER_EXPORT SchedulerTqmDelegate : public TaskQueueManagerDelegate {
- public:
- SchedulerTqmDelegate() {}
-
- // If the underlying task runner supports the concept of a default task
- // runner, the delegate should implement this function to redirect that task
- // runner to the scheduler.
- virtual void SetDefaultTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) = 0;
-
- // Similarly this method can be used to restore the original task runner when
- // the scheduler no longer wants to intercept tasks.
- virtual void RestoreDefaultTaskRunner() = 0;
-
- protected:
- ~SchedulerTqmDelegate() override {}
-
- DISALLOW_COPY_AND_ASSIGN(SchedulerTqmDelegate);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_H_
diff --git a/chromium/components/scheduler/child/scheduler_tqm_delegate_for_test.cc b/chromium/components/scheduler/child/scheduler_tqm_delegate_for_test.cc
deleted file mode 100644
index 87b96f663fa..00000000000
--- a/chromium/components/scheduler/child/scheduler_tqm_delegate_for_test.cc
+++ /dev/null
@@ -1,67 +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 "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "components/scheduler/base/task_queue_manager_delegate_for_test.h"
-
-namespace scheduler {
-
-// static
-scoped_refptr<SchedulerTqmDelegateForTest> SchedulerTqmDelegateForTest::Create(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- std::unique_ptr<base::TickClock> time_source) {
- return make_scoped_refptr(
- new SchedulerTqmDelegateForTest(task_runner, std::move(time_source)));
-}
-
-SchedulerTqmDelegateForTest::SchedulerTqmDelegateForTest(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- std::unique_ptr<base::TickClock> time_source)
- : task_runner_(
- TaskQueueManagerDelegateForTest::Create(task_runner,
- std::move(time_source))) {}
-
-SchedulerTqmDelegateForTest::~SchedulerTqmDelegateForTest() {}
-
-void SchedulerTqmDelegateForTest::SetDefaultTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- default_task_runner_ = std::move(task_runner);
-}
-
-void SchedulerTqmDelegateForTest::RestoreDefaultTaskRunner() {
- default_task_runner_ = nullptr;
-}
-
-bool SchedulerTqmDelegateForTest::PostDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- return task_runner_->PostDelayedTask(from_here, task, delay);
-}
-
-bool SchedulerTqmDelegateForTest::PostNonNestableDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- return task_runner_->PostNonNestableDelayedTask(from_here, task, delay);
-}
-
-bool SchedulerTqmDelegateForTest::RunsTasksOnCurrentThread() const {
- return task_runner_->RunsTasksOnCurrentThread();
-}
-
-bool SchedulerTqmDelegateForTest::IsNested() const {
- return task_runner_->IsNested();
-}
-
-base::TimeTicks SchedulerTqmDelegateForTest::NowTicks() {
- return task_runner_->NowTicks();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/scheduler_tqm_delegate_for_test.h b/chromium/components/scheduler/child/scheduler_tqm_delegate_for_test.h
deleted file mode 100644
index aeb2da12ea8..00000000000
--- a/chromium/components/scheduler/child/scheduler_tqm_delegate_for_test.h
+++ /dev/null
@@ -1,59 +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_RENDERER_SCHEDULER_TQM_DELEGATE_FOR_TEST_H_
-#define CONTENT_RENDERER_SCHEDULER_TQM_DELEGATE_FOR_TEST_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-
-namespace scheduler {
-
-class TaskQueueManagerDelegateForTest;
-
-class SchedulerTqmDelegateForTest : public SchedulerTqmDelegate {
- public:
- static scoped_refptr<SchedulerTqmDelegateForTest> Create(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- std::unique_ptr<base::TickClock> time_source);
-
- // SchedulerTqmDelegate implementation
- void SetDefaultTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
- void RestoreDefaultTaskRunner() override;
- bool PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override;
- bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override;
- bool RunsTasksOnCurrentThread() const override;
- bool IsNested() const override;
- base::TimeTicks NowTicks() override;
-
- base::SingleThreadTaskRunner* default_task_runner() const {
- return default_task_runner_.get();
- }
-
- protected:
- ~SchedulerTqmDelegateForTest() override;
-
- private:
- SchedulerTqmDelegateForTest(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- std::unique_ptr<base::TickClock> time_source);
-
- scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
-
- scoped_refptr<TaskQueueManagerDelegateForTest> task_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(SchedulerTqmDelegateForTest);
-};
-
-} // namespace scheduler
-
-#endif // CONTENT_RENDERER_SCHEDULER_TQM_DELEGATE_FOR_TEST_H_
diff --git a/chromium/components/scheduler/child/scheduler_tqm_delegate_impl.cc b/chromium/components/scheduler/child/scheduler_tqm_delegate_impl.cc
deleted file mode 100644
index ee4abcb3341..00000000000
--- a/chromium/components/scheduler/child/scheduler_tqm_delegate_impl.cc
+++ /dev/null
@@ -1,67 +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 "components/scheduler/child/scheduler_tqm_delegate_impl.h"
-
-#include <utility>
-
-namespace scheduler {
-
-// static
-scoped_refptr<SchedulerTqmDelegateImpl> SchedulerTqmDelegateImpl::Create(
- base::MessageLoop* message_loop,
- std::unique_ptr<base::TickClock> time_source) {
- return make_scoped_refptr(
- new SchedulerTqmDelegateImpl(message_loop, std::move(time_source)));
-}
-
-SchedulerTqmDelegateImpl::SchedulerTqmDelegateImpl(
- base::MessageLoop* message_loop,
- std::unique_ptr<base::TickClock> time_source)
- : message_loop_(message_loop),
- message_loop_task_runner_(message_loop->task_runner()),
- time_source_(std::move(time_source)) {}
-
-SchedulerTqmDelegateImpl::~SchedulerTqmDelegateImpl() {
- RestoreDefaultTaskRunner();
-}
-
-void SchedulerTqmDelegateImpl::SetDefaultTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- message_loop_->SetTaskRunner(task_runner);
-}
-
-void SchedulerTqmDelegateImpl::RestoreDefaultTaskRunner() {
- if (base::MessageLoop::current() == message_loop_)
- message_loop_->SetTaskRunner(message_loop_task_runner_);
-}
-
-bool SchedulerTqmDelegateImpl::PostDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- return message_loop_task_runner_->PostDelayedTask(from_here, task, delay);
-}
-
-bool SchedulerTqmDelegateImpl::PostNonNestableDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) {
- return message_loop_task_runner_->PostNonNestableDelayedTask(from_here, task,
- delay);
-}
-
-bool SchedulerTqmDelegateImpl::RunsTasksOnCurrentThread() const {
- return message_loop_task_runner_->RunsTasksOnCurrentThread();
-}
-
-bool SchedulerTqmDelegateImpl::IsNested() const {
- return message_loop_->IsNested();
-}
-
-base::TimeTicks SchedulerTqmDelegateImpl::NowTicks() {
- return time_source_->NowTicks();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/scheduler_tqm_delegate_impl.h b/chromium/components/scheduler/child/scheduler_tqm_delegate_impl.h
deleted file mode 100644
index aca86e26165..00000000000
--- a/chromium/components/scheduler/child/scheduler_tqm_delegate_impl.h
+++ /dev/null
@@ -1,56 +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 COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_IMPL_H_
-#define COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_IMPL_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/time/tick_clock.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-class SCHEDULER_EXPORT SchedulerTqmDelegateImpl : public SchedulerTqmDelegate {
- public:
- // |message_loop| is not owned and must outlive the lifetime of this object.
- static scoped_refptr<SchedulerTqmDelegateImpl> Create(
- base::MessageLoop* message_loop,
- std::unique_ptr<base::TickClock> time_source);
-
- // SchedulerTqmDelegate implementation
- void SetDefaultTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
- void RestoreDefaultTaskRunner() override;
- bool PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override;
- bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) override;
- bool RunsTasksOnCurrentThread() const override;
- bool IsNested() const override;
- base::TimeTicks NowTicks() override;
-
- protected:
- ~SchedulerTqmDelegateImpl() override;
-
- private:
- SchedulerTqmDelegateImpl(base::MessageLoop* message_loop,
- std::unique_ptr<base::TickClock> time_source);
-
- // Not owned.
- base::MessageLoop* message_loop_;
- scoped_refptr<SingleThreadTaskRunner> message_loop_task_runner_;
- std::unique_ptr<base::TickClock> time_source_;
-
- DISALLOW_COPY_AND_ASSIGN(SchedulerTqmDelegateImpl);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_IMPL_H_
diff --git a/chromium/components/scheduler/child/scheduler_tqm_delegate_impl_unittest.cc b/chromium/components/scheduler/child/scheduler_tqm_delegate_impl_unittest.cc
deleted file mode 100644
index b6e42be62d7..00000000000
--- a/chromium/components/scheduler/child/scheduler_tqm_delegate_impl_unittest.cc
+++ /dev/null
@@ -1,31 +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 "components/scheduler/child/scheduler_tqm_delegate_impl.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/time/default_tick_clock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace scheduler {
-
-TEST(SchedulerTqmDelegateImplTest, TestTaskRunnerOverriding) {
- base::MessageLoop loop;
- scoped_refptr<base::SingleThreadTaskRunner> original_runner(
- loop.task_runner());
- scoped_refptr<base::SingleThreadTaskRunner> custom_runner(
- new base::TestSimpleTaskRunner());
- {
- scoped_refptr<SchedulerTqmDelegateImpl> delegate(
- SchedulerTqmDelegateImpl::Create(
- &loop, base::WrapUnique(new base::DefaultTickClock())));
- delegate->SetDefaultTaskRunner(custom_runner);
- DCHECK_EQ(custom_runner, loop.task_runner());
- }
- DCHECK_EQ(original_runner, loop.task_runner());
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/single_thread_idle_task_runner.cc b/chromium/components/scheduler/child/single_thread_idle_task_runner.cc
deleted file mode 100644
index e73adf543a1..00000000000
--- a/chromium/components/scheduler/child/single_thread_idle_task_runner.cc
+++ /dev/null
@@ -1,90 +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 "components/scheduler/child/single_thread_idle_task_runner.h"
-
-#include "base/location.h"
-#include "base/trace_event/blame_context.h"
-#include "base/trace_event/trace_event.h"
-
-namespace scheduler {
-
-SingleThreadIdleTaskRunner::SingleThreadIdleTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> idle_priority_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> after_wakeup_task_runner,
- Delegate* delegate,
- const char* tracing_category)
- : idle_priority_task_runner_(idle_priority_task_runner),
- after_wakeup_task_runner_(after_wakeup_task_runner),
- delegate_(delegate),
- tracing_category_(tracing_category),
- blame_context_(nullptr),
- weak_factory_(this) {
- DCHECK(!idle_priority_task_runner_ ||
- idle_priority_task_runner_->RunsTasksOnCurrentThread());
- DCHECK(!after_wakeup_task_runner_ ||
- after_wakeup_task_runner_->RunsTasksOnCurrentThread());
- weak_scheduler_ptr_ = weak_factory_.GetWeakPtr();
-}
-
-SingleThreadIdleTaskRunner::~SingleThreadIdleTaskRunner() {
-}
-
-SingleThreadIdleTaskRunner::Delegate::Delegate() {
-}
-
-SingleThreadIdleTaskRunner::Delegate::~Delegate() {
-}
-
-bool SingleThreadIdleTaskRunner::RunsTasksOnCurrentThread() const {
- return idle_priority_task_runner_->RunsTasksOnCurrentThread();
-}
-
-void SingleThreadIdleTaskRunner::PostIdleTask(
- const tracked_objects::Location& from_here,
- const IdleTask& idle_task) {
- delegate_->OnIdleTaskPosted();
- idle_priority_task_runner_->PostTask(
- from_here, base::Bind(&SingleThreadIdleTaskRunner::RunTask,
- weak_scheduler_ptr_, idle_task));
-}
-
-void SingleThreadIdleTaskRunner::PostNonNestableIdleTask(
- const tracked_objects::Location& from_here,
- const IdleTask& idle_task) {
- delegate_->OnIdleTaskPosted();
- idle_priority_task_runner_->PostNonNestableTask(
- from_here, base::Bind(&SingleThreadIdleTaskRunner::RunTask,
- weak_scheduler_ptr_, idle_task));
-}
-
-void SingleThreadIdleTaskRunner::PostIdleTaskAfterWakeup(
- const tracked_objects::Location& from_here,
- const IdleTask& idle_task) {
- // Don't signal posting of idle task to the delegate here, wait until the
- // after-wakeup task posts the real idle task.
- after_wakeup_task_runner_->PostTask(
- FROM_HERE, base::Bind(&SingleThreadIdleTaskRunner::PostIdleTask,
- weak_scheduler_ptr_, from_here, idle_task));
-}
-
-void SingleThreadIdleTaskRunner::RunTask(IdleTask idle_task) {
- base::TimeTicks deadline = delegate_->WillProcessIdleTask();
- TRACE_EVENT1(tracing_category_, "SingleThreadIdleTaskRunner::RunTask",
- "allotted_time_ms",
- (deadline - base::TimeTicks::Now()).InMillisecondsF());
- if (blame_context_)
- blame_context_->Enter();
- idle_task.Run(deadline);
- if (blame_context_)
- blame_context_->Leave();
- delegate_->DidProcessIdleTask();
-}
-
-void SingleThreadIdleTaskRunner::SetBlameContext(
- base::trace_event::BlameContext* blame_context) {
- blame_context_ = blame_context;
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/single_thread_idle_task_runner.h b/chromium/components/scheduler/child/single_thread_idle_task_runner.h
deleted file mode 100644
index 04485865267..00000000000
--- a/chromium/components/scheduler/child/single_thread_idle_task_runner.h
+++ /dev/null
@@ -1,99 +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 COMPONENTS_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_
-#define COMPONENTS_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/time/time.h"
-#include "base/trace_event/trace_event.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-namespace trace_event {
-class BlameContext;
-}
-}
-
-namespace scheduler {
-
-// A SingleThreadIdleTaskRunner is a task runner for running idle tasks. Idle
-// tasks have an unbound argument which is bound to a deadline
-// (in base::TimeTicks) when they are run. The idle task is expected to
-// complete by this deadline.
-class SingleThreadIdleTaskRunner
- : public base::RefCountedThreadSafe<SingleThreadIdleTaskRunner> {
- public:
- typedef base::Callback<void(base::TimeTicks)> IdleTask;
-
- // Used to request idle task deadlines and signal posting of idle tasks.
- class SCHEDULER_EXPORT Delegate {
- public:
- Delegate();
- virtual ~Delegate();
-
- // Signals that an idle task has been posted. This will be called on the
- // posting thread, which may not be the same thread as the
- // SingleThreadIdleTaskRunner runs on.
- virtual void OnIdleTaskPosted() = 0;
-
- // Signals that a new idle task is about to be run and returns the deadline
- // for this idle task.
- virtual base::TimeTicks WillProcessIdleTask() = 0;
-
- // Signals that an idle task has finished being run.
- virtual void DidProcessIdleTask() = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Delegate);
- };
-
- // NOTE Category strings must have application lifetime (statics or
- // literals). They may not include " chars.
- SingleThreadIdleTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> idle_priority_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> after_wakeup_task_runner,
- Delegate* Delegate,
- const char* tracing_category);
-
- virtual void PostIdleTask(const tracked_objects::Location& from_here,
- const IdleTask& idle_task);
-
- virtual void PostNonNestableIdleTask(
- const tracked_objects::Location& from_here,
- const IdleTask& idle_task);
-
- virtual void PostIdleTaskAfterWakeup(
- const tracked_objects::Location& from_here,
- const IdleTask& idle_task);
-
- bool RunsTasksOnCurrentThread() const;
-
- void SetBlameContext(base::trace_event::BlameContext* blame_context);
-
- protected:
- virtual ~SingleThreadIdleTaskRunner();
-
- private:
- friend class base::RefCountedThreadSafe<SingleThreadIdleTaskRunner>;
-
- void RunTask(IdleTask idle_task);
-
- scoped_refptr<base::SingleThreadTaskRunner> idle_priority_task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> after_wakeup_task_runner_;
- Delegate* delegate_; // NOT OWNED
- const char* tracing_category_;
- base::trace_event::BlameContext* blame_context_; // Not owned.
- base::WeakPtr<SingleThreadIdleTaskRunner> weak_scheduler_ptr_;
- base::WeakPtrFactory<SingleThreadIdleTaskRunner> weak_factory_;
- DISALLOW_COPY_AND_ASSIGN(SingleThreadIdleTaskRunner);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_
diff --git a/chromium/components/scheduler/child/web_scheduler_impl.cc b/chromium/components/scheduler/child/web_scheduler_impl.cc
deleted file mode 100644
index cc1a2ecc65c..00000000000
--- a/chromium/components/scheduler/child/web_scheduler_impl.cc
+++ /dev/null
@@ -1,97 +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 "components/scheduler/child/web_scheduler_impl.h"
-
-#include "base/bind.h"
-#include "base/single_thread_task_runner.h"
-#include "components/scheduler/child/web_task_runner_impl.h"
-#include "components/scheduler/child/worker_scheduler.h"
-#include "third_party/WebKit/public/platform/WebTraceLocation.h"
-#include "third_party/WebKit/public/platform/WebViewScheduler.h"
-
-namespace scheduler {
-
-WebSchedulerImpl::WebSchedulerImpl(
- ChildScheduler* child_scheduler,
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner,
- scoped_refptr<TaskQueue> loading_task_runner,
- scoped_refptr<TaskQueue> timer_task_runner)
- : child_scheduler_(child_scheduler),
- idle_task_runner_(idle_task_runner),
- timer_task_runner_(timer_task_runner),
- loading_web_task_runner_(new WebTaskRunnerImpl(loading_task_runner)),
- timer_web_task_runner_(new WebTaskRunnerImpl(timer_task_runner)) {}
-
-WebSchedulerImpl::~WebSchedulerImpl() {
-}
-
-void WebSchedulerImpl::shutdown() {
- child_scheduler_->Shutdown();
-}
-
-bool WebSchedulerImpl::shouldYieldForHighPriorityWork() {
- return child_scheduler_->ShouldYieldForHighPriorityWork();
-}
-
-bool WebSchedulerImpl::canExceedIdleDeadlineIfRequired() {
- return child_scheduler_->CanExceedIdleDeadlineIfRequired();
-}
-
-void WebSchedulerImpl::runIdleTask(
- std::unique_ptr<blink::WebThread::IdleTask> task,
- base::TimeTicks deadline) {
- task->run((deadline - base::TimeTicks()).InSecondsF());
-}
-
-void WebSchedulerImpl::postIdleTask(const blink::WebTraceLocation& web_location,
- blink::WebThread::IdleTask* task) {
- DCHECK(idle_task_runner_);
- std::unique_ptr<blink::WebThread::IdleTask> scoped_task(task);
- tracked_objects::Location location(web_location.functionName(),
- web_location.fileName(), -1, nullptr);
- idle_task_runner_->PostIdleTask(
- location,
- base::Bind(&WebSchedulerImpl::runIdleTask, base::Passed(&scoped_task)));
-}
-
-void WebSchedulerImpl::postNonNestableIdleTask(
- const blink::WebTraceLocation& web_location,
- blink::WebThread::IdleTask* task) {
- DCHECK(idle_task_runner_);
- std::unique_ptr<blink::WebThread::IdleTask> scoped_task(task);
- tracked_objects::Location location(web_location.functionName(),
- web_location.fileName(), -1, nullptr);
- idle_task_runner_->PostNonNestableIdleTask(
- location,
- base::Bind(&WebSchedulerImpl::runIdleTask, base::Passed(&scoped_task)));
-}
-
-void WebSchedulerImpl::postIdleTaskAfterWakeup(
- const blink::WebTraceLocation& web_location,
- blink::WebThread::IdleTask* task) {
- DCHECK(idle_task_runner_);
- std::unique_ptr<blink::WebThread::IdleTask> scoped_task(task);
- tracked_objects::Location location(web_location.functionName(),
- web_location.fileName(), -1, nullptr);
- idle_task_runner_->PostIdleTaskAfterWakeup(
- location,
- base::Bind(&WebSchedulerImpl::runIdleTask, base::Passed(&scoped_task)));
-}
-
-blink::WebTaskRunner* WebSchedulerImpl::loadingTaskRunner() {
- return loading_web_task_runner_.get();
-}
-
-blink::WebTaskRunner* WebSchedulerImpl::timerTaskRunner() {
- return timer_web_task_runner_.get();
-}
-
-std::unique_ptr<blink::WebViewScheduler>
-WebSchedulerImpl::createWebViewScheduler(blink::WebView*) {
- NOTREACHED();
- return nullptr;
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/web_scheduler_impl.h b/chromium/components/scheduler/child/web_scheduler_impl.h
deleted file mode 100644
index 0219a9431f3..00000000000
--- a/chromium/components/scheduler/child/web_scheduler_impl.h
+++ /dev/null
@@ -1,66 +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_CHILD_SCHEDULER_BASE_WEB_SCHEDULER_IMPL_H_
-#define CONTENT_CHILD_SCHEDULER_BASE_WEB_SCHEDULER_IMPL_H_
-
-#include <memory>
-
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-#include "components/scheduler/scheduler_export.h"
-#include "third_party/WebKit/public/platform/WebScheduler.h"
-#include "third_party/WebKit/public/platform/WebThread.h"
-
-namespace scheduler {
-
-class ChildScheduler;
-class SingleThreadIdleTaskRunner;
-class TaskQueue;
-class WebTaskRunnerImpl;
-
-class SCHEDULER_EXPORT WebSchedulerImpl : public blink::WebScheduler {
- public:
- WebSchedulerImpl(ChildScheduler* child_scheduler,
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner,
- scoped_refptr<TaskQueue> loading_task_runner,
- scoped_refptr<TaskQueue> timer_task_runner);
- ~WebSchedulerImpl() override;
-
- // blink::WebScheduler implementation:
- void shutdown() override;
- bool shouldYieldForHighPriorityWork() override;
- bool canExceedIdleDeadlineIfRequired() override;
- void postIdleTask(const blink::WebTraceLocation& location,
- blink::WebThread::IdleTask* task) override;
- void postNonNestableIdleTask(const blink::WebTraceLocation& location,
- blink::WebThread::IdleTask* task) override;
- void postIdleTaskAfterWakeup(const blink::WebTraceLocation& location,
- blink::WebThread::IdleTask* task) override;
- blink::WebTaskRunner* loadingTaskRunner() override;
- blink::WebTaskRunner* timerTaskRunner() override;
- std::unique_ptr<blink::WebViewScheduler> createWebViewScheduler(
- blink::WebView*) override;
- void suspendTimerQueue() override {}
- void resumeTimerQueue() override {}
- void addPendingNavigation(
- blink::WebScheduler::NavigatingFrameType type) override {}
- void removePendingNavigation(
- blink::WebScheduler::NavigatingFrameType type) override {}
- void onNavigationStarted() override {}
-
- private:
- static void runIdleTask(std::unique_ptr<blink::WebThread::IdleTask> task,
- base::TimeTicks deadline);
-
- ChildScheduler* child_scheduler_; // NOT OWNED
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
- scoped_refptr<TaskQueue> timer_task_runner_;
- std::unique_ptr<WebTaskRunnerImpl> loading_web_task_runner_;
- std::unique_ptr<WebTaskRunnerImpl> timer_web_task_runner_;
-};
-
-} // namespace scheduler
-
-#endif // CONTENT_CHILD_SCHEDULER_BASE_WEB_SCHEDULER_IMPL_H_
diff --git a/chromium/components/scheduler/child/web_task_runner_impl.cc b/chromium/components/scheduler/child/web_task_runner_impl.cc
deleted file mode 100644
index 922ca4a95ed..00000000000
--- a/chromium/components/scheduler/child/web_task_runner_impl.cc
+++ /dev/null
@@ -1,73 +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 "components/scheduler/child/web_task_runner_impl.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/base/time_domain.h"
-#include "third_party/WebKit/public/platform/WebTraceLocation.h"
-
-namespace scheduler {
-
-WebTaskRunnerImpl::WebTaskRunnerImpl(scoped_refptr<TaskQueue> task_queue)
- : task_queue_(task_queue) {}
-
-WebTaskRunnerImpl::~WebTaskRunnerImpl() {}
-
-void WebTaskRunnerImpl::postTask(const blink::WebTraceLocation& web_location,
- blink::WebTaskRunner::Task* task) {
- tracked_objects::Location location(web_location.functionName(),
- web_location.fileName(), -1, nullptr);
- task_queue_->PostTask(
- location,
- base::Bind(
- &WebTaskRunnerImpl::runTask,
- base::Passed(std::unique_ptr<blink::WebTaskRunner::Task>(task))));
-}
-
-void WebTaskRunnerImpl::postDelayedTask(
- const blink::WebTraceLocation& web_location,
- blink::WebTaskRunner::Task* task,
- double delayMs) {
- DCHECK_GE(delayMs, 0.0);
- tracked_objects::Location location(web_location.functionName(),
- web_location.fileName(), -1, nullptr);
- task_queue_->PostDelayedTask(
- location,
- base::Bind(
- &WebTaskRunnerImpl::runTask,
- base::Passed(std::unique_ptr<blink::WebTaskRunner::Task>(task))),
- base::TimeDelta::FromMillisecondsD(delayMs));
-}
-
-double WebTaskRunnerImpl::virtualTimeSeconds() const {
- return (Now() - base::TimeTicks::UnixEpoch()).InSecondsF();
-}
-
-double WebTaskRunnerImpl::monotonicallyIncreasingVirtualTimeSeconds() const {
- return Now().ToInternalValue() /
- static_cast<double>(base::Time::kMicrosecondsPerSecond);
-}
-
-base::TimeTicks WebTaskRunnerImpl::Now() const {
- TimeDomain* time_domain = task_queue_->GetTimeDomain();
- // It's possible task_queue_ has been Unregistered which can lead to a null
- // TimeDomain. If that happens just return the current real time.
- if (!time_domain)
- return base::TimeTicks::Now();
- return time_domain->Now();
-}
-
-blink::WebTaskRunner* WebTaskRunnerImpl::clone() {
- return new WebTaskRunnerImpl(task_queue_);
-}
-
-void WebTaskRunnerImpl::runTask(
- std::unique_ptr<blink::WebTaskRunner::Task> task) {
- task->run();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/web_task_runner_impl.h b/chromium/components/scheduler/child/web_task_runner_impl.h
deleted file mode 100644
index deebd83de61..00000000000
--- a/chromium/components/scheduler/child/web_task_runner_impl.h
+++ /dev/null
@@ -1,53 +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 COMPONENTS_SCHEDULER_CHILD_WEB_TASK_RUNNER_H_
-#define COMPONENTS_SCHEDULER_CHILD_WEB_TASK_RUNNER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-#include "components/scheduler/scheduler_export.h"
-#include "third_party/WebKit/public/platform/WebTaskRunner.h"
-
-namespace scheduler {
-class TaskQueue;
-
-class SCHEDULER_EXPORT WebTaskRunnerImpl : public blink::WebTaskRunner {
- public:
- explicit WebTaskRunnerImpl(scoped_refptr<TaskQueue> task_queue);
-
- ~WebTaskRunnerImpl() override;
-
- // blink::WebTaskRunner implementation:
- void postTask(const blink::WebTraceLocation& web_location,
- blink::WebTaskRunner::Task* task) override;
- void postDelayedTask(const blink::WebTraceLocation& web_location,
- blink::WebTaskRunner::Task* task,
- double delayMs) override;
- double virtualTimeSeconds() const override;
- double monotonicallyIncreasingVirtualTimeSeconds() const override;
- blink::WebTaskRunner* clone() override;
-
- // blink::WebTaskRunner::Task should be wrapped by base::Passed() when
- // used with base::Bind(). See https://crbug.com/551356.
- // runTask() is a helper to call blink::WebTaskRunner::Task::run from
- // std::unique_ptr<blink::WebTaskRunner::Task>.
- // runTask() is placed here because std::unique_ptr<> cannot be used from
- // Blink.
- static void runTask(std::unique_ptr<blink::WebTaskRunner::Task>);
-
- private:
- base::TimeTicks Now() const;
-
- scoped_refptr<TaskQueue> task_queue_;
-
- DISALLOW_COPY_AND_ASSIGN(WebTaskRunnerImpl);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_WEB_TASK_RUNNER_H_
diff --git a/chromium/components/scheduler/child/webthread_base.cc b/chromium/components/scheduler/child/webthread_base.cc
deleted file mode 100644
index cc3a5da2fb0..00000000000
--- a/chromium/components/scheduler/child/webthread_base.cc
+++ /dev/null
@@ -1,106 +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.
-
-// An implementation of WebThread in terms of base::MessageLoop and
-// base::Thread
-
-#include "components/scheduler/child/webthread_base.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/memory/ptr_util.h"
-#include "base/pending_task.h"
-#include "base/threading/platform_thread.h"
-#include "components/scheduler/child/single_thread_idle_task_runner.h"
-#include "third_party/WebKit/public/platform/WebTraceLocation.h"
-
-namespace scheduler {
-
-class WebThreadBase::TaskObserverAdapter
- : public base::MessageLoop::TaskObserver {
- public:
- explicit TaskObserverAdapter(WebThread::TaskObserver* observer)
- : observer_(observer) {}
-
- void WillProcessTask(const base::PendingTask& pending_task) override {
- observer_->willProcessTask();
- }
-
- void DidProcessTask(const base::PendingTask& pending_task) override {
- observer_->didProcessTask();
- }
-
- private:
- WebThread::TaskObserver* observer_;
-};
-
-WebThreadBase::WebThreadBase() {
-}
-
-WebThreadBase::~WebThreadBase() {
- for (auto& observer_entry : task_observer_map_) {
- delete observer_entry.second;
- }
-}
-
-void WebThreadBase::addTaskObserver(TaskObserver* observer) {
- CHECK(isCurrentThread());
- std::pair<TaskObserverMap::iterator, bool> result = task_observer_map_.insert(
- std::make_pair(observer, nullptr));
- if (result.second)
- result.first->second = new TaskObserverAdapter(observer);
- AddTaskObserverInternal(result.first->second);
-}
-
-void WebThreadBase::removeTaskObserver(TaskObserver* observer) {
- CHECK(isCurrentThread());
- TaskObserverMap::iterator iter = task_observer_map_.find(observer);
- if (iter == task_observer_map_.end())
- return;
- RemoveTaskObserverInternal(iter->second);
- delete iter->second;
- task_observer_map_.erase(iter);
-}
-
-void WebThreadBase::AddTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer) {
- base::MessageLoop::current()->AddTaskObserver(observer);
-}
-
-void WebThreadBase::RemoveTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer) {
- base::MessageLoop::current()->RemoveTaskObserver(observer);
-}
-
-// static
-void WebThreadBase::RunWebThreadIdleTask(
- std::unique_ptr<blink::WebThread::IdleTask> idle_task,
- base::TimeTicks deadline) {
- idle_task->run((deadline - base::TimeTicks()).InSecondsF());
-}
-
-void WebThreadBase::postIdleTask(const blink::WebTraceLocation& web_location,
- IdleTask* idle_task) {
- tracked_objects::Location location(web_location.functionName(),
- web_location.fileName(), -1, nullptr);
- GetIdleTaskRunner()->PostIdleTask(
- location, base::Bind(&WebThreadBase::RunWebThreadIdleTask,
- base::Passed(base::WrapUnique(idle_task))));
-}
-
-void WebThreadBase::postIdleTaskAfterWakeup(
- const blink::WebTraceLocation& web_location,
- IdleTask* idle_task) {
- tracked_objects::Location location(web_location.functionName(),
- web_location.fileName(), -1, nullptr);
- GetIdleTaskRunner()->PostIdleTaskAfterWakeup(
- location, base::Bind(&WebThreadBase::RunWebThreadIdleTask,
- base::Passed(base::WrapUnique(idle_task))));
-}
-
-bool WebThreadBase::isCurrentThread() const {
- return GetTaskRunner()->BelongsToCurrentThread();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/webthread_base.h b/chromium/components/scheduler/child/webthread_base.h
deleted file mode 100644
index 0075d5f39f2..00000000000
--- a/chromium/components/scheduler/child/webthread_base.h
+++ /dev/null
@@ -1,67 +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 COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_BASE_H_
-#define COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_BASE_H_
-
-#include <map>
-#include <memory>
-
-#include "base/threading/thread.h"
-#include "components/scheduler/scheduler_export.h"
-#include "third_party/WebKit/public/platform/WebThread.h"
-
-namespace blink {
-class WebTraceLocation;
-}
-
-namespace scheduler {
-class SingleThreadIdleTaskRunner;
-
-class SCHEDULER_EXPORT WebThreadBase : public blink::WebThread {
- public:
- ~WebThreadBase() override;
-
- // blink::WebThread implementation.
- bool isCurrentThread() const override;
- blink::PlatformThreadId threadId() const override = 0;
-
- virtual void postIdleTask(const blink::WebTraceLocation& location,
- IdleTask* idle_task);
- virtual void postIdleTaskAfterWakeup(const blink::WebTraceLocation& location,
- IdleTask* idle_task);
-
- void addTaskObserver(TaskObserver* observer) override;
- void removeTaskObserver(TaskObserver* observer) override;
-
- // Returns the base::Bind-compatible task runner for posting tasks to this
- // thread. Can be called from any thread.
- virtual base::SingleThreadTaskRunner* GetTaskRunner() const = 0;
-
- // Returns the base::Bind-compatible task runner for posting idle tasks to
- // this thread. Can be called from any thread.
- virtual scheduler::SingleThreadIdleTaskRunner* GetIdleTaskRunner() const = 0;
-
- protected:
- class TaskObserverAdapter;
-
- WebThreadBase();
-
- virtual void AddTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer);
- virtual void RemoveTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer);
-
- static void RunWebThreadIdleTask(
- std::unique_ptr<blink::WebThread::IdleTask> idle_task,
- base::TimeTicks deadline);
-
- private:
- typedef std::map<TaskObserver*, TaskObserverAdapter*> TaskObserverMap;
- TaskObserverMap task_observer_map_;
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_BASE_H_
diff --git a/chromium/components/scheduler/child/webthread_impl_for_worker_scheduler.cc b/chromium/components/scheduler/child/webthread_impl_for_worker_scheduler.cc
deleted file mode 100644
index ff7ec336f00..00000000000
--- a/chromium/components/scheduler/child/webthread_impl_for_worker_scheduler.cc
+++ /dev/null
@@ -1,129 +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 "components/scheduler/child/webthread_impl_for_worker_scheduler.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/memory/ptr_util.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/time/default_tick_clock.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_impl.h"
-#include "components/scheduler/child/web_scheduler_impl.h"
-#include "components/scheduler/child/web_task_runner_impl.h"
-#include "components/scheduler/child/worker_scheduler_impl.h"
-#include "third_party/WebKit/public/platform/WebTraceLocation.h"
-
-namespace scheduler {
-
-WebThreadImplForWorkerScheduler::WebThreadImplForWorkerScheduler(
- const char* name)
- : WebThreadImplForWorkerScheduler(name, base::Thread::Options()) {}
-
-WebThreadImplForWorkerScheduler::WebThreadImplForWorkerScheduler(
- const char* name,
- base::Thread::Options options)
- : thread_(new base::Thread(name ? name : std::string())) {
- bool started = thread_->StartWithOptions(options);
- CHECK(started);
- thread_task_runner_ = thread_->task_runner();
-}
-
-void WebThreadImplForWorkerScheduler::Init() {
- base::WaitableEvent completion(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- thread_task_runner_->PostTask(
- FROM_HERE, base::Bind(&WebThreadImplForWorkerScheduler::InitOnThread,
- base::Unretained(this), &completion));
- completion.Wait();
-}
-
-WebThreadImplForWorkerScheduler::~WebThreadImplForWorkerScheduler() {
- if (task_runner_delegate_) {
- base::WaitableEvent completion(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- // Restore the original task runner so that the thread can tear itself down.
- thread_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&WebThreadImplForWorkerScheduler::RestoreTaskRunnerOnThread,
- base::Unretained(this), &completion));
- completion.Wait();
- }
- thread_->Stop();
-}
-
-void WebThreadImplForWorkerScheduler::InitOnThread(
- base::WaitableEvent* completion) {
- // TODO(alexclarke): Do we need to unify virtual time for workers and the
- // main thread?
- worker_scheduler_ = CreateWorkerScheduler();
- worker_scheduler_->Init();
- task_runner_ = worker_scheduler_->DefaultTaskRunner();
- idle_task_runner_ = worker_scheduler_->IdleTaskRunner();
- web_scheduler_.reset(new WebSchedulerImpl(
- worker_scheduler_.get(), worker_scheduler_->IdleTaskRunner(),
- worker_scheduler_->DefaultTaskRunner(),
- worker_scheduler_->DefaultTaskRunner()));
- base::MessageLoop::current()->AddDestructionObserver(this);
- web_task_runner_ = base::WrapUnique(new WebTaskRunnerImpl(task_runner_));
- completion->Signal();
-}
-
-void WebThreadImplForWorkerScheduler::RestoreTaskRunnerOnThread(
- base::WaitableEvent* completion) {
- task_runner_delegate_->RestoreDefaultTaskRunner();
- completion->Signal();
-}
-
-void WebThreadImplForWorkerScheduler::WillDestroyCurrentMessageLoop() {
- task_runner_ = nullptr;
- idle_task_runner_ = nullptr;
- web_scheduler_.reset();
- worker_scheduler_.reset();
-}
-
-std::unique_ptr<scheduler::WorkerScheduler>
-WebThreadImplForWorkerScheduler::CreateWorkerScheduler() {
- task_runner_delegate_ = SchedulerTqmDelegateImpl::Create(
- thread_->message_loop(), base::WrapUnique(new base::DefaultTickClock()));
- return WorkerScheduler::Create(task_runner_delegate_);
-}
-
-blink::PlatformThreadId WebThreadImplForWorkerScheduler::threadId() const {
- return thread_->GetThreadId();
-}
-
-blink::WebScheduler* WebThreadImplForWorkerScheduler::scheduler() const {
- return web_scheduler_.get();
-}
-
-base::SingleThreadTaskRunner* WebThreadImplForWorkerScheduler::GetTaskRunner()
- const {
- return task_runner_.get();
-}
-
-SingleThreadIdleTaskRunner* WebThreadImplForWorkerScheduler::GetIdleTaskRunner()
- const {
- return idle_task_runner_.get();
-}
-
-blink::WebTaskRunner* WebThreadImplForWorkerScheduler::getWebTaskRunner() {
- return web_task_runner_.get();
-}
-
-void WebThreadImplForWorkerScheduler::AddTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer) {
- worker_scheduler_->AddTaskObserver(observer);
-}
-
-void WebThreadImplForWorkerScheduler::RemoveTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer) {
- worker_scheduler_->RemoveTaskObserver(observer);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/webthread_impl_for_worker_scheduler.h b/chromium/components/scheduler/child/webthread_impl_for_worker_scheduler.h
deleted file mode 100644
index e2e3b3c52dc..00000000000
--- a/chromium/components/scheduler/child/webthread_impl_for_worker_scheduler.h
+++ /dev/null
@@ -1,77 +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 COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_
-#define COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_
-
-#include "base/threading/thread.h"
-#include "components/scheduler/base/task_queue_manager.h"
-#include "components/scheduler/child/webthread_base.h"
-
-namespace base {
-class WaitableEvent;
-};
-
-namespace blink {
-class WebScheduler;
-};
-
-namespace scheduler {
-class SchedulerTqmDelegate;
-class SingleThreadIdleTaskRunner;
-class TaskQueue;
-class WebSchedulerImpl;
-class WebTaskRunnerImpl;
-class WorkerScheduler;
-
-class SCHEDULER_EXPORT WebThreadImplForWorkerScheduler
- : public WebThreadBase,
- public base::MessageLoop::DestructionObserver {
- public:
- explicit WebThreadImplForWorkerScheduler(const char* name);
- WebThreadImplForWorkerScheduler(const char* name,
- base::Thread::Options options);
- ~WebThreadImplForWorkerScheduler() override;
-
- void Init();
-
- // blink::WebThread implementation.
- blink::WebScheduler* scheduler() const override;
- blink::PlatformThreadId threadId() const override;
- blink::WebTaskRunner* getWebTaskRunner() override;
-
- // WebThreadBase implementation.
- base::SingleThreadTaskRunner* GetTaskRunner() const override;
- scheduler::SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override;
-
- // base::MessageLoop::DestructionObserver implementation.
- void WillDestroyCurrentMessageLoop() override;
-
- protected:
- base::Thread* thread() const { return thread_.get(); }
-
- private:
- virtual std::unique_ptr<scheduler::WorkerScheduler> CreateWorkerScheduler();
-
- void AddTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer) override;
- void RemoveTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer) override;
-
- void InitOnThread(base::WaitableEvent* completion);
- void RestoreTaskRunnerOnThread(base::WaitableEvent* completion);
-
- std::unique_ptr<base::Thread> thread_;
- std::unique_ptr<scheduler::WorkerScheduler> worker_scheduler_;
- std::unique_ptr<scheduler::WebSchedulerImpl> web_scheduler_;
- scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_;
- scoped_refptr<TaskQueue> task_runner_;
- scoped_refptr<scheduler::SingleThreadIdleTaskRunner> idle_task_runner_;
- scoped_refptr<SchedulerTqmDelegate> task_runner_delegate_;
- std::unique_ptr<WebTaskRunnerImpl> web_task_runner_;
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_
diff --git a/chromium/components/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc b/chromium/components/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc
deleted file mode 100644
index 13a777b04b5..00000000000
--- a/chromium/components/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc
+++ /dev/null
@@ -1,206 +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 "components/scheduler/child/webthread_impl_for_worker_scheduler.h"
-
-#include "base/macros.h"
-#include "base/synchronization/waitable_event.h"
-#include "components/scheduler/child/web_scheduler_impl.h"
-#include "components/scheduler/child/worker_scheduler_impl.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebTraceLocation.h"
-
-using testing::_;
-using testing::AnyOf;
-using testing::ElementsAre;
-using testing::Invoke;
-
-namespace scheduler {
-namespace {
-
-class NopTask : public blink::WebTaskRunner::Task {
- public:
- ~NopTask() override {}
-
- void run() override {}
-};
-
-class MockTask : public blink::WebTaskRunner::Task {
- public:
- ~MockTask() override {}
-
- MOCK_METHOD0(run, void());
-};
-
-class MockIdleTask : public blink::WebThread::IdleTask {
- public:
- ~MockIdleTask() override {}
-
- MOCK_METHOD1(run, void(double deadline));
-};
-
-class TestObserver : public blink::WebThread::TaskObserver {
- public:
- explicit TestObserver(std::string* calls) : calls_(calls) {}
-
- ~TestObserver() override {}
-
- void willProcessTask() override { calls_->append(" willProcessTask"); }
-
- void didProcessTask() override { calls_->append(" didProcessTask"); }
-
- private:
- std::string* calls_; // NOT OWNED
-};
-
-class TestTask : public blink::WebTaskRunner::Task {
- public:
- explicit TestTask(std::string* calls) : calls_(calls) {}
-
- ~TestTask() override {}
-
- void run() override { calls_->append(" run"); }
-
- private:
- std::string* calls_; // NOT OWNED
-};
-
-void addTaskObserver(WebThreadImplForWorkerScheduler* thread,
- TestObserver* observer) {
- thread->addTaskObserver(observer);
-}
-
-void removeTaskObserver(WebThreadImplForWorkerScheduler* thread,
- TestObserver* observer) {
- thread->removeTaskObserver(observer);
-}
-
-void shutdownOnThread(WebThreadImplForWorkerScheduler* thread) {
- WebSchedulerImpl* web_scheduler_impl =
- static_cast<WebSchedulerImpl*>(thread->scheduler());
- web_scheduler_impl->shutdown();
-}
-
-} // namespace
-
-class WebThreadImplForWorkerSchedulerTest : public testing::Test {
- public:
- WebThreadImplForWorkerSchedulerTest() {}
-
- ~WebThreadImplForWorkerSchedulerTest() override {}
-
- void SetUp() override {
- thread_.reset(new WebThreadImplForWorkerScheduler("test thread"));
- thread_->Init();
- }
-
- void RunOnWorkerThread(const tracked_objects::Location& from_here,
- const base::Closure& task) {
- base::WaitableEvent completion(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- thread_->GetTaskRunner()->PostTask(
- from_here,
- base::Bind(&WebThreadImplForWorkerSchedulerTest::RunOnWorkerThreadTask,
- base::Unretained(this), task, &completion));
- completion.Wait();
- }
-
- protected:
- void RunOnWorkerThreadTask(const base::Closure& task,
- base::WaitableEvent* completion) {
- task.Run();
- completion->Signal();
- }
-
- std::unique_ptr<WebThreadImplForWorkerScheduler> thread_;
-
- DISALLOW_COPY_AND_ASSIGN(WebThreadImplForWorkerSchedulerTest);
-};
-
-TEST_F(WebThreadImplForWorkerSchedulerTest, TestDefaultTask) {
- std::unique_ptr<MockTask> task(new MockTask());
- base::WaitableEvent completion(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- EXPECT_CALL(*task, run());
- ON_CALL(*task, run())
- .WillByDefault(Invoke([&completion]() { completion.Signal(); }));
-
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- task.release());
- completion.Wait();
-}
-
-TEST_F(WebThreadImplForWorkerSchedulerTest,
- TestTaskExecutedBeforeThreadDeletion) {
- std::unique_ptr<MockTask> task(new MockTask());
- base::WaitableEvent completion(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- EXPECT_CALL(*task, run());
- ON_CALL(*task, run())
- .WillByDefault(Invoke([&completion]() { completion.Signal(); }));
-
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- task.release());
- thread_.reset();
-}
-
-TEST_F(WebThreadImplForWorkerSchedulerTest, TestIdleTask) {
- std::unique_ptr<MockIdleTask> task(new MockIdleTask());
- base::WaitableEvent completion(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- EXPECT_CALL(*task, run(_));
- ON_CALL(*task, run(_))
- .WillByDefault(Invoke([&completion](double) { completion.Signal(); }));
-
- thread_->postIdleTask(blink::WebTraceLocation(), task.release());
- // We need to post a wakeup task or idle work will never happen.
- thread_->getWebTaskRunner()->postDelayedTask(blink::WebTraceLocation(),
- new NopTask(), 50ll);
-
- completion.Wait();
-}
-
-TEST_F(WebThreadImplForWorkerSchedulerTest, TestTaskObserver) {
- std::string calls;
- TestObserver observer(&calls);
-
- RunOnWorkerThread(FROM_HERE,
- base::Bind(&addTaskObserver, thread_.get(), &observer));
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- new TestTask(&calls));
- RunOnWorkerThread(FROM_HERE,
- base::Bind(&removeTaskObserver, thread_.get(), &observer));
-
- // We need to be careful what we test here. We want to make sure the
- // observers are un in the expected order before and after the task.
- // Sometimes we get an internal scheduler task running before or after
- // TestTask as well. This is not a bug, and we need to make sure the test
- // doesn't fail when that happens.
- EXPECT_THAT(calls, testing::HasSubstr("willProcessTask run didProcessTask"));
-}
-
-TEST_F(WebThreadImplForWorkerSchedulerTest, TestShutdown) {
- std::unique_ptr<MockTask> task(new MockTask());
- std::unique_ptr<MockTask> delayed_task(new MockTask());
-
- EXPECT_CALL(*task, run()).Times(0);
- EXPECT_CALL(*delayed_task, run()).Times(0);
-
- RunOnWorkerThread(FROM_HERE, base::Bind(&shutdownOnThread, thread_.get()));
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- task.release());
- thread_->getWebTaskRunner()->postDelayedTask(blink::WebTraceLocation(),
- task.release(), 50ll);
- thread_.reset();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/worker_scheduler.cc b/chromium/components/scheduler/child/worker_scheduler.cc
deleted file mode 100644
index 1bf3cb0ea48..00000000000
--- a/chromium/components/scheduler/child/worker_scheduler.cc
+++ /dev/null
@@ -1,28 +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 "components/scheduler/child/worker_scheduler.h"
-
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-#include "components/scheduler/child/worker_scheduler_impl.h"
-
-namespace scheduler {
-
-WorkerScheduler::WorkerScheduler() {
-}
-
-WorkerScheduler::~WorkerScheduler() {
-}
-
-// static
-std::unique_ptr<WorkerScheduler> WorkerScheduler::Create(
- scoped_refptr<SchedulerTqmDelegate> main_task_runner) {
- return base::WrapUnique(new WorkerSchedulerImpl(std::move(main_task_runner)));
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/worker_scheduler.h b/chromium/components/scheduler/child/worker_scheduler.h
deleted file mode 100644
index 076b5385edd..00000000000
--- a/chromium/components/scheduler/child/worker_scheduler.h
+++ /dev/null
@@ -1,40 +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 COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_H_
-#define COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "components/scheduler/child/child_scheduler.h"
-#include "components/scheduler/child/single_thread_idle_task_runner.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-class MessageLoop;
-}
-
-namespace scheduler {
-class SchedulerTqmDelegate;
-
-class SCHEDULER_EXPORT WorkerScheduler : public ChildScheduler {
- public:
- ~WorkerScheduler() override;
- static std::unique_ptr<WorkerScheduler> Create(
- scoped_refptr<SchedulerTqmDelegate> main_task_runner);
-
- // Must be called before the scheduler can be used. Does any post construction
- // initialization needed such as initializing idle period detection.
- virtual void Init() = 0;
-
- protected:
- WorkerScheduler();
- DISALLOW_COPY_AND_ASSIGN(WorkerScheduler);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_H_
diff --git a/chromium/components/scheduler/child/worker_scheduler_impl.cc b/chromium/components/scheduler/child/worker_scheduler_impl.cc
deleted file mode 100644
index e74328d10fc..00000000000
--- a/chromium/components/scheduler/child/worker_scheduler_impl.cc
+++ /dev/null
@@ -1,93 +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 "components/scheduler/child/worker_scheduler_impl.h"
-
-#include "base/bind.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-
-namespace scheduler {
-
-WorkerSchedulerImpl::WorkerSchedulerImpl(
- scoped_refptr<SchedulerTqmDelegate> main_task_runner)
- : helper_(main_task_runner,
- "worker.scheduler",
- TRACE_DISABLED_BY_DEFAULT("worker.scheduler"),
- TRACE_DISABLED_BY_DEFAULT("worker.scheduler.debug")),
- idle_helper_(&helper_,
- this,
- "worker.scheduler",
- TRACE_DISABLED_BY_DEFAULT("worker.scheduler"),
- "WorkerSchedulerIdlePeriod",
- base::TimeDelta::FromMilliseconds(300)) {
- initialized_ = false;
- TRACE_EVENT_OBJECT_CREATED_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this);
-}
-
-WorkerSchedulerImpl::~WorkerSchedulerImpl() {
- TRACE_EVENT_OBJECT_DELETED_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this);
-}
-
-void WorkerSchedulerImpl::Init() {
- initialized_ = true;
- idle_helper_.EnableLongIdlePeriod();
-}
-
-scoped_refptr<TaskQueue> WorkerSchedulerImpl::DefaultTaskRunner() {
- DCHECK(initialized_);
- return helper_.DefaultTaskRunner();
-}
-
-scoped_refptr<SingleThreadIdleTaskRunner>
-WorkerSchedulerImpl::IdleTaskRunner() {
- DCHECK(initialized_);
- return idle_helper_.IdleTaskRunner();
-}
-
-bool WorkerSchedulerImpl::CanExceedIdleDeadlineIfRequired() const {
- DCHECK(initialized_);
- return idle_helper_.CanExceedIdleDeadlineIfRequired();
-}
-
-bool WorkerSchedulerImpl::ShouldYieldForHighPriorityWork() {
- // We don't consider any work as being high priority on workers.
- return false;
-}
-
-void WorkerSchedulerImpl::AddTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- DCHECK(initialized_);
- helper_.AddTaskObserver(task_observer);
-}
-
-void WorkerSchedulerImpl::RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- DCHECK(initialized_);
- helper_.RemoveTaskObserver(task_observer);
-}
-
-void WorkerSchedulerImpl::Shutdown() {
- DCHECK(initialized_);
- helper_.Shutdown();
-}
-
-SchedulerHelper* WorkerSchedulerImpl::GetSchedulerHelperForTesting() {
- return &helper_;
-}
-
-bool WorkerSchedulerImpl::CanEnterLongIdlePeriod(base::TimeTicks,
- base::TimeDelta*) {
- return true;
-}
-
-base::TimeTicks WorkerSchedulerImpl::CurrentIdleTaskDeadlineForTesting() const {
- return idle_helper_.CurrentIdleTaskDeadline();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/child/worker_scheduler_impl.h b/chromium/components/scheduler/child/worker_scheduler_impl.h
deleted file mode 100644
index 83446cfde49..00000000000
--- a/chromium/components/scheduler/child/worker_scheduler_impl.h
+++ /dev/null
@@ -1,66 +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 COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_IMPL_H_
-#define COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_IMPL_H_
-
-#include "base/macros.h"
-#include "components/scheduler/child/idle_helper.h"
-#include "components/scheduler/child/scheduler_helper.h"
-#include "components/scheduler/child/worker_scheduler.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-namespace trace_event {
-class ConvertableToTraceFormat;
-}
-}
-
-namespace scheduler {
-
-class SchedulerTqmDelegate;
-
-class SCHEDULER_EXPORT WorkerSchedulerImpl : public WorkerScheduler,
- public IdleHelper::Delegate {
- public:
- explicit WorkerSchedulerImpl(
- scoped_refptr<SchedulerTqmDelegate> main_task_runner);
- ~WorkerSchedulerImpl() override;
-
- // WorkerScheduler implementation:
- scoped_refptr<TaskQueue> DefaultTaskRunner() override;
- scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override;
- bool CanExceedIdleDeadlineIfRequired() const override;
- bool ShouldYieldForHighPriorityWork() override;
- void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override;
- void RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) override;
- void Init() override;
- void Shutdown() override;
-
- SchedulerHelper* GetSchedulerHelperForTesting();
- base::TimeTicks CurrentIdleTaskDeadlineForTesting() const;
-
- protected:
- // IdleHelper::Delegate implementation:
- bool CanEnterLongIdlePeriod(
- base::TimeTicks now,
- base::TimeDelta* next_long_idle_period_delay_out) override;
- void IsNotQuiescent() override {}
- void OnIdlePeriodStarted() override {}
- void OnIdlePeriodEnded() override {}
-
- private:
- void MaybeStartLongIdlePeriod();
-
- SchedulerHelper helper_;
- IdleHelper idle_helper_;
- bool initialized_;
-
- DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImpl);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_IMPL_H_
diff --git a/chromium/components/scheduler/child/worker_scheduler_impl_unittest.cc b/chromium/components/scheduler/child/worker_scheduler_impl_unittest.cc
deleted file mode 100644
index c5ff4a6253e..00000000000
--- a/chromium/components/scheduler/child/worker_scheduler_impl_unittest.cc
+++ /dev/null
@@ -1,385 +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 "components/scheduler/child/worker_scheduler_impl.h"
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::ElementsAreArray;
-
-namespace scheduler {
-
-namespace {
-void NopTask() {
-}
-
-int TimeTicksToIntMs(const base::TimeTicks& time) {
- return static_cast<int>((time - base::TimeTicks()).InMilliseconds());
-}
-
-void RecordTimelineTask(std::vector<std::string>* timeline,
- base::SimpleTestTickClock* clock) {
- timeline->push_back(base::StringPrintf("run RecordTimelineTask @ %d",
- TimeTicksToIntMs(clock->NowTicks())));
-}
-
-void AppendToVectorTestTask(std::vector<std::string>* vector,
- std::string value) {
- vector->push_back(value);
-}
-
-void AppendToVectorIdleTestTask(std::vector<std::string>* vector,
- std::string value,
- base::TimeTicks deadline) {
- AppendToVectorTestTask(vector, value);
-}
-
-void TimelineIdleTestTask(std::vector<std::string>* timeline,
- base::TimeTicks deadline) {
- timeline->push_back(base::StringPrintf("run TimelineIdleTestTask deadline %d",
- TimeTicksToIntMs(deadline)));
-}
-
-}; // namespace
-
-class WorkerSchedulerImplForTest : public WorkerSchedulerImpl {
- public:
- WorkerSchedulerImplForTest(
- scoped_refptr<SchedulerTqmDelegate> main_task_runner,
- base::SimpleTestTickClock* clock_)
- : WorkerSchedulerImpl(main_task_runner),
- clock_(clock_),
- timeline_(nullptr) {}
-
- void RecordTimelineEvents(std::vector<std::string>* timeline) {
- timeline_ = timeline;
- }
-
- private:
- bool CanEnterLongIdlePeriod(
- base::TimeTicks now,
- base::TimeDelta* next_long_idle_period_delay_out) override {
- if (timeline_) {
- timeline_->push_back(base::StringPrintf("CanEnterLongIdlePeriod @ %d",
- TimeTicksToIntMs(now)));
- }
- return WorkerSchedulerImpl::CanEnterLongIdlePeriod(
- now, next_long_idle_period_delay_out);
- }
-
- void IsNotQuiescent() override {
- if (timeline_) {
- timeline_->push_back(base::StringPrintf(
- "IsNotQuiescent @ %d", TimeTicksToIntMs(clock_->NowTicks())));
- }
- WorkerSchedulerImpl::IsNotQuiescent();
- }
-
- base::SimpleTestTickClock* clock_; // NOT OWNED
- std::vector<std::string>* timeline_; // NOT OWNED
-};
-
-class WorkerSchedulerImplTest : public testing::Test {
- public:
- WorkerSchedulerImplTest()
- : clock_(new base::SimpleTestTickClock()),
- mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_.get(), true)),
- main_task_runner_(SchedulerTqmDelegateForTest::Create(
- mock_task_runner_,
- base::WrapUnique(new TestTimeSource(clock_.get())))),
- scheduler_(
- new WorkerSchedulerImplForTest(main_task_runner_, clock_.get())),
- timeline_(nullptr) {
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- }
-
- ~WorkerSchedulerImplTest() override {}
-
- void TearDown() override {
- // Check that all tests stop posting tasks.
- while (mock_task_runner_->RunUntilIdle()) {
- }
- }
-
- void Init() {
- scheduler_->Init();
- default_task_runner_ = scheduler_->DefaultTaskRunner();
- idle_task_runner_ = scheduler_->IdleTaskRunner();
- timeline_ = nullptr;
- }
-
- void RecordTimelineEvents(std::vector<std::string>* timeline) {
- timeline_ = timeline;
- scheduler_->RecordTimelineEvents(timeline);
- }
-
- void RunUntilIdle() {
- if (timeline_) {
- timeline_->push_back(base::StringPrintf(
- "RunUntilIdle begin @ %d", TimeTicksToIntMs(clock_->NowTicks())));
- }
- mock_task_runner_->RunUntilIdle();
- if (timeline_) {
- timeline_->push_back(base::StringPrintf(
- "RunUntilIdle end @ %d", TimeTicksToIntMs(clock_->NowTicks())));
- }
- }
-
- // Helper for posting several tasks of specific types. |task_descriptor| is a
- // string with space delimited task identifiers. The first letter of each
- // task identifier specifies the task type:
- // - 'D': Default task
- // - 'I': Idle task
- void PostTestTasks(std::vector<std::string>* run_order,
- const std::string& task_descriptor) {
- std::istringstream stream(task_descriptor);
- while (!stream.eof()) {
- std::string task;
- stream >> task;
- switch (task[0]) {
- case 'D':
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
- break;
- case 'I':
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&AppendToVectorIdleTestTask, run_order, task));
- break;
- default:
- NOTREACHED();
- }
- }
- }
-
- static base::TimeDelta maximum_idle_period_duration() {
- return base::TimeDelta::FromMilliseconds(
- IdleHelper::kMaximumIdlePeriodMillis);
- }
-
- protected:
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- // Only one of mock_task_runner_ or message_loop_ will be set.
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
-
- scoped_refptr<SchedulerTqmDelegate> main_task_runner_;
- std::unique_ptr<WorkerSchedulerImplForTest> scheduler_;
- scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
- std::vector<std::string>* timeline_; // NOT OWNED
-
- DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImplTest);
-};
-
-TEST_F(WorkerSchedulerImplTest, TestPostDefaultTask) {
- Init();
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "D1 D2 D3 D4");
-
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D1"), std::string("D2"),
- std::string("D3"), std::string("D4")));
-}
-
-TEST_F(WorkerSchedulerImplTest, TestPostIdleTask) {
- Init();
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1");
-
- RunUntilIdle();
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("I1")));
-}
-
-TEST_F(WorkerSchedulerImplTest, TestPostDefaultAndIdleTasks) {
- Init();
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D2 D3 D4");
-
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D2"), std::string("D3"),
- std::string("D4"), std::string("I1")));
-}
-
-TEST_F(WorkerSchedulerImplTest, TestPostDefaultDelayedAndIdleTasks) {
- Init();
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D2 D3 D4");
-
- default_task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "DELAYED"),
- base::TimeDelta::FromMilliseconds(1000));
-
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D2"), std::string("D3"),
- std::string("D4"), std::string("I1"),
- std::string("DELAYED")));
-}
-
-TEST_F(WorkerSchedulerImplTest, TestIdleTaskWhenIsNotQuiescent) {
- std::vector<std::string> timeline;
- RecordTimelineEvents(&timeline);
- Init();
-
- timeline.push_back("Post default task");
- // Post a delayed task timed to occur mid way during the long idle period.
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
- base::Unretained(clock_.get())));
- RunUntilIdle();
-
- timeline.push_back("Post idle task");
- idle_task_runner_->PostIdleTask(FROM_HERE,
- base::Bind(&TimelineIdleTestTask, &timeline));
-
- RunUntilIdle();
-
- std::string expected_timeline[] = {"CanEnterLongIdlePeriod @ 5",
- "Post default task",
- "run RecordTimelineTask @ 5",
- "Post idle task",
- "IsNotQuiescent @ 5",
- "CanEnterLongIdlePeriod @ 305",
- "run TimelineIdleTestTask deadline 355"};
-
- EXPECT_THAT(timeline, ElementsAreArray(expected_timeline));
-}
-
-TEST_F(WorkerSchedulerImplTest, TestIdleDeadlineWithPendingDelayedTask) {
- std::vector<std::string> timeline;
- RecordTimelineEvents(&timeline);
- Init();
-
- timeline.push_back("Post delayed and idle tasks");
- // Post a delayed task timed to occur mid way during the long idle period.
- default_task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
- base::Unretained(clock_.get())),
- base::TimeDelta::FromMilliseconds(20));
- idle_task_runner_->PostIdleTask(FROM_HERE,
- base::Bind(&TimelineIdleTestTask, &timeline));
-
- RunUntilIdle();
-
- std::string expected_timeline[] = {
- "CanEnterLongIdlePeriod @ 5",
- "Post delayed and idle tasks",
- "CanEnterLongIdlePeriod @ 5",
- "run TimelineIdleTestTask deadline 25", // Note the short 20ms deadline.
- "run RecordTimelineTask @ 25"};
-
- EXPECT_THAT(timeline, ElementsAreArray(expected_timeline));
-}
-
-TEST_F(WorkerSchedulerImplTest,
- TestIdleDeadlineWithPendingDelayedTaskFarInTheFuture) {
- std::vector<std::string> timeline;
- RecordTimelineEvents(&timeline);
- Init();
-
- timeline.push_back("Post delayed and idle tasks");
- // Post a delayed task timed to occur well after the long idle period.
- default_task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
- base::Unretained(clock_.get())),
- base::TimeDelta::FromMilliseconds(500));
- idle_task_runner_->PostIdleTask(FROM_HERE,
- base::Bind(&TimelineIdleTestTask, &timeline));
-
- RunUntilIdle();
-
- std::string expected_timeline[] = {
- "CanEnterLongIdlePeriod @ 5",
- "Post delayed and idle tasks",
- "CanEnterLongIdlePeriod @ 5",
- "run TimelineIdleTestTask deadline 55", // Note the full 50ms deadline.
- "run RecordTimelineTask @ 505"};
-
- EXPECT_THAT(timeline, ElementsAreArray(expected_timeline));
-}
-
-TEST_F(WorkerSchedulerImplTest, TestPostIdleTaskAfterRunningUntilIdle) {
- Init();
-
- default_task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(1000));
- RunUntilIdle();
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 I2 D3");
-
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D3"), std::string("I1"),
- std::string("I2")));
-}
-
-TEST_F(WorkerSchedulerImplTest, TestLongIdlePeriodTimeline) {
- Init();
-
- std::vector<std::string> timeline;
- RecordTimelineEvents(&timeline);
-
- // The scheduler should not run the initiate_next_long_idle_period task if
- // there are no idle tasks and no other task woke up the scheduler, thus
- // the idle period deadline shouldn't update at the end of the current long
- // idle period.
- base::TimeTicks idle_period_deadline =
- scheduler_->CurrentIdleTaskDeadlineForTesting();
- clock_->Advance(maximum_idle_period_duration());
- RunUntilIdle();
-
- base::TimeTicks new_idle_period_deadline =
- scheduler_->CurrentIdleTaskDeadlineForTesting();
- EXPECT_EQ(idle_period_deadline, new_idle_period_deadline);
-
- // Posting a after-wakeup idle task also shouldn't wake the scheduler or
- // initiate the next long idle period.
- timeline.push_back("PostIdleTaskAfterWakeup");
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&TimelineIdleTestTask, &timeline));
- RunUntilIdle();
- new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting();
-
- // Running a normal task should initiate a new long idle period after waiting
- // 300ms for quiescence.
- timeline.push_back("Post RecordTimelineTask");
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
- base::Unretained(clock_.get())));
- RunUntilIdle();
-
- std::string expected_timeline[] = {
- "RunUntilIdle begin @ 55",
- "RunUntilIdle end @ 55",
- "PostIdleTaskAfterWakeup",
- "RunUntilIdle begin @ 55", // NOTE idle task doesn't run till later.
- "RunUntilIdle end @ 55",
- "Post RecordTimelineTask",
- "RunUntilIdle begin @ 55",
- "run RecordTimelineTask @ 55",
- "IsNotQuiescent @ 55", // NOTE we have to wait for quiescence.
- "CanEnterLongIdlePeriod @ 355",
- "run TimelineIdleTestTask deadline 405",
- "RunUntilIdle end @ 355"};
-
- EXPECT_THAT(timeline, ElementsAreArray(expected_timeline));
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/common/scheduler_switches.cc b/chromium/components/scheduler/common/scheduler_switches.cc
deleted file mode 100644
index 8498ee70629..00000000000
--- a/chromium/components/scheduler/common/scheduler_switches.cc
+++ /dev/null
@@ -1,15 +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 "components/scheduler/common/scheduler_switches.h"
-
-namespace scheduler {
-namespace switches {
-
-// Disable task throttling of timer tasks from background pages.
-const char kDisableBackgroundTimerThrottling[] =
- "disable-background-timer-throttling";
-
-} // namespace switches
-} // namespace scheduler
diff --git a/chromium/components/scheduler/common/scheduler_switches.h b/chromium/components/scheduler/common/scheduler_switches.h
deleted file mode 100644
index fd738e14b33..00000000000
--- a/chromium/components/scheduler/common/scheduler_switches.h
+++ /dev/null
@@ -1,16 +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 COMPONENTS_SCHEDULER_COMMON_SCHEDULER_SWITCHES_H_
-#define COMPONENTS_SCHEDULER_COMMON_SCHEDULER_SWITCHES_H_
-
-namespace scheduler {
-namespace switches {
-
-extern const char kDisableBackgroundTimerThrottling[];
-
-} // namespace switches
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_COMMON_SCHEDULER_SWITCHES_H_
diff --git a/chromium/components/scheduler/renderer/DEPS b/chromium/components/scheduler/renderer/DEPS
deleted file mode 100644
index f278ea0ac5b..00000000000
--- a/chromium/components/scheduler/renderer/DEPS
+++ /dev/null
@@ -1,18 +0,0 @@
-include_rules = [
- "+components/scheduler/base",
- "+components/scheduler/child",
- "+components/scheduler/common",
- "+components/scheduler/scheduler_export.h",
- "+cc/base",
- "+cc/output",
- "+ui/gfx",
- "+third_party/WebKit/public/platform",
- "+third_party/WebKit/public/web",
- "+v8",
-]
-
-specific_include_rules = {
- ".*test\.cc": [
- "+cc/test",
- ],
-}
diff --git a/chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain.cc b/chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain.cc
deleted file mode 100644
index 8d589a773fd..00000000000
--- a/chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h"
-
-namespace scheduler {
-
-AutoAdvancingVirtualTimeDomain::AutoAdvancingVirtualTimeDomain(
- base::TimeTicks initial_time)
- : VirtualTimeDomain(nullptr, initial_time),
- can_advance_virtual_time_(true) {}
-
-AutoAdvancingVirtualTimeDomain::~AutoAdvancingVirtualTimeDomain() {}
-
-bool AutoAdvancingVirtualTimeDomain::MaybeAdvanceTime() {
- base::TimeTicks run_time;
- if (!can_advance_virtual_time_ || !NextScheduledRunTime(&run_time)) {
- return false;
- }
- AdvanceTo(run_time);
- return true;
-}
-
-void AutoAdvancingVirtualTimeDomain::RequestWakeup(base::TimeTicks now,
- base::TimeDelta delay) {
- base::TimeTicks dummy;
- if (can_advance_virtual_time_ && !NextScheduledRunTime(&dummy))
- RequestDoWork();
-}
-
-void AutoAdvancingVirtualTimeDomain::SetCanAdvanceVirtualTime(
- bool can_advance_virtual_time) {
- can_advance_virtual_time_ = can_advance_virtual_time;
- if (can_advance_virtual_time_)
- RequestDoWork();
-}
-
-const char* AutoAdvancingVirtualTimeDomain::GetName() const {
- return "AutoAdvancingVirtualTimeDomain";
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain.h b/chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain.h
deleted file mode 100644
index 82b58d69438..00000000000
--- a/chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain.h
+++ /dev/null
@@ -1,45 +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 COMPONENTS_SCHEDULER_RENDERER_AUTO_ADVANCING_VIRTUAL_TIME_DOMAIN_H_
-#define COMPONENTS_SCHEDULER_RENDERER_AUTO_ADVANCING_VIRTUAL_TIME_DOMAIN_H_
-
-#include "base/macros.h"
-#include "components/scheduler/base/virtual_time_domain.h"
-
-namespace scheduler {
-
-// A time domain that runs tasks sequentially in time order but doesn't sleep
-// between delayed tasks.
-//
-// KEY: A-E are delayed tasks
-// | A B C D E (Execution with RealTimeDomain)
-// |-----------------------------> time
-//
-// |ABCDE (Execution with AutoAdvancingVirtualTimeDomain)
-// |-----------------------------> time
-class SCHEDULER_EXPORT AutoAdvancingVirtualTimeDomain
- : public VirtualTimeDomain {
- public:
- explicit AutoAdvancingVirtualTimeDomain(base::TimeTicks initial_time);
- ~AutoAdvancingVirtualTimeDomain() override;
-
- // TimeDomain implementation:
- bool MaybeAdvanceTime() override;
- void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override;
- const char* GetName() const override;
-
- // Controls whether or not virtual time is allowed to advance, when the
- // TaskQueueManager runs out of immediate work to do.
- void SetCanAdvanceVirtualTime(bool can_advance_virtual_time);
-
- private:
- bool can_advance_virtual_time_;
-
- DISALLOW_COPY_AND_ASSIGN(AutoAdvancingVirtualTimeDomain);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_AUTO_ADVANCING_VIRTUAL_TIME_DOMAIN_H_
diff --git a/chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc b/chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
deleted file mode 100644
index 578c8f7f27a..00000000000
--- a/chromium/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
+++ /dev/null
@@ -1,94 +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 "components/scheduler/renderer/auto_advancing_virtual_time_domain.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/task_queue_manager.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace scheduler {
-
-class AutoAdvancingVirtualTimeDomainTest : public testing::Test {
- public:
- AutoAdvancingVirtualTimeDomainTest() {}
- ~AutoAdvancingVirtualTimeDomainTest() override {}
-
- void SetUp() override {
- clock_.reset(new base::SimpleTestTickClock());
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
-
- test_time_source_.reset(new TestTimeSource(clock_.get()));
- mock_task_runner_ = make_scoped_refptr(
- new cc::OrderedSimpleTaskRunner(clock_.get(), false));
- main_task_runner_ = SchedulerTqmDelegateForTest::Create(
- mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get())));
- manager_ = base::WrapUnique(
- new TaskQueueManager(main_task_runner_, "test.scheduler",
- "test.scheduler", "test.scheduler.debug"));
- task_runner_ =
- manager_->NewTaskQueue(TaskQueue::Spec("test_task_queue"));
- initial_time_= clock_->NowTicks();
- auto_advancing_time_domain_.reset(
- new AutoAdvancingVirtualTimeDomain(initial_time_));
- manager_->RegisterTimeDomain(auto_advancing_time_domain_.get());
- task_runner_->SetTimeDomain(auto_advancing_time_domain_.get());
- }
-
- void TearDown() override {
- task_runner_->UnregisterTaskQueue();
- manager_->UnregisterTimeDomain(auto_advancing_time_domain_.get());
- }
-
- base::TimeTicks initial_time_;
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- std::unique_ptr<TestTimeSource> test_time_source_;
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
- scoped_refptr<SchedulerTqmDelegate> main_task_runner_;
- std::unique_ptr<TaskQueueManager> manager_;
- scoped_refptr<TaskQueue> task_runner_;
- std::unique_ptr<AutoAdvancingVirtualTimeDomain> auto_advancing_time_domain_;
-};
-
-namespace {
-void NopTask(bool* task_run) {
- *task_run = true;
-}
-} // namesapce
-
-TEST_F(AutoAdvancingVirtualTimeDomainTest, VirtualTimeAdvances) {
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
- bool task_run = false;
- task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(NopTask, &task_run), delay);
-
- mock_task_runner_->RunUntilIdle();
-
- EXPECT_EQ(initial_time_, clock_->NowTicks());
- EXPECT_EQ(initial_time_ + delay,
- auto_advancing_time_domain_->CreateLazyNow().Now());
- EXPECT_TRUE(task_run);
-}
-
-TEST_F(AutoAdvancingVirtualTimeDomainTest, VirtualTimeDoesNotAdvance) {
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
- bool task_run = false;
- task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(NopTask, &task_run), delay);
-
- auto_advancing_time_domain_->SetCanAdvanceVirtualTime(false);
-
- mock_task_runner_->RunUntilIdle();
-
- EXPECT_EQ(initial_time_, clock_->NowTicks());
- EXPECT_EQ(initial_time_, auto_advancing_time_domain_->CreateLazyNow().Now());
- EXPECT_FALSE(task_run);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/deadline_task_runner.cc b/chromium/components/scheduler/renderer/deadline_task_runner.cc
deleted file mode 100644
index fd6859f3208..00000000000
--- a/chromium/components/scheduler/renderer/deadline_task_runner.cc
+++ /dev/null
@@ -1,40 +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 "components/scheduler/renderer/deadline_task_runner.h"
-
-#include "base/bind.h"
-
-namespace scheduler {
-
-DeadlineTaskRunner::DeadlineTaskRunner(
- const base::Closure& callback,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : callback_(callback), task_runner_(task_runner) {
- cancelable_run_internal_.Reset(
- base::Bind(&DeadlineTaskRunner::RunInternal, base::Unretained(this)));
-}
-
-DeadlineTaskRunner::~DeadlineTaskRunner() {
-}
-
-void DeadlineTaskRunner::SetDeadline(const tracked_objects::Location& from_here,
- base::TimeDelta delay,
- base::TimeTicks now) {
- DCHECK(delay > base::TimeDelta());
- base::TimeTicks deadline = now + delay;
- if (deadline_.is_null() || deadline < deadline_) {
- deadline_ = deadline;
- cancelable_run_internal_.Cancel();
- task_runner_->PostDelayedTask(from_here,
- cancelable_run_internal_.callback(), delay);
- }
-}
-
-void DeadlineTaskRunner::RunInternal() {
- deadline_ = base::TimeTicks();
- callback_.Run();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/deadline_task_runner.h b/chromium/components/scheduler/renderer/deadline_task_runner.h
deleted file mode 100644
index 9ac4823277b..00000000000
--- a/chromium/components/scheduler/renderer/deadline_task_runner.h
+++ /dev/null
@@ -1,50 +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 COMPONENTS_SCHEDULER_RENDERER_DEADLINE_TASK_RUNNER_H_
-#define COMPONENTS_SCHEDULER_RENDERER_DEADLINE_TASK_RUNNER_H_
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/time/time.h"
-#include "components/scheduler/base/cancelable_closure_holder.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-// Runs a posted task at latest by a given deadline, but possibly sooner.
-class SCHEDULER_EXPORT DeadlineTaskRunner {
- public:
- DeadlineTaskRunner(const base::Closure& callback,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
-
- ~DeadlineTaskRunner();
-
- // If there is no outstanding task then a task is posted to run after |delay|.
- // If there is an outstanding task which is scheduled to run:
- // a) sooner - then this is a NOP.
- // b) later - then the outstanding task is cancelled and a new task is
- // posted to run after |delay|.
- //
- // Once the deadline task has run, we reset.
- void SetDeadline(const tracked_objects::Location& from_here,
- base::TimeDelta delay,
- base::TimeTicks now);
-
- private:
- void RunInternal();
-
- CancelableClosureHolder cancelable_run_internal_;
- base::Closure callback_;
- base::TimeTicks deadline_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(DeadlineTaskRunner);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_DEADLINE_TASK_RUNNER_H_
diff --git a/chromium/components/scheduler/renderer/deadline_task_runner_unittest.cc b/chromium/components/scheduler/renderer/deadline_task_runner_unittest.cc
deleted file mode 100644
index 058a341fe27..00000000000
--- a/chromium/components/scheduler/renderer/deadline_task_runner_unittest.cc
+++ /dev/null
@@ -1,101 +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 "components/scheduler/renderer/deadline_task_runner.h"
-
-#include <memory>
-
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace scheduler {
-
-class DeadlineTaskRunnerTest : public testing::Test {
- public:
- DeadlineTaskRunnerTest() {}
- ~DeadlineTaskRunnerTest() override {}
-
- void SetUp() override {
- clock_.reset(new base::SimpleTestTickClock());
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- mock_task_runner_ = new cc::OrderedSimpleTaskRunner(clock_.get(), true);
- deadline_task_runner_.reset(new DeadlineTaskRunner(
- base::Bind(&DeadlineTaskRunnerTest::TestTask, base::Unretained(this)),
- mock_task_runner_));
- run_times_.clear();
- }
-
- bool RunUntilIdle() { return mock_task_runner_->RunUntilIdle(); }
-
- void TestTask() { run_times_.push_back(clock_->NowTicks()); }
-
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
- std::unique_ptr<DeadlineTaskRunner> deadline_task_runner_;
- std::vector<base::TimeTicks> run_times_;
-};
-
-TEST_F(DeadlineTaskRunnerTest, RunOnce) {
- base::TimeTicks start_time = clock_->NowTicks();
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
- deadline_task_runner_->SetDeadline(FROM_HERE, delay, clock_->NowTicks());
- RunUntilIdle();
-
- EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay));
-};
-
-TEST_F(DeadlineTaskRunnerTest, RunTwice) {
- base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks deadline1 = clock_->NowTicks() + delay1;
- deadline_task_runner_->SetDeadline(FROM_HERE, delay1, clock_->NowTicks());
- RunUntilIdle();
-
- base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(100);
- base::TimeTicks deadline2 = clock_->NowTicks() + delay2;
- deadline_task_runner_->SetDeadline(FROM_HERE, delay2, clock_->NowTicks());
- RunUntilIdle();
-
- EXPECT_THAT(run_times_, testing::ElementsAre(deadline1, deadline2));
-};
-
-TEST_F(DeadlineTaskRunnerTest, EarlierDeadlinesTakePrecidence) {
- base::TimeTicks start_time = clock_->NowTicks();
- base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(1);
- base::TimeDelta delay10 = base::TimeDelta::FromMilliseconds(10);
- base::TimeDelta delay100 = base::TimeDelta::FromMilliseconds(100);
- deadline_task_runner_->SetDeadline(FROM_HERE, delay100, clock_->NowTicks());
- deadline_task_runner_->SetDeadline(FROM_HERE, delay10, clock_->NowTicks());
- deadline_task_runner_->SetDeadline(FROM_HERE, delay1, clock_->NowTicks());
-
- RunUntilIdle();
-
- EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay1));
-};
-
-TEST_F(DeadlineTaskRunnerTest, LaterDeadlinesIgnored) {
- base::TimeTicks start_time = clock_->NowTicks();
- base::TimeDelta delay100 = base::TimeDelta::FromMilliseconds(100);
- base::TimeDelta delay10000 = base::TimeDelta::FromMilliseconds(10000);
- deadline_task_runner_->SetDeadline(FROM_HERE, delay100, clock_->NowTicks());
- deadline_task_runner_->SetDeadline(FROM_HERE, delay10000, clock_->NowTicks());
-
- RunUntilIdle();
-
- EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay100));
-};
-
-TEST_F(DeadlineTaskRunnerTest, DeleteDeadlineTaskRunnerAfterPosting) {
- deadline_task_runner_->SetDeadline(
- FROM_HERE, base::TimeDelta::FromMilliseconds(10), clock_->NowTicks());
-
- // Deleting the pending task should cancel it.
- deadline_task_runner_.reset(nullptr);
- RunUntilIdle();
-
- EXPECT_TRUE(run_times_.empty());
-};
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/idle_time_estimator.cc b/chromium/components/scheduler/renderer/idle_time_estimator.cc
deleted file mode 100644
index 30c91561b5d..00000000000
--- a/chromium/components/scheduler/renderer/idle_time_estimator.cc
+++ /dev/null
@@ -1,74 +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 "components/scheduler/renderer/idle_time_estimator.h"
-
-#include "base/time/default_tick_clock.h"
-
-namespace scheduler {
-
-IdleTimeEstimator::IdleTimeEstimator(
- const scoped_refptr<TaskQueue>& compositor_task_runner,
- base::TickClock* time_source,
- int sample_count,
- double estimation_percentile)
- : compositor_task_runner_(compositor_task_runner),
- per_frame_compositor_task_runtime_(sample_count),
- time_source_(time_source),
- estimation_percentile_(estimation_percentile),
- nesting_level_(0),
- did_commit_(false) {
- compositor_task_runner_->AddTaskObserver(this);
-}
-
-IdleTimeEstimator::~IdleTimeEstimator() {
- compositor_task_runner_->RemoveTaskObserver(this);
-}
-
-base::TimeDelta IdleTimeEstimator::GetExpectedIdleDuration(
- base::TimeDelta compositor_frame_interval) const {
- base::TimeDelta expected_compositor_task_runtime_ =
- per_frame_compositor_task_runtime_.Percentile(estimation_percentile_);
- return std::max(base::TimeDelta(), compositor_frame_interval -
- expected_compositor_task_runtime_);
-}
-
-void IdleTimeEstimator::DidCommitFrameToCompositor() {
- // This will run inside of a WillProcessTask / DidProcessTask pair, let
- // DidProcessTask know a frame was comitted.
- if (nesting_level_ == 1)
- did_commit_ = true;
-}
-
-void IdleTimeEstimator::Clear() {
- task_start_time_ = base::TimeTicks();
- prev_commit_time_ = base::TimeTicks();
- cumulative_compositor_runtime_ = base::TimeDelta();
- per_frame_compositor_task_runtime_.Clear();
- did_commit_ = false;
-}
-
-void IdleTimeEstimator::WillProcessTask(const base::PendingTask& pending_task) {
- nesting_level_++;
- if (nesting_level_ == 1)
- task_start_time_ = time_source_->NowTicks();
-}
-
-void IdleTimeEstimator::DidProcessTask(const base::PendingTask& pending_task) {
- nesting_level_--;
- DCHECK_GE(nesting_level_, 0);
- if (nesting_level_ != 0)
- return;
-
- cumulative_compositor_runtime_ += time_source_->NowTicks() - task_start_time_;
-
- if (did_commit_) {
- per_frame_compositor_task_runtime_.InsertSample(
- cumulative_compositor_runtime_);
- cumulative_compositor_runtime_ = base::TimeDelta();
- did_commit_ = false;
- }
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/idle_time_estimator.h b/chromium/components/scheduler/renderer/idle_time_estimator.h
deleted file mode 100644
index 3664a384f67..00000000000
--- a/chromium/components/scheduler/renderer/idle_time_estimator.h
+++ /dev/null
@@ -1,58 +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 COMPONENTS_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_
-#define COMPONENTS_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/time/tick_clock.h"
-#include "cc/base/rolling_time_delta_history.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-// Estimates how much idle time there is available. Ignores nested tasks.
-class SCHEDULER_EXPORT IdleTimeEstimator
- : public base::MessageLoop::TaskObserver {
- public:
- IdleTimeEstimator(const scoped_refptr<TaskQueue>& compositor_task_runner,
- base::TickClock* time_source,
- int sample_count,
- double estimation_percentile);
-
- ~IdleTimeEstimator() override;
-
- // Expected Idle time is defined as: |compositor_frame_interval| minus
- // expected compositor task duration.
- base::TimeDelta GetExpectedIdleDuration(
- base::TimeDelta compositor_frame_interval) const;
-
- void DidCommitFrameToCompositor();
-
- void Clear();
-
- // TaskObserver implementation:
- void WillProcessTask(const base::PendingTask& pending_task) override;
- void DidProcessTask(const base::PendingTask& pending_task) override;
-
- private:
- scoped_refptr<TaskQueue> compositor_task_runner_;
- cc::RollingTimeDeltaHistory per_frame_compositor_task_runtime_;
- base::TickClock* time_source_; // NOT OWNED
- double estimation_percentile_;
-
- base::TimeTicks task_start_time_;
- base::TimeTicks prev_commit_time_;
- base::TimeDelta cumulative_compositor_runtime_;
- int nesting_level_;
- bool did_commit_;
-
- DISALLOW_COPY_AND_ASSIGN(IdleTimeEstimator);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_
diff --git a/chromium/components/scheduler/renderer/idle_time_estimator_unittest.cc b/chromium/components/scheduler/renderer/idle_time_estimator_unittest.cc
deleted file mode 100644
index c50ad837240..00000000000
--- a/chromium/components/scheduler/renderer/idle_time_estimator_unittest.cc
+++ /dev/null
@@ -1,167 +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 "components/scheduler/renderer/idle_time_estimator.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/task_queue_manager.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace scheduler {
-
-class IdleTimeEstimatorForTest : public IdleTimeEstimator {
- public:
- IdleTimeEstimatorForTest(
- const scoped_refptr<TaskQueue>& compositor_task_runner,
- TestTimeSource* test_time_source,
- int sample_count,
- double estimation_percentile)
- : IdleTimeEstimator(compositor_task_runner,
- test_time_source,
- sample_count,
- estimation_percentile) {}
-};
-
-class IdleTimeEstimatorTest : public testing::Test {
- public:
- IdleTimeEstimatorTest()
- : frame_length_(base::TimeDelta::FromMilliseconds(16)) {}
-
- ~IdleTimeEstimatorTest() override {}
-
- void SetUp() override {
- clock_.reset(new base::SimpleTestTickClock());
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- test_time_source_.reset(new TestTimeSource(clock_.get()));
- mock_task_runner_ = make_scoped_refptr(
- new cc::OrderedSimpleTaskRunner(clock_.get(), false));
- main_task_runner_ = SchedulerTqmDelegateForTest::Create(
- mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get())));
- manager_ = base::WrapUnique(
- new TaskQueueManager(main_task_runner_, "test.scheduler",
- "test.scheduler", "test.scheduler.debug"));
- compositor_task_runner_ =
- manager_->NewTaskQueue(TaskQueue::Spec("compositor_tq"));
- estimator_.reset(new IdleTimeEstimatorForTest(
- compositor_task_runner_, test_time_source_.get(), 10, 50));
- }
-
- void SimulateFrameWithOneCompositorTask(int compositor_time) {
- base::TimeDelta non_idle_time =
- base::TimeDelta::FromMilliseconds(compositor_time);
- base::PendingTask task(FROM_HERE, base::Closure());
- estimator_->WillProcessTask(task);
- clock_->Advance(non_idle_time);
- estimator_->DidCommitFrameToCompositor();
- estimator_->DidProcessTask(task);
- if (non_idle_time < frame_length_)
- clock_->Advance(frame_length_ - non_idle_time);
- }
-
- void SimulateFrameWithTwoCompositorTasks(int compositor_time1,
- int compositor_time2) {
- base::TimeDelta non_idle_time1 =
- base::TimeDelta::FromMilliseconds(compositor_time1);
- base::TimeDelta non_idle_time2 =
- base::TimeDelta::FromMilliseconds(compositor_time2);
- base::PendingTask task(FROM_HERE, base::Closure());
- estimator_->WillProcessTask(task);
- clock_->Advance(non_idle_time1);
- estimator_->DidProcessTask(task);
-
- estimator_->WillProcessTask(task);
- clock_->Advance(non_idle_time2);
- estimator_->DidCommitFrameToCompositor();
- estimator_->DidProcessTask(task);
-
- base::TimeDelta idle_time = frame_length_ - non_idle_time1 - non_idle_time2;
- clock_->Advance(idle_time);
- }
-
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- std::unique_ptr<TestTimeSource> test_time_source_;
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
- scoped_refptr<SchedulerTqmDelegate> main_task_runner_;
- std::unique_ptr<TaskQueueManager> manager_;
- scoped_refptr<TaskQueue> compositor_task_runner_;
- std::unique_ptr<IdleTimeEstimatorForTest> estimator_;
- const base::TimeDelta frame_length_;
-};
-
-TEST_F(IdleTimeEstimatorTest, InitialTimeEstimateWithNoData) {
- EXPECT_EQ(frame_length_, estimator_->GetExpectedIdleDuration(frame_length_));
-}
-
-TEST_F(IdleTimeEstimatorTest, BasicEstimation_SteadyState) {
- SimulateFrameWithOneCompositorTask(5);
- SimulateFrameWithOneCompositorTask(5);
-
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
- estimator_->GetExpectedIdleDuration(frame_length_));
-}
-
-TEST_F(IdleTimeEstimatorTest, BasicEstimation_Variable) {
- SimulateFrameWithOneCompositorTask(5);
- SimulateFrameWithOneCompositorTask(6);
- SimulateFrameWithOneCompositorTask(7);
- SimulateFrameWithOneCompositorTask(7);
- SimulateFrameWithOneCompositorTask(7);
- SimulateFrameWithOneCompositorTask(8);
-
- // We expect it to return the median.
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(9),
- estimator_->GetExpectedIdleDuration(frame_length_));
-}
-
-TEST_F(IdleTimeEstimatorTest, NoIdleTime) {
- SimulateFrameWithOneCompositorTask(100);
- SimulateFrameWithOneCompositorTask(100);
-
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(0),
- estimator_->GetExpectedIdleDuration(frame_length_));
-}
-
-TEST_F(IdleTimeEstimatorTest, Clear) {
- SimulateFrameWithOneCompositorTask(5);
- SimulateFrameWithOneCompositorTask(5);
-
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
- estimator_->GetExpectedIdleDuration(frame_length_));
- estimator_->Clear();
-
- EXPECT_EQ(frame_length_, estimator_->GetExpectedIdleDuration(frame_length_));
-}
-
-TEST_F(IdleTimeEstimatorTest, Estimation_MultipleTasks) {
- SimulateFrameWithTwoCompositorTasks(1, 4);
- SimulateFrameWithTwoCompositorTasks(1, 4);
-
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
- estimator_->GetExpectedIdleDuration(frame_length_));
-}
-
-TEST_F(IdleTimeEstimatorTest, IgnoresNestedTasks) {
- SimulateFrameWithOneCompositorTask(5);
- SimulateFrameWithOneCompositorTask(5);
-
- base::PendingTask task(FROM_HERE, base::Closure());
- estimator_->WillProcessTask(task);
- SimulateFrameWithTwoCompositorTasks(4, 4);
- SimulateFrameWithTwoCompositorTasks(4, 4);
- SimulateFrameWithTwoCompositorTasks(4, 4);
- SimulateFrameWithTwoCompositorTasks(4, 4);
- estimator_->DidCommitFrameToCompositor();
- estimator_->DidProcessTask(task);
-
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
- estimator_->GetExpectedIdleDuration(frame_length_));
-}
-
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/render_widget_scheduling_state.cc b/chromium/components/scheduler/renderer/render_widget_scheduling_state.cc
deleted file mode 100644
index 77e99390f8c..00000000000
--- a/chromium/components/scheduler/renderer/render_widget_scheduling_state.cc
+++ /dev/null
@@ -1,65 +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 "components/scheduler/renderer/render_widget_scheduling_state.h"
-
-#include "components/scheduler/renderer/render_widget_signals.h"
-
-namespace scheduler {
-
-RenderWidgetSchedulingState::RenderWidgetSchedulingState(
- RenderWidgetSignals* render_widget_scheduling_signals)
- : render_widget_signals_(render_widget_scheduling_signals),
- hidden_(false),
- has_touch_handler_(false) {
- render_widget_signals_->IncNumVisibleRenderWidgets();
-}
-
-RenderWidgetSchedulingState::~RenderWidgetSchedulingState() {
- if (hidden_)
- return;
-
- render_widget_signals_->DecNumVisibleRenderWidgets();
-
- if (has_touch_handler_) {
- render_widget_signals_->DecNumVisibleRenderWidgetsWithTouchHandlers();
- }
-}
-
-void RenderWidgetSchedulingState::SetHidden(bool hidden) {
- if (hidden_ == hidden)
- return;
-
- hidden_ = hidden;
-
- if (hidden_) {
- render_widget_signals_->DecNumVisibleRenderWidgets();
- if (has_touch_handler_) {
- render_widget_signals_->DecNumVisibleRenderWidgetsWithTouchHandlers();
- }
- } else {
- render_widget_signals_->IncNumVisibleRenderWidgets();
- if (has_touch_handler_) {
- render_widget_signals_->IncNumVisibleRenderWidgetsWithTouchHandlers();
- }
- }
-}
-
-void RenderWidgetSchedulingState::SetHasTouchHandler(bool has_touch_handler) {
- if (has_touch_handler_ == has_touch_handler)
- return;
-
- has_touch_handler_ = has_touch_handler;
-
- if (hidden_)
- return;
-
- if (has_touch_handler_) {
- render_widget_signals_->IncNumVisibleRenderWidgetsWithTouchHandlers();
- } else {
- render_widget_signals_->DecNumVisibleRenderWidgetsWithTouchHandlers();
- }
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/render_widget_scheduling_state.h b/chromium/components/scheduler/renderer/render_widget_scheduling_state.h
deleted file mode 100644
index 7ad042733dd..00000000000
--- a/chromium/components/scheduler/renderer/render_widget_scheduling_state.h
+++ /dev/null
@@ -1,34 +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 COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SCHEDULING_STATE_H_
-#define COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SCHEDULING_STATE_H_
-
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-class RenderWidgetSignals;
-
-class SCHEDULER_EXPORT RenderWidgetSchedulingState {
- public:
- void SetHidden(bool hidden);
- void SetHasTouchHandler(bool has_touch_handler);
-
- ~RenderWidgetSchedulingState();
-
- private:
- friend class RenderWidgetSignals;
-
- explicit RenderWidgetSchedulingState(
- RenderWidgetSignals* render_widget_scheduling_signals);
-
- RenderWidgetSignals* render_widget_signals_; // NOT OWNED
- bool hidden_;
- bool has_touch_handler_;
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SCHEDULING_STATE_H_
diff --git a/chromium/components/scheduler/renderer/render_widget_signals.cc b/chromium/components/scheduler/renderer/render_widget_signals.cc
deleted file mode 100644
index 800103cd2c0..00000000000
--- a/chromium/components/scheduler/renderer/render_widget_signals.cc
+++ /dev/null
@@ -1,63 +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 "components/scheduler/renderer/render_widget_signals.h"
-
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "components/scheduler/renderer/render_widget_scheduling_state.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-RenderWidgetSignals::RenderWidgetSignals(Observer* observer)
- : observer_(observer),
- num_visible_render_widgets_(0),
- num_visible_render_widgets_with_touch_handlers_(0) {}
-
-std::unique_ptr<RenderWidgetSchedulingState>
-RenderWidgetSignals::NewRenderWidgetSchedulingState() {
- return base::WrapUnique(new RenderWidgetSchedulingState(this));
-}
-
-void RenderWidgetSignals::IncNumVisibleRenderWidgets() {
- num_visible_render_widgets_++;
-
- if (num_visible_render_widgets_ == 1)
- observer_->SetAllRenderWidgetsHidden(false);
-}
-
-void RenderWidgetSignals::DecNumVisibleRenderWidgets() {
- num_visible_render_widgets_--;
- DCHECK_GE(num_visible_render_widgets_, 0);
-
- if (num_visible_render_widgets_ == 0)
- observer_->SetAllRenderWidgetsHidden(true);
-}
-
-void RenderWidgetSignals::IncNumVisibleRenderWidgetsWithTouchHandlers() {
- num_visible_render_widgets_with_touch_handlers_++;
-
- if (num_visible_render_widgets_with_touch_handlers_ == 1)
- observer_->SetHasVisibleRenderWidgetWithTouchHandler(true);
-}
-
-void RenderWidgetSignals::DecNumVisibleRenderWidgetsWithTouchHandlers() {
- num_visible_render_widgets_with_touch_handlers_--;
- DCHECK_GE(num_visible_render_widgets_with_touch_handlers_, 0);
-
- if (num_visible_render_widgets_with_touch_handlers_ == 0)
- observer_->SetHasVisibleRenderWidgetWithTouchHandler(false);
-}
-
-void RenderWidgetSignals::AsValueInto(
- base::trace_event::TracedValue* state) const {
- state->BeginDictionary("renderer_widget_signals");
- state->SetInteger("num_visible_render_widgets", num_visible_render_widgets_);
- state->SetInteger("num_visible_render_widgets_with_touch_handlers",
- num_visible_render_widgets_with_touch_handlers_);
- state->EndDictionary();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/render_widget_signals.h b/chromium/components/scheduler/renderer/render_widget_signals.h
deleted file mode 100644
index 9e645b2a5b7..00000000000
--- a/chromium/components/scheduler/renderer/render_widget_signals.h
+++ /dev/null
@@ -1,58 +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 COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SIGNALS_H_
-#define COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SIGNALS_H_
-
-#include <memory>
-
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-class RenderWidgetSchedulingState;
-
-class SCHEDULER_EXPORT RenderWidgetSignals {
- public:
- class SCHEDULER_EXPORT Observer {
- public:
- virtual ~Observer() {}
-
- // If |hidden| is true then all render widgets managed by this renderer
- // process have been hidden.
- // If |hidden| is false at least one render widget managed by this renderer
- // process has become visible and the renderer is no longer hidden.
- // Will be called on the main thread.
- virtual void SetAllRenderWidgetsHidden(bool hidden) = 0;
-
- // Tells the observer whether or not we have at least one touch handler on
- // a visible render widget. Will be called on the main thread.
- virtual void SetHasVisibleRenderWidgetWithTouchHandler(
- bool has_visible_render_widget_with_touch_handler) = 0;
- };
-
- explicit RenderWidgetSignals(Observer* observer);
-
- std::unique_ptr<RenderWidgetSchedulingState> NewRenderWidgetSchedulingState();
-
- void AsValueInto(base::trace_event::TracedValue* state) const;
-
- private:
- friend class RenderWidgetSchedulingState;
-
- void IncNumVisibleRenderWidgets();
- void DecNumVisibleRenderWidgets();
- void IncNumVisibleRenderWidgetsWithTouchHandlers();
- void DecNumVisibleRenderWidgetsWithTouchHandlers();
-
- Observer* observer_; // NOT OWNED
- int num_visible_render_widgets_;
- int num_visible_render_widgets_with_touch_handlers_;
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SIGNALS_H_
diff --git a/chromium/components/scheduler/renderer/render_widget_signals_unittest.cpp b/chromium/components/scheduler/renderer/render_widget_signals_unittest.cpp
deleted file mode 100644
index 60d1de5b2b6..00000000000
--- a/chromium/components/scheduler/renderer/render_widget_signals_unittest.cpp
+++ /dev/null
@@ -1,266 +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 "components/scheduler/renderer/render_widget_signals.h"
-
-#include "base/macros.h"
-#include "components/scheduler/renderer/render_widget_scheduling_state.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::AnyNumber;
-using testing::Mock;
-using testing::_;
-
-namespace scheduler {
-
-namespace {
-class MockObserver : public RenderWidgetSignals::Observer {
- public:
- MockObserver() {}
- virtual ~MockObserver() {}
-
- MOCK_METHOD1(SetAllRenderWidgetsHidden, void(bool hidden));
- MOCK_METHOD1(SetHasVisibleRenderWidgetWithTouchHandler,
- void(bool has_visible_render_widget_with_touch_handler));
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockObserver);
-};
-}
-
-class RenderWidgetSignalsTest : public testing::Test {
- public:
- RenderWidgetSignalsTest() {}
- ~RenderWidgetSignalsTest() override {}
-
- void SetUp() override {
- mock_observer_.reset(new MockObserver());
- render_widget_signals_.reset(new RenderWidgetSignals(mock_observer_.get()));
- }
-
- void IgnoreWidgetCreationCallbacks() {
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false))
- .Times(AnyNumber());
- }
-
- void IgnoreWidgetDestructionCallbacks() {
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true))
- .Times(AnyNumber());
- }
-
- std::unique_ptr<MockObserver> mock_observer_;
- std::unique_ptr<RenderWidgetSignals> render_widget_signals_;
-};
-
-TEST_F(RenderWidgetSignalsTest, RenderWidgetSchedulingStateLifeCycle) {
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)).Times(1);
- std::unique_ptr<RenderWidgetSchedulingState> widget1_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1);
-}
-
-TEST_F(RenderWidgetSignalsTest, RenderWidget_Hidden) {
- IgnoreWidgetCreationCallbacks();
- std::unique_ptr<RenderWidgetSchedulingState> widget1_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1);
- widget1_state->SetHidden(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- IgnoreWidgetDestructionCallbacks();
-}
-
-TEST_F(RenderWidgetSignalsTest, RenderWidget_HiddenThreeTimesShownOnce) {
- IgnoreWidgetCreationCallbacks();
- std::unique_ptr<RenderWidgetSchedulingState> widget1_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1);
- widget1_state->SetHidden(true);
- widget1_state->SetHidden(true);
- widget1_state->SetHidden(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)).Times(1);
- widget1_state->SetHidden(false);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- IgnoreWidgetDestructionCallbacks();
-}
-
-TEST_F(RenderWidgetSignalsTest, MultipleRenderWidgetsBecomeHiddenThenVisible) {
- IgnoreWidgetCreationCallbacks();
- std::unique_ptr<RenderWidgetSchedulingState> widget1_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- std::unique_ptr<RenderWidgetSchedulingState> widget2_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- std::unique_ptr<RenderWidgetSchedulingState> widget3_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- // Widgets are initially assumed to be visible so start hiding them, we should
- // not get any calls to SetAllRenderWidgetsHidden till the last one is hidden.
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(_)).Times(0);
- widget1_state->SetHidden(true);
- widget2_state->SetHidden(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1);
- widget3_state->SetHidden(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- // We should get a call back once the first widget is unhidden and no more
- // after that.
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)).Times(1);
- widget1_state->SetHidden(false);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(_)).Times(0);
- widget2_state->SetHidden(false);
- widget3_state->SetHidden(false);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- IgnoreWidgetDestructionCallbacks();
-}
-
-TEST_F(RenderWidgetSignalsTest, TouchHandlerAddedAndRemoved_VisibleWidget) {
- IgnoreWidgetCreationCallbacks();
-
- std::unique_ptr<RenderWidgetSchedulingState> widget_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true))
- .Times(1);
- widget_state->SetHasTouchHandler(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false))
- .Times(1);
- widget_state->SetHasTouchHandler(false);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- IgnoreWidgetDestructionCallbacks();
-}
-
-TEST_F(RenderWidgetSignalsTest,
- TouchHandlerAddedThriceAndRemovedOnce_VisibleWidget) {
- IgnoreWidgetCreationCallbacks();
-
- std::unique_ptr<RenderWidgetSchedulingState> widget_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true))
- .Times(1);
- widget_state->SetHasTouchHandler(true);
- widget_state->SetHasTouchHandler(true);
- widget_state->SetHasTouchHandler(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false))
- .Times(1);
- widget_state->SetHasTouchHandler(false);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- IgnoreWidgetDestructionCallbacks();
-}
-
-TEST_F(RenderWidgetSignalsTest, TouchHandlerAddedAndRemoved_HiddenWidget) {
- IgnoreWidgetCreationCallbacks();
-
- std::unique_ptr<RenderWidgetSchedulingState> widget_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1);
- widget_state->SetHidden(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_))
- .Times(0);
- widget_state->SetHasTouchHandler(true);
- widget_state->SetHasTouchHandler(false);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- IgnoreWidgetDestructionCallbacks();
-}
-
-TEST_F(RenderWidgetSignalsTest,
- MultipleTouchHandlerAddedAndRemoved_VisibleWidgets) {
- IgnoreWidgetCreationCallbacks();
-
- std::unique_ptr<RenderWidgetSchedulingState> widget1_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- std::unique_ptr<RenderWidgetSchedulingState> widget2_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- std::unique_ptr<RenderWidgetSchedulingState> widget3_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- // We should only get a callback for the first widget with a touch handler.
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true))
- .Times(1);
- widget1_state->SetHasTouchHandler(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_))
- .Times(0);
- widget2_state->SetHasTouchHandler(true);
- widget3_state->SetHasTouchHandler(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- // We should only get a callback when the last touch handler is removed.
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_))
- .Times(0);
- widget1_state->SetHasTouchHandler(false);
- widget2_state->SetHasTouchHandler(false);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false))
- .Times(1);
- widget3_state->SetHasTouchHandler(false);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- IgnoreWidgetDestructionCallbacks();
-}
-
-TEST_F(RenderWidgetSignalsTest,
- TouchHandlerAddedThenWigetDeleted_VisibleWidget) {
- IgnoreWidgetCreationCallbacks();
-
- std::unique_ptr<RenderWidgetSchedulingState> widget_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true))
- .Times(1);
- widget_state->SetHasTouchHandler(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false))
- .Times(1);
- IgnoreWidgetDestructionCallbacks();
-}
-
-TEST_F(RenderWidgetSignalsTest,
- TouchHandlerAddedThenWigetDeleted_HiddenWidget) {
- IgnoreWidgetCreationCallbacks();
-
- std::unique_ptr<RenderWidgetSchedulingState> widget_state =
- render_widget_signals_->NewRenderWidgetSchedulingState();
- EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1);
- widget_state->SetHidden(true);
- Mock::VerifyAndClearExpectations(mock_observer_.get());
-
- EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_))
- .Times(0);
- IgnoreWidgetDestructionCallbacks();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/renderer_scheduler.cc b/chromium/components/scheduler/renderer/renderer_scheduler.cc
deleted file mode 100644
index dd7badeeed3..00000000000
--- a/chromium/components/scheduler/renderer/renderer_scheduler.cc
+++ /dev/null
@@ -1,77 +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 "components/scheduler/renderer/renderer_scheduler.h"
-
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/metrics/field_trial.h"
-#include "base/time/default_tick_clock.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_impl.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_impl.h"
-#include "components/scheduler/common/scheduler_switches.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-
-namespace scheduler {
-namespace {
-const base::Feature kExpensiveTaskBlockingPolicyFeature{
- "SchedulerExpensiveTaskBlocking", base::FEATURE_ENABLED_BY_DEFAULT};
-}
-
-RendererScheduler::RendererScheduler() {
-}
-
-RendererScheduler::~RendererScheduler() {
-}
-
-RendererScheduler::RAILModeObserver::~RAILModeObserver() = default;
-
-// static
-std::unique_ptr<RendererScheduler> RendererScheduler::Create() {
- // Ensure worker.scheduler, worker.scheduler.debug and
- // renderer.scheduler.debug appear as an option in about://tracing
- base::trace_event::TraceLog::GetCategoryGroupEnabled(
- TRACE_DISABLED_BY_DEFAULT("worker.scheduler"));
- base::trace_event::TraceLog::GetCategoryGroupEnabled(
- TRACE_DISABLED_BY_DEFAULT("worker.scheduler.debug"));
- base::trace_event::TraceLog::GetCategoryGroupEnabled(
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug"));
-
- base::MessageLoop* message_loop = base::MessageLoop::current();
- std::unique_ptr<RendererSchedulerImpl> scheduler(
- new RendererSchedulerImpl(SchedulerTqmDelegateImpl::Create(
- message_loop, base::WrapUnique(new base::DefaultTickClock()))));
-
- // Runtime features are not currently available in html_viewer.
- if (base::FeatureList::GetInstance()) {
- bool blocking_allowed =
- base::FeatureList::IsEnabled(kExpensiveTaskBlockingPolicyFeature);
- // Also check the old style FieldTrial API for perf waterfall compatibility.
- const std::string group_name = base::FieldTrialList::FindFullName(
- kExpensiveTaskBlockingPolicyFeature.name);
- blocking_allowed |= base::StartsWith(group_name, "Enabled",
- base::CompareCase::INSENSITIVE_ASCII);
- scheduler->SetExpensiveTaskBlockingAllowed(blocking_allowed);
- }
- return base::WrapUnique<RendererScheduler>(scheduler.release());
-}
-
-// static
-const char* RendererScheduler::InputEventStateToString(
- InputEventState input_event_state) {
- switch (input_event_state) {
- case InputEventState::EVENT_CONSUMED_BY_COMPOSITOR:
- return "event_consumed_by_compositor";
- case InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD:
- return "event_forwarded_to_main_thread";
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/renderer_scheduler.h b/chromium/components/scheduler/renderer/renderer_scheduler.h
deleted file mode 100644
index f915feb0a04..00000000000
--- a/chromium/components/scheduler/renderer/renderer_scheduler.h
+++ /dev/null
@@ -1,184 +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 COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_H_
-#define COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "components/scheduler/child/child_scheduler.h"
-#include "components/scheduler/child/single_thread_idle_task_runner.h"
-#include "components/scheduler/renderer/render_widget_scheduling_state.h"
-#include "components/scheduler/scheduler_export.h"
-#include "third_party/WebKit/public/platform/WebScheduler.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "v8/include/v8.h"
-
-namespace base {
-namespace trace_event {
-class BlameContext;
-}
-}
-
-namespace cc {
-struct BeginFrameArgs;
-}
-
-namespace blink {
-class WebLocalFrame;
-class WebThread;
-}
-
-namespace scheduler {
-
-class RenderWidgetSchedulingState;
-
-class SCHEDULER_EXPORT RendererScheduler : public ChildScheduler {
- public:
- class SCHEDULER_EXPORT RAILModeObserver {
- public:
- virtual ~RAILModeObserver();
- virtual void OnRAILModeChanged(v8::RAILMode rail_mode) = 0;
- };
-
- ~RendererScheduler() override;
- static std::unique_ptr<RendererScheduler> Create();
-
- // Returns the compositor task runner.
- virtual scoped_refptr<TaskQueue> CompositorTaskRunner() = 0;
-
- // Creates a WebThread implementation for the renderer main thread.
- virtual std::unique_ptr<blink::WebThread> CreateMainThread() = 0;
-
- // Returns the loading task runner. This queue is intended for tasks related
- // to resource dispatch, foreground HTML parsing, etc...
- virtual scoped_refptr<TaskQueue> LoadingTaskRunner() = 0;
-
- // Returns the timer task runner. This queue is intended for DOM Timers.
- // TODO(alexclarke): Get rid of this default timer queue.
- virtual scoped_refptr<TaskQueue> TimerTaskRunner() = 0;
-
- // Returns a new loading task runner. This queue is intended for tasks related
- // to resource dispatch, foreground HTML parsing, etc...
- virtual scoped_refptr<TaskQueue> NewLoadingTaskRunner(const char* name) = 0;
-
- // Returns a new timer task runner. This queue is intended for DOM Timers.
- virtual scoped_refptr<TaskQueue> NewTimerTaskRunner(const char* name) = 0;
-
- // Returns a new RenderWidgetSchedulingState. The signals from this will be
- // used to make scheduling decisions.
- virtual std::unique_ptr<RenderWidgetSchedulingState>
- NewRenderWidgetSchedulingState() = 0;
-
- // Called to notify about the start of an extended period where no frames
- // need to be drawn. Must be called from the main thread.
- virtual void BeginFrameNotExpectedSoon() = 0;
-
- // Called to notify about the start of a new frame. Must be called from the
- // main thread.
- virtual void WillBeginFrame(const cc::BeginFrameArgs& args) = 0;
-
- // Called to notify that a previously begun frame was committed. Must be
- // called from the main thread.
- virtual void DidCommitFrameToCompositor() = 0;
-
- // Keep RendererScheduler::InputEventStateToString in sync with this enum.
- enum class InputEventState {
- EVENT_CONSUMED_BY_COMPOSITOR,
- EVENT_FORWARDED_TO_MAIN_THREAD,
- };
- static const char* InputEventStateToString(InputEventState input_event_state);
-
- // Tells the scheduler that the system processed an input event. Called by the
- // compositor (impl) thread. Note it's expected that every call to
- // DidHandleInputEventOnCompositorThread where |event_state| is
- // EVENT_FORWARDED_TO_MAIN_THREAD will be followed by a corresponding call
- // to DidHandleInputEventOnMainThread.
- virtual void DidHandleInputEventOnCompositorThread(
- const blink::WebInputEvent& web_input_event,
- InputEventState event_state) = 0;
-
- // Tells the scheduler that the system processed an input event. Must be
- // called from the main thread.
- virtual void DidHandleInputEventOnMainThread(
- const blink::WebInputEvent& web_input_event) = 0;
-
- // Tells the scheduler that the system is displaying an input animation (e.g.
- // a fling). Called by the compositor (impl) thread.
- virtual void DidAnimateForInputOnCompositorThread() = 0;
-
- // Tells the scheduler that the renderer process has been backgrounded, i.e.,
- // there are no critical, user facing activities (visual, audio, etc...)
- // driven by this process. A stricter condition than |OnRendererHidden()|, the
- // process is assumed to be foregrounded when the scheduler is constructed.
- // Must be called on the main thread.
- virtual void OnRendererBackgrounded() = 0;
-
- // Tells the scheduler that the renderer process has been foregrounded.
- // This is the assumed state when the scheduler is constructed.
- // Must be called on the main thread.
- virtual void OnRendererForegrounded() = 0;
-
- // Tells the scheduler that the render process should be suspended. This can
- // only be done when the renderer is backgrounded. The renderer will be
- // automatically resumed when foregrounded.
- virtual void SuspendRenderer() = 0;
-
- // Tells the scheduler that a navigation task is pending. While any main-frame
- // navigation tasks are pending, the scheduler will ensure that loading tasks
- // are not blocked even if they are expensive. Must be called on the main
- // thread.
- virtual void AddPendingNavigation(
- blink::WebScheduler::NavigatingFrameType type) = 0;
-
- // Tells the scheduler that a navigation task is no longer pending.
- // Must be called on the main thread.
- virtual void RemovePendingNavigation(
- blink::WebScheduler::NavigatingFrameType type) = 0;
-
- // Tells the scheduler that a navigation has started. The scheduler will
- // prioritize loading tasks for a short duration afterwards.
- // Must be called from the main thread.
- virtual void OnNavigationStarted() = 0;
-
- // Returns true if the scheduler has reason to believe that high priority work
- // may soon arrive on the main thread, e.g., if gesture events were observed
- // recently.
- // Must be called from the main thread.
- virtual bool IsHighPriorityWorkAnticipated() = 0;
-
- // Suspends the timer queue and increments the timer queue suspension count.
- // May only be called from the main thread.
- virtual void SuspendTimerQueue() = 0;
-
- // Decrements the timer queue suspension count and re-enables the timer queue
- // if the suspension count is zero and the current schduler policy allows it.
- virtual void ResumeTimerQueue() = 0;
-
- // Sets whether to allow suspension of timers after the backgrounded signal is
- // received via OnRendererBackgrounded. Defaults to disabled.
- virtual void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) = 0;
-
- // Sets the default blame context to which top level work should be
- // attributed in this renderer. |blame_context| must outlive this scheduler.
- virtual void SetTopLevelBlameContext(
- base::trace_event::BlameContext* blame_context) = 0;
-
- // The renderer scheduler maintains an estimated RAIL mode[1]. This observer
- // can be used to get notified when the mode changes. The observer will be
- // called on the main thread and must outlive this class.
- // [1]
- // https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail
- virtual void SetRAILModeObserver(RAILModeObserver* observer) = 0;
-
- protected:
- RendererScheduler();
- DISALLOW_COPY_AND_ASSIGN(RendererScheduler);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_H_
diff --git a/chromium/components/scheduler/renderer/renderer_scheduler_impl.cc b/chromium/components/scheduler/renderer/renderer_scheduler_impl.cc
deleted file mode 100644
index d1d2e032088..00000000000
--- a/chromium/components/scheduler/renderer/renderer_scheduler_impl.cc
+++ /dev/null
@@ -1,1418 +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 "components/scheduler/renderer/renderer_scheduler_impl.h"
-
-#include "base/bind.h"
-#include "base/debug/stack_trace.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "cc/output/begin_frame_args.h"
-#include "components/scheduler/base/task_queue_impl.h"
-#include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/base/virtual_time_domain.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-#include "components/scheduler/renderer/web_view_scheduler_impl.h"
-#include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h"
-
-namespace scheduler {
-namespace {
-// The run time of loading tasks is strongly bimodal. The vast majority are
-// very cheap, but there are usually a handful of very expensive tasks (e.g ~1
-// second on a mobile device) so we take a very pesimistic view when estimating
-// the cost of loading tasks.
-const int kLoadingTaskEstimationSampleCount = 1000;
-const double kLoadingTaskEstimationPercentile = 99;
-const int kTimerTaskEstimationSampleCount = 1000;
-const double kTimerTaskEstimationPercentile = 99;
-const int kShortIdlePeriodDurationSampleCount = 10;
-const double kShortIdlePeriodDurationPercentile = 50;
-// Amount of idle time left in a frame (as a ratio of the vsync interval) above
-// which main thread compositing can be considered fast.
-const double kFastCompositingIdleTimeThreshold = .2;
-} // namespace
-
-RendererSchedulerImpl::RendererSchedulerImpl(
- scoped_refptr<SchedulerTqmDelegate> main_task_runner)
- : helper_(main_task_runner,
- "renderer.scheduler",
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")),
- idle_helper_(&helper_,
- this,
- "renderer.scheduler",
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerIdlePeriod",
- base::TimeDelta()),
- render_widget_scheduler_signals_(this),
- control_task_runner_(helper_.ControlTaskRunner()),
- compositor_task_runner_(
- helper_.NewTaskQueue(TaskQueue::Spec("compositor_tq")
- .SetShouldMonitorQuiescence(true))),
- delayed_update_policy_runner_(
- base::Bind(&RendererSchedulerImpl::UpdatePolicy,
- base::Unretained(this)),
- helper_.ControlTaskRunner()),
- main_thread_only_(compositor_task_runner_,
- helper_.scheduler_tqm_delegate().get()),
- policy_may_need_update_(&any_thread_lock_),
- weak_factory_(this) {
- throttling_helper_.reset(new ThrottlingHelper(this, "renderer.scheduler"));
- update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy,
- weak_factory_.GetWeakPtr());
- end_renderer_hidden_idle_period_closure_.Reset(base::Bind(
- &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr()));
-
- suspend_timers_when_backgrounded_closure_.Reset(
- base::Bind(&RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded,
- weak_factory_.GetWeakPtr()));
-
- default_loading_task_runner_ = NewLoadingTaskRunner("default_loading_tq");
- default_timer_task_runner_ = NewTimerTaskRunner("default_timer_tq");
-
- TRACE_EVENT_OBJECT_CREATED_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
- this);
-
- helper_.SetObserver(this);
-}
-
-RendererSchedulerImpl::~RendererSchedulerImpl() {
- TRACE_EVENT_OBJECT_DELETED_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
- this);
-
- for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) {
- loading_queue->RemoveTaskObserver(
- &MainThreadOnly().loading_task_cost_estimator);
- }
- for (const scoped_refptr<TaskQueue>& timer_queue : timer_task_runners_) {
- timer_queue->RemoveTaskObserver(
- &MainThreadOnly().timer_task_cost_estimator);
- }
-
- // Ensure the renderer scheduler was shut down explicitly, because otherwise
- // we could end up having stale pointers to the Blink heap which has been
- // terminated by this point.
- DCHECK(MainThreadOnly().was_shutdown);
-}
-
-RendererSchedulerImpl::MainThreadOnly::MainThreadOnly(
- const scoped_refptr<TaskQueue>& compositor_task_runner,
- base::TickClock* time_source)
- : loading_task_cost_estimator(time_source,
- kLoadingTaskEstimationSampleCount,
- kLoadingTaskEstimationPercentile),
- timer_task_cost_estimator(time_source,
- kTimerTaskEstimationSampleCount,
- kTimerTaskEstimationPercentile),
- idle_time_estimator(compositor_task_runner,
- time_source,
- kShortIdlePeriodDurationSampleCount,
- kShortIdlePeriodDurationPercentile),
- current_use_case(UseCase::NONE),
- timer_queue_suspend_count(0),
- navigation_task_expected_count(0),
- expensive_task_policy(ExpensiveTaskPolicy::RUN),
- renderer_hidden(false),
- renderer_backgrounded(false),
- renderer_suspended(false),
- timer_queue_suspension_when_backgrounded_enabled(false),
- timer_queue_suspended_when_backgrounded(false),
- was_shutdown(false),
- loading_tasks_seem_expensive(false),
- timer_tasks_seem_expensive(false),
- touchstart_expected_soon(false),
- have_seen_a_begin_main_frame(false),
- have_reported_blocking_intervention_in_current_policy(false),
- have_reported_blocking_intervention_since_navigation(false),
- has_visible_render_widget_with_touch_handler(false),
- begin_frame_not_expected_soon(false),
- expensive_task_blocking_allowed(true),
- in_idle_period_for_testing(false),
- rail_mode_observer(nullptr) {}
-
-RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {}
-
-RendererSchedulerImpl::AnyThread::AnyThread()
- : awaiting_touch_start_response(false),
- in_idle_period(false),
- begin_main_frame_on_critical_path(false),
- last_gesture_was_compositor_driven(false),
- default_gesture_prevented(true),
- have_seen_touchstart(false) {}
-
-RendererSchedulerImpl::AnyThread::~AnyThread() {}
-
-RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly()
- : last_input_type(blink::WebInputEvent::Undefined) {}
-
-RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {}
-
-void RendererSchedulerImpl::Shutdown() {
- throttling_helper_.reset();
- helper_.Shutdown();
- MainThreadOnly().was_shutdown = true;
- MainThreadOnly().rail_mode_observer = nullptr;
-}
-
-std::unique_ptr<blink::WebThread> RendererSchedulerImpl::CreateMainThread() {
- return base::WrapUnique(new WebThreadImplForRendererScheduler(this));
-}
-
-scoped_refptr<TaskQueue> RendererSchedulerImpl::DefaultTaskRunner() {
- return helper_.DefaultTaskRunner();
-}
-
-scoped_refptr<TaskQueue> RendererSchedulerImpl::CompositorTaskRunner() {
- helper_.CheckOnValidThread();
- return compositor_task_runner_;
-}
-
-scoped_refptr<SingleThreadIdleTaskRunner>
-RendererSchedulerImpl::IdleTaskRunner() {
- return idle_helper_.IdleTaskRunner();
-}
-
-scoped_refptr<TaskQueue> RendererSchedulerImpl::LoadingTaskRunner() {
- helper_.CheckOnValidThread();
- return default_loading_task_runner_;
-}
-
-scoped_refptr<TaskQueue> RendererSchedulerImpl::TimerTaskRunner() {
- helper_.CheckOnValidThread();
- return default_timer_task_runner_;
-}
-
-scoped_refptr<TaskQueue> RendererSchedulerImpl::ControlTaskRunner() {
- helper_.CheckOnValidThread();
- return helper_.ControlTaskRunner();
-}
-
-scoped_refptr<TaskQueue> RendererSchedulerImpl::NewLoadingTaskRunner(
- const char* name) {
- helper_.CheckOnValidThread();
- scoped_refptr<TaskQueue> loading_task_queue(helper_.NewTaskQueue(
- TaskQueue::Spec(name).SetShouldMonitorQuiescence(true)));
- loading_task_runners_.insert(loading_task_queue);
- loading_task_queue->SetQueueEnabled(
- MainThreadOnly().current_policy.loading_queue_policy.is_enabled);
- loading_task_queue->SetQueuePriority(
- MainThreadOnly().current_policy.loading_queue_policy.priority);
- if (MainThreadOnly().current_policy.loading_queue_policy.time_domain_type ==
- TimeDomainType::THROTTLED) {
- throttling_helper_->IncreaseThrottleRefCount(loading_task_queue.get());
- }
- loading_task_queue->AddTaskObserver(
- &MainThreadOnly().loading_task_cost_estimator);
- return loading_task_queue;
-}
-
-scoped_refptr<TaskQueue> RendererSchedulerImpl::NewTimerTaskRunner(
- const char* name) {
- helper_.CheckOnValidThread();
- scoped_refptr<TaskQueue> timer_task_queue(
- helper_.NewTaskQueue(TaskQueue::Spec(name)
- .SetShouldMonitorQuiescence(true)
- .SetShouldReportWhenExecutionBlocked(true)));
- timer_task_runners_.insert(timer_task_queue);
- timer_task_queue->SetQueueEnabled(
- MainThreadOnly().current_policy.timer_queue_policy.is_enabled);
- timer_task_queue->SetQueuePriority(
- MainThreadOnly().current_policy.timer_queue_policy.priority);
- if (MainThreadOnly().current_policy.timer_queue_policy.time_domain_type ==
- TimeDomainType::THROTTLED) {
- throttling_helper_->IncreaseThrottleRefCount(timer_task_queue.get());
- }
- timer_task_queue->AddTaskObserver(
- &MainThreadOnly().timer_task_cost_estimator);
- return timer_task_queue;
-}
-
-std::unique_ptr<RenderWidgetSchedulingState>
-RendererSchedulerImpl::NewRenderWidgetSchedulingState() {
- return render_widget_scheduler_signals_.NewRenderWidgetSchedulingState();
-}
-
-void RendererSchedulerImpl::OnUnregisterTaskQueue(
- const scoped_refptr<TaskQueue>& task_queue) {
- if (throttling_helper_.get())
- throttling_helper_->UnregisterTaskQueue(task_queue.get());
-
- if (loading_task_runners_.find(task_queue) != loading_task_runners_.end()) {
- task_queue->RemoveTaskObserver(
- &MainThreadOnly().loading_task_cost_estimator);
- loading_task_runners_.erase(task_queue);
- } else if (timer_task_runners_.find(task_queue) !=
- timer_task_runners_.end()) {
- task_queue->RemoveTaskObserver(&MainThreadOnly().timer_task_cost_estimator);
- timer_task_runners_.erase(task_queue);
- }
-}
-
-bool RendererSchedulerImpl::CanExceedIdleDeadlineIfRequired() const {
- return idle_helper_.CanExceedIdleDeadlineIfRequired();
-}
-
-void RendererSchedulerImpl::AddTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- helper_.AddTaskObserver(task_observer);
-}
-
-void RendererSchedulerImpl::RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) {
- helper_.RemoveTaskObserver(task_observer);
-}
-
-void RendererSchedulerImpl::WillBeginFrame(const cc::BeginFrameArgs& args) {
- TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::WillBeginFrame", "args", args.AsValue());
- helper_.CheckOnValidThread();
- if (helper_.IsShutdown())
- return;
-
- EndIdlePeriod();
- MainThreadOnly().estimated_next_frame_begin = args.frame_time + args.interval;
- MainThreadOnly().have_seen_a_begin_main_frame = true;
- MainThreadOnly().begin_frame_not_expected_soon = false;
- MainThreadOnly().compositor_frame_interval = args.interval;
- {
- base::AutoLock lock(any_thread_lock_);
- AnyThread().begin_main_frame_on_critical_path = args.on_critical_path;
- }
-}
-
-void RendererSchedulerImpl::DidCommitFrameToCompositor() {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::DidCommitFrameToCompositor");
- helper_.CheckOnValidThread();
- if (helper_.IsShutdown())
- return;
-
- base::TimeTicks now(helper_.scheduler_tqm_delegate()->NowTicks());
- if (now < MainThreadOnly().estimated_next_frame_begin) {
- // TODO(rmcilroy): Consider reducing the idle period based on the runtime of
- // the next pending delayed tasks (as currently done in for long idle times)
- idle_helper_.StartIdlePeriod(
- IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now,
- MainThreadOnly().estimated_next_frame_begin);
- }
-
- MainThreadOnly().idle_time_estimator.DidCommitFrameToCompositor();
-}
-
-void RendererSchedulerImpl::BeginFrameNotExpectedSoon() {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::BeginFrameNotExpectedSoon");
- helper_.CheckOnValidThread();
- if (helper_.IsShutdown())
- return;
-
- MainThreadOnly().begin_frame_not_expected_soon = true;
- idle_helper_.EnableLongIdlePeriod();
- {
- base::AutoLock lock(any_thread_lock_);
- AnyThread().begin_main_frame_on_critical_path = false;
- }
-}
-
-void RendererSchedulerImpl::SetAllRenderWidgetsHidden(bool hidden) {
- TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::SetAllRenderWidgetsHidden", "hidden",
- hidden);
-
- helper_.CheckOnValidThread();
-
- if (helper_.IsShutdown() || MainThreadOnly().renderer_hidden == hidden)
- return;
-
- end_renderer_hidden_idle_period_closure_.Cancel();
-
- if (hidden) {
- idle_helper_.EnableLongIdlePeriod();
-
- // Ensure that we stop running idle tasks after a few seconds of being
- // hidden.
- base::TimeDelta end_idle_when_hidden_delay =
- base::TimeDelta::FromMilliseconds(kEndIdleWhenHiddenDelayMillis);
- control_task_runner_->PostDelayedTask(
- FROM_HERE, end_renderer_hidden_idle_period_closure_.callback(),
- end_idle_when_hidden_delay);
- MainThreadOnly().renderer_hidden = true;
- } else {
- MainThreadOnly().renderer_hidden = false;
- EndIdlePeriod();
- }
-
- // TODO(alexclarke): Should we update policy here?
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
- this, AsValue(helper_.scheduler_tqm_delegate()->NowTicks()));
-}
-
-void RendererSchedulerImpl::SetHasVisibleRenderWidgetWithTouchHandler(
- bool has_visible_render_widget_with_touch_handler) {
- helper_.CheckOnValidThread();
- if (has_visible_render_widget_with_touch_handler ==
- MainThreadOnly().has_visible_render_widget_with_touch_handler)
- return;
-
- MainThreadOnly().has_visible_render_widget_with_touch_handler =
- has_visible_render_widget_with_touch_handler;
-
- base::AutoLock lock(any_thread_lock_);
- UpdatePolicyLocked(UpdateType::FORCE_UPDATE);
-}
-
-void RendererSchedulerImpl::OnRendererBackgrounded() {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::OnRendererBackgrounded");
- helper_.CheckOnValidThread();
- if (helper_.IsShutdown() || MainThreadOnly().renderer_backgrounded)
- return;
-
- MainThreadOnly().renderer_backgrounded = true;
- if (!MainThreadOnly().timer_queue_suspension_when_backgrounded_enabled)
- return;
-
- suspend_timers_when_backgrounded_closure_.Cancel();
- base::TimeDelta suspend_timers_when_backgrounded_delay =
- base::TimeDelta::FromMilliseconds(
- kSuspendTimersWhenBackgroundedDelayMillis);
- control_task_runner_->PostDelayedTask(
- FROM_HERE, suspend_timers_when_backgrounded_closure_.callback(),
- suspend_timers_when_backgrounded_delay);
-}
-
-void RendererSchedulerImpl::OnRendererForegrounded() {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::OnRendererForegrounded");
- helper_.CheckOnValidThread();
- if (helper_.IsShutdown() || !MainThreadOnly().renderer_backgrounded)
- return;
-
- MainThreadOnly().renderer_backgrounded = false;
- MainThreadOnly().renderer_suspended = false;
- suspend_timers_when_backgrounded_closure_.Cancel();
- ResumeTimerQueueWhenForegrounded();
-}
-
-void RendererSchedulerImpl::SuspendRenderer() {
- helper_.CheckOnValidThread();
- DCHECK(MainThreadOnly().renderer_backgrounded);
- if (helper_.IsShutdown())
- return;
- suspend_timers_when_backgrounded_closure_.Cancel();
- // TODO(hajimehoshi): We might need to suspend not only timer queue but also
- // e.g. loading tasks or postMessage.
- MainThreadOnly().renderer_suspended = true;
- SuspendTimerQueueWhenBackgrounded();
-}
-
-void RendererSchedulerImpl::EndIdlePeriod() {
- if (MainThreadOnly().in_idle_period_for_testing)
- return;
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::EndIdlePeriod");
- helper_.CheckOnValidThread();
- idle_helper_.EndIdlePeriod();
-}
-
-void RendererSchedulerImpl::EndIdlePeriodForTesting(
- const base::Closure& callback,
- base::TimeTicks time_remaining) {
- MainThreadOnly().in_idle_period_for_testing = false;
- EndIdlePeriod();
- callback.Run();
-}
-
-bool RendererSchedulerImpl::PolicyNeedsUpdateForTesting() {
- return policy_may_need_update_.IsSet();
-}
-
-// static
-bool RendererSchedulerImpl::ShouldPrioritizeInputEvent(
- const blink::WebInputEvent& web_input_event) {
- // We regard MouseMove events with the left mouse button down as a signal
- // that the user is doing something requiring a smooth frame rate.
- if (web_input_event.type == blink::WebInputEvent::MouseMove &&
- (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) {
- return true;
- }
- // Ignore all other mouse events because they probably don't signal user
- // interaction needing a smooth framerate. NOTE isMouseEventType returns false
- // for mouse wheel events, hence we regard them as user input.
- // Ignore keyboard events because it doesn't really make sense to enter
- // compositor priority for them.
- if (blink::WebInputEvent::isMouseEventType(web_input_event.type) ||
- blink::WebInputEvent::isKeyboardEventType(web_input_event.type)) {
- return false;
- }
- return true;
-}
-
-void RendererSchedulerImpl::DidHandleInputEventOnCompositorThread(
- const blink::WebInputEvent& web_input_event,
- InputEventState event_state) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::DidHandleInputEventOnCompositorThread");
- if (!ShouldPrioritizeInputEvent(web_input_event))
- return;
-
- UpdateForInputEventOnCompositorThread(web_input_event.type, event_state);
-}
-
-void RendererSchedulerImpl::DidAnimateForInputOnCompositorThread() {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::DidAnimateForInputOnCompositorThread");
- base::AutoLock lock(any_thread_lock_);
- AnyThread().fling_compositor_escalation_deadline =
- helper_.scheduler_tqm_delegate()->NowTicks() +
- base::TimeDelta::FromMilliseconds(kFlingEscalationLimitMillis);
-}
-
-void RendererSchedulerImpl::UpdateForInputEventOnCompositorThread(
- blink::WebInputEvent::Type type,
- InputEventState input_event_state) {
- base::AutoLock lock(any_thread_lock_);
- base::TimeTicks now = helper_.scheduler_tqm_delegate()->NowTicks();
-
- // TODO(alexclarke): Move WebInputEventTraits where we can access it from here
- // and record the name rather than the integer representation.
- TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::UpdateForInputEventOnCompositorThread",
- "type", static_cast<int>(type), "input_event_state",
- InputEventStateToString(input_event_state));
-
- base::TimeDelta unused_policy_duration;
- UseCase previous_use_case =
- ComputeCurrentUseCase(now, &unused_policy_duration);
- bool was_awaiting_touch_start_response =
- AnyThread().awaiting_touch_start_response;
-
- AnyThread().user_model.DidStartProcessingInputEvent(type, now);
-
- if (input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR)
- AnyThread().user_model.DidFinishProcessingInputEvent(now);
-
- if (type) {
- switch (type) {
- case blink::WebInputEvent::TouchStart:
- AnyThread().awaiting_touch_start_response = true;
- // This is just a fail-safe to reset the state of
- // |last_gesture_was_compositor_driven| to the default. We don't know
- // yet where the gesture will run.
- AnyThread().last_gesture_was_compositor_driven = false;
- AnyThread().have_seen_touchstart = true;
- // Assume the default gesture is prevented until we see evidence
- // otherwise.
- AnyThread().default_gesture_prevented = true;
- break;
-
- case blink::WebInputEvent::TouchMove:
- // Observation of consecutive touchmoves is a strong signal that the
- // page is consuming the touch sequence, in which case touchstart
- // response prioritization is no longer necessary. Otherwise, the
- // initial touchmove should preserve the touchstart response pending
- // state.
- if (AnyThread().awaiting_touch_start_response &&
- CompositorThreadOnly().last_input_type ==
- blink::WebInputEvent::TouchMove) {
- AnyThread().awaiting_touch_start_response = false;
- }
- break;
-
- case blink::WebInputEvent::GesturePinchUpdate:
- case blink::WebInputEvent::GestureScrollUpdate:
- // If we see events for an established gesture, we can lock it to the
- // appropriate thread as the gesture can no longer be cancelled.
- AnyThread().last_gesture_was_compositor_driven =
- input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR;
- AnyThread().awaiting_touch_start_response = false;
- AnyThread().default_gesture_prevented = false;
- break;
-
- case blink::WebInputEvent::GestureFlingCancel:
- AnyThread().fling_compositor_escalation_deadline = base::TimeTicks();
- break;
-
- case blink::WebInputEvent::GestureTapDown:
- case blink::WebInputEvent::GestureShowPress:
- case blink::WebInputEvent::GestureScrollEnd:
- // With no observable effect, these meta events do not indicate a
- // meaningful touchstart response and should not impact task priority.
- break;
-
- default:
- AnyThread().awaiting_touch_start_response = false;
- break;
- }
- }
-
- // Avoid unnecessary policy updates if the use case did not change.
- UseCase use_case = ComputeCurrentUseCase(now, &unused_policy_duration);
-
- if (use_case != previous_use_case ||
- was_awaiting_touch_start_response !=
- AnyThread().awaiting_touch_start_response) {
- EnsureUrgentPolicyUpdatePostedOnMainThread(FROM_HERE);
- }
- CompositorThreadOnly().last_input_type = type;
-}
-
-void RendererSchedulerImpl::DidHandleInputEventOnMainThread(
- const blink::WebInputEvent& web_input_event) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::DidHandleInputEventOnMainThread");
- helper_.CheckOnValidThread();
- if (ShouldPrioritizeInputEvent(web_input_event)) {
- base::AutoLock lock(any_thread_lock_);
- AnyThread().user_model.DidFinishProcessingInputEvent(
- helper_.scheduler_tqm_delegate()->NowTicks());
- }
-}
-
-bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() {
- helper_.CheckOnValidThread();
- if (helper_.IsShutdown())
- return false;
-
- MaybeUpdatePolicy();
- // The touchstart, synchronized gesture and main-thread gesture use cases
- // indicate a strong likelihood of high-priority work in the near future.
- UseCase use_case = MainThreadOnly().current_use_case;
- return MainThreadOnly().touchstart_expected_soon ||
- use_case == UseCase::TOUCHSTART ||
- use_case == UseCase::MAIN_THREAD_GESTURE ||
- use_case == UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING ||
- use_case == UseCase::SYNCHRONIZED_GESTURE;
-}
-
-bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() {
- helper_.CheckOnValidThread();
- if (helper_.IsShutdown())
- return false;
-
- MaybeUpdatePolicy();
- // We only yield if there's a urgent task to be run now, or we are expecting
- // one soon (touch start).
- // Note: even though the control queue has the highest priority we don't yield
- // for it since these tasks are not user-provided work and they are only
- // intended to run before the next task, not interrupt the tasks.
- switch (MainThreadOnly().current_use_case) {
- case UseCase::COMPOSITOR_GESTURE:
- case UseCase::NONE:
- return MainThreadOnly().touchstart_expected_soon;
-
- case UseCase::MAIN_THREAD_GESTURE:
- case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING:
- case UseCase::SYNCHRONIZED_GESTURE:
- return compositor_task_runner_->HasPendingImmediateWork() ||
- MainThreadOnly().touchstart_expected_soon;
-
- case UseCase::TOUCHSTART:
- return true;
-
- case UseCase::LOADING:
- return false;
-
- default:
- NOTREACHED();
- return false;
- }
-}
-
-base::TimeTicks RendererSchedulerImpl::CurrentIdleTaskDeadlineForTesting()
- const {
- return idle_helper_.CurrentIdleTaskDeadline();
-}
-
-void RendererSchedulerImpl::RunIdleTasksForTesting(
- const base::Closure& callback) {
- MainThreadOnly().in_idle_period_for_testing = true;
- IdleTaskRunner()->PostIdleTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImpl::EndIdlePeriodForTesting,
- weak_factory_.GetWeakPtr(), callback));
- idle_helper_.EnableLongIdlePeriod();
-}
-
-void RendererSchedulerImpl::MaybeUpdatePolicy() {
- helper_.CheckOnValidThread();
- if (policy_may_need_update_.IsSet()) {
- UpdatePolicy();
- }
-}
-
-void RendererSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread(
- const tracked_objects::Location& from_here) {
- // TODO(scheduler-dev): Check that this method isn't called from the main
- // thread.
- any_thread_lock_.AssertAcquired();
- if (!policy_may_need_update_.IsSet()) {
- policy_may_need_update_.SetWhileLocked(true);
- control_task_runner_->PostTask(from_here, update_policy_closure_);
- }
-}
-
-void RendererSchedulerImpl::UpdatePolicy() {
- base::AutoLock lock(any_thread_lock_);
- UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
-}
-
-void RendererSchedulerImpl::ForceUpdatePolicy() {
- base::AutoLock lock(any_thread_lock_);
- UpdatePolicyLocked(UpdateType::FORCE_UPDATE);
-}
-
-void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
- helper_.CheckOnValidThread();
- any_thread_lock_.AssertAcquired();
- if (helper_.IsShutdown())
- return;
-
- base::TimeTicks now = helper_.scheduler_tqm_delegate()->NowTicks();
- policy_may_need_update_.SetWhileLocked(false);
-
- base::TimeDelta expected_use_case_duration;
- UseCase use_case = ComputeCurrentUseCase(now, &expected_use_case_duration);
- MainThreadOnly().current_use_case = use_case;
-
- base::TimeDelta touchstart_expected_flag_valid_for_duration;
- bool touchstart_expected_soon = false;
- if (MainThreadOnly().has_visible_render_widget_with_touch_handler) {
- touchstart_expected_soon = AnyThread().user_model.IsGestureExpectedSoon(
- now, &touchstart_expected_flag_valid_for_duration);
- }
- MainThreadOnly().touchstart_expected_soon = touchstart_expected_soon;
-
- base::TimeDelta longest_jank_free_task_duration =
- EstimateLongestJankFreeTaskDuration();
- MainThreadOnly().longest_jank_free_task_duration =
- longest_jank_free_task_duration;
-
- bool loading_tasks_seem_expensive = false;
- bool timer_tasks_seem_expensive = false;
- loading_tasks_seem_expensive =
- MainThreadOnly().loading_task_cost_estimator.expected_task_duration() >
- longest_jank_free_task_duration;
- timer_tasks_seem_expensive =
- MainThreadOnly().timer_task_cost_estimator.expected_task_duration() >
- longest_jank_free_task_duration;
- MainThreadOnly().timer_tasks_seem_expensive = timer_tasks_seem_expensive;
- MainThreadOnly().loading_tasks_seem_expensive = loading_tasks_seem_expensive;
-
- // The |new_policy_duration| is the minimum of |expected_use_case_duration|
- // and |touchstart_expected_flag_valid_for_duration| unless one is zero in
- // which case we choose the other.
- base::TimeDelta new_policy_duration = expected_use_case_duration;
- if (new_policy_duration.is_zero() ||
- (touchstart_expected_flag_valid_for_duration > base::TimeDelta() &&
- new_policy_duration > touchstart_expected_flag_valid_for_duration)) {
- new_policy_duration = touchstart_expected_flag_valid_for_duration;
- }
-
- if (new_policy_duration > base::TimeDelta()) {
- MainThreadOnly().current_policy_expiration_time = now + new_policy_duration;
- delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration,
- now);
- } else {
- MainThreadOnly().current_policy_expiration_time = base::TimeTicks();
- }
-
- // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely
- // slow, because that can cause starvation in other task sources.
- bool main_thread_compositing_is_fast =
- MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration(
- MainThreadOnly().compositor_frame_interval) >
- MainThreadOnly().compositor_frame_interval *
- kFastCompositingIdleTimeThreshold;
-
- Policy new_policy;
- ExpensiveTaskPolicy expensive_task_policy = ExpensiveTaskPolicy::RUN;
- new_policy.rail_mode = v8::PERFORMANCE_ANIMATION;
-
- switch (use_case) {
- case UseCase::COMPOSITOR_GESTURE:
- if (touchstart_expected_soon) {
- new_policy.rail_mode = v8::PERFORMANCE_RESPONSE;
- expensive_task_policy = ExpensiveTaskPolicy::BLOCK;
- new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY;
- } else {
- // What we really want to do is priorize loading tasks, but that doesn't
- // seem to be safe. Instead we do that by proxy by deprioritizing
- // compositor tasks. This should be safe since we've already gone to the
- // pain of fixing ordering issues with them.
- new_policy.compositor_queue_policy.priority =
- TaskQueue::BEST_EFFORT_PRIORITY;
- }
- break;
-
- case UseCase::SYNCHRONIZED_GESTURE:
- new_policy.compositor_queue_policy.priority =
- main_thread_compositing_is_fast ? TaskQueue::HIGH_PRIORITY
- : TaskQueue::NORMAL_PRIORITY;
- if (touchstart_expected_soon) {
- new_policy.rail_mode = v8::PERFORMANCE_RESPONSE;
- expensive_task_policy = ExpensiveTaskPolicy::BLOCK;
- } else {
- expensive_task_policy = ExpensiveTaskPolicy::THROTTLE;
- }
- break;
-
- case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING:
- // In main thread input handling scenarios we don't have perfect knowledge
- // about which things we should be prioritizing, so we don't attempt to
- // block expensive tasks because we don't know whether they were integral
- // to the page's functionality or not.
- new_policy.compositor_queue_policy.priority =
- main_thread_compositing_is_fast ? TaskQueue::HIGH_PRIORITY
- : TaskQueue::NORMAL_PRIORITY;
- break;
-
- case UseCase::MAIN_THREAD_GESTURE:
- // A main thread gesture is for example a scroll gesture which is handled
- // by the main thread. Since we know the established gesture type, we can
- // be a little more aggressive about prioritizing compositing and input
- // handling over other tasks.
- new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY;
- if (touchstart_expected_soon) {
- new_policy.rail_mode = v8::PERFORMANCE_RESPONSE;
- expensive_task_policy = ExpensiveTaskPolicy::BLOCK;
- } else {
- expensive_task_policy = ExpensiveTaskPolicy::THROTTLE;
- }
- break;
-
- case UseCase::TOUCHSTART:
- new_policy.rail_mode = v8::PERFORMANCE_RESPONSE;
- new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY;
- new_policy.loading_queue_policy.is_enabled = false;
- new_policy.timer_queue_policy.is_enabled = false;
- // NOTE this is a nop due to the above.
- expensive_task_policy = ExpensiveTaskPolicy::BLOCK;
- break;
-
- case UseCase::NONE:
- // It's only safe to block tasks that if we are expecting a compositor
- // driven gesture.
- if (touchstart_expected_soon &&
- AnyThread().last_gesture_was_compositor_driven) {
- new_policy.rail_mode = v8::PERFORMANCE_RESPONSE;
- expensive_task_policy = ExpensiveTaskPolicy::BLOCK;
- }
- break;
-
- case UseCase::LOADING:
- new_policy.rail_mode = v8::PERFORMANCE_LOAD;
- new_policy.loading_queue_policy.priority = TaskQueue::HIGH_PRIORITY;
- new_policy.default_queue_policy.priority = TaskQueue::HIGH_PRIORITY;
- break;
-
- default:
- NOTREACHED();
- }
-
- // TODO(skyostil): Add an idle state for foreground tabs too.
- if (MainThreadOnly().renderer_hidden)
- new_policy.rail_mode = v8::PERFORMANCE_IDLE;
-
- if (expensive_task_policy == ExpensiveTaskPolicy::BLOCK &&
- (!MainThreadOnly().expensive_task_blocking_allowed ||
- !MainThreadOnly().have_seen_a_begin_main_frame ||
- MainThreadOnly().navigation_task_expected_count > 0)) {
- expensive_task_policy = ExpensiveTaskPolicy::RUN;
- }
-
- switch (expensive_task_policy) {
- case ExpensiveTaskPolicy::RUN:
- break;
-
- case ExpensiveTaskPolicy::BLOCK:
- if (loading_tasks_seem_expensive)
- new_policy.loading_queue_policy.is_enabled = false;
- if (timer_tasks_seem_expensive)
- new_policy.timer_queue_policy.is_enabled = false;
- break;
-
- case ExpensiveTaskPolicy::THROTTLE:
- if (loading_tasks_seem_expensive) {
- new_policy.loading_queue_policy.time_domain_type =
- TimeDomainType::THROTTLED;
- }
- if (timer_tasks_seem_expensive) {
- new_policy.timer_queue_policy.time_domain_type =
- TimeDomainType::THROTTLED;
- }
- break;
- }
-
- MainThreadOnly().expensive_task_policy = expensive_task_policy;
-
- if (MainThreadOnly().timer_queue_suspend_count != 0 ||
- MainThreadOnly().timer_queue_suspended_when_backgrounded) {
- new_policy.timer_queue_policy.is_enabled = false;
- new_policy.timer_queue_policy.time_domain_type = TimeDomainType::REAL;
- }
-
- if (MainThreadOnly().renderer_suspended) {
- new_policy.loading_queue_policy.is_enabled = false;
- DCHECK(!new_policy.timer_queue_policy.is_enabled);
- }
-
- // Tracing is done before the early out check, because it's quite possible we
- // will otherwise miss this information in traces.
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
- this, AsValueLocked(now));
- TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case",
- use_case);
- TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode",
- new_policy.rail_mode);
- TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "touchstart_expected_soon",
- MainThreadOnly().touchstart_expected_soon);
- TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "expensive_task_policy", expensive_task_policy);
- TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererScheduler.loading_tasks_seem_expensive",
- MainThreadOnly().loading_tasks_seem_expensive);
- TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererScheduler.timer_tasks_seem_expensive",
- MainThreadOnly().timer_tasks_seem_expensive);
-
- // TODO(alexclarke): Can we get rid of force update now?
- if (update_type == UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED &&
- new_policy == MainThreadOnly().current_policy) {
- return;
- }
-
- ApplyTaskQueuePolicy(compositor_task_runner_.get(),
- MainThreadOnly().current_policy.compositor_queue_policy,
- new_policy.compositor_queue_policy);
-
- for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) {
- ApplyTaskQueuePolicy(loading_queue.get(),
- MainThreadOnly().current_policy.loading_queue_policy,
- new_policy.loading_queue_policy);
- }
-
- for (const scoped_refptr<TaskQueue>& timer_queue : timer_task_runners_) {
- ApplyTaskQueuePolicy(timer_queue.get(),
- MainThreadOnly().current_policy.timer_queue_policy,
- new_policy.timer_queue_policy);
- }
- MainThreadOnly().have_reported_blocking_intervention_in_current_policy =
- false;
-
- // TODO(alexclarke): We shouldn't have to prioritize the default queue, but it
- // appears to be necessary since the order of loading tasks and IPCs (which
- // are mostly dispatched on the default queue) need to be preserved.
- ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(),
- MainThreadOnly().current_policy.default_queue_policy,
- new_policy.default_queue_policy);
- if (MainThreadOnly().rail_mode_observer &&
- new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) {
- MainThreadOnly().rail_mode_observer->OnRAILModeChanged(
- new_policy.rail_mode);
- }
-
- DCHECK(compositor_task_runner_->IsQueueEnabled());
- MainThreadOnly().current_policy = new_policy;
-}
-
-void RendererSchedulerImpl::ApplyTaskQueuePolicy(
- TaskQueue* task_queue,
- const TaskQueuePolicy& old_task_queue_policy,
- const TaskQueuePolicy& new_task_queue_policy) const {
- if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) {
- throttling_helper_->SetQueueEnabled(task_queue,
- new_task_queue_policy.is_enabled);
- }
-
- if (old_task_queue_policy.priority != new_task_queue_policy.priority)
- task_queue->SetQueuePriority(new_task_queue_policy.priority);
-
- if (old_task_queue_policy.time_domain_type !=
- new_task_queue_policy.time_domain_type) {
- if (new_task_queue_policy.time_domain_type == TimeDomainType::THROTTLED) {
- throttling_helper_->IncreaseThrottleRefCount(task_queue);
- } else if (old_task_queue_policy.time_domain_type ==
- TimeDomainType::THROTTLED) {
- throttling_helper_->DecreaseThrottleRefCount(task_queue);
- }
- }
-}
-
-RendererSchedulerImpl::UseCase RendererSchedulerImpl::ComputeCurrentUseCase(
- base::TimeTicks now,
- base::TimeDelta* expected_use_case_duration) const {
- any_thread_lock_.AssertAcquired();
- // Special case for flings. This is needed because we don't get notification
- // of a fling ending (although we do for cancellation).
- if (AnyThread().fling_compositor_escalation_deadline > now &&
- !AnyThread().awaiting_touch_start_response) {
- *expected_use_case_duration =
- AnyThread().fling_compositor_escalation_deadline - now;
- return UseCase::COMPOSITOR_GESTURE;
- }
- // Above all else we want to be responsive to user input.
- *expected_use_case_duration =
- AnyThread().user_model.TimeLeftInUserGesture(now);
- if (*expected_use_case_duration > base::TimeDelta()) {
- // Has a gesture been fully established?
- if (AnyThread().awaiting_touch_start_response) {
- // No, so arrange for compositor tasks to be run at the highest priority.
- return UseCase::TOUCHSTART;
- }
-
- // Yes a gesture has been established. Based on how the gesture is handled
- // we need to choose between one of four use cases:
- // 1. COMPOSITOR_GESTURE where the gesture is processed only on the
- // compositor thread.
- // 2. MAIN_THREAD_GESTURE where the gesture is processed only on the main
- // thread.
- // 3. MAIN_THREAD_CUSTOM_INPUT_HANDLING where the main thread processes a
- // stream of input events and has prevented a default gesture from being
- // started.
- // 4. SYNCHRONIZED_GESTURE where the gesture is processed on both threads.
- // TODO(skyostil): Consider removing in_idle_period_ and
- // HadAnIdlePeriodRecently() unless we need them here.
- if (AnyThread().last_gesture_was_compositor_driven) {
- if (AnyThread().begin_main_frame_on_critical_path) {
- return UseCase::SYNCHRONIZED_GESTURE;
- } else {
- return UseCase::COMPOSITOR_GESTURE;
- }
- }
- if (AnyThread().default_gesture_prevented) {
- return UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING;
- } else {
- return UseCase::MAIN_THREAD_GESTURE;
- }
- }
-
- // TODO(alexclarke): return UseCase::LOADING if signals suggest the system is
- // in the initial 1s of RAIL loading.
- return UseCase::NONE;
-}
-
-base::TimeDelta RendererSchedulerImpl::EstimateLongestJankFreeTaskDuration()
- const {
- switch (MainThreadOnly().current_use_case) {
- case UseCase::TOUCHSTART:
- case UseCase::COMPOSITOR_GESTURE:
- case UseCase::LOADING:
- case UseCase::NONE:
- return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis);
-
- case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING:
- case UseCase::MAIN_THREAD_GESTURE:
- case UseCase::SYNCHRONIZED_GESTURE:
- return MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration(
- MainThreadOnly().compositor_frame_interval);
-
- default:
- NOTREACHED();
- return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis);
- }
-}
-
-bool RendererSchedulerImpl::CanEnterLongIdlePeriod(
- base::TimeTicks now,
- base::TimeDelta* next_long_idle_period_delay_out) {
- helper_.CheckOnValidThread();
-
- MaybeUpdatePolicy();
- if (MainThreadOnly().current_use_case == UseCase::TOUCHSTART) {
- // Don't start a long idle task in touch start priority, try again when
- // the policy is scheduled to end.
- *next_long_idle_period_delay_out =
- std::max(base::TimeDelta(),
- MainThreadOnly().current_policy_expiration_time - now);
- return false;
- }
- return true;
-}
-
-SchedulerHelper* RendererSchedulerImpl::GetSchedulerHelperForTesting() {
- return &helper_;
-}
-
-TaskCostEstimator*
-RendererSchedulerImpl::GetLoadingTaskCostEstimatorForTesting() {
- return &MainThreadOnly().loading_task_cost_estimator;
-}
-
-TaskCostEstimator*
-RendererSchedulerImpl::GetTimerTaskCostEstimatorForTesting() {
- return &MainThreadOnly().timer_task_cost_estimator;
-}
-
-IdleTimeEstimator* RendererSchedulerImpl::GetIdleTimeEstimatorForTesting() {
- return &MainThreadOnly().idle_time_estimator;
-}
-
-void RendererSchedulerImpl::SuspendTimerQueue() {
- MainThreadOnly().timer_queue_suspend_count++;
- ForceUpdatePolicy();
-#ifndef NDEBUG
- DCHECK(!default_timer_task_runner_->IsQueueEnabled());
- for (const auto& runner : timer_task_runners_) {
- DCHECK(!runner->IsQueueEnabled());
- }
-#endif
-}
-
-void RendererSchedulerImpl::ResumeTimerQueue() {
- MainThreadOnly().timer_queue_suspend_count--;
- DCHECK_GE(MainThreadOnly().timer_queue_suspend_count, 0);
- ForceUpdatePolicy();
-}
-
-void RendererSchedulerImpl::SetTimerQueueSuspensionWhenBackgroundedEnabled(
- bool enabled) {
- // Note that this will only take effect for the next backgrounded signal.
- MainThreadOnly().timer_queue_suspension_when_backgrounded_enabled = enabled;
-}
-
-std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-RendererSchedulerImpl::AsValue(base::TimeTicks optional_now) const {
- base::AutoLock lock(any_thread_lock_);
- return AsValueLocked(optional_now);
-}
-
-// static
-const char* RendererSchedulerImpl::ExpensiveTaskPolicyToString(
- ExpensiveTaskPolicy expensive_task_policy) {
- switch (expensive_task_policy) {
- case ExpensiveTaskPolicy::RUN:
- return "RUN";
- case ExpensiveTaskPolicy::BLOCK:
- return "BLOCK";
- case ExpensiveTaskPolicy::THROTTLE:
- return "THROTTLE";
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-
-std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
- helper_.CheckOnValidThread();
- any_thread_lock_.AssertAcquired();
-
- if (optional_now.is_null())
- optional_now = helper_.scheduler_tqm_delegate()->NowTicks();
- std::unique_ptr<base::trace_event::TracedValue> state(
- new base::trace_event::TracedValue());
- state->SetBoolean(
- "has_visible_render_widget_with_touch_handler",
- MainThreadOnly().has_visible_render_widget_with_touch_handler);
- state->SetString("current_use_case",
- UseCaseToString(MainThreadOnly().current_use_case));
- state->SetString("rail_mode",
- RAILModeToString(MainThreadOnly().current_policy.rail_mode));
- state->SetBoolean("expensive_task_blocking_allowed",
- MainThreadOnly().expensive_task_blocking_allowed);
- state->SetBoolean("loading_tasks_seem_expensive",
- MainThreadOnly().loading_tasks_seem_expensive);
- state->SetBoolean("timer_tasks_seem_expensive",
- MainThreadOnly().timer_tasks_seem_expensive);
- state->SetBoolean("begin_frame_not_expected_soon",
- MainThreadOnly().begin_frame_not_expected_soon);
- state->SetBoolean("touchstart_expected_soon",
- MainThreadOnly().touchstart_expected_soon);
- state->SetString("idle_period_state",
- IdleHelper::IdlePeriodStateToString(
- idle_helper_.SchedulerIdlePeriodState()));
- state->SetBoolean("renderer_hidden", MainThreadOnly().renderer_hidden);
- state->SetBoolean("have_seen_a_begin_main_frame",
- MainThreadOnly().have_seen_a_begin_main_frame);
- state->SetBoolean(
- "have_reported_blocking_intervention_in_current_policy",
- MainThreadOnly().have_reported_blocking_intervention_in_current_policy);
- state->SetBoolean(
- "have_reported_blocking_intervention_since_navigation",
- MainThreadOnly().have_reported_blocking_intervention_since_navigation);
- state->SetBoolean("renderer_backgrounded",
- MainThreadOnly().renderer_backgrounded);
- state->SetBoolean("timer_queue_suspended_when_backgrounded",
- MainThreadOnly().timer_queue_suspended_when_backgrounded);
- state->SetInteger("timer_queue_suspend_count",
- MainThreadOnly().timer_queue_suspend_count);
- state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF());
- state->SetDouble(
- "rails_loading_priority_deadline",
- (AnyThread().rails_loading_priority_deadline - base::TimeTicks())
- .InMillisecondsF());
- state->SetDouble(
- "fling_compositor_escalation_deadline",
- (AnyThread().fling_compositor_escalation_deadline - base::TimeTicks())
- .InMillisecondsF());
- state->SetInteger("navigation_task_expected_count",
- MainThreadOnly().navigation_task_expected_count);
- state->SetDouble("last_idle_period_end_time",
- (AnyThread().last_idle_period_end_time - base::TimeTicks())
- .InMillisecondsF());
- state->SetBoolean("awaiting_touch_start_response",
- AnyThread().awaiting_touch_start_response);
- state->SetBoolean("begin_main_frame_on_critical_path",
- AnyThread().begin_main_frame_on_critical_path);
- state->SetBoolean("last_gesture_was_compositor_driven",
- AnyThread().last_gesture_was_compositor_driven);
- state->SetBoolean("default_gesture_prevented",
- AnyThread().default_gesture_prevented);
- state->SetDouble("expected_loading_task_duration",
- MainThreadOnly()
- .loading_task_cost_estimator.expected_task_duration()
- .InMillisecondsF());
- state->SetDouble("expected_timer_task_duration",
- MainThreadOnly()
- .timer_task_cost_estimator.expected_task_duration()
- .InMillisecondsF());
- // TODO(skyostil): Can we somehow trace how accurate these estimates were?
- state->SetDouble(
- "longest_jank_free_task_duration",
- MainThreadOnly().longest_jank_free_task_duration.InMillisecondsF());
- state->SetDouble(
- "compositor_frame_interval",
- MainThreadOnly().compositor_frame_interval.InMillisecondsF());
- state->SetDouble(
- "estimated_next_frame_begin",
- (MainThreadOnly().estimated_next_frame_begin - base::TimeTicks())
- .InMillisecondsF());
- state->SetBoolean("in_idle_period", AnyThread().in_idle_period);
-
- state->SetString(
- "expensive_task_policy",
- ExpensiveTaskPolicyToString(MainThreadOnly().expensive_task_policy));
-
- AnyThread().user_model.AsValueInto(state.get());
- render_widget_scheduler_signals_.AsValueInto(state.get());
-
- return std::move(state);
-}
-
-void RendererSchedulerImpl::OnIdlePeriodStarted() {
- base::AutoLock lock(any_thread_lock_);
- AnyThread().in_idle_period = true;
- UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
-}
-
-void RendererSchedulerImpl::OnIdlePeriodEnded() {
- base::AutoLock lock(any_thread_lock_);
- AnyThread().last_idle_period_end_time =
- helper_.scheduler_tqm_delegate()->NowTicks();
- AnyThread().in_idle_period = false;
- UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
-}
-
-void RendererSchedulerImpl::AddPendingNavigation(
- blink::WebScheduler::NavigatingFrameType type) {
- helper_.CheckOnValidThread();
- if (type == blink::WebScheduler::NavigatingFrameType::kMainFrame) {
- MainThreadOnly().navigation_task_expected_count++;
- UpdatePolicy();
- }
-}
-
-void RendererSchedulerImpl::RemovePendingNavigation(
- blink::WebScheduler::NavigatingFrameType type) {
- helper_.CheckOnValidThread();
- DCHECK_GT(MainThreadOnly().navigation_task_expected_count, 0);
- if (type == blink::WebScheduler::NavigatingFrameType::kMainFrame &&
- MainThreadOnly().navigation_task_expected_count > 0) {
- MainThreadOnly().navigation_task_expected_count--;
- UpdatePolicy();
- }
-}
-
-void RendererSchedulerImpl::OnNavigationStarted() {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "RendererSchedulerImpl::OnNavigationStarted");
- base::AutoLock lock(any_thread_lock_);
- AnyThread().rails_loading_priority_deadline =
- helper_.scheduler_tqm_delegate()->NowTicks() +
- base::TimeDelta::FromMilliseconds(
- kRailsInitialLoadingPrioritizationMillis);
- ResetForNavigationLocked();
-}
-
-bool RendererSchedulerImpl::HadAnIdlePeriodRecently(base::TimeTicks now) const {
- return (now - AnyThread().last_idle_period_end_time) <=
- base::TimeDelta::FromMilliseconds(
- kIdlePeriodStarvationThresholdMillis);
-}
-
-void RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded() {
- DCHECK(MainThreadOnly().renderer_backgrounded);
- if (MainThreadOnly().timer_queue_suspended_when_backgrounded)
- return;
-
- MainThreadOnly().timer_queue_suspended_when_backgrounded = true;
- ForceUpdatePolicy();
-}
-
-void RendererSchedulerImpl::ResumeTimerQueueWhenForegrounded() {
- DCHECK(!MainThreadOnly().renderer_backgrounded);
- if (!MainThreadOnly().timer_queue_suspended_when_backgrounded)
- return;
-
- MainThreadOnly().timer_queue_suspended_when_backgrounded = false;
- ForceUpdatePolicy();
-}
-
-void RendererSchedulerImpl::ResetForNavigationLocked() {
- helper_.CheckOnValidThread();
- any_thread_lock_.AssertAcquired();
- AnyThread().user_model.Reset(helper_.scheduler_tqm_delegate()->NowTicks());
- AnyThread().have_seen_touchstart = false;
- MainThreadOnly().loading_task_cost_estimator.Clear();
- MainThreadOnly().timer_task_cost_estimator.Clear();
- MainThreadOnly().idle_time_estimator.Clear();
- MainThreadOnly().have_seen_a_begin_main_frame = false;
- MainThreadOnly().have_reported_blocking_intervention_since_navigation = false;
- UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
-}
-
-void RendererSchedulerImpl::SetTopLevelBlameContext(
- base::trace_event::BlameContext* blame_context) {
- // Any task that runs in the default task runners belongs to the context of
- // all frames (as opposed to a particular frame). Note that the task itself
- // may still enter a more specific blame context if necessary.
- //
- // Per-frame task runners (loading, timers, etc.) are configured with a more
- // specific blame context by WebFrameSchedulerImpl.
- control_task_runner_->SetBlameContext(blame_context);
- DefaultTaskRunner()->SetBlameContext(blame_context);
- default_loading_task_runner_->SetBlameContext(blame_context);
- default_timer_task_runner_->SetBlameContext(blame_context);
- compositor_task_runner_->SetBlameContext(blame_context);
- idle_helper_.IdleTaskRunner()->SetBlameContext(blame_context);
-}
-
-void RendererSchedulerImpl::SetRAILModeObserver(RAILModeObserver* observer) {
- MainThreadOnly().rail_mode_observer = observer;
-}
-
-void RendererSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) {
- helper_.RegisterTimeDomain(time_domain);
-}
-
-void RendererSchedulerImpl::UnregisterTimeDomain(TimeDomain* time_domain) {
- helper_.UnregisterTimeDomain(time_domain);
-}
-
-void RendererSchedulerImpl::SetExpensiveTaskBlockingAllowed(bool allowed) {
- MainThreadOnly().expensive_task_blocking_allowed = allowed;
-}
-
-base::TickClock* RendererSchedulerImpl::tick_clock() const {
- return helper_.scheduler_tqm_delegate().get();
-}
-
-void RendererSchedulerImpl::AddWebViewScheduler(
- WebViewSchedulerImpl* web_view_scheduler) {
- MainThreadOnly().web_view_schedulers.insert(web_view_scheduler);
-}
-
-void RendererSchedulerImpl::RemoveWebViewScheduler(
- WebViewSchedulerImpl* web_view_scheduler) {
- DCHECK(MainThreadOnly().web_view_schedulers.find(web_view_scheduler) !=
- MainThreadOnly().web_view_schedulers.end());
- MainThreadOnly().web_view_schedulers.erase(web_view_scheduler);
-}
-
-void RendererSchedulerImpl::BroadcastConsoleWarning(
- const std::string& message) {
- helper_.CheckOnValidThread();
- for (auto& web_view_scheduler : MainThreadOnly().web_view_schedulers)
- web_view_scheduler->AddConsoleWarning(message);
-}
-
-void RendererSchedulerImpl::OnTriedToExecuteBlockedTask(
- const TaskQueue& queue,
- const base::PendingTask& task) {
- if (!MainThreadOnly().expensive_task_blocking_allowed ||
- MainThreadOnly().current_use_case == UseCase::TOUCHSTART ||
- MainThreadOnly().longest_jank_free_task_duration <
- base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis) ||
- MainThreadOnly().timer_queue_suspend_count ||
- MainThreadOnly().timer_queue_suspended_when_backgrounded) {
- return;
- }
- if (!MainThreadOnly().timer_tasks_seem_expensive &&
- !MainThreadOnly().loading_tasks_seem_expensive) {
- return;
- }
- if (!MainThreadOnly().have_reported_blocking_intervention_in_current_policy) {
- MainThreadOnly().have_reported_blocking_intervention_in_current_policy =
- true;
- TRACE_EVENT_INSTANT0("renderer.scheduler",
- "RendererSchedulerImpl::TaskBlocked",
- TRACE_EVENT_SCOPE_THREAD);
- }
-
- if (!MainThreadOnly().have_reported_blocking_intervention_since_navigation) {
- {
- base::AutoLock lock(any_thread_lock_);
- if (!AnyThread().have_seen_touchstart)
- return;
- }
- MainThreadOnly().have_reported_blocking_intervention_since_navigation =
- true;
- BroadcastConsoleWarning(
- "Blink deferred a task in order to make scrolling smoother. "
- "Your timer and network tasks should take less than 50ms to run "
- "to avoid this. Please see "
- "https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail"
- " and https://crbug.com/574343#c40 for more information.");
- }
-}
-
-// static
-const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) {
- switch (use_case) {
- case UseCase::NONE:
- return "none";
- case UseCase::COMPOSITOR_GESTURE:
- return "compositor_gesture";
- case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING:
- return "main_thread_custom_input_handling";
- case UseCase::SYNCHRONIZED_GESTURE:
- return "synchronized_gesture";
- case UseCase::TOUCHSTART:
- return "touchstart";
- case UseCase::LOADING:
- return "loading";
- case UseCase::MAIN_THREAD_GESTURE:
- return "main_thread_gesture";
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-
-// static
-const char* RendererSchedulerImpl::RAILModeToString(v8::RAILMode rail_mode) {
- switch (rail_mode) {
- case v8::PERFORMANCE_RESPONSE:
- return "response";
- case v8::PERFORMANCE_ANIMATION:
- return "animation";
- case v8::PERFORMANCE_IDLE:
- return "idle";
- case v8::PERFORMANCE_LOAD:
- return "load";
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/renderer_scheduler_impl.h b/chromium/components/scheduler/renderer/renderer_scheduler_impl.h
deleted file mode 100644
index 75ded915c01..00000000000
--- a/chromium/components/scheduler/renderer/renderer_scheduler_impl.h
+++ /dev/null
@@ -1,462 +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 COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_
-#define COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_
-
-#include "base/atomicops.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "components/scheduler/base/pollable_thread_safe_flag.h"
-#include "components/scheduler/child/idle_helper.h"
-#include "components/scheduler/child/scheduler_helper.h"
-#include "components/scheduler/renderer/deadline_task_runner.h"
-#include "components/scheduler/renderer/idle_time_estimator.h"
-#include "components/scheduler/renderer/render_widget_signals.h"
-#include "components/scheduler/renderer/renderer_scheduler.h"
-#include "components/scheduler/renderer/task_cost_estimator.h"
-#include "components/scheduler/renderer/throttling_helper.h"
-#include "components/scheduler/renderer/user_model.h"
-#include "components/scheduler/renderer/web_view_scheduler_impl.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-namespace trace_event {
-class ConvertableToTraceFormat;
-}
-}
-
-namespace scheduler {
-class RenderWidgetSchedulingState;
-class WebViewSchedulerImpl;
-class ThrottlingHelper;
-
-class SCHEDULER_EXPORT RendererSchedulerImpl
- : public RendererScheduler,
- public IdleHelper::Delegate,
- public SchedulerHelper::Observer,
- public RenderWidgetSignals::Observer {
- public:
- // Keep RendererScheduler::UseCaseToString in sync with this enum.
- enum class UseCase {
- // No active use case detected.
- NONE,
- // A continuous gesture (e.g., scroll, pinch) which is being driven by the
- // compositor thread.
- COMPOSITOR_GESTURE,
- // An unspecified touch gesture which is being handled by the main thread.
- // Note that since we don't have a full view of the use case, we should be
- // careful to prioritize all work equally.
- MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- // A continuous gesture (e.g., scroll, pinch) which is being driven by the
- // compositor thread but also observed by the main thread. An example is
- // synchronized scrolling where a scroll listener on the main thread changes
- // page layout based on the current scroll position.
- SYNCHRONIZED_GESTURE,
- // A gesture has recently started and we are about to run main thread touch
- // listeners to find out the actual gesture type. To minimize touch latency,
- // only input handling work should run in this state.
- TOUCHSTART,
- // The page is loading.
- LOADING,
- // A continuous gesture (e.g., scroll) which is being handled by the main
- // thread.
- MAIN_THREAD_GESTURE,
- // Must be the last entry.
- USE_CASE_COUNT,
- FIRST_USE_CASE = NONE,
- };
- static const char* UseCaseToString(UseCase use_case);
- static const char* RAILModeToString(v8::RAILMode rail_mode);
-
- RendererSchedulerImpl(scoped_refptr<SchedulerTqmDelegate> main_task_runner);
- ~RendererSchedulerImpl() override;
-
- // RendererScheduler implementation:
- std::unique_ptr<blink::WebThread> CreateMainThread() override;
- scoped_refptr<TaskQueue> DefaultTaskRunner() override;
- scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override;
- scoped_refptr<TaskQueue> CompositorTaskRunner() override;
- scoped_refptr<TaskQueue> LoadingTaskRunner() override;
- scoped_refptr<TaskQueue> TimerTaskRunner() override;
- scoped_refptr<TaskQueue> NewLoadingTaskRunner(const char* name) override;
- scoped_refptr<TaskQueue> NewTimerTaskRunner(const char* name) override;
- std::unique_ptr<RenderWidgetSchedulingState> NewRenderWidgetSchedulingState()
- override;
- void WillBeginFrame(const cc::BeginFrameArgs& args) override;
- void BeginFrameNotExpectedSoon() override;
- void DidCommitFrameToCompositor() override;
- void DidHandleInputEventOnCompositorThread(
- const blink::WebInputEvent& web_input_event,
- InputEventState event_state) override;
- void DidHandleInputEventOnMainThread(
- const blink::WebInputEvent& web_input_event) override;
- void DidAnimateForInputOnCompositorThread() override;
- void OnRendererBackgrounded() override;
- void OnRendererForegrounded() override;
- void SuspendRenderer() override;
- void AddPendingNavigation(
- blink::WebScheduler::NavigatingFrameType type) override;
- void RemovePendingNavigation(
- blink::WebScheduler::NavigatingFrameType type) override;
- void OnNavigationStarted() override;
- bool IsHighPriorityWorkAnticipated() override;
- bool ShouldYieldForHighPriorityWork() override;
- bool CanExceedIdleDeadlineIfRequired() const override;
- void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override;
- void RemoveTaskObserver(
- base::MessageLoop::TaskObserver* task_observer) override;
- void Shutdown() override;
- void SuspendTimerQueue() override;
- void ResumeTimerQueue() override;
- void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) override;
- void SetTopLevelBlameContext(
- base::trace_event::BlameContext* blame_context) override;
- void SetRAILModeObserver(RAILModeObserver* observer) override;
-
- // RenderWidgetSignals::Observer implementation:
- void SetAllRenderWidgetsHidden(bool hidden) override;
- void SetHasVisibleRenderWidgetWithTouchHandler(
- bool has_visible_render_widget_with_touch_handler) override;
-
- // SchedulerHelper::Observer implementation:
- void OnUnregisterTaskQueue(const scoped_refptr<TaskQueue>& queue) override;
- void OnTriedToExecuteBlockedTask(const TaskQueue& queue,
- const base::PendingTask& task) override;
-
- // Returns a task runner where tasks run at the highest possible priority.
- scoped_refptr<TaskQueue> ControlTaskRunner();
-
- void RegisterTimeDomain(TimeDomain* time_domain);
- void UnregisterTimeDomain(TimeDomain* time_domain);
-
- void SetExpensiveTaskBlockingAllowed(bool allowed);
-
- void AddWebViewScheduler(WebViewSchedulerImpl* web_view_scheduler);
- void RemoveWebViewScheduler(WebViewSchedulerImpl* web_view_scheduler);
-
- // Test helpers.
- SchedulerHelper* GetSchedulerHelperForTesting();
- TaskCostEstimator* GetLoadingTaskCostEstimatorForTesting();
- TaskCostEstimator* GetTimerTaskCostEstimatorForTesting();
- IdleTimeEstimator* GetIdleTimeEstimatorForTesting();
- base::TimeTicks CurrentIdleTaskDeadlineForTesting() const;
- void RunIdleTasksForTesting(const base::Closure& callback);
- void EndIdlePeriodForTesting(const base::Closure& callback,
- base::TimeTicks time_remaining);
- bool PolicyNeedsUpdateForTesting();
-
- base::TickClock* tick_clock() const;
-
- RealTimeDomain* real_time_domain() const {
- return helper_.real_time_domain();
- }
-
- ThrottlingHelper* throttling_helper() { return throttling_helper_.get(); }
-
- private:
- friend class RendererSchedulerImplTest;
- friend class RendererSchedulerImplForTest;
- friend class RenderWidgetSchedulingState;
-
- enum class ExpensiveTaskPolicy { RUN, BLOCK, THROTTLE };
-
- enum class TimeDomainType {
- REAL,
- THROTTLED,
- };
-
- struct TaskQueuePolicy {
- TaskQueuePolicy()
- : is_enabled(true),
- priority(TaskQueue::NORMAL_PRIORITY),
- time_domain_type(TimeDomainType::REAL) {}
-
- bool is_enabled;
- TaskQueue::QueuePriority priority;
- TimeDomainType time_domain_type;
-
- bool operator==(const TaskQueuePolicy& other) const {
- return is_enabled == other.is_enabled && priority == other.priority &&
- time_domain_type == other.time_domain_type;
- }
- };
-
- struct Policy {
- TaskQueuePolicy compositor_queue_policy;
- TaskQueuePolicy loading_queue_policy;
- TaskQueuePolicy timer_queue_policy;
- TaskQueuePolicy default_queue_policy;
- v8::RAILMode rail_mode = v8::PERFORMANCE_ANIMATION;
-
- bool operator==(const Policy& other) const {
- return compositor_queue_policy == other.compositor_queue_policy &&
- loading_queue_policy == other.loading_queue_policy &&
- timer_queue_policy == other.timer_queue_policy &&
- default_queue_policy == other.default_queue_policy &&
- rail_mode == other.rail_mode;
- }
- };
-
- class PollableNeedsUpdateFlag {
- public:
- PollableNeedsUpdateFlag(base::Lock* write_lock);
- ~PollableNeedsUpdateFlag();
-
- // Set the flag. May only be called if |write_lock| is held.
- void SetWhileLocked(bool value);
-
- // Returns true iff the flag is set to true.
- bool IsSet() const;
-
- private:
- base::subtle::Atomic32 flag_;
- base::Lock* write_lock_; // Not owned.
-
- DISALLOW_COPY_AND_ASSIGN(PollableNeedsUpdateFlag);
- };
-
- // IdleHelper::Delegate implementation:
- bool CanEnterLongIdlePeriod(
- base::TimeTicks now,
- base::TimeDelta* next_long_idle_period_delay_out) override;
- void IsNotQuiescent() override {}
- void OnIdlePeriodStarted() override;
- void OnIdlePeriodEnded() override;
-
- void EndIdlePeriod();
-
- // Returns the serialized scheduler state for tracing.
- std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue(
- base::TimeTicks optional_now) const;
- std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValueLocked(
- base::TimeTicks optional_now) const;
-
- static bool ShouldPrioritizeInputEvent(
- const blink::WebInputEvent& web_input_event);
-
- // The amount of time which idle periods can continue being scheduled when the
- // renderer has been hidden, before going to sleep for good.
- static const int kEndIdleWhenHiddenDelayMillis = 10000;
-
- // The amount of time for which loading tasks will be prioritized over
- // other tasks during the initial page load.
- static const int kRailsInitialLoadingPrioritizationMillis = 1000;
-
- // The amount of time in milliseconds we have to respond to user input as
- // defined by RAILS.
- static const int kRailsResponseTimeMillis = 50;
-
- // For the purposes of deciding whether or not it's safe to turn timers and
- // loading tasks on only in idle periods, we regard the system as being as
- // being "idle period" starved if there hasn't been an idle period in the last
- // 10 seconds. This was chosen to be long enough to cover most anticipated
- // user gestures.
- static const int kIdlePeriodStarvationThresholdMillis = 10000;
-
- // The amount of time to wait before suspending shared timers after the
- // renderer has been backgrounded. This is used only if background suspension
- // of shared timers is enabled.
- static const int kSuspendTimersWhenBackgroundedDelayMillis = 5 * 60 * 1000;
-
- // The time we should stay in a priority-escalated mode after a call to
- // DidAnimateForInputOnCompositorThread().
- static const int kFlingEscalationLimitMillis = 100;
-
- // Schedules an immediate PolicyUpdate, if there isn't one already pending and
- // sets |policy_may_need_update_|. Note |any_thread_lock_| must be
- // locked.
- void EnsureUrgentPolicyUpdatePostedOnMainThread(
- const tracked_objects::Location& from_here);
-
- // Update the policy if a new signal has arrived. Must be called from the main
- // thread.
- void MaybeUpdatePolicy();
-
- // Locks |any_thread_lock_| and updates the scheduler policy. May early
- // out if the policy is unchanged. Must be called from the main thread.
- void UpdatePolicy();
-
- // Like UpdatePolicy, except it doesn't early out.
- void ForceUpdatePolicy();
-
- enum class UpdateType {
- MAY_EARLY_OUT_IF_POLICY_UNCHANGED,
- FORCE_UPDATE,
- };
-
- // The implelemtation of UpdatePolicy & ForceUpdatePolicy. It is allowed to
- // early out if |update_type| is MAY_EARLY_OUT_IF_POLICY_UNCHANGED.
- virtual void UpdatePolicyLocked(UpdateType update_type);
-
- // Helper for computing the use case. |expected_usecase_duration| will be
- // filled with the amount of time after which the use case should be updated
- // again. If the duration is zero, a new use case update should not be
- // scheduled. Must be called with |any_thread_lock_| held. Can be called from
- // any thread.
- UseCase ComputeCurrentUseCase(
- base::TimeTicks now,
- base::TimeDelta* expected_use_case_duration) const;
-
- // An input event of some sort happened, the policy may need updating.
- void UpdateForInputEventOnCompositorThread(blink::WebInputEvent::Type type,
- InputEventState input_event_state);
-
- // Returns true if there has been at least one idle period in the last
- // |kIdlePeriodStarvationThresholdMillis|.
- bool HadAnIdlePeriodRecently(base::TimeTicks now) const;
-
- // Helpers for safely suspending/resuming the timer queue after a
- // background/foreground signal.
- void SuspendTimerQueueWhenBackgrounded();
- void ResumeTimerQueueWhenForegrounded();
-
- // The task cost estimators and the UserModel need to be reset upon page
- // nagigation. This function does that. Must be called from the main thread.
- void ResetForNavigationLocked();
-
- // Estimates the maximum task length that won't cause a jank based on the
- // current system state. Must be called from the main thread.
- base::TimeDelta EstimateLongestJankFreeTaskDuration() const;
-
- // Log a console warning message to all WebViews in this process.
- void BroadcastConsoleWarning(const std::string& message);
-
- void ApplyTaskQueuePolicy(TaskQueue* task_queue,
- const TaskQueuePolicy& old_task_queue_policy,
- const TaskQueuePolicy& new_task_queue_policy) const;
-
- static const char* ExpensiveTaskPolicyToString(
- ExpensiveTaskPolicy expensive_task_policy);
-
- SchedulerHelper helper_;
- IdleHelper idle_helper_;
- std::unique_ptr<ThrottlingHelper> throttling_helper_;
- RenderWidgetSignals render_widget_scheduler_signals_;
-
- const scoped_refptr<TaskQueue> control_task_runner_;
- const scoped_refptr<TaskQueue> compositor_task_runner_;
- std::set<scoped_refptr<TaskQueue>> loading_task_runners_;
- std::set<scoped_refptr<TaskQueue>> timer_task_runners_;
- scoped_refptr<TaskQueue> default_loading_task_runner_;
- scoped_refptr<TaskQueue> default_timer_task_runner_;
-
- base::Closure update_policy_closure_;
- DeadlineTaskRunner delayed_update_policy_runner_;
- CancelableClosureHolder end_renderer_hidden_idle_period_closure_;
- CancelableClosureHolder suspend_timers_when_backgrounded_closure_;
-
- // We have decided to improve thread safety at the cost of some boilerplate
- // (the accessors) for the following data members.
-
- struct MainThreadOnly {
- MainThreadOnly(const scoped_refptr<TaskQueue>& compositor_task_runner,
- base::TickClock* time_source);
- ~MainThreadOnly();
-
- TaskCostEstimator loading_task_cost_estimator;
- TaskCostEstimator timer_task_cost_estimator;
- IdleTimeEstimator idle_time_estimator;
- UseCase current_use_case;
- Policy current_policy;
- base::TimeTicks current_policy_expiration_time;
- base::TimeTicks estimated_next_frame_begin;
- base::TimeDelta compositor_frame_interval;
- base::TimeDelta longest_jank_free_task_duration;
- int timer_queue_suspend_count; // TIMER_TASK_QUEUE suspended if non-zero.
- int navigation_task_expected_count;
- ExpensiveTaskPolicy expensive_task_policy;
- bool renderer_hidden;
- bool renderer_backgrounded;
- bool renderer_suspended;
- bool timer_queue_suspension_when_backgrounded_enabled;
- bool timer_queue_suspended_when_backgrounded;
- bool was_shutdown;
- bool loading_tasks_seem_expensive;
- bool timer_tasks_seem_expensive;
- bool touchstart_expected_soon;
- bool have_seen_a_begin_main_frame;
- bool have_reported_blocking_intervention_in_current_policy;
- bool have_reported_blocking_intervention_since_navigation;
- bool has_visible_render_widget_with_touch_handler;
- bool begin_frame_not_expected_soon;
- bool expensive_task_blocking_allowed;
- bool in_idle_period_for_testing;
- std::set<WebViewSchedulerImpl*> web_view_schedulers; // Not owned.
- RAILModeObserver* rail_mode_observer; // Not owned.
- };
-
- struct AnyThread {
- AnyThread();
- ~AnyThread();
-
- base::TimeTicks last_idle_period_end_time;
- base::TimeTicks rails_loading_priority_deadline;
- base::TimeTicks fling_compositor_escalation_deadline;
- UserModel user_model;
- bool awaiting_touch_start_response;
- bool in_idle_period;
- bool begin_main_frame_on_critical_path;
- bool last_gesture_was_compositor_driven;
- bool default_gesture_prevented;
- bool have_seen_touchstart;
- };
-
- struct CompositorThreadOnly {
- CompositorThreadOnly();
- ~CompositorThreadOnly();
-
- blink::WebInputEvent::Type last_input_type;
- std::unique_ptr<base::ThreadChecker> compositor_thread_checker;
-
- void CheckOnValidThread() {
-#if DCHECK_IS_ON()
- // We don't actually care which thread this called from, just so long as
- // its consistent.
- if (!compositor_thread_checker)
- compositor_thread_checker.reset(new base::ThreadChecker());
- DCHECK(compositor_thread_checker->CalledOnValidThread());
-#endif
- }
- };
-
- // Don't access main_thread_only_, instead use MainThreadOnly().
- MainThreadOnly main_thread_only_;
- MainThreadOnly& MainThreadOnly() {
- helper_.CheckOnValidThread();
- return main_thread_only_;
- }
- const struct MainThreadOnly& MainThreadOnly() const {
- helper_.CheckOnValidThread();
- return main_thread_only_;
- }
-
- mutable base::Lock any_thread_lock_;
- // Don't access any_thread_, instead use AnyThread().
- AnyThread any_thread_;
- AnyThread& AnyThread() {
- any_thread_lock_.AssertAcquired();
- return any_thread_;
- }
- const struct AnyThread& AnyThread() const {
- any_thread_lock_.AssertAcquired();
- return any_thread_;
- }
-
- // Don't access compositor_thread_only_, instead use CompositorThreadOnly().
- CompositorThreadOnly compositor_thread_only_;
- CompositorThreadOnly& CompositorThreadOnly() {
- compositor_thread_only_.CheckOnValidThread();
- return compositor_thread_only_;
- }
-
- PollableThreadSafeFlag policy_may_need_update_;
- base::WeakPtrFactory<RendererSchedulerImpl> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImpl);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_
diff --git a/chromium/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/chromium/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
deleted file mode 100644
index bede56febbf..00000000000
--- a/chromium/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
+++ /dev/null
@@ -1,3371 +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 "components/scheduler/renderer/renderer_scheduler_impl.h"
-
-#include <utility>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/output/begin_frame_args.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_impl.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace scheduler {
-
-namespace {
-class FakeInputEvent : public blink::WebInputEvent {
- public:
- explicit FakeInputEvent(blink::WebInputEvent::Type event_type)
- : WebInputEvent(sizeof(FakeInputEvent)) {
- type = event_type;
- }
-
- FakeInputEvent(blink::WebInputEvent::Type event_type, int event_modifiers)
- : WebInputEvent(sizeof(FakeInputEvent)) {
- type = event_type;
- modifiers = event_modifiers;
- }
-};
-
-void AppendToVectorTestTask(std::vector<std::string>* vector,
- std::string value) {
- vector->push_back(value);
-}
-
-void AppendToVectorIdleTestTask(std::vector<std::string>* vector,
- std::string value,
- base::TimeTicks deadline) {
- AppendToVectorTestTask(vector, value);
-}
-
-void NullTask() {
-}
-
-void AppendToVectorReentrantTask(base::SingleThreadTaskRunner* task_runner,
- std::vector<int>* vector,
- int* reentrant_count,
- int max_reentrant_count) {
- vector->push_back((*reentrant_count)++);
- if (*reentrant_count < max_reentrant_count) {
- task_runner->PostTask(
- FROM_HERE,
- base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner),
- vector, reentrant_count, max_reentrant_count));
- }
-}
-
-void IdleTestTask(int* run_count,
- base::TimeTicks* deadline_out,
- base::TimeTicks deadline) {
- (*run_count)++;
- *deadline_out = deadline;
-}
-
-int max_idle_task_reposts = 2;
-
-void RepostingIdleTestTask(SingleThreadIdleTaskRunner* idle_task_runner,
- int* run_count,
- base::TimeTicks deadline) {
- if ((*run_count + 1) < max_idle_task_reposts) {
- idle_task_runner->PostIdleTask(
- FROM_HERE, base::Bind(&RepostingIdleTestTask,
- base::Unretained(idle_task_runner), run_count));
- }
- (*run_count)++;
-}
-
-void RepostingUpdateClockIdleTestTask(
- SingleThreadIdleTaskRunner* idle_task_runner,
- int* run_count,
- base::SimpleTestTickClock* clock,
- base::TimeDelta advance_time,
- std::vector<base::TimeTicks>* deadlines,
- base::TimeTicks deadline) {
- if ((*run_count + 1) < max_idle_task_reposts) {
- idle_task_runner->PostIdleTask(
- FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask,
- base::Unretained(idle_task_runner), run_count,
- clock, advance_time, deadlines));
- }
- deadlines->push_back(deadline);
- (*run_count)++;
- clock->Advance(advance_time);
-}
-
-void WillBeginFrameIdleTask(RendererScheduler* scheduler,
- base::SimpleTestTickClock* clock,
- base::TimeTicks deadline) {
- scheduler->WillBeginFrame(cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL));
-}
-
-void UpdateClockToDeadlineIdleTestTask(base::SimpleTestTickClock* clock,
- int* run_count,
- base::TimeTicks deadline) {
- clock->Advance(deadline - clock->NowTicks());
- (*run_count)++;
-}
-
-void PostingYieldingTestTask(RendererSchedulerImpl* scheduler,
- base::SingleThreadTaskRunner* task_runner,
- bool simulate_input,
- bool* should_yield_before,
- bool* should_yield_after) {
- *should_yield_before = scheduler->ShouldYieldForHighPriorityWork();
- task_runner->PostTask(FROM_HERE, base::Bind(NullTask));
- if (simulate_input) {
- scheduler->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- }
- *should_yield_after = scheduler->ShouldYieldForHighPriorityWork();
-}
-
-enum class SimulateInputType {
- None,
- TouchStart,
- TouchEnd,
- GestureScrollBegin,
- GestureScrollEnd
-};
-
-void AnticipationTestTask(RendererSchedulerImpl* scheduler,
- SimulateInputType simulate_input,
- bool* is_anticipated_before,
- bool* is_anticipated_after) {
- *is_anticipated_before = scheduler->IsHighPriorityWorkAnticipated();
- switch (simulate_input) {
- case SimulateInputType::None:
- break;
-
- case SimulateInputType::TouchStart:
- scheduler->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- break;
-
- case SimulateInputType::TouchEnd:
- scheduler->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchEnd),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- break;
-
- case SimulateInputType::GestureScrollBegin:
- scheduler->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollBegin),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- break;
-
- case SimulateInputType::GestureScrollEnd:
- scheduler->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollEnd),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- break;
- }
- *is_anticipated_after = scheduler->IsHighPriorityWorkAnticipated();
-}
-
-}; // namespace
-
-class RendererSchedulerImplForTest : public RendererSchedulerImpl {
- public:
- using RendererSchedulerImpl::OnIdlePeriodEnded;
- using RendererSchedulerImpl::OnIdlePeriodStarted;
- using RendererSchedulerImpl::EstimateLongestJankFreeTaskDuration;
-
- RendererSchedulerImplForTest(
- scoped_refptr<SchedulerTqmDelegate> main_task_runner)
- : RendererSchedulerImpl(main_task_runner), update_policy_count_(0) {}
-
- void UpdatePolicyLocked(UpdateType update_type) override {
- update_policy_count_++;
- RendererSchedulerImpl::UpdatePolicyLocked(update_type);
-
- std::string use_case = RendererSchedulerImpl::UseCaseToString(
- MainThreadOnly().current_use_case);
- if (MainThreadOnly().touchstart_expected_soon) {
- use_cases_.push_back(use_case + " touchstart expected");
- } else {
- use_cases_.push_back(use_case);
- }
- }
-
- void EnsureUrgentPolicyUpdatePostedOnMainThread() {
- base::AutoLock lock(any_thread_lock_);
- RendererSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread(
- FROM_HERE);
- }
-
- void ScheduleDelayedPolicyUpdate(base::TimeTicks now, base::TimeDelta delay) {
- delayed_update_policy_runner_.SetDeadline(FROM_HERE, delay, now);
- }
-
- bool BeginMainFrameOnCriticalPath() {
- base::AutoLock lock(any_thread_lock_);
- return AnyThread().begin_main_frame_on_critical_path;
- }
-
- int update_policy_count_;
- std::vector<std::string> use_cases_;
-};
-
-// Lets gtest print human readable Policy values.
-::std::ostream& operator<<(::std::ostream& os,
- const RendererSchedulerImpl::UseCase& use_case) {
- return os << RendererSchedulerImpl::UseCaseToString(use_case);
-}
-
-class RendererSchedulerImplTest : public testing::Test {
- public:
- using UseCase = RendererSchedulerImpl::UseCase;
-
- RendererSchedulerImplTest() : clock_(new base::SimpleTestTickClock()) {
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- }
-
- RendererSchedulerImplTest(base::MessageLoop* message_loop)
- : clock_(new base::SimpleTestTickClock()), message_loop_(message_loop) {
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- }
-
- ~RendererSchedulerImplTest() override {}
-
- void SetUp() override {
- if (message_loop_) {
- main_task_runner_ = SchedulerTqmDelegateImpl::Create(
- message_loop_.get(),
- base::WrapUnique(new TestTimeSource(clock_.get())));
- } else {
- mock_task_runner_ = make_scoped_refptr(
- new cc::OrderedSimpleTaskRunner(clock_.get(), false));
- main_task_runner_ = SchedulerTqmDelegateForTest::Create(
- mock_task_runner_,
- base::WrapUnique(new TestTimeSource(clock_.get())));
- }
- Initialize(
- base::WrapUnique(new RendererSchedulerImplForTest(main_task_runner_)));
- }
-
- void Initialize(std::unique_ptr<RendererSchedulerImplForTest> scheduler) {
- scheduler_ = std::move(scheduler);
- default_task_runner_ = scheduler_->DefaultTaskRunner();
- compositor_task_runner_ = scheduler_->CompositorTaskRunner();
- loading_task_runner_ = scheduler_->LoadingTaskRunner();
- idle_task_runner_ = scheduler_->IdleTaskRunner();
- timer_task_runner_ = scheduler_->TimerTaskRunner();
- }
-
- void TearDown() override {
- DCHECK(!mock_task_runner_.get() || !message_loop_.get());
- scheduler_->Shutdown();
- if (mock_task_runner_.get()) {
- // Check that all tests stop posting tasks.
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- while (mock_task_runner_->RunUntilIdle()) {
- }
- } else {
- message_loop_->RunUntilIdle();
- }
- scheduler_.reset();
- }
-
- void RunUntilIdle() {
- // Only one of mock_task_runner_ or message_loop_ should be set.
- DCHECK(!mock_task_runner_.get() || !message_loop_.get());
- if (mock_task_runner_.get())
- mock_task_runner_->RunUntilIdle();
- else
- message_loop_->RunUntilIdle();
- }
-
- void DoMainFrame() {
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = false;
- scheduler_->WillBeginFrame(begin_frame_args);
- scheduler_->DidCommitFrameToCompositor();
- }
-
- void DoMainFrameOnCriticalPath() {
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
- }
-
- void ForceTouchStartToBeExpectedSoon() {
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollEnd),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- clock_->Advance(priority_escalation_after_input_duration() * 2);
- scheduler_->ForceUpdatePolicy();
- }
-
- void SimulateExpensiveTasks(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
- // RunUntilIdle won't actually run all of the SimpleTestTickClock::Advance
- // tasks unless we set AutoAdvanceNow to true :/
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
-
- // Simulate a bunch of expensive tasks
- for (int i = 0; i < 10; i++) {
- task_runner->PostTask(FROM_HERE,
- base::Bind(&base::SimpleTestTickClock::Advance,
- base::Unretained(clock_.get()),
- base::TimeDelta::FromMilliseconds(500)));
- }
-
- RunUntilIdle();
-
- // Switch back to not auto-advancing because we want to be in control of
- // when time advances.
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(false);
- }
-
- enum class TouchEventPolicy {
- SEND_TOUCH_START,
- DONT_SEND_TOUCH_START,
- };
-
- void SimulateCompositorGestureStart(TouchEventPolicy touch_event_policy) {
- if (touch_event_policy == TouchEventPolicy::SEND_TOUCH_START) {
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- }
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollBegin),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- }
-
- // Simulate a gesture where there is an active compositor scroll, but no
- // scroll updates are generated. Instead, the main thread handles
- // non-canceleable touch events, making this an effectively main thread
- // driven gesture.
- void SimulateMainThreadGestureWithoutScrollUpdates() {
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollBegin),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- }
-
- // Simulate a gesture where the main thread handles touch events but does not
- // preventDefault(), allowing the gesture to turn into a compositor driven
- // gesture. This function also verifies the necessary policy updates are
- // scheduled.
- void SimulateMainThreadGestureWithoutPreventDefault() {
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
-
- // Touchstart policy update.
- EXPECT_TRUE(scheduler_->PolicyNeedsUpdateForTesting());
- EXPECT_EQ(UseCase::TOUCHSTART, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_FALSE(scheduler_->PolicyNeedsUpdateForTesting());
-
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureTapCancel),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollBegin),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
-
- // Main thread gesture policy update.
- EXPECT_TRUE(scheduler_->PolicyNeedsUpdateForTesting());
- EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_FALSE(scheduler_->PolicyNeedsUpdateForTesting());
-
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchScrollStarted),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
-
- // Compositor thread gesture policy update.
- EXPECT_TRUE(scheduler_->PolicyNeedsUpdateForTesting());
- EXPECT_EQ(UseCase::COMPOSITOR_GESTURE,
- ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_FALSE(scheduler_->PolicyNeedsUpdateForTesting());
- }
-
- void SimulateMainThreadGestureStart(TouchEventPolicy touch_event_policy,
- blink::WebInputEvent::Type gesture_type) {
- if (touch_event_policy == TouchEventPolicy::SEND_TOUCH_START) {
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart));
-
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove));
-
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove));
- }
- if (gesture_type != blink::WebInputEvent::Undefined) {
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(gesture_type),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(FakeInputEvent(gesture_type));
- }
- }
-
- void SimulateMainThreadInputHandlingCompositorTask(
- base::TimeDelta begin_main_frame_duration) {
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- clock_->Advance(begin_main_frame_duration);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove));
- scheduler_->DidCommitFrameToCompositor();
- }
-
- void SimulateMainThreadCompositorTask(
- base::TimeDelta begin_main_frame_duration) {
- clock_->Advance(begin_main_frame_duration);
- scheduler_->DidCommitFrameToCompositor();
- simulate_compositor_task_ran_ = true;
- }
-
- bool SimulatedCompositorTaskPending() const {
- return !simulate_compositor_task_ran_;
- }
-
- void SimulateTimerTask(base::TimeDelta duration) {
- clock_->Advance(duration);
- simulate_timer_task_ran_ = true;
- }
-
- void EnableIdleTasks() { DoMainFrame(); }
-
- UseCase CurrentUseCase() {
- return scheduler_->MainThreadOnly().current_use_case;
- }
-
- UseCase ForceUpdatePolicyAndGetCurrentUseCase() {
- scheduler_->ForceUpdatePolicy();
- return scheduler_->MainThreadOnly().current_use_case;
- }
-
- v8::RAILMode RAILMode() {
- return scheduler_->MainThreadOnly().current_policy.rail_mode;
- }
-
- bool BeginFrameNotExpectedSoon() {
- return scheduler_->MainThreadOnly().begin_frame_not_expected_soon;
- }
-
- bool TouchStartExpectedSoon() {
- return scheduler_->MainThreadOnly().touchstart_expected_soon;
- }
-
- bool HaveSeenABeginMainframe() {
- return scheduler_->MainThreadOnly().have_seen_a_begin_main_frame;
- }
-
- bool LoadingTasksSeemExpensive() {
- return scheduler_->MainThreadOnly().loading_tasks_seem_expensive;
- }
-
- bool TimerTasksSeemExpensive() {
- return scheduler_->MainThreadOnly().timer_tasks_seem_expensive;
- }
-
- base::TimeTicks EstimatedNextFrameBegin() {
- return scheduler_->MainThreadOnly().estimated_next_frame_begin;
- }
-
- int NavigationTaskExpectedCount() {
- return scheduler_->MainThreadOnly().navigation_task_expected_count;
- }
-
- // Helper for posting several tasks of specific types. |task_descriptor| is a
- // string with space delimited task identifiers. The first letter of each
- // task identifier specifies the task type:
- // - 'D': Default task
- // - 'C': Compositor task
- // - 'L': Loading task
- // - 'I': Idle task
- // - 'T': Timer task
- void PostTestTasks(std::vector<std::string>* run_order,
- const std::string& task_descriptor) {
- std::istringstream stream(task_descriptor);
- while (!stream.eof()) {
- std::string task;
- stream >> task;
- switch (task[0]) {
- case 'D':
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
- break;
- case 'C':
- compositor_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
- break;
- case 'L':
- loading_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
- break;
- case 'I':
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&AppendToVectorIdleTestTask, run_order, task));
- break;
- case 'T':
- timer_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
- break;
- default:
- NOTREACHED();
- }
- }
- }
-
- protected:
- static base::TimeDelta priority_escalation_after_input_duration() {
- return base::TimeDelta::FromMilliseconds(
- UserModel::kGestureEstimationLimitMillis);
- }
-
- static base::TimeDelta subsequent_input_expected_after_input_duration() {
- return base::TimeDelta::FromMilliseconds(
- UserModel::kExpectSubsequentGestureMillis);
- }
-
- static base::TimeDelta maximum_idle_period_duration() {
- return base::TimeDelta::FromMilliseconds(
- IdleHelper::kMaximumIdlePeriodMillis);
- }
-
- static base::TimeDelta end_idle_when_hidden_delay() {
- return base::TimeDelta::FromMilliseconds(
- RendererSchedulerImpl::kEndIdleWhenHiddenDelayMillis);
- }
-
- static base::TimeDelta idle_period_starvation_threshold() {
- return base::TimeDelta::FromMilliseconds(
- RendererSchedulerImpl::kIdlePeriodStarvationThresholdMillis);
- }
-
- static base::TimeDelta suspend_timers_when_backgrounded_delay() {
- return base::TimeDelta::FromMilliseconds(
- RendererSchedulerImpl::kSuspendTimersWhenBackgroundedDelayMillis);
- }
-
- static base::TimeDelta rails_response_time() {
- return base::TimeDelta::FromMilliseconds(
- RendererSchedulerImpl::kRailsResponseTimeMillis);
- }
-
- template <typename E>
- static void CallForEachEnumValue(E first,
- E last,
- const char* (*function)(E)) {
- for (E val = first; val < last;
- val = static_cast<E>(static_cast<int>(val) + 1)) {
- (*function)(val);
- }
- }
-
- static void CheckAllUseCaseToString() {
- CallForEachEnumValue<RendererSchedulerImpl::UseCase>(
- RendererSchedulerImpl::UseCase::FIRST_USE_CASE,
- RendererSchedulerImpl::UseCase::USE_CASE_COUNT,
- &RendererSchedulerImpl::UseCaseToString);
- }
-
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- // Only one of mock_task_runner_ or message_loop_ will be set.
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
- std::unique_ptr<base::MessageLoop> message_loop_;
-
- scoped_refptr<SchedulerTqmDelegate> main_task_runner_;
- std::unique_ptr<RendererSchedulerImplForTest> scheduler_;
- scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner_;
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner_;
- bool simulate_timer_task_ran_;
- bool simulate_compositor_task_ran_;
-
- DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplTest);
-};
-
-TEST_F(RendererSchedulerImplTest, TestPostDefaultTask) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "D1 D2 D3 D4");
-
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D1"), std::string("D2"),
- std::string("D3"), std::string("D4")));
-}
-
-TEST_F(RendererSchedulerImplTest, TestPostDefaultAndCompositor) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "D1 C1");
- RunUntilIdle();
- EXPECT_THAT(run_order, testing::Contains("D1"));
- EXPECT_THAT(run_order, testing::Contains("C1"));
-}
-
-TEST_F(RendererSchedulerImplTest, TestRentrantTask) {
- int count = 0;
- std::vector<int> run_order;
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(AppendToVectorReentrantTask,
- base::RetainedRef(default_task_runner_), &run_order,
- &count, 5));
- RunUntilIdle();
-
- EXPECT_THAT(run_order, testing::ElementsAre(0, 1, 2, 3, 4));
-}
-
-TEST_F(RendererSchedulerImplTest, TestPostIdleTask) {
- int run_count = 0;
- base::TimeTicks expected_deadline =
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(2300);
- base::TimeTicks deadline_in_task;
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(100));
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- RunUntilIdle();
- EXPECT_EQ(0, run_count); // Shouldn't run yet as no WillBeginFrame.
-
- scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL));
- RunUntilIdle();
- EXPECT_EQ(0, run_count); // Shouldn't run as no DidCommitFrameToCompositor.
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(1200));
- scheduler_->DidCommitFrameToCompositor();
- RunUntilIdle();
- EXPECT_EQ(0, run_count); // We missed the deadline.
-
- scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL));
- clock_->Advance(base::TimeDelta::FromMilliseconds(800));
- scheduler_->DidCommitFrameToCompositor();
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
- EXPECT_EQ(expected_deadline, deadline_in_task);
-}
-
-TEST_F(RendererSchedulerImplTest, TestRepostingIdleTask) {
- int run_count = 0;
-
- max_idle_task_reposts = 2;
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&RepostingIdleTestTask,
- base::RetainedRef(idle_task_runner_), &run_count));
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-
- // Reposted tasks shouldn't run until next idle period.
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TestIdleTaskExceedsDeadline) {
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- int run_count = 0;
-
- // Post two UpdateClockToDeadlineIdleTestTask tasks.
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count));
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count));
-
- EnableIdleTasks();
- RunUntilIdle();
- // Only the first idle task should execute since it's used up the deadline.
- EXPECT_EQ(1, run_count);
-
- EnableIdleTasks();
- RunUntilIdle();
- // Second task should be run on the next idle period.
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TestPostIdleTaskAfterWakeup) {
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- EnableIdleTasks();
- RunUntilIdle();
- // Shouldn't run yet as no other task woke up the scheduler.
- EXPECT_EQ(0, run_count);
-
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- EnableIdleTasks();
- RunUntilIdle();
- // Another after wakeup idle task shouldn't wake the scheduler.
- EXPECT_EQ(0, run_count);
-
- default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
-
- RunUntilIdle();
- EnableIdleTasks(); // Must start a new idle period before idle task runs.
- RunUntilIdle();
- // Execution of default task queue task should trigger execution of idle task.
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TestPostIdleTaskAfterWakeupWhileAwake) {
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
-
- RunUntilIdle();
- EnableIdleTasks(); // Must start a new idle period before idle task runs.
- RunUntilIdle();
- // Should run as the scheduler was already awakened by the normal task.
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TestPostIdleTaskWakesAfterWakeupIdleTask) {
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- EnableIdleTasks();
- RunUntilIdle();
- // Must start a new idle period before after-wakeup idle task runs.
- EnableIdleTasks();
- RunUntilIdle();
- // Normal idle task should wake up after-wakeup idle task.
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TestDelayedEndIdlePeriodCanceled) {
- int run_count = 0;
-
- base::TimeTicks deadline_in_task;
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- // Trigger the beginning of an idle period for 1000ms.
- scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL));
- DoMainFrame();
-
- // End the idle period early (after 500ms), and send a WillBeginFrame which
- // specifies that the next idle period should end 1000ms from now.
- clock_->Advance(base::TimeDelta::FromMilliseconds(500));
- scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL));
-
- RunUntilIdle();
- EXPECT_EQ(0, run_count); // Not currently in an idle period.
-
- // Trigger the start of the idle period before the task to end the previous
- // idle period has been triggered.
- clock_->Advance(base::TimeDelta::FromMilliseconds(400));
- scheduler_->DidCommitFrameToCompositor();
-
- // Post a task which simulates running until after the previous end idle
- // period delayed task was scheduled for
- scheduler_->DefaultTaskRunner()->PostTask(FROM_HERE, base::Bind(NullTask));
- clock_->Advance(base::TimeDelta::FromMilliseconds(300));
-
- RunUntilIdle();
- EXPECT_EQ(1, run_count); // We should still be in the new idle period.
-}
-
-TEST_F(RendererSchedulerImplTest, TestDefaultPolicy) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1"),
- std::string("C1"), std::string("D2"),
- std::string("C2"), std::string("I1")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestCompositorPolicy_CompositorHandlesInput_WithTouchHandler) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- EnableIdleTasks();
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1"),
- std::string("D2"), std::string("I1"),
- std::string("C1"), std::string("C2")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE,
- CurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestCompositorPolicy_MainThreadHandlesInput_WithoutScrollUpdates) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- EnableIdleTasks();
- SimulateMainThreadGestureWithoutScrollUpdates();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("L1"), std::string("D1"),
- std::string("D2"), std::string("I1")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- CurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestCompositorPolicy_MainThreadHandlesInput_WithoutPreventDefault) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- EnableIdleTasks();
- SimulateMainThreadGestureWithoutPreventDefault();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1"),
- std::string("D2"), std::string("I1"),
- std::string("C1"), std::string("C2")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE,
- CurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestCompositorPolicy_CompositorHandlesInput_LongGestureDuration) {
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- EnableIdleTasks();
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
-
- base::TimeTicks loop_end_time =
- clock_->NowTicks() + base::TimeDelta::FromMilliseconds(
- UserModel::kMedianGestureDurationMillis * 2);
-
- // The UseCase::COMPOSITOR_GESTURE usecase initially deprioritizes compositor
- // tasks (see TestCompositorPolicy_CompositorHandlesInput_WithTouchHandler)
- // but if the gesture is long enough, compositor tasks get prioritized again.
- while (clock_->NowTicks() < loop_end_time) {
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- clock_->Advance(base::TimeDelta::FromMilliseconds(16));
- RunUntilIdle();
- }
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("L1"), std::string("D1"),
- std::string("D2")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE,
- CurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestCompositorPolicy_CompositorHandlesInput_WithoutTouchHandler) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START);
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1"),
- std::string("D2"), std::string("I1"),
- std::string("C1"), std::string("C2")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE,
- CurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestCompositorPolicy_MainThreadHandlesInput_WithTouchHandler) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- EnableIdleTasks();
- SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollBegin);
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("L1"), std::string("D1"),
- std::string("D2"), std::string("I1")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- CurrentUseCase());
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::GestureFlingStart));
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestCompositorPolicy_MainThreadHandlesInput_WithoutTouchHandler) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollBegin);
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("L1"), std::string("D1"),
- std::string("D2"), std::string("I1")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- CurrentUseCase());
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::GestureFlingStart));
-}
-
-TEST_F(RendererSchedulerImplTest, TestCompositorPolicy_DidAnimateForInput) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D1 C1 D2 C2");
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- scheduler_->DidAnimateForInputOnCompositorThread();
- // Note DidAnimateForInputOnCompositorThread does not by itself trigger a
- // policy update.
- EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE,
- ForceUpdatePolicyAndGetCurrentUseCase());
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D1"), std::string("D2"),
- std::string("I1"), std::string("C1"),
- std::string("C2")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE,
- CurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest, Navigation_ResetsTaskCostEstimations) {
- std::vector<std::string> run_order;
-
- SimulateExpensiveTasks(timer_task_runner_);
- scheduler_->OnNavigationStarted();
- PostTestTasks(&run_order, "C1 T1");
-
- SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollBegin);
- scheduler_->DidCommitFrameToCompositor(); // Starts Idle Period
- RunUntilIdle();
-
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("T1")));
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveTimersDontRunWhenMainThreadScrolling) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(timer_task_runner_);
- DoMainFrame();
- SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollUpdate);
-
- PostTestTasks(&run_order, "C1 T1");
-
- RunUntilIdle();
- EXPECT_FALSE(TouchStartExpectedSoon());
- EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_GESTURE,
- CurrentUseCase());
-
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("C1")));
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveTimersDoRunWhenMainThreadInputHandling) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(timer_task_runner_);
- DoMainFrame();
- SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
- blink::WebInputEvent::Undefined);
-
- PostTestTasks(&run_order, "C1 T1");
-
- RunUntilIdle();
- EXPECT_FALSE(TouchStartExpectedSoon());
- EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- CurrentUseCase());
-
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("T1")));
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveTimersDoRunWhenMainThreadScrolling_AndOnCriticalPath) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(timer_task_runner_);
- DoMainFrameOnCriticalPath();
- SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollBegin);
-
- PostTestTasks(&run_order, "C1 T1");
-
- RunUntilIdle();
- EXPECT_FALSE(TouchStartExpectedSoon());
- EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- CurrentUseCase());
-
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("T1")));
-}
-
-TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy_Compositor) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 D1 C1 D2 C2 T1 T2");
-
- // Observation of touchstart should defer execution of timer, idle and loading
- // tasks.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2")));
-
- // Animation or meta events like TapDown/FlingCancel shouldn't affect the
- // priority.
- run_order.clear();
- scheduler_->DidAnimateForInputOnCompositorThread();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureFlingCancel),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureTapDown),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- // Action events like ScrollBegin will kick us back into compositor priority,
- // allowing service of the timer, loading and idle queues.
- run_order.clear();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollBegin),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
-
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("T1"),
- std::string("T2")));
-}
-
-TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy_MainThread) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 D1 C1 D2 C2 T1 T2");
-
- // Observation of touchstart should defer execution of timer, idle and loading
- // tasks.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart));
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2")));
-
- // Meta events like TapDown/FlingCancel shouldn't affect the priority.
- run_order.clear();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureFlingCancel),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::GestureFlingCancel));
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureTapDown),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::GestureTapDown));
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- // Action events like ScrollBegin will kick us back into compositor priority,
- // allowing service of the timer, loading and idle queues.
- run_order.clear();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollBegin),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollBegin));
- RunUntilIdle();
-
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("T1"),
- std::string("T2")));
-}
-
-// TODO(alexclarke): Reenable once we've reinstaed the Loading UseCase.
-TEST_F(RendererSchedulerImplTest, DISABLED_LoadingUseCase) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D1 C1 T1 L1 D2 C2 T2 L2");
-
- scheduler_->OnNavigationStarted();
- EnableIdleTasks();
- RunUntilIdle();
-
- // In loading policy, loading tasks are prioritized other others.
- std::string loading_policy_expected[] = {
- std::string("D1"), std::string("L1"), std::string("D2"),
- std::string("L2"), std::string("C1"), std::string("T1"),
- std::string("C2"), std::string("T2"), std::string("I1")};
- EXPECT_THAT(run_order, testing::ElementsAreArray(loading_policy_expected));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::LOADING, CurrentUseCase());
-
- // Advance 15s and try again, the loading policy should have ended and the
- // task order should return to the NONE use case where loading tasks are no
- // longer prioritized.
- clock_->Advance(base::TimeDelta::FromMilliseconds(150000));
- run_order.clear();
- PostTestTasks(&run_order, "I1 D1 C1 T1 L1 D2 C2 T2 L2");
- EnableIdleTasks();
- RunUntilIdle();
-
- std::string default_order_expected[] = {
- std::string("D1"), std::string("C1"), std::string("T1"),
- std::string("L1"), std::string("D2"), std::string("C2"),
- std::string("T2"), std::string("L2"), std::string("I1")};
- EXPECT_THAT(run_order, testing::ElementsAreArray(default_order_expected));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest,
- EventConsumedOnCompositorThread_IgnoresMouseMove_WhenMouseUp) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::MouseMove),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
- // Note compositor tasks are not prioritized.
- EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D1"), std::string("C1"),
- std::string("D2"), std::string("C2"),
- std::string("I1")));
-}
-
-TEST_F(RendererSchedulerImplTest,
- EventForwardedToMainThread_IgnoresMouseMove_WhenMouseUp) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::MouseMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- RunUntilIdle();
- // Note compositor tasks are not prioritized.
- EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D1"), std::string("C1"),
- std::string("D2"), std::string("C2"),
- std::string("I1")));
-}
-
-TEST_F(RendererSchedulerImplTest,
- EventConsumedOnCompositorThread_MouseMove_WhenMouseDown) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::MouseMove,
- blink::WebInputEvent::LeftButtonDown),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
- // Note compositor tasks are prioritized.
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2"),
- std::string("I1")));
-}
-
-TEST_F(RendererSchedulerImplTest,
- EventForwardedToMainThread_MouseMove_WhenMouseDown) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::MouseMove,
- blink::WebInputEvent::LeftButtonDown),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- RunUntilIdle();
- // Note compositor tasks are prioritized.
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2"),
- std::string("I1")));
- scheduler_->DidHandleInputEventOnMainThread(FakeInputEvent(
- blink::WebInputEvent::MouseMove, blink::WebInputEvent::LeftButtonDown));
-}
-
-TEST_F(RendererSchedulerImplTest, EventConsumedOnCompositorThread_MouseWheel) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::MouseWheel),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
- // Note compositor tasks are prioritized.
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2"),
- std::string("I1")));
-}
-
-TEST_F(RendererSchedulerImplTest, EventForwardedToMainThread_MouseWheel) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::MouseWheel),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- RunUntilIdle();
- // Note compositor tasks are prioritized.
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2"),
- std::string("I1")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- CurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest,
- EventConsumedOnCompositorThread_IgnoresKeyboardEvents) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::KeyDown),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
- // Note compositor tasks are not prioritized.
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D1"), std::string("C1"),
- std::string("D2"), std::string("C2"),
- std::string("I1")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest,
- EventForwardedToMainThread_IgnoresKeyboardEvents) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "I1 D1 C1 D2 C2");
-
- EnableIdleTasks();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::KeyDown),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- RunUntilIdle();
- // Note compositor tasks are not prioritized.
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D1"), std::string("C1"),
- std::string("D2"), std::string("C2"),
- std::string("I1")));
- EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase());
- // Note compositor tasks are not prioritized.
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::KeyDown));
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestMainthreadScrollingUseCaseDoesNotStarveDefaultTasks) {
- SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollBegin);
- EnableIdleTasks();
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "D1 C1");
-
- for (int i = 0; i < 20; i++) {
- compositor_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
- }
- PostTestTasks(&run_order, "C2");
-
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureFlingStart),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
- // Ensure that the default D1 task gets to run at some point before the final
- // C2 compositor task.
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("D1"),
- std::string("C2")));
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestCompositorPolicyEnds_CompositorHandlesInput) {
- SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START);
- EXPECT_EQ(UseCase::COMPOSITOR_GESTURE,
- ForceUpdatePolicyAndGetCurrentUseCase());
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(1000));
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestCompositorPolicyEnds_MainThreadHandlesInput) {
- SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollBegin);
- EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- ForceUpdatePolicyAndGetCurrentUseCase());
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(1000));
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest, TestTouchstartPolicyEndsAfterTimeout) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 D1 C1 D2 C2");
-
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2")));
-
- run_order.clear();
- clock_->Advance(base::TimeDelta::FromMilliseconds(1000));
-
- // Don't post any compositor tasks to simulate a very long running event
- // handler.
- PostTestTasks(&run_order, "D1 D2");
-
- // Touchstart policy mode should have ended now that the clock has advanced.
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1"),
- std::string("D2")));
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestTouchstartPolicyEndsAfterConsecutiveTouchmoves) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "L1 D1 C1 D2 C2");
-
- // Observation of touchstart should defer execution of idle and loading tasks.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("C2"),
- std::string("D1"), std::string("D2")));
-
- // Receiving the first touchmove will not affect scheduler priority.
- run_order.clear();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- // Receiving the second touchmove will kick us back into compositor priority.
- run_order.clear();
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- RunUntilIdle();
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("L1")));
-}
-
-TEST_F(RendererSchedulerImplTest, TestIsHighPriorityWorkAnticipated) {
- bool is_anticipated_before = false;
- bool is_anticipated_after = false;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(),
- SimulateInputType::None, &is_anticipated_before,
- &is_anticipated_after));
- RunUntilIdle();
- // In its default state, without input receipt, the scheduler should indicate
- // that no high-priority is anticipated.
- EXPECT_FALSE(is_anticipated_before);
- EXPECT_FALSE(is_anticipated_after);
-
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(),
- SimulateInputType::TouchStart,
- &is_anticipated_before, &is_anticipated_after));
- bool dummy;
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(),
- SimulateInputType::TouchEnd, &dummy, &dummy));
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AnticipationTestTask, scheduler_.get(),
- SimulateInputType::GestureScrollBegin, &dummy, &dummy));
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AnticipationTestTask, scheduler_.get(),
- SimulateInputType::GestureScrollEnd, &dummy, &dummy));
-
- RunUntilIdle();
- // When input is received, the scheduler should indicate that high-priority
- // work is anticipated.
- EXPECT_FALSE(is_anticipated_before);
- EXPECT_TRUE(is_anticipated_after);
-
- clock_->Advance(priority_escalation_after_input_duration() * 2);
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(),
- SimulateInputType::None, &is_anticipated_before,
- &is_anticipated_after));
- RunUntilIdle();
- // Without additional input, the scheduler should go into NONE
- // use case but with scrolling expected where high-priority work is still
- // anticipated.
- EXPECT_EQ(UseCase::NONE, CurrentUseCase());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_TRUE(is_anticipated_before);
- EXPECT_TRUE(is_anticipated_after);
-
- clock_->Advance(subsequent_input_expected_after_input_duration() * 2);
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(),
- SimulateInputType::None, &is_anticipated_before,
- &is_anticipated_after));
- RunUntilIdle();
- // Eventually the scheduler should go into the default use case where
- // high-priority work is no longer anticipated.
- EXPECT_EQ(UseCase::NONE, CurrentUseCase());
- EXPECT_FALSE(TouchStartExpectedSoon());
- EXPECT_FALSE(is_anticipated_before);
- EXPECT_FALSE(is_anticipated_after);
-}
-
-TEST_F(RendererSchedulerImplTest, TestShouldYield) {
- bool should_yield_before = false;
- bool should_yield_after = false;
-
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
- base::RetainedRef(default_task_runner_), false,
- &should_yield_before, &should_yield_after));
- RunUntilIdle();
- // Posting to default runner shouldn't cause yielding.
- EXPECT_FALSE(should_yield_before);
- EXPECT_FALSE(should_yield_after);
-
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
- base::RetainedRef(compositor_task_runner_), false,
- &should_yield_before, &should_yield_after));
- RunUntilIdle();
- // Posting while not mainthread scrolling shouldn't cause yielding.
- EXPECT_FALSE(should_yield_before);
- EXPECT_FALSE(should_yield_after);
-
- default_task_runner_->PostTask(
- FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
- base::RetainedRef(compositor_task_runner_), true,
- &should_yield_before, &should_yield_after));
- RunUntilIdle();
- // We should be able to switch to compositor priority mid-task.
- EXPECT_FALSE(should_yield_before);
- EXPECT_TRUE(should_yield_after);
-}
-
-TEST_F(RendererSchedulerImplTest, TestShouldYield_TouchStart) {
- // Receiving a touchstart should immediately trigger yielding, even if
- // there's no immediately pending work in the compositor queue.
- EXPECT_FALSE(scheduler_->ShouldYieldForHighPriorityWork());
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- EXPECT_TRUE(scheduler_->ShouldYieldForHighPriorityWork());
- RunUntilIdle();
-}
-
-TEST_F(RendererSchedulerImplTest, SlowMainThreadInputEvent) {
- EXPECT_EQ(UseCase::NONE, CurrentUseCase());
-
- // An input event should bump us into input priority.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureFlingStart),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- RunUntilIdle();
- EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase());
-
- // Simulate the input event being queued for a very long time. The compositor
- // task we post here represents the enqueued input task.
- clock_->Advance(priority_escalation_after_input_duration() * 2);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::GestureFlingStart));
- RunUntilIdle();
-
- // Even though we exceeded the input priority escalation period, we should
- // still be in main thread gesture since the input remains queued.
- EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase());
-
- // After the escalation period ends we should go back into normal mode.
- clock_->Advance(priority_escalation_after_input_duration() * 2);
- RunUntilIdle();
- EXPECT_EQ(UseCase::NONE, CurrentUseCase());
-}
-
-class RendererSchedulerImplWithMockSchedulerTest
- : public RendererSchedulerImplTest {
- public:
- void SetUp() override {
- mock_task_runner_ = make_scoped_refptr(
- new cc::OrderedSimpleTaskRunner(clock_.get(), false));
- main_task_runner_ = SchedulerTqmDelegateForTest::Create(
- mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get())));
- mock_scheduler_ = new RendererSchedulerImplForTest(main_task_runner_);
- Initialize(base::WrapUnique(mock_scheduler_));
- }
-
- protected:
- RendererSchedulerImplForTest* mock_scheduler_;
-};
-
-TEST_F(RendererSchedulerImplWithMockSchedulerTest,
- OnlyOnePendingUrgentPolicyUpdatey) {
- mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread();
- mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread();
- mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread();
- mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread();
-
- RunUntilIdle();
-
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
-}
-
-TEST_F(RendererSchedulerImplWithMockSchedulerTest,
- OnePendingDelayedAndOneUrgentUpdatePolicy) {
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
-
- mock_scheduler_->ScheduleDelayedPolicyUpdate(
- clock_->NowTicks(), base::TimeDelta::FromMilliseconds(1));
- mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread();
-
- RunUntilIdle();
-
- // We expect both the urgent and the delayed updates to run.
- EXPECT_EQ(2, mock_scheduler_->update_policy_count_);
-}
-
-TEST_F(RendererSchedulerImplWithMockSchedulerTest,
- OneUrgentAndOnePendingDelayedUpdatePolicy) {
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
-
- mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread();
- mock_scheduler_->ScheduleDelayedPolicyUpdate(
- clock_->NowTicks(), base::TimeDelta::FromMilliseconds(1));
-
- RunUntilIdle();
-
- // We expect both the urgent and the delayed updates to run.
- EXPECT_EQ(2, mock_scheduler_->update_policy_count_);
-}
-
-TEST_F(RendererSchedulerImplWithMockSchedulerTest,
- UpdatePolicyCountTriggeredByOneInputEvent) {
- // We expect DidHandleInputEventOnCompositorThread to post an urgent policy
- // update.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- EXPECT_EQ(0, mock_scheduler_->update_policy_count_);
- mock_task_runner_->RunPendingTasks();
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
-
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart));
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(1000));
- RunUntilIdle();
-
- // We finally expect a delayed policy update 100ms later.
- EXPECT_EQ(2, mock_scheduler_->update_policy_count_);
-}
-
-TEST_F(RendererSchedulerImplWithMockSchedulerTest,
- UpdatePolicyCountTriggeredByThreeInputEvents) {
- // We expect DidHandleInputEventOnCompositorThread to post an urgent policy
- // update.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- EXPECT_EQ(0, mock_scheduler_->update_policy_count_);
- mock_task_runner_->RunPendingTasks();
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
-
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart));
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
-
- // The second call to DidHandleInputEventOnCompositorThread should not post a
- // policy update because we are already in compositor priority.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- mock_task_runner_->RunPendingTasks();
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
-
- // We expect DidHandleInputEvent to trigger a policy update.
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove));
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
-
- // The third call to DidHandleInputEventOnCompositorThread should post a
- // policy update because the awaiting_touch_start_response_ flag changed.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
- mock_task_runner_->RunPendingTasks();
- EXPECT_EQ(2, mock_scheduler_->update_policy_count_);
-
- // We expect DidHandleInputEvent to trigger a policy update.
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove));
- EXPECT_EQ(2, mock_scheduler_->update_policy_count_);
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(1000));
- RunUntilIdle();
-
- // We finally expect a delayed policy update.
- EXPECT_EQ(3, mock_scheduler_->update_policy_count_);
-}
-
-TEST_F(RendererSchedulerImplWithMockSchedulerTest,
- UpdatePolicyCountTriggeredByTwoInputEventsWithALongSeparatingDelay) {
- // We expect DidHandleInputEventOnCompositorThread to post an urgent policy
- // update.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- EXPECT_EQ(0, mock_scheduler_->update_policy_count_);
- mock_task_runner_->RunPendingTasks();
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
-
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart));
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(1000));
- RunUntilIdle();
- // We expect a delayed policy update.
- EXPECT_EQ(2, mock_scheduler_->update_policy_count_);
-
- // We expect the second call to DidHandleInputEventOnCompositorThread to post
- // an urgent policy update because we are no longer in compositor priority.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- EXPECT_EQ(2, mock_scheduler_->update_policy_count_);
- mock_task_runner_->RunPendingTasks();
- EXPECT_EQ(3, mock_scheduler_->update_policy_count_);
-
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove));
- EXPECT_EQ(3, mock_scheduler_->update_policy_count_);
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(1000));
- RunUntilIdle();
-
- // We finally expect a delayed policy update.
- EXPECT_EQ(4, mock_scheduler_->update_policy_count_);
-}
-
-TEST_F(RendererSchedulerImplWithMockSchedulerTest,
- EnsureUpdatePolicyNotTriggeredTooOften) {
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
-
- EXPECT_EQ(0, mock_scheduler_->update_policy_count_);
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
-
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
-
- // We expect the first call to IsHighPriorityWorkAnticipated to be called
- // after receiving an input event (but before the UpdateTask was processed) to
- // call UpdatePolicy.
- EXPECT_EQ(1, mock_scheduler_->update_policy_count_);
- scheduler_->IsHighPriorityWorkAnticipated();
- EXPECT_EQ(2, mock_scheduler_->update_policy_count_);
- // Subsequent calls should not call UpdatePolicy.
- scheduler_->IsHighPriorityWorkAnticipated();
- scheduler_->IsHighPriorityWorkAnticipated();
- scheduler_->IsHighPriorityWorkAnticipated();
- scheduler_->ShouldYieldForHighPriorityWork();
- scheduler_->ShouldYieldForHighPriorityWork();
- scheduler_->ShouldYieldForHighPriorityWork();
- scheduler_->ShouldYieldForHighPriorityWork();
-
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollEnd),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchEnd),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
-
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart));
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove));
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove));
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchEnd));
-
- EXPECT_EQ(2, mock_scheduler_->update_policy_count_);
-
- // We expect both the urgent and the delayed updates to run in addition to the
- // earlier updated cause by IsHighPriorityWorkAnticipated, a final update
- // transitions from 'not_scrolling touchstart expected' to 'not_scrolling'.
- RunUntilIdle();
- EXPECT_THAT(
- mock_scheduler_->use_cases_,
- testing::ElementsAre(
- std::string("none"), std::string("compositor_gesture"),
- std::string("compositor_gesture touchstart expected"),
- std::string("none touchstart expected"), std::string("none")));
-}
-
-class RendererSchedulerImplWithMessageLoopTest
- : public RendererSchedulerImplTest {
- public:
- RendererSchedulerImplWithMessageLoopTest()
- : RendererSchedulerImplTest(new base::MessageLoop()) {}
- ~RendererSchedulerImplWithMessageLoopTest() override {}
-
- void PostFromNestedRunloop(std::vector<
- std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>* tasks) {
- base::MessageLoop::ScopedNestableTaskAllower allow(message_loop_.get());
- for (std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>& pair : *tasks) {
- if (pair.second) {
- idle_task_runner_->PostIdleTask(FROM_HERE, pair.first);
- } else {
- idle_task_runner_->PostNonNestableIdleTask(FROM_HERE, pair.first);
- }
- }
- EnableIdleTasks();
- message_loop_->RunUntilIdle();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplWithMessageLoopTest);
-};
-
-TEST_F(RendererSchedulerImplWithMessageLoopTest,
- NonNestableIdleTaskDoesntExecuteInNestedLoop) {
- std::vector<std::string> order;
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("1")));
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("2")));
-
- std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>
- tasks_to_post_from_nested_loop;
- tasks_to_post_from_nested_loop.push_back(std::make_pair(
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("3")),
- false));
- tasks_to_post_from_nested_loop.push_back(std::make_pair(
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("4")), true));
- tasks_to_post_from_nested_loop.push_back(std::make_pair(
- base::Bind(&AppendToVectorIdleTestTask, &order, std::string("5")), true));
-
- default_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(
- &RendererSchedulerImplWithMessageLoopTest::PostFromNestedRunloop,
- base::Unretained(this),
- base::Unretained(&tasks_to_post_from_nested_loop)));
-
- EnableIdleTasks();
- RunUntilIdle();
- // Note we expect task 3 to run last because it's non-nestable.
- EXPECT_THAT(order, testing::ElementsAre(std::string("1"), std::string("2"),
- std::string("4"), std::string("5"),
- std::string("3")));
-}
-
-TEST_F(RendererSchedulerImplTest, TestLongIdlePeriod) {
- base::TimeTicks expected_deadline =
- clock_->NowTicks() + maximum_idle_period_duration();
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- RunUntilIdle();
- EXPECT_EQ(0, run_count); // Shouldn't run yet as no idle period.
-
- scheduler_->BeginFrameNotExpectedSoon();
- RunUntilIdle();
- EXPECT_EQ(1, run_count); // Should have run in a long idle time.
- EXPECT_EQ(expected_deadline, deadline_in_task);
-}
-
-TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodWithPendingDelayedTask) {
- base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(30);
- base::TimeTicks expected_deadline = clock_->NowTicks() + pending_task_delay;
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
- pending_task_delay);
-
- scheduler_->BeginFrameNotExpectedSoon();
- RunUntilIdle();
- EXPECT_EQ(1, run_count); // Should have run in a long idle time.
- EXPECT_EQ(expected_deadline, deadline_in_task);
-}
-
-TEST_F(RendererSchedulerImplTest,
- TestLongIdlePeriodWithLatePendingDelayedTask) {
- base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(10);
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
- pending_task_delay);
-
- // Advance clock until after delayed task was meant to be run.
- clock_->Advance(base::TimeDelta::FromMilliseconds(20));
-
- // Post an idle task and BeginFrameNotExpectedSoon to initiate a long idle
- // period. Since there is a late pending delayed task this shouldn't actually
- // start an idle period.
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- scheduler_->BeginFrameNotExpectedSoon();
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- // After the delayed task has been run we should trigger an idle period.
- clock_->Advance(maximum_idle_period_duration());
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodRepeating) {
- mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
- std::vector<base::TimeTicks> actual_deadlines;
- int run_count = 0;
-
- max_idle_task_reposts = 3;
- base::TimeTicks clock_before(clock_->NowTicks());
- base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10));
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingUpdateClockIdleTestTask,
- base::RetainedRef(idle_task_runner_), &run_count, clock_.get(),
- idle_task_runtime, &actual_deadlines));
- scheduler_->BeginFrameNotExpectedSoon();
- RunUntilIdle();
- EXPECT_EQ(3, run_count);
- EXPECT_THAT(
- actual_deadlines,
- testing::ElementsAre(
- clock_before + maximum_idle_period_duration(),
- clock_before + idle_task_runtime + maximum_idle_period_duration(),
- clock_before + (2 * idle_task_runtime) +
- maximum_idle_period_duration()));
-
- // Check that idle tasks don't run after the idle period ends with a
- // new BeginMainFrame.
- max_idle_task_reposts = 5;
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&RepostingUpdateClockIdleTestTask,
- base::RetainedRef(idle_task_runner_), &run_count, clock_.get(),
- idle_task_runtime, &actual_deadlines));
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&WillBeginFrameIdleTask,
- base::Unretained(scheduler_.get()), clock_.get()));
- RunUntilIdle();
- EXPECT_EQ(4, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodDoesNotWakeScheduler) {
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- // Start a long idle period and get the time it should end.
- scheduler_->BeginFrameNotExpectedSoon();
- // The scheduler should not run the initiate_next_long_idle_period task if
- // there are no idle tasks and no other task woke up the scheduler, thus
- // the idle period deadline shouldn't update at the end of the current long
- // idle period.
- base::TimeTicks idle_period_deadline =
- scheduler_->CurrentIdleTaskDeadlineForTesting();
- clock_->Advance(maximum_idle_period_duration());
- RunUntilIdle();
-
- base::TimeTicks new_idle_period_deadline =
- scheduler_->CurrentIdleTaskDeadlineForTesting();
- EXPECT_EQ(idle_period_deadline, new_idle_period_deadline);
-
- // Posting a after-wakeup idle task also shouldn't wake the scheduler or
- // initiate the next long idle period.
- idle_task_runner_->PostIdleTaskAfterWakeup(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
- RunUntilIdle();
- new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting();
- EXPECT_EQ(idle_period_deadline, new_idle_period_deadline);
- EXPECT_EQ(0, run_count);
-
- // Running a normal task should initiate a new long idle period though.
- default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
- RunUntilIdle();
- new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting();
- EXPECT_EQ(idle_period_deadline + maximum_idle_period_duration(),
- new_idle_period_deadline);
-
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodInTouchStartPolicy) {
- base::TimeTicks deadline_in_task;
- int run_count = 0;
-
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-
- // Observation of touchstart should defer the start of the long idle period.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- scheduler_->BeginFrameNotExpectedSoon();
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- // The long idle period should start after the touchstart policy has finished.
- clock_->Advance(priority_escalation_after_input_duration());
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
-}
-
-void TestCanExceedIdleDeadlineIfRequiredTask(RendererScheduler* scheduler,
- bool* can_exceed_idle_deadline_out,
- int* run_count,
- base::TimeTicks deadline) {
- *can_exceed_idle_deadline_out = scheduler->CanExceedIdleDeadlineIfRequired();
- (*run_count)++;
-}
-
-TEST_F(RendererSchedulerImplTest, CanExceedIdleDeadlineIfRequired) {
- int run_count = 0;
- bool can_exceed_idle_deadline = false;
-
- // Should return false if not in an idle period.
- EXPECT_FALSE(scheduler_->CanExceedIdleDeadlineIfRequired());
-
- // Should return false for short idle periods.
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
- &can_exceed_idle_deadline, &run_count));
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_EQ(1, run_count);
- EXPECT_FALSE(can_exceed_idle_deadline);
-
- // Should return false for a long idle period which is shortened due to a
- // pending delayed task.
- default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
- base::TimeDelta::FromMilliseconds(10));
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
- &can_exceed_idle_deadline, &run_count));
- scheduler_->BeginFrameNotExpectedSoon();
- RunUntilIdle();
- EXPECT_EQ(2, run_count);
- EXPECT_FALSE(can_exceed_idle_deadline);
-
- // Next long idle period will be for the maximum time, so
- // CanExceedIdleDeadlineIfRequired should return true.
- clock_->Advance(maximum_idle_period_duration());
- idle_task_runner_->PostIdleTask(
- FROM_HERE,
- base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
- &can_exceed_idle_deadline, &run_count));
- RunUntilIdle();
- EXPECT_EQ(3, run_count);
- EXPECT_TRUE(can_exceed_idle_deadline);
-
- // Next long idle period will be for the maximum time, so
- // CanExceedIdleDeadlineIfRequired should return true.
- scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL));
- EXPECT_FALSE(scheduler_->CanExceedIdleDeadlineIfRequired());
-}
-
-TEST_F(RendererSchedulerImplTest, TestRendererHiddenIdlePeriod) {
- int run_count = 0;
-
- max_idle_task_reposts = 2;
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&RepostingIdleTestTask,
- base::RetainedRef(idle_task_runner_), &run_count));
-
- // Renderer should start in visible state.
- RunUntilIdle();
- EXPECT_EQ(0, run_count);
-
- // When we hide the renderer it should start a max deadline idle period, which
- // will run an idle task and then immediately start a new idle period, which
- // runs the second idle task.
- scheduler_->SetAllRenderWidgetsHidden(true);
- RunUntilIdle();
- EXPECT_EQ(2, run_count);
-
- // Advance time by amount of time by the maximum amount of time we execute
- // idle tasks when hidden (plus some slack) - idle period should have ended.
- max_idle_task_reposts = 3;
- idle_task_runner_->PostIdleTask(
- FROM_HERE, base::Bind(&RepostingIdleTestTask,
- base::RetainedRef(idle_task_runner_), &run_count));
- clock_->Advance(end_idle_when_hidden_delay() +
- base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- EXPECT_EQ(2, run_count);
-}
-
-TEST_F(RendererSchedulerImplTest, TimerQueueEnabledByDefault) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("T1"), std::string("T2")));
-}
-
-TEST_F(RendererSchedulerImplTest, SuspendAndResumeTimerQueue) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
-
- scheduler_->SuspendTimerQueue();
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- scheduler_->ResumeTimerQueue();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("T1"), std::string("T2")));
-}
-
-TEST_F(RendererSchedulerImplTest, SuspendAndThrottleTimerQueue) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
-
- scheduler_->SuspendTimerQueue();
- RunUntilIdle();
- scheduler_->throttling_helper()->IncreaseThrottleRefCount(
- static_cast<TaskQueue*>(timer_task_runner_.get()));
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-}
-
-TEST_F(RendererSchedulerImplTest, ThrottleAndSuspendTimerQueue) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
-
- scheduler_->throttling_helper()->IncreaseThrottleRefCount(
- static_cast<TaskQueue*>(timer_task_runner_.get()));
- RunUntilIdle();
- scheduler_->SuspendTimerQueue();
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-}
-
-TEST_F(RendererSchedulerImplTest, MultipleSuspendsNeedMultipleResumes) {
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
-
- scheduler_->SuspendTimerQueue();
- scheduler_->SuspendTimerQueue();
- scheduler_->SuspendTimerQueue();
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- scheduler_->ResumeTimerQueue();
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- scheduler_->ResumeTimerQueue();
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- scheduler_->ResumeTimerQueue();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("T1"), std::string("T2")));
-}
-
-TEST_F(RendererSchedulerImplTest, SuspendRenderer) {
- // Assume that the renderer is backgrounded.
- scheduler_->OnRendererBackgrounded();
-
- // Tasks in some queues don't fire when the renderer is suspended.
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "D1 C1 L1 I1 T1");
- scheduler_->SuspendRenderer();
- EnableIdleTasks();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("D1"), std::string("C1"),
- std::string("I1")));
-
- // The rest queued tasks fire when the tab goes foregrounded.
- run_order.clear();
- scheduler_->OnRendererForegrounded();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("T1")));
-}
-
-TEST_F(RendererSchedulerImplTest, UseCaseToString) {
- CheckAllUseCaseToString();
-}
-
-TEST_F(RendererSchedulerImplTest, MismatchedDidHandleInputEventOnMainThread) {
- // This should not DCHECK because there was no corresponding compositor side
- // call to DidHandleInputEventOnCompositorThread with
- // INPUT_EVENT_ACK_STATE_NOT_CONSUMED. There are legitimate reasons for the
- // compositor to not be there and we don't want to make debugging impossible.
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::GestureFlingStart));
-}
-
-TEST_F(RendererSchedulerImplTest, BeginMainFrameOnCriticalPath) {
- ASSERT_FALSE(scheduler_->BeginMainFrameOnCriticalPath());
-
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL);
- scheduler_->WillBeginFrame(begin_frame_args);
- ASSERT_TRUE(scheduler_->BeginMainFrameOnCriticalPath());
-
- begin_frame_args.on_critical_path = false;
- scheduler_->WillBeginFrame(begin_frame_args);
- ASSERT_FALSE(scheduler_->BeginMainFrameOnCriticalPath());
-}
-
-TEST_F(RendererSchedulerImplTest, ShutdownPreventsPostingOfNewTasks) {
- scheduler_->Shutdown();
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "D1 C1");
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-}
-
-TEST_F(RendererSchedulerImplTest, TestRendererBackgroundedTimerSuspension) {
- scheduler_->SetTimerQueueSuspensionWhenBackgroundedEnabled(true);
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
-
- // The background signal will not immediately suspend the timer queue.
- scheduler_->OnRendererBackgrounded();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("T1"), std::string("T2")));
-
- run_order.clear();
- PostTestTasks(&run_order, "T3");
- RunUntilIdle();
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("T3")));
-
- // Advance the time until after the scheduled timer queue suspension.
- run_order.clear();
- clock_->Advance(suspend_timers_when_backgrounded_delay() +
- base::TimeDelta::FromMilliseconds(10));
- RunUntilIdle();
- ASSERT_TRUE(run_order.empty());
-
- // Timer tasks should be suspended until the foregrounded signal.
- PostTestTasks(&run_order, "T4 T5");
- RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- scheduler_->OnRendererForegrounded();
- RunUntilIdle();
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("T4"), std::string("T5")));
-
- // Subsequent timer tasks should fire as usual.
- run_order.clear();
- PostTestTasks(&run_order, "T6");
- RunUntilIdle();
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("T6")));
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveLoadingTasksNotBlockedTillFirstBeginMainFrame) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(loading_task_runner_);
- ForceTouchStartToBeExpectedSoon();
- PostTestTasks(&run_order, "L1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_FALSE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1")));
-
- // Emit a BeginMainFrame, and the loading task should get blocked.
- DoMainFrame();
- run_order.clear();
-
- PostTestTasks(&run_order, "L1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode());
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveLoadingTasksNotBlockedIfNoTouchHandler) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(false);
- DoMainFrame();
- SimulateExpensiveTasks(loading_task_runner_);
- ForceTouchStartToBeExpectedSoon();
- PostTestTasks(&run_order, "L1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_FALSE(TouchStartExpectedSoon());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode());
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveTimerTaskBlocked_UseCase_NONE_PreviousCompositorGesture) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- ForceTouchStartToBeExpectedSoon();
-
- PostTestTasks(&run_order, "T1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_FALSE(LoadingTasksSeemExpensive());
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode());
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveTimerTaskNotBlocked_UseCase_NONE_PreviousMainThreadGesture) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
-
- SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollBegin);
- EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- ForceUpdatePolicyAndGetCurrentUseCase());
-
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchEnd),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- scheduler_->DidHandleInputEventOnMainThread(
- FakeInputEvent(blink::WebInputEvent::TouchEnd));
-
- clock_->Advance(priority_escalation_after_input_duration() * 2);
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
-
- PostTestTasks(&run_order, "T1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_FALSE(LoadingTasksSeemExpensive());
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("T1"), std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode());
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveTimerTaskBlocked_UseCase_COMPOSITOR_GESTURE) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- ForceTouchStartToBeExpectedSoon();
- scheduler_->DidAnimateForInputOnCompositorThread();
-
- PostTestTasks(&run_order, "T1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(UseCase::COMPOSITOR_GESTURE,
- ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_FALSE(LoadingTasksSeemExpensive());
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode());
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveTimerTaskNotBlockedIfDisallowed_UseCase_COMPOSITOR_GESTURE) {
- std::vector<std::string> run_order;
-
- scheduler_->SetExpensiveTaskBlockingAllowed(false);
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- ForceTouchStartToBeExpectedSoon();
- scheduler_->DidAnimateForInputOnCompositorThread();
-
- PostTestTasks(&run_order, "T1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(UseCase::COMPOSITOR_GESTURE,
- ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_FALSE(LoadingTasksSeemExpensive());
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("T1"),
- std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode());
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveTimerTaskBlocked_EvenIfBeginMainFrameNotExpectedSoon) {
- std::vector<std::string> run_order;
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- ForceTouchStartToBeExpectedSoon();
- scheduler_->BeginFrameNotExpectedSoon();
-
- PostTestTasks(&run_order, "T1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_FALSE(LoadingTasksSeemExpensive());
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode());
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveLoadingTasksBlockedIfChildFrameNavigationExpected) {
- std::vector<std::string> run_order;
-
- DoMainFrame();
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(loading_task_runner_);
- ForceTouchStartToBeExpectedSoon();
- scheduler_->AddPendingNavigation(
- blink::WebScheduler::NavigatingFrameType::kChildFrame);
-
- PostTestTasks(&run_order, "L1 D1");
- RunUntilIdle();
-
- // The expensive loading task gets blocked.
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode());
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveLoadingTasksNotBlockedIfMainFrameNavigationExpected) {
- std::vector<std::string> run_order;
-
- DoMainFrame();
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(loading_task_runner_);
- ForceTouchStartToBeExpectedSoon();
- scheduler_->AddPendingNavigation(
- blink::WebScheduler::NavigatingFrameType::kMainFrame);
-
- PostTestTasks(&run_order, "L1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_EQ(1, NavigationTaskExpectedCount());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1")));
-
- // After the nagigation has been cancelled, the expensive loading tasks should
- // get blocked.
- scheduler_->RemovePendingNavigation(
- blink::WebScheduler::NavigatingFrameType::kMainFrame);
- run_order.clear();
-
- PostTestTasks(&run_order, "L1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_EQ(0, NavigationTaskExpectedCount());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode());
-}
-
-TEST_F(
- RendererSchedulerImplTest,
- ExpensiveLoadingTasksNotBlockedIfMainFrameNavigationExpected_Multiple) {
- std::vector<std::string> run_order;
-
- DoMainFrame();
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateExpensiveTasks(loading_task_runner_);
- ForceTouchStartToBeExpectedSoon();
- scheduler_->AddPendingNavigation(
- blink::WebScheduler::NavigatingFrameType::kMainFrame);
- scheduler_->AddPendingNavigation(
- blink::WebScheduler::NavigatingFrameType::kMainFrame);
-
- PostTestTasks(&run_order, "L1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_EQ(2, NavigationTaskExpectedCount());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1")));
-
-
- run_order.clear();
- scheduler_->RemovePendingNavigation(
- blink::WebScheduler::NavigatingFrameType::kMainFrame);
- // Navigation task expected ref count non-zero so expensive tasks still not
- // blocked.
- PostTestTasks(&run_order, "L1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_EQ(1, NavigationTaskExpectedCount());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("L1"), std::string("D1")));
-
-
- run_order.clear();
- scheduler_->RemovePendingNavigation(
- blink::WebScheduler::NavigatingFrameType::kMainFrame);
- // Navigation task expected ref count is now zero, the expensive loading tasks
- // should get blocked.
- PostTestTasks(&run_order, "L1 D1");
- RunUntilIdle();
-
- EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase());
- EXPECT_TRUE(HaveSeenABeginMainframe());
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_EQ(0, NavigationTaskExpectedCount());
- EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1")));
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode());
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveLoadingTasksNotBlockedDuringMainThreadGestures) {
- std::vector<std::string> run_order;
-
- SimulateExpensiveTasks(loading_task_runner_);
-
- // Loading tasks should not be disabled during main thread user interactions.
- PostTestTasks(&run_order, "C1 L1");
-
- // Trigger main_thread_gesture UseCase
- SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollBegin);
- RunUntilIdle();
- EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- CurrentUseCase());
-
- EXPECT_TRUE(LoadingTasksSeemExpensive());
- EXPECT_FALSE(TimerTasksSeemExpensive());
- EXPECT_THAT(run_order,
- testing::ElementsAre(std::string("C1"), std::string("L1")));
- EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode());
-}
-
-TEST_F(RendererSchedulerImplTest, ModeratelyExpensiveTimer_NotBlocked) {
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
- blink::WebInputEvent::TouchMove);
- RunUntilIdle();
- for (int i = 0; i < 20; i++) {
- simulate_timer_task_ran_ = false;
-
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = false;
- scheduler_->WillBeginFrame(begin_frame_args);
-
- compositor_task_runner_->PostTask(
- FROM_HERE, base::Bind(&RendererSchedulerImplTest::
- SimulateMainThreadInputHandlingCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(8)));
- timer_task_runner_->PostTask(
- FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(4)));
-
- RunUntilIdle();
- EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
- EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- CurrentUseCase())
- << " i = " << i;
- EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i;
- EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i;
-
- base::TimeDelta time_till_next_frame =
- EstimatedNextFrameBegin() - clock_->NowTicks();
- if (time_till_next_frame > base::TimeDelta())
- clock_->Advance(time_till_next_frame);
- }
-}
-
-TEST_F(RendererSchedulerImplTest,
- FourtyMsTimer_NotBlocked_CompositorScrolling) {
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- RunUntilIdle();
- for (int i = 0; i < 20; i++) {
- simulate_timer_task_ran_ = false;
-
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = false;
- scheduler_->WillBeginFrame(begin_frame_args);
- scheduler_->DidAnimateForInputOnCompositorThread();
-
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(8)));
- timer_task_runner_->PostTask(
- FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(40)));
-
- RunUntilIdle();
- EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
- EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE,
- CurrentUseCase())
- << " i = " << i;
- EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i;
- EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i;
-
- base::TimeDelta time_till_next_frame =
- EstimatedNextFrameBegin() - clock_->NowTicks();
- if (time_till_next_frame > base::TimeDelta())
- clock_->Advance(time_till_next_frame);
- }
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveTimer_NotBlocked_UseCase_MAIN_THREAD_CUSTOM_INPUT_HANDLING) {
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
- blink::WebInputEvent::TouchMove);
- RunUntilIdle();
- for (int i = 0; i < 20; i++) {
- simulate_timer_task_ran_ = false;
-
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = false;
- scheduler_->WillBeginFrame(begin_frame_args);
-
- compositor_task_runner_->PostTask(
- FROM_HERE, base::Bind(&RendererSchedulerImplTest::
- SimulateMainThreadInputHandlingCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(8)));
- timer_task_runner_->PostTask(
- FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(10)));
-
- RunUntilIdle();
- EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING,
- CurrentUseCase())
- << " i = " << i;
- EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i;
- if (i == 0) {
- EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i;
- } else {
- EXPECT_TRUE(TimerTasksSeemExpensive()) << " i = " << i;
- }
- EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
-
- base::TimeDelta time_till_next_frame =
- EstimatedNextFrameBegin() - clock_->NowTicks();
- if (time_till_next_frame > base::TimeDelta())
- clock_->Advance(time_till_next_frame);
- }
-}
-
-TEST_F(RendererSchedulerImplTest,
- EstimateLongestJankFreeTaskDuration_UseCase_NONE) {
- EXPECT_EQ(UseCase::NONE, CurrentUseCase());
- EXPECT_EQ(rails_response_time(),
- scheduler_->EstimateLongestJankFreeTaskDuration());
-}
-
-TEST_F(RendererSchedulerImplTest,
- EstimateLongestJankFreeTaskDuration_UseCase_COMPOSITOR_GESTURE) {
- SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START);
- EXPECT_EQ(UseCase::COMPOSITOR_GESTURE,
- ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_EQ(rails_response_time(),
- scheduler_->EstimateLongestJankFreeTaskDuration());
-}
-
-// TODO(alexclarke): Reenable once we've reinstaed the Loading UseCase.
-TEST_F(RendererSchedulerImplTest,
- DISABLED_EstimateLongestJankFreeTaskDuration_UseCase_) {
- scheduler_->OnNavigationStarted();
- EXPECT_EQ(UseCase::LOADING, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_EQ(rails_response_time(),
- scheduler_->EstimateLongestJankFreeTaskDuration());
-}
-
-TEST_F(RendererSchedulerImplTest,
- EstimateLongestJankFreeTaskDuration_UseCase_MAIN_THREAD_GESTURE) {
- SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollUpdate);
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = false;
- scheduler_->WillBeginFrame(begin_frame_args);
-
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImplTest::
- SimulateMainThreadInputHandlingCompositorTask,
- base::Unretained(this), base::TimeDelta::FromMilliseconds(5)));
-
- RunUntilIdle();
- EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, CurrentUseCase());
-
- // 16ms frame - 5ms compositor work = 11ms for other stuff.
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
- scheduler_->EstimateLongestJankFreeTaskDuration());
-}
-
-TEST_F(
- RendererSchedulerImplTest,
- EstimateLongestJankFreeTaskDuration_UseCase_MAIN_THREAD_CUSTOM_INPUT_HANDLING) {
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = false;
- scheduler_->WillBeginFrame(begin_frame_args);
-
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImplTest::
- SimulateMainThreadInputHandlingCompositorTask,
- base::Unretained(this), base::TimeDelta::FromMilliseconds(5)));
-
- RunUntilIdle();
- EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase());
-
- // 16ms frame - 5ms compositor work = 11ms for other stuff.
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
- scheduler_->EstimateLongestJankFreeTaskDuration());
-}
-
-TEST_F(RendererSchedulerImplTest,
- EstimateLongestJankFreeTaskDuration_UseCase_SYNCHRONIZED_GESTURE) {
- SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START);
-
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
-
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
- base::Unretained(this), base::TimeDelta::FromMilliseconds(5)));
-
- RunUntilIdle();
- EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase());
-
- // 16ms frame - 5ms compositor work = 11ms for other stuff.
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(11),
- scheduler_->EstimateLongestJankFreeTaskDuration());
-}
-
-class WebViewSchedulerImplForTest : public WebViewSchedulerImpl {
- public:
- WebViewSchedulerImplForTest(RendererSchedulerImpl* scheduler)
- : WebViewSchedulerImpl(nullptr, scheduler, false) {}
- ~WebViewSchedulerImplForTest() override {}
-
- void AddConsoleWarning(const std::string& message) override {
- console_warnings_.push_back(message);
- }
-
- const std::vector<std::string>& console_warnings() const {
- return console_warnings_;
- }
-
- private:
- std::vector<std::string> console_warnings_;
-
- DISALLOW_COPY_AND_ASSIGN(WebViewSchedulerImplForTest);
-};
-
-TEST_F(RendererSchedulerImplTest, BlockedTimerNotification) {
- // Make sure we see one (and just one) console warning about an expensive
- // timer being deferred.
- WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get());
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- scheduler_->SetExpensiveTaskBlockingAllowed(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
- ForceTouchStartToBeExpectedSoon();
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
- RunUntilIdle();
-
- EXPECT_EQ(0u, run_order.size());
- EXPECT_EQ(1u, web_view_scheduler.console_warnings().size());
- EXPECT_NE(std::string::npos,
- web_view_scheduler.console_warnings()[0].find("crbug.com/574343"));
-}
-
-TEST_F(RendererSchedulerImplTest,
- BlockedTimerNotification_ExpensiveTaskBlockingNotAllowed) {
- // Make sure we don't report warnings about blocked tasks when expensive task
- // blocking is not allowed.
- WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get());
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- scheduler_->SetExpensiveTaskBlockingAllowed(false);
- scheduler_->SuspendTimerQueue();
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
- ForceTouchStartToBeExpectedSoon();
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
- RunUntilIdle();
-
- EXPECT_EQ(0u, run_order.size());
- EXPECT_EQ(0u, web_view_scheduler.console_warnings().size());
-}
-
-TEST_F(RendererSchedulerImplTest, BlockedTimerNotification_TimersSuspended) {
- // Make sure we don't report warnings about blocked tasks when timers are
- // being blocked for other reasons.
- WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get());
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- scheduler_->SetExpensiveTaskBlockingAllowed(true);
- scheduler_->SuspendTimerQueue();
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
- ForceTouchStartToBeExpectedSoon();
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
- RunUntilIdle();
-
- EXPECT_EQ(0u, run_order.size());
- EXPECT_EQ(0u, web_view_scheduler.console_warnings().size());
-}
-
-TEST_F(RendererSchedulerImplTest, BlockedTimerNotification_TOUCHSTART) {
- // Make sure we don't report warnings about blocked tasks during TOUCHSTART.
- WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get());
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- EXPECT_EQ(UseCase::TOUCHSTART, ForceUpdatePolicyAndGetCurrentUseCase());
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
- RunUntilIdle();
-
- EXPECT_EQ(0u, run_order.size());
- EXPECT_EQ(0u, web_view_scheduler.console_warnings().size());
-}
-
-TEST_F(RendererSchedulerImplTest,
- BlockedTimerNotification_SYNCHRONIZED_GESTURE) {
- // Make sure we only report warnings during a high blocking threshold.
- WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get());
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- DoMainFrame();
- SimulateExpensiveTasks(timer_task_runner_);
- SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START);
-
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
-
- EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE,
- ForceUpdatePolicyAndGetCurrentUseCase());
-
- std::vector<std::string> run_order;
- PostTestTasks(&run_order, "T1 T2");
- RunUntilIdle();
-
- EXPECT_EQ(0u, run_order.size());
- EXPECT_EQ(0u, web_view_scheduler.console_warnings().size());
-}
-
-namespace {
-void SlowCountingTask(size_t* count,
- base::SimpleTestTickClock* clock,
- int task_duration,
- scoped_refptr<base::SingleThreadTaskRunner> timer_queue) {
- clock->Advance(base::TimeDelta::FromMilliseconds(task_duration));
- if (++(*count) < 500) {
- timer_queue->PostTask(FROM_HERE, base::Bind(SlowCountingTask, count, clock,
- task_duration, timer_queue));
- }
-}
-}
-
-TEST_F(RendererSchedulerImplTest,
- SYNCHRONIZED_GESTURE_TimerTaskThrottling_task_expensive) {
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
-
- base::TimeTicks first_throttled_run_time =
- ThrottlingHelper::ThrottledRunTime(clock_->NowTicks());
-
- size_t count = 0;
- // With the compositor task taking 10ms, there is not enough time to run this
- // 7ms timer task in the 16ms frame.
- scheduler_->TimerTaskRunner()->PostTask(
- FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 7,
- scheduler_->TimerTaskRunner()));
-
- for (int i = 0; i < 1000; i++) {
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
-
- simulate_compositor_task_ran_ = false;
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(10)));
-
- mock_task_runner_->RunTasksWhile(
- base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
- base::Unretained(this)));
- EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i;
-
- // Before the policy is updated the queue will be enabled. Subsequently it
- // will be disabled until the throttled queue is pumped.
- bool expect_queue_enabled =
- (i == 0) || (clock_->NowTicks() > first_throttled_run_time);
- EXPECT_EQ(expect_queue_enabled,
- scheduler_->TimerTaskRunner()->IsQueueEnabled())
- << "i = " << i;
- }
-
- // Task is throttled but not completely blocked.
- EXPECT_EQ(12u, count);
-}
-
-TEST_F(RendererSchedulerImplTest,
- SYNCHRONIZED_GESTURE_TimerTaskThrottling_TimersSuspended) {
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
-
- base::TimeTicks first_throttled_run_time =
- ThrottlingHelper::ThrottledRunTime(clock_->NowTicks());
-
- size_t count = 0;
- // With the compositor task taking 10ms, there is not enough time to run this
- // 7ms timer task in the 16ms frame.
- scheduler_->TimerTaskRunner()->PostTask(
- FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 7,
- scheduler_->TimerTaskRunner()));
-
- bool suspended = false;
- for (int i = 0; i < 1000; i++) {
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
-
- simulate_compositor_task_ran_ = false;
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(10)));
-
- mock_task_runner_->RunTasksWhile(
- base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
- base::Unretained(this)));
- EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i;
-
- // Before the policy is updated the queue will be enabled. Subsequently it
- // will be disabled until the throttled queue is pumped.
- bool expect_queue_enabled =
- (i == 0) || (clock_->NowTicks() > first_throttled_run_time);
- if (suspended)
- expect_queue_enabled = false;
- EXPECT_EQ(expect_queue_enabled,
- scheduler_->TimerTaskRunner()->IsQueueEnabled())
- << "i = " << i;
-
- // After we've run any expensive tasks suspend the queue. The throttling
- // helper should /not/ re-enable this queue under any circumstances while
- // timers are suspended.
- if (count > 0 && !suspended) {
- EXPECT_EQ(2u, count);
- scheduler_->SuspendTimerQueue();
- suspended = true;
- }
- }
-
- // Make sure the timer queue stayed suspended!
- EXPECT_EQ(2u, count);
-}
-
-TEST_F(RendererSchedulerImplTest,
- SYNCHRONIZED_GESTURE_TimerTaskThrottling_task_not_expensive) {
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
-
- size_t count = 0;
- // With the compositor task taking 10ms, there is enough time to run this 6ms
- // timer task in the 16ms frame.
- scheduler_->TimerTaskRunner()->PostTask(
- FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 6,
- scheduler_->TimerTaskRunner()));
-
- for (int i = 0; i < 1000; i++) {
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
-
- simulate_compositor_task_ran_ = false;
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(10)));
-
- mock_task_runner_->RunTasksWhile(
- base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
- base::Unretained(this)));
- EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i;
- EXPECT_TRUE(scheduler_->TimerTaskRunner()->IsQueueEnabled()) << "i = " << i;
- }
-
- // Task is not throttled.
- EXPECT_EQ(500u, count);
-}
-
-TEST_F(RendererSchedulerImplTest,
- ExpensiveTimerTaskBlocked_SYNCHRONIZED_GESTURE_TouchStartExpected) {
- SimulateExpensiveTasks(timer_task_runner_);
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- ForceTouchStartToBeExpectedSoon();
-
- // Bump us into SYNCHRONIZED_GESTURE.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
-
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
-
- EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE,
- ForceUpdatePolicyAndGetCurrentUseCase());
-
- EXPECT_TRUE(TimerTasksSeemExpensive());
- EXPECT_TRUE(TouchStartExpectedSoon());
- EXPECT_FALSE(scheduler_->TimerTaskRunner()->IsQueueEnabled());
-}
-
-TEST_F(RendererSchedulerImplTest, DenyLongIdleDuringTouchStart) {
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
- EXPECT_EQ(UseCase::TOUCHSTART, ForceUpdatePolicyAndGetCurrentUseCase());
-
- // First check that long idle is denied during the TOUCHSTART use case.
- IdleHelper::Delegate* idle_delegate = scheduler_.get();
- base::TimeTicks now;
- base::TimeDelta next_time_to_check;
- EXPECT_FALSE(idle_delegate->CanEnterLongIdlePeriod(now, &next_time_to_check));
- EXPECT_GE(next_time_to_check, base::TimeDelta());
-
- // Check again at a time past the TOUCHSTART expiration. We should still get a
- // non-negative delay to when to check again.
- now += base::TimeDelta::FromMilliseconds(500);
- EXPECT_FALSE(idle_delegate->CanEnterLongIdlePeriod(now, &next_time_to_check));
- EXPECT_GE(next_time_to_check, base::TimeDelta());
-}
-
-TEST_F(RendererSchedulerImplTest, TestCompositorPolicy_TouchStartDuringFling) {
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- scheduler_->DidAnimateForInputOnCompositorThread();
- // Note DidAnimateForInputOnCompositorThread does not by itself trigger a
- // policy update.
- EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE,
- ForceUpdatePolicyAndGetCurrentUseCase());
-
- // Make sure TouchStart causes a policy change.
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchStart),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
- EXPECT_EQ(RendererSchedulerImpl::UseCase::TOUCHSTART,
- ForceUpdatePolicyAndGetCurrentUseCase());
-}
-
-TEST_F(RendererSchedulerImplTest, SYNCHRONIZED_GESTURE_CompositingExpensive) {
- SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START);
-
- // With the compositor task taking 20ms, there is not enough time to run
- // other tasks in the same 16ms frame. To avoid starvation, compositing tasks
- // should therefore not get prioritized.
- std::vector<std::string> run_order;
- for (int i = 0; i < 1000; i++)
- PostTestTasks(&run_order, "T1");
-
- for (int i = 0; i < 100; i++) {
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate),
- RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
-
- simulate_compositor_task_ran_ = false;
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(20)));
-
- mock_task_runner_->RunTasksWhile(
- base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
- base::Unretained(this)));
- EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i;
- }
-
- // Timer tasks should not have been starved by the expensive compositor
- // tasks.
- EXPECT_EQ(TaskQueue::NORMAL_PRIORITY,
- scheduler_->CompositorTaskRunner()->GetQueuePriority());
- EXPECT_EQ(1000u, run_order.size());
-}
-
-TEST_F(RendererSchedulerImplTest, MAIN_THREAD_CUSTOM_INPUT_HANDLING) {
- SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollBegin);
-
- // With the compositor task taking 20ms, there is not enough time to run
- // other tasks in the same 16ms frame. To avoid starvation, compositing tasks
- // should therefore not get prioritized.
- std::vector<std::string> run_order;
- for (int i = 0; i < 1000; i++)
- PostTestTasks(&run_order, "T1");
-
- for (int i = 0; i < 100; i++) {
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::TouchMove),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
-
- simulate_compositor_task_ran_ = false;
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(20)));
-
- mock_task_runner_->RunTasksWhile(
- base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
- base::Unretained(this)));
- EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase())
- << "i = " << i;
- }
-
- // Timer tasks should not have been starved by the expensive compositor
- // tasks.
- EXPECT_EQ(TaskQueue::NORMAL_PRIORITY,
- scheduler_->CompositorTaskRunner()->GetQueuePriority());
- EXPECT_EQ(1000u, run_order.size());
-}
-
-TEST_F(RendererSchedulerImplTest, MAIN_THREAD_GESTURE) {
- SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START,
- blink::WebInputEvent::GestureScrollBegin);
-
- // With the compositor task taking 20ms, there is not enough time to run
- // other tasks in the same 16ms frame. However because this is a main thread
- // gesture instead of custom main thread input handling, we allow the timer
- // tasks to be starved.
- std::vector<std::string> run_order;
- for (int i = 0; i < 1000; i++)
- PostTestTasks(&run_order, "T1");
-
- for (int i = 0; i < 100; i++) {
- cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(),
- base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL);
- begin_frame_args.on_critical_path = true;
- scheduler_->WillBeginFrame(begin_frame_args);
- scheduler_->DidHandleInputEventOnCompositorThread(
- FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate),
- RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD);
-
- simulate_compositor_task_ran_ = false;
- compositor_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
- base::Unretained(this),
- base::TimeDelta::FromMilliseconds(20)));
-
- mock_task_runner_->RunTasksWhile(
- base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
- base::Unretained(this)));
- EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, CurrentUseCase()) << "i = " << i;
- }
-
- EXPECT_EQ(TaskQueue::HIGH_PRIORITY,
- scheduler_->CompositorTaskRunner()->GetQueuePriority());
- EXPECT_EQ(279u, run_order.size());
-}
-
-class MockRAILModeObserver : public RendererScheduler::RAILModeObserver {
- public:
- MOCK_METHOD1(OnRAILModeChanged, void(v8::RAILMode rail_mode));
-};
-
-TEST_F(RendererSchedulerImplTest, TestResponseRAILMode) {
- MockRAILModeObserver observer;
- scheduler_->SetRAILModeObserver(&observer);
- EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_RESPONSE));
-
- scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
- ForceTouchStartToBeExpectedSoon();
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode());
- scheduler_->SetRAILModeObserver(nullptr);
-}
-
-TEST_F(RendererSchedulerImplTest, TestAnimateRAILMode) {
- MockRAILModeObserver observer;
- scheduler_->SetRAILModeObserver(&observer);
- EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_ANIMATION)).Times(0);
-
- EXPECT_FALSE(BeginFrameNotExpectedSoon());
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode());
- scheduler_->SetRAILModeObserver(nullptr);
-}
-
-TEST_F(RendererSchedulerImplTest, TestIdleRAILMode) {
- MockRAILModeObserver observer;
- scheduler_->SetRAILModeObserver(&observer);
- EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_ANIMATION));
- EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_IDLE));
-
- scheduler_->SetAllRenderWidgetsHidden(true);
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_EQ(v8::PERFORMANCE_IDLE, RAILMode());
- scheduler_->SetAllRenderWidgetsHidden(false);
- EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase());
- EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode());
- scheduler_->SetRAILModeObserver(nullptr);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/renderer_web_scheduler_impl.cc b/chromium/components/scheduler/renderer/renderer_web_scheduler_impl.cc
deleted file mode 100644
index e53e01d3ca2..00000000000
--- a/chromium/components/scheduler/renderer/renderer_web_scheduler_impl.cc
+++ /dev/null
@@ -1,49 +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 "components/scheduler/renderer/renderer_web_scheduler_impl.h"
-
-#include <memory>
-
-#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/common/scheduler_switches.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-#include "components/scheduler/renderer/web_view_scheduler_impl.h"
-
-namespace scheduler {
-
-RendererWebSchedulerImpl::RendererWebSchedulerImpl(
- RendererSchedulerImpl* renderer_scheduler)
- : WebSchedulerImpl(renderer_scheduler,
- renderer_scheduler->IdleTaskRunner(),
- renderer_scheduler->LoadingTaskRunner(),
- renderer_scheduler->TimerTaskRunner()),
- renderer_scheduler_(renderer_scheduler) {}
-
-RendererWebSchedulerImpl::~RendererWebSchedulerImpl() {
-}
-
-void RendererWebSchedulerImpl::suspendTimerQueue() {
- renderer_scheduler_->SuspendTimerQueue();
-}
-
-void RendererWebSchedulerImpl::resumeTimerQueue() {
- renderer_scheduler_->ResumeTimerQueue();
-}
-
-std::unique_ptr<blink::WebViewScheduler>
-RendererWebSchedulerImpl::createWebViewScheduler(blink::WebView* web_view) {
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- return base::WrapUnique(new WebViewSchedulerImpl(
- web_view, renderer_scheduler_,
- command_line->HasSwitch(switches::kDisableBackgroundTimerThrottling)));
-}
-
-void RendererWebSchedulerImpl::onNavigationStarted() {
- renderer_scheduler_->OnNavigationStarted();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/renderer_web_scheduler_impl.h b/chromium/components/scheduler/renderer/renderer_web_scheduler_impl.h
deleted file mode 100644
index 9cb4cbd11ae..00000000000
--- a/chromium/components/scheduler/renderer/renderer_web_scheduler_impl.h
+++ /dev/null
@@ -1,33 +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 COMPONENTS_SCHEDULER_RENDERER_RENDERER_WEB_SCHEDULER_IMPL_H_
-#define COMPONENTS_SCHEDULER_RENDERER_RENDERER_WEB_SCHEDULER_IMPL_H_
-
-#include "components/scheduler/child/web_scheduler_impl.h"
-
-namespace scheduler {
-
-class RendererSchedulerImpl;
-
-class SCHEDULER_EXPORT RendererWebSchedulerImpl : public WebSchedulerImpl {
- public:
- explicit RendererWebSchedulerImpl(RendererSchedulerImpl* renderer_scheduler);
-
- ~RendererWebSchedulerImpl() override;
-
- // blink::WebScheduler implementation:
- void suspendTimerQueue() override;
- void resumeTimerQueue() override;
- std::unique_ptr<blink::WebViewScheduler> createWebViewScheduler(
- blink::WebView* web_view) override;
- void onNavigationStarted() override;
-
- private:
- RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_RENDERER_WEB_SCHEDULER_IMPL_H_
diff --git a/chromium/components/scheduler/renderer/task_cost_estimator.cc b/chromium/components/scheduler/renderer/task_cost_estimator.cc
deleted file mode 100644
index ce8dee90875..00000000000
--- a/chromium/components/scheduler/renderer/task_cost_estimator.cc
+++ /dev/null
@@ -1,43 +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 "components/scheduler/renderer/task_cost_estimator.h"
-
-#include "base/time/default_tick_clock.h"
-
-namespace scheduler {
-
-TaskCostEstimator::TaskCostEstimator(base::TickClock* time_source,
- int sample_count,
- double estimation_percentile)
- : rolling_time_delta_history_(sample_count),
- time_source_(time_source),
- outstanding_task_count_(0),
- estimation_percentile_(estimation_percentile) {}
-
-TaskCostEstimator::~TaskCostEstimator() {}
-
-void TaskCostEstimator::WillProcessTask(const base::PendingTask& pending_task) {
- // Avoid measuring the duration in nested run loops.
- if (++outstanding_task_count_ == 1)
- task_start_time_ = time_source_->NowTicks();
-}
-
-void TaskCostEstimator::DidProcessTask(const base::PendingTask& pending_task) {
- if (--outstanding_task_count_ == 0) {
- base::TimeDelta duration = time_source_->NowTicks() - task_start_time_;
- rolling_time_delta_history_.InsertSample(duration);
- }
-}
-
-base::TimeDelta TaskCostEstimator::expected_task_duration() const {
- return rolling_time_delta_history_.Percentile(estimation_percentile_);
-}
-
-void TaskCostEstimator::Clear() {
- rolling_time_delta_history_.Clear();
- expected_task_duration_ = base::TimeDelta();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/task_cost_estimator.h b/chromium/components/scheduler/renderer/task_cost_estimator.h
deleted file mode 100644
index c4e43c44518..00000000000
--- a/chromium/components/scheduler/renderer/task_cost_estimator.h
+++ /dev/null
@@ -1,50 +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 COMPONENTS_SCHEDULER_RENDERER_TASK_COST_ESTIMATOR_H_
-#define COMPONENTS_SCHEDULER_RENDERER_TASK_COST_ESTIMATOR_H_
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/time/time.h"
-#include "cc/base/rolling_time_delta_history.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace base {
-class TickClock;
-}
-
-namespace scheduler {
-
-// Estimates the cost of running tasks based on historical timing data.
-class SCHEDULER_EXPORT TaskCostEstimator
- : public base::MessageLoop::TaskObserver {
- public:
- TaskCostEstimator(base::TickClock* time_source,
- int sample_count,
- double estimation_percentile);
- ~TaskCostEstimator() override;
-
- base::TimeDelta expected_task_duration() const;
-
- // TaskObserver implementation:
- void WillProcessTask(const base::PendingTask& pending_task) override;
- void DidProcessTask(const base::PendingTask& pending_task) override;
-
- void Clear();
-
- private:
- cc::RollingTimeDeltaHistory rolling_time_delta_history_;
- base::TickClock* time_source_; // NOT OWNED
- int outstanding_task_count_;
- double estimation_percentile_;
- base::TimeTicks task_start_time_;
- base::TimeDelta expected_task_duration_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskCostEstimator);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_TASK_COST_ESTIMATOR_H_
diff --git a/chromium/components/scheduler/renderer/task_cost_estimator_unittest.cc b/chromium/components/scheduler/renderer/task_cost_estimator_unittest.cc
deleted file mode 100644
index a8297daf49b..00000000000
--- a/chromium/components/scheduler/renderer/task_cost_estimator_unittest.cc
+++ /dev/null
@@ -1,80 +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 "components/scheduler/renderer/task_cost_estimator.h"
-
-#include <memory>
-
-#include "base/test/simple_test_tick_clock.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace scheduler {
-
-class TaskCostEstimatorTest : public testing::Test {
- public:
- TaskCostEstimatorTest() {}
- ~TaskCostEstimatorTest() override {}
-
- void SetUp() override {
- test_time_source_.reset(new TestTimeSource(&clock_));
- }
-
- base::SimpleTestTickClock clock_;
- std::unique_ptr<TestTimeSource> test_time_source_;
-};
-
-class TaskCostEstimatorForTest : public TaskCostEstimator {
- public:
- TaskCostEstimatorForTest(TestTimeSource* test_time_source,
- int sample_count,
- double estimation_percentile)
- : TaskCostEstimator(test_time_source,
- sample_count,
- estimation_percentile) {}
-};
-
-TEST_F(TaskCostEstimatorTest, BasicEstimation) {
- TaskCostEstimatorForTest estimator(test_time_source_.get(), 1, 100);
- base::PendingTask task(FROM_HERE, base::Closure());
-
- estimator.WillProcessTask(task);
- clock_.Advance(base::TimeDelta::FromMilliseconds(500));
- estimator.DidProcessTask(task);
-
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(500),
- estimator.expected_task_duration());
-}
-
-TEST_F(TaskCostEstimatorTest, Clear) {
- TaskCostEstimatorForTest estimator(test_time_source_.get(), 1, 100);
- base::PendingTask task(FROM_HERE, base::Closure());
-
- estimator.WillProcessTask(task);
- clock_.Advance(base::TimeDelta::FromMilliseconds(500));
- estimator.DidProcessTask(task);
-
- estimator.Clear();
-
- EXPECT_EQ(base::TimeDelta(), estimator.expected_task_duration());
-}
-
-TEST_F(TaskCostEstimatorTest, NestedRunLoop) {
- TaskCostEstimatorForTest estimator(test_time_source_.get(), 1, 100);
- base::PendingTask task(FROM_HERE, base::Closure());
-
- // Make sure we ignore the tasks inside the nested run loop.
- estimator.WillProcessTask(task);
- estimator.WillProcessTask(task);
- clock_.Advance(base::TimeDelta::FromMilliseconds(500));
- estimator.DidProcessTask(task);
- clock_.Advance(base::TimeDelta::FromMilliseconds(500));
- estimator.DidProcessTask(task);
-
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000),
- estimator.expected_task_duration());
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/throttled_time_domain.cc b/chromium/components/scheduler/renderer/throttled_time_domain.cc
deleted file mode 100644
index b66c8208e91..00000000000
--- a/chromium/components/scheduler/renderer/throttled_time_domain.cc
+++ /dev/null
@@ -1,39 +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 "components/scheduler/renderer/throttled_time_domain.h"
-
-namespace scheduler {
-
-ThrottledTimeDomain::ThrottledTimeDomain(TimeDomain::Observer* observer,
- const char* tracing_category)
- : RealTimeDomain(observer, tracing_category) {}
-
-ThrottledTimeDomain::~ThrottledTimeDomain() {}
-
-const char* ThrottledTimeDomain::GetName() const {
- return "ThrottledTimeDomain";
-}
-
-void ThrottledTimeDomain::RequestWakeup(base::TimeTicks now,
- base::TimeDelta delay) {
- // We assume the owner (i.e. ThrottlingHelper) will manage wakeups on our
- // behalf.
-}
-
-bool ThrottledTimeDomain::MaybeAdvanceTime() {
- base::TimeTicks next_run_time;
- if (!NextScheduledRunTime(&next_run_time))
- return false;
-
- base::TimeTicks now = Now();
- if (now >= next_run_time)
- return true; // Causes DoWork to post a continuation.
-
- // Unlike RealTimeDomain::MaybeAdvanceTime we don't request a wake up here, we
- // assume the owner (i.e. ThrottlingHelper) will manage wakeups on our behalf.
- return false;
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/throttled_time_domain.h b/chromium/components/scheduler/renderer/throttled_time_domain.h
deleted file mode 100644
index e334c909450..00000000000
--- a/chromium/components/scheduler/renderer/throttled_time_domain.h
+++ /dev/null
@@ -1,34 +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 COMPONENTS_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_
-#define COMPONENTS_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_
-
-#include "base/macros.h"
-#include "components/scheduler/base/real_time_domain.h"
-
-namespace scheduler {
-
-// A time domain for throttled tasks. behaves like an RealTimeDomain except it
-// relies on the owner (ThrottlingHelper) to schedule wakeups.
-class SCHEDULER_EXPORT ThrottledTimeDomain : public RealTimeDomain {
- public:
- ThrottledTimeDomain(TimeDomain::Observer* observer,
- const char* tracing_category);
- ~ThrottledTimeDomain() override;
-
- // TimeDomain implementation:
- const char* GetName() const override;
- void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override;
- bool MaybeAdvanceTime() override;
-
- using TimeDomain::ClearExpiredWakeups;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ThrottledTimeDomain);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_
diff --git a/chromium/components/scheduler/renderer/throttling_helper.cc b/chromium/components/scheduler/renderer/throttling_helper.cc
deleted file mode 100644
index c5335bfe91c..00000000000
--- a/chromium/components/scheduler/renderer/throttling_helper.cc
+++ /dev/null
@@ -1,191 +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 "components/scheduler/renderer/throttling_helper.h"
-
-#include "base/logging.h"
-#include "components/scheduler/base/real_time_domain.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-#include "components/scheduler/renderer/throttled_time_domain.h"
-#include "components/scheduler/renderer/web_frame_scheduler_impl.h"
-#include "third_party/WebKit/public/platform/WebFrameScheduler.h"
-
-namespace scheduler {
-
-ThrottlingHelper::ThrottlingHelper(RendererSchedulerImpl* renderer_scheduler,
- const char* tracing_category)
- : task_runner_(renderer_scheduler->ControlTaskRunner()),
- renderer_scheduler_(renderer_scheduler),
- tick_clock_(renderer_scheduler->tick_clock()),
- tracing_category_(tracing_category),
- time_domain_(new ThrottledTimeDomain(this, tracing_category)),
- weak_factory_(this) {
- suspend_timers_when_backgrounded_closure_.Reset(base::Bind(
- &ThrottlingHelper::PumpThrottledTasks, weak_factory_.GetWeakPtr()));
- forward_immediate_work_closure_ =
- base::Bind(&ThrottlingHelper::OnTimeDomainHasImmediateWork,
- weak_factory_.GetWeakPtr());
-
- renderer_scheduler_->RegisterTimeDomain(time_domain_.get());
-}
-
-ThrottlingHelper::~ThrottlingHelper() {
- // It's possible for queues to be still throttled, so we need to tidy up
- // before unregistering the time domain.
- for (const TaskQueueMap::value_type& map_entry : throttled_queues_) {
- TaskQueue* task_queue = map_entry.first;
- task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain());
- task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
- }
-
- renderer_scheduler_->UnregisterTimeDomain(time_domain_.get());
-}
-
-void ThrottlingHelper::SetQueueEnabled(TaskQueue* task_queue, bool enabled) {
- TaskQueueMap::iterator find_it = throttled_queues_.find(task_queue);
-
- if (find_it == throttled_queues_.end()) {
- task_queue->SetQueueEnabled(enabled);
- return;
- }
-
- find_it->second.enabled = enabled;
-
- // We don't enable the queue here because it's throttled and there might be
- // tasks in it's work queue that would execute immediatly rather than after
- // PumpThrottledTasks runs.
- if (!enabled)
- task_queue->SetQueueEnabled(false);
-}
-
-void ThrottlingHelper::IncreaseThrottleRefCount(TaskQueue* task_queue) {
- DCHECK_NE(task_queue, task_runner_.get());
-
- std::pair<TaskQueueMap::iterator, bool> insert_result =
- throttled_queues_.insert(std::make_pair(
- task_queue, Metadata(1, task_queue->IsQueueEnabled())));
-
- if (insert_result.second) {
- // The insert was succesful so we need to throttle the queue.
- task_queue->SetTimeDomain(time_domain_.get());
- task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
- task_queue->SetQueueEnabled(false);
-
- if (!task_queue->IsEmpty()) {
- if (task_queue->HasPendingImmediateWork()) {
- OnTimeDomainHasImmediateWork();
- } else {
- OnTimeDomainHasDelayedWork();
- }
- }
- } else {
- // An entry already existed in the map so we need to increment the refcount.
- insert_result.first->second.throttling_ref_count++;
- }
-}
-
-void ThrottlingHelper::DecreaseThrottleRefCount(TaskQueue* task_queue) {
- TaskQueueMap::iterator iter = throttled_queues_.find(task_queue);
-
- if (iter != throttled_queues_.end() &&
- --iter->second.throttling_ref_count == 0) {
- bool enabled = iter->second.enabled;
- // The refcount has become zero, we need to unthrottle the queue.
- throttled_queues_.erase(iter);
-
- task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain());
- task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
- task_queue->SetQueueEnabled(enabled);
- }
-}
-
-void ThrottlingHelper::UnregisterTaskQueue(TaskQueue* task_queue) {
- throttled_queues_.erase(task_queue);
-}
-
-void ThrottlingHelper::OnTimeDomainHasImmediateWork() {
- // Forward to the main thread if called from another thread.
- if (!task_runner_->RunsTasksOnCurrentThread()) {
- task_runner_->PostTask(FROM_HERE, forward_immediate_work_closure_);
- return;
- }
- TRACE_EVENT0(tracing_category_,
- "ThrottlingHelper::OnTimeDomainHasImmediateWork");
- base::TimeTicks now = tick_clock_->NowTicks();
- MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, now, now);
-}
-
-void ThrottlingHelper::OnTimeDomainHasDelayedWork() {
- TRACE_EVENT0(tracing_category_,
- "ThrottlingHelper::OnTimeDomainHasDelayedWork");
- base::TimeTicks next_scheduled_delayed_task;
- bool has_delayed_task =
- time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task);
- DCHECK(has_delayed_task);
- base::TimeTicks now = tick_clock_->NowTicks();
- MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, now,
- next_scheduled_delayed_task);
-}
-
-void ThrottlingHelper::PumpThrottledTasks() {
- TRACE_EVENT0(tracing_category_, "ThrottlingHelper::PumpThrottledTasks");
- pending_pump_throttled_tasks_runtime_ = base::TimeTicks();
-
- LazyNow lazy_low(tick_clock_);
- for (const TaskQueueMap::value_type& map_entry : throttled_queues_) {
- TaskQueue* task_queue = map_entry.first;
- if (task_queue->IsEmpty())
- continue;
-
- task_queue->SetQueueEnabled(map_entry.second.enabled);
- task_queue->PumpQueue(&lazy_low, false);
- }
- // Make sure NextScheduledRunTime gives us an up-to date result.
- time_domain_->ClearExpiredWakeups();
-
- base::TimeTicks next_scheduled_delayed_task;
- // Maybe schedule a call to ThrottlingHelper::PumpThrottledTasks if there is
- // a pending delayed task. NOTE posting a non-delayed task in the future will
- // result in ThrottlingHelper::OnTimeDomainHasImmediateWork being called.
- if (time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task)) {
- MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, lazy_low.Now(),
- next_scheduled_delayed_task);
- }
-}
-
-/* static */
-base::TimeTicks ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks unthrottled_runtime) {
- const base::TimeDelta one_second = base::TimeDelta::FromSeconds(1);
- return unthrottled_runtime + one_second -
- ((unthrottled_runtime - base::TimeTicks()) % one_second);
-}
-
-void ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked(
- const tracked_objects::Location& from_here,
- base::TimeTicks now,
- base::TimeTicks unthrottled_runtime) {
- base::TimeTicks throttled_runtime =
- ThrottledRunTime(std::max(now, unthrottled_runtime));
- // If there is a pending call to PumpThrottledTasks and it's sooner than
- // |unthrottled_runtime| then return.
- if (!pending_pump_throttled_tasks_runtime_.is_null() &&
- throttled_runtime >= pending_pump_throttled_tasks_runtime_) {
- return;
- }
-
- pending_pump_throttled_tasks_runtime_ = throttled_runtime;
-
- suspend_timers_when_backgrounded_closure_.Cancel();
-
- base::TimeDelta delay = pending_pump_throttled_tasks_runtime_ - now;
- TRACE_EVENT1(tracing_category_,
- "ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked",
- "delay_till_next_pump_ms", delay.InMilliseconds());
- task_runner_->PostDelayedTask(
- from_here, suspend_timers_when_backgrounded_closure_.callback(), delay);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/throttling_helper.h b/chromium/components/scheduler/renderer/throttling_helper.h
deleted file mode 100644
index db995aea8c2..00000000000
--- a/chromium/components/scheduler/renderer/throttling_helper.h
+++ /dev/null
@@ -1,99 +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 COMPONENTS_SCHEDULER_RENDERER_THROTTLING_HELPER_H_
-#define COMPONENTS_SCHEDULER_RENDERER_THROTTLING_HELPER_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "components/scheduler/base/cancelable_closure_holder.h"
-#include "components/scheduler/base/time_domain.h"
-#include "components/scheduler/scheduler_export.h"
-#include "third_party/WebKit/public/platform/WebViewScheduler.h"
-
-namespace scheduler {
-
-class RendererSchedulerImpl;
-class ThrottledTimeDomain;
-class WebFrameSchedulerImpl;
-
-class SCHEDULER_EXPORT ThrottlingHelper : public TimeDomain::Observer {
- public:
- ThrottlingHelper(RendererSchedulerImpl* renderer_scheduler,
- const char* tracing_category);
-
- ~ThrottlingHelper() override;
-
- // TimeDomain::Observer implementation:
- void OnTimeDomainHasImmediateWork() override;
- void OnTimeDomainHasDelayedWork() override;
-
- // The purpose of this method is to make sure throttling doesn't conflict with
- // enabling/disabling the queue for policy reasons.
- // If |task_queue| is throttled then the ThrottlingHelper remembers the
- // |enabled| setting. In addition if |enabled| is false then the queue is
- // immediatly disabled. Otherwise if |task_queue| not throttled then
- // TaskQueue::SetEnabled(enabled) is called.
- void SetQueueEnabled(TaskQueue* task_queue, bool enabled);
-
- // Increments the throttled refcount and causes |task_queue| to be throttled
- // if its not already throttled.
- void IncreaseThrottleRefCount(TaskQueue* task_queue);
-
- // If the refcouint is non-zero it's decremented. If the throttled refcount
- // becomes zero then |task_queue| is unthrottled. If the refcount was already
- // zero this function does nothing.
- void DecreaseThrottleRefCount(TaskQueue* task_queue);
-
- // Removes |task_queue| from |throttled_queues_|.
- void UnregisterTaskQueue(TaskQueue* task_queue);
-
- const ThrottledTimeDomain* time_domain() const { return time_domain_.get(); }
-
- static base::TimeTicks ThrottledRunTime(base::TimeTicks unthrottled_runtime);
-
- const scoped_refptr<TaskQueue>& task_runner() const { return task_runner_; }
-
- private:
- struct Metadata {
- Metadata() : throttling_ref_count(0), enabled(false) {}
-
- Metadata(size_t ref_count, bool is_enabled)
- : throttling_ref_count(ref_count), enabled(is_enabled) {}
-
- size_t throttling_ref_count;
- bool enabled;
- };
- using TaskQueueMap = std::map<TaskQueue*, Metadata>;
-
- void PumpThrottledTasks();
-
- // Note |unthrottled_runtime| might be in the past. When this happens we
- // compute the delay to the next runtime based on now rather than
- // unthrottled_runtime.
- void MaybeSchedulePumpThrottledTasksLocked(
- const tracked_objects::Location& from_here,
- base::TimeTicks now,
- base::TimeTicks unthrottled_runtime);
-
- TaskQueueMap throttled_queues_;
- base::Closure forward_immediate_work_closure_;
- scoped_refptr<TaskQueue> task_runner_;
- RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED
- base::TickClock* tick_clock_; // NOT OWNED
- const char* tracing_category_; // NOT OWNED
- std::unique_ptr<ThrottledTimeDomain> time_domain_;
-
- CancelableClosureHolder suspend_timers_when_backgrounded_closure_;
- base::TimeTicks pending_pump_throttled_tasks_runtime_;
-
- base::WeakPtrFactory<ThrottlingHelper> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ThrottlingHelper);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_THROTTLING_HELPER_H_
diff --git a/chromium/components/scheduler/renderer/throttling_helper_unittest.cc b/chromium/components/scheduler/renderer/throttling_helper_unittest.cc
deleted file mode 100644
index cae2b7f9ca0..00000000000
--- a/chromium/components/scheduler/renderer/throttling_helper_unittest.cc
+++ /dev/null
@@ -1,455 +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 "components/scheduler/renderer/throttling_helper.h"
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-#include "components/scheduler/renderer/web_frame_scheduler_impl.h"
-#include "components/scheduler/renderer/web_view_scheduler_impl.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::ElementsAre;
-
-namespace scheduler {
-
-namespace {
-void CountingTask(size_t* count, scoped_refptr<TaskQueue> timer_queue) {
- if (++(*count) < 10) {
- timer_queue->PostTask(FROM_HERE,
- base::Bind(&CountingTask, count, timer_queue));
- }
-}
-}
-
-class ThrottlingHelperTest : public testing::Test {
- public:
- ThrottlingHelperTest() {}
- ~ThrottlingHelperTest() override {}
-
- void SetUp() override {
- clock_.reset(new base::SimpleTestTickClock());
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- mock_task_runner_ =
- make_scoped_refptr(new cc::OrderedSimpleTaskRunner(clock_.get(), true));
- delegate_ = SchedulerTqmDelegateForTest::Create(
- mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get())));
- scheduler_.reset(new RendererSchedulerImpl(delegate_));
- throttling_helper_ = scheduler_->throttling_helper();
- timer_queue_ = scheduler_->NewTimerTaskRunner("test_queue");
- }
-
- void TearDown() override {
- scheduler_->Shutdown();
- scheduler_.reset();
- }
-
- void ExpectThrottled(scoped_refptr<TaskQueue> timer_queue) {
- size_t count = 0;
- timer_queue->PostTask(FROM_HERE,
- base::Bind(&CountingTask, &count, timer_queue));
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_LT(count, 10u);
- mock_task_runner_->RunUntilIdle();
- }
-
- void ExpectUnthrottled(scoped_refptr<TaskQueue> timer_queue) {
- size_t count = 0;
- timer_queue->PostTask(FROM_HERE,
- base::Bind(&CountingTask, &count, timer_queue));
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(count, 10u);
- mock_task_runner_->RunUntilIdle();
- }
-
- protected:
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
- scoped_refptr<SchedulerTqmDelegate> delegate_;
- std::unique_ptr<RendererSchedulerImpl> scheduler_;
- scoped_refptr<TaskQueue> timer_queue_;
- ThrottlingHelper* throttling_helper_; // NOT OWNED
-
- DISALLOW_COPY_AND_ASSIGN(ThrottlingHelperTest);
-};
-
-TEST_F(ThrottlingHelperTest, ThrottledRunTime) {
- EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
- ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.0)));
-
- EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
- ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.1)));
-
- EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
- ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.2)));
-
- EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
- ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.5)));
-
- EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
- ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.8)));
-
- EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0),
- ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.9)));
-
- EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(2.0),
- ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0)));
-
- EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(2.0),
- ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(1.1)));
-
- EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(9.0),
- ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(8.0)));
-
- EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(9.0),
- ThrottlingHelper::ThrottledRunTime(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(8.1)));
-}
-
-namespace {
-void TestTask(std::vector<base::TimeTicks>* run_times,
- base::SimpleTestTickClock* clock) {
- run_times->push_back(clock->NowTicks());
-}
-} // namespace
-
-TEST_F(ThrottlingHelperTest, TimerAlignment) {
- std::vector<base::TimeTicks> run_times;
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(200.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(800.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(1200.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(8300.0));
-
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
-
- mock_task_runner_->RunUntilIdle();
-
- // Times are aligned to a multipple of 1000 milliseconds.
- EXPECT_THAT(
- run_times,
- ElementsAre(
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0),
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0),
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(2000.0),
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(9000.0)));
-}
-
-TEST_F(ThrottlingHelperTest, TimerAlignment_Unthrottled) {
- std::vector<base::TimeTicks> run_times;
- base::TimeTicks start_time = clock_->NowTicks();
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(200.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(800.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(1200.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(8300.0));
-
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
-
- mock_task_runner_->RunUntilIdle();
-
- // Times are not aligned.
- EXPECT_THAT(
- run_times,
- ElementsAre(start_time + base::TimeDelta::FromMilliseconds(200.0),
- start_time + base::TimeDelta::FromMilliseconds(800.0),
- start_time + base::TimeDelta::FromMilliseconds(1200.0),
- start_time + base::TimeDelta::FromMilliseconds(8300.0)));
-}
-
-TEST_F(ThrottlingHelperTest, Refcount) {
- ExpectUnthrottled(timer_queue_.get());
-
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- ExpectThrottled(timer_queue_);
-
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- ExpectThrottled(timer_queue_);
-
- throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
- ExpectThrottled(timer_queue_);
-
- throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
- ExpectUnthrottled(timer_queue_);
-
- // Should be a NOP.
- throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
- ExpectUnthrottled(timer_queue_);
-
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- ExpectThrottled(timer_queue_);
-}
-
-TEST_F(ThrottlingHelperTest,
- ThrotlingAnEmptyQueueDoesNotPostPumpThrottledTasksLocked) {
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
-
- EXPECT_TRUE(throttling_helper_->task_runner()->IsEmpty());
-}
-
-TEST_F(ThrottlingHelperTest, WakeUpForNonDelayedTask) {
- std::vector<base::TimeTicks> run_times;
-
- // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick.
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
-
- // Posting a task should trigger the pump.
- timer_queue_->PostTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()));
-
- mock_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_times,
- ElementsAre(base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(1000.0)));
-}
-
-TEST_F(ThrottlingHelperTest, WakeUpForDelayedTask) {
- std::vector<base::TimeTicks> run_times;
-
- // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick.
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
-
- // Posting a task should trigger the pump.
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(1200.0));
-
- mock_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_times,
- ElementsAre(base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(2000.0)));
-}
-
-namespace {
-bool MessageLoopTaskCounter(size_t* count) {
- *count = *count + 1;
- return true;
-}
-
-void NopTask() {}
-
-} // namespace
-
-TEST_F(ThrottlingHelperTest,
- SingleThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) {
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
-
- base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
- timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay);
-
- size_t task_count = 0;
- mock_task_runner_->RunTasksWhile(
- base::Bind(&MessageLoopTaskCounter, &task_count));
-
- EXPECT_EQ(1u, task_count);
-}
-
-TEST_F(ThrottlingHelperTest,
- SingleFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) {
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
-
- base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5));
- timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay);
-
- size_t task_count = 0;
- mock_task_runner_->RunTasksWhile(
- base::Bind(&MessageLoopTaskCounter, &task_count));
-
- EXPECT_EQ(1u, task_count);
-}
-
-TEST_F(ThrottlingHelperTest,
- TwoFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) {
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- std::vector<base::TimeTicks> run_times;
-
- base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5));
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- delay);
-
- base::TimeDelta delay2(base::TimeDelta::FromSecondsD(5.5));
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- delay2);
-
- size_t task_count = 0;
- mock_task_runner_->RunTasksWhile(
- base::Bind(&MessageLoopTaskCounter, &task_count));
-
- EXPECT_EQ(2u, task_count); // There are two since the cancelled task runs in
- // the same DoWork batch.
-
- EXPECT_THAT(
- run_times,
- ElementsAre(base::TimeTicks() + base::TimeDelta::FromSeconds(6),
- base::TimeTicks() + base::TimeDelta::FromSeconds(16)));
-}
-
-TEST_F(ThrottlingHelperTest, TaskDelayIsBasedOnRealTime) {
- std::vector<base::TimeTicks> run_times;
-
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
-
- // Post an initial task that should run at the first aligned time period.
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(900.0));
-
- mock_task_runner_->RunUntilIdle();
-
- // Advance realtime.
- clock_->Advance(base::TimeDelta::FromMilliseconds(250));
-
- // Post a task that due to real time + delay must run in the third aligned
- // time period.
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(900.0));
-
- mock_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(
- run_times,
- ElementsAre(
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0),
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(3000.0)));
-}
-
-TEST_F(ThrottlingHelperTest, ThrottledTasksReportRealTime) {
- EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks());
-
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks());
-
- clock_->Advance(base::TimeDelta::FromMilliseconds(250));
- // Make sure the throttled time domain's Now() reports the same as the
- // underlying clock.
- EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks());
-}
-
-TEST_F(ThrottlingHelperTest, TaskQueueDisabledTillPump) {
- timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- EXPECT_TRUE(timer_queue_->IsQueueEnabled());
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- EXPECT_FALSE(timer_queue_->IsQueueEnabled());
-
- mock_task_runner_->RunUntilIdle(); // Wait until the pump.
- EXPECT_TRUE(timer_queue_->IsQueueEnabled());
-}
-
-TEST_F(ThrottlingHelperTest, TaskQueueUnthrottle_InitiallyEnabled) {
- timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- timer_queue_->SetQueueEnabled(true); // NOP
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- EXPECT_FALSE(timer_queue_->IsQueueEnabled());
-
- throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
- EXPECT_TRUE(timer_queue_->IsQueueEnabled());
-}
-
-TEST_F(ThrottlingHelperTest, TaskQueueUnthrottle_InitiallyDisabled) {
- timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- timer_queue_->SetQueueEnabled(false);
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- EXPECT_FALSE(timer_queue_->IsQueueEnabled());
-
- throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
- EXPECT_FALSE(timer_queue_->IsQueueEnabled());
-}
-
-TEST_F(ThrottlingHelperTest, SetQueueEnabled_Unthrottled) {
- timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- throttling_helper_->SetQueueEnabled(timer_queue_.get(), false);
- EXPECT_FALSE(timer_queue_->IsQueueEnabled());
-
- throttling_helper_->SetQueueEnabled(timer_queue_.get(), true);
- EXPECT_TRUE(timer_queue_->IsQueueEnabled());
-}
-
-TEST_F(ThrottlingHelperTest, SetQueueEnabled_DisabledWhileThrottled) {
- timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- EXPECT_FALSE(timer_queue_->IsQueueEnabled());
-
- throttling_helper_->SetQueueEnabled(timer_queue_.get(), false);
- throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
- EXPECT_FALSE(timer_queue_->IsQueueEnabled());
-}
-
-TEST_F(ThrottlingHelperTest, TaskQueueDisabledTillPump_ThenManuallyDisabled) {
- timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- EXPECT_TRUE(timer_queue_->IsQueueEnabled());
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- EXPECT_FALSE(timer_queue_->IsQueueEnabled());
-
- mock_task_runner_->RunUntilIdle(); // Wait until the pump.
- EXPECT_TRUE(timer_queue_->IsQueueEnabled());
-
- throttling_helper_->SetQueueEnabled(timer_queue_.get(), false);
- EXPECT_FALSE(timer_queue_->IsQueueEnabled());
-}
-
-TEST_F(ThrottlingHelperTest, DoubleIncrementDoubleDecrement) {
- timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask));
-
- EXPECT_TRUE(timer_queue_->IsQueueEnabled());
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
- EXPECT_FALSE(timer_queue_->IsQueueEnabled());
- throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
- throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get());
- EXPECT_TRUE(timer_queue_->IsQueueEnabled());
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/user_model.cc b/chromium/components/scheduler/renderer/user_model.cc
deleted file mode 100644
index c71e86c21d8..00000000000
--- a/chromium/components/scheduler/renderer/user_model.cc
+++ /dev/null
@@ -1,222 +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 "components/scheduler/renderer/user_model.h"
-
-#include "base/metrics/histogram_macros.h"
-
-namespace scheduler {
-
-namespace {
-// This enum is used to back a histogram, and should therefore be treated as
-// append-only.
-enum GesturePredictionResult {
- GESTURE_OCCURED_WAS_PREDICTED = 0,
- GESTURE_OCCURED_BUT_NOT_PREDICTED = 1,
- GESTURE_PREDICTED_BUT_DID_NOT_OCCUR = 2,
- GESTURE_PREDICTION_RESULT_COUNT = 3
-};
-
-void RecordGesturePrediction(GesturePredictionResult result) {
- UMA_HISTOGRAM_ENUMERATION(
- "RendererScheduler.UserModel.GesturePredictedCorrectly", result,
- GESTURE_PREDICTION_RESULT_COUNT);
-}
-
-} // namespace
-
-UserModel::UserModel()
- : pending_input_event_count_(0),
- is_gesture_active_(false),
- is_gesture_expected_(false) {}
-UserModel::~UserModel() {}
-
-void UserModel::DidStartProcessingInputEvent(blink::WebInputEvent::Type type,
- const base::TimeTicks now) {
- last_input_signal_time_ = now;
- if (type == blink::WebInputEvent::TouchStart ||
- type == blink::WebInputEvent::GestureScrollBegin ||
- type == blink::WebInputEvent::GesturePinchBegin) {
- // Only update stats once per gesture.
- if (!is_gesture_active_) {
- last_gesture_start_time_ = now;
-
- RecordGesturePrediction(is_gesture_expected_
- ? GESTURE_OCCURED_WAS_PREDICTED
- : GESTURE_OCCURED_BUT_NOT_PREDICTED);
-
- if (!last_reset_time_.is_null()) {
- base::TimeDelta time_since_reset = now - last_reset_time_;
- UMA_HISTOGRAM_MEDIUM_TIMES(
- "RendererScheduler.UserModel.GestureStartTimeSinceModelReset",
- time_since_reset);
- }
-
- // If there has been a previous gesture, record a UMA metric for the time
- // interval between then and now.
- if (!last_continuous_gesture_time_.is_null()) {
- base::TimeDelta time_since_last_gesture =
- now - last_continuous_gesture_time_;
- UMA_HISTOGRAM_MEDIUM_TIMES(
- "RendererScheduler.UserModel.TimeBetweenGestures",
- time_since_last_gesture);
- }
- }
-
- is_gesture_active_ = true;
- }
-
- // We need to track continuous gestures seperatly for scroll detection
- // because taps should not be confused with scrolls.
- if (type == blink::WebInputEvent::GestureScrollBegin ||
- type == blink::WebInputEvent::GestureScrollEnd ||
- type == blink::WebInputEvent::GestureScrollUpdate ||
- type == blink::WebInputEvent::GestureFlingStart ||
- type == blink::WebInputEvent::GestureFlingCancel ||
- type == blink::WebInputEvent::GesturePinchBegin ||
- type == blink::WebInputEvent::GesturePinchEnd ||
- type == blink::WebInputEvent::GesturePinchUpdate) {
- last_continuous_gesture_time_ = now;
- }
-
- // If the gesture has ended, clear |is_gesture_active_| and record a UMA
- // metric that tracks its duration.
- if (type == blink::WebInputEvent::GestureScrollEnd ||
- type == blink::WebInputEvent::GesturePinchEnd ||
- type == blink::WebInputEvent::GestureFlingStart ||
- type == blink::WebInputEvent::TouchEnd) {
- // Only update stats once per gesture.
- if (is_gesture_active_) {
- base::TimeDelta duration = now - last_gesture_start_time_;
- UMA_HISTOGRAM_TIMES("RendererScheduler.UserModel.GestureDuration",
- duration);
- }
- is_gesture_active_ = false;
- }
-
- TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
- "is_gesture_active", is_gesture_active_);
-
- pending_input_event_count_++;
-}
-
-void UserModel::DidFinishProcessingInputEvent(const base::TimeTicks now) {
- last_input_signal_time_ = now;
- if (pending_input_event_count_ > 0)
- pending_input_event_count_--;
-}
-
-base::TimeDelta UserModel::TimeLeftInUserGesture(base::TimeTicks now) const {
- base::TimeDelta escalated_priority_duration =
- base::TimeDelta::FromMilliseconds(kGestureEstimationLimitMillis);
-
- // If the input event is still pending, go into input prioritized policy and
- // check again later.
- if (pending_input_event_count_ > 0)
- return escalated_priority_duration;
- if (last_input_signal_time_.is_null() ||
- last_input_signal_time_ + escalated_priority_duration < now) {
- return base::TimeDelta();
- }
- return last_input_signal_time_ + escalated_priority_duration - now;
-}
-
-bool UserModel::IsGestureExpectedSoon(
- const base::TimeTicks now,
- base::TimeDelta* prediction_valid_duration) {
- bool was_gesture_expected = is_gesture_expected_;
- is_gesture_expected_ =
- IsGestureExpectedSoonImpl(now, prediction_valid_duration);
-
- // Track when we start expecting a gesture so we can work out later if a
- // gesture actually happened.
- if (!was_gesture_expected && is_gesture_expected_)
- last_gesture_expected_start_time_ = now;
-
- if (was_gesture_expected && !is_gesture_expected_ &&
- last_gesture_expected_start_time_ > last_gesture_start_time_) {
- RecordGesturePrediction(GESTURE_PREDICTED_BUT_DID_NOT_OCCUR);
- }
- return is_gesture_expected_;
-}
-
-bool UserModel::IsGestureExpectedSoonImpl(
- const base::TimeTicks now,
- base::TimeDelta* prediction_valid_duration) const {
- if (is_gesture_active_) {
- if (IsGestureExpectedToContinue(now, prediction_valid_duration)) {
- return false;
- } else {
- // If a gesture is not expected to continue then we expect a subsequent
- // gesture soon.
- *prediction_valid_duration =
- base::TimeDelta::FromMilliseconds(kExpectSubsequentGestureMillis);
- return true;
- }
- } else {
- // If we've have a finished a gesture then a subsequent gesture is deemed
- // likely.
- base::TimeDelta expect_subsequent_gesture_for =
- base::TimeDelta::FromMilliseconds(kExpectSubsequentGestureMillis);
- if (last_continuous_gesture_time_.is_null() ||
- last_continuous_gesture_time_ + expect_subsequent_gesture_for <= now) {
- return false;
- }
- *prediction_valid_duration =
- last_continuous_gesture_time_ + expect_subsequent_gesture_for - now;
- return true;
- }
-}
-
-bool UserModel::IsGestureExpectedToContinue(
- const base::TimeTicks now,
- base::TimeDelta* prediction_valid_duration) const {
- if (!is_gesture_active_)
- return false;
-
- base::TimeDelta median_gesture_duration =
- base::TimeDelta::FromMilliseconds(kMedianGestureDurationMillis);
- base::TimeTicks expected_gesture_end_time =
- last_gesture_start_time_ + median_gesture_duration;
-
- if (expected_gesture_end_time > now) {
- *prediction_valid_duration = expected_gesture_end_time - now;
- return true;
- }
- return false;
-}
-
-void UserModel::Reset(base::TimeTicks now) {
- last_input_signal_time_ = base::TimeTicks();
- last_gesture_start_time_ = base::TimeTicks();
- last_continuous_gesture_time_ = base::TimeTicks();
- last_gesture_expected_start_time_ = base::TimeTicks();
- last_reset_time_ = now;
- is_gesture_active_ = false;
- is_gesture_expected_ = false;
-}
-
-void UserModel::AsValueInto(base::trace_event::TracedValue* state) const {
- state->BeginDictionary("user_model");
- state->SetInteger("pending_input_event_count", pending_input_event_count_);
- state->SetDouble(
- "last_input_signal_time",
- (last_input_signal_time_ - base::TimeTicks()).InMillisecondsF());
- state->SetDouble(
- "last_gesture_start_time",
- (last_gesture_start_time_ - base::TimeTicks()).InMillisecondsF());
- state->SetDouble(
- "last_continuous_gesture_time",
- (last_continuous_gesture_time_ - base::TimeTicks()).InMillisecondsF());
- state->SetDouble("last_gesture_expected_start_time",
- (last_gesture_expected_start_time_ - base::TimeTicks())
- .InMillisecondsF());
- state->SetDouble("last_reset_time",
- (last_reset_time_ - base::TimeTicks()).InMillisecondsF());
- state->SetBoolean("is_gesture_expected", is_gesture_expected_);
- state->SetBoolean("is_gesture_active", is_gesture_active_);
- state->EndDictionary();
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/user_model.h b/chromium/components/scheduler/renderer/user_model.h
deleted file mode 100644
index f93b10beadc..00000000000
--- a/chromium/components/scheduler/renderer/user_model.h
+++ /dev/null
@@ -1,84 +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 COMPONENTS_SCHEDULER_RENDERER_USER_MODEL_H_
-#define COMPONENTS_SCHEDULER_RENDERER_USER_MODEL_H_
-
-#include "base/macros.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "components/scheduler/renderer/renderer_scheduler.h"
-#include "components/scheduler/scheduler_export.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-
-namespace scheduler {
-
-class SCHEDULER_EXPORT UserModel {
- public:
- UserModel();
- ~UserModel();
-
- // Tells us that the system started processing an input event. Must be paired
- // with a call to DidFinishProcessingInputEvent.
- void DidStartProcessingInputEvent(blink::WebInputEvent::Type type,
- const base::TimeTicks now);
-
- // Tells us that the system finished processing an input event.
- void DidFinishProcessingInputEvent(const base::TimeTicks now);
-
- // Returns the estimated amount of time left in the current user gesture, to a
- // maximum of |kGestureEstimationLimitMillis|. After that time has elapased
- // this function should be called again.
- base::TimeDelta TimeLeftInUserGesture(base::TimeTicks now) const;
-
- // Tries to guess if a user gesture is expected soon. Currently this is
- // very simple, but one day I hope to do something more sophisticated here.
- // The prediction may change after |prediction_valid_duration| has elapsed.
- bool IsGestureExpectedSoon(const base::TimeTicks now,
- base::TimeDelta* prediction_valid_duration);
-
- // Returns true if a gesture has been in progress for less than the median
- // gesture duration. The prediction may change after
- // |prediction_valid_duration| has elapsed.
- bool IsGestureExpectedToContinue(
- const base::TimeTicks now,
- base::TimeDelta* prediction_valid_duration) const;
-
- void AsValueInto(base::trace_event::TracedValue* state) const;
-
- // The time we should stay in a priority-escalated mode after an input event.
- static const int kGestureEstimationLimitMillis = 100;
-
- // This is based on two weeks of Android usage data.
- static const int kMedianGestureDurationMillis = 300;
-
- // We consider further gesture start events to be likely if the user has
- // interacted with the device in the past two seconds.
- // Based on Android usage data, 2000ms between gestures is the 75th percentile
- // with 700ms being the 50th.
- static const int kExpectSubsequentGestureMillis = 2000;
-
- // Clears input signals.
- void Reset(base::TimeTicks now);
-
- private:
- bool IsGestureExpectedSoonImpl(
- const base::TimeTicks now,
- base::TimeDelta* prediction_valid_duration) const;
-
- int pending_input_event_count_;
- base::TimeTicks last_input_signal_time_;
- base::TimeTicks last_gesture_start_time_;
- base::TimeTicks last_continuous_gesture_time_; // Doesn't include Taps.
- base::TimeTicks last_gesture_expected_start_time_;
- base::TimeTicks last_reset_time_;
- bool is_gesture_active_; // This typically means the user's finger is down.
- bool is_gesture_expected_;
-
- DISALLOW_COPY_AND_ASSIGN(UserModel);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_USER_MODEL_H_
diff --git a/chromium/components/scheduler/renderer/user_model_unittest.cc b/chromium/components/scheduler/renderer/user_model_unittest.cc
deleted file mode 100644
index 87afc72595b..00000000000
--- a/chromium/components/scheduler/renderer/user_model_unittest.cc
+++ /dev/null
@@ -1,254 +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 "components/scheduler/renderer/user_model.h"
-
-#include "base/test/simple_test_tick_clock.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace scheduler {
-
-class UserModelTest : public testing::Test {
- public:
- UserModelTest() {}
- ~UserModelTest() override {}
-
- void SetUp() override {
- clock_.reset(new base::SimpleTestTickClock());
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
-
- user_model_.reset(new UserModel());
- }
-
- protected:
- static base::TimeDelta priority_escalation_after_input_duration() {
- return base::TimeDelta::FromMilliseconds(
- UserModel::kGestureEstimationLimitMillis);
- }
-
- static base::TimeDelta subsequent_input_expected_after_input_duration() {
- return base::TimeDelta::FromMilliseconds(
- UserModel::kExpectSubsequentGestureMillis);
- }
-
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- std::unique_ptr<UserModel> user_model_;
-};
-
-TEST_F(UserModelTest, TimeLeftInUserGesture_NoInput) {
- EXPECT_EQ(base::TimeDelta(),
- user_model_->TimeLeftInUserGesture(clock_->NowTicks()));
-}
-
-TEST_F(UserModelTest, TimeLeftInUserGesture_ImmediatelyAfterInput) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::TouchStart, clock_->NowTicks());
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
- EXPECT_EQ(priority_escalation_after_input_duration(),
- user_model_->TimeLeftInUserGesture(clock_->NowTicks()));
-}
-
-TEST_F(UserModelTest, TimeLeftInUserGesture_ShortlyAfterInput) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::TouchStart, clock_->NowTicks());
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
- base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10));
- clock_->Advance(delta);
- EXPECT_EQ(priority_escalation_after_input_duration() - delta,
- user_model_->TimeLeftInUserGesture(clock_->NowTicks()));
-}
-
-TEST_F(UserModelTest, TimeLeftInUserGesture_LongAfterInput) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::TouchStart, clock_->NowTicks());
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
- clock_->Advance(priority_escalation_after_input_duration() * 2);
- EXPECT_EQ(base::TimeDelta(),
- user_model_->TimeLeftInUserGesture(clock_->NowTicks()));
-}
-
-TEST_F(UserModelTest, DidFinishProcessingInputEvent_Delayed) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::TouchStart, clock_->NowTicks());
- clock_->Advance(priority_escalation_after_input_duration() * 10);
-
- EXPECT_EQ(priority_escalation_after_input_duration(),
- user_model_->TimeLeftInUserGesture(clock_->NowTicks()));
-
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
- base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10));
- clock_->Advance(delta);
-
- EXPECT_EQ(priority_escalation_after_input_duration() - delta,
- user_model_->TimeLeftInUserGesture(clock_->NowTicks()));
-}
-
-TEST_F(UserModelTest, GestureExpectedSoon_NoRecentInput) {
- base::TimeDelta prediction_valid_duration;
- EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(),
- &prediction_valid_duration));
- EXPECT_EQ(base::TimeDelta(), prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfter_GestureScrollBegin) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks());
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
-
- base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10));
- clock_->Advance(delta);
-
- base::TimeDelta prediction_valid_duration;
- EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(),
- &prediction_valid_duration));
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(
- UserModel::kMedianGestureDurationMillis) -
- delta,
- prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, GestureExpectedSoon_LongAfter_GestureScrollBegin) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks());
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
-
- base::TimeDelta delta(base::TimeDelta::FromMilliseconds(
- UserModel::kMedianGestureDurationMillis * 2));
- clock_->Advance(delta);
-
- base::TimeDelta prediction_valid_duration;
- EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(),
- &prediction_valid_duration));
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(
- UserModel::kExpectSubsequentGestureMillis),
- prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, GestureExpectedSoon_ImmediatelyAfter_GestureScrollEnd) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks());
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
-
- base::TimeDelta prediction_valid_duration;
- EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(),
- &prediction_valid_duration));
- EXPECT_EQ(subsequent_input_expected_after_input_duration(),
- prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfter_GestureScrollEnd) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks());
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
-
- base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10));
- clock_->Advance(delta);
-
- base::TimeDelta prediction_valid_duration;
- EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(),
- &prediction_valid_duration));
- EXPECT_EQ(subsequent_input_expected_after_input_duration() - delta,
- prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, GestureExpectedSoon_LongAfter_GestureScrollEnd) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks());
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
- clock_->Advance(subsequent_input_expected_after_input_duration() * 2);
-
- base::TimeDelta prediction_valid_duration;
- EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(),
- &prediction_valid_duration));
- EXPECT_EQ(base::TimeDelta(), prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfter_GesturePinchEnd) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GesturePinchEnd, clock_->NowTicks());
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
-
- base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10));
- clock_->Advance(delta);
-
- base::TimeDelta prediction_valid_duration;
- EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(),
- &prediction_valid_duration));
- EXPECT_EQ(subsequent_input_expected_after_input_duration() - delta,
- prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfterInput_GestureTap) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GestureTap, clock_->NowTicks());
- user_model_->DidFinishProcessingInputEvent(clock_->NowTicks());
-
- base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10));
- clock_->Advance(delta);
-
- base::TimeDelta prediction_valid_duration;
- EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(),
- &prediction_valid_duration));
- EXPECT_EQ(base::TimeDelta(), prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, IsGestureExpectedToContinue_NoGesture) {
- base::TimeDelta prediction_valid_duration;
- EXPECT_FALSE(user_model_->IsGestureExpectedToContinue(
- clock_->NowTicks(), &prediction_valid_duration));
- EXPECT_EQ(base::TimeDelta(), prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, IsGestureExpectedToContinue_GestureJustStarted) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks());
- base::TimeDelta prediction_valid_duration;
- EXPECT_TRUE(user_model_->IsGestureExpectedToContinue(
- clock_->NowTicks(), &prediction_valid_duration));
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(
- UserModel::kMedianGestureDurationMillis),
- prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, IsGestureExpectedToContinue_GestureJustEnded) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks());
- base::TimeDelta prediction_valid_duration;
- EXPECT_FALSE(user_model_->IsGestureExpectedToContinue(
- clock_->NowTicks(), &prediction_valid_duration));
- EXPECT_EQ(base::TimeDelta(), prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, IsGestureExpectedToContinue_ShortlyAfterGestureStarted) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks());
-
- base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10));
- clock_->Advance(delta);
-
- base::TimeDelta prediction_valid_duration;
- EXPECT_TRUE(user_model_->IsGestureExpectedToContinue(
- clock_->NowTicks(), &prediction_valid_duration));
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(
- UserModel::kMedianGestureDurationMillis) -
- delta,
- prediction_valid_duration);
-}
-
-TEST_F(UserModelTest, IsGestureExpectedToContinue_LongAfterGestureStarted) {
- user_model_->DidStartProcessingInputEvent(
- blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks());
-
- base::TimeDelta delta(base::TimeDelta::FromMilliseconds(
- UserModel::kMedianGestureDurationMillis * 2));
- clock_->Advance(delta);
-
- base::TimeDelta prediction_valid_duration;
- EXPECT_FALSE(user_model_->IsGestureExpectedToContinue(
- clock_->NowTicks(), &prediction_valid_duration));
- EXPECT_EQ(base::TimeDelta(), prediction_valid_duration);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/web_frame_scheduler_impl.cc b/chromium/components/scheduler/renderer/web_frame_scheduler_impl.cc
deleted file mode 100644
index fba6b691b5c..00000000000
--- a/chromium/components/scheduler/renderer/web_frame_scheduler_impl.cc
+++ /dev/null
@@ -1,124 +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 "components/scheduler/renderer/web_frame_scheduler_impl.h"
-
-#include "base/trace_event/blame_context.h"
-#include "components/scheduler/base/real_time_domain.h"
-#include "components/scheduler/base/virtual_time_domain.h"
-#include "components/scheduler/child/web_task_runner_impl.h"
-#include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-#include "components/scheduler/renderer/web_view_scheduler_impl.h"
-#include "third_party/WebKit/public/platform/BlameContext.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-
-namespace scheduler {
-
-WebFrameSchedulerImpl::WebFrameSchedulerImpl(
- RendererSchedulerImpl* renderer_scheduler,
- WebViewSchedulerImpl* parent_web_view_scheduler,
- base::trace_event::BlameContext* blame_context)
- : renderer_scheduler_(renderer_scheduler),
- parent_web_view_scheduler_(parent_web_view_scheduler),
- blame_context_(blame_context),
- frame_visible_(true),
- page_visible_(true) {}
-
-WebFrameSchedulerImpl::~WebFrameSchedulerImpl() {
- if (loading_task_queue_.get()) {
- loading_task_queue_->UnregisterTaskQueue();
- loading_task_queue_->SetBlameContext(nullptr);
- }
-
- if (timer_task_queue_.get()) {
- timer_task_queue_->UnregisterTaskQueue();
- timer_task_queue_->SetBlameContext(nullptr);
- }
-
- if (parent_web_view_scheduler_)
- parent_web_view_scheduler_->Unregister(this);
-}
-
-void WebFrameSchedulerImpl::DetachFromWebViewScheduler() {
- parent_web_view_scheduler_ = nullptr;
-}
-
-void WebFrameSchedulerImpl::setFrameVisible(bool frame_visible) {
- frame_visible_ = frame_visible;
- // TODO(alexclarke): Do something with this flag.
-}
-
-blink::WebTaskRunner* WebFrameSchedulerImpl::loadingTaskRunner() {
- DCHECK(parent_web_view_scheduler_);
- if (!loading_web_task_runner_) {
- loading_task_queue_ =
- renderer_scheduler_->NewLoadingTaskRunner("frame_loading_tq");
- loading_task_queue_->SetBlameContext(blame_context_);
- if (parent_web_view_scheduler_->virtual_time_domain()) {
- loading_task_queue_->SetTimeDomain(
- parent_web_view_scheduler_->virtual_time_domain());
- }
- loading_web_task_runner_.reset(new WebTaskRunnerImpl(loading_task_queue_));
- }
- return loading_web_task_runner_.get();
-}
-
-blink::WebTaskRunner* WebFrameSchedulerImpl::timerTaskRunner() {
- DCHECK(parent_web_view_scheduler_);
- if (!timer_web_task_runner_) {
- timer_task_queue_ =
- renderer_scheduler_->NewTimerTaskRunner("frame_timer_tq");
- timer_task_queue_->SetBlameContext(blame_context_);
- if (parent_web_view_scheduler_->virtual_time_domain()) {
- timer_task_queue_->SetTimeDomain(
- parent_web_view_scheduler_->virtual_time_domain());
- } else if (!page_visible_) {
- renderer_scheduler_->throttling_helper()->IncreaseThrottleRefCount(
- timer_task_queue_.get());
- }
- timer_web_task_runner_.reset(new WebTaskRunnerImpl(timer_task_queue_));
- }
- return timer_web_task_runner_.get();
-}
-
-void WebFrameSchedulerImpl::setPageVisible(bool page_visible) {
- DCHECK(parent_web_view_scheduler_);
- if (page_visible_ == page_visible)
- return;
-
- page_visible_ = page_visible;
-
- if (!timer_web_task_runner_ ||
- parent_web_view_scheduler_->virtual_time_domain()) {
- return;
- }
-
- if (page_visible_) {
- renderer_scheduler_->throttling_helper()->DecreaseThrottleRefCount(
- timer_task_queue_.get());
- } else {
- renderer_scheduler_->throttling_helper()->IncreaseThrottleRefCount(
- timer_task_queue_.get());
- }
-}
-
-void WebFrameSchedulerImpl::OnVirtualTimeDomainChanged() {
- DCHECK(parent_web_view_scheduler_);
- DCHECK(parent_web_view_scheduler_->virtual_time_domain());
-
- if (timer_task_queue_) {
- renderer_scheduler_->throttling_helper()->UnregisterTaskQueue(
- timer_task_queue_.get());
- timer_task_queue_->SetTimeDomain(
- parent_web_view_scheduler_->virtual_time_domain());
- }
-
- if (loading_task_queue_) {
- loading_task_queue_->SetTimeDomain(
- parent_web_view_scheduler_->virtual_time_domain());
- }
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/web_frame_scheduler_impl.h b/chromium/components/scheduler/renderer/web_frame_scheduler_impl.h
deleted file mode 100644
index 25a18518660..00000000000
--- a/chromium/components/scheduler/renderer/web_frame_scheduler_impl.h
+++ /dev/null
@@ -1,70 +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 COMPONENTS_SCHEDULER_RENDERER_WEB_FRAME_SCHEDULER_IMPL_H_
-#define COMPONENTS_SCHEDULER_RENDERER_WEB_FRAME_SCHEDULER_IMPL_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/trace_event/trace_event.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/scheduler_export.h"
-#include "third_party/WebKit/public/platform/WebFrameScheduler.h"
-
-namespace base {
-namespace trace_event {
-class BlameContext;
-} // namespace trace_event
-class SingleThreadTaskRunner;
-} // namespace base
-
-namespace scheduler {
-
-class AutoAdvancingVirtualTimeDomain;
-class RendererSchedulerImpl;
-class TaskQueue;
-class WebTaskRunnerImpl;
-class WebViewSchedulerImpl;
-
-class SCHEDULER_EXPORT WebFrameSchedulerImpl : public blink::WebFrameScheduler {
- public:
- WebFrameSchedulerImpl(RendererSchedulerImpl* renderer_scheduler,
- WebViewSchedulerImpl* parent_web_view_scheduler,
- base::trace_event::BlameContext* blame_context);
-
- ~WebFrameSchedulerImpl() override;
-
- // blink::WebFrameScheduler implementation:
- void setFrameVisible(bool frame_visible) override;
- void setPageVisible(bool page_visible) override;
- blink::WebTaskRunner* loadingTaskRunner() override;
- blink::WebTaskRunner* timerTaskRunner() override;
-
- void OnVirtualTimeDomainChanged();
-
- private:
- friend class WebViewSchedulerImpl;
-
- void DetachFromWebViewScheduler();
- void ApplyPolicyToTimerQueue();
-
- scoped_refptr<TaskQueue> loading_task_queue_;
- scoped_refptr<TaskQueue> timer_task_queue_;
- std::unique_ptr<WebTaskRunnerImpl> loading_web_task_runner_;
- std::unique_ptr<WebTaskRunnerImpl> timer_web_task_runner_;
- RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED
- WebViewSchedulerImpl* parent_web_view_scheduler_; // NOT OWNED
- base::trace_event::BlameContext* blame_context_; // NOT OWNED
- TaskQueue::PumpPolicy virtual_time_pump_policy_;
- bool frame_visible_;
- bool page_visible_;
-
- DISALLOW_COPY_AND_ASSIGN(WebFrameSchedulerImpl);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_WEB_FRAME_SCHEDULER_IMPL_H_
diff --git a/chromium/components/scheduler/renderer/web_view_scheduler_impl.cc b/chromium/components/scheduler/renderer/web_view_scheduler_impl.cc
deleted file mode 100644
index 4ab4c11c570..00000000000
--- a/chromium/components/scheduler/renderer/web_view_scheduler_impl.cc
+++ /dev/null
@@ -1,115 +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 "components/scheduler/renderer/web_view_scheduler_impl.h"
-
-#include "base/logging.h"
-#include "components/scheduler/base/virtual_time_domain.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-#include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-#include "components/scheduler/renderer/web_frame_scheduler_impl.h"
-#include "third_party/WebKit/public/platform/WebFrameScheduler.h"
-#include "third_party/WebKit/public/web/WebConsoleMessage.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
-#include "third_party/WebKit/public/web/WebView.h"
-
-namespace scheduler {
-
-WebViewSchedulerImpl::WebViewSchedulerImpl(
- blink::WebView* web_view,
- RendererSchedulerImpl* renderer_scheduler,
- bool disable_background_timer_throttling)
- : virtual_time_pump_policy_(TaskQueue::PumpPolicy::AUTO),
- web_view_(web_view),
- renderer_scheduler_(renderer_scheduler),
- page_visible_(true),
- disable_background_timer_throttling_(disable_background_timer_throttling),
- allow_virtual_time_to_advance_(true) {
- renderer_scheduler->AddWebViewScheduler(this);
-}
-
-WebViewSchedulerImpl::~WebViewSchedulerImpl() {
- // TODO(alexclarke): Find out why we can't rely on the web view outliving the
- // frame.
- for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) {
- frame_scheduler->DetachFromWebViewScheduler();
- }
- renderer_scheduler_->RemoveWebViewScheduler(this);
- if (virtual_time_domain_)
- renderer_scheduler_->UnregisterTimeDomain(virtual_time_domain_.get());
-}
-
-void WebViewSchedulerImpl::setPageVisible(bool page_visible) {
- if (disable_background_timer_throttling_ || page_visible_ == page_visible)
- return;
-
- page_visible_ = page_visible;
-
- for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) {
- frame_scheduler->setPageVisible(page_visible_);
- }
-}
-
-std::unique_ptr<WebFrameSchedulerImpl>
-WebViewSchedulerImpl::createWebFrameSchedulerImpl(
- base::trace_event::BlameContext* blame_context) {
- std::unique_ptr<WebFrameSchedulerImpl> frame_scheduler(
- new WebFrameSchedulerImpl(renderer_scheduler_, this, blame_context));
- frame_scheduler->setPageVisible(page_visible_);
- frame_schedulers_.insert(frame_scheduler.get());
- return frame_scheduler;
-}
-
-std::unique_ptr<blink::WebFrameScheduler>
-WebViewSchedulerImpl::createFrameScheduler(blink::BlameContext* blame_context) {
- return createWebFrameSchedulerImpl(blame_context);
-}
-
-void WebViewSchedulerImpl::Unregister(WebFrameSchedulerImpl* frame_scheduler) {
- DCHECK(frame_schedulers_.find(frame_scheduler) != frame_schedulers_.end());
- frame_schedulers_.erase(frame_scheduler);
-}
-
-void WebViewSchedulerImpl::AddConsoleWarning(const std::string& message) {
- if (!web_view_ || !web_view_->mainFrame())
- return;
- blink::WebConsoleMessage console_message(
- blink::WebConsoleMessage::LevelWarning,
- blink::WebString::fromUTF8(message));
- web_view_->mainFrame()->addMessageToConsole(console_message);
-}
-
-void WebViewSchedulerImpl::enableVirtualTime() {
- // If we've already switched to virtual time then we don't need to do
- // anything more.
- if (virtual_time_domain_.get())
- return;
-
- virtual_time_domain_.reset(new AutoAdvancingVirtualTimeDomain(
- renderer_scheduler_->tick_clock()->NowTicks()));
- renderer_scheduler_->RegisterTimeDomain(virtual_time_domain_.get());
-
- virtual_time_domain_->SetCanAdvanceVirtualTime(
- allow_virtual_time_to_advance_);
-
- for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) {
- frame_scheduler->OnVirtualTimeDomainChanged();
- }
-}
-
-void WebViewSchedulerImpl::setAllowVirtualTimeToAdvance(
- bool allow_virtual_time_to_advance) {
- if (allow_virtual_time_to_advance_ == allow_virtual_time_to_advance)
- return;
-
- allow_virtual_time_to_advance_ = allow_virtual_time_to_advance;
-
- if (virtual_time_domain_) {
- virtual_time_domain_->SetCanAdvanceVirtualTime(
- allow_virtual_time_to_advance);
- }
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/web_view_scheduler_impl.h b/chromium/components/scheduler/renderer/web_view_scheduler_impl.h
deleted file mode 100644
index f061517bad1..00000000000
--- a/chromium/components/scheduler/renderer/web_view_scheduler_impl.h
+++ /dev/null
@@ -1,79 +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 COMPONENTS_SCHEDULER_RENDERER_WEB_VIEW_SCHEDULER_IMPL_H_
-#define COMPONENTS_SCHEDULER_RENDERER_WEB_VIEW_SCHEDULER_IMPL_H_
-
-#include <memory>
-#include <set>
-#include <string>
-
-#include "base/macros.h"
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/scheduler_export.h"
-#include "third_party/WebKit/public/platform/WebViewScheduler.h"
-
-namespace base {
-namespace trace_event {
-class BlameContext;
-} // namespace trace_event
-class SingleThreadTaskRunner;
-} // namespace base
-
-namespace blink {
-class WebView;
-} // namespace blink
-
-namespace scheduler {
-
-class AutoAdvancingVirtualTimeDomain;
-class RendererSchedulerImpl;
-class WebFrameSchedulerImpl;
-
-class SCHEDULER_EXPORT WebViewSchedulerImpl : public blink::WebViewScheduler {
- public:
- WebViewSchedulerImpl(blink::WebView* web_view,
- RendererSchedulerImpl* renderer_scheduler,
- bool disable_background_timer_throttling);
-
- ~WebViewSchedulerImpl() override;
-
- // blink::WebViewScheduler implementation:
- void setPageVisible(bool page_visible) override;
- std::unique_ptr<blink::WebFrameScheduler> createFrameScheduler(
- blink::BlameContext* blame_context) override;
- void enableVirtualTime() override;
- void setAllowVirtualTimeToAdvance(
- bool allow_virtual_time_to_advance) override;
-
- // Virtual for testing.
- virtual void AddConsoleWarning(const std::string& message);
-
- std::unique_ptr<WebFrameSchedulerImpl> createWebFrameSchedulerImpl(
- base::trace_event::BlameContext* blame_context);
-
- private:
- friend class WebFrameSchedulerImpl;
-
- void Unregister(WebFrameSchedulerImpl* frame_scheduler);
-
- AutoAdvancingVirtualTimeDomain* virtual_time_domain() const {
- return virtual_time_domain_.get();
- }
-
- std::set<WebFrameSchedulerImpl*> frame_schedulers_;
- std::unique_ptr<AutoAdvancingVirtualTimeDomain> virtual_time_domain_;
- TaskQueue::PumpPolicy virtual_time_pump_policy_;
- blink::WebView* web_view_;
- RendererSchedulerImpl* renderer_scheduler_;
- bool page_visible_;
- bool disable_background_timer_throttling_;
- bool allow_virtual_time_to_advance_;
-
- DISALLOW_COPY_AND_ASSIGN(WebViewSchedulerImpl);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_WEB_VIEW_SCHEDULER_IMPL_H_
diff --git a/chromium/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/chromium/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
deleted file mode 100644
index 8ccc4dfc83c..00000000000
--- a/chromium/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
+++ /dev/null
@@ -1,504 +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 "components/scheduler/renderer/web_view_scheduler_impl.h"
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/memory/ptr_util.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-#include "components/scheduler/renderer/web_frame_scheduler_impl.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebTaskRunner.h"
-#include "third_party/WebKit/public/platform/WebTraceLocation.h"
-
-using testing::ElementsAre;
-
-namespace scheduler {
-
-class WebViewSchedulerImplTest : public testing::Test {
- public:
- WebViewSchedulerImplTest() {}
- ~WebViewSchedulerImplTest() override {}
-
- void SetUp() override {
- clock_.reset(new base::SimpleTestTickClock());
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- mock_task_runner_ =
- make_scoped_refptr(new cc::OrderedSimpleTaskRunner(clock_.get(), true));
- delagate_ = SchedulerTqmDelegateForTest::Create(
- mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get())));
- scheduler_.reset(new RendererSchedulerImpl(delagate_));
- web_view_scheduler_.reset(new WebViewSchedulerImpl(
- nullptr, scheduler_.get(), DisableBackgroundTimerThrottling()));
- web_frame_scheduler_ =
- web_view_scheduler_->createWebFrameSchedulerImpl(nullptr);
- }
-
- void TearDown() override {
- web_frame_scheduler_.reset();
- web_view_scheduler_.reset();
- scheduler_->Shutdown();
- scheduler_.reset();
- }
-
- virtual bool DisableBackgroundTimerThrottling() const { return false; }
-
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
- scoped_refptr<SchedulerTqmDelegate> delagate_;
- std::unique_ptr<RendererSchedulerImpl> scheduler_;
- std::unique_ptr<WebViewSchedulerImpl> web_view_scheduler_;
- std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler_;
-};
-
-TEST_F(WebViewSchedulerImplTest, TestDestructionOfFrameSchedulersBefore) {
- std::unique_ptr<blink::WebFrameScheduler> frame1(
- web_view_scheduler_->createFrameScheduler(nullptr));
- std::unique_ptr<blink::WebFrameScheduler> frame2(
- web_view_scheduler_->createFrameScheduler(nullptr));
-}
-
-TEST_F(WebViewSchedulerImplTest, TestDestructionOfFrameSchedulersAfter) {
- std::unique_ptr<blink::WebFrameScheduler> frame1(
- web_view_scheduler_->createFrameScheduler(nullptr));
- std::unique_ptr<blink::WebFrameScheduler> frame2(
- web_view_scheduler_->createFrameScheduler(nullptr));
- web_view_scheduler_.reset();
-}
-
-namespace {
-class RepeatingTask : public blink::WebTaskRunner::Task {
- public:
- RepeatingTask(blink::WebTaskRunner* web_task_runner, int* run_count)
- : web_task_runner_(web_task_runner), run_count_(run_count) {}
-
- ~RepeatingTask() override {}
-
- void run() override {
- (*run_count_)++;
- web_task_runner_->postDelayedTask(
- BLINK_FROM_HERE, new RepeatingTask(web_task_runner_, run_count_), 1.0);
- }
-
- private:
- blink::WebTaskRunner* web_task_runner_; // NOT OWNED
- int* run_count_; // NOT OWNED
-};
-} // namespace
-
-TEST_F(WebViewSchedulerImplTest, RepeatingTimer_PageInForeground) {
- web_view_scheduler_->setPageVisible(true);
-
- int run_count = 0;
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count),
- 1.0);
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(1000, run_count);
-}
-
-TEST_F(WebViewSchedulerImplTest, RepeatingTimer_PageInBackground) {
- web_view_scheduler_->setPageVisible(false);
-
- int run_count = 0;
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count),
- 1.0);
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(WebViewSchedulerImplTest, RepeatingLoadingTask_PageInBackground) {
- web_view_scheduler_->setPageVisible(false);
-
- int run_count = 0;
- web_frame_scheduler_->loadingTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler_->loadingTaskRunner(), &run_count),
- 1.0);
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(1000, run_count); // Loading tasks should not be throttled
-}
-
-TEST_F(WebViewSchedulerImplTest, RepeatingTimers_OneBackgroundOneForeground) {
- std::unique_ptr<WebViewSchedulerImpl> web_view_scheduler2(
- new WebViewSchedulerImpl(nullptr, scheduler_.get(), false));
- std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler2 =
- web_view_scheduler2->createWebFrameSchedulerImpl(nullptr);
-
- web_view_scheduler_->setPageVisible(true);
- web_view_scheduler2->setPageVisible(false);
-
- int run_count1 = 0;
- int run_count2 = 0;
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count1),
- 1.0);
- web_frame_scheduler2->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler2->timerTaskRunner(), &run_count2),
- 1.0);
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(1000, run_count1);
- EXPECT_EQ(1, run_count2);
-}
-
-namespace {
-class VirtualTimeRecorderTask : public blink::WebTaskRunner::Task {
- public:
- VirtualTimeRecorderTask(base::SimpleTestTickClock* clock,
- blink::WebTaskRunner* web_task_runner,
- std::vector<base::TimeTicks>* out_real_times,
- std::vector<size_t>* out_virtual_times_ms)
- : clock_(clock),
- web_task_runner_(web_task_runner),
- out_real_times_(out_real_times),
- out_virtual_times_ms_(out_virtual_times_ms) {}
-
- ~VirtualTimeRecorderTask() override {}
-
- void run() override {
- out_real_times_->push_back(clock_->NowTicks());
- out_virtual_times_ms_->push_back(
- web_task_runner_->monotonicallyIncreasingVirtualTimeSeconds() * 1000.0);
- }
-
- private:
- base::SimpleTestTickClock* clock_; // NOT OWNED
- blink::WebTaskRunner* web_task_runner_; // NOT OWNED
- std::vector<base::TimeTicks>* out_real_times_; // NOT OWNED
- std::vector<size_t>* out_virtual_times_ms_; // NOT OWNED
-};
-}
-
-TEST_F(WebViewSchedulerImplTest, VirtualTime_TimerFastForwarding) {
- std::vector<base::TimeTicks> real_times;
- std::vector<size_t> virtual_times_ms;
- base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
- size_t initial_virtual_time_ms =
- web_frame_scheduler_->timerTaskRunner()
- ->monotonicallyIncreasingVirtualTimeSeconds() *
- 1000.0;
-
- web_view_scheduler_->enableVirtualTime();
-
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new VirtualTimeRecorderTask(clock_.get(),
- web_frame_scheduler_->timerTaskRunner(),
- &real_times, &virtual_times_ms),
- 2.0);
-
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new VirtualTimeRecorderTask(clock_.get(),
- web_frame_scheduler_->timerTaskRunner(),
- &real_times, &virtual_times_ms),
- 20.0);
-
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new VirtualTimeRecorderTask(clock_.get(),
- web_frame_scheduler_->timerTaskRunner(),
- &real_times, &virtual_times_ms),
- 200.0);
-
- mock_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(real_times, ElementsAre(initial_real_time,
- initial_real_time, initial_real_time));
- EXPECT_THAT(virtual_times_ms,
- ElementsAre(initial_virtual_time_ms + 2,
- initial_virtual_time_ms + 20,
- initial_virtual_time_ms + 200));
-}
-
-TEST_F(WebViewSchedulerImplTest, VirtualTime_LoadingTaskFastForwarding) {
- std::vector<base::TimeTicks> real_times;
- std::vector<size_t> virtual_times_ms;
- base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
- size_t initial_virtual_time_ms =
- web_frame_scheduler_->timerTaskRunner()
- ->monotonicallyIncreasingVirtualTimeSeconds() *
- 1000.0;
-
- web_view_scheduler_->enableVirtualTime();
-
- web_frame_scheduler_->loadingTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new VirtualTimeRecorderTask(clock_.get(),
- web_frame_scheduler_->loadingTaskRunner(),
- &real_times, &virtual_times_ms),
- 2.0);
-
- web_frame_scheduler_->loadingTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new VirtualTimeRecorderTask(clock_.get(),
- web_frame_scheduler_->loadingTaskRunner(),
- &real_times, &virtual_times_ms),
- 20.0);
-
- web_frame_scheduler_->loadingTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new VirtualTimeRecorderTask(clock_.get(),
- web_frame_scheduler_->loadingTaskRunner(),
- &real_times, &virtual_times_ms),
- 200.0);
-
- mock_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(real_times, ElementsAre(initial_real_time,
- initial_real_time, initial_real_time));
- EXPECT_THAT(virtual_times_ms,
- ElementsAre(initial_virtual_time_ms + 2,
- initial_virtual_time_ms + 20,
- initial_virtual_time_ms + 200));
-}
-
-TEST_F(WebViewSchedulerImplTest,
- RepeatingTimer_PageInBackground_MeansNothingForVirtualTime) {
- web_view_scheduler_->enableVirtualTime();
- web_view_scheduler_->setPageVisible(false);
- base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
-
- int run_count = 0;
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count),
- 1.0);
-
- mock_task_runner_->RunTasksWhile(mock_task_runner_->TaskRunCountBelow(2000));
- // Virtual time means page visibility is ignored.
- EXPECT_EQ(1999, run_count);
-
- // The global tick clock has not moved, yet we ran a large number of "delayed"
- // tasks despite calling setPageVisible(false).
- EXPECT_EQ(initial_real_time, scheduler_->tick_clock()->NowTicks());
-}
-
-namespace {
-class RunOrderTask : public blink::WebTaskRunner::Task {
- public:
- RunOrderTask(int index, std::vector<int>* out_run_order)
- : index_(index),
- out_run_order_(out_run_order) {}
-
- ~RunOrderTask() override {}
-
- void run() override {
- out_run_order_->push_back(index_);
- }
-
- private:
- int index_;
- std::vector<int>* out_run_order_; // NOT OWNED
-};
-
-class DelayedRunOrderTask : public blink::WebTaskRunner::Task {
- public:
- DelayedRunOrderTask(int index, blink::WebTaskRunner* task_runner,
- std::vector<int>* out_run_order)
- : index_(index),
- task_runner_(task_runner),
- out_run_order_(out_run_order) {}
-
- ~DelayedRunOrderTask() override {}
-
- void run() override {
- out_run_order_->push_back(index_);
- task_runner_->postTask(
- BLINK_FROM_HERE, new RunOrderTask(index_ + 1, out_run_order_));
- }
-
- private:
- int index_;
- blink::WebTaskRunner* task_runner_; // NOT OWNED
- std::vector<int>* out_run_order_; // NOT OWNED
-};
-}
-
-TEST_F(WebViewSchedulerImplTest, VirtualTime_NotAllowedToAdvance) {
- std::vector<int> run_order;
-
- web_view_scheduler_->setAllowVirtualTimeToAdvance(false);
- web_view_scheduler_->enableVirtualTime();
-
- web_frame_scheduler_->timerTaskRunner()->postTask(
- BLINK_FROM_HERE, new RunOrderTask(0, &run_order));
-
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new DelayedRunOrderTask(1, web_frame_scheduler_->timerTaskRunner(),
- &run_order),
- 2.0);
-
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new DelayedRunOrderTask(3, web_frame_scheduler_->timerTaskRunner(),
- &run_order),
- 4.0);
-
- mock_task_runner_->RunUntilIdle();
-
- // Immediate tasks are allowed to run even if delayed tasks are not.
- EXPECT_THAT(run_order, ElementsAre(0));
-}
-
-TEST_F(WebViewSchedulerImplTest, VirtualTime_AllowedToAdvance) {
- std::vector<int> run_order;
-
- web_view_scheduler_->setAllowVirtualTimeToAdvance(true);
- web_view_scheduler_->enableVirtualTime();
-
- web_frame_scheduler_->timerTaskRunner()->postTask(
- BLINK_FROM_HERE, new RunOrderTask(0, &run_order));
-
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new DelayedRunOrderTask(1, web_frame_scheduler_->timerTaskRunner(),
- &run_order),
- 2.0);
-
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new DelayedRunOrderTask(3, web_frame_scheduler_->timerTaskRunner(),
- &run_order),
- 4.0);
-
- mock_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4));
-}
-
-class WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling
- : public WebViewSchedulerImplTest {
- public:
- WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling() {}
- ~WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling() override {}
-
- bool DisableBackgroundTimerThrottling() const override { return true; }
-};
-
-TEST_F(WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling,
- RepeatingTimer_PageInBackground) {
- web_view_scheduler_->setPageVisible(false);
-
- int run_count = 0;
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count),
- 1.0);
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(1000, run_count);
-}
-
-TEST_F(WebViewSchedulerImplTest, VirtualTimeSettings_NewWebFrameScheduler) {
- std::vector<int> run_order;
-
- web_view_scheduler_->setAllowVirtualTimeToAdvance(false);
- web_view_scheduler_->enableVirtualTime();
-
- std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler =
- web_view_scheduler_->createWebFrameSchedulerImpl(nullptr);
-
- web_frame_scheduler->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE, new RunOrderTask(1, &run_order), 0.1);
-
- mock_task_runner_->RunUntilIdle();
- EXPECT_TRUE(run_order.empty());
-
- web_view_scheduler_->setAllowVirtualTimeToAdvance(true);
- mock_task_runner_->RunUntilIdle();
-
- EXPECT_THAT(run_order, ElementsAre(1));
-}
-
-namespace {
-class DeleteWebFrameSchedulerTask : public blink::WebTaskRunner::Task {
- public:
- explicit DeleteWebFrameSchedulerTask(WebViewSchedulerImpl* web_view_scheduler)
- : web_frame_scheduler_(
- web_view_scheduler->createWebFrameSchedulerImpl(nullptr)) {}
-
- ~DeleteWebFrameSchedulerTask() override {}
-
- void run() override { web_frame_scheduler_.reset(); }
-
- WebFrameSchedulerImpl* web_frame_scheduler() const {
- return web_frame_scheduler_.get();
- }
-
- private:
- std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler_;
-};
-
-class DeleteWebViewSchedulerTask : public blink::WebTaskRunner::Task {
- public:
- explicit DeleteWebViewSchedulerTask(WebViewSchedulerImpl* web_view_scheduler)
- : web_view_scheduler_(web_view_scheduler) {}
-
- ~DeleteWebViewSchedulerTask() override {}
-
- void run() override { web_view_scheduler_.reset(); }
-
- private:
- std::unique_ptr<WebViewSchedulerImpl> web_view_scheduler_;
-};
-} // namespace
-
-TEST_F(WebViewSchedulerImplTest, DeleteWebFrameSchedulers_InTask) {
- for (int i = 0; i < 10; i++) {
- DeleteWebFrameSchedulerTask* task =
- new DeleteWebFrameSchedulerTask(web_view_scheduler_.get());
- task->web_frame_scheduler()->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE, task, 1.0);
- }
- mock_task_runner_->RunUntilIdle();
-}
-
-TEST_F(WebViewSchedulerImplTest, DeleteWebViewScheduler_InTask) {
- web_frame_scheduler_->timerTaskRunner()->postTask(
- BLINK_FROM_HERE,
- new DeleteWebViewSchedulerTask(web_view_scheduler_.release()));
- mock_task_runner_->RunUntilIdle();
-}
-
-TEST_F(WebViewSchedulerImplTest, DeleteThrottledQueue_InTask) {
- web_view_scheduler_->setPageVisible(false);
-
- DeleteWebFrameSchedulerTask* delete_frame_task =
- new DeleteWebFrameSchedulerTask(web_view_scheduler_.get());
- blink::WebTaskRunner* timer_task_runner =
- delete_frame_task->web_frame_scheduler()->timerTaskRunner();
-
- int run_count = 0;
- timer_task_runner->postDelayedTask(
- BLINK_FROM_HERE, new RepeatingTask(timer_task_runner, &run_count), 1.0);
-
- // Note this will run at time t = 10s since we start at time t = 5000us, and
- // it will prevent further tasks from running (i.e. the RepeatingTask) by
- // deleting the WebFrameScheduler.
- timer_task_runner->postDelayedTask(BLINK_FROM_HERE, delete_frame_task,
- 9990.0);
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(100));
- EXPECT_EQ(10, run_count);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc b/chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
deleted file mode 100644
index b2419b463cb..00000000000
--- a/chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
+++ /dev/null
@@ -1,59 +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 "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h"
-
-#include "components/scheduler/base/task_queue.h"
-#include "components/scheduler/child/web_task_runner_impl.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-#include "components/scheduler/renderer/renderer_web_scheduler_impl.h"
-#include "third_party/WebKit/public/platform/WebTraceLocation.h"
-
-namespace scheduler {
-
-WebThreadImplForRendererScheduler::WebThreadImplForRendererScheduler(
- RendererSchedulerImpl* scheduler)
- : web_scheduler_(new RendererWebSchedulerImpl(scheduler)),
- task_runner_(scheduler->DefaultTaskRunner()),
- idle_task_runner_(scheduler->IdleTaskRunner()),
- scheduler_(scheduler),
- thread_id_(base::PlatformThread::CurrentId()),
- web_task_runner_(new WebTaskRunnerImpl(scheduler->DefaultTaskRunner())) {}
-
-WebThreadImplForRendererScheduler::~WebThreadImplForRendererScheduler() {
-}
-
-blink::PlatformThreadId WebThreadImplForRendererScheduler::threadId() const {
- return thread_id_;
-}
-
-blink::WebScheduler* WebThreadImplForRendererScheduler::scheduler() const {
- return web_scheduler_.get();
-}
-
-base::SingleThreadTaskRunner* WebThreadImplForRendererScheduler::GetTaskRunner()
- const {
- return task_runner_.get();
-}
-
-SingleThreadIdleTaskRunner*
-WebThreadImplForRendererScheduler::GetIdleTaskRunner() const {
- return idle_task_runner_.get();
-}
-
-blink::WebTaskRunner* WebThreadImplForRendererScheduler::getWebTaskRunner() {
- return web_task_runner_.get();
-}
-
-void WebThreadImplForRendererScheduler::AddTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer) {
- scheduler_->AddTaskObserver(observer);
-}
-
-void WebThreadImplForRendererScheduler::RemoveTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer) {
- scheduler_->RemoveTaskObserver(observer);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h b/chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h
deleted file mode 100644
index 04b0ece28bb..00000000000
--- a/chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h
+++ /dev/null
@@ -1,51 +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 COMPONENTS_SCHEDULER_RENDERER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_
-#define COMPONENTS_SCHEDULER_RENDERER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_
-
-#include "base/containers/scoped_ptr_hash_map.h"
-#include "components/scheduler/child/webthread_base.h"
-
-namespace blink {
-class WebScheduler;
-};
-
-namespace scheduler {
-class RendererSchedulerImpl;
-class WebSchedulerImpl;
-class WebTaskRunnerImpl;
-
-class SCHEDULER_EXPORT WebThreadImplForRendererScheduler
- : public WebThreadBase {
- public:
- explicit WebThreadImplForRendererScheduler(RendererSchedulerImpl* scheduler);
- ~WebThreadImplForRendererScheduler() override;
-
- // blink::WebThread implementation.
- blink::WebScheduler* scheduler() const override;
- blink::PlatformThreadId threadId() const override;
- blink::WebTaskRunner* getWebTaskRunner() override;
-
- // WebThreadBase implementation.
- base::SingleThreadTaskRunner* GetTaskRunner() const override;
- SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override;
-
- private:
- void AddTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer) override;
- void RemoveTaskObserverInternal(
- base::MessageLoop::TaskObserver* observer) override;
-
- std::unique_ptr<WebSchedulerImpl> web_scheduler_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
- RendererSchedulerImpl* scheduler_; // Not owned.
- blink::PlatformThreadId thread_id_;
- std::unique_ptr<WebTaskRunnerImpl> web_task_runner_;
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_
diff --git a/chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc b/chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
deleted file mode 100644
index 1d29f244f2f..00000000000
--- a/chromium/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
+++ /dev/null
@@ -1,213 +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 "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h"
-
-#include <stddef.h>
-
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_impl.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebTaskRunner.h"
-#include "third_party/WebKit/public/platform/WebTraceLocation.h"
-
-namespace scheduler {
-namespace {
-
-const int kWorkBatchSize = 2;
-
-class MockTask : public blink::WebTaskRunner::Task {
- public:
- MOCK_METHOD0(run, void());
-};
-
-class MockTaskObserver : public blink::WebThread::TaskObserver {
- public:
- MOCK_METHOD0(willProcessTask, void());
- MOCK_METHOD0(didProcessTask, void());
-};
-} // namespace
-
-class WebThreadImplForRendererSchedulerTest : public testing::Test {
- public:
- WebThreadImplForRendererSchedulerTest() {}
-
- void SetUp() override {
- clock_.reset(new base::SimpleTestTickClock());
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- scheduler_.reset(new RendererSchedulerImpl(SchedulerTqmDelegateImpl::Create(
- &message_loop_, base::WrapUnique(new TestTimeSource(clock_.get())))));
- default_task_runner_ = scheduler_->DefaultTaskRunner();
- thread_ = scheduler_->CreateMainThread();
- }
-
- ~WebThreadImplForRendererSchedulerTest() override {}
-
- void SetWorkBatchSizeForTesting(size_t work_batch_size) {
- scheduler_->GetSchedulerHelperForTesting()->SetWorkBatchSizeForTesting(
- work_batch_size);
- }
-
- void TearDown() override { scheduler_->Shutdown(); }
-
- protected:
- base::MessageLoop message_loop_;
- std::unique_ptr<base::SimpleTestTickClock> clock_;
- std::unique_ptr<RendererSchedulerImpl> scheduler_;
- scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
- std::unique_ptr<blink::WebThread> thread_;
-
- DISALLOW_COPY_AND_ASSIGN(WebThreadImplForRendererSchedulerTest);
-};
-
-TEST_F(WebThreadImplForRendererSchedulerTest, TestTaskObserver) {
- MockTaskObserver observer;
- thread_->addTaskObserver(&observer);
- std::unique_ptr<MockTask> task(new MockTask());
-
- {
- testing::InSequence sequence;
- EXPECT_CALL(observer, willProcessTask());
- EXPECT_CALL(*task, run());
- EXPECT_CALL(observer, didProcessTask());
- }
-
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- task.release());
- base::RunLoop().RunUntilIdle();
- thread_->removeTaskObserver(&observer);
-}
-
-TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithOneTask) {
- MockTaskObserver observer;
- thread_->addTaskObserver(&observer);
- std::unique_ptr<MockTask> task(new MockTask());
-
- SetWorkBatchSizeForTesting(kWorkBatchSize);
- {
- testing::InSequence sequence;
- EXPECT_CALL(observer, willProcessTask());
- EXPECT_CALL(*task, run());
- EXPECT_CALL(observer, didProcessTask());
- }
-
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- task.release());
- base::RunLoop().RunUntilIdle();
- thread_->removeTaskObserver(&observer);
-}
-
-TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithTwoTasks) {
- MockTaskObserver observer;
- thread_->addTaskObserver(&observer);
- std::unique_ptr<MockTask> task1(new MockTask());
- std::unique_ptr<MockTask> task2(new MockTask());
-
- SetWorkBatchSizeForTesting(kWorkBatchSize);
- {
- testing::InSequence sequence;
- EXPECT_CALL(observer, willProcessTask());
- EXPECT_CALL(*task1, run());
- EXPECT_CALL(observer, didProcessTask());
-
- EXPECT_CALL(observer, willProcessTask());
- EXPECT_CALL(*task2, run());
- EXPECT_CALL(observer, didProcessTask());
- }
-
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- task1.release());
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- task2.release());
- base::RunLoop().RunUntilIdle();
- thread_->removeTaskObserver(&observer);
-}
-
-TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithThreeTasks) {
- MockTaskObserver observer;
- thread_->addTaskObserver(&observer);
- std::unique_ptr<MockTask> task1(new MockTask());
- std::unique_ptr<MockTask> task2(new MockTask());
- std::unique_ptr<MockTask> task3(new MockTask());
-
- SetWorkBatchSizeForTesting(kWorkBatchSize);
- {
- testing::InSequence sequence;
- EXPECT_CALL(observer, willProcessTask());
- EXPECT_CALL(*task1, run());
- EXPECT_CALL(observer, didProcessTask());
-
- EXPECT_CALL(observer, willProcessTask());
- EXPECT_CALL(*task2, run());
- EXPECT_CALL(observer, didProcessTask());
-
- EXPECT_CALL(observer, willProcessTask());
- EXPECT_CALL(*task3, run());
- EXPECT_CALL(observer, didProcessTask());
- }
-
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- task1.release());
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- task2.release());
- thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- task3.release());
- base::RunLoop().RunUntilIdle();
- thread_->removeTaskObserver(&observer);
-}
-
-class ExitRunLoopTask : public blink::WebTaskRunner::Task {
- public:
- ExitRunLoopTask(base::RunLoop* run_loop) : run_loop_(run_loop) {}
-
- void run() override { run_loop_->Quit(); }
-
- private:
- base::RunLoop* run_loop_;
-};
-
-void EnterRunLoop(base::MessageLoop* message_loop, blink::WebThread* thread) {
- // Note: WebThreads do not support nested run loops, which is why we use a
- // run loop directly.
- base::RunLoop run_loop;
- thread->getWebTaskRunner()->postTask(blink::WebTraceLocation(),
- new ExitRunLoopTask(&run_loop));
- message_loop->SetNestableTasksAllowed(true);
- run_loop.Run();
-}
-
-TEST_F(WebThreadImplForRendererSchedulerTest, TestNestedRunLoop) {
- MockTaskObserver observer;
- thread_->addTaskObserver(&observer);
-
- {
- testing::InSequence sequence;
-
- // One callback for EnterRunLoop.
- EXPECT_CALL(observer, willProcessTask());
-
- // A pair for ExitRunLoopTask.
- EXPECT_CALL(observer, willProcessTask());
- EXPECT_CALL(observer, didProcessTask());
-
- // A final callback for EnterRunLoop.
- EXPECT_CALL(observer, didProcessTask());
- }
-
- message_loop_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&EnterRunLoop, base::Unretained(&message_loop_),
- base::Unretained(thread_.get())));
- base::RunLoop().RunUntilIdle();
- thread_->removeTaskObserver(&observer);
-}
-
-} // namespace scheduler
diff --git a/chromium/components/scheduler/scheduler.gyp b/chromium/components/scheduler/scheduler.gyp
deleted file mode 100644
index 5afb0d9c360..00000000000
--- a/chromium/components/scheduler/scheduler.gyp
+++ /dev/null
@@ -1,68 +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.
-
-{
- 'variables': {
- # This turns on e.g. the filename-based detection of which
- # platforms to include source files on (e.g. files ending in
- # _mac.h or _mac.cc are only compiled on MacOSX).
- 'chromium_code': 1,
- },
- 'includes': [
- 'scheduler.gypi',
- ],
- 'targets': [
- {
- # GN version: //components/scheduler:common
- 'target_name': 'scheduler_common',
- 'type': 'static_library',
- 'include_dirs': [
- '../..',
- ],
- 'sources': [
- '<@(scheduler_common_sources)',
- ],
- },
- {
- # GN version: //components/scheduler:scheduler
- 'target_name': 'scheduler',
- 'type': '<(component)',
- 'dependencies': [
- 'scheduler_common',
- '../../base/base.gyp:base',
- '../../cc/cc.gyp:cc',
- '../../third_party/WebKit/public/blink.gyp:blink',
- '../../ui/gfx/gfx.gyp:gfx',
- ],
- 'include_dirs': [
- '../..',
- ],
- 'defines': [
- 'SCHEDULER_IMPLEMENTATION',
- ],
- # Disable c4267 warnings until we fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- 'sources': [
- '<@(scheduler_sources)',
- ],
- 'export_dependent_settings': [
- '../../third_party/WebKit/public/blink.gyp:blink',
- ],
- },
- {
- # GN version: //components/scheduler:test_support
- 'target_name': 'scheduler_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../../third_party/WebKit/public/blink.gyp:blink',
- ],
- 'include_dirs': [
- '../..',
- ],
- 'sources': [
- '<@(scheduler_test_support_sources)',
- ],
- },
- ],
-}
diff --git a/chromium/components/scheduler/scheduler.gypi b/chromium/components/scheduler/scheduler.gypi
deleted file mode 100644
index dbcfefd96f2..00000000000
--- a/chromium/components/scheduler/scheduler.gypi
+++ /dev/null
@@ -1,104 +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.
-
-{
- 'variables': {
- 'scheduler_common_sources': [
- # Sources list duplicated in GN build.
- 'common/scheduler_switches.cc',
- 'common/scheduler_switches.h',
- ],
- 'scheduler_sources': [
- # Sources list duplicated in GN build.
- 'base/cancelable_closure_holder.cc',
- 'base/cancelable_closure_holder.h',
- 'base/lazy_now.cc',
- 'base/lazy_now.h',
- 'base/real_time_domain.cc',
- 'base/real_time_domain.h',
- 'base/task_queue.h',
- 'base/task_queue_impl.cc',
- 'base/task_queue_impl.h',
- 'base/task_queue_manager.cc',
- 'base/task_queue_manager.h',
- 'base/task_queue_manager_delegate.h',
- 'base/task_queue_selector.cc',
- 'base/task_queue_selector.h',
- 'base/time_domain.cc',
- 'base/time_domain.h',
- 'base/work_queue.cc',
- 'base/work_queue.h',
- 'base/work_queue_sets.cc',
- 'base/work_queue_sets.h',
- 'base/pollable_thread_safe_flag.cc',
- 'base/pollable_thread_safe_flag.h',
- 'base/virtual_time_domain.cc',
- 'base/virtual_time_domain.h',
- 'base/enqueue_order.h',
- 'base/enqueue_order.cc',
- 'child/child_scheduler.h',
- 'child/compositor_worker_scheduler.cc',
- 'child/compositor_worker_scheduler.h',
- 'child/idle_helper.cc',
- 'child/idle_helper.h',
- 'child/scheduler_helper.cc',
- 'child/scheduler_helper.h',
- 'child/scheduler_tqm_delegate.h',
- 'child/scheduler_tqm_delegate_impl.cc',
- 'child/scheduler_tqm_delegate_impl.h',
- 'child/single_thread_idle_task_runner.cc',
- 'child/single_thread_idle_task_runner.h',
- 'child/web_scheduler_impl.cc',
- 'child/web_scheduler_impl.h',
- 'child/web_task_runner_impl.cc',
- 'child/web_task_runner_impl.h',
- 'child/webthread_base.cc',
- 'child/webthread_base.h',
- 'child/webthread_impl_for_worker_scheduler.cc',
- 'child/webthread_impl_for_worker_scheduler.h',
- 'child/worker_scheduler.cc',
- 'child/worker_scheduler.h',
- 'child/worker_scheduler_impl.cc',
- 'child/worker_scheduler_impl.h',
- 'renderer/auto_advancing_virtual_time_domain.cc',
- 'renderer/auto_advancing_virtual_time_domain.h',
- 'renderer/deadline_task_runner.cc',
- 'renderer/deadline_task_runner.h',
- 'renderer/idle_time_estimator.cc',
- 'renderer/idle_time_estimator.h',
- 'renderer/renderer_scheduler.cc',
- 'renderer/renderer_scheduler.h',
- 'renderer/renderer_scheduler_impl.cc',
- 'renderer/renderer_scheduler_impl.h',
- 'renderer/renderer_web_scheduler_impl.cc',
- 'renderer/renderer_web_scheduler_impl.h',
- 'renderer/render_widget_scheduling_state.cc',
- 'renderer/render_widget_scheduling_state.h',
- 'renderer/render_widget_signals.cc',
- 'renderer/render_widget_signals.h',
- 'renderer/task_cost_estimator.cc',
- 'renderer/task_cost_estimator.h',
- 'renderer/throttled_time_domain.cc',
- 'renderer/throttled_time_domain.h',
- 'renderer/throttling_helper.cc',
- 'renderer/throttling_helper.h',
- 'renderer/web_frame_scheduler_impl.cc',
- 'renderer/web_frame_scheduler_impl.h',
- 'renderer/web_view_scheduler_impl.cc',
- 'renderer/web_view_scheduler_impl.h',
- 'renderer/user_model.cc',
- 'renderer/user_model.h',
- 'renderer/webthread_impl_for_renderer_scheduler.cc',
- 'renderer/webthread_impl_for_renderer_scheduler.h',
- 'scheduler_export.h',
- ],
- 'scheduler_test_support_sources': [
- # Sources list duplicated in GN build.
- 'test/lazy_scheduler_message_loop_delegate_for_tests.cc',
- 'test/lazy_scheduler_message_loop_delegate_for_tests.h',
- 'test/renderer_scheduler_test_support.h',
- 'test/renderer_scheduler_test_support.cc',
- ],
- },
-}
diff --git a/chromium/components/scheduler/scheduler_export.h b/chromium/components/scheduler/scheduler_export.h
deleted file mode 100644
index b441b84800b..00000000000
--- a/chromium/components/scheduler/scheduler_export.h
+++ /dev/null
@@ -1,29 +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 COMPONENTS_SCHEDULER_SCHEDULER_EXPORT_H_
-#define COMPONENTS_SCHEDULER_SCHEDULER_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(SCHEDULER_IMPLEMENTATION)
-#define SCHEDULER_EXPORT __declspec(dllexport)
-#else
-#define SCHEDULER_EXPORT __declspec(dllimport)
-#endif // defined(SCHEDULER_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(SCHEDULER_IMPLEMENTATION)
-#define SCHEDULER_EXPORT __attribute__((visibility("default")))
-#else
-#define SCHEDULER_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define SCHEDULER_EXPORT
-#endif
-
-#endif // COMPONENTS_SCHEDULER_SCHEDULER_EXPORT_H_
diff --git a/chromium/components/search.gypi b/chromium/components/search.gypi
deleted file mode 100644
index 5c79aa708e3..00000000000
--- a/chromium/components/search.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'search',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../url/url.gyp:url_lib',
- 'google_core_browser',
- 'search_engines',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'search/search.cc',
- 'search/search.h',
- 'search/search_switches.cc',
- 'search/search_switches.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/search/BUILD.gn b/chromium/components/search/BUILD.gn
index 50c908df5eb..cc2f790d51f 100644
--- a/chromium/components/search/BUILD.gn
+++ b/chromium/components/search/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("search") {
+static_library("search") {
sources = [
"search.cc",
"search.h",
diff --git a/chromium/components/search/search.cc b/chromium/components/search/search.cc
index cbc95523552..97cdacb9856 100644
--- a/chromium/components/search/search.cc
+++ b/chromium/components/search/search.cc
@@ -55,12 +55,6 @@ const char kEmbeddedSearchFieldTrialName[] = "EmbeddedSearch";
// be ignored and Instant Extended will not be enabled by default.
const char kDisablingSuffix[] = "DISABLED";
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
-const char kEnableQueryExtractionFlagName[] = "query_extraction";
-#endif
-
-const char kAllowPrefetchNonDefaultMatch[] = "allow_prefetch_non_default_match";
-
#if defined(OS_ANDROID)
const char kPrefetchSearchResultsFlagName[] = "prefetch_results";
@@ -165,7 +159,8 @@ bool GetBoolValueForFlagWithDefault(const std::string& flag,
}
std::string InstantExtendedEnabledParam(bool for_search) {
- if (for_search && !IsQueryExtractionEnabled())
+ // TODO(treib): Remove |for_search| and update callers that set it to true.
+ if (for_search)
return std::string();
return std::string(google_util::kInstantExtendedAPIParam) + "=" +
base::Uint64ToString(EmbeddedSearchPageVersion()) + "&";
@@ -176,25 +171,6 @@ std::string ForceInstantResultsParam(bool for_prerender) {
: std::string();
}
-bool IsQueryExtractionEnabled() {
-#if defined(OS_IOS) || defined(OS_ANDROID)
- return false;
-#else
- if (!IsInstantExtendedAPIEnabled())
- return false;
-
- const base::CommandLine* command_line =
- base::CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kEnableQueryExtraction))
- return true;
-
- FieldTrialFlags flags;
- return GetFieldTrialInfo(&flags) &&
- GetBoolValueForFlagWithDefault(kEnableQueryExtractionFlagName, false,
- flags);
-#endif // defined(OS_IOS) || defined(OS_ANDROID)
-}
-
bool ShouldPrefetchSearchResults() {
if (!IsInstantExtendedAPIEnabled())
return false;
@@ -228,16 +204,6 @@ bool ShouldReuseInstantSearchBasePage() {
#endif
}
-bool ShouldAllowPrefetchNonDefaultMatch() {
- if (!ShouldPrefetchSearchResults())
- return false;
-
- FieldTrialFlags flags;
- return GetFieldTrialInfo(&flags) &&
- GetBoolValueForFlagWithDefault(kAllowPrefetchNonDefaultMatch, false,
- flags);
-}
-
// |url| should either have a secure scheme or have a non-HTTPS base URL that
// the user specified using --google-base-url. (This allows testers to use
// --google-base-url to point at non-HTTPS servers, which eases testing.)
@@ -247,11 +213,4 @@ bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url) {
google_util::StartsWithCommandLineGoogleBaseURL(url));
}
-void EnableQueryExtractionForTesting() {
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
- base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
- cl->AppendSwitch(switches::kEnableQueryExtraction);
-#endif
-}
-
} // namespace search
diff --git a/chromium/components/search/search.h b/chromium/components/search/search.h
index d97b240be0b..a8b21a472bd 100644
--- a/chromium/components/search/search.h
+++ b/chromium/components/search/search.h
@@ -77,9 +77,6 @@ std::string InstantExtendedEnabledParam(bool for_search);
// the returned string to be non-empty.
std::string ForceInstantResultsParam(bool for_prerender);
-// Returns whether query extraction is enabled.
-bool IsQueryExtractionEnabled();
-
// Returns true if 'prefetch_results' flag is set to true in field trials to
// prefetch high-confidence search suggestions.
bool ShouldPrefetchSearchResults();
@@ -88,23 +85,11 @@ bool ShouldPrefetchSearchResults();
// trials to reuse the prerendered page to commit any search query.
bool ShouldReuseInstantSearchBasePage();
-// Returns true if 'allow_prefetch_non_default_match' flag is enabled in field
-// trials to allow prefetching the suggestion marked to be prefetched by the
-// suggest server even if it is not the default match.
-bool ShouldAllowPrefetchNonDefaultMatch();
-
// |url| should either have a secure scheme or have a non-HTTPS base URL that
// the user specified using --google-base-url. (This allows testers to use
// --google-base-url to point at non-HTTPS servers, which eases testing.)
bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url);
-// -----------------------------------------------------
-// The following APIs are exposed for use in tests only.
-// -----------------------------------------------------
-
-// Forces query in the omnibox to be on for tests.
-void EnableQueryExtractionForTesting();
-
} // namespace search
#endif // COMPONENTS_SEARCH_SEARCH_H_
diff --git a/chromium/components/search/search_android_unittest.cc b/chromium/components/search/search_android_unittest.cc
index 063ec1a6f21..387975f3014 100644
--- a/chromium/components/search/search_android_unittest.cc
+++ b/chromium/components/search/search_android_unittest.cc
@@ -5,11 +5,8 @@
#include "components/search/search.h"
#include "base/command_line.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/statistics_recorder.h"
#include "components/search/search.h"
#include "components/search/search_switches.h"
-#include "components/variations/entropy_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace search {
@@ -25,11 +22,6 @@ TEST(SearchTest, EmbeddedSearchAPIEnabled) {
EXPECT_TRUE(IsInstantExtendedAPIEnabled());
}
-TEST(SearchTest, QueryExtractionEnabled) {
- // Query extraction is disabled on mobile.
- EXPECT_FALSE(IsQueryExtractionEnabled());
-}
-
} // namespace
} // namespace chrome
diff --git a/chromium/components/search/search_switches.cc b/chromium/components/search/search_switches.cc
index 6d4b47d31a2..b8026033f9f 100644
--- a/chromium/components/search/search_switches.cc
+++ b/chromium/components/search/search_switches.cc
@@ -18,11 +18,4 @@ const char kPrefetchSearchResults[] = "prefetch-search-results";
#endif
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
-
-// Enables query in the omnibox.
-const char kEnableQueryExtraction[] = "enable-query-extraction";
-
-#endif
-
} // namespace switches
diff --git a/chromium/components/search/search_switches.h b/chromium/components/search/search_switches.h
index 46208e0711e..ada2e1727b2 100644
--- a/chromium/components/search/search_switches.h
+++ b/chromium/components/search/search_switches.h
@@ -14,10 +14,6 @@ extern const char kEnableEmbeddedSearchAPI[];
extern const char kPrefetchSearchResults[];
#endif
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
-extern const char kEnableQueryExtraction[];
-#endif
-
} // namespace switches
#endif // COMPONENTS_SEARCH_SEARCH_SWITCHES_H_
diff --git a/chromium/components/search/search_unittest.cc b/chromium/components/search/search_unittest.cc
index 622ecd54c00..d5adaa47b14 100644
--- a/chromium/components/search/search_unittest.cc
+++ b/chromium/components/search/search_unittest.cc
@@ -6,6 +6,7 @@
#include <memory>
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/statistics_recorder.h"
#include "build/build_config.h"
@@ -18,7 +19,7 @@ class EmbeddedSearchFieldTrialTest : public testing::Test {
protected:
void SetUp() override {
field_trial_list_.reset(new base::FieldTrialList(
- new metrics::SHA1EntropyProvider("42")));
+ base::MakeUnique<metrics::SHA1EntropyProvider>("42")));
base::StatisticsRecorder::Initialize();
}
@@ -151,20 +152,6 @@ TEST_F(SearchTest, ShouldReuseInstantSearchBasePage_Default) {
EXPECT_TRUE(ShouldReuseInstantSearchBasePage());
}
-TEST_F(SearchTest, ShouldAllowPrefetchNonDefaultMatch_DisabledViaFieldTrial) {
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Group1 espv:89 allow_prefetch_non_default_match:0"));
- EXPECT_FALSE(ShouldAllowPrefetchNonDefaultMatch());
- EXPECT_EQ(89ul, EmbeddedSearchPageVersion());
-}
-
-TEST_F(SearchTest, ShouldAllowPrefetchNonDefaultMatch_EnabledViaFieldTrial) {
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Group1 espv:80 allow_prefetch_non_default_match:1"));
- EXPECT_TRUE(ShouldAllowPrefetchNonDefaultMatch());
- EXPECT_EQ(80ul, EmbeddedSearchPageVersion());
-}
-
TEST_F(SearchTest, ForceInstantResultsParam) {
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
"Group1 espv:2"));
@@ -180,63 +167,17 @@ TEST_F(InstantExtendedEnabledParamTest, QueryExtractionDisabled) {
"Group1 espv:12"));
// Make sure InstantExtendedEnabledParam() returns an empty string for search
// requests.
- EXPECT_FALSE(IsQueryExtractionEnabled());
EXPECT_EQ("", InstantExtendedEnabledParam(true));
EXPECT_EQ("espv=12&", InstantExtendedEnabledParam(false));
}
-TEST_F(InstantExtendedEnabledParamTest, QueryExtractionEnabled) {
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Group1 espv:10 query_extraction:1"));
- EXPECT_TRUE(IsQueryExtractionEnabled());
- // Make sure InstantExtendedEnabledParam() returns a non-empty param string
- // for search requests.
- EXPECT_EQ("espv=10&", InstantExtendedEnabledParam(true));
- EXPECT_EQ("espv=10&", InstantExtendedEnabledParam(false));
-}
-
TEST_F(InstantExtendedEnabledParamTest, UseDefaultEmbeddedSearchPageVersion) {
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Group1 espv:-1 query_extraction:1"));
- EXPECT_TRUE(IsQueryExtractionEnabled());
- EXPECT_EQ("espv=2&", InstantExtendedEnabledParam(true));
+ "EmbeddedSearch", "Group1 espv:-1"));
+ EXPECT_EQ("", InstantExtendedEnabledParam(true));
EXPECT_EQ("espv=2&", InstantExtendedEnabledParam(false));
}
-typedef EmbeddedSearchFieldTrialTest IsQueryExtractionEnabledTest;
-
-TEST_F(IsQueryExtractionEnabledTest, NotSet) {
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
- "Group1 espv:2"));
- EXPECT_TRUE(IsInstantExtendedAPIEnabled());
- EXPECT_FALSE(IsQueryExtractionEnabled());
- EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
-}
-
-TEST_F(IsQueryExtractionEnabledTest, EnabledViaFieldTrial) {
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Group1 espv:2 query_extraction:1"));
- EXPECT_TRUE(IsInstantExtendedAPIEnabled());
- EXPECT_TRUE(IsQueryExtractionEnabled());
- EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
-}
-
-TEST_F(IsQueryExtractionEnabledTest, DisabledViaFieldTrial) {
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Group1 espv:2 query_extraction:0"));
- EXPECT_TRUE(IsInstantExtendedAPIEnabled());
- EXPECT_FALSE(IsQueryExtractionEnabled());
- EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
-}
-
-TEST_F(IsQueryExtractionEnabledTest, EnabledViaCommandLine) {
- EnableQueryExtractionForTesting();
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "EmbeddedSearch", "Group1 espv:2 query_extraction:0"));
- EXPECT_TRUE(IsInstantExtendedAPIEnabled());
- EXPECT_TRUE(IsQueryExtractionEnabled());
- EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
-}
#endif // !defined(OS_IOS) && !defined(OS_ANDROID)
} // namespace search
diff --git a/chromium/components/search_engines.gypi b/chromium/components/search_engines.gypi
deleted file mode 100644
index 1e1a5ceee9b..00000000000
--- a/chromium/components/search_engines.gypi
+++ /dev/null
@@ -1,113 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/search_engines
- 'target_name': 'search_engines',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../sql/sql.gyp:sql',
- '../sync/sync.gyp:sync',
- '../third_party/libxml/libxml.gyp:libxml',
- '../ui/gfx/gfx.gyp:gfx',
- '../url/url.gyp:url_lib',
- 'component_metrics_proto',
- 'components_strings.gyp:components_strings',
- 'components.gyp:infobars_core',
- 'google_core_browser',
- 'history_core_browser',
- 'keyed_service_core',
- 'policy',
- 'pref_registry',
- 'prefs/prefs.gyp:prefs',
- 'rappor',
- 'search_engines/prepopulated_engines.gyp:prepopulated_engines',
- 'sync_driver',
- 'url_formatter/url_formatter.gyp:url_formatter',
- 'webdata_common',
- ],
- 'export_dependent_settings': [
- 'component_metrics_proto',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'search_engines/default_search_manager.cc',
- 'search_engines/default_search_manager.h',
- 'search_engines/default_search_policy_handler.cc',
- 'search_engines/default_search_policy_handler.h',
- 'search_engines/default_search_pref_migration.cc',
- 'search_engines/default_search_pref_migration.h',
- 'search_engines/keyword_table.cc',
- 'search_engines/keyword_table.h',
- 'search_engines/keyword_web_data_service.cc',
- 'search_engines/keyword_web_data_service.h',
- 'search_engines/search_engine_data_type_controller.cc',
- 'search_engines/search_engine_data_type_controller.h',
- 'search_engines/search_engine_type.h',
- 'search_engines/search_engines_pref_names.cc',
- 'search_engines/search_engines_pref_names.h',
- 'search_engines/search_engines_switches.cc',
- 'search_engines/search_engines_switches.h',
- 'search_engines/search_host_to_urls_map.cc',
- 'search_engines/search_host_to_urls_map.h',
- 'search_engines/search_terms_data.cc',
- 'search_engines/search_terms_data.h',
- 'search_engines/template_url.cc',
- 'search_engines/template_url.h',
- 'search_engines/template_url_data.cc',
- 'search_engines/template_url_data.h',
- 'search_engines/template_url_fetcher.cc',
- 'search_engines/template_url_fetcher.h',
- 'search_engines/template_url_id.h',
- 'search_engines/template_url_parser.cc',
- 'search_engines/template_url_parser.h',
- 'search_engines/template_url_prepopulate_data.cc',
- 'search_engines/template_url_prepopulate_data.h',
- 'search_engines/template_url_service.cc',
- 'search_engines/template_url_service.h',
- 'search_engines/template_url_service_client.h',
- 'search_engines/template_url_service_observer.h',
- 'search_engines/util.cc',
- 'search_engines/util.h',
- ],
- 'conditions': [
- ['configuration_policy==0', {
- 'dependencies!': [
- 'policy'
- ],
- 'sources!': [
- 'search_engines/default_search_policy_handler.cc',
- 'search_engines/default_search_policy_handler.h',
- ],
- }],
- ],
- },
- {
- # GN version: //components/search_engines:test_support
- 'target_name': 'search_engines_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../testing/gtest.gyp:gtest',
- 'search_engines',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'search_engines/default_search_pref_test_util.cc',
- 'search_engines/default_search_pref_test_util.h',
- 'search_engines/testing_search_terms_data.cc',
- 'search_engines/testing_search_terms_data.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/search_engines/BUILD.gn b/chromium/components/search_engines/BUILD.gn
index b4779bccdf1..9281c378963 100644
--- a/chromium/components/search_engines/BUILD.gn
+++ b/chromium/components/search_engines/BUILD.gn
@@ -68,13 +68,12 @@ static_library("search_engines") {
"//components/prefs",
"//components/rappor",
"//components/strings",
- "//components/sync_driver",
+ "//components/sync",
"//components/url_formatter",
"//components/webdata/common",
"//google_apis",
"//net",
"//sql",
- "//sync",
"//third_party/libxml",
"//ui/base",
"//ui/gfx",
@@ -88,13 +87,13 @@ static_library("search_engines") {
"default_search_policy_handler.h",
]
deps += [
- "//components/policy",
- "//components/policy:policy_component",
+ "//components/policy:generated",
+ "//components/policy/core/browser",
]
}
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"default_search_pref_test_util.cc",
@@ -127,14 +126,15 @@ source_set("unit_tests") {
":prepopulated_engines",
":test_support",
"//base",
+ "//base/test:test_support",
"//components/google/core/browser",
"//components/pref_registry:test_support",
"//components/prefs",
- "//components/sync_driver:test_support",
+ "//components/sync:test_support_sync_api",
+ "//components/sync:test_support_sync_driver",
"//components/syncable_prefs:test_support",
"//components/webdata/common",
"//sql",
- "//sync:test_support_sync_api",
"//testing/gmock",
"//testing/gtest",
"//url",
@@ -144,8 +144,8 @@ source_set("unit_tests") {
sources += [ "default_search_policy_handler_unittest.cc" ]
deps += [
- "//components/policy",
- "//components/policy:policy_component_test_support",
+ "//components/policy:generated",
+ "//components/policy/core/browser:test_support",
]
}
}
diff --git a/chromium/components/search_engines/DEPS b/chromium/components/search_engines/DEPS
index 6ed289ae24f..7c626caf8a3 100644
--- a/chromium/components/search_engines/DEPS
+++ b/chromium/components/search_engines/DEPS
@@ -6,11 +6,11 @@ include_rules = [
"+components/metrics/proto",
# TODO(mpearson): for experiment; remove after crbug.com/488901 is launched.
"+components/omnibox/browser/omnibox_field_trial.h",
- "+components/policy/core",
+ "+components/policy",
"+components/pref_registry",
"+components/prefs",
"+components/rappor",
- "+components/sync_driver",
+ "+components/sync",
"+components/syncable_prefs/testing_pref_service_syncable.h",
"+components/url_formatter",
"+components/webdata",
@@ -18,9 +18,7 @@ include_rules = [
"+grit/components_strings.h",
"+libxml",
"+net",
- "+policy",
"+sql",
- "+sync",
"+ui/base",
"+ui/gfx",
]
diff --git a/chromium/components/search_engines/default_search_manager.cc b/chromium/components/search_engines/default_search_manager.cc
index 966a721f17e..42b29d29ee7 100644
--- a/chromium/components/search_engines/default_search_manager.cc
+++ b/chromium/components/search_engines/default_search_manager.cc
@@ -15,7 +15,6 @@
#include "base/compiler_specific.h"
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -263,27 +262,26 @@ void DefaultSearchManager::MergePrefsDataWithPrepopulated() {
return;
size_t default_search_index;
- ScopedVector<TemplateURLData> prepopulated_urls =
+ std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
TemplateURLPrepopulateData::GetPrepopulatedEngines(pref_service_,
&default_search_index);
- for (size_t i = 0; i < prepopulated_urls.size(); ++i) {
- if (prepopulated_urls[i]->prepopulate_id ==
- prefs_default_search_->prepopulate_id) {
- if (!prefs_default_search_->safe_for_autoreplace) {
- prepopulated_urls[i]->safe_for_autoreplace = false;
- prepopulated_urls[i]->SetKeyword(prefs_default_search_->keyword());
- prepopulated_urls[i]->SetShortName(prefs_default_search_->short_name());
- }
- prepopulated_urls[i]->id = prefs_default_search_->id;
- prepopulated_urls[i]->sync_guid = prefs_default_search_->sync_guid;
- prepopulated_urls[i]->date_created = prefs_default_search_->date_created;
- prepopulated_urls[i]->last_modified =
- prefs_default_search_->last_modified;
- prefs_default_search_.reset(prepopulated_urls[i]);
- prepopulated_urls.weak_erase(prepopulated_urls.begin() + i);
- return;
+ for (auto& engine : prepopulated_urls) {
+ if (engine->prepopulate_id != prefs_default_search_->prepopulate_id)
+ continue;
+
+ if (!prefs_default_search_->safe_for_autoreplace) {
+ engine->safe_for_autoreplace = false;
+ engine->SetKeyword(prefs_default_search_->keyword());
+ engine->SetShortName(prefs_default_search_->short_name());
}
+ engine->id = prefs_default_search_->id;
+ engine->sync_guid = prefs_default_search_->sync_guid;
+ engine->date_created = prefs_default_search_->date_created;
+ engine->last_modified = prefs_default_search_->last_modified;
+
+ prefs_default_search_ = std::move(engine);
+ return;
}
}
diff --git a/chromium/components/search_engines/default_search_manager_unittest.cc b/chromium/components/search_engines/default_search_manager_unittest.cc
index 682b7144979..a8df14e94ba 100644
--- a/chromium/components/search_engines/default_search_manager_unittest.cc
+++ b/chromium/components/search_engines/default_search_manager_unittest.cc
@@ -67,19 +67,19 @@ void SetOverrides(user_prefs::TestingPrefServiceSyncable* prefs, bool update) {
alternate_urls->AppendString("http://foo.com/alternate?q={searchTerms}");
entry->Set("alternate_urls", alternate_urls);
entry->SetString("search_terms_replacement_key", "espv");
- overrides->Append(entry->DeepCopy());
+ overrides->Append(entry->CreateDeepCopy());
entry.reset(new base::DictionaryValue);
entry->SetInteger("id", 1002);
entry->SetString("name", update ? "new_bar" : "bar");
entry->SetString("keyword", update ? "new_bark" : "bark");
entry->SetString("encoding", std::string());
- overrides->Append(entry->DeepCopy());
+ overrides->Append(entry->CreateDeepCopy());
entry->SetInteger("id", 1003);
entry->SetString("name", "baz");
entry->SetString("keyword", "bazk");
entry->SetString("encoding", "UTF-8");
- overrides->Append(entry->DeepCopy());
+ overrides->Append(entry->CreateDeepCopy());
prefs->SetUserPref(prefs::kSearchProviderOverrides, overrides);
}
@@ -192,12 +192,12 @@ TEST_F(DefaultSearchManagerTest, DefaultSearchSetByUserPref) {
size_t default_search_index = 0;
DefaultSearchManager manager(pref_service(),
DefaultSearchManager::ObserverCallback());
- ScopedVector<TemplateURLData> prepopulated_urls =
+ std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
TemplateURLPrepopulateData::GetPrepopulatedEngines(pref_service(),
&default_search_index);
DefaultSearchManager::Source source = DefaultSearchManager::FROM_POLICY;
// If no user pref is set, we should use the pre-populated values.
- ExpectSimilar(prepopulated_urls[default_search_index],
+ ExpectSimilar(prepopulated_urls[default_search_index].get(),
manager.GetDefaultSearchEngine(&source));
EXPECT_EQ(DefaultSearchManager::FROM_FALLBACK, source);
@@ -222,7 +222,7 @@ TEST_F(DefaultSearchManagerTest, DefaultSearchSetByUserPref) {
// Clearing the user pref should cause the default search to revert to the
// prepopulated vlaues.
manager.ClearUserSelectedDefaultSearchEngine();
- ExpectSimilar(prepopulated_urls[default_search_index],
+ ExpectSimilar(prepopulated_urls[default_search_index].get(),
manager.GetDefaultSearchEngine(&source));
EXPECT_EQ(DefaultSearchManager::FROM_FALLBACK, source);
}
@@ -233,13 +233,13 @@ TEST_F(DefaultSearchManagerTest, DefaultSearchSetByOverrides) {
size_t default_search_index = 0;
DefaultSearchManager manager(pref_service(),
DefaultSearchManager::ObserverCallback());
- ScopedVector<TemplateURLData> prepopulated_urls =
+ std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
TemplateURLPrepopulateData::GetPrepopulatedEngines(pref_service(),
&default_search_index);
DefaultSearchManager::Source source = DefaultSearchManager::FROM_POLICY;
TemplateURLData first_default(*manager.GetDefaultSearchEngine(&source));
- ExpectSimilar(prepopulated_urls[default_search_index], &first_default);
+ ExpectSimilar(prepopulated_urls[default_search_index].get(), &first_default);
EXPECT_EQ(DefaultSearchManager::FROM_FALLBACK, source);
// Update the overrides:
@@ -248,7 +248,7 @@ TEST_F(DefaultSearchManagerTest, DefaultSearchSetByOverrides) {
pref_service(), &default_search_index);
// Make sure DefaultSearchManager updated:
- ExpectSimilar(prepopulated_urls[default_search_index],
+ ExpectSimilar(prepopulated_urls[default_search_index].get(),
manager.GetDefaultSearchEngine(&source));
EXPECT_EQ(DefaultSearchManager::FROM_FALLBACK, source);
EXPECT_NE(manager.GetDefaultSearchEngine(NULL)->short_name(),
diff --git a/chromium/components/search_engines/default_search_policy_handler.cc b/chromium/components/search_engines/default_search_policy_handler.cc
index 341f7f00e1c..7c742da5903 100644
--- a/chromium/components/search_engines/default_search_policy_handler.cc
+++ b/chromium/components/search_engines/default_search_policy_handler.cc
@@ -10,18 +10,17 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "components/policy/core/browser/policy_error_map.h"
#include "components/policy/core/common/policy_map.h"
+#include "components/policy/policy_constants.h"
#include "components/prefs/pref_value_map.h"
#include "components/search_engines/default_search_manager.h"
#include "components/search_engines/search_engines_pref_names.h"
#include "components/search_engines/search_terms_data.h"
#include "components/search_engines/template_url.h"
#include "grit/components_strings.h"
-#include "policy/policy_constants.h"
namespace policy {
@@ -186,19 +185,17 @@ DefaultSearchPolicyHandler::DefaultSearchPolicyHandler() {
for (size_t i = 0; i < arraysize(kDefaultSearchPolicyMap); ++i) {
const char* policy_name = kDefaultSearchPolicyMap[i].policy_name;
if (policy_name == key::kDefaultSearchProviderEncodings) {
- handlers_.push_back(new DefaultSearchEncodingsPolicyHandler());
+ handlers_.push_back(
+ base::MakeUnique<DefaultSearchEncodingsPolicyHandler>());
} else {
- handlers_.push_back(new SimplePolicyHandler(
- policy_name,
- kDefaultSearchPolicyMap[i].preference_path,
+ handlers_.push_back(base::MakeUnique<SimplePolicyHandler>(
+ policy_name, kDefaultSearchPolicyMap[i].preference_path,
kDefaultSearchPolicyMap[i].value_type));
}
}
}
-DefaultSearchPolicyHandler::~DefaultSearchPolicyHandler() {
- STLDeleteElements(&handlers_);
-}
+DefaultSearchPolicyHandler::~DefaultSearchPolicyHandler() {}
bool DefaultSearchPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
PolicyErrorMap* errors) {
@@ -209,10 +206,8 @@ bool DefaultSearchPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
// Add an error for all specified default search policies except
// DefaultSearchProviderEnabled.
- for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
- handlers_.begin();
- handler != handlers_.end(); ++handler) {
- const char* policy_name = (*handler)->policy_name();
+ for (const auto& handler : handlers_) {
+ const char* policy_name = handler->policy_name();
if (policy_name != key::kDefaultSearchProviderEnabled &&
HasDefaultSearchPolicy(policies, policy_name)) {
errors->AddError(policy_name, IDS_POLICY_DEFAULT_SEARCH_DISABLED);
@@ -306,13 +301,13 @@ void DefaultSearchPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
bool DefaultSearchPolicyHandler::CheckIndividualPolicies(
const PolicyMap& policies,
PolicyErrorMap* errors) {
- for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
- handlers_.begin();
- handler != handlers_.end(); ++handler) {
- if (!(*handler)->CheckPolicySettings(policies, errors))
- return false;
+ bool all_ok = true;
+ for (const auto& handler : handlers_) {
+ // It's important to call CheckPolicySettings() on all handlers and not just
+ // exit on the first error, so we report all policy errors.
+ all_ok &= handler->CheckPolicySettings(policies, errors);
}
- return true;
+ return all_ok;
}
bool DefaultSearchPolicyHandler::HasDefaultSearchPolicy(
@@ -323,10 +318,8 @@ bool DefaultSearchPolicyHandler::HasDefaultSearchPolicy(
bool DefaultSearchPolicyHandler::AnyDefaultSearchPoliciesSpecified(
const PolicyMap& policies) {
- for (std::vector<TypeCheckingPolicyHandler*>::const_iterator handler =
- handlers_.begin();
- handler != handlers_.end(); ++handler) {
- if (policies.Get((*handler)->policy_name()))
+ for (const auto& handler : handlers_) {
+ if (policies.Get(handler->policy_name()))
return true;
}
return false;
@@ -369,7 +362,7 @@ void DefaultSearchPolicyHandler::EnsureListPrefExists(
base::Value* value;
base::ListValue* list_value;
if (!prefs->GetValue(path, &value) || !value->GetAsList(&list_value))
- prefs->SetValue(path, base::WrapUnique(new base::ListValue()));
+ prefs->SetValue(path, base::MakeUnique<base::ListValue>());
}
} // namespace policy
diff --git a/chromium/components/search_engines/default_search_policy_handler.h b/chromium/components/search_engines/default_search_policy_handler.h
index e406ca22578..499d5a4f0bc 100644
--- a/chromium/components/search_engines/default_search_policy_handler.h
+++ b/chromium/components/search_engines/default_search_policy_handler.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_SEARCH_ENGINES_DEFAULT_SEARCH_POLICY_HANDLER_H_
#define COMPONENTS_SEARCH_ENGINES_DEFAULT_SEARCH_POLICY_HANDLER_H_
+#include <memory>
#include <vector>
#include "base/macros.h"
@@ -70,7 +71,7 @@ class DefaultSearchPolicyHandler : public ConfigurationPolicyHandler {
void EnsureListPrefExists(PrefValueMap* prefs, const std::string& path);
// The ConfigurationPolicyHandler handlers for each default search policy.
- std::vector<TypeCheckingPolicyHandler*> handlers_;
+ std::vector<std::unique_ptr<TypeCheckingPolicyHandler>> handlers_;
DISALLOW_COPY_AND_ASSIGN(DefaultSearchPolicyHandler);
};
diff --git a/chromium/components/search_engines/default_search_policy_handler_unittest.cc b/chromium/components/search_engines/default_search_policy_handler_unittest.cc
index 6cdbf02f86c..fece4e7a298 100644
--- a/chromium/components/search_engines/default_search_policy_handler_unittest.cc
+++ b/chromium/components/search_engines/default_search_policy_handler_unittest.cc
@@ -10,9 +10,9 @@
#include "components/policy/core/browser/configuration_policy_pref_store.h"
#include "components/policy/core/browser/configuration_policy_pref_store_test.h"
#include "components/policy/core/common/policy_types.h"
+#include "components/policy/policy_constants.h"
#include "components/search_engines/default_search_manager.h"
#include "components/search_engines/search_engines_pref_names.h"
-#include "policy/policy_constants.h"
namespace {
// TODO(caitkp): Should we find a way to route this through DefaultSearchManager
@@ -88,22 +88,22 @@ void DefaultSearchPolicyHandlerTest::
encodings->AppendString("UTF-8");
policy->Set(key::kDefaultSearchProviderEnabled, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::FundamentalValue(true)), nullptr);
+ base::MakeUnique<base::FundamentalValue>(true), nullptr);
policy->Set(key::kDefaultSearchProviderSearchURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kSearchURL)), nullptr);
+ base::MakeUnique<base::StringValue>(kSearchURL), nullptr);
policy->Set(key::kDefaultSearchProviderName, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kName)), nullptr);
+ base::MakeUnique<base::StringValue>(kName), nullptr);
policy->Set(key::kDefaultSearchProviderKeyword, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kKeyword)), nullptr);
+ base::MakeUnique<base::StringValue>(kKeyword), nullptr);
policy->Set(key::kDefaultSearchProviderSuggestURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kSuggestURL)), nullptr);
+ base::MakeUnique<base::StringValue>(kSuggestURL), nullptr);
policy->Set(key::kDefaultSearchProviderIconURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kIconURL)), nullptr);
+ base::MakeUnique<base::StringValue>(kIconURL), nullptr);
policy->Set(key::kDefaultSearchProviderEncodings, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
base::WrapUnique(encodings), nullptr);
@@ -112,17 +112,16 @@ void DefaultSearchPolicyHandlerTest::
default_alternate_urls_.CreateDeepCopy(), nullptr);
policy->Set(key::kDefaultSearchProviderSearchTermsReplacementKey,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kReplacementKey)),
- nullptr);
+ base::MakeUnique<base::StringValue>(kReplacementKey), nullptr);
policy->Set(key::kDefaultSearchProviderImageURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kImageURL)), nullptr);
+ base::MakeUnique<base::StringValue>(kImageURL), nullptr);
policy->Set(key::kDefaultSearchProviderImageURLPostParams,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kImageParams)), nullptr);
+ base::MakeUnique<base::StringValue>(kImageParams), nullptr);
policy->Set(key::kDefaultSearchProviderNewTabURL, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
- base::WrapUnique(new base::StringValue(kNewTabURL)), nullptr);
+ base::MakeUnique<base::StringValue>(kNewTabURL), nullptr);
}
// Checks that if the default search policy is missing, that no elements of the
diff --git a/chromium/components/search_engines/default_search_pref_migration.cc b/chromium/components/search_engines/default_search_pref_migration.cc
index 4753a04ec31..5912275f3b7 100644
--- a/chromium/components/search_engines/default_search_pref_migration.cc
+++ b/chromium/components/search_engines/default_search_pref_migration.cc
@@ -12,7 +12,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/search_engines/default_search_pref_migration_unittest.cc b/chromium/components/search_engines/default_search_pref_migration_unittest.cc
index 41cb14eea58..5de070b2910 100644
--- a/chromium/components/search_engines/default_search_pref_migration_unittest.cc
+++ b/chromium/components/search_engines/default_search_pref_migration_unittest.cc
@@ -79,7 +79,7 @@ void DefaultSearchPrefMigrationTest::SaveDefaultSearchProviderToLegacyPrefs(
base::ListValue alternate_urls;
std::string search_terms_replacement_key;
if (t_url) {
- DCHECK_EQ(TemplateURL::NORMAL, t_url->GetType());
+ DCHECK_EQ(TemplateURL::NORMAL, t_url->type());
enabled = true;
search_url = t_url->url();
suggest_url = t_url->suggestions_url();
diff --git a/chromium/components/search_engines/keyword_table.cc b/chromium/components/search_engines/keyword_table.cc
index fcbd5255825..eee2ac8273e 100644
--- a/chromium/components/search_engines/keyword_table.cc
+++ b/chromium/components/search_engines/keyword_table.cc
@@ -446,7 +446,7 @@ bool KeywordTable::MigrateKeywordsTableForVersion45(const std::string& name) {
TemplateURL turl(data);
// Don't persist extension keywords to disk. These will get added to the
// TemplateURLService as the extensions are loaded.
- bool delete_entry = turl.GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
+ bool delete_entry = turl.type() == TemplateURL::OMNIBOX_API_EXTENSION;
if (!delete_entry && generate_keyword) {
// Explicitly generate keywords for all rows with the autogenerate bit set
// or where the keyword is empty.
diff --git a/chromium/components/search_engines/keyword_table_unittest.cc b/chromium/components/search_engines/keyword_table_unittest.cc
index 0aea5edba69..0e4503aaee8 100644
--- a/chromium/components/search_engines/keyword_table_unittest.cc
+++ b/chromium/components/search_engines/keyword_table_unittest.cc
@@ -7,7 +7,6 @@
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
@@ -29,7 +28,7 @@ class KeywordTableTest : public testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- file_ = temp_dir_.path().AppendASCII("TestWebDatabase");
+ file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
table_.reset(new KeywordTable);
db_.reset(new WebDatabase);
diff --git a/chromium/components/search_engines/prepopulated_engines.gyp b/chromium/components/search_engines/prepopulated_engines.gyp
deleted file mode 100644
index c67aa68e015..00000000000
--- a/chromium/components/search_engines/prepopulated_engines.gyp
+++ /dev/null
@@ -1,25 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/search_engines:prepopulated_engines
- 'target_name': 'prepopulated_engines',
- 'type': 'static_library',
- 'sources': [
- 'prepopulated_engines.json',
- ],
- 'includes': [
- '../../build/json_to_struct.gypi',
- ],
- 'variables': {
- 'chromium_code': 1,
- 'schema_file': 'prepopulated_engines_schema.json',
- 'namespace': 'TemplateURLPrepopulateData',
- 'cc_dir': 'components/search_engines',
- },
- },
- ],
-}
diff --git a/chromium/components/search_engines/prepopulated_engines.json b/chromium/components/search_engines/prepopulated_engines.json
index 721bfd60824..97dad3e51dc 100644
--- a/chromium/components/search_engines/prepopulated_engines.json
+++ b/chromium/components/search_engines/prepopulated_engines.json
@@ -11,7 +11,7 @@
// The following unique IDs are available:
// 7, 11, 12, 13, 14, 18, 19, 20, 22, 24, 26, 28, 29, 30, 32, 33, 34, 39, 37,
// 38, 40, 41, 42, 46, 47, 48, 49, 51, 52, 58, 59, 69, 71, 72, 82, 84, 86,
-// 88, 89, 91+
+// 89, 91+
//
// IDs > 1000 are reserved for distribution custom engines.
//
@@ -30,7 +30,7 @@
// Increment this if you change the data in ways that mean users with
// existing data should get a new version.
- "kCurrentDataVersion": 91
+ "kCurrentDataVersion": 96
},
// The following engines are included in country lists and are added to the
@@ -163,9 +163,9 @@
"naver": {
"name": "\ub124\uc774\ubc84",
"keyword": "naver.com",
- "favicon_url": "http://sstatic.naver.net/search/favicon/favicon_140327.ico",
- "search_url": "http://search.naver.com/search.naver?ie={inputEncoding}&query={searchTerms}",
- "suggest_url": "http://ac.search.naver.com/nx/ac?of=os&ie={inputEncoding}&q={searchTerms}&oe={outputEncoding}",
+ "favicon_url": "https://ssl.pstatic.net/sstatic/search/favicon/favicon_140327.ico",
+ "search_url": "https://search.naver.com/search.naver?ie={inputEncoding}&query={searchTerms}",
+ "suggest_url": "https://ac.search.naver.com/nx/ac?of=os&ie={inputEncoding}&q={searchTerms}&oe={outputEncoding}",
"type": "SEARCH_ENGINE_NAVER",
"id": 67
},
@@ -189,11 +189,22 @@
"id": 25
},
+ "so_360": {
+ "name": "360",
+ "keyword": "so.com",
+ "favicon_url": "https://www.so.com/favicon.ico",
+ "search_url": "https://www.so.com/s?ie={inputEncoding}&q={searchTerms}",
+ "suggest_url": "https://sug.so.360.cn/suggest?encodein={inputEncoding}&encodeout={outputEncoding}&format=opensearch&word={searchTerms}",
+ "type": "SEARCH_ENGINE_360",
+ "id": 88
+ },
+
"sogou": {
"name": "\u641c\u72d7",
"keyword": "sogou.com",
- "favicon_url": "http://www.sogou.com/images/logo/old/favicon.ico",
- "search_url": "http://www.sogou.com/web?ie={inputEncoding}&query={searchTerms}",
+ "favicon_url": "https://www.sogou.com/images/logo/old/favicon.ico",
+ "search_url": "https://www.sogou.com/web?ie={inputEncoding}&query={searchTerms}",
+ "suggest_url": "http://api.sugg.sogou.com/su?type=addrbar&key={searchTerms}&ie={inputEncoding}",
"type": "SEARCH_ENGINE_SOGOU",
"id": 56
},
@@ -580,7 +591,7 @@
"keyword": "yandex.by",
"favicon_url": "https://yastatic.net/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico",
"search_url": "https://yandex.by/{yandex:searchPath}?text={searchTerms}",
- "suggest_url": "https://api.browser.yandex.by/suggest/get?part={searchTerms}",
+ "suggest_url": "https://suggest.yandex.by/suggest-ff.cgi?part={searchTerms}",
"image_url": "https://yandex.by/images/search/?rpt=imageview",
"image_url_post_params": "upfile={google:imageThumbnail},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight},prg=1",
"new_tab_url": "https://www.yandex.by/chrome/newtab",
@@ -593,7 +604,7 @@
"keyword": "yandex.kz",
"favicon_url": "https://yastatic.net/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico",
"search_url": "https://yandex.kz/{yandex:searchPath}?text={searchTerms}",
- "suggest_url": "https://api.browser.yandex.kz/suggest/get?part={searchTerms}",
+ "suggest_url": "https://suggest.yandex.kz/suggest-ff.cgi?part={searchTerms}",
"image_url": "https://yandex.kz/images/search/?rpt=imageview",
"image_url_post_params": "upfile={google:imageThumbnail},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight},prg=1",
"new_tab_url": "https://www.yandex.kz/chrome/newtab",
@@ -606,7 +617,7 @@
"keyword": "yandex.ru",
"favicon_url": "https://yastatic.net/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico",
"search_url": "https://yandex.ru/{yandex:searchPath}?text={searchTerms}",
- "suggest_url": "https://api.browser.yandex.ru/suggest/get?part={searchTerms}",
+ "suggest_url": "https://suggest.yandex.ru/suggest-ff.cgi?part={searchTerms}",
"image_url": "https://yandex.ru/images/search/?rpt=imageview",
"image_url_post_params": "upfile={google:imageThumbnail},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight},prg=1",
"new_tab_url": "https://www.yandex.ru/chrome/newtab",
@@ -619,7 +630,7 @@
"keyword": "yandex.com.tr",
"favicon_url": "https://yastatic.net/lego/_/rBTjd6UOPk5913OSn5ZQVYMTQWQ.ico",
"search_url": "https://www.yandex.com.tr/{yandex:searchPath}?text={searchTerms}",
- "suggest_url": "https://api.browser.yandex.com.tr/suggest/get?part={searchTerms}",
+ "suggest_url": "https://suggest.yandex.com.tr/suggest-ff.cgi?part={searchTerms}",
"image_url": "https://yandex.com.tr/gorsel/search?rpt=imageview",
"image_url_post_params": "upfile={google:imageThumbnail},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight},prg=1",
"new_tab_url": "https://www.yandex.com.tr/chrome/newtab",
@@ -632,7 +643,7 @@
"keyword": "yandex.ua",
"favicon_url": "https://yastatic.net/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico",
"search_url": "https://yandex.ua/{yandex:searchPath}?text={searchTerms}",
- "suggest_url": "https://api.browser.yandex.ua/suggest/get?part={searchTerms}",
+ "suggest_url": "https://suggest.yandex.ua/suggest-ff.cgi?part={searchTerms}",
"image_url": "https://yandex.ua/images/search/?rpt=imageview",
"image_url_post_params": "upfile={google:imageThumbnail},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight},prg=1",
"new_tab_url": "https://www.yandex.ua/chrome/newtab",
diff --git a/chromium/components/search_engines/search_engine_data_type_controller.cc b/chromium/components/search_engines/search_engine_data_type_controller.cc
index 6492095eb02..536f38703ac 100644
--- a/chromium/components/search_engines/search_engine_data_type_controller.cc
+++ b/chromium/components/search_engines/search_engine_data_type_controller.cc
@@ -7,15 +7,10 @@
namespace browser_sync {
SearchEngineDataTypeController::SearchEngineDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
TemplateURLService* template_url_service)
- : UIDataTypeController(ui_thread,
- error_callback,
- syncer::SEARCH_ENGINES,
- sync_client),
- ui_thread_(ui_thread),
+ : UIDataTypeController(syncer::SEARCH_ENGINES, dump_stack, sync_client),
template_url_service_(template_url_service) {}
TemplateURLService::Subscription*
@@ -27,6 +22,7 @@ SearchEngineDataTypeController::~SearchEngineDataTypeController() {}
// We want to start the TemplateURLService before we begin associating.
bool SearchEngineDataTypeController::StartModels() {
+ DCHECK(CalledOnValidThread());
// If the TemplateURLService is loaded, continue with association. We force
// a load here to prevent the rest of Sync from waiting on
// TemplateURLService's lazy load.
@@ -37,19 +33,20 @@ bool SearchEngineDataTypeController::StartModels() {
}
// Register a callback and continue when the TemplateURLService is loaded.
- template_url_subscription_ =
- template_url_service_->RegisterOnLoadedCallback(base::Bind(
- &SearchEngineDataTypeController::OnTemplateURLServiceLoaded, this));
+ template_url_subscription_ = template_url_service_->RegisterOnLoadedCallback(
+ base::Bind(&SearchEngineDataTypeController::OnTemplateURLServiceLoaded,
+ base::AsWeakPtr(this)));
return false; // Don't continue Start.
}
void SearchEngineDataTypeController::StopModels() {
+ DCHECK(CalledOnValidThread());
template_url_subscription_.reset();
}
void SearchEngineDataTypeController::OnTemplateURLServiceLoaded() {
- DCHECK(ui_thread_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
DCHECK_EQ(MODEL_STARTING, state_);
template_url_subscription_.reset();
OnModelLoaded();
diff --git a/chromium/components/search_engines/search_engine_data_type_controller.h b/chromium/components/search_engines/search_engine_data_type_controller.h
index cc4cb6157c2..0a6e1dc1ca4 100644
--- a/chromium/components/search_engines/search_engine_data_type_controller.h
+++ b/chromium/components/search_engines/search_engine_data_type_controller.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "components/search_engines/template_url_service.h"
-#include "components/sync_driver/ui_data_type_controller.h"
+#include "components/sync/driver/ui_data_type_controller.h"
class Profile;
@@ -19,29 +19,23 @@ namespace browser_sync {
// Controller for the SEARCH_ENGINES sync data type. This class tells sync
// how to load the model for this data type, and the superclasses manage
// controlling the rest of the state of the datatype with regards to sync.
-class SearchEngineDataTypeController
- : public sync_driver::UIDataTypeController {
+class SearchEngineDataTypeController : public syncer::UIDataTypeController {
public:
- SearchEngineDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
- TemplateURLService* template_url_service);
+ // |dump_stack| is called when an unrecoverable error occurs.
+ SearchEngineDataTypeController(const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
+ TemplateURLService* template_url_service);
+ ~SearchEngineDataTypeController() override;
TemplateURLService::Subscription* GetSubscriptionForTesting();
private:
- ~SearchEngineDataTypeController() override;
-
// FrontendDataTypeController:
bool StartModels() override;
void StopModels() override;
void OnTemplateURLServiceLoaded();
- // A reference to the UI thread's task runner.
- const scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
-
// A pointer to the template URL service that this data type will use.
TemplateURLService* template_url_service_;
diff --git a/chromium/components/search_engines/search_engine_data_type_controller_unittest.cc b/chromium/components/search_engines/search_engine_data_type_controller_unittest.cc
index 97930b8cd2d..bf37a330de2 100644
--- a/chromium/components/search_engines/search_engine_data_type_controller_unittest.cc
+++ b/chromium/components/search_engines/search_engine_data_type_controller_unittest.cc
@@ -10,16 +10,17 @@
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/tracked_objects.h"
#include "components/search_engines/template_url_service.h"
-#include "components/sync_driver/data_type_controller_mock.h"
-#include "components/sync_driver/fake_generic_change_processor.h"
-#include "components/sync_driver/fake_sync_client.h"
-#include "components/sync_driver/sync_api_component_factory_mock.h"
-#include "sync/api/fake_syncable_service.h"
+#include "components/sync/api/fake_syncable_service.h"
+#include "components/sync/driver/data_type_controller_mock.h"
+#include "components/sync/driver/fake_generic_change_processor.h"
+#include "components/sync/driver/fake_sync_client.h"
+#include "components/sync/driver/sync_api_component_factory_mock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
@@ -31,16 +32,16 @@ using testing::SetArgumentPointee;
namespace browser_sync {
namespace {
-class SyncSearchEngineDataTypeControllerTest
- : public testing::Test,
- public sync_driver::FakeSyncClient {
+class SyncSearchEngineDataTypeControllerTest : public testing::Test,
+ public syncer::FakeSyncClient {
public:
SyncSearchEngineDataTypeControllerTest()
- : sync_driver::FakeSyncClient(&profile_sync_factory_),
- template_url_service_(new TemplateURLService(nullptr, 0)) {
+ : syncer::FakeSyncClient(&profile_sync_factory_),
+ template_url_service_(nullptr, 0),
+ search_engine_dtc_(base::Closure(), this, &template_url_service_) {
// Disallow the TemplateURLService from loading until
// PreloadTemplateURLService() is called .
- template_url_service_->set_disable_load(true);
+ template_url_service_.set_disable_load(true);
}
// FakeSyncClient overrides.
@@ -49,84 +50,74 @@ class SyncSearchEngineDataTypeControllerTest
return syncable_service_.AsWeakPtr();
}
- void SetUp() override {
- search_engine_dtc_ = new SearchEngineDataTypeController(
- base::ThreadTaskRunnerHandle::Get(),
- base::Bind(&base::DoNothing), this,
- template_url_service_.get());
- }
-
void TearDown() override {
// Must be done before we pump the loop.
syncable_service_.StopSyncing(syncer::SEARCH_ENGINES);
- search_engine_dtc_ = NULL;
}
protected:
void PreloadTemplateURLService() {
- template_url_service_->set_disable_load(false);
- template_url_service_->Load();
+ template_url_service_.set_disable_load(false);
+ template_url_service_.Load();
}
void SetStartExpectations() {
- search_engine_dtc_->SetGenericChangeProcessorFactoryForTest(
- base::WrapUnique<sync_driver::GenericChangeProcessorFactory>(
- new sync_driver::FakeGenericChangeProcessorFactory(
- base::WrapUnique(new sync_driver::FakeGenericChangeProcessor(
- syncer::SEARCH_ENGINES, this)))));
+ search_engine_dtc_.SetGenericChangeProcessorFactoryForTest(
+ base::WrapUnique<syncer::GenericChangeProcessorFactory>(
+ new syncer::FakeGenericChangeProcessorFactory(
+ base::MakeUnique<syncer::FakeGenericChangeProcessor>(
+ syncer::SEARCH_ENGINES, this))));
EXPECT_CALL(model_load_callback_, Run(_, _));
}
void Start() {
- search_engine_dtc_->LoadModels(
- base::Bind(&sync_driver::ModelLoadCallbackMock::Run,
+ search_engine_dtc_.LoadModels(
+ base::Bind(&syncer::ModelLoadCallbackMock::Run,
base::Unretained(&model_load_callback_)));
- search_engine_dtc_->StartAssociating(
- base::Bind(&sync_driver::StartCallbackMock::Run,
- base::Unretained(&start_callback_)));
+ search_engine_dtc_.StartAssociating(base::Bind(
+ &syncer::StartCallbackMock::Run, base::Unretained(&start_callback_)));
base::RunLoop().RunUntilIdle();
}
base::MessageLoop message_loop_;
- std::unique_ptr<TemplateURLService> template_url_service_;
- scoped_refptr<SearchEngineDataTypeController> search_engine_dtc_;
- SyncApiComponentFactoryMock profile_sync_factory_;
+ TemplateURLService template_url_service_;
+ SearchEngineDataTypeController search_engine_dtc_;
+ syncer::SyncApiComponentFactoryMock profile_sync_factory_;
syncer::FakeSyncableService syncable_service_;
- sync_driver::StartCallbackMock start_callback_;
- sync_driver::ModelLoadCallbackMock model_load_callback_;
+ syncer::StartCallbackMock start_callback_;
+ syncer::ModelLoadCallbackMock model_load_callback_;
};
TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceReady) {
SetStartExpectations();
// We want to start ready.
PreloadTemplateURLService();
- EXPECT_CALL(start_callback_, Run(sync_driver::DataTypeController::OK, _, _));
+ EXPECT_CALL(start_callback_, Run(syncer::DataTypeController::OK, _, _));
- EXPECT_EQ(sync_driver::DataTypeController::NOT_RUNNING,
- search_engine_dtc_->state());
+ EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
+ search_engine_dtc_.state());
EXPECT_FALSE(syncable_service_.syncing());
Start();
- EXPECT_EQ(sync_driver::DataTypeController::RUNNING,
- search_engine_dtc_->state());
+ EXPECT_EQ(syncer::DataTypeController::RUNNING, search_engine_dtc_.state());
EXPECT_TRUE(syncable_service_.syncing());
}
TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceNotReady) {
EXPECT_CALL(model_load_callback_, Run(_, _));
EXPECT_FALSE(syncable_service_.syncing());
- search_engine_dtc_->LoadModels(
- base::Bind(&sync_driver::ModelLoadCallbackMock::Run,
+ search_engine_dtc_.LoadModels(
+ base::Bind(&syncer::ModelLoadCallbackMock::Run,
base::Unretained(&model_load_callback_)));
- EXPECT_TRUE(search_engine_dtc_->GetSubscriptionForTesting());
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_STARTING,
- search_engine_dtc_->state());
+ EXPECT_TRUE(search_engine_dtc_.GetSubscriptionForTesting());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING,
+ search_engine_dtc_.state());
EXPECT_FALSE(syncable_service_.syncing());
// Send the notification that the TemplateURLService has started.
PreloadTemplateURLService();
- EXPECT_EQ(NULL, search_engine_dtc_->GetSubscriptionForTesting());
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_LOADED,
- search_engine_dtc_->state());
+ EXPECT_EQ(NULL, search_engine_dtc_.GetSubscriptionForTesting());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_LOADED,
+ search_engine_dtc_.state());
// Wait until WebDB is loaded before we shut it down.
base::RunLoop().RunUntilIdle();
@@ -136,7 +127,7 @@ TEST_F(SyncSearchEngineDataTypeControllerTest, StartAssociationFailed) {
SetStartExpectations();
PreloadTemplateURLService();
EXPECT_CALL(start_callback_,
- Run(sync_driver::DataTypeController::ASSOCIATION_FAILED, _, _));
+ Run(syncer::DataTypeController::ASSOCIATION_FAILED, _, _));
syncable_service_.set_merge_data_and_start_syncing_error(
syncer::SyncError(FROM_HERE,
syncer::SyncError::DATATYPE_ERROR,
@@ -144,46 +135,44 @@ TEST_F(SyncSearchEngineDataTypeControllerTest, StartAssociationFailed) {
syncer::SEARCH_ENGINES));
Start();
- EXPECT_EQ(sync_driver::DataTypeController::DISABLED,
- search_engine_dtc_->state());
+ EXPECT_EQ(syncer::DataTypeController::DISABLED, search_engine_dtc_.state());
EXPECT_FALSE(syncable_service_.syncing());
- search_engine_dtc_->Stop();
- EXPECT_EQ(sync_driver::DataTypeController::NOT_RUNNING,
- search_engine_dtc_->state());
+ search_engine_dtc_.Stop();
+ EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
+ search_engine_dtc_.state());
EXPECT_FALSE(syncable_service_.syncing());
}
TEST_F(SyncSearchEngineDataTypeControllerTest, Stop) {
SetStartExpectations();
PreloadTemplateURLService();
- EXPECT_CALL(start_callback_, Run(sync_driver::DataTypeController::OK, _, _));
+ EXPECT_CALL(start_callback_, Run(syncer::DataTypeController::OK, _, _));
- EXPECT_EQ(sync_driver::DataTypeController::NOT_RUNNING,
- search_engine_dtc_->state());
+ EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
+ search_engine_dtc_.state());
EXPECT_FALSE(syncable_service_.syncing());
Start();
- EXPECT_EQ(sync_driver::DataTypeController::RUNNING,
- search_engine_dtc_->state());
+ EXPECT_EQ(syncer::DataTypeController::RUNNING, search_engine_dtc_.state());
EXPECT_TRUE(syncable_service_.syncing());
- search_engine_dtc_->Stop();
- EXPECT_EQ(sync_driver::DataTypeController::NOT_RUNNING,
- search_engine_dtc_->state());
+ search_engine_dtc_.Stop();
+ EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
+ search_engine_dtc_.state());
EXPECT_FALSE(syncable_service_.syncing());
}
TEST_F(SyncSearchEngineDataTypeControllerTest, StopBeforeLoaded) {
EXPECT_FALSE(syncable_service_.syncing());
- search_engine_dtc_->LoadModels(
- base::Bind(&sync_driver::ModelLoadCallbackMock::Run,
+ search_engine_dtc_.LoadModels(
+ base::Bind(&syncer::ModelLoadCallbackMock::Run,
base::Unretained(&model_load_callback_)));
- EXPECT_TRUE(search_engine_dtc_->GetSubscriptionForTesting());
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_STARTING,
- search_engine_dtc_->state());
+ EXPECT_TRUE(search_engine_dtc_.GetSubscriptionForTesting());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING,
+ search_engine_dtc_.state());
EXPECT_FALSE(syncable_service_.syncing());
- search_engine_dtc_->Stop();
- EXPECT_EQ(NULL, search_engine_dtc_->GetSubscriptionForTesting());
- EXPECT_EQ(sync_driver::DataTypeController::NOT_RUNNING,
- search_engine_dtc_->state());
+ search_engine_dtc_.Stop();
+ EXPECT_EQ(NULL, search_engine_dtc_.GetSubscriptionForTesting());
+ EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
+ search_engine_dtc_.state());
EXPECT_FALSE(syncable_service_.syncing());
}
diff --git a/chromium/components/search_engines/search_engine_type.h b/chromium/components/search_engines/search_engine_type.h
index a1872cc701e..f61971487da 100644
--- a/chromium/components/search_engines/search_engine_type.h
+++ b/chromium/components/search_engines/search_engine_type.h
@@ -59,6 +59,7 @@ enum SearchEngineType {
SEARCH_ENGINE_YAHOO,
SEARCH_ENGINE_YANDEX,
SEARCH_ENGINE_ZOZNAM,
+ SEARCH_ENGINE_360,
SEARCH_ENGINE_MAX // Bounding value needed for UMA histogram macro.
};
diff --git a/chromium/components/search_engines/search_host_to_urls_map.cc b/chromium/components/search_engines/search_host_to_urls_map.cc
index d10f62b2def..62c2e5e2fb2 100644
--- a/chromium/components/search_engines/search_host_to_urls_map.cc
+++ b/chromium/components/search_engines/search_host_to_urls_map.cc
@@ -16,7 +16,7 @@ SearchHostToURLsMap::~SearchHostToURLsMap() {
}
void SearchHostToURLsMap::Init(
- const TemplateURLService::TemplateURLVector& template_urls,
+ const TemplateURLService::OwnedTemplateURLVector& template_urls,
const SearchTermsData& search_terms_data) {
DCHECK(!initialized_);
initialized_ = true; // Set here so Add doesn't assert.
@@ -27,7 +27,7 @@ void SearchHostToURLsMap::Add(TemplateURL* template_url,
const SearchTermsData& search_terms_data) {
DCHECK(initialized_);
DCHECK(template_url);
- DCHECK_NE(TemplateURL::OMNIBOX_API_EXTENSION, template_url->GetType());
+ DCHECK_NE(TemplateURL::OMNIBOX_API_EXTENSION, template_url->type());
const GURL url(template_url->GenerateSearchURL(search_terms_data));
if (!url.is_valid() || !url.has_host())
@@ -39,7 +39,7 @@ void SearchHostToURLsMap::Add(TemplateURL* template_url,
void SearchHostToURLsMap::Remove(TemplateURL* template_url) {
DCHECK(initialized_);
DCHECK(template_url);
- DCHECK_NE(TemplateURL::OMNIBOX_API_EXTENSION, template_url->GetType());
+ DCHECK_NE(TemplateURL::OMNIBOX_API_EXTENSION, template_url->type());
for (HostToURLsMap::iterator i = host_to_urls_map_.begin();
i != host_to_urls_map_.end(); ++i) {
@@ -76,9 +76,8 @@ SearchHostToURLsMap::TemplateURLSet* SearchHostToURLsMap::GetURLsForHost(
}
void SearchHostToURLsMap::Add(
- const TemplateURLService::TemplateURLVector& template_urls,
+ const TemplateURLService::OwnedTemplateURLVector& template_urls,
const SearchTermsData& search_terms_data) {
- for (TemplateURLService::TemplateURLVector::const_iterator i(
- template_urls.begin()); i != template_urls.end(); ++i)
- Add(*i, search_terms_data);
+ for (const auto& turl : template_urls)
+ Add(turl.get(), search_terms_data);
}
diff --git a/chromium/components/search_engines/search_host_to_urls_map.h b/chromium/components/search_engines/search_host_to_urls_map.h
index 0235ce555b2..2f46625f7bf 100644
--- a/chromium/components/search_engines/search_host_to_urls_map.h
+++ b/chromium/components/search_engines/search_host_to_urls_map.h
@@ -23,7 +23,7 @@ class SearchHostToURLsMap {
~SearchHostToURLsMap();
// Initializes the map.
- void Init(const TemplateURLService::TemplateURLVector& template_urls,
+ void Init(const TemplateURLService::OwnedTemplateURLVector& template_urls,
const SearchTermsData& search_terms_data);
// Adds a new TemplateURL to the map. Since |template_url| is owned
@@ -48,7 +48,7 @@ class SearchHostToURLsMap {
typedef std::map<std::string, TemplateURLSet> HostToURLsMap;
// Adds many URLs to the map.
- void Add(const TemplateURLService::TemplateURLVector& template_urls,
+ void Add(const TemplateURLService::OwnedTemplateURLVector& template_urls,
const SearchTermsData& search_terms_data);
// Maps from host to set of TemplateURLs whose search url host is host.
diff --git a/chromium/components/search_engines/search_host_to_urls_map_unittest.cc b/chromium/components/search_engines/search_host_to_urls_map_unittest.cc
index 9d29769a7d8..18916fe26ec 100644
--- a/chromium/components/search_engines/search_host_to_urls_map_unittest.cc
+++ b/chromium/components/search_engines/search_host_to_urls_map_unittest.cc
@@ -9,8 +9,10 @@
#include <memory>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "components/search_engines/search_terms_data.h"
#include "components/search_engines/template_url.h"
+#include "components/search_engines/template_url_service.h"
#include "testing/gtest/include/gtest/gtest.h"
typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet;
@@ -24,7 +26,7 @@ class SearchHostToURLsMapTest : public testing::Test {
protected:
std::unique_ptr<SearchHostToURLsMap> provider_map_;
- std::unique_ptr<TemplateURL> t_urls_[2];
+ TemplateURLService::OwnedTemplateURLVector template_urls_;
std::string host_;
DISALLOW_COPY_AND_ASSIGN(SearchHostToURLsMapTest);
@@ -35,15 +37,12 @@ void SearchHostToURLsMapTest::SetUp() {
host_ = "www.unittest.com";
TemplateURLData data;
data.SetURL("http://" + host_ + "/path1");
- t_urls_[0].reset(new TemplateURL(data));
+ template_urls_.push_back(base::MakeUnique<TemplateURL>(data));
data.SetURL("http://" + host_ + "/path2");
- t_urls_[1].reset(new TemplateURL(data));
- std::vector<TemplateURL*> template_urls;
- template_urls.push_back(t_urls_[0].get());
- template_urls.push_back(t_urls_[1].get());
+ template_urls_.push_back(base::MakeUnique<TemplateURL>(data));
provider_map_.reset(new SearchHostToURLsMap);
- provider_map_->Init(template_urls, SearchTermsData());
+ provider_map_->Init(template_urls_, SearchTermsData());
}
TEST_F(SearchHostToURLsMapTest, Add) {
@@ -57,55 +56,44 @@ TEST_F(SearchHostToURLsMapTest, Add) {
}
TEST_F(SearchHostToURLsMapTest, Remove) {
- provider_map_->Remove(t_urls_[0].get());
+ provider_map_->Remove(template_urls_[0].get());
const TemplateURL* found_url = provider_map_->GetTemplateURLForHost(host_);
- ASSERT_EQ(t_urls_[1].get(), found_url);
+ ASSERT_EQ(template_urls_[1].get(), found_url);
const TemplateURLSet* urls = provider_map_->GetURLsForHost(host_);
- ASSERT_TRUE(urls != NULL);
+ ASSERT_TRUE(urls != nullptr);
int url_count = 0;
for (TemplateURLSet::const_iterator i(urls->begin()); i != urls->end(); ++i) {
url_count++;
- ASSERT_EQ(t_urls_[1].get(), *i);
+ ASSERT_EQ(template_urls_[1].get(), *i);
}
ASSERT_EQ(1, url_count);
}
TEST_F(SearchHostToURLsMapTest, GetTemplateURLForKnownHost) {
const TemplateURL* found_url = provider_map_->GetTemplateURLForHost(host_);
- ASSERT_TRUE(found_url == t_urls_[0].get() || found_url == t_urls_[1].get());
+ ASSERT_TRUE(found_url == template_urls_[0].get() ||
+ found_url == template_urls_[1].get());
}
TEST_F(SearchHostToURLsMapTest, GetTemplateURLForUnknownHost) {
const TemplateURL* found_url =
provider_map_->GetTemplateURLForHost("a" + host_);
- ASSERT_TRUE(found_url == NULL);
+ ASSERT_TRUE(found_url == nullptr);
}
TEST_F(SearchHostToURLsMapTest, GetURLsForKnownHost) {
const TemplateURLSet* urls = provider_map_->GetURLsForHost(host_);
- ASSERT_TRUE(urls != NULL);
+ ASSERT_TRUE(urls != nullptr);
- bool found_urls[arraysize(t_urls_)] = { false };
-
- for (TemplateURLSet::const_iterator i(urls->begin()); i != urls->end(); ++i) {
- const TemplateURL* url = *i;
- for (size_t i = 0; i < arraysize(found_urls); ++i) {
- if (url == t_urls_[i].get()) {
- found_urls[i] = true;
- break;
- }
- }
- }
-
- for (size_t i = 0; i < arraysize(found_urls); ++i)
- ASSERT_TRUE(found_urls[i]);
+ for (const auto& url : template_urls_)
+ EXPECT_NE(urls->end(), urls->find(url.get()));
}
TEST_F(SearchHostToURLsMapTest, GetURLsForUnknownHost) {
const SearchHostToURLsMap::TemplateURLSet* urls =
provider_map_->GetURLsForHost("a" + host_);
- ASSERT_TRUE(urls == NULL);
+ ASSERT_TRUE(urls == nullptr);
}
diff --git a/chromium/components/search_engines/template_url.cc b/chromium/components/search_engines/template_url.cc
index a3be5cff8eb..a058755ca3f 100644
--- a/chromium/components/search_engines/template_url.cc
+++ b/chromium/components/search_engines/template_url.cc
@@ -188,33 +188,29 @@ TemplateURLRef::SearchTermsArgs::ContextualSearchParams::
: version(-1),
start(base::string16::npos),
end(base::string16::npos),
- resolve(true) {
-}
+ contextual_cards_version(0) {}
-TemplateURLRef::SearchTermsArgs::ContextualSearchParams::
- ContextualSearchParams(
- const int version,
- const std::string& selection,
- const std::string& base_page_url,
- const bool resolve)
+TemplateURLRef::SearchTermsArgs::ContextualSearchParams::ContextualSearchParams(
+ int version,
+ const std::string& selection,
+ const std::string& base_page_url,
+ int contextual_cards_version)
: version(version),
start(base::string16::npos),
end(base::string16::npos),
selection(selection),
base_page_url(base_page_url),
- resolve(resolve) {
-}
+ contextual_cards_version(contextual_cards_version) {}
-TemplateURLRef::SearchTermsArgs::ContextualSearchParams::
- ContextualSearchParams(
- const int version,
- const size_t start,
- const size_t end,
- const std::string& selection,
- const std::string& content,
- const std::string& base_page_url,
- const std::string& encoding,
- const bool resolve)
+TemplateURLRef::SearchTermsArgs::ContextualSearchParams::ContextualSearchParams(
+ int version,
+ size_t start,
+ size_t end,
+ const std::string& selection,
+ const std::string& content,
+ const std::string& base_page_url,
+ const std::string& encoding,
+ int contextual_cards_version)
: version(version),
start(start),
end(end),
@@ -222,8 +218,7 @@ TemplateURLRef::SearchTermsArgs::ContextualSearchParams::
content(content),
base_page_url(base_page_url),
encoding(encoding),
- resolve(resolve) {
-}
+ contextual_cards_version(contextual_cards_version) {}
TemplateURLRef::SearchTermsArgs::ContextualSearchParams::ContextualSearchParams(
const ContextualSearchParams& other) = default;
@@ -1020,8 +1015,11 @@ std::string TemplateURLRef::HandleReplacements(
context_data.append("ctxs_encoding=" + params.encoding + "&");
}
- context_data.append(
- params.resolve ? "ctxsl_resolve=1" : "ctxsl_resolve=0");
+ // The above parameters all add a trailing "&" so there must be one last
+ // parameter that's always added at the end.
+ context_data.append("ctxsl_coca=" +
+ base::IntToString(
+ params.contextual_cards_version));
HandleReplacement(std::string(), context_data, *i, &url);
break;
@@ -1185,27 +1183,21 @@ std::string TemplateURLRef::HandleReplacements(
// TemplateURL ----------------------------------------------------------------
TemplateURL::AssociatedExtensionInfo::AssociatedExtensionInfo(
- Type type,
const std::string& extension_id)
- : type(type),
- extension_id(extension_id),
- wants_to_be_default_engine(false) {
- DCHECK_NE(NORMAL, type);
-}
+ : extension_id(extension_id), wants_to_be_default_engine(false) {}
TemplateURL::AssociatedExtensionInfo::~AssociatedExtensionInfo() {
}
-TemplateURL::TemplateURL(const TemplateURLData& data)
+TemplateURL::TemplateURL(const TemplateURLData& data, Type type)
: data_(data),
url_ref_(nullptr),
- suggestions_url_ref_(this,
- TemplateURLRef::SUGGEST),
- instant_url_ref_(this,
- TemplateURLRef::INSTANT),
+ suggestions_url_ref_(this, TemplateURLRef::SUGGEST),
+ instant_url_ref_(this, TemplateURLRef::INSTANT),
image_url_ref_(this, TemplateURLRef::IMAGE),
new_tab_url_ref_(this, TemplateURLRef::NEW_TAB),
contextual_search_url_ref_(this, TemplateURLRef::CONTEXTUAL_SEARCH),
+ type_(type),
engine_type_(SEARCH_ENGINE_UNKNOWN) {
ResizeURLRefVector();
SetPrepopulateId(data_.prepopulate_id);
@@ -1310,7 +1302,7 @@ bool TemplateURL::HasGoogleBaseURLs(
bool TemplateURL::IsGoogleSearchURLWithReplaceableKeyword(
const SearchTermsData& search_terms_data) const {
- return (GetType() == NORMAL) &&
+ return (type_ == NORMAL) &&
url_ref_->HasGoogleBaseURLs(search_terms_data) &&
google_util::IsGoogleHostname(base::UTF16ToUTF8(data_.keyword()),
google_util::DISALLOW_SUBDOMAIN);
@@ -1325,10 +1317,6 @@ bool TemplateURL::HasSameKeywordAs(
search_terms_data));
}
-TemplateURL::Type TemplateURL::GetType() const {
- return extension_info_ ? extension_info_->type : NORMAL;
-}
-
std::string TemplateURL::GetExtensionId() const {
DCHECK(extension_info_);
return extension_info_->extension_id;
@@ -1502,7 +1490,7 @@ void TemplateURL::ResetKeywordIfNecessary(
const SearchTermsData& search_terms_data,
bool force) {
if (IsGoogleSearchURLWithReplaceableKeyword(search_terms_data) || force) {
- DCHECK(GetType() != OMNIBOX_API_EXTENSION);
+ DCHECK_NE(OMNIBOX_API_EXTENSION, type_);
GURL url(GenerateSearchURL(search_terms_data));
if (url.is_valid())
data_.SetKeyword(GenerateKeyword(url));
diff --git a/chromium/components/search_engines/template_url.h b/chromium/components/search_engines/template_url.h
index 16c79ea9f9d..e931a0ae6b1 100644
--- a/chromium/components/search_engines/template_url.h
+++ b/chromium/components/search_engines/template_url.h
@@ -83,20 +83,20 @@ class TemplateURLRef {
// parameters.
// TODO(donnd): Remove base_page_url and selection parameters once
// they are logged from the HTTP header.
- ContextualSearchParams(const int version,
+ ContextualSearchParams(int version,
const std::string& selection,
const std::string& base_page_url,
- const bool resolve);
+ int contextual_cards_version);
// TODO(donnd): Delete constructor once Clank, iOS, and tests no
// longer depend on it.
- ContextualSearchParams(const int version,
- const size_t start,
- const size_t end,
+ ContextualSearchParams(int version,
+ size_t start,
+ size_t end,
const std::string& selection,
const std::string& content,
const std::string& base_page_url,
const std::string& encoding,
- const bool resolve);
+ int contextual_cards_version);
ContextualSearchParams(const ContextualSearchParams& other);
~ContextualSearchParams();
@@ -121,10 +121,9 @@ class TemplateURLRef {
// The encoding of content.
std::string encoding;
- // If true, the server will generate a search term based on the user
- // selection and context. Otherwise the user selection will be used as-is
- // as the search term.
- bool resolve;
+ // The version of Contextual Cards data to request.
+ // A value of 0 indicates no data needed.
+ int contextual_cards_version;
};
// The search terms (query).
@@ -499,16 +498,16 @@ class TemplateURL {
NORMAL_CONTROLLED_BY_EXTENSION,
// The keyword associated with an extension that uses the Omnibox API.
OMNIBOX_API_EXTENSION,
+ // Installed only on this device. Should not be synced.
+ LOCAL,
};
// An AssociatedExtensionInfo represents information about the extension that
// added the search engine.
struct AssociatedExtensionInfo {
- AssociatedExtensionInfo(Type type, const std::string& extension_id);
+ explicit AssociatedExtensionInfo(const std::string& extension_id);
~AssociatedExtensionInfo();
- Type type;
-
std::string extension_id;
// Whether the search engine is supposed to be default.
@@ -519,7 +518,7 @@ class TemplateURL {
base::Time install_time;
};
- explicit TemplateURL(const TemplateURLData& data);
+ explicit TemplateURL(const TemplateURLData& data, Type type = NORMAL);
~TemplateURL();
// Generates a suitable keyword for the specified url, which must be valid.
@@ -613,6 +612,8 @@ class TemplateURL {
return contextual_search_url_ref_;
}
+ Type type() const { return type_; }
+
// This setter shouldn't be used except by TemplateURLService and
// TemplateURLServiceClient implementations.
void set_extension_info(
@@ -638,8 +639,6 @@ class TemplateURL {
bool HasSameKeywordAs(const TemplateURLData& other,
const SearchTermsData& search_terms_data) const;
- Type GetType() const;
-
// Returns the id of the extension that added this search engine. Only call
// this for TemplateURLs of type NORMAL_CONTROLLED_BY_EXTENSION or
// OMNIBOX_API_EXTENSION.
@@ -755,6 +754,8 @@ class TemplateURL {
TemplateURLRef contextual_search_url_ref_;
std::unique_ptr<AssociatedExtensionInfo> extension_info_;
+ const Type type_;
+
// Caches the computed engine type across successive calls to GetEngineType().
mutable SearchEngineType engine_type_;
diff --git a/chromium/components/search_engines/template_url_fetcher.cc b/chromium/components/search_engines/template_url_fetcher.cc
index 16068752d0b..6274531e2c5 100644
--- a/chromium/components/search_engines/template_url_fetcher.cc
+++ b/chromium/components/search_engines/template_url_fetcher.cc
@@ -111,9 +111,9 @@ void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete(
return;
}
- template_url_.reset(TemplateURLParser::Parse(
- fetcher_->template_url_service_->search_terms_data(), false,
- data.data(), data.length(), NULL));
+ template_url_ = TemplateURLParser::Parse(
+ fetcher_->template_url_service_->search_terms_data(), false, data.data(),
+ data.length(), nullptr);
if (!template_url_.get() ||
!template_url_->url_ref().SupportsReplacement(
fetcher_->template_url_service_->search_terms_data())) {
@@ -168,7 +168,7 @@ void TemplateURLFetcher::RequestDelegate::AddSearchProvider() {
// Mark the keyword as replaceable so it can be removed if necessary.
data.safe_for_autoreplace = true;
- model->Add(new TemplateURL(data));
+ model->Add(base::MakeUnique<TemplateURL>(data));
fetcher_->RequestCompleted(this);
// WARNING: RequestCompleted deletes us.
@@ -208,19 +208,20 @@ void TemplateURLFetcher::ScheduleDownload(
return;
// Make sure we aren't already downloading this request.
- for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
- if (((*i)->url() == osdd_url) || ((*i)->keyword() == keyword))
+ for (const auto& request : requests_) {
+ if ((request->url() == osdd_url) || (request->keyword() == keyword))
return;
}
- requests_.push_back(new RequestDelegate(
+ requests_.push_back(base::MakeUnique<RequestDelegate>(
this, keyword, osdd_url, favicon_url, url_fetcher_customize_callback));
}
void TemplateURLFetcher::RequestCompleted(RequestDelegate* request) {
- Requests::iterator i =
- std::find(requests_.begin(), requests_.end(), request);
+ auto i = std::find_if(requests_.begin(), requests_.end(),
+ [request](const std::unique_ptr<RequestDelegate>& ptr) {
+ return ptr.get() == request;
+ });
DCHECK(i != requests_.end());
- requests_.weak_erase(i);
- delete request;
+ requests_.erase(i);
}
diff --git a/chromium/components/search_engines/template_url_fetcher.h b/chromium/components/search_engines/template_url_fetcher.h
index f229a4ea0b2..c2c05ed4bd5 100644
--- a/chromium/components/search_engines/template_url_fetcher.h
+++ b/chromium/components/search_engines/template_url_fetcher.h
@@ -68,13 +68,11 @@ class TemplateURLFetcher : public KeyedService {
private:
friend class RequestDelegate;
- typedef ScopedVector<RequestDelegate> Requests;
-
TemplateURLService* template_url_service_;
scoped_refptr<net::URLRequestContextGetter> request_context_;
// In progress requests.
- Requests requests_;
+ std::vector<std::unique_ptr<RequestDelegate>> requests_;
DISALLOW_COPY_AND_ASSIGN(TemplateURLFetcher);
};
diff --git a/chromium/components/search_engines/template_url_parser.cc b/chromium/components/search_engines/template_url_parser.cc
index 9c93747b27b..e3eec92f67d 100644
--- a/chromium/components/search_engines/template_url_parser.cc
+++ b/chromium/components/search_engines/template_url_parser.cc
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -140,12 +141,13 @@ class TemplateURLParsingContext {
static void EndElementImpl(void* ctx, const xmlChar* name);
static void CharactersImpl(void* ctx, const xmlChar* ch, int len);
- // Returns a heap-allocated TemplateURL representing the result of parsing.
- // This will be NULL if parsing failed or if the results were invalid for some
- // reason (e.g. the resulting URL was not HTTP[S], a name wasn't supplied,
- // a resulting TemplateURLRef was invalid, etc.).
- TemplateURL* GetTemplateURL(const SearchTermsData& search_terms_data,
- bool show_in_default_list);
+ // Returns a TemplateURL representing the result of parsing. This will be
+ // null if parsing failed or if the results were invalid for some reason (e.g.
+ // the resulting URL was not HTTP[S], a name wasn't supplied, a resulting
+ // TemplateURLRef was invalid, etc.).
+ std::unique_ptr<TemplateURL> GetTemplateURL(
+ const SearchTermsData& search_terms_data,
+ bool show_in_default_list);
private:
// Key is UTF8 encoded.
@@ -299,14 +301,14 @@ void TemplateURLParsingContext::CharactersImpl(void* ctx,
base::StringPiece(reinterpret_cast<const char*>(ch), len));
}
-TemplateURL* TemplateURLParsingContext::GetTemplateURL(
+std::unique_ptr<TemplateURL> TemplateURLParsingContext::GetTemplateURL(
const SearchTermsData& search_terms_data,
bool show_in_default_list) {
// TODO(jcampan): Support engines that use POST; see http://crbug.com/18107
if (method_ == TemplateURLParsingContext::POST ||
data_.short_name().empty() || !IsHTTPRef(data_.url()) ||
!IsHTTPRef(data_.suggestions_url))
- return NULL;
+ return nullptr;
if (suggestion_method_ == TemplateURLParsingContext::POST)
data_.suggestions_url.clear();
@@ -324,15 +326,16 @@ TemplateURL* TemplateURLParsingContext::GetTemplateURL(
data_.show_in_default_list = show_in_default_list;
// Bail if the search URL is empty or if either TemplateURLRef is invalid.
- std::unique_ptr<TemplateURL> template_url(new TemplateURL(data_));
+ std::unique_ptr<TemplateURL> template_url =
+ base::MakeUnique<TemplateURL>(data_);
if (template_url->url().empty() ||
!template_url->url_ref().IsValid(search_terms_data) ||
(!template_url->suggestions_url().empty() &&
!template_url->suggestions_url_ref().IsValid(search_terms_data))) {
- return NULL;
+ return nullptr;
}
- return template_url.release();
+ return template_url;
}
// static
@@ -490,7 +493,7 @@ TemplateURLParsingContext::ElementType
// TemplateURLParser ----------------------------------------------------------
// static
-TemplateURL* TemplateURLParser::Parse(
+std::unique_ptr<TemplateURL> TemplateURLParser::Parse(
const SearchTermsData& search_terms_data,
bool show_in_default_list,
const char* data,
@@ -511,6 +514,6 @@ TemplateURL* TemplateURLParser::Parse(
static_cast<int>(length));
xmlSubstituteEntitiesDefault(last_sub_entities_value);
- return error ?
- NULL : context.GetTemplateURL(search_terms_data, show_in_default_list);
+ return error ? nullptr : context.GetTemplateURL(search_terms_data,
+ show_in_default_list);
}
diff --git a/chromium/components/search_engines/template_url_parser.h b/chromium/components/search_engines/template_url_parser.h
index ead5906b918..a878cc95dd3 100644
--- a/chromium/components/search_engines/template_url_parser.h
+++ b/chromium/components/search_engines/template_url_parser.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include <memory>
#include <string>
#include "base/macros.h"
@@ -30,19 +31,19 @@ class TemplateURLParser {
};
// Decodes the chunk of data representing a TemplateURL, creates the
- // TemplateURL, and returns it. The caller owns the returned object.
- // Returns NULL if data does not describe a valid TemplateURL, the
- // URLs referenced do not point to valid http/https resources, or for some
- // other reason we do not support the described TemplateURL.
- // |parameter_filter| can be used if you want to filter some parameters out of
- // the URL. For example, when importing from another browser, we remove any
- // parameter identifying that browser. If set to NULL, the URL is not
- // modified.
- static TemplateURL* Parse(const SearchTermsData& search_terms_data,
- bool show_in_default_list,
- const char* data,
- size_t length,
- ParameterFilter* parameter_filter);
+ // TemplateURL, and returns it. Returns null if the data does not describe a
+ // valid TemplateURL, the URLs referenced do not point to valid http/https
+ // resources, or for some other reason we do not support the described
+ // TemplateURL. |parameter_filter| can be used if you want to filter some
+ // parameters out of the URL. For example, when importing from another
+ // browser, we remove any parameter identifying that browser. If set to null,
+ // the URL is not modified.
+ static std::unique_ptr<TemplateURL> Parse(
+ const SearchTermsData& search_terms_data,
+ bool show_in_default_list,
+ const char* data,
+ size_t length,
+ ParameterFilter* parameter_filter);
private:
// No one should create one of these.
diff --git a/chromium/components/search_engines/template_url_prepopulate_data.cc b/chromium/components/search_engines/template_url_prepopulate_data.cc
index 114757dd66d..72574064b75 100644
--- a/chromium/components/search_engines/template_url_prepopulate_data.cc
+++ b/chromium/components/search_engines/template_url_prepopulate_data.cc
@@ -10,7 +10,6 @@
#include "base/logging.h"
#include "base/macros.h"
-#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
@@ -126,7 +125,7 @@ const PrepopulatedEngine* engines_CL[] =
// China
const PrepopulatedEngine* engines_CN[] =
- { &google, &baidu, &sogou, };
+ { &google, &baidu, &sogou, &so_360};
// Colombia
const PrepopulatedEngine* engines_CO[] =
@@ -537,6 +536,12 @@ int CountryCharsToCountryIDWithUpdate(char c1, char c2) {
return CountryCharsToCountryID(c1, c2);
}
+int CountryStringToCountryID(const std::string& country) {
+ return (country.length() == 2)
+ ? CountryCharsToCountryIDWithUpdate(country[0], country[1])
+ : kCountryIDUnknown;
+}
+
#if defined(OS_WIN)
// For reference, a list of GeoIDs can be found at
@@ -610,14 +615,12 @@ int GetCountryIDFromPrefs(PrefService* prefs) {
return prefs->GetInteger(prefs::kCountryIDAtInstall);
}
-void GetPrepopulationSetFromCountryID(PrefService* prefs,
- const PrepopulatedEngine*** engines,
- size_t* num_engines) {
- // NOTE: This function should ALWAYS set its outparams.
-
+std::vector<std::unique_ptr<TemplateURLData>> GetPrepopulationSetFromCountryID(
+ int country_id) {
+ const PrepopulatedEngine** engines;
+ size_t num_engines;
// If you add a new country make sure to update the unit test for coverage.
- switch (GetCountryIDFromPrefs(prefs)) {
-
+ switch (country_id) {
#define CHAR_A 'A'
#define CHAR_B 'B'
#define CHAR_C 'C'
@@ -651,9 +654,9 @@ void GetPrepopulationSetFromCountryID(PrefService* prefs,
#define UNHANDLED_COUNTRY(code1, code2)\
case CODE_TO_ID(code1, code2):
#define END_UNHANDLED_COUNTRIES(code1, code2)\
- *engines = engines_##code1##code2;\
- *num_engines = arraysize(engines_##code1##code2);\
- return;
+ engines = engines_##code1##code2;\
+ num_engines = arraysize(engines_##code1##code2);\
+ break;
#define DECLARE_COUNTRY(code1, code2)\
UNHANDLED_COUNTRY(code1, code2)\
END_UNHANDLED_COUNTRIES(code1, code2)
@@ -966,6 +969,11 @@ void GetPrepopulationSetFromCountryID(PrefService* prefs,
default: // Unhandled location
END_UNHANDLED_COUNTRIES(def, ault)
}
+
+ std::vector<std::unique_ptr<TemplateURLData>> t_urls;
+ for (size_t i = 0; i < num_engines; ++i)
+ t_urls.push_back(MakeTemplateURLDataFromPrepopulatedEngine(*engines[i]));
+ return t_urls;
}
std::unique_ptr<TemplateURLData> MakePrepopulatedTemplateURLData(
@@ -1000,7 +1008,7 @@ std::unique_ptr<TemplateURLData> MakePrepopulatedTemplateURLData(
data->suggestions_url_post_params = suggest_url_post_params.as_string();
data->instant_url_post_params = instant_url_post_params.as_string();
data->image_url_post_params = image_url_post_params.as_string();
- data->favicon_url = GURL(favicon_url.as_string());
+ data->favicon_url = GURL(favicon_url);
data->show_in_default_list = true;
data->safe_for_autoreplace = true;
data->input_encodings.push_back(encoding.as_string());
@@ -1017,9 +1025,9 @@ std::unique_ptr<TemplateURLData> MakePrepopulatedTemplateURLData(
return data;
}
-ScopedVector<TemplateURLData> GetPrepopulatedTemplateURLData(
+std::vector<std::unique_ptr<TemplateURLData>> GetPrepopulatedTemplateURLData(
PrefService* prefs) {
- ScopedVector<TemplateURLData> t_urls;
+ std::vector<std::unique_ptr<TemplateURLData>> t_urls;
if (!prefs)
return t_urls;
@@ -1070,12 +1078,12 @@ ScopedVector<TemplateURLData> GetPrepopulatedTemplateURLData(
engine->GetList("alternate_urls", &alternate_urls);
engine->GetString("search_terms_replacement_key",
&search_terms_replacement_key);
- t_urls.push_back(MakePrepopulatedTemplateURLData(name, keyword,
- search_url, suggest_url, instant_url, image_url, new_tab_url,
- contextual_search_url, search_url_post_params,
+ t_urls.push_back(MakePrepopulatedTemplateURLData(
+ name, keyword, search_url, suggest_url, instant_url, image_url,
+ new_tab_url, contextual_search_url, search_url_post_params,
suggest_url_post_params, instant_url_post_params,
image_url_post_params, favicon_url, encoding, *alternate_urls,
- search_terms_replacement_key, id).release());
+ search_terms_replacement_key, id));
}
}
return t_urls;
@@ -1105,25 +1113,33 @@ int GetDataVersion(PrefService* prefs) {
kCurrentDataVersion;
}
-ScopedVector<TemplateURLData> GetPrepopulatedEngines(
+std::vector<std::unique_ptr<TemplateURLData>> GetPrepopulatedEngines(
PrefService* prefs,
size_t* default_search_provider_index) {
// If there is a set of search engines in the preferences file, it overrides
// the built-in set.
*default_search_provider_index = 0;
- ScopedVector<TemplateURLData> t_urls = GetPrepopulatedTemplateURLData(prefs);
+ std::vector<std::unique_ptr<TemplateURLData>> t_urls =
+ GetPrepopulatedTemplateURLData(prefs);
if (!t_urls.empty())
return t_urls;
- const PrepopulatedEngine** engines;
- size_t num_engines;
- GetPrepopulationSetFromCountryID(prefs, &engines, &num_engines);
- for (size_t i = 0; i != num_engines; ++i) {
- t_urls.push_back(
- MakeTemplateURLDataFromPrepopulatedEngine(*engines[i]).release());
+ return GetPrepopulationSetFromCountryID(GetCountryIDFromPrefs(prefs));
+}
+
+#if defined(OS_ANDROID)
+std::vector<std::unique_ptr<TemplateURLData>> GetLocalPrepopulatedEngines(
+ const std::string& locale,
+ PrefService* prefs) {
+ int country_id = CountryStringToCountryID(locale);
+ if (country_id == kCountryIDUnknown ||
+ country_id == GetCountryIDFromPrefs(prefs)) {
+ return std::vector<std::unique_ptr<TemplateURLData>>();
}
- return t_urls;
+
+ return GetPrepopulationSetFromCountryID(country_id);
}
+#endif
std::vector<const PrepopulatedEngine*> GetAllPrepopulatedEngines() {
return std::vector<const PrepopulatedEngine*>(std::begin(kAllEngines),
@@ -1158,17 +1174,15 @@ void ClearPrepopulatedEnginesInPrefs(PrefService* prefs) {
std::unique_ptr<TemplateURLData> GetPrepopulatedDefaultSearch(
PrefService* prefs) {
- std::unique_ptr<TemplateURLData> default_search_provider;
size_t default_search_index;
// This could be more efficient. We are loading all the URLs to only keep
// the first one.
- ScopedVector<TemplateURLData> loaded_urls =
+ std::vector<std::unique_ptr<TemplateURLData>> loaded_urls =
GetPrepopulatedEngines(prefs, &default_search_index);
- if (default_search_index < loaded_urls.size()) {
- default_search_provider.reset(loaded_urls[default_search_index]);
- loaded_urls.weak_erase(loaded_urls.begin() + default_search_index);
- }
- return default_search_provider;
+
+ return (default_search_index < loaded_urls.size())
+ ? std::move(loaded_urls[default_search_index])
+ : nullptr;
}
SearchEngineType GetEngineType(const GURL& url) {
@@ -1203,9 +1217,7 @@ SearchEngineType GetEngineType(const GURL& url) {
#if defined(OS_WIN)
int GetCurrentCountryID() {
- GEOID geo_id = GetUserGeoID(GEOCLASS_NATION);
-
- return GeoIDToCountryID(geo_id);
+ return GeoIDToCountryID(GetUserGeoID(GEOCLASS_NATION));
}
#elif defined(OS_MACOSX)
@@ -1228,41 +1240,30 @@ int GetCurrentCountryID() {
#elif defined(OS_ANDROID)
int GetCurrentCountryID() {
- const std::string& country_code = base::android::GetDefaultCountryCode();
- return (country_code.size() == 2) ?
- CountryCharsToCountryIDWithUpdate(country_code[0], country_code[1]) :
- kCountryIDUnknown;
+ return CountryStringToCountryID(base::android::GetDefaultCountryCode());
}
#elif defined(OS_POSIX)
int GetCurrentCountryID() {
const char* locale = setlocale(LC_MESSAGES, NULL);
-
if (!locale)
return kCountryIDUnknown;
// The format of a locale name is:
// language[_territory][.codeset][@modifier], where territory is an ISO 3166
// country code, which is what we want.
+
+ // First remove the language portion.
std::string locale_str(locale);
- size_t begin = locale_str.find('_');
- if (begin == std::string::npos || locale_str.size() - begin < 3)
+ size_t territory_delim = locale_str.find('_');
+ if (territory_delim == std::string::npos)
return kCountryIDUnknown;
+ locale_str.erase(0, territory_delim + 1);
- ++begin;
- size_t end = locale_str.find_first_of(".@", begin);
- if (end == std::string::npos)
- end = locale_str.size();
-
- // The territory part must contain exactly two characters.
- if (end - begin == 2) {
- return CountryCharsToCountryIDWithUpdate(
- base::ToUpperASCII(locale_str[begin]),
- base::ToUpperASCII(locale_str[begin + 1]));
- }
-
- return kCountryIDUnknown;
+ // Next remove any codeset/modifier portion and uppercase.
+ return CountryStringToCountryID(
+ base::ToUpperASCII(locale_str.substr(0, locale_str.find_first_of(".@"))));
}
#endif // OS_*
diff --git a/chromium/components/search_engines/template_url_prepopulate_data.h b/chromium/components/search_engines/template_url_prepopulate_data.h
index a3224f33adb..4a218f73f1f 100644
--- a/chromium/components/search_engines/template_url_prepopulate_data.h
+++ b/chromium/components/search_engines/template_url_prepopulate_data.h
@@ -11,7 +11,6 @@
#include <string>
#include <vector>
-#include "base/memory/scoped_vector.h"
#include "base/strings/string16.h"
#include "components/search_engines/search_engine_type.h"
@@ -36,13 +35,23 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// file then it returns the version specified there.
int GetDataVersion(PrefService* prefs);
-// Loads the set of TemplateURLs from the prepopulate data. On return,
+// Returns the prepopulated URLs for the current country.
// |default_search_provider_index| is set to the index of the default search
-// provider.
-ScopedVector<TemplateURLData> GetPrepopulatedEngines(
+// provider within the returned vector.
+std::vector<std::unique_ptr<TemplateURLData>> GetPrepopulatedEngines(
PrefService* prefs,
size_t* default_search_provider_index);
+#if defined(OS_ANDROID)
+// Returns the prepopulated URLs associated with |locale|, if it differs from
+// the current country. |locale| should be a two-character uppercase ISO 3166-1
+// country code. If the given locale is the same as the existing locale, returns
+// an empty vector.
+std::vector<std::unique_ptr<TemplateURLData>> GetLocalPrepopulatedEngines(
+ const std::string& locale,
+ PrefService* prefs);
+#endif
+
// Returns all prepopulated engines for all locales. Used only by tests.
std::vector<const PrepopulatedEngine*> GetAllPrepopulatedEngines();
diff --git a/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc b/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc
index acda60f229d..e57a940cf89 100644
--- a/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc
+++ b/chromium/components/search_engines/template_url_prepopulate_data_unittest.cc
@@ -12,7 +12,6 @@
#include "base/command_line.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
#include "base/strings/utf_string_conversions.h"
#include "components/google/core/browser/google_switches.h"
#include "components/pref_registry/testing_pref_service_syncable.h"
@@ -106,7 +105,7 @@ TEST_F(TemplateURLPrepopulateDataTest, UniqueIDs) {
for (size_t i = 0; i < arraysize(kCountryIds); ++i) {
prefs_.SetInteger(prefs::kCountryIDAtInstall, kCountryIds[i]);
size_t default_index;
- ScopedVector<TemplateURLData> urls =
+ std::vector<std::unique_ptr<TemplateURLData>> urls =
TemplateURLPrepopulateData::GetPrepopulatedEngines(&prefs_,
&default_index);
std::set<int> unique_ids;
@@ -132,14 +131,14 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
entry->SetString("favicon_url", "http://foi.com/favicon.ico");
entry->SetString("encoding", "UTF-8");
entry->SetInteger("id", 1001);
- overrides->Append(entry->DeepCopy());
+ overrides->Append(entry->CreateDeepCopy());
prefs_.SetUserPref(prefs::kSearchProviderOverrides, overrides);
int version = TemplateURLPrepopulateData::GetDataVersion(&prefs_);
EXPECT_EQ(1, version);
size_t default_index;
- ScopedVector<TemplateURLData> t_urls =
+ std::vector<std::unique_ptr<TemplateURLData>> t_urls =
TemplateURLPrepopulateData::GetPrepopulatedEngines(&prefs_,
&default_index);
@@ -163,7 +162,7 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
entry->Set("alternate_urls", alternate_urls);
entry->SetString("search_terms_replacement_key", "espv");
overrides = new base::ListValue;
- overrides->Append(entry->DeepCopy());
+ overrides->Append(entry->CreateDeepCopy());
prefs_.SetUserPref(prefs::kSearchProviderOverrides, overrides);
t_urls = TemplateURLPrepopulateData::GetPrepopulatedEngines(
@@ -187,17 +186,17 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
// Test that subsequent providers are loaded even if an intermediate
// provider has an incomplete configuration.
overrides = new base::ListValue;
- overrides->Append(entry->DeepCopy());
+ overrides->Append(entry->CreateDeepCopy());
entry->SetInteger("id", 1002);
entry->SetString("name", "bar");
entry->SetString("keyword", "bark");
entry->SetString("encoding", std::string());
- overrides->Append(entry->DeepCopy());
+ overrides->Append(entry->CreateDeepCopy());
entry->SetInteger("id", 1003);
entry->SetString("name", "baz");
entry->SetString("keyword", "bazk");
entry->SetString("encoding", "UTF-8");
- overrides->Append(entry->DeepCopy());
+ overrides->Append(entry->CreateDeepCopy());
prefs_.SetUserPref(prefs::kSearchProviderOverrides, overrides);
t_urls =
@@ -231,7 +230,7 @@ TEST_F(TemplateURLPrepopulateDataTest, ClearProvidersFromPrefs) {
EXPECT_EQ(TemplateURLPrepopulateData::kCurrentDataVersion, version);
size_t default_index;
- ScopedVector<TemplateURLData> t_urls =
+ std::vector<std::unique_ptr<TemplateURLData>> t_urls =
TemplateURLPrepopulateData::GetPrepopulatedEngines(&prefs_,
&default_index);
ASSERT_FALSE(t_urls.empty());
@@ -260,7 +259,7 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrepopulated) {
// Use United States.
prefs_.SetInteger(prefs::kCountryIDAtInstall, 'U'<<8|'S');
size_t default_index;
- ScopedVector<TemplateURLData> t_urls =
+ std::vector<std::unique_ptr<TemplateURLData>> t_urls =
TemplateURLPrepopulateData::GetPrepopulatedEngines(&prefs_,
&default_index);
diff --git a/chromium/components/search_engines/template_url_service.cc b/chromium/components/search_engines/template_url_service.cc
index 064a37db4e6..29a06edce37 100644
--- a/chromium/components/search_engines/template_url_service.cc
+++ b/chromium/components/search_engines/template_url_service.cc
@@ -8,14 +8,14 @@
#include <utility>
#include "base/auto_reset.h"
+#include "base/callback.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/guid.h"
#include "base/i18n/case_conversion.h"
-#include "base/memory/scoped_vector.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/profiler/scoped_tracker.h"
-#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -33,13 +33,13 @@
#include "components/search_engines/template_url_service_client.h"
#include "components/search_engines/template_url_service_observer.h"
#include "components/search_engines/util.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/protocol/search_engine_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
#include "components/url_formatter/url_fixer.h"
#include "components/url_formatter/url_formatter.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/protocol/search_engine_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
#include "url/gurl.h"
typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet;
@@ -182,7 +182,17 @@ size_t GetMeaningfulKeywordLength(const base::string16& keyword,
// The meaningful keyword length is the length of any portion before the
// registry ("co.uk") and its preceding dot.
return keyword.length() - (registry_length ? (registry_length + 1) : 0);
+}
+
+bool Contains(TemplateURLService::OwnedTemplateURLVector* template_urls,
+ TemplateURL* turl) {
+ return FindTemplateURL(template_urls, turl) != template_urls->end();
+}
+bool IsCreatedByExtension(TemplateURL* template_url) {
+ return template_url->type() ==
+ TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION ||
+ template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION;
}
} // namespace
@@ -206,9 +216,9 @@ class TemplateURLService::LessWithPrefix {
bool operator()(
const KeywordToTURLAndMeaningfulLength::value_type& elem1,
const KeywordToTURLAndMeaningfulLength::value_type& elem2) const {
- return (elem1.second.first == NULL) ?
- (elem2.first.compare(0, elem1.first.length(), elem1.first) > 0) :
- (elem1.first < elem2.first);
+ return (elem1.second.first == nullptr)
+ ? (elem2.first.compare(0, elem1.first.length(), elem1.first) > 0)
+ : (elem1.first < elem2.first);
}
};
@@ -235,7 +245,7 @@ TemplateURLService::TemplateURLService(
load_failed_(false),
disable_load_(false),
load_handle_(0),
- default_search_provider_(NULL),
+ default_search_provider_(nullptr),
next_id_(kInvalidTemplateURLID + 1),
clock_(new base::DefaultClock),
models_associated_(false),
@@ -246,22 +256,22 @@ TemplateURLService::TemplateURLService(
base::Bind(&TemplateURLService::OnDefaultSearchChange,
base::Unretained(this))) {
DCHECK(search_terms_data_);
- Init(NULL, 0);
+ Init(nullptr, 0);
}
TemplateURLService::TemplateURLService(const Initializer* initializers,
const int count)
- : prefs_(NULL),
+ : prefs_(nullptr),
search_terms_data_(new SearchTermsData),
- web_data_service_(NULL),
- google_url_tracker_(NULL),
- rappor_service_(NULL),
+ web_data_service_(nullptr),
+ google_url_tracker_(nullptr),
+ rappor_service_(nullptr),
provider_map_(new SearchHostToURLsMap),
loaded_(false),
load_failed_(false),
disable_load_(false),
load_handle_(0),
- default_search_provider_(NULL),
+ default_search_provider_(nullptr),
next_id_(kInvalidTemplateURLID + 1),
clock_(new base::DefaultClock),
models_associated_(false),
@@ -277,15 +287,19 @@ TemplateURLService::TemplateURLService(const Initializer* initializers,
TemplateURLService::~TemplateURLService() {
// |web_data_service_| should be deleted during Shutdown().
DCHECK(!web_data_service_.get());
- STLDeleteElements(&template_urls_);
}
// static
void TemplateURLService::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
+#if defined(OS_IOS) || defined(OS_ANDROID)
+ uint32_t flags = PrefRegistry::NO_REGISTRATION_FLAGS;
+#else
+ uint32_t flags = user_prefs::PrefRegistrySyncable::SYNCABLE_PREF;
+#endif
registry->RegisterStringPref(prefs::kSyncedDefaultSearchProviderGUID,
std::string(),
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ flags);
registry->RegisterBooleanPref(prefs::kDefaultSearchProviderEnabled, true);
registry->RegisterStringPref(prefs::kDefaultSearchProviderName,
std::string());
@@ -405,10 +419,10 @@ TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
keyword_to_turl_and_length_.find(keyword));
if (elem != keyword_to_turl_and_length_.end())
return elem->second.first;
- return (!loaded_ &&
- initial_default_search_provider_.get() &&
- (initial_default_search_provider_->keyword() == keyword)) ?
- initial_default_search_provider_.get() : NULL;
+ return (!loaded_ && initial_default_search_provider_ &&
+ (initial_default_search_provider_->keyword() == keyword))
+ ? initial_default_search_provider_.get()
+ : nullptr;
}
TemplateURL* TemplateURLService::GetTemplateURLForGUID(
@@ -416,10 +430,10 @@ TemplateURL* TemplateURLService::GetTemplateURLForGUID(
GUIDToTURL::const_iterator elem(guid_to_turl_.find(sync_guid));
if (elem != guid_to_turl_.end())
return elem->second;
- return (!loaded_ &&
- initial_default_search_provider_.get() &&
- (initial_default_search_provider_->sync_guid() == sync_guid)) ?
- initial_default_search_provider_.get() : NULL;
+ return (!loaded_ && initial_default_search_provider_ &&
+ (initial_default_search_provider_->sync_guid() == sync_guid))
+ ? initial_default_search_provider_.get()
+ : nullptr;
}
TemplateURL* TemplateURLService::GetTemplateURLForHost(
@@ -427,52 +441,59 @@ TemplateURL* TemplateURLService::GetTemplateURLForHost(
if (loaded_)
return provider_map_->GetTemplateURLForHost(host);
TemplateURL* initial_dsp = initial_default_search_provider_.get();
- if (!initial_dsp)
- return NULL;
- return (initial_dsp->GenerateSearchURL(search_terms_data()).host() == host) ?
- initial_dsp : NULL;
+ return (initial_dsp &&
+ (initial_dsp->GenerateSearchURL(search_terms_data()).host() == host))
+ ? initial_dsp
+ : nullptr;
}
-bool TemplateURLService::Add(TemplateURL* template_url) {
+TemplateURL* TemplateURLService::Add(
+ std::unique_ptr<TemplateURL> template_url) {
KeywordWebDataService::BatchModeScoper scoper(web_data_service_.get());
- if (!AddNoNotify(template_url, true))
- return false;
- NotifyObservers();
- return true;
+ TemplateURL* template_url_ptr = AddNoNotify(std::move(template_url), true);
+ if (template_url_ptr)
+ NotifyObservers();
+ return template_url_ptr;
}
-void TemplateURLService::AddWithOverrides(TemplateURL* template_url,
- const base::string16& short_name,
- const base::string16& keyword,
- const std::string& url) {
+TemplateURL* TemplateURLService::AddWithOverrides(
+ std::unique_ptr<TemplateURL> template_url,
+ const base::string16& short_name,
+ const base::string16& keyword,
+ const std::string& url) {
DCHECK(!short_name.empty());
DCHECK(!keyword.empty());
DCHECK(!url.empty());
template_url->data_.SetShortName(short_name);
template_url->data_.SetKeyword(keyword);
template_url->SetURL(url);
- Add(template_url);
+ return Add(std::move(template_url));
}
-void TemplateURLService::AddExtensionControlledTURL(
- TemplateURL* template_url,
+TemplateURL* TemplateURLService::AddExtensionControlledTURL(
+ std::unique_ptr<TemplateURL> template_url,
std::unique_ptr<TemplateURL::AssociatedExtensionInfo> info) {
DCHECK(loaded_);
DCHECK(template_url);
DCHECK_EQ(kInvalidTemplateURLID, template_url->id());
DCHECK(info);
- DCHECK_NE(TemplateURL::NORMAL, info->type);
+ DCHECK_NE(TemplateURL::NORMAL, template_url->type());
DCHECK_EQ(info->wants_to_be_default_engine,
template_url->show_in_default_list());
- DCHECK(!FindTemplateURLForExtension(info->extension_id, info->type));
+ DCHECK(
+ !FindTemplateURLForExtension(info->extension_id, template_url->type()));
template_url->extension_info_.swap(info);
KeywordWebDataService::BatchModeScoper scoper(web_data_service_.get());
- if (AddNoNotify(template_url, true)) {
- if (template_url->extension_info_->wants_to_be_default_engine)
+ TemplateURL* template_url_ptr = AddNoNotify(std::move(template_url), true);
+ if (template_url_ptr) {
+ if (template_url_ptr->extension_info_->wants_to_be_default_engine) {
UpdateExtensionDefaultSearchEngine();
+ }
NotifyObservers();
}
+
+ return template_url_ptr;
}
void TemplateURLService::Remove(TemplateURL* template_url) {
@@ -490,7 +511,7 @@ void TemplateURLService::RemoveExtensionControlledTURL(
// NULL this out so that we can call RemoveNoNotify.
// UpdateExtensionDefaultSearchEngine will cause it to be reset.
if (default_search_provider_ == url)
- default_search_provider_ = NULL;
+ default_search_provider_ = nullptr;
KeywordWebDataService::BatchModeScoper scoper(web_data_service_.get());
RemoveNoNotify(url);
UpdateExtensionDefaultSearchEngine();
@@ -503,25 +524,25 @@ void TemplateURLService::RemoveAutoGeneratedSince(base::Time created_after) {
void TemplateURLService::RemoveAutoGeneratedBetween(base::Time created_after,
base::Time created_before) {
- RemoveAutoGeneratedForOriginBetween(GURL(), created_after, created_before);
+ RemoveAutoGeneratedForUrlsBetween(base::Callback<bool(const GURL&)>(),
+ created_after, created_before);
}
-void TemplateURLService::RemoveAutoGeneratedForOriginBetween(
- const GURL& origin,
+void TemplateURLService::RemoveAutoGeneratedForUrlsBetween(
+ const base::Callback<bool(const GURL&)>& url_filter,
base::Time created_after,
base::Time created_before) {
- GURL o(origin.GetOrigin());
bool should_notify = false;
KeywordWebDataService::BatchModeScoper scoper(web_data_service_.get());
for (size_t i = 0; i < template_urls_.size();) {
if (template_urls_[i]->date_created() >= created_after &&
(created_before.is_null() ||
template_urls_[i]->date_created() < created_before) &&
- CanReplace(template_urls_[i]) &&
- (o.is_empty() ||
- template_urls_[i]->GenerateSearchURL(
- search_terms_data()).GetOrigin() == o)) {
- RemoveNoNotify(template_urls_[i]);
+ CanReplace(template_urls_[i].get()) &&
+ (url_filter.is_null() ||
+ url_filter.Run(
+ template_urls_[i]->GenerateSearchURL(search_terms_data())))) {
+ RemoveNoNotify(template_urls_[i].get());
should_notify = true;
} else {
++i;
@@ -546,24 +567,26 @@ void TemplateURLService::RegisterOmniboxKeyword(
data.SetShortName(base::UTF8ToUTF16(extension_name));
data.SetKeyword(base::UTF8ToUTF16(keyword));
data.SetURL(template_url_string);
- TemplateURL* url = new TemplateURL(data);
std::unique_ptr<TemplateURL::AssociatedExtensionInfo> info(
- new TemplateURL::AssociatedExtensionInfo(
- TemplateURL::OMNIBOX_API_EXTENSION, extension_id));
- AddExtensionControlledTURL(url, std::move(info));
+ new TemplateURL::AssociatedExtensionInfo(extension_id));
+ AddExtensionControlledTURL(
+ base::MakeUnique<TemplateURL>(data, TemplateURL::OMNIBOX_API_EXTENSION),
+ std::move(info));
}
TemplateURLService::TemplateURLVector TemplateURLService::GetTemplateURLs() {
- return template_urls_;
+ TemplateURLVector result;
+ for (const auto& turl : template_urls_)
+ result.push_back(turl.get());
+ return result;
}
void TemplateURLService::IncrementUsageCount(TemplateURL* url) {
DCHECK(url);
// Extension-controlled search engines are not persisted.
- if (url->GetType() != TemplateURL::NORMAL)
+ if (url->type() != TemplateURL::NORMAL)
return;
- if (std::find(template_urls_.begin(), template_urls_.end(), url) ==
- template_urls_.end())
+ if (!Contains(&template_urls_, url))
return;
++url->data_.usage_count;
@@ -586,7 +609,7 @@ bool TemplateURLService::CanMakeDefault(const TemplateURL* url) {
DefaultSearchManager::FROM_FALLBACK)) &&
(url != GetDefaultSearchProvider()) &&
url->url_ref().SupportsReplacement(search_terms_data()) &&
- (url->GetType() == TemplateURL::NORMAL);
+ (url->type() == TemplateURL::NORMAL);
}
void TemplateURLService::SetUserSelectedDefaultSearchProvider(
@@ -594,13 +617,13 @@ void TemplateURLService::SetUserSelectedDefaultSearchProvider(
// Omnibox keywords cannot be made default. Extension-controlled search
// engines can be made default only by the extension itself because they
// aren't persisted.
- DCHECK(!url || (url->GetType() == TemplateURL::NORMAL));
+ DCHECK(!url || !IsCreatedByExtension(url));
if (load_failed_) {
// Skip the DefaultSearchManager, which will persist to user preferences.
if ((default_search_provider_source_ == DefaultSearchManager::FROM_USER) ||
(default_search_provider_source_ ==
DefaultSearchManager::FROM_FALLBACK)) {
- ApplyDefaultSearchChange(url ? &url->data() : NULL,
+ ApplyDefaultSearchChange(url ? &url->data() : nullptr,
DefaultSearchManager::FROM_USER);
}
} else {
@@ -644,11 +667,11 @@ void TemplateURLService::RepairPrepopulatedSearchEngines() {
DefaultSearchManager::FROM_FALLBACK)) {
// Clear |default_search_provider_| in case we want to remove the engine it
// points to. This will get reset at the end of the function anyway.
- default_search_provider_ = NULL;
+ default_search_provider_ = nullptr;
}
size_t default_search_provider_index = 0;
- ScopedVector<TemplateURLData> prepopulated_urls =
+ std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
TemplateURLPrepopulateData::GetPrepopulatedEngines(
prefs_, &default_search_provider_index);
DCHECK(!prepopulated_urls.empty());
@@ -674,7 +697,7 @@ void TemplateURLService::RepairPrepopulatedSearchEngines() {
actions.added_engines.begin();
i < actions.added_engines.end();
++i) {
- AddNoNotify(new TemplateURL(*i), true);
+ AddNoNotify(base::MakeUnique<TemplateURL>(*i), true);
}
base::AutoReset<DefaultSearchChangeOrigin> change_origin(
@@ -745,12 +768,13 @@ void TemplateURLService::OnWebDataServiceRequestDone(
// Results are null if the database went away or (most likely) wasn't
// loaded.
load_failed_ = true;
- web_data_service_ = NULL;
+ web_data_service_ = nullptr;
ChangeToLoadedState();
return;
}
- TemplateURLVector template_urls;
+ std::unique_ptr<OwnedTemplateURLVector> template_urls =
+ base::MakeUnique<OwnedTemplateURLVector>();
int new_resource_keyword_version = 0;
{
// TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
@@ -760,10 +784,10 @@ void TemplateURLService::OnWebDataServiceRequestDone(
"422460 TemplateURLService::OnWebDataServiceRequestDone 2"));
GetSearchProvidersUsingKeywordResult(
- *result, web_data_service_.get(), prefs_, &template_urls,
+ *result, web_data_service_.get(), prefs_, template_urls.get(),
(default_search_provider_source_ == DefaultSearchManager::FROM_USER)
? initial_default_search_provider_.get()
- : NULL,
+ : nullptr,
search_terms_data(), &new_resource_keyword_version, &pre_sync_deletes_);
}
@@ -776,7 +800,7 @@ void TemplateURLService::OnWebDataServiceRequestDone(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"422460 TemplateURLService::OnWebDataServiceRequestDone 4"));
- PatchMissingSyncGUIDs(&template_urls);
+ PatchMissingSyncGUIDs(template_urls.get());
// TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
// is fixed.
@@ -784,7 +808,7 @@ void TemplateURLService::OnWebDataServiceRequestDone(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"422460 TemplateURLService::OnWebDataServiceRequestDone 41"));
- SetTemplateURLs(&template_urls);
+ SetTemplateURLs(std::move(template_urls));
// TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
// is fixed.
@@ -850,7 +874,7 @@ base::string16 TemplateURLService::GetKeywordShortName(
// to track changes to the model, this should become a DCHECK.
if (template_url) {
*is_omnibox_api_extension_keyword =
- template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
+ template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION;
return template_url->AdjustedShortNameForLocaleDirection();
}
*is_omnibox_api_extension_keyword = false;
@@ -874,7 +898,7 @@ void TemplateURLService::Shutdown() {
DCHECK(web_data_service_.get());
web_data_service_->CancelRequest(load_handle_);
}
- web_data_service_ = NULL;
+ web_data_service_ = nullptr;
}
syncer::SyncDataList TemplateURLService::GetAllSyncData(
@@ -882,15 +906,14 @@ syncer::SyncDataList TemplateURLService::GetAllSyncData(
DCHECK_EQ(syncer::SEARCH_ENGINES, type);
syncer::SyncDataList current_data;
- for (TemplateURLVector::const_iterator iter = template_urls_.begin();
- iter != template_urls_.end(); ++iter) {
+ for (const auto& turl : template_urls_) {
// We don't sync keywords managed by policy.
- if ((*iter)->created_by_policy())
+ if (turl->created_by_policy())
continue;
// We don't sync extension-controlled search engines.
- if ((*iter)->GetType() != TemplateURL::NORMAL)
+ if (turl->type() != TemplateURL::NORMAL)
continue;
- current_data.push_back(CreateSyncDataFromTemplateURL(**iter));
+ current_data.push_back(CreateSyncDataFromTemplateURL(*turl));
}
return current_data;
@@ -998,8 +1021,10 @@ syncer::SyncError TemplateURLService::ProcessSyncChanges(
// Force the local ID to kInvalidTemplateURLID so we can add it.
TemplateURLData data(turl->data());
data.id = kInvalidTemplateURLID;
- TemplateURL* added = new TemplateURL(data);
- if (Add(added))
+ std::unique_ptr<TemplateURL> added_ptr =
+ base::MakeUnique<TemplateURL>(data);
+ TemplateURL* added = added_ptr.get();
+ if (Add(std::move(added_ptr)))
MaybeUpdateDSEAfterSync(added);
} else if (iter->change_type() == syncer::SyncChange::ACTION_UPDATE) {
if (!existing_turl) {
@@ -1192,7 +1217,7 @@ void TemplateURLService::ProcessTemplateURLChange(
return;
// Avoid syncing extension-controlled search engines.
- if (turl->GetType() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION)
+ if (turl->type() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION)
return;
syncer::SyncChangeList changes;
@@ -1272,7 +1297,7 @@ TemplateURLService::CreateTemplateURLFromTemplateURLAndSyncData(
sync_data));
UMA_HISTOGRAM_ENUMERATION(kDeleteSyncedEngineHistogramName,
DELETE_ENGINE_EMPTY_FIELD, DELETE_ENGINE_MAX);
- return NULL;
+ return nullptr;
}
TemplateURLData data(existing_turl ?
@@ -1326,17 +1351,19 @@ TemplateURLService::CreateTemplateURLFromTemplateURLAndSyncData(
UpdateTemplateURLIfPrepopulated(turl.get(), prefs);
// We used to sync keywords associated with omnibox extensions, but no longer
- // want to. However, if we delete these keywords from sync, we'll break any
- // synced old versions of Chrome which were relying on them. Instead, for now
- // we simply ignore these.
- // TODO(vasilii): After a few Chrome versions, change this to go ahead and
- // delete these from sync.
+ // want to. Delete them from the server.
+ // TODO(vasilii): After a few Chrome versions, delete this code together with
+ // IsOmniboxExtensionURL().
DCHECK(client);
- client->RestoreExtensionInfoIfNecessary(turl.get());
- if (turl->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)
- return NULL;
+ if (client->IsOmniboxExtensionURL(turl->url())) {
+ change_list->push_back(
+ syncer::SyncChange(FROM_HERE,
+ syncer::SyncChange::ACTION_DELETE,
+ sync_data));
+ return nullptr;
+ }
- DCHECK_EQ(TemplateURL::NORMAL, turl->GetType());
+ DCHECK_EQ(TemplateURL::NORMAL, turl->type());
if (reset_keyword || deduped) {
if (reset_keyword)
turl->ResetKeywordIfNecessary(search_terms_data, true);
@@ -1418,8 +1445,7 @@ void TemplateURLService::Init(const Initializer* initializers,
data.SetShortName(base::UTF8ToUTF16(initializers[i].content));
data.SetKeyword(base::UTF8ToUTF16(initializers[i].keyword));
data.SetURL(initializers[i].url);
- TemplateURL* template_url = new TemplateURL(data);
- AddNoNotify(template_url, true);
+ AddNoNotify(base::MakeUnique<TemplateURL>(data), true);
// Set the first provided identifier to be the default.
if (i == 0)
@@ -1442,18 +1468,16 @@ void TemplateURLService::RemoveFromMaps(TemplateURL* template_url) {
// In the case of more than one extension, we use the most recently
// installed (which will be the most recently added, which will have the
// highest ID).
- TemplateURL* best_fallback = NULL;
- for (TemplateURLVector::const_iterator i(template_urls_.begin());
- i != template_urls_.end(); ++i) {
- TemplateURL* turl = *i;
+ TemplateURL* best_fallback = nullptr;
+ for (const auto& turl : template_urls_) {
// This next statement relies on the fact that there can only be one
// non-Omnibox API TemplateURL with a given keyword.
- if ((turl != template_url) && (turl->keyword() == keyword) &&
+ if ((turl.get() != template_url) && (turl->keyword() == keyword) &&
(!best_fallback ||
- (best_fallback->GetType() != TemplateURL::OMNIBOX_API_EXTENSION) ||
- ((turl->GetType() == TemplateURL::OMNIBOX_API_EXTENSION) &&
+ (best_fallback->type() != TemplateURL::OMNIBOX_API_EXTENSION) ||
+ ((turl->type() == TemplateURL::OMNIBOX_API_EXTENSION) &&
(turl->id() > best_fallback->id()))))
- best_fallback = turl;
+ best_fallback = turl.get();
}
RemoveFromDomainMap(template_url);
if (best_fallback) {
@@ -1464,7 +1488,7 @@ void TemplateURLService::RemoveFromMaps(TemplateURL* template_url) {
}
}
- if (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)
+ if (template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)
return;
if (!template_url->sync_guid().empty())
@@ -1477,7 +1501,7 @@ void TemplateURLService::RemoveFromMaps(TemplateURL* template_url) {
void TemplateURLService::AddToMaps(TemplateURL* template_url) {
bool template_url_is_omnibox_api =
- template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
+ template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION;
const base::string16& keyword = template_url->keyword();
KeywordToTURLAndMeaningfulLength::const_iterator i =
keyword_to_turl_and_length_.find(keyword);
@@ -1491,7 +1515,7 @@ void TemplateURLService::AddToMaps(TemplateURL* template_url) {
// Manually-modified keywords > extension keywords > replaceable keywords
// When there are multiple extensions, the last-added wins.
bool existing_url_is_omnibox_api =
- existing_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
+ existing_url->type() == TemplateURL::OMNIBOX_API_EXTENSION;
DCHECK(existing_url_is_omnibox_api || template_url_is_omnibox_api);
if (existing_url_is_omnibox_api ?
!CanReplace(template_url) : CanReplace(existing_url)) {
@@ -1545,37 +1569,29 @@ void TemplateURLService::AddToMap(TemplateURL* template_url) {
template_url, GetMeaningfulKeywordLength(keyword, template_url));
}
-// Helper for partition() call in next function.
-bool HasValidID(TemplateURL* t_url) {
- return t_url->id() != kInvalidTemplateURLID;
-}
-
-void TemplateURLService::SetTemplateURLs(TemplateURLVector* urls) {
+void TemplateURLService::SetTemplateURLs(
+ std::unique_ptr<OwnedTemplateURLVector> urls) {
// Partition the URLs first, instead of implementing the loops below by simply
// scanning the input twice. While it's not supposed to happen normally, it's
// possible for corrupt databases to return multiple entries with the same
// keyword. In this case, the first loop may delete the first entry when
// adding the second. If this happens, the second loop must not attempt to
// access the deleted entry. Partitioning ensures this constraint.
- TemplateURLVector::iterator first_invalid(
- std::partition(urls->begin(), urls->end(), HasValidID));
+ auto first_invalid = std::partition(
+ urls->begin(), urls->end(), [](const std::unique_ptr<TemplateURL>& turl) {
+ return turl->id() != kInvalidTemplateURLID;
+ });
// First, add the items that already have id's, so that the next_id_ gets
// properly set.
- for (TemplateURLVector::const_iterator i = urls->begin(); i != first_invalid;
- ++i) {
+ for (auto i = urls->begin(); i != first_invalid; ++i) {
next_id_ = std::max(next_id_, (*i)->id());
- AddNoNotify(*i, false);
+ AddNoNotify(std::move(*i), false);
}
// Next add the new items that don't have id's.
- for (TemplateURLVector::const_iterator i = first_invalid; i != urls->end();
- ++i)
- AddNoNotify(*i, true);
-
- // Clear the input vector to reduce the chance callers will try to use a
- // (possibly deleted) entry.
- urls->clear();
+ for (auto i = first_invalid; i != urls->end(); ++i)
+ AddNoNotify(std::move(*i), true);
}
void TemplateURLService::ChangeToLoadedState() {
@@ -1598,8 +1614,9 @@ void TemplateURLService::ChangeToLoadedState() {
// This will cause a call to NotifyObservers().
ApplyDefaultSearchChangeNoMetrics(
- initial_default_search_provider_ ?
- &initial_default_search_provider_->data() : NULL,
+ initial_default_search_provider_
+ ? &initial_default_search_provider_->data()
+ : nullptr,
default_search_provider_source_);
initial_default_search_provider_.reset();
@@ -1632,27 +1649,25 @@ bool TemplateURLService::CanReplace(const TemplateURL* t_url) {
TemplateURL* TemplateURLService::FindNonExtensionTemplateURLForKeyword(
const base::string16& keyword) {
TemplateURL* keyword_turl = GetTemplateURLForKeyword(keyword);
- if (!keyword_turl || (keyword_turl->GetType() == TemplateURL::NORMAL))
+ if (!keyword_turl || (keyword_turl->type() == TemplateURL::NORMAL))
return keyword_turl;
// The extension keyword in the model may be hiding a replaceable
// non-extension keyword. Look for it.
- for (TemplateURLVector::const_iterator i(template_urls_.begin());
- i != template_urls_.end(); ++i) {
- if (((*i)->GetType() == TemplateURL::NORMAL) &&
- ((*i)->keyword() == keyword))
- return *i;
+ for (const auto& turl : template_urls_) {
+ if ((turl->type() == TemplateURL::NORMAL) &&
+ (turl->keyword() == keyword))
+ return turl.get();
}
- return NULL;
+ return nullptr;
}
bool TemplateURLService::UpdateNoNotify(TemplateURL* existing_turl,
const TemplateURL& new_values) {
DCHECK(existing_turl);
- if (std::find(template_urls_.begin(), template_urls_.end(), existing_turl) ==
- template_urls_.end())
+ if (!Contains(&template_urls_, existing_turl))
return false;
- DCHECK_NE(TemplateURL::OMNIBOX_API_EXTENSION, existing_turl->GetType());
+ DCHECK_NE(TemplateURL::OMNIBOX_API_EXTENSION, existing_turl->type());
base::string16 old_keyword(existing_turl->keyword());
keyword_to_turl_and_length_.erase(old_keyword);
@@ -1688,7 +1703,7 @@ bool TemplateURLService::UpdateNoNotify(TemplateURL* existing_turl,
// case we delete the existing keyword if it's replaceable, or else undo
// the change in keyword for |existing_turl|.
TemplateURL* existing_keyword_turl = i->second.first;
- if (existing_keyword_turl->GetType() != TemplateURL::NORMAL) {
+ if (existing_keyword_turl->type() != TemplateURL::NORMAL) {
if (!CanReplace(existing_turl)) {
AddToMap(existing_turl);
AddToDomainMap(existing_turl);
@@ -1730,14 +1745,14 @@ void TemplateURLService::UpdateTemplateURLIfPrepopulated(
return;
size_t default_search_index;
- ScopedVector<TemplateURLData> prepopulated_urls =
- TemplateURLPrepopulateData::GetPrepopulatedEngines(
- prefs, &default_search_index);
-
- for (size_t i = 0; i < prepopulated_urls.size(); ++i) {
- if (prepopulated_urls[i]->prepopulate_id == prepopulate_id) {
- MergeIntoPrepopulatedEngineData(template_url, prepopulated_urls[i]);
- template_url->CopyFrom(TemplateURL(*prepopulated_urls[i]));
+ std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
+ TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs,
+ &default_search_index);
+
+ for (const auto& url : prepopulated_urls) {
+ if (url->prepopulate_id == prepopulate_id) {
+ MergeIntoPrepopulatedEngineData(template_url, url.get());
+ template_url->CopyFrom(TemplateURL(*url));
}
}
}
@@ -1822,32 +1837,30 @@ void TemplateURLService::GoogleBaseURLChanged() {
KeywordWebDataService::BatchModeScoper scoper(web_data_service_.get());
bool something_changed = false;
- for (TemplateURLVector::iterator i(template_urls_.begin());
- i != template_urls_.end(); ++i) {
- TemplateURL* t_url = *i;
- if (t_url->HasGoogleBaseURLs(search_terms_data())) {
- TemplateURL updated_turl(t_url->data());
+ for (const auto& turl : template_urls_) {
+ if (turl->HasGoogleBaseURLs(search_terms_data())) {
+ TemplateURL updated_turl(turl->data());
updated_turl.ResetKeywordIfNecessary(search_terms_data(), false);
KeywordToTURLAndMeaningfulLength::const_iterator existing_entry =
keyword_to_turl_and_length_.find(updated_turl.keyword());
if ((existing_entry != keyword_to_turl_and_length_.end()) &&
- (existing_entry->second.first != t_url)) {
+ (existing_entry->second.first != turl.get())) {
// The new autogenerated keyword conflicts with another TemplateURL.
- // Overwrite it if it's replaceable; otherwise, leave |t_url| using its
- // current keyword. (This will not prevent |t_url| from auto-updating
+ // Overwrite it if it's replaceable; otherwise, leave |turl| using its
+ // current keyword. (This will not prevent |turl| from auto-updating
// the keyword in the future if the conflicting TemplateURL disappears.)
- // Note that we must still update |t_url| in this case, or the
+ // Note that we must still update |turl| in this case, or the
// |provider_map_| will not be updated correctly.
if (CanReplace(existing_entry->second.first))
RemoveNoNotify(existing_entry->second.first);
else
- updated_turl.data_.SetKeyword(t_url->keyword());
+ updated_turl.data_.SetKeyword(turl->keyword());
}
something_changed = true;
// This will send the keyword change to sync. Note that other clients
// need to reset the keyword to an appropriate local value when this
// change arrives; see CreateTemplateURLFromTemplateURLAndSyncData().
- UpdateNoNotify(t_url, updated_turl);
+ UpdateNoNotify(turl.get(), updated_turl);
}
}
if (something_changed)
@@ -1890,8 +1903,8 @@ bool TemplateURLService::ApplyDefaultSearchChangeNoMetrics(
// default.
bool changed = TemplateURL::MatchesData(
initial_default_search_provider_.get(), data, search_terms_data());
- initial_default_search_provider_.reset(
- data ? new TemplateURL(*data) : NULL);
+ initial_default_search_provider_ =
+ data ? base::MakeUnique<TemplateURL>(*data) : nullptr;
default_search_provider_source_ = source;
return changed;
}
@@ -1900,7 +1913,7 @@ bool TemplateURLService::ApplyDefaultSearchChangeNoMetrics(
// Note that we exclude the case of data == NULL because that could cause a
// false positive for recursion when the initial_default_search_provider_ is
// NULL due to policy. We'll never actually get recursion with data == NULL.
- if (source == default_search_provider_source_ && data != NULL &&
+ if (source == default_search_provider_source_ && data != nullptr &&
TemplateURL::MatchesData(default_search_provider_, data,
search_terms_data()))
return false;
@@ -1916,11 +1929,11 @@ bool TemplateURLService::ApplyDefaultSearchChangeNoMetrics(
// well as to add the new one, if appropriate.
UpdateProvidersCreatedByPolicy(
&template_urls_,
- source == DefaultSearchManager::FROM_POLICY ? data : NULL);
+ source == DefaultSearchManager::FROM_POLICY ? data : nullptr);
}
if (!data) {
- default_search_provider_ = NULL;
+ default_search_provider_ = nullptr;
} else if (source == DefaultSearchManager::FROM_EXTENSION) {
default_search_provider_ = FindMatchingExtensionTemplateURL(
*data, TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION);
@@ -1942,8 +1955,10 @@ bool TemplateURLService::ApplyDefaultSearchChangeNoMetrics(
// (1) Tests that initialize the TemplateURLService in peculiar ways.
// (2) If the user deleted the pre-populated default and we subsequently
// lost their user-selected value.
- TemplateURL* new_dse = new TemplateURL(*data);
- if (AddNoNotify(new_dse, true))
+ std::unique_ptr<TemplateURL> new_dse_ptr =
+ base::MakeUnique<TemplateURL>(*data);
+ TemplateURL* new_dse = new_dse_ptr.get();
+ if (AddNoNotify(std::move(new_dse_ptr), true))
default_search_provider_ = new_dse;
}
} else if (source == DefaultSearchManager::FROM_USER) {
@@ -1958,8 +1973,10 @@ bool TemplateURLService::ApplyDefaultSearchChangeNoMetrics(
UpdateNoNotify(default_search_provider_, TemplateURL(new_data));
} else {
new_data.id = kInvalidTemplateURLID;
- TemplateURL* new_dse = new TemplateURL(new_data);
- if (AddNoNotify(new_dse, true))
+ std::unique_ptr<TemplateURL> new_dse_ptr =
+ base::MakeUnique<TemplateURL>(new_data);
+ TemplateURL* new_dse = new_dse_ptr.get();
+ if (AddNoNotify(std::move(new_dse_ptr), true))
default_search_provider_ = new_dse;
}
if (default_search_provider_ && prefs_) {
@@ -1980,14 +1997,14 @@ bool TemplateURLService::ApplyDefaultSearchChangeNoMetrics(
return changed;
}
-bool TemplateURLService::AddNoNotify(TemplateURL* template_url,
- bool newly_adding) {
+TemplateURL* TemplateURLService::AddNoNotify(
+ std::unique_ptr<TemplateURL> template_url,
+ bool newly_adding) {
DCHECK(template_url);
if (newly_adding) {
DCHECK_EQ(kInvalidTemplateURLID, template_url->id());
- DCHECK(std::find(template_urls_.begin(), template_urls_.end(),
- template_url) == template_urls_.end());
+ DCHECK(!Contains(&template_urls_, template_url.get()));
template_url->data_.id = ++next_id_;
}
@@ -2006,21 +2023,19 @@ bool TemplateURLService::AddNoNotify(TemplateURL* template_url,
// that any "pre-existing" entries we find are actually coming from
// |template_urls_|, lest we detect a "conflict" between the
// |initial_default_search_provider_| and the web data version of itself.
- if (template_url->GetType() != TemplateURL::OMNIBOX_API_EXTENSION &&
+ if (template_url->type() != TemplateURL::OMNIBOX_API_EXTENSION &&
existing_keyword_turl &&
- existing_keyword_turl->GetType() != TemplateURL::OMNIBOX_API_EXTENSION &&
- (std::find(template_urls_.begin(), template_urls_.end(),
- existing_keyword_turl) != template_urls_.end())) {
- DCHECK_NE(existing_keyword_turl, template_url);
+ existing_keyword_turl->type() != TemplateURL::OMNIBOX_API_EXTENSION &&
+ Contains(&template_urls_, existing_keyword_turl)) {
+ DCHECK_NE(existing_keyword_turl, template_url.get());
// Only replace one of the TemplateURLs if they are either both extensions,
// or both not extensions.
- bool are_same_type = existing_keyword_turl->GetType() ==
- template_url->GetType();
+ bool are_same_type = IsCreatedByExtension(existing_keyword_turl) ==
+ IsCreatedByExtension(template_url.get());
if (CanReplace(existing_keyword_turl) && are_same_type) {
RemoveNoNotify(existing_keyword_turl);
- } else if (CanReplace(template_url) && are_same_type) {
- delete template_url;
- return false;
+ } else if (CanReplace(template_url.get()) && are_same_type) {
+ return nullptr;
} else {
base::string16 new_keyword =
UniquifyKeyword(*existing_keyword_turl, false);
@@ -2029,38 +2044,37 @@ bool TemplateURLService::AddNoNotify(TemplateURL* template_url,
existing_keyword_turl->url());
}
}
- template_urls_.push_back(template_url);
- AddToMaps(template_url);
+ TemplateURL* template_url_ptr = template_url.get();
+ template_urls_.push_back(std::move(template_url));
+ AddToMaps(template_url_ptr);
- if (newly_adding &&
- (template_url->GetType() == TemplateURL::NORMAL)) {
+ if (newly_adding && (template_url_ptr->type() == TemplateURL::NORMAL)) {
if (web_data_service_.get())
- web_data_service_->AddKeyword(template_url->data());
+ web_data_service_->AddKeyword(template_url_ptr->data());
// Inform sync of the addition. Note that this will assign a GUID to
// template_url and add it to the guid_to_turl_.
- ProcessTemplateURLChange(FROM_HERE,
- template_url,
+ ProcessTemplateURLChange(FROM_HERE, template_url_ptr,
syncer::SyncChange::ACTION_ADD);
}
- return true;
+ return template_url_ptr;
}
void TemplateURLService::RemoveNoNotify(TemplateURL* template_url) {
DCHECK(template_url != default_search_provider_);
- TemplateURLVector::iterator i =
- std::find(template_urls_.begin(), template_urls_.end(), template_url);
+ auto i = FindTemplateURL(&template_urls_, template_url);
if (i == template_urls_.end())
return;
RemoveFromMaps(template_url);
// Remove it from the vector containing all TemplateURLs.
+ std::unique_ptr<TemplateURL> scoped_turl = std::move(*i);
template_urls_.erase(i);
- if (template_url->GetType() == TemplateURL::NORMAL) {
+ if (template_url->type() == TemplateURL::NORMAL) {
if (web_data_service_.get())
web_data_service_->RemoveKeyword(template_url->id());
@@ -2075,9 +2089,6 @@ void TemplateURLService::RemoveNoNotify(TemplateURL* template_url) {
if (loaded_ && client_)
client_->DeleteAllSearchTermsForKeyword(template_url->id());
-
- // We own the TemplateURL and need to delete it.
- delete template_url;
}
bool TemplateURLService::ResetTemplateURLNoNotify(
@@ -2116,13 +2127,12 @@ void TemplateURLService::NotifyObservers() {
// that were set by policy, unless it is the current default search provider, in
// which case it is updated with the data from prefs.
void TemplateURLService::UpdateProvidersCreatedByPolicy(
- TemplateURLVector* template_urls,
+ OwnedTemplateURLVector* template_urls,
const TemplateURLData* default_from_prefs) {
DCHECK(template_urls);
- for (TemplateURLVector::iterator i = template_urls->begin();
- i != template_urls->end(); ) {
- TemplateURL* template_url = *i;
+ for (auto i = template_urls->begin(); i != template_urls->end();) {
+ TemplateURL* template_url = i->get();
if (template_url->created_by_policy()) {
if (default_from_prefs &&
TemplateURL::MatchesData(template_url, default_from_prefs,
@@ -2133,30 +2143,32 @@ void TemplateURLService::UpdateProvidersCreatedByPolicy(
// database and the |default_search_provider|.
default_search_provider_ = template_url;
// Prevent us from saving any other entries, or creating a new one.
- default_from_prefs = NULL;
+ default_from_prefs = nullptr;
++i;
continue;
}
+ TemplateURLID id = template_url->id();
RemoveFromMaps(template_url);
i = template_urls->erase(i);
if (web_data_service_.get())
- web_data_service_->RemoveKeyword(template_url->id());
- delete template_url;
+ web_data_service_->RemoveKeyword(id);
} else {
++i;
}
}
if (default_from_prefs) {
- default_search_provider_ = NULL;
+ default_search_provider_ = nullptr;
default_search_provider_source_ = DefaultSearchManager::FROM_POLICY;
TemplateURLData new_data(*default_from_prefs);
if (new_data.sync_guid.empty())
new_data.sync_guid = base::GenerateGUID();
new_data.created_by_policy = true;
- TemplateURL* new_dse = new TemplateURL(new_data);
- if (AddNoNotify(new_dse, true))
+ std::unique_ptr<TemplateURL> new_dse_ptr =
+ base::MakeUnique<TemplateURL>(new_data);
+ TemplateURL* new_dse = new_dse_ptr.get();
+ if (AddNoNotify(std::move(new_dse_ptr), true))
default_search_provider_ = new_dse;
}
}
@@ -2182,7 +2194,7 @@ base::string16 TemplateURLService::UniquifyKeyword(const TemplateURL& turl,
// for extensions, as their keywords are not associated with their URLs).
GURL gurl(turl.url());
if (gurl.is_valid() &&
- (turl.GetType() != TemplateURL::OMNIBOX_API_EXTENSION)) {
+ (turl.type() != TemplateURL::OMNIBOX_API_EXTENSION)) {
base::string16 keyword_candidate = TemplateURL::GenerateKeyword(gurl);
if (!GetTemplateURLForKeyword(keyword_candidate))
return keyword_candidate;
@@ -2218,7 +2230,7 @@ void TemplateURLService::ResolveSyncKeywordConflict(
DCHECK(applied_sync_turl);
DCHECK(change_list);
DCHECK_EQ(applied_sync_turl->keyword(), unapplied_sync_turl->keyword());
- DCHECK_EQ(TemplateURL::NORMAL, applied_sync_turl->GetType());
+ DCHECK_EQ(TemplateURL::NORMAL, applied_sync_turl->type());
// Both |unapplied_sync_turl| and |applied_sync_turl| are known to Sync, so
// don't delete either of them. Instead, determine which is "better" and
@@ -2346,25 +2358,24 @@ void TemplateURLService::MergeInSyncTemplateURL(
// Force the local ID to kInvalidTemplateURLID so we can add it.
TemplateURLData data(sync_turl->data());
data.id = kInvalidTemplateURLID;
- TemplateURL* added = new TemplateURL(data);
+ std::unique_ptr<TemplateURL> added_ptr =
+ base::MakeUnique<TemplateURL>(data);
+ TemplateURL* added = added_ptr.get();
base::AutoReset<DefaultSearchChangeOrigin> change_origin(
&dsp_change_origin_, DSP_CHANGE_SYNC_ADD);
- if (Add(added))
+ if (Add(std::move(added_ptr)))
MaybeUpdateDSEAfterSync(added);
- merge_result->set_num_items_added(
- merge_result->num_items_added() + 1);
+ merge_result->set_num_items_added(merge_result->num_items_added() + 1);
}
}
void TemplateURLService::PatchMissingSyncGUIDs(
- TemplateURLVector* template_urls) {
+ OwnedTemplateURLVector* template_urls) {
DCHECK(template_urls);
- for (TemplateURLVector::iterator i = template_urls->begin();
- i != template_urls->end(); ++i) {
- TemplateURL* template_url = *i;
+ for (auto& template_url : *template_urls) {
DCHECK(template_url);
if (template_url->sync_guid().empty() &&
- (template_url->GetType() == TemplateURL::NORMAL)) {
+ (template_url->type() == TemplateURL::NORMAL)) {
template_url->data_.sync_guid = base::GenerateGUID();
if (web_data_service_.get())
web_data_service_->UpdateKeyword(template_url->data());
@@ -2419,51 +2430,46 @@ void TemplateURLService::AddMatchingKeywordsHelper(
TemplateURL* TemplateURLService::FindPrepopulatedTemplateURL(
int prepopulated_id) {
- for (TemplateURLVector::const_iterator i = template_urls_.begin();
- i != template_urls_.end(); ++i) {
- if ((*i)->prepopulate_id() == prepopulated_id)
- return *i;
+ for (const auto& turl : template_urls_) {
+ if (turl->prepopulate_id() == prepopulated_id)
+ return turl.get();
}
- return NULL;
+ return nullptr;
}
TemplateURL* TemplateURLService::FindTemplateURLForExtension(
const std::string& extension_id,
TemplateURL::Type type) {
DCHECK_NE(TemplateURL::NORMAL, type);
- for (TemplateURLVector::const_iterator i = template_urls_.begin();
- i != template_urls_.end(); ++i) {
- if ((*i)->GetType() == type &&
- (*i)->GetExtensionId() == extension_id)
- return *i;
+ for (const auto& turl : template_urls_) {
+ if (turl->type() == type && turl->GetExtensionId() == extension_id)
+ return turl.get();
}
- return NULL;
+ return nullptr;
}
TemplateURL* TemplateURLService::FindMatchingExtensionTemplateURL(
const TemplateURLData& data,
TemplateURL::Type type) {
DCHECK_NE(TemplateURL::NORMAL, type);
- for (TemplateURLVector::const_iterator i = template_urls_.begin();
- i != template_urls_.end(); ++i) {
- if ((*i)->GetType() == type &&
- TemplateURL::MatchesData(*i, &data, search_terms_data()))
- return *i;
+ for (const auto& turl : template_urls_) {
+ if (turl->type() == type &&
+ TemplateURL::MatchesData(turl.get(), &data, search_terms_data()))
+ return turl.get();
}
- return NULL;
+ return nullptr;
}
void TemplateURLService::UpdateExtensionDefaultSearchEngine() {
- TemplateURL* most_recently_intalled_default = NULL;
- for (TemplateURLVector::const_iterator i = template_urls_.begin();
- i != template_urls_.end(); ++i) {
- if (((*i)->GetType() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION) &&
- (*i)->extension_info_->wants_to_be_default_engine &&
- (*i)->SupportsReplacement(search_terms_data()) &&
+ TemplateURL* most_recently_intalled_default = nullptr;
+ for (const auto& turl : template_urls_) {
+ if ((turl->type() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION) &&
+ turl->extension_info_->wants_to_be_default_engine &&
+ turl->SupportsReplacement(search_terms_data()) &&
(!most_recently_intalled_default ||
(most_recently_intalled_default->extension_info_->install_time <
- (*i)->extension_info_->install_time)))
- most_recently_intalled_default = *i;
+ turl->extension_info_->install_time)))
+ most_recently_intalled_default = turl.get();
}
if (most_recently_intalled_default) {
diff --git a/chromium/components/search_engines/template_url_service.h b/chromium/components/search_engines/template_url_service.h
index 551b357ffc4..329131160eb 100644
--- a/chromium/components/search_engines/template_url_service.h
+++ b/chromium/components/search_engines/template_url_service.h
@@ -27,18 +27,18 @@
#include "components/search_engines/keyword_web_data_service.h"
#include "components/search_engines/template_url.h"
#include "components/search_engines/template_url_id.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/syncable_service.h"
#include "components/webdata/common/web_data_service_consumer.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/syncable_service.h"
class GURL;
class PrefService;
class SearchHostToURLsMap;
class SearchTermsData;
class TemplateURL;
-struct TemplateURLData;
class TemplateURLServiceClient;
class TemplateURLServiceObserver;
+struct TemplateURLData;
namespace rappor {
class RapporService;
@@ -78,6 +78,7 @@ class TemplateURLService : public WebDataServiceConsumer,
public:
using QueryTerms = std::map<std::string, std::string>;
using TemplateURLVector = std::vector<TemplateURL*>;
+ using OwnedTemplateURLVector = std::vector<std::unique_ptr<TemplateURL>>;
using SyncDataMap = std::map<std::string, syncer::SyncData>;
using Subscription = base::CallbackList<void(void)>::Subscription;
@@ -165,21 +166,21 @@ class TemplateURLService : public WebDataServiceConsumer,
// or NULL if there are no such TemplateURLs
TemplateURL* GetTemplateURLForHost(const std::string& host);
- // Takes ownership of |template_url| and adds it to this model. For obvious
- // reasons, it is illegal to Add() the same |template_url| pointer twice.
- // Returns true if the Add is successful.
- bool Add(TemplateURL* template_url);
+ // Adds |template_url| to this model. Returns a raw pointer to |template_url|
+ // if the addition succeeded, or null on failure. (Many callers need still
+ // need a raw pointer to the TemplateURL so they can access it later.)
+ TemplateURL* Add(std::unique_ptr<TemplateURL> template_url);
// Like Add(), but overwrites the |template_url|'s values with the provided
// ones.
- void AddWithOverrides(TemplateURL* template_url,
- const base::string16& short_name,
- const base::string16& keyword,
- const std::string& url);
+ TemplateURL* AddWithOverrides(std::unique_ptr<TemplateURL> template_url,
+ const base::string16& short_name,
+ const base::string16& keyword,
+ const std::string& url);
- // Adds a search engine with the specified info.
- void AddExtensionControlledTURL(
- TemplateURL* template_url,
+ // Adds a search engine with the specified info for extensions.
+ TemplateURL* AddExtensionControlledTURL(
+ std::unique_ptr<TemplateURL> template_url,
std::unique_ptr<TemplateURL::AssociatedExtensionInfo> info);
// Removes the keyword from the model. This deletes the supplied TemplateURL.
@@ -202,11 +203,12 @@ class TemplateURLService : public WebDataServiceConsumer,
base::Time created_before);
// Removes all auto-generated keywords that were created in the specified
- // range for a specified |origin|. If |origin| is empty, deletes all
+ // range and match |url_filter|. If |url_filter| is_null(), deletes all
// auto-generated keywords in the range.
- void RemoveAutoGeneratedForOriginBetween(const GURL& origin,
- base::Time created_after,
- base::Time created_before);
+ void RemoveAutoGeneratedForUrlsBetween(
+ const base::Callback<bool(const GURL&)>& url_filter,
+ base::Time created_after,
+ base::Time created_before);
// Adds a TemplateURL for an extension with an omnibox keyword.
// Only 1 keyword is allowed for a given extension. If a keyword
@@ -490,11 +492,7 @@ class TemplateURLService : public WebDataServiceConsumer,
// Sets the keywords. This is used once the keywords have been loaded.
// This does NOT notify the delegate or the database.
- //
- // This transfers ownership of the elements in |urls| to |this|, and may
- // delete some elements, so it's not safe for callers to access any elements
- // after calling; to reinforce this, this function clears |urls| on exit.
- void SetTemplateURLs(TemplateURLVector* urls);
+ void SetTemplateURLs(std::unique_ptr<OwnedTemplateURLVector> urls);
// Transitions to the loaded state.
void ChangeToLoadedState();
@@ -566,17 +564,19 @@ class TemplateURLService : public WebDataServiceConsumer,
// {google:baseSuggestURL}.
void GoogleBaseURLChanged();
- // Adds a new TemplateURL to this model. TemplateURLService will own the
- // reference, and delete it when the TemplateURL is removed.
+ // Adds a new TemplateURL to this model.
+ //
// If |newly_adding| is false, we assume that this TemplateURL was already
// part of the model in the past, and therefore we don't need to do things
// like assign it an ID or notify sync.
- // This function guarantees that on return the model will not have two
- // non-extension TemplateURLs with the same keyword. If that means that it
- // cannot add the provided argument, it will delete it and return false.
- // Caller is responsible for notifying observers if this function returns
- // true.
- bool AddNoNotify(TemplateURL* template_url, bool newly_adding);
+ //
+ // This function guarantees that on return the model will not have two non-
+ // extension TemplateURLs with the same keyword. If that means that it cannot
+ // add the provided argument, it will return null. Otherwise it will return
+ // the raw pointer to the TemplateURL. The caller is responsible for
+ // notifying observers if this function succeeds.
+ TemplateURL* AddNoNotify(std::unique_ptr<TemplateURL> template_url,
+ bool newly_adding);
// Removes the keyword from the model. This deletes the supplied TemplateURL.
// This fails if the supplied template_url is the default search provider.
@@ -598,7 +598,7 @@ class TemplateURLService : public WebDataServiceConsumer,
// |default_from_prefs|. |default_from_prefs| may be NULL if there is no
// policy-defined DSE in effect.
void UpdateProvidersCreatedByPolicy(
- TemplateURLVector* template_urls,
+ OwnedTemplateURLVector* template_urls,
const TemplateURLData* default_from_prefs);
// Resets the sync GUID of the specified TemplateURL and persists the change
@@ -662,18 +662,10 @@ class TemplateURLService : public WebDataServiceConsumer,
// Goes through a vector of TemplateURLs and ensure that both the in-memory
// and database copies have valid sync_guids. This is to fix crbug.com/102038,
// where old entries were being pushed to Sync without a sync_guid.
- void PatchMissingSyncGUIDs(TemplateURLVector* template_urls);
+ void PatchMissingSyncGUIDs(OwnedTemplateURLVector* template_urls);
void OnSyncedDefaultSearchProviderGUIDChanged();
- // Adds |template_urls| to |template_urls_|.
- //
- // This transfers ownership of the elements in |template_urls| to |this|, and
- // may delete some elements, so it's not safe for callers to access any
- // elements after calling; to reinforce this, this function clears
- // |template_urls| on exit.
- void AddTemplateURLs(TemplateURLVector* template_urls);
-
// Adds to |matches| all TemplateURLs stored in |keyword_to_turl_and_length|
// whose keywords begin with |prefix|, sorted shortest-keyword-first. If
// |supports_replacement_only| is true, only TemplateURLs that support
@@ -742,7 +734,7 @@ class TemplateURLService : public WebDataServiceConsumer,
// Mapping from Sync GUIDs to the TemplateURL.
GUIDToTURL guid_to_turl_;
- TemplateURLVector template_urls_;
+ OwnedTemplateURLVector template_urls_;
base::ObserverList<TemplateURLServiceObserver> model_observers_;
diff --git a/chromium/components/search_engines/template_url_service_client.h b/chromium/components/search_engines/template_url_service_client.h
index 46147aee398..77a22d26706 100644
--- a/chromium/components/search_engines/template_url_service_client.h
+++ b/chromium/components/search_engines/template_url_service_client.h
@@ -37,8 +37,9 @@ class TemplateURLServiceClient {
// Adds the given URL to history as a keyword generated visit.
virtual void AddKeywordGeneratedVisit(const GURL& url) = 0;
- // Restores the extension info of a TemplateURL loaded from the database.
- virtual void RestoreExtensionInfoIfNecessary(TemplateURL* template_url) = 0;
+ // Given the main search |url| for a TemplateURL, returns whether the
+ // TemplateURL is from an omnibox extension.
+ virtual bool IsOmniboxExtensionURL(const std::string& url) = 0;
};
#endif // COMPONENTS_SEARCH_ENGINES_TEMPLATE_URL_SERVICE_CLIENT_H_
diff --git a/chromium/components/search_engines/template_url_service_util_unittest.cc b/chromium/components/search_engines/template_url_service_util_unittest.cc
index d9a79cad2f8..4321d560251 100644
--- a/chromium/components/search_engines/template_url_service_util_unittest.cc
+++ b/chromium/components/search_engines/template_url_service_util_unittest.cc
@@ -5,7 +5,6 @@
#include <stddef.h>
#include "base/memory/ptr_util.h"
-#include "base/memory/scoped_vector.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/search_engines/search_terms_data.h"
@@ -34,73 +33,58 @@ std::unique_ptr<TemplateURL> CreatePrepopulateTemplateURL(
int prepopulate_id,
const std::string& keyword,
TemplateURLID id) {
- return base::WrapUnique(new TemplateURL(
- *CreatePrepopulateTemplateURLData(prepopulate_id, keyword, id)));
+ return base::MakeUnique<TemplateURL>(
+ *CreatePrepopulateTemplateURLData(prepopulate_id, keyword, id));
}
}; // namespace
TEST(TemplateURLServiceUtilTest, RemoveDuplicatePrepopulateIDs) {
- ScopedVector<TemplateURLData> prepopulated_turls;
- TemplateURLService::TemplateURLVector local_turls;
- STLElementDeleter<TemplateURLService::TemplateURLVector> local_turls_deleter(
- &local_turls);
+ std::vector<std::unique_ptr<TemplateURLData>> prepopulated_turls;
+ TemplateURLService::OwnedTemplateURLVector local_turls;
prepopulated_turls.push_back(
- CreatePrepopulateTemplateURLData(1, "winner4", 1).release());
- prepopulated_turls.push_back(
- CreatePrepopulateTemplateURLData(2, "xxx", 2).release());
- prepopulated_turls.push_back(
- CreatePrepopulateTemplateURLData(3, "yyy", 3).release());
+ CreatePrepopulateTemplateURLData(1, "winner4", 1));
+ prepopulated_turls.push_back(CreatePrepopulateTemplateURLData(2, "xxx", 2));
+ prepopulated_turls.push_back(CreatePrepopulateTemplateURLData(3, "yyy", 3));
// Create a sets of different TURLs grouped by prepopulate ID. Each group
// will test a different heuristic of RemoveDuplicatePrepopulateIDs.
// Ignored set - These should be left alone as they do not have valid
// prepopulate IDs.
- local_turls.push_back(
- CreatePrepopulateTemplateURL(0, "winner1", 4).release());
- local_turls.push_back(
- CreatePrepopulateTemplateURL(0, "winner2", 5).release());
- local_turls.push_back(
- CreatePrepopulateTemplateURL(0, "winner3", 6).release());
+ local_turls.push_back(CreatePrepopulateTemplateURL(0, "winner1", 4));
+ local_turls.push_back(CreatePrepopulateTemplateURL(0, "winner2", 5));
+ local_turls.push_back(CreatePrepopulateTemplateURL(0, "winner3", 6));
size_t num_non_prepopulated_urls = local_turls.size();
// Keyword match set - Prefer the one that matches the keyword of the
// prepopulate ID.
- local_turls.push_back(CreatePrepopulateTemplateURL(1, "loser1", 7).release());
- local_turls.push_back(CreatePrepopulateTemplateURL(1, "loser2", 8).release());
- local_turls.push_back(
- CreatePrepopulateTemplateURL(1, "winner4", 9).release());
+ local_turls.push_back(CreatePrepopulateTemplateURL(1, "loser1", 7));
+ local_turls.push_back(CreatePrepopulateTemplateURL(1, "loser2", 8));
+ local_turls.push_back(CreatePrepopulateTemplateURL(1, "winner4", 9));
// Default set - Prefer the default search engine over all other criteria.
// The last one is the default. It will be passed as the
// default_search_provider parameter to RemoveDuplicatePrepopulateIDs.
- local_turls.push_back(
- CreatePrepopulateTemplateURL(2, "loser3", 10).release());
- local_turls.push_back(CreatePrepopulateTemplateURL(2, "xxx", 11).release());
- TemplateURL* default_turl =
- CreatePrepopulateTemplateURL(2, "winner5", 12).release();
- local_turls.push_back(default_turl);
+ local_turls.push_back(CreatePrepopulateTemplateURL(2, "loser3", 10));
+ local_turls.push_back(CreatePrepopulateTemplateURL(2, "xxx", 11));
+ local_turls.push_back(CreatePrepopulateTemplateURL(2, "winner5", 12));
+ TemplateURL* default_turl = local_turls.back().get();
// ID set - Prefer the lowest TemplateURLID if the keywords don't match and if
// none are the default.
- local_turls.push_back(
- CreatePrepopulateTemplateURL(3, "winner6", 13).release());
- local_turls.push_back(
- CreatePrepopulateTemplateURL(3, "loser5", 14).release());
- local_turls.push_back(
- CreatePrepopulateTemplateURL(3, "loser6", 15).release());
+ local_turls.push_back(CreatePrepopulateTemplateURL(3, "winner6", 13));
+ local_turls.push_back(CreatePrepopulateTemplateURL(3, "loser5", 14));
+ local_turls.push_back(CreatePrepopulateTemplateURL(3, "loser6", 15));
- RemoveDuplicatePrepopulateIDs(NULL, prepopulated_turls, default_turl,
- &local_turls, SearchTermsData(), NULL);
+ RemoveDuplicatePrepopulateIDs(nullptr, prepopulated_turls, default_turl,
+ &local_turls, SearchTermsData(), nullptr);
// Verify that the expected local TURLs survived the process.
EXPECT_EQ(local_turls.size(),
prepopulated_turls.size() + num_non_prepopulated_urls);
- for (TemplateURLService::TemplateURLVector::const_iterator itr =
- local_turls.begin(); itr != local_turls.end(); ++itr) {
- EXPECT_TRUE(base::StartsWith((*itr)->keyword(),
- base::ASCIIToUTF16("winner"),
+ for (const auto& turl : local_turls) {
+ EXPECT_TRUE(base::StartsWith(turl->keyword(), base::ASCIIToUTF16("winner"),
base::CompareCase::SENSITIVE));
}
}
diff --git a/chromium/components/search_engines/template_url_unittest.cc b/chromium/components/search_engines/template_url_unittest.cc
index e0a413a5684..672579bf474 100644
--- a/chromium/components/search_engines/template_url_unittest.cc
+++ b/chromium/components/search_engines/template_url_unittest.cc
@@ -1690,24 +1690,24 @@ TEST_F(TemplateURLTest, ContextualSearchParameters) {
TemplateURLRef::SearchTermsArgs search_terms_args(ASCIIToUTF16("foo"));
std::string result = url.url_ref().ReplaceSearchTerms(search_terms_args,
search_terms_data_);
- EXPECT_EQ("http://bar/_/contextualsearch?ctxsl_resolve=1", result);
+ EXPECT_EQ("http://bar/_/contextualsearch?ctxsl_coca=0", result);
TemplateURLRef::SearchTermsArgs::ContextualSearchParams params(
- 1, 6, 11, "allen", "woody+allen+movies", "www.wikipedia.org",
- "utf-8", true);
+ 1, 6, 11, "allen", "woody+allen+movies", "www.wikipedia.org", "utf-8", 1);
search_terms_args.contextual_search_params = params;
result = url.url_ref().ReplaceSearchTerms(search_terms_args,
search_terms_data_);
- EXPECT_EQ("http://bar/_/contextualsearch?"
- "ctxs=1&"
- "ctxs_start=6&"
- "ctxs_end=11&"
- "q=allen&"
- "ctxs_content=woody+allen+movies&"
- "ctxsl_url=www.wikipedia.org&"
- "ctxs_encoding=utf-8&"
- "ctxsl_resolve=1",
- result);
+ EXPECT_EQ(
+ "http://bar/_/contextualsearch?"
+ "ctxs=1&"
+ "ctxs_start=6&"
+ "ctxs_end=11&"
+ "q=allen&"
+ "ctxs_content=woody+allen+movies&"
+ "ctxsl_url=www.wikipedia.org&"
+ "ctxs_encoding=utf-8&"
+ "ctxsl_coca=1",
+ result);
}
TEST_F(TemplateURLTest, GenerateKeyword) {
diff --git a/chromium/components/search_engines/util.cc b/chromium/components/search_engines/util.cc
index c8918540995..3ad9a198b7a 100644
--- a/chromium/components/search_engines/util.cc
+++ b/chromium/components/search_engines/util.cc
@@ -7,13 +7,14 @@
#include <stddef.h>
#include <stdint.h>
+#include <algorithm>
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/logging.h"
-#include "base/memory/scoped_vector.h"
+#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "components/prefs/pref_service.h"
#include "components/search_engines/template_url.h"
@@ -49,34 +50,27 @@ GURL GetDefaultSearchURLForSearchTerms(TemplateURLService* service,
void RemoveDuplicatePrepopulateIDs(
KeywordWebDataService* service,
- const ScopedVector<TemplateURLData>& prepopulated_urls,
+ const std::vector<std::unique_ptr<TemplateURLData>>& prepopulated_urls,
TemplateURL* default_search_provider,
- TemplateURLService::TemplateURLVector* template_urls,
+ TemplateURLService::OwnedTemplateURLVector* template_urls,
const SearchTermsData& search_terms_data,
std::set<std::string>* removed_keyword_guids) {
DCHECK(template_urls);
// For convenience construct an ID->TemplateURL* map from |prepopulated_urls|.
- typedef std::map<int, TemplateURLData*> PrepopulatedURLMap;
- PrepopulatedURLMap prepopulated_url_map;
- for (std::vector<TemplateURLData*>::const_iterator i(
- prepopulated_urls.begin());
- i != prepopulated_urls.end();
- ++i)
- prepopulated_url_map[(*i)->prepopulate_id] = *i;
+ std::map<int, TemplateURLData*> prepopulated_url_map;
+ for (const auto& url : prepopulated_urls)
+ prepopulated_url_map[url->prepopulate_id] = url.get();
// Separate |template_urls| into prepopulated and non-prepopulated groups.
- typedef std::multimap<int, TemplateURL*> UncheckedURLMap;
- UncheckedURLMap unchecked_urls;
- TemplateURLService::TemplateURLVector checked_urls;
- for (TemplateURLService::TemplateURLVector::iterator i(
- template_urls->begin()); i != template_urls->end(); ++i) {
- TemplateURL* turl = *i;
+ std::multimap<int, std::unique_ptr<TemplateURL>> unchecked_urls;
+ TemplateURLService::OwnedTemplateURLVector checked_urls;
+ for (auto& turl : *template_urls) {
int prepopulate_id = turl->prepopulate_id();
if (prepopulate_id)
- unchecked_urls.insert(std::make_pair(prepopulate_id, turl));
+ unchecked_urls.insert(std::make_pair(prepopulate_id, std::move(turl)));
else
- checked_urls.push_back(turl);
+ checked_urls.push_back(std::move(turl));
}
// For each group of prepopulated URLs with one ID, find the best URL to use
@@ -85,12 +79,11 @@ void RemoveDuplicatePrepopulateIDs(
while (!unchecked_urls.empty()) {
// Find the best URL.
int prepopulate_id = unchecked_urls.begin()->first;
- PrepopulatedURLMap::const_iterator prepopulated_url =
- prepopulated_url_map.find(prepopulate_id);
- UncheckedURLMap::iterator end = unchecked_urls.upper_bound(prepopulate_id);
- UncheckedURLMap::iterator best = unchecked_urls.begin();
+ auto prepopulated_url = prepopulated_url_map.find(prepopulate_id);
+ auto end = unchecked_urls.upper_bound(prepopulate_id);
+ auto best = unchecked_urls.begin();
bool matched_keyword = false;
- for (UncheckedURLMap::iterator i = unchecked_urls.begin(); i != end; ++i) {
+ for (auto i = unchecked_urls.begin(); i != end; ++i) {
// If the user-selected DSE is a prepopulated engine its properties will
// either come from the prepopulation origin or from the user preferences
// file (see DefaultSearchManager). Those properties will end up
@@ -121,8 +114,8 @@ void RemoveDuplicatePrepopulateIDs(
}
// Add the best URL to the checked group and delete the rest.
- checked_urls.push_back(best->second);
- for (UncheckedURLMap::iterator i = unchecked_urls.begin(); i != end; ++i) {
+ checked_urls.push_back(std::move(best->second));
+ for (auto i = unchecked_urls.begin(); i != end; ++i) {
if (i == best)
continue;
if (service) {
@@ -130,7 +123,6 @@ void RemoveDuplicatePrepopulateIDs(
if (removed_keyword_guids)
removed_keyword_guids->insert(i->second->sync_guid());
}
- delete i->second;
}
// Done with this group.
@@ -193,9 +185,9 @@ ActionsFromPrepopulateData::~ActionsFromPrepopulateData() {}
// ownership of |prepopulated_urls| and will clear the vector.
void MergeEnginesFromPrepopulateData(
KeywordWebDataService* service,
- ScopedVector<TemplateURLData>* prepopulated_urls,
+ std::vector<std::unique_ptr<TemplateURLData>>* prepopulated_urls,
size_t default_search_index,
- TemplateURLService::TemplateURLVector* template_urls,
+ TemplateURLService::OwnedTemplateURLVector* template_urls,
TemplateURL* default_search_provider,
std::set<std::string>* removed_keyword_guids) {
DCHECK(prepopulated_urls);
@@ -205,12 +197,10 @@ void MergeEnginesFromPrepopulateData(
prepopulated_urls, *template_urls, default_search_provider));
// Remove items.
- for (std::vector<TemplateURL*>::iterator i = actions.removed_engines.begin();
- i < actions.removed_engines.end(); ++i) {
- std::unique_ptr<TemplateURL> template_url(*i);
- TemplateURLService::TemplateURLVector::iterator j = std::find(
- template_urls->begin(), template_urls->end(), template_url.get());
+ for (const auto* removed_engine : actions.removed_engines) {
+ auto j = FindTemplateURL(template_urls, removed_engine);
DCHECK(j != template_urls->end());
+ std::unique_ptr<TemplateURL> template_url = std::move(*j);
DCHECK(!default_search_provider ||
(*j)->prepopulate_id() != default_search_provider->prepopulate_id());
template_urls->erase(j);
@@ -222,41 +212,32 @@ void MergeEnginesFromPrepopulateData(
}
// Edit items.
- for (EditedEngines::iterator i(actions.edited_engines.begin());
- i < actions.edited_engines.end(); ++i) {
- TemplateURLData& data = i->second;
- std::unique_ptr<TemplateURL> existing_url(i->first);
+ for (const auto& edited_engine : actions.edited_engines) {
+ const TemplateURLData& data = edited_engine.second;
if (service)
service->UpdateKeyword(data);
// Replace the entry in |template_urls| with the updated one.
- TemplateURLService::TemplateURLVector::iterator j = std::find(
- template_urls->begin(), template_urls->end(), existing_url.get());
- *j = new TemplateURL(data);
+ auto j = FindTemplateURL(template_urls, edited_engine.first);
+ *j = base::MakeUnique<TemplateURL>(data);
}
// Add items.
- for (std::vector<TemplateURLData>::const_iterator it =
- actions.added_engines.begin();
- it != actions.added_engines.end();
- ++it) {
- template_urls->push_back(new TemplateURL(*it));
- }
+ for (const auto& added_engine : actions.added_engines)
+ template_urls->push_back(base::MakeUnique<TemplateURL>(added_engine));
}
ActionsFromPrepopulateData CreateActionsFromCurrentPrepopulateData(
- ScopedVector<TemplateURLData>* prepopulated_urls,
- const TemplateURLService::TemplateURLVector& existing_urls,
+ std::vector<std::unique_ptr<TemplateURLData>>* prepopulated_urls,
+ const TemplateURLService::OwnedTemplateURLVector& existing_urls,
const TemplateURL* default_search_provider) {
// Create a map to hold all provided |template_urls| that originally came from
// prepopulate data (i.e. have a non-zero prepopulate_id()).
- typedef std::map<int, TemplateURL*> IDMap;
- IDMap id_to_turl;
- for (TemplateURLService::TemplateURLVector::const_iterator i(
- existing_urls.begin()); i != existing_urls.end(); ++i) {
- int prepopulate_id = (*i)->prepopulate_id();
+ std::map<int, TemplateURL*> id_to_turl;
+ for (auto& turl : existing_urls) {
+ int prepopulate_id = turl->prepopulate_id();
if (prepopulate_id > 0)
- id_to_turl[prepopulate_id] = *i;
+ id_to_turl[prepopulate_id] = turl.get();
}
// For each current prepopulated URL, check whether |template_urls| contained
@@ -264,13 +245,11 @@ ActionsFromPrepopulateData CreateActionsFromCurrentPrepopulateData(
// current data. (If the passed-in URL was user-edited, we persist the user's
// name and keyword.) If not, add the prepopulated URL.
ActionsFromPrepopulateData actions;
- for (size_t i = 0; i < prepopulated_urls->size(); ++i) {
- // We take ownership of |prepopulated_urls[i]|.
- std::unique_ptr<TemplateURLData> prepopulated_url((*prepopulated_urls)[i]);
+ for (auto& prepopulated_url : *prepopulated_urls) {
const int prepopulated_id = prepopulated_url->prepopulate_id;
DCHECK_NE(0, prepopulated_id);
- IDMap::iterator existing_url_iter(id_to_turl.find(prepopulated_id));
+ auto existing_url_iter = id_to_turl.find(prepopulated_id);
if (existing_url_iter != id_to_turl.end()) {
// Update the data store with the new prepopulated data. Preserve user
// edits to the name and keyword.
@@ -287,10 +266,6 @@ ActionsFromPrepopulateData CreateActionsFromCurrentPrepopulateData(
actions.added_engines.push_back(*prepopulated_url);
}
}
- // The above loop takes ownership of all the contents of prepopulated_urls.
- // Clear the pointers.
- prepopulated_urls->weak_erase(prepopulated_urls->begin(),
- prepopulated_urls->end());
// The block above removed all the URLs from the |id_to_turl| map that were
// found in the prepopulate data. Any remaining URLs that haven't been
@@ -298,7 +273,7 @@ ActionsFromPrepopulateData CreateActionsFromCurrentPrepopulateData(
// We assume that this entry is equivalent to the DSE if its prepopulate ID
// and keyword both match. If the prepopulate ID _does_ match all properties
// will be replaced with those from |default_search_provider| anyway.
- for (IDMap::iterator i(id_to_turl.begin()); i != id_to_turl.end(); ++i) {
+ for (auto i = id_to_turl.begin(); i != id_to_turl.end(); ++i) {
TemplateURL* template_url = i->second;
if ((template_url->safe_for_autoreplace()) &&
(!default_search_provider ||
@@ -315,7 +290,7 @@ void GetSearchProvidersUsingKeywordResult(
const WDTypedResult& result,
KeywordWebDataService* service,
PrefService* prefs,
- TemplateURLService::TemplateURLVector* template_urls,
+ TemplateURLService::OwnedTemplateURLVector* template_urls,
TemplateURL* default_search_provider,
const SearchTermsData& search_terms_data,
int* new_resource_keyword_version,
@@ -328,8 +303,7 @@ void GetSearchProvidersUsingKeywordResult(
WDKeywordsResult keyword_result = reinterpret_cast<
const WDResult<WDKeywordsResult>*>(&result)->GetValue();
- for (KeywordTable::Keywords::iterator i(keyword_result.keywords.begin());
- i != keyword_result.keywords.end(); ++i) {
+ for (auto& keyword : keyword_result.keywords) {
// Fix any duplicate encodings in the local database. Note that we don't
// adjust the last_modified time of this keyword; this way, we won't later
// overwrite any changes on the sync server that happened to this keyword
@@ -339,9 +313,9 @@ void GetSearchProvidersUsingKeywordResult(
// update the server with the merged, de-duped results at that time. We
// still fix here, though, to correct problems in clients that have disabled
// search engine sync, since in that case that code will never be reached.
- if (DeDupeEncodings(&i->input_encodings) && service)
- service->UpdateKeyword(*i);
- template_urls->push_back(new TemplateURL(*i));
+ if (DeDupeEncodings(&keyword.input_encodings) && service)
+ service->UpdateKeyword(keyword);
+ template_urls->push_back(base::MakeUnique<TemplateURL>(keyword));
}
*new_resource_keyword_version = keyword_result.builtin_keyword_version;
@@ -355,7 +329,7 @@ void GetSearchProvidersUsingKeywordResult(
void GetSearchProvidersUsingLoadedEngines(
KeywordWebDataService* service,
PrefService* prefs,
- TemplateURLService::TemplateURLVector* template_urls,
+ TemplateURLService::OwnedTemplateURLVector* template_urls,
TemplateURL* default_search_provider,
const SearchTermsData& search_terms_data,
int* resource_keyword_version,
@@ -363,7 +337,7 @@ void GetSearchProvidersUsingLoadedEngines(
DCHECK(template_urls);
DCHECK(resource_keyword_version);
size_t default_search_index;
- ScopedVector<TemplateURLData> prepopulated_urls =
+ std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs,
&default_search_index);
RemoveDuplicatePrepopulateIDs(service, prepopulated_urls,
@@ -393,3 +367,12 @@ bool DeDupeEncodings(std::vector<std::string>* encodings) {
encodings->swap(deduped_encodings);
return encodings->size() != deduped_encodings.size();
}
+
+TemplateURLService::OwnedTemplateURLVector::iterator FindTemplateURL(
+ TemplateURLService::OwnedTemplateURLVector* urls,
+ const TemplateURL* url) {
+ return std::find_if(urls->begin(), urls->end(),
+ [url](const std::unique_ptr<TemplateURL>& ptr) {
+ return ptr.get() == url;
+ });
+}
diff --git a/chromium/components/search_engines/util.h b/chromium/components/search_engines/util.h
index 6c235b96cf5..39034e5b6fd 100644
--- a/chromium/components/search_engines/util.h
+++ b/chromium/components/search_engines/util.h
@@ -6,6 +6,7 @@
#define COMPONENTS_SEARCH_ENGINES_UTIL_H_
// This file contains utility functions for search engine functionality.
+
#include <memory>
#include <set>
#include <string>
@@ -14,9 +15,6 @@
#include "base/strings/string16.h"
#include "components/search_engines/template_url_service.h"
-template <typename T>
-class ScopedVector;
-
class KeywordWebDataService;
class PrefService;
class TemplateURL;
@@ -77,8 +75,8 @@ struct ActionsFromPrepopulateData {
//
// NOTE: Takes ownership of, and clears, |prepopulated_urls|.
ActionsFromPrepopulateData CreateActionsFromCurrentPrepopulateData(
- ScopedVector<TemplateURLData>* prepopulated_urls,
- const TemplateURLService::TemplateURLVector& existing_urls,
+ std::vector<std::unique_ptr<TemplateURLData>>* prepopulated_urls,
+ const TemplateURLService::OwnedTemplateURLVector& existing_urls,
const TemplateURL* default_search_provider);
// Processes the results of KeywordWebDataService::GetKeywords, combining it
@@ -97,7 +95,7 @@ void GetSearchProvidersUsingKeywordResult(
const WDTypedResult& result,
KeywordWebDataService* service,
PrefService* prefs,
- TemplateURLService::TemplateURLVector* template_urls,
+ TemplateURLService::OwnedTemplateURLVector* template_urls,
TemplateURL* default_search_provider,
const SearchTermsData& search_terms_data,
int* new_resource_keyword_version,
@@ -113,7 +111,7 @@ void GetSearchProvidersUsingKeywordResult(
void GetSearchProvidersUsingLoadedEngines(
KeywordWebDataService* service,
PrefService* prefs,
- TemplateURLService::TemplateURLVector* template_urls,
+ TemplateURLService::OwnedTemplateURLVector* template_urls,
TemplateURL* default_search_provider,
const SearchTermsData& search_terms_data,
int* resource_keyword_version,
@@ -131,10 +129,14 @@ bool DeDupeEncodings(std::vector<std::string>* encodings);
// so it's accessible by unittests.
void RemoveDuplicatePrepopulateIDs(
KeywordWebDataService* service,
- const ScopedVector<TemplateURLData>& prepopulated_urls,
+ const std::vector<std::unique_ptr<TemplateURLData>>& prepopulated_urls,
TemplateURL* default_search_provider,
- TemplateURLService::TemplateURLVector* template_urls,
+ TemplateURLService::OwnedTemplateURLVector* template_urls,
const SearchTermsData& search_terms_data,
std::set<std::string>* removed_keyword_guids);
+TemplateURLService::OwnedTemplateURLVector::iterator FindTemplateURL(
+ TemplateURLService::OwnedTemplateURLVector* urls,
+ const TemplateURL* url);
+
#endif // COMPONENTS_SEARCH_ENGINES_UTIL_H_
diff --git a/chromium/components/search_provider_logos.gypi b/chromium/components/search_provider_logos.gypi
deleted file mode 100644
index 3b5f777ca6c..00000000000
--- a/chromium/components/search_provider_logos.gypi
+++ /dev/null
@@ -1,32 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'search_provider_logos',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../ui/gfx/gfx.gyp:gfx',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'search_provider_logos/google_logo_api.cc',
- 'search_provider_logos/google_logo_api.h',
- 'search_provider_logos/logo_cache.cc',
- 'search_provider_logos/logo_cache.h',
- 'search_provider_logos/logo_common.cc',
- 'search_provider_logos/logo_common.h',
- 'search_provider_logos/logo_tracker.cc',
- 'search_provider_logos/logo_tracker.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/search_provider_logos/BUILD.gn b/chromium/components/search_provider_logos/BUILD.gn
index 57ef56d79dd..3191df25c9a 100644
--- a/chromium/components/search_provider_logos/BUILD.gn
+++ b/chromium/components/search_provider_logos/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("search_provider_logos") {
+static_library("search_provider_logos") {
sources = [
"google_logo_api.cc",
"google_logo_api.h",
@@ -12,6 +12,8 @@ source_set("search_provider_logos") {
"logo_common.h",
"logo_tracker.cc",
"logo_tracker.h",
+ "switches.cc",
+ "switches.h",
]
public_deps = [
diff --git a/chromium/components/search_provider_logos/google_logo_api.cc b/chromium/components/search_provider_logos/google_logo_api.cc
index 02c127dea1c..40fc1e8d596 100644
--- a/chromium/components/search_provider_logos/google_logo_api.cc
+++ b/chromium/components/search_provider_logos/google_logo_api.cc
@@ -79,9 +79,17 @@ std::unique_ptr<EncodedLogo> GoogleParseLogoResponse(
// Default parsing failure to be true.
*parsing_failed = true;
- std::unique_ptr<base::Value> value = base::JSONReader::Read(response_sp);
- if (!value.get())
+
+ int error_code;
+ std::string error_string;
+ int error_line;
+ int error_col;
+ std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
+ response_sp, 0, &error_code, &error_string, &error_line, &error_col);
+ if (!value) {
+ LOG(WARNING) << error_string << " at " << error_line << ":" << error_col;
return nullptr;
+ }
// The important data lives inside several nested dictionaries:
// {"update": {"logo": { "mime_type": ..., etc } } }
const base::DictionaryValue* outer_dict;
diff --git a/chromium/components/search_provider_logos/logo_cache.cc b/chromium/components/search_provider_logos/logo_cache.cc
index 0ef01aeb2bf..70fbe7b939d 100644
--- a/chromium/components/search_provider_logos/logo_cache.cc
+++ b/chromium/components/search_provider_logos/logo_cache.cc
@@ -70,7 +70,7 @@ void LogoCache::UpdateCachedLogoMetadata(const LogoMetadata& metadata) {
DCHECK(metadata_);
DCHECK_EQ(metadata_->fingerprint, metadata.fingerprint);
- UpdateMetadata(base::WrapUnique(new LogoMetadata(metadata)));
+ UpdateMetadata(base::MakeUnique<LogoMetadata>(metadata));
WriteMetadata();
}
diff --git a/chromium/components/search_provider_logos/logo_cache_unittest.cc b/chromium/components/search_provider_logos/logo_cache_unittest.cc
index 8b43fc31d86..6a7dcbae646 100644
--- a/chromium/components/search_provider_logos/logo_cache_unittest.cc
+++ b/chromium/components/search_provider_logos/logo_cache_unittest.cc
@@ -107,7 +107,7 @@ class LogoCacheTest : public ::testing::Test {
void InitCache() {
cache_.reset(new LogoCache(
- cache_parent_dir_.path().Append(FILE_PATH_LITERAL("cache"))));
+ cache_parent_dir_.GetPath().Append(FILE_PATH_LITERAL("cache"))));
}
void ExpectMetadata(const LogoMetadata* expected_metadata) {
diff --git a/chromium/components/search_provider_logos/logo_tracker.cc b/chromium/components/search_provider_logos/logo_tracker.cc
index 1e38413956d..2027d8ab500 100644
--- a/chromium/components/search_provider_logos/logo_tracker.cc
+++ b/chromium/components/search_provider_logos/logo_tracker.cc
@@ -7,12 +7,15 @@
#include <algorithm>
#include <utility>
+#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_clock.h"
+#include "components/search_provider_logos/switches.h"
#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
@@ -23,8 +26,6 @@ namespace {
const int64_t kMaxDownloadBytes = 1024 * 1024;
-//const int kDecodeLogoTimeoutSeconds = 30;
-
// Returns whether the metadata for the cached logo indicates that the logo is
// OK to show, i.e. it's not expired or it's allowed to be shown temporarily
// after expiration.
@@ -208,14 +209,19 @@ void LogoTracker::FetchLogo() {
DCHECK(!fetcher_);
DCHECK(!is_idle_);
- GURL url;
std::string fingerprint;
if (cached_logo_ && !cached_logo_->metadata.fingerprint.empty() &&
cached_logo_->metadata.expiration_time >= clock_->Now()) {
fingerprint = cached_logo_->metadata.fingerprint;
}
- url = append_queryparams_func_.Run(
- logo_url_, fingerprint, wants_cta_, transparent_);
+ GURL url;
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kGoogleDoodleUrl)) {
+ url = GURL(command_line->GetSwitchValueASCII(switches::kGoogleDoodleUrl));
+ } else {
+ url = append_queryparams_func_.Run(
+ logo_url_, fingerprint, wants_cta_, transparent_);
+ }
fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
fetcher_->SetRequestContext(request_context_getter_.get());
@@ -295,7 +301,7 @@ void LogoTracker::OnFreshLogoAvailable(
}
}
- DCHECK(download_outcome != kDownloadOutcomeNotTracked);
+ DCHECK_NE(kDownloadOutcomeNotTracked, download_outcome);
ReturnToIdle(download_outcome);
}
@@ -303,7 +309,16 @@ void LogoTracker::OnURLFetchComplete(const net::URLFetcher* source) {
DCHECK(!is_idle_);
std::unique_ptr<net::URLFetcher> cleanup_fetcher(fetcher_.release());
- if (!source->GetStatus().is_success() || (source->GetResponseCode() != 200)) {
+ if (!source->GetStatus().is_success()) {
+ ReturnToIdle(DOWNLOAD_OUTCOME_DOWNLOAD_FAILED);
+ return;
+ }
+
+ int response_code = source->GetResponseCode();
+ if (response_code != net::HTTP_OK &&
+ response_code != net::URLFetcher::RESPONSE_CODE_INVALID) {
+ // RESPONSE_CODE_INVALID is returned when fetching from a file: URL
+ // (for testing). In all other cases we would have had a non-success status.
ReturnToIdle(DOWNLOAD_OUTCOME_DOWNLOAD_FAILED);
return;
}
@@ -326,7 +341,8 @@ void LogoTracker::OnURLFetchComplete(const net::URLFetcher* source) {
void LogoTracker::OnURLFetchDownloadProgress(const net::URLFetcher* source,
int64_t current,
- int64_t total) {
+ int64_t total,
+ int64_t current_network_bytes) {
if (total > kMaxDownloadBytes || current > kMaxDownloadBytes) {
LOG(WARNING) << "Search provider logo exceeded download size limit";
ReturnToIdle(DOWNLOAD_OUTCOME_DOWNLOAD_FAILED);
diff --git a/chromium/components/search_provider_logos/logo_tracker.h b/chromium/components/search_provider_logos/logo_tracker.h
index a312457d5fe..851e1bc5a03 100644
--- a/chromium/components/search_provider_logos/logo_tracker.h
+++ b/chromium/components/search_provider_logos/logo_tracker.h
@@ -204,7 +204,8 @@ class LogoTracker : public net::URLFetcherDelegate {
void OnURLFetchComplete(const net::URLFetcher* source) override;
void OnURLFetchDownloadProgress(const net::URLFetcher* source,
int64_t current,
- int64_t total) override;
+ int64_t total,
+ int64_t current_network_bytes) override;
// The URL from which the logo is fetched.
GURL logo_url_;
diff --git a/chromium/components/search_provider_logos/logo_tracker_unittest.cc b/chromium/components/search_provider_logos/logo_tracker_unittest.cc
index 00fd281b30d..fe8a43664e6 100644
--- a/chromium/components/search_provider_logos/logo_tracker_unittest.cc
+++ b/chromium/components/search_provider_logos/logo_tracker_unittest.cc
@@ -14,12 +14,10 @@
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/json/json_writer.h"
-#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/test/simple_test_clock.h"
@@ -341,7 +339,7 @@ class LogoTrackerTest : public ::testing::Test {
// after logo_tracker_'s destruction. Ensure that logo_cache_ is actually
// destructed before the test ends to make gmock happy.
delete logo_tracker_;
- message_loop_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
// Returns the response that the server would send for the given logo.
diff --git a/chromium/components/search_provider_logos/switches.cc b/chromium/components/search_provider_logos/switches.cc
new file mode 100644
index 00000000000..32679db4c64
--- /dev/null
+++ b/chromium/components/search_provider_logos/switches.cc
@@ -0,0 +1,14 @@
+// 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 "components/search_provider_logos/switches.h"
+
+namespace search_provider_logos {
+namespace switches {
+
+// Overrides the URL used to fetch the current Google Doodle.
+const char kGoogleDoodleUrl[] = "google-doodle-url";
+
+} // namespace switches
+} // namespace search_provider_logos
diff --git a/chromium/components/search_provider_logos/switches.h b/chromium/components/search_provider_logos/switches.h
new file mode 100644
index 00000000000..385690fe445
--- /dev/null
+++ b/chromium/components/search_provider_logos/switches.h
@@ -0,0 +1,16 @@
+// 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 COMPONENTS_SEARCH_PROVIDER_LOGOS_SWITCHES_H_
+#define COMPONENTS_SEARCH_PROVIDER_LOGOS_SWITCHES_H_
+
+namespace search_provider_logos {
+namespace switches {
+
+extern const char kGoogleDoodleUrl[];
+
+} // namespace switches
+} // namespace search_provider_logos
+
+#endif // COMPONENTS_SEARCH_PROVIDER_LOGOS_SWITCHES_H_
diff --git a/chromium/components/security_interstitials.gypi b/chromium/components/security_interstitials.gypi
deleted file mode 100644
index 025aba7f76e..00000000000
--- a/chromium/components/security_interstitials.gypi
+++ /dev/null
@@ -1,42 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/security_interstitials/core
- 'target_name': 'security_interstitials_core',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../net/net.gyp:net',
- '../ui/base/ui_base.gyp:ui_base',
- 'components_strings.gyp:components_strings',
- 'google_core_browser',
- 'history_core_browser',
- 'metrics',
- 'rappor',
- 'ssl_errors',
- 'url_formatter/url_formatter.gyp:url_formatter'
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'security_interstitials/core/bad_clock_ui.cc',
- 'security_interstitials/core/bad_clock_ui.h',
- 'security_interstitials/core/common_string_util.cc',
- 'security_interstitials/core/common_string_util.h',
- 'security_interstitials/core/controller_client.cc',
- 'security_interstitials/core/controller_client.h',
- 'security_interstitials/core/metrics_helper.cc',
- 'security_interstitials/core/metrics_helper.h',
- 'security_interstitials/core/ssl_error_ui.cc',
- 'security_interstitials/core/ssl_error_ui.h',
- ]
- }
- ]
-} \ No newline at end of file
diff --git a/chromium/components/security_interstitials/core/BUILD.gn b/chromium/components/security_interstitials/core/BUILD.gn
index 6595ce9043a..dbd5bccad12 100644
--- a/chromium/components/security_interstitials/core/BUILD.gn
+++ b/chromium/components/security_interstitials/core/BUILD.gn
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/security_interstitials.gyp:security_interstitials_core
static_library("core") {
sources = [
"bad_clock_ui.cc",
diff --git a/chromium/components/security_interstitials/core/bad_clock_ui.cc b/chromium/components/security_interstitials/core/bad_clock_ui.cc
index 59d62d57113..58a85ed5204 100644
--- a/chromium/components/security_interstitials/core/bad_clock_ui.cc
+++ b/chromium/components/security_interstitials/core/bad_clock_ui.cc
@@ -42,6 +42,7 @@ void BadClockUI::PopulateStringsForHTML(base::DictionaryValue* load_time_data) {
common_string_util::PopulateSSLLayoutStrings(cert_error_, load_time_data);
common_string_util::PopulateSSLDebuggingStrings(ssl_info_, time_triggered_,
load_time_data);
+ common_string_util::PopulateNewIconStrings(load_time_data);
// Clock-specific strings.
PopulateClockStrings(load_time_data);
@@ -107,6 +108,9 @@ void BadClockUI::HandleCommand(SecurityInterstitialCommands command) {
case CMD_OPEN_REPORTING_PRIVACY:
controller_->OpenExtendedReportingPrivacyPolicy();
break;
+ case CMD_OPEN_WHITEPAPER:
+ controller_->OpenExtendedReportingWhitepaper();
+ break;
case CMD_PROCEED:
case CMD_OPEN_HELP_CENTER:
case CMD_RELOAD:
diff --git a/chromium/components/security_interstitials/core/browser/resources/extended_reporting.js b/chromium/components/security_interstitials/core/browser/resources/extended_reporting.js
index 817b3ff6346..5a72ad12204 100644
--- a/chromium/components/security_interstitials/core/browser/resources/extended_reporting.js
+++ b/chromium/components/security_interstitials/core/browser/resources/extended_reporting.js
@@ -33,6 +33,12 @@ function setupExtendedReportingCheckbox() {
$('body').classList.add('extended-reporting-has-checkbox');
+ if ($('whitepaper-link')) {
+ $('whitepaper-link').addEventListener('click', function(event) {
+ sendCommand(CMD_OPEN_WHITEPAPER);
+ });
+ }
+
$('opt-in-checkbox').addEventListener('click', function() {
sendCommand($('opt-in-checkbox').checked ?
CMD_DO_REPORT :
diff --git a/chromium/components/security_interstitials/core/browser/resources/images/1x/triangle_red.png b/chromium/components/security_interstitials/core/browser/resources/images/1x/triangle_red.png
new file mode 100644
index 00000000000..4fd8f7598d1
--- /dev/null
+++ b/chromium/components/security_interstitials/core/browser/resources/images/1x/triangle_red.png
Binary files differ
diff --git a/chromium/components/security_interstitials/core/browser/resources/images/1x/triangle_white.png b/chromium/components/security_interstitials/core/browser/resources/images/1x/triangle_white.png
new file mode 100644
index 00000000000..0b488382c6c
--- /dev/null
+++ b/chromium/components/security_interstitials/core/browser/resources/images/1x/triangle_white.png
Binary files differ
diff --git a/chromium/components/security_interstitials/core/browser/resources/images/2x/triangle_red.png b/chromium/components/security_interstitials/core/browser/resources/images/2x/triangle_red.png
new file mode 100644
index 00000000000..d49ca44c615
--- /dev/null
+++ b/chromium/components/security_interstitials/core/browser/resources/images/2x/triangle_red.png
Binary files differ
diff --git a/chromium/components/security_interstitials/core/browser/resources/images/2x/triangle_white.png b/chromium/components/security_interstitials/core/browser/resources/images/2x/triangle_white.png
new file mode 100644
index 00000000000..025ae66be52
--- /dev/null
+++ b/chromium/components/security_interstitials/core/browser/resources/images/2x/triangle_white.png
Binary files differ
diff --git a/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.css b/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.css
index f7ac6ac4af2..606c7c82aad 100644
--- a/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.css
+++ b/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.css
@@ -193,7 +193,13 @@ input[type=checkbox]:focus ~ .checkbox {
display: none;
}
-.safe-browsing .icon {
+.safe-browsing .new-icons {
+ background-image: -webkit-image-set(
+ url(images/1x/triangle_white.png) 1x,
+ url(images/2x/triangle_white.png) 2x);
+}
+
+.safe-browsing .old-icons {
background-image: -webkit-image-set(
url(images/1x/stop_sign.png) 1x,
url(images/2x/stop_sign.png) 2x);
@@ -204,7 +210,13 @@ input[type=checkbox]:focus ~ .checkbox {
font-size: .875em;
}
-.ssl .icon {
+.ssl .new-icons {
+ background-image: -webkit-image-set(
+ url(images/1x/triangle_red.png) 1x,
+ url(images/2x/triangle_red.png) 2x);
+}
+
+.ssl .old-icons {
background-image: -webkit-image-set(
url(images/1x/brokenssl_red.png) 1x,
url(images/2x/brokenssl_red.png) 2x);
diff --git a/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.js b/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.js
index f25461628dc..332f6939fc3 100644
--- a/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.js
+++ b/chromium/components/security_interstitials/core/browser/resources/interstitial_v2.js
@@ -8,7 +8,7 @@
var expandedDetails = false;
var keyPressState = 0;
-// Should match SecurityInterstitialCommands in security_interstitial_page.h
+// Should match security_interstitials::SecurityInterstitialCommands
var CMD_DONT_PROCEED = 0;
var CMD_PROCEED = 1;
// Ways for user to get more information
@@ -23,8 +23,9 @@ var CMD_OPEN_LOGIN = 7;
var CMD_DO_REPORT = 8;
var CMD_DONT_REPORT = 9;
var CMD_OPEN_REPORTING_PRIVACY = 10;
+var CMD_OPEN_WHITEPAPER = 11;
// Report a phishing error.
-var CMD_REPORT_PHISHING_ERROR = 11;
+var CMD_REPORT_PHISHING_ERROR = 12;
/**
* A convenience method for sending commands to the parent page.
@@ -109,6 +110,11 @@ function setupEvents() {
$('body').classList.add('safe-browsing');
}
+ if (loadTimeData.getBoolean('iconUpdate') === true)
+ $('icon').classList.add('new-icons');
+ else
+ $('icon').classList.add('old-icons');
+
if (hidePrimaryButton) {
$('primary-button').classList.add('hidden');
} else {
@@ -148,13 +154,17 @@ function setupEvents() {
if (ssl && overridable) {
$('proceed-link').classList.add('small-link');
- } else if ($('help-link')) {
- // Overridable SSL page doesn't have this link.
- $('help-link').addEventListener('click', function(event) {
- if (ssl || loadTimeData.getBoolean('phishing'))
- sendCommand(CMD_OPEN_HELP_CENTER);
- else
- sendCommand(CMD_OPEN_DIAGNOSTIC);
+ }
+
+ if ($('diagnostic-link')) {
+ $('diagnostic-link').addEventListener('click', function(event) {
+ sendCommand(CMD_OPEN_DIAGNOSTIC);
+ });
+ }
+
+ if ($('learn-more-link')) {
+ $('learn-more-link').addEventListener('click', function(event) {
+ sendCommand(CMD_OPEN_HELP_CENTER);
});
}
diff --git a/chromium/components/security_interstitials/core/common_string_util.cc b/chromium/components/security_interstitials/core/common_string_util.cc
index 2cb0375d0d0..c5f01ea9669 100644
--- a/chromium/components/security_interstitials/core/common_string_util.cc
+++ b/chromium/components/security_interstitials/core/common_string_util.cc
@@ -4,6 +4,7 @@
#include "components/security_interstitials/core/common_string_util.h"
+#include "base/feature_list.h"
#include "base/i18n/rtl.h"
#include "base/i18n/time_formatting.h"
#include "base/strings/string_util.h"
@@ -12,6 +13,11 @@
#include "net/base/net_errors.h"
#include "ui/base/l10n/l10n_util.h"
+namespace {
+ const base::Feature kSecurityWarningIconUpdate{
+ "SecurityWarningIconUpdate", base::FEATURE_DISABLED_BY_DEFAULT};
+} // namespace
+
namespace security_interstitials {
namespace common_string_util {
@@ -50,6 +56,11 @@ void PopulateSSLDebuggingStrings(const net::SSLInfo ssl_info,
"pem", base::JoinString(encoded_chain, base::StringPiece()));
}
+void PopulateNewIconStrings(base::DictionaryValue* load_time_data) {
+ load_time_data->SetBoolean(
+ "iconUpdate", base::FeatureList::IsEnabled(kSecurityWarningIconUpdate));
+}
+
} // namespace common_string_util
} // namespace security_interstitials
diff --git a/chromium/components/security_interstitials/core/common_string_util.h b/chromium/components/security_interstitials/core/common_string_util.h
index 146b03d1209..da10ee7a872 100644
--- a/chromium/components/security_interstitials/core/common_string_util.h
+++ b/chromium/components/security_interstitials/core/common_string_util.h
@@ -29,6 +29,9 @@ void PopulateSSLDebuggingStrings(const net::SSLInfo ssl_info,
const base::Time time_triggered,
base::DictionaryValue* load_time_data);
+// For determining whether to use the old or new icon sets.
+void PopulateNewIconStrings(base::DictionaryValue* load_time_data);
+
} // common_string_util
} // namespace security_interstitials
diff --git a/chromium/components/security_interstitials/core/controller_client.cc b/chromium/components/security_interstitials/core/controller_client.cc
index a17f3f19f90..e38fc18dd79 100644
--- a/chromium/components/security_interstitials/core/controller_client.cc
+++ b/chromium/components/security_interstitials/core/controller_client.cc
@@ -22,18 +22,16 @@ const char kPrivacyLinkHtml[] =
"<a id=\"privacy-link\" href=\"\" onclick=\"sendCommand(%d); "
"return false;\" onmousedown=\"return false;\">%s</a>";
-ControllerClient::ControllerClient() {}
+ControllerClient::ControllerClient(
+ std::unique_ptr<MetricsHelper> metrics_helper)
+ : metrics_helper_(std::move(metrics_helper)) {}
+
ControllerClient::~ControllerClient() {}
MetricsHelper* ControllerClient::metrics_helper() const {
return metrics_helper_.get();
}
-void ControllerClient::set_metrics_helper(
- std::unique_ptr<MetricsHelper> metrics_helper) {
- metrics_helper_ = std::move(metrics_helper);
-}
-
void ControllerClient::SetReportingPreference(bool report) {
GetPrefService()->SetBoolean(GetExtendedReportingPrefName(), report);
metrics_helper_->RecordUserInteraction(
@@ -50,4 +48,13 @@ void ControllerClient::OpenExtendedReportingPrivacyPolicy() {
OpenUrlInCurrentTab(privacy_url);
}
+void ControllerClient::OpenExtendedReportingWhitepaper() {
+ metrics_helper_->RecordUserInteraction(MetricsHelper::SHOW_WHITEPAPER);
+ GURL whitepaper_url(
+ l10n_util::GetStringUTF8(IDS_SAFE_BROWSING_WHITEPAPER_URL));
+ whitepaper_url = google_util::AppendGoogleLocaleParam(whitepaper_url,
+ GetApplicationLocale());
+ OpenUrlInCurrentTab(whitepaper_url);
+}
+
} // namespace security_interstitials
diff --git a/chromium/components/security_interstitials/core/controller_client.h b/chromium/components/security_interstitials/core/controller_client.h
index 2aced84ce84..42f9990ee2f 100644
--- a/chromium/components/security_interstitials/core/controller_client.h
+++ b/chromium/components/security_interstitials/core/controller_client.h
@@ -46,8 +46,9 @@ enum SecurityInterstitialCommands {
CMD_DO_REPORT = 8,
CMD_DONT_REPORT = 9,
CMD_OPEN_REPORTING_PRIVACY = 10,
+ CMD_OPEN_WHITEPAPER = 11,
// Report a phishing error
- CMD_REPORT_PHISHING_ERROR = 11,
+ CMD_REPORT_PHISHING_ERROR = 12,
};
// Provides methods for handling commands from the user, which requires some
@@ -55,12 +56,13 @@ enum SecurityInterstitialCommands {
// by the JavaScript error page.
class ControllerClient {
public:
- ControllerClient();
+ explicit ControllerClient(std::unique_ptr<MetricsHelper> metrics_helper);
virtual ~ControllerClient();
// Handle the user's reporting preferences.
void SetReportingPreference(bool report);
void OpenExtendedReportingPrivacyPolicy();
+ void OpenExtendedReportingWhitepaper();
// If available, open the operating system's date/time settings.
virtual bool CanLaunchDateAndTimeSettings() = 0;
@@ -76,7 +78,6 @@ class ControllerClient {
virtual void Reload() = 0;
MetricsHelper* metrics_helper() const;
- void set_metrics_helper(std::unique_ptr<MetricsHelper> metrics_helper);
virtual void OpenUrlInCurrentTab(const GURL& url) = 0;
diff --git a/chromium/components/security_interstitials/core/metrics_helper.h b/chromium/components/security_interstitials/core/metrics_helper.h
index 7f41376e79e..66a3d6dd874 100644
--- a/chromium/components/security_interstitials/core/metrics_helper.h
+++ b/chromium/components/security_interstitials/core/metrics_helper.h
@@ -55,6 +55,7 @@ class MetricsHelper {
SET_EXTENDED_REPORTING_DISABLED,
EXTENDED_REPORTING_IS_ENABLED,
REPORT_PHISHING_ERROR,
+ SHOW_WHITEPAPER,
MAX_INTERACTION
};
diff --git a/chromium/components/security_interstitials/core/ssl_error_ui.cc b/chromium/components/security_interstitials/core/ssl_error_ui.cc
index 993b19a8448..320fbbe0447 100644
--- a/chromium/components/security_interstitials/core/ssl_error_ui.cc
+++ b/chromium/components/security_interstitials/core/ssl_error_ui.cc
@@ -16,7 +16,7 @@ namespace security_interstitials {
namespace {
// URL for help page.
-const char kHelpURL[] = "https://support.google.com/chrome/answer/4454607";
+const char kHelpURL[] = "https://support.google.com/chrome/answer/6098869";
bool IsMasked(int options, SSLErrorUI::SSLErrorOptionsMask mask) {
return ((options & mask) != 0);
@@ -66,6 +66,7 @@ void SSLErrorUI::PopulateStringsForHTML(base::DictionaryValue* load_time_data) {
common_string_util::PopulateSSLLayoutStrings(cert_error_, load_time_data);
common_string_util::PopulateSSLDebuggingStrings(ssl_info_, time_triggered_,
load_time_data);
+ common_string_util::PopulateNewIconStrings(load_time_data);
// Shared values for both the overridable and non-overridable versions.
load_time_data->SetBoolean("bad_clock", false);
@@ -181,6 +182,9 @@ void SSLErrorUI::HandleCommand(SecurityInterstitialCommands command) {
case CMD_OPEN_REPORTING_PRIVACY:
controller_->OpenExtendedReportingPrivacyPolicy();
break;
+ case CMD_OPEN_WHITEPAPER:
+ controller_->OpenExtendedReportingWhitepaper();
+ break;
case CMD_OPEN_DATE_SETTINGS:
case CMD_OPEN_DIAGNOSTIC:
case CMD_OPEN_LOGIN:
diff --git a/chromium/components/security_interstitials_strings.grdp b/chromium/components/security_interstitials_strings.grdp
index 14f8f56d3bf..9cf633464ef 100644
--- a/chromium/components/security_interstitials_strings.grdp
+++ b/chromium/components/security_interstitials_strings.grdp
@@ -51,6 +51,9 @@
<!-- Extended reporting strings -->
<message name="IDS_SAFE_BROWSING_PRIVACY_POLICY_URL" translateable="false">
+ https://www.google.com/chrome/browser/privacy/#safe-browsing-policies
+ </message>
+ <message name="IDS_SAFE_BROWSING_WHITEPAPER_URL" translateable="false">
https://www.google.com/chrome/browser/privacy/whitepaper.html#malware
</message>
@@ -64,22 +67,6 @@
<message name="IDS_SSL_V2_PRIMARY_PARAGRAPH" desc="The primary explanatory paragraph for the SSL interstitial.">
Attackers might be trying to steal your information from <ph name="BEGIN_BOLD">&lt;strong&gt;</ph><ph name="SITE">$1<ex>google.com</ex></ph><ph name="END_BOLD">&lt;/strong&gt;</ph> (for example, passwords, messages, or credit cards).
</message>
- <if expr="_google_chrome">
- <message name="IDS_SSL_NONOVERRIDABLE_MORE" desc="Body text for the explanation shown if user clicks on the Details button.">
- <ph name="SITE">$1<ex>google.com</ex></ph> normally uses encryption to protect your information. When Google Chrome tried to connect to <ph name="SITE">$1<ex>google.com</ex></ph> this time, the website sent back unusual and incorrect credentials. This may happen when an attacker is trying to pretend to be <ph name="SITE">$1<ex>google.com</ex></ph>, or a Wi-Fi sign-in screen has interrupted the connection. Your information is still secure because Google Chrome stopped the connection before any data was exchanged.
- </message>
- <message name="IDS_SSL_NONOVERRIDABLE_INVALID" desc="A sentence to explain why the user can't proceed.">
- You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because the website sent scrambled credentials that Google Chrome cannot process. Network errors and attacks are usually temporary, so this page will probably work later.
- </message>
- </if>
- <if expr="not _google_chrome">
- <message name="IDS_SSL_NONOVERRIDABLE_MORE" desc="Body text for the explanation shown if user clicks on the Details button.">
- <ph name="SITE">$1<ex>google.com</ex></ph> normally uses encryption to protect your information. When Chromium tried to connect to <ph name="SITE">$1<ex>google.com</ex></ph> this time, the website sent back unusual and incorrect credentials. This may happen when an attacker is trying to pretend to be <ph name="SITE">$1<ex>google.com</ex></ph>, or a Wi-Fi sign-in screen has interrupted the connection. Your information is still secure because Chromium stopped the connection before any data was exchanged.
- </message>
- <message name="IDS_SSL_NONOVERRIDABLE_INVALID" desc="A sentence to explain why the user can't proceed.">
- You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because the website sent scrambled credentials that Chromium cannot process. Network errors and attacks are usually temporary, so this page will probably work later.
- </message>
- </if>
<!-- SSL error page: overridable -->
<message name="IDS_SSL_OVERRIDABLE_SAFETY_BUTTON" desc="The text for the button that takes the user back to the previous page.">
@@ -94,13 +81,29 @@
Reload
</message>
<message name="IDS_SSL_NONOVERRIDABLE_PINNED" desc="A sentence to explain why the user can't proceed, plus a link to a help page about certificate pinning.">
- You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because the website <ph name="BEGIN_LINK">&lt;a href="#" id="help-link"&gt;</ph>uses certificate pinning<ph name="END_LINK">&lt;/a&gt;</ph>. Network errors and attacks are usually temporary, so this page will probably work later.
+ You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because the website uses certificate pinning. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_SSL_NONOVERRIDABLE_HSTS" desc="A sentence to explain why the user can't proceed, plus a link to a help page about HSTS.">
- You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because the website <ph name="BEGIN_LINK">&lt;a href="#" id="help-link"&gt;</ph>uses HSTS<ph name="END_LINK">&lt;/a&gt;</ph>. Network errors and attacks are usually temporary, so this page will probably work later.
+ You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because the website uses HSTS. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_SSL_NONOVERRIDABLE_REVOKED" desc="A sentence to explain why the user can't proceed, plus a link to a help page about certificate revocation.">
- You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because <ph name="BEGIN_LINK">&lt;a href="#" id="help-link"&gt;</ph>this certificate has been revoked<ph name="END_LINK">&lt;/a&gt;</ph>. Network errors and attacks are usually temporary, so this page will probably work later.
+ You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because its certificate has been revoked. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
+ <if expr="_google_chrome">
+ <message name="IDS_SSL_NONOVERRIDABLE_MORE" desc="Body text for the explanation shown if user clicks on the Details button.">
+ <ph name="SITE">$1<ex>google.com</ex></ph> normally uses encryption to protect your information. When Google Chrome tried to connect to <ph name="SITE">$1<ex>google.com</ex></ph> this time, the website sent back unusual and incorrect credentials. This may happen when an attacker is trying to pretend to be <ph name="SITE">$1<ex>google.com</ex></ph>, or a Wi-Fi sign-in screen has interrupted the connection. Your information is still secure because Google Chrome stopped the connection before any data was exchanged.
+ </message>
+ <message name="IDS_SSL_NONOVERRIDABLE_INVALID" desc="A sentence to explain why the user can't proceed.">
+ You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because the website sent scrambled credentials that Google Chrome cannot process. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
+ </message>
+ </if>
+ <if expr="not _google_chrome">
+ <message name="IDS_SSL_NONOVERRIDABLE_MORE" desc="Body text for the explanation shown if user clicks on the Details button.">
+ <ph name="SITE">$1<ex>google.com</ex></ph> normally uses encryption to protect your information. When Chromium tried to connect to <ph name="SITE">$1<ex>google.com</ex></ph> this time, the website sent back unusual and incorrect credentials. This may happen when an attacker is trying to pretend to be <ph name="SITE">$1<ex>google.com</ex></ph>, or a Wi-Fi sign-in screen has interrupted the connection. Your information is still secure because Chromium stopped the connection before any data was exchanged.
+ </message>
+ <message name="IDS_SSL_NONOVERRIDABLE_INVALID" desc="A sentence to explain why the user can't proceed.">
+ You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because the website sent scrambled credentials that Chromium cannot process. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
+ </message>
+ </if>
-</grit-part> \ No newline at end of file
+</grit-part>
diff --git a/chromium/components/security_state.gypi b/chromium/components/security_state.gypi
deleted file mode 100644
index d1376b44b98..00000000000
--- a/chromium/components/security_state.gypi
+++ /dev/null
@@ -1,42 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'security_state',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'security_state/security_state_model.cc',
- 'security_state/security_state_model.h',
- 'security_state/security_state_model_client.h',
- 'security_state/switches.cc',
- 'security_state/switches.h',
- ]
- },
- ],
- 'conditions' : [
- ['OS=="android"', {
- 'targets': [
- {
- # GN: //components/security_state:security_state_enums_java
- 'target_name': 'security_state_enums_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'security_state/security_state_model.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- ],
- },
- ],
- ],
-}
diff --git a/chromium/components/security_state/BUILD.gn b/chromium/components/security_state/BUILD.gn
index 4d2823b8e31..9eab4a3a0aa 100644
--- a/chromium/components/security_state/BUILD.gn
+++ b/chromium/components/security_state/BUILD.gn
@@ -7,8 +7,7 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-# GYP version: components/security_state.gyp
-source_set("security_state") {
+static_library("security_state") {
sources = [
"security_state_model.cc",
"security_state_model.h",
@@ -24,7 +23,6 @@ source_set("security_state") {
}
if (is_android) {
- # GYP: //components/security_state.gypi:security_state_enums_java
java_cpp_enum("security_state_enums_java") {
sources = [
"security_state_model.h",
diff --git a/chromium/components/security_state/security_state_model.cc b/chromium/components/security_state/security_state_model.cc
index 4084402f050..6239186adb5 100644
--- a/chromium/components/security_state/security_state_model.cc
+++ b/chromium/components/security_state/security_state_model.cc
@@ -18,34 +18,68 @@ namespace security_state {
namespace {
-SecurityStateModel::SecurityLevel GetSecurityLevelForNonSecureFieldTrial() {
+// Do not change or reorder this enum, and add new values at the end. It is used
+// in the MarkHttpAs histogram.
+enum MarkHttpStatus { NEUTRAL, NON_SECURE, HTTP_SHOW_WARNING, LAST_STATUS };
+
+// If |switch_or_field_trial_group| corresponds to a valid
+// MarkHttpAs group, sets |*level| and |*histogram_status| to the
+// appropriate values and returns true. Otherwise, returns false.
+bool GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
+ std::string switch_or_field_trial_group,
+ bool displayed_sensitive_input_on_http,
+ SecurityStateModel::SecurityLevel* level,
+ MarkHttpStatus* histogram_status) {
+ if (switch_or_field_trial_group == switches::kMarkHttpAsNeutral) {
+ *level = SecurityStateModel::NONE;
+ *histogram_status = NEUTRAL;
+ return true;
+ }
+
+ if (switch_or_field_trial_group == switches::kMarkHttpAsDangerous) {
+ *level = SecurityStateModel::DANGEROUS;
+ *histogram_status = NON_SECURE;
+ return true;
+ }
+
+ if (switch_or_field_trial_group ==
+ switches::kMarkHttpWithPasswordsOrCcWithChip) {
+ if (displayed_sensitive_input_on_http) {
+ *level = SecurityStateModel::HTTP_SHOW_WARNING;
+ *histogram_status = HTTP_SHOW_WARNING;
+ } else {
+ *level = SecurityStateModel::NONE;
+ *histogram_status = NEUTRAL;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+SecurityStateModel::SecurityLevel GetSecurityLevelForNonSecureFieldTrial(
+ bool displayed_sensitive_input_on_http) {
std::string choice =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kMarkNonSecureAs);
+ switches::kMarkHttpAs);
std::string group = base::FieldTrialList::FindFullName("MarkNonSecureAs");
- // Do not change this enum. It is used in the histogram.
- enum MarkNonSecureStatus { NEUTRAL, DUBIOUS, NON_SECURE, LAST_STATUS };
- const char kEnumeration[] = "MarkNonSecureAs";
+ const char kEnumeration[] = "MarkHttpAs";
SecurityStateModel::SecurityLevel level = SecurityStateModel::NONE;
- MarkNonSecureStatus status;
-
- if (choice == switches::kMarkNonSecureAsNeutral) {
- status = NEUTRAL;
- level = SecurityStateModel::NONE;
- } else if (choice == switches::kMarkNonSecureAsNonSecure) {
- status = NON_SECURE;
- level = SecurityStateModel::SECURITY_ERROR;
- } else if (group == switches::kMarkNonSecureAsNeutral) {
- status = NEUTRAL;
- level = SecurityStateModel::NONE;
- } else if (group == switches::kMarkNonSecureAsNonSecure) {
- status = NON_SECURE;
- level = SecurityStateModel::SECURITY_ERROR;
- } else {
- status = NEUTRAL;
- level = SecurityStateModel::NONE;
+ MarkHttpStatus status;
+
+ // If the command-line switch is set, then it takes precedence over
+ // the field trial group.
+ if (!GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
+ choice, displayed_sensitive_input_on_http, &level, &status)) {
+ if (!GetSecurityLevelAndHistogramValueForNonSecureFieldTrial(
+ group, displayed_sensitive_input_on_http, &level, &status)) {
+ // If neither the command-line switch nor field trial group is set, then
+ // nonsecure defaults to neutral.
+ status = NEUTRAL;
+ level = SecurityStateModel::NONE;
+ }
}
UMA_HISTOGRAM_ENUMERATION(kEnumeration, status, LAST_STATUS);
@@ -72,19 +106,14 @@ SecurityStateModel::SHA1DeprecationStatus GetSHA1DeprecationStatus(
return SecurityStateModel::NO_DEPRECATED_SHA1;
}
-SecurityStateModel::MixedContentStatus GetMixedContentStatus(
- const SecurityStateModel::VisibleSecurityState& visible_security_state) {
- bool ran_insecure_content = visible_security_state.ran_mixed_content;
- bool displayed_insecure_content =
- visible_security_state.displayed_mixed_content;
- if (ran_insecure_content && displayed_insecure_content)
- return SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT;
- if (ran_insecure_content)
- return SecurityStateModel::RAN_MIXED_CONTENT;
- if (displayed_insecure_content)
- return SecurityStateModel::DISPLAYED_MIXED_CONTENT;
-
- return SecurityStateModel::NO_MIXED_CONTENT;
+SecurityStateModel::ContentStatus GetContentStatus(bool displayed, bool ran) {
+ if (ran && displayed)
+ return SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN;
+ if (ran)
+ return SecurityStateModel::CONTENT_STATUS_RAN;
+ if (displayed)
+ return SecurityStateModel::CONTENT_STATUS_DISPLAYED;
+ return SecurityStateModel::CONTENT_STATUS_NONE;
}
SecurityStateModel::SecurityLevel GetSecurityLevelForRequest(
@@ -92,36 +121,52 @@ SecurityStateModel::SecurityLevel GetSecurityLevelForRequest(
SecurityStateModelClient* client,
const scoped_refptr<net::X509Certificate>& cert,
SecurityStateModel::SHA1DeprecationStatus sha1_status,
- SecurityStateModel::MixedContentStatus mixed_content_status) {
- DCHECK(visible_security_state.initialized);
+ SecurityStateModel::ContentStatus mixed_content_status,
+ SecurityStateModel::ContentStatus content_with_cert_errors_status) {
+ DCHECK(visible_security_state.connection_info_initialized ||
+ visible_security_state.fails_malware_check);
+
+ // Override the connection security information if the website failed the
+ // browser's malware checks.
+ if (visible_security_state.fails_malware_check)
+ return SecurityStateModel::DANGEROUS;
+
GURL url = visible_security_state.url;
switch (visible_security_state.initial_security_level) {
- case SecurityStateModel::NONE: {
- if (!client->IsOriginSecure(url) && url.IsStandard())
- return GetSecurityLevelForNonSecureFieldTrial();
+ case SecurityStateModel::NONE:
+ case SecurityStateModel::HTTP_SHOW_WARNING: {
+ if (!client->IsOriginSecure(url) && url.IsStandard()) {
+ return GetSecurityLevelForNonSecureFieldTrial(
+ visible_security_state.displayed_password_field_on_http ||
+ visible_security_state.displayed_credit_card_field_on_http);
+ }
return SecurityStateModel::NONE;
}
- case SecurityStateModel::SECURITY_ERROR:
- return SecurityStateModel::SECURITY_ERROR;
+ case SecurityStateModel::DANGEROUS:
+ return SecurityStateModel::DANGEROUS;
case SecurityStateModel::SECURITY_WARNING:
- case SecurityStateModel::SECURITY_POLICY_WARNING:
+ case SecurityStateModel::SECURE_WITH_POLICY_INSTALLED_CERT:
return visible_security_state.initial_security_level;
case SecurityStateModel::SECURE:
case SecurityStateModel::EV_SECURE: {
// Major cert errors and active mixed content will generally be
- // downgraded by the embedder to SECURITY_ERROR and handled above,
+ // downgraded by the embedder to DANGEROUS and handled above,
// but downgrade here just in case.
net::CertStatus cert_status = visible_security_state.cert_status;
if (net::IsCertStatusError(cert_status) &&
!net::IsCertStatusMinorError(cert_status)) {
- return SecurityStateModel::SECURITY_ERROR;
+ return SecurityStateModel::DANGEROUS;
}
- if (mixed_content_status == SecurityStateModel::RAN_MIXED_CONTENT ||
+ if (mixed_content_status == SecurityStateModel::CONTENT_STATUS_RAN ||
mixed_content_status ==
- SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT) {
+ SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN ||
+ content_with_cert_errors_status ==
+ SecurityStateModel::CONTENT_STATUS_RAN ||
+ content_with_cert_errors_status ==
+ SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN) {
return SecurityStateModel::kRanInsecureContentLevel;
}
@@ -131,19 +176,24 @@ SecurityStateModel::SecurityLevel GetSecurityLevelForRequest(
// other authenticated-but-with-errors indicate something may
// be wrong, or may be wrong in the future, but is unclear now.
if (client->UsedPolicyInstalledCertificate())
- return SecurityStateModel::SECURITY_POLICY_WARNING;
+ return SecurityStateModel::SECURE_WITH_POLICY_INSTALLED_CERT;
if (sha1_status == SecurityStateModel::DEPRECATED_SHA1_MAJOR)
- return SecurityStateModel::SECURITY_ERROR;
+ return SecurityStateModel::DANGEROUS;
if (sha1_status == SecurityStateModel::DEPRECATED_SHA1_MINOR)
return SecurityStateModel::NONE;
// Active mixed content is handled above.
- DCHECK_NE(SecurityStateModel::RAN_MIXED_CONTENT, mixed_content_status);
- DCHECK_NE(SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT,
+ DCHECK_NE(SecurityStateModel::CONTENT_STATUS_RAN, mixed_content_status);
+ DCHECK_NE(SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN,
mixed_content_status);
- if (mixed_content_status == SecurityStateModel::DISPLAYED_MIXED_CONTENT)
+
+ if (mixed_content_status ==
+ SecurityStateModel::CONTENT_STATUS_DISPLAYED ||
+ content_with_cert_errors_status ==
+ SecurityStateModel::CONTENT_STATUS_DISPLAYED) {
return SecurityStateModel::kDisplayedInsecureContentLevel;
+ }
if (net::IsCertStatusError(cert_status)) {
// Major cert errors are handled above.
@@ -170,34 +220,48 @@ void SecurityInfoForRequest(
const SecurityStateModel::VisibleSecurityState& visible_security_state,
const scoped_refptr<net::X509Certificate>& cert,
SecurityStateModel::SecurityInfo* security_info) {
- if (!visible_security_state.initialized) {
+ if (!visible_security_state.connection_info_initialized) {
*security_info = SecurityStateModel::SecurityInfo();
+ security_info->fails_malware_check =
+ visible_security_state.fails_malware_check;
+ if (security_info->fails_malware_check) {
+ security_info->security_level = GetSecurityLevelForRequest(
+ visible_security_state, client, cert,
+ SecurityStateModel::UNKNOWN_SHA1,
+ SecurityStateModel::CONTENT_STATUS_UNKNOWN,
+ SecurityStateModel::CONTENT_STATUS_UNKNOWN);
+ }
return;
}
- security_info->cert_id = visible_security_state.cert_id;
+ security_info->certificate = visible_security_state.certificate;
security_info->sha1_deprecation_status =
GetSHA1DeprecationStatus(cert, visible_security_state);
security_info->mixed_content_status =
- GetMixedContentStatus(visible_security_state);
+ GetContentStatus(visible_security_state.displayed_mixed_content,
+ visible_security_state.ran_mixed_content);
+ security_info->content_with_cert_errors_status = GetContentStatus(
+ visible_security_state.displayed_content_with_cert_errors,
+ visible_security_state.ran_content_with_cert_errors);
security_info->security_bits = visible_security_state.security_bits;
security_info->connection_status = visible_security_state.connection_status;
+ security_info->key_exchange_group = visible_security_state.key_exchange_group;
security_info->cert_status = visible_security_state.cert_status;
security_info->scheme_is_cryptographic =
visible_security_state.url.SchemeIsCryptographic();
+ security_info->obsolete_ssl_status =
+ net::ObsoleteSSLStatus(security_info->connection_status);
security_info->pkp_bypassed = visible_security_state.pkp_bypassed;
- security_info->is_secure_protocol_and_ciphersuite =
- (net::SSLConnectionStatusToVersion(security_info->connection_status) >=
- net::SSL_CONNECTION_VERSION_TLS1_2 &&
- net::IsSecureTLSCipherSuite(net::SSLConnectionStatusToCipherSuite(
- security_info->connection_status)));
-
security_info->sct_verify_statuses =
visible_security_state.sct_verify_statuses;
- security_info->security_level =
- GetSecurityLevelForRequest(visible_security_state, client, cert,
- security_info->sha1_deprecation_status,
- security_info->mixed_content_status);
+ security_info->fails_malware_check =
+ visible_security_state.fails_malware_check;
+
+ security_info->security_level = GetSecurityLevelForRequest(
+ visible_security_state, client, cert,
+ security_info->sha1_deprecation_status,
+ security_info->mixed_content_status,
+ security_info->content_with_cert_errors_status);
}
} // namespace
@@ -207,18 +271,20 @@ const SecurityStateModel::SecurityLevel
SecurityStateModel::NONE;
const SecurityStateModel::SecurityLevel
SecurityStateModel::kRanInsecureContentLevel =
- SecurityStateModel::SECURITY_ERROR;
+ SecurityStateModel::DANGEROUS;
SecurityStateModel::SecurityInfo::SecurityInfo()
: security_level(SecurityStateModel::NONE),
+ fails_malware_check(false),
sha1_deprecation_status(SecurityStateModel::NO_DEPRECATED_SHA1),
- mixed_content_status(SecurityStateModel::NO_MIXED_CONTENT),
+ mixed_content_status(SecurityStateModel::CONTENT_STATUS_NONE),
+ content_with_cert_errors_status(SecurityStateModel::CONTENT_STATUS_NONE),
scheme_is_cryptographic(false),
cert_status(0),
- cert_id(0),
security_bits(-1),
connection_status(0),
- is_secure_protocol_and_ciphersuite(false),
+ key_exchange_group(0),
+ obsolete_ssl_status(net::OBSOLETE_SSL_NONE),
pkp_bypassed(false) {}
SecurityStateModel::SecurityInfo::~SecurityInfo() {}
@@ -227,30 +293,14 @@ SecurityStateModel::SecurityStateModel() {}
SecurityStateModel::~SecurityStateModel() {}
-const SecurityStateModel::SecurityInfo& SecurityStateModel::GetSecurityInfo()
- const {
+void SecurityStateModel::GetSecurityInfo(
+ SecurityStateModel::SecurityInfo* result) const {
scoped_refptr<net::X509Certificate> cert = nullptr;
client_->RetrieveCert(&cert);
- // Check if the cached |security_info_| must be recomputed.
VisibleSecurityState new_visible_state;
client_->GetVisibleSecurityState(&new_visible_state);
- bool visible_security_state_changed =
- !(visible_security_state_ == new_visible_state);
- if (!visible_security_state_changed) {
- // A cert must be present in order for the site to be considered
- // EV_SECURE, and the cert might have been removed since the
- // security level was last computed.
- if (security_info_.security_level == EV_SECURE && !cert) {
- security_info_.security_level = SECURE;
- }
- return security_info_;
- }
-
- visible_security_state_ = new_visible_state;
- SecurityInfoForRequest(client_, visible_security_state_, cert,
- &security_info_);
- return security_info_;
+ SecurityInfoForRequest(client_, new_visible_state, cert, result);
}
void SecurityStateModel::SetClient(SecurityStateModelClient* client) {
@@ -258,15 +308,20 @@ void SecurityStateModel::SetClient(SecurityStateModelClient* client) {
}
SecurityStateModel::VisibleSecurityState::VisibleSecurityState()
- : initialized(false),
- initial_security_level(SecurityStateModel::NONE),
- cert_id(0),
+ : initial_security_level(SecurityStateModel::NONE),
+ fails_malware_check(false),
+ connection_info_initialized(false),
cert_status(0),
connection_status(0),
+ key_exchange_group(0),
security_bits(-1),
displayed_mixed_content(false),
ran_mixed_content(false),
- pkp_bypassed(false) {}
+ displayed_content_with_cert_errors(false),
+ ran_content_with_cert_errors(false),
+ pkp_bypassed(false),
+ displayed_password_field_on_http(false),
+ displayed_credit_card_field_on_http(false) {}
SecurityStateModel::VisibleSecurityState::~VisibleSecurityState() {}
@@ -274,13 +329,23 @@ bool SecurityStateModel::VisibleSecurityState::operator==(
const SecurityStateModel::VisibleSecurityState& other) const {
return (url == other.url &&
initial_security_level == other.initial_security_level &&
- cert_id == other.cert_id && cert_status == other.cert_status &&
+ fails_malware_check == other.fails_malware_check &&
+ !!certificate == !!other.certificate &&
+ (certificate ? certificate->Equals(other.certificate.get()) : true) &&
connection_status == other.connection_status &&
+ key_exchange_group == other.key_exchange_group &&
security_bits == other.security_bits &&
sct_verify_statuses == other.sct_verify_statuses &&
displayed_mixed_content == other.displayed_mixed_content &&
ran_mixed_content == other.ran_mixed_content &&
- pkp_bypassed == other.pkp_bypassed);
+ displayed_content_with_cert_errors ==
+ other.displayed_content_with_cert_errors &&
+ ran_content_with_cert_errors == other.ran_content_with_cert_errors &&
+ pkp_bypassed == other.pkp_bypassed &&
+ displayed_password_field_on_http ==
+ other.displayed_password_field_on_http &&
+ displayed_credit_card_field_on_http ==
+ other.displayed_credit_card_field_on_http);
}
} // namespace security_state
diff --git a/chromium/components/security_state/security_state_model.h b/chromium/components/security_state/security_state_model.h
index b4ff3e9c5f1..df7eba5c258 100644
--- a/chromium/components/security_state/security_state_model.h
+++ b/chromium/components/security_state/security_state_model.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_SECURITY_STATE_SECURITY_STATE_MODEL_H_
#define COMPONENTS_SECURITY_STATE_SECURITY_STATE_MODEL_H_
+#include <stdint.h>
+
#include "base/macros.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/sct_status_flags.h"
@@ -34,30 +36,40 @@ class SecurityStateModel {
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.security_state
// GENERATED_JAVA_CLASS_NAME_OVERRIDE: ConnectionSecurityLevel
enum SecurityLevel {
- // HTTP/no URL/HTTPS but with insecure passive content on the page
+ // HTTP/no URL/HTTPS but with insecure passive content on the page.
NONE,
- // HTTPS with valid EV cert
+ // HTTP, in a case where we want to show a visible warning about the page's
+ // lack of security.
+ //
+ // The criteria used to classify pages as NONE vs. HTTP_SHOW_WARNING will
+ // change over time. Eventually, NONE will be eliminated.
+ // See https://crbug.com/647754.
+ HTTP_SHOW_WARNING,
+
+ // HTTPS with valid EV cert.
EV_SECURE,
- // HTTPS (non-EV) with valid cert
+ // HTTPS (non-EV) with valid cert.
SECURE,
- // HTTPS, but with an outdated protocol version
+ // HTTPS, but with an outdated protocol version.
SECURITY_WARNING,
// HTTPS, but the certificate verification chain is anchored on a
- // certificate that was installed by the system administrator
- SECURITY_POLICY_WARNING,
+ // certificate that was installed by the system administrator.
+ SECURE_WITH_POLICY_INSTALLED_CERT,
- // Attempted HTTPS and failed, page not authenticated, or HTTPS with
- // insecure active content on the page
- SECURITY_ERROR,
+ // Attempted HTTPS and failed, page not authenticated, HTTPS with
+ // insecure active content on the page, malware, phishing, or any other
+ // serious security issue that could be dangerous.
+ DANGEROUS,
};
// Describes how the SHA1 deprecation policy applies to an HTTPS
// connection.
enum SHA1DeprecationStatus {
+ UNKNOWN_SHA1,
// No SHA1 deprecation policy applies.
NO_DEPRECATED_SHA1,
// The connection used a certificate with a SHA1 signature in the
@@ -70,16 +82,16 @@ class SecurityStateModel {
DEPRECATED_SHA1_MAJOR,
};
- // Describes the type of mixed content (if any) that a site
- // displayed/ran.
- enum MixedContentStatus {
- NO_MIXED_CONTENT,
- // The site displayed insecure resources (passive mixed content).
- DISPLAYED_MIXED_CONTENT,
- // The site ran insecure code (active mixed content).
- RAN_MIXED_CONTENT,
- // The site both ran and displayed insecure resources.
- RAN_AND_DISPLAYED_MIXED_CONTENT,
+ // The ContentStatus enum is used to describe content on the page that
+ // has significantly different security properties than the main page
+ // load. Content can be passive content that is displayed (such as
+ // images) or active content that is run (such as scripts or iframes).
+ enum ContentStatus {
+ CONTENT_STATUS_UNKNOWN,
+ CONTENT_STATUS_NONE,
+ CONTENT_STATUS_DISPLAYED,
+ CONTENT_STATUS_RAN,
+ CONTENT_STATUS_DISPLAYED_AND_RAN,
};
// Describes the security status of a page or request. This is the
@@ -88,25 +100,39 @@ class SecurityStateModel {
SecurityInfo();
~SecurityInfo();
SecurityLevel security_level;
+ // True if the page fails the browser's malware or phishing checks.
+ bool fails_malware_check;
SHA1DeprecationStatus sha1_deprecation_status;
- MixedContentStatus mixed_content_status;
+ // |mixed_content_status| describes the presence of content that was
+ // loaded over a nonsecure (HTTP) connection.
+ ContentStatus mixed_content_status;
+ // |content_with_cert_errors_status| describes the presence of
+ // content that was loaded over an HTTPS connection with
+ // certificate errors.
+ ContentStatus content_with_cert_errors_status;
// The verification statuses of the signed certificate timestamps
// for the connection.
std::vector<net::ct::SCTVerifyStatus> sct_verify_statuses;
bool scheme_is_cryptographic;
net::CertStatus cert_status;
- int cert_id;
+ scoped_refptr<net::X509Certificate> certificate;
// The security strength, in bits, of the SSL cipher suite. In late
// 2015, 128 is considered the minimum.
- // 0 means the connection is not encrypted.
- // -1 means the security strength is unknown.
+ //
+ // 0 means the connection uses HTTPS but is not encrypted. -1 means
+ // the security strength is unknown or the connection does not use
+ // HTTPS.
int security_bits;
// Information about the SSL connection, such as protocol and
// ciphersuite. See ssl_connection_flags.h in net.
int connection_status;
- // True if the protocol version and ciphersuite for the connection
- // are considered secure.
- bool is_secure_protocol_and_ciphersuite;
+ // The ID of the (EC)DH group used by the key exchange. The value is zero if
+ // unknown (older cache entries may not store the value) or not applicable.
+ uint16_t key_exchange_group;
+ // A mask that indicates which of the protocol version,
+ // key exchange, or cipher for the connection is considered
+ // obsolete. See net::ObsoleteSSLMask for specific mask values.
+ int obsolete_ssl_status;
// True if pinning was bypassed due to a local trust anchor.
bool pkp_bypassed;
@@ -119,16 +145,24 @@ class SecurityStateModel {
VisibleSecurityState();
~VisibleSecurityState();
bool operator==(const VisibleSecurityState& other) const;
- bool initialized;
GURL url;
// The baseline SecurityLevel describing the page or request before
// any SecurityStateModel policies have been applied.
SecurityLevel initial_security_level;
+ // True if the page fails the browser's malware or phishing checks.
+ bool fails_malware_check;
+
+ // CONNECTION SECURITY FIELDS
+ // Whether the connection security fields are initialized.
+ bool connection_info_initialized;
// The following fields contain information about the connection
// used to load the page or request.
- int cert_id;
+ scoped_refptr<net::X509Certificate> certificate;
net::CertStatus cert_status;
int connection_status;
+ // The ID of the (EC)DH group used by the key exchange. The value is zero if
+ // unknown (older cache entries may not store the value) or not applicable.
+ uint16_t key_exchange_group;
int security_bits;
// The verification statuses of the Signed Certificate
// Timestamps (if any) that the server provided.
@@ -137,8 +171,16 @@ class SecurityStateModel {
bool displayed_mixed_content;
// True if the page ran active mixed content.
bool ran_mixed_content;
+ // True if the page displayed passive subresources with certificate errors.
+ bool displayed_content_with_cert_errors;
+ // True if the page ran active subresources with certificate errors.
+ bool ran_content_with_cert_errors;
// True if PKP was bypassed due to a local trust anchor.
bool pkp_bypassed;
+ // True if the page was an HTTP page that displayed a password field.
+ bool displayed_password_field_on_http;
+ // True if the page was an HTTP page that displayed a credit card field.
+ bool displayed_credit_card_field_on_http;
};
// These security levels describe the treatment given to pages that
@@ -150,20 +192,12 @@ class SecurityStateModel {
SecurityStateModel();
virtual ~SecurityStateModel();
- // Returns a SecurityInfo describing the current page. Results are
- // cached so that computation is only done when the relevant security
- // state has changed.
- const SecurityInfo& GetSecurityInfo() const;
+ // Populates |result| to describe the current page.
+ void GetSecurityInfo(SecurityInfo* result) const;
void SetClient(SecurityStateModelClient* client);
private:
- // Caches the SecurityInfo for the visible page. Marked
- // mutable so that the const accessor GetSecurityInfo() can update the
- // cached values.
- mutable SecurityInfo security_info_;
- mutable VisibleSecurityState visible_security_state_;
-
SecurityStateModelClient* client_;
DISALLOW_COPY_AND_ASSIGN(SecurityStateModel);
diff --git a/chromium/components/security_state/security_state_model_unittest.cc b/chromium/components/security_state/security_state_model_unittest.cc
index 1a21b858502..c2943524c90 100644
--- a/chromium/components/security_state/security_state_model_unittest.cc
+++ b/chromium/components/security_state/security_state_model_unittest.cc
@@ -6,8 +6,11 @@
#include <stdint.h>
+#include "base/command_line.h"
#include "components/security_state/security_state_model_client.h"
+#include "components/security_state/switches.h"
#include "net/cert/x509_certificate.h"
+#include "net/ssl/ssl_cipher_suite_names.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_certificate_data.h"
@@ -18,17 +21,22 @@ namespace security_state {
namespace {
-const char kUrl[] = "https://foo.test";
+const char kHttpsUrl[] = "https://foo.test";
+const char kHttpUrl[] = "http://foo.test";
class TestSecurityStateModelClient : public SecurityStateModelClient {
public:
TestSecurityStateModelClient()
- : initial_security_level_(SecurityStateModel::SECURE),
+ : url_(kHttpsUrl),
+ initial_security_level_(SecurityStateModel::SECURE),
connection_status_(net::SSL_CONNECTION_VERSION_TLS1_2
<< net::SSL_CONNECTION_VERSION_SHIFT),
cert_status_(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT),
displayed_mixed_content_(false),
- ran_mixed_content_(false) {
+ ran_mixed_content_(false),
+ fails_malware_check_(false),
+ displayed_password_field_on_http_(false),
+ displayed_credit_card_field_on_http_(false) {
cert_ =
net::ImportCertFromFile(net::GetTestCertsDirectory(), "sha1_2016.pem");
}
@@ -49,23 +57,39 @@ class TestSecurityStateModelClient : public SecurityStateModelClient {
void SetRanMixedContent(bool ran_mixed_content) {
ran_mixed_content_ = ran_mixed_content;
}
+ void set_fails_malware_check(bool fails_malware_check) {
+ fails_malware_check_ = fails_malware_check;
+ }
void set_initial_security_level(
SecurityStateModel::SecurityLevel security_level) {
initial_security_level_ = security_level;
}
+ void set_displayed_password_field_on_http(
+ bool displayed_password_field_on_http) {
+ displayed_password_field_on_http_ = displayed_password_field_on_http;
+ }
+ void set_displayed_credit_card_field_on_http(
+ bool displayed_credit_card_field_on_http) {
+ displayed_credit_card_field_on_http_ = displayed_credit_card_field_on_http;
+ }
+
+ void UseHttpUrl() { url_ = GURL(kHttpUrl); }
// SecurityStateModelClient:
void GetVisibleSecurityState(
SecurityStateModel::VisibleSecurityState* state) override {
- state->initialized = true;
- state->url = GURL(kUrl);
+ state->connection_info_initialized = true;
+ state->url = url_;
state->initial_security_level = initial_security_level_;
- state->cert_id = 1;
state->cert_status = cert_status_;
state->connection_status = connection_status_;
state->security_bits = 256;
state->displayed_mixed_content = displayed_mixed_content_;
state->ran_mixed_content = ran_mixed_content_;
+ state->fails_malware_check = fails_malware_check_;
+ state->displayed_password_field_on_http = displayed_password_field_on_http_;
+ state->displayed_credit_card_field_on_http =
+ displayed_credit_card_field_on_http_;
}
bool RetrieveCert(scoped_refptr<net::X509Certificate>* cert) override {
@@ -75,17 +99,21 @@ class TestSecurityStateModelClient : public SecurityStateModelClient {
bool UsedPolicyInstalledCertificate() override { return false; }
- // Always returns true because all unit tests in this file test
- // scenarios in which the origin is secure.
- bool IsOriginSecure(const GURL& url) override { return true; }
+ bool IsOriginSecure(const GURL& url) override {
+ return url_ == GURL(kHttpsUrl);
+ }
private:
+ GURL url_;
SecurityStateModel::SecurityLevel initial_security_level_;
scoped_refptr<net::X509Certificate> cert_;
int connection_status_;
net::CertStatus cert_status_;
bool displayed_mixed_content_;
bool ran_mixed_content_;
+ bool fails_malware_check_;
+ bool displayed_password_field_on_http_;
+ bool displayed_credit_card_field_on_http_;
};
// Tests that SHA1-signed certificates expiring in 2016 downgrade the
@@ -94,8 +122,8 @@ TEST(SecurityStateModelTest, SHA1Warning) {
TestSecurityStateModelClient client;
SecurityStateModel model;
model.SetClient(&client);
- const SecurityStateModel::SecurityInfo& security_info =
- model.GetSecurityInfo();
+ SecurityStateModel::SecurityInfo security_info;
+ model.GetSecurityInfo(&security_info);
EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR,
security_info.sha1_deprecation_status);
EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level);
@@ -108,24 +136,24 @@ TEST(SecurityStateModelTest, SHA1WarningMixedContent) {
SecurityStateModel model;
model.SetClient(&client);
client.SetDisplayedMixedContent(true);
- const SecurityStateModel::SecurityInfo& security_info1 =
- model.GetSecurityInfo();
+ SecurityStateModel::SecurityInfo security_info1;
+ model.GetSecurityInfo(&security_info1);
EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR,
security_info1.sha1_deprecation_status);
- EXPECT_EQ(SecurityStateModel::DISPLAYED_MIXED_CONTENT,
+ EXPECT_EQ(SecurityStateModel::CONTENT_STATUS_DISPLAYED,
security_info1.mixed_content_status);
EXPECT_EQ(SecurityStateModel::NONE, security_info1.security_level);
- client.set_initial_security_level(SecurityStateModel::SECURITY_ERROR);
+ client.set_initial_security_level(SecurityStateModel::DANGEROUS);
client.SetDisplayedMixedContent(false);
client.SetRanMixedContent(true);
- const SecurityStateModel::SecurityInfo& security_info2 =
- model.GetSecurityInfo();
+ SecurityStateModel::SecurityInfo security_info2;
+ model.GetSecurityInfo(&security_info2);
EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR,
security_info2.sha1_deprecation_status);
- EXPECT_EQ(SecurityStateModel::RAN_MIXED_CONTENT,
+ EXPECT_EQ(SecurityStateModel::CONTENT_STATUS_RAN,
security_info2.mixed_content_status);
- EXPECT_EQ(SecurityStateModel::SECURITY_ERROR, security_info2.security_level);
+ EXPECT_EQ(SecurityStateModel::DANGEROUS, security_info2.security_level);
}
// Tests that SHA1 warnings don't interfere with the handling of major
@@ -134,13 +162,13 @@ TEST(SecurityStateModelTest, SHA1WarningBrokenHTTPS) {
TestSecurityStateModelClient client;
SecurityStateModel model;
model.SetClient(&client);
- client.set_initial_security_level(SecurityStateModel::SECURITY_ERROR);
+ client.set_initial_security_level(SecurityStateModel::DANGEROUS);
client.AddCertStatus(net::CERT_STATUS_DATE_INVALID);
- const SecurityStateModel::SecurityInfo& security_info =
- model.GetSecurityInfo();
+ SecurityStateModel::SecurityInfo security_info;
+ model.GetSecurityInfo(&security_info);
EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR,
security_info.sha1_deprecation_status);
- EXPECT_EQ(SecurityStateModel::SECURITY_ERROR, security_info.security_level);
+ EXPECT_EQ(SecurityStateModel::DANGEROUS, security_info.security_level);
}
// Tests that |security_info.is_secure_protocol_and_ciphersuite| is
@@ -155,9 +183,9 @@ TEST(SecurityStateModelTest, SecureProtocolAndCiphersuite) {
client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_2
<< net::SSL_CONNECTION_VERSION_SHIFT);
client.SetCipherSuite(ciphersuite);
- const SecurityStateModel::SecurityInfo& security_info =
- model.GetSecurityInfo();
- EXPECT_TRUE(security_info.is_secure_protocol_and_ciphersuite);
+ SecurityStateModel::SecurityInfo security_info;
+ model.GetSecurityInfo(&security_info);
+ EXPECT_EQ(net::OBSOLETE_SSL_NONE, security_info.obsolete_ssl_status);
}
TEST(SecurityStateModelTest, NonsecureProtocol) {
@@ -170,9 +198,9 @@ TEST(SecurityStateModelTest, NonsecureProtocol) {
client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_1
<< net::SSL_CONNECTION_VERSION_SHIFT);
client.SetCipherSuite(ciphersuite);
- const SecurityStateModel::SecurityInfo& security_info =
- model.GetSecurityInfo();
- EXPECT_FALSE(security_info.is_secure_protocol_and_ciphersuite);
+ SecurityStateModel::SecurityInfo security_info;
+ model.GetSecurityInfo(&security_info);
+ EXPECT_EQ(net::OBSOLETE_SSL_MASK_PROTOCOL, security_info.obsolete_ssl_status);
}
TEST(SecurityStateModelTest, NonsecureCiphersuite) {
@@ -185,9 +213,93 @@ TEST(SecurityStateModelTest, NonsecureCiphersuite) {
client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_2
<< net::SSL_CONNECTION_VERSION_SHIFT);
client.SetCipherSuite(ciphersuite);
- const SecurityStateModel::SecurityInfo& security_info =
- model.GetSecurityInfo();
- EXPECT_FALSE(security_info.is_secure_protocol_and_ciphersuite);
+ SecurityStateModel::SecurityInfo security_info;
+ model.GetSecurityInfo(&security_info);
+ EXPECT_EQ(net::OBSOLETE_SSL_MASK_KEY_EXCHANGE | net::OBSOLETE_SSL_MASK_CIPHER,
+ security_info.obsolete_ssl_status);
+}
+
+// Tests that the malware/phishing status is set, and it overrides valid HTTPS.
+TEST(SecurityStateModelTest, MalwareOverride) {
+ TestSecurityStateModelClient client;
+ SecurityStateModel model;
+ model.SetClient(&client);
+ // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 from
+ // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-4
+ const uint16_t ciphersuite = 0xc02f;
+ client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_2
+ << net::SSL_CONNECTION_VERSION_SHIFT);
+ client.SetCipherSuite(ciphersuite);
+ client.set_fails_malware_check(true);
+ SecurityStateModel::SecurityInfo security_info;
+ model.GetSecurityInfo(&security_info);
+ EXPECT_TRUE(security_info.fails_malware_check);
+ EXPECT_EQ(SecurityStateModel::DANGEROUS, security_info.security_level);
+}
+
+// Tests that the malware/phishing status is set, even if other connection info
+// is not available.
+TEST(SecurityStateModelTest, MalwareWithoutCOnnectionState) {
+ TestSecurityStateModelClient client;
+ SecurityStateModel model;
+ model.SetClient(&client);
+ client.set_fails_malware_check(true);
+ SecurityStateModel::SecurityInfo security_info;
+ model.GetSecurityInfo(&security_info);
+ EXPECT_TRUE(security_info.fails_malware_check);
+ EXPECT_EQ(SecurityStateModel::DANGEROUS, security_info.security_level);
+}
+
+// Tests that password fields cause the security level to be downgraded
+// to HTTP_SHOW_WARNING when the command-line switch is set.
+TEST(SecurityStateModelTest, PasswordFieldWarning) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kMarkHttpAs,
+ switches::kMarkHttpWithPasswordsOrCcWithChip);
+ TestSecurityStateModelClient client;
+ client.UseHttpUrl();
+ client.set_initial_security_level(SecurityStateModel::NONE);
+ SecurityStateModel model;
+ model.SetClient(&client);
+ client.set_displayed_password_field_on_http(true);
+ SecurityStateModel::SecurityInfo security_info;
+ model.GetSecurityInfo(&security_info);
+ EXPECT_EQ(SecurityStateModel::HTTP_SHOW_WARNING,
+ security_info.security_level);
+}
+
+// Tests that credit card fields cause the security level to be downgraded
+// to HTTP_SHOW_WARNING when the command-line switch is set.
+TEST(SecurityStateModelTest, CreditCardFieldWarning) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kMarkHttpAs,
+ switches::kMarkHttpWithPasswordsOrCcWithChip);
+ TestSecurityStateModelClient client;
+ client.UseHttpUrl();
+ client.set_initial_security_level(SecurityStateModel::NONE);
+ SecurityStateModel model;
+ model.SetClient(&client);
+ client.set_displayed_credit_card_field_on_http(true);
+ SecurityStateModel::SecurityInfo security_info;
+ model.GetSecurityInfo(&security_info);
+ EXPECT_EQ(SecurityStateModel::HTTP_SHOW_WARNING,
+ security_info.security_level);
+}
+
+// Tests that neither password nor credit fields cause the security
+// level to be downgraded to HTTP_SHOW_WARNING when the command-line switch
+// is NOT set.
+TEST(SecurityStateModelTest, HttpWarningNotSetWithoutSwitch) {
+ TestSecurityStateModelClient client;
+ client.UseHttpUrl();
+ client.set_initial_security_level(SecurityStateModel::NONE);
+ SecurityStateModel model;
+ model.SetClient(&client);
+ client.set_displayed_password_field_on_http(true);
+ client.set_displayed_credit_card_field_on_http(true);
+ SecurityStateModel::SecurityInfo security_info;
+ model.GetSecurityInfo(&security_info);
+ EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level);
}
} // namespace
diff --git a/chromium/components/security_state/switches.cc b/chromium/components/security_state/switches.cc
index 13cbe1a3c90..1852f5bd99a 100644
--- a/chromium/components/security_state/switches.cc
+++ b/chromium/components/security_state/switches.cc
@@ -8,9 +8,10 @@ namespace security_state {
namespace switches {
// Use to opt-in to marking HTTP as non-secure.
-const char kMarkNonSecureAs[] = "mark-non-secure-as";
-const char kMarkNonSecureAsNeutral[] = "neutral";
-const char kMarkNonSecureAsNonSecure[] = "non-secure";
+const char kMarkHttpAs[] = "mark-non-secure-as";
+const char kMarkHttpAsNeutral[] = "neutral";
+const char kMarkHttpAsDangerous[] = "non-secure";
+const char kMarkHttpWithPasswordsOrCcWithChip[] = "non-secure-passwords-cc";
} // namespace switches
} // namespace security_state
diff --git a/chromium/components/security_state/switches.h b/chromium/components/security_state/switches.h
index b4ed6bfba14..e138669f633 100644
--- a/chromium/components/security_state/switches.h
+++ b/chromium/components/security_state/switches.h
@@ -8,9 +8,10 @@
namespace security_state {
namespace switches {
-extern const char kMarkNonSecureAs[];
-extern const char kMarkNonSecureAsNeutral[];
-extern const char kMarkNonSecureAsNonSecure[];
+extern const char kMarkHttpAs[];
+extern const char kMarkHttpAsNeutral[];
+extern const char kMarkHttpAsDangerous[];
+extern const char kMarkHttpWithPasswordsOrCcWithChip[];
}
} // namespace security_state
diff --git a/chromium/components/service_tab_launcher.gypi b/chromium/components/service_tab_launcher.gypi
deleted file mode 100644
index a6abf8aab7c..00000000000
--- a/chromium/components/service_tab_launcher.gypi
+++ /dev/null
@@ -1,52 +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.
-
-{
- 'targets': [
- {
- # GN: //components/serivce_tab_launcher:service_tab_launcher
- 'target_name': 'service_tab_launcher',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- 'service_tab_launcher_jni_headers',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'service_tab_launcher/browser/android/service_tab_launcher.cc',
- 'service_tab_launcher/browser/android/service_tab_launcher.h',
- 'service_tab_launcher/component_jni_registrar.cc',
- 'service_tab_launcher/component_jni_registrar.h',
- ],
- },
- {
- # GN: //components/serivce_tab_launcher:service_tab_launcher_java
- 'target_name': 'service_tab_launcher_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_java',
- ],
- 'variables': {
- 'java_in_dir': 'service_tab_launcher/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN: //components/serivce_tab_launcher:service_tab_launcher_jni_headers
- 'target_name': 'service_tab_launcher_jni_headers',
- 'type': 'none',
- 'sources': [
- 'service_tab_launcher/android/java/src/org/chromium/components/service_tab_launcher/ServiceTabLauncher.java',
- ],
- 'variables': {
- 'jni_gen_package': 'service_tab_launcher',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- ],
-}
diff --git a/chromium/components/service_tab_launcher/BUILD.gn b/chromium/components/service_tab_launcher/BUILD.gn
deleted file mode 100644
index afc17e1de4b..00000000000
--- a/chromium/components/service_tab_launcher/BUILD.gn
+++ /dev/null
@@ -1,38 +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.
-
-import("//build/config/android/rules.gni")
-
-# GYP: //components/service_tab_launcher:service_tab_launcher
-static_library("service_tab_launcher") {
- sources = [
- "browser/android/service_tab_launcher.cc",
- "browser/android/service_tab_launcher.h",
- "component_jni_registrar.cc",
- "component_jni_registrar.h",
- ]
-
- deps = [
- ":service_tab_launcher_jni_headers",
- "//base",
- "//content/public/browser",
- ]
-}
-
-# GYP: //components/service_tab_launcher:service_tab_launcher_java
-android_library("service_tab_launcher_java") {
- deps = [
- "//base:base_java",
- "//content/public/android:content_java",
- ]
- java_files = [ "android/java/src/org/chromium/components/service_tab_launcher/ServiceTabLauncher.java" ]
-}
-
-# GYP: //components/service_tab_launcher:service_tab_launcher_jni_headers
-generate_jni("service_tab_launcher_jni_headers") {
- sources = [
- "android/java/src/org/chromium/components/service_tab_launcher/ServiceTabLauncher.java",
- ]
- jni_package = "service_tab_launcher"
-}
diff --git a/chromium/components/service_tab_launcher/DEPS b/chromium/components/service_tab_launcher/DEPS
deleted file mode 100644
index 49a36451963..00000000000
--- a/chromium/components/service_tab_launcher/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+content/public/browser",
- "+jni",
-]
diff --git a/chromium/components/service_tab_launcher/OWNERS b/chromium/components/service_tab_launcher/OWNERS
deleted file mode 100644
index dca8ea9a66b..00000000000
--- a/chromium/components/service_tab_launcher/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-tedchoc@chromium.org
-miguelg@chromium.org
-peter@chromium.org
diff --git a/chromium/components/service_tab_launcher/android/DEPS b/chromium/components/service_tab_launcher/android/DEPS
deleted file mode 100644
index 0d019e19974..00000000000
--- a/chromium/components/service_tab_launcher/android/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+content/public/android/java",
-]
diff --git a/chromium/components/service_tab_launcher/browser/android/service_tab_launcher.cc b/chromium/components/service_tab_launcher/browser/android/service_tab_launcher.cc
deleted file mode 100644
index f4691815f69..00000000000
--- a/chromium/components/service_tab_launcher/browser/android/service_tab_launcher.cc
+++ /dev/null
@@ -1,105 +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 "components/service_tab_launcher/browser/android/service_tab_launcher.h"
-
-#include "base/android/context_utils.h"
-#include "base/android/jni_string.h"
-#include "base/callback.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/page_navigator.h"
-#include "content/public/browser/web_contents.h"
-#include "jni/ServiceTabLauncher_jni.h"
-
-using base::android::AttachCurrentThread;
-using base::android::ConvertUTF8ToJavaString;
-using base::android::GetApplicationContext;
-
-// Called by Java when the WebContents instance for a request Id is available.
-void OnWebContentsForRequestAvailable(
- JNIEnv* env,
- const JavaParamRef<jclass>& clazz,
- jint request_id,
- const JavaParamRef<jobject>& android_web_contents) {
- service_tab_launcher::ServiceTabLauncher::GetInstance()->OnTabLaunched(
- request_id,
- content::WebContents::FromJavaWebContents(android_web_contents));
-}
-
-namespace service_tab_launcher {
-
-// static
-ServiceTabLauncher* ServiceTabLauncher::GetInstance() {
- return base::Singleton<ServiceTabLauncher>::get();
-}
-
-ServiceTabLauncher::ServiceTabLauncher() {
- java_object_.Reset(
- Java_ServiceTabLauncher_getInstance(AttachCurrentThread(),
- GetApplicationContext()));
-}
-
-ServiceTabLauncher::~ServiceTabLauncher() {}
-
-void ServiceTabLauncher::LaunchTab(
- content::BrowserContext* browser_context,
- const content::OpenURLParams& params,
- const TabLaunchedCallback& callback) {
- if (!java_object_.obj()) {
- LOG(ERROR) << "No ServiceTabLauncher is available to launch a new tab.";
- callback.Run(nullptr);
- return;
- }
-
- WindowOpenDisposition disposition = params.disposition;
- if (disposition != NEW_WINDOW && disposition != NEW_POPUP &&
- disposition != NEW_FOREGROUND_TAB && disposition != NEW_BACKGROUND_TAB) {
- // ServiceTabLauncher can currently only launch new tabs.
- NOTIMPLEMENTED();
- return;
- }
-
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> url = ConvertUTF8ToJavaString(
- env, params.url.spec());
- ScopedJavaLocalRef<jstring> referrer_url =
- ConvertUTF8ToJavaString(env, params.referrer.url.spec());
- ScopedJavaLocalRef<jstring> headers = ConvertUTF8ToJavaString(
- env, params.extra_headers);
-
- ScopedJavaLocalRef<jobject> post_data;
-
- int request_id = tab_launched_callbacks_.Add(
- new TabLaunchedCallback(callback));
- DCHECK_GE(request_id, 1);
-
- Java_ServiceTabLauncher_launchTab(env,
- java_object_.obj(),
- GetApplicationContext(),
- request_id,
- browser_context->IsOffTheRecord(),
- url.obj(),
- disposition,
- referrer_url.obj(),
- params.referrer.policy,
- headers.obj(),
- post_data.obj());
-}
-
-void ServiceTabLauncher::OnTabLaunched(int request_id,
- content::WebContents* web_contents) {
- TabLaunchedCallback* callback = tab_launched_callbacks_.Lookup(request_id);
- DCHECK(callback);
-
- if (callback)
- callback->Run(web_contents);
-
- tab_launched_callbacks_.Remove(request_id);
-}
-
-bool ServiceTabLauncher::RegisterServiceTabLauncher(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-} // namespace service_tab_launcher
diff --git a/chromium/components/service_tab_launcher/browser/android/service_tab_launcher.h b/chromium/components/service_tab_launcher/browser/android/service_tab_launcher.h
deleted file mode 100644
index 004e78bf6d3..00000000000
--- a/chromium/components/service_tab_launcher/browser/android/service_tab_launcher.h
+++ /dev/null
@@ -1,62 +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 COMPONENTS_SERVICE_TAB_LAUNCHER_BROWSER_ANDROID_SERVICE_TAB_LAUNCHER_H_
-#define COMPONENTS_SERVICE_TAB_LAUNCHER_BROWSER_ANDROID_SERVICE_TAB_LAUNCHER_H_
-
-#include "base/android/jni_android.h"
-#include "base/callback_forward.h"
-#include "base/id_map.h"
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-
-namespace content {
-class BrowserContext;
-struct OpenURLParams;
-class WebContents;
-}
-
-namespace service_tab_launcher {
-
-// Launcher for creating new tabs on Android from a background service, where
-// there may not necessarily be an Activity or a tab model at all. When the
-// tab has been launched, the user of this class will be informed with the
-// content::WebContents instance associated with the tab.
-class ServiceTabLauncher {
- using TabLaunchedCallback = base::Callback<void(content::WebContents*)>;
-
- public:
- // Returns the singleton instance of the service tab launcher.
- static ServiceTabLauncher* GetInstance();
-
- // Launches a new tab when we're in a Service rather than in an Activity.
- // |callback| will be invoked with the resulting content::WebContents* when
- // the tab is avialable. This method must only be called from the UI thread.
- void LaunchTab(content::BrowserContext* browser_context,
- const content::OpenURLParams& params,
- const TabLaunchedCallback& callback);
-
- // To be called when the tab for |request_id| has launched, with the
- // associated |web_contents|. The WebContents must not yet have started
- // the provisional load for the main frame of the navigation.
- void OnTabLaunched(int request_id, content::WebContents* web_contents);
-
- static bool RegisterServiceTabLauncher(JNIEnv* env);
-
- private:
- friend struct base::DefaultSingletonTraits<ServiceTabLauncher>;
-
- ServiceTabLauncher();
- ~ServiceTabLauncher();
-
- IDMap<TabLaunchedCallback, IDMapOwnPointer> tab_launched_callbacks_;
-
- base::android::ScopedJavaGlobalRef<jobject> java_object_;
-
- DISALLOW_COPY_AND_ASSIGN(ServiceTabLauncher);
-};
-
-} // namespace service_tab_launcher
-
-#endif // COMPONENTS_SERVICE_TAB_LAUNCHER_BROWSER_ANDROID_SERVICE_TAB_LAUNCHER_H_
diff --git a/chromium/components/session_manager.gypi b/chromium/components/session_manager.gypi
deleted file mode 100644
index e87d3e01c08..00000000000
--- a/chromium/components/session_manager.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'targets': [
- {
- # GN: //components/session_manager/core
- 'target_name': 'session_manager_component',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'SESSION_IMPLEMENTATION',
- ],
- 'sources': [
- 'session_manager/core/session_manager.cc',
- 'session_manager/core/session_manager.h',
- 'session_manager/session_manager_export.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/session_manager/OWNERS b/chromium/components/session_manager/OWNERS
index 2af5394fe72..e7a8a061b62 100644
--- a/chromium/components/session_manager/OWNERS
+++ b/chromium/components/session_manager/OWNERS
@@ -1,3 +1,2 @@
achuith@chromium.org
alemate@chromium.org
-dzhioev@chromium.org
diff --git a/chromium/components/sessions.gypi b/chromium/components/sessions.gypi
deleted file mode 100644
index 24599fb7c9c..00000000000
--- a/chromium/components/sessions.gypi
+++ /dev/null
@@ -1,165 +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.
-
-{
- 'variables': {
- # Core sources shared by sessions_content and sessions_ios. These can't
- # be a separate shared library since one symbol is implemented higher up in
- # the sessions_content/ios layer.
- 'sessions_core_sources': [
- 'sessions/core/base_session_service.cc',
- 'sessions/core/base_session_service.h',
- 'sessions/core/base_session_service_commands.cc',
- 'sessions/core/base_session_service_commands.h',
- 'sessions/core/base_session_service_delegate.h',
- 'sessions/core/live_tab.cc',
- 'sessions/core/live_tab.h',
- 'sessions/core/live_tab_context.h',
- 'sessions/core/persistent_tab_restore_service.cc',
- 'sessions/core/persistent_tab_restore_service.h',
- 'sessions/core/serialized_navigation_driver.h',
- 'sessions/core/serialized_navigation_entry.cc',
- 'sessions/core/serialized_navigation_entry.h',
- 'sessions/core/session_backend.cc',
- 'sessions/core/session_backend.h',
- 'sessions/core/session_command.cc',
- 'sessions/core/session_command.h',
- 'sessions/core/session_constants.cc',
- 'sessions/core/session_constants.h',
- 'sessions/core/session_id.cc',
- 'sessions/core/session_id.h',
- 'sessions/core/session_service_commands.cc',
- 'sessions/core/session_service_commands.h',
- 'sessions/core/session_types.cc',
- 'sessions/core/session_types.h',
- 'sessions/core/tab_restore_service.cc',
- 'sessions/core/tab_restore_service.h',
- 'sessions/core/tab_restore_service_client.cc',
- 'sessions/core/tab_restore_service_client.h',
- 'sessions/core/tab_restore_service_helper.cc',
- 'sessions/core/tab_restore_service_helper.h',
- 'sessions/core/tab_restore_service_observer.h',
- ],
- },
- 'targets': [
- {
- # GN version: //components/sessions:test_support
- 'target_name': 'sessions_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../skia/skia.gyp:skia',
- '../sync/sync.gyp:sync',
- '../testing/gtest.gyp:gtest',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'sessions/core/serialized_navigation_entry_test_helper.cc',
- 'sessions/core/serialized_navigation_entry_test_helper.h',
- ],
- 'conditions': [
- ['OS!="ios" and OS!="android"', {
- 'sources': [
- 'sessions/core/base_session_service_test_helper.cc',
- 'sessions/core/base_session_service_test_helper.h',
- ],
- }],
- ],
- },
- ],
-
- # Platform-specific targets.
- 'conditions': [
- ['OS!="ios"', {
- 'targets': [
- {
- # GN version: //components/sessions
- 'target_name': 'sessions_content',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../content/content.gyp:content_browser',
- '../skia/skia.gyp:skia',
- '../sync/sync.gyp:sync',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx_geometry',
- '../url/url.gyp:url_lib',
- 'keyed_service_core',
- 'variations',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'SESSIONS_IMPLEMENTATION',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- '<@(sessions_core_sources)',
-
- 'sessions/content/content_live_tab.cc',
- 'sessions/content/content_live_tab.h',
- 'sessions/content/content_platform_specific_tab_data.cc',
- 'sessions/content/content_platform_specific_tab_data.h',
- 'sessions/content/content_serialized_navigation_builder.cc',
- 'sessions/content/content_serialized_navigation_builder.h',
- 'sessions/content/content_serialized_navigation_driver.cc',
- 'sessions/content/content_serialized_navigation_driver.h',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'sources': [
- 'sessions/core/in_memory_tab_restore_service.cc',
- 'sessions/core/in_memory_tab_restore_service.h',
- ],
- 'sources!': [
- 'sessions/core/persistent_tab_restore_service.cc',
- ],
- },
- ],
- ],
- }],
- }, { # OS==ios
- 'targets': [
- {
- # GN version: //components/sessions
- 'target_name': 'sessions_ios',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../ios/web/ios_web.gyp:ios_web',
- '../sync/sync.gyp:sync',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx_geometry',
- '../url/url.gyp:url_lib',
- 'keyed_service_core',
- 'variations',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'SESSIONS_IMPLEMENTATION',
- ],
- 'sources': [
- '<@(sessions_core_sources)',
-
- 'sessions/ios/ios_live_tab.h',
- 'sessions/ios/ios_live_tab.mm',
- 'sessions/ios/ios_serialized_navigation_builder.h',
- 'sessions/ios/ios_serialized_navigation_builder.mm',
- 'sessions/ios/ios_serialized_navigation_driver.cc',
- 'sessions/ios/ios_serialized_navigation_driver.h',
- ],
- },
- ],
- }],
- ],
-
-}
diff --git a/chromium/components/sessions/BUILD.gn b/chromium/components/sessions/BUILD.gn
index a85234730e5..fc20eacf6da 100644
--- a/chromium/components/sessions/BUILD.gn
+++ b/chromium/components/sessions/BUILD.gn
@@ -11,17 +11,19 @@ config("implementation") {
}
if (!is_ios) {
- # GYP version: components/sessions.gypi:sessions_content
component("sessions") {
sources = [
"content/content_live_tab.cc",
"content/content_live_tab.h",
"content/content_platform_specific_tab_data.cc",
"content/content_platform_specific_tab_data.h",
+ "content/content_record_password_state.cc",
+ "content/content_record_password_state.h",
"content/content_serialized_navigation_builder.cc",
"content/content_serialized_navigation_builder.h",
"content/content_serialized_navigation_driver.cc",
"content/content_serialized_navigation_driver.h",
+ "content/extended_info_handler.h",
]
configs += [ ":implementation" ]
@@ -114,22 +116,22 @@ source_set("shared") {
public_deps = [
"//components/keyed_service/core",
- "//sync/protocol",
+ "//components/sync/protocol",
]
deps = [
"//base",
"//components/keyed_service/core",
+ "//components/sync",
"//components/variations",
"//skia",
- "//sync",
"//ui/base",
"//ui/gfx",
"//url",
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"core/serialized_navigation_entry_test_helper.cc",
@@ -141,8 +143,8 @@ source_set("test_support") {
]
deps = [
"//base",
+ "//components/sync",
"//skia",
- "//sync",
"//testing/gtest",
"//ui/base", # For page_transition_types.h.
"//url",
@@ -180,7 +182,7 @@ source_set("unit_tests") {
deps = [
":test_support",
"//base/test:test_support",
- "//sync",
+ "//components/sync",
"//testing/gtest",
"//ui/base", # For page transition types.
"//url",
diff --git a/chromium/components/sessions/DEPS b/chromium/components/sessions/DEPS
index 5ae3e85dc6b..a704684cce3 100644
--- a/chromium/components/sessions/DEPS
+++ b/chromium/components/sessions/DEPS
@@ -1,6 +1,6 @@
include_rules = [
- "+sync",
+ "+components/sync",
+ "+components/variations",
"+ui/base",
"+ui/gfx",
- "+components/variations",
]
diff --git a/chromium/components/sessions/OWNERS b/chromium/components/sessions/OWNERS
index 367baa763d5..28a63b1ec6d 100644
--- a/chromium/components/sessions/OWNERS
+++ b/chromium/components/sessions/OWNERS
@@ -1,4 +1,3 @@
-marja@chromium.org
sky@chromium.org
skuhne@chromium.org
diff --git a/chromium/components/sessions/content/content_live_tab.cc b/chromium/components/sessions/content/content_live_tab.cc
index f8a7940432f..7b1dff013ee 100644
--- a/chromium/components/sessions/content/content_live_tab.cc
+++ b/chromium/components/sessions/content/content_live_tab.cc
@@ -58,8 +58,8 @@ int ContentLiveTab::GetEntryCount() {
std::unique_ptr<sessions::PlatformSpecificTabData>
ContentLiveTab::GetPlatformSpecificTabData() {
- return base::WrapUnique(
- new sessions::ContentPlatformSpecificTabData(web_contents()));
+ return base::MakeUnique<sessions::ContentPlatformSpecificTabData>(
+ web_contents());
}
void ContentLiveTab::LoadIfNecessary() {
diff --git a/chromium/components/sessions/content/content_platform_specific_tab_data.cc b/chromium/components/sessions/content/content_platform_specific_tab_data.cc
index 755f5cf56ad..bca42b8dea8 100644
--- a/chromium/components/sessions/content/content_platform_specific_tab_data.cc
+++ b/chromium/components/sessions/content/content_platform_specific_tab_data.cc
@@ -21,11 +21,4 @@ ContentPlatformSpecificTabData::ContentPlatformSpecificTabData() {}
ContentPlatformSpecificTabData::~ContentPlatformSpecificTabData() {}
-std::unique_ptr<PlatformSpecificTabData>
-ContentPlatformSpecificTabData::Clone() {
- ContentPlatformSpecificTabData* clone = new ContentPlatformSpecificTabData();
- clone->session_storage_namespace_ = session_storage_namespace_;
- return base::WrapUnique(clone);
-}
-
} // namespace sessions
diff --git a/chromium/components/sessions/content/content_platform_specific_tab_data.h b/chromium/components/sessions/content/content_platform_specific_tab_data.h
index 1ccc6dd7c64..711a444a221 100644
--- a/chromium/components/sessions/content/content_platform_specific_tab_data.h
+++ b/chromium/components/sessions/content/content_platform_specific_tab_data.h
@@ -32,9 +32,6 @@ class SESSIONS_EXPORT ContentPlatformSpecificTabData
}
private:
- // PlatformSpecificTabData:
- std::unique_ptr<PlatformSpecificTabData> Clone() override;
-
scoped_refptr<content::SessionStorageNamespace> session_storage_namespace_;
};
diff --git a/chromium/components/sessions/content/content_record_password_state.cc b/chromium/components/sessions/content/content_record_password_state.cc
new file mode 100644
index 00000000000..5e4c26fa5ce
--- /dev/null
+++ b/chromium/components/sessions/content/content_record_password_state.cc
@@ -0,0 +1,42 @@
+// 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 "components/sessions/content/content_record_password_state.h"
+
+#include "content/public/browser/navigation_entry.h"
+
+namespace sessions {
+
+namespace {
+// The key used to store PasswordState in the NavigationEntry;
+// We stash an enum value in the first character of the string16 that is
+// associated with this key.
+const char kPasswordStateKey[] = "sessions_password_state";
+}
+
+SerializedNavigationEntry::PasswordState GetPasswordStateFromNavigation(
+ const content::NavigationEntry& entry) {
+ base::string16 password_state_str;
+ if (!entry.GetExtraData(kPasswordStateKey, &password_state_str) ||
+ password_state_str.size() != 1) {
+ return SerializedNavigationEntry::PASSWORD_STATE_UNKNOWN;
+ }
+
+ SerializedNavigationEntry::PasswordState state =
+ static_cast<SerializedNavigationEntry::PasswordState>(
+ password_state_str[0]);
+
+ DCHECK_GE(state, SerializedNavigationEntry::PASSWORD_STATE_UNKNOWN);
+ DCHECK_LE(state, SerializedNavigationEntry::HAS_PASSWORD_FIELD);
+ return state;
+}
+
+void SetPasswordStateInNavigation(
+ SerializedNavigationEntry::PasswordState state,
+ content::NavigationEntry* entry) {
+ base::string16 password_state_str(1, static_cast<uint16_t>(state));
+ entry->SetExtraData(kPasswordStateKey, password_state_str);
+}
+
+} // namespace sessions
diff --git a/chromium/components/sessions/content/content_record_password_state.h b/chromium/components/sessions/content/content_record_password_state.h
new file mode 100644
index 00000000000..491d01069a7
--- /dev/null
+++ b/chromium/components/sessions/content/content_record_password_state.h
@@ -0,0 +1,27 @@
+// 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 COMPONENTS_SESSIONS_CONTENT_CONTENT_RECORD_PASSWORD_STATE_H_
+#define COMPONENTS_SESSIONS_CONTENT_CONTENT_RECORD_PASSWORD_STATE_H_
+
+#include "components/sessions/core/serialized_navigation_entry.h"
+#include "components/sessions/core/sessions_export.h"
+
+namespace content {
+class NavigationEntry;
+}
+
+namespace sessions {
+
+// Helper functions for storing/getting PasswordState in a NavigationEntry.
+SESSIONS_EXPORT SerializedNavigationEntry::PasswordState
+GetPasswordStateFromNavigation(const content::NavigationEntry& entry);
+
+SESSIONS_EXPORT void SetPasswordStateInNavigation(
+ SerializedNavigationEntry::PasswordState state,
+ content::NavigationEntry* entry);
+
+} // namespace sessions
+
+#endif // COMPONENTS_SESSIONS_CONTENT_CONTENT_RECORD_PASSWORD_STATE_H_
diff --git a/chromium/components/sessions/content/content_serialized_navigation_builder.cc b/chromium/components/sessions/content/content_serialized_navigation_builder.cc
index 072f72e22e9..1894bcb8869 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_builder.cc
+++ b/chromium/components/sessions/content/content_serialized_navigation_builder.cc
@@ -4,6 +4,10 @@
#include "components/sessions/content/content_serialized_navigation_builder.h"
+#include "base/logging.h"
+#include "components/sessions/content/content_record_password_state.h"
+#include "components/sessions/content/content_serialized_navigation_driver.h"
+#include "components/sessions/content/extended_info_handler.h"
#include "components/sessions/core/serialized_navigation_entry.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/favicon_status.h"
@@ -39,6 +43,17 @@ ContentSerializedNavigationBuilder::FromNavigationEntry(
navigation.favicon_url_ = entry.GetFavicon().url;
navigation.http_status_code_ = entry.GetHttpStatusCode();
navigation.redirect_chain_ = entry.GetRedirectChain();
+ navigation.password_state_ = GetPasswordStateFromNavigation(entry);
+
+ for (const auto& handler_entry :
+ ContentSerializedNavigationDriver::GetInstance()
+ ->GetAllExtendedInfoHandlers()) {
+ ExtendedInfoHandler* handler = handler_entry.second.get();
+ DCHECK(handler);
+ std::string value = handler->GetExtendedInfo(entry);
+ if (!value.empty())
+ navigation.extended_info_map_[handler_entry.first] = value;
+ }
return navigation;
}
@@ -76,6 +91,20 @@ ContentSerializedNavigationBuilder::ToNavigationEntry(
entry->SetHttpStatusCode(navigation->http_status_code_);
entry->SetRedirectChain(navigation->redirect_chain_);
+ const ContentSerializedNavigationDriver::ExtendedInfoHandlerMap&
+ extended_info_handlers = ContentSerializedNavigationDriver::GetInstance()
+ ->GetAllExtendedInfoHandlers();
+ for (const auto& extended_info_entry : navigation->extended_info_map_) {
+ const std::string& key = extended_info_entry.first;
+ if (!extended_info_handlers.count(key))
+ continue;
+ ExtendedInfoHandler* extended_info_handler =
+ extended_info_handlers.at(key).get();
+ DCHECK(extended_info_handler);
+ extended_info_handler->RestoreExtendedInfo(extended_info_entry.second,
+ entry.get());
+ }
+
// These fields should have default values.
DCHECK_EQ(SerializedNavigationEntry::STATE_INVALID,
navigation->blocked_state_);
diff --git a/chromium/components/sessions/content/content_serialized_navigation_builder_unittest.cc b/chromium/components/sessions/content/content_serialized_navigation_builder_unittest.cc
index 4109a8a3603..5f402982435 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_builder_unittest.cc
+++ b/chromium/components/sessions/content/content_serialized_navigation_builder_unittest.cc
@@ -4,6 +4,11 @@
#include "components/sessions/content/content_serialized_navigation_builder.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/sessions/content/content_record_password_state.h"
+#include "components/sessions/content/content_serialized_navigation_driver.h"
+#include "components/sessions/content/extended_info_handler.h"
#include "components/sessions/core/serialized_navigation_entry.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "content/public/browser/favicon_status.h"
@@ -15,6 +20,35 @@
namespace sessions {
namespace {
+
+const char kExtendedInfoKey1[] = "Key 1";
+const char kExtendedInfoValue1[] = "Value 1";
+const char kExtendedInfoKey2[] = "Key 2";
+const char kExtendedInfoValue2[] = "Value 2";
+
+class TestExtendedInfoHandler : public ExtendedInfoHandler {
+ public:
+ explicit TestExtendedInfoHandler(const std::string& key) : key_(key) {}
+ ~TestExtendedInfoHandler() override {}
+
+ std::string GetExtendedInfo(
+ const content::NavigationEntry& entry) const override {
+ base::string16 data;
+ entry.GetExtraData(key_, &data);
+ return base::UTF16ToASCII(data);
+ }
+
+ void RestoreExtendedInfo(const std::string& info,
+ content::NavigationEntry* entry) override {
+ entry->SetExtraData(key_, base::ASCIIToUTF16(info));
+ }
+
+ private:
+ std::string key_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestExtendedInfoHandler);
+};
+
// Create a NavigationEntry from the test_data constants in
// serialized_navigation_entry_test_helper.h.
std::unique_ptr<content::NavigationEntry> MakeNavigationEntryForTest() {
@@ -35,6 +69,8 @@ std::unique_ptr<content::NavigationEntry> MakeNavigationEntryForTest() {
navigation_entry->SetTimestamp(test_data::kTimestamp);
navigation_entry->SetExtraData(kSearchTermsKey,
test_data::kSearchTerms);
+ SetPasswordStateInNavigation(test_data::kPasswordState,
+ navigation_entry.get());
navigation_entry->GetFavicon().valid = true;
navigation_entry->GetFavicon().url = test_data::kFaviconURL;
navigation_entry->SetHttpStatusCode(test_data::kHttpStatusCode);
@@ -46,6 +82,19 @@ std::unique_ptr<content::NavigationEntry> MakeNavigationEntryForTest() {
return navigation_entry;
}
+void SetExtendedInfoForTest(content::NavigationEntry* entry) {
+ entry->SetExtraData(kExtendedInfoKey1,
+ base::ASCIIToUTF16(kExtendedInfoValue1));
+ entry->SetExtraData(kExtendedInfoKey2,
+ base::ASCIIToUTF16(kExtendedInfoValue2));
+ ContentSerializedNavigationDriver::GetInstance()->RegisterExtendedInfoHandler(
+ kExtendedInfoKey1, base::WrapUnique<ExtendedInfoHandler>(
+ new TestExtendedInfoHandler(kExtendedInfoKey1)));
+ ContentSerializedNavigationDriver::GetInstance()->RegisterExtendedInfoHandler(
+ kExtendedInfoKey2, base::WrapUnique<ExtendedInfoHandler>(
+ new TestExtendedInfoHandler(kExtendedInfoKey2)));
+}
+
} // namespace
@@ -54,6 +103,7 @@ std::unique_ptr<content::NavigationEntry> MakeNavigationEntryForTest() {
TEST(ContentSerializedNavigationBuilderTest, FromNavigationEntry) {
const std::unique_ptr<content::NavigationEntry> navigation_entry(
MakeNavigationEntryForTest());
+ SetExtendedInfoForTest(navigation_entry.get());
const SerializedNavigationEntry& navigation =
ContentSerializedNavigationBuilder::FromNavigationEntry(
@@ -81,6 +131,15 @@ TEST(ContentSerializedNavigationBuilderTest, FromNavigationEntry) {
EXPECT_EQ(test_data::kRedirectURL0, navigation.redirect_chain()[0]);
EXPECT_EQ(test_data::kRedirectURL1, navigation.redirect_chain()[1]);
EXPECT_EQ(test_data::kVirtualURL, navigation.redirect_chain()[2]);
+ EXPECT_EQ(test_data::kPasswordState, navigation.password_state());
+
+ ASSERT_EQ(2U, navigation.extended_info_map().size());
+ ASSERT_EQ(1U, navigation.extended_info_map().count(kExtendedInfoKey1));
+ EXPECT_EQ(kExtendedInfoValue1,
+ navigation.extended_info_map().at(kExtendedInfoKey1));
+ ASSERT_EQ(1U, navigation.extended_info_map().count(kExtendedInfoKey2));
+ EXPECT_EQ(kExtendedInfoValue2,
+ navigation.extended_info_map().at(kExtendedInfoKey2));
}
// Create a NavigationEntry, then create another one by converting to
@@ -90,6 +149,7 @@ TEST(ContentSerializedNavigationBuilderTest, FromNavigationEntry) {
TEST(ContentSerializedNavigationBuilderTest, ToNavigationEntry) {
const std::unique_ptr<content::NavigationEntry> old_navigation_entry(
MakeNavigationEntryForTest());
+ SetExtendedInfoForTest(old_navigation_entry.get());
const SerializedNavigationEntry& navigation =
ContentSerializedNavigationBuilder::FromNavigationEntry(
@@ -127,6 +187,26 @@ TEST(ContentSerializedNavigationBuilderTest, ToNavigationEntry) {
new_navigation_entry->GetRedirectChain()[1]);
EXPECT_EQ(test_data::kVirtualURL,
new_navigation_entry->GetRedirectChain()[2]);
+
+ base::string16 extra_data;
+ EXPECT_TRUE(
+ new_navigation_entry->GetExtraData(kExtendedInfoKey1, &extra_data));
+ EXPECT_EQ(kExtendedInfoValue1, base::UTF16ToASCII(extra_data));
+ EXPECT_TRUE(
+ new_navigation_entry->GetExtraData(kExtendedInfoKey2, &extra_data));
+ EXPECT_EQ(kExtendedInfoValue2, base::UTF16ToASCII(extra_data));
+}
+
+TEST(ContentSerializedNavigationBuilderTest, SetPasswordState) {
+ std::unique_ptr<content::NavigationEntry> entry(
+ content::NavigationEntry::Create());
+
+ EXPECT_EQ(SerializedNavigationEntry::PASSWORD_STATE_UNKNOWN,
+ GetPasswordStateFromNavigation(*entry));
+ SetPasswordStateInNavigation(SerializedNavigationEntry::NO_PASSWORD_FIELD,
+ entry.get());
+ EXPECT_EQ(SerializedNavigationEntry::NO_PASSWORD_FIELD,
+ GetPasswordStateFromNavigation(*entry));
}
} // namespace sessions
diff --git a/chromium/components/sessions/content/content_serialized_navigation_driver.cc b/chromium/components/sessions/content/content_serialized_navigation_driver.cc
index a3305a86953..8f4d47bd3fe 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_driver.cc
+++ b/chromium/components/sessions/content/content_serialized_navigation_driver.cc
@@ -18,6 +18,13 @@ const int kObsoleteReferrerPolicyAlways = 0;
const int kObsoleteReferrerPolicyDefault = 1;
const int kObsoleteReferrerPolicyNever = 2;
const int kObsoleteReferrerPolicyOrigin = 3;
+
+bool IsUberOrUberReplacementURL(const GURL& url) {
+ return url.SchemeIs(content::kChromeUIScheme) &&
+ (url.host() == content::kChromeUIHistoryHost ||
+ url.host() == content::kChromeUIUberHost);
+}
+
} // namespace
// static
@@ -103,6 +110,14 @@ void ContentSerializedNavigationDriver::Sanitize(
content::Referrer::SanitizeForRequest(navigation->virtual_url_,
old_referrer);
+ // Clear any Uber UI page state so that these pages are reloaded rather than
+ // restored from page state. This fixes session restore when WebUI URLs
+ // change.
+ if (IsUberOrUberReplacementURL(navigation->virtual_url_) &&
+ IsUberOrUberReplacementURL(navigation->original_request_url_)) {
+ navigation->encoded_page_state_ = std::string();
+ }
+
// No need to compare the policy, as it doesn't change during
// sanitization. If there has been a change, the referrer needs to be
// stripped from the page state as well.
@@ -133,4 +148,18 @@ std::string ContentSerializedNavigationDriver::StripReferrerFromPageState(
.ToEncodedData();
}
+void ContentSerializedNavigationDriver::RegisterExtendedInfoHandler(
+ const std::string& key,
+ std::unique_ptr<ExtendedInfoHandler> handler) {
+ DCHECK(!key.empty());
+ DCHECK(!extended_info_handler_map_.count(key));
+ DCHECK(handler.get());
+ extended_info_handler_map_[key] = std::move(handler);
+}
+
+const ContentSerializedNavigationDriver::ExtendedInfoHandlerMap&
+ContentSerializedNavigationDriver::GetAllExtendedInfoHandlers() const {
+ return extended_info_handler_map_;
+}
+
} // namespace sessions
diff --git a/chromium/components/sessions/content/content_serialized_navigation_driver.h b/chromium/components/sessions/content/content_serialized_navigation_driver.h
index c0911d70e87..a471738f339 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_driver.h
+++ b/chromium/components/sessions/content/content_serialized_navigation_driver.h
@@ -7,6 +7,12 @@
#include "components/sessions/core/serialized_navigation_driver.h"
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "components/sessions/content/extended_info_handler.h"
#include "components/sessions/core/sessions_export.h"
namespace base {
@@ -38,9 +44,27 @@ class SESSIONS_EXPORT ContentSerializedNavigationDriver
std::string StripReferrerFromPageState(
const std::string& page_state) const override;
+ // Registers a handler that is used to read and write the extended
+ // info stored in SerializedNavigationEntry. As part of serialization |key|
+ // is written to disk, as such once a handler is registered it should always
+ // be registered to the same key.
+ void RegisterExtendedInfoHandler(
+ const std::string& key,
+ std::unique_ptr<ExtendedInfoHandler> handler);
+
+ using ExtendedInfoHandlerMap =
+ std::map<std::string, std::unique_ptr<ExtendedInfoHandler>>;
+
+ // Returns all the registered handlers to deal with the extended info.
+ const ExtendedInfoHandlerMap& GetAllExtendedInfoHandlers() const;
+
private:
ContentSerializedNavigationDriver();
friend struct base::DefaultSingletonTraits<ContentSerializedNavigationDriver>;
+
+ ExtendedInfoHandlerMap extended_info_handler_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentSerializedNavigationDriver);
};
} // namespace sessions
diff --git a/chromium/components/sessions/content/extended_info_handler.h b/chromium/components/sessions/content/extended_info_handler.h
new file mode 100644
index 00000000000..3ceafa77160
--- /dev/null
+++ b/chromium/components/sessions/content/extended_info_handler.h
@@ -0,0 +1,40 @@
+// 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 COMPONENTS_SESSIONS_CONTENT_EXTENDED_INFO_HANDLER_H_
+#define COMPONENTS_SESSIONS_CONTENT_EXTENDED_INFO_HANDLER_H_
+
+#include <string>
+
+#include "components/sessions/core/sessions_export.h"
+
+namespace content {
+class NavigationEntry;
+}
+
+namespace sessions {
+
+// This interface is used to store and retrieve arbitrary key/value pairs for
+// a NavigationEntry that are not a core part of NavigationEntry.
+// WARNING: implementations must deal with versioning. In particular
+// RestoreExtendedInfo() may be called with data from a previous version of
+// Chrome.
+class SESSIONS_EXPORT ExtendedInfoHandler {
+ public:
+ ExtendedInfoHandler() {}
+ virtual ~ExtendedInfoHandler() {}
+
+ // Returns the data to write to disk for the specified NavigationEntry.
+ virtual std::string GetExtendedInfo(
+ const content::NavigationEntry& entry) const = 0;
+
+ // Restores |info| which was obtained from a previous call to
+ // GetExtendedInfo() to a NavigationEntry.
+ virtual void RestoreExtendedInfo(const std::string& info,
+ content::NavigationEntry* entry) = 0;
+};
+
+} // namespace sessions
+
+#endif // COMPONENTS_SESSIONS_CONTENT_EXTENDED_INFO_HANDLER_H_
diff --git a/chromium/components/sessions/core/in_memory_tab_restore_service.cc b/chromium/components/sessions/core/in_memory_tab_restore_service.cc
index 5caf5767c3d..cdc31f19474 100644
--- a/chromium/components/sessions/core/in_memory_tab_restore_service.cc
+++ b/chromium/components/sessions/core/in_memory_tab_restore_service.cc
@@ -55,8 +55,8 @@ std::vector<LiveTab*> InMemoryTabRestoreService::RestoreMostRecentEntry(
return helper_.RestoreMostRecentEntry(context);
}
-TabRestoreService::Tab* InMemoryTabRestoreService::RemoveTabEntryById(
- SessionID::id_type id) {
+std::unique_ptr<TabRestoreService::Tab>
+InMemoryTabRestoreService::RemoveTabEntryById(SessionID::id_type id) {
return helper_.RemoveTabEntryById(id);
}
@@ -81,6 +81,10 @@ void InMemoryTabRestoreService::DeleteLastSession() {
// See comment above.
}
+bool InMemoryTabRestoreService::IsRestoring() const {
+ return helper_.IsRestoring();
+}
+
void InMemoryTabRestoreService::Shutdown() {
}
diff --git a/chromium/components/sessions/core/in_memory_tab_restore_service.h b/chromium/components/sessions/core/in_memory_tab_restore_service.h
index eeb49044865..c6174c32b0e 100644
--- a/chromium/components/sessions/core/in_memory_tab_restore_service.h
+++ b/chromium/components/sessions/core/in_memory_tab_restore_service.h
@@ -42,7 +42,7 @@ class SESSIONS_EXPORT InMemoryTabRestoreService : public TabRestoreService {
const Entries& entries() const override;
std::vector<LiveTab*> RestoreMostRecentEntry(
LiveTabContext* context) override;
- Tab* RemoveTabEntryById(SessionID::id_type id) override;
+ std::unique_ptr<Tab> RemoveTabEntryById(SessionID::id_type id) override;
std::vector<LiveTab*> RestoreEntryById(
LiveTabContext* context,
SessionID::id_type id,
@@ -50,6 +50,7 @@ class SESSIONS_EXPORT InMemoryTabRestoreService : public TabRestoreService {
void LoadTabsFromLastSession() override;
bool IsLoaded() const override;
void DeleteLastSession() override;
+ bool IsRestoring() const override;
void Shutdown() override;
private:
diff --git a/chromium/components/sessions/core/persistent_tab_restore_service.cc b/chromium/components/sessions/core/persistent_tab_restore_service.cc
index 984c3af264d..d9266e74d7c 100644
--- a/chromium/components/sessions/core/persistent_tab_restore_service.cc
+++ b/chromium/components/sessions/core/persistent_tab_restore_service.cc
@@ -15,8 +15,8 @@
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
#include "base/stl_util.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/time/time.h"
@@ -35,8 +35,6 @@ typedef bool PinnedStatePayload;
typedef int32_t RestoredEntryPayload;
-typedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry;
-
// Payload used for the start of a tab close. This is the old struct that is
// used for backwards compat when it comes to reading the session files.
struct SelectedNavigationInTabPayload {
@@ -111,6 +109,32 @@ const int kEntriesPerReset = 40;
const size_t kMaxEntries = TabRestoreServiceHelper::kMaxEntries;
+void RemoveEntryByID(
+ SessionID::id_type id,
+ std::vector<std::unique_ptr<TabRestoreService::Entry>>* entries) {
+ // Look for the entry in the top-level collection.
+ for (auto it = entries->begin(); it != entries->end(); ++it) {
+ TabRestoreService::Entry& entry = **it;
+ // Erase it if it's our target.
+ if (entry.id == id) {
+ entries->erase(it);
+ return;
+ }
+ // If this entry is a window, look through its tabs.
+ if (entry.type == TabRestoreService::WINDOW) {
+ auto& window = static_cast<TabRestoreService::Window&>(entry);
+ for (auto it = window.tabs.begin(); it != window.tabs.end(); ++it) {
+ const TabRestoreService::Tab& tab = **it;
+ // Erase it if it's our target.
+ if (tab.id == id) {
+ window.tabs.erase(it);
+ return;
+ }
+ }
+ }
+ }
+}
+
} // namespace
// PersistentTabRestoreService::Delegate ---------------------------------------
@@ -148,8 +172,9 @@ class PersistentTabRestoreService::Delegate
bool IsLoaded() const;
// Creates and add entries to |entries| for each of the windows in |windows|.
- static void CreateEntriesFromWindows(std::vector<SessionWindow*>* windows,
- std::vector<Entry*>* entries);
+ static void CreateEntriesFromWindows(
+ std::vector<std::unique_ptr<sessions::SessionWindow>>* windows,
+ std::vector<std::unique_ptr<Entry>>* entries);
void Shutdown();
@@ -189,18 +214,20 @@ class PersistentTabRestoreService::Delegate
void OnGotLastSessionCommands(ScopedVector<SessionCommand> commands);
// Populates |loaded_entries| with Entries from |commands|.
- void CreateEntriesFromCommands(const std::vector<SessionCommand*>& commands,
- std::vector<Entry*>* loaded_entries);
+ void CreateEntriesFromCommands(
+ const std::vector<SessionCommand*>& commands,
+ std::vector<std::unique_ptr<Entry>>* loaded_entries);
// Validates all entries in |entries|, deleting any with no navigations. This
// also deletes any entries beyond the max number of entries we can hold.
- static void ValidateAndDeleteEmptyEntries(std::vector<Entry*>* entries);
+ static void ValidateAndDeleteEmptyEntries(
+ std::vector<std::unique_ptr<Entry>>* entries);
// Callback from BaseSessionService when we've received the windows from the
// previous session. This creates and add entries to |staging_entries_| and
// invokes LoadStateChanged. |ignored_active_window| is ignored because we
// don't need to restore activation.
- void OnGotPreviousSession(ScopedVector<SessionWindow> windows,
+ void OnGotPreviousSession(std::vector<std::unique_ptr<SessionWindow>> windows,
SessionID::id_type ignored_active_window);
// Converts a SessionWindow into a Window, returning true on success. We use 0
@@ -213,13 +240,6 @@ class PersistentTabRestoreService::Delegate
// observers are notified.
void LoadStateChanged();
- // If |id_to_entry| contains an entry for |id| the corresponding entry is
- // deleted and removed from both |id_to_entry| and |entries|. This is used
- // when creating entries from the backend file.
- void RemoveEntryByID(SessionID::id_type id,
- IDToEntry* id_to_entry,
- std::vector<TabRestoreService::Entry*>* entries);
-
private:
// The associated client.
TabRestoreServiceClient* client_;
@@ -240,7 +260,7 @@ class PersistentTabRestoreService::Delegate
// Results from previously closed tabs/sessions is first added here. When the
// results from both us and the session restore service have finished loading
// LoadStateChanged is invoked, which adds these entries to entries_.
- ScopedVector<Entry> staging_entries_;
+ std::vector<std::unique_ptr<Entry>> staging_entries_;
// Used when loading previous tabs/session and open tabs/session.
base::CancelableTaskTracker cancelable_task_tracker_;
@@ -287,14 +307,18 @@ void PersistentTabRestoreService::Delegate::OnWillSaveCommands() {
DCHECK(static_cast<size_t>(to_write_count) <= entries.size());
std::advance(i, entries.size() - static_cast<int>(to_write_count));
for (; i != entries.rend(); ++i) {
- Entry* entry = *i;
- if (entry->type == TAB) {
- Tab* tab = static_cast<Tab*>(entry);
- int selected_index = GetSelectedNavigationIndexToPersist(*tab);
- if (selected_index != -1)
- ScheduleCommandsForTab(*tab, selected_index);
- } else {
- ScheduleCommandsForWindow(*static_cast<Window*>(entry));
+ Entry& entry = **i;
+ switch (entry.type) {
+ case TAB: {
+ Tab& tab = static_cast<Tab&>(entry);
+ int selected_index = GetSelectedNavigationIndexToPersist(tab);
+ if (selected_index != -1)
+ ScheduleCommandsForTab(tab, selected_index);
+ break;
+ }
+ case WINDOW:
+ ScheduleCommandsForWindow(static_cast<Window&>(entry));
+ break;
}
entries_written_++;
}
@@ -379,12 +403,12 @@ bool PersistentTabRestoreService::Delegate::IsLoaded() const {
// static
void PersistentTabRestoreService::Delegate::CreateEntriesFromWindows(
- std::vector<SessionWindow*>* windows,
- std::vector<Entry*>* entries) {
- for (size_t i = 0; i < windows->size(); ++i) {
- std::unique_ptr<Window> window(new Window());
- if (ConvertSessionWindowToWindow((*windows)[i], window.get()))
- entries->push_back(window.release());
+ std::vector<std::unique_ptr<sessions::SessionWindow>>* windows,
+ std::vector<std::unique_ptr<Entry>>* entries) {
+ for (const auto& session_window : *windows) {
+ std::unique_ptr<Window> window = base::MakeUnique<Window>();
+ if (ConvertSessionWindowToWindow(session_window.get(), window.get()))
+ entries->push_back(std::move(window));
}
}
@@ -399,7 +423,7 @@ void PersistentTabRestoreService::Delegate::ScheduleCommandsForWindow(
int valid_tab_count = 0;
int real_selected_tab = selected_tab;
for (size_t i = 0; i < window.tabs.size(); ++i) {
- if (GetSelectedNavigationIndexToPersist(window.tabs[i]) != -1) {
+ if (GetSelectedNavigationIndexToPersist(*window.tabs[i]) != -1) {
valid_tab_count++;
} else if (static_cast<int>(i) < selected_tab) {
real_selected_tab--;
@@ -418,9 +442,9 @@ void PersistentTabRestoreService::Delegate::ScheduleCommandsForWindow(
}
for (size_t i = 0; i < window.tabs.size(); ++i) {
- int selected_index = GetSelectedNavigationIndexToPersist(window.tabs[i]);
+ int selected_index = GetSelectedNavigationIndexToPersist(*window.tabs[i]);
if (selected_index != -1)
- ScheduleCommandsForTab(window.tabs[i], selected_index);
+ ScheduleCommandsForTab(*window.tabs[i], selected_index);
}
}
@@ -555,28 +579,28 @@ int PersistentTabRestoreService::Delegate::GetSelectedNavigationIndexToPersist(
void PersistentTabRestoreService::Delegate::OnGotLastSessionCommands(
ScopedVector<SessionCommand> commands) {
- std::vector<Entry*> entries;
+ std::vector<std::unique_ptr<TabRestoreService::Entry>> entries;
CreateEntriesFromCommands(commands.get(), &entries);
// Closed tabs always go to the end.
- staging_entries_.insert(staging_entries_.end(), entries.begin(),
- entries.end());
+ staging_entries_.insert(staging_entries_.end(),
+ make_move_iterator(entries.begin()),
+ make_move_iterator(entries.end()));
load_state_ |= LOADED_LAST_TABS;
LoadStateChanged();
}
void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands(
const std::vector<SessionCommand*>& commands,
- std::vector<Entry*>* loaded_entries) {
+ std::vector<std::unique_ptr<Entry>>* loaded_entries) {
if (tab_restore_service_helper_->entries().size() == kMaxEntries)
return;
- // Iterate through the commands populating entries and id_to_entry.
- ScopedVector<Entry> entries;
- IDToEntry id_to_entry;
+ // Iterate through the commands, populating |entries|.
+ std::vector<std::unique_ptr<Entry>> entries;
// If non-null we're processing the navigations of this tab.
- Tab* current_tab = NULL;
+ Tab* current_tab = nullptr;
// If non-null we're processing the tabs of this window.
- Window* current_window = NULL;
+ Window* current_window = nullptr;
// If > 0, we've gotten a window command but not all the tabs yet.
int pending_window_tabs = 0;
for (std::vector<SessionCommand*>::const_iterator i = commands.begin();
@@ -590,13 +614,13 @@ void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands(
return;
}
- current_tab = NULL;
- current_window = NULL;
+ current_tab = nullptr;
+ current_window = nullptr;
RestoredEntryPayload payload;
if (!command.GetPayload(&payload, sizeof(payload)))
return;
- RemoveEntryByID(payload, &id_to_entry, &(entries.get()));
+ RemoveEntryByID(payload, &entries);
break;
}
@@ -630,14 +654,13 @@ void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands(
return;
}
- RemoveEntryByID(payload.window_id, &id_to_entry, &(entries.get()));
+ RemoveEntryByID(payload.window_id, &entries);
- current_window = new Window();
+ entries.push_back(base::MakeUnique<Window>());
+ current_window = static_cast<Window*>(entries.back().get());
current_window->selected_tab_index = payload.selected_tab_index;
current_window->timestamp =
base::Time::FromInternalValue(payload.timestamp);
- entries.push_back(current_window);
- id_to_entry[payload.window_id] = current_window;
break;
}
@@ -660,17 +683,16 @@ void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands(
NOTREACHED();
return;
}
- current_window->tabs.resize(current_window->tabs.size() + 1);
- current_tab = &(current_window->tabs.back());
+ current_window->tabs.push_back(base::MakeUnique<Tab>());
+ current_tab = current_window->tabs.back().get();
if (--pending_window_tabs == 0)
- current_window = NULL;
+ current_window = nullptr;
} else {
- RemoveEntryByID(payload.id, &id_to_entry, &(entries.get()));
- current_tab = new Tab();
- id_to_entry[payload.id] = current_tab;
+ RemoveEntryByID(payload.id, &entries);
+ entries.push_back(base::MakeUnique<Tab>());
+ current_tab = static_cast<Tab*>(entries.back().get());
current_tab->timestamp =
base::Time::FromInternalValue(payload.timestamp);
- entries.push_back(current_tab);
}
current_tab->current_navigation_index = payload.index;
break;
@@ -757,40 +779,34 @@ void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands(
}
// If there was corruption some of the entries won't be valid.
- ValidateAndDeleteEmptyEntries(&(entries.get()));
+ ValidateAndDeleteEmptyEntries(&entries);
- loaded_entries->swap(entries.get());
+ loaded_entries->swap(entries);
}
// static
void PersistentTabRestoreService::Delegate::ValidateAndDeleteEmptyEntries(
- std::vector<Entry*>* entries) {
- std::vector<Entry*> valid_entries;
- std::vector<Entry*> invalid_entries;
+ std::vector<std::unique_ptr<Entry>>* entries) {
+ std::vector<std::unique_ptr<Entry>> valid_entries;
// Iterate from the back so that we keep the most recently closed entries.
- for (std::vector<Entry*>::reverse_iterator i = entries->rbegin();
- i != entries->rend(); ++i) {
- if (TabRestoreServiceHelper::ValidateEntry(*i))
- valid_entries.push_back(*i);
- else
- invalid_entries.push_back(*i);
+ for (auto i = entries->rbegin(); i != entries->rend(); ++i) {
+ if (TabRestoreServiceHelper::ValidateEntry(**i))
+ valid_entries.push_back(std::move(*i));
}
// NOTE: at this point the entries are ordered with newest at the front.
entries->swap(valid_entries);
-
- // Delete the remaining entries.
- STLDeleteElements(&invalid_entries);
}
void PersistentTabRestoreService::Delegate::OnGotPreviousSession(
- ScopedVector<SessionWindow> windows,
+ std::vector<std::unique_ptr<SessionWindow>> windows,
SessionID::id_type ignored_active_window) {
- std::vector<Entry*> entries;
- CreateEntriesFromWindows(&windows.get(), &entries);
+ std::vector<std::unique_ptr<Entry>> entries;
+ CreateEntriesFromWindows(&windows, &entries);
// Previous session tabs go first.
- staging_entries_.insert(staging_entries_.begin(), entries.begin(),
- entries.end());
+ staging_entries_.insert(staging_entries_.begin(),
+ make_move_iterator(entries.begin()),
+ make_move_iterator(entries.end()));
load_state_ |= LOADED_LAST_SESSION;
LoadStateChanged();
}
@@ -800,8 +816,8 @@ bool PersistentTabRestoreService::Delegate::ConvertSessionWindowToWindow(
Window* window) {
for (size_t i = 0; i < session_window->tabs.size(); ++i) {
if (!session_window->tabs[i]->navigations.empty()) {
- window->tabs.resize(window->tabs.size() + 1);
- Tab& tab = window->tabs.back();
+ window->tabs.push_back(base::MakeUnique<Tab>());
+ Tab& tab = *window->tabs.back();
tab.pinned = session_window->tabs[i]->pinned;
tab.navigations.swap(session_window->tabs[i]->navigations);
tab.current_navigation_index =
@@ -850,19 +866,14 @@ void PersistentTabRestoreService::Delegate::LoadStateChanged() {
}
// And add them.
- for (size_t i = 0; i < staging_entries_.size(); ++i) {
- staging_entries_[i]->from_last_session = true;
- tab_restore_service_helper_->AddEntry(staging_entries_[i], false, false);
+ for (auto& staging_entry : staging_entries_) {
+ staging_entry->from_last_session = true;
+ tab_restore_service_helper_->AddEntry(std::move(staging_entry), false,
+ false);
}
- // AddEntry takes ownership of the entry, need to clear out entries so that
- // it doesn't delete them.
- staging_entries_.weak_clear();
-
- // Make it so we rewrite all the tabs. We need to do this otherwise we won't
- // correctly write out the entries when Save is invoked (Save starts from
- // the front, not the end and we just added the entries to the end).
- entries_to_write_ = staging_entries_.size();
+ staging_entries_.clear();
+ entries_to_write_ = 0;
tab_restore_service_helper_->PruneEntries();
tab_restore_service_helper_->NotifyTabsChanged();
@@ -870,40 +881,6 @@ void PersistentTabRestoreService::Delegate::LoadStateChanged() {
tab_restore_service_helper_->NotifyLoaded();
}
-void PersistentTabRestoreService::Delegate::RemoveEntryByID(
- SessionID::id_type id,
- IDToEntry* id_to_entry,
- std::vector<TabRestoreService::Entry*>* entries) {
- // Look for the entry in the map. If it is present, erase it from both
- // collections and return.
- IDToEntry::iterator i = id_to_entry->find(id);
- if (i != id_to_entry->end()) {
- entries->erase(std::find(entries->begin(), entries->end(), i->second));
- delete i->second;
- id_to_entry->erase(i);
- return;
- }
-
- // Otherwise, loop over all items in the map and see if any of the Windows
- // have Tabs with the |id|.
- for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end();
- ++i) {
- if (i->second->type == TabRestoreService::WINDOW) {
- TabRestoreService::Window* window =
- static_cast<TabRestoreService::Window*>(i->second);
- std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin();
- for ( ; j != window->tabs.end(); ++j) {
- // If the ID matches one of this window's tabs, remove it from the
- // list.
- if ((*j).id == id) {
- window->tabs.erase(j);
- return;
- }
- }
- }
- }
-}
-
// PersistentTabRestoreService -------------------------------------------------
PersistentTabRestoreService::PersistentTabRestoreService(
@@ -953,8 +930,8 @@ std::vector<LiveTab*> PersistentTabRestoreService::RestoreMostRecentEntry(
return helper_.RestoreMostRecentEntry(context);
}
-TabRestoreService::Tab* PersistentTabRestoreService::RemoveTabEntryById(
- SessionID::id_type id) {
+std::unique_ptr<TabRestoreService::Tab>
+PersistentTabRestoreService::RemoveTabEntryById(SessionID::id_type id) {
return helper_.RemoveTabEntryById(id);
}
@@ -973,6 +950,10 @@ void PersistentTabRestoreService::DeleteLastSession() {
return delegate_->DeleteLastSession();
}
+bool PersistentTabRestoreService::IsRestoring() const {
+ return helper_.IsRestoring();
+}
+
void PersistentTabRestoreService::Shutdown() {
return delegate_->Shutdown();
}
diff --git a/chromium/components/sessions/core/persistent_tab_restore_service.h b/chromium/components/sessions/core/persistent_tab_restore_service.h
index ac3ffd4125b..9d2eaa869c2 100644
--- a/chromium/components/sessions/core/persistent_tab_restore_service.h
+++ b/chromium/components/sessions/core/persistent_tab_restore_service.h
@@ -38,7 +38,7 @@ class SESSIONS_EXPORT PersistentTabRestoreService : public TabRestoreService {
const Entries& entries() const override;
std::vector<LiveTab*> RestoreMostRecentEntry(
LiveTabContext* context) override;
- Tab* RemoveTabEntryById(SessionID::id_type id) override;
+ std::unique_ptr<Tab> RemoveTabEntryById(SessionID::id_type id) override;
std::vector<LiveTab*> RestoreEntryById(
LiveTabContext* context,
SessionID::id_type id,
@@ -46,6 +46,7 @@ class SESSIONS_EXPORT PersistentTabRestoreService : public TabRestoreService {
void LoadTabsFromLastSession() override;
bool IsLoaded() const override;
void DeleteLastSession() override;
+ bool IsRestoring() const override;
void Shutdown() override;
private:
diff --git a/chromium/components/sessions/core/serialized_navigation_entry.cc b/chromium/components/sessions/core/serialized_navigation_entry.cc
index 4d3a9f6e942..08685eb3602 100644
--- a/chromium/components/sessions/core/serialized_navigation_entry.cc
+++ b/chromium/components/sessions/core/serialized_navigation_entry.cc
@@ -9,11 +9,12 @@
#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
#include "components/sessions/core/serialized_navigation_driver.h"
-#include "sync/protocol/session_specifics.pb.h"
-#include "sync/util/time.h"
+#include "components/sync/base/time.h"
+#include "components/sync/protocol/session_specifics.pb.h"
namespace sessions {
+// TODO(treib): Remove, not needed anymore. crbug.com/627747
const char kSearchTermsKey[] = "search_terms";
SerializedNavigationEntry::SerializedNavigationEntry()
@@ -25,7 +26,8 @@ SerializedNavigationEntry::SerializedNavigationEntry()
is_overriding_user_agent_(false),
http_status_code_(0),
is_restored_(false),
- blocked_state_(STATE_INVALID) {
+ blocked_state_(STATE_INVALID),
+ password_state_(PASSWORD_STATE_UNKNOWN) {
referrer_policy_ =
SerializedNavigationDriver::Get()->GetDefaultReferrerPolicy();
}
@@ -127,6 +129,12 @@ SerializedNavigationEntry SerializedNavigationEntry::FromSyncData(
if (sync_data.has_favicon_url())
navigation.favicon_url_ = GURL(sync_data.favicon_url());
+ if (sync_data.has_password_state()) {
+ navigation.password_state_ =
+ static_cast<SerializedNavigationEntry::PasswordState>(
+ sync_data.password_state());
+ }
+
navigation.http_status_code_ = sync_data.http_status_code();
SerializedNavigationDriver::Get()->Sanitize(&navigation);
@@ -205,6 +213,7 @@ enum TypeMask {
// search_terms_
// http_status_code_
// referrer_policy_
+// extended_info_map_
void SerializedNavigationEntry::WriteToPickle(int max_size,
base::Pickle* pickle) const {
@@ -249,6 +258,12 @@ void SerializedNavigationEntry::WriteToPickle(int max_size,
pickle->WriteInt(http_status_code_);
pickle->WriteInt(referrer_policy_);
+
+ pickle->WriteInt(extended_info_map_.size());
+ for (const auto entry : extended_info_map_) {
+ WriteStringToPickle(pickle, &bytes_written, max_size, entry.first);
+ WriteStringToPickle(pickle, &bytes_written, max_size, entry.second);
+ }
}
bool SerializedNavigationEntry::ReadFromPickle(base::PickleIterator* iterator) {
@@ -327,6 +342,17 @@ bool SerializedNavigationEntry::ReadFromPickle(base::PickleIterator* iterator) {
SerializedNavigationDriver::Get()->StripReferrerFromPageState(
encoded_page_state_);
}
+
+ int extended_info_map_size = 0;
+ if (iterator->ReadInt(&extended_info_map_size) &&
+ extended_info_map_size > 0) {
+ for (int i = 0; i < extended_info_map_size; ++i) {
+ std::string key;
+ std::string value;
+ if (iterator->ReadString(&key) && iterator->ReadString(&value))
+ extended_info_map_[key] = value;
+ }
+ }
}
SerializedNavigationDriver::Get()->Sanitize(this);
@@ -444,6 +470,9 @@ sync_pb::TabNavigation SerializedNavigationEntry::ToSyncData() const {
static_cast<sync_pb::TabNavigation_BlockedState>(blocked_state_));
}
+ sync_data.set_password_state(
+ static_cast<sync_pb::TabNavigation_PasswordState>(password_state_));
+
for (std::set<std::string>::const_iterator it =
content_pack_categories_.begin();
it != content_pack_categories_.end(); ++it) {
diff --git a/chromium/components/sessions/core/serialized_navigation_entry.h b/chromium/components/sessions/core/serialized_navigation_entry.h
index a61951d29f8..8601c972027 100644
--- a/chromium/components/sessions/core/serialized_navigation_entry.h
+++ b/chromium/components/sessions/core/serialized_navigation_entry.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <map>
#include <memory>
#include <set>
#include <string>
@@ -48,6 +49,14 @@ class SESSIONS_EXPORT SerializedNavigationEntry {
STATE_BLOCKED = 2,
};
+ // These must match the proto. They are in priority order such that if a
+ // higher value is seen, it should overwrite a lower value.
+ enum PasswordState {
+ PASSWORD_STATE_UNKNOWN = 0,
+ NO_PASSWORD_FIELD = 1,
+ HAS_PASSWORD_FIELD = 2,
+ };
+
// Creates an invalid (index < 0) SerializedNavigationEntry.
SerializedNavigationEntry();
SerializedNavigationEntry(const SerializedNavigationEntry& other);
@@ -96,11 +105,17 @@ class SESSIONS_EXPORT SerializedNavigationEntry {
bool is_overriding_user_agent() const { return is_overriding_user_agent_; }
base::Time timestamp() const { return timestamp_; }
- BlockedState blocked_state() { return blocked_state_; }
+ BlockedState blocked_state() const { return blocked_state_; }
void set_blocked_state(BlockedState blocked_state) {
blocked_state_ = blocked_state;
}
- std::set<std::string> content_pack_categories() {
+
+ PasswordState password_state() const { return password_state_; }
+ void set_password_state(PasswordState password_state) {
+ password_state_ = password_state;
+ }
+
+ std::set<std::string> content_pack_categories() const {
return content_pack_categories_;
}
void set_content_pack_categories(
@@ -109,6 +124,10 @@ class SESSIONS_EXPORT SerializedNavigationEntry {
}
const std::vector<GURL>& redirect_chain() const { return redirect_chain_; }
+ const std::map<std::string, std::string>& extended_info_map() const {
+ return extended_info_map_;
+ }
+
private:
friend class ContentSerializedNavigationBuilder;
friend class ContentSerializedNavigationDriver;
@@ -140,7 +159,12 @@ class SESSIONS_EXPORT SerializedNavigationEntry {
// Additional information.
BlockedState blocked_state_;
+ PasswordState password_state_;
std::set<std::string> content_pack_categories_;
+
+ // Provides storage for arbitrary key/value pairs used by features. This
+ // data is not synced.
+ std::map<std::string, std::string> extended_info_map_;
};
} // namespace sessions
diff --git a/chromium/components/sessions/core/serialized_navigation_entry_test_helper.cc b/chromium/components/sessions/core/serialized_navigation_entry_test_helper.cc
index 2b9c400819f..f090d67a112 100644
--- a/chromium/components/sessions/core/serialized_navigation_entry_test_helper.cc
+++ b/chromium/components/sessions/core/serialized_navigation_entry_test_helper.cc
@@ -7,7 +7,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/sessions/core/serialized_navigation_entry.h"
-#include "sync/util/time.h"
+#include "components/sync/base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -39,6 +39,12 @@ const GURL kRedirectURL0 = GURL("http://go/redirect0");
const GURL kRedirectURL1 = GURL("http://go/redirect1");
const GURL kOtherURL = GURL("http://other.com");
const int kPageID = 10;
+const SerializedNavigationEntry::PasswordState kPasswordState =
+ SerializedNavigationEntry::HAS_PASSWORD_FIELD;
+const std::string kExtendedInfoKey1 = "key 1";
+const std::string kExtendedInfoKey2 = "key 2";
+const std::string kExtendedInfoValue1 = "value 1";
+const std::string kExtendedInfoValue2 = "value 2";
} // namespace test_data
@@ -94,6 +100,12 @@ SerializedNavigationEntryTestHelper::CreateNavigationForTest() {
navigation.search_terms_ = test_data::kSearchTerms;
navigation.favicon_url_ = test_data::kFaviconURL;
navigation.http_status_code_ = test_data::kHttpStatusCode;
+ navigation.password_state_ = test_data::kPasswordState;
+
+ navigation.extended_info_map_[test_data::kExtendedInfoKey1] =
+ test_data::kExtendedInfoValue1;
+ navigation.extended_info_map_[test_data::kExtendedInfoKey2] =
+ test_data::kExtendedInfoValue2;
navigation.redirect_chain_.push_back(test_data::kRedirectURL0);
navigation.redirect_chain_.push_back(test_data::kRedirectURL1);
diff --git a/chromium/components/sessions/core/serialized_navigation_entry_test_helper.h b/chromium/components/sessions/core/serialized_navigation_entry_test_helper.h
index ca415e12906..880f07b94c8 100644
--- a/chromium/components/sessions/core/serialized_navigation_entry_test_helper.h
+++ b/chromium/components/sessions/core/serialized_navigation_entry_test_helper.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
+#include "components/sessions/core/serialized_navigation_entry.h"
#include "ui/base/page_transition_types.h"
class GURL;
@@ -46,6 +47,11 @@ extern const GURL kRedirectURL0;
extern const GURL kRedirectURL1;
extern const GURL kOtherURL;
extern const int kPageID;
+extern const SerializedNavigationEntry::PasswordState kPasswordState;
+extern const std::string kExtendedInfoKey1;
+extern const std::string kExtendedInfoKey2;
+extern const std::string kExtendedInfoValue1;
+extern const std::string kExtendedInfoValue2;
} // namespace test_data
diff --git a/chromium/components/sessions/core/serialized_navigation_entry_unittest.cc b/chromium/components/sessions/core/serialized_navigation_entry_unittest.cc
index be70f9d2c1b..3f94c108994 100644
--- a/chromium/components/sessions/core/serialized_navigation_entry_unittest.cc
+++ b/chromium/components/sessions/core/serialized_navigation_entry_unittest.cc
@@ -17,8 +17,8 @@
#include "base/time/time.h"
#include "components/sessions/core/serialized_navigation_driver.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
-#include "sync/protocol/session_specifics.pb.h"
-#include "sync/util/time.h"
+#include "components/sync/base/time.h"
+#include "components/sync/protocol/session_specifics.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
@@ -132,6 +132,18 @@ TEST(SerializedNavigationEntryTest, Pickle) {
EXPECT_EQ(test_data::kSearchTerms, new_navigation.search_terms());
EXPECT_EQ(test_data::kHttpStatusCode, new_navigation.http_status_code());
+ ASSERT_EQ(2U, new_navigation.extended_info_map().size());
+ ASSERT_EQ(1U, new_navigation.extended_info_map().count(
+ test_data::kExtendedInfoKey1));
+ EXPECT_EQ(
+ test_data::kExtendedInfoValue1,
+ new_navigation.extended_info_map().at(test_data::kExtendedInfoKey1));
+ ASSERT_EQ(1U, new_navigation.extended_info_map().count(
+ test_data::kExtendedInfoKey2));
+ EXPECT_EQ(
+ test_data::kExtendedInfoValue2,
+ new_navigation.extended_info_map().at(test_data::kExtendedInfoKey2));
+
// Fields that are not written to the pickle.
EXPECT_EQ(0, new_navigation.unique_id());
EXPECT_EQ(std::string(), new_navigation.encoded_page_state());
diff --git a/chromium/components/sessions/core/session_backend.cc b/chromium/components/sessions/core/session_backend.cc
index 00eec4af0d9..4b0cbe76bd4 100644
--- a/chromium/components/sessions/core/session_backend.cc
+++ b/chromium/components/sessions/core/session_backend.cc
@@ -12,7 +12,7 @@
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/memory/scoped_vector.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
diff --git a/chromium/components/sessions/core/session_backend_unittest.cc b/chromium/components/sessions/core/session_backend_unittest.cc
index c59ca27f714..76f0950dd0b 100644
--- a/chromium/components/sessions/core/session_backend_unittest.cc
+++ b/chromium/components/sessions/core/session_backend_unittest.cc
@@ -40,7 +40,7 @@ class SessionBackendTest : public testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- path_ = temp_dir_.path().Append(FILE_PATH_LITERAL("SessionTestDirs"));
+ path_ = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("SessionTestDirs"));
base::CreateDirectory(path_);
}
diff --git a/chromium/components/sessions/core/session_service_commands.cc b/chromium/components/sessions/core/session_service_commands.cc
index 29b2f28a802..9e506ee1123 100644
--- a/chromium/components/sessions/core/session_service_commands.cc
+++ b/chromium/components/sessions/core/session_service_commands.cc
@@ -6,9 +6,11 @@
#include <stdint.h>
#include <string.h>
+
#include <utility>
#include <vector>
+#include "base/memory/ptr_util.h"
#include "base/pickle.h"
#include "components/sessions/core/base_session_service_commands.h"
#include "components/sessions/core/base_session_service_delegate.h"
@@ -72,24 +74,24 @@ struct WindowBoundsPayload3 {
int32_t show_state;
};
-typedef SessionID::id_type ActiveWindowPayload;
+using ActiveWindowPayload = SessionID::id_type;
struct IDAndIndexPayload {
SessionID::id_type id;
int32_t index;
};
-typedef IDAndIndexPayload TabIndexInWindowPayload;
+using TabIndexInWindowPayload = IDAndIndexPayload;
-typedef IDAndIndexPayload TabNavigationPathPrunedFromBackPayload;
+using TabNavigationPathPrunedFromBackPayload = IDAndIndexPayload;
-typedef IDAndIndexPayload SelectedNavigationIndexPayload;
+using SelectedNavigationIndexPayload = IDAndIndexPayload;
-typedef IDAndIndexPayload SelectedTabInIndexPayload;
+using SelectedTabInIndexPayload = IDAndIndexPayload;
-typedef IDAndIndexPayload WindowTypePayload;
+using WindowTypePayload = IDAndIndexPayload;
-typedef IDAndIndexPayload TabNavigationPathPrunedFromFrontPayload;
+using TabNavigationPathPrunedFromFrontPayload = IDAndIndexPayload;
struct PinnedStatePayload {
SessionID::id_type tab_id;
@@ -115,8 +117,10 @@ enum PersistedWindowShowState {
PERSISTED_SHOW_STATE_END = 7
};
-typedef std::map<SessionID::id_type, SessionTab*> IdToSessionTab;
-typedef std::map<SessionID::id_type, SessionWindow*> IdToSessionWindow;
+using IdToSessionTab =
+ std::map<SessionID::id_type, std::unique_ptr<SessionTab>>;
+using IdToSessionWindow =
+ std::map<SessionID::id_type, std::unique_ptr<SessionWindow>>;
// Assert to ensure PersistedWindowShowState is updated if ui::WindowShowState
// is changed.
@@ -172,19 +176,18 @@ ui::WindowShowState PersistedShowStateToShowState(int state) {
// Iterates through the vector updating the selected_tab_index of each
// SessionWindow based on the actual tabs that were restored.
-void UpdateSelectedTabIndex(std::vector<SessionWindow*>* windows) {
- for (std::vector<SessionWindow*>::const_iterator i = windows->begin();
- i != windows->end(); ++i) {
+void UpdateSelectedTabIndex(
+ std::vector<std::unique_ptr<SessionWindow>>* windows) {
+ for (auto& window : *windows) {
// See note in SessionWindow as to why we do this.
int new_index = 0;
- for (std::vector<SessionTab*>::const_iterator j = (*i)->tabs.begin();
- j != (*i)->tabs.end(); ++j) {
- if ((*j)->tab_visual_index == (*i)->selected_tab_index) {
- new_index = static_cast<int>(j - (*i)->tabs.begin());
+ for (auto j = window->tabs.begin(); j != window->tabs.end(); ++j) {
+ if ((*j)->tab_visual_index == window->selected_tab_index) {
+ new_index = static_cast<int>(j - window->tabs.begin());
break;
}
}
- (*i)->selected_tab_index = new_index;
+ window->selected_tab_index = new_index;
}
}
@@ -192,28 +195,28 @@ void UpdateSelectedTabIndex(std::vector<SessionWindow*>* windows) {
// not exist, one is created.
SessionWindow* GetWindow(SessionID::id_type window_id,
IdToSessionWindow* windows) {
- std::map<int, SessionWindow*>::iterator i = windows->find(window_id);
+ auto i = windows->find(window_id);
if (i == windows->end()) {
SessionWindow* window = new SessionWindow();
window->window_id.set_id(window_id);
- (*windows)[window_id] = window;
+ (*windows)[window_id] = base::WrapUnique(window);
return window;
}
- return i->second;
+ return i->second.get();
}
// Returns the tab with the specified id in tabs. If a tab does not exist,
// it is created.
SessionTab* GetTab(SessionID::id_type tab_id, IdToSessionTab* tabs) {
DCHECK(tabs);
- std::map<int, SessionTab*>::iterator i = tabs->find(tab_id);
+ auto i = tabs->find(tab_id);
if (i == tabs->end()) {
SessionTab* tab = new SessionTab();
tab->tab_id.set_id(tab_id);
- (*tabs)[tab_id] = tab;
+ (*tabs)[tab_id] = base::WrapUnique(tab);
return tab;
}
- return i->second;
+ return i->second.get();
}
// Returns an iterator into navigations pointing to the navigation whose
@@ -226,8 +229,7 @@ std::vector<sessions::SerializedNavigationEntry>::iterator
std::vector<sessions::SerializedNavigationEntry>* navigations,
int index) {
DCHECK(navigations);
- for (std::vector<sessions::SerializedNavigationEntry>::iterator
- i = navigations->begin(); i != navigations->end(); ++i) {
+ for (auto i = navigations->begin(); i != navigations->end(); ++i) {
if (i->index() >= index)
return i;
}
@@ -237,14 +239,14 @@ std::vector<sessions::SerializedNavigationEntry>::iterator
// Function used in sorting windows. Sorting is done based on window id. As
// window ids increment for each new window, this effectively sorts by creation
// time.
-static bool WindowOrderSortFunction(const SessionWindow* w1,
- const SessionWindow* w2) {
+static bool WindowOrderSortFunction(const std::unique_ptr<SessionWindow>& w1,
+ const std::unique_ptr<SessionWindow>& w2) {
return w1->window_id.id() < w2->window_id.id();
}
// Compares the two tabs based on visual index.
-static bool TabVisualIndexSortFunction(const SessionTab* t1,
- const SessionTab* t2) {
+static bool TabVisualIndexSortFunction(const std::unique_ptr<SessionTab>& t1,
+ const std::unique_ptr<SessionTab>& t2) {
const int delta = t1->tab_visual_index - t2->tab_visual_index;
return delta == 0 ? (t1->tab_id.id() < t2->tab_id.id()) : (delta < 0);
}
@@ -253,66 +255,65 @@ static bool TabVisualIndexSortFunction(const SessionTab* t1,
// . Deletes and removes any windows with no tabs. NOTE: constrained windows
// that have been dragged out are of type browser. As such, this preserves any
// dragged out constrained windows (aka popups that have been dragged out).
-// . Sorts the tabs in windows with valid tabs based on the tabs
-// visual order, and adds the valid windows to windows.
-void SortTabsBasedOnVisualOrderAndPrune(
- std::map<int, SessionWindow*>* windows,
- std::vector<SessionWindow*>* valid_windows) {
- std::map<int, SessionWindow*>::iterator i = windows->begin();
- while (i != windows->end()) {
- SessionWindow* window = i->second;
+// . Sorts the tabs in windows with valid tabs based on the tabs;
+// visual order, and adds the valid windows to |valid_windows|.
+void SortTabsBasedOnVisualOrderAndClear(
+ IdToSessionWindow* windows,
+ std::vector<std::unique_ptr<SessionWindow>>* valid_windows) {
+ for (auto& window_pair : *windows) {
+ std::unique_ptr<SessionWindow> window = std::move(window_pair.second);
if (window->tabs.empty() || window->is_constrained) {
- delete window;
- windows->erase(i++);
+ continue;
} else {
// Valid window; sort the tabs and add it to the list of valid windows.
std::sort(window->tabs.begin(), window->tabs.end(),
&TabVisualIndexSortFunction);
- // Otherwise, add the window such that older windows appear first.
+ // Add the window such that older windows appear first.
if (valid_windows->empty()) {
- valid_windows->push_back(window);
+ valid_windows->push_back(std::move(window));
} else {
valid_windows->insert(
std::upper_bound(valid_windows->begin(), valid_windows->end(),
window, &WindowOrderSortFunction),
- window);
+ std::move(window));
}
- ++i;
}
}
+
+ // There are no more pointers left in |window|, just empty husks from the
+ // move, so clear it out.
+ windows->clear();
}
// Adds tabs to their parent window based on the tab's window_id. This
// ignores tabs with no navigations.
-void AddTabsToWindows(std::map<int, SessionTab*>* tabs,
- std::map<int, SessionWindow*>* windows) {
- DVLOG(1) << "AddTabsToWindws";
+void AddTabsToWindows(IdToSessionTab* tabs, IdToSessionWindow* windows) {
+ DVLOG(1) << "AddTabsToWindows";
DVLOG(1) << "Tabs " << tabs->size() << ", windows " << windows->size();
- std::map<int, SessionTab*>::iterator i = tabs->begin();
- while (i != tabs->end()) {
- SessionTab* tab = i->second;
- if (tab->window_id.id() && !tab->navigations.empty()) {
- SessionWindow* window = GetWindow(tab->window_id.id(), windows);
- window->tabs.push_back(tab);
- tabs->erase(i++);
-
- // See note in SessionTab as to why we do this.
- std::vector<sessions::SerializedNavigationEntry>::iterator j =
- FindClosestNavigationWithIndex(&(tab->navigations),
- tab->current_navigation_index);
- if (j == tab->navigations.end()) {
- tab->current_navigation_index =
- static_cast<int>(tab->navigations.size() - 1);
- } else {
- tab->current_navigation_index =
- static_cast<int>(j - tab->navigations.begin());
- }
+ for (auto& tab_pair : *tabs) {
+ std::unique_ptr<SessionTab> tab = std::move(tab_pair.second);
+ if (!tab->window_id.id() || tab->navigations.empty())
+ continue;
+
+ SessionTab* tab_ptr = tab.get();
+ SessionWindow* window = GetWindow(tab_ptr->window_id.id(), windows);
+ window->tabs.push_back(std::move(tab));
+
+ // See note in SessionTab as to why we do this.
+ auto j = FindClosestNavigationWithIndex(&tab_ptr->navigations,
+ tab_ptr->current_navigation_index);
+ if (j == tab_ptr->navigations.end()) {
+ tab_ptr->current_navigation_index =
+ static_cast<int>(tab_ptr->navigations.size() - 1);
} else {
- // Never got a set tab index in window, or tabs are empty, nothing
- // to do.
- ++i;
+ tab_ptr->current_navigation_index =
+ static_cast<int>(j - tab_ptr->navigations.begin());
}
}
+
+ // There are no more pointers left in |tabs|, just empty husks from the
+ // move, so clear it out.
+ tabs->clear();
}
// Creates tabs and windows from the commands specified in |data|. The created
@@ -323,15 +324,14 @@ void AddTabsToWindows(std::map<int, SessionTab*>* tabs,
// This does NOT add any created SessionTabs to SessionWindow.tabs, that is
// done by AddTabsToWindows.
bool CreateTabsAndWindows(const ScopedVector<SessionCommand>& data,
- std::map<int, SessionTab*>* tabs,
- std::map<int, SessionWindow*>* windows,
+ IdToSessionTab* tabs,
+ IdToSessionWindow* windows,
SessionID::id_type* active_window_id) {
// If the file is corrupt (command with wrong size, or unknown command), we
// still return true and attempt to restore what we we can.
DVLOG(1) << "CreateTabsAndWindows";
- for (std::vector<SessionCommand*>::const_iterator i = data.begin();
- i != data.end(); ++i) {
+ for (auto i = data.begin(); i != data.end(); ++i) {
const SessionCommand::id_type kCommandSetWindowBounds2 = 10;
const SessionCommand* command = *i;
@@ -397,13 +397,11 @@ bool CreateTabsAndWindows(const ScopedVector<SessionCommand>& data,
DVLOG(1) << "Failed reading command " << command->id();
return true;
}
- if (command->id() == kCommandTabClosed) {
- delete GetTab(payload.id, tabs);
+ if (command->id() == kCommandTabClosed)
tabs->erase(payload.id);
- } else {
- delete GetWindow(payload.id, windows);
+ else
windows->erase(payload.id);
- }
+
break;
}
@@ -434,9 +432,7 @@ bool CreateTabsAndWindows(const ScopedVector<SessionCommand>& data,
std::max(-1, tab->current_navigation_index - payload.index);
// And update the index of existing navigations.
- for (std::vector<sessions::SerializedNavigationEntry>::iterator
- i = tab->navigations.begin();
- i != tab->navigations.end();) {
+ for (auto i = tab->navigations.begin(); i != tab->navigations.end();) {
i->set_index(i->index() - payload.index);
if (i->index() < 0)
i = tab->navigations.erase(i);
@@ -456,9 +452,8 @@ bool CreateTabsAndWindows(const ScopedVector<SessionCommand>& data,
return true;
}
SessionTab* tab = GetTab(tab_id, tabs);
- std::vector<sessions::SerializedNavigationEntry>::iterator i =
- FindClosestNavigationWithIndex(&(tab->navigations),
- navigation.index());
+ auto i = FindClosestNavigationWithIndex(&(tab->navigations),
+ navigation.index());
if (i != tab->navigations.end() && i->index() == navigation.index())
*i = navigation;
else
@@ -614,8 +609,8 @@ std::unique_ptr<SessionCommand> CreateSetSelectedTabInWindowCommand(
SelectedTabInIndexPayload payload = { 0 };
payload.id = window_id.id();
payload.index = index;
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandSetSelectedTabInIndex, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command = base::MakeUnique<SessionCommand>(
+ kCommandSetSelectedTabInIndex, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -624,8 +619,8 @@ std::unique_ptr<SessionCommand> CreateSetTabWindowCommand(
const SessionID& window_id,
const SessionID& tab_id) {
SessionID::id_type payload[] = { window_id.id(), tab_id.id() };
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandSetTabWindow, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command =
+ base::MakeUnique<SessionCommand>(kCommandSetTabWindow, sizeof(payload));
memcpy(command->contents(), payload, sizeof(payload));
return command;
}
@@ -641,8 +636,8 @@ std::unique_ptr<SessionCommand> CreateSetWindowBoundsCommand(
payload.w = bounds.width();
payload.h = bounds.height();
payload.show_state = ShowStateToPersistedShowState(show_state);
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandSetWindowBounds3, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command = base::MakeUnique<SessionCommand>(
+ kCommandSetWindowBounds3, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -653,8 +648,8 @@ std::unique_ptr<SessionCommand> CreateSetTabIndexInWindowCommand(
TabIndexInWindowPayload payload = { 0 };
payload.id = tab_id.id();
payload.index = new_index;
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandSetTabIndexInWindow, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command = base::MakeUnique<SessionCommand>(
+ kCommandSetTabIndexInWindow, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -668,8 +663,8 @@ std::unique_ptr<SessionCommand> CreateTabClosedCommand(
memset(&payload, 0, sizeof(payload));
payload.id = tab_id;
payload.close_time = base::Time::Now().ToInternalValue();
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandTabClosed, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command =
+ base::MakeUnique<SessionCommand>(kCommandTabClosed, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -681,8 +676,8 @@ std::unique_ptr<SessionCommand> CreateWindowClosedCommand(
memset(&payload, 0, sizeof(payload));
payload.id = window_id;
payload.close_time = base::Time::Now().ToInternalValue();
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandWindowClosed, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command =
+ base::MakeUnique<SessionCommand>(kCommandWindowClosed, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -693,8 +688,8 @@ std::unique_ptr<SessionCommand> CreateSetSelectedNavigationIndexCommand(
SelectedNavigationIndexPayload payload = { 0 };
payload.id = tab_id.id();
payload.index = index;
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandSetSelectedNavigationIndex, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command = base::MakeUnique<SessionCommand>(
+ kCommandSetSelectedNavigationIndex, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -705,8 +700,8 @@ std::unique_ptr<SessionCommand> CreateSetWindowTypeCommand(
WindowTypePayload payload = { 0 };
payload.id = window_id.id();
payload.index = static_cast<int32_t>(type);
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandSetWindowType, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command =
+ base::MakeUnique<SessionCommand>(kCommandSetWindowType, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -717,8 +712,8 @@ std::unique_ptr<SessionCommand> CreatePinnedStateCommand(
PinnedStatePayload payload = { 0 };
payload.tab_id = tab_id.id();
payload.pinned_state = is_pinned;
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandSetPinnedState, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command =
+ base::MakeUnique<SessionCommand>(kCommandSetPinnedState, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -729,16 +724,16 @@ std::unique_ptr<SessionCommand> CreateSessionStorageAssociatedCommand(
base::Pickle pickle;
pickle.WriteInt(tab_id.id());
pickle.WriteString(session_storage_persistent_id);
- return std::unique_ptr<SessionCommand>(
- new SessionCommand(kCommandSessionStorageAssociated, pickle));
+ return std::unique_ptr<SessionCommand>(base::MakeUnique<SessionCommand>(
+ kCommandSessionStorageAssociated, pickle));
}
std::unique_ptr<SessionCommand> CreateSetActiveWindowCommand(
const SessionID& window_id) {
ActiveWindowPayload payload = 0;
payload = window_id.id();
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandSetActiveWindow, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command = base::MakeUnique<SessionCommand>(
+ kCommandSetActiveWindow, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -749,8 +744,8 @@ std::unique_ptr<SessionCommand> CreateLastActiveTimeCommand(
LastActiveTimePayload payload = {0};
payload.tab_id = tab_id.id();
payload.last_active_time = last_active_time.ToInternalValue();
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandLastActiveTime, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command =
+ base::MakeUnique<SessionCommand>(kCommandLastActiveTime, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -761,8 +756,8 @@ std::unique_ptr<SessionCommand> CreateSetWindowWorkspaceCommand(
base::Pickle pickle;
pickle.WriteInt(window_id.id());
pickle.WriteString(workspace);
- std::unique_ptr<SessionCommand> command(
- new SessionCommand(kCommandSetWindowWorkspace2, pickle));
+ std::unique_ptr<SessionCommand> command =
+ base::MakeUnique<SessionCommand>(kCommandSetWindowWorkspace2, pickle);
return command;
}
@@ -772,8 +767,8 @@ std::unique_ptr<SessionCommand> CreateTabNavigationPathPrunedFromBackCommand(
TabNavigationPathPrunedFromBackPayload payload = { 0 };
payload.id = tab_id.id();
payload.index = count;
- std::unique_ptr<SessionCommand> command(new SessionCommand(
- kCommandTabNavigationPathPrunedFromBack, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command = base::MakeUnique<SessionCommand>(
+ kCommandTabNavigationPathPrunedFromBack, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -784,8 +779,8 @@ std::unique_ptr<SessionCommand> CreateTabNavigationPathPrunedFromFrontCommand(
TabNavigationPathPrunedFromFrontPayload payload = { 0 };
payload.id = tab_id.id();
payload.index = count;
- std::unique_ptr<SessionCommand> command(new SessionCommand(
- kCommandTabNavigationPathPrunedFromFront, sizeof(payload)));
+ std::unique_ptr<SessionCommand> command = base::MakeUnique<SessionCommand>(
+ kCommandTabNavigationPathPrunedFromFront, sizeof(payload));
memcpy(command->contents(), &payload, sizeof(payload));
return command;
}
@@ -885,21 +880,23 @@ bool IsClosingCommand(SessionCommand* command) {
command->id() == kCommandWindowClosed;
}
-void RestoreSessionFromCommands(const ScopedVector<SessionCommand>& commands,
- std::vector<SessionWindow*>* valid_windows,
- SessionID::id_type* active_window_id) {
- std::map<int, SessionTab*> tabs;
- std::map<int, SessionWindow*> windows;
+void RestoreSessionFromCommands(
+ const ScopedVector<SessionCommand>& commands,
+ std::vector<std::unique_ptr<SessionWindow>>* valid_windows,
+ SessionID::id_type* active_window_id) {
+ IdToSessionTab tabs;
+ IdToSessionWindow windows;
DVLOG(1) << "RestoreSessionFromCommands " << commands.size();
if (CreateTabsAndWindows(commands, &tabs, &windows, active_window_id)) {
AddTabsToWindows(&tabs, &windows);
- SortTabsBasedOnVisualOrderAndPrune(&windows, valid_windows);
+ SortTabsBasedOnVisualOrderAndClear(&windows, valid_windows);
UpdateSelectedTabIndex(valid_windows);
}
- STLDeleteValues(&tabs);
- // Don't delete contents of windows, that is done by the caller as all
- // valid windows are added to valid_windows.
+ // AddTabsToWindows should have processed all the tabs.
+ DCHECK_EQ(0u, tabs.size());
+ // SortTabsBasedOnVisualOrderAndClear should have processed all the windows.
+ DCHECK_EQ(0u, windows.size());
}
} // namespace sessions
diff --git a/chromium/components/sessions/core/session_service_commands.h b/chromium/components/sessions/core/session_service_commands.h
index 495743f12e1..7d0f80988d1 100644
--- a/chromium/components/sessions/core/session_service_commands.h
+++ b/chromium/components/sessions/core/session_service_commands.h
@@ -6,10 +6,10 @@
#define COMPONENTS_SESSIONS_CORE_SESSION_SERVICE_COMMANDS_H_
#include <map>
+#include <memory>
#include <string>
#include "base/callback.h"
-#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/task/cancelable_task_tracker.h"
#include "components/sessions/core/base_session_service.h"
@@ -92,13 +92,12 @@ SESSIONS_EXPORT bool ReplacePendingCommand(
SESSIONS_EXPORT bool IsClosingCommand(SessionCommand* command);
// Converts a list of commands into SessionWindows. On return any valid
-// windows are added to valid_windows. It is up to the caller to delete
-// the windows added to valid_windows. |active_window_id| will be set with the
+// windows are added to |valid_windows|. |active_window_id| will be set with the
// id of the last active window, but it's only valid when this id corresponds
-// to the id of one of the windows in valid_windows.
+// to the id of one of the windows in |valid_windows|.
SESSIONS_EXPORT void RestoreSessionFromCommands(
const ScopedVector<SessionCommand>& commands,
- std::vector<SessionWindow*>* valid_windows,
+ std::vector<std::unique_ptr<SessionWindow>>* valid_windows,
SessionID::id_type* active_window_id);
} // namespace sessions
diff --git a/chromium/components/sessions/core/session_types.cc b/chromium/components/sessions/core/session_types.cc
index df2ae12199d..db020bf0b83 100644
--- a/chromium/components/sessions/core/session_types.cc
+++ b/chromium/components/sessions/core/session_types.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include "base/stl_util.h"
#include "components/sessions/core/session_command.h"
namespace sessions {
@@ -70,9 +69,7 @@ SessionWindow::SessionWindow()
is_constrained(true),
show_state(ui::SHOW_STATE_DEFAULT) {}
-SessionWindow::~SessionWindow() {
- STLDeleteElements(&tabs);
-}
+SessionWindow::~SessionWindow() {}
sync_pb::SessionWindow SessionWindow::ToSyncData() const {
sync_pb::SessionWindow sync_data;
@@ -91,8 +88,8 @@ sync_pb::SessionWindow SessionWindow::ToSyncData() const {
NOTREACHED() << "Unhandled browser type.";
}
- for (size_t i = 0; i < tabs.size(); i++)
- sync_data.add_tab(tabs[i]->tab_id.id());
+ for (const auto& tab : tabs)
+ sync_data.add_tab(tab->tab_id.id());
return sync_data;
}
diff --git a/chromium/components/sessions/core/session_types.h b/chromium/components/sessions/core/session_types.h
index f7de29254d7..92839c785b0 100644
--- a/chromium/components/sessions/core/session_types.h
+++ b/chromium/components/sessions/core/session_types.h
@@ -16,8 +16,8 @@
#include "components/sessions/core/serialized_navigation_entry.h"
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/sessions_export.h"
+#include "components/sync/protocol/session_specifics.pb.h"
#include "components/variations/variations_associated_data.h"
-#include "sync/protocol/session_specifics.pb.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
@@ -62,7 +62,7 @@ struct SESSIONS_EXPORT SessionTab {
// Unique id of the window.
SessionID window_id;
- // Unique if of the tab.
+ // Unique id of the tab.
SessionID tab_id;
// Visual index of the tab within its window. There may be gaps in these
@@ -166,7 +166,7 @@ struct SESSIONS_EXPORT SessionWindow {
base::Time timestamp;
// The tabs, ordered by visual order.
- std::vector<SessionTab*> tabs;
+ std::vector<std::unique_ptr<SessionTab>> tabs;
// Is the window maximized, minimized, or normal?
ui::WindowShowState show_state;
diff --git a/chromium/components/sessions/core/session_types_unittest.cc b/chromium/components/sessions/core/session_types_unittest.cc
index c7e09439f4e..e7ef985bf58 100644
--- a/chromium/components/sessions/core/session_types_unittest.cc
+++ b/chromium/components/sessions/core/session_types_unittest.cc
@@ -11,8 +11,8 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
-#include "sync/protocol/session_specifics.pb.h"
-#include "sync/util/time.h"
+#include "components/sync/base/time.h"
+#include "components/sync/protocol/session_specifics.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
diff --git a/chromium/components/sessions/core/tab_restore_service.cc b/chromium/components/sessions/core/tab_restore_service.cc
index a69dc3d22ec..8bf31952e70 100644
--- a/chromium/components/sessions/core/tab_restore_service.cc
+++ b/chromium/components/sessions/core/tab_restore_service.cc
@@ -15,67 +15,14 @@ TabRestoreService::TimeFactory::~TimeFactory() {}
// ID of the next Entry.
static SessionID::id_type next_entry_id = 1;
-TabRestoreService::Entry::Entry()
- : id(next_entry_id++),
- type(TAB),
- from_last_session(false) {}
+TabRestoreService::Entry::~Entry() = default;
+TabRestoreService::Entry::Entry(Type type) : id(next_entry_id++), type(type) {}
-TabRestoreService::Entry::Entry(Type type)
- : id(next_entry_id++),
- type(type),
- from_last_session(false) {}
+TabRestoreService::Tab::Tab() : Entry(TAB) {}
+TabRestoreService::Tab::~Tab() = default;
-TabRestoreService::Entry::~Entry() {}
-
-// Tab ------------------------------------------------------------------------
-
-TabRestoreService::Tab::Tab()
- : Entry(TAB),
- current_navigation_index(-1),
- browser_id(0),
- tabstrip_index(-1),
- pinned(false) {
-}
-
-TabRestoreService::Tab::Tab(const TabRestoreService::Tab& tab)
- : Entry(TAB),
- navigations(tab.navigations),
- current_navigation_index(tab.current_navigation_index),
- browser_id(tab.browser_id),
- tabstrip_index(tab.tabstrip_index),
- pinned(tab.pinned),
- extension_app_id(tab.extension_app_id),
- user_agent_override(tab.user_agent_override) {
- if (tab.platform_data)
- platform_data = tab.platform_data->Clone();
-}
-
-TabRestoreService::Tab::~Tab() {
-}
-
-TabRestoreService::Tab& TabRestoreService::Tab::operator=(
- const TabRestoreService::Tab& tab) {
- navigations = tab.navigations;
- current_navigation_index = tab.current_navigation_index;
- browser_id = tab.browser_id;
- tabstrip_index = tab.tabstrip_index;
- pinned = tab.pinned;
- extension_app_id = tab.extension_app_id;
- user_agent_override = tab.user_agent_override;
-
- if (tab.platform_data)
- platform_data = tab.platform_data->Clone();
-
- return *this;
-}
-
-// Window ---------------------------------------------------------------------
-
-TabRestoreService::Window::Window() : Entry(WINDOW), selected_tab_index(-1) {
-}
-
-TabRestoreService::Window::~Window() {
-}
+TabRestoreService::Window::Window() : Entry(WINDOW) {}
+TabRestoreService::Window::~Window() = default;
// TabRestoreService ----------------------------------------------------------
diff --git a/chromium/components/sessions/core/tab_restore_service.h b/chromium/components/sessions/core/tab_restore_service.h
index f9eda99c3c0..a851f813e57 100644
--- a/chromium/components/sessions/core/tab_restore_service.h
+++ b/chromium/components/sessions/core/tab_restore_service.h
@@ -52,8 +52,6 @@ class SESSIONS_EXPORT TabRestoreService : public KeyedService {
};
struct SESSIONS_EXPORT Entry {
- Entry();
- explicit Entry(Type type);
virtual ~Entry();
// Unique id for this entry. The id is guaranteed to be unique for a
@@ -61,7 +59,7 @@ class SESSIONS_EXPORT TabRestoreService : public KeyedService {
SessionID::id_type id;
// The type of the entry.
- Type type;
+ const Type type;
// The time when the window or tab was closed.
base::Time timestamp;
@@ -69,34 +67,35 @@ class SESSIONS_EXPORT TabRestoreService : public KeyedService {
// Is this entry from the last session? This is set to true for entries that
// were closed during the last session, and false for entries that were
// closed during this session.
- bool from_last_session;
+ bool from_last_session = false;
+
+ protected:
+ explicit Entry(Type type);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Entry);
};
// Represents a previously open tab.
struct SESSIONS_EXPORT Tab : public Entry {
Tab();
- Tab(const Tab& tab);
~Tab() override;
- Tab& operator=(const Tab& tab);
-
- bool has_browser() const { return browser_id > 0; }
-
// The navigations.
std::vector<SerializedNavigationEntry> navigations;
// Index of the selected navigation in navigations.
- int current_navigation_index;
+ int current_navigation_index = -1;
// The ID of the browser to which this tab belonged, so it can be restored
// there. May be 0 (an invalid SessionID) when restoring an entire session.
- SessionID::id_type browser_id;
+ SessionID::id_type browser_id = 0;
// Index within the tab strip. May be -1 for an unknown index.
- int tabstrip_index;
+ int tabstrip_index = -1;
// True if the tab was pinned.
- bool pinned;
+ bool pinned = false;
// If non-empty gives the id of the extension for the tab.
std::string extension_app_id;
@@ -114,16 +113,16 @@ class SESSIONS_EXPORT TabRestoreService : public KeyedService {
~Window() override;
// The tabs that comprised the window, in order.
- std::vector<Tab> tabs;
+ std::vector<std::unique_ptr<Tab>> tabs;
// Index of the selected tab.
- int selected_tab_index;
+ int selected_tab_index = -1;
// If an application window, the name of the app.
std::string app_name;
};
- typedef std::list<Entry*> Entries;
+ typedef std::list<std::unique_ptr<Entry>> Entries;
~TabRestoreService() override;
@@ -160,9 +159,8 @@ class SESSIONS_EXPORT TabRestoreService : public KeyedService {
virtual std::vector<LiveTab*> RestoreMostRecentEntry(
LiveTabContext* context) = 0;
- // Removes the Tab with id |id| from the list and returns it; ownership is
- // passed to the caller.
- virtual Tab* RemoveTabEntryById(SessionID::id_type id) = 0;
+ // Removes the Tab with id |id| from the list and returns it.
+ virtual std::unique_ptr<Tab> RemoveTabEntryById(SessionID::id_type id) = 0;
// Restores an entry by id. If there is no entry with an id matching |id|,
// this does nothing. If |context| is NULL, this creates a new window for the
@@ -184,20 +182,16 @@ class SESSIONS_EXPORT TabRestoreService : public KeyedService {
// Deletes the last session.
virtual void DeleteLastSession() = 0;
+
+ // Returns true if we're in the process of restoring some entries.
+ virtual bool IsRestoring() const = 0;
};
// A class that is used to associate platform-specific data with
// TabRestoreService::Tab. See LiveTab::GetPlatformSpecificTabData().
-// Subclasses of this class must be copyable by implementing the Clone() method
-// for usage by the Tab struct, which is itself copyable and assignable.
class SESSIONS_EXPORT PlatformSpecificTabData {
public:
virtual ~PlatformSpecificTabData();
-
- private:
- friend TabRestoreService::Tab;
-
- virtual std::unique_ptr<PlatformSpecificTabData> Clone() = 0;
};
} // namespace sessions
diff --git a/chromium/components/sessions/core/tab_restore_service_client.h b/chromium/components/sessions/core/tab_restore_service_client.h
index 0d36c627068..d26f0f1a565 100644
--- a/chromium/components/sessions/core/tab_restore_service_client.h
+++ b/chromium/components/sessions/core/tab_restore_service_client.h
@@ -28,8 +28,9 @@ class LiveTabContext;
// Callback from TabRestoreServiceClient::GetLastSession.
// The second parameter is the id of the window that was last active.
-typedef base::Callback<void(ScopedVector<SessionWindow>, SessionID::id_type)>
- GetLastSessionCallback;
+using GetLastSessionCallback =
+ base::Callback<void(std::vector<std::unique_ptr<SessionWindow>>,
+ SessionID::id_type)>;
// A client interface that needs to be supplied to the tab restore service by
// the embedder.
diff --git a/chromium/components/sessions/core/tab_restore_service_helper.cc b/chromium/components/sessions/core/tab_restore_service_helper.cc
index f89946f240c..05094d2f7c9 100644
--- a/chromium/components/sessions/core/tab_restore_service_helper.cc
+++ b/chromium/components/sessions/core/tab_restore_service_helper.cc
@@ -10,6 +10,7 @@
#include <iterator>
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "components/sessions/core/live_tab.h"
@@ -52,7 +53,6 @@ TabRestoreServiceHelper::TabRestoreServiceHelper(
TabRestoreServiceHelper::~TabRestoreServiceHelper() {
FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
TabRestoreServiceDestroyed(tab_restore_service_));
- STLDeleteElements(&entries_);
}
void TabRestoreServiceHelper::AddObserver(
@@ -74,48 +74,39 @@ void TabRestoreServiceHelper::CreateHistoricalTab(LiveTab* live_tab,
if (closing_contexts_.find(context) != closing_contexts_.end())
return;
- std::unique_ptr<Tab> local_tab(new Tab());
+ auto local_tab = base::MakeUnique<Tab>();
PopulateTab(local_tab.get(), index, context, live_tab);
if (local_tab->navigations.empty())
return;
- AddEntry(local_tab.release(), true, true);
+ AddEntry(std::move(local_tab), true, true);
}
void TabRestoreServiceHelper::BrowserClosing(LiveTabContext* context) {
closing_contexts_.insert(context);
- std::unique_ptr<Window> window(new Window());
+ auto window = base::MakeUnique<Window>();
window->selected_tab_index = context->GetSelectedIndex();
window->timestamp = TimeNow();
window->app_name = context->GetAppName();
- // Don't use std::vector::resize() because it will push copies of an empty tab
- // into the vector, which will give all tabs in a window the same ID.
- for (int i = 0; i < context->GetTabCount(); ++i) {
- window->tabs.push_back(Tab());
- }
- size_t entry_index = 0;
for (int tab_index = 0; tab_index < context->GetTabCount(); ++tab_index) {
- PopulateTab(&(window->tabs[entry_index]), tab_index, context,
+ auto tab = base::MakeUnique<Tab>();
+ PopulateTab(tab.get(), tab_index, context,
context->GetLiveTabAt(tab_index));
- if (window->tabs[entry_index].navigations.empty()) {
- window->tabs.erase(window->tabs.begin() + entry_index);
- } else {
- window->tabs[entry_index].browser_id = context->GetSessionID().id();
- entry_index++;
+ if (!tab->navigations.empty()) {
+ tab->browser_id = context->GetSessionID().id();
+ window->tabs.push_back(std::move(tab));
}
}
if (window->tabs.size() == 1 && window->app_name.empty()) {
// Short-circuit creating a Window if only 1 tab was present. This fixes
- // http://crbug.com/56744. Copy the Tab because it's owned by an object on
- // the stack.
- AddEntry(new Tab(window->tabs[0]), true, true);
+ // http://crbug.com/56744.
+ AddEntry(std::move(window->tabs[0]), true, true);
} else if (!window->tabs.empty()) {
- window->selected_tab_index =
- std::min(static_cast<int>(window->tabs.size() - 1),
- window->selected_tab_index);
- AddEntry(window.release(), true, true);
+ window->selected_tab_index = std::min(
+ static_cast<int>(window->tabs.size() - 1), window->selected_tab_index);
+ AddEntry(std::move(window), true, true);
}
}
@@ -126,7 +117,7 @@ void TabRestoreServiceHelper::BrowserClosed(LiveTabContext* context) {
void TabRestoreServiceHelper::ClearEntries() {
if (observer_)
observer_->OnClearEntries();
- STLDeleteElements(&entries_);
+ entries_.clear();
NotifyTabsChanged();
}
@@ -138,22 +129,21 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreMostRecentEntry(
LiveTabContext* context) {
if (entries_.empty())
return std::vector<LiveTab*>();
-
- return RestoreEntryById(context, entries_.front()->id, UNKNOWN);
+ return RestoreEntryById(context, entries_.front()->id,
+ WindowOpenDisposition::UNKNOWN);
}
-TabRestoreService::Tab* TabRestoreServiceHelper::RemoveTabEntryById(
- SessionID::id_type id) {
- Entries::iterator i = GetEntryIteratorById(id);
- if (i == entries_.end())
- return NULL;
+std::unique_ptr<TabRestoreService::Tab>
+TabRestoreServiceHelper::RemoveTabEntryById(SessionID::id_type id) {
+ auto it = GetEntryIteratorById(id);
+ if (it == entries_.end())
+ return nullptr;
- Entry* entry = *i;
- if (entry->type != TabRestoreService::TAB)
- return NULL;
+ if ((*it)->type != TabRestoreService::TAB)
+ return nullptr;
- Tab* tab = static_cast<Tab*>(entry);
- entries_.erase(i);
+ auto tab = std::unique_ptr<Tab>(static_cast<Tab*>(it->release()));
+ entries_.erase(it);
return tab;
}
@@ -162,105 +152,107 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById(
SessionID::id_type id,
WindowOpenDisposition disposition) {
Entries::iterator entry_iterator = GetEntryIteratorById(id);
- if (entry_iterator == entries_.end())
+ if (entry_iterator == entries_.end()) {
// Don't hoark here, we allow an invalid id.
return std::vector<LiveTab*>();
+ }
if (observer_)
observer_->OnRestoreEntryById(id, entry_iterator);
restoring_ = true;
- Entry* entry = *entry_iterator;
+ auto& entry = **entry_iterator;
// If the entry's ID does not match the ID that is being restored, then the
// entry is a window from which a single tab will be restored.
- bool restoring_tab_in_window = entry->id != id;
-
- if (!restoring_tab_in_window) {
- entries_.erase(entry_iterator);
- entry_iterator = entries_.end();
- }
+ bool restoring_tab_in_window = entry.id != id;
// |context| will be NULL in cases where one isn't already available (eg,
// when invoked on Mac OS X with no windows open). In this case, create a
// new browser into which we restore the tabs.
std::vector<LiveTab*> live_tabs;
- if (entry->type == TabRestoreService::TAB) {
- Tab* tab = static_cast<Tab*>(entry);
- LiveTab* restored_tab = NULL;
- context = RestoreTab(*tab, context, disposition, &restored_tab);
- live_tabs.push_back(restored_tab);
- context->ShowBrowserWindow();
- } else if (entry->type == TabRestoreService::WINDOW) {
- LiveTabContext* current_context = context;
- Window* window = static_cast<Window*>(entry);
-
- // When restoring a window, either the entire window can be restored, or a
- // single tab within it. If the entry's ID matches the one to restore, then
- // the entire window will be restored.
- if (!restoring_tab_in_window) {
- context = client_->CreateLiveTabContext(window->app_name);
- for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) {
- const Tab& tab = window->tabs[tab_i];
- LiveTab* restored_tab = context->AddRestoredTab(
- tab.navigations, context->GetTabCount(),
- tab.current_navigation_index, tab.extension_app_id,
- static_cast<int>(tab_i) == window->selected_tab_index, tab.pinned,
- tab.from_last_session, tab.platform_data.get(),
- tab.user_agent_override);
- if (restored_tab) {
- restored_tab->LoadIfNecessary();
- client_->OnTabRestored(
- tab.navigations.at(tab.current_navigation_index).virtual_url());
- live_tabs.push_back(restored_tab);
+ switch (entry.type) {
+ case TabRestoreService::TAB: {
+ auto& tab = static_cast<const Tab&>(entry);
+ LiveTab* restored_tab = nullptr;
+ context = RestoreTab(tab, context, disposition, &restored_tab);
+ live_tabs.push_back(restored_tab);
+ context->ShowBrowserWindow();
+ break;
+ }
+ case TabRestoreService::WINDOW: {
+ LiveTabContext* current_context = context;
+ auto& window = static_cast<Window&>(entry);
+
+ // When restoring a window, either the entire window can be restored, or a
+ // single tab within it. If the entry's ID matches the one to restore,
+ // then the entire window will be restored.
+ if (!restoring_tab_in_window) {
+ context = client_->CreateLiveTabContext(window.app_name);
+ for (size_t tab_i = 0; tab_i < window.tabs.size(); ++tab_i) {
+ const Tab& tab = *window.tabs[tab_i];
+ LiveTab* restored_tab = context->AddRestoredTab(
+ tab.navigations, context->GetTabCount(),
+ tab.current_navigation_index, tab.extension_app_id,
+ static_cast<int>(tab_i) == window.selected_tab_index, tab.pinned,
+ tab.from_last_session, tab.platform_data.get(),
+ tab.user_agent_override);
+ if (restored_tab) {
+ restored_tab->LoadIfNecessary();
+ client_->OnTabRestored(
+ tab.navigations.at(tab.current_navigation_index).virtual_url());
+ live_tabs.push_back(restored_tab);
+ }
}
- }
- // All the window's tabs had the same former browser_id.
- if (window->tabs[0].has_browser()) {
- UpdateTabBrowserIDs(window->tabs[0].browser_id,
- context->GetSessionID().id());
- }
- } else {
- // Restore a single tab from the window. Find the tab that matches the ID
- // in the window and restore it.
- for (std::vector<Tab>::iterator tab_i = window->tabs.begin();
- tab_i != window->tabs.end(); ++tab_i) {
- const Tab& tab = *tab_i;
- if (tab.id == id) {
- LiveTab* restored_tab = NULL;
- context = RestoreTab(tab, context, disposition, &restored_tab);
- live_tabs.push_back(restored_tab);
- window->tabs.erase(tab_i);
+ // All the window's tabs had the same former browser_id.
+ if (auto browser_id = window.tabs[0]->browser_id) {
+ UpdateTabBrowserIDs(browser_id, context->GetSessionID().id());
+ }
+ } else {
+ // Restore a single tab from the window. Find the tab that matches the
+ // ID
+ // in the window and restore it.
+ for (auto tab_i = window.tabs.begin(); tab_i != window.tabs.end();
+ ++tab_i) {
+ SessionID::id_type restored_tab_browser_id;
+ {
+ const Tab& tab = **tab_i;
+ if (tab.id != id)
+ continue;
+
+ restored_tab_browser_id = tab.browser_id;
+ LiveTab* restored_tab = nullptr;
+ context = RestoreTab(tab, context, disposition, &restored_tab);
+ live_tabs.push_back(restored_tab);
+ window.tabs.erase(tab_i);
+ }
// If restoring the tab leaves the window with nothing else, delete it
// as well.
- if (!window->tabs.size()) {
+ if (window.tabs.empty()) {
entries_.erase(entry_iterator);
- delete entry;
} else {
// Update the browser ID of the rest of the tabs in the window so if
// any one is restored, it goes into the same window as the tab
// being restored now.
- UpdateTabBrowserIDs(tab.browser_id, context->GetSessionID().id());
- for (std::vector<Tab>::iterator tab_j = window->tabs.begin();
- tab_j != window->tabs.end(); ++tab_j) {
- (*tab_j).browser_id = context->GetSessionID().id();
- }
+ UpdateTabBrowserIDs(restored_tab_browser_id,
+ context->GetSessionID().id());
+ for (auto& tab_j : window.tabs)
+ tab_j->browser_id = context->GetSessionID().id();
}
break;
}
}
- }
- context->ShowBrowserWindow();
+ context->ShowBrowserWindow();
- if (disposition == CURRENT_TAB && current_context &&
- current_context->GetActiveLiveTab()) {
- current_context->CloseTab();
+ if (disposition == WindowOpenDisposition::CURRENT_TAB &&
+ current_context && current_context->GetActiveLiveTab()) {
+ current_context->CloseTab();
+ }
+ break;
}
- } else {
- NOTREACHED();
}
if (!restoring_tab_in_window) {
- delete entry;
+ entries_.erase(entry_iterator);
}
restoring_ = false;
@@ -268,6 +260,10 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById(
return live_tabs;
}
+bool TabRestoreServiceHelper::IsRestoring() const {
+ return restoring_;
+}
+
void TabRestoreServiceHelper::NotifyTabsChanged() {
FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
TabRestoreServiceChanged(tab_restore_service_));
@@ -278,18 +274,17 @@ void TabRestoreServiceHelper::NotifyLoaded() {
TabRestoreServiceLoaded(tab_restore_service_));
}
-void TabRestoreServiceHelper::AddEntry(Entry* entry,
+void TabRestoreServiceHelper::AddEntry(std::unique_ptr<Entry> entry,
bool notify,
bool to_front) {
- if (!FilterEntry(entry) || (entries_.size() >= kMaxEntries && !to_front)) {
- delete entry;
+ if (!FilterEntry(*entry) || (entries_.size() >= kMaxEntries && !to_front)) {
return;
}
if (to_front)
- entries_.push_front(entry);
+ entries_.push_front(std::move(entry));
else
- entries_.push_back(entry);
+ entries_.push_back(std::move(entry));
PruneEntries();
@@ -303,19 +298,13 @@ void TabRestoreServiceHelper::AddEntry(Entry* entry,
void TabRestoreServiceHelper::PruneEntries() {
Entries new_entries;
- for (TabRestoreService::Entries::const_iterator iter = entries_.begin();
- iter != entries_.end(); ++iter) {
- TabRestoreService::Entry* entry = *iter;
-
- if (FilterEntry(entry) &&
- new_entries.size() < kMaxEntries) {
- new_entries.push_back(entry);
- } else {
- delete entry;
+ for (auto& entry : entries_) {
+ if (FilterEntry(*entry) && new_entries.size() < kMaxEntries) {
+ new_entries.push_back(std::move(entry));
}
}
- entries_ = new_entries;
+ entries_ = std::move(new_entries);
}
TabRestoreService::Entries::iterator
@@ -327,10 +316,9 @@ TabRestoreServiceHelper::GetEntryIteratorById(SessionID::id_type id) {
// For Window entries, see if the ID matches a tab. If so, report the window
// as the Entry.
if ((*i)->type == TabRestoreService::WINDOW) {
- std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs;
- for (std::vector<Tab>::iterator j = tabs.begin();
- j != tabs.end(); ++j) {
- if ((*j).id == id) {
+ auto& window = static_cast<const Window&>(**i);
+ for (const auto& tab : window.tabs) {
+ if (tab->id == id) {
return i;
}
}
@@ -340,13 +328,13 @@ TabRestoreServiceHelper::GetEntryIteratorById(SessionID::id_type id) {
}
// static
-bool TabRestoreServiceHelper::ValidateEntry(Entry* entry) {
- if (entry->type == TabRestoreService::TAB)
- return ValidateTab(static_cast<Tab*>(entry));
-
- if (entry->type == TabRestoreService::WINDOW)
- return ValidateWindow(static_cast<Window*>(entry));
-
+bool TabRestoreServiceHelper::ValidateEntry(const Entry& entry) {
+ switch (entry.type) {
+ case TabRestoreService::TAB:
+ return ValidateTab(static_cast<const Tab&>(entry));
+ case TabRestoreService::WINDOW:
+ return ValidateWindow(static_cast<const Window&>(entry));
+ }
NOTREACHED();
return false;
}
@@ -369,8 +357,6 @@ void TabRestoreServiceHelper::PopulateTab(Tab* tab,
}
tab->timestamp = TimeNow();
tab->current_navigation_index = live_tab->GetCurrentEntryIndex();
- if (tab->current_navigation_index == -1 && entry_count > 0)
- tab->current_navigation_index = 0;
tab->tabstrip_index = index;
tab->extension_app_id = client_->GetExtensionAppIDForTab(live_tab);
@@ -392,13 +378,13 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab(
WindowOpenDisposition disposition,
LiveTab** live_tab) {
LiveTab* restored_tab;
- if (disposition == CURRENT_TAB && context) {
+ if (disposition == WindowOpenDisposition::CURRENT_TAB && context) {
restored_tab = context->ReplaceRestoredTab(
tab.navigations, tab.current_navigation_index, tab.from_last_session,
tab.extension_app_id, tab.platform_data.get(), tab.user_agent_override);
} else {
// We only respsect the tab's original browser if there's no disposition.
- if (disposition == UNKNOWN && tab.has_browser()) {
+ if (disposition == WindowOpenDisposition::UNKNOWN && tab.browser_id) {
context = client_->FindLiveTabContextWithID(tab.browser_id);
}
@@ -407,24 +393,25 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab(
// |context| will be NULL in cases where one isn't already available (eg,
// when invoked on Mac OS X with no windows open). In this case, create a
// new browser into which we restore the tabs.
- if (context && disposition != NEW_WINDOW) {
+ if (context && disposition != WindowOpenDisposition::NEW_WINDOW) {
tab_index = tab.tabstrip_index;
} else {
context = client_->CreateLiveTabContext(std::string());
- if (tab.has_browser())
+ if (tab.browser_id)
UpdateTabBrowserIDs(tab.browser_id, context->GetSessionID().id());
}
// Place the tab at the end if the tab index is no longer valid or
// we were passed a specific disposition.
if (tab_index < 0 || tab_index > context->GetTabCount() ||
- disposition != UNKNOWN) {
+ disposition != WindowOpenDisposition::UNKNOWN) {
tab_index = context->GetTabCount();
}
restored_tab = context->AddRestoredTab(
tab.navigations, tab_index, tab.current_navigation_index,
- tab.extension_app_id, disposition != NEW_BACKGROUND_TAB, tab.pinned,
+ tab.extension_app_id,
+ disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB, tab.pinned,
tab.from_last_session, tab.platform_data.get(),
tab.user_agent_override);
restored_tab->LoadIfNecessary();
@@ -437,86 +424,68 @@ LiveTabContext* TabRestoreServiceHelper::RestoreTab(
return context;
}
+bool TabRestoreServiceHelper::ValidateTab(const Tab& tab) {
+ return !tab.navigations.empty() &&
+ static_cast<size_t>(tab.current_navigation_index) <
+ tab.navigations.size();
+}
-bool TabRestoreServiceHelper::ValidateTab(Tab* tab) {
- if (tab->navigations.empty())
+bool TabRestoreServiceHelper::ValidateWindow(const Window& window) {
+ if (static_cast<size_t>(window.selected_tab_index) >= window.tabs.size()) {
return false;
+ }
- tab->current_navigation_index =
- std::max(0, std::min(tab->current_navigation_index,
- static_cast<int>(tab->navigations.size()) - 1));
-
- return true;
-}
-
-bool TabRestoreServiceHelper::ValidateWindow(Window* window) {
- window->selected_tab_index =
- std::max(0, std::min(window->selected_tab_index,
- static_cast<int>(window->tabs.size() - 1)));
-
- int i = 0;
- for (std::vector<Tab>::iterator tab_i = window->tabs.begin();
- tab_i != window->tabs.end();) {
- if (!ValidateTab(&(*tab_i))) {
- tab_i = window->tabs.erase(tab_i);
- if (i < window->selected_tab_index)
- window->selected_tab_index--;
- else if (i == window->selected_tab_index)
- window->selected_tab_index = 0;
- } else {
- ++tab_i;
- ++i;
+ for (const auto& tab : window.tabs) {
+ if (!ValidateTab(*tab)) {
+ return false;
}
}
- if (window->tabs.empty())
- return false;
-
return true;
}
-bool TabRestoreServiceHelper::IsTabInteresting(const Tab* tab) {
- if (tab->navigations.empty())
+bool TabRestoreServiceHelper::IsTabInteresting(const Tab& tab) {
+ if (tab.navigations.empty())
return false;
- if (tab->navigations.size() > 1)
+ if (tab.navigations.size() > 1)
return true;
- return tab->pinned ||
- tab->navigations.at(0).virtual_url() != client_->GetNewTabURL();
+ return tab.pinned ||
+ tab.navigations.at(0).virtual_url() != client_->GetNewTabURL();
}
-bool TabRestoreServiceHelper::IsWindowInteresting(const Window* window) {
- if (window->tabs.empty())
+bool TabRestoreServiceHelper::IsWindowInteresting(const Window& window) {
+ if (window.tabs.empty())
return false;
- if (window->tabs.size() > 1)
+ if (window.tabs.size() > 1)
return true;
- return IsTabInteresting(&window->tabs[0]);
+ return IsTabInteresting(*window.tabs[0]);
}
-bool TabRestoreServiceHelper::FilterEntry(Entry* entry) {
+bool TabRestoreServiceHelper::FilterEntry(const Entry& entry) {
if (!ValidateEntry(entry))
return false;
- if (entry->type == TabRestoreService::TAB)
- return IsTabInteresting(static_cast<Tab*>(entry));
- else if (entry->type == TabRestoreService::WINDOW)
- return IsWindowInteresting(static_cast<Window*>(entry));
-
+ switch (entry.type) {
+ case TabRestoreService::TAB:
+ return IsTabInteresting(static_cast<const Tab&>(entry));
+ case TabRestoreService::WINDOW:
+ return IsWindowInteresting(static_cast<const Window&>(entry));
+ }
NOTREACHED();
return false;
}
void TabRestoreServiceHelper::UpdateTabBrowserIDs(SessionID::id_type old_id,
SessionID::id_type new_id) {
- for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) {
- Entry* entry = *i;
+ for (const auto& entry : entries_) {
if (entry->type == TabRestoreService::TAB) {
- Tab* tab = static_cast<Tab*>(entry);
- if (tab->browser_id == old_id)
- tab->browser_id = new_id;
+ auto& tab = static_cast<Tab&>(*entry);
+ if (tab.browser_id == old_id)
+ tab.browser_id = new_id;
}
}
}
diff --git a/chromium/components/sessions/core/tab_restore_service_helper.h b/chromium/components/sessions/core/tab_restore_service_helper.h
index 8a9ed484082..3568e559654 100644
--- a/chromium/components/sessions/core/tab_restore_service_helper.h
+++ b/chromium/components/sessions/core/tab_restore_service_helper.h
@@ -78,10 +78,11 @@ class SESSIONS_EXPORT TabRestoreServiceHelper {
void ClearEntries();
const Entries& entries() const;
std::vector<LiveTab*> RestoreMostRecentEntry(LiveTabContext* context);
- Tab* RemoveTabEntryById(SessionID::id_type id);
+ std::unique_ptr<Tab> RemoveTabEntryById(SessionID::id_type id);
std::vector<LiveTab*> RestoreEntryById(LiveTabContext* context,
SessionID::id_type id,
WindowOpenDisposition disposition);
+ bool IsRestoring() const;
// Notifies observers the tabs have changed.
void NotifyTabsChanged();
@@ -89,11 +90,11 @@ class SESSIONS_EXPORT TabRestoreServiceHelper {
// Notifies observers the service has loaded.
void NotifyLoaded();
- // Adds |entry| to the list of entries and takes ownership. If |prune| is true
- // |PruneAndNotify| is invoked. If |to_front| is true the entry is added to
- // the front, otherwise the back. Normal closes go to the front, but
- // tab/window closes from the previous session are added to the back.
- void AddEntry(Entry* entry, bool prune, bool to_front);
+ // Adds |entry| to the list of entries. If |prune| is true |PruneAndNotify| is
+ // invoked. If |to_front| is true the entry is added to the front, otherwise
+ // the back. Normal closes go to the front, but tab/window closes from the
+ // previous session are added to the back.
+ void AddEntry(std::unique_ptr<Entry> entry, bool prune, bool to_front);
// Prunes |entries_| to contain only kMaxEntries, and removes uninteresting
// entries.
@@ -106,7 +107,7 @@ class SESSIONS_EXPORT TabRestoreServiceHelper {
Entries::iterator GetEntryIteratorById(SessionID::id_type id);
// Calls either ValidateTab or ValidateWindow as appropriate.
- static bool ValidateEntry(Entry* entry);
+ static bool ValidateEntry(const Entry& entry);
private:
friend class PersistentTabRestoreService;
@@ -130,23 +131,22 @@ class SESSIONS_EXPORT TabRestoreServiceHelper {
WindowOpenDisposition disposition,
LiveTab** live_tab);
- // Returns true if |tab| has more than one navigation. If |tab| has more
- // than one navigation |tab->current_navigation_index| is constrained based
- // on the number of navigations.
- static bool ValidateTab(Tab* tab);
+ // Returns true if |tab| has at least one navigation and
+ // |tab->current_navigation_index| is in bounds.
+ static bool ValidateTab(const Tab& tab);
// Validates all the tabs in a window, plus the window's active tab index.
- static bool ValidateWindow(Window* window);
+ static bool ValidateWindow(const Window& window);
// Returns true if |tab| is one we care about restoring.
- bool IsTabInteresting(const Tab* tab);
+ bool IsTabInteresting(const Tab& tab);
// Checks whether |window| is interesting --- if it only contains a single,
// uninteresting tab, it's not interesting.
- bool IsWindowInteresting(const Window* window);
+ bool IsWindowInteresting(const Window& window);
// Validates and checks |entry| for interesting.
- bool FilterEntry(Entry* entry);
+ bool FilterEntry(const Entry& entry);
// Finds tab entries with the old browser_id and sets it to the new one.
void UpdateTabBrowserIDs(SessionID::id_type old_id,
diff --git a/chromium/components/signin.gypi b/chromium/components/signin.gypi
deleted file mode 100644
index 049ab5a461f..00000000000
--- a/chromium/components/signin.gypi
+++ /dev/null
@@ -1,268 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/signin/core/common
- 'target_name': 'signin_core_common',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'signin/core/common/profile_management_switches.cc',
- 'signin/core/common/profile_management_switches.h',
- 'signin/core/common/signin_pref_names.cc',
- 'signin/core/common/signin_pref_names.h',
- 'signin/core/common/signin_switches.cc',
- 'signin/core/common/signin_switches.h',
- ],
- },
- {
- # GN version: //components/signin/core/account_id
- 'target_name': 'signin_core_account_id',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'signin/core/account_id/account_id.cc',
- 'signin/core/account_id/account_id.h',
- ],
- },
- {
- # GN version: //components/signin/core/browser
- 'target_name': 'signin_core_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../crypto/crypto.gyp:crypto',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../sql/sql.gyp:sql',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_proto_cpp',
- '../third_party/icu/icu.gyp:icui18n',
- '../third_party/icu/icu.gyp:icuuc',
- 'content_settings_core_browser',
- 'content_settings_core_common',
- 'google_core_browser',
- 'invalidation_public',
- 'keyed_service_core',
- 'metrics',
- 'os_crypt',
- 'prefs/prefs.gyp:prefs',
- 'signin_core_common',
- 'signin_core_account_id',
- 'webdata_common',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'signin/core/browser/about_signin_internals.cc',
- 'signin/core/browser/about_signin_internals.h',
- 'signin/core/browser/account_fetcher_service.cc',
- 'signin/core/browser/account_fetcher_service.h',
- 'signin/core/browser/account_info.cc',
- 'signin/core/browser/account_info.h',
- 'signin/core/browser/account_info_fetcher.cc',
- 'signin/core/browser/account_info_fetcher.h',
- 'signin/core/browser/account_investigator.cc',
- 'signin/core/browser/account_investigator.h',
- 'signin/core/browser/account_reconcilor.cc',
- 'signin/core/browser/account_reconcilor.h',
- 'signin/core/browser/account_tracker_service.cc',
- 'signin/core/browser/account_tracker_service.h',
- 'signin/core/browser/android/component_jni_registrar.cc',
- 'signin/core/browser/android/component_jni_registrar.h',
- 'signin/core/browser/child_account_info_fetcher.cc',
- 'signin/core/browser/child_account_info_fetcher.h',
- 'signin/core/browser/child_account_info_fetcher_android.cc',
- 'signin/core/browser/child_account_info_fetcher_android.h',
- 'signin/core/browser/child_account_info_fetcher_impl.cc',
- 'signin/core/browser/child_account_info_fetcher_impl.h',
- 'signin/core/browser/device_activity_fetcher.cc',
- 'signin/core/browser/device_activity_fetcher.h',
- 'signin/core/browser/gaia_cookie_manager_service.cc',
- 'signin/core/browser/gaia_cookie_manager_service.h',
- 'signin/core/browser/profile_identity_provider.cc',
- 'signin/core/browser/profile_identity_provider.h',
- 'signin/core/browser/profile_oauth2_token_service.cc',
- 'signin/core/browser/profile_oauth2_token_service.h',
- 'signin/core/browser/refresh_token_annotation_request.cc',
- 'signin/core/browser/refresh_token_annotation_request.h',
- 'signin/core/browser/signin_client.cc',
- 'signin/core/browser/signin_client.h',
- 'signin/core/browser/signin_cookie_changed_subscription.cc',
- 'signin/core/browser/signin_cookie_changed_subscription.h',
- 'signin/core/browser/signin_error_controller.cc',
- 'signin/core/browser/signin_error_controller.h',
- 'signin/core/browser/signin_header_helper.cc',
- 'signin/core/browser/signin_header_helper.h',
- 'signin/core/browser/signin_internals_util.cc',
- 'signin/core/browser/signin_internals_util.h',
- 'signin/core/browser/signin_investigator.cc',
- 'signin/core/browser/signin_investigator.h',
- 'signin/core/browser/signin_manager.cc',
- 'signin/core/browser/signin_manager.h',
- 'signin/core/browser/signin_manager_base.cc',
- 'signin/core/browser/signin_manager_base.h',
- 'signin/core/browser/signin_metrics.cc',
- 'signin/core/browser/signin_metrics.h',
- 'signin/core/browser/signin_status_metrics_provider.cc',
- 'signin/core/browser/signin_status_metrics_provider.h',
- 'signin/core/browser/signin_status_metrics_provider_base.cc',
- 'signin/core/browser/signin_status_metrics_provider_base.h',
- 'signin/core/browser/signin_status_metrics_provider_delegate.cc',
- 'signin/core/browser/signin_status_metrics_provider_delegate.h',
- 'signin/core/browser/signin_tracker.cc',
- 'signin/core/browser/signin_tracker.h',
- 'signin/core/browser/webdata/token_service_table.cc',
- 'signin/core/browser/webdata/token_service_table.h',
- 'signin/core/browser/webdata/token_web_data.cc',
- 'signin/core/browser/webdata/token_web_data.h',
- ],
- 'conditions': [
- ['OS=="android"', {
- 'dependencies': [
- 'signin_core_browser_jni_headers',
- ],
- 'sources!': [
- 'signin/core/browser/child_account_info_fetcher_impl.cc',
- 'signin/core/browser/child_account_info_fetcher_impl.h',
- ],
- }],
- ['chromeos==1', {
- 'sources!': [
- 'signin/core/browser/signin_manager.cc',
- 'signin/core/browser/signin_status_metrics_provider.cc',
- 'signin/core/browser/signin_status_metrics_provider_delegate.cc',
- ],
- }],
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- # GN version: //components/signin/core/browser:test_support
- 'target_name': 'signin_core_browser_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'signin_core_browser',
- '../testing/gtest.gyp:gtest',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'signin/core/browser/fake_account_fetcher_service.cc',
- 'signin/core/browser/fake_account_fetcher_service.h',
- 'signin/core/browser/fake_auth_status_provider.cc',
- 'signin/core/browser/fake_auth_status_provider.h',
- 'signin/core/browser/fake_gaia_cookie_manager_service.cc',
- 'signin/core/browser/fake_gaia_cookie_manager_service.h',
- 'signin/core/browser/fake_profile_oauth2_token_service.cc',
- 'signin/core/browser/fake_profile_oauth2_token_service.h',
- 'signin/core/browser/fake_signin_manager.cc',
- 'signin/core/browser/fake_signin_manager.h',
- 'signin/core/browser/test_signin_client.cc',
- 'signin/core/browser/test_signin_client.h',
- ],
- },
- ],
- 'conditions': [
- ['OS == "android"', {
- 'targets': [
- {
- # GN version: //components/signin/core/browser/android:java
- 'target_name': 'signin_core_browser_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base',
- '../sync/sync.gyp:sync_java',
- ],
- 'variables': {
- 'java_in_dir': 'signin/core/browser/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN version: //components/signin/core/browser/android:jni_headers
- 'target_name': 'signin_core_browser_jni_headers',
- 'type': 'none',
- 'sources': [
- 'signin/core/browser/android/java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java',
- ],
- 'variables': {
- 'jni_gen_package': 'components/signin',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- # GN: //components/signin/core/browser:investigated_scenario_java
- 'target_name': 'investigated_scenario_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'signin/core/browser/signin_investigator.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- ],
- }],
- ['OS == "ios"', {
- 'targets': [
- {
- # GN version: //components/signin/ios/browser
- 'target_name': 'signin_ios_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../ios/web/ios_web.gyp:ios_web',
- 'signin_core_browser',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'signin/ios/browser/account_consistency_service.h',
- 'signin/ios/browser/account_consistency_service.mm',
- 'signin/ios/browser/manage_accounts_delegate.h',
- 'signin/ios/browser/merge_session_observer_bridge.h',
- 'signin/ios/browser/merge_session_observer_bridge.mm',
- 'signin/ios/browser/oauth2_token_service_observer_bridge.h',
- 'signin/ios/browser/oauth2_token_service_observer_bridge.mm',
- 'signin/ios/browser/profile_oauth2_token_service_ios_delegate.h',
- 'signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm',
- 'signin/ios/browser/profile_oauth2_token_service_ios_provider.h',
- 'signin/ios/browser/profile_oauth2_token_service_ios_provider.mm',
- ],
- },
- {
- # GN version: //components/signin/ios/browser:test_support
- 'target_name': 'signin_ios_browser_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../google_apis/google_apis.gyp:google_apis_test_support',
- 'signin_ios_browser',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h',
- 'signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.mm',
- 'signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h',
- 'signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/signin/DEPS b/chromium/components/signin/DEPS
index 7a268e8c84a..89ffc6df341 100644
--- a/chromium/components/signin/DEPS
+++ b/chromium/components/signin/DEPS
@@ -12,10 +12,3 @@ include_rules = [
"+net",
"+sql",
]
-
-# Tests can use syncable_prefs
-specific_include_rules = {
- ".*unittest\.cc": [
- "+components/syncable_prefs",
- ]
-}
diff --git a/chromium/components/signin/core/account_id/BUILD.gn b/chromium/components/signin/core/account_id/BUILD.gn
index 51091e0109b..f769b9044b9 100644
--- a/chromium/components/signin/core/account_id/BUILD.gn
+++ b/chromium/components/signin/core/account_id/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("account_id") {
+static_library("account_id") {
sources = [
"account_id.cc",
"account_id.h",
diff --git a/chromium/components/signin/core/browser/BUILD.gn b/chromium/components/signin/core/browser/BUILD.gn
index 0c3eb74c1ff..602802d96fe 100644
--- a/chromium/components/signin/core/browser/BUILD.gn
+++ b/chromium/components/signin/core/browser/BUILD.gn
@@ -6,7 +6,7 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-source_set("browser") {
+static_library("browser") {
sources = [
"about_signin_internals.cc",
"about_signin_internals.h",
@@ -74,6 +74,10 @@ source_set("browser") {
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+ public_deps = [
+ "//components/signin/core/account_id",
+ "//components/signin/core/common",
+ ]
deps = [
"//base",
"//base:i18n",
@@ -86,8 +90,6 @@ source_set("browser") {
"//components/os_crypt",
"//components/pref_registry",
"//components/prefs",
- "//components/signin/core/account_id",
- "//components/signin/core/common",
"//components/webdata/common",
"//crypto",
"//google_apis",
@@ -113,7 +115,7 @@ source_set("browser") {
}
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"fake_account_fetcher_service.cc",
@@ -150,6 +152,7 @@ source_set("unit_tests") {
"gaia_cookie_manager_service_unittest.cc",
"refresh_token_annotation_request_unittest.cc",
"signin_error_controller_unittest.cc",
+ "signin_header_helper_unittest.cc",
"signin_investigator_unittest.cc",
"signin_status_metrics_provider_unittest.cc",
"webdata/token_service_table_unittest.cc",
@@ -157,9 +160,10 @@ source_set("unit_tests") {
deps = [
":test_support",
+ "//components/content_settings/core/browser",
"//components/os_crypt:test_support",
+ "//components/pref_registry:test_support",
"//components/signin/core/common",
- "//components/syncable_prefs:test_support",
"//testing/gmock",
]
@@ -172,7 +176,6 @@ source_set("unit_tests") {
}
if (is_android) {
- # GYP: //component/signin.gypi:investigated_scenario_java
java_cpp_enum("investigated_scenario_java") {
sources = [
"signin_investigator.h",
diff --git a/chromium/components/signin/core/browser/about_signin_internals.cc b/chromium/components/signin/core/browser/about_signin_internals.cc
index e1ac32ceb97..b6b897b6325 100644
--- a/chromium/components/signin/core/browser/about_signin_internals.cc
+++ b/chromium/components/signin/core/browser/about_signin_internals.cc
@@ -429,7 +429,8 @@ bool AboutSigninInternals::TokenInfo::LessThan(const TokenInfo* a,
void AboutSigninInternals::TokenInfo::Invalidate() { removed_ = true; }
-base::DictionaryValue* AboutSigninInternals::TokenInfo::ToValue() const {
+std::unique_ptr<base::DictionaryValue>
+AboutSigninInternals::TokenInfo::ToValue() const {
std::unique_ptr<base::DictionaryValue> token_info(
new base::DictionaryValue());
token_info->SetString("service", consumer_id);
@@ -471,7 +472,7 @@ base::DictionaryValue* AboutSigninInternals::TokenInfo::ToValue() const {
token_info->SetString("status", "Waiting for response");
}
- return token_info.release();
+ return token_info;
}
AboutSigninInternals::SigninStatus::SigninStatus()
@@ -481,7 +482,7 @@ AboutSigninInternals::SigninStatus::~SigninStatus() {
for (TokenInfoMap::iterator it = token_info_map.begin();
it != token_info_map.end();
++it) {
- STLDeleteElements(&it->second);
+ base::STLDeleteElements(&it->second);
}
}
@@ -653,8 +654,7 @@ AboutSigninInternals::SigninStatus::ToValue(
"422460 AboutSigninInternals::SigninStatus::ToValue43"));
for (size_t i = 0; i < tokens.size(); ++i) {
- base::DictionaryValue* token_info = tokens[i]->ToValue();
- token_details->Append(token_info);
+ token_details->Append(tokens[i]->ToValue());
}
}
diff --git a/chromium/components/signin/core/browser/about_signin_internals.h b/chromium/components/signin/core/browser/about_signin_internals.h
index 9d77dd61b87..7af382bfc8e 100644
--- a/chromium/components/signin/core/browser/about_signin_internals.h
+++ b/chromium/components/signin/core/browser/about_signin_internals.h
@@ -108,7 +108,7 @@ class AboutSigninInternals
TokenInfo(const std::string& consumer_id,
const OAuth2TokenService::ScopeSet& scopes);
~TokenInfo();
- base::DictionaryValue* ToValue() const;
+ std::unique_ptr<base::DictionaryValue> ToValue() const;
static bool LessThan(const TokenInfo* a, const TokenInfo* b);
diff --git a/chromium/components/signin/core/browser/account_investigator.cc b/chromium/components/signin/core/browser/account_investigator.cc
index 03d72c9200c..e468f0330df 100644
--- a/chromium/components/signin/core/browser/account_investigator.cc
+++ b/chromium/components/signin/core/browser/account_investigator.cc
@@ -201,7 +201,8 @@ AccountRelation AccountInvestigator::DiscernRelation(
void AccountInvestigator::TryPeriodicReport() {
std::vector<ListedAccount> signed_in_accounts, signed_out_accounts;
if (cookie_service_->ListAccounts(&signed_in_accounts,
- &signed_out_accounts)) {
+ &signed_out_accounts,
+ "ChromiumAccountInvestigator")) {
DoPeriodicReport(signed_in_accounts, signed_out_accounts);
} else {
periodic_pending_ = true;
diff --git a/chromium/components/signin/core/browser/account_investigator_unittest.cc b/chromium/components/signin/core/browser/account_investigator_unittest.cc
index 1b9edd66a47..d70acac2036 100644
--- a/chromium/components/signin/core/browser/account_investigator_unittest.cc
+++ b/chromium/components/signin/core/browser/account_investigator_unittest.cc
@@ -12,13 +12,14 @@
#include "base/run_loop.h"
#include "base/test/histogram_tester.h"
#include "base/timer/timer.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/pref_registry/testing_pref_service_syncable.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
#include "components/signin/core/browser/fake_signin_manager.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "components/signin/core/browser/test_signin_client.h"
#include "components/signin/core/common/signin_pref_names.h"
-#include "components/syncable_prefs/testing_pref_service_syncable.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/google_service_auth_error.h"
@@ -154,7 +155,7 @@ class AccountInvestigatorTest : public testing::Test {
private:
// Timer needs a message loop.
base::MessageLoop message_loop_;
- syncable_prefs::TestingPrefServiceSyncable prefs_;
+ user_prefs::TestingPrefServiceSyncable prefs_;
AccountTrackerService account_tracker_service_;
TestSigninClient signin_client_;
FakeSigninManager signin_manager_;
diff --git a/chromium/components/signin/core/browser/account_reconcilor.cc b/chromium/components/signin/core/browser/account_reconcilor.cc
index 1a924082d25..5a0170eb3f6 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor.cc
@@ -26,9 +26,13 @@
namespace {
+// String used for source parameter in GAIA cookie manager calls.
+const char kSource[] = "ChromiumAccountReconcilor";
+
class AccountEqualToFunc {
public:
- AccountEqualToFunc(const gaia::ListedAccount& account) : account_(account) {}
+ explicit AccountEqualToFunc(const gaia::ListedAccount& account)
+ : account_(account) {}
bool operator()(const gaia::ListedAccount& other) const;
private:
@@ -242,14 +246,14 @@ void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
return;
}
VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id;
- cookie_manager_service_->AddAccountToCookie(account_id);
+ cookie_manager_service_->AddAccountToCookie(account_id, kSource);
}
void AccountReconcilor::PerformLogoutAllAccountsAction() {
if (!switches::IsEnableAccountConsistency())
return;
VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction";
- cookie_manager_service_->LogOutAllAccounts();
+ cookie_manager_service_->LogOutAllAccounts(kSource);
}
void AccountReconcilor::StartReconcile() {
@@ -286,7 +290,8 @@ void AccountReconcilor::StartReconcile() {
// Rely on the GCMS to manage calls to and responses from ListAccounts.
if (cookie_manager_service_->ListAccounts(&gaia_accounts_,
- &signed_out_accounts)) {
+ &signed_out_accounts,
+ kSource)) {
OnGaiaAccountsInCookieUpdated(
gaia_accounts_,
signed_out_accounts,
@@ -366,7 +371,7 @@ void AccountReconcilor::OnNewProfileManagementFlagChanged(
void AccountReconcilor::OnReceivedManageAccountsResponse(
signin::GAIAServiceType service_type) {
if (service_type == signin::GAIA_SERVICE_TYPE_ADDSESSION) {
- cookie_manager_service_->TriggerListAccounts();
+ cookie_manager_service_->TriggerListAccounts(kSource);
}
}
diff --git a/chromium/components/signin/core/browser/account_tracker_service.cc b/chromium/components/signin/core/browser/account_tracker_service.cc
index b1dc370db2b..84f522a7eba 100644
--- a/chromium/components/signin/core/browser/account_tracker_service.cc
+++ b/chromium/components/signin/core/browser/account_tracker_service.cc
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/profiler/scoped_tracker.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
@@ -185,7 +186,7 @@ void AccountTrackerService::NotifyAccountRemoved(const AccountState& state) {
void AccountTrackerService::StartTrackingAccount(
const std::string& account_id) {
- if (!ContainsKey(accounts_, account_id)) {
+ if (!base::ContainsKey(accounts_, account_id)) {
DVLOG(1) << "StartTracking " << account_id;
AccountState state;
state.info.account_id = account_id;
@@ -196,7 +197,7 @@ void AccountTrackerService::StartTrackingAccount(
void AccountTrackerService::StopTrackingAccount(const std::string& account_id) {
DVLOG(1) << "StopTracking " << account_id;
- if (ContainsKey(accounts_, account_id)) {
+ if (base::ContainsKey(accounts_, account_id)) {
AccountState& state = accounts_[account_id];
RemoveFromPrefs(state);
if (!state.info.gaia.empty())
@@ -209,7 +210,7 @@ void AccountTrackerService::StopTrackingAccount(const std::string& account_id) {
void AccountTrackerService::SetAccountStateFromUserInfo(
const std::string& account_id,
const base::DictionaryValue* user_info) {
- DCHECK(ContainsKey(accounts_, account_id));
+ DCHECK(base::ContainsKey(accounts_, account_id));
AccountState& state = accounts_[account_id];
std::string gaia_id;
@@ -244,7 +245,7 @@ void AccountTrackerService::SetAccountStateFromUserInfo(
void AccountTrackerService::SetIsChildAccount(const std::string& account_id,
const bool& is_child_account) {
- DCHECK(ContainsKey(accounts_, account_id));
+ DCHECK(base::ContainsKey(accounts_, account_id));
AccountState& state = accounts_[account_id];
if (state.info.is_child_account == is_child_account)
return;
@@ -279,7 +280,7 @@ void AccountTrackerService::MigrateToGaiaId() {
std::string account_id = it->first;
if (account_id != state.info.gaia) {
std::string new_account_id = state.info.gaia;
- if (!ContainsKey(accounts_, new_account_id)) {
+ if (!base::ContainsKey(accounts_, new_account_id)) {
AccountState new_state = state;
new_state.info.account_id = new_account_id;
migrated_accounts.insert(make_pair(new_account_id, new_state));
@@ -291,7 +292,7 @@ void AccountTrackerService::MigrateToGaiaId() {
// Remove any obsolete account.
for (auto account_id : to_remove) {
- if (ContainsKey(accounts_, account_id)) {
+ if (base::ContainsKey(accounts_, account_id)) {
AccountState& state = accounts_[account_id];
RemoveFromPrefs(state);
accounts_.erase(account_id);
@@ -405,7 +406,7 @@ void AccountTrackerService::SaveToPrefs(const AccountState& state) {
if (!dict) {
dict = new base::DictionaryValue();
- update->Append(dict); // |update| takes ownership.
+ update->Append(base::WrapUnique(dict));
dict->SetString(kAccountKeyPath, account_id_16);
}
@@ -469,7 +470,7 @@ std::string AccountTrackerService::PickAccountIdForAccount(
std::string AccountTrackerService::SeedAccountInfo(const std::string& gaia,
const std::string& email) {
const std::string account_id = PickAccountIdForAccount(gaia, email);
- const bool already_exists = ContainsKey(accounts_, account_id);
+ const bool already_exists = base::ContainsKey(accounts_, account_id);
StartTrackingAccount(account_id);
AccountState& state = accounts_[account_id];
DCHECK(!already_exists || state.info.gaia.empty() || state.info.gaia == gaia);
@@ -488,7 +489,7 @@ std::string AccountTrackerService::SeedAccountInfo(const std::string& gaia,
std::string AccountTrackerService::SeedAccountInfo(AccountInfo info) {
info.account_id = PickAccountIdForAccount(info.gaia, info.email);
- if (!ContainsKey(accounts_, info.account_id)) {
+ if (!base::ContainsKey(accounts_, info.account_id)) {
StartTrackingAccount(info.account_id);
}
diff --git a/chromium/components/signin/core/browser/account_tracker_service_unittest.cc b/chromium/components/signin/core/browser/account_tracker_service_unittest.cc
index 27ac5bcc5e6..b6847009f33 100644
--- a/chromium/components/signin/core/browser/account_tracker_service_unittest.cc
+++ b/chromium/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -3,8 +3,11 @@
// found in the LICENSE file.
#include <algorithm>
+#include <memory>
+#include <utility>
#include <vector>
+#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/scoped_user_pref_update.h"
@@ -904,17 +907,17 @@ TEST_F(AccountTrackerServiceTest, MigrateAccountIdToGaiaId) {
ListPrefUpdate update(&pref, AccountTrackerService::kAccountInfoPref);
- base::DictionaryValue* dict = new base::DictionaryValue();
- update->Append(dict);
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("account_id", base::UTF8ToUTF16(email_alpha));
dict->SetString("email", base::UTF8ToUTF16(email_alpha));
dict->SetString("gaia", base::UTF8ToUTF16(gaia_alpha));
+ update->Append(std::move(dict));
- dict = new base::DictionaryValue();
- update->Append(dict);
+ dict.reset(new base::DictionaryValue());
dict->SetString("account_id", base::UTF8ToUTF16(email_beta));
dict->SetString("email", base::UTF8ToUTF16(email_beta));
dict->SetString("gaia", base::UTF8ToUTF16(gaia_beta));
+ update->Append(std::move(dict));
std::unique_ptr<TestSigninClient> client;
client.reset(new TestSigninClient(&pref));
@@ -956,17 +959,17 @@ TEST_F(AccountTrackerServiceTest, CanNotMigrateAccountIdToGaiaId) {
ListPrefUpdate update(&pref, AccountTrackerService::kAccountInfoPref);
- base::DictionaryValue* dict = new base::DictionaryValue();
- update->Append(dict);
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("account_id", base::UTF8ToUTF16(email_alpha));
dict->SetString("email", base::UTF8ToUTF16(email_alpha));
dict->SetString("gaia", base::UTF8ToUTF16(gaia_alpha));
+ update->Append(std::move(dict));
- dict = new base::DictionaryValue();
- update->Append(dict);
+ dict.reset(new base::DictionaryValue());
dict->SetString("account_id", base::UTF8ToUTF16(email_beta));
dict->SetString("email", base::UTF8ToUTF16(email_beta));
dict->SetString("gaia", base::UTF8ToUTF16(std::string()));
+ update->Append(std::move(dict));
std::unique_ptr<TestSigninClient> client;
client.reset(new TestSigninClient(&pref));
@@ -1008,24 +1011,24 @@ TEST_F(AccountTrackerServiceTest, GaiaIdMigrationCrashInTheMiddle) {
ListPrefUpdate update(&pref, AccountTrackerService::kAccountInfoPref);
- base::DictionaryValue* dict = new base::DictionaryValue();
- update->Append(dict);
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("account_id", base::UTF8ToUTF16(email_alpha));
dict->SetString("email", base::UTF8ToUTF16(email_alpha));
dict->SetString("gaia", base::UTF8ToUTF16(gaia_alpha));
+ update->Append(std::move(dict));
- dict = new base::DictionaryValue();
- update->Append(dict);
+ dict.reset(new base::DictionaryValue());
dict->SetString("account_id", base::UTF8ToUTF16(email_beta));
dict->SetString("email", base::UTF8ToUTF16(email_beta));
dict->SetString("gaia", base::UTF8ToUTF16(gaia_beta));
+ update->Append(std::move(dict));
// Succeed miggrated account.
- dict = new base::DictionaryValue();
- update->Append(dict);
+ dict.reset(new base::DictionaryValue());
dict->SetString("account_id", base::UTF8ToUTF16(gaia_alpha));
dict->SetString("email", base::UTF8ToUTF16(email_alpha));
dict->SetString("gaia", base::UTF8ToUTF16(gaia_alpha));
+ update->Append(std::move(dict));
std::unique_ptr<TestSigninClient> client;
client.reset(new TestSigninClient(&pref));
diff --git a/chromium/components/signin/core/browser/android/BUILD.gn b/chromium/components/signin/core/browser/android/BUILD.gn
index 9d56632547c..c9f5bc3f598 100644
--- a/chromium/components/signin/core/browser/android/BUILD.gn
+++ b/chromium/components/signin/core/browser/android/BUILD.gn
@@ -4,7 +4,6 @@
import("//build/config/android/rules.gni")
-# GYP version: components/signin.gypi:signin_core_browser_jni_headers
generate_jni("jni_headers") {
sources = [
"java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java",
@@ -12,13 +11,47 @@ generate_jni("jni_headers") {
jni_package = "components/signin"
}
-# GYP version: components/signin.gypi:signin_core_browser_java
android_library("java") {
deps = [
"//base:base_java",
- "//sync/android:sync_java",
+ "//net/android:net_java",
+ google_play_services_library,
]
- java_files =
- [ "java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java" ]
+ java_files = [
+ "java/src/org/chromium/components/signin/AccountManagerDelegate.java",
+ "java/src/org/chromium/components/signin/AccountManagerHelper.java",
+ "java/src/org/chromium/components/signin/AuthException.java",
+ "java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java",
+ "java/src/org/chromium/components/signin/ChromeSigninController.java",
+ "java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java",
+ ]
+}
+
+android_library("javatests") {
+ testonly = true
+ deps = [
+ ":java",
+ ":signin_java_test_support",
+ "//base:base_java",
+ "//base:base_java_test_support",
+ ]
+
+ java_files = [ "javatests/src/org/chromium/components/signin/test/AccountManagerHelperTest.java" ]
+}
+
+android_library("signin_java_test_support") {
+ testonly = true
+ deps = [
+ ":java",
+ "//base:base_java",
+ "//base:base_java_test_support",
+ "//third_party/jsr-305:jsr_305_javalib",
+ ]
+
+ java_files = [
+ "javatests/src/org/chromium/components/signin/test/util/AccountHolder.java",
+ "javatests/src/org/chromium/components/signin/test/util/MockAccountManager.java",
+ "javatests/src/org/chromium/components/signin/test/util/SimpleFuture.java",
+ ]
}
diff --git a/chromium/components/signin/core/browser/android/java/DEPS b/chromium/components/signin/core/browser/android/java/DEPS
deleted file mode 100644
index a7565d5e70a..00000000000
--- a/chromium/components/signin/core/browser/android/java/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+sync/android/java/src/org/chromium/sync/signin",
-]
diff --git a/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc b/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc
index 132158856ed..2697018b72a 100644
--- a/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc
+++ b/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc
@@ -10,6 +10,8 @@
#include "components/signin/core/browser/account_tracker_service.h"
#include "jni/ChildAccountInfoFetcher_jni.h"
+using base::android::JavaParamRef;
+
// static
void ChildAccountInfoFetcherAndroid::StartFetchingChildAccountInfo(
AccountFetcherService* service,
@@ -22,8 +24,8 @@ void ChildAccountInfoFetcherAndroid::StartFetchingChildAccountInfo(
return;
Java_ChildAccountInfoFetcher_fetch(
env, reinterpret_cast<jlong>(service),
- base::android::ConvertUTF8ToJavaString(env, account_id).obj(),
- base::android::ConvertUTF8ToJavaString(env, account_name).obj());
+ base::android::ConvertUTF8ToJavaString(env, account_id),
+ base::android::ConvertUTF8ToJavaString(env, account_name));
}
// static
diff --git a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
index 8a0249cd615..bf95c888a37 100644
--- a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
@@ -107,3 +107,12 @@ void FakeGaiaCookieManagerService::SetListAccountsResponseTwoAccountsWithExpiry(
account2_expired ? 0 : 1, gaia_id2),
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
}
+
+std::string FakeGaiaCookieManagerService::GetSourceForRequest(
+ const GaiaCookieManagerService::GaiaCookieRequest& request,
+ const std::string& source_default) {
+ // Always return the default. This value must match the source used in the
+ // SetXXXResponseYYY methods above so that the test URLFetcher factory will
+ // be able to find the URLs.
+ return GaiaConstants::kChromeSource;
+}
diff --git a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h
index cc79071e440..4d67f40b41a 100644
--- a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h
+++ b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h
@@ -43,6 +43,10 @@ class FakeGaiaCookieManagerService : public GaiaCookieManagerService {
bool account2_expired);
private:
+ std::string GetSourceForRequest(
+ const GaiaCookieManagerService::GaiaCookieRequest& request,
+ const std::string& source_default) override;
+
// Provide a fake response for calls to /ListAccounts.
net::FakeURLFetcherFactory* url_fetcher_factory_;
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc b/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
index d6b4f01106f..cb807f69f37 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -7,7 +7,6 @@
#include <stddef.h>
#include <queue>
-#include <vector>
#include "base/json/json_reader.h"
#include "base/metrics/histogram_macros.h"
@@ -32,29 +31,29 @@ namespace {
// In case of an error while fetching using the GaiaAuthFetcher or URLFetcher,
// retry with exponential backoff. Try up to 7 times within 15 minutes.
const net::BackoffEntry::Policy kBackoffPolicy = {
- // Number of initial errors (in sequence) to ignore before applying
- // exponential back-off rules.
- 0,
+ // Number of initial errors (in sequence) to ignore before applying
+ // exponential back-off rules.
+ 0,
- // Initial delay for exponential backoff in ms.
- 1000,
+ // Initial delay for exponential backoff in ms.
+ 1000,
- // Factor by which the waiting time will be multiplied.
- 3,
+ // Factor by which the waiting time will be multiplied.
+ 3,
- // Fuzzing percentage. ex: 10% will spread requests randomly
- // between 90%-100% of the calculated time.
- 0.2, // 20%
+ // Fuzzing percentage. ex: 10% will spread requests randomly
+ // between 90%-100% of the calculated time.
+ 0.2, // 20%
- // Maximum amount of time we are willing to delay our request in ms.
- 1000 * 60 * 60 * 4, // 15 minutes.
+ // Maximum amount of time we are willing to delay our request in ms.
+ 1000 * 60 * 60 * 4, // 15 minutes.
- // Time to keep an entry from being discarded even when it
- // has no significant state, -1 to never discard.
- -1,
+ // Time to keep an entry from being discarded even when it
+ // has no significant state, -1 to never discard.
+ -1,
- // Don't use initial delay unless the last request was an error.
- false,
+ // Don't use initial delay unless the last request was an error.
+ false,
};
const int kMaxFetcherRetries = 8;
@@ -74,9 +73,9 @@ enum GaiaCookieRequestType {
GaiaCookieManagerService::GaiaCookieRequest::GaiaCookieRequest(
GaiaCookieRequestType request_type,
- const std::string& account_id)
- : request_type_(request_type),
- account_id_(account_id) {}
+ const std::string& account_id,
+ const std::string& source)
+ : request_type_(request_type), account_id_(account_id), source_(source) {}
GaiaCookieManagerService::GaiaCookieRequest::~GaiaCookieRequest() {
}
@@ -84,23 +83,28 @@ GaiaCookieManagerService::GaiaCookieRequest::~GaiaCookieRequest() {
// static
GaiaCookieManagerService::GaiaCookieRequest
GaiaCookieManagerService::GaiaCookieRequest::CreateAddAccountRequest(
- const std::string& account_id) {
+ const std::string& account_id,
+ const std::string& source) {
return GaiaCookieManagerService::GaiaCookieRequest(
- GaiaCookieManagerService::GaiaCookieRequestType::ADD_ACCOUNT, account_id);
+ GaiaCookieManagerService::GaiaCookieRequestType::ADD_ACCOUNT, account_id,
+ source);
}
// static
GaiaCookieManagerService::GaiaCookieRequest
-GaiaCookieManagerService::GaiaCookieRequest::CreateLogOutRequest() {
+GaiaCookieManagerService::GaiaCookieRequest::CreateLogOutRequest(
+ const std::string& source) {
return GaiaCookieManagerService::GaiaCookieRequest(
- GaiaCookieManagerService::GaiaCookieRequestType::LOG_OUT, std::string());
+ GaiaCookieManagerService::GaiaCookieRequestType::LOG_OUT, std::string(),
+ source);
}
GaiaCookieManagerService::GaiaCookieRequest
-GaiaCookieManagerService::GaiaCookieRequest::CreateListAccountsRequest() {
+GaiaCookieManagerService::GaiaCookieRequest::CreateListAccountsRequest(
+ const std::string& source) {
return GaiaCookieManagerService::GaiaCookieRequest(
GaiaCookieManagerService::GaiaCookieRequestType::LIST_ACCOUNTS,
- std::string());
+ std::string(), source);
}
GaiaCookieManagerService::ExternalCcResultFetcher::ExternalCcResultFetcher(
@@ -289,7 +293,9 @@ GaiaCookieManagerService::GaiaCookieManagerService(
fetcher_retries_(0),
source_(source),
external_cc_result_fetched_(false),
- list_accounts_stale_(true) {}
+ list_accounts_stale_(true) {
+ DCHECK(!source_.empty());
+}
GaiaCookieManagerService::~GaiaCookieManagerService() {
CancelAll();
@@ -309,7 +315,8 @@ void GaiaCookieManagerService::Shutdown() {
void GaiaCookieManagerService::AddAccountToCookieInternal(
- const std::string& account_id) {
+ const std::string& account_id,
+ const std::string& source) {
DCHECK(!account_id.empty());
if (!signin_client_->AreSigninCookiesAllowed()) {
SignalComplete(account_id,
@@ -317,7 +324,8 @@ void GaiaCookieManagerService::AddAccountToCookieInternal(
return;
}
- requests_.push_back(GaiaCookieRequest::CreateAddAccountRequest(account_id));
+ requests_.push_back(
+ GaiaCookieRequest::CreateAddAccountRequest(account_id, source));
if (requests_.size() == 1) {
signin_client_->DelayNetworkCall(
base::Bind(&GaiaCookieManagerService::StartFetchingUbertoken,
@@ -326,25 +334,28 @@ void GaiaCookieManagerService::AddAccountToCookieInternal(
}
void GaiaCookieManagerService::AddAccountToCookie(
- const std::string& account_id) {
+ const std::string& account_id,
+ const std::string& source) {
VLOG(1) << "GaiaCookieManagerService::AddAccountToCookie: " << account_id;
access_token_ = std::string();
- AddAccountToCookieInternal(account_id);
+ AddAccountToCookieInternal(account_id, source);
}
void GaiaCookieManagerService::AddAccountToCookieWithToken(
const std::string& account_id,
- const std::string& access_token) {
+ const std::string& access_token,
+ const std::string& source) {
VLOG(1) << "GaiaCookieManagerService::AddAccountToCookieWithToken: "
<< account_id;
DCHECK(!access_token.empty());
access_token_ = access_token;
- AddAccountToCookieInternal(account_id);
+ AddAccountToCookieInternal(account_id, source);
}
bool GaiaCookieManagerService::ListAccounts(
std::vector<gaia::ListedAccount>* accounts,
- std::vector<gaia::ListedAccount>* signed_out_accounts) {
+ std::vector<gaia::ListedAccount>* signed_out_accounts,
+ const std::string& source) {
if (!list_accounts_stale_) {
if (accounts)
accounts->assign(listed_accounts_.begin(), listed_accounts_.end());
@@ -357,14 +368,14 @@ bool GaiaCookieManagerService::ListAccounts(
return true;
}
- TriggerListAccounts();
+ TriggerListAccounts(source);
return false;
}
-void GaiaCookieManagerService::TriggerListAccounts() {
+void GaiaCookieManagerService::TriggerListAccounts(const std::string& source) {
if (requests_.empty()) {
fetcher_retries_ = 0;
- requests_.push_back(GaiaCookieRequest::CreateListAccountsRequest());
+ requests_.push_back(GaiaCookieRequest::CreateListAccountsRequest(source));
signin_client_->DelayNetworkCall(
base::Bind(&GaiaCookieManagerService::StartFetchingListAccounts,
base::Unretained(this)));
@@ -372,20 +383,20 @@ void GaiaCookieManagerService::TriggerListAccounts() {
[](const GaiaCookieRequest& request) {
return request.request_type() == LIST_ACCOUNTS;
}) == requests_.end()) {
- requests_.push_back(GaiaCookieRequest::CreateListAccountsRequest());
+ requests_.push_back(GaiaCookieRequest::CreateListAccountsRequest(source));
}
}
void GaiaCookieManagerService::ForceOnCookieChangedProcessing() {
GURL google_url = GaiaUrls::GetInstance()->google_url();
- net::CanonicalCookie cookie(
- google_url, kGaiaCookieName, "", google_url.host(), "", base::Time(),
- base::Time(), base::Time(), false, false,
- net::CookieSameSite::DEFAULT_MODE, net::COOKIE_PRIORITY_DEFAULT);
- OnCookieChanged(cookie, true);
+ std::unique_ptr<net::CanonicalCookie> cookie(net::CanonicalCookie::Create(
+ google_url, kGaiaCookieName, std::string(), "." + google_url.host(),
+ std::string(), base::Time(), base::Time(), false, false,
+ net::CookieSameSite::DEFAULT_MODE, false, net::COOKIE_PRIORITY_DEFAULT));
+ OnCookieChanged(*cookie, net::CookieStore::ChangeCause::UNKNOWN_DELETION);
}
-void GaiaCookieManagerService::LogOutAllAccounts() {
+void GaiaCookieManagerService::LogOutAllAccounts(const std::string& source) {
VLOG(1) << "GaiaCookieManagerService::LogOutAllAccounts";
bool log_out_queued = false;
@@ -424,7 +435,7 @@ void GaiaCookieManagerService::LogOutAllAccounts() {
}
if (!log_out_queued) {
- requests_.push_back(GaiaCookieRequest::CreateLogOutRequest());
+ requests_.push_back(GaiaCookieRequest::CreateLogOutRequest(source));
if (requests_.size() == 1) {
fetcher_retries_ = 0;
signin_client_->DelayNetworkCall(
@@ -450,11 +461,17 @@ void GaiaCookieManagerService::CancelAll() {
fetcher_timer_.Stop();
}
+std::string GaiaCookieManagerService::GetSourceForRequest(
+ const GaiaCookieManagerService::GaiaCookieRequest& request,
+ const std::string& source_default) {
+ return request.source().empty() ? source_default : request.source();
+}
+
void GaiaCookieManagerService::OnCookieChanged(
const net::CanonicalCookie& cookie,
- bool removed) {
+ net::CookieStore::ChangeCause cause) {
DCHECK_EQ(kGaiaCookieName, cookie.Name());
- DCHECK_EQ(GaiaUrls::GetInstance()->google_url().host(), cookie.Domain());
+ DCHECK(cookie.IsDomainMatch(GaiaUrls::GetInstance()->google_url().host()));
list_accounts_stale_ = true;
// Ignore changes to the cookie while requests are pending. These changes
// are caused by the service itself as it adds accounts. A side effects is
@@ -462,7 +479,33 @@ void GaiaCookieManagerService::OnCookieChanged(
// are pending, will be lost. However, trying to process these changes could
// cause an endless loop (see crbug.com/516070).
if (requests_.empty()) {
- requests_.push_back(GaiaCookieRequest::CreateListAccountsRequest());
+ // Build gaia "source" based on cause to help track down channel id issues.
+ std::string source(source_);
+ switch (cause) {
+ case net::CookieStore::ChangeCause::INSERTED:
+ source += "INSERTED";
+ break;
+ case net::CookieStore::ChangeCause::EXPLICIT:
+ source += "EXPLICIT";
+ break;
+ case net::CookieStore::ChangeCause::UNKNOWN_DELETION:
+ source += "UNKNOWN_DELETION";
+ break;
+ case net::CookieStore::ChangeCause::OVERWRITE:
+ source += "OVERWRITE";
+ break;
+ case net::CookieStore::ChangeCause::EXPIRED:
+ source += "EXPIRED";
+ break;
+ case net::CookieStore::ChangeCause::EVICTED:
+ source += "EVICTED";
+ break;
+ case net::CookieStore::ChangeCause::EXPIRED_OVERWRITE:
+ source += "EXPIRED_OVERWRITE";
+ break;
+ }
+
+ requests_.push_back(GaiaCookieRequest::CreateListAccountsRequest(source));
fetcher_retries_ = 0;
signin_client_->DelayNetworkCall(
base::Bind(&GaiaCookieManagerService::StartFetchingListAccounts,
@@ -516,6 +559,9 @@ void GaiaCookieManagerService::OnMergeSessionSuccess(const std::string& data) {
<< requests_.front().account_id();
DCHECK(requests_.front().request_type() ==
GaiaCookieRequestType::ADD_ACCOUNT);
+
+ list_accounts_stale_ = true;
+
const std::string account_id = requests_.front().account_id();
HandleNextRequest();
SignalComplete(account_id, GoogleServiceAuthError::AuthErrorNone());
@@ -619,6 +665,8 @@ void GaiaCookieManagerService::OnLogOutSuccess() {
DCHECK(requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT);
VLOG(1) << "GaiaCookieManagerService::OnLogOutSuccess";
+ list_accounts_stale_ = true;
+
fetcher_backoff_.InformOfRequest(true);
HandleNextRequest();
}
@@ -660,7 +708,8 @@ void GaiaCookieManagerService::StartFetchingUbertoken() {
void GaiaCookieManagerService::StartFetchingMergeSession() {
DCHECK(!uber_token_.empty());
gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
- this, source_, signin_client_->GetURLRequestContext()));
+ this, GetSourceForRequest(requests_.front(), source_),
+ signin_client_->GetURLRequestContext()));
gaia_auth_fetcher_->StartMergeSession(uber_token_,
external_cc_result_fetcher_.GetExternalCcResult());
@@ -670,14 +719,16 @@ void GaiaCookieManagerService::StartFetchingLogOut() {
DCHECK(requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT);
VLOG(1) << "GaiaCookieManagerService::StartFetchingLogOut";
gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
- this, source_, signin_client_->GetURLRequestContext()));
+ this, GetSourceForRequest(requests_.front(), source_),
+ signin_client_->GetURLRequestContext()));
gaia_auth_fetcher_->StartLogOut();
}
void GaiaCookieManagerService::StartFetchingListAccounts() {
VLOG(1) << "GaiaCookieManagerService::ListAccounts";
gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
- this, source_, signin_client_->GetURLRequestContext()));
+ this, GetSourceForRequest(requests_.front(), source_),
+ signin_client_->GetURLRequestContext()));
gaia_auth_fetcher_->StartListAccounts();
}
@@ -719,6 +770,6 @@ void GaiaCookieManagerService::HandleNextRequest() {
base::Bind(&GaiaCookieManagerService::StartFetchingListAccounts,
base::Unretained(this)));
break;
- };
+ }
}
}
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service.h b/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
index f14f1cae0f9..47c673fc8b1 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
@@ -2,10 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_GAIA_COOKIE_MANAGER_SERVICE_H
-#define COMPONENTS_SIGNIN_CORE_BROWSER_GAIA_COOKIE_MANAGER_SERVICE_H
+#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_GAIA_COOKIE_MANAGER_SERVICE_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_GAIA_COOKIE_MANAGER_SERVICE_H_
#include <deque>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
#include "base/macros.h"
#include "base/observer_list.h"
@@ -51,19 +56,24 @@ class GaiaCookieManagerService : public KeyedService,
GaiaCookieRequestType request_type() const { return request_type_; }
const std::string& account_id() const {return account_id_; }
+ const std::string& source() const {return source_; }
static GaiaCookieRequest CreateAddAccountRequest(
- const std::string& account_id);
- static GaiaCookieRequest CreateLogOutRequest();
- static GaiaCookieRequest CreateListAccountsRequest();
+ const std::string& account_id,
+ const std::string& source);
+ static GaiaCookieRequest CreateLogOutRequest(const std::string& source);
+ static GaiaCookieRequest CreateListAccountsRequest(
+ const std::string& source);
private:
GaiaCookieRequest(
GaiaCookieRequestType request_type,
- const std::string& account_id);
+ const std::string& account_id,
+ const std::string& source);
GaiaCookieRequestType request_type_;
std::string account_id_;
+ std::string source_;
};
class Observer {
@@ -104,7 +114,7 @@ class GaiaCookieManagerService : public KeyedService,
// Maps tokens to the fetched result for that token.
typedef std::map<std::string, std::string> ResultMap;
- ExternalCcResultFetcher(GaiaCookieManagerService* helper);
+ explicit ExternalCcResultFetcher(GaiaCookieManagerService* helper);
~ExternalCcResultFetcher() override;
// Gets the current value of the external connection check result string.
@@ -161,9 +171,11 @@ class GaiaCookieManagerService : public KeyedService,
void Init();
void Shutdown() override;
- void AddAccountToCookie(const std::string& account_id);
+ void AddAccountToCookie(const std::string& account_id,
+ const std::string& source);
void AddAccountToCookieWithToken(const std::string& account_id,
- const std::string& access_token);
+ const std::string& access_token,
+ const std::string& source);
// Returns if the listed accounts are up to date or not (ignore the out
// parameter if return is false). The parameter will be assigned the current
@@ -172,11 +184,12 @@ class GaiaCookieManagerService : public KeyedService,
// If either of |accounts| or |signed_out_accounts| is null, the corresponding
// accounts returned from /ListAccounts are ignored.
bool ListAccounts(std::vector<gaia::ListedAccount>* accounts,
- std::vector<gaia::ListedAccount>* signed_out_accounts);
+ std::vector<gaia::ListedAccount>* signed_out_accounts,
+ const std::string& source);
// Triggers a ListAccounts fetch. This is public so that callers that know
// that a check which GAIA should be done can force it.
- void TriggerListAccounts();
+ void TriggerListAccounts(const std::string& source);
// Forces the processing of OnCookieChanged. This is public so that callers
// that know the GAIA APISID cookie might have changed can inform the
@@ -191,7 +204,7 @@ class GaiaCookieManagerService : public KeyedService,
void CancelAll();
// Signout all accounts.
- void LogOutAllAccounts();
+ void LogOutAllAccounts(const std::string& source);
// Call observers when merge session completes. This public so that callers
// that know that a given account is already in the cookie jar can simply
@@ -221,9 +234,16 @@ class GaiaCookieManagerService : public KeyedService,
return signin_client_->GetURLRequestContext();
}
+ // Returns the source value to use for GaiaFetcher requests. This is
+ // virtual to allow tests and fake classes to override.
+ virtual std::string GetSourceForRequest(
+ const GaiaCookieManagerService::GaiaCookieRequest& request,
+ const std::string& source_default);
+
// Called when a cookie changes. If the cookie relates to a GAIA APISID
// cookie, then we call ListAccounts and fire OnGaiaAccountsInCookieUpdated.
- void OnCookieChanged(const net::CanonicalCookie& cookie, bool removed);
+ void OnCookieChanged(const net::CanonicalCookie& cookie,
+ net::CookieStore::ChangeCause cause);
// Overridden from UbertokenConsumer.
void OnUbertokenSuccess(const std::string& token) override;
@@ -238,7 +258,8 @@ class GaiaCookieManagerService : public KeyedService,
void OnLogOutFailure(const GoogleServiceAuthError& error) override;
// Helper method for AddAccountToCookie* methods.
- void AddAccountToCookieInternal(const std::string& account_id);
+ void AddAccountToCookieInternal(const std::string& account_id,
+ const std::string& source);
// Starts the proess of fetching the uber token and performing a merge session
// for the next account. Virtual so that it can be overriden in tests.
@@ -301,4 +322,4 @@ class GaiaCookieManagerService : public KeyedService,
DISALLOW_COPY_AND_ASSIGN(GaiaCookieManagerService);
};
-#endif // COMPONENTS_SIGNIN_CORE_BROWSER_GAIA_COOKIE_MANAGER_SERVICE_H
+#endif // COMPONENTS_SIGNIN_CORE_BROWSER_GAIA_COOKIE_MANAGER_SERVICE_H_
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc b/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
index 9e5f896f956..b490a9f8b3e 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
@@ -179,7 +179,7 @@ TEST_F(GaiaCookieManagerServiceTest, Success) {
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
no_error()));
- helper.AddAccountToCookie("acc1@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token");
}
@@ -192,7 +192,7 @@ TEST_F(GaiaCookieManagerServiceTest, FailedMergeSession) {
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
error()));
- helper.AddAccountToCookie("acc1@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionFailure(&helper, error());
// Persistent error incurs no further retries.
DCHECK(!helper.is_running());
@@ -208,7 +208,7 @@ TEST_F(GaiaCookieManagerServiceTest, AddAccountCookiesDisabled) {
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
canceled()));
- helper.AddAccountToCookie("acc1@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
}
TEST_F(GaiaCookieManagerServiceTest, MergeSessionRetried) {
@@ -220,7 +220,7 @@ TEST_F(GaiaCookieManagerServiceTest, MergeSessionRetried) {
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
no_error()));
- helper.AddAccountToCookie("acc1@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionFailure(&helper, canceled());
DCHECK(helper.is_running());
// Transient error incurs a retry after 1 second.
@@ -242,7 +242,7 @@ TEST_F(GaiaCookieManagerServiceTest, MergeSessionRetriedTwice) {
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
no_error()));
- helper.AddAccountToCookie("acc1@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionFailure(&helper, canceled());
DCHECK(helper.is_running());
// Transient error incurs a retry after 1 second.
@@ -275,7 +275,7 @@ TEST_F(GaiaCookieManagerServiceTest, FailedUbertoken) {
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
error()));
- helper.AddAccountToCookie("acc1@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
SimulateUbertokenFailure(&helper, error());
}
@@ -289,8 +289,8 @@ TEST_F(GaiaCookieManagerServiceTest, ContinueAfterSuccess) {
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
no_error()));
- helper.AddAccountToCookie("acc1@gmail.com");
- helper.AddAccountToCookie("acc2@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
SimulateMergeSessionSuccess(&helper, "token2");
}
@@ -305,8 +305,8 @@ TEST_F(GaiaCookieManagerServiceTest, ContinueAfterFailure1) {
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
no_error()));
- helper.AddAccountToCookie("acc1@gmail.com");
- helper.AddAccountToCookie("acc2@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionFailure(&helper, error());
SimulateMergeSessionSuccess(&helper, "token2");
}
@@ -321,8 +321,8 @@ TEST_F(GaiaCookieManagerServiceTest, ContinueAfterFailure2) {
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
no_error()));
- helper.AddAccountToCookie("acc1@gmail.com");
- helper.AddAccountToCookie("acc2@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
SimulateUbertokenFailure(&helper, error());
SimulateMergeSessionSuccess(&helper, "token2");
}
@@ -334,17 +334,17 @@ TEST_F(GaiaCookieManagerServiceTest, AllRequestsInMultipleGoes) {
EXPECT_CALL(helper, StartFetchingUbertoken()).Times(4);
EXPECT_CALL(observer, OnAddAccountToCookieCompleted(_, no_error())).Times(4);
- helper.AddAccountToCookie("acc1@gmail.com");
- helper.AddAccountToCookie("acc2@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
- helper.AddAccountToCookie("acc3@gmail.com");
+ helper.AddAccountToCookie("acc3@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token2");
SimulateMergeSessionSuccess(&helper, "token3");
- helper.AddAccountToCookie("acc4@gmail.com");
+ helper.AddAccountToCookie("acc4@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token4");
}
@@ -358,10 +358,10 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsNoQueue) {
no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
- helper.AddAccountToCookie("acc2@gmail.com");
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
- helper.LogOutAllAccounts();
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
SimulateLogOutSuccess(&helper);
ASSERT_FALSE(helper.is_running());
}
@@ -375,10 +375,10 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsFails) {
no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
- helper.AddAccountToCookie("acc2@gmail.com");
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
- helper.LogOutAllAccounts();
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
SimulateLogOutFailure(&helper, error());
// CookieManagerService is still running; it is retrying the failed logout.
ASSERT_TRUE(helper.is_running());
@@ -393,8 +393,8 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsAfterOneAddInQueue) {
no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
- helper.AddAccountToCookie("acc2@gmail.com");
- helper.LogOutAllAccounts();
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
SimulateLogOutSuccess(&helper);
@@ -411,10 +411,10 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsAfterTwoAddsInQueue) {
canceled()));
EXPECT_CALL(helper, StartFetchingLogOut());
- helper.AddAccountToCookie("acc1@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
// The Log Out should prevent this AddAccount from being fetched.
- helper.AddAccountToCookie("acc2@gmail.com");
- helper.LogOutAllAccounts();
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
SimulateLogOutSuccess(&helper);
@@ -429,12 +429,12 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsTwice) {
no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
- helper.AddAccountToCookie("acc2@gmail.com");
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
- helper.LogOutAllAccounts();
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
// Only one LogOut will be fetched.
- helper.LogOutAllAccounts();
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
SimulateLogOutSuccess(&helper);
}
@@ -448,11 +448,11 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsBeforeAdd) {
EXPECT_CALL(helper, StartFetchingLogOut());
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc3@gmail.com",
no_error()));
- helper.AddAccountToCookie("acc2@gmail.com");
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
- helper.LogOutAllAccounts();
- helper.AddAccountToCookie("acc3@gmail.com");
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
+ helper.AddAccountToCookie("acc3@gmail.com", GaiaConstants::kChromeSource);
SimulateLogOutSuccess(&helper);
// After LogOut the MergeSession should be fetched.
@@ -471,13 +471,13 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsBeforeLogoutAndAdd) {
EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc3@gmail.com",
no_error()));
- helper.AddAccountToCookie("acc2@gmail.com");
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
- helper.LogOutAllAccounts();
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
// Second LogOut will never be fetched.
- helper.LogOutAllAccounts();
- helper.AddAccountToCookie("acc3@gmail.com");
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
+ helper.AddAccountToCookie("acc3@gmail.com", GaiaConstants::kChromeSource);
SimulateLogOutSuccess(&helper);
// After LogOut the MergeSession should be fetched.
@@ -500,13 +500,13 @@ TEST_F(GaiaCookieManagerServiceTest, PendingSigninThenSignout) {
// Total sign in 2 times, not enforcing ordered sequences.
EXPECT_CALL(helper, StartFetchingUbertoken()).Times(2);
- helper.AddAccountToCookie("acc1@gmail.com");
- helper.LogOutAllAccounts();
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
SimulateLogOutSuccess(&helper);
- helper.AddAccountToCookie("acc3@gmail.com");
+ helper.AddAccountToCookie("acc3@gmail.com", GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token3");
}
@@ -521,9 +521,9 @@ TEST_F(GaiaCookieManagerServiceTest, CancelSignIn) {
no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
- helper.AddAccountToCookie("acc1@gmail.com");
- helper.AddAccountToCookie("acc2@gmail.com");
- helper.LogOutAllAccounts();
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
+ helper.LogOutAllAccounts(GaiaConstants::kChromeSource);
SimulateMergeSessionSuccess(&helper, "token1");
SimulateLogOutSuccess(&helper);
@@ -538,7 +538,8 @@ TEST_F(GaiaCookieManagerServiceTest, ListAccountsFirstReturnsEmpty) {
EXPECT_CALL(helper, StartFetchingListAccounts());
- ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts));
+ ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts,
+ GaiaConstants::kChromeSource));
ASSERT_TRUE(list_accounts.empty());
ASSERT_TRUE(signed_out_accounts.empty());
}
@@ -564,7 +565,8 @@ TEST_F(GaiaCookieManagerServiceTest, ListAccountsFindsOneAccount) {
EXPECT_CALL(observer, OnGaiaAccountsInCookieUpdated(
expected_accounts, expected_signed_out_accounts, no_error()));
- ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts));
+ ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts,
+ GaiaConstants::kChromeSource));
SimulateListAccountsSuccess(&helper,
"[\"f\", [[\"b\", 0, \"n\", \"a@b.com\", \"p\", 0, 0, 0, 0, 1, \"8\"]]]");
@@ -598,7 +600,8 @@ TEST_F(GaiaCookieManagerServiceTest, ListAccountsFindsSignedOutAccounts) {
EXPECT_CALL(observer, OnGaiaAccountsInCookieUpdated(
expected_accounts, expected_signed_out_accounts, no_error()));
- ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts));
+ ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts,
+ GaiaConstants::kChromeSource));
SimulateListAccountsSuccess(&helper,
"[\"f\","
@@ -611,7 +614,8 @@ TEST_F(GaiaCookieManagerServiceTest, ListAccountsAcceptsNull) {
InstrumentedGaiaCookieManagerService helper(token_service(), signin_client());
MockObserver observer(&helper);
- ASSERT_FALSE(helper.ListAccounts(nullptr, nullptr));
+ ASSERT_FALSE(helper.ListAccounts(nullptr, nullptr,
+ GaiaConstants::kChromeSource));
SimulateListAccountsSuccess(&helper,
"[\"f\","
@@ -620,11 +624,13 @@ TEST_F(GaiaCookieManagerServiceTest, ListAccountsAcceptsNull) {
"null,null,null,1]]]");
std::vector<gaia::ListedAccount> signed_out_accounts;
- ASSERT_TRUE(helper.ListAccounts(nullptr, &signed_out_accounts));
+ ASSERT_TRUE(helper.ListAccounts(nullptr, &signed_out_accounts,
+ GaiaConstants::kChromeSource));
ASSERT_EQ(1u, signed_out_accounts.size());
std::vector<gaia::ListedAccount> accounts;
- ASSERT_TRUE(helper.ListAccounts(&accounts, nullptr));
+ ASSERT_TRUE(helper.ListAccounts(&accounts, nullptr,
+ GaiaConstants::kChromeSource));
ASSERT_EQ(1u, accounts.size());
}
@@ -641,13 +647,15 @@ TEST_F(GaiaCookieManagerServiceTest, ListAccountsAfterOnCookieChanged) {
EXPECT_CALL(observer,
OnGaiaAccountsInCookieUpdated(
empty_list_accounts, empty_signed_out_accounts, no_error()));
- ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts));
+ ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts,
+ GaiaConstants::kChromeSource));
ASSERT_TRUE(list_accounts.empty());
ASSERT_TRUE(signed_out_accounts.empty());
SimulateListAccountsSuccess(&helper, "[\"f\",[]]");
// ListAccounts returns cached data.
- ASSERT_TRUE(helper.ListAccounts(&list_accounts, &signed_out_accounts));
+ ASSERT_TRUE(helper.ListAccounts(&list_accounts, &signed_out_accounts,
+ GaiaConstants::kChromeSource));
ASSERT_TRUE(list_accounts.empty());
ASSERT_TRUE(signed_out_accounts.empty());
@@ -658,7 +666,8 @@ TEST_F(GaiaCookieManagerServiceTest, ListAccountsAfterOnCookieChanged) {
helper.ForceOnCookieChangedProcessing();
// OnCookieChanged should invalidate cached data.
- ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts));
+ ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts,
+ GaiaConstants::kChromeSource));
ASSERT_TRUE(list_accounts.empty());
ASSERT_TRUE(signed_out_accounts.empty());
SimulateListAccountsSuccess(&helper, "[\"f\",[]]");
@@ -755,7 +764,7 @@ TEST_F(GaiaCookieManagerServiceTest, UbertokenSuccessFetchesExternalCC) {
InstrumentedGaiaCookieManagerService helper(token_service(), signin_client());
EXPECT_CALL(helper, StartFetchingUbertoken());
- helper.AddAccountToCookie("acc1@gmail.com");
+ helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
ASSERT_FALSE(factory()->GetFetcherByID(0));
SimulateUbertokenSuccess(&helper, "token");
@@ -780,7 +789,7 @@ TEST_F(GaiaCookieManagerServiceTest, UbertokenSuccessFetchesExternalCCOnce) {
helper.external_cc_result_fetcher_for_testing()->Start();
EXPECT_CALL(helper, StartFetchingUbertoken());
- helper.AddAccountToCookie("acc2@gmail.com");
+ helper.AddAccountToCookie("acc2@gmail.com", GaiaConstants::kChromeSource);
// There is already a ExternalCCResultFetch underway. This will trigger
// StartFetchingMergeSession.
EXPECT_CALL(helper, StartFetchingMergeSession());
diff --git a/chromium/components/signin/core/browser/signin_cookie_changed_subscription.cc b/chromium/components/signin/core/browser/signin_cookie_changed_subscription.cc
index bfcfde49dcf..3f432525937 100644
--- a/chromium/components/signin/core/browser/signin_cookie_changed_subscription.cc
+++ b/chromium/components/signin/core/browser/signin_cookie_changed_subscription.cc
@@ -87,19 +87,17 @@ void SigninCookieChangedSubscription::RunAsyncOnCookieChanged(
scoped_refptr<base::TaskRunner> proxy,
base::WeakPtr<SigninCookieChangedSubscription> subscription,
const net::CanonicalCookie& cookie,
- bool removed) {
+ net::CookieStore::ChangeCause cause) {
proxy->PostTask(FROM_HERE,
base::Bind(&SigninCookieChangedSubscription::OnCookieChanged,
- subscription,
- cookie,
- removed));
+ subscription, cookie, cause));
}
void SigninCookieChangedSubscription::OnCookieChanged(
const net::CanonicalCookie& cookie,
- bool removed) {
+ net::CookieStore::ChangeCause cause) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!callback_.is_null()) {
- callback_.Run(cookie, removed);
+ callback_.Run(cookie, cause);
}
}
diff --git a/chromium/components/signin/core/browser/signin_cookie_changed_subscription.h b/chromium/components/signin/core/browser/signin_cookie_changed_subscription.h
index e0ad83c5fce..d1569863c22 100644
--- a/chromium/components/signin/core/browser/signin_cookie_changed_subscription.h
+++ b/chromium/components/signin/core/browser/signin_cookie_changed_subscription.h
@@ -55,10 +55,11 @@ class SigninCookieChangedSubscription
scoped_refptr<base::TaskRunner> proxy,
base::WeakPtr<SigninCookieChangedSubscription> subscription,
const net::CanonicalCookie& cookie,
- bool removed);
+ net::CookieStore::ChangeCause cause);
// Handler for cookie changed events.
- void OnCookieChanged(const net::CanonicalCookie& cookie, bool removed);
+ void OnCookieChanged(const net::CanonicalCookie& cookie,
+ net::CookieStore::ChangeCause cause);
// The context getter.
scoped_refptr<net::URLRequestContextGetter> context_getter_;
diff --git a/chromium/components/signin/core/browser/signin_error_controller_unittest.cc b/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
index d0cffdd0912..7a3b3e85008 100644
--- a/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
@@ -153,7 +153,7 @@ TEST_F(SigninErrorControllerTest, AuthStatusEnumerateAllErrors) {
{ GoogleServiceAuthError::SERVICE_UNAVAILABLE, true },
{ GoogleServiceAuthError::TWO_FACTOR, true },
{ GoogleServiceAuthError::REQUEST_CANCELED, true },
- { GoogleServiceAuthError::HOSTED_NOT_ALLOWED, true },
+ { GoogleServiceAuthError::HOSTED_NOT_ALLOWED_DEPRECATED, false },
{ GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE, true },
{ GoogleServiceAuthError::SERVICE_ERROR, true },
{ GoogleServiceAuthError::WEB_LOGIN_REQUIRED, true },
@@ -162,6 +162,8 @@ TEST_F(SigninErrorControllerTest, AuthStatusEnumerateAllErrors) {
"table array does not match the number of auth error types");
for (size_t i = 0; i < arraysize(table); ++i) {
+ if (GoogleServiceAuthError::IsDeprecated(table[i].error_state))
+ continue;
FakeAuthStatusProvider provider(error_controller_.get());
provider.SetAuthError(kTestAccountId,
GoogleServiceAuthError(table[i].error_state));
diff --git a/chromium/components/signin/core/browser/signin_header_helper.cc b/chromium/components/signin/core/browser/signin_header_helper.cc
index 578cb5806cf..0d192ea5668 100644
--- a/chromium/components/signin/core/browser/signin_header_helper.cc
+++ b/chromium/components/signin/core/browser/signin_header_helper.cc
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "components/content_settings/core/browser/cookie_settings.h"
@@ -17,6 +18,7 @@
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/base/escape.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"
@@ -26,7 +28,6 @@ namespace {
// Dictionary of fields in a mirror response header.
typedef std::map<std::string, std::string> MirrorResponseHeaderDictionary;
-const char kChromeConnectedHeader[] = "X-Chrome-Connected";
const char kChromeManageAccountsHeader[] = "X-Chrome-Manage-Accounts";
const char kContinueUrlAttrName[] = "continue_url";
const char kEmailAttrName[] = "email";
@@ -46,6 +47,23 @@ bool IsDriveOrigin(const GURL& url) {
return url == kGoogleDriveURL || url == kGoogleDocsURL;
}
+bool IsUrlEligibleToIncludeGaiaId(const GURL& url, bool is_header_request) {
+ if (is_header_request) {
+ // GAIA Id is only necessary for Drive. Don't set it otherwise.
+ return IsDriveOrigin(url.GetOrigin());
+ }
+
+ // Cookie requests don't have the granularity to only include the GAIA Id for
+ // Drive origin. Set it on all google.com instead.
+ if (!url.SchemeIsCryptographic())
+ return false;
+
+ const std::string kGoogleDomain = "google.com";
+ std::string domain = net::registry_controlled_domains::GetDomainAndRegistry(
+ url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
+ return domain == kGoogleDomain;
+}
+
// Determines the service type that has been passed from GAIA in the header.
signin::GAIAServiceType GetGAIAServiceTypeFromHeader(
const std::string& header_value) {
@@ -87,7 +105,7 @@ MirrorResponseHeaderDictionary ParseMirrorResponseHeader(
}
std::string BuildMirrorRequestIfPossible(
- const char* pattern,
+ bool is_header_request,
const GURL& url,
const std::string& account_id,
const content_settings::CookieSettings* cookie_settings,
@@ -100,38 +118,32 @@ std::string BuildMirrorRequestIfPossible(
return std::string();
}
- // Only set the header for Drive and Gaia always, and other Google properties
- // if account consistency is enabled.
- // Vasquette, which is integrated with most Google properties, needs the
- // header to redirect certain user actions to Chrome native UI. Drive and Gaia
- // need the header to tell if the current user is connected. The drive path is
- // a temporary workaround until the more generic chrome.principals API is
- // available.
- GURL origin(url.GetOrigin());
- bool is_enable_account_consistency = switches::IsEnableAccountConsistency();
- bool is_google_url = is_enable_account_consistency &&
- (google_util::IsGoogleDomainUrl(
- url, google_util::ALLOW_SUBDOMAIN,
- google_util::DISALLOW_NON_STANDARD_PORTS) ||
- google_util::IsYoutubeDomainUrl(
- url, google_util::ALLOW_SUBDOMAIN,
- google_util::DISALLOW_NON_STANDARD_PORTS));
- if (!is_google_url && !IsDriveOrigin(origin) &&
- !gaia::IsGaiaSignonRealm(origin)) {
+ // Check if url is elligible for the header.
+ if (!signin::IsUrlEligibleForXChromeConnectedHeader(url))
return std::string();
+
+ std::vector<std::string> parts;
+ if (IsUrlEligibleToIncludeGaiaId(url, is_header_request)) {
+ // Only set the GAIA Id on domains that actually requires it.
+ parts.push_back(
+ base::StringPrintf("%s=%s", kGaiaIdAttrName, account_id.c_str()));
}
+ parts.push_back(
+ base::StringPrintf("%s=%s", kProfileModeAttrName,
+ base::IntToString(profile_mode_mask).c_str()));
+ parts.push_back(base::StringPrintf(
+ "%s=%s", kEnableAccountConsistencyAttrName,
+ switches::IsEnableAccountConsistency() ? "true" : "false"));
- return base::StringPrintf(pattern, kGaiaIdAttrName, account_id.c_str(),
- kProfileModeAttrName,
- base::IntToString(profile_mode_mask).c_str(),
- kEnableAccountConsistencyAttrName,
- is_enable_account_consistency ? "true" : "false");
+ return base::JoinString(parts, is_header_request ? "," : ":");
}
} // namespace
namespace signin {
+extern const char kChromeConnectedHeader[] = "X-Chrome-Connected";
+
ManageAccountsParams::ManageAccountsParams()
: service_type(GAIA_SERVICE_TYPE_NONE),
email(""),
@@ -161,11 +173,12 @@ std::string BuildMirrorRequestCookieIfPossible(
const std::string& account_id,
const content_settings::CookieSettings* cookie_settings,
int profile_mode_mask) {
- return BuildMirrorRequestIfPossible("%s=%s:%s=%s:%s=%s", url, account_id,
- cookie_settings, profile_mode_mask);
- }
+ return BuildMirrorRequestIfPossible(false /* is_header_request */, url,
+ account_id, cookie_settings,
+ profile_mode_mask);
+}
-bool AppendMirrorRequestHeaderIfPossible(
+bool AppendOrRemoveMirrorRequestHeaderIfPossible(
net::URLRequest* request,
const GURL& redirect_url,
const std::string& account_id,
@@ -173,9 +186,21 @@ bool AppendMirrorRequestHeaderIfPossible(
int profile_mode_mask) {
const GURL& url = redirect_url.is_empty() ? request->url() : redirect_url;
std::string header_value = BuildMirrorRequestIfPossible(
- "%s=%s,%s=%s,%s=%s", url, account_id, cookie_settings, profile_mode_mask);
- if (header_value.empty())
+ true /* is_header_request */, url, account_id, cookie_settings,
+ profile_mode_mask);
+ if (header_value.empty()) {
+ // If the request is being redirected, and it has the x-chrome-connected
+ // header, and current url is a Google URL, and the redirected one is not,
+ // remove the header.
+ if (!redirect_url.is_empty() &&
+ request->extra_request_headers().HasHeader(
+ signin::kChromeConnectedHeader) &&
+ signin::IsUrlEligibleForXChromeConnectedHeader(request->url()) &&
+ !signin::IsUrlEligibleForXChromeConnectedHeader(redirect_url)) {
+ request->RemoveRequestHeaderByName(signin::kChromeConnectedHeader);
+ }
return false;
+ }
request->SetExtraRequestHeaderByName(kChromeConnectedHeader, header_value,
false);
return true;
@@ -215,7 +240,9 @@ ManageAccountsParams BuildManageAccountsParamsIfExists(net::URLRequest* request,
return empty_params;
std::string header_value;
- if (!request->response_headers()->GetNormalizedHeader(
+ net::HttpResponseHeaders* response_headers = request->response_headers();
+ if (!response_headers ||
+ !response_headers->GetNormalizedHeader(
kChromeManageAccountsHeader, &header_value)) {
return empty_params;
}
@@ -224,4 +251,32 @@ ManageAccountsParams BuildManageAccountsParamsIfExists(net::URLRequest* request,
return BuildManageAccountsParams(header_value);
}
+// Checks if the url has the required properties to have an
+// X-Chrome-Connected header.
+bool IsUrlEligibleForXChromeConnectedHeader(const GURL& url) {
+ // Only set the header for Drive and Gaia always, and other Google properties
+ // if account consistency is enabled.
+ // Vasquette, which is integrated with most Google properties, needs the
+ // header to redirect certain user actions to Chrome native UI. Drive and Gaia
+ // need the header to tell if the current user is connected. The drive path is
+ // a temporary workaround until the more generic chrome.principals API is
+ // available.
+
+ // Consider the account id sensitive and limit it to secure domains.
+ if (!url.SchemeIsCryptographic())
+ return false;
+
+ GURL origin(url.GetOrigin());
+ bool is_enable_account_consistency = switches::IsEnableAccountConsistency();
+ bool is_google_url = is_enable_account_consistency &&
+ (google_util::IsGoogleDomainUrl(
+ url, google_util::ALLOW_SUBDOMAIN,
+ google_util::DISALLOW_NON_STANDARD_PORTS) ||
+ google_util::IsYoutubeDomainUrl(
+ url, google_util::ALLOW_SUBDOMAIN,
+ google_util::DISALLOW_NON_STANDARD_PORTS));
+ return is_google_url || IsDriveOrigin(origin) ||
+ gaia::IsGaiaSignonRealm(origin);
+}
+
} // namespace signin
diff --git a/chromium/components/signin/core/browser/signin_header_helper.h b/chromium/components/signin/core/browser/signin_header_helper.h
index 8d5d37c1fdc..9f000bc6411 100644
--- a/chromium/components/signin/core/browser/signin_header_helper.h
+++ b/chromium/components/signin/core/browser/signin_header_helper.h
@@ -30,6 +30,8 @@ enum ProfileMode {
PROFILE_MODE_ADD_ACCOUNT_DISABLED = 1 << 1
};
+extern const char kChromeConnectedHeader[];
+
// The ServiceType specified by GAIA in the response header accompanying the 204
// response. This indicates the action Chrome is supposed to lead the user to
// perform.
@@ -73,7 +75,11 @@ struct ManageAccountsParams {
bool SettingsAllowSigninCookies(
const content_settings::CookieSettings* cookie_settings);
-// Returns the X-CHROME-CONNECTED cookie, or an empty string if it should not be
+// Checks if the url has the required properties to have an
+// X-Chrome-Connected header.
+bool IsUrlEligibleForXChromeConnectedHeader(const GURL& url);
+
+// Returns the CHROME_CONNECTED cookie, or an empty string if it should not be
// added to the request to |url|.
std::string BuildMirrorRequestCookieIfPossible(
const GURL& url,
@@ -83,8 +89,8 @@ std::string BuildMirrorRequestCookieIfPossible(
// Adds X-Chrome-Connected header to all Gaia requests from a connected profile,
// with the exception of requests from gaia webview.
-// Returns true if the account management header was added to the request.
-bool AppendMirrorRequestHeaderIfPossible(
+// Removes the header in case it should not be transfered to a redirected url.
+bool AppendOrRemoveMirrorRequestHeaderIfPossible(
net::URLRequest* request,
const GURL& redirect_url,
const std::string& account_id,
diff --git a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
new file mode 100644
index 00000000000..cd560ab5ee4
--- /dev/null
+++ b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -0,0 +1,200 @@
+// 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 <memory>
+
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/pref_registry/testing_pref_service_syncable.h"
+#include "components/signin/core/browser/signin_header_helper.h"
+#include "components/signin/core/common/signin_switches.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+class SigninHeaderHelperTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ content_settings::CookieSettings::RegisterProfilePrefs(prefs_.registry());
+ HostContentSettingsMap::RegisterProfilePrefs(prefs_.registry());
+
+ settings_map_ = new HostContentSettingsMap(
+ &prefs_, false /* incognito_profile */, false /* guest_profile */);
+ cookie_settings_ =
+ new content_settings::CookieSettings(settings_map_.get(), &prefs_, "");
+ }
+
+ void TearDown() override { settings_map_->ShutdownOnUIThread(); }
+
+ void CheckMirrorCookieRequest(const GURL& url,
+ const std::string& account_id,
+ const std::string& expected_request) {
+ EXPECT_EQ(signin::BuildMirrorRequestCookieIfPossible(
+ url, account_id, cookie_settings_.get(),
+ signin::PROFILE_MODE_DEFAULT),
+ expected_request);
+ }
+
+ void CheckMirrorHeaderRequest(const GURL& url,
+ const std::string& account_id,
+ const std::string& expected_request) {
+ bool expected_result = !expected_request.empty();
+ std::unique_ptr<net::URLRequest> url_request =
+ url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr);
+ EXPECT_EQ(signin::AppendOrRemoveMirrorRequestHeaderIfPossible(
+ url_request.get(), GURL(), account_id, cookie_settings_.get(),
+ signin::PROFILE_MODE_DEFAULT),
+ expected_result);
+ std::string request;
+ EXPECT_EQ(url_request->extra_request_headers().GetHeader(
+ signin::kChromeConnectedHeader, &request),
+ expected_result);
+ if (expected_result) {
+ EXPECT_EQ(expected_request, request);
+ }
+ }
+
+ base::MessageLoop loop_;
+
+ user_prefs::TestingPrefServiceSyncable prefs_;
+ net::TestURLRequestContext url_request_context_;
+
+ scoped_refptr<HostContentSettingsMap> settings_map_;
+ scoped_refptr<content_settings::CookieSettings> cookie_settings_;
+};
+
+// Tests that no Mirror request is returned when the user is not signed in (no
+// account id).
+TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestNoAccountId) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAccountConsistency);
+ CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "", "");
+ CheckMirrorCookieRequest(GURL("https://docs.google.com"), "", "");
+}
+
+// Tests that no Mirror request is returned when the cookies aren't allowed to
+// be set.
+TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestCookieSettingBlocked) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAccountConsistency);
+ cookie_settings_->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
+ CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "0123456789", "");
+ CheckMirrorCookieRequest(GURL("https://docs.google.com"), "0123456789", "");
+}
+
+// Tests that no Mirror request is returned when the target is a non-Google URL.
+TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestExternalURL) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAccountConsistency);
+ CheckMirrorHeaderRequest(GURL("https://foo.com"), "0123456789", "");
+ CheckMirrorCookieRequest(GURL("https://foo.com"), "0123456789", "");
+}
+
+// Tests that the Mirror request is returned without the GAIA Id when the target
+// is a google TLD domain.
+TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleTLD) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAccountConsistency);
+ CheckMirrorHeaderRequest(GURL("https://google.fr"), "0123456789",
+ "mode=0,enable_account_consistency=true");
+ CheckMirrorCookieRequest(GURL("https://google.de"), "0123456789",
+ "mode=0:enable_account_consistency=true");
+}
+
+// Tests that the Mirror request is returned when the target is the domain
+// google.com, and that the GAIA Id is only attached for the cookie.
+TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleCom) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAccountConsistency);
+ CheckMirrorHeaderRequest(GURL("https://www.google.com"), "0123456789",
+ "mode=0,enable_account_consistency=true");
+ CheckMirrorCookieRequest(
+ GURL("https://www.google.com"), "0123456789",
+ "id=0123456789:mode=0:enable_account_consistency=true");
+}
+
+// Tests that the Mirror request is returned with the GAIA Id on Drive origin,
+// even if account consistency is disabled.
+TEST_F(SigninHeaderHelperTest, TestMirrorRequestDrive) {
+ DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableAccountConsistency));
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kDisableAccountConsistency);
+ CheckMirrorHeaderRequest(
+ GURL("https://docs.google.com/document"), "0123456789",
+ "id=0123456789,mode=0,enable_account_consistency=false");
+ CheckMirrorCookieRequest(
+ GURL("https://drive.google.com/drive"), "0123456789",
+ "id=0123456789:mode=0:enable_account_consistency=false");
+
+ // Enable Account Consistency will override the disable.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAccountConsistency);
+ CheckMirrorHeaderRequest(
+ GURL("https://docs.google.com/document"), "0123456789",
+ "id=0123456789,mode=0,enable_account_consistency=true");
+ CheckMirrorCookieRequest(
+ GURL("https://drive.google.com/drive"), "0123456789",
+ "id=0123456789:mode=0:enable_account_consistency=true");
+}
+
+// Tests that the Mirror header request is returned normally when the redirect
+// URL is eligible.
+TEST_F(SigninHeaderHelperTest, TestMirrorHeaderEligibleRedirectURL) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAccountConsistency);
+
+ const GURL url("https://docs.google.com/document");
+ const GURL redirect_url("https://www.google.com");
+ const std::string account_id = "0123456789";
+ std::unique_ptr<net::URLRequest> url_request =
+ url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr);
+ EXPECT_TRUE(signin::AppendOrRemoveMirrorRequestHeaderIfPossible(
+ url_request.get(), redirect_url, account_id, cookie_settings_.get(),
+ signin::PROFILE_MODE_DEFAULT));
+ EXPECT_TRUE(url_request->extra_request_headers().HasHeader(
+ signin::kChromeConnectedHeader));
+}
+
+// Tests that the Mirror header request is stripped when the redirect URL is not
+// eligible.
+TEST_F(SigninHeaderHelperTest, TestMirrorHeaderNonEligibleRedirectURL) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAccountConsistency);
+
+ const GURL url("https://docs.google.com/document");
+ const GURL redirect_url("http://www.foo.com");
+ const std::string account_id = "0123456789";
+ std::unique_ptr<net::URLRequest> url_request =
+ url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr);
+ EXPECT_FALSE(signin::AppendOrRemoveMirrorRequestHeaderIfPossible(
+ url_request.get(), redirect_url, account_id, cookie_settings_.get(),
+ signin::PROFILE_MODE_DEFAULT));
+ EXPECT_FALSE(url_request->extra_request_headers().HasHeader(
+ signin::kChromeConnectedHeader));
+}
+
+// Tests that the Mirror header, whatever its value is, is untouched when both
+// the current and the redirect URL are non-eligible.
+TEST_F(SigninHeaderHelperTest, TestIgnoreMirrorHeaderNonEligibleURLs) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAccountConsistency);
+
+ const GURL url("https://www.bar.com");
+ const GURL redirect_url("http://www.foo.com");
+ const std::string account_id = "0123456789";
+ const std::string fake_header = "foo,bar";
+ std::unique_ptr<net::URLRequest> url_request =
+ url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr);
+ url_request->SetExtraRequestHeaderByName(signin::kChromeConnectedHeader,
+ fake_header, false);
+ EXPECT_FALSE(signin::AppendOrRemoveMirrorRequestHeaderIfPossible(
+ url_request.get(), redirect_url, account_id, cookie_settings_.get(),
+ signin::PROFILE_MODE_DEFAULT));
+ std::string header;
+ EXPECT_TRUE(url_request->extra_request_headers().GetHeader(
+ signin::kChromeConnectedHeader, &header));
+ EXPECT_EQ(fake_header, header);
+}
diff --git a/chromium/components/signin/core/browser/signin_manager.cc b/chromium/components/signin/core/browser/signin_manager.cc
index 10e6ce3597e..cb537ec9e6d 100644
--- a/chromium/components/signin/core/browser/signin_manager.cc
+++ b/chromium/components/signin/core/browser/signin_manager.cc
@@ -333,7 +333,8 @@ void SigninManager::MergeSigninCredentialIntoCookieJar() {
if (!IsAuthenticated())
return;
- cookie_manager_service_->AddAccountToCookie(GetAuthenticatedAccountId());
+ cookie_manager_service_->AddAccountToCookie(GetAuthenticatedAccountId(),
+ "ChromiumSigninManager");
}
void SigninManager::CompletePendingSignin() {
diff --git a/chromium/components/signin/core/browser/signin_metrics.h b/chromium/components/signin/core/browser/signin_metrics.h
index 4d227e62690..0ba0eb04b0d 100644
--- a/chromium/components/signin/core/browser/signin_metrics.h
+++ b/chromium/components/signin/core/browser/signin_metrics.h
@@ -140,6 +140,8 @@ enum class AccessPoint : int {
ACCESS_POINT_PASSWORD_BUBBLE,
ACCESS_POINT_AUTOFILL_DROPDOWN,
ACCESS_POINT_NTP_CONTENT_SUGGESTIONS,
+ ACCESS_POINT_RESIGNIN_INFOBAR,
+ ACCESS_POINT_TAB_SWITCHER,
ACCESS_POINT_MAX, // This must be last.
};
diff --git a/chromium/components/signin/core/browser/signin_status_metrics_provider_base.cc b/chromium/components/signin/core/browser/signin_status_metrics_provider_base.cc
index 89f0ab5bc58..3ef29c9c0f3 100644
--- a/chromium/components/signin/core/browser/signin_status_metrics_provider_base.cc
+++ b/chromium/components/signin/core/browser/signin_status_metrics_provider_base.cc
@@ -4,7 +4,7 @@
#include "components/signin/core/browser/signin_status_metrics_provider_base.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
SigninStatusMetricsProviderBase::SigninStatusMetricsProviderBase()
: signin_status_(UNKNOWN_SIGNIN_STATUS) {}
diff --git a/chromium/components/signin/core/browser/test_signin_client.cc b/chromium/components/signin/core/browser/test_signin_client.cc
index cef73eb2435..ad301a6e487 100644
--- a/chromium/components/signin/core/browser/test_signin_client.cc
+++ b/chromium/components/signin/core/browser/test_signin_client.cc
@@ -54,11 +54,11 @@ std::string TestSigninClient::GetProductVersion() { return ""; }
void TestSigninClient::LoadTokenDatabase() {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- base::FilePath path = temp_dir_.path().AppendASCII("TestWebDB");
+ base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
scoped_refptr<WebDatabaseService> web_database =
new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
base::ThreadTaskRunnerHandle::Get());
- web_database->AddTable(base::WrapUnique(new TokenServiceTable()));
+ web_database->AddTable(base::MakeUnique<TokenServiceTable>());
web_database->LoadDatabase();
database_ =
new TokenWebData(web_database, base::ThreadTaskRunnerHandle::Get(),
diff --git a/chromium/components/signin/core/browser/webdata/token_service_table_unittest.cc b/chromium/components/signin/core/browser/webdata/token_service_table_unittest.cc
index fd44a258edf..47391e47637 100644
--- a/chromium/components/signin/core/browser/webdata/token_service_table_unittest.cc
+++ b/chromium/components/signin/core/browser/webdata/token_service_table_unittest.cc
@@ -23,7 +23,7 @@ class TokenServiceTableTest : public testing::Test {
void SetUp() override {
OSCryptMocker::SetUpWithSingleton();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- file_ = temp_dir_.path().AppendASCII("TestWebDatabase");
+ file_ = temp_dir_.GetPath().AppendASCII("TestWebDatabase");
table_.reset(new TokenServiceTable);
db_.reset(new WebDatabase);
diff --git a/chromium/components/signin/core/browser/webdata/token_web_data.cc b/chromium/components/signin/core/browser/webdata/token_web_data.cc
index 679333f9c99..8c390faf642 100644
--- a/chromium/components/signin/core/browser/webdata/token_web_data.cc
+++ b/chromium/components/signin/core/browser/webdata/token_web_data.cc
@@ -50,8 +50,8 @@ class TokenWebDataBackend
std::unique_ptr<WDTypedResult> GetAllTokens(WebDatabase* db) {
std::map<std::string, std::string> map;
TokenServiceTable::FromWebDatabase(db)->GetAllTokens(&map);
- return base::WrapUnique(
- new WDResult<std::map<std::string, std::string>>(TOKEN_RESULT, map));
+ return base::MakeUnique<WDResult<std::map<std::string, std::string>>>(
+ TOKEN_RESULT, map);
}
protected:
diff --git a/chromium/components/signin/core/common/BUILD.gn b/chromium/components/signin/core/common/BUILD.gn
index f34af62a3fa..670bde9c185 100644
--- a/chromium/components/signin/core/common/BUILD.gn
+++ b/chromium/components/signin/core/common/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("common") {
+static_library("common") {
sources = [
"profile_management_switches.cc",
"profile_management_switches.h",
diff --git a/chromium/components/signin/core/common/signin_switches.cc b/chromium/components/signin/core/common/signin_switches.cc
index 70eddfecdaf..9826d61228f 100644
--- a/chromium/components/signin/core/common/signin_switches.cc
+++ b/chromium/components/signin/core/common/signin_switches.cc
@@ -36,12 +36,12 @@ const char kExtensionsMultiAccount[] = "extensions-multi-account";
const char kGoogleProfileInfo[] = "google-profile-info";
const base::Feature kMaterialDesignUserManager {
- "MaterialDesignUserManager", base::FEATURE_DISABLED_BY_DEFAULT
+ "MaterialDesignUserManager", base::FEATURE_ENABLED_BY_DEFAULT
};
// Enables or disables the material design desktop user menu.
const base::Feature kMaterialDesignUserMenu {
- "MaterialDesignUserMenu", base::FEATURE_DISABLED_BY_DEFAULT
+ "MaterialDesignUserMenu", base::FEATURE_ENABLED_BY_DEFAULT
};
// Enables or disables the new password separated sign in flow in a tab modal
diff --git a/chromium/components/signin/ios/browser/BUILD.gn b/chromium/components/signin/ios/browser/BUILD.gn
index 9d1572b3cc1..c0a9f35c7ed 100644
--- a/chromium/components/signin/ios/browser/BUILD.gn
+++ b/chromium/components/signin/ios/browser/BUILD.gn
@@ -35,8 +35,6 @@ source_set("browser") {
source_set("test_support") {
testonly = true
sources = [
- "fake_profile_oauth2_token_service_ios_delegate.h",
- "fake_profile_oauth2_token_service_ios_delegate.mm",
"fake_profile_oauth2_token_service_ios_provider.h",
"fake_profile_oauth2_token_service_ios_provider.mm",
]
diff --git a/chromium/components/signin/ios/browser/account_consistency_service.h b/chromium/components/signin/ios/browser/account_consistency_service.h
index 39b80d42842..cc61d8fe64a 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service.h
+++ b/chromium/components/signin/ios/browser/account_consistency_service.h
@@ -78,7 +78,8 @@ class AccountConsistencyService : public KeyedService,
// Does nothing if the cookie is not set on |domain|.
void RemoveChromeConnectedCookieFromDomain(const std::string& domain);
- // Notifies the AccountConsistencyService that browsing data has been removed.
+ // Notifies the AccountConsistencyService that browsing data has been removed
+ // for any time period.
void OnBrowsingDataRemoved();
private:
@@ -115,7 +116,7 @@ class AccountConsistencyService : public KeyedService,
// Can return nil if the browser state is not active.
WKWebView* GetWKWebView();
// Actually creates a WKWebView. Virtual for testing.
- virtual WKWebView* CreateWKWebView();
+ virtual WKWebView* CreateWKWebView() NS_RETURNS_RETAINED;
// Stops any page loading in the WKWebView currently in use and releases it.
void ResetWKWebView();
diff --git a/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h b/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h
deleted file mode 100644
index d262a28fa3f..00000000000
--- a/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h
+++ /dev/null
@@ -1,61 +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 COMPONENTS_SIGNIN_IOS_BROWSER_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_DELEGATE_H_
-#define COMPONENTS_SIGNIN_IOS_BROWSER_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_DELEGATE_H_
-
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
-
-class FakeProfileOAuth2TokenServiceIOSDelegate
- : public ProfileOAuth2TokenServiceIOSDelegate {
- public:
- FakeProfileOAuth2TokenServiceIOSDelegate(
- SigninClient* client,
- ProfileOAuth2TokenServiceIOSProvider* provider,
- AccountTrackerService* account_tracker_service,
- SigninErrorController* signin_error_controller);
- ~FakeProfileOAuth2TokenServiceIOSDelegate() override;
-
- OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
- const std::string& account_id,
- net::URLRequestContextGetter* getter,
- OAuth2AccessTokenConsumer* consumer) override;
-
- bool RefreshTokenIsAvailable(const std::string& account_id) const override;
- bool RefreshTokenHasError(const std::string& account_id) const override;
- void UpdateAuthError(const std::string& account_id,
- const GoogleServiceAuthError& error) override;
-
- std::vector<std::string> GetAccounts() override;
- void RevokeAllCredentials() override;
-
- void LoadCredentials(const std::string& primary_account_id) override;
-
- void UpdateCredentials(const std::string& account_id,
- const std::string& refresh_token) override;
- void RevokeCredentials(const std::string& account_id) override;
- void AddOrUpdateAccount(const std::string& account_id) override;
- void RemoveAccount(const std::string& account_id) override;
-
- private:
- void IssueRefreshTokenForUser(const std::string& account_id,
- const std::string& token);
- std::string GetRefreshToken(const std::string& account_id) const;
-
- // Calls to this class are expected to be made from the browser UI thread.
- // The purpose of this checker is to detect access to
- // ProfileOAuth2TokenService from multiple threads in upstream code.
- base::ThreadChecker thread_checker_;
-
- // Maps account ids to their refresh token strings.
- std::map<std::string, std::string> refresh_tokens_;
- // Maps account ids to their auth errors.
- std::map<std::string, GoogleServiceAuthError> auth_errors_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeProfileOAuth2TokenServiceIOSDelegate);
-};
-
-#endif // COMPONENTS_SIGNIN_IOS_BROWSER_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_DELEGATE_H_
diff --git a/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.mm b/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.mm
deleted file mode 100644
index 73224fe285d..00000000000
--- a/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.mm
+++ /dev/null
@@ -1,132 +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 "components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h"
-#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
-
-FakeProfileOAuth2TokenServiceIOSDelegate::
- FakeProfileOAuth2TokenServiceIOSDelegate(
- SigninClient* client,
- ProfileOAuth2TokenServiceIOSProvider* provider,
- AccountTrackerService* account_tracker_service,
- SigninErrorController* signin_error_controller)
- : ProfileOAuth2TokenServiceIOSDelegate(client,
- provider,
- account_tracker_service,
- signin_error_controller) {}
-
-FakeProfileOAuth2TokenServiceIOSDelegate::
- ~FakeProfileOAuth2TokenServiceIOSDelegate() {}
-
-OAuth2AccessTokenFetcher*
-FakeProfileOAuth2TokenServiceIOSDelegate::CreateAccessTokenFetcher(
- const std::string& account_id,
- net::URLRequestContextGetter* getter,
- OAuth2AccessTokenConsumer* consumer) {
- std::map<std::string, std::string>::const_iterator it =
- refresh_tokens_.find(account_id);
- DCHECK(it != refresh_tokens_.end());
- std::string refresh_token(it->second);
- return new OAuth2AccessTokenFetcherImpl(consumer, getter, refresh_token);
-}
-
-bool FakeProfileOAuth2TokenServiceIOSDelegate::RefreshTokenIsAvailable(
- const std::string& account_id) const {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- return !GetRefreshToken(account_id).empty();
-}
-
-bool FakeProfileOAuth2TokenServiceIOSDelegate::RefreshTokenHasError(
- const std::string& account_id) const {
- DCHECK(thread_checker_.CalledOnValidThread());
- auto it = auth_errors_.find(account_id);
- return it != auth_errors_.end() && IsError(it->second);
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::UpdateAuthError(
- const std::string& account_id,
- const GoogleServiceAuthError& error) {
- DCHECK(thread_checker_.CalledOnValidThread());
- auth_errors_.erase(account_id);
- auth_errors_.emplace(account_id, error);
-}
-
-std::string FakeProfileOAuth2TokenServiceIOSDelegate::GetRefreshToken(
- const std::string& account_id) const {
- std::map<std::string, std::string>::const_iterator it =
- refresh_tokens_.find(account_id);
- if (it != refresh_tokens_.end())
- return it->second;
- return std::string();
-}
-
-std::vector<std::string>
-FakeProfileOAuth2TokenServiceIOSDelegate::GetAccounts() {
- std::vector<std::string> account_ids;
- for (std::map<std::string, std::string>::const_iterator iter =
- refresh_tokens_.begin();
- iter != refresh_tokens_.end(); ++iter) {
- account_ids.push_back(iter->first);
- }
- return account_ids;
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::RevokeAllCredentials() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- std::vector<std::string> account_ids = GetAccounts();
- for (std::vector<std::string>::const_iterator it = account_ids.begin();
- it != account_ids.end(); it++) {
- RevokeCredentials(*it);
- }
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::LoadCredentials(
- const std::string& primary_account_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
- FireRefreshTokensLoaded();
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::UpdateCredentials(
- const std::string& account_id,
- const std::string& refresh_token) {
- IssueRefreshTokenForUser(account_id, refresh_token);
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::AddOrUpdateAccount(
- const std::string& account_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- UpdateCredentials(account_id, "fake_refresh_token");
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::RemoveAccount(
- const std::string& account_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!account_id.empty());
-
- IssueRefreshTokenForUser(account_id, "");
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::IssueRefreshTokenForUser(
- const std::string& account_id,
- const std::string& token) {
- ScopedBatchChange batch(this);
- if (token.empty()) {
- refresh_tokens_.erase(account_id);
- auth_errors_.erase(account_id);
- FireRefreshTokenRevoked(account_id);
- } else {
- refresh_tokens_[account_id] = token;
- auth_errors_.emplace(account_id,
- GoogleServiceAuthError(GoogleServiceAuthError::NONE));
- FireRefreshTokenAvailable(account_id);
- }
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::RevokeCredentials(
- const std::string& account_id) {
- IssueRefreshTokenForUser(account_id, std::string());
-}
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
index 4e4a8eb5f52..10ea6c9d379 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
@@ -20,7 +20,7 @@ class ProfileOAuth2TokenServiceIOSDelegate : public OAuth2TokenServiceDelegate {
public:
ProfileOAuth2TokenServiceIOSDelegate(
SigninClient* client,
- ProfileOAuth2TokenServiceIOSProvider* provider,
+ std::unique_ptr<ProfileOAuth2TokenServiceIOSProvider> provider,
AccountTrackerService* account_tracker_service,
SigninErrorController* signin_error_controller);
~ProfileOAuth2TokenServiceIOSDelegate() override;
@@ -116,7 +116,7 @@ class ProfileOAuth2TokenServiceIOSDelegate : public OAuth2TokenServiceDelegate {
// The client with which this instance was initialied, or NULL.
SigninClient* client_;
- ProfileOAuth2TokenServiceIOSProvider* provider_;
+ std::unique_ptr<ProfileOAuth2TokenServiceIOSProvider> provider_;
AccountTrackerService* account_tracker_service_;
// The error controller with which this instance was initialized, or NULL.
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
index aaee0a2656c..6577c507280 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
@@ -177,11 +177,11 @@ ProfileOAuth2TokenServiceIOSDelegate::AccountStatus::GetAuthStatus() const {
ProfileOAuth2TokenServiceIOSDelegate::ProfileOAuth2TokenServiceIOSDelegate(
SigninClient* client,
- ProfileOAuth2TokenServiceIOSProvider* provider,
+ std::unique_ptr<ProfileOAuth2TokenServiceIOSProvider> provider,
AccountTrackerService* account_tracker_service,
SigninErrorController* signin_error_controller)
: client_(client),
- provider_(provider),
+ provider_(std::move(provider)),
account_tracker_service_(account_tracker_service),
signin_error_controller_(signin_error_controller) {
DCHECK(client_);
@@ -302,7 +302,7 @@ ProfileOAuth2TokenServiceIOSDelegate::CreateAccessTokenFetcher(
OAuth2AccessTokenConsumer* consumer) {
AccountInfo account_info =
account_tracker_service_->GetAccountInfo(account_id);
- return new SSOAccessTokenFetcher(consumer, provider_, account_info);
+ return new SSOAccessTokenFetcher(consumer, provider_.get(), account_info);
}
std::vector<std::string> ProfileOAuth2TokenServiceIOSDelegate::GetAccounts() {
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
index c93afa05e6f..163fb03295b 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
@@ -4,6 +4,7 @@
#include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
+#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
@@ -49,10 +50,11 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
prefs_.registry()->RegisterListPref(
prefs::kTokenServiceExcludedSecondaryAccounts);
+ fake_provider_ = new FakeProfileOAuth2TokenServiceIOSProvider();
factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_revoke_url(), "",
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
oauth2_delegate_.reset(new ProfileOAuth2TokenServiceIOSDelegate(
- &client_, &fake_provider_, &account_tracker_,
+ &client_, base::WrapUnique(fake_provider_), &account_tracker_,
&signin_error_controller_));
oauth2_delegate_->AddObserver(this);
signin_error_controller_.AddObserver(this);
@@ -107,7 +109,7 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
TestSigninClient client_;
AccountTrackerService account_tracker_;
SigninErrorController signin_error_controller_;
- FakeProfileOAuth2TokenServiceIOSProvider fake_provider_;
+ FakeProfileOAuth2TokenServiceIOSProvider* fake_provider_;
std::unique_ptr<ProfileOAuth2TokenServiceIOSDelegate> oauth2_delegate_;
TestingOAuth2TokenServiceConsumer consumer_;
int token_available_count_;
@@ -121,7 +123,7 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
LoadRevokeCredentialsOneAccount) {
- ProviderAccount account = fake_provider_.AddAccount("gaia_1", "email_1@x");
+ ProviderAccount account = fake_provider_->AddAccount("gaia_1", "email_1@x");
oauth2_delegate_->LoadCredentials(GetAccountId(account));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, token_available_count_);
@@ -141,9 +143,9 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
LoadRevokeCredentialsMultipleAccounts) {
- ProviderAccount account1 = fake_provider_.AddAccount("gaia_1", "email_1@x");
- ProviderAccount account2 = fake_provider_.AddAccount("gaia_2", "email_2@x");
- ProviderAccount account3 = fake_provider_.AddAccount("gaia_3", "email_3@x");
+ ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
+ ProviderAccount account2 = fake_provider_->AddAccount("gaia_2", "email_2@x");
+ ProviderAccount account3 = fake_provider_->AddAccount("gaia_3", "email_3@x");
oauth2_delegate_->LoadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3, token_available_count_);
@@ -172,17 +174,17 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, ReloadCredentials) {
- ProviderAccount account1 = fake_provider_.AddAccount("gaia_1", "email_1@x");
- ProviderAccount account2 = fake_provider_.AddAccount("gaia_2", "email_2@x");
- ProviderAccount account3 = fake_provider_.AddAccount("gaia_3", "email_3@x");
+ ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
+ ProviderAccount account2 = fake_provider_->AddAccount("gaia_2", "email_2@x");
+ ProviderAccount account3 = fake_provider_->AddAccount("gaia_3", "email_3@x");
oauth2_delegate_->LoadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
// Change the accounts.
ResetObserverCounts();
- fake_provider_.ClearAccounts();
- fake_provider_.AddAccount(account1.gaia, account1.email);
- ProviderAccount account4 = fake_provider_.AddAccount("gaia_4", "email_4@x");
+ fake_provider_->ClearAccounts();
+ fake_provider_->AddAccount(account1.gaia, account1.email);
+ ProviderAccount account4 = fake_provider_->AddAccount("gaia_4", "email_4@x");
oauth2_delegate_->ReloadCredentials();
EXPECT_EQ(1, token_available_count_);
@@ -201,8 +203,8 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, ReloadCredentials) {
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
ReloadCredentialsIgnoredIfNoPrimaryAccountId) {
- ProviderAccount account1 = fake_provider_.AddAccount("gaia_1", "email_1@x");
- ProviderAccount account2 = fake_provider_.AddAccount("gaia_2", "email_2@x");
+ ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
+ ProviderAccount account2 = fake_provider_->AddAccount("gaia_2", "email_2@x");
oauth2_delegate_->ReloadCredentials();
EXPECT_EQ(0, token_available_count_);
@@ -217,8 +219,8 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
ReloadCredentialsWithPrimaryAccountId) {
- ProviderAccount account1 = fake_provider_.AddAccount("gaia_1", "email_1@x");
- ProviderAccount account2 = fake_provider_.AddAccount("gaia_2", "email_2@x");
+ ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
+ ProviderAccount account2 = fake_provider_->AddAccount("gaia_2", "email_2@x");
oauth2_delegate_->ReloadCredentials(GetAccountId(account1));
EXPECT_EQ(2, token_available_count_);
@@ -232,7 +234,7 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, StartRequestSuccess) {
- ProviderAccount account1 = fake_provider_.AddAccount("gaia_1", "email_1@x");
+ ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
oauth2_delegate_->LoadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
@@ -248,14 +250,14 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, StartRequestSuccess) {
EXPECT_EQ(0, access_token_failure_);
ResetObserverCounts();
- fake_provider_.IssueAccessTokenForAllRequests();
+ fake_provider_->IssueAccessTokenForAllRequests();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, access_token_success_);
EXPECT_EQ(0, access_token_failure_);
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, StartRequestFailure) {
- ProviderAccount account1 = fake_provider_.AddAccount("gaia_1", "email_1@x");
+ ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
oauth2_delegate_->LoadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
@@ -271,7 +273,7 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, StartRequestFailure) {
EXPECT_EQ(0, access_token_failure_);
ResetObserverCounts();
- fake_provider_.IssueAccessTokenErrorForAllRequests();
+ fake_provider_->IssueAccessTokenErrorForAllRequests();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, access_token_success_);
EXPECT_EQ(1, access_token_failure_);
@@ -281,7 +283,7 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, StartRequestFailure) {
// revoked.
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
UpdateAuthErrorAfterRevokeCredentials) {
- ProviderAccount account1 = fake_provider_.AddAccount("gaia_1", "email_1@x");
+ ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
oauth2_delegate_->ReloadCredentials(GetAccountId(account1));
base::RunLoop().RunUntilIdle();
diff --git a/chromium/components/spellcheck/OWNERS b/chromium/components/spellcheck/OWNERS
new file mode 100644
index 00000000000..e06a48fbed2
--- /dev/null
+++ b/chromium/components/spellcheck/OWNERS
@@ -0,0 +1,5 @@
+groby@chromium.org
+rouslan@chromium.org
+
+# Android, component, refactoring
+timvolodine@chromium.org
diff --git a/chromium/components/spellcheck/browser/BUILD.gn b/chromium/components/spellcheck/browser/BUILD.gn
new file mode 100644
index 00000000000..e7315b84e3c
--- /dev/null
+++ b/chromium/components/spellcheck/browser/BUILD.gn
@@ -0,0 +1,82 @@
+# 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.
+
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
+source_set("browser") {
+ sources = [
+ "feedback.cc",
+ "feedback.h",
+ "feedback_sender.cc",
+ "feedback_sender.h",
+ "misspelling.cc",
+ "misspelling.h",
+ "pref_names.cc",
+ "pref_names.h",
+ "spellcheck_action.cc",
+ "spellcheck_action.h",
+ "spellcheck_dictionary.h",
+ "spellcheck_host_metrics.cc",
+ "spellcheck_host_metrics.h",
+ "spellcheck_message_filter_platform.h",
+ "spellcheck_message_filter_platform_android.cc",
+ "spellcheck_platform.h",
+ "spellcheck_platform_android.cc",
+ "spellcheck_platform_mac.mm",
+ "spellchecker_session_bridge_android.cc",
+ "spellchecker_session_bridge_android.h",
+ "spelling_service_client.cc",
+ "spelling_service_client.h",
+ "word_trimmer.cc",
+ "word_trimmer.h",
+ ]
+
+ public_deps = [
+ "//base",
+ "//components/spellcheck/common",
+ ]
+ deps = [
+ "//components/data_use_measurement/core",
+ "//components/prefs",
+ "//components/user_prefs",
+ "//content/public/browser",
+ "//content/public/common",
+ "//google_apis",
+ "//net",
+ ]
+
+ if (is_android) {
+ sources += [
+ "android/component_jni_registrar.cc",
+ "android/component_jni_registrar.h",
+ ]
+ deps += [ "android:jni_headers" ]
+ }
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "feedback_sender_unittest.cc",
+ "feedback_unittest.cc",
+ "misspelling_unittest.cc",
+ "spellcheck_action_unittest.cc",
+ "spellcheck_host_metrics_unittest.cc",
+ "spellcheck_platform_mac_unittest.cc",
+ "word_trimmer_unittest.cc",
+ ]
+
+ deps = [
+ ":browser",
+ "//base",
+ "//base/test:test_support",
+ "//components/spellcheck/common",
+ "//components/variations",
+ "//content/test:test_support",
+ "//net:test_support",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/spellcheck/browser/DEPS b/chromium/components/spellcheck/browser/DEPS
new file mode 100644
index 00000000000..b843201b602
--- /dev/null
+++ b/chromium/components/spellcheck/browser/DEPS
@@ -0,0 +1,12 @@
+include_rules = [
+ "+components/data_use_measurement",
+ "+components/prefs",
+ "+components/user_prefs",
+ "+components/variations",
+ "+content/public/browser",
+ "+content/public/test",
+ "+crypto",
+ "+google_apis",
+ "+jni",
+ "+net",
+]
diff --git a/chromium/components/spellcheck/browser/android/BUILD.gn b/chromium/components/spellcheck/browser/android/BUILD.gn
new file mode 100644
index 00000000000..29299405baf
--- /dev/null
+++ b/chromium/components/spellcheck/browser/android/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+generate_jni("jni_headers") {
+ sources = [
+ "java/src/org/chromium/components/spellcheck/SpellCheckerSessionBridge.java",
+ ]
+ jni_package = "components/spellcheck"
+}
+
+android_library("java") {
+ deps = [
+ "//base:base_java",
+ ]
+
+ java_files = [ "java/src/org/chromium/components/spellcheck/SpellCheckerSessionBridge.java" ]
+}
diff --git a/chromium/components/spellcheck/browser/feedback.cc b/chromium/components/spellcheck/browser/feedback.cc
new file mode 100644
index 00000000000..3f54ec2f076
--- /dev/null
+++ b/chromium/components/spellcheck/browser/feedback.cc
@@ -0,0 +1,193 @@
+// 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.
+//
+// The |Feedback| object keeps track of each instance of user feedback in a map
+// |misspellings_|. This is a map from uint32_t hashes to |Misspelling| objects.
+//
+// Each misspelling should be present in only one renderer process. The
+// |Feedback| objects keeps track of misspelling-renderer relationship in the
+// |renderers_| map of renderer process identifiers to a set of hashes.
+//
+// When the user adds a misspelling to their custom dictionary, all of the
+// |Misspelling| objects with the same misspelled string are updated. The
+// |Feedback| object facilitates efficient access to these misspellings through
+// a |text_| map of misspelled strings to a set of hashes.
+
+#include "components/spellcheck/browser/feedback.h"
+
+#include <algorithm>
+#include <iterator>
+#include <limits>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+
+namespace spellcheck {
+
+Feedback::Feedback(size_t max_total_text_size)
+ : max_total_text_size_(max_total_text_size), total_text_size_(0) {
+ DCHECK_GE(max_total_text_size, 1024U);
+}
+
+Feedback::~Feedback() {}
+
+Misspelling* Feedback::GetMisspelling(uint32_t hash) {
+ HashMisspellingMap::iterator misspelling_it = misspellings_.find(hash);
+ if (misspelling_it == misspellings_.end())
+ return nullptr;
+ return &misspelling_it->second;
+}
+
+void Feedback::FinalizeRemovedMisspellings(
+ int renderer_process_id,
+ const std::vector<uint32_t>& remaining_markers) {
+ RendererHashesMap::iterator renderer_it =
+ renderers_.find(renderer_process_id);
+ if (renderer_it == renderers_.end() || renderer_it->second.empty())
+ return;
+ HashCollection& renderer_hashes = renderer_it->second;
+ HashCollection remaining_hashes(remaining_markers.begin(),
+ remaining_markers.end());
+ std::vector<HashCollection::value_type> removed_hashes =
+ base::STLSetDifference<std::vector<HashCollection::value_type>>(
+ renderer_hashes, remaining_hashes);
+ for (auto hash : removed_hashes) {
+ HashMisspellingMap::iterator misspelling_it = misspellings_.find(hash);
+ if (misspelling_it != misspellings_.end() &&
+ !misspelling_it->second.action.IsFinal()) {
+ misspelling_it->second.action.Finalize();
+ }
+ }
+}
+
+bool Feedback::RendererHasMisspellings(int renderer_process_id) const {
+ RendererHashesMap::const_iterator renderer_it =
+ renderers_.find(renderer_process_id);
+ return renderer_it != renderers_.end() && !renderer_it->second.empty();
+}
+
+std::vector<Misspelling> Feedback::GetMisspellingsInRenderer(
+ int renderer_process_id) const {
+ std::vector<Misspelling> misspellings_in_renderer;
+ RendererHashesMap::const_iterator renderer_it =
+ renderers_.find(renderer_process_id);
+ if (renderer_it == renderers_.end() || renderer_it->second.empty())
+ return misspellings_in_renderer;
+ const HashCollection& renderer_hashes = renderer_it->second;
+ for (HashCollection::const_iterator hash_it = renderer_hashes.begin();
+ hash_it != renderer_hashes.end(); ++hash_it) {
+ HashMisspellingMap::const_iterator misspelling_it =
+ misspellings_.find(*hash_it);
+ if (misspelling_it != misspellings_.end())
+ misspellings_in_renderer.push_back(misspelling_it->second);
+ }
+ return misspellings_in_renderer;
+}
+
+void Feedback::EraseFinalizedMisspellings(int renderer_process_id) {
+ RendererHashesMap::iterator renderer_it =
+ renderers_.find(renderer_process_id);
+ if (renderer_it == renderers_.end())
+ return;
+ HashCollection& renderer_hashes = renderer_it->second;
+ for (HashCollection::const_iterator hash_it = renderer_hashes.begin();
+ hash_it != renderer_hashes.end();) {
+ HashMisspellingMap::iterator misspelling_it = misspellings_.find(*hash_it);
+ HashCollection::iterator erasable_hash_it = hash_it;
+ ++hash_it;
+ if (misspelling_it == misspellings_.end())
+ continue;
+ const Misspelling& misspelling = misspelling_it->second;
+ if (!misspelling.action.IsFinal())
+ continue;
+ renderer_hashes.erase(erasable_hash_it);
+ text_[GetMisspelledString(misspelling)].erase(misspelling.hash);
+ size_t approximate_size = ApproximateSerializedSize(misspelling_it->second);
+ // Prevent underlfow.
+ if (total_text_size_ >= approximate_size)
+ total_text_size_ -= approximate_size;
+ else
+ total_text_size_ = 0;
+ misspellings_.erase(misspelling_it);
+ }
+ if (renderer_hashes.empty())
+ renderers_.erase(renderer_it);
+}
+
+bool Feedback::HasMisspelling(uint32_t hash) const {
+ return !!misspellings_.count(hash);
+}
+
+void Feedback::AddMisspelling(int renderer_process_id,
+ const Misspelling& misspelling) {
+ HashMisspellingMap::iterator misspelling_it =
+ misspellings_.find(misspelling.hash);
+ if (misspelling_it != misspellings_.end()) {
+ const Misspelling& existing_misspelling = misspelling_it->second;
+ text_[GetMisspelledString(existing_misspelling)].erase(misspelling.hash);
+ for (RendererHashesMap::iterator renderer_it = renderers_.begin();
+ renderer_it != renderers_.end();) {
+ HashCollection& renderer_hashes = renderer_it->second;
+ RendererHashesMap::iterator erasable_renderer_it = renderer_it;
+ ++renderer_it;
+ renderer_hashes.erase(misspelling.hash);
+ if (renderer_hashes.empty())
+ renderers_.erase(erasable_renderer_it);
+ }
+ } else {
+ size_t approximate_size = ApproximateSerializedSize(misspelling);
+ // Prevent overflow.
+ if (total_text_size_ <=
+ std::numeric_limits<size_t>::max() - approximate_size) {
+ total_text_size_ += approximate_size;
+ }
+ if (total_text_size_ >= max_total_text_size_)
+ return;
+ }
+ misspellings_[misspelling.hash] = misspelling;
+ text_[GetMisspelledString(misspelling)].insert(misspelling.hash);
+ renderers_[renderer_process_id].insert(misspelling.hash);
+}
+
+bool Feedback::Empty() const {
+ return misspellings_.empty();
+}
+
+std::vector<int> Feedback::GetRendersWithMisspellings() const {
+ std::vector<int> renderers_with_misspellings;
+ for (const auto& renderer : renderers_) {
+ if (!renderer.second.empty())
+ renderers_with_misspellings.push_back(renderer.first);
+ }
+ return renderers_with_misspellings;
+}
+
+void Feedback::FinalizeAllMisspellings() {
+ for (auto& misspelling : misspellings_) {
+ if (!misspelling.second.action.IsFinal())
+ misspelling.second.action.Finalize();
+ }
+}
+
+std::vector<Misspelling> Feedback::GetAllMisspellings() const {
+ std::vector<Misspelling> all_misspellings;
+ for (const auto& misspelling : misspellings_)
+ all_misspellings.push_back(misspelling.second);
+ return all_misspellings;
+}
+
+void Feedback::Clear() {
+ total_text_size_ = 0;
+ misspellings_.clear();
+ text_.clear();
+ renderers_.clear();
+}
+
+const std::set<uint32_t>& Feedback::FindMisspellings(
+ const base::string16& misspelled_text) const {
+ const TextHashesMap::const_iterator text_it = text_.find(misspelled_text);
+ return text_it == text_.end() ? empty_hash_collection_ : text_it->second;
+}
+
+} // namespace spellcheck
diff --git a/chromium/components/spellcheck/browser/feedback.h b/chromium/components/spellcheck/browser/feedback.h
new file mode 100644
index 00000000000..76f71e78b09
--- /dev/null
+++ b/chromium/components/spellcheck/browser/feedback.h
@@ -0,0 +1,123 @@
+// 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.
+//
+// An object to store user feedback to spellcheck suggestions from spelling
+// service.
+//
+// Stores feedback for the spelling service in |Misspelling| objects. Each
+// |Misspelling| object is identified by a |hash| and corresponds to a document
+// marker with the same |hash| identifier in the renderer.
+
+#ifndef COMPONENTS_SPELLCHECK_BROWSER_FEEDBACK_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_FEEDBACK_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/spellcheck/browser/misspelling.h"
+
+namespace spellcheck {
+
+// Stores user feedback to spellcheck suggestions. Sample usage:
+// Feedback feedback;
+// feedback.AddMisspelling(renderer_process_id, Misspelling(
+// base::ASCIIToUTF16("Helllo world"), 0, 6,
+// std::vector<base::string16>(), GenerateRandomHash()));
+// feedback.FinalizeRemovedMisspellings(renderer_process_id,
+// std::vector<uint32_t>());
+// ProcessFeedback(feedback.GetMisspellingsInRenderer(renderer_process_id));
+// feedback.EraseFinalizedMisspellings(renderer_process_id);
+class Feedback {
+ public:
+ explicit Feedback(size_t max_total_text_size);
+ ~Feedback();
+
+ // Returns the misspelling identified by |hash|. Returns NULL if there's no
+ // misspelling identified by |hash|. Retains the ownership of the result. The
+ // caller should not modify the hash in the returned misspelling.
+ Misspelling* GetMisspelling(uint32_t hash);
+
+ // Finalizes the user actions on misspellings that are removed from the
+ // renderer process with ID |renderer_process_id|.
+ void FinalizeRemovedMisspellings(
+ int renderer_process_id,
+ const std::vector<uint32_t>& remaining_markers);
+
+ // Returns true if the renderer with process ID |renderer_process_id| has
+ // misspellings.
+ bool RendererHasMisspellings(int renderer_process_id) const;
+
+ // Returns a copy of the misspellings in renderer with process ID
+ // |renderer_process_id|.
+ std::vector<Misspelling> GetMisspellingsInRenderer(
+ int renderer_process_id) const;
+
+ // Erases the misspellings with final user actions in the renderer with
+ // process ID |renderer_process_id|.
+ void EraseFinalizedMisspellings(int renderer_process_id);
+
+ // Returns true if there's a misspelling with |hash| identifier.
+ bool HasMisspelling(uint32_t hash) const;
+
+ // Adds the |misspelling| to feedback data. If the |misspelling| has a
+ // duplicate hash, then replaces the existing misspelling with the same hash.
+ void AddMisspelling(int renderer_process_id, const Misspelling& misspelling);
+
+ // Returns true if there're no misspellings.
+ bool Empty() const;
+
+ // Returns a list of process identifiers for renderers that have misspellings.
+ std::vector<int> GetRendersWithMisspellings() const;
+
+ // Finalizes all misspellings.
+ void FinalizeAllMisspellings();
+
+ // Returns a copy of all misspellings.
+ std::vector<Misspelling> GetAllMisspellings() const;
+
+ // Removes all misspellings.
+ void Clear();
+
+ // Returns a list of all misspelling identifiers for |misspelled_text|.
+ const std::set<uint32_t>& FindMisspellings(
+ const base::string16& misspelled_text) const;
+
+ private:
+ typedef std::map<uint32_t, Misspelling> HashMisspellingMap;
+ typedef std::set<uint32_t> HashCollection;
+ typedef std::map<int, HashCollection> RendererHashesMap;
+ typedef std::map<base::string16, HashCollection> TextHashesMap;
+
+ // An empty hash collection to return when FindMisspellings() does not find
+ // misspellings.
+ const HashCollection empty_hash_collection_;
+
+ // The limit on the amount of data to send to the server at once.
+ const size_t max_total_text_size_;
+
+ // Size of all feedback text, used to limit the estimated amount of data sent
+ // to the server at once.
+ size_t total_text_size_;
+
+ // A map of hashes that identify document markers to feedback data to be sent
+ // to spelling service.
+ HashMisspellingMap misspellings_;
+
+ // A map of renderer process ID to hashes that identify misspellings.
+ RendererHashesMap renderers_;
+
+ // A map of misspelled text to hashes that identify misspellings.
+ TextHashesMap text_;
+
+ DISALLOW_COPY_AND_ASSIGN(Feedback);
+};
+
+} // namespace spellcheck
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_FEEDBACK_H_
diff --git a/chromium/components/spellcheck/browser/feedback_sender.cc b/chromium/components/spellcheck/browser/feedback_sender.cc
new file mode 100644
index 00000000000..5d7e8d00bd8
--- /dev/null
+++ b/chromium/components/spellcheck/browser/feedback_sender.cc
@@ -0,0 +1,461 @@
+// 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.
+//
+// The |FeedbackSender| object stores the user feedback to spellcheck
+// suggestions in a |Feedback| object.
+//
+// When spelling service returns spellcheck results, these results first arrive
+// in |FeedbackSender| to assign hash identifiers for each
+// misspelling-suggestion pair. If the spelling service identifies the same
+// misspelling as already displayed to the user, then |FeedbackSender| reuses
+// the same hash identifiers to avoid duplication. It detects the duplicates by
+// comparing misspelling offsets in text. Spelling service can return duplicates
+// because we request spellcheck for whole paragraphs, as context around a
+// misspelled word is important to the spellcheck algorithm.
+//
+// All feedback is initially pending. When a user acts upon a misspelling such
+// that the misspelling is no longer displayed (red squiggly line goes away),
+// then the feedback for this misspelling is finalized. All finalized feedback
+// is erased after being sent to the spelling service. Pending feedback is kept
+// around for |kSessionHours| hours and then finalized even if user did not act
+// on the misspellings.
+//
+// |FeedbackSender| periodically requests a list of hashes of all remaining
+// misspellings in renderers. When a renderer responds with a list of hashes,
+// |FeedbackSender| uses the list to determine which misspellings are no longer
+// displayed to the user and sends the current state of user feedback to the
+// spelling service.
+
+#include "components/spellcheck/browser/feedback_sender.h"
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/hash.h"
+#include "base/json/json_writer.h"
+#include "base/location.h"
+#include "base/metrics/field_trial.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/values.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/spellcheck/browser/word_trimmer.h"
+#include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/common/spellcheck_marker.h"
+#include "components/spellcheck/common/spellcheck_messages.h"
+#include "components/spellcheck/common/spellcheck_switches.h"
+#include "content/public/browser/render_process_host.h"
+#include "crypto/random.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
+#include "google_apis/google_api_keys.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace spellcheck {
+
+namespace {
+
+const size_t kMaxFeedbackSizeBytes = 10 * 1024 * 1024; // 10 MB
+
+// The default URL where feedback data is sent.
+const char kFeedbackServiceURL[] = "https://www.googleapis.com/rpc";
+
+// The minimum number of seconds between sending batches of feedback.
+const int kMinIntervalSeconds = 5;
+
+// Returns a hash of |session_start|, the current timestamp, and
+// |suggestion_index|.
+uint32_t BuildHash(const base::Time& session_start, size_t suggestion_index) {
+ return base::Hash(
+ base::StringPrintf("%" PRId64 "%" PRId64 "%" PRIuS,
+ session_start.ToInternalValue(),
+ base::Time::Now().ToInternalValue(),
+ suggestion_index));
+}
+
+uint64_t BuildAnonymousHash(const FeedbackSender::RandSalt& r,
+ const base::string16& s) {
+ std::unique_ptr<crypto::SecureHash> hash(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+
+ hash->Update(s.data(), s.size() * sizeof(s[0]));
+ hash->Update(&r, sizeof(r));
+
+ uint64_t result;
+ hash->Finish(&result, sizeof(result));
+ return result;
+}
+
+// Returns a pending feedback data structure for the spellcheck |result| and
+// |text|.
+Misspelling BuildFeedback(const SpellCheckResult& result,
+ const base::string16& text) {
+ size_t start = result.location;
+ base::string16 context = TrimWords(&start, start + result.length, text,
+ spellcheck::kContextWordCount);
+ return Misspelling(context,
+ start,
+ result.length,
+ std::vector<base::string16>(1, result.replacement),
+ result.hash);
+}
+
+// Builds suggestion info from |suggestions|.
+std::unique_ptr<base::ListValue> BuildSuggestionInfo(
+ const std::vector<Misspelling>& misspellings,
+ bool is_first_feedback_batch,
+ const FeedbackSender::RandSalt& salt) {
+ std::unique_ptr<base::ListValue> list(new base::ListValue);
+ for (const auto& raw_misspelling : misspellings) {
+ std::unique_ptr<base::DictionaryValue> misspelling(
+ SerializeMisspelling(raw_misspelling));
+ misspelling->SetBoolean("isFirstInSession", is_first_feedback_batch);
+ misspelling->SetBoolean("isAutoCorrection", false);
+ // hash(R) fields come from red_underline_extensions.proto
+ // fixed64 user_misspelling_id = ...
+ misspelling->SetString(
+ "userMisspellingId",
+ base::Uint64ToString(BuildAnonymousHash(
+ salt, raw_misspelling.context.substr(raw_misspelling.location,
+ raw_misspelling.length))));
+ // repeated fixed64 user_suggestion_id = ...
+ std::unique_ptr<base::ListValue> suggestion_list(new base::ListValue());
+ for (const auto& suggestion : raw_misspelling.suggestions) {
+ suggestion_list->AppendString(
+ base::Uint64ToString(BuildAnonymousHash(salt, suggestion)));
+ }
+ misspelling->Set("userSuggestionId", suggestion_list.release());
+ list->Append(std::move(misspelling));
+ }
+ return list;
+}
+
+// Builds feedback parameters from |suggestion_info|, |language|, and |country|.
+// Takes ownership of |suggestion_list|.
+std::unique_ptr<base::DictionaryValue> BuildParams(
+ std::unique_ptr<base::ListValue> suggestion_info,
+ const std::string& language,
+ const std::string& country) {
+ std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue);
+ params->Set("suggestionInfo", suggestion_info.release());
+ params->SetString("key", google_apis::GetAPIKey());
+ params->SetString("language", language);
+ params->SetString("originCountry", country);
+ params->SetString("clientName", "Chrome");
+ return params;
+}
+
+// Builds feedback data from |params|. Takes ownership of |params|.
+std::unique_ptr<base::Value> BuildFeedbackValue(
+ std::unique_ptr<base::DictionaryValue> params,
+ const std::string& api_version) {
+ std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
+ result->Set("params", params.release());
+ result->SetString("method", "spelling.feedback");
+ result->SetString("apiVersion", api_version);
+ return std::move(result);
+}
+
+// Returns true if the misspelling location is within text bounds.
+bool IsInBounds(int misspelling_location,
+ int misspelling_length,
+ size_t text_length) {
+ return misspelling_location >= 0 && misspelling_length > 0 &&
+ static_cast<size_t>(misspelling_location) < text_length &&
+ static_cast<size_t>(misspelling_location + misspelling_length) <=
+ text_length;
+}
+
+// Returns the feedback API version.
+std::string GetApiVersion() {
+ // This guard is temporary.
+ // TODO(rouslan): Remove the guard. http://crbug.com/247726
+ if (base::FieldTrialList::FindFullName(kFeedbackFieldTrialName) ==
+ kFeedbackFieldTrialEnabledGroupName &&
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ spellcheck::switches::kEnableSpellingFeedbackFieldTrial)) {
+ return "v2-internal";
+ }
+ return "v2";
+}
+
+} // namespace
+
+FeedbackSender::FeedbackSender(net::URLRequestContextGetter* request_context,
+ const std::string& language,
+ const std::string& country)
+ : request_context_(request_context),
+ api_version_(GetApiVersion()),
+ language_(language),
+ country_(country),
+ misspelling_counter_(0),
+ feedback_(kMaxFeedbackSizeBytes),
+ session_start_(base::Time::Now()),
+ feedback_service_url_(kFeedbackServiceURL) {
+ // The command-line switch is for testing and temporary.
+ // TODO(rouslan): Remove the command-line switch when testing is complete.
+ // http://crbug.com/247726
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ spellcheck::switches::kSpellingServiceFeedbackUrl)) {
+ feedback_service_url_ =
+ GURL(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ spellcheck::switches::kSpellingServiceFeedbackUrl));
+ }
+}
+
+FeedbackSender::~FeedbackSender() {
+}
+
+void FeedbackSender::SelectedSuggestion(uint32_t hash, int suggestion_index) {
+ Misspelling* misspelling = feedback_.GetMisspelling(hash);
+ // GetMisspelling() returns null for flushed feedback. Feedback is flushed
+ // when the session expires every |kSessionHours| hours.
+ if (!misspelling)
+ return;
+ misspelling->action.set_type(SpellcheckAction::TYPE_SELECT);
+ misspelling->action.set_index(suggestion_index);
+ misspelling->timestamp = base::Time::Now();
+}
+
+void FeedbackSender::AddedToDictionary(uint32_t hash) {
+ Misspelling* misspelling = feedback_.GetMisspelling(hash);
+ // GetMisspelling() returns null for flushed feedback. Feedback is flushed
+ // when the session expires every |kSessionHours| hours.
+ if (!misspelling)
+ return;
+ misspelling->action.set_type(SpellcheckAction::TYPE_ADD_TO_DICT);
+ misspelling->timestamp = base::Time::Now();
+ const std::set<uint32_t>& hashes =
+ feedback_.FindMisspellings(GetMisspelledString(*misspelling));
+ for (uint32_t hash : hashes) {
+ Misspelling* duplicate_misspelling = feedback_.GetMisspelling(hash);
+ if (!duplicate_misspelling || duplicate_misspelling->action.IsFinal())
+ continue;
+ duplicate_misspelling->action.set_type(SpellcheckAction::TYPE_ADD_TO_DICT);
+ duplicate_misspelling->timestamp = misspelling->timestamp;
+ }
+}
+
+void FeedbackSender::RecordInDictionary(uint32_t hash) {
+ Misspelling* misspelling = feedback_.GetMisspelling(hash);
+ // GetMisspelling() returns null for flushed feedback. Feedback is flushed
+ // when the session expires every |kSessionHours| hours.
+ if (!misspelling)
+ return;
+ misspelling->action.set_type(SpellcheckAction::TYPE_IN_DICTIONARY);
+}
+
+void FeedbackSender::IgnoredSuggestions(uint32_t hash) {
+ Misspelling* misspelling = feedback_.GetMisspelling(hash);
+ // GetMisspelling() returns null for flushed feedback. Feedback is flushed
+ // when the session expires every |kSessionHours| hours.
+ if (!misspelling)
+ return;
+ misspelling->action.set_type(SpellcheckAction::TYPE_PENDING_IGNORE);
+ misspelling->timestamp = base::Time::Now();
+}
+
+void FeedbackSender::ManuallyCorrected(uint32_t hash,
+ const base::string16& correction) {
+ Misspelling* misspelling = feedback_.GetMisspelling(hash);
+ // GetMisspelling() returns null for flushed feedback. Feedback is flushed
+ // when the session expires every |kSessionHours| hours.
+ if (!misspelling)
+ return;
+ misspelling->action.set_type(SpellcheckAction::TYPE_MANUALLY_CORRECTED);
+ misspelling->action.set_value(correction);
+ misspelling->timestamp = base::Time::Now();
+}
+
+void FeedbackSender::OnReceiveDocumentMarkers(
+ int renderer_process_id,
+ const std::vector<uint32_t>& markers) {
+ if ((base::Time::Now() - session_start_).InHours() >=
+ spellcheck::kSessionHours) {
+ FlushFeedback();
+ return;
+ }
+
+ if (!feedback_.RendererHasMisspellings(renderer_process_id))
+ return;
+
+ feedback_.FinalizeRemovedMisspellings(renderer_process_id, markers);
+ SendFeedback(feedback_.GetMisspellingsInRenderer(renderer_process_id),
+ !renderers_sent_feedback_.count(renderer_process_id));
+ renderers_sent_feedback_.insert(renderer_process_id);
+ feedback_.EraseFinalizedMisspellings(renderer_process_id);
+}
+
+void FeedbackSender::OnSpellcheckResults(
+ int renderer_process_id,
+ const base::string16& text,
+ const std::vector<SpellCheckMarker>& markers,
+ std::vector<SpellCheckResult>* results) {
+ // Don't collect feedback if not going to send it.
+ if (!timer_.IsRunning())
+ return;
+
+ // Generate a map of marker offsets to marker hashes. This map helps to
+ // efficiently lookup feedback data based on the position of the misspelling
+ // in text.
+ typedef std::map<size_t, uint32_t> MarkerMap;
+ MarkerMap marker_map;
+ for (size_t i = 0; i < markers.size(); ++i)
+ marker_map[markers[i].offset] = markers[i].hash;
+
+ for (auto& result : *results) {
+ if (!IsInBounds(result.location, result.length, text.length()))
+ continue;
+ MarkerMap::const_iterator marker_it = marker_map.find(result.location);
+ if (marker_it != marker_map.end() &&
+ feedback_.HasMisspelling(marker_it->second)) {
+ // If the renderer already has a marker for this spellcheck result, then
+ // set the hash of the spellcheck result to be the same as the marker.
+ result.hash = marker_it->second;
+ } else {
+ // If the renderer does not yet have a marker for this spellcheck result,
+ // then generate a new hash for the spellcheck result.
+ result.hash = BuildHash(session_start_, ++misspelling_counter_);
+ }
+ // Save the feedback data for the spellcheck result.
+ feedback_.AddMisspelling(renderer_process_id, BuildFeedback(result, text));
+ }
+}
+
+void FeedbackSender::OnLanguageCountryChange(const std::string& language,
+ const std::string& country) {
+ FlushFeedback();
+ language_ = language;
+ country_ = country;
+}
+
+void FeedbackSender::StartFeedbackCollection() {
+ if (timer_.IsRunning())
+ return;
+
+ int interval_seconds = spellcheck::kFeedbackIntervalSeconds;
+ // This command-line switch is for testing and temporary.
+ // TODO(rouslan): Remove the command-line switch when testing is complete.
+ // http://crbug.com/247726
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ spellcheck::switches::kSpellingServiceFeedbackIntervalSeconds)) {
+ base::StringToInt(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ spellcheck::switches::kSpellingServiceFeedbackIntervalSeconds),
+ &interval_seconds);
+ if (interval_seconds < kMinIntervalSeconds)
+ interval_seconds = kMinIntervalSeconds;
+ static const int kSessionSeconds = spellcheck::kSessionHours * 60 * 60;
+ if (interval_seconds > kSessionSeconds)
+ interval_seconds = kSessionSeconds;
+ }
+ timer_.Start(FROM_HERE,
+ base::TimeDelta::FromSeconds(interval_seconds),
+ this,
+ &FeedbackSender::RequestDocumentMarkers);
+}
+
+void FeedbackSender::StopFeedbackCollection() {
+ if (!timer_.IsRunning())
+ return;
+
+ FlushFeedback();
+ timer_.Stop();
+}
+
+void FeedbackSender::RandBytes(void* p, size_t len) {
+ crypto::RandBytes(p, len);
+}
+
+void FeedbackSender::OnURLFetchComplete(const net::URLFetcher* source) {
+ for (ScopedVector<net::URLFetcher>::iterator sender_it = senders_.begin();
+ sender_it != senders_.end();
+ ++sender_it) {
+ if (*sender_it == source) {
+ senders_.erase(sender_it);
+ return;
+ }
+ }
+ delete source;
+}
+
+void FeedbackSender::RequestDocumentMarkers() {
+ // Request document markers from all the renderers that are still alive.
+ std::set<int> alive_renderers;
+ for (content::RenderProcessHost::iterator it(
+ content::RenderProcessHost::AllHostsIterator());
+ !it.IsAtEnd();
+ it.Advance()) {
+ alive_renderers.insert(it.GetCurrentValue()->GetID());
+ it.GetCurrentValue()->Send(new SpellCheckMsg_RequestDocumentMarkers());
+ }
+
+ // Asynchronously send out the feedback for all the renderers that are no
+ // longer alive.
+ std::vector<int> known_renderers = feedback_.GetRendersWithMisspellings();
+ std::sort(known_renderers.begin(), known_renderers.end());
+ std::vector<int> dead_renderers =
+ base::STLSetDifference<std::vector<int>>(known_renderers,
+ alive_renderers);
+ for (int renderer_process_id : dead_renderers) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&FeedbackSender::OnReceiveDocumentMarkers, AsWeakPtr(),
+ renderer_process_id, std::vector<uint32_t>()));
+ }
+}
+
+void FeedbackSender::FlushFeedback() {
+ if (feedback_.Empty())
+ return;
+ feedback_.FinalizeAllMisspellings();
+ SendFeedback(feedback_.GetAllMisspellings(),
+ renderers_sent_feedback_.empty());
+ feedback_.Clear();
+ renderers_sent_feedback_.clear();
+ session_start_ = base::Time::Now();
+ timer_.Reset();
+}
+
+void FeedbackSender::SendFeedback(const std::vector<Misspelling>& feedback_data,
+ bool is_first_feedback_batch) {
+ if (base::Time::Now() - last_salt_update_ > base::TimeDelta::FromHours(24)) {
+ RandBytes(&salt_, sizeof(salt_));
+ last_salt_update_ = base::Time::Now();
+ }
+ std::unique_ptr<base::Value> feedback_value(BuildFeedbackValue(
+ BuildParams(
+ BuildSuggestionInfo(feedback_data, is_first_feedback_batch, salt_),
+ language_, country_),
+ api_version_));
+ std::string feedback;
+ base::JSONWriter::Write(*feedback_value, &feedback);
+
+ // The tests use this identifier to mock the URL fetcher.
+ static const int kUrlFetcherId = 0;
+ net::URLFetcher* sender =
+ net::URLFetcher::Create(kUrlFetcherId, feedback_service_url_,
+ net::URLFetcher::POST, this).release();
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ sender, data_use_measurement::DataUseUserData::SPELL_CHECKER);
+ sender->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES);
+ sender->SetUploadData("application/json", feedback);
+ senders_.push_back(sender);
+
+ // Request context is nullptr in testing.
+ if (request_context_.get()) {
+ sender->SetRequestContext(request_context_.get());
+ sender->Start();
+ }
+}
+
+} // namespace spellcheck
diff --git a/chromium/components/spellcheck/browser/feedback_sender.h b/chromium/components/spellcheck/browser/feedback_sender.h
new file mode 100644
index 00000000000..f97b674a40e
--- /dev/null
+++ b/chromium/components/spellcheck/browser/feedback_sender.h
@@ -0,0 +1,196 @@
+// 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.
+//
+// An object to record and send user feedback to spelling service. The spelling
+// service uses the feedback to improve its suggestions.
+//
+// Assigns uint32_t hash identifiers to spelling suggestions from spelling
+// service and stores these suggestions. Records user's actions on these
+// suggestions. Periodically sends batches of user feedback to the spelling
+// service.
+
+#ifndef COMPONENTS_SPELLCHECK_BROWSER_FEEDBACK_SENDER_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_FEEDBACK_SENDER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <array>
+#include <climits>
+#include <map>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "components/spellcheck/browser/feedback.h"
+#include "components/spellcheck/browser/misspelling.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "url/gurl.h"
+
+class SpellCheckMarker;
+struct SpellCheckResult;
+
+namespace net {
+class URLFetcher;
+class URLRequestContextGetter;
+}
+
+namespace spellcheck {
+
+namespace {
+
+// Constants for the feedback field trial.
+const char kFeedbackFieldTrialName[] = "SpellingServiceFeedback";
+const char kFeedbackFieldTrialEnabledGroupName[] = "Enabled";
+
+} // namespace
+
+// Stores and sends user feedback to the spelling service. Sample usage:
+// FeedbackSender sender(profile.GetRequestContext(), language, country);
+// sender.OnSpellcheckResults(spellcheck_results_from_spelling_service,
+// renderer_process_id,
+// spellchecked_text,
+// existing_hashes);
+// sender.SelectedSuggestion(hash, suggestion_index);
+class FeedbackSender : public base::SupportsWeakPtr<FeedbackSender>,
+ public net::URLFetcherDelegate {
+ public:
+ // Constructs a feedback sender. Keeps |request_context| in a scoped_refptr,
+ // because URLRequestContextGetter implements RefcountedThreadSafe.
+ FeedbackSender(net::URLRequestContextGetter* request_context,
+ const std::string& language,
+ const std::string& country);
+ ~FeedbackSender() override;
+
+ // Records that user selected suggestion |suggestion_index| for the
+ // misspelling identified by |hash|.
+ void SelectedSuggestion(uint32_t hash, int suggestion_index);
+
+ // Records that user added the misspelling identified by |hash| to the
+ // dictionary.
+ void AddedToDictionary(uint32_t hash);
+
+ // Records that user right-clicked on the misspelling identified by |hash|,
+ // but did not select any suggestion.
+ void IgnoredSuggestions(uint32_t hash);
+
+ // Records that user did not choose any suggestion but manually corrected the
+ // misspelling identified by |hash| to string |correction|, which is not in
+ // the list of suggestions.
+ void ManuallyCorrected(uint32_t hash, const base::string16& correction);
+
+ // Records that user has the misspelling in the custom dictionary. The user
+ // will never see the spellcheck suggestions for the misspelling.
+ void RecordInDictionary(uint32_t hash);
+
+ // Receives document markers for renderer with process ID |render_process_id|
+ // when the renderer responds to a RequestDocumentMarkers() call. Finalizes
+ // feedback for the markers that are gone from the renderer. Sends feedback
+ // data for the renderer with process ID |renderer_process_id| to the spelling
+ // service. If the current session has expired, then refreshes the session
+ // start timestamp and sends out all of the feedback data.
+ void OnReceiveDocumentMarkers(int renderer_process_id,
+ const std::vector<uint32_t>& markers);
+
+ // Generates feedback data based on spellcheck results. The new feedback data
+ // is pending. Sets hash identifiers for |results|. Called when spelling
+ // service client receives results from the spelling service. Does not take
+ // ownership of |results|.
+ void OnSpellcheckResults(int renderer_process_id,
+ const base::string16& text,
+ const std::vector<SpellCheckMarker>& markers,
+ std::vector<SpellCheckResult>* results);
+
+ // Receives updated language and country code for feedback. Finalizes and
+ // sends out all of the feedback data.
+ void OnLanguageCountryChange(const std::string& language,
+ const std::string& country);
+
+ // Starts collecting feedback, if it's not already being collected.
+ void StartFeedbackCollection();
+
+ // Sends out all previously collected data and stops collecting feedback, if
+ // it was being collected.
+ void StopFeedbackCollection();
+
+ // 256 bits
+ typedef std::array<char, 256 / CHAR_BIT> RandSalt;
+
+ private:
+ friend class FeedbackSenderTest;
+
+ // Allow unit tests to override RNG.
+ virtual void RandBytes(void* p, size_t len);
+
+ // net::URLFetcherDelegate implementation. Takes ownership of |source|.
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+ // Requests the document markers from all of the renderers to determine which
+ // feedback can be finalized. Finalizes feedback for renderers that are gone.
+ // Called periodically when |timer_| fires.
+ void RequestDocumentMarkers();
+
+ // Sends out all feedback data. Resets the session-start timestamp to now.
+ // Restarts the timer that requests markers from the renderers.
+ void FlushFeedback();
+
+ // Sends out the |feedback_data|.
+ void SendFeedback(const std::vector<Misspelling>& feedback_data,
+ bool is_first_feedback_batch);
+
+ // URL request context for the feedback senders.
+ scoped_refptr<net::URLRequestContextGetter> request_context_;
+
+ // The feedback API version.
+ const std::string api_version_;
+
+ // The language of text. The string is a BCP 47 language tag.
+ std::string language_;
+
+ // The country of origin. The string is the ISO 3166-1 alpha-3 code.
+ std::string country_;
+
+ // Misspelling counter used to generate unique hash identifier for each
+ // misspelling.
+ size_t misspelling_counter_;
+
+ // Feedback data.
+ Feedback feedback_;
+
+ // A set of renderer process IDs for renderers that have sent out feedback in
+ // this session.
+ std::set<int> renderers_sent_feedback_;
+
+ // When the session started.
+ base::Time session_start_;
+
+ // The last time that we updated |salt_|.
+ base::Time last_salt_update_;
+
+ // A random number updated once a day.
+ RandSalt salt_;
+
+ // The URL where the feedback data should be sent.
+ GURL feedback_service_url_;
+
+ // A timer to periodically request a list of document spelling markers from
+ // all of the renderers. The timer starts in StartFeedbackCollection() and
+ // stops in StopFeedbackCollection(). The timer stops and abandons its tasks
+ // on destruction.
+ base::RepeatingTimer timer_;
+
+ // Feedback senders that need to stay alive for the duration of sending data.
+ // If a sender is destroyed before it finishes, then sending feedback will be
+ // canceled.
+ ScopedVector<net::URLFetcher> senders_;
+
+ DISALLOW_COPY_AND_ASSIGN(FeedbackSender);
+};
+
+} // namespace spellcheck
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_FEEDBACK_SENDER_H_
diff --git a/chromium/components/spellcheck/browser/feedback_sender_unittest.cc b/chromium/components/spellcheck/browser/feedback_sender_unittest.cc
new file mode 100644
index 00000000000..e4c81469e52
--- /dev/null
+++ b/chromium/components/spellcheck/browser/feedback_sender_unittest.cc
@@ -0,0 +1,729 @@
+// 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.
+//
+// Unit tests for |FeedbackSender| object.
+
+#include "components/spellcheck/browser/feedback_sender.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/common/spellcheck_marker.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "components/spellcheck/common/spellcheck_switches.h"
+#include "components/variations/entropy_provider.h"
+#include "content/public/test/test_browser_thread.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace spellcheck {
+
+namespace {
+
+const char kCountry[] = "USA";
+const char kLanguage[] = "en";
+const char kText[] = "Helllo world.";
+const int kMisspellingLength = 6;
+const int kMisspellingStart = 0;
+const int kRendererProcessId = 0;
+const int kUrlFetcherId = 0;
+
+// Builds a simple spellcheck result.
+SpellCheckResult BuildSpellCheckResult() {
+ return SpellCheckResult(SpellCheckResult::SPELLING,
+ kMisspellingStart,
+ kMisspellingLength,
+ base::UTF8ToUTF16("Hello"));
+}
+
+// Returns the number of times that |needle| appears in |haystack| without
+// overlaps. For example, CountOccurences("bananana", "nana") returns 1.
+int CountOccurences(const std::string& haystack, const std::string& needle) {
+ int number_of_occurrences = 0;
+ for (size_t pos = haystack.find(needle);
+ pos != std::string::npos;
+ pos = haystack.find(needle, pos + needle.length())) {
+ ++number_of_occurrences;
+ }
+ return number_of_occurrences;
+}
+
+class MockFeedbackSender : public spellcheck::FeedbackSender {
+ public:
+ MockFeedbackSender(net::URLRequestContextGetter* request_context,
+ const std::string& language,
+ const std::string& country)
+ : FeedbackSender(request_context, language, country), random_(0) {}
+
+ void RandBytes(void* p, size_t len) override {
+ memset(p, 0, len);
+ if (len >= sizeof(random_))
+ *(unsigned*)p = ++random_;
+ }
+
+ private:
+ // For returning a different value from each call to RandUint64().
+ unsigned random_;
+};
+
+std::string GetMisspellingId(const std::string& raw_data) {
+ std::unique_ptr<base::Value> parsed_data(
+ base::JSONReader::Read(raw_data).release());
+ EXPECT_TRUE(parsed_data.get());
+ base::DictionaryValue* actual_data;
+ EXPECT_TRUE(parsed_data->GetAsDictionary(&actual_data));
+ base::ListValue* suggestions = NULL;
+ EXPECT_TRUE(actual_data->GetList("params.suggestionInfo", &suggestions));
+ base::DictionaryValue* suggestion = NULL;
+ EXPECT_TRUE(suggestions->GetDictionary(0, &suggestion));
+ std::string value;
+ EXPECT_TRUE(suggestion->GetString("userMisspellingId", &value));
+ return value;
+}
+
+} // namespace
+
+// A test fixture to help keep tests simple.
+class FeedbackSenderTest : public testing::Test {
+ public:
+ FeedbackSenderTest() : ui_thread_(content::BrowserThread::UI, &loop_) {
+ feedback_.reset(new MockFeedbackSender(NULL, kLanguage, kCountry));
+ feedback_->StartFeedbackCollection();
+ }
+
+ ~FeedbackSenderTest() override {}
+
+ protected:
+ // Appends the "--enable-spelling-service-feedback" switch to the
+ // command-line.
+ void AppendCommandLineSwitch() {
+ // The command-line switch is temporary.
+ // TODO(rouslan): Remove the command-line switch. http://crbug.com/247726
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ spellcheck::switches::kEnableSpellingFeedbackFieldTrial);
+ feedback_.reset(new MockFeedbackSender(NULL, kLanguage, kCountry));
+ feedback_->StartFeedbackCollection();
+ }
+
+ // Enables the "SpellingServiceFeedback.Enabled" field trial.
+ void EnableFieldTrial() {
+ // The field trial is temporary.
+ // TODO(rouslan): Remove the field trial. http://crbug.com/247726
+ field_trial_list_.reset(
+ new base::FieldTrialList(
+ base::MakeUnique<metrics::SHA1EntropyProvider>("foo")));
+ field_trial_ = base::FieldTrialList::CreateFieldTrial(
+ kFeedbackFieldTrialName, kFeedbackFieldTrialEnabledGroupName);
+ field_trial_->group();
+ feedback_.reset(new MockFeedbackSender(NULL, kLanguage, kCountry));
+ feedback_->StartFeedbackCollection();
+ }
+
+ uint32_t AddPendingFeedback() {
+ std::vector<SpellCheckResult> results(1, BuildSpellCheckResult());
+ feedback_->OnSpellcheckResults(kRendererProcessId,
+ base::UTF8ToUTF16(kText),
+ std::vector<SpellCheckMarker>(),
+ &results);
+ return results[0].hash;
+ }
+
+ void ExpireSession() {
+ feedback_->session_start_ =
+ base::Time::Now() -
+ base::TimeDelta::FromHours(spellcheck::kSessionHours);
+ }
+
+ bool UploadDataContains(const std::string& data) const {
+ const net::TestURLFetcher* fetcher =
+ fetchers_.GetFetcherByID(kUrlFetcherId);
+ return fetcher && CountOccurences(fetcher->upload_data(), data) > 0;
+ }
+
+ bool UploadDataContains(const std::string& data,
+ int number_of_occurrences) const {
+ const net::TestURLFetcher* fetcher =
+ fetchers_.GetFetcherByID(kUrlFetcherId);
+ return fetcher && CountOccurences(fetcher->upload_data(), data) ==
+ number_of_occurrences;
+ }
+
+ // Returns true if the feedback sender would be uploading data now. The test
+ // does not open network connections.
+ bool IsUploadingData() const {
+ return !!fetchers_.GetFetcherByID(kUrlFetcherId);
+ }
+
+ void ClearUploadData() {
+ fetchers_.RemoveFetcherFromMap(kUrlFetcherId);
+ }
+
+ std::string GetUploadData() const {
+ const net::TestURLFetcher* fetcher =
+ fetchers_.GetFetcherByID(kUrlFetcherId);
+ return fetcher ? fetcher->upload_data() : std::string();
+ }
+
+ void AdjustUpdateTime(base::TimeDelta offset) {
+ feedback_->last_salt_update_ += offset;
+ }
+
+ std::unique_ptr<MockFeedbackSender> feedback_;
+
+ private:
+ base::MessageLoop loop_;
+ content::TestBrowserThread ui_thread_;
+ std::unique_ptr<base::FieldTrialList> field_trial_list_;
+ scoped_refptr<base::FieldTrial> field_trial_;
+ net::TestURLFetcherFactory fetchers_;
+};
+
+// Do not send data if there's no feedback.
+TEST_F(FeedbackSenderTest, NoFeedback) {
+ EXPECT_FALSE(IsUploadingData());
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_FALSE(IsUploadingData());
+}
+
+// Do not send data if not aware of which markers are still in the document.
+TEST_F(FeedbackSenderTest, NoDocumentMarkersReceived) {
+ EXPECT_FALSE(IsUploadingData());
+ uint32_t hash = AddPendingFeedback();
+ EXPECT_FALSE(IsUploadingData());
+ static const int kSuggestionIndex = 1;
+ feedback_->SelectedSuggestion(hash, kSuggestionIndex);
+ EXPECT_FALSE(IsUploadingData());
+}
+
+// Send PENDING feedback message if the marker is still in the document, and the
+// user has not performed any action on it.
+TEST_F(FeedbackSenderTest, PendingFeedback) {
+ uint32_t hash = AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>(1, hash));
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
+}
+
+TEST_F(FeedbackSenderTest, IdenticalFeedback) {
+ std::vector<uint32_t> hashes;
+ hashes.push_back(AddPendingFeedback());
+ hashes.push_back(AddPendingFeedback());
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId, hashes);
+ std::string actual_data = GetUploadData();
+ std::unique_ptr<base::DictionaryValue> actual(
+ static_cast<base::DictionaryValue*>(
+ base::JSONReader::Read(GetUploadData()).release()));
+ base::ListValue* suggestions = NULL;
+ ASSERT_TRUE(actual->GetList("params.suggestionInfo", &suggestions));
+ base::DictionaryValue* suggestion0 = NULL;
+ ASSERT_TRUE(suggestions->GetDictionary(0, &suggestion0));
+ base::DictionaryValue* suggestion1 = NULL;
+ ASSERT_TRUE(suggestions->GetDictionary(0, &suggestion1));
+ std::string value0, value1;
+ ASSERT_TRUE(suggestion0->GetString("userMisspellingId", &value0));
+ ASSERT_TRUE(suggestion1->GetString("userMisspellingId", &value1));
+ EXPECT_EQ(value0, value1);
+ base::ListValue* suggestion_ids = NULL;
+ ASSERT_TRUE(suggestion0->GetList("userSuggestionId", &suggestion_ids));
+ ASSERT_TRUE(suggestion_ids->GetString(0, &value0));
+ ASSERT_TRUE(suggestion1->GetList("userSuggestionId", &suggestion_ids));
+ ASSERT_TRUE(suggestion_ids->GetString(0, &value1));
+ EXPECT_EQ(value0, value1);
+}
+
+TEST_F(FeedbackSenderTest, NonidenticalFeedback) {
+ std::vector<uint32_t> hashes;
+ hashes.push_back(AddPendingFeedback());
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId, hashes);
+ std::string raw_data0 = GetUploadData();
+ hashes.clear();
+ hashes.push_back(AddPendingFeedback());
+ AdjustUpdateTime(-base::TimeDelta::FromHours(25));
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId, hashes);
+ std::string raw_data1 = GetUploadData();
+
+ std::string value0(GetMisspellingId(raw_data0));
+ std::string value1(GetMisspellingId(raw_data1));
+ EXPECT_NE(value0, value1);
+}
+
+// Send NO_ACTION feedback message if the marker has been removed from the
+// document.
+TEST_F(FeedbackSenderTest, NoActionFeedback) {
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"NO_ACTION\""));
+}
+
+// Send SELECT feedback message if the user has selected a spelling suggestion.
+TEST_F(FeedbackSenderTest, SelectFeedback) {
+ uint32_t hash = AddPendingFeedback();
+ static const int kSuggestionIndex = 0;
+ feedback_->SelectedSuggestion(hash, kSuggestionIndex);
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"SELECT\""));
+ EXPECT_TRUE(UploadDataContains("\"actionTargetIndex\":" +
+ base::StringPrintf("%d", kSuggestionIndex)));
+}
+
+// Send ADD_TO_DICT feedback message if the user has added the misspelled word
+// to the custom dictionary.
+TEST_F(FeedbackSenderTest, AddToDictFeedback) {
+ uint32_t hash = AddPendingFeedback();
+ feedback_->AddedToDictionary(hash);
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"ADD_TO_DICT\""));
+}
+
+// Send IN_DICTIONARY feedback message if the user has the misspelled word in
+// the custom dictionary.
+TEST_F(FeedbackSenderTest, InDictionaryFeedback) {
+ uint32_t hash = AddPendingFeedback();
+ feedback_->RecordInDictionary(hash);
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"IN_DICTIONARY\""));
+}
+
+// Send PENDING feedback message if the user saw the spelling suggestion, but
+// decided to not select it, and the marker is still in the document.
+TEST_F(FeedbackSenderTest, IgnoreFeedbackMarkerInDocument) {
+ uint32_t hash = AddPendingFeedback();
+ feedback_->IgnoredSuggestions(hash);
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>(1, hash));
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
+}
+
+// Send IGNORE feedback message if the user saw the spelling suggestion, but
+// decided to not select it, and the marker is no longer in the document.
+TEST_F(FeedbackSenderTest, IgnoreFeedbackMarkerNotInDocument) {
+ uint32_t hash = AddPendingFeedback();
+ feedback_->IgnoredSuggestions(hash);
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"IGNORE\""));
+}
+
+// Send MANUALLY_CORRECTED feedback message if the user manually corrected the
+// misspelled word.
+TEST_F(FeedbackSenderTest, ManuallyCorrectedFeedback) {
+ uint32_t hash = AddPendingFeedback();
+ static const std::string kManualCorrection = "Howdy";
+ feedback_->ManuallyCorrected(hash, base::ASCIIToUTF16(kManualCorrection));
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"MANUALLY_CORRECTED\""));
+ EXPECT_TRUE(UploadDataContains("\"actionTargetValue\":\"" +
+ kManualCorrection + "\""));
+}
+
+// Send feedback messages in batch.
+TEST_F(FeedbackSenderTest, BatchFeedback) {
+ std::vector<SpellCheckResult> results;
+ results.push_back(SpellCheckResult(SpellCheckResult::SPELLING,
+ kMisspellingStart,
+ kMisspellingLength,
+ base::ASCIIToUTF16("Hello")));
+ static const int kSecondMisspellingStart = 7;
+ static const int kSecondMisspellingLength = 5;
+ results.push_back(SpellCheckResult(SpellCheckResult::SPELLING,
+ kSecondMisspellingStart,
+ kSecondMisspellingLength,
+ base::ASCIIToUTF16("world")));
+ feedback_->OnSpellcheckResults(kRendererProcessId,
+ base::UTF8ToUTF16(kText),
+ std::vector<SpellCheckMarker>(),
+ &results);
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"NO_ACTION\"", 2));
+}
+
+// Send a series of PENDING feedback messages and one final NO_ACTION feedback
+// message with the same hash identifier for a single misspelling.
+TEST_F(FeedbackSenderTest, SameHashFeedback) {
+ uint32_t hash = AddPendingFeedback();
+ std::vector<uint32_t> remaining_markers(1, hash);
+
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
+ std::string hash_string = base::StringPrintf("\"suggestionId\":\"%u\"", hash);
+ EXPECT_TRUE(UploadDataContains(hash_string));
+ ClearUploadData();
+
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
+ EXPECT_TRUE(UploadDataContains(hash_string));
+ ClearUploadData();
+
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"NO_ACTION\""));
+ EXPECT_TRUE(UploadDataContains(hash_string));
+ ClearUploadData();
+
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_FALSE(IsUploadingData());
+}
+
+// When a session expires:
+// 1) Pending feedback is finalized and sent to the server in the last message
+// batch in the session.
+// 2) No feedback is sent until a spellcheck request happens.
+// 3) Existing markers get new hash identifiers.
+TEST_F(FeedbackSenderTest, SessionExpirationFeedback) {
+ std::vector<SpellCheckResult> results(
+ 1,
+ SpellCheckResult(SpellCheckResult::SPELLING,
+ kMisspellingStart,
+ kMisspellingLength,
+ base::ASCIIToUTF16("Hello")));
+ feedback_->OnSpellcheckResults(kRendererProcessId,
+ base::UTF8ToUTF16(kText),
+ std::vector<SpellCheckMarker>(),
+ &results);
+ uint32_t original_hash = results[0].hash;
+ std::vector<uint32_t> remaining_markers(1, original_hash);
+
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
+ EXPECT_FALSE(UploadDataContains("\"actionType\":\"NO_ACTION\""));
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
+ std::string original_hash_string =
+ base::StringPrintf("\"suggestionId\":\"%u\"", original_hash);
+ EXPECT_TRUE(UploadDataContains(original_hash_string));
+ ClearUploadData();
+
+ ExpireSession();
+
+ // Last message batch in the current session has only finalized messages.
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"NO_ACTION\""));
+ EXPECT_FALSE(UploadDataContains("\"actionType\":\"PENDING\""));
+ EXPECT_TRUE(UploadDataContains(original_hash_string));
+ ClearUploadData();
+
+ // The next session starts on the next spellchecker request. Until then,
+ // there's no more feedback sent.
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
+ EXPECT_FALSE(IsUploadingData());
+
+ // The first spellcheck request after session expiration creates different
+ // document marker hash identifiers.
+ std::vector<SpellCheckMarker> original_markers(
+ 1, SpellCheckMarker(results[0].hash, results[0].location));
+ results[0] = SpellCheckResult(SpellCheckResult::SPELLING,
+ kMisspellingStart,
+ kMisspellingLength,
+ base::ASCIIToUTF16("Hello"));
+ feedback_->OnSpellcheckResults(
+ kRendererProcessId, base::UTF8ToUTF16(kText), original_markers, &results);
+ uint32_t updated_hash = results[0].hash;
+ EXPECT_NE(updated_hash, original_hash);
+ remaining_markers[0] = updated_hash;
+
+ // The first feedback message batch in session |i + 1| has the new document
+ // marker hash identifiers.
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId, remaining_markers);
+ EXPECT_FALSE(UploadDataContains("\"actionType\":\"NO_ACTION\""));
+ EXPECT_TRUE(UploadDataContains("\"actionType\":\"PENDING\""));
+ EXPECT_FALSE(UploadDataContains(original_hash_string));
+ std::string updated_hash_string =
+ base::StringPrintf("\"suggestionId\":\"%u\"", updated_hash);
+ EXPECT_TRUE(UploadDataContains(updated_hash_string));
+}
+
+// First message in session has an indicator.
+TEST_F(FeedbackSenderTest, FirstMessageInSessionIndicator) {
+ // Session 1, message 1
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"isFirstInSession\":true"));
+
+ // Session 1, message 2
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"isFirstInSession\":false"));
+
+ ExpireSession();
+
+ // Session 1, message 3 (last)
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"isFirstInSession\":false"));
+
+ // Session 2, message 1
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"isFirstInSession\":true"));
+
+ // Session 2, message 2
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"isFirstInSession\":false"));
+}
+
+// Flush all feedback when the spellcheck language and country change.
+TEST_F(FeedbackSenderTest, OnLanguageCountryChange) {
+ AddPendingFeedback();
+ feedback_->OnLanguageCountryChange("pt", "BR");
+ EXPECT_TRUE(UploadDataContains("\"language\":\"en\""));
+ AddPendingFeedback();
+ feedback_->OnLanguageCountryChange("en", "US");
+ EXPECT_TRUE(UploadDataContains("\"language\":\"pt\""));
+}
+
+// The field names and types should correspond to the API.
+TEST_F(FeedbackSenderTest, FeedbackAPI) {
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ std::string actual_data = GetUploadData();
+ std::unique_ptr<base::DictionaryValue> actual(
+ static_cast<base::DictionaryValue*>(
+ base::JSONReader::Read(actual_data).release()));
+ actual->SetString("params.key", "TestDummyKey");
+ base::ListValue* suggestions = nullptr;
+ actual->GetList("params.suggestionInfo", &suggestions);
+ base::DictionaryValue* suggestion = nullptr;
+ suggestions->GetDictionary(0, &suggestion);
+ suggestion->SetString("suggestionId", "42");
+ suggestion->SetString("timestamp", "9001");
+ static const std::string expected_data =
+ "{\"apiVersion\":\"v2\","
+ "\"method\":\"spelling.feedback\","
+ "\"params\":"
+ "{\"clientName\":\"Chrome\","
+ "\"originCountry\":\"USA\","
+ "\"key\":\"TestDummyKey\","
+ "\"language\":\"en\","
+ "\"suggestionInfo\":[{"
+ "\"isAutoCorrection\":false,"
+ "\"isFirstInSession\":true,"
+ "\"misspelledLength\":6,"
+ "\"misspelledStart\":0,"
+ "\"originalText\":\"Helllo world\","
+ "\"suggestionId\":\"42\","
+ "\"suggestions\":[\"Hello\"],"
+ "\"timestamp\":\"9001\","
+ "\"userActions\":[{\"actionType\":\"NO_ACTION\"}],"
+ "\"userMisspellingId\":\"14573599553589145012\","
+ "\"userSuggestionId\":[\"14761077877524043800\"]}]}}";
+ std::unique_ptr<base::Value> expected = base::JSONReader::Read(expected_data);
+ EXPECT_TRUE(expected->Equals(actual.get()))
+ << "Expected data: " << expected_data
+ << "\nActual data: " << actual_data;
+}
+
+// The default API version is "v2".
+TEST_F(FeedbackSenderTest, DefaultApiVersion) {
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("\"apiVersion\":\"v2\""));
+ EXPECT_FALSE(UploadDataContains("\"apiVersion\":\"v2-internal\""));
+}
+
+// The API version should not change for field-trial participants that do not
+// append the command-line switch.
+TEST_F(FeedbackSenderTest, FieldTrialAloneHasSameApiVersion) {
+ EnableFieldTrial();
+
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+
+ EXPECT_TRUE(UploadDataContains("\"apiVersion\":\"v2\""));
+ EXPECT_FALSE(UploadDataContains("\"apiVersion\":\"v2-internal\""));
+}
+
+// The API version should not change if the command-line switch is appended, but
+// the user is not participating in the field-trial.
+TEST_F(FeedbackSenderTest, CommandLineSwitchAloneHasSameApiVersion) {
+ AppendCommandLineSwitch();
+
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+
+ EXPECT_TRUE(UploadDataContains("\"apiVersion\":\"v2\""));
+ EXPECT_FALSE(UploadDataContains("\"apiVersion\":\"v2-internal\""));
+}
+
+// The API version should be different for field-trial participants that also
+// append the command-line switch.
+TEST_F(FeedbackSenderTest, InternalApiVersion) {
+ AppendCommandLineSwitch();
+ EnableFieldTrial();
+
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+
+ EXPECT_FALSE(UploadDataContains("\"apiVersion\":\"v2\""));
+ EXPECT_TRUE(UploadDataContains("\"apiVersion\":\"v2-internal\""));
+}
+
+// Duplicate spellcheck results should be matched to the existing markers.
+TEST_F(FeedbackSenderTest, MatchDupliateResultsWithExistingMarkers) {
+ uint32_t hash = AddPendingFeedback();
+ std::vector<SpellCheckResult> results(
+ 1,
+ SpellCheckResult(SpellCheckResult::SPELLING,
+ kMisspellingStart,
+ kMisspellingLength,
+ base::ASCIIToUTF16("Hello")));
+ std::vector<SpellCheckMarker> markers(
+ 1, SpellCheckMarker(hash, results[0].location));
+ EXPECT_EQ(static_cast<uint32_t>(0), results[0].hash);
+ feedback_->OnSpellcheckResults(
+ kRendererProcessId, base::UTF8ToUTF16(kText), markers, &results);
+ EXPECT_EQ(hash, results[0].hash);
+}
+
+// Adding a word to dictionary should trigger ADD_TO_DICT feedback for every
+// occurrence of that word.
+TEST_F(FeedbackSenderTest, MultipleAddToDictFeedback) {
+ std::vector<SpellCheckResult> results;
+ static const int kSentenceLength = 14;
+ static const int kNumberOfSentences = 2;
+ static const base::string16 kTextWithDuplicates =
+ base::ASCIIToUTF16("Helllo world. Helllo world.");
+ for (int i = 0; i < kNumberOfSentences; ++i) {
+ results.push_back(SpellCheckResult(SpellCheckResult::SPELLING,
+ kMisspellingStart + i * kSentenceLength,
+ kMisspellingLength,
+ base::ASCIIToUTF16("Hello")));
+ }
+ static const int kNumberOfRenderers = 2;
+ int last_renderer_process_id = -1;
+ for (int i = 0; i < kNumberOfRenderers; ++i) {
+ feedback_->OnSpellcheckResults(kRendererProcessId + i,
+ kTextWithDuplicates,
+ std::vector<SpellCheckMarker>(),
+ &results);
+ last_renderer_process_id = kRendererProcessId + i;
+ }
+ std::vector<uint32_t> remaining_markers;
+ for (size_t i = 0; i < results.size(); ++i)
+ remaining_markers.push_back(results[i].hash);
+ feedback_->OnReceiveDocumentMarkers(last_renderer_process_id,
+ remaining_markers);
+ EXPECT_TRUE(UploadDataContains("PENDING", 2));
+ EXPECT_FALSE(UploadDataContains("ADD_TO_DICT"));
+
+ feedback_->AddedToDictionary(results[0].hash);
+ feedback_->OnReceiveDocumentMarkers(last_renderer_process_id,
+ remaining_markers);
+ EXPECT_FALSE(UploadDataContains("PENDING"));
+ EXPECT_TRUE(UploadDataContains("ADD_TO_DICT", 2));
+}
+
+// ADD_TO_DICT feedback for multiple occurrences of a word should trigger only
+// for pending feedback.
+TEST_F(FeedbackSenderTest, AddToDictOnlyPending) {
+ AddPendingFeedback();
+ uint32_t add_to_dict_hash = AddPendingFeedback();
+ uint32_t select_hash = AddPendingFeedback();
+ feedback_->SelectedSuggestion(select_hash, 0);
+ feedback_->AddedToDictionary(add_to_dict_hash);
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(UploadDataContains("SELECT", 1));
+ EXPECT_TRUE(UploadDataContains("ADD_TO_DICT", 2));
+}
+
+// Spellcheck results that are out-of-bounds are not added to feedback.
+TEST_F(FeedbackSenderTest, IgnoreOutOfBounds) {
+ std::vector<SpellCheckResult> results;
+ results.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 0, 100, base::UTF8ToUTF16("Hello")));
+ results.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 100, 3, base::UTF8ToUTF16("world")));
+ results.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, -1, 3, base::UTF8ToUTF16("how")));
+ results.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 0, 0, base::UTF8ToUTF16("are")));
+ results.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 2, -1, base::UTF8ToUTF16("you")));
+ feedback_->OnSpellcheckResults(kRendererProcessId,
+ base::UTF8ToUTF16(kText),
+ std::vector<SpellCheckMarker>(),
+ &results);
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_FALSE(IsUploadingData());
+}
+
+// FeedbackSender does not collect and upload feedback when instructed to stop.
+TEST_F(FeedbackSenderTest, CanStopFeedbackCollection) {
+ feedback_->StopFeedbackCollection();
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_FALSE(IsUploadingData());
+}
+
+// FeedbackSender resumes collecting and uploading feedback when instructed to
+// start after stopping.
+TEST_F(FeedbackSenderTest, CanResumeFeedbackCollection) {
+ feedback_->StopFeedbackCollection();
+ feedback_->StartFeedbackCollection();
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(IsUploadingData());
+}
+
+// FeedbackSender does not collect data while being stopped and upload it later.
+TEST_F(FeedbackSenderTest, NoFeedbackCollectionWhenStopped) {
+ feedback_->StopFeedbackCollection();
+ AddPendingFeedback();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ feedback_->StartFeedbackCollection();
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_FALSE(IsUploadingData());
+}
+
+// The feedback context is trimmed to 2 words on the left and 2 words on the
+// right side of the misspelling.
+TEST_F(FeedbackSenderTest, TrimFeedback) {
+ std::vector<SpellCheckResult> results(
+ 1, SpellCheckResult(SpellCheckResult::SPELLING, 13, 3,
+ base::UTF8ToUTF16("the")));
+ feedback_->OnSpellcheckResults(
+ kRendererProcessId,
+ base::UTF8ToUTF16("Far and away teh best prize that life has to offer is "
+ "the chance to work hard at work worth doing."),
+ std::vector<SpellCheckMarker>(), &results);
+ feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(
+ UploadDataContains(",\"originalText\":\"and away teh best prize\","));
+ EXPECT_TRUE(UploadDataContains(",\"misspelledStart\":9,"));
+}
+
+} // namespace spellcheck
diff --git a/chromium/components/spellcheck/browser/feedback_unittest.cc b/chromium/components/spellcheck/browser/feedback_unittest.cc
new file mode 100644
index 00000000000..5c68747bcfd
--- /dev/null
+++ b/chromium/components/spellcheck/browser/feedback_unittest.cc
@@ -0,0 +1,302 @@
+// 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.
+//
+// Unit tests for |Feedback| object.
+
+#include "components/spellcheck/browser/feedback.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ASCIIToUTF16;
+
+namespace spellcheck {
+
+namespace {
+
+// Maximum number of bytes of feedback that would be sent to the server at once.
+const size_t kMaxFeedbackSize = 1024;
+
+// Identifier for a renderer process.
+const int kRendererProcessId = 7;
+
+// Hash identifier for a misspelling.
+const uint32_t kMisspellingHash = 42;
+
+} // namespace
+
+// A test fixture to help keep the tests simple.
+class FeedbackTest : public testing::Test {
+ public:
+ FeedbackTest() : feedback_(kMaxFeedbackSize) {}
+ ~FeedbackTest() override {}
+
+ protected:
+ void AddMisspelling(int renderer_process_id, uint32_t hash) {
+ feedback_.AddMisspelling(renderer_process_id,
+ Misspelling(base::string16(), 0, 0,
+ std::vector<base::string16>(), hash));
+ }
+
+ spellcheck::Feedback feedback_;
+};
+
+TEST_F(FeedbackTest, LimitFeedbackSize) {
+ // Adding too much feedback data should prevent adding more feedback.
+ feedback_.AddMisspelling(
+ kRendererProcessId,
+ Misspelling(
+ base::ASCIIToUTF16("0123456789"), 0, 1,
+ std::vector<base::string16>(50, base::ASCIIToUTF16("9876543210")),
+ 0));
+ feedback_.AddMisspelling(
+ kRendererProcessId,
+ Misspelling(
+ base::ASCIIToUTF16("0123456789"), 0, 1,
+ std::vector<base::string16>(50, base::ASCIIToUTF16("9876543210")),
+ kMisspellingHash));
+ EXPECT_EQ(nullptr, feedback_.GetMisspelling(kMisspellingHash));
+
+ // Clearing the existing feedback data should allow adding feedback again.
+ feedback_.Clear();
+ feedback_.AddMisspelling(
+ kRendererProcessId,
+ Misspelling(
+ base::ASCIIToUTF16("0123456789"), 0, 1,
+ std::vector<base::string16>(50, base::ASCIIToUTF16("9876543210")),
+ kMisspellingHash));
+ EXPECT_NE(nullptr, feedback_.GetMisspelling(kMisspellingHash));
+ feedback_.Clear();
+
+ // Erasing finalized misspellings should allow adding feedback again.
+ feedback_.AddMisspelling(
+ kRendererProcessId,
+ Misspelling(
+ base::ASCIIToUTF16("0123456789"), 0, 1,
+ std::vector<base::string16>(50, base::ASCIIToUTF16("9876543210")),
+ 0));
+ feedback_.FinalizeRemovedMisspellings(kRendererProcessId,
+ std::vector<uint32_t>());
+ feedback_.EraseFinalizedMisspellings(kRendererProcessId);
+ feedback_.AddMisspelling(
+ kRendererProcessId,
+ Misspelling(
+ base::ASCIIToUTF16("0123456789"), 0, 1,
+ std::vector<base::string16>(50, base::ASCIIToUTF16("9876543210")),
+ kMisspellingHash));
+ EXPECT_NE(nullptr, feedback_.GetMisspelling(kMisspellingHash));
+}
+
+// Should be able to retrieve misspelling after it's added.
+TEST_F(FeedbackTest, RetreiveMisspelling) {
+ EXPECT_EQ(nullptr, feedback_.GetMisspelling(kMisspellingHash));
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ Misspelling* result = feedback_.GetMisspelling(kMisspellingHash);
+ EXPECT_NE(nullptr, result);
+ EXPECT_EQ(kMisspellingHash, result->hash);
+}
+
+// Removed misspellings should be finalized.
+TEST_F(FeedbackTest, FinalizeRemovedMisspellings) {
+ static const int kRemovedMisspellingHash = 1;
+ static const int kRemainingMisspellingHash = 2;
+ AddMisspelling(kRendererProcessId, kRemovedMisspellingHash);
+ AddMisspelling(kRendererProcessId, kRemainingMisspellingHash);
+ std::vector<uint32_t> remaining_markers(1, kRemainingMisspellingHash);
+ feedback_.FinalizeRemovedMisspellings(kRendererProcessId, remaining_markers);
+ Misspelling* removed_misspelling =
+ feedback_.GetMisspelling(kRemovedMisspellingHash);
+ EXPECT_NE(nullptr, removed_misspelling);
+ EXPECT_TRUE(removed_misspelling->action.IsFinal());
+ Misspelling* remaining_misspelling =
+ feedback_.GetMisspelling(kRemainingMisspellingHash);
+ EXPECT_NE(nullptr, remaining_misspelling);
+ EXPECT_FALSE(remaining_misspelling->action.IsFinal());
+}
+
+// Duplicate misspellings should not be finalized.
+TEST_F(FeedbackTest, DuplicateMisspellingFinalization) {
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ std::vector<uint32_t> remaining_markers(1, kMisspellingHash);
+ feedback_.FinalizeRemovedMisspellings(kRendererProcessId, remaining_markers);
+ std::vector<Misspelling> misspellings = feedback_.GetAllMisspellings();
+ EXPECT_EQ(static_cast<size_t>(1), misspellings.size());
+ EXPECT_FALSE(misspellings[0].action.IsFinal());
+}
+
+// Misspellings should be associated with a renderer.
+TEST_F(FeedbackTest, RendererHasMisspellings) {
+ EXPECT_FALSE(feedback_.RendererHasMisspellings(kRendererProcessId));
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ EXPECT_TRUE(feedback_.RendererHasMisspellings(kRendererProcessId));
+}
+
+// Should be able to retrieve misspellings in renderer.
+TEST_F(FeedbackTest, GetMisspellingsInRenderer) {
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ const std::vector<Misspelling>& renderer_with_misspellings =
+ feedback_.GetMisspellingsInRenderer(kRendererProcessId);
+ EXPECT_EQ(static_cast<size_t>(1), renderer_with_misspellings.size());
+ EXPECT_EQ(kMisspellingHash, renderer_with_misspellings[0].hash);
+ const std::vector<Misspelling>& renderer_without_misspellings =
+ feedback_.GetMisspellingsInRenderer(kRendererProcessId + 1);
+ EXPECT_EQ(static_cast<size_t>(0), renderer_without_misspellings.size());
+}
+
+// Finalized misspellings should be erased.
+TEST_F(FeedbackTest, EraseFinalizedMisspellings) {
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ feedback_.FinalizeRemovedMisspellings(kRendererProcessId,
+ std::vector<uint32_t>());
+ EXPECT_TRUE(feedback_.RendererHasMisspellings(kRendererProcessId));
+ feedback_.EraseFinalizedMisspellings(kRendererProcessId);
+ EXPECT_FALSE(feedback_.RendererHasMisspellings(kRendererProcessId));
+ EXPECT_TRUE(feedback_.GetMisspellingsInRenderer(kRendererProcessId).empty());
+}
+
+// Should be able to check for misspelling existence.
+TEST_F(FeedbackTest, HasMisspelling) {
+ EXPECT_FALSE(feedback_.HasMisspelling(kMisspellingHash));
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ EXPECT_TRUE(feedback_.HasMisspelling(kMisspellingHash));
+}
+
+// Should be able to check for feedback data presence.
+TEST_F(FeedbackTest, EmptyFeedback) {
+ EXPECT_TRUE(feedback_.Empty());
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ EXPECT_FALSE(feedback_.Empty());
+}
+
+// Should be able to retrieve a list of all renderers with misspellings.
+TEST_F(FeedbackTest, GetRendersWithMisspellings) {
+ EXPECT_TRUE(feedback_.GetRendersWithMisspellings().empty());
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ AddMisspelling(kRendererProcessId + 1, kMisspellingHash + 1);
+ std::vector<int> result = feedback_.GetRendersWithMisspellings();
+ EXPECT_EQ(static_cast<size_t>(2), result.size());
+ EXPECT_NE(result[0], result[1]);
+ EXPECT_TRUE(result[0] == kRendererProcessId ||
+ result[0] == kRendererProcessId + 1);
+ EXPECT_TRUE(result[1] == kRendererProcessId ||
+ result[1] == kRendererProcessId + 1);
+}
+
+// Should be able to finalize all misspellings.
+TEST_F(FeedbackTest, FinalizeAllMisspellings) {
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ AddMisspelling(kRendererProcessId + 1, kMisspellingHash + 1);
+ {
+ std::vector<Misspelling> pending = feedback_.GetAllMisspellings();
+ for (std::vector<Misspelling>::const_iterator it = pending.begin();
+ it != pending.end(); ++it) {
+ EXPECT_FALSE(it->action.IsFinal());
+ }
+ }
+ feedback_.FinalizeAllMisspellings();
+ {
+ std::vector<Misspelling> final = feedback_.GetAllMisspellings();
+ for (std::vector<Misspelling>::const_iterator it = final.begin();
+ it != final.end(); ++it) {
+ EXPECT_TRUE(it->action.IsFinal());
+ }
+ }
+}
+
+// Should be able to retrieve a copy of all misspellings.
+TEST_F(FeedbackTest, GetAllMisspellings) {
+ EXPECT_TRUE(feedback_.GetAllMisspellings().empty());
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ AddMisspelling(kRendererProcessId + 1, kMisspellingHash + 1);
+ const std::vector<Misspelling>& result = feedback_.GetAllMisspellings();
+ EXPECT_EQ(static_cast<size_t>(2), result.size());
+ EXPECT_NE(result[0].hash, result[1].hash);
+ EXPECT_TRUE(result[0].hash == kMisspellingHash ||
+ result[0].hash == kMisspellingHash + 1);
+ EXPECT_TRUE(result[1].hash == kMisspellingHash ||
+ result[1].hash == kMisspellingHash + 1);
+}
+
+// Should be able to clear all misspellings.
+TEST_F(FeedbackTest, ClearFeedback) {
+ AddMisspelling(kRendererProcessId, kMisspellingHash);
+ AddMisspelling(kRendererProcessId + 1, kMisspellingHash + 1);
+ EXPECT_FALSE(feedback_.Empty());
+ feedback_.Clear();
+ EXPECT_TRUE(feedback_.Empty());
+}
+
+// Should be able to find misspellings by misspelled word.
+TEST_F(FeedbackTest, FindMisspellingsByText) {
+ static const base::string16 kMisspelledText =
+ ASCIIToUTF16("Helllo world. Helllo world");
+ static const base::string16 kSuggestion = ASCIIToUTF16("Hello");
+ static const int kMisspellingStart = 0;
+ static const int kMisspellingLength = 6;
+ static const int kSentenceLength = 14;
+ static const int kNumberOfSentences = 2;
+ static const int kNumberOfRenderers = 2;
+ uint32_t hash = kMisspellingHash;
+ for (int renderer_process_id = kRendererProcessId;
+ renderer_process_id < kRendererProcessId + kNumberOfRenderers;
+ ++renderer_process_id) {
+ for (int j = 0; j < kNumberOfSentences; ++j) {
+ feedback_.AddMisspelling(
+ renderer_process_id,
+ Misspelling(kMisspelledText, kMisspellingStart + j * kSentenceLength,
+ kMisspellingLength,
+ std::vector<base::string16>(1, kSuggestion), ++hash));
+ }
+ }
+
+ static const base::string16 kOtherMisspelledText =
+ ASCIIToUTF16("Somethign else");
+ static const base::string16 kOtherSuggestion = ASCIIToUTF16("Something");
+ static const int kOtherMisspellingStart = 0;
+ static const int kOtherMisspellingLength = 9;
+ feedback_.AddMisspelling(
+ kRendererProcessId,
+ Misspelling(kOtherMisspelledText, kOtherMisspellingStart,
+ kOtherMisspellingLength,
+ std::vector<base::string16>(1, kOtherSuggestion), hash + 1));
+
+ static const base::string16 kMisspelledWord = ASCIIToUTF16("Helllo");
+ const std::set<uint32_t>& misspellings =
+ feedback_.FindMisspellings(kMisspelledWord);
+ EXPECT_EQ(static_cast<size_t>(kNumberOfSentences * kNumberOfRenderers),
+ misspellings.size());
+
+ for (std::set<uint32_t>::const_iterator it = misspellings.begin();
+ it != misspellings.end(); ++it) {
+ Misspelling* misspelling = feedback_.GetMisspelling(*it);
+ EXPECT_NE(nullptr, misspelling);
+ EXPECT_TRUE(misspelling->hash >= kMisspellingHash &&
+ misspelling->hash <= hash);
+ EXPECT_EQ(kMisspelledWord, GetMisspelledString(*misspelling));
+ }
+}
+
+// Should not be able to find misspellings by misspelled word after they have
+// been removed.
+TEST_F(FeedbackTest, CannotFindMisspellingsByTextAfterErased) {
+ static const base::string16 kMisspelledText = ASCIIToUTF16("Helllo world");
+ static const base::string16 kMisspelledWord = ASCIIToUTF16("Helllo");
+ static const base::string16 kSuggestion = ASCIIToUTF16("Hello");
+ static const int kMisspellingStart = 0;
+ static const int kMisspellingLength = 6;
+ feedback_.AddMisspelling(
+ kRendererProcessId,
+ Misspelling(kMisspelledText, kMisspellingStart, kMisspellingLength,
+ std::vector<base::string16>(1, kSuggestion),
+ kMisspellingHash));
+ feedback_.GetMisspelling(kMisspellingHash)->action.Finalize();
+ feedback_.EraseFinalizedMisspellings(kRendererProcessId);
+ EXPECT_TRUE(feedback_.FindMisspellings(kMisspelledWord).empty());
+}
+
+} // namespace spellcheck
diff --git a/chromium/components/spellcheck/browser/misspelling.cc b/chromium/components/spellcheck/browser/misspelling.cc
new file mode 100644
index 00000000000..9268a946f78
--- /dev/null
+++ b/chromium/components/spellcheck/browser/misspelling.cc
@@ -0,0 +1,86 @@
+// 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.
+//
+// The |Misspelling| object stores the misspelling, a spellcheck suggestion for
+// it, and user's action on it. The misspelling is stored as |context|,
+// |location|, and |length| instead of only misspelled text, because the
+// spellcheck algorithm uses the context.
+
+#include "components/spellcheck/browser/misspelling.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+
+namespace {
+
+// Builds a value from a list of spellcheck suggestions.
+std::unique_ptr<base::Value> BuildSuggestionsValue(
+ const std::vector<base::string16>& list) {
+ std::unique_ptr<base::ListValue> result(new base::ListValue);
+ result->AppendStrings(list);
+ return std::move(result);
+}
+
+// Builds a value from a spellcheck action.
+std::unique_ptr<base::Value> BuildUserActionValue(
+ const SpellcheckAction& action) {
+ std::unique_ptr<base::ListValue> result(new base::ListValue);
+ result->Append(action.Serialize());
+ return std::move(result);
+}
+
+} // namespace
+
+Misspelling::Misspelling()
+ : location(0), length(0), hash(0), timestamp(base::Time::Now()) {}
+
+Misspelling::Misspelling(const base::string16& context,
+ size_t location,
+ size_t length,
+ const std::vector<base::string16>& suggestions,
+ uint32_t hash)
+ : context(context),
+ location(location),
+ length(length),
+ suggestions(suggestions),
+ hash(hash),
+ timestamp(base::Time::Now()) {}
+
+Misspelling::Misspelling(const Misspelling& other) = default;
+
+Misspelling::~Misspelling() {}
+
+std::unique_ptr<base::DictionaryValue> SerializeMisspelling(
+ const Misspelling& misspelling) {
+ std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
+ result->SetString(
+ "timestamp",
+ base::Int64ToString(static_cast<long>(misspelling.timestamp.ToJsTime())));
+ result->SetInteger("misspelledLength", misspelling.length);
+ result->SetInteger("misspelledStart", misspelling.location);
+ result->SetString("originalText", misspelling.context);
+ result->SetString("suggestionId", base::UintToString(misspelling.hash));
+ result->Set("suggestions",
+ BuildSuggestionsValue(misspelling.suggestions).release());
+ result->Set("userActions",
+ BuildUserActionValue(misspelling.action).release());
+ return result;
+}
+
+base::string16 GetMisspelledString(const Misspelling& misspelling) {
+ // Feedback sender does not create Misspelling objects for spellcheck results
+ // that are out-of-bounds of checked text length.
+ if (misspelling.location > misspelling.context.length())
+ return base::string16();
+ return misspelling.context.substr(misspelling.location, misspelling.length);
+}
+
+size_t ApproximateSerializedSize(const Misspelling& misspelling) {
+ // Estimated by eyeballing JSON overhead.
+ const size_t kNumberOfOverheadBytes = 180;
+ size_t result = misspelling.context.length() + kNumberOfOverheadBytes;
+ for (const base::string16& suggestion : misspelling.suggestions)
+ result += suggestion.size();
+ return result;
+}
diff --git a/chromium/components/spellcheck/browser/misspelling.h b/chromium/components/spellcheck/browser/misspelling.h
new file mode 100644
index 00000000000..3ce5a63f0d9
--- /dev/null
+++ b/chromium/components/spellcheck/browser/misspelling.h
@@ -0,0 +1,79 @@
+// 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.
+//
+// An object to store user feedback to a single spellcheck suggestion.
+//
+// Stores the spellcheck suggestion, its uint32_t hash identifier, and user's
+// feedback. The feedback is indirect, in the sense that we record user's
+// |action| instead of asking them how they feel about a spellcheck suggestion.
+// The object can serialize itself.
+
+#ifndef COMPONENTS_SPELLCHECK_BROWSER_MISSPELLING_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_MISSPELLING_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/time/time.h"
+#include "components/spellcheck/browser/spellcheck_action.h"
+
+// Stores user feedback to a spellcheck suggestion. Sample usage:
+// Misspelling misspelling.
+// misspelling.context = base::ASCIIToUTF16("Helllo world");
+// misspelling.location = 0;
+// misspelling.length = 6;
+// misspelling.suggestions =
+// std::vector<base::string16>(1, base::ASCIIToUTF16("Hello"));
+// misspelling.hash = GenerateRandomHash();
+// misspelling.action.set_type(SpellcheckAction::TYPE_SELECT);
+// misspelling.action.set_index(0);
+// Process(SerializeMisspelling(misspelling));
+struct Misspelling {
+ Misspelling();
+ Misspelling(const base::string16& context,
+ size_t location,
+ size_t length,
+ const std::vector<base::string16>& suggestions,
+ uint32_t hash);
+ Misspelling(const Misspelling& other);
+ ~Misspelling();
+
+ // A several-word text snippet that immediately surrounds the misspelling.
+ base::string16 context;
+
+ // The number of characters between the beginning of |context| and the first
+ // misspelled character.
+ size_t location;
+
+ // The number of characters in the misspelling.
+ size_t length;
+
+ // Spelling suggestions.
+ std::vector<base::string16> suggestions;
+
+ // The hash that identifies the misspelling.
+ uint32_t hash;
+
+ // User action.
+ SpellcheckAction action;
+
+ // The time when the user applied the action.
+ base::Time timestamp;
+};
+
+// Serializes the data in this object into a dictionary value.
+std::unique_ptr<base::DictionaryValue> SerializeMisspelling(
+ const Misspelling& misspelling);
+
+// Returns the substring of |context| that begins at |location| and contains
+// |length| characters.
+base::string16 GetMisspelledString(const Misspelling& misspelling);
+
+// Returns the approximate size of the misspelling when serialized.
+size_t ApproximateSerializedSize(const Misspelling& misspelling);
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_MISSPELLING_H_
diff --git a/chromium/components/spellcheck/browser/misspelling_unittest.cc b/chromium/components/spellcheck/browser/misspelling_unittest.cc
new file mode 100644
index 00000000000..ec0b8c24f8f
--- /dev/null
+++ b/chromium/components/spellcheck/browser/misspelling_unittest.cc
@@ -0,0 +1,53 @@
+// 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.
+//
+// Unit tests for |Misspelling| object.
+
+#include "components/spellcheck/browser/misspelling.h"
+
+#include "base/json/json_reader.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(MisspellingTest, SerializeTest) {
+ Misspelling misspelling;
+ misspelling.context = base::ASCIIToUTF16("How doe sit know");
+ misspelling.location = 4;
+ misspelling.length = 7;
+ misspelling.timestamp = base::Time::FromJsTime(42);
+ misspelling.hash = 9001;
+ misspelling.suggestions.push_back(base::ASCIIToUTF16("does it"));
+
+ std::unique_ptr<base::Value> expected = base::JSONReader::Read(
+ "{\"originalText\": \"How doe sit know\","
+ "\"misspelledStart\": 4,"
+ "\"misspelledLength\": 7,"
+ "\"timestamp\": \"42\","
+ "\"suggestionId\":\"9001\","
+ "\"suggestions\": [\"does it\"],"
+ "\"userActions\": [{\"actionType\": \"PENDING\"}]}");
+
+ std::unique_ptr<base::DictionaryValue> serialized(
+ SerializeMisspelling(misspelling));
+ EXPECT_TRUE(serialized->Equals(expected.get()));
+}
+
+TEST(MisspellingTest, GetMisspelledStringTest) {
+ Misspelling misspelling;
+ misspelling.context = base::ASCIIToUTF16("How doe sit know");
+ misspelling.location = 4;
+ misspelling.length = 7;
+ EXPECT_EQ(base::ASCIIToUTF16("doe sit"), GetMisspelledString(misspelling));
+
+ misspelling.length = 0;
+ EXPECT_EQ(base::string16(), GetMisspelledString(misspelling));
+
+ misspelling.location = misspelling.context.length();
+ misspelling.length = 7;
+ EXPECT_EQ(base::string16(), GetMisspelledString(misspelling));
+
+ misspelling.location = misspelling.context.length() + 1;
+ EXPECT_EQ(base::string16(), GetMisspelledString(misspelling));
+}
diff --git a/chromium/components/spellcheck/browser/pref_names.cc b/chromium/components/spellcheck/browser/pref_names.cc
new file mode 100644
index 00000000000..7c544bfb9ee
--- /dev/null
+++ b/chromium/components/spellcheck/browser/pref_names.cc
@@ -0,0 +1,24 @@
+// 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 "components/spellcheck/browser/pref_names.h"
+
+namespace spellcheck {
+namespace prefs {
+
+// Boolean pref to define the default values for using spellchecker.
+const char kEnableSpellcheck[] = "browser.enable_spellchecking";
+
+// String which represents the dictionary name for our spell-checker.
+// This is an old preference that is being migrated to kSpellCheckDictionaries.
+const char kSpellCheckDictionary[] = "spellcheck.dictionary";
+
+// List of strings representing the dictionary names for our spell-checker.
+const char kSpellCheckDictionaries[] = "spellcheck.dictionaries";
+
+// String which represents whether we use the spelling service.
+const char kSpellCheckUseSpellingService[] = "spellcheck.use_spelling_service";
+
+} // namespace prefs
+} // namespace spellcheck
diff --git a/chromium/components/spellcheck/browser/pref_names.h b/chromium/components/spellcheck/browser/pref_names.h
new file mode 100644
index 00000000000..be374e5dc8c
--- /dev/null
+++ b/chromium/components/spellcheck/browser/pref_names.h
@@ -0,0 +1,19 @@
+// 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 COMPONENTS_SPELLCHECK_BROWSER_PREF_NAMES_H
+#define COMPONENTS_SPELLCHECK_BROWSER_PREF_NAMES_H
+
+namespace spellcheck {
+namespace prefs {
+
+extern const char kEnableSpellcheck[];
+extern const char kSpellCheckDictionaries[];
+extern const char kSpellCheckDictionary[];
+extern const char kSpellCheckUseSpellingService[];
+
+} // namespace prefs
+} // namespace spellcheck
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_PREF_NAMES_H
diff --git a/chromium/components/spellcheck/browser/spellcheck_action.cc b/chromium/components/spellcheck/browser/spellcheck_action.cc
new file mode 100644
index 00000000000..f34001b8fd9
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_action.cc
@@ -0,0 +1,74 @@
+// 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 "components/spellcheck/browser/spellcheck_action.h"
+
+#include "base/logging.h"
+#include "base/values.h"
+
+SpellcheckAction::SpellcheckAction() : type_(TYPE_PENDING), index_(-1) {}
+
+SpellcheckAction::SpellcheckAction(SpellcheckActionType type,
+ int index,
+ base::string16 value)
+ : type_(type), index_(index), value_(value) {}
+
+SpellcheckAction::~SpellcheckAction() {}
+
+bool SpellcheckAction::IsFinal() const {
+ return type_ == TYPE_ADD_TO_DICT ||
+ type_ == TYPE_IGNORE ||
+ type_ == TYPE_IN_DICTIONARY ||
+ type_ == TYPE_MANUALLY_CORRECTED ||
+ type_ == TYPE_NO_ACTION ||
+ type_ == TYPE_SELECT;
+}
+
+void SpellcheckAction::Finalize() {
+ switch (type_) {
+ case TYPE_PENDING:
+ type_ = TYPE_NO_ACTION;
+ break;
+ case TYPE_PENDING_IGNORE:
+ type_ = TYPE_IGNORE;
+ break;
+ default:
+ DCHECK(IsFinal());
+ break;
+ }
+}
+
+std::unique_ptr<base::DictionaryValue> SpellcheckAction::Serialize() const {
+ std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
+ switch (type_) {
+ case TYPE_SELECT:
+ result->SetString("actionType", "SELECT");
+ result->SetInteger("actionTargetIndex", index_);
+ break;
+ case TYPE_ADD_TO_DICT:
+ result->SetString("actionType", "ADD_TO_DICT");
+ break;
+ case TYPE_IGNORE:
+ result->SetString("actionType", "IGNORE");
+ break;
+ case TYPE_IN_DICTIONARY:
+ result->SetString("actionType", "IN_DICTIONARY");
+ break;
+ case TYPE_NO_ACTION:
+ result->SetString("actionType", "NO_ACTION");
+ break;
+ case TYPE_MANUALLY_CORRECTED:
+ result->SetString("actionType", "MANUALLY_CORRECTED");
+ result->SetString("actionTargetValue", value_);
+ break;
+ case TYPE_PENDING:
+ case TYPE_PENDING_IGNORE:
+ result->SetString("actionType", "PENDING");
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return result;
+}
diff --git a/chromium/components/spellcheck/browser/spellcheck_action.h b/chromium/components/spellcheck/browser/spellcheck_action.h
new file mode 100644
index 00000000000..2320da671f9
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_action.h
@@ -0,0 +1,83 @@
+// 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 COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_ACTION_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_ACTION_H_
+
+#include <memory>
+
+#include "base/strings/string16.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+// User's action on a misspelled word.
+class SpellcheckAction {
+ public:
+ // Type of spellcheck action.
+ enum SpellcheckActionType {
+ // User added the word to the dictionary and cannot take more actions on
+ // this misspelling.
+ TYPE_ADD_TO_DICT,
+ // User took a look at the suggestions in the context menu, but did not
+ // select any suggestions. The user cannot take any more actions on the
+ // misspelling, because it has been deleted from the web page.
+ TYPE_IGNORE,
+ // The misspelling is in user's custom spellcheck dictionary. The user will
+ // not see spellcheck suggestions for this misspelling.
+ TYPE_IN_DICTIONARY,
+ // The user manually corrected the word to |value|. The user cannot take
+ // more actions on this misspelling.
+ TYPE_MANUALLY_CORRECTED,
+ // The user has taken no action on the misspelling and will not take any
+ // more actions, because the misspelled text has been removed from the web
+ // page.
+ TYPE_NO_ACTION,
+ // The user has taken no action on the misspelled yet, but might take an
+ // action in the future, because the misspelling is still on the web page.
+ TYPE_PENDING,
+ // User took a look at the suggestions in the context menu, but did not
+ // select any suggestions. The user still can take further actions on the
+ // misspelling.
+ TYPE_PENDING_IGNORE,
+ // The user has selected the suggestion at |index| and cannot take more
+ // actions on this misspelling.
+ TYPE_SELECT,
+ };
+
+ SpellcheckAction();
+ SpellcheckAction(SpellcheckActionType type, int index, base::string16 value);
+ ~SpellcheckAction();
+
+ // Returns true if the action is final and should be sent to the feedback
+ // server. Otherwise returns false.
+ bool IsFinal() const;
+
+ // Makes this action final and ready to be sent to the feedback server. The
+ // method is idempotent. Finalizing an action that is already final does
+ // nothing.
+ void Finalize();
+
+ // Serializes the data in this object into a dictionary value.
+ std::unique_ptr<base::DictionaryValue> Serialize() const;
+
+ void set_type(SpellcheckActionType type) { type_ = type; }
+ void set_index(int index) { index_ = index; }
+ void set_value(const base::string16& value) { value_ = value; }
+
+ SpellcheckActionType type() const { return type_; }
+
+ private:
+ // User action.
+ SpellcheckActionType type_;
+
+ // The index for the user action, if applicable.
+ int index_;
+
+ // The value for the user action, if applicable.
+ base::string16 value_;
+};
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_ACTION_H_
diff --git a/chromium/components/spellcheck/browser/spellcheck_action_unittest.cc b/chromium/components/spellcheck/browser/spellcheck_action_unittest.cc
new file mode 100644
index 00000000000..b5e031a170d
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_action_unittest.cc
@@ -0,0 +1,100 @@
+// 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 "components/spellcheck/browser/spellcheck_action.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SpellcheckActionTest, FinalActionsTest) {
+ static const SpellcheckAction::SpellcheckActionType kFinalActions[] = {
+ SpellcheckAction::TYPE_ADD_TO_DICT,
+ SpellcheckAction::TYPE_IGNORE,
+ SpellcheckAction::TYPE_IN_DICTIONARY,
+ SpellcheckAction::TYPE_MANUALLY_CORRECTED,
+ SpellcheckAction::TYPE_NO_ACTION,
+ SpellcheckAction::TYPE_SELECT,
+ };
+ SpellcheckAction action;
+ for (size_t i = 0; i < arraysize(kFinalActions); ++i) {
+ action.set_type(kFinalActions[i]);
+ ASSERT_TRUE(action.IsFinal());
+ }
+}
+
+TEST(SpellcheckActionTest, PendingActionsTest) {
+ static const SpellcheckAction::SpellcheckActionType kPendingActions[] = {
+ SpellcheckAction::TYPE_PENDING,
+ SpellcheckAction::TYPE_PENDING_IGNORE,
+ };
+ SpellcheckAction action;
+ for (size_t i = 0; i < arraysize(kPendingActions); ++i) {
+ action.set_type(kPendingActions[i]);
+ ASSERT_FALSE(action.IsFinal());
+ }
+}
+
+TEST(SpellcheckActionTest, FinalizeTest) {
+ SpellcheckAction action;
+ action.set_type(SpellcheckAction::TYPE_PENDING);
+ action.Finalize();
+ ASSERT_EQ(SpellcheckAction::TYPE_NO_ACTION, action.type());
+
+ action.set_type(SpellcheckAction::TYPE_PENDING_IGNORE);
+ action.Finalize();
+ ASSERT_EQ(SpellcheckAction::TYPE_IGNORE, action.type());
+}
+
+TEST(SpellcheckActionTest, SerializeTest) {
+ static const size_t kNumTestCases = 7;
+ static const struct {
+ SpellcheckAction action;
+ std::string expected;
+ } kTestCases[] = {
+ { SpellcheckAction(
+ SpellcheckAction::TYPE_ADD_TO_DICT, -1,
+ base::ASCIIToUTF16("nothing")),
+ "{\"actionType\": \"ADD_TO_DICT\"}" },
+ { SpellcheckAction(
+ SpellcheckAction::TYPE_IGNORE, -1, base::ASCIIToUTF16("nothing")),
+ "{\"actionType\": \"IGNORE\"}" },
+ { SpellcheckAction(
+ SpellcheckAction::TYPE_IN_DICTIONARY, -1,
+ base::ASCIIToUTF16("nothing")),
+ "{\"actionType\": \"IN_DICTIONARY\"}" },
+ { SpellcheckAction(
+ SpellcheckAction::TYPE_MANUALLY_CORRECTED, -1,
+ base::ASCIIToUTF16("hello")),
+ "{\"actionTargetValue\": \"hello\","
+ "\"actionType\": \"MANUALLY_CORRECTED\"}" },
+ { SpellcheckAction(
+ SpellcheckAction::TYPE_NO_ACTION, -1, base::ASCIIToUTF16("nothing")),
+ "{\"actionType\": \"NO_ACTION\"}" },
+ { SpellcheckAction(
+ SpellcheckAction::TYPE_PENDING, -1, base::ASCIIToUTF16("nothing")),
+ "{\"actionType\": \"PENDING\"}" },
+ { SpellcheckAction(
+ SpellcheckAction::TYPE_PENDING_IGNORE, -1,
+ base::ASCIIToUTF16("nothing")),
+ "{\"actionType\": \"PENDING\"}" },
+ { SpellcheckAction(
+ SpellcheckAction::TYPE_SELECT, 42, base::ASCIIToUTF16("nothing")),
+ "{\"actionTargetIndex\": 42, \"actionType\": \"SELECT\"}" },
+ };
+ for (size_t i = 0; i < kNumTestCases; ++i) {
+ std::unique_ptr<base::DictionaryValue> serialized(
+ kTestCases[i].action.Serialize());
+ std::unique_ptr<base::Value> expected =
+ base::JSONReader::Read(kTestCases[i].expected);
+ EXPECT_TRUE(serialized->Equals(expected.get()));
+ }
+}
diff --git a/chromium/components/spellcheck/browser/spellcheck_dictionary.h b/chromium/components/spellcheck/browser/spellcheck_dictionary.h
new file mode 100644
index 00000000000..7d79a710322
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_dictionary.h
@@ -0,0 +1,23 @@
+// 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 COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_DICTIONARY_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_DICTIONARY_H_
+
+#include "base/macros.h"
+
+// Defines a dictionary for use in the spellchecker system and provides access
+// to words within the dictionary.
+class SpellcheckDictionary {
+ public:
+ SpellcheckDictionary() {}
+ virtual ~SpellcheckDictionary() {}
+
+ virtual void Load() = 0;
+
+ protected:
+ DISALLOW_COPY_AND_ASSIGN(SpellcheckDictionary);
+};
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_DICTIONARY_H_
diff --git a/chromium/components/spellcheck/browser/spellcheck_host_metrics.cc b/chromium/components/spellcheck/browser/spellcheck_host_metrics.cc
new file mode 100644
index 00000000000..19a253e6c39
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_host_metrics.cc
@@ -0,0 +1,149 @@
+// 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 "components/spellcheck/browser/spellcheck_host_metrics.h"
+
+#include <stdint.h>
+
+#include "base/md5.h"
+#include "base/metrics/histogram_macros.h"
+
+SpellCheckHostMetrics::SpellCheckHostMetrics()
+ : misspelled_word_count_(0),
+ last_misspelled_word_count_(-1),
+ spellchecked_word_count_(0),
+ last_spellchecked_word_count_(-1),
+ suggestion_show_count_(0),
+ last_suggestion_show_count_(-1),
+ replaced_word_count_(0),
+ last_replaced_word_count_(-1),
+ last_unique_word_count_(-1),
+ start_time_(base::TimeTicks::Now()) {
+ const uint64_t kHistogramTimerDurationInMinutes = 30;
+ recording_timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMinutes(kHistogramTimerDurationInMinutes),
+ this, &SpellCheckHostMetrics::OnHistogramTimerExpired);
+ RecordWordCounts();
+}
+
+SpellCheckHostMetrics::~SpellCheckHostMetrics() {
+}
+
+// static
+void SpellCheckHostMetrics::RecordCustomWordCountStats(size_t count) {
+ UMA_HISTOGRAM_COUNTS("SpellCheck.CustomWords", count);
+}
+
+void SpellCheckHostMetrics::RecordEnabledStats(bool enabled) {
+ UMA_HISTOGRAM_BOOLEAN("SpellCheck.Enabled", enabled);
+ // Because SpellCheckHost is instantiated lazily, the size of
+ // custom dictionary is unknown at this time. We mark it as -1 and
+ // record actual value later. See SpellCheckHost for more detail.
+ if (enabled)
+ RecordCustomWordCountStats(static_cast<size_t>(-1));
+}
+
+void SpellCheckHostMetrics::RecordCheckedWordStats(const base::string16& word,
+ bool misspell) {
+ spellchecked_word_count_++;
+ if (misspell) {
+ misspelled_word_count_++;
+ // If an user misspelled, that user should be counted as a part of
+ // the population. So we ensure to instantiate the histogram
+ // entries here at the first time.
+ if (misspelled_word_count_ == 1)
+ RecordReplacedWordStats(0);
+ }
+
+ int percentage = (100 * misspelled_word_count_) / spellchecked_word_count_;
+ UMA_HISTOGRAM_PERCENTAGE("SpellCheck.MisspellRatio", percentage);
+
+ // Collects actual number of checked words, excluding duplication.
+ base::MD5Digest digest;
+ base::MD5Sum(reinterpret_cast<const unsigned char*>(word.c_str()),
+ word.size() * sizeof(base::char16), &digest);
+ checked_word_hashes_.insert(base::MD5DigestToBase16(digest));
+
+ RecordWordCounts();
+}
+
+void SpellCheckHostMetrics::OnHistogramTimerExpired() {
+ if (0 < spellchecked_word_count_) {
+ // Collects word checking rate, which is represented
+ // as a word count per hour.
+ base::TimeDelta since_start = base::TimeTicks::Now() - start_time_;
+ // This shouldn't happen since OnHistogramTimerExpired() is called on
+ // a 30 minute interval. If the time was 0 we will end up dividing by zero.
+ CHECK_NE(0, since_start.InSeconds());
+ size_t checked_words_per_hour = spellchecked_word_count_ *
+ base::TimeDelta::FromHours(1).InSeconds() / since_start.InSeconds();
+ UMA_HISTOGRAM_COUNTS("SpellCheck.CheckedWordsPerHour",
+ checked_words_per_hour);
+ }
+}
+
+void SpellCheckHostMetrics::RecordDictionaryCorruptionStats(bool corrupted) {
+ UMA_HISTOGRAM_BOOLEAN("SpellCheck.DictionaryCorrupted", corrupted);
+}
+
+void SpellCheckHostMetrics::RecordSuggestionStats(int delta) {
+ suggestion_show_count_ += delta;
+ // RecordReplacedWordStats() Calls RecordWordCounts() eventually.
+ RecordReplacedWordStats(0);
+}
+
+void SpellCheckHostMetrics::RecordReplacedWordStats(int delta) {
+ replaced_word_count_ += delta;
+
+ if (misspelled_word_count_) {
+ // zero |misspelled_word_count_| is possible when an extension
+ // gives the misspelling, which is not recorded as a part of this
+ // metrics.
+ int percentage = (100 * replaced_word_count_) / misspelled_word_count_;
+ UMA_HISTOGRAM_PERCENTAGE("SpellCheck.ReplaceRatio", percentage);
+ }
+
+ if (suggestion_show_count_) {
+ int percentage = (100 * replaced_word_count_) / suggestion_show_count_;
+ UMA_HISTOGRAM_PERCENTAGE("SpellCheck.SuggestionHitRatio", percentage);
+ }
+
+ RecordWordCounts();
+}
+
+void SpellCheckHostMetrics::RecordWordCounts() {
+ if (spellchecked_word_count_ != last_spellchecked_word_count_) {
+ DCHECK(spellchecked_word_count_ > last_spellchecked_word_count_);
+ UMA_HISTOGRAM_COUNTS("SpellCheck.CheckedWords", spellchecked_word_count_);
+ last_spellchecked_word_count_ = spellchecked_word_count_;
+ }
+
+ if (misspelled_word_count_ != last_misspelled_word_count_) {
+ DCHECK(misspelled_word_count_ > last_misspelled_word_count_);
+ UMA_HISTOGRAM_COUNTS("SpellCheck.MisspelledWords", misspelled_word_count_);
+ last_misspelled_word_count_ = misspelled_word_count_;
+ }
+
+ if (replaced_word_count_ != last_replaced_word_count_) {
+ DCHECK(replaced_word_count_ > last_replaced_word_count_);
+ UMA_HISTOGRAM_COUNTS("SpellCheck.ReplacedWords", replaced_word_count_);
+ last_replaced_word_count_ = replaced_word_count_;
+ }
+
+ if (((int)checked_word_hashes_.size()) != last_unique_word_count_) {
+ DCHECK((int)checked_word_hashes_.size() > last_unique_word_count_);
+ UMA_HISTOGRAM_COUNTS("SpellCheck.UniqueWords", checked_word_hashes_.size());
+ last_unique_word_count_ = checked_word_hashes_.size();
+ }
+
+ if (suggestion_show_count_ != last_suggestion_show_count_) {
+ DCHECK(suggestion_show_count_ > last_suggestion_show_count_);
+ UMA_HISTOGRAM_COUNTS("SpellCheck.ShownSuggestions", suggestion_show_count_);
+ last_suggestion_show_count_ = suggestion_show_count_;
+ }
+}
+
+void SpellCheckHostMetrics::RecordSpellingServiceStats(bool enabled) {
+ UMA_HISTOGRAM_BOOLEAN("SpellCheck.SpellingService.Enabled", enabled);
+}
diff --git a/chromium/components/spellcheck/browser/spellcheck_host_metrics.h b/chromium/components/spellcheck/browser/spellcheck_host_metrics.h
new file mode 100644
index 00000000000..d2f0db7e61c
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_host_metrics.h
@@ -0,0 +1,97 @@
+// 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 COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_HOST_METRICS_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_HOST_METRICS_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+// A helper object for recording spell-check related histograms.
+// This class encapsulates histogram names and metrics API.
+// This also carries a set of counters for collecting histograms
+// and a timer for making a periodical summary.
+//
+// We expect a user of SpellCheckHost class to instantiate this object,
+// and pass the metrics object to SpellCheckHost's factory method.
+//
+// metrics.reset(new SpellCheckHostMetrics());
+// spell_check_host = SpellChecHost::Create(...., metrics.get());
+//
+// The lifetime of the object should be managed by a caller,
+// and the lifetime should be longer than SpellCheckHost instance
+// because SpellCheckHost will use the object.
+class SpellCheckHostMetrics {
+ public:
+ SpellCheckHostMetrics();
+ ~SpellCheckHostMetrics();
+
+ // Collects the number of words in the custom dictionary, which is
+ // to be uploaded via UMA.
+ static void RecordCustomWordCountStats(size_t count);
+
+ // Collects status of spellchecking enabling state, which is
+ // to be uploaded via UMA
+ void RecordEnabledStats(bool enabled);
+
+ // Collects a histogram for dictionary corruption rate
+ // to be uploaded via UMA
+ void RecordDictionaryCorruptionStats(bool corrupted);
+
+ // Collects status of spellchecking enabling state, which is
+ // to be uploaded via UMA
+ void RecordCheckedWordStats(const base::string16& word, bool misspell);
+
+ // Collects a histogram for misspelled word replacement
+ // to be uploaded via UMA
+ void RecordReplacedWordStats(int delta);
+
+ // Collects a histogram for context menu showing as a spell correction
+ // attempt to be uploaded via UMA
+ void RecordSuggestionStats(int delta);
+
+ // Records if spelling service is enabled or disabled.
+ void RecordSpellingServiceStats(bool enabled);
+
+ private:
+ friend class SpellcheckHostMetricsTest;
+ void OnHistogramTimerExpired();
+
+ // Records various counters without changing their values.
+ void RecordWordCounts();
+
+ // Number of corrected words of checked words.
+ int misspelled_word_count_;
+ int last_misspelled_word_count_;
+
+ // Number of checked words.
+ int spellchecked_word_count_;
+ int last_spellchecked_word_count_;
+
+ // Number of suggestion list showings.
+ int suggestion_show_count_;
+ int last_suggestion_show_count_;
+
+ // Number of misspelled words replaced by a user.
+ int replaced_word_count_;
+ int last_replaced_word_count_;
+
+ // Last recorded number of unique words.
+ int last_unique_word_count_;
+
+ // Time when first spellcheck happened.
+ base::TimeTicks start_time_;
+ // Set of checked words in the hashed form.
+ base::hash_set<std::string> checked_word_hashes_;
+ base::RepeatingTimer recording_timer_;
+};
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_HOST_METRICS_H_
diff --git a/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc b/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc
new file mode 100644
index 00000000000..b77ddb28dc5
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc
@@ -0,0 +1,116 @@
+// 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 "components/spellcheck/browser/spellcheck_host_metrics.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/histogram_tester.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+// For version specific disabled tests below (http://crbug.com/230534).
+#include "base/win/windows_version.h"
+#endif
+
+class SpellcheckHostMetricsTest : public testing::Test {
+ public:
+ SpellcheckHostMetricsTest() {
+ }
+
+ static void SetUpTestCase() {
+ base::StatisticsRecorder::Initialize();
+ }
+
+ void SetUp() override { metrics_.reset(new SpellCheckHostMetrics); }
+
+ SpellCheckHostMetrics* metrics() { return metrics_.get(); }
+ void RecordWordCountsForTesting() { metrics_->RecordWordCounts(); }
+
+ private:
+ base::MessageLoop loop_;
+ std::unique_ptr<SpellCheckHostMetrics> metrics_;
+};
+
+TEST_F(SpellcheckHostMetricsTest, RecordEnabledStats) {
+ const char kMetricName[] = "SpellCheck.Enabled";
+ base::HistogramTester histogram_tester1;
+
+ metrics()->RecordEnabledStats(false);
+
+ histogram_tester1.ExpectBucketCount(kMetricName, 0, 1);
+ histogram_tester1.ExpectBucketCount(kMetricName, 1, 0);
+
+ base::HistogramTester histogram_tester2;
+
+ metrics()->RecordEnabledStats(true);
+
+ histogram_tester2.ExpectBucketCount(kMetricName, 0, 0);
+ histogram_tester2.ExpectBucketCount(kMetricName, 1, 1);
+}
+
+TEST_F(SpellcheckHostMetricsTest, CustomWordStats) {
+#if defined(OS_WIN)
+// Failing consistently on Win7. See crbug.com/230534.
+ if (base::win::GetVersion() >= base::win::VERSION_VISTA)
+ return;
+#endif
+ SpellCheckHostMetrics::RecordCustomWordCountStats(123);
+
+ // Determine if test failures are due the statistics recorder not being
+ // available or because the histogram just isn't there: crbug.com/230534.
+ EXPECT_TRUE(base::StatisticsRecorder::IsActive());
+
+ base::HistogramTester histogram_tester;
+
+ SpellCheckHostMetrics::RecordCustomWordCountStats(23);
+ histogram_tester.ExpectBucketCount("SpellCheck.CustomWords", 23, 1);
+}
+
+TEST_F(SpellcheckHostMetricsTest, RecordWordCountsDiscardsDuplicates) {
+ // This test ensures that RecordWordCounts only records metrics if they
+ // have changed from the last invocation.
+ const char* const histogram_names[] = {
+ "SpellCheck.CheckedWords", "SpellCheck.MisspelledWords",
+ "SpellCheck.ReplacedWords", "SpellCheck.UniqueWords",
+ "SpellCheck.ShownSuggestions"};
+
+ // Ensure all histograms exist.
+ metrics()->RecordCheckedWordStats(base::ASCIIToUTF16("test"), false);
+ RecordWordCountsForTesting();
+
+ // Create the tester, taking a snapshot of current histogram samples.
+ base::HistogramTester histogram_tester;
+
+ // Nothing changed, so this invocation should not affect any histograms.
+ RecordWordCountsForTesting();
+
+ // Get samples for all affected histograms.
+ for (size_t i = 0; i < arraysize(histogram_names); ++i)
+ histogram_tester.ExpectTotalCount(histogram_names[i], 0);
+}
+
+TEST_F(SpellcheckHostMetricsTest, RecordSpellingServiceStats) {
+ const char kMetricName[] = "SpellCheck.SpellingService.Enabled";
+ base::HistogramTester histogram_tester1;
+
+ metrics()->RecordSpellingServiceStats(false);
+
+ histogram_tester1.ExpectBucketCount(kMetricName, 0, 1);
+ histogram_tester1.ExpectBucketCount(kMetricName, 1, 0);
+
+ base::HistogramTester histogram_tester2;
+
+ metrics()->RecordSpellingServiceStats(true);
+ histogram_tester2.ExpectBucketCount(kMetricName, 0, 0);
+ histogram_tester2.ExpectBucketCount(kMetricName, 1, 1);
+}
diff --git a/chromium/components/spellcheck/browser/spellcheck_message_filter_platform.h b/chromium/components/spellcheck/browser/spellcheck_message_filter_platform.h
new file mode 100644
index 00000000000..3acdcf059c4
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_message_filter_platform.h
@@ -0,0 +1,77 @@
+// 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 COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_MESSAGE_FILTER_PLATFORM_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_MESSAGE_FILTER_PLATFORM_H_
+
+#include <map>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "components/spellcheck/browser/spelling_service_client.h"
+#include "components/spellcheck/common/spellcheck_marker.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "content/public/browser/browser_message_filter.h"
+
+class SpellCheckerSessionBridge;
+
+// A message filter implementation that receives
+// the platform-specific spell checker requests from SpellCheckProvider.
+class SpellCheckMessageFilterPlatform : public content::BrowserMessageFilter {
+ public:
+ explicit SpellCheckMessageFilterPlatform(int render_process_id);
+
+ // BrowserMessageFilter implementation.
+ void OverrideThreadForMessage(const IPC::Message& message,
+ content::BrowserThread::ID* thread) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ // Adjusts remote_results by examining local_results. Any result that's both
+ // local and remote stays type SPELLING, all others are flagged GRAMMAR.
+ // (This is needed to force gray underline for remote-only results.)
+ static void CombineResults(
+ std::vector<SpellCheckResult>* remote_results,
+ const std::vector<SpellCheckResult>& local_results);
+
+ private:
+ friend class TestingSpellCheckMessageFilter;
+ friend class SpellcheckMessageFilterPlatformMacTest;
+
+ ~SpellCheckMessageFilterPlatform() override;
+
+ void OnCheckSpelling(const base::string16& word, int route_id, bool* correct);
+ void OnFillSuggestionList(const base::string16& word,
+ std::vector<base::string16>* suggestions);
+ void OnShowSpellingPanel(bool show);
+ void OnUpdateSpellingPanelWithMisspelledWord(const base::string16& word);
+ void OnRequestTextCheck(int route_id,
+ int identifier,
+ const base::string16& text,
+ std::vector<SpellCheckMarker> markers);
+
+ int ToDocumentTag(int route_id);
+ void RetireDocumentTag(int route_id);
+ std::map<int,int> tag_map_;
+
+ int render_process_id_;
+
+#if defined(OS_ANDROID)
+ friend struct content::BrowserThread::DeleteOnThread<
+ content::BrowserThread::UI>;
+ friend class base::DeleteHelper<SpellCheckMessageFilterPlatform>;
+
+ void OnToggleSpellCheck(bool enabled, bool checked);
+ void OnDestruct() const override;
+
+ // Android-specific object used to query the Android spellchecker.
+ std::unique_ptr<SpellCheckerSessionBridge> impl_;
+#else
+ // A JSON-RPC client that calls the Spelling service in the background.
+ std::unique_ptr<SpellingServiceClient> client_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(SpellCheckMessageFilterPlatform);
+};
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_MESSAGE_FILTER_PLATFORM_H_
diff --git a/chromium/components/spellcheck/browser/spellcheck_message_filter_platform_android.cc b/chromium/components/spellcheck/browser/spellcheck_message_filter_platform_android.cc
new file mode 100644
index 00000000000..ed3c41e3c8d
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_message_filter_platform_android.cc
@@ -0,0 +1,105 @@
+// 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 "components/spellcheck/browser/spellcheck_message_filter_platform.h"
+
+#include "components/spellcheck/browser/spellchecker_session_bridge_android.h"
+#include "components/spellcheck/common/spellcheck_messages.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+SpellCheckMessageFilterPlatform::SpellCheckMessageFilterPlatform(
+ int render_process_id)
+ : BrowserMessageFilter(SpellCheckMsgStart),
+ render_process_id_(render_process_id),
+ impl_(new SpellCheckerSessionBridge(render_process_id)) {}
+
+void SpellCheckMessageFilterPlatform::OverrideThreadForMessage(
+ const IPC::Message& message, BrowserThread::ID* thread) {
+ switch (message.type()) {
+ case SpellCheckHostMsg_RequestTextCheck::ID:
+ case SpellCheckHostMsg_ToggleSpellCheck::ID:
+ *thread = BrowserThread::UI;
+ break;
+ default:
+ break;
+ }
+}
+
+bool SpellCheckMessageFilterPlatform::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(SpellCheckMessageFilterPlatform, message)
+ IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RequestTextCheck, OnRequestTextCheck)
+ IPC_MESSAGE_HANDLER(SpellCheckHostMsg_ToggleSpellCheck, OnToggleSpellCheck)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+// static
+void SpellCheckMessageFilterPlatform::CombineResults(
+ std::vector<SpellCheckResult>* remote_results,
+ const std::vector<SpellCheckResult>& local_results) {
+ NOTREACHED();
+}
+
+SpellCheckMessageFilterPlatform::~SpellCheckMessageFilterPlatform() {}
+
+void SpellCheckMessageFilterPlatform::OnCheckSpelling(
+ const base::string16& word,
+ int route_id,
+ bool* correct) {
+ NOTREACHED();
+}
+
+void SpellCheckMessageFilterPlatform::OnFillSuggestionList(
+ const base::string16& word,
+ std::vector<base::string16>* suggestions) {
+ NOTREACHED();
+}
+
+void SpellCheckMessageFilterPlatform::OnShowSpellingPanel(bool show) {
+ NOTREACHED();
+}
+
+void SpellCheckMessageFilterPlatform::OnUpdateSpellingPanelWithMisspelledWord(
+ const base::string16& word) {
+ NOTREACHED();
+}
+
+void SpellCheckMessageFilterPlatform::OnRequestTextCheck(
+ int route_id,
+ int identifier,
+ const base::string16& text,
+ std::vector<SpellCheckMarker> markers) {
+ DCHECK(!text.empty());
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ impl_->RequestTextCheck(route_id, identifier, text);
+}
+
+int SpellCheckMessageFilterPlatform::ToDocumentTag(int route_id) {
+ NOTREACHED();
+ return -1;
+}
+
+void SpellCheckMessageFilterPlatform::RetireDocumentTag(int route_id) {
+ NOTREACHED();
+}
+
+void SpellCheckMessageFilterPlatform::OnToggleSpellCheck(
+ bool enabled,
+ bool checked) {
+ if (!enabled)
+ impl_->DisconnectSession();
+}
+
+void SpellCheckMessageFilterPlatform::OnDestruct() const {
+ // Needs to be destroyed on the UI thread, to avoid race conditions
+ // on the java side during clean-up.
+ BrowserThread::DeleteOnUIThread::Destruct(this);
+}
diff --git a/chromium/components/spellcheck/browser/spellcheck_platform.h b/chromium/components/spellcheck/browser/spellcheck_platform.h
new file mode 100644
index 00000000000..4455046239a
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_platform.h
@@ -0,0 +1,115 @@
+// 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.
+
+// This file defines the interface that any platform-specific spellchecker
+// needs to implement in order to be used by the browser.
+
+#ifndef COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_PLATFORM_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_PLATFORM_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/strings/string16.h"
+
+struct SpellCheckResult;
+
+namespace content {
+class BrowserMessageFilter;
+} // namespace content
+
+namespace spellcheck_platform {
+
+typedef base::Callback<void(
+ const std::vector<SpellCheckResult>& /* results */)>
+ TextCheckCompleteCallback;
+
+// Get the languages supported by the platform spellchecker and store them in
+// |spellcheck_languages|. Note that they must be converted to
+// Chromium style codes (en-US not en_US). See spellchecker.cc for a full list.
+void GetAvailableLanguages(std::vector<std::string>* spellcheck_languages);
+
+// Returns the language used for spellchecking on the platform.
+std::string GetSpellCheckerLanguage();
+
+// Returns true if there is a platform-specific spellchecker that can be used.
+bool SpellCheckerAvailable();
+
+// Returns true if the platform spellchecker has a spelling panel.
+bool SpellCheckerProvidesPanel();
+
+// Returns true if the platform spellchecker panel is visible.
+bool SpellingPanelVisible();
+
+// Shows the spelling panel if |show| is true and hides it if it is not.
+void ShowSpellingPanel(bool show);
+
+// Changes the word show in the spelling panel to be |word|. Note that the
+// spelling panel need not be displayed for this to work.
+void UpdateSpellingPanelWithMisspelledWord(const base::string16& word);
+
+// Translates the codes used by chrome to the language codes used by os x
+// and checks the given language agains the languages that the current system
+// supports. If the platform-specific spellchecker supports the language,
+// then returns true, otherwise false.
+bool PlatformSupportsLanguage(const std::string& current_language);
+
+// Sets the language for the platform-specific spellchecker.
+void SetLanguage(const std::string& lang_to_set);
+
+// Checks the spelling of the given string, using the platform-specific
+// spellchecker. Returns true if the word is spelled correctly.
+bool CheckSpelling(const base::string16& word_to_check, int tag);
+
+// Fills the given vector |optional_suggestions| with a number (up to
+// kMaxSuggestions, which is defined in spellchecker_common.h) of suggestions
+// for the string |wrong_word|.
+void FillSuggestionList(const base::string16& wrong_word,
+ std::vector<base::string16>* optional_suggestions);
+
+// Adds the given word to the platform dictionary.
+void AddWord(const base::string16& word);
+
+// Remove a given word from the platform dictionary.
+void RemoveWord(const base::string16& word);
+
+// Gets a unique tag to identify a document. Used in ignoring words.
+int GetDocumentTag();
+
+// Tells the platform spellchecker to ignore a word. This doesn't take a tag
+// because in most of the situations in which it is called, the only way to know
+// the tag for sure is to ask the renderer, which would mean blocking in the
+// browser, so (on the mac, anyway) we remember the most recent tag and use
+// it, since it should always be from the same document.
+void IgnoreWord(const base::string16& word);
+
+// Tells the platform spellchecker that a document associated with a tag has
+// closed. Generally, this means that any ignored words associated with that
+// document can now be forgotten.
+void CloseDocumentWithTag(int tag);
+
+// Requests an asyncronous spell and grammar checking.
+// The result is returned to an IPC message to |destination| thus it should
+// not be null.
+void RequestTextCheck(int document_tag,
+ const base::string16& text,
+ TextCheckCompleteCallback callback);
+
+// Internal state, to restore system state after testing.
+// Not public since it contains Cocoa data types.
+class SpellcheckerStateInternal;
+
+// Test helper, forces the system spellchecker to en-US for its lifetime.
+class ScopedEnglishLanguageForTest {
+ public:
+ ScopedEnglishLanguageForTest();
+ ~ScopedEnglishLanguageForTest();
+ private:
+ SpellcheckerStateInternal* state_;
+};
+
+} // namespace spellcheck_platform
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECK_PLATFORM_H_
diff --git a/chromium/components/spellcheck/browser/spellcheck_platform_android.cc b/chromium/components/spellcheck/browser/spellcheck_platform_android.cc
new file mode 100644
index 00000000000..3cca6be1772
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_platform_android.cc
@@ -0,0 +1,75 @@
+// 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 "components/spellcheck/browser/spellcheck_platform.h"
+
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "components/spellcheck/common/spellcheck_features.h"
+
+namespace spellcheck_platform {
+
+void GetAvailableLanguages(std::vector<std::string>* spellcheck_languages) {
+}
+
+std::string GetSpellCheckerLanguage() {
+ return std::string();
+}
+
+bool SpellCheckerAvailable() {
+ return spellcheck::IsAndroidSpellCheckFeatureEnabled();
+}
+
+bool SpellCheckerProvidesPanel() {
+ return false;
+}
+
+bool SpellingPanelVisible() {
+ return false;
+}
+
+void ShowSpellingPanel(bool show) {
+}
+
+void UpdateSpellingPanelWithMisspelledWord(const base::string16& word) {
+}
+
+bool PlatformSupportsLanguage(const std::string& current_language) {
+ return true;
+}
+
+void SetLanguage(const std::string& lang_to_set) {
+}
+
+bool CheckSpelling(const base::string16& word_to_check, int tag) {
+ return true;
+}
+
+void FillSuggestionList(const base::string16& wrong_word,
+ std::vector<base::string16>* optional_suggestions) {
+}
+
+void AddWord(const base::string16& word) {
+}
+
+void RemoveWord(const base::string16& word) {
+}
+
+int GetDocumentTag() {
+ return 1;
+}
+
+void IgnoreWord(const base::string16& word) {
+}
+
+void CloseDocumentWithTag(int tag) {
+}
+
+void RequestTextCheck(int document_tag,
+ const base::string16& text,
+ TextCheckCompleteCallback callback) {
+
+}
+
+} // namespace spellcheck_platform
diff --git a/chromium/components/spellcheck/browser/spellcheck_platform_mac.mm b/chromium/components/spellcheck/browser/spellcheck_platform_mac.mm
new file mode 100644
index 00000000000..0461807230b
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_platform_mac.mm
@@ -0,0 +1,309 @@
+// 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.
+
+// Integration with OS X built-in spellchecker.
+
+#include "components/spellcheck/browser/spellcheck_platform.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/time/time.h"
+#include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "content/public/browser/browser_message_filter.h"
+#include "content/public/browser/browser_thread.h"
+
+using base::TimeTicks;
+using content::BrowserMessageFilter;
+using content::BrowserThread;
+
+namespace {
+// The number of characters in the first part of the language code.
+const unsigned int kShortLanguageCodeSize = 2;
+
+// +[NSSpellChecker sharedSpellChecker] can throw exceptions depending
+// on the state of the pasteboard, or possibly as a result of
+// third-party code (when setting up services entries). The following
+// receives nil if an exception is thrown, in which case
+// spell-checking will not work, but it also will not crash the
+// browser.
+NSSpellChecker* SharedSpellChecker() {
+ @try {
+ return [NSSpellChecker sharedSpellChecker];
+ } @catch (id exception) {
+ return nil;
+ }
+}
+
+// A private utility function to convert hunspell language codes to OS X
+// language codes.
+NSString* ConvertLanguageCodeToMac(const std::string& hunspell_lang_code) {
+ NSString* whole_code = base::SysUTF8ToNSString(hunspell_lang_code);
+
+ if ([whole_code length] > kShortLanguageCodeSize) {
+ NSString* lang_code = [whole_code
+ substringToIndex:kShortLanguageCodeSize];
+ // Add 1 here to skip the underscore.
+ NSString* region_code = [whole_code
+ substringFromIndex:(kShortLanguageCodeSize + 1)];
+
+ // Check for the special case of en-US and pt-PT, since OS X lists these
+ // as just en and pt respectively.
+ // TODO(pwicks): Find out if there are other special cases for languages
+ // not installed on the system by default. Are there others like pt-PT?
+ if (([lang_code isEqualToString:@"en"] &&
+ [region_code isEqualToString:@"US"]) ||
+ ([lang_code isEqualToString:@"pt"] &&
+ [region_code isEqualToString:@"PT"])) {
+ return lang_code;
+ }
+
+ // Otherwise, just build a string that uses an underscore instead of a
+ // dash between the language and the region code, since this is the
+ // format that OS X uses.
+ NSString* os_x_language =
+ [NSString stringWithFormat:@"%@_%@", lang_code, region_code];
+ return os_x_language;
+ } else {
+ // Special case for Polish.
+ if ([whole_code isEqualToString:@"pl"]) {
+ return @"pl_PL";
+ }
+ // This is just a language code with the same format as OS X
+ // language code.
+ return whole_code;
+ }
+}
+
+std::string ConvertLanguageCodeFromMac(NSString* lang_code) {
+ // TODO(pwicks):figure out what to do about Multilingual
+ // Guards for strange cases.
+ if ([lang_code isEqualToString:@"en"]) return std::string("en-US");
+ if ([lang_code isEqualToString:@"pt"]) return std::string("pt-PT");
+ if ([lang_code isEqualToString:@"pl_PL"]) return std::string("pl");
+
+ if ([lang_code length] > kShortLanguageCodeSize &&
+ [lang_code characterAtIndex:kShortLanguageCodeSize] == '_') {
+ return base::SysNSStringToUTF8([NSString stringWithFormat:@"%@-%@",
+ [lang_code substringToIndex:kShortLanguageCodeSize],
+ [lang_code substringFromIndex:(kShortLanguageCodeSize + 1)]]);
+ }
+ return base::SysNSStringToUTF8(lang_code);
+}
+
+} // namespace
+
+namespace spellcheck_platform {
+
+void GetAvailableLanguages(std::vector<std::string>* spellcheck_languages) {
+ NSArray* availableLanguages = [SharedSpellChecker() availableLanguages];
+ for (NSString* lang_code in availableLanguages) {
+ spellcheck_languages->push_back(
+ ConvertLanguageCodeFromMac(lang_code));
+ }
+}
+
+std::string GetSpellCheckerLanguage() {
+ return ConvertLanguageCodeFromMac([SharedSpellChecker() language]);
+}
+
+bool SpellCheckerAvailable() {
+ // If this file was compiled, then we know that we are on OS X 10.5 at least
+ // and can safely return true here.
+ return true;
+}
+
+bool SpellCheckerProvidesPanel() {
+ // OS X has a Spelling Panel, so we can return true here.
+ return true;
+}
+
+bool SpellingPanelVisible() {
+ // This should only be called from the main thread.
+ DCHECK([NSThread currentThread] == [NSThread mainThread]);
+ return [[SharedSpellChecker() spellingPanel] isVisible];
+}
+
+void ShowSpellingPanel(bool show) {
+ if (show) {
+ [[SharedSpellChecker() spellingPanel]
+ performSelectorOnMainThread:@selector(makeKeyAndOrderFront:)
+ withObject:nil
+ waitUntilDone:YES];
+ } else {
+ [[SharedSpellChecker() spellingPanel]
+ performSelectorOnMainThread:@selector(close)
+ withObject:nil
+ waitUntilDone:YES];
+ }
+}
+
+void UpdateSpellingPanelWithMisspelledWord(const base::string16& word) {
+ NSString * word_to_display = base::SysUTF16ToNSString(word);
+ [SharedSpellChecker()
+ performSelectorOnMainThread:
+ @selector(updateSpellingPanelWithMisspelledWord:)
+ withObject:word_to_display
+ waitUntilDone:YES];
+}
+
+bool PlatformSupportsLanguage(const std::string& current_language) {
+ // First, convert the language to an OS X language code.
+ NSString* mac_lang_code = ConvertLanguageCodeToMac(current_language);
+
+ // Then grab the languages available.
+ NSArray* availableLanguages = [SharedSpellChecker() availableLanguages];
+
+ // Return true if the given language is supported by OS X.
+ return [availableLanguages containsObject:mac_lang_code];
+}
+
+void SetLanguage(const std::string& lang_to_set) {
+ // Do not set any language right now, since Chrome should honor the
+ // system spellcheck settings. (http://crbug.com/166046)
+ // Fix this once Chrome actually allows setting a spellcheck language
+ // in chrome://settings.
+ // NSString* NS_lang_to_set = ConvertLanguageCodeToMac(lang_to_set);
+ // [SharedSpellChecker() setLanguage:NS_lang_to_set];
+}
+
+static int last_seen_tag_;
+
+bool CheckSpelling(const base::string16& word_to_check, int tag) {
+ last_seen_tag_ = tag;
+
+ // -[NSSpellChecker checkSpellingOfString] returns an NSRange that
+ // we can look at to determine if a word is misspelled.
+ NSRange spell_range = {0,0};
+
+ // Convert the word to an NSString.
+ NSString* NS_word_to_check = base::SysUTF16ToNSString(word_to_check);
+ // Check the spelling, starting at the beginning of the word.
+ spell_range = [SharedSpellChecker()
+ checkSpellingOfString:NS_word_to_check startingAt:0
+ language:nil wrap:NO inSpellDocumentWithTag:tag
+ wordCount:NULL];
+
+ // If the length of the misspelled word == 0,
+ // then there is no misspelled word.
+ bool word_correct = (spell_range.length == 0);
+ return word_correct;
+}
+
+void FillSuggestionList(const base::string16& wrong_word,
+ std::vector<base::string16>* optional_suggestions) {
+ NSString* ns_wrong_word = base::SysUTF16ToNSString(wrong_word);
+ NSSpellChecker* checker = SharedSpellChecker();
+ NSString* language = [checker language];
+ NSArray* guesses =
+ [checker guessesForWordRange:NSMakeRange(0, [ns_wrong_word length])
+ inString:ns_wrong_word
+ language:language
+ inSpellDocumentWithTag:last_seen_tag_];
+ int i = 0;
+ for (NSString* guess in guesses) {
+ optional_suggestions->push_back(base::SysNSStringToUTF16(guess));
+ if (++i >= spellcheck::kMaxSuggestions)
+ break;
+ }
+}
+
+void AddWord(const base::string16& word) {
+ NSString* word_to_add = base::SysUTF16ToNSString(word);
+ [SharedSpellChecker() learnWord:word_to_add];
+}
+
+void RemoveWord(const base::string16& word) {
+ NSString *word_to_remove = base::SysUTF16ToNSString(word);
+ [SharedSpellChecker() unlearnWord:word_to_remove];
+}
+
+int GetDocumentTag() {
+ NSInteger doc_tag = [NSSpellChecker uniqueSpellDocumentTag];
+ return static_cast<int>(doc_tag);
+}
+
+void IgnoreWord(const base::string16& word) {
+ [SharedSpellChecker() ignoreWord:base::SysUTF16ToNSString(word)
+ inSpellDocumentWithTag:last_seen_tag_];
+}
+
+void CloseDocumentWithTag(int tag) {
+ [SharedSpellChecker() closeSpellDocumentWithTag:static_cast<NSInteger>(tag)];
+}
+
+void RequestTextCheck(int document_tag,
+ const base::string16& text,
+ TextCheckCompleteCallback callback) {
+ NSString* text_to_check = base::SysUTF16ToNSString(text);
+ NSRange range_to_check = NSMakeRange(0, [text_to_check length]);
+
+ [SharedSpellChecker()
+ requestCheckingOfString:text_to_check
+ range:range_to_check
+ types:NSTextCheckingTypeSpelling
+ options:nil
+ inSpellDocumentWithTag:document_tag
+ completionHandler:^(NSInteger,
+ NSArray *results,
+ NSOrthography*,
+ NSInteger) {
+ std::vector<SpellCheckResult> check_results;
+ for (NSTextCheckingResult* result in results) {
+ // Deliberately ignore non-spelling results. OSX at the very least
+ // delivers a result of NSTextCheckingTypeOrthography for the
+ // whole fragment, which underlines the entire checked range.
+ if ([result resultType] != NSTextCheckingTypeSpelling)
+ continue;
+
+ // In this use case, the spell checker should never
+ // return anything but a single range per result.
+ check_results.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING,
+ [result range].location,
+ [result range].length));
+ }
+ // TODO(groby): Verify we don't need to post from here.
+ callback.Run(check_results);
+ }];
+}
+
+class SpellcheckerStateInternal {
+ public:
+ SpellcheckerStateInternal();
+ ~SpellcheckerStateInternal();
+
+ private:
+ BOOL automaticallyIdentifiesLanguages_;
+ NSString* language_;
+};
+
+SpellcheckerStateInternal::SpellcheckerStateInternal() {
+ language_ = [SharedSpellChecker() language];
+ automaticallyIdentifiesLanguages_ =
+ [SharedSpellChecker() automaticallyIdentifiesLanguages];
+ [SharedSpellChecker() setLanguage:@"en"];
+ [SharedSpellChecker() setAutomaticallyIdentifiesLanguages:NO];
+}
+
+SpellcheckerStateInternal::~SpellcheckerStateInternal() {
+ [SharedSpellChecker() setLanguage:language_];
+ [SharedSpellChecker() setAutomaticallyIdentifiesLanguages:
+ automaticallyIdentifiesLanguages_];
+}
+
+ScopedEnglishLanguageForTest::ScopedEnglishLanguageForTest()
+ : state_(new SpellcheckerStateInternal) {
+}
+
+ScopedEnglishLanguageForTest::~ScopedEnglishLanguageForTest() {
+ delete state_;
+}
+
+} // namespace spellcheck_platform
diff --git a/chromium/components/spellcheck/browser/spellcheck_platform_mac_unittest.cc b/chromium/components/spellcheck/browser/spellcheck_platform_mac_unittest.cc
new file mode 100644
index 00000000000..7f9d41821ae
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellcheck_platform_mac_unittest.cc
@@ -0,0 +1,396 @@
+// 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 "components/spellcheck/browser/spellcheck_platform.h"
+
+#include <stddef.h>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class SpellcheckPlatformMacTest: public testing::Test {
+ public:
+ SpellcheckPlatformMacTest()
+ : callback_(base::Bind(&SpellcheckPlatformMacTest::CompletionCallback,
+ base::Unretained(this))),
+ callback_finished_(false) {}
+
+ void WaitForCallback() {
+ content::RunMessageLoop();
+ }
+
+ std::vector<SpellCheckResult> results_;
+ spellcheck_platform::TextCheckCompleteCallback callback_;
+ bool callback_finished_;
+
+ private:
+ void QuitMessageLoop() {
+ CHECK(base::MessageLoop::current() == &message_loop_);
+ base::MessageLoop::current()->QuitWhenIdle();
+ }
+
+ void CompletionCallback(const std::vector<SpellCheckResult>& results) {
+ results_ = results;
+ callback_finished_ = true;
+ message_loop_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&SpellcheckPlatformMacTest::QuitMessageLoop,
+ base::Unretained(this)));
+ }
+
+ base::MessageLoopForUI message_loop_;
+ spellcheck_platform::ScopedEnglishLanguageForTest scoped_language_;
+};
+
+// Tests that words are properly ignored. Currently only enabled on OS X as it
+// is the only platform to support ignoring words. Note that in this test, we
+// supply a non-zero doc_tag, in order to test that ignored words are matched to
+// the correct document.
+TEST_F(SpellcheckPlatformMacTest, IgnoreWords_EN_US) {
+ const char* kTestCases[] = {
+ "teh",
+ "morblier",
+ "watre",
+ "noooen",
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ const base::string16 word(base::ASCIIToUTF16(kTestCases[i]));
+ const int doc_tag = spellcheck_platform::GetDocumentTag();
+
+ // The word should show up as misspelled.
+ EXPECT_FALSE(spellcheck_platform::CheckSpelling(word, doc_tag)) << word;
+
+ // Ignore the word.
+ spellcheck_platform::IgnoreWord(word);
+
+ // The word should now show up as correctly spelled.
+ EXPECT_TRUE(spellcheck_platform::CheckSpelling(word, doc_tag)) << word;
+
+ // Close the docuemnt. Any words that we had previously ignored should no
+ // longer be ignored and thus should show up as misspelled.
+ spellcheck_platform::CloseDocumentWithTag(doc_tag);
+
+ // The word should now show be spelled wrong again
+ EXPECT_FALSE(spellcheck_platform::CheckSpelling(word, doc_tag)) << word;
+ }
+} // Test IgnoreWords_EN_US
+
+TEST_F(SpellcheckPlatformMacTest, SpellCheckSuggestions_EN_US) {
+ static const struct {
+ const char* input; // A string to be tested.
+ const char* suggested_word; // A suggested word that should occur.
+ } kTestCases[] = {
+ // We need to have separate test cases here, since hunspell and the OS X
+ // spellchecking service occasionally differ on what they consider a valid
+ // suggestion for a given word, although these lists could likely be
+ // integrated somewhat. The test cases for non-Mac are in
+ // chrome/renderer/spellcheck_unittest.cc
+ // These words come from the wikipedia page of the most commonly
+ // misspelled words in english.
+ // (http://en.wikipedia.org/wiki/Commonly_misspelled_words).
+ // However, 10.6 loads multiple dictionaries and enables many non-English
+ // dictionaries by default. As a result, we have removed from the list any
+ // word that is marked as correct because it is correct in another
+ // language.
+ {"absense", "absence"},
+ {"acceptible", "acceptable"},
+ {"accidentaly", "accidentally"},
+ {"acheive", "achieve"},
+ {"acknowlege", "acknowledge"},
+ {"acquaintence", "acquaintance"},
+ {"aquire", "acquire"},
+ {"aquit", "acquit"},
+ {"acrage", "acreage"},
+ {"adultary", "adultery"},
+ {"advertize", "advertise"},
+ {"adviseable", "advisable"},
+ {"alchohol", "alcohol"},
+ {"alege", "allege"},
+ {"allegaince", "allegiance"},
+ {"allmost", "almost"},
+ // Ideally, this test should pass. It works in firefox, but not in hunspell
+ // or OS X.
+ // {"alot", "a lot"},
+ {"amatuer", "amateur"},
+ {"ammend", "amend"},
+ {"amung", "among"},
+ {"anually", "annually"},
+ {"apparant", "apparent"},
+ {"artic", "arctic"},
+ {"arguement", "argument"},
+ {"athiest", "atheist"},
+ {"athelete", "athlete"},
+ {"avrage", "average"},
+ {"awfull", "awful"},
+ {"ballance", "balance"},
+ {"basicly", "basically"},
+ {"becuase", "because"},
+ {"becomeing", "becoming"},
+ {"befor", "before"},
+ {"begining", "beginning"},
+ {"beleive", "believe"},
+ {"bellweather", "bellwether"},
+ {"benifit", "benefit"},
+ // This particular spelling correction was removed in OSX 10.10. Replacing
+ // it with another spelling correction that also works on older OSes.
+ // {"bouy", "buoy"},
+ {"bouy", "body"},
+ {"briliant", "brilliant"},
+ {"burgler", "burglar"},
+ {"camoflage", "camouflage"},
+ {"carefull", "careful"},
+ {"Carribean", "Caribbean"},
+ {"catagory", "category"},
+ {"cauhgt", "caught"},
+ {"cieling", "ceiling"},
+ {"cemetary", "cemetery"},
+ {"certin", "certain"},
+ {"changable", "changeable"},
+ {"cheif", "chief"},
+ {"citezen", "citizen"},
+ {"collaegue", "colleague"},
+ {"colum", "column"},
+ {"comming", "coming"},
+ {"commited", "committed"},
+ {"compitition", "competition"},
+ {"conceed", "concede"},
+ {"congradulate", "congratulate"},
+ {"consciencious", "conscientious"},
+ {"concious", "conscious"},
+ {"concensus", "consensus"},
+ {"contraversy", "controversy"},
+ {"conveniance", "convenience"},
+ {"critecize", "criticize"},
+ {"dacquiri", "daiquiri"},
+ {"decieve", "deceive"},
+ {"dicide", "decide"},
+ {"definate", "definite"},
+ {"definitly", "definitely"},
+ {"desparate", "desperate"},
+ {"develope", "develop"},
+ {"diffrence", "difference"},
+ {"disapear", "disappear"},
+ {"disapoint", "disappoint"},
+ {"disasterous", "disastrous"},
+ {"disipline", "discipline"},
+ {"drunkeness", "drunkenness"},
+ {"dumbell", "dumbbell"},
+ {"easely", "easily"},
+ {"eigth", "eight"},
+ {"embarass", "embarrass"},
+ {"enviroment", "environment"},
+ {"equiped", "equipped"},
+ {"equiptment", "equipment"},
+ {"exagerate", "exaggerate"},
+ {"exellent", "excellent"},
+ {"exsept", "except"},
+ {"exercize", "exercise"},
+ {"exilerate", "exhilarate"},
+ {"existance", "existence"},
+ {"experiance", "experience"},
+ {"experament", "experiment"},
+ {"explaination", "explanation"},
+ {"facinating", "fascinating"},
+ {"firey", "fiery"},
+ {"finaly", "finally"},
+ {"flourescent", "fluorescent"},
+ {"foriegn", "foreign"},
+ {"fourty", "forty"},
+ {"foreward", "forward"},
+ {"freind", "friend"},
+ {"fundemental", "fundamental"},
+ {"guage", "gauge"},
+ {"generaly", "generally"},
+ {"goverment", "government"},
+ {"gratefull", "grateful"},
+ {"garantee", "guarantee"},
+ {"guidence", "guidance"},
+ {"happyness", "happiness"},
+ {"harrass", "harass"},
+ {"heighth", "height"},
+ {"heirarchy", "hierarchy"},
+ {"humerous", "humorous"},
+ {"hygene", "hygiene"},
+ {"hipocrit", "hypocrite"},
+ {"idenity", "identity"},
+ {"ignorence", "ignorance"},
+ {"imaginery", "imaginary"},
+ {"immitate", "imitate"},
+ {"immitation", "imitation"},
+ {"imediately", "immediately"},
+ {"incidently", "incidentally"},
+ {"independant", "independent"},
+ {"indispensible", "indispensable"},
+ {"innoculate", "inoculate"},
+ {"inteligence", "intelligence"},
+ {"intresting", "interesting"},
+ {"interuption", "interruption"},
+ {"irrelevent", "irrelevant"},
+ {"irritible", "irritable"},
+ {"jellous", "jealous"},
+ {"knowlege", "knowledge"},
+ {"labratory", "laboratory"},
+ {"lenght", "length"},
+ {"liason", "liaison"},
+ {"libary", "library"},
+ {"lisence", "license"},
+ {"lonelyness", "loneliness"},
+ {"lieing", "lying"},
+ {"maintenence", "maintenance"},
+ {"manuever", "maneuver"},
+ {"marrige", "marriage"},
+ {"mathmatics", "mathematics"},
+ {"medcine", "medicine"},
+ {"miniture", "miniature"},
+ {"minite", "minute"},
+ {"mischevous", "mischievous"},
+ {"mispell", "misspell"},
+ // Maybe this one should pass, as it works in hunspell, but not in firefox.
+ // {"misterius", "mysterious"},
+ {"naturaly", "naturally"},
+ {"neccessary", "necessary"},
+ {"neice", "niece"},
+ {"nieghbor", "neighbor"},
+ {"nieghbour", "neighbor"},
+ {"niether", "neither"},
+ {"noticable", "noticeable"},
+ {"occassion", "occasion"},
+ {"occasionaly", "occasionally"},
+ {"occurrance", "occurrence"},
+ {"occured", "occurred"},
+ {"ommision", "omission"},
+ {"oppurtunity", "opportunity"},
+ {"outragous", "outrageous"},
+ {"parrallel", "parallel"},
+ {"parliment", "parliament"},
+ {"particurly", "particularly"},
+ {"passtime", "pastime"},
+ {"peculier", "peculiar"},
+ {"percieve", "perceive"},
+ {"pernament", "permanent"},
+ {"perseverence", "perseverance"},
+ {"personaly", "personally"},
+ {"persaude", "persuade"},
+ {"pichure", "picture"},
+ {"peice", "piece"},
+ {"plagerize", "plagiarize"},
+ {"playright", "playwright"},
+ {"plesant", "pleasant"},
+ {"pollitical", "political"},
+ {"posession", "possession"},
+ {"potatos", "potatoes"},
+ {"practicle", "practical"},
+ {"preceed", "precede"},
+ {"predjudice", "prejudice"},
+ {"presance", "presence"},
+ {"privelege", "privilege"},
+ // This one should probably work. It does in FF and Hunspell.
+ // {"probly", "probably"},
+ {"proffesional", "professional"},
+ {"promiss", "promise"},
+ {"pronounciation", "pronunciation"},
+ {"prufe", "proof"},
+ {"psycology", "psychology"},
+ {"publically", "publicly"},
+ {"quanity", "quantity"},
+ {"quarentine", "quarantine"},
+ {"questionaire", "questionnaire"},
+ {"readible", "readable"},
+ {"realy", "really"},
+ {"recieve", "receive"},
+ {"reciept", "receipt"},
+ {"reconize", "recognize"},
+ {"recomend", "recommend"},
+ {"refered", "referred"},
+ {"referance", "reference"},
+ {"relevent", "relevant"},
+ {"religous", "religious"},
+ {"repitition", "repetition"},
+ {"restarant", "restaurant"},
+ {"rythm", "rhythm"},
+ {"rediculous", "ridiculous"},
+ {"sacrefice", "sacrifice"},
+ {"saftey", "safety"},
+ {"sissors", "scissors"},
+ {"secratary", "secretary"},
+ {"seperate", "separate"},
+ {"sargent", "sergeant"},
+ {"shineing", "shining"},
+ {"similer", "similar"},
+ {"sinceerly", "sincerely"},
+ {"speach", "speech"},
+ {"strenght", "strength"},
+ {"succesful", "successful"},
+ {"supercede", "supersede"},
+ {"surelly", "surely"},
+ {"suprise", "surprise"},
+ {"temperture", "temperature"},
+ {"temprary", "temporary"},
+ {"tommorrow", "tomorrow"},
+ {"tounge", "tongue"},
+ {"truely", "truly"},
+ {"twelth", "twelfth"},
+ {"tyrany", "tyranny"},
+ {"underate", "underrate"},
+ {"untill", "until"},
+ {"unuseual", "unusual"},
+ {"upholstry", "upholstery"},
+ {"usible", "usable"},
+ {"useing", "using"},
+ {"usualy", "usually"},
+ {"vaccuum", "vacuum"},
+ {"vegatarian", "vegetarian"},
+ {"vehical", "vehicle"},
+ {"visious", "vicious"},
+ {"villege", "village"},
+ {"wierd", "weird"},
+ {"wellcome", "welcome"},
+ {"wellfare", "welfare"},
+ {"wilfull", "willful"},
+ {"withold", "withhold"},
+ {"writting", "writing"},
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ const base::string16 word(base::ASCIIToUTF16(kTestCases[i].input));
+ EXPECT_FALSE(spellcheck_platform::CheckSpelling(word, 0)) << word;
+
+ // Check if the suggested words occur.
+ std::vector<base::string16> suggestions;
+ spellcheck_platform::FillSuggestionList(word, &suggestions);
+ bool suggested_word_is_present = false;
+ const base::string16 suggested_word(
+ base::ASCIIToUTF16(kTestCases[i].suggested_word));
+ for (size_t j = 0; j < suggestions.size(); j++) {
+ if (suggestions[j].compare(suggested_word) == 0) {
+ suggested_word_is_present = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(suggested_word_is_present) << suggested_word;
+ }
+}
+
+// The OSX spellchecker returns non-spellcheck results when invoked on a
+// sentence, specifically an NSTextCheckingTypeOrthography result indicating
+// the language used in that sentence. Test that it is filtered out from
+// RequestTextCheck results.
+TEST_F(SpellcheckPlatformMacTest, SpellCheckIgnoresOrthography) {
+ base::string16 test_string(base::ASCIIToUTF16("Icland is awesome."));
+ spellcheck_platform::RequestTextCheck(0, test_string, callback_);
+ WaitForCallback();
+ EXPECT_TRUE(callback_finished_);
+ EXPECT_EQ(1U, results_.size());
+}
+
+} // namespace
diff --git a/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc b/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc
new file mode 100644
index 00000000000..5c2644f8ecc
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc
@@ -0,0 +1,131 @@
+// 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 "components/spellcheck/browser/spellchecker_session_bridge_android.h"
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "components/spellcheck/common/spellcheck_messages.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "jni/SpellCheckerSessionBridge_jni.h"
+
+using base::android::JavaParamRef;
+
+SpellCheckerSessionBridge::SpellCheckerSessionBridge(int render_process_id)
+ : render_process_id_(render_process_id),
+ java_object_initialization_failed_(false) {}
+
+SpellCheckerSessionBridge::~SpellCheckerSessionBridge() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // Clean-up java side to avoid any stale JNI callbacks.
+ DisconnectSession();
+}
+
+// static
+bool SpellCheckerSessionBridge::RegisterJNI(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+void SpellCheckerSessionBridge::RequestTextCheck(int route_id,
+ int identifier,
+ const base::string16& text) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // SpellCheckerSessionBridge#create() will return null if spell checker
+ // service is unavailable.
+ if (java_object_initialization_failed_)
+ return;
+
+ // RequestTextCheck IPC arrives at the message filter before
+ // ToggleSpellCheck IPC when the user focuses an input field that already
+ // contains completed text. We need to initialize the spellchecker here
+ // rather than in response to ToggleSpellCheck so that the existing text
+ // will be spellchecked immediately.
+ if (java_object_.is_null()) {
+ java_object_.Reset(Java_SpellCheckerSessionBridge_create(
+ base::android::AttachCurrentThread(),
+ reinterpret_cast<intptr_t>(this)));
+ if (java_object_.is_null()) {
+ java_object_initialization_failed_ = true;
+ return;
+ }
+ }
+
+ // Save incoming requests to run at the end of the currently active request.
+ // If multiple requests arrive during one active request, only the most
+ // recent request will run (the others get overwritten).
+ if (active_request_) {
+ pending_request_.reset(new SpellingRequest(route_id, identifier, text));
+ return;
+ }
+
+ active_request_.reset(new SpellingRequest(route_id, identifier, text));
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_SpellCheckerSessionBridge_requestTextCheck(
+ env, java_object_, base::android::ConvertUTF16ToJavaString(env, text));
+}
+
+void SpellCheckerSessionBridge::ProcessSpellCheckResults(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jobj,
+ const JavaParamRef<jintArray>& offset_array,
+ const JavaParamRef<jintArray>& length_array) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ std::vector<int> offsets;
+ std::vector<int> lengths;
+
+ base::android::JavaIntArrayToIntVector(env, offset_array, &offsets);
+ base::android::JavaIntArrayToIntVector(env, length_array, &lengths);
+
+ std::vector<SpellCheckResult> results;
+ for (size_t i = 0; i < offsets.size(); i++) {
+ results.push_back(
+ SpellCheckResult(SpellCheckResult::SPELLING, offsets[i], lengths[i]));
+ }
+
+ content::RenderProcessHost* sender =
+ content::RenderProcessHost::FromID(render_process_id_);
+
+ if (sender != nullptr) {
+ sender->Send(new SpellCheckMsg_RespondTextCheck(
+ active_request_->route_id, active_request_->identifier,
+ active_request_->text, results));
+ }
+
+ active_request_ = std::move(pending_request_);
+ if (active_request_) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_SpellCheckerSessionBridge_requestTextCheck(
+ env, java_object_,
+ base::android::ConvertUTF16ToJavaString(env, active_request_->text));
+ }
+}
+
+void SpellCheckerSessionBridge::DisconnectSession() {
+ // Needs to be executed on the same thread as the RequestTextCheck and
+ // ProcessSpellCheckResults methods, which is the UI thread.
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ active_request_.reset();
+ pending_request_.reset();
+
+ if (!java_object_.is_null()) {
+ Java_SpellCheckerSessionBridge_disconnect(
+ base::android::AttachCurrentThread(), java_object_);
+ java_object_.Reset();
+ }
+}
+
+SpellCheckerSessionBridge::SpellingRequest::SpellingRequest(
+ int route_id,
+ int identifier,
+ const base::string16& text)
+ : route_id(route_id), identifier(identifier), text(text) {}
+
+SpellCheckerSessionBridge::SpellingRequest::~SpellingRequest() {}
diff --git a/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.h b/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.h
new file mode 100644
index 00000000000..4d47f37d9ee
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.h
@@ -0,0 +1,65 @@
+// 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 COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECKER_SESSION_BRIDGE_ANDROID_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECKER_SESSION_BRIDGE_ANDROID_H_
+
+#include <jni.h>
+
+#include <memory>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+
+// A class used to interface between the Java class of the same name and the
+// android message filter. This class receives text to be spellchecked
+// from the message filter, sends that text to the Java side via JNI to be
+// spellchecked, and then sends those results to the renderer.
+class SpellCheckerSessionBridge {
+ public:
+ explicit SpellCheckerSessionBridge(int render_process_id);
+ ~SpellCheckerSessionBridge();
+ static bool RegisterJNI(JNIEnv* env);
+
+ // Receives text to be checked from the message filter and sends it to Java
+ // to be spellchecked.
+ void RequestTextCheck(int route_id,
+ int identifier,
+ const base::string16& text);
+
+ // Receives information from Java side about the typos in a given string
+ // of text, processes these and sends them to the renderer.
+ void ProcessSpellCheckResults(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jobj,
+ const base::android::JavaParamRef<jintArray>& offset_array,
+ const base::android::JavaParamRef<jintArray>& length_array);
+
+ // Sets the handle to the Java SpellCheckerSessionBridge object to null,
+ // marking the Java object for garbage collection.
+ void DisconnectSession();
+
+ private:
+ struct SpellingRequest {
+ SpellingRequest(int route_id, int identifier, const base::string16& text);
+ ~SpellingRequest();
+
+ int route_id;
+ int identifier;
+ base::string16 text;
+ };
+
+ int render_process_id_;
+
+ std::unique_ptr<SpellingRequest> active_request_;
+ std::unique_ptr<SpellingRequest> pending_request_;
+
+ base::android::ScopedJavaGlobalRef<jobject> java_object_;
+ bool java_object_initialization_failed_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellCheckerSessionBridge);
+};
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_SPELLCHECKER_SESSION_BRIDGE_ANDROID_H_
diff --git a/chromium/components/spellcheck/browser/spelling_service_client.cc b/chromium/components/spellcheck/browser/spelling_service_client.cc
new file mode 100644
index 00000000000..44c51ccb695
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spelling_service_client.cc
@@ -0,0 +1,274 @@
+// 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 "components/spellcheck/browser/spelling_service_client.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+
+#include "base/json/json_reader.h"
+#include "base/json/string_escape.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/prefs/pref_service.h"
+#include "components/spellcheck/browser/pref_names.h"
+#include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "google_apis/google_api_keys.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_fetcher.h"
+#include "url/gurl.h"
+
+namespace {
+
+// The URL for requesting spell checking and sending user feedback.
+const char kSpellingServiceURL[] = "https://www.googleapis.com/rpc";
+
+// The location of spellcheck suggestions in JSON response from spelling
+// service.
+const char kMisspellingsPath[] = "result.spellingCheckResponse.misspellings";
+
+// The location of error messages in JSON response from spelling service.
+const char kErrorPath[] = "error";
+
+// Languages currently supported by SPELLCHECK.
+const char* const kValidLanguages[] = {"en", "es", "fi", "da"};
+
+} // namespace
+
+SpellingServiceClient::SpellingServiceClient() {}
+
+SpellingServiceClient::~SpellingServiceClient() {}
+
+bool SpellingServiceClient::RequestTextCheck(
+ content::BrowserContext* context,
+ ServiceType type,
+ const base::string16& text,
+ const TextCheckCompleteCallback& callback) {
+ DCHECK(type == SUGGEST || type == SPELLCHECK);
+ if (!context || !IsAvailable(context, type)) {
+ callback.Run(false, text, std::vector<SpellCheckResult>());
+ return false;
+ }
+
+ const PrefService* pref = user_prefs::UserPrefs::Get(context);
+ DCHECK(pref);
+
+ std::string dictionary;
+ pref->GetList(spellcheck::prefs::kSpellCheckDictionaries)
+ ->GetString(0, &dictionary);
+
+ std::string language_code;
+ std::string country_code;
+ spellcheck::GetISOLanguageCountryCodeFromLocale(dictionary, &language_code,
+ &country_code);
+
+ // Replace typographical apostrophes with typewriter apostrophes, so that
+ // server word breaker behaves correctly.
+ const base::char16 kApostrophe = 0x27;
+ const base::char16 kRightSingleQuotationMark = 0x2019;
+ base::string16 text_copy = text;
+ std::replace(text_copy.begin(), text_copy.end(), kRightSingleQuotationMark,
+ kApostrophe);
+
+ // Format the JSON request to be sent to the Spelling service.
+ std::string encoded_text = base::GetQuotedJSONString(text_copy);
+
+ static const char kSpellingRequest[] =
+ "{"
+ "\"method\":\"spelling.check\","
+ "\"apiVersion\":\"v%d\","
+ "\"params\":{"
+ "\"text\":%s,"
+ "\"language\":\"%s\","
+ "\"originCountry\":\"%s\","
+ "\"key\":%s"
+ "}"
+ "}";
+ std::string api_key = base::GetQuotedJSONString(google_apis::GetAPIKey());
+ std::string request = base::StringPrintf(
+ kSpellingRequest, type, encoded_text.c_str(), language_code.c_str(),
+ country_code.c_str(), api_key.c_str());
+
+ GURL url = GURL(kSpellingServiceURL);
+ net::URLFetcher* fetcher = CreateURLFetcher(url).release();
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ fetcher, data_use_measurement::DataUseUserData::SPELL_CHECKER);
+ fetcher->SetRequestContext(
+ content::BrowserContext::GetDefaultStoragePartition(context)
+ ->GetURLRequestContext());
+ fetcher->SetUploadData("application/json", request);
+ fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES);
+ spellcheck_fetchers_[fetcher] = base::MakeUnique<TextCheckCallbackData>(
+ base::WrapUnique(fetcher), callback, text);
+ fetcher->Start();
+ return true;
+}
+
+bool SpellingServiceClient::IsAvailable(content::BrowserContext* context,
+ ServiceType type) {
+ const PrefService* pref = user_prefs::UserPrefs::Get(context);
+ DCHECK(pref);
+ // If prefs don't allow spellchecking, if the context is off the record, or if
+ // multilingual spellchecking is enabled the spelling service should be
+ // unavailable.
+ if (!pref->GetBoolean(spellcheck::prefs::kEnableSpellcheck) ||
+ !pref->GetBoolean(spellcheck::prefs::kSpellCheckUseSpellingService) ||
+ context->IsOffTheRecord())
+ return false;
+
+ // If the locale for spelling has not been set, the user has not decided to
+ // use spellcheck so we don't do anything remote (suggest or spelling).
+ std::string locale;
+ pref->GetList(spellcheck::prefs::kSpellCheckDictionaries)
+ ->GetString(0, &locale);
+ if (locale.empty())
+ return false;
+
+ // Finally, if all options are available, we only enable only SUGGEST
+ // if SPELLCHECK is not available for our language because SPELLCHECK results
+ // are a superset of SUGGEST results.
+ for (const char* language : kValidLanguages) {
+ if (!locale.compare(0, 2, language))
+ return type == SPELLCHECK;
+ }
+
+ // Only SUGGEST is allowed.
+ return type == SUGGEST;
+}
+
+bool SpellingServiceClient::ParseResponse(
+ const std::string& data,
+ std::vector<SpellCheckResult>* results) {
+ // When this JSON-RPC call finishes successfully, the Spelling service returns
+ // an JSON object listed below.
+ // * result - an envelope object representing the result from the APIARY
+ // server, which is the JSON-API front-end for the Spelling service. This
+ // object consists of the following variable:
+ // - spellingCheckResponse (SpellingCheckResponse).
+ // * SpellingCheckResponse - an object representing the result from the
+ // Spelling service. This object consists of the following variable:
+ // - misspellings (optional array of Misspelling)
+ // * Misspelling - an object representing a misspelling region and its
+ // suggestions. This object consists of the following variables:
+ // - charStart (number) - the beginning of the misspelled region;
+ // - charLength (number) - the length of the misspelled region;
+ // - suggestions (array of string) - the suggestions for the misspelling
+ // text, and;
+ // - canAutoCorrect (optional boolean) - whether we can use the first
+ // suggestion for auto-correction.
+ // For example, the Spelling service returns the following JSON when we send a
+ // spelling request for "duck goes quisk" as of 16 August, 2011.
+ // {
+ // "result": {
+ // "spellingCheckResponse": {
+ // "misspellings": [{
+ // "charStart": 10,
+ // "charLength": 5,
+ // "suggestions": [{ "suggestion": "quack" }],
+ // "canAutoCorrect": false
+ // }]
+ // }
+ // }
+ // }
+ // If the service is not available, the Spelling service returns JSON with an
+ // error.
+ // {
+ // "error": {
+ // "code": 400,
+ // "message": "Bad Request",
+ // "data": [...]
+ // }
+ // }
+ std::unique_ptr<base::DictionaryValue> value(
+ static_cast<base::DictionaryValue*>(
+ base::JSONReader::Read(data, base::JSON_ALLOW_TRAILING_COMMAS)
+ .release()));
+ if (!value.get() || !value->IsType(base::Value::TYPE_DICTIONARY))
+ return false;
+
+ // Check for errors from spelling service.
+ base::DictionaryValue* error = NULL;
+ if (value->GetDictionary(kErrorPath, &error))
+ return false;
+
+ // Retrieve the array of Misspelling objects. When the input text does not
+ // have misspelled words, it returns an empty JSON. (In this case, its HTTP
+ // status is 200.) We just return true for this case.
+ base::ListValue* misspellings = NULL;
+ if (!value->GetList(kMisspellingsPath, &misspellings))
+ return true;
+
+ for (size_t i = 0; i < misspellings->GetSize(); ++i) {
+ // Retrieve the i-th misspelling region and put it to the given vector. When
+ // the Spelling service sends two or more suggestions, we read only the
+ // first one because SpellCheckResult can store only one suggestion.
+ base::DictionaryValue* misspelling = NULL;
+ if (!misspellings->GetDictionary(i, &misspelling))
+ return false;
+
+ int start = 0;
+ int length = 0;
+ base::ListValue* suggestions = NULL;
+ if (!misspelling->GetInteger("charStart", &start) ||
+ !misspelling->GetInteger("charLength", &length) ||
+ !misspelling->GetList("suggestions", &suggestions)) {
+ return false;
+ }
+
+ base::DictionaryValue* suggestion = NULL;
+ base::string16 replacement;
+ if (!suggestions->GetDictionary(0, &suggestion) ||
+ !suggestion->GetString("suggestion", &replacement)) {
+ return false;
+ }
+ SpellCheckResult result(SpellCheckResult::SPELLING, start, length,
+ replacement);
+ results->push_back(result);
+ }
+ return true;
+}
+
+SpellingServiceClient::TextCheckCallbackData::TextCheckCallbackData(
+ std::unique_ptr<net::URLFetcher> fetcher,
+ TextCheckCompleteCallback callback,
+ base::string16 text)
+ : fetcher(std::move(fetcher)), callback(callback), text(text) {}
+
+SpellingServiceClient::TextCheckCallbackData::~TextCheckCallbackData() {}
+
+void SpellingServiceClient::OnURLFetchComplete(const net::URLFetcher* source) {
+ DCHECK(base::ContainsKey(spellcheck_fetchers_, source));
+ std::unique_ptr<TextCheckCallbackData> callback_data =
+ std::move(spellcheck_fetchers_[source]);
+ spellcheck_fetchers_.erase(source);
+
+ bool success = false;
+ std::vector<SpellCheckResult> results;
+ if (source->GetResponseCode() / 100 == 2) {
+ std::string data;
+ source->GetResponseAsString(&data);
+ success = ParseResponse(data, &results);
+ }
+
+ // The callback may release the last (transitive) dependency on |this|. It
+ // MUST be the last function called.
+ callback_data->callback.Run(success, callback_data->text, results);
+}
+
+std::unique_ptr<net::URLFetcher> SpellingServiceClient::CreateURLFetcher(
+ const GURL& url) {
+ return net::URLFetcher::Create(url, net::URLFetcher::POST, this);
+}
diff --git a/chromium/components/spellcheck/browser/spelling_service_client.h b/chromium/components/spellcheck/browser/spelling_service_client.h
new file mode 100644
index 00000000000..344e4558167
--- /dev/null
+++ b/chromium/components/spellcheck/browser/spelling_service_client.h
@@ -0,0 +1,129 @@
+// 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 COMPONENTS_SPELLCHECK_BROWSER_SPELLING_SERVICE_CLIENT_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_SPELLING_SERVICE_CLIENT_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "net/url_request/url_fetcher_delegate.h"
+
+class GURL;
+class TextCheckClientDelegate;
+struct SpellCheckResult;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace net {
+class URLFetcher;
+} // namespace net
+
+// A class that encapsulates a JSON-RPC call to the Spelling service to check
+// text there. This class creates a JSON-RPC request, sends the request to the
+// service with URLFetcher, parses a response from the service, and calls a
+// provided callback method. When a user deletes this object before it finishes
+// a JSON-RPC call, this class cancels the JSON-RPC call without calling the
+// callback method. A simple usage is creating a SpellingServiceClient and
+// calling its RequestTextCheck method as listed in the following snippet.
+//
+// class MyClient {
+// public:
+// MyClient();
+// virtual ~MyClient();
+//
+// void OnTextCheckComplete(
+// int tag,
+// bool success,
+// const std::vector<SpellCheckResult>& results) {
+// ...
+// }
+//
+// void MyTextCheck(BrowserContext* context, const base::string16& text) {
+// client_.reset(new SpellingServiceClient);
+// client_->RequestTextCheck(context, 0, text,
+// base::Bind(&MyClient::OnTextCheckComplete,
+// base::Unretained(this));
+// }
+// private:
+// std::unique_ptr<SpellingServiceClient> client_;
+// };
+//
+class SpellingServiceClient : public net::URLFetcherDelegate {
+ public:
+ // Service types provided by the Spelling service. The Spelling service
+ // consists of a couple of backends:
+ // * SUGGEST: Retrieving suggestions for a word (used by Google Search), and;
+ // * SPELLCHECK: Spellchecking text (used by Google Docs).
+ // This type is used for choosing a backend when sending a JSON-RPC request to
+ // the service.
+ enum ServiceType {
+ SUGGEST = 1,
+ SPELLCHECK = 2,
+ };
+ typedef base::Callback<void(
+ bool /* success */,
+ const base::string16& /* text */,
+ const std::vector<SpellCheckResult>& /* results */)>
+ TextCheckCompleteCallback;
+
+ SpellingServiceClient();
+ ~SpellingServiceClient() override;
+
+ // Sends a text-check request to the Spelling service. When we send a request
+ // to the Spelling service successfully, this function returns true. (This
+ // does not mean the service finishes checking text successfully.) We will
+ // call |callback| when we receive a text-check response from the service.
+ bool RequestTextCheck(content::BrowserContext* context,
+ ServiceType type,
+ const base::string16& text,
+ const TextCheckCompleteCallback& callback);
+
+ // Returns whether the specified service is available for the given context.
+ static bool IsAvailable(content::BrowserContext* context, ServiceType type);
+
+ protected:
+ // Parses a JSON-RPC response from the Spelling service.
+ bool ParseResponse(const std::string& data,
+ std::vector<SpellCheckResult>* results);
+
+ private:
+ struct TextCheckCallbackData {
+ TextCheckCallbackData(std::unique_ptr<net::URLFetcher> fetcher,
+ TextCheckCompleteCallback callback,
+ base::string16 text);
+ ~TextCheckCallbackData();
+
+ // The fetcher used.
+ std::unique_ptr<net::URLFetcher> fetcher;
+
+ // The callback function to be called when we receive a response from the
+ // Spelling service and parse it.
+ TextCheckCompleteCallback callback;
+
+ // The text checked by the Spelling service.
+ base::string16 text;
+ };
+
+ // net::URLFetcherDelegate implementation.
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+ // Creates a URLFetcher object used for sending a JSON-RPC request. This
+ // function is overridden by unit tests to prevent them from actually sending
+ // requests to the Spelling service.
+ virtual std::unique_ptr<net::URLFetcher> CreateURLFetcher(const GURL& url);
+
+ // The URLFetcher object used for sending a JSON-RPC request.
+ std::map<const net::URLFetcher*, std::unique_ptr<TextCheckCallbackData>>
+ spellcheck_fetchers_;
+};
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_SPELLING_SERVICE_CLIENT_H_
diff --git a/chromium/components/spellcheck/browser/word_trimmer.cc b/chromium/components/spellcheck/browser/word_trimmer.cc
new file mode 100644
index 00000000000..6e4da3328e8
--- /dev/null
+++ b/chromium/components/spellcheck/browser/word_trimmer.cc
@@ -0,0 +1,50 @@
+// 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 "components/spellcheck/browser/word_trimmer.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/i18n/break_iterator.h"
+
+base::string16 TrimWords(size_t* start,
+ size_t end,
+ const base::string16& text,
+ size_t keep) {
+ if (*start > text.length() || *start > end)
+ return text;
+ base::i18n::BreakIterator iter(text, base::i18n::BreakIterator::BREAK_WORD);
+ if (!iter.Init())
+ return text;
+ // A circular buffer of the last |keep + 1| words seen before position |start|
+ // in |text|.
+ std::vector<size_t> word_offset(keep + 1, 0);
+ size_t first = std::string::npos;
+ size_t last = std::string::npos;
+ while (iter.Advance()) {
+ if (iter.IsWord()) {
+ word_offset[keep] = iter.prev();
+ if ((*start >= iter.prev() && *start < iter.pos()) ||
+ (end > iter.prev() && end <= iter.pos())) {
+ if (first == std::string::npos)
+ first = word_offset[0];
+ last = iter.pos();
+ }
+ if (first == std::string::npos) {
+ std::rotate(word_offset.begin(),
+ word_offset.begin() + 1,
+ word_offset.end());
+ }
+ if (iter.prev() > end && keep) {
+ last = iter.pos();
+ keep--;
+ }
+ }
+ }
+ if (first == std::string::npos)
+ return text;
+ *start -= first;
+ return text.substr(first, last - first);
+}
diff --git a/chromium/components/spellcheck/browser/word_trimmer.h b/chromium/components/spellcheck/browser/word_trimmer.h
new file mode 100644
index 00000000000..686034d2ae2
--- /dev/null
+++ b/chromium/components/spellcheck/browser/word_trimmer.h
@@ -0,0 +1,34 @@
+// 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 COMPONENTS_SPELLCHECK_BROWSER_WORD_TRIMMER_H_
+#define COMPONENTS_SPELLCHECK_BROWSER_WORD_TRIMMER_H_
+
+#include <stddef.h>
+
+#include "base/strings/string16.h"
+
+// Trims |text| to contain only the range from |start| to |end| and |keep| words
+// on either side of the range. The |start| and |end| parameters are character
+// indexes into |text|. The |keep| parameter is the number of words to keep on
+// either side of the |start|-|end| range. The function updates |start| in
+// accordance with the trimming.
+//
+// Example:
+//
+// size_t start = 14;
+// size_t end = 23;
+// base::string16 text =
+// base::ASCIIToUTF16("one two three four five six seven eight");
+// int keep = 2;
+// base::string16 trimmed = TrimWords(&start, end, text, keep);
+// DCHECK(trimmed == base::ASCIIToUTF16("two three four five six seven"));
+// DCHECK(start == 10);
+//
+base::string16 TrimWords(size_t* start,
+ size_t end,
+ const base::string16& text,
+ size_t keep);
+
+#endif // COMPONENTS_SPELLCHECK_BROWSER_WORD_TRIMMER_H_
diff --git a/chromium/components/spellcheck/browser/word_trimmer_unittest.cc b/chromium/components/spellcheck/browser/word_trimmer_unittest.cc
new file mode 100644
index 00000000000..3930dd2510e
--- /dev/null
+++ b/chromium/components/spellcheck/browser/word_trimmer_unittest.cc
@@ -0,0 +1,67 @@
+// 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 "components/spellcheck/browser/word_trimmer.h"
+
+#include <stddef.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ASCIIToUTF16;
+
+TEST(WordTrimmerTest, TrimWordsEmptyText) {
+ size_t start = 0;
+ size_t end = 0;
+ EXPECT_EQ(base::string16(), TrimWords(&start, end, base::string16(), 0));
+ EXPECT_EQ(0UL, start);
+}
+
+TEST(WordTrimmerTest, TrimWordsStart) {
+ size_t start = 0;
+ size_t end = 3;
+ EXPECT_EQ(ASCIIToUTF16("one two three"),
+ TrimWords(&start, end, ASCIIToUTF16("one two three four"), 2));
+ EXPECT_EQ(0UL, start);
+}
+
+TEST(WordTrimmerTest, TrimWordsEnd) {
+ size_t start = 14;
+ size_t end = 18;
+ EXPECT_EQ(ASCIIToUTF16("two three four"),
+ TrimWords(&start, end, ASCIIToUTF16("one two three four"), 2));
+ EXPECT_EQ(10UL, start);
+}
+
+TEST(WordTrimmerTest, TrimWordsMiddle) {
+ size_t start = 14;
+ size_t end = 23;
+ EXPECT_EQ(ASCIIToUTF16("two three four five six seven"), TrimWords(
+ &start, end, ASCIIToUTF16("one two three four five six seven eight"), 2));
+ EXPECT_EQ(10UL, start);
+}
+
+TEST(WordTrimmerTest, TrimWordsEmptyKeep) {
+ size_t start = 18;
+ size_t end = 18;
+ EXPECT_EQ(ASCIIToUTF16("two three four five six"), TrimWords(
+ &start, end, ASCIIToUTF16("one two three four five six seven eight"), 2));
+ EXPECT_EQ(14UL, start);
+}
+
+TEST(WordTrimmerTest, TrimWordsOutOfBounds) {
+ size_t start = 4;
+ size_t end = 5;
+ EXPECT_EQ(ASCIIToUTF16("one"), TrimWords(
+ &start, end, ASCIIToUTF16("one"), 2));
+ EXPECT_EQ(4UL, start);
+}
+
+TEST(WordTrimmerTest, TrimWordsInvalid) {
+ size_t start = 23;
+ size_t end = 14;
+ EXPECT_EQ(ASCIIToUTF16("one two three four five six seven eight"), TrimWords(
+ &start, end, ASCIIToUTF16("one two three four five six seven eight"), 2));
+ EXPECT_EQ(23UL, start);
+}
diff --git a/chromium/components/spellcheck/common/BUILD.gn b/chromium/components/spellcheck/common/BUILD.gn
new file mode 100644
index 00000000000..465a327f214
--- /dev/null
+++ b/chromium/components/spellcheck/common/BUILD.gn
@@ -0,0 +1,26 @@
+# 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.
+
+source_set("common") {
+ sources = [
+ "spellcheck_bdict_language.h",
+ "spellcheck_common.cc",
+ "spellcheck_common.h",
+ "spellcheck_features.cc",
+ "spellcheck_features.h",
+ "spellcheck_marker.h",
+ "spellcheck_message_generator.cc",
+ "spellcheck_message_generator.h",
+ "spellcheck_messages.h",
+ "spellcheck_result.h",
+ "spellcheck_switches.cc",
+ "spellcheck_switches.h",
+ ]
+
+ deps = [
+ "//base:i18n",
+ "//ipc",
+ "//third_party/icu",
+ ]
+}
diff --git a/chromium/components/spellcheck/common/DEPS b/chromium/components/spellcheck/common/DEPS
new file mode 100644
index 00000000000..1c40d981eb6
--- /dev/null
+++ b/chromium/components/spellcheck/common/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ipc",
+]
diff --git a/chromium/components/spellcheck/common/OWNERS b/chromium/components/spellcheck/common/OWNERS
new file mode 100644
index 00000000000..42444bcd16d
--- /dev/null
+++ b/chromium/components/spellcheck/common/OWNERS
@@ -0,0 +1,2 @@
+per-file *_messages*.h=set noparent
+per-file *_messages*.h=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/spellcheck/common/spellcheck_bdict_language.h b/chromium/components/spellcheck/common/spellcheck_bdict_language.h
new file mode 100644
index 00000000000..95022944076
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_bdict_language.h
@@ -0,0 +1,17 @@
+// 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 COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_BDICT_LANGUAGE_H_
+#define COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_BDICT_LANGUAGE_H_
+
+#include <string>
+
+#include "ipc/ipc_platform_file.h"
+
+struct SpellCheckBDictLanguage {
+ IPC::PlatformFileForTransit file;
+ std::string language;
+};
+
+#endif // COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_BDICT_LANGUAGE_H_
diff --git a/chromium/components/spellcheck/common/spellcheck_common.cc b/chromium/components/spellcheck/common/spellcheck_common.cc
new file mode 100644
index 00000000000..c3b817e4086
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_common.cc
@@ -0,0 +1,190 @@
+// 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 "components/spellcheck/common/spellcheck_common.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_util.h"
+#include "third_party/icu/source/common/unicode/uloc.h"
+#include "third_party/icu/source/common/unicode/urename.h"
+#include "third_party/icu/source/common/unicode/utypes.h"
+
+namespace spellcheck {
+
+struct LanguageRegion {
+ const char* language; // The language.
+ const char* language_region; // language & region, used by dictionaries.
+};
+
+struct LanguageVersion {
+ const char* language; // The language input.
+ const char* version; // The corresponding version.
+};
+
+static const LanguageRegion g_supported_spellchecker_languages[] = {
+ // Several languages are not to be included in the spellchecker list:
+ // th-TH, vi-VI.
+ {"af", "af-ZA"},
+ {"bg", "bg-BG"},
+ {"ca", "ca-ES"},
+ {"cs", "cs-CZ"},
+ {"da", "da-DK"},
+ {"de", "de-DE"},
+ {"el", "el-GR"},
+ {"en-AU", "en-GB"},
+ {"en-CA", "en-CA"},
+ {"en-GB", "en-GB"},
+ {"en-US", "en-US"},
+ {"es", "es-ES"},
+ {"es-419", "es-ES"},
+ {"es-AR", "es-ES"},
+ {"es-ES", "es-ES"},
+ {"es-MX", "es-ES"},
+ {"es-US", "es-ES"},
+ {"et", "et-EE"},
+ {"fa", "fa-IR"},
+ {"fo", "fo-FO"},
+ {"fr", "fr-FR"},
+ {"he", "he-IL"},
+ {"hi", "hi-IN"},
+ {"hr", "hr-HR"},
+ {"hu", "hu-HU"},
+ {"id", "id-ID"},
+ {"it", "it-IT"},
+ {"ko", "ko"},
+ {"lt", "lt-LT"},
+ {"lv", "lv-LV"},
+ {"nb", "nb-NO"},
+ {"nl", "nl-NL"},
+ {"pl", "pl-PL"},
+ {"pt-BR", "pt-BR"},
+ {"pt-PT", "pt-PT"},
+ {"ro", "ro-RO"},
+ {"ru", "ru-RU"},
+ {"sh", "sh"},
+ {"sk", "sk-SK"},
+ {"sl", "sl-SI"},
+ {"sq", "sq"},
+ {"sr", "sr"},
+ {"sv", "sv-SE"},
+ {"ta", "ta-IN"},
+ {"tg", "tg-TG"},
+ {"tr", "tr-TR"},
+ {"uk", "uk-UA"},
+ {"vi", "vi-VN"},
+};
+
+bool IsValidRegion(const std::string& region) {
+ for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages); ++i) {
+ if (g_supported_spellchecker_languages[i].language_region == region)
+ return true;
+ }
+ return false;
+}
+
+// This function returns the language-region version of language name.
+// e.g. returns hi-IN for hi.
+std::string GetSpellCheckLanguageRegion(const std::string& input_language) {
+ for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages); ++i) {
+ if (g_supported_spellchecker_languages[i].language == input_language) {
+ return std::string(g_supported_spellchecker_languages[i].language_region);
+ }
+ }
+
+ return input_language;
+}
+
+base::FilePath GetVersionedFileName(const std::string& input_language,
+ const base::FilePath& dict_dir) {
+ // The default dictionary version is 3-0. This version indicates that the bdic
+ // file contains a checksum.
+ static const char kDefaultVersionString[] = "-3-0";
+
+ // Add non-default version strings here. Use the same version for all the
+ // dictionaries that you add at the same time. Increment the major version
+ // number if you're updating either dic or aff files. Increment the minor
+ // version number if you're updating only dic_delta files.
+ static LanguageVersion special_version_string[] = {
+ {"tr-TR", "-4-0"}, // Jan 9, 2013: Add "FLAG num" to aff to avoid heapcheck
+ // crash.
+ {"tg-TG", "-5-0"}, // Mar 4, 2014: Add Tajik dictionary.
+
+ // April 2016: Local fixes
+ {"en-CA", "-7-1"},
+ {"en-GB", "-7-1"},
+ {"en-US", "-7-1"},
+
+ // March 2016: Initial check-in of Persian
+ {"fa-IR", "-7-0"},
+ };
+
+ // Generate the bdict file name using default version string or special
+ // version string, depending on the language.
+ std::string language = GetSpellCheckLanguageRegion(input_language);
+ std::string versioned_bdict_file_name(language + kDefaultVersionString +
+ ".bdic");
+ for (size_t i = 0; i < arraysize(special_version_string); ++i) {
+ if (language == special_version_string[i].language) {
+ versioned_bdict_file_name =
+ language + special_version_string[i].version + ".bdic";
+ break;
+ }
+ }
+
+ return dict_dir.AppendASCII(versioned_bdict_file_name);
+}
+
+std::string GetCorrespondingSpellCheckLanguage(const std::string& language) {
+ std::string best_match;
+ // Look for exact match in the Spell Check language list.
+ for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages); ++i) {
+ // First look for exact match in the language region of the list.
+ std::string spellcheck_language(
+ g_supported_spellchecker_languages[i].language);
+ if (spellcheck_language == language)
+ return language;
+
+ // Next, look for exact match in the language_region part of the list.
+ std::string spellcheck_language_region(
+ g_supported_spellchecker_languages[i].language_region);
+ if (spellcheck_language_region == language) {
+ if (best_match.empty())
+ best_match = g_supported_spellchecker_languages[i].language;
+ }
+ }
+
+ // No match found - return best match, if any.
+ return best_match;
+}
+
+void SpellCheckLanguages(std::vector<std::string>* languages) {
+ for (size_t i = 0; i < arraysize(g_supported_spellchecker_languages); ++i) {
+ languages->push_back(g_supported_spellchecker_languages[i].language);
+ }
+}
+
+void GetISOLanguageCountryCodeFromLocale(const std::string& locale,
+ std::string* language_code,
+ std::string* country_code) {
+ DCHECK(language_code);
+ DCHECK(country_code);
+ char language[ULOC_LANG_CAPACITY] = ULOC_ENGLISH;
+ const char* country = "USA";
+ if (!locale.empty()) {
+ UErrorCode error = U_ZERO_ERROR;
+ char id[ULOC_LANG_CAPACITY + ULOC_SCRIPT_CAPACITY + ULOC_COUNTRY_CAPACITY];
+ uloc_addLikelySubtags(locale.c_str(), id, arraysize(id), &error);
+ error = U_ZERO_ERROR;
+ uloc_getLanguage(id, language, arraysize(language), &error);
+ country = uloc_getISO3Country(id);
+ }
+ *language_code = std::string(language);
+ *country_code = std::string(country);
+}
+
+} // namespace spellcheck
diff --git a/chromium/components/spellcheck/common/spellcheck_common.h b/chromium/components/spellcheck/common/spellcheck_common.h
new file mode 100644
index 00000000000..5b7e93f0cdc
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_common.h
@@ -0,0 +1,67 @@
+// 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 COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_COMMON_H_
+#define COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_COMMON_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+namespace base {
+class FilePath;
+}
+
+namespace spellcheck {
+
+// The number of hours that a session of feedback for spelling service lasts.
+// After this number of hours passes, all feedback.
+static const int kSessionHours = 6;
+
+// The number of context words to keep on either side of a misspelling for
+// spelling service feedback.
+static const int kContextWordCount = 2;
+
+// The number of seconds between sending feedback to spelling service.
+static const int kFeedbackIntervalSeconds = 1800; // 30 minutes
+
+// Max number of dictionary suggestions.
+static const int kMaxSuggestions = 5;
+
+// Maximum number of words in the custom spellcheck dictionary that can be
+// synced.
+static const size_t MAX_SYNCABLE_DICTIONARY_WORDS = 1300;
+
+// Maximum number of bytes in a word that can be added to the custom spellcheck
+// dictionary.
+static const size_t MAX_CUSTOM_DICTIONARY_WORD_BYTES = 99;
+
+base::FilePath GetVersionedFileName(const std::string& input_language,
+ const base::FilePath& dict_dir);
+
+// Returns the spellcheck language that should be used for |language|. For
+// example, converts "hu-HU" into "hu", because we have only one variant of
+// Hungarian. Converts "en-US" into "en-US", because we have several variants of
+// English dictionaries.
+//
+// Returns an empty string if no spellcheck language found. For example, there's
+// no single dictionary for English, so this function returns an empty string
+// for "en".
+std::string GetCorrespondingSpellCheckLanguage(const std::string& language);
+
+// Get SpellChecker supported languages.
+void SpellCheckLanguages(std::vector<std::string>* languages);
+
+// Gets the ISO codes for the language and country of this |locale|. The
+// |locale| is an ISO locale ID that may not include a country ID, e.g., "fr" or
+// "de". This method converts the UI locale to a full locale ID and converts the
+// full locale ID to an ISO language code and an ISO3 country code.
+void GetISOLanguageCountryCodeFromLocale(const std::string& locale,
+ std::string* language_code,
+ std::string* country_code);
+
+} // namespace spellcheck
+
+#endif // COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_COMMON_H_
diff --git a/chromium/components/spellcheck/common/spellcheck_features.cc b/chromium/components/spellcheck/common/spellcheck_features.cc
new file mode 100644
index 00000000000..33b2271f243
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_features.cc
@@ -0,0 +1,37 @@
+// 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 "components/spellcheck/common/spellcheck_features.h"
+
+#include "base/sys_info.h"
+
+namespace spellcheck {
+
+#if defined(ENABLE_SPELLCHECK) && defined(OS_ANDROID)
+
+// Enables/disables Android spellchecker.
+const base::Feature kAndroidSpellChecker{
+ "AndroidSpellChecker", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables/disables Android spellchecker on non low-end Android devices.
+const base::Feature kAndroidSpellCheckerNonLowEnd{
+ "AndroidSpellCheckerNonLowEnd", base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsAndroidSpellCheckFeatureEnabled() {
+ if (base::FeatureList::IsEnabled(
+ spellcheck::kAndroidSpellCheckerNonLowEnd)) {
+ return !base::SysInfo::IsLowEndDevice();
+ }
+
+ if (base::FeatureList::IsEnabled(
+ spellcheck::kAndroidSpellChecker)) {
+ return true;
+ }
+
+ return false;
+}
+
+#endif // defined(ENABLE_SPELLCHECK) && defined(OS_ANDROID)
+
+} // namespace spellcheck
diff --git a/chromium/components/spellcheck/common/spellcheck_features.h b/chromium/components/spellcheck/common/spellcheck_features.h
new file mode 100644
index 00000000000..ba0e2f2f8b4
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_features.h
@@ -0,0 +1,21 @@
+// 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 COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_FEATURES_H_
+#define COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace spellcheck {
+
+#if defined(ENABLE_SPELLCHECK) && defined(OS_ANDROID)
+extern const base::Feature kAndroidSpellChecker;
+extern const base::Feature kAndroidSpellCheckerNonLowEnd;
+
+bool IsAndroidSpellCheckFeatureEnabled();
+#endif // defined(ENABLE_SPELLCHECK) && defined(OS_ANDROID)
+
+} // namespace spellcheck
+
+#endif // COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_FEATURES_H_
diff --git a/chromium/components/spellcheck/common/spellcheck_marker.h b/chromium/components/spellcheck/common/spellcheck_marker.h
new file mode 100644
index 00000000000..c30803ee5b8
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_marker.h
@@ -0,0 +1,39 @@
+// 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 COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_MARKER_H_
+#define COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_MARKER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+class SpellCheckMarker {
+ public:
+ // A predicate to test spellcheck marker validity.
+ class IsValidPredicate {
+ public:
+ typedef SpellCheckMarker argument_type;
+ explicit IsValidPredicate(size_t text_length) : text_length_(text_length) {}
+ bool operator()(const SpellCheckMarker& marker) const {
+ return marker.offset < text_length_;
+ }
+
+ private:
+ size_t text_length_;
+ };
+
+ // IPC requires a default constructor.
+ SpellCheckMarker() : hash(0xFFFFFFFF), offset(UINT32_MAX) {}
+
+ SpellCheckMarker(uint32_t hash, uint32_t offset)
+ : hash(hash), offset(offset) {}
+
+ uint32_t hash;
+ // Note: we use uint32_t instead of size_t because this struct is sent over
+ // IPC which could span 32 & 64 bit processes. This is fine since the offset
+ // shouldn't exceed UINT32_MAX even on 64 bit builds.
+ uint32_t offset;
+};
+
+#endif // COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_MARKER_H_
diff --git a/chromium/components/spellcheck/common/spellcheck_message_generator.cc b/chromium/components/spellcheck/common/spellcheck_message_generator.cc
new file mode 100644
index 00000000000..b11fe093beb
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_message_generator.cc
@@ -0,0 +1,39 @@
+// 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.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "components/spellcheck/common/spellcheck_message_generator.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "components/spellcheck/common/spellcheck_message_generator.h"
+
+// Generate destructors.
+#include "ipc/struct_destructor_macros.h"
+#include "components/spellcheck/common/spellcheck_message_generator.h"
+
+// Generate param traits size methods.
+#include "ipc/param_traits_size_macros.h"
+namespace IPC {
+#include "components/spellcheck/common/spellcheck_message_generator.h"
+} // namespace IPC
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "components/spellcheck/common/spellcheck_message_generator.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "components/spellcheck/common/spellcheck_message_generator.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "components/spellcheck/common/spellcheck_message_generator.h"
+} // namespace IPC
diff --git a/chromium/components/spellcheck/common/spellcheck_message_generator.h b/chromium/components/spellcheck/common/spellcheck_message_generator.h
new file mode 100644
index 00000000000..0876034c524
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_message_generator.h
@@ -0,0 +1,9 @@
+// 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.
+
+// Multiply-included file, hence no include guard.
+
+#if defined(ENABLE_SPELLCHECK)
+#include "components/spellcheck/common/spellcheck_messages.h"
+#endif
diff --git a/chromium/components/spellcheck/common/spellcheck_messages.h b/chromium/components/spellcheck/common/spellcheck_messages.h
new file mode 100644
index 00000000000..49ef8020c1f
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_messages.h
@@ -0,0 +1,146 @@
+// 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.
+
+// IPC messages for spellcheck.
+// Multiply-included message file, hence no include guard.
+
+#include <stdint.h>
+
+#include "components/spellcheck/common/spellcheck_bdict_language.h"
+#include "components/spellcheck/common/spellcheck_marker.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_platform_file.h"
+
+#if !defined(ENABLE_SPELLCHECK)
+#error "Spellcheck should be enabled"
+#endif
+
+#define IPC_MESSAGE_START SpellCheckMsgStart
+
+IPC_ENUM_TRAITS(SpellCheckResult::Decoration)
+
+IPC_STRUCT_TRAITS_BEGIN(SpellCheckResult)
+ IPC_STRUCT_TRAITS_MEMBER(decoration)
+ IPC_STRUCT_TRAITS_MEMBER(location)
+ IPC_STRUCT_TRAITS_MEMBER(length)
+ IPC_STRUCT_TRAITS_MEMBER(replacement)
+ IPC_STRUCT_TRAITS_MEMBER(hash)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(SpellCheckMarker)
+ IPC_STRUCT_TRAITS_MEMBER(hash)
+ IPC_STRUCT_TRAITS_MEMBER(offset)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(SpellCheckBDictLanguage)
+ IPC_STRUCT_TRAITS_MEMBER(file)
+ IPC_STRUCT_TRAITS_MEMBER(language)
+IPC_STRUCT_TRAITS_END()
+
+// Messages sent from the browser to the renderer.
+
+IPC_MESSAGE_CONTROL1(SpellCheckMsg_EnableSpellCheck, bool)
+
+// Passes some initialization params from the browser to the renderer's
+// spellchecker. This can be called directly after startup or in (async)
+// response to a RequestDictionary ViewHost message.
+IPC_MESSAGE_CONTROL2(SpellCheckMsg_Init,
+ std::vector<SpellCheckBDictLanguage> /* bdict_languages */,
+ std::set<std::string> /* custom_dict_words */)
+
+// Words have been added and removed in the custom dictionary; update the local
+// custom word list.
+IPC_MESSAGE_CONTROL2(SpellCheckMsg_CustomDictionaryChanged,
+ std::set<std::string> /* words_added */,
+ std::set<std::string> /* words_removed */)
+
+// Request a list of all document markers in the renderer for spelling service
+// feedback.
+IPC_MESSAGE_CONTROL0(SpellCheckMsg_RequestDocumentMarkers)
+
+// Send a list of document markers in the renderer to the spelling service
+// feedback sender.
+IPC_MESSAGE_CONTROL1(SpellCheckHostMsg_RespondDocumentMarkers,
+ std::vector<uint32_t> /* document marker identifiers */)
+
+#if !defined(USE_BROWSER_SPELLCHECKER)
+// Sends text-check results from the Spelling service when the service finishes
+// checking text received by a SpellCheckHostMsg_CallSpellingService message.
+// If the service is not available, the 4th parameter should be false and the
+// 5th parameter should contain the requested sentence.
+IPC_MESSAGE_ROUTED4(SpellCheckMsg_RespondSpellingService,
+ int /* request identifier given by WebKit */,
+ bool /* succeeded calling service */,
+ base::string16 /* sentence */,
+ std::vector<SpellCheckResult>)
+#endif
+
+#if defined(USE_BROWSER_SPELLCHECKER)
+// This message tells the renderer to advance to the next misspelling. It is
+// sent when the user clicks the "Find Next" button on the spelling panel.
+IPC_MESSAGE_ROUTED0(SpellCheckMsg_AdvanceToNextMisspelling)
+
+// Sends when NSSpellChecker finishes checking text received by a preceding
+// SpellCheckHostMsg_RequestTextCheck message.
+IPC_MESSAGE_ROUTED3(SpellCheckMsg_RespondTextCheck,
+ int /* request identifier given by WebKit */,
+ base::string16 /* sentence */,
+ std::vector<SpellCheckResult>)
+
+IPC_MESSAGE_ROUTED1(SpellCheckMsg_ToggleSpellPanel, bool)
+#endif
+
+// Messages sent from the renderer to the browser.
+
+// The renderer has tried to spell check a word, but couldn't because no
+// dictionary was available to load. Request that the browser find an
+// appropriate dictionary and return it.
+IPC_MESSAGE_CONTROL0(SpellCheckHostMsg_RequestDictionary)
+
+// Tracks spell checking occurrence to collect histogram.
+IPC_MESSAGE_ROUTED2(SpellCheckHostMsg_NotifyChecked,
+ base::string16 /* word */,
+ bool /* true if checked word is misspelled */)
+
+#if !defined(USE_BROWSER_SPELLCHECKER)
+// Asks the Spelling service to check text. When the service finishes checking
+// the input text, it sends a SpellingCheckMsg_RespondSpellingService with
+// text-check results.
+IPC_MESSAGE_CONTROL4(SpellCheckHostMsg_CallSpellingService,
+ int /* route_id for response */,
+ int /* request identifier given by WebKit */,
+ base::string16 /* sentence */,
+ std::vector<SpellCheckMarker> /* markers */)
+#endif
+
+#if defined(USE_BROWSER_SPELLCHECKER)
+// Tells the browser to display or not display the SpellingPanel
+IPC_MESSAGE_ROUTED1(SpellCheckHostMsg_ShowSpellingPanel,
+ bool /* if true, then show it, otherwise hide it*/)
+
+// Tells the browser to update the spelling panel with the given word.
+IPC_MESSAGE_ROUTED1(SpellCheckHostMsg_UpdateSpellingPanelWithMisspelledWord,
+ base::string16 /* the word to update the panel with */)
+
+// TODO(groby): This needs to originate from SpellcheckProvider.
+IPC_SYNC_MESSAGE_CONTROL2_1(SpellCheckHostMsg_CheckSpelling,
+ base::string16 /* word */,
+ int /* route_id */,
+ bool /* correct */)
+
+IPC_SYNC_MESSAGE_CONTROL1_1(SpellCheckHostMsg_FillSuggestionList,
+ base::string16 /* word */,
+ std::vector<base::string16> /* suggestions */)
+
+IPC_MESSAGE_CONTROL4(SpellCheckHostMsg_RequestTextCheck,
+ int /* route_id for response */,
+ int /* request identifier given by WebKit */,
+ base::string16 /* sentence */,
+ std::vector<SpellCheckMarker> /* markers */)
+
+IPC_MESSAGE_ROUTED2(SpellCheckHostMsg_ToggleSpellCheck,
+ bool /* enabled */,
+ bool /* checked */)
+#endif // USE_BROWSER_SPELLCHECKER
diff --git a/chromium/components/spellcheck/common/spellcheck_result.h b/chromium/components/spellcheck/common/spellcheck_result.h
new file mode 100644
index 00000000000..61d193b07ca
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_result.h
@@ -0,0 +1,43 @@
+// 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 COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_RESULT_H_
+#define COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_RESULT_H_
+
+#include <stdint.h>
+
+#include "base/strings/string16.h"
+
+// This class mirrors blink::WebTextCheckingResult which holds a
+// misspelled range inside the checked text. It also contains a
+// possible replacement of the misspelling if it is available.
+struct SpellCheckResult {
+ enum Decoration {
+ // Red underline for misspelled words.
+ SPELLING = 1 << 1,
+
+ // Gray underline for correctly spelled words that are incorrectly used in
+ // their context.
+ GRAMMAR = 1 << 2,
+
+ // No underline for words that spellcheck needs to track. For example, a
+ // word in the custom spellcheck dictionary.
+ INVISIBLE = 1 << 3,
+ };
+
+ explicit SpellCheckResult(Decoration d = SPELLING,
+ int loc = 0,
+ int len = 0,
+ const base::string16& rep = base::string16(),
+ uint32_t h = 0)
+ : decoration(d), location(loc), length(len), replacement(rep), hash(h) {}
+
+ Decoration decoration;
+ int location;
+ int length;
+ base::string16 replacement;
+ uint32_t hash;
+};
+
+#endif // COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_RESULT_H_
diff --git a/chromium/components/spellcheck/common/spellcheck_switches.cc b/chromium/components/spellcheck/common/spellcheck_switches.cc
new file mode 100644
index 00000000000..0e794638a82
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_switches.cc
@@ -0,0 +1,33 @@
+// 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 "build/build_config.h"
+#include "components/spellcheck/common/spellcheck_switches.h"
+
+namespace spellcheck {
+namespace switches {
+
+#if defined(ENABLE_SPELLCHECK)
+// Enables participation in the field trial for user feedback to spelling
+// service.
+const char kEnableSpellingFeedbackFieldTrial[] =
+ "enable-spelling-feedback-field-trial";
+
+// Specifies the number of seconds between sending batches of feedback to
+// spelling service. The default is 30 minutes. The minimum is 5 seconds. This
+// switch is for temporary testing only.
+// TODO(rouslan): Remove this flag when feedback testing is complete. Revisit by
+// August 2013.
+const char kSpellingServiceFeedbackIntervalSeconds[] =
+ "spelling-service-feedback-interval-seconds";
+
+// Specifies the URL where spelling service feedback data will be sent instead
+// of the default URL. This switch is for temporary testing only.
+// TODO(rouslan): Remove this flag when feedback testing is complete. Revisit by
+// August 2013.
+const char kSpellingServiceFeedbackUrl[] = "spelling-service-feedback-url";
+#endif // defined(ENABLE_SPELLCHECK)
+
+} // namespace switches
+} // namespace spellcheck
diff --git a/chromium/components/spellcheck/common/spellcheck_switches.h b/chromium/components/spellcheck/common/spellcheck_switches.h
new file mode 100644
index 00000000000..abe4d6e2f8e
--- /dev/null
+++ b/chromium/components/spellcheck/common/spellcheck_switches.h
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_SWITCHES_H_
+#define COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_SWITCHES_H_
+
+#include "build/build_config.h"
+
+namespace spellcheck {
+namespace switches {
+
+#if defined(ENABLE_SPELLCHECK)
+extern const char kEnableSpellingFeedbackFieldTrial[];
+extern const char kSpellingServiceFeedbackIntervalSeconds[];
+extern const char kSpellingServiceFeedbackUrl[];
+#endif // defined(ENABLE_SPELLCHECK)
+
+} // namespace switches
+} // namespace spellcheck
+
+#endif // COMPONENTS_SPELLCHECK_COMMON_SPELLCHECK_SWITCHES_H_
diff --git a/chromium/components/spellcheck/renderer/BUILD.gn b/chromium/components/spellcheck/renderer/BUILD.gn
new file mode 100644
index 00000000000..96663628cf0
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/BUILD.gn
@@ -0,0 +1,107 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+
+source_set("renderer") {
+ sources = [
+ "custom_dictionary_engine.cc",
+ "custom_dictionary_engine.h",
+ "hunspell_engine.cc",
+ "hunspell_engine.h",
+ "platform_spelling_engine.cc",
+ "platform_spelling_engine.h",
+ "spellcheck.cc",
+ "spellcheck.h",
+ "spellcheck_language.cc",
+ "spellcheck_language.h",
+ "spellcheck_provider.cc",
+ "spellcheck_provider.h",
+ "spellcheck_worditerator.cc",
+ "spellcheck_worditerator.h",
+ "spelling_engine.h",
+ ]
+
+ if (!use_browser_spellchecker) {
+ sources -= [
+ "platform_spelling_engine.cc",
+ "platform_spelling_engine.h",
+ ]
+ }
+
+ if (is_android) {
+ sources -= [
+ "hunspell_engine.cc",
+ "hunspell_engine.h",
+ ]
+ }
+
+ deps = [
+ "//base:i18n",
+ "//components/spellcheck/common",
+ "//content/public/renderer",
+ "//ipc",
+ "//third_party/WebKit/public:blink",
+ "//third_party/icu",
+ ]
+
+ if (!is_android) {
+ deps += [ "//third_party/hunspell" ]
+ }
+
+ if (is_win) {
+ cflags = [ "/wd4267" ] # conversion from 'size_t' to 'int' on x64 (crbug.com/633312)
+ }
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "custom_dictionary_engine_unittest.cc",
+ "spellcheck_multilingual_unittest.cc",
+ "spellcheck_provider_hunspell_unittest.cc",
+ "spellcheck_provider_mac_unittest.cc",
+ "spellcheck_provider_test.cc",
+ "spellcheck_provider_test.h",
+ "spellcheck_unittest.cc",
+ "spellcheck_worditerator_unittest.cc",
+ ]
+ data = [
+ "//third_party/hunspell_dictionaries/",
+ ]
+
+ if (is_mac) {
+ sources -= [
+ # This tests Chrome's spellchecker which Mac doesn't use.
+ "spellcheck_multilingual_unittest.cc",
+ "spellcheck_provider_hunspell_unittest.cc",
+ ]
+ }
+
+ if (is_android) {
+ sources -= [
+ "spellcheck_multilingual_unittest.cc",
+ "spellcheck_provider_hunspell_unittest.cc",
+ "spellcheck_unittest.cc",
+ ]
+ }
+
+ deps = [
+ ":renderer",
+ "//base:i18n",
+ "//components/spellcheck/common",
+ "//ipc:ipc",
+ "//testing/gtest",
+ "//third_party/WebKit/public:blink",
+ "//third_party/icu",
+ ]
+
+ if (is_mac && !is_ios) {
+ deps += [ "//third_party/hunspell" ]
+ }
+
+ if (is_win) {
+ cflags = [ "/wd4267" ] # conversion from 'size_t' to 'int' on x64 (crbug.com/633312)
+ }
+}
diff --git a/chromium/components/spellcheck/renderer/DEPS b/chromium/components/spellcheck/renderer/DEPS
new file mode 100644
index 00000000000..16305c71d9d
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+content/public/renderer",
+ "+ipc",
+ "+third_party/WebKit/public",
+ "+third_party/hunspell",
+]
diff --git a/chromium/components/spellcheck/renderer/custom_dictionary_engine.cc b/chromium/components/spellcheck/renderer/custom_dictionary_engine.cc
new file mode 100644
index 00000000000..e00b7ec178d
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/custom_dictionary_engine.cc
@@ -0,0 +1,49 @@
+// 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 "components/spellcheck/renderer/custom_dictionary_engine.h"
+
+#include <stddef.h>
+
+#include "base/strings/utf_string_conversions.h"
+
+CustomDictionaryEngine::CustomDictionaryEngine() {
+}
+
+CustomDictionaryEngine::~CustomDictionaryEngine() {
+}
+
+void CustomDictionaryEngine::Init(const std::set<std::string>& custom_words) {
+ dictionary_.clear();
+
+ // SpellingMenuOberver calls UTF16ToUTF8(word) to convert words for storage,
+ // synchronization, and use in the custom dictionary engine. Since
+ // (UTF8ToUTF16(UTF16ToUTF8(word)) == word) holds, the engine does not need to
+ // normalize the strings.
+ for (const std::string& word : custom_words)
+ dictionary_.insert(base::UTF8ToUTF16(word));
+}
+
+void CustomDictionaryEngine::OnCustomDictionaryChanged(
+ const std::set<std::string>& words_added,
+ const std::set<std::string>& words_removed) {
+ for (const std::string& word : words_added)
+ dictionary_.insert(base::UTF8ToUTF16(word));
+
+ for (const std::string& word : words_removed)
+ dictionary_.erase(base::UTF8ToUTF16(word));
+}
+
+bool CustomDictionaryEngine::SpellCheckWord(
+ const base::string16& text,
+ int misspelling_start,
+ int misspelling_len) {
+ // The text to be checked is empty on OSX(async) right now.
+ // TODO(groby): Fix as part of async hook-up. (http://crbug.com/178241)
+ return
+ misspelling_start >= 0 &&
+ misspelling_len > 0 &&
+ size_t(misspelling_start + misspelling_len) <= text.length() &&
+ dictionary_.count(text.substr(misspelling_start, misspelling_len)) > 0;
+}
diff --git a/chromium/components/spellcheck/renderer/custom_dictionary_engine.h b/chromium/components/spellcheck/renderer/custom_dictionary_engine.h
new file mode 100644
index 00000000000..52e37e6d179
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/custom_dictionary_engine.h
@@ -0,0 +1,43 @@
+// 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 COMPONENTS_SPELLCHECK_RENDERER_CUSTOM_DICTIONARY_ENGINE_H_
+#define COMPONENTS_SPELLCHECK_RENDERER_CUSTOM_DICTIONARY_ENGINE_H_
+
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+
+// Custom spellcheck dictionary. Words in this dictionary are always correctly
+// spelled. Words that are not in this dictionary may or may not be correctly
+// spelled.
+class CustomDictionaryEngine {
+ public:
+ CustomDictionaryEngine();
+ ~CustomDictionaryEngine();
+
+ // Initialize the custom dictionary engine.
+ void Init(const std::set<std::string>& words);
+
+ // Spellcheck |text|. Assumes that another spelling engine has set
+ // |misspelling_start| and |misspelling_len| to indicate a misspelling.
+ // Returns true if there are no misspellings, otherwise returns false.
+ bool SpellCheckWord(const base::string16& text,
+ int misspelling_start,
+ int misspelling_len);
+
+ // Update custom dictionary words.
+ void OnCustomDictionaryChanged(const std::set<std::string>& words_added,
+ const std::set<std::string>& words_removed);
+
+ private:
+ // Correctly spelled words.
+ std::set<base::string16> dictionary_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomDictionaryEngine);
+};
+
+#endif // COMPONENTS_SPELLCHECK_RENDERER_CUSTOM_DICTIONARY_ENGINE_H_
diff --git a/chromium/components/spellcheck/renderer/custom_dictionary_engine_unittest.cc b/chromium/components/spellcheck/renderer/custom_dictionary_engine_unittest.cc
new file mode 100644
index 00000000000..635316cacfa
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/custom_dictionary_engine_unittest.cc
@@ -0,0 +1,30 @@
+// 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 "base/strings/utf_string_conversions.h"
+#include "components/spellcheck/renderer/custom_dictionary_engine.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(CustomDictionaryTest, HandlesEmptyWordWithInvalidSubstring) {
+ CustomDictionaryEngine engine;
+ std::set<std::string> custom_words;
+ engine.Init(custom_words);
+ EXPECT_FALSE(engine.SpellCheckWord(base::string16().c_str(), 15, 23));
+}
+
+TEST(CustomDictionaryTest, Basic) {
+ CustomDictionaryEngine engine;
+ EXPECT_FALSE(engine.SpellCheckWord(base::ASCIIToUTF16("helllo").c_str(),
+ 0, 6));
+ std::set<std::string> custom_words;
+ custom_words.insert("helllo");
+ engine.Init(custom_words);
+ EXPECT_TRUE(engine.SpellCheckWord(base::ASCIIToUTF16("helllo").c_str(),
+ 0, 6));
+}
+
+TEST(CustomDictionaryTest, HandlesNullCharacters) {
+ base::char16 data[4] = {'a', 0, 'b', 'c'};
+ EXPECT_FALSE(CustomDictionaryEngine().SpellCheckWord(data, 1, 1));
+}
diff --git a/chromium/components/spellcheck/renderer/hunspell_engine.cc b/chromium/components/spellcheck/renderer/hunspell_engine.cc
new file mode 100644
index 00000000000..191856541d8
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/hunspell_engine.cc
@@ -0,0 +1,140 @@
+// 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 "components/spellcheck/renderer/hunspell_engine.h"
+
+#include <stddef.h>
+#include <algorithm>
+#include <iterator>
+#include <utility>
+
+#include "base/files/memory_mapped_file.h"
+#include "base/time/time.h"
+#include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/common/spellcheck_messages.h"
+#include "content/public/renderer/render_thread.h"
+#include "third_party/hunspell/src/hunspell/hunspell.hxx"
+
+using content::RenderThread;
+
+namespace {
+ // Maximum length of words we actually check.
+ // 64 is the observed limits for OSX system checker.
+ const size_t kMaxCheckedLen = 64;
+
+ // Maximum length of words we provide suggestions for.
+ // 24 is the observed limits for OSX system checker.
+ const size_t kMaxSuggestLen = 24;
+
+ static_assert(kMaxCheckedLen <= size_t(MAXWORDLEN),
+ "MaxCheckedLen too long");
+ static_assert(kMaxSuggestLen <= kMaxCheckedLen,
+ "MaxSuggestLen too long");
+} // namespace
+
+#if !defined(USE_BROWSER_SPELLCHECKER)
+SpellingEngine* CreateNativeSpellingEngine() {
+ return new HunspellEngine();
+}
+#endif
+
+HunspellEngine::HunspellEngine()
+ : hunspell_enabled_(false),
+ initialized_(false),
+ dictionary_requested_(false) {
+ // Wait till we check the first word before doing any initializing.
+}
+
+HunspellEngine::~HunspellEngine() {
+}
+
+void HunspellEngine::Init(base::File file) {
+ initialized_ = true;
+ hunspell_.reset();
+ bdict_file_.reset();
+ file_ = std::move(file);
+ hunspell_enabled_ = file_.IsValid();
+ // Delay the actual initialization of hunspell until it is needed.
+}
+
+void HunspellEngine::InitializeHunspell() {
+ if (hunspell_.get())
+ return;
+
+ bdict_file_.reset(new base::MemoryMappedFile);
+
+ if (bdict_file_->Initialize(std::move(file_))) {
+ hunspell_.reset(new Hunspell(bdict_file_->data(), bdict_file_->length()));
+ } else {
+ NOTREACHED() << "Could not mmap spellchecker dictionary.";
+ }
+}
+
+bool HunspellEngine::CheckSpelling(const base::string16& word_to_check,
+ int tag) {
+ // Assume all words that cannot be checked are valid. Since Chrome can't
+ // offer suggestions on them, either, there's no point in flagging them to
+ // the user.
+ bool word_correct = true;
+ std::string word_to_check_utf8(base::UTF16ToUTF8(word_to_check));
+
+ // Limit the size of checked words.
+ if (word_to_check_utf8.length() <= kMaxCheckedLen) {
+ // If |hunspell_| is NULL here, an error has occurred, but it's better
+ // to check rather than crash.
+ if (hunspell_.get()) {
+ // |hunspell_->spell| returns 0 if the word is misspelled.
+ word_correct = (hunspell_->spell(word_to_check_utf8.c_str()) != 0);
+ }
+ }
+
+ return word_correct;
+}
+
+void HunspellEngine::FillSuggestionList(
+ const base::string16& wrong_word,
+ std::vector<base::string16>* optional_suggestions) {
+ std::string wrong_word_utf8(base::UTF16ToUTF8(wrong_word));
+ if (wrong_word_utf8.length() > kMaxSuggestLen)
+ return;
+
+ // If |hunspell_| is NULL here, an error has occurred, but it's better
+ // to check rather than crash.
+ // TODO(groby): Technically, it's not. We should track down the issue.
+ if (!hunspell_.get())
+ return;
+
+ char** suggestions = NULL;
+ int number_of_suggestions =
+ hunspell_->suggest(&suggestions, wrong_word_utf8.c_str());
+
+ // Populate the vector of WideStrings.
+ for (int i = 0; i < number_of_suggestions; ++i) {
+ if (i < spellcheck::kMaxSuggestions)
+ optional_suggestions->push_back(base::UTF8ToUTF16(suggestions[i]));
+ free(suggestions[i]);
+ }
+ if (suggestions != NULL)
+ free(suggestions);
+}
+
+bool HunspellEngine::InitializeIfNeeded() {
+ if (!initialized_ && !dictionary_requested_) {
+ // RenderThread will not exist in test.
+ if (RenderThread::Get())
+ RenderThread::Get()->Send(new SpellCheckHostMsg_RequestDictionary);
+ dictionary_requested_ = true;
+ return true;
+ }
+
+ // Don't initialize if hunspell is disabled.
+ if (file_.IsValid())
+ InitializeHunspell();
+
+ return !initialized_;
+}
+
+bool HunspellEngine::IsEnabled() {
+ return hunspell_enabled_;
+}
diff --git a/chromium/components/spellcheck/renderer/hunspell_engine.h b/chromium/components/spellcheck/renderer/hunspell_engine.h
new file mode 100644
index 00000000000..02adcee0def
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/hunspell_engine.h
@@ -0,0 +1,63 @@
+// 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 COMPONENTS_SPELLCHECK_RENDERER_HUNSPELL_ENGINE_H_
+#define COMPONENTS_SPELLCHECK_RENDERER_HUNSPELL_ENGINE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/renderer/spelling_engine.h"
+
+class Hunspell;
+
+namespace base {
+class MemoryMappedFile;
+}
+
+class HunspellEngine : public SpellingEngine {
+ public:
+ HunspellEngine();
+ ~HunspellEngine() override;
+
+ void Init(base::File file) override;
+
+ bool InitializeIfNeeded() override;
+ bool IsEnabled() override;
+ bool CheckSpelling(const base::string16& word_to_check, int tag) override;
+ void FillSuggestionList(
+ const base::string16& wrong_word,
+ std::vector<base::string16>* optional_suggestions) override;
+
+ private:
+ // Initializes the Hunspell dictionary, or does nothing if |hunspell_| is
+ // non-null. This blocks.
+ void InitializeHunspell();
+
+ // We memory-map the BDict file.
+ std::unique_ptr<base::MemoryMappedFile> bdict_file_;
+
+ // The hunspell dictionary in use.
+ std::unique_ptr<Hunspell> hunspell_;
+
+ base::File file_;
+
+ // This flag is true if hunspell is enabled.
+ bool hunspell_enabled_;
+
+ // This flag is true if we have been initialized.
+ // The value indicates whether we should request a
+ // dictionary from the browser when the render view asks us to check the
+ // spelling of a word.
+ bool initialized_;
+
+ // This flag is true if we have requested dictionary.
+ bool dictionary_requested_;
+};
+
+#endif // COMPONENTS_SPELLCHECK_RENDERER_HUNSPELL_ENGINE_H_
diff --git a/chromium/components/spellcheck/renderer/platform_spelling_engine.cc b/chromium/components/spellcheck/renderer/platform_spelling_engine.cc
new file mode 100644
index 00000000000..6c9176abecc
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/platform_spelling_engine.cc
@@ -0,0 +1,47 @@
+// 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 "components/spellcheck/renderer/platform_spelling_engine.h"
+
+#include "components/spellcheck/common/spellcheck_messages.h"
+#include "content/public/renderer/render_thread.h"
+
+using content::RenderThread;
+
+SpellingEngine* CreateNativeSpellingEngine() {
+ return new PlatformSpellingEngine();
+}
+
+void PlatformSpellingEngine::Init(base::File bdict_file) {
+ DCHECK(!bdict_file.IsValid());
+}
+
+bool PlatformSpellingEngine::InitializeIfNeeded() {
+ return false;
+}
+
+bool PlatformSpellingEngine::IsEnabled() {
+ return true;
+}
+
+// Synchronously query against the platform's spellchecker.
+// TODO(groby): We might want async support here, too. Ideally,
+// all engines share a similar path for async requests.
+bool PlatformSpellingEngine::CheckSpelling(const base::string16& word_to_check,
+ int tag) {
+ bool word_correct = false;
+ RenderThread::Get()->Send(new SpellCheckHostMsg_CheckSpelling(
+ word_to_check, tag, &word_correct));
+ return word_correct;
+}
+
+// Synchronously query against the platform's spellchecker.
+// TODO(groby): We might want async support here, too. Ideally,
+// all engines share a similar path for async requests.
+void PlatformSpellingEngine::FillSuggestionList(
+ const base::string16& wrong_word,
+ std::vector<base::string16>* optional_suggestions) {
+ RenderThread::Get()->Send(new SpellCheckHostMsg_FillSuggestionList(
+ wrong_word, optional_suggestions));
+}
diff --git a/chromium/components/spellcheck/renderer/platform_spelling_engine.h b/chromium/components/spellcheck/renderer/platform_spelling_engine.h
new file mode 100644
index 00000000000..294d826258f
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/platform_spelling_engine.h
@@ -0,0 +1,23 @@
+// 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 COMPONENTS_SPELLCHECK_RENDERER_PLATFORM_SPELLING_ENGINE_H_
+#define COMPONENTS_SPELLCHECK_RENDERER_PLATFORM_SPELLING_ENGINE_H_
+
+#include "base/compiler_specific.h"
+#include "components/spellcheck/renderer/spelling_engine.h"
+
+class PlatformSpellingEngine : public SpellingEngine {
+ public:
+ void Init(base::File bdict_file) override;
+ bool InitializeIfNeeded() override;
+ bool IsEnabled() override;
+ bool CheckSpelling(const base::string16& word_to_check, int tag) override;
+ void FillSuggestionList(
+ const base::string16& wrong_word,
+ std::vector<base::string16>* optional_suggestions) override;
+};
+
+#endif // COMPONENTS_SPELLCHECK_RENDERER_PLATFORM_SPELLING_ENGINE_H_
+
diff --git a/chromium/components/spellcheck/renderer/spellcheck.cc b/chromium/components/spellcheck/renderer/spellcheck.cc
new file mode 100644
index 00000000000..4757dc65233
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck.cc
@@ -0,0 +1,544 @@
+// 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 "components/spellcheck/renderer/spellcheck.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/common/spellcheck_features.h"
+#include "components/spellcheck/common/spellcheck_messages.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "components/spellcheck/common/spellcheck_switches.h"
+#include "components/spellcheck/renderer/spellcheck_language.h"
+#include "components/spellcheck/renderer/spellcheck_provider.h"
+#include "content/public/renderer/render_thread.h"
+#include "content/public/renderer/render_view.h"
+#include "content/public/renderer/render_view_visitor.h"
+#include "ipc/ipc_platform_file.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h"
+#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
+#include "third_party/WebKit/public/web/WebTextDecorationType.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+using blink::WebVector;
+using blink::WebString;
+using blink::WebTextCheckingResult;
+using blink::WebTextDecorationType;
+
+namespace {
+const int kNoOffset = 0;
+const int kNoTag = 0;
+
+class UpdateSpellcheckEnabled : public content::RenderViewVisitor {
+ public:
+ explicit UpdateSpellcheckEnabled(bool enabled) : enabled_(enabled) {}
+ bool Visit(content::RenderView* render_view) override;
+
+ private:
+ bool enabled_; // New spellcheck-enabled state.
+ DISALLOW_COPY_AND_ASSIGN(UpdateSpellcheckEnabled);
+};
+
+bool UpdateSpellcheckEnabled::Visit(content::RenderView* render_view) {
+ SpellCheckProvider* provider = SpellCheckProvider::Get(render_view);
+ DCHECK(provider);
+ provider->EnableSpellcheck(enabled_);
+ return true;
+}
+
+class DocumentMarkersCollector : public content::RenderViewVisitor {
+ public:
+ DocumentMarkersCollector() {}
+ ~DocumentMarkersCollector() override {}
+ const std::vector<uint32_t>& markers() const { return markers_; }
+ bool Visit(content::RenderView* render_view) override;
+
+ private:
+ std::vector<uint32_t> markers_;
+ DISALLOW_COPY_AND_ASSIGN(DocumentMarkersCollector);
+};
+
+bool DocumentMarkersCollector::Visit(content::RenderView* render_view) {
+ if (!render_view || !render_view->GetWebView())
+ return true;
+ WebVector<uint32_t> markers;
+ render_view->GetWebView()->spellingMarkers(&markers);
+ for (size_t i = 0; i < markers.size(); ++i)
+ markers_.push_back(markers[i]);
+ // Visit all render views.
+ return true;
+}
+
+class DocumentMarkersRemover : public content::RenderViewVisitor {
+ public:
+ explicit DocumentMarkersRemover(const std::set<std::string>& words);
+ ~DocumentMarkersRemover() override {}
+ bool Visit(content::RenderView* render_view) override;
+
+ private:
+ WebVector<WebString> words_;
+ DISALLOW_COPY_AND_ASSIGN(DocumentMarkersRemover);
+};
+
+DocumentMarkersRemover::DocumentMarkersRemover(
+ const std::set<std::string>& words)
+ : words_(words.size()) {
+ std::transform(words.begin(), words.end(), words_.begin(),
+ [](const std::string& w) { return WebString::fromUTF8(w); });
+}
+
+bool DocumentMarkersRemover::Visit(content::RenderView* render_view) {
+ if (render_view && render_view->GetWebView())
+ render_view->GetWebView()->removeSpellingMarkersUnderWords(words_);
+ return true;
+}
+
+bool IsApostrophe(base::char16 c) {
+ const base::char16 kApostrophe = 0x27;
+ const base::char16 kRightSingleQuotationMark = 0x2019;
+ return c == kApostrophe || c == kRightSingleQuotationMark;
+}
+
+// Makes sure that the apostrophes in the |spelling_suggestion| are the same
+// type as in the |misspelled_word| and in the same order. Ignore differences in
+// the number of apostrophes.
+void PreserveOriginalApostropheTypes(const base::string16& misspelled_word,
+ base::string16* spelling_suggestion) {
+ auto it = spelling_suggestion->begin();
+ for (const base::char16& c : misspelled_word) {
+ if (IsApostrophe(c)) {
+ it = std::find_if(it, spelling_suggestion->end(), IsApostrophe);
+ if (it == spelling_suggestion->end())
+ return;
+
+ *it++ = c;
+ }
+ }
+}
+
+} // namespace
+
+class SpellCheck::SpellcheckRequest {
+ public:
+ SpellcheckRequest(const base::string16& text,
+ blink::WebTextCheckingCompletion* completion)
+ : text_(text), completion_(completion) {
+ DCHECK(completion);
+ }
+ ~SpellcheckRequest() {}
+
+ base::string16 text() { return text_; }
+ blink::WebTextCheckingCompletion* completion() { return completion_; }
+
+ private:
+ base::string16 text_; // Text to be checked in this task.
+
+ // The interface to send the misspelled ranges to WebKit.
+ blink::WebTextCheckingCompletion* completion_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellcheckRequest);
+};
+
+
+// Initializes SpellCheck object.
+// spellcheck_enabled_ currently MUST be set to true, due to peculiarities of
+// the initialization sequence.
+// Since it defaults to true, newly created SpellCheckProviders will enable
+// spellchecking. After the first word is typed, the provider requests a check,
+// which in turn triggers the delayed initialization sequence in SpellCheck.
+// This does send a message to the browser side, which triggers the creation
+// of the SpellcheckService. That does create the observer for the preference
+// responsible for enabling/disabling checking, which allows subsequent changes
+// to that preference to be sent to all SpellCheckProviders.
+// Setting |spellcheck_enabled_| to false by default prevents that mechanism,
+// and as such the SpellCheckProviders will never be notified of different
+// values.
+// TODO(groby): Simplify this.
+SpellCheck::SpellCheck() : spellcheck_enabled_(true) {}
+
+SpellCheck::~SpellCheck() {
+}
+
+void SpellCheck::FillSuggestions(
+ const std::vector<std::vector<base::string16>>& suggestions_list,
+ std::vector<base::string16>* optional_suggestions) {
+ DCHECK(optional_suggestions);
+ size_t num_languages = suggestions_list.size();
+
+ // Compute maximum number of suggestions in a single language.
+ size_t max_suggestions = 0;
+ for (const auto& suggestions : suggestions_list)
+ max_suggestions = std::max(max_suggestions, suggestions.size());
+
+ for (size_t count = 0; count < (max_suggestions * num_languages); ++count) {
+ size_t language = count % num_languages;
+ size_t index = count / num_languages;
+
+ if (suggestions_list[language].size() <= index)
+ continue;
+
+ const base::string16& suggestion = suggestions_list[language][index];
+ // Only add the suggestion if it's unique.
+ if (!base::ContainsValue(*optional_suggestions, suggestion)) {
+ optional_suggestions->push_back(suggestion);
+ }
+ if (optional_suggestions->size() >= spellcheck::kMaxSuggestions) {
+ break;
+ }
+ }
+}
+
+bool SpellCheck::OnControlMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(SpellCheck, message)
+ IPC_MESSAGE_HANDLER(SpellCheckMsg_Init, OnInit)
+ IPC_MESSAGE_HANDLER(SpellCheckMsg_CustomDictionaryChanged,
+ OnCustomDictionaryChanged)
+ IPC_MESSAGE_HANDLER(SpellCheckMsg_EnableSpellCheck, OnEnableSpellCheck)
+ IPC_MESSAGE_HANDLER(SpellCheckMsg_RequestDocumentMarkers,
+ OnRequestDocumentMarkers)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void SpellCheck::OnInit(
+ const std::vector<SpellCheckBDictLanguage>& bdict_languages,
+ const std::set<std::string>& custom_words) {
+ languages_.clear();
+ for (const auto& bdict_language : bdict_languages) {
+ AddSpellcheckLanguage(
+ IPC::PlatformFileForTransitToFile(bdict_language.file),
+ bdict_language.language);
+ }
+
+ custom_dictionary_.Init(custom_words);
+#if !defined(USE_BROWSER_SPELLCHECKER)
+ PostDelayedSpellCheckTask(pending_request_param_.release());
+#endif
+}
+
+void SpellCheck::OnCustomDictionaryChanged(
+ const std::set<std::string>& words_added,
+ const std::set<std::string>& words_removed) {
+ custom_dictionary_.OnCustomDictionaryChanged(words_added, words_removed);
+ if (words_added.empty())
+ return;
+ DocumentMarkersRemover markersRemover(words_added);
+ content::RenderView::ForEach(&markersRemover);
+}
+
+void SpellCheck::OnEnableSpellCheck(bool enable) {
+ spellcheck_enabled_ = enable;
+ UpdateSpellcheckEnabled updater(enable);
+ content::RenderView::ForEach(&updater);
+}
+
+void SpellCheck::OnRequestDocumentMarkers() {
+ DocumentMarkersCollector collector;
+ content::RenderView::ForEach(&collector);
+ content::RenderThread::Get()->Send(
+ new SpellCheckHostMsg_RespondDocumentMarkers(collector.markers()));
+}
+
+// TODO(groby): Make sure we always have a spelling engine, even before
+// AddSpellcheckLanguage() is called.
+void SpellCheck::AddSpellcheckLanguage(base::File file,
+ const std::string& language) {
+ languages_.push_back(new SpellcheckLanguage());
+ languages_.back()->Init(std::move(file), language);
+}
+
+bool SpellCheck::SpellCheckWord(
+ const base::char16* text_begin,
+ int position_in_text,
+ int text_length,
+ int tag,
+ int* misspelling_start,
+ int* misspelling_len,
+ std::vector<base::string16>* optional_suggestions) {
+ DCHECK(text_length >= position_in_text);
+ DCHECK(misspelling_start && misspelling_len) << "Out vars must be given.";
+
+ // Do nothing if we need to delay initialization. (Rather than blocking,
+ // report the word as correctly spelled.)
+ if (InitializeIfNeeded())
+ return true;
+
+ // These are for holding misspelling or skippable word positions and lengths
+ // between calls to SpellcheckLanguage::SpellCheckWord.
+ int possible_misspelling_start;
+ int possible_misspelling_len;
+ // The longest sequence of text that all languages agree is skippable.
+ int agreed_skippable_len;
+ // A vector of vectors containing spelling suggestions from different
+ // languages.
+ std::vector<std::vector<base::string16>> suggestions_list;
+ // A vector to hold a language's misspelling suggestions between spellcheck
+ // calls.
+ std::vector<base::string16> language_suggestions;
+
+ // This loop only advances if all languages agree that a sequence of text is
+ // skippable.
+ for (; position_in_text <= text_length;
+ position_in_text += agreed_skippable_len) {
+ // Reseting |agreed_skippable_len| to the worst-case length each time
+ // prevents some unnecessary iterations.
+ agreed_skippable_len = text_length;
+ *misspelling_start = 0;
+ *misspelling_len = 0;
+ suggestions_list.clear();
+
+ for (ScopedVector<SpellcheckLanguage>::iterator language =
+ languages_.begin();
+ language != languages_.end();) {
+ language_suggestions.clear();
+ SpellcheckLanguage::SpellcheckWordResult result =
+ (*language)->SpellCheckWord(
+ text_begin, position_in_text, text_length, tag,
+ &possible_misspelling_start, &possible_misspelling_len,
+ optional_suggestions ? &language_suggestions : nullptr);
+
+ switch (result) {
+ case SpellcheckLanguage::SpellcheckWordResult::IS_CORRECT:
+ *misspelling_start = 0;
+ *misspelling_len = 0;
+ return true;
+ case SpellcheckLanguage::SpellcheckWordResult::IS_SKIPPABLE:
+ agreed_skippable_len =
+ std::min(agreed_skippable_len, possible_misspelling_len);
+ // If true, this means the spellchecker moved past a word that was
+ // previously determined to be misspelled or skippable, which means
+ // another spellcheck language marked it as correct.
+ if (position_in_text != possible_misspelling_start) {
+ *misspelling_len = 0;
+ position_in_text = possible_misspelling_start;
+ suggestions_list.clear();
+ language = languages_.begin();
+ } else {
+ language++;
+ }
+ break;
+ case SpellcheckLanguage::SpellcheckWordResult::IS_MISSPELLED:
+ *misspelling_start = possible_misspelling_start;
+ *misspelling_len = possible_misspelling_len;
+ // If true, this means the spellchecker moved past a word that was
+ // previously determined to be misspelled or skippable, which means
+ // another spellcheck language marked it as correct.
+ if (position_in_text != *misspelling_start) {
+ suggestions_list.clear();
+ language = languages_.begin();
+ position_in_text = *misspelling_start;
+ } else {
+ suggestions_list.push_back(language_suggestions);
+ language++;
+ }
+ break;
+ }
+ }
+
+ // If |*misspelling_len| is non-zero, that means at least one language
+ // marked a word misspelled and no other language considered it correct.
+ if (*misspelling_len != 0) {
+ if (optional_suggestions)
+ FillSuggestions(suggestions_list, optional_suggestions);
+ return false;
+ }
+ }
+
+ NOTREACHED();
+ return true;
+}
+
+bool SpellCheck::SpellCheckParagraph(
+ const base::string16& text,
+ WebVector<WebTextCheckingResult>* results) {
+#if !defined(USE_BROWSER_SPELLCHECKER)
+ // Mac and Android have their own spell checkers,so this method won't be used
+ DCHECK(results);
+ std::vector<WebTextCheckingResult> textcheck_results;
+ size_t length = text.length();
+ size_t position_in_text = 0;
+
+ // Spellcheck::SpellCheckWord() automatically breaks text into words and
+ // checks the spellings of the extracted words. This function sets the
+ // position and length of the first misspelled word and returns false when
+ // the text includes misspelled words. Therefore, we just repeat calling the
+ // function until it returns true to check the whole text.
+ int misspelling_start = 0;
+ int misspelling_length = 0;
+ while (position_in_text <= length) {
+ if (SpellCheckWord(text.c_str(),
+ position_in_text,
+ length,
+ kNoTag,
+ &misspelling_start,
+ &misspelling_length,
+ NULL)) {
+ results->assign(textcheck_results);
+ return true;
+ }
+
+ if (!custom_dictionary_.SpellCheckWord(
+ text, misspelling_start, misspelling_length)) {
+ base::string16 replacement;
+ textcheck_results.push_back(WebTextCheckingResult(
+ blink::WebTextDecorationTypeSpelling,
+ misspelling_start,
+ misspelling_length,
+ replacement));
+ }
+ position_in_text = misspelling_start + misspelling_length;
+ }
+ results->assign(textcheck_results);
+ return false;
+#else
+ // This function is only invoked for spell checker functionality that runs
+ // on the render thread. OSX and Android builds don't have that.
+ NOTREACHED();
+ return true;
+#endif
+}
+
+// OSX and Android use their own spell checkers
+#if !defined(USE_BROWSER_SPELLCHECKER)
+void SpellCheck::RequestTextChecking(
+ const base::string16& text,
+ blink::WebTextCheckingCompletion* completion) {
+ // Clean up the previous request before starting a new request.
+ if (pending_request_param_.get())
+ pending_request_param_->completion()->didCancelCheckingText();
+
+ pending_request_param_.reset(new SpellcheckRequest(
+ text, completion));
+ // We will check this text after we finish loading the hunspell dictionary.
+ if (InitializeIfNeeded())
+ return;
+
+ PostDelayedSpellCheckTask(pending_request_param_.release());
+}
+#endif
+
+bool SpellCheck::InitializeIfNeeded() {
+ if (languages_.empty())
+ return true;
+
+ bool initialize_if_needed = false;
+ for (SpellcheckLanguage* language : languages_)
+ initialize_if_needed |= language->InitializeIfNeeded();
+
+ return initialize_if_needed;
+}
+
+// OSX and Android don't have |pending_request_param_|
+#if !defined(USE_BROWSER_SPELLCHECKER)
+void SpellCheck::PostDelayedSpellCheckTask(SpellcheckRequest* request) {
+ if (!request)
+ return;
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&SpellCheck::PerformSpellCheck, AsWeakPtr(),
+ base::Owned(request)));
+}
+#endif
+
+// Mac and Android use their platform engines instead.
+#if !defined(USE_BROWSER_SPELLCHECKER)
+void SpellCheck::PerformSpellCheck(SpellcheckRequest* param) {
+ DCHECK(param);
+
+ if (languages_.empty() ||
+ std::find_if(languages_.begin(), languages_.end(),
+ [](SpellcheckLanguage* language) {
+ return !language->IsEnabled();
+ }) != languages_.end()) {
+ param->completion()->didCancelCheckingText();
+ } else {
+ WebVector<blink::WebTextCheckingResult> results;
+ SpellCheckParagraph(param->text(), &results);
+ param->completion()->didFinishCheckingText(results);
+ }
+}
+#endif
+
+void SpellCheck::CreateTextCheckingResults(
+ ResultFilter filter,
+ int line_offset,
+ const base::string16& line_text,
+ const std::vector<SpellCheckResult>& spellcheck_results,
+ WebVector<WebTextCheckingResult>* textcheck_results) {
+ DCHECK(!line_text.empty());
+
+ std::vector<WebTextCheckingResult> results;
+ for (const SpellCheckResult& spellcheck_result : spellcheck_results) {
+ DCHECK_LE(static_cast<size_t>(spellcheck_result.location),
+ line_text.length());
+ DCHECK_LE(static_cast<size_t>(spellcheck_result.location +
+ spellcheck_result.length),
+ line_text.length());
+
+ const base::string16& misspelled_word =
+ line_text.substr(spellcheck_result.location, spellcheck_result.length);
+ base::string16 replacement = spellcheck_result.replacement;
+ SpellCheckResult::Decoration decoration = spellcheck_result.decoration;
+
+ // Ignore words in custom dictionary.
+ if (custom_dictionary_.SpellCheckWord(misspelled_word, 0,
+ misspelled_word.length())) {
+ continue;
+ }
+
+ // Use the same types of appostrophes as in the mispelled word.
+ PreserveOriginalApostropheTypes(misspelled_word, &replacement);
+
+ // Ignore misspellings due the typographical apostrophe.
+ if (misspelled_word == replacement)
+ continue;
+
+ if (filter == USE_NATIVE_CHECKER) {
+ // Double-check misspelled words with out spellchecker and attach grammar
+ // markers to them if our spellchecker tells us they are correct words,
+ // i.e. they are probably contextually-misspelled words.
+ int unused_misspelling_start = 0;
+ int unused_misspelling_length = 0;
+ if (decoration == SpellCheckResult::SPELLING &&
+ SpellCheckWord(misspelled_word.c_str(), kNoOffset,
+ misspelled_word.length(), kNoTag,
+ &unused_misspelling_start, &unused_misspelling_length,
+ nullptr)) {
+ decoration = SpellCheckResult::GRAMMAR;
+ }
+ }
+
+ results.push_back(WebTextCheckingResult(
+ static_cast<WebTextDecorationType>(decoration),
+ line_offset + spellcheck_result.location, spellcheck_result.length,
+ replacement, spellcheck_result.hash));
+ }
+
+ textcheck_results->assign(results);
+}
+
+bool SpellCheck::IsSpellcheckEnabled() {
+#if defined(OS_ANDROID)
+ if (!spellcheck::IsAndroidSpellCheckFeatureEnabled()) return false;
+#endif
+ return spellcheck_enabled_;
+}
diff --git a/chromium/components/spellcheck/renderer/spellcheck.h b/chromium/components/spellcheck/renderer/spellcheck.h
new file mode 100644
index 00000000000..9bcd1ce0295
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck.h
@@ -0,0 +1,164 @@
+// 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 COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_H_
+#define COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "components/spellcheck/renderer/custom_dictionary_engine.h"
+#include "content/public/renderer/render_thread_observer.h"
+
+struct SpellCheckBDictLanguage;
+class SpellcheckLanguage;
+struct SpellCheckResult;
+
+namespace blink {
+class WebTextCheckingCompletion;
+struct WebTextCheckingResult;
+template <typename T> class WebVector;
+}
+
+namespace IPC {
+class Message;
+}
+
+// TODO(morrita): Needs reorg with SpellCheckProvider.
+// See http://crbug.com/73699.
+// Shared spellchecking logic/data for a RenderProcess. All RenderViews use
+// this object to perform spellchecking tasks.
+class SpellCheck : public content::RenderThreadObserver,
+ public base::SupportsWeakPtr<SpellCheck> {
+ public:
+ // TODO(groby): I wonder if this can be private, non-mac only.
+ class SpellcheckRequest;
+ enum ResultFilter {
+ DO_NOT_MODIFY = 1, // Do not modify results.
+ USE_NATIVE_CHECKER, // Use native checker to double-check.
+ };
+
+ SpellCheck();
+ ~SpellCheck() override;
+
+ void AddSpellcheckLanguage(base::File file, const std::string& language);
+
+ // If there are no dictionary files, then this requests them from the browser
+ // and does not block. In this case it returns true.
+ // If there are dictionary files, but their Hunspell has not been loaded, then
+ // this loads their Hunspell.
+ // If each dictionary file's Hunspell is already loaded, this does nothing. In
+ // both the latter cases it returns false, meaning that it is OK to continue
+ // spellchecking.
+ bool InitializeIfNeeded();
+
+ // SpellCheck a word.
+ // Returns true if spelled correctly for any language in |languages_|, false
+ // otherwise.
+ // If any spellcheck languages failed to initialize, always returns true.
+ // The |tag| parameter should either be a unique identifier for the document
+ // that the word came from (if the current platform requires it), or 0.
+ // In addition, finds the suggested words for a given word
+ // and puts them into |*optional_suggestions|.
+ // If the word is spelled correctly, the vector is empty.
+ // If optional_suggestions is NULL, suggested words will not be looked up.
+ // Note that doing suggest lookups can be slow.
+ bool SpellCheckWord(const base::char16* text_begin,
+ int position_in_text,
+ int text_length,
+ int tag,
+ int* misspelling_start,
+ int* misspelling_len,
+ std::vector<base::string16>* optional_suggestions);
+
+ // SpellCheck a paragraph.
+ // Returns true if |text| is correctly spelled, false otherwise.
+ // If the spellchecker failed to initialize, always returns true.
+ bool SpellCheckParagraph(
+ const base::string16& text,
+ blink::WebVector<blink::WebTextCheckingResult>* results);
+
+ // Requests to spellcheck the specified text in the background. This function
+ // posts a background task and calls SpellCheckParagraph() in the task.
+#if !defined (USE_BROWSER_SPELLCHECKER)
+ void RequestTextChecking(const base::string16& text,
+ blink::WebTextCheckingCompletion* completion);
+#endif
+
+ // Creates a list of WebTextCheckingResult objects (used by WebKit) from a
+ // list of SpellCheckResult objects (used by Chrome). This function also
+ // checks misspelled words returned by the Spelling service and changes the
+ // underline colors of contextually-misspelled words.
+ void CreateTextCheckingResults(
+ ResultFilter filter,
+ int line_offset,
+ const base::string16& line_text,
+ const std::vector<SpellCheckResult>& spellcheck_results,
+ blink::WebVector<blink::WebTextCheckingResult>* textcheck_results);
+
+ bool IsSpellcheckEnabled();
+
+ private:
+ friend class SpellCheckTest;
+ FRIEND_TEST_ALL_PREFIXES(SpellCheckTest, GetAutoCorrectionWord_EN_US);
+ FRIEND_TEST_ALL_PREFIXES(SpellCheckTest,
+ RequestSpellCheckMultipleTimesWithoutInitialization);
+
+ // Evenly fill |optional_suggestions| with a maximum of |kMaxSuggestions|
+ // suggestions from |suggestions_list|. suggestions_list[i][j] is the j-th
+ // suggestion from the i-th language's suggestions. |optional_suggestions|
+ // cannot be null.
+ static void FillSuggestions(
+ const std::vector<std::vector<base::string16>>& suggestions_list,
+ std::vector<base::string16>* optional_suggestions);
+
+ // RenderThreadObserver implementation:
+ bool OnControlMessageReceived(const IPC::Message& message) override;
+
+ // Message handlers.
+ void OnInit(const std::vector<SpellCheckBDictLanguage>& bdict_languages,
+ const std::set<std::string>& custom_words);
+ void OnCustomDictionaryChanged(const std::set<std::string>& words_added,
+ const std::set<std::string>& words_removed);
+ void OnEnableSpellCheck(bool enable);
+ void OnRequestDocumentMarkers();
+
+#if !defined (USE_BROWSER_SPELLCHECKER)
+ // Posts delayed spellcheck task and clear it if any.
+ // Takes ownership of |request|.
+ void PostDelayedSpellCheckTask(SpellcheckRequest* request);
+
+ // Performs spell checking from the request queue.
+ void PerformSpellCheck(SpellcheckRequest* request);
+
+ // The parameters of a pending background-spellchecking request. When WebKit
+ // sends a background-spellchecking request before initializing hunspell,
+ // we save its parameters and start spellchecking after we finish initializing
+ // hunspell. (When WebKit sends two or more requests, we cancel the previous
+ // requests so we do not have to use vectors.)
+ std::unique_ptr<SpellcheckRequest> pending_request_param_;
+#endif
+
+ // A vector of objects used to actually check spelling, one for each enabled
+ // language.
+ ScopedVector<SpellcheckLanguage> languages_;
+
+ // Custom dictionary spelling engine.
+ CustomDictionaryEngine custom_dictionary_;
+
+ // Remember state for spellchecking.
+ bool spellcheck_enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellCheck);
+};
+
+#endif // COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_H_
diff --git a/chromium/components/spellcheck/renderer/spellcheck_language.cc b/chromium/components/spellcheck/renderer/spellcheck_language.cc
new file mode 100644
index 00000000000..994ac792e5d
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_language.cc
@@ -0,0 +1,151 @@
+// 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 "components/spellcheck/renderer/spellcheck_language.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "components/spellcheck/renderer/spellcheck_worditerator.h"
+#include "components/spellcheck/renderer/spelling_engine.h"
+
+
+SpellcheckLanguage::SpellcheckLanguage()
+ : platform_spelling_engine_(CreateNativeSpellingEngine()) {
+}
+
+SpellcheckLanguage::~SpellcheckLanguage() {
+}
+
+void SpellcheckLanguage::Init(base::File file, const std::string& language) {
+ DCHECK(platform_spelling_engine_.get());
+ platform_spelling_engine_->Init(std::move(file));
+
+ character_attributes_.SetDefaultLanguage(language);
+ text_iterator_.Reset();
+ contraction_iterator_.Reset();
+}
+
+bool SpellcheckLanguage::InitializeIfNeeded() {
+ DCHECK(platform_spelling_engine_.get());
+ return platform_spelling_engine_->InitializeIfNeeded();
+}
+
+SpellcheckLanguage::SpellcheckWordResult SpellcheckLanguage::SpellCheckWord(
+ const base::char16* text_begin,
+ int position_in_text,
+ int text_length,
+ int tag,
+ int* skip_or_misspelling_start,
+ int* skip_or_misspelling_len,
+ std::vector<base::string16>* optional_suggestions) {
+ int remaining_text_len = text_length - position_in_text;
+ DCHECK(remaining_text_len >= 0);
+ DCHECK(skip_or_misspelling_start && skip_or_misspelling_len)
+ << "Out vars must be given.";
+
+ // Do nothing if we need to delay initialization. (Rather than blocking,
+ // report the word as correctly spelled.)
+ if (InitializeIfNeeded())
+ return IS_CORRECT;
+
+ // Do nothing if spell checking is disabled.
+ if (!platform_spelling_engine_.get() ||
+ !platform_spelling_engine_->IsEnabled())
+ return IS_CORRECT;
+
+ *skip_or_misspelling_start = 0;
+ *skip_or_misspelling_len = 0;
+ if (remaining_text_len == 0)
+ return IS_CORRECT; // No input means always spelled correctly.
+
+ base::string16 word;
+ int word_start;
+ int word_length;
+ if (!text_iterator_.IsInitialized() &&
+ !text_iterator_.Initialize(&character_attributes_, true)) {
+ // We failed to initialize text_iterator_, return as spelled correctly.
+ VLOG(1) << "Failed to initialize SpellcheckWordIterator";
+ return IS_CORRECT;
+ }
+
+ text_iterator_.SetText(text_begin + position_in_text, remaining_text_len);
+ DCHECK(platform_spelling_engine_.get());
+ for (SpellcheckWordIterator::WordIteratorStatus status =
+ text_iterator_.GetNextWord(&word, &word_start, &word_length);
+ status != SpellcheckWordIterator::IS_END_OF_TEXT;
+ status = text_iterator_.GetNextWord(&word, &word_start, &word_length)) {
+ // Found a character that is not able to be spellchecked so determine how
+ // long the sequence of uncheckable characters is and then return.
+ if (status == SpellcheckWordIterator::IS_SKIPPABLE) {
+ *skip_or_misspelling_start = position_in_text + word_start;
+ while (status == SpellcheckWordIterator::IS_SKIPPABLE) {
+ *skip_or_misspelling_len += word_length;
+ status = text_iterator_.GetNextWord(&word, &word_start, &word_length);
+ }
+ return IS_SKIPPABLE;
+ }
+
+ // Found a word (or a contraction) that the spellchecker can check the
+ // spelling of.
+ if (platform_spelling_engine_->CheckSpelling(word, tag))
+ continue;
+
+ // If the given word is a concatenated word of two or more valid words
+ // (e.g. "hello:hello"), we should treat it as a valid word.
+ if (IsValidContraction(word, tag))
+ continue;
+
+ *skip_or_misspelling_start = position_in_text + word_start;
+ *skip_or_misspelling_len = word_length;
+
+ // Get the list of suggested words.
+ if (optional_suggestions) {
+ platform_spelling_engine_->FillSuggestionList(word,
+ optional_suggestions);
+ }
+ return IS_MISSPELLED;
+ }
+
+ return IS_CORRECT;
+}
+
+// Returns whether or not the given string is a valid contraction.
+// This function is a fall-back when the SpellcheckWordIterator class
+// returns a concatenated word which is not in the selected dictionary
+// (e.g. "in'n'out") but each word is valid.
+bool SpellcheckLanguage::IsValidContraction(const base::string16& contraction,
+ int tag) {
+ if (!contraction_iterator_.IsInitialized() &&
+ !contraction_iterator_.Initialize(&character_attributes_, false)) {
+ // We failed to initialize the word iterator, return as spelled correctly.
+ VLOG(1) << "Failed to initialize contraction_iterator_";
+ return true;
+ }
+
+ contraction_iterator_.SetText(contraction.c_str(), contraction.length());
+
+ base::string16 word;
+ int word_start;
+ int word_length;
+
+ DCHECK(platform_spelling_engine_.get());
+ for (SpellcheckWordIterator::WordIteratorStatus status =
+ contraction_iterator_.GetNextWord(&word, &word_start, &word_length);
+ status != SpellcheckWordIterator::IS_END_OF_TEXT;
+ status = contraction_iterator_.GetNextWord(&word, &word_start,
+ &word_length)) {
+ if (status == SpellcheckWordIterator::IS_SKIPPABLE)
+ continue;
+
+ if (!platform_spelling_engine_->CheckSpelling(word, tag))
+ return false;
+ }
+ return true;
+}
+
+bool SpellcheckLanguage::IsEnabled() {
+ DCHECK(platform_spelling_engine_.get());
+ return platform_spelling_engine_->IsEnabled();
+}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_language.h b/chromium/components/spellcheck/renderer/spellcheck_language.h
new file mode 100644
index 00000000000..0843a457839
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_language.h
@@ -0,0 +1,99 @@
+// 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 COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_LANGUAGE_H_
+#define COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_LANGUAGE_H_
+
+#include <memory>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/spellcheck/renderer/spellcheck_worditerator.h"
+
+class SpellingEngine;
+
+class SpellcheckLanguage {
+ public:
+ enum SpellcheckWordResult {
+ // Denotes that every recognized word is spelled correctly, from the point
+ // of spellchecking to the end of the text.
+ IS_CORRECT,
+ // A sequence of skippable characters, such as punctuation, spaces, or
+ // characters not recognized by the current spellchecking language.
+ IS_SKIPPABLE,
+ // A misspelled word has been found in the text.
+ IS_MISSPELLED
+ };
+
+ SpellcheckLanguage();
+ ~SpellcheckLanguage();
+
+ void Init(base::File file, const std::string& language);
+
+ // Spellcheck a sequence of text.
+ // |text_length| is the length of the text being spellchecked. The |tag|
+ // parameter should either be a unique identifier for the document that the
+ // word came from (if the current platform requires it), or 0.
+ //
+ // - Returns IS_CORRECT if every word from |position_in_text| to the end of
+ // the text is recognized and spelled correctly. Also, returns IS_CORRECT if
+ // the spellchecker failed to initialize.
+ //
+ // - Returns IS_SKIPPABLE if a sequence of skippable characters, such as
+ // punctuation, spaces, or unrecognized characters, is found.
+ // |skip_or_misspelling_start| and |skip_or_misspelling_len| are then set to
+ // the position and the length of the sequence of skippable characters.
+ //
+ // - Returns IS_MISSPELLED if a misspelled word is found.
+ // |skip_or_misspelling_start| and |skip_or_misspelling_len| are then set to
+ // the position and length of the misspelled word. In addition, finds the
+ // suggested words for a given misspelled word and puts them into
+ // |*optional_suggestions|. If optional_suggestions is NULL, suggested words
+ // will not be looked up. Note that doing suggest lookups can be slow.
+ SpellcheckWordResult SpellCheckWord(
+ const base::char16* text_begin,
+ int position_in_text,
+ int text_length,
+ int tag,
+ int* skip_or_misspelling_start,
+ int* skip_or_misspelling_len,
+ std::vector<base::string16>* optional_suggestions);
+
+ // Initialize |spellcheck_| if that hasn't happened yet.
+ bool InitializeIfNeeded();
+
+ // Return true if the underlying spellcheck engine is enabled.
+ bool IsEnabled();
+
+ private:
+ friend class SpellCheckTest;
+
+ // Returns whether or not the given word is a contraction of valid words
+ // (e.g. "word:word").
+ bool IsValidContraction(const base::string16& word, int tag);
+
+ // Represents character attributes used for filtering out characters which
+ // are not supported by this SpellCheck object.
+ SpellcheckCharAttribute character_attributes_;
+
+ // Represents word iterators used in this spellchecker. The |text_iterator_|
+ // splits text provided by WebKit into words, contractions, or concatenated
+ // words. The |contraction_iterator_| splits a concatenated word extracted by
+ // |text_iterator_| into word components so we can treat a concatenated word
+ // consisting only of correct words as a correct word.
+ SpellcheckWordIterator text_iterator_;
+ SpellcheckWordIterator contraction_iterator_;
+
+ // Pointer to a platform-specific spelling engine, if it is in use. This
+ // should only be set if hunspell is not used. (I.e. on OSX, for now)
+ std::unique_ptr<SpellingEngine> platform_spelling_engine_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellcheckLanguage);
+};
+
+#endif // COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_LANGUAGE_H_
diff --git a/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
new file mode 100644
index 00000000000..1eda2490d3e
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
@@ -0,0 +1,256 @@
+// 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 <stddef.h>
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "base/macros.h"
+#include "base/path_service.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "components/spellcheck/renderer/spellcheck.h"
+#include "components/spellcheck/renderer/spellcheck_provider_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
+
+namespace {
+
+struct SpellcheckTestCase {
+ // A string of text for checking.
+ const wchar_t* input;
+ // The position and the length of the first misspelled word, if any.
+ int expected_misspelling_start;
+ int expected_misspelling_length;
+};
+
+base::FilePath GetHunspellDirectory() {
+ base::FilePath hunspell_directory;
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &hunspell_directory))
+ return base::FilePath();
+
+ hunspell_directory = hunspell_directory.AppendASCII("third_party");
+ hunspell_directory = hunspell_directory.AppendASCII("hunspell_dictionaries");
+ return hunspell_directory;
+}
+
+} // namespace
+
+class MultilingualSpellCheckTest : public testing::Test {
+ public:
+ MultilingualSpellCheckTest() {}
+
+ void ReinitializeSpellCheck(const std::string& unsplit_languages) {
+ spellcheck_ = new SpellCheck();
+ provider_.reset(new TestingSpellCheckProvider(spellcheck_));
+ InitializeSpellCheck(unsplit_languages);
+ }
+
+ void InitializeSpellCheck(const std::string& unsplit_languages) {
+ base::FilePath hunspell_directory = GetHunspellDirectory();
+ EXPECT_FALSE(hunspell_directory.empty());
+ std::vector<std::string> languages = base::SplitString(
+ unsplit_languages, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ for (const auto& language : languages) {
+ base::File file(
+ spellcheck::GetVersionedFileName(language, hunspell_directory),
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+ spellcheck_->AddSpellcheckLanguage(std::move(file), language);
+ }
+ }
+
+ ~MultilingualSpellCheckTest() override {}
+ TestingSpellCheckProvider* provider() { return provider_.get(); }
+
+ protected:
+ void ExpectSpellCheckWordResults(const std::string& languages,
+ const SpellcheckTestCase* test_cases,
+ size_t num_test_cases) {
+ ReinitializeSpellCheck(languages);
+
+ for (size_t i = 0; i < num_test_cases; ++i) {
+ int misspelling_start = 0;
+ int misspelling_length = 0;
+ static_cast<blink::WebSpellCheckClient*>(provider())
+ ->spellCheck(blink::WebString(base::WideToUTF16(test_cases[i].input)),
+ misspelling_start, misspelling_length, nullptr);
+
+ EXPECT_EQ(test_cases[i].expected_misspelling_start, misspelling_start)
+ << "Improper misspelling location found with the languages "
+ << languages << " when checking \"" << test_cases[i].input << "\".";
+ EXPECT_EQ(test_cases[i].expected_misspelling_length, misspelling_length)
+ << "Improper misspelling length found with the languages "
+ << languages << " when checking \"" << test_cases[i].input << "\".";
+ }
+ }
+
+ void ExpectSpellCheckParagraphResults(
+ const base::string16& input,
+ const std::vector<SpellCheckResult>& expected) {
+ blink::WebVector<blink::WebTextCheckingResult> results;
+ spellcheck_->SpellCheckParagraph(blink::WebString(input), &results);
+
+ EXPECT_EQ(expected.size(), results.size());
+ size_t size = std::min(results.size(), expected.size());
+ for (size_t i = 0; i < size; ++i) {
+ EXPECT_EQ(blink::WebTextDecorationTypeSpelling, results[i].decoration);
+ EXPECT_EQ(expected[i].location, results[i].location);
+ EXPECT_EQ(expected[i].length, results[i].length);
+ }
+ }
+
+ private:
+ // Owned by |provider_|.
+ SpellCheck* spellcheck_;
+ std::unique_ptr<TestingSpellCheckProvider> provider_;
+};
+
+// Check that a string of different words is properly spellchecked for different
+// combinations of different languages.
+TEST_F(MultilingualSpellCheckTest, MultilingualSpellCheckWord) {
+ static const SpellcheckTestCase kTestCases[] = {
+ // An English, Spanish, Russian, and Greek word, all spelled correctly.
+ {L"rocket destruyan \x0432\x0441\x0435\x0445 \x03C4\x03B9\x03C2", 0, 0},
+ // A misspelled English word.
+ {L"rocktt destruyan \x0432\x0441\x0435\x0445 \x03C4\x03B9\x03C2", 0, 6},
+ // A misspelled Spanish word.
+ {L"rocket destruynn \x0432\x0441\x0435\x0445 \x03C4\x03B9\x03C2", 7, 9},
+ // A misspelled Russian word.
+ {L"rocket destruyan \x0430\x0430\x0430\x0430 \x03C4\x03B9\x03C2", 17, 4},
+ // A misspelled Greek word.
+ {L"rocket destruyan \x0432\x0441\x0435\x0445 \x03B1\x03B1\x03B1\x03B1",
+ 22, 4},
+ // An English word, then Russian, and then a misspelled English word.
+ {L"rocket \x0432\x0441\x0435\x0445 rocktt", 12, 6},
+ };
+
+ // A sorted list of languages. This must start sorted to get all possible
+ // permutations.
+ std::string languages = "el-GR,en-US,es-ES,ru-RU";
+ std::vector<std::string> permuted_languages = base::SplitString(
+ languages, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ do {
+ languages = base::JoinString(permuted_languages, ",");
+ ExpectSpellCheckWordResults(languages, kTestCases, arraysize(kTestCases));
+ } while (std::next_permutation(permuted_languages.begin(),
+ permuted_languages.end()));
+}
+
+TEST_F(MultilingualSpellCheckTest, MultilingualSpellCheckWordEnglishSpanish) {
+ static const SpellcheckTestCase kTestCases[] = {
+ {L"", 0, 0},
+ {L"head hand foot legs arms", 0, 0},
+ {L"head hand foot legs arms zzzz", 25, 4},
+ {L"head hand zzzz foot legs arms", 10, 4},
+ {L"zzzz head hand foot legs arms", 0, 4},
+ {L"zzzz head zzzz foot zzzz arms", 0, 4},
+ {L"head hand foot arms zzzz zzzz", 20, 4},
+ {L"I do not want a monstrous snake near me.", 0, 0},
+ {L"zz do not want a monstrous snake near me.", 0, 2},
+ {L"I do not want zz monstrous snake near me.", 14, 2},
+ {L"I do not want a monstrous zz near me.", 26, 2},
+ {L"I do not want a monstrou snake near me.", 16, 8},
+ {L"I do not want a monstrous snake near zz.", 37, 2},
+ {L"Partially Spanish is very bueno.", 0, 0},
+ {L"Sleeping in the biblioteca is good.", 0, 0},
+ {L"Hermano is my favorite name.", 0, 0},
+ {L"hola hola hola hola hola hola", 0, 0},
+ {L"sand hola hola hola hola hola", 0, 0},
+ {L"hola sand sand sand sand sand", 0, 0},
+ {L"sand sand sand sand sand hola", 0, 0},
+ {L"sand hola sand hola sand hola", 0, 0},
+ {L"hola sand hola sand hola sand", 0, 0},
+ {L"hola:legs", 0, 9},
+ {L"legs:hola", 0, 9}};
+ ExpectSpellCheckWordResults("en-US,es-ES", kTestCases, arraysize(kTestCases));
+}
+
+// If there are no spellcheck languages, no text should be marked as misspelled.
+TEST_F(MultilingualSpellCheckTest, MultilingualSpellCheckParagraphBlank) {
+ ReinitializeSpellCheck(std::string());
+
+ ExpectSpellCheckParagraphResults(
+ // English, German, Spanish, and a misspelled word.
+ base::UTF8ToUTF16("rocket Schwarzkommando destruyan pcnyhon"),
+ std::vector<SpellCheckResult>());
+}
+
+// Make sure nothing is considered misspelled when at least one of the selected
+// languages determines that a word is correctly spelled.
+TEST_F(MultilingualSpellCheckTest, MultilingualSpellCheckParagraphCorrect) {
+ ReinitializeSpellCheck("en-US,es-ES,de-DE");
+
+ ExpectSpellCheckParagraphResults(
+ // English, German, and Spanish words, all spelled correctly.
+ base::UTF8ToUTF16("rocket Schwarzkommando destruyan"),
+ std::vector<SpellCheckResult>());
+}
+
+// Make sure that all the misspellings in the text are found.
+TEST_F(MultilingualSpellCheckTest, MultilingualSpellCheckParagraph) {
+ ReinitializeSpellCheck("en-US,es-ES");
+ std::vector<SpellCheckResult> expected;
+ expected.push_back(SpellCheckResult(SpellCheckResult::SPELLING, 7, 15));
+ expected.push_back(SpellCheckResult(SpellCheckResult::SPELLING, 33, 7));
+
+ ExpectSpellCheckParagraphResults(
+ // English, German, Spanish, and a misspelled word.
+ base::UTF8ToUTF16("rocket Schwarzkommando destruyan pcnyhon"), expected);
+}
+
+// Ensure that suggestions are handled properly for multiple languages.
+TEST_F(MultilingualSpellCheckTest, MultilingualSpellCheckSuggestions) {
+ ReinitializeSpellCheck("en-US,es-ES");
+ static const struct {
+ // A string of text for checking.
+ const wchar_t* input;
+ // The position and the length of the first invalid word.
+ int expected_misspelling_start;
+ int expected_misspelling_length;
+ // A comma separated string of suggested words that should occur, in their
+ // expected order.
+ const wchar_t* expected_suggestions;
+ } kTestCases[] = {
+ {L"rocket", 0, 0},
+ {L"destruyan", 0, 0},
+ {L"rocet", 0, 5, L"rocket,roce,crochet,troce,rocen"},
+ {L"jum", 0, 3, L"hum,jun,ju,um,juma"},
+ {L"asdne", 0, 5, L"sadness,desasne"},
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ blink::WebVector<blink::WebString> suggestions;
+ int misspelling_start;
+ int misspelling_length;
+ static_cast<blink::WebSpellCheckClient*>(provider())
+ ->spellCheck(blink::WebString(base::WideToUTF16(kTestCases[i].input)),
+ misspelling_start, misspelling_length, &suggestions);
+
+ EXPECT_EQ(kTestCases[i].expected_misspelling_start, misspelling_start);
+ EXPECT_EQ(kTestCases[i].expected_misspelling_length, misspelling_length);
+ if (!kTestCases[i].expected_suggestions) {
+ EXPECT_EQ(0UL, suggestions.size());
+ continue;
+ }
+
+ std::vector<base::string16> expected_suggestions = base::SplitString(
+ base::WideToUTF16(kTestCases[i].expected_suggestions),
+ base::string16(1, ','), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ EXPECT_EQ(expected_suggestions.size(), suggestions.size());
+ for (size_t j = 0;
+ j < std::min(expected_suggestions.size(), suggestions.size()); j++) {
+ EXPECT_EQ(expected_suggestions[j], base::string16(suggestions[j]));
+ }
+ }
+}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.cc b/chromium/components/spellcheck/renderer/spellcheck_provider.cc
new file mode 100644
index 00000000000..f52fe596705
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.cc
@@ -0,0 +1,350 @@
+// 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 "components/spellcheck/renderer/spellcheck_provider.h"
+
+#include "base/command_line.h"
+#include "base/metrics/histogram_macros.h"
+#include "components/spellcheck/common/spellcheck_marker.h"
+#include "components/spellcheck/common/spellcheck_messages.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "components/spellcheck/renderer/spellcheck.h"
+#include "components/spellcheck/renderer/spellcheck_language.h"
+#include "content/public/renderer/render_view.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h"
+#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
+#include "third_party/WebKit/public/web/WebTextDecorationType.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+using blink::WebElement;
+using blink::WebLocalFrame;
+using blink::WebString;
+using blink::WebTextCheckingCompletion;
+using blink::WebTextCheckingResult;
+using blink::WebTextDecorationType;
+using blink::WebVector;
+
+static_assert(int(blink::WebTextDecorationTypeSpelling) ==
+ int(SpellCheckResult::SPELLING), "mismatching enums");
+static_assert(int(blink::WebTextDecorationTypeGrammar) ==
+ int(SpellCheckResult::GRAMMAR), "mismatching enums");
+static_assert(int(blink::WebTextDecorationTypeInvisibleSpellcheck) ==
+ int(SpellCheckResult::INVISIBLE), "mismatching enums");
+
+SpellCheckProvider::SpellCheckProvider(
+ content::RenderView* render_view,
+ SpellCheck* spellcheck)
+ : content::RenderViewObserver(render_view),
+ content::RenderViewObserverTracker<SpellCheckProvider>(render_view),
+ spelling_panel_visible_(false),
+ spellcheck_(spellcheck) {
+ DCHECK(spellcheck_);
+ if (render_view) { // NULL in unit tests.
+ render_view->GetWebView()->setSpellCheckClient(this);
+ EnableSpellcheck(spellcheck_->IsSpellcheckEnabled());
+ }
+}
+
+SpellCheckProvider::~SpellCheckProvider() {
+}
+
+void SpellCheckProvider::RequestTextChecking(
+ const base::string16& text,
+ WebTextCheckingCompletion* completion,
+ const std::vector<SpellCheckMarker>& markers) {
+ // Ignore invalid requests.
+ if (text.empty() || !HasWordCharacters(text, 0)) {
+ completion->didCancelCheckingText();
+ return;
+ }
+
+ // Try to satisfy check from cache.
+ if (SatisfyRequestFromCache(text, completion))
+ return;
+
+ // Send this text to a browser. A browser checks the user profile and send
+ // this text to the Spelling service only if a user enables this feature.
+ last_request_.clear();
+ last_results_.assign(blink::WebVector<blink::WebTextCheckingResult>());
+
+#if defined(USE_BROWSER_SPELLCHECKER)
+ // Text check (unified request for grammar and spell check) is only
+ // available for browser process, so we ask the system spellchecker
+ // over IPC or return an empty result if the checker is not
+ // available.
+ Send(new SpellCheckHostMsg_RequestTextCheck(
+ routing_id(),
+ text_check_completions_.Add(completion),
+ text,
+ markers));
+#else
+ Send(new SpellCheckHostMsg_CallSpellingService(
+ routing_id(),
+ text_check_completions_.Add(completion),
+ base::string16(text),
+ markers));
+#endif // !USE_BROWSER_SPELLCHECKER
+}
+
+bool SpellCheckProvider::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(SpellCheckProvider, message)
+#if !defined(USE_BROWSER_SPELLCHECKER)
+ IPC_MESSAGE_HANDLER(SpellCheckMsg_RespondSpellingService,
+ OnRespondSpellingService)
+#endif
+#if defined(USE_BROWSER_SPELLCHECKER)
+ IPC_MESSAGE_HANDLER(SpellCheckMsg_AdvanceToNextMisspelling,
+ OnAdvanceToNextMisspelling)
+ IPC_MESSAGE_HANDLER(SpellCheckMsg_RespondTextCheck, OnRespondTextCheck)
+ IPC_MESSAGE_HANDLER(SpellCheckMsg_ToggleSpellPanel, OnToggleSpellPanel)
+#endif
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void SpellCheckProvider::FocusedNodeChanged(const blink::WebNode& unused) {
+#if defined(USE_BROWSER_SPELLCHECKER)
+ WebLocalFrame* frame = render_view()->GetWebView()->focusedFrame();
+ WebElement element = frame->document().isNull() ? WebElement() :
+ frame->document().focusedElement();
+ bool enabled = !element.isNull() && element.isEditable();
+ bool checked = enabled && frame->isSpellCheckingEnabled();
+
+ Send(new SpellCheckHostMsg_ToggleSpellCheck(routing_id(), enabled, checked));
+#endif // USE_BROWSER_SPELLCHECKER
+}
+
+void SpellCheckProvider::spellCheck(
+ const WebString& text,
+ int& offset,
+ int& length,
+ WebVector<WebString>* optional_suggestions) {
+ base::string16 word(text);
+ std::vector<base::string16> suggestions;
+ const int kWordStart = 0;
+ spellcheck_->SpellCheckWord(
+ word.c_str(), kWordStart, word.size(), routing_id(),
+ &offset, &length, optional_suggestions ? & suggestions : NULL);
+ if (optional_suggestions) {
+ *optional_suggestions = suggestions;
+ UMA_HISTOGRAM_COUNTS("SpellCheck.api.check.suggestions", word.size());
+ } else {
+ UMA_HISTOGRAM_COUNTS("SpellCheck.api.check", word.size());
+ // If optional_suggestions is not requested, the API is called
+ // for marking. So we use this for counting markable words.
+ Send(new SpellCheckHostMsg_NotifyChecked(routing_id(), word, 0 < length));
+ }
+}
+
+void SpellCheckProvider::requestCheckingOfText(
+ const WebString& text,
+ const WebVector<uint32_t>& markers,
+ const WebVector<unsigned>& marker_offsets,
+ WebTextCheckingCompletion* completion) {
+ std::vector<SpellCheckMarker> spellcheck_markers;
+ for (size_t i = 0; i < markers.size(); ++i) {
+ spellcheck_markers.push_back(
+ SpellCheckMarker(markers[i], marker_offsets[i]));
+ }
+ RequestTextChecking(text, completion, spellcheck_markers);
+ UMA_HISTOGRAM_COUNTS("SpellCheck.api.async", text.length());
+}
+
+void SpellCheckProvider::cancelAllPendingRequests() {
+ for (WebTextCheckCompletions::iterator iter(&text_check_completions_);
+ !iter.IsAtEnd(); iter.Advance()) {
+ iter.GetCurrentValue()->didCancelCheckingText();
+ }
+ text_check_completions_.Clear();
+}
+
+void SpellCheckProvider::showSpellingUI(bool show) {
+#if defined(USE_BROWSER_SPELLCHECKER)
+ UMA_HISTOGRAM_BOOLEAN("SpellCheck.api.showUI", show);
+ Send(new SpellCheckHostMsg_ShowSpellingPanel(routing_id(), show));
+#endif
+}
+
+bool SpellCheckProvider::isShowingSpellingUI() {
+ return spelling_panel_visible_;
+}
+
+void SpellCheckProvider::updateSpellingUIWithMisspelledWord(
+ const WebString& word) {
+#if defined(USE_BROWSER_SPELLCHECKER)
+ Send(new SpellCheckHostMsg_UpdateSpellingPanelWithMisspelledWord(routing_id(),
+ word));
+#endif
+}
+
+#if !defined(USE_BROWSER_SPELLCHECKER)
+void SpellCheckProvider::OnRespondSpellingService(
+ int identifier,
+ bool succeeded,
+ const base::string16& line,
+ const std::vector<SpellCheckResult>& results) {
+ WebTextCheckingCompletion* completion =
+ text_check_completions_.Lookup(identifier);
+ if (!completion)
+ return;
+ text_check_completions_.Remove(identifier);
+
+ // If |succeeded| is false, we use local spellcheck as a fallback.
+ if (!succeeded) {
+ spellcheck_->RequestTextChecking(line, completion);
+ return;
+ }
+
+ // Double-check the returned spellchecking results with our spellchecker to
+ // visualize the differences between ours and the on-line spellchecker.
+ blink::WebVector<blink::WebTextCheckingResult> textcheck_results;
+ spellcheck_->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER,
+ 0,
+ line,
+ results,
+ &textcheck_results);
+ completion->didFinishCheckingText(textcheck_results);
+
+ // Cache the request and the converted results.
+ last_request_ = line;
+ last_results_.swap(textcheck_results);
+}
+#endif
+
+bool SpellCheckProvider::HasWordCharacters(
+ const base::string16& text,
+ int index) const {
+ const base::char16* data = text.data();
+ int length = text.length();
+ while (index < length) {
+ uint32_t code = 0;
+ U16_NEXT(data, index, length, code);
+ UErrorCode error = U_ZERO_ERROR;
+ if (uscript_getScript(code, &error) != USCRIPT_COMMON)
+ return true;
+ }
+ return false;
+}
+
+#if defined(USE_BROWSER_SPELLCHECKER)
+void SpellCheckProvider::OnAdvanceToNextMisspelling() {
+ if (!render_view()->GetWebView())
+ return;
+ render_view()->GetWebView()->focusedFrame()->executeCommand(
+ WebString::fromUTF8("AdvanceToNextMisspelling"));
+}
+
+void SpellCheckProvider::OnRespondTextCheck(
+ int identifier,
+ const base::string16& line,
+ const std::vector<SpellCheckResult>& results) {
+ // TODO(groby): Unify with SpellCheckProvider::OnRespondSpellingService
+ DCHECK(spellcheck_);
+ WebTextCheckingCompletion* completion =
+ text_check_completions_.Lookup(identifier);
+ if (!completion)
+ return;
+ text_check_completions_.Remove(identifier);
+ blink::WebVector<blink::WebTextCheckingResult> textcheck_results;
+ spellcheck_->CreateTextCheckingResults(SpellCheck::DO_NOT_MODIFY,
+ 0,
+ line,
+ results,
+ &textcheck_results);
+ completion->didFinishCheckingText(textcheck_results);
+
+ // Cache the request and the converted results.
+ last_request_ = line;
+ last_results_.swap(textcheck_results);
+}
+
+void SpellCheckProvider::OnToggleSpellPanel(bool is_currently_visible) {
+ if (!render_view()->GetWebView())
+ return;
+ // We need to tell the webView whether the spelling panel is visible or not so
+ // that it won't need to make ipc calls later.
+ spelling_panel_visible_ = is_currently_visible;
+ render_view()->GetWebView()->focusedFrame()->executeCommand(
+ WebString::fromUTF8("ToggleSpellPanel"));
+}
+#endif
+
+void SpellCheckProvider::EnableSpellcheck(bool enable) {
+ if (!render_view()->GetWebView())
+ return;
+
+ WebLocalFrame* frame = render_view()->GetWebView()->focusedFrame();
+ // TODO(yabinh): The null check should be unnecessary.
+ // See crbug.com/625068
+ if (!frame)
+ return;
+
+ frame->enableSpellChecking(enable);
+ if (!enable)
+ frame->removeSpellingMarkers();
+}
+
+bool SpellCheckProvider::SatisfyRequestFromCache(
+ const base::string16& text,
+ WebTextCheckingCompletion* completion) {
+ size_t last_length = last_request_.length();
+
+ // Send back the |last_results_| if the |last_request_| is a substring of
+ // |text| and |text| does not have more words to check. Provider cannot cancel
+ // the spellcheck request here, because WebKit might have discarded the
+ // previous spellcheck results and erased the spelling markers in response to
+ // the user editing the text.
+ base::string16 request(text);
+ size_t text_length = request.length();
+ if (text_length >= last_length &&
+ !request.compare(0, last_length, last_request_)) {
+ if (text_length == last_length || !HasWordCharacters(text, last_length)) {
+ completion->didFinishCheckingText(last_results_);
+ return true;
+ }
+ int code = 0;
+ int length = static_cast<int>(text_length);
+ U16_PREV(text.data(), 0, length, code);
+ UErrorCode error = U_ZERO_ERROR;
+ if (uscript_getScript(code, &error) != USCRIPT_COMMON) {
+ completion->didCancelCheckingText();
+ return true;
+ }
+ }
+ // Create a subset of the cached results and return it if the given text is a
+ // substring of the cached text.
+ if (text_length < last_length &&
+ !last_request_.compare(0, text_length, request)) {
+ size_t result_size = 0;
+ for (size_t i = 0; i < last_results_.size(); ++i) {
+ size_t start = last_results_[i].location;
+ size_t end = start + last_results_[i].length;
+ if (start <= text_length && end <= text_length)
+ ++result_size;
+ }
+ if (result_size > 0) {
+ blink::WebVector<blink::WebTextCheckingResult> results(result_size);
+ for (size_t i = 0; i < result_size; ++i) {
+ results[i].decoration = last_results_[i].decoration;
+ results[i].location = last_results_[i].location;
+ results[i].length = last_results_[i].length;
+ results[i].replacement = last_results_[i].replacement;
+ }
+ completion->didFinishCheckingText(results);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void SpellCheckProvider::OnDestruct() {
+ delete this;
+}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.h b/chromium/components/spellcheck/renderer/spellcheck_provider.h
new file mode 100644
index 00000000000..46e160624ed
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.h
@@ -0,0 +1,134 @@
+// 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 COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_PROVIDER_H_
+#define COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_PROVIDER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/id_map.h"
+#include "base/macros.h"
+#include "content/public/renderer/render_view_observer.h"
+#include "content/public/renderer/render_view_observer_tracker.h"
+#include "third_party/WebKit/public/web/WebSpellCheckClient.h"
+
+class RenderView;
+class SpellCheck;
+class SpellCheckMarker;
+struct SpellCheckResult;
+
+namespace blink {
+class WebString;
+class WebTextCheckingCompletion;
+struct WebTextCheckingResult;
+}
+
+// This class deals with invoking browser-side spellcheck mechanism
+// which is done asynchronously.
+class SpellCheckProvider
+ : public content::RenderViewObserver,
+ public content::RenderViewObserverTracker<SpellCheckProvider>,
+ public blink::WebSpellCheckClient {
+ public:
+ typedef IDMap<blink::WebTextCheckingCompletion> WebTextCheckCompletions;
+
+ SpellCheckProvider(content::RenderView* render_view,
+ SpellCheck* spellcheck);
+ ~SpellCheckProvider() override;
+
+ // Requests async spell and grammar checker to the platform text
+ // checker, which is available on the browser process.
+ void RequestTextChecking(
+ const base::string16& text,
+ blink::WebTextCheckingCompletion* completion,
+ const std::vector<SpellCheckMarker>& markers);
+
+ // The number of ongoing IPC requests.
+ size_t pending_text_request_size() const {
+ return text_check_completions_.size();
+ }
+
+ // Replace shared spellcheck data.
+ void set_spellcheck(SpellCheck* spellcheck) { spellcheck_ = spellcheck; }
+
+ // Enables document-wide spellchecking.
+ void EnableSpellcheck(bool enabled);
+
+ // RenderViewObserver implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void FocusedNodeChanged(const blink::WebNode& node) override;
+
+ private:
+ friend class TestingSpellCheckProvider;
+
+ // Tries to satisfy a spell check request from the cache in |last_request_|.
+ // Returns true (and cancels/finishes the completion) if it can, false
+ // if the provider should forward the query on.
+ bool SatisfyRequestFromCache(const base::string16& text,
+ blink::WebTextCheckingCompletion* completion);
+
+ // RenderViewObserver implementation.
+ void OnDestruct() override;
+
+ // blink::WebSpellCheckClient implementation.
+ void spellCheck(
+ const blink::WebString& text,
+ int& offset,
+ int& length,
+ blink::WebVector<blink::WebString>* optional_suggestions) override;
+
+ void requestCheckingOfText(
+ const blink::WebString& text,
+ const blink::WebVector<uint32_t>& markers,
+ const blink::WebVector<unsigned>& marker_offsets,
+ blink::WebTextCheckingCompletion* completion) override;
+
+ void cancelAllPendingRequests() override;
+ void showSpellingUI(bool show) override;
+ bool isShowingSpellingUI() override;
+ void updateSpellingUIWithMisspelledWord(
+ const blink::WebString& word) override;
+
+#if !defined(USE_BROWSER_SPELLCHECKER)
+ void OnRespondSpellingService(
+ int identifier,
+ bool succeeded,
+ const base::string16& text,
+ const std::vector<SpellCheckResult>& results);
+#endif
+
+ // Returns whether |text| has word characters, i.e. whether a spellchecker
+ // needs to check this text.
+ bool HasWordCharacters(const base::string16& text, int index) const;
+
+#if defined(USE_BROWSER_SPELLCHECKER)
+ void OnAdvanceToNextMisspelling();
+ void OnRespondTextCheck(
+ int identifier,
+ const base::string16& line,
+ const std::vector<SpellCheckResult>& results);
+ void OnToggleSpellPanel(bool is_currently_visible);
+#endif
+
+ // Holds ongoing spellchecking operations, assigns IDs for the IPC routing.
+ WebTextCheckCompletions text_check_completions_;
+
+ // The last text sent to the browser process to spellcheck it and its
+ // spellchecking results.
+ base::string16 last_request_;
+ blink::WebVector<blink::WebTextCheckingResult> last_results_;
+
+ // True if the browser is showing the spelling panel for us.
+ bool spelling_panel_visible_;
+
+ // Weak pointer to shared (per RenderView) spellcheck data.
+ SpellCheck* spellcheck_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellCheckProvider);
+};
+
+#endif // COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_PROVIDER_H_
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc
new file mode 100644
index 00000000000..84022a0624e
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc
@@ -0,0 +1,183 @@
+// 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 <vector>
+
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/spellcheck/common/spellcheck_marker.h"
+#include "components/spellcheck/renderer/spellcheck_provider_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+// Tests for Hunspell functionality in SpellcheckingProvider
+
+using base::ASCIIToUTF16;
+using base::WideToUTF16;
+
+namespace {
+
+TEST_F(SpellCheckProviderTest, UsingHunspell) {
+ FakeTextCheckingCompletion completion;
+ provider_.RequestTextChecking(blink::WebString("hello"),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(completion.completion_count_, 1U);
+ EXPECT_EQ(provider_.messages_.size(), 0U);
+ EXPECT_EQ(provider_.pending_text_request_size(), 0U);
+}
+
+// Tests that the SpellCheckProvider object sends a spellcheck request when a
+// user finishes typing a word. Also this test verifies that this object checks
+// only a line being edited by the user.
+TEST_F(SpellCheckProviderTest, MultiLineText) {
+ FakeTextCheckingCompletion completion;
+
+ // Verify that the SpellCheckProvider class does not spellcheck empty text.
+ provider_.ResetResult();
+ provider_.RequestTextChecking(
+ blink::WebString(), &completion, std::vector<SpellCheckMarker>());
+ EXPECT_TRUE(provider_.text_.empty());
+
+ // Verify that the SpellCheckProvider class does not spellcheck text while we
+ // are typing a word.
+ provider_.ResetResult();
+ provider_.RequestTextChecking(
+ blink::WebString("First"), &completion, std::vector<SpellCheckMarker>());
+ EXPECT_TRUE(provider_.text_.empty());
+
+ // Verify that the SpellCheckProvider class spellcheck the first word when we
+ // type a space key, i.e. when we finish typing a word.
+ provider_.ResetResult();
+ provider_.RequestTextChecking(blink::WebString("First "),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(ASCIIToUTF16("First "), provider_.text_);
+
+ // Verify that the SpellCheckProvider class spellcheck the first line when we
+ // type a return key, i.e. when we finish typing a line.
+ provider_.ResetResult();
+ provider_.RequestTextChecking(blink::WebString("First Second\n"),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(ASCIIToUTF16("First Second\n"), provider_.text_);
+
+ // Verify that the SpellCheckProvider class spellcheck the lines when we
+ // finish typing a word "Third" to the second line.
+ provider_.ResetResult();
+ provider_.RequestTextChecking(blink::WebString("First Second\nThird "),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(ASCIIToUTF16("First Second\nThird "), provider_.text_);
+
+ // Verify that the SpellCheckProvider class does not send a spellcheck request
+ // when a user inserts whitespace characters.
+ provider_.ResetResult();
+ provider_.RequestTextChecking(blink::WebString("First Second\nThird "),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_TRUE(provider_.text_.empty());
+
+ // Verify that the SpellCheckProvider class spellcheck the lines when we type
+ // a period.
+ provider_.ResetResult();
+ provider_.RequestTextChecking(
+ blink::WebString("First Second\nThird Fourth."),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(ASCIIToUTF16("First Second\nThird Fourth."), provider_.text_);
+}
+
+// Tests that the SpellCheckProvider class does not send requests to the
+// spelling service when not necessary.
+TEST_F(SpellCheckProviderTest, CancelUnnecessaryRequests) {
+ FakeTextCheckingCompletion completion;
+ provider_.RequestTextChecking(blink::WebString("hello."),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(completion.completion_count_, 1U);
+ EXPECT_EQ(completion.cancellation_count_, 0U);
+ EXPECT_EQ(provider_.spelling_service_call_count_, 1U);
+
+ // Test that the SpellCheckProvider does not send a request with the same text
+ // as above.
+ provider_.RequestTextChecking(blink::WebString("hello."),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(completion.completion_count_, 2U);
+ EXPECT_EQ(completion.cancellation_count_, 0U);
+ EXPECT_EQ(provider_.spelling_service_call_count_, 1U);
+
+ // Test that the SpellCheckProvider class cancels an incoming request that
+ // does not include any words.
+ provider_.RequestTextChecking(blink::WebString(":-)"),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(completion.completion_count_, 3U);
+ EXPECT_EQ(completion.cancellation_count_, 1U);
+ EXPECT_EQ(provider_.spelling_service_call_count_, 1U);
+
+ // Test that the SpellCheckProvider class sends a request when it receives a
+ // Russian word.
+ const wchar_t kRussianWord[] = L"\x0431\x0451\x0434\x0440\x0430";
+ provider_.RequestTextChecking(blink::WebString(WideToUTF16(kRussianWord)),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(completion.completion_count_, 4U);
+ EXPECT_EQ(completion.cancellation_count_, 1U);
+ EXPECT_EQ(provider_.spelling_service_call_count_, 2U);
+}
+
+// Tests that the SpellCheckProvider calls didFinishCheckingText() when
+// necessary.
+TEST_F(SpellCheckProviderTest, CompleteNecessaryRequests) {
+ FakeTextCheckingCompletion completion;
+
+ base::string16 text = ASCIIToUTF16("Icland is an icland ");
+ provider_.RequestTextChecking(
+ blink::WebString(text), &completion, std::vector<SpellCheckMarker>());
+ EXPECT_EQ(0U, completion.cancellation_count_) << "Should finish checking \""
+ << text << "\"";
+
+ const int kSubstringLength = 18;
+ base::string16 substring = text.substr(0, kSubstringLength);
+ provider_.RequestTextChecking(blink::WebString(substring),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(0U, completion.cancellation_count_) << "Should finish checking \""
+ << substring << "\"";
+
+ provider_.RequestTextChecking(
+ blink::WebString(text), &completion, std::vector<SpellCheckMarker>());
+ EXPECT_EQ(0U, completion.cancellation_count_) << "Should finish checking \""
+ << text << "\"";
+}
+
+// Tests that the SpellCheckProvider cancels spelling requests in the middle of
+// a word.
+TEST_F(SpellCheckProviderTest, CancelMidWordRequests) {
+ FakeTextCheckingCompletion completion;
+ provider_.RequestTextChecking(blink::WebString("hello "),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(completion.completion_count_, 1U);
+ EXPECT_EQ(completion.cancellation_count_, 0U);
+ EXPECT_EQ(provider_.spelling_service_call_count_, 1U);
+
+ provider_.RequestTextChecking(blink::WebString("hello world"),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(completion.completion_count_, 2U);
+ EXPECT_EQ(completion.cancellation_count_, 1U);
+ EXPECT_EQ(provider_.spelling_service_call_count_, 1U);
+
+ provider_.RequestTextChecking(blink::WebString("hello world."),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(completion.completion_count_, 3U);
+ EXPECT_EQ(completion.cancellation_count_, 1U);
+ EXPECT_EQ(provider_.spelling_service_call_count_, 2U);
+}
+
+} // namespace
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_mac_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_mac_unittest.cc
new file mode 100644
index 00000000000..1440313d4ef
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_mac_unittest.cc
@@ -0,0 +1,92 @@
+// 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 <tuple>
+#include <vector>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/spellcheck/common/spellcheck_marker.h"
+#include "components/spellcheck/common/spellcheck_messages.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "components/spellcheck/renderer/spellcheck_provider_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+namespace {
+
+class SpellCheckProviderMacTest : public SpellCheckProviderTest {};
+
+void FakeMessageArrival(
+ SpellCheckProvider* provider,
+ const SpellCheckHostMsg_RequestTextCheck::Param& parameters) {
+ std::vector<SpellCheckResult> fake_result;
+ bool handled = provider->OnMessageReceived(
+ SpellCheckMsg_RespondTextCheck(
+ 0,
+ std::get<1>(parameters),
+ base::ASCIIToUTF16("test"),
+ fake_result));
+ EXPECT_TRUE(handled);
+}
+
+TEST_F(SpellCheckProviderMacTest, SingleRoundtripSuccess) {
+ FakeTextCheckingCompletion completion;
+
+ provider_.RequestTextChecking(blink::WebString("hello "),
+ &completion,
+ std::vector<SpellCheckMarker>());
+ EXPECT_EQ(completion.completion_count_, 0U);
+ EXPECT_EQ(provider_.messages_.size(), 1U);
+ EXPECT_EQ(provider_.pending_text_request_size(), 1U);
+
+ SpellCheckHostMsg_RequestTextCheck::Param read_parameters1;
+ bool ok = SpellCheckHostMsg_RequestTextCheck::Read(
+ provider_.messages_[0], &read_parameters1);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(std::get<2>(read_parameters1), base::UTF8ToUTF16("hello "));
+
+ FakeMessageArrival(&provider_, read_parameters1);
+ EXPECT_EQ(completion.completion_count_, 1U);
+ EXPECT_EQ(provider_.pending_text_request_size(), 0U);
+}
+
+TEST_F(SpellCheckProviderMacTest, TwoRoundtripSuccess) {
+ FakeTextCheckingCompletion completion1;
+ provider_.RequestTextChecking(blink::WebString("hello "),
+ &completion1,
+ std::vector<SpellCheckMarker>());
+ FakeTextCheckingCompletion completion2;
+ provider_.RequestTextChecking(blink::WebString("bye "),
+ &completion2,
+ std::vector<SpellCheckMarker>());
+
+ EXPECT_EQ(completion1.completion_count_, 0U);
+ EXPECT_EQ(completion2.completion_count_, 0U);
+ EXPECT_EQ(provider_.messages_.size(), 2U);
+ EXPECT_EQ(provider_.pending_text_request_size(), 2U);
+
+ SpellCheckHostMsg_RequestTextCheck::Param read_parameters1;
+ bool ok = SpellCheckHostMsg_RequestTextCheck::Read(
+ provider_.messages_[0], &read_parameters1);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(std::get<2>(read_parameters1), base::UTF8ToUTF16("hello "));
+
+ SpellCheckHostMsg_RequestTextCheck::Param read_parameters2;
+ ok = SpellCheckHostMsg_RequestTextCheck::Read(
+ provider_.messages_[1], &read_parameters2);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(std::get<2>(read_parameters2), base::UTF8ToUTF16("bye "));
+
+ FakeMessageArrival(&provider_, read_parameters1);
+ EXPECT_EQ(completion1.completion_count_, 1U);
+ EXPECT_EQ(completion2.completion_count_, 0U);
+ EXPECT_EQ(provider_.pending_text_request_size(), 1U);
+
+ FakeMessageArrival(&provider_, read_parameters2);
+ EXPECT_EQ(completion1.completion_count_, 1U);
+ EXPECT_EQ(completion2.completion_count_, 1U);
+ EXPECT_EQ(provider_.pending_text_request_size(), 0U);
+}
+
+} // namespace
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
new file mode 100644
index 00000000000..71a6c6d07ad
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
@@ -0,0 +1,100 @@
+// 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 "components/spellcheck/renderer/spellcheck_provider_test.h"
+
+#include "base/stl_util.h"
+#include "components/spellcheck/common/spellcheck_marker.h"
+#include "components/spellcheck/common/spellcheck_messages.h"
+#include "components/spellcheck/renderer/spellcheck.h"
+#include "ipc/ipc_message_macros.h"
+
+class MockSpellcheck: public SpellCheck {
+};
+
+FakeTextCheckingCompletion::FakeTextCheckingCompletion()
+: completion_count_(0),
+ cancellation_count_(0) {
+}
+
+FakeTextCheckingCompletion::~FakeTextCheckingCompletion() {}
+
+void FakeTextCheckingCompletion::didFinishCheckingText(
+ const blink::WebVector<blink::WebTextCheckingResult>& results) {
+ ++completion_count_;
+}
+
+void FakeTextCheckingCompletion::didCancelCheckingText() {
+ ++completion_count_;
+ ++cancellation_count_;
+}
+
+TestingSpellCheckProvider::TestingSpellCheckProvider()
+ : SpellCheckProvider(NULL, new MockSpellcheck),
+ spelling_service_call_count_(0) {
+}
+
+TestingSpellCheckProvider::TestingSpellCheckProvider(
+ SpellCheck* spellcheck)
+ : SpellCheckProvider(nullptr, spellcheck),
+ spelling_service_call_count_(0) {
+}
+
+TestingSpellCheckProvider::~TestingSpellCheckProvider() {
+ delete spellcheck_;
+}
+
+bool TestingSpellCheckProvider::Send(IPC::Message* message) {
+#if !defined(USE_BROWSER_SPELLCHECKER)
+ // Call our mock message handlers.
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(TestingSpellCheckProvider, *message)
+ IPC_MESSAGE_HANDLER(SpellCheckHostMsg_CallSpellingService,
+ OnCallSpellingService)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ if (handled) {
+ delete message;
+ return true;
+ }
+#endif
+
+ messages_.push_back(message);
+ return true;
+}
+
+void TestingSpellCheckProvider::OnCallSpellingService(int route_id,
+ int identifier,
+ const base::string16& text,
+ const std::vector<SpellCheckMarker>& markers) {
+#if defined (USE_BROWSER_SPELLCHECKER)
+ NOTREACHED();
+#else
+ ++spelling_service_call_count_;
+ blink::WebTextCheckingCompletion* completion =
+ text_check_completions_.Lookup(identifier);
+ if (!completion) {
+ ResetResult();
+ return;
+ }
+ text_.assign(text);
+ text_check_completions_.Remove(identifier);
+ std::vector<blink::WebTextCheckingResult> results;
+ results.push_back(blink::WebTextCheckingResult(
+ blink::WebTextDecorationTypeSpelling,
+ 0, 5, blink::WebString("hello")));
+ completion->didFinishCheckingText(results);
+ last_request_ = text;
+ last_results_ = results;
+#endif
+}
+
+void TestingSpellCheckProvider::ResetResult() {
+ text_.clear();
+}
+
+SpellCheckProviderTest::SpellCheckProviderTest() {}
+SpellCheckProviderTest::~SpellCheckProviderTest() {}
+
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_test.h b/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
new file mode 100644
index 00000000000..3ef9d965a31
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
@@ -0,0 +1,68 @@
+// 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 COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_PROVIDER_TEST_H_
+#define COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_PROVIDER_TEST_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "base/memory/scoped_vector.h"
+#include "base/strings/string16.h"
+#include "components/spellcheck/renderer/spellcheck_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h"
+#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
+
+namespace IPC {
+ class Message;
+}
+
+// A fake completion object for verification.
+class FakeTextCheckingCompletion : public blink::WebTextCheckingCompletion {
+ public:
+ FakeTextCheckingCompletion();
+ ~FakeTextCheckingCompletion();
+
+ void didFinishCheckingText(
+ const blink::WebVector<blink::WebTextCheckingResult>& results) override;
+ void didCancelCheckingText() override;
+
+ size_t completion_count_;
+ size_t cancellation_count_;
+};
+
+// Faked test target, which stores sent message for verification.
+class TestingSpellCheckProvider : public SpellCheckProvider {
+ public:
+ TestingSpellCheckProvider();
+ // Takes ownership of |spellcheck|.
+ explicit TestingSpellCheckProvider(SpellCheck* spellcheck);
+
+ ~TestingSpellCheckProvider() override;
+ bool Send(IPC::Message* message) override;
+ void OnCallSpellingService(int route_id,
+ int identifier,
+ const base::string16& text,
+ const std::vector<SpellCheckMarker>& markers);
+ void ResetResult();
+
+ base::string16 text_;
+ ScopedVector<IPC::Message> messages_;
+ size_t spelling_service_call_count_;
+};
+
+// SpellCheckProvider test fixture.
+class SpellCheckProviderTest : public testing::Test {
+ public:
+ SpellCheckProviderTest();
+ ~SpellCheckProviderTest() override;
+
+ protected:
+ TestingSpellCheckProvider provider_;
+};
+
+#endif // COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_PROVIDER_TEST_H_
diff --git a/chromium/components/spellcheck/renderer/spellcheck_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
new file mode 100644
index 00000000000..5d0e6c97a0a
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
@@ -0,0 +1,1570 @@
+// 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 "components/spellcheck/renderer/spellcheck.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "components/spellcheck/common/spellcheck_common.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "components/spellcheck/renderer/hunspell_engine.h"
+#include "components/spellcheck/renderer/spellcheck_language.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h"
+#include "third_party/WebKit/public/web/WebTextCheckingResult.h"
+
+#define TYPOGRAPHICAL_APOSTROPHE L"\x2019"
+
+namespace {
+const int kNoOffset = 0;
+const int kNoTag = 0;
+
+base::FilePath GetHunspellDirectory() {
+ base::FilePath hunspell_directory;
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &hunspell_directory))
+ return base::FilePath();
+
+ hunspell_directory = hunspell_directory.AppendASCII("third_party");
+ hunspell_directory = hunspell_directory.AppendASCII("hunspell_dictionaries");
+ return hunspell_directory;
+}
+
+} // namespace
+
+// TODO(groby): This needs to be a BrowserTest for OSX.
+class SpellCheckTest : public testing::Test {
+ public:
+ SpellCheckTest() {
+ ReinitializeSpellCheck("en-US");
+ }
+
+ void ReinitializeSpellCheck(const std::string& language) {
+ spell_check_.reset(new SpellCheck());
+ InitializeSpellCheck(language);
+ }
+
+ void UninitializeSpellCheck() {
+ spell_check_.reset(new SpellCheck());
+ }
+
+ bool InitializeIfNeeded() {
+ return spell_check()->InitializeIfNeeded();
+ }
+
+ void InitializeSpellCheck(const std::string& language) {
+ base::FilePath hunspell_directory = GetHunspellDirectory();
+ EXPECT_FALSE(hunspell_directory.empty());
+ base::File file(
+ spellcheck::GetVersionedFileName(language, hunspell_directory),
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+#if defined(OS_MACOSX)
+ // TODO(groby): Forcing spellcheck to use hunspell, even on OSX.
+ // Instead, tests should exercise individual spelling engines.
+ spell_check_->languages_.push_back(new SpellcheckLanguage());
+ spell_check_->languages_.front()->platform_spelling_engine_.reset(
+ new HunspellEngine);
+ spell_check_->languages_.front()->Init(std::move(file), language);
+#else
+ spell_check_->AddSpellcheckLanguage(std::move(file), language);
+#endif
+ }
+
+ ~SpellCheckTest() override {}
+
+ SpellCheck* spell_check() { return spell_check_.get(); }
+
+ bool CheckSpelling(const std::string& word, int tag) {
+ return spell_check_->languages_.front()
+ ->platform_spelling_engine_->CheckSpelling(base::ASCIIToUTF16(word),
+ tag);
+ }
+
+ bool IsValidContraction(const base::string16& word, int tag) {
+ return spell_check_->languages_.front()->IsValidContraction(word, tag);
+ }
+
+ static void FillSuggestions(
+ const std::vector<std::vector<base::string16>>& suggestions_list,
+ std::vector<base::string16>* optional_suggestions) {
+ SpellCheck::FillSuggestions(suggestions_list, optional_suggestions);
+ }
+
+#if !defined(OS_MACOSX)
+ protected:
+ void TestSpellCheckParagraph(
+ const base::string16& input,
+ const std::vector<SpellCheckResult>& expected) {
+ blink::WebVector<blink::WebTextCheckingResult> results;
+ spell_check()->SpellCheckParagraph(input,
+ &results);
+
+ EXPECT_EQ(results.size(), expected.size());
+ size_t size = std::min(results.size(), expected.size());
+ for (size_t j = 0; j < size; ++j) {
+ EXPECT_EQ(results[j].decoration, blink::WebTextDecorationTypeSpelling);
+ EXPECT_EQ(results[j].location, expected[j].location);
+ EXPECT_EQ(results[j].length, expected[j].length);
+ }
+ }
+#endif
+
+ private:
+ std::unique_ptr<SpellCheck> spell_check_;
+ base::MessageLoop loop;
+};
+
+// A fake completion object for verification.
+class MockTextCheckingCompletion : public blink::WebTextCheckingCompletion {
+ public:
+ MockTextCheckingCompletion()
+ : completion_count_(0) {
+ }
+
+ void didFinishCheckingText(
+ const blink::WebVector<blink::WebTextCheckingResult>& results) override {
+ completion_count_++;
+ last_results_ = results;
+ }
+
+ void didCancelCheckingText() override {
+ completion_count_++;
+ }
+
+ size_t completion_count_;
+ blink::WebVector<blink::WebTextCheckingResult> last_results_;
+};
+
+// Operates unit tests for the content::SpellCheck::SpellCheckWord() function
+// with the US English dictionary.
+// The unit tests in this function consist of:
+// * Tests for the function with empty strings;
+// * Tests for the function with a valid English word;
+// * Tests for the function with a valid non-English word;
+// * Tests for the function with a valid English word with a preceding
+// space character;
+// * Tests for the function with a valid English word with a preceding
+// non-English word;
+// * Tests for the function with a valid English word with a following
+// space character;
+// * Tests for the function with a valid English word with a following
+// non-English word;
+// * Tests for the function with two valid English words concatenated
+// with space characters or non-English words;
+// * Tests for the function with an invalid English word;
+// * Tests for the function with an invalid English word with a preceding
+// space character;
+// * Tests for the function with an invalid English word with a preceding
+// non-English word;
+// * Tests for the function with an invalid English word with a following
+// space character;
+// * Tests for the function with an invalid English word with a following
+// non-English word, and;
+// * Tests for the function with two invalid English words concatenated
+// with space characters or non-English words.
+// A test with a "[ROBUSTNESS]" mark shows it is a robustness test and it uses
+// grammatically incorrect string.
+// TODO(groby): Please feel free to add more tests.
+TEST_F(SpellCheckTest, SpellCheckStrings_EN_US) {
+ static const struct {
+ // A string to be tested.
+ const wchar_t* input;
+ // An expected result for this test case.
+ // * true: the input string does not have any invalid words.
+ // * false: the input string has one or more invalid words.
+ bool expected_result;
+ // The position and the length of the first invalid word.
+ int misspelling_start;
+ int misspelling_length;
+ } kTestCases[] = {
+ // Empty strings.
+ {L"", true},
+ {L" ", true},
+ {L"\xA0", true},
+ {L"\x3000", true},
+
+ // A valid English word "hello".
+ {L"hello", true},
+ // A valid Chinese word (meaning "hello") consisting of two CJKV
+ // ideographs
+ {L"\x4F60\x597D", true},
+ // A valid Korean word (meaning "hello") consisting of five hangul
+ // syllables
+ {L"\xC548\xB155\xD558\xC138\xC694", true},
+ // A valid Japanese word (meaning "hello") consisting of five Hiragana
+ // letters
+ {L"\x3053\x3093\x306B\x3061\x306F", true},
+ // A valid Hindi word (meaning ?) consisting of six Devanagari letters
+ // (This word is copied from "http://b/issue?id=857583".)
+ {L"\x0930\x093E\x091C\x0927\x093E\x0928", true},
+ // A valid English word "affix" using a Latin ligature 'ffi'
+ {L"a\xFB03x", true},
+ // A valid English word "hello" (fullwidth version)
+ {L"\xFF28\xFF45\xFF4C\xFF4C\xFF4F", true},
+ // Two valid Greek words (meaning "hello") consisting of seven Greek
+ // letters
+ {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", true},
+ // A valid Russian word (meaning "hello") consisting of twelve Cyrillic
+ // letters
+ {L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435", true},
+ // A valid English contraction
+ {L"isn't", true},
+ // A valid English contraction with a typographical apostrophe.
+ {L"isn" TYPOGRAPHICAL_APOSTROPHE L"t", true},
+ // A valid English word enclosed with underscores.
+ {L"_hello_", true},
+
+ // A valid English word with a preceding whitespace
+ {L" " L"hello", true},
+ // A valid English word with a preceding no-break space
+ {L"\xA0" L"hello", true},
+ // A valid English word with a preceding ideographic space
+ {L"\x3000" L"hello", true},
+ // A valid English word with a preceding Chinese word
+ {L"\x4F60\x597D" L"hello", true},
+ // [ROBUSTNESS] A valid English word with a preceding Korean word
+ {L"\xC548\xB155\xD558\xC138\xC694" L"hello", true},
+ // A valid English word with a preceding Japanese word
+ {L"\x3053\x3093\x306B\x3061\x306F" L"hello", true},
+ // [ROBUSTNESS] A valid English word with a preceding Hindi word
+ {L"\x0930\x093E\x091C\x0927\x093E\x0928" L"hello", true},
+ // [ROBUSTNESS] A valid English word with two preceding Greek words
+ {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
+ L"hello", true},
+ // [ROBUSTNESS] A valid English word with a preceding Russian word
+ {L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435" L"hello", true},
+
+ // A valid English word with a following whitespace
+ {L"hello" L" ", true},
+ // A valid English word with a following no-break space
+ {L"hello" L"\xA0", true},
+ // A valid English word with a following ideographic space
+ {L"hello" L"\x3000", true},
+ // A valid English word with a following Chinese word
+ {L"hello" L"\x4F60\x597D", true},
+ // [ROBUSTNESS] A valid English word with a following Korean word
+ {L"hello" L"\xC548\xB155\xD558\xC138\xC694", true},
+ // A valid English word with a following Japanese word
+ {L"hello" L"\x3053\x3093\x306B\x3061\x306F", true},
+ // [ROBUSTNESS] A valid English word with a following Hindi word
+ {L"hello" L"\x0930\x093E\x091C\x0927\x093E\x0928", true},
+ // [ROBUSTNESS] A valid English word with two following Greek words
+ {L"hello"
+ L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", true},
+ // [ROBUSTNESS] A valid English word with a following Russian word
+ {L"hello" L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435", true},
+
+ // Two valid English words concatenated with a whitespace
+ {L"hello" L" " L"hello", true},
+ // Two valid English words concatenated with a no-break space
+ {L"hello" L"\xA0" L"hello", true},
+ // Two valid English words concatenated with an ideographic space
+ {L"hello" L"\x3000" L"hello", true},
+ // Two valid English words concatenated with a Chinese word
+ {L"hello" L"\x4F60\x597D" L"hello", true},
+ // [ROBUSTNESS] Two valid English words concatenated with a Korean word
+ {L"hello" L"\xC548\xB155\xD558\xC138\xC694" L"hello", true},
+ // Two valid English words concatenated with a Japanese word
+ {L"hello" L"\x3053\x3093\x306B\x3061\x306F" L"hello", true},
+ // [ROBUSTNESS] Two valid English words concatenated with a Hindi word
+ {L"hello" L"\x0930\x093E\x091C\x0927\x093E\x0928" L"hello" , true},
+ // [ROBUSTNESS] Two valid English words concatenated with two Greek words
+ {L"hello" L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
+ L"hello", true},
+ // [ROBUSTNESS] Two valid English words concatenated with a Russian word
+ {L"hello" L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435" L"hello", true},
+ // [ROBUSTNESS] Two valid English words concatenated with a contraction
+ // character.
+ {L"hello:hello", true},
+
+ // An invalid English word
+ {L"ifmmp", false, 0, 5},
+ // An invalid English word "bffly" containing a Latin ligature 'ffl'
+ {L"b\xFB04y", false, 0, 3},
+ // An invalid English word "ifmmp" (fullwidth version)
+ {L"\xFF29\xFF46\xFF4D\xFF4D\xFF50", false, 0, 5},
+ // An invalid English contraction
+ {L"jtm'u", false, 0, 5},
+ // An invalid English word enclosed with underscores.
+ {L"_ifmmp_", false, 1, 5},
+
+ // An invalid English word with a preceding whitespace
+ {L" " L"ifmmp", false, 1, 5},
+ // An invalid English word with a preceding no-break space
+ {L"\xA0" L"ifmmp", false, 1, 5},
+ // An invalid English word with a preceding ideographic space
+ {L"\x3000" L"ifmmp", false, 1, 5},
+ // An invalid English word with a preceding Chinese word
+ {L"\x4F60\x597D" L"ifmmp", false, 2, 5},
+ // [ROBUSTNESS] An invalid English word with a preceding Korean word
+ {L"\xC548\xB155\xD558\xC138\xC694" L"ifmmp", false, 5, 5},
+ // An invalid English word with a preceding Japanese word
+ {L"\x3053\x3093\x306B\x3061\x306F" L"ifmmp", false, 5, 5},
+ // [ROBUSTNESS] An invalid English word with a preceding Hindi word
+ {L"\x0930\x093E\x091C\x0927\x093E\x0928" L"ifmmp", false, 6, 5},
+ // [ROBUSTNESS] An invalid English word with two preceding Greek words
+ {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
+ L"ifmmp", false, 8, 5},
+ // [ROBUSTNESS] An invalid English word with a preceding Russian word
+ {L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435" L"ifmmp", false, 12, 5},
+
+ // An invalid English word with a following whitespace
+ {L"ifmmp" L" ", false, 0, 5},
+ // An invalid English word with a following no-break space
+ {L"ifmmp" L"\xA0", false, 0, 5},
+ // An invalid English word with a following ideographic space
+ {L"ifmmp" L"\x3000", false, 0, 5},
+ // An invalid English word with a following Chinese word
+ {L"ifmmp" L"\x4F60\x597D", false, 0, 5},
+ // [ROBUSTNESS] An invalid English word with a following Korean word
+ {L"ifmmp" L"\xC548\xB155\xD558\xC138\xC694", false, 0, 5},
+ // An invalid English word with a following Japanese word
+ {L"ifmmp" L"\x3053\x3093\x306B\x3061\x306F", false, 0, 5},
+ // [ROBUSTNESS] An invalid English word with a following Hindi word
+ {L"ifmmp" L"\x0930\x093E\x091C\x0927\x093E\x0928", false, 0, 5},
+ // [ROBUSTNESS] An invalid English word with two following Greek words
+ {L"ifmmp"
+ L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", false, 0, 5},
+ // [ROBUSTNESS] An invalid English word with a following Russian word
+ {L"ifmmp" L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435", false, 0, 5},
+
+ // Two invalid English words concatenated with a whitespace
+ {L"ifmmp" L" " L"ifmmp", false, 0, 5},
+ // Two invalid English words concatenated with a no-break space
+ {L"ifmmp" L"\xA0" L"ifmmp", false, 0, 5},
+ // Two invalid English words concatenated with an ideographic space
+ {L"ifmmp" L"\x3000" L"ifmmp", false, 0, 5},
+ // Two invalid English words concatenated with a Chinese word
+ {L"ifmmp" L"\x4F60\x597D" L"ifmmp", false, 0, 5},
+ // [ROBUSTNESS] Two invalid English words concatenated with a Korean word
+ {L"ifmmp" L"\xC548\xB155\xD558\xC138\xC694" L"ifmmp", false, 0, 5},
+ // Two invalid English words concatenated with a Japanese word
+ {L"ifmmp" L"\x3053\x3093\x306B\x3061\x306F" L"ifmmp", false, 0, 5},
+ // [ROBUSTNESS] Two invalid English words concatenated with a Hindi word
+ {L"ifmmp" L"\x0930\x093E\x091C\x0927\x093E\x0928" L"ifmmp" , false, 0, 5},
+ // [ROBUSTNESS] Two invalid English words concatenated with two Greek words
+ {L"ifmmp" L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
+ L"ifmmp", false, 0, 5},
+ // [ROBUSTNESS] Two invalid English words concatenated with a Russian word
+ {L"ifmmp" L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435" L"ifmmp", false, 0, 5},
+ // [ROBUSTNESS] Two invalid English words concatenated with a contraction
+ // character.
+ {L"ifmmp:ifmmp", false, 0, 11},
+
+ // [REGRESSION] Issue 13432: "Any word of 13 or 14 characters is not
+ // spellcheck" <http://crbug.com/13432>.
+ {L"qwertyuiopasd", false, 0, 13},
+ {L"qwertyuiopasdf", false, 0, 14},
+
+ // [REGRESSION] Issue 128896: "en_US hunspell dictionary includes
+ // acknowledgement but not acknowledgements" <http://crbug.com/128896>
+ {L"acknowledgement", true},
+ {L"acknowledgements", true},
+
+ // Issue 123290: "Spellchecker should treat numbers as word characters"
+ {L"0th", true},
+ {L"1st", true},
+ {L"2nd", true},
+ {L"3rd", true},
+ {L"4th", true},
+ {L"5th", true},
+ {L"6th", true},
+ {L"7th", true},
+ {L"8th", true},
+ {L"9th", true},
+ {L"10th", true},
+ {L"100th", true},
+ {L"1000th", true},
+ {L"25", true},
+ {L"2012", true},
+ {L"100,000,000", true},
+ {L"3.141592653", true},
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ size_t input_length = 0;
+ if (kTestCases[i].input != NULL) {
+ input_length = wcslen(kTestCases[i].input);
+ }
+ int misspelling_start;
+ int misspelling_length;
+ bool result = spell_check()->SpellCheckWord(
+ base::WideToUTF16(kTestCases[i].input).c_str(),
+ kNoOffset,
+ static_cast<int>(input_length),
+ kNoTag,
+ &misspelling_start,
+ &misspelling_length, NULL);
+
+ EXPECT_EQ(kTestCases[i].expected_result, result);
+ EXPECT_EQ(kTestCases[i].misspelling_start, misspelling_start);
+ EXPECT_EQ(kTestCases[i].misspelling_length, misspelling_length);
+ }
+}
+
+TEST_F(SpellCheckTest, SpellCheckSuggestions_EN_US) {
+ static const struct {
+ // A string to be tested.
+ const wchar_t* input;
+ // An expected result for this test case.
+ // * true: the input string does not have any invalid words.
+ // * false: the input string has one or more invalid words.
+ bool expected_result;
+ // The position and the length of the first invalid word.
+ int misspelling_start;
+ int misspelling_length;
+
+ // A suggested word that should occur.
+ const wchar_t* suggested_word;
+ } kTestCases[] = {
+ {L"ello", false, 0, 0, L"hello"},
+ {L"ello", false, 0, 0, L"cello"},
+ {L"wate", false, 0, 0, L"water"},
+ {L"wate", false, 0, 0, L"waste"},
+ {L"wate", false, 0, 0, L"sate"},
+ {L"wate", false, 0, 0, L"ate"},
+ {L"jum", false, 0, 0, L"jump"},
+ {L"jum", false, 0, 0, L"hum"},
+ {L"jum", false, 0, 0, L"sum"},
+ {L"jum", false, 0, 0, L"um"},
+ {L"alot", false, 0, 0, L"a lot"},
+ // A regression test for Issue 36523.
+ {L"privliged", false, 0, 0, L"privileged"},
+ // TODO (Sidchat): add many more examples.
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ std::vector<base::string16> suggestions;
+ size_t input_length = 0;
+ if (kTestCases[i].input != NULL) {
+ input_length = wcslen(kTestCases[i].input);
+ }
+ int misspelling_start;
+ int misspelling_length;
+ bool result = spell_check()->SpellCheckWord(
+ base::WideToUTF16(kTestCases[i].input).c_str(),
+ kNoOffset,
+ static_cast<int>(input_length),
+ kNoTag,
+ &misspelling_start,
+ &misspelling_length,
+ &suggestions);
+
+ // Check for spelling.
+ EXPECT_EQ(kTestCases[i].expected_result, result);
+
+ // Check if the suggested words occur.
+ bool suggested_word_is_present = false;
+ for (int j = 0; j < static_cast<int>(suggestions.size()); j++) {
+ if (suggestions.at(j).compare(
+ base::WideToUTF16(kTestCases[i].suggested_word)) == 0) {
+ suggested_word_is_present = true;
+ break;
+ }
+ }
+
+ EXPECT_TRUE(suggested_word_is_present);
+ }
+}
+
+// This test verifies our spellchecker can split a text into words and check
+// the spelling of each word in the text.
+#if defined(THREAD_SANITIZER)
+// SpellCheckTest.SpellCheckText fails under ThreadSanitizer v2.
+// See http://crbug.com/217909.
+#define MAYBE_SpellCheckText DISABLED_SpellCheckText
+#else
+#define MAYBE_SpellCheckText SpellCheckText
+#endif // THREAD_SANITIZER
+TEST_F(SpellCheckTest, MAYBE_SpellCheckText) {
+ static const struct {
+ const char* language;
+ const wchar_t* input;
+ } kTestCases[] = {
+ {
+ // Afrikaans
+ "af-ZA",
+ L"Google se missie is om die w\x00EAreld se inligting te organiseer en "
+ L"dit bruikbaar en toeganklik te maak."
+ }, {
+ // Bulgarian
+ "bg-BG",
+ L"\x041c\x0438\x0441\x0438\x044f\x0442\x0430 "
+ L"\x043d\x0430 Google \x0435 \x0434\x0430 \x043e"
+ L"\x0440\x0433\x0430\x043d\x0438\x0437\x0438\x0440"
+ L"\x0430 \x0441\x0432\x0435\x0442\x043e\x0432"
+ L"\x043d\x0430\x0442\x0430 \x0438\x043d\x0444"
+ L"\x043e\x0440\x043c\x0430\x0446\x0438\x044f "
+ L"\x0438 \x0434\x0430 \x044f \x043d"
+ L"\x0430\x043f\x0440\x0430\x0432\x0438 \x0443"
+ L"\x043d\x0438\x0432\x0435\x0440\x0441\x0430\x043b"
+ L"\x043d\x043e \x0434\x043e\x0441\x0442\x044a"
+ L"\x043f\x043d\x0430 \x0438 \x043f\x043e"
+ L"\x043b\x0435\x0437\x043d\x0430."
+ }, {
+ // Catalan
+ "ca-ES",
+ L"La missi\x00F3 de Google \x00E9s organitzar la informaci\x00F3 "
+ L"del m\x00F3n i fer que sigui \x00FAtil i accessible universalment."
+ }, {
+ // Czech
+ "cs-CZ",
+ L"Posl\x00E1n\x00EDm spole\x010Dnosti Google je "
+ L"uspo\x0159\x00E1\x0064\x0061t informace z cel\x00E9ho sv\x011Bta "
+ L"tak, aby byly v\x0161\x0065obecn\x011B p\x0159\x00EDstupn\x00E9 "
+ L"a u\x017Eite\x010Dn\x00E9."
+ }, {
+ // Danish
+ "da-DK",
+ L"Googles "
+ L"mission er at organisere verdens information og g\x00F8re den "
+ L"almindeligt tilg\x00E6ngelig og nyttig."
+ }, {
+ // German
+ "de-DE",
+ L"Das Ziel von Google besteht darin, die auf der Welt vorhandenen "
+ L"Informationen zu organisieren und allgemein zug\x00E4nglich und "
+ L"nutzbar zu machen."
+ }, {
+ // Greek
+ "el-GR",
+ L"\x0391\x03C0\x03BF\x03C3\x03C4\x03BF\x03BB\x03AE "
+ L"\x03C4\x03B7\x03C2 Google \x03B5\x03AF\x03BD\x03B1\x03B9 "
+ L"\x03BD\x03B1 \x03BF\x03C1\x03B3\x03B1\x03BD\x03CE\x03BD\x03B5\x03B9 "
+ L"\x03C4\x03B9\x03C2 "
+ L"\x03C0\x03BB\x03B7\x03C1\x03BF\x03C6\x03BF\x03C1\x03AF\x03B5\x03C2 "
+ L"\x03C4\x03BF\x03C5 \x03BA\x03CC\x03C3\x03BC\x03BF\x03C5 "
+ L"\x03BA\x03B1\x03B9 \x03BD\x03B1 \x03C4\x03B9\x03C2 "
+ L"\x03BA\x03B1\x03B8\x03B9\x03C3\x03C4\x03AC "
+ L"\x03C0\x03C1\x03BF\x03C3\x03B2\x03AC\x03C3\x03B9\x03BC\x03B5\x03C2 "
+ L"\x03BA\x03B1\x03B9 \x03C7\x03C1\x03AE\x03C3\x03B9\x03BC\x03B5\x03C2."
+ }, {
+ // English (Australia)
+ "en-AU",
+ L"Google's mission is to organise the world's information and make it "
+ L"universally accessible and useful."
+ }, {
+ // English (Canada)
+ "en-CA",
+ L"Google's mission is to organize the world's information and make it "
+ L"universally accessible and useful."
+ }, {
+ // English (United Kingdom)
+ "en-GB",
+ L"Google's mission is to organise the world's information and make it "
+ L"universally accessible and useful."
+ }, {
+ // English (United States)
+ "en-US",
+ L"Google's mission is to organize the world's information and make it "
+ L"universally accessible and useful."
+ }, {
+ // Spanish
+ "es-ES",
+ L"La misi\x00F3n de "
+ // L"Google" - to be added.
+ L" es organizar la informaci\x00F3n mundial "
+ L"para que resulte universalmente accesible y \x00FAtil."
+ }, {
+ // Estonian
+ "et-EE",
+ // L"Google'ile " - to be added.
+ L"\x00FClesanne on korraldada maailma teavet ja teeb selle "
+ L"k\x00F5igile k\x00E4ttesaadavaks ja kasulikuks.",
+ }, {
+ // Persian
+ "fa",
+ L"\x0686\x0647 \x0637\x0648\x0631 \x0622\x06cc\x0627 \x0634\x0645\x0627 "
+ L"\x0627\x06cc\x0631\x0627\x0646\x06cc \x0647\x0633\x062a\x06cc\x062f"
+ }, {
+ // Faroese
+ "fo-FO",
+ L"Google er at samskipa alla vitan \x00ED heiminum og gera hana alment "
+ L"atkomiliga og n\x00FDtiliga."
+ }, {
+ // French
+ "fr-FR",
+ L"Google a pour mission d'organiser les informations \x00E0 "
+ L"l'\x00E9\x0063helle mondiale dans le but de les rendre accessibles "
+ L"et utiles \x00E0 tous."
+ }, {
+ // Hebrew
+ "he-IL",
+ L"\x05D4\x05DE\x05E9\x05D9\x05DE\x05D4 \x05E9\x05DC Google "
+ L"\x05D4\x05D9\x05D0 \x05DC\x05D0\x05E8\x05D2\x05DF "
+ L"\x05D0\x05EA \x05D4\x05DE\x05D9\x05D3\x05E2 "
+ L"\x05D4\x05E2\x05D5\x05DC\x05DE\x05D9 "
+ L"\x05D5\x05DC\x05D4\x05E4\x05D5\x05DA \x05D0\x05D5\x05EA\x05D5 "
+ L"\x05DC\x05D6\x05DE\x05D9\x05DF "
+ L"\x05D5\x05E9\x05D9\x05DE\x05D5\x05E9\x05D9 \x05D1\x05DB\x05DC "
+ L"\x05D4\x05E2\x05D5\x05DC\x05DD. "
+ // Two words with ASCII double/single quoation marks.
+ L"\x05DE\x05E0\x05DB\x0022\x05DC \x05E6\x0027\x05D9\x05E4\x05E1"
+ }, {
+ // Hindi
+ "hi-IN",
+ L"Google \x0915\x093E \x092E\x093F\x0936\x0928 "
+ L"\x0926\x0941\x0928\x093F\x092F\x093E \x0915\x0940 "
+ L"\x091C\x093E\x0928\x0915\x093E\x0930\x0940 \x0915\x094B "
+ L"\x0935\x094D\x092F\x0935\x0938\x094D\x0925\x093F\x0924 "
+ L"\x0915\x0930\x0928\x093E \x0914\x0930 \x0909\x0938\x0947 "
+ L"\x0938\x093E\x0930\x094D\x0935\x092D\x094C\x092E\x093F\x0915 "
+ L"\x0930\x0942\x092A \x0938\x0947 \x092A\x0939\x0941\x0901\x091A "
+ L"\x092E\x0947\x0902 \x0914\x0930 \x0909\x092A\x092F\x094B\x0917\x0940 "
+ L"\x092C\x0928\x093E\x0928\x093E \x0939\x0948."
+ }, {
+ // Hungarian
+ "hu-HU",
+ L"A Google azt a k\x00FCldet\x00E9st v\x00E1llalta mag\x00E1ra, "
+ L"hogy a vil\x00E1gon fellelhet\x0151 inform\x00E1\x0063i\x00F3kat "
+ L"rendszerezze \x00E9s \x00E1ltal\x00E1nosan el\x00E9rhet\x0151v\x00E9, "
+ L"illetve haszn\x00E1lhat\x00F3v\x00E1 tegye."
+ }, {
+ // Croatian
+ "hr-HR",
+ // L"Googleova " - to be added.
+ L"je misija organizirati svjetske informacije i u\x010Diniti ih "
+ // L"univerzalno " - to be added.
+ L"pristupa\x010Dnima i korisnima."
+ }, {
+ // Indonesian
+ "id-ID",
+ L"Misi Google adalah untuk mengelola informasi dunia dan membuatnya "
+ L"dapat diakses dan bermanfaat secara universal."
+ }, {
+ // Italian
+ "it-IT",
+ L"La missione di Google \x00E8 organizzare le informazioni a livello "
+ L"mondiale e renderle universalmente accessibili e fruibili."
+ }, {
+ // Lithuanian
+ "lt-LT",
+ L"\x201EGoogle\x201C tikslas \x2013 rinkti ir sisteminti pasaulio "
+ L"informacij\x0105 bei padaryti j\x0105 prieinam\x0105 ir "
+ L"nauding\x0105 visiems."
+ }, {
+ // Latvian
+ "lv-LV",
+ L"Google uzdevums ir k\x0101rtot pasaules inform\x0101"
+ L"ciju un padar\x012Bt to univers\x0101li pieejamu un noder\x012Bgu."
+ }, {
+ // Norwegian
+ "nb-NO",
+ // L"Googles " - to be added.
+ L"m\x00E5l er \x00E5 organisere informasjonen i verden og "
+ L"gj\x00F8re den tilgjengelig og nyttig for alle."
+ }, {
+ // Dutch
+ "nl-NL",
+ L"Het doel van Google is om alle informatie wereldwijd toegankelijk "
+ L"en bruikbaar te maken."
+ }, {
+ // Polish
+ "pl-PL",
+ L"Misj\x0105 Google jest uporz\x0105" L"dkowanie \x015Bwiatowych "
+ L"zasob\x00F3w informacji, aby sta\x0142y si\x0119 one powszechnie "
+ L"dost\x0119pne i u\x017Cyteczne."
+ }, {
+ // Portuguese (Brazil)
+ "pt-BR",
+ L"A miss\x00E3o do "
+#if !defined(OS_MACOSX)
+ L"Google "
+#endif
+ L"\x00E9 organizar as informa\x00E7\x00F5"
+ L"es do mundo todo e "
+#if !defined(OS_MACOSX)
+ L"torn\x00E1-las "
+#endif
+ L"acess\x00EDveis e \x00FAteis em car\x00E1ter universal."
+ }, {
+ // Portuguese (Portugal)
+ "pt-PT",
+ L"O "
+#if !defined(OS_MACOSX)
+ L"Google "
+#endif
+ L"tem por miss\x00E3o organizar a informa\x00E7\x00E3o do "
+ L"mundo e "
+#if !defined(OS_MACOSX)
+ L"torn\x00E1-la "
+#endif
+ L"universalmente acess\x00EDvel e \x00FAtil"
+ }, {
+ // Romanian
+ "ro-RO",
+ L"Misiunea Google este de a organiza informa\x021B3iile lumii \x0219i de "
+ L"a le face accesibile \x0219i utile la nivel universal."
+ }, {
+ // Russian
+ "ru-RU",
+ L"\x041C\x0438\x0441\x0441\x0438\x044F Google "
+ L"\x0441\x043E\x0441\x0442\x043E\x0438\x0442 \x0432 "
+ L"\x043E\x0440\x0433\x0430\x043D\x0438\x0437\x0430\x0446\x0438\x0438 "
+ L"\x043C\x0438\x0440\x043E\x0432\x043E\x0439 "
+ L"\x0438\x043D\x0444\x043E\x0440\x043C\x0430\x0446\x0438\x0438, "
+ L"\x043E\x0431\x0435\x0441\x043F\x0435\x0447\x0435\x043D\x0438\x0438 "
+ L"\x0435\x0435 "
+ L"\x0434\x043E\x0441\x0442\x0443\x043F\x043D\x043E\x0441\x0442\x0438 "
+ L"\x0438 \x043F\x043E\x043B\x044C\x0437\x044B \x0434\x043B\x044F "
+ L"\x0432\x0441\x0435\x0445."
+ // A Russian word including U+0451. (Bug 15558 <http://crbug.com/15558>)
+ L"\x0451\x043B\x043A\x0430"
+ }, {
+ // Serbo-Croatian (Serbian Latin)
+ "sh",
+ L"Google-ova misija je da organizuje sve informacije na svetu i "
+ L"u\x010dini ih univerzal-no dostupnim i korisnim."
+ }, {
+ // Serbian
+ "sr",
+ L"\x0047\x006f\x006f\x0067\x006c\x0065\x002d\x043e\x0432\x0430 "
+ L"\x043c\x0438\x0441\x0438\x0458\x0430 \x0458\x0435 \x0434\x0430 "
+ L"\x043e\x0440\x0433\x0430\x043d\x0438\x0437\x0443\x0458\x0435 "
+ L"\x0441\x0432\x0435 "
+ L"\x0438\x043d\x0444\x043e\x0440\x043c\x0430\x0446\x0438\x0458\x0435 "
+ L"\x043d\x0430 \x0441\x0432\x0435\x0442\x0443 \x0438 "
+ L"\x0443\x0447\x0438\x043d\x0438 \x0438\x0445 "
+ L"\x0443\x043d\x0438\x0432\x0435\x0440\x0437\x0430\x043b\x043d\x043e "
+ L"\x0434\x043e\x0441\x0442\x0443\x043f\x043d\x0438\x043c \x0438 "
+ L"\x043a\x043e\x0440\x0438\x0441\x043d\x0438\x043c."
+ }, {
+ // Slovak
+ "sk-SK",
+ L"Spolo\x010Dnos\x0165 Google si dala za \x00FAlohu usporiada\x0165 "
+ L"inform\x00E1\x0063ie "
+ L"z cel\x00E9ho sveta a zabezpe\x010Di\x0165, "
+ L"aby boli v\x0161eobecne dostupn\x00E9 a u\x017Eito\x010Dn\x00E9."
+ }, {
+ // Slovenian
+ "sl-SI",
+ // L"Googlovo " - to be added.
+ L"poslanstvo je organizirati svetovne informacije in "
+ L"omogo\x010Diti njihovo dostopnost in s tem uporabnost za vse."
+ }, {
+ // Swedish
+ "sv-SE",
+ L"Googles m\x00E5ls\x00E4ttning \x00E4r att ordna v\x00E4rldens "
+ L"samlade information och g\x00F6ra den tillg\x00E4nglig f\x00F6r alla."
+ }, {
+ // Turkish
+ "tr-TR",
+ // L"Google\x2019\x0131n " - to be added.
+ L"misyonu, d\x00FCnyadaki t\x00FCm bilgileri "
+ L"organize etmek ve evrensel olarak eri\x015Filebilir ve "
+ L"kullan\x0131\x015Fl\x0131 k\x0131lmakt\x0131r."
+ }, {
+ // Ukranian
+ "uk-UA",
+ L"\x041c\x0456\x0441\x0456\x044f "
+ L"\x043a\x043e\x043c\x043f\x0430\x043d\x0456\x0457 Google "
+ L"\x043f\x043e\x043b\x044f\x0433\x0430\x0454 \x0432 "
+ L"\x0442\x043e\x043c\x0443, \x0449\x043e\x0431 "
+ L"\x0443\x043f\x043e\x0440\x044f\x0434\x043a\x0443\x0432\x0430\x0442"
+ L"\x0438 \x0456\x043d\x0444\x043e\x0440\x043c\x0430\x0446\x0456\x044e "
+ L"\x0437 \x0443\x0441\x044c\x043e\x0433\x043e "
+ L"\x0441\x0432\x0456\x0442\x0443 \x0442\x0430 "
+ L"\x0437\x0440\x043e\x0431\x0438\x0442\x0438 \x0457\x0457 "
+ L"\x0443\x043d\x0456\x0432\x0435\x0440\x0441\x0430\x043b\x044c\x043d"
+ L"\x043e \x0434\x043e\x0441\x0442\x0443\x043f\x043d\x043e\x044e "
+ L"\x0442\x0430 \x043a\x043e\x0440\x0438\x0441\x043d\x043e\x044e."
+ }, {
+ // Vietnamese
+ "vi-VN",
+ L"Nhi\x1EC7m v\x1EE5 c\x1EE7\x0061 "
+ L"Google la \x0111\x1EC3 t\x1ED5 ch\x1EE9\x0063 "
+ L"c\x00E1\x0063 th\x00F4ng tin c\x1EE7\x0061 "
+ L"th\x1EBF gi\x1EDBi va l\x00E0m cho n\x00F3 universal c\x00F3 "
+ L"th\x1EC3 truy c\x1EADp va h\x1EEFu d\x1EE5ng h\x01A1n."
+ }, {
+ // Korean
+ "ko",
+ L"Google\xC758 \xBAA9\xD45C\xB294 \xC804\xC138\xACC4\xC758 "
+ L"\xC815\xBCF4\xB97C \xCCB4\xACC4\xD654\xD558\xC5EC \xBAA8\xB450\xAC00 "
+ L"\xD3B8\xB9AC\xD558\xAC8C \xC774\xC6A9\xD560 \xC218 "
+ L"\xC788\xB3C4\xB85D \xD558\xB294 \xAC83\xC785\xB2C8\xB2E4."
+ }, {
+ // Albanian
+ "sq",
+ L"Misioni i Google \x00EBsht\x00EB q\x00EB t\x00EB organizoj\x00EB "
+ L"informacionin e bot\x00EBs dhe t\x00EB b\x00EBjn\x00EB at\x00EB "
+ L"universalisht t\x00EB arritshme dhe t\x00EB dobishme."
+ }, {
+ // Tamil
+ "ta",
+ L"Google \x0B87\x0BA9\x0BCD "
+ L"\x0BA8\x0BC7\x0BBE\x0B95\x0BCD\x0B95\x0BAE\x0BCD "
+ L"\x0B89\x0BB2\x0B95\x0BBF\x0BA9\x0BCD \x0BA4\x0B95\x0BB5\x0BB2\x0BCD "
+ L"\x0B8F\x0BB1\x0BCD\x0BAA\x0BBE\x0B9F\x0BC1 \x0B87\x0BA4\x0BC1 "
+ L"\x0B89\x0BB2\x0B95\x0BB3\x0BBE\x0BB5\x0BBF\x0BAF "
+ L"\x0B85\x0BA3\x0BC1\x0B95\x0B95\x0BCD \x0B95\x0BC2\x0B9F\x0BBF\x0BAF "
+ L"\x0BAE\x0BB1\x0BCD\x0BB1\x0BC1\x0BAE\x0BCD "
+ L"\x0BAA\x0BAF\x0BA9\x0BC1\x0BB3\x0BCD\x0BB3 "
+ L"\x0B9A\x0BC6\x0BAF\x0BCD\x0BAF \x0B89\x0BB3\x0BCD\x0BB3\x0BA4\x0BC1."
+ }, {
+ // Tajik
+ "tg",
+ L"\x041c\x0438\x0441\x0441\x0438\x044f\x0438 Google \x0438\x043d "
+ L"\x043c\x0443\x0440\x0430\x0442\x0442\x0430\x0431 "
+ L"\x0441\x043e\x0445\x0442\x0430\x043d\x0438 "
+ L"\x043c\x0430\x044a\x043b\x0443\x043c\x043e\x0442\x04b3\x043e\x0438 "
+ L"\x043c\x0430\x0432\x04b7\x0443\x0434\x0430, \x043e\x0441\x043e\x043d "
+ L"\x043d\x0430\x043c\x0443\x0434\x0430\x043d\x0438 "
+ L"\x0438\x0441\x0442\x0438\x0444\x043e\x0434\x0430\x0431\x0430\x0440"
+ L"\x04e3 \x0432\x0430 \x0434\x0430\x0441\x0442\x0440\x0430\x0441\x0438 "
+ L"\x0443\x043c\x0443\x043c "
+ L"\x0433\x0430\x0440\x0434\x043e\x043d\x0438\x0434\x0430\x043d\x0438 "
+ L"\x043e\x043d\x04b3\x043e \x0430\x0441\x0442."
+ },
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ ReinitializeSpellCheck(kTestCases[i].language);
+ size_t input_length = 0;
+ if (kTestCases[i].input != NULL)
+ input_length = wcslen(kTestCases[i].input);
+
+ int misspelling_start = 0;
+ int misspelling_length = 0;
+ bool result = spell_check()->SpellCheckWord(
+ base::WideToUTF16(kTestCases[i].input).c_str(),
+ kNoOffset,
+ static_cast<int>(input_length),
+ kNoTag,
+ &misspelling_start,
+ &misspelling_length, NULL);
+
+ EXPECT_TRUE(result)
+ << "\""
+ << std::wstring(kTestCases[i].input).substr(
+ misspelling_start, misspelling_length)
+ << "\" is misspelled in "
+ << kTestCases[i].language
+ << ".";
+ EXPECT_EQ(0, misspelling_start);
+ EXPECT_EQ(0, misspelling_length);
+ }
+}
+
+// Verify that our SpellCheck::SpellCheckWord() returns false when it checks
+// misspelled words.
+TEST_F(SpellCheckTest, MisspelledWords) {
+ static const struct {
+ const char* language;
+ const wchar_t* input;
+ } kTestCases[] = {
+ {
+ // A misspelled word for English
+ "en-US",
+ L"aaaaaaaaaa",
+ }, {
+ // A misspelled word for Greek.
+ "el-GR",
+ L"\x03B1\x03B1\x03B1\x03B1\x03B1\x03B1\x03B1\x03B1\x03B1\x03B1",
+ }, {
+ // A misspelled word for Persian.
+ "fa",
+ L"\x06cc\x06a9\x06cc\x0634\x0627\x0646",
+ }, {
+ // A misspelled word for Hebrew
+ "he-IL",
+ L"\x05D0\x05D0\x05D0\x05D0\x05D0\x05D0\x05D0\x05D0\x05D0\x05D0",
+ }, {
+ // Hindi
+ "hi-IN",
+ L"\x0905\x0905\x0905\x0905\x0905\x0905\x0905\x0905\x0905\x0905",
+ }, {
+ // A misspelled word for Russian
+ "ru-RU",
+ L"\x0430\x0430\x0430\x0430\x0430\x0430\x0430\x0430\x0430\x0430",
+ },
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ ReinitializeSpellCheck(kTestCases[i].language);
+
+ base::string16 word(base::WideToUTF16(kTestCases[i].input));
+ int word_length = static_cast<int>(word.length());
+ int misspelling_start = 0;
+ int misspelling_length = 0;
+ bool result = spell_check()->SpellCheckWord(word.c_str(),
+ kNoOffset,
+ word_length,
+ kNoTag,
+ &misspelling_start,
+ &misspelling_length,
+ NULL);
+ EXPECT_FALSE(result);
+ EXPECT_EQ(0, misspelling_start);
+ EXPECT_EQ(word_length, misspelling_length);
+ }
+}
+
+// Since SpellCheck::SpellCheckParagraph is not implemented on Mac,
+// we skip these SpellCheckParagraph tests on Mac.
+#if !defined(OS_MACOSX)
+
+// Make sure SpellCheckParagraph does not crash if the input is empty.
+TEST_F(SpellCheckTest, SpellCheckParagraphEmptyParagraph) {
+ std::vector<SpellCheckResult> expected;
+ TestSpellCheckParagraph(base::UTF8ToUTF16(""), expected);
+}
+
+// A simple test case having no misspellings.
+TEST_F(SpellCheckTest, SpellCheckParagraphNoMisspellings) {
+ const base::string16 text = base::UTF8ToUTF16("apple");
+ std::vector<SpellCheckResult> expected;
+ TestSpellCheckParagraph(text, expected);
+}
+
+// A simple test case having one misspelling.
+TEST_F(SpellCheckTest, SpellCheckParagraphSingleMisspellings) {
+ const base::string16 text = base::UTF8ToUTF16("zz");
+ std::vector<SpellCheckResult> expected;
+ expected.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 0, 2));
+
+ TestSpellCheckParagraph(text, expected);
+}
+
+// A simple test case having multiple misspellings.
+TEST_F(SpellCheckTest, SpellCheckParagraphMultipleMisspellings) {
+ const base::string16 text = base::UTF8ToUTF16("zz, zz");
+ std::vector<SpellCheckResult> expected;
+ expected.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 0, 2));
+ expected.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 4, 2));
+
+ TestSpellCheckParagraph(text, expected);
+}
+
+// Make sure a relatively long (correct) sentence can be spellchecked.
+TEST_F(SpellCheckTest, SpellCheckParagraphLongSentence) {
+ std::vector<SpellCheckResult> expected;
+ // The text is taken from US constitution preamble.
+ const base::string16 text = base::UTF8ToUTF16(
+ "We the people of the United States, in order to form a more perfect "
+ "union, establish justice, insure domestic tranquility, provide for "
+ "the common defense, promote the general welfare, and secure the "
+ "blessings of liberty to ourselves and our posterity, do ordain and "
+ "establish this Constitution for the United States of America.");
+
+ TestSpellCheckParagraph(text, expected);
+}
+
+// Make sure all misspellings can be found in a relatively long sentence.
+TEST_F(SpellCheckTest, SpellCheckParagraphLongSentenceMultipleMisspellings) {
+ std::vector<SpellCheckResult> expected;
+
+ // All 'the' are converted to 'hte' in US consitition preamble.
+ const base::string16 text = base::UTF8ToUTF16(
+ "We hte people of hte United States, in order to form a more perfect "
+ "union, establish justice, insure domestic tranquility, provide for "
+ "hte common defense, promote hte general welfare, and secure hte "
+ "blessings of liberty to ourselves and our posterity, do ordain and "
+ "establish this Constitution for hte United States of America.");
+
+ expected.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 3, 3));
+ expected.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 17, 3));
+ expected.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 135, 3));
+ expected.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 163, 3));
+ expected.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 195, 3));
+ expected.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 298, 3));
+
+ TestSpellCheckParagraph(text, expected);
+}
+
+// We also skip RequestSpellCheck tests on Mac, because a system spellchecker
+// is used on Mac instead of SpellCheck::RequestTextChecking.
+
+// Make sure RequestTextChecking does not crash if input is empty.
+TEST_F(SpellCheckTest, RequestSpellCheckWithEmptyString) {
+ MockTextCheckingCompletion completion;
+
+ spell_check()->RequestTextChecking(base::string16(), &completion);
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(completion.completion_count_, 1U);
+}
+
+// A simple test case having no misspellings.
+TEST_F(SpellCheckTest, RequestSpellCheckWithoutMisspelling) {
+ MockTextCheckingCompletion completion;
+
+ const base::string16 text = base::ASCIIToUTF16("hello");
+ spell_check()->RequestTextChecking(text, &completion);
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(completion.completion_count_, 1U);
+}
+
+// A simple test case having one misspelling.
+TEST_F(SpellCheckTest, RequestSpellCheckWithSingleMisspelling) {
+ MockTextCheckingCompletion completion;
+
+ const base::string16 text = base::ASCIIToUTF16("apple, zz");
+ spell_check()->RequestTextChecking(text, &completion);
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(completion.completion_count_, 1U);
+ EXPECT_EQ(completion.last_results_.size(), 1U);
+ EXPECT_EQ(completion.last_results_[0].location, 7);
+ EXPECT_EQ(completion.last_results_[0].length, 2);
+}
+
+// A simple test case having a few misspellings.
+TEST_F(SpellCheckTest, RequestSpellCheckWithMisspellings) {
+ MockTextCheckingCompletion completion;
+
+ const base::string16 text = base::ASCIIToUTF16("apple, zz, orange, zz");
+ spell_check()->RequestTextChecking(text, &completion);
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(completion.completion_count_, 1U);
+ EXPECT_EQ(completion.last_results_.size(), 2U);
+ EXPECT_EQ(completion.last_results_[0].location, 7);
+ EXPECT_EQ(completion.last_results_[0].length, 2);
+ EXPECT_EQ(completion.last_results_[1].location, 19);
+ EXPECT_EQ(completion.last_results_[1].length, 2);
+}
+
+// A test case that multiple requests comes at once. Make sure all
+// requests are processed.
+TEST_F(SpellCheckTest, RequestSpellCheckWithMultipleRequests) {
+ MockTextCheckingCompletion completion[3];
+
+ const base::string16 text[3] = {
+ base::ASCIIToUTF16("what, zz"),
+ base::ASCIIToUTF16("apple, zz"),
+ base::ASCIIToUTF16("orange, zz")
+ };
+
+ for (int i = 0; i < 3; ++i)
+ spell_check()->RequestTextChecking(text[i], &completion[i]);
+
+ base::RunLoop().RunUntilIdle();
+
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_EQ(completion[i].completion_count_, 1U);
+ EXPECT_EQ(completion[i].last_results_.size(), 1U);
+ EXPECT_EQ(completion[i].last_results_[0].location, 6 + i);
+ EXPECT_EQ(completion[i].last_results_[0].length, 2);
+ }
+}
+
+// A test case that spellchecking is requested before initializing.
+// In this case, we postpone to post a request.
+TEST_F(SpellCheckTest, RequestSpellCheckWithoutInitialization) {
+ UninitializeSpellCheck();
+
+ MockTextCheckingCompletion completion;
+ const base::string16 text = base::ASCIIToUTF16("zz");
+
+ spell_check()->RequestTextChecking(text, &completion);
+
+ // The task will not be posted yet.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(completion.completion_count_, 0U);
+}
+
+// Requests several spellchecking before initializing. Except the last one,
+// posting requests is cancelled and text is rendered as correct one.
+TEST_F(SpellCheckTest, RequestSpellCheckMultipleTimesWithoutInitialization) {
+ UninitializeSpellCheck();
+
+ MockTextCheckingCompletion completion[3];
+ const base::string16 text[3] = {
+ base::ASCIIToUTF16("what, zz"),
+ base::ASCIIToUTF16("apple, zz"),
+ base::ASCIIToUTF16("orange, zz")
+ };
+
+ // Calls RequestTextchecking a few times.
+ for (int i = 0; i < 3; ++i)
+ spell_check()->RequestTextChecking(text[i], &completion[i]);
+
+ // The last task will be posted after initialization, however the other
+ // requests should be pressed without spellchecking.
+ base::RunLoop().RunUntilIdle();
+ for (int i = 0; i < 2; ++i)
+ EXPECT_EQ(completion[i].completion_count_, 1U);
+ EXPECT_EQ(completion[2].completion_count_, 0U);
+
+ // Checks the last request is processed after initialization.
+ InitializeSpellCheck("en-US");
+
+ // Calls PostDelayedSpellCheckTask instead of OnInit here for simplicity.
+ spell_check()->PostDelayedSpellCheckTask(
+ spell_check()->pending_request_param_.release());
+ base::RunLoop().RunUntilIdle();
+ for (int i = 0; i < 3; ++i)
+ EXPECT_EQ(completion[i].completion_count_, 1U);
+}
+
+#endif
+
+// Verify that the SpellCheck class keeps the spelling marker added to a
+// misspelled word "zz".
+TEST_F(SpellCheckTest, CreateTextCheckingResultsKeepsMarkers) {
+ base::string16 text = base::ASCIIToUTF16("zz");
+ std::vector<SpellCheckResult> spellcheck_results;
+ spellcheck_results.push_back(
+ SpellCheckResult(SpellCheckResult::SPELLING, 0, 2, base::string16()));
+ blink::WebVector<blink::WebTextCheckingResult> textcheck_results;
+ spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, 0,
+ text, spellcheck_results,
+ &textcheck_results);
+ ASSERT_EQ(spellcheck_results.size(), textcheck_results.size());
+ EXPECT_EQ(blink::WebTextDecorationTypeSpelling,
+ textcheck_results[0].decoration);
+ EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location);
+ EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length);
+}
+
+// Verify that the SpellCheck class replaces the spelling marker added to a
+// contextually-misspelled word "bean" with a grammar marker.
+TEST_F(SpellCheckTest, CreateTextCheckingResultsAddsGrammarMarkers) {
+ base::string16 text = base::ASCIIToUTF16("I have bean to USA.");
+ std::vector<SpellCheckResult> spellcheck_results;
+ spellcheck_results.push_back(
+ SpellCheckResult(SpellCheckResult::SPELLING, 7, 4, base::string16()));
+ blink::WebVector<blink::WebTextCheckingResult> textcheck_results;
+ spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, 0,
+ text, spellcheck_results,
+ &textcheck_results);
+ ASSERT_EQ(spellcheck_results.size(), textcheck_results.size());
+ EXPECT_EQ(blink::WebTextDecorationTypeGrammar,
+ textcheck_results[0].decoration);
+ EXPECT_EQ(spellcheck_results[0].location, textcheck_results[0].location);
+ EXPECT_EQ(spellcheck_results[0].length, textcheck_results[0].length);
+}
+
+// Verify that the SpellCheck preserves the original apostrophe type in the
+// checked text, regardless of the type of apostrophe the browser returns.
+TEST_F(SpellCheckTest, CreateTextCheckingResultsKeepsTypographicalApostrophe) {
+ base::string16 text = base::WideToUTF16(
+ L"Ik've havn" TYPOGRAPHICAL_APOSTROPHE L"t ni'n"
+ TYPOGRAPHICAL_APOSTROPHE L"out-s I've I" TYPOGRAPHICAL_APOSTROPHE
+ L"ve");
+ std::vector<SpellCheckResult> spellcheck_results;
+
+ // All typewriter apostrophe results.
+ spellcheck_results.push_back(SpellCheckResult(SpellCheckResult::SPELLING, 0,
+ 5, base::UTF8ToUTF16("I've")));
+ spellcheck_results.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 6, 6, base::UTF8ToUTF16("haven't")));
+ spellcheck_results.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 13, 10, base::UTF8ToUTF16("in'n'out's")));
+
+ // Replacements that differ only by apostrophe type should be ignored.
+ spellcheck_results.push_back(SpellCheckResult(SpellCheckResult::SPELLING, 24,
+ 4, base::UTF8ToUTF16("I've")));
+ spellcheck_results.push_back(SpellCheckResult(SpellCheckResult::SPELLING, 29,
+ 4, base::UTF8ToUTF16("I've")));
+
+ // All typographical apostrophe results.
+ spellcheck_results.push_back(
+ SpellCheckResult(SpellCheckResult::SPELLING, 0, 5,
+ base::WideToUTF16(L"I" TYPOGRAPHICAL_APOSTROPHE L"ve")));
+ spellcheck_results.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 6, 6,
+ base::WideToUTF16(L"haven" TYPOGRAPHICAL_APOSTROPHE L"t")));
+ spellcheck_results.push_back(SpellCheckResult(
+ SpellCheckResult::SPELLING, 13, 10, base::WideToUTF16(
+ L"in" TYPOGRAPHICAL_APOSTROPHE L"n" TYPOGRAPHICAL_APOSTROPHE L"out"
+ TYPOGRAPHICAL_APOSTROPHE L"s")));
+
+ // Replacements that differ only by apostrophe type should be ignored.
+ spellcheck_results.push_back(
+ SpellCheckResult(SpellCheckResult::SPELLING, 24, 4,
+ base::WideToUTF16(L"I" TYPOGRAPHICAL_APOSTROPHE L"ve")));
+ spellcheck_results.push_back(
+ SpellCheckResult(SpellCheckResult::SPELLING, 29, 4,
+ base::WideToUTF16(L"I" TYPOGRAPHICAL_APOSTROPHE L"ve")));
+
+ blink::WebVector<blink::WebTextCheckingResult> textcheck_results;
+ spell_check()->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, 0,
+ text, spellcheck_results,
+ &textcheck_results);
+
+ static const wchar_t* kExpectedReplacements[] = {
+ L"I've",
+ L"haven" TYPOGRAPHICAL_APOSTROPHE L"t",
+ L"in'n" TYPOGRAPHICAL_APOSTROPHE L"out's",
+ L"I've",
+ L"haven" TYPOGRAPHICAL_APOSTROPHE L"t",
+ L"in'n" TYPOGRAPHICAL_APOSTROPHE L"out" TYPOGRAPHICAL_APOSTROPHE L"s",
+ };
+
+ ASSERT_EQ(arraysize(kExpectedReplacements), textcheck_results.size());
+ for (size_t i = 0; i < arraysize(kExpectedReplacements); ++i) {
+ EXPECT_EQ(base::WideToUTF16(kExpectedReplacements[i]),
+ textcheck_results[i].replacement)
+ << "i=" << i << "\nactual: \""
+ << base::string16(textcheck_results[i].replacement) << "\"";
+ }
+}
+
+// Checks some words that should be present in all English dictionaries.
+TEST_F(SpellCheckTest, EnglishWords) {
+ static const struct {
+ const char* input;
+ bool should_pass;
+ } kTestCases[] = {
+ // Issue 146093: "Chromebook" and "Chromebox" not included in spell-checking
+ // dictionary.
+ {"Chromebook", true},
+ {"Chromebooks", true},
+ {"Chromebox", true},
+ {"Chromeboxes", true},
+ {"Chromeblade", true},
+ {"Chromeblades", true},
+ {"Chromebase", true},
+ {"Chromebases", true},
+ // Issue 94708: Spell-checker incorrectly reports whisky as misspelled.
+ {"whisky", true},
+ {"whiskey", true},
+ {"whiskies", true},
+ // Issue 98678: "Recency" should be included in client-side dictionary.
+ {"recency", true},
+ {"recencies", false},
+ // Issue 140486
+ {"movie", true},
+ {"movies", true},
+ };
+
+ static const char* const kLocales[] = { "en-GB", "en-US", "en-CA", "en-AU" };
+
+ for (size_t j = 0; j < arraysize(kLocales); ++j) {
+ ReinitializeSpellCheck(kLocales[j]);
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ size_t input_length = 0;
+ if (kTestCases[i].input != NULL)
+ input_length = strlen(kTestCases[i].input);
+
+ int misspelling_start = 0;
+ int misspelling_length = 0;
+ bool result = spell_check()->SpellCheckWord(
+ base::ASCIIToUTF16(kTestCases[i].input).c_str(),
+ kNoOffset,
+ static_cast<int>(input_length),
+ kNoTag,
+ &misspelling_start,
+ &misspelling_length, NULL);
+
+ EXPECT_EQ(kTestCases[i].should_pass, result) << kTestCases[i].input <<
+ " in " << kLocales[j];
+ }
+ }
+}
+
+// Checks that NOSUGGEST works in English dictionaries.
+TEST_F(SpellCheckTest, NoSuggest) {
+ static const struct {
+ const char* input;
+ const char* suggestion;
+ const char* locale;
+ bool should_pass;
+ } kTestCases[] = {
+ {"suckerbert", "cocksucker", "en-GB", true},
+ {"suckerbert", "cocksucker", "en-US", true},
+ {"suckerbert", "cocksucker", "en-CA", true},
+ {"suckerbert", "cocksucker", "en-AU", true},
+ {"suckerbert", "cocksuckers", "en-GB", true},
+ {"suckerbert", "cocksuckers", "en-US", true},
+ {"suckerbert", "cocksuckers", "en-CA", true},
+ {"suckerbert", "cocksuckers", "en-AU", true},
+ {"Batasunaa", "Batasuna", "ca-ES", true},
+ {"pornoo", "porno", "it-IT", true},
+ {"catass", "catas", "lt-LT", true},
+ {"kuracc", "kurac", "sl-SI", true},
+ {"pittt", "pitt", "sv-SE", true},
+ };
+
+ size_t test_cases_size = arraysize(kTestCases);
+ for (size_t i = 0; i < test_cases_size; ++i) {
+ ReinitializeSpellCheck(kTestCases[i].locale);
+ size_t suggestion_length = 0;
+ if (kTestCases[i].suggestion != NULL)
+ suggestion_length = strlen(kTestCases[i].suggestion);
+
+ // First check that the NOSUGGEST flag didn't mark this word as not being in
+ // the dictionary.
+ int misspelling_start = 0;
+ int misspelling_length = 0;
+ bool result = spell_check()->SpellCheckWord(
+ base::ASCIIToUTF16(kTestCases[i].suggestion).c_str(),
+ kNoOffset,
+ static_cast<int>(suggestion_length),
+ kNoTag,
+ &misspelling_start,
+ &misspelling_length, NULL);
+
+ EXPECT_EQ(kTestCases[i].should_pass, result) << kTestCases[i].suggestion <<
+ " in " << kTestCases[i].locale;
+
+ // Now verify that this test case does not show up as a suggestion.
+ std::vector<base::string16> suggestions;
+ size_t input_length = 0;
+ if (kTestCases[i].input != NULL)
+ input_length = strlen(kTestCases[i].input);
+ result = spell_check()->SpellCheckWord(
+ base::ASCIIToUTF16(kTestCases[i].input).c_str(),
+ kNoOffset,
+ static_cast<int>(input_length),
+ kNoTag,
+ &misspelling_start,
+ &misspelling_length,
+ &suggestions);
+ // Input word should be a misspelling.
+ EXPECT_FALSE(result) << kTestCases[i].input
+ << " is not a misspelling in "
+ << kTestCases[i].locale;
+ // Check if the suggested words occur.
+ for (int j = 0; j < static_cast<int>(suggestions.size()); j++) {
+ for (size_t t = 0; t < test_cases_size; t++) {
+ int compare_result = suggestions.at(j).compare(
+ base::ASCIIToUTF16(kTestCases[t].suggestion));
+ EXPECT_FALSE(compare_result == 0) << kTestCases[t].suggestion <<
+ " in " << kTestCases[i].locale;
+ }
+ }
+ }
+}
+
+// Check that the correct dictionary files are checked in.
+TEST_F(SpellCheckTest, DictionaryFiles) {
+ std::vector<std::string> spellcheck_languages;
+ spellcheck::SpellCheckLanguages(&spellcheck_languages);
+ EXPECT_FALSE(spellcheck_languages.empty());
+
+ base::FilePath hunspell = GetHunspellDirectory();
+ for (size_t i = 0; i < spellcheck_languages.size(); ++i) {
+ base::FilePath dict =
+ spellcheck::GetVersionedFileName(spellcheck_languages[i], hunspell);
+ EXPECT_TRUE(base::PathExists(dict)) << dict.value() << " not found";
+ }
+}
+
+// TODO(groby): Add a test for hunspell itself, when MAXWORDLEN is exceeded.
+TEST_F(SpellCheckTest, SpellingEngine_CheckSpelling) {
+ static const struct {
+ const char* word;
+ bool expected_result;
+ } kTestCases[] = {
+ { "", true },
+ { "automatic", true },
+ { "hello", true },
+ { "forglobantic", false },
+ { "xfdssfsdfaasds", false },
+ { // 64 chars are the longest word to check - this should fail checking.
+ "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl",
+ false
+ },
+ { // Any word longer than 64 chars should be exempt from checking.
+ "reallylongwordthatabsolutelyexceedsthespecifiedcharacterlimitabit",
+ true
+ }
+ };
+
+ // Initialization magic - call InitializeIfNeeded twice. The first one simply
+ // flags internal state that a dictionary was requested. The second one will
+ // take the passed-in file and initialize hunspell with it. (The file was
+ // passed to hunspell in the ctor for the test fixture).
+ // This needs to be done since we need to ensure the SpellingEngine objects
+ // contained in the SpellcheckLanguages in |languages_| from the test fixture
+ // does get initialized.
+ // TODO(groby): Clean up this mess.
+ InitializeIfNeeded();
+ ASSERT_FALSE(InitializeIfNeeded());
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ bool result = CheckSpelling(kTestCases[i].word, 0);
+ EXPECT_EQ(kTestCases[i].expected_result, result) <<
+ "Failed test for " << kTestCases[i].word;
+ }
+}
+
+// Chrome should not suggest "Othello" for "hellllo" or "identically" for
+// "accidently".
+TEST_F(SpellCheckTest, LogicalSuggestions) {
+ static const struct {
+ const char* misspelled;
+ const char* suggestion;
+ } kTestCases[] = {
+ { "hellllo", "hello" },
+ { "accidently", "accidentally" }
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ int misspelling_start = 0;
+ int misspelling_length = 0;
+ std::vector<base::string16> suggestions;
+ EXPECT_FALSE(spell_check()->SpellCheckWord(
+ base::ASCIIToUTF16(kTestCases[i].misspelled).c_str(),
+ kNoOffset,
+ strlen(kTestCases[i].misspelled),
+ kNoTag,
+ &misspelling_start,
+ &misspelling_length,
+ &suggestions));
+ EXPECT_GE(suggestions.size(), static_cast<size_t>(1));
+ if (suggestions.size() > 0)
+ EXPECT_EQ(suggestions[0], base::ASCIIToUTF16(kTestCases[i].suggestion));
+ }
+}
+
+// Words with apostrophes should be valid contractions.
+TEST_F(SpellCheckTest, IsValidContraction) {
+ static const char* kLanguages[] = {
+ "en-AU",
+ "en-CA",
+ "en-GB",
+ "en-US",
+ };
+
+ static const wchar_t* kWords[] = {
+ L"in'n'out",
+ L"in" TYPOGRAPHICAL_APOSTROPHE L"n" TYPOGRAPHICAL_APOSTROPHE L"out",
+ };
+
+ for (size_t i = 0; i < arraysize(kLanguages); ++i) {
+ ReinitializeSpellCheck(kLanguages[i]);
+ for (size_t j = 0; j < arraysize(kWords); ++j)
+ EXPECT_TRUE(IsValidContraction(base::WideToUTF16(kWords[j]), 0));
+ }
+}
+
+TEST_F(SpellCheckTest, FillSuggestions_OneLanguageNoSuggestions) {
+ std::vector<std::vector<base::string16>> suggestions_list;
+ std::vector<base::string16> suggestion_results;
+
+ suggestions_list.resize(1);
+
+ FillSuggestions(suggestions_list, &suggestion_results);
+ EXPECT_TRUE(suggestion_results.empty());
+}
+
+TEST_F(SpellCheckTest, FillSuggestions_OneLanguageFewSuggestions) {
+ std::vector<std::vector<base::string16>> suggestions_list;
+ std::vector<base::string16> suggestion_results;
+
+ suggestions_list.resize(1);
+ suggestions_list[0].push_back(base::ASCIIToUTF16("foo"));
+
+ FillSuggestions(suggestions_list, &suggestion_results);
+ ASSERT_EQ(1U, suggestion_results.size());
+ EXPECT_EQ(base::ASCIIToUTF16("foo"), suggestion_results[0]);
+}
+
+TEST_F(SpellCheckTest, FillSuggestions_OneLanguageManySuggestions) {
+ std::vector<std::vector<base::string16>> suggestions_list;
+ std::vector<base::string16> suggestion_results;
+
+ suggestions_list.resize(1);
+ for (int i = 0; i < spellcheck::kMaxSuggestions + 2; ++i)
+ suggestions_list[0].push_back(base::ASCIIToUTF16(base::IntToString(i)));
+
+ FillSuggestions(suggestions_list, &suggestion_results);
+ ASSERT_EQ(static_cast<size_t>(spellcheck::kMaxSuggestions),
+ suggestion_results.size());
+ for (int i = 0; i < spellcheck::kMaxSuggestions; ++i)
+ EXPECT_EQ(base::ASCIIToUTF16(base::IntToString(i)), suggestion_results[i]);
+}
+
+TEST_F(SpellCheckTest, FillSuggestions_RemoveDuplicates) {
+ std::vector<std::vector<base::string16>> suggestions_list;
+ std::vector<base::string16> suggestion_results;
+
+ suggestions_list.resize(2);
+ for (size_t i = 0; i < 2; ++i) {
+ suggestions_list[i].push_back(base::ASCIIToUTF16("foo"));
+ suggestions_list[i].push_back(base::ASCIIToUTF16("bar"));
+ suggestions_list[i].push_back(base::ASCIIToUTF16("baz"));
+ }
+
+ FillSuggestions(suggestions_list, &suggestion_results);
+ ASSERT_EQ(3U, suggestion_results.size());
+ EXPECT_EQ(base::ASCIIToUTF16("foo"), suggestion_results[0]);
+ EXPECT_EQ(base::ASCIIToUTF16("bar"), suggestion_results[1]);
+ EXPECT_EQ(base::ASCIIToUTF16("baz"), suggestion_results[2]);
+}
+
+TEST_F(SpellCheckTest, FillSuggestions_TwoLanguages) {
+ std::vector<std::vector<base::string16>> suggestions_list;
+ std::vector<base::string16> suggestion_results;
+
+ suggestions_list.resize(2);
+ for (size_t i = 0; i < 2; ++i) {
+ std::string prefix = base::IntToString(i);
+ suggestions_list[i].push_back(base::ASCIIToUTF16(prefix + "foo"));
+ suggestions_list[i].push_back(base::ASCIIToUTF16(prefix + "bar"));
+ suggestions_list[i].push_back(base::ASCIIToUTF16(prefix + "baz"));
+ }
+
+ // Yes, this test assumes kMaxSuggestions is 5. If it isn't, the test needs
+ // to be updated accordingly.
+ ASSERT_EQ(5, spellcheck::kMaxSuggestions);
+ FillSuggestions(suggestions_list, &suggestion_results);
+ ASSERT_EQ(5U, suggestion_results.size());
+ EXPECT_EQ(base::ASCIIToUTF16("0foo"), suggestion_results[0]);
+ EXPECT_EQ(base::ASCIIToUTF16("1foo"), suggestion_results[1]);
+ EXPECT_EQ(base::ASCIIToUTF16("0bar"), suggestion_results[2]);
+ EXPECT_EQ(base::ASCIIToUTF16("1bar"), suggestion_results[3]);
+ EXPECT_EQ(base::ASCIIToUTF16("0baz"), suggestion_results[4]);
+}
+
+TEST_F(SpellCheckTest, FillSuggestions_ThreeLanguages) {
+ std::vector<std::vector<base::string16>> suggestions_list;
+ std::vector<base::string16> suggestion_results;
+
+ suggestions_list.resize(3);
+ for (size_t i = 0; i < 3; ++i) {
+ std::string prefix = base::IntToString(i);
+ suggestions_list[i].push_back(base::ASCIIToUTF16(prefix + "foo"));
+ suggestions_list[i].push_back(base::ASCIIToUTF16(prefix + "bar"));
+ suggestions_list[i].push_back(base::ASCIIToUTF16(prefix + "baz"));
+ }
+
+ // Yes, this test assumes kMaxSuggestions is 5. If it isn't, the test needs
+ // to be updated accordingly.
+ ASSERT_EQ(5, spellcheck::kMaxSuggestions);
+ FillSuggestions(suggestions_list, &suggestion_results);
+ ASSERT_EQ(5U, suggestion_results.size());
+ EXPECT_EQ(base::ASCIIToUTF16("0foo"), suggestion_results[0]);
+ EXPECT_EQ(base::ASCIIToUTF16("1foo"), suggestion_results[1]);
+ EXPECT_EQ(base::ASCIIToUTF16("2foo"), suggestion_results[2]);
+ EXPECT_EQ(base::ASCIIToUTF16("0bar"), suggestion_results[3]);
+ EXPECT_EQ(base::ASCIIToUTF16("1bar"), suggestion_results[4]);
+}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc b/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc
new file mode 100644
index 00000000000..84b64e788e1
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc
@@ -0,0 +1,443 @@
+// 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.
+
+// Implements a custom word iterator used for our spellchecker.
+
+#include "components/spellcheck/renderer/spellcheck_worditerator.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/i18n/break_iterator.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/spellcheck/renderer/spellcheck.h"
+#include "third_party/icu/source/common/unicode/normlzr.h"
+#include "third_party/icu/source/common/unicode/schriter.h"
+#include "third_party/icu/source/common/unicode/uscript.h"
+#include "third_party/icu/source/i18n/unicode/ulocdata.h"
+
+// SpellcheckCharAttribute implementation:
+
+SpellcheckCharAttribute::SpellcheckCharAttribute()
+ : script_code_(USCRIPT_LATIN) {
+}
+
+SpellcheckCharAttribute::~SpellcheckCharAttribute() {
+}
+
+void SpellcheckCharAttribute::SetDefaultLanguage(const std::string& language) {
+ CreateRuleSets(language);
+}
+
+base::string16 SpellcheckCharAttribute::GetRuleSet(
+ bool allow_contraction) const {
+ return allow_contraction ?
+ ruleset_allow_contraction_ : ruleset_disallow_contraction_;
+}
+
+void SpellcheckCharAttribute::CreateRuleSets(const std::string& language) {
+ // The template for our custom rule sets, which is based on the word-break
+ // rules of ICU 4.0:
+ // <http://source.icu-project.org/repos/icu/icu/tags/release-4-0/source/data/brkitr/word.txt>.
+ // The major differences from the original one are listed below:
+ // * It discards comments in the original rules.
+ // * It discards characters not needed by our spellchecker (e.g. numbers,
+ // punctuation characters, Hiraganas, Katakanas, CJK Ideographs, and so on).
+ // * It allows customization of the $ALetter value (i.e. word characters).
+ // * It allows customization of the $ALetterPlus value (i.e. whether or not to
+ // use the dictionary data).
+ // * It allows choosing whether or not to split a text at contraction
+ // characters.
+ // This template only changes the forward-iteration rules. So, calling
+ // ubrk_prev() returns the same results as the original template.
+ static const char kRuleTemplate[] =
+ "!!chain;"
+ "$CR = [\\p{Word_Break = CR}];"
+ "$LF = [\\p{Word_Break = LF}];"
+ "$Newline = [\\p{Word_Break = Newline}];"
+ "$Extend = [\\p{Word_Break = Extend}];"
+ "$Format = [\\p{Word_Break = Format}];"
+ "$Katakana = [\\p{Word_Break = Katakana}];"
+ // Not all the characters in a given script are ALetter.
+ // For instance, U+05F4 is MidLetter. So, this may be
+ // better, but it leads to an empty set error in Thai.
+ // "$ALetter = [[\\p{script=%s}] & [\\p{Word_Break = ALetter}]];"
+ "$ALetter = [\\p{script=%s}%s];"
+ // U+0027 (single quote/apostrophe) is not in MidNumLet any more
+ // in UAX 29 rev 21 or later. For our purpose, U+0027
+ // has to be treated as MidNumLet. ( http://crbug.com/364072 )
+ "$MidNumLet = [\\p{Word_Break = MidNumLet} \\u0027];"
+ "$MidLetter = [\\p{Word_Break = MidLetter}%s];"
+ "$MidNum = [\\p{Word_Break = MidNum}];"
+ "$Numeric = [\\p{Word_Break = Numeric}];"
+ "$ExtendNumLet = [\\p{Word_Break = ExtendNumLet}];"
+
+ "$Control = [\\p{Grapheme_Cluster_Break = Control}]; "
+ "%s" // ALetterPlus
+
+ "$KatakanaEx = $Katakana ($Extend | $Format)*;"
+ "$ALetterEx = $ALetterPlus ($Extend | $Format)*;"
+ "$MidNumLetEx = $MidNumLet ($Extend | $Format)*;"
+ "$MidLetterEx = $MidLetter ($Extend | $Format)*;"
+ "$MidNumEx = $MidNum ($Extend | $Format)*;"
+ "$NumericEx = $Numeric ($Extend | $Format)*;"
+ "$ExtendNumLetEx = $ExtendNumLet ($Extend | $Format)*;"
+
+ "$Hiragana = [\\p{script=Hiragana}];"
+ "$Ideographic = [\\p{Ideographic}];"
+ "$HiraganaEx = $Hiragana ($Extend | $Format)*;"
+ "$IdeographicEx = $Ideographic ($Extend | $Format)*;"
+
+ "!!forward;"
+ "$CR $LF;"
+ "[^$CR $LF $Newline]? ($Extend | $Format)+;"
+ "$ALetterEx {200};"
+ "$ALetterEx $ALetterEx {200};"
+ "%s" // (Allow|Disallow) Contraction
+
+ "!!reverse;"
+ "$BackALetterEx = ($Format | $Extend)* $ALetterPlus;"
+ "$BackMidNumLetEx = ($Format | $Extend)* $MidNumLet;"
+ "$BackNumericEx = ($Format | $Extend)* $Numeric;"
+ "$BackMidNumEx = ($Format | $Extend)* $MidNum;"
+ "$BackMidLetterEx = ($Format | $Extend)* $MidLetter;"
+ "$BackKatakanaEx = ($Format | $Extend)* $Katakana;"
+ "$BackExtendNumLetEx= ($Format | $Extend)* $ExtendNumLet;"
+ "$LF $CR;"
+ "($Format | $Extend)* [^$CR $LF $Newline]?;"
+ "$BackALetterEx $BackALetterEx;"
+ "$BackALetterEx ($BackMidLetterEx | $BackMidNumLetEx) $BackALetterEx;"
+ "$BackNumericEx $BackNumericEx;"
+ "$BackNumericEx $BackALetterEx;"
+ "$BackALetterEx $BackNumericEx;"
+ "$BackNumericEx ($BackMidNumEx | $BackMidNumLetEx) $BackNumericEx;"
+ "$BackKatakanaEx $BackKatakanaEx;"
+ "$BackExtendNumLetEx ($BackALetterEx | $BackNumericEx |"
+ " $BackKatakanaEx | $BackExtendNumLetEx);"
+ "($BackALetterEx | $BackNumericEx | $BackKatakanaEx)"
+ " $BackExtendNumLetEx;"
+
+ "!!safe_reverse;"
+ "($Extend | $Format)+ .?;"
+ "($MidLetter | $MidNumLet) $BackALetterEx;"
+ "($MidNum | $MidNumLet) $BackNumericEx;"
+
+ "!!safe_forward;"
+ "($Extend | $Format)+ .?;"
+ "($MidLetterEx | $MidNumLetEx) $ALetterEx;"
+ "($MidNumEx | $MidNumLetEx) $NumericEx;";
+
+ // Retrieve the script codes used by the given language from ICU. When the
+ // given language consists of two or more scripts, we just use the first
+ // script. The size of returned script codes is always < 8. Therefore, we use
+ // an array of size 8 so we can include all script codes without insufficient
+ // buffer errors.
+ UErrorCode error = U_ZERO_ERROR;
+ UScriptCode script_code[8];
+ int scripts = uscript_getCode(language.c_str(), script_code,
+ arraysize(script_code), &error);
+ if (U_SUCCESS(error) && scripts >= 1)
+ script_code_ = script_code[0];
+
+ // Retrieve the values for $ALetter and $ALetterPlus. We use the dictionary
+ // only for the languages which need it (i.e. Korean and Thai) to prevent ICU
+ // from returning dictionary words (i.e. Korean or Thai words) for languages
+ // which don't need them.
+ const char* aletter = uscript_getName(script_code_);
+ if (!aletter)
+ aletter = "Latin";
+
+ const char kWithDictionary[] =
+ "$dictionary = [:LineBreak = Complex_Context:];"
+ "$ALetterPlus = [$ALetter [$dictionary-$Extend-$Control]];";
+ const char kWithoutDictionary[] = "$ALetterPlus = $ALetter;";
+ const char* aletter_plus = kWithoutDictionary;
+ if (script_code_ == USCRIPT_HANGUL || script_code_ == USCRIPT_THAI ||
+ script_code_ == USCRIPT_LAO || script_code_ == USCRIPT_KHMER)
+ aletter_plus = kWithDictionary;
+
+ // Treat numbers as word characters except for Arabic and Hebrew.
+ const char* aletter_extra = " [0123456789]";
+ if (script_code_ == USCRIPT_HEBREW)
+ aletter_extra = "";
+ else if (script_code_ == USCRIPT_ARABIC)
+ // When "script=Arabic", it does not include tatweel, which is
+ // "script=Common" so add it back. Otherwise, it creates unwanted
+ // word breaks.
+ aletter_extra = " [\\u0640]";
+
+ const char kMidLetterExtra[] = "";
+ // For Hebrew, treat single/double quoation marks as MidLetter.
+ const char kMidLetterExtraHebrew[] = "\"'";
+ const char* midletter_extra = kMidLetterExtra;
+ if (script_code_ == USCRIPT_HEBREW)
+ midletter_extra = kMidLetterExtraHebrew;
+
+ // Create two custom rule-sets: one allows contraction and the other does not.
+ // We save these strings in UTF-16 so we can use it without conversions. (ICU
+ // needs UTF-16 strings.)
+ const char kAllowContraction[] =
+ "$ALetterEx ($MidLetterEx | $MidNumLetEx) $ALetterEx {200};";
+ const char kDisallowContraction[] = "";
+
+ ruleset_allow_contraction_ = base::ASCIIToUTF16(
+ base::StringPrintf(kRuleTemplate,
+ aletter,
+ aletter_extra,
+ midletter_extra,
+ aletter_plus,
+ kAllowContraction));
+ ruleset_disallow_contraction_ = base::ASCIIToUTF16(
+ base::StringPrintf(kRuleTemplate,
+ aletter,
+ aletter_extra,
+ midletter_extra,
+ aletter_plus,
+ kDisallowContraction));
+}
+
+bool SpellcheckCharAttribute::OutputChar(UChar c,
+ base::string16* output) const {
+ // Call the language-specific function if necessary.
+ // Otherwise, we call the default one.
+ switch (script_code_) {
+ case USCRIPT_ARABIC:
+ return OutputArabic(c, output);
+
+ case USCRIPT_HANGUL:
+ return OutputHangul(c, output);
+
+ case USCRIPT_HEBREW:
+ return OutputHebrew(c, output);
+
+ default:
+ return OutputDefault(c, output);
+ }
+}
+
+bool SpellcheckCharAttribute::OutputArabic(UChar c,
+ base::string16* output) const {
+ // Include non-Arabic characters (which should trigger a spelling error)
+ // and Arabic characters excluding vowel marks and class "Lm".
+ // We filter the latter because, while they are "letters", they are
+ // optional and so don't affect the correctness of the rest of the word.
+ if (!(0x0600 <= c && c <= 0x06FF) || (u_isalpha(c) && c != 0x0640))
+ output->push_back(c);
+ return true;
+}
+
+bool SpellcheckCharAttribute::OutputHangul(UChar c,
+ base::string16* output) const {
+ // Decompose a Hangul character to a Hangul vowel and consonants used by our
+ // spellchecker. A Hangul character of Unicode is a ligature consisting of a
+ // Hangul vowel and consonants, e.g. U+AC01 "Gag" consists of U+1100 "G",
+ // U+1161 "a", and U+11A8 "g". That is, we can treat each Hangul character as
+ // a point of a cubic linear space consisting of (first consonant, vowel, last
+ // consonant). Therefore, we can compose a Hangul character from a vowel and
+ // two consonants with linear composition:
+ // character = 0xAC00 +
+ // (first consonant - 0x1100) * 28 * 21 +
+ // (vowel - 0x1161) * 28 +
+ // (last consonant - 0x11A7);
+ // We can also decompose a Hangul character with linear decomposition:
+ // first consonant = (character - 0xAC00) / 28 / 21;
+ // vowel = (character - 0xAC00) / 28 % 21;
+ // last consonant = (character - 0xAC00) % 28;
+ // This code is copied from Unicode Standard Annex #15
+ // <http://unicode.org/reports/tr15> and added some comments.
+ const int kSBase = 0xAC00; // U+AC00: the top of Hangul characters.
+ const int kLBase = 0x1100; // U+1100: the top of Hangul first consonants.
+ const int kVBase = 0x1161; // U+1161: the top of Hangul vowels.
+ const int kTBase = 0x11A7; // U+11A7: the top of Hangul last consonants.
+ const int kLCount = 19; // The number of Hangul first consonants.
+ const int kVCount = 21; // The number of Hangul vowels.
+ const int kTCount = 28; // The number of Hangul last consonants.
+ const int kNCount = kVCount * kTCount;
+ const int kSCount = kLCount * kNCount;
+
+ int index = c - kSBase;
+ if (index < 0 || index >= kSBase + kSCount) {
+ // This is not a Hangul syllable. Call the default output function since we
+ // should output this character when it is a Hangul syllable.
+ return OutputDefault(c, output);
+ }
+
+ // This is a Hangul character. Decompose this characters into Hangul vowels
+ // and consonants.
+ int l = kLBase + index / kNCount;
+ int v = kVBase + (index % kNCount) / kTCount;
+ int t = kTBase + index % kTCount;
+ output->push_back(l);
+ output->push_back(v);
+ if (t != kTBase)
+ output->push_back(t);
+ return true;
+}
+
+bool SpellcheckCharAttribute::OutputHebrew(UChar c,
+ base::string16* output) const {
+ // Discard characters except Hebrew alphabets. We also discard Hebrew niqquds
+ // to prevent our Hebrew dictionary from marking a Hebrew word including
+ // niqquds as misspelled. (Same as Arabic vowel marks, we need to check
+ // niqquds manually and filter them out since their script codes are
+ // USCRIPT_HEBREW.)
+ // Pass through ASCII single/double quotation marks and Hebrew Geresh and
+ // Gershayim.
+ if ((0x05D0 <= c && c <= 0x05EA) || c == 0x22 || c == 0x27 ||
+ c == 0x05F4 || c == 0x05F3)
+ output->push_back(c);
+ return true;
+}
+
+bool SpellcheckCharAttribute::OutputDefault(UChar c,
+ base::string16* output) const {
+ // Check the script code of this character and output only if it is the one
+ // used by the spellchecker language.
+ UErrorCode status = U_ZERO_ERROR;
+ UScriptCode script_code = uscript_getScript(c, &status);
+ if (script_code == script_code_ || script_code == USCRIPT_COMMON)
+ output->push_back(c);
+ return true;
+}
+
+// SpellcheckWordIterator implementation:
+
+SpellcheckWordIterator::SpellcheckWordIterator()
+ : text_(NULL),
+ attribute_(NULL),
+ iterator_() {
+}
+
+SpellcheckWordIterator::~SpellcheckWordIterator() {
+ Reset();
+}
+
+bool SpellcheckWordIterator::Initialize(
+ const SpellcheckCharAttribute* attribute,
+ bool allow_contraction) {
+ // Create a custom ICU break iterator with empty text used in this object. (We
+ // allow setting text later so we can re-use this iterator.)
+ DCHECK(attribute);
+ const base::string16 rule(attribute->GetRuleSet(allow_contraction));
+
+ // If there is no rule set, the attributes were invalid.
+ if (rule.empty())
+ return false;
+
+ std::unique_ptr<base::i18n::BreakIterator> iterator(
+ new base::i18n::BreakIterator(base::string16(), rule));
+ if (!iterator->Init()) {
+ // Since we're not passing in any text, the only reason this could fail
+ // is if we fail to parse the rules. Since the rules are hardcoded,
+ // that would be a bug in this class.
+ NOTREACHED() << "failed to open iterator (broken rules)";
+ return false;
+ }
+ iterator_ = std::move(iterator);
+
+ // Set the character attributes so we can normalize the words extracted by
+ // this iterator.
+ attribute_ = attribute;
+ return true;
+}
+
+bool SpellcheckWordIterator::IsInitialized() const {
+ // Return true iff we have an iterator.
+ return !!iterator_;
+}
+
+bool SpellcheckWordIterator::SetText(const base::char16* text, size_t length) {
+ DCHECK(!!iterator_);
+
+ // Set the text to be split by this iterator.
+ if (!iterator_->SetText(text, length)) {
+ LOG(ERROR) << "failed to set text";
+ return false;
+ }
+
+ text_ = text;
+ return true;
+}
+
+SpellcheckWordIterator::WordIteratorStatus SpellcheckWordIterator::GetNextWord(
+ base::string16* word_string,
+ int* word_start,
+ int* word_length) {
+ DCHECK(!!text_);
+
+ word_string->clear();
+ *word_start = 0;
+ *word_length = 0;
+
+ if (!text_) {
+ return IS_END_OF_TEXT;
+ }
+
+ // Find a word that can be checked for spelling or a character that can be
+ // skipped over. Rather than moving past a skippable character this returns
+ // IS_SKIPPABLE and defers handling the character to the calling function.
+ while (iterator_->Advance()) {
+ const size_t start = iterator_->prev();
+ const size_t length = iterator_->pos() - start;
+ switch (iterator_->GetWordBreakStatus()) {
+ case base::i18n::BreakIterator::IS_WORD_BREAK: {
+ if (Normalize(start, length, word_string)) {
+ *word_start = start;
+ *word_length = length;
+ return IS_WORD;
+ }
+ break;
+ }
+ case base::i18n::BreakIterator::IS_SKIPPABLE_WORD: {
+ *word_string = iterator_->GetString();
+ *word_start = start;
+ *word_length = length;
+ return IS_SKIPPABLE;
+ }
+ // |iterator_| is RULE_BASED so the break status should never be
+ // IS_LINE_OR_CHAR_BREAK.
+ case base::i18n::BreakIterator::IS_LINE_OR_CHAR_BREAK: {
+ NOTREACHED();
+ break;
+ }
+ }
+ }
+
+ // There aren't any more words in the given text.
+ return IS_END_OF_TEXT;
+}
+
+void SpellcheckWordIterator::Reset() {
+ iterator_.reset();
+}
+
+bool SpellcheckWordIterator::Normalize(int input_start,
+ int input_length,
+ base::string16* output_string) const {
+ // We use NFKC (Normalization Form, Compatible decomposition, followed by
+ // canonical Composition) defined in Unicode Standard Annex #15 to normalize
+ // this token because it it the most suitable normalization algorithm for our
+ // spellchecker. Nevertheless, it is not a perfect algorithm for our
+ // spellchecker and we need manual normalization as well. The normalized
+ // text does not have to be NUL-terminated since its characters are copied to
+ // string16, which adds a NUL character when we need.
+ icu::UnicodeString input(FALSE, &text_[input_start], input_length);
+ UErrorCode status = U_ZERO_ERROR;
+ icu::UnicodeString output;
+ icu::Normalizer::normalize(input, UNORM_NFKC, 0, output, status);
+ if (status != U_ZERO_ERROR && status != U_STRING_NOT_TERMINATED_WARNING)
+ return false;
+
+ // Copy the normalized text to the output.
+ icu::StringCharacterIterator it(output);
+ for (UChar c = it.first(); c != icu::CharacterIterator::DONE; c = it.next())
+ attribute_->OutputChar(c, output_string);
+
+ return !output_string->empty();
+}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_worditerator.h b/chromium/components/spellcheck/renderer/spellcheck_worditerator.h
new file mode 100644
index 00000000000..ea2f038c1de
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_worditerator.h
@@ -0,0 +1,200 @@
+// 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.
+
+// Defines an iterator class that enumerates words supported by our spellchecker
+// from multi-language text. This class is used for filtering out characters
+// not supported by our spellchecker.
+
+#ifndef COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_WORDITERATOR_H_
+#define COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_WORDITERATOR_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "third_party/icu/source/common/unicode/uscript.h"
+
+namespace base {
+namespace i18n {
+class BreakIterator;
+} // namespace i18n
+} // namespace base
+
+// A class which encapsulates language-specific operations used by
+// SpellcheckWordIterator. When we set the spellchecker language, this class
+// creates rule sets that filter out the characters not supported by the
+// spellchecker. (Please read the comment in the SpellcheckWordIterator class
+// about how to use this class.)
+class SpellcheckCharAttribute {
+ public:
+ SpellcheckCharAttribute();
+ ~SpellcheckCharAttribute();
+
+ // Sets the language of the spellchecker. When this function is called with an
+ // ISO language code, this function creates the custom rule-sets used by
+ // the ICU break iterator so it can extract only words used by the language.
+ // GetRuleSet() returns the rule-sets created in this function.
+ void SetDefaultLanguage(const std::string& language);
+
+ // Returns a custom rule-set string used by the ICU break iterator. This class
+ // has two rule-sets, one splits a contraction and the other does not, so we
+ // can split a concaticated word (e.g. "seven-year-old") into words (e.g.
+ // "seven", "year", and "old") and check their spellings. The result stirng is
+ // encoded in UTF-16 since ICU needs UTF-16 strings.
+ base::string16 GetRuleSet(bool allow_contraction) const;
+
+ // Outputs a character only if it is a word character. (Please read the
+ // comments in CreateRuleSets() why we need this function.)
+ bool OutputChar(UChar c, base::string16* output) const;
+
+ private:
+ // Creates the rule-sets that return words possibly used by the given
+ // language. Unfortunately, these rule-sets are not perfect and have some
+ // false-positives. For example, they return combined accent marks even though
+ // we need English words only. We call OutputCharacter() to filter out such
+ // false-positive characters.
+ void CreateRuleSets(const std::string& language);
+
+ // Outputs a character only if it is one used by the given language. These
+ // functions are called from OutputChar().
+ bool OutputArabic(UChar c, base::string16* output) const;
+ bool OutputHangul(UChar c, base::string16* output) const;
+ bool OutputHebrew(UChar c, base::string16* output) const;
+ bool OutputDefault(UChar c, base::string16* output) const;
+
+ // The custom rule-set strings used by ICU break iterator. Since it is not so
+ // easy to create custom rule-sets from an ISO language code, this class
+ // saves these rule-set strings created when we set the language.
+ base::string16 ruleset_allow_contraction_;
+ base::string16 ruleset_disallow_contraction_;
+
+ // The script code used by this language.
+ UScriptCode script_code_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellcheckCharAttribute);
+};
+
+// A class which extracts words that can be checked for spelling from a
+// multi-language string. The ICU word-break iterator does not discard some
+// punctuation characters attached to a word. For example, when we set a word
+// "_hello_" to a word-break iterator, it just returns "_hello_". Neither does
+// it discard characters not used by the language. For example, it returns
+// Russian words even though we need English words only. To extract only the
+// words that our spellchecker can check their spellings, this class uses custom
+// rule-sets created by the SpellcheckCharAttribute class. Also, this class
+// normalizes extracted words so our spellchecker can check the spellings of
+// words that include ligatures, combined characters, full-width characters,
+// etc. This class uses UTF-16 strings as its input and output strings since
+// UTF-16 is the native encoding of ICU and avoid unnecessary conversions
+// when changing the encoding of this string for our spellchecker. (Chrome can
+// use two or more spellcheckers and we cannot assume their encodings.)
+// The following snippet is an example that extracts words with this class.
+//
+// // Creates the language-specific attributes for US English.
+// SpellcheckCharAttribute attribute;
+// attribute.SetDefaultLanguage("en-US");
+//
+// // Set up a SpellcheckWordIterator object which extracts English words,
+// // and retrieve them.
+// SpellcheckWordIterator iterator;
+// base::string16 text(base::UTF8ToUTF16("this is a test."));
+// iterator.Initialize(&attribute, true);
+// iterator.SetText(text.c_str(), text_.length());
+//
+// base::string16 word;
+// int offset;
+// int length;
+// while (iterator.GetNextWord(&word, &offset, &length)) {
+// ...
+// }
+//
+class SpellcheckWordIterator {
+ public:
+ enum WordIteratorStatus {
+ // The end of a sequence of text that the iterator recognizes as characters
+ // that can form a word.
+ IS_WORD,
+ // Non-word characters that the iterator can skip past, such as punctuation,
+ // whitespace, and characters from another character set.
+ IS_SKIPPABLE,
+ // The end of the text that the iterator is going over.
+ IS_END_OF_TEXT
+ };
+
+ SpellcheckWordIterator();
+ ~SpellcheckWordIterator();
+
+ // Initializes a word-iterator object with the language-specific attribute. If
+ // we need to split contractions and concatenated words, call this function
+ // with its 'allow_contraction' parameter false. (This function uses lots of
+ // temporal memory to compile a custom word-break rule into an automaton.)
+ bool Initialize(const SpellcheckCharAttribute* attribute,
+ bool allow_contraction);
+
+ // Returns whether this word iterator is initialized.
+ bool IsInitialized() const;
+
+ // Set text to be iterated. (This text does not have to be NULL-terminated.)
+ // This function also resets internal state so we can reuse this iterator
+ // without calling Initialize().
+ bool SetText(const base::char16* text, size_t length);
+
+ // Advances |iterator_| through |text_| and gets the current status of the
+ // word iterator within |text|:
+ //
+ // - Returns IS_WORD if the iterator just found the end of a sequence of word
+ // characters and it was able to normalize the sequence. This stores the
+ // normalized string into |word_string| and stores the position and length
+ // into |word_start| and |word_length| respectively. Keep in mind that
+ // since this function normalizes the output word, the length of
+ // |word_string| may be different from the |word_length|. Therefore, when
+ // we call functions that change the input text, such as
+ // string16::replace(), we need to use |word_start| and |word_length| as
+ // listed in the following snippet:
+ //
+ // while(iterator.GetNextWord(&word, &offset, &length))
+ // text.replace(offset, length, word);
+ //
+ // - Returns IS_SKIPPABLE if the iterator just found a character that the
+ // iterator can skip past such as punctuation, whitespace, and characters
+ // from another character set. This stores the character, position, and
+ // length into |word_string|, |word_start|, and |word_length| respectively.
+ //
+ // - Returns IS_END_OF_TEXT if the iterator has reached the end of |text_|.
+ SpellcheckWordIterator::WordIteratorStatus
+ GetNextWord(base::string16* word_string, int* word_start, int* word_length);
+
+ // Releases all the resources attached to this object.
+ void Reset();
+
+ private:
+ // Normalizes a non-terminated string returned from an ICU word-break
+ // iterator. A word returned from an ICU break iterator may include characters
+ // not supported by our spellchecker, e.g. ligatures, combining/ characters,
+ // full-width letters, etc. This function replaces such characters with
+ // alternative characters supported by our spellchecker. This function also
+ // calls SpellcheckWordIterator::OutputChar() to filter out false-positive
+ // characters.
+ bool Normalize(int input_start,
+ int input_length,
+ base::string16* output_string) const;
+
+ // The pointer to the input string from which we are extracting words.
+ const base::char16* text_;
+
+ // The language-specific attributes used for filtering out non-word
+ // characters.
+ const SpellcheckCharAttribute* attribute_;
+
+ // The break iterator.
+ std::unique_ptr<base::i18n::BreakIterator> iterator_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpellcheckWordIterator);
+};
+
+#endif // COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_WORDITERATOR_H_
+
diff --git a/chromium/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc
new file mode 100644
index 00000000000..37ac36dfe02
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spellcheck_worditerator_unittest.cc
@@ -0,0 +1,508 @@
+// 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 <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "base/format_macros.h"
+#include "base/i18n/break_iterator.h"
+#include "base/macros.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/spellcheck/renderer/spellcheck_worditerator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::i18n::BreakIterator;
+using WordIteratorStatus = SpellcheckWordIterator::WordIteratorStatus;
+
+namespace {
+
+struct TestCase {
+ const char* language;
+ bool allow_contraction;
+ const wchar_t* expected_words;
+};
+
+base::string16 GetRulesForLanguage(const std::string& language) {
+ SpellcheckCharAttribute attribute;
+ attribute.SetDefaultLanguage(language);
+ return attribute.GetRuleSet(true);
+}
+
+WordIteratorStatus GetNextNonSkippableWord(SpellcheckWordIterator* iterator,
+ base::string16* word_string,
+ int* word_start,
+ int* word_length) {
+ WordIteratorStatus status = SpellcheckWordIterator::IS_SKIPPABLE;
+ while (status == SpellcheckWordIterator::IS_SKIPPABLE)
+ status = iterator->GetNextWord(word_string, word_start, word_length);
+ return status;
+}
+
+} // namespace
+
+// Tests whether or not our SpellcheckWordIterator can extract words used by the
+// specified language from a multi-language text.
+TEST(SpellcheckWordIteratorTest, SplitWord) {
+ // An input text. This text includes words of several languages. (Some words
+ // are not separated with whitespace characters.) Our SpellcheckWordIterator
+ // should extract the words used by the specified language from this text and
+ // normalize them so our spell-checker can check their spellings. If
+ // characters are found that are not from the specified language the test
+ // skips them.
+ const wchar_t kTestText[] =
+ // Graphic characters
+ L"!@#$%^&*()"
+ // Latin (including a contraction character and a ligature).
+ L"hello:hello a\xFB03x"
+ // Greek
+ L"\x03B3\x03B5\x03B9\x03AC\x0020\x03C3\x03BF\x03C5"
+ // Cyrillic
+ L"\x0437\x0434\x0440\x0430\x0432\x0441\x0442\x0432"
+ L"\x0443\x0439\x0442\x0435"
+ // Hebrew (including niqquds)
+ L"\x05e9\x05c1\x05b8\x05dc\x05d5\x05b9\x05dd "
+ // Hebrew words with U+0027 and U+05F3
+ L"\x05e6\x0027\x05d9\x05e4\x05e1 \x05e6\x05F3\x05d9\x05e4\x05e1 "
+ // Hebrew words with U+0022 and U+05F4
+ L"\x05e6\x05d4\x0022\x05dc \x05e6\x05d4\x05f4\x05dc "
+ // Hebrew words enclosed with ASCII quotes.
+ L"\"\x05e6\x05d4\x0022\x05dc\" '\x05e9\x05c1\x05b8\x05dc\x05d5'"
+ // Arabic (including vowel marks)
+ L"\x0627\x064e\x0644\x0633\x064e\x0651\x0644\x0627\x0645\x064f "
+ L"\x0639\x064e\x0644\x064e\x064a\x0652\x0643\x064f\x0645\x0652 "
+ // Farsi/Persian (including vowel marks)
+ // Make sure \u064b - \u0652 are removed.
+ L"\x0647\x0634\x064e\x0631\x062d "
+ L"\x0647\x062e\x0648\x0627\x0647 "
+ L"\x0650\x062f\x0631\x062f "
+ L"\x0631\x0645\x0627\x0646\x0652 "
+ L"\x0633\x0631\x0651 "
+ L"\x0646\x0646\x064e\x062c\x064f\x0633 "
+ L"\x0627\x0644\x062d\x0645\x062f "
+ // Also make sure that class "Lm" (the \u0640) is filtered out too.
+ L"\x062c\x062c\x0640\x062c\x062c"
+ // Hindi
+ L"\x0930\x093E\x091C\x0927\x093E\x0928"
+ // Thai
+ L"\x0e2a\x0e27\x0e31\x0e2a\x0e14\x0e35\x0020\x0e04"
+ L"\x0e23\x0e31\x0e1a"
+ // Hiraganas
+ L"\x3053\x3093\x306B\x3061\x306F"
+ // CJKV ideographs
+ L"\x4F60\x597D"
+ // Hangul Syllables
+ L"\xC548\xB155\xD558\xC138\xC694"
+ // Full-width latin : Hello
+ L"\xFF28\xFF45\xFF4C\xFF4C\xFF4F "
+ L"e.g.,";
+
+ // The languages and expected results used in this test.
+ static const TestCase kTestCases[] = {
+ {
+ // English (keep contraction words)
+ "en-US", true, L"hello:hello affix Hello e.g"
+ }, {
+ // English (split contraction words)
+ "en-US", false, L"hello hello affix Hello e g"
+ }, {
+ // Greek
+ "el-GR", true,
+ L"\x03B3\x03B5\x03B9\x03AC\x0020\x03C3\x03BF\x03C5"
+ }, {
+ // Russian
+ "ru-RU", true,
+ L"\x0437\x0434\x0440\x0430\x0432\x0441\x0442\x0432"
+ L"\x0443\x0439\x0442\x0435"
+ }, {
+ // Hebrew
+ "he-IL", true,
+ L"\x05e9\x05dc\x05d5\x05dd "
+ L"\x05e6\x0027\x05d9\x05e4\x05e1 \x05e6\x05F3\x05d9\x05e4\x05e1 "
+ L"\x05e6\x05d4\x0022\x05dc \x05e6\x05d4\x05f4\x05dc "
+ L"\x05e6\x05d4\x0022\x05dc \x05e9\x05dc\x05d5"
+ }, {
+ // Arabic
+ "ar", true,
+ L"\x0627\x0644\x0633\x0644\x0627\x0645 "
+ L"\x0639\x0644\x064a\x0643\x0645 "
+ // Farsi/Persian
+ L"\x0647\x0634\x0631\x062d "
+ L"\x0647\x062e\x0648\x0627\x0647 "
+ L"\x062f\x0631\x062f "
+ L"\x0631\x0645\x0627\x0646 "
+ L"\x0633\x0631 "
+ L"\x0646\x0646\x062c\x0633 "
+ L"\x0627\x0644\x062d\x0645\x062f "
+ L"\x062c\x062c\x062c\x062c"
+ }, {
+ // Hindi
+ "hi-IN", true,
+ L"\x0930\x093E\x091C\x0927\x093E\x0928"
+ }, {
+ // Thai
+ "th-TH", true,
+ L"\x0e2a\x0e27\x0e31\x0e2a\x0e14\x0e35\x0020\x0e04"
+ L"\x0e23\x0e31\x0e1a"
+ }, {
+ // Korean
+ "ko-KR", true,
+ L"\x110b\x1161\x11ab\x1102\x1167\x11bc\x1112\x1161"
+ L"\x1109\x1166\x110b\x116d"
+ },
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ SCOPED_TRACE(base::StringPrintf("kTestCases[%" PRIuS "]: language=%s", i,
+ kTestCases[i].language));
+
+ SpellcheckCharAttribute attributes;
+ attributes.SetDefaultLanguage(kTestCases[i].language);
+
+ base::string16 input(base::WideToUTF16(kTestText));
+ SpellcheckWordIterator iterator;
+ EXPECT_TRUE(iterator.Initialize(&attributes,
+ kTestCases[i].allow_contraction));
+ EXPECT_TRUE(iterator.SetText(input.c_str(), input.length()));
+
+ std::vector<base::string16> expected_words = base::SplitString(
+ base::WideToUTF16(kTestCases[i].expected_words),
+ base::string16(1, ' '), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ base::string16 actual_word;
+ int actual_start, actual_len;
+ size_t index = 0;
+ for (SpellcheckWordIterator::WordIteratorStatus status =
+ iterator.GetNextWord(&actual_word, &actual_start, &actual_len);
+ status != SpellcheckWordIterator::IS_END_OF_TEXT;
+ status =
+ iterator.GetNextWord(&actual_word, &actual_start, &actual_len)) {
+ if (status == SpellcheckWordIterator::WordIteratorStatus::IS_SKIPPABLE)
+ continue;
+
+ EXPECT_TRUE(index < expected_words.size());
+ if (index < expected_words.size())
+ EXPECT_EQ(expected_words[index], actual_word);
+ ++index;
+ }
+ }
+}
+
+// Tests whether our SpellcheckWordIterator extracts an empty word without
+// getting stuck in an infinite loop when inputting a Khmer text. (This is a
+// regression test for Issue 46278.)
+TEST(SpellcheckWordIteratorTest, RuleSetConsistency) {
+ SpellcheckCharAttribute attributes;
+ attributes.SetDefaultLanguage("en-US");
+
+ const wchar_t kTestText[] = L"\x1791\x17c1\x002e";
+ base::string16 input(base::WideToUTF16(kTestText));
+
+ SpellcheckWordIterator iterator;
+ EXPECT_TRUE(iterator.Initialize(&attributes, true));
+ EXPECT_TRUE(iterator.SetText(input.c_str(), input.length()));
+
+ // When SpellcheckWordIterator uses an inconsistent ICU ruleset, the following
+ // iterator.GetNextWord() calls get stuck in an infinite loop. Therefore, this
+ // test succeeds if this call returns without timeouts.
+ base::string16 actual_word;
+ int actual_start, actual_len;
+ WordIteratorStatus status = GetNextNonSkippableWord(
+ &iterator, &actual_word, &actual_start, &actual_len);
+
+ EXPECT_EQ(SpellcheckWordIterator::WordIteratorStatus::IS_END_OF_TEXT, status);
+ EXPECT_EQ(0, actual_start);
+ EXPECT_EQ(0, actual_len);
+}
+
+// Vertify our SpellcheckWordIterator can treat ASCII numbers as word characters
+// on LTR languages. On the other hand, it should not treat ASCII numbers as
+// word characters on RTL languages because they change the text direction from
+// RTL to LTR.
+TEST(SpellcheckWordIteratorTest, TreatNumbersAsWordCharacters) {
+ // A set of a language, a dummy word, and a text direction used in this test.
+ // For each language, this test splits a dummy word, which consists of ASCII
+ // numbers and an alphabet of the language, into words. When ASCII numbers are
+ // treated as word characters, the split word becomes equal to the dummy word.
+ // Otherwise, the split word does not include ASCII numbers.
+ static const struct {
+ const char* language;
+ const wchar_t* text;
+ bool left_to_right;
+ } kTestCases[] = {
+ {
+ // English
+ "en-US", L"0123456789" L"a", true,
+ }, {
+ // Greek
+ "el-GR", L"0123456789" L"\x03B1", true,
+ }, {
+ // Russian
+ "ru-RU", L"0123456789" L"\x0430", true,
+ }, {
+ // Hebrew
+ "he-IL", L"0123456789" L"\x05D0", false,
+ }, {
+ // Arabic
+ "ar", L"0123456789" L"\x0627", false,
+ }, {
+ // Hindi
+ "hi-IN", L"0123456789" L"\x0905", true,
+ }, {
+ // Thai
+ "th-TH", L"0123456789" L"\x0e01", true,
+ }, {
+ // Korean
+ "ko-KR", L"0123456789" L"\x1100\x1161", true,
+ },
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ SCOPED_TRACE(base::StringPrintf("kTestCases[%" PRIuS "]: language=%s", i,
+ kTestCases[i].language));
+
+ SpellcheckCharAttribute attributes;
+ attributes.SetDefaultLanguage(kTestCases[i].language);
+
+ base::string16 input_word(base::WideToUTF16(kTestCases[i].text));
+ SpellcheckWordIterator iterator;
+ EXPECT_TRUE(iterator.Initialize(&attributes, true));
+ EXPECT_TRUE(iterator.SetText(input_word.c_str(), input_word.length()));
+
+ base::string16 actual_word;
+ int actual_start, actual_len;
+ WordIteratorStatus status = GetNextNonSkippableWord(
+ &iterator, &actual_word, &actual_start, &actual_len);
+
+ EXPECT_EQ(SpellcheckWordIterator::WordIteratorStatus::IS_WORD, status);
+ if (kTestCases[i].left_to_right)
+ EXPECT_EQ(input_word, actual_word);
+ else
+ EXPECT_NE(input_word, actual_word);
+ }
+}
+
+// Verify SpellcheckWordIterator treats typographical apostrophe as a part of
+// the word.
+TEST(SpellcheckWordIteratorTest, TypographicalApostropheIsPartOfWord) {
+ static const struct {
+ const char* language;
+ const wchar_t* input;
+ const wchar_t* expected;
+ } kTestCases[] = {
+ // Typewriter apostrophe:
+ {"en-AU", L"you're", L"you're"},
+ {"en-CA", L"you're", L"you're"},
+ {"en-GB", L"you're", L"you're"},
+ {"en-US", L"you're", L"you're"},
+ {"en-US", L"!!!!you're", L"you're"},
+ // Typographical apostrophe:
+ {"en-AU", L"you\x2019re", L"you\x2019re"},
+ {"en-CA", L"you\x2019re", L"you\x2019re"},
+ {"en-GB", L"you\x2019re", L"you\x2019re"},
+ {"en-US", L"you\x2019re", L"you\x2019re"},
+ {"en-US", L"....you\x2019re", L"you\x2019re"},
+ };
+
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ SpellcheckCharAttribute attributes;
+ attributes.SetDefaultLanguage(kTestCases[i].language);
+
+ base::string16 input_word(base::WideToUTF16(kTestCases[i].input));
+ base::string16 expected_word(base::WideToUTF16(kTestCases[i].expected));
+ SpellcheckWordIterator iterator;
+ EXPECT_TRUE(iterator.Initialize(&attributes, true));
+ EXPECT_TRUE(iterator.SetText(input_word.c_str(), input_word.length()));
+
+ base::string16 actual_word;
+ int actual_start, actual_len;
+ WordIteratorStatus status = GetNextNonSkippableWord(
+ &iterator, &actual_word, &actual_start, &actual_len);
+
+ EXPECT_EQ(SpellcheckWordIterator::WordIteratorStatus::IS_WORD, status);
+ EXPECT_EQ(expected_word, actual_word);
+ EXPECT_LE(0, actual_start);
+ EXPECT_EQ(expected_word.length(),
+ static_cast<base::string16::size_type>(actual_len));
+ }
+}
+
+TEST(SpellcheckWordIteratorTest, Initialization) {
+ // Test initialization works when a default language is set.
+ {
+ SpellcheckCharAttribute attributes;
+ attributes.SetDefaultLanguage("en-US");
+
+ SpellcheckWordIterator iterator;
+ EXPECT_TRUE(iterator.Initialize(&attributes, true));
+ }
+
+ // Test initialization fails when no default language is set.
+ {
+ SpellcheckCharAttribute attributes;
+
+ SpellcheckWordIterator iterator;
+ EXPECT_FALSE(iterator.Initialize(&attributes, true));
+ }
+}
+
+// This test uses English rules to check that different character set
+// combinations properly find word breaks and skippable characters.
+TEST(SpellcheckWordIteratorTest, FindSkippableWordsEnglish) {
+ // A string containing the English word "foo", followed by two Khmer
+ // characters, the English word "Can", and then two Russian characters and
+ // punctuation.
+ base::string16 text(
+ base::WideToUTF16(L"foo \x1791\x17C1 Can \x041C\x0438..."));
+ BreakIterator iter(text, GetRulesForLanguage("en-US"));
+ ASSERT_TRUE(iter.Init());
+
+ EXPECT_TRUE(iter.Advance());
+ // Finds "foo".
+ EXPECT_EQ(base::UTF8ToUTF16("foo"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK);
+ EXPECT_TRUE(iter.Advance());
+ // Finds the space and then the Khmer characters.
+ EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::WideToUTF16(L"\x1791\x17C1"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ // Finds the next space and "Can".
+ EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16("Can"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK);
+ EXPECT_TRUE(iter.Advance());
+ // Finds the next space and each Russian character.
+ EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::WideToUTF16(L"\x041C"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::WideToUTF16(L"\x0438"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ // Finds the periods at the end.
+ EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_FALSE(iter.Advance());
+}
+
+// This test uses Russian rules to check that different character set
+// combinations properly find word breaks and skippable characters.
+TEST(SpellcheckWordIteratorTest, FindSkippableWordsRussian) {
+ // A string containing punctuation followed by two Russian characters, the
+ // English word "Can", and then two Khmer characters.
+ base::string16 text(base::WideToUTF16(L".;\x041C\x0438 Can \x1791\x17C1 "));
+ BreakIterator iter(text, GetRulesForLanguage("ru-RU"));
+ ASSERT_TRUE(iter.Init());
+
+ EXPECT_TRUE(iter.Advance());
+ // Finds the period and semicolon.
+ EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16(";"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ // Finds all the Russian characters.
+ EXPECT_EQ(base::WideToUTF16(L"\x041C\x0438"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK);
+ EXPECT_TRUE(iter.Advance());
+ // Finds the space and each character in "Can".
+ EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16("C"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16("a"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16("n"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ // Finds the next space, the Khmer characters, and the last two spaces.
+ EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::WideToUTF16(L"\x1791\x17C1"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_FALSE(iter.Advance());
+}
+
+// This test uses Khmer rules to check that different character set combinations
+// properly find word breaks and skippable characters. Khmer does not use spaces
+// between words and uses a dictionary to determine word breaks instead.
+TEST(SpellcheckWordIteratorTest, FindSkippableWordsKhmer) {
+ // A string containing two Russian characters followed by two, three, and
+ // two-character Khmer words, and then English characters and punctuation.
+ base::string16 text(base::WideToUTF16(
+ L"\x041C\x0438 \x178F\x17BE\x179B\x17C4\x1780\x1798\x1780zoo. ,"));
+ BreakIterator iter(text, GetRulesForLanguage("km"));
+ ASSERT_TRUE(iter.Init());
+
+ EXPECT_TRUE(iter.Advance());
+ // Finds each Russian character and the space.
+ EXPECT_EQ(base::WideToUTF16(L"\x041C"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::WideToUTF16(L"\x0438"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ // Finds the first two-character Khmer word.
+ EXPECT_EQ(base::WideToUTF16(L"\x178F\x17BE"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK);
+ EXPECT_TRUE(iter.Advance());
+ // Finds the three-character Khmer word and then the next two-character word.
+ // Note: Technically these are two different Khmer words so the Khmer language
+ // rule should find a break between them but due to the heuristic/statistical
+ // nature of the Khmer word breaker it does not.
+ EXPECT_EQ(base::WideToUTF16(L"\x179B\x17C4\x1780\x1798\x1780"),
+ iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_WORD_BREAK);
+ EXPECT_TRUE(iter.Advance());
+ // Finds each character in "zoo".
+ EXPECT_EQ(base::UTF8ToUTF16("z"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16("o"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16("o"), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ // Finds the period, space, and comma.
+ EXPECT_EQ(base::UTF8ToUTF16("."), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_EQ(base::UTF8ToUTF16(","), iter.GetString());
+ EXPECT_EQ(iter.GetWordBreakStatus(), BreakIterator::IS_SKIPPABLE_WORD);
+ EXPECT_FALSE(iter.Advance());
+}
diff --git a/chromium/components/spellcheck/renderer/spelling_engine.h b/chromium/components/spellcheck/renderer/spelling_engine.h
new file mode 100644
index 00000000000..2fb32a800c4
--- /dev/null
+++ b/chromium/components/spellcheck/renderer/spelling_engine.h
@@ -0,0 +1,34 @@
+// 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 COMPONENTS_SPELLCHECK_RENDERER_SPELLING_ENGINE_H_
+#define COMPONENTS_SPELLCHECK_RENDERER_SPELLING_ENGINE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/strings/string16.h"
+
+// Creates the platform's "native" spelling engine.
+class SpellingEngine* CreateNativeSpellingEngine();
+
+// Interface to different spelling engines.
+class SpellingEngine {
+ public:
+ virtual ~SpellingEngine() {}
+
+ // Initialize spelling engine with browser-side info. Must be called before
+ // any other functions are called.
+ virtual void Init(base::File bdict_file) = 0;
+ virtual bool InitializeIfNeeded() = 0;
+ virtual bool IsEnabled() = 0;
+ virtual bool CheckSpelling(const base::string16& word_to_check, int tag) = 0;
+ virtual void FillSuggestionList(
+ const base::string16& wrong_word,
+ std::vector<base::string16>* optional_suggestions) = 0;
+};
+
+#endif // COMPONENTS_SPELLCHECK_RENDERER_SPELLING_ENGINE_H_
+
diff --git a/chromium/components/ssl_config.gypi b/chromium/components/ssl_config.gypi
deleted file mode 100644
index 2e742b21ef6..00000000000
--- a/chromium/components/ssl_config.gypi
+++ /dev/null
@@ -1,31 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/ssl_config
- 'target_name': 'ssl_config',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- 'content_settings_core_browser',
- 'content_settings_core_common',
- 'prefs/prefs.gyp:prefs',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'ssl_config/ssl_config_prefs.cc',
- 'ssl_config/ssl_config_prefs.h',
- 'ssl_config/ssl_config_service_manager.h',
- 'ssl_config/ssl_config_service_manager_pref.cc',
- 'ssl_config/ssl_config_switches.cc',
- 'ssl_config/ssl_config_switches.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/ssl_config/BUILD.gn b/chromium/components/ssl_config/BUILD.gn
index babcc5cb0bd..d514ca633d5 100644
--- a/chromium/components/ssl_config/BUILD.gn
+++ b/chromium/components/ssl_config/BUILD.gn
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/ssl_config.gypi:ssl_config
-source_set("ssl_config") {
+static_library("ssl_config") {
sources = [
"ssl_config_prefs.cc",
"ssl_config_prefs.h",
@@ -30,6 +29,7 @@ source_set("unit_tests") {
deps = [
":ssl_config",
"//base",
+ "//base/test:test_support",
"//components/prefs:test_support",
"//net",
"//testing/gtest",
diff --git a/chromium/components/ssl_config/ssl_config_prefs.cc b/chromium/components/ssl_config/ssl_config_prefs.cc
index bdd7e21c502..540be23ad3a 100644
--- a/chromium/components/ssl_config/ssl_config_prefs.cc
+++ b/chromium/components/ssl_config/ssl_config_prefs.cc
@@ -11,6 +11,7 @@ namespace prefs {
const char kCertRevocationCheckingEnabled[] = "ssl.rev_checking.enabled";
const char kCertRevocationCheckingRequiredLocalAnchors[] =
"ssl.rev_checking.required_for_local_anchors";
+const char kCertEnableSha1LocalAnchors[] = "ssl.sha1_enabled_for_local_anchors";
const char kSSLVersionMin[] = "ssl.version_min";
const char kSSLVersionMax[] = "ssl.version_max";
const char kCipherSuiteBlacklist[] = "ssl.cipher_suites.blacklist";
diff --git a/chromium/components/ssl_config/ssl_config_prefs.h b/chromium/components/ssl_config/ssl_config_prefs.h
index d43f4926793..7f19e1ecdd3 100644
--- a/chromium/components/ssl_config/ssl_config_prefs.h
+++ b/chromium/components/ssl_config/ssl_config_prefs.h
@@ -10,6 +10,7 @@ namespace prefs {
extern const char kCertRevocationCheckingEnabled[];
extern const char kCertRevocationCheckingRequiredLocalAnchors[];
+extern const char kCertEnableSha1LocalAnchors[];
extern const char kSSLVersionMin[];
extern const char kSSLVersionMax[];
extern const char kCipherSuiteBlacklist[];
diff --git a/chromium/components/ssl_config/ssl_config_service_manager_pref.cc b/chromium/components/ssl_config/ssl_config_service_manager_pref.cc
index cd67d4c86c3..a3736de9bb1 100644
--- a/chromium/components/ssl_config/ssl_config_service_manager_pref.cc
+++ b/chromium/components/ssl_config/ssl_config_service_manager_pref.cc
@@ -79,6 +79,8 @@ uint16_t SSLProtocolVersionFromString(const std::string& version_str) {
version = net::SSL_PROTOCOL_VERSION_TLS1_1;
} else if (version_str == switches::kSSLVersionTLSv12) {
version = net::SSL_PROTOCOL_VERSION_TLS1_2;
+ } else if (version_str == switches::kSSLVersionTLSv13) {
+ version = net::SSL_PROTOCOL_VERSION_TLS1_3;
}
return version;
}
@@ -170,6 +172,7 @@ class SSLConfigServiceManagerPref : public ssl_config::SSLConfigServiceManager {
// The local_state prefs (should only be accessed from UI thread)
BooleanPrefMember rev_checking_enabled_;
BooleanPrefMember rev_checking_required_local_anchors_;
+ BooleanPrefMember sha1_local_anchors_enabled_;
StringPrefMember ssl_version_min_;
StringPrefMember ssl_version_max_;
BooleanPrefMember dhe_enabled_;
@@ -208,6 +211,9 @@ SSLConfigServiceManagerPref::SSLConfigServiceManagerPref(
rev_checking_required_local_anchors_.Init(
ssl_config::prefs::kCertRevocationCheckingRequiredLocalAnchors,
local_state, local_state_callback);
+ sha1_local_anchors_enabled_.Init(
+ ssl_config::prefs::kCertEnableSha1LocalAnchors, local_state,
+ local_state_callback);
ssl_version_min_.Init(ssl_config::prefs::kSSLVersionMin, local_state,
local_state_callback);
ssl_version_max_.Init(ssl_config::prefs::kSSLVersionMax, local_state,
@@ -235,6 +241,8 @@ void SSLConfigServiceManagerPref::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(
ssl_config::prefs::kCertRevocationCheckingRequiredLocalAnchors,
default_config.rev_checking_required_local_anchors);
+ registry->RegisterBooleanPref(ssl_config::prefs::kCertEnableSha1LocalAnchors,
+ default_config.sha1_local_anchors_enabled);
registry->RegisterStringPref(ssl_config::prefs::kSSLVersionMin,
std::string());
registry->RegisterStringPref(ssl_config::prefs::kSSLVersionMax,
@@ -262,7 +270,7 @@ void SSLConfigServiceManagerPref::OnPreferenceChanged(
// update |cached_config_|.
io_task_runner_->PostTask(FROM_HERE,
base::Bind(&SSLConfigServicePref::SetNewSSLConfig,
- ssl_config_service_.get(), new_config));
+ ssl_config_service_, new_config));
}
void SSLConfigServiceManagerPref::GetSSLConfigFromPrefs(
@@ -275,6 +283,7 @@ void SSLConfigServiceManagerPref::GetSSLConfigFromPrefs(
config->rev_checking_enabled = false;
config->rev_checking_required_local_anchors =
rev_checking_required_local_anchors_.GetValue();
+ config->sha1_local_anchors_enabled = sha1_local_anchors_enabled_.GetValue();
std::string version_min_str = ssl_version_min_.GetValue();
std::string version_max_str = ssl_version_max_.GetValue();
config->version_min = net::kDefaultSSLVersionMin;
@@ -285,8 +294,7 @@ void SSLConfigServiceManagerPref::GetSSLConfigFromPrefs(
config->version_min = version_min;
}
if (version_max) {
- uint16_t supported_version_max = config->version_max;
- config->version_max = std::min(supported_version_max, version_max);
+ config->version_max = version_max;
}
config->disabled_cipher_suites = disabled_cipher_suites_;
config->dhe_enabled = dhe_enabled_.GetValue();
diff --git a/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc b/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
index ec2aefa5338..cecdb8efdc8 100644
--- a/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
+++ b/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "components/prefs/testing_pref_service.h"
@@ -181,10 +182,8 @@ TEST_F(SSLConfigServiceManagerPrefTest, NoSSL3) {
// Tests that DHE may be re-enabled via features.
TEST_F(SSLConfigServiceManagerPrefTest, DHEFeature) {
// Toggle the feature.
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine("DHECiphers", std::string());
- base::FeatureList::SetInstance(std::move(feature_list));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("DHECiphers", std::string());
TestingPrefServiceSimple local_state;
SSLConfigServiceManager::RegisterPrefs(local_state.registry());
diff --git a/chromium/components/ssl_config/ssl_config_switches.cc b/chromium/components/ssl_config/ssl_config_switches.cc
index 05ed87b7f7a..2152f87e7bb 100644
--- a/chromium/components/ssl_config/ssl_config_switches.cc
+++ b/chromium/components/ssl_config/ssl_config_switches.cc
@@ -6,10 +6,12 @@
namespace switches {
-// Specifies the maximum SSL/TLS version ("tls1", "tls1.1", or "tls1.2").
+// Specifies the maximum SSL/TLS version ("tls1", "tls1.1", "tls1.2", or
+// "tls1.3").
const char kSSLVersionMax[] = "ssl-version-max";
-// Specifies the minimum SSL/TLS version ("tls1", "tls1.1", or "tls1.2").
+// Specifies the minimum SSL/TLS version ("tls1", "tls1.1", "tls1.2", or
+// "tls1.3").
const char kSSLVersionMin[] = "ssl-version-min";
// These values aren't switches, but rather the values that kSSLVersionMax and
@@ -17,5 +19,6 @@ const char kSSLVersionMin[] = "ssl-version-min";
const char kSSLVersionTLSv1[] = "tls1";
const char kSSLVersionTLSv11[] = "tls1.1";
const char kSSLVersionTLSv12[] = "tls1.2";
+const char kSSLVersionTLSv13[] = "tls1.3";
} // namespace switches
diff --git a/chromium/components/ssl_config/ssl_config_switches.h b/chromium/components/ssl_config/ssl_config_switches.h
index 795f8ff8163..34c7d24ca67 100644
--- a/chromium/components/ssl_config/ssl_config_switches.h
+++ b/chromium/components/ssl_config/ssl_config_switches.h
@@ -12,6 +12,7 @@ extern const char kSSLVersionMin[];
extern const char kSSLVersionTLSv1[];
extern const char kSSLVersionTLSv11[];
extern const char kSSLVersionTLSv12[];
+extern const char kSSLVersionTLSv13[];
} // namespace switches
diff --git a/chromium/components/ssl_errors.gypi b/chromium/components/ssl_errors.gypi
deleted file mode 100644
index 9d4f39551c5..00000000000
--- a/chromium/components/ssl_errors.gypi
+++ /dev/null
@@ -1,31 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/ssl_errors
- 'target_name': 'ssl_errors',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base_i18n',
- '../net/net.gyp:net',
- '../ui/base/ui_base.gyp:ui_base',
- 'components_strings.gyp:components_strings',
- 'network_time',
- 'url_formatter/url_formatter.gyp:url_formatter',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'ssl_errors/error_classification.cc',
- 'ssl_errors/error_classification.h',
- 'ssl_errors/error_info.cc',
- 'ssl_errors/error_info.h',
- ]
- }
- ]
-} \ No newline at end of file
diff --git a/chromium/components/ssl_errors/BUILD.gn b/chromium/components/ssl_errors/BUILD.gn
index 7ed952b84b8..d58ffa37b45 100644
--- a/chromium/components/ssl_errors/BUILD.gn
+++ b/chromium/components/ssl_errors/BUILD.gn
@@ -2,8 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/ssl_errors.gypi
-source_set("ssl_errors") {
+static_library("ssl_errors") {
sources = [
"error_classification.cc",
"error_classification.h",
diff --git a/chromium/components/ssl_errors/error_classification.cc b/chromium/components/ssl_errors/error_classification.cc
index 579c5cc0150..b6867d7bc6e 100644
--- a/chromium/components/ssl_errors/error_classification.cc
+++ b/chromium/components/ssl_errors/error_classification.cc
@@ -38,6 +38,26 @@ using base::TimeDelta;
namespace ssl_errors {
namespace {
+// Describes the result of getting network time and if it was
+// unavailable, why it was unavailable. This enum is being histogrammed
+// so do not reorder or remove values.
+enum NetworkClockState {
+ // The clock state relative to network time is unknown because the
+ // NetworkTimeTracker has no information from the network.
+ NETWORK_CLOCK_STATE_UNKNOWN_NO_SYNC = 0,
+ // The clock state relative to network time is unknown because the
+ // user's clock has fallen out of sync with the latest information
+ // from the network (due to e.g. suspend/resume).
+ NETWORK_CLOCK_STATE_UNKNOWN_SYNC_LOST,
+ // The clock is "close enough" to the network time.
+ NETWORK_CLOCK_STATE_OK,
+ // The clock is in the past relative to network time.
+ NETWORK_CLOCK_STATE_CLOCK_IN_PAST,
+ // The clock is in the future relative to network time.
+ NETWORK_CLOCK_STATE_CLOCK_IN_FUTURE,
+ NETWORK_CLOCK_STATE_MAX
+};
+
// Events for UMA. Do not reorder or change!
enum SSLInterstitialCause {
CLOCK_PAST,
@@ -207,15 +227,25 @@ ClockState GetClockState(
base::Time now_network;
base::TimeDelta uncertainty;
const base::TimeDelta kNetworkTimeFudge = base::TimeDelta::FromMinutes(5);
- ClockState network_state = CLOCK_STATE_UNKNOWN;
- if (network_time_tracker->GetNetworkTime(&now_network, &uncertainty)) {
- if (now_system < now_network - uncertainty - kNetworkTimeFudge) {
- network_state = CLOCK_STATE_PAST;
- } else if (now_system > now_network + uncertainty + kNetworkTimeFudge) {
- network_state = CLOCK_STATE_FUTURE;
- } else {
- network_state = CLOCK_STATE_OK;
- }
+ NetworkClockState network_state = NETWORK_CLOCK_STATE_MAX;
+ network_time::NetworkTimeTracker::NetworkTimeResult network_time_result =
+ network_time_tracker->GetNetworkTime(&now_network, &uncertainty);
+ switch (network_time_result) {
+ case network_time::NetworkTimeTracker::NETWORK_TIME_AVAILABLE:
+ if (now_system < now_network - uncertainty - kNetworkTimeFudge) {
+ network_state = NETWORK_CLOCK_STATE_CLOCK_IN_PAST;
+ } else if (now_system > now_network + uncertainty + kNetworkTimeFudge) {
+ network_state = NETWORK_CLOCK_STATE_CLOCK_IN_FUTURE;
+ } else {
+ network_state = NETWORK_CLOCK_STATE_OK;
+ }
+ break;
+ case network_time::NetworkTimeTracker::NETWORK_TIME_SYNC_LOST:
+ network_state = NETWORK_CLOCK_STATE_UNKNOWN_SYNC_LOST;
+ break;
+ case network_time::NetworkTimeTracker::NETWORK_TIME_NO_SYNC:
+ network_state = NETWORK_CLOCK_STATE_UNKNOWN_NO_SYNC;
+ break;
}
ClockState build_time_state = CLOCK_STATE_UNKNOWN;
@@ -228,13 +258,28 @@ ClockState GetClockState(
build_time_state = CLOCK_STATE_FUTURE;
}
- UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.clockstate.network",
- network_state, CLOCK_STATE_MAX);
+ UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.clockstate.network2",
+ network_time_result, NETWORK_CLOCK_STATE_MAX);
UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.clockstate.build_time",
build_time_state, CLOCK_STATE_MAX);
- return network_state == CLOCK_STATE_UNKNOWN ? build_time_state
- : network_state;
+ switch (network_state) {
+ case NETWORK_CLOCK_STATE_UNKNOWN_NO_SYNC:
+ case NETWORK_CLOCK_STATE_UNKNOWN_SYNC_LOST:
+ return build_time_state;
+ case NETWORK_CLOCK_STATE_OK:
+ return CLOCK_STATE_OK;
+ case NETWORK_CLOCK_STATE_CLOCK_IN_PAST:
+ return CLOCK_STATE_PAST;
+ case NETWORK_CLOCK_STATE_CLOCK_IN_FUTURE:
+ return CLOCK_STATE_FUTURE;
+ case NETWORK_CLOCK_STATE_MAX:
+ NOTREACHED();
+ return CLOCK_STATE_UNKNOWN;
+ }
+
+ NOTREACHED();
+ return CLOCK_STATE_UNKNOWN;
}
void SetBuildTimeForTesting(const base::Time& testing_time) {
diff --git a/chromium/components/ssl_errors/error_classification.h b/chromium/components/ssl_errors/error_classification.h
index 99ab0f1dc8b..9bcaeae0475 100644
--- a/chromium/components/ssl_errors/error_classification.h
+++ b/chromium/components/ssl_errors/error_classification.h
@@ -108,7 +108,7 @@ void RecordUMAStatisticsForClockInterstitial(bool overridable,
HostnameTokens Tokenize(const std::string& name);
// Sets a clock for browser tests that check the build time. Used by
-// IsUserClockInThePast and IsUserClockInTheFuture.
+// GetClockState().
void SetBuildTimeForTesting(const base::Time& testing_time);
// Returns true if the hostname has a known Top Level Domain.
diff --git a/chromium/components/ssl_errors/error_classification_unittest.cc b/chromium/components/ssl_errors/error_classification_unittest.cc
index 71b67a4c3f7..425a9f2e8ee 100644
--- a/chromium/components/ssl_errors/error_classification_unittest.cc
+++ b/chromium/components/ssl_errors/error_classification_unittest.cc
@@ -6,6 +6,7 @@
#include "base/files/file_path.h"
#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
#include "base/strings/string_split.h"
#include "base/time/default_clock.h"
#include "base/time/default_tick_clock.h"
@@ -192,8 +193,8 @@ TEST_F(SSLErrorClassificationTest, GetClockState) {
network_time::NetworkTimeTracker::RegisterPrefs(pref_service.registry());
base::MessageLoop loop;
network_time::NetworkTimeTracker network_time_tracker(
- base::WrapUnique(new base::DefaultClock()),
- base::WrapUnique(new base::DefaultTickClock()), &pref_service,
+ base::MakeUnique<base::DefaultClock>(),
+ base::MakeUnique<base::DefaultTickClock>(), &pref_service,
new net::TestURLRequestContextGetter(
base::ThreadTaskRunnerHandle::Get()));
diff --git a/chromium/components/ssl_errors_strings.grdp b/chromium/components/ssl_errors_strings.grdp
index 9b16fb5683e..b79b74353d7 100644
--- a/chromium/components/ssl_errors_strings.grdp
+++ b/chromium/components/ssl_errors_strings.grdp
@@ -2,7 +2,7 @@
<grit-part>
<message name="IDS_CERT_ERROR_COMMON_NAME_INVALID_DETAILS" desc="Details for an unsafe common name in an X509 certificate">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is from <ph name="DOMAIN2">&lt;strong&gt;$2<ex>fakepaypal.com</ex>&lt;/strong&gt;</ph>. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is from <ph name="DOMAIN2">&lt;strong&gt;$2<ex>fakepaypal.com</ex>&lt;/strong&gt;</ph>. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_COMMON_NAME_INVALID_DESCRIPTION" desc="Description for an unsafe common name in an X509 certificate">
Server's certificate does not match the URL.
@@ -10,8 +10,8 @@
<message name="IDS_CERT_ERROR_EXPIRED_DETAILS" desc="Details for an expired X509 certificate [ICU Syntax]">
{1, plural,
- =1 {This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;{0}<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate expired yesterday. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_DATE">{2, date, full}<ex>Monday, July 16, 2012</ex></ph>. Does that look right? If not, you should correct your system's clock and then refresh this page.}
- other {This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;{0}<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate expired # days ago. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_DATE">{2, date, full}<ex>Monday, July 16, 2012</ex></ph>. Does that look right? If not, you should correct your system's clock and then refresh this page.}}
+ =1 {This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;{0}<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate expired yesterday. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_DATE">{2, date, full}<ex>Monday, July 16, 2012</ex></ph>. Does that look right? If not, you should correct your system's clock and then refresh this page. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.}
+ other {This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;{0}<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate expired # days ago. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_DATE">{2, date, full}<ex>Monday, July 16, 2012</ex></ph>. Does that look right? If not, you should correct your system's clock and then refresh this page. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.}}
</message>
<message name="IDS_CERT_ERROR_EXPIRED_DESCRIPTION" desc="Description for an expired X509 certificate">
Server's certificate has expired.
@@ -19,22 +19,22 @@
<message name="IDS_CERT_ERROR_NOT_YET_VALID_DETAILS" desc="Details for an X509 certificate that is not yet valid [ICU Syntax]">
{1, plural,
- =1 {This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;{0}<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is supposedly from tomorrow. This may be caused by a misconfiguration or an attacker intercepting your connection.}
- other {This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;{0}<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is supposedly from # days in the future. This may be caused by a misconfiguration or an attacker intercepting your connection.}}
+ =1 {This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;{0}<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is supposedly from tomorrow. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.}
+ other {This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;{0}<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is supposedly from # days in the future. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.}}
</message>
<message name="IDS_CERT_ERROR_NOT_YET_VALID_DESCRIPTION" desc="Description for an X509 certificate that is not yet valid">
Server's certificate is not yet valid.
</message>
<message name="IDS_CERT_ERROR_NOT_VALID_AT_THIS_TIME_DETAILS" desc="Details for a chain with a X509 certificate that is not valid at this time.">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not valid at this time. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not valid at this time. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_NOT_VALID_AT_THIS_TIME_DESCRIPTION" desc="Description for a chain with a X509 certificate that is not valid at this time.">
Server's certificate is not valid at this time.
</message>
<message name="IDS_CERT_ERROR_CHAIN_EXPIRED_DETAILS" desc="Details for an expired root or intermediate cert in chain">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate expired. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_TIME">$3<ex>July 18, 2012</ex></ph>. Does that look right? If not, you should correct your system's clock and then refresh this page.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate expired. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_TIME">$3<ex>July 18, 2012</ex></ph>. Does that look right? If not, you should correct your system's clock and then refresh this page. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_CHAIN_EXPIRED_DESCRIPTION" desc="Description for an expired intermediate/root certificate in chain">
A root or intermediate certificate has expired.
@@ -45,62 +45,62 @@
</message>
<message name="IDS_CERT_ERROR_CONTAINS_ERRORS_DETAILS" desc="Details of the error page for an X509 certificate that contains errors">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate contains errors. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate contains errors. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_CONTAINS_ERRORS_DESCRIPTION" desc="Description of the error page for an X509 certificate that contains errors">
Server's certificate contains errors.
</message>
<message name="IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_DETAILS" desc="Details for being unable to check revocation status of an X509 certificate">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate might be revoked. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate might be revoked. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_DESCRIPTION" desc="Description for being unable to check revocation status of an X509 certificate">
Server's certificate cannot be checked.
</message>
<message name="IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DETAILS" desc="Details for not finding a revocation mechanism in an X509 certificate">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate might be revoked. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate might be revoked. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DESCRIPTION" desc="Description for not finding a revocation mechanism in an X509 certificate">
No revocation mechanism found.
</message>
<message name="IDS_CERT_ERROR_REVOKED_CERT_DETAILS" desc="Details of the error page for a revoked certificate">
- You attempted to reach <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>, but the certificate that the server presented has been revoked by its issuer. This means that the security credentials the server presented absolutely should not be trusted. You may be communicating with an attacker.
+ You attempted to reach <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>, but the certificate that the server presented has been revoked by its issuer. This means that the security credentials the server presented absolutely should not be trusted. You may be communicating with an attacker. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_REVOKED_CERT_DESCRIPTION" desc="Description of the error page for a revoked certificate">
Server's certificate has been revoked.
</message>
<message name="IDS_CERT_ERROR_INVALID_CERT_DETAILS" desc="Details of the error page for an X509 certificate that is invalid">
- You attempted to reach <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>, but the server presented an invalid certificate.
+ You attempted to reach <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>, but the server presented an invalid certificate. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_INVALID_CERT_DESCRIPTION" desc="Description of the error page for an X509 certificate that is invalid">
Server's certificate is invalid.
</message>
<message name="IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DETAILS" desc="Details of the error page for a certificate signed using a weak signature algorithm">
- You attempted to reach <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>, but the server presented a certificate signed using a weak signature algorithm. This means that the security credentials the server presented could have been forged, and the server may not be the server you expected (you may be communicating with an attacker).
+ You attempted to reach <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>, but the server presented a certificate signed using a weak signature algorithm. This means that the security credentials the server presented could have been forged, and the server may not be the server you expected (you may be communicating with an attacker). <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DESCRIPTION" desc="Description of the error page for a certificate signed using a weak signature algorithm">
Server's certificate is signed using a weak signature algorithm.
</message>
<message name="IDS_CERT_ERROR_WEAK_KEY_DETAILS" desc="Details of the error page for a certificate containing a weak key">
- You attempted to reach <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>, but the server presented a certificate containing a weak key. An attacker could have broken the private key, and the server may not be the server you expected (you may be communicating with an attacker).
+ You attempted to reach <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>, but the server presented a certificate containing a weak key. An attacker could have broken the private key, and the server may not be the server you expected (you may be communicating with an attacker). <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION" desc="Description of the error page for a certificate containing a weak key">
The server certificate contains a weak cryptographic key.
</message>
<message name="IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DETAILS" desc="Details of the error page for a certificate that contains a name outside of its scope">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate might have been issued fraudulently. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate might have been issued fraudulently. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DESCRIPTION" desc="Description of the error page for a certificate that contains a name outside of its scope">
Server's certificate violates name constraints.
</message>
<message name="IDS_CERT_ERROR_VALIDITY_TOO_LONG_DETAILS" desc="Details of the error page for a certificate whose validity period is too long">
- You attempted to reach <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>, but the server presented a certificate whose validity period is too long to be trustworthy.
+ You attempted to reach <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>, but the server presented a certificate whose validity period is too long to be trustworthy. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_VALIDITY_TOO_LONG_DESCRIPTION" desc="Description of the error page for a certificate whose validity period is too long">
The server certificate has a validity period that is too long.
@@ -114,14 +114,14 @@
</message>
<message name="IDS_CERT_ERROR_SUMMARY_PINNING_FAILURE_DETAILS" desc="Details of the error page for a certificate which doesn't match the built-in pins for that name">
- The server presented a certificate that doesn't match built-in expectations. These expectations are included for certain, high-security websites in order to protect you.
+ The server presented a certificate that doesn't match built-in expectations. These expectations are included for certain, high-security websites in order to protect you. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_SUMMARY_PINNING_FAILURE_DESCRIPTION" desc="Description of the error page for a certificate which doesn't match the built-in pins for that name">
The server's certificate appears to be a forgery.
</message>
<message name="IDS_CERT_ERROR_CERTIFICATE_TRANSPARENCY_REQUIRED_DETAILS" desc="Details of the error page for a site or certificate that requires compliance with the Chromium Certificate Transparency Policy">
- The server presented a certificate that was not publicly disclosed using the Certificate Transparency policy. This is a requirement for some certificates, to ensure that they are trustworthy and protect against attackers.
+ The server presented a certificate that was not publicly disclosed using the Certificate Transparency policy. This is a requirement for some certificates, to ensure that they are trustworthy and protect against attackers. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
<message name="IDS_CERT_ERROR_CERTIFICATE_TRANSPARENCY_REQUIRED_DESCRIPTION" desc="Description of the error page for a site or certificate that requires compliance with the Chromium Certificate Transparency Policy">
The server's certificate was not disclosed via Certificate Transparency.
@@ -130,17 +130,17 @@
<if expr="_google_chrome">
<if expr="is_ios">
<message name="IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS" desc="Details for an X509 certificate with an invalid authority">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by Chrome. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by Chrome. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
</if>
<if expr="is_android">
<message name="IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS" desc="Details for an X509 certificate with an invalid authority">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by your device's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by your device's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
</if>
<if expr="not is_ios and not is_android">
<message name="IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS" desc="Details for an X509 certificate with an invalid authority">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by your computer's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by your computer's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
</if>
</if>
@@ -148,17 +148,17 @@
<if expr="not _google_chrome">
<if expr="is_ios">
<message name="IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS" desc="Details for an X509 certificate with an invalid authority">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by Chromium. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by Chromium. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
</if>
<if expr="is_android">
<message name="IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS" desc="Details for an X509 certificate with an invalid authority">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by your device's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by your device's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
</if>
<if expr="not is_ios and not is_android">
<message name="IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS" desc="Details for an X509 certificate with an invalid authority">
- This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by your computer's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection.
+ This server could not prove that it is <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph>; its security certificate is not trusted by your computer's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>.
</message>
</if>
</if>
diff --git a/chromium/components/startup_metric_utils.gypi b/chromium/components/startup_metric_utils.gypi
deleted file mode 100644
index b080530705d..00000000000
--- a/chromium/components/startup_metric_utils.gypi
+++ /dev/null
@@ -1,90 +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.
-
-# We have 2 separate browser targets because //components/html_viewer requires
-# startup_metric_utils_browser, but has symbols that conflict with mojo symbols
-# that startup_metric_utils_browser_host indirectly depends on.
-
-{
- 'targets': [
- {
- # GN version: //components/startup_metric_utils/browser:lib
- 'target_name': 'startup_metric_utils_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- 'components.gyp:version_info',
- 'prefs/prefs.gyp:prefs',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'startup_metric_utils/browser/pref_names.cc',
- 'startup_metric_utils/browser/pref_names.h',
- 'startup_metric_utils/browser/startup_metric_utils.cc',
- 'startup_metric_utils/browser/startup_metric_utils.h',
- ],
- },
- {
- # GN version: //components/startup_metric_utils/browser:host
- 'target_name': 'startup_metric_utils_browser_host',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- 'startup_metric_utils_browser',
- 'startup_metric_utils_interfaces'
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'startup_metric_utils/browser/startup_metric_host_impl.cc',
- 'startup_metric_utils/browser/startup_metric_host_impl.h',
- ],
- },
- {
- # GN version: //components/startup_metric_utils/common:interfaces
- 'target_name': 'startup_metric_utils_interfaces',
- 'type': 'static_library',
- 'sources': [
- 'startup_metric_utils/common/startup_metric.mojom',
- ],
- 'dependencies': [
- '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_custom_types_mojom',
- ],
- 'variables': {
- 'mojom_typemaps': [
- '<(DEPTH)/mojo/common/common_custom_types.typemap',
- ],
- },
- 'includes': [
- '../mojo/mojom_bindings_generator.gypi',
- ],
- },
- ],
- 'conditions': [
- ['OS == "win"', {
- 'targets': [
- {
- # GN version: //components/startup_metric_utils/common
- 'target_name': 'startup_metric_utils_win',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- 'components.gyp:variations',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'startup_metric_utils/common/pre_read_field_trial_utils_win.cc',
- 'startup_metric_utils/common/pre_read_field_trial_utils_win.h',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/startup_metric_utils/OWNERS b/chromium/components/startup_metric_utils/OWNERS
index f75fe2eb49d..221025c99d0 100644
--- a/chromium/components/startup_metric_utils/OWNERS
+++ b/chromium/components/startup_metric_utils/OWNERS
@@ -1,2 +1,2 @@
-erikchen@chromium.org
+fdoray@chromium.org
gab@chromium.org
diff --git a/chromium/components/startup_metric_utils/browser/BUILD.gn b/chromium/components/startup_metric_utils/browser/BUILD.gn
index cd407610db9..2f9f4176f9e 100644
--- a/chromium/components/startup_metric_utils/browser/BUILD.gn
+++ b/chromium/components/startup_metric_utils/browser/BUILD.gn
@@ -15,7 +15,7 @@ group("browser") {
]
}
-source_set("lib") {
+static_library("lib") {
sources = [
"pref_names.cc",
"pref_names.h",
@@ -30,7 +30,7 @@ source_set("lib") {
]
}
-source_set("host") {
+static_library("host") {
sources = [
"startup_metric_host_impl.cc",
"startup_metric_host_impl.h",
diff --git a/chromium/components/startup_metric_utils/browser/startup_metric_host_impl.cc b/chromium/components/startup_metric_utils/browser/startup_metric_host_impl.cc
index 055fec80354..d64d62602bc 100644
--- a/chromium/components/startup_metric_utils/browser/startup_metric_host_impl.cc
+++ b/chromium/components/startup_metric_utils/browser/startup_metric_host_impl.cc
@@ -5,21 +5,22 @@
#include "components/startup_metric_utils/browser/startup_metric_host_impl.h"
#include "components/startup_metric_utils/browser/startup_metric_utils.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
namespace startup_metric_utils {
-// static
-void StartupMetricHostImpl::Create(mojom::StartupMetricHostRequest request) {
- new StartupMetricHostImpl(std::move(request));
-}
-StartupMetricHostImpl::StartupMetricHostImpl(
- mojom::StartupMetricHostRequest request)
- : binding_(this, std::move(request)) {}
+StartupMetricHostImpl::StartupMetricHostImpl() = default;
StartupMetricHostImpl::~StartupMetricHostImpl() = default;
+// static
+void StartupMetricHostImpl::Create(mojom::StartupMetricHostRequest request) {
+ mojo::MakeStrongBinding(base::MakeUnique<StartupMetricHostImpl>(),
+ std::move(request));
+}
+
void StartupMetricHostImpl::RecordRendererMainEntryTime(
- const base::TimeTicks& renderer_main_entry_time) {
+ base::TimeTicks renderer_main_entry_time) {
startup_metric_utils::RecordRendererMainEntryTime(renderer_main_entry_time);
}
diff --git a/chromium/components/startup_metric_utils/browser/startup_metric_host_impl.h b/chromium/components/startup_metric_utils/browser/startup_metric_host_impl.h
index cf903f37139..6901e13bf56 100644
--- a/chromium/components/startup_metric_utils/browser/startup_metric_host_impl.h
+++ b/chromium/components/startup_metric_utils/browser/startup_metric_host_impl.h
@@ -10,22 +10,19 @@
#include "base/macros.h"
#include "base/time/time.h"
#include "components/startup_metric_utils/common/startup_metric.mojom.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
namespace startup_metric_utils {
class StartupMetricHostImpl : public mojom::StartupMetricHost {
public:
+ StartupMetricHostImpl();
+ ~StartupMetricHostImpl() override;
+
static void Create(mojom::StartupMetricHostRequest request);
private:
- explicit StartupMetricHostImpl(mojom::StartupMetricHostRequest request);
- ~StartupMetricHostImpl() override;
-
void RecordRendererMainEntryTime(
- const base::TimeTicks& renderer_main_entry_time) override;
-
- mojo::StrongBinding<mojom::StartupMetricHost> binding_;
+ base::TimeTicks renderer_main_entry_time) override;
DISALLOW_COPY_AND_ASSIGN(StartupMetricHostImpl);
};
diff --git a/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc b/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
index d2d64446972..6d9ffcc2da6 100644
--- a/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
+++ b/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
@@ -5,11 +5,12 @@
#include "components/startup_metric_utils/browser/startup_metric_utils.h"
#include <stddef.h>
+#include <stdint.h>
-#include <memory>
+#include <string>
+#include <vector>
#include "base/containers/hash_tables.h"
-#include "base/environment.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
@@ -28,7 +29,6 @@
#if defined(OS_WIN)
#include <winternl.h>
#include "base/win/win_util.h"
-#include "base/win/windows_version.h"
#endif
namespace startup_metric_utils {
@@ -48,14 +48,39 @@ base::LazyInstance<base::TimeTicks>::Leaky g_browser_main_entry_point_ticks =
base::LazyInstance<base::TimeTicks>::Leaky g_renderer_main_entry_point_ticks =
LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::TimeTicks>::Leaky
+ g_browser_exe_main_entry_point_ticks = LAZY_INSTANCE_INITIALIZER;
+
// Only used by RecordMainEntryTimeHistogram(), should go away with it (do not
// add new uses of this), see crbug.com/317481 for discussion on why it was kept
// as-is for now.
base::LazyInstance<base::Time>::Leaky g_browser_main_entry_point_time =
LAZY_INSTANCE_INITIALIZER;
+// An enumeration of startup temperatures. This must be kept in sync with the
+// UMA StartupType enumeration defined in histograms.xml.
+enum StartupTemperature {
+ // The startup was a cold start: nearly all of the binaries and resources were
+ // brought into memory using hard faults.
+ COLD_STARTUP_TEMPERATURE = 0,
+ // The startup was a warm start: the binaries and resources were mostly
+ // already resident in memory and effectively no hard faults were observed.
+ WARM_STARTUP_TEMPERATURE = 1,
+ // The startup type couldn't quite be classified as warm or cold, but rather
+ // was somewhere in between.
+ LUKEWARM_STARTUP_TEMPERATURE = 2,
+ // This must be after all meaningful values. All new values should be added
+ // above this one.
+ STARTUP_TEMPERATURE_COUNT,
+ // Startup temperature wasn't yet determined.
+ UNDETERMINED_STARTUP_TEMPERATURE
+};
+
StartupTemperature g_startup_temperature = UNDETERMINED_STARTUP_TEMPERATURE;
+constexpr int kUndeterminedStartupsWithCurrentVersion = 0;
+int g_startups_with_current_version = kUndeterminedStartupsWithCurrentVersion;
+
#if defined(OS_WIN)
// These values are taken from the Startup.BrowserMessageLoopStartHardFaultCount
@@ -67,11 +92,11 @@ StartupTemperature g_startup_temperature = UNDETERMINED_STARTUP_TEMPERATURE;
// Maximum number of hard faults tolerated for a startup to be classified as a
// warm start. Set at roughly the 40th percentile of the HardFaultCount
// histogram.
-const uint32_t WARM_START_HARD_FAULT_COUNT_THRESHOLD = 5;
+constexpr uint32_t kWarmStartHardFaultCountThreshold = 5;
// Minimum number of hard faults expected for a startup to be classified as a
// cold start. Set at roughly the 60th percentile of the HardFaultCount
// histogram.
-const uint32_t COLD_START_HARD_FAULT_COUNT_THRESHOLD = 1200;
+constexpr uint32_t kColdStartHardFaultCountThreshold = 1200;
// The struct used to return system process information via the NT internal
// QuerySystemInformation call. This is partially documented at
@@ -102,41 +127,96 @@ struct SYSTEM_PROCESS_INFORMATION_EX {
// The signature of the NtQuerySystemInformation function.
typedef NTSTATUS (WINAPI *NtQuerySystemInformationPtr)(
SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
+
+// Gets the hard fault count of the current process through |hard_fault_count|.
+// Returns true on success.
+bool GetHardFaultCountForCurrentProcess(uint32_t* hard_fault_count) {
+ DCHECK(hard_fault_count);
+
+ // Get the function pointer.
+ static const NtQuerySystemInformationPtr query_sys_info =
+ reinterpret_cast<NtQuerySystemInformationPtr>(::GetProcAddress(
+ GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation"));
+ if (query_sys_info == nullptr)
+ return false;
+
+ // The output of this system call depends on the number of threads and
+ // processes on the entire system, and this can change between calls. Retry
+ // a small handful of times growing the buffer along the way.
+ // NOTE: The actual required size depends entirely on the number of processes
+ // and threads running on the system. The initial guess suffices for
+ // ~100s of processes and ~1000s of threads.
+ std::vector<uint8_t> buffer(32 * 1024);
+ for (size_t tries = 0; tries < 3; ++tries) {
+ ULONG return_length = 0;
+ const NTSTATUS status =
+ query_sys_info(SystemProcessInformation, buffer.data(),
+ static_cast<ULONG>(buffer.size()), &return_length);
+ // Insufficient space in the buffer.
+ if (return_length > buffer.size()) {
+ buffer.resize(return_length);
+ continue;
+ }
+ if (NT_SUCCESS(status) && return_length <= buffer.size())
+ break;
+ return false;
+ }
+
+ // Look for the struct housing information for the current process.
+ const DWORD proc_id = ::GetCurrentProcessId();
+ size_t index = 0;
+ while (index < buffer.size()) {
+ DCHECK_LE(index + sizeof(SYSTEM_PROCESS_INFORMATION_EX), buffer.size());
+ SYSTEM_PROCESS_INFORMATION_EX* proc_info =
+ reinterpret_cast<SYSTEM_PROCESS_INFORMATION_EX*>(buffer.data() + index);
+ if (base::win::HandleToUint32(proc_info->UniqueProcessId) == proc_id) {
+ *hard_fault_count = proc_info->HardFaultCount;
+ return true;
+ }
+ // The list ends when NextEntryOffset is zero. This also prevents busy
+ // looping if the data is in fact invalid.
+ if (proc_info->NextEntryOffset <= 0)
+ return false;
+ index += proc_info->NextEntryOffset;
+ }
+
+ return false;
+}
#endif // defined(OS_WIN)
#define UMA_HISTOGRAM_TIME_IN_MINUTES_MONTH_RANGE(name, sample) \
UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, \
base::TimeDelta::FromDays(30).InMinutes(), 50)
-// Helper macro for splitting out an UMA histogram based on cold or warm start.
+// Helper macro for splitting out an UMA histogram based on startup temperature.
// |type| is the histogram type, and corresponds to an UMA macro like
// UMA_HISTOGRAM_LONG_TIMES. It must itself be a macro that only takes two
// parameters.
// |basename| is the basename of the histogram. A histogram of this name will
-// always be recorded to. If the startup is either cold or warm then a value
-// will also be recorded to the histogram with name |basename| and suffix
-// ".ColdStart" or ".WarmStart", as appropriate.
+// always be recorded to. If the startup temperature is known then a value will
+// also be recorded to the histogram with name |basename| and suffix
+// ".ColdStart", ".WarmStart" or ".LukewarmStartup" as appropriate.
// |value_expr| is an expression evaluating to the value to be recorded. This
// will be evaluated exactly once and cached, so side effects are not an issue.
// A metric logged using this macro must have an affected-histogram entry in the
// definition of the StartupTemperature suffix in histograms.xml.
// This macro must only be used in code that runs after |g_startup_temperature|
// has been initialized.
-#define UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE(type, basename, value_expr) \
- { \
- const auto kValue = value_expr; \
+#define UMA_HISTOGRAM_WITH_TEMPERATURE(type, basename, value_expr) \
+ do { \
+ const auto value = value_expr; \
/* Always record to the base histogram. */ \
- type(basename, kValue); \
+ type(basename, value); \
/* Record to the cold/warm/lukewarm suffixed histogram as appropriate. */ \
switch (g_startup_temperature) { \
case COLD_STARTUP_TEMPERATURE: \
- type(basename ".ColdStartup", kValue); \
+ type(basename ".ColdStartup", value); \
break; \
case WARM_STARTUP_TEMPERATURE: \
- type(basename ".WarmStartup", kValue); \
+ type(basename ".WarmStartup", value); \
break; \
case LUKEWARM_STARTUP_TEMPERATURE: \
- type(basename ".LukewarmStartup", kValue); \
+ type(basename ".LukewarmStartup", value); \
break; \
case UNDETERMINED_STARTUP_TEMPERATURE: \
break; \
@@ -144,21 +224,80 @@ typedef NTSTATUS (WINAPI *NtQuerySystemInformationPtr)(
NOTREACHED(); \
break; \
} \
- }
+ } while (0)
+
+// Records |value_expr| to the histogram with name |basename| suffixed with the
+// number of startups with the current version in addition to all histograms
+// recorded by UMA_HISTOGRAM_WITH_TEMPERATURE.
+// A metric logged using this macro must have affected-histogram entries in the
+// definition of the StartupTemperature and SameVersionStartupCounts suffixes in
+// histograms.xml.
+// This macro must only be used in code that runs after |g_startup_temperature|
+// and |g_startups_with_current_version| have been initialized.
+#define UMA_HISTOGRAM_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(type, basename, \
+ value_expr) \
+ do { \
+ const auto value_same_version_count = value_expr; \
+ /* Record to the base histogram and to a histogram suffixed with the \
+ startup temperature. */ \
+ UMA_HISTOGRAM_WITH_TEMPERATURE(type, basename, value_same_version_count); \
+ /* Record to a histogram suffixed with the number of startups for the \
+ current version. Since the number of startups for the current version \
+ is set once per process, using a histogram macro which expects a \
+ constant histogram name across invocations is fine. */ \
+ const auto same_version_startup_count_suffix = \
+ GetSameVersionStartupCountSuffix(); \
+ if (!same_version_startup_count_suffix.empty()) { \
+ type(basename + same_version_startup_count_suffix, \
+ value_same_version_count); \
+ } \
+ } while (0)
-#define UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE( \
- type, basename, begin_ticks, end_ticks) \
- { \
- UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE(type, basename, \
- end_ticks - begin_ticks) \
+#define UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE(type, basename, begin_ticks, \
+ end_ticks) \
+ do { \
+ UMA_HISTOGRAM_WITH_TEMPERATURE(type, basename, end_ticks - begin_ticks); \
TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1( \
- "startup", basename, 0, begin_ticks.ToInternalValue(), "Temperature", \
+ "startup", basename, 0, begin_ticks, "Temperature", \
g_startup_temperature); \
TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP1( \
- "startup", basename, 0, end_ticks.ToInternalValue(), "Temperature", \
+ "startup", basename, 0, end_ticks, "Temperature", \
g_startup_temperature); \
+ } while (0)
+
+#define UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT( \
+ type, basename, begin_ticks, end_ticks) \
+ do { \
+ UMA_HISTOGRAM_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT( \
+ type, basename, end_ticks - begin_ticks); \
+ TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP2( \
+ "startup", basename, 0, begin_ticks, "Temperature", \
+ g_startup_temperature, "Startups with current version", \
+ g_startups_with_current_version); \
+ TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP2( \
+ "startup", basename, 0, end_ticks, "Temperature", \
+ g_startup_temperature, "Startups with current version", \
+ g_startups_with_current_version); \
+ } while (0)
+
+std::string GetSameVersionStartupCountSuffix() {
+ // TODO(fdoray): Remove this once crbug.com/580207 is fixed.
+ if (g_startups_with_current_version ==
+ kUndeterminedStartupsWithCurrentVersion) {
+ return std::string();
}
+ // The suffix is |g_startups_with_current_version| up to
+ // |kMaxSameVersionCountRecorded|. Higher counts are grouped in the ".Over"
+ // suffix. Make sure to reflect changes to |kMaxSameVersionCountRecorded| in
+ // the "SameVersionStartupCounts" histogram suffix.
+ constexpr int kMaxSameVersionCountRecorded = 9;
+ DCHECK_GE(g_startups_with_current_version, 1);
+ if (g_startups_with_current_version > kMaxSameVersionCountRecorded)
+ return ".Over";
+ return std::string(".") + base::IntToString(g_startups_with_current_version);
+}
+
// Returns the system uptime on process launch.
base::TimeDelta GetSystemUptimeOnProcessLaunch() {
// Process launch time is not available on Android.
@@ -178,17 +317,15 @@ void RecordSystemUptimeHistogram() {
if (system_uptime_on_process_launch.is_zero())
return;
- UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE(UMA_HISTOGRAM_LONG_TIMES_100,
- "Startup.SystemUptime",
- GetSystemUptimeOnProcessLaunch());
+ UMA_HISTOGRAM_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
+ UMA_HISTOGRAM_LONG_TIMES_100, "Startup.SystemUptime",
+ GetSystemUptimeOnProcessLaunch());
}
// On Windows, records the number of hard-faults that have occurred in the
-// current chrome.exe process since it was started. A version of the histograms
-// recorded in this method suffixed by |same_version_startup_count| will also be
-// recorded (unless |same_version_startup_count| is 0 which indicates it's
-// unknown). This is a nop on other platforms.
-void RecordHardFaultHistogram(int same_version_startup_count) {
+// current chrome.exe process since it was started. This is a nop on other
+// platforms.
+void RecordHardFaultHistogram() {
#if defined(OS_WIN)
uint32_t hard_fault_count = 0;
@@ -196,23 +333,8 @@ void RecordHardFaultHistogram(int same_version_startup_count) {
if (!GetHardFaultCountForCurrentProcess(&hard_fault_count))
return;
- std::string same_version_startup_count_suffix;
- if (same_version_startup_count != 0) {
- // Histograms below will be suffixed by |same_version_startup_count| up to
- // |kMaxSameVersionCountRecorded|, higher counts will be grouped in the
- // ".Over" suffix. Make sure to reflect changes to
- // kMaxSameVersionCountRecorded in the "SameVersionStartupCounts" histogram
- // suffix.
- const int kMaxSameVersionCountRecorded = 9;
- same_version_startup_count_suffix.push_back('.');
- DCHECK_GE(same_version_startup_count, 1);
- if (same_version_startup_count <= kMaxSameVersionCountRecorded) {
- same_version_startup_count_suffix.append(
- base::IntToString(same_version_startup_count));
- } else {
- same_version_startup_count_suffix.append("Over");
- }
- }
+ const std::string same_version_startup_count_suffix(
+ GetSameVersionStartupCountSuffix());
// Hard fault counts are expected to be in the thousands range,
// corresponding to faulting in ~10s of MBs of code ~10s of KBs at a time.
@@ -234,9 +356,9 @@ void RecordHardFaultHistogram(int same_version_startup_count) {
// Determine the startup type based on the number of observed hard faults.
DCHECK_EQ(UNDETERMINED_STARTUP_TEMPERATURE, g_startup_temperature);
- if (hard_fault_count < WARM_START_HARD_FAULT_COUNT_THRESHOLD) {
+ if (hard_fault_count < kWarmStartHardFaultCountThreshold) {
g_startup_temperature = WARM_STARTUP_TEMPERATURE;
- } else if (hard_fault_count >= COLD_START_HARD_FAULT_COUNT_THRESHOLD) {
+ } else if (hard_fault_count >= kColdStartHardFaultCountThreshold) {
g_startup_temperature = COLD_STARTUP_TEMPERATURE;
} else {
g_startup_temperature = LUKEWARM_STARTUP_TEMPERATURE;
@@ -338,42 +460,25 @@ void RecordRendererMainEntryHistogram() {
if (!browser_main_entry_point_ticks.is_null() &&
!renderer_main_entry_point_ticks.is_null()) {
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100, "Startup.BrowserMainToRendererMain",
browser_main_entry_point_ticks, renderer_main_entry_point_ticks);
}
}
-// Environment variable that stores the timestamp when the executable's main()
-// function was entered in TimeTicks. This is required because chrome.exe and
-// chrome.dll don't share the same static storage.
-const char kChromeMainTicksEnvVar[] = "CHROME_MAIN_TICKS";
-
-// Returns the time of main entry recorded from RecordExeMainEntryTime.
-base::TimeTicks ExeMainEntryPointTicks() {
- std::unique_ptr<base::Environment> env(base::Environment::Create());
- std::string ticks_string;
- int64_t time_int = 0;
- if (env->GetVar(kChromeMainTicksEnvVar, &ticks_string) &&
- base::StringToInt64(ticks_string, &time_int)) {
- return base::TimeTicks::FromInternalValue(time_int);
- }
- return base::TimeTicks();
-}
-
void AddStartupEventsForTelemetry()
{
DCHECK(!g_browser_main_entry_point_ticks.Get().is_null());
TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
"startup", "Startup.BrowserMainEntryPoint", 0,
- g_browser_main_entry_point_ticks.Get().ToInternalValue());
+ g_browser_main_entry_point_ticks.Get());
if (!g_process_creation_ticks.Get().is_null())
{
TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
"startup", "Startup.BrowserProcessCreation", 0,
- g_process_creation_ticks.Get().ToInternalValue());
+ g_process_creation_ticks.Get());
}
}
@@ -381,7 +486,7 @@ void AddStartupEventsForTelemetry()
// last startup from |pref_service| and overwrites it with the timestamp of the
// current startup. If the startup temperature has been set by
// RecordBrowserMainMessageLoopStart, the time since last startup is also logged
-// to an histogram suffixed with the startup temperature.
+// to a histogram suffixed with the startup temperature.
void RecordTimeSinceLastStartup(PrefService* pref_service) {
#if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX)
DCHECK(pref_service);
@@ -403,7 +508,7 @@ void RecordTimeSinceLastStartup(PrefService* pref_service) {
// Ignore negative values, which can be caused by system clock changes.
if (minutes_since_last_startup >= 0) {
- UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE(
+ UMA_HISTOGRAM_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_TIME_IN_MINUTES_MONTH_RANGE,
"Startup.TimeSinceLastStartup", minutes_since_last_startup);
}
@@ -417,91 +522,32 @@ void RecordTimeSinceLastStartup(PrefService* pref_service) {
// Logs the Startup.SameVersionStartupCount histogram. Relies on |pref_service|
// to know information about the previous startups and store information for
-// future ones. Returns the number of startups with the same version count that
-// was logged.
-int RecordSameVersionStartupCount(PrefService* pref_service) {
+// future ones. Stores the logged value in |g_startups_with_current_version|.
+void RecordSameVersionStartupCount(PrefService* pref_service) {
DCHECK(pref_service);
+ DCHECK_EQ(kUndeterminedStartupsWithCurrentVersion,
+ g_startups_with_current_version);
const std::string current_version = version_info::GetVersionNumber();
- int startups_with_current_version = 0;
if (current_version == pref_service->GetString(prefs::kLastStartupVersion)) {
- startups_with_current_version =
+ g_startups_with_current_version =
pref_service->GetInteger(prefs::kSameVersionStartupCount);
- ++startups_with_current_version;
+ ++g_startups_with_current_version;
pref_service->SetInteger(prefs::kSameVersionStartupCount,
- startups_with_current_version);
+ g_startups_with_current_version);
} else {
- startups_with_current_version = 1;
+ g_startups_with_current_version = 1;
pref_service->SetString(prefs::kLastStartupVersion, current_version);
pref_service->SetInteger(prefs::kSameVersionStartupCount, 1);
}
UMA_HISTOGRAM_COUNTS_100("Startup.SameVersionStartupCount",
- startups_with_current_version);
- return startups_with_current_version;
+ g_startups_with_current_version);
}
} // namespace
-#if defined(OS_WIN)
-bool GetHardFaultCountForCurrentProcess(uint32_t* hard_fault_count) {
- DCHECK(hard_fault_count);
-
- if (base::win::GetVersion() < base::win::VERSION_WIN7)
- return false;
-
- // Get the function pointer.
- static const NtQuerySystemInformationPtr query_sys_info =
- reinterpret_cast<NtQuerySystemInformationPtr>(::GetProcAddress(
- GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation"));
- if (query_sys_info == nullptr)
- return false;
-
- // The output of this system call depends on the number of threads and
- // processes on the entire system, and this can change between calls. Retry
- // a small handful of times growing the buffer along the way.
- // NOTE: The actual required size depends entirely on the number of processes
- // and threads running on the system. The initial guess suffices for
- // ~100s of processes and ~1000s of threads.
- std::vector<uint8_t> buffer(32 * 1024);
- for (size_t tries = 0; tries < 3; ++tries) {
- ULONG return_length = 0;
- NTSTATUS status =
- query_sys_info(SystemProcessInformation, buffer.data(),
- static_cast<ULONG>(buffer.size()), &return_length);
- // Insufficient space in the buffer.
- if (return_length > buffer.size()) {
- buffer.resize(return_length);
- continue;
- }
- if (NT_SUCCESS(status) && return_length <= buffer.size())
- break;
- return false;
- }
-
- // Look for the struct housing information for the current process.
- DWORD proc_id = ::GetCurrentProcessId();
- size_t index = 0;
- while (index < buffer.size()) {
- DCHECK_LE(index + sizeof(SYSTEM_PROCESS_INFORMATION_EX), buffer.size());
- SYSTEM_PROCESS_INFORMATION_EX* proc_info =
- reinterpret_cast<SYSTEM_PROCESS_INFORMATION_EX*>(buffer.data() + index);
- if (base::win::HandleToUint32(proc_info->UniqueProcessId) == proc_id) {
- *hard_fault_count = proc_info->HardFaultCount;
- return true;
- }
- // The list ends when NextEntryOffset is zero. This also prevents busy
- // looping if the data is in fact invalid.
- if (proc_info->NextEntryOffset <= 0)
- return false;
- index += proc_info->NextEntryOffset;
- }
-
- return false;
-}
-#endif // defined(OS_WIN)
-
void RegisterPrefs(PrefRegistrySimple* registry) {
DCHECK(registry);
registry->RegisterInt64Pref(prefs::kLastStartupTimestamp, 0);
@@ -535,79 +581,101 @@ void RecordMainEntryPointTime(const base::Time& time) {
DCHECK(!g_browser_main_entry_point_time.Get().is_null());
}
-void RecordExeMainEntryPointTime(const base::Time& time) {
- const std::string exe_load_ticks =
- base::Int64ToString(StartupTimeToTimeTicks(time).ToInternalValue());
- std::unique_ptr<base::Environment> env(base::Environment::Create());
- env->SetVar(kChromeMainTicksEnvVar, exe_load_ticks);
+void RecordExeMainEntryPointTicks(const base::TimeTicks& ticks) {
+ DCHECK(g_browser_exe_main_entry_point_ticks.Get().is_null());
+ g_browser_exe_main_entry_point_ticks.Get() = ticks;
+ DCHECK(!g_browser_exe_main_entry_point_ticks.Get().is_null());
}
void RecordBrowserMainMessageLoopStart(const base::TimeTicks& ticks,
bool is_first_run,
PrefService* pref_service) {
- int same_version_startup_count = 0;
- if (pref_service)
- same_version_startup_count = RecordSameVersionStartupCount(pref_service);
+ DCHECK(pref_service);
+
+ RecordSameVersionStartupCount(pref_service);
// Keep RecordHardFaultHistogram() first as much as possible as many other
// histograms depend on it setting |g_startup_temperature|.
- RecordHardFaultHistogram(same_version_startup_count);
+ RecordHardFaultHistogram();
AddStartupEventsForTelemetry();
- if (pref_service)
- RecordTimeSinceLastStartup(pref_service);
+ RecordTimeSinceLastStartup(pref_service);
RecordSystemUptimeHistogram();
RecordMainEntryTimeHistogram();
const base::TimeTicks& process_creation_ticks =
g_process_creation_ticks.Get();
if (!is_first_run && !process_creation_ticks.is_null()) {
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100, "Startup.BrowserMessageLoopStartTime",
process_creation_ticks, ticks);
}
- // Bail if uptime < 7 minutes, to filter out cases where Chrome may have been
- // autostarted and the machine is under io pressure.
- if (base::SysInfo::Uptime() < base::TimeDelta::FromMinutes(7))
- return;
+ // TODO(fdoray): Remove histograms that are only recorded after 7 minutes of
+ // OS uptime once M54 hits stable. These histograms are kept for now to allow
+ // regressions to be caught reliably in M54, to be removed in M55.
+ // crbug.com/634408
+ const bool is_seven_minutes_after_boot =
+ base::SysInfo::Uptime() < base::TimeDelta::FromMinutes(7);
- // The Startup.BrowserMessageLoopStartTime histogram exhibits instability in
- // the field which limits its usefulness in all scenarios except when we have
- // a very large sample size. Attempt to mitigate this with a new metric:
- // * Measure time from main entry rather than the OS' notion of process start.
- // * Only measure launches that occur 7 minutes after boot to try to avoid
- // cases where Chrome is auto-started and IO is heavily loaded.
+ // Record timing between the shared library's main() entry and the browser
+ // main message loop start.
if (is_first_run) {
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE(
UMA_HISTOGRAM_LONG_TIMES,
- "Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun",
+ "Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun2",
g_browser_main_entry_point_ticks.Get(), ticks);
+ if (is_seven_minutes_after_boot) {
+ UMA_HISTOGRAM_WITH_TEMPERATURE(
+ UMA_HISTOGRAM_LONG_TIMES,
+ "Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun",
+ ticks - g_browser_main_entry_point_ticks.Get());
+ }
} else {
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES,
- "Startup.BrowserMessageLoopStartTimeFromMainEntry",
+ "Startup.BrowserMessageLoopStartTimeFromMainEntry2",
g_browser_main_entry_point_ticks.Get(), ticks);
+ if (is_seven_minutes_after_boot) {
+ UMA_HISTOGRAM_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
+ UMA_HISTOGRAM_LONG_TIMES,
+ "Startup.BrowserMessageLoopStartTimeFromMainEntry",
+ ticks - g_browser_main_entry_point_ticks.Get());
+ }
}
// Record timings between process creation, the main() in the executable being
// reached and the main() in the shared library being reached.
- if (!process_creation_ticks.is_null()) {
- const base::TimeTicks exe_main_ticks = ExeMainEntryPointTicks();
- if (!exe_main_ticks.is_null()) {
- // Process create to chrome.exe:main().
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ if (!process_creation_ticks.is_null() &&
+ !g_browser_exe_main_entry_point_ticks.Get().is_null()) {
+ const base::TimeTicks exe_main_ticks =
+ g_browser_exe_main_entry_point_ticks.Get();
+ const base::TimeTicks main_entry_ticks =
+ g_browser_main_entry_point_ticks.Get();
+ // Process create to chrome.exe:main().
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
+ UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ProcessCreateToExeMain2",
+ process_creation_ticks, exe_main_ticks);
+
+ // chrome.exe:main() to chrome.dll:main().
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
+ UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ExeMainToDllMain2",
+ exe_main_ticks, main_entry_ticks);
+
+ // Process create to chrome.dll:main(). Reported as a histogram only as
+ // the other two events above are sufficient for tracing purposes.
+ UMA_HISTOGRAM_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
+ UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ProcessCreateToDllMain2",
+ main_entry_ticks - process_creation_ticks);
+
+ if (is_seven_minutes_after_boot) {
+ UMA_HISTOGRAM_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ProcessCreateToExeMain",
- process_creation_ticks, exe_main_ticks);
-
- // chrome.exe:main() to chrome.dll:main().
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ exe_main_ticks - process_creation_ticks);
+ UMA_HISTOGRAM_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ExeMainToDllMain",
- exe_main_ticks, g_browser_main_entry_point_ticks.Get());
-
- // Process create to chrome.dll:main(). Reported as a histogram only as
- // the other two events above are sufficient for tracing purposes.
- UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE(
+ main_entry_ticks - exe_main_ticks);
+ UMA_HISTOGRAM_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ProcessCreateToDllMain",
- g_browser_main_entry_point_ticks.Get() - process_creation_ticks);
+ main_entry_ticks - process_creation_ticks);
}
}
}
@@ -620,7 +688,7 @@ void RecordBrowserWindowDisplay(const base::TimeTicks& ticks) {
if (WasNonBrowserUIDisplayed() || g_process_creation_ticks.Get().is_null())
return;
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES, "Startup.BrowserWindowDisplay",
g_process_creation_ticks.Get(), ticks);
}
@@ -631,8 +699,8 @@ void RecordBrowserOpenTabsDelta(const base::TimeDelta& delta) {
return;
is_first_call = false;
- UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE(UMA_HISTOGRAM_LONG_TIMES_100,
- "Startup.BrowserOpenTabs", delta);
+ UMA_HISTOGRAM_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
+ UMA_HISTOGRAM_LONG_TIMES_100, "Startup.BrowserOpenTabs", delta);
}
void RecordRendererMainEntryTime(const base::TimeTicks& ticks) {
@@ -650,7 +718,7 @@ void RecordFirstWebContentsMainFrameLoad(const base::TimeTicks& ticks) {
if (WasNonBrowserUIDisplayed() || g_process_creation_ticks.Get().is_null())
return;
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100, "Startup.FirstWebContents.MainFrameLoad2",
g_process_creation_ticks.Get(), ticks);
}
@@ -668,7 +736,7 @@ void RecordFirstWebContentsNonEmptyPaint(const base::TimeTicks& ticks) {
if (WasNonBrowserUIDisplayed() || g_process_creation_ticks.Get().is_null())
return;
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100, "Startup.FirstWebContents.NonEmptyPaint2",
g_process_creation_ticks.Get(), ticks);
}
@@ -681,7 +749,7 @@ void RecordFirstWebContentsMainNavigationStart(const base::TimeTicks& ticks) {
if (WasNonBrowserUIDisplayed() || g_process_creation_ticks.Get().is_null())
return;
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100,
"Startup.FirstWebContents.MainNavigationStart",
g_process_creation_ticks.Get(), ticks);
@@ -696,7 +764,7 @@ void RecordFirstWebContentsMainNavigationFinished(
if (WasNonBrowserUIDisplayed() || g_process_creation_ticks.Get().is_null())
return;
- UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(
+ UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
UMA_HISTOGRAM_LONG_TIMES_100,
"Startup.FirstWebContents.MainNavigationFinished",
g_process_creation_ticks.Get(), ticks);
@@ -706,8 +774,4 @@ base::TimeTicks MainEntryPointTicks() {
return g_browser_main_entry_point_ticks.Get();
}
-StartupTemperature GetStartupTemperature() {
- return g_startup_temperature;
-}
-
} // namespace startup_metric_utils
diff --git a/chromium/components/startup_metric_utils/browser/startup_metric_utils.h b/chromium/components/startup_metric_utils/browser/startup_metric_utils.h
index cdfb55c99ce..90e827468bf 100644
--- a/chromium/components/startup_metric_utils/browser/startup_metric_utils.h
+++ b/chromium/components/startup_metric_utils/browser/startup_metric_utils.h
@@ -5,11 +5,7 @@
#ifndef COMPONENTS_STARTUP_METRIC_UTILS_BROWSER_STARTUP_METRIC_UTILS_H_
#define COMPONENTS_STARTUP_METRIC_UTILS_BROWSER_STARTUP_METRIC_UTILS_H_
-#include <stdint.h>
-#include <string>
-
#include "base/time/time.h"
-#include "build/build_config.h"
class PrefRegistrySimple;
class PrefService;
@@ -22,31 +18,6 @@ class PrefService;
namespace startup_metric_utils {
-// An enumeration of startup temperatures. This must be kept in sync with the
-// UMA StartupType enumeration defined in histograms.xml.
-enum StartupTemperature {
- // The startup was a cold start: nearly all of the binaries and resources were
- // brought into memory using hard faults.
- COLD_STARTUP_TEMPERATURE = 0,
- // The startup was a warm start: the binaries and resources were mostly
- // already resident in memory and effectively no hard faults were observed.
- WARM_STARTUP_TEMPERATURE = 1,
- // The startup type couldn't quite be classified as warm or cold, but rather
- // was somewhere in between.
- LUKEWARM_STARTUP_TEMPERATURE = 2,
- // This must be after all meaningful values. All new values should be added
- // above this one.
- STARTUP_TEMPERATURE_COUNT,
- // Startup temperature wasn't yet determined.
- UNDETERMINED_STARTUP_TEMPERATURE
-};
-
-#if defined(OS_WIN)
-// Gets the hard fault count of the current process through |hard_fault_count|.
-// Returns true on success.
-bool GetHardFaultCountForCurrentProcess(uint32_t* hard_fault_count);
-#endif // defined(OS_WIN)
-
// Registers startup related prefs in |registry|.
void RegisterPrefs(PrefRegistrySimple* registry);
@@ -74,13 +45,11 @@ void RecordMainEntryPointTime(const base::Time& time);
// Call this with the time when the executable is loaded and main() is entered.
// Can be different from |RecordMainEntryPointTime| when the startup process is
// contained in a separate dll, such as with chrome.exe / chrome.dll on Windows.
-void RecordExeMainEntryPointTime(const base::Time& time);
+void RecordExeMainEntryPointTicks(const base::TimeTicks& time);
// Call this with the time recorded just before the message loop is started.
// |is_first_run| - is the current launch part of a first run. |pref_service| is
-// an optional parameter which, if provided, will be used to store state for
-// stats that span multiple startups; in its absence those stats will not be
-// recorded.
+// used to store state for stats that span multiple startups.
void RecordBrowserMainMessageLoopStart(const base::TimeTicks& ticks,
bool is_first_run,
PrefService* pref_service);
@@ -118,11 +87,6 @@ void RecordFirstWebContentsMainNavigationFinished(const base::TimeTicks& ticks);
// recorded yet. This method is expected to be called from the UI thread.
base::TimeTicks MainEntryPointTicks();
-// Returns the startup type. This is only currently supported on the Windows
-// platform and will simply return UNCERTAIN_STARTUP_TYPE on other platforms.
-// This is only valid after a call to RecordBrowserMainMessageLoopStart().
-StartupTemperature GetStartupTemperature();
-
} // namespace startup_metric_utils
#endif // COMPONENTS_STARTUP_METRIC_UTILS_BROWSER_STARTUP_METRIC_UTILS_H_
diff --git a/chromium/components/startup_metric_utils/common/BUILD.gn b/chromium/components/startup_metric_utils/common/BUILD.gn
index 54fd89587c0..4bb32b55c11 100644
--- a/chromium/components/startup_metric_utils/common/BUILD.gn
+++ b/chromium/components/startup_metric_utils/common/BUILD.gn
@@ -4,19 +4,6 @@
import("//mojo/public/tools/bindings/mojom.gni")
-source_set("common") {
- sources = [
- "pre_read_field_trial_utils_win.cc",
- "pre_read_field_trial_utils_win.h",
- ]
-
- deps = [
- "//base",
- "//components/variations",
- "//ipc",
- ]
-}
-
mojom("interfaces") {
sources = [
"startup_metric.mojom",
@@ -24,4 +11,6 @@ mojom("interfaces") {
deps = [
"//mojo/common:common_custom_types",
]
+
+ use_new_wrapper_types = false
}
diff --git a/chromium/components/startup_metric_utils/common/DEPS b/chromium/components/startup_metric_utils/common/DEPS
deleted file mode 100644
index 80f6f908e13..00000000000
--- a/chromium/components/startup_metric_utils/common/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+components/variations",
-]
diff --git a/chromium/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc b/chromium/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc
deleted file mode 100644
index cb9207a58da..00000000000
--- a/chromium/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc
+++ /dev/null
@@ -1,151 +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 "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
-
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/metrics/field_trial.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/registry.h"
-#include "components/variations/variations_associated_data.h"
-
-namespace startup_metric_utils {
-
-namespace {
-
-// Name of the pre-read field trial. This name is used to get the pre-read group
-// to use for the next startup from base::FieldTrialList.
-const char kPreReadFieldTrialName[] = "PreRead";
-
-// Name of the synthetic pre-read field trial. A synthetic field trial is
-// registered so that UMA metrics recorded during the current startup are
-// annotated with the pre-read group that is actually used during this startup.
-const char kPreReadSyntheticFieldTrialName[] = "SyntheticPreRead";
-
-// Variation names for the PreRead field trial. All variations change the
-// default behavior, i.e. the default is the inverse of the variation. Thus,
-// variations that cancel something that is done by default have a negative
-// name.
-const base::char16 kNoPreReadVariationName[] = L"NoPreRead";
-const base::char16 kHighPriorityVariationName[] = L"HighPriority";
-const base::char16 kPrefetchVirtualMemoryVariationName[] =
- L"PrefetchVirtualMemory";
-const base::char16 kPreReadChromeChildInBrowser[] =
- L"PreReadChromeChildInBrowser";
-
-// Registry key in which the PreRead field trial group is stored.
-const base::char16 kPreReadFieldTrialRegistryKey[] = L"\\PreReadFieldTrial";
-
-// Pre-read options to use for the current process. This is initialized by
-// InitializePreReadOptions().
-PreReadOptions g_pre_read_options = {};
-
-// Returns the registry path in which the PreRead group is stored.
-base::string16 GetPreReadRegistryPath(
- const base::string16& product_registry_path) {
- return product_registry_path + kPreReadFieldTrialRegistryKey;
-}
-
-// Returns true if |key| has a value named |name| which is not zero.
-bool ReadBool(const base::win::RegKey& key, const base::char16* name) {
- DWORD value = 0;
- return key.ReadValueDW(name, &value) == ERROR_SUCCESS && value != 0;
-}
-
-} // namespace
-
-void InitializePreReadOptions(const base::string16& product_registry_path) {
- DCHECK(!product_registry_path.empty());
-
-#if DCHECK_IS_ON()
- static bool initialized = false;
- DCHECK(!initialized);
- initialized = true;
-#endif // DCHECK_IS_ON()
-
- // Open the PreRead field trial's registry key.
- const base::string16 registry_path =
- GetPreReadRegistryPath(product_registry_path);
- const base::win::RegKey key(HKEY_CURRENT_USER, registry_path.c_str(),
- KEY_QUERY_VALUE);
-
- // Set the PreRead field trial's options.
- g_pre_read_options.pre_read = !ReadBool(key, kNoPreReadVariationName);
- g_pre_read_options.high_priority = ReadBool(key, kHighPriorityVariationName);
- g_pre_read_options.prefetch_virtual_memory =
- ReadBool(key, kPrefetchVirtualMemoryVariationName);
- g_pre_read_options.pre_read_chrome_child_in_browser =
- ReadBool(key, kPreReadChromeChildInBrowser);
-}
-
-PreReadOptions GetPreReadOptions() {
- return g_pre_read_options;
-}
-
-void UpdatePreReadOptions(const base::string16& product_registry_path) {
- DCHECK(!product_registry_path.empty());
-
- const base::string16 registry_path =
- GetPreReadRegistryPath(product_registry_path);
-
- // Clear the experiment key. That way, when the trial is shut down, the
- // registry will be cleaned automatically. Also, this prevents variation
- // params from the previous group to stay in the registry when the group is
- // updated.
- base::win::RegKey(HKEY_CURRENT_USER, registry_path.c_str(), KEY_SET_VALUE)
- .DeleteKey(L"");
-
- // Get the new group name.
- const base::string16 group = base::UTF8ToUTF16(
- base::FieldTrialList::FindFullName(kPreReadFieldTrialName));
- if (group.empty())
- return;
-
- // Get variation params for the new group.
- std::map<std::string, std::string> variation_params;
- variations::GetVariationParams(kPreReadFieldTrialName, &variation_params);
-
- // Open the registry key.
- base::win::RegKey key(HKEY_CURRENT_USER, registry_path.c_str(),
- KEY_SET_VALUE);
-
- // Write variation params in the registry.
- for (const auto& variation_param : variation_params) {
- if (!variation_param.second.empty()) {
- if (key.WriteValue(base::UTF8ToUTF16(variation_param.first).c_str(), 1) !=
- ERROR_SUCCESS) {
- // Abort on failure to prevent the group name from being written in the
- // registry if not all variation params have been written. No synthetic
- // field trial is registered when there is no group name in the
- // registry.
- return;
- }
- }
- }
-
- // Write the new group name in the registry.
- key.WriteValue(L"", group.c_str());
-}
-
-void RegisterPreReadSyntheticFieldTrial(
- const base::string16& product_registry_path,
- const RegisterPreReadSyntheticFieldTrialCallback&
- register_synthetic_field_trial) {
- DCHECK(!product_registry_path.empty());
-
- const base::win::RegKey key(
- HKEY_CURRENT_USER, GetPreReadRegistryPath(product_registry_path).c_str(),
- KEY_QUERY_VALUE);
- base::string16 group;
- key.ReadValue(L"", &group);
-
- if (!group.empty()) {
- register_synthetic_field_trial.Run(kPreReadSyntheticFieldTrialName,
- base::UTF16ToUTF8(group));
- }
-}
-
-} // namespace startup_metric_utils
diff --git a/chromium/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h b/chromium/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h
deleted file mode 100644
index beed901efec..00000000000
--- a/chromium/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h
+++ /dev/null
@@ -1,64 +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 COMPONENTS_STARTUP_METRIC_UTILS_COMMON_PRE_READ_FIELD_TRIAL_UTILS_WIN_H_
-#define COMPONENTS_STARTUP_METRIC_UTILS_COMMON_PRE_READ_FIELD_TRIAL_UTILS_WIN_H_
-
-#include <string>
-
-#include "base/callback_forward.h"
-#include "base/strings/string16.h"
-
-// Utility functions to support the PreRead field trial. The PreRead field trial
-// changes the way DLLs are pre-read during startup.
-
-namespace startup_metric_utils {
-
-// Callback to register a synthetic field trial.
-using RegisterPreReadSyntheticFieldTrialCallback =
- const base::Callback<bool(const std::string&, const std::string&)>;
-
-// The options controlled by the PreRead field trial.
-struct PreReadOptions {
- // Pre-read DLLs explicitly.
- bool pre_read : 1;
-
- // Pre-read DLLs with a high thread priority.
- bool high_priority : 1;
-
- // Pre-read DLLs using the ::PrefetchVirtualMemory function, if available.
- bool prefetch_virtual_memory : 1;
-
- // Pre-read chrome_child.dll in the browser process and not in child
- // processes.
- bool pre_read_chrome_child_in_browser : 1;
-};
-
-// Initializes DLL pre-reading options from the registry.
-// |product_registry_path| is the registry path under which the registry key for
-// this field trial resides.
-void InitializePreReadOptions(const base::string16& product_registry_path);
-
-// Returns the bitfield of the DLL pre-reading options to use for the current
-// process. InitializePreReadOptions() must have been called before this.
-PreReadOptions GetPreReadOptions();
-
-// Updates DLL pre-reading options in the registry with the latest info for the
-// next startup. |product_registry_path| is the registry path under which the
-// registry key for this field trial resides.
-void UpdatePreReadOptions(const base::string16& product_registry_path);
-
-// Registers a synthetic field trial with the PreRead group currently stored in
-// the registry. This must be done before the first metric log
-// (metrics::MetricsLog) is created. Otherwise, UMA metrics generated during
-// startup won't be correctly annotated. |product_registry_path| is the registry
-// path under which the key for this field trial resides.
-void RegisterPreReadSyntheticFieldTrial(
- const base::string16& product_registry_path,
- const RegisterPreReadSyntheticFieldTrialCallback&
- register_synthetic_field_trial);
-
-} // namespace startup_metric_utils
-
-#endif // COMPONENTS_STARTUP_METRIC_UTILS_COMMON_PRE_READ_FIELD_TRIAL_UTILS_WIN_H_
diff --git a/chromium/components/storage_monitor.gypi b/chromium/components/storage_monitor.gypi
deleted file mode 100644
index d5176722e27..00000000000
--- a/chromium/components/storage_monitor.gypi
+++ /dev/null
@@ -1,132 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/storage_monitor
- 'target_name': 'storage_monitor',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'storage_monitor/image_capture_device.h',
- 'storage_monitor/image_capture_device.mm',
- 'storage_monitor/image_capture_device_manager.h',
- 'storage_monitor/image_capture_device_manager.mm',
- 'storage_monitor/media_storage_util.cc',
- 'storage_monitor/media_storage_util.h',
- 'storage_monitor/media_transfer_protocol_device_observer_linux.cc',
- 'storage_monitor/media_transfer_protocol_device_observer_linux.h',
- 'storage_monitor/mtab_watcher_linux.cc',
- 'storage_monitor/mtab_watcher_linux.h',
- 'storage_monitor/portable_device_watcher_win.cc',
- 'storage_monitor/portable_device_watcher_win.h',
- 'storage_monitor/removable_device_constants.cc',
- 'storage_monitor/removable_device_constants.h',
- 'storage_monitor/removable_storage_observer.h',
- 'storage_monitor/storage_info.cc',
- 'storage_monitor/storage_info.h',
- 'storage_monitor/storage_monitor.cc',
- 'storage_monitor/storage_monitor.h',
- 'storage_monitor/storage_monitor_chromeos.cc',
- 'storage_monitor/storage_monitor_chromeos.h',
- 'storage_monitor/storage_monitor_linux.cc',
- 'storage_monitor/storage_monitor_linux.h',
- 'storage_monitor/storage_monitor_mac.h',
- 'storage_monitor/storage_monitor_mac.mm',
- 'storage_monitor/storage_monitor_win.cc',
- 'storage_monitor/storage_monitor_win.h',
- 'storage_monitor/transient_device_ids.cc',
- 'storage_monitor/transient_device_ids.h',
- 'storage_monitor/udev_util_linux.cc',
- 'storage_monitor/udev_util_linux.h',
- 'storage_monitor/volume_mount_watcher_win.cc',
- 'storage_monitor/volume_mount_watcher_win.h',
- ],
- 'conditions': [
- ['OS == "mac"', {
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/DiskArbitration.framework',
- '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
- '$(SDKROOT)/System/Library/Frameworks/ImageCaptureCore.framework',
- ],
- },
- }],
- ['OS=="linux"', {
- 'dependencies': [
- '../device/media_transfer_protocol/media_transfer_protocol.gyp:device_media_transfer_protocol',
- '../device/media_transfer_protocol/media_transfer_protocol.gyp:mtp_file_entry_proto',
- '../device/media_transfer_protocol/media_transfer_protocol.gyp:mtp_storage_info_proto',
- ],
- }],
- ['use_udev==1', {
- 'dependencies': [
- '../device/udev_linux/udev.gyp:udev_linux',
- ],
- }, { # use_udev==0
- 'sources!': [
- 'storage_monitor/storage_monitor_linux.cc',
- 'storage_monitor/storage_monitor_linux.h',
- 'storage_monitor/udev_util_linux.cc',
- 'storage_monitor/udev_util_linux.h',
- ],
- }],
- ['chromeos==1', {
- 'sources!': [
- 'storage_monitor/mtab_watcher_linux.cc',
- 'storage_monitor/mtab_watcher_linux.h',
- 'storage_monitor/storage_monitor_linux.cc',
- 'storage_monitor/storage_monitor_linux.h',
- ],
- }],
- ],
- },
- {
- # GN version: //components/storage_monitor:test_support
- 'target_name': 'storage_monitor_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'storage_monitor',
- ],
- 'sources': [
- 'storage_monitor/mock_removable_storage_observer.cc',
- 'storage_monitor/mock_removable_storage_observer.h',
- 'storage_monitor/test_media_transfer_protocol_manager_linux.cc',
- 'storage_monitor/test_media_transfer_protocol_manager_linux.h',
- 'storage_monitor/test_portable_device_watcher_win.cc',
- 'storage_monitor/test_portable_device_watcher_win.h',
- 'storage_monitor/test_storage_monitor.cc',
- 'storage_monitor/test_storage_monitor.h',
- 'storage_monitor/test_storage_monitor_win.cc',
- 'storage_monitor/test_storage_monitor_win.h',
- 'storage_monitor/test_volume_mount_watcher_win.cc',
- 'storage_monitor/test_volume_mount_watcher_win.h',
- ],
- 'conditions': [
- ['OS=="linux"', {
- 'dependencies': [
- '../device/media_transfer_protocol/media_transfer_protocol.gyp:device_media_transfer_protocol',
- '../device/media_transfer_protocol/media_transfer_protocol.gyp:mtp_file_entry_proto',
- '../device/media_transfer_protocol/media_transfer_protocol.gyp:mtp_storage_info_proto',
- ],
- }],
- ['OS=="win"', {
- 'dependencies': [
- '../testing/gtest.gyp:gtest',
- ],
- }],
- ],
- },
- ],
-}
diff --git a/chromium/components/storage_monitor/BUILD.gn b/chromium/components/storage_monitor/BUILD.gn
index dbbedf8b0e8..87b79115744 100644
--- a/chromium/components/storage_monitor/BUILD.gn
+++ b/chromium/components/storage_monitor/BUILD.gn
@@ -4,8 +4,7 @@
import("//build/config/features.gni")
-# GYP version: components/storage_monitor.gypi:storage_monitor
-source_set("storage_monitor") {
+static_library("storage_monitor") {
sources = [
"image_capture_device.h",
"image_capture_device.mm",
@@ -13,8 +12,6 @@ source_set("storage_monitor") {
"image_capture_device_manager.mm",
"media_storage_util.cc",
"media_storage_util.h",
- "media_transfer_protocol_device_observer_linux.cc",
- "media_transfer_protocol_device_observer_linux.h",
"mtab_watcher_linux.cc",
"mtab_watcher_linux.h",
"portable_device_watcher_win.cc",
@@ -56,12 +53,16 @@ source_set("storage_monitor") {
]
}
- if (is_linux) {
+ if (is_chromeos && use_dbus) {
deps += [
"//device/media_transfer_protocol",
"//device/media_transfer_protocol:mtp_file_entry_proto",
"//device/media_transfer_protocol:mtp_storage_info_proto",
]
+ sources += [
+ "media_transfer_protocol_device_observer_chromeos.cc",
+ "media_transfer_protocol_device_observer_chromeos.h",
+ ]
}
if (use_udev) {
@@ -87,14 +88,13 @@ source_set("storage_monitor") {
}
}
-# GYP version: components/storage_monitor.gypi:storage_monitor_test_support
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"mock_removable_storage_observer.cc",
"mock_removable_storage_observer.h",
- "test_media_transfer_protocol_manager_linux.cc",
- "test_media_transfer_protocol_manager_linux.h",
+ "test_media_transfer_protocol_manager_chromeos.cc",
+ "test_media_transfer_protocol_manager_chromeos.h",
"test_portable_device_watcher_win.cc",
"test_portable_device_watcher_win.h",
"test_storage_monitor.cc",
@@ -111,7 +111,7 @@ source_set("test_support") {
"//content/public/browser",
]
- if (is_linux) {
+ if (is_chromeos && use_dbus) {
deps = [
"//device/media_transfer_protocol",
"//device/media_transfer_protocol:mtp_file_entry_proto",
@@ -131,7 +131,7 @@ source_set("unit_tests") {
sources = [
"image_capture_device_manager_unittest.mm",
"media_storage_util_unittest.cc",
- "media_transfer_protocol_device_observer_linux_unittest.cc",
+ "media_transfer_protocol_device_observer_chromeos_unittest.cc",
"storage_info_unittest.cc",
"storage_monitor_mac_unittest.mm",
"storage_monitor_unittest.cc",
@@ -146,17 +146,20 @@ source_set("unit_tests") {
"//testing/gtest",
]
- if (is_linux) {
- deps += [ "//device/media_transfer_protocol" ]
- if (!is_chromeos) {
+ if (use_dbus) {
+ if (is_chromeos) {
+ deps += [
+ "//device/media_transfer_protocol",
+ "//device/media_transfer_protocol:mtp_file_entry_proto",
+ "//device/media_transfer_protocol:mtp_storage_info_proto",
+ "//testing/gmock",
+ ]
+ sources += [ "storage_monitor_chromeos_unittest.cc" ]
+ } else if (is_linux) {
sources += [ "storage_monitor_linux_unittest.cc" ]
}
}
if (is_chromeos) {
- sources += [ "storage_monitor_chromeos_unittest.cc" ]
- deps += [
- "//chromeos:test_support",
- "//testing/gmock",
- ]
+ deps += [ "//chromeos:test_support" ]
}
}
diff --git a/chromium/components/storage_monitor/image_capture_device_manager_unittest.mm b/chromium/components/storage_monitor/image_capture_device_manager_unittest.mm
index 22a07ded33d..09dd75f50b5 100644
--- a/chromium/components/storage_monitor/image_capture_device_manager_unittest.mm
+++ b/chromium/components/storage_monitor/image_capture_device_manager_unittest.mm
@@ -358,7 +358,7 @@ TEST_F(ImageCaptureDeviceManagerTest, DownloadFile) {
// Test that a nonexistent file we ask to be downloaded will
// return us a not-found error.
- base::FilePath temp_file = temp_dir.path().Append("tempfile");
+ base::FilePath temp_file = temp_dir.GetPath().Append("tempfile");
[camera downloadFile:std::string("nonexistent") localPath:temp_file];
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1U, listener_.downloads().size());
@@ -405,7 +405,7 @@ TEST_F(ImageCaptureDeviceManagerTest, TestSubdirectories) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- base::FilePath temp_file = temp_dir.path().Append("tempfile");
+ base::FilePath temp_file = temp_dir.GetPath().Append("tempfile");
[camera downloadFile:("dir/" + kTestFileName) localPath:temp_file];
base::RunLoop().RunUntilIdle();
diff --git a/chromium/components/storage_monitor/media_storage_util_unittest.cc b/chromium/components/storage_monitor/media_storage_util_unittest.cc
index a63126465f9..5b895a8701d 100644
--- a/chromium/components/storage_monitor/media_storage_util_unittest.cc
+++ b/chromium/components/storage_monitor/media_storage_util_unittest.cc
@@ -52,12 +52,12 @@ class MediaStorageUtilTest : public testing::Test {
protected:
// Create mount point for the test device.
base::FilePath CreateMountPoint(bool create_dcim_dir) {
- base::FilePath path(scoped_temp_dir_.path());
+ base::FilePath path(scoped_temp_dir_.GetPath());
if (create_dcim_dir)
path = path.Append(kDCIMDirectoryName);
if (!base::CreateDirectory(path))
return base::FilePath();
- return scoped_temp_dir_.path();
+ return scoped_temp_dir_.GetPath();
}
void SetUp() override {
diff --git a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc
new file mode 100644
index 00000000000..061619991f3
--- /dev/null
+++ b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc
@@ -0,0 +1,252 @@
+// 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 "components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h"
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/storage_monitor/media_storage_util.h"
+#include "components/storage_monitor/removable_device_constants.h"
+#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
+
+namespace storage_monitor {
+
+namespace {
+
+// Device root path constant.
+const char kRootPath[] = "/";
+
+// Constructs and returns the location of the device using the |storage_name|.
+std::string GetDeviceLocationFromStorageName(const std::string& storage_name) {
+ // Construct a dummy device path using the storage name. This is only used
+ // for registering device media file system.
+ // E.g.: If the |storage_name| is "usb:2,2:12345" then "/usb:2,2:12345" is the
+ // device location.
+ DCHECK(!storage_name.empty());
+ return kRootPath + storage_name;
+}
+
+// Returns the storage identifier of the device from the given |storage_name|.
+// E.g. If the |storage_name| is "usb:2,2:65537", the storage identifier is
+// "65537".
+std::string GetStorageIdFromStorageName(const std::string& storage_name) {
+ std::vector<base::StringPiece> name_parts = base::SplitStringPiece(
+ storage_name, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ return name_parts.size() == 3 ? name_parts[2].as_string() : std::string();
+}
+
+// Returns a unique device id from the given |storage_info|.
+std::string GetDeviceIdFromStorageInfo(const MtpStorageInfo& storage_info) {
+ const std::string storage_id =
+ GetStorageIdFromStorageName(storage_info.storage_name());
+ if (storage_id.empty())
+ return std::string();
+
+ // Some devices have multiple data stores. Therefore, include storage id as
+ // part of unique id along with vendor, model and volume information.
+ const std::string vendor_id = base::UintToString(storage_info.vendor_id());
+ const std::string model_id = base::UintToString(storage_info.product_id());
+ return StorageInfo::MakeDeviceId(
+ StorageInfo::MTP_OR_PTP,
+ kVendorModelVolumeStoragePrefix + vendor_id + ":" + model_id + ":" +
+ storage_info.volume_identifier() + ":" + storage_id);
+}
+
+// Returns the |data_store_id| string in the required format.
+// If the |data_store_id| is 65537, this function returns " (65537)".
+std::string GetFormattedIdString(const std::string& data_store_id) {
+ return ("(" + data_store_id + ")");
+}
+
+// Helper function to get device label from storage information.
+base::string16 GetDeviceLabelFromStorageInfo(
+ const MtpStorageInfo& storage_info) {
+ std::string device_label;
+ const std::string& vendor_name = storage_info.vendor();
+ device_label = vendor_name;
+
+ const std::string& product_name = storage_info.product();
+ if (!product_name.empty()) {
+ if (!device_label.empty())
+ device_label += " ";
+ device_label += product_name;
+ }
+
+ // Add the data store id to the device label.
+ if (!device_label.empty()) {
+ const std::string& volume_id = storage_info.volume_identifier();
+ if (!volume_id.empty()) {
+ device_label += GetFormattedIdString(volume_id);
+ } else {
+ const std::string data_store_id =
+ GetStorageIdFromStorageName(storage_info.storage_name());
+ if (!data_store_id.empty())
+ device_label += GetFormattedIdString(data_store_id);
+ }
+ }
+ return base::UTF8ToUTF16(device_label);
+}
+
+// Helper function to get the device storage details such as device id, label
+// and location. On success and fills in |id|, |label|, |location|,
+// |vendor_name|, and |product_name|.
+void GetStorageInfo(const std::string& storage_name,
+ device::MediaTransferProtocolManager* mtp_manager,
+ std::string* id,
+ base::string16* label,
+ std::string* location,
+ base::string16* vendor_name,
+ base::string16* product_name) {
+ DCHECK(!storage_name.empty());
+ const MtpStorageInfo* storage_info =
+ mtp_manager->GetStorageInfo(storage_name);
+
+ if (!storage_info)
+ return;
+
+ *id = GetDeviceIdFromStorageInfo(*storage_info);
+ *label = GetDeviceLabelFromStorageInfo(*storage_info);
+ *location = GetDeviceLocationFromStorageName(storage_name);
+ *vendor_name = base::UTF8ToUTF16(storage_info->vendor());
+ *product_name = base::UTF8ToUTF16(storage_info->product());
+}
+
+} // namespace
+
+MediaTransferProtocolDeviceObserverChromeOS::
+ MediaTransferProtocolDeviceObserverChromeOS(
+ StorageMonitor::Receiver* receiver,
+ device::MediaTransferProtocolManager* mtp_manager)
+ : mtp_manager_(mtp_manager),
+ get_storage_info_func_(&GetStorageInfo),
+ notifications_(receiver) {
+ mtp_manager_->AddObserver(this);
+ EnumerateStorages();
+}
+
+// This constructor is only used by unit tests.
+MediaTransferProtocolDeviceObserverChromeOS::
+ MediaTransferProtocolDeviceObserverChromeOS(
+ StorageMonitor::Receiver* receiver,
+ device::MediaTransferProtocolManager* mtp_manager,
+ GetStorageInfoFunc get_storage_info_func)
+ : mtp_manager_(mtp_manager),
+ get_storage_info_func_(get_storage_info_func),
+ notifications_(receiver) {}
+
+MediaTransferProtocolDeviceObserverChromeOS::
+ ~MediaTransferProtocolDeviceObserverChromeOS() {
+ mtp_manager_->RemoveObserver(this);
+}
+
+bool MediaTransferProtocolDeviceObserverChromeOS::GetStorageInfoForPath(
+ const base::FilePath& path,
+ StorageInfo* storage_info) const {
+ DCHECK(storage_info);
+
+ if (!path.IsAbsolute())
+ return false;
+
+ std::vector<base::FilePath::StringType> path_components;
+ path.GetComponents(&path_components);
+ if (path_components.size() < 2)
+ return false;
+
+ // First and second component of the path specifies the device location.
+ // E.g.: If |path| is "/usb:2,2:65537/DCIM/Folder_a", "/usb:2,2:65537" is the
+ // device location.
+ StorageLocationToInfoMap::const_iterator info_it =
+ storage_map_.find(GetDeviceLocationFromStorageName(path_components[1]));
+ if (info_it == storage_map_.end())
+ return false;
+
+ *storage_info = info_it->second;
+ return true;
+}
+
+void MediaTransferProtocolDeviceObserverChromeOS::EjectDevice(
+ const std::string& device_id,
+ base::Callback<void(StorageMonitor::EjectStatus)> callback) {
+ std::string location;
+ if (!GetLocationForDeviceId(device_id, &location)) {
+ callback.Run(StorageMonitor::EJECT_NO_SUCH_DEVICE);
+ return;
+ }
+
+ // TODO(thestig): Change this to tell the mtp manager to eject the device.
+
+ StorageChanged(false, location);
+ callback.Run(StorageMonitor::EJECT_OK);
+}
+
+// device::MediaTransferProtocolManager::Observer override.
+void MediaTransferProtocolDeviceObserverChromeOS::StorageChanged(
+ bool is_attached,
+ const std::string& storage_name) {
+ DCHECK(!storage_name.empty());
+
+ // New storage is attached.
+ if (is_attached) {
+ std::string device_id;
+ base::string16 storage_label;
+ std::string location;
+ base::string16 vendor_name;
+ base::string16 product_name;
+ get_storage_info_func_(storage_name, mtp_manager_, &device_id,
+ &storage_label, &location, &vendor_name,
+ &product_name);
+
+ // Keep track of device id and device name to see how often we receive
+ // empty values.
+ MediaStorageUtil::RecordDeviceInfoHistogram(false, device_id,
+ storage_label);
+ if (device_id.empty() || storage_label.empty())
+ return;
+
+ DCHECK(!base::ContainsKey(storage_map_, location));
+
+ StorageInfo storage_info(device_id, location, storage_label, vendor_name,
+ product_name, 0);
+ storage_map_[location] = storage_info;
+ notifications_->ProcessAttach(storage_info);
+ } else {
+ // Existing storage is detached.
+ StorageLocationToInfoMap::iterator it =
+ storage_map_.find(GetDeviceLocationFromStorageName(storage_name));
+ if (it == storage_map_.end())
+ return;
+ notifications_->ProcessDetach(it->second.device_id());
+ storage_map_.erase(it);
+ }
+}
+
+void MediaTransferProtocolDeviceObserverChromeOS::EnumerateStorages() {
+ typedef std::vector<std::string> StorageList;
+ StorageList storages = mtp_manager_->GetStorages();
+ for (StorageList::const_iterator storage_iter = storages.begin();
+ storage_iter != storages.end(); ++storage_iter) {
+ StorageChanged(true, *storage_iter);
+ }
+}
+
+bool MediaTransferProtocolDeviceObserverChromeOS::GetLocationForDeviceId(
+ const std::string& device_id,
+ std::string* location) const {
+ for (StorageLocationToInfoMap::const_iterator it = storage_map_.begin();
+ it != storage_map_.end(); ++it) {
+ if (it->second.device_id() == device_id) {
+ *location = it->first;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace storage_monitor
diff --git a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h
new file mode 100644
index 00000000000..a004426f3f9
--- /dev/null
+++ b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h
@@ -0,0 +1,95 @@
+// 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 COMPONENTS_STORAGE_MONITOR_MEDIA_TRANSFER_PROTOCOL_DEVICE_OBSERVER_CHROMEOS_H_
+#define COMPONENTS_STORAGE_MONITOR_MEDIA_TRANSFER_PROTOCOL_DEVICE_OBSERVER_CHROMEOS_H_
+
+#include <map>
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/storage_monitor/storage_monitor.h"
+#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace storage_monitor {
+
+// Gets the mtp device information given a |storage_name|. On success,
+// fills in |id|, |name|, |location|, |vendor_name|, and |product_name|.
+typedef void (*GetStorageInfoFunc)(
+ const std::string& storage_name,
+ device::MediaTransferProtocolManager* mtp_manager,
+ std::string* id,
+ base::string16* name,
+ std::string* location,
+ base::string16* vendor_name,
+ base::string16* product_name);
+
+// Helper class to send MTP storage attachment and detachment events to
+// StorageMonitor.
+class MediaTransferProtocolDeviceObserverChromeOS
+ : public device::MediaTransferProtocolManager::Observer {
+ public:
+ MediaTransferProtocolDeviceObserverChromeOS(
+ StorageMonitor::Receiver* receiver,
+ device::MediaTransferProtocolManager* mtp_manager);
+ ~MediaTransferProtocolDeviceObserverChromeOS() override;
+
+ // Finds the storage that contains |path| and populates |storage_info|.
+ // Returns false if unable to find the storage.
+ bool GetStorageInfoForPath(const base::FilePath& path,
+ StorageInfo* storage_info) const;
+
+ void EjectDevice(const std::string& device_id,
+ base::Callback<void(StorageMonitor::EjectStatus)> callback);
+
+ protected:
+ // Only used in unit tests.
+ MediaTransferProtocolDeviceObserverChromeOS(
+ StorageMonitor::Receiver* receiver,
+ device::MediaTransferProtocolManager* mtp_manager,
+ GetStorageInfoFunc get_storage_info_func);
+
+ // device::MediaTransferProtocolManager::Observer implementation.
+ // Exposed for unit tests.
+ void StorageChanged(bool is_attached,
+ const std::string& storage_name) override;
+
+ private:
+ // Mapping of storage location and mtp storage info object.
+ typedef std::map<std::string, StorageInfo> StorageLocationToInfoMap;
+
+ // Enumerate existing mtp storage devices.
+ void EnumerateStorages();
+
+ // Find the |storage_map_| key for the record with this |device_id|. Returns
+ // true on success, false on failure.
+ bool GetLocationForDeviceId(const std::string& device_id,
+ std::string* location) const;
+
+ // Pointer to the MTP manager. Not owned. Client must ensure the MTP
+ // manager outlives this object.
+ device::MediaTransferProtocolManager* mtp_manager_;
+
+ // Map of all attached mtp devices.
+ StorageLocationToInfoMap storage_map_;
+
+ // Function handler to get storage information. This is useful to set a mock
+ // handler for unit testing.
+ GetStorageInfoFunc get_storage_info_func_;
+
+ // The notifications object to use to signal newly attached devices.
+ // Guaranteed to outlive this class.
+ StorageMonitor::Receiver* const notifications_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDeviceObserverChromeOS);
+};
+
+} // namespace storage_monitor
+
+#endif // COMPONENTS_STORAGE_MONITOR_MEDIA_TRANSFER_PROTOCOL_DEVICE_OBSERVER_CHROMEOS_H_
diff --git a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos_unittest.cc b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos_unittest.cc
new file mode 100644
index 00000000000..0ddc6123e3d
--- /dev/null
+++ b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos_unittest.cc
@@ -0,0 +1,177 @@
+// 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.
+//
+// MediaTransferProtocolDeviceObserverChromeOS unit tests.
+
+#include "components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h"
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/storage_monitor/mock_removable_storage_observer.h"
+#include "components/storage_monitor/storage_info.h"
+#include "components/storage_monitor/storage_monitor.h"
+#include "components/storage_monitor/test_storage_monitor.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace storage_monitor {
+
+namespace {
+
+// Sample mtp device storage information.
+const char kStorageLabel[] = "Camera V1.0";
+const char kStorageLocation[] = "/usb:2,2,88888";
+const char kStorageUniqueId[] = "VendorModelSerial:COM:MOD2012:283";
+const char kStorageWithInvalidInfo[] = "usb:2,3,11111";
+const char kStorageWithValidInfo[] = "usb:2,2,88888";
+const char kStorageVendor[] = "ExampleVendor";
+const char kStorageProductName[] = "ExampleCamera";
+
+// Returns the mtp device id given the |unique_id|.
+std::string GetMtpDeviceId(const std::string& unique_id) {
+ return StorageInfo::MakeDeviceId(StorageInfo::MTP_OR_PTP, unique_id);
+}
+
+// Helper function to get the device storage details such as device id, label
+// and location. On success, fills in |id|, |label|, |location|, |vendor_name|,
+// and |product_name|.
+void GetStorageInfo(const std::string& storage_name,
+ device::MediaTransferProtocolManager* mtp_manager,
+ std::string* id,
+ base::string16* label,
+ std::string* location,
+ base::string16* vendor_name,
+ base::string16* product_name) {
+ if (storage_name == kStorageWithInvalidInfo)
+ return; // Do not set any storage details.
+
+ ASSERT_EQ(kStorageWithValidInfo, storage_name);
+
+ *id = GetMtpDeviceId(kStorageUniqueId);
+ *label = base::ASCIIToUTF16(kStorageLabel);
+ *location = kStorageLocation;
+ *vendor_name = base::ASCIIToUTF16(kStorageVendor);
+ *product_name = base::ASCIIToUTF16(kStorageProductName);
+}
+
+class TestMediaTransferProtocolDeviceObserverChromeOS
+ : public MediaTransferProtocolDeviceObserverChromeOS {
+ public:
+ TestMediaTransferProtocolDeviceObserverChromeOS(
+ StorageMonitor::Receiver* receiver,
+ device::MediaTransferProtocolManager* mtp_manager)
+ : MediaTransferProtocolDeviceObserverChromeOS(receiver,
+ mtp_manager,
+ &GetStorageInfo) {}
+
+ // Notifies MediaTransferProtocolDeviceObserverChromeOS about the attachment
+ // of
+ // mtp storage device given the |storage_name|.
+ void MtpStorageAttached(const std::string& storage_name) {
+ StorageChanged(true, storage_name);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ // Notifies MediaTransferProtocolDeviceObserverChromeOS about the detachment
+ // of
+ // mtp storage device given the |storage_name|.
+ void MtpStorageDetached(const std::string& storage_name) {
+ StorageChanged(false, storage_name);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestMediaTransferProtocolDeviceObserverChromeOS);
+};
+
+} // namespace
+
+// A class to test the functionality of
+// MediaTransferProtocolDeviceObserverChromeOS member functions.
+class MediaTransferProtocolDeviceObserverChromeOSTest : public testing::Test {
+ public:
+ MediaTransferProtocolDeviceObserverChromeOSTest()
+ : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
+
+ ~MediaTransferProtocolDeviceObserverChromeOSTest() override {}
+
+ protected:
+ void SetUp() override {
+ mock_storage_observer_.reset(new MockRemovableStorageObserver);
+ TestStorageMonitor* monitor = TestStorageMonitor::CreateAndInstall();
+ mtp_device_observer_.reset(
+ new TestMediaTransferProtocolDeviceObserverChromeOS(
+ monitor->receiver(), monitor->media_transfer_protocol_manager()));
+ monitor->AddObserver(mock_storage_observer_.get());
+ }
+
+ void TearDown() override {
+ StorageMonitor* monitor = StorageMonitor::GetInstance();
+ monitor->RemoveObserver(mock_storage_observer_.get());
+ mtp_device_observer_.reset();
+ TestStorageMonitor::Destroy();
+ }
+
+ // Returns the device changed observer object.
+ MockRemovableStorageObserver& observer() { return *mock_storage_observer_; }
+
+ TestMediaTransferProtocolDeviceObserverChromeOS* mtp_device_observer() {
+ return mtp_device_observer_.get();
+ }
+
+ private:
+ content::TestBrowserThreadBundle thread_bundle_;
+
+ std::unique_ptr<TestMediaTransferProtocolDeviceObserverChromeOS>
+ mtp_device_observer_;
+ std::unique_ptr<MockRemovableStorageObserver> mock_storage_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDeviceObserverChromeOSTest);
+};
+
+// Test to verify basic mtp storage attach and detach notifications.
+TEST_F(MediaTransferProtocolDeviceObserverChromeOSTest, BasicAttachDetach) {
+ std::string device_id = GetMtpDeviceId(kStorageUniqueId);
+
+ // Attach a mtp storage.
+ mtp_device_observer()->MtpStorageAttached(kStorageWithValidInfo);
+
+ EXPECT_EQ(1, observer().attach_calls());
+ EXPECT_EQ(0, observer().detach_calls());
+ EXPECT_EQ(device_id, observer().last_attached().device_id());
+ EXPECT_EQ(kStorageLocation, observer().last_attached().location());
+ EXPECT_EQ(base::ASCIIToUTF16(kStorageVendor),
+ observer().last_attached().vendor_name());
+ EXPECT_EQ(base::ASCIIToUTF16(kStorageProductName),
+ observer().last_attached().model_name());
+
+ // Detach the attached storage.
+ mtp_device_observer()->MtpStorageDetached(kStorageWithValidInfo);
+
+ EXPECT_EQ(1, observer().attach_calls());
+ EXPECT_EQ(1, observer().detach_calls());
+ EXPECT_EQ(device_id, observer().last_detached().device_id());
+}
+
+// When a mtp storage device with invalid storage label and id is
+// attached/detached, there should not be any device attach/detach
+// notifications.
+TEST_F(MediaTransferProtocolDeviceObserverChromeOSTest,
+ StorageWithInvalidInfo) {
+ // Attach the mtp storage with invalid storage info.
+ mtp_device_observer()->MtpStorageAttached(kStorageWithInvalidInfo);
+
+ // Detach the attached storage.
+ mtp_device_observer()->MtpStorageDetached(kStorageWithInvalidInfo);
+
+ EXPECT_EQ(0, observer().attach_calls());
+ EXPECT_EQ(0, observer().detach_calls());
+}
+
+} // namespace storage_monitor
diff --git a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux.cc b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux.cc
deleted file mode 100644
index 7d093d97e96..00000000000
--- a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux.cc
+++ /dev/null
@@ -1,252 +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 "components/storage_monitor/media_transfer_protocol_device_observer_linux.h"
-
-#include <vector>
-
-#include "base/files/file_path.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/storage_monitor/media_storage_util.h"
-#include "components/storage_monitor/removable_device_constants.h"
-#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
-
-namespace storage_monitor {
-
-namespace {
-
-// Device root path constant.
-const char kRootPath[] = "/";
-
-// Constructs and returns the location of the device using the |storage_name|.
-std::string GetDeviceLocationFromStorageName(const std::string& storage_name) {
- // Construct a dummy device path using the storage name. This is only used
- // for registering device media file system.
- // E.g.: If the |storage_name| is "usb:2,2:12345" then "/usb:2,2:12345" is the
- // device location.
- DCHECK(!storage_name.empty());
- return kRootPath + storage_name;
-}
-
-// Returns the storage identifier of the device from the given |storage_name|.
-// E.g. If the |storage_name| is "usb:2,2:65537", the storage identifier is
-// "65537".
-std::string GetStorageIdFromStorageName(const std::string& storage_name) {
- std::vector<base::StringPiece> name_parts = base::SplitStringPiece(
- storage_name, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- return name_parts.size() == 3 ? name_parts[2].as_string() : std::string();
-}
-
-// Returns a unique device id from the given |storage_info|.
-std::string GetDeviceIdFromStorageInfo(const MtpStorageInfo& storage_info) {
- const std::string storage_id =
- GetStorageIdFromStorageName(storage_info.storage_name());
- if (storage_id.empty())
- return std::string();
-
- // Some devices have multiple data stores. Therefore, include storage id as
- // part of unique id along with vendor, model and volume information.
- const std::string vendor_id = base::UintToString(storage_info.vendor_id());
- const std::string model_id = base::UintToString(storage_info.product_id());
- return StorageInfo::MakeDeviceId(
- StorageInfo::MTP_OR_PTP,
- kVendorModelVolumeStoragePrefix + vendor_id + ":" + model_id + ":" +
- storage_info.volume_identifier() + ":" + storage_id);
-}
-
-// Returns the |data_store_id| string in the required format.
-// If the |data_store_id| is 65537, this function returns " (65537)".
-std::string GetFormattedIdString(const std::string& data_store_id) {
- return ("(" + data_store_id + ")");
-}
-
-// Helper function to get device label from storage information.
-base::string16 GetDeviceLabelFromStorageInfo(
- const MtpStorageInfo& storage_info) {
- std::string device_label;
- const std::string& vendor_name = storage_info.vendor();
- device_label = vendor_name;
-
- const std::string& product_name = storage_info.product();
- if (!product_name.empty()) {
- if (!device_label.empty())
- device_label += " ";
- device_label += product_name;
- }
-
- // Add the data store id to the device label.
- if (!device_label.empty()) {
- const std::string& volume_id = storage_info.volume_identifier();
- if (!volume_id.empty()) {
- device_label += GetFormattedIdString(volume_id);
- } else {
- const std::string data_store_id =
- GetStorageIdFromStorageName(storage_info.storage_name());
- if (!data_store_id.empty())
- device_label += GetFormattedIdString(data_store_id);
- }
- }
- return base::UTF8ToUTF16(device_label);
-}
-
-// Helper function to get the device storage details such as device id, label
-// and location. On success and fills in |id|, |label|, |location|,
-// |vendor_name|, and |product_name|.
-void GetStorageInfo(const std::string& storage_name,
- device::MediaTransferProtocolManager* mtp_manager,
- std::string* id,
- base::string16* label,
- std::string* location,
- base::string16* vendor_name,
- base::string16* product_name) {
- DCHECK(!storage_name.empty());
- const MtpStorageInfo* storage_info =
- mtp_manager->GetStorageInfo(storage_name);
-
- if (!storage_info)
- return;
-
- *id = GetDeviceIdFromStorageInfo(*storage_info);
- *label = GetDeviceLabelFromStorageInfo(*storage_info);
- *location = GetDeviceLocationFromStorageName(storage_name);
- *vendor_name = base::UTF8ToUTF16(storage_info->vendor());
- *product_name = base::UTF8ToUTF16(storage_info->product());
-}
-
-} // namespace
-
-MediaTransferProtocolDeviceObserverLinux::
-MediaTransferProtocolDeviceObserverLinux(
- StorageMonitor::Receiver* receiver,
- device::MediaTransferProtocolManager* mtp_manager)
- : mtp_manager_(mtp_manager),
- get_storage_info_func_(&GetStorageInfo),
- notifications_(receiver) {
- mtp_manager_->AddObserver(this);
- EnumerateStorages();
-}
-
-// This constructor is only used by unit tests.
-MediaTransferProtocolDeviceObserverLinux::
-MediaTransferProtocolDeviceObserverLinux(
- StorageMonitor::Receiver* receiver,
- device::MediaTransferProtocolManager* mtp_manager,
- GetStorageInfoFunc get_storage_info_func)
- : mtp_manager_(mtp_manager),
- get_storage_info_func_(get_storage_info_func),
- notifications_(receiver) {
-}
-
-MediaTransferProtocolDeviceObserverLinux::
-~MediaTransferProtocolDeviceObserverLinux() {
- mtp_manager_->RemoveObserver(this);
-}
-
-bool MediaTransferProtocolDeviceObserverLinux::GetStorageInfoForPath(
- const base::FilePath& path,
- StorageInfo* storage_info) const {
- DCHECK(storage_info);
-
- if (!path.IsAbsolute())
- return false;
-
- std::vector<base::FilePath::StringType> path_components;
- path.GetComponents(&path_components);
- if (path_components.size() < 2)
- return false;
-
- // First and second component of the path specifies the device location.
- // E.g.: If |path| is "/usb:2,2:65537/DCIM/Folder_a", "/usb:2,2:65537" is the
- // device location.
- StorageLocationToInfoMap::const_iterator info_it =
- storage_map_.find(GetDeviceLocationFromStorageName(path_components[1]));
- if (info_it == storage_map_.end())
- return false;
-
- *storage_info = info_it->second;
- return true;
-}
-
-void MediaTransferProtocolDeviceObserverLinux::EjectDevice(
- const std::string& device_id,
- base::Callback<void(StorageMonitor::EjectStatus)> callback) {
- std::string location;
- if (!GetLocationForDeviceId(device_id, &location)) {
- callback.Run(StorageMonitor::EJECT_NO_SUCH_DEVICE);
- return;
- }
-
- // TODO(thestig): Change this to tell the mtp manager to eject the device.
-
- StorageChanged(false, location);
- callback.Run(StorageMonitor::EJECT_OK);
-}
-
-// device::MediaTransferProtocolManager::Observer override.
-void MediaTransferProtocolDeviceObserverLinux::StorageChanged(
- bool is_attached,
- const std::string& storage_name) {
- DCHECK(!storage_name.empty());
-
- // New storage is attached.
- if (is_attached) {
- std::string device_id;
- base::string16 storage_label;
- std::string location;
- base::string16 vendor_name;
- base::string16 product_name;
- get_storage_info_func_(storage_name, mtp_manager_,
- &device_id, &storage_label, &location,
- &vendor_name, &product_name);
-
- // Keep track of device id and device name to see how often we receive
- // empty values.
- MediaStorageUtil::RecordDeviceInfoHistogram(false, device_id,
- storage_label);
- if (device_id.empty() || storage_label.empty())
- return;
-
- DCHECK(!ContainsKey(storage_map_, location));
-
- StorageInfo storage_info(device_id, location, storage_label,
- vendor_name, product_name, 0);
- storage_map_[location] = storage_info;
- notifications_->ProcessAttach(storage_info);
- } else {
- // Existing storage is detached.
- StorageLocationToInfoMap::iterator it =
- storage_map_.find(GetDeviceLocationFromStorageName(storage_name));
- if (it == storage_map_.end())
- return;
- notifications_->ProcessDetach(it->second.device_id());
- storage_map_.erase(it);
- }
-}
-
-void MediaTransferProtocolDeviceObserverLinux::EnumerateStorages() {
- typedef std::vector<std::string> StorageList;
- StorageList storages = mtp_manager_->GetStorages();
- for (StorageList::const_iterator storage_iter = storages.begin();
- storage_iter != storages.end(); ++storage_iter) {
- StorageChanged(true, *storage_iter);
- }
-}
-
-bool MediaTransferProtocolDeviceObserverLinux::GetLocationForDeviceId(
- const std::string& device_id, std::string* location) const {
- for (StorageLocationToInfoMap::const_iterator it = storage_map_.begin();
- it != storage_map_.end(); ++it) {
- if (it->second.device_id() == device_id) {
- *location = it->first;
- return true;
- }
- }
-
- return false;
-}
-
-} // namespace storage_monitor
diff --git a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux.h b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux.h
deleted file mode 100644
index 611d0da2940..00000000000
--- a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux.h
+++ /dev/null
@@ -1,95 +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 COMPONENTS_STORAGE_MONITOR_MEDIA_TRANSFER_PROTOCOL_DEVICE_OBSERVER_LINUX_H_
-#define COMPONENTS_STORAGE_MONITOR_MEDIA_TRANSFER_PROTOCOL_DEVICE_OBSERVER_LINUX_H_
-
-#include <map>
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "components/storage_monitor/storage_monitor.h"
-#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace storage_monitor {
-
-// Gets the mtp device information given a |storage_name|. On success,
-// fills in |id|, |name|, |location|, |vendor_name|, and |product_name|.
-typedef void (*GetStorageInfoFunc)(
- const std::string& storage_name,
- device::MediaTransferProtocolManager* mtp_manager,
- std::string* id,
- base::string16* name,
- std::string* location,
- base::string16* vendor_name,
- base::string16* product_name);
-
-// Helper class to send MTP storage attachment and detachment events to
-// StorageMonitor.
-class MediaTransferProtocolDeviceObserverLinux
- : public device::MediaTransferProtocolManager::Observer {
- public:
- MediaTransferProtocolDeviceObserverLinux(
- StorageMonitor::Receiver* receiver,
- device::MediaTransferProtocolManager* mtp_manager);
- ~MediaTransferProtocolDeviceObserverLinux() override;
-
- // Finds the storage that contains |path| and populates |storage_info|.
- // Returns false if unable to find the storage.
- bool GetStorageInfoForPath(const base::FilePath& path,
- StorageInfo* storage_info) const;
-
- void EjectDevice(const std::string& device_id,
- base::Callback<void(StorageMonitor::EjectStatus)> callback);
-
- protected:
- // Only used in unit tests.
- MediaTransferProtocolDeviceObserverLinux(
- StorageMonitor::Receiver* receiver,
- device::MediaTransferProtocolManager* mtp_manager,
- GetStorageInfoFunc get_storage_info_func);
-
- // device::MediaTransferProtocolManager::Observer implementation.
- // Exposed for unit tests.
- void StorageChanged(bool is_attached,
- const std::string& storage_name) override;
-
- private:
- // Mapping of storage location and mtp storage info object.
- typedef std::map<std::string, StorageInfo> StorageLocationToInfoMap;
-
- // Enumerate existing mtp storage devices.
- void EnumerateStorages();
-
- // Find the |storage_map_| key for the record with this |device_id|. Returns
- // true on success, false on failure.
- bool GetLocationForDeviceId(const std::string& device_id,
- std::string* location) const;
-
- // Pointer to the MTP manager. Not owned. Client must ensure the MTP
- // manager outlives this object.
- device::MediaTransferProtocolManager* mtp_manager_;
-
- // Map of all attached mtp devices.
- StorageLocationToInfoMap storage_map_;
-
- // Function handler to get storage information. This is useful to set a mock
- // handler for unit testing.
- GetStorageInfoFunc get_storage_info_func_;
-
- // The notifications object to use to signal newly attached devices.
- // Guaranteed to outlive this class.
- StorageMonitor::Receiver* const notifications_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDeviceObserverLinux);
-};
-
-} // namespace storage_monitor
-
-#endif // COMPONENTS_STORAGE_MONITOR_MEDIA_TRANSFER_PROTOCOL_DEVICE_OBSERVER_LINUX_H_
diff --git a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc
deleted file mode 100644
index 0bb6ba81bc4..00000000000
--- a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_linux_unittest.cc
+++ /dev/null
@@ -1,176 +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.
-//
-// MediaTransferProtocolDeviceObserverLinux unit tests.
-
-#include "components/storage_monitor/media_transfer_protocol_device_observer_linux.h"
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/storage_monitor/mock_removable_storage_observer.h"
-#include "components/storage_monitor/storage_info.h"
-#include "components/storage_monitor/storage_monitor.h"
-#include "components/storage_monitor/test_storage_monitor.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace storage_monitor {
-
-namespace {
-
-// Sample mtp device storage information.
-const char kStorageLabel[] = "Camera V1.0";
-const char kStorageLocation[] = "/usb:2,2,88888";
-const char kStorageUniqueId[] = "VendorModelSerial:COM:MOD2012:283";
-const char kStorageWithInvalidInfo[] = "usb:2,3,11111";
-const char kStorageWithValidInfo[] = "usb:2,2,88888";
-const char kStorageVendor[] = "ExampleVendor";
-const char kStorageProductName[] = "ExampleCamera";
-
-// Returns the mtp device id given the |unique_id|.
-std::string GetMtpDeviceId(const std::string& unique_id) {
- return StorageInfo::MakeDeviceId(StorageInfo::MTP_OR_PTP, unique_id);
-}
-
-// Helper function to get the device storage details such as device id, label
-// and location. On success, fills in |id|, |label|, |location|, |vendor_name|,
-// and |product_name|.
-void GetStorageInfo(const std::string& storage_name,
- device::MediaTransferProtocolManager* mtp_manager,
- std::string* id,
- base::string16* label,
- std::string* location,
- base::string16* vendor_name,
- base::string16* product_name) {
- if (storage_name == kStorageWithInvalidInfo)
- return; // Do not set any storage details.
-
- ASSERT_EQ(kStorageWithValidInfo, storage_name);
-
- *id = GetMtpDeviceId(kStorageUniqueId);
- *label = base::ASCIIToUTF16(kStorageLabel);
- *location = kStorageLocation;
- *vendor_name = base::ASCIIToUTF16(kStorageVendor);
- *product_name = base::ASCIIToUTF16(kStorageProductName);
-}
-
-class TestMediaTransferProtocolDeviceObserverLinux
- : public MediaTransferProtocolDeviceObserverLinux {
- public:
- TestMediaTransferProtocolDeviceObserverLinux(
- StorageMonitor::Receiver* receiver,
- device::MediaTransferProtocolManager* mtp_manager)
- : MediaTransferProtocolDeviceObserverLinux(receiver, mtp_manager,
- &GetStorageInfo) {
- }
-
- // Notifies MediaTransferProtocolDeviceObserverLinux about the attachment of
- // mtp storage device given the |storage_name|.
- void MtpStorageAttached(const std::string& storage_name) {
- StorageChanged(true, storage_name);
- base::RunLoop().RunUntilIdle();
- }
-
- // Notifies MediaTransferProtocolDeviceObserverLinux about the detachment of
- // mtp storage device given the |storage_name|.
- void MtpStorageDetached(const std::string& storage_name) {
- StorageChanged(false, storage_name);
- base::RunLoop().RunUntilIdle();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestMediaTransferProtocolDeviceObserverLinux);
-};
-
-} // namespace
-
-// A class to test the functionality of MediaTransferProtocolDeviceObserverLinux
-// member functions.
-class MediaTransferProtocolDeviceObserverLinuxTest : public testing::Test {
- public:
- MediaTransferProtocolDeviceObserverLinuxTest()
- : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
-
- ~MediaTransferProtocolDeviceObserverLinuxTest() override {}
-
- protected:
- void SetUp() override {
- mock_storage_observer_.reset(new MockRemovableStorageObserver);
- TestStorageMonitor* monitor = TestStorageMonitor::CreateAndInstall();
- mtp_device_observer_.reset(
- new TestMediaTransferProtocolDeviceObserverLinux(
- monitor->receiver(), monitor->media_transfer_protocol_manager()));
- monitor->AddObserver(mock_storage_observer_.get());
- }
-
- void TearDown() override {
- StorageMonitor* monitor = StorageMonitor::GetInstance();
- monitor->RemoveObserver(mock_storage_observer_.get());
- mtp_device_observer_.reset();
- TestStorageMonitor::Destroy();
- }
-
- // Returns the device changed observer object.
- MockRemovableStorageObserver& observer() {
- return *mock_storage_observer_;
- }
-
- TestMediaTransferProtocolDeviceObserverLinux* mtp_device_observer() {
- return mtp_device_observer_.get();
- }
-
- private:
- content::TestBrowserThreadBundle thread_bundle_;
-
- std::unique_ptr<TestMediaTransferProtocolDeviceObserverLinux>
- mtp_device_observer_;
- std::unique_ptr<MockRemovableStorageObserver> mock_storage_observer_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDeviceObserverLinuxTest);
-};
-
-// Test to verify basic mtp storage attach and detach notifications.
-TEST_F(MediaTransferProtocolDeviceObserverLinuxTest, BasicAttachDetach) {
- std::string device_id = GetMtpDeviceId(kStorageUniqueId);
-
- // Attach a mtp storage.
- mtp_device_observer()->MtpStorageAttached(kStorageWithValidInfo);
-
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
- EXPECT_EQ(device_id, observer().last_attached().device_id());
- EXPECT_EQ(kStorageLocation, observer().last_attached().location());
- EXPECT_EQ(base::ASCIIToUTF16(kStorageVendor),
- observer().last_attached().vendor_name());
- EXPECT_EQ(base::ASCIIToUTF16(kStorageProductName),
- observer().last_attached().model_name());
-
- // Detach the attached storage.
- mtp_device_observer()->MtpStorageDetached(kStorageWithValidInfo);
-
- EXPECT_EQ(1, observer().attach_calls());
- EXPECT_EQ(1, observer().detach_calls());
- EXPECT_EQ(device_id, observer().last_detached().device_id());
-}
-
-// When a mtp storage device with invalid storage label and id is
-// attached/detached, there should not be any device attach/detach
-// notifications.
-TEST_F(MediaTransferProtocolDeviceObserverLinuxTest, StorageWithInvalidInfo) {
- // Attach the mtp storage with invalid storage info.
- mtp_device_observer()->MtpStorageAttached(kStorageWithInvalidInfo);
-
- // Detach the attached storage.
- mtp_device_observer()->MtpStorageDetached(kStorageWithInvalidInfo);
-
- EXPECT_EQ(0, observer().attach_calls());
- EXPECT_EQ(0, observer().detach_calls());
-}
-
-} // namespace storage_monitor
diff --git a/chromium/components/storage_monitor/portable_device_watcher_win.cc b/chromium/components/storage_monitor/portable_device_watcher_win.cc
index 421e112602c..1fa2e2320f5 100644
--- a/chromium/components/storage_monitor/portable_device_watcher_win.cc
+++ b/chromium/components/storage_monitor/portable_device_watcher_win.cc
@@ -626,11 +626,11 @@ void PortableDeviceWatcherWin::OnDidHandleDeviceAttachEvent(
const StorageObjects& storage_objects = device_details->storage_objects;
const base::string16& name = device_details->name;
const base::string16& location = device_details->location;
- DCHECK(!ContainsKey(device_map_, location));
+ DCHECK(!base::ContainsKey(device_map_, location));
for (StorageObjects::const_iterator storage_iter = storage_objects.begin();
storage_iter != storage_objects.end(); ++storage_iter) {
const std::string& storage_id = storage_iter->object_persistent_id;
- DCHECK(!ContainsKey(storage_map_, storage_id));
+ DCHECK(!base::ContainsKey(storage_map_, storage_id));
// Keep track of storage id and storage name to see how often we receive
// empty values.
diff --git a/chromium/components/storage_monitor/storage_monitor.cc b/chromium/components/storage_monitor/storage_monitor.cc
index 6f2b23ccace..beb45fd2c33 100644
--- a/chromium/components/storage_monitor/storage_monitor.cc
+++ b/chromium/components/storage_monitor/storage_monitor.cc
@@ -162,7 +162,7 @@ void StorageMonitor::MarkInitialized() {
void StorageMonitor::ProcessAttach(const StorageInfo& info) {
{
base::AutoLock lock(storage_lock_);
- if (ContainsKey(storage_map_, info.device_id())) {
+ if (base::ContainsKey(storage_map_, info.device_id())) {
// This can happen if our unique id scheme fails. Ignore the incoming
// non-unique attachment.
return;
diff --git a/chromium/components/storage_monitor/storage_monitor.h b/chromium/components/storage_monitor/storage_monitor.h
index 5e8654abdee..5c58581d605 100644
--- a/chromium/components/storage_monitor/storage_monitor.h
+++ b/chromium/components/storage_monitor/storage_monitor.h
@@ -120,7 +120,7 @@ class StorageMonitor {
base::string16* storage_object_id) const = 0;
#endif
-#if defined(OS_LINUX)
+#if defined(OS_CHROMEOS)
virtual device::MediaTransferProtocolManager*
media_transfer_protocol_manager() = 0;
#endif
diff --git a/chromium/components/storage_monitor/storage_monitor_chromeos.cc b/chromium/components/storage_monitor/storage_monitor_chromeos.cc
index bc1d7c58ba9..228cc4408c2 100644
--- a/chromium/components/storage_monitor/storage_monitor_chromeos.cc
+++ b/chromium/components/storage_monitor/storage_monitor_chromeos.cc
@@ -13,7 +13,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/storage_monitor/media_storage_util.h"
-#include "components/storage_monitor/media_transfer_protocol_device_observer_linux.h"
+#include "components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h"
#include "components/storage_monitor/removable_device_constants.h"
#include "content/public/browser/browser_thread.h"
#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
@@ -111,7 +111,7 @@ void StorageMonitorCros::Init() {
}
media_transfer_protocol_device_observer_.reset(
- new MediaTransferProtocolDeviceObserverLinux(
+ new MediaTransferProtocolDeviceObserverChromeOS(
receiver(), media_transfer_protocol_manager_.get()));
}
@@ -162,7 +162,7 @@ void StorageMonitorCros::OnMountEvent(
switch (event) {
case DiskMountManager::MOUNTING: {
- if (ContainsKey(mount_map_, mount_info.mount_path)) {
+ if (base::ContainsKey(mount_map_, mount_info.mount_path)) {
NOTREACHED();
return;
}
@@ -210,7 +210,7 @@ bool StorageMonitorCros::GetStorageInfoForPath(
return false;
base::FilePath current = path;
- while (!ContainsKey(mount_map_, current.value()) &&
+ while (!base::ContainsKey(mount_map_, current.value()) &&
current != current.DirName()) {
current = current.DirName();
}
@@ -280,7 +280,7 @@ void StorageMonitorCros::AddMountedPath(
bool has_dcim) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (ContainsKey(mount_map_, mount_info.mount_path)) {
+ if (base::ContainsKey(mount_map_, mount_info.mount_path)) {
// CheckExistingMountPointsOnUIThread() added the mount point information
// in the map before the device attached handler is called. Therefore, an
// entry for the device already exists in the map.
diff --git a/chromium/components/storage_monitor/storage_monitor_chromeos.h b/chromium/components/storage_monitor/storage_monitor_chromeos.h
index 7b3386b5ccc..b427c220867 100644
--- a/chromium/components/storage_monitor/storage_monitor_chromeos.h
+++ b/chromium/components/storage_monitor/storage_monitor_chromeos.h
@@ -26,7 +26,7 @@
namespace storage_monitor {
-class MediaTransferProtocolDeviceObserverLinux;
+class MediaTransferProtocolDeviceObserverChromeOS;
class StorageMonitorCros : public StorageMonitor,
public chromeos::disks::DiskMountManager::Observer {
@@ -86,7 +86,7 @@ class StorageMonitorCros : public StorageMonitor,
std::unique_ptr<device::MediaTransferProtocolManager>
media_transfer_protocol_manager_;
- std::unique_ptr<MediaTransferProtocolDeviceObserverLinux>
+ std::unique_ptr<MediaTransferProtocolDeviceObserverChromeOS>
media_transfer_protocol_device_observer_;
base::WeakPtrFactory<StorageMonitorCros> weak_ptr_factory_;
diff --git a/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc b/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc
index 415f4a18eef..5ffb3f8eacb 100644
--- a/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc
+++ b/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc
@@ -19,7 +19,7 @@
#include "components/storage_monitor/mock_removable_storage_observer.h"
#include "components/storage_monitor/removable_device_constants.h"
#include "components/storage_monitor/storage_info.h"
-#include "components/storage_monitor/test_media_transfer_protocol_manager_linux.h"
+#include "components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h"
#include "components/storage_monitor/test_storage_monitor.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
@@ -68,7 +68,7 @@ class TestStorageMonitorCros : public StorageMonitorCros {
void Init() override {
SetMediaTransferProtocolManagerForTest(
- new TestMediaTransferProtocolManagerLinux());
+ new TestMediaTransferProtocolManagerChromeOS());
StorageMonitorCros::Init();
}
@@ -237,7 +237,7 @@ uint64_t StorageMonitorCrosTest::GetDeviceStorageSize(
base::FilePath StorageMonitorCrosTest::CreateMountPoint(
const std::string& dir, bool with_dcim_dir) {
- base::FilePath return_path(scoped_temp_dir_.path());
+ base::FilePath return_path(scoped_temp_dir_.GetPath());
return_path = return_path.AppendASCII(dir);
base::FilePath path(return_path);
if (with_dcim_dir)
@@ -257,7 +257,7 @@ void StorageMonitorCrosTest::PostQuitToUIThread() {
void StorageMonitorCrosTest::WaitForFileThread() {
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
base::Bind(&PostQuitToUIThread));
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
}
void StorageMonitorCrosTest::EjectNotify(StorageMonitor::EjectStatus status) {
diff --git a/chromium/components/storage_monitor/storage_monitor_linux.cc b/chromium/components/storage_monitor/storage_monitor_linux.cc
index b08986723c2..4b3a01fae7b 100644
--- a/chromium/components/storage_monitor/storage_monitor_linux.cc
+++ b/chromium/components/storage_monitor/storage_monitor_linux.cc
@@ -24,7 +24,6 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/storage_monitor/media_storage_util.h"
-#include "components/storage_monitor/media_transfer_protocol_device_observer_linux.h"
#include "components/storage_monitor/removable_device_constants.h"
#include "components/storage_monitor/storage_info.h"
#include "components/storage_monitor/udev_util_linux.h"
@@ -264,16 +263,6 @@ void StorageMonitorLinux::Init() {
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&StorageMonitorLinux::OnMtabWatcherCreated,
weak_ptr_factory_.GetWeakPtr()));
-
- if (!media_transfer_protocol_manager_) {
- media_transfer_protocol_manager_.reset(
- device::MediaTransferProtocolManager::Initialize(
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
- }
-
- media_transfer_protocol_device_observer_.reset(
- new MediaTransferProtocolDeviceObserverLinux(
- receiver(), media_transfer_protocol_manager_.get()));
}
bool StorageMonitorLinux::GetStorageInfoForPath(
@@ -282,19 +271,12 @@ bool StorageMonitorLinux::GetStorageInfoForPath(
DCHECK(device_info);
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // TODO(thestig) |media_transfer_protocol_device_observer_| should always be
- // valid.
- if (media_transfer_protocol_device_observer_ &&
- media_transfer_protocol_device_observer_->GetStorageInfoForPath(
- path, device_info)) {
- return true;
- }
-
if (!path.IsAbsolute())
return false;
base::FilePath current = path;
- while (!ContainsKey(mount_info_map_, current) && current != current.DirName())
+ while (!base::ContainsKey(mount_info_map_, current) &&
+ current != current.DirName())
current = current.DirName();
MountMap::const_iterator mount_info = mount_info_map_.find(current);
@@ -304,22 +286,11 @@ bool StorageMonitorLinux::GetStorageInfoForPath(
return true;
}
-device::MediaTransferProtocolManager*
-StorageMonitorLinux::media_transfer_protocol_manager() {
- return media_transfer_protocol_manager_.get();
-}
-
void StorageMonitorLinux::SetGetDeviceInfoCallbackForTest(
const GetDeviceInfoCallback& get_device_info_callback) {
get_device_info_callback_ = get_device_info_callback;
}
-void StorageMonitorLinux::SetMediaTransferProtocolManagerForTest(
- device::MediaTransferProtocolManager* test_manager) {
- DCHECK(!media_transfer_protocol_manager_);
- media_transfer_protocol_manager_.reset(test_manager);
-}
-
void StorageMonitorLinux::EjectDevice(
const std::string& device_id,
base::Callback<void(EjectStatus)> callback) {
@@ -329,10 +300,7 @@ void StorageMonitorLinux::EjectDevice(
return;
}
- if (type == StorageInfo::MTP_OR_PTP) {
- media_transfer_protocol_device_observer_->EjectDevice(device_id, callback);
- return;
- }
+ DCHECK_NE(type, StorageInfo::MTP_OR_PTP);
// Find the mount point for the given device ID.
base::FilePath path;
@@ -468,7 +436,7 @@ void StorageMonitorLinux::UpdateMtab(const MountPointDeviceMap& new_mtab) {
bool StorageMonitorLinux::IsDeviceAlreadyMounted(
const base::FilePath& mount_device) const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- return ContainsKey(mount_priority_map_, mount_device);
+ return base::ContainsKey(mount_priority_map_, mount_device);
}
void StorageMonitorLinux::HandleDeviceMountedMultipleTimes(
diff --git a/chromium/components/storage_monitor/storage_monitor_linux.h b/chromium/components/storage_monitor/storage_monitor_linux.h
index 05a59f7c542..a007bf9c7a6 100644
--- a/chromium/components/storage_monitor/storage_monitor_linux.h
+++ b/chromium/components/storage_monitor/storage_monitor_linux.h
@@ -31,8 +31,6 @@
namespace storage_monitor {
-class MediaTransferProtocolDeviceObserverLinux;
-
class StorageMonitorLinux : public StorageMonitor,
public MtabWatcherLinux::Delegate {
public:
@@ -54,9 +52,6 @@ class StorageMonitorLinux : public StorageMonitor,
void SetGetDeviceInfoCallbackForTest(
const GetDeviceInfoCallback& get_device_info_callback);
- void SetMediaTransferProtocolManagerForTest(
- device::MediaTransferProtocolManager* test_manager);
-
// MtabWatcherLinux::Delegate implementation.
void UpdateMtab(
const MtabWatcherLinux::MountPointDeviceMap& new_mtab) override;
@@ -95,8 +90,6 @@ class StorageMonitorLinux : public StorageMonitor,
StorageInfo* device_info) const override;
void EjectDevice(const std::string& device_id,
base::Callback<void(EjectStatus)> callback) override;
- device::MediaTransferProtocolManager* media_transfer_protocol_manager()
- override;
// Called when the MtabWatcher has been created.
void OnMtabWatcherCreated(MtabWatcherLinux* watcher);
@@ -130,11 +123,6 @@ class StorageMonitorLinux : public StorageMonitor,
// points.
MountPriorityMap mount_priority_map_;
- std::unique_ptr<device::MediaTransferProtocolManager>
- media_transfer_protocol_manager_;
- std::unique_ptr<MediaTransferProtocolDeviceObserverLinux>
- media_transfer_protocol_device_observer_;
-
std::unique_ptr<MtabWatcherLinux, MtabWatcherLinuxDeleter> mtab_watcher_;
base::WeakPtrFactory<StorageMonitorLinux> weak_ptr_factory_;
diff --git a/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc b/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc
index 1c49430df52..92311f2c1ea 100644
--- a/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc
+++ b/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc
@@ -25,7 +25,6 @@
#include "components/storage_monitor/removable_device_constants.h"
#include "components/storage_monitor/storage_info.h"
#include "components/storage_monitor/storage_monitor.h"
-#include "components/storage_monitor/test_media_transfer_protocol_manager_linux.h"
#include "components/storage_monitor/test_storage_monitor.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -126,8 +125,6 @@ class TestStorageMonitorLinux : public StorageMonitorLinux {
public:
explicit TestStorageMonitorLinux(const base::FilePath& path)
: StorageMonitorLinux(path) {
- SetMediaTransferProtocolManagerForTest(
- new TestMediaTransferProtocolManagerLinux());
SetGetDeviceInfoCallbackForTest(base::Bind(&GetDeviceInfo));
}
~TestStorageMonitorLinux() override {}
@@ -167,7 +164,8 @@ class StorageMonitorLinuxTest : public testing::Test {
void SetUp() override {
// Create and set up a temp dir with files for the test.
ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
- base::FilePath test_dir = scoped_temp_dir_.path().AppendASCII("test_etc");
+ base::FilePath test_dir =
+ scoped_temp_dir_.GetPath().AppendASCII("test_etc");
ASSERT_TRUE(base::CreateDirectory(test_dir));
mtab_file_ = test_dir.AppendASCII("test_mtab");
MtabTestData initial_test_data[] = {
@@ -232,7 +230,7 @@ class StorageMonitorLinuxTest : public testing::Test {
void RemoveDCIMDirFromMountPoint(const std::string& dir) {
base::FilePath dcim =
- scoped_temp_dir_.path().AppendASCII(dir).Append(kDCIMDirectoryName);
+ scoped_temp_dir_.GetPath().AppendASCII(dir).Append(kDCIMDirectoryName);
base::DeleteFile(dcim, false);
}
@@ -259,7 +257,7 @@ class StorageMonitorLinuxTest : public testing::Test {
// Returns the full path to the created directory on success, or an empty
// path on failure.
base::FilePath CreateMountPoint(const std::string& dir, bool with_dcim_dir) {
- base::FilePath return_path(scoped_temp_dir_.path());
+ base::FilePath return_path(scoped_temp_dir_.GetPath());
return_path = return_path.AppendASCII(dir);
base::FilePath path(return_path);
if (with_dcim_dir)
diff --git a/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm b/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm
index 30bffda1adf..47c091a2d66 100644
--- a/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm
+++ b/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm
@@ -123,10 +123,10 @@ TEST_F(StorageMonitorMacTest, UpdateVolumeName) {
TEST_F(StorageMonitorMacTest, DCIM) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- ASSERT_TRUE(base::CreateDirectory(
- temp_dir.path().Append(kDCIMDirectoryName)));
+ ASSERT_TRUE(
+ base::CreateDirectory(temp_dir.GetPath().Append(kDCIMDirectoryName)));
- base::FilePath mount_point = temp_dir.path();
+ base::FilePath mount_point = temp_dir.GetPath();
std::string device_id = StorageInfo::MakeDeviceId(
StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, unique_id_);
StorageInfo info = CreateStorageInfo(device_id, "", mount_point, kTestSize);
diff --git a/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.cc b/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.cc
new file mode 100644
index 00000000000..dcef6643d17
--- /dev/null
+++ b/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.cc
@@ -0,0 +1,110 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h"
+
+#include "device/media_transfer_protocol/mtp_file_entry.pb.h"
+#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
+
+namespace storage_monitor {
+
+TestMediaTransferProtocolManagerChromeOS::
+ TestMediaTransferProtocolManagerChromeOS() {}
+
+TestMediaTransferProtocolManagerChromeOS::
+ ~TestMediaTransferProtocolManagerChromeOS() {}
+
+void TestMediaTransferProtocolManagerChromeOS::AddObserver(Observer* observer) {
+}
+
+void TestMediaTransferProtocolManagerChromeOS::RemoveObserver(
+ Observer* observer) {}
+
+const std::vector<std::string>
+TestMediaTransferProtocolManagerChromeOS::GetStorages() const {
+ return std::vector<std::string>();
+}
+const MtpStorageInfo* TestMediaTransferProtocolManagerChromeOS::GetStorageInfo(
+ const std::string& storage_name) const {
+ return NULL;
+}
+
+void TestMediaTransferProtocolManagerChromeOS::GetStorageInfoFromDevice(
+ const std::string& storage_name,
+ const GetStorageInfoFromDeviceCallback& callback) {
+ MtpStorageInfo mtp_storage_info;
+ callback.Run(mtp_storage_info, true /* error */);
+}
+
+void TestMediaTransferProtocolManagerChromeOS::OpenStorage(
+ const std::string& storage_name,
+ const std::string& mode,
+ const OpenStorageCallback& callback) {
+ callback.Run("", true);
+}
+
+void TestMediaTransferProtocolManagerChromeOS::CloseStorage(
+ const std::string& storage_handle,
+ const CloseStorageCallback& callback) {
+ callback.Run(true);
+}
+
+void TestMediaTransferProtocolManagerChromeOS::CreateDirectory(
+ const std::string& storage_handle,
+ const uint32_t parent_id,
+ const std::string& directory_name,
+ const CreateDirectoryCallback& callback) {
+ callback.Run(true /* error */);
+}
+
+void TestMediaTransferProtocolManagerChromeOS::ReadDirectory(
+ const std::string& storage_handle,
+ const uint32_t file_id,
+ const size_t max_size,
+ const ReadDirectoryCallback& callback) {
+ callback.Run(std::vector<MtpFileEntry>(), false /* no more entries*/,
+ true /* error */);
+}
+
+void TestMediaTransferProtocolManagerChromeOS::ReadFileChunk(
+ const std::string& storage_handle,
+ uint32_t file_id,
+ uint32_t offset,
+ uint32_t count,
+ const ReadFileCallback& callback) {
+ callback.Run(std::string(), true);
+}
+
+void TestMediaTransferProtocolManagerChromeOS::GetFileInfo(
+ const std::string& storage_handle,
+ uint32_t file_id,
+ const GetFileInfoCallback& callback) {
+ callback.Run(MtpFileEntry(), true);
+}
+
+void TestMediaTransferProtocolManagerChromeOS::RenameObject(
+ const std::string& storage_handle,
+ const uint32_t object_id,
+ const std::string& new_name,
+ const RenameObjectCallback& callback) {
+ callback.Run(true /* error */);
+}
+
+void TestMediaTransferProtocolManagerChromeOS::CopyFileFromLocal(
+ const std::string& storage_handle,
+ const int source_file_descriptor,
+ const uint32_t parent_id,
+ const std::string& file_name,
+ const CopyFileFromLocalCallback& callback) {
+ callback.Run(true /* error */);
+}
+
+void TestMediaTransferProtocolManagerChromeOS::DeleteObject(
+ const std::string& storage_handle,
+ const uint32_t object_id,
+ const DeleteObjectCallback& callback) {
+ callback.Run(true /* error */);
+}
+
+} // namespace storage_monitor
diff --git a/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h b/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h
new file mode 100644
index 00000000000..403e350f478
--- /dev/null
+++ b/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h
@@ -0,0 +1,72 @@
+// 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 COMPONENTS_STORAGE_MONITOR_TEST_MEDIA_TRANSFER_PROTOCOL_MANAGER_CHROMEOS_H_
+#define COMPONENTS_STORAGE_MONITOR_TEST_MEDIA_TRANSFER_PROTOCOL_MANAGER_CHROMEOS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
+
+namespace storage_monitor {
+
+// A dummy MediaTransferProtocolManager implementation.
+class TestMediaTransferProtocolManagerChromeOS
+ : public device::MediaTransferProtocolManager {
+ public:
+ TestMediaTransferProtocolManagerChromeOS();
+ ~TestMediaTransferProtocolManagerChromeOS() override;
+
+ private:
+ // device::MediaTransferProtocolManager implementation.
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+ const std::vector<std::string> GetStorages() const override;
+ const MtpStorageInfo* GetStorageInfo(
+ const std::string& storage_name) const override;
+ void GetStorageInfoFromDevice(
+ const std::string& storage_name,
+ const GetStorageInfoFromDeviceCallback& callback) override;
+ void OpenStorage(const std::string& storage_name,
+ const std::string& mode,
+ const OpenStorageCallback& callback) override;
+ void CloseStorage(const std::string& storage_handle,
+ const CloseStorageCallback& callback) override;
+ void CreateDirectory(const std::string& storage_handle,
+ const uint32_t parent_id,
+ const std::string& directory_name,
+ const CreateDirectoryCallback& callback) override;
+ void ReadDirectory(const std::string& storage_handle,
+ const uint32_t file_id,
+ const size_t max_size,
+ const ReadDirectoryCallback& callback) override;
+ void ReadFileChunk(const std::string& storage_handle,
+ uint32_t file_id,
+ uint32_t offset,
+ uint32_t count,
+ const ReadFileCallback& callback) override;
+ void GetFileInfo(const std::string& storage_handle,
+ uint32_t file_id,
+ const GetFileInfoCallback& callback) override;
+ void RenameObject(const std::string& storage_handle,
+ const uint32_t object_id,
+ const std::string& new_name,
+ const RenameObjectCallback& callback) override;
+ void CopyFileFromLocal(const std::string& storage_handle,
+ const int source_file_descriptor,
+ const uint32_t parent_id,
+ const std::string& file_name,
+ const CopyFileFromLocalCallback& callback) override;
+ void DeleteObject(const std::string& storage_handle,
+ const uint32_t object_id,
+ const DeleteObjectCallback& callback) override;
+
+ DISALLOW_COPY_AND_ASSIGN(TestMediaTransferProtocolManagerChromeOS);
+};
+
+} // namespace storage_monitor
+
+#endif // COMPONENTS_STORAGE_MONITOR_TEST_MEDIA_TRANSFER_PROTOCOL_MANAGER_CHROMEOS_H_
diff --git a/chromium/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc b/chromium/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc
deleted file mode 100644
index addfd872740..00000000000
--- a/chromium/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc
+++ /dev/null
@@ -1,110 +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 "components/storage_monitor/test_media_transfer_protocol_manager_linux.h"
-
-#include "device/media_transfer_protocol/mtp_file_entry.pb.h"
-#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
-
-namespace storage_monitor {
-
-TestMediaTransferProtocolManagerLinux::
-TestMediaTransferProtocolManagerLinux() {}
-
-TestMediaTransferProtocolManagerLinux::
-~TestMediaTransferProtocolManagerLinux() {}
-
-void TestMediaTransferProtocolManagerLinux::AddObserver(Observer* observer) {}
-
-void TestMediaTransferProtocolManagerLinux::RemoveObserver(
- Observer* observer) {}
-
-const std::vector<std::string>
-TestMediaTransferProtocolManagerLinux::GetStorages() const {
- return std::vector<std::string>();
-}
-const MtpStorageInfo* TestMediaTransferProtocolManagerLinux::GetStorageInfo(
- const std::string& storage_name) const {
- return NULL;
-}
-
-void TestMediaTransferProtocolManagerLinux::GetStorageInfoFromDevice(
- const std::string& storage_name,
- const GetStorageInfoFromDeviceCallback& callback) {
- MtpStorageInfo mtp_storage_info;
- callback.Run(mtp_storage_info, true /* error */);
-}
-
-void TestMediaTransferProtocolManagerLinux::OpenStorage(
- const std::string& storage_name,
- const std::string& mode,
- const OpenStorageCallback& callback) {
- callback.Run("", true);
-}
-
-void TestMediaTransferProtocolManagerLinux::CloseStorage(
- const std::string& storage_handle,
- const CloseStorageCallback& callback) {
- callback.Run(true);
-}
-
-void TestMediaTransferProtocolManagerLinux::CreateDirectory(
- const std::string& storage_handle,
- const uint32_t parent_id,
- const std::string& directory_name,
- const CreateDirectoryCallback& callback) {
- callback.Run(true /* error */);
-}
-
-void TestMediaTransferProtocolManagerLinux::ReadDirectory(
- const std::string& storage_handle,
- const uint32_t file_id,
- const size_t max_size,
- const ReadDirectoryCallback& callback) {
- callback.Run(std::vector<MtpFileEntry>(),
- false /* no more entries*/,
- true /* error */);
-}
-
-void TestMediaTransferProtocolManagerLinux::ReadFileChunk(
- const std::string& storage_handle,
- uint32_t file_id,
- uint32_t offset,
- uint32_t count,
- const ReadFileCallback& callback) {
- callback.Run(std::string(), true);
-}
-
-void TestMediaTransferProtocolManagerLinux::GetFileInfo(
- const std::string& storage_handle,
- uint32_t file_id,
- const GetFileInfoCallback& callback) {
- callback.Run(MtpFileEntry(), true);
-}
-
-void TestMediaTransferProtocolManagerLinux::RenameObject(
- const std::string& storage_handle,
- const uint32_t object_id,
- const std::string& new_name,
- const RenameObjectCallback& callback) {
- callback.Run(true /* error */);
-}
-
-void TestMediaTransferProtocolManagerLinux::CopyFileFromLocal(
- const std::string& storage_handle,
- const int source_file_descriptor,
- const uint32_t parent_id,
- const std::string& file_name,
- const CopyFileFromLocalCallback& callback) {
- callback.Run(true /* error */);
-}
-
-void TestMediaTransferProtocolManagerLinux::DeleteObject(
- const std::string& storage_handle,
- const uint32_t object_id,
- const DeleteObjectCallback& callback) {
- callback.Run(true /* error */);
-}
-
-} // namespace storage_monitor
diff --git a/chromium/components/storage_monitor/test_media_transfer_protocol_manager_linux.h b/chromium/components/storage_monitor/test_media_transfer_protocol_manager_linux.h
deleted file mode 100644
index c53b39c9915..00000000000
--- a/chromium/components/storage_monitor/test_media_transfer_protocol_manager_linux.h
+++ /dev/null
@@ -1,72 +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 COMPONENTS_STORAGE_MONITOR_TEST_MEDIA_TRANSFER_PROTOCOL_MANAGER_LINUX_H_
-#define COMPONENTS_STORAGE_MONITOR_TEST_MEDIA_TRANSFER_PROTOCOL_MANAGER_LINUX_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
-
-namespace storage_monitor {
-
-// A dummy MediaTransferProtocolManager implementation.
-class TestMediaTransferProtocolManagerLinux
- : public device::MediaTransferProtocolManager {
- public:
- TestMediaTransferProtocolManagerLinux();
- ~TestMediaTransferProtocolManagerLinux() override;
-
- private:
- // device::MediaTransferProtocolManager implementation.
- void AddObserver(Observer* observer) override;
- void RemoveObserver(Observer* observer) override;
- const std::vector<std::string> GetStorages() const override;
- const MtpStorageInfo* GetStorageInfo(
- const std::string& storage_name) const override;
- void GetStorageInfoFromDevice(
- const std::string& storage_name,
- const GetStorageInfoFromDeviceCallback& callback) override;
- void OpenStorage(const std::string& storage_name,
- const std::string& mode,
- const OpenStorageCallback& callback) override;
- void CloseStorage(const std::string& storage_handle,
- const CloseStorageCallback& callback) override;
- void CreateDirectory(const std::string& storage_handle,
- const uint32_t parent_id,
- const std::string& directory_name,
- const CreateDirectoryCallback& callback) override;
- void ReadDirectory(const std::string& storage_handle,
- const uint32_t file_id,
- const size_t max_size,
- const ReadDirectoryCallback& callback) override;
- void ReadFileChunk(const std::string& storage_handle,
- uint32_t file_id,
- uint32_t offset,
- uint32_t count,
- const ReadFileCallback& callback) override;
- void GetFileInfo(const std::string& storage_handle,
- uint32_t file_id,
- const GetFileInfoCallback& callback) override;
- void RenameObject(const std::string& storage_handle,
- const uint32_t object_id,
- const std::string& new_name,
- const RenameObjectCallback& callback) override;
- void CopyFileFromLocal(const std::string& storage_handle,
- const int source_file_descriptor,
- const uint32_t parent_id,
- const std::string& file_name,
- const CopyFileFromLocalCallback& callback) override;
- void DeleteObject(const std::string& storage_handle,
- const uint32_t object_id,
- const DeleteObjectCallback& callback) override;
-
- DISALLOW_COPY_AND_ASSIGN(TestMediaTransferProtocolManagerLinux);
-};
-
-} // namespace storage_monitor
-
-#endif // COMPONENTS_STORAGE_MONITOR_TEST_MEDIA_TRANSFER_PROTOCOL_MANAGER_LINUX_H_
diff --git a/chromium/components/storage_monitor/test_storage_monitor.cc b/chromium/components/storage_monitor/test_storage_monitor.cc
index 3277f6fa585..3ab33bb0413 100644
--- a/chromium/components/storage_monitor/test_storage_monitor.cc
+++ b/chromium/components/storage_monitor/test_storage_monitor.cc
@@ -11,8 +11,8 @@
#include "build/build_config.h"
#include "components/storage_monitor/storage_info.h"
-#if defined(OS_LINUX)
-#include "components/storage_monitor/test_media_transfer_protocol_manager_linux.h"
+#if defined(OS_CHROMEOS)
+#include "components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h"
#include "device/media_transfer_protocol/media_transfer_protocol_manager.h" // nogncheck
#endif
@@ -21,9 +21,9 @@ namespace storage_monitor {
TestStorageMonitor::TestStorageMonitor()
: StorageMonitor(),
init_called_(false) {
-#if defined(OS_LINUX)
+#if defined(OS_CHROMEOS)
media_transfer_protocol_manager_.reset(
- new TestMediaTransferProtocolManagerLinux());
+ new TestMediaTransferProtocolManagerChromeOS());
#endif
}
@@ -115,7 +115,7 @@ bool TestStorageMonitor::GetMTPStorageInfoFromDeviceId(
}
#endif
-#if defined(OS_LINUX)
+#if defined(OS_CHROMEOS)
device::MediaTransferProtocolManager*
TestStorageMonitor::media_transfer_protocol_manager() {
return media_transfer_protocol_manager_.get();
diff --git a/chromium/components/storage_monitor/test_storage_monitor.h b/chromium/components/storage_monitor/test_storage_monitor.h
index ec29b8c66c0..df3c57a4240 100644
--- a/chromium/components/storage_monitor/test_storage_monitor.h
+++ b/chromium/components/storage_monitor/test_storage_monitor.h
@@ -46,7 +46,7 @@ class TestStorageMonitor : public StorageMonitor {
base::string16* storage_object_id) const override;
#endif
-#if defined(OS_LINUX)
+#if defined(OS_CHROMEOS)
device::MediaTransferProtocolManager* media_transfer_protocol_manager()
override;
#endif
@@ -73,7 +73,7 @@ class TestStorageMonitor : public StorageMonitor {
// Paths considered for testing purposes to be on removable storage.
std::vector<base::FilePath> removable_paths_;
-#if defined(OS_LINUX)
+#if defined(OS_CHROMEOS)
std::unique_ptr<device::MediaTransferProtocolManager>
media_transfer_protocol_manager_;
#endif
diff --git a/chromium/components/storage_monitor/test_volume_mount_watcher_win.cc b/chromium/components/storage_monitor/test_volume_mount_watcher_win.cc
index c847ad2a586..115054aab6d 100644
--- a/chromium/components/storage_monitor/test_volume_mount_watcher_win.cc
+++ b/chromium/components/storage_monitor/test_volume_mount_watcher_win.cc
@@ -21,7 +21,7 @@ namespace {
base::FilePath GetTempRoot() {
base::ScopedTempDir temp_dir;
EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
- base::FilePath temp_root = temp_dir.path();
+ base::FilePath temp_root = temp_dir.GetPath();
while (temp_root.DirName() != temp_root)
temp_root = temp_root.DirName();
return temp_root;
diff --git a/chromium/components/storage_monitor/transient_device_ids.cc b/chromium/components/storage_monitor/transient_device_ids.cc
index 3f1930224aa..fdbcecffaaf 100644
--- a/chromium/components/storage_monitor/transient_device_ids.cc
+++ b/chromium/components/storage_monitor/transient_device_ids.cc
@@ -21,11 +21,11 @@ std::string TransientDeviceIds::GetTransientIdForDeviceId(
const std::string& device_id) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!ContainsKey(device_id_map_, device_id)) {
+ if (!base::ContainsKey(device_id_map_, device_id)) {
std::string transient_id;
do {
transient_id = base::GenerateGUID();
- } while (ContainsKey(transient_id_map_, transient_id));
+ } while (base::ContainsKey(transient_id_map_, transient_id));
device_id_map_[device_id] = transient_id;
transient_id_map_[transient_id] = device_id;
diff --git a/chromium/components/storage_monitor/volume_mount_watcher_win.cc b/chromium/components/storage_monitor/volume_mount_watcher_win.cc
index 2ae52b51137..49ccccb493a 100644
--- a/chromium/components/storage_monitor/volume_mount_watcher_win.cc
+++ b/chromium/components/storage_monitor/volume_mount_watcher_win.cc
@@ -372,7 +372,7 @@ void VolumeMountWatcherWin::AddDevicesOnUIThread(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (size_t i = 0; i < removable_devices.size(); i++) {
- if (ContainsKey(pending_device_checks_, removable_devices[i]))
+ if (base::ContainsKey(pending_device_checks_, removable_devices[i]))
continue;
pending_device_checks_.insert(removable_devices[i]);
device_info_task_runner_->PostTask(
diff --git a/chromium/components/strings/BUILD.gn b/chromium/components/strings/BUILD.gn
index fefb4820300..395dbee3767 100644
--- a/chromium/components/strings/BUILD.gn
+++ b/chromium/components/strings/BUILD.gn
@@ -64,8 +64,6 @@ group("strings") {
]
}
-# GYP version: components/components_strings.gyp:components_strings
-# (generate_components_strings action)
grit("components_strings") {
source = "../components_strings.grd"
outputs = [
@@ -91,8 +89,6 @@ if (is_android) {
}
}
-# GYP version: components/components_strings.gyp:components_strings
-# (generate_components_chromium_strings action)
grit("components_chromium_strings") {
source = "../components_chromium_strings.grd"
outputs = [
@@ -103,8 +99,6 @@ grit("components_chromium_strings") {
}
}
-# GYP version: components/components_strings.gyp:components_strings
-# (generate_components_google_chrome_strings action)
grit("components_google_chrome_strings") {
source = "../components_google_chrome_strings.grd"
outputs = [
@@ -164,8 +158,6 @@ if (is_android) {
]
}
-# GYP version: components/components_strings.gyp:components_strings
-# (generate_components_locale_settings action)
grit("components_locale_settings") {
source = "../components_locale_settings.grd"
outputs = [
diff --git a/chromium/components/strings/components_chromium_strings_ko.xtb b/chromium/components/strings/components_chromium_strings_ko.xtb
index 10daa9ee3ef..35309d75298 100644
--- a/chromium/components/strings/components_chromium_strings_ko.xtb
+++ b/chromium/components/strings/components_chromium_strings_ko.xtb
@@ -2,7 +2,7 @@
<!DOCTYPE translationbundle>
<translationbundle lang="ko">
<translation id="130631256467250065">기기를 다́‹œ ́‹œ́‘í•  ë•Œ 변경́‚¬í•­́´ ́ ́©ë©ë‹ˆë‹¤.</translation>
-<translation id="275588974610408078">́˜¤ë¥˜ ë³´ê³ ́„œë” Chromiuḿ—́„œ ́‚¬́©í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
+<translation id="275588974610408078">비́ •́ƒ ́¢…료 ë³´ê³ ́„œë” Chromiuḿ—́„œ ́‚¬́©í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="3550966579244642892">Chromium OS ́´ˆê¸° ́„¤́ •́´ ́™„료ë˜́§€ ́•́•˜́µë‹ˆë‹¤.</translation>
<translation id="3748537968684000502">́§€ê¸ˆ ́•ˆ́ „í•œ Chromium í˜́´́§€ë¥¼ ë³´ê³  계́‹­ë‹ˆë‹¤.</translation>
<translation id="4365115785552740256">Chromiuḿ€ <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ́˜¤í”ˆ́†Œ́¤ 프로́ í¸ë¥¼ 비롯한 ́—¬ëŸ¬ <ph name="BEGIN_LINK_OSS" />́˜¤í”ˆ́†Œ́¤ ́†Œí”„í¸́›΅–´<ph name="END_LINK_OSS" />́— 기́´ˆí•´ 만들́–´́§„ 브ë¼́°́ €́…니다.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_tr.xtb b/chromium/components/strings/components_google_chrome_strings_tr.xtb
index 48ff3703bdd..b3c01d0b748 100644
--- a/chromium/components/strings/components_google_chrome_strings_tr.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_tr.xtb
@@ -6,7 +6,7 @@
<translation id="2748463065602559597">GĂ¼venli bir Google Chrome sayfasını görĂ¼ntĂ¼lĂ¼yorsunuz.</translation>
<translation id="2874156562296220396">Google Chrome, <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> açık kaynak projesi ve diÄŸer <ph name="BEGIN_LINK_OSS" />açık kaynak yazılımlar<ph name="END_LINK_OSS" /> ile oluÅŸturulmuÅŸtur.</translation>
<translation id="3140883423282498090">Yaptığınız deÄŸiÅŸiklikler Google Chrome'u yeniden baÅŸlattığınızda geçerli olacak.</translation>
-<translation id="3444832043240812445"><ph name="BEGIN_LINK" />Kilitlenme bildirmeyi etkinleÅŸtirdiyseniz<ph name="END_LINK" />, bu sayfada yalnızca, karşılaÅŸtığınız son kilitlenme olayları hakkında bilgiler gösterilir.</translation>
+<translation id="3444832043240812445">KarşılaÅŸtığınız son kilitlenme olayları hakkındaki bilgiler yalnızca <ph name="BEGIN_LINK" />kilitlenme bildirmeyi etkinleÅŸtirdiyseniz<ph name="END_LINK" /> bu sayfada gösterilir.</translation>
<translation id="3875312571075912821">GĂ¼venlik duvarınızın veya virĂ¼sten korunma programınızın ayarlarından,
Chrome'un aÄŸa eriÅŸmesine izin verin.</translation>
<translation id="4010643444566880169">Chrome OS ilk kurulumu tamamlayamadı.</translation>
diff --git a/chromium/components/strings/components_strings_am.xtb b/chromium/components/strings/components_strings_am.xtb
index 10fbb915122..bf71ccf84db 100644
--- a/chromium/components/strings/components_strings_am.xtb
+++ b/chromium/components/strings/components_strings_am.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="am">
+<translation id="1008557486741366299">á áˆá• á á‹­á‹°áˆˆáˆ</translation>
<translation id="1015730422737071372">ተጨማሪ á‹áˆ­á‹áˆ®á‰½á• ያቅርቡ</translation>
<translation id="1032854598605920125">በሰዓት á á‰…ጣጫ á áˆ½á¨áˆ­á­áˆ­</translation>
<translation id="1038842779957582377">á‹«áˆá‰³á‹ˆá‰€ ስáˆ</translation>
+<translation id="1053591932240354961">ድር ጣቢያዠGoogle Chrome áˆá‹«áˆµá‰°á“áŒá‹°á‹ የማይችሠብትá•á‰µá• ያሉ á áˆ³áˆ›á áˆáˆµá­áˆ­á•á‰¶á‰½ ስለላᨠá áˆá• <ph name="SITE" />ᕠመáŒá‰¥á˜á‰µ á á‹­á‰½áˆ‰áˆá¢ የá á‹á‰³áˆ¨ መረብ ስህተቶች á¥á“ ጥቃቶች ብዙá‹á• áŒá‹œ áŒá‹œá‹«á‹ á“ቸá‹á£ ስለá‹áˆ… ይህ ገጽ áˆá“áˆá‰£á‰µ በá‹áˆ‹ ላይ áˆáˆ áˆ« ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="1055184225775184556">&amp;á á­áˆá• ቀáˆá‰¥áˆµ</translation>
<translation id="10614374240317010">በጭራሽ á áˆá‰°á‰€áˆ˜áŒ áˆ</translation>
-<translation id="1064422015032085147">ድረ-ገጹᕠየáˆá‹«áˆµá‰°á“áŒá‹°á‹ á áŒˆáˆáŒ‹á‹­ á¨áˆá­ በላይ ጫᓠበá‹á‰¶á‰ á‰³áˆ ወይሠበጥገᓠላይ áˆáˆ†á• ይችላáˆá¢
- á¨áˆá­ በላይ ብዙ ትራáá­ á¥á•á‹³á‹«áˆáˆá‰… á¥á“ áˆá”ታá‹á• ወደ ባሰ ደረጃ á¥á•á‹³á‹­áˆ„ድ ለመá¨áˆ‹á¨áˆ ሲባáˆá£
- ወደá‹áˆ… á‹©á áˆ­á¤áˆ የáˆá‰€áˆ­á‰¡ ጥያቄá‹á‰½ ለáŒá‹œá‹ á á‹­áˆá‰€á‹µáˆ‹á‰¸á‹áˆá¢</translation>
<translation id="106701514854093668">የዴስá­á‰¶á• á‹•áˆá‰£á‰¶á‰½</translation>
<translation id="1080116354587839789">á¨áˆµá‹á‰± ጋር á áˆ˜áŒ£áŒ¥á•</translation>
+<translation id="1103124106085518534">ለá áˆá• ተá¨á“á‹á—áˆ</translation>
<translation id="1103523840287552314">áˆáˆáŒá‹œ <ph name="LANGUAGE" />ᕠመተርáŒáˆ</translation>
<translation id="1107591249535594099">áˆáˆá­á‰µ á¨á‰°á‹°áˆ¨áŒˆá‰ á‰µá£ Chrome ለተሻለ áˆáŒ£á• የቅጽ á áˆáˆ‹áˆ የá«áˆ­á‹µá‹á• ቅጂ በá‹áˆ… መሣሪያ ላይ á‹«á¨áˆ›á‰»áˆá¢</translation>
+<translation id="1111153019813902504">የቅርብ áŒá‹œ á‹•áˆá‰£á‰¶á‰½</translation>
<translation id="1113869188872983271">&amp;á¥á•á‹°áŒˆá“ ደርድርᕠቀáˆá‰¥áˆµ</translation>
+<translation id="1126551341858583091">የá á«á‰£á‰¢á‹«á‹ ማá¨áˆ›á‰»á‹ መጠᕠ<ph name="CRASH_SIZE" /> áá‹á¢</translation>
<translation id="112840717907525620">የመáˆáˆªá‹« መሸáŒáŒ« á¥áˆº</translation>
<translation id="113188000913989374"><ph name="SITE" /> á¥á•á‹²áˆ… ይላáˆá¦</translation>
<translation id="1132774398110320017">የChrome ራስ-ሙላ ቅá•á‰¥áˆ®á‰½...</translation>
-<translation id="1150979032973867961">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘á• áˆá‹«áˆ¨áŒ‹áŒáŒ¥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á¥á‹á‰…ᓠማረጋገጫዠበá®áˆá’á‹á‰°áˆ­á‹ ስርዓተ á­á‹ˆá“ የáˆá‰³áˆ˜á• á á‹­á‹°áˆˆáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢</translation>
<translation id="1152921474424827756">የ<ph name="URL" /> <ph name="BEGIN_LINK" />የተሸáŒáŒ  ቅጂ<ph name="END_LINK" /> ይድረሱ</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ሳይታሰብ áŒá•á™áቱᕠዘáŒá‰·áˆá¢</translation>
<translation id="1161325031994447685">á¨Wi-Fi ጋር ዳáŒáˆ በማገá“á˜á‰µ</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">á áˆµá‹ˆáŒá‹µ</translation>
<translation id="1201402288615127009">ቀጣይ</translation>
<translation id="1201895884277373915">ተጨማሪ á¨á‹áˆ… ጣቢያ</translation>
-<translation id="121201262018556460"><ph name="DOMAIN" />ᕠለመድረስ áˆá­áˆ¨á‹‹áˆá£ áŒá• á áŒˆáˆáŒ‹á‹© á‹°á«áˆ› á‰áˆá የያዘ የá¥á‹á‰…ᓠማረጋገጫ áዠያቀረበá‹á¢ á á•á‹µ á áŒ¥á‰‚ የáŒáˆ á‰áˆá‰á• ሰብሮ áˆáˆ†á• ይችላáˆá£ á¥á“ á áŒˆáˆáŒ‹á‹© የጠበá‰á‰µ ላይሆᕠይችላሠ(á¨á áŒ¥á‰‚ ጋር á¥á‹¨á‰°áŒˆá“á™ áˆáˆ†á‘ ይችላሉ)á¢</translation>
+<translation id="1206967143813997005">መጥá የመጀመሪያ áርማ</translation>
+<translation id="1209206284964581585">ለá áˆá• ደብቅ</translation>
<translation id="1219129156119358924">የስርዓት ደህá•áት</translation>
<translation id="1227224963052638717">á‹«áˆá‰³á‹ˆá‰€ መመሪያá¢</translation>
<translation id="1227633850867390598">á¥áˆ´á‰µ ይደብá‰</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">á á‹</translation>
<translation id="1430915738399379752">á á‰µáˆ</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" />በ<ph name="DOMAIN" /> ላይ ያለá‹á• ገጽ የመáŒá‰¥á˜á‰µ<ph name="END_LINK" /> ሙá¨áˆ« ታáŒá‹·áˆá¢</translation>
+<translation id="1491663344921578213">የድር ጣቢያዠየá¥á‹á‰…ᓠማረጋገጫ ማያያá‹á• ስለáˆáŒ á‰€áˆ á áˆá• <ph name="SITE" />ᕠመáŒá‰¥á˜á‰µ á á‹­á‰½áˆ‰áˆá¢ የá á‹á‰³áˆ¨ መረብ ስህተቶች á¥á“ ጥቃቶች ብዙá‹á• áŒá‹œ áŒá‹œá‹«á‹ á“ቸá‹á£ ስለá‹áˆ… ይህ ገጽ áˆá“áˆá‰£á‰µ በá‹áˆ‹ ላይ áˆáˆ áˆ« ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="1506687042165942984">የá‹áˆ…ᕠገጽ የተቀመጠ (ለáˆáˆ³áˆŒ ቀᑠያለáˆá‰ á‰µ á¥á•á‹°áˆ†á የታወቀ) ቅጂᕠá áˆ³á‹­á¢</translation>
<translation id="1519264250979466059">የáŒá•á‰¥ ቀá•</translation>
<translation id="1549470594296187301">ይህᕠባህሪ ለመጠቀሠጃቫስá­áˆªá•á‰µ መá•á‰ƒá‰µ á áˆˆá‰ á‰µá¢</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">የá á‹á‰³áˆ¨ መረቡ á‹á‰…ር áˆá­ á‹«áˆáˆ†á á¥á“ áˆáˆ˜áŒ£ የማይችሠáá‹á¢</translation>
<translation id="1644574205037202324">ታሪá­</translation>
<translation id="1645368109819982629">የማይደገá á•áˆ®á‰¶á®áˆ</translation>
-<translation id="1655462015569774233">{1,plural, =1{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠለማረጋገጥ á á‹­á‰½áˆáˆá¤ የደህá•áት ማረጋገጫ á¥á‹á‰…ᓠማረጋገጫዠትላá•á‰µá“ áŒá‹œá‹ á áˆáበታáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢ የá®áˆá’á‹á‰°áˆ­á‹ ሰዓት á áˆá• በ<ph name="CURRENT_DATE" /> ተቀá“ብሯáˆá¢ ትá­á­áˆ ይመስáˆá‹á‰³áˆ? ትá­á­áˆ á«áˆáˆ†áᣠየá¥áˆ­áˆµá‹á• ስርዓት ሰዓት ማስተá«á¨áˆ á¥á“ ይህá•á• áŒˆá… áˆ›á‹°áˆµ á áˆˆá‰¥á‹á¢}one{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠለማረጋገጥ á á‹­á‰½áˆáˆá¤ የደህá•áት ማረጋገጫ á¥á‹á‰…ᓠማረጋገጫዠá¨# ቀá–ች በáት áŒá‹œá‹ á áˆááˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢ የá®áˆá’á‹á‰°áˆ­á‹ ሰዓት á áˆá• በ<ph name="CURRENT_DATE" /> ተቀá“ብሯáˆá¢ ትá­á­áˆ ይመስáˆá‹á‰³áˆ? ትá­á­áˆ á«áˆáˆ†áᣠየá¥áˆ­áˆµá‹á• ስርዓት ሰዓት ማስተá«á¨áˆ á¥á“ ይህá•á• áŒˆá… áˆ›á‹°áˆµ á áˆˆá‰¥á‹á¢}other{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠለማረጋገጥ á á‹­á‰½áˆáˆá¤ የደህá•áት ማረጋገጫ á¥á‹á‰…ᓠማረጋገጫዠá¨# ቀá–ች በáት áŒá‹œá‹ á áˆááˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢ የá®áˆá’á‹á‰°áˆ­á‹ ሰዓት á áˆá• በ<ph name="CURRENT_DATE" /> ተቀá“ብሯáˆá¢ ትá­á­áˆ ይመስáˆá‹á‰³áˆ? ትá­á­áˆ á«áˆáˆ†áᣠየá¥áˆ­áˆµá‹á• ስርዓት ሰዓት ማስተá«á¨áˆ á¥á“ ይህá•á• áŒˆá… áˆ›á‹°áˆµ á áˆˆá‰¥á‹á¢}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> የá¥áˆ­áˆµá‹á• መረጃ ለመጠበቅ በመደበááት áˆáˆµáŒ áˆ« ይጠቀማáˆá¢ Google Chrome á áˆá• á¨<ph name="SITE" /> ጋር ለመገá“á˜á‰µ ሲáˆá­áˆ­ ድር ጣቢያዠያáˆá‰°áˆˆáˆ˜á‹± á¥á“ ትá­á­áˆ á‹«áˆáˆ†á‘ áˆáˆµá­áˆ­áቶችᕠመáˆáˆ·áˆá¢ ይህ á á•á‹µ á áŒ¥á‰‚ <ph name="SITE" />á• á áˆµáˆ˜áˆµáˆ ለመቅረብ ሲáˆá­áˆ­ áዠወይሠá á•á‹µ የWi-Fi መáŒá‰¢á‹« ገጽ áŒá•á™áቱᕠሲያቋረጥ áˆá¨áˆ°á‰µ ይችላáˆá¢ Google Chrome ማá•á›á‹áˆ የá‹áˆ‚ብ áˆá‹á‹áŒ¥ á¨áˆ˜á«áˆ„ዱ በáት áŒá•á™áቱᕠስላቋረጠዠየá¥áˆ­áˆµá‹ መረጃ ደህá•áት á áˆá•áˆ የተጠበቀ áá‹á¢</translation>
<translation id="168841957122794586">የá áŒˆáˆáŒ‹á‹­ á¥á‹á‰…ᓠማረጋገጫዠደá«áˆ› የሆá ባለስá‹áˆ­ መረጃ á‰áˆá áዠያለá‹á¢</translation>
<translation id="1701955595840307032">የተጠቆመ ይዘት á‹«áŒá™</translation>
-<translation id="1706954506755087368">{1,plural, =1{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> á¥á•á‹°áˆ†á ማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት ማረጋገጫ á¥á‹á‰…ᓠማረጋገጫዠá¨áገ የመጣ áዠይላáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢}one{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> á¥á•á‹°áˆ†á ማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት ማረጋገጫ á¥á‹á‰…ᓠማረጋገጫዠየወደáት # ቀá•á–ች የመጣ áዠይላáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢}other{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> á¥á•á‹°áˆ†á ማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት ማረጋገጫ á¥á‹á‰…ᓠማረጋገጫዠየወደáት # ቀá•á–ች የመጣ áዠይላáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢}}</translation>
<translation id="1710259589646384581">ስርዓተ á­á‹ˆá“</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">የሥርዓት á áˆµá‰°á‹³á‹³áˆªá‹á• ለማáጋገር á‹­áˆá­áˆ©á¢</translation>
<translation id="17513872634828108">ትሮችᕠá­áˆá‰µ</translation>
<translation id="1753706481035618306">የገጽ á‰áŒ¥áˆ­</translation>
-<translation id="1761412452051366565">በGoogle የáˆáŒ á‰†áˆ áŒáˆ‹á‹áት የተላበሰ ይዘትᕠለማáŒá˜á‰µ ስáˆáˆ¨á‰µá• ያብሩá¢</translation>
-<translation id="1763864636252898013">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘á• áˆá‹«áˆ¨áŒ‹áŒáŒ¥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á¥á‹á‰…ᓠማረጋገጫዠበመሣሪያዠስርዓተ á­á‹ˆá“ የáˆá‰³áˆ˜á• á á‹­á‹°áˆˆáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />የWindows á á‹á‰³áˆ¨ መረብ መመርመሪያá‹á• ለማሄድ á‹­áˆá­áˆ©<ph name="END_LINK" />á¢</translation>
<translation id="1783075131180517613">á¥á‰£á­á‹ የማመሳሰሠይለá áˆáˆ¨áŒá‹á• ያዘáˆá‘á¢</translation>
<translation id="1791429645902722292">Google ዘመá“á‹ á‰áˆá</translation>
+<translation id="1815084229389833348">በቅርብ áŒá‹œ የáŒá‰ áŸá‰¸á‹ á‹•áˆá‰£á‰¶á‰½á‹ á¥á‹áˆ… ላይ ይታያሉá¢</translation>
<translation id="1821930232296380041">áˆá­ á‹«áˆáˆ†á ጥያቄ ወይሠየጥያቄ áˆá¬á‰¶á‰½</translation>
<translation id="1838667051080421715">የá á•á‹µ ድረ-ገጽ áˆá•áŒ­á• á¥á‹¨á‰°áˆ˜áˆˆá¨á‰± áá‹á¢</translation>
<translation id="1871208020102129563">የ.pac ስá­áˆªá•á‰µ á‹©á áˆ­á¤áˆ ሳይሆᕠተ᪠á áŒˆáˆáŒ‹á‹®á‰½á• á¥á•á‹²áŒ á‰€áˆ áዠተ᪠የተዋቀረá‹á¢</translation>
<translation id="1883255238294161206">á‹áˆ­á‹áˆ­ ሰብስብ</translation>
<translation id="1898423065542865115">በማጣራት ላይ</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> የá¥áˆ­áˆµá‹á• የመáŒá‰¢á‹« á¥á‹á‰…ᓠማረጋገጫ á áˆá‰°á‰€á‰ áˆˆáˆá£ ወይሠደáŒáˆ የመáŒá‰¢á‹« á¥á‹á‰…ᓠማረጋገጫዠáŒá‹œá‹ á áˆáበት áˆáˆ†á• ይችላáˆá¢</translation>
<translation id="194030505837763158">ወደ <ph name="LINK" /> ሂድ</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> á¥áˆá‰£á‰¶á‰½</translation>
<translation id="1973335181906896915">የመለያ á‰áŒ¥áˆ­ መስጠት ላይ ስህተት</translation>
<translation id="1974060860693918893">የላቀ</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{á¥á“ 1 ተጨማሪ}one{á¥á“ # ተጨማሪ}other{á¥á“ # ተጨማሪ}}</translation>
<translation id="2025186561304664664">ተ᪠ወደ ራስ-á‹á‰…ር ተዋቅሯáˆá¢</translation>
<translation id="2030481566774242610"><ph name="LINK" />ᕠማለትዠáá‹?</translation>
<translation id="2031925387125903299">የá¥áˆ­áˆµá‹ ወላጆች á¥áˆ­áˆµá‹ በመጀመሪያ ጉብáትዠላይ ያሉ á á‹²áˆµ ጣቢያá‹á‰½á• ማጽደቅ ስላለባቸዠይህᕠመáˆá¥á­á‰µ á¥á‹¨á‰°áˆ˜áˆˆá¨á‰± áá‹á¢</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />ወáªáˆ‰á• á¥á“ á¬áˆ‹á‹á• መáˆá‰°áˆ½<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">á‹á• á®á‹µ</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 የá áˆµá‰°á‹«á‹¨á‰µ ጥቆማ}one{# የá áˆµá‰°á‹«á‹¨á‰µ ጥቆማá‹á‰½}other{# የá áˆµá‰°á‹«á‹¨á‰µ ጥቆማá‹á‰½}}</translation>
<translation id="2065985942032347596">ማረጋገጫ ያስáˆáˆáŒ‹áˆ</translation>
<translation id="2079545284768500474">ቀáˆá‰¥áˆµ</translation>
<translation id="20817612488360358">የስርዓት ተ᪠ቅá•á‰¥áˆ®á‰½ ስራ ላይ á¥á•á‹²á‹áˆ‰ ተቀá“ብረዋሠáŒá• áŒáˆáŒ½ የሆá የተ᪠á‹á‰…ርሠተገáˆáŒ¿áˆá¢</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">á¥áˆá‰£á‰µ á áˆ­á‰µá‹•</translation>
<translation id="2166049586286450108">ሙሉ የá áˆµá‰°á‹³á‹°áˆ­ መድረሻ</translation>
<translation id="2166378884831602661">ይህ ጣቢያ ደህá•áቱ á áˆµá‰°áˆ›áˆ›á የሆá áŒá•á™áት ማቅረብ á á‹­á‰½áˆáˆ</translation>
-<translation id="2171101176734966184"><ph name="DOMAIN" />ᕠለመድረስ áˆá­áˆ¨á‹‹áˆá£ áገር áŒá• á áŒˆáˆáŒ‹á‹© á‹°á«áˆ› የáርማ ስáˆá‰°á‰€áˆ˜áˆ­ በመጠቀሠየተáˆáˆ¨áˆ˜ የá¥á‹á‰…ᓠማረጋገጫ áዠያረጋገጠá‹á¢ ይህሠማለት á áŒˆáˆáŒ‹á‹© ያቀረበዠየደህá•áት áˆáˆµá­áˆ­áቶች የተጭበረበሩ áˆáˆ†á‘ ይችላሉᣠá¥á“ሠá áŒˆáˆáŒ‹á‹© á¥áˆ­áˆµá‹ የáˆáŒ á‰¥á‰á‰µ á áŒˆáˆáŒ‹á‹­ ላይሆᕠይችላሠ(á¨á áŒ¥á‰‚ ጋር á¥á‹¨á‰°áŒˆá“á™ áˆáˆ†á• ይችላáˆ)á¢</translation>
<translation id="2181821976797666341">መáˆáˆªá‹«á‹á‰½</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 á á‹µáˆ«áˆ»}one{# á á‹µáˆ«áˆ»á‹á‰½}other{# á á‹µáˆ«áˆ»á‹á‰½}}</translation>
<translation id="2212735316055980242">መመሪያ á áˆá‰°áŒˆá˜áˆ</translation>
<translation id="2213606439339815911">áŒá‰¤á‰¶á‰½á• በማáˆáŒ£á‰µ ላይ...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> á áˆá‰°áŒˆá˜áˆ</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />የመመርመሪያ መተáŒá‰ áˆªá‹«á‹á•<ph name="END_LINK" /> በመጠቀሠáŒá•á™áትá‹á• ያስተá«á­áˆ‰á‰µ</translation>
+<translation id="2239100178324503013">á áˆá• ላá­</translation>
<translation id="225207911366869382">ይህ ዋጋ ለá‹áˆ… መመሪያ ተቋርጧáˆá¢</translation>
<translation id="2262243747453050782">የá¤á‰½ ቲ ቲ ᒠስህተት</translation>
<translation id="2282872951544483773">የማይገᙠሙá¨áˆ«á‹á‰½</translation>
<translation id="2292556288342944218">የá¥áˆ­áˆµá‹ የበየáመረብ መዳረሻ ታáŒá‹·áˆ</translation>
<translation id="229702904922032456">የá á•á‹µ የስር ወይሠመሃá¨áˆ á¥á‹á‰…ᓠማረጋገጫ áŒá‹œá‹ á áˆáበታáˆá¢</translation>
<translation id="230155334948463882">á á‹²áˆµ á«áˆ­á‹µ?</translation>
+<translation id="2305919008529760154">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á‹•á‹á‰…ᓠማረገጫዠበተጭበረበረ መáˆá© የወጣ áˆáˆ†á• ይችላáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በጠለሠá áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> የተጠቃሠስሠá¥á“ የይለá ቃሠያስáˆáˆáŒˆá‹‹áˆá¢</translation>
+<translation id="2318774815570432836">የድር ጣቢያዠHSTS ስለáˆáŒ á‰€áˆ á áˆá• <ph name="SITE" /> መáŒá‰¥á˜á‰µ á á‹­á‰½áˆ‰áˆá¢ የá á‹á‰³áˆ¨ መረብ ስህተቶች á¥á“ ጥቃቶች á á‰¥á‹›á›á‹ áŒá‹œ áŒá‹œá‹«á‹ á“ቸá‹á£ ስለá‹áˆ… ይህ ገጽ በá‹áˆ‹ ላይ áˆáˆ áˆ« ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="2328300916057834155">ችላ የተባለ የመረጃ ጠቋሠ<ph name="ENTRY_INDEX" /> áˆá­ á‹«áˆáˆ†á á¥áˆá‰£á‰µ</translation>
<translation id="2354001756790975382">ሌላ á¥áˆá‰£á‰¶á‰½</translation>
<translation id="2359808026110333948">ቀጥáˆ</translation>
<translation id="2365563543831475020">በ<ph name="CRASH_TIME" /> ላይ የተያዘዠየብáˆáˆ½á‰µ ሪá–ርት á áˆá‰°áˆ°á‰€áˆˆáˆ</translation>
<translation id="2367567093518048410">ደረጃ</translation>
+<translation id="2371153335857947666">{1,plural, =1{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት ማረጋገጫ áˆáˆµá­áˆ­ ወረቀቱ ትላá•á‰µá“ áŒá‹œá‹ á áˆáበታáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ የá®áˆá’á‹á‰°áˆ­á‹ ሰዓት á áˆá• ወደ <ph name="CURRENT_DATE" /> ተቀá“ብሯáˆá¢ ትá­á­áˆ ይመስáˆá‹á‰³áˆ? ትá­á­áˆ á«áˆáˆ†á የስርዓትá‹á‹á• ሰዓት ማስተá«á¨áˆ á¥á“ ይህá•á• ገጽ ማደስ á áˆˆá‰¥á‹á‰µá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢}one{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት ማረጋገጫ á¥á‹á‰…ᓠማረጋገጫዠá¨# ቀá–ች በáት áŒá‹œá‹ á áˆááˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ የá®áˆá’á‹á‰°áˆ­á‹ ሰዓት á áˆá• ወደ <ph name="CURRENT_DATE" /> ተቀá“ብሯáˆá¢ ትá­á­áˆ ይመስáˆá‹á‰³áˆ? ትá­á­áˆ á«áˆáˆ†á የስርዓትá‹á• ሰዓት ማስተá«á¨áˆ á¥á“ ይህá•á• ገጽ ማደስ á áˆˆá‰¥á‹á‰µá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢}other{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት ማረጋገጫ á¥á‹á‰…ᓠማረጋገጫዠá¨# ቀá–ች በáት áŒá‹œá‹ á áˆááˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ የá®áˆá’á‹á‰°áˆ­á‹ ሰዓት á áˆá• ወደ <ph name="CURRENT_DATE" /> ተቀá“ብሯáˆá¢ ትá­á­áˆ ይመስáˆá‹á‰³áˆ? ትá­á­áˆ á«áˆáˆ†á የስርዓትá‹á• ሰዓት ማስተá«á¨áˆ á¥á“ ይህá•á• ገጽ ማደስ á áˆˆá‰¥á‹á‰µá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢}}</translation>
<translation id="237718015863234333">áˆá•áˆ የበይáገጽ á áˆ›áˆ«áŒ®á‰½ á á‹­áŒˆá™áˆ</translation>
<translation id="2384307209577226199">የá•áŒá‹µ ድርጅት áባሪ</translation>
-<translation id="238526402387145295"><ph name="SITE" /> <ph name="BEGIN_LINK" />HSTS ስለáˆáŒ á‰€áˆ<ph name="END_LINK" /> ድር ጣቢያá‹á• á áˆá• መጠቀሠá á‹­á‰½áˆ‰áˆá¢ የá á‹á‰³áˆ¨ መረብ ስህተቶች á¥á“ ጥቃቶች á á‰¥á‹›á›á‹ áŒá‹œ áŒá‹œá‹«á‹ á“ቸá‹á£ ስለá‹áˆ… ይህ ገጽ በá‹áˆ‹ ላይ áˆáˆ°áˆ« ይችላáˆá¢</translation>
<translation id="2386255080630008482">የá áŒˆáˆáŒ‹á‹­ á¥á‹á‰…ᓠማረጋገጫ ተሽሯáˆá¢</translation>
<translation id="2392959068659972793">áˆá•áˆ á¥áˆ´á‰µ á‹«áˆá‰°á‹‹á‰€áˆ¨áˆ‹á‰¸á‹ መáˆáˆªá‹«á‹á‰½á• á áˆ³á‹­</translation>
<translation id="2396249848217231973">&amp;ስረዛᕠቀáˆá‰¥áˆµ</translation>
-<translation id="2413528052993050574">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘á• áˆá‹«áˆ¨áŒ‹áŒáŒ¥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á¥á‹á‰…ᓠማረጋገጫዠተሽሮ áˆáˆ†á• ይችላáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢</translation>
<translation id="2455981314101692989">ይህ ድረ-ገጽ ለá‹áˆ… ቅጽ ራስ-መሙላትᕠá áˆ°á“á­áˆáˆá¢</translation>
+<translation id="2463739503403862330">ሙላ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />የá á‹á‰³áˆ¨ መረብ መመርመሪያᕠበማሄድ ላይ<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">áˆá­ á‹«áˆáˆ†á የáለጋ á‹©á áˆ­á¤áˆá¢</translation>
<translation id="2491120439723279231">የá áŒˆáˆáŒ‹á‹­ á¥á‹á‰…ᓠማረጋገጫ ስህተቶችᕠይዟáˆá¢</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">á áˆµáŒˆá‰£</translation>
<translation id="2674170444375937751">á¥áˆ­áŒáŒ á› áá‹á‰µ á¥áá‹áˆ…ᕠገጾች á¨á‰³áˆªá­á‹ መሰረዠይáˆáˆáŒ‹áˆ‰?</translation>
<translation id="2677748264148917807">ለቅቀህ á‹áŒ£</translation>
+<translation id="269990154133806163">á áŒˆáˆáŒ‹á‹© የá¥á‹á‰…ᓠማረጋገጫ áŒáˆáŒ½áት መመሪያá‹á• በመጠቀሠበይዠያáˆá‰°áŒˆáˆˆáŒ¸ የá¥á‹á‰…ᓠማረጋገጫᕠá á‰…ርቧáˆá¢ ይህ ለá á•á‹³á•á‹µ የá¥á‹á‰…ᓠማረጋገጫá‹á‰½ áˆá‰³áˆ˜á‘ የáˆá‰½áˆ‰ መሆá“ቸá‹á• ለማረጋገጥ á¥á“ á¨á áŒ¥á‰‚á‹á‰½ ጥበቃ ለማድረጠá¥á•á‹²á‰»áˆ á áˆµáˆáˆ‹áŒ áá‹á¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">ዋጋ á¨á‰…ርጸት ጋር á á‹­á‹›áˆ˜á‹µáˆá¢</translation>
<translation id="2704951214193499422">Chromium በá‹áˆ… áŒá‹œ የá¥áˆ­áˆµá‹á• á«áˆ­á‹µ ማረጋገጥ á áˆá‰»áˆˆáˆá¢ á¥á‰£á­á‹ ቆይተዠá¥á•á‹°áŒˆá“ á‹­áˆá­áˆ©á¢</translation>
<translation id="2705137772291741111">የተቀመጠዠ(የተሸáŒáŒ ) የá‹áˆ… ጣቢያ ቅጂ የáˆáበብ á áˆáበረáˆá¢</translation>
<translation id="2709516037105925701">ራስ-ሙላ</translation>
+<translation id="2712118517637785082"><ph name="DOMAIN" />ᕠለመድረስ áˆá­áˆ¨á‹‹áˆá£ áገር áŒá• á áŒˆáˆáŒ‹á‹© ያቀረበዠየá¥á‹á‰…ᓠማረጋገጫ በሰጪዠተሽሯáˆá¢ ይህ ማለት á áŒˆáˆáŒ‹á‹© ያቀረበዠየደህá•áት áˆáˆµá­áˆ­áቶች áˆáŒ½áˆ áˆá‰³áˆ˜á‘ á á‹­áŒˆá‰£áˆá¢ á¨á áŒ¥á‰‚ ጋር á¥á‹¨á‰°áŒˆá“á™ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">áቃድ ጠይቅ</translation>
<translation id="2721148159707890343">ጥያቄ ተሳá­á‰·áˆ</translation>
<translation id="2728127805433021124">የá áŒˆáˆáŒ‹á‹© á¥á‹á‰…ᓠማረጋገጫ የተáˆáˆ¨áˆ˜á‹ በደá«áˆ› የáርማ ስáˆá‰°á‰€áˆ˜áˆ­ áá‹á¢</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">የá á‹µáˆ«áˆ» á¥á“ áለጋ á áˆáˆŒ</translation>
<translation id="2826760142808435982">áŒá•á™áቱ የተመሰጠረ á¥á“ <ph name="CIPHER" />ᕠበመጠቀሠየተረጋገጠ áá‹á£ á¥á“ <ph name="KX" />á• á¥á•á‹° የá‰áˆá መቀያየሪያ ስáˆá‰µ ይጠቀáˆá‰ á‰³áˆá¢</translation>
<translation id="2835170189407361413">ቅጽ á áŒ½á‹³</translation>
-<translation id="2837049386027881519">áŒá•á™áቱ የቆየ የቲ á¤áˆ á¤áˆµ ወይሠá¤áˆµ á¤áˆµ á¤áˆ á•áˆ®á‰¶á®áˆ ስሪትᕠበመጠቀሠá¥á•á‹°áŒˆá“ መáˆá¨áˆ­ áበረበትᢠይሄ በተለáˆá‹¶ á áŒˆáˆáŒ‹á‹© በጣሠየቆየ ሶáትዌር á¥á‹¨á‰°áŒ á‰€áˆ˜ መሆá‘á•á“ ሌáˆá‰½ የደህá•áት ችáŒáˆ®á‰½ áˆá–ሩበት ይችላሠማለት áá‹á¢</translation>
<translation id="284702764277384724">በ<ph name="HOST_NAME" /> ላይ የáበረዠየá áŒˆáˆáŒ‹á‹­ á¥á‹á‰…ᓠማረጋገጫ የተጨበረበረ ይመስላáˆá¢</translation>
<translation id="2889159643044928134">ዳáŒáˆ á á‰µáŒ«á•</translation>
-<translation id="2896499918916051536">ይህ ተሰ᪠á á‹­á‹°áŒˆááˆá¢</translation>
+<translation id="2900469785430194048">Google Chrome ይህᕠድረ-ገጽ ለማሳየት በáˆáˆá­áˆ­á‰ á‰µ áŒá‹œ ማá…ደረ ትá‹áˆµá‰³ á áˆá‰†á‰ á‰³áˆá¢</translation>
<translation id="2909946352844186028">የá á‹á‰³áˆ¨ መረብ ለá‹áŒ¥ ተገáቷáˆá¢</translation>
-<translation id="2915500479781995473">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘á• áˆá‹«áˆ¨áŒ‹áŒáŒ¥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á¥á‹á‰…ᓠማረጋገጫዠáŒá‹œ á áˆáበታáˆá¢ ይሄ በተሳሳተ á‹á‰…ር ወይሠáŒá•á™áትá‹á• á¥á‹¨áŒ áˆˆáˆ ባለ á á•á‹µ á áŒ¥á‰‚ የተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢ የá®áˆá’á‹á‰°áˆ­á‹ ሰዓት በá áˆá‘ áŒá‹œ ወደ <ph name="CURRENT_TIME" /> ተዋቅሯáˆá¢ ትá­á­áˆ ይመስላáˆ? á«áˆáˆ†á የስርዓትá‹á• ሰዓት á áˆµá‰°á«á­áˆˆá‹ ይህᕠገጽ ማደስ á áˆˆá‰¥á‹á‰µá¢</translation>
<translation id="2922350208395188000">የá áŒˆáˆáŒ‹á‹­ á¥á‹á‰…ᓠማረጋገጫ áˆáˆ¨áŒ‹áŒˆáŒ¥ á áˆá‰»áˆˆáˆá¢</translation>
-<translation id="2941952326391522266">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘á• áˆá‹«áˆ¨áŒ‹áŒáŒ¥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á¥á‹á‰…ᓠማረጋገጫዠበ<ph name="DOMAIN2" /> áዠየተሰጠá‹á¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢</translation>
<translation id="2948083400971632585">á¨á‰…á•á‰¥áˆ®á‰½ ገጽ ሆáዠማá“ቸá‹á•áˆ ለáŒá•á™áት የተዋቀሩ ተáªá‹á‰½á• ማሰá“á¨áˆ ይችላሉá¢</translation>
<translation id="2955913368246107853">á áŒá á áˆáˆŒá• á‹áŒ‹</translation>
<translation id="2958431318199492670">የá á‹á‰³áˆ¨ መረብ á‹á‰…ሩ በᦠá¤á• ሲ መስáˆáˆ­á‰± á á‹­áŒˆá‹›áˆá¢ á á•á‹³á•á‹µ የá‹á‰…ሩ á­ááˆá‰½ ላይመጡ ይችላሉá¢</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">የተሳሳተ የመáˆáˆªá‹« á á‹­áት</translation>
<translation id="3032412215588512954">ይህᕠጣቢያ ዳáŒáˆ መጫᕠይáˆáˆáŒ‹áˆ‰?</translation>
<translation id="3037605927509011580">á‹á‹­á£ ተሰá“á¨áˆˆ!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{በተሰመሩ መሣሪያá‹á‰½ ላይ ቢያá•áˆµ 1 á•áŒ¥áˆ}=1{1 á•áŒ¥áˆ (á¥á“ ተጨማሪ የተሰመሩ መሣሪያá‹á‰½ ላይ)}one{# á•áŒ¥áˆá‰½ (á¥á“ ተጨማሪ የተሰመሩ መሣሪያá‹á‰½ ላይ)}other{# á•áŒ¥áˆá‰½ (á¥á“ ተጨማሪ የተሰመሩ መሣሪያá‹á‰½ ላይ)}}</translation>
<translation id="3041612393474885105">የሰርቲáá¬á‰µ መረጃ</translation>
<translation id="3063697135517575841">Chrome በá‹áˆ… áŒá‹œ የá¥áˆ­áˆµá‹á• á«áˆ­á‹µ ማረጋገጥ á áˆá‰»áˆˆáˆá¢ á¥á‰£á­á‹ ቆይተዠá¥á•á‹°áŒˆá“ á‹­áˆá­áˆ©á¢</translation>
<translation id="3093245981617870298">á¨áˆ˜áˆµáˆ˜áˆ­ á‹áŒª áá‹á‰µá¢</translation>
@@ -205,15 +208,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">á¥áŒ…ጠበጣሠá á‹²áˆµ</translation>
<translation id="3207960819495026254">á‹•áˆá‰£á‰µ ተደርáŒá‰ á‰³áˆ</translation>
-<translation id="3225919329040284222">á áŒˆáˆáŒ‹á‹© á á‰¥áˆ¨á‹ የተሰሩ የáˆáŒ á‰ á‰ ማሟያá‹á‰½á• የማያሟላ የá¥á‹á‰…ᓠማረጋገጫ áዠያቀረበá‹á¢ á¥áá‹áˆ… የáˆáŒ á‰ á‰ ማሟያá‹á‰½ á¥áˆ­áˆµá‹á• ለመጠበቅ ለተረጋገጡ á¨áተᛠደህá•áት ላላቸዠድር ጣቢያá‹á‰½ ተá«á‰µá‰°á‹‹áˆá¢</translation>
<translation id="3226128629678568754">ገጹᕠለመጫᕠየáˆá‹«áˆµáˆáˆáŒˆá‹ á‹áˆ‚ብ ዳáŒáˆ ለማስገባት የዳáŒáˆ ጫᕠá á‹áˆ«áˆ©á• ይጫá‘á¢</translation>
<translation id="3228969707346345236">ገጹ á áˆµá‰€á‹µáˆ በ<ph name="LANGUAGE" /> ስለሆá ትርጉሙ á áˆá‰°áˆ³á«áˆá¢</translation>
<translation id="323107829343500871">የ<ph name="CREDIT_CARD" /> ሲቪሲ ያስገቡ</translation>
<translation id="3254409185687681395">ለá¥á‹áˆ… ገጽ á‹•áˆá‰£á‰µ á á‰¥áŒ…</translation>
<translation id="3270847123878663523">&amp;ዳáŒáˆ ደርድርᕠቀáˆá‰¥áˆµ</translation>
<translation id="3286538390144397061">á áˆá• ዳáŒáˆ á áˆµáŒ€áˆáˆ­</translation>
+<translation id="3303855915957856445">áˆá•áˆ የáለጋ á‹áŒ¤á‰¶á‰½ á áˆá‰°áŒˆá™áˆ</translation>
<translation id="3305707030755673451">የá¥áˆ­áˆµá‹ á‹áˆ‚ብ <ph name="TIME" /> ላይ በá¥áˆ­áˆµá‹ የስáˆáˆ¨á‰µ የይለá ቃሠተመስጥሯáˆá¢ ስáˆáˆ¨á‰µá• ለመጀመር ያስገቡትá¢</translation>
<translation id="333371639341676808">ይህ ገጽ ተጨማሪ ማገá“á›á‹á‰½á• á¥á•á‹³á‹­áˆáŒ¥áˆ­ á áŒá‹µá¢</translation>
+<translation id="3338095232262050444">ደህá•áቱ የተጠበቀ áá‹</translation>
<translation id="3340978935015468852">ቅá•á‰¥áˆ®á‰½</translation>
<translation id="3345135638360864351">ይህᕠጣቢያ ለመድረስ ያቀረቡት ጥያቄ ወደ <ph name="NAME" /> áˆáˆ‹á­ á áˆá‰°á‰»áˆˆáˆá¢ á¥á‰£á­á‹ á¥á•á‹°áŒˆá“ á‹­áˆá­áˆ©á¢</translation>
<translation id="3355823806454867987">የተ᪠ቅá•á‰¥áˆ®á‰½á• በመቀየር ላይ...</translation>
@@ -231,6 +235,7 @@
<translation id="3452404311384756672">የáˆáˆ˜áŒ£á‹ በየá¦</translation>
<translation id="3462200631372590220">የላበደብቅ</translation>
<translation id="3479539252931486093">ይህ á‹«áˆá‰°áŒ á‰ á‰€ áበር? <ph name="BEGIN_LINK" />ያሳá‹á‰á•<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">á áˆá• á á‹­á‹°áˆˆáˆ</translation>
<translation id="348000606199325318">የብáˆáˆ½á‰µ መታወቂያ <ph name="CRASH_LOCAL_ID" /> (የá áŒˆáˆáŒ‹á‹­ መታወቂያᦠ<ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">በá‹áˆ… áŒá‹œ ላይ ወላጅህᕠማáŒá˜á‰µ á áˆá‰»áˆá•áˆá¢ á¥á‰£á­áˆ… á¥á•á‹°áŒˆá“ áˆá­áˆ­á¢</translation>
<translation id="3527085408025491307">á á‰ƒá</translation>
@@ -239,6 +244,7 @@
<translation id="3542684924769048008">የይለá ቃሠይጠቀሙ ለá¦</translation>
<translation id="3549644494707163724">áˆáˆ‰áˆ የተመሳሰለ á‹áˆ‚ብ á¨á¥áˆ«áˆµá‹ የተመሳሰለ ይለá áˆáˆ¨áŒ ጋር ያመስጥሩ</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> ተጨማሪ...</translation>
+<translation id="3555561725129903880">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የዕá‹á‰…ᓠማረጋገጫዠá¨<ph name="DOMAIN2" /> የመጣ áá‹á¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">áŒá•á™áትዠየáŒáˆ á á‹­á‹°áˆˆáˆ</translation>
<translation id="3583757800736429874">&amp;á‹áˆ°á‹µá• ድገáˆ</translation>
<translation id="3586931643579894722">á‹áˆ­á‹áˆ­ ደብቅ</translation>
@@ -250,12 +256,15 @@
<translation id="3623476034248543066">á¥áˆ´á‰µ á áˆ³á‹­</translation>
<translation id="3630155396527302611">á á‹á‰³áˆ¨ መረቡ á¥á•á‹²á‹°áˆ­áˆµ የተáˆá‰€á‹°áˆˆá‰µ መሣሪያ áዠተብሠá áˆµá‰€á‹µáˆ á¨á‰°á‹˜áˆ¨á‹˜áˆ¨ á¨á‹áˆ­á‹áˆ©
á áˆµá‹ˆáŒá‹°á‹ á¥á•á‹°áŒˆá“ ለማá¨áˆ á‹­áˆá­áˆ©á¢</translation>
+<translation id="3638794133396384728">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á‹•á‹á‰…ᓠማረጋገጫዠየá áŒˆáˆáŒáˆá‰µ áŒá‹œá‹ á áˆáበታáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ የá¥áˆ­áˆµá‹ á®áˆá’á‹á‰°áˆ­ ሰዓት á áˆá• ወደ <ph name="CURRENT_TIME" /> ተዋቅሯáˆá¢ ትá­á­áˆ ይመስላáˆ? á«áˆáˆ†á የሥርዓትá‹á• ሰዓት ማስተá«á¨áˆá“ á¨á‹á‹« ይህᕠገጽ ማደስ á‹­á–ርብá‹á‰³áˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="3648607100222897006">á¥áá‹áˆ… የሙá¨áˆ« ባህሪያት በማá•á›á‹áˆ áŒá‹œ áˆá‰€á‹¨áˆ©á£ áˆáˆ°á‰ áˆ© ወይሠáˆáŒ á‰ ይችላሉᢠá¨á¥áá‹áˆ… ሙá¨áˆ«á‹á‰½ á‹áˆµáŒ¥ á á•á‹±á• ቢያበሩት áˆá• áˆá¨áˆ°á‰µ á¥á•á‹°áˆá‰½áˆ áˆá•áˆ á á‹­áት ዋስትá“á‹á‰½á• á á•áˆ°áŒ¥áˆá£ á¥á•á‹²á‹«á‹áˆ á áˆ³áˆ½á‹ ድá•áŒˆá‰µ áˆá‰ƒáŒ áˆ áˆáˆ‰ ይችላáˆá¢ ቀáˆá‹±á• á¥á•á‰°á‹ˆá‹á“ á áˆ³áˆ½á‹ áˆáˆ‰á•áˆ á‹áˆ‚ብá‹á• áˆáˆ°áˆ­á‹˜á‹ ይችላሠወይሠደáŒáˆ ደህá•áትዠá¥á“ áŒáˆ‹á‹áትዠባáˆá‰°áŒ á‰ á‰ መá•áŒˆá‹¶á‰½ ጥቃት áˆá‹°áˆ­áˆµá‰£á‰¸á‹ ይችላáˆá¢ የáˆá‹«áቋቸá‹á• ማá•á›á‹áˆ ሙá¨áˆ«á‹á‰½ ለáˆáˆ‰áˆ የá‹áˆ… á áˆ³áˆ½ ተጠቃሠáዠየáˆáá‰á‰µá¢ á¥á‰£á­á‹ በጥá•á‰ƒá‰„ ይቀጥሉá¢</translation>
<translation id="3650584904733503804">ማረጋገጥ ተሳá­á‰·áˆ</translation>
<translation id="3655670868607891010">ይህá•á• በተደጋጋáˆáት የáˆá‹«á‹© á¨áˆ†á‘ <ph name="HELP_LINK" />á• á‹­áˆá­áˆ©á¢</translation>
<translation id="3658742229777143148">á­áˆˆáˆ³</translation>
+<translation id="3678029195006412963">ጥያቄ áˆáˆáˆ¨áˆ á áˆá‰°á‰»áˆˆáˆ</translation>
<translation id="3681007416295224113">የሰርቲáá¬á‰µ መረጃ</translation>
<translation id="3693415264595406141">የይለá ቃáˆá¦</translation>
+<translation id="3696411085566228381">áˆá•áˆ</translation>
<translation id="3700528541715530410">á‹á‹­á£ ይህá•á• ገጽ የመድረስ áˆá‰ƒá‹µ የሌáˆá‹á‰µ ይመስላáˆá¢</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">በመጫᕠላይ...</translation>
@@ -263,7 +272,6 @@
<translation id="3714780639079136834">የáˆá‰£á‹­áˆ á‹áˆ‚ብ ወይሠWi-Fi ማብራት</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ወáªáˆ‰á•á£ á¬áˆ‹á‹á• á¥á“ የዲá¤á•á¤áˆµ á‹á‰…ረትᕠመáˆá‰°áˆ½<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">á¥áˆ­áˆµá‹ የቀዱት á áŒˆá“á</translation>
-<translation id="3744899669254331632">የድር ጣቢያዠChromium áˆá‹«áˆµá¬á‹³á‰¸á‹ የማይችሉ የተዘበራረበáˆáˆµá­áˆ­áቶችᕠስለላᨠá áˆá• ላይ <ph name="SITE" />ᕠመáŒá‰¥á˜á‰µ á á‹­á‰½áˆ‰áˆá¢ የá á‹á‰³áˆ¨ መረብ ስህተቶች á¥á“ ጥቃቶች ብዙá‹á• áŒá‹œ áŒá‹œá‹«á‹ á“ቸá‹á£ ስለá‹áˆ… ይህ ገጽ በá‹áˆ‹ ላይ áˆá“áˆá‰£á‰µ áˆáˆ°áˆ« ይችሠይሆá“áˆá¢</translation>
<translation id="375403751935624634">በá áŒˆáˆáŒ‹á‹­ ስህተት áˆá­á•á‹«á‰µ የትርጉሠስራዠተሰá“á­áˆáˆá¢</translation>
<translation id="3759461132968374835">በቅርብ áŒá‹œ ሪá–ርት የተደረጉ ብáˆáˆ½á‰¶á‰½ የለá‹á‰µáˆá¢ የብáˆáˆ½á‰µ ሪá–ርት ማድረጠተሰá“á­áˆ ሳለ የተá¨áˆ°á‰± ብáˆáˆ½á‰¶á‰½ á¥á‹áˆ… á á‹­á‰³á‹©áˆá¢</translation>
<translation id="3788090790273268753">የá‹áˆ… ጣቢያ የዕá‹á‰…ᓠማረጋገጫ á áŒˆáˆáŒáˆá‰µ 2016 ላይ ያበቃáˆá£ á¥á“ የዕá‹á‰…ᓠማረጋገጫ ሰá•áˆ°áˆˆá‰± SHA-1 በመጠቀሠየተáˆáˆ¨áˆ˜ የዕá‹á‰…ᓠማረጋገጫᕠያá«á‰µá‰³áˆá¢</translation>
@@ -275,19 +283,25 @@
<translation id="3884278016824448484">የáˆáŒ‹áŒ­ የመሣሪያ ለዪ</translation>
<translation id="3885155851504623709">ቤተ-á­áˆ…áት á á«á‰£á‰¢</translation>
<translation id="3901925938762663762">á«áˆ­á‹± á áŒˆáˆáŒáˆá‰µ áŒá‹œá‹ á á‰¥á‰…ቷáˆ</translation>
+<translation id="3910267023907260648"><ph name="DOMAIN" />ᕠለመድረስ áˆá­áˆ¨á‹‹áˆá£ áገር áŒá• á áŒˆáˆáŒ‹á‹© á‹°á«áˆ› የáርማ ስáˆá‰°-ቀመር በመጠቀሠየተáˆáˆ¨áˆ˜ የá¥á‹á‰…ᓠማረጋገጫ áዠያቀረበá‹á¢ ይህሠማለት á áŒˆáˆáŒ‹á‹© ያቀረበዠየደህá•áት áˆáˆµá­áˆ­áቶች የተጭበረበሩ áˆáˆ†á‘ ይችላሉᣠá¥á“ሠá áŒˆáˆáŒ‹á‹© á¥áˆ­áˆµá‹ የáˆáŒ á‰¥á‰á‰µ á áŒˆáˆáŒ‹á‹­ ላይሆᕠይችላሠ(á¨á áŒ¥á‰‚ ጋር á¥á‹¨á‰°áŒˆá“á™ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት ማረጋገጫ áˆáˆµá­áˆ­ ወረቀቱ á¨áገ የመጣ መሆᑠáá‹á¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢}one{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት ማረጋገጫ á¥á‹á‰…ᓠማረጋገጫዠá¨# ቀá–ች ወደáት የመጣ መሆᑠáá‹á¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢}other{ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት ማረጋገጫ á¥á‹á‰…ᓠማረጋገጫዠá¨# ቀá–ች ወደáት የመጣ መሆᑠáá‹á¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢}}</translation>
<translation id="3934680773876859118">የᒠዲ á¤á ሰáድ መጫᕠá áˆá‰°áˆ³á«áˆ</translation>
<translation id="3963721102035795474">የá á•á‰£á‰¢ áˆáታ</translation>
+<translation id="397105322502079400">በማስላት ላይ...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> ታáŒá‹·áˆ</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 ድረ-ገጽ በá á‰…ራቢያ}one{# ድረ-ገጾች በá á‰…ራቢያ}other{# ድረ-ገጾች በá á‰…ራቢያ}}</translation>
<translation id="4021036232240155012">ዲá¤á•á¤áˆµ የá á•á‹µ ድር ጣቢያ ስሠወደ የá¥áˆ± የበይáመረብ á á‹µáˆ«áˆ» የáˆá‰°áˆ¨áŒ‰áˆ የá á‹á‰³áˆ¨ መረብ á áŒˆáˆáŒáˆá‰µ áá‹á¢</translation>
<translation id="4030383055268325496">&amp;á á­áˆá• ቀáˆá‰¥áˆµ</translation>
-<translation id="4032534284272647190">የ<ph name="URL" /> መዳረሻ ተá¨áˆá­áˆáˆá¢</translation>
<translation id="404928562651467259">ማስጠá•á‰€á‰‚á‹«</translation>
<translation id="4058922952496707368">á‰áˆá «<ph name="SUBKEY" />»ᦠ<ph name="ERROR" /></translation>
<translation id="4075732493274867456">á‹°á•á‰ á›á‹ á¥á“ á áŒˆáˆáŒ‹á‹© የተለመደ የá¤áˆµá¤áˆµá¤áˆ á•áˆ®á‰¶á®áˆ ስሪት ወይሠየስá መሰá‹áˆ­ ጥቅሠá á‹­á‹°áŒá‰áˆá¢</translation>
<translation id="4079302484614802869">የተ᪠á‹á‰…ር ቋሠá áŒˆáˆáŒ‹á‹®á‰½á• ሳይሆᕠየ.pac ስá­áˆªá•á‰µ á‹©á áˆ­á¤áˆ ለመጠቀሠáዠየተዋቀረá‹á¢</translation>
<translation id="4103249731201008433">የመሣሪያ መለያ á‰áŒ¥áˆ­ áˆá­ á‹«áˆáˆ†á áá‹</translation>
<translation id="4103763322291513355">የተá¨áˆˆá¨áˆ‰ የዩ á áˆ­ á¤áˆá‰½ á‹áˆ­á‹áˆ­ á¥á“ ሌáˆá‰½ በስርዓት á áˆµá‰°á‹³á‹³áˆªá‹ á áˆµáŒˆá‹³áŒ…áት የተሰጣቸዠመመሪያá‹á‰½á• ለማየት &lt;strong&gt;chrome://policy&lt;/strong&gt;á• á‹­áŒá‰¥á™á¢</translation>
+<translation id="4110615724604346410">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የዕá‹á‰…ᓠማረጋገጫዠስህተቶች á áˆ‰á‰ á‰µá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="4117700440116928470">የመመሪያ ወሰᕠá á‹­á‹°áŒˆááˆá¢</translation>
+<translation id="4118212371799607889">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የዕá‹á‰…ᓠማረጋገጫዠበChromium የታመá á á‹­á‹°áˆˆáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 ሌላ}one{# ሌáˆá‰½}other{# ሌáˆá‰½}}</translation>
<translation id="4130226655945681476">የá á‹á‰³áˆ¨ መረብ ገመዶችá•á£ áˆá‹°áˆ á¥á“ ራá‹á‰°áˆ­á• በመáˆá‰°áˆ½ ላይ</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromium ይህᕠá«áˆ­á‹µ á¥á•á‹²á‹«áˆµá‰€áˆáŒ¥áˆá‹á‰µ á‹­áˆáˆáŒ‹áˆ‰?</translation>
@@ -295,6 +309,7 @@
<translation id="4176463684765177261">ተሰá“á­áˆáˆ</translation>
<translation id="4196861286325780578">&amp;á‹áˆ°á‹µá• ድገáˆ</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />የá¬áˆ‹ á¥á“ የጸረ-ቫይረስ á‹á‰…ረቶችᕠመáˆá‰°áˆ½<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{áˆá•áˆ}=1{1 መተáŒá‰ áˆªá‹« ($1)}=2{2 መተáŒá‰ áˆªá‹«á‹á‰½ ($1ᣠ$2)}one{# መተáŒá‰ áˆªá‹«á‹á‰½ ($1ᣠ$2ᣠ$3)}other{# መተáŒá‰ áˆªá‹«á‹á‰½ ($1ᣠ$2ᣠ$3)}}</translation>
<translation id="4220128509585149162">ብáˆáˆ½á‰¶á‰½</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />የá á‹á‰³áˆ¨ መረብ መመርመሪያᕠá áˆ‚á‹°á‹ á‹­áˆá­áˆ©<ph name="END_LINK" /></translation>
<translation id="4250680216510889253">á á‹­</translation>
@@ -303,14 +318,15 @@
<translation id="4269787794583293679">(áˆá•áˆ የተጠቃሠስሠየለáˆ)</translation>
<translation id="4300246636397505754">የወላጅ á áˆµá‰°á‹«á‹¨á‰µ ጥቆማá‹á‰½</translation>
<translation id="4304224509867189079">á‹­áŒá‰¡</translation>
+<translation id="432290197980158659">á áŒˆáˆáŒ‹á‹© በá‹áˆµáŒ -áŒá•á‰¡ የáˆáŒ á‰ á‰ áገሮች ጋር የማይዛመድ የዕá‹á‰…ᓠማረጋገጫ á á‰…ርቧáˆá¢ á¥áá‹áˆ… የáˆáŒ á‰ á‰ áገሮች á¥áˆ­áˆµá‹á• ለመጠበቅ ሲባሠá¨áተᛠደህá•áት ጥበቃ በáˆá‹«áˆµáˆáˆáŒ‹á‰¸á‹ የተወሰᑠድር ጣቢያá‹á‰½ ላይ ተá«á‰µá‰°á‹‹áˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="4325863107915753736">ጽሑá‰á• ማáŒá˜á‰µ á áˆá‰°á‰»áˆˆáˆ</translation>
+<translation id="4331708818696583467">ደህá•áቱ á áˆá‰°áŒ á‰ á‰€áˆ</translation>
<translation id="4372948949327679948">የተጠበቀዠየ<ph name="VALUE_TYPE" /> ዋጋ áá‹á¢</translation>
-<translation id="4377125064752653719"><ph name="DOMAIN" />ᕠለመድረስ áˆá­áˆ¨á‹‹áˆá£ áገር áŒá• á áŒˆáˆáŒ‹á‹© ያቀረበዠየá¥á‹á‰…ᓠማረጋገጫ በሰጪዠተሽሯáˆá¢ ይህ ማለት á áŒˆáˆáŒ‹á‹© ያቀረበዠየደህá•áት áˆáˆµá­áˆ­áቶች áˆáŒ½áˆ áˆá‰³áˆ˜á‘ á á‹­áŒˆá‰£áˆá¢ á¨á áŒ¥á‰‚ ጋር á¥á‹¨á‰°áŒˆá“á™ áˆáˆ†á• ይችላáˆá¢</translation>
<translation id="4381091992796011497">የተጣቃሠስáˆá¦</translation>
<translation id="4394049700291259645">á áˆ°á“á­áˆ</translation>
<translation id="4395129973926795186">á¨<ph name="START_DATE" /> á¥áˆµá¨ <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">የáለጋ á‹áŒ¤á‰¶á‰½</translation>
-<translation id="4424024547088906515">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘á• áˆá‹«áˆ¨áŒ‹áŒáŒ¥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á¥á‹á‰…ᓠማረጋገጫዠበChrome የáˆá‰³áˆ˜á• á á‹­á‹°áˆˆáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> የመáŒá‰¢á‹« á¥á‹á‰…ᓠማረጋገጫá‹á• á áˆá‰°á‰€á‰ áˆˆáˆá£ ወይሠገᓠá áˆá‰°áˆ°áŒ á‹á‰µ ይሆá“áˆá¢</translation>
<translation id="443673843213245140">የተ᪠መጠቀሠተሰá“á­áˆáˆ áŒá• áŒáˆáŒ½ የሆá የተ᪠á‹á‰…ር ተገáˆáŒ¿áˆá¢</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Google SafeSites ስለáቃ ይህᕠመáˆá¥á­á‰µ á¥á‹¨á‰°áˆ˜áˆˆá¨á‰± áá‹á¢</translation>
@@ -322,12 +338,12 @@
<translation id="4522570452068850558">á‹áˆ­á‹áˆ®á‰½</translation>
<translation id="4558551763791394412">ቅጥያá‹á‰½á‹á• á áˆ°á“á­áˆˆá‹ á‹­áˆá­áˆ©á¢</translation>
<translation id="4587425331216688090">á á‹µáˆ«áˆ» á¨Chrome ይወገድ?</translation>
+<translation id="4589078953350245614">ወደ <ph name="DOMAIN" /> ለመድረስ áˆá­áˆ¨á‹ áበርᣠáገር áŒá• á áŒˆáˆáŒ‹á‹© የማይሠራ የዕá‹á‰…ᓠማረጋገጫ á á‰…ርቧáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="4592951414987517459">ወደ የá¥áˆ­áˆµá‹ <ph name="DOMAIN" /> áŒá•á™áት ዘመá“ዠየáˆáˆµáŒ áˆ« ጥቅሠበመጠቀሠተመስጥሯáˆá¢</translation>
<translation id="4594403342090139922">&amp;ሰርá‹á• ቀáˆá‰¥áˆµ</translation>
+<translation id="4627442949885028695">á¨áˆŒáˆ‹ መሣሪያ ላይ ቀጥáˆ</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">የቅጥያ ገጽ á¥á‹¨á‰°áˆ˜áˆˆá¨á‰± áá‹á¢</translation>
-<translation id="467662567472608290">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘á• áˆá‹«áˆ¨áŒ‹áŒáŒ¥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á¥á‹á‰…ᓠማረጋገጫዠስህተቶች á áˆ‰á‰ á‰µá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢</translation>
-<translation id="4697214168136963651"><ph name="URL" /> ታáŒá‹¶ áበር</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">የá¥áˆ­áˆµá‹ áŒá•á™áት ተቋርጧáˆ</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />የWindows á á‹á‰³áˆ¨ መረብ መመርመሪያᕠበማሄድ ላይ<ph name="END_LINK" /></translation>
@@ -335,21 +351,26 @@
<translation id="4728558894243024398">የመሣሪያ ስርዓት</translation>
<translation id="4744603770635761495">የáˆáˆáŒ¸áˆ ዱá«</translation>
<translation id="4756388243121344051">&amp;ታሪá­</translation>
+<translation id="4759238208242260848">የወረዱ</translation>
<translation id="4764776831041365478"><ph name="URL" /> ላይ ያለዠድረ-ገጽ ለáŒá‹œá‹ የማይሰራ ወይሠá¥áˆµá¨áˆ˜áŒ¨áˆ¨áˆ»á‹ ወደ á á‹²áˆµ የድር á á‹µáˆ«áˆ» ተዛá‹áˆ® áˆáˆ†á• ይችላáˆá¢</translation>
<translation id="4771973620359291008">á‹«áˆá‰³á‹ˆá‰€ ስህተት ተá¨áˆµá‰·áˆá¢</translation>
<translation id="4782449893814226250">ይህᕠገጽ መáŒá‰¥á˜á‰µ ችáŒáˆ­ á«áˆˆá‹ ጠይቀዋáˆá¢</translation>
<translation id="4800132727771399293">የá¥áˆ­áˆµá‹á• የá áŒˆáˆáŒáˆá‰µ ማብቂያ ቀᕠá¥á“ CVC á‹­áˆá‰µáˆ¹ á¥á“ á¥á•á‹°áŒˆá“ á‹­áˆá­áˆ©</translation>
-<translation id="4807049035289105102"><ph name="SITE" /> Google Chrome áˆáˆ°áˆ«á‰£á‰¸á‹ የማይችላቸዠየተዘበራረበáˆáˆµá­áˆ­áቶችᕠስለላᨠድር ጣቢያá‹á• á áˆá• መáŒá‰¥á˜á‰µ á á‹­á‰½áˆ‰áˆá¢ የá á‹á‰³áˆ¨ መረብ ስህተቶች á¥á“ ጥቃቶች á á‰¥á‹›á›á‹ áŒá‹œ áŒá‹œá‹«á‹ á“ቸá‹á£ ስለá‹áˆ… ይህ ገጽ በá‹áˆ‹ ላይ áˆáˆ°áˆ« ይችላáˆá¢</translation>
<translation id="4813512666221746211">የá á‹á‰³áˆ¨ መረብ ስህተት</translation>
<translation id="4816492930507672669">ገጹᕠá áˆ˜áŒ£áŒ¥á•</translation>
<translation id="4850886885716139402">á áˆ³á‹­</translation>
<translation id="4880827082731008257">የáለጋ ታሪá­</translation>
+<translation id="4884656795097055129">áŒá‹œá‹ ትá­á­áˆ ሲሆᕠተጨማሪ ጽሑáች ይታያሉá¢</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />ᣠ<ph name="TYPE_2" />á£, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{á¥á“ 1 ተጨማሪ ድረ-ገጽ}one{á¥á“ # ተጨማሪ ድረ-ገጾች}other{á¥á“ # ተጨማሪ ድረ-ገጾች}}</translation>
<translation id="4923417429809017348">ገጹ á¨áˆ›á‹­á‰³á‹ˆá‰… ቋá•á‰‹ ወደ <ph name="LANGUAGE_LANGUAGE" /> ተተርጉሟáˆ</translation>
<translation id="4926049483395192435">መገለጽ á áˆˆá‰ á‰µá¢</translation>
<translation id="4930497775425430760">የá¥áˆ­áˆµá‹ ወላጅ በመጀመሪያ ጉብáትዠላይ ያሉ á á‹²áˆµ ጣቢያá‹á‰½á• ማጽደቅ ስላለባቸዠይህᕠመáˆá¥á­á‰µ á¥á‹¨á‰°áˆ˜áˆˆá¨á‰± áá‹á¢</translation>
<translation id="495170559598752135">á¥áˆ­áˆáŒƒá‹á‰½</translation>
<translation id="4958444002117714549">á‹áˆ­á‹áˆ©á• ዘርጋ</translation>
+<translation id="4962322354953122629">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የዕá‹á‰…ᓠማረጋገጫዠበChrome የታመá á á‹­á‹°áˆˆáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="498957508165411911">á¨<ph name="ORIGINAL_LANGUAGE" /> ወደ <ph name="TARGET_LANGUAGE" /> ይተርáŒáˆ?</translation>
+<translation id="4989809363548539747">ይህ ተሰ᪠á á‹­á‹°áŒˆááˆ</translation>
<translation id="5002932099480077015">የáቃ á¥á•á‹°áˆ†á Chrome ለበለጠ áˆáŒ£á• ቅጽ á áˆáˆ‹áˆ ሲባሠበá‹áˆ… መሳሪያ ላይ ያለዠየá«áˆ­á‹µá‹á• ቅጂ á‹«á¨áˆ›á‰»áˆá¢</translation>
<translation id="5019198164206649151">የመጠባበቂያ ማá¨áˆ›á‰» በመጥá áˆá”ታ ላይ</translation>
<translation id="5023310440958281426">የá áˆµá‰°á‹³á‹³áˆªá‹ መመሪያá‹á‰½á• ያረጋáŒáŒ¡</translation>
@@ -357,13 +378,12 @@
<translation id="5031870354684148875">ስለ Google ትርጉáˆ</translation>
<translation id="5040262127954254034">áŒáˆ‹á‹áት</translation>
<translation id="5045550434625856497">ትá­á­áˆ á‹«áˆáˆ†á የይለá ቃáˆ</translation>
+<translation id="5056549851600133418">ለá¥áˆ­áˆµá‹ የáˆáˆ†á‘ ጽሑáች</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />የወáªáˆ‰á• á á‹µáˆ«áˆ» መáˆá‰°áˆ½<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">የá áŒˆáˆáŒ‹á‹­ የዕá‹á‰…ᓠማረጋገጫ በá‹áˆ… áŒá‹œ ላይ የáˆáˆ°áˆ« á á‹­á‹°áˆˆáˆá¢</translation>
<translation id="5089810972385038852">áŒá‹›á‰µ</translation>
-<translation id="5094747076828555589">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘á• áˆá‹«áˆ¨áŒ‹áŒáŒ¥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á¥á‹á‰…ᓠማረጋገጫዠበChromium የáˆá‰³áˆ˜á• á á‹­á‹°áˆˆáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢</translation>
<translation id="5095208057601539847">ጠቅላይ áŒá‹›á‰µ</translation>
<translation id="5115563688576182185">(64-ቢት)</translation>
-<translation id="5122371513570456792">ለ«<ph name="SEARCH_STRING" />» <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ተገáተዋáˆá¢</translation>
<translation id="5141240743006678641">የተመሳሰሉ የይለá ቃላት á¨Google áˆáˆµá­áˆ­áቶችዠጋር ያመሳስሉ</translation>
<translation id="5145883236150621069">የስህተት á®á‹µ በመáˆáˆªá‹«á‹ áˆáˆ‹áˆ½ á‹áˆµáŒ¥ á áˆˆ</translation>
<translation id="5171045022955879922">á‹­áˆáˆáŒ‰ ወይሠዩá áˆ­á¤áˆ ይጻá‰</translation>
@@ -372,18 +392,18 @@
<translation id="5190835502935405962">የዕáˆá‰£á‰¶á‰½ á áˆáˆŒ</translation>
<translation id="5199729219167945352">ሙá¨áˆ«á‹á‰½</translation>
<translation id="5251803541071282808">ደመá“</translation>
+<translation id="5277279256032773186">በሥራ ላይ Chrome á¥á‹¨á‰°áŒ á‰€áˆ™ áá‹á‰µ? á•áŒá‹µ ሥራá‹á‰½ ለሠራተáቻቸዠየChrome ቅá•á‰¥áˆ®á‰½á• ማስተዳደር ይችላሉᢠየበለጠ ይረዱ</translation>
<translation id="5299298092464848405">መáˆáˆªá‹«á• መተá•á‰°á• ላይ ስህተት</translation>
<translation id="5300589172476337783">á áˆ³á‹­</translation>
<translation id="5308689395849655368">የብáˆáˆ½á‰µ ሪá–ርት ማድረጠተሰá“á­áˆáˆá¢</translation>
<translation id="5317780077021120954">á áˆµá‰€áˆáŒ¥</translation>
<translation id="5327248766486351172">ስáˆ</translation>
+<translation id="5359637492792381994">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የዕá‹á‰…ᓠማረጋገጫዠበá‹áˆ… áŒá‹œ ላይ የáˆáˆ áˆ« á á‹­á‹°áˆˆáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="536296301121032821">የመáˆáˆªá‹« ቅá•á‰¥áˆ®á‰½á• ማá¨áˆ›á‰¸á‰µ á áˆá‰°áˆ³á«áˆ</translation>
-<translation id="540969355065856584">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘á• áˆá‹«áˆ¨áŒ‹áŒáŒ¥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á¥á‹á‰…ᓠማረጋገጫዠበá‹áˆ… áŒá‹œ ላይ የáˆáˆ°áˆ« á á‹­á‹°áˆˆáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢</translation>
<translation id="5421136146218899937">የá áˆ°áˆ³ á‹áˆ‚ብ á áŒ½á‹³â€¦</translation>
<translation id="5430298929874300616">á‹•áˆá‰£á‰µ á áˆµá‹ˆáŒá‹µ</translation>
<translation id="5431657950005405462">የá¥áˆ­áˆµá‹ á‹á‹­áˆ á áˆá‰°áŒˆá˜áˆ</translation>
<translation id="5435775191620395718">ታሪá­á• á¨á‹áˆ… መሣሪያ በማሳየት ላይᢠ<ph name="BEGIN_LINK" />የበለጠ ለመረዳት<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">የá¥áˆ­áˆµá‹ የተሰመረ á‹áˆ‚ብ በብጠየይለá áˆáˆ¨áŒ ጥበቃ የáˆá‹°áˆ¨áŒáˆˆá‰µ ስለሆá áŒáˆ‹á‹áት የተላበሰ የይዘት ጥቆማá‹á‰½ በá áˆá‘ áŒá‹œ ተሰá“á­áˆˆá‹‹áˆá¢</translation>
<translation id="5439770059721715174">«<ph name="ERROR_PATH" />» ላይ የብያᔠማረጋገጥ ስህተትᦠ<ph name="ERROR" /></translation>
<translation id="5452270690849572955">ይህ <ph name="HOST_NAME" /> ገጽ áˆáŒˆá á á‹­á‰½áˆáˆ</translation>
<translation id="5455374756549232013">መጥá የመáˆáˆªá‹« áŒá‹œ ማህተáˆ</translation>
@@ -408,14 +428,18 @@ nil</translation>
<translation id="5622887735448669177">ይህᕠጣቢያ መá‹áŒ£á‰µ á‹­áˆáˆáŒ‹áˆ‰?</translation>
<translation id="5629630648637658800">የመáˆáˆªá‹« ቅá•á‰¥áˆ®á‰½á• መጫᕠá áˆá‰°áˆ³á«áˆ</translation>
<translation id="5631439013527180824">áˆá­ á‹«áˆáˆ†á የመሣሪያ á áˆµá‰°á‹³á‹°áˆ­ ማስመሰያ</translation>
-<translation id="5650551054760837876">áˆá•áˆ የáለጋ á‹áŒ¤á‰¶á‰½ á áˆá‰°áŒˆá™áˆá¢</translation>
<translation id="5677928146339483299">ታáŒá‹·áˆ</translation>
<translation id="5710435578057952990">የá‹áˆ… ድረ-ገጽ ማá•áት á áˆá‰°áˆ¨áŒ‹áŒˆáŒ áˆá¢</translation>
<translation id="5720705177508910913">የá áˆá‘ ተጠቃáˆ</translation>
+<translation id="572328651809341494">የቅርብ áŒá‹œ ትሮች</translation>
<translation id="5784606427469807560">የá¥áˆ­áˆµá‹á• á«áˆ­á‹µ ማረጋገጥ ላይ á á•á‹µ ችáŒáˆ­ áበርᢠየበይáመረብ áŒá•á™áትá‹á• á‹­áˆá‰µáˆ¹á‰µ á¥á“ á¥á•á‹°áŒˆá“ á‹­áˆá­áˆ©á¢</translation>
<translation id="5785756445106461925">በተጨማሪᣠይህ ገጽ ደህá•áታቸዠያáˆá‰°áŒ á‰ á‰€ ሌáˆá‰½ á•á‰¥áˆ¨á‰¶á‰½á• á á«á‰µá‰·áˆá¢ á¥áá‹áˆ… á•á‰¥áˆ¨á‰¶á‰½ በሽáŒáŒáˆ­ ወቅት በሌáˆá‰½ áˆá‰³á‹© ይችላሉᣠá¥á“ሠየገጹᕠመáˆá­ ለመለወጥ በá áŒ¥á‰‚á‹á‰½ áˆá‰€á‹¨áˆ© ይችላሉá¢</translation>
+<translation id="5786044859038896871">የá«áˆ­á‹µá‹á• መረጃ መሙላት á‹­áˆáˆáŒ‹áˆ‰?</translation>
+<translation id="5803412860119678065">የá¥áˆ­áˆµá‹á• <ph name="CARD_DETAIL" /> መሙላት á‹­áˆáˆáŒ‹áˆ‰?</translation>
<translation id="5810442152076338065">ወደ <ph name="DOMAIN" /> áŒá•á™áትዠáጹማዠስá መሰá‹áˆ­ ጥቅሠበመጠቀሠየተመሳጠረ áá‹á¢</translation>
<translation id="5813119285467412249">&amp;á á­áˆá• ድገáˆ</translation>
+<translation id="5814352347845180253">á¨<ph name="SITE" /> á¥á“ ሌáˆá‰½ á á•á‹³á•á‹µ ጣቢያá‹á‰½ የመጣ የá•áˆªáˆá‹¨áˆ ይዘት መዳረሻ áˆá‹«áŒ¡ ይችላሉá¢</translation>
+<translation id="5843436854350372569"><ph name="DOMAIN" />ᕠለመድረስ áˆá­áˆ¨á‹‹áˆá£ áŒá• á áŒˆáˆáŒ‹á‹© á‹°á«áˆ› á‰áˆá የያዘ የá¥á‹á‰…ᓠማረጋገጫ áዠያቀረበá‹á¢ á á•á‹µ á áŒ¥á‰‚ የáŒáˆ á‰áˆá‰á• ሰብሮ áˆáˆ†á• ይችላáˆá£ á¥á“ á áŒˆáˆáŒ‹á‹© የጠበá‰á‰µ ላይሆᕠይችላሠ(á¨á áŒ¥á‰‚ ጋር á¥á‹¨á‰°áŒˆá“á™ áˆáˆ†á‘ ይችላሉ)ᢠ<ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">የá¥áˆ­áˆµá‹ á áˆµá‰°á‹³á‹³áˆª ይህᕠጣቢያ ስላገደዠይህᕠመáˆá¥á­á‰µ á¥á‹¨á‰°áˆ˜áˆˆá¨á‰± áá‹á¢</translation>
<translation id="5857090052475505287">á á‹²áˆµ á á‰ƒá</translation>
<translation id="5869405914158311789">ይህ ጣቢያ áˆá‹°áˆ¨áˆµá‰ á‰µ á á‹­á‰½áˆáˆ</translation>
@@ -423,6 +447,7 @@ nil</translation>
<translation id="5872918882028971132">የወላጅ á áˆµá‰°á‹«á‹¨á‰µ ጥቆማá‹á‰½</translation>
<translation id="59107663811261420">ይህ የá«áˆ­á‹µ á á‹­áት ለá‹áˆ… áጋዴ በGoogle á­áá‹«á‹á‰½ á á‹­á‹°áŒˆááˆá¢ á¥á‰£á­á‹ የተለየ á«áˆ­á‹µ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="59174027418879706">áቅቷáˆ</translation>
+<translation id="5926846154125914413">á¨á á•á‹³á•á‹µ ጣቢያá‹á‰½ የመጣ የá•áˆªáˆá‹¨áˆ ይዘት መዳረሻ áˆá‹«áŒ¡ ይችላሉá¢</translation>
<translation id="5966707198760109579">ሳáˆá•á‰µ</translation>
<translation id="5967867314010545767">á¨á‰³áˆªá­ á áˆµá‹ˆáŒá‹µ</translation>
<translation id="5975083100439434680">á áˆ³á•áˆµ</translation>
@@ -434,12 +459,12 @@ nil</translation>
<translation id="604124094241169006">ራስ-ሰር</translation>
<translation id="6042308850641462728">ተጨማሪ</translation>
<translation id="6060685159320643512">ይጠá•á‰€á‰á£ á¥áá‹áˆ… ሙá¨áˆ«á‹á‰½ áˆá‹«áˆµá‰¸áŒáˆ© ይችላሉ</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{áˆá•áˆ}=1{1}one{#}other{#}}</translation>
<translation id="6146055958333702838">ማá“ቸá‹áˆ ገመዶችᕠይáˆá‰µáˆ¹á“ á¥á‹¨á‰°áŒ á‰€áˆ™ áˆáˆ†á‘ የáˆá‰½áˆá‰¸á‹á• ማá•á›á‹áˆ ራá‹á‰°áˆ®á‰½á£
áˆá‹°áˆá‰½á• ወይሠሌላ á á‹á‰³áˆ¨ መረብ መሣሪያá‹á‰½á• ዳáŒáˆ ያስጀáˆáˆ©á¢</translation>
<translation id="614940544461990577">á‹­áˆá­áˆ©á¦</translation>
<translation id="6150607114729249911">á‹á‹­! ይህᕠገጽ መáŒá‰¥á˜á‰µ ችáŒáˆ­ á‹­á‘ረዠወይሠá á‹­á‘ረዠወላጅá‹á• መጠየቅ á áˆˆá‰¥á‹á‰µá¢</translation>
<translation id="6151417162996330722">የá áŒˆáˆáŒ‹á‹­ á¥á‹á‰…ᓠማረጋገጫዠበጣሠረጅሠየሆá የማረጋገጫ áŒá‹œ á áˆˆá‹á¢</translation>
-<translation id="6154808779448689242">የተመለሰዠየመáˆáˆªá‹« ማስመሰያ á¨á áˆá‘ ማስመሰያ ጋር á á‹­á‹›áˆ˜á‹µáˆ</translation>
<translation id="6165508094623778733">ተጨማሪ ለመረዳት</translation>
<translation id="6203231073485539293">የበይáመረብ áŒá‘ááትá‹á• ያረጋáŒáŒ¡</translation>
<translation id="6218753634732582820">á¨Chromium ላይ á á‹µáˆ«áˆ» ይወገድ?</translation>
@@ -452,24 +477,30 @@ nil</translation>
<translation id="6328639280570009161">የá á‹á‰³áˆ¨ መረብ መገመትᕠá áˆ°á“á­áˆˆá‹ á‹­áˆá­áˆ©</translation>
<translation id="6337534724793800597">መáˆáˆªá‹«á‹á‰½á• በስሠá áŒ£áˆ«</translation>
<translation id="6342069812937806050">áˆá­ á áˆá•</translation>
+<translation id="6345221851280129312">á‹«áˆá‰³á‹ˆá‰€ መጠá•</translation>
<translation id="6355080345576803305">የይá‹á‹ á­áለ-áŒá‹œ መሻር</translation>
<translation id="6358450015545214790">á¥áá‹áˆ… áˆá• ማለት á“ቸá‹?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 ሌላ የá áˆµá‰°á‹«á‹¨á‰µ ጥቆማ}one{# ሌáˆá‰½ የá áˆµá‰°á‹«á‹¨á‰µ ጥቆማá‹á‰½}other{# ሌáˆá‰½ የá áˆµá‰°á‹«á‹¨á‰µ ጥቆማá‹á‰½}}</translation>
<translation id="6387478394221739770">á á‹²áˆµ የChrome ባህሪያትᕠይáˆáˆáŒ‹áˆ‰? የቅድመ á‹­áˆá•á‰³ ሰርጣችá•á• በchrome.com/beta ላይ á‹­áˆá­áˆ©á‰µá¢</translation>
-<translation id="641480858134062906"><ph name="URL" /> ለመጫᕠá áˆá‰°á‰»áˆˆáˆ</translation>
+<translation id="6389758589412724634">Chromium ይህᕠድረ-ገጽ ለማሳየት በáˆáˆá­áˆ­á‰ á‰µ áŒá‹œ ማá…ደረ ትá‹áˆµá‰³ á áˆá‰†á‰ á‰³áˆá¢</translation>
+<translation id="6416403317709441254">የድር ጣቢያዠChrome áˆá‹«áˆµá‰°á“áŒá‹°á‹ የማይችሠብትá•á‰µá• ያሉ á áˆ³áˆ›á áˆáˆµá­áˆ­á•á‰¶á‰½ ስለላᨠá áˆá• <ph name="SITE" />ᕠመáŒá‰¥á˜á‰µ á á‹­á‰½áˆ‰áˆá¢ የá á‹á‰³áˆ¨ መረብ ስህተቶች á¥á“ ጥቃቶች ብዙá‹á• áŒá‹œ áŒá‹œá‹«á‹ á“ቸዠስለá‹áˆ… ይህ ገጽ áˆá“áˆá‰£á‰µ በá‹áˆ‹ ላይ áˆáˆ áˆ« ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="6417515091412812850">የá¥á‹á‰…ᓠማረጋገጫዠተሽሮ á¥á•á‹°áˆ†á ማረጋገጥ á áˆá‰°á‰»áˆˆáˆá¢</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ማገá“á˜á‰µ á áˆ»áˆáˆ¨á ብáˆáˆá¢</translation>
<translation id="6445051938772793705">á áŒˆáˆ­</translation>
<translation id="6451458296329894277">á¥á•á‹°áŒˆá“ ለማስገባት የማረጋገጫ ቅጽ</translation>
<translation id="6458467102616083041">áባሪዠáለጋ በመáˆáˆªá‹« ስለተሰá“á¨áˆˆ ችላ ተብáˆáˆá¢</translation>
+<translation id="6462969404041126431">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á‹•á‹á‰…ᓠማረጋገጫዠተሽሮ áˆáˆ†á• ይችላáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="647261751007945333">የመሣሪያ መáˆáˆªá‹«á‹á‰½</translation>
<translation id="6489534406876378309">ድáˆáˆµáˆ¶á‰½á• መስቀሠጀáˆáˆ­</translation>
<translation id="6529602333819889595">&amp;ሰርá‹á• ድገáˆ</translation>
+<translation id="6534179046333460208">የá á«áˆ‹á‹ ድር ጥቆማá‹á‰½</translation>
<translation id="6550675742724504774">á áˆ›áˆ«áŒ®á‰½</translation>
+<translation id="6593753688552673085">á¨<ph name="UPPER_ESTIMATE" /> በታች</translation>
<translation id="6596325263575161958">የáˆáˆµáŒ áˆ« á áˆ›áˆ«áŒ®á‰½</translation>
<translation id="662080504995468778">ቆይ</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> áለጋ</translation>
-<translation id="6634865548447745291"><ph name="BEGIN_LINK" />ይህ የá¥á‹á‰…ᓠማረጋገጫ ስለተሻረ<ph name="END_LINK" /> <ph name="SITE" />ᕠመáŒá‰¥á˜á‰µ á á‹­á‰½áˆ‰áˆá¢ የá á‹á‰³áˆ¨ መረብ ስህተቶች á¥á“ ጥቃቶች á á‰¥á‹›á›á‹ áŒá‹œ áŒá‹œá‹«á‹ ብቻ á“ቸá‹á£ ስለá‹áˆ… ይህ ገጽ በá‹áˆ‹ ላይ áˆáˆ°áˆ« ይችላáˆá¢</translation>
<translation id="6644283850729428850">ይህ መመሪያ ተቋርጧáˆá¢</translation>
+<translation id="6652240803263749613">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á‹•á‹á‰…ᓠማረጋገጫዠበá¥áˆ­áˆµá‹ á®áˆá’á‹á‰°áˆ­ ሥርዓተ á­á‹á“ የታመá á á‹­á‹°áˆˆáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="6656103420185847513">á á‰ƒá ያርትዑ</translation>
<translation id="6660210980321319655"><ph name="CRASH_TIME" /> ላይ በራስ-ሰር ሪá“ርት ተደርጓáˆ</translation>
<translation id="6671697161687535275">የá áˆµá‰°á‹«á‹¨á‰µ ጥቆማ á¨Chromium ይወገድ?</translation>
@@ -477,6 +508,7 @@ nil</translation>
<translation id="6710213216561001401">ቀዳáˆ</translation>
<translation id="6710594484020273272">&lt;የáለጋ ቃሠይተይቡ&gt;</translation>
<translation id="6711464428925977395">በተ᪠á áŒˆáˆáŒ‹á‹© ላይ የሆá ችáŒáˆ­ á áˆˆ ወይሠá á‹µáˆ«áˆ»á‹ ትá­á­áˆ á á‹­á‹°áˆˆáˆá¢</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{áˆá•áˆ}=1{1 á•áŒ¥áˆ}one{# á•áŒ¥áˆá‰½}other{# á•áŒ¥áˆá‰½}}</translation>
<translation id="674375294223700098">á‹«áˆá‰³á‹ˆá‰€ የá áŒˆáˆáŒ‹á‹­ á¥á‹á‰…ᓠማረጋገጫ ስህተትá¢</translation>
<translation id="6753269504797312559">የመáˆáˆªá‹« á¥áˆ´á‰µ</translation>
<translation id="6757797048963528358">የá¥áˆ­áˆµá‹ መሣሪያ ተáቷáˆá¢</translation>
@@ -488,7 +520,6 @@ nil</translation>
<translation id="6891596781022320156">የመመሪያ ደረጃ á á‹­á‹°áŒˆááˆá¢</translation>
<translation id="6895330447102777224">የá¥áˆ­áˆµá‹ á«áˆ­á‹µ ተረጋáŒáŒ§áˆ</translation>
<translation id="6897140037006041989">የተጠቀሠተወá«á‹­</translation>
-<translation id="6903907808598579934">ስáˆáˆ¨á‰µá• á á‰¥áˆ«</translation>
<translation id="6915804003454593391">ተጠቃáˆá¦</translation>
<translation id="6957887021205513506">የá áŒˆáˆáŒ‹á‹© á¥á‹á‰…ᓠማረጋገጫ የተጭበረበረ ይመስላáˆá¢</translation>
<translation id="6965382102122355670">á‹­áˆá•</translation>
@@ -496,9 +527,11 @@ nil</translation>
<translation id="6970216967273061347">ወረዳ</translation>
<translation id="6973656660372572881">áˆáˆˆá‰±áˆ ቋሠተ᪠á áŒˆáˆáŒ‹á‹®á‰½ á¥á“ የ.pac ስá­áˆªá•á‰µ á‹©á áˆ­á¤áˆ ተገáˆáŒ¸á‹‹áˆá¢</translation>
<translation id="6989763994942163495">የላበቅá•á‰¥áˆ®á‰½á• á áˆ³á‹­...</translation>
+<translation id="7000990526846637657">áˆá•áˆ የታሪ᭠áŒá‰¤á‰¶á‰½ á áˆá‰°áŒˆá™áˆ</translation>
+<translation id="7009986207543992532">ወደ <ph name="DOMAIN" /> ለመድረስ áˆá­áˆ¨á‹‹áˆá£ áገር áŒá• á áŒˆáˆáŒ‹á‹© የáˆáˆ áˆ«á‰ á‰µ á­áለ áŒá‹œ የታመá á¥á•á‹³á‹­áˆ†á• á¨áˆá­ በላይ ረዥሠáŒá‹œ የሆá የዕá‹á‰…ᓠማረጋገጫᕠá á‰…ርቧáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">የá¥áˆ­áˆµá‹ Google መለያ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ላይ ሌáˆá‰½ የá áˆ°áˆ³ ታሪ᭠ዓይáቶች áˆá–ረዠይችላáˆ</translation>
<translation id="7029809446516969842">የይለá ቃላት</translation>
-<translation id="7050187094878475250"><ph name="DOMAIN" /> ጋር ለመድረስ áˆá­áˆ¨á‹‹áˆá£ áገር áŒá• á áŒˆáˆáŒ‹á‹© á áˆµá‰°áˆ›áˆ›á ለመሆᕠየáˆá‹«áˆµá‰¸áŒáˆ­ በጣሠረጅሠየሆá የማረጋገጫ áŒá‹œ áዠያለá‹á¢</translation>
<translation id="7087282848513945231">á á‹áˆ«áŒƒ</translation>
<translation id="7088615885725309056">የቆየ</translation>
<translation id="7090678807593890770"><ph name="LINK" />ᕠበGoogle ላይ á‹­áˆáˆáŒ‰</translation>
@@ -517,13 +550,13 @@ nil</translation>
<translation id="7246609911581847514">የá¥áˆ­áˆµá‹ á áˆµá‰°á‹³á‹³áˆª በመጀመሪያ ጉብáትዠላይ á á‹²áˆµ ጣቢያá‹á‰½á• ማጽደቅ ስላለባቸዠይህᕠመáˆá¥á­á‰µ á¥á‹¨á‰°áˆ˜áˆˆá¨á‰± áá‹á¢</translation>
<translation id="724975217298816891">የá«áˆ­á‹µ á‹áˆ­á‹áˆ®á‰½á‹á• ለማዘመᕠየ<ph name="CREDIT_CARD" /> áŒá‹œ ማለáá‹« ቀᕠá¥á“ ሲቪሲ ያስገቡᢠá á•á‹´ á«áˆ¨áŒ‹áŒˆáŒ¡ በá‹áˆ‹ የá«áˆ­á‹µ á‹áˆ­á‹áˆ®á‰½á‹ ለá‹áˆ… ጣቢያ ይጋራሉá¢</translation>
<translation id="725866823122871198">የá¥áˆ­áˆµá‹ የá®áˆá’ዩተር ቀᕠá¥á“ ሰዓት (<ph name="DATE_AND_TIME" />) áˆá­ ስላáˆáˆ†á‘ የáŒáˆ áŒá•á™áት ወደ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> áˆáˆ˜áˆ°áˆ¨á‰µ á á‹­á‰½áˆáˆá¢</translation>
-<translation id="7265986070661382626"><ph name="SITE" /> <ph name="BEGIN_LINK" />የá¥á‹á‰…ᓠማረጋገጫ መሰá«á‰µá• ስለáˆáŒ á‰€áˆ<ph name="END_LINK" /> ድር ጣቢያá‹á• á áˆá• መáŒá‰¥á˜á‰µ á á‹­á‰½áˆ‰áˆá¢ የá á‹á‰³áˆ¨ መረብ ስህተቶች á¥á“ ጥቃቶች á á‰¥á‹›á›á‹ áŒá‹œ áŒá‹œá‹«á‹ á“ቸá‹á£ ስለá‹áˆ… ይህ ገጽ በá‹áˆ‹ ላይ áˆáˆ°áˆ« ይችላáˆá¢</translation>
<translation id="7269802741830436641">ድረ-ገጹ የá á‹µáˆ«áˆ» ቅየራ áˆáˆáˆáˆµ á áˆˆá‹</translation>
<translation id="7275334191706090484">የተዳደሩ á¥áˆá‰£á‰¶á‰½</translation>
<translation id="7298195798382681320">የተመá¨áˆ©</translation>
-<translation id="7301833672208172928">የታሪ᭠ስáˆáˆ¨á‰µá• á á‰¥áˆ«</translation>
+<translation id="7309308571273880165">በ<ph name="CRASH_TIME" /> ላይ የተáሳ የብáˆáˆ½á‰µ ሪá–ርት (ሰቀላ በተጠቃሠተጠይቆ áበርᣠሆá–ሠáŒá• á¥áˆµá«áˆá• á áˆá‰°áˆ°á‰€áˆˆáˆ)</translation>
<translation id="7334320624316649418">&amp;ማስተá«á¨áˆá• ድገáˆ</translation>
<translation id="733923710415886693">የá áŒˆáˆáŒ‹á‹© የá¥á‹á‰…ᓠማረጋገጫ በá¥á‹á‰…ᓠማረጋገጫ áŒáˆáŒ½áት በá©áˆ á áˆá‰°áŒˆáˆˆáŒ¸áˆá¢</translation>
+<translation id="7351800657706554155">ይህ የá¥á‹á‰…ᓠማረጋገጫ ስለተሻረ <ph name="SITE" />ᕠመáŒá‰¥á˜á‰µ á á‹­á‰½áˆ‰áˆá¢ የá á‹á‰³áˆ¨ መረብ ስህተቶች á¥á“ ጥቃቶች á á‰¥á‹›á›á‹ áŒá‹œ áŒá‹œá‹«á‹ ብቻ á“ቸá‹á£ ስለá‹áˆ… ይህ ገጽ በá‹áˆ‹ ላይ áˆáˆ áˆ« ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">የትá¥á‹›á‹ መስመር</translation>
<translation id="7372973238305370288">የáለጋ á‹áŒ¤á‰µ</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -542,16 +575,17 @@ nil</translation>
<translation id="7469372306589899959">á«áˆ­á‹µá• በማረጋገጥ ላይ</translation>
<translation id="7481312909269577407">ወደ áት</translation>
<translation id="7485870689360869515">áˆá•áˆ á‹áˆ‚ብ á áˆá‰°áŒˆá˜áˆá¢</translation>
+<translation id="7508255263130623398">የተመላሽ መመሪያ መሣሪያ መታወቂያ ባዶ áዠወይሠá¨á áˆá‘ የመሣሪያ መታወቂያ ጋር á á‹­á‹›áˆ˜á‹µáˆ</translation>
<translation id="7514365320538308">á á‹áˆ­á‹µ</translation>
<translation id="7518003948725431193">ለá‹áˆ… የድር á á‹µáˆ«áˆ» áˆá•áˆ ድረ-ገጽ á áˆá‰°áŒˆá˜áˆá¦ <ph name="URL" /></translation>
<translation id="7537536606612762813">áŒá‹´á‰³</translation>
<translation id="7542995811387359312">ይህ ቅጽ ደህá•áቱ የተጠበቀ áŒá•á™áት ስለማይጠቀሠየá­áˆ¬á‹²á‰µ á«áˆ­á‹µ ራስ-መሙላት ተሰá“á­áˆáˆá¢</translation>
<translation id="7549584377607005141">ይህ ድረ-ገጽ በá áŒá‰£á‰¡ á¥á•á‹²á‰³á‹­ ቀደሠብለዠያስገቡት á‹áˆ‚ብ ያስáˆáˆáŒˆá‹‹áˆá¢ ይህᕠá‹áˆ‚ብ á¥á•á‹°áŒˆá“ መላ᭠ይችላሉᣠáገር áŒá• ይህᕠበማድረáŒá‹ ይህ ገጽ á¨á‹áˆ… በáት á‹«á¨á“ወáዠማá•á›á‹áˆ á¥áˆ­áˆáŒƒ á‹­á‹°áŒáˆ›áˆ‰á¢</translation>
<translation id="7554791636758816595">á á‹²áˆµ ትር</translation>
-<translation id="7567204685887185387">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘á• áˆá‹«áˆ¨áŒ‹áŒáŒ¥ á áˆá‰»áˆˆáˆá¤ የደህá•áት á¥á‹á‰…ᓠማረጋገጫዠበተጭበረበረ áˆá”ታ ተሰጥቶ áˆáˆ†á• ይችላáˆá¢ ይሄ በተሳሳተ á á‹ˆá‰ƒá‰€áˆ­ ወይሠá á•á‹µ á áŒ¥á‰‚ áŒá•á™áትá‹á• በመጥለበየተá¨áˆ°á‰° áˆáˆ†á• ይችላáˆá¢</translation>
<translation id="7568593326407688803">ይህ ገጽ በ<ph name="ORIGINAL_LANGUAGE" />áá‹á¢ መተርáŒáˆ á‹­áˆáˆáŒ‹áˆ‰?</translation>
<translation id="7569952961197462199">á­áˆ¬á‹²á‰µ á«áˆ­á‹µ á¨Chrome ይወገድ?</translation>
<translation id="7578104083680115302">Google ላይ ያስቀመጧቸá‹á• á«áˆ­á‹¶á‰½ በመጠቀሠበáˆáˆ‰áˆ መሣሪያá‹á‰½ ላይ በጣቢያá‹á‰½á“ መተáŒá‰ áˆªá‹«á‹á‰½ ላይ በáጥáት á‹­á­áˆáˆ‰á¢</translation>
+<translation id="7588950540487816470">á á«áˆ‹á‹ ድር</translation>
<translation id="7592362899630581445">የá áŒˆáˆáŒ‹á‹© á¥á‹á‰…ᓠማረጋገጫ á á•á‹³á•á‹µ ገደቦችᕠይጥሳáˆá¢</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> በá áˆá‘ áŒá‹œ ይህᕠጥያቄ ተቀብሠለማስተá“ገድ á á‹­á‰½áˆáˆá¢</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" />ᕠበጭራሽ á á‰µá‰°áˆ­áŒ‰áˆ</translation>
@@ -562,6 +596,7 @@ nil</translation>
<translation id="7637571805876720304">á­áˆ¬á‹²á‰µ á«áˆ­á‹µ á¨Chromium ይወገድ?</translation>
<translation id="765676359832457558">የላበቅá•á‰¥áˆ®á‰½á• ደብቅ...</translation>
<translation id="7658239707568436148">ይቅር</translation>
+<translation id="7667346355482952095">የተመለሰዠየመመሪያ ማስመሰያ ባዶ áዠወይሠá¨á áˆá‘ ማስመሰያ ጋር á á‹­á‹›áˆ˜á‹µáˆ</translation>
<translation id="7668654391829183341">á‹«áˆá‰³á‹ˆá‰€ መሣሪያ</translation>
<translation id="7674629440242451245">á á‹²áˆµ የሆᑠá áˆªá የChrome ባህሪያትᕠይáˆáˆáŒ‹áˆ‰? በ chrome.com/dev ላይ ያለá‹á• የdev ሰርጣችá•á• á‹­áˆá­áˆ©á‰µá¢</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ወደ <ph name="SITE" /> ቀጥሠ(ደህá•áቱ á‹«áˆá‰°áŒ á‰ á‰€)<ph name="END_LINK" /></translation>
@@ -578,10 +613,10 @@ nil</translation>
<translation id="780301667611848630">á á‹­á£ á áˆ˜áˆ°áŒá“ለáˆ</translation>
<translation id="7805768142964895445">áˆá”ታ</translation>
<translation id="7813600968533626083">የá áˆµá‰°á‹«á‹¨á‰µ ጥቆማ á¨Chrome ይወገድ?</translation>
+<translation id="7815407501681723534">ለ«<ph name="SEARCH_STRING" />» <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ተገáተዋáˆá¢</translation>
<translation id="785549533363645510">ሆá–ሠáŒá• የማይታዩ á á‹­á‹°áˆ‰áˆá¢ ማá•áት የማያሳá‹á‰… áˆáታ መጠቀሠየá¥áˆ­áˆµá‹á• á áˆ°áˆ³á£ የበይáመረብ á áŒˆáˆáŒáˆá‰µ á á‰…ራቢ ወይሠየáˆáŒá‰ áŸá‰¸á‹ ድር ጣቢያá‹á‰½ á¨á áˆ°áˆªá‹ á á‹­á‹°á‰¥á‰ƒá‰¸á‹áˆá¢</translation>
<translation id="7887683347370398519">የá¥áˆ­áˆµá‹á• CVC á‹­áˆá‰µáˆ¹ á¥á“ á¥á•á‹°áŒˆá“ á‹­áˆá­áˆ©</translation>
<translation id="7894616681410591072">á‹á‹­! ይህᕠገጽ ለመድረስ á¨<ph name="NAME" /> áቃድ ማáŒá˜á‰µ á áˆˆá‰¥á‹á‰µá¢</translation>
-<translation id="790025292736025802"><ph name="URL" /> á áˆá‰°áŒˆá˜áˆ</translation>
<translation id="7912024687060120840">በá‹áˆ… á á‰ƒá á‹áˆµáŒ¥á¦</translation>
<translation id="7920092496846849526">ይህᕠገጽ መáŒá‰¥á˜á‰µ ችáŒáˆ­ á«áˆˆá‹ ወላጅá‹á• ጠይቀዋáˆá¢</translation>
<translation id="7935318582918952113">የDOM ማጣሪያ</translation>
@@ -594,9 +629,10 @@ nil</translation>
<translation id="7995512525968007366">á áˆá‰°áŒ á‰€áˆ°áˆ</translation>
<translation id="8012647001091218357">በá‹áˆ… áŒá‹œ ላይ ወላጆችህᕠመድረስ á áˆá‰»áˆá•áˆá¢ á¥á‰£á­áˆ… á¥á•á‹°áŒˆá“ áˆá­áˆ­á¢</translation>
<translation id="8034522405403831421">ይህ ገጽ በ<ph name="SOURCE_LANGUAGE" /> áá‹á¢ ወደ <ph name="TARGET_LANGUAGE" /> ይተርáŒáˆ?</translation>
-<translation id="8034955203865359138">áˆá•áˆ የታሪ᭠áŒá‰¤á‰¶á‰½ á áˆá‰°áŒˆá™áˆá¢</translation>
<translation id="8088680233425245692">ጽሑá‰á• ማየት á áˆá‰°á‰»áˆˆáˆá¢</translation>
+<translation id="8089520772729574115">á¨1 ሜባ á‹«áሰ</translation>
<translation id="8091372947890762290">ማáŒá‰ áˆ­ በá áŒˆáˆáŒ‹á‹© ላይ በመጠባበቅ ላይ áá‹</translation>
+<translation id="8129262335948759431">á‹«áˆá‰³á‹ˆá‰€ መጠá•</translation>
<translation id="8131740175452115882">á áˆ¨áŒ‹áŒáŒ¥</translation>
<translation id="8134994873729925007">የ<ph name="HOST_NAME" /> á áŒˆáˆáŒ‹á‹­ <ph name="BEGIN_ABBR" />ዲá¤á•á¤áˆµ á á‹µáˆ«áˆ»<ph name="END_ABBR" /> áˆáŒˆá á áˆá‰°á‰»áˆˆáˆá¢</translation>
<translation id="8149426793427495338">የá¥áˆ­áˆµá‹ á®áˆá’á‹á‰° ተáቷáˆá¢</translation>
@@ -605,6 +641,7 @@ nil</translation>
<translation id="8201077131113104583">የማይሰራ የURL á‹áˆ›á” ለቅጥያ á¨áˆ˜á‰³á‹ˆá‰‚á‹« «<ph name="EXTENSION_ID" />» ጋርá¢</translation>
<translation id="8218327578424803826">የተመደበ መገᛠá á«á‰£á‰¢á¦</translation>
<translation id="8225771182978767009">ይህᕠá®áˆá’á‹á‰°áˆ­ ያቀá“በረዠሰዠይህᕠጣቢያ ለማገድ መርጧáˆá¢</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />ᣠ<ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">á¥á‹¨áˆáˆˆáŒ‰á‰µ ያሉት ገጽ ያስገቡትᕠመረጃ ተጥቅሟáˆá¢ ወደዛ ገጽ መመለስ ወስደá‹á‰µ የáበረá‹á• ርáˆáŒƒ á¥á•á‹²á‹°áŒˆáˆ áˆá‹«á‹°áˆ­áŒ ይችላáˆá¢ ለመቀጠሠይáˆáˆáŒ‹áˆ‰?</translation>
<translation id="8249320324621329438">ለመጨረሻ áŒá‹œ የመጣá‹á¦</translation>
<translation id="8261506727792406068">ሰርá‹</translation>
@@ -617,12 +654,17 @@ nil</translation>
<translation id="8349305172487531364">የዕáˆá‰£á‰¶á‰½ á áˆáˆŒ</translation>
<translation id="8363502534493474904">የá á‹áˆ®á•áˆ‹á• áˆáታᕠማጥá‹á‰µ</translation>
<translation id="8364627913115013041">á áˆá‰°á‹‹á‰€áˆ¨áˆá¢</translation>
+<translation id="8380941800586852976">á á‹°áŒˆá›</translation>
<translation id="8412145213513410671">ብáˆáˆ½á‰¶á‰½ (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">ተመሳሳዩ የይለá áˆáˆ¨áŒ‰á• áˆáˆˆá‰µ áŒá‹œ ማስገባት á áˆˆá‰¥á‹á‰µá¢</translation>
<translation id="8428213095426709021">ቅá•á‰¥áˆ®á‰½</translation>
+<translation id="8433057134996913067">ይህ á¨á á‰¥á‹›á›á‹á‰¹ የድር ጣቢያá‹á‰½ ዘáŒá‰¶ ያስወጣá‹á‰³áˆá¢</translation>
<translation id="8437238597147034694">&amp;á‹áˆ°á‹µá• ቀáˆá‰¥áˆµ</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 á­áˆ¬á‹²á‰µ á«áˆ­á‹µ}one{# á­áˆ¬á‹²á‰µ á«áˆ­á‹¶á‰½}other{# á­áˆ¬á‹²á‰µ á«áˆ­á‹¶á‰½}}</translation>
+<translation id="8483780878231876732">á¨á¥áˆ­áˆµá‹ የGoogle መለያ á«áˆ­á‹¶á‰½á• ለመጠቀሠወደ Chrome በመለያ á‹­áŒá‰¡</translation>
<translation id="8488350697529856933">የáˆáˆ˜áˆˆá¨á‰°á‹ ለ</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> áˆáˆ‹áˆ½ ለመስጠት á¨áˆá­ በላይ ረዥሠáŒá‹œ ወስዷáˆá¢</translation>
+<translation id="852346902619691059">ይህ á áŒˆáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆá‘ᕠማረጋገጥ á áˆá‰»áˆˆáˆá¤ የዕá‹á‰…ᓠማረጋገጫዠበá¥áˆ­áˆµá‹ መሣሪያ ሥርዓተ á­á‹ˆá“ የታመá á á‹­á‹°áˆˆáˆá¢ ይህ በተሳሳተ á‹á‰…ረት ወይሠየá¥áˆ­áˆµá‹á• áŒá•á™áት በáˆáŒ áˆá á áŒ¥á‰‚ áˆá­á•á‹«á‰µ የተáˆáŒ áˆ¨ áˆáˆ†á• ይችላáˆá¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" />á¢</translation>
<translation id="8530504477309582336">ይህ የá«áˆ­á‹µ á á‹­áት በGoogle á­áá‹«á‹á‰½ á á‹­á‹°áŒˆááˆá¢ á¥á‰£á­á‹ የተለየ á«áˆ­á‹µ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="8550022383519221471">የማመሳሰሠá áŒˆáˆáŒáˆá‰µ ለáŒáˆ«á‹ á á‹­áŒˆááˆá¢</translation>
<translation id="8553075262323480129">የገጹ ቋá•á‰‹ áˆá‰³á‹ˆá‰… ስላáˆá‰»áˆˆ ትርጉሙ á áˆá‰°áˆ³á«áˆá¢</translation>
@@ -634,15 +676,12 @@ nil</translation>
<translation id="8647750283161643317">áˆáˆ‰á•áˆ ወደ áባሪ ዳáŒáˆ á áˆµáŒ€áˆáˆ­</translation>
<translation id="8680787084697685621">የመለያ መáŒá‰¢á‹« á‹áˆ­á‹áˆ®á‰½ áŒá‹œ ያለáˆá‰£á‰¸á‹ á“ቸá‹á¢</translation>
<translation id="8703575177326907206">á¨<ph name="DOMAIN" /> ጋር ያለá‹á‰µ áŒá•á™áት á áˆá‰°áˆ˜áˆ°áŒ áˆ¨áˆ</translation>
-<translation id="8713130696108419660">መጥá የá áˆµáŒ€áˆ›áˆª áርማ</translation>
<translation id="8725066075913043281">á¥á•á‹°áŒˆá“ á‹­áˆá­áˆ©</translation>
<translation id="8728672262656704056">ማá•áት የማያሳá‹á‰… áˆáታ á‹áˆµáŒ¥ ገብተዋáˆ</translation>
<translation id="8730621377337864115">ተá¨á“á‹á—áˆ</translation>
<translation id="8738058698779197622">ደህá•áቱ የተጠበቀ áŒá•á™áት ለመመስረትᣠየá¥áˆ­áˆµá‹ ሰዓት በትá­á­áˆ መቀá“በር ያስáˆáˆáŒˆá‹‹áˆá¢ ይህᕠየሆáበት áˆá­á•á‹«á‰µ የድር ጣቢያá‹á‰½ ራሳቸá‹á• ለማሳወቅ የáˆáŒ á‰€áˆ™á‰£á‰¸á‹ የáˆáˆµá­áˆ­ ወረቀቶች የáˆáˆ°áˆ©á‰µ ለተወሰᑠá­áለ áŒá‹œá‹«á‰¶á‰½ ብቻ ስለሆá áá‹á¢ የá¥áˆ­áˆµá‹ መሣሪያ ሰዓት áˆá­ á¥á•á‹³áˆˆáˆ˜áˆ†á‘ መጠᕠChromium á¥áá‹áˆ…á• áˆáˆµá­áˆ­ ወረቀቶች áˆá‹«áˆ¨áŒ‹áŒáŒ£á‰¸á‹ á á‹­á‰½áˆáˆá¢</translation>
<translation id="8740359287975076522">የ<ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;የዲá¤á•á¤áˆµ á á‹µáˆ«áˆ»&lt;/abbr&gt; áˆáŒˆá á áˆá‰°á‰»áˆˆáˆá¢ ችáŒáˆ©á• በመመርመር ላይá¢</translation>
-<translation id="8741995161408053644">የá¥áˆ­áˆµá‹ Google መለያ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ላይ ሌáˆá‰½ የá áˆ°áˆ³ ታሪ᭠ዓይáቶች áˆá–ረዠይችላáˆá¢</translation>
<translation id="8790007591277257123">&amp;ሰርá‹á• ድገáˆ</translation>
-<translation id="8790687370365610530">በGoogle የተጠቆመ áŒáˆ‹á‹áት የተላበሰ ይዘትᕠለማáŒá˜á‰µ ስáˆáˆ¨á‰µá• ያብሩá¢</translation>
<translation id="8798099450830957504">á¥á•á‹°á‹ˆáˆ¨á‹°</translation>
<translation id="8804164990146287819">የáŒáˆ‹á‹áት መመሪያ</translation>
<translation id="8820817407110198400">á‹•áˆá‰£á‰¶á‰½</translation>
@@ -664,13 +703,11 @@ nil</translation>
<translation id="8971063699422889582">የá áŒˆáˆáŒ‹á‹­ á¥á‹á‰…ᓠማረጋገጫ áŒá‹œá‹ á áˆáበታáˆá¢</translation>
<translation id="8987927404178983737">ወር</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">á áŒˆáˆáŒ‹á‹© የá¥á‹á‰…ᓠማረጋገጫ áŒáˆáŒ½áት መመሪያá‹á• በመጠቀሠበይዠያáˆá‰°áŒˆáˆˆáŒ¸ የá¥á‹á‰…ᓠማረጋገጫᕠá á‰…ርቧáˆá¢ ይህ ለá á•á‹³á•á‹µ የá¥á‹á‰…ᓠማረጋገጫá‹á‰½ áˆá‰³áˆ˜á‘ የáˆá‰½áˆ‰ መሆá“ቸá‹á• ለማረጋገጥ á¥á“ á¨á áŒ¥á‰‚á‹á‰½ ጥበቃ ለማድረጠá¥á•á‹²á‰»áˆ á áˆµáˆáˆ‹áŒ áá‹á¢</translation>
<translation id="9001074447101275817">ተ᪠<ph name="DOMAIN" /> የተጠቃሠስሠá¥á“ የይለá ቃሠያስáˆáˆáŒˆá‹‹áˆá¢</translation>
<translation id="901974403500617787">በመላዠስርዓት ላይ የáˆá‰°áŒˆá‰ áˆ© ጥቆማá‹á‰½ በባለቤቱ ብቻ áá‹ áˆá‹‹á‰€áˆ© የáˆá‰½áˆ‰á‰µá¦ <ph name="OWNER_EMAIL" />á¢</translation>
<translation id="9020542370529661692">ይህ ገጽ ወደ <ph name="TARGET_LANGUAGE" /> ተተርጉሟáˆ</translation>
<translation id="9038649477754266430">ገጾችᕠይበáˆáŒ¥ በáጥáት ለመጫᕠየáŒáˆ˜á‰³ á áŒˆáˆáŒáˆá‰µá• ይጠቀሙ</translation>
<translation id="9039213469156557790">በተጨማሪᣠይህ ገጽ ደህá•áታቸዠያáˆá‰°áŒ á‰ á‰€ ሌáˆá‰½ á•á‰¥áˆ¨á‰¶á‰½á• á á«á‰µá‰·áˆá¢ á¥áá‹áˆ… á•á‰¥áˆ¨á‰¶á‰½ በሽáŒáŒáˆ­ ወቅት በሌáˆá‰½ áˆá‰³á‹© ይችላሉᣠá¥á“ሠየገጹᕠባህሪ ለመለወጥ በá áŒ¥á‰‚á‹á‰½ áˆá‰€á‹¨áˆ© ይችላሉá¢</translation>
-<translation id="9049981332609050619"><ph name="DOMAIN" />ᕠለመድረስ áˆá­áˆ¨á‹ áበርᣠáŒá• á áŒˆáˆáŒ‹á‹© áˆá­ á‹«áˆáˆ†á የá¥á‹á‰…ᓠማረጋገጫ áዠያሳየá‹á¢</translation>
<translation id="9050666287014529139">የይለá áˆáˆ¨áŒ</translation>
<translation id="9065203028668620118">á áˆ­á‰µá‹•</translation>
<translation id="9092364396508701805">የ<ph name="HOST_NAME" /> ገጽ á¥á‹¨áˆ áˆ« á á‹­á‹°áˆˆáˆ</translation>
diff --git a/chromium/components/strings/components_strings_ar.xtb b/chromium/components/strings/components_strings_ar.xtb
index c81a907aa84..b8b5d0ebe8c 100644
--- a/chromium/components/strings/components_strings_ar.xtb
+++ b/chromium/components/strings/components_strings_ar.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ar">
+<translation id="1008557486741366299">Ù„Ùس الآن</translation>
<translation id="1015730422737071372">تقدÙÙ… تÙاصÙÙ„ إضاÙÙØ©</translation>
<translation id="1032854598605920125">تدوÙر Ù٠اتجاه عقارب الساعة</translation>
<translation id="1038842779957582377">اسم غÙر معروÙ</translation>
+<translation id="1053591932240354961">â€Ù„ا Ùمكنك زÙارة <ph name="SITE" /> الآن نظرًا لأن موقع الوÙب أرسل بÙانات اعتماد مختلطة Ùتعذر على Google Chrome معالجتها. أخطاء الشبكة والهجمات علÙها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصÙحة لاحقًا على الأرجح. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">تراجع عن الإ&amp;ضاÙØ©</translation>
<translation id="10614374240317010">لم Ùتم الحÙظ مطلقًا</translation>
-<translation id="1064422015032085147">â€Ù‚د Ùكون الخادم الذ٠ÙستضÙ٠صÙحة الوÙب زائد التحمÙÙ„ أو Ù‚Ùد الصÙانة.
- ولتجنب جذب عدد زÙارات كبÙر وتجنب جعل الموق٠أكثر سوءًا،
- Ùقد تم عدم السماح بالطلبات إلى عنوان URL هذا مؤقتًا.</translation>
<translation id="106701514854093668">الإشارات المرجعÙØ© على سطح المكتب</translation>
<translation id="1080116354587839789">ملاءمة مع العرض</translation>
+<translation id="1103124106085518534">Ù„Ùس هناك محتوى جدÙد</translation>
<translation id="1103523840287552314">ترجمة اللغة <ph name="LANGUAGE" /> دائمًا</translation>
<translation id="1107591249535594099">â€Ø¥Ø°Ø§ تم وضع علامة على هذا الخÙار، سÙخزّن Chrome نسخة من هذه البطاقة على هذا الجهاز لتعبئة النماذج بشكل أسرع.</translation>
+<translation id="1111153019813902504">الإشارات الجدÙدة</translation>
<translation id="1113869188872983271">تراجع عن إعادة الت&amp;رتÙب</translation>
+<translation id="1126551341858583091">Ùمثل الحجم على سعة التخزÙÙ† المحلÙØ© <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">ذاكرة التخزÙÙ† المؤقت للسÙاسة بحالة جÙدة</translation>
<translation id="113188000913989374"><ph name="SITE" /> Ùعرض:</translation>
<translation id="1132774398110320017">â€Ø¥Ø¹Ø¯Ø§Ø¯Ø§Øª الملء التلقائ٠ÙÙ Chrome...</translation>
-<translation id="1150979032973867961">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان غÙر موثقة من خلال نظام تشغÙÙ„ الكمبÙوتر. وربما Ùكون السبب Ù٠ذلك خطأ Ù٠التكوÙÙ† أو مهاجمًا Ùعترض الاتصال.</translation>
<translation id="1152921474424827756">الدخول إلى <ph name="BEGIN_LINK" />النسخة المخزنة مؤقتًا<ph name="END_LINK" /> من <ph name="URL" /></translation>
<translation id="1158211211994409885">أغلق <ph name="HOST_NAME" /> الاتصال على نحو غÙر متوقع.</translation>
<translation id="1161325031994447685">â€Ø¥Ø¹Ø§Ø¯Ø© الاتصال بـ Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">إزالة</translation>
<translation id="1201402288615127009">التالÙ</translation>
<translation id="1201895884277373915">المزÙد من هذا الموقع</translation>
-<translation id="121201262018556460">لقد حاولت الوصول إلى <ph name="DOMAIN" />ØŒ ولكن الخادم قدّم شهادة تحتو٠على Ù…Ùتاح ضعÙÙ. ربما قام أحد المهاجمÙÙ† باختراق المÙتاح الخاص، ولا Ùكون الخادم هو الخادم الذ٠تتوقعه (قد تكون على اتصال بأحد المهاجمÙÙ†).</translation>
+<translation id="1206967143813997005">توقÙع أوّÙل٠سÙئ</translation>
+<translation id="1209206284964581585">إخÙاء الآن</translation>
<translation id="1219129156119358924">أمان النظام</translation>
<translation id="1227224963052638717">سÙاسة غÙر معروÙØ©.</translation>
<translation id="1227633850867390598">إخÙاء القÙمة</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">نعم</translation>
<translation id="1430915738399379752">طباعة</translation>
<translation id="1442912890475371290">تمّ منع محاولة <ph name="BEGIN_LINK" /> الانتقال إلى إحدى الصÙحات على <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">لا Ùمكنك زÙارة <ph name="SITE" /> الآن نظرًا لأن موقع الوÙب Ùستخدم أداة التحقق من صحة الشهادات. أخطاء الشبكة والهجمات علÙها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصÙحة لاحقًا على الأرجح. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">عرض نسخة محÙوظة (أ٠معرو٠أنها منتهÙØ©) من هذه الصÙحة.</translation>
<translation id="1519264250979466059">تارÙØ® الإصدار</translation>
<translation id="1549470594296187301">â€Ùجب تمكÙÙ† JavaScript لاستخدام هذه المÙزة.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">تهÙئة الشبكة غÙر صالحة ÙˆÙتعذر استÙرادها.</translation>
<translation id="1644574205037202324">السجل</translation>
<translation id="1645368109819982629">بروتوكول غÙر معتمد</translation>
-<translation id="1655462015569774233">{1,plural, =1{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه أمس. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ ثم تحدÙØ« هذه الصÙحة.}zero{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه منذ # Ùوم. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ ثم تحدÙØ« هذه الصÙحة.}two{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه منذ ÙومÙÙ† (#). ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ ثم تحدÙØ« هذه الصÙحة.}few{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه منذ # Ø£Ùام. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ ثم تحدÙØ« هذه الصÙحة.}many{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه منذ # Ùومًا. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ ثم تحدÙØ« هذه الصÙحة.}other{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه منذ # Ùوم. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ ثم تحدÙØ« هذه الصÙحة.}}</translation>
<translation id="1676269943528358898">â€Ùستخدم <ph name="SITE" /> التشÙÙر عادة لحماÙØ© معلوماتك. عندما حاول Google Chrome الاتصال بموقع <ph name="SITE" /> هذه المرة، أرجÙع موقع الوÙب بÙانات اعتماد غÙر عادÙØ© وغÙر صحÙحة. وقد Ùحدث هذا عندما Ùحاول أحد المهاجمÙÙ† التظاهر بأنه موقع <ph name="SITE" />ØŒ أو إذا قاطعت شاشة تسجÙÙ„ دخول Wi-Fi الاتصال. ولكن لا تزال معلوماتك آمنة نظرًا لأن Google Chrome أوقÙ٠الاتصال قبل تبادل أ٠بÙانات.</translation>
<translation id="168841957122794586">تحتو٠شهادة الخادم على Ù…Ùتاح تشÙÙر ضعÙÙ.</translation>
<translation id="1701955595840307032">الحصول على المحتوى المقترح</translation>
-<translation id="1706954506755087368">{1,plural, =1{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه من الغد. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك.}zero{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه خلال # Ùوم Ù٠المستقبل. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك.}two{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه خلال ÙومÙÙ† (#) Ù٠المستقبل. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك.}few{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه خلال # Ø£Ùام Ù٠المستقبل. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك.}many{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه خلال # Ùومًا Ù٠المستقبل. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك.}other{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه خلال # Ùوم Ù٠المستقبل. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك.}}</translation>
<translation id="1710259589646384581">نظام التشغÙÙ„</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">جرّب الاتصال بمشر٠النظام.</translation>
<translation id="17513872634828108">علامات التبوÙب المÙتوحة</translation>
<translation id="1753706481035618306">رقم الصÙحة</translation>
-<translation id="1761412452051366565">â€Ù„لحصول على محتوى مخصص اقترحته GoogleØŒ شغّل المزامنة.</translation>
-<translation id="1763864636252898013">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان غÙر موثوقة من خلال نظام تشغÙÙ„ جهازك. وربما Ùكون السبب Ù٠ذلك خطأ Ù٠التكوÙÙ† أو مهاجمًا Ùعترض الاتصال.</translation>
<translation id="1768211456781949159">â€<ph name="BEGIN_LINK" />تجربة تشغÙÙ„ بÙانات التشخÙص لشبكة Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">الرجاء تحدÙØ« عبارة مرور المزامنة.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">ستظهر هنا الإشارات المرجعÙØ© الت٠زرتها مؤخرًا.</translation>
<translation id="1821930232296380041">طلب غÙر صالح، أو معلمات طلب غÙر صالحة</translation>
<translation id="1838667051080421715">أنت تعرض مصدر صÙحة ÙˆÙب.</translation>
<translation id="1871208020102129563">â€ØªÙ… تعÙÙÙ† الخادم الوكÙÙ„ لاستخدام الخوادم الوكÙلة الثابتة ولÙس عنوان URL لنص برمج٠pac.</translation>
<translation id="1883255238294161206">تصغÙر القائمة</translation>
<translation id="1898423065542865115">التصÙÙØ©</translation>
-<translation id="1911837502049945214">لم Ùقبل <ph name="HOST_NAME" /> شهادة تسجÙÙ„ الدخول أو ربما انتهت صلاحÙØ© شهادة تسجÙÙ„ الدخول.</translation>
<translation id="194030505837763158">الانتقال إلى <ph name="LINK" /></translation>
<translation id="1962204205936693436">إشارات <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">خطأ أثناء التسلسل</translation>
<translation id="1974060860693918893">إعدادات متقدمة</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{وتطبÙÙ‚ آخر}zero{Ùˆ# تطبÙÙ‚ آخر}two{وتطبÙقان (#) آخران}few{Ùˆ# تطبÙقات أخرى}many{Ùˆ# تطبÙقًا آخر}other{Ùˆ# تطبÙÙ‚ آخر}}</translation>
<translation id="2025186561304664664">تم تعÙÙÙ† الخادم الوكÙÙ„ على التهÙئة التلقائÙØ©.</translation>
<translation id="2030481566774242610">هل تقصد <ph name="LINK" />؟</translation>
<translation id="2031925387125903299">ظهرت لك هذه الرسالة نظرًا لحاجة والدÙÙƒ للمواÙقة على المواقع الجدÙدة عند زÙارتك الأولى.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />التحقق من الخادم الوكÙÙ„ والجدار النارÙ<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">الرمز البرÙدÙ</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{اقتراح واحد}zero{# اقتراح}two{اقتراحان (#)}few{# اقتراحات}many{# اقتراحًا}other{# اقتراح}}</translation>
<translation id="2065985942032347596">Ùجب إدخال اسم المستخدم وكلمة المرور</translation>
<translation id="2079545284768500474">تراجع</translation>
<translation id="20817612488360358">تم تعÙÙÙ† إعدادات الخادم الوكÙÙ„ Ù„Ùتم استخدامها وتم Ø£Ùضًا تحدÙد تهÙئة صرÙحة للخادم الوكÙÙ„.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">تعدÙÙ„ الإشارة</translation>
<translation id="2166049586286450108">الوصول الكامل للمشرÙ</translation>
<translation id="2166378884831602661">لا Ùمكن لموقع الوÙب هذا توÙÙر اتصال آمن</translation>
-<translation id="2171101176734966184">لقد حاولت الوصول إلى <ph name="DOMAIN" />ØŒ ولكن قدّÙÙ… الخادم شهادة موقّعة باستخدام خوارزمÙØ© توقÙع ضعÙÙØ©ØŒ مما Ùعن٠أن بÙانات اعتماد الأمان الت٠قدمها الخادم من المحتمل أنه تم تزÙÙÙها، وأن الخادم قد لا Ùكون هو الخادم الذ٠تتوقعه (قد تكون على اتصال بأحد المهاجمÙÙ†).</translation>
<translation id="2181821976797666341">السÙاسات</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{عنوان واحد}zero{# عنوان}two{عنوانان (#)}few{# عناوÙÙ†}many{# عنوانًا}other{# عنوان}}</translation>
<translation id="2212735316055980242">تعذر العثور على السÙاسة</translation>
<translation id="2213606439339815911">جار٠جلب الإدخالات...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> غÙر متوÙّر</translation>
<translation id="2230458221926704099">إصلاح الاتصال باستخدام <ph name="BEGIN_LINK" />تطبÙÙ‚ بÙانات التشخÙص<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">إرسال الآن</translation>
<translation id="225207911366869382">تم تجاهل القÙمة لهذه السÙاسة.</translation>
<translation id="2262243747453050782">â€Ø®Ø·Ø£ HTTP</translation>
<translation id="2282872951544483773">التجارب غÙر المتاحة</translation>
<translation id="2292556288342944218">تم حظر دخولك إلى الإنترنت</translation>
<translation id="229702904922032456">انتهت صلاحÙØ© الشهادة الأساسÙØ© أو المتوسطة.</translation>
<translation id="230155334948463882">بطاقة جدÙدة؟</translation>
+<translation id="2305919008529760154">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› قد Ùكون تم إصدار شهادة أمانه عن طرÙÙ‚ الاحتÙال. وربما Ùكون سبب ذلك خطأً Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">ÙتطلّÙب <ph name="DOMAIN" /> اسم مستخدم وكلمة مرور.</translation>
+<translation id="2318774815570432836">â€Ù„ا Ùمكنك زÙارة <ph name="SITE" /> الآن نظرًا لأن موقع الوÙب Ùستخدم HSTS. أخطاء الشبكة والهجمات علÙها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصÙحة لاحقًا على الأرجح. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">تم تجاهل الإشارة المرجعÙØ© غÙر الصالحة Ù٠الÙهرس <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">الإشارات الأخرى</translation>
<translation id="2359808026110333948">المتابعة</translation>
<translation id="2365563543831475020">لم Ùتم تحمÙÙ„ تقرÙر الأعطال الذ٠تم الحصول علÙÙ‡ ÙÙ <ph name="CRASH_TIME" /></translation>
<translation id="2367567093518048410">المستوى</translation>
+<translation id="2371153335857947666">{1,plural, =1{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه أمس. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ Ø«ÙÙ… تحدÙØ« هذه الصÙحة. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}zero{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه منذ # Ùوم. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ Ø«ÙÙ… تحدÙØ« هذه الصÙحة. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}two{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه منذ ÙومÙÙ† (#). ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ Ø«ÙÙ… تحدÙØ« هذه الصÙحة. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}few{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه منذ # Ø£Ùام. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ Ø«ÙÙ… تحدÙØ« هذه الصÙحة. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}many{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه منذ # Ùومًا. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ Ø«ÙÙ… تحدÙØ« هذه الصÙحة. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}other{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› انتهت صلاحÙØ© شهادة أمانه منذ # Ùوم. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_DATE" />. هل Ùبدو ذلك صحÙحًا؟ إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ Ø«ÙÙ… تحدÙØ« هذه الصÙحة. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">لا توجد بدائل لعناصر واجهة المستخدم</translation>
<translation id="2384307209577226199">السÙاسة اÙتراضÙØ© Ù٠المؤسسة ÙˆÙمكن إلغاؤها</translation>
-<translation id="238526402387145295">â€Ù„ا Ùمكنك زÙارة <ph name="SITE" /> الآن لأن موقع الوÙب <ph name="BEGIN_LINK" />Ùستخدم HSTS<ph name="END_LINK" />. أخطاء الشبكة والهجمات علÙها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصÙحة لاحقًا على الأرجح.</translation>
<translation id="2386255080630008482">تم إبطال شهادة الخادم.</translation>
<translation id="2392959068659972793">عرض السÙاسات الت٠لم Ùتم تعÙÙÙ† Ù‚ÙÙ… لها</translation>
<translation id="2396249848217231973">تراجع عن الحذ&amp;Ù</translation>
-<translation id="2413528052993050574">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان ربما تم إلغاء صلاحÙتها. وربما Ùكون السبب Ù٠ذلك خطأ Ù٠التكوÙÙ† أو مهاجمًا Ùعترض اتصالك.</translation>
<translation id="2455981314101692989">عطلت صÙحة الوÙب هذه الملء التلقائ٠لهذا النموذج.</translation>
+<translation id="2463739503403862330">ملء</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />تشغÙÙ„ بÙانات تشخÙص الشبكة<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">â€Ø¹Ù†ÙˆØ§Ù† URL للبحث غÙر صالح.</translation>
<translation id="2491120439723279231">تحتو٠شهادة الخادم على أخطاء.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">إرسال</translation>
<translation id="2674170444375937751">هل ترÙد بالتأكÙد حذ٠هذه الصÙحات من السجل؟</translation>
<translation id="2677748264148917807">الخروج</translation>
+<translation id="269990154133806163">قدم الخادم شهادة لم Ùتم الكش٠عنها علنًا باستخدام سÙاسة شهادة الشÙاÙÙØ©. وهذا ضرور٠لبعض الشهادات، لضمان أنها جدÙرة بالثقة ومحمÙØ© من المهاجمÙÙ†. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">القÙمة لا تطابق التنسÙÙ‚.</translation>
<translation id="2704951214193499422">â€Ù„Ù… Ùتمكن Chromium من التأكد من بطاقتك Ù٠الوقت الحالÙ. ÙÙرجى إعادة المحاولة Ù٠وقت لاحق.</translation>
<translation id="2705137772291741111">تعذر قراءة النسخة المحÙوظة (المخزنة Ù٠ذاكرة التخزÙÙ† المؤقت) لموقع الوÙب هذا.</translation>
<translation id="2709516037105925701">الملء التلقائÙ</translation>
+<translation id="2712118517637785082">لقد حاولت الوصول إلى <ph name="DOMAIN" />ØŒ ولكن جهة إصدار الشهادة الت٠قدمها الخادم قد أبطلت الشهادة. وهذا Ùعن٠أن بÙانات اعتماد الأمان الت٠قدمها الخادم Ùجب عدم الوثوق بها مطلقًا. Ùقد تكون على اتصال بأحد المهاجمÙÙ†. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">طلب إذن</translation>
<translation id="2721148159707890343">تم إرسال الطلب بنجاح</translation>
<translation id="2728127805433021124">شهادة الخادم موقّعة باستخدام خوارزمÙØ© توقÙع ضعÙÙØ©.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">شرÙØ· العناوÙÙ† والبحث</translation>
<translation id="2826760142808435982">تم تشÙÙر الاتصال ومصادقته باستخدام <ph name="CIPHER" />ØŒ ÙˆÙستخدم <ph name="KX" /> كآلÙØ© التبادل الرئÙسÙØ©.</translation>
<translation id="2835170189407361413">محو النموذج</translation>
-<translation id="2837049386027881519">â€Ùجب إعادة محاولة إجراء الاتصال باستخدام إصدار أقدم من بروتوكول TLS أو طبقة المقابس الآمنة. Ùعن٠هذا عادة أن الخادم Ùستخدم برنامجًا قدÙمًا جدًا وقد تكون به مشكلات أمان أخرى.</translation>
<translation id="284702764277384724">Ùبدو أن شهادة الخادم على <ph name="HOST_NAME" /> مزÙÙØ©.</translation>
<translation id="2889159643044928134">إلغاء إعادة التحمÙÙ„</translation>
-<translation id="2896499918916051536">هذا المكون الإضاÙ٠غÙر معتمد.</translation>
+<translation id="2900469785430194048">â€Ù†Ùدت ذاكرة Google Chrome أثناء محاولة عرض صÙحة الوÙب هذه.</translation>
<translation id="2909946352844186028">تم اكتشا٠حدوث تغÙÙر Ù٠الشبكة.</translation>
-<translation id="2915500479781995473">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان منتهÙØ© الصلاحÙØ©. وربما Ùكون سبب ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض الاتصال. تم تعÙÙÙ† ساعة الكمبÙوتر حالÙًا على <ph name="CURRENT_TIME" />. هل تبدو الساعة صحÙحة؟ إذا لم تكن كذلك، Ùجب علÙÙƒ تصحÙØ­ ساعة النظام، ثم تحدÙØ« هذه الصÙحة.</translation>
<translation id="2922350208395188000">لا Ùمكن التحقق من شهادة الخادم.</translation>
-<translation id="2941952326391522266">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان من <ph name="DOMAIN2" />. وربما سبب ذلك خطأ Ù٠التكوÙÙ† أو مهاجمًا Ùعترض اتصالك.</translation>
<translation id="2948083400971632585">Ùمكنك تعطÙÙ„ أ٠خوادم وكÙلة تمت تهÙئتها لاتصال من صÙحة الإعدادات.</translation>
<translation id="2955913368246107853">إغلاق شرÙØ· البحث</translation>
<translation id="2958431318199492670">â€Ù„ا تتواÙÙ‚ تهÙئة الشبكة مع معÙار ONC. قد لا Ùتم استÙراد بعض أجزاء التهÙئة.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">نوع السÙاسة غÙر صحÙØ­</translation>
<translation id="3032412215588512954">هل ترÙد إعادة تحمÙÙ„ هذا الموقع؟</translation>
<translation id="3037605927509011580">عذرًا!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{عنصر واحد على الأقل على الأجهزة المتزامنة}=1{عنصر واحد (1) (وأكثر على الأجهزة المتزامنة)}two{عنصران (#) (وأكثر على الأجهزة المتزامنة)}few{# عناصر (وأكثر على الأجهزة المتزامنة)}many{# عنصرًا (وأكثر على الأجهزة المتزامنة)}other{# عنصر (وأكثر على الأجهزة المتزامنة)}}</translation>
<translation id="3041612393474885105">معلومات الشهادة</translation>
<translation id="3063697135517575841">â€Ù„Ù… Ùتمكن Chrome من التأكد من بطاقتك Ù٠الوقت الحالÙ. ÙÙرجى إعادة المحاولة Ù٠وقت لاحق.</translation>
<translation id="3093245981617870298">أنت غÙر متصل.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">الأحدث</translation>
<translation id="3207960819495026254">محدد بعلامة متابعة القراءة</translation>
-<translation id="3225919329040284222">قدم الخادم شهادة لا تتطابق مع التوقعات المضمّنة. تم تضمÙÙ† هذه التوقعات للحصول على مواقع ÙˆÙب موثوقة وآمنة جدًا لتوÙÙر الحماÙØ© لك.</translation>
<translation id="3226128629678568754">اضغط على زر إعادة التحمÙÙ„ لإعادة إرسال البÙانات المطلوبة لتحمÙÙ„ الصÙحة.</translation>
<translation id="3228969707346345236">أخÙقت الترجمة لأن الصÙحة باللغة <ph name="LANGUAGE" /> Ùعلاً.</translation>
<translation id="323107829343500871">â€Ø£Ø¯Ø®Ù„ رمز التحقق من البطاقة (CVC) لـ <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">وضع إشارة على هذه الصÙحة</translation>
<translation id="3270847123878663523">تراجع عن إعادة الت&amp;رتÙب</translation>
<translation id="3286538390144397061">إعادة التشغÙÙ„ الآن</translation>
+<translation id="3303855915957856445">لم Ùتم العثور على أ٠نتائج بحث</translation>
<translation id="3305707030755673451">تم تشÙÙر بÙاناتك باستخدام عبارة مرور المزامنة ÙÙ <ph name="TIME" />. أدخلها لبدء المزامنة.</translation>
<translation id="333371639341676808">منع هذه الصÙحة من إنشاء مربّعات حوار إضاÙÙØ©.</translation>
+<translation id="3338095232262050444">آمن</translation>
<translation id="3340978935015468852">الإعدادات</translation>
<translation id="3345135638360864351">تعذر إرسال طلبك للوصول إلى هذا الموقع إلى <ph name="NAME" />. ÙÙرجى إعادة المحاولة مرة أخرى.</translation>
<translation id="3355823806454867987">تغÙÙر إعدادات الخادم الوكÙÙ„...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">الÙاصل الزمن٠للجلب:</translation>
<translation id="3462200631372590220">الإخÙاء (Ø®Ùار متقدم)</translation>
<translation id="3479539252931486093">ألم تتوقّÙع هذا؟ <ph name="BEGIN_LINK" />أطلÙعنا على الأمر<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Ù„Ùس الآن</translation>
<translation id="348000606199325318">معرّ٠التعطّÙÙ„ <ph name="CRASH_LOCAL_ID" /> (معرّ٠الخادم: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">لم نتمكن من الوصول إلى أحد والدÙÙƒ Ù٠الوقت الحالÙ. ÙÙرجى إعادة المحاولة مرة أخرى.</translation>
<translation id="3527085408025491307">المجلد</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">استخدام كلمة مرور لـ:</translation>
<translation id="3549644494707163724">تشÙÙر جمÙع البÙانات المتزامنة باستخدام عبارة مرور المزامنة</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> أخرى...</translation>
+<translation id="3555561725129903880">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />ØŒ بل إن شهادة أمانه من <ph name="DOMAIN2" />. وربما Ùكون سبب ذلك خطأً Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">اتصالك Ù„Ùس خاصًا</translation>
<translation id="3583757800736429874">إ&amp;عادة النقل</translation>
<translation id="3586931643579894722">إخÙاء التÙاصÙÙ„</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">عرض القÙمة</translation>
<translation id="3630155396527302611">إذا تم بالÙعل إدراج صÙحة الوÙب كبرنامج مسموح له بالدخول إلى الشبكة، Ùجرّب
إزالتها من القائمة وإضاÙتها مرةً أخرى.</translation>
+<translation id="3638794133396384728">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إن شهادة أمانه انتهت صلاحÙتها. وربما Ùكون سبب ذلك خطأً Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. تم تعÙÙÙ† ساعة الكمبÙوتر لدÙÙƒ حالÙًا على <ph name="CURRENT_TIME" />. هل Ùبدو ذلك صحÙحًا؟. إذا لم Ùكن الأمر كذلك، Ùجب تصحÙØ­ ساعة النظام لدÙÙƒ ثم تحدÙØ« هذه الصÙحة. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">ربما تتغÙر أو تتعطل أو تختÙ٠هذه المÙزات التجرÙبÙØ© Ù٠أ٠وقت. ولا نعط٠أ٠ضمانات Ø­Ùال ما Ùمكن حدوثه إذا شغلت إحدى هذه المÙزات التجرÙبÙØ©ØŒ وقد Ùتعطل المتصÙØ­ بشكل Ù…Ùاجئ. وبشكل جدÙØŒ قد Ùحذ٠المتصÙØ­ جمÙع بÙاناتك، أو قد تتعرض خصوصÙتك وأمانك للاختراق بطرق غÙر متوقعة. Ø£Ù Ù…Ùزات تجرÙبÙØ© تمكّنها سÙتم تمكÙنها لجمÙع مستخدم٠هذا المتصÙØ­. الرجاء المتابعة بحذر.</translation>
<translation id="3650584904733503804">تم التحقق بنجاح</translation>
<translation id="3655670868607891010">إذا كنت تشاهد هذا بكثرة، Ùجرّب <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">التعدÙÙ„</translation>
+<translation id="3678029195006412963">تعذر توقÙع الطلب</translation>
<translation id="3681007416295224113">معلومات الشهادة</translation>
<translation id="3693415264595406141">كلمة المرور:</translation>
+<translation id="3696411085566228381">بدون</translation>
<translation id="3700528541715530410">عÙوًا، Ù„Ùس لدÙÙƒ إذن بالدخول إلى هذه الصÙحة.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">تحمÙÙ„...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">â€ØªØ´ØºÙÙ„ بÙانات شبكة الجوّال أو Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />التحقق من تهÙئة الخادم الوكÙÙ„ والجدار النار٠ونظام أسماء النطاقات<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">الرابط الذ٠نسخته</translation>
-<translation id="3744899669254331632">â€Ù„ا Ùمكنك زÙارة <ph name="SITE" /> Ù٠الوقت الحال٠لأن الموقع أرسل اعتمادات مختلطة Ø­ÙØ« لا ÙستطÙع Chromium المعالجة. أخطاء الشبكة وهجماتها عادةً ما تكون مؤقتة، لذلك من المحتمل أن تعمل هذه الصÙحة Ù٠وقت لاحق.</translation>
<translation id="375403751935624634">أخÙقت الترجمة بسبب حدوث خطأ Ù٠الخادم.</translation>
<translation id="3759461132968374835">Ù„Ùس لدÙÙƒ أ٠أعطال تم الإبلاغ عنها مؤخرًا. الأعطال الت٠حدثت عندما تم تعطÙÙ„ الإبلاغ عن الأعطال لن تظهر هنا.</translation>
<translation id="3788090790273268753">â€ØªÙ†ØªÙ‡Ù صلاحÙØ© شهادة هذا الموقع ÙÙ 2016ØŒ وتتضمن سلسلة الشهادات شهادة موقعة باستخدام SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">معر٠جهاز متضارب</translation>
<translation id="3885155851504623709">دائرة</translation>
<translation id="3901925938762663762">انتهت صلاحÙØ© البطاقة</translation>
+<translation id="3910267023907260648">لقد حاولت الوصول إلى <ph name="DOMAIN" />ØŒ ولكن قدّÙÙ… الخادم شهادة موقّعة باستخدام خوارزمÙØ© توقÙع ضعÙÙØ©ØŒ مما Ùعن٠أن بÙانات اعتماد الأمان الت٠قدمها الخادم من المحتمل أنه تم تزÙÙÙها، وأن الخادم قد لا Ùكون هو الخادم الذ٠تتوقعه (قد تكون على اتصال بأحد المهاجمÙÙ†). <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه من الغد. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}zero{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه خلال # Ùوم Ù٠المستقبل. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}two{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه خلال ÙومÙÙ† (#) Ù٠المستقبل. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}few{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه خلال # Ø£Ùام Ù٠المستقبل. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}many{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه خلال # Ùومًا Ù٠المستقبل. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}other{هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› من المÙترض أن تبدأ شهادة أمانه خلال # Ùوم Ù٠المستقبل. ربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">â€Ø¥Ø®Ùاق تحمÙÙ„ مستند PDF</translation>
<translation id="3963721102035795474">وضع القارئ</translation>
+<translation id="397105322502079400">جار٠الحساب...</translation>
<translation id="3973234410852337861">تم حظر <ph name="HOST_NAME" /></translation>
+<translation id="40103911065039147">{URL_count,plural, =1{صÙحة ÙˆÙب واحدة مجاورة}zero{# صÙحات ÙˆÙب مجاورة}two{صÙحتا ÙˆÙب (#) مجاورتان}few{# صÙحات ÙˆÙب مجاورة}many{# صÙحة ÙˆÙب مجاورة}other{# صÙحة ÙˆÙب مجاورة}}</translation>
<translation id="4021036232240155012">â€ÙÙعد نظام أسماء النطاقات (DNS) هو خدمة الشبكة الت٠تترجم اسم موقع ÙˆÙب إلى عنوانه على شبكة الإنترنت.</translation>
<translation id="4030383055268325496">تراجع عن الإ&amp;ضاÙØ©</translation>
-<translation id="4032534284272647190">تم رÙض الدخول إلى<ph name="URL" />.</translation>
<translation id="404928562651467259">تحذÙر</translation>
<translation id="4058922952496707368">المÙتاح "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">لا Ùدعم كل من العمÙÙ„ والخادم مجموعة تشÙÙر أو إصدار بروتوكول طبقة المقابس الآمنة الشائع.</translation>
<translation id="4079302484614802869">â€ØªÙ… تعÙÙÙ† تهÙئة الخادم الوكÙÙ„ لاستخدام عنوان URL نص برمج٠â€.pac ولÙس الخوادم الوكÙلة الثابتة.</translation>
<translation id="4103249731201008433">الرقم التسلسل٠للجهاز غÙر صالح</translation>
<translation id="4103763322291513355">â€Ø§Ù†ØªÙ‚Ù„ إلى &lt;strong&gt;chrome://policy&lt;/strong&gt; لمشاهدة قائمة بعناوÙÙ† URL المضاÙØ© إلى القائمة السوداء والسÙاسات الأخرى الت٠Ùرضها مشر٠النظام.</translation>
+<translation id="4110615724604346410">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />ØŒ بل إن شهادة أمانه تحتو٠على أخطاء. وربما Ùكون سبب ذلك خطأً Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">نطاق السÙاسة غÙر متواÙÙ‚.</translation>
+<translation id="4118212371799607889">â€Ù‡Ø°Ø§ الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />ØŒ بل إن شهادة أمانه غÙر موثوقة من Ù‚Ùبل Chromium. وربما Ùكون السبب Ù٠ذلك خطأ Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{عنصر واحد آخر}zero{# عنصر آخر}two{عنصران آخران (#)}few{# عناصر أخرى}many{# عنصرًا آخر}other{# عنصر آخر}}</translation>
<translation id="4130226655945681476">التحقق من كابلات الشبكة، والمودم، وجهاز التوجÙÙ‡</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">â€Ù‡Ù„ ترÙد من Chromium Ø­Ùظ هذه البطاقة؟</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">معطل</translation>
<translation id="4196861286325780578">إ&amp;عادة النقل</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />التحقق من عملÙات تهÙئة الجدار النار٠وبرامج مكاÙحة الÙÙروسات<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{لا Ø´ÙØ¡}=1{تطبÙÙ‚ واحد ($1)}=2{تطبÙقان (2) ($1ØŒ $2)}few{# تطبÙقات ($1ØŒ $2ØŒ $3)}many{# تطبÙقًا ($1ØŒ $2ØŒ $3)}other{# تطبÙÙ‚ ($1ØŒ $2ØŒ $3)}}</translation>
<translation id="4220128509585149162">الأعطال</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />تجربة تشغÙÙ„ بÙانات تشخÙص الشبكة<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">لا</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(اسم المستخدم غÙر موجود)</translation>
<translation id="4300246636397505754">اقتراحات الآباء</translation>
<translation id="4304224509867189079">تسجÙÙ„ الدخول</translation>
+<translation id="432290197980158659">قدم الخادم شهادة لا تتطابق مع التوقعات المضمّنة. تم تضمÙÙ† هذه التوقعات للحصول على مواقع ÙˆÙب موثوقة وآمنة جدًا لتوÙÙر الحماÙØ© لك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">أخÙÙ‚ العثور على المقالة</translation>
+<translation id="4331708818696583467">غÙر آمن</translation>
<translation id="4372948949327679948">القÙمة <ph name="VALUE_TYPE" /> المتوقعة.</translation>
-<translation id="4377125064752653719">لقد حاولت الوصول إلى <ph name="DOMAIN" />ØŒ ولكن جهة إصدار الشهادة الت٠قدمها الخادم قد أبطلت الشهادة. وهذا Ùعن٠أن بÙانات اعتماد الأمان الت٠قدمها الخادم Ùجب عدم الوثوق بها مطلقًا. Ùقد تكون على اتصال بأحد المهاجمÙÙ†.</translation>
<translation id="4381091992796011497">اسم المستخدم:</translation>
<translation id="4394049700291259645">تعطÙÙ„</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> إلى <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">نتائج البحث</translation>
-<translation id="4424024547088906515">â€Ù‡Ø°Ø§ الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان غÙر موثوقة من قبل Chrome. وربما Ùكون السبب Ù٠ذلك خطأ Ù٠التكوÙÙ† أو مهاجمًا Ùعترض الاتصال.</translation>
+<translation id="4432688616882109544">لم Ùقبل <ph name="HOST_NAME" /> شهادة تسجÙÙ„ الدخول أو من المحتمل ألا Ùكون قد تم تقدÙÙ… واحدة.</translation>
<translation id="443673843213245140">تم تعطÙÙ„ استخدام الخادم الوكÙÙ„ ولكن تم تحدÙد تهÙئة صرÙحة للخادم الوكÙÙ„.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">â€Ø¸Ù‡Ø±Øª هذه الرسالة لأنه تم تمكÙÙ† Google SafeSites.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">التÙاصÙÙ„</translation>
<translation id="4558551763791394412">جرّب تعطÙÙ„ الإضاÙات.</translation>
<translation id="4587425331216688090">â€Ù‡Ù„ ترÙد إزالة العنوان من ChromeØŸ</translation>
+<translation id="4589078953350245614">لقد حاولت الوصول إلى <ph name="DOMAIN" />ØŒ ولكن الخادم قدم شهادة غÙر صالحة. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Ùتم ترمÙز اتصالك بالنطاق <ph name="DOMAIN" /> باستخدام مجموعة تشÙÙر حدÙثة.</translation>
<translation id="4594403342090139922">تراجع عن الحذ&amp;Ù</translation>
+<translation id="4627442949885028695">متابعة من جهاز آخر</translation>
<translation id="4668929960204016307">،</translation>
<translation id="4670097147947922288">أنت تعرض حالÙًا صÙحة إضاÙØ©.</translation>
-<translation id="467662567472608290">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان تحتو٠على أخطاء. وربما Ùكون السبب Ù٠ذلك خطأ Ù٠التكوÙÙ† أو مهاجمًا Ùعترض اتصالك.</translation>
-<translation id="4697214168136963651">تم حظر <ph name="URL" /></translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" />†<ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">تم قطع اتصالك</translation>
<translation id="4722547256916164131">â€<ph name="BEGIN_LINK" />تشغÙÙ„ بÙانات تشخÙص شبكة Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">النظام الأساسÙ</translation>
<translation id="4744603770635761495">المسار التنÙÙØ°Ù</translation>
<translation id="4756388243121344051">ال&amp;سجل</translation>
+<translation id="4759238208242260848">التنزÙلات</translation>
<translation id="4764776831041365478">قد تكون صÙحة الوÙب على العنوان <ph name="URL" /> غÙر متاحة مؤقتًا أو قد Ùكون تم نقلها نهائÙًا إلى عنوان ÙˆÙب جدÙد.</translation>
<translation id="4771973620359291008">حدث خطأ غÙر محدّد.</translation>
<translation id="4782449893814226250">لقد سألت والدÙÙƒ ما إذا كان مناسبًا لك زÙارة هذه الصÙحة.</translation>
<translation id="4800132727771399293">â€ØªØ­Ù‚Ù‚ من تارÙØ® انتهاء الصلاحÙØ© ورمز التحقق من البطاقة (CVC) وأعد المحاولة مرة أخرى.</translation>
-<translation id="4807049035289105102">â€Ù„ا Ùمكنك زÙارة <ph name="SITE" /> الآن نظرًا لأن موقع الوÙب أرسل بÙانات اعتماد مختلطة Ùتعذر على Google Chrome معالجتها. وعادةً ما تكون أخطاء الشبكة والهجمات علÙها مؤقتة؛ لذا ستعمل هذه الصÙحة لاحقًا على الأرجح.</translation>
<translation id="4813512666221746211">حدث خطأ Ù٠الشبكة</translation>
<translation id="4816492930507672669">احتواء ضمن الصÙحة</translation>
<translation id="4850886885716139402">عرض</translation>
<translation id="4880827082731008257">سجلّ البحث</translation>
+<translation id="4884656795097055129">ستظهر المزÙد من المقالات Ù٠الوقت المناسب.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />، <ph name="TYPE_2" />، <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{وصÙحة ÙˆÙب واحدة إضاÙÙØ©}zero{Ùˆ# صÙحة ÙˆÙب إضاÙÙØ©}two{وصÙحتا ÙˆÙب (#) إضاÙÙتان}few{Ùˆ# صÙحات ÙˆÙب إضاÙÙØ©}many{Ùˆ# صÙحة ÙˆÙب إضاÙÙØ©}other{Ùˆ# صÙحة ÙˆÙب إضاÙÙØ©}}</translation>
<translation id="4923417429809017348">تمت ترجمة هذه الصÙحة من لغة غÙر معروÙØ© إلى اللغة <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Ùجب تحدÙدها.</translation>
<translation id="4930497775425430760">ظهرت لك هذه الرسالة نظرًا لحاجة والدÙÙƒ للمواÙقة على المواقع الجدÙدة عند زÙارتك الأولى.</translation>
<translation id="495170559598752135">إجراءات</translation>
<translation id="4958444002117714549">توسÙع القائمة</translation>
+<translation id="4962322354953122629">â€Ù‡Ø°Ø§ الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إن شهادة أمانه غÙر موثوقة من Ù‚Ùبل Chrome. وربما Ùكون السبب Ù٠ذلك خطأً Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">هل ترÙد الترجمة من <ph name="ORIGINAL_LANGUAGE" /> إلى <ph name="TARGET_LANGUAGE" />ØŸ</translation>
+<translation id="4989809363548539747">هذا المكوّÙÙ† الإضاÙ٠غÙر مدعوم</translation>
<translation id="5002932099480077015">â€Ø¥Ø°Ø§ تم التمكÙن، سÙخزن Chrome نسخة من بطاقتك على هذا الجهاز لملء النموذج بشكل أسرع.</translation>
<translation id="5019198164206649151">التخزÙÙ† المساعد Ù٠حالة سÙئة</translation>
<translation id="5023310440958281426">التحقق من سÙاسات المشرÙ</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">â€Ù…علومات عن الترجمة من Google</translation>
<translation id="5040262127954254034">الخصوصÙØ©</translation>
<translation id="5045550434625856497">كلمة مرور غÙر صحÙحة</translation>
+<translation id="5056549851600133418">مقالات من أجلك</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />التحقق من عنوان الخادم الوكÙÙ„<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">شهادة الخادم Ù„Ùست صالحة حالÙًا.</translation>
<translation id="5089810972385038852">بلد/دولة</translation>
-<translation id="5094747076828555589">â€Ù‡Ø°Ø§ الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان غÙر موثوقة من قبل Chromium. وربما Ùكون السبب Ù٠ذلك خطأ Ù٠التكوÙÙ† أو مهاجمًا Ùعترض الاتصال.</translation>
<translation id="5095208057601539847">الإقلÙÙ…</translation>
<translation id="5115563688576182185">(64 بت)</translation>
-<translation id="5122371513570456792">تم العثور على <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> لـ "<ph name="SEARCH_STRING" />".</translation>
<translation id="5141240743006678641">â€ØªØ´ÙÙر كلمات المرور المتزامنة باستخدام بÙانات اعتماد Google</translation>
<translation id="5145883236150621069">Ùوجد رمز خطأ Ù٠استجابة السÙاسة</translation>
<translation id="5171045022955879922">â€Ø§Ù„بحث أو إدخال عنوان URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">شرÙØ· الإشارات</translation>
<translation id="5199729219167945352">التجارب</translation>
<translation id="5251803541071282808">السحاب</translation>
+<translation id="5277279256032773186">â€Ù‡Ù„ تستخدم Chrome Ù٠العمل؟ Ùمكن للأنشطة التجارÙØ© إدارة إعدادات Chrome لموظÙÙها. تعرّÙ٠على المزÙد</translation>
<translation id="5299298092464848405">خطأ Ù٠تحلÙÙ„ السÙاسة</translation>
<translation id="5300589172476337783">عرض</translation>
<translation id="5308689395849655368">Ù…Ùزة الإبلاغ عن الأعطال معطلة.</translation>
<translation id="5317780077021120954">Ø­Ùظ</translation>
<translation id="5327248766486351172">الاسم</translation>
+<translation id="5359637492792381994">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />ØŒ بل إن شهادة أمانه غÙر صالحة حالÙًا. وربما Ùكون السبب Ù٠ذلك خطأً Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">أخÙÙ‚ تخزÙÙ† إعدادات السÙاسة</translation>
-<translation id="540969355065856584">لم Ùتمكن هذا الخادم من إثبات أنه <ph name="DOMAIN" />Ø› بل إن شهادة الأمان الخاصة به غÙر صالحة حالÙًا. وربما Ùكون السبب Ù٠ذلك وجود خطأ Ù٠التكوÙÙ† أو اعترض أحد المهاجمÙÙ† للاتصال.</translation>
<translation id="5421136146218899937">محو بÙانات التصÙØ­...</translation>
<translation id="5430298929874300616">إزالة إشارة مرجعÙØ©</translation>
<translation id="5431657950005405462">لم Ùتم العثور على ملÙÙƒ</translation>
<translation id="5435775191620395718">عرض السجل من هذا الجهاز. <ph name="BEGIN_LINK" />مزÙد من المعلومات<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">اقتراحات المحتوى المخصص معطلة حالÙًا، لأن بÙاناتك المتزامنة محمÙØ© بعبارة مرور مخصصة.</translation>
<translation id="5439770059721715174">حدث خطأ Ù٠مصادقة المخطط على "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">لا Ùمكن العثور على صÙحة <ph name="HOST_NAME" /> هذه.</translation>
<translation id="5455374756549232013">الطابع الزمن٠للسÙاسة سÙئ</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">هل ترÙد الخروج من هذا الموقع؟</translation>
<translation id="5629630648637658800">أخÙÙ‚ تحمÙÙ„ إعدادات السÙاسة</translation>
<translation id="5631439013527180824">الرمز الممÙز لإدارة الجهاز غÙر صالح</translation>
-<translation id="5650551054760837876">لم Ùتمّ العثور على أ٠نتائج بحث.</translation>
<translation id="5677928146339483299">تم المنع</translation>
<translation id="5710435578057952990">لم Ùتمّ التحقق من هوÙØ© هذا الموقع.</translation>
<translation id="5720705177508910913">المستخدم الحالÙ</translation>
+<translation id="572328651809341494">علامات التبوÙب الأخÙرة</translation>
<translation id="5784606427469807560">حدثت مشكلة أثناء التأكد من بطاقتك. تحقق من اتصالك بالإنترنت وأعد المحاولة.</translation>
<translation id="5785756445106461925">إضاÙØ© إلى ذلك، تتضمن هذه الصÙحة موارد أخرى غÙر آمنة. ÙˆÙستطÙع الآخرون مشاهدة هذه الموارد أثناء نقلها، كما ÙستطÙع أ٠مهاجم تعدÙلها لتغÙÙر مظهر الصÙحة.</translation>
+<translation id="5786044859038896871">هل ترÙد ملء معلومات بطاقتك؟</translation>
+<translation id="5803412860119678065">هل ترÙد ملء <ph name="CARD_DETAIL" />ØŸ</translation>
<translation id="5810442152076338065">Ùتم ترمÙز اتصالك بالنطاق <ph name="DOMAIN" /> باستخدام مجموعة تشÙÙر قدÙمة.</translation>
<translation id="5813119285467412249">إعا&amp;دة الإضاÙØ©</translation>
+<translation id="5814352347845180253">قد تÙقد إمكانÙØ© الدخول إلى محتوى متمÙز من <ph name="SITE" /> وبعض المواقع الأخرى.</translation>
+<translation id="5843436854350372569">لقد حاولت الوصول إلى <ph name="DOMAIN" />ØŒ ولكن الخادم قدّم شهادة تحتو٠على Ù…Ùتاح ضعÙÙ. ربما اخترق أحد المهاجمÙÙ† المÙتاح الخاص، وقد لا Ùكون الخادم هو الخادم الذ٠تتوقعه (قد تكون على اتصال بأحد المهاجمÙÙ†). <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">ظهرت هذه الرسالة لأن مدÙرك حظر هذا الموقع.</translation>
<translation id="5857090052475505287">مجلد جدÙد</translation>
<translation id="5869405914158311789">لا Ùمكن الوصول إلى موقع الوÙب هذا</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">اقتراحات الآباء</translation>
<translation id="59107663811261420">â€Ù‡Ø°Ø§ النوع من البطاقات غÙر متواÙÙ‚ مع Google Payments لهذا التاجر. ÙÙرجى تحدÙد بطاقة أخرى.</translation>
<translation id="59174027418879706">تم التمكÙÙ†</translation>
+<translation id="5926846154125914413">قد تÙقد إمكانÙØ© الدخول إلى محتوى متمÙز من بعض المواقع.</translation>
<translation id="5966707198760109579">الأسبوع</translation>
<translation id="5967867314010545767">إزالة من السجل</translation>
<translation id="5975083100439434680">تصغÙر</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">تلقائÙ</translation>
<translation id="6042308850641462728">المزÙد</translation>
<translation id="6060685159320643512">احذر، هذه التجارب غÙر مضمونة النتائج</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{لا Ø´ÙØ¡}=1{1}two{#}few{#}many{#}other{#}}</translation>
<translation id="6146055958333702838">تحقق من أ٠كابلات وأعد تشغÙÙ„ أ٠أجهزة توجÙÙ‡ أو أجهزة مودم أو أجهزة شبكة
أخرى ربما تستخدمها.</translation>
<translation id="614940544461990577">جرّب:</translation>
<translation id="6150607114729249911">عÙوًا! علÙÙƒ أن تسأل والدÙÙƒ ما إذا كان مناسبًا لك زÙارة هذه الصÙحة.</translation>
<translation id="6151417162996330722">Ùترة صلاحÙØ© شهادة الخادم طوÙلة جدًا.</translation>
-<translation id="6154808779448689242">لا Ùتطابق الرمز الممÙز لسÙاسة الإرجاع مع الرمز الممÙز الحالÙ</translation>
<translation id="6165508094623778733">مزÙد من المعلومات</translation>
<translation id="6203231073485539293">التحقق من اتصالك بالإنترنت</translation>
<translation id="6218753634732582820">â€Ù‡Ù„ ترÙد إزالة العنوان من ChromiumØŸ</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">تجربة تعطÙÙ„ التنبؤ بإجراءات الشبكة</translation>
<translation id="6337534724793800597">تصÙÙØ© السÙاسات بحسب الاسم</translation>
<translation id="6342069812937806050">الآن</translation>
+<translation id="6345221851280129312">حجم غÙر معروÙ</translation>
<translation id="6355080345576803305">إلغاء الجلسة العامة</translation>
<translation id="6358450015545214790">ماذا تعن٠هذه الأقسام؟</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{اقتراح واحد آخر}zero{# اقتراح آخر}two{اقتراحان آخران (#)}few{# اقتراحات أخرى}many{# اقتراحًا آخر}other{# اقتراح آخر}}</translation>
<translation id="6387478394221739770">â€Ø¥Ø°Ø§ كنت مهتمًا بمÙزات Google الجدÙدة والرائعة، ÙÙÙمكنك تجربة القناة التجرÙبÙØ© على chrome.com/beta.</translation>
-<translation id="641480858134062906">Ùشل تحمÙÙ„ <ph name="URL" /></translation>
+<translation id="6389758589412724634">â€Ù†Ùدت ذاكرة Chromium أثناء محاولة عرض صÙحة الوÙب هذه.</translation>
+<translation id="6416403317709441254">â€Ù„ا Ùمكنك زÙارة <ph name="SITE" /> الآن نظرًا لأن موقع الوÙب أرسل بÙانات اعتماد مختلطة Ùتعذر على Chromium معالجتها. أخطاء الشبكة والهجمات علÙها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصÙحة لاحقًا على الأرجح. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">تعذر التحقق مما إذا كانت الشهادة قد تم إبطالها.</translation>
<translation id="6433595998831338502">رÙض <ph name="HOST_NAME" /> الاتصال.</translation>
<translation id="6445051938772793705">البلد</translation>
<translation id="6451458296329894277">تأكÙد إعادة إرسال النموذج</translation>
<translation id="6458467102616083041">تم التجاهل نظرًا لتعطÙÙ„ البحث الاÙتراض٠بواسطة السÙاسة.</translation>
+<translation id="6462969404041126431">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />ØŒ قد Ùكون تم إبطال شهادة أمانه. وربما Ùكون سبب ذلك خطأً Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">سÙاسات الأجهزة</translation>
<translation id="6489534406876378309">بدء تحمÙÙ„ الأعطال</translation>
<translation id="6529602333819889595">إعادة الح&amp;Ø°Ù</translation>
+<translation id="6534179046333460208">اقتراحات الشبكة المادÙØ©</translation>
<translation id="6550675742724504774">Ø®Ùارات</translation>
+<translation id="6593753688552673085">أقل من <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Ø®Ùارات التشÙÙر</translation>
<translation id="662080504995468778">البقاء</translation>
<translation id="6628463337424475685">بحث <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">لا Ùمكنك زÙارة <ph name="SITE" /> الآن لأنه <ph name="BEGIN_LINK" />تم إبطال هذه الشهادة<ph name="END_LINK" />. أخطاء الشبكة والهجمات علÙها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصÙحة لاحقًا على الأرجح.</translation>
<translation id="6644283850729428850">تم تجاهل هذه السÙاسة.</translation>
+<translation id="6652240803263749613">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />ØŒ بل إن شهادة أمانه غÙر موثوقة من Ù‚Ùبل نظام تشغÙÙ„ الكمبÙوتر. وربما Ùكون السبب Ù٠ذلك خطأً Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">تعدÙÙ„ مجلد</translation>
<translation id="6660210980321319655">تم الإبلاغ عنه تلقائÙًا <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">â€Ù‡Ù„ ترÙد إزالة اقتراح النموذج من ChromiumØŸ</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">السابق</translation>
<translation id="6710594484020273272">&lt;إدخال عبارة البحث&gt;</translation>
<translation id="6711464428925977395">هناك خطأ ما Ù٠الخادم الوكÙÙ„ØŒ أو العنوان غÙر صحÙØ­.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{لا Ø´ÙØ¡}=1{عنصر واحد}two{عنصران (#)}few{# عناصر}many{# عنصرًا}other{# عنصر}}</translation>
<translation id="674375294223700098">حدث خطأ غÙر معرو٠Ù٠شهادة الخادم.</translation>
<translation id="6753269504797312559">Ù‚Ùمة السÙاسة</translation>
<translation id="6757797048963528358">خضع جهازك إلى وضع السكون.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">مستوى السÙاسة غÙر مدعوم.</translation>
<translation id="6895330447102777224">تم التأكد من بطاقتك</translation>
<translation id="6897140037006041989">وكÙÙ„ المستخدم</translation>
-<translation id="6903907808598579934">تشغÙÙ„ المزامنة</translation>
<translation id="6915804003454593391">المستخدم:</translation>
<translation id="6957887021205513506">Ùبدو أن شهادة الخادم مزÙÙØ©.</translation>
<translation id="6965382102122355670">مواÙÙ‚</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">المنطقة</translation>
<translation id="6973656660372572881">â€ØªÙ… تحدÙد كل من الخوادم الوكÙلة الثابتة وعنوان URL للنص البرمج٠pac.</translation>
<translation id="6989763994942163495">عرض الإعدادات المتقدمة...</translation>
+<translation id="7000990526846637657">لم Ùتم العثور على أ٠إدخالات Ù٠السجلّ</translation>
+<translation id="7009986207543992532">لقد حاولت الوصول إلى <ph name="DOMAIN" />ØŒ ولكن الخادم قدّم شهادة مدة صلاحÙتها طوÙلة جدًا مما Ùجعلها غÙر جدÙرة بالثقة. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">â€Ù‚د Ùتضمن حسابك ÙÙ Google نماذج أخرى من سجلّ التصÙØ­ ÙÙ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">كلمات المرور</translation>
-<translation id="7050187094878475250">لقد حاولت الوصول إلى <ph name="DOMAIN" />ØŒ ولكن الخادم قدم شهادة مدة صلاحÙتها طوÙلة جدًا مما Ùجعلها غÙر جدÙرة بالثقة.</translation>
<translation id="7087282848513945231">المقاطعة/الإقلÙÙ…/المنطقة</translation>
<translation id="7088615885725309056">أقدم</translation>
<translation id="7090678807593890770">â€Ø§Ù„بحث ÙÙ Google عن <ph name="LINK" /></translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">ظهرت لك هذه الرسالة نظرًا لحاجة مدÙرك للمواÙقة على المواقع الجدÙدة عند زÙارتك الأولى.</translation>
<translation id="724975217298816891">â€Ø£Ø¯Ø®Ù„ تارÙØ® انتهاء الصلاحÙØ© ورمز التحقق من البطاقة (CVC) لـ <ph name="CREDIT_CARD" /> لتحدÙØ« تÙاصÙÙ„ بطاقتك. بعد تأكÙدك، ستتم مشاركة تÙاصÙÙ„ بطاقتك مع هذا الموقع.</translation>
<translation id="725866823122871198">تعذر إنشاء اتصال خاص بـ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> نظرًا لأن التارÙØ® والوقت لجهاز الكمبÙوتر (<ph name="DATE_AND_TIME" />) غÙر صحÙØ­ÙÙ†.</translation>
-<translation id="7265986070661382626">لا Ùمكنك زÙارة <ph name="SITE" /> لأن موقع الوÙب <ph name="BEGIN_LINK" />Ùستخدم أداة التحقق من صحة الشهادات<ph name="END_LINK" />. أخطاء الشبكة والهجمات علÙها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصÙحة لاحقًا على الأرجح.</translation>
<translation id="7269802741830436641">تحتو٠صÙحة الوÙب هذه على حلقة إعادة توجÙÙ‡</translation>
<translation id="7275334191706090484">الإشارات المرجعÙØ© المÙدارة</translation>
<translation id="7298195798382681320">موصى بها</translation>
-<translation id="7301833672208172928">تشغÙÙ„ مزامنة السجل</translation>
+<translation id="7309308571273880165">تقرÙر الأعطال الذ٠تم الحصول علÙÙ‡ ÙÙ <ph name="CRASH_TIME" /> (التحمÙÙ„ مطلوب بواسطة المستخدم، لم Ùتم التحمÙÙ„ بعد)</translation>
<translation id="7334320624316649418">إعادة Ø¥&amp;جراء الترتÙب</translation>
<translation id="733923710415886693">لم Ùتم الكش٠عن شهادة الخادم عن طرÙÙ‚ شهادة الشÙاÙÙØ©.</translation>
+<translation id="7351800657706554155">لا Ùمكنك زÙارة <ph name="SITE" /> الآن نظرًا لأنه تم إبطال شهادته. وعادةً ما تكون أخطاء الشبكة والهجمات علÙها مؤقتة، لذا ستعمل هذه الصÙحة لاحقًا على الأرجح. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">سطر الأوامر</translation>
<translation id="7372973238305370288">نتÙجة البحث</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" />†- <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">جار٠التاكد من البطاقة</translation>
<translation id="7481312909269577407">إلى الأمام</translation>
<translation id="7485870689360869515">لم Ùتم العثور على بÙانات.</translation>
+<translation id="7508255263130623398">رقم تعرÙ٠الجهاز المعروض للسÙاسة Ùارغ أو لا Ùتطابق مع رقم تعرÙ٠الجهاز الحالÙ</translation>
<translation id="7514365320538308">تنزÙÙ„</translation>
<translation id="7518003948725431193">لم Ùتم العثور على أ٠صÙحة ÙˆÙب لعنوان الوÙب:<ph name="URL" /></translation>
<translation id="7537536606612762813">إلزامÙØ©</translation>
<translation id="7542995811387359312">تم تعطÙÙ„ الملء التلقائ٠لبطاقة الائتمان لأن هذا النموذج لا Ùستخدم اتصالاً آمنًا.</translation>
<translation id="7549584377607005141">تتطلب صÙحة الوÙب هذه البÙانات الت٠أدخلتها Ù٠وقت سابق لعرضها بشكل صحÙØ­. Ùمكنك إرسال هذه المعلومات مرة أخرى ولكن بذلك ستكرر أ٠إجراء اتخذته هذه الصÙحة Ù٠وقت سابق.</translation>
<translation id="7554791636758816595">علامة تبوÙب جدÙدة</translation>
-<translation id="7567204685887185387">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان تم إصدارها عن طرÙÙ‚ الاحتÙال. وربما Ùكون سبب ذلك خطأ Ù٠التكوÙÙ† أو مهاجمًا Ùعترض اتصالك.</translation>
<translation id="7568593326407688803">تتوÙر هذه الصÙحة باللغة<ph name="ORIGINAL_LANGUAGE" />Ùهل ترÙد ترجمتها؟</translation>
<translation id="7569952961197462199">â€Ù‡Ù„ ترÙد إزالة بطاقة الائتمان من ChromeØŸ</translation>
<translation id="7578104083680115302">â€Ø§Ù„دÙع سرÙعًا على المواقع والتطبÙقات عبر الأجهزة باستخدام البطاقات الت٠حÙظتها ÙÙ Google.</translation>
+<translation id="7588950540487816470">الشبكة المادÙØ©</translation>
<translation id="7592362899630581445">تنتهك شهادة الخادم القÙود المÙروضة على الاسم.</translation>
<translation id="759889825892636187">Ùتعذر على <ph name="HOST_NAME" /> معالجة هذا الطلب حالÙًا.</translation>
<translation id="7600965453749440009">عدم الترجمة مطلقًا من اللغة <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">â€Ù‡Ù„ ترÙد إزالة بطاقة الائتمان من ChromiumØŸ</translation>
<translation id="765676359832457558">إخÙاء الإعدادات المتقدمة...</translation>
<translation id="7658239707568436148">إلغاء</translation>
+<translation id="7667346355482952095">الرمز الممÙز المعروض للسÙاسة خالÙًا أو لا Ùتطابق مع الرمز الممÙز الحالÙ</translation>
<translation id="7668654391829183341">جهاز غÙر معروÙ</translation>
<translation id="7674629440242451245">â€Ø¥Ø°Ø§ كنت مهتمًا بمÙزات Google الجدÙدة والرائعة، ÙÙÙمكنك تجربة قناة مطور٠البرامج على chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />متابعة إلى <ph name="SITE" /> (غÙر آمن)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">لا، شكرًا</translation>
<translation id="7805768142964895445">الحالة</translation>
<translation id="7813600968533626083">â€Ù‡Ù„ ترÙد إزالة اقتراح النموذج من ChromeØŸ</translation>
+<translation id="7815407501681723534">تم العثور على <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> لـ "<ph name="SEARCH_STRING" />"</translation>
<translation id="785549533363645510">ومع ذلك، أنت غÙر مرئÙ. لا ÙØ®Ù٠الانتقال إلى وضع التخÙ٠التصÙØ­ من صاحب العمل أو مزود خدمة الإنترنت أو المواقع الت٠تزورها.</translation>
<translation id="7887683347370398519">â€ØªØ­Ù‚Ù‚ من رمز التحقق من البطاقة (CVC) ثم أعد المحاولة.</translation>
<translation id="7894616681410591072">عÙوًا، أنت بحاجة إلى الحصول على إذن من <ph name="NAME" /> للدخول إلى هذه الصÙحة.</translation>
-<translation id="790025292736025802">تعذر العثور على <ph name="URL" /></translation>
<translation id="7912024687060120840">Ù٠المجلد:</translation>
<translation id="7920092496846849526">هل سألت والدÙÙƒ ما إذا كان مناسبًا لك زÙارة هذه الصÙحة.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">غÙر محدد</translation>
<translation id="8012647001091218357">لم نتمكن من الوصول إلى والدÙÙƒ Ù٠الوقت الحالÙ. ÙÙرجى إعادة المحاولة مرة أخرى.</translation>
<translation id="8034522405403831421">هذه الصÙحة باللغة <ph name="SOURCE_LANGUAGE" />. هل ترÙد ترجمتها إلى اللغة <ph name="TARGET_LANGUAGE" />ØŸ</translation>
-<translation id="8034955203865359138">لم Ùتم العثور على أ٠إدخالات Ù٠السجل.</translation>
<translation id="8088680233425245692">أخÙÙ‚ عرض المقالة.</translation>
+<translation id="8089520772729574115">أقل من Ù…ÙغاباÙت واحدة</translation>
<translation id="8091372947890762290">التنشÙØ· Ù‚Ùد الانتظار Ù٠الخادم</translation>
+<translation id="8129262335948759431">كمÙØ© غÙر معروÙØ©</translation>
<translation id="8131740175452115882">التأكÙد</translation>
<translation id="8134994873729925007">تعذر العثور على <ph name="BEGIN_ABBR" />عنوان نظام أسماء النطاقات<ph name="END_ABBR" /> للخادم <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">خضع جهاز الكمبÙوتر إلى وضع السكون.</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">â€Ø¹Ù†ÙˆØ§Ù† URL لتحدÙØ« الإضاÙØ© الت٠تحتو٠على رقم التعرÙÙ "<ph name="EXTENSION_ID" />" غÙر صالح.</translation>
<translation id="8218327578424803826">الموقع الذ٠تم تعÙÙنه:</translation>
<translation id="8225771182978767009">اختار الشخص الذ٠أعد جهاز الكمبÙوتر حظر موقع الوÙب هذا.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />، <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">استخدمت الصÙحة الت٠تبحث عنها المعلومات الت٠أدخلتها وقد Ùؤدّ٠الرجوع إلÙها إلى تكرار جمÙع الإجراءات السابقة. هل ترÙد المتابعة؟</translation>
<translation id="8249320324621329438">تارÙØ® آخر عملÙØ© جلب:</translation>
<translation id="8261506727792406068">حذÙ</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">شرÙØ· الإشارات</translation>
<translation id="8363502534493474904">Ø¥Ùقا٠تشغÙÙ„ وضع الطائرة</translation>
<translation id="8364627913115013041">لم Ùتم تعÙÙنها.</translation>
+<translation id="8380941800586852976">ضارة</translation>
<translation id="8412145213513410671">الأعطال (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Ùجب إدخال عبارة المرور Ù†Ùسها مرتÙÙ†.</translation>
<translation id="8428213095426709021">إعدادات</translation>
+<translation id="8433057134996913067">سÙؤد٠هذا إلى خروجك من معظم مواقع الوÙب.</translation>
<translation id="8437238597147034694">تراجع عن ال&amp;نقل</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{بطاقة ائتمان واحدة}zero{# بطاقة ائتمان}two{بطاقتا ائتمان (#)}few{# بطاقات ائتمان}many{# بطاقة ائتمان}other{# بطاقة ائتمان}}</translation>
+<translation id="8483780878231876732">â€Ù„استخدام البطاقات من حسابك ÙÙ GoogleØŒ ÙÙرجى تسجÙÙ„ الدخول إلى Chrome</translation>
<translation id="8488350697529856933">تنطبق على</translation>
<translation id="8498891568109133222">استغرق <ph name="HOST_NAME" /> وقتًا أطول مما Ùجب للاستجابة.</translation>
+<translation id="852346902619691059">هذا الخادم لم Ùتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إن شهادة أمانه غÙر موثوقة من Ù‚Ùبل نظام تشغÙÙ„ جهازك. وربما Ùكون السبب Ù٠ذلك خطأً Ù٠التهÙئة أو مهاجمًا Ùعترض اتصالك. <ph name="BEGIN_LEARN_MORE_LINK" />مزÙد من المعلومات<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">â€Ù‡Ø°Ø§ النوع من البطاقات غÙر متواÙÙ‚ مع Google Payments. ÙÙرجى تحدÙد بطاقة مختلÙØ©.</translation>
<translation id="8550022383519221471">خدمة المزامنة غÙر متاحة لنطاقك.</translation>
<translation id="8553075262323480129">أخÙقت الترجمة لتعذر تحدÙد لغة الصÙحة.</translation>
@@ -633,15 +675,12 @@
<translation id="8647750283161643317">إعادة التعÙÙÙ† على الإعدادات الاÙتراضÙØ©</translation>
<translation id="8680787084697685621">تÙاصÙÙ„ تسجÙÙ„ الدخول إلى الحساب قدÙمة.</translation>
<translation id="8703575177326907206">الاتصال بالموقع <ph name="DOMAIN" /> غÙر محمÙÙ‘ بنظام تشÙÙر.</translation>
-<translation id="8713130696108419660">توقÙع أول٠غÙر صحÙØ­</translation>
<translation id="8725066075913043281">أعد المحاولة</translation>
<translation id="8728672262656704056">لقد انتقلت إلى وضع التصÙØ­ المتخÙÙ</translation>
<translation id="8730621377337864115">تم</translation>
<translation id="8738058698779197622">â€Ù„إنشاء اتصال آمن، Ùإنك بحاجة إلى ضبط ساعتك بشكل صحÙØ­. وذلك لأن الشهادات الت٠تستخدمها مواقع الوÙب لتعرÙÙ Ù†Ùسها تكون صالحة Ùقط Ù„Ùترات محددة من الوقت. Ùإذا كانت ساعة جهازك غÙر صحÙحة، Ùلن Ùتمكن Chromium من التحقق من هذه الشهادات.</translation>
<translation id="8740359287975076522">â€ØªØ¹Ø°Ø± العثور على &lt;/abbr&gt;عنوان نظام أسماء النطاقات (DNS)â€&lt;abbr id="dnsDefinition"&gt; لـ <ph name="HOST_NAME" />. جار٠تشخÙص المشكلة.</translation>
-<translation id="8741995161408053644">â€Ù‚د Ùتضمن حسابك ÙÙ Google على نماذج أخرى من سجل التصÙØ­ ÙÙ <ph name="BEGIN_LINK" /> history.google.com <ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">إعادة الح&amp;Ø°Ù</translation>
-<translation id="8790687370365610530">â€Ù„لحصول على محتوى مخصص اقترحته GoogleØŒ شغّل مزامنة السجل.</translation>
<translation id="8798099450830957504">الاÙتراضÙ</translation>
<translation id="8804164990146287819">سÙاسة الخصوصÙØ©</translation>
<translation id="8820817407110198400">إشارات</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">انتهت صلاحÙØ© شهادة الخادم.</translation>
<translation id="8987927404178983737">شهر</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" />†[<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">قدم الخادم شهادة لم Ùتم الكش٠عنها علنًا باستخدام سÙاسة شهادة الشÙاÙÙØ©. وهذا ضرور٠لبعض الشهادات، لضمان أنها جدÙرة بالثقة ومحمÙØ© من المهاجمÙÙ†.</translation>
<translation id="9001074447101275817">Ùتطلب الخادم الوكÙÙ„ <ph name="DOMAIN" /> اسم مستخدم وكلمة مرور.</translation>
<translation id="901974403500617787">لا Ùمكن تعÙÙÙ† العلامات الت٠تسر٠عبر النظام إلا من Ù‚Ùبل المالك: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">تمت ترجمة هذه الصÙحة إلى <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">استخدام إحدى خدمات التوقع لتحمÙÙ„ الصÙحات بسرعة أكبر</translation>
<translation id="9039213469156557790">إضاÙØ© إلى ذلك، تتضمن هذه الصÙحة موارد أخرى غÙر آمنة. ÙˆÙستطÙع الآخرون مشاهدة هذه الموارد أثناء نقلها، كما ÙستطÙع أ٠مهاجم تعدÙلها لتغÙÙر سلوك الصÙحة.</translation>
-<translation id="9049981332609050619">لقد حاولت الوصول إلى <ph name="DOMAIN" />, ولكن الخادم قدّم شهادة غÙر صالحة.</translation>
<translation id="9050666287014529139">عبارة المرور</translation>
<translation id="9065203028668620118">تحرÙر</translation>
<translation id="9092364396508701805">صÙحة <ph name="HOST_NAME" /> لا تعمل</translation>
diff --git a/chromium/components/strings/components_strings_bg.xtb b/chromium/components/strings/components_strings_bg.xtb
index 0d243865f04..e377d48b0ff 100644
--- a/chromium/components/strings/components_strings_bg.xtb
+++ b/chromium/components/strings/components_strings_bg.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="bg">
+<translation id="1008557486741366299">Đе ÑĐµĐ³Đ°</translation>
<translation id="1015730422737071372">Đ’ÑĐ²ĐµĐ¶Đ´Đ°Đ½Đµ Đ½Đ° Đ´Đ¾Đ¿ÑĐ»Đ½Đ¸Ñ‚ĐµĐ»Đ½Đ¸ Đ¿Đ¾Đ´Ñ€Đ¾Đ±Đ½Đ¾ÑÑ‚Đ¸</translation>
<translation id="1032854598605920125">Đ—Đ°Đ²ÑÑ€Ñ‚Đ°Đ½Đµ Đ¿Đ¾ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸ĐºĐ¾Đ²Đ°Ñ‚Đ° ÑÑ‚Ñ€ĐµĐ»ĐºĐ°</translation>
<translation id="1038842779957582377">Đ½ĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ¾ Đ¸Đ¼Đµ</translation>
+<translation id="1053591932240354961">Đ’ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" />, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚ÑÑ‚ Đ¸Đ·Đ¿Ñ€Đ°Ñ‚Đ¸ Đ½ĐµĐ²Đ°Đ»Đ¸Đ´Đ½Đ¸ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸ Đ´Đ°Đ½Đ½Đ¸, ĐºĐ¾Đ¸Ñ‚Đ¾ Google Chrome Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾Đ±Ñ€Đ°Đ±Đ¾Ñ‚Đ¸. ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ¸Ñ‚Đµ Đ³Ñ€ĐµÑˆĐºĐ¸ и Đ°Ñ‚Đ°ĐºĐ¸ ÑĐ° Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¸, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Đ¿Đ¾-ĐºÑÑĐ½Đ¾. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;ĐÑ‚Đ¼ÑĐ½Đ° Đ½Đ° Đ´Đ¾Đ±Đ°Đ²ÑĐ½ĐµÑ‚Đ¾</translation>
<translation id="10614374240317010">ĐĐµĐ·Đ°Đ¿Đ°Đ·Đ²Đ°Đ½Đ¸ Đ½Đ¸ĐºĐ¾Đ³Đ°</translation>
-<translation id="1064422015032085147">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚, Ñ…Đ¾ÑÑ‚Đ²Đ°Ñ‰ ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°, Đ¼Đ¾Đ¶Đµ Đ´Đ° е Đ¿Ñ€ĐµÑ‚Đ¾Đ²Đ°Ñ€ĐµĐ½ или Đ² Đ¿Ñ€Đ¾Ñ†ĐµÑ Đ½Đ° Đ¿Ñ€Đ¾Ñ„Đ¸Đ»Đ°ĐºÑ‚Đ¸ĐºĐ°.
-Đ—Đ° Đ´Đ° Ñе Đ¸Đ·Đ±ĐµĐ³Đ½Đµ Đ³ĐµĐ½ĐµÑ€Đ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° Ñ‚Đ²ÑÑ€Đ´Đµ Đ¼Đ½Đ¾Đ³Đ¾ Ñ‚Ñ€Đ°Ñ„Đ¸Đº и Đ²Đ»Đ¾ÑˆĐ°Đ²Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° ÑĐ¸Ñ‚ÑƒĐ°Ñ†Đ¸ÑÑ‚Đ°,
-Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¾ Đ·Đ°Đ±Ñ€Đ°Đ½Đ¸Ñ…Đ¼Đµ Đ·Đ°ÑĐ²ĐºĐ¸Ñ‚Đµ Đ´Đ¾ Ñ‚Đ¾Đ·Đ¸ URL Đ°Đ´Ñ€ĐµÑ.</translation>
<translation id="106701514854093668">ĐĐ°ÑÑ‚Đ¾Đ»Đ½Đ¸ Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ¸</translation>
<translation id="1080116354587839789">ĐŸĐ¾Đ±Đ¸Ñ€Đ°Đ½Đµ Đ½Đ° ÑˆĐ¸Ñ€Đ¸Đ½Đ°</translation>
+<translation id="1103124106085518534">Đ“Đ¾Ñ‚Đ¾Đ²Đ¾ Đ·Đ°ÑĐµĐ³Đ°</translation>
<translation id="1103523840287552314">Đ’Đ¸Đ½Đ°Đ³Đ¸ Đ´Đ° Ñе Đ¿Ñ€ĐµĐ²ĐµĐ¶Đ´Đ° Đ¾Ñ‚ <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">ĐĐºĐ¾ Đ¿Đ¾ÑÑ‚Đ°Đ²Đ¸Ñ‚Đµ Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ°, Chrome Ñ‰Đµ ÑÑÑ…Ñ€Đ°Đ½ÑĐ²Đ° ĐºĐ¾Đ¿Đ¸Đµ Đ½Đ° ĐºĐ°Ñ€Ñ‚Đ°Ñ‚Đ° Đ²Đ¸ Đ½Đ° Ñ‚Đ¾Đ²Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾ Ñ Ñ†ĐµĐ» Đ¿Đ¾-бÑÑ€Đ·Đ¾ Đ¿Đ¾Đ¿ÑĐ»Đ²Đ°Đ½Đµ Đ½Đ° Ñ„Đ¾Ñ€Đ¼ÑƒĐ»ÑÑ€Đ¸.</translation>
+<translation id="1111153019813902504">Đ¡ĐºĐ¾Ñ€Đ¾ÑˆĐ½Đ¸ Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ¸</translation>
<translation id="1113869188872983271">&amp;ĐÑ‚Đ¼ÑĐ½Đ° Đ½Đ° Đ¿Ñ€ĐµĐ½Đ°Ñ€ĐµĐ¶Đ´Đ°Đ½ĐµÑ‚Đ¾</translation>
+<translation id="1126551341858583091">Đ Đ°Đ·Đ¼ĐµÑ€ÑÑ‚ Đ½Đ° Đ»Đ¾ĐºĐ°Đ»Đ½Đ¾Ñ‚Đ¾ Ñ…Ñ€Đ°Đ½Đ¸Đ»Đ¸Ñ‰Đµ е <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">ĐĐµÑˆÑÑ‚ Đ½Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾ е Đ² Đ´Đ¾Đ±Ñ€Đ¾ ÑÑÑÑ‚Đ¾ÑĐ½Đ¸Đµ</translation>
<translation id="113188000913989374"><ph name="SITE" /> Đ¸Đ·Đ¿Ñ€Đ°Ñ‰Đ° Đ¿Đ¾Đ´ĐºĐ°Đ½Đ°:</translation>
<translation id="1132774398110320017">ĐĐ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ·Đ° ĐĐ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đ¾ Đ¿Đ¾Đ¿ÑĐ»Đ²Đ°Đ½Đµ Đ² Chrome...</translation>
-<translation id="1150979032973867961">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />; Đ¾Đ¿ĐµÑ€Đ°Ñ†Đ¸Đ¾Đ½Đ½Đ°Ñ‚Đ° ÑиÑÑ‚ĐµĐ¼Đ° Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€Đ° Đ²Đ¸ Đ½ÑĐ¼Đ° Đ´Đ¾Đ²ĐµÑ€Đ¸Đµ Đ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ°Ñ‚Đ°ĐºÑƒĐ²Đ°Ñ‰.</translation>
<translation id="1152921474424827756">Đ’Đ¸Đ¶Ñ‚Đµ <ph name="BEGIN_LINK" />ĐºĐµÑˆĐ¸Ñ€Đ°Đ½Đ¾ ĐºĐ¾Đ¿Đ¸Đµ<ph name="END_LINK" /> Đ½Đ° <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> Đ½ĐµĐ¾Ñ‡Đ°ĐºĐ²Đ°Đ½Đ¾ Đ¿Ñ€ĐµĐºÑ€Đ°Ñ‚Đ¸ Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ°.</translation>
<translation id="1161325031994447685">Đ¡Đ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñе Đ¾Ñ‚Đ½Đ¾Đ²Đ¾ Ñ Wi-Fi.</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">ĐŸÑ€ĐµĐ¼Đ°Ñ…Đ²Đ°Đ½Đµ</translation>
<translation id="1201402288615127009">ĐĐ°Đ¿Ñ€ĐµĐ´</translation>
<translation id="1201895884277373915">ĐÑ‰Đµ Đ¾Ñ‚ Ñ‚Đ¾Đ·Đ¸ ÑĐ°Đ¹Ñ‚</translation>
-<translation id="121201262018556460">ĐĐ°Đ¿Ñ€Đ°Đ²Đ¸Ñ…Ñ‚Đµ Đ¾Đ¿Đ¸Ñ‚ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñ/ÑÑ <ph name="DOMAIN" />, Đ½Đ¾ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, ÑÑĐ´ÑÑ€Đ¶Đ°Ñ‰ Ñлаб ĐºĐ»Ñч. Đ’ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ° Đ´Đ° е Đ¿Ñ€Đ¾Đ±Đ¸Đ» Đ»Đ¸Ñ‡Đ½Đ¸Ñ ĐºĐ»Ñч и ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ´Đ° Đ½Đµ е Ñ‚Đ¾Đ·Đ¸, ĐºĐ¾Đ¹Ñ‚Đ¾ Đ¾Ñ‡Đ°ĐºĐ²Đ°Ñ‚Đµ (Đ²ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ´Đ° ÑÑ‚Đµ Ñе ÑĐ²ÑÑ€Đ·Đ°Đ»Đ¸ Ñ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°).</translation>
+<translation id="1206967143813997005">ĐĐµĐ²Đ°Đ»Đ¸Đ´ĐµĐ½ Đ¿ÑÑ€Đ²Đ¾Đ½Đ°Ñ‡Đ°Đ»ĐµĐ½ Đ¿Đ¾Đ´Đ¿Đ¸Ñ</translation>
+<translation id="1209206284964581585">Đ¡ĐºÑ€Đ¸Đ²Đ°Đ½Đµ Đ·Đ°ÑĐµĐ³Đ°</translation>
<translation id="1219129156119358924">Đ¡Đ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ½Đ° ÑиÑÑ‚ĐµĐ¼Đ°Ñ‚Đ°</translation>
<translation id="1227224963052638717">ĐĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ¾ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾.</translation>
<translation id="1227633850867390598">Đ¡ĐºÑ€Đ¸Đ²Đ°Đ½Đµ Đ½Đ° ÑÑ‚Đ¾Đ¹Đ½Đ¾ÑÑ‚Ñ‚Đ°</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Да</translation>
<translation id="1430915738399379752">ĐŸĐµÑ‡Đ°Ñ‚</translation>
<translation id="1442912890475371290">Đ‘Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½ бе Đ¾Đ¿Đ¸Ñ‚ Đ·Đ° <ph name="BEGIN_LINK" />Đ¿Đ¾ÑĐµÑ‰ĐµĐ½Đ¸Đµ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ¾Ñ‚ <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Đ’ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" />, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚ÑÑ‚ Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° Ñ„Đ¸ĐºÑĐ¸Ñ€Đ°Đ½Đµ Đ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¸Ñ‚Đµ. ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ¸Ñ‚Đµ Đ³Ñ€ĐµÑˆĐºĐ¸ и Đ°Ñ‚Đ°ĐºĐ¸ ÑĐ° Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¸, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Đ¿Đ¾-ĐºÑÑĐ½Đ¾. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">ĐŸĐ¾ĐºĐ°Đ·Đ²Đ°Đ½Đµ Đ½Đ° Đ·Đ°Đ¿Đ°Đ·ĐµĐ½Đ¾ ĐºĐ¾Đ¿Đ¸Đµ Đ½Đ° Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° (Đ·Đ° ĐºĐ¾ĐµÑ‚Đ¾ е Đ¸Đ·Đ²ĐµÑÑ‚Đ½Đ¾, Ñ‡Đµ Đ½Đµ е Đ°ĐºÑ‚ÑƒĐ°Đ»Đ½Đ¾).</translation>
<translation id="1519264250979466059">Đ”Đ°Ñ‚Đ° Đ½Đ° Đ²ĐµÑ€ÑиÑÑ‚Đ°</translation>
<translation id="1549470594296187301">Đ¢Ñ€ÑĐ±Đ²Đ° Đ´Đ° Đ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Ñ‚Đµ JavaScript, Đ·Đ° Đ´Đ° Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ°Ñ‚Đµ Ñ‚Đ°Đ·Đ¸ Ñ„ÑƒĐ½ĐºÑ†Đ¸Ñ.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">ĐĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸ÑÑ‚Đ° Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ° е Đ½ĐµĐ²Đ°Đ»Đ¸Đ´Đ½Đ° и Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Ñе Đ¸Đ¼Đ¿Đ¾Ñ€Ñ‚Đ¸Ñ€Đ°.</translation>
<translation id="1644574205037202324">Đ˜ÑÑ‚Đ¾Ñ€Đ¸Ñ</translation>
<translation id="1645368109819982629">ĐĐµĐ¿Đ¾Đ´Đ´ÑÑ€Đ¶Đ°Đ½ Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»</translation>
-<translation id="1655462015569774233">{1,plural, =1{Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¸Đ·Ñ‚ĐµĐºÑĐ» Đ²Ñ‡ĐµÑ€Đ°. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸ĐºÑÑ‚ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€Đ° Đ²Đ¸ Đ¿Đ¾ĐºĐ°Đ·Đ²Đ° <ph name="CURRENT_DATE" />. Đ¢Đ¾Đ²Đ° Đ¸Đ·Đ³Đ»ĐµĐ¶Đ´Đ° ли Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾? ĐĐºĐ¾ Đ½Đµ е, Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° ÑĐ²ĐµÑ€Đ¸Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Ñ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸Đº и Ñлед Ñ‚Đ¾Đ²Đ° Đ´Đ° Đ¾Đ¿Ñ€ĐµÑĐ½Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°.}other{Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¸Đ·Ñ‚ĐµĐºÑĐ» Đ¿Ñ€ĐµĐ´Đ¸ # Đ´Đ½Đ¸. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸ĐºÑÑ‚ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€Đ° Đ²Đ¸ Đ¿Đ¾ĐºĐ°Đ·Đ²Đ° <ph name="CURRENT_DATE" />. Đ¢Đ¾Đ²Đ° Đ¸Đ·Đ³Đ»ĐµĐ¶Đ´Đ° ли Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾? ĐĐºĐ¾ Đ½Đµ е, Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° ÑĐ²ĐµÑ€Đ¸Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Ñ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸Đº и Ñлед Ñ‚Đ¾Đ²Đ° Đ´Đ° Đ¾Đ¿Ñ€ĐµÑĐ½Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°.}}</translation>
<translation id="1676269943528358898">ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ <ph name="SITE" /> Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đµ Đ·Đ° Đ·Đ°Ñ‰Đ¸Ñ‚Đ° Đ½Đ° Đ¸Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸ÑÑ‚Đ° Đ²Đ¸. ĐĐ¾Đ³Đ°Ñ‚Đ¾ Google Chrome Đ¾Đ¿Đ¸Ñ‚Đ° Đ´Đ° уÑÑ‚Đ°Đ½Đ¾Đ²Đ¸ Đ²Ñ€ÑĐ·ĐºĐ° Ñ/ÑÑ <ph name="SITE" /> Ñ‚Đ¾Đ·Đ¸ Đ¿ÑÑ‚, ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚ÑÑ‚ Đ²ÑÑ€Đ½Đ° Đ½ĐµĐ¾Đ±Đ¸Ñ‡Đ°Đ¹Đ½Đ¸ и Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¸ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸ Đ´Đ°Đ½Đ½Đ¸. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе ÑĐ»ÑƒÑ‡Đ¸, ĐºĐ¾Đ³Đ°Ñ‚Đ¾ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ° Đ¿Ñ€Đ¾Đ±Đ²Đ° Đ´Đ° Ñе Đ¿Ñ€ĐµĐ´ÑÑ‚Đ°Đ²Đ¸ Đ·Đ° <ph name="SITE" /> или Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° е Đ¿Ñ€ĐµĐºÑÑĐ½Đ°Ñ‚Đ° Đ¾Ñ‚ ĐµĐºÑ€Đ°Đ½ Đ·Đ° Đ²Ñ…Đ¾Đ´ Đ² Wi-Fi. Đ˜Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸ÑÑ‚Đ° Đ²Đ¸ Đ¿Ñ€Đ¾Đ´ÑĐ»Đ¶Đ°Đ²Đ° Đ´Đ° е Đ·Đ°Ñ‰Đ¸Ñ‚ĐµĐ½Đ°, Ñ‚ÑĐ¹ ĐºĐ°Ñ‚Đ¾ Chrome ÑĐ¿Ñ€Ñ Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ°, Đ¿Ñ€ĐµĐ´Đ¸ Đ´Đ° бÑĐ´Đ°Ñ‚ Đ¾Đ±Đ¼ĐµĐ½ĐµĐ½Đ¸ Đ´Đ°Đ½Đ½Đ¸.</translation>
<translation id="168841957122794586">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° ÑÑĐ´ÑÑ€Đ¶Đ° Ñлаб ĐºÑ€Đ¸Đ¿Ñ‚Đ¾Đ³Ñ€Đ°Ñ„ÑĐºĐ¸ ĐºĐ»Ñч.</translation>
<translation id="1701955595840307032">ĐŸĐ¾Đ»ÑƒÑ‡Đ°Đ²Đ°Đ¹Ñ‚Đµ Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¾ ÑÑĐ´ÑÑ€Đ¶Đ°Đ½Đ¸Đµ</translation>
-<translation id="1706954506755087368">{1,plural, =1{Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¾Ñ‚ ÑƒÑ‚Ñ€Đµ. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°.}other{Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¾Ñ‚ # Đ´Đ½Đ¸ Đ² бÑĐ´ĐµÑ‰ĐµÑ‚Đ¾. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°.}}</translation>
<translation id="1710259589646384581">ĐĐ¡</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Đ¡Đ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñе ÑÑÑ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Ñ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€.</translation>
<translation id="17513872634828108">ĐÑ‚Đ²Đ¾Ñ€ĐµĐ½Đ¸ Ñ€Đ°Đ·Đ´ĐµĐ»Đ¸</translation>
<translation id="1753706481035618306">ĐĐ¾Đ¼ĐµÑ€ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°</translation>
-<translation id="1761412452051366565">Đ—Đ° Đ´Đ° Đ¿Đ¾Đ»ÑƒÑ‡Đ°Đ²Đ°Ñ‚Đµ Đ¿ĐµÑ€ÑĐ¾Đ½Đ°Đ»Đ¸Đ·Đ¸Ñ€Đ°Đ½Đ¾ ÑÑĐ´ÑÑ€Đ¶Đ°Đ½Đ¸Đµ, Đ¿Ñ€ĐµĐ´Đ»Đ°Đ³Đ°Đ½Đ¾ Đ¾Ñ‚ Google, Đ²ĐºĐ»ÑÑ‡ĐµÑ‚Đµ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾.</translation>
-<translation id="1763864636252898013">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />; Đ¾Đ¿ĐµÑ€Đ°Ñ†Đ¸Đ¾Đ½Đ½Đ°Ñ‚Đ° ÑиÑÑ‚ĐµĐ¼Đ° Đ½Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾Ñ‚Đ¾ Đ²Đ¸ Đ½ÑĐ¼Đ° Đ´Đ¾Đ²ĐµÑ€Đ¸Đµ Đ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ°Ñ‚Đ°ĐºÑƒĐ²Đ°Ñ‰.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />ĐĐ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ´Đ° ÑÑ‚Đ°Ñ€Ñ‚Đ¸Ñ€Đ°Ñ‚Đµ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ° Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºĐ° Đ² Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">ĐœĐ¾Đ»Ñ, Đ°ĐºÑ‚ÑƒĐ°Đ»Đ¸Đ·Đ¸Ñ€Đ°Đ¹Ñ‚Đµ Đ¿Ñ€Đ¾Đ¿ÑƒÑĐºĐ° Ñи Đ·Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½Đµ.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">ĐĐ°ÑĐºĐ¾Ñ€Đ¾ Đ¿Đ¾ÑĐµÑ‚ĐµĐ½Đ¸Ñ‚Đµ Đ¾Ñ‚ Đ²Đ°Ñ Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ¸ Ñ‰Đµ Ñе Đ¿Đ¾ĐºĐ°Đ·Đ²Đ°Ñ‚ Ñ‚ÑƒĐº.</translation>
<translation id="1821930232296380041">Đ—Đ°ÑĐ²ĐºĐ°Ñ‚Đ° или Đ¿Đ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ¸Ñ‚Đµ Đ¹ ÑĐ° Đ½ĐµĐ²Đ°Đ»Đ¸Đ´Đ½Đ¸</translation>
<translation id="1838667051080421715">ĐŸÑ€ĐµĐ³Đ»ĐµĐ¶Đ´Đ°Ñ‚Đµ Đ¸Đ·Ñ…Đ¾Đ´Đ½Đ¸Ñ ĐºĐ¾Đ´ Đ½Đ° ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°.</translation>
<translation id="1871208020102129563">Đ—Đ° Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ° е Đ·Đ°Đ´Đ°Đ´ĐµĐ½Đ¾ Đ´Đ° Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° Ñ„Đ¸ĐºÑĐ¸Ñ€Đ°Đ½Đ¸ Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ¸, Đ° Đ½Đµ URL Đ°Đ´Ñ€ĐµÑ Đ½Đ° ÑĐºÑ€Đ¸Đ¿Ñ‚ Đ²ÑĐ² Ñ„Đ¾Ñ€Đ¼Đ°Ñ‚ .pac.</translation>
<translation id="1883255238294161206">Đ¡Đ²Đ¸Đ²Đ°Đ½Đµ Đ½Đ° ÑĐ¿Đ¸ÑÑĐºĐ°</translation>
<translation id="1898423065542865115">Đ¤Đ¸Đ»Ñ‚Ñ€Đ¸Ñ€Đ°Đ½Đµ</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> Đ½Đµ Đ¿Ñ€Đ¸Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ·Đ° Đ²Ñ…Đ¾Đ´ или Ñ‚Đ¾Đ¹ Đ¼Đ¾Đ¶Đµ Đ´Đ° е Ñ Đ¸Đ·Ñ‚ĐµĐºĐ»Đ° Đ²Đ°Đ»Đ¸Đ´Đ½Đ¾ÑÑ‚.</translation>
<translation id="194030505837763158">ĐÑĐ¼ <ph name="LINK" /></translation>
<translation id="1962204205936693436">ĐÑ‚Đ¼ĐµÑ‚ĐºĐ¸ Đ¾Ñ‚ <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Đ“Ñ€ĐµÑˆĐºĐ° Đ¿Ñ€Đ¸ ÑĐµÑ€Đ¸Đ°Đ»Đ¸Đ·Đ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾</translation>
<translation id="1974060860693918893">Đ Đ°Đ·ÑˆĐ¸Ñ€ĐµĐ½Đ¸</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{и Đ¾Ñ‰Đµ 1}other{и Đ¾Ñ‰Đµ #}}</translation>
<translation id="2025186561304664664">Đ—Đ° Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ° е Đ·Đ°Đ´Đ°Đ´ĐµĐ½Đ° Đ°Đ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ.</translation>
<translation id="2030481566774242610">ĐœĐ¾Đ¶Đµ би Đ¸Đ¼Đ°Ñ…Ñ‚Đµ Đ¿Ñ€ĐµĐ´Đ²Đ¸Đ´ <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Đ’Đ¸Đ¶Đ´Đ°Ñ‚Đµ Ñ‚Đ¾Đ²Đ° ÑÑĐ¾Đ±Ñ‰ĐµĐ½Đ¸Đµ, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»Đ¸Ñ‚Đµ Đ²Đ¸ Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° Đ¾Đ´Đ¾Đ±Ñ€ÑÑ‚ Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑĐ°Đ¹Ñ‚Đ¾Đ²Đµ Đ¿Ñ€Đ¸ Đ¿ÑÑ€Đ²Đ¾Ñ‚Đ¾ Đ²Đ¸ Đ¿Đ¾ÑĐµÑ‰ĐµĐ½Đ¸Đµ.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ²ĐµÑ€ĐµÑ‚Đµ Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ° и Đ·Đ°Ñ‰Đ¸Ñ‚Đ½Đ°Ñ‚Đ° ÑÑ‚ĐµĐ½Đ°<ph name="END_LINK" />.</translation>
<translation id="2053553514270667976">ĐŸĐ¾Ñ‰ĐµĐ½ÑĐºĐ¸ ĐºĐ¾Đ´</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸Đµ}other{# Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ}}</translation>
<translation id="2065985942032347596">Đ˜Đ·Đ¸ÑĐºĐ²Đ° Ñе ÑƒĐ´Đ¾ÑÑ‚Đ¾Đ²ĐµÑ€ÑĐ²Đ°Đ½Đµ Đ½Đ° ÑĐ°Đ¼Đ¾Đ»Đ¸Ñ‡Đ½Đ¾ÑÑ‚Ñ‚Đ°</translation>
<translation id="2079545284768500474">ĐÑ‚Đ¼ÑĐ½Đ°</translation>
<translation id="20817612488360358">Đ—Đ° Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ°Đ½Đµ ÑĐ° Đ·Đ°Đ´Đ°Đ´ĐµĐ½Đ¸ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ·Đ° Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ°, Đ½Đ¾ е Đ¿Đ¾ÑĐ¾Ñ‡ĐµĐ½Đ° и Đ¸Đ·Ñ€Đ¸Ñ‡Đ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Đ ĐµĐ´Đ°ĐºÑ‚Đ¸Ñ€Đ°Đ½Đµ Đ½Đ° Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ°Ñ‚Đ°</translation>
<translation id="2166049586286450108">ĐŸÑĐ»ĐµĐ½ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€ÑĐºĐ¸ Đ´Đ¾ÑÑ‚ÑĐ¿</translation>
<translation id="2166378884831602661">Đ¢Đ¾Đ·Đ¸ ÑĐ°Đ¹Ñ‚ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾ÑĐ¸Đ³ÑƒÑ€Đ¸ Đ·Đ°Ñ‰Đ¸Ñ‚ĐµĐ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°</translation>
-<translation id="2171101176734966184">ĐĐ°Đ¿Ñ€Đ°Đ²Đ¸Ñ…Ñ‚Đµ Đ¾Đ¿Đ¸Ñ‚ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñ/ÑÑ <ph name="DOMAIN" />, Đ½Đ¾ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, Đ¿Đ¾Đ´Đ¿Đ¸ÑĐ°Đ½ ÑÑÑ Ñлаб Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚ÑĐ¼. Đ¢Đ¾Đ²Đ° Đ¾Đ·Đ½Đ°Ñ‡Đ°Đ²Đ°, Ñ‡Đµ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸Ñ‚Đµ Đ´Đ°Đ½Đ½Đ¸ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ¾Ñ‚ ÑÑÑ€Đ²ÑÑ€Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° ÑĐ° Ñ„Đ°Đ»ÑˆĐ¸Ñ„Đ¸Ñ†Đ¸Ñ€Đ°Đ½Đ¸ и Ñ‚Đ¾Đ¹ Đ´Đ° Đ½Đµ е Ñ‚Đ¾Đ·Đ¸, ĐºĐ¾Đ¹Ñ‚Đ¾ Đ¾Ñ‡Đ°ĐºĐ²Đ°Ñ‚Đµ (Đ²ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ´Đ° ÑÑ‚Đµ Ñе ÑĐ²ÑÑ€Đ·Đ°Đ»Đ¸ Ñ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°).</translation>
<translation id="2181821976797666341">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ°</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 Đ°Đ´Ñ€ĐµÑ}other{# Đ°Đ´Ñ€ĐµÑĐ°}}</translation>
<translation id="2212735316055980242">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾ Đ½Đµ е Đ½Đ°Đ¼ĐµÑ€ĐµĐ½Đ¾</translation>
<translation id="2213606439339815911">Đ—Đ°Đ¿Đ¸ÑĐ¸Ñ‚Đµ Ñе Đ¸Đ·Đ²Đ»Đ¸Ñ‡Đ°Ñ‚...</translation>
-<translation id="2214283295778284209">ĐÑĐ¼Đ° Đ´Đ¾ÑÑ‚ÑĐ¿ Đ´Đ¾ <ph name="SITE" /></translation>
<translation id="2230458221926704099">ĐŸĐ¾Đ¿Ñ€Đ°Đ²ĐµÑ‚Đµ Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Ñи Đ¿Đ¾ÑÑ€ĐµĐ´ÑÑ‚Đ²Đ¾Đ¼ <ph name="BEGIN_LINK" />Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸ĐµÑ‚Đ¾ Đ·Đ° Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºĐ°<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Đ˜Đ·Đ¿Ñ€Đ°Ñ‰Đ°Đ½Đµ ÑĐµĐ³Đ°</translation>
<translation id="225207911366869382">Đ¡Ñ‚Đ¾Đ¹Đ½Đ¾ÑÑ‚Ñ‚Đ° е Đ¾Ñ‚Ñ‚ĐµĐ³Đ»ĐµĐ½Đ° Đ·Đ° Ñ‚Đ¾Đ²Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾.</translation>
<translation id="2262243747453050782">HTTP Đ³Ñ€ĐµÑˆĐºĐ°</translation>
<translation id="2282872951544483773">Đ•ĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ¸, ĐºĐ¾Đ¸Ñ‚Đ¾ Đ½Đµ ÑĐ° Đ½Đ°Đ»Đ¸Ñ†Đµ</translation>
<translation id="2292556288342944218">Đ”Đ¾ÑÑ‚ÑĐ¿ÑÑ‚ Đ²Đ¸ Đ´Đ¾ Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ е Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½</translation>
<translation id="229702904922032456">Đ’Đ°Đ»Đ¸Đ´Đ½Đ¾ÑÑ‚Ñ‚Đ° Đ½Đ° Đ¾ÑĐ½Đ¾Đ²ĐµĐ½ или Đ¼ĐµĐ¶Đ´Đ¸Đ½ĐµĐ½ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ е Đ¸Đ·Ñ‚ĐµĐºĐ»Đ°.</translation>
<translation id="230155334948463882">ĐĐ¾Đ²Đ° ĐºĐ°Ñ€Ñ‚Đ°?</translation>
+<translation id="2305919008529760154">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ’ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ´Đ° е Đ¸Đ·Đ´Đ°Đ´ĐµĐ½ Đ¸Đ·Đ¼Đ°Đ¼Đ½Đ¸Ñ‡ĐµÑĐºĐ¸. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">Đ˜Đ·Đ¸ÑĐºĐ²Đ°Ñ‚ Ñе Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»ÑĐºĐ¾ Đ¸Đ¼Đµ и Đ¿Đ°Ñ€Đ¾Đ»Đ° Đ·Đ° <ph name="DOMAIN" />.</translation>
+<translation id="2318774815570432836">Đ’ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" />, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚ÑÑ‚ Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° HSTS. ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ¸Ñ‚Đµ Đ³Ñ€ĐµÑˆĐºĐ¸ и Đ°Ñ‚Đ°ĐºĐ¸ ÑĐ° Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¸, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Đ¿Đ¾-ĐºÑÑĐ½Đ¾. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">ĐŸÑ€ĐµĐ½ĐµĐ±Ñ€ĐµĐ³Đ½Đ°Ñ‚Đ° бе Đ½ĐµĐ²Đ°Đ»Đ¸Đ´Đ½Đ° Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ° Đ² Đ¸Đ½Đ´ĐµĐºÑ <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Đ”Ñ€ÑƒĐ³Đ¸ Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ¸</translation>
<translation id="2359808026110333948">ĐĐ°Đ¿Ñ€ĐµĐ´</translation>
<translation id="2365563543831475020">Đ¡Đ¸Đ³Đ½Đ°Đ»ÑÑ‚ Đ·Đ° ÑÑ€Đ¸Đ², Đ·Đ°Đ¿Đ¸ÑĐ°Đ½ Đ²/ÑĐ² <ph name="CRASH_TIME" />, Đ½Đµ бе ĐºĐ°Ñ‡ĐµĐ½</translation>
<translation id="2367567093518048410">ĐĐ¸Đ²Đ¾</translation>
+<translation id="2371153335857947666">{1,plural, =1{Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¸Đ·Ñ‚ĐµĐºÑĐ» Đ²Ñ‡ĐµÑ€Đ°. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸ĐºÑÑ‚ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€Đ° Đ²Đ¸ Đ¿Đ¾ĐºĐ°Đ·Đ²Đ° <ph name="CURRENT_DATE" />. Đ¢Đ¾Đ²Đ° Đ¸Đ·Đ³Đ»ĐµĐ¶Đ´Đ° ли Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾? ĐĐºĐ¾ Đ½Đµ е, Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° ÑĐ²ĐµÑ€Đ¸Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Ñ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸Đº и Ñлед Ñ‚Đ¾Đ²Đ° Đ´Đ° Đ¾Đ¿Ñ€ĐµÑĐ½Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.}other{Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¸Đ·Ñ‚ĐµĐºÑĐ» Đ¿Ñ€ĐµĐ´Đ¸ # Đ´Đ½Đ¸. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸ĐºÑÑ‚ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€Đ° Đ²Đ¸ Đ¿Đ¾ĐºĐ°Đ·Đ²Đ° <ph name="CURRENT_DATE" />. Đ¢Đ¾Đ²Đ° Đ¸Đ·Đ³Đ»ĐµĐ¶Đ´Đ° ли Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾? ĐĐºĐ¾ Đ½Đµ е, Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° ÑĐ²ĐµÑ€Đ¸Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Ñ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸Đº и Ñлед Ñ‚Đ¾Đ²Đ° Đ´Đ° Đ¾Đ¿Ñ€ĐµÑĐ½Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">ĐÑĐ¼Đ° Đ°Đ»Ñ‚ĐµÑ€Đ½Đ°Ñ‚Đ¸Đ²Đ¸ Đ½Đ° Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»ÑĐºĐ¸Ñ Đ¸Đ½Ñ‚ĐµÑ€Ñ„ĐµĐ¹Ñ</translation>
<translation id="2384307209577226199">Đ—Đ°Đ´Đ°Đ´ĐµĐ½Đ¾ Đ¿Đ¾ Đ¿Đ¾Đ´Ñ€Đ°Đ·Đ±Đ¸Ñ€Đ°Đ½Đµ Đ² ĐºĐ¾Ñ€Đ¿Đ¾Ñ€Đ°Ñ‚Đ¸Đ²Đ½Đ° ÑÑ€ĐµĐ´Đ°</translation>
-<translation id="238526402387145295">Đ’ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" />, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚ÑÑ‚ <ph name="BEGIN_LINK" />Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° HSTS<ph name="END_LINK" />. ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ³Ñ€ĐµÑˆĐºĐ¸Ñ‚Đµ Đ² Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ° и Đ°Ñ‚Đ°ĐºĐ¸Ñ‚Đµ ÑÑ€ĐµÑ‰Ñƒ Đ½ĐµÑ ÑĐ° Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¸, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Đ¿Đ¾-ĐºÑÑĐ½Đ¾.</translation>
<translation id="2386255080630008482">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° е Đ°Đ½ÑƒĐ»Đ¸Ñ€Đ°Đ½.</translation>
<translation id="2392959068659972793">Да Ñе Đ¿Đ¾ĐºĐ°Đ·Đ²Đ°Ñ‚ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°Ñ‚Đ° без Đ·Đ°Đ´Đ°Đ´ĐµĐ½Đ° ÑÑ‚Đ¾Đ¹Đ½Đ¾ÑÑ‚</translation>
<translation id="2396249848217231973">&amp;ĐÑ‚Đ¼ÑĐ½Đ° Đ½Đ° Đ¸Đ·Ñ‚Ñ€Đ¸Đ²Đ°Đ½ĐµÑ‚Đ¾</translation>
-<translation id="2413528052993050574">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />; Đ²ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ´Đ° е Đ¾Ñ‚Ñ‚ĐµĐ³Đ»ĐµĐ½. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ°Ñ‚Đ°ĐºÑƒĐ²Đ°Ñ‰.</translation>
<translation id="2455981314101692989">Đ¢Đ°Đ·Đ¸ ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° е Đ´ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ»Đ° Đ°Đ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đ¾Ñ‚Đ¾ Đ¿Đ¾Đ¿ÑĐ»Đ²Đ°Đ½Đµ Đ·Đ° Ñ‚Đ¾Đ·Đ¸ Ñ„Đ¾Ñ€Đ¼ÑƒĐ»ÑÑ€.</translation>
+<translation id="2463739503403862330">ĐŸĐ¾Đ¿ÑĐ»Đ²Đ°Đ½Đµ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Đ¡Ñ‚Đ°Ñ€Ñ‚Đ¸Ñ€Đ°Đ¹Ñ‚Đµ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ° Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºĐ°<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">ĐĐµĐ²Đ°Đ»Đ¸Đ´ĐµĐ½ URL Đ°Đ´Ñ€ĐµÑ Đ·Đ° Ñ‚ÑÑ€ÑĐµĐ½Đµ.</translation>
<translation id="2491120439723279231">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° ÑÑĐ´ÑÑ€Đ¶Đ° Đ³Ñ€ĐµÑˆĐºĐ¸.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Đ˜Đ·Đ¿Ñ€Đ°Ñ‰Đ°Đ½Đµ</translation>
<translation id="2674170444375937751">ĐаиÑÑ‚Đ¸Đ½Đ° ли иÑĐºĐ°Ñ‚Đµ Đ´Đ° Đ¸Đ·Ñ‚Ñ€Đ¸ĐµÑ‚Đµ Ñ‚ĐµĐ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ¸ Đ¾Ñ‚ иÑÑ‚Đ¾Ñ€Đ¸ÑÑ‚Đ° Ñи?</translation>
<translation id="2677748264148917807">Đ˜Đ·Đ»Đ¸Đ·Đ°Đ½Đµ</translation>
+<translation id="269990154133806163">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, ĐºĐ¾Đ¹Ñ‚Đ¾ Đ½Đµ е Ñ€Đ°Đ·ĐºÑ€Đ¸Ñ‚ Đ¿ÑƒĐ±Đ»Đ¸Ñ‡Đ½Đ¾ Ñ‡Ñ€ĐµĐ· Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾ Đ² ĐŸÑ€Đ¾Đ·Ñ€Đ°Ñ‡Đ½Đ¾ÑÑ‚ Đ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¸Ñ‚Đµ. Đ¢Đ¾Đ²Đ° Ñе изиÑĐºĐ²Đ° Đ·Đ° Đ½ÑĐºĐ¾Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¸ Ñ Ñ†ĐµĐ» Đ·Đ°Ñ‰Đ¸Ñ‚Đ° ÑÑ€ĐµÑ‰Ñƒ Ñ…Đ°ĐºĐµÑ€Đ¸ и Đ·Đ° Đ´Đ° е ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾, Ñ‡Đµ ÑĐ° Đ½Đ°Đ´ĐµĐ¶Đ´Đ½Đ¸. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Đ¡Ñ‚Đ¾Đ¹Đ½Đ¾ÑÑ‚Ñ‚Đ° Đ½Đµ ÑÑĐ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²Đ° Đ½Đ° Ñ„Đ¾Ñ€Đ¼Đ°Ñ‚Đ°.</translation>
<translation id="2704951214193499422">Chromium Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ¿Đ¾Ñ‚Đ²ÑÑ€Đ´Đ¸ ĐºĐ°Ñ€Ñ‚Đ°Ñ‚Đ° Đ²Đ¸. ĐœĐ¾Đ»Ñ, Đ¾Đ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾ Đ¿Đ¾-ĐºÑÑĐ½Đ¾.</translation>
<translation id="2705137772291741111">Đ—Đ°Đ¿Đ°Đ·ĐµĐ½Đ¾Ñ‚Đ¾ (ĐºĐµÑˆĐ¸Ñ€Đ°Đ½Đ¾) ĐºĐ¾Đ¿Đ¸Đµ Đ½Đ° Ñ‚Đ¾Đ·Đ¸ ÑĐ°Đ¹Ñ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Ñе Đ¿Ñ€Đ¾Ñ‡ĐµÑ‚Đµ.</translation>
<translation id="2709516037105925701">ĐĐ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đ¾ Đ¿Đ¾Đ¿ÑĐ»Đ²Đ°Đ½Đµ</translation>
+<translation id="2712118517637785082">ĐĐ°Đ¿Ñ€Đ°Đ²Đ¸Ñ…Ñ‚Đµ Đ¾Đ¿Đ¸Ñ‚ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñ/ÑÑ <ph name="DOMAIN" />, Đ½Đ¾ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´oÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, Đ°Đ½ÑƒĐ»Đ¸Ñ€Đ°Đ½ Đ¾Ñ‚ Đ¸Đ·Đ´Đ°Ñ‚ĐµĐ»Ñ Đ¼Ñƒ. Đ¢Đ¾Đ²Đ° Đ¾Đ·Đ½Đ°Ñ‡Đ°Đ²Đ°, Ñ‡Đµ Đ² Đ½Đ¸ĐºĐ°ĐºÑĐ² ÑĐ»ÑƒÑ‡Đ°Đ¹ Đ½Đµ Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° Ñе Đ´Đ¾Đ²ĐµÑ€ÑĐ²Đ°Ñ‚Đµ Đ½Đ° Đ¿Ñ€ĐµĐ´ÑÑ‚Đ°Đ²ĐµĐ½Đ¸Ñ‚Đµ Đ¾Ñ‚ ÑÑÑ€Đ²ÑÑ€Đ° Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸ Đ´Đ°Đ½Đ½Đ¸ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚. Đ’ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ´Đ° ÑÑ‚Đµ Ñе ÑĐ²ÑÑ€Đ·Đ°Đ»Đ¸ Ñ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Đ˜ÑĐºĐ°Đ½Đµ Đ½Đ° Ñ€Đ°Đ·Ñ€ĐµÑˆĐµĐ½Đ¸Đµ</translation>
<translation id="2721148159707890343">Đ—Đ°ÑĐ²ĐºĐ°Ñ‚Đ° е уÑĐ¿ĐµÑˆĐ½Đ°</translation>
<translation id="2728127805433021124">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° е Đ¿Đ¾Đ´Đ¿Đ¸ÑĐ°Đ½ ÑÑÑ Ñлаб Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚ÑĐ¼.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Đ›ĐµĐ½Ñ‚Đ° Đ·Đ° Đ°Đ´Ñ€ĐµÑи и Đ·Đ° Ñ‚ÑÑ€ÑĐµĐ½Đµ</translation>
<translation id="2826760142808435982">Đ’Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° е ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ° и ÑƒĐ´Đ¾ÑÑ‚Đ¾Đ²ĐµÑ€ĐµĐ½Đ° Đ¿Đ¾ÑÑ€ĐµĐ´ÑÑ‚Đ²Đ¾Đ¼ <ph name="CIPHER" /> и Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° <ph name="KX" /> ĐºĐ°Ñ‚Đ¾ Đ¼ĐµÑ…Đ°Đ½Đ¸Đ·ÑĐ¼ Đ·Đ° Đ¾Đ±Đ¼ĐµĐ½ Đ½Đ° ĐºĐ»ÑÑ‡Đ¾Đ²Đµ.</translation>
<translation id="2835170189407361413">Đ˜Đ·Ñ‡Đ¸ÑÑ‚Đ²Đ°Đ½Đµ Đ½Đ° Ñ„Đ¾Ñ€Đ¼ÑƒĐ»ÑÑ€Đ°</translation>
-<translation id="2837049386027881519">Đ’Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Ñ‚Ñ€ÑĐ±Đ²Đ°ÑˆĐµ Đ´Đ° Ñе Đ¸Đ·Đ¿Ñ€Đ¾Đ±Đ²Đ° Đ¾Ñ‚Đ½Đ¾Đ²Đ¾ Đ¿Đ¾ÑÑ€ĐµĐ´ÑÑ‚Đ²Đ¾Đ¼ Đ¿Đ¾-ÑÑ‚Đ°Ñ€Đ° Đ²ĐµÑ€ÑĐ¸Ñ Đ½Đ° TLS или SSL Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»Đ°. Đ¢Đ¾Đ²Đ° Đ¾Đ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ¾Đ·Đ½Đ°Ñ‡Đ°Đ²Đ°, Ñ‡Đµ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° Đ¼Đ½Đ¾Đ³Đ¾ ÑÑ‚Đ°Ñ€ ÑĐ¾Ñ„Ñ‚ÑƒĐµÑ€ и Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¸Đ¼Đ° Đ´Ñ€ÑƒĐ³Đ¸ Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ¸ ÑÑÑ ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚Ñ‚Đ°.</translation>
<translation id="284702764277384724">Đ˜Đ·Đ³Đ»ĐµĐ¶Đ´Đ°, Ñ‡Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° Đ½Đ° Đ°Đ´Ñ€ĐµÑ <ph name="HOST_NAME" /> е Đ¿Đ¾Đ´Đ¿Ñ€Đ°Đ²ĐµĐ½.</translation>
<translation id="2889159643044928134">Без Đ¿Ñ€ĐµĐ·Đ°Ñ€ĐµĐ¶Đ´Đ°Đ½Đµ</translation>
-<translation id="2896499918916051536">Đ¢Đ°Đ·Đ¸ Đ¿Ñ€Đ¸ÑÑ‚Đ°Đ²ĐºĐ° Đ½Đµ Ñе Đ¿Đ¾Đ´Đ´ÑÑ€Đ¶Đ°.</translation>
+<translation id="2900469785430194048">ĐŸĐ°Đ¼ĐµÑ‚Ñ‚Đ° Đ½Đ° Google Chrome Ñе Đ¸Đ·Ñ‡ĐµÑ€Đ¿Đ°, Đ´Đ¾ĐºĐ°Ñ‚Đ¾ Đ±Ñ€Đ°ÑƒĐ·ÑÑ€ÑÑ‚ Đ¾Đ¿Đ¸Ñ‚Đ²Đ°ÑˆĐµ Đ´Đ° Đ¿Đ¾ĐºĐ°Đ¶Đµ Ñ‚Đ°Đ·Đ¸ ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°.</translation>
<translation id="2909946352844186028">Đ£ÑÑ‚Đ°Đ½Đ¾Đ²ĐµĐ½Đ° бе Đ¿Ñ€Đ¾Đ¼ÑĐ½Đ° Đ² Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ°.</translation>
-<translation id="2915500479781995473">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" /> – ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¸Đ·Ñ‚ĐµĐºÑĐ». Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸ĐºÑÑ‚ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€Đ° Đ²Đ¸ Đ¿Đ¾ĐºĐ°Đ·Đ²Đ° <ph name="CURRENT_TIME" />. Đ¢Đ¾Đ²Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ли е? ĐĐºĐ¾ Đ½Đµ е, Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° ÑĐ²ĐµÑ€Đ¸Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Ñ Ñи Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸Đº и Ñлед Ñ‚Đ¾Đ²Đ° Đ´Đ° Đ¾Đ¿Ñ€ĐµÑĐ½Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°.</translation>
<translation id="2922350208395188000">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° бÑде Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐµĐ½.</translation>
-<translation id="2941952326391522266">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />; ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¾Ñ‚ <ph name="DOMAIN2" />. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ°Ñ‚Đ°ĐºÑƒĐ²Đ°Ñ‰.</translation>
<translation id="2948083400971632585">ĐœĐ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ´ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Ñ‚Đµ Đ²ÑĐ¸Ñ‡ĐºĐ¸ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đ¸ Đ·Đ° Đ´Đ°Đ´ĐµĐ½Đ° Đ²Ñ€ÑĐ·ĐºĐ° Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ¸ Đ¾Ñ‚ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ° â€ĐĐ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸â€œ.</translation>
<translation id="2955913368246107853">Đ—Đ°Ñ‚Đ²Đ°Ñ€ÑĐ½Đµ Đ½Đ° Đ»ĐµĐ½Ñ‚Đ°Ñ‚Đ° Đ·Đ° Ñ‚ÑÑ€ÑĐµĐ½Đµ</translation>
<translation id="2958431318199492670">ĐĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸ÑÑ‚Đ° Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ° Đ½Đµ ÑĐ¿Đ°Đ·Đ²Đ° ÑÑ‚Đ°Đ½Đ´Đ°Ñ€Ñ‚Đ° Đ½Đ° ONC. Đ’ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Ñ‡Đ°ÑÑ‚Đ¸ Đ¾Ñ‚ Đ½ĐµÑ Đ´Đ° Đ½Đµ ÑĐ° Đ¸Đ¼Đ¿Đ¾Ñ€Ñ‚Đ¸Ñ€Đ°Đ½Đ¸.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Đ“Ñ€ĐµÑˆĐµĐ½ Ñ‚Đ¸Đ¿ Đ½Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾</translation>
<translation id="3032412215588512954">Đ˜ÑĐºĐ°Ñ‚Đµ ли Đ´Đ° Đ¿Ñ€ĐµĐ·Đ°Ñ€ĐµĐ´Đ¸Ñ‚Đµ Ñ‚Đ¾Đ·Đ¸ ÑĐ°Đ¹Ñ‚?</translation>
<translation id="3037605927509011580">Đ£Đ¶Đ°Ñ!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{Đ¿Đ¾Đ½Đµ 1 ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½Đ¸ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°}=1{1 ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚ (и Đ´Ñ€ÑƒĐ³Đ¸ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½Đ¸ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°)}other{# ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚Đ° (и Đ´Ñ€ÑƒĐ³Đ¸ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½Đ¸ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°)}}</translation>
<translation id="3041612393474885105">Đ˜Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ Đ·Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°</translation>
<translation id="3063697135517575841">Chrome Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ¿Đ¾Ñ‚Đ²ÑÑ€Đ´Đ¸ ĐºĐ°Ñ€Ñ‚Đ°Ñ‚Đ° Đ²Đ¸. ĐœĐ¾Đ»Ñ, Đ¾Đ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾ Đ¿Đ¾-ĐºÑÑĐ½Đ¾.</translation>
<translation id="3093245981617870298">ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ ÑÑ‚Đµ Đ¾Ñ„Đ»Đ°Đ¹Đ½.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">ĐĐ°Đ¹-Đ½Đ¾Đ²Đ°</translation>
<translation id="3207960819495026254">Đ¡ Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ°</translation>
-<translation id="3225919329040284222">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, ĐºĐ¾Đ¹Ñ‚Đ¾ Đ½Đµ ÑÑĐ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²Đ° Đ½Đ° Đ²Đ³Ñ€Đ°Đ´ĐµĐ½Đ¸Ñ‚Đµ Đ¾Ñ‡Đ°ĐºĐ²Đ°Đ½Đ¸Ñ. Đ¢Đµ ÑĐ° Đ²ĐºĐ»ÑÑ‡ĐµĐ½Đ¸ Đ·Đ° Đ¾Đ¿Ñ€ĐµĐ´ĐµĐ»ĐµĐ½Đ¸ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚Đ¾Đ²Đµ Ñ Đ³Đ¾Đ»ÑĐ¼Đ° ÑÑ‚ĐµĐ¿ĐµĐ½ Đ½Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚, Đ·Đ° Đ´Đ° Đ²Đ¸ Đ¿Ñ€ĐµĐ´Đ¿Đ°Đ·Đ¸Đ¼.</translation>
<translation id="3226128629678568754">ĐĐ°Ñ‚Đ¸ÑĐ½ĐµÑ‚Đµ Đ±ÑƒÑ‚Đ¾Đ½Đ° Đ·Đ° Đ¿Ñ€ĐµĐ·Đ°Ñ€ĐµĐ¶Đ´Đ°Đ½Đµ, Đ·Đ° Đ´Đ° Đ¸Đ·Đ¿Ñ€Đ°Ñ‚Đ¸Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾ Đ´Đ°Đ½Đ½Đ¸Ñ‚Đµ, Đ½ĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ¸ Đ·Đ° Đ¾Ñ‚Đ²Đ°Ñ€ÑĐ½ĐµÑ‚Đ¾ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°.</translation>
<translation id="3228969707346345236">ĐŸÑ€ĐµĐ²Đ¾Đ´ÑÑ‚ Đ½Đµ бе уÑĐ¿ĐµÑˆĐµĐ½, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ° Đ²ĐµÑ‡Đµ е Đ½Đ° <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Đ’ÑĐ²ĐµĐ´ĐµÑ‚Đµ ĐºĐ¾Đ´Đ° Đ·Đ° Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐºĐ° Đ·Đ° <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Đ—Đ°Đ¿Đ°Đ·Đ²Đ°Đ½Đµ Đ½Đ° Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ° ĐºÑĐ¼ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°</translation>
<translation id="3270847123878663523">&amp;ĐÑ‚Đ¼ÑĐ½Đ° Đ½Đ° Đ¿Ñ€ĐµĐ½Đ°Ñ€ĐµĐ¶Đ´Đ°Đ½ĐµÑ‚Đ¾</translation>
<translation id="3286538390144397061">РеÑÑ‚Đ°Ñ€Ñ‚Đ¸Ñ€Đ°Đ½Đµ ÑĐµĐ³Đ°</translation>
+<translation id="3303855915957856445">ĐÑĐ¼Đ° Đ½Đ°Đ¼ĐµÑ€ĐµĐ½Đ¸ Ñ€ĐµĐ·ÑƒĐ»Ñ‚Đ°Ñ‚Đ¸ Đ¾Ñ‚ Ñ‚ÑÑ€ÑĐµĐ½ĐµÑ‚Đ¾</translation>
<translation id="3305707030755673451">ĐĐ° <ph name="TIME" /> Đ´Đ°Đ½Đ½Đ¸Ñ‚Đµ Đ²Đ¸ бÑÑ…Đ° ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¸ Ñ Đ¿Ñ€Đ¾Đ¿ÑƒÑĐºĐ° Đ²Đ¸ Đ·Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½Đµ. Đ’ÑĐ²ĐµĐ´ĐµÑ‚Đµ Đ³Đ¾, Đ·Đ° Đ´Đ° ÑÑ‚Đ°Ñ€Ñ‚Đ¸Ñ€Đ°Ñ‚Đµ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾.</translation>
<translation id="333371639341676808">Да Đ½Đµ Ñе Đ¿Đ¾ĐºĐ°Đ·Đ²Đ°Ñ‚ Đ´Đ¾Đ¿ÑĐ»Đ½Đ¸Ñ‚ĐµĐ»Đ½Đ¸ Đ´Đ¸Đ°Đ»Đ¾Đ³Đ¾Đ²Đ¸ Đ¿Ñ€Đ¾Đ·Đ¾Ñ€Ñ†Đ¸ Đ¾Ñ‚ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°.</translation>
+<translation id="3338095232262050444">Đ˜Đ¼Đ° Đ·Đ°Ñ‰Đ¸Ñ‚Đ°</translation>
<translation id="3340978935015468852">Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸</translation>
<translation id="3345135638360864351">Đ—Đ°ÑĐ²ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ·Đ° Đ´Đ¾ÑÑ‚ÑĐ¿ Đ´Đ¾ Ñ‚Đ¾Đ·Đ¸ ÑĐ°Đ¹Ñ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Ñе Đ¸Đ·Đ¿Ñ€Đ°Ñ‚Đ¸ Đ´Đ¾ <ph name="NAME" />. ĐœĐ¾Đ»Ñ, Đ¾Đ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾.</translation>
<translation id="3355823806454867987">ĐŸÑ€Đ¾Đ¼ÑĐ½Đ° Đ½Đ° Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸Ñ‚Đµ Đ½Đ° Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ°...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Đ˜Đ½Ñ‚ĐµÑ€Đ²Đ°Đ» Đ½Đ° Đ¸Đ·Đ²Đ»Đ¸Ñ‡Đ°Đ½Đµ:</translation>
<translation id="3462200631372590220">Đ¡ĐºÑ€Đ¸Đ²Đ°Đ½Đµ Đ½Đ° Đ¿Đ¾Đ´Ñ€Đ¾Đ±Đ½Đ¾ÑÑ‚Đ¸Ñ‚Đµ</translation>
<translation id="3479539252931486093">Đ¢Đ¾Đ²Đ° Đ½ĐµĐ¾Ñ‡Đ°ĐºĐ²Đ°Đ½Đ¾ ли Đ±ĐµÑˆĐµ? <ph name="BEGIN_LINK" />Đ£Đ²ĐµĐ´Đ¾Đ¼ĐµÑ‚Đµ Đ½Đ¸<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Đе ÑĐµĐ³Đ°</translation>
<translation id="348000606199325318">Đ˜Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¾Ñ€ Đ½Đ° ÑÑ€Đ¸Đ²Đ°: <ph name="CRASH_LOCAL_ID" /> (Đ˜Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¾Ñ€ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ°: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Đе Đ¼Đ¾Đ¶Đ°Ñ…Đ¼Đµ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµĐ¼ Ñ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»Ñ Đ²Đ¸. ĐœĐ¾Đ»Ñ, Đ¾Đ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾.</translation>
<translation id="3527085408025491307">ĐŸĐ°Đ¿ĐºĐ°</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Đ˜Đ·Đ¿Đ¾Đ»Đ·Đ²Đ°Đ½Đµ Đ½Đ° Đ¿Đ°Ñ€Đ¾Đ»Đ°Ñ‚Đ° Đ·Đ°:</translation>
<translation id="3549644494707163724">Đ’ÑĐ¸Ñ‡ĐºĐ¸ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½Đ¸ Đ´Đ°Đ½Đ½Đ¸ Đ´Đ° Ñе ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Ñ‚ ÑÑÑ ÑĐ¾Đ±ÑÑ‚Đ²ĐµĐ½Đ¸Ñ Đ²Đ¸ Đ¿Ñ€Đ¾Đ¿ÑƒÑĐº Đ·Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½Đµ</translation>
<translation id="3549761410225185768">ĐÑ‰Đµ <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¾Ñ‚ <ph name="DOMAIN2" />. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Đ’Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ½Đµ е Đ¿Đ¾Đ²ĐµÑ€Đ¸Ñ‚ĐµĐ»Đ½Đ°</translation>
<translation id="3583757800736429874">&amp;Đ’ÑĐ·ÑÑ‚Đ°Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ¿Ñ€ĐµĐ¼ĐµÑÑ‚Đ²Đ°Đ½ĐµÑ‚Đ¾</translation>
<translation id="3586931643579894722">Đ¡ĐºÑ€Đ¸Đ²Đ°Đ½Đµ Đ½Đ° Đ¿Đ¾Đ´Ñ€Đ¾Đ±Đ½Đ¾ÑÑ‚Đ¸Ñ‚Đµ</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">ĐŸĐ¾ĐºĐ°Đ·Đ²Đ°Đ½Đµ Đ½Đ° ÑÑ‚Đ¾Đ¹Đ½Đ¾ÑÑ‚Ñ‚Đ°</translation>
<translation id="3630155396527302611">ĐĐºĐ¾ Đ±Ñ€Đ°ÑƒĐ·ÑÑ€ÑÑ‚ Đ²ĐµÑ‡Đµ е Đ² ÑĐ¿Đ¸ÑÑĐºĐ° Ñ Đ¿Ñ€Đ¾Đ³Ñ€Đ°Đ¼Đ¸ Ñ Ñ€Đ°Đ·Ñ€ĐµÑˆĐµĐ½ Đ´Đ¾ÑÑ‚ÑĐ¿ Đ´Đ¾ Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ°, Đ¾Đ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ
Đ´Đ° Đ³Đ¾ Đ¿Ñ€ĐµĐ¼Đ°Ñ…Đ½ĐµÑ‚Đµ Đ¾Ñ‚Ñ‚Đ°Đ¼ и Đ´Đ° Đ³Đ¾ Đ´Đ¾Đ±Đ°Đ²Đ¸Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾.</translation>
+<translation id="3638794133396384728">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¸Đ·Ñ‚ĐµĐºÑĐ». Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸ĐºÑÑ‚ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€Đ° Đ²Đ¸ Đ¿Đ¾ĐºĐ°Đ·Đ²Đ° <ph name="CURRENT_TIME" />. Đ¢Đ¾Đ²Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ли е? ĐĐºĐ¾ Đ½Đµ е, Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° ÑĐ²ĐµÑ€Đ¸Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Ñ Ñи Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸Đº и Ñлед Ñ‚Đ¾Đ²Đ° Đ´Đ° Đ¾Đ¿Ñ€ĐµÑĐ½Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Đ¢ĐµĐ·Đ¸ ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ°Đ»Đ½Đ¸ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¸ Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ¿Ñ€Đ¾Đ¼ĐµĐ½ÑÑ‚, Đ¿Đ¾Đ²Ñ€ĐµĐ´ÑÑ‚ или Đ¸Đ·Ñ‡ĐµĐ·Đ½Đ°Ñ‚ Đ¿Đ¾ Đ²ÑÑĐºĐ¾ Đ²Ñ€ĐµĐ¼Đµ. Đе Đ´Đ°Đ²Đ°Đ¼Đµ абÑĐ¾Đ»ÑÑ‚Đ½Đ¾ Đ½Đ¸ĐºĐ°ĐºĐ²Đ° Đ³Đ°Ñ€Đ°Đ½Ñ†Đ¸Ñ ĐºĐ°ĐºĐ²Đ¾ Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе ÑĐ»ÑƒÑ‡Đ¸, Đ°ĐºĐ¾ Đ²ĐºĐ»ÑÑ‡Đ¸Ñ‚Đµ Đ½ÑĐºĐ¾Ñ Đ¾Ñ‚ Ñ‚ÑÑ…. Đ’ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ´Đ¾Ñ€Đ¸ Đ±Ñ€Đ°ÑƒĐ·ÑÑ€ÑÑ‚ Đ²Đ¸ ÑĐ¿Đ¾Đ½Ñ‚Đ°Đ½Đ½Đ¾ Đ´Đ° Ñе ÑĐ°Đ¼Đ¾Đ·Đ°Đ¿Đ°Đ»Đ¸. Đ¨ĐµĐ³Đ°Ñ‚Đ° Đ½Đ°ÑÑ‚Ñ€Đ°Đ½Đ¸, Đ±Ñ€Đ°ÑƒĐ·ÑÑ€ÑÑ‚ Đ²Đ¸ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¸Đ·Ñ‚Ñ€Đ¸Đµ Đ²ÑĐ¸Ñ‡ĐºĐ¸Ñ‚Đµ Đ²Đ¸ Đ´Đ°Đ½Đ½Đ¸ или ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚Ñ‚Đ° и Đ¿Đ¾Đ²ĐµÑ€Đ¸Ñ‚ĐµĐ»Đ½Đ¾ÑÑ‚Ñ‚Đ° Đ²Đ¸ Đ¼Đ¾Đ¶Đµ Đ´Đ° бÑĐ´Đ°Ñ‚ ĐºĐ¾Đ¼Đ¿Ñ€Đ¾Đ¼ĐµÑ‚Đ¸Ñ€Đ°Đ½Đ¸ Đ¿Đ¾ Đ½ĐµĐ¾Ñ‡Đ°ĐºĐ²Đ°Đ½Đ¸ Đ½Đ°Ñ‡Đ¸Đ½Đ¸. ĐĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đ¸Ñ‚Đµ Đ¾Ñ‚ Đ²Đ°Ñ ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ¸ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚ÑÑ‚ Đ·Đ° Đ²ÑĐ¸Ñ‡ĐºĐ¸ Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»Đ¸ Đ½Đ° Ñ‚Đ¾Đ·Đ¸ Đ±Ñ€Đ°ÑƒĐ·ÑÑ€. ĐœĐ¾Đ»Ñ, Đ´ĐµĐ¹ÑÑ‚Đ²Đ°Đ¹Ñ‚Đµ Đ²Đ½Đ¸Đ¼Đ°Ñ‚ĐµĐ»Đ½Đ¾.</translation>
<translation id="3650584904733503804">ĐŸĐ¾Ñ‚Đ²ÑÑ€Đ¶Đ´Đ°Đ²Đ°Đ½ĐµÑ‚Đ¾ е уÑĐ¿ĐµÑˆĐ½Đ¾</translation>
<translation id="3655670868607891010">ĐĐºĐ¾ Đ²Đ¸Đ¶Đ´Đ°Ñ‚Đµ Ñ‚Đ¾Đ²Đ° Ñ‡ĐµÑÑ‚Đ¾, Đ¾Đ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Đ ĐµĐ²Đ¸Đ·Đ¸Ñ</translation>
+<translation id="3678029195006412963">Đ—Đ°ÑĐ²ĐºĐ°Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° бÑде Đ¿Đ¾Đ´Đ¿Đ¸ÑĐ°Đ½Đ°</translation>
<translation id="3681007416295224113">Đ˜Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ Đ·Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°</translation>
<translation id="3693415264595406141">ĐŸĐ°Ñ€Đ¾Đ»Đ°:</translation>
+<translation id="3696411085566228381">Đ½ÑĐ¼Đ°</translation>
<translation id="3700528541715530410">ĐĐ¼Đ¸ ÑĐµĐ³Đ°! Đ˜Đ·Đ³Đ»ĐµĐ¶Đ´Đ°, Ñ‡Đµ Đ½ÑĐ¼Đ°Ñ‚Đµ Ñ€Đ°Đ·Ñ€ĐµÑˆĐµĐ½Đ¸Đµ Đ·Đ° Đ´Đ¾ÑÑ‚ÑĐ¿ Đ´Đ¾ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> â€<ph name="TITLE" />“ <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Đ—Đ°Ñ€ĐµĐ¶Đ´Đ° Ñе...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Đ’ĐºĐ»ÑÑ‡ĐµÑ‚Đµ Đ¼Đ¾Đ±Đ¸Đ»Đ½Đ¸Ñ‚Đµ Đ´Đ°Đ½Đ½Đ¸ или Wi-Fi.</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ²ĐµÑ€ĐµÑ‚Đµ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸ÑÑ‚Đ° Đ½Đ° Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ°, Đ·Đ°Ñ‰Đ¸Ñ‚Đ½Đ°Ñ‚Đ° ÑÑ‚ĐµĐ½Đ° и DNS<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">ĐĐ¾Đ¿Đ¸Ñ€Đ°Đ½Đ° Đ¾Ñ‚ Đ²Đ°Ñ Đ²Ñ€ÑĐ·ĐºĐ°</translation>
-<translation id="3744899669254331632">Đ’ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" />, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚ÑÑ‚ Đ¸Đ·Đ¿Ñ€Đ°Ñ‚Đ¸ ĐºĐ¾Đ´Đ¸Ñ€Đ°Đ½Đ¸ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸ Đ´Đ°Đ½Đ½Đ¸, ĐºĐ¾Đ¸Ñ‚Đ¾ Chromium Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾Đ±Ñ€Đ°Đ±Đ¾Ñ‚Đ¸. ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ³Ñ€ĐµÑˆĐºĐ¸Ñ‚Đµ Đ² Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ° и Đ°Ñ‚Đ°ĐºĐ¸Ñ‚Đµ ÑÑ€ĐµÑ‰Ñƒ Đ½ĐµÑ ÑĐ° Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¸, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Đ¿Đ¾-ĐºÑÑĐ½Đ¾.</translation>
<translation id="375403751935624634">ĐŸÑ€ĐµĐ²Đ¾Đ´ÑÑ‚ Đ½Đµ бе уÑĐ¿ĐµÑˆĐµĐ½ Đ¿Đ¾Ñ€Đ°Đ´Đ¸ Đ³Ñ€ĐµÑˆĐºĐ° Đ² ÑÑÑ€Đ²ÑÑ€Đ°.</translation>
<translation id="3759461132968374835">ĐĐ°ÑĐºĐ¾Ñ€Đ¾ Đ½Đµ ÑÑ‚Đµ ÑÑĐ¾Đ±Ñ‰Đ°Đ²Đ°Đ»Đ¸ Đ·Đ° ÑÑ€Đ¸Đ²Đ¾Đ²Đµ. Đ¢ĐµĐ·Đ¸, Đ²ÑĐ·Đ½Đ¸ĐºĐ½Đ°Đ»Đ¸ Đ¿Ñ€Đ¸ Đ´ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đ¾ Đ¸Đ·Đ¿Ñ€Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° ÑĐ¸Đ³Đ½Đ°Đ»Đ¸ Đ·Đ° ÑÑ€Đ¸Đ²Đ¾Đ²Đµ, Đ½Đµ Ñе Đ¿Đ¾ĐºĐ°Đ·Đ²Đ°Ñ‚ Ñ‚ÑƒĐº.</translation>
<translation id="3788090790273268753">Đ’Đ°Đ»Đ¸Đ´Đ½Đ¾ÑÑ‚Ñ‚Đ° Đ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ·Đ° Ñ‚Đ¾Đ·Đ¸ ÑĐ°Đ¹Ñ‚ Đ¸Đ·Ñ‚Đ¸Ñ‡Đ° Đ¿Ñ€ĐµĐ· 2016 Đ³., Đ° ÑÑĐ¾Ñ‚Đ²ĐµÑ‚Đ½Đ°Ñ‚Đ° Đ²ĐµÑ€Đ¸Đ³Đ° ÑÑĐ´ÑÑ€Đ¶Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, Đ¿Đ¾Đ´Đ¿Đ¸ÑĐ°Đ½ Ñ SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Đ˜Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸ÑÑ‚ Đ½Đ¾Đ¼ĐµÑ€ Đ½Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾Ñ‚Đ¾ е Đ½ĐµÑÑĐ²Đ¼ĐµÑÑ‚Đ¸Đ¼</translation>
<translation id="3885155851504623709">ĐĐ±Ñ‰Đ¸Đ½Đ°</translation>
<translation id="3901925938762663762">ĐĐ°Ñ€Ñ‚Đ°Ñ‚Đ° е Ñ Đ¸Đ·Ñ‚ĐµĐºĐ»Đ° Đ²Đ°Đ»Đ¸Đ´Đ½Đ¾ÑÑ‚</translation>
+<translation id="3910267023907260648">ĐĐ°Đ¿Ñ€Đ°Đ²Đ¸Ñ…Ñ‚Đµ Đ¾Đ¿Đ¸Ñ‚ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñ/ÑÑ <ph name="DOMAIN" />, Đ½Đ¾ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, Đ¿Đ¾Đ´Đ¿Đ¸ÑĐ°Đ½ ÑÑÑ Ñлаб Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚ÑĐ¼. Đ¢Đ¾Đ²Đ° Đ¾Đ·Đ½Đ°Ñ‡Đ°Đ²Đ°, Ñ‡Đµ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸Ñ‚Đµ Đ´Đ°Đ½Đ½Đ¸ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ¾Ñ‚ ÑÑÑ€Đ²ÑÑ€Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° ÑĐ° Ñ„Đ°Đ»ÑˆĐ¸Ñ„Đ¸Ñ†Đ¸Ñ€Đ°Đ½Đ¸ и Ñ‚Đ¾Đ¹ Đ´Đ° Đ½Đµ е Ñ‚Đ¾Đ·Đ¸, ĐºĐ¾Đ¹Ñ‚Đ¾ Đ¾Ñ‡Đ°ĐºĐ²Đ°Ñ‚Đµ (Đ²ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ´Đ° ÑÑ‚Đµ Ñе ÑĐ²ÑÑ€Đ·Đ°Đ»Đ¸ Ñ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°). <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¾Ñ‚ ÑƒÑ‚Ñ€Đµ. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.}other{Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ е Đ¾Ñ‚ # Đ´Đ½Đ¸ Đ² бÑĐ´ĐµÑ‰ĐµÑ‚Đ¾. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF Đ´Đ¾ĐºÑƒĐ¼ĐµĐ½Ñ‚ÑÑ‚ Đ½Đµ уÑĐ¿Ñ Đ´Đ° Ñе Đ·Đ°Ñ€ĐµĐ´Đ¸</translation>
<translation id="3963721102035795474">Đ ĐµĐ¶Đ¸Đ¼ Đ·Đ° Ñ‡ĐµÑ‚ĐµĐ½Đµ</translation>
+<translation id="397105322502079400">Đ˜Đ·Ñ‡Đ¸ÑĐ»ÑĐ²Đ° Ñе...</translation>
<translation id="3973234410852337861">Đ¥Đ¾ÑÑ‚ÑÑ‚ <ph name="HOST_NAME" /> е Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ² Đ±Đ»Đ¸Đ·Đ¾ÑÑ‚}other{# ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ¸ Đ² Đ±Đ»Đ¸Đ·Đ¾ÑÑ‚}}</translation>
<translation id="4021036232240155012">DNS е уÑĐ»ÑƒĐ³Đ°Ñ‚Đ° Đ·Đ° Đ¼Ñ€ĐµĐ¶Đ¸, ĐºĐ¾ÑÑ‚Đ¾ Đ¿Ñ€ĐµĐ¾Đ±Ñ€Đ°Đ·ÑƒĐ²Đ° Đ¸Đ¼ĐµĐ½Đ°Ñ‚Đ° Đ½Đ° ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚Đ¾Đ²ĐµÑ‚Đµ ĐºÑĐ¼ Ñ‚ĐµÑ…Đ½Đ¸Ñ‚Đµ Đ°Đ´Ñ€ĐµÑи Đ² Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚.</translation>
<translation id="4030383055268325496">&amp;ĐÑ‚Đ¼ÑĐ½Đ° Đ½Đ° Đ´Đ¾Đ±Đ°Đ²ÑĐ½ĐµÑ‚Đ¾</translation>
-<translation id="4032534284272647190">Đ”Đ¾ÑÑ‚ÑĐ¿ÑÑ‚ Đ´Đ¾ <ph name="URL" /> бе Đ¾Ñ‚ĐºĐ°Đ·Đ°Đ½.</translation>
<translation id="404928562651467259">ĐŸĐ Đ•Đ”Đ£ĐŸĐ Đ•Đ–Đ”Đ•ĐĐ˜Đ•</translation>
<translation id="4058922952496707368">ĐĐ»Ñч â€<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">ĐĐ»Đ¸ĐµĐ½Ñ‚ÑÑ‚ и ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¿Đ¾Đ´Đ´ÑÑ€Đ¶Đ°Ñ‚ Đ¾Đ±Ñ‰Đ° Đ²ĐµÑ€ÑĐ¸Ñ Đ¸Đ»Đ¸ Đ¿Đ°ĐºĐµÑ‚ Đ·Đ° ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đµ Đ·Đ° Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»Đ° SSL.</translation>
<translation id="4079302484614802869">Đ—Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸ÑÑ‚Đ° Đ½Đ° Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ° е Đ·Đ°Đ´Đ°Đ´ĐµĐ½Đ¾ Đ´Đ° Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° URL Đ°Đ´Ñ€ĐµÑ Đ½Đ° ÑĐºÑ€Đ¸Đ¿Ñ‚ Đ²ÑĐ² Ñ„Đ¾Ñ€Đ¼Đ°Ñ‚ .pac, Đ° Đ½Đµ Ñ„Đ¸ĐºÑĐ¸Ñ€Đ°Đ½Đ¸ Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ¸.</translation>
<translation id="4103249731201008433">Đ¡ĐµÑ€Đ¸Đ¹Đ½Đ¸ÑÑ‚ Đ½Đ¾Đ¼ĐµÑ€ Đ½Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾Ñ‚Đ¾ е Đ½ĐµĐ²Đ°Đ»Đ¸Đ´ĐµĐ½</translation>
<translation id="4103763322291513355">ĐŸĐ¾ÑĐµÑ‚ĐµÑ‚Đµ &lt;strong&gt;chrome://policy&lt;/strong&gt;, Đ·Đ° Đ´Đ° Đ²Đ¸Đ´Đ¸Ñ‚Đµ Đ¸Đ·Đ±Ñ€Đ¾ĐµĐ½Đ¸ URL Đ°Đ´Ñ€ĐµÑĐ¸Ñ‚Đµ Đ² Ñ‡ĐµÑ€Đ½Đ¸Ñ ÑĐ¿Đ¸ÑÑĐº и Đ´Ñ€ÑƒĐ³Đ¸Ñ‚Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°, Đ½Đ°Đ»Đ¾Đ¶ĐµĐ½Đ¸ Đ¾Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Ñ Đ²Đ¸ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€.</translation>
+<translation id="4110615724604346410">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ ÑÑĐ´ÑÑ€Đ¶Đ° Đ³Ñ€ĐµÑˆĐºĐ¸. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">ĐĐ±Ñ…Đ²Đ°Ñ‚ÑÑ‚ Đ½Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°Ñ‚Đ° Đ½Đµ Ñе Đ¿Đ¾Đ´Đ´ÑÑ€Đ¶Đ°.</translation>
+<translation id="4118212371799607889">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ½Đµ Ñе ÑÑ‡Đ¸Ñ‚Đ° Đ·Đ° Đ½Đ°Đ´ĐµĐ¶Đ´ĐµĐ½ Đ¾Ñ‚ Chromium. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{Đ¾Ñ‰Đµ 1 ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚}other{Đ¾Ñ‰Đµ # ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚Đ°}}</translation>
<translation id="4130226655945681476">ĐŸÑ€Đ¾Đ²ĐµÑ€ĐµÑ‚Đµ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ¸Ñ‚Đµ ĐºĐ°Đ±ĐµĐ»Đ¸, Đ¼Đ¾Đ´ĐµĐ¼Đ° и Đ¼Đ°Ñ€ÑˆÑ€ÑƒÑ‚Đ¸Đ·Đ°Ñ‚Đ¾Ñ€Đ°.</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Đ˜ÑĐºĐ°Ñ‚Đµ ли Chromium Đ´Đ° Đ·Đ°Đ¿Đ°Đ·Đ¸ Ñ‚Đ°Đ·Đ¸ ĐºĐ°Ñ€Ñ‚Đ°?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Đ”ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đ¾</translation>
<translation id="4196861286325780578">&amp;Đ’ÑĐ·ÑÑ‚Đ°Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ¿Ñ€ĐµĐ¼ĐµÑÑ‚Đ²Đ°Đ½ĐµÑ‚Đ¾</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ²ĐµÑ€ĐµÑ‚Đµ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸ÑÑ‚Đ° Đ½Đ° Đ·Đ°Ñ‰Đ¸Ñ‚Đ½Đ°Ñ‚Đ° ÑÑ‚ĐµĐ½Đ° и Đ°Đ½Ñ‚Đ¸Đ²Đ¸Ñ€ÑƒÑĐ½Đ¸Ñ ÑĐ¾Ñ„Ñ‚ÑƒĐµÑ€<ph name="END_LINK" />.</translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{Đ½ÑĐ¼Đ°}=1{1 Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Đµ ($1)}=2{2 Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ ($1, $2)}other{# Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Đ¡Ñ€Đ¸Đ²Đ¾Đ²Đµ</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />ĐĐ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ´Đ° ÑÑ‚Đ°Ñ€Ñ‚Đ¸Ñ€Đ°Ñ‚Đµ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ° Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºĐ°<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Đе</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(ĐÑĐ¼Đ° Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»ÑĐºĐ¾ Đ¸Đ¼Đµ)</translation>
<translation id="4300246636397505754">ĐÑĐ½Đ¾Đ²Đ½Đ¸ Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ</translation>
<translation id="4304224509867189079">Đ’Ñ…Đ¾Đ´</translation>
+<translation id="432290197980158659">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, ĐºĐ¾Đ¹Ñ‚Đ¾ Đ½Đµ ÑÑĐ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²Đ° Đ½Đ° Đ²Đ³Ñ€Đ°Đ´ĐµĐ½Đ¸Ñ‚Đµ Đ¾Ñ‡Đ°ĐºĐ²Đ°Đ½Đ¸Ñ. Đ¡ Ñ†ĐµĐ» Đ²Đ°ÑˆĐ° Đ·Đ°Ñ‰Đ¸Ñ‚Đ° Ñ‚Đµ ÑĐ° Đ²ĐºĐ»ÑÑ‡ĐµĐ½Đ¸ Đ·Đ° Đ¾Đ¿Ñ€ĐµĐ´ĐµĐ»ĐµĐ½Đ¸ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚Đ¾Đ²Đµ Ñ Đ³Đ¾Đ»ÑĐ¼Đ° ÑÑ‚ĐµĐ¿ĐµĐ½ Đ½Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">ĐĐ°Đ¼Đ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° ÑÑ‚Đ°Ñ‚Đ¸ÑÑ‚Đ° Đ½Đµ бе уÑĐ¿ĐµÑˆĐ½Đ¾</translation>
+<translation id="4331708818696583467">ĐÑĐ¼Đ° Đ·Đ°Ñ‰Đ¸Ñ‚Đ°</translation>
<translation id="4372948949327679948">ĐÑ‡Đ°ĐºĐ²Đ°Đ½Đ° е ÑÑ‚Đ¾Đ¹Đ½Đ¾ÑÑ‚ Đ¾Ñ‚ Ñ‚Đ¸Đ¿ <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">ĐĐ°Đ¿Ñ€Đ°Đ²Đ¸Ñ…Ñ‚Đµ Đ¾Đ¿Đ¸Ñ‚ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñ/ÑÑ <ph name="DOMAIN" />, Đ½Đ¾ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´oÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, Đ°Đ½ÑƒĐ»Đ¸Ñ€Đ°Đ½ Đ¾Ñ‚ Đ¸Đ·Đ´Đ°Ñ‚ĐµĐ»Ñ Ñи. Đ¢Đ¾Đ²Đ° Đ¾Đ·Đ½Đ°Ñ‡Đ°Đ²Đ°, Ñ‡Đµ Đ² Đ½Đ¸ĐºĐ°ĐºÑĐ² ÑĐ»ÑƒÑ‡Đ°Đ¹ Đ½Đµ Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° Ñе Đ´Đ¾Đ²ĐµÑ€ÑĐ²Đ°Ñ‚Đµ Đ½Đ° Đ¿Ñ€ĐµĐ´ÑÑ‚Đ°Đ²ĐµĐ½Đ¸Ñ‚Đµ Đ¾Ñ‚ ÑÑÑ€Đ²ÑÑ€Đ° Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸ Đ´Đ°Đ½Đ½Đ¸ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚. Đ’ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ´Đ° ÑÑ‚Đµ Ñе ÑĐ²ÑÑ€Đ·Đ°Đ»Đ¸ Ñ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°.</translation>
<translation id="4381091992796011497">ĐŸĐ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»ÑĐºĐ¾ Đ¸Đ¼Đµ:</translation>
<translation id="4394049700291259645">Đ”ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đµ</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> Đ´Đ¾ <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">Ñ€ĐµĐ·ÑƒĐ»Ñ‚Đ°Ñ‚Đ° Đ¾Ñ‚ Ñ‚ÑÑ€ÑĐµĐ½ĐµÑ‚Đ¾</translation>
-<translation id="4424024547088906515">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />; Chrome Đ½ÑĐ¼Đ° Đ´Đ¾Đ²ĐµÑ€Đ¸Đµ Đ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ°Ñ‚Đ°ĐºÑƒĐ²Đ°Ñ‰.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> Đ½Đµ Đ¿Ñ€Đ¸Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ·Đ° Đ²Ñ…Đ¾Đ´ или е Đ²ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ Đ´Đ° Đ½Đµ е Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²ĐµĐ½ Ñ‚Đ°ĐºÑĐ².</translation>
<translation id="443673843213245140">Đ˜Đ·Đ¿Đ¾Đ»Đ·Đ²Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€ е Đ´ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đ¾, Đ½Đ¾ е Đ¿Đ¾ÑĐ¾Ñ‡ĐµĐ½Đ° Đ¸Đ·Ñ€Đ¸Ñ‡Đ½Đ° Đ½ĐµĐ³Đ¾Đ²Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Đ’Đ¸Đ¶Đ´Đ°Ñ‚Đµ Ñ‚Đ¾Đ²Đ° ÑÑĐ¾Đ±Ñ‰ĐµĐ½Đ¸Đµ, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ Ñ„Đ¸Đ»Ñ‚ÑÑ€ÑÑ‚ Google SafeSites е Đ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½Đ¾ÑÑ‚Đ¸</translation>
<translation id="4558551763791394412">ĐĐ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ´Đ° Đ´ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Ñ‚Đµ Ñ€Đ°Đ·ÑˆĐ¸Ñ€ĐµĐ½Đ¸ÑÑ‚Đ°.</translation>
<translation id="4587425331216688090">ĐĐ´Ñ€ĐµÑÑÑ‚ Đ´Đ° Ñе Đ¿Ñ€ĐµĐ¼Đ°Ñ…Đ½Đµ ли Đ¾Ñ‚ Chrome?</translation>
+<translation id="4589078953350245614">ĐĐ¿Đ¸Ñ‚Đ°Ñ…Ñ‚Đµ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñ/ÑÑ <ph name="DOMAIN" />, Đ½Đ¾ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ Đ½ĐµĐ²Đ°Đ»Đ¸Đ´ĐµĐ½ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Đ’Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Ñ/ÑÑ <ph name="DOMAIN" /> е ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ° ÑÑÑ ÑÑĐ²Ñ€ĐµĐ¼ĐµĐ½ĐµĐ½ ĐºÑ€Đ¸Đ¿Ñ‚Đ¾Đ³Ñ€Đ°Ñ„ÑĐºĐ¸ Đ¿Đ°ĐºĐµÑ‚.</translation>
<translation id="4594403342090139922">&amp;ĐÑ‚Đ¼ÑĐ½Đ° Đ½Đ° Đ¸Đ·Ñ‚Ñ€Đ¸Đ²Đ°Đ½ĐµÑ‚Đ¾</translation>
+<translation id="4627442949885028695">ĐŸÑ€Đ¾Đ´ÑĐ»Đ¶Đ°Đ²Đ°Đ½Đµ Đ¾Ñ‚ Đ´Ñ€ÑƒĐ³Đ¾ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">ĐŸÑ€ĐµĐ³Đ»ĐµĐ¶Đ´Đ°Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ½Đ° Ñ€Đ°Đ·ÑˆĐ¸Ñ€ĐµĐ½Đ¸Đµ.</translation>
-<translation id="467662567472608290">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />; ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ ÑÑĐ´ÑÑ€Đ¶Đ° Đ³Ñ€ĐµÑˆĐºĐ¸. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ°Ñ‚Đ°ĐºÑƒĐ²Đ°Ñ‰.</translation>
-<translation id="4697214168136963651">Đ—Đ°ÑĐ²ĐºĐ°Ñ‚Đ° <ph name="URL" /> бе Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½Đ°</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Đ’Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ бе Đ¿Ñ€ĐµĐºÑÑĐ½Đ°Ñ‚Đ°</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Đ¡Ñ‚Đ°Ñ€Ñ‚Đ¸Ñ€Đ°Đ¹Ñ‚Đµ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ° Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºĐ° Đ² Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">ĐŸĐ»Đ°Ñ‚Ñ„Đ¾Ñ€Đ¼Đ°</translation>
<translation id="4744603770635761495">ĐŸÑÑ‚ ĐºÑĐ¼ Đ¸Đ·Đ¿ÑĐ»Đ½Đ¸Đ¼Đ¸Ñ Ñ„Đ°Đ¹Đ»</translation>
<translation id="4756388243121344051">&amp;Đ˜ÑÑ‚Đ¾Ñ€Đ¸Ñ</translation>
+<translation id="4759238208242260848">Đ˜Đ·Ñ‚ĐµĐ³Đ»ÑĐ½Đ¸Ñ</translation>
<translation id="4764776831041365478">Đ”Đ¾ ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ° Đ½Đ° Đ°Đ´Ñ€ĐµÑ <ph name="URL" /> Đ¼Đ¾Đ¶Đµ Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¾ Đ´Đ° Đ½ÑĐ¼Đ° Đ´Đ¾ÑÑ‚ÑĐ¿ или Đ´Đ° е Đ¿Ñ€ĐµĐ¼ĐµÑÑ‚ĐµĐ½Đ° Đ·Đ° Đ¿Đ¾ÑÑ‚Đ¾ÑĐ½Đ½Đ¾ Đ½Đ° Đ½Đ¾Đ² ÑƒĐµĐ± Đ°Đ´Ñ€ĐµÑ.</translation>
<translation id="4771973620359291008">Đ’ÑĐ·Đ½Đ¸ĐºĐ½Đ° Đ½ĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ° Đ³Ñ€ĐµÑˆĐºĐ°.</translation>
<translation id="4782449893814226250">ĐŸĐ¾Đ¿Đ¸Ñ‚Đ°Ñ…Ñ‚Đµ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»Đ¸Ñ‚Đµ Ñи дали Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°.</translation>
<translation id="4800132727771399293">ĐŸÑ€ĐµĐ³Đ»ĐµĐ´Đ°Đ¹Ñ‚Đµ Đ´Đ°Ñ‚Đ°Ñ‚Đ° Đ½Đ° Đ²Đ°Đ»Đ¸Đ´Đ½Đ¾ÑÑ‚ и ĐºĐ¾Đ´Đ° Đ·Đ° Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐºĐ° и Đ¾Đ¿Ñ‚Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾</translation>
-<translation id="4807049035289105102">Đ’ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" />, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚ÑÑ‚ Đ¸Đ·Đ¿Ñ€Đ°Ñ‚Đ¸ ĐºĐ¾Đ´Đ¸Ñ€Đ°Đ½Đ¸ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸ Đ´Đ°Đ½Đ½Đ¸, ĐºĐ¾Đ¸Ñ‚Đ¾ Google Chrome Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾Đ±Ñ€Đ°Đ±Đ¾Ñ‚Đ¸. ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ³Ñ€ĐµÑˆĐºĐ¸Ñ‚Đµ Đ² Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ° и Đ°Ñ‚Đ°ĐºĐ¸Ñ‚Đµ ÑÑ€ĐµÑ‰Ñƒ Đ½ĐµÑ ÑĐ° Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¸, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Đ¿Đ¾-ĐºÑÑĐ½Đ¾.</translation>
<translation id="4813512666221746211">Đ“Ñ€ĐµÑˆĐºĐ° Đ² Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ°</translation>
<translation id="4816492930507672669">Да Ñе Đ¿Đ¾Đ±ĐµÑ€Đµ Đ² ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°</translation>
<translation id="4850886885716139402">Đ˜Đ·Đ³Đ»ĐµĐ´</translation>
<translation id="4880827082731008257">Đ¢ÑÑ€ÑĐµĐ½Đµ Đ² иÑÑ‚Đ¾Ñ€Đ¸ÑÑ‚Đ°</translation>
+<translation id="4884656795097055129">Đ’ Đ¿Đ¾Đ´Ñ…Đ¾Đ´ÑÑ‰Đ¸Ñ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚ Ñ‰Đµ Ñе Đ¿Đ¾ĐºĐ°Đ¶Đ°Ñ‚ Đ¾Ñ‰Đµ ÑÑ‚Đ°Ñ‚Đ¸Đ¸.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> и <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{и Đ¾Ñ‰Đµ 1 ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°}other{и Đ¾Ñ‰Đµ # ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ¸}}</translation>
<translation id="4923417429809017348">Đ¢Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° е Đ¿Ñ€ĐµĐ²ĐµĐ´ĐµĐ½Đ° Đ¾Ñ‚ Đ½ĐµĐ¿Đ¾Đ·Đ½Đ°Ñ‚ ĐµĐ·Đ¸Đº Đ½Đ° <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Đ¢Ñ€ÑĐ±Đ²Đ° Đ´Đ° Ñе Đ¿Đ¾ÑĐ¾Ñ‡Đ¸.</translation>
<translation id="4930497775425430760">Đ’Đ¸Đ¶Đ´Đ°Ñ‚Đµ Ñ‚Đ¾Đ²Đ° ÑÑĐ¾Đ±Ñ‰ĐµĐ½Đ¸Đµ, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»ÑÑ‚ Đ²Đ¸ Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° Đ¾Đ´Đ¾Đ±Ñ€Đ¸ Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑĐ°Đ¹Ñ‚Đ¾Đ²Đµ Đ¿Ñ€Đ¸ Đ¿ÑÑ€Đ²Đ¾Ñ‚Đ¾ Đ²Đ¸ Đ¿Đ¾ÑĐµÑ‰ĐµĐ½Đ¸Đµ.</translation>
<translation id="495170559598752135">Đ”ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ</translation>
<translation id="4958444002117714549">Đ Đ°Đ·Đ³ÑĐ²Đ°Đ½Đµ Đ½Đ° ÑĐ¿Đ¸ÑÑĐºĐ°</translation>
+<translation id="4962322354953122629">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ½Đµ Ñе ÑÑ‡Đ¸Ñ‚Đ° Đ·Đ° Đ½Đ°Đ´ĐµĐ¶Đ´ĐµĐ½ Đ¾Ñ‚ Chrome. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Да Ñе Đ¿Ñ€ĐµĐ²ĐµĐ´Đµ ли Đ¾Ñ‚ <ph name="ORIGINAL_LANGUAGE" /> Đ½Đ° <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Đ¢Đ°Đ·Đ¸ Đ¿Ñ€Đ¸ÑÑ‚Đ°Đ²ĐºĐ° Đ½Đµ Ñе Đ¿Đ¾Đ´Đ´ÑÑ€Đ¶Đ°</translation>
<translation id="5002932099480077015">ĐĐºĐ¾ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Ñ‚Đ° е Đ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đ°, ĐºĐ¾Đ¿Đ¸Đµ Đ½Đ° ĐºĐ°Ñ€Ñ‚Đ°Ñ‚Đ° Đ²Đ¸ Ñ‰Đµ Ñе ÑÑÑ…Ñ€Đ°Đ½ÑĐ²Đ° Đ² Chrome Đ½Đ° Ñ‚Đ¾Đ²Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾ Ñ Ñ†ĐµĐ» Đ¿Đ¾-бÑÑ€Đ·Đ¾ Đ¿Đ¾Đ¿ÑĐ»Đ²Đ°Đ½Đµ Đ½Đ° Ñ„Đ¾Ñ€Đ¼ÑƒĐ»ÑÑ€Đ¸.</translation>
<translation id="5019198164206649151">Đ”Đ¾Đ¿ÑĐ»Đ½Đ¸Ñ‚ĐµĐ»Đ½Đ¾Ñ‚Đ¾ Ñ…Ñ€Đ°Đ½Đ¸Đ»Đ¸Ñ‰Đµ е Đ² Đ»Đ¾ÑˆĐ¾ ÑÑÑÑ‚Đ¾ÑĐ½Đ¸Đµ</translation>
<translation id="5023310440958281426">ĐŸÑ€Đ¾Đ²ĐµÑ€ĐµÑ‚Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°Ñ‚Đ° Đ½Đ° Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Đ°</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Đ’ÑĐ¸Ñ‡ĐºĐ¾ Đ·Đ° Google ĐŸÑ€ĐµĐ²Đ¾Đ´Đ°Ñ‡</translation>
<translation id="5040262127954254034">ĐŸĐ¾Đ²ĐµÑ€Đ¸Ñ‚ĐµĐ»Đ½Đ¾ÑÑ‚</translation>
<translation id="5045550434625856497">Đ“Ñ€ĐµÑˆĐ½Đ° Đ¿Đ°Ñ€Đ¾Đ»Đ°</translation>
+<translation id="5056549851600133418">Đ¡Ñ‚Đ°Ñ‚Đ¸Đ¸ Đ·Đ° Đ²Đ°Ñ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ²ĐµÑ€ĐµÑ‚Đµ Đ°Đ´Ñ€ĐµÑĐ° Đ½Đ° Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ°<ph name="END_LINK" />.</translation>
<translation id="5087286274860437796">ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° Đ½Đµ е Đ²Đ°Đ»Đ¸Đ´ĐµĐ½.</translation>
<translation id="5089810972385038852">Đ©Đ°Ñ‚</translation>
-<translation id="5094747076828555589">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />; Chromium Đ½ÑĐ¼Đ° Đ´Đ¾Đ²ĐµÑ€Đ¸Đµ Đ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ°Ñ‚Đ°ĐºÑƒĐ²Đ°Ñ‰.</translation>
<translation id="5095208057601539847">ĐŸÑ€Đ¾Đ²Đ¸Đ½Ñ†Đ¸Ñ</translation>
<translation id="5115563688576182185">(64 Đ±Đ¸Ñ‚Đ°)</translation>
-<translation id="5122371513570456792"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> Đ·Đ° â€<ph name="SEARCH_STRING" />“.</translation>
<translation id="5141240743006678641">Đ¡Đ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½Đ¸Ñ‚Đµ Đ¿Đ°Ñ€Đ¾Đ»Đ¸ Đ´Đ° Ñе ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Ñ‚ Ñ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸Ñ‚Đµ Đ²Đ¸ Đ´Đ°Đ½Đ½Đ¸ Đ·Đ° Google</translation>
<translation id="5145883236150621069">Đ’ Đ¾Ñ‚Đ³Đ¾Đ²Đ¾Ñ€Đ° Đ·Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾ Đ¿Ñ€Đ¸ÑÑÑÑ‚Đ²Đ° ĐºĐ¾Đ´ Đ½Đ° Đ³Ñ€ĐµÑˆĐºĐ°</translation>
<translation id="5171045022955879922">Đ¢ÑÑ€ÑĐµÑ‚Đµ или Đ²ÑĐ²ĐµĐ´ĐµÑ‚Đµ URL Đ°Đ´Ñ€ĐµÑ</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Đ›ĐµĐ½Ñ‚Đ° Đ½Đ° Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ¸Ñ‚Đµ</translation>
<translation id="5199729219167945352">Đ•ĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ¸</translation>
<translation id="5251803541071282808">ĐĐ±Đ»Đ°Đº</translation>
+<translation id="5277279256032773186">Đ˜Đ·Đ¿Đ¾Đ»Đ·Đ²Đ°Ñ‚Đµ Chrome Đ½Đ° Ñ€Đ°Đ±Đ¾Ñ‚Đ½Đ¾Ñ‚Đ¾ Ñи Đ¼ÑÑÑ‚Đ¾? Đ‘Đ¸Đ·Đ½ĐµÑĐ¸Ñ‚Đµ Đ¼Đ¾Đ³Đ°Ñ‚ Đ´Đ° ÑƒĐ¿Ñ€Đ°Đ²Đ»ÑĐ²Đ°Ñ‚ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸Ñ‚Đµ Đ½Đ° Đ±Ñ€Đ°ÑƒĐ·ÑÑ€Đ° Đ·Đ° ÑĐ»ÑƒĐ¶Đ¸Ñ‚ĐµĐ»Đ¸Ñ‚Đµ Ñи. ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ</translation>
<translation id="5299298092464848405">Đ“Ñ€ĐµÑˆĐºĐ° Đ¿Ñ€Đ¸ ÑĐ¸Đ½Ñ‚Đ°ĐºÑ‚Đ¸Ñ‡Đ½Đ¸Ñ Đ°Đ½Đ°Đ»Đ¸Đ· Đ½Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾</translation>
<translation id="5300589172476337783">ĐŸĐ¾ĐºĐ°Đ·Đ²Đ°Đ½Đµ</translation>
<translation id="5308689395849655368">Đ˜Đ·Đ¿Ñ€Đ°Ñ‰Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° ÑĐ¸Đ³Đ½Đ°Đ»Đ¸ Đ·Đ° ÑÑ€Đ¸Đ²Đ¾Đ²Đµ е Đ´ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đ¾.</translation>
<translation id="5317780077021120954">Đ—Đ°Đ¿Đ°Đ·Đ²Đ°Đ½Đµ</translation>
<translation id="5327248766486351172">Đ˜Đ¼Đµ</translation>
+<translation id="5359637492792381994">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ½Đµ е Đ²Đ°Đ»Đ¸Đ´ĐµĐ½. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Đ¡ÑÑ…Ñ€Đ°Đ½ÑĐ²Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸Ñ‚Đµ Đ·Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾ Đ½Đµ бе уÑĐ¿ĐµÑˆĐ½Đ¾</translation>
-<translation id="540969355065856584">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ½Đµ е Đ²Đ°Đ»Đ¸Đ´ĐµĐ½. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°.</translation>
<translation id="5421136146218899937">Đ˜Đ·Ñ‡Đ¸ÑÑ‚Đ²Đ°Đ½Đµ Đ½Đ° Đ´Đ°Đ½Đ½Đ¸Ñ‚Đµ Đ·Đ° ÑÑÑ€Ñ„Đ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾...</translation>
<translation id="5430298929874300616">ĐŸÑ€ĐµĐ¼Đ°Ñ…Đ²Đ°Đ½Đµ Đ½Đ° Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ°Ñ‚Đ°</translation>
<translation id="5431657950005405462">Đ¤Đ°Đ¹Đ»ÑÑ‚ Đ²Đ¸ Đ½Đµ бе Đ½Đ°Đ¼ĐµÑ€ĐµĐ½</translation>
<translation id="5435775191620395718">ĐŸĐ¾ĐºĐ°Đ·Đ²Đ° Ñе иÑÑ‚Đ¾Ñ€Đ¸ÑÑ‚Đ° Đ¾Ñ‚ Ñ‚Đ¾Đ²Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾. <ph name="BEGIN_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ Đ¿ĐµÑ€ÑĐ¾Đ½Đ°Đ»Đ¸Đ·Đ¸Ñ€Đ°Đ½Đ¸Ñ‚Đµ Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ Đ·Đ° ÑÑĐ´ÑÑ€Đ¶Đ°Đ½Đ¸Đµ ÑĐ° Đ´ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đ¸, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½Đ¸Ñ‚Đµ Đ²Đ¸ Đ´Đ°Đ½Đ½Đ¸ ÑĐ° Đ·Đ°Ñ‰Đ¸Ñ‚ĐµĐ½Đ¸ Ñ Đ¿ĐµÑ€ÑĐ¾Đ½Đ°Đ»Đ¸Đ·Đ¸Ñ€Đ°Đ½ Đ¿Ñ€Đ¾Đ¿ÑƒÑĐº.</translation>
<translation id="5439770059721715174">ĐŸÑ€Đ¸ Đ¿Đ¾Ñ‚Đ²ÑÑ€Đ¶Đ´Đ°Đ²Đ°Đ½Đµ Đ½Đ° ÑÑ…ĐµĐ¼Đ°Ñ‚Đ° Đ²ÑĐ·Đ½Đ¸ĐºĐ½Đ° Đ³Ñ€ĐµÑˆĐºĐ° Đ²/ÑĐ² â€<ph name="ERROR_PATH" />“: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Đ¢Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ½Đ° <ph name="HOST_NAME" /> Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° бÑде Đ½Đ°Đ¼ĐµÑ€ĐµĐ½Đ°</translation>
<translation id="5455374756549232013">ĐĐµĐ²Đ°Đ»Đ¸Đ´Đ½Đ¾ ĐºĐ»ĐµĐ¹Đ¼Đ¾ Đ·Đ° Đ´Đ°Ñ‚Đ° и Ñ‡Đ°Ñ Đ½Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Đ˜ÑĐºĐ°Ñ‚Đµ ли Đ´Đ° Đ½Đ°Đ¿ÑƒÑĐ½ĐµÑ‚Đµ Ñ‚Đ¾Đ·Đ¸ ÑĐ°Đ¹Ñ‚?</translation>
<translation id="5629630648637658800">Đ—Đ°Ñ€ĐµĐ¶Đ´Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸Ñ‚Đµ Đ·Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾ Đ½Đµ бе уÑĐ¿ĐµÑˆĐ½Đ¾</translation>
<translation id="5631439013527180824">ĐĐµĐ²Đ°Đ»Đ¸Đ´Đ½Đ¾ Đ¾Đ·Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ Đ·Đ° ÑƒĐ¿Ñ€Đ°Đ²Đ»ĐµĐ½Đ¸Đµ Đ½Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾Ñ‚Đ¾</translation>
-<translation id="5650551054760837876">Đе ÑĐ° Đ½Đ°Đ¼ĐµÑ€ĐµĐ½Đ¸ Ñ€ĐµĐ·ÑƒĐ»Ñ‚Đ°Ñ‚Đ¸ Đ¾Ñ‚ Ñ‚ÑÑ€ÑĐµĐ½ĐµÑ‚Đ¾.</translation>
<translation id="5677928146339483299">Đ‘Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½Đ¾</translation>
<translation id="5710435578057952990">Đ¡Đ°Đ¼Đ¾Đ»Đ¸Ñ‡Đ½Đ¾ÑÑ‚Ñ‚Đ° Đ½Đ° Ñ‚Đ¾Đ·Đ¸ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚ Đ½Đµ е Đ¿Đ¾Ñ‚Đ²ÑÑ€Đ´ĐµĐ½Đ°.</translation>
<translation id="5720705177508910913">Đ¢ĐµĐºÑƒÑ‰Đ¸ÑÑ‚ Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»</translation>
+<translation id="572328651809341494">Đ¡ĐºĐ¾Ñ€Đ¾ÑˆĐ½Đ¸ Ñ€Đ°Đ·Đ´ĐµĐ»Đ¸</translation>
<translation id="5784606427469807560">ĐŸÑ€Đ¸ Đ¿Đ¾Ñ‚Đ²ÑÑ€Đ¶Đ´Đ°Đ²Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° ĐºĐ°Ñ€Ñ‚Đ°Ñ‚Đ° Đ²Đ¸ Đ²ÑĐ·Đ½Đ¸ĐºĐ½Đ° Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼. ĐŸÑ€Đ¾Đ²ĐµÑ€ĐµÑ‚Đµ Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Ñи Ñ Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ и Đ¾Đ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾.</translation>
<translation id="5785756445106461925">ĐÑĐ²ĐµĐ½ Ñ‚Đ¾Đ²Đ° Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐºĐ»ÑÑ‡Đ²Đ° Đ´Ñ€ÑƒĐ³Đ¸ Ñ€ĐµÑурÑи, ĐºĐ¾Đ¸Ñ‚Đ¾ Đ½Đµ ÑĐ° Đ·Đ°Ñ‰Đ¸Ñ‚ĐµĐ½Đ¸. Đ”Đ¾ĐºĐ°Ñ‚Đ¾ Ñе Đ¿Ñ€ĐµĐ´Đ°Đ²Đ°Ñ‚, Ñ‚Đµ Đ¼Đ¾Đ³Đ°Ñ‚ Đ´Đ° бÑĐ´Đ°Ñ‚ Đ²Đ¸Đ´ĐµĐ½Đ¸ Đ¾Ñ‚ Đ´Ñ€ÑƒĐ³Đ¸ Ñ…Đ¾Ñ€Đ° и Đ´Đ° бÑĐ´Đ°Ñ‚ Đ¼Đ¾Đ´Đ¸Ñ„Đ¸Ñ†Đ¸Ñ€Đ°Đ½Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Đ´Đ° Ñе Đ¿Ñ€Đ¾Đ¼ĐµĐ½Đ¸ Đ¸Đ·Đ³Đ»ĐµĐ´ÑÑ‚ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°.</translation>
+<translation id="5786044859038896871">Đ˜ÑĐºĐ°Ñ‚Đµ ли Đ´Đ° Ñе Đ¿Đ¾Đ¿ÑĐ»Đ½ÑÑ‚ Đ´Đ°Đ½Đ½Đ¸Ñ‚Đµ Đ·Đ° ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ°Ñ‚Đ° Đ²Đ¸ ĐºĐ°Ñ€Ñ‚Đ°?</translation>
+<translation id="5803412860119678065">Đ˜ÑĐºĐ°Ñ‚Đµ ли Đ´Đ° Ñе Đ¿Đ¾Đ¿ÑĐ»Đ½ÑÑ‚ Đ´Đ°Đ½Đ½Đ¸Ñ‚Đµ Đ·Đ° <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Đ’Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Ñ/ÑÑ <ph name="DOMAIN" /> е ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ° Ñ Đ¾ÑÑ‚Đ°Ñ€ÑĐ» ĐºÑ€Đ¸Đ¿Ñ‚Đ¾Đ³Ñ€Đ°Ñ„ÑĐºĐ¸ Đ¿Đ°ĐºĐµÑ‚.</translation>
<translation id="5813119285467412249">&amp;Đ’ÑĐ·ÑÑ‚Đ°Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ´Đ¾Đ±Đ°Đ²ÑĐ½ĐµÑ‚Đ¾</translation>
+<translation id="5814352347845180253">ĐœĐ¾Đ¶Đµ Đ´Đ° Đ·Đ°Đ³ÑƒĐ±Đ¸Ñ‚Đµ Đ´Đ¾ÑÑ‚ÑĐ¿ Đ´Đ¾ Đ¿Đ»Đ°Ñ‚ĐµĐ½Đ¾ ÑÑĐ´ÑÑ€Đ¶Đ°Đ½Đ¸Đµ Đ¾Ñ‚ <ph name="SITE" /> и Đ½ÑĐºĐ¾Đ¸ Đ´Ñ€ÑƒĐ³Đ¸ ÑĐ°Đ¹Ñ‚Đ¾Đ²Đµ.</translation>
+<translation id="5843436854350372569">ĐĐ¿Đ¸Ñ‚Đ°Ñ…Ñ‚Đµ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñ/ÑÑ <ph name="DOMAIN" />, Đ½Đ¾ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, ÑÑĐ´ÑÑ€Đ¶Đ°Ñ‰ Ñлаб ĐºĐ»Ñч. Đ’ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ° Đ´Đ° е ĐºĐ¾Đ¼Đ¿Ñ€Đ¾Đ¼ĐµÑ‚Đ¸Ñ€Đ°Đ» Ñ‡Đ°ÑÑ‚Đ½Đ¸Ñ ĐºĐ»Ñч и ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ´Đ° Đ½Đµ е Ñ‚Đ¾Đ·Đ¸, ĐºĐ¾Đ¹Ñ‚Đ¾ Đ¾Ñ‡Đ°ĐºĐ²Đ°Ñ‚Đµ (Đ²ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ´Đ° ÑÑ‚Đµ Ñе ÑĐ²ÑÑ€Đ·Đ°Đ»Đ¸ Ñ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°). <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Đ’Đ¸Đ¶Đ´Đ°Ñ‚Đµ Ñ‚Đ¾Đ²Đ° ÑÑĐ¾Đ±Ñ‰ĐµĐ½Đ¸Đµ, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ Đ¼ĐµĐ½Đ¸Đ´Đ¶ÑÑ€ÑÑ‚ Đ²Đ¸ е Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ» ÑĐ°Đ¹Ñ‚Đ°.</translation>
<translation id="5857090052475505287">ĐĐ¾Đ²Đ° Đ¿Đ°Đ¿ĐºĐ°</translation>
<translation id="5869405914158311789">ĐÑĐ¼Đ° Đ´Đ¾ÑÑ‚ÑĐ¿ Đ´Đ¾ Ñ‚Đ¾Đ·Đ¸ ÑĐ°Đ¹Ñ‚</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">ĐÑĐ½Đ¾Đ²Đ½Đ¸ Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ</translation>
<translation id="59107663811261420">Đ¢Đ¾Đ·Đ¸ Ñ‚Đ¸Đ¿ ĐºĐ°Ñ€Ñ‚Đ° Đ½Đµ Ñе Đ¿Đ¾Đ´Đ´ÑÑ€Đ¶Đ° Đ¾Ñ‚ Google Payments Đ·Đ° Ñ‚Đ¾Đ·Đ¸ Ñ‚ÑÑ€Đ³Đ¾Đ²ĐµÑ†. ĐœĐ¾Đ»Ñ, Đ¸Đ·Đ±ĐµÑ€ĐµÑ‚Đµ Đ´Ñ€ÑƒĐ³Đ°.</translation>
<translation id="59174027418879706">ĐĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đ¾</translation>
+<translation id="5926846154125914413">ĐœĐ¾Đ¶Đµ Đ´Đ° Đ·Đ°Đ³ÑƒĐ±Đ¸Ñ‚Đµ Đ´Đ¾ÑÑ‚ÑĐ¿ Đ´Đ¾ Đ¿Đ»Đ°Ñ‚ĐµĐ½Đ¾ ÑÑĐ´ÑÑ€Đ¶Đ°Đ½Đ¸Đµ Đ¾Ñ‚ Đ½ÑĐºĐ¾Đ¸ ÑĐ°Đ¹Ñ‚Đ¾Đ²Đµ.</translation>
<translation id="5966707198760109579">Đ¡ĐµĐ´Đ¼Đ¸Ñ†Đ°</translation>
<translation id="5967867314010545767">ĐŸÑ€ĐµĐ¼Đ°Ñ…Đ²Đ°Đ½Đµ Đ¾Ñ‚ иÑÑ‚Đ¾Ñ€Đ¸ÑÑ‚Đ°</translation>
<translation id="5975083100439434680">ĐĐ°Đ¼Đ°Đ»ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ¼Đ°Ñ‰Đ°Đ±Đ°</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">ĐĐ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đ¾</translation>
<translation id="6042308850641462728">ĐÑ‰Đµ</translation>
<translation id="6060685159320643512">Đ’Đ½Đ¸Đ¼Đ°Đ²Đ°Đ¹Ñ‚Đµ, Ñ‚ĐµĐ·Đ¸ ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ¸ Đ¼Đ¾Đ¶Đµ Đ´Đ° ÑĐ° Đ¾Đ¿Đ°ÑĐ½Đ¸</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{Đ½ÑĐ¼Đ°}=1{1}other{#}}</translation>
<translation id="6146055958333702838">ĐŸÑ€Đ¾Đ²ĐµÑ€ĐµÑ‚Đµ Đ²ÑĐ¸Ñ‡ĐºĐ¸ ĐºĐ°Đ±ĐµĐ»Đ¸ и Ñ€ĐµÑÑ‚Đ°Ñ€Ñ‚Đ¸Ñ€Đ°Đ¹Ñ‚Đµ Đ¼Đ°Ñ€ÑˆÑ€ÑƒÑ‚Đ¸Đ·Đ°Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ, Đ¼Đ¾Đ´ĐµĐ¼Đ¸Ñ‚Đµ или Đ´Ñ€ÑƒĐ³Đ¸Ñ‚Đµ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ¸
уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°, ĐºĐ¾Đ¸Ñ‚Đ¾ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ°Ñ‚Đµ.</translation>
<translation id="614940544461990577">Đ˜Đ·Đ¿Ñ€Đ¾Đ±Đ²Đ°Đ¹Ñ‚Đµ ÑĐ»ĐµĐ´Đ½Đ¾Ñ‚Đ¾:</translation>
<translation id="6150607114729249911">ĐĐ¼Đ¸ ÑĐµĐ³Đ°! Đ¢Ñ€ÑĐ±Đ²Đ° Đ´Đ° Đ¿Đ¾Đ¿Đ¸Ñ‚Đ°Ñ‚Đµ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»Đ¸Ñ‚Đµ Ñи дали Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°.</translation>
<translation id="6151417162996330722">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° Đ¸Đ¼Đ° Ñ‚Đ²ÑÑ€Đ´Đµ Đ´ÑĐ»ÑĐ³ Đ¿ĐµÑ€Đ¸Đ¾Đ´ Đ½Đ° Đ²Đ°Đ»Đ¸Đ´Đ½Đ¾ÑÑ‚.</translation>
-<translation id="6154808779448689242">Đ˜Đ·Đ²ĐµĐ´ĐµĐ½Đ¾Ñ‚Đ¾ Đ¾Đ·Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ Đ½Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾ Đ½Đµ ÑÑĐ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²Đ° Đ½Đ° Ñ‚ĐµĐºÑƒÑ‰Đ¾Ñ‚Đ¾</translation>
<translation id="6165508094623778733">ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ</translation>
<translation id="6203231073485539293">ĐŸÑ€Đ¾Đ²ĐµÑ€ĐµÑ‚Đµ Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Ñи Ñ Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚</translation>
<translation id="6218753634732582820">ĐĐ´Ñ€ĐµÑÑÑ‚ Đ´Đ° Ñе Đ¿Ñ€ĐµĐ¼Đ°Ñ…Đ½Đµ ли Đ¾Ñ‚ Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">ĐĐ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ´Đ° Đ´ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Ñ‚Đµ Đ¿Ñ€ĐµĐ´Đ²Đ¸Đ¶Đ´Đ°Đ½Đ¸ÑÑ‚Đ° Đ·Đ° Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ°</translation>
<translation id="6337534724793800597">Đ¤Đ¸Đ»Ñ‚Ñ€Đ¸Ñ€Đ°Đ½Đµ Đ½Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°Ñ‚Đ° Đ¿Đ¾ Đ¸Đ¼Đµ</translation>
<translation id="6342069812937806050">Đ¢Đ¾ĐºÑƒ-Ñ‰Đ¾</translation>
+<translation id="6345221851280129312">Đ½ĐµĐ¸Đ·Đ²ĐµÑÑ‚ĐµĐ½ Ñ€Đ°Đ·Đ¼ĐµÑ€</translation>
<translation id="6355080345576803305">ĐŸÑ€Đ¸Đ½ÑƒĐ´Đ¸Ñ‚ĐµĐ»Đ½Đ¾ Đ·Đ°Đ´Đ°Đ´ĐµĐ½Đ¾ Đ¿Đ¾Ñ€Đ°Đ´Đ¸ Đ¾Đ±Ñ‰ĐµÑÑ‚Đ²ĐµĐ½Đ° ÑеÑиÑ</translation>
<translation id="6358450015545214790">ĐĐ°ĐºĐ²Đ¾ Đ¾Đ·Đ½Đ°Ñ‡Đ°Đ²Đ°Ñ‚ Ñ‚ĐµĐ·Đ¸ Đ½ĐµÑ‰Đ°?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{Đ¾Ñ‰Đµ 1 Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸Đµ}other{Đ¾Ñ‰Đµ # Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ}}</translation>
<translation id="6387478394221739770">Đ¢ÑÑ€ÑĐ¸Ñ‚Đµ Đ¸Đ½Ñ‚ĐµÑ€ĐµÑĐ½Đ¸ Đ½Đ¾Đ²Đ¸ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¸ Đ½Đ° Chrome? Đ˜Đ·Đ¿Ñ€Đ¾Đ±Đ²Đ°Đ¹Ñ‚Đµ Đ±ĐµÑ‚Đ° ĐºĐ°Đ½Đ°Đ»Đ° Đ½Đ° Đ°Đ´Ñ€ĐµÑ chrome.com/beta.</translation>
-<translation id="641480858134062906">ĐĐµÑƒÑĐ¿ĐµÑˆĐ½Đ¾ Đ·Đ°Ñ€ĐµĐ¶Đ´Đ°Đ½Đµ Đ½Đ° <ph name="URL" /></translation>
+<translation id="6389758589412724634">ĐŸĐ°Đ¼ĐµÑ‚Ñ‚Đ° Đ½Đ° Chromium Ñе Đ¸Đ·Ñ‡ĐµÑ€Đ¿Đ°, Đ´Đ¾ĐºĐ°Ñ‚Đ¾ Đ±Ñ€Đ°ÑƒĐ·ÑÑ€ÑÑ‚ Đ¾Đ¿Đ¸Ñ‚Đ²Đ°ÑˆĐµ Đ´Đ° Đ¿Đ¾ĐºĐ°Đ¶Đµ Ñ‚Đ°Đ·Đ¸ ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°.</translation>
+<translation id="6416403317709441254">Đ’ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" />, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚ÑÑ‚ Đ¸Đ·Đ¿Ñ€Đ°Ñ‚Đ¸ Đ½ĐµĐ²Đ°Đ»Đ¸Đ´Đ½Đ¸ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Đ¸ Đ´Đ°Đ½Đ½Đ¸, ĐºĐ¾Đ¸Ñ‚Đ¾ Chromium Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾Đ±Ñ€Đ°Đ±Đ¾Ñ‚Đ¸. ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ¸Ñ‚Đµ Đ³Ñ€ĐµÑˆĐºĐ¸ и Đ°Ñ‚Đ°ĐºĐ¸ ÑĐ° Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¸, Ñ‚Đ°ĐºĐ° Ñ‡Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ° Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Đ¿Đ¾-ĐºÑÑĐ½Đ¾. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Đе Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸ дали ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ е Đ°Đ½ÑƒĐ»Đ¸Ñ€Đ°Đ½.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> Đ¾Ñ‚ĐºĐ°Đ·Đ° Đ´Đ° уÑÑ‚Đ°Đ½Đ¾Đ²Đ¸ Đ²Ñ€ÑĐ·ĐºĐ°.</translation>
<translation id="6445051938772793705">Đ”ÑÑ€Đ¶Đ°Đ²Đ°</translation>
<translation id="6451458296329894277">ĐŸĐ¾Ñ‚Đ²ÑÑ€Đ´ĐµÑ‚Đµ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ½Đ¾Ñ‚Đ¾ Đ¸Đ·Đ¿Ñ€Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Ñ„Đ¾Ñ€Đ¼ÑƒĐ»ÑÑ€Đ°</translation>
<translation id="6458467102616083041">Бе Đ¿Ñ€ĐµĐ½ĐµĐ±Ñ€ĐµĐ³Đ½Đ°Ñ‚Đ¾, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ Đ¾ÑĐ½Đ¾Đ²Đ½Đ¾Ñ‚Đ¾ Ñ‚ÑÑ€ÑĐµĐ½Đµ е Đ´ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đ¾ Đ¾Ñ‚ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾.</translation>
+<translation id="6462969404041126431">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ’ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ´Đ° е Đ°Đ½ÑƒĐ»Đ¸Ñ€Đ°Đ½. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ° Đ·Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾Ñ‚Đ¾</translation>
<translation id="6489534406876378309">Đ¡Ñ‚Đ°Ñ€Ñ‚Đ¸Ñ€Đ°Đ½Đµ Đ½Đ° ĐºĐ°Ñ‡Đ²Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° ÑÑ€Đ¸Đ²Đ¾Đ²Đµ</translation>
<translation id="6529602333819889595">&amp;Đ’ÑĐ·ÑÑ‚Đ°Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ¸Đ·Ñ‚Ñ€Đ¸Đ²Đ°Đ½ĐµÑ‚Đ¾</translation>
+<translation id="6534179046333460208">ĐŸÑ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ Đ¾Ñ‚ Đ¤Đ¸Đ·Đ¸Ñ‡ĐµÑĐºĐ°Ñ‚Đ° Đ¼Ñ€ĐµĐ¶Đ°</translation>
<translation id="6550675742724504774">ĐĐ¿Ñ†Đ¸Đ¸</translation>
+<translation id="6593753688552673085">Đ¿Đ¾-Đ¼Đ°Đ»ĐºĐ¾ Đ¾Ñ‚ <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">ĐĐ¿Ñ†Đ¸Đ¸ Đ·Đ° ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đµ</translation>
<translation id="662080504995468778">ĐÑÑ‚Đ°Đ²Đ°Đ½Đµ</translation>
<translation id="6628463337424475685">Đ¢ÑÑ€ÑĐµĐ½Đµ Ñ/ÑÑ <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Đ’ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" />, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ <ph name="BEGIN_LINK" />Ñ‚Đ¾Đ·Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ е Đ°Đ½ÑƒĐ»Đ¸Ñ€Đ°Đ½<ph name="END_LINK" />. ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ³Ñ€ĐµÑˆĐºĐ¸Ñ‚Đµ Đ² Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ° и Đ°Ñ‚Đ°ĐºĐ¸Ñ‚Đµ ÑÑ€ĐµÑ‰Ñƒ Đ½ĐµÑ ÑĐ° Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¸, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Đ¿Đ¾-ĐºÑÑĐ½Đ¾.</translation>
<translation id="6644283850729428850">Đ¢Đ¾Đ²Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾ е Đ¾Ñ‚Ñ‚ĐµĐ³Đ»ĐµĐ½Đ¾.</translation>
+<translation id="6652240803263749613">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ½Đµ Ñе ÑÑ‡Đ¸Ñ‚Đ° Đ·Đ° Đ½Đ°Đ´ĐµĐ¶Đ´ĐµĐ½ Đ¾Ñ‚ Đ¾Đ¿ĐµÑ€Đ°Ñ†Đ¸Đ¾Đ½Đ½Đ°Ñ‚Đ° ÑиÑÑ‚ĐµĐ¼Đ° Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€Đ° Đ²Đ¸. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Đ ĐµĐ´Đ°ĐºÑ‚Đ¸Ñ€Đ°Đ½Đµ Đ½Đ° Đ¿Đ°Đ¿ĐºĐ°Ñ‚Đ°</translation>
<translation id="6660210980321319655">Đ¡Đ¸Đ³Đ½Đ°Đ»ÑÑ‚ е Đ¿Đ¾Đ´Đ°Đ´ĐµĐ½ Đ°Đ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đ¾ Đ²/ÑĐ² <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">ĐŸÑ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸ĐµÑ‚Đ¾ Đ·Đ° Ñ„Đ¾Ñ€Đ¼ÑƒĐ»ÑÑ€Đ¸ Đ´Đ° Ñе Đ¿Ñ€ĐµĐ¼Đ°Ñ…Đ½Đµ ли Đ¾Ñ‚ Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">ĐŸÑ€ĐµĐ´Đ¸ÑˆĐ½Đ°</translation>
<translation id="6710594484020273272">&lt;Đ’ÑĐ²ĐµĐ´ĐµÑ‚Đµ Đ´ÑƒĐ¼Đ° Đ·Đ° Ñ‚ÑÑ€ÑĐµĐ½Đµ&gt;</translation>
<translation id="6711464428925977395">ĐĐµÑ‰Đ¾ Đ½Đµ е Đ½Đ°Ñ€ĐµĐ´ Ñ Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ° или Đ°Đ´Ñ€ĐµÑÑÑ‚ е Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ĐµĐ½.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{Đ½ÑĐ¼Đ°}=1{1 ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚}other{# ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚Đ°}}</translation>
<translation id="674375294223700098">ĐĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ° Đ³Ñ€ĐµÑˆĐºĐ° Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ°.</translation>
<translation id="6753269504797312559">Đ¡Ñ‚Đ¾Đ¹Đ½Đ¾ÑÑ‚ Đ·Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾</translation>
<translation id="6757797048963528358">Đ£ÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾Ñ‚Đ¾ Đ²Đ¸ Đ¿Ñ€ĐµĐ¼Đ¸Đ½Đ° Đ² ÑĐ¿Ñщ Ñ€ĐµĐ¶Đ¸Đ¼.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">ĐĐ¸Đ²Đ¾Ñ‚Đ¾ Đ½Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Ñ‚Đ¾ Đ½Đµ Ñе Đ¿Đ¾Đ´Đ´ÑÑ€Đ¶Đ°.</translation>
<translation id="6895330447102777224">ĐĐ°Ñ€Ñ‚Đ°Ñ‚Đ° Đ²Đ¸ е Đ¿Đ¾Ñ‚Đ²ÑÑ€Đ´ĐµĐ½Đ°</translation>
<translation id="6897140037006041989">ĐŸĐ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»ÑĐºĐ¸ Đ°Đ³ĐµĐ½Ñ‚</translation>
-<translation id="6903907808598579934">Đ’ĐºĐ»ÑÑ‡Đ²Đ°Đ½Đµ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾</translation>
<translation id="6915804003454593391">ĐŸĐ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»:</translation>
<translation id="6957887021205513506">Đ˜Đ·Đ³Đ»ĐµĐ¶Đ´Đ°, Ñ‡Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° е Đ¿Đ¾Đ´Đ¿Ñ€Đ°Đ²ĐµĐ½.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">ĐĐºÑ€ÑĐ³</translation>
<translation id="6973656660372572881">ĐŸĐ¾ÑĐ¾Ñ‡ĐµĐ½Đ¸ ÑĐ° ĐºĐ°ĐºÑ‚Đ¾ Ñ„Đ¸ĐºÑĐ¸Ñ€Đ°Đ½Đ¸ Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ¸, Ñ‚Đ°ĐºĐ° и URL Đ°Đ´Ñ€ĐµÑ Đ½Đ° ÑĐºÑ€Đ¸Đ¿Ñ‚ Đ²ÑĐ² Ñ„Đ¾Ñ€Đ¼Đ°Ñ‚ .pac.</translation>
<translation id="6989763994942163495">ĐŸĐ¾ĐºĐ°Đ·Đ²Đ°Đ½Đµ Đ½Đ° Ñ€Đ°Đ·ÑˆĐ¸Ñ€ĐµĐ½Đ¸Ñ‚Đµ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸...</translation>
+<translation id="7000990526846637657">ĐÑĐ¼Đ° Đ½Đ°Đ¼ĐµÑ€ĐµĐ½Đ¸ Đ·Đ°Đ¿Đ¸Ñи Đ² иÑÑ‚Đ¾Ñ€Đ¸ÑÑ‚Đ°</translation>
+<translation id="7009986207543992532">ĐĐ¿Đ¸Ñ‚Đ°Ñ…Ñ‚Đµ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñ/ÑÑ <ph name="DOMAIN" />, Đ½Đ¾ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, Ñ‡Đ¸Đ¹Ñ‚Đ¾ Đ¿ĐµÑ€Đ¸Đ¾Đ´ Đ½Đ° Đ²Đ°Đ»Đ¸Đ´Đ½Đ¾ÑÑ‚ е Ñ‚Đ²ÑÑ€Đ´Đµ Đ´ÑĐ»ÑĐ³, Đ·Đ° Đ´Đ° е Đ½Đ°Đ´ĐµĐ¶Đ´ĐµĐ½. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Đ’ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ² Đ¿Ñ€Đ¾Ñ„Đ¸Đ»Đ° Đ²Đ¸ Đ² Google Đ´Đ° Đ¸Đ¼Đ° Đ´Ñ€ÑƒĐ³Đ¸ Đ²Đ¸Đ´Đ¾Đ²Đµ иÑÑ‚Đ¾Ñ€Đ¸Ñ Đ½Đ° ÑÑÑ€Ñ„Đ¸Ñ€Đ°Đ½Đµ, ÑÑÑ…Ñ€Đ°Đ½ÑĐ²Đ°Đ½Đ¸ Đ½Đ° Đ°Đ´Ñ€ĐµÑ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">ĐŸĐ°Ñ€Đ¾Đ»Đ¸</translation>
-<translation id="7050187094878475250">ĐĐ¿Đ¸Ñ‚Đ°Ñ…Ñ‚Đµ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµÑ‚Đµ Ñ/ÑÑ <ph name="DOMAIN" />, Đ½Đ¾ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, Ñ‡Đ¸Đ¹Ñ‚Đ¾ Đ¿ĐµÑ€Đ¸Đ¾Đ´ Đ½Đ° Đ²Đ°Đ»Đ¸Đ´Đ½Đ¾ÑÑ‚ е Ñ‚Đ²ÑÑ€Đ´Đµ Đ´ÑĐ»ÑĐ³, Đ·Đ° Đ´Đ° е Đ½Đ°Đ´ĐµĐ¶Đ´ĐµĐ½.</translation>
<translation id="7087282848513945231">ĐĐºÑ€ÑĐ³</translation>
<translation id="7088615885725309056">ĐŸĐ¾-ÑÑ‚Đ°Ñ€Đ°</translation>
<translation id="7090678807593890770">ĐŸĐ¾Ñ‚ÑÑ€ÑĐµÑ‚Đµ â€<ph name="LINK" />“ Ñ Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Đ’Đ¸Đ¶Đ´Đ°Ñ‚Đµ Ñ‚Đ¾Đ²Đ° ÑÑĐ¾Đ±Ñ‰ĐµĐ½Đ¸Đµ, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ Đ¼ĐµĐ½Đ¸Đ´Đ¶ÑÑ€ÑÑ‚ Đ²Đ¸ Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° Đ¾Đ´Đ¾Đ±Ñ€Đ¸ Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑĐ°Đ¹Ñ‚Đ¾Đ²Đµ Đ¿Ñ€Đ¸ Đ¿ÑÑ€Đ²Đ¾Ñ‚Đ¾ Đ²Đ¸ Đ¿Đ¾ÑĐµÑ‰ĐµĐ½Đ¸Đµ.</translation>
<translation id="724975217298816891">Đ’ÑĐ²ĐµĐ´ĐµÑ‚Đµ Đ´Đ°Ñ‚Đ°Ñ‚Đ° Đ½Đ° Đ²Đ°Đ»Đ¸Đ´Đ½Đ¾ÑÑ‚ и ĐºĐ¾Đ´Đ° Đ·Đ° Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐºĐ° Đ·Đ° <ph name="CREDIT_CARD" />, Đ·Đ° Đ´Đ° Đ°ĐºÑ‚ÑƒĐ°Đ»Đ¸Đ·Đ¸Ñ€Đ°Ñ‚Đµ Đ´Đ°Đ½Đ½Đ¸Ñ‚Đµ Đ·Đ° ĐºĐ°Ñ€Ñ‚Đ°Ñ‚Đ° Ñи. Đ¡Đ»ĐµĐ´ ĐºĐ°Ñ‚Đ¾ Ñ Đ¿Đ¾Ñ‚Đ²ÑÑ€Đ´Đ¸Ñ‚Đµ, Ñ‚Đµ Ñ‰Đµ бÑĐ´Đ°Ñ‚ ÑĐ¿Đ¾Đ´ĐµĐ»ĐµĐ½Đ¸ Ñ Ñ‚Đ¾Đ·Đ¸ ÑĐ°Đ¹Ñ‚.</translation>
<translation id="725866823122871198">Đе Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе уÑÑ‚Đ°Đ½Đ¾Đ²Đ¸ Ñ‡Đ°ÑÑ‚Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ° Ñ/ÑÑ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, Ñ‚ÑĐ¹ ĐºĐ°Ñ‚Đ¾ Đ´Đ°Ñ‚Đ°Ñ‚Đ° и Ñ‡Đ°ÑÑÑ‚ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€Đ° Đ²Đ¸ (<ph name="DATE_AND_TIME" />) ÑĐ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¸.</translation>
-<translation id="7265986070661382626">Đ’ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" />, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚ÑÑ‚ <ph name="BEGIN_LINK" />Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° Ñ„Đ¸ĐºÑĐ¸Ñ€Đ°Đ½Đµ Đ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¸Ñ‚Đµ<ph name="END_LINK" />. ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ³Ñ€ĐµÑˆĐºĐ¸Ñ‚Đµ Đ² Đ¼Ñ€ĐµĐ¶Đ°Ñ‚Đ° и Đ°Ñ‚Đ°ĐºĐ¸Ñ‚Đµ ÑÑ€ĐµÑ‰Ñƒ Đ½ĐµÑ ÑĐ° Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¸, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Đ¿Đ¾-ĐºÑÑĐ½Đ¾.</translation>
<translation id="7269802741830436641">Đ¢Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²Đ¾Đ´Đ¸ Đ´Đ¾ Ñ†Đ¸ĐºĐ»Đ¸Ñ‡Đ½Đ¾ Đ¿Ñ€ĐµĐ½Đ°ÑĐ¾Ñ‡Đ²Đ°Đ½Đµ</translation>
<translation id="7275334191706090484">Đ£Đ¿Ñ€Đ°Đ²Đ»ÑĐ²Đ°Đ½Đ¸ Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ¸</translation>
<translation id="7298195798382681320">ĐŸÑ€ĐµĐ¿Đ¾Ñ€ÑÑ‡Đ¸Ñ‚ĐµĐ»Đ½Đ¾</translation>
-<translation id="7301833672208172928">Đ’ĐºĐ»ÑÑ‡Đ²Đ°Đ½Đµ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° иÑÑ‚Đ¾Ñ€Đ¸ÑÑ‚Đ°</translation>
+<translation id="7309308571273880165">Đ¡Đ¸Đ³Đ½Đ°Đ» Đ·Đ° ÑÑ€Đ¸Đ², Đ·Đ°Đ¿Đ¸ÑĐ°Đ½ Đ²/ÑĐ² <ph name="CRASH_TIME" /> (Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»ÑÑ‚ е Đ·Đ°ÑĐ²Đ¸Đ» ĐºĐ°Ñ‡Đ²Đ°Đ½Đµ, ĐºĐ¾ĐµÑ‚Đ¾ Đ¾Ñ‰Đµ Đ½Đµ е Đ¸Đ·Đ²ÑÑ€ÑˆĐµĐ½Đ¾)</translation>
<translation id="7334320624316649418">&amp;Đ’ÑĐ·ÑÑ‚Đ°Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ¿Ñ€ĐµĐ½Đ°Ñ€ĐµĐ¶Đ´Đ°Đ½ĐµÑ‚Đ¾</translation>
<translation id="733923710415886693">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° Đ½Đµ е Ñ€Đ°Đ·ĐºÑ€Đ¸Ñ‚ Ñ‡Ñ€ĐµĐ· ĐŸÑ€Đ¾Đ·Ñ€Đ°Ñ‡Đ½Đ¾ÑÑ‚ Đ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¸Ñ‚Đµ.</translation>
+<translation id="7351800657706554155">Đ’ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ ÑĐ°Đ¹Ñ‚Đ° <ph name="SITE" />, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ е Đ°Đ½ÑƒĐ»Đ¸Ñ€Đ°Đ½. ĐĐ±Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¾ Đ¼Ñ€ĐµĐ¶Đ¾Đ²Đ¸Ñ‚Đµ Đ³Ñ€ĐµÑˆĐºĐ¸ и Đ°Ñ‚Đ°ĐºĐ¸ ÑĐ° Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¸, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾ Ñ‰Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Đ¿Đ¾-ĐºÑÑĐ½Đ¾. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">ĐĐ¾Đ¼Đ°Đ½Đ´ĐµĐ½ Ñ€ĐµĐ´</translation>
<translation id="7372973238305370288">Ñ€ĐµĐ·ÑƒĐ»Ñ‚Đ°Ñ‚ Đ¾Ñ‚ Ñ‚ÑÑ€ÑĐµĐ½ĐµÑ‚Đ¾</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">ĐĐ°Ñ€Ñ‚Đ°Ñ‚Đ° Ñе Đ¿Đ¾Ñ‚Đ²ÑÑ€Đ¶Đ´Đ°Đ²Đ°</translation>
<translation id="7481312909269577407">ĐŸÑ€ĐµĐ¿Ñ€Đ°Ñ‰Đ°Đ½Đµ</translation>
<translation id="7485870689360869515">ĐÑĐ¼Đ° Đ½Đ°Đ¼ĐµÑ€ĐµĐ½Đ¸ Đ´Đ°Đ½Đ½Đ¸.</translation>
+<translation id="7508255263130623398">Đ’ÑÑ€Đ½Đ°Ñ‚Đ¸ÑÑ‚ Đ¾Ñ‚ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°Ñ‚Đ° Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½ĐµĐ½ Đ½Đ¾Đ¼ĐµÑ€ Đ½Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾Ñ‚Đ¾ е Đ¿Ñ€Đ°Đ·ĐµĐ½ или Đ½Đµ ÑÑĐ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²Đ° Đ½Đ° Ñ‚ĐµĐºÑƒÑ‰Đ¸Ñ</translation>
<translation id="7514365320538308">Đ˜Đ·Ñ‚ĐµĐ³Đ»ÑĐ½Đµ</translation>
<translation id="7518003948725431193">Đе е Đ½Đ°Đ¼ĐµÑ€ĐµĐ½Đ° ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ·Đ° ÑƒĐµĐ± Đ°Đ´Ñ€ĐµÑĐ°: <ph name="URL" /></translation>
<translation id="7537536606612762813">Đ—Đ°Đ´ÑĐ»Đ¶Đ¸Ñ‚ĐµĐ»Đ½Đ¾</translation>
<translation id="7542995811387359312">ĐĐ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đ¾Ñ‚Đ¾ Đ¿Đ¾Đ¿ÑĐ»Đ²Đ°Đ½Đµ Đ½Đ° ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ°Ñ‚Đ° ĐºĐ°Ñ€Ñ‚Đ° е Đ´ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đ¾, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ Ñ‚Đ¾Đ·Đ¸ Ñ„Đ¾Ñ€Đ¼ÑƒĐ»ÑÑ€ Đ½Đµ Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° Đ·Đ°Ñ‰Đ¸Ñ‚ĐµĐ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°.</translation>
<translation id="7549584377607005141">Đ—Đ° Đ´Đ° Ñе Đ¿Đ¾ĐºĐ°Đ¶Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ Ñ‚Đ°Đ·Đ¸ ÑƒĐµĐ± ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°, ÑĐ° Đ½ĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ¸ Đ¿Đ¾-Ñ€Đ°Đ½Đ¾ Đ²ÑĐ²ĐµĐ´ĐµĐ½Đ¸Ñ‚Đµ Đ¾Ñ‚ Đ²Đ°Ñ Đ´Đ°Đ½Đ½Đ¸. ĐœĐ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ³Đ¸ Đ¸Đ·Đ¿Ñ€Đ°Ñ‚Đ¸Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾, Đ½Đ¾ Ñ‚Đ°ĐºĐ° Ñ‰Đµ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ Đ²ÑÑĐºĐ¾ Đ¸Đ·Đ¿ÑĐ»Đ½ĐµĐ½Đ¾ Đ¾Ñ‚ Đ½ĐµÑ Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Đµ.</translation>
<translation id="7554791636758816595">ĐĐ¾Đ² Ñ€Đ°Đ·Đ´ĐµĐ»</translation>
-<translation id="7567204685887185387">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />; Đ²ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ´Đ° е Đ¸Đ·Đ´Đ°Đ´ĐµĐ½ Đ¸Đ·Đ¼Đ°Đ¼Đ½Đ¸Ñ‡ĐµÑĐºĐ¸. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ°Ñ‚Đ°ĐºÑƒĐ²Đ°Ñ‰.</translation>
<translation id="7568593326407688803">Đ¢Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° е Đ½Đ°<ph name="ORIGINAL_LANGUAGE" />Đ˜ÑĐºĐ°Ñ‚Đµ ли Đ´Đ° Ñ Đ¿Ñ€ĐµĐ²ĐµĐ´ĐµÑ‚Đµ?</translation>
<translation id="7569952961197462199">ĐÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ°Ñ‚Đ° ĐºĐ°Ñ€Ñ‚Đ° Đ´Đ° Ñе Đ¿Ñ€ĐµĐ¼Đ°Ñ…Đ½Đµ ли Đ¾Ñ‚ Chrome?</translation>
<translation id="7578104083680115302">Đ˜Đ·Đ²ÑÑ€ÑˆĐ²Đ°Đ¹Ñ‚Đµ бÑÑ€Đ·Đ¸ Đ¿Đ»Đ°Ñ‰Đ°Đ½Đ¸Ñ Đ² ÑĐ°Đ¹Ñ‚Đ¾Đ²Đµ и Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ Đ¾Ñ‚ Đ²ÑÑĐºĐ°ĐºĐ²Đ¸ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ° Đ¿Đ¾ÑÑ€ĐµĐ´ÑÑ‚Đ²Đ¾Đ¼ ĐºĐ°Ñ€Ñ‚Đ¸Ñ‚Đµ, ĐºĐ¾Đ¸Ñ‚Đ¾ ÑÑ‚Đµ Đ·Đ°Đ¿Đ°Đ·Đ¸Đ»Đ¸ Đ² Google.</translation>
+<translation id="7588950540487816470">Đ¤Đ¸Đ·Đ¸Ñ‡ĐµÑĐºĐ° Đ¼Ñ€ĐµĐ¶Đ°</translation>
<translation id="7592362899630581445">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° Đ½Đ°Ñ€ÑƒÑˆĐ°Đ²Đ° Đ¾Đ³Ñ€Đ°Đ½Đ¸Ñ‡ĐµĐ½Đ¸ÑÑ‚Đ° Đ·Đ° Đ¸Đ¼Đµ.</translation>
<translation id="759889825892636187">ĐŸĐ¾Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐ¼ <ph name="HOST_NAME" /> Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾Đ±Ñ€Đ°Đ±Đ¾Ñ‚Đ¸ Ñ‚Đ°Đ·Đ¸ Đ·Đ°ÑĐ²ĐºĐ°.</translation>
<translation id="7600965453749440009">ĐĐ¸ĐºĐ¾Đ³Đ° Đ´Đ° Đ½Đµ Ñе Đ¿Ñ€ĐµĐ²ĐµĐ¶Đ´Đ° Đ¾Ñ‚ <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">ĐÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ°Ñ‚Đ° ĐºĐ°Ñ€Ñ‚Đ° Đ´Đ° Ñе Đ¿Ñ€ĐµĐ¼Đ°Ñ…Đ½Đµ ли Đ¾Ñ‚ Chromium?</translation>
<translation id="765676359832457558">Đ¡ĐºÑ€Đ¸Đ²Đ°Đ½Đµ Đ½Đ° Ñ€Đ°Đ·ÑˆĐ¸Ñ€ĐµĐ½Đ¸Ñ‚Đµ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸...</translation>
<translation id="7658239707568436148">ĐÑ‚ĐºĐ°Đ·</translation>
+<translation id="7667346355482952095">Đ’ÑÑ€Đ½Đ°Ñ‚Đ¾Ñ‚Đ¾ Đ¾Đ·Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ Đ·Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°Ñ‚Đ° е Đ¿Ñ€Đ°Đ·Đ½Đ¾ или Đ½Đµ ÑÑĐ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²Đ° Đ½Đ° Ñ‚ĐµĐºÑƒÑ‰Đ¾Ñ‚Đ¾</translation>
<translation id="7668654391829183341">ĐĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ¾ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾</translation>
<translation id="7674629440242451245">Đ¢ÑÑ€ÑĐ¸Ñ‚Đµ Đ¸Đ½Ñ‚ĐµÑ€ĐµÑĐ½Đ¸ Đ½Đ¾Đ²Đ¸ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¸ Đ½Đ° Chrome? Đ˜Đ·Đ¿Ñ€Đ¾Đ±Đ²Đ°Đ¹Ñ‚Đµ ĐºĐ°Đ½Đ°Đ»Đ° Đ·Đ° Đ¿Ñ€Đ¾Đ³Ñ€Đ°Đ¼Đ¸ÑÑ‚Đ¸ Đ½Đ° Đ°Đ´Ñ€ĐµÑ chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ´ÑĐ»Đ¶Đ°Đ²Đ°Đ½Đµ ĐºÑĐ¼ <ph name="SITE" /> (Đ¾Đ¿Đ°ÑĐ½Đ¾)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">Đе, Đ±Đ»Đ°Đ³Đ¾Đ´Đ°Ñ€Ñ</translation>
<translation id="7805768142964895445">Đ¡ÑÑÑ‚Đ¾ÑĐ½Đ¸Đµ</translation>
<translation id="7813600968533626083">ĐŸÑ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸ĐµÑ‚Đ¾ Đ·Đ° Ñ„Đ¾Ñ€Đ¼ÑƒĐ»ÑÑ€Đ¸ Đ´Đ° Ñе Đ¿Ñ€ĐµĐ¼Đ°Ñ…Đ½Đµ ли Đ¾Ñ‚ Chrome?</translation>
+<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> Đ·Đ° â€<ph name="SEARCH_STRING" />“</translation>
<translation id="785549533363645510">Đ¡ÑÑ€Ñ„Đ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾ Đ²Đ¸ Đ¾Đ±Đ°Ñ‡Đµ Đ½Đµ е Đ½ĐµĐ²Đ¸Đ´Đ¸Đ¼Đ¾. ĐŸÑ€Đ¸ Đ¿Ñ€ĐµĐ¼Đ¸Đ½Đ°Đ²Đ°Đ½Đµ Đ² Ñ€ĐµĐ¶Đ¸Đ¼ â€Đ¸Đ½ĐºĐ¾Đ³Đ½Đ¸Ñ‚Đ¾â€œ Ñ‚Đ¾ Đ½Đµ Ñе ÑĐºÑ€Đ¸Đ²Đ° Đ¾Ñ‚ Ñ€Đ°Đ±Đ¾Ñ‚Đ¾Đ´Đ°Ñ‚ĐµĐ»Ñ Đ²Đ¸ и Đ¾Ñ‚ Đ´Đ¾ÑÑ‚Đ°Đ²Ñ‡Đ¸ĐºĐ° Đ²Đ¸ Đ½Đ° Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ уÑĐ»ÑƒĐ³Đ¸, Đ½Đ¸Ñ‚Đ¾ Đ¾Ñ‚ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚Đ¾Đ²ĐµÑ‚Đµ, ĐºĐ¾Đ¸Ñ‚Đ¾ Đ¿Đ¾ÑĐµÑ‰Đ°Đ²Đ°Ñ‚Đµ.</translation>
<translation id="7887683347370398519">ĐŸÑ€ĐµĐ³Đ»ĐµĐ´Đ°Đ¹Ñ‚Đµ ĐºĐ¾Đ´Đ° Đ·Đ° Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐºĐ° и Đ¾Đ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾</translation>
<translation id="7894616681410591072">ĐĐ¼Đ¸ ÑĐµĐ³Đ°! Đ—Đ° Đ´Đ¾ÑÑ‚ÑĐ¿ Đ´Đ¾ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²Đ¸ е Đ½ĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ¾ Ñ€Đ°Đ·Ñ€ĐµÑˆĐµĐ½Đ¸Đµ Đ¾Ñ‚ <ph name="NAME" />.</translation>
-<translation id="790025292736025802"><ph name="URL" /> Đ½Đµ е Đ½Đ°Đ¼ĐµÑ€ĐµĐ½</translation>
<translation id="7912024687060120840">Đ’ Đ¿Đ°Đ¿ĐºĐ°Ñ‚Đ°:</translation>
<translation id="7920092496846849526">ĐŸĐ¾Đ¿Đ¸Ñ‚Đ°Ñ…Ñ‚Đµ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»Ñ Ñи дали Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">Đе е Đ¿Đ¾ÑĐ¾Ñ‡ĐµĐ½Đ¾</translation>
<translation id="8012647001091218357">Đе Đ¼Đ¾Đ¶Đ°Ñ…Đ¼Đµ Đ´Đ° Ñе ÑĐ²ÑÑ€Đ¶ĐµĐ¼ Ñ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»Đ¸Ñ‚Đµ Đ²Đ¸. ĐœĐ¾Đ»Ñ, Đ¾Đ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾.</translation>
<translation id="8034522405403831421">Đ¢Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° е Đ½Đ° <ph name="SOURCE_LANGUAGE" />. Да Ñе Đ¿Ñ€ĐµĐ²ĐµĐ´Đµ ли Đ½Đ° <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">ĐÑĐ¼Đ° Đ½Đ°Đ¼ĐµÑ€ĐµĐ½Đ¸ Đ·Đ°Đ¿Đ¸Ñи Đ² иÑÑ‚Đ¾Ñ€Đ¸ÑÑ‚Đ°.</translation>
<translation id="8088680233425245692">ĐŸÑ€ĐµĐ³Đ»ĐµĐ¶Đ´Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° ÑÑ‚Đ°Ñ‚Đ¸ÑÑ‚Đ° Đ½Đµ бе уÑĐ¿ĐµÑˆĐ½Đ¾.</translation>
+<translation id="8089520772729574115">Đ¿Đ¾-Đ¼Đ°Đ»ĐºĐ¾ Đ¾Ñ‚ 1 ĐœĐ‘</translation>
<translation id="8091372947890762290">Đ’ ÑÑÑ€Đ²ÑÑ€Đ° Ñе Đ¸Đ·Ñ‡Đ°ĐºĐ²Đ° Đ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đµ</translation>
+<translation id="8129262335948759431">Đ½ĐµĐ¸Đ·Đ²ĐµÑÑ‚ĐµĐ½ Đ±Ñ€Đ¾Đ¹</translation>
<translation id="8131740175452115882">ĐŸĐ¾Ñ‚Đ²ÑÑ€Đ¶Đ´Đ°Đ²Đ°Đ½Đµ</translation>
<translation id="8134994873729925007">Đе Đ¼Đ¾Đ¶Đ° Đ´Đ° бÑде Đ½Đ°Đ¼ĐµÑ€ĐµĐ½ <ph name="BEGIN_ABBR" />DNS Đ°Đ´Ñ€ĐµÑÑÑ‚<ph name="END_ABBR" /> Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° Đ½Đ° <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">ĐĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€ÑÑ‚ Đ²Đ¸ Đ¿Ñ€ĐµĐ¼Đ¸Đ½Đ° Đ² ÑĐ¿Ñщ Ñ€ĐµĐ¶Đ¸Đ¼.</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">ĐĐµĐ²Đ°Đ»Đ¸Đ´ĐµĐ½ URL Đ°Đ´Ñ€ĐµÑ Đ·Đ° Đ°ĐºÑ‚ÑƒĐ°Đ»Đ¸Đ·Đ¸Ñ€Đ°Đ½Đµ Đ½Đ° Ñ€Đ°Đ·ÑˆĐ¸Ñ€ĐµĐ½Đ¸ĐµÑ‚Đ¾ Ñ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½ĐµĐ½ Đ½Đ¾Đ¼ĐµÑ€ <ph name="EXTENSION_ID" />.</translation>
<translation id="8218327578424803826">Đ—Đ°Đ´Đ°Đ´ĐµĐ½Đ¾ Đ¼ĐµÑÑ‚Đ¾Đ¿Đ¾Đ»Đ¾Đ¶ĐµĐ½Đ¸Đµ:</translation>
<translation id="8225771182978767009">Đ§Đ¾Đ²ĐµĐºÑÑ‚, ĐºĐ¾Đ¹Ñ‚Đ¾ е Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¸Đ» ĐºĐ¾Đ¼Đ¿ÑÑ‚ÑÑ€Đ°, е Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ» Ñ‚Đ¾Đ·Đ¸ ÑĐ°Đ¹Ñ‚.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" /> и <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Đ¡Ñ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°, ĐºĐ¾ÑÑ‚Đ¾ Ñ‚ÑÑ€ÑĐ¸Ñ‚Đµ, Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ° Đ²ÑĐ²ĐµĐ´ĐµĐ½Đ°Ñ‚Đ° Đ¾Ñ‚ Đ²Đ°Ñ Đ¸Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ. ĐĐºĐ¾ Ñе Đ²ÑÑ€Đ½ĐµÑ‚Đµ Đ½Đ° Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°, Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑÑ‚Đ°, ĐºĐ¾Đ¸Ñ‚Đ¾ Đ²ĐµÑ‡Đµ ÑÑ‚Đµ Đ¸Đ·Đ¿ÑĐ»Đ½Đ¸Đ»Đ¸, Đ¼Đ¾Đ¶Đµ Đ´Đ° бÑĐ´Đ°Ñ‚ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€ĐµĐ½Đ¸. Đ˜ÑĐºĐ°Ñ‚Đµ ли Đ´Đ° Đ¿Ñ€Đ¾Đ´ÑĐ»Đ¶Đ¸Ñ‚Đµ?</translation>
<translation id="8249320324621329438">ĐŸĐ¾ÑĐ»ĐµĐ´Đ½Đ¾ Đ¸Đ·Đ²Đ»Đ¸Ñ‡Đ°Đ½Đµ:</translation>
<translation id="8261506727792406068">Đ˜Đ·Ñ‚Ñ€Đ¸Đ²Đ°Đ½Đµ</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">Đ›ĐµĐ½Ñ‚Đ° Đ½Đ° Đ¾Ñ‚Đ¼ĐµÑ‚ĐºĐ¸Ñ‚Đµ</translation>
<translation id="8363502534493474904">Đ˜Đ·ĐºĐ»ÑÑ‡ĐµÑ‚Đµ ÑĐ°Đ¼Đ¾Đ»ĐµÑ‚Đ½Đ¸Ñ Ñ€ĐµĐ¶Đ¸Đ¼.</translation>
<translation id="8364627913115013041">Đе е Đ·Đ°Đ´Đ°Đ´ĐµĐ½Đ¾.</translation>
+<translation id="8380941800586852976">ĐĐ¿Đ°ÑĐ½Đ¾</translation>
<translation id="8412145213513410671">Đ¡Ñ€Đ¸Đ²Đ¾Đ²Đµ (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Đ¢Ñ€ÑĐ±Đ²Đ° Đ´Đ° Đ²ÑĐ²ĐµĐ´ĐµÑ‚Đµ ĐµĐ´Đ¸Đ½ и ÑÑÑ‰Đ¸ Đ¿Ñ€Đ¾Đ¿ÑƒÑĐº Đ´Đ²Đ° Đ¿ÑÑ‚Đ¸.</translation>
<translation id="8428213095426709021">ĐĐ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸</translation>
+<translation id="8433057134996913067">Ще Đ¸Đ·Đ»ĐµĐ·ĐµÑ‚Đµ Đ¾Ñ‚ Đ¿Đ¾Đ²ĐµÑ‡ĐµÑ‚Đ¾ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚Đ¾Đ²Đµ.</translation>
<translation id="8437238597147034694">&amp;ĐÑ‚Đ¼ÑĐ½Đ° Đ½Đ° Đ¿Ñ€ĐµĐ¼ĐµÑÑ‚Đ²Đ°Đ½ĐµÑ‚Đ¾</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ° ĐºĐ°Ñ€Ñ‚Đ°}other{# ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ¸ ĐºĐ°Ñ€Ñ‚Đ¸}}</translation>
+<translation id="8483780878231876732">Đ—Đ° Đ´Đ° Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ°Ñ‚Đµ ĐºĐ°Ñ€Ñ‚Đ¸Ñ‚Đµ Đ¾Ñ‚ Đ¿Ñ€Đ¾Ñ„Đ¸Đ»Đ° Ñи Đ² Google, Đ²Đ»ĐµĐ·Ñ‚Đµ Đ² Chrome</translation>
<translation id="8488350697529856933">ĐŸÑ€Đ¸Đ»Đ°Đ³Đ° Ñе ĐºÑĐ¼</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> Đ½Đµ Đ¾Ñ‚Đ³Đ¾Đ²Đ°Ñ€Ñ Ñ‚Đ²ÑÑ€Đ´Đµ Đ´ÑĐ»Đ³Đ¾ Đ²Ñ€ĐµĐ¼Đµ.</translation>
+<translation id="852346902619691059">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ, Ñ‡Đµ е <ph name="DOMAIN" />. Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ¼Ñƒ Đ·Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾ÑÑ‚ Đ½Đµ Ñе ÑÑ‡Đ¸Ñ‚Đ° Đ·Đ° Đ½Đ°Đ´ĐµĐ¶Đ´ĐµĐ½ Đ¾Ñ‚ Đ¾Đ¿ĐµÑ€Đ°Ñ†Đ¸Đ¾Đ½Đ½Đ°Ñ‚Đ° ÑиÑÑ‚ĐµĐ¼Đ° Đ½Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾Ñ‚Đ¾ Đ²Đ¸. Đ¢Đ¾Đ²Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе Đ´Ñлжи Đ½Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸Ñ€Đ°Đ½Đµ или Đ½Đ° Đ¿Ñ€ĐµÑ…Đ²Đ°Ñ‰Đ°Đ½Đµ Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°. <ph name="BEGIN_LEARN_MORE_LINK" />ĐĐ°ÑƒÑ‡ĐµÑ‚Đµ Đ¿Đ¾Đ²ĐµÑ‡Đµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Đ¢Đ¾Đ·Đ¸ Ñ‚Đ¸Đ¿ ĐºĐ°Ñ€Ñ‚Đ° Đ½Đµ Ñе Đ¿Đ¾Đ´Đ´ÑÑ€Đ¶Đ° Đ¾Ñ‚ Google Payments. ĐœĐ¾Đ»Ñ, Đ¸Đ·Đ±ĐµÑ€ĐµÑ‚Đµ Đ´Ñ€ÑƒĐ³Đ°.</translation>
<translation id="8550022383519221471">Đ£ÑĐ»ÑƒĐ³Đ°Ñ‚Đ° Đ·Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½Đµ Đ½Đµ е Đ½Đ°Đ»Đ¸Ñ†Đµ Đ·Đ° Đ²Đ°ÑˆĐ¸Ñ Đ´Đ¾Đ¼ĐµĐ¹Đ½.</translation>
<translation id="8553075262323480129">ĐŸÑ€ĐµĐ²Đ¾Đ´ÑÑ‚ Đ½Đµ бе уÑĐ¿ĐµÑˆĐµĐ½, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ĐµĐ·Đ¸ĐºÑÑ‚ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° бÑде Đ¾Đ¿Ñ€ĐµĐ´ĐµĐ»ĐµĐ½.</translation>
@@ -633,15 +675,12 @@
<translation id="8647750283161643317">Đ’ÑĐ·ÑÑ‚Đ°Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ²ÑĐ¸Ñ‡ĐºĐ¾ ĐºÑĐ¼ ÑÑ‚Đ°Đ½Đ´Đ°Ñ€Ñ‚Đ½Đ¾Ñ‚Đ¾ ÑÑÑÑ‚Đ¾ÑĐ½Đ¸Đµ</translation>
<translation id="8680787084697685621">Đ”Đ°Đ½Đ½Đ¸Ñ‚Đµ Đ·Đ° Đ²Ñ…Đ¾Đ´ Đ² Đ¿Ñ€Đ¾Ñ„Đ¸Đ»Đ° Đ²Đ¸ Đ½Đµ ÑĐ° Đ°ĐºÑ‚ÑƒĐ°Đ»Đ½Đ¸.</translation>
<translation id="8703575177326907206">Đ’Ñ€ÑĐ·ĐºĐ°Ñ‚Đ° Đ²Đ¸ Ñ <ph name="DOMAIN" /> Đ½Đµ е ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ°.</translation>
-<translation id="8713130696108419660">Đ›Đ¾Ñˆ Đ¿Đ¾Đ´Đ¿Đ¸Ñ Đ¿Đ¾ÑÑ€ĐµĐ´ÑÑ‚Đ²Đ¾Đ¼ Đ¿ÑÑ€Đ²Đ¾Đ½Đ°Ñ‡Đ°Đ»Đ½Đ¸Ñ ĐºĐ»Ñч</translation>
<translation id="8725066075913043281">ĐĐ¿Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ¾Ñ‚Đ½Đ¾Đ²Đ¾</translation>
<translation id="8728672262656704056">ĐŸÑ€ĐµĐ¼Đ¸Đ½Đ°Ñ…Ñ‚Đµ Đ² Ñ€ĐµĐ¶Đ¸Đ¼ â€Đ¸Đ½ĐºĐ¾Đ³Đ½Đ¸Ñ‚Đ¾â€œ</translation>
<translation id="8730621377337864115">Đ“Đ¾Ñ‚Đ¾Đ²Đ¾</translation>
<translation id="8738058698779197622">Đ—Đ° уÑÑ‚Đ°Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° ÑĐ¸Đ³ÑƒÑ€Đ½Đ° Đ²Ñ€ÑĐ·ĐºĐ° е Đ½ĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ¾ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸ĐºÑÑ‚ Đ²Đ¸ Đ´Đ° е Đ²ĐµÑ€ĐµĐ½. Đ¢Đ¾Đ²Đ° е Ñ‚Đ°ĐºĐ°, Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¸Ñ‚Đµ, Ñ ĐºĐ¾Đ¸Ñ‚Đ¾ ÑƒĐµĐ±ÑĐ°Đ¹Ñ‚Đ¾Đ²ĐµÑ‚Đµ Ñе Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸Ñ†Đ¸Ñ€Đ°Ñ‚, ÑĐ° Đ²Đ°Đ»Đ¸Đ´Đ½Đ¸ ÑĐ°Đ¼Đ¾ Đ·Đ° ĐºĐ¾Đ½ĐºÑ€ĐµÑ‚Đ½Đ¸ Đ¿ĐµÑ€Đ¸Đ¾Đ´Đ¸ Đ¾Ñ‚ Đ²Ñ€ĐµĐ¼Đµ. Đ¢ÑĐ¹ ĐºĐ°Ñ‚Đ¾ Ñ‡Đ°ÑĐ¾Đ²Đ½Đ¸ĐºÑÑ‚ Đ½Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾Ñ‚Đ¾ Đ²Đ¸ Đ½Đµ е Đ²ĐµÑ€ĐµĐ½, Chromium Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¿Đ¾Ñ‚Đ²ÑÑ€Đ´Đ¸ Ñ‚ĐµĐ·Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¸.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS Đ°Đ´Ñ€ĐµÑÑÑ‚&lt;/abbr&gt; Đ½Đ° <ph name="HOST_NAME" /> Đ½Đµ Đ¼Đ¾Đ¶Đ° Đ´Đ° бÑде Đ½Đ°Đ¼ĐµÑ€ĐµĐ½. ĐŸÑ€Đ¾Đ±Đ»ĐµĐ¼ÑÑ‚ Ñе Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸Ñ†Đ¸Ñ€Đ°.</translation>
-<translation id="8741995161408053644">Đ’ÑĐ·Đ¼Đ¾Đ¶Đ½Đ¾ е Đ² Đ¿Ñ€Đ¾Ñ„Đ¸Đ»Đ° Đ²Đ¸ Đ² Google Đ´Đ° Đ¸Đ¼Đ° Đ´Ñ€ÑƒĐ³Đ¸ Đ²Đ¸Đ´Đ¾Đ²Đµ иÑÑ‚Đ¾Ñ€Đ¸Ñ Đ½Đ° ÑÑÑ€Ñ„Đ¸Ñ€Đ°Đ½Đµ, ÑÑÑ…Ñ€Đ°Đ½ÑĐ²Đ°Đ½Đ¸ Đ½Đ° Đ°Đ´Ñ€ĐµÑ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Đ’ÑĐ·ÑÑ‚Đ°Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ¸Đ·Ñ‚Ñ€Đ¸Đ²Đ°Đ½ĐµÑ‚Đ¾</translation>
-<translation id="8790687370365610530">Đ—Đ° Đ´Đ° Đ¿Đ¾Đ»ÑƒÑ‡Đ°Đ²Đ°Ñ‚Đµ Đ¿ĐµÑ€ÑĐ¾Đ½Đ°Đ»Đ¸Đ·Đ¸Ñ€Đ°Đ½Đ¾ ÑÑĐ´ÑÑ€Đ¶Đ°Đ½Đ¸Đµ, Đ¿Ñ€ĐµĐ´Đ»Đ°Đ³Đ°Đ½Đ¾ Đ¾Ñ‚ Google, Đ²ĐºĐ»ÑÑ‡ĐµÑ‚Đµ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾ Đ½Đ° иÑÑ‚Đ¾Ñ€Đ¸ÑÑ‚Đ°.</translation>
<translation id="8798099450830957504">ĐŸĐ¾ Đ¿Đ¾Đ´Ñ€Đ°Đ·Đ±Đ¸Ñ€Đ°Đ½Đµ</translation>
<translation id="8804164990146287819">Đ”ĐµĐºĐ»Đ°Ñ€Đ°Ñ†Đ¸Ñ Đ·Đ° Đ¿Đ¾Đ²ĐµÑ€Đ¸Ñ‚ĐµĐ»Đ½Đ¾ÑÑ‚</translation>
<translation id="8820817407110198400">ĐÑ‚Đ¼ĐµÑ‚ĐºĐ¸</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ÑÑ‚ Đ½Đ° ÑÑÑ€Đ²ÑÑ€Đ° е Ñ Đ¸Đ·Ñ‚ĐµĐºĐ»Đ° Đ²Đ°Đ»Đ¸Đ´Đ½Đ¾ÑÑ‚.</translation>
<translation id="8987927404178983737">ĐœĐµÑĐµÑ†</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Đ¡ÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, ĐºĐ¾Đ¹Ñ‚Đ¾ Đ½Đµ е Ñ€Đ°Đ·ĐºÑ€Đ¸Ñ‚ Đ¿ÑƒĐ±Đ»Đ¸Ñ‡Đ½Đ¾ Ñ‡Ñ€ĐµĐ· Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾ Đ² ĐŸÑ€Đ¾Đ·Ñ€Đ°Ñ‡Đ½Đ¾ÑÑ‚ Đ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¸Ñ‚Đµ. Đ¢Đ¾Đ²Đ° Ñе изиÑĐºĐ²Đ° Đ·Đ° Đ½ÑĐºĐ¾Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¸ Ñ Ñ†ĐµĐ» Đ·Đ°Ñ‰Đ¸Ñ‚Đ° ÑÑ€ĐµÑ‰Ñƒ Ñ…Đ°ĐºĐµÑ€Đ¸ и Đ·Đ° Đ´Đ° е ÑĐ¸Đ³ÑƒÑ€Đ½Đ¾, Ñ‡Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¸Đ¼ Ñе Đ¸Đ¼Đ° Đ´Đ¾Đ²ĐµÑ€Đ¸Đµ.</translation>
<translation id="9001074447101275817">Đ˜Đ·Đ¸ÑĐºĐ²Đ°Ñ‚ Ñе Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»ÑĐºĐ¾ Đ¸Đ¼Đµ и Đ¿Đ°Ñ€Đ¾Đ»Đ° Đ·Đ° Đ¿Ñ€Đ¾ĐºÑи ÑÑÑ€Đ²ÑÑ€Đ° <ph name="DOMAIN" />.</translation>
<translation id="901974403500617787">Đ¤Đ»Đ°Đ³Đ¾Đ²ĐµÑ‚Đµ, ĐºĐ¾Đ¸Ñ‚Đ¾ Ñе Đ¿Ñ€Đ¸Đ»Đ°Đ³Đ°Ñ‚ Đ·Đ° цÑĐ»Đ°Ñ‚Đ° ÑиÑÑ‚ĐµĐ¼Đ°, Đ¼Đ¾Đ³Đ°Ñ‚ Đ´Đ° бÑĐ´Đ°Ñ‚ Đ·Đ°Đ´Đ°Đ´ĐµĐ½Đ¸ ÑĐ°Đ¼Đ¾ Đ¾Ñ‚ ÑĐ¾Đ±ÑÑ‚Đ²ĐµĐ½Đ¸ĐºĐ°: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Đ¢Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° е Đ¿Ñ€ĐµĐ²ĐµĐ´ĐµĐ½Đ° Đ½Đ° <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Đ˜Đ·Đ¿Đ¾Đ»Đ·Đ²Đ°Đ½Đµ Đ½Đ° уÑĐ»ÑƒĐ³Đ° Đ·Đ° Đ¿Ñ€ĐµĐ´Đ²Đ¸Đ¶Đ´Đ°Đ½Đµ Ñ Ñ†ĐµĐ» Đ¿Đ¾-бÑÑ€Đ·Đ¾ Đ·Đ°Ñ€ĐµĐ¶Đ´Đ°Đ½Đµ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ¸Ñ‚Đµ</translation>
<translation id="9039213469156557790">ĐÑĐ²ĐµĐ½ Ñ‚Đ¾Đ²Đ° Ñ‚Đ°Đ·Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐºĐ»ÑÑ‡Đ²Đ° Đ´Ñ€ÑƒĐ³Đ¸ Ñ€ĐµÑурÑи, ĐºĐ¾Đ¸Ñ‚Đ¾ Đ½Đµ ÑĐ° Đ·Đ°Ñ‰Đ¸Ñ‚ĐµĐ½Đ¸. Đ”Đ¾ĐºĐ°Ñ‚Đ¾ Ñе Đ¿Ñ€ĐµĐ´Đ°Đ²Đ°Ñ‚, Ñ‚Đµ Đ¼Đ¾Đ³Đ°Ñ‚ Đ´Đ° бÑĐ´Đ°Ñ‚ Đ²Đ¸Đ´ĐµĐ½Đ¸ Đ¾Ñ‚ Đ´Ñ€ÑƒĐ³Đ¸ Ñ…Đ¾Ñ€Đ° и Đ´Đ° бÑĐ´Đ°Ñ‚ Đ¼Đ¾Đ´Đ¸Ñ„Đ¸Ñ†Đ¸Ñ€Đ°Đ½Đ¸ Đ¾Ñ‚ Đ¸Đ·Đ²ÑÑ€ÑˆĐ¸Ñ‚ĐµĐ» Đ½Đ° Đ°Ñ‚Đ°ĐºĐ°, Ñ‚Đ°ĐºĐ° Ñ‡Đµ Đ´Đ° Ñе Đ¿Ñ€Đ¾Đ¼ĐµĐ½Đ¸ Đ¿Đ¾Đ²ĐµĐ´ĐµĐ½Đ¸ĐµÑ‚Đ¾ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ°.</translation>
-<translation id="9049981332609050619">ĐĐ¿Đ¸Ñ‚Đ°Ñ…Ñ‚Đµ Đ´Đ° Đ¾Ñ‚Đ²Đ¾Ñ€Đ¸Ñ‚Đµ <ph name="DOMAIN" />, Đ½Đ¾ ÑÑÑ€Đ²ÑÑ€ÑÑ‚ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸ Đ½ĐµĐ²Đ°Đ»Đ¸Đ´ĐµĐ½ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚.</translation>
<translation id="9050666287014529139">ĐŸĐ°Ñ€Đ¾Đ»Đ°</translation>
<translation id="9065203028668620118">Đ ĐµĐ´Đ°ĐºÑ‚Đ¸Ñ€Đ°Đ½Đµ</translation>
<translation id="9092364396508701805">Đ¡Ñ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°Ñ‚Đ° Đ½Đ° <ph name="HOST_NAME" /> Đ½Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ¸</translation>
diff --git a/chromium/components/strings/components_strings_bn.xtb b/chromium/components/strings/components_strings_bn.xtb
index 1f940316b9e..4c75bb9c611 100644
--- a/chromium/components/strings/components_strings_bn.xtb
+++ b/chromium/components/strings/components_strings_bn.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="bn">
+<translation id="1008557486741366299">à¦à¦–নই নয়</translation>
<translation id="1015730422737071372">অতিরিকà§à¦¤ বিবরণ দিন</translation>
<translation id="1032854598605920125">ঘড়ির কাà¦à¦Ÿà¦¾à¦° দিকে ঘোরান</translation>
<translation id="1038842779957582377">অজানা নাম</translation>
+<translation id="1053591932240354961">à¦à¦‡ মà§à¦¹à§‚রà§à¦¤à§‡ আপনি <ph name="SITE" /> ঠযেতে পারবেন না কারণ ওয়েবসাইটটি à¦à¦®à¦¨ অবোধà§à¦¯ শংসাপতà§à¦° পাঠিয়েছে যেটি Google Chrome à¦à¦¾à¦²à¦¾à¦¤à§‡ পারছে না। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত কিছà§à¦•à§à¦·à¦¨à§‡à¦° জনà§à¦¯ হয়ে থাকে, তাই à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="1055184225775184556">&amp;যোগ করাকে পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
<translation id="10614374240317010">কখনও সংরকà§à¦·à¦¿à¦¤ হয়নি</translation>
-<translation id="1064422015032085147">যে সারà§à¦­à¦¾à¦° ওয়েবপৃষà§à¦ à¦¾à¦Ÿà¦¿ হোসà§à¦Ÿ করছে সেটি ওভারলোড হয়ে থাকতে পারে বা সেটি রকà§à¦·à¦£à¦¾à¦¬à§‡à¦•à§à¦·à¦£à¦¾à¦§à§€à¦¨ অবসà§à¦¥à¦¾à§Ÿ আছে।
- খà§à¦¬ বেশি টà§à¦°à¦¾à¦«à¦¿à¦• তৈরি করা à¦à§œà¦¾à¦¨à§‹ à¦à¦¬à¦‚ পরিসà§à¦¥à¦¿à¦¤à¦¿à¦° আরো অবনতি à¦à§œà¦¾à¦¨à§‹à¦° উদà§à¦¦à§‡à¦¶à§à¦¯à§‡,
- à¦à¦‡ URL ঠঅনà§à¦°à§‹à¦§ পাঠানো সাময়িকভাবে অননà§à¦®à§‹à¦¦à¦¿à¦¤ করা হয়েছে।</translation>
<translation id="106701514854093668">ডেসà§à¦•à¦Ÿà¦ª বà§à¦•à¦®à¦¾à¦°à§à¦•</translation>
<translation id="1080116354587839789">পà§à¦°à¦¸à§à¦¥à§‡à¦° মধà§à¦¯à§‡ আà¦à¦Ÿà¦¾à¦¨</translation>
+<translation id="1103124106085518534">à¦à¦–নকার মতো সমà§à¦ªà¦¨à§à¦¨ হয়েছে</translation>
<translation id="1103523840287552314">সরà§à¦¬à¦¦à¦¾ অনà§à¦¬à¦¾à¦¦ করà§à¦¨ <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">যদি পরীকà§à¦·à¦¾ করা হয়, Chrome দà§à¦°à§à¦¤ ফরà§à¦® পূরণ করার জনà§à¦¯ à¦à¦‡ ডিভাইসে থাকা আপনার কারà§à¦¡à§‡à¦° à¦à¦•à¦Ÿà¦¿ পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ সà¦à§à¦à§Ÿ করবে৷</translation>
+<translation id="1111153019813902504">সামà§à¦ªà§à¦°à¦¤à¦¿à¦• ঘà§à¦°à§‡ দেখা বà§à¦•à¦®à¦¾à¦°à§à¦•à¦—à§à¦²à¦¿</translation>
<translation id="1113869188872983271">&amp;পà§à¦¨à¦°à§à¦¬à¦¿à¦¨à§à¦¯à¦¾à¦¸à¦•à§‡ পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
+<translation id="1126551341858583091">সà§à¦¥à¦¾à¦¨à§€à¦¯à¦¼ সà¦à§à¦à§Ÿà¦¸à§à¦¥à¦¾à¦¨à§‡à¦° আকার হলো <ph name="CRASH_SIZE" />।</translation>
<translation id="112840717907525620">নীতি কà§à¦¯à¦¾à¦¶à§‡à¦Ÿà¦¿ ঠিক আছে</translation>
<translation id="113188000913989374"><ph name="SITE" /> বলছে:</translation>
<translation id="1132774398110320017">Chrome সà§à¦¬à¦¤à¦ƒà¦ªà§‚রà§à¦£ সেটিংস...</translation>
-<translation id="1150979032973867961">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° নিকট বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯ নয়। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="1152921474424827756"><ph name="URL" /> à¦à¦° <ph name="BEGIN_LINK" />কà§à¦¯à¦¾à¦¶à§‡ করা অনà§à¦²à¦¿à¦ªà¦¿<ph name="END_LINK" /> অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করà§à¦¨</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> অপà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¿à¦¤à¦­à¦¾à¦¬à§‡ সংযোগ বনà§à¦§ করেছে।</translation>
<translation id="1161325031994447685">ওয়াই-ফাই ঠপà§à¦¨à¦°à¦¾à§Ÿ সংযà§à¦•à§à¦¤ করে দেখà§à¦¨</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">সরান</translation>
<translation id="1201402288615127009">পরবরà§à¦¤à§€</translation>
<translation id="1201895884277373915">à¦à¦‡ সাইট থেকে আরো</translation>
-<translation id="121201262018556460">আপনি <ph name="DOMAIN" />-ঠপৌà¦à¦›à¦¾à¦¨à§‹à¦° পà§à¦°à¦à§‡à¦·à§à¦Ÿà¦¾ করেছেন, কিনà§à¦¤à§ সারà§à¦­à¦¾à¦° à¦à¦•à¦Ÿà¦¿ দà§à¦°à§à¦¬à¦² কী সমà§à¦¬à¦²à¦¿à¦¤ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে৷ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত কী ভঙà§à¦— করে থাকতে পারে à¦à¦¬à¦‚ সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ আপনার পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¿à¦¤ সারà§à¦­à¦¾à¦° নাও হতে পারে (হতে পারে আপনি à¦à¦•à¦œà¦¨ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° সাথে যোগাযোগ করছেন)৷</translation>
+<translation id="1206967143813997005">নষà§à¦Ÿ পà§à¦°à¦¾à¦¥à¦®à¦¿à¦• সà§à¦¬à¦¾à¦•à§à¦·à¦°</translation>
+<translation id="1209206284964581585">à¦à¦–নকার মতো লà§à¦•à¦¾à¦¨</translation>
<translation id="1219129156119358924">সিসà§à¦Ÿà§‡à¦® নিরাপতà§à¦¤à¦¾</translation>
<translation id="1227224963052638717">অজানা নীতি৷</translation>
<translation id="1227633850867390598">মান লà§à¦•à¦¾à¦¨</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">হà§à¦¯à¦¾à¦</translation>
<translation id="1430915738399379752">পà§à¦°à¦¿à¦¨à§à¦Ÿ</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /><ph name="DOMAIN" /> ঠপৃষà§à¦ à¦¾ পরিদরà§à¦¶à¦¨ করার<ph name="END_LINK" /> পà§à¦°à¦à§‡à¦·à§à¦Ÿà¦¾ অবরà§à¦¦à§à¦§ করা হয়েছে৷</translation>
+<translation id="1491663344921578213">আপনি à¦à¦–ন <ph name="SITE" /> ঠযেতে পারবেন না কারণ ওয়েবসাইটটি পিন করা শংসাপতà§à¦° বà§à¦¯à¦¬à¦¹à¦¾à¦° করছে। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত সাময়িকভাবে হয়ে থাকে, তাই à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="1506687042165942984">à¦à¦‡ পৃষà§à¦ à¦¾à¦° à¦à¦•à¦Ÿà¦¿ সংরকà§à¦·à¦¿à¦¤ পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ (অরà§à¦¥à¦¾à§,তারিখ সীমার বাইরে হিসাবে পরিà¦à¦¿à¦¤) পà§à¦°à¦¦à¦°à§à¦¶à¦¨ করà§à¦¨à§·</translation>
<translation id="1519264250979466059">নিরà§à¦®à¦¾à¦£à§‡à¦° তারিখ</translation>
<translation id="1549470594296187301">à¦à¦‡ বৈশিষà§à¦Ÿà§à¦¯à¦Ÿà¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করার জনà§à¦¯ JavaScript সকà§à¦·à¦® করা পà§à¦°à§Ÿà§‹à¦œà¦¨à¥¤</translation>
@@ -60,37 +63,35 @@
<translation id="1644184664548287040">নেটওয়ারà§à¦• কনফিগারেশনটি অবৈধ à¦à¦¬à¦‚ আমদানি করা যায়নি৷</translation>
<translation id="1644574205037202324">ইতিহাস</translation>
<translation id="1645368109819982629">অসমরà§à¦¥à¦¿à¦¤ পà§à¦°à§‹à¦Ÿà§‹à¦•à¦²</translation>
-<translation id="1655462015569774233">{1,plural, =1{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ গতকাল মেয়াদোতà§à¦¤à§€à¦°à§à¦£ হয়েছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে। আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° ঘড়ি বরà§à¦¤à¦®à¦¾à¦¨à§‡ <ph name="CURRENT_DATE" /> ঠসেট করা আছে। à¦à¦Ÿà¦¿ কি ঠিক আছে বলে মনে হà¦à§à¦›à§‡? যদি তা না হয়, তাহলে আপনার সিসà§à¦Ÿà§‡à¦® ঘড়িটি ঠিক করা উà¦à¦¿à¦¤ হবে à¦à¦¬à¦‚ তারপর à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ রিফà§à¦°à§‡à¦¶ করা উà¦à¦¿à¦¤à¥¤}one{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ # দিন আগে মেয়াদোতà§à¦¤à§€à¦°à§à¦£ হয়েছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে। আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° ঘড়ি বরà§à¦¤à¦®à¦¾à¦¨à§‡ <ph name="CURRENT_DATE" /> ঠসেট করা আছে। à¦à¦Ÿà¦¿ কি ঠিক আছে বলে মনে হà¦à§à¦›à§‡? যদি তা না হয়, তাহলে আপনার সিসà§à¦Ÿà§‡à¦® ঘড়িটি ঠিক করা উà¦à¦¿à¦¤ হবে à¦à¦¬à¦‚ তারপর à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ রিফà§à¦°à§‡à¦¶ করা উà¦à¦¿à¦¤à¥¤}other{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ # দিন আগে মেয়াদোতà§à¦¤à§€à¦°à§à¦£ হয়েছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে। আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° ঘড়ি বরà§à¦¤à¦®à¦¾à¦¨à§‡ <ph name="CURRENT_DATE" /> ঠসেট করা আছে। à¦à¦Ÿà¦¿ কি ঠিক আছে বলে মনে হà¦à§à¦›à§‡? যদি তা না হয়, তাহলে আপনার সিসà§à¦Ÿà§‡à¦® ঘড়িটি ঠিক করা উà¦à¦¿à¦¤ হবে à¦à¦¬à¦‚ তারপর à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ রিফà§à¦°à§‡à¦¶ করা উà¦à¦¿à¦¤à¥¤}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> সাধারণত আপনার তথà§à¦¯ সà§à¦°à¦•à§à¦·à¦¿à¦¤ রাখতে à¦à¦¨à¦•à§à¦°à¦¿à¦ªà¦¶à¦¾à¦¨ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে। à¦à¦‡à¦¬à¦¾à¦° যখন Google Chrome <ph name="SITE" /> à¦à¦° সাথে সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করার à¦à§‡à¦·à§à¦Ÿà¦¾ করেছে, তখন ওয়েবসাইটটি অসà§à¦¬à¦¾à¦­à¦¾à¦¬à¦¿à¦• à¦à¦¬à¦‚ ভà§à¦² শংসাপতà§à¦° পাঠিয়েছে। হয় à¦à¦•à¦œà¦¨ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ <ph name="SITE" /> হওয়ার ভান করছে, অথবা কোনো ওয়াই-ফাই পà§à¦°à¦¬à§‡à¦¶ করà§à¦¨ সà§à¦•à§à¦°à§€à¦£ সংযোগকে বাধা দেওয়া হয়েছে। আপনার তথà§à¦¯ à¦à¦–নো নিরাপদ আছে কারণ কোনো ডেটা আদানপà§à¦°à¦¦à¦¾à¦¨à§‡à¦° আগেই Google Chrome সংযোগটিকে বনà§à¦§ করে দিয়েছে।</translation>
<translation id="168841957122794586">সারà§à¦­à¦¾à¦° শংসাপতà§à¦°à§‡ à¦à¦•à¦Ÿà¦¿ দà§à¦°à§à¦¬à¦² কপিরাইট কী আছে৷</translation>
<translation id="1701955595840307032">পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤ সামগà§à¦°à§€ পান</translation>
-<translation id="1706954506755087368">{1,plural, =1{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ আগামীকালের বলে মনে হà¦à§à¦›à§‡à¥¤ কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে।}one{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ আগামী # দিন পরের বলে মনে হà¦à§à¦›à§‡à¥¤ কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে।}other{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ আগামী # দিন পরের বলে মনে হà¦à§à¦›à§‡à¥¤ কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে।}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">সিসà§à¦Ÿà§‡à¦® পà§à¦°à¦¶à¦¾à¦¸à¦•à§‡à¦° সাথে যোগাযোগ করে দেখà§à¦¨à¥¤</translation>
<translation id="17513872634828108">খোলা টà§à¦¯à¦¾à¦¬</translation>
<translation id="1753706481035618306">পৃষà§à¦ à¦¾ সংখà§à¦¯à¦¾</translation>
-<translation id="1761412452051366565">Google দà§à¦¬à¦¾à¦°à¦¾ পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤ বà§à¦¯à¦•à§à¦¤à¦¿à¦—তকৃত সামগà§à¦°à§€ পেতে, সিঙà§à¦• à¦à¦¾à¦²à§ করà§à¦¨à¥¤</translation>
-<translation id="1763864636252898013">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ আপনার ডিভােইসের নিকট বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯ নয়। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows নেটওয়ারà§à¦• ডায়গনিসà§à¦Ÿà¦¿à¦•à§à¦¸ à¦à¦¾à¦²à¦¿à§Ÿà§‡ দেখà§à¦¨<ph name="END_LINK" />।</translation>
<translation id="1783075131180517613">দয়া করে আপনার সিঙà§à¦• পাসফà§à¦°à§‡à¦œ আপডেট করà§à¦¨à§·</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">আপনার সমà§à¦ªà§à¦°à¦¤à¦¿ ঘà§à¦°à§‡ দেখা বà§à¦•à¦®à¦¾à¦°à§à¦•à¦—à§à¦²à¦¿ à¦à¦–ানে দেখা যাবে।</translation>
<translation id="1821930232296380041">অবৈধ অনà§à¦°à§‹à¦§ বা অনà§à¦°à§‹à¦§ মাপকাঠিগà§à¦²à¦¿</translation>
<translation id="1838667051080421715">আপনি à¦à¦•à¦Ÿà¦¿ ওয়েব পৃষà§à¦ à¦¾à¦° উà§à¦¸ কোড দেখছেন।</translation>
<translation id="1871208020102129563">
পà§à¦°à¦•à§à¦¸à¦¿ সà§à¦¥à¦¿à¦° পà§à¦°à¦•à§à¦¸à¦¿ সারà§à¦­à¦¾à¦°à¦—à§à¦²à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে সেট করা আছে কোনো .pac সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ URL নয়৷</translation>
<translation id="1883255238294161206">তালিকা সঙà§à¦•à§à¦à¦¿à¦¤ করà§à¦¨</translation>
<translation id="1898423065542865115">ফিলà§à¦Ÿà¦¾à¦° হà¦à§à¦›à§‡</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> আপনার লগইন শংসাপতà§à¦°à¦Ÿà¦¿ সà§à¦¬à§€à¦•à¦¾à¦° করেনি, অথবা আপনার লগইন শংসাপতà§à¦°à§‡à¦° মেয়াদ হয়ত শেষ হয়ে গেছে।</translation>
<translation id="194030505837763158"><ph name="LINK" /> ঠযান</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> বà§à¦•à¦®à¦¾à¦°à§à¦•à¦—à§à¦²à¦¿</translation>
<translation id="1973335181906896915">ধারাবাহিকতাতে তà§à¦°à§à¦Ÿà¦¿</translation>
<translation id="1974060860693918893">উনà§à¦¨à¦¤</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{à¦à¦¬à¦‚ আরো ১টি}one{à¦à¦¬à¦‚ আরো #টি}other{à¦à¦¬à¦‚ আরো #টি}}</translation>
<translation id="2025186561304664664">সà§à¦¬à¦¤à¦ƒ কনফিগার করতে পà§à¦°à¦•à§à¦¸à¦¿ সেট করা হয়৷</translation>
<translation id="2030481566774242610">আপনি কি <ph name="LINK" /> বোà¦à¦¾à¦¤à§‡ à¦à§‡à§Ÿà§‡à¦›à¦¿à¦²à§‡à¦¨?</translation>
<translation id="2031925387125903299">নতà§à¦¨ সাইটগà§à¦²à¦¿ আপনি পà§à¦°à¦¥à¦® বারের মত ঘà§à¦°à§‡ দেখার সময় আপনার পিতামাতার সেগà§à¦²à¦¿ অনà§à¦®à§‹à¦¦à¦¨ দেওয়ার পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨ হওয়ার কারণে আপনি à¦à¦‡ বারà§à¦¤à¦¾à¦Ÿà¦¿ দেখতে পাà¦à§à¦›à§‡à¦¨à¥¤</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />পà§à¦°à¦•à§à¦¸à¦¿ à¦à¦¬à¦‚ ফায়ারওয়াল পরীকà§à¦·à¦¾ করে দেখà§à¦¨<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">পিন কোড</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{১টি পà§à¦°à¦¸à§à¦¤à¦¾à¦¬}one{#টি পà§à¦°à¦¸à§à¦¤à¦¾à¦¬}other{#টি পà§à¦°à¦¸à§à¦¤à¦¾à¦¬}}</translation>
<translation id="2065985942032347596">পà§à¦°à¦®à¦¾à¦£à§€à¦•à¦°à¦£ পà§à¦°à§Ÿà§‹à¦œà¦¨</translation>
<translation id="2079545284768500474">পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à§Ÿ ফিরà§à¦¨</translation>
<translation id="20817612488360358">সিসà§à¦Ÿà§‡à¦® পà§à¦°à¦•à§à¦¸à¦¿ সেটিংস বà§à¦¯à¦¬à¦¹à¦¾à¦° করার জনà§à¦¯ সেট আছে কিনà§à¦¤à§ à¦à¦•à¦Ÿà¦¿ সà§à¦¨à¦¿à¦°à§à¦¦à¦¿à¦·à§à¦Ÿ পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশনও নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করা আছে৷</translation>
@@ -106,32 +107,34 @@
<translation id="2149973817440762519">বà§à¦•à¦®à¦¾à¦°à§à¦• সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ করà§à¦¨</translation>
<translation id="2166049586286450108">পূরà§à¦£ পà§à¦°à¦¶à¦¾à¦¸à¦• অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸</translation>
<translation id="2166378884831602661">à¦à¦‡ সাইটটি à¦à¦•à¦Ÿà¦¿ সà§à¦°à¦•à§à¦·à¦¿à¦¤ সংযোগ দিতে পারছে না</translation>
-<translation id="2171101176734966184">আপনি <ph name="DOMAIN" />-ঠপৌà¦à¦›à¦¾à¦¨à§‹à¦° পà§à¦°à¦à§‡à¦·à§à¦Ÿà¦¾ করেছেন, কিনà§à¦¤à§ সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ à¦à¦•à¦Ÿà¦¿ দà§à¦°à§à¦¬à¦² অà§à¦¯à¦¾à¦²à¦—ারিদম সà§à¦¬à¦¾à¦•à§à¦·à¦° বà§à¦¯à¦¬à¦¹à¦¾à¦° করে à¦à¦•à¦Ÿà¦¿ সà§à¦¬à¦¾à¦•à§à¦·à¦°à¦¿à¦¤ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে৷ à¦à¦° অরà§à¦¥ হ'ল সারà§à¦­à¦¾à¦° যে সà§à¦°à¦•à§à¦·à¦¾ পà§à¦°à¦®à¦¾à¦£à¦ªà¦¤à§à¦°à¦¾à¦¦à¦¿ উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে তা জাল হতে পারে à¦à¦¬à¦‚ সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ আপনার পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¿à¦¤ সারà§à¦­à¦¾à¦° নাও হতে পারে (হতে পারে আপনি à¦à¦•à¦œà¦¨ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° সাথে যোগাযোগ করছেন)৷</translation>
<translation id="2181821976797666341">নীতিসমূহ</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{১টি ঠিকানা}one{ #টি ঠিকানা}other{ #টি ঠিকানা}}</translation>
<translation id="2212735316055980242">নীতি পাওয়া যায়নি</translation>
<translation id="2213606439339815911">à¦à¦¨à§à¦Ÿà§à¦°à¦¿à¦—à§à¦²à¦¿ আনা হà¦à§à¦›à§‡...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> উপলভà§à¦¯ নয়</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ডায়াগনসà§à¦Ÿà¦¿à¦• অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨<ph name="END_LINK" /> বà§à¦¯à¦¬à¦¹à¦¾à¦° করে আপনার সংযোগ ঠিক করà§à¦¨</translation>
+<translation id="2239100178324503013">à¦à¦–নই পাঠান</translation>
<translation id="225207911366869382">à¦à¦‡ মান à¦à¦‡ নীতির জনà§à¦¯ অসমরà§à¦¥à¦¿à¦¤ হয়েছে৷</translation>
<translation id="2262243747453050782">HTTP তà§à¦°à§à¦Ÿà¦¿</translation>
<translation id="2282872951544483773">অনà§à¦ªà¦²à¦¬à§à¦§ পরীকà§à¦·à¦¾à¦¨à¦¿à¦°à§€à¦•à§à¦·à¦¾à¦—à§à¦²à¦¿</translation>
<translation id="2292556288342944218">আপনার ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ অবরà§à¦¦à§à¦§ করা হয়েছে</translation>
<translation id="229702904922032456">à¦à¦•à¦Ÿà¦¿ রà§à¦Ÿ বা মধà§à¦¯à¦¬à¦°à§à¦¤à§€ শংসাপতà§à¦°à§‡à¦° মেয়াদ শেষ হয়েছে৷</translation>
<translation id="230155334948463882">নতà§à¦¨ কারà§à¦¡?</translation>
+<translation id="2305919008529760154">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ পà§à¦°à¦¤à¦¾à¦°à¦£à¦¾à¦ªà§‚রà§à¦£ উপায়ে জারি করা হতে পারে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> à¦à¦° জনà§à¦¯ à¦à¦•à¦Ÿà¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€à¦° নাম à¦à¦¬à¦‚ পাসওয়ারà§à¦¡ পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨à¥¤</translation>
+<translation id="2318774815570432836">আপনি à¦à¦–ন <ph name="SITE" /> ঠযেতে পারবেন না কারণ ওয়েবসাইটটি HSTS বà§à¦¯à¦¬à¦¹à¦¾à¦° করছে। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত সাময়িকভাবে হয়ে থাকে, তাই à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="2328300916057834155"><ph name="ENTRY_INDEX" /> সূà¦à¦¿à¦¤à§‡ অবৈধ বà§à¦•à¦®à¦¾à¦°à§à¦• à¦à§œà¦¿à§Ÿà§‡ যাওয়া হয়েছে</translation>
<translation id="2354001756790975382">অনà§à¦¯ বà§à¦•à¦®à¦¾à¦°à§à¦•à¦¸</translation>
<translation id="2359808026110333948">অবিরত</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" /> ঠকà§à¦¯à¦¾à¦ªà¦à¦¾à¦° করা কà§à¦°à§à¦¯à¦¾à¦¶ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ আপলোড করা হয়নি</translation>
<translation id="2367567093518048410">সà§à¦¤à¦°</translation>
+<translation id="2371153335857947666">{1,plural, =1{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ গতকাল মেয়াদোতà§à¦¤à§€à¦°à§à¦£ হয়েছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে। আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° ঘড়ি বরà§à¦¤à¦®à¦¾à¦¨à§‡ <ph name="CURRENT_DATE" /> ঠসেট করা আছে। à¦à¦Ÿà¦¿ কি ঠিক আছে বলে মনে হà¦à§à¦›à§‡? যদি তা না হয়, তাহলে আপনার সিসà§à¦Ÿà§‡à¦® ঘড়িটি ঠিক করা উà¦à¦¿à¦¤ হবে à¦à¦¬à¦‚ তারপর à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ রিফà§à¦°à§‡à¦¶ করা উà¦à¦¿à¦¤à¥¤ <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।}one{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ # দিন আগে মেয়াদোতà§à¦¤à§€à¦°à§à¦£ হয়েছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে। আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° ঘড়ি বরà§à¦¤à¦®à¦¾à¦¨à§‡ <ph name="CURRENT_DATE" /> ঠসেট করা আছে। à¦à¦Ÿà¦¿ কি ঠিক আছে বলে মনে হà¦à§à¦›à§‡? যদি তা না হয়, তাহলে আপনার সিসà§à¦Ÿà§‡à¦® ঘড়িটি ঠিক করা উà¦à¦¿à¦¤ হবে à¦à¦¬à¦‚ তারপর à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ রিফà§à¦°à§‡à¦¶ করা উà¦à¦¿à¦¤à¥¤ <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।}other{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ # দিন আগে মেয়াদোতà§à¦¤à§€à¦°à§à¦£ হয়েছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে। আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° ঘড়ি বরà§à¦¤à¦®à¦¾à¦¨à§‡ <ph name="CURRENT_DATE" /> ঠসেট করা আছে। à¦à¦Ÿà¦¿ কি ঠিক আছে বলে মনে হà¦à§à¦›à§‡? যদি তা না হয়, তাহলে আপনার সিসà§à¦Ÿà§‡à¦® ঘড়িটি ঠিক করা উà¦à¦¿à¦¤ হবে à¦à¦¬à¦‚ তারপর à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ রিফà§à¦°à§‡à¦¶ করা উà¦à¦¿à¦¤à¥¤ <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।}}</translation>
<translation id="237718015863234333">কোনো UI বিকলà§à¦ª উপলবà§à¦§ নেই</translation>
<translation id="2384307209577226199">à¦à¦¨à§à¦Ÿà¦¾à¦°à¦ªà§à¦°à¦¾à¦‡à¦œ ডিফলà§à¦Ÿ</translation>
-<translation id="238526402387145295">ওয়েবসাইটটি <ph name="BEGIN_LINK" />HSTS বà§à¦¯à¦¬à¦¹à¦¾à¦°<ph name="END_LINK" /> করার কারণে আপনি à¦à¦–ন <ph name="SITE" /> ঠযেতে পারবেন না। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত সাময়িকভাবে হয়, তাই à¦à¦‡ পৃষà§à¦ à¦¾ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে।</translation>
<translation id="2386255080630008482">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°à¦Ÿà¦¿ পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হয়েছে৷</translation>
<translation id="2392959068659972793">কোনো মান সেট করা নেই à¦à¦®à¦¨ নীতিগà§à¦²à¦¿ দেখান</translation>
<translation id="2396249848217231973">&amp;মà§à¦›à§‡ ফেলাকে পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
-<translation id="2413528052993050574">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦° পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হতে পারে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="2455981314101692989">à¦à¦‡ ওয়েবপৃষà§à¦ à¦¾à¦Ÿà¦¿ à¦à¦‡ ফরà§à¦®à¦Ÿà¦¿à¦° জনà§à¦¯ সà§à¦¬à¦¯à¦¼à¦‚কà§à¦°à¦¿à¦¯à¦¼ পূরণ ফরà§à¦®à¦•à§‡ অকà§à¦·à¦® করেছে৷</translation>
+<translation id="2463739503403862330">পূরণ করà§à¦¨</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />নেটওয়ারà§à¦• ডায়গনিসà§à¦Ÿà¦¿à¦•à§à¦¸ à¦à¦¾à¦²à¦¾à¦¨<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">অবৈধ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨à§‡à¦° URL৷</translation>
<translation id="2491120439723279231">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°à§‡ তà§à¦°à§à¦Ÿà¦¿ আছে৷</translation>
@@ -153,10 +156,12 @@
<translation id="2653659639078652383">জমা</translation>
<translation id="2674170444375937751">আপনি কি আপনার ইতিহাস থেকে à¦à¦‡ পৃষà§à¦ à¦¾à¦—à§à¦²à¦¿ মোছার বিষয়ে নিশà§à¦à¦¿à¦¤?</translation>
<translation id="2677748264148917807">ছেড়ে à¦à¦²à§‡ যান</translation>
+<translation id="269990154133806163">সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ à¦à¦®à¦¨ à¦à¦•à¦Ÿà¦¿ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে যেটি শংসাপতà§à¦°à§‡à¦° সà§à¦¬à¦à§à¦›à¦¤à¦¾à¦° নীতি বà§à¦¯à¦¬à¦¹à¦¾à¦° করে সরà§à¦¬à¦œà¦¨à§€à¦¨à¦­à¦¾à¦¬à§‡ পà§à¦°à¦•à¦¾à¦¶ করা হয়নি। à¦à¦Ÿà¦¿ কিছৠশংসাপতà§à¦°à§‡à¦° জনà§à¦¯ à¦à¦•à¦Ÿà¦¿ আবশà§à¦¯à¦•à¦¤à¦¾, যাতে করে সেগà§à¦²à¦¿à¦° বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯à¦¤à¦¾ নিশà§à¦à¦¿à¦¤ করা যায় à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦¦à§‡à¦° বিরà§à¦¦à§à¦§à§‡ সà§à¦°à¦•à§à¦·à¦¾ নেওয়া যায়।<ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="2704283930420550640">বিনà§à¦¯à¦¾à¦¸à§‡à¦° সাথে মূলà§à¦¯ মেলে না৷</translation>
<translation id="2704951214193499422">Chromium à¦à¦‡ মà§à¦¹à§‚রà§à¦¤à§‡ আপনার কারà§à¦¡ নিশà§à¦à¦¿à¦¤ করতে অকà§à¦·à¦® হয়েছে৷ দয়া করে পরে আবার à¦à§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨à§·</translation>
<translation id="2705137772291741111">à¦à¦‡ সাইটের সংরকà§à¦·à¦¿à¦¤ (সà¦à§à¦à¦¿à¦¤) অনà§à¦²à¦¿à¦ªà¦¿ পড়া সমà§à¦­à¦¬ হয়নি।</translation>
<translation id="2709516037105925701">সà§à¦¬à§Ÿà¦‚পূরণ</translation>
+<translation id="2712118517637785082">আপনি <ph name="DOMAIN" /> ঠপৌà¦à¦›à¦¾à¦¨à§‹à¦° পà§à¦°à¦à§‡à¦·à§à¦Ÿà¦¾ করেছেন, তবে সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ যে শংসাপতà§à¦°à¦Ÿà¦¿ উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে সেটির ইসà§à¦¯à§à¦•à¦¾à¦°à§€ সেটিকে পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করেছে। à¦à¦° অরà§à¦¥ হ'ল সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ যে সà§à¦°à¦•à§à¦·à¦¾ পà§à¦°à¦®à¦¾à¦¨à¦ªà¦¤à§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে তা à¦à¦•à§‡à¦¬à¦¾à¦°à§‡à¦‡ বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯ নয়। হতে পারে আপনি à¦à¦•à¦œà¦¨ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° সাথে যোগাযোগ করছেন। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="2712173769900027643">অনà§à¦®à¦¤à¦¿ নিন</translation>
<translation id="2721148159707890343">অনà§à¦°à§‹à¦§ সফল হয়েছে</translation>
<translation id="2728127805433021124">à¦à¦•à¦Ÿà¦¿ দà§à¦°à§à¦¬à¦² সà§à¦¬à¦¾à¦•à§à¦·à¦° অà§à¦¯à¦¾à¦²à¦—োরিদম বà§à¦¯à¦¬à¦¹à¦¾à¦° করে সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°à§‡ সাইন করা হয়েছে৷</translation>
@@ -168,14 +173,11 @@
<translation id="2824775600643448204">ঠিকানা à¦à¦¬à¦‚ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ দণà§à¦¡</translation>
<translation id="2826760142808435982"><ph name="CIPHER" /> বà§à¦¯à¦¬à¦¹à¦¾à¦° করে à¦à¦‡ সংযোগটি à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿà§‡à¦¡ à¦à¦¬à¦‚ পà§à¦°à¦®à¦¾à¦£à§€à¦•à§ƒà¦¤ করা হয়েছে à¦à¦¬à¦‚ কী à¦à¦•à§à¦¸à¦à§‡à¦à§à¦œ পà§à¦°à¦•à§à¦°à¦¿à§Ÿà¦¾ হিসাবে <ph name="KX" /> বà§à¦¯à¦¬à¦¹à¦¾à¦° করে৷</translation>
<translation id="2835170189407361413">ফরà§à¦® সাফ করà§à¦¨</translation>
-<translation id="2837049386027881519">TLS অথবা SSL পà§à¦°à§‹à¦Ÿà§‹à¦•à¦²à§‡à¦° পà§à¦°à§‹à¦¨à§‹ সংসà§à¦•à¦°à¦£ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে সংযোগের জনà§à¦¯ পà§à¦¨à¦°à¦¾à§Ÿ à¦à§‡à¦·à§à¦Ÿà¦¾ করা হয়েছে৷ সাধারণত à¦à¦° অরà§à¦¥ হল সারà§à¦­à¦¾à¦° ভীষণ পà§à¦°à§‹à¦¨à§‹ সংসà§à¦•à¦°à¦£ বà§à¦¯à¦¬à¦¹à¦¾à¦° করছে à¦à¦¬à¦‚ à¦à¦¤à§‡ অনà§à¦¯ কোনো নিরাপতà§à¦¤à¦¾ সমসà§à¦¯à¦¾ থাকতে পারে৷</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> à¦à¦° সারà§à¦­à¦¾à¦° শংসাপতà§à¦°à¦Ÿà¦¿ জাল বলে মনে হà¦à§à¦›à§‡à¥¤</translation>
<translation id="2889159643044928134">পà§à¦¨à¦°à¦¾à§Ÿ লোড করবেন না</translation>
-<translation id="2896499918916051536">à¦à¦‡ পà§à¦²à¦¾à¦— ইন সমরà§à¦¥à¦¿à¦¤ নয়৷</translation>
+<translation id="2900469785430194048">à¦à¦‡ ওয়েবপৃষà§à¦ à¦¾ পà§à¦°à¦¦à¦°à§à¦¶à¦¨ করার সময় Google Chrome à¦à¦° মেমরি শেষ হয়ে গেছে।</translation>
<translation id="2909946352844186028">à¦à¦•à¦Ÿà¦¿ নেটওয়ারà§à¦• পরিবরà§à¦¤à¦¨ সনাকà§à¦¤ হয়েছে৷</translation>
-<translation id="2915500479781995473">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿à¦° মেয়াদোতà§à¦¤à§€à¦°à§à¦£ হয়ে গেছে৷ কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে৷ আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° ঘড়িটি বরà§à¦¤à¦®à¦¾à¦¨à§‡ <ph name="CURRENT_TIME" /> হিসেবে সেট করা আছে৷ à¦à¦Ÿà¦¿ কি ঠিক আছে? ঠিক না থাকলে, আপনার সিসà§à¦Ÿà§‡à¦® ঘড়িটি ঠিক করে পৃষà§à¦ à¦¾à¦Ÿà¦¿ রিফà§à¦°à§‡à¦¶ করা উà¦à¦¿à§à§·</translation>
<translation id="2922350208395188000">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦° à¦à§‡à¦• করা যাবে না৷</translation>
-<translation id="2941952326391522266">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦° <ph name="DOMAIN2" /> থেকে পাওয়া। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="2948083400971632585">আপনি সেটিংস পৃষà§à¦ à¦¾ থেকে সংযোগের জনà§à¦¯ কনফিগার করা যেকোনো পà§à¦°à¦•à§à¦¸à¦¿ নিষà§à¦•à§à¦°à¦¿à¦¯à¦¼ করতে পারেন৷</translation>
<translation id="2955913368246107853">খোà¦à¦œ দণà§à¦¡ বনà§à¦§ করà§à¦¨</translation>
<translation id="2958431318199492670">নেটওয়ারà§à¦• কনফিগারেশন ONC মানকের সাথে সমà§à¦®à¦¤ নয়৷ কনফিগারেশনের অংশগà§à¦²à¦¿ আমদানিকৃত নাও হতে পারে৷</translation>
@@ -189,6 +191,7 @@
<translation id="3024663005179499861">নীতির ভà§à¦² পà§à¦°à¦•à¦¾à¦°</translation>
<translation id="3032412215588512954">আপনি কি à¦à¦‡ সাইটটি পà§à¦¨à¦°à¦¾à¦¯à¦¼ লোড করতে à¦à¦¾à¦¨?</translation>
<translation id="3037605927509011580">ইস!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{সিঙà§à¦• করা ডিভাইসে নà§à¦¯à§‚নতম ১টি আইটেম}=1{১টি আইটেম (à¦à¦¬à¦‚ সিঙà§à¦• করা ডিভাইসে আরো)}one{#টি আইটেম (à¦à¦¬à¦‚ সিঙà§à¦• করা ডিভাইসে আরো)}other{#টি আইটেম (à¦à¦¬à¦‚ সিঙà§à¦• করা ডিভাইসে আরো)}}</translation>
<translation id="3041612393474885105">শংসাপতà§à¦° তথà§à¦¯</translation>
<translation id="3063697135517575841">Chrome à¦à¦‡ মà§à¦¹à§‚রà§à¦¤à§‡ আপনার কারà§à¦¡ নিশà§à¦à¦¿à¦¤ করতে পারছে না৷ অনà§à¦—à§à¦°à¦¹ করে পরে আবার à¦à§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨à§·</translation>
<translation id="3093245981617870298">আপনি অফলাইনে আছেন৷</translation>
@@ -207,15 +210,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">নবীনতম</translation>
<translation id="3207960819495026254">বà§à¦•à¦®à¦¾à¦°à§à¦• করা হয়েছে</translation>
-<translation id="3225919329040284222">সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ à¦à¦®à¦¨ à¦à¦•à¦Ÿà¦¿ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨à¦¾ করেছে যা বিলà§à¦Ÿ-ইন পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¾à¦—à§à¦²à¦¿à¦° সাথে মেলে না৷ à¦à¦‡ পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¾à¦—à§à¦²à¦¿ আপনাকে সà§à¦°à¦•à§à¦·à¦¿à¦¤ করতে কিছৠনিশà§à¦à¦¿à¦¤, উà¦à§à¦ সà§à¦°à¦•à§à¦·à¦¾à¦° ওয়েবসাইটের জনà§à¦¯ অনà§à¦¤à¦°à§à¦­à§à¦•à§à¦¤à§·</translation>
<translation id="3226128629678568754">পৃষà§à¦ à¦¾à¦Ÿà¦¿ লোড করতে পà§à¦°à§Ÿà§‹à¦œà¦¨à§€à§Ÿ ডেটেটি পà§à¦¨à¦°à¦¾à§Ÿ জমা দিতে পà§à¦¨à¦°à¦¾à§Ÿ লোড করার বোতামটি টিপà§à¦¨à§·</translation>
<translation id="3228969707346345236">পৃষà§à¦ à¦¾à¦Ÿà¦¿ ইতিমধà§à¦¯à§‡ <ph name="LANGUAGE" />-ঠথাকার কারণে অনà§à¦¬à¦¾à¦¦ বà§à¦¯à¦°à§à¦¥ হয়েছে৷</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" /> à¦à¦° CVC লিখà§à¦¨</translation>
<translation id="3254409185687681395">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ বà§à¦•à¦®à¦¾à¦°à§à¦• করà§à¦¨</translation>
<translation id="3270847123878663523">&amp;পà§à¦¨à¦°à§à¦¬à¦¿à¦¨à§à¦¯à¦¾à¦¸à¦•à§‡ পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
<translation id="3286538390144397061">à¦à¦–ন পà§à¦°à§à¦¨à¦¸à§‚à¦à¦¨à¦¾ করবেন</translation>
+<translation id="3303855915957856445">কোনো অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ ফলাফল পাওয়া যায়নি</translation>
<translation id="3305707030755673451">আপনার ডেটা আপনার সিঙà§à¦• পাসফà§à¦°à§‡à¦œ দিয়ে <ph name="TIME" /> ঠà¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ করা হয়েছে। সিঙà§à¦• শà§à¦°à§ করার জনà§à¦¯ à¦à¦Ÿà¦¿ লিখà§à¦¨à¥¤</translation>
<translation id="333371639341676808">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿à¦•à§‡ অতিরিকà§à¦¤ কথোপকথন তৈরি করা থেকে আটকান৷</translation>
+<translation id="3338095232262050444">সà§à¦°à¦•à§à¦·à¦¿à¦¤</translation>
<translation id="3340978935015468852">সেটিংস</translation>
<translation id="3345135638360864351">à¦à¦‡ সাইটটি অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করার জনà§à¦¯ আপনার অনà§à¦°à§‹à¦§ <ph name="NAME" /> ঠপাঠানো যায়নি৷ অনà§à¦—à§à¦°à¦¹ করে আবার à¦à§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨à§·</translation>
<translation id="3355823806454867987">পà§à¦°à¦•à§à¦¸à¦¿ সেটিংস পরিবরà§à¦¤à¦¨ করà§à¦¨...</translation>
@@ -233,6 +237,7 @@
<translation id="3452404311384756672">বিরামকাল পà§à¦°à¦¾à¦ªà§à¦¤ করà§à¦¨:</translation>
<translation id="3462200631372590220">উনà§à¦¨à¦¤ করার বিশদ বিবরণ, লà§à¦•à¦¾à¦¨</translation>
<translation id="3479539252931486093">à¦à¦Ÿà¦¿ কি অপà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¿à¦¤ ছিল? <ph name="BEGIN_LINK" />আমাদেরকে জানান<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">à¦à¦–নই নয়</translation>
<translation id="348000606199325318">কà§à¦°à§à¦¯à¦¾à¦¶ আইডি <ph name="CRASH_LOCAL_ID" /> (সারà§à¦­à¦¾à¦° আইডি: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">আমরা à¦à¦‡ মà§à¦¹à§‚রà§à¦¤à§‡ আপনার পিতামাতার সাথে যোগাযোগ করতে পারিনি৷ অনà§à¦—à§à¦°à¦¹ করে আবার à¦à§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨à§·</translation>
<translation id="3527085408025491307">ফোলà§à¦¡à¦¾à¦°</translation>
@@ -241,6 +246,7 @@
<translation id="3542684924769048008">à¦à¦° জনà§à¦¯ পাসওয়ারà§à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨:</translation>
<translation id="3549644494707163724">আপনার নিজসà§à¦¬ সিঙà§à¦• পাসফà§à¦°à§‡à¦œà§‡à¦° মাধà§à¦¯à¦®à§‡ সমসà§à¦¤ সিঙà§à¦• হওয়া ডেটা à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ করà§à¦¨</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" />টি আরো...</translation>
+<translation id="3555561725129903880">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ <ph name="DOMAIN2" /> থেকে à¦à¦¸à§‡à¦›à§‡à¥¤ কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="3566021033012934673">আপনার সংযোগ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত নয়</translation>
<translation id="3583757800736429874">&amp;সরানোর কাজটি পà§à¦¨à¦°à¦¾à§Ÿ করà§à¦¨</translation>
<translation id="3586931643579894722">বিশদ বিবরণ লà§à¦•à¦¾à¦¨</translation>
@@ -252,12 +258,15 @@
<translation id="3623476034248543066">মান দেখান</translation>
<translation id="3630155396527302611">নেটওয়ারà§à¦• অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করতে à¦à¦Ÿà¦¿ যদি ইতোমধà§à¦¯à§‡ মà¦à§à¦œà§à¦°à¦¿à¦•à§ƒà¦¤ পà§à¦°à§‹à¦—à§à¦°à¦¾à¦® হিসাবে তালিকাতে থাকে, তাহলে
তালিকাটি থেকে à¦à¦Ÿà¦¿ সরানোর à¦à§‡à¦·à§à¦Ÿà¦¾ করে পà§à¦¨à¦°à¦¾à§Ÿ যোগ করে দেখà§à¦¨à¥¤</translation>
+<translation id="3638794133396384728">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ মেয়াদোতà§à¦¤à§€à¦°à§à¦£ হয়ে গেছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° ঘড়িটি বরà§à¦¤à¦®à¦¾à¦¨à§‡ <ph name="CURRENT_TIME" /> হিসেবে সেট করা আছে। à¦à¦Ÿà¦¿ কি ঠিক আছে? ঠিক না থাকলে, আপনার সিসà§à¦Ÿà§‡à¦® ঘড়িটি ঠিক করে পৃষà§à¦ à¦¾à¦Ÿà¦¿ রিফà§à¦°à§‡à¦¶ করা উà¦à¦¿à§à§·<ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="3648607100222897006">à¦à¦‡ পরীকà§à¦·à¦¾à¦®à§‚লক বৈশিষà§à¦Ÿà§à¦¯à¦—à§à¦²à¦¿ যেকোনো সময়ে পরিবরà§à¦¤à¦¨, ভঙà§à¦— বা অদৃশà§à¦¯ হয়ে যেতে পারে৷ আপনি à¦à¦‡ পরীকà§à¦·à¦¾à¦—à§à¦²à¦¿à¦° যেকোনো à¦à¦•à¦Ÿà¦¿ à¦à¦¾à¦²à§ করতে কী ঘটতে পারে সে সমà§à¦ªà¦°à§à¦•à§‡ আমরা কোনো রকম নিশà§à¦à¦¯à¦¼à¦¤à¦¾ দিই না à¦à¦¬à¦‚ à¦à¦®à¦¨à¦•à¦¿ আপনার বà§à¦°à¦¾à¦‰à¦œà¦¾à¦° তাতà§à¦•à§à¦·à¦£à¦¿à¦•à¦­à¦¾à¦¬à§‡ বিসà§à¦«à§‹à¦°à¦£ ঘটাতে পারে৷ মজা সরিয়ে, আপনার বà§à¦°à¦¾à¦‰à¦œà¦¾à¦° আপনার সকল ডেটা মà§à¦›à§‡ দিতে পারে, বা আপনার সà§à¦°à¦•à§à¦·à¦¾ ও গোপনীয়তা অপà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¿à¦¤à¦­à¦¾à¦¬à§‡ কà§à¦·à¦¤à¦¿à¦—à§à¦°à¦¸à§à¦¥ হতে পারে৷ আপনার দà§à¦¬à¦¾à¦°à¦¾ সকà§à¦°à¦¿à§Ÿ করা যেকোনো পরীকà§à¦·à¦¾ à¦à¦‡ বà§à¦°à¦¾à¦‰à¦œà¦¾à¦°à§‡à¦° সমসà§à¦¤ বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€à¦¦à§‡à¦° জনà§à¦¯ সকà§à¦°à¦¿à§Ÿ হবে৷ দয়া করে সাবধানতার সাথে à¦à¦—িয়ে যান৷</translation>
<translation id="3650584904733503804">বৈধতা যাà¦à¦¾à¦‡à¦•à¦°à¦£ সফল হয়েছে</translation>
<translation id="3655670868607891010">আপনি যদি à¦à¦Ÿà¦¿ পà§à¦°à¦¾à§Ÿà¦¶à¦‡ দেখতে পান, তাহলে <ph name="HELP_LINK" /> à¦à§‡à¦·à§à¦Ÿà¦¾ করে দেখà§à¦¨à§·</translation>
<translation id="3658742229777143148">পà§à¦¨à¦°à§à¦¬à¦¿à¦¬à§‡à¦à¦¨à¦¾</translation>
+<translation id="3678029195006412963">অনà§à¦°à§‹à¦§à¦Ÿà¦¿ সà§à¦¬à¦¾à¦•à§à¦·à¦°à¦¿à¦¤ করা যায়নি</translation>
<translation id="3681007416295224113">শংসাপতà§à¦° তথà§à¦¯</translation>
<translation id="3693415264595406141">পাসওয়ারà§à¦¡:</translation>
+<translation id="3696411085566228381">কিছà§à¦‡ নেই</translation>
<translation id="3700528541715530410">ওহো, মনে হà¦à§à¦›à§‡ à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করার অনà§à¦®à¦¤à¦¿ আপনার নেই।</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">লোড হà¦à§à¦›à§‡...</translation>
@@ -265,7 +274,6 @@
<translation id="3714780639079136834">মোবাইল ডেটা বা ওয়াই-ফাই à¦à¦¾à¦²à§ করে দেখà§à¦¨</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />পà§à¦°à¦•à§à¦¸à¦¿, ফায়ারওয়াল à¦à¦¬à¦‚ DNS কনফিগারেশন পরীকà§à¦·à¦¾ করে দেখà§à¦¨<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">আপনার অনà§à¦²à¦¿à¦ªà¦¿ করা লিঙà§à¦•</translation>
-<translation id="3744899669254331632">à¦à¦‡ মূহà§à¦°à§à¦¤à§‡ আপনি <ph name="SITE" />-ঠযেতে পারবেন না কারণ ওয়েবসাইটি মিশà§à¦°à¦¿à¦¤ পà§à¦°à¦®à¦¾à¦£à¦ªà¦¤à§à¦°à¦¾à¦¦à¦¿ পাঠিয়েছে যা Chromium পà§à¦°à¦•à§à¦°à¦¿à§Ÿà¦¾ করতে পারেনা৷ নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত অসà§à¦¥à¦¾à¦¯à¦¼à§€, তাই à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে৷</translation>
<translation id="375403751935624634">à¦à¦•à¦Ÿà¦¿ সারà§à¦­à¦¾à¦° তà§à¦°à§à¦Ÿà¦¿à¦° কারণে অনà§à¦¬à¦¾à¦¦ বà§à¦¯à¦°à§à¦¥ হয়েছে৷</translation>
<translation id="3759461132968374835">আপনার কাছে সামà§à¦ªà§à¦°à¦¤à¦¿à¦• পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ করা কোনও কà§à¦°à§à¦¯à¦¾à¦¶ নেই৷ কà§à¦°à§à¦¯à¦¾à¦¶ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ অকà§à¦·à¦® থাকাকালীন ঘটা কà§à¦°à§à¦¯à¦¾à¦¶ à¦à¦–ানে উপসà§à¦¥à¦¿à¦¤ হবে না৷</translation>
<translation id="3788090790273268753">২০১৬ সালে à¦à¦‡ সাইটের শংসাপতà§à¦° মেয়াদোতà§à¦¤à§€à¦°à§à¦£ হবে, à¦à¦¬à¦‚ শংসাপতà§à¦° শৃঙà§à¦–লে SHA-1 বà§à¦¯à¦¬à¦¹à¦¾à¦° করে সà§à¦¬à¦¾à¦•à§à¦·à¦° করা à¦à¦•à¦Ÿà¦¿ শংসাপতà§à¦° রয়েছে।</translation>
@@ -277,19 +285,25 @@
<translation id="3884278016824448484">পরসà§à¦ªà¦° বিরোধী ডিভাইস সনাকà§à¦¤à¦•à¦¾à¦°à§€</translation>
<translation id="3885155851504623709">পারিশ</translation>
<translation id="3901925938762663762">কারà§à¦¡à¦Ÿà¦¿à¦° মেয়াদ শেষ হয়েছে</translation>
+<translation id="3910267023907260648">আপনি <ph name="DOMAIN" /> ঠপৌà¦à¦›à¦¾à¦¨à§‹à¦° পà§à¦°à¦à§‡à¦·à§à¦Ÿà¦¾ করেছেন, কিনà§à¦¤à§ সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ à¦à¦•à¦Ÿà¦¿ দà§à¦°à§à¦¬à¦² সà§à¦¬à¦¾à¦•à§à¦·à¦° অà§à¦¯à¦¾à¦²à¦—রিদম বà§à¦¯à¦¬à¦¹à¦¾à¦° করে à¦à¦•à¦Ÿà¦¿ সà§à¦¬à¦¾à¦•à§à¦·à¦°à¦¿à¦¤ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে। à¦à¦° অরà§à¦¥ হ'ল সারà§à¦­à¦¾à¦° যে সà§à¦°à¦•à§à¦·à¦¾ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে তা জাল হতে পারে à¦à¦¬à¦‚ সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ আপনার পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¿à¦¤ সারà§à¦­à¦¾à¦° নাও হতে পারে (হতে পারে আপনি à¦à¦•à¦œà¦¨ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° সাথে যোগাযোগ করছেন)। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
+<translation id="3933571093587347751">{1,plural, =1{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ আগামীকালের বলে মনে হà¦à§à¦›à§‡à¥¤ কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।}one{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ আগামী # দিন পরের বলে মনে হà¦à§à¦›à§‡à¥¤ কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।}other{à¦à¦‡ সারà§à¦­à¦¾à¦° যে <ph name="DOMAIN" /> তা à¦à¦Ÿà¦¿ পà§à¦°à¦®à¦¾à¦£ করতে পারেনি; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ আগামী # দিন পরের বলে মনে হà¦à§à¦›à§‡à¥¤ কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা আপনার সংযোগে বাধাপà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° কারণে à¦à¦®à¦¨à¦Ÿà¦¿ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।}}</translation>
<translation id="3934680773876859118">PDF দসà§à¦¤à¦¾à¦¬à§‡à¦œ লোড হতে বà§à¦¯à¦°à§à¦¥</translation>
<translation id="3963721102035795474">পাঠক মোড</translation>
+<translation id="397105322502079400">গণনা করা হà¦à§à¦›à§‡...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> অবরà§à¦¦à§à¦§ হয়ে রয়েছে</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{আশেপাশের ১টি ওয়েবপৃষà§à¦ à¦¾}one{আশেপাশের #টি ওয়েবপৃষà§à¦ à¦¾}other{আশেপাশের #টি ওয়েবপৃষà§à¦ à¦¾}}</translation>
<translation id="4021036232240155012">DNS সেই নেটওয়ারà§à¦• পরিষেবা যা কোনো ওয়েবসাইটের নামকে ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ ঠিকানায় রà§à¦ªà¦¾à¦¨à§à¦¤à¦°à¦¿à¦¤ করে।</translation>
<translation id="4030383055268325496">&amp;যোগ করাকে পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
-<translation id="4032534284272647190"><ph name="URL" />তে অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ অসà§à¦¬à§€à¦•à§ƒà¦¤à§·</translation>
<translation id="404928562651467259">সতরà§à¦•à¦¤à¦¾</translation>
<translation id="4058922952496707368">কী "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">কà§à¦²à¦¾à§Ÿà§‡à¦¨à§à¦Ÿ ও সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ কোনো অভিনà§à¦¨ SSL পà§à¦°à§‹à¦Ÿà§‹à¦•à¦² সংসà§à¦•à¦°à¦£ বা সাইফার সà§à¦¯à§à¦Ÿ সমরà§à¦¥à¦¨ করে না।</translation>
<translation id="4079302484614802869">পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশনটি .pac সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ URL-ঠবà§à¦¯à¦¬à¦¹à¦¾à¦° করাতে সেট থাকে সà§à¦¥à¦¿à¦° পà§à¦°à¦•à§à¦¸à¦¿ সারà§à¦­à¦¾à¦°à¦—à§à¦²à¦¿à¦¤à§‡ নয়৷</translation>
<translation id="4103249731201008433">ডিভাইসের কà§à¦°à¦®à¦¿à¦• সংখà§à¦¯à¦¾ অবৈধ</translation>
<translation id="4103763322291513355">নিবারিত URLগà§à¦²à¦¿à¦° তালিকা à¦à¦¬à¦‚ আপনার সিসà§à¦Ÿà§‡à¦® পà§à¦°à¦¶à¦¾à¦¸à¦•à§‡à¦° দà§à¦¬à¦¾à¦°à¦¾ জারি করা অনà§à¦¯à¦¾à¦¨à§à¦¯ নীতিগà§à¦²à¦¿ দেখার জনà§à¦¯ &lt;strong&gt;chrome://policy&lt;/strong&gt; ঠযান৷</translation>
+<translation id="4110615724604346410">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿à¦¤à§‡ তà§à¦°à§à¦Ÿà¦¿ রয়েছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="4117700440116928470">নীতির সà§à¦¯à§‹à¦—টি সমরà§à¦¥à¦¿à¦¤ নয়৷</translation>
+<translation id="4118212371799607889">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; Chromium à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿à¦•à§‡ বিশà§à¦¬à¦¾à¦¸ করে না। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{আরো ১টি}one{অনà§à¦¯à¦¾à¦¨à§à¦¯ #টি}other{অনà§à¦¯à¦¾à¦¨à§à¦¯ #টি}}</translation>
<translation id="4130226655945681476">নেটওয়ারà§à¦•à§‡à¦° তার, মডেম, à¦à¦¬à¦‚ রাউটার পরীকà§à¦·à¦¾ করà§à¦¨</translation>
<translation id="4148925816941278100">আমেরিকান à¦à¦•à§à¦¸à¦ªà§à¦°à§‡à¦¸</translation>
<translation id="4169947484918424451">আপনি কি à¦à¦¾à¦¨ যে Chromium à¦à¦‡ কারà§à¦¡ সংরকà§à¦·à¦£ করà§à¦•?</translation>
@@ -297,6 +311,7 @@
<translation id="4176463684765177261">অকà§à¦·à¦®</translation>
<translation id="4196861286325780578">&amp;সরানোর কাজটি পà§à¦¨à¦°à¦¾à§Ÿ করà§à¦¨</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ফায়ারওয়াল à¦à¦¬à¦‚ অà§à¦¯à¦¾à¦¨à§à¦Ÿà¦¿à¦­à¦¾à¦‡à¦°à¦¾à¦¸ কনফিগারেশন পরীকà§à¦·à¦¾ করে দেখà§à¦¨<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{কিছà§à¦‡ নেই}=1{১টি অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨ ($1)}=2{২টি অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨ ($1, $2)}one{#টি অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨ ($1, $2, $3)}other{#টি অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨ ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">কà§à¦°à§à¦¯à¦¾à¦¶à§‡à¦¸</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />নেটওয়ারà§à¦• ডায়গনিসà§à¦Ÿà¦¿à¦•à§à¦¸ à¦à¦¾à¦²à¦¿à§Ÿà§‡ দেখà§à¦¨<ph name="END_LINK" />।</translation>
<translation id="4250680216510889253">না</translation>
@@ -305,14 +320,15 @@
<translation id="4269787794583293679">(কোনো বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€à¦° নাম নেই)</translation>
<translation id="4300246636397505754">মূল পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾à¦—à§à¦²à¦¿</translation>
<translation id="4304224509867189079">লগ ইন</translation>
+<translation id="432290197980158659">সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ à¦à¦®à¦¨ à¦à¦•à¦Ÿà¦¿ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে যা বিলà§à¦Ÿ-ইন পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¾à¦—à§à¦²à¦¿à¦° সাথে মিলছে না। à¦à¦‡ পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¾à¦—à§à¦²à¦¿ আপনাকে সà§à¦°à¦•à§à¦·à¦¿à¦¤ করতে কিছৠনিরà§à¦¦à¦¿à¦·à§à¦Ÿ, উà¦à§à¦ সà§à¦°à¦•à§à¦·à¦¾à¦° ওয়েবসাইটের জনà§à¦¯ অনà§à¦¤à¦°à§à¦­à§à¦•à§à¦¤ করা হয়। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="4325863107915753736">নিবনà§à¦§ খà§à¦à¦œà§‡ পেতে বà§à¦¯à¦°à§à¦¥ হয়েছে</translation>
+<translation id="4331708818696583467">সà§à¦°à¦•à§à¦·à¦¿à¦¤ নয়</translation>
<translation id="4372948949327679948">পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¿à¦¤ <ph name="VALUE_TYPE" /> মান৷</translation>
-<translation id="4377125064752653719">আপনি <ph name="DOMAIN" />-ঠপৌà¦à¦›à¦¾à¦¨à§‹à¦° পà§à¦°à¦à§‡à¦·à§à¦Ÿà¦¾ করেছেন, তবে সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ যে শংসাপতà§à¦°à¦Ÿà¦¿ উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে সেটির জারিকরà§à¦¤à¦¾ সেটিকে পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করেছে৷ à¦à¦° অরà§à¦¥ হ'ল সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ যে সà§à¦°à¦•à§à¦·à¦¾ পà§à¦°à¦®à¦¾à¦¨à¦ªà¦¤à§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে তা কোনওমতেই বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯ নয়৷ হতে পারে আপনি à¦à¦•à¦œà¦¨ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° সাথে যোগাযোগ করছেন৷</translation>
<translation id="4381091992796011497">বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€ নাম:</translation>
<translation id="4394049700291259645">অকà§à¦·à¦®</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> থেকে <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨à§‡à¦° ফলাফলগà§à¦²à¦¿</translation>
-<translation id="4424024547088906515">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦° Chrome à¦à¦° নিকট বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯ নয়। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> আপনার লগইন শংসাপতà§à¦°à¦Ÿà¦¿ সà§à¦¬à§€à¦•à¦¾à¦° করেনি, অথবা কোনো শংসাপতà§à¦° দেওয়া হয়নি।</translation>
<translation id="443673843213245140">পà§à¦°à¦•à§à¦¸à¦¿à¦° বà§à¦¯à¦¬à¦¹à¦¾à¦° অকà§à¦·à¦® করা হয়েছে কিনà§à¦¤à§ কোনো সà§à¦ªà¦·à§à¦Ÿ পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশান নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করা হয়েছে৷</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Google SafeSites সকà§à¦·à¦® করার কারণে আপনি à¦à¦‡ বারà§à¦¤à¦¾à¦Ÿà¦¿ দেখতে পাà¦à§à¦›à§‡à¦¨à¥¤</translation>
@@ -324,12 +340,12 @@
<translation id="4522570452068850558">বিশদ বিবরণ</translation>
<translation id="4558551763791394412">আপনার à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¾à¦¨à¦—à§à¦²à¦¿ অকà§à¦·à¦® করে দেখà§à¦¨à¥¤</translation>
<translation id="4587425331216688090">Chrome থেকে ঠিকানা সরাবেন?</translation>
+<translation id="4589078953350245614">আপনি <ph name="DOMAIN" /> ঠপৌà¦à¦›à¦¾à¦¨à§‹à¦° পà§à¦°à¦à§‡à¦·à§à¦Ÿà¦¾ à¦à¦¾à¦²à¦¿à§Ÿà§‡à¦›à§‡à¦¨ কিনà§à¦¤à§ সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ à¦à¦•à¦Ÿà¦¿ অবৈধ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="4592951414987517459">à¦à¦•à¦Ÿà¦¿ আধà§à¦¨à¦¿à¦• সাইফার সà§à¦¯à§à¦Ÿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে <ph name="DOMAIN" />-ঠআপনার সংযোগ à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ করা হয়েছে।</translation>
<translation id="4594403342090139922">&amp;মà§à¦›à§‡ ফেলাকে পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
+<translation id="4627442949885028695">অনà§à¦¯ ডিভাইস থেকে à¦à¦¾à¦²à¦¿à§Ÿà§‡ যান</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">আপনি à¦à¦•à¦Ÿà¦¿ à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¾à¦¨ পৃষà§à¦ à¦¾ দেখছেন।</translation>
-<translation id="467662567472608290">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à§‡ কিছৠতà§à¦°à§à¦Ÿà¦¿ আছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
-<translation id="4697214168136963651"><ph name="URL" /> অবরোধ করা হয়েছে</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">আপনার সংযোগ বাধাপà§à¦°à¦¾à¦ªà§à¦¤ হয়েছে</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows নেটওয়ারà§à¦• ডায়গনিসà§à¦Ÿà¦¿à¦•à§à¦¸ à¦à¦¾à¦²à¦¾à¦¨<ph name="END_LINK" /></translation>
@@ -337,21 +353,26 @@
<translation id="4728558894243024398">পà§à¦²à§à¦¯à¦¾à¦Ÿà¦«à¦°à§à¦®</translation>
<translation id="4744603770635761495">সমà§à¦ªà¦¾à¦¦à¦¨à¦¯à§‹à¦—à§à¦¯ পথ</translation>
<translation id="4756388243121344051">&amp;ইতিহাস</translation>
+<translation id="4759238208242260848">ডাউনলোডগà§à¦²à¦¿</translation>
<translation id="4764776831041365478"><ph name="URL" />-ঠওয়েবপৃষà§à¦ à¦¾à¦Ÿà¦¿ হতে পারে অসà§à¦¥à¦¾à§Ÿà§€à¦­à¦¾à¦¬à§‡ ডাউন আছে অথবা হতে পারে à¦à¦Ÿà¦¿ সà§à¦¥à¦¾à§Ÿà§€à¦­à¦¾à¦¬à§‡ কোনো নতà§à¦¨ ওয়েব ঠিকানাতে সরানো হয়েছে৷</translation>
<translation id="4771973620359291008">à¦à¦•à¦Ÿà¦¿ অজানা তà§à¦°à§à¦Ÿà¦¿ ঘটেছে৷</translation>
<translation id="4782449893814226250">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ দেখার জনà§à¦¯ উপযà§à¦•à§à¦¤ কিনা তা আপনি আপনার মাতাপিতাকে জিজà§à¦à¦¾à¦¸à¦¾ করেছেন৷</translation>
<translation id="4800132727771399293">আপনার মেয়াদ শেষের তারিখ à¦à¦¬à¦‚ CVC পরীকà§à¦·à¦¾ করà§à¦¨ à¦à¦¬à¦‚ আবার à¦à§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨</translation>
-<translation id="4807049035289105102">à¦à¦‡ মà§à¦¹à§‚রà§à¦¤à§‡ আপনি <ph name="SITE" /> ঠযেতে পারবেন না কারণ ওয়েবসাইটটি অবোধà§à¦¯ শংসাপতà§à¦° পাঠিয়েছে যেটি Google Chrome পà§à¦°à¦•à§à¦°à¦¿à§Ÿà¦¾ করতে পারছে না। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত সাময়িকভাবে হয়, তাই à¦à¦‡ পৃষà§à¦ à¦¾ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে।</translation>
<translation id="4813512666221746211">নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿</translation>
<translation id="4816492930507672669">পৃষà§à¦ à¦¾à¦¤à§‡ মানানসই</translation>
<translation id="4850886885716139402">দেখà§à¦¨</translation>
<translation id="4880827082731008257">ইতিহাস অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨</translation>
+<translation id="4884656795097055129">সঠিক সময়ে আরো নিবনà§à¦§ হাজির হবে।</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{à¦à¦¬à¦‚ আরো ১টি ওয়েব পৃষà§à¦ à¦¾}one{à¦à¦¬à¦‚ আরো #টি ওয়েব পৃষà§à¦ à¦¾}other{à¦à¦¬à¦‚ আরো #টি ওয়েব পৃষà§à¦ à¦¾}}</translation>
<translation id="4923417429809017348">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ কোন অজানা ভাষা থেকে <ph name="LANGUAGE_LANGUAGE" />-ঠঅনà§à¦¬à¦¾à¦¦ করা হয়েছে</translation>
<translation id="4926049483395192435">নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করা উà¦à¦¿à¦¤à§·</translation>
<translation id="4930497775425430760">নতà§à¦¨ সাইটগà§à¦²à¦¿ আপনি পà§à¦°à¦¥à¦® বারের মত ঘà§à¦°à§‡ দেখার সময় আপনার পিতা বা মাতার সেগà§à¦²à¦¿ অনà§à¦®à§‹à¦¦à¦¨ দেওয়ার পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨ হওয়ার কারণে আপনি à¦à¦‡ বারà§à¦¤à¦¾à¦Ÿà¦¿ দেখতে পাà¦à§à¦›à§‡à¦¨à¥¤</translation>
<translation id="495170559598752135">কà§à¦°à¦¿à§Ÿà¦¾à¦¸à¦®à§‚হ</translation>
<translation id="4958444002117714549">তালিকা পà§à¦°à¦¸à¦¾à¦°à¦¿à¦¤ করà§à¦¨</translation>
+<translation id="4962322354953122629">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; Chrome à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿à¦•à§‡ বিশà§à¦¬à¦¾à¦¸ করে না। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="498957508165411911"><ph name="ORIGINAL_LANGUAGE" /> থেকে <ph name="TARGET_LANGUAGE" /> তে অনà§à¦¬à¦¾à¦¦ করবেন?</translation>
+<translation id="4989809363548539747">à¦à¦‡ পà§à¦²à¦¾à¦— ইন সমরà§à¦¥à¦¿à¦¤ নয়</translation>
<translation id="5002932099480077015">সকà§à¦°à¦¿à¦¯à¦¼ করা হলে, ফরà§à¦® পূরনের কাজ দà§à¦°à§à¦¤ করতে Chrome à¦à¦‡ ডিভাইসে আপনার কারà§à¦¡à§‡à¦° à¦à¦•à¦Ÿà¦¿ পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ সংরকà§à¦·à¦£ করবে।</translation>
<translation id="5019198164206649151">বà§à¦¯à¦¾à¦•à¦¿à¦‚ সà§à¦Ÿà§‹à¦°à¦Ÿà¦¿ তà§à¦°à§à¦Ÿà¦¿à¦ªà§‚রà§à¦£ অবসà§à¦¥à¦¾à§Ÿ আছে</translation>
<translation id="5023310440958281426">আপনার পà§à¦°à¦¶à¦¾à¦¸à¦•à§‡à¦° নীতিগà§à¦²à¦¿ দেখà§à¦¨</translation>
@@ -359,13 +380,12 @@
<translation id="5031870354684148875">Google অনà§à¦¬à¦¾à¦¦ সমà§à¦¬à¦¨à§à¦§à§‡</translation>
<translation id="5040262127954254034">গোপনীয়তা</translation>
<translation id="5045550434625856497">ভà§à¦² পাসওয়ারà§à¦¡</translation>
+<translation id="5056549851600133418">আপনার জনà§à¦¯ নিবনà§à¦§à¦—à§à¦²à¦¿</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />পà§à¦°à¦•à§à¦¸à¦¿ ঠিকানা পরীকà§à¦·à¦¾ করে দেখà§à¦¨<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦° à¦à¦‡ সময়ে বৈধ নয়৷</translation>
<translation id="5089810972385038852">রাজà§à¦¯</translation>
-<translation id="5094747076828555589">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ Chromium à¦à¦° নিকট বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯ নয়। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="5095208057601539847">পà§à¦°à¦¦à§‡à¦¶</translation>
<translation id="5115563688576182185">(৬৪-বিট)</translation>
-<translation id="5122371513570456792">'<ph name="SEARCH_STRING" />'-à¦à¦° জনà§à¦¯ <ph name="NUMBER_OF_RESULTS" />টি <ph name="SEARCH_RESULTS" /> খà§à¦à¦œà§‡ পাওয়া গেছে৷</translation>
<translation id="5141240743006678641">আপনার Google শংসাপতà§à¦°à§‡à¦° সাথে সিঙà§à¦• করা পাসওয়ারà§à¦¡à¦—à§à¦²à¦¿ à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ করà§à¦¨à§·</translation>
<translation id="5145883236150621069">নীতি পà§à¦°à¦¤à¦¿à¦•à§à¦°à¦¿à¦¯à¦¼à¦¾à¦° মধà§à¦¯à§‡ তà§à¦°à§à¦Ÿà¦¿ কোড উপসà§à¦¥à¦¿à¦¤</translation>
<translation id="5171045022955879922">অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ করà§à¦¨ বা URL লিখà§à¦¨</translation>
@@ -374,18 +394,18 @@
<translation id="5190835502935405962">বà§à¦•à¦®à¦¾à¦°à§à¦• দণà§à¦¡</translation>
<translation id="5199729219167945352">পরীকà§à¦·à¦¾à¦¦à¦¿</translation>
<translation id="5251803541071282808">কà§à¦²à¦¾à¦‰à¦¡</translation>
+<translation id="5277279256032773186">করà§à¦®à¦•à§à¦·à§‡à¦¤à§à¦°à§‡ Chrome বà§à¦¯à¦¬à¦¹à¦¾à¦° করছেন? বà§à¦¯à¦¬à¦¸à¦¾à¦—à§à¦²à§‹ তাদের করà§à¦®à¦à¦¾à¦°à§€à¦¦à§‡à¦° জনà§à¦¯ Chrome সেটিংস পরিà¦à¦¾à¦²à¦¨à¦¾ করতে পারে। আরো জানà§à¦¨</translation>
<translation id="5299298092464848405">নীতি বিশà§à¦²à§‡à¦·à¦£ করার সময় তà§à¦°à§à¦Ÿà¦¿</translation>
<translation id="5300589172476337783">দেখান</translation>
<translation id="5308689395849655368">কà§à¦°à§à¦¯à¦¾à¦¶ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ অকà§à¦·à¦® আছে৷</translation>
<translation id="5317780077021120954">সংরকà§à¦·à¦£ করà§à¦¨</translation>
<translation id="5327248766486351172">নাম</translation>
+<translation id="5359637492792381994">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; বরà§à¦¤à¦®à¦¾à¦¨à§‡ à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ বৈধ না। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="536296301121032821">নীতি সেটিংস সংরকà§à¦·à¦£ করতে বà§à¦¯à¦°à§à¦¥ হয়েছে</translation>
-<translation id="540969355065856584">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦° à¦à¦‡ সময়ে বৈধ নয়। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="5421136146218899937">বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ ডেটা সাফ করà§à¦¨...</translation>
<translation id="5430298929874300616">বà§à¦•à¦®à¦¾à¦°à§à¦• সরান</translation>
<translation id="5431657950005405462">আপনার ফাইলটি পাওয়া যায়নি</translation>
<translation id="5435775191620395718">à¦à¦‡ ডিভাইস থেকে ইতিহাস দেখাà¦à§à¦›à§‡à¥¤ <ph name="BEGIN_LINK" />আরো জানà§à¦¨<ph name="END_LINK" />।</translation>
-<translation id="5437003064129843501">বà§à¦¯à¦•à§à¦¤à¦¿à¦—তকৃত সামগà§à¦°à§€ পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾ বরà§à¦¤à¦®à¦¾à¦¨à§‡ নিষà§à¦•à§à¦°à¦¿à¦¯à¦¼ করা আছে, কারণ আপনার সিঙà§à¦• করা ডেটা à¦à¦•à¦Ÿà¦¿ কাসà§à¦Ÿà¦® পাসফà§à¦°à§‡à¦œ দিয়ে সà§à¦°à¦•à§à¦·à¦¿à¦¤ করা আছে।</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" ঠসà§à¦•à¦¿à¦®à¦¾ বৈধতার তà§à¦°à§à¦Ÿà¦¿ হয়েছে: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">à¦à¦‡ <ph name="HOST_NAME" /> পৃষà§à¦ à¦¾à¦Ÿà¦¿ পাওয়া যাà¦à§à¦›à§‡ না</translation>
<translation id="5455374756549232013">তà§à¦°à§à¦Ÿà¦¿à¦ªà§‚রà§à¦£ নীতি টাইমসà§à¦Ÿà§à¦¯à¦¾à¦®à§à¦ª</translation>
@@ -408,14 +428,18 @@
<translation id="5622887735448669177">আপনি কি à¦à¦‡ সাইটটি ছেড়ে যেতে à¦à¦¾à¦¨?</translation>
<translation id="5629630648637658800">নীতি সেটিংস লোড করতে বà§à¦¯à¦°à§à¦¥ হয়েছে</translation>
<translation id="5631439013527180824">অবৈধ ডিভাইস পরিà¦à¦¾à¦²à¦¨à¦¾ টোকেন</translation>
-<translation id="5650551054760837876">কোনো অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ ফলাফল পাওয়া যায় নি৷</translation>
<translation id="5677928146339483299">অবরà§à¦¦à§à¦§</translation>
<translation id="5710435578057952990">à¦à¦‡ ওয়েবসাইটির পরিà¦à§Ÿ যাà¦à¦¾à¦‡ করা হয় নি৷</translation>
<translation id="5720705177508910913">বরà§à¦¤à¦®à¦¾à¦¨ বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€</translation>
+<translation id="572328651809341494">সামà§à¦ªà§à¦°à¦¤à¦¿à¦• টà§à¦¯à¦¾à¦¬à¦—à§à¦²à¦¿</translation>
<translation id="5784606427469807560">আপনার কারà§à¦¡à¦Ÿà¦¿ নিশà§à¦à¦¿à¦¤ করতে à¦à¦•à¦Ÿà¦¿ সমসà§à¦¯à¦¾ হয়েছিল৷আপনার ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ সংযোগ পরীকà§à¦·à¦¾ করে আবার à¦à§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨à§·</translation>
<translation id="5785756445106461925">উপরনà§à¦¤à§, à¦à¦‡ পৃষà§à¦ à¦¾à¦¤à§‡ অনà§à¦¯à¦¾à¦¨à§à¦¯ সংসà§à¦¥à¦¾à¦¨ অনà§à¦¤à¦°à§à¦­à§à¦•à§à¦¤ রয়েছে যা নিরাপদ নয়৷ à¦à¦‡ সংসà§à¦¥à¦¾à¦¨à¦—à§à¦²à¦¿ টà§à¦°à¦¾à¦¨à¦œà¦¿à¦Ÿà§‡à¦° সময় অনà§à¦¯à¦°à¦¾ দেখতে পাবে à¦à¦¬à¦‚ পৃষà§à¦ à¦¾à¦Ÿà¦¿à¦° à¦à§‡à¦¹à¦¾à¦°à¦¾à¦Ÿà¦¿ পরিবরà§à¦¤à¦¨ করতে কোনও আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ à¦à¦° পরিবরà§à¦¤à¦¨ করতে পারেন৷</translation>
+<translation id="5786044859038896871">আপনি কি আপনার কারà§à¦¡à§‡à¦° তথà§à¦¯ পূরণ করতে à¦à¦¾à¦¨?</translation>
+<translation id="5803412860119678065">আপনি কি আপনার <ph name="CARD_DETAIL" /> à¦à¦° তথà§à¦¯ পূরণ করতে à¦à¦¾à¦¨?</translation>
<translation id="5810442152076338065"><ph name="DOMAIN" />-ঠআপনার সংযোগ à¦à¦•à¦Ÿà¦¿ অপà§à¦°à¦à¦²à¦¿à¦¤ সাইফার সà§à¦¯à§à¦Ÿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ করা হয়েছে৷</translation>
<translation id="5813119285467412249">&amp;যোগ করাকে পà§à¦¨à¦°à¦¾à¦¯à¦¼ করà§à¦¨</translation>
+<translation id="5814352347845180253">আপনি <ph name="SITE" /> à¦à¦¬à¦‚ অনà§à¦¯à¦¾à¦¨à§à¦¯ সাইট থেকে পà§à¦°à¦¿à¦®à¦¿à¦¯à¦¼à¦¾à¦® সামগà§à¦°à§€à¦¤à§‡ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ হারাতে পারেন।</translation>
+<translation id="5843436854350372569">আপনি <ph name="DOMAIN" /> ঠপৌà¦à¦›à¦¾à¦¨à§‹à¦° পà§à¦°à¦à§‡à¦·à§à¦Ÿà¦¾ করেছেন, কিনà§à¦¤à§ সারà§à¦­à¦¾à¦° à¦à¦•à¦Ÿà¦¿ দà§à¦°à§à¦¬à¦² কী সমà§à¦¬à¦²à¦¿à¦¤ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে৷ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত কী ভঙà§à¦— করে থাকতে পারে à¦à¦¬à¦‚ সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ আপনার পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¿à¦¤ সারà§à¦­à¦¾à¦° নাও হতে পারে (হতে পারে আপনি à¦à¦•à¦œà¦¨ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦° সাথে যোগাযোগ করছেন)। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="5855235287355719921">আপনার পরিà¦à¦¾à¦²à¦• à¦à¦‡ সাইটটি অবরà§à¦¦à§à¦§ করার কারণে আপনি à¦à¦‡ বারà§à¦¤à¦¾à¦Ÿà¦¿ দেখতে পাà¦à§à¦›à§‡à¦¨à¥¤</translation>
<translation id="5857090052475505287">নতà§à¦¨ ফোলà§à¦¡à¦¾à¦°</translation>
<translation id="5869405914158311789">à¦à¦‡ সাইটটিতে পৌছানো যাà¦à§à¦›à§‡ না</translation>
@@ -423,6 +447,7 @@
<translation id="5872918882028971132">মূল পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾à¦—à§à¦²à¦¿</translation>
<translation id="59107663811261420">à¦à¦‡ বণিকের জনà§à¦¯ à¦à¦‡ ধরনের কারà§à¦¡ Google Payments দà§à¦¬à¦¾à¦°à¦¾ সমরà§à¦¥à¦¿à¦¤ নয়৷ দয়া করে à¦à¦•à¦Ÿà¦¿ আলাদা কারà§à¦¡ নিরà§à¦¬à¦¾à¦à¦¨ করà§à¦¨à§·</translation>
<translation id="59174027418879706">সকà§à¦·à¦® করা হযেছে</translation>
+<translation id="5926846154125914413">আপনি কিছৠসাইট থেকে পà§à¦°à¦¿à¦®à¦¿à¦¯à¦¼à¦¾à¦® সামগà§à¦°à§€à¦¤à§‡ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ হারাতে পারেন।</translation>
<translation id="5966707198760109579">সপà§à¦¤à¦¾à¦¹</translation>
<translation id="5967867314010545767">ইতিহাস থেকে সরান</translation>
<translation id="5975083100439434680">জà§à¦® কমান</translation>
@@ -434,11 +459,11 @@
<translation id="604124094241169006">সà§à¦¬à§Ÿà¦‚কà§à¦°à¦¿à§Ÿ</translation>
<translation id="6042308850641462728">আরো</translation>
<translation id="6060685159320643512">সাবধান হন, à¦à¦‡ পরীকà§à¦·à¦¾à¦—à§à¦²à¦¿ সমসà§à¦¯à¦¾ সৃষà§à¦Ÿà¦¿ করতে পারে</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{কিছà§à¦‡ নেই}=1{১}one{#}other{#}}</translation>
<translation id="6146055958333702838">সব কেবল পরীকà§à¦·à¦¾ করà§à¦¨ à¦à¦¬à¦‚ আপনি বà§à¦¯à¦¬à¦¹à¦¾à¦° করছেন à¦à¦®à¦¨ যেকোনো রাউটার, মডেম বা অনà§à¦¯à¦¾à¦¨à§à¦¯ নেটওয়ারà§à¦• ডিভাইসগà§à¦²à¦¿ পà§à¦¨à¦°à¦¾à§Ÿ à¦à¦¾à¦²à§ করà§à¦¨à¥¤</translation>
<translation id="614940544461990577">à¦à¦Ÿà¦¿ করে দেখà§à¦¨:</translation>
<translation id="6150607114729249911">ওহো! à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿à¦¤à§‡ যাওয়া ঠিক হবে কিনা সেই বিষয়ে আপনাকে আপনার পিতামাতাকে জিজà§à¦à¦¾à¦¸à¦¾ করতে হবে।</translation>
<translation id="6151417162996330722">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°à§‡à¦° বৈধতার সময়সীমা আছে যা খà§à¦¬à¦‡ দীরà§à¦˜à¥¤</translation>
-<translation id="6154808779448689242">ফিরে পাওয়া নীতি টোকেন বরà§à¦¤à¦®à¦¾à¦¨ টোকেনের সঙà§à¦—ে মেলে না</translation>
<translation id="6165508094623778733">আরো জানà§à¦¨</translation>
<translation id="6203231073485539293">আপনার ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ সংযোগ পরীকà§à¦·à¦¾ করà§à¦¨</translation>
<translation id="6218753634732582820">Chromium থেকে ঠিকানা সরাবেন?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">নেটওয়ারà§à¦• পূরà§à¦¬à¦¾à¦¨à§à¦®à¦¾à¦¨ নিষà§à¦•à§à¦°à¦¿à¦¯à¦¼ করার à¦à§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨</translation>
<translation id="6337534724793800597">নাম অনà§à¦¸à¦¾à¦°à§‡ ফিলà§à¦Ÿà¦¾à¦°à¦—à§à¦²à¦¿ বাছাই করà§à¦¨</translation>
<translation id="6342069812937806050">à¦à¦–নই</translation>
+<translation id="6345221851280129312">অজানা আকার</translation>
<translation id="6355080345576803305">সরà§à¦¬à¦œà¦¨à§€à¦¨ অধিবেশন ওভাররাইড</translation>
<translation id="6358450015545214790">à¦à¦° অরà§à¦¥ কী?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{আরো ১টি পà§à¦°à¦¸à§à¦¤à¦¾à¦¬}one{অনà§à¦¯à¦¾à¦¨à§à¦¯ #টি পà§à¦°à¦¸à§à¦¤à¦¾à¦¬}other{অনà§à¦¯à¦¾à¦¨à§à¦¯ #টি পà§à¦°à¦¸à§à¦¤à¦¾à¦¬}}</translation>
<translation id="6387478394221739770">Chrome à¦à¦° নতà§à¦¨ দà§à¦°à§à¦¦à¦¾à¦¨à§à¦¤ বৈশিষà§à¦Ÿà§à¦¯à¦—à§à¦²à¦¿à¦¤à§‡ আগà§à¦°à¦¹à§€? chrome.com/beta ঠআমাদের বিটা à¦à§à¦¯à¦¾à¦¨à§‡à¦² বà§à¦¯à¦¬à¦¹à¦¾à¦° করে দেখà§à¦¨à§·</translation>
-<translation id="641480858134062906"><ph name="URL" /> লোড করতে বà§à¦¯à¦°à§à¦¥</translation>
+<translation id="6389758589412724634">à¦à¦‡ ওয়েবপৃষà§à¦ à¦¾ পà§à¦°à¦¦à¦°à§à¦¶à¦¨ করার সময় Chromium à¦à¦° মেমরি শেষ হয়ে গেছে।</translation>
+<translation id="6416403317709441254">আপনি <ph name="SITE" /> ঠযেতে পারবেন না কারণ ওয়েবসাইটটি à¦à¦•à¦Ÿà¦¿ অবোধà§à¦¯ শংসাপতà§à¦° পাঠিয়েছে যেটি Chromium পà§à¦°à¦•à§à¦°à¦¿à§Ÿà¦¾ করতে পারছে না। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত সাময়িকভাবে হয়ে থাকে, তাই à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="6417515091412812850">শংসাপতà§à¦°à¦•à¦°à¦£à¦Ÿà¦¿ পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হয়েছে কিনা তা যাà¦à¦¾à¦‡à§Ÿà§‡ অকà§à¦·à¦®à§·</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> সংযোগ করতে পà§à¦°à¦¤à§à¦¯à¦¾à¦–à§à¦¯à¦¾à¦¨ করেছে।</translation>
<translation id="6445051938772793705">দেশ</translation>
<translation id="6451458296329894277">ফরà§à¦® পà§à¦¨à¦ƒà¦œà¦®à¦¾ নিশà§à¦à¦¿à¦¤ করà§à¦¨</translation>
<translation id="6458467102616083041">নীতি দà§à¦¬à¦¾à¦°à¦¾ ডিফলà§à¦Ÿ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ অকà§à¦·à¦® করা হয়েছে সেই কারণে উপেকà§à¦·à¦¾ করা হয়েছে৷</translation>
+<translation id="6462969404041126431">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿ হয়ত পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হয়েছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="647261751007945333">ডিভাইস নীতিগà§à¦²à¦¿</translation>
<translation id="6489534406876378309">কà§à¦°à§à¦¯à¦¾à¦¶à¦—à§à¦²à¦¿ আপলোড করা শà§à¦°à§ করà§à¦¨</translation>
<translation id="6529602333819889595">&amp;মà§à¦›à§‡ ফেলাকে পà§à¦¨à¦°à¦¾à§Ÿ করà§à¦¨</translation>
+<translation id="6534179046333460208">বাসà§à¦¤à¦¬à¦¿à¦• ওয়েব পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾à¦—à§à¦²à¦¿</translation>
<translation id="6550675742724504774">বিকলà§à¦ªà¦¸à¦®à§‚হ</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" /> à¦à¦° কম</translation>
<translation id="6596325263575161958">à¦à¦¨à¦•à§à¦°à¦¿à¦ªà¦¶à¦¨ বিকলà§à¦ªà¦—à§à¦²à¦¿</translation>
<translation id="662080504995468778">থাকà§à¦¨</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨</translation>
-<translation id="6634865548447745291">আপনি à¦à¦–ন <ph name="SITE" /> ঠযেতে পারবেন না কারণ <ph name="BEGIN_LINK" /> à¦à¦‡ শংসাপতà§à¦° পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হয়েছে<ph name="END_LINK" />। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত সাময়িকভাবে হয়, তাই à¦à¦‡ পৃষà§à¦ à¦¾ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে।</translation>
<translation id="6644283850729428850">à¦à¦‡ নীতিটি অসমরà§à¦¥à¦¿à¦¤ হয়েছে৷</translation>
+<translation id="6652240803263749613">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° অপারেটিং সিসà§à¦Ÿà§‡à¦® à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿à¦•à§‡ বিশà§à¦¬à¦¾à¦¸ করে না। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="6656103420185847513">ফোলà§à¦¡à¦¾à¦° সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ করà§à¦¨</translation>
<translation id="6660210980321319655">সà§à¦¬à¦¯à¦¼à¦‚কà§à¦°à¦¿à¦¯à¦¼à¦­à¦¾à¦¬à§‡ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ করা হয়েছে <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Chromium থেকে ফরà§à¦® পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾ সরাবেন?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">পূরà§à¦¬à¦¬à¦°à§à¦¤à§€</translation>
<translation id="6710594484020273272">&lt;অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨à§‡à¦° পদ লিখà§à¦¨&gt;</translation>
<translation id="6711464428925977395">পà§à¦°à¦•à§à¦¸à§€ সারà§à¦­à¦¾à¦°à§‡à¦° কোনো সমসà§à¦¯à¦¾ হয়েছে, অথবা ঠিকানাটি ভà§à¦²à¥¤</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{কিছà§à¦‡ নেই}=1{১টি আইটেম}one{#টি আইটেম}other{#টি আইটেম}}</translation>
<translation id="674375294223700098">অজানা সারà§à¦­à¦¾à¦° শংসাপতà§à¦° তà§à¦°à§à¦Ÿà¦¿à§·</translation>
<translation id="6753269504797312559">নীতি মান</translation>
<translation id="6757797048963528358">আপনার ডিভাইস নিদà§à¦°à¦¾ মোডে গিয়েছে।</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">নীতি সà§à¦¤à¦° সমরà§à¦¥à¦¿à¦¤ নয়।</translation>
<translation id="6895330447102777224">আপনার কারà§à¦¡à¦Ÿà¦¿ নিশà§à¦à¦¿à¦¤ করা হয়েছে</translation>
<translation id="6897140037006041989">বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€ à¦à¦œà§‡à¦¨à§à¦Ÿ</translation>
-<translation id="6903907808598579934">সিঙà§à¦• à¦à¦¾à¦²à§ করà§à¦¨</translation>
<translation id="6915804003454593391">বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€:</translation>
<translation id="6957887021205513506">সারà§à¦­à¦¾à¦°à¦Ÿà¦¿à¦° শংসাপতà§à¦°à¦Ÿà¦¿ à¦à¦•à¦Ÿà¦¿ জাল হিসাবে উপসà§à¦¥à¦¿à¦¤ হয়েছে৷</translation>
<translation id="6965382102122355670">ঠিক আছে</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">জেলা</translation>
<translation id="6973656660372572881">সà§à¦¥à¦¿à¦° পà§à¦°à¦•à§à¦¸à¦¿ সারà§à¦­à¦¾à¦° à¦à¦¬à¦‚ .pac সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ URL-à¦à¦° উভয়ই নিরà§à¦¦à¦¿à¦·à§à¦Ÿ আছে৷</translation>
<translation id="6989763994942163495">উনà§à¦¨à¦¤ সেটিংস দেখান ...</translation>
+<translation id="7000990526846637657">কোনো ইতিহাস à¦à¦¨à§à¦Ÿà§à¦°à¦¿ পাওয়া যায়নি</translation>
+<translation id="7009986207543992532">আপনি <ph name="DOMAIN" /> ঠপৌà¦à¦›à¦¾à¦¨à§‹à¦° পà§à¦°à¦à§‡à¦·à§à¦Ÿà¦¾ করেছেন, কিনà§à¦¤à§ সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ à¦à¦®à¦¨ à¦à¦•à¦Ÿà¦¿ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে যার মেয়াদ খà§à¦¬ বেশি সময়ের যা বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯ নয়। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985"><ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ঠআপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° অনà§à¦¯à¦¾à¦¨à§à¦¯ ধরনের বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ ইতিহাস থাকতে পারে</translation>
<translation id="7029809446516969842">পাসওয়ারà§à¦¡</translation>
-<translation id="7050187094878475250">আমি <ph name="DOMAIN" />-ঠসংযোগ করার à¦à§‡à¦·à§à¦Ÿà¦¾ করেছেন, কিনà§à¦¤à§ সারà§à¦­à¦¾à¦° à¦à¦•à¦Ÿà¦¿ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে যার বৈধতার সময়সীমা à¦à¦¤ বেশী যে বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯ নয়।</translation>
<translation id="7087282848513945231">দেশ</translation>
<translation id="7088615885725309056">পূরà§à¦¬à¦¤à¦°</translation>
<translation id="7090678807593890770">Google ঠ<ph name="LINK" /> à¦à¦° অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ করà§à¦¨</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">নতà§à¦¨ সাইটগà§à¦²à¦¿ আপনি পà§à¦°à¦¥à¦® বারের মত ঘà§à¦°à§‡ দেখার সময় আপনার পরিà¦à¦¾à¦²à¦•à§‡à¦° সেগà§à¦²à¦¿ অনà§à¦®à§‹à¦¦à¦¨ দেওয়ার পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨ হওয়ার কারণে আপনি à¦à¦‡ বারà§à¦¤à¦¾à¦Ÿà¦¿ দেখতে পাà¦à§à¦›à§‡à¦¨à¥¤</translation>
<translation id="724975217298816891">আপনার কারà§à¦¡à§‡à¦° বিবরণ আপডেট করার জনà§à¦¯ মেয়াদ শেষের তারিখ à¦à¦¬à¦‚ <ph name="CREDIT_CARD" /> à¦à¦° CVC লিখà§à¦¨à¥¤ আপনি নিশà§à¦à¦¿à¦¤ করলে, আপনার কারà§à¦¡à§‡à¦° বিবরণ à¦à¦‡ সাইটের সাথে শেয়ার করা হবে।</translation>
<translation id="725866823122871198"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ঠà¦à¦•à¦Ÿà¦¿ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করা যায়নি কারণ আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à§‡à¦° তারিখ à¦à¦¬à¦‚ সময় (<ph name="DATE_AND_TIME" />) সঠিক নয়৷</translation>
-<translation id="7265986070661382626">আপনি à¦à¦–ন <ph name="SITE" /> ঠযেতে পারবেন না কারণ ওয়েবসাইটটি <ph name="BEGIN_LINK" />পিন করা শংসাপতà§à¦° বà§à¦¯à¦¬à¦¹à¦¾à¦°<ph name="END_LINK" /> করছে। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত সাময়িকভাবে হয়, তাই à¦à¦‡ পৃষà§à¦ à¦¾ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে।</translation>
<translation id="7269802741830436641">à¦à¦‡ ওয়েবপৃষà§à¦ à¦¾à¦Ÿà¦¿à¦° à¦à¦•à¦Ÿà¦¿ পà§à¦¨à¦ƒà¦à¦¾à¦²à¦¨à¦¾ লà§à¦ª আছে</translation>
<translation id="7275334191706090484">পরিà¦à¦¾à¦²à¦¿à¦¤ বà§à¦•à¦®à¦¾à¦°à§à¦•à¦—à§à¦²à¦¿</translation>
<translation id="7298195798382681320">পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤</translation>
-<translation id="7301833672208172928">ইতিহাস সিঙà§à¦• à¦à¦¾à¦²à§ করà§à¦¨</translation>
+<translation id="7309308571273880165"><ph name="CRASH_TIME" /> ঠকà§à¦°à§à¦¯à¦¾à¦¶ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ কà§à¦¯à¦¾à¦ªà¦à¦¾à¦° করা হয়েছে (বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€ দà§à¦¬à¦¾à¦°à¦¾ আপলোডের অনà§à¦°à§‹à¦§ করা হয়েছে, à¦à¦–নও আপলোড করা হয়নি)</translation>
<translation id="7334320624316649418">&amp;পà§à¦¨à¦°à§à¦¬à¦¿à¦¨à§à¦¯à¦¾à¦¸à¦•à§‡ পà§à¦¨à¦°à¦¾à§Ÿ করà§à¦¨</translation>
<translation id="733923710415886693">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°à¦Ÿà¦¿ শংসাপতà§à¦°à§‡à¦° সà§à¦¬à¦à§à¦›à¦¤à¦¾à¦° মাধà§à¦¯à¦®à§‡ পà§à¦°à¦•à¦¾à¦¶ করা হয়নি।</translation>
+<translation id="7351800657706554155">আপনি à¦à¦–ন <ph name="SITE" /> ঠযেতে পারবেন না কারণ à¦à¦‡ শংসাপতà§à¦° পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হয়েছে। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত সাময়িকভাবে হয়ে থাকে, তাই à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="7353601530677266744">কমà§à¦¯à¦¾à¦¨à§à¦¡ লাইন</translation>
<translation id="7372973238305370288">ফলাফল অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ করà§à¦¨</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,26 +574,28 @@
<translation id="7469372306589899959">কারà§à¦¡ নিশà§à¦à¦¿à¦¤ করা হà¦à§à¦›à§‡</translation>
<translation id="7481312909269577407">ফরওয়ারà§à¦¡</translation>
<translation id="7485870689360869515">কোনো ডেটা পাওয়া যায়নি৷</translation>
+<translation id="7508255263130623398">ফিরে পাওয়া নীতির ডিভাইস আইডি খালি অথবা বরà§à¦¤à¦®à¦¾à¦¨ ডিভাইস আইডির সাথে মিলছে না</translation>
<translation id="7514365320538308">ডাউনলোড করà§à¦¨</translation>
<translation id="7518003948725431193">à¦à¦‡ ওয়েব ঠিকানার কোনও ওয়েবপৃষà§à¦ à¦¾ পাওয়া যায় নি: <ph name="URL" /></translation>
<translation id="7537536606612762813">বাধà§à¦¯à¦¤à¦¾à¦®à§‚লক</translation>
<translation id="7542995811387359312">সà§à¦¬à¦¯à¦¼à¦‚কà§à¦°à¦¿à¦¯à¦¼ কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡ পূরণটি অকà§à¦·à¦® রয়েছে কারণ à¦à¦‡ ফরà§à¦®à¦Ÿà¦¿ কোনও সà§à¦°à¦•à§à¦·à¦¿à¦¤ সংযোগ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে না৷</translation>
<translation id="7549584377607005141">à¦à¦‡ ওয়েবপৃষà§à¦ à¦¾à¦° à¦à¦®à¦¨ ডেটার দরকার যা আপনি ঠিকভাবে পà§à¦°à¦¦à¦°à§à¦¶à¦¿à¦¤ হওয়ার জনà§à¦¯ আগেই পà§à¦°à¦¬à§‡à¦¶ করেছেন৷ আপনি à¦à¦‡ ডেটাটি আবার পাঠাতে পারেন, কিনà§à¦¤à§ à¦à¦®à¦¨à¦Ÿà¦¿ করে আপনি যেকোনো পদকà§à¦·à§‡à¦ªà§‡à¦° পà§à¦¨à¦°à¦¾à¦¬à§ƒà¦¤à§à¦¤à¦¿ করবেন যা à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ আগেই সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ করেছে৷</translation>
<translation id="7554791636758816595">নতà§à¦¨ টà§à¦¯à¦¾à¦¬</translation>
-<translation id="7567204685887185387">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦° পà§à¦°à¦¤à¦¾à¦°à¦£à¦¾à¦ªà§‚রà§à¦£à¦­à¦¾à¦¬à§‡ ইসà§à¦¯à§ করা হয়ে থাকতে পারে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="7568593326407688803">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿<ph name="ORIGINAL_LANGUAGE" />ভাষাতে আছে আপনি কি à¦à¦Ÿà¦¿à¦•à§‡ অনà§à¦¬à¦¾à¦¦ করতে à¦à¦¾à¦‡à¦¬à§‡à¦¨?</translation>
<translation id="7569952961197462199">Chrome থেকে কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡ সরাবেন?</translation>
<translation id="7578104083680115302">আপনি Google à¦à¦° সাথে সংরকà§à¦·à¦£ করেছেন à¦à¦®à¦¨ কারà§à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে ডিভাইস জà§à¦¡à¦¼à§‡ সাইট à¦à¦¬à¦‚ অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨à¦—à§à¦²à¦¿à¦¤à§‡ দà§à¦°à§à¦¤ অরà§à¦¥ পরিশোধ করà§à¦¨à¥¤</translation>
+<translation id="7588950540487816470">বাসà§à¦¤à¦¬à¦¿à¦• ওয়েব</translation>
<translation id="7592362899630581445">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°, নামের সীমাবদà§à¦§à¦¤à¦¾à¦—à§à¦²à¦¿ লঙà§à¦˜à¦¨ করে৷</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> বরà§à¦¤à¦®à¦¾à¦¨à§‡ à¦à¦‡ অনà§à¦°à§‹à¦§à¦Ÿà¦¿ পরিà¦à¦¾à¦²à¦¨à¦¾ করতে অকà§à¦·à¦®à¥¤</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" /> কখনও অনà§à¦¬à¦¾à¦¦ করবেন না</translation>
<translation id="7610193165460212391">সীমার বাইরে মান <ph name="VALUE" />৷</translation>
<translation id="7613889955535752492">মেয়াদোতà§à¦¤à§€à¦°à§à¦£: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
-<translation id="7615602087246926389">আপনার কাছে ইতিমধà§à¦¯à§‡à¦‡ à¦à¦®à¦¨ ডেটা আছে যা Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° পাসওয়ারà§à¦¡à§‡à¦° কোনো ভিনà§à¦¨ সংসà§à¦•à¦°à¦£ বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡à¦° দà§à¦¬à¦¾à¦°à¦¾ à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ করা হয়৷ দয়া করে à¦à¦Ÿà¦¿à¦•à§‡ নীà¦à§‡ লিখà§à¦¨à§·</translation>
+<translation id="7615602087246926389">আপনার কাছে ইতিমধà§à¦¯à§‡à¦‡ à¦à¦®à¦¨ ডেটা আছে যা Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° পাসওয়ারà§à¦¡à§‡à¦° কোনো ভিনà§à¦¨ সংসà§à¦•à¦°à¦£ বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡à¦° দà§à¦¬à¦¾à¦°à¦¾ à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ করা হয়৷ দয়া করে à¦à¦Ÿà¦¿à¦•à§‡ নিà¦à§‡ লিখà§à¦¨à§·</translation>
<translation id="7634554953375732414">à¦à¦‡ সাইটে আপনার সংযোগ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত নয়।</translation>
<translation id="7637571805876720304">Chromium থেকে কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡ সরাবেন?</translation>
<translation id="765676359832457558">উনà§à¦¨à¦¤ সেটিংস লà§à¦•à¦¾à¦¨...</translation>
<translation id="7658239707568436148">বাতিল</translation>
+<translation id="7667346355482952095">ফিরে পাওয়া নীতির টোকেন খালি অথবা বরà§à¦¤à¦®à¦¾à¦¨ টোকেনের সঙà§à¦—ে মেলে না</translation>
<translation id="7668654391829183341">অজানা ডিভাইস</translation>
<translation id="7674629440242451245">Chrome à¦à¦° নতà§à¦¨ দà§à¦°à§à¦¦à¦¾à¦¨à§à¦¤ বৈশিষà§à¦Ÿà§à¦¯à¦—à§à¦²à¦¿à¦¤à§‡ আগà§à¦°à¦¹à§€? chrome.com/dev ঠআমাদের ডেভ à¦à§à¦¯à¦¾à¦¨à§‡à¦² বà§à¦¯à¦¬à¦¹à¦¾à¦° করে দেখà§à¦¨à§·</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /> <ph name="SITE" /> ঠà¦à¦—িয়ে যান (নিরাপদ নয়) <ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">না থাক</translation>
<translation id="7805768142964895445">সà§à¦¥à¦¿à¦¤à¦¿</translation>
<translation id="7813600968533626083">Chrome থেকে ফরà§à¦® পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾ সরাবেন?</translation>
+<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' à¦à¦° জনà§à¦¯ <ph name="NUMBER_OF_RESULTS" />টি <ph name="SEARCH_RESULTS" /> খà§à¦à¦œà§‡ পাওয়া গেছে</translation>
<translation id="785549533363645510">আপনি অবশà§à¦¯ অদৃশà§à¦¯ থাকবেন না। ছদà§à¦®à¦¬à§‡à¦¶à§€ মোডে গেলেও তা আপনার নিয়োগকরà§à¦¤à¦¾, আপনার ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ পরিষেবা পà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ অথবা আপনার পরিদরà§à¦¶à¦¨ করা ওয়েবসাইট থেকে আপনার বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚কে আড়াল করবে না।</translation>
<translation id="7887683347370398519">আপনার CVC পরীকà§à¦·à¦¾ করà§à¦¨ à¦à¦¬à¦‚ আবার à¦à§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨</translation>
<translation id="7894616681410591072">ওহো, à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করতে <ph name="NAME" /> à¦à¦° থেকে আপনার অনà§à¦®à¦¤à¦¿à¦° পà§à¦°à§Ÿà§‹à¦œà¦¨à§·</translation>
-<translation id="790025292736025802"><ph name="URL" /> পাওয়া যায় নি</translation>
<translation id="7912024687060120840">ফোলà§à¦¡à¦¾à¦°à§‡:</translation>
<translation id="7920092496846849526">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿à¦¤à§‡ যাওয়া ঠিক হবে কিনা সেই বিষয়ে আপনি আপনার পিতামাতার অনà§à¦®à¦¤à¦¿ নিন৷</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করে উলà§à¦²à§‡à¦– করা নেই</translation>
<translation id="8012647001091218357">à¦à¦‡ মà§à¦¹à§‚রà§à¦¤à§‡ আমরা আপনার পিতামাতার কাছে পৌà¦à¦›à¦¾à¦¤à§‡ পারিনি৷ অনà§à¦—à§à¦°à¦¹ করে আবার à¦à§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨à§·</translation>
<translation id="8034522405403831421">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ <ph name="SOURCE_LANGUAGE" /> ভাষায় রয়েছে৷ à¦à¦Ÿà¦¿à¦•à§‡ <ph name="TARGET_LANGUAGE" /> ভাষায় অনà§à¦¬à¦¾à¦¦ করবেন?</translation>
-<translation id="8034955203865359138">কোনো ইতিহাস à¦à¦¨à§à¦Ÿà¦¿ পাওয়া যায়নি৷</translation>
<translation id="8088680233425245692">নিবনà§à¦§ দেখতে বà§à¦¯à¦°à§à¦¥ হয়েছে৷</translation>
+<translation id="8089520772729574115">১ মেগাবাইটের কম</translation>
<translation id="8091372947890762290">সারà§à¦­à¦¾à¦°à§‡ সকà§à¦°à¦¿à§Ÿà¦•à¦°à¦£ বাকি আছে</translation>
+<translation id="8129262335948759431">অজানা পরিমাণ</translation>
<translation id="8131740175452115882">নিশà§à¦à¦¿à¦¤ হন</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> à¦à¦° সারà§à¦­à¦¾à¦° <ph name="BEGIN_ABBR" />DNS ঠিকানা<ph name="END_ABBR" />খà§à¦à¦œà§‡ পাওয়া যায়নি।</translation>
<translation id="8149426793427495338">আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦°à¦Ÿà¦¿ নিদà§à¦°à¦¾ মোডে গিয়েছে।</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" ID যà§à¦•à§à¦¤ à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¾à¦¨à§‡à¦° অবৈধ আপডেট URL।</translation>
<translation id="8218327578424803826">নিরà§à¦§à¦¾à¦°à¦¿à¦¤ অবসà§à¦¥à¦¾à¦¨:</translation>
<translation id="8225771182978767009">à¦à¦‡ কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦° যিনি সেট আপ করেছেন তিনি à¦à¦‡ সাইটটি অবরà§à¦¦à§à¦§ করার বিষয়টি à¦à§Ÿà¦¨ করেছেন।</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">আপনি যে পৃষà§à¦ à¦¾à¦Ÿà¦¿ খà§à¦à¦œà¦›à§‡à¦¨ সেটি আপনার পà§à¦°à¦¬à§‡à¦¶ করানো তথà§à¦¯ বà§à¦¯à¦¬à¦¹à¦¾à¦° করছে৷ à¦à¦‡ পৃষà§à¦ à¦¾à¦¤à§‡ ফিরে à¦à¦²à§‡ কোনো কà§à¦°à¦¿à§Ÿà¦¾ আবার করতে হতে পারে৷ আপনি কি অবিরত করতে à¦à¦¾à¦¨?</translation>
<translation id="8249320324621329438">সরà§à¦¬à¦¶à§‡à¦· পà§à¦°à¦¾à¦ªà§à¦¤ করেছে:</translation>
<translation id="8261506727792406068">মà§à¦›à§à¦¨</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">বà§à¦•à¦®à¦¾à¦°à§à¦•à¦¸ দণà§à¦¡</translation>
<translation id="8363502534493474904">বিমান মোড বনà§à¦§ করে দেখà§à¦¨</translation>
<translation id="8364627913115013041">সেট করা নেই৷</translation>
+<translation id="8380941800586852976">বিপজà§à¦œà¦¨à¦•</translation>
<translation id="8412145213513410671">কà§à¦°à§à¦¯à¦¾à¦¶ (<ph name="CRASH_COUNT" />টি)</translation>
<translation id="8412392972487953978">আপনাকে à¦à¦•à¦‡ পাসফà§à¦°à§‡à¦œ অবশà§à¦¯à¦‡ দà§'বার পà§à¦°à¦¬à§‡à¦¶ করাতে হবে৷</translation>
<translation id="8428213095426709021">সেটিংস</translation>
+<translation id="8433057134996913067">à¦à¦Ÿà¦¿ বেশিরভাগ ওয়েবসাইট থেকে আপনাকে পà§à¦°à¦¸à§à¦¥à¦¾à¦¨ করà§à¦¨ করবে।</translation>
<translation id="8437238597147034694">&amp;সরানোকে পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{১টি কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡}one{#টি কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡}other{#টি কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡}}</translation>
+<translation id="8483780878231876732">আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ থেকে কারà§à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করার জনà§à¦¯ Chrome ঠসাইন ইন করà§à¦¨</translation>
<translation id="8488350697529856933">à¦à¦¤à§‡ পà§à¦°à§Ÿà§‹à¦— হয়</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> সাড়া দিতে খà§à¦¬à§‡ বেশি সময় নিয়েছে।</translation>
+<translation id="852346902619691059">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¾ <ph name="DOMAIN" />; আপনার ডিভাইসের অপারেটিং সিসà§à¦Ÿà§‡à¦® à¦à¦° নিরাপতà§à¦¤à¦¾ শংসাপতà§à¦°à¦Ÿà¦¿à¦•à§‡ বিশà§à¦¬à¦¾à¦¸ করে না। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিà¦à§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরো জানà§à¦¨<ph name="END_LEARN_MORE_LINK" />।</translation>
<translation id="8530504477309582336">à¦à¦‡ ধরনের কারà§à¦¡ Google Payments দà§à¦¬à¦¾à¦°à¦¾ সমরà§à¦¥à¦¿à¦¤ নয়৷ দয়া করে à¦à¦•à¦Ÿà¦¿ আলাদা কারà§à¦¡ নিরà§à¦¬à¦¾à¦à¦¨ করà§à¦¨à§·</translation>
<translation id="8550022383519221471">আপনার ডোমেনের জনà§à¦¯ সিঙà§à¦• পরিষেবা উপলবà§à¦§ নেই৷</translation>
<translation id="8553075262323480129">পৃষà§à¦ à¦¾à¦° ভাষা নিরà§à¦§à¦¾à¦°à¦£ না করতে পারার কারণে অনà§à¦¬à¦¾à¦¦ বà§à¦¯à¦°à§à¦¥ হয়েছে৷</translation>
@@ -633,15 +675,12 @@
<translation id="8647750283161643317">সবগà§à¦²à¦¿à¦•à§‡ ডিফলà§à¦Ÿà§‡ পà§à¦¨à¦°à¦¾à§Ÿ সেট করà§à¦¨</translation>
<translation id="8680787084697685621">অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ সাইন-ইন বিশদ তারিখ সীমার বাইরে৷</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" />-ঠআপনার কানেকশন à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ হয় নি৷</translation>
-<translation id="8713130696108419660">খারাপ ইনিশিয়াল সà§à¦¬à¦¾à¦•à§à¦·à¦°</translation>
<translation id="8725066075913043281">আবার à¦à§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨</translation>
<translation id="8728672262656704056">আপনি ছদà§à¦®à¦¬à§‡à¦¶à§‡ রয়েছেন৷</translation>
<translation id="8730621377337864115">সমà§à¦ªà¦¨à§à¦¨ হয়েছে</translation>
<translation id="8738058698779197622">নিরাপদ নেটওয়ারà§à¦• সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করতে আপনার ঘড়িকে সঠিকভাবে সেট করতে হবে৷ নিরাপদ সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করার জনà§à¦¯ নিজেদের সনাকà§à¦¤ করার জনà§à¦¯ ওয়েবসাইটগà§à¦²à¦¿ যে শংসাপতà§à¦°à¦—à§à¦²à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে, সেগà§à¦²à¦¿ শà§à¦§à§à¦®à¦¾à¦¤à§à¦° নিরà§à¦¦à¦¿à¦·à§à¦Ÿ সময়ের জনà§à¦¯ বৈধ থাকে৷ যেহেতৠআপনার ডিভাইসের ঘড়িটি ভà§à¦², সেই জনà§à¦¯ Chromium সঠিকভাবে শংসাপতà§à¦°à¦—à§à¦²à¦¿ পরীকà§à¦·à¦¾ করতে পারে না৷</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> à¦à¦° &lt;abbr id="dnsDefinition"&gt;DNS ঠিকানা&lt;/abbr&gt; পাওয়া যায়নি। সমসà§à¦¯à¦¾ নিরà§à¦£à§Ÿ করা হà¦à§à¦›à§‡à¥¤</translation>
-<translation id="8741995161408053644"><ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ঠআপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° অনà§à¦¯à¦¾à¦¨à§à¦¯ ধরনের বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ ইতিহাস থাকতে পারে।</translation>
<translation id="8790007591277257123">&amp;মà§à¦›à§‡ ফেলাকে পà§à¦¨à¦°à¦¾à§Ÿ করà§à¦¨</translation>
-<translation id="8790687370365610530">Google দà§à¦¬à¦¾à¦°à¦¾ পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤ বà§à¦¯à¦•à§à¦¤à¦¿à¦—তকৃত সামগà§à¦°à§€ পেতে, ইতিহাস সিঙà§à¦• à¦à¦¾à¦²à§ করà§à¦¨à¥¤</translation>
<translation id="8798099450830957504">ডিফলà§à¦Ÿ</translation>
<translation id="8804164990146287819">গোপনীয়তা নীতি</translation>
<translation id="8820817407110198400">বà§à¦•à¦®à¦¾à¦°à§à¦•à¦¸</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">সারà§à¦­à¦¾à¦°à§‡à¦° শংসাপতà§à¦°à§‡à¦° মেয়াদ ফà§à¦°à¦¿à§Ÿà§‡à¦›à§‡à§·</translation>
<translation id="8987927404178983737">মাস</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ à¦à¦®à¦¨ à¦à¦•à¦Ÿà¦¿ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে যেটি শংসাপতà§à¦°à§‡à¦° সà§à¦¬à¦à§à¦›à¦¤à¦¾à¦° নীতি বà§à¦¯à¦¬à¦¹à¦¾à¦° করে সরà§à¦¬à¦œà¦¨à§€à¦¨à¦­à¦¾à¦¬à§‡ পà§à¦°à¦•à¦¾à¦¶ করা হয়নি। à¦à¦Ÿà¦¾ কিছৠশংসাপতà§à¦°à§‡à¦° জনà§à¦¯ à¦à¦•à¦Ÿà¦¿ আবশà§à¦¯à¦•à¦¤à¦¾, যাতে করে সেগà§à¦²à¦¿à¦° বিশà§à¦¬à¦¾à¦¸à¦¯à§‹à¦—à§à¦¯à¦¤ করা যায় à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦¦à§‡à¦° বিরà§à¦¦à§à¦§à§‡ সà§à¦°à¦•à§à¦·à¦¾ নেওয়া যায়।</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> পà§à¦°à¦•à§à¦¸à§€à¦Ÿà¦¿à¦° à¦à¦•à¦Ÿà¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€ নাম à¦à¦¬à¦‚ পাসওয়ারà§à¦¡ পà§à¦°à§Ÿà§‹à¦œà¦¨à¥¤</translation>
<translation id="901974403500617787">যে ফà§à¦²à§à¦¯à¦¾à¦—গà§à¦²à¦¿ সমসà§à¦¤ সিসà§à¦Ÿà§‡à¦® জà§à§œà§‡ পà§à¦°à§Ÿà§‹à¦— করা হয় সেগà§à¦²à¦¿ শà§à¦§à§à¦®à¦¾à¦¤à§à¦° মালিকের দà§à¦¬à¦¾à¦°à¦¾ সেট করা যেতে পারে: <ph name="OWNER_EMAIL" />৷</translation>
<translation id="9020542370529661692">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ <ph name="TARGET_LANGUAGE" /> ঠঅনà§à¦¬à¦¾à¦¦ করা হয়েছে</translation>
<translation id="9038649477754266430">পৃষà§à¦ à¦¾ আরো দà§à¦°à§à¦¤ লোড করার জনà§à¦¯ কোনো পূরà§à¦¬à¦¾à¦­à¦¾à¦· পরিষেবা বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨</translation>
<translation id="9039213469156557790">উপরনà§à¦¤à§, à¦à¦‡ পৃষà§à¦ à¦¾à¦¤à§‡ অনà§à¦¯à¦¾à¦¨à§à¦¯ সংসà§à¦¥à¦¾à¦¨ অনà§à¦¤à¦°à§à¦­à§à¦•à§à¦¤ রয়েছে যা নিরাপদ নয়৷ à¦à¦‡ সংসà§à¦¥à¦¾à¦¨à¦—à§à¦²à¦¿ টà§à¦°à¦¾à¦¨à¦œà¦¿à¦Ÿà§‡à¦° সময় অনà§à¦¯à¦°à¦¾ দেখতে পাবে à¦à¦¬à¦‚ পৃষà§à¦ à¦¾à¦Ÿà¦¿à¦° আà¦à¦°à¦£ পরিবরà§à¦¤à¦¨ করার জনà§à¦¯ কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ à¦à¦° পরিবরà§à¦¤à¦¨ করতে পারেন৷</translation>
-<translation id="9049981332609050619">আপনি <ph name="DOMAIN" />-ঠপৌছানোর পà§à¦°à§Ÿà¦¾à¦¸ করছেন, কিনà§à¦¤à§ সারà§à¦­à¦¾à¦° à¦à¦•à¦Ÿà¦¿ অবৈধ শংসাপতà§à¦° উপসà§à¦¥à¦¾à¦ªà¦¨ করেছে|</translation>
<translation id="9050666287014529139">পাসফà§à¦°à§‡à¦œ</translation>
<translation id="9065203028668620118">সমà§à¦ªà¦¾à¦¦à¦¨à¦¾</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> পৃষà§à¦ à¦¾à¦Ÿà¦¿ কাজ করছে না</translation>
diff --git a/chromium/components/strings/components_strings_ca.xtb b/chromium/components/strings/components_strings_ca.xtb
index 0ffe6ef1108..0a27a43a1c6 100644
--- a/chromium/components/strings/components_strings_ca.xtb
+++ b/chromium/components/strings/components_strings_ca.xtb
@@ -1,21 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ca">
+<translation id="1008557486741366299">Ara no</translation>
<translation id="1015730422737071372">Proporcioneu mĂ©s informaciĂ³</translation>
<translation id="1032854598605920125">Gira en el sentit de les agulles del rellotge</translation>
<translation id="1038842779957582377">nom desconegut</translation>
+<translation id="1053591932240354961">En aquest moment no pots visitar <ph name="SITE" /> perquè el lloc web ha enviat credencials aleatĂ²ries que Google Chrome no pot processar. Els errors i els atacs de xarxa solen ser temporals, de manera que Ă©s probable que aquesta pĂ gina torni a funcionar mĂ©s tard. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;DesfĂ©s l'addiciĂ³</translation>
<translation id="10614374240317010">Contrasenyes que no es desen mai</translation>
-<translation id="1064422015032085147">Pot ser que el servidor on s'allotja la pĂ gina web estigui sobrecarregat o bĂ© que s'hi estiguin realitzant tasques de manteniment. Per evitar que es generi massa trĂ nsit i la situaciĂ³ empitjori, no es permet enviar sol·licituds a aquest URL de manera temporal.</translation>
<translation id="106701514854093668">Adreces d'interès d'escriptori</translation>
<translation id="1080116354587839789">Ajusta a l'amplada</translation>
-<translation id="1103523840287552314">Tradueix sempre l'idioma <ph name="LANGUAGE" /></translation>
+<translation id="1103124106085518534">Tot llest per ara</translation>
+<translation id="1103523840287552314">Tradueix sempre de: <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Si s'activa aquesta casella, Chrome emmagatzema una cĂ²pia d'aquesta targeta al dispositiu per agilitzar l'emplenament de formularis.</translation>
+<translation id="1111153019813902504">Adreces d'interès recents</translation>
<translation id="1113869188872983271">&amp;Desfés el canvi d'ordre</translation>
+<translation id="1126551341858583091">La mida de l'emmagatzematge local Ă©s de <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">La memĂ²ria cau de la polĂ­tica estĂ  en bon estat</translation>
<translation id="113188000913989374"><ph name="SITE" /> diu:</translation>
<translation id="1132774398110320017">ConfiguraciĂ³ d'Emplenament automĂ tic de Chrome...</translation>
-<translation id="1150979032973867961">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el sistema operatiu del vostre ordinador considera que el seu certificat de seguretat no Ă©s de confiança. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³.</translation>
<translation id="1152921474424827756">Accediu a una <ph name="BEGIN_LINK" />cĂ²pia emmagatzemada a la memĂ²ria cau<ph name="END_LINK" /> de la pĂ gina <ph name="URL" />.</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ha tancat la connexiĂ³ de manera inesperada.</translation>
<translation id="1161325031994447685">Torneu-vos a connectar a la xarxa Wi-Fi</translation>
@@ -23,7 +26,8 @@
<translation id="1181037720776840403">Suprimeix</translation>
<translation id="1201402288615127009">SegĂ¼ent</translation>
<translation id="1201895884277373915">MĂ©s entrades d'aquest lloc</translation>
-<translation id="121201262018556460">Heu provat d'accedir a <ph name="DOMAIN" />, perĂ² el servidor ha presentat un certificat que contĂ© una clau dèbil. És possible que un atacant hagi accedit a la clau privada i que aquest servidor no sigui el que espereu (pot ser que us estigueu comunicant amb un atacant).</translation>
+<translation id="1206967143813997005">Signatura inicial incorrecta</translation>
+<translation id="1209206284964581585">Amaga per ara</translation>
<translation id="1219129156119358924">Seguretat del sistema</translation>
<translation id="1227224963052638717">PolĂ­tica desconeguda.</translation>
<translation id="1227633850867390598">Amaga el valor</translation>
@@ -44,6 +48,7 @@
<translation id="1426410128494586442">SĂ­</translation>
<translation id="1430915738399379752">ImpressiĂ³</translation>
<translation id="1442912890475371290">S'ha bloquejat un intent <ph name="BEGIN_LINK" />d'accés a una pàgina de <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">En aquest moment no pots visitar <ph name="SITE" /> perquè el lloc web fa servir la fixaciĂ³ de certificats. Els errors i els atacs de xarxa solen ser temporals, de manera que Ă©s probable que aquesta pĂ gina torni a funcionar mĂ©s tard. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Mostra una cĂ²pia desada (Ă©s a dir, no actualitzada) d'aquesta pĂ gina.</translation>
<translation id="1519264250979466059">Data de creaciĂ³</translation>
<translation id="1549470594296187301">Heu d'activar el JavaScript per utilitzar aquesta funciĂ³.</translation>
@@ -58,36 +63,34 @@
<translation id="1644184664548287040">La configuraciĂ³ de la xarxa no Ă©s vĂ lida i no s'ha pogut importar.</translation>
<translation id="1644574205037202324">Historial</translation>
<translation id="1645368109819982629">Protocol no admès</translation>
-<translation id="1655462015569774233">{1,plural, =1{Aquest servidor no ha pogut demostrar que sigui <ph name="DOMAIN" /> perquè el seu certificat de seguretat va caducar ahir. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³. Actualment, el rellotge del vostre ordinador estĂ  configurat amb la data <ph name="CURRENT_DATE" />. És correcta? Si no ho Ă©s, corregiu el rellotge del sistema i, a continuaciĂ³, actualitzeu aquesta pĂ gina.}other{Aquest servidor no ha pogut demostrar que sigui <ph name="DOMAIN" /> perquè el seu certificat va caducar fa # dies. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³. Actualment, el rellotge del vostre ordinador estĂ  configurat amb la data <ph name="CURRENT_DATE" />. És correcta? Si no ho Ă©s, corregiu el rellotge del sistema i, a continuaciĂ³, actualitzeu aquesta pĂ gina.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> utilitza normalment l'encriptaciĂ³ per protegir la vostra informaciĂ³. En aquesta ocasiĂ³, quan Google Chrome ha provat de connectar-se a <ph name="SITE" />, el lloc web ha enviat credencials poc comunes i incorrectes. Pot ser que un atacant estigui provant de fer-se passar per <ph name="SITE" /> o que una pantalla d'inici de sessiĂ³ a la xarxa Wi-Fi hagi interromput la connexiĂ³. En qualsevol cas, la vostra informaciĂ³ continua estant segura, perquè Google Chrome ha aturat la connexiĂ³ abans no s'intercanviĂ©s cap dada.</translation>
<translation id="168841957122794586">El certificat de servidor conté una clau criptogràfica dèbil.</translation>
<translation id="1701955595840307032">Obtén suggeriments de contingut</translation>
-<translation id="1706954506755087368">{1,plural, =1{Aquest servidor no ha pogut demostrar que sigui <ph name="DOMAIN" /> perquè, suposadament, el seu certificat de seguretat tĂ© la data de demĂ . AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³.}other{Aquest servidor no ha pogut demostrar que sigui <ph name="DOMAIN" />; perquè, suposadament, el seu certificat de seguretat tĂ© una data que Ă©s d'aquĂ­ a # dies. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³.}}</translation>
<translation id="1710259589646384581">SO</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Proveu de contactar amb l'administrador del sistema.</translation>
<translation id="17513872634828108">Pestanyes obertes</translation>
<translation id="1753706481035618306">NĂºmero de pĂ gina</translation>
-<translation id="1761412452051366565">Activa la sincronitzaciĂ³ perquè Google et suggereixi contingut personalitzat.</translation>
-<translation id="1763864636252898013">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el sistema operatiu del vostre dispositiu considera que el seu certificat de seguretat no Ă©s de confiança. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Proveu d'executar el DiagnĂ²stic de xarxa de Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Actualitzeu la frase de contrasenya de sincronitzaciĂ³.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Les pĂ gines que has visitat fa poc es mostraran aquĂ­.</translation>
<translation id="1821930232296380041">Sol·licitud o paràmetres de la sol·licitud no vàlids</translation>
<translation id="1838667051080421715">EstĂ s veient el codi font d'una pĂ gina web.</translation>
<translation id="1871208020102129563">El servidor intermediari està configurat perquè utilitzi servidors intermediaris fixos, en lloc d'un URL d'script .pac.</translation>
<translation id="1883255238294161206">Redueix la llista</translation>
<translation id="1898423065542865115">Filtratge</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> no ha acceptat el certificat d'inici de sessiĂ³, o potser ha caducat.</translation>
<translation id="194030505837763158">VĂ©s a <ph name="LINK" /></translation>
<translation id="1962204205936693436">Adreces d'interès de <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Error de serialitzaciĂ³</translation>
<translation id="1974060860693918893">ConfiguraciĂ³ avançada</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{i 1 aplicaciĂ³ mĂ©s}other{i # aplicacions mĂ©s}}</translation>
<translation id="2025186561304664664">El servidor intermediari està definit perquè es configuri automàticament.</translation>
<translation id="2030481566774242610">VolĂ­eu dir <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Veieu aquest missatge perquè els vostres pares han d'aprovar els llocs que visiteu per primera vegada.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Comproveu el servidor intermediari i el tallafoc<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Codi postal</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 suggeriment}other{# suggeriments}}</translation>
<translation id="2065985942032347596">Es necessita autenticaciĂ³</translation>
<translation id="2079545284768500474">Desfés</translation>
<translation id="20817612488360358">S'ha definit la configuraciĂ³ del servidor intermediari del sistema perquè es pugui utilitzar, perĂ² tambĂ© s'ha especificat una configuraciĂ³ del servidor intermediari explĂ­cita.</translation>
@@ -103,32 +106,34 @@
<translation id="2149973817440762519">EdiciĂ³ de l'adreça d'interès</translation>
<translation id="2166049586286450108">Accés complet d'administrador</translation>
<translation id="2166378884831602661">Aquest lloc no pot proporcionar una connexiĂ³ segura</translation>
-<translation id="2171101176734966184">Heu provat d'accedir a <ph name="DOMAIN" />, perĂ² el servidor ha presentat un certificat signat mitjançant un algoritme de signatura dèbil. AixĂ² indica que les credencials de seguretat que ha presentat el servidor podrien haver estat falsificades i que Ă©s possible que el servidor no sigui el que esperĂ veu (Ă©s possible que us estigueu comunicant amb un atacant).</translation>
<translation id="2181821976797666341">PolĂ­tiques</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adreça}other{# adreces}}</translation>
<translation id="2212735316055980242">No es troba la polĂ­tica</translation>
<translation id="2213606439339815911">S'estan recuperant les entrades...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> no estĂ  disponible</translation>
<translation id="2230458221926704099">Repareu la connexiĂ³ amb l'<ph name="BEGIN_LINK" />aplicaciĂ³ de diagnĂ²stic<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Envia ara</translation>
<translation id="225207911366869382">El valor d'aquesta polĂ­tica Ă©s obsolet.</translation>
<translation id="2262243747453050782">Error d'HTTP</translation>
<translation id="2282872951544483773">Experiments no disponibles</translation>
<translation id="2292556288342944218">El vostre accés a Internet està bloquejat</translation>
<translation id="229702904922032456">Ha caducat un certificat arrel o intermedi.</translation>
<translation id="230155334948463882">És una targeta nova?</translation>
+<translation id="2305919008529760154">Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" />. És possible que el seu certificat de seguretat s'hagi emès de manera fraudulenta. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> requereix un nom d'usuari i una contrasenya.</translation>
+<translation id="2318774815570432836">En aquest moment no pots visitar <ph name="SITE" /> perquè el lloc web fa servir HSTS. Els errors i els atacs de xarxa solen ser temporals, de manera que Ă©s probable que aquesta pĂ gina torni a funcionar mĂ©s tard. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">S'ha ignorat l'adreça d'interès no vàlida a l'índex <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Altres adreces d'interès</translation>
<translation id="2359808026110333948">Continua</translation>
<translation id="2365563543831475020">L'informe d'error capturat (<ph name="CRASH_TIME" />) no s'ha penjat</translation>
<translation id="2367567093518048410">Nivell</translation>
+<translation id="2371153335857947666">{1,plural, =1{Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" /> perquè el seu certificat de seguretat va caducar ahir. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. Actualment, el rellotge del teu ordinador estĂ  configurat amb la data <ph name="CURRENT_DATE" />. És correcta? Si no ho Ă©s, corregeix el rellotge del sistema i, a continuaciĂ³, actualitza aquesta pĂ gina. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.}other{Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" /> perquè el seu certificat va caducar fa # dies. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. Actualment, el rellotge del teu ordinador estĂ  configurat amb la data <ph name="CURRENT_DATE" />. És correcta? Si no ho Ă©s, corregeix el rellotge del sistema i, a continuaciĂ³, actualitza aquesta pĂ gina. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">No hi ha cap alternativa a la IU disponible.</translation>
<translation id="2384307209577226199">Predeterminada de l'empresa</translation>
-<translation id="238526402387145295">En aquest moment no podeu visitar <ph name="SITE" /> perquè el lloc web <ph name="BEGIN_LINK" />fa servir HSTS<ph name="END_LINK" />. Els errors de la xarxa i els atacs solen ser temporals, de manera que és probable que aquesta pàgina torni a funcionar més tard.</translation>
<translation id="2386255080630008482">El certificat del servidor s'ha revocat.</translation>
<translation id="2392959068659972793">Mostra les polĂ­tiques sense valors definits</translation>
<translation id="2396249848217231973">&amp;DesfĂ©s la supressiĂ³</translation>
-<translation id="2413528052993050574">El servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè Ă©s possible que el seu certificat de seguretat s'hagi revocat. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³.</translation>
<translation id="2455981314101692989">Aquesta pĂ gina web ha desactivat l'emplenament automĂ tic per a aquest formulari.</translation>
+<translation id="2463739503403862330">Emplena</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Executar el DiagnĂ²stic de xarxa<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL de cerca no vĂ lid.</translation>
<translation id="2491120439723279231">El certificat del servidor conté errors.</translation>
@@ -150,10 +155,12 @@
<translation id="2653659639078652383">Envia</translation>
<translation id="2674170444375937751">EstĂ s segur que vols suprimir aquestes pĂ gines de l'historial?</translation>
<translation id="2677748264148917807">Surt</translation>
+<translation id="269990154133806163">El servidor ha presentat un certificat que no s'ha divulgat pĂºblicament mitjançant la polĂ­tica Transparència de certificats. AixĂ² Ă©s un requisit d'alguns certificats per garantir que sĂ³n de confiança i una mesura de protecciĂ³ contra els atacants. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">El valor no coincideix amb el format.</translation>
<translation id="2704951214193499422">En aquest moment Chromium no ha pogut confirmar la teva targeta. Torna-ho a provar més tard.</translation>
<translation id="2705137772291741111">La cĂ²pia desada (a la memĂ²ria cau) d'aquest lloc no s'ha pogut llegir.</translation>
<translation id="2709516037105925701">Emplenament autom.</translation>
+<translation id="2712118517637785082">Has provat d'accedir a <ph name="DOMAIN" />, perĂ² l'emissor ha revocat el certificat que ha presentat el servidor. AixĂ² vol dir que les credencials de seguretat que ha proporcionat el servidor no sĂ³n de confiança. És possible que t'estiguis comunicant amb un atacant. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Demana permĂ­s</translation>
<translation id="2721148159707890343">Sol·licitud realitzada correctament</translation>
<translation id="2728127805433021124">El certificat del servidor està signat mitjançant un algoritme de signatura dèbil.</translation>
@@ -165,14 +172,11 @@
<translation id="2824775600643448204">Barra d'adreces i de cerca</translation>
<translation id="2826760142808435982">La connexiĂ³ s'ha encriptat i autenticat mitjançant <ph name="CIPHER" /> i fa servir <ph name="KX" /> com a mecanisme d'intercanvi clau.</translation>
<translation id="2835170189407361413">Esborra el formulari</translation>
-<translation id="2837049386027881519">S'ha hagut de tornar a intentar la connexiĂ³ mitjançant una versiĂ³ anterior del protocol TLS o SSL. Generalment, aixĂ² vol dir que el servidor utilitza un programari molt antic i Ă©s possible que tingui altres problemes de seguretat.</translation>
<translation id="284702764277384724">Sembla que el certificat de servidor disponible a <ph name="HOST_NAME" /> Ă©s una falsificaciĂ³.</translation>
<translation id="2889159643044928134">No tornis a carregar</translation>
-<translation id="2896499918916051536">Aquest connector no Ă©s compatible.</translation>
+<translation id="2900469785430194048">Google Chrome s'ha quedat sense memĂ²ria en provar de mostrar aquesta pĂ gina web.</translation>
<translation id="2909946352844186028">S'ha detectat un canvi a la xarxa.</translation>
-<translation id="2915500479781995473">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el seu certificat de seguretat ha caducat. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³. Actualment, el rellotge de l'ordinador estĂ  definit com a <ph name="CURRENT_TIME" />. Creieu que Ă©s correcte? Si no Ă©s aixĂ­, corregiu el rellotge del sistema i actualitzeu aquesta pĂ gina.</translation>
<translation id="2922350208395188000">No es pot comprovar el certificat del servidor.</translation>
-<translation id="2941952326391522266">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el seu certificat de seguretat provĂ© del domini <ph name="DOMAIN2" />. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³.</translation>
<translation id="2948083400971632585">Podeu desactivar qualsevol servidor intermediari configurat per a una connexiĂ³ des de la pĂ gina de configuraciĂ³.</translation>
<translation id="2955913368246107853">Tanca la barra de cerca</translation>
<translation id="2958431318199492670">La configuraciĂ³ de la xarxa no compleix l'estĂ ndard ONC. Pot ser que algunes opcions de configuraciĂ³ no s'hagin importat.</translation>
@@ -186,6 +190,7 @@
<translation id="3024663005179499861">Tipus de polĂ­tica incorrecte</translation>
<translation id="3032412215588512954">Voleu tornar a carregar aquest lloc?</translation>
<translation id="3037605927509011580">Oh, no!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{almenys 1 element als dispositius sincronitzats}=1{1 element (i altres elements als dispositius sincronitzats)}other{# elements (i altres elements als dispositius sincronitzats)}}</translation>
<translation id="3041612393474885105">InformaciĂ³ del certificat</translation>
<translation id="3063697135517575841">Chrome no ha pogut confirmar la teva targeta. Torna-ho a provar més tard.</translation>
<translation id="3093245981617870298">Esteu fora de lĂ­nia.</translation>
@@ -204,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Els més recents</translation>
<translation id="3207960819495026254">S'ha afegit a les adreces d'interès.</translation>
-<translation id="3225919329040284222">El servidor ha presentat un certificat que no coincideix amb les expectatives integrades. Les expectatives s'inclouen perquè determinats llocs web d'alta seguretat us protegeixin.</translation>
<translation id="3226128629678568754">Premeu el botĂ³ de tornar a carregar per tornar a enviar les dades necessĂ ries per carregar la pĂ gina.</translation>
<translation id="3228969707346345236">S'ha produĂ¯t un error en fer la traducciĂ³ perquè la pĂ gina ja estĂ  en <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Introdueix el CVC de la targeta <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Afegeix aquesta pàgina a les adreces d'interès</translation>
<translation id="3270847123878663523">&amp;Desfés el canvi d'ordre</translation>
<translation id="3286538390144397061">Reinicia ara</translation>
+<translation id="3303855915957856445">No s'ha trobat cap resultat de la cerca</translation>
<translation id="3305707030755673451">Les vostres dades es van encriptar el dia <ph name="TIME" /> amb la vostra frase de contrasenya de sincronitzaciĂ³. IntroduĂ¯u-la per començar la sincronitzaciĂ³.</translation>
<translation id="333371639341676808">Evita que aquesta pĂ gina creĂ¯ diĂ legs addicionals.</translation>
+<translation id="3338095232262050444">Segur</translation>
<translation id="3340978935015468852">configuraciĂ³</translation>
<translation id="3345135638360864351">La sol·licitud per accedir al lloc no s'ha pogut enviar a <ph name="NAME" />. Torneu-ho a provar.</translation>
<translation id="3355823806454867987">Canvia la configuraciĂ³ del servidor intermediari...</translation>
@@ -230,31 +236,36 @@
<translation id="3452404311384756672">Obtén l'interval:</translation>
<translation id="3462200631372590220">Amaga la informaciĂ³ avançada</translation>
<translation id="3479539252931486093">Heu trobat el lloc bloquejat de manera inesperada? <ph name="BEGIN_LINK" />Informeu-nos-en<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Ara no</translation>
<translation id="348000606199325318">Identificador d'error <ph name="CRASH_LOCAL_ID" /> (identificador de servidor: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">En aquests moments no ens hem pogut posar en contacte amb els pares. Torneu-ho a provar.</translation>
<translation id="3527085408025491307">Carpeta</translation>
<translation id="3528171143076753409">El certificat del servidor no és de confiança.</translation>
<translation id="3539171420378717834">Desa una cĂ²pia d'aquesta targeta al dispositiu</translation>
<translation id="3542684924769048008">Utilitzar la contrasenya per a:</translation>
-<translation id="3549644494707163724">Encripta totes les dades sincronitzades amb la vostra frase de contrasenya de sincronitzaciĂ³</translation>
+<translation id="3549644494707163724">Encripta totes les dades sincronitzades amb la teva frase de contrasenya de sincronitzaciĂ³</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> més...</translation>
+<translation id="3555561725129903880">Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" /> perquè el seu certificat de seguretat provĂ© del domini <ph name="DOMAIN2" />. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">La vostra connexiĂ³ no Ă©s privada</translation>
<translation id="3583757800736429874">&amp;Refés el moviment</translation>
<translation id="3586931643579894722">Oculta els detalls</translation>
<translation id="3587482841069643663">Tots</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3609138628363401169">El servidor no admet l'extensiĂ³ de renegociaciĂ³ TLS.</translation>
-<translation id="36224234498066874">Elimina les dades de navegaciĂ³...</translation>
+<translation id="36224234498066874">Esborra les dades de navegaciĂ³</translation>
<translation id="362276910939193118">Mostra l'historial complet</translation>
<translation id="3623476034248543066">Mostra el valor</translation>
<translation id="3630155396527302611">Si ja estĂ  inclĂ²s a la llista de programes autoritzats per accedir a la xarxa, proveu
de suprimir-lo de la llista i torneu-lo a afegir.</translation>
+<translation id="3638794133396384728">Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" /> perquè el seu certificat de seguretat ha caducat. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. Actualment, el rellotge del teu ordinador estĂ  configurat amb la data <ph name="CURRENT_TIME" />. És correcta? Si no ho Ă©s, corregeix el rellotge del sistema i, a continuaciĂ³, actualitza aquesta pĂ gina. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Aquestes funcions experimentals poden canviar, trencar-se o desaparèixer en qualsevol moment. No donem cap garantia sobre què pot passar si activeu algun d'aquests experiments, i fins i tot el vostre navegador es podria fregir de sobte. Bromes a part,Ă©s possible que el vostre navegador suprimeixi totes les vostres dades, o bĂ© la seguretat i la privadesa poden estar compromeses de maneres inesperades. Qualsevol experiment que activeu s'activaran per a tots els usuaris d'aquest navegador. Continueu amb precauciĂ³.</translation>
<translation id="3650584904733503804">ValidaciĂ³ correcta</translation>
<translation id="3655670868607891010">Si aquest missatge apareix sovint, proveu aquests <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">RevisiĂ³</translation>
+<translation id="3678029195006412963">La sol·licitud no s'ha pogut signar</translation>
<translation id="3681007416295224113">InformaciĂ³ del certificat</translation>
<translation id="3693415264595406141">Contrasenya:</translation>
+<translation id="3696411085566228381">cap</translation>
<translation id="3700528541715530410">Sembla que no teniu permĂ­s per accedir a aquesta pĂ gina.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">S'estĂ  carregant...</translation>
@@ -262,7 +273,6 @@
<translation id="3714780639079136834">Activeu les dades mĂ²bils o la Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Comproveu el servidor intermediari, el tallafoc i la configuraciĂ³ de DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Enllaç que heu copiat</translation>
-<translation id="3744899669254331632">En aquest moments no podeu visitar la pĂ gina <ph name="SITE" /> perquè el lloc web ha enviat credencials aleatĂ²ries que Chromium no pot processar. Els atacs i els errors de xarxa acostumen a ser temporals, o sigui que probablement la pĂ gina funcionarĂ  mĂ©s endavant.</translation>
<translation id="375403751935624634">S'ha produĂ¯t un error en el procĂ©s de traducciĂ³ a causa d'un error del servidor.</translation>
<translation id="3759461132968374835">No heu informat de cap bloqueig recentment. Els bloquejos que es van produir mentre la creaciĂ³ d'informes de bloqueig estava desactivada no apareixeran aquĂ­.</translation>
<translation id="3788090790273268753">El certificat d'aquest lloc caduca al 2016, i la cadena de certificats conté un certificat que s'ha signat amb SHA-1.</translation>
@@ -274,19 +284,25 @@
<translation id="3884278016824448484">L'identificador del dispositiu ja s'estĂ  utilitzant</translation>
<translation id="3885155851504623709">DiĂ²cesi</translation>
<translation id="3901925938762663762">La targeta ha caducat</translation>
+<translation id="3910267023907260648">Has provat d'accedir a <ph name="DOMAIN" />, perĂ² el servidor ha presentat un certificat signat mitjançant un algoritme de signatura poc segur. AixĂ² indica que les credencials de seguretat que ha proporcionat el servidor es podrien haver falsificat i que Ă©s possible que el servidor no sigui el que esperaves (sinĂ³ un atacant). <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" /> perquè, suposadament, el seu certificat de seguretat tĂ© la data de demĂ . AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.}other{Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" /> perquè, suposadament, el seu certificat de seguretat tĂ© una data que Ă©s d'aquĂ­ a # dies. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">No es pot carregar el document en format PDF</translation>
<translation id="3963721102035795474">Mode de lector</translation>
+<translation id="397105322502079400">S’està calculant...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> estĂ  bloquejat</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{Hi ha 1 pĂ gina web a prop}other{Hi ha # pĂ gines web a prop}}</translation>
<translation id="4021036232240155012">DNS és el servei de xarxa que tradueix el nom d'un lloc web en l'adreça d'Internet corresponent.</translation>
<translation id="4030383055268325496">&amp;DesfĂ©s l'addiciĂ³</translation>
-<translation id="4032534284272647190">S'ha denegat l'accés a <ph name="URL" />.</translation>
<translation id="404928562651467259">ADVERTIMENT</translation>
<translation id="4058922952496707368">Tecla "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">El client i el servidor no admeten cap versiĂ³ de protocol SSL ni cap sistema de xifratge comuns.</translation>
<translation id="4079302484614802869">La configuraciĂ³ del servidor intermediari s'ha definit perquè utilitzi un URL d'script .pac, en lloc de servidors intermedis fixos.</translation>
<translation id="4103249731201008433">El nĂºmero de sèrie del dispositiu no Ă©s vĂ lid</translation>
<translation id="4103763322291513355">Visiteu &lt;strong&gt;chrome://policy&lt;/strong&gt; per veure la llista d'URL inclosos a la llista negra i altres polĂ­tiques aplicades per l'administrador del sistema.</translation>
+<translation id="4110615724604346410">Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" /> perquè el seu certificat de seguretat contĂ© errors. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">L'Ă mbit de la polĂ­tica no s'admet.</translation>
+<translation id="4118212371799607889">Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" />. Chromium no confia en el certificat de seguretat presentat. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 element més}other{# elements més}}</translation>
<translation id="4130226655945681476">Comproveu els cables de xarxa, el mĂ²dem i l'encaminador</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Voleu que Chromium desi aquesta targeta?</translation>
@@ -294,6 +310,7 @@
<translation id="4176463684765177261">Desactivat</translation>
<translation id="4196861286325780578">&amp;Refés el moviment</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Comproveu la configuraciĂ³ del tallafoc i de l'antivirus<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{cap}=1{1 aplicaciĂ³ ($1)}=2{2 aplicacions ($1, $2)}other{# aplicacions ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Errors</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Proveu d'executar el DiagnĂ²stic de xarxa<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">No</translation>
@@ -302,14 +319,15 @@
<translation id="4269787794583293679">(Sense nom d'usuari)</translation>
<translation id="4300246636397505754">Suggeriments per als responsables</translation>
<translation id="4304224509867189079">Accedeix</translation>
+<translation id="432290197980158659">El servidor ha presentat un certificat que no coincideix amb el que s'esperava. Aquestes expectatives es posen en prĂ ctica en determinats llocs web d'alta seguretat per protegir-te. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">No s'ha pogut trobar l'article</translation>
+<translation id="4331708818696583467">No segur</translation>
<translation id="4372948949327679948">Valor <ph name="VALUE_TYPE" /> esperat.</translation>
-<translation id="4377125064752653719">Heu provat d'accedir a <ph name="DOMAIN" />, perĂ² l'emissor ha revocat el certificat que ha presentat el servidor. AixĂ² vol dir que no heu de confiar gens en les credencials de seguretat que ha presentat el servidor. És possible que us estigueu comunicant amb un atacant.</translation>
<translation id="4381091992796011497">Nom d'usuari:</translation>
<translation id="4394049700291259645">Desactiva</translation>
<translation id="4395129973926795186">Del dia <ph name="START_DATE" /> al dia <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">resultats de la cerca</translation>
-<translation id="4424024547088906515">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè Chrome considera que el seu certificat de seguretat no Ă©s de confiança. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> no ha acceptat el certificat d'inici de sessiĂ³ o pot ser que no se n'hagi proporcionat cap.</translation>
<translation id="443673843213245140">L'Ăºs d'un servidor intermediari no estĂ  activat, perĂ² s'ha especificat una configuraciĂ³ explĂ­cita d'un servidor intermediari.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Veieu aquest missatge perquè el filtre Google SafeSites està activat.</translation>
@@ -321,12 +339,12 @@
<translation id="4522570452068850558">Detalls</translation>
<translation id="4558551763791394412">Desactiveu les extensions</translation>
<translation id="4587425331216688090">Voleu suprimir l'adreça de Chrome?</translation>
+<translation id="4589078953350245614">Has provat d'accedir a <ph name="DOMAIN" />, perĂ² el certificat que ha presentat el servidor no Ă©s vĂ lid. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">La connexiĂ³ a <ph name="DOMAIN" /> s'ha encriptat amb un sistema de xifratge modern.</translation>
<translation id="4594403342090139922">&amp;DesfĂ©s la supressiĂ³</translation>
+<translation id="4627442949885028695">Continua des d'un altre dispositiu</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Esteu consultant una pĂ gina d'extensions.</translation>
-<translation id="467662567472608290">El servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el seu certificat de seguretat contĂ© errors. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> s'ha bloquejat</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">La connexiĂ³ s'ha interromput</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Executar el DiagnĂ²stic de xarxa de Windows<ph name="END_LINK" /></translation>
@@ -334,21 +352,26 @@
<translation id="4728558894243024398">Plataforma</translation>
<translation id="4744603770635761495">CamĂ­ executable</translation>
<translation id="4756388243121344051">&amp;Historial</translation>
+<translation id="4759238208242260848">Baixades</translation>
<translation id="4764776831041365478">És possible que la pàgina web de <ph name="URL" /> estigui temporalment inactiva o que s'hagi desplaçat permanentment a una nova adreça web.</translation>
<translation id="4771973620359291008">S'ha produĂ¯t un error desconegut.</translation>
<translation id="4782449893814226250">S'ha enviat una sol·licitud als pares per visitar aquesta pàgina.</translation>
<translation id="4800132727771399293">Comproveu la data de caducitat i el CVC i torneu-ho a provar</translation>
-<translation id="4807049035289105102">En aquest moment no podeu visitar <ph name="SITE" /> perquè el lloc web ha enviat credencials aleatĂ²ries que Google Chrome no pot processar. Els errors i els atacs de xarxa solen ser temporals, de manera que Ă©s probable que aquesta pĂ gina torni a funcionar mĂ©s tard.</translation>
<translation id="4813512666221746211">Error de xarxa</translation>
<translation id="4816492930507672669">Ajusta a la mida de la pĂ gina</translation>
<translation id="4850886885716139402">VisualitzaciĂ³</translation>
<translation id="4880827082731008257">Cerca a l'historial</translation>
+<translation id="4884656795097055129">Es mostraran mĂ©s articles en el moment oportĂº.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{i 1 pàgina web més}other{i # pàgines web més}}</translation>
<translation id="4923417429809017348">Aquesta pĂ gina s'ha traduĂ¯t des d'un idioma desconegut a: <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">S'ha d'especificar.</translation>
<translation id="4930497775425430760">Veieu aquest missatge perquè els vostres pares han d'aprovar els llocs que visiteu per primera vegada.</translation>
<translation id="495170559598752135">Accions</translation>
<translation id="4958444002117714549">Desplega la llista</translation>
+<translation id="4962322354953122629">Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" />. Chrome no confia en el certificat de seguretat presentat. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Voleu traduir de <ph name="ORIGINAL_LANGUAGE" /> a <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Aquest connector no Ă©s compatible</translation>
<translation id="5002932099480077015">Si s'activa, Chrome emmagatzemarĂ  una cĂ²pia de la targeta en aquest dispositiu per agilitzar l'emplenament de formularis.</translation>
<translation id="5019198164206649151">L'emmagatzematge de la cĂ²pia de seguretat estĂ  en mal estat</translation>
<translation id="5023310440958281426">Consulteu les polĂ­tiques de l'administrador</translation>
@@ -356,13 +379,12 @@
<translation id="5031870354684148875">Sobre el Traductor de Google</translation>
<translation id="5040262127954254034">Privadesa</translation>
<translation id="5045550434625856497">Contrasenya incorrecta</translation>
+<translation id="5056549851600133418">Articles que us poden interessar</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Comproveu l'adreça del servidor intermediari<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">En aquest moment el certificat del servidor no Ă©s vĂ lid.</translation>
<translation id="5089810972385038852">Estat</translation>
-<translation id="5094747076828555589">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè Chromium considera que el seu certificat de seguretat no Ă©s de confiança. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³.</translation>
<translation id="5095208057601539847">ProvĂ­ncia</translation>
<translation id="5115563688576182185">(64 bits)</translation>
-<translation id="5122371513570456792">S'han trobat <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> per a "<ph name="SEARCH_STRING" />".</translation>
<translation id="5141240743006678641">Encripta contrasenyes sincronitzades amb les vostres credencials de Google</translation>
<translation id="5145883236150621069">Hi ha un codi d'error en la resposta a la polĂ­tica</translation>
<translation id="5171045022955879922">Cerqueu o escriviu l'URL</translation>
@@ -371,18 +393,18 @@
<translation id="5190835502935405962">Barra d'adreces d'interès</translation>
<translation id="5199729219167945352">Experiments</translation>
<translation id="5251803541071282808">NĂºvol</translation>
+<translation id="5277279256032773186">Fas servir Chrome a la feina? Les empreses poden gestionar la configuraciĂ³ de Chrome dels empleats. MĂ©s informaciĂ³</translation>
<translation id="5299298092464848405">S'ha produĂ¯t un error en analitzar la polĂ­tica</translation>
<translation id="5300589172476337783">Mostra</translation>
<translation id="5308689395849655368">La creaciĂ³ d'informes de bloqueig estĂ  desactivada.</translation>
<translation id="5317780077021120954">Desa</translation>
<translation id="5327248766486351172">Nom</translation>
+<translation id="5359637492792381994">Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" /> perquè el seu certificat de seguretat no Ă©s vĂ lid en aquest moment. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">No s'ha pogut emmagatzemar la configuraciĂ³ de la polĂ­tica</translation>
-<translation id="540969355065856584">Aquest servidor no ha pogut demostrar que sigui <ph name="DOMAIN" /> perquè el seu certificat de seguretat no Ă©s vĂ lid en aquest moment. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la connexiĂ³.</translation>
<translation id="5421136146218899937">Esborra les dades de navegaciĂ³...</translation>
<translation id="5430298929874300616">Suprimeix l'adreça d'interès</translation>
<translation id="5431657950005405462">No s'ha trobat el fitxer</translation>
<translation id="5435775191620395718">Es mostra l'historial d'aquest dispositiu. <ph name="BEGIN_LINK" />Obteniu mĂ©s informaciĂ³<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Actualment, els suggeriments de contingut personalitzats estan desactivats perquè les teves dades sincronitzades estan protegides per una frase de contrasenya personalitzada.</translation>
<translation id="5439770059721715174">Error de validaciĂ³ de l'esquema a "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">No s'ha trobat aquesta pĂ gina de <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">Marca de temps de la polĂ­tica incorrecta</translation>
@@ -405,14 +427,18 @@
<translation id="5622887735448669177">Voleu sortir d'aquest lloc?</translation>
<translation id="5629630648637658800">No s'ha pogut carregar la configuraciĂ³ de la polĂ­tica</translation>
<translation id="5631439013527180824">Testimoni de gestiĂ³ del dispositiu no vĂ lid</translation>
-<translation id="5650551054760837876">No s'han trobat resultats de cerca.</translation>
<translation id="5677928146339483299">Bloquejat</translation>
<translation id="5710435578057952990">La identitat d'aquest lloc web no ha estat verificada.</translation>
<translation id="5720705177508910913">Usuari actual</translation>
+<translation id="572328651809341494">Pestanyes recents</translation>
<translation id="5784606427469807560">S'ha produĂ¯t un problema en confirmar la targeta. Comprova la connexiĂ³ a Internet i torna-ho a provar.</translation>
<translation id="5785756445106461925">A mĂ©s, aquesta pĂ gina contĂ© altres recursos que no sĂ³n segurs. La resta d'usuaris poden visualitzar-los mentre estan en trĂ nsit, i algun atacant podria modificar-los per canviar l'aparença de la pĂ gina.</translation>
+<translation id="5786044859038896871">Vols emplenar la informaciĂ³ de la teva targeta?</translation>
+<translation id="5803412860119678065">Vols emplenar la informaciĂ³ de la teva targeta <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">La connexiĂ³ a <ph name="DOMAIN" /> s'ha encriptat amb un sistema de xifratge obsolet.</translation>
<translation id="5813119285467412249">&amp;RefĂ©s l'addiciĂ³</translation>
+<translation id="5814352347845180253">Pot ser que perdis l'accés al contingut prèmium de <ph name="SITE" /> i d'altres llocs.</translation>
+<translation id="5843436854350372569">Has provat d'accedir a <ph name="DOMAIN" />, perĂ² el servidor ha presentat un certificat que contĂ© una clau poc segura. És possible que un atacant hagi desencriptat la clau privada i que aquest servidor no sigui el que esperaves (sinĂ³ un atacant). <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Veieu aquest missatge perquè el gestor ha bloquejat aquest lloc.</translation>
<translation id="5857090052475505287">Carpeta nova</translation>
<translation id="5869405914158311789">No es pot accedir a aquest lloc</translation>
@@ -420,6 +446,7 @@
<translation id="5872918882028971132">Suggeriments per als responsables</translation>
<translation id="59107663811261420">Google Payments no admet aquest tipus de targeta per a aquest comerciant. Seleccioneu-ne una altra.</translation>
<translation id="59174027418879706">Activada</translation>
+<translation id="5926846154125914413">Pot ser que perdis l'accés al contingut prèmium d'alguns llocs.</translation>
<translation id="5966707198760109579">Setmana</translation>
<translation id="5967867314010545767">Elimina de l'historial</translation>
<translation id="5975083100439434680">Redueix</translation>
@@ -431,12 +458,12 @@
<translation id="604124094241169006">AutomĂ tic</translation>
<translation id="6042308850641462728">MĂ©s</translation>
<translation id="6060685159320643512">Compte! Aquests experiments mosseguen</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{cap}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Reviseu els cables i reinicieu els encaminadors, els mĂ²dems o altres
dispositius de xarxa que feu servir.</translation>
<translation id="614940544461990577">Proveu aquestes solucions:</translation>
<translation id="6150607114729249911">S'ha de demanar permĂ­s als pares per poder visitar aquesta pĂ gina.</translation>
<translation id="6151417162996330722">El perĂ­ode de validesa del certificat del servidor Ă©s massa gran.</translation>
-<translation id="6154808779448689242">El testimoni de la polĂ­tica que s'ha retornat no coincideix amb el testimoni actual</translation>
<translation id="6165508094623778733">MĂ©s informaciĂ³</translation>
<translation id="6203231073485539293">ComprovaciĂ³ de la connexiĂ³ a Internet</translation>
<translation id="6218753634732582820">Voleu suprimir l'adreça de Chromium?</translation>
@@ -449,24 +476,30 @@
<translation id="6328639280570009161">Proveu de desactivar la predicciĂ³ de xarxa</translation>
<translation id="6337534724793800597">Filtra les polĂ­tiques pel nom</translation>
<translation id="6342069812937806050">Ara mateix</translation>
+<translation id="6345221851280129312">mida desconeguda</translation>
<translation id="6355080345576803305">Substitueix en sessions pĂºbliques</translation>
<translation id="6358450015545214790">Què vol dir tot aixĂ²?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 suggeriment més}other{# suggeriments més}}</translation>
<translation id="6387478394221739770">Esteu interessat en les funcions de Chrome noves i interessants? Proveu el nostre canal beta a la pĂ gina chrome.com/beta.</translation>
-<translation id="641480858134062906">No s'ha pogut carregar <ph name="URL" /></translation>
+<translation id="6389758589412724634">Chromium s'ha quedat sense memĂ²ria en provar de mostrar aquesta pĂ gina web.</translation>
+<translation id="6416403317709441254">En aquest moment no pots visitar <ph name="SITE" /> perquè el lloc web ha enviat credencials aleatĂ²ries que Chromium no pot processar. Els errors i els atacs de xarxa solen ser temporals, de manera que Ă©s probable que aquesta pĂ gina torni a funcionar mĂ©s tard. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">No es pot comprovar si s'ha revocat el certificat.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> no ens ha permès establir la connexiĂ³.</translation>
<translation id="6445051938772793705">PaĂ­s</translation>
<translation id="6451458296329894277">Confirma el reenviament del formulari</translation>
<translation id="6458467102616083041">S'ha ignorat perquè la política ha desactivat la cerca predeterminada.</translation>
+<translation id="6462969404041126431">Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" />. És possible que el seu certificat de seguretat s'hagi revocat. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">PolĂ­tiques de dispositius</translation>
<translation id="6489534406876378309">Comença a penjar els errors</translation>
<translation id="6529602333819889595">&amp;RefĂ©s la supressiĂ³</translation>
+<translation id="6534179046333460208">Suggeriments del Web fĂ­sic</translation>
<translation id="6550675742724504774">Opcions</translation>
+<translation id="6593753688552673085">menys de: <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opcions d'encriptaciĂ³</translation>
<translation id="662080504995468778">No surtis</translation>
<translation id="6628463337424475685">Cerca de <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">En aquest moment no podeu visitar <ph name="SITE" /> perquè <ph name="BEGIN_LINK" />aquest certificat s'ha revocat<ph name="END_LINK" />. Els errors de la xarxa i els atacs solen ser temporals, de manera que és probable que aquesta pàgina torni a funcionar més tard.</translation>
<translation id="6644283850729428850">Aquesta polĂ­tica ha quedat obsoleta.</translation>
+<translation id="6652240803263749613">Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" />. El sistema operatiu del teu ordinador no confia en el certificat de seguretat presentat. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">EdiciĂ³ de la carpeta</translation>
<translation id="6660210980321319655">Data i hora del bloqueig notificat automĂ ticament: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Voleu suprimir el suggeriment de formulari de Chromium?</translation>
@@ -474,6 +507,7 @@
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Escriviu el terme de cerca&gt;</translation>
<translation id="6711464428925977395">Hi ha hagut algun problema amb el servidor intermediari o l'adreça no és correcta.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{cap}=1{1 element}other{# elements}}</translation>
<translation id="674375294223700098">Error de certificat del servidor desconegut.</translation>
<translation id="6753269504797312559">Valor de la polĂ­tica</translation>
<translation id="6757797048963528358">El dispositiu ha entrat en mode de repĂ²s.</translation>
@@ -485,7 +519,6 @@
<translation id="6891596781022320156">No s'admet el nivell de la polĂ­tica.</translation>
<translation id="6895330447102777224">La teva targeta s'ha confirmat</translation>
<translation id="6897140037006041989">Agent d'usuari</translation>
-<translation id="6903907808598579934">Activa la sincronitzaciĂ³</translation>
<translation id="6915804003454593391">Usuari:</translation>
<translation id="6957887021205513506">Sembla que el certificat del servidor Ă©s una falsificaciĂ³.</translation>
<translation id="6965382102122355670">D'acord</translation>
@@ -493,9 +526,11 @@
<translation id="6970216967273061347">Districte</translation>
<translation id="6973656660372572881">S'especifiquen tant els servidors intermediaris fixos com un URL d'script .pac.</translation>
<translation id="6989763994942163495">Mostra la configuraciĂ³ avançada...</translation>
+<translation id="7000990526846637657">No s'ha trobat cap entrada a l'historial</translation>
+<translation id="7009986207543992532">Has provat d'accedir a <ph name="DOMAIN" />, perĂ² el servidor ha presentat un certificat amb un perĂ­ode de validesa massa llarg per poder confiar-hi. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">És possible que el teu compte de Google tingui altres formes de l'historial de navegaciĂ³ a <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Contrasenyes</translation>
-<translation id="7050187094878475250">Heu provat de connectar-vos a <ph name="DOMAIN" />, perĂ² el servidor ha presentat un certificat amb un perĂ­ode de validesa massa gran per poder confiar-hi.</translation>
<translation id="7087282848513945231">Comptat</translation>
<translation id="7088615885725309056">MĂ©s antic</translation>
<translation id="7090678807593890770">Cerqueu <ph name="LINK" /> a Google</translation>
@@ -514,13 +549,13 @@
<translation id="7246609911581847514">Veieu aquest missatge perquè el gestor ha d'aprovar els llocs que visiteu per primera vegada.</translation>
<translation id="724975217298816891">Introdueix la data de caducitat i el CVC de la targeta <ph name="CREDIT_CARD" /> per actualitzar-ne els detalls. Un cop confirmada, els detalls de la targeta es compartiran amb aquest lloc.</translation>
<translation id="725866823122871198">No s'ha pogut establir una connexiĂ³ privada amb <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> perquè la data i l'hora (<ph name="DATE_AND_TIME" />) de l'ordinador no sĂ³n correctes.</translation>
-<translation id="7265986070661382626">En aquest moment no podeu visitar <ph name="SITE" /> perquè el lloc web <ph name="BEGIN_LINK" />fa servir una fixaciĂ³ de certificat<ph name="END_LINK" />. Els errors de la xarxa i els atacs solen ser temporals, de manera que Ă©s probable que aquesta pĂ gina torni a funcionar mĂ©s tard.</translation>
<translation id="7269802741830436641">Aquesta pĂ gina web tĂ© un bucle de redirecciĂ³</translation>
<translation id="7275334191706090484">Adreces d'interès gestionades</translation>
<translation id="7298195798382681320">Recomanada</translation>
-<translation id="7301833672208172928">Activa la sincronitzaciĂ³ de l'historial</translation>
+<translation id="7309308571273880165">S'ha capturat un informe d'error (<ph name="CRASH_TIME" />) (càrrega sol·licitada per l'usuari, encara no s'ha dut a terme)</translation>
<translation id="7334320624316649418">&amp;Refés el canvi d'ordre</translation>
<translation id="733923710415886693">El certificat del servidor no s'ha divulgat mitjançant la Transparència de certificats.</translation>
+<translation id="7351800657706554155">En aquest moment no pots visitar <ph name="SITE" /> perquè el seu certificat s'ha revocat. Els errors i els atacs de xarxa solen ser temporals, de manera que Ă©s probable que aquesta pĂ gina torni a funcionar mĂ©s tard. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">LĂ­nia d'ordres</translation>
<translation id="7372973238305370288">resultat de la cerca</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -539,16 +574,17 @@ El mode d'incĂ²gnit, <ph name="SHORTCUT_KEY" />, us pot resultar prĂ ctic la pro
<translation id="7469372306589899959">S'estĂ  confirmant la targeta</translation>
<translation id="7481312909269577407">Endavant</translation>
<translation id="7485870689360869515">No s'han trobat dades.</translation>
+<translation id="7508255263130623398">L'identificador de dispositiu de la polĂ­tica que s'ha tornat Ă©s buit o no coincideix amb l'actual</translation>
<translation id="7514365320538308">Baixa</translation>
<translation id="7518003948725431193">No s'ha trobat cap pàgina web per a l'adreça: <ph name="URL" /></translation>
<translation id="7537536606612762813">ObligatĂ²ria</translation>
<translation id="7542995811387359312">L'emplenament automĂ tic de targetes de crèdit estĂ  desactivat perquè el formulari no utilitza una connexiĂ³ segura.</translation>
<translation id="7549584377607005141">Aquesta pĂ gina web necessita dades que heu introduĂ¯t anteiorment per poder mostrar-la correctament. Podeu tornar a enviar les dades, perĂ² es tornarĂ  a repetir qualsevol acciĂ³ que la pĂ gina hagi dut a terme prèviament.</translation>
<translation id="7554791636758816595">Pestanya nova</translation>
-<translation id="7567204685887185387">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè Ă©s possible que el seu certificat de seguretat s'hagi emès de manera fraudulenta. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que intercepta la vostra connexiĂ³.</translation>
<translation id="7568593326407688803">Aquesta pĂ gina estĂ  en<ph name="ORIGINAL_LANGUAGE" />Voleu traduir-la?</translation>
<translation id="7569952961197462199">Voleu suprimir la targeta de crèdit de Chrome?</translation>
<translation id="7578104083680115302">Agilitzeu els pagaments en llocs i en aplicacions des de qualsevol dispositiu mitjançant les targetes que hàgiu desat a Google.</translation>
+<translation id="7588950540487816470">El Web fĂ­sic</translation>
<translation id="7592362899630581445">El certificat del servidor incompleix les restriccions de nom.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> no pot gestionar la sol·licitud en aquest moment.</translation>
<translation id="7600965453749440009">No tradueixis mai de: <ph name="LANGUAGE" /></translation>
@@ -559,6 +595,7 @@ El mode d'incĂ²gnit, <ph name="SHORTCUT_KEY" />, us pot resultar prĂ ctic la pro
<translation id="7637571805876720304">Voleu suprimir la targeta de crèdit de Chromium?</translation>
<translation id="765676359832457558">Amaga la configuraciĂ³ avançada...</translation>
<translation id="7658239707568436148">Cancel·la</translation>
+<translation id="7667346355482952095">El testimoni de la polĂ­tica que s'ha retornat Ă©s buit o no coincideix amb el testimoni actual</translation>
<translation id="7668654391829183341">Dispositiu desconegut</translation>
<translation id="7674629440242451245">Esteu interessat en les funcions de Chrome noves i interessants? Proveu el nostre canal per a desenvolupadors a la pĂ gina chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Continua per accedir a <ph name="SITE" /> (no segur)<ph name="END_LINK" /></translation>
@@ -575,10 +612,10 @@ El mode d'incĂ²gnit, <ph name="SHORTCUT_KEY" />, us pot resultar prĂ ctic la pro
<translation id="780301667611848630">No, grĂ cies</translation>
<translation id="7805768142964895445">Estat</translation>
<translation id="7813600968533626083">Voleu suprimir el suggeriment de formulari de Chrome?</translation>
+<translation id="7815407501681723534">S'han trobat <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> per a "<ph name="SEARCH_STRING" />"</translation>
<translation id="785549533363645510">Tanmateix, no sou invisible. La vostra empresa, el vostre proveĂ¯dor de serveis d'Internet i els llocs web que visiteu poden veure la vostra navegaciĂ³ d'incĂ²gnit.</translation>
<translation id="7887683347370398519">Comproveu el CVC i torneu-ho a provar</translation>
<translation id="7894616681410591072"><ph name="NAME" /> us ha de donar permĂ­s per accedir a aquesta pĂ gina.</translation>
-<translation id="790025292736025802">No s'ha trobat <ph name="URL" /></translation>
<translation id="7912024687060120840">A la carpeta:</translation>
<translation id="7920092496846849526">S'ha enviat una sol·licitud als pares per visitar aquesta pàgina.</translation>
<translation id="7935318582918952113">Destil·lador DOM</translation>
@@ -591,9 +628,10 @@ El mode d'incĂ²gnit, <ph name="SHORTCUT_KEY" />, us pot resultar prĂ ctic la pro
<translation id="7995512525968007366">No especificat</translation>
<translation id="8012647001091218357">En aquests moments no ens hem pogut posar en contacte amb els pares. Torneu-ho a provar.</translation>
<translation id="8034522405403831421">Aquesta pĂ gina estĂ  escrita en <ph name="SOURCE_LANGUAGE" />. Vols traduir-la a <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">No s'ha trobat cap entrada a l'historial.</translation>
<translation id="8088680233425245692">No s'ha pogut consultar l'article.</translation>
+<translation id="8089520772729574115">menys d'1 MB</translation>
<translation id="8091372947890762290">L'activaciĂ³ estĂ  pendent al servidor</translation>
+<translation id="8129262335948759431">quantitat desconeguda</translation>
<translation id="8131740175452115882">Confirma</translation>
<translation id="8134994873729925007">No s'ha trobat l'<ph name="BEGIN_ABBR" />adreça DNS<ph name="END_ABBR" /> del servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">L'ordinador ha entrat en mode de repĂ²s.</translation>
@@ -602,6 +640,7 @@ El mode d'incĂ²gnit, <ph name="SHORTCUT_KEY" />, us pot resultar prĂ ctic la pro
<translation id="8201077131113104583">L'URL d'actualitzaciĂ³ per a l'extensiĂ³ amb identificador "<ph name="EXTENSION_ID" />" no Ă©s vĂ lid.</translation>
<translation id="8218327578424803826">UbicaciĂ³ assignada:</translation>
<translation id="8225771182978767009">La persona que ha configurat l'ordinador ha bloquejat aquest lloc.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">La pĂ gina que busques utilitzava informaciĂ³ que vas introduir. Tornar a aquesta pĂ gina podria provocar una repeticiĂ³ de qualsevol acciĂ³ realitzada. Vols continuar?</translation>
<translation id="8249320324621329438">Ăltima obtenciĂ³:</translation>
<translation id="8261506727792406068">Suprimeix</translation>
@@ -614,12 +653,17 @@ El mode d'incĂ²gnit, <ph name="SHORTCUT_KEY" />, us pot resultar prĂ ctic la pro
<translation id="8349305172487531364">Barra d'adreces d'interès</translation>
<translation id="8363502534493474904">Desactiveu el mode d'aviĂ³</translation>
<translation id="8364627913115013041">No s'ha definit.</translation>
+<translation id="8380941800586852976">Perillosa</translation>
<translation id="8412145213513410671">Bloqueigs (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Heu d'introduir la mateixa frase de contrasenya dues vegades.</translation>
<translation id="8428213095426709021">ConfiguraciĂ³</translation>
+<translation id="8433057134996913067">Amb aquesta acciĂ³ es tancarĂ  la sessiĂ³ a la majoria de llocs web.</translation>
<translation id="8437238597147034694">&amp;Desfés el moviment</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 targeta de crèdit}other{# targetes de crèdit}}</translation>
+<translation id="8483780878231876732">Per poder utilitzar targetes del teu compte de Google, inicia la sessiĂ³ a Chrome</translation>
<translation id="8488350697529856933">Objectiu d'aplicaciĂ³</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ha tardat massa a respondre.</translation>
+<translation id="852346902619691059">Aquest servidor no ha pogut demostrar que Ă©s <ph name="DOMAIN" />. El sistema operatiu del teu dispositiu no confia en el certificat de seguretat presentat. AixĂ² pot ser a causa d'una configuraciĂ³ incorrecta o d'un atacant que ha interceptat la teva connexiĂ³. <ph name="BEGIN_LEARN_MORE_LINK" />ObtĂ©n mĂ©s informaciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Google Payments no admet aquest tipus de targeta. Seleccioneu-ne una altra.</translation>
<translation id="8550022383519221471">El servei de sincronitzaciĂ³ no estĂ  disponible per al vostre domini.</translation>
<translation id="8553075262323480129">S'ha produĂ¯t un error en fer la traducciĂ³ perquè no s'ha pogut determinar l'idioma de la pĂ gina.</translation>
@@ -631,15 +675,12 @@ El mode d'incĂ²gnit, <ph name="SHORTCUT_KEY" />, us pot resultar prĂ ctic la pro
<translation id="8647750283161643317">Restableix-ho tot als valors predeterminats</translation>
<translation id="8680787084697685621">Les dades d'inici de sessiĂ³ del compte no estan actualitzades.</translation>
<translation id="8703575177326907206">La teva connexiĂ³ a <ph name="DOMAIN" /> no estĂ  xifrada.</translation>
-<translation id="8713130696108419660">Signatura inicial incorrecta</translation>
<translation id="8725066075913043281">Torna-ho a provar</translation>
<translation id="8728672262656704056">Heu passat al mode d'incĂ²gnit.</translation>
<translation id="8730621377337864115">Fet</translation>
<translation id="8738058698779197622">Per establir una connexiĂ³ segura, el rellotge ha d'estar ben ajustat, perquè els certificats que els llocs web fan servir per identificar-se nomĂ©s sĂ³n vĂ lids per a perĂ­odes de temps concrets. Com que el rellotge del dispositiu no estĂ  ben ajustat, Chromium no pot verificar aquests certificats.</translation>
<translation id="8740359287975076522">No s'ha trobat l'&lt;abbr id="dnsDefinition"&gt;adreça DNS&lt;/abbr&gt; de <ph name="HOST_NAME" />. S'està diagnosticant el problema.</translation>
-<translation id="8741995161408053644">És possible que el vostre compte de Google tingui altres formes de l'historial de navegaciĂ³ a <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;RefĂ©s la supressiĂ³</translation>
-<translation id="8790687370365610530">Activa la sincronitzaciĂ³ de l'historial perquè Google et suggereixi contingut personalitzat.</translation>
<translation id="8798099450830957504">Predeterminat</translation>
<translation id="8804164990146287819">PolĂ­tica de privadesa</translation>
<translation id="8820817407110198400">Adreces d'interès</translation>
@@ -661,13 +702,11 @@ El mode d'incĂ²gnit, <ph name="SHORTCUT_KEY" />, us pot resultar prĂ ctic la pro
<translation id="8971063699422889582">El certificat del servidor ha caducat.</translation>
<translation id="8987927404178983737">Mes</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">El servidor ha presentat un certificat que no s'ha divulgat pĂºblicament mitjançant la polĂ­tica Transparència de certificats. AixĂ² Ă©s un requisit d'alguns certificats per garantir que sĂ³n de confiança i una mesura de protecciĂ³ contra els atacants.</translation>
<translation id="9001074447101275817">El servidor intermediari del domini <ph name="DOMAIN" /> requereix un nom d'usuari i una contrasenya.</translation>
<translation id="901974403500617787">Les marques que s'apliquen a tot el sistema només les pot definir l'usuari: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Aquesta pĂ gina s'ha traduĂ¯t a <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Utilitza un servei de predicciĂ³ per poder carregar les pĂ gines mĂ©s rĂ pidament</translation>
<translation id="9039213469156557790">A mĂ©s, aquesta pĂ gina contĂ© altres recursos que no sĂ³n segurs. La resta d'usuaris poden visualitzar-los mentre estan en trĂ nsit, i algun atacant podria modificar-los per canviar el comportament de la pĂ gina.</translation>
-<translation id="9049981332609050619">Heu provat d'accedir a <ph name="DOMAIN" />, perĂ² el servidor ha presentat un certificat no vĂ lid.</translation>
<translation id="9050666287014529139">Frase de contrasenya</translation>
<translation id="9065203028668620118">Edita</translation>
<translation id="9092364396508701805">La pĂ gina de <ph name="HOST_NAME" /> no funciona</translation>
diff --git a/chromium/components/strings/components_strings_cs.xtb b/chromium/components/strings/components_strings_cs.xtb
index df8ed6d45c0..20b4a38b2ed 100644
--- a/chromium/components/strings/components_strings_cs.xtb
+++ b/chromium/components/strings/components_strings_cs.xtb
@@ -1,21 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="cs">
+<translation id="1008557486741366299">NynĂ­ ne</translation>
<translation id="1015730422737071372">Zadejte dalÅ¡Ă­ podrobnosti</translation>
<translation id="1032854598605920125">OtoÄit ve smÄ›ru hodinovĂ½ch ruÄiÄek</translation>
<translation id="1038842779957582377">neznĂ¡mĂ© jmĂ©no</translation>
+<translation id="1053591932240354961">Web <ph name="SITE" /> nynĂ­ nemůžete navÅ¡tĂ­vit, protože webovĂ© strĂ¡nky odeslaly zakĂ³dovanĂ© identifikaÄnĂ­ Ăºdaje, kterĂ© Chrome nedokĂ¡Å¾e zpracovat. SĂ­Å¥ovĂ© chyby aÂ Ăºtoky jsou obvykle doÄasnĂ©, tato strĂ¡nka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">&amp;VrĂ¡tit pÅ™idĂ¡nĂ­ zpÄ›t</translation>
<translation id="10614374240317010">Nikdy se neuklĂ¡dajĂ­</translation>
-<translation id="1064422015032085147">Server hostujĂ­cĂ­ webovou strĂ¡nku je pravdÄ›podobnÄ› pÅ™etĂ­Å¾en nebo probĂ­hĂ¡ jeho Ăºdržba. Aby bylo zabrĂ¡nÄ›no generovĂ¡nĂ­ nadmÄ›rnĂ©ho provozu, kterĂ½ by situaci dĂ¡le zhorÅ¡il, jsou požadavky na tuto adresu URL doÄasnÄ› zakĂ¡zĂ¡ny.</translation>
<translation id="106701514854093668">ZĂ¡ložky v PC</translation>
<translation id="1080116354587839789">PÅ™izpůsobit na Å¡Ă­Å™ku</translation>
+<translation id="1103124106085518534">ProzatĂ­m hotovo</translation>
<translation id="1103523840287552314">Vždy pÅ™eklĂ¡dat jazyk <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Pokud je tato možnost zaÅ¡krtnuta, Chrome v tomto zaÅ™Ă­zenĂ­ bude za ĂºÄelem rychlejÅ¡Ă­ho vyplňovĂ¡nĂ­ formulĂ¡Å™Å¯ uchovĂ¡vat kopii vaÅ¡Ă­ karty.</translation>
+<translation id="1111153019813902504">NejnovÄ›jÅ¡Ă­ zĂ¡ložky</translation>
<translation id="1113869188872983271">&amp;VrĂ¡tit zmÄ›nu uspoÅ™Ă¡dĂ¡nĂ­ zpÄ›t</translation>
+<translation id="1126551341858583091">Velikost mĂ­stnĂ­ho ĂºložiÅ¡tÄ› je <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Mezipaměť zĂ¡sady je v poÅ™Ă¡dku</translation>
<translation id="113188000913989374">Web <ph name="SITE" /> Å™Ă­kĂ¡:</translation>
<translation id="1132774398110320017">NastavenĂ­ AutomatickĂ©ho vyplňovĂ¡nĂ­ v prohlĂ­Å¾eÄi Chrome...</translation>
-<translation id="1150979032973867961">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. OperaÄnĂ­ systĂ©m vaÅ¡eho poÄĂ­taÄe nedůvěřuje jeho bezpeÄnostnĂ­mu certifikĂ¡tu.Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.</translation>
<translation id="1152921474424827756">OtevÅ™ete <ph name="BEGIN_LINK" />archivovanou kopii<ph name="END_LINK" /> strĂ¡nky <ph name="URL" /></translation>
<translation id="1158211211994409885">Web <ph name="HOST_NAME" /> neoÄekĂ¡vanÄ› ukonÄil pÅ™ipojenĂ­.</translation>
<translation id="1161325031994447685">Obnovit pÅ™ipojenĂ­ k sĂ­ti Wi-Fi</translation>
@@ -23,7 +26,8 @@
<translation id="1181037720776840403">Odebrat</translation>
<translation id="1201402288615127009">DalÅ¡Ă­</translation>
<translation id="1201895884277373915">VĂ­ce z tohoto webu</translation>
-<translation id="121201262018556460">Pokusili jste se pÅ™ejĂ­t na web <ph name="DOMAIN" />, server vÅ¡ak pÅ™edložil certifikĂ¡t obsahujĂ­cĂ­ slabĂ½ klĂ­Ä. ĂtoÄnĂ­k možnĂ¡ prolomil soukromĂ½ klĂ­Ä a může se jednat o jinĂ½ server, než pÅ™edpoklĂ¡dĂ¡te (můžete komunikovat s ĂºtoÄnĂ­kem).</translation>
+<translation id="1206967143813997005">ChybnĂ½ poÄĂ¡teÄnĂ­ podpis</translation>
+<translation id="1209206284964581585">ProzatĂ­m skrĂ½t</translation>
<translation id="1219129156119358924">ZabezpeÄenĂ­ systĂ©mu</translation>
<translation id="1227224963052638717">NeznĂ¡mĂ¡ zĂ¡sada.</translation>
<translation id="1227633850867390598">SkrĂ½t hodnotu</translation>
@@ -44,6 +48,7 @@
<translation id="1426410128494586442">Ano</translation>
<translation id="1430915738399379752">Tisk</translation>
<translation id="1442912890475371290">Byl zablokovĂ¡n pokus <ph name="BEGIN_LINK" /> navÅ¡tĂ­vit strĂ¡nku v domĂ©nÄ› <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Web <ph name="SITE" /> nynĂ­ nemůžete navÅ¡tĂ­vit, protože pouÅ¾Ă­vĂ¡ pÅ™ipĂ­nĂ¡nĂ­ certifikĂ¡tů. SĂ­Å¥ovĂ© chyby aÂ Ăºtoky jsou obvykle doÄasnĂ©, tato strĂ¡nka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">ZobrazĂ­ uloženou (tj. neaktuĂ¡lnĂ­) kopii tĂ©to strĂ¡nky</translation>
<translation id="1519264250979466059">Datum sestavenĂ­</translation>
<translation id="1549470594296187301">Chcete-li tuto funkci pouÅ¾Ă­t, musĂ­ bĂ½t aktivovĂ¡n JavaScript.</translation>
@@ -58,36 +63,34 @@
<translation id="1644184664548287040">Konfigurace sĂ­tÄ› je neplatnĂ¡ a nelze ji importovat.</translation>
<translation id="1644574205037202324">Historie</translation>
<translation id="1645368109819982629">NepodporovanĂ½ protokol</translation>
-<translation id="1655462015569774233">{1,plural, =1{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Platnost jeho bezpeÄnostnĂ­ho certifikĂ¡tu vÄera vyprÅ¡ela. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. Hodiny ve vaÅ¡em poÄĂ­taÄi jsou aktuĂ¡lnÄ› nastaveny na <ph name="CURRENT_DATE" />. Je to sprĂ¡vnÄ›? Pokud ne, mÄ›li byste nastavit sprĂ¡vnĂ© hodiny systĂ©mu a potĂ© tuto strĂ¡nku naÄĂ­st znovu.}few{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Platnost jeho bezpeÄnostnĂ­ho certifikĂ¡tu vyprÅ¡ela pÅ™ed # dny. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. Hodiny ve vaÅ¡em poÄĂ­taÄi jsou aktuĂ¡lnÄ› nastaveny na <ph name="CURRENT_DATE" />. Je to sprĂ¡vnÄ›? Pokud ne, mÄ›li byste Äas v poÄĂ­taÄi opravit a potĂ© tuto strĂ¡nku naÄĂ­st znovu.}many{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Platnost jeho bezpeÄnostnĂ­ho certifikĂ¡tu vyprÅ¡ela pÅ™ed # dnem. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. Hodiny ve vaÅ¡em poÄĂ­taÄi jsou aktuĂ¡lnÄ› nastaveny na <ph name="CURRENT_DATE" />. Je to sprĂ¡vnÄ›? Pokud ne, mÄ›li byste nastavit sprĂ¡vnĂ© hodiny systĂ©mu a potĂ© tuto strĂ¡nku naÄĂ­st znovu.}other{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Platnost jeho bezpeÄnostnĂ­ho certifikĂ¡tu vyprÅ¡ela pÅ™ed # dny. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. Hodiny ve vaÅ¡em poÄĂ­taÄi jsou aktuĂ¡lnÄ› nastaveny na <ph name="CURRENT_DATE" />. Je to sprĂ¡vnÄ›? Pokud ne, mÄ›li byste nastavit sprĂ¡vnĂ© hodiny systĂ©mu a potĂ© tuto strĂ¡nku naÄĂ­st znovu.}}</translation>
<translation id="1676269943528358898">Web <ph name="SITE" /> vaÅ¡e informace běžnÄ› chrĂ¡nĂ­ Å¡ifrovĂ¡nĂ­m. Když se prohlĂ­Å¾eÄ Chrome k webu <ph name="SITE" /> pokusil pÅ™ipojit tentokrĂ¡t, web vrĂ¡til neobvyklĂ© a nesprĂ¡vnĂ© identifikaÄnĂ­ Ăºdaje. K tomuto problĂ©mu může dojĂ­t, pokud se za web <ph name="SITE" /> pokouÅ¡Ă­ vydĂ¡vat nÄ›jakĂ½ ĂºtoÄnĂ­k nebo pokud bylo pÅ™ipojenĂ­ pÅ™eruÅ¡eno pÅ™ihlaÅ¡ovacĂ­ obrazovkou sĂ­tÄ› Wi-Fi. VaÅ¡e informace jsou i nadĂ¡le v bezpeÄĂ­, protože prohlĂ­Å¾eÄ Google Chrome pÅ™ipojenĂ­ pÅ™eruÅ¡il dÅ™Ă­ve, než doÅ¡lo k odeslĂ¡nĂ­ jakĂ½chkoliv dat.</translation>
<translation id="168841957122794586">CertifikĂ¡t serveru obsahuje slabĂ½ kryptografickĂ½ klĂ­Ä.</translation>
<translation id="1701955595840307032">ZĂ­skejte nĂ¡vrhy obsahu</translation>
-<translation id="1706954506755087368">{1,plural, =1{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. UvedenĂ© datum vystavenĂ­ jeho bezpeÄnostnĂ­ho certifikĂ¡tu je zĂ­tra. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.}few{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. UvedenĂ© datum vystavenĂ­ jeho bezpeÄnostnĂ­ho certifikĂ¡tu je až za # dny. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.}many{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. UvedenĂ© datum vystavenĂ­ jeho bezpeÄnostnĂ­ho certifikĂ¡tu je až za # dne. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.}other{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. UvedenĂ© datum vystavenĂ­ jeho bezpeÄnostnĂ­ho certifikĂ¡tu je až za # dnĂ­. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.}}</translation>
<translation id="1710259589646384581">OperaÄnĂ­ systĂ©m</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Zkuste kontaktovat administrĂ¡tora systĂ©mu.</translation>
<translation id="17513872634828108">OtevÅ™enĂ© karty</translation>
<translation id="1753706481035618306">ÄŒĂ­slo strĂ¡nky</translation>
-<translation id="1761412452051366565">Chcete-li od Googlu zĂ­skat personalizovanĂ© nĂ¡vrhy obsahu, zapnÄ›te synchronizaci.</translation>
-<translation id="1763864636252898013">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. OperaÄnĂ­ systĂ©m vaÅ¡eho zaÅ™Ă­zenĂ­ nedůvěřuje jeho bezpeÄnostnĂ­mu certifikĂ¡tu. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Zkuste spustit Diagnostiku sítě systému Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Aktualizujte prosĂ­m heslovou frĂ¡zi pro synchronizaci.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Zde se zobrazĂ­ nedĂ¡vno navÅ¡tĂ­venĂ© zĂ¡ložky.</translation>
<translation id="1821930232296380041">NeplatnĂ½ požadavek nebo parametry požadavku</translation>
<translation id="1838667051080421715">Zobrazuje se vĂ¡m zdrojovĂ½ kĂ³d webovĂ© strĂ¡nky.</translation>
<translation id="1871208020102129563">Proxy je nastaveno na pouÅ¾Ă­vĂ¡nĂ­ pevnÄ› danĂ½ch serverů proxy, nikoliv adresy URL skriptu PAC.</translation>
<translation id="1883255238294161206">Sbalit seznam</translation>
<translation id="1898423065542865115">FiltrovĂ¡nĂ­</translation>
-<translation id="1911837502049945214">Web <ph name="HOST_NAME" /> nepÅ™ijal pÅ™ihlaÅ¡ovacĂ­ certifikĂ¡t. Je možnĂ©, že platnost certifikĂ¡tu vyprÅ¡ela.</translation>
<translation id="194030505837763158">PÅ™ejĂ­t na odkaz <ph name="LINK" /></translation>
<translation id="1962204205936693436">ZĂ¡ložky domĂ©ny <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Chyba serializace</translation>
<translation id="1974060860693918893">RozÅ¡Ă­Å™enĂ¡ nastavenĂ­</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{a 1 dalÅ¡Ă­}few{a # dalÅ¡Ă­}many{a # dalÅ¡Ă­}other{a # dalÅ¡Ă­ch}}</translation>
<translation id="2025186561304664664">Proxy server je nastaven na automatickou konfiguraci.</translation>
<translation id="2030481566774242610">Měli jste na mysli <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Tato zprĂ¡va se zobrazila, protože je potÅ™eba, aby pÅ™i prvnĂ­ nĂ¡vÅ¡tÄ›vÄ› novĂ©ho webu povolili pÅ™Ă­stup rodiÄe.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Zkontrolovat proxy server a firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">PSČ</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 nĂ¡vrh}few{# nĂ¡vrhy}many{# nĂ¡vrhu}other{# nĂ¡vrhů}}</translation>
<translation id="2065985942032347596">Vyžaduje se ověřenĂ­</translation>
<translation id="2079545284768500474">Zpět</translation>
<translation id="20817612488360358">Jako aktivnĂ­ jsou nakonfigurovĂ¡na systĂ©movĂ¡ nastavenĂ­ proxy serveru, je vÅ¡ak urÄena i explicitnĂ­ konfigurace proxy serveru.</translation>
@@ -103,32 +106,34 @@
<translation id="2149973817440762519">Upravit zĂ¡ložku</translation>
<translation id="2166049586286450108">ĂplnĂ½ pÅ™Ă­stup administrĂ¡tora</translation>
<translation id="2166378884831602661">Tento web nemůže poskytnout zabezpeÄenĂ© pÅ™ipojenĂ­</translation>
-<translation id="2171101176734966184">Pokusili jste se pÅ™ejĂ­t na web <ph name="DOMAIN" />, server vÅ¡ak pÅ™edložil certifikĂ¡t podepsanĂ½ slabĂ½m algoritmem. To znamenĂ¡, že bezpeÄnostnĂ­ pověřenĂ­ pÅ™edloženĂ¡ serverem mohou bĂ½t faleÅ¡nĂ¡ a může se jednat o ĂºplnÄ› jinĂ½ server, než pÅ™edpoklĂ¡dĂ¡te (můžete komunikovat s ĂºtoÄnĂ­kem).</translation>
<translation id="2181821976797666341">ZĂ¡sady</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}few{# adresy}many{# adresy}other{# adres}}</translation>
<translation id="2212735316055980242">ZĂ¡sada nebyla nalezena</translation>
<translation id="2213606439339815911">NaÄĂ­tĂ¡nĂ­ zĂ¡znamů...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> nenĂ­ dostupnĂ¡</translation>
<translation id="2230458221926704099">Opravte pÅ™ipojenĂ­ pomocĂ­ <ph name="BEGIN_LINK" />diagnostickĂ© aplikace<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Odeslat</translation>
<translation id="225207911366869382">Tato hodnota již pro tuto zĂ¡sadu nenĂ­ podporovĂ¡na.</translation>
<translation id="2262243747453050782">Chyba protokolu HTTP</translation>
<translation id="2282872951544483773">Nedostupné experimenty</translation>
<translation id="2292556288342944218">VaÅ¡e pÅ™ipojenĂ­ k internetu je blokovĂ¡no</translation>
<translation id="229702904922032456">Platnost koÅ™enovĂ©ho nebo zprostÅ™edkujĂ­cĂ­ho certifikĂ¡tu vyprÅ¡ela.</translation>
<translation id="230155334948463882">NovĂ¡ karta?</translation>
+<translation id="2305919008529760154">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Je možnĂ©, že jeho bezpeÄnostnĂ­ certifikĂ¡t byl vydĂ¡n podvodnÄ›. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535">DomĂ©na <ph name="DOMAIN" /> vyžaduje zadĂ¡nĂ­ uživatelskĂ©ho jmĂ©na a hesla.</translation>
+<translation id="2318774815570432836">Web <ph name="SITE" /> nynĂ­ nemůžete navÅ¡tĂ­vit, protože pouÅ¾Ă­vĂ¡ zabezpeÄenĂ­ HSTS. SĂ­Å¥ovĂ© chyby aÂ Ăºtoky jsou obvykle doÄasnĂ©, tato strĂ¡nka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">Byla ignorovĂ¡na neplatnĂ¡ zĂ¡ložka u indexu <ph name="ENTRY_INDEX" />.</translation>
<translation id="2354001756790975382">OstatnĂ­ zĂ¡ložky</translation>
<translation id="2359808026110333948">PokraÄovat</translation>
<translation id="2365563543831475020">ZprĂ¡va o selhĂ¡nĂ­ poÅ™Ă­zenĂ¡ <ph name="CRASH_TIME" /> nebyla nahrĂ¡na</translation>
<translation id="2367567093518048410">Ăroveň</translation>
+<translation id="2371153335857947666">{1,plural, =1{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Platnost jeho bezpeÄnostnĂ­ho certifikĂ¡tu vÄera vyprÅ¡ela. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. Hodiny ve vaÅ¡em poÄĂ­taÄi jsou aktuĂ¡lnÄ› nastaveny na <ph name="CURRENT_DATE" />. Je to sprĂ¡vnÄ›? Pokud ne, mÄ›li byste hodiny systĂ©mu nastavit sprĂ¡vnÄ› a potĂ© tuto strĂ¡nku naÄĂ­st znovu. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" />}few{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Platnost jeho bezpeÄnostnĂ­ho certifikĂ¡tu vyprÅ¡ela pÅ™ed # dny. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. Hodiny ve vaÅ¡em poÄĂ­taÄi jsou aktuĂ¡lnÄ› nastaveny na <ph name="CURRENT_DATE" />. Je to sprĂ¡vnÄ›? Pokud ne, mÄ›li byste hodiny systĂ©mu nastavit sprĂ¡vnÄ› a potĂ© tuto strĂ¡nku naÄĂ­st znovu. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" />}many{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Platnost jeho bezpeÄnostnĂ­ho certifikĂ¡tu vyprÅ¡ela pÅ™ed # dne. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. Hodiny ve vaÅ¡em poÄĂ­taÄi jsou aktuĂ¡lnÄ› nastaveny na <ph name="CURRENT_DATE" />. Je to sprĂ¡vnÄ›? Pokud ne, mÄ›li byste hodiny systĂ©mu nastavit sprĂ¡vnÄ› a potĂ© tuto strĂ¡nku naÄĂ­st znovu. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" />}other{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Platnost jeho bezpeÄnostnĂ­ho certifikĂ¡tu vyprÅ¡ela pÅ™ed # dny. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. Hodiny ve vaÅ¡em poÄĂ­taÄi jsou aktuĂ¡lnÄ› nastaveny na <ph name="CURRENT_DATE" />. Je to sprĂ¡vnÄ›? Pokud ne, mÄ›li byste hodiny systĂ©mu nastavit sprĂ¡vnÄ› a potĂ© tuto strĂ¡nku naÄĂ­st znovu. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">Å½Ă¡dnĂ© alternativy uživatelskĂ©ho rozhranĂ­ nejsou k dispozici</translation>
<translation id="2384307209577226199">VĂ½chozĂ­ podnikovĂ© nastavenĂ­</translation>
-<translation id="238526402387145295">Web <ph name="SITE" /> nynĂ­ nemůžete navÅ¡tĂ­vit, protože <ph name="BEGIN_LINK" />pouÅ¾Ă­vĂ¡ zabezpeÄenĂ­ HSTS<ph name="END_LINK" />. SĂ­Å¥ovĂ© chyby a Ăºtoky jsou obvykle doÄasnĂ©, tato strĂ¡nka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat.</translation>
<translation id="2386255080630008482">CertifikĂ¡t serveru byl zamĂ­tnut.</translation>
<translation id="2392959068659972793">Zobrazit zĂ¡sady bez nastavenĂ½ch hodnot</translation>
<translation id="2396249848217231973">&amp;VrĂ¡tit smazĂ¡nĂ­ zpÄ›t</translation>
-<translation id="2413528052993050574">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Jeho bezpeÄnostnĂ­ certifikĂ¡t byl zÅ™ejmÄ› zruÅ¡en. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.</translation>
<translation id="2455981314101692989">U tohoto formulĂ¡Å™e je na danĂ© webovĂ© strĂ¡nce vypnuto automatickĂ© vyplňovĂ¡nĂ­.</translation>
+<translation id="2463739503403862330">Vyplnit</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Spustit Diagnostiku sĂ­tÄ›<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">NeplatnĂ¡ adresa URL vyhledĂ¡vĂ¡nĂ­.</translation>
<translation id="2491120439723279231">CertifikĂ¡t serveru obsahuje chyby.</translation>
@@ -150,10 +155,12 @@
<translation id="2653659639078652383">Odeslat</translation>
<translation id="2674170444375937751">Jste si jisti, že chcete tyto strĂ¡nky odstranit ze svĂ© historie?</translation>
<translation id="2677748264148917807">OdejĂ­t</translation>
+<translation id="269990154133806163">Server pÅ™edložil certifikĂ¡t, kterĂ½ nebyl zveÅ™ejnÄ›n v souladu se zĂ¡sadou Certificate Transparency. U nÄ›kterĂ½ch certifikĂ¡tů je to z důvodu kontroly důvÄ›ryhodnosti a ochrany pÅ™ed ĂºtoÄnĂ­ky vyžadovĂ¡no. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">Hodnota neodpovĂ­dĂ¡ formĂ¡tu.</translation>
<translation id="2704951214193499422">ProhlĂ­Å¾eÄ Chromium vaÅ¡i kartu aktuĂ¡lnÄ› nemohl ověřit. Zkuste to prosĂ­m znovu pozdÄ›ji.</translation>
<translation id="2705137772291741111">Kopii tohoto webu uloženou v mezipamÄ›ti se nepodaÅ™ilo pÅ™eÄĂ­st.</translation>
<translation id="2709516037105925701">AutomatickĂ© vyplňovĂ¡nĂ­</translation>
+<translation id="2712118517637785082">Pokusili jste se pÅ™ejĂ­t na web <ph name="DOMAIN" />, ale certifikĂ¡t pÅ™edloženĂ½ tĂ­mto webem byl vydavatelem zruÅ¡en. To znamenĂ¡, že bezpeÄnostnĂ­m pověřenĂ­m, kterĂ¡ web pÅ™edložil, nelze vůbec důvěřovat. Je možnĂ©, že komunikujete sÂ ĂºtoÄnĂ­kem. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">PoÅ¾Ă¡dat o oprĂ¡vnÄ›nĂ­</translation>
<translation id="2721148159707890343">Požadavek byl ĂºspěšnĂ½</translation>
<translation id="2728127805433021124">CertifikĂ¡t serveru je podepsĂ¡n slabĂ½m algoritmem.</translation>
@@ -165,14 +172,11 @@
<translation id="2824775600643448204">AdresnĂ­ a vyhledĂ¡vacĂ­ Å™Ă¡dek</translation>
<translation id="2826760142808435982">PÅ™ipojenĂ­ je Å¡ifrovĂ¡no a ověřeno pomocĂ­ Å¡ifry <ph name="CIPHER" /> a jako mechanismus vĂ½mÄ›ny klĂ­Äů pouÅ¾Ă­vĂ¡ <ph name="KX" />.</translation>
<translation id="2835170189407361413">Vymazat formulĂ¡Å™</translation>
-<translation id="2837049386027881519">Pokus o pÅ™ipojenĂ­ musel probÄ›hnout znovu pomocĂ­ starÅ¡Ă­ verze protokolu TLS nebo SSL. Obvykle to znamenĂ¡, že server pouÅ¾Ă­vĂ¡ zastaralĂ½ software a může mĂ­t dalÅ¡Ă­ problĂ©my se zabezpeÄenĂ­m.</translation>
<translation id="284702764277384724">ZdĂ¡ se, že certifikĂ¡t serveru webu <ph name="HOST_NAME" /> je podvrh.</translation>
<translation id="2889159643044928134">NenaÄĂ­tat znovu</translation>
-<translation id="2896499918916051536">Tento plugin nenĂ­ podporovĂ¡n.</translation>
+<translation id="2900469785430194048">ProhlĂ­Å¾eÄ Google Chrome k zobrazenĂ­ tĂ©to webovĂ© strĂ¡nky nemÄ›l dostatek pamÄ›ti.</translation>
<translation id="2909946352844186028">Byla zjiÅ¡tÄ›na zmÄ›na sĂ­tÄ›.</translation>
-<translation id="2915500479781995473">Tento server nemohl prokĂ¡zat, že patÅ™Ă­ do domĂ©ny <ph name="DOMAIN" />. Platnost jeho bezpeÄnostnĂ­ho certifikĂ¡tu vyprÅ¡ela. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. Hodiny ve vaÅ¡em poÄĂ­taÄi jsou aktuĂ¡lnÄ› nastaveny na <ph name="CURRENT_TIME" />. Je to sprĂ¡vnÄ›? Pokud ne, mÄ›li byste Äas v poÄĂ­taÄi opravit a potĂ© tuto strĂ¡nku naÄĂ­st znovu.</translation>
<translation id="2922350208395188000">CertifikĂ¡t serveru nelze zkontrolovat.</translation>
-<translation id="2941952326391522266">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Jeho bezpeÄnostnĂ­ certifikĂ¡t pochĂ¡zĂ­ z domĂ©ny <ph name="DOMAIN2" />. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.</translation>
<translation id="2948083400971632585">LibovolnĂ© servery proxy nakonfigurovanĂ© pro pÅ™ipojenĂ­ můžete zakĂ¡zat na strĂ¡nce NastavenĂ­.</translation>
<translation id="2955913368246107853">ZavÅ™Ă­t vyhledĂ¡vacĂ­ liÅ¡tu</translation>
<translation id="2958431318199492670">Konfigurace sĂ­tÄ› nesplňuje standard ONC. Může se stĂ¡t, že nÄ›kterĂ© ÄĂ¡sti konfigurace nebudou importovĂ¡ny.</translation>
@@ -186,6 +190,7 @@
<translation id="3024663005179499861">ChybnĂ½ typ zĂ¡sady</translation>
<translation id="3032412215588512954">Chcete tento web naÄĂ­st znovu?</translation>
<translation id="3037605927509011580">Aj, chyba!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{alespoň jedna položka v synchronizovanĂ½ch zaÅ™Ă­zenĂ­ch}=1{1 položka (a dalÅ¡Ă­ v synchronizovanĂ½ch zaÅ™Ă­zenĂ­ch)}few{# položky (a dalÅ¡Ă­ v synchronizovanĂ½ch zaÅ™Ă­zenĂ­ch)}many{# položky (a dalÅ¡Ă­ v synchronizovanĂ½ch zaÅ™Ă­zenĂ­ch)}other{# položek (a dalÅ¡Ă­ v synchronizovanĂ½ch zaÅ™Ă­zenĂ­ch)}}</translation>
<translation id="3041612393474885105">Informace o certifikĂ¡tu</translation>
<translation id="3063697135517575841">Chrome vaÅ¡i kartu aktuĂ¡lnÄ› nemohl ověřit. Zkuste to prosĂ­m znovu pozdÄ›ji.</translation>
<translation id="3093245981617870298">Nejste pÅ™ipojeni k sĂ­ti.</translation>
@@ -201,15 +206,16 @@
<translation id="3176929007561373547">Zkontrolujte nastavenĂ­ proxy serveru nebo se obraÅ¥te na sprĂ¡vce sĂ­tÄ›, aby ověřil, zda proxy server funguje. Pokud se domnĂ­vĂ¡te, že by proxy server nemÄ›l bĂ½t pouÅ¾Ă­vĂ¡n: <ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">NejnovÄ›jÅ¡Ă­</translation>
<translation id="3207960819495026254">PÅ™idĂ¡no do zĂ¡ložek</translation>
-<translation id="3225919329040284222">Server se prokĂ¡zal certifikĂ¡tem, kterĂ½ neodpovĂ­dĂ¡ integrovanĂ½m oÄekĂ¡vĂ¡nĂ­m. Tato oÄekĂ¡vanĂ­ jsou zahrnuta u urÄitĂ½ch webovĂ½ch strĂ¡nek s vysokou ĂºrovnĂ­ zabezpeÄenĂ­ kvůli vaÅ¡Ă­ ochranÄ›.</translation>
<translation id="3226128629678568754">KliknÄ›te na tlaÄĂ­tko NaÄĂ­st znovu. TĂ­m znovu odeÅ¡lete Ăºdaje potÅ™ebnĂ© k naÄtenĂ­ strĂ¡nky.</translation>
<translation id="3228969707346345236">PÅ™eklad se nezdaÅ™il. StrĂ¡nka je již v jazyce <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Zadejte kĂ³d CVC karty <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">PÅ™idat strĂ¡nku do zĂ¡ložek</translation>
<translation id="3270847123878663523">&amp;VrĂ¡tit zmÄ›nu uspoÅ™Ă¡dĂ¡nĂ­ zpÄ›t</translation>
<translation id="3286538390144397061">Restartovat</translation>
+<translation id="3303855915957856445">Nebyly nalezeny Å¾Ă¡dnĂ© vĂ½sledky</translation>
<translation id="3305707030755673451">VaÅ¡e data byla <ph name="TIME" /> zaÅ¡ifrovĂ¡na pomocĂ­ heslovĂ© frĂ¡ze pro synchronizaci. Chcete-li zahĂ¡jit synchronizaci, zadejte ji.</translation>
<translation id="333371639341676808">BrĂ¡nit tĂ©to strĂ¡nce ve vytvĂ¡Å™enĂ­ dalÅ¡Ă­ch dialogovĂ½ch oken.</translation>
+<translation id="3338095232262050444">ZabezpeÄeno</translation>
<translation id="3340978935015468852">nastavenĂ­</translation>
<translation id="3345135638360864351">OdeslĂ¡nĂ­ Å¾Ă¡dosti o pÅ™Ă­stup k tomuto webu uživateli <ph name="NAME" /> se nezdaÅ™ilo. Zkuste to prosĂ­m znovu.</translation>
<translation id="3355823806454867987">Změna nastavení proxy...</translation>
@@ -227,6 +233,7 @@
<translation id="3452404311384756672">Interval naÄtenĂ­:</translation>
<translation id="3462200631372590220">SkrĂ½t rozÅ¡Ă­Å™enĂ©</translation>
<translation id="3479539252931486093">Nebylo toto oÄekĂ¡vĂ¡no? <ph name="BEGIN_LINK" />Informujte nĂ¡s<ph name="END_LINK" />.</translation>
+<translation id="3479552764303398839">NynĂ­ ne</translation>
<translation id="348000606199325318">ID selhĂ¡nĂ­ <ph name="CRASH_LOCAL_ID" /> (ID serveru: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">V tuto chvĂ­li se nĂ¡m s vaÅ¡Ă­m rodiÄem nepodaÅ™ilo spojit. Zkuste to prosĂ­m znovu.</translation>
<translation id="3527085408025491307">Složka</translation>
@@ -235,6 +242,7 @@
<translation id="3542684924769048008">PouÅ¾Ă­t heslo pro:</translation>
<translation id="3549644494707163724">Å ifrovat synchronizovanĂ¡ data pomocĂ­ vlastnĂ­ heslovĂ© frĂ¡ze pro synchronizaci.</translation>
<translation id="3549761410225185768">Ještě <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Jeho bezpeÄnostnĂ­ certifikĂ¡t pochĂ¡zĂ­ z domĂ©ny <ph name="DOMAIN2" />. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">VaÅ¡e pÅ™ipojenĂ­ nenĂ­ soukromĂ©</translation>
<translation id="3583757800736429874">&amp;Opakovat pÅ™esunutĂ­</translation>
<translation id="3586931643579894722">SkrĂ½t podrobnosti</translation>
@@ -245,12 +253,15 @@
<translation id="362276910939193118">Zobrazit celou historii</translation>
<translation id="3623476034248543066">Zobrazit hodnotu</translation>
<translation id="3630155396527302611">Pokud je program v seznamu programů s oprĂ¡vnÄ›nĂ­m pÅ™istupovat k sĂ­ti již uveden, zkuste jej ze seznamu odebrat a znovu pÅ™idat.</translation>
+<translation id="3638794133396384728">Tento server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ do domĂ©ny <ph name="DOMAIN" />. Platnost jeho bezpeÄnostnĂ­ho certifikĂ¡tu vyprÅ¡ela. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. Hodiny ve vaÅ¡em poÄĂ­taÄi jsou aktuĂ¡lnÄ› nastaveny na <ph name="CURRENT_TIME" />. Je to sprĂ¡vnÄ›? Pokud ne, mÄ›li byste hodiny systĂ©mu nastavit sprĂ¡vnÄ› a potĂ© tuto strĂ¡nku naÄĂ­st znovu. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">Tyto experimentĂ¡lnĂ­ funkce se mohou kdykoli zmÄ›nit, zhroutit nebo zmizet. Nemůžeme vůbec zaruÄit, co se po zapnutĂ­ tÄ›chto experimentů stane. ProhlĂ­Å¾eÄ může napÅ™Ă­klad samovolnÄ› vybouchnout. Ale bez legrace: ProhlĂ­Å¾eÄ může smazat veÅ¡kerĂ© vaÅ¡e Ăºdaje nebo neoÄekĂ¡vanĂ½mi způsoby naruÅ¡it vaÅ¡e zabezpeÄenĂ­ Äi soukromĂ­. Experimenty, kterĂ© zapnete, budou k dispozici vÅ¡em uživatelům prohlĂ­Å¾eÄe. BuÄte prosĂ­m obezÅ™etnĂ­.</translation>
<translation id="3650584904733503804">OvěřenĂ­ probÄ›hlo ĂºspěšnÄ›</translation>
<translation id="3655670868607891010">Pokud se vĂ¡m tato strĂ¡nka zobrazuje Äasto, zkuste vyuÅ¾Ă­t tyto <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Verze</translation>
+<translation id="3678029195006412963">Požadavek nebylo možnĂ© podepsat</translation>
<translation id="3681007416295224113">Informace o certifikĂ¡tu</translation>
<translation id="3693415264595406141">Heslo:</translation>
+<translation id="3696411085566228381">Å¾Ă¡dnĂ©</translation>
<translation id="3700528541715530410">Jejda, zdĂ¡ se, že k pÅ™Ă­stupu na tuto strĂ¡nku nemĂ¡te oprĂ¡vnÄ›nĂ­.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">NaÄĂ­tĂ¡nĂ­...</translation>
@@ -258,7 +269,6 @@
<translation id="3714780639079136834">Zapnout mobilnĂ­ datovĂ© pÅ™ipojenĂ­ nebo Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Zkontrolovat proxy server, firewall a konfiguraci DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">ZkopĂ­rovanĂ½ odkaz</translation>
-<translation id="3744899669254331632">Web <ph name="SITE" /> nynĂ­ nelze navÅ¡tĂ­vit, protože tento web odeslal nesprĂ¡vnĂ© identifikaÄnĂ­ Ăºdaje, kterĂ© prohlĂ­Å¾eÄ Chromium nedokĂ¡Å¾e zpracovat. SĂ­Å¥ovĂ© chyby a Ăºtoky jsou obvykle doÄasnĂ©, tato strĂ¡nka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat.</translation>
<translation id="375403751935624634">Z důvodu chyby serveru se překlad nezdařil.</translation>
<translation id="3759461132968374835">NemĂ¡te Å¾Ă¡dnĂ¡ nedĂ¡vno hlĂ¡Å¡enĂ¡ selhĂ¡nĂ­. SelhĂ¡nĂ­, ke kterĂ½m doÅ¡lo, když byla služba hlĂ¡Å¡enĂ­ o selhĂ¡nĂ­ch vypnutĂ¡, se zde nezobrazujĂ­.</translation>
<translation id="3788090790273268753">CertifikĂ¡t tÄ›chto webovĂ½ch strĂ¡nek vyprÅ¡Ă­ v roce 2016 a řetÄ›zec certifikĂ¡tů obsahuje certifikĂ¡t podepsanĂ½ pomocĂ­ technologie SHA-1.</translation>
@@ -270,19 +280,25 @@
<translation id="3884278016824448484">KonfliktnĂ­ identifikĂ¡tor zaÅ™Ă­zenĂ­</translation>
<translation id="3885155851504623709">Okrsek</translation>
<translation id="3901925938762663762">Karta vypršela</translation>
+<translation id="3910267023907260648">Pokusili jste se pÅ™ejĂ­t na web <ph name="DOMAIN" />, server vÅ¡ak pÅ™edložil certifikĂ¡t podepsanĂ½ slabĂ½m algoritmem. To znamenĂ¡, že bezpeÄnostnĂ­ pověřenĂ­ pÅ™edloženĂ¡ serverem mohou bĂ½t faleÅ¡nĂ¡ a může se jednat oÂ ĂºplnÄ› jinĂ½ server, než pÅ™edpoklĂ¡dĂ¡te (můžete komunikovat sÂ ĂºtoÄnĂ­kem). <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. UvedenĂ© datum vystavenĂ­ jeho bezpeÄnostnĂ­ho certifikĂ¡tu je zĂ­tra. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" />}few{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. UvedenĂ© datum vystavenĂ­ jeho bezpeÄnostnĂ­ho certifikĂ¡tu je až za # dny. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" />}many{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. UvedenĂ© datum vystavenĂ­ jeho bezpeÄnostnĂ­ho certifikĂ¡tu je až za # dne. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" />}other{Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. UvedenĂ© datum vystavenĂ­ jeho bezpeÄnostnĂ­ho certifikĂ¡tu je až za # dnĂ­. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">NaÄĂ­tĂ¡nĂ­ dokumentu PDF se nezdaÅ™ilo.</translation>
<translation id="3963721102035795474">Režim ÄteÄky</translation>
+<translation id="397105322502079400">ProbĂ­hĂ¡ vĂ½poÄet…</translation>
<translation id="3973234410852337861">Web <ph name="HOST_NAME" /> je blokovĂ¡n</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 webovĂ¡ strĂ¡nka v okolĂ­}few{# webovĂ© strĂ¡nky v okolĂ­}many{# webovĂ© strĂ¡nky v okolĂ­}other{# webovĂ½ch strĂ¡nek v okolĂ­}}</translation>
<translation id="4021036232240155012">DNS je sĂ­Å¥ovĂ¡ služba, kterĂ¡ pÅ™eklĂ¡dĂ¡ nĂ¡zvy webů na internetovĂ© adresy.</translation>
<translation id="4030383055268325496">&amp;VrĂ¡tit pÅ™idĂ¡nĂ­ zpÄ›t</translation>
-<translation id="4032534284272647190">PÅ™Ă­stup na adresu <ph name="URL" /> odepÅ™en.</translation>
<translation id="404928562651467259">UPOZORNÄNĂ</translation>
<translation id="4058922952496707368">KlĂ­Ä <ph name="SUBKEY" />: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Klient a server nepodporujĂ­ spoleÄnou verzi protokolu SSL nebo Å¡ifrovacĂ­ sadu.</translation>
<translation id="4079302484614802869">Proxy je nastaveno na pouÅ¾Ă­vĂ¡nĂ­ adresy URL skriptu PAC, nikoliv pevnÄ› danĂ½ch serverů proxy.</translation>
<translation id="4103249731201008433">SĂ©riovĂ© ÄĂ­slo zaÅ™Ă­zenĂ­ je neplatnĂ©</translation>
<translation id="4103763322291513355">Na strĂ¡nce &lt;strong&gt;chrome://policy&lt;/strong&gt; naleznete seznam zakĂ¡zanĂ½ch adres URL a dalÅ¡Ă­ zĂ¡sady vynucenĂ© vaÅ¡Ă­m sprĂ¡vcem systĂ©mu.</translation>
+<translation id="4110615724604346410">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />, protože jeho bezpeÄnostnĂ­ certifikĂ¡t obsahuje chyby. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">Rozsah zĂ¡sady nenĂ­ podporovĂ¡n.</translation>
+<translation id="4118212371799607889">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Chromium jeho bezpeÄnostnĂ­mu certifikĂ¡tu nedůvěřuje. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 dalÅ¡Ă­}few{# dalÅ¡Ă­}many{# dalÅ¡Ă­}other{# dalÅ¡Ă­ch}}</translation>
<translation id="4130226655945681476">Zkontrolovat sĂ­Å¥ovĂ© kabely, modem a smÄ›rovaÄ</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chcete, aby prohlĂ­Å¾eÄ Chromium tuto kartu uložil?</translation>
@@ -290,6 +306,7 @@
<translation id="4176463684765177261">DeaktivovĂ¡no</translation>
<translation id="4196861286325780578">&amp;Opakovat pÅ™esunutĂ­</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Zkontrolovat konfiguraci firewallu a antivirového softwaru<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{Å¾Ă¡dnĂ¡ aplikace}=1{1 aplikace ($1)}=2{2 aplikace ($1, $2)}few{# aplikace ($1, $2 $3)}many{# aplikace ($1, $2 $3)}other{# aplikacĂ­ ($1, $2 $3)}}</translation>
<translation id="4220128509585149162">SelhĂ¡nĂ­</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Zkuste spustit Diagnostiku sĂ­tÄ›<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Ne</translation>
@@ -298,14 +315,15 @@
<translation id="4269787794583293679">(Å½Ă¡dnĂ© uživatelskĂ© jmĂ©no)</translation>
<translation id="4300246636397505754">NĂ¡vrhy rodiÄů</translation>
<translation id="4304224509867189079">PÅ™ihlĂ¡sit se</translation>
+<translation id="432290197980158659">Server se prokĂ¡zal certifikĂ¡tem, kterĂ½ neodpovĂ­dĂ¡ integrovanĂ½m oÄekĂ¡vĂ¡nĂ­m. Tato oÄekĂ¡vanĂ­ jsou zahrnuta u urÄitĂ½ch webovĂ½ch strĂ¡nek s vysokou ĂºrovnĂ­ zabezpeÄenĂ­ kvůli vaÅ¡Ă­ ochranÄ›. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">ÄŒlĂ¡nek nebyl nalezen</translation>
+<translation id="4331708818696583467">NezabezpeÄeno</translation>
<translation id="4372948949327679948">OÄekĂ¡vĂ¡na hodnota <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">Pokusili jste se pÅ™ejĂ­t na web <ph name="DOMAIN" />, ale certifikĂ¡t prezentovanĂ½ tĂ­mto webem byl vydavatelem certifikĂ¡tu zruÅ¡en. To znamenĂ¡, že bezpeÄnostnĂ­m pověřenĂ­m, kterĂ¡ web prezentoval, nelze zcela důvěřovat. Je možnĂ©, že komunikujete s ĂºtoÄnĂ­kem.</translation>
<translation id="4381091992796011497">JmĂ©no uživatele:</translation>
<translation id="4394049700291259645">Deaktivovat</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> – <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">vĂ½sledky vyhledĂ¡vĂ¡nĂ­</translation>
-<translation id="4424024547088906515">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Chrome jeho bezpeÄnostnĂ­mu certifikĂ¡tu nedůvěřuje. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.</translation>
+<translation id="4432688616882109544">Web <ph name="HOST_NAME" /> nepÅ™ijal pÅ™ihlaÅ¡ovacĂ­ certifikĂ¡t, pÅ™Ă­padnÄ› Å¾Ă¡dnĂ½ certifikĂ¡t nebyl poskytnut.</translation>
<translation id="443673843213245140">VyužitĂ­ proxy serveru je zakĂ¡zĂ¡no, je vÅ¡ak urÄena explicitnĂ­ konfigurace proxy serveru.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Tato zprĂ¡va se zobrazila, protože je aktivnĂ­ filtrovĂ¡nĂ­ SafeSites od Googlu.</translation>
@@ -317,12 +335,12 @@
<translation id="4522570452068850558">Podrobnosti</translation>
<translation id="4558551763791394412">Zkuste zakĂ¡zat rozÅ¡Ă­Å™enĂ­.</translation>
<translation id="4587425331216688090">Odstranit adresu z Chromu?</translation>
+<translation id="4589078953350245614">Pokusili jste se pÅ™ejĂ­t do domĂ©ny <ph name="DOMAIN" />, ale server pÅ™edložil neplatnĂ½ certifikĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459">VaÅ¡e pÅ™ipojenĂ­ k domĂ©nÄ› <ph name="DOMAIN" /> je Å¡ifrovĂ¡no za použitĂ­ modernĂ­ Å¡ifrovacĂ­ sady.</translation>
<translation id="4594403342090139922">&amp;VrĂ¡tit smazĂ¡nĂ­ zpÄ›t</translation>
+<translation id="4627442949885028695">PokraÄovat z jinĂ©ho zaÅ™Ă­zenĂ­</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">ProhlĂ­Å¾Ă­te si strĂ¡nku rozÅ¡Ă­Å™enĂ­.</translation>
-<translation id="467662567472608290">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />, protože jeho bezpeÄnostnĂ­ certifikĂ¡t obsahuje chyby. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.</translation>
-<translation id="4697214168136963651">Adresa <ph name="URL" /> byla blokovĂ¡na</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">PÅ™ipojenĂ­ bylo pÅ™eruÅ¡eno</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Spustit Diagnostiku sítě systému Windows<ph name="END_LINK" /></translation>
@@ -330,21 +348,26 @@
<translation id="4728558894243024398">Platforma</translation>
<translation id="4744603770635761495">SpustitelnĂ¡ cesta</translation>
<translation id="4756388243121344051">Historie</translation>
+<translation id="4759238208242260848">StaženĂ© soubory</translation>
<translation id="4764776831041365478">WebovĂ© strĂ¡nky na adrese <ph name="URL" /> jsou možnĂ¡ doÄasnÄ› nedostupnĂ© nebo mohly bĂ½t pÅ™emĂ­stÄ›ny na novou webovou adresu.</translation>
<translation id="4771973620359291008">DoÅ¡lo k neznĂ¡mĂ© chybÄ›.</translation>
<translation id="4782449893814226250">PoÅ¾Ă¡dali jste rodiÄe o povolenĂ­ nĂ¡vÅ¡tÄ›vy tĂ©to strĂ¡nky.</translation>
<translation id="4800132727771399293">Zkontrolujte datum vyprÅ¡enĂ­ platnosti a kĂ³d CVC a zkuste to znovu.</translation>
-<translation id="4807049035289105102">Web <ph name="SITE" /> nynĂ­ nemůžete navÅ¡tĂ­vit, protože webovĂ© strĂ¡nky odeslaly zakĂ³dovanĂ© identifikaÄnĂ­ Ăºdaje, kterĂ© Chrome nedokĂ¡Å¾e zpracovat. SĂ­Å¥ovĂ© chyby aÂ Ăºtoky jsou obvykle doÄasnĂ©, tato strĂ¡nka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat.</translation>
<translation id="4813512666221746211">Chyba sĂ­tÄ›</translation>
<translation id="4816492930507672669">PÅ™izpůsobit na strĂ¡nku</translation>
<translation id="4850886885716139402">Zobrazit</translation>
<translation id="4880827082731008257">Hledat v historii</translation>
+<translation id="4884656795097055129">Ve sprĂ¡vnou chvĂ­li se zobrazĂ­ dalÅ¡Ă­ ÄlĂ¡nky.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{a 1 dalÅ¡Ă­ webovĂ¡ strĂ¡nka}few{a # dalÅ¡Ă­ webovĂ© strĂ¡nky}many{a # dalÅ¡Ă­ webovĂ© strĂ¡nky}other{a # dalÅ¡Ă­ch webovĂ½ch strĂ¡nek}}</translation>
<translation id="4923417429809017348">Tato strĂ¡nka byla pÅ™eložena z neznĂ¡mĂ©ho jazyka do jazyka <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">MusĂ­ bĂ½t uvedeno</translation>
<translation id="4930497775425430760">Tato zprĂ¡va se zobrazila, protože je potÅ™eba, aby pÅ™i prvnĂ­ nĂ¡vÅ¡tÄ›vÄ› novĂ©ho webu povolil pÅ™Ă­stup rodiÄ.</translation>
<translation id="495170559598752135">Akce</translation>
<translation id="4958444002117714549">Rozbalit seznam</translation>
+<translation id="4962322354953122629">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Chrome jeho bezpeÄnostnĂ­mu certifikĂ¡tu nedůvěřuje. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911">Přeložit z jazyka <ph name="ORIGINAL_LANGUAGE" /> do jazyka <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Tento plugin nenĂ­ podporovĂ¡n</translation>
<translation id="5002932099480077015">Pokud je tato možnost aktivovĂ¡na, Chrome do zaÅ™Ă­zenĂ­ uloÅ¾Ă­ kopii karty za ĂºÄelem rychlejÅ¡Ă­ho vyplňovĂ¡nĂ­ formulĂ¡Å™Å¯.</translation>
<translation id="5019198164206649151">ZĂ¡ložnĂ­ ĂºložiÅ¡tÄ› je ve Å¡patnĂ©m stavu</translation>
<translation id="5023310440958281426">Zkontrolujte zĂ¡sady svĂ©ho sprĂ¡vce</translation>
@@ -352,13 +375,12 @@
<translation id="5031870354684148875">O PÅ™ekladaÄi Google</translation>
<translation id="5040262127954254034">Ochrana soukromĂ­</translation>
<translation id="5045550434625856497">NesprĂ¡vnĂ© heslo</translation>
+<translation id="5056549851600133418">ÄŒlĂ¡nky pro vĂ¡s</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Zkontrolovat adresu proxy serveru<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">CertifikĂ¡t serveru v tuto chvĂ­li nenĂ­ platnĂ½.</translation>
<translation id="5089810972385038852">StĂ¡t/kraj</translation>
-<translation id="5094747076828555589">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Chromium jeho bezpeÄnostnĂ­mu certifikĂ¡tu nedůvěřuje. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.</translation>
<translation id="5095208057601539847">Provincie</translation>
<translation id="5115563688576182185">(64bitovĂ½)</translation>
-<translation id="5122371513570456792">NalezenĂ© <ph name="NUMBER_OF_RESULTS" /> pro dotaz â€<ph name="SEARCH_STRING" />“: <ph name="SEARCH_RESULTS" /></translation>
<translation id="5141240743006678641">Å ifrovat synchronizovanĂ¡ hesla pomocĂ­ hesla k ĂºÄtu Google</translation>
<translation id="5145883236150621069">OdpovÄ›Ä zĂ¡sady obsahuje kĂ³d chyby</translation>
<translation id="5171045022955879922">VyhledĂ¡vejte Äi zadejte URL</translation>
@@ -367,18 +389,18 @@
<translation id="5190835502935405962">LiÅ¡ta zĂ¡ložek</translation>
<translation id="5199729219167945352">Experimenty</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">PouÅ¾Ă­vĂ¡te Chrome v prĂ¡ci? Firmy mohou spravovat nastavenĂ­ prohlĂ­Å¾eÄe Chrome pro svĂ© zamÄ›stnance. DalÅ¡Ă­ informace</translation>
<translation id="5299298092464848405">PÅ™i analĂ½ze zĂ¡sady doÅ¡lo k chybÄ›</translation>
<translation id="5300589172476337783">Zobrazit</translation>
<translation id="5308689395849655368">ZprĂ¡vy o selhĂ¡nĂ­ jsou zakĂ¡zĂ¡ny.</translation>
<translation id="5317780077021120954">Uložit</translation>
<translation id="5327248766486351172">NĂ¡zev</translation>
+<translation id="5359637492792381994">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Jeho bezpeÄnostnĂ­ certifikĂ¡t v tuto chvĂ­li nenĂ­ platnĂ½. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">UklĂ¡dĂ¡nĂ­ nastavenĂ­ zĂ¡sady se nezdaÅ™ilo</translation>
-<translation id="540969355065856584">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Jeho bezpeÄnostnĂ­ certifikĂ¡t v tuto chvĂ­li nenĂ­ platnĂ½. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.</translation>
<translation id="5421136146218899937">Vymazat Ăºdaje o prohlĂ­Å¾enĂ­...</translation>
<translation id="5430298929874300616">Odstranit zĂ¡ložku</translation>
<translation id="5431657950005405462">Soubor nebyl nalezen</translation>
<translation id="5435775191620395718">Zobrazuje se historie z tohoto zaÅ™Ă­zenĂ­. <ph name="BEGIN_LINK" />DalÅ¡Ă­ informace<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">PersonalizovanĂ© nĂ¡vrhy obsahu jsou aktuĂ¡lnÄ› vypnuty, protože jsou vaÅ¡e synchronizovanĂ¡ data chrĂ¡nÄ›na vlastnĂ­ heslovou frĂ¡zĂ­.</translation>
<translation id="5439770059721715174">Chyba validace schématu v místě <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Tuto strĂ¡nku na webu <ph name="HOST_NAME" /> nelze najĂ­t</translation>
<translation id="5455374756549232013">ChybnĂ© ÄasovĂ© razĂ­tko zĂ¡sady</translation>
@@ -401,14 +423,18 @@ Kontaktujte administrĂ¡tora systĂ©mu.</translation>
<translation id="5622887735448669177">Chcete tento web opustit?</translation>
<translation id="5629630648637658800">NaÄĂ­tĂ¡nĂ­ nastavenĂ­ zĂ¡sady se nezdaÅ™ilo</translation>
<translation id="5631439013527180824">NeplatnĂ½ token sprĂ¡vy zaÅ™Ă­zenĂ­</translation>
-<translation id="5650551054760837876">Nebyly nalezeny Å¾Ă¡dnĂ© vĂ½sledky vyhledĂ¡vĂ¡nĂ­.</translation>
<translation id="5677928146339483299">ZablokovĂ¡no</translation>
<translation id="5710435578057952990">Identita tÄ›chto webovĂ½ch strĂ¡nek nebyla ověřena.</translation>
<translation id="5720705177508910913">AktuĂ¡lnĂ­ uživatel</translation>
+<translation id="572328651809341494">NedĂ¡vno použitĂ© karty</translation>
<translation id="5784606427469807560">PÅ™i ověřovĂ¡nĂ­ vaÅ¡Ă­ karty doÅ¡lo k problĂ©mu. Zkontrolujte pÅ™ipojenĂ­ k internetu a zkuste to znovu.</translation>
<translation id="5785756445106461925">Tato strĂ¡nka obsahuje jeÅ¡tÄ› dalÅ¡Ă­ nezabezpeÄenĂ© zdroje. Tyto zdroje budou bÄ›hem pÅ™enosu moci zobrazit jinĂ­ uživatelĂ© a pÅ™Ă­padnĂ­ ĂºtoÄnĂ­ci je mohou upravit a zmÄ›nit tak vzhled strĂ¡nky.</translation>
+<translation id="5786044859038896871">Chcete vyplnit informace o kartě?</translation>
+<translation id="5803412860119678065">Chcete vyplnit informace o kartě <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">VaÅ¡e pÅ™ipojenĂ­ k domĂ©nÄ› <ph name="DOMAIN" /> je Å¡ifrovĂ¡no za použitĂ­ zastaralĂ© Å¡ifrovacĂ­ sady.</translation>
<translation id="5813119285467412249">&amp;Opakovat pÅ™idĂ¡nĂ­</translation>
+<translation id="5814352347845180253">Můžete ztratit pÅ™Ă­stup k prĂ©miovĂ©mu obsahu z webu <ph name="SITE" /> a nÄ›kterĂ½ch dalÅ¡Ă­ch webů.</translation>
+<translation id="5843436854350372569">Pokusili jste se pÅ™ejĂ­t do domĂ©ny <ph name="DOMAIN" />, ale server pÅ™edložil certifikĂ¡t se slabĂ½m klĂ­Äem. Je možnĂ©, že se ĂºtoÄnĂ­kovi podaÅ™ilo soukromĂ½ klĂ­Ä prolomit a že se jednĂ¡ o jinĂ½ server, než pÅ™edpoklĂ¡dĂ¡te (můžete komunikovat sÂ ĂºtoÄnĂ­kem). <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">Tato zprĂ¡va se zobrazila, protože sprĂ¡vce k tomuto webu zablokoval pÅ™Ă­stup.</translation>
<translation id="5857090052475505287">NovĂ¡ složka</translation>
<translation id="5869405914158311789">Tento web nenĂ­ dostupnĂ½</translation>
@@ -416,6 +442,7 @@ Kontaktujte administrĂ¡tora systĂ©mu.</translation>
<translation id="5872918882028971132">NĂ¡vrhy rodiÄů</translation>
<translation id="59107663811261420">Tento typ karty ve službÄ› Google Payments u tohoto obchodnĂ­ka nenĂ­ podporovĂ¡n. Vyberte prosĂ­m jinou kartu.</translation>
<translation id="59174027418879706">AktivnĂ­</translation>
+<translation id="5926846154125914413">Můžete ztratit pÅ™Ă­stup k prĂ©miovĂ©mu obsahu z nÄ›kterĂ½ch webů.</translation>
<translation id="5966707198760109579">TĂ½den</translation>
<translation id="5967867314010545767">Odstranit z historie</translation>
<translation id="5975083100439434680">OddĂ¡lit</translation>
@@ -427,11 +454,11 @@ Kontaktujte administrĂ¡tora systĂ©mu.</translation>
<translation id="604124094241169006">Automaticky</translation>
<translation id="6042308850641462728">VĂ­ce</translation>
<translation id="6060685159320643512">Pozor, tyto experimenty mohou skonÄit vÅ¡elijak.</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{Å¾Ă¡dnĂ¡ aplikace}=1{1}few{#}many{#}other{#}}</translation>
<translation id="6146055958333702838">Zkontrolujte vÅ¡echny kabely a restartujte vÅ¡echny smÄ›rovaÄe, modemy a dalÅ¡Ă­ sĂ­Å¥ovĂ¡ zaÅ™Ă­zenĂ­, kterĂ¡ pouÅ¾Ă­vĂ¡te.</translation>
<translation id="614940544461990577">Zkuste:</translation>
<translation id="6150607114729249911">Jejda! K nĂ¡vÅ¡tÄ›vÄ› tĂ©to strĂ¡nky potÅ™ebujete souhlas rodiÄů.</translation>
<translation id="6151417162996330722">CertifikĂ¡t serveru mĂ¡ pÅ™Ă­liÅ¡ dlouhĂ© obdobĂ­ platnosti.</translation>
-<translation id="6154808779448689242">VrĂ¡cenĂ½ token zĂ¡sad neodpovĂ­dĂ¡ aktuĂ¡lnĂ­mu tokenu</translation>
<translation id="6165508094623778733">DalÅ¡Ă­Â informace</translation>
<translation id="6203231073485539293">Zkontrolujte pÅ™ipojenĂ­ k internetu</translation>
<translation id="6218753634732582820">Odstranit adresu z prohlĂ­Å¾eÄe Chromium?</translation>
@@ -444,24 +471,30 @@ Kontaktujte administrĂ¡tora systĂ©mu.</translation>
<translation id="6328639280570009161">Zkuste deaktivovat pÅ™edvĂ­dĂ¡nĂ­ akcĂ­ sĂ­tÄ›</translation>
<translation id="6337534724793800597">Filtrovat zĂ¡sady podle nĂ¡zvu</translation>
<translation id="6342069812937806050">PrĂ¡vÄ› teÄ</translation>
+<translation id="6345221851280129312">neznĂ¡mĂ¡ velikost</translation>
<translation id="6355080345576803305">PÅ™epsĂ¡nĂ­ veÅ™ejnĂ© relace</translation>
<translation id="6358450015545214790">NĂ¡povÄ›da</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 dalÅ¡Ă­ nĂ¡vrh}few{# dalÅ¡Ă­ nĂ¡vrhy}many{# dalÅ¡Ă­ho nĂ¡vrhu}other{# dalÅ¡Ă­ch nĂ¡vrhů}}</translation>
<translation id="6387478394221739770">ZajĂ­majĂ­ vĂ¡s novĂ© funkce Chromu? VyzkouÅ¡ejte kanĂ¡l beta na adrese chrome.com/beta.</translation>
-<translation id="641480858134062906">StrĂ¡nku <ph name="URL" /> se nepodaÅ™ilo se naÄĂ­st.</translation>
+<translation id="6389758589412724634">ProhlĂ­Å¾eÄ Chromium k zobrazenĂ­ tĂ©to webovĂ© strĂ¡nky nemÄ›l dostatek pamÄ›ti.</translation>
+<translation id="6416403317709441254">Web <ph name="SITE" /> nynĂ­ nelze navÅ¡tĂ­vit, protože tento web odeslal nesprĂ¡vnĂ© identifikaÄnĂ­ Ăºdaje, kterĂ© prohlĂ­Å¾eÄ Chromium nedokĂ¡Å¾e zpracovat. SĂ­Å¥ovĂ© chyby aÂ Ăºtoky jsou obvykle doÄasnĂ©, tato strĂ¡nka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">Nelze ověřit, zda byl certifikĂ¡t zruÅ¡en.</translation>
<translation id="6433595998831338502">Web <ph name="HOST_NAME" /> odmĂ­tl pÅ™ipojenĂ­.</translation>
<translation id="6445051938772793705">ZemÄ›</translation>
<translation id="6451458296329894277">Potvrdit novĂ© odeslĂ¡nĂ­ formulĂ¡Å™e</translation>
<translation id="6458467102616083041">IgnorovĂ¡no, protože vĂ½chozĂ­ vyhledĂ¡vĂ¡nĂ­ je zakĂ¡zĂ¡no zĂ¡sadou.</translation>
+<translation id="6462969404041126431">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Je možnĂ©, že jeho bezpeÄnostnĂ­ certifikĂ¡t byl zruÅ¡en. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">ZĂ¡sady zaÅ™Ă­zenĂ­</translation>
<translation id="6489534406876378309">ZaÄĂ­t nahrĂ¡vat zprĂ¡vy o selhĂ¡nĂ­</translation>
<translation id="6529602333819889595">&amp;Opakovat smazĂ¡nĂ­</translation>
+<translation id="6534179046333460208">NĂ¡vrhy fyzickĂ©ho webu</translation>
<translation id="6550675742724504774">Možnosti</translation>
+<translation id="6593753688552673085">mĂ©nÄ› než <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Možnosti Å¡ifrovĂ¡nĂ­</translation>
<translation id="662080504995468778">Zůstat</translation>
<translation id="6628463337424475685">VyhledĂ¡vĂ¡nĂ­ <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Web <ph name="SITE" /> nynĂ­ nemůžete navÅ¡tĂ­vit, protože <ph name="BEGIN_LINK" />tento certifikĂ¡t byl zruÅ¡en<ph name="END_LINK" />. SĂ­Å¥ovĂ© chyby a Ăºtoky jsou obvykle doÄasnĂ©, tato strĂ¡nka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat.</translation>
<translation id="6644283850729428850">Tato zĂ¡sada se již nepouÅ¾Ă­vĂ¡.</translation>
+<translation id="6652240803263749613">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. OperaÄnĂ­ systĂ©m vaÅ¡eho poÄĂ­taÄe jeho bezpeÄnostnĂ­mu certifikĂ¡tu nedůvěřuje. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">Ăprava složky</translation>
<translation id="6660210980321319655">Automaticky zaznamenĂ¡no <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Odstranit nĂ¡vrh položky formulĂ¡Å™e z prohlĂ­Å¾eÄe Chromium?</translation>
@@ -469,6 +502,7 @@ Kontaktujte administrĂ¡tora systĂ©mu.</translation>
<translation id="6710213216561001401">PÅ™edchozĂ­</translation>
<translation id="6710594484020273272">&lt;Zadejte vyhledĂ¡vacĂ­ dotaz&gt;</translation>
<translation id="6711464428925977395">DoÅ¡lo k chybÄ› proxy serveru nebo jste zadali nesprĂ¡vnou adresu.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{Å¾Ă¡dnĂ© položky}=1{1 položka}few{# položky}many{# položky}other{# položek}}</translation>
<translation id="674375294223700098">NeznĂ¡mĂ¡ chyba certifikĂ¡tu serveru.</translation>
<translation id="6753269504797312559">Hodnota zĂ¡sady</translation>
<translation id="6757797048963528358">ZaÅ™Ă­zenĂ­ pÅ™eÅ¡lo do režimu spĂ¡nku.</translation>
@@ -480,7 +514,6 @@ Kontaktujte administrĂ¡tora systĂ©mu.</translation>
<translation id="6891596781022320156">Ăroveň zĂ¡sady nenĂ­ podporovĂ¡na.</translation>
<translation id="6895330447102777224">Vaše karta je ověřena</translation>
<translation id="6897140037006041989">User agent</translation>
-<translation id="6903907808598579934">Zapnout synchronizaci</translation>
<translation id="6915804003454593391">Uživatel:</translation>
<translation id="6957887021205513506">ZdĂ¡ se, že certifikĂ¡t serveru je podvrh.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -488,9 +521,11 @@ Kontaktujte administrĂ¡tora systĂ©mu.</translation>
<translation id="6970216967273061347">Obvod</translation>
<translation id="6973656660372572881">UrÄeny jsou pevnÄ› danĂ© servery proxy i adresa URL skriptu PAC.</translation>
<translation id="6989763994942163495">Zobrazit rozÅ¡Ă­Å™enĂ¡ nastavenĂ­...</translation>
+<translation id="7000990526846637657">Nebyly nalezeny Å¾Ă¡dnĂ© historickĂ© zĂ¡znamy</translation>
+<translation id="7009986207543992532">Pokusili jste se pÅ™ipojit k domĂ©nÄ› <ph name="DOMAIN" />, ale server pÅ™edložil certifikĂ¡t, kterĂ½ mĂ¡ pÅ™Ă­liÅ¡ dlouhĂ© obdobĂ­ platnosti, a je proto nedůvÄ›ryhodnĂ½. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Na adrese <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> mohou bĂ½t k dispozici dalÅ¡Ă­ formy historie prohlĂ­Å¾enĂ­ zaznamenanĂ© ve vaÅ¡em ĂºÄtu Google</translation>
<translation id="7029809446516969842">Hesla</translation>
-<translation id="7050187094878475250">Pokusili jste se pÅ™ipojit k domĂ©nÄ› <ph name="DOMAIN" />, ale server pÅ™edložil certifikĂ¡t, kterĂ½ mĂ¡ pÅ™Ă­liÅ¡ dlouhĂ© obdobĂ­ platnosti a je proto nedůvÄ›ryhodnĂ½.</translation>
<translation id="7087282848513945231">Obvod</translation>
<translation id="7088615885725309056">StarÅ¡Ă­</translation>
<translation id="7090678807593890770">Vyhledejte na Googlu <ph name="LINK" /></translation>
@@ -509,13 +544,13 @@ Kontaktujte administrĂ¡tora systĂ©mu.</translation>
<translation id="7246609911581847514">Tato zprĂ¡va se zobrazila, protože je potÅ™eba, aby pÅ™i prvnĂ­ nĂ¡vÅ¡tÄ›vÄ› novĂ©ho webu povolil pÅ™Ă­stup sprĂ¡vce.</translation>
<translation id="724975217298816891">Chcete-li aktualizovat Ăºdaje o kartÄ›, zadejte datum vyprÅ¡enĂ­ platnosti a kĂ³d CVC karty <ph name="CREDIT_CARD" />. Po ověřenĂ­ budou Ăºdaje o kartÄ› sdĂ­leny s tĂ­mto webem.</translation>
<translation id="725866823122871198">SoukromĂ© pÅ™ipojenĂ­ k domĂ©nÄ› <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nelze navĂ¡zat, protože mĂ¡te v poÄĂ­taÄi nastaveno chybnĂ© datum a Äas (<ph name="DATE_AND_TIME" />).</translation>
-<translation id="7265986070661382626">Web <ph name="SITE" /> nynĂ­ nemůžete navÅ¡tĂ­vit, protože <ph name="BEGIN_LINK" />pouÅ¾Ă­vĂ¡ pÅ™ipĂ­nĂ¡nĂ­ certifikĂ¡tů<ph name="END_LINK" />. SĂ­Å¥ovĂ© chyby a Ăºtoky jsou obvykle doÄasnĂ©, tato strĂ¡nka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat.</translation>
<translation id="7269802741830436641">Tato strĂ¡nka obsahuje smyÄku pÅ™esmÄ›rovĂ¡nĂ­</translation>
<translation id="7275334191706090484">SpravovanĂ© zĂ¡ložky</translation>
<translation id="7298195798382681320">DoporuÄeno</translation>
-<translation id="7301833672208172928">Zapnout synchronizaci historie</translation>
+<translation id="7309308571273880165">ZprĂ¡va o selhĂ¡nĂ­ poÅ™Ă­zenĂ¡ <ph name="CRASH_TIME" /> (o nahrĂ¡nĂ­ poÅ¾Ă¡dal uživatel, dosud nenahrĂ¡na)</translation>
<translation id="7334320624316649418">&amp;Opakovat zmÄ›nu uspoÅ™Ă¡dĂ¡nĂ­</translation>
<translation id="733923710415886693">CertifikĂ¡t serveru nebyl zveÅ™ejnÄ›n prostÅ™ednictvĂ­m projektu Certificate Transparency.</translation>
+<translation id="7351800657706554155">Web <ph name="SITE" /> nynĂ­ nemůžete navÅ¡tĂ­vit, protože jeho certifikĂ¡t byl zruÅ¡en. SĂ­Å¥ovĂ© chyby aÂ Ăºtoky jsou obvykle doÄasnĂ©, tato strĂ¡nka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">PÅ™Ă­kazovĂ½ Å™Ă¡dek</translation>
<translation id="7372973238305370288">vĂ½sledek vyhledĂ¡vĂ¡nĂ­</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -534,16 +569,17 @@ Pssst! PÅ™Ă­Å¡tÄ› by se vĂ¡m mohl hodit anonymnĂ­ režim (<ph name="SHORTCUT_KEY
<translation id="7469372306589899959">OvěřovĂ¡nĂ­ karty</translation>
<translation id="7481312909269577407">Vpřed</translation>
<translation id="7485870689360869515">Nebyla nalezena Å¾Ă¡dnĂ¡ data.</translation>
+<translation id="7508255263130623398">VrĂ¡cenĂ© ID zaÅ™Ă­zenĂ­ pro zĂ¡sady je prĂ¡zdnĂ© nebo neodpovĂ­dĂ¡ aktuĂ¡lnĂ­mu ID zaÅ™Ă­zenĂ­</translation>
<translation id="7514365320538308">StĂ¡hnout</translation>
<translation id="7518003948725431193">Na webovĂ© adrese <ph name="URL" /> se nepodaÅ™ilo nalĂ©zt Å¾Ă¡dnou webovou strĂ¡nku.</translation>
<translation id="7537536606612762813">PovinnĂ¡</translation>
<translation id="7542995811387359312">AutomatickĂ© vyplňovĂ¡nĂ­ Ăºdajů platebnĂ­ karty je deaktivovĂ¡no, protože tento formulĂ¡Å™ nepouÅ¾Ă­vĂ¡ zabezpeÄenĂ© pÅ™ipojenĂ­.</translation>
<translation id="7549584377607005141">Tato strĂ¡nka potÅ™ebuje ke sprĂ¡vnĂ©mu zobrazenĂ­ data, kterĂ¡ jste zadali dÅ™Ă­ve. Tyto Ăºdaje můžete odeslat znovu, ale zopakujete tĂ­m vÅ¡echny akce, kterĂ© tato strĂ¡nka již pÅ™edtĂ­m provedla.</translation>
<translation id="7554791636758816595">NovĂ¡ karta</translation>
-<translation id="7567204685887185387">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. Jeho bezpeÄnostnĂ­ certifikĂ¡t byl zÅ™ejmÄ› vydĂ¡n podvodnÄ›. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k.</translation>
<translation id="7568593326407688803">Tato strĂ¡nka je v jazyce<ph name="ORIGINAL_LANGUAGE" />Chcete ji pÅ™eložit?</translation>
<translation id="7569952961197462199">Odstranit platebnĂ­ kartu z Chromu?</translation>
<translation id="7578104083680115302">PlaÅ¥te na webech a v aplikacĂ­ch v různĂ½ch zaÅ™Ă­zenĂ­ch rychle pomocĂ­ karet uloženĂ½ch na Googlu.</translation>
+<translation id="7588950540487816470">FyzickĂ½ web</translation>
<translation id="7592362899630581445">CertifikĂ¡t serveru poruÅ¡uje omezenĂ­ nĂ¡zvů domĂ©n.</translation>
<translation id="759889825892636187">Web <ph name="HOST_NAME" /> momentĂ¡lnÄ› tento požadavek nemůže zpracovat.</translation>
<translation id="7600965453749440009">Jazyk <ph name="LANGUAGE" /> nikdy nepÅ™eklĂ¡dat</translation>
@@ -554,6 +590,7 @@ Pssst! PÅ™Ă­Å¡tÄ› by se vĂ¡m mohl hodit anonymnĂ­ režim (<ph name="SHORTCUT_KEY
<translation id="7637571805876720304">Odstranit platebnĂ­ kartu z prohlĂ­Å¾eÄe Chromium?</translation>
<translation id="765676359832457558">SkrĂ½t rozÅ¡Ă­Å™enĂ¡ nastavenĂ­...</translation>
<translation id="7658239707568436148">Zrušit</translation>
+<translation id="7667346355482952095">VrĂ¡cenĂ½ klĂ­Ä zĂ¡sady je prĂ¡zdnĂ½ nebo neodpovĂ­dĂ¡ aktuĂ¡lnĂ­mu klĂ­Äi.</translation>
<translation id="7668654391829183341">NeznĂ¡mĂ© zaÅ™Ă­zenĂ­</translation>
<translation id="7674629440242451245">ZajĂ­majĂ­ vĂ¡s novĂ© funkce Chromu? VyzkouÅ¡ejte kanĂ¡l pro vĂ½vojĂ¡Å™e na adrese chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />PokraÄovat na web <ph name="SITE" /> (nespolehlivĂ½)<ph name="END_LINK" /></translation>
@@ -570,10 +607,10 @@ Pssst! PÅ™Ă­Å¡tÄ› by se vĂ¡m mohl hodit anonymnĂ­ režim (<ph name="SHORTCUT_KEY
<translation id="780301667611848630">Ne, děkuji</translation>
<translation id="7805768142964895445">Stav</translation>
<translation id="7813600968533626083">Odstranit nĂ¡vrh položky formulĂ¡Å™e z Chromu?</translation>
+<translation id="7815407501681723534">NalezenĂ© <ph name="SEARCH_RESULTS" /> pro dotaz â€<ph name="SEARCH_STRING" />“: <ph name="NUMBER_OF_RESULTS" /></translation>
<translation id="785549533363645510">To neznamenĂ¡, že jste neviditelnĂ­. AnonymnĂ­ režim neskryje vaÅ¡i aktivitu pÅ™ed vaÅ¡Ă­m zamÄ›stnavatelem, poskytovatelem internetovĂ½ch služeb ani webovĂ½mi strĂ¡nkami, kterĂ© navÅ¡tĂ­vĂ­te.</translation>
<translation id="7887683347370398519">Zkontrolujte kĂ³d CVC a zkuste to znovu</translation>
<translation id="7894616681410591072">Jejda! PÅ™Ă­stup na tuto strĂ¡nku vyžaduje povolenĂ­ uživatele <ph name="NAME" />.</translation>
-<translation id="790025292736025802">Adresa <ph name="URL" /> nenalezena</translation>
<translation id="7912024687060120840">Ve složce:</translation>
<translation id="7920092496846849526">Zeptali jste se svĂ©ho rodiÄe, zda můžete navÅ¡tĂ­vit tuto strĂ¡nku.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -586,9 +623,10 @@ Pssst! PÅ™Ă­Å¡tÄ› by se vĂ¡m mohl hodit anonymnĂ­ režim (<ph name="SHORTCUT_KEY
<translation id="7995512525968007366">NenĂ­ zadĂ¡no</translation>
<translation id="8012647001091218357">V tuto chvĂ­li se nĂ¡m s vaÅ¡imi rodiÄi nepodaÅ™ilo spojit. Zkuste to prosĂ­m znovu.</translation>
<translation id="8034522405403831421">StrĂ¡nka je v jazyce <ph name="SOURCE_LANGUAGE" />. Chcete ji pÅ™eložit do jazyka <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Nebyly nalezeny Å¾Ă¡dnĂ© historickĂ© zĂ¡znamy.</translation>
<translation id="8088680233425245692">ZobrazenĂ­ ÄlĂ¡nku se nezdaÅ™ilo.</translation>
+<translation id="8089520772729574115">mĂ©nÄ› než 1 MB</translation>
<translation id="8091372947890762290">ÄŒekĂ¡ se na aktivaci na serveru</translation>
+<translation id="8129262335948759431">neznĂ¡mĂ© množstvĂ­</translation>
<translation id="8131740175452115882">Potvrdit</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Adresa DNS<ph name="END_ABBR" /> serveru <ph name="HOST_NAME" /> nebyla nalezena.</translation>
<translation id="8149426793427495338">PoÄĂ­taÄ pÅ™eÅ¡el do režimu spĂ¡nku.</translation>
@@ -597,6 +635,7 @@ Pssst! PÅ™Ă­Å¡tÄ› by se vĂ¡m mohl hodit anonymnĂ­ režim (<ph name="SHORTCUT_KEY
<translation id="8201077131113104583">NeplatnĂ¡ adresa URL aktualizace rozÅ¡Ă­Å™enĂ­ s ID <ph name="EXTENSION_ID" />.</translation>
<translation id="8218327578424803826">PÅ™iÅ™azenĂ© mĂ­sto:</translation>
<translation id="8225771182978767009">Uživatel, kterĂ½ tento poÄĂ­taÄ nastavoval, se rozhodl tento web blokovat.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">StrĂ¡nka, kterou hledĂ¡te, pouÅ¾Ă­vala vĂ¡mi zadanĂ© informace. NĂ¡vrat na tuto strĂ¡nku by mohl způsobit, že akce, kterou jste provedli, bude opakovĂ¡na. PÅ™ejete si pokraÄovat?</translation>
<translation id="8249320324621329438">Naposledy naÄteno:</translation>
<translation id="8261506727792406068">Vymazat</translation>
@@ -609,12 +648,17 @@ Pssst! PÅ™Ă­Å¡tÄ› by se vĂ¡m mohl hodit anonymnĂ­ režim (<ph name="SHORTCUT_KEY
<translation id="8349305172487531364">LiÅ¡ta zĂ¡ložek</translation>
<translation id="8363502534493474904">Vypnout režim Letadlo</translation>
<translation id="8364627913115013041">Nenastaveno.</translation>
+<translation id="8380941800586852976">NebezpeÄnĂ©</translation>
<translation id="8412145213513410671">SelhĂ¡nĂ­ (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Stejnou heslovou frĂ¡zi musĂ­te zadat dvakrĂ¡t.</translation>
<translation id="8428213095426709021">NastavenĂ­</translation>
+<translation id="8433057134996913067">Budete odhlĂ¡Å¡eni z vÄ›tÅ¡iny webů.</translation>
<translation id="8437238597147034694">&amp;VrĂ¡tit pÅ™esunutĂ­ zpÄ›t</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 platebnĂ­ karta}few{# platebnĂ­ karty}many{# platebnĂ­ karty}other{# platebnĂ­ch karet}}</translation>
+<translation id="8483780878231876732">Chcete-li pouÅ¾Ă­vat karty zÂ ĂºÄtu Google, pÅ™ihlaste se do Chromu.</translation>
<translation id="8488350697529856933">PlatĂ­ pro</translation>
<translation id="8498891568109133222">OdpovÄ›Ä webu <ph name="HOST_NAME" /> trvala pÅ™Ă­liÅ¡ dlouho.</translation>
+<translation id="852346902619691059">Server nedokĂ¡zal prokĂ¡zat, že patÅ™Ă­ domĂ©nÄ› <ph name="DOMAIN" />. OperaÄnĂ­ systĂ©m vaÅ¡eho zaÅ™Ă­zenĂ­ jeho bezpeÄnostnĂ­mu certifikĂ¡tu nedůvěřuje. Může to bĂ½t způsobeno nesprĂ¡vnou konfiguracĂ­ nebo tĂ­m, že vaÅ¡e pÅ™ipojenĂ­ zachytĂ¡vĂ¡ ĂºtoÄnĂ­k. <ph name="BEGIN_LEARN_MORE_LINK" />DalÅ¡Ă­ informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Služba Google Payments tento typ karty nepodporuje. Vyberte prosĂ­m jinou kartu.</translation>
<translation id="8550022383519221471">Služba synchronizace nenĂ­ pro vaÅ¡i domĂ©nu k dispozici.</translation>
<translation id="8553075262323480129">PÅ™eklad se nezdaÅ™il. NepodaÅ™ilo se rozpoznat jazyk strĂ¡nky.</translation>
@@ -626,15 +670,12 @@ Pssst! PÅ™Ă­Å¡tÄ› by se vĂ¡m mohl hodit anonymnĂ­ režim (<ph name="SHORTCUT_KEY
<translation id="8647750283161643317">Obnovit u vÅ¡ech experimentů vĂ½chozĂ­ nastavenĂ­</translation>
<translation id="8680787084697685621">PÅ™ihlaÅ¡ovacĂ­ Ăºdaje k ĂºÄtu jsou zastaralĂ©.</translation>
<translation id="8703575177326907206">VaÅ¡e spojenĂ­ se serverem <ph name="DOMAIN" /> nenĂ­ Å¡ifrovanĂ©.</translation>
-<translation id="8713130696108419660">NesprĂ¡vnĂ½ poÄĂ¡teÄnĂ­ podpis</translation>
<translation id="8725066075913043281">Zkusit znovu</translation>
<translation id="8728672262656704056">Jste v anonymnĂ­m režimu</translation>
<translation id="8730621377337864115">Hotovo</translation>
<translation id="8738058698779197622">Aby bylo možnĂ© navĂ¡zat zabezpeÄenĂ© spojenĂ­, hodiny musejĂ­ bĂ½t nastaveny sprĂ¡vnÄ›. Důvodem je, že certifikĂ¡ty, pomocĂ­ kterĂ½ch se weby identifikujĂ­, platĂ­ pouze pro pevnÄ› danĂ¡ obdobĂ­. Jelikož hodiny v zaÅ™Ă­zenĂ­ nejsou nastaveny sprĂ¡vnÄ›, prohlĂ­Å¾eÄ Chromium tyto certifikĂ¡ty nemůže ověřit.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Adresu DNS&lt;/abbr&gt; webu <ph name="HOST_NAME" /> nelze najĂ­t. DiagnostikovĂ¡nĂ­ problĂ©mu…</translation>
-<translation id="8741995161408053644">Na strĂ¡nce <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> mohou bĂ½t k dispozici dalÅ¡Ă­ formy historie prohlĂ­Å¾enĂ­ zaznamenanĂ© ve vaÅ¡em ĂºÄtu Google.</translation>
<translation id="8790007591277257123">&amp;Opakovat smazĂ¡nĂ­</translation>
-<translation id="8790687370365610530">Chcete-li od Googlu dostĂ¡vat personalizovanĂ© nĂ¡vrhy obsahu, zapnÄ›te synchronizaci historie.</translation>
<translation id="8798099450830957504">VĂ½chozĂ­</translation>
<translation id="8804164990146287819">ZĂ¡sady ochrany soukromĂ­</translation>
<translation id="8820817407110198400">ZĂ¡ložky</translation>
@@ -656,13 +697,11 @@ Pssst! PÅ™Ă­Å¡tÄ› by se vĂ¡m mohl hodit anonymnĂ­ režim (<ph name="SHORTCUT_KEY
<translation id="8971063699422889582">Platnost certifikĂ¡tu serveru vyprÅ¡ela.</translation>
<translation id="8987927404178983737">Měsíc</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Server pÅ™edložil certifikĂ¡t, kterĂ½ nebyl zveÅ™ejnÄ›n v souladu se zĂ¡sadou Certificate Transparency. U nÄ›kterĂ½ch certifikĂ¡tů je to z důvodu kontroly důvÄ›ryhodnosti a ochrany pÅ™ed ĂºtoÄnĂ­ky vyžadovĂ¡no.</translation>
<translation id="9001074447101275817">Proxy <ph name="DOMAIN" /> vyžaduje uživatelskĂ© jmĂ©no a heslo.</translation>
<translation id="901974403500617787">PÅ™Ă­znaky, kterĂ© platĂ­ v celĂ©m systĂ©mu, může nastavit pouze vlastnĂ­k: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">StrĂ¡nka byla pÅ™eložena do jazyka <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">PouÅ¾Ă­vat službu pÅ™edpovĂ­dĂ¡nĂ­ k rychlejÅ¡Ă­mu naÄĂ­tĂ¡nĂ­ strĂ¡nek</translation>
<translation id="9039213469156557790">Tato strĂ¡nka obsahuje jeÅ¡tÄ› dalÅ¡Ă­ nezabezpeÄenĂ© zdroje. Tyto zdroje budou bÄ›hem pÅ™enosu moci zobrazit jinĂ­ uživatelĂ© a pÅ™Ă­padnĂ­ ĂºtoÄnĂ­ci je mohou upravit a zmÄ›nit tak chovĂ¡nĂ­ strĂ¡nky.</translation>
-<translation id="9049981332609050619">Pokusili jste se pÅ™ejĂ­t do domĂ©ny <ph name="DOMAIN" />, ale server pÅ™edložil certifikĂ¡t, jehož platnost vyprÅ¡ela.</translation>
<translation id="9050666287014529139">HeslovĂ¡ frĂ¡ze</translation>
<translation id="9065203028668620118">Upravit</translation>
<translation id="9092364396508701805">StrĂ¡nka <ph name="HOST_NAME" /> nefunguje</translation>
diff --git a/chromium/components/strings/components_strings_da.xtb b/chromium/components/strings/components_strings_da.xtb
index 157ea406265..900d044e277 100644
--- a/chromium/components/strings/components_strings_da.xtb
+++ b/chromium/components/strings/components_strings_da.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="da">
+<translation id="1008557486741366299">Ikke nu</translation>
<translation id="1015730422737071372">Angiv yderligere oplysninger</translation>
<translation id="1032854598605920125">Rotér med uret</translation>
<translation id="1038842779957582377">ukendt navn</translation>
+<translation id="1053591932240354961">Du kan ikke gĂ¥ til <ph name="SITE" /> lige nu, da websitet sendte krypterede loginoplysninger, som Google Chrome ikke kan behandle. Netværksfejl og hackerangreb er normalt midlertidige, sĂ¥ siden vil sandsynligvis fungere senere. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Fortryd tilføjelse</translation>
<translation id="10614374240317010">Aldrig gemt</translation>
-<translation id="1064422015032085147">Den server, der hoster websiden, kan være overbelastet eller under vedligeholdelse.
- For at undgĂ¥ at generere for meget trafik og forværre situationen
- er anmodninger pĂ¥ denne webadresse midlertidigt blevet deaktiveret.</translation>
<translation id="106701514854093668">Bogmærker pĂ¥ pc</translation>
<translation id="1080116354587839789">Tilpas til bredden</translation>
+<translation id="1103124106085518534">Færdig indtil videre</translation>
<translation id="1103523840287552314">Oversæt altid <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Hvis dette felt er markeret, gemmer Chrome en kopi af dit kort pĂ¥ denne enhed, sĂ¥ formularer hurtigere kan udfyldes fremover.</translation>
+<translation id="1111153019813902504">Seneste bogmærker</translation>
<translation id="1113869188872983271">&amp;Fortryd omarrangering</translation>
+<translation id="1126551341858583091">Størrelsen pĂ¥ den lokale lagerplads er <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache for politik er OK</translation>
<translation id="113188000913989374"><ph name="SITE" /> siger:</translation>
<translation id="1132774398110320017">Indstillinger for Autofyld i Chrome...</translation>
-<translation id="1150979032973867961">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da operativsystemet pĂ¥ din computer ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="1152921474424827756">FĂ¥ adgang til en <ph name="BEGIN_LINK" />cachelagret kopi<ph name="END_LINK" /> af <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> lukkede forbindelsen uventet.</translation>
<translation id="1161325031994447685">Genoprette forbindelse til Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Fjern</translation>
<translation id="1201402288615127009">Næste</translation>
<translation id="1201895884277373915">Mere fra dette website</translation>
-<translation id="121201262018556460">Du har forsøgt at fĂ¥ fat i <ph name="DOMAIN" />, men serveren har præsenteret et certifikat med en svag nøgle. En hacker kan have knækket den private nøgle, og serveren er muligvis ikke den forventede server (du kommunikerer muligvis med en hacker).</translation>
+<translation id="1206967143813997005">Ugyldig første signatur</translation>
+<translation id="1209206284964581585">Skjul indtil videre</translation>
<translation id="1219129156119358924">Systemsikkerhed</translation>
<translation id="1227224963052638717">Ukendt politik.</translation>
<translation id="1227633850867390598">Skjul værdi</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Ja</translation>
<translation id="1430915738399379752">Udskriv</translation>
<translation id="1442912890475371290">Et forsøg pĂ¥ at <ph name="BEGIN_LINK" />besøge en side pĂ¥ <ph name="DOMAIN" /><ph name="END_LINK" /> blev blokeret.</translation>
+<translation id="1491663344921578213">Du kan ikke gĂ¥ til <ph name="SITE" /> lige nu, da websitet anvender certifikatlĂ¥sning. Netværksfejl og hackerangreb er normalt midlertidige, sĂ¥ denne side vil sandsynligvis fungere senere. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Vis en gemt (dvs. forældet) kopi af denne side.</translation>
<translation id="1519264250979466059">Versionsdato</translation>
<translation id="1549470594296187301">JavaScript skal være aktiveret, før du kan bruge denne funktion.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Netværkskonfigurationen er ugyldig og kunne ikke importeres.</translation>
<translation id="1644574205037202324">Historik</translation>
<translation id="1645368109819982629">Ikke-understøttet protokol</translation>
-<translation id="1655462015569774233">{1,plural, =1{Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat udløb i gĂ¥r. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. Computerens ur er angivet til <ph name="CURRENT_DATE" />. Er det korrekt? Hvis ikke, skal du rette systemets ur og derefter opdatere denne side.}one{Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat udløb for # dag siden. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. Computerens ur er angivet til <ph name="CURRENT_DATE" />. Er det korrekt? Hvis ikke, skal du rette systemets ur og derefter opdatere denne side.}other{Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat udløb for # dage siden. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. Computerens ur er angivet til <ph name="CURRENT_DATE" />. Er det korrekt? Hvis ikke, skal du rette systemets ur og derefter opdatere denne side.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> bruger normalt kryptering til at beskytte dine oplysninger. Da Google Chrome forsøgte at oprette forbindelse til <ph name="SITE" /> denne gang, returnerede websitet usædvanlige og forkerte legitimationsoplysninger. Dette kan skyldes, at en hacker forsøger at udgive sig for at være <ph name="SITE" />, eller at en Wi-Fi-loginskærm har forstyrret forbindelsen. Dine oplysninger er stadig sikre, idet Google Chrome afbrød forbindelsen, inden der blev udvekslet data.</translation>
<translation id="168841957122794586">Servercertifikatet indeholder en svag kryptografisk nøgle.</translation>
<translation id="1701955595840307032">Hent foreslĂ¥et indhold</translation>
-<translation id="1706954506755087368">{1,plural, =1{Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat tilsyneladende først gælder fra i morgen. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.}one{Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat tilsyneladende først gælder fra om # dag. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.}other{Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat tilsyneladende først gælder fra om # dage. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Prøv at kontakte systemadministratoren.</translation>
<translation id="17513872634828108">Ă…bne faner</translation>
<translation id="1753706481035618306">Sidetal</translation>
-<translation id="1761412452051366565">AktivĂ©r synkronisering for at hente brugertilpasset indhold, som er foreslĂ¥et af Google.</translation>
-<translation id="1763864636252898013">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da operativsystemet pĂ¥ din enhed ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Prøv at køre Windows Netværksdiagnosticering<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Opdater din adgangssætning til synkronisering.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">De bogmærker, du har besøgt for nylig, vises her.</translation>
<translation id="1821930232296380041">Ugyldig anmodning eller anmodningsparametre</translation>
<translation id="1838667051080421715">Du fĂ¥r vist kilden for en webside.</translation>
<translation id="1871208020102129563">Proxy er indstillet til at bruge faste proxyservere, ikke webadresser til .pac-scripts.</translation>
<translation id="1883255238294161206">Skjul liste</translation>
<translation id="1898423065542865115">Filtrering</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> accepterede ikke dit logincertifikat, eller dit logincertifikat er muligvis udløbet.</translation>
<translation id="194030505837763158">GĂ¥ til <ph name="LINK" /></translation>
<translation id="1962204205936693436">Bogmærker fra <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Serialiseringsfejl</translation>
<translation id="1974060860693918893">Avanceret</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{og 1 mere}one{og # mere}other{og # mere}}</translation>
<translation id="2025186561304664664">Proxyen konfigureres automatisk.</translation>
<translation id="2030481566774242610">Mente du <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Denne meddelelse vises, fordi dine forældre skal godkende nye websites, første gang du besøger dem.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Kontrollere din proxy og din firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Postnummer</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 forslag}one{# forslag}other{# forslag}}</translation>
<translation id="2065985942032347596">Godkendelse pĂ¥krævet</translation>
<translation id="2079545284768500474">Fortryd</translation>
<translation id="20817612488360358">Indstillingerne for systemproxy er angivet at blive brugt, men en eksplicit proxykonfiguration er ogsĂ¥ angivet.</translation>
@@ -105,33 +106,35 @@
<translation id="2149973817440762519">Rediger bogmærke</translation>
<translation id="2166049586286450108">Fuld administratoradgang</translation>
<translation id="2166378884831602661">Dette website kan ikke levere en sikker forbindelse</translation>
-<translation id="2171101176734966184">Du forsøgte at fĂ¥ fat pĂ¥ <ph name="DOMAIN" />, men serveren har præsenteret et certifikat, der er signeret med en svag signaturalgoritme. Det betyder, at sikkerhedsoplysningerne fra serveren kan være forfalskede, og at serveren muligvis ikke er den server, som du har forventet (du kommunikerer muligvis med en hacker).</translation>
<translation id="2181821976797666341">Politikker</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}one{# adresse}other{# adresser}}</translation>
<translation id="2212735316055980242">Politikken blev ikke fundet</translation>
<translation id="2213606439339815911">Indlæg hentes...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> er ikke tilgængelig</translation>
<translation id="2230458221926704099">Ret problemerne med din forbindelse ved hjælp af <ph name="BEGIN_LINK" />diagnoseappen<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Send nu</translation>
<translation id="225207911366869382">Denne værdi er forældet for denne politik.</translation>
<translation id="2262243747453050782">HTTP-fejl</translation>
<translation id="2282872951544483773">Utilgængelige eksperimenter</translation>
<translation id="2292556288342944218">Din internetadgang er blokeret</translation>
<translation id="229702904922032456">Et rodcertifikat eller et midlertidigt certifikat er udløbet.</translation>
<translation id="230155334948463882">Har du fĂ¥et nyt kort?</translation>
+<translation id="2305919008529760154">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet kan være udstedt pĂ¥ ulovlig vis. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> kræver et brugernavn og en adgangskode.</translation>
+<translation id="2318774815570432836">Du kan ikke gĂ¥ til <ph name="SITE" /> lige nu, fordi websitet bruger HSTS. Netværksfejl og hackerangreb er normalt midlertidige, sĂ¥ siden vil sandsynligvis fungere senere. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Ugyldigt bogmærke ved indeks <ph name="ENTRY_INDEX" /> er ignoreret</translation>
<translation id="2354001756790975382">Andre bogmærker</translation>
<translation id="2359808026110333948">Fortsæt</translation>
<translation id="2365563543831475020">Nedbrudsrapporten, der blev registreret <ph name="CRASH_TIME" />, blev ikke uploadet</translation>
<translation id="2367567093518048410">Niveau</translation>
+<translation id="2371153335857947666">{1,plural, =1{Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet udløb i gĂ¥r. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. Computerens ur er angivet til <ph name="CURRENT_DATE" />. Er det korrekt? Hvis ikke, skal du rette systemets ur og derefter opdatere denne side. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.}one{Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet udløb for # dag siden. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. Computerens ur er angivet til <ph name="CURRENT_DATE" />. Er det korrekt? Hvis ikke, skal du rette systemets ur og derefter opdatere denne side. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.}other{Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet udløb for # dage siden. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. Computerens ur er angivet til <ph name="CURRENT_DATE" />. Er det korrekt? Hvis ikke, skal du rette systemets ur og derefter opdatere denne side. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Der er ingen alternative grænseflader</translation>
<translation id="2384307209577226199">Virksomhedsstandard</translation>
-<translation id="238526402387145295">Du kan ikke gĂ¥ til <ph name="SITE" /> lige nu, fordi websitet <ph name="BEGIN_LINK" />bruger HSTS<ph name="END_LINK" />. Netværksfejl og angreb er normalt midlertidige, sĂ¥ siden vil sandsynligvis fungere senere.</translation>
<translation id="2386255080630008482">Serverens certifikat er blevet tilbagekaldt.</translation>
<translation id="2392959068659972793">Vis politikker uden nogen værdier</translation>
<translation id="2396249848217231973">&amp;Fortryd sletning</translation>
-<translation id="2413528052993050574">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da sikkerhedscertifikatet muligvis er blevet tilbagekaldt. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="2455981314101692989">Denne webside har deaktiveret automatisk udfyldning af denne formular.</translation>
-<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Kører Netværksdiagnosticering<ph name="END_LINK" /></translation>
+<translation id="2463739503403862330">Udfyld</translation>
+<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Køre Netværksdiagnosticering<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ugyldig søgewebadresse.</translation>
<translation id="2491120439723279231">Serverens certifikat indeholder fejl.</translation>
<translation id="2495083838625180221">Værktøj til parsing af JSON-filer</translation>
@@ -152,14 +155,16 @@
<translation id="2653659639078652383">Indsend</translation>
<translation id="2674170444375937751">Er du sikker pĂ¥, at du vil slette disse sider fra din historik?</translation>
<translation id="2677748264148917807">Forlad</translation>
+<translation id="269990154133806163">Serveren præsenterede et certifikat, som ikke var offentliggjort via politikken Certifikatgennemsigtighed. Dette er et krav for visse certifikater for at sikre, at de er pĂ¥lidelige og beskytter mod hackere. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Værdien stemmer ikke overens med formatet.</translation>
<translation id="2704951214193499422">Chromium kan ikke bekræfte dit kort i øjeblikket. Prøv igen senere.</translation>
<translation id="2705137772291741111">Den gemte (cachelagrede) kopi af dette website kunne ikke læses.</translation>
<translation id="2709516037105925701">AutoFyld</translation>
+<translation id="2712118517637785082">Du har forsøgt at fĂ¥ forbindelse til <ph name="DOMAIN" />, men serverens certifikat er blevet tilbagekaldt af udstederen. Det betyder, at du bestemt ikke bør have tillid til serverens sikkerhedsoplysninger. Du kommunikerer muligvis med en hacker. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Spørg om tilladelse</translation>
<translation id="2721148159707890343">Anmodning lykkedes</translation>
<translation id="2728127805433021124">Serverens certifikat er signeret ved hjælp af en svag signaturalgoritme.</translation>
-<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Kører Diagnosticering af forbindelse<ph name="END_LINK" /></translation>
+<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Køre Diagnosticering af forbindelse<ph name="END_LINK" /></translation>
<translation id="2742870351467570537">Fjern valgte elementer</translation>
<translation id="277499241957683684">Manglende enhedsregistrering</translation>
<translation id="2778107779445548489">Denne meddelelse vises, fordi en af dine forældre har blokeret dette website.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Adresse og søgelinje</translation>
<translation id="2826760142808435982">Forbindelsen er krypteret og godkendt ved hjælp af <ph name="CIPHER" />, og den anvender <ph name="KX" /> som primær udvekslingsmekanisme.</translation>
<translation id="2835170189407361413">Ryd formular</translation>
-<translation id="2837049386027881519">Forbindelsen skulle prøves igen ved hjælp af en ældre version af TLS- eller SSL-protokollen. Det betyder typisk, at serveren bruger meget gammel software og kan have andre sikkerhedsproblemer.</translation>
<translation id="284702764277384724">Serverens certifikat pĂ¥ <ph name="HOST_NAME" /> lader til at være en forfalskning.</translation>
<translation id="2889159643044928134">Genindlæs ikke siden</translation>
-<translation id="2896499918916051536">Dette plugin understøttes ikke.</translation>
+<translation id="2900469785430194048">Google Chrome løb tør for hukommelse, da websiden skulle vises.</translation>
<translation id="2909946352844186028">Der blev registreret en netværksændring.</translation>
-<translation id="2915500479781995473">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da sikkerhedscertifikatet er udløbet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. Uret pĂ¥ din computer er indstillet til <ph name="CURRENT_TIME" />. Er det korrekt? Hvis ikke, skal du indstille uret og opdatere siden.</translation>
<translation id="2922350208395188000">Serverens certifikat kan ikke kontrolleres.</translation>
-<translation id="2941952326391522266">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da sikkerhedscertifikatet er fra <ph name="DOMAIN2" />. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="2948083400971632585">Du kan deaktivere alle proxyer, der er konfigureret for en forbindelse, fra siden Indstillinger.</translation>
<translation id="2955913368246107853">Luk søgefeltet</translation>
<translation id="2958431318199492670">Netværkskonfigurationen overholder ikke ONC-standarden. Dele af konfiguration kan muligvis ikke importeres.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Forkert politiktype</translation>
<translation id="3032412215588512954">Vil du genindlæse denne side?</translation>
<translation id="3037605927509011580">Ă˜v, surt!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{mindst 1 element pĂ¥ synkroniserede enheder}=1{1 element (og flere pĂ¥ synkroniserede enheder)}one{# element (og flere pĂ¥ synkroniserede enheder)}other{# elementer (og flere pĂ¥ synkroniserede enheder)}}</translation>
<translation id="3041612393474885105">Certifikatoplysninger</translation>
<translation id="3063697135517575841">Chrome kan ikke bekræfte dit kort i øjeblikket. Prøv igen senere.</translation>
<translation id="3093245981617870298">Du er offline.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Nyeste</translation>
<translation id="3207960819495026254">Bogmærket</translation>
-<translation id="3225919329040284222">Serveren præsenterede et certifikat, der ikke svarer til de indbyggede forventninger. Disse forventninger medtages for bestemte websites med høj sikkerhed for at beskytte dig.</translation>
<translation id="3226128629678568754">Tryk pĂ¥ genindlæsningsknappen for at genindsende de data, der er nødvendige for at indlæse siden.</translation>
<translation id="3228969707346345236">Oversættelsen mislykkedes, fordi siden allerede er pĂ¥ <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Indtast kontrolkoden for <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Tilføj denne side som bogmærke</translation>
<translation id="3270847123878663523">&amp;Fortryd omarrangering</translation>
<translation id="3286538390144397061">Genstart nu</translation>
+<translation id="3303855915957856445">Der blev ikke fundet nogen søgeresultater</translation>
<translation id="3305707030755673451">Dine data blev krypteret med din adgangssætning til synkronisering d. <ph name="TIME" />. Indtast adgangssætningen for at starte synkroniseringen.</translation>
<translation id="333371639341676808">UndgĂ¥, at denne side laver nye dialogbokse.</translation>
+<translation id="3338095232262050444">Sikker</translation>
<translation id="3340978935015468852">indstillinger</translation>
<translation id="3345135638360864351">Din anmodning om at fĂ¥ adgang til dette website kunne ikke sendes til <ph name="NAME" />. Prøv igen.</translation>
<translation id="3355823806454867987">Skift indstillinger for proxy...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Hent interval:</translation>
<translation id="3462200631372590220">Skjul avanceret</translation>
<translation id="3479539252931486093">Var dette uventet? <ph name="BEGIN_LINK" />Giv os gerne feedback<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Ikke nu</translation>
<translation id="348000606199325318">Nedbruds-id <ph name="CRASH_LOCAL_ID" /> (server-id: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Vi kan ikke fĂ¥ fat i din forælder pĂ¥ nuværende tidspunkt. Prøv igen.</translation>
<translation id="3527085408025491307">Mappe</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Brug adgangskode til:</translation>
<translation id="3549644494707163724">Krypter alle synkroniserede data med din egen adgangssætning til synkronisering</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> mere...</translation>
+<translation id="3555561725129903880">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet tilhører <ph name="DOMAIN2" />. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Din forbindelse er ikke privat</translation>
<translation id="3583757800736429874">&amp;Annuller fortryd flytning</translation>
<translation id="3586931643579894722">Skjul oplysninger</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Vis værdi</translation>
<translation id="3630155396527302611">Hvis programmet allerede stĂ¥r pĂ¥ listen over programmer, der har adgang til netværket, kan du prøve
at fjerne det fra listen og tilføje det igen.</translation>
+<translation id="3638794133396384728">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet er udløbet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. Computerens ur er angivet til <ph name="CURRENT_TIME" />. Er det korrekt? Hvis ikke, skal du rette systemets ur og derefter opdatere denne side. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Disse eksperimentelle funktioner kan ændre sig, gĂ¥ i stykker eller forsvinde nĂ¥r som helst. Vi giver absolut ingen garantier for, hvad der kan ske, hvis du aktiverer en af ​​disse eksperimentelle funktioner, og din browser kan mĂ¥ske endda finde pĂ¥ spontant at selvantænde. Spøg til side. Din browser kan muligvis slette alle dine data, eller din sikkerhed eller dine personlige oplysninger kan komme i fare pĂ¥ uventet vis. Enhver eksperimentel funktion, du aktiverer, aktiveres for alle brugere af denne browser. Vær forsigtig, hvis du fortsætter.</translation>
<translation id="3650584904733503804">Valideringen er fuldført</translation>
<translation id="3655670868607891010">Hvis du ser dette jævnligt, kan du prøve <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Revision</translation>
+<translation id="3678029195006412963">Anmodningen kunne ikke signeres</translation>
<translation id="3681007416295224113">Certifikatoplysninger</translation>
<translation id="3693415264595406141">Adgangskode:</translation>
+<translation id="3696411085566228381">ingen</translation>
<translation id="3700528541715530410">Ups, det ser ud til, at du ikke har tilladelse til at se denne side.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Indlæser...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Tænde for mobildata eller Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Tjekke proxy-, firewall- og DNS-konfigurationen<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Link, du har kopieret</translation>
-<translation id="3744899669254331632">Du kan ikke gĂ¥ til <ph name="SITE" /> lige nu, da websitet sendte krypterede loginoplysninger, som Chromium ikke kan behandle. Netværksfejl og angreb er normalt midlertidige, sĂ¥ denne side vil sandsynligvis fungere igen senere.</translation>
<translation id="375403751935624634">Oversættelsen mislykkedes pĂ¥ grund af en serverfejl.</translation>
<translation id="3759461132968374835">Du har ingen nyligt rapporterede nedbrud. Nedbrud, der opstod, mens rapportering om nedbrud var deaktiveret, vises ikke her.</translation>
<translation id="3788090790273268753">Certifikatet for dette website udløber i 2016, og certifikatkæden indeholder et certifikat, der er signeret med SHA-1.</translation>
@@ -276,26 +284,33 @@
<translation id="3884278016824448484">Modstridende enheds-id</translation>
<translation id="3885155851504623709">Sogn</translation>
<translation id="3901925938762663762">Kortet er udløbet</translation>
+<translation id="3910267023907260648">Du forsøgte at fĂ¥ forbindelse til <ph name="DOMAIN" />, men serveren har præsenteret et certifikat, der er signeret med en svag signaturalgoritme. Det betyder, at sikkerhedsoplysningerne fra serveren kan være forfalskede, og at serveren muligvis ikke er den server, som du har forventet (du kommunikerer muligvis med en hacker). <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />,</translation>
+<translation id="3933571093587347751">{1,plural, =1{Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet tilsyneladende først gælder fra i morgen. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.}one{Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet tilsyneladende først gælder fra om # dag. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.}other{Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet tilsyneladende først gælder fra om # dage. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF-dokumentet kunne ikke indlæses</translation>
<translation id="3963721102035795474">Læser-tilstand</translation>
+<translation id="397105322502079400">Beregner...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> er blokeret</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 webside tæt pĂ¥}one{# webside tæt pĂ¥}other{# websider tæt pĂ¥}}</translation>
<translation id="4021036232240155012">DNS er den netværkstjeneste, der oversætter navnet pĂ¥ et website til dets internetadresse.</translation>
<translation id="4030383055268325496">&amp;Fortryd tilføjelse</translation>
-<translation id="4032534284272647190">Der blev nægtet adgang til <ph name="URL" />.</translation>
<translation id="404928562651467259">ADVARSEL</translation>
<translation id="4058922952496707368">Nøgle "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Klienten og serveren understøtter ikke en fælles SSL-protokolversion eller et fælles krypteringsprogram.</translation>
<translation id="4079302484614802869">Proxykonfiguration er angivet til at anvende en webadresse for .pac-script, ikke faste proxyservere.</translation>
<translation id="4103249731201008433">Enhedens serienummer er ugyldigt</translation>
<translation id="4103763322291513355">GĂ¥ til &lt;strong&gt;chrome://policy&lt;/strong&gt; for at se listen over sortlistede webadresser og andre politikker, din systemadministrator har igangsat.</translation>
+<translation id="4110615724604346410">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet indeholder fejl. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Politikkens omfang understøttes ikke.</translation>
-<translation id="4130226655945681476">Kontrollerer netværkskabler, modem og routeren</translation>
+<translation id="4118212371799607889">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da Chromium ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 anden/andet}one{# anden/andet}other{# andre}}</translation>
+<translation id="4130226655945681476">Kontrollere netværkskabler, modem og router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Skal Chromium gemme dette kort?</translation>
<translation id="4171400957073367226">Ugyldig verifikationssignatur</translation>
<translation id="4176463684765177261">Deaktiveret</translation>
<translation id="4196861286325780578">&amp;Annuller fortryd flytning</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Kontrollere firewall- og antiviruskonfigurationer<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{ingen}=1{1 app ($1)}=2{2 apps ($1, $2)}one{# app ($1, $2, $3)}other{# apps ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Nedbrud</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Prøv at køre Netværksdiagnosticering<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Nej</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Intet brugernavn)</translation>
<translation id="4300246636397505754">Forslag fra forældre</translation>
<translation id="4304224509867189079">Log ind</translation>
+<translation id="432290197980158659">Serveren præsenterede et certifikat, der ikke svarer til de indbyggede forventninger. Disse forventninger medtages for bestemte websites med høj sikkerhed for at beskytte dig. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Artiklen blev ikke fundet.</translation>
+<translation id="4331708818696583467">Ikke sikker</translation>
<translation id="4372948949327679948">Forventet <ph name="VALUE_TYPE" />-værdi.</translation>
-<translation id="4377125064752653719">Du har forsøgt at fĂ¥ fat pĂ¥ <ph name="DOMAIN" />, men serverens certifikat er blevet tilbagekaldt af udgiveren. Det betyder, at du bestemt ikke bør have tillid til serverens sikkerhedsoplysninger. Du kommunikerer muligvis med en hacker.</translation>
<translation id="4381091992796011497">Brugernavn:</translation>
<translation id="4394049700291259645">Deaktiver</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> til <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">søgeresultater</translation>
-<translation id="4424024547088906515">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da Chrome ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> accepterede ikke dit logincertifikat, eller der er ikke angivet et.</translation>
<translation id="443673843213245140">Brug af en proxy er deaktiveret, men en eksplicit proxykonfiguration er angivet.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Denne meddelelse vises, fordi Google SafeSites er aktiveret.</translation>
@@ -323,34 +339,39 @@
<translation id="4522570452068850558">Detaljer</translation>
<translation id="4558551763791394412">Prøv at deaktivere dine udvidelser.</translation>
<translation id="4587425331216688090">Vil du fjerne adressen fra Chrome?</translation>
+<translation id="4589078953350245614">Du har forsøgt at fĂ¥ forbindelse til <ph name="DOMAIN" />, men serveren præsenterede et ugyldigt certifikat. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Din forbindelse til <ph name="DOMAIN" /> er krypteret ved hjælp af en moderne krypteringspakke.</translation>
<translation id="4594403342090139922">&amp;Fortryd sletning</translation>
+<translation id="4627442949885028695">Fortsæt fra en anden enhed</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Du er i øjeblikket pĂ¥ en udvidelsesside.</translation>
-<translation id="467662567472608290">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da sikkerhedscertifikatet indeholder fejl. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> blev blokeret</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Din forbindelse blev afbrudt</translation>
-<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Kører Windows Netværksdiagnosticering<ph name="END_LINK" /></translation>
+<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Køre Windows Netværksdiagnosticering<ph name="END_LINK" /></translation>
<translation id="4726672564094551039">Opdater politikker</translation>
<translation id="4728558894243024398">Platform</translation>
<translation id="4744603770635761495">Eksekverbar sti</translation>
<translation id="4756388243121344051">&amp;Historik</translation>
+<translation id="4759238208242260848">Downloads</translation>
<translation id="4764776831041365478">Websiden pĂ¥ <ph name="URL" /> kan være midlertidigt nede, eller ogsĂ¥ er den permanent flyttet til en ny webadresse.</translation>
<translation id="4771973620359291008">Der er opstĂ¥et en ukendt fejl.</translation>
<translation id="4782449893814226250">Du har spurgt dine forældre, om det er i orden at besøge denne side.</translation>
<translation id="4800132727771399293">Kontrollér, om din kontrolkode og udløbsdato er korrekte, og prøv igen.</translation>
-<translation id="4807049035289105102">Du kan ikke gĂ¥ til <ph name="SITE" /> lige nu, da websitet sendte krypterede legitimationsoplysninger, som Google Chrome ikke kan hĂ¥ndtere. Netværksfejl og angreb er normalt midlertidige, sĂ¥ denne side vil sandsynligvis fungere senere.</translation>
<translation id="4813512666221746211">Netværksfejl</translation>
<translation id="4816492930507672669">Tilpas til siden</translation>
<translation id="4850886885716139402">Vis</translation>
<translation id="4880827082731008257">Søg i historikken</translation>
+<translation id="4884656795097055129">Der vises flere artikler, nĂ¥r det er relevant.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{og 1 anden webside}one{og # anden webside}other{og # andre websider}}</translation>
<translation id="4923417429809017348">Denne side er oversat fra et ukendt sprog til <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Skal angives.</translation>
<translation id="4930497775425430760">Denne meddelelse vises, fordi en af dine forældre skal godkende nye websites, første gang du besøger dem.</translation>
<translation id="495170559598752135">Handlinger</translation>
<translation id="4958444002117714549">Udvid liste</translation>
+<translation id="4962322354953122629">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da Chrome ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Vil du oversætte fra <ph name="ORIGINAL_LANGUAGE" /> til <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Dette plugin understøttes ikke</translation>
<translation id="5002932099480077015">Hvis denne indstilling er slĂ¥et til, gemmer Chrome en kopi af dit kort pĂ¥ denne enhed for at gøre det hurtigere at udfylde formularer.</translation>
<translation id="5019198164206649151">Sikkerhedskopien er fejlbehæftet</translation>
<translation id="5023310440958281426">Læs din administrators politikker</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Om Google Oversæt</translation>
<translation id="5040262127954254034">Beskyttelse af personlige oplysninger</translation>
<translation id="5045550434625856497">Ugyldig adgangskode</translation>
+<translation id="5056549851600133418">Artikler til dig</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Tjekke proxy-adressen<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Serverens certifikatet er ikke gyldigt i øjeblikket.</translation>
<translation id="5089810972385038852">Delstat</translation>
-<translation id="5094747076828555589">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da Chromium ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="5095208057601539847">Provins</translation>
<translation id="5115563688576182185">(64-bit)</translation>
-<translation id="5122371513570456792">Der blev fundet <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for "<ph name="SEARCH_STRING" />".</translation>
<translation id="5141240743006678641">Krypter synkroniserede adgangskoder med dine Google-loginoplysninger</translation>
<translation id="5145883236150621069">Fejlkode til stede i politiksvar</translation>
<translation id="5171045022955879922">Søg, eller indtast webadresse</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Bogmærkelinje</translation>
<translation id="5199729219167945352">Eksperimenter</translation>
<translation id="5251803541071282808">Skyen</translation>
+<translation id="5277279256032773186">Bruger du Chrome pĂ¥ arbejdet? Virksomheder kan administrere Chrome-indstillinger for deres medarbejdere. FĂ¥ flere oplysninger</translation>
<translation id="5299298092464848405">Der opstod en fejl ved parsing af politik</translation>
<translation id="5300589172476337783">Vis</translation>
<translation id="5308689395849655368">Rapportering af nedbrud er deaktiveret.</translation>
<translation id="5317780077021120954">Gem</translation>
<translation id="5327248766486351172">Navn</translation>
+<translation id="5359637492792381994">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet ikke er gyldigt i øjeblikket. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Der kunne ikke gemmes indstillinger for politik</translation>
-<translation id="540969355065856584">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat ikke er gyldigt i øjeblikket. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="5421136146218899937">Ryd browserdata...</translation>
<translation id="5430298929874300616">Fjern bogmærke</translation>
<translation id="5431657950005405462">Din fil blev ikke fundet</translation>
<translation id="5435775191620395718">Viser historik fra denne enhed. <ph name="BEGIN_LINK" />FĂ¥ flere oplysninger<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Du modtager i øjeblikket ikke forslag til brugertilpasset indhold, da dine synkroniserede data beskyttes med en brugerdefineret adgangssætning.</translation>
<translation id="5439770059721715174">Skemavalideringsfejl pĂ¥ "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Denne side fra <ph name="HOST_NAME" /> kan ikke findes</translation>
<translation id="5455374756549232013">Forkert tidsstempel for politik</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Vil du forlade denne side?</translation>
<translation id="5629630648637658800">Der kunne ikke indlæses indstillinger for politik</translation>
<translation id="5631439013527180824">Ugyldigt token for enhedsadministration</translation>
-<translation id="5650551054760837876">Ingen søgeresultater fundet.</translation>
<translation id="5677928146339483299">Blokeret</translation>
<translation id="5710435578057952990">Dette websites identitet er ikke blevet bekræftet.</translation>
<translation id="5720705177508910913">Aktuel bruger</translation>
+<translation id="572328651809341494">Seneste faner</translation>
<translation id="5784606427469807560">Der opstod et problem under bekræftelsen af dit kort. Kontrollér, at du har forbindelse til internettet, og prøv igen.</translation>
<translation id="5785756445106461925">Desuden indeholder denne side andre ressourcer, som ikke er sikre. Disse ressourcer kan ses af andre under overførslen og kan ændres af en hacker, sĂ¥ siden ser anderledes ud.</translation>
+<translation id="5786044859038896871">Skal dine kortoplysninger udfyldes?</translation>
+<translation id="5803412860119678065">Skal <ph name="CARD_DETAIL" /> udfyldes?</translation>
<translation id="5810442152076338065">Din forbindelse til <ph name="DOMAIN" /> er krypteret ved hjælp af en forældet krypteringspakke.</translation>
<translation id="5813119285467412249">&amp;Annuller fortryd tilføjelse</translation>
+<translation id="5814352347845180253">Du kan miste adgangen til Premium-indhold pĂ¥ <ph name="SITE" /> og visse andre websites.</translation>
+<translation id="5843436854350372569">Du har forsøgt at fĂ¥ forbindelse til <ph name="DOMAIN" />, men serveren har præsenteret et certifikat med en svag nøgle. En hacker kan have knækket den private nøgle, og serveren er muligvis ikke den forventede server (du kommunikerer muligvis med en hacker). <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Denne meddelelse vises, fordi din administrator har blokeret dette website.</translation>
<translation id="5857090052475505287">Ny mappe</translation>
<translation id="5869405914158311789">Der kan ikke oprettes forbindelse til dette website</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Forslag fra forældre</translation>
<translation id="59107663811261420">Denne korttype understøttes ikke af Google Payments for denne sælger. Vælg et andet kort.</translation>
<translation id="59174027418879706">Aktiveret</translation>
+<translation id="5926846154125914413">Du kan miste adgangen til Premium-indhold pĂ¥ visse websites.</translation>
<translation id="5966707198760109579">Uge</translation>
<translation id="5967867314010545767">Fjern fra historik</translation>
<translation id="5975083100439434680">Zoom ud</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Automatisk</translation>
<translation id="6042308850641462728">Mere</translation>
<translation id="6060685159320643512">Vær forsigtig. Disse eksperimenter kan være farlige</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{ingen}=1{1}one{#}other{#}}</translation>
<translation id="6146055958333702838">Kontrollér eventuelle kabler, og genstart alle routere, modemmer eller andre
netværksenheder, du bruger.</translation>
<translation id="614940544461990577">Prøv at:</translation>
<translation id="6150607114729249911">Ups! Du er nødt til at spørge dine forældre, om det er i orden, at du Ă¥bner dette website.</translation>
<translation id="6151417162996330722">Servercertifikatet har en gyldighedsperiode, der er for lang.</translation>
-<translation id="6154808779448689242">Det returnerede token for politikken stemmer ikke overens med det nuværende token</translation>
<translation id="6165508094623778733">Flere oplysninger</translation>
<translation id="6203231073485539293">Kontrollér din internetforbindelse</translation>
<translation id="6218753634732582820">Vil du fjerne adressen fra Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Prøv at deaktivere netværksforslag</translation>
<translation id="6337534724793800597">Filtrer politikker efter navn</translation>
<translation id="6342069812937806050">Lige nu</translation>
+<translation id="6345221851280129312">ukendt størrelse</translation>
<translation id="6355080345576803305">Tilsidesættelse af offentlig session</translation>
<translation id="6358450015545214790">Hvad betyder dette?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 andet forslag}one{# andet forslag}other{# andre forslag}}</translation>
<translation id="6387478394221739770">Er du interesseret i smarte nye Chrome-funktioner? Prøv vores betakanal pĂ¥ chrome.com/beta.</translation>
-<translation id="641480858134062906"><ph name="URL" /> indlæsningen mislykkedes</translation>
+<translation id="6389758589412724634">Chromium løb tør for hukommelse, da websiden skulle vises.</translation>
+<translation id="6416403317709441254">Du kan ikke gĂ¥ til <ph name="SITE" /> lige nu, da websitet sender krypterede loginoplysninger, som Chromium ikke kan behandle. Netværksfejl og hackerangreb er normalt midlertidige, sĂ¥ siden vil sandsynligvis fungere senere. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Kan ikke kontrollere, om certifikatet er tilbagekaldt.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> nægtede at oprette forbindelse.</translation>
<translation id="6445051938772793705">Land</translation>
<translation id="6451458296329894277">Bekræft genindsendelse af formular</translation>
<translation id="6458467102616083041">Ignoreret, fordi standardsøgning er deaktiveret af politikken.</translation>
+<translation id="6462969404041126431">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da sikkerhedscertifikatet muligvis er blevet tilbagekaldt. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Enhedspolitikker</translation>
<translation id="6489534406876378309">Start upload af nedbrud</translation>
<translation id="6529602333819889595">&amp;Annuller fortryd slet</translation>
+<translation id="6534179046333460208">Forslag til Fysisk web</translation>
<translation id="6550675742724504774">Valgmuligheder</translation>
+<translation id="6593753688552673085">mindre end <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Krypteringsmuligheder</translation>
<translation id="662080504995468778">Bliv her</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> -søgning</translation>
-<translation id="6634865548447745291">Du kan ikke gĂ¥ til <ph name="SITE" /> lige nu, da <ph name="BEGIN_LINK" />dette certifikat er blevet tilbagekaldt<ph name="END_LINK" />. Netværksfejl og angreb er normalt midlertidige, sĂ¥ denne side vil sandsynligvis fungere senere.</translation>
<translation id="6644283850729428850">Denne politik er forældet.</translation>
+<translation id="6652240803263749613">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da din computers operativsystem ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Rediger mappe</translation>
<translation id="6660210980321319655">Rapporteret automatisk <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Vil du fjerne formularforslag fra Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Forrige</translation>
<translation id="6710594484020273272">&lt;Indtast søgeterm&gt;</translation>
<translation id="6711464428925977395">Der er noget galt med proxyserveren, eller adressen er forkert.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{ingen}=1{1 element}one{# element}other{# elementer}}</translation>
<translation id="674375294223700098">Ukendt fejl i servercertifikatet.</translation>
<translation id="6753269504797312559">Politikkens værdi</translation>
<translation id="6757797048963528358">Din enhed gik i dvale.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Politikniveauet understøttes ikke.</translation>
<translation id="6895330447102777224">Dit kort er bekræftet</translation>
<translation id="6897140037006041989">Brugeragent</translation>
-<translation id="6903907808598579934">Aktivér synkronisering</translation>
<translation id="6915804003454593391">Bruger:</translation>
<translation id="6957887021205513506">Serverens certifikat ser ud til at være en forfalskning.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Distrikt</translation>
<translation id="6973656660372572881">BĂ¥de faste proxyservere og en webadresse for .pac-script angives.</translation>
<translation id="6989763994942163495">Vis avancerede indstillinger...</translation>
+<translation id="7000990526846637657">Der blev ikke fundet nogen poster i historikken</translation>
+<translation id="7009986207543992532">Du forsøgte at fĂ¥ forbindelse til <ph name="DOMAIN" />, men serveren præsenterede et certifikat, hvis gyldighedsperiode er for lang til at være pĂ¥lidelig. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Din Google-konto kan have andre former for browserhistorik pĂ¥ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="7029809446516969842">Adgangskoder</translation>
-<translation id="7050187094878475250">Du forsøgte at gĂ¥ til <ph name="DOMAIN" />, men serveren præsenterede et certifikat, hvis gyldighedsperiode er for lang til at være pĂ¥lidelig.</translation>
<translation id="7087282848513945231">Amt/region</translation>
<translation id="7088615885725309056">Ældre</translation>
<translation id="7090678807593890770">Søg efter <ph name="LINK" /> pĂ¥ Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Denne meddelelse vises, fordi din administrator skal godkende nye websites, første gang du besøger dem.</translation>
<translation id="724975217298816891">Opdater dine kortoplysninger ved at indtaste udløbsdatoen og kontrolkoden for <ph name="CREDIT_CARD" />. NĂ¥r du bekræfter, deles dine kortoplysninger med dette website.</translation>
<translation id="725866823122871198">Der kunne ikke oprettes en privat forbindelse til <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, da dato og tid (<ph name="DATE_AND_TIME" />) pĂ¥ din enhed er forkerte.</translation>
-<translation id="7265986070661382626">Du kan ikke gĂ¥ til <ph name="SITE" /> lige nu, da websitet <ph name="BEGIN_LINK" />anvender certifikatlĂ¥sning<ph name="END_LINK" />. Netværksfejl og angreb er normalt midlertidige, sĂ¥ denne side vil sandsynligvis fungere senere.</translation>
<translation id="7269802741830436641">Denne webside har et loop ved omdirigering</translation>
<translation id="7275334191706090484">Administrerede bogmærker</translation>
<translation id="7298195798382681320">Anbefalet</translation>
-<translation id="7301833672208172928">Aktivér synkronisering af historik</translation>
+<translation id="7309308571273880165">Nedbrudsrapport registreret <ph name="CRASH_TIME" /> (upload, som brugeren anmodede om, er endnu ikke uploadet)</translation>
<translation id="7334320624316649418">&amp;Annuller fortryd omarrangering</translation>
<translation id="733923710415886693">Servercertifikatet blev ikke fremvist via Certifikatsgennemsigtighed.</translation>
+<translation id="7351800657706554155">Du kan ikke gĂ¥ til <ph name="SITE" /> lige nu, da dette certifikat er blevet tilbagekaldt. Netværksfejl og hackerangreb er normalt midlertidige, sĂ¥ denne side vil sandsynligvis fungere senere. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Kommandolinje</translation>
<translation id="7372973238305370288">søgeresultat</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="7469372306589899959">Bekræfter kort</translation>
<translation id="7481312909269577407">Frem</translation>
<translation id="7485870689360869515">Der blev ikke fundet nogen data.</translation>
+<translation id="7508255263130623398">Det returnerede enheds-id for politikken er tomt eller stemmer ikke overens med det nuværende enheds-id</translation>
<translation id="7514365320538308">Download</translation>
<translation id="7518003948725431193">Ingen webside fundet pĂ¥ webadressen: <ph name="URL" /></translation>
<translation id="7537536606612762813">Obligatorisk</translation>
<translation id="7542995811387359312">Automatisk udfyldning af kreditkort er deaktiveret, fordi formularen ikke bruger en sikker forbindelse.</translation>
<translation id="7549584377607005141">Denne webside kræver data, du tidligere har indtastet, før den kan vises korrekt. Du kan sende disse data igen, men hvis du gør dette, gentager du enhver handling, som denne side tidligere har foretaget.</translation>
<translation id="7554791636758816595">Ny fane</translation>
-<translation id="7567204685887185387">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da sikkerhedscertifikatet er udstedt pĂ¥ ulovlig vis. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="7568593326407688803">Denne side er pĂ¥<ph name="ORIGINAL_LANGUAGE" />Vil du oversætte den?</translation>
<translation id="7569952961197462199">Vil du fjerne kreditkortet fra Chrome?</translation>
<translation id="7578104083680115302">Betal hurtigt pĂ¥ websites og i apps pĂ¥ alle enheder ved hjælp af kort, du har gemt med Google.</translation>
+<translation id="7588950540487816470">Fysisk web</translation>
<translation id="7592362899630581445">Begrænsningerne for serverens certifikatnavn er overtrĂ¥dt.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> kan i øjeblikket ikke behandle denne anmodning.</translation>
<translation id="7600965453749440009">Oversæt aldrig <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="7637571805876720304">Vil du fjerne kreditkortet fra Chromium?</translation>
<translation id="765676359832457558">Skjul avancerede indstillinger...</translation>
<translation id="7658239707568436148">Annuller</translation>
+<translation id="7667346355482952095">Det returnerede token for politikken er tomt eller stemmer ikke overens med det nuværende token</translation>
<translation id="7668654391829183341">Ukendt enhed</translation>
<translation id="7674629440242451245">Er du interesseret i smarte nye Chrome-funktioner? Prøv vores udviklerkanal pĂ¥ chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Fortsæt til <ph name="SITE" /> (usikkert)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="780301667611848630">Nej tak</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7813600968533626083">Vil du fjerne formularforslaget fra Chrome?</translation>
+<translation id="7815407501681723534">Der blev fundet <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for "<ph name="SEARCH_STRING" />"</translation>
<translation id="785549533363645510">Du er dog ikke usynlig. Inkognitotilstand skjuler ikke din browserhistorik over for din arbejdsgiver, din internetudbyder eller de websites, du besøger.</translation>
<translation id="7887683347370398519">Kontrollér, om din kontrolkode er korrekt, og prøv igen.</translation>
<translation id="7894616681410591072">Ups! Du skal have tilladelse fra <ph name="NAME" /> for at fĂ¥ adgang til dette website.</translation>
-<translation id="790025292736025802"><ph name="URL" /> blev ikke fundet</translation>
<translation id="7912024687060120840">I mappe:</translation>
<translation id="7920092496846849526">Du har spurgt en af dine forældre, om det er i orden, at du besøger denne side.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,17 +628,19 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="7995512525968007366">Ikke angivet</translation>
<translation id="8012647001091218357">Vi kan ikke fĂ¥ kontakt til dine forældre pĂ¥ nuværende tidspunkt. Prøv igen.</translation>
<translation id="8034522405403831421">Denne side er pĂ¥ <ph name="SOURCE_LANGUAGE" />. Vil du oversætte den til <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Der blev ikke fundet nogen poster i historikken.</translation>
<translation id="8088680233425245692">Artiklen kunne ikke vises.</translation>
+<translation id="8089520772729574115">mindre end 1 MB</translation>
<translation id="8091372947890762290">Aktivering afventer serveren</translation>
+<translation id="8129262335948759431">ukendt mængde</translation>
<translation id="8131740175452115882">Bekræft</translation>
-<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />DNS-adressen<ph name="END_ABBR" /> for <ph name="HOST_NAME" />'s server kunne ikke findes.</translation>
+<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />DNS-adressen<ph name="END_ABBR" /> for <ph name="HOST_NAME" />s server blev ikke fundet.</translation>
<translation id="8149426793427495338">Din computer gik i dvale.</translation>
<translation id="8150722005171944719">Filen i <ph name="URL" /> kan ikke læses. Den kan være blevet fjernet, flyttet, eller ogsĂ¥ forhindrer filtilladelser muligvis adgangen.</translation>
<translation id="8194797478851900357">&amp;Fortryd flytning</translation>
<translation id="8201077131113104583">Ugyldig webadresse til opdatering for udvidelse med id'et "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Tildelt placering:</translation>
<translation id="8225771182978767009">Den person, der har konfigureret denne computer, har valgt at blokere dette website.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Siden, du søger, benyttede oplysninger, du har indtastet. Vender du tilbage til denne side kan det betyde, at enhver handling, du har foretaget, skal gentages. Vil du fortsætte?</translation>
<translation id="8249320324621329438">Sidste hentet:</translation>
<translation id="8261506727792406068">Slet</translation>
@@ -616,12 +653,17 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="8349305172487531364">Bogmærkelinje</translation>
<translation id="8363502534493474904">Deaktivere flytilstand</translation>
<translation id="8364627913115013041">Ikke angivet.</translation>
+<translation id="8380941800586852976">Farlig</translation>
<translation id="8412145213513410671">Nedbrud (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Du skal angive den samme adgangssætning to gange.</translation>
<translation id="8428213095426709021">Indstillinger</translation>
+<translation id="8433057134996913067">Dette logger dig ud af de fleste websites.</translation>
<translation id="8437238597147034694">&amp;Fortryd flytning</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kreditkort}one{# kreditkort}other{# kreditkort}}</translation>
+<translation id="8483780878231876732">Hvis du vil bruge kort fra din Google-konto, skal du logge ind i Chrome</translation>
<translation id="8488350697529856933">Gælder for</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> var for lang tid om at svare.</translation>
+<translation id="852346902619691059">Denne server kunne ikke bevise, at den tilhører <ph name="DOMAIN" />, da din enheds operativsystem ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse. <ph name="BEGIN_LEARN_MORE_LINK" />FĂ¥ flere oplysninger<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Denne korttype understøttes ikke af Google Payments. Vælg et andet kort.</translation>
<translation id="8550022383519221471">Synkroniseringstjenesten er ikke tilgængelig for dit domæne.</translation>
<translation id="8553075262323480129">Oversættelsen mislykkedes, fordi sidens sprog ikke kunne fastslĂ¥s.</translation>
@@ -633,15 +675,12 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="8647750283161643317">Nulstil alle til standard</translation>
<translation id="8680787084697685621">Oplysningerne om kontologin er forældede.</translation>
<translation id="8703575177326907206">Din forbindelse til <ph name="DOMAIN" /> er ikke krypteret.</translation>
-<translation id="8713130696108419660">Ugyldig første signatur</translation>
<translation id="8725066075913043281">Forsøg igen</translation>
<translation id="8728672262656704056">Du er nu i inkognitotilstand</translation>
-<translation id="8730621377337864115">Fuldført</translation>
+<translation id="8730621377337864115">Udfør</translation>
<translation id="8738058698779197622">For at kunne oprette en sikker forbindelse skal dit ur være indstillet korrekt. Det er vigtigt, da de certifikater, som websites bruger til at identificere sig selv, kun er gyldige i bestemte tidsperioder. Da uret pĂ¥ din enhed gĂ¥r forkert, kan Chromium ikke bekræfte disse certifikater.</translation>
-<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS-adressen&lt;/abbr&gt; for <ph name="HOST_NAME" /> kunne ikke findes. Diagnosticerer problemet.</translation>
-<translation id="8741995161408053644">Din Google-konto kan have andre former for browserhistorik pĂ¥ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
+<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS-adressen&lt;/abbr&gt; for <ph name="HOST_NAME" /> blev ikke fundet. Diagnosticerer problemet.</translation>
<translation id="8790007591277257123">&amp;Annuller fortryd sletning</translation>
-<translation id="8790687370365610530">AktivĂ©r synkronisering af historik for at hente brugertilpasset indhold, der er foreslĂ¥et af Google.</translation>
<translation id="8798099450830957504">Standard</translation>
<translation id="8804164990146287819">Privatlivspolitik</translation>
<translation id="8820817407110198400">Bogmærker</translation>
@@ -663,13 +702,11 @@ Psst! Prøv at bruge Inkognitotilstand <ph name="SHORTCUT_KEY" /> næste gang.</
<translation id="8971063699422889582">Serverens certifikat er udløbet.</translation>
<translation id="8987927404178983737">MĂ¥ned</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Serveren viste et certifikat, der ikke blev fremvist offentligt ved hjælp af politikken for Certifikatsgennemsigtighed. Dette pĂ¥kræves for nogle certifikater for at sikre, at de er troværdige, og beskytter mod hackere.</translation>
<translation id="9001074447101275817">Proxyserveren <ph name="DOMAIN" /> kræver et brugernavn og en adgangskode.</translation>
<translation id="901974403500617787">Markeringer, der gælder for hele systemet, kan kun indstilles af ejeren: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Denne side er oversat til <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Brug en forudsigelsestjeneste til hurtigere sideindlæsning</translation>
<translation id="9039213469156557790">Desuden indeholder denne side andre ressourcer, som ikke er sikre. Disse ressourcer kan ses af andre under overførslen og kan ændres af en hacker, sĂ¥ siden opfører sig anderledes.</translation>
-<translation id="9049981332609050619">Du har forsøgt at nĂ¥ <ph name="DOMAIN" />, men serveren præsenterede et ugyldigt certifikat.</translation>
<translation id="9050666287014529139">Adgangssætning</translation>
<translation id="9065203028668620118">Rediger</translation>
<translation id="9092364396508701805">Siden fra <ph name="HOST_NAME" /> fungerer ikke</translation>
diff --git a/chromium/components/strings/components_strings_de.xtb b/chromium/components/strings/components_strings_de.xtb
index ed16837ff3d..255273cc1b3 100644
--- a/chromium/components/strings/components_strings_de.xtb
+++ b/chromium/components/strings/components_strings_de.xtb
@@ -1,24 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="de">
+<translation id="1008557486741366299">Jetzt nicht</translation>
<translation id="1015730422737071372">Weitere Details angeben</translation>
<translation id="1032854598605920125">Im Uhrzeigersinn drehen</translation>
<translation id="1038842779957582377">Unbekannter Name</translation>
+<translation id="1053591932240354961">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website verschlĂ¼sselte Anmeldedaten gesendet hat, die von Google Chrome nicht verarbeitet werden können. Netzwerkfehler und Angriffe sind in der Regel nur vorĂ¼bergehend, sodass die Seite wahrscheinlich später wieder funktioniert. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">&amp;HinzufĂ¼gen rĂ¼ckgängig machen</translation>
<translation id="10614374240317010">Nie speichern fĂ¼r…</translation>
-<translation id="1064422015032085147">Der Server, auf dem die Webseite gehostet wird, ist möglicherweise Ă¼berlastet
- oder wird u. U. gewartet. Um nicht zu viel Traffic zu generieren und die
- Situation nicht zu verschlimmern, sind Anfragen an diese URL vorĂ¼bergehend
- nicht zulässig.</translation>
<translation id="106701514854093668">Desktop-Lesezeichen</translation>
<translation id="1080116354587839789">An Breite anpassen</translation>
+<translation id="1103124106085518534">Fertig</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> immer Ă¼bersetzen</translation>
<translation id="1107591249535594099">Bei Aktivierung speichert Chrome eine Kopie Ihrer Karte auf diesem Gerät, damit Formulare schneller ausgefĂ¼llt werden können.</translation>
+<translation id="1111153019813902504">Vor Kurzem gespeicherte Lesezeichen</translation>
<translation id="1113869188872983271">&amp;Neu anordnen rĂ¼ckgängig machen</translation>
+<translation id="1126551341858583091">Die GrĂ¶ĂŸe auf dem lokalen Speicher ist <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Richtlinien-Cache einwandfrei</translation>
<translation id="113188000913989374">Unter <ph name="SITE" /> wird Folgendes angezeigt:</translation>
<translation id="1132774398110320017">AutoFill-Einstellungen fĂ¼r Chrome...</translation>
-<translation id="1150979032973867961">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem Ihres Computers als nicht vertrauenswĂ¼rdig eingestuft. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="1152921474424827756">Rufen Sie eine <ph name="BEGIN_LINK" />im Cache gespeicherte Kopie<ph name="END_LINK" /> von <ph name="URL" /> auf.</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> hat die Verbindung unerwartet geschlossen.</translation>
<translation id="1161325031994447685">WLAN-Verbindung erneut herstellen</translation>
@@ -26,7 +26,8 @@
<translation id="1181037720776840403">Entfernen</translation>
<translation id="1201402288615127009">Weiter</translation>
<translation id="1201895884277373915">Mehr von dieser Website</translation>
-<translation id="121201262018556460">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat jedoch ein Zertifikat mit einem schwachen SchlĂ¼ssel Ă¼bermittelt. Ein Hacker könnte den privaten SchlĂ¼ssel geknackt haben, sodass es sich möglicherweise nicht um den erwarteten Server handelt, sondern Sie stattdessen mit einem Hacker kommunizieren.</translation>
+<translation id="1206967143813997005">Erste Signatur ungĂ¼ltig</translation>
+<translation id="1209206284964581585">Vorerst ausblenden</translation>
<translation id="1219129156119358924">Systemsicherheit</translation>
<translation id="1227224963052638717">Unbekannte Richtlinie</translation>
<translation id="1227633850867390598">Wert ausblenden</translation>
@@ -47,6 +48,7 @@
<translation id="1426410128494586442">Ja</translation>
<translation id="1430915738399379752">Drucken</translation>
<translation id="1442912890475371290">Versuch zum <ph name="BEGIN_LINK" />Besuch einer Seite unter <ph name="DOMAIN" /><ph name="END_LINK" /> blockiert</translation>
+<translation id="1491663344921578213">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website das Zertifikats-Pinning nutzt. Netzwerkfehler und Angriffe sind in der Regel nur vorĂ¼bergehend, sodass die Seite später wahrscheinlich wieder funktioniert. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">Zeigt eine gespeicherte (veraltete) Kopie dieser Seite an</translation>
<translation id="1519264250979466059">Build-Datum</translation>
<translation id="1549470594296187301">FĂ¼r diese Funktion muss JavaScript aktiviert sein.</translation>
@@ -61,36 +63,34 @@
<translation id="1644184664548287040">Die Netzwerkkonfiguration ist ungĂ¼ltig und konnte nicht importiert werden.</translation>
<translation id="1644574205037202324">Verlauf</translation>
<translation id="1645368109819982629">Nicht unterstĂ¼tztes Protokoll</translation>
-<translation id="1655462015569774233">{1,plural, =1{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist gestern abgelaufen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. Die Uhr Ihres Computers ist derzeit auf <ph name="CURRENT_DATE" /> eingestellt. Ist das korrekt? Falls nicht, stellen Sie die Uhr Ihres Systems richtig ein und aktualisieren Sie anschlieĂŸend diese Seite.}other{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist vor # Tagen abgelaufen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. Die Uhr Ihres Computers ist derzeit auf <ph name="CURRENT_DATE" /> eingestellt. Ist das korrekt? Falls nicht, stellen Sie die Uhr Ihres Systems richtig ein und aktualisieren Sie anschlieĂŸend diese Seite.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> schĂ¼tzt Ihre Daten in der Regel durch VerschlĂ¼sselung. Als Google Chrome dieses Mal versuchte, eine Verbindung zu <ph name="SITE" /> herzustellen, gab die Website ungewöhnliche und falsche Anmeldedaten zurĂ¼ck. Entweder versucht ein Angreifer, sich als <ph name="SITE" /> auszugeben, oder die Verbindung wurde durch eine WLAN-Anmeldeseite unterbrochen. Da Google Chrome die Verbindung vor dem Austausch von Daten unterbrochen hat, sind Ihre Informationen weiterhin sicher.</translation>
<translation id="168841957122794586">Das Serverzertifikat weist einen schwachen kryptografischen SchlĂ¼ssel auf.</translation>
<translation id="1701955595840307032">Vorgeschlagene Inhalte erhalten</translation>
-<translation id="1706954506755087368">{1,plural, =1{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gilt vermutlich erst ab morgen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.}other{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gilt vermutlich erst in # Tagen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.}}</translation>
<translation id="1710259589646384581">Betriebssystem</translation>
<translation id="1734864079702812349">American Express</translation>
<translation id="1734878702283171397">Setzen Sie sich mit dem Systemadministrator in Verbindung.</translation>
<translation id="17513872634828108">Geöffnete Tabs</translation>
<translation id="1753706481035618306">Seitenzahl</translation>
-<translation id="1761412452051366565">Aktivieren Sie die Synchronisierung, um personalisierte, von Google vorgeschlagene Inhalte zu erhalten.</translation>
-<translation id="1763864636252898013">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem Ihres Geräts als nicht vertrauenswĂ¼rdig eingestuft. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Versuchen Sie, die Windows-Netzwerkdiagnose auszufĂ¼hren.<ph name="END_LINK" /></translation>
<translation id="1783075131180517613">Synchronisierungs-Passphrase aktualisieren</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Hier werden Ihre kĂ¼rzlich aufgerufenen Lesezeichen angezeigt.</translation>
<translation id="1821930232296380041">Anfrage oder Anfrageparameter ungĂ¼ltig</translation>
<translation id="1838667051080421715">Dies ist die Quelle einer Webseite.</translation>
<translation id="1871208020102129563">Der Proxy ist zur Verwendung von festen Proxyservern konfiguriert, nicht zur Verwendung einer PAC-Skript-URL.</translation>
<translation id="1883255238294161206">Liste ausblenden</translation>
<translation id="1898423065542865115">Filtern</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> hat Ihr Anmeldezertifikat nicht akzeptiert oder Ihr Anmeldezertifikat ist möglicherweise abgelaufen.</translation>
<translation id="194030505837763158">Besuchen Sie die Seite <ph name="LINK" />.</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" />-Lesezeichen</translation>
<translation id="1973335181906896915">Fehler bei der Serialisierung</translation>
<translation id="1974060860693918893">Erweitert</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{und 1 weitere}other{und # weitere}}</translation>
<translation id="2025186561304664664">Proxy ist auf automatische Konfiguration eingestellt.</translation>
<translation id="2030481566774242610">Meinten Sie <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Diese Nachricht wird dir angezeigt, weil deine Eltern neue Websites zuerst genehmigen mĂ¼ssen, bevor du sie öffnen kannst.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Proxy und Firewall prĂ¼fen<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Postleitzahl</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 Vorschlag}other{# Vorschläge}}</translation>
<translation id="2065985942032347596">Authentifizierung erforderlich</translation>
<translation id="2079545284768500474">RĂ¼ckgängig</translation>
<translation id="20817612488360358">Die System-Proxy-Einstellungen sind zur Verwendung angegeben, gleichzeitig wurde aber auch eine explizite Proxy-Konfiguration festgelegt.</translation>
@@ -106,32 +106,34 @@
<translation id="2149973817440762519">Lesezeichen bearbeiten</translation>
<translation id="2166049586286450108">Vollständiger Administratorzugriff</translation>
<translation id="2166378884831602661">Diese Website kann keine sichere Verbindung bereitstellen</translation>
-<translation id="2171101176734966184">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat jedoch ein Zertifikat Ă¼bermittelt, das einen schwachen Signaturalgorithmus verwendet. Das bedeutet, dass die vom Server Ă¼bermittelten Sicherheitsinformationen gefälscht sein könnten und es sich möglicherweise gar nicht um den erwarteten Server handelt, sondern Sie mit einem Hacker kommunizieren.</translation>
<translation id="2181821976797666341">Richtlinien</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 Adresse}other{# Adressen}}</translation>
<translation id="2212735316055980242">Richtlinie nicht gefunden</translation>
<translation id="2213606439339815911">Einträge werden abgerufen...</translation>
-<translation id="2214283295778284209">Nicht verfĂ¼gbar: <ph name="SITE" /></translation>
<translation id="2230458221926704099">Beheben Sie den Verbindungsfehler mithilfe der <ph name="BEGIN_LINK" />Diagnose-App<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Jetzt senden</translation>
<translation id="225207911366869382">Dieser Wert fĂ¼r die Richtlinie ist veraltet.</translation>
<translation id="2262243747453050782">HTTP-Fehler</translation>
<translation id="2282872951544483773">Nicht verfĂ¼gbare Experimente</translation>
<translation id="2292556288342944218">Ihre Internetverbindung ist gesperrt</translation>
<translation id="229702904922032456">Ein Stamm- oder Zwischenzertifikat ist abgelaufen.</translation>
<translation id="230155334948463882">Neue Karte?</translation>
+<translation id="2305919008529760154">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wurde möglicherweise in betrĂ¼gerischer Absicht ausgegeben. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535">FĂ¼r <ph name="DOMAIN" /> sind ein Nutzername und ein Passwort erforderlich.</translation>
+<translation id="2318774815570432836">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, da die Website HSTS verwendet. Netzwerkfehler und Angriffe sind in der Regel nur vorĂ¼bergehend, sodass die Seite wahrscheinlich später wieder funktioniert. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">UngĂ¼ltiges Lesezeichen bei Index <ph name="ENTRY_INDEX" /> ignoriert</translation>
<translation id="2354001756790975382">Weitere Lesezeichen</translation>
<translation id="2359808026110333948">Weiter</translation>
<translation id="2365563543831475020">Absturzbericht erfasst um <ph name="CRASH_TIME" />, wurde nicht hochgeladen</translation>
<translation id="2367567093518048410">Ebene</translation>
+<translation id="2371153335857947666">{1,plural, =1{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist gestern abgelaufen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. Die Uhr Ihres Computers ist derzeit auf <ph name="CURRENT_DATE" /> eingestellt. Ist das korrekt? Falls nicht, stellen Sie die Uhr Ihres Systems richtig ein und aktualisieren Sie anschlieĂŸend diese Seite. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" />}other{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist vor # Tagen abgelaufen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. Die Uhr Ihres Computers ist derzeit auf <ph name="CURRENT_DATE" /> eingestellt. Ist das korrekt? Falls nicht, stellen Sie die Uhr Ihres Systems richtig ein und aktualisieren Sie anschlieĂŸend diese Seite. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">Keine Alternativen fĂ¼r die Benutzeroberfläche verfĂ¼gbar</translation>
<translation id="2384307209577226199">Standardeinstellung durch Unternehmen</translation>
-<translation id="238526402387145295"><ph name="SITE" /> kann zurzeit nicht aufgerufen werden, da die Website <ph name="BEGIN_LINK" />HSTS verwendet<ph name="END_LINK" />. Netzwerkfehler und Angriffe sind in der Regel nur vorĂ¼bergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="2386255080630008482">Das Serverzertifikat wurde aufgehoben.</translation>
<translation id="2392959068659972793">Richtlinien ohne Wert zeigen</translation>
<translation id="2396249848217231973">&amp;Löschen rĂ¼ckgängig machen</translation>
-<translation id="2413528052993050574">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wurde möglicherweise widerrufen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="2455981314101692989">Auf dieser Webseite ist die AutoFill-Funktion fĂ¼r das Formular deaktiviert.</translation>
+<translation id="2463739503403862330">AusfĂ¼llen</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Netzwerkdiagnose ausfĂ¼hren<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">UngĂ¼ltige Such-URL</translation>
<translation id="2491120439723279231">Das Serverzertifikat enthält Fehler.</translation>
@@ -153,10 +155,12 @@
<translation id="2653659639078652383">Senden</translation>
<translation id="2674170444375937751">Möchten Sie diese Seiten wirklich aus dem Verlauf löschen?</translation>
<translation id="2677748264148917807">Verlassen</translation>
+<translation id="269990154133806163">Der Server hat ein Zertifikat Ă¼bermittelt, das nicht gemĂ¤ĂŸ der Richtlinien zur Zertifikatstransparenz öffentlich offengelegt wurde. Dies ist fĂ¼r einige Zertifikate jedoch eine Voraussetzung, mit der sichergestellt wird, dass sie vertrauenswĂ¼rdig sind und vor Angriffen schĂ¼tzen. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">Wert stimmt nicht mit dem Format Ă¼berein.</translation>
<translation id="2704951214193499422">Ihre Karte kann von Chromium zurzeit nicht bestätigt werden. Bitte versuchen Sie es später noch einmal.</translation>
<translation id="2705137772291741111">Die (im Cache) gespeicherte Kopie dieser Website war nicht lesbar.</translation>
<translation id="2709516037105925701">AutoFill</translation>
+<translation id="2712118517637785082">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, das vom Server Ă¼bermittelte Zertifikat wurde jedoch vom entsprechenden Aussteller widerrufen. Das bedeutet, dass die vom Server Ă¼bermittelten Sicherheitsinformationen nicht vertrauenswĂ¼rdig sind. Möglicherweise kommunizieren Sie mit einem Hacker. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">Berechtigung anfordern</translation>
<translation id="2721148159707890343">Anfrage erfolgreich</translation>
<translation id="2728127805433021124">Das Serverzertifikat ist mit einem schwachen Signaturalgorithmus signiert.</translation>
@@ -168,14 +172,11 @@
<translation id="2824775600643448204">Adress- und Suchleiste</translation>
<translation id="2826760142808435982">Die Verbindung ist mit <ph name="CIPHER" /> verschlĂ¼sselt und authentifiziert und verwendet <ph name="KX" /> als Mechanismus fĂ¼r den SchlĂ¼sselaustausch.</translation>
<translation id="2835170189407361413">Formular leeren</translation>
-<translation id="2837049386027881519">Das Herstellen der Verbindung musste mit einer älteren Version des TLS- oder SSL-Protokolls wiederholt werden. Normalerweise bedeutet dies, dass der Server sehr alte Software verwendet und möglicherweise andere Sicherheitsprobleme bestehen.</translation>
<translation id="284702764277384724">Das Serverzertifikat bei <ph name="HOST_NAME" /> ist anscheinend eine Fälschung.</translation>
<translation id="2889159643044928134">Nicht neu laden</translation>
-<translation id="2896499918916051536">Dieses Plug-in wird nicht unterstĂ¼tzt.</translation>
+<translation id="2900469785430194048">Beim Versuch, diese Webseite aufzurufen, hat Google Chrome das Arbeitsspeicherlimit erreicht.</translation>
<translation id="2909946352844186028">Eine Netzwerkänderung ist aufgetreten.</translation>
-<translation id="2915500479781995473">Dieser Server konnte nicht nachweisen, dass es sich dabei um <ph name="DOMAIN" /> handelt, da das Sicherheitszertifikat abgelaufen ist. Der Grund hierfĂ¼r könnte eine fehlerhafte Konfiguration oder ein Angreifer sein, der Ihre Verbindung abfängt. Die Uhr Ihres Computers zeigt derzeit <ph name="CURRENT_TIME" /> an. Ist das korrekt? Falls nicht, stellen Sie die Uhr Ihres Systems richtig ein und aktualisieren Sie dann diese Seite.</translation>
<translation id="2922350208395188000">Das Serverzertifikat kann nicht Ă¼berprĂ¼ft werden.</translation>
-<translation id="2941952326391522266">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat stammt von <ph name="DOMAIN2" />. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="2948083400971632585">Sie können alle fĂ¼r eine Verbindung konfigurierten Proxys auf der Seite "Einstellungen" deaktivieren.</translation>
<translation id="2955913368246107853">Suchleiste schlieĂŸen</translation>
<translation id="2958431318199492670">Die Netzwerkkonfiguration stimmt nicht mit dem ONC-Standard Ă¼berein. Die Konfiguration wird unter Umständen nicht vollständig importiert.</translation>
@@ -189,6 +190,7 @@
<translation id="3024663005179499861">Falscher Richtlinientyp</translation>
<translation id="3032412215588512954">Möchten Sie diese Website neu laden?</translation>
<translation id="3037605927509011580">Oh nein!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{mindestens 1 Inhalt auf synchronisierten Geräten}=1{1 Inhalt (und weitere auf synchronisierten Geräten)}other{# Inhalte (und weitere auf synchronisierten Geräten)}}</translation>
<translation id="3041612393474885105">Zertifikatinformationen</translation>
<translation id="3063697135517575841">Ihre Karte kann von Chrome zurzeit nicht bestätigt werden. Bitte versuchen Sie es später noch einmal.</translation>
<translation id="3093245981617870298">Sie sind offline.</translation>
@@ -207,15 +209,16 @@
folgt: <ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Neueste</translation>
<translation id="3207960819495026254">Mit einem Lesezeichen versehen</translation>
-<translation id="3225919329040284222">Der Server hat ein Zertifikat Ă¼bermittelt, das nicht mit den integrierten Erwartungen Ă¼bereinstimmt. Diese Erwartungen sind zu Ihrem Schutz in bestimmten Websites mit hohen Sicherheitsstandards enthalten.</translation>
<translation id="3226128629678568754">Klicken Sie auf die Schaltfläche zum erneuten Laden, um die fĂ¼r das Laden der Seite erforderlichen Daten erneut zu senden.</translation>
<translation id="3228969707346345236">Die Ăœbersetzung ist fehlgeschlagen, weil die Seite bereits auf <ph name="LANGUAGE" /> ist.</translation>
<translation id="323107829343500871">CVC fĂ¼r <ph name="CREDIT_CARD" /> eingeben</translation>
<translation id="3254409185687681395">Lesezeichen fĂ¼r diese Seite erstellen</translation>
<translation id="3270847123878663523">&amp;Neu anordnen rĂ¼ckgängig machen</translation>
<translation id="3286538390144397061">Jetzt neu starten</translation>
+<translation id="3303855915957856445">Keine Suchergebnisse gefunden</translation>
<translation id="3305707030755673451">Ihre Daten wurden am <ph name="TIME" /> mit Ihrer Synchronisierungspassphrase verschlĂ¼sselt. Geben Sie diese ein, um die Synchronisierung zu starten.</translation>
<translation id="333371639341676808">Diese Seite am Erstellen zusätzlicher Dialoge hindern</translation>
+<translation id="3338095232262050444">Sicher</translation>
<translation id="3340978935015468852">Einstellungen</translation>
<translation id="3345135638360864351">Ihre Zugriffsanfrage fĂ¼r diese Website konnte nicht an <ph name="NAME" /> gesendet werden. Bitte versuchen Sie es erneut.</translation>
<translation id="3355823806454867987">Proxy-Einstellungen ändern...</translation>
@@ -233,6 +236,7 @@
<translation id="3452404311384756672">Abrufintervall:</translation>
<translation id="3462200631372590220">Erweiterte Informationen ausblenden</translation>
<translation id="3479539252931486093">Geschah dies unerwartet? <ph name="BEGIN_LINK" />Informieren Sie uns<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Jetzt nicht</translation>
<translation id="348000606199325318">Absturz-ID <ph name="CRASH_LOCAL_ID" /> (Server-ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Wir können deinen Vater bzw. deine Mutter momentan nicht erreichen. Bitte versuche es später erneut.</translation>
<translation id="3527085408025491307">Ordner</translation>
@@ -241,6 +245,7 @@
<translation id="3542684924769048008">Passwort verwenden fĂ¼r:</translation>
<translation id="3549644494707163724">Alle synchronisierten Daten mit Ihrer eigenen Synchronisierungspassphrase verschlĂ¼sseln</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> weitere...</translation>
+<translation id="3555561725129903880">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat stammt von <ph name="DOMAIN2" />. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">Dies ist keine sichere Verbindung</translation>
<translation id="3583757800736429874">&amp;Verschieben wiederholen</translation>
<translation id="3586931643579894722">Details ausblenden</translation>
@@ -251,12 +256,15 @@
<translation id="362276910939193118">Gesamtverlauf anzeigen</translation>
<translation id="3623476034248543066">Wert zeigen</translation>
<translation id="3630155396527302611">Falls das Programm schon in der Liste mit erlaubtem Netzwerkzugriff eingetragen ist, entfernen Sie es aus der Liste und fĂ¼gen Sie es noch einmal hinzu.</translation>
+<translation id="3638794133396384728">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist abgelaufen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. Die Uhr Ihres Computers ist momentan auf <ph name="CURRENT_TIME" /> eingestellt. Ist das korrekt? Falls nicht, stellen Sie die Uhr Ihres Systems richtig ein und aktualisieren Sie anschlieĂŸend diese Seite. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">Diese experimentellen Funktionen können sich jederzeit ändern, abstĂ¼rzen oder deaktiviert werden. Wir Ă¼bernehmen keinerlei Gewährleistung fĂ¼r die Folgen der Aktivierung eines dieser Experimente. Es ist sogar möglich, dass Ihr Browser spontan in Flammen aufgeht. SpaĂŸ beiseite: Es ist möglich, dass Ihr Browser alle Ihre Daten löscht. Möglicherweise werden auch Ihre Sicherheits- und Datenschutzeinstellungen auf unerwartete Weise manipuliert. Alle von Ihnen aktivierten Experimente werden fĂ¼r alle Nutzer dieses Browsers aktiviert. Seien Sie also vorsichtig, wenn Sie fortfahren.</translation>
<translation id="3650584904733503804">ĂœberprĂ¼fung erfolgreich</translation>
<translation id="3655670868607891010">Sollte Ihnen diese Meldung häufiger angezeigt werden, sehen Sie sich unsere <ph name="HELP_LINK" /> an.</translation>
<translation id="3658742229777143148">Ăœberarbeitung</translation>
+<translation id="3678029195006412963">Anfrage konnte nicht signiert werden</translation>
<translation id="3681007416295224113">Zertifikatinformationen</translation>
<translation id="3693415264595406141">Passwort:</translation>
+<translation id="3696411085566228381">keine</translation>
<translation id="3700528541715530410">Hoppla. Sie sind offenbar nicht berechtigt, auf diese Seite zuzugreifen.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Wird geladen...</translation>
@@ -264,7 +272,6 @@
<translation id="3714780639079136834">Mobile Daten oder WLAN aktivieren</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Proxy, Firewall und DNS-Konfiguration prĂ¼fen<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Von Ihnen kopierter Link</translation>
-<translation id="3744899669254331632">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website verschlĂ¼sselte Anmeldedaten gesendet hat, die von Chromium nicht verarbeitet werden können. Netzwerkfehler und Angriffe sind in der Regel nur vorĂ¼bergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="375403751935624634">Aufgrund eines Serverfehlers ist die Ăœbersetzung fehlgeschlagen.</translation>
<translation id="3759461132968374835">Es liegen keine kĂ¼rzlich gemeldeten AbstĂ¼rze vor. AbstĂ¼rze, die bei deaktivierter Absturzberichtsfunktion aufgetreten sind, werden hier nicht angezeigt.</translation>
<translation id="3788090790273268753">Das Zertifikat fĂ¼r diese Website läuft 2016 ab und die Zertifikatskette enthält ein Zertifikat mit SHA-1-Signatur.</translation>
@@ -276,19 +283,25 @@
<translation id="3884278016824448484">In Konflikt stehende Gerätekennung</translation>
<translation id="3885155851504623709">Gemeinde</translation>
<translation id="3901925938762663762">Die Karte ist abgelaufen.</translation>
+<translation id="3910267023907260648">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat jedoch ein Zertifikat Ă¼bermittelt, das einen schwachen Signaturalgorithmus verwendet. Das bedeutet, dass die vom Server Ă¼bermittelten Sicherheitsinformationen gefälscht sein könnten und es sich möglicherweise gar nicht um den erwarteten Server handelt, sondern Sie mit einem Hacker kommunizieren. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gilt vermutlich erst ab morgen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" />}other{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gilt vermutlich erst in # Tagen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">Fehler beim Laden des PDF-Dokuments</translation>
<translation id="3963721102035795474">Lesemodus</translation>
+<translation id="397105322502079400">Wird berechnet...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> ist gesperrt</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 Webseite in der Nähe}other{# Webseiten in der Nähe}}</translation>
<translation id="4021036232240155012">DNS ist der Netzwerkdienst, der den Namen einer Website in die entsprechende Internetadresse umwandelt.</translation>
<translation id="4030383055268325496">&amp;HinzufĂ¼gen rĂ¼ckgängig machen</translation>
-<translation id="4032534284272647190">Zugriff auf <ph name="URL" /> verweigert</translation>
<translation id="404928562651467259">Warnung</translation>
<translation id="4058922952496707368">SchlĂ¼ssel "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Client und Server unterstĂ¼tzen keine gemeinsame SSL-Protokollversion oder VerschlĂ¼sselungssammlung.</translation>
<translation id="4079302484614802869">Die Proxy-Konfiguration ist auf die Verwendung einer PAC-Skript-URL und nicht die von festen Proxyservern eingestellt.</translation>
<translation id="4103249731201008433">Seriennummer des Geräts ist ungĂ¼ltig.</translation>
<translation id="4103763322291513355">Unter &lt;strong&gt;chrome://policy&lt;/strong&gt; finden Sie eine Liste der blockierten URLs und andere Richtlinien, die durch Ihren Systemadministrator erzwungen werden.</translation>
+<translation id="4110615724604346410">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat enthält Fehler. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">Richtlinienbereich wird nicht unterstĂ¼tzt.</translation>
+<translation id="4118212371799607889">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chromium nicht als vertrauenswĂ¼rdig eingestuft. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 weiterer}other{# weitere}}</translation>
<translation id="4130226655945681476">PrĂ¼fen Sie Netzwerkkabel, Modem und Router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Möchten Sie, dass Chromium diese Karte speichert?</translation>
@@ -296,6 +309,7 @@
<translation id="4176463684765177261">Deaktiviert</translation>
<translation id="4196861286325780578">&amp;Verschieben wiederholen</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Firewall und Antivirenkonfiguration prĂ¼fen<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{keine}=1{1 App ($1)}=2{2 Apps ($1, $2)}other{# Apps ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">AbstĂ¼rze</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Versuchen Sie, die Netzwerkdiagnose auszufĂ¼hren.<ph name="END_LINK" /></translation>
<translation id="4250680216510889253">Nein</translation>
@@ -304,14 +318,15 @@
<translation id="4269787794583293679">(Kein Nutzername)</translation>
<translation id="4300246636397505754">Vorschläge fĂ¼r Eltern</translation>
<translation id="4304224509867189079">Anmelden</translation>
+<translation id="432290197980158659">Der Server hat ein Zertifikat Ă¼bermittelt, das nicht mit den integrierten Erwartungen Ă¼bereinstimmt. Diese Erwartungen sind zu Ihrem Schutz in bestimmten Websites mit hohen Sicherheitsstandards enthalten. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">Der Artikel wurde nicht gefunden.</translation>
+<translation id="4331708818696583467">Nicht sicher</translation>
<translation id="4372948949327679948">Erwarteter <ph name="VALUE_TYPE" />-Wert</translation>
-<translation id="4377125064752653719">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, das vom Server Ă¼bermittelte Zertifikat wurde jedoch vom entsprechenden Aussteller widerrufen. Das bedeutet, dass die vom Server Ă¼bermittelten Sicherheitsinformationen nicht vertrauenswĂ¼rdig sind. Möglicherweise kommunizieren Sie mit einem Hacker.</translation>
<translation id="4381091992796011497">Nutzername:</translation>
<translation id="4394049700291259645">Deaktivieren</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> bis <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">Suchergebnisse</translation>
-<translation id="4424024547088906515">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chrome als nicht vertrauenswĂ¼rdig eingestuft. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> hat Ihr Anmeldezertifikat nicht akzeptiert oder es wurde keines bereitgestellt.</translation>
<translation id="443673843213245140">Die Proxy-Nutzung ist deaktiviert, es ist jedoch eine explizite Proxy-Konfiguration festgelegt.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Diese Nachricht wird Ihnen angezeigt, weil Google SafeSites aktiviert ist.</translation>
@@ -323,12 +338,12 @@
<translation id="4522570452068850558">Details</translation>
<translation id="4558551763791394412">Deaktivieren Sie Ihre Erweiterungen.</translation>
<translation id="4587425331216688090">Adresse aus Chrome entfernen?</translation>
+<translation id="4589078953350245614">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat sich jedoch mit einem ungĂ¼ltigen Zertifikat ausgewiesen. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459">Ihre Verbindung zu <ph name="DOMAIN" /> ist mit einer modernen Codier-Suite verschlĂ¼sselt.</translation>
<translation id="4594403342090139922">&amp;Löschen rĂ¼ckgängig machen</translation>
+<translation id="4627442949885028695">Auf einem anderen Gerät fortsetzen</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Sie sehen sich eine Erweiterungsseite an.</translation>
-<translation id="467662567472608290">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat enthält Fehler. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> wurde blockiert.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Ihre Verbindung wurde unterbrochen</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows-Netzwerkdiagnose ausfĂ¼hren<ph name="END_LINK" /></translation>
@@ -336,21 +351,26 @@
<translation id="4728558894243024398">Plattform</translation>
<translation id="4744603770635761495">AusfĂ¼hrbarer Pfad</translation>
<translation id="4756388243121344051">&amp;Verlauf</translation>
+<translation id="4759238208242260848">Downloads</translation>
<translation id="4764776831041365478">Die Webseite unter <ph name="URL" /> ist möglicherweise vorĂ¼bergehend nicht verfĂ¼gbar oder wurde dauerhaft an eine neue Webadresse verschoben.</translation>
<translation id="4771973620359291008">Ein unbekannter Fehler ist aufgetreten.</translation>
<translation id="4782449893814226250">Du hast deine Eltern gefragt, ob du diese Seite besuchen darfst.</translation>
<translation id="4800132727771399293">PrĂ¼fen Sie Ihr Ablaufdatum und Ihren CVC und versuchen Sie es dann erneut.</translation>
-<translation id="4807049035289105102">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, da die Website verschlĂ¼sselte Anmeldedaten gesendet hat, die von Google Chrome nicht verarbeitet werden können. Netzwerkfehler und Angriffe sind in der Regel nur vorĂ¼bergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="4813512666221746211">Netzwerkfehler</translation>
<translation id="4816492930507672669">An Seite anpassen</translation>
<translation id="4850886885716139402">Anzeigen</translation>
<translation id="4880827082731008257">Im Verlauf suchen</translation>
+<translation id="4884656795097055129">Weitere Artikel werden zu gegebener Zeit erscheinen.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{und 1 weitere Webseite}other{und # weitere Webseiten}}</translation>
<translation id="4923417429809017348">Diese Seite wurde von einer unbekannten Sprache in <ph name="LANGUAGE_LANGUAGE" /> Ă¼bersetzt.</translation>
<translation id="4926049483395192435">Angabe erforderlich</translation>
<translation id="4930497775425430760">Diese Nachricht wird dir angezeigt, weil dein Elternteil neue Websites zuerst genehmigen muss, bevor du sie öffnen kannst.</translation>
<translation id="495170559598752135">Aktionen</translation>
<translation id="4958444002117714549">Liste einblenden</translation>
+<translation id="4962322354953122629">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chrome nicht als vertrauenswĂ¼rdig eingestuft. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911">Ăœbersetzen (<ph name="ORIGINAL_LANGUAGE" /> &gt; <ph name="TARGET_LANGUAGE" />)?</translation>
+<translation id="4989809363548539747">Dieses Plug-in wird nicht unterstĂ¼tzt</translation>
<translation id="5002932099480077015">Wenn diese Funktion aktiviert ist, speichert Chrome eine Kopie Ihrer Karte auf diesem Gerät, um ein AusfĂ¼llen von Formularen zu beschleunigen.</translation>
<translation id="5019198164206649151">Sicherungsspeicher ist fehlerhaft.</translation>
<translation id="5023310440958281426">Informieren Sie sich Ă¼ber die von Ihrem Administrator festgelegten Richtlinien.</translation>
@@ -358,13 +378,12 @@
<translation id="5031870354684148875">Ăœber Google Ăœbersetzer</translation>
<translation id="5040262127954254034">Datenschutz</translation>
<translation id="5045550434625856497">Falsches Passwort</translation>
+<translation id="5056549851600133418">Artikel fĂ¼r Sie</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Proxyadresse prĂ¼fen<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Das Serverzertifikat ist zurzeit ungĂ¼ltig.</translation>
<translation id="5089810972385038852">Bundesstaat/-land</translation>
-<translation id="5094747076828555589">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chromium als nicht vertrauenswĂ¼rdig eingestuft. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="5095208057601539847">Provinz</translation>
<translation id="5115563688576182185">(64-Bit)</translation>
-<translation id="5122371513570456792"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> fĂ¼r "<ph name="SEARCH_STRING" />" gefunden</translation>
<translation id="5141240743006678641">Synchronisierte Passwörter mit Ihren Google-Anmeldeinformationen verschlĂ¼sseln</translation>
<translation id="5145883236150621069">Fehlercode in der Richtlinienantwort</translation>
<translation id="5171045022955879922">Suchen oder URL eingeben</translation>
@@ -373,18 +392,18 @@
<translation id="5190835502935405962">Lesezeichenleiste</translation>
<translation id="5199729219167945352">Experimente</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">Nutzen Sie Chrome bei der Arbeit? Unternehmen können Chrome-Einstellungen fĂ¼r ihre Mitarbeiter verwalten. Weitere Informationen</translation>
<translation id="5299298092464848405">Fehler beim Parsen der Richtlinie</translation>
<translation id="5300589172476337783">Anzeigen</translation>
<translation id="5308689395849655368">Die Absturzberichtsfunktion ist deaktiviert.</translation>
<translation id="5317780077021120954">Speichern</translation>
<translation id="5327248766486351172">Name</translation>
+<translation id="5359637492792381994">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist zurzeit ungĂ¼ltig. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Fehler beim Speichern der Richtlinieneinstellungen</translation>
-<translation id="540969355065856584">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist zurzeit ungĂ¼ltig. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="5421136146218899937">Browserdaten löschen...</translation>
<translation id="5430298929874300616">Lesezeichen löschen</translation>
<translation id="5431657950005405462">Ihre Datei wurde nicht gefunden</translation>
<translation id="5435775191620395718">Der Verlauf fĂ¼r dieses Gerät wird angezeigt. <ph name="BEGIN_LINK" />Weitere Informationen.<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">Die personalisierten Inhaltsvorschläge sind momentan deaktiviert, weil Ihre synchronisierten Daten durch eine benutzerdefinierte Passphrase geschĂ¼tzt werden.</translation>
<translation id="5439770059721715174">Schemavalidierungsfehler in "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Diese <ph name="HOST_NAME" />-Seite wurde nicht gefunden</translation>
<translation id="5455374756549232013">Zeitstempel der Richtlinie ist fehlerhaft.</translation>
@@ -407,14 +426,18 @@
<translation id="5622887735448669177">Möchten Sie diese Website verlassen?</translation>
<translation id="5629630648637658800">Fehler beim Laden der Richtlinieneinstellungen</translation>
<translation id="5631439013527180824">UngĂ¼ltiges Management-Token fĂ¼r das Gerät</translation>
-<translation id="5650551054760837876">Keine Suchergebnisse gefunden.</translation>
<translation id="5677928146339483299">Blockiert</translation>
<translation id="5710435578057952990">Die Identität dieser Website wurde nicht verifiziert.</translation>
<translation id="5720705177508910913">Aktueller Nutzer</translation>
+<translation id="572328651809341494">Zuletzt geöffnete Tabs</translation>
<translation id="5784606427469807560">Beim Bestätigen Ihrer Karte ist ein Problem aufgetreten. ĂœberprĂ¼fen Sie Ihre Internetverbindung und versuchen Sie es noch einmal.</translation>
<translation id="5785756445106461925">AuĂŸerdem enthält diese Seite andere, nicht sichere Ressourcen. Diese Ressourcen können während der Ăœbertragung von anderen Nutzern angezeigt und von Angreifern bearbeitet werden, die das Layout der Seite verändern.</translation>
+<translation id="5786044859038896871">Möchten Sie Ihre Kreditkarteninformationen eingeben?</translation>
+<translation id="5803412860119678065">Möchten Sie die Daten Ihrer <ph name="CARD_DETAIL" /> eingeben?</translation>
<translation id="5810442152076338065">Ihre Verbindung zu <ph name="DOMAIN" /> ist mit einer veralteten Codier-Suite verschlĂ¼sselt.</translation>
<translation id="5813119285467412249">&amp;HinzufĂ¼gen wiederholen</translation>
+<translation id="5814352347845180253">Eventuell verlieren Sie den Zugriff auf Premiuminhalte von <ph name="SITE" /> und einigen anderen Websites.</translation>
+<translation id="5843436854350372569">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat jedoch ein Zertifikat mit einem schwachen SchlĂ¼ssel Ă¼bermittelt. Ein Hacker könnte den privaten SchlĂ¼ssel geknackt haben, sodass es sich möglicherweise nicht um den erwarteten Server handelt, sondern Sie stattdessen mit einem Hacker kommunizieren. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">Diese Nachricht wird Ihnen angezeigt, weil Ihr Administrator diese Website blockiert hat.</translation>
<translation id="5857090052475505287">Neuer Ordner</translation>
<translation id="5869405914158311789">Diese Website ist nicht erreichbar</translation>
@@ -422,6 +445,7 @@
<translation id="5872918882028971132">Vorschläge fĂ¼r Eltern</translation>
<translation id="59107663811261420">Dieser Kartentyp wird von Google Payments fĂ¼r diesen Händler nicht unterstĂ¼tzt. Bitte verwenden Sie eine andere Karte.</translation>
<translation id="59174027418879706">Aktiviert</translation>
+<translation id="5926846154125914413">Eventuell verlieren Sie den Zugriff auf Premiuminhalte von einigen Websites.</translation>
<translation id="5966707198760109579">Woche</translation>
<translation id="5967867314010545767">Aus Verlauf entfernen</translation>
<translation id="5975083100439434680">Verkleinern</translation>
@@ -433,12 +457,12 @@
<translation id="604124094241169006">Automatisch</translation>
<translation id="6042308850641462728">Mehr</translation>
<translation id="6060685159320643512">Vorsichtig, diese Experimente können gefährlich sein!</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{keine}=1{1}other{#}}</translation>
<translation id="6146055958333702838">ĂœberprĂ¼fen Sie alle Kabel und starten Sie alle verwendeten Router, Modems und
anderen Netzwerkgeräte neu.</translation>
<translation id="614940544461990577">Versuchen Sie Folgendes:</translation>
<translation id="6150607114729249911">Hoppla. Du musst deine Eltern fragen, ob du diese Seite besuchen darfst.</translation>
<translation id="6151417162996330722">Die GĂ¼ltigkeitsdauer des Serverzertifikats ist zu lang.</translation>
-<translation id="6154808779448689242">ZurĂ¼ckgegebenes Token der Richtlinie entspricht nicht dem aktuellen Token.</translation>
<translation id="6165508094623778733">Weitere Informationen</translation>
<translation id="6203231073485539293">Bitte Ă¼berprĂ¼fen Sie Ihre Internetverbindung.</translation>
<translation id="6218753634732582820">Adresse aus Chromium entfernen?</translation>
@@ -451,24 +475,30 @@
<translation id="6328639280570009161">Deaktivieren Sie die Netzwerkvervollständigung.</translation>
<translation id="6337534724793800597">Richtlinien nach Name filtern</translation>
<translation id="6342069812937806050">Abgeschlossen</translation>
+<translation id="6345221851280129312">unbekannte GrĂ¶ĂŸe</translation>
<translation id="6355080345576803305">Ăœberschreibung öffentlicher Sitzung</translation>
<translation id="6358450015545214790">Was bedeuten diese Hinweise?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 weiterer Vorschlag}other{# weitere Vorschläge}}</translation>
<translation id="6387478394221739770">Interessiert an coolen neuen Chrome-Funktionen? Testen Sie unsere Betaversion unter chrome.com/beta.</translation>
-<translation id="641480858134062906"><ph name="URL" /> konnte nicht geladen werden</translation>
+<translation id="6389758589412724634">Beim Versuch, diese Webseite aufzurufen, hat Chromium das Arbeitsspeicherlimit erreicht.</translation>
+<translation id="6416403317709441254">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website verschlĂ¼sselte Anmeldedaten gesendet hat, die von Chromium nicht verarbeitet werden können. Netzwerkfehler und Angriffe sind in der Regel nur vorĂ¼bergehend, sodass die Seite wahrscheinlich später wieder funktioniert. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">ĂœberprĂ¼fung, ob das Zertifikat zurĂ¼ckgerufen wurde, nicht möglich</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> hat die Verbindung abgelehnt.</translation>
<translation id="6445051938772793705">Land</translation>
<translation id="6451458296329894277">Erneute Formular-Ăœbermittlung bestätigen</translation>
<translation id="6458467102616083041">Ignoriert, da Standardsuche durch Richtlinie deaktiviert</translation>
+<translation id="6462969404041126431">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wurde möglicherweise widerrufen. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Geräterichtlinien</translation>
<translation id="6489534406876378309">Hochladen von AbstĂ¼rzen starten</translation>
<translation id="6529602333819889595">&amp;Löschen wiederholen</translation>
+<translation id="6534179046333460208">Physical Web-Vorschläge</translation>
<translation id="6550675742724504774">Optionen</translation>
+<translation id="6593753688552673085">weniger als <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">VerschlĂ¼sselungsoptionen</translation>
<translation id="662080504995468778">Bleiben</translation>
<translation id="6628463337424475685"><ph name="ENGINE" />-Suche</translation>
-<translation id="6634865548447745291">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, da <ph name="BEGIN_LINK" />dieses Zertifikat widerrufen wurde<ph name="END_LINK" />. Netzwerkfehler und Angriffe sind in der Regel nur vorĂ¼bergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="6644283850729428850">Diese Richtlinie ist veraltet.</translation>
+<translation id="6652240803263749613">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem Ihres Computers nicht als vertrauenswĂ¼rdig eingestuft. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">Ordner bearbeiten</translation>
<translation id="6660210980321319655">Automatische Meldung am <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Vorschlag fĂ¼r das Formular aus Chromium entfernen?</translation>
@@ -476,6 +506,7 @@
<translation id="6710213216561001401">ZurĂ¼ck</translation>
<translation id="6710594484020273272">&lt;Suchbegriff eingeben&gt;</translation>
<translation id="6711464428925977395">Mit dem Proxyserver ist ein Problem aufgetreten oder die Adresse ist falsch.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{keine}=1{1 Inhalt}other{# Inhalte}}</translation>
<translation id="674375294223700098">Fehler wegen unbekanntem Serverzertifikat</translation>
<translation id="6753269504797312559">Wert der Richtlinie</translation>
<translation id="6757797048963528358">Ihr Gerät ist im Ruhemodus.</translation>
@@ -487,7 +518,6 @@
<translation id="6891596781022320156">Richtlinienebene wird nicht unterstĂ¼tzt.</translation>
<translation id="6895330447102777224">Ihre Karte wurde bestätigt</translation>
<translation id="6897140037006041989">User-Agent</translation>
-<translation id="6903907808598579934">Synchronisierung aktivieren</translation>
<translation id="6915804003454593391">Nutzer:</translation>
<translation id="6957887021205513506">Das Zertifikat des Servers ist möglicherweise eine Fälschung.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +525,11 @@
<translation id="6970216967273061347">Bezirk</translation>
<translation id="6973656660372572881">Sowohl feste Proxyserver als auch eine PAC-Skript-URL sind festgelegt.</translation>
<translation id="6989763994942163495">Erweiterte Einstellungen anzeigen</translation>
+<translation id="7000990526846637657">Keine Verlaufseinträge gefunden</translation>
+<translation id="7009986207543992532">Sie haben versucht, <ph name="DOMAIN" /> aufzurufen. Der Server hat jedoch ein Zertifikat präsentiert, dessen GĂ¼ltigkeitsdauer zu lang ist, um vertrauenswĂ¼rdig zu sein.<ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Möglicherweise sind in Ihrem Google-Konto noch andere Formen des Browserverlaufs unter <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> vorhanden</translation>
<translation id="7029809446516969842">Passwörter</translation>
-<translation id="7050187094878475250">Sie haben versucht, <ph name="DOMAIN" /> zu erreichen. Der Server hat jedoch ein Zertifikat präsentiert, dessen GĂ¼ltigkeitsdauer zu lang ist, um vertrauenswĂ¼rdig zu sein.</translation>
<translation id="7087282848513945231">Landkreis</translation>
<translation id="7088615885725309056">Ă„lter</translation>
<translation id="7090678807593890770">Auf Google nach <ph name="LINK" /> suchen</translation>
@@ -516,13 +548,13 @@
<translation id="7246609911581847514">Diese Nachricht wird Ihnen angezeigt, weil Ihr Administrator neue Websites zuerst genehmigen muss, bevor Sie diese öffnen können.</translation>
<translation id="724975217298816891">Geben Sie das GĂ¼ltigkeitsdatum und den CVC fĂ¼r <ph name="CREDIT_CARD" /> ein, um Ihre Kartendetails zu aktualisieren. Nach erfolgter Bestätigung werden die Kartendetails an diese Website weitergegeben.</translation>
<translation id="725866823122871198">Es kann keine private Verbindung zu <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hergestellt werden, weil Datum und Uhrzeit Ihres Computers falsch sind (<ph name="DATE_AND_TIME" />).</translation>
-<translation id="7265986070661382626"><ph name="SITE" /> kann zurzeit nicht aufgerufen werden, weil die Website das <ph name="BEGIN_LINK" />Zertifikats-Pinning<ph name="END_LINK" /> nutzt. Netzwerkfehler und Angriffe sind in der Regel nur vorĂ¼bergehend, sodass die Seite später wahrscheinlich wieder funktioniert.</translation>
<translation id="7269802741830436641">Diese Webseite weist eine Weiterleitung auf.</translation>
<translation id="7275334191706090484">Verwaltete Lesezeichen</translation>
<translation id="7298195798382681320">Empfohlen</translation>
-<translation id="7301833672208172928">Synchronisierung des Verlaufs aktivieren</translation>
+<translation id="7309308571273880165">Absturzbericht erfasst: <ph name="CRASH_TIME" /> (Upload wurde vom Nutzer angefordert, aber noch nicht abgeschlossen)</translation>
<translation id="7334320624316649418">&amp;Neu anordnen wiederholen</translation>
<translation id="733923710415886693">Das Serverzertifikat wurde nicht Ă¼ber die Zertifikatstransparenz offengelegt.</translation>
+<translation id="7351800657706554155">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, da das Zertifikat dieser Website widerrufen wurde. Netzwerkfehler und Angriffe sind in der Regel nur vorĂ¼bergehend, sodass die Seite wahrscheinlich später wieder funktioniert. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen.<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">Befehlszeile</translation>
<translation id="7372973238305370288">Suchergebnis</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +573,17 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="7469372306589899959">Karte wird bestätigt</translation>
<translation id="7481312909269577407">Vorwärts</translation>
<translation id="7485870689360869515">Keine Daten gefunden</translation>
+<translation id="7508255263130623398">ZurĂ¼ckgegebene Geräte-ID der Richtlinie ist leer oder entspricht nicht der aktuellen Geräte-ID</translation>
<translation id="7514365320538308">Herunterladen</translation>
<translation id="7518003948725431193">FĂ¼r folgende Webadresse wurde keine Webseite gefunden: <ph name="URL" />.</translation>
<translation id="7537536606612762813">Verbindlich</translation>
<translation id="7542995811387359312">Die Funktion zur automatischen AusfĂ¼llung der Kreditkartendaten ist deaktiviert, da dieses Formular keine sichere Verbindung nutzt.</translation>
<translation id="7549584377607005141">Damit diese Webseite richtig angezeigt wird, werden die Daten benötigt, die Sie zuvor eingegeben haben. Sie können diese Daten erneut senden, dabei werden jedoch sämtliche Aktionen wiederholt, die zuvor durch diese Seite ausgefĂ¼hrt wurden.</translation>
<translation id="7554791636758816595">Neuer Tab</translation>
-<translation id="7567204685887185387">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wurde möglicherweise in betrĂ¼gerischer Absicht ausgegeben. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="7568593326407688803">Diese Seite ist auf<ph name="ORIGINAL_LANGUAGE" />Soll sie Ă¼bersetzt werden?</translation>
<translation id="7569952961197462199">Kreditkarte aus Chrome entfernen?</translation>
<translation id="7578104083680115302">Mit Karten, die Sie bei Google gespeichert haben, können Sie schnell und geräteĂ¼bergreifend auf Websites und in Apps bezahlen.</translation>
+<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Das Serverzertifikat verstĂ¶ĂŸt gegen Namensbeschränkungen.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> kann diese Anfrage momentan nicht verarbeiten.</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" /> nie Ă¼bersetzen</translation>
@@ -561,6 +594,7 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="7637571805876720304">Kreditkarte aus Chromium entfernen?</translation>
<translation id="765676359832457558">Erweiterte Einstellungen ausblenden</translation>
<translation id="7658239707568436148">Abbrechen</translation>
+<translation id="7667346355482952095">ZurĂ¼ckgegebenes Token der Richtlinie ist leer oder entspricht nicht dem aktuellen Token</translation>
<translation id="7668654391829183341">Unbekanntes Gerät</translation>
<translation id="7674629440242451245">Interessiert an coolen neuen Chrome-Funktionen? Testen Sie unsere Dev-Version unter chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Weiter zu <ph name="SITE" /> (unsicher)<ph name="END_LINK" /></translation>
@@ -577,10 +611,10 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="780301667611848630">Kein Interesse</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7813600968533626083">Vorschlag fĂ¼r das Formular aus Chrome entfernen?</translation>
+<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> fĂ¼r "<ph name="SEARCH_STRING" />" gefunden</translation>
<translation id="785549533363645510">Sie sind jedoch nicht unsichtbar. Der Inkognitomodus verhindert nicht, dass Informationen zu Ihren Webaktivitäten von Ihrem Arbeitgeber, Ihrem Internetanbieter oder den von Ihnen besuchten Websites erfasst werden.</translation>
<translation id="7887683347370398519">PrĂ¼fen Sie Ihren CVC und versuchen Sie es dann erneut.</translation>
<translation id="7894616681410591072">Hoppla. Sie benötigen die Genehmigung von <ph name="NAME" />, um diese Seite zu öffnen.</translation>
-<translation id="790025292736025802"><ph name="URL" /> wurde nicht gefunden</translation>
<translation id="7912024687060120840">Im Ordner:</translation>
<translation id="7920092496846849526">Du hast deine Eltern gefragt, ob du diese Seite besuchen darfst.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +627,10 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="7995512525968007366">Nicht angegeben</translation>
<translation id="8012647001091218357">Wir können deine Eltern momentan nicht erreichen. Bitte versuche es später erneut.</translation>
<translation id="8034522405403831421">Diese Seite ist auf <ph name="SOURCE_LANGUAGE" />. In folgende Sprache Ă¼bersetzen: <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Keine Verlaufseinträge gefunden</translation>
<translation id="8088680233425245692">Der Artikel kann nicht angezeigt werden.</translation>
+<translation id="8089520772729574115">weniger als 1 MB</translation>
<translation id="8091372947890762290">Aktivierung auf dem Server steht noch aus.</translation>
+<translation id="8129262335948759431">unbekannter Wert</translation>
<translation id="8131740175452115882">Bestätigen</translation>
<translation id="8134994873729925007">Die <ph name="BEGIN_ABBR" />DNS-Adresse<ph name="END_ABBR" /> des Servers von <ph name="HOST_NAME" /> wurde nicht gefunden.</translation>
<translation id="8149426793427495338">Ihr Computer ist im Ruhemodus.</translation>
@@ -604,6 +639,7 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="8201077131113104583">UngĂ¼ltige Update-URL fĂ¼r Erweiterung mit der ID "<ph name="EXTENSION_ID" />"</translation>
<translation id="8218327578424803826">Zugewiesener Standort:</translation>
<translation id="8225771182978767009">Die Person, die diesen Computer eingerichtet hat, hat diese Website gesperrt.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Die gesuchte Seite hat die von Ihnen eingegebenen Informationen verwendet bzw. verarbeitet. Wenn Sie zu dieser Seite zurĂ¼ckgehen, wird möglicherweise eine bereits ausgefĂ¼hrte Aktion wiederholt. Möchten Sie fortfahren?</translation>
<translation id="8249320324621329438">Letzter Abruf:</translation>
<translation id="8261506727792406068">Löschen</translation>
@@ -616,12 +652,17 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="8349305172487531364">Lesezeichenleiste</translation>
<translation id="8363502534493474904">Flugmodus ausschalten</translation>
<translation id="8364627913115013041">Nicht eingerichtet</translation>
+<translation id="8380941800586852976">Schädlich</translation>
<translation id="8412145213513410671">AbstĂ¼rze (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Sie mĂ¼ssen zweimal dieselbe Passphrase eingeben.</translation>
<translation id="8428213095426709021">Einstellungen</translation>
+<translation id="8433057134996913067">Dadurch werden Sie von den meisten Websites abgemeldet.</translation>
<translation id="8437238597147034694">&amp;Verschieben rĂ¼ckgängig machen</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 Kreditkarte}other{# Kreditkarten}}</translation>
+<translation id="8483780878231876732">Melden Sie sich in Chrome an, um in Ihrem Google-Konto gespeicherte Kreditkarten zu verwenden</translation>
<translation id="8488350697529856933">Gilt fĂ¼r</translation>
<translation id="8498891568109133222">Die Antwort von <ph name="HOST_NAME" /> hat zu lange gedauert.</translation>
+<translation id="852346902619691059">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem Ihres Geräts nicht als vertrauenswĂ¼rdig eingestuft. Mögliche GrĂ¼nde sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Dieser Kartentyp wird von Google Payments nicht unterstĂ¼tzt. Bitte verwenden Sie eine andere Karte.</translation>
<translation id="8550022383519221471">Der Synchronisierungsdienst ist nicht fĂ¼r diese Domain verfĂ¼gbar.</translation>
<translation id="8553075262323480129">Die Ăœbersetzung ist fehlgeschlagen, weil die Sprache der Seite nicht ermittelt werden konnte.</translation>
@@ -633,15 +674,12 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="8647750283161643317">Alle auf Standardeinstellung zurĂ¼cksetzen</translation>
<translation id="8680787084697685621">Die Anmeldeinformationen fĂ¼r dieses Konto sind veraltet.</translation>
<translation id="8703575177326907206">Die Verbindung zu <ph name="DOMAIN" /> ist nicht verschlĂ¼sselt.</translation>
-<translation id="8713130696108419660">Erste Signatur ungĂ¼ltig</translation>
<translation id="8725066075913043281">Erneut versuchen</translation>
<translation id="8728672262656704056">Sie haben den Inkognitomodus aktiviert</translation>
<translation id="8730621377337864115">Fertig</translation>
<translation id="8738058698779197622">Zum Aufbau einer sicheren Verbindung muss die Uhrzeit richtig eingestellt sein. Der Grund hierfĂ¼r ist, dass Websites sich mithilfe von Zertifikaten identifizieren, die nur fĂ¼r einen bestimmten Zeitraum gelten. Da die Uhrzeit Ihres Geräts falsch ist, kann Chromium diese Zertifikate nicht bestätigen.</translation>
<translation id="8740359287975076522">Die &lt;abbr id="dnsDefinition"&gt;DNS-Adresse&lt;/abbr&gt; von <ph name="HOST_NAME" /> wurde nicht gefunden. Eine Problemdiagnose wird durchgefĂ¼hrt.</translation>
-<translation id="8741995161408053644">Möglicherweise sind in Ihrem Google-Konto noch andere Formen des Browserverlaufs unter <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> vorhanden.</translation>
<translation id="8790007591277257123">&amp;Löschen wiederholen</translation>
-<translation id="8790687370365610530">Aktivieren Sie die Synchronisierung des Verlaufs, um personalisierte, von Google vorgeschlagene Inhalte zu erhalten.</translation>
<translation id="8798099450830957504">Standardeinstellung</translation>
<translation id="8804164990146287819">Datenschutzerklärung</translation>
<translation id="8820817407110198400">Lesezeichen</translation>
@@ -663,13 +701,11 @@ Geheimtipp: Verwenden Sie nächstes Mal den Inkognitomodus (<ph name="SHORTCUT_K
<translation id="8971063699422889582">Das Serverzertifikat ist abgelaufen.</translation>
<translation id="8987927404178983737">Monat</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Der Server präsentierte ein Zertifikat, das nicht gemĂ¤ĂŸ der Richtlinie zur Zertifikatstransparenz öffentlich offengelegt wurde. Dies ist fĂ¼r einige Zertifikate jedoch eine Voraussetzung, mit der sichergestellt wird, dass sie vertrauenswĂ¼rdig sind und vor Angriffen schĂ¼tzen.</translation>
<translation id="9001074447101275817">FĂ¼r den Proxy <ph name="DOMAIN" /> sind ein Nutzername und ein Passwort erforderlich.</translation>
<translation id="901974403500617787">Parameter, die systemweit gelten, können nur vom EigentĂ¼mer festgelegt werden: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Die Seite wurde Ă¼bersetzt und liegt nun auf <ph name="TARGET_LANGUAGE" /> vor.</translation>
<translation id="9038649477754266430">Vorhersagedienst zum schnelleren Laden von Seiten verwenden</translation>
<translation id="9039213469156557790">AuĂŸerdem enthält diese Seite andere, nicht sichere Ressourcen. Diese Ressourcen können während der Ăœbertragung von anderen Nutzern angezeigt und von Angreifern bearbeitet werden, die das Verhalten der Seite verändern.</translation>
-<translation id="9049981332609050619">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat sich jedoch mit einem ungĂ¼ltigen Zertifikat ausgewiesen.</translation>
<translation id="9050666287014529139">Passphrase</translation>
<translation id="9065203028668620118">Bearbeiten</translation>
<translation id="9092364396508701805">Die Seite <ph name="HOST_NAME" /> funktioniert nicht</translation>
diff --git a/chromium/components/strings/components_strings_el.xtb b/chromium/components/strings/components_strings_el.xtb
index ac823711c7e..17309b84131 100644
--- a/chromium/components/strings/components_strings_el.xtb
+++ b/chromium/components/strings/components_strings_el.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="el">
+<translation id="1008557486741366299">Όχι Ï„ÏÏα</translation>
<translation id="1015730422737071372">ÎαταχωÏίστε επιπλέον λεπτομέÏειες</translation>
<translation id="1032854598605920125">ΠεÏιστÏοφή Ï€Ïος τα δεξιά</translation>
<translation id="1038842779957582377">άγνωστο όνομα</translation>
+<translation id="1053591932240354961">Δεν μποÏείτε να επισκεφτείτε τον ιστότοπο <ph name="SITE" /> αυτήν τη στιγμή γιατί ο ιστότοπος έστειλε κωδικοποιημένα διαπιστευτήÏια τα οποία δεν μποÏεί να επεξεÏγαστεί το Chrome. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά, συνεπÏÏ‚ αυτή η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;ΑναίÏεση Ï€Ïοσθήκης</translation>
<translation id="10614374240317010">Δεν έχει αποθηκευθεί ποτέ</translation>
-<translation id="1064422015032085147">O διακομιστής που φιλοξενεί την ιστοσελίδα ενδέχεται να είναι υπεÏφοÏτωμένος ή να υποβάλλεται σε συντήÏηση.
- Για να αποφευχθεί η υπεÏβολικά μεγάλη επισκεψιμότητα και η επιδείνωση της κατάστασης,
- τα αιτήματα σε αυτό το URL δεν επιτÏέπονται Ï€ÏοσωÏινά.</translation>
<translation id="106701514854093668">Σελιδοδείκτες επιτÏαπέζιου υπολογιστή</translation>
<translation id="1080116354587839789">ΠÏοσαÏμογή στο πλάτος</translation>
+<translation id="1103124106085518534">Τέλος Ï€Ïος το παÏόν</translation>
<translation id="1103523840287552314">Îα μεταφÏάζονται πάντα τα <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Εάν επιλεγεί, το Chrome θα αποθηκεÏει ένα αντίγÏαφο της κάÏτας σας σε αυτήν τη συσκευή για ταχÏτεÏη συμπλήÏωση φοÏμÏν.</translation>
+<translation id="1111153019813902504">ΠÏόσφατοι σελιδοδείκτες</translation>
<translation id="1113869188872983271">&amp;ΑναίÏεση αναδιάταξης</translation>
+<translation id="1126551341858583091">Το μέγεθος του Ï„Î¿Ï€Î¹ÎºÎ¿Ï Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏÏου είναι <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Η Ï€ÏοσωÏινή μνήμη της πολιτικής είναι εντάξει</translation>
<translation id="113188000913989374">Ο ιστότοπος <ph name="SITE" /> λέει:</translation>
<translation id="1132774398110320017">Ρυθμίσεις Αυτόματης συμπλήÏωσης Chrome…</translation>
-<translation id="1150979032973867961">Ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το λειτουÏγικό σÏστημα της συσκευής σας. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
<translation id="1152921474424827756">ΠÏόσβαση σε <ph name="BEGIN_LINK" />Ï€ÏοσωÏινό αντίγÏαφο<ph name="END_LINK" /> της διεÏθυνσης <ph name="URL" /></translation>
<translation id="1158211211994409885">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> τεÏμάτισε απÏοσδόκητα τη σÏνδεση.</translation>
<translation id="1161325031994447685">Επανασυνδεθείτε στο Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">ÎατάÏγηση</translation>
<translation id="1201402288615127009">Επόμενο</translation>
<translation id="1201895884277373915">ΠεÏισσότεÏα από αυτόν τον ιστότοπο</translation>
-<translation id="121201262018556460">ΠÏοσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, αλλά ο διακομιστής παÏουσίασε ένα πιστοποιητικό που πεÏιέχει ένα αδÏναμο κλειδί. Îάποιος εισβολέας θα μποÏοÏσε να έχει παÏαβιάσει το ιδιωτικό κλειδί και ο διακομιστής ενδέχεται να μην είναι ο διακομιστής που αναμένατε (μποÏεί να επικοινωνείτε με έναν εισβολέα).</translation>
+<translation id="1206967143813997005">Εσφαλμένη αÏχική υπογÏαφή</translation>
+<translation id="1209206284964581585">ΠÏοσωÏινή απόκÏυψη</translation>
<translation id="1219129156119358924">Ασφάλεια συστήματος</translation>
<translation id="1227224963052638717">Άγνωστη πολιτική.</translation>
<translation id="1227633850867390598">ΑπόκÏυψη τιμής</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Îαι</translation>
<translation id="1430915738399379752">ΕκτÏπωση</translation>
<translation id="1442912890475371290">Αποκλείστηκε απόπειÏα <ph name="BEGIN_LINK" /> ανοίγματος σελίδας στο <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Δεν μποÏείτε να επισκεφτείτε τον ιστότοπο <ph name="SITE" /> αυτήν τη στιγμή γιατί ο ιστότοπος χÏησιμοποιεί certificate pinning (κλείδωμα πιστοποιητικÏν). Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά, συνεπÏÏ‚ αυτή η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Εμφάνιση ενός αποθηκευμένου αντιγÏάφου (Ï€.χ. επιβεβαιωμένες μη ενημεÏωμένες εκδόσεις) αυτής της σελίδας.</translation>
<translation id="1519264250979466059">ΗμεÏομηνία κατασκευής</translation>
<translation id="1549470594296187301">Θα Ï€Ïέπει να ενεÏγοποιηθεί η JavaScript για τη χÏήση αυτής της λειτουÏγίας.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Η διαμόÏφωση δικτÏου είναι μη έγκυÏη και δεν ήταν δυνατή η εισαγωγή της.</translation>
<translation id="1644574205037202324">ΙστοÏικό</translation>
<translation id="1645368109819982629">Μη υποστηÏιζόμενο Ï€Ïωτόκολλο</translation>
-<translation id="1655462015569774233">{1,plural, =1{Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του έληξε χθες. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. Το Ïολόι του υπολογιστή σας αυτήν τη στιγμή είναι Ïυθμισμένο στην ημεÏομηνία <ph name="CURRENT_DATE" />. Είναι σωστή αυτή η ÏÏθμιση; Εάν όχι, θα Ï€Ïέπει να διοÏθÏσετε το Ïολόι του συστήματός σας και έπειτα να ανανεÏσετε αυτήν τη σελίδα.}other{Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του έληξε Ï€Ïιν από # ημέÏες. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. Το Ïολόι του υπολογιστή σας αυτήν τη στιγμή είναι Ïυθμισμένο στην ημεÏομηνία <ph name="CURRENT_DATE" />. Είναι σωστή αυτή η ÏÏθμιση; Εάν όχι, θα Ï€Ïέπει να διοÏθÏσετε το Ïολόι του συστήματός σας και έπειτα να ανανεÏσετε αυτήν τη σελίδα.}}</translation>
<translation id="1676269943528358898">Îανονικά, ο ιστότοπος <ph name="SITE" /> χÏησιμοποιεί κÏυπτογÏάφηση για να Ï€ÏοστατεÏει τα στοιχεία σας. Όταν το Google Chrome επιχείÏησε Ï€Ïόσφατα να συνδεθεί στο <ph name="SITE" />, ο ιστότοπος ανταποκÏίθηκε δημιουÏγÏντας ασυνήθιστα και εσφαλμένα διαπιστευτήÏια. Αυτό μποÏεί να συμβεί όταν κάποιος εισβολέας Ï€Ïοσπαθεί να υποκÏιθεί ότι είναι ο ιστότοπος <ph name="SITE" /> ή όταν κάποια οθόνη σÏνδεσης Wi-Fi έχει διακόψει τη σÏνδεσή σας. Τα στοιχεία σας εξακολουθοÏν να είναι ασφαλή επειδή το Google Chrome διέκοψε τη σÏνδεση Ï€Ïιν από την ανταλλαγή δεδομένων.</translation>
<translation id="168841957122794586">Το πιστοποιητικό διακομιστή πεÏιέχει ένα αδÏναμο κÏυπτογÏαφικό κλειδί.</translation>
<translation id="1701955595840307032">Λήψη Ï€Ïοτεινόμενου πεÏιεχομένου</translation>
-<translation id="1706954506755087368">{1,plural, =1{Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Η ημεÏομηνία του Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Î±ÏƒÏ†Î±Î»ÎµÎ¯Î±Ï‚ του υποτίθεται ότι είναι αυÏιανή. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας.}other{Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Η ημεÏομηνία του Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Î±ÏƒÏ†Î±Î»ÎµÎ¯Î±Ï‚ του υποτίθεται ότι είναι από # ημέÏες μετά. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">ΠÏοσπαθήστε να επικοινωνήσετε με το διαχειÏιστή συστήματος.</translation>
<translation id="17513872634828108">Ανοικτές καÏτέλες</translation>
<translation id="1753706481035618306">ΑÏιθμός σελίδας</translation>
-<translation id="1761412452051366565">Για να λάβετε εξατομικευμένο πεÏιεχόμενο που Ï€Ïοτείνεται από την Google, ενεÏγοποιήστε τον συγχÏονισμό.</translation>
-<translation id="1763864636252898013">Ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το λειτουÏγικό σÏστημα της συσκευής σας. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Δοκιμάστε να εκτελέσετε τον Διαγνωστικό έλεγχο δικτÏου των Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">ΕνημεÏÏστε την κωδική φÏάση Ï€Ïόσβασης συγχÏονισμοÏ.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Οι σελιδοδείκτες που επισκεφτήκατε Ï€Ïόσφατα θα εμφανίζονται εδÏ.</translation>
<translation id="1821930232296380041">Μη έγκυÏο αίτημα ή παÏάμετÏοι αιτήματος</translation>
<translation id="1838667051080421715">Βλέπετε την πηγή μιας ιστοσελίδας.</translation>
<translation id="1871208020102129563">Ο διακομιστής μεσολάβησης έχει Ïυθμιστεί να χÏησιμοποιεί διακομιστές μεσολάβησης και όχι μια διεÏθυνση URL σεναÏίου .pac.</translation>
<translation id="1883255238294161206">ΣÏμπτυξη λίστας</translation>
<translation id="1898423065542865115">ΦιλτÏάÏισμα</translation>
-<translation id="1911837502049945214">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> δεν αποδέχτηκε το πιστοποιητικό σÏνδεσής σας ή το πιστοποιητικό σÏνδεσης ενδέχεται να έχει λήξει.</translation>
<translation id="194030505837763158">Μετάβαση στο σÏνδεσμο <ph name="LINK" /></translation>
<translation id="1962204205936693436">Σελιδοδείκτες <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Σφάλμα σειÏιοποίησης</translation>
<translation id="1974060860693918893">ΣÏνθετες</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{και άλλο 1 άτομο}other{και άλλα # άτομα}}</translation>
<translation id="2025186561304664664">Ο διακομιστής μεσολάβησης έχει Ïυθμιστεί σε αυτόματη διαμόÏφωση.</translation>
<translation id="2030481566774242610">Μήπως εννοείτε <ph name="LINK" />;</translation>
<translation id="2031925387125903299">Αυτό το μήνυμα εμφανίζεται επειδή οι γονείς σου θα Ï€Ïέπει να εγκÏίνουν τυχόν νέους ιστότοπους την Ï€ÏÏτη φοÏά που τους επισκέπτεσαι.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Ελέγξτε το διακομιστή μεσολάβησης και το τείχος Ï€Ïοστασίας<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ΤαχυδÏομικός κÏδικας</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 Ï€Ïόταση}other{# Ï€Ïοτάσεις}}</translation>
<translation id="2065985942032347596">Απαιτείται έλεγχος ταυτότητας</translation>
<translation id="2079545284768500474">ΑναίÏεση</translation>
<translation id="20817612488360358">Οι Ïυθμίσεις διακομιστή μεσολάβησης του συστήματος έχουν οÏιστεί για να χÏησιμοποιηθοÏν, αλλά καθοÏίζεται επίσης μια Ïητή διαμόÏφωση του διακομιστή μεσολάβησης.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">ΕπεξεÏγασία σελιδοδείκτη</translation>
<translation id="2166049586286450108">ΠλήÏης Ï€Ïόσβαση διαχειÏιστή</translation>
<translation id="2166378884831602661">Αυτός ο ιστότοπος δεν μποÏεί να Ï€ÏοσφέÏει ασφαλή σÏνδεση</translation>
-<translation id="2171101176734966184">ΠÏοσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, αλλά ο διακομιστής παÏουσίασε ένα πιστοποιητικό το οποίο ήταν υπογεγÏαμμένο με έναν αδÏναμο αλγόÏιθμο υπογÏαφής. Αυτό σημαίνει ότι μποÏεί να έχουν πλαστογÏαφηθεί τα διαπιστευτήÏια ασφαλείας που επέδειξε ο διακομιστής και ότι αυτός ο διακομιστής ενδέχεται να μην είναι αυτό που αναμένετε (ενδέχεται να επικοινωνείτε με έναν εισβολέα).</translation>
<translation id="2181821976797666341">Πολιτικές</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 διεÏθυνση}other{# διευθÏνσεις}}</translation>
<translation id="2212735316055980242">Η πολιτική δε βÏέθηκε</translation>
<translation id="2213606439339815911">Ανάκτηση καταχωÏίσεων…</translation>
-<translation id="2214283295778284209">Ο ιστότοπος <ph name="SITE" /> δεν είναι διαθέσιμος</translation>
<translation id="2230458221926704099">ΕπιδιοÏθÏστε τη σÏνδεσή σας χÏησιμοποιÏντας την <ph name="BEGIN_LINK" />εφαÏμογή διαγνωστικÏν ελέγχων<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Αποστολή Ï„ÏÏα</translation>
<translation id="225207911366869382">Αυτή η πολιτική έχει καταÏγηθεί για τη συγκεκÏιμένη πολιτική.</translation>
<translation id="2262243747453050782">Σφάλμα HTTP</translation>
<translation id="2282872951544483773">Μη διαθέσιμα πειÏάματα</translation>
<translation id="2292556288342944218">Η Ï€Ïόσβασή σας στο διαδίκτυο είναι αποκλεισμένη</translation>
<translation id="229702904922032456">Ένα πιστοποιητικό Ïίζας ή ένα ενδιάμεσο πιστοποιητικό έχει λήξει.</translation>
<translation id="230155334948463882">Îέα κάÏτα;</translation>
+<translation id="2305919008529760154">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του μποÏεί να εκδόθηκε παÏάνομα. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">Ο τομέας <ph name="DOMAIN" /> απαιτεί ένα όνομα χÏήστη και έναν κωδικό Ï€Ïόσβασης.</translation>
+<translation id="2318774815570432836">Δεν μποÏείτε να επισκεφτείτε τον ιστότοπο <ph name="SITE" /> αυτήν τη στιγμή γιατί ο ιστότοπος χÏησιμοποιεί HSTS. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά, συνεπÏÏ‚ αυτή η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Μη έγκυÏος σελιδοδείκτης στο ευÏετήÏιο <ph name="ENTRY_INDEX" /> που παÏαβλέφθηκε</translation>
<translation id="2354001756790975382">Άλλοι σελιδοδείκτες</translation>
<translation id="2359808026110333948">Συνέχεια</translation>
<translation id="2365563543831475020">Οι αναφοÏές σφαλμάτων που καταγÏάφηκαν <ph name="CRASH_TIME" /> δεν έχουν μεταφοÏτωθεί</translation>
<translation id="2367567093518048410">Επίπεδο</translation>
+<translation id="2371153335857947666">{1,plural, =1{Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του έληξε χθες. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. Το Ïολόι του υπολογιστή σας αυτήν τη στιγμή είναι Ïυθμισμένο στην ημεÏομηνία <ph name="CURRENT_DATE" />. Είναι σωστή αυτή η ÏÏθμιση; Εάν όχι, θα Ï€Ïέπει να διοÏθÏσετε το Ïολόι του συστήματός σας και έπειτα να ανανεÏσετε αυτήν τη σελίδα. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.}other{Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του έληξε Ï€Ïιν από # ημέÏες. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. Το Ïολόι του υπολογιστή σας αυτήν τη στιγμή είναι Ïυθμισμένο στην ημεÏομηνία <ph name="CURRENT_DATE" />. Είναι σωστή αυτή η ÏÏθμιση; Εάν όχι, θα Ï€Ïέπει να διοÏθÏσετε το Ïολόι του συστήματός σας και έπειτα να ανανεÏσετε αυτήν τη σελίδα. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Δεν διατίθενται εναλλακτικές διεπαφές</translation>
<translation id="2384307209577226199">ΠÏοεπιλογή επιχείÏησης</translation>
-<translation id="238526402387145295">Δεν μποÏείτε να επισκεφτείτε τον ιστότοπο <ph name="SITE" /> αυτήν τη στιγμή επειδή ο ιστότοπος <ph name="BEGIN_LINK" />χÏησιμοποιεί HSTS<ph name="END_LINK" />. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά, συνεπÏÏ‚ αυτή η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα.</translation>
<translation id="2386255080630008482">Το πιστοποιητικό του διακομιστή ανακλήθηκε.</translation>
<translation id="2392959068659972793">Εμφάνιση πολιτικÏν χωÏίς τιμή που να έχει οÏιστεί.</translation>
<translation id="2396249848217231973">&amp;ΑναίÏεση διαγÏαφής</translation>
-<translation id="2413528052993050574">Ο διακομιστής δεν κατάφεÏε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του μποÏεί να έχει ανακληθεί. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
<translation id="2455981314101692989">Σε αυτήν την ιστοσελίδα έχει απενεÏγοποιηθεί η αυτόματη συμπλήÏωση για τη συγκεκÏιμένη φόÏμα.</translation>
+<translation id="2463739503403862330">ΣυμπλήÏωση</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Îα εκτελέσετε τον Διαγνωστικό έλεγχο δικτÏου<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Μη έγκυÏη διεÏθυνση URL αναζήτησης.</translation>
<translation id="2491120439723279231">Το πιστοποιητικό του διακομιστή πεÏιέχει σφάλματα.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Υποβολή</translation>
<translation id="2674170444375937751">Είστε βέβαιοι ότι θέλετε να διαγÏάψετε αυτές τις σελίδες από το ιστοÏικό σας;</translation>
<translation id="2677748264148917807">ΑποχÏÏηση</translation>
+<translation id="269990154133806163">Ο διακομιστής παÏουσίασε ένα πιστοποιητικό το οποίο δεν αποκαλÏφθηκε δημοσίως με χÏήση της πολιτικής Διαφάνειας πιστοποιητικÏν. Αυτό απαιτείται για οÏισμένα πιστοποιητικά, Ï€Ïοκειμένου να διασφαλιστεί ότι είναι αξιόπιστα και παÏέχουν Ï€Ïοστασία ενάντια σε εισβολείς. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Η τιμή δεν συμφωνεί με τη μοÏφή.</translation>
<translation id="2704951214193499422">Δεν ήταν δυνατή η επιβεβαίωση της κάÏτας σας από το Chromium αυτήν τη στιγμή. Δοκιμάστε ξανά αÏγότεÏα.</translation>
<translation id="2705137772291741111">Δεν είναι δυνατή η ανάγνωση του αποθηκευμένου αντιγÏάφου (κÏυφής μνήμης) Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… ιστότοπου.</translation>
<translation id="2709516037105925701">Αυτόματη συμπλήÏωση</translation>
+<translation id="2712118517637785082">ΠÏοσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, όμως το πιστοποιητικό που παÏουσιάστηκε από τον διακομιστή ανακλήθηκε από τον εκδότη του. Αυτό σημαίνει ότι τα διαπιστευτήÏια ασφαλείας που παÏουσιάστηκαν από τον διακομιστή δεν Ï€Ïέπει σε καμία πεÏίπτωση να θεωÏηθοÏν αξιόπιστα. Ενδέχεται να επικοινωνείτε με κάποιον εισβολέα. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Îα ζητηθεί άδεια</translation>
<translation id="2721148159707890343">Το αίτημα ήταν επιτυχές</translation>
<translation id="2728127805433021124">Το πιστοποιητικό του διακομιστή είναι υπογεγÏαμμένο με έναν αδÏναμο αλγόÏιθμο υπογÏαφής.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">ΓÏαμμή διευθÏνσεων και αναζήτησης</translation>
<translation id="2826760142808435982">Η κÏυπτογÏάφηση και ο έλεγχος ταυτότητας της σÏνδεσης γίνονται με <ph name="CIPHER" /> και χÏησιμοποιεί το <ph name="KX" /> ως μηχανισμό ανταλλαγής κλειδιÏν.</translation>
<translation id="2835170189407361413">ΔιαγÏαφή φόÏμας</translation>
-<translation id="2837049386027881519">Η σÏνδεση θα Ï€Ïέπει να επαναληφθεί με χÏήση μιας παλαιότεÏης έκδοσης του Ï€Ïωτοκόλλου TLS ή SSL. Αυτό συνήθως σημαίνει ότι ο διακομιστής χÏησιμοποιεί Ï€Î¿Î»Ï Ï€Î±Î»Î¹ÏŒ λογισμικό και ενδέχεται να αντιμετωπίζει ζητήματα ασφάλειας.</translation>
<translation id="284702764277384724">Το πιστοποιητικό διακομιστή στον κεντÏικό υπολογιστή <ph name="HOST_NAME" /> φαίνεται πως είναι πλαστό.</translation>
<translation id="2889159643044928134">Îα μην γίνει επανάληψη φόÏτωσης</translation>
-<translation id="2896499918916051536">Αυτή η Ï€Ïοσθήκη δεν υποστηÏίζεται.</translation>
+<translation id="2900469785430194048">Η διαθέσιμη μνήμη του Google Chrome εξαντλήθηκε, κατά την Ï€Ïοσπάθεια Ï€Ïοβολής αυτής της ιστοσελίδας.</translation>
<translation id="2909946352844186028">Εντοπίστηκε μια αλλαγή δικτÏου.</translation>
-<translation id="2915500479781995473">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του έχει λήξει. Αυτό ίσως να οφείλεται σε λάθος διαμόÏφωση ή σε έναν εισβολέα που επιτίθεται στη σÏνδεσή σας. Αυτήν τη στιγμή, η ÏÏα του υπολογιστή σας έχει οÏιστεί σε <ph name="CURRENT_TIME" />. Είναι σωστό αυτό; Εάν όχι, θα Ï€Ïέπει να διοÏθÏσετε το Ïολόι του συστήματός σας και έπειτα να ανανεÏσετε αυτήν τη σελίδα.</translation>
<translation id="2922350208395188000">Δεν είναι δυνατός ο έλεγχος του Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Ï„Î¿Ï… διακομιστή.</translation>
-<translation id="2941952326391522266">Ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του είναι από το <ph name="DOMAIN2" />. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
<translation id="2948083400971632585">ΜποÏείτε να απενεÏγοποιήσετε τυχόν διακομιστές μεσολάβησης που έχουν διαμοÏφωθεί για μια σÏνδεση από τη σελίδα Ïυθμίσεων.</translation>
<translation id="2955913368246107853">Îλείσιμο γÏαμμής εÏÏεσης</translation>
<translation id="2958431318199492670">Η διαμόÏφωση δικτÏου δεν συμμοÏφÏνεται με το Ï€Ïότυπο ONC. ΟÏισμένα τμήματα αυτής της διαμόÏφωσης ενδέχεται να μην εισαχθοÏν.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Λανθασμένος Ï„Ïπος πολιτικής</translation>
<translation id="3032412215588512954">Θέλετε να φοÏÏ„Ïσετε ξανά αυτόν τον ιστότοπο;</translation>
<translation id="3037605927509011580">Όπα! Îάτι πήγε στÏαβά!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{τουλάχιστον ένα στοιχείο στις συγχÏονισμένες συσκευές}=1{1 στοιχείο (και πεÏισσότεÏα στις συγχÏονισμένες συσκευές)}other{# στοιχεία (και πεÏισσότεÏα στις συγχÏονισμένες συσκευές)}}</translation>
<translation id="3041612393474885105">ΠληÏοφοÏίες πιστοποιητικοÏ</translation>
<translation id="3063697135517575841">Δεν ήταν δυνατή η επιβεβαίωση της κάÏτας σας από το Chrome αυτήν τη στιγμή. Δοκιμάστε ξανά αÏγότεÏα.</translation>
<translation id="3093245981617870298">Είστε εκτός σÏνδεσης.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">ÎεότεÏο</translation>
<translation id="3207960819495026254">ΠÏοστέθηκε στους σελιδοδείκτες</translation>
-<translation id="3225919329040284222">Ο διακομιστής παÏουσίασε ένα πιστοποιητικό που δεν αντιστοιχεί στις ενσωματωμένες Ï€Ïοϋποθέσεις. Αυτές οι Ï€Ïοϋποθέσεις συμπεÏιλαμβάνονται σε συγκεκÏιμένους ιστότοπους υψηλής ασφάλειας για την Ï€Ïοστασία σας.</translation>
<translation id="3226128629678568754">Πατήστε το κουμπί της επανάληψης φόÏτωσης για να υποβάλετε ξανά τα δεδομένα που απαιτοÏνται για τη φόÏτωση της σελίδας.</translation>
<translation id="3228969707346345236">Η μετάφÏαση απέτυχε επειδή η σελίδα είναι ήδη στα <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Εισαγάγετε τον κωδικό CVC για την πιστωτική κάÏτα <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">ΠÏοσθήκη αυτής της σελίδας στους σελιδοδείκτες</translation>
<translation id="3270847123878663523">&amp;ΑναίÏεση αναδιάταξης</translation>
<translation id="3286538390144397061">Άμεση επανεκκίνηση</translation>
+<translation id="3303855915957856445">Δεν βÏέθηκαν αποτελέσματα αναζήτησης</translation>
<translation id="3305707030755673451">Τα δεδομένα σας κÏυπτογÏαφήθηκαν με τη δική σας φÏάση Ï€Ïόσβασης συγχÏÎ¿Î½Î¹ÏƒÎ¼Î¿Ï ÏƒÏ„Î¹Ï‚ <ph name="TIME" />. ΠληκτÏολογήστε την για να ξεκινήσει ο συγχÏονισμός.</translation>
<translation id="333371639341676808">ΑποτÏοπή δημιουÏγίας Ï€Ïόσθετων πλαισίων διαλόγου από αυτή τη σελίδα.</translation>
+<translation id="3338095232262050444">Ασφαλές</translation>
<translation id="3340978935015468852">Ïυθμίσεις</translation>
<translation id="3345135638360864351">Δεν ήταν δυνατή η αποστολή του αιτήματος Ï€Ïόσβασής σας σε αυτόν τον ιστότοπο σε <ph name="NAME" />. Δοκιμάστε ξανά.</translation>
<translation id="3355823806454867987">Αλλαγή Ïυθμίσεων διακομιστή μεσολάβησης...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Διάστημα ανάκτησης:</translation>
<translation id="3462200631372590220">ΑπόκÏυψη σÏνθετων</translation>
<translation id="3479539252931486093">Δεν το πεÏιμένατε; <ph name="BEGIN_LINK" />ΕνημεÏÏστε μας<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Όχι Ï„ÏÏα</translation>
<translation id="348000606199325318">ΑναγνωÏιστικό σφάλματος <ph name="CRASH_LOCAL_ID" /> (ΑναγνωÏιστικό διακομιστή: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Δεν ήταν δυνατή η επικοινωνία με τον γονέα σας αυτήν τη στιγμή. Δοκιμάστε ξανά.</translation>
<translation id="3527085408025491307">Φάκελος</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">ΧÏήση ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης για:</translation>
<translation id="3549644494707163724">ÎÏυπτογÏάφηση όλων των συγχÏονισμένων δεδομένων με τη δική σας φÏάση Ï€Ïόσβασης συγχÏονισμοÏ</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> πεÏισσότεÏες…</translation>
+<translation id="3555561725129903880">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του είναι από το <ph name="DOMAIN2" />. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Η σÏνδεσή σας δεν είναι ιδιωτική</translation>
<translation id="3583757800736429874">&amp;Επανάληψη μετακίνησης</translation>
<translation id="3586931643579894722">ΑπόκÏυψη λεπτομεÏειÏν</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Εμφάνιση τιμής</translation>
<translation id="3630155396527302611">Εάν έχει ήδη καταχωÏιστεί ως Ï€ÏόγÏαμμα στο οποίο επιτÏέπεται η Ï€Ïόσβαση στο δίκτυο, δοκιμάστε
να το καταÏγήσετε από τη λίστα και να το Ï€Ïοσθέσετε ξανά.</translation>
+<translation id="3638794133396384728">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του έληξε. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. Το Ïολόι του υπολογιστή σας αυτήν τη στιγμή είναι Ïυθμισμένο στην ημεÏομηνία <ph name="CURRENT_TIME" />. Είναι σωστή αυτή η ÏÏθμιση; Εάν όχι, θα Ï€Ïέπει να διοÏθÏσετε το Ïολόι του συστήματός σας και έπειτα να ανανεÏσετε αυτήν τη σελίδα. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Αυτές οι πειÏαματικές λειτουÏγίες ενδέχεται να αλλάξουν, να διακοποÏν ή να εξαφανιστοÏν οποιαδήποτε στιγμή. Δεν παÏέχουμε καμία εγγÏηση όσον αφοÏά τι θα συμβεί σε πεÏίπτωση που ενεÏγοποιήσετε κάποια από αυτές, ÎµÎ½Ï Ï„Î¿ Ï€ÏόγÏαμμα πεÏιήγησής σας ενδέχεται να παÏουσιάσει σφάλμα, όπως να διαγÏάψει όλα τα δεδομένα σας. Επίσης, η ασφάλεια και το απόÏÏητο ενδέχεται να παÏαβιαστοÏν με μη αναμενόμενους Ï„Ïόπους. Αν ενεÏγοποιήσετε κάποια πειÏαματική λειτουÏγία, η λειτουÏγία θα ενεÏγοποιηθεί για όλους τους χÏήστες Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… Ï€ÏογÏάμματος πεÏιήγησης. Συνεχίστε με Ï€Ïοσοχή.</translation>
<translation id="3650584904733503804">Επιτυχής επικÏÏωση</translation>
<translation id="3655670868607891010">Αν αυτό το μήνυμα εμφανίζεται συχνά, μποÏείτε να βÏείτε βοήθεια ÎµÎ´Ï <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">ΑναθεÏÏηση</translation>
+<translation id="3678029195006412963">Δεν ήταν δυνατή η έγκÏιση του αιτήματος</translation>
<translation id="3681007416295224113">ΠληÏοφοÏίες πιστοποιητικοÏ</translation>
<translation id="3693415264595406141">Îωδικός Ï€Ïόσβασης:</translation>
+<translation id="3696411085566228381">κανένα</translation>
<translation id="3700528541715530410">Ωχ, φαίνεται ότι δεν έχετε άδεια Ï€Ïόσβασης σε αυτήν τη σελίδα.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">ΦόÏτωση...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">ΕνεÏγοποιήστε τα δεδομένα κινητής τηλεφωνίας ή το Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Ελέγξτε το διακομιστή μεσολάβησης, το τείχος Ï€Ïοστασίας και τη διαμόÏφωση DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">ΣÏνδεσμος που αντιγÏ.</translation>
-<translation id="3744899669254331632">Δεν μποÏείτε να επισκεφτείτε τον ιστότοπο <ph name="SITE" /> αυτήν τη στιγμή, επειδή ο ιστότοπος έστειλε κωδικοποιημένα διαπιστευτήÏια τα οποία δεν είναι δυνατό να επεξεÏγαστεί το Chromium. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά φαινόμενα, συνεπÏÏ‚ η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα.</translation>
<translation id="375403751935624634">Η μετάφÏαση απέτυχε λόγω σφάλματος διακομιστή.</translation>
<translation id="3759461132968374835">Δεν έχετε Ï€Ïόσφατα αναφεÏθέντα σφάλματα. Τα σφάλματα που Ï€Ïοέκυψαν όταν η αναφοÏά σφαλμάτων ήταν απενεÏγοποιημένη δεν θα εμφανιστοÏν εδÏ.</translation>
<translation id="3788090790273268753">Το πιστοποιητικό για αυτόν τον ιστότοπο λήγει το 2016 και η αλυσίδα πιστοποιητικÏν πεÏιέχει ένα πιστοποιητικό το οποίο έχει υπογÏαφεί με SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">ΑναγνωÏιστικό συσκευής που Ï€Ïοκαλεί διένεξη</translation>
<translation id="3885155851504623709">ΕνοÏία</translation>
<translation id="3901925938762663762">Η κάÏτα έχει λήξει</translation>
+<translation id="3910267023907260648">ΠÏοσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, αλλά ο διακομιστής παÏουσίασε ένα πιστοποιητικό το οποίο ήταν υπογεγÏαμμένο με έναν αδÏναμο αλγόÏιθμο υπογÏαφής. Αυτό σημαίνει ότι μποÏεί να έχουν πλαστογÏαφηθεί τα διαπιστευτήÏια ασφαλείας που επέδειξε ο διακομιστής και ότι αυτός ο διακομιστής ενδέχεται να μην είναι αυτό που αναμένετε (ενδέχεται να επικοινωνείτε με έναν εισβολέα). <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Η ημεÏομηνία του Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Î±ÏƒÏ†Î±Î»ÎµÎ¯Î±Ï‚ του υποτίθεται ότι είναι αυÏιανή. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.}other{Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Η ημεÏομηνία του Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Î±ÏƒÏ†Î±Î»ÎµÎ¯Î±Ï‚ του υποτίθεται ότι είναι από # ημέÏες μετά. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Δεν ήταν δυνατή η φόÏτωση του εγγÏάφου PDF</translation>
<translation id="3963721102035795474">ΛειτουÏγία αναγνÏστη</translation>
+<translation id="397105322502079400">Υπολογισμός…</translation>
<translation id="3973234410852337861">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> είναι αποκλεισμένος</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 ιστοσελίδα σε κοντινή απόσταση}other{# ιστοσελίδες σε κοντινή απόσταση}}</translation>
<translation id="4021036232240155012">Το DNS είναι η υπηÏεσία δικτÏου που μεταφÏάζει το όνομα ενός ιστότοπου στη διεÏθυνσή του στο διαδίκτυο.</translation>
<translation id="4030383055268325496">&amp;ΑναίÏεση Ï€Ïοσθήκης</translation>
-<translation id="4032534284272647190">ΑπαγοÏεÏεται η Ï€Ïόσβαση στο <ph name="URL" />.</translation>
<translation id="404928562651467259">ΠΡΟΕΙΔΟΠΟΙΗΣΗ</translation>
<translation id="4058922952496707368">Îλειδί "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Η εφαÏμογή πελάτης και ο διακομιστής δεν υποστηÏίζουν κάποια κοινή έκδοση Ï€Ïωτοκόλλου SSL ή σουίτα κÏυπτογÏάφησης.</translation>
<translation id="4079302484614802869">Η διαμόÏφωση του διακομιστή μεσολάβησης είναι οÏισμένη να χÏησιμοποιεί μια διεÏθυνση URL σεναÏίου .pac και όχι σταθεÏοÏÏ‚ διακομιστές μεσολάβησης.</translation>
<translation id="4103249731201008433">Ο σειÏιακός αÏιθμός της συσκευής δεν είναι έγκυÏος</translation>
<translation id="4103763322291513355">Επισκεφτείτε την &lt;strong&gt;chrome://policy&lt;/strong&gt; για να δείτε τη λίστα των ανεπιθÏμητων διευθÏνσεων URL και άλλες πολιτικές που έχουν τεθεί σε εφαÏμογή από το διαχειÏιστή του συστήματός σας.</translation>
+<translation id="4110615724604346410">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του πεÏιέχει σφάλματα. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Το εÏÏος της πολιτικής δεν υποστηÏίζεται.</translation>
+<translation id="4118212371799607889">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το Chromium. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 ακόμα}other{# ακόμα}}</translation>
<translation id="4130226655945681476">Έλεγχος καλωδίων, μόντεμ και δÏομολογητή δικτÏου</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Θέλετε το Chromium να αποθηκεÏσει αυτήν την κάÏτα;</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">ΑπενεÏγοποιημένη</translation>
<translation id="4196861286325780578">&amp;Επανάληψη μετακίνησης</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Ελέγξτε τις διαμοÏφÏσεις του τείχους Ï€Ïοστασίας και της Ï€Ïοστασίας από ιοÏÏ‚<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{καμία}=1{1 εφαÏμογή ($1)}=2{2 εφαÏμογές ($1, $2)}other{# εφαÏμογές ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Απότομες διακοπές λειτουÏγίας</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Δοκιμάστε να εκτελέσετε τον Διαγνωστικό έλεγχο δικτÏου<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Όχι</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(ΧωÏίς όνομα χÏήστη)</translation>
<translation id="4300246636397505754">Γονικές Ï€Ïοτάσεις</translation>
<translation id="4304224509867189079">ΣÏνδεση</translation>
+<translation id="432290197980158659">Αυτός ο διακομιστής παÏουσίασε ένα πιστοποιητικό που δεν αντιστοιχεί στις ενσωματωμένες Ï€Ïοϋποθέσεις. Αυτές οι Ï€Ïοϋποθέσεις συμπεÏιλαμβάνονται σε συγκεκÏιμένους ιστότοπους υψηλής ασφάλειας για την Ï€Ïοστασία σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Αποτυχία εÏÏεσης άÏθÏου</translation>
+<translation id="4331708818696583467">Μη ασφαλές</translation>
<translation id="4372948949327679948">Αναμενόμενη τιμή <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">ΠÏοσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, όμως το πιστοποιητικό που παÏουσιάστηκε από το διακομιστή ανακλήθηκε από τον εκδότη του. Αυτό σημαίνει ότι τα διαπιστευτήÏια ασφαλείας που παÏουσιάστηκαν από το διακομιστή δεν Ï€Ïέπει σε καμία πεÏίπτωση να θεωÏηθοÏν αξιόπιστα. Ενδέχεται να επικοινωνείτε με κάποιον εισβολέα.</translation>
<translation id="4381091992796011497">Όνομα χÏήστη:</translation>
<translation id="4394049700291259645">ΑπενεÏγοποίηση</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> έως <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">αποτελέσματα αναζήτησης</translation>
-<translation id="4424024547088906515">Ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από τον Chrome. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
+<translation id="4432688616882109544">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> δεν αποδέχτηκε το πιστοποιητικό σÏνδεσής σας ή μποÏεί να μην διατέθηκε πιστοποιητικό σÏνδεσης.</translation>
<translation id="443673843213245140">Η χÏήση ενός διακομιστή μεσολάβησης είναι απενεÏγοποιημένη, αλλά έχει καθοÏιστεί μια Ïητή διαμόÏφωση διακομιστή μεσολάβησης.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Αυτό το μήνυμα εμφανίζεται επειδή έχει ενεÏγοποιηθεί το Google SafeSites.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">ΛεπτομέÏειες</translation>
<translation id="4558551763791394412">Δοκιμάστε να απενεÏγοποιήσετε τις επεκτάσεις σας.</translation>
<translation id="4587425331216688090">ÎατάÏγηση διεÏθυνσης από το Chrome;</translation>
+<translation id="4589078953350245614">ΠÏοσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, αλλά ο διακομιστής παÏουσίασε ένα μη έγκυÏο πιστοποιητικό. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Η σÏνδεσή σας στο <ph name="DOMAIN" /> κÏυπτογÏαφείται χÏησιμοποιÏντας ένα σÏγχÏονο Ï€ÏόγÏαμμα κÏυπτογÏάφησης.</translation>
<translation id="4594403342090139922">&amp;ΑναίÏεση διαγÏαφής</translation>
+<translation id="4627442949885028695">Συνέχεια από άλλη συσκευή</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Βλέπετε μια σελίδα επέκτασης.</translation>
-<translation id="467662567472608290">Ο διακομιστής δεν κατάφεÏε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του πεÏιέχει σφάλματα. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
-<translation id="4697214168136963651">Η διεÏθυνση <ph name="URL" /> αποκλείστηκε</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Η σÏνδεσή σας διακόπηκε</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Îα εκτελέσετε τον Διαγνωστικό έλεγχο δικτÏου των Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">ΠλατφόÏμα</translation>
<translation id="4744603770635761495">ΔιαδÏομή εκτελέσιμου</translation>
<translation id="4756388243121344051">&amp;ΙστοÏικό</translation>
+<translation id="4759238208242260848">Λήψεις</translation>
<translation id="4764776831041365478">Η ιστοσελίδα στη διεÏθυνση <ph name="URL" /> μποÏεί να βÏίσκεται Ï€ÏοσωÏινά εκτός λειτουÏγίας ή ίσως έχει μεταφεÏθεί μόνιμα σε νέα διεÏθυνση ιστοÏ.</translation>
<translation id="4771973620359291008">ΠαÏουσιάστηκε άγνωστο σφάλμα.</translation>
<translation id="4782449893814226250">ΡÏτησες τους γονείς σου εάν σου επιτÏέπουν να επισκεφτείς αυτήν τη σελίδα.</translation>
<translation id="4800132727771399293">Ελέγξτε την ημεÏομηνία λήξης και τον κωδικό σας CVC και δοκιμάστε ξανά</translation>
-<translation id="4807049035289105102">Δεν μποÏείτε να επισκεφτείτε το <ph name="SITE" /> αυτήν τη στιγμή επειδή ο ιστότοπος έστειλε κωδικοποιημένα διαπιστευτήÏια τα οποία δεν μποÏεί να επεξεÏγαστεί το Google Chrome. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά, συνεπÏÏ‚ αυτή η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα.</translation>
<translation id="4813512666221746211">Σφάλμα δικτÏου</translation>
<translation id="4816492930507672669">ΠÏοσαÏμογή στη σελίδα</translation>
<translation id="4850886885716139402">ΠÏοβολή</translation>
<translation id="4880827082731008257">ΙστοÏικό αναζήτησης</translation>
+<translation id="4884656795097055129">Θα εμφανιστοÏν πεÏισσότεÏα άÏθÏα την κατάλληλη στιγμή.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{και 1 ακόμη ιστοσελίδα}other{και # ακόμη ιστοσελίδες}}</translation>
<translation id="4923417429809017348">Αυτή η σελίδα έχει μεταφÏαστεί από μια άγνωστη γλÏσσας στα <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">ΠÏέπει να καθοÏιστεί.</translation>
<translation id="4930497775425430760">Αυτό το μήνυμα εμφανίζεται επειδή ο γονέας σου θα Ï€Ïέπει να εγκÏίνει τυχόν νέους ιστότοπους την Ï€ÏÏτη φοÏά που τους επισκέπτεσαι.</translation>
<translation id="495170559598752135">ΕνέÏγειες</translation>
<translation id="4958444002117714549">Ανάπτυξη λίστας</translation>
+<translation id="4962322354953122629">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το Chrome. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">ΜετάφÏαση των <ph name="ORIGINAL_LANGUAGE" /> στα <ph name="TARGET_LANGUAGE" />;</translation>
+<translation id="4989809363548539747">Αυτή η Ï€Ïοσθήκη δεν υποστηÏίζεται</translation>
<translation id="5002932099480077015">Εάν ενεÏγοποιηθεί, το Chrome θα αποθηκεÏσει ένα αντίγÏαφο της κάÏτας σας σε αυτήν τη συσκευή για ταχÏτεÏη συμπλήÏωση φοÏμÏν.</translation>
<translation id="5019198164206649151">Η αποθήκευση αντιγÏάφων ασφαλείας είναι σε κακή κατάσταση</translation>
<translation id="5023310440958281426">Ελέγξτε τις πολιτικές του διαχειÏιστή</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Σχετικά με τη Google ΜετάφÏαση</translation>
<translation id="5040262127954254034">ΑπόÏÏητο</translation>
<translation id="5045550434625856497">Λανθασμένος κωδικός Ï€Ïόσβασης</translation>
+<translation id="5056549851600133418">ΆÏθÏα για εσάς</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Ελέγξτε τη διεÏθυνση του διακομιστή μεσολάβησης<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Το πιστοποιητικό του διακομιστή δεν είναι έγκυÏο αυτήν τη στιγμή.</translation>
<translation id="5089810972385038852">Πολιτεία</translation>
-<translation id="5094747076828555589">Ο διακομιστής δεν μποÏεί να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το Chromium. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
<translation id="5095208057601539847">ΕπαÏχία</translation>
<translation id="5115563688576182185">(64-bit)</translation>
-<translation id="5122371513570456792">Î’Ïέθηκαν <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> για "<ph name="SEARCH_STRING" />".</translation>
<translation id="5141240743006678641">ÎÏυπτογÏαφήστε συγχÏονισμένους κωδικοÏÏ‚ Ï€Ïόσβασης με τα διαπιστευτήÏιά σας Google.</translation>
<translation id="5145883236150621069">Î’Ïέθηκε κωδικός σφάλματος στην απόκÏιση πολιτικής</translation>
<translation id="5171045022955879922">Αναζήτηση ή πληκτÏολόγηση διεÏθυνσης URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">ΓÏαμμή σελιδοδεικτÏν</translation>
<translation id="5199729219167945352">ΠειÏάματα</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">ΧÏησιμοποιείτε το Chrome στη δουλειά σας; Οι επιχειÏήσεις μποÏοÏν να διαχειÏίζονται τις Ïυθμίσεις του Chrome για τους εÏγαζόμενοÏÏ‚ τους. Μάθετε πεÏισσότεÏα</translation>
<translation id="5299298092464848405">Σφάλμα ανάλυσης πολιτικής</translation>
<translation id="5300589172476337783">Εμφάνιση</translation>
<translation id="5308689395849655368">Η αναφοÏά σφαλμάτων είναι απενεÏγοποιημένη.</translation>
<translation id="5317780077021120954">Αποθήκευση</translation>
<translation id="5327248766486351172">Όνομα</translation>
+<translation id="5359637492792381994">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν είναι έγκυÏο αυτήν τη στιγμή. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Αποτυχία αποθήκευσης Ïυθμίσεων πολιτικής</translation>
-<translation id="540969355065856584">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν είναι έγκυÏο αυτήν τη στιγμή. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας.</translation>
<translation id="5421136146218899937">ΔιαγÏαφή δεδομένων πεÏιήγησης...</translation>
<translation id="5430298929874300616">ÎατάÏγηση σελιδοδείκτη</translation>
<translation id="5431657950005405462">Το αÏχείο σας δεν βÏέθηκε</translation>
<translation id="5435775191620395718">Εμφάνιση ιστοÏÎ¹ÎºÎ¿Ï Î±Ï€ÏŒ αυτήν τη συσκευή. <ph name="BEGIN_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Οι Ï€Ïοτάσεις εξατομικευμένου πεÏιεχομένου είναι επί του παÏόντος απενεÏγοποιημένες, επειδή τα συγχÏονισμένα δεδομένα σας Ï€ÏοστατεÏονται με μια Ï€ÏοσαÏμοσμένη φÏάση Ï€Ïόσβασης.</translation>
<translation id="5439770059721715174">Σφάλμα επαλήθευσης σχήματος σε "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Δεν είναι δυνατός ο εντοπισμός αυτής της σελίδας του κεντÏÎ¹ÎºÎ¿Ï Ï…Ï€Î¿Î»Î¿Î³Î¹ÏƒÏ„Î® <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">Εσφαλμένη χÏονική σήμανση πολιτικής</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Θέλετε να φÏγετε από αυτόν τον ιστότοπο;</translation>
<translation id="5629630648637658800">Αποτυχία φόÏτωσης Ïυθμίσεων πολιτικής</translation>
<translation id="5631439013527180824">Μη έγκυÏο διακÏιτικό διαχείÏισης συσκευής</translation>
-<translation id="5650551054760837876">Δεν βÏέθηκαν αποτελέσματα αναζήτησης.</translation>
<translation id="5677928146339483299">Αποκλεισμένος</translation>
<translation id="5710435578057952990">Η ταυτότητα Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… ιστότοπου δεν έχει επαληθευτεί.</translation>
<translation id="5720705177508910913">ΤÏέχων χÏήστης</translation>
+<translation id="572328651809341494">ΠÏόσφατες καÏτέλες</translation>
<translation id="5784606427469807560">ΠαÏουσιάστηκε κάποιο Ï€Ïόβλημα κατά την επιβεβαίωση της κάÏτας σας. Ελέγξτε τη σÏνδεσή σας στο διαδίκτυο και δοκιμάστε ξανά.</translation>
<translation id="5785756445106461925">Επίσης, αυτή η σελίδα πεÏιέχει άλλους πόÏους, οι οποίοι δεν είναι ασφαλείς. Αυτοί οι πόÏοι μποÏοÏν να Ï€ÏοβληθοÏν από άλλους χÏήστες κατά τη μετάβαση και μποÏοÏν να Ï„ÏοποποιηθοÏν από έναν εισβολέα Ïστε να αλλάξει η εμφάνιση της σελίδας.</translation>
+<translation id="5786044859038896871">Θέλετε να συμπληÏωθοÏν τα στοιχεία της κάÏτας σας;</translation>
+<translation id="5803412860119678065">Θέλετε να συμπληÏωθοÏν τα στοιχεία της κάÏτας <ph name="CARD_DETAIL" />;</translation>
<translation id="5810442152076338065">Η σÏνδεσή σας στο <ph name="DOMAIN" /> κÏυπτογÏαφείται χÏησιμοποιÏντας ένα απαÏχαιωμένο Ï€ÏόγÏαμμα κÏυπτογÏάφησης.</translation>
<translation id="5813119285467412249">&amp;Επανάληψη Ï€Ïοσθήκης</translation>
+<translation id="5814352347845180253">Ενδέχεται να χάσετε την Ï€Ïόσβαση σε Ï€Ïονομιακό πεÏιεχόμενο από τον ιστότοπο <ph name="SITE" /> και οÏισμένους άλλους ιστότοπους.</translation>
+<translation id="5843436854350372569">ΠÏοσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, αλλά ο διακομιστής παÏουσίασε ένα πιστοποιητικό που πεÏιέχει ένα αδÏναμο κλειδί. Îάποιος εισβολέας θα μποÏοÏσε να έχει παÏαβιάσει το ιδιωτικό κλειδί και ο διακομιστής ενδέχεται να μην είναι ο διακομιστής που αναμένατε (μποÏεί να επικοινωνείτε με έναν εισβολέα). <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Αυτό το μήνυμα εμφανίζεται επειδή ο διαχειÏιστής σας απέκλεισε αυτόν τον ιστότοπο.</translation>
<translation id="5857090052475505287">Îέος φάκελος</translation>
<translation id="5869405914158311789">Δεν είναι δυνατή η Ï€Ïόσβαση σε αυτόν τον ιστότοπο</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Γονικές Ï€Ïοτάσεις</translation>
<translation id="59107663811261420">Αυτός ο Ï„Ïπος κάÏτας δεν υποστηÏίζεται από το Google Payments γι' αυτόν τον έμποÏο. Επιλέξτε διαφοÏετική κάÏτα.</translation>
<translation id="59174027418879706">ΕνεÏγή</translation>
+<translation id="5926846154125914413">Ενδέχεται να χάσετε την Ï€Ïόσβαση σε Ï€Ïονομιακό πεÏιεχόμενο από οÏισμένους ιστότοπους.</translation>
<translation id="5966707198760109579">Εβδομάδα</translation>
<translation id="5967867314010545767">ÎατάÏγηση από το ιστοÏικό</translation>
<translation id="5975083100439434680">ΣμίκÏυνση</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Αυτόματη</translation>
<translation id="6042308850641462728">ΠεÏισσότεÏα</translation>
<translation id="6060685159320643512">ΠÏοσοχή, τέτοια πειÏάματα είναι επικÏνδυνα</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{καμία}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Ελέγξτε τυχόν καλÏδια και επανεκκινήστε δÏομολογητές, μόντεμ ή άλλες συσκευές
του δικτÏου που ενδεχομένως χÏησιμοποιείτε.</translation>
<translation id="614940544461990577">Δοκιμάστε να κάνετε τα εξής:</translation>
<translation id="6150607114729249911">Θα Ï€Ïέπει να Ïωτήσεις τους γονείς σου εάν σου επιτÏέπουν να επισκεφτείς αυτήν τη σελίδα.</translation>
<translation id="6151417162996330722">Το πιστοποιητικό του διακομιστή έχει Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î· πεÏίοδο εγκυÏότητας.</translation>
-<translation id="6154808779448689242">Το εμφανιζόμενο διακÏιτικό πολιτικής δεν αντιστοιχεί με το Ï„Ïέχον διακÏιτικό</translation>
<translation id="6165508094623778733">Μάθετε πεÏισσότεÏα</translation>
<translation id="6203231073485539293">Ελέγξτε τη σÏνδεσή σας στο Internet</translation>
<translation id="6218753634732582820">Îα καταÏγηθεί η διεÏθυνση από το Chromium;</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Δοκιμάστε να απενεÏγοποιήσετε την Ï€Ïόβλεψη δικτÏου</translation>
<translation id="6337534724793800597">ΦιλτÏάÏισμα πολιτικÏν με βάση το όνομα</translation>
<translation id="6342069812937806050">ΠÏιν λίγο</translation>
+<translation id="6345221851280129312">άγνωστο μέγεθος</translation>
<translation id="6355080345576803305">ΠαÏάκαμψη δημόσιας πεÏιόδου σÏνδεσης</translation>
<translation id="6358450015545214790">Τι σημαίνουν αυτά;</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 Ï€Ïόταση ακόμα}other{# Ï€Ïοτάσεις ακόμα}}</translation>
<translation id="6387478394221739770">Θέλετε να ενημεÏÏνεστε για τις συναÏπαστικές νέες δυνατότητες του Chrome; Επισκεφτείτε το κανάλι beta στη διεÏθυνση chrome.com/beta.</translation>
-<translation id="641480858134062906">Απέτυχε η φόÏτωση για <ph name="URL" /></translation>
+<translation id="6389758589412724634">Η διαθέσιμη μνήμη του Chromium εξαντλήθηκε, κατά την Ï€Ïοσπάθεια Ï€Ïοβολής αυτής της ιστοσελίδας.</translation>
+<translation id="6416403317709441254">Δεν μποÏείτε να επισκεφτείτε τον ιστότοπο <ph name="SITE" /> αυτήν τη στιγμή γιατί ο ιστότοπος έστειλε κωδικοποιημένα διαπιστευτήÏια τα οποία δεν είναι δυνατό να επεξεÏγαστεί το Chromium. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά φαινόμενα, συνεπÏÏ‚ η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Δεν είναι δυνατόν να ελεγχθεί αν το πιστοποιητικό έχει ακυÏωθεί.</translation>
<translation id="6433595998831338502">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> απέÏÏιψε τη σÏνδεση.</translation>
<translation id="6445051938772793705">ΧÏÏα</translation>
<translation id="6451458296329894277">Επιβεβαίωση νέας υποβολής φόÏμας</translation>
<translation id="6458467102616083041">Αγνοήθηκε επειδή η Ï€Ïοεπιλεγμένη αναζήτηση είναι απενεÏγοποιημένη από την πολιτική.</translation>
+<translation id="6462969404041126431">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του μποÏεί να ανακληθεί. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Πολιτικές συσκευÏν </translation>
<translation id="6489534406876378309">ΈναÏξη μεταφόÏτωσης σφαλμάτων</translation>
<translation id="6529602333819889595">&amp;Επανάληψη διαγÏαφής</translation>
+<translation id="6534179046333460208">ΠÏοτάσεις Î¦Ï…ÏƒÎ¹ÎºÎ¿Ï Î´Î¹ÎºÏ„Ïου</translation>
<translation id="6550675742724504774">Επιλογές</translation>
+<translation id="6593753688552673085">λιγότεÏο από <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Επιλογές κÏυπτογÏάφησης</translation>
<translation id="662080504995468778">ΠαÏαμονή</translation>
<translation id="6628463337424475685">Αναζήτηση <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Δεν μποÏείτε να επισκεφτείτε τον ιστότοπο <ph name="SITE" /> αυτήν τη στιγμή επειδή <ph name="BEGIN_LINK" />αυτό το πιστοποιητικό έχει ανακληθεί<ph name="END_LINK" />. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά, συνεπÏÏ‚ αυτή η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα.</translation>
<translation id="6644283850729428850">Αυτή η πολιτική έχει αποσυÏθεί.</translation>
+<translation id="6652240803263749613">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το λειτουÏγικό σÏστημα του υπολογιστή σας. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">ΕπεξεÏγασία φακέλου</translation>
<translation id="6660210980321319655">Αυτόματη αναφοÏά <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Îα καταÏγηθεί η Ï€Ïόταση φόÏμας από το Chromium;</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">ΠÏοηγοÏμενο</translation>
<translation id="6710594484020273272">&lt;ΠληκτÏολογήστε ÏŒÏο αναζήτησης&gt;</translation>
<translation id="6711464428925977395">ΥπάÏχει κάποιο Ï€Ïόβλημα με το διακομιστή μεσολάβησης ή η διεÏθυνση είναι εσφαλμένη.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{καμία}=1{1 στοιχείο}other{# στοιχεία}}</translation>
<translation id="674375294223700098">Άγνωστο σφάλμα Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Î´Î¹Î±ÎºÎ¿Î¼Î¹ÏƒÏ„Î®</translation>
<translation id="6753269504797312559">Τιμή πολιτικής</translation>
<translation id="6757797048963528358">Η συσκευή σας τέθηκε σε αδÏάνεια.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Το επίπεδο πολιτικής δεν υποστηÏίζεται.</translation>
<translation id="6895330447102777224">Η κάÏτα σας επιβεβαιÏθηκε</translation>
<translation id="6897140037006041989">ΠαÏάγοντας χÏήστη</translation>
-<translation id="6903907808598579934">ΕνεÏγοποίηση συγχÏονισμοÏ</translation>
<translation id="6915804003454593391">ΧÏήστης</translation>
<translation id="6957887021205513506">Το πιστοποιητικό του διακομιστή φαίνεται να είναι πλαστό.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">ΠεÏιοχή</translation>
<translation id="6973656660372572881">ÎαθοÏίζονται τόσο οι σταθεÏοί διακομιστές μεσολάβησης όσο και μια διεÏθυνση URL σεναÏίου .pac.</translation>
<translation id="6989763994942163495">Εμφάνιση σÏνθετων Ïυθμίσεων…</translation>
+<translation id="7000990526846637657">Δεν βÏέθηκαν καταχωÏίσεις ιστοÏικοÏ</translation>
+<translation id="7009986207543992532">ΠÏοσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, αλλά ο διακομιστής παÏουσίασε ένα πιστοποιητικό με πεÏίοδο εγκυÏότητας η οποία είναι Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î· για να θεωÏηθεί αξιόπιστη. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Ο ΛογαÏιασμός σας Google ενδέχεται να διαθέτει άλλες μοÏφές ιστοÏÎ¹ÎºÎ¿Ï Ï€ÎµÏιήγησης στη διεÏθυνση <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Îωδικοί Ï€Ïόσβασης</translation>
-<translation id="7050187094878475250">ΕπιχειÏήσατε να μεταβείτε στο <ph name="DOMAIN" />, αλλά ο διακομιστής παÏουσίασε ένα πιστοποιητικό με πεÏίοδο εγκυÏότητας η οποία είναι Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î· για να θεωÏηθεί αξιόπιστη.</translation>
<translation id="7087282848513945231">ΠεÏιφέÏεια</translation>
<translation id="7088615885725309056">ΠαλαιότεÏο</translation>
<translation id="7090678807593890770">Αναζητήστε στο Google για <ph name="LINK" /></translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Αυτό το μήνυμα εμφανίζεται επειδή ο διαχειÏιστής σας θα Ï€Ïέπει να εγκÏίνει τυχόν νέους ιστότοπους την Ï€ÏÏτη φοÏά που τους επισκέπτεστε.</translation>
<translation id="724975217298816891">Εισαγάγετε την ημεÏομηνία λήξης και τον κωδικό CVC για την πιστωτική κάÏτα <ph name="CREDIT_CARD" />, Ï€Ïοκειμένου να ενημεÏÏσετε τα στοιχεία της κάÏτας σας. Μετά την επιβεβαίωση, θα γίνει κοινή χÏήση των στοιχείων της κάÏτας σας με αυτόν τον ιστότοπο.</translation>
<translation id="725866823122871198">Δεν είναι δυνατή η επίτευξη ιδιωτικής σÏνδεσης με τον τομέα <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> επειδή η ημεÏομηνία και η ÏÏα (<ph name="DATE_AND_TIME" />) του υπολογιστή σας είναι λανθασμένες.</translation>
-<translation id="7265986070661382626">Δεν μποÏείτε να επισκεφτείτε το <ph name="SITE" /> αυτήν τη στιγμή επειδή ο ιστότοπος <ph name="BEGIN_LINK" />χÏησιμοποιεί certificate pinning (κλείδωμα πιστοποιητικÏν)<ph name="END_LINK" />. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά, συνεπÏÏ‚ αυτή η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα.</translation>
<translation id="7269802741830436641">Αυτή η ιστοσελίδα πεÏιλαμβάνει βÏόχο ανακατεÏθυνσης</translation>
<translation id="7275334191706090484">ΔιαχειÏιζόμενοι σελιδοδείκτες</translation>
<translation id="7298195798382681320">ΠÏοτεινόμενες</translation>
-<translation id="7301833672208172928">ΕνεÏγοποίηση συγχÏÎ¿Î½Î¹ÏƒÎ¼Î¿Ï Î¹ÏƒÏ„Î¿ÏικοÏ</translation>
+<translation id="7309308571273880165">ΑναφοÏά σφαλμάτων που καταγÏάφηκε στις <ph name="CRASH_TIME" /> (η μεταφόÏτωση ζητήθηκε από τον χÏήστη, δεν έχει μεταφοÏτωθεί ακόμη)</translation>
<translation id="7334320624316649418">&amp;Επανάληψη αναδιάταξης</translation>
<translation id="733923710415886693">Το πιστοποιητικό του διακομιστή δεν αποκαλÏφθηκε μέσω της Διαφάνειας πιστοποιητικÏν.</translation>
+<translation id="7351800657706554155">Δεν μποÏείτε να επισκεφτείτε τον ιστότοπο <ph name="SITE" /> αυτήν τη στιγμή γιατί το πιστοποιητικό του έχει ανακληθεί. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά, συνεπÏÏ‚ αυτή η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">ΓÏαμμή εντολÏν</translation>
<translation id="7372973238305370288">αποτέλεσμα αναζήτησης</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">Επιβεβαίωση κάÏτας</translation>
<translation id="7481312909269577407">ΠÏοÏθηση</translation>
<translation id="7485870689360869515">Δεν βÏέθηκαν δεδομένα</translation>
+<translation id="7508255263130623398">Η εμφανιζόμενη συσκευή πολιτικής είναι κενή ή δεν αντιστοιχεί στο Ï„Ïέχον αναγνωÏιστικό συσκευής</translation>
<translation id="7514365320538308">Λήψη</translation>
<translation id="7518003948725431193">Δεν βÏέθηκε καμία ιστοσελίδα για τη διεÏθυνση ιστοÏ:<ph name="URL" /></translation>
<translation id="7537536606612762813">ΥποχÏεωτική</translation>
<translation id="7542995811387359312">Η αυτόματη συμπλήÏωση πιστωτικής κάÏτας έχει απενεÏγοποιηθεί, επειδή αυτή η φόÏμα δεν χÏησιμοποιεί ασφαλή σÏνδεση.</translation>
<translation id="7549584377607005141">Για τη σωστή εμφάνιση αυτής της ιστοσελίδας, απαιτοÏνται δεδομένα που καταχωÏίσατε νωÏίτεÏα. ΜποÏείτε να αποστείλετε ξανά αυτά τα δεδομένα, ωστόσο, έτσι θα επαναλάβετε κάθε ενέÏγεια που εκτέλεσε νωÏίτεÏα αυτή η σελίδα.</translation>
<translation id="7554791636758816595">Îέα καÏτέλα</translation>
-<translation id="7567204685887185387">Ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του μποÏεί να εκδόθηκε παÏάνομα. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
<translation id="7568593326407688803">Αυτή η σελίδα είναι στα<ph name="ORIGINAL_LANGUAGE" />Θέλετε να τη μεταφÏάσετε;</translation>
<translation id="7569952961197462199">ÎατάÏγηση πιστωτικής κάÏτας από το Chrome;</translation>
<translation id="7578104083680115302">Îάντε γÏήγοÏες πληÏωμές σε ιστότοπους και εφαÏμογές σε διαφοÏετικές συσκευές χÏησιμοποιÏντας κάÏτες που έχετε αποθηκεÏσει στο Google.</translation>
+<translation id="7588950540487816470">Φυσικό δίκτυο</translation>
<translation id="7592362899630581445">Το πιστοποιητικό του διακομιστή παÏαβαίνει τους πεÏιοÏισμοÏÏ‚ ονόματος.</translation>
<translation id="759889825892636187">Αυτήν τη στιγμή, ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> δεν μποÏεί να διαχειÏιστεί αυτό το αίτημα.</translation>
<translation id="7600965453749440009">Îα μην γίνεται ποτέ μετάφÏαση από <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">Îα καταÏγηθεί η πιστωτική κάÏτα από το Chromium;</translation>
<translation id="765676359832457558">ΑπόκÏυψη σÏνθετων Ïυθμίσεων…</translation>
<translation id="7658239707568436148">ΑκÏÏωση</translation>
+<translation id="7667346355482952095">Το εμφανιζόμενο διακÏιτικό πολιτικής είναι κενό ή δεν αντιστοιχεί στο Ï„Ïέχον διακÏιτικό</translation>
<translation id="7668654391829183341">Άγνωστη συσκευή</translation>
<translation id="7674629440242451245">Θέλετε να ενημεÏÏνεστε για τις συναÏπαστικές νέες δυνατότητες του Chrome; Επισκεφτείτε το κανάλι Ï€ÏογÏαμματιστÏν στη διεÏθυνση chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Μετάβαση στον ιστότοπο <ph name="SITE" /> (μη ασφαλής)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">Όχι, ευχαÏιστÏ</translation>
<translation id="7805768142964895445">Îατάσταση</translation>
<translation id="7813600968533626083">ÎατάÏγηση Ï€Ïότασης φόÏμας από το Chrome;</translation>
+<translation id="7815407501681723534">Î’Ïέθηκαν <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> για τον ÏŒÏο αναζήτησης "<ph name="SEARCH_STRING" />"</translation>
<translation id="785549533363645510">Ωστόσο, δεν είστε αόÏατος/η. Με την κατάσταση ανÏνυμης πεÏιήγησης δεν μποÏείτε να αποκÏÏψετε τα στοιχεία της πεÏιήγησής σας από τους εÏγοδότες σας, τον πάÏοχο υπηÏεσιÏν διαδικτÏου που χÏησιμοποιείτε ή τους ιστότοπους που επισκέπτεστε.</translation>
<translation id="7887683347370398519">Ελέγξτε τον κωδικό σας CVC και δοκιμάστε ξανά</translation>
<translation id="7894616681410591072">ΧÏειάζεστε άδεια από το χÏήστη <ph name="NAME" /> για να μεταβείτε σε αυτήν τη σελίδα.</translation>
-<translation id="790025292736025802">Δεν είναι δυνατή η εÏÏεση της διεÏθυνσης <ph name="URL" /></translation>
<translation id="7912024687060120840">Στον φάκελο:</translation>
<translation id="7920092496846849526">ΡÏτησες τους γονείς σου εάν σου επιτÏέπουν να επισκεφτείς αυτήν τη σελίδα.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">Δεν καθοÏίστηκε</translation>
<translation id="8012647001091218357">Δεν ήταν δυνατή η επικοινωνία με τους γονείς σας αυτήν τη στιγμή. Δοκιμάστε ξανά.</translation>
<translation id="8034522405403831421">Αυτή η σελίδα είναι στα <ph name="SOURCE_LANGUAGE" />. ΜετάφÏασή της στα <ph name="TARGET_LANGUAGE" />;</translation>
-<translation id="8034955203865359138">Δεν βÏέθηκαν καταχωÏίσεις ιστοÏικοÏ.</translation>
<translation id="8088680233425245692">Αποτυχία Ï€Ïοβολής άÏθÏου.</translation>
+<translation id="8089520772729574115">λιγότεÏο από 1 MB</translation>
<translation id="8091372947890762290">Η ενεÏγοποίηση στο διακομιστή εκκÏεμεί</translation>
+<translation id="8129262335948759431">άγνωστη ποσότητα</translation>
<translation id="8131740175452115882">Επιβεβαίωση</translation>
<translation id="8134994873729925007">Δεν ήταν δυνατή η εÏÏεση της <ph name="BEGIN_ABBR" />διεÏθυνσης DNS<ph name="END_ABBR" /> του διακομιστή <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Ο υπολογιστής σας τέθηκε σε αδÏάνεια.</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">Η διεÏθυνση URL ενημέÏωσης για την επέκταση με αναγνωÏιστικό ID "<ph name="EXTENSION_ID" />", δεν είναι έγκυÏη.</translation>
<translation id="8218327578424803826">ΕκχωÏημένη τοποθεσία:</translation>
<translation id="8225771182978767009">Το άτομο που ÏÏθμισε αυτόν τον υπολογιστή επέλεξε να αποκλείσει αυτόν τον ιστότοπο.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Στη σελίδα που αναζητάτε χÏησιμοποποιήθηκαν πληÏοφοÏίες που καταχωÏίσατε. Αν επιστÏέψετε σε αυτή τη σελίδα ίσως επαναληφθοÏν ενέÏγειες που εκτελέσατε. Θέλετε να συνεχίσετε;</translation>
<translation id="8249320324621329438">Τελευταία ανάκτηση:</translation>
<translation id="8261506727792406068">ΔιαγÏαφή</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">ΓÏαμμή σελιδοδεικτÏν</translation>
<translation id="8363502534493474904">ΑπενεÏγοποιήστε τη λειτουÏγία πτήσης</translation>
<translation id="8364627913115013041">Δεν έχει οÏιστεί.</translation>
+<translation id="8380941800586852976">Επικίνδυνο</translation>
<translation id="8412145213513410671">Σφάλματα (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">ΠÏέπει να εισαγάγετε δÏο φοÏές την ίδια φÏάση Ï€Ïόσβασης.</translation>
<translation id="8428213095426709021">Ρυθμίσεις</translation>
+<translation id="8433057134996913067">Αυτή η ενέÏγεια θα σας αποσυνδέσει από τους πεÏισσότεÏους ιστότοπους.</translation>
<translation id="8437238597147034694">&amp;ΑναίÏεση μετακίνησης</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 πιστωτική κάÏτα}other{# πιστωτικές κάÏτες}}</translation>
+<translation id="8483780878231876732">Για να χÏησιμοποιήσετε κάÏτες από τον ΛογαÏιασμό σας Google, συνδεθείτε στο Chrome</translation>
<translation id="8488350697529856933">ΙσχÏει για</translation>
<translation id="8498891568109133222">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> άÏγησε Ï€Î¿Î»Ï Î½Î± ανταποκÏιθεί.</translation>
+<translation id="852346902619691059">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι το <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το λειτουÏγικό σÏστημα της συσκευής σας. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Αυτός ο Ï„Ïπος κάÏτας δεν υποστηÏίζεται από το Google Payments. Επιλέξτε άλλη κάÏτα.</translation>
<translation id="8550022383519221471">Η υπηÏεσία συγχÏÎ¿Î½Î¹ÏƒÎ¼Î¿Ï Î´ÎµÎ½ είναι διαθέσιμη για τον τομέα σας.</translation>
<translation id="8553075262323480129">Η μετάφÏαση απέτυχε επειδή δεν ήταν δυνατός ο Ï€ÏοσδιοÏισμός της σελίδας.</translation>
@@ -633,17 +675,14 @@
<translation id="8647750283161643317">ΕπαναφοÏά Ï€ÏοεπιλογÏν</translation>
<translation id="8680787084697685621">Τα στοιχεία σÏνδεσης λογαÏÎ¹Î±ÏƒÎ¼Î¿Ï Î­Ï‡Î¿Ï…Î½ λήξει.</translation>
<translation id="8703575177326907206">Η σÏνδεσή σας με τον τομέα <ph name="DOMAIN" /> δεν είναι κÏυπτογÏαφημένη.</translation>
-<translation id="8713130696108419660">Εσφαλμένη αÏχική υπογÏαφή</translation>
<translation id="8725066075913043281">ΠÏοσπαθήστε ξανά</translation>
<translation id="8728672262656704056">ΠÏαγματοποιείτε ανÏνυμη πεÏιήγηση</translation>
<translation id="8730621377337864115">ΟλοκληÏÏθηκε</translation>
<translation id="8738058698779197622">Για την επίτευξη μιας ασφαλοÏÏ‚ σÏνδεσης, θα Ï€Ïέπει να γίνει σωστή ÏÏθμιση του ÏÎ¿Î»Î¿Î³Î¹Î¿Ï ÏƒÎ±Ï‚. Αυτό οφείλεται στο γεγονός ότι τα πιστοποιητικά που χÏησιμοποιοÏν οι ιστότοποι για την ταυτοποίησή τους είναι έγκυÏα μόνο για συγκεκÏιμένες χÏονικές πεÏιόδους. Εφόσον το Ïολόι της συσκευής σας δεν είναι σωστά Ïυθμισμένο, το Chromium δεν μποÏεί να επαληθεÏσει αυτά τα πιστοποιητικά.</translation>
<translation id="8740359287975076522">Δεν ήταν δυνατός ο εντοπισμός της &lt;abbr id="dnsDefinition"&gt;διεÏθυνσης DNS&lt;/abbr&gt; του κεντÏÎ¹ÎºÎ¿Ï Ï…Ï€Î¿Î»Î¿Î³Î¹ÏƒÏ„Î® <ph name="HOST_NAME" />. Γίνεται διάγνωση του Ï€Ïοβλήματος.</translation>
-<translation id="8741995161408053644">Ο ΛογαÏιασμός σας Google ενδέχεται να διαθέτει άλλες μοÏφές ιστοÏÎ¹ÎºÎ¿Ï Ï€ÎµÏιήγησης στη διεÏθυνση <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Επανάληψη διαγÏαφής</translation>
-<translation id="8790687370365610530">Για να λάβετε εξατομικευμένο πεÏιεχόμενο που Ï€Ïοτείνεται από την Google, ενεÏγοποιήστε τον συγχÏονισμό ιστοÏικοÏ.</translation>
<translation id="8798099450830957504">ΠÏοεπιλογή</translation>
-<translation id="8804164990146287819">Πολιτική ΑποÏÏήτου</translation>
+<translation id="8804164990146287819">Πολιτική αποÏÏήτου</translation>
<translation id="8820817407110198400">Σελιδοδείκτες</translation>
<translation id="8834246243508017242">ΕνεÏγοποίηση Αυτόματης συμπλήÏωσης χÏησιμοποιÏντας τις Επαφές…</translation>
<translation id="883848425547221593">Άλλοι σελιδοδείκτες</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">Το πιστοποιητικό του διακομιστή έχει λήξει.</translation>
<translation id="8987927404178983737">Μήνας</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Ο διακομιστής παÏουσίασε ένα πιστοποιητικό το οποίο δεν αποκαλÏφθηκε δημοσίως με χÏήση της πολιτικής Διαφάνειας πιστοποιητικÏν. Αυτό απαιτείται για οÏισμένα πιστοποιητικά, Ï€Ïοκειμένου να διασφαλιστεί ότι είναι αξιόπιστα και παÏέχουν Ï€Ïοστασία ενάντια σε εισβολείς.</translation>
<translation id="9001074447101275817">Απαιτείται όνομα χÏήστη και κωδικός Ï€Ïόσβασης για το διακομιστή μεσολάβησης <ph name="DOMAIN" />.</translation>
<translation id="901974403500617787">Οι επισημάνσεις που ισχÏουν για ολόκληÏο το σÏστημα μποÏοÏν να οÏιστοÏν μόνο από τον κάτοχο: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Αυτή η σελίδα έχει μεταφÏαστεί στα <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="9038649477754266430">ΧÏήση μιας υπηÏεσίας Ï€Ïόβλεψης για ταχÏτεÏη φόÏτωση σελίδων</translation>
<translation id="9039213469156557790">Επίσης, αυτή η σελίδα πεÏιέχει άλλους πόÏους, οι οποίοι δεν είναι ασφαλείς. Αυτοί οι πόÏοι μποÏοÏν να Ï€ÏοβληθοÏν από άλλους χÏήστες κατά τη μετάβαση και μποÏοÏν να Ï„ÏοποποιηθοÏν από έναν εισβολέα Ïστε να αλλάξει η συμπεÏιφοÏά της σελίδας.</translation>
-<translation id="9049981332609050619">ΕπιχειÏήσατε να μεταβείτε στον <ph name="DOMAIN" /> , αλλά ο διακομιστής παÏουσίασε ένα μη έγκυÏο πιστοποιητικό.</translation>
<translation id="9050666287014529139">ΦÏάση Ï€Ïόσβασής σας</translation>
<translation id="9065203028668620118">ΕπεξεÏγασία</translation>
<translation id="9092364396508701805">Η σελίδα του κεντÏÎ¹ÎºÎ¿Ï Ï…Ï€Î¿Î»Î¿Î³Î¹ÏƒÏ„Î® <ph name="HOST_NAME" /> δεν λειτουÏγεί</translation>
diff --git a/chromium/components/strings/components_strings_en-GB.xtb b/chromium/components/strings/components_strings_en-GB.xtb
index e37e23304e0..6df3cb670a6 100644
--- a/chromium/components/strings/components_strings_en-GB.xtb
+++ b/chromium/components/strings/components_strings_en-GB.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="en-GB">
+<translation id="1008557486741366299">Not Now</translation>
<translation id="1015730422737071372">Provide additional details.</translation>
<translation id="1032854598605920125">Rotate clockwise</translation>
<translation id="1038842779957582377">unknown name</translation>
+<translation id="1053591932240354961">You cannot visit <ph name="SITE" /> at the moment because the website sent scrambled credentials that Google Chrome cannot process. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Undo Add</translation>
<translation id="10614374240317010">Never saved</translation>
-<translation id="1064422015032085147">The server hosting the web page might be overloaded or under maintenance.
- In order to avoid generating too much traffic and make the situation worse,
- requests to this URL have been temporarily disallowed.</translation>
<translation id="106701514854093668">Desktop Bookmarks</translation>
<translation id="1080116354587839789">Fit to width</translation>
+<translation id="1103124106085518534">Finished for now</translation>
<translation id="1103523840287552314">Always translate <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">If ticked, Chrome will store a copy of your card on this device for faster form filling.</translation>
+<translation id="1111153019813902504">Recent bookmarks</translation>
<translation id="1113869188872983271">&amp;Undo reorder</translation>
+<translation id="1126551341858583091">The size on the local storage is <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Policy cache OK</translation>
<translation id="113188000913989374"><ph name="SITE" /> says:</translation>
<translation id="1132774398110320017">Chrome Auto-fill settings...</translation>
-<translation id="1150979032973867961">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by your computer's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="1152921474424827756">Access a <ph name="BEGIN_LINK" />cached copy<ph name="END_LINK" /> of <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> unexpectedly closed the connection.</translation>
<translation id="1161325031994447685">Reconnecting to Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Remove</translation>
<translation id="1201402288615127009">Next</translation>
<translation id="1201895884277373915">More from this site</translation>
-<translation id="121201262018556460">You attempted to reach <ph name="DOMAIN" />, but the server presented a certificate containing a weak key. An attacker could have broken the private key and the server may not be the server you expected (you may be communicating with an attacker).</translation>
+<translation id="1206967143813997005">Bad initial signature</translation>
+<translation id="1209206284964581585">Hide for now</translation>
<translation id="1219129156119358924">System Security</translation>
<translation id="1227224963052638717">Unknown policy.</translation>
<translation id="1227633850867390598">Hide value</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Yes</translation>
<translation id="1430915738399379752">Print</translation>
<translation id="1442912890475371290">Blocked attempt <ph name="BEGIN_LINK" /> to visit a page on <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">You cannot visit <ph name="SITE" /> at the moment because the website uses certificate pinning. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Show a saved (i.e. known to be out of date) copy of this page.</translation>
<translation id="1519264250979466059">Build Date</translation>
<translation id="1549470594296187301">JavaScript must be enabled to use this feature.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">The network configuration is invalid and couldn't be imported.</translation>
<translation id="1644574205037202324">History</translation>
<translation id="1645368109819982629">Unsupported protocol</translation>
-<translation id="1655462015569774233">{1,plural, =1{This server could not prove that it is <ph name="DOMAIN" />; its security certificate expired yesterday. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_DATE" />. Does that look right? If not, you should correct your system's clock and then refresh this page.}other{This server could not prove that it is <ph name="DOMAIN" />; its security certificate expired # days ago. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_DATE" />. Does that look right? If not, you should correct your system's clock and then refresh this page.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> normally uses encryption to protect your information. When Google Chrome tried to connect to <ph name="SITE" /> this time, the website sent back unusual and incorrect credentials. This may happen when an attacker is trying to pretend to be <ph name="SITE" />, or a Wi-Fi sign-in screen has interrupted the connection. Your information is still secure because Google Chrome stopped the connection before any data was exchanged.</translation>
<translation id="168841957122794586">The server certificate contains a weak cryptographic key.</translation>
<translation id="1701955595840307032">Get suggested content</translation>
-<translation id="1706954506755087368">{1,plural, =1{This server could not prove that it is <ph name="DOMAIN" />; its security certificate is supposedly from tomorrow. This may be caused by a misconfiguration or an attacker intercepting your connection.}other{This server could not prove that it is <ph name="DOMAIN" />; its security certificate is supposedly from # days in the future. This may be caused by a misconfiguration or an attacker intercepting your connection.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Try contacting the system admin.</translation>
<translation id="17513872634828108">Open tabs</translation>
<translation id="1753706481035618306">Page number</translation>
-<translation id="1761412452051366565">To get personalised content suggested by Google, turn on sync.</translation>
-<translation id="1763864636252898013">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by your device's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Try running Windows Network Diagnostics<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Please update your sync passphrase.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Your recently visited bookmarks will appear here.</translation>
<translation id="1821930232296380041">Invalid request or request parameters</translation>
<translation id="1838667051080421715">You are viewing the source of a web page.</translation>
<translation id="1871208020102129563">Proxy is set to use fixed proxy servers, not a .pac script URL.</translation>
<translation id="1883255238294161206">Collapse list</translation>
<translation id="1898423065542865115">Filtering</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> didn’t accept your login certificate or your login certificate may have expired.</translation>
<translation id="194030505837763158">Go to <ph name="LINK" /></translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> Bookmarks</translation>
<translation id="1973335181906896915">Serialisation error</translation>
<translation id="1974060860693918893">Advanced</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{and 1 more}other{and # more}}</translation>
<translation id="2025186561304664664">Proxy is set to auto-configured.</translation>
<translation id="2030481566774242610">Did you mean <ph name="LINK" />?</translation>
<translation id="2031925387125903299">You're seeing this message because your parents need to approve new sites on your first visit.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Checking the proxy and the firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ZIP code</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 suggestion}other{# suggestions}}</translation>
<translation id="2065985942032347596">Authentication Required</translation>
<translation id="2079545284768500474">Undo</translation>
<translation id="20817612488360358">System proxy settings are set to be used but an explicit proxy configuration is also specified.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Edit Bookmark</translation>
<translation id="2166049586286450108">Full Admin Access</translation>
<translation id="2166378884831602661">This site can’t provide a secure connection</translation>
-<translation id="2171101176734966184">You attempted to reach <ph name="DOMAIN" />, but the server presented a certificate signed using a weak signature algorithm. This means that the security credentials the server presented could have been forged and the server may not be the server you expected (you may be communicating with an attacker).</translation>
<translation id="2181821976797666341">Policies</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 address}other{# addresses}}</translation>
<translation id="2212735316055980242">Policy not found</translation>
<translation id="2213606439339815911">Fetching entries...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> is not available</translation>
<translation id="2230458221926704099">Fix your connection using the <ph name="BEGIN_LINK" />diagnostics app<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Send now</translation>
<translation id="225207911366869382">This value is deprecated for this policy.</translation>
<translation id="2262243747453050782">HTTP error</translation>
<translation id="2282872951544483773">Unavailable Experiments</translation>
<translation id="2292556288342944218">Your Internet access is blocked</translation>
<translation id="229702904922032456">A root or intermediate certificate has expired.</translation>
<translation id="230155334948463882">New card?</translation>
+<translation id="2305919008529760154">This server could not prove that it is <ph name="DOMAIN" />; its security certificate might have been issued fraudulently. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> requires a username and password.</translation>
+<translation id="2318774815570432836">You cannot visit <ph name="SITE" /> at the moment because the website uses HSTS. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Ignored invalid bookmark at index <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Other bookmarks</translation>
<translation id="2359808026110333948">Continue</translation>
<translation id="2365563543831475020">Crash report captured on <ph name="CRASH_TIME" /> was not uploaded</translation>
<translation id="2367567093518048410">Level</translation>
+<translation id="2371153335857947666">{1,plural, =1{This server could not prove that it is <ph name="DOMAIN" />; its security certificate expired yesterday. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_DATE" />. Does that look right? If not, you should correct your system's clock and then refresh this page. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.}other{This server could not prove that it is <ph name="DOMAIN" />; its security certificate expired # days ago. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_DATE" />. Does that look right? If not, you should correct your system's clock and then refresh this page. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">No UI alternatives available</translation>
<translation id="2384307209577226199">Enterprise default</translation>
-<translation id="238526402387145295">You cannot visit <ph name="SITE" /> right now because the website <ph name="BEGIN_LINK" />uses HSTS<ph name="END_LINK" />. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
<translation id="2386255080630008482">Server's certificate has been revoked</translation>
<translation id="2392959068659972793">Show policies with no value set</translation>
<translation id="2396249848217231973">&amp;Undo delete</translation>
-<translation id="2413528052993050574">This server could not prove that it is <ph name="DOMAIN" />; its security certificate might be revoked. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="2455981314101692989">This web page has disabled automatic filling for this form.</translation>
+<translation id="2463739503403862330">Fill in</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Running Network Diagnostics<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Invalid search URL.</translation>
<translation id="2491120439723279231">Server's certificate contains errors.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Submit</translation>
<translation id="2674170444375937751">Are you sure that you want to delete these pages from your history?</translation>
<translation id="2677748264148917807">Leave</translation>
+<translation id="269990154133806163">The server presented a certificate that was not publicly disclosed using the Certificate Transparency policy. This is a requirement for some certificates, to ensure that they are trustworthy and protect against attackers. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Value doesn't match format.</translation>
<translation id="2704951214193499422">Chromium was unable to confirm your card at this time. Please try again later.</translation>
<translation id="2705137772291741111">The saved (cached) copy of this site was unreadable.</translation>
<translation id="2709516037105925701">Auto-fill</translation>
+<translation id="2712118517637785082">You attempted to reach <ph name="DOMAIN" />, but the certificate that the server presented has been revoked by its issuer. This means that the security credentials the server presented absolutely should not be trusted. You may be communicating with an attacker. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Ask permission</translation>
<translation id="2721148159707890343">Request succeeded</translation>
<translation id="2728127805433021124">Server's certificate is signed using a weak signature algorithm.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Address and search bar</translation>
<translation id="2826760142808435982">The connection is encrypted and authenticated using <ph name="CIPHER" /> and uses <ph name="KX" /> as the key exchange mechanism.</translation>
<translation id="2835170189407361413">Clear form</translation>
-<translation id="2837049386027881519">The connection had to be retried using an older version of the TLS or SSL protocol. This typically means that the server is using very old software and may have other security issues.</translation>
<translation id="284702764277384724">The server certificate at <ph name="HOST_NAME" /> appears to be a forgery.</translation>
<translation id="2889159643044928134">Don't reload</translation>
-<translation id="2896499918916051536">This plug-in is not supported.</translation>
+<translation id="2900469785430194048">Google Chrome ran out of memory while trying to display this web page.</translation>
<translation id="2909946352844186028">A network change was detected.</translation>
-<translation id="2915500479781995473">This server could not prove that it is <ph name="DOMAIN" />; its security certificate expired. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_TIME" />. Does that look right? If not, you should correct your system's clock and then refresh this page.</translation>
<translation id="2922350208395188000">Server's certificate cannot be checked.</translation>
-<translation id="2941952326391522266">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is from <ph name="DOMAIN2" />. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="2948083400971632585">You can disable any proxies configured for a connection from the settings page.</translation>
<translation id="2955913368246107853">Close find bar</translation>
<translation id="2958431318199492670">The network configuration doesn't comply to the ONC standard. Parts of the configuration may not be imported.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Wrong policy type</translation>
<translation id="3032412215588512954">Do you want to reload this site?</translation>
<translation id="3037605927509011580">Aw, Snap!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{at least 1 item on synced devices}=1{1 item (and more on synced devices)}other{# items (and more on synced devices)}}</translation>
<translation id="3041612393474885105">Certificate Information</translation>
<translation id="3063697135517575841">Chrome was unable to confirm your card at this time. Please try again later.</translation>
<translation id="3093245981617870298">You are offline</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Newest</translation>
<translation id="3207960819495026254">Bookmarked</translation>
-<translation id="3225919329040284222">The server presented a certificate that doesn't match built-in expectations. These expectations are included for certain, high-security websites in order to protect you.</translation>
<translation id="3226128629678568754">Press the reload button to resubmit the data needed to load the page.</translation>
<translation id="3228969707346345236">The translation failed because the page is already in <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Enter the CVC for <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Bookmark this page</translation>
<translation id="3270847123878663523">&amp;Undo Reorder</translation>
<translation id="3286538390144397061">Restart Now</translation>
+<translation id="3303855915957856445">No search results found</translation>
<translation id="3305707030755673451">Your data was encrypted with your sync passphrase on <ph name="TIME" />. Enter it to start sync.</translation>
<translation id="333371639341676808">Prevent this page from creating additional dialogues.</translation>
+<translation id="3338095232262050444">Secure</translation>
<translation id="3340978935015468852">settings</translation>
<translation id="3345135638360864351">Your request to access this site could not be sent to <ph name="NAME" />. Please try again.</translation>
<translation id="3355823806454867987">Change proxy settings...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Fetch interval:</translation>
<translation id="3462200631372590220">Hide advanced</translation>
<translation id="3479539252931486093">Was this unexpected? <ph name="BEGIN_LINK" />Let us know<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Not now</translation>
<translation id="348000606199325318">Crash ID <ph name="CRASH_LOCAL_ID" /> (Server ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">We could not reach your parent at the moment. Please try again.</translation>
<translation id="3527085408025491307">Folder</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Use password for:</translation>
<translation id="3549644494707163724">Encrypt all synced data with your own sync passphrase</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> more...</translation>
+<translation id="3555561725129903880">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is from <ph name="DOMAIN2" />. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Your connection is not private</translation>
<translation id="3583757800736429874">&amp;Redo Move</translation>
<translation id="3586931643579894722">Hide details</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Show value</translation>
<translation id="3630155396527302611">If it is already listed as a program allowed to access the network, try
removing it from the list and adding it again.</translation>
+<translation id="3638794133396384728">This server could not prove that it is <ph name="DOMAIN" />; its security certificate expired. This may be caused by a misconfiguration or an attacker intercepting your connection. Your computer's clock is currently set to <ph name="CURRENT_TIME" />. Does that look right? If not, you should correct your system's clock and then refresh this page. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">These experimental features may change, break or disappear at any time. We make absolutely no guarantees about what may happen if you turn one of these experiments on, and your browser may even spontaneously combust. Jokes aside, your browser may delete all your data or your security and privacy could be compromised in unexpected ways. Any experiments that you enable will be enabled for all users of this browser. Please proceed with caution.</translation>
<translation id="3650584904733503804">Validation successful</translation>
<translation id="3655670868607891010">If you're seeing this frequently, try these <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Revision</translation>
+<translation id="3678029195006412963">Request could not be signed</translation>
<translation id="3681007416295224113">Certificate information</translation>
<translation id="3693415264595406141">Password:</translation>
+<translation id="3696411085566228381">none</translation>
<translation id="3700528541715530410">Oops, looks like you don't have permission to access this page.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Loading...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Turning on mobile data or Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Checking the proxy, firewall and DNS configuration<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Link that you copied</translation>
-<translation id="3744899669254331632">You cannot visit <ph name="SITE" /> right now because the website sent scrambled credentials that Chromium cannot process. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
<translation id="375403751935624634">The translation failed because of a server error.</translation>
<translation id="3759461132968374835">You have no recently reported crashes. Crashes that occurred when crash reporting was disabled will not appear here.</translation>
<translation id="3788090790273268753">The certificate for this site expires in 2016, and the certificate chain contains a certificate signed using SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Conflicting device identifier</translation>
<translation id="3885155851504623709">Parish</translation>
<translation id="3901925938762663762">The card is expired</translation>
+<translation id="3910267023907260648">You attempted to reach <ph name="DOMAIN" />, but the server presented a certificate signed using a weak signature algorithm. This means that the security credentials that the server presented could have been forged, and the server may not be the server you expected (you may be communicating with an attacker). <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{This server could not prove that it is <ph name="DOMAIN" />; its security certificate is supposedly from tomorrow. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.}other{This server could not prove that it is <ph name="DOMAIN" />; its security certificate is supposedly from # days in the future. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Failed to load PDF document</translation>
<translation id="3963721102035795474">Reader Mode</translation>
+<translation id="397105322502079400">Calculating...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> is blocked</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 web page nearby}other{# web pages nearby}}</translation>
<translation id="4021036232240155012">DNS is the network service that translates a website’s name to its Internet address.</translation>
<translation id="4030383055268325496">&amp;Undo add</translation>
-<translation id="4032534284272647190">Access to <ph name="URL" /> denied.</translation>
<translation id="404928562651467259">WARNING</translation>
<translation id="4058922952496707368">Key "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">The client and server don't support a common SSL protocol version or cipher suite.</translation>
<translation id="4079302484614802869">Proxy configuration is set to use a .pac script URL, not fixed proxy servers.</translation>
<translation id="4103249731201008433">Device serial number is invalid</translation>
<translation id="4103763322291513355">Visit &lt;strong&gt;chrome://policy&lt;/strong&gt; to see the list of blacklisted URLs and other policies enforced by your system administrator.</translation>
+<translation id="4110615724604346410">This server could not prove that it is <ph name="DOMAIN" />; its security certificate contains errors. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Policy scope is not supported.</translation>
+<translation id="4118212371799607889">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by Chromium. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 other}other{# others}}</translation>
<translation id="4130226655945681476">Checking the network cables, modem and router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Do you want Chromium to save this card?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Disabled</translation>
<translation id="4196861286325780578">&amp;Redo move</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Checking firewall and antivirus configurations<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{none}=1{1 app ($1)}=2{2 apps ($1, $2)}other{# apps ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Crashes</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Try running Network Diagnostics<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">No</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(No username)</translation>
<translation id="4300246636397505754">Parent suggestions</translation>
<translation id="4304224509867189079">Log In</translation>
+<translation id="432290197980158659">The server presented a certificate that doesn't match built-in expectations. These expectations are included for certain, high-security websites in order to protect you. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Failed to find article</translation>
+<translation id="4331708818696583467">Not Secure</translation>
<translation id="4372948949327679948">Expected <ph name="VALUE_TYPE" /> value.</translation>
-<translation id="4377125064752653719">You attempted to reach <ph name="DOMAIN" />, but the certificate that the server presented has been revoked by its issuer. This means that the security credentials the server presented absolutely should not be trusted. You may be communicating with an attacker.</translation>
<translation id="4381091992796011497">User Name:</translation>
<translation id="4394049700291259645">Disable</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> to <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">search results</translation>
-<translation id="4424024547088906515">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by Chrome. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> didn’t accept your login certificate, or one may not have been provided.</translation>
<translation id="443673843213245140">Use of a proxy is disabled but an explicit proxy configuration is specified.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">You're seeing this message because Google SafeSites is enabled.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Details</translation>
<translation id="4558551763791394412">Try disabling your extensions.</translation>
<translation id="4587425331216688090">Remove address from Chrome?</translation>
+<translation id="4589078953350245614">You attempted to reach <ph name="DOMAIN" />, but the server presented an invalid certificate. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Your connection to <ph name="DOMAIN" /> is encrypted using a modern cipher suite.</translation>
<translation id="4594403342090139922">&amp;Undo Delete</translation>
+<translation id="4627442949885028695">Continue from another device</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">You are viewing an extension page.</translation>
-<translation id="467662567472608290">This server could not prove that it is <ph name="DOMAIN" />; its security certificate contains errors. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> was blocked</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Your connection was interrupted</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Running Windows Network Diagnostics<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Platform</translation>
<translation id="4744603770635761495">Executable Path</translation>
<translation id="4756388243121344051">&amp;History</translation>
+<translation id="4759238208242260848">Downloads</translation>
<translation id="4764776831041365478">The web page at <ph name="URL" /> might be temporarily down or it may have moved permanently to a new web address.</translation>
<translation id="4771973620359291008">An unknown error has occurred.</translation>
<translation id="4782449893814226250">You asked your parents if it's OK to visit this page.</translation>
<translation id="4800132727771399293">Check your expiration date and CVC and try again</translation>
-<translation id="4807049035289105102">You cannot visit <ph name="SITE" /> at the moment because the website sent scrambled credentials that Google Chrome cannot process. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
<translation id="4813512666221746211">Network error</translation>
<translation id="4816492930507672669">Fit to page</translation>
<translation id="4850886885716139402">View</translation>
<translation id="4880827082731008257">Search history</translation>
+<translation id="4884656795097055129">More articles will appear when the time is right.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{and 1 more web page}other{and # more web pages}}</translation>
<translation id="4923417429809017348">This page has been translated from an unknown language into <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Must be specified.</translation>
<translation id="4930497775425430760">You're seeing this message because your parent needs to approve new sites on your first visit.</translation>
<translation id="495170559598752135">Actions</translation>
<translation id="4958444002117714549">Expand list</translation>
+<translation id="4962322354953122629">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by Chrome. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Translate from <ph name="ORIGINAL_LANGUAGE" /> to <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">This plug-in is not supported</translation>
<translation id="5002932099480077015">If enabled, Chrome will store a copy of your card on this device for faster form filling.</translation>
<translation id="5019198164206649151">Backing store in bad state</translation>
<translation id="5023310440958281426">Check your administrator's policies</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">About Google Translate</translation>
<translation id="5040262127954254034">Privacy</translation>
<translation id="5045550434625856497">Incorrect password</translation>
+<translation id="5056549851600133418">Articles for you</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Checking the proxy address<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Server's certificate is not valid at this time.</translation>
<translation id="5089810972385038852">County</translation>
-<translation id="5094747076828555589">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by Chromium. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="5095208057601539847">Province</translation>
<translation id="5115563688576182185">(64-bit)</translation>
-<translation id="5122371513570456792">Found <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for '<ph name="SEARCH_STRING" />'.</translation>
<translation id="5141240743006678641">Encrypt synced passwords with your Google credentials</translation>
<translation id="5145883236150621069">Error code present in the policy response</translation>
<translation id="5171045022955879922">Search or type URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Bookmarks Bar</translation>
<translation id="5199729219167945352">Experiments</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">Using Chrome at work? Businesses can manage Chrome settings for their employees. Find out more</translation>
<translation id="5299298092464848405">Error parsing policy</translation>
<translation id="5300589172476337783">Show</translation>
<translation id="5308689395849655368">Crash reporting is disabled.</translation>
<translation id="5317780077021120954">Save</translation>
<translation id="5327248766486351172">Name</translation>
+<translation id="5359637492792381994">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not valid at this time. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Failed to store policy settings</translation>
-<translation id="540969355065856584">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not valid at this time. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="5421136146218899937">Clear browsing data...</translation>
<translation id="5430298929874300616">Remove bookmark</translation>
<translation id="5431657950005405462">Your file was not found</translation>
<translation id="5435775191620395718">Showing history from this device. <ph name="BEGIN_LINK" />Find out more<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Personalised content suggestions are currently disabled, because your synced data is protected with a customised passphrase.</translation>
<translation id="5439770059721715174">Schema validation error at "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">This <ph name="HOST_NAME" /> page can’t be found</translation>
<translation id="5455374756549232013">Bad policy timestamp</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Do you want to leave this site?</translation>
<translation id="5629630648637658800">Failed to load policy settings</translation>
<translation id="5631439013527180824">Invalid device management token</translation>
-<translation id="5650551054760837876">No search results found.</translation>
<translation id="5677928146339483299">Blocked</translation>
<translation id="5710435578057952990">The identity of this website has not been verified.</translation>
<translation id="5720705177508910913">Current user</translation>
+<translation id="572328651809341494">Recent tabs</translation>
<translation id="5784606427469807560">There was a problem confirming your card. Check your Internet connection and try again.</translation>
<translation id="5785756445106461925">Further, this page includes other resources which are not secure. These resources can be viewed by others while in transit, and can be modified by an attacker to change the look of the page.</translation>
+<translation id="5786044859038896871">Do you want to fill in your card info?</translation>
+<translation id="5803412860119678065">Do you want to fill in your <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Your connection to <ph name="DOMAIN" /> is encrypted using an obsolete cipher suite.</translation>
<translation id="5813119285467412249">&amp;Redo Add</translation>
+<translation id="5814352347845180253">You may lose access to premium content from <ph name="SITE" /> and some other sites.</translation>
+<translation id="5843436854350372569">You attempted to reach <ph name="DOMAIN" />, but the server presented a certificate containing a weak key. An attacker could have broken the private key, and the server may not be the server you expected (you may be communicating with an attacker). <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">You're seeing this message because your manager blocked this site.</translation>
<translation id="5857090052475505287">New Folder</translation>
<translation id="5869405914158311789">This site can’t be reached</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Parent Suggestions</translation>
<translation id="59107663811261420">This type of card is not supported by Google Payments for this merchant. Please select a different card.</translation>
<translation id="59174027418879706">Enabled</translation>
+<translation id="5926846154125914413">You may lose access to premium content from some sites.</translation>
<translation id="5966707198760109579">Week</translation>
<translation id="5967867314010545767">Remove from history</translation>
<translation id="5975083100439434680">Zoom out</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Automatic</translation>
<translation id="6042308850641462728">More</translation>
<translation id="6060685159320643512">Careful, these experiments may bite</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{none}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Check any cables and reboot any routers, modems or other network
devices you may be using.</translation>
<translation id="614940544461990577">Try:</translation>
<translation id="6150607114729249911">Oops! You need to ask your parents if it's OK to visit this page.</translation>
<translation id="6151417162996330722">The server certificate has a validity period that is too long.</translation>
-<translation id="6154808779448689242">Returned policy token doesn't match current token</translation>
<translation id="6165508094623778733">Learn more</translation>
<translation id="6203231073485539293">Check your Internet connection</translation>
<translation id="6218753634732582820">Remove address from Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Try disabling network prediction</translation>
<translation id="6337534724793800597">Filter policies by name</translation>
<translation id="6342069812937806050">Just now</translation>
+<translation id="6345221851280129312">unknown size</translation>
<translation id="6355080345576803305">Public session override</translation>
<translation id="6358450015545214790">What do these mean?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 other suggestion}other{# other suggestions}}</translation>
<translation id="6387478394221739770">Interested in cool new Chrome features? Try our beta channel at chrome.com/beta.</translation>
-<translation id="641480858134062906"><ph name="URL" /> failed to load</translation>
+<translation id="6389758589412724634">Chromium ran out of memory while trying to display this web page.</translation>
+<translation id="6416403317709441254">You cannot visit <ph name="SITE" /> at the moment because the website sent scrambled credentials that Chromium cannot process. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Unable to check whether the certificate has been revoked.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> refused to connect.</translation>
<translation id="6445051938772793705">Country</translation>
<translation id="6451458296329894277">Confirm Form Resubmission</translation>
<translation id="6458467102616083041">Ignored because default search is disabled by policy.</translation>
+<translation id="6462969404041126431">This server could not prove that it is <ph name="DOMAIN" />; its security certificate might be revoked. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Device policies</translation>
<translation id="6489534406876378309">Start uploading crashes</translation>
<translation id="6529602333819889595">&amp;Redo Delete</translation>
+<translation id="6534179046333460208">Physical Web suggestions</translation>
<translation id="6550675742724504774">Options</translation>
+<translation id="6593753688552673085">less than <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Encryption options</translation>
<translation id="662080504995468778">Stay</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Search</translation>
-<translation id="6634865548447745291">You cannot visit <ph name="SITE" /> at the moment because <ph name="BEGIN_LINK" />this certificate has been revoked<ph name="END_LINK" />. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
<translation id="6644283850729428850">This policy has been deprecated.</translation>
+<translation id="6652240803263749613">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by your computer's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Edit Folder</translation>
<translation id="6660210980321319655">Automatically reported <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Remove form suggestion from Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Previous</translation>
<translation id="6710594484020273272">&lt;Type search term&gt;</translation>
<translation id="6711464428925977395">There is something wrong with the proxy server or the address is incorrect.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{none}=1{1 item}other{# items}}</translation>
<translation id="674375294223700098">Unknown server certificate error.</translation>
<translation id="6753269504797312559">Policy Value</translation>
<translation id="6757797048963528358">Your device went to sleep.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Policy level is not supported.</translation>
<translation id="6895330447102777224">Your card is confirmed</translation>
<translation id="6897140037006041989">User Agent</translation>
-<translation id="6903907808598579934">Turn on sync</translation>
<translation id="6915804003454593391">User:</translation>
<translation id="6957887021205513506">The server's certificate appears to be a forgery.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">District</translation>
<translation id="6973656660372572881">Both fixed proxy servers and a .pac script URL are specified.</translation>
<translation id="6989763994942163495">+ Show advanced settings</translation>
+<translation id="7000990526846637657">No history entries found</translation>
+<translation id="7009986207543992532">You attempted to reach <ph name="DOMAIN" />, but the server presented a certificate whose validity period is too long to be trustworthy. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Your Google account may have other forms of browsing history at <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Passwords</translation>
-<translation id="7050187094878475250">You attempted to reach <ph name="DOMAIN" />, but the server presented a certificate whose validity period is too long to be trustworthy.</translation>
<translation id="7087282848513945231">County</translation>
<translation id="7088615885725309056">Older</translation>
<translation id="7090678807593890770">Search Google for <ph name="LINK" /></translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">You're seeing this message because your manager needs to approve new sites on your first visit.</translation>
<translation id="724975217298816891">Enter the expiry date and CVC for <ph name="CREDIT_CARD" /> to update your card details. Once you've confirmed, your card details will be shared with this site.</translation>
<translation id="725866823122871198">A private connection to <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> can't be established because your computer's date and time (<ph name="DATE_AND_TIME" />) are incorrect.</translation>
-<translation id="7265986070661382626">You cannot visit <ph name="SITE" /> at the moment because the website <ph name="BEGIN_LINK" />uses certificate pinning<ph name="END_LINK" />. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
<translation id="7269802741830436641">This web page has a redirect loop</translation>
<translation id="7275334191706090484">Managed Bookmarks</translation>
<translation id="7298195798382681320">Recommended</translation>
-<translation id="7301833672208172928">Turn on history sync</translation>
+<translation id="7309308571273880165">Crash report captured on <ph name="CRASH_TIME" /> (upload requested by user, not yet uploaded)</translation>
<translation id="7334320624316649418">&amp;Redo reorder</translation>
<translation id="733923710415886693">The server's certificate was not disclosed via Certificate Transparency.</translation>
+<translation id="7351800657706554155">You cannot visit <ph name="SITE" /> at the moment because its certificate has been revoked. Network errors and attacks are usually temporary, so this page will probably work later. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Command Line</translation>
<translation id="7372973238305370288">search result</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="7469372306589899959">Confirming card</translation>
<translation id="7481312909269577407">Forward</translation>
<translation id="7485870689360869515">No data found.</translation>
+<translation id="7508255263130623398">Returned policy device ID is empty or doesn't match current device ID</translation>
<translation id="7514365320538308">Download</translation>
<translation id="7518003948725431193">No web page was found for the web address: <ph name="URL" /></translation>
<translation id="7537536606612762813">Mandatory</translation>
<translation id="7542995811387359312">Automatic credit card filling is disabled because this form does not use a secure connection.</translation>
<translation id="7549584377607005141">This web page requires data that you entered earlier in order to be properly displayed. You can send this data again, but by doing so you will repeat any action this page previously performed.</translation>
<translation id="7554791636758816595">New Tab</translation>
-<translation id="7567204685887185387">This server could not prove that it is <ph name="DOMAIN" />; its security certificate might have been issued fraudulently. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="7568593326407688803">This page is in<ph name="ORIGINAL_LANGUAGE" />Would you like to translate it?</translation>
<translation id="7569952961197462199">Remove credit card from Chrome?</translation>
<translation id="7578104083680115302">Pay quickly on sites and apps across devices using cards that you have saved with Google.</translation>
+<translation id="7588950540487816470">Physical web</translation>
<translation id="7592362899630581445">Server's certificate violates name constraints.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> is currently unable to handle this request.</translation>
<translation id="7600965453749440009">Never translate <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="7637571805876720304">Remove credit card from Chromium?</translation>
<translation id="765676359832457558">Hide advanced settings ...</translation>
<translation id="7658239707568436148">Cancel</translation>
+<translation id="7667346355482952095">Returned policy token is empty or doesn't match current token</translation>
<translation id="7668654391829183341">Unknown device</translation>
<translation id="7674629440242451245">Interested in cool new Chrome features? Try our dev channel at chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Proceed to <ph name="SITE" /> (unsafe)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="780301667611848630">No, thank you</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7813600968533626083">Remove form suggestion from Chrome?</translation>
+<translation id="7815407501681723534">Found <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for '<ph name="SEARCH_STRING" />'</translation>
<translation id="785549533363645510">However, you aren’t invisible. Going incognito doesn’t hide your browsing from your employer, your Internet service provider or the websites that you visit.</translation>
<translation id="7887683347370398519">Check your CVC and try again</translation>
<translation id="7894616681410591072">Oops! You need permission from <ph name="NAME" /> to access this page.</translation>
-<translation id="790025292736025802"><ph name="URL" /> is not found</translation>
<translation id="7912024687060120840">In Folder:</translation>
<translation id="7920092496846849526">You asked your parent if it's OK to visit this page.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="7995512525968007366">Not Specified</translation>
<translation id="8012647001091218357">We could not reach your parents at the moment. Please try again.</translation>
<translation id="8034522405403831421">This page is in <ph name="SOURCE_LANGUAGE" />. Translate it to <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">No history entries found.</translation>
<translation id="8088680233425245692">Failed to view article.</translation>
+<translation id="8089520772729574115">less than 1 MB</translation>
<translation id="8091372947890762290">Activation is pending on the server</translation>
+<translation id="8129262335948759431">unknown amount</translation>
<translation id="8131740175452115882">Confirm</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />’s server <ph name="BEGIN_ABBR" />DNS address<ph name="END_ABBR" /> could not be found.</translation>
<translation id="8149426793427495338">Your computer went to sleep.</translation>
@@ -604,6 +640,7 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="8201077131113104583">Invalid update URL for extension with ID "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Assigned Location:</translation>
<translation id="8225771182978767009">The person who set up this computer has chosen to block this site.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">The page that you're looking for used information that you entered. Returning to that page might cause any action that you took to be repeated. Do you want to continue?</translation>
<translation id="8249320324621329438">Last fetched:</translation>
<translation id="8261506727792406068">Delete</translation>
@@ -616,12 +653,17 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="8349305172487531364">Bookmarks bar</translation>
<translation id="8363502534493474904">Turning off aeroplane mode</translation>
<translation id="8364627913115013041">Not set.</translation>
+<translation id="8380941800586852976">Dangerous</translation>
<translation id="8412145213513410671">Crashes (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">You must enter the same passphrase twice.</translation>
<translation id="8428213095426709021">Settings</translation>
+<translation id="8433057134996913067">This will sign you out of most websites.</translation>
<translation id="8437238597147034694">&amp;Undo move</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 credit card}other{# credit cards}}</translation>
+<translation id="8483780878231876732">To use cards from your Google account, sign in to Chrome</translation>
<translation id="8488350697529856933">Applies to</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> took too long to respond.</translation>
+<translation id="852346902619691059">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by your device's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection. <ph name="BEGIN_LEARN_MORE_LINK" />Find out more<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">This type of card is not supported by Google Payments. Please select a different card.</translation>
<translation id="8550022383519221471">Sync service is not available for your domain.</translation>
<translation id="8553075262323480129">The translation failed because the page's language could not be determined.</translation>
@@ -633,15 +675,12 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="8647750283161643317">Reset all to default</translation>
<translation id="8680787084697685621">Account sign-in details are out of date.</translation>
<translation id="8703575177326907206">Your connection to <ph name="DOMAIN" /> is not encrypted.</translation>
-<translation id="8713130696108419660">Bad intial signature</translation>
<translation id="8725066075913043281">Try again</translation>
<translation id="8728672262656704056">You’ve gone incognito</translation>
<translation id="8730621377337864115">Finished</translation>
<translation id="8738058698779197622">To establish a secure connection, your clock needs to be set correctly. This is because the certificates that websites use to identify themselves are only valid for specific periods of time. Since your device's clock is incorrect, Chromium cannot verify these certificates.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />’s &lt;abbr id="dnsDefinition"&gt;DNS address&lt;/abbr&gt; could not be found. Diagnosing the problem.</translation>
-<translation id="8741995161408053644">Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Redo delete</translation>
-<translation id="8790687370365610530">To get personalised content suggested by Google, turn on history sync.</translation>
<translation id="8798099450830957504">Default</translation>
<translation id="8804164990146287819">Privacy Policy</translation>
<translation id="8820817407110198400">Bookmarks</translation>
@@ -663,13 +702,11 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY" /> may come in handy next time.</tr
<translation id="8971063699422889582">Server's certificate has expired.</translation>
<translation id="8987927404178983737">Month</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">The server presented a certificate that was not publicly disclosed using the Certificate Transparency policy. This is a requirement for some certificates, to ensure that they are trustworthy and protect against attackers.</translation>
<translation id="9001074447101275817">The proxy <ph name="DOMAIN" /> requires a username and password.</translation>
<translation id="901974403500617787">Flags that apply system-wide can only be set by the owner: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">This page has been translated to <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Use a prediction service to load pages more quickly</translation>
<translation id="9039213469156557790">Furthermore, this page includes other resources which are not secure. These resources can be viewed by others while in transit, and can be modified by an attacker to change the behaviour of the page.</translation>
-<translation id="9049981332609050619">You attempted to reach <ph name="DOMAIN" />, but the server presented an invalid certificate.</translation>
<translation id="9050666287014529139">Passphrase</translation>
<translation id="9065203028668620118">Edit</translation>
<translation id="9092364396508701805">The <ph name="HOST_NAME" /> page isn’t working</translation>
diff --git a/chromium/components/strings/components_strings_es-419.xtb b/chromium/components/strings/components_strings_es-419.xtb
index be8d5d0b25d..950c5a0004e 100644
--- a/chromium/components/strings/components_strings_es-419.xtb
+++ b/chromium/components/strings/components_strings_es-419.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="es-419">
+<translation id="1008557486741366299">Ahora no</translation>
<translation id="1015730422737071372">Proporciona mĂ¡s detalles</translation>
<translation id="1032854598605920125">Girar a la derecha</translation>
<translation id="1038842779957582377">nombre desconocido</translation>
+<translation id="1053591932240354961">No puedes visitar <ph name="SITE" /> ahora mismo porque el sitio web enviĂ³ credenciales confusas que Google Chrome no puede procesar. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta pĂ¡gina funcione mĂ¡s tarde. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">&amp;Deshacer Agregar</translation>
<translation id="10614374240317010">Nunca guardado</translation>
-<translation id="1064422015032085147">El servidor que aloja la pĂ¡gina web podrĂ­a estar sobrecargado o en mantenimiento.
- Para evitar que se genere demasiado trĂ¡fico y empeore la situaciĂ³n,
- se inhabilitaron temporalmente las solicitudes a esta URL.</translation>
<translation id="106701514854093668">Marcadores de escritorio</translation>
<translation id="1080116354587839789">Ajustar al ancho</translation>
+<translation id="1103124106085518534">Listo por ahora</translation>
<translation id="1103523840287552314">Siempre traducir <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Si marcas esta opciĂ³n, Chrome almacenarĂ¡ una copia de la tarjeta en el dispositivo para completar mĂ¡s rĂ¡pidamente los formularios.</translation>
+<translation id="1111153019813902504">Marcadores recientes</translation>
<translation id="1113869188872983271">&amp;Deshacer Reorganizar</translation>
+<translation id="1126551341858583091">El tamaño del almacenamiento local es <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Caché de política correcta</translation>
<translation id="113188000913989374"><ph name="SITE" /> dice:</translation>
<translation id="1132774398110320017">ConfiguraciĂ³n de la funciĂ³n Autocompletar de Chrome…</translation>
-<translation id="1150979032973867961">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el sistema operativo de la computadora no confĂ­a en el certificado de seguridad. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante interceptĂ³ la conexiĂ³n.</translation>
<translation id="1152921474424827756">Accede a una <ph name="BEGIN_LINK" />copia almacenada en caché<ph name="END_LINK" /> de <ph name="URL" />.</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> cerrĂ³ la conexiĂ³n de forma inesperada.</translation>
<translation id="1161325031994447685">Volver a conectarte a Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Eliminar</translation>
<translation id="1201402288615127009">Siguiente</translation>
<translation id="1201895884277373915">MĂ¡s sobre este sitio</translation>
-<translation id="121201262018556460">Intentaste acceder a <ph name="DOMAIN" />, pero el servidor presentĂ³ un certificado que contiene una clave no segura. Es posible que un atacante haya descifrado la clave privada y que este no sea el servidor esperado (es posible que hayas establecido comunicaciĂ³n con un atacante).</translation>
+<translation id="1206967143813997005">La firma inicial no es vĂ¡lida</translation>
+<translation id="1209206284964581585">Ocultar por el momento</translation>
<translation id="1219129156119358924">Seguridad del sistema</translation>
<translation id="1227224963052638717">PolĂ­tica desconocida</translation>
<translation id="1227633850867390598">Ocultar valor</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">SĂ­</translation>
<translation id="1430915738399379752">Imprimir</translation>
<translation id="1442912890475371290">Se bloqueĂ³ un intento de <ph name="BEGIN_LINK" />acceso a una pĂ¡gina en <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">No puedes visitar <ph name="SITE" /> ahora mismo porque el sitio web usa la fijaciĂ³n de certificados. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta pĂ¡gina funcione mĂ¡s tarde. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">Se muestra una copia guardada (es decir, desactualizada) de la pĂ¡gina.</translation>
<translation id="1519264250979466059">Fecha de compilaciĂ³n</translation>
<translation id="1549470594296187301">JavaScript debe estar habilitado para usar esta funciĂ³n.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">La configuraciĂ³n de red no es vĂ¡lida y no se pudo importar.</translation>
<translation id="1644574205037202324">Historial</translation>
<translation id="1645368109819982629">Protocolo no compatible</translation>
-<translation id="1655462015569774233">{1,plural, =1{El servidor no logrĂ³ comprobar si el dominio es <ph name="DOMAIN" />; el certificado de seguridad venciĂ³ ayer. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n. Actualmente, el reloj de la computadora estĂ¡ configurado en la siguiente fecha: <ph name="CURRENT_DATE" />. ¿Es correcto? De no ser asĂ­, corrige el reloj del sistema y, a continuaciĂ³n, actualiza la pĂ¡gina.}other{El servidor no logrĂ³ comprobar si el dominio es <ph name="DOMAIN" />; el certificado de seguridad venciĂ³ hace # dĂ­as. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n. Actualmente, el reloj de la computadora estĂ¡ configurado en la siguiente fecha: <ph name="CURRENT_DATE" />. ¿Es correcto? De no ser asĂ­, corrige el reloj del sistema y, a continuaciĂ³n, actualiza la pĂ¡gina.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> suele utilizar la encriptaciĂ³n para proteger la informaciĂ³n. Cuando Google Chrome intentĂ³ conectarse a <ph name="SITE" />, el sitio web devolviĂ³ credenciales incorrectas y poco comunes. Es posible que un atacante quiera suplantar a <ph name="SITE" /> o que una pantalla de acceso Wi-Fi haya interrumpido la conexiĂ³n. Tu informaciĂ³n permanece segura porque Google Chrome detuvo la conexiĂ³n para evitar el intercambio de datos.</translation>
<translation id="168841957122794586">El certificado del servidor contiene una clave criptogrĂ¡fica no segura.</translation>
<translation id="1701955595840307032">Obtener contenido sugerido</translation>
-<translation id="1706954506755087368">{1,plural, =1{El servidor no logrĂ³ comprobar si el dominio es <ph name="DOMAIN" />; supuestamente, el certificado de seguridad entra en vigencia mañana. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.}other{El servidor no logrĂ³ comprobar si el dominio es <ph name="DOMAIN" />; supuestamente, el certificado de seguridad entra en vigencia en # dĂ­as. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.}}</translation>
<translation id="1710259589646384581">SO</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Intenta comunicarte con el administrador del sistema.</translation>
<translation id="17513872634828108">Pestañas abiertas</translation>
<translation id="1753706481035618306">NĂºmero de pĂ¡gina</translation>
-<translation id="1761412452051366565">Para obtener contenido personalizado y sugerido por Google, activa la sincronizaciĂ³n.</translation>
-<translation id="1763864636252898013">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el sistema operativo del dispositivo no confĂ­a en el certificado de seguridad. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante interceptĂ³ la conexiĂ³n.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Intenta ejecutar el DiagnĂ³stico de red de Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Actualiza tu frase de contraseña de sincronizaciĂ³n.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Los marcadores que visitaste recientemente aparecerĂ¡n aquĂ­.</translation>
<translation id="1821930232296380041">Solicitud o parĂ¡metros de solicitud no vĂ¡lidos</translation>
<translation id="1838667051080421715">EstĂ¡s viendo la fuente de una pĂ¡gina web.</translation>
<translation id="1871208020102129563">El proxy estĂ¡ configurado para usar servidores proxy fijos, no una URL de script .pac.</translation>
<translation id="1883255238294161206">Ocultar lista</translation>
<translation id="1898423065542865115">Filtrado</translation>
-<translation id="1911837502049945214">O bien <ph name="HOST_NAME" /> no aceptĂ³ tu certificado de acceso, o es posible que tu certificado de acceso haya expirado.</translation>
<translation id="194030505837763158">Ir a <ph name="LINK" /></translation>
<translation id="1962204205936693436">Marcadores de <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Error de serializaciĂ³n</translation>
<translation id="1974060860693918893">Avanzada</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{y 1 mĂ¡s}other{y # mĂ¡s}}</translation>
<translation id="2025186561304664664">El proxy se estableciĂ³ en configuraciĂ³n automĂ¡tica.</translation>
<translation id="2030481566774242610">¿Quisiste decir: <ph name="LINK" />?</translation>
<translation id="2031925387125903299">EstĂ¡s viendo este mensaje porque tus padres deben aprobar nuevos sitios en tu primera visita.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Comprobar el proxy y el firewall<ph name="END_LINK" />.</translation>
<translation id="2053553514270667976">CĂ³digo Postal</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 sugerencia}other{# sugerencias}}</translation>
<translation id="2065985942032347596">Se requiere autenticaciĂ³n</translation>
<translation id="2079545284768500474">Deshacer</translation>
<translation id="20817612488360358">Se ha establecido la configuraciĂ³n de proxy del sistema, pero tambiĂ©n se ha especificado una configuraciĂ³n explĂ­cita de proxy.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Editar marcador</translation>
<translation id="2166049586286450108">Acceso de administrador completo</translation>
<translation id="2166378884831602661">Este sitio no puede proporcionar una conexiĂ³n segura</translation>
-<translation id="2171101176734966184">Intentaste acceder a <ph name="DOMAIN" />, pero el servidor presentĂ³ un certificado firmado con un algoritmo de firma no seguro. Es posible que se hayan falsificado las credenciales de seguridad presentadas por el servidor y que este no sea el servidor esperado (es posible que hayas establecido comunicaciĂ³n con un atacante).</translation>
<translation id="2181821976797666341">PolĂ­ticas</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 direcciĂ³n}other{# direcciones}}</translation>
<translation id="2212735316055980242">No se encontrĂ³ la polĂ­tica.</translation>
<translation id="2213606439339815911">Recuperando entradas…</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> no estĂ¡ disponible.</translation>
<translation id="2230458221926704099">Corregir la conexiĂ³n con la <ph name="BEGIN_LINK" />app de diagnĂ³stico<ph name="END_LINK" />.</translation>
+<translation id="2239100178324503013">Enviar ahora</translation>
<translation id="225207911366869382">Este valor ya no se utiliza para esta polĂ­tica.</translation>
<translation id="2262243747453050782">Error de HTTP</translation>
<translation id="2282872951544483773">Experimentos no disponibles</translation>
<translation id="2292556288342944218">Se bloqueĂ³ tu acceso a Internet</translation>
<translation id="229702904922032456">Un certificado raĂ­z o intermedio venciĂ³.</translation>
<translation id="230155334948463882">¿Una tarjeta nueva?</translation>
+<translation id="2305919008529760154">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad podrĂ­a haberse emitido de forma fraudulenta. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> requiere un nombre de usuario y una contraseña.</translation>
+<translation id="2318774815570432836">No puedes visitar <ph name="SITE" /> ahora mismo porque el sitio web usa HSTS. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta pĂ¡gina funcione mĂ¡s tarde. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">Marcador no vĂ¡lido ignorado en el Ă­ndice <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Otros marcadores</translation>
<translation id="2359808026110333948">Continuar</translation>
<translation id="2365563543831475020">El informe de fallos que se capturĂ³ a las <ph name="CRASH_TIME" /> no se cargĂ³</translation>
<translation id="2367567093518048410">Nivel</translation>
+<translation id="2371153335857947666">{1,plural, =1{Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; su certificado de seguridad caducĂ³ ayer. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. El reloj de la computadora actualmente estĂ¡ configurado en la siguiente fecha: <ph name="CURRENT_DATE" />. ¿Es correcto? De no ser asĂ­, corrige el reloj del sistema y, luego, actualiza esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" />}other{Este servidor no pudo comprobar si el dominio es <ph name="DOMAIN" />; su certificado de seguridad caducĂ³ hace # dĂ­as. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. El reloj de la computadora actualmente estĂ¡ configurado en la siguiente fecha: <ph name="CURRENT_DATE" />. ¿Es correcto? De no ser asĂ­, corrige el reloj del sistema y, luego, actualiza esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">No hay alternativas de interfaz de usuario disponibles.</translation>
<translation id="2384307209577226199">Empresa (predeterminada)</translation>
-<translation id="238526402387145295">No puedes visitar <ph name="SITE" /> ahora porque el sitio web <ph name="BEGIN_LINK" />utiliza HSTS<ph name="END_LINK" />. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta pĂ¡gina funcione mĂ¡s tarde.</translation>
<translation id="2386255080630008482">Se ha revocado el certificado del servidor.</translation>
<translation id="2392959068659972793">Mostrar polĂ­ticas sin valor establecido</translation>
<translation id="2396249848217231973">&amp;Deshacer Eliminar</translation>
-<translation id="2413528052993050574">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" /> y se podrĂ­a revocar el certificado de seguridad. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante interceptĂ³ la conexiĂ³n.</translation>
<translation id="2455981314101692989">Esta pĂ¡gina web ha inhabilitado la funciĂ³n de rellenado automĂ¡tico para este formulario.</translation>
+<translation id="2463739503403862330">Llenar</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />EjecuciĂ³n del DiagnĂ³stico de red<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL de bĂºsqueda no vĂ¡lida</translation>
<translation id="2491120439723279231">El certificado del servidor contiene errores.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Enviar</translation>
<translation id="2674170444375937751">¿EstĂ¡s seguro de que deseas eliminar estas pĂ¡ginas del historial?</translation>
<translation id="2677748264148917807">Abandonar</translation>
+<translation id="269990154133806163">El servidor presentĂ³ un certificado que no se divulgĂ³ de forma pĂºblica con la polĂ­tica Certificado de transparencia. Este es un requisito para algunos certificados que permite garantizar su confiabilidad y protegerte de atacantes. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">El valor no coincide con el formato.</translation>
<translation id="2704951214193499422">Chrome no pudo confirmar tu tarjeta. Vuelve a intentarlo mĂ¡s tarde.</translation>
<translation id="2705137772291741111">La copia guardada (en caché) de este sitio es ilegible.</translation>
<translation id="2709516037105925701">Autocompletar</translation>
+<translation id="2712118517637785082">Intentaste acceder a <ph name="DOMAIN" />, pero el emisor anulĂ³ el certificado que presentĂ³ el servidor. Esto significa que no se debe confiar en absoluto en las credenciales de seguridad que presentĂ³ el servidor; es posible que te comuniques con un atacante. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">Solicitar permiso</translation>
<translation id="2721148159707890343">Solicitud correcta</translation>
<translation id="2728127805433021124">El certificado del servidor estĂ¡ firmado con un algoritmo de firma no seguro.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Barra de direcciones y de bĂºsqueda</translation>
<translation id="2826760142808435982">La conexiĂ³n se encriptĂ³ y autenticĂ³ con <ph name="CIPHER" />, y utiliza <ph name="KX" /> como el mecanismo de intercambio de claves.</translation>
<translation id="2835170189407361413">Eliminar formulario</translation>
-<translation id="2837049386027881519">Se intentĂ³ establecer la conexiĂ³n nuevamente utilizando una versiĂ³n anterior del protocolo SSL o TLS. Esto normalmente significa que el servidor estĂ¡ utilizando software muy antiguo y puede tener otros problemas de seguridad.</translation>
<translation id="284702764277384724">El certificado del servidor en <ph name="HOST_NAME" /> parece falso.</translation>
<translation id="2889159643044928134">No volver a cargar</translation>
-<translation id="2896499918916051536">El complemento no es compatible.</translation>
+<translation id="2900469785430194048">Google Chrome se quedĂ³ sin memoria cuando intentaba mostrar esta pĂ¡gina web.</translation>
<translation id="2909946352844186028">Se detectĂ³ un cambio de red.</translation>
-<translation id="2915500479781995473">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad venciĂ³. Es posible que esto se deba a una configuraciĂ³n incorrecta o a un atacante que interceptĂ³ la conexiĂ³n. La hora actual del reloj de la computadora es <ph name="CURRENT_TIME" />. ¿Es correcta? De lo contrario, corrige la hora del sistema y actualiza la pĂ¡gina.</translation>
<translation id="2922350208395188000">No se puede comprobar el certificado del servidor.</translation>
-<translation id="2941952326391522266">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad proviene de <ph name="DOMAIN2" />. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante interceptĂ³ la conexiĂ³n.</translation>
<translation id="2948083400971632585">Puedes inhabilitar los servidores proxy configurados para una conexiĂ³n desde la pĂ¡gina de configuraciĂ³n.</translation>
<translation id="2955913368246107853">Cerrar la barra de bĂºsqueda</translation>
<translation id="2958431318199492670">La configuraciĂ³n de red no cumple con el estĂ¡ndar ONC. Es posible que no se importen algunas partes de la configuraciĂ³n.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Tipo de polĂ­tica incorrecto</translation>
<translation id="3032412215588512954">¿Deseas volver a cargar este sitio?</translation>
<translation id="3037605927509011580">¡Oh, no!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{al menos 1 elemento en dispositivos sincronizados}=1{1 elemento (y mĂ¡s en dispositivos sincronizados)}other{# elementos (y mĂ¡s en dispositivos sincronizados)}}</translation>
<translation id="3041612393474885105">InformaciĂ³n sobre el certificado</translation>
<translation id="3063697135517575841">Chrome no pudo confirmar tu tarjeta en este momento. Vuelve a intentarlo mĂ¡s tarde.</translation>
<translation id="3093245981617870298">No estĂ¡s conectado.</translation>
@@ -207,15 +210,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">MĂ¡s reciente</translation>
<translation id="3207960819495026254">Agregada a marcadores</translation>
-<translation id="3225919329040284222">El servidor mostrĂ³ un certificado que no coincide con lo esperado. Estas expectativas se incluyen en determinados sitios web con un alto nivel de seguridad para garantizar tu protecciĂ³n.</translation>
<translation id="3226128629678568754">Presiona el botĂ³n para volver a cargar y, de ese modo, enviar nuevamente los datos necesarios para cargar la pĂ¡gina.</translation>
<translation id="3228969707346345236">FallĂ³ la traducciĂ³n debido a que la pĂ¡gina ya se encuentra en <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Ingresar el CVC de la tarjeta <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Agregar esta pĂ¡gina a Marcadores</translation>
<translation id="3270847123878663523">&amp;Deshacer Reorganizar</translation>
<translation id="3286538390144397061">Reiniciar ahora</translation>
+<translation id="3303855915957856445">No se encontraron resultados en la bĂºsqueda</translation>
<translation id="3305707030755673451">Tus datos se encriptaron con tu frase de contraseña para sincronizaciĂ³n el <ph name="TIME" />. Debes ingresarla para iniciar la sincronizaciĂ³n.</translation>
<translation id="333371639341676808">Evita que esta pĂ¡gina cree cuadros de diĂ¡logo adicionales.</translation>
+<translation id="3338095232262050444">Seguro</translation>
<translation id="3340978935015468852">configuraciĂ³n</translation>
<translation id="3345135638360864351">No se pudo enviar la solicitud de acceso al sitio a <ph name="NAME" />. Vuelve a intentarlo.</translation>
<translation id="3355823806454867987">Cambiar la configuraciĂ³n del proxy...</translation>
@@ -233,6 +237,7 @@
<translation id="3452404311384756672">Obtener intervalo:</translation>
<translation id="3462200631372590220">Ocultar detalles avanzados</translation>
<translation id="3479539252931486093">¿OcurriĂ³ algo inesperado? <ph name="BEGIN_LINK" />CuĂ©ntanos<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Ahora no</translation>
<translation id="348000606199325318">ID de fallo <ph name="CRASH_LOCAL_ID" /> (ID de servidor: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">No pudimos comunicarnos con ninguno de tus padres. Vuelve a intentarlo.</translation>
<translation id="3527085408025491307">Carpeta</translation>
@@ -241,6 +246,7 @@
<translation id="3542684924769048008">Utilizar la contraseña para:</translation>
<translation id="3549644494707163724">Encriptar todos los datos sincronizados con tu propia frase de contraseña para sincronizaciĂ³n</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> mĂ¡s...</translation>
+<translation id="3555561725129903880">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad es del dominio <ph name="DOMAIN2" />. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">La conexiĂ³n no es privada</translation>
<translation id="3583757800736429874">&amp;Rehacer Mover</translation>
<translation id="3586931643579894722">Ocultar detalles</translation>
@@ -252,12 +258,15 @@
<translation id="3623476034248543066">Mostrar valor</translation>
<translation id="3630155396527302611">Si ya estĂ¡ incluido como un programa con permiso para acceder a la red, intenta
quitarlo de la lista y agregarlo de nuevo.</translation>
+<translation id="3638794133396384728">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad caducĂ³. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. El reloj de tu computadora estĂ¡ establecido con la siguiente hora: <ph name="CURRENT_TIME" />. ¿Es correcto? De lo contrario, deberĂ¡s corregir el reloj de tu sistema y, luego, actualizar esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">Estas funciones experimentales pueden modificarse, dejar de funcionar o desaparecer en cualquier momento. No ofrecemos ninguna garantĂ­a para lo que pueda ocurrir si activas alguno de estos experimentos, y es posible que tu navegador se bloquee repentinamente. Bromas aparte, ten en cuenta que el navegador puede eliminar todos tus datos y que tu seguridad y tu privacidad se podrĂ­an ver comprometidas de forma inesperada. Cualquier experimento que actives, se activarĂ¡ para todos los usuarios de este navegador, asĂ­ que te recomendamos que actĂºes con precauciĂ³n.</translation>
<translation id="3650584904733503804">ValidaciĂ³n correcta</translation>
<translation id="3655670868607891010">Si este mensaje aparece con frecuencia, haz clic aquí: <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">RevisiĂ³n</translation>
+<translation id="3678029195006412963">La solicitud no se pudo firmar</translation>
<translation id="3681007416295224113">InformaciĂ³n sobre el certificado</translation>
<translation id="3693415264595406141">Contraseña:</translation>
+<translation id="3696411085566228381">ninguno</translation>
<translation id="3700528541715530410">Parece que no tienes permiso para acceder a esta pĂ¡gina.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Cargando...</translation>
@@ -265,7 +274,6 @@
<translation id="3714780639079136834">Activar los datos mĂ³viles o la conexiĂ³n Wi-Fi.</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Comprobar la configuraciĂ³n del proxy, firewall o DNS<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">VĂ­nculo copiado</translation>
-<translation id="3744899669254331632">No puedes visitar <ph name="SITE" /> en este momento porque el sitio web enviĂ³ credenciales encriptadas que Chromium no puede procesar. Los ataques y errores de red generalmente son temporales, por lo que esta pĂ¡gina probablemente funcionarĂ¡ de nuevo mĂ¡s tarde.</translation>
<translation id="375403751935624634">FallĂ³ la traducciĂ³n debido a un error de servidor.</translation>
<translation id="3759461132968374835">No has notificado ningĂºn bloqueo recientemente. Los bloqueos que se hayan producido mientras la funciĂ³n de notificaciĂ³n de bloqueos estaba desactivada no aparecerĂ¡n en esta pĂ¡gina.</translation>
<translation id="3788090790273268753">El certificado de este sitio web vence en 2016 y la cadena del certificado contiene un certificado que se firmĂ³ con SHA-1.</translation>
@@ -277,19 +285,25 @@
<translation id="3884278016824448484">Hay un identificador de dispositivo en conflicto.</translation>
<translation id="3885155851504623709">Parroquia</translation>
<translation id="3901925938762663762">CaducĂ³ la tarjeta.</translation>
+<translation id="3910267023907260648">Intentaste acceder a <ph name="DOMAIN" />, pero el servidor presentĂ³ un certificado firmado con un algoritmo de firma no seguro. Es posible que se hayan falsificado las credenciales de seguridad presentadas por el servidor y que este no sea el servidor esperado (es posible que te comuniques con un atacante). <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; supuestamente, su certificado de seguridad entra en vigencia mañana. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" />}other{El servidor no pudo comprobar si el dominio es <ph name="DOMAIN" />; supuestamente, su certificado de seguridad entra en vigencia en # dĂ­as. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">No se pudo cargar el documento PDF</translation>
<translation id="3963721102035795474">Modo de lectura</translation>
+<translation id="397105322502079400">Calculando...</translation>
<translation id="3973234410852337861">Se bloqueĂ³ <ph name="HOST_NAME" /></translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 pĂ¡gina web cercana}other{# pĂ¡ginas web cercanas}}</translation>
<translation id="4021036232240155012">DNS es el servicio en red que traduce el nombre de un sitio web en su direcciĂ³n de Internet.</translation>
<translation id="4030383055268325496">&amp;Deshacer Agregar</translation>
-<translation id="4032534284272647190">Acceso a <ph name="URL" /> denegado.</translation>
<translation id="404928562651467259">ADVERTENCIA</translation>
<translation id="4058922952496707368">Clave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">El cliente y el servidor no admiten un conjunto de cifrado o una versiĂ³n de protocolo SSL en comĂºn.</translation>
<translation id="4079302484614802869">El proxy estĂ¡ configurado para usar una URL de script .pac, no servidores proxy fijos.</translation>
<translation id="4103249731201008433">El nĂºmero de serie del dispositivo no es vĂ¡lido.</translation>
<translation id="4103763322291513355">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver las URL en lista negra y otras polĂ­ticas que estableciĂ³ el administrador del sistema.</translation>
+<translation id="4110615724604346410">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; su certificado de seguridad tiene errores. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">No se admite el alcance de la polĂ­tica.</translation>
+<translation id="4118212371799607889">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; Chromium no confĂ­a en el certificado de seguridad. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 mĂ¡s}other{# mĂ¡s}}</translation>
<translation id="4130226655945681476">Comprobar los cables de red, el mĂ³dem y el router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">¿Quieres que Chromium guarde esta tarjeta?</translation>
@@ -297,6 +311,7 @@
<translation id="4176463684765177261">Deshabilitado</translation>
<translation id="4196861286325780578">&amp;Rehacer Mover</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Comprobar las configuraciones de firewall y antivirus<ph name="END_LINK" />.</translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{ninguna}=1{1 app ($1)}=2{2 apps ($1, $2)}other{# apps ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Fallos</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Intenta ejecutar el DiagnĂ³stico de red<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">No</translation>
@@ -305,14 +320,15 @@
<translation id="4269787794583293679">(Sin nombre de usuario)</translation>
<translation id="4300246636397505754">Sugerencias para padres</translation>
<translation id="4304224509867189079">Acceder</translation>
+<translation id="432290197980158659">El servidor mostrĂ³ un certificado que no coincide con lo esperado. Estas expectativas se incluyen en determinados sitios web con un alto nivel de seguridad para garantizar tu protecciĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">No se pudo encontrar el artĂ­culo</translation>
+<translation id="4331708818696583467">No seguro</translation>
<translation id="4372948949327679948">Valor <ph name="VALUE_TYPE" /> esperado.</translation>
-<translation id="4377125064752653719">Intentaste acceder a <ph name="DOMAIN" />, pero el emisor anulĂ³ el certificado que presentĂ³ el servidor. Esto significa que no se debe confiar en absoluto en las credenciales de seguridad que presentĂ³ el servidor. Te puedes estar comunicando con un atacante.</translation>
<translation id="4381091992796011497">Nombre de usuario:</translation>
<translation id="4394049700291259645">Inhabilitar</translation>
<translation id="4395129973926795186">desde <ph name="START_DATE" /> hasta <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">resultados de bĂºsqueda</translation>
-<translation id="4424024547088906515">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; Chrome no confĂ­a en el certificado de seguridad. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante interceptĂ³ la conexiĂ³n.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> no aceptĂ³ tu certificado de acceso o es posible que no se haya proporcionado.</translation>
<translation id="443673843213245140">Se inhabilitĂ³ el uso de un proxy, pero se especificĂ³ una configuraciĂ³n explĂ­cita de proxy.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">EstĂ¡s viendo este mensaje porque Google SafeSites estĂ¡ inhabilitado.</translation>
@@ -324,12 +340,12 @@
<translation id="4522570452068850558">Detalles</translation>
<translation id="4558551763791394412">Intenta inhabilitar tus extensiones.</translation>
<translation id="4587425331216688090">¿Confirmas que quieres quitar la direcciĂ³n de Chrome?</translation>
+<translation id="4589078953350245614">Intentaste acceder a <ph name="DOMAIN" />, pero el servidor presentĂ³ un certificado no vĂ¡lido. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459">Tu conexiĂ³n a <ph name="DOMAIN" /> estĂ¡ encriptada con un conjunto de cifrado moderno.</translation>
<translation id="4594403342090139922">&amp;Deshacer Eliminar</translation>
+<translation id="4627442949885028695">CĂ³mo continuar desde otro dispositivo</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">EstĂ¡s viendo la pĂ¡gina de una extensiĂ³n.</translation>
-<translation id="467662567472608290">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad contiene errores. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante interceptĂ³ la conexiĂ³n.</translation>
-<translation id="4697214168136963651">Se bloqueĂ³ <ph name="URL" />.</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Se interrumpiĂ³ la conexiĂ³n</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />EjecuciĂ³n del DiagnĂ³stico de red de Windows<ph name="END_LINK" /></translation>
@@ -337,21 +353,26 @@
<translation id="4728558894243024398">Plataforma</translation>
<translation id="4744603770635761495">Ruta ejecutable</translation>
<translation id="4756388243121344051">&amp;Historial</translation>
+<translation id="4759238208242260848">Descargas</translation>
<translation id="4764776831041365478">Es posible que la pĂ¡gina web en <ph name="URL" /> no funcione temporalmente o se haya trasladado de manera permanente a una nueva direcciĂ³n web.</translation>
<translation id="4771973620359291008">Se ha producido un error desconocido.</translation>
<translation id="4782449893814226250">Les preguntaste a tus padres si puedes visitar esta pĂ¡gina.</translation>
<translation id="4800132727771399293">Verifica la fecha de vencimiento y el CVC, y vuelve a intentarlo.</translation>
-<translation id="4807049035289105102">No puedes visitar <ph name="SITE" /> ahora porque el sitio web enviĂ³ credenciales confusas que Google Chrome no puede procesar. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta pĂ¡gina funcione mĂ¡s tarde.</translation>
<translation id="4813512666221746211">Error de red</translation>
<translation id="4816492930507672669">Ajustar a la pĂ¡gina</translation>
<translation id="4850886885716139402">Ver</translation>
<translation id="4880827082731008257">Buscar historial</translation>
+<translation id="4884656795097055129">Se mostrarĂ¡n mĂ¡s artĂ­culos en el momento adecuado.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{y 1 pĂ¡gina web mĂ¡s}other{y # pĂ¡ginas web mĂ¡s}}</translation>
<translation id="4923417429809017348">Esta pĂ¡gina ha sido traducida desde un idioma desconocido a <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Debe especificarse un valor.</translation>
<translation id="4930497775425430760">EstĂ¡s viendo este mensaje porque tus padres tienen que aprobar nuevos sitios en tu primera visita.</translation>
<translation id="495170559598752135">Acciones</translation>
<translation id="4958444002117714549">Mostrar lista</translation>
+<translation id="4962322354953122629">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; Chrome no confĂ­a en el certificado de seguridad. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911">¿Quieres traducir del <ph name="ORIGINAL_LANGUAGE" /> al <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Este complemento no es compatible</translation>
<translation id="5002932099480077015">Si se habilita esta opciĂ³n, Chrome almacenarĂ¡ una copia de la tarjeta en el dispositivo para llenar mĂ¡s rĂ¡pidamente los formularios.</translation>
<translation id="5019198164206649151">La memoria auxiliar se encuentra en mal estado.</translation>
<translation id="5023310440958281426">Revisa las polĂ­ticas del administrador.</translation>
@@ -359,13 +380,12 @@
<translation id="5031870354684148875">Acerca de Google Traductor</translation>
<translation id="5040262127954254034">Privacidad</translation>
<translation id="5045550434625856497">Contraseña incorrecta</translation>
+<translation id="5056549851600133418">ArtĂ­culos para ti</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Comprobar la direcciĂ³n de proxy<ph name="END_LINK" />.</translation>
<translation id="5087286274860437796">El certificado del servidor no es vĂ¡lido en este momento.</translation>
<translation id="5089810972385038852">Estado</translation>
-<translation id="5094747076828555589">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; Chromium no confĂ­a en el certificado de seguridad. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante interceptĂ³ la conexiĂ³n.</translation>
<translation id="5095208057601539847">Provincia</translation>
<translation id="5115563688576182185">(64 bits)</translation>
-<translation id="5122371513570456792">Se encontraron <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />".</translation>
<translation id="5141240743006678641">Encriptar contraseñas sincronizadas con tus credenciales de Google</translation>
<translation id="5145883236150621069">CĂ³digo de error en la respuesta de la polĂ­tica</translation>
<translation id="5171045022955879922">Buscar o escribir URL</translation>
@@ -374,18 +394,18 @@
<translation id="5190835502935405962">Barra de marcadores</translation>
<translation id="5199729219167945352">Experimentos</translation>
<translation id="5251803541071282808">Nube</translation>
+<translation id="5277279256032773186">¿Usas Chrome en el trabajo? Las empresas pueden administrar la configuraciĂ³n de Chrome para sus empleados. MĂ¡s informaciĂ³n</translation>
<translation id="5299298092464848405">Error al analizar la polĂ­tica</translation>
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5308689395849655368">NotificaciĂ³n de fallas desactivada.</translation>
<translation id="5317780077021120954">Guardar</translation>
<translation id="5327248766486351172">Nombre</translation>
+<translation id="5359637492792381994">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; su certificado de seguridad no es vĂ¡lido en este momento. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Error al almacenar la configuraciĂ³n de la polĂ­tica</translation>
-<translation id="540969355065856584">Este servidor no pudo demostrar que se trata de <ph name="DOMAIN" />; el certificado de seguridad no es vĂ¡lido en este momento. Esto puede deberse a una configuraciĂ³n incorrecta o a un ataque que intercepta tu conexiĂ³n.</translation>
<translation id="5421136146218899937">Borrar datos de navegaciĂ³n...</translation>
<translation id="5430298929874300616">Eliminar marcador</translation>
<translation id="5431657950005405462">No se encontrĂ³ tu archivo</translation>
<translation id="5435775191620395718">Se muestra el historial de este dispositivo. <ph name="BEGIN_LINK" />MĂ¡s informaciĂ³n<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Las sugerencias de contenido personalizado estĂ¡n inhabilitadas, porque tus datos sincronizados estĂ¡n protegidos con una frase de contraseña personalizada.</translation>
<translation id="5439770059721715174">Error de validaciĂ³n de esquema en "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">No se encuentra esta pĂ¡gina <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">Marca de tiempo de polĂ­tica incorrecta</translation>
@@ -408,14 +428,18 @@
<translation id="5622887735448669177">¿Deseas salir de este sitio?</translation>
<translation id="5629630648637658800">Error al cargar la configuraciĂ³n de la polĂ­tica</translation>
<translation id="5631439013527180824">Token de administraciĂ³n de dispositivos no vĂ¡lido</translation>
-<translation id="5650551054760837876">No se han encontrado resultados de bĂºsqueda.</translation>
<translation id="5677928146339483299">Bloqueado</translation>
<translation id="5710435578057952990">No se ha verificado la identidad de este sitio web.</translation>
<translation id="5720705177508910913">Usuario actual</translation>
+<translation id="572328651809341494">Pestañas recientes</translation>
<translation id="5784606427469807560">Se produjo un problema al confirmar tu tarjeta. Comprueba tu conexiĂ³n a Internet y vuelve a intentarlo.</translation>
<translation id="5785756445106461925">AdemĂ¡s, esta pĂ¡gina incluye otros recursos que no son seguros. Otras personas pueden ver estos recursos mientras se encuentran en trĂ¡nsito, y un atacante puede modificarlos para cambiar la apariencia de la pĂ¡gina.</translation>
+<translation id="5786044859038896871">¿Deseas llenar los campos con la informaciĂ³n de tu tarjeta?</translation>
+<translation id="5803412860119678065">¿Deseas llenar los campos con la informaciĂ³n de tu tarjeta <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Tu conexiĂ³n a <ph name="DOMAIN" /> estĂ¡ encriptada con un conjunto de cifrado obsoleto.</translation>
<translation id="5813119285467412249">&amp;Rehacer Agregar</translation>
+<translation id="5814352347845180253">Es posible que ya no puedas acceder al contenido premium de <ph name="SITE" /> y otros sitios.</translation>
+<translation id="5843436854350372569">Intentaste acceder a <ph name="DOMAIN" />, pero el servidor presentĂ³ un certificado que contiene una clave no segura. Es posible que un atacante haya descifrado la clave privada y que este no sea el servidor esperado (es posible que te comuniques con un atacante). <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">EstĂ¡s viendo este mensaje porque tu administrador bloqueĂ³ este sitio.</translation>
<translation id="5857090052475505287">Nueva carpeta</translation>
<translation id="5869405914158311789">No se puede acceder a este sitio</translation>
@@ -423,6 +447,7 @@
<translation id="5872918882028971132">Sugerencias para padres</translation>
<translation id="59107663811261420">Google Payments no admite este tipo de tarjeta para este comerciante. Selecciona otra tarjeta.</translation>
<translation id="59174027418879706">Activado</translation>
+<translation id="5926846154125914413">Es posible que ya no puedas acceder al contenido premium de otros sitios.</translation>
<translation id="5966707198760109579">Semana</translation>
<translation id="5967867314010545767">Eliminar del historial</translation>
<translation id="5975083100439434680">Alejar</translation>
@@ -434,12 +459,12 @@
<translation id="604124094241169006">AutomĂ¡tico</translation>
<translation id="6042308850641462728">MĂ¡s</translation>
<translation id="6060685159320643512">Cuidado, estos experimentos pueden dañarte</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{ninguna}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Revisa los cables y reinicia los routers, mĂ³dems u otros dispositivos
de red que estés usando.</translation>
<translation id="614940544461990577">Intenta:</translation>
<translation id="6150607114729249911">Debes preguntar a tus padres si puedes visitar esta pĂ¡gina.</translation>
<translation id="6151417162996330722">El certificado de servidor tiene un perĂ­odo de validez demasiado extenso.</translation>
-<translation id="6154808779448689242">El token de polĂ­tica devuelto no coincide con el token actual.</translation>
<translation id="6165508094623778733">MĂ¡s informaciĂ³n</translation>
<translation id="6203231073485539293">Comprueba tu conexiĂ³n a Internet.</translation>
<translation id="6218753634732582820">¿Confirmas que quieres quitar la direcciĂ³n de Chromium?</translation>
@@ -452,24 +477,30 @@
<translation id="6328639280570009161">Intenta inhabilitar la predicciĂ³n de red.</translation>
<translation id="6337534724793800597">Filtrar polĂ­ticas por nombre</translation>
<translation id="6342069812937806050">Recién</translation>
+<translation id="6345221851280129312">tamaño desconocido</translation>
<translation id="6355080345576803305">AnulaciĂ³n de sesiĂ³n pĂºblica</translation>
<translation id="6358450015545214790">¿QuĂ© significa esto?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 sugerencia mĂ¡s}other{# sugerencias mĂ¡s}}</translation>
<translation id="6387478394221739770">Si estĂ¡s interesado en probar nuevas e interesantes funciones de Chrome, visita nuestro canal beta en chrome.com/beta.</translation>
-<translation id="641480858134062906">Se produjo un error al cargar <ph name="URL" />.</translation>
+<translation id="6389758589412724634">Chromium se quedĂ³ sin memoria cuando intentaba mostrar esta pĂ¡gina web.</translation>
+<translation id="6416403317709441254">No puedes visitar <ph name="SITE" /> ahora mismo porque el sitio web enviĂ³ credenciales confusas que Chromium no puede procesar. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta pĂ¡gina funcione mĂ¡s tarde. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">No se pudo verificar si el certificado ha sido revocado.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> rechazĂ³ la conexiĂ³n.</translation>
<translation id="6445051938772793705">PaĂ­s</translation>
<translation id="6451458296329894277">Confirmar reenvĂ­o del formulario</translation>
<translation id="6458467102616083041">Se ignora porque la polĂ­tica inhabilita la bĂºsqueda predeterminada.</translation>
+<translation id="6462969404041126431">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; es posible que su certificado de seguridad se haya revocado. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">PolĂ­ticas de dispositivos</translation>
<translation id="6489534406876378309">Comenzar a cargar fallos</translation>
<translation id="6529602333819889595">&amp;Rehacer Eliminar</translation>
+<translation id="6534179046333460208">Sugerencias de la Web fĂ­sica</translation>
<translation id="6550675742724504774">Opciones</translation>
+<translation id="6593753688552673085">menos de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opciones de encriptaciĂ³n</translation>
<translation id="662080504995468778">Permanecer aquĂ­</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> BĂºsqueda</translation>
-<translation id="6634865548447745291">No puedes visitar <ph name="SITE" /> ahora porque <ph name="BEGIN_LINK" />este certificado se revocĂ³<ph name="END_LINK" />. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta pĂ¡gina funcione mĂ¡s tarde.</translation>
<translation id="6644283850729428850">Esta polĂ­tica no ha sido aprobada.</translation>
+<translation id="6652240803263749613">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el sistema operativo de tu computadora no confĂ­a en el certificado de seguridad. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">Editar carpeta</translation>
<translation id="6660210980321319655">Se informĂ³ automĂ¡ticamente el <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">¿Confirmas que quieres quitar la sugerencia de formulario de Chromium?</translation>
@@ -477,6 +508,7 @@
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Escribe el tĂ©rmino de bĂºsqueda&gt;</translation>
<translation id="6711464428925977395">Hay un error en el servidor proxy o la direcciĂ³n es incorrecta.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{ninguno}=1{1 elemento}other{# elementos}}</translation>
<translation id="674375294223700098">Error de certificado de servidor desconocido.</translation>
<translation id="6753269504797312559">Valor de la polĂ­tica</translation>
<translation id="6757797048963528358">El dispositivo se suspendiĂ³.</translation>
@@ -488,7 +520,6 @@
<translation id="6891596781022320156">No se admite el nivel de polĂ­ticas.</translation>
<translation id="6895330447102777224">Tu tarjeta se confirmĂ³</translation>
<translation id="6897140037006041989">User agent</translation>
-<translation id="6903907808598579934">Activar la sincronizaciĂ³n</translation>
<translation id="6915804003454593391">Usuario:</translation>
<translation id="6957887021205513506">El certificado del servidor parece falso.</translation>
<translation id="6965382102122355670">Aceptar</translation>
@@ -496,9 +527,11 @@
<translation id="6970216967273061347">Distrito</translation>
<translation id="6973656660372572881">Se especifican servidores proxy fijos y URL de secuencias de comandos .pac.</translation>
<translation id="6989763994942163495">Mostrar configuraciĂ³n avanzada...</translation>
+<translation id="7000990526846637657">No se encontraron entradas en el historial</translation>
+<translation id="7009986207543992532">Intentaste acceder a <ph name="DOMAIN" />, pero el certificado de servidor tenĂ­a un perĂ­odo de validez demasiado extenso para ser fiable. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Es posible que tu cuenta de Google tenga otros formularios del historial de navegaciĂ³n en <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Contraseñas</translation>
-<translation id="7050187094878475250">Intentaste acceder a <ph name="DOMAIN" />, pero el certificado de servidor tenĂ­a un perĂ­odo de validez demasiado extenso para ser fiable.</translation>
<translation id="7087282848513945231">Condado</translation>
<translation id="7088615885725309056">Anterior</translation>
<translation id="7090678807593890770">Buscar <ph name="LINK" /> en Google</translation>
@@ -517,13 +550,13 @@
<translation id="7246609911581847514">EstĂ¡s viendo este mensaje porque tu administrador tiene que aprobar nuevos sitios en tu primera visita.</translation>
<translation id="724975217298816891">Ingresa la fecha de vencimiento y el CVC de la tarjeta <ph name="CREDIT_CARD" /> para actualizar sus datos. DespuĂ©s de confirmarla, los datos de tu tarjeta se compartirĂ¡n con este sitio.</translation>
<translation id="725866823122871198">No se puede establecer una conexiĂ³n privada a <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque la fecha y la hora del equipo (<ph name="DATE_AND_TIME" />) son incorrectas.</translation>
-<translation id="7265986070661382626">No puedes visitar <ph name="SITE" /> ahora porque el sitio web <ph name="BEGIN_LINK" />utiliza fijaciĂ³n de certificados<ph name="END_LINK" />. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta pĂ¡gina funcione mĂ¡s tarde.</translation>
<translation id="7269802741830436641">Esta pĂ¡gina web tiene un bucle de redirecciĂ³n</translation>
<translation id="7275334191706090484">Marcadores administrados</translation>
<translation id="7298195798382681320">Recomendada</translation>
-<translation id="7301833672208172928">Activar la sincronizaciĂ³n del historial</translation>
+<translation id="7309308571273880165">El informe de fallos se capturĂ³ a las <ph name="CRASH_TIME" /> (el usuario solicitĂ³ la carga; todavĂ­a no se cargĂ³)</translation>
<translation id="7334320624316649418">&amp;Rehacer Reorganizar</translation>
<translation id="733923710415886693">El certificado del servidor no se divulgĂ³ mediante el Certificado de transparencia.</translation>
+<translation id="7351800657706554155">No puedes visitar <ph name="SITE" /> ahora mismo porque este certificado se revocĂ³. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta pĂ¡gina funcione mĂ¡s tarde. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">LĂ­nea de comandos</translation>
<translation id="7372973238305370288">resultado de bĂºsqueda</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -542,16 +575,17 @@
<translation id="7469372306589899959">Confirmando la tarjeta</translation>
<translation id="7481312909269577407">Reenviar</translation>
<translation id="7485870689360869515">No se encontrĂ³ ningĂºn dato.</translation>
+<translation id="7508255263130623398">El ID de dispositivo de la polĂ­tica que se muestra estĂ¡ vacĂ­o o no coincide con el ID de dispositivo actual</translation>
<translation id="7514365320538308">Descargar</translation>
<translation id="7518003948725431193">No se encontrĂ³ una pĂ¡gina web para la siguiente direcciĂ³n web: <ph name="URL" /></translation>
<translation id="7537536606612762813">Obligatoria</translation>
<translation id="7542995811387359312">El rellenado automĂ¡tico de la tarjeta de crĂ©dito se inhabilitĂ³ porque este formulario no usa una conexiĂ³n segura.</translation>
<translation id="7549584377607005141">Esta pĂ¡gina web necesita los datos ingresados anteriormente para mostrarse correctamente. Puedes volver a enviar los datos, pero ten en cuenta que se repetirĂ¡n las acciones que la pĂ¡gina haya realizado anteriormente.</translation>
<translation id="7554791636758816595">Nueva pestaña</translation>
-<translation id="7567204685887185387">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad podrĂ­a haberse emitido de forma fraudulenta. Es posible que esto se deba a una configuraciĂ³n incorrecta o a que un atacante interceptĂ³ la conexiĂ³n.</translation>
<translation id="7568593326407688803">Esta pĂ¡gina estĂ¡ en<ph name="ORIGINAL_LANGUAGE" />¿Quieres traducirla?</translation>
<translation id="7569952961197462199">¿Confirmas que quieres quitar la tarjeta de crĂ©dito de Chrome?</translation>
<translation id="7578104083680115302">Paga con rapidez en sitios y apps a través de varios dispositivos con tarjetas que guardaste en Google.</translation>
+<translation id="7588950540487816470">Web fĂ­sica</translation>
<translation id="7592362899630581445">El certificado del servidor no cumple con las restricciones de nombre.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> no puede procesar esta solicitud en este momento.</translation>
<translation id="7600965453749440009">Nunca traducir <ph name="LANGUAGE" /></translation>
@@ -562,6 +596,7 @@
<translation id="7637571805876720304">¿Confirmas que quieres quitar la tarjeta de crĂ©dito de Chromium?</translation>
<translation id="765676359832457558">Ocultar configuraciĂ³n avanzada...</translation>
<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7667346355482952095">El token de polĂ­tica mostrado estĂ¡ vacĂ­o o no coincide con el token actual</translation>
<translation id="7668654391829183341">Dispositivo desconocido</translation>
<translation id="7674629440242451245">Si estĂ¡s interesado en probar nuevas e interesantes funciones de Chrome, visita nuestro canal de programadores en chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Continuar a <ph name="SITE" /> (no seguro)<ph name="END_LINK" /></translation>
@@ -578,10 +613,10 @@
<translation id="780301667611848630">No, gracias</translation>
<translation id="7805768142964895445">Estado</translation>
<translation id="7813600968533626083">¿Confirmas que quieres quitar la sugerencia de formulario de Chrome?</translation>
+<translation id="7815407501681723534">Se encontraron <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
<translation id="785549533363645510">Sin embargo, no eres invisible. El modo de navegaciĂ³n de incĂ³gnito no oculta tu navegaciĂ³n de tu empleador, de tu proveedor de servicios de Internet, ni de los sitios web que visitas.</translation>
<translation id="7887683347370398519">Verifica tu CVC y vuelve a intentarlo.</translation>
<translation id="7894616681410591072">Parece que necesitas el permiso de <ph name="NAME" /> para acceder a esta pĂ¡gina.</translation>
-<translation id="790025292736025802">No se encuentra <ph name="URL" /></translation>
<translation id="7912024687060120840">En carpeta:</translation>
<translation id="7920092496846849526">Les preguntaste a tus padres si puedes visitar esta pĂ¡gina.</translation>
<translation id="7935318582918952113">Filtro de DOM</translation>
@@ -594,9 +629,10 @@
<translation id="7995512525968007366">Sin especificar</translation>
<translation id="8012647001091218357">No pudimos comunicarnos con tus padres. Vuelve a intentarlo.</translation>
<translation id="8034522405403831421">Esta pĂ¡gina estĂ¡ en <ph name="SOURCE_LANGUAGE" />. ¿Quieres traducirla al <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">No se encontraron entradas del historial.</translation>
<translation id="8088680233425245692">Error al visualizar artĂ­culo</translation>
+<translation id="8089520772729574115">menos de 1 Mb</translation>
<translation id="8091372947890762290">La activaciĂ³n estĂ¡ pendiente en el servidor.</translation>
+<translation id="8129262335948759431">cantidad desconocida</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">No se encontrĂ³ la <ph name="BEGIN_ABBR" />direcciĂ³n DNS<ph name="END_ABBR" /> del servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">La computadora se suspendiĂ³.</translation>
@@ -605,6 +641,7 @@
<translation id="8201077131113104583">URL de actualizaciĂ³n no vĂ¡lida para la extensiĂ³n con ID "<ph name="EXTENSION_ID" />"</translation>
<translation id="8218327578424803826">UbicaciĂ³n asignada:</translation>
<translation id="8225771182978767009">La persona que configurĂ³ esta computadora decidiĂ³ bloquear este sitio.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">La pĂ¡gina que buscas ha utilizado la informaciĂ³n que has especificado. Volver a la pĂ¡gina podrĂ­a provocar la repeticiĂ³n de alguna acciĂ³n. ¿Deseas continuar?</translation>
<translation id="8249320324621329438">Se obtuvo por Ăºltima vez:</translation>
<translation id="8261506727792406068">Eliminar</translation>
@@ -617,12 +654,17 @@
<translation id="8349305172487531364">Barra de marcadores</translation>
<translation id="8363502534493474904">Desactivar el modo de aviĂ³n.</translation>
<translation id="8364627913115013041">Sin establecer</translation>
+<translation id="8380941800586852976">Peligrosa</translation>
<translation id="8412145213513410671">Bloqueos (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Debes ingresar la misma frase de contraseña dos veces.</translation>
<translation id="8428213095426709021">ConfiguraciĂ³n</translation>
+<translation id="8433057134996913067">Si realizas esta acciĂ³n, saldrĂ¡s de la mayorĂ­a de los sitios web.</translation>
<translation id="8437238597147034694">&amp;Deshacer Mover</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 tarjeta de crédito}other{# tarjetas de crédito}}</translation>
+<translation id="8483780878231876732">Para usar tarjetas de tu cuenta de Google, accede a tu cuenta en Chrome</translation>
<translation id="8488350697529856933">Se aplica a</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> tardĂ³ demasiado en responder.</translation>
+<translation id="852346902619691059">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el sistema operativo de tu dispositivo no confĂ­a en el certificado de seguridad. Es posible que se deba a una configuraciĂ³n incorrecta o a que un atacante haya interceptado tu conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Google Payments no admite este tipo de tarjeta. Selecciona otra tarjeta.</translation>
<translation id="8550022383519221471">El servicio de sincronizaciĂ³n no estĂ¡ disponible para tu dominio.</translation>
<translation id="8553075262323480129">FallĂ³ la traducciĂ³n debido a que no se pudo determinar el idioma de la pĂ¡gina.</translation>
@@ -634,15 +676,12 @@
<translation id="8647750283161643317">Restablecer todos los valores predeterminados</translation>
<translation id="8680787084697685621">Los datos de inicio de cuenta estĂ¡n desactualizados</translation>
<translation id="8703575177326907206">Tu conexiĂ³n a <ph name="DOMAIN" /> no estĂ¡ cifrada.</translation>
-<translation id="8713130696108419660">Firma inicial no vĂ¡lida</translation>
<translation id="8725066075913043281">Intentar nuevamente</translation>
<translation id="8728672262656704056">EstĂ¡s en modo incĂ³gnito</translation>
<translation id="8730621377337864115">Listo</translation>
<translation id="8738058698779197622">Para establecer una conexiĂ³n segura, el reloj debe estar configurado correctamente. Esto se debe a que los certificados que usan los sitios web para su identificaciĂ³n solo son vĂ¡lidos por perĂ­odos de tiempo especĂ­ficos. Debido a que la configuraciĂ³n del reloj del dispositivo es incorrecta, Chromium no puede verificar estos certificados.</translation>
<translation id="8740359287975076522">No se encontrĂ³ <ph name="HOST_NAME" />’s &lt;abbr id="dnsDefinition"&gt;DNS address&lt;/abbr&gt;. Se estĂ¡ diagnosticando el problema.</translation>
-<translation id="8741995161408053644">Es posible que tu cuenta de Google tenga otros formularios del historial de navegaciĂ³n en <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Rehacer Eliminar</translation>
-<translation id="8790687370365610530">Para obtener contenido personalizado y sugerido por Google, activa la sincronizaciĂ³n del historial.</translation>
<translation id="8798099450830957504">Predeterminado</translation>
<translation id="8804164990146287819">PolĂ­tica de privacidad</translation>
<translation id="8820817407110198400">Marcadores</translation>
@@ -664,13 +703,11 @@
<translation id="8971063699422889582">El certificado del servidor ha caducado.</translation>
<translation id="8987927404178983737">Mes</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">El servidor presentĂ³ un certificado que no se divulgĂ³ de forma pĂºblica con la polĂ­tica Certificado de transparencia. Este es un requisito para algunos certificados que permite garantizar su confiabilidad y protegerte de atacantes.</translation>
<translation id="9001074447101275817">El proxy <ph name="DOMAIN" /> requiere un nombre de usuario y una contraseña.</translation>
<translation id="901974403500617787">El propietario es el Ăºnico que puede especificar las marcas que se aplican a todo el sistema: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Esta pĂ¡gina se tradujo al <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="9038649477754266430">Utilizar un servicio de predicciĂ³n para cargar las pĂ¡ginas mĂ¡s rĂ¡pido</translation>
<translation id="9039213469156557790">AdemĂ¡s, esta pĂ¡gina incluye otros recursos que no son seguros. Otras personas pueden ver estos recursos mientras se encuentran en trĂ¡nsito, y un atacante puede modificarlos para cambiar el funcionamiento de la pĂ¡gina.</translation>
-<translation id="9049981332609050619">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor presentĂ³ un certificado no vĂ¡lido.</translation>
<translation id="9050666287014529139">Frase de contraseña</translation>
<translation id="9065203028668620118">Editar</translation>
<translation id="9092364396508701805">La pĂ¡gina <ph name="HOST_NAME" /> no estĂ¡ funcionando</translation>
diff --git a/chromium/components/strings/components_strings_es.xtb b/chromium/components/strings/components_strings_es.xtb
index a85f02ae38f..842df076b1e 100644
--- a/chromium/components/strings/components_strings_es.xtb
+++ b/chromium/components/strings/components_strings_es.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="es">
+<translation id="1008557486741366299">Ahora no</translation>
<translation id="1015730422737071372">ProporciĂ³nanos mĂ¡s detalles</translation>
<translation id="1032854598605920125">Girar hacia la derecha</translation>
<translation id="1038842779957582377">nombre desconocido</translation>
+<translation id="1053591932240354961">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web ha enviado credenciales codificadas que Google Chrome no puede procesar. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta pĂ¡gina funcione mĂ¡s tarde. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">&amp;Deshacer acciĂ³n de añadir</translation>
<translation id="10614374240317010">Contraseñas que nunca se guardan</translation>
-<translation id="1064422015032085147">El servidor que aloja la pĂ¡gina web puede estar sobrecargado o en mantenimiento.
- Para evitar que se genere demasiado trĂ¡fico y que la situaciĂ³n empeore,
- no se permiten temporalmente las solicitudes para acceder a esta URL.</translation>
<translation id="106701514854093668">Marcadores del ordenador</translation>
<translation id="1080116354587839789">Se ajusta al ancho</translation>
+<translation id="1103124106085518534">Todo listo por ahora</translation>
<translation id="1103523840287552314">Traducir siempre el <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Si se selecciona, Chrome almacenarĂ¡ una copia de tu tarjeta en este dispositivo para completar formularios mĂ¡s rĂ¡pidamente.</translation>
+<translation id="1111153019813902504">Marcadores visitados recientemente</translation>
<translation id="1113869188872983271">&amp;Deshacer reorganizaciĂ³n</translation>
+<translation id="1126551341858583091">El tamaño del almacenamiento local es de <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Caché de política correcta</translation>
<translation id="113188000913989374"><ph name="SITE" /> dice:</translation>
<translation id="1132774398110320017">ConfiguraciĂ³n de la funciĂ³n Autocompletar de Chrome...</translation>
-<translation id="1150979032973867961">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, el sistema operativo de tu ordenador no confĂ­a en su certificado de seguridad. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.</translation>
<translation id="1152921474424827756">Accede a una <ph name="BEGIN_LINK" />copia almacenada en caché<ph name="END_LINK" /> de <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ha cerrado la conexiĂ³n de forma inesperada.</translation>
<translation id="1161325031994447685">Volver a conectarte a una red Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Eliminar</translation>
<translation id="1201402288615127009">Siguiente</translation>
<translation id="1201895884277373915">MĂ¡s entradas de este sitio</translation>
-<translation id="121201262018556460">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado que contiene una clave no segura. Es posible que alguien haya descifrado la clave privada y que hayas accedido a la pĂ¡gina de esa persona en lugar de establecer conexiĂ³n con el servidor.</translation>
+<translation id="1206967143813997005">Firma inicial no vĂ¡lida</translation>
+<translation id="1209206284964581585">Ocultar por ahora</translation>
<translation id="1219129156119358924">Seguridad del sistema</translation>
<translation id="1227224963052638717">PolĂ­tica desconocida</translation>
<translation id="1227633850867390598">Ocultar valor</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">SĂ­</translation>
<translation id="1430915738399379752">Imprimir</translation>
<translation id="1442912890475371290">Se ha bloqueado un intento de <ph name="BEGIN_LINK" />acceso a una pĂ¡gina de <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web utiliza la fijaciĂ³n de certificados. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta pĂ¡gina funcione mĂ¡s tarde. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">Muestra una copia guardada (es decir, no actualizada) de esta pĂ¡gina.</translation>
<translation id="1519264250979466059">Fecha de compilaciĂ³n</translation>
<translation id="1549470594296187301">JavaScript debe estar habilitado para utilizar esta funciĂ³n.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">La configuraciĂ³n de red no es vĂ¡lida y no se ha podido importar.</translation>
<translation id="1644574205037202324">Historial</translation>
<translation id="1645368109819982629">Protocolo no admitido</translation>
-<translation id="1655462015569774233">{1,plural, =1{Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad caducĂ³ ayer. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. El reloj de tu ordenador estĂ¡ establecido actualmente en las <ph name="CURRENT_DATE" />. ¿Es correcto? Si no lo es, corrige el reloj del sistema y, a continuaciĂ³n, actualiza esta pĂ¡gina.}other{Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad caducĂ³ hace # dĂ­as. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. El reloj de tu ordenador estĂ¡ establecido actualmente en las <ph name="CURRENT_DATE" />. ¿Es correcto? Si no lo es, corrige el reloj del sistema y, a continuaciĂ³n, actualiza esta pĂ¡gina.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> utiliza normalmente el cifrado para proteger tu informaciĂ³n. Cuando Google Chrome intentĂ³ establecer conexiĂ³n con <ph name="SITE" />, el sitio web devolviĂ³ unas credenciales inusuales e incorrectas. Esto puede ocurrir si un atacante intenta suplantar la identidad de <ph name="SITE" /> o si una pantalla de inicio de sesiĂ³n Wi-Fi interrumpe la conexiĂ³n. Tu informaciĂ³n sigue estando protegida, ya que Google Chrome detuvo la conexiĂ³n antes de que se intercambiaran datos.</translation>
<translation id="168841957122794586">El certificado del servidor contiene una clave criptogrĂ¡fica no segura.</translation>
<translation id="1701955595840307032">Obtener contenido sugerido</translation>
-<translation id="1706954506755087368">{1,plural, =1{Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; supuestamente, su certificado de seguridad es vĂ¡lido a partir de mañana. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n.}other{Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; supuestamente, su certificado de seguridad es vĂ¡lido dentro de # dĂ­as. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n.}}</translation>
<translation id="1710259589646384581">Sistema operativo</translation>
<translation id="1734864079702812349">American Express</translation>
<translation id="1734878702283171397">Intenta ponerte en contacto con el administrador del sistema.</translation>
<translation id="17513872634828108">Pestañas abiertas</translation>
<translation id="1753706481035618306">NĂºmero de pĂ¡gina</translation>
-<translation id="1761412452051366565">Para obtener contenido personalizado sugerido por Google, activa la sincronizaciĂ³n.</translation>
-<translation id="1763864636252898013">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, el sistema operativo de tu dispositivo no confĂ­a en su certificado de seguridad. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Prueba a ejecutar DiagnĂ³sticos de red de Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Actualiza tu frase de contraseña de sincronizaciĂ³n.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Los marcadores a los que hayas accedido recientemente aparecerĂ¡n aquĂ­.</translation>
<translation id="1821930232296380041">ParĂ¡metros de solicitud o solicitud no vĂ¡lidos</translation>
<translation id="1838667051080421715">EstĂ¡s viendo la fuente de una pĂ¡gina web.</translation>
<translation id="1871208020102129563">Se ha configurado el proxy de forma que use servidores proxy fijos, en lugar de una URL de secuencia de comandos .pac.</translation>
<translation id="1883255238294161206">Contraer lista</translation>
<translation id="1898423065542865115">Filtrado</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> no ha aceptado el certificado de inicio de sesiĂ³n o puede que este haya caducado.</translation>
<translation id="194030505837763158">Ir a <ph name="LINK" /></translation>
<translation id="1962204205936693436">Marcadores de <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Error de serializaciĂ³n</translation>
<translation id="1974060860693918893">Opciones avanzadas</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{y una mĂ¡s}other{y # mĂ¡s}}</translation>
<translation id="2025186561304664664">Se ha establecido que el proxy se configure automĂ¡ticamente.</translation>
<translation id="2030481566774242610">¿QuerĂ­as decir <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Este mensaje aparece porque tus padres deben aprobar los sitios web nuevos cuando accedas a ellos por primera vez.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Comprobar el proxy y el cortafuegos<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">CĂ³digo postal</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{Una sugerencia}other{# sugerencias}}</translation>
<translation id="2065985942032347596">Se requiere autenticaciĂ³n</translation>
<translation id="2079545284768500474">Deshacer</translation>
<translation id="20817612488360358">Se ha establecido la configuraciĂ³n del proxy del sistema, pero tambiĂ©n se han especificado ajustes de proxy explĂ­citos.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Editar marcador</translation>
<translation id="2166049586286450108">Acceso de administrador completo</translation>
<translation id="2166378884831602661">Este sitio web no puede proporcionar una conexiĂ³n segura</translation>
-<translation id="2171101176734966184">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado firmado con un algoritmo de firma no seguro. Una posible causa de este problema es que se hayan falsificado las credenciales de seguridad presentadas por el servidor y que hayas accedido a la pĂ¡gina de un atacante en lugar de establecer conexiĂ³n con el servidor en cuestiĂ³n.</translation>
<translation id="2181821976797666341">PolĂ­ticas</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{Una direcciĂ³n}other{# direcciones}}</translation>
<translation id="2212735316055980242">PolĂ­tica no encontrada</translation>
<translation id="2213606439339815911">Recuperando entradas...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> no estĂ¡ disponible.</translation>
<translation id="2230458221926704099">Soluciona los problemas de tu conexiĂ³n con la <ph name="BEGIN_LINK" />aplicaciĂ³n de diagnĂ³stico<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Enviar ahora</translation>
<translation id="225207911366869382">Este valor ya no se utiliza para esta polĂ­tica.</translation>
<translation id="2262243747453050782">Error de HTTP</translation>
<translation id="2282872951544483773">Experimentos no disponibles</translation>
<translation id="2292556288342944218">Tu acceso a Internet estĂ¡ bloqueado</translation>
<translation id="229702904922032456">Ha caducado un certificado raĂ­z o intermedio.</translation>
<translation id="230155334948463882">¿Nueva tarjeta?</translation>
+<translation id="2305919008529760154">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad podrĂ­a haberse emitido de forma fraudulenta. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> necesita un nombre de usuario y una contraseña.</translation>
+<translation id="2318774815570432836">No puedes acceder a <ph name="SITE" /> en este momento por que el sitio web utiliza HSTS. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta pĂ¡gina funcione mĂ¡s tarde. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">Se ha ignorado un marcador no vĂ¡lido en el Ă­ndice <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Otros marcadores</translation>
<translation id="2359808026110333948">Continuar</translation>
<translation id="2365563543831475020">No se ha subido el informe sobre fallos registrado el <ph name="CRASH_TIME" /></translation>
<translation id="2367567093518048410">Nivel</translation>
+<translation id="2371153335857947666">{1,plural, =1{Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad caducĂ³ ayer. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. La fecha que consta en el reloj de tu ordenador actualmente es el <ph name="CURRENT_DATE" />. ¿Es correcto? Si no lo es, corrige el reloj del sistema y, a continuaciĂ³n, actualiza esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" />}other{Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad caducĂ³ hace # dĂ­as. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. La fecha que consta en el reloj de tu ordenador actualmente es el <ph name="CURRENT_DATE" />. ¿Es correcto? Si no lo es, corrige el reloj del sistema y, a continuaciĂ³n, actualiza esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">No hay alternativas de IU disponibles</translation>
<translation id="2384307209577226199">Empresa (con valores predeterminados)</translation>
-<translation id="238526402387145295">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web <ph name="BEGIN_LINK" />utiliza HSTS<ph name="END_LINK" />. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta pĂ¡gina funcione mĂ¡s tarde.</translation>
<translation id="2386255080630008482">Se ha revocado el certificado de servidor.</translation>
<translation id="2392959068659972793">Mostrar polĂ­ticas sin valores establecidos</translation>
<translation id="2396249848217231973">&amp;Deshacer eliminaciĂ³n</translation>
-<translation id="2413528052993050574">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" /> y se podrĂ­a rechazar su certificado de seguridad. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.</translation>
<translation id="2455981314101692989">Esta pĂ¡gina ha inhabilitado la opciĂ³n de autocompletar para este formulario.</translation>
+<translation id="2463739503403862330">Rellenar</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Ejecutar DiagnĂ³sticos de red<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">La URL de bĂºsqueda no es vĂ¡lida.</translation>
<translation id="2491120439723279231">El certificado del servidor contiene errores.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Enviar</translation>
<translation id="2674170444375937751">¿Seguro que quieres eliminar estas pĂ¡ginas del historial?</translation>
<translation id="2677748264148917807">Salir</translation>
+<translation id="269990154133806163">El servidor ha mostrado un certificado que no se ha hecho pĂºblico mediante la polĂ­tica de transparencia en los certificados. Este requisito se aplica a algunos certificados para garantizar que son de confianza y ofrecer protecciĂ³n contra los atacantes. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">El valor no coincide con el formato.</translation>
<translation id="2704951214193499422">Chromium no ha podido confirmar tu tarjeta en este momento. Vuelve a intentarlo mĂ¡s tarde.</translation>
<translation id="2705137772291741111">La copia guardada (almacenada en caché) de este sitio web no se ha podido leer.</translation>
<translation id="2709516037105925701">Autocompletar</translation>
+<translation id="2712118517637785082">Has intentado acceder a <ph name="DOMAIN" />, pero el emisor ha revocado el certificado mostrado por el servidor, lo que significa que las credenciales de seguridad presentadas por el servidor no son de confianza. Es posible que hayas accedido a la pĂ¡gina de un atacante. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">Solicitar permiso</translation>
<translation id="2721148159707890343">Solicitud correcta</translation>
<translation id="2728127805433021124">El certificado del servidor estĂ¡ firmado con un algoritmo de firma no seguro.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Barra de direcciones y de bĂºsqueda </translation>
<translation id="2826760142808435982">La conexiĂ³n se ha encriptado y autenticado con <ph name="CIPHER" />, y utiliza <ph name="KX" /> como el mecanismo de intercambio clave.</translation>
<translation id="2835170189407361413">Eliminar formulario</translation>
-<translation id="2837049386027881519">Se ha vuelto a recuperar la conexiĂ³n con una versiĂ³n anterior del protocolo SSL o TLS. Este error suele indicar que el servidor utiliza un software demasiado obsoleto y que es posible que se produzcan otros problemas de seguridad.</translation>
<translation id="284702764277384724">Parece que el certificado de servidor de la pĂ¡gina <ph name="HOST_NAME" /> es falso.</translation>
<translation id="2889159643044928134">No volver a cargar</translation>
-<translation id="2896499918916051536">No se admite este complemento.</translation>
+<translation id="2900469785430194048">Google Chrome se ha quedado sin memoria al intentar mostrar esta pĂ¡gina web.</translation>
<translation id="2909946352844186028">Se ha detectado un cambio de red.</translation>
-<translation id="2915500479781995473">Este servidor no ha podido probar que su dominio sea <ph name="DOMAIN" />, ya que su certificado de seguridad ha caducado. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n. La hora actual del reloj de tu ordenador es <ph name="CURRENT_TIME" />. ¿Es correcta? Si no lo es, debes corregir la hora del sistema y, a continuaciĂ³n, actualizar esta pĂ¡gina.</translation>
<translation id="2922350208395188000">No es posible comprobar el certificado del servidor.</translation>
-<translation id="2941952326391522266">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, su certificado de seguridad procede de <ph name="DOMAIN2" />. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.</translation>
<translation id="2948083400971632585">Puedes inhabilitar los servidores proxy configurados para una conexiĂ³n en la pĂ¡gina de configuraciĂ³n.</translation>
<translation id="2955913368246107853">Cerrar la barra de bĂºsqueda</translation>
<translation id="2958431318199492670">La configuraciĂ³n de red no cumple el estĂ¡ndar ONC. Es posible que no se importen partes de la configuraciĂ³n.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Tipo de polĂ­tica incorrecto</translation>
<translation id="3032412215588512954">¿Quieres volver a cargar este sitio web?</translation>
<translation id="3037605927509011580">¡Oh, no!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{al menos un elemento en dispositivos sincronizados}=1{un elemento (y otros elementos mĂ¡s en dispositivos sincronizados)}other{# elementos (y otros elementos mĂ¡s en dispositivos sincronizados)}}</translation>
<translation id="3041612393474885105">Datos del certificado</translation>
<translation id="3063697135517575841">Chrome no ha podido confirmar tu tarjeta en este momento. Vuelve a intentarlo mĂ¡s tarde.</translation>
<translation id="3093245981617870298">No tienes conexiĂ³n.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Los mĂ¡s recientes</translation>
<translation id="3207960819495026254">Añadido a marcadores</translation>
-<translation id="3225919329040284222">El servidor ha mostrado un certificado que no coincide con lo que se esperaba. Algunos sitios web tienen un alto nivel de seguridad para garantizar tu protecciĂ³n y esperan ciertas caracterĂ­sticas de los certificados.</translation>
<translation id="3226128629678568754">Pulsa el botĂ³n de actualizaciĂ³n de pĂ¡gina para que se vuelvan a enviar los datos necesarios para cargar la pĂ¡gina.</translation>
<translation id="3228969707346345236">La traducciĂ³n no ha podido realizarse correctamente porque la pĂ¡gina ya estĂ¡ en <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Introduce el cĂ³digo CVC de la tarjeta <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Añadir esta pĂ¡gina a marcadores</translation>
<translation id="3270847123878663523">&amp;Deshacer reorganizaciĂ³n</translation>
<translation id="3286538390144397061">Reiniciar ahora</translation>
+<translation id="3303855915957856445">No se han encontrado resultados de bĂºsqueda</translation>
<translation id="3305707030755673451">Tus datos se cifraron con tu frase de contraseña de sincronizaciĂ³n el <ph name="TIME" />. IntrodĂºcela para iniciar la sincronizaciĂ³n.</translation>
<translation id="333371639341676808">Evita que esta pĂ¡gina cree cuadros de diĂ¡logo adicionales.</translation>
+<translation id="3338095232262050444">Es seguro</translation>
<translation id="3340978935015468852">configuraciĂ³n</translation>
<translation id="3345135638360864351">No se ha podido enviar la solicitud de acceso a este sitio a <ph name="NAME" />. Vuelve a intentarlo.</translation>
<translation id="3355823806454867987">Cambiar la configuraciĂ³n de proxy...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Intervalo de comprobaciĂ³n:</translation>
<translation id="3462200631372590220">Ocultar opciones avanzadas</translation>
<translation id="3479539252931486093">¿No te lo esperabas? <ph name="BEGIN_LINK" />NotifĂ­canoslo<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Ahora no</translation>
<translation id="348000606199325318">ID de bloqueo <ph name="CRASH_LOCAL_ID" /> (ID de servidor: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">No hemos podido contactar con tu padre/madre/tutor. Vuelve a intentarlo.</translation>
<translation id="3527085408025491307">Carpeta</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Utilizar contraseña para:</translation>
<translation id="3549644494707163724">Cifrar todos los datos sincronizados con tu propia frase de contraseña de sincronizaciĂ³n</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> mĂ¡s...</translation>
+<translation id="3555561725129903880">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad procede de <ph name="DOMAIN2" />. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">La conexiĂ³n no es privada</translation>
<translation id="3583757800736429874">&amp;Rehacer movimiento</translation>
<translation id="3586931643579894722">Ocultar detalles</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Mostrar valor</translation>
<translation id="3630155396527302611">Si ya estĂ¡ incluido como programa autorizado para acceder a la red,
elimínalo de la lista y vuelve a añadirlo.</translation>
+<translation id="3638794133396384728">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad ha caducado. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. En el reloj de tu ordenador consta que son las <ph name="CURRENT_TIME" />. ¿Es correcto? Si no lo es, corrige el reloj del sistema y, a continuaciĂ³n, actualiza esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">Estas funciones experimentales pueden cambiar, dejar de funcionar o desaparecer en cualquier momento. No ofrecemos ningĂºn tipo de garantĂ­a de lo que pueda ocurrir si se habilita alguna de estas funciones experimentales, y es posible que el navegador se bloquee repentinamente. Bromas aparte, ten en cuenta que el navegador puede eliminar todos tus datos y que tu seguridad y tu privacidad se podrĂ­an ver comprometidas de forma inesperada. Cualquier experimento que habilites se habilitarĂ¡ para todos los usuarios del navegador, asĂ­ que te recomendamos que actĂºes con precauciĂ³n.</translation>
<translation id="3650584904733503804">ValidaciĂ³n correcta</translation>
<translation id="3655670868607891010">Si este mensaje aparece con frecuencia, prueba a solucionarlo con estas <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">RevisiĂ³n</translation>
+<translation id="3678029195006412963">No se ha podido firmar la solicitud</translation>
<translation id="3681007416295224113">Datos del certificado</translation>
<translation id="3693415264595406141">Contraseña:</translation>
+<translation id="3696411085566228381">ninguno</translation>
<translation id="3700528541715530410">Parece que no tienes permiso para acceder a esta pĂ¡gina.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Cargando...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Activar los datos mĂ³viles o la conexiĂ³n Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Comprobar el proxy, el cortafuegos y la configuraciĂ³n de DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Enlace copiado</translation>
-<translation id="3744899669254331632">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web ha enviado credenciales codificadas que Chromium no puede procesar. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta pĂ¡gina funcione mĂ¡s tarde.</translation>
<translation id="375403751935624634">Se ha producido un error de traducciĂ³n debido a un problema con el servidor.</translation>
<translation id="3759461132968374835">No se ha notificado ningĂºn fallo recientemente. Los fallos que se hayan producido cuando la funciĂ³n de notificaciĂ³n de fallos estaba inhabilitada no aparecerĂ¡n en esta pĂ¡gina.</translation>
<translation id="3788090790273268753">El certificado de este sitio web vence en 2016 y la cadena de certificados incluye un certificado firmado con SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Identificador de dispositivo en conflicto</translation>
<translation id="3885155851504623709">Parroquia</translation>
<translation id="3901925938762663762">La tarjeta ha caducado</translation>
+<translation id="3910267023907260648">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado firmado con un algoritmo de firma no seguro. Una posible causa de este problema es que se hayan falsificado las credenciales de seguridad presentadas por el servidor y que hayas accedido a la pĂ¡gina de un atacante en lugar de establecer conexiĂ³n con el servidor en cuestiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; supuestamente, su certificado de seguridad es vĂ¡lido a partir de mañana. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" />}other{Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; supuestamente, su certificado de seguridad es vĂ¡lido dentro de # dĂ­as. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">Se ha producido un error al cargar el documento PDF.</translation>
<translation id="3963721102035795474">Modo de lectura</translation>
+<translation id="397105322502079400">Calculando...</translation>
<translation id="3973234410852337861">La pĂ¡gina <ph name="HOST_NAME" /> estĂ¡ bloqueada</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{ 1 pĂ¡gina web cercana}other{ # pĂ¡ginas web cercanas}}</translation>
<translation id="4021036232240155012">DNS es el servicio de red que permite traducir el nombre de un sitio web a su direcciĂ³n de Internet.</translation>
<translation id="4030383055268325496">&amp;Deshacer acciĂ³n de añadir</translation>
-<translation id="4032534284272647190">Se ha denegado el acceso a <ph name="URL" /></translation>
<translation id="404928562651467259">ADVERTENCIA</translation>
<translation id="4058922952496707368">Clave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">El cliente y el servidor no son compatibles con la misma versiĂ³n de protocolo SSL o de cifrado.</translation>
<translation id="4079302484614802869">Se ha configurado el proxy para que use una URL de secuencia de comandos .pac, en lugar de servidores proxy fijos.</translation>
<translation id="4103249731201008433">El nĂºmero de serie del dispositivo no es vĂ¡lido.</translation>
<translation id="4103763322291513355">Accede a la pĂ¡gina &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver la lista de URLs no admitidas y otras polĂ­ticas establecidas por el administrador del sistema.</translation>
+<translation id="4110615724604346410">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad contiene errores. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">No se admite el alcance de la polĂ­tica.</translation>
+<translation id="4118212371799607889">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; Chromium no confĂ­a en su certificado de seguridad. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{Uno mĂ¡s}other{# mĂ¡s}}</translation>
<translation id="4130226655945681476">Comprobar los cables de red, el mĂ³dem y el router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">¿Quieres que Chromium guarde esta tarjeta?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Inhabilitado</translation>
<translation id="4196861286325780578">&amp;Rehacer movimiento</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Comprobar la configuraciĂ³n del cortafuegos y del antivirus<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{ninguna}=1{Una aplicaciĂ³n ($1)}=2{Dos aplicaciones ($1, $2)}other{# aplicaciones ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">La pĂ¡gina no responde o se cierra</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Prueba a ejecutar DiagnĂ³sticos de red<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">No</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(NingĂºn nombre de usuario)</translation>
<translation id="4300246636397505754">Sugerencias de padres</translation>
<translation id="4304224509867189079">Iniciar sesiĂ³n</translation>
+<translation id="432290197980158659">El servidor ha mostrado un certificado que no coincide con lo que se esperaba. Algunos sitios web tienen un alto nivel de seguridad para garantizar tu protecciĂ³n y esperan ciertas caracterĂ­sticas de los certificados. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">Error al buscar el artĂ­culo</translation>
+<translation id="4331708818696583467">No es seguro</translation>
<translation id="4372948949327679948">Se esperaba un valor <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">Has intentado acceder a <ph name="DOMAIN" />, pero el emisor ha revocado el certificado mostrado por el servidor, lo que significa que las credenciales de seguridad presentadas por el servidor no son de confianza. Es posible que hayas accedido a la pĂ¡gina de un atacante.</translation>
<translation id="4381091992796011497">Nombre de usuario:</translation>
<translation id="4394049700291259645">Inhabilitar</translation>
<translation id="4395129973926795186">Del <ph name="START_DATE" /> al <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">resultados de la bĂºsqueda</translation>
-<translation id="4424024547088906515">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, Chrome no confĂ­a en su certificado de seguridad. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> no ha aceptado el certificado de inicio de sesiĂ³n o es posible que no se haya proporcionado ninguno.</translation>
<translation id="443673843213245140">Se ha inhabilitado el uso de un servidor proxy, pero se han especificado ajustes de proxy explĂ­citos.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Este mensaje aparece porque se ha habilitado Google SafeSites.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Detalles</translation>
<translation id="4558551763791394412">Inhabilita las extensiones.</translation>
<translation id="4587425331216688090">¿Eliminar direcciĂ³n de Chrome?</translation>
+<translation id="4589078953350245614">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado no vĂ¡lido. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459">Tu conexiĂ³n con <ph name="DOMAIN" /> estĂ¡ cifrada con un conjunto de cifrado moderno.</translation>
<translation id="4594403342090139922">&amp;Deshacer eliminaciĂ³n</translation>
+<translation id="4627442949885028695">Continuar en otro dispositivo</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Estas viendo la pĂ¡gina de una extensiĂ³n.</translation>
-<translation id="467662567472608290">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, su certificado de seguridad contiene errores. El problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.</translation>
-<translation id="4697214168136963651">Se ha bloqueado la pĂ¡gina <ph name="URL" /></translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Se ha interrumpido la conexiĂ³n</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Ejecutar DiagnĂ³sticos de red de Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Plataforma</translation>
<translation id="4744603770635761495">Ruta del ejecutable</translation>
<translation id="4756388243121344051">&amp;Historial</translation>
+<translation id="4759238208242260848">Descargas</translation>
<translation id="4764776831041365478">Es posible que la pĂ¡gina web <ph name="URL" /> estĂ© temporalmente inactiva o que se haya trasladado definitivamente a otra direcciĂ³n.</translation>
<translation id="4771973620359291008">Se ha producido un error desconocido.</translation>
<translation id="4782449893814226250">Has solicitado permiso a tus padres para poder acceder a esta pĂ¡gina.</translation>
<translation id="4800132727771399293">Comprueba la fecha de caducidad y el cĂ³digo CVC, y vuelve a intentarlo</translation>
-<translation id="4807049035289105102">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web ha enviado credenciales codificadas que Google Chrome no puede procesar. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta pĂ¡gina funcione mĂ¡s tarde.</translation>
<translation id="4813512666221746211">Error de red</translation>
<translation id="4816492930507672669">Ajustar a pĂ¡gina</translation>
<translation id="4850886885716139402">Ver</translation>
<translation id="4880827082731008257">Buscar en el historial</translation>
+<translation id="4884656795097055129">Se mostrarĂ¡n mĂ¡s artĂ­culos en el momento adecuado.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> y <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{ y 1 pĂ¡gina web mĂ¡s}other{ y # pĂ¡ginas web mĂ¡s}}</translation>
<translation id="4923417429809017348">Esta pĂ¡gina se ha traducido de un idioma desconocido al <ph name="LANGUAGE_LANGUAGE" />.</translation>
<translation id="4926049483395192435">Se debe especificar un valor.</translation>
<translation id="4930497775425430760">Este mensaje aparece porque uno de tus padres debe aprobar los sitios web nuevos cuando accedas a ellos por primera vez.</translation>
<translation id="495170559598752135">Acciones</translation>
<translation id="4958444002117714549">Expandir lista</translation>
+<translation id="4962322354953122629">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; Chrome no confĂ­a en su certificado de seguridad. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911">¿Traducir del <ph name="ORIGINAL_LANGUAGE" /> al <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Este complemento no es compatible</translation>
<translation id="5002932099480077015">Si se habilita esta opciĂ³n, Chrome guardarĂ¡ una copia de tu tarjeta en este dispositivo para rellenar la informaciĂ³n mĂ¡s rĂ¡pido.</translation>
<translation id="5019198164206649151">El almacĂ©n secundario estĂ¡ en mal estado.</translation>
<translation id="5023310440958281426">Consulta las polĂ­ticas del administrador</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Informacion del Traductor de Google</translation>
<translation id="5040262127954254034">Privacidad</translation>
<translation id="5045550434625856497">Contraseña incorrecta</translation>
+<translation id="5056549851600133418">ArtĂ­culos recomendados para ti</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Comprobar la direcciĂ³n del proxy<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">El certificado del servidor no es vĂ¡lido en este momento.</translation>
<translation id="5089810972385038852">Estado</translation>
-<translation id="5094747076828555589">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, Chromium no confĂ­a en su certificado de seguridad. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.</translation>
<translation id="5095208057601539847">Provincia</translation>
<translation id="5115563688576182185">(64 bits)</translation>
-<translation id="5122371513570456792">Se han encontrado <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />".</translation>
<translation id="5141240743006678641">Cifrar contraseñas sincronizadas con tus credenciales de Google</translation>
<translation id="5145883236150621069">CĂ³digo de error presente en respuesta de la polĂ­tica</translation>
<translation id="5171045022955879922">Busca o escribe una URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Barra de marcadores</translation>
<translation id="5199729219167945352">Experimentos</translation>
<translation id="5251803541071282808">Nube</translation>
+<translation id="5277279256032773186">¿Usas Chrome en el trabajo? Las empresas pueden administrar la configuraciĂ³n de Chrome de sus empleados. MĂ¡s informaciĂ³n</translation>
<translation id="5299298092464848405">Error al analizar la polĂ­tica</translation>
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5308689395849655368">NotificaciĂ³n de fallos inhabilitada</translation>
<translation id="5317780077021120954">Guardar</translation>
<translation id="5327248766486351172">Nombre</translation>
+<translation id="5359637492792381994">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; su certificado de seguridad no es vĂ¡lido en este momento. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Error al almacenar la configuraciĂ³n de la polĂ­tica</translation>
-<translation id="540969355065856584">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, ya que su certificado de seguridad no es vĂ¡lido en este momento. Esto puede deberse a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.</translation>
<translation id="5421136146218899937">Borrar datos de navegaciĂ³n...</translation>
<translation id="5430298929874300616">Eliminar marcador</translation>
<translation id="5431657950005405462">No se ha encontrado tu archivo</translation>
<translation id="5435775191620395718">Mostrando historial de este dispositivo. <ph name="BEGIN_LINK" />MĂ¡s informaciĂ³n<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Las sugerencias de contenido personalizado estĂ¡n actualmente inhabilitadas porque tus datos sincronizados estĂ¡n protegidos con una frase de contraseña personalizada.</translation>
<translation id="5439770059721715174">Error de validaciĂ³n de esquema en "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">No se puede encontrar esta pĂ¡gina (<ph name="HOST_NAME" />)</translation>
<translation id="5455374756549232013">Marca de tiempo de polĂ­tica incorrecta</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">¿Quieres salir de este sitio web?</translation>
<translation id="5629630648637658800">Error al cargar la configuraciĂ³n de la polĂ­tica</translation>
<translation id="5631439013527180824">Token de administraciĂ³n de dispositivos no vĂ¡lido</translation>
-<translation id="5650551054760837876">No se han encontrado resultados de bĂºsqueda.</translation>
<translation id="5677928146339483299">Con bloqueo</translation>
<translation id="5710435578057952990">No se ha verificado la identidad de este sitio web.</translation>
<translation id="5720705177508910913">Usuario actual</translation>
+<translation id="572328651809341494">Pestañas recientes</translation>
<translation id="5784606427469807560">Se ha producido un problema al confirmar tu tarjeta. Comprueba tu conexiĂ³n a Internet y vuelve a intentarlo.</translation>
<translation id="5785756445106461925">AdemĂ¡s, esta pĂ¡gina incluye otros recursos que no son seguros. Otros usuarios pueden acceder a estos recursos mientras estĂ¡n en circulaciĂ³n y un atacante puede modificarlos para cambiar el aspecto de la pĂ¡gina.</translation>
+<translation id="5786044859038896871">¿Quieres rellenar la informaciĂ³n de la tarjeta?</translation>
+<translation id="5803412860119678065">¿Quieres rellenar la informaciĂ³n de <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Tu conexiĂ³n con <ph name="DOMAIN" /> estĂ¡ cifrada con un conjunto de cifrado obsoleto.</translation>
<translation id="5813119285467412249">&amp;Rehacer acciĂ³n de añadir</translation>
+<translation id="5814352347845180253">Es posible que dejes de tener acceso al contenido premium de <ph name="SITE" /> y algunos otros sitios web.</translation>
+<translation id="5843436854350372569">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado que contiene una clave no segura. Es posible que alguien haya descifrado la clave privada y que hayas accedido a la pĂ¡gina de esa persona en lugar de establecer conexiĂ³n con el servidor. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">Este mensaje aparece porque el administrador ha bloqueado este sitio web.</translation>
<translation id="5857090052475505287">Nueva carpeta</translation>
<translation id="5869405914158311789">No se puede acceder a este sitio web</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Sugerencias de padres</translation>
<translation id="59107663811261420">Google Payments no admite este tipo de tarjeta para este comerciante. Selecciona otra.</translation>
<translation id="59174027418879706">Habilitada</translation>
+<translation id="5926846154125914413">Es posible que dejes de tener acceso al contenido premium de algunos sitios web.</translation>
<translation id="5966707198760109579">Semana</translation>
<translation id="5967867314010545767">Eliminar del historial</translation>
<translation id="5975083100439434680">Reducir</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">AutomĂ¡tico</translation>
<translation id="6042308850641462728">MĂ¡s</translation>
<translation id="6060685159320643512">¡AtenciĂ³n! Estos experimentos pueden ser peligrosos</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{ninguna}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Comprueba los cables y reinicia los routers, los mĂ³dems o cualquier otro dispositivo
de red que estés utilizando.</translation>
<translation id="614940544461990577">Prueba a:</translation>
<translation id="6150607114729249911">¡Vaya! Debes pedir permiso a tus padres para poder acceder a esta pĂ¡gina.</translation>
<translation id="6151417162996330722">El certificado del servidor tiene un perĂ­odo de validez demasiado largo.</translation>
-<translation id="6154808779448689242">El token de polĂ­tica devuelto no coincide con el token actual.</translation>
<translation id="6165508094623778733">MĂ¡s informaciĂ³n</translation>
<translation id="6203231073485539293">Comprueba tu conexiĂ³n a Internet</translation>
<translation id="6218753634732582820">¿Quitar direcciĂ³n de Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Prueba a inhabilitar la predicciĂ³n de red</translation>
<translation id="6337534724793800597">Filtrar polĂ­ticas por nombre</translation>
<translation id="6342069812937806050">Ahora</translation>
+<translation id="6345221851280129312">tamaño desconocido</translation>
<translation id="6355080345576803305">AnulaciĂ³n de sesiĂ³n pĂºblica</translation>
<translation id="6358450015545214790">¿Necesitas ayuda?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{Una sugerencia mĂ¡s}other{# sugerencias mĂ¡s}}</translation>
<translation id="6387478394221739770">Si estĂ¡s interesado en probar nuevas e interesantes funciones de Chrome, prueba nuestro canal beta en la pĂ¡gina chrome.com/beta.</translation>
-<translation id="641480858134062906">Se ha producido un error al cargar <ph name="URL" />.</translation>
+<translation id="6389758589412724634">Chromium se ha quedado sin memoria al intentar mostrar esta pĂ¡gina web.</translation>
+<translation id="6416403317709441254">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web ha enviado credenciales codificadas que Chromium no puede procesar. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta pĂ¡gina funcione mĂ¡s tarde. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">No se ha podido comprobar si se ha revocado el certificado.</translation>
<translation id="6433595998831338502">La pĂ¡gina <ph name="HOST_NAME" /> ha rechazado la conexiĂ³n.</translation>
<translation id="6445051938772793705">PaĂ­s</translation>
<translation id="6451458296329894277">Confirmar reenvĂ­o del formulario</translation>
<translation id="6458467102616083041">Se ha ignorado el valor porque se ha establecido una polĂ­tica que inhabilita la bĂºsqueda predeterminada.</translation>
+<translation id="6462969404041126431">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; es posible que su certificado de seguridad se revoque. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">PolĂ­ticas de dispositivos</translation>
<translation id="6489534406876378309">Empezar a subir errores</translation>
<translation id="6529602333819889595">&amp;Rehacer eliminaciĂ³n</translation>
+<translation id="6534179046333460208">Sugerencias de la Web fĂ­sica</translation>
<translation id="6550675742724504774">ConfiguraciĂ³n</translation>
+<translation id="6593753688552673085">menos de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opciones de cifrado</translation>
<translation id="662080504995468778">Seguir aquĂ­</translation>
<translation id="6628463337424475685">BĂºsqueda de <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">No puedes acceder a <ph name="SITE" /> en este momento porque <ph name="BEGIN_LINK" />este certificado se ha revocado<ph name="END_LINK" />. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta pĂ¡gina funcione mĂ¡s tarde.</translation>
<translation id="6644283850729428850">Esta polĂ­tica estĂ¡ obsoleta.</translation>
+<translation id="6652240803263749613">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; el sistema operativo de tu ordenador no confĂ­a en su certificado de seguridad. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">Editar carpeta</translation>
<translation id="6660210980321319655">Notificado automĂ¡ticamente el <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">¿Quitar sugerencia de formulario de Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Introducir tĂ©rmino de bĂºsqueda&gt;</translation>
<translation id="6711464428925977395">Se ha producido un error con el servidor proxy o la direcciĂ³n es incorrecta.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{ninguno}=1{Un elemento}other{# elementos}}</translation>
<translation id="674375294223700098">Error de certificado de servidor desconocido</translation>
<translation id="6753269504797312559">Valor de la polĂ­tica</translation>
<translation id="6757797048963528358">El dispositivo se ha suspendido.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">No se admite el nivel de la polĂ­tica.</translation>
<translation id="6895330447102777224">Tu tarjeta se ha confirmado</translation>
<translation id="6897140037006041989">Agente de usuario</translation>
-<translation id="6903907808598579934">Activar sincronizaciĂ³n</translation>
<translation id="6915804003454593391">Usuario:</translation>
<translation id="6957887021205513506">El certificado del servidor parece ser falso.</translation>
<translation id="6965382102122355670">Aceptar</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Distrito</translation>
<translation id="6973656660372572881">Se especifican tanto servidores proxy fijos como una URL de secuencia de comandos .pac.</translation>
<translation id="6989763994942163495">Mostrar configuraciĂ³n avanzada...</translation>
+<translation id="7000990526846637657">No se han encontrado entradas del historial</translation>
+<translation id="7009986207543992532">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado cuyo perĂ­odo de validez es demasiado largo para que se considere de confianza. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Es posible que en tu cuenta de Google haya otros datos de navegaciĂ³n registrados, que puedes consultar en la pĂ¡gina <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Contraseñas</translation>
-<translation id="7050187094878475250">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado cuyo perĂ­odo de validez es demasiado largo para que se considere de confianza.</translation>
<translation id="7087282848513945231">Condado</translation>
<translation id="7088615885725309056">MĂ¡s antiguos</translation>
<translation id="7090678807593890770">Busca <ph name="LINK" /> en Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Este mensaje aparece porque el administrador debe aprobar los sitios web nuevos cuando accedas a ellos por primera vez.</translation>
<translation id="724975217298816891">Introduce la fecha de caducidad y el cĂ³digo CVC de la tarjeta <ph name="CREDIT_CARD" /> para actualizar sus detalles. Cuando la confirmes, su informaciĂ³n se compartirĂ¡ con este sitio web.</translation>
<translation id="725866823122871198">No se puede establecer una conexiĂ³n privada con <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque la fecha y la hora de tu ordenador (<ph name="DATE_AND_TIME" />) no son correctas.</translation>
-<translation id="7265986070661382626">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web <ph name="BEGIN_LINK" />utiliza la fijaciĂ³n de certificados<ph name="END_LINK" />. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta pĂ¡gina funcione mĂ¡s tarde.</translation>
<translation id="7269802741830436641">Esta pĂ¡gina web tiene un bucle de redireccionamiento</translation>
<translation id="7275334191706090484">Marcadores administrados</translation>
<translation id="7298195798382681320">Recomendadas</translation>
-<translation id="7301833672208172928">Activar sincronizaciĂ³n del historial</translation>
+<translation id="7309308571273880165">Informe sobre fallos registrado el <ph name="CRASH_TIME" /> (el usuario ha solicitado que se suba, pero aĂºn no se ha hecho)</translation>
<translation id="7334320624316649418">&amp;Rehacer reorganizaciĂ³n</translation>
<translation id="733923710415886693">El certificado del servidor no se ha revelado a través de la Transparencia en los Certificados.</translation>
+<translation id="7351800657706554155">No puedes acceder a <ph name="SITE" /> en este momento porque su certificado se ha revocado. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta pĂ¡gina funcione mĂ¡s tarde. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">LĂ­nea de comandos</translation>
<translation id="7372973238305370288">resultado de bĂºsqueda</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">Confirmando tarjeta</translation>
<translation id="7481312909269577407">Adelante</translation>
<translation id="7485870689360869515">No se han encontrado datos.</translation>
+<translation id="7508255263130623398">El ID de dispositivo de polĂ­tica devuelto estĂ¡ vacĂ­o o no coincide con el ID de dispositivo actual</translation>
<translation id="7514365320538308">Descargar</translation>
<translation id="7518003948725431193">No se ha encontrado ninguna pĂ¡gina web para la direcciĂ³n <ph name="URL" />.</translation>
<translation id="7537536606612762813">Obligatoria</translation>
<translation id="7542995811387359312">La opciĂ³n de autocompletado de la tarjeta de crĂ©dito estĂ¡ inhabilitada porque este formulario no utiliza una conexiĂ³n segura.</translation>
<translation id="7549584377607005141">Esta pĂ¡gina web necesita los datos introducidos anteriormente para mostrarse correctamente. Puedes volver a enviar los datos, pero se repetirĂ¡n las acciones que haya realizado la pĂ¡gina.</translation>
<translation id="7554791636758816595">Nueva pestaña</translation>
-<translation id="7567204685887185387">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, su certificado de seguridad podrĂ­a haberse emitido de forma fraudulenta. El problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante haya interceptado la conexiĂ³n.</translation>
<translation id="7568593326407688803">Esta pĂ¡gina estĂ¡ escrita en<ph name="ORIGINAL_LANGUAGE" />¿Quieres traducirla?</translation>
<translation id="7569952961197462199">¿Eliminar tarjeta de crĂ©dito de Chrome?</translation>
<translation id="7578104083680115302">Paga rĂ¡pidamente en aplicaciones y sitios web desde tus dispositivos utilizando las tarjetas que has guardado en Google.</translation>
+<translation id="7588950540487816470">Web fĂ­sica</translation>
<translation id="7592362899630581445">El certificado del servidor incluye un nombre que estĂ¡ fuera de su cobertura.</translation>
<translation id="759889825892636187">La pĂ¡gina <ph name="HOST_NAME" /> no puede procesar esta solicitud ahora.</translation>
<translation id="7600965453749440009">No traducir nunca del <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">¿Quitar tarjeta de crĂ©dito de Chromium?</translation>
<translation id="765676359832457558">Ocultar configuraciĂ³n avanzada...</translation>
<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7667346355482952095">El token de polĂ­tica devuelto estĂ¡ vacĂ­o o no coincide con el token actual</translation>
<translation id="7668654391829183341">Dispositivo desconocido</translation>
<translation id="7674629440242451245">Si estĂ¡s interesado en probar nuevas e interesantes funciones de Chrome, prueba el canal para desarrolladores en la pĂ¡gina chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Acceder a <ph name="SITE" /> (sitio no seguro)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">No, gracias</translation>
<translation id="7805768142964895445">Estado</translation>
<translation id="7813600968533626083">¿Eliminar sugerencia de formulario de Chrome?</translation>
+<translation id="7815407501681723534">Se han encontrado <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> de <ph name="SEARCH_STRING" /></translation>
<translation id="785549533363645510">Ten en cuenta que tus acciones no serĂ¡n totalmente invisibles. El uso del modo incĂ³gnito no te permite ocultar tu actividad de navegaciĂ³n a tu empresa, a tu proveedor de servicios de Internet o a los sitios web que visites.</translation>
<translation id="7887683347370398519">Comprueba el cĂ³digo CVC y vuelve a intentarlo</translation>
<translation id="7894616681410591072">¡Vaya! Necesitas permiso de <ph name="NAME" /> para acceder a esta pĂ¡gina.</translation>
-<translation id="790025292736025802"><ph name="URL" /> no se encuentra</translation>
<translation id="7912024687060120840">En la carpeta:</translation>
<translation id="7920092496846849526">Has solicitado permiso a uno de tus padres para poder acceder a esta pĂ¡gina.</translation>
<translation id="7935318582918952113">Extractor de DOM</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">Sin especificar</translation>
<translation id="8012647001091218357">No hemos podido contactar con tus padres. Vuelve a intentarlo.</translation>
<translation id="8034522405403831421">Esta pĂ¡gina estĂ¡ escrita en <ph name="SOURCE_LANGUAGE" />. ¿Quieres traducirla al <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">No se han encontrado entradas de historial.</translation>
<translation id="8088680233425245692">Se ha producido un error al ver el artĂ­culo.</translation>
+<translation id="8089520772729574115">menos de 1 MB</translation>
<translation id="8091372947890762290">La activaciĂ³n estĂ¡ pendiente en el servidor.</translation>
+<translation id="8129262335948759431">cantidad desconocida</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">No se ha podido encontrar la <ph name="BEGIN_ABBR" />direcciĂ³n DNS<ph name="END_ABBR" /> del servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">El ordenador se ha suspendido.</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">URL de actualizaciĂ³n no vĂ¡lida para la extensiĂ³n <ph name="EXTENSION_ID" />.</translation>
<translation id="8218327578424803826">UbicaciĂ³n asignada:</translation>
<translation id="8225771182978767009">La persona que ha configurado este ordenador ha elegido bloquear este sitio web.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" /> o <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">La pĂ¡gina que buscas ha utilizado la informaciĂ³n que has especificado. Volver a la pĂ¡gina podrĂ­a provocar la repeticiĂ³n de alguna acciĂ³n. ¿Quieres continuar?</translation>
<translation id="8249320324621329438">Ăltima comprobaciĂ³n:</translation>
<translation id="8261506727792406068">Eliminar</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">Barra de marcadores</translation>
<translation id="8363502534493474904">Desactivar el modo aviĂ³n</translation>
<translation id="8364627913115013041">No establecida</translation>
+<translation id="8380941800586852976">Peligroso</translation>
<translation id="8412145213513410671">Fallos (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Debes introducir la misma frase de contraseña dos veces.</translation>
<translation id="8428213095426709021">Ajustes</translation>
+<translation id="8433057134996913067">Con esta opciĂ³n, tu sesiĂ³n se cerrarĂ¡ en la mayorĂ­a de sitios web.</translation>
<translation id="8437238597147034694">&amp;Deshacer movimiento</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{Una tarjeta de crédito}other{# tarjetas de crédito}}</translation>
+<translation id="8483780878231876732">Inicia sesiĂ³n en Chrome para utilizar tarjetas de tu cuenta de Google</translation>
<translation id="8488350697529856933">Aplicable a</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ha tardado demasiado tiempo en responder.</translation>
+<translation id="852346902619691059">Este servidor no ha podido demostrar que es <ph name="DOMAIN" />; el sistema operativo de tu dispositivo no confĂ­a en su certificado de seguridad. Este problema puede deberse a una configuraciĂ³n incorrecta o a que un atacante ha interceptado la conexiĂ³n. <ph name="BEGIN_LEARN_MORE_LINK" />MĂ¡s informaciĂ³n<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Google Payments no admite este tipo de tarjeta. Selecciona otra.</translation>
<translation id="8550022383519221471">El servicio de sincronizaciĂ³n no estĂ¡ disponible en tu dominio.</translation>
<translation id="8553075262323480129">La traducciĂ³n no se ha realizado correctamente porque no se ha podido determinar el idioma de la pĂ¡gina.</translation>
@@ -633,15 +675,12 @@
<translation id="8647750283161643317">Restablecer todo a su estado predeterminado</translation>
<translation id="8680787084697685621">La informaciĂ³n de inicio de sesiĂ³n no estĂ¡ actualizada.</translation>
<translation id="8703575177326907206">Tu conexiĂ³n a <ph name="DOMAIN" /> no estĂ¡ cifrada.</translation>
-<translation id="8713130696108419660">Firma inicial incorrecta</translation>
<translation id="8725066075913043281">Volver a intentarlo</translation>
<translation id="8728672262656704056">Has iniciado una sesiĂ³n de incĂ³gnito</translation>
<translation id="8730621377337864115">Listo</translation>
<translation id="8738058698779197622">Para establecer una conexiĂ³n segura, tu reloj debe estar correctamente configurado. Esto se debe a que los certificados utilizados por los sitios web para identificarse son solo vĂ¡lidos durante perĂ­odos especĂ­ficos de tiempo. Dado que la hora de tu dispositivo no es correcta, Chromium no puede verificar estos certificados.</translation>
<translation id="8740359287975076522">No se ha podido encontrar la &lt;abbr id="dnsDefinition"&gt;direcciĂ³n DNS&lt;/abbr&gt; de la pĂ¡gina <ph name="HOST_NAME" />. Se estĂ¡ diagnosticando el problema.</translation>
-<translation id="8741995161408053644">Es posible que tu cuenta de Google tenga otras formas del historial de navegaciĂ³n en la pĂ¡gina <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Rehacer eliminaciĂ³n</translation>
-<translation id="8790687370365610530">Para obtener contenido personalizado sugerido por Google, activa la sincronizaciĂ³n del historial.</translation>
<translation id="8798099450830957504">Predeterminado</translation>
<translation id="8804164990146287819">PolĂ­tica de Privacidad</translation>
<translation id="8820817407110198400">Marcadores</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">El certificado del servidor ha caducado.</translation>
<translation id="8987927404178983737">Mes</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">El servidor ha mostrado un certificado que no se ha hecho pĂºblico mediante la PolĂ­tica de Transparencia en los Certificados. Este requisito se aplica a algunos certificados para garantizar que son de confianza y ofrecer protecciĂ³n contra los atacantes.</translation>
<translation id="9001074447101275817">El proxy <ph name="DOMAIN" /> requiere un nombre de usuario y una contraseña.</translation>
<translation id="901974403500617787">Las opciones que se aplican a todo el sistema solo las puede establecer el propietario: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Esta pĂ¡gina se ha traducido al <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Utilizar un servicio de predicciones para que las pĂ¡ginas se carguen mĂ¡s rĂ¡pido</translation>
<translation id="9039213469156557790">AdemĂ¡s, esta pĂ¡gina incluye otros recursos que no son seguros. Otros usuarios pueden acceder a estos recursos mientras estĂ¡n en circulaciĂ³n y un atacante puede modificarlos para cambiar el comportamiento de la pĂ¡gina.</translation>
-<translation id="9049981332609050619">Has intentado acceder a <ph name="DOMAIN" />, pero el servidor ha presentado un certificado no vĂ¡lido.</translation>
<translation id="9050666287014529139">Frase de contraseña</translation>
<translation id="9065203028668620118">Editar</translation>
<translation id="9092364396508701805">La pĂ¡gina <ph name="HOST_NAME" /> no funciona</translation>
diff --git a/chromium/components/strings/components_strings_et.xtb b/chromium/components/strings/components_strings_et.xtb
index 74095b7948c..17a2e06a5b0 100644
--- a/chromium/components/strings/components_strings_et.xtb
+++ b/chromium/components/strings/components_strings_et.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="et">
+<translation id="1008557486741366299">Mitte praegu</translation>
<translation id="1015730422737071372">Esitage lisateavet</translation>
<translation id="1032854598605920125">Pööra päripäeva</translation>
<translation id="1038842779957582377">tundmatu nimi</translation>
+<translation id="1053591932240354961">Te ei saa saiti <ph name="SITE" /> praegu kĂ¼lastada, kuna see saatis Å¡ifreeritud mandaadi, mida Google Chrome ei saa töödelda. Võrguvead ja -rĂ¼nnakud on tavaliselt ajutised, nii et leht on tõenäoliselt hiljem töökorras. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Võta lisamine tagasi</translation>
<translation id="10614374240317010">Ei ole kunagi salvestatud</translation>
-<translation id="1064422015032085147">Veebilehte hostiv server võib olla Ă¼le koormatud või seda hooldatakse.
- Liigse liikluse tekitamise ja olukorra halvendamise vältimiseks
- on päringud sellele URL-ile ajutiselt keelatud.</translation>
<translation id="106701514854093668">Töölaua järjehoidjad</translation>
<translation id="1080116354587839789">Sobita laiusesse</translation>
+<translation id="1103124106085518534">Valmis</translation>
<translation id="1103523840287552314">Tõlgi alati: <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Kui see on märgitud, salvestab Chrome teie kaardi koopia sellesse seadmesse, et vormi kiiremini täita.</translation>
+<translation id="1111153019813902504">Hiljuti kasutatud järjehoidjad</translation>
<translation id="1113869188872983271">&amp;Võta korrastamine tagasi</translation>
+<translation id="1126551341858583091">Kohaliku salvestusruumi maht on <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Reegli vahemälu töötab probleemideta</translation>
<translation id="113188000913989374"><ph name="SITE" /> Ă¼tleb:</translation>
<translation id="1132774398110320017">Chrome'i automaattäite seaded ...</translation>
-<translation id="1150979032973867961">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, arvuti operatsioonisĂ¼steem ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või rĂ¼ndaja, kes on sekkunud teie Ă¼hendusse.</translation>
<translation id="1152921474424827756">Hankige juurdepääs aadressi <ph name="URL" /> <ph name="BEGIN_LINK" />vahemällu salvestatud koopiale<ph name="END_LINK" /></translation>
<translation id="1158211211994409885">Host <ph name="HOST_NAME" /> sulges ootamatult Ă¼henduse.</translation>
<translation id="1161325031994447685">Ăœhendage uuesti WiFi-ga</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Eemalda</translation>
<translation id="1201402288615127009">Edasi</translation>
<translation id="1201895884277373915">Veel sellelt saidilt</translation>
-<translation id="121201262018556460">Proovisite jõuda saidile <ph name="DOMAIN" />, kuid server esitas nõrka võtit sisaldava sertifikaadi. Võimalik, et rĂ¼ndaja on privaatvõtme lahti murdnud ja tegemist ei pruugi olla oodatud serveriga (võimalik, et suhtlete rĂ¼ndajaga).</translation>
+<translation id="1206967143813997005">Sobimatu algne allkiri</translation>
+<translation id="1209206284964581585">Peida praeguseks</translation>
<translation id="1219129156119358924">SĂ¼steemi turvalisus</translation>
<translation id="1227224963052638717">Tundmatud eeskirjad.</translation>
<translation id="1227633850867390598">Peida väärtus</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Jah</translation>
<translation id="1430915738399379752">Printimine</translation>
<translation id="1442912890475371290">Blokeeriti katse <ph name="BEGIN_LINK" />domeeni <ph name="DOMAIN" /> lehte kĂ¼lastada<ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Te ei saa saiti <ph name="SITE" /> praegu kĂ¼lastada, sest see kasutab sertifikaadi kinnitamist. Võrguvead ja -rĂ¼nnakud on tavaliselt ajutised, nii et leht on tõenäoliselt hiljem töökorras. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Lehe salvestatud (s.t teadaolevalt aegunud) koopia kuvamine.</translation>
<translation id="1519264250979466059">Järgu kuupäev</translation>
<translation id="1549470594296187301">Selle funktsiooni kasutamiseks peab JavaScript olema lubatud.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Võrgu seadistus on sobimatu ja seda ei saa importida.</translation>
<translation id="1644574205037202324">Ajalugu</translation>
<translation id="1645368109819982629">Toetuseta protokoll</translation>
-<translation id="1655462015569774233">{1,plural, =1{Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />, selle turvasertifikaat aegus eile. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. Teie arvuti kell on praegu seatud kuupäevale <ph name="CURRENT_DATE" />. Kas see on õige? Kui ei ole, seadke sĂ¼steemi kell õigeks ja värskendage lehte.}other{Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />, selle turvasertifikaat aegus # päeva tagasi. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. Teie arvuti kell on praegu seatud kuupäevale <ph name="CURRENT_DATE" />. Kas see on õige? Kui ei ole, seadke sĂ¼steemi kell õigeks ja värskendage lehte.}}</translation>
<translation id="1676269943528358898">Sait <ph name="SITE" /> kasutab teie teabe kaitsmiseks tavaliselt krĂ¼pteerimist. Kui Google Chrome pĂ¼Ă¼dis seekord saidiga <ph name="SITE" /> Ă¼hendust luua, tagastas veebisait ebatavalised ja valed mandaadid. See võib juhtuda siis, kui rĂ¼ndaja proovib teeselda, et on sait <ph name="SITE" />, või WiFi sisselogimisekraan on Ă¼henduse katkestanud. Teie teave on endiselt kaitstud, sest Google Chrome peatas Ă¼henduse enne andmevahetust.</translation>
<translation id="168841957122794586">Serveri sertifikaat sisaldab nõrka krĂ¼ptograafilist võtit.</translation>
<translation id="1701955595840307032">Soovitatud sisu hankimine</translation>
-<translation id="1706954506755087368">{1,plural, =1{Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />, selle turvasertifikaat hakkab väidetavalt kehtima homme. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja.}other{Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />, selle turvasertifikaat hakkab väidetavalt kehtima # päeva pärast. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Proovige Ă¼hendust võtta sĂ¼steemiadministraatoriga.</translation>
<translation id="17513872634828108">Avatud vahelehed</translation>
<translation id="1753706481035618306">Lk</translation>
-<translation id="1761412452051366565">Google'i soovitatud isikupärastatud sisu hankimiseks lĂ¼litage sĂ¼nkroonimine sisse.</translation>
-<translation id="1763864636252898013">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, seadme operatsioonisĂ¼steem ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või rĂ¼ndaja, kes on sekkunud teie Ă¼hendusse.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Proovige käitada Windowsi võrgudiagnostika tööriista<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Värskendage sĂ¼nkroonimise parooli.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Teie hiljuti kĂ¼lastatud järjehoidjad kuvatakse siin.</translation>
<translation id="1821930232296380041">Taotlus või selle parameetrid on kehtetud</translation>
<translation id="1838667051080421715">Vaatate veebilehe lähtekoodi.</translation>
<translation id="1871208020102129563">Puhverserver on seatud kasutama fikseeritud puhverservereid, mitte pac-skripti URL-i.</translation>
<translation id="1883255238294161206">Ahenda loend</translation>
<translation id="1898423065542865115">Filtreerimine</translation>
-<translation id="1911837502049945214">Host <ph name="HOST_NAME" /> ei aktsepteerinud teie sisselogimise sertifikaati või see võib olla aegunud.</translation>
<translation id="194030505837763158">Avage <ph name="LINK" /></translation>
<translation id="1962204205936693436">Domeeni <ph name="DOMAIN" /> järjehoidjad</translation>
<translation id="1973335181906896915">Viga jadaks teisendamisel</translation>
<translation id="1974060860693918893">Täpsemad</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{ja veel 1}other{ja veel #}}</translation>
<translation id="2025186561304664664">Puhverserver seadistatakse automaatselt.</translation>
<translation id="2030481566774242610">Kas mõtlesite aadressi <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Näete seda sõnumit, kuna teie vanemad peavad uued saidid esmakordsel kĂ¼lastusel kinnitama.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Kontrollige puhverserverit ja tulemĂ¼Ă¼ri<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Postiindeks</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 soovitus}other{# soovitust}}</translation>
<translation id="2065985942032347596">Vajalik autentimine</translation>
<translation id="2079545284768500474">Võta tagasi</translation>
<translation id="20817612488360358">Kasutamiseks on määratud sĂ¼steemi puhverserveri seaded, kuid määratud on ka konkreetne puhverserveri konfigureerimine.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Muuda järjehoidjat</translation>
<translation id="2166049586286450108">Täielik administraatorijuurdepääs</translation>
<translation id="2166378884831602661">See sait ei saa turvalist Ă¼hendust luua</translation>
-<translation id="2171101176734966184">PĂ¼Ă¼dsite jõuda saidile <ph name="DOMAIN" />, kuid server esitas sertifikaadi, mis on allkirjastatud nõrga allkirjaalgoritmiga. See tähendab, et serveri esitatud turvamandaadid võivad olla võltsitud ning server ei pruugi olla see, mida eeldate (võimalik, et suhtlete rĂ¼ndajaga).</translation>
<translation id="2181821976797666341">Reeglid</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 aadress}other{# aadressi}}</translation>
<translation id="2212735316055980242">Reeglit ei leitud</translation>
<translation id="2213606439339815911">Kirjete toomine ...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> pole saadaval</translation>
<translation id="2230458221926704099">Parandage oma Ă¼hendus <ph name="BEGIN_LINK" />diagnostikarakenduse<ph name="END_LINK" /> abil</translation>
+<translation id="2239100178324503013">Saada kohe</translation>
<translation id="225207911366869382">Väärtus on eeskirjade jaoks aegunud.</translation>
<translation id="2262243747453050782">HTTP viga</translation>
<translation id="2282872951544483773">Kättesaamatud katsetused</translation>
<translation id="2292556288342944218">Teie juurdepääs Internetile on blokeeritud</translation>
<translation id="229702904922032456">Juur- või kesktaseme sertifikaat on aegunud.</translation>
<translation id="230155334948463882">Uus kaart?</translation>
+<translation id="2305919008529760154">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat võib olla väljastatud petturlikul moel. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">Domeen <ph name="DOMAIN" /> nõuab kasutajanime ja parooli.</translation>
+<translation id="2318774815570432836">Te ei saa saiti <ph name="SITE" /> praegu kĂ¼lastada, sest veebisait kasutab HSTS-i. Võrguvead ja -rĂ¼nnakud on tavaliselt ajutised, nii et leht on tõenäoliselt hiljem töökorras. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Ignoreeriti vale järjehoidjat registris <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Muud järjehoidjad</translation>
<translation id="2359808026110333948">Jätka</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" /> talletatud krahhiaruannet ei laaditud Ă¼les</translation>
<translation id="2367567093518048410">Tase</translation>
+<translation id="2371153335857947666">{1,plural, =1{Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat aegus eile. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. Teie arvuti kell on praegu seatud kuupäevale <ph name="CURRENT_DATE" />. Kas see on õige? Kui ei ole, seadke sĂ¼steemi kell õigeks ja värskendage lehte. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.}other{Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat aegus # päeva tagasi. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. Teie arvuti kell on praegu seatud kuupäevale <ph name="CURRENT_DATE" />. Kas see on õige? Kui ei ole, seadke sĂ¼steemi kell õigeks ja värskendage lehte. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Kasutajaliidese alternatiive pole saadaval</translation>
<translation id="2384307209577226199">Ettevõtte vaikeseade</translation>
-<translation id="238526402387145295">Te ei saa saiti <ph name="SITE" /> praegu kĂ¼lastada, sest veebisait <ph name="BEGIN_LINK" />kasutab HSTS-i<ph name="END_LINK" />. Võrguvead ja -rĂ¼nnakud on tavaliselt ajutised, nii et leht tõenäoliselt hiljem töötab.</translation>
<translation id="2386255080630008482">Serveri sertifikaat on tĂ¼histatud.</translation>
<translation id="2392959068659972793">Kuva reeglid, mille väärtusi pole määratud</translation>
<translation id="2396249848217231973">&amp;Võta kustutamine tagasi</translation>
-<translation id="2413528052993050574">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, selle turvasertifikaat võib olla tĂ¼histatud. Selle põhjuseks võib olla vale seadistus või rĂ¼ndaja, kes on sekkunud teie Ă¼hendusse.</translation>
<translation id="2455981314101692989">See veebileht on keelanud automaatse täitmise selle vormi puhul.</translation>
+<translation id="2463739503403862330">Täida</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Võrgudiagnostika käitamine<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Kehtetu otsingu URL.</translation>
<translation id="2491120439723279231">Serveri sertifikaat sisaldab vigu.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Esita</translation>
<translation id="2674170444375937751">Olete kindel, et soovite need lehekĂ¼ljed oma ajaloost kustutada?</translation>
<translation id="2677748264148917807">Lahku</translation>
+<translation id="269990154133806163">Server esitas sertifikaadi, mida ei ole sertifikaadi läbipaistvuse reegli kohaselt avalikustatud. See on teatud sertifikaatide puhul nõutav, et need oleksid usaldusväärsed ja kaitseksid rĂ¼ndajate eest. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Väärtus ei vasta vormingule.</translation>
<translation id="2704951214193499422">Chromium ei saanud praegu teie kaarti kinnitada. Proovige hiljem uuesti.</translation>
<translation id="2705137772291741111">Selle saidi (vahemällu) salvestatud koopia oli loetamatu.</translation>
<translation id="2709516037105925701">Automaatne täitmine</translation>
+<translation id="2712118517637785082">PĂ¼Ă¼dsite jõuda domeenile <ph name="DOMAIN" />, kuid sertifikaadi väljaandja on serveri esitatud sertifikaadi tĂ¼histanud. See tähendab, et serveri esitatud turvamandaate ei tohi mingil juhul usaldada. Võimalik, et suhtlete rĂ¼ndajaga. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">KĂ¼si luba</translation>
<translation id="2721148159707890343">Taotlus õnnestus</translation>
<translation id="2728127805433021124">Serveri sertifikaat on allkirjastatud nõrga allkirjaalgoritmiga.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Aadressi- ja otsinguriba</translation>
<translation id="2826760142808435982">Ăœhendus on krĂ¼ptitud ja autenditud Ă¼ksusega <ph name="CIPHER" /> ning kasutab peamise vahetusmehhanismina Ă¼ksust <ph name="KX" />.</translation>
<translation id="2835170189407361413">TĂ¼hjenda vorm</translation>
-<translation id="2837049386027881519">Ăœhenduse loomist tuli korrata TLS- või SSL-protokolli vanema versiooniga. See tähendab tavaliselt seda, et serveri tarkvara on väga vana ja sellel võib olla muid turvaprobleeme.</translation>
<translation id="284702764277384724">Hosti <ph name="HOST_NAME" /> serveri sertifikaat näib olevat võltsing.</translation>
<translation id="2889159643044928134">Ă„ra laadi uuesti</translation>
-<translation id="2896499918916051536">Seda pistikprogrammi ei toetata.</translation>
+<translation id="2900469785430194048">Google Chrome'il pole selle veebilehe kuvamiseks piisavalt mälu.</translation>
<translation id="2909946352844186028">Tuvastati võrgumuudatus.</translation>
-<translation id="2915500479781995473">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />; selle turvasertifikaat on aegunud. Selle põhjuseks võib olla vale seadistus või rĂ¼ndaja, kes on sekkunud teie Ă¼hendusse. Teie arvuti kell on praegu <ph name="CURRENT_TIME" />. Kas see on õige? Kui see pole õige, korrigeerige sĂ¼steemi kellaaega ja värskendage lehte.</translation>
<translation id="2922350208395188000">Serveri sertifikaati ei saa kontrollida.</translation>
-<translation id="2941952326391522266">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, selle turvasertifikaati pärineb domeenilt <ph name="DOMAIN2" />. Selle põhjuseks võib olla vale seadistus või rĂ¼ndaja, kes on sekkunud teie Ă¼hendusse.</translation>
<translation id="2948083400971632585">Seadete lehel saate keelata kõik Ă¼henduse jaoks konfigureeritud puhverserverid.</translation>
<translation id="2955913368246107853">Sule leiuriba</translation>
<translation id="2958431318199492670">Võrgu seadistus ei vasta ONC standardile. On võimalik, et seadistuse mõnd osa ei saa importida.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Reegli tĂ¼Ă¼p on vale</translation>
<translation id="3032412215588512954">Kas soovite selle saidi uuesti laadida?</translation>
<translation id="3037605927509011580">Ups, ebaõnn!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{vähemalt 1 Ă¼ksus sĂ¼nkroonitud seadmetes}=1{1 Ă¼ksus (ja rohkem sĂ¼nkroonitud seadmetes)}other{# Ă¼ksust (ja rohkem sĂ¼nkroonitud seadmetes)}}</translation>
<translation id="3041612393474885105">Sertifikaadi andmed</translation>
<translation id="3063697135517575841">Chrome ei saanud praegu teie kaarti kinnitada. Proovige hiljem uuesti.</translation>
<translation id="3093245981617870298">Olete võrguĂ¼henduseta.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Kõige uuemad</translation>
<translation id="3207960819495026254">Järjehoidjatesse lisatud</translation>
-<translation id="3225919329040284222">Serveri esitatud sertifikaat ei vasta sisseehitatud ootustele. Ootused on teie kaitsmiseks kaasatud kindlate kõrge turvalisusega veebisaitide jaoks.</translation>
<translation id="3226128629678568754">Lehe laadimiseks vajalike andmete uuesti esitamiseks vajutage uuesti laadimise nuppu.</translation>
<translation id="3228969707346345236">Tõlkimine nurjus, kuna lehe keel on juba <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Krediitkaardi <ph name="CREDIT_CARD" /> CVC sisestamine</translation>
<translation id="3254409185687681395">Lisa see lehekĂ¼lg järjehoidjatesse</translation>
<translation id="3270847123878663523">&amp;Võta korrastamine tagasi</translation>
<translation id="3286538390144397061">Taaskäivitada kohe</translation>
+<translation id="3303855915957856445">Otsingutulemusi ei leitud</translation>
<translation id="3305707030755673451">Teie andmed krĂ¼pteeriti <ph name="TIME" /> teie sĂ¼nkroonimisparooliga. Sisestage see sĂ¼nkroonimise alustamiseks.</translation>
<translation id="333371639341676808">Keela sellel lehekĂ¼ljel lisadialoogide loomine.</translation>
+<translation id="3338095232262050444">Turvaline</translation>
<translation id="3340978935015468852">seaded</translation>
<translation id="3345135638360864351">Saidi kĂ¼lastamise taotlust ei õnnestunud saata kontaktile <ph name="NAME" />. Proovige uuesti.</translation>
<translation id="3355823806454867987">Muuda puhverserveri seadeid ...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Hankimise intervall:</translation>
<translation id="3462200631372590220">Peida täpsemad Ă¼ksikasjad</translation>
<translation id="3479539252931486093">Kas see oli ootamatu? <ph name="BEGIN_LINK" />Andke meile sellest teada<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Mitte praegu</translation>
<translation id="348000606199325318">Krahhi ID <ph name="CRASH_LOCAL_ID" /> (serveri ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Teie vanemaga ei õnnestunud praegu Ă¼hendust võtta. Proovige hiljem uuesti.</translation>
<translation id="3527085408025491307">Kaust</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Kasuta parooli:</translation>
<translation id="3549644494707163724">KrĂ¼pteerige kõik sĂ¼nkroonitud andmed oma sĂ¼nkroonimise parooliga</translation>
<translation id="3549761410225185768">Veel <ph name="NUM_TABS_MORE" /> ...</translation>
+<translation id="3555561725129903880">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />. Selle turvasertifikaat pärineb domeenilt <ph name="DOMAIN2" />. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Teie Ă¼hendus ei ole privaatne</translation>
<translation id="3583757800736429874">&amp;Teisalda uuesti</translation>
<translation id="3586931643579894722">Peida Ă¼ksikasjad</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Kuva väärtused</translation>
<translation id="3630155396527302611">Kui see on juba loendis kui programm, millele on lubatud võrgujuurdepääs, proovige
see loendist eemaldada ja siis uuesti lisada.</translation>
+<translation id="3638794133396384728">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat on aegunud. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. Teie arvuti kell on praegu seatud kuupäevale <ph name="CURRENT_TIME" />. Kas see on õige? Kui ei, seadke sĂ¼steemi kell õigeks ja värskendage lehte. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Need eksperimentaalsed funktsioonid võivad igal ajal muutuda, rikki minna või kaduda. Me ei anna mingeid garantiisid selle kohta, mis juhtub, kui mõne eksperimendi sisse lĂ¼litate. Võimalik on teie brauseri iseeneslik sĂ¼ttimine. Kui tõsiselt rääkida, siis võib brauser kustutada kõik teie andmed või ootamatul viisil võidakse rikkuda teie turvalisust ja privaatsust. Kõik eksperimendid, mis te brauseris lubate, lubatakse brauseri kõigile kasutajatele. Jätkake ettevaatlikult.</translation>
<translation id="3650584904733503804">Valideerimine õnnestus</translation>
<translation id="3655670868607891010">Kui näete seda sageli, proovige järgmist: <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Redaktsioon</translation>
+<translation id="3678029195006412963">Taotlust ei saanud allkirjastada</translation>
<translation id="3681007416295224113">Sertifikaadi andmed</translation>
<translation id="3693415264595406141">Parool:</translation>
+<translation id="3696411085566228381">puudub</translation>
<translation id="3700528541715530410">Vabandust! Paistab, et teil pole luba sellele lehele juurdepääsu hankimiseks.</translation>
<translation id="3704609568417268905"><ph name="TIME" />, <ph name="BOOKMARKED" />, <ph name="TITLE" />, <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Laadimine...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">LĂ¼litage sisse mobiilne andmeside või WiFi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Kontrollige puhverserveri, tulemĂ¼Ă¼ri ja DNS-i seadistust<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Teie kopeeritud link</translation>
-<translation id="3744899669254331632">Te ei saa saiti <ph name="SITE" /> praegu kĂ¼lastada, sest veebisait saatis tagasi arusaamatud mandaadid, mida Chromium ei saa töödelda. Võrguvead ja -rĂ¼nnakud on tavaliselt ajutised, nii et leht tõenäoliselt hiljem töötab.</translation>
<translation id="375403751935624634">Tõlkimine ebaõnnestus serverivea tõttu.</translation>
<translation id="3759461132968374835">Hiljuti teatatud krahhe ei ole. Siin ei ilmu krahhid, mis toimusid siis, kui krahhide aruandlus oli keelatud.</translation>
<translation id="3788090790273268753">Selle saidi sertifikaat aegub 2016. aastal ja sertifikaadiahel sisaldab sertifikaati, mis on allkirjastatud SHA-1-ga.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Seadme identifikaator on konfliktne</translation>
<translation id="3885155851504623709">Vald</translation>
<translation id="3901925938762663762">Kaart on aegunud</translation>
+<translation id="3910267023907260648">PĂ¼Ă¼dsite jõuda domeenile <ph name="DOMAIN" />, kuid server esitas sertifikaadi, mis on allkirjastatud nõrga allkirjaalgoritmiga. See tähendab, et serveri esitatud turvamandaadid võivad olla võltsitud ja tegemist ei pruugi olla oodatud serveriga (võimalik, et suhtlete rĂ¼ndajaga). <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat hakkab väidetavalt kehtima homme. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.}other{Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat hakkab väidetavalt kehtima # päeva pärast. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF-dokumendi laadimine nurjus</translation>
<translation id="3963721102035795474">Lugejarežiim</translation>
+<translation id="397105322502079400">Arvutamine ...</translation>
<translation id="3973234410852337861">Host <ph name="HOST_NAME" /> on blokeeritud</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{Läheduses on 1 veebileht}other{Läheduses on # veebilehte}}</translation>
<translation id="4021036232240155012">DNS on võrguteenus, mis tõlgib veebisaidi nime selle Interneti-aadressiks.</translation>
<translation id="4030383055268325496">&amp;Võta lisamine tagasi</translation>
-<translation id="4032534284272647190">Juurdepääs aadressile <ph name="URL" /> on keelatud.</translation>
<translation id="404928562651467259">HOIATUS</translation>
<translation id="4058922952496707368">Võti â€<ph name="SUBKEY" />â€: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Klient ja server ei toeta tavapärast SSL-protokolli versiooni ega Å¡ifreerimiskomplekti.</translation>
<translation id="4079302484614802869">Puhverserveri konfigureerimine on määratud kasutama pac-skripti URL-i, mitte fikseeritud puhverservereid.</translation>
<translation id="4103249731201008433">Seadme seerianumber on kehtetu</translation>
<translation id="4103763322291513355">KĂ¼lastage saiti &lt;strong&gt;chrome://policy&lt;/strong&gt;, et näha mustas nimekirjas olevate URL-ide loendit ja teisi reegleid, mille on jõustanud teie sĂ¼steemiadministraator.</translation>
+<translation id="4110615724604346410">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat sisaldab vigu. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Reegli ulatust ei toetata.</translation>
+<translation id="4118212371799607889">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Chromium ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{veel 1}other{veel #}}</translation>
<translation id="4130226655945681476">Kontrollige võrgukaableid, modemit ja ruuterit</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Kas soovite, et Chromium salvestaks selle kaardi?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Keelatud</translation>
<translation id="4196861286325780578">&amp;Teisalda uuesti</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Kontrollige tulemĂ¼Ă¼ri ja viirusetõrje seadistusi<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{mitte Ă¼htegi}=1{1 rakendus ($1)}=2{2 rakendust ($1, $2)}other{# rakendust ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Krahhid</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Proovige käitada võrgudiagnostikat<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Ei</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Kasutajanimi puudub)</translation>
<translation id="4300246636397505754">Vanema soovitused</translation>
<translation id="4304224509867189079">Logi sisse</translation>
+<translation id="432290197980158659">Server esitas sertifikaadi, mis ei kattu sisseehitatud ootustega. Ootusi rakendatakse teatud väga turvaliste veebisaitide puhul teie kaitsmiseks. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Artiklit ei leitud</translation>
+<translation id="4331708818696583467">Pole turvaline</translation>
<translation id="4372948949327679948">Oodatud väärtus: <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">PĂ¼Ă¼dsite jõuda saidile <ph name="DOMAIN" />, kuid sertifikaadi väljaandja on serveri esitatud sertifikaadi tagasi võtnud. See tähendab, et serveri esitatud turvamandaate ei tohiks mingil juhul usaldada. Võimalik, et suhtlete rĂ¼ndajaga.</translation>
<translation id="4381091992796011497">Kasutajanimi:</translation>
<translation id="4394049700291259645">Keela</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> kuni <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">otsingutulemused</translation>
-<translation id="4424024547088906515">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, Chrome ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või rĂ¼ndaja, kes on sekkunud teie Ă¼hendusse.</translation>
+<translation id="4432688616882109544">Host <ph name="HOST_NAME" /> ei aktsepteerinud teie sisselogimise sertifikaati või te ei esitanud seda.</translation>
<translation id="443673843213245140">Puhverserveri kasutamine on keelatud, kuid määratud on ka konkreetne puhverserveri konfigureerimine.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Näete seda sõnumit, kuna Google SafeSites on lubatud.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Ăœksikasjad</translation>
<translation id="4558551763791394412">Keelake laiendused.</translation>
<translation id="4587425331216688090">Kas eemaldada Chrome'ist aadress?</translation>
+<translation id="4589078953350245614">PĂ¼Ă¼dsite jõuda domeenile <ph name="DOMAIN" />, ent server esitas kehtetu sertifikaadi. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Teie Ă¼hendus domeeniga <ph name="DOMAIN" /> on krĂ¼pteeritud tänapäevase Å¡ifreerimiskomplektiga.</translation>
<translation id="4594403342090139922">&amp;Võta kustutamine tagasi</translation>
+<translation id="4627442949885028695">Jätkake sealt, kus muus seadmes pooleli jäite</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Vaatate laienduste lehte.</translation>
-<translation id="467662567472608290">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, selle turvasertifikaat sisaldab vigu. Selle põhjuseks võib olla vale seadistus või rĂ¼ndaja, kes on sekkunud teie Ă¼hendusse.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> oli blokeeritud</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Teie Ă¼hendus katkes</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windowsi võrgudiagnostika käitamine<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Platvorm</translation>
<translation id="4744603770635761495">Täitmistee</translation>
<translation id="4756388243121344051">&amp;Ajalugu</translation>
+<translation id="4759238208242260848">Allalaadimised</translation>
<translation id="4764776831041365478">Veebileht aadressil <ph name="URL" /> võib olla ajutiselt maas või jäädavalt uuele veebiaadressile teisaldatud.</translation>
<translation id="4771973620359291008">Tekkis tundmatu viga.</translation>
<translation id="4782449893814226250">KĂ¼sisite oma vanemalt, kas võite seda lehte kĂ¼lastada.</translation>
<translation id="4800132727771399293">Kontrollige aegumiskuupäeva ja CVC-d ning proovige uuesti</translation>
-<translation id="4807049035289105102">Te ei saa saiti <ph name="SITE" /> praegu kĂ¼lastada, sest veebisait saatis tagasi arusaamatud mandaadid, mida Google Chrome ei saa töödelda. Võrguvead ja -rĂ¼nnakud on tavaliselt ajutised, nii et leht tõenäoliselt hiljem töötab.</translation>
<translation id="4813512666221746211">Võrgu viga</translation>
<translation id="4816492930507672669">Sobita lehele</translation>
<translation id="4850886885716139402">Kuva</translation>
<translation id="4880827082731008257">Otsi ajaloost</translation>
+<translation id="4884656795097055129">Sobival ajal kuvatakse rohkem artikleid.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{ja veel 1 veebileht}other{ja veel # veebilehte}}</translation>
<translation id="4923417429809017348">Leht on tõlgitud teadmata keelest <ph name="LANGUAGE_LANGUAGE" /> keelde</translation>
<translation id="4926049483395192435">Tuleb määrata.</translation>
<translation id="4930497775425430760">Näete seda sõnumit, kuna teie vanem peab uued saidid esmakordsel kĂ¼lastusel kinnitama.</translation>
<translation id="495170559598752135">Toimingud</translation>
<translation id="4958444002117714549">Laienda loendit</translation>
+<translation id="4962322354953122629">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Chrome ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Kas tõlkida <ph name="ORIGINAL_LANGUAGE" /> keelest <ph name="TARGET_LANGUAGE" /> keelde?</translation>
+<translation id="4989809363548539747">Seda pistikprogrammi ei toetata</translation>
<translation id="5002932099480077015">Kui see on lubatud, salvestab Chrome teie kaardi koopia vormide kiiremini täitmiseks sellesse seadmesse.</translation>
<translation id="5019198164206649151">Varusalves esineb probleeme</translation>
<translation id="5023310440958281426">Tutvuge administraatori reeglitega</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Teave Google'i tõlke kohta</translation>
<translation id="5040262127954254034">Privaatsus</translation>
<translation id="5045550434625856497">Vale salasõna</translation>
+<translation id="5056549851600133418">Teile soovitatud artiklid</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Kontrollige puhverserveri aadressi<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Serveri sertifikaat pole praegu kehtiv.</translation>
<translation id="5089810972385038852">Osariik</translation>
-<translation id="5094747076828555589">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, Chromium ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või rĂ¼ndaja, kes on sekkunud teie Ă¼hendusse.</translation>
<translation id="5095208057601539847">Provints</translation>
<translation id="5115563688576182185">(64-bitine)</translation>
-<translation id="5122371513570456792">Otsingule â€<ph name="SEARCH_STRING" />†saadi tulemuseks <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" />.</translation>
<translation id="5141240743006678641">KrĂ¼pteerige sĂ¼nkroonitud paroolid oma Google'i mandaadiga</translation>
<translation id="5145883236150621069">Reegli vastuses sisaldus veakood</translation>
<translation id="5171045022955879922">Otsige või sisestage URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Järjehoidjariba</translation>
<translation id="5199729219167945352">Katsed</translation>
<translation id="5251803541071282808">Pilv</translation>
+<translation id="5277279256032773186">Kas kasutate Chrome'i tööl? Ettevõtted võivad hallata töötajate Chrome'i seadeid. Lisateave</translation>
<translation id="5299298092464848405">Reegli sõelumisel ilmnes viga</translation>
<translation id="5300589172476337783">Kuva</translation>
<translation id="5308689395849655368">Krahhide aruandlus on keelatud.</translation>
<translation id="5317780077021120954">Salvesta</translation>
<translation id="5327248766486351172">Nimi</translation>
+<translation id="5359637492792381994">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat on praegu kehtetu. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Reegli seadete talletamine ebaõnnestus</translation>
-<translation id="540969355065856584">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />; selle turvasertifikaat pole praegu kehtiv. Selle põhjuseks võib olla vale seadistus või rĂ¼ndaja, kes on sekkunud teie Ă¼hendusse.</translation>
<translation id="5421136146218899937">Sirvimisandmete kustutamine ...</translation>
<translation id="5430298929874300616">Järjehoidja eemaldamine</translation>
<translation id="5431657950005405462">Teie faili ei leitud</translation>
<translation id="5435775191620395718">Kuvatakse ajalugu sellest seadmest. <ph name="BEGIN_LINK" />Lisateave<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Isikupärastatud sisu soovitused on praegu keelatud, kuna teie sĂ¼nkroonitud andmed on kaitstud kohandatud parooliga.</translation>
<translation id="5439770059721715174">Skeemi valideerimise viga asukohas â€<ph name="ERROR_PATH" />â€: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Hosti <ph name="HOST_NAME" /> lehte ei leita</translation>
<translation id="5455374756549232013">Reegli ajatempel on sobimatu</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Kas soovite sellelt saidilt lahkuda?</translation>
<translation id="5629630648637658800">Reegli seadete laadimine ebaõnnestus</translation>
<translation id="5631439013527180824">Seadme halduse luba on kehtetu</translation>
-<translation id="5650551054760837876">Otsingutulemusi ei leitud.</translation>
<translation id="5677928146339483299">Blokeeritud</translation>
<translation id="5710435578057952990">Selle veebisaidi identiteeti pole kinnitanud.</translation>
<translation id="5720705177508910913">Praegune kasutaja</translation>
+<translation id="572328651809341494">Hiljutised vahelehed</translation>
<translation id="5784606427469807560">Kaardi kinnitamisel tekkis probleem. Kontrollige Interneti-Ă¼hendust ja proovige uuesti.</translation>
<translation id="5785756445106461925">Lisaks sisaldab see leht teisi ressursse, mis pole turvalised. Edastamise ajal võivad ressursse vaadata ka teised ja rĂ¼ndajad saavad lehe välimuse muutmiseks ressursse muuta.</translation>
+<translation id="5786044859038896871">Kas soovite sisestada oma kaarditeabe?</translation>
+<translation id="5803412860119678065">Kas soovite sisestada kirje <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Teie Ă¼hendus domeeniga <ph name="DOMAIN" /> on krĂ¼pteeritud aegunud Å¡ifreerimiskomplektiga.</translation>
<translation id="5813119285467412249">&amp;Lisa uuesti</translation>
+<translation id="5814352347845180253">Võite kaotada juurdepääsu saidi <ph name="SITE" /> ja mõnede muude saitide tasulisele sisule.</translation>
+<translation id="5843436854350372569">Proovisite jõuda domeenile <ph name="DOMAIN" />, kuid server esitas nõrka võtit sisaldava sertifikaadi. Võimalik, et rĂ¼ndaja on privaatvõtme lahti murdnud ja tegemist ei pruugi olla oodatud serveriga (võib-olla suhtlete rĂ¼ndajaga). <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Näete seda sõnumit, kuna haldur blokeeris selle saidi.</translation>
<translation id="5857090052475505287">Uus kaust</translation>
<translation id="5869405914158311789">Selle saidiga ei saa Ă¼hendust</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Vanema soovitused</translation>
<translation id="59107663811261420">Google Payments ei toeta selle kaupmehe puhul seda tĂ¼Ă¼pi kaarti. Valige teine kaart.</translation>
<translation id="59174027418879706">Lubatud</translation>
+<translation id="5926846154125914413">Võite kaotada juurdepääsu mõnede saitide tasulisele sisule.</translation>
<translation id="5966707198760109579">Nädal</translation>
<translation id="5967867314010545767">Eemalda ajaloost</translation>
<translation id="5975083100439434680">Suumib välja</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Automaatne</translation>
<translation id="6042308850641462728">Rohkem</translation>
<translation id="6060685159320643512">Ettevaatust, need katsed võivad hammustada.</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{mitte Ă¼htegi}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Kontrollige kaableid ning taaskäivitage kõik ruuterid, modemid ja muud
kasutuses olevad võrguseadmed.</translation>
<translation id="614940544461990577">Proovige järgmist.</translation>
<translation id="6150607114729249911">Vabandust! Peate kĂ¼sima oma vanematelt, kas võite seda lehte kĂ¼lastada.</translation>
<translation id="6151417162996330722">Serveri sertifikaadi kehtivusaeg on liiga pikk.</translation>
-<translation id="6154808779448689242">Tagastatud reegli luba ei kattu praeguse loaga</translation>
<translation id="6165508094623778733">Lisateave</translation>
<translation id="6203231073485539293">Kontrollige Interneti-Ă¼hendust</translation>
<translation id="6218753634732582820">Kas eemaldada Chromiumist aadress?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Proovige keelata võrguprognoos</translation>
<translation id="6337534724793800597">Reeglite filtreerimine nime järgi</translation>
<translation id="6342069812937806050">Ă„sja</translation>
+<translation id="6345221851280129312">tundmatu suurus</translation>
<translation id="6355080345576803305">Avaliku seansi alistamine</translation>
<translation id="6358450015545214790">Mida need tähendavad?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{veel 1 soovitus}other{veel # soovitust}}</translation>
<translation id="6387478394221739770">Kas olete huvitatud Chrome'i uutest lahedatest funktsioonidest? Proovige meie beetakanalit aadressil chrome.com/beta.</translation>
-<translation id="641480858134062906">Aadressilt <ph name="URL" /> laadimine ebaõnnestus</translation>
+<translation id="6389758589412724634">Chromiumil pole selle veebilehe kuvamiseks piisavalt mälu.</translation>
+<translation id="6416403317709441254">Te ei saa saiti <ph name="SITE" /> praegu kĂ¼lastada, sest veebisait saatis Å¡ifreeritud mandaadi, mida Chromium ei saa töödelda. Võrguvead ja -rĂ¼nnakud on tavaliselt ajutised, nii et leht on tõenäoliselt hiljem töökorras. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Ei saa kontrollida sertifikaadi võimalikku tĂ¼histamist.</translation>
<translation id="6433595998831338502">Host <ph name="HOST_NAME" /> keeldus Ă¼hendamast.</translation>
<translation id="6445051938772793705">Riik</translation>
<translation id="6451458296329894277">Kinnita vormi uuestiesitamist</translation>
<translation id="6458467102616083041">Seda eiratakse, kuna vaikeotsing on reegliga keelatud.</translation>
+<translation id="6462969404041126431">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Selle turvasertifikaat on võib-olla tĂ¼histatud. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Seadme reeglid</translation>
<translation id="6489534406876378309">Krahhide Ă¼leslaadimise alustamine</translation>
<translation id="6529602333819889595">&amp;Kustuta uuesti</translation>
+<translation id="6534179046333460208">FĂ¼Ă¼silise veebi soovitused</translation>
<translation id="6550675742724504774">Valikud</translation>
+<translation id="6593753688552673085">vähem kui <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">KrĂ¼pteerimise valikud</translation>
<translation id="662080504995468778">Jää siia</translation>
<translation id="6628463337424475685"><ph name="ENGINE" />'i otsing</translation>
-<translation id="6634865548447745291">Te ei saa saiti <ph name="SITE" /> praegu kĂ¼lastada, sest <ph name="BEGIN_LINK" />see sertifikaat on tĂ¼histatud<ph name="END_LINK" />. Võrguvead ja -rĂ¼nnakud on tavaliselt ajutised, nii et leht tõenäoliselt hiljem töötab.</translation>
<translation id="6644283850729428850">See reegel on aegunud.</translation>
+<translation id="6652240803263749613">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Teie arvuti operatsioonisĂ¼steem ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Kausta muutmine</translation>
<translation id="6660210980321319655">Automaatne teavitamine: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Kas eemaldada Chromiumist vormi soovitus?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Eelmine</translation>
<translation id="6710594484020273272">&lt;Sisestage otsingutermin&gt;</translation>
<translation id="6711464428925977395">Puhverserveriga on midagi valesti või aadress on vale.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{mitte Ă¼htegi}=1{1 Ă¼ksus}other{# Ă¼ksust}}</translation>
<translation id="674375294223700098">Serveri sertifikaadi tundmatu viga.</translation>
<translation id="6753269504797312559">Reegli väärtus</translation>
<translation id="6757797048963528358">Teie seade lĂ¼litus unerežiimile.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Reegli taset ei toetata.</translation>
<translation id="6895330447102777224">Teie kaart on kinnitatud</translation>
<translation id="6897140037006041989">Kasutajaagent</translation>
-<translation id="6903907808598579934">LĂ¼lita sĂ¼nkroonimine sisse</translation>
<translation id="6915804003454593391">Kasutaja:</translation>
<translation id="6957887021205513506">Serveri sertifikaat näib olevat võltsing.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Ringkond</translation>
<translation id="6973656660372572881">Määratud on nii fikseeritud puhverserverid kui ka pac-skriptiga URL.</translation>
<translation id="6989763994942163495">Kuva täpsemad seaded ...</translation>
+<translation id="7000990526846637657">Ajalookirjeid ei leitud</translation>
+<translation id="7009986207543992532">PĂ¼Ă¼dsite jõuda domeenile <ph name="DOMAIN" />, ent server esitas sertifikaadi, mille kehtivusperiood on liiga pikk, et olla usaldusväärne. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">Hiina UnionPay</translation>
+<translation id="7012372675181957985">Aadressil <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> võib teie Google'i kontol olla muus vormis sirvimisajalugu</translation>
<translation id="7029809446516969842">Paroolid</translation>
-<translation id="7050187094878475250">Ăœritasite jõuda domeenile <ph name="DOMAIN" />, kuid server esitas sertifikaadi, mille kehtivusaeg on liiga pikk, et olla usaldusväärne.</translation>
<translation id="7087282848513945231">Maakond</translation>
<translation id="7088615885725309056">Vanemad</translation>
<translation id="7090678807593890770">Sisestage Google'isse otsing <ph name="LINK" /></translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Näete seda sõnumit, kuna teie haldur peab uued saidid esmakordsel kĂ¼lastusel kinnitama.</translation>
<translation id="724975217298816891">Kaardi Ă¼ksikasjade värskendamiseks sisestage krediitkaardi <ph name="CREDIT_CARD" /> aegumiskuupäev ja CVC. Kui selle kinnitate, jagatakse teie kaardi Ă¼ksikasju selle saidiga.</translation>
<translation id="725866823122871198">Privaatset Ă¼hendust ei saa domeeniga <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> luua, kuna arvuti kuupäev ja kellaaeg (<ph name="DATE_AND_TIME" />) on valed.</translation>
-<translation id="7265986070661382626">Te ei saa saiti <ph name="SITE" /> praegu kĂ¼lastada, sest veebisait <ph name="BEGIN_LINK" />kasutab sertifikaadi kinnitamist<ph name="END_LINK" />. Võrguvead ja -rĂ¼nnakud on tavaliselt ajutised, nii et leht tõenäoliselt hiljem töötab.</translation>
<translation id="7269802741830436641">Sellel veebilehel on Ă¼mbersuunamissilmus</translation>
<translation id="7275334191706090484">Hallatud järjehoidjad</translation>
<translation id="7298195798382681320">Soovitatud</translation>
-<translation id="7301833672208172928">LĂ¼lita ajaloo sĂ¼nkroonimine sisse</translation>
+<translation id="7309308571273880165">Krahhiaruanne jäädvustati ajal <ph name="CRASH_TIME" /> (kasutaja taotles Ă¼leslaadimist; pole veel Ă¼les laaditud)</translation>
<translation id="7334320624316649418">&amp;Korrasta uuesti</translation>
<translation id="733923710415886693">Serveri sertifikaati ei avalikustatud sertifikaadi läbipaistvuse reegli kaudu.</translation>
+<translation id="7351800657706554155">Te ei saa saiti <ph name="SITE" /> praegu kĂ¼lastada, sest selle sertifikaat on tĂ¼histatud. Võrguvead ja -rĂ¼nnakud on tavaliselt ajutised, nii et leht on tõenäoliselt hiljem töökorras. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Käsurida</translation>
<translation id="7372973238305370288">otsingutulemus</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="7469372306589899959">Kaarti kinnitatakse</translation>
<translation id="7481312909269577407">Edasta</translation>
<translation id="7485870689360869515">Andmeid ei leitud.</translation>
+<translation id="7508255263130623398">Tagastatud reegli seadme-ID on tĂ¼hi või ei kattu praeguse seadme-ID-ga</translation>
<translation id="7514365320538308">Laadi alla</translation>
<translation id="7518003948725431193">Järgneval veebiaadressil ei olnud Ă¼htegi veebilehte: <ph name="URL" /></translation>
<translation id="7537536606612762813">Kohustuslik</translation>
<translation id="7542995811387359312">Automaatne krediitkaardi täide on keelatud, sest see vorm ei kasuta turvalist Ă¼hendust.</translation>
<translation id="7549584377607005141">See veebileht vajab korralikult kuvamiseks varem sisestatud andmeid. Võite need andmed uuesti saata, kuid seda tehes kordate lehe iga eelnevat toimingut.</translation>
<translation id="7554791636758816595">Uus vaheleht</translation>
-<translation id="7567204685887185387">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, selle turvasertifikaat võib olla väljastatud pettuse teel. Selle põhjuseks võib olla vale seadistus või rĂ¼ndaja, kes on sekkunud teie Ă¼hendusse.</translation>
<translation id="7568593326407688803">See leht on keeles<ph name="ORIGINAL_LANGUAGE" />Kas soovite seda tõlkida?</translation>
<translation id="7569952961197462199">Kas eemaldada Chrome'ist krediitkaart?</translation>
<translation id="7578104083680115302">Google'i salvestatud kaartide abil saate eri seadmetes saitidel ja rakendustes kiirelt maksta.</translation>
+<translation id="7588950540487816470">FĂ¼Ă¼siline veeb</translation>
<translation id="7592362899630581445">Serveri sertifikaat rikub nime piiranguid.</translation>
<translation id="759889825892636187">Host <ph name="HOST_NAME" /> ei saa praegu seda taotlust töödelda.</translation>
<translation id="7600965453749440009">Ära kunagi tõlgi: <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="7637571805876720304">Kas eemaldada Chromiumist krediitkaart?</translation>
<translation id="765676359832457558">Peida täpsemad seaded ...</translation>
<translation id="7658239707568436148">TĂ¼hista</translation>
+<translation id="7667346355482952095">Tagastatud reegli luba on tĂ¼hi või ei kattu praeguse loaga</translation>
<translation id="7668654391829183341">Tundmatu seade</translation>
<translation id="7674629440242451245">Kas olete huvitatud Chrome'i uutest lahedatest funktsioonidest? Proovige meie arenduskanalit aadressil chrome.com/beta.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Edasiliikumine saidile <ph name="SITE" /> (ebaturvaline)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="780301667611848630">Ei, aitäh</translation>
<translation id="7805768142964895445">Olek</translation>
<translation id="7813600968533626083">Kas eemaldada Chrome'ist vormi soovitus?</translation>
+<translation id="7815407501681723534">Otsingule â€<ph name="SEARCH_STRING" />†leiti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" />.</translation>
<translation id="785549533363645510">Te pole siiski nähtamatu. Inkognito režiimi kasutamine ei varja teie sirvimist tööandja, Interneti-teenuse pakkuja ega kĂ¼lastatavate veebisaitide eest.</translation>
<translation id="7887683347370398519">Kontrollige CVC-d ja proovige uuesti</translation>
<translation id="7894616681410591072">Vabandust! Vajate sellele lehele juurdepääsemiseks kasutaja <ph name="NAME" /> antud luba.</translation>
-<translation id="790025292736025802">Aadressi <ph name="URL" /> ei leitud</translation>
<translation id="7912024687060120840">Kaustas:</translation>
<translation id="7920092496846849526">KĂ¼sisite vanemalt, kas võite seda lehte kĂ¼lastada.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="7995512525968007366">Ei ole määratud</translation>
<translation id="8012647001091218357">Teie vanematega ei õnnestunud praegu Ă¼hendust võtta. Proovige hiljem uuesti.</translation>
<translation id="8034522405403831421">Leht on <ph name="SOURCE_LANGUAGE" /> keeles. Kas tõlkida <ph name="TARGET_LANGUAGE" /> keelde?</translation>
-<translation id="8034955203865359138">Ajaloo sisestusi ei leitud.</translation>
<translation id="8088680233425245692">Artikli kuvamine ebaõnnestus.</translation>
+<translation id="8089520772729574115">vähem kui 1 MB</translation>
<translation id="8091372947890762290">Aktiveerimine on serveris ootel</translation>
+<translation id="8129262335948759431">andmemaht on teadmata</translation>
<translation id="8131740175452115882">Kinnita</translation>
<translation id="8134994873729925007">Hosti <ph name="HOST_NAME" /> serveri <ph name="BEGIN_ABBR" />DNS-aadressi<ph name="END_ABBR" /> ei leitud.</translation>
<translation id="8149426793427495338">Teie arvuti lĂ¼litus unerežiimile.</translation>
@@ -604,6 +640,7 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="8201077131113104583">ID-ga â€<ph name="EXTENSION_ID" />†laienduse kehtetu värskendamise URL.</translation>
<translation id="8218327578424803826">Määratud asukoht:</translation>
<translation id="8225771182978767009">Arvuti seadistanud inimene blokeeris selle saidi.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Teie poolt otsitav lehekĂ¼lg kasutas teie sisestatud andmeid. Sellele lehekĂ¼ljele naasmine võib kaasa tuua kõikide sooritatud tegevuste kordamise. Soovite jätkata?</translation>
<translation id="8249320324621329438">Viimati toodud:</translation>
<translation id="8261506727792406068">Kustuta</translation>
@@ -616,12 +653,17 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="8349305172487531364">Järjehoidjariba</translation>
<translation id="8363502534493474904">LĂ¼litage lennukirežiim välja</translation>
<translation id="8364627913115013041">Määramata.</translation>
+<translation id="8380941800586852976">Ohtlik</translation>
<translation id="8412145213513410671">Krahhid (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Peate sisestama sama parooli kaks korda.</translation>
<translation id="8428213095426709021">Seaded</translation>
+<translation id="8433057134996913067">See logib teid välja enamikult veebisaitidelt.</translation>
<translation id="8437238597147034694">&amp;Võta teisaldamine tagasi</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 krediitkaart}other{# krediitkaarti}}</translation>
+<translation id="8483780878231876732">Google'i konto kaartide kasutamiseks logige sisse Chrome'i</translation>
<translation id="8488350697529856933">Kehtib:</translation>
<translation id="8498891568109133222">Hostil <ph name="HOST_NAME" /> kulus vastamiseks liiga kaua aega.</translation>
+<translation id="852346902619691059">Server ei suutnud tõestada, et tegemist on domeeniga <ph name="DOMAIN" />. Teie seadme operatsioonisĂ¼steem ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või teie Ă¼hendust segav rĂ¼ndaja. <ph name="BEGIN_LEARN_MORE_LINK" />Vaadake lisateavet<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Google Payments ei toeta seda tĂ¼Ă¼pi kaarti. Valige teine kaart.</translation>
<translation id="8550022383519221471">SĂ¼nkroonimisteenus ei ole domeeni jaoks saadaval.</translation>
<translation id="8553075262323480129">Tõlkimine nurjus, kuna lehe keelt ei õnnestunud määrata.</translation>
@@ -633,15 +675,12 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="8647750283161643317">Lähtesta kõik vaikeolekusse</translation>
<translation id="8680787084697685621">Konto sisselogimisĂ¼ksikasjad on aegunud.</translation>
<translation id="8703575177326907206">Teie Ă¼hendus <ph name="DOMAIN" />'ga pole krĂ¼ptitud.</translation>
-<translation id="8713130696108419660">Sobimatu esialgne allkiri</translation>
<translation id="8725066075913043281">Proovi uuesti</translation>
<translation id="8728672262656704056">Olete inkognito režiimis</translation>
<translation id="8730621377337864115">Valmis</translation>
<translation id="8738058698779197622">Turvalise Ă¼henduse loomiseks peab kell olema õigesti seadistatud. See on nii, kuna sertifikaadid, mida veebisaidid kasutavad enda tuvastamiseks, kehtivad ainult teatud perioodi jooksul. Kuna teie seadme kell on vale, ei saa Chromium neid sertifikaate kinnitada.</translation>
<translation id="8740359287975076522">Hosti <ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS-aadressi&lt;/abbr&gt; ei leitud. Probleemi diagnoositakse.</translation>
-<translation id="8741995161408053644">Aadressil <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> võib teie Google'i kontol olla muus vormis sirvimisajalugu.</translation>
<translation id="8790007591277257123">&amp;Kustuta uuesti</translation>
-<translation id="8790687370365610530">Google'i soovitatud isikupärastatud sisu hankimiseks lĂ¼litage ajaloo sĂ¼nkroonimine sisse.</translation>
<translation id="8798099450830957504">Vaikimisi</translation>
<translation id="8804164990146287819">Privaatsuseeskirjad</translation>
<translation id="8820817407110198400">Järjehoidjad</translation>
@@ -663,13 +702,11 @@ Inkognito režiim <ph name="SHORTCUT_KEY" /> võib järgmisel korral kasulikuks
<translation id="8971063699422889582">Serveri sertifikaat on aegunud.</translation>
<translation id="8987927404178983737">kuu</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Server esitas sertifikaadi, mida ei ole sertifikaadi läbipaistvuse reegli kohaselt avalikustatud. See on teatud sertifikaatide puhul nõutav, et need oleksid usaldusväärsed ja kaitseksid rĂ¼ndajate eest.</translation>
<translation id="9001074447101275817">Puhverserver <ph name="DOMAIN" /> nõuab kasutajanime ja parooli.</translation>
<translation id="901974403500617787">Kogu sĂ¼steemis kehtivaid märgiseid saab määrata ainult omanik: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">See leht on tõlgitud <ph name="TARGET_LANGUAGE" /> keelde</translation>
<translation id="9038649477754266430">Kasuta lehtede kiiremaks laadimiseks ennustusteenust</translation>
<translation id="9039213469156557790">Lisaks sisaldab see leht teisi ressursse, mis pole turvalised. Edastamise ajal võivad ressursse vaadata ka teised ja rĂ¼ndajad saavad lehe käitumise muutmiseks ressursse muuta.</translation>
-<translation id="9049981332609050619">Proovisite jõuda domeenile <ph name="DOMAIN" />, kuid server esitas kehtetu sertifikaadi.</translation>
<translation id="9050666287014529139">Parool</translation>
<translation id="9065203028668620118">Muuda</translation>
<translation id="9092364396508701805">Hosti <ph name="HOST_NAME" /> leht ei tööta</translation>
diff --git a/chromium/components/strings/components_strings_fa.xtb b/chromium/components/strings/components_strings_fa.xtb
index d97042e11e8..9ab524f9d39 100644
--- a/chromium/components/strings/components_strings_fa.xtb
+++ b/chromium/components/strings/components_strings_fa.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fa">
+<translation id="1008557486741366299">اکنون نه</translation>
<translation id="1015730422737071372">جزئیات بیشتری ارائه دهید</translation>
<translation id="1032854598605920125">چرخش در جهت عقربه‌های ساعت</translation>
<translation id="1038842779957582377">نام ناشناس</translation>
+<translation id="1053591932240354961">â€Ø¯Ø±Ø­Ø§Ù„‌حاضر نمی‌توانید از <ph name="SITE" /> دیدن کنید، زیرا این وب‌سایت اعتبارنامه‌های درهمی ارسال کرده است Ú©Ù‡ Google Chrome نمی‌تواند آن‌ها را پردازش کند. خطاها Ùˆ حمله‌های شبکه معمولاً موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;واگرد اÙزودن</translation>
<translation id="10614374240317010">هرگز ذخیره نمی‌شود</translation>
-<translation id="1064422015032085147">سروری Ú©Ù‡ این صÙحه وب را میزبانی می‌کند ممکن است بیش از حد بار داشته باشد یا تحت سرویس Ùˆ نگهداری باشد.
- برای جلوگیری از ایجاد تراÙیک بیش از حد Ùˆ بدتر شدن وضعیت،
- درخواست‌های ارسالی به این نشانی وب موقتاً رد شده‌اند.</translation>
<translation id="106701514854093668">نشانک‌های دسک‌تاپ</translation>
<translation id="1080116354587839789">متناسب با پهنا</translation>
+<translation id="1103124106085518534">Ùعلاً چیزی وجود ندارد</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> همیشه ترجمه شود</translation>
<translation id="1107591249535594099">â€Ø§Ú¯Ø± علامت زده شود، Chrome یک Ú©Ù¾ÛŒ از این کارت را در دستگاه نگهداری می‌کند تا برای پرکردن Ùرم‌ها از آن استÙاده شود.</translation>
+<translation id="1111153019813902504">نشانک‌های اخیر</translation>
<translation id="1113869188872983271">&amp;واگرد ترتیب‌بندی مجدد</translation>
+<translation id="1126551341858583091">اندازه در Ùضای ذخیره‌سازی محلی <ph name="CRASH_SIZE" /> است.</translation>
<translation id="112840717907525620">حاÙظه پنهان خط‌مشی مورد تأیید است</translation>
<translation id="113188000913989374"><ph name="SITE" /> می‌گوید:</translation>
<translation id="1132774398110320017">â€ØªÙ†Ø¸ÛŒÙ…ات تکمیل خودکار Chrome...</translation>
-<translation id="1150979032973867961">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن مورداعتماد سیستم عامل رایانه شما نیست. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجی اتصال شما را قطع کرده است.</translation>
<translation id="1152921474424827756">دسترسی به یک <ph name="BEGIN_LINK" />نسخه ذخیره شده در حاÙظه پنهان<ph name="END_LINK" /> از <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> به‌طور غیرمنتظره‌ای اتصال را قطع کرد.</translation>
<translation id="1161325031994447685">â€Ø§ØªØµØ§Ù„ مجدد به Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">حذÙ</translation>
<translation id="1201402288615127009">بعدی</translation>
<translation id="1201895884277373915">موارد بیشتر از این سایت</translation>
-<translation id="121201262018556460">شما می‌خواستید به <ph name="DOMAIN" /> دسترسی یابید، اما سرور یک گواهی دارای کلید ضعی٠ارائه داد. یک مهاجم ممکن است کلید خصوصی را تخریب کرده باشد و سرور، همان سروری نباشد که شما انتظار داشتید (ممکن است در حال ارتباط با یک مهاجم باشید).</translation>
+<translation id="1206967143813997005">امضای اولیه نادرست</translation>
+<translation id="1209206284964581585">Ùعلاً پنهان شود</translation>
<translation id="1219129156119358924">سیستم امنیتی</translation>
<translation id="1227224963052638717">خط‌مشی ناشناس.</translation>
<translation id="1227633850867390598">پنهان کردن مقدار</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">بله</translation>
<translation id="1430915738399379752">چاپ</translation>
<translation id="1442912890475371290">تلاش <ph name="BEGIN_LINK" /> برای بازدید از صÙحه‌ای در <ph name="DOMAIN" /><ph name="END_LINK" /> مسدود شد.</translation>
+<translation id="1491663344921578213">درحال‌حاضر نمی‌توانید از <ph name="SITE" /> دیدن کنید، زیرا این وب‌سایت از پین کردن گواهینامه استÙاده می‌کند. خطاها Ùˆ حمله‌های شبکه معمولاً موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">یک نسخه ذخیره‌شده (یعنی قدیمی) از این صÙحه نشان داده شود.</translation>
<translation id="1519264250979466059">تاریخ ساخت</translation>
<translation id="1549470594296187301">برای استÙاده از این قابلیت، جاوا اسکریپت باید Ùعال باشد.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">پیکربندی شبکه نامعتبر است و نتوانست وارد شود.</translation>
<translation id="1644574205037202324">سابقه</translation>
<translation id="1645368109819982629">پروتکل پشتیبانی‌نشده</translation>
-<translation id="1655462015569774233">{1,plural, =1{این سرور نتوانست ثابت کند این <ph name="DOMAIN" /> است؛ اعتبار گواهی امنیتی آن دیروز به پایان رسیده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. آیا درست است؟ اگر پاسخ منÙÛŒ است، باید ساعت سیستمتان را درست کنید Ùˆ سپس این صÙحه را بازخوانی کنید.}one{این سرور نتوانست ثابت کند این <ph name="DOMAIN" /> است. اعتبار گواهی امنیتی آن # روز قبل به پایان رسیده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. آیا درست است؟ اگر پاسخ منÙÛŒ است، باید ساعت سیستمتان را درست کنید Ùˆ سپس این صÙحه را بازخوانی کنید.}other{این سرور نتوانست ثابت کند این <ph name="DOMAIN" /> است. اعتبار گواهی امنیتی آن # روز قبل به پایان رسیده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. آیا درست است؟ اگر پاسخ منÙÛŒ است، باید ساعت سیستمتان را درست کنید Ùˆ سپس این صÙحه را بازخوانی کنید.}}</translation>
<translation id="1676269943528358898">â€<ph name="SITE" /> معمولاً برای محاÙظت از اطلاعات شما از رمزگذاری استÙاده می‌کند. اما این بار Ú©Ù‡ Chrome تلاش کرد به <ph name="SITE" /> متصل شود، وب‌سایت اعتبارنامه‌ای نامعمول Ùˆ نادرست را برگرداند. ممکن است مهاجمی در تلاش باشد خود را به‌جای <ph name="SITE" /> معرÙÛŒ کند یا یک صÙحه ورود به سیستم Wi-Fi در ارتباط اختلال ایجاد کرده باشد. اطلاعات شما همچنان ایمن است، زیرا Google Chrome قبل از هرگونه تبادل داده، اتصال را متوق٠کرد.</translation>
<translation id="168841957122794586">گواهی‌نامه سرور دارای یک کلید رمزنگاری ضعی٠است.</translation>
<translation id="1701955595840307032">دریاÙت محتوای پیشنهادی</translation>
-<translation id="1706954506755087368">{1,plural, =1{این سرور نتوانست ثابت کند این <ph name="DOMAIN" /> است؛ اعتبار گواهی امنیتی آن ظاهراً Ùردا شروع می‌شود. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند.}one{این سرور نتوانست ثابت کند این <ph name="DOMAIN" /> است؛ اعتبار گواهی امنیتی آن ظاهراً # روز دیگر شروع می‌شود. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند.}other{این سرور نتوانست ثابت کند این <ph name="DOMAIN" /> است؛ اعتبار گواهی امنیتی آن ظاهراً # روز دیگر شروع می‌شود. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">با سرپرست سیستم تماس بگیرید.</translation>
<translation id="17513872634828108">بازکردن برگه‌ها</translation>
<translation id="1753706481035618306">شماره صÙحه</translation>
-<translation id="1761412452051366565">â€Ø¨Ø±Ø§ÛŒ دریاÙت محتوای شخصی‌سازی‌شده پیشنهادی GoogleØŒ همگام‌سازی را روشن کنید.</translation>
-<translation id="1763864636252898013">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن مورداعتماد سیستم عامل دستگاه شما نیست. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجی اتصال شما را قطع کرده است.</translation>
<translation id="1768211456781949159">â€<ph name="BEGIN_LINK" />Windows Network Diagnostics را اجرا کنید<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">لطÙاً «رمز عبارتی همگام‌سازی» خود را به‌روزرسانی کنید.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">نشانک‌هایی که به‌تازگی از آن‌ها دیدن کرده‌اید، اینجا نشان داده می‌شوند.</translation>
<translation id="1821930232296380041">پارامترهای درخواست یا درخواست نامعتبر</translation>
<translation id="1838667051080421715">درحال مشاهده منبع یک صÙحه وب هستید.</translation>
<translation id="1871208020102129563">â€ØªÙ†Ø¸ÛŒÙ… پروکسی به گونه‌ای است Ú©Ù‡ از سرورهای ثابت پروکسی استÙاده کند Ùˆ از آدرس اسکریپت pac. استÙاده نکند.</translation>
<translation id="1883255238294161206">Ú©ÙˆÚ†Ú© کردن Ùهرست</translation>
<translation id="1898423065542865115">Ùیلتر کردن</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> گواهی ثبت ورود شما را نپذیرÙت، یا ممکن است گواهی ثبت ورود شما منقضی شده باشد.</translation>
<translation id="194030505837763158">رÙتن به <ph name="LINK" /></translation>
<translation id="1962204205936693436">نشانک‌های <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">خطای ترتیب</translation>
<translation id="1974060860693918893">پیشرÙته</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{و ۱ برنامه دیگر}one{و # برنامه دیگر}other{و # برنامه دیگر}}</translation>
<translation id="2025186561304664664">پروکسی بر روی پیکربندی خودکار تنظیم شده است.</translation>
<translation id="2030481566774242610">منظورتان <ph name="LINK" /> بود؟</translation>
<translation id="2031925387125903299">این پیام را به این دلیل می‌بینید که والدینتان باید اولین باری که از سایت جدیدی بازدید می‌کنید آن را تأیید کنند.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />بررسی پروکسی و دیوار آتش<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">کد پستی</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{۱ پیشنهاد}one{# پیشنهاد}other{# پیشنهاد}}</translation>
<translation id="2065985942032347596">راستی‌آزمایی لازم است</translation>
<translation id="2079545284768500474">لغو</translation>
<translation id="20817612488360358">تنظیمات پروکسی سیستم تنظیم شده تا مورد استÙاده قرار گیرد، اما یک پیکربندی مشخص برای پروکسی نیز تعیین شده است.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">ویرایش نشانک</translation>
<translation id="2166049586286450108">دسترسی کامل سرپرست</translation>
<translation id="2166378884831602661">این سایت نمی‌تواند اتصالی ایمن ارائه دهد</translation>
-<translation id="2171101176734966184">شما سعی داشتید به <ph name="DOMAIN" /> دسترسی داشته باشید، اما گواهی ارائه شده از سوی سرور با استÙاده از یک الگوریتم امضای ضعی٠امضا شده است. یعنی ممکن است اطلاعات کاربری امنیتی ارائه شده از سوی سرور ساختگی باشد Ùˆ ممکن است این سرور سروی نباشد Ú©Ù‡ شما می‌خواستید (ممکن است شما با یک مهاجم در ارتباط باشید).</translation>
<translation id="2181821976797666341">خط‌ مشی‌ها</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{۱ نشانی}one{# نشانی}other{# نشانی}}</translation>
<translation id="2212735316055980242">خط‌مشی یاÙت نشد</translation>
<translation id="2213606439339815911">در حال واکشی موارد...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> در دسترس نیست</translation>
<translation id="2230458221926704099">با استÙاده از <ph name="BEGIN_LINK" />برنامه عیب‌یابی<ph name="END_LINK" />ØŒ مشکل اتصالتان را برطر٠کنید</translation>
+<translation id="2239100178324503013">اکنون ارسال شود</translation>
<translation id="225207911366869382">این مقدار برای این خط‌مشی منسوخ شده است؟</translation>
<translation id="2262243747453050782">â€Ø®Ø·Ø§ÛŒ HTTP</translation>
<translation id="2282872951544483773">آزمایش‌های غیرقابل دسترس</translation>
<translation id="2292556288342944218">دسترسی شما به اینترنت مسدود است</translation>
<translation id="229702904922032456">گواهینامه واسط یا ریشه منقضی شده است.</translation>
<translation id="230155334948463882">کارت جدید؟</translation>
+<translation id="2305919008529760154">این سرور نتوانست اثبات کند <ph name="DOMAIN" /> است؛ شاید گواهینامه امنیتی آن متقلبانه صادر شده باشد. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> به نام کاربری و گذرواژه نیاز دارد.</translation>
+<translation id="2318774815570432836">â€Ø¯Ø±Ø­Ø§Ù„‌حاضر نمی‌توانید از <ph name="SITE" /> دیدن کنید، زیرا این وب‌سایت از HSTS استÙاده می‌کند. خطاها Ùˆ حمله‌های شبکه معمولاً موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">نشانک نامعتبر در نمایه <ph name="ENTRY_INDEX" /> نادیده گرÙته شد</translation>
<translation id="2354001756790975382">نشانک‌های دیگر</translation>
<translation id="2359808026110333948">ادامه</translation>
<translation id="2365563543831475020">گزارش خرابی ثبت‌شده در <ph name="CRASH_TIME" /> بارگذاری نشد</translation>
<translation id="2367567093518048410">سطح</translation>
+<translation id="2371153335857947666">{1,plural, =1{این سرور نتوانست ثابت کند Ú©Ù‡ <ph name="DOMAIN" /> است؛ اعتبار گواهینامه امنیتی آن دیروز به پایان رسیده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. درست است؟ اگر پاسخ منÙÛŒ است، باید ساعت سیستمتان را درست کنید Ùˆ سپس این صÙحه را بازخوانی کنید. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.}one{این سرور نتوانست ثابت کند Ú©Ù‡ <ph name="DOMAIN" /> است. اعتبار گواهینامه امنیتی آن # روز قبل به پایان رسیده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. درست است؟ اگر پاسخ منÙÛŒ است، باید ساعت سیستمتان را درست کنید Ùˆ سپس این صÙحه را بازخوانی کنید. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.}other{این سرور نتوانست ثابت کند Ú©Ù‡ <ph name="DOMAIN" /> است. اعتبار گواهینامه امنیتی آن # روز قبل به پایان رسیده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. درست است؟ اگر پاسخ منÙÛŒ است، باید ساعت سیستمتان را درست کنید Ùˆ سپس این صÙحه را بازخوانی کنید. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">هیچ گزینه واسط کاربری موجود نیست</translation>
<translation id="2384307209577226199">پیش‌Ùرض شرکتی</translation>
-<translation id="238526402387145295">â€Ø¯Ø± حال حاضر نمی‌توانید از <ph name="SITE" /> بازدید کنید، زیرا این وب‌سایت <ph name="BEGIN_LINK" />از HSTS استÙاده می‌کند<ph name="END_LINK" />. معمولاً خطاهای شبکه Ùˆ حمله‌ها موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد.</translation>
<translation id="2386255080630008482">گواهی سرور باطل شده است.</translation>
<translation id="2392959068659972793">نمایش خط‌مشی‌ها با مقدار تنظیم نشده</translation>
<translation id="2396249848217231973">&amp;واگرد حذÙ</translation>
-<translation id="2413528052993050574">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ ممکن است گواهی امنیتی آن باطل شده باشد. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصال شما را قطع کرده است.</translation>
<translation id="2455981314101692989">این صÙحهٔ وب، تکمیل خودکار این Ùرم را غیر Ùعال کرده است.</translation>
+<translation id="2463739503403862330">تکمیل</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />در حال اجرای عیب‌یابی شبکه<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">â€URL جستجو نامعتبر است.</translation>
<translation id="2491120439723279231">گواهی سرور دارای چندین خطاست.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">ارائه</translation>
<translation id="2674170444375937751">آیا مطمئن هستید می‌خواهید این صÙحات را از سابقه خود حذ٠کنید؟</translation>
<translation id="2677748264148917807">خروج</translation>
+<translation id="269990154133806163">سرور گواهینامه‌ای ارائه کرد Ú©Ù‡ با استÙاده از خط‌مشی «شÙاÙ‌سازی گواهینامه» به‌صورت عمومی آشکار نشده بود. این شرط لازمی برای بعضی از گواهینامه‌ها است تا اطمینان حاصل شود Ú©Ù‡ قابل‌اعتماد هستند Ùˆ در برابر مهاجمین محاÙظت می‌شوند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">مقدار با Ùرمت مطابقت ندارد.</translation>
<translation id="2704951214193499422">â€Chromium درحال حاضر نمی‌تواند کارت شما را تأیید کند. لطÙاً بعداً دوباره امتحان کنید.</translation>
<translation id="2705137772291741111">کپی ذخیره‌شده (ذخیره موقت‌شده) این سایت قابل خواندن نبود.</translation>
<translation id="2709516037105925701">تکمیل خودکار</translation>
+<translation id="2712118517637785082">سعی داشتید به <ph name="DOMAIN" /> دسترسی داشته باشید، اما گواهینامه‌ای که سرور ارائه کرد توسط صادرکننده آن باطل شده است. به این معنی که قطعاً نباید به گواهینامه‌های امنیتی که این سرور ارائه می‌دهد اعتماد کرد. ممکن است درحال ارتباط با یک مهاجم باشید. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">درخواست اجازه</translation>
<translation id="2721148159707890343">درخواست با موÙقیت انجام شد</translation>
<translation id="2728127805433021124">گواهی سرور با استÙاده از یک الگوریتم امضای ضعی٠امضا شده است.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">نوار جستجو و آدرس</translation>
<translation id="2826760142808435982">اتصال با استÙاده از <ph name="CIPHER" /> رمزگذاری Ùˆ راستی‌آزمایی شده است Ùˆ از <ph name="KX" /> به عنوان مکانیسم تبادل کلید استÙاده می‌کند.</translation>
<translation id="2835170189407361413">پاک کردن Ùرم</translation>
-<translation id="2837049386027881519">â€Ø¨Ø§ استÙاده از نسخه قدیمی پروتکل TLS یا SSL باید دوباره سعی کنید اتصال را برقرار کنید. یعنی سرور از نرم‌اÙزار خیلی قدیمی استÙاده می‌کند Ùˆ ممکن است مسائل امنیتی دیگری داشته باشد.</translation>
<translation id="284702764277384724">به نظر می‌رسد که گواهی سرور در <ph name="HOST_NAME" /> جعلی باشد.</translation>
<translation id="2889159643044928134">تازه‌سازی نشود</translation>
-<translation id="2896499918916051536">این اÙزایه پشتیبانی نمی‌شود.</translation>
+<translation id="2900469785430194048">â€Google Chrome هنگام تلاش برای نمایش این صÙحه با کمبود حاÙظه روبرو شد.</translation>
<translation id="2909946352844186028">تغییر شبکه تشخیص داده شد.</translation>
-<translation id="2915500479781995473">این سرور نتوانست اثبات کند Ú©Ù‡ این <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن منقضی شده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصال شما را قطع کرده است. در حال حاضر ساعت رایانه‌تان روی <ph name="CURRENT_TIME" /> تنظیم شده است. آیا این زمان درست است؟ اگر درست نیست، باید ساعت سیستم‌تان را تنظیم کنید Ùˆ سپس این صÙحه را بازخوانی نمایید.</translation>
<translation id="2922350208395188000">گواهی سرور بررسی نمی‌شود.</translation>
-<translation id="2941952326391522266">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن از <ph name="DOMAIN2" /> است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجی اتصال شما را قطع کرده است.</translation>
<translation id="2948083400971632585">در صÙحه تنظیمات می‌توانید همه پراکسی‌های پیکربندی شده برای هر اتصال را از کار بیاندازید.</translation>
<translation id="2955913368246107853">بستن نوار یاÙتن</translation>
<translation id="2958431318199492670">â€Ù¾ÛŒÚ©Ø±Ø¨Ù†Ø¯ÛŒ شبکه با استاندارد ONC تطابق ندارد. بخشی از پیکربندی ممکن است وارد نشود.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">نوع خط‌مشی اشتباه است</translation>
<translation id="3032412215588512954">می‌خواهید این سایت را تازه‌سازی کنید؟</translation>
<translation id="3037605927509011580">اوه، نه!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{حداقل ۱ مورد در دستگاه‌های همگام‌سازی‌شده}=1{۱ مورد (و بیشتر در دستگاه‌های همگام‌سازی‌شده)}one{# مورد (و بیشتر در دستگاه‌های همگام‌سازی‌شده)}other{# مورد (و بیشتر در دستگاه‌های همگام‌سازی‌شده)}}</translation>
<translation id="3041612393474885105">اطلاعات گواهی</translation>
<translation id="3063697135517575841">â€Chrome درحال حاضر نمی‌تواند کارت شما را تأیید کند. لطÙاً بعداً دوباره امتحان کنید.</translation>
<translation id="3093245981617870298">شما Ø¢Ùلاین هستید.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">جدیدترین</translation>
<translation id="3207960819495026254">نشانک‌گذاری شده</translation>
-<translation id="3225919329040284222">سرور گواهی را نشان می‌دهد Ú©Ù‡ با موارد پیش‌بینی‌شده داخلی مطابقت ندارد. این پیش‌بینی‌ها به‌طور حتم وب‌سایتهای دارای امنیت بالا را جهت محاÙظت از شما در بر می‌گیرند.</translation>
<translation id="3226128629678568754">دکمه تازه‌سازی را Ùشار دهید تا داده‌های مورد نیاز برای بارگیری صÙحه مجدداً ارسال شود.</translation>
<translation id="3228969707346345236">ترجمه انجام نشد زیرا صÙحه در حال حاضر به زبان <ph name="LANGUAGE" /> است.</translation>
<translation id="323107829343500871">â€CVC کارت <ph name="CREDIT_CARD" /> را وارد کنید</translation>
<translation id="3254409185687681395">نشانک گذاری این صÙحه</translation>
<translation id="3270847123878663523">&amp;واگرد ترتیب‌بندی مجدد</translation>
<translation id="3286538390144397061">راه‌اندازی مجدد اکنون</translation>
+<translation id="3303855915957856445">هیچ نتیجه‌ای برای جستجو یاÙت نشد</translation>
<translation id="3305707030755673451">داده‌های شما در تاریخ <ph name="TIME" /> با عبارت عبور همگام‌سازی‌تان رمزگذاری شد. برای شروع همگام‌سازی آن را وارد کنید.</translation>
<translation id="333371639341676808">از ایجاد کادرهای Ú¯Ùتگوی دیگر توسط این صÙحه جلوگیری شود.</translation>
+<translation id="3338095232262050444">ایمن</translation>
<translation id="3340978935015468852">تنظیمات</translation>
<translation id="3345135638360864351">درخواست شما برای دسترسی به این سایت به <ph name="NAME" /> ارسال نشد. لطÙاً دوباره امتحان کنید.</translation>
<translation id="3355823806454867987">تغییر تنظیمات پروکسی...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Ùاصله زمانی واکشی:</translation>
<translation id="3462200631372590220">پنهان کردن پیشرÙته</translation>
<translation id="3479539252931486093">غیرمنتظره بود؟ <ph name="BEGIN_LINK" />به ما اطلاع دهید<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">اکنون نه</translation>
<translation id="348000606199325318">شناسه خرابی <ph name="CRASH_LOCAL_ID" /> (شناسه سرور: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">در حال حاضر نمی‌توانیم با والدینتان تماس برقرار کنیم. لطÙاً دوباره امتحان کنید.</translation>
<translation id="3527085408025491307">پوشه</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">استÙاده از گذرواژه برای:</translation>
<translation id="3549644494707163724">رمزگذاری همه داده‌های همگام‌سازی‌شده با رمزعبارتی همگام‌سازی خودتان</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> برگه بیشتر...</translation>
+<translation id="3555561725129903880">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن از <ph name="DOMAIN2" /> است. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی ارتباط شما را اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">اتصال شما خصوصی نیست</translation>
<translation id="3583757800736429874">&amp;انجام مجدد انتقال</translation>
<translation id="3586931643579894722">عدم نمایش جزئیات</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">نشان دادن مقدار</translation>
<translation id="3630155396527302611">اگر درحال حاضر به‌عنوان برنامه‌ای برای دسترسی به شبکه در Ùهرست قرار دارد،
سعی کنید آن را از Ùهرست حذ٠کرده Ùˆ دوباره به Ùهرست اضاÙÙ‡ کنید.</translation>
+<translation id="3638794133396384728">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ اعتبار گواهینامه امنیتی آن به پایان رسیده است. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. ساعت رایانه‌تان در این لحظه <ph name="CURRENT_TIME" /> را نشان می‌دهد. این زمان درست است؟ اگر درست نیست، باید ساعت سیستم خود را تصحیح کنید، سپس این صÙحه را بازخوانی کنید. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">این ویژگی‌های آزمایشی ممکن است در هر زمانی تغییر کنند، نقض شوند یا ناپدید شوند. اگر یکی از این ویژگی‌های آزمایشی را Ùعال کنید ما هیچ تضمینی در مورد آنچه Ú©Ù‡ ممکن است اتÙاق بیÙتد نداریم، Ùˆ حتی ممکن است مرورگر شما خود به خود ناپدید شود. در واقع، ممکن است مرورگر شما تمام داده‌های شما را حذ٠کند یا امنیت Ùˆ حریم خصوصی شما می‌تواند به صورت غیرمنتظره‌ای به خطر بیÙتد. هر ویژگی آزمایشی Ú©Ù‡ Ùعال می‌کنید برای تمام کاربران این مرورگر Ùعال خواهد شد. لطÙاً با احتیاط ادامه دهید.</translation>
<translation id="3650584904733503804">ارزیابی موÙÙ‚ بود</translation>
<translation id="3655670868607891010">اگر مکرراً با این مشکل مواجه می‌شوید، <ph name="HELP_LINK" /> را امتحان کنید.</translation>
<translation id="3658742229777143148">ویرایش</translation>
+<translation id="3678029195006412963">درخواست امضا نشد</translation>
<translation id="3681007416295224113">اطلاعات گواهی</translation>
<translation id="3693415264595406141">گذرواژه:</translation>
+<translation id="3696411085566228381">هیچ‌کدام</translation>
<translation id="3700528541715530410">اوه، به نظر می‌رسد Ú©Ù‡ شما مجاز به دسترسی به این صÙحه نیستید.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> â€<ph name="BOOKMARKED" /> â€<ph name="TITLE" /> â€<ph name="DOMAIN" /></translation>
<translation id="370665806235115550">در حال بارکردن…</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">â€Ø±ÙˆØ´Ù† کردن داده‌ شبکه تلÙÙ† همراه یا Wi-Fi</translation>
<translation id="3717027428350673159">â€<ph name="BEGIN_LINK" />بررسی پروکسی، دیوار آتش Ùˆ پیکربندی DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">پیوندی که کپی کرده‌اید</translation>
-<translation id="3744899669254331632">â€Ù†Ù…ی‌توانید اکنون از <ph name="SITE" /> دیدن کنید زیرا وب‌سایت اعتبارنامه‌های درهمی ارسال کرده Ú©Ù‡ Chromium نمی‌تواند پردازش کند. خطاها Ùˆ حمله‌های شبکه معمولاً موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار می‌کند.</translation>
<translation id="375403751935624634">بدلیل خطای سرور ترجمه انجام نشد.</translation>
<translation id="3759461132968374835">شما اخیراً گزارش خرابی ارسال نکرده‌اید. مشکلاتی Ú©Ù‡ در هنگام غیرÙعال بودن ویژگی ارائه گزارش خرابی ایجاد شده است، در اینجا نمایش داده نمی‌شود.</translation>
<translation id="3788090790273268753">â€Ú¯ÙˆØ§Ù‡ÛŒ این سایت در سال Û²Û°Û±Û¶ منقضی می‌شود Ùˆ زنجیره گواهی حاوی یک گواهی با امضای SHA-1 است.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">شناسه دستگاه یکسان نیست</translation>
<translation id="3885155851504623709">استان</translation>
<translation id="3901925938762663762">کارت منقضی شده است</translation>
+<translation id="3910267023907260648">سعی داشتید به <ph name="DOMAIN" /> دسترسی داشته باشید، اما سرور گواهینامه‌ای ارائه کرد Ú©Ù‡ با استÙاده از الگوریتم امضای ضعیÙÛŒ امضا شده است. به این معنی Ú©Ù‡ ممکن است گواهینامه‌های امنیتی ارائه‌شده توسط این سرور جعلی باشد Ùˆ ممکن است این سرور، سرور موردانتظار شما نباشد (شاید درحال ارتباط با یک مهاجم باشید). <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{این سرور نمی‌تواند ثابت کند <ph name="DOMAIN" /> است؛ اعتبار گواهینامه امنیتی آن ظاهراً Ùردا شروع می‌شود. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.}one{این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ اعتبار گواهینامه امنیتی آن ظاهراً # روز دیگر شروع می‌شود. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.}other{این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ اعتبار گواهینامه امنیتی آن ظاهراً # روز دیگر شروع می‌شود. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصالتان را قطع می‌کند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">â€Ø¨Ø§Ø±Ú¯ÛŒØ±ÛŒ سند PDF انجام نشد</translation>
<translation id="3963721102035795474">حالت «خواننده»</translation>
+<translation id="397105322502079400">در حال محاسبه…</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> مسدود است</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{ Û± صÙحه وب در این نزدیکی است}one{ # صÙحه وب در این نزدیکی است}other{ # صÙحه وب در این نزدیکی است}}</translation>
<translation id="4021036232240155012">â€DNS خدماتی از شبکه است Ú©Ù‡ نام وب‌سایت را به آدرس اینترنتی آن ترجمه می‌کند.</translation>
<translation id="4030383055268325496">&amp;واگرد اÙزودن</translation>
-<translation id="4032534284272647190">دسترسی به <ph name="URL" /> رد شد.</translation>
<translation id="404928562651467259">اخطار</translation>
<translation id="4058922952496707368">کلید "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">â€Ú©Ù„اینت Ùˆ سرور از مجموعه رمزگذاری یا نسخه پروتکل SSL مشترکی استÙاده نمی‌کنند.</translation>
<translation id="4079302484614802869">â€ØªÙ†Ø¸ÛŒÙ…ات پروکسی، برای استÙاده از آدرس اسکریپت pac. تنظیم شده است Ùˆ از سرورهای ثابت نمی‌تواند استÙاده کند.</translation>
<translation id="4103249731201008433">شماره سریال دستگاه نامعتبر است</translation>
<translation id="4103763322291513355">â€Ø¨Ø±Ø§ÛŒ مشاهده Ùهرست نشانی‌های وب ممنوع Ùˆ سایر خط‌مشی‌های اجباری براساس تصمیم سرپرست سیستم خود از &lt;strong&gt;chrome://policy&lt;/strong&gt; بازدید نمایید.</translation>
+<translation id="4110615724604346410">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن خطاهایی دارد. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">محدوده خط‌مشی پشتیبانی نمی‌شود.</translation>
+<translation id="4118212371799607889">â€Ø§ÛŒÙ† سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن مورداعتماد Chromium نیست. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{۱ مورد دیگر}one{# مورد دیگر}other{# مورد دیگر}}</translation>
<translation id="4130226655945681476">بررسی کابل‌های شبکه، مودم یا رهیاب</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">â€Ù…ی‌خواهید Chromium این کارت را ذخیره کند؟</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">غیرÙعال شد</translation>
<translation id="4196861286325780578">&amp;انجام مجدد انتقال</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />بررسی پیکربندی آنتی‌ویروس و دیوار آتش<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{هیچ‌}=1{۱ برنامه ($1)}=2{۲ برنامه ($1،†$2)}one{# برنامه ($1،†$2،†$3)}other{# برنامه ($1،†$2،†$3)}}</translation>
<translation id="4220128509585149162">خرابی ها</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />عیب‌یابی شبکه را اجرا کنید<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">نه</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(بدون نام کاربری)</translation>
<translation id="4300246636397505754">پیشنهادات والدین</translation>
<translation id="4304224509867189079">ورود به سیستم</translation>
+<translation id="432290197980158659">سرور گواهینامه‌ای ارائه کرد Ú©Ù‡ با انتظارات داخلی مطابقت ندارد. این انتظارات برای بعضی از وب‌سایت‌های با امنیت بالا Ùˆ با هد٠محاÙظت از شما درنظر گرÙته شده‌اند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">مقاله یاÙت نشد.</translation>
+<translation id="4331708818696583467">امن نیست</translation>
<translation id="4372948949327679948">مقدار مورد انتظار <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">شما سعی در دسترسی به <ph name="DOMAIN" /> را داشتید، اما صادر کننده، گواهی ارائه شده از سوی سرور را باطل کرده است. یعنی اصلاً نباید به اطلاعات کاربری که این سرور ارائه می‌کند اطمینان کرد. ممکن است شما با مهاجمی در ارتباط باشید.</translation>
<translation id="4381091992796011497">نام کاربری:</translation>
<translation id="4394049700291259645">غیر Ùعال کردن</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> تا <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">نتایج جستجو</translation>
-<translation id="4424024547088906515">â€Ø§ÛŒÙ† سرور نتوانست اثبات کند Ú©Ù‡ این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن مورداعتماد Chrome نیست. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجی اتصال شما را قطع کرده است.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> گواهی ورود به سیستمتان را نپذیرÙت یا ممکن است گواهی‌ای ارائه نشده باشد.</translation>
<translation id="443673843213245140">استÙاده از پروکسی غیرÙعال است اما یک پیکربندی خاص برای پروکسی تعیین شده است.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">â€Ø§ÛŒÙ† پیام را به این دلیل می‌بینید Ú©Ù‡ Google SafeSites Ùعال است.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">جزئیات</translation>
<translation id="4558551763791394412">اÙزونه‌ها را غیرÙعال کنید.</translation>
<translation id="4587425331216688090">â€Ø¢Ø¯Ø±Ø³ از Chrome پاک شود؟</translation>
+<translation id="4589078953350245614">سعی داشتید به <ph name="DOMAIN" /> دسترسی داشته باشید، اما سرور گواهینامه نامعتبری ارائه کرد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">اتصال شما به <ph name="DOMAIN" /> با استÙاده از یک مجموعه رمز مدرن، رمزگذاری شده است.</translation>
<translation id="4594403342090139922">&amp;واگرد حذÙ</translation>
+<translation id="4627442949885028695">ادامه از دستگاه دیگری</translation>
<translation id="4668929960204016307">،</translation>
<translation id="4670097147947922288">درحال مشاهده یک صÙحه اÙزونه هستید.</translation>
-<translation id="467662567472608290">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن خطاهایی دارد. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصال شما را قطع کرده است.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> مسدود شد</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">اتصال شما قطع شد</translation>
<translation id="4722547256916164131">â€<ph name="BEGIN_LINK" />در حال اجرای Windows Network Diagnostics<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">پلت Ùورم</translation>
<translation id="4744603770635761495">مسیر قابل اجرا</translation>
<translation id="4756388243121344051">&amp;سابقه</translation>
+<translation id="4759238208242260848">بارگیری‌ها</translation>
<translation id="4764776831041365478">ممکن است صÙحهٔ وب <ph name="URL" /> موقتاً خراب باشد یا ممکن است برای همیشه به آدرس وب جدید منتقل شده باشد.</translation>
<translation id="4771973620359291008">خطای ناشناخته‌ای رخ داد.</translation>
<translation id="4782449893814226250">از والدینتان پرسیدید آیا اجازه بازدید از این صÙحه را دارید.</translation>
<translation id="4800132727771399293">â€ØªØ§Ø±ÛŒØ® انقضا Ùˆ CVC را بررسی کرده Ùˆ دوباره امتحان کنید</translation>
-<translation id="4807049035289105102">â€Ø¯Ø± این لحظه نمی‌توانید از <ph name="SITE" /> دیدن کنید زیرا این وب‌سایت اعتبارنامه‌های درهمی ارسال کرده است Ú©Ù‡ Google Chrome نمی‌تواند پردازش کند. خطاهای شبکه Ùˆ حمله‌ها معمولاً موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد.</translation>
<translation id="4813512666221746211">خطای شبکه</translation>
<translation id="4816492930507672669">متناسب با صÙحه</translation>
<translation id="4850886885716139402">نما</translation>
<translation id="4880827082731008257">سابقه جستجو</translation>
+<translation id="4884656795097055129">مقالات بیشتری در زمان مناسب نشان داده خواهند شد.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />،†<ph name="TYPE_2" />،†<ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{ Ùˆ Û± صÙحه وب دیگر}one{ Ùˆ # صÙحه وب دیگر}other{ Ùˆ # صÙحه وب دیگر}}</translation>
<translation id="4923417429809017348">این صÙحه از یک زبان ناشناس به <ph name="LANGUAGE_LANGUAGE" /> ترجمه شده است.</translation>
<translation id="4926049483395192435">باید مشخص شود.</translation>
<translation id="4930497775425430760">این پیام را به این دلیل می‌بینید که والدینتان باید اولین باری که از سایت جدیدی بازدید می‌کنید آن را تأیید کنند.</translation>
<translation id="495170559598752135">عملکردها</translation>
<translation id="4958444002117714549">بزرگ کردن Ùهرست</translation>
+<translation id="4962322354953122629">â€Ø§ÛŒÙ† سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن مورداعتماد Chrome نیست. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">از <ph name="ORIGINAL_LANGUAGE" /> به <ph name="TARGET_LANGUAGE" /> ترجمه شود؟</translation>
+<translation id="4989809363548539747">این اÙزایه پشتیبانی نمی‌شود</translation>
<translation id="5002932099480077015">â€Ø§Ú¯Ø± Ùعال شود، Chrome یک Ú©Ù¾ÛŒ از کارت شما را برای پرکردن سریع‌تر Ùرم در این دستگاه ذخیره می‌کند.</translation>
<translation id="5019198164206649151">پشتیبان‌گیری ذخیره در وضعیت نادرست است</translation>
<translation id="5023310440958281426">خط‌مشی‌های سرپرست سیستمتان را بررسی کنید</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">â€Ø¯Ø±Ø¨Ø§Ø±Ù‡ â€â€«Ù…ترجم Google‬</translation>
<translation id="5040262127954254034">حریم خصوصی</translation>
<translation id="5045550434625856497">گذرواژه نادرست</translation>
+<translation id="5056549851600133418">مقالاتی برای شما</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />بررسی آدرس پروکسی<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">در حال حاضر گواهی سرور معتبر نیست.</translation>
<translation id="5089810972385038852">ایالت</translation>
-<translation id="5094747076828555589">â€Ø§ÛŒÙ† سرور نتوانست اثبات کند Ú©Ù‡ این <ph name="DOMAIN" /> است؛ گواهی امنیت آن مورداعتماد Chromium نیست. علت این موضوع می‌توان پیکربندی اشتباه باشد یا مهاجمی اتصال شما را قطع کرده است.</translation>
<translation id="5095208057601539847">استان</translation>
<translation id="5115563688576182185">(۶۴ بیت)</translation>
-<translation id="5122371513570456792"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> برای «<ph name="SEARCH_STRING" />» پیدا شد.</translation>
<translation id="5141240743006678641">â€Ø±Ù…زگذاری گذرواژه‌های همگام‌سازی شده با اطلاعات کاربری Google شما</translation>
<translation id="5145883236150621069">کد خطا در پاسخ خط‌مشی موجود است</translation>
<translation id="5171045022955879922">â€Ø¬Ø³ØªØ¬Ùˆ یا تایپ URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">نوار نشانک‌ها</translation>
<translation id="5199729219167945352">آزمایشات</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">â€Ø§Ø² Chrome در محل کار استÙاده می‌کنید؟ کسب Ùˆ کارها می‌توانند تنظیمات Chrome را برای کارمندانشان مدیریت کنند. بیشتر بدانید</translation>
<translation id="5299298092464848405">خطا در تجزیه خط‌‌مشی</translation>
<translation id="5300589172476337783">نمایش</translation>
<translation id="5308689395849655368">گزارش خرابی غیر Ùعال است.</translation>
<translation id="5317780077021120954">ذخیره</translation>
<translation id="5327248766486351172">نام</translation>
+<translation id="5359637492792381994">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن درحال‌حاضر معتبر نیست. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">تنظیمات خط‌‌مشی ذخیره نشد</translation>
-<translation id="540969355065856584">این سرور نتوانست ثابت کند که <ph name="DOMAIN" /> است؛ در حال حاضر، گواهی امنیتی آن معتبر نیست. ممکن است این مشکل به دلیل پیکربندی نادرست یا قطع اتصال شما توسط حمله‌کننده ایجاد شده باشد.</translation>
<translation id="5421136146218899937">پاک کردن داده‌های مرور...</translation>
<translation id="5430298929874300616">حذ٠نشانک</translation>
<translation id="5431657950005405462">Ùایل شما پیدا نشد</translation>
<translation id="5435775191620395718">در حال نمایش سابقه از این دستگاه. <ph name="BEGIN_LINK" />بیشتر بدانید<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">پیشنهاد محتوای شخصی‌سازی‌شده درحال حاضر غیرÙعال است، چون داده‌های همگام‌سازی‌شده‌تان با عبارت عبور سÙارشی محاÙظت می‌شود.</translation>
<translation id="5439770059721715174">خطای تأیید طرح در «<ph name="ERROR_PATH" />»:†<ph name="ERROR" /></translation>
<translation id="5452270690849572955">صÙحه <ph name="HOST_NAME" /> پیدا نمی‌شود</translation>
<translation id="5455374756549232013">مهر زمان خط‌مشی نادرست است</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">می‌خواهید از این سایت خارج شوید؟</translation>
<translation id="5629630648637658800">تنظیمات خط‌مشی بارگیری نشد</translation>
<translation id="5631439013527180824">نشانه مدیریت دستگاه نامعتبر است</translation>
-<translation id="5650551054760837876">هیچ نتیجه‌ای برای جستجو یاÙت نشد.</translation>
<translation id="5677928146339483299">مسدود است</translation>
<translation id="5710435578057952990">هویت این وب سایت تأیید نشده است.</translation>
<translation id="5720705177508910913">کاربر کنونی</translation>
+<translation id="572328651809341494">برگه‌های اخیر</translation>
<translation id="5784606427469807560">هنگام تأیید کارت مشکلی پیش آمد. اتصال اینترنتتان را بررسی و دوباره امتحان کنید.</translation>
<translation id="5785756445106461925">علاوه بر این، این صÙحه دارای منابع دیگری است Ú©Ù‡ امن نیستند. دیگران می‌توانند در حین انتقال، این منابع را ببینند Ùˆ این منابع می‌توانند برای تغییر Ù‚ÙÙ„ صÙحه، توسط یک مهاجم تغییر داده شوند.</translation>
+<translation id="5786044859038896871">می‌خواهید اطلاعات کارتتان را وارد کنید؟</translation>
+<translation id="5803412860119678065">می‌خواهید <ph name="CARD_DETAIL" /> خود را وارد کنید؟</translation>
<translation id="5810442152076338065">اتصال شما به <ph name="DOMAIN" /> با استÙاده از یک مجموعه رمز منسوخ، رمزگذاری شده است.</translation>
<translation id="5813119285467412249">&amp;انجام مجدد اÙزودن</translation>
+<translation id="5814352347845180253">ممکن است دسترسی به محتوای ممتاز از <ph name="SITE" /> و برخی دیگر سایت‌ها را از دست بدهید.</translation>
+<translation id="5843436854350372569">سعی داشتید به <ph name="DOMAIN" /> دسترسی داشته باشید، اما سرور گواهینامه‌ای حاوی یک کلید ضعی٠ارائه کرد. ممکن است مهاجمی کلید خصوصی را شکسته باشد و ممکن است این سرور، سرور موردانتظار شما نباشد (ممکن است درحال ارتباط با یک مهاجم باشید). <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">این پیام را به این دلیل می‌بینید که مدیرتان این سایت را مسدود کرده است.</translation>
<translation id="5857090052475505287">پوشهٔ جدید</translation>
<translation id="5869405914158311789">دسترسی به این سایت امکان‌پذیر نیست</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">پیشنهادات والدین</translation>
<translation id="59107663811261420">â€Google Payments این نوع کارت را برای این تاجر پشتیبانی نمی‌کند. لطÙاً کارت دیگری انتخاب کنید.</translation>
<translation id="59174027418879706">Ùعال شد</translation>
+<translation id="5926846154125914413">ممکن است دسترسی به محتوای ممتاز برخی از سایت‌ها را از دست بدهید.</translation>
<translation id="5966707198760109579">Ù‡Ùته</translation>
<translation id="5967867314010545767">حذ٠از سابقه</translation>
<translation id="5975083100439434680">کوچک نمایی</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">خودکار</translation>
<translation id="6042308850641462728">بیشتر</translation>
<translation id="6060685159320643512">مراقب باشید، این آزمایشات ممکن است خطرناک باشند</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{هیچ‌}=1{۱}one{#}other{#}}</translation>
<translation id="6146055958333702838">همه کابل‌ها را بررسی کنید و همه ره‌یاب‌ها، مودم‌ها، یا دیگر دستگاه‌های
 شبکه‌ای را Ú©Ù‡ ممکن است درحال استÙاده از آن‌ها باشید مجدداً راه‌اندازی کنید.</translation>
<translation id="614940544461990577">این موارد را امتحان کنید:</translation>
<translation id="6150607114729249911">وای! برای بازدید از این صÙحه باید از والدینتان اجازه بگیرید.</translation>
<translation id="6151417162996330722">دوره اعتبار گواهینامه سرور بسیار طولانی است.</translation>
-<translation id="6154808779448689242">نشانه خط‌مشی بازگشتی با نشانه Ùعلی تطابق ندارد</translation>
<translation id="6165508094623778733">بیشتر بدانید</translation>
<translation id="6203231073485539293">اتصال اینترنتتان را بررسی کنید</translation>
<translation id="6218753634732582820">â€Ø¢Ø¯Ø±Ø³ از Chromium پاک شود؟</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">غیرÙعال کردن پیش‌بینی شبکه را امتحان کنید</translation>
<translation id="6337534724793800597">Ùیلتر کردن خط‌مشی‌ها براساس نام</translation>
<translation id="6342069812937806050">Ùقط اکنون</translation>
+<translation id="6345221851280129312">اندازه ناشناس</translation>
<translation id="6355080345576803305">لغو جلسه عمومی</translation>
<translation id="6358450015545214790">معنی این‌ها چیست؟</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{۱ پیشنهاد دیگر}one{# پیشنهاد دیگر}other{# پیشنهاد دیگر}}</translation>
<translation id="6387478394221739770">â€Ø¹Ù„اقه‌مند به قابلیت‌های جدید Ùˆ جالب Chrome هستید؟ کانال بتای ما را در chrome.com/beta امتحان کنید.</translation>
-<translation id="641480858134062906">بارگیری <ph name="URL" /> ناموÙÙ‚ بود</translation>
+<translation id="6389758589412724634">â€Chromium هنگام تلاش برای نمایش این صÙحه با کمبود حاÙظه روبرو شد.</translation>
+<translation id="6416403317709441254">â€Ø¯Ø±Ø­Ø§Ù„‌حاضر نمی‌توانید از <ph name="SITE" /> دیدن کنید، زیرا این وب‌سایت اعتبارنامه‌های درهمی ارسال کرده است Ú©Ù‡ Chromium نمی‌تواند آن‌ها را پردازش کند. خطاها Ùˆ حمله‌های شبکه معمولاً موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">امکان بررسی اینکه آیا مجوز باطل شده است یا نه وجود ندارد.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> از اتصال خودداری کرد.</translation>
<translation id="6445051938772793705">کشور</translation>
<translation id="6451458296329894277">تأیید ارسال مجدد Ùرم</translation>
<translation id="6458467102616083041">نادیده گرÙته شد زیرا جستجوی پیش‌Ùرض توسط قانون غیرÙعال شده است.</translation>
+<translation id="6462969404041126431">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ شاید گواهینامه امنیتی آن باطل شده باشد. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">خط‌‌مشی‌های دستگاه</translation>
-<translation id="6489534406876378309">شروع آپلود کردن خرابی‌ها</translation>
+<translation id="6489534406876378309">شروع بارگذاری کردن خرابی‌ها</translation>
<translation id="6529602333819889595">&amp;انجام مجدد حذÙ</translation>
+<translation id="6534179046333460208">پیشنهادهای «وب Ùیزیکی»</translation>
<translation id="6550675742724504774">گزینه‌ها</translation>
+<translation id="6593753688552673085">کمتر از <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">گزینه‌های رمزگذاری</translation>
<translation id="662080504995468778">ماندن</translation>
<translation id="6628463337424475685">جستجوی <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">در حال حاضر نمی‌توانید از <ph name="SITE" /> بازدید کنید زیرا <ph name="BEGIN_LINK" />این گواهینامه باطل شده است<ph name="END_LINK" />. معمولاً خطاهای شبکه Ùˆ حمله‌ها موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد.</translation>
<translation id="6644283850729428850">این قانون قدیمی شده است.</translation>
+<translation id="6652240803263749613">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن مورداعتماد سیستم‌عامل رایانه شما نیست. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">ویرایش پوشه</translation>
<translation id="6660210980321319655">به‌صورت خودکار در <ph name="CRASH_TIME" /> گزارش داده شد</translation>
<translation id="6671697161687535275">â€Ù¾ÛŒØ´Ù†Ù‡Ø§Ø¯ Ùرم از Chromium پاک شود؟</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">قبلی</translation>
<translation id="6710594484020273272">&lt;عبارت جستجو را تایپ کنید&gt;</translation>
<translation id="6711464428925977395">مشکلی در سرور پروکسی وجود دارد یا این آدرس درست نیست.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{هیچ‌}=1{۱ مورد}one{# مورد}other{# مورد}}</translation>
<translation id="674375294223700098">خطای ناشناس گواهی سرور.</translation>
<translation id="6753269504797312559">مقدار خط‌‌مشی</translation>
<translation id="6757797048963528358">دستگاهتان به خواب رÙته است.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">سطح خط‌مشی پشتیبانی نمی‌شود.</translation>
<translation id="6895330447102777224">کارتتان تأیید شد</translation>
<translation id="6897140037006041989">نماینده کاربر</translation>
-<translation id="6903907808598579934">روشن کردن همگام‌سازی</translation>
<translation id="6915804003454593391">کاربر:</translation>
<translation id="6957887021205513506">به نظر می‌رسد که گواهی سرور جعلی باشد.</translation>
<translation id="6965382102122355670">تأیید</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">حوزه</translation>
<translation id="6973656660372572881">â€Ù‡Ù… سرورهای پروکسی ثابت Ùˆ هم آدرس اسکریپت pac. مشخص شده‌اند.</translation>
<translation id="6989763994942163495">نمایش تنظیمات پیشرÙته ...</translation>
+<translation id="7000990526846637657">هیچ ورودی سابقه‌ای پیدا نشد</translation>
+<translation id="7009986207543992532">سعی کردید به <ph name="DOMAIN" /> دسترسی داشته باشید، اما سرور گواهینامه‌ای ارائه کرد که دوره اعتبار بیش از اندازه طولانی آن قابل‌اعتماد نیست. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">â€Ù…Ù…Ú©Ù† است «حساب Google» شما سابقه مروری به Ø´Ú©Ù„ دیگری در <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> داشته باشد</translation>
<translation id="7029809446516969842">گذرواژه‌ها</translation>
-<translation id="7050187094878475250">تلاش کردید به دامنه <ph name="DOMAIN" /> بروید اما گواهینامه‌ای که سرور ارائه کرد، دارای یک تاریخ اعتبار بسیار طولانی است و مورداعتماد نیست.</translation>
<translation id="7087282848513945231">شهرستان</translation>
<translation id="7088615885725309056">قدیمی تر</translation>
<translation id="7090678807593890770">â€Ø¬Ø³ØªØ¬ÙˆÛŒ <ph name="LINK" /> در Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">این پیام را به این دلیل می‌بینید که مدیرتان باید اولین باری که از سایت جدیدی بازدید می‌کنید آن را تأیید کند.</translation>
<translation id="724975217298816891">â€Ø¨Ø±Ø§ÛŒ به‌روزرسانی جزئیات کارتتان، تاریخ انقضا Ùˆ CVC کارت <ph name="CREDIT_CARD" /> را وارد کنید. بعد از تأیید شدن، جزئیات کارتتان با این سایت به اشتراک گذاشته می‌شود.</translation>
<translation id="725866823122871198">اتصال خصوصی به <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> برقرار نمی‌شود زیرا تاریخ و زمان رایانه شما (<ph name="DATE_AND_TIME" />) نادرست است.</translation>
-<translation id="7265986070661382626">در حال حاضر نمی‌توانید از <ph name="SITE" /> بازدید کنید زیرا این وب‌سایت <ph name="BEGIN_LINK" />از پین کردن مجوز استÙاده می‌کند<ph name="END_LINK" />. معمولاً خطاهای شبکه Ùˆ حمله‌ها موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد.</translation>
<translation id="7269802741830436641">این صÙحهٔ وب دارای یک دور هدایت مجدد است</translation>
<translation id="7275334191706090484">نشانک‌های مدیریت شده</translation>
<translation id="7298195798382681320">توصیه می‌شود</translation>
-<translation id="7301833672208172928">روشن کردن همگام‌سازی سابقه</translation>
+<translation id="7309308571273880165">گزارش خرابی ثبت‌شده در <ph name="CRASH_TIME" /> (کاربر درخواست بارگذاری کرده است، هنوز بارگذاری نشده است)</translation>
<translation id="7334320624316649418">&amp;انجام مجدد ترتیب‌بندی مجدد</translation>
<translation id="733923710415886693">گواهی سرور از طریق Ø´ÙاÙیت گواهینامه نشان داده نشده بود.</translation>
+<translation id="7351800657706554155">درحال‌حاضر نمی‌توانید از <ph name="SITE" /> دیدن کنید، زیرا گواهینامه آن باطل شده است. خطاها Ùˆ حمله‌های شبکه معمولاً موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">خط Ùرمان</translation>
<translation id="7372973238305370288">نتیجه جستجو</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">درحال تایید کارت</translation>
<translation id="7481312909269577407">ارسال کردن</translation>
<translation id="7485870689360869515">هیچ داده‌ای یاÙت نشد.</translation>
-<translation id="7514365320538308">دانلود</translation>
+<translation id="7508255263130623398">شناسه دستگاه خط‌مشی برگردانده‌شده خالی است یا با شناسه کنونی دستگاه مطابقت ندارد</translation>
+<translation id="7514365320538308">بارگیری</translation>
<translation id="7518003948725431193">صÙحه وبی با این آدرس وب یاÙت نشد: <ph name="URL" /></translation>
<translation id="7537536606612762813">اجباری</translation>
<translation id="7542995811387359312">تکمیل خودکار کارت اعتباری غیر Ùعال است زیرا این Ùرم از یک اتصال امن استÙاده نمی‌کند.</translation>
<translation id="7549584377607005141">این صÙحه وب برای نمایش صحیح به داده‌هایی نیاز دارد Ú©Ù‡ قبلاً وارد کرده‌اید. می‌توانید این داده‌ها را دوباره ارسال کنید، اما با انجام این کار، هر اقدامی Ú©Ù‡ این صÙحه قبلاً انجام داده است تکرار می‌شود.</translation>
<translation id="7554791636758816595">برگهٔ جدید</translation>
-<translation id="7567204685887185387">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ ممکن است گواهی امنیتی آن به صورت تقلبی صادر شده باشد. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصال شما را قطع کرده است.</translation>
<translation id="7568593326407688803">این صÙحه به <ph name="ORIGINAL_LANGUAGE" /> است، آیا مایلید ترجمه شود؟</translation>
<translation id="7569952961197462199">â€Ú©Ø§Ø±Øª اعتباری از Chrome پاک شود؟</translation>
<translation id="7578104083680115302">â€Ø¨Ø§ استÙاده از کارت‌هایی Ú©Ù‡ با Google ذخیره کرده‌اید به‌سرعت در همه دستگاه‌هایتان پرداخت‌های سایت‌ها Ùˆ برنامه‌ها را انجام دهید.</translation>
+<translation id="7588950540487816470">وب Ùیزیکی</translation>
<translation id="7592362899630581445">گواهی سرور محدودیت‌های نام را نقض می‌کند.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> درحال حاضر نمی‌تواند این درخواست را انجام دهد.</translation>
<translation id="7600965453749440009">هرگز <ph name="LANGUAGE" /> ترجمه نشود</translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">â€Ú©Ø§Ø±Øª اعتباری از Chromium پاک شود؟</translation>
<translation id="765676359832457558">پنهان کردن تنظیمات پیشرÙته…</translation>
<translation id="7658239707568436148">لغو</translation>
+<translation id="7667346355482952095">کد خط‌مشی برگردانده‌شده خالی است یا با کد کنونی مطابقت ندارد</translation>
<translation id="7668654391829183341">دستگاه ناشناس</translation>
<translation id="7674629440242451245">â€Ø¹Ù„اقه‌مند به قابلیت‌های جدید Ùˆ جالب Chrome هستید؟ کانال برنامه‌نویسان ما را در chrome.com/dev امتحان کنید.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ادامه به <ph name="SITE" /> (غیرایمن)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">نه متشکرم</translation>
<translation id="7805768142964895445">وضعیت</translation>
<translation id="7813600968533626083">â€Ù¾ÛŒØ´Ù†Ù‡Ø§Ø¯ Ùرم از Chrome پاک شود؟</translation>
+<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /><ph name="SEARCH_RESULTS" /> برای «<ph name="SEARCH_STRING" />» پیدا شد</translation>
<translation id="785549533363645510">اما، شما نامرئی نیستید. با استÙاده از حالت ناشناس، مرورتان از چشمان کارÙرمای شما، ارائه‌دهنده خدمات اینترنت یا وب‌‌سایت‌هایی Ú©Ù‡ بازدید می‌کنید پنهان نمی‌ماند.</translation>
<translation id="7887683347370398519">â€CVC را بررسی کرده Ùˆ دوباره امتحان کنید</translation>
<translation id="7894616681410591072">وای! برای دسترسی به این صÙحه باید از <ph name="NAME" /> اجازه بگیرید.</translation>
-<translation id="790025292736025802"><ph name="URL" /> یاÙت نشد</translation>
<translation id="7912024687060120840">در پوشه:</translation>
<translation id="7920092496846849526">از والدینتان پرسیدید آیا اجازه بازدید از این صÙحه را دارید.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">تعیین نشده</translation>
<translation id="8012647001091218357">در حال حاضر نمی‌توانیم با والدینتان ارتباط برقرار کنیم. لطÙاً دوباره امتحان کنید.</translation>
<translation id="8034522405403831421">این صÙحه به زبان <ph name="SOURCE_LANGUAGE" /> است. مایلید آن را به <ph name="TARGET_LANGUAGE" /> ترجمه کنید؟</translation>
-<translation id="8034955203865359138">ورودی سابقه یاÙت نشد.</translation>
<translation id="8088680233425245692">مشاهده مقاله ناموÙÙ‚ بود.</translation>
+<translation id="8089520772729574115">کمتر از ۱ مگابایت</translation>
<translation id="8091372947890762290">Ùعال‌سازی در سرور در حالت تعلیق است</translation>
+<translation id="8129262335948759431">مقدار ناشناس</translation>
<translation id="8131740175452115882">تأیید</translation>
<translation id="8134994873729925007">â€<ph name="BEGIN_ABBR" />نشانی DNS<ph name="END_ABBR" /> سرور <ph name="HOST_NAME" /> پیدا نشد.</translation>
<translation id="8149426793427495338">رایانه‌تان به خواب رÙته است.</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">نشانی وب به‌روزرسانی نامعتبر برای برنامه اÙزودنی با شناسه «<ph name="EXTENSION_ID" />».</translation>
<translation id="8218327578424803826">مکان اختصاص یاÙته:</translation>
<translation id="8225771182978767009">شخصی که این رایانه را راه‌اندازی کرده این سایت را مسدود کرده است.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />،†<ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">صÙحه‌ای Ú©Ù‡ جستجو می‌کنید از اطلاعاتی استÙاده می‌کند Ú©Ù‡ شما وارد کرده‌اید. بازگشت به آن صÙحه ممکن است باعث شود اقدامی را Ú©Ù‡ قبلاً انجام دادید دوباره تکرار کنید. آیا می‌خواهید ادامه دهید؟</translation>
<translation id="8249320324621329438">آخرین واکشی شده:</translation>
<translation id="8261506727792406068">حذÙ</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">نوار نشانک‌ها</translation>
<translation id="8363502534493474904">خاموش کردن حالت هواپیما</translation>
<translation id="8364627913115013041">تنظیم نشده است.</translation>
+<translation id="8380941800586852976">خطرناک</translation>
<translation id="8412145213513410671">خرابی ها (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">شما باید همان عبارت عبور را دوبار وارد کنید.</translation>
<translation id="8428213095426709021">تنظیمات</translation>
+<translation id="8433057134996913067">با این کار از سیستم بیشتر وب‌سایت‌ها خارج می‌شوید.</translation>
<translation id="8437238597147034694">&amp;واگرد انتقال</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{۱ کارت اعتباری}one{# کارت اعتباری}other{# کارت اعتباری}}</translation>
+<translation id="8483780878231876732">â€Ø¨Ø±Ø§ÛŒ استÙاده از کارت‌ها از حساب Google خود، به سیستم Chrome وارد شوید</translation>
<translation id="8488350697529856933">اعمال برای</translation>
<translation id="8498891568109133222">پاسخ <ph name="HOST_NAME" /> بیش از حد طول کشیده است.</translation>
+<translation id="852346902619691059">این سرور نتوانست ثابت کند <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن مورداعتماد سیستم‌عامل دستگاه شما نیست. ممکن است پیکربندی اشتباهی علت آن باشد یا مهاجمی اتصالتان را قطع کرده باشد. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">â€Google Payments این نوع کارت را پشتیبانی نمی‌کند. لطÙاً کارت دیگری انتخاب کنید.</translation>
<translation id="8550022383519221471">خدمات همگام‌سازی برای دامنهٔ شما موجود نیست.</translation>
<translation id="8553075262323480129">ترجمه انجام نشد زیرا زبان صÙحه تعیین نشد.</translation>
@@ -633,15 +675,12 @@
<translation id="8647750283161643317">بازنشانی همه به موارد پیش‌Ùرض</translation>
<translation id="8680787084697685621">جزئیات ورود به سیستم حساب قدیمی است.</translation>
<translation id="8703575177326907206">اتصال شما به <ph name="DOMAIN" /> رمزگذاری نشده است.</translation>
-<translation id="8713130696108419660">امضای اولیه خراب</translation>
<translation id="8725066075913043281">سعی مجدد</translation>
<translation id="8728672262656704056">به صورت ناشناس وارد شدید</translation>
<translation id="8730621377337864115">تمام</translation>
<translation id="8738058698779197622">â€Ø¨Ù‡ منظور برقراری یک اتصال امن، لازم است Ú©Ù‡ ساعت شما به درستی تنظیم شود. زیرا گواهینامه‌هایی Ú©Ù‡ وب‌سایت‌ها برای شناسایی خودشان استÙاده می‌کنند تنها برای دوره‌های زمانی خاصی معتبر هستند. از آنجایی Ú©Ù‡ ساعت دستگاه نادرست است، Chromium نمی‌تواند این گواهینامه‌ها را تأیید کند.</translation>
<translation id="8740359287975076522">â€<ph name="HOST_NAME" />’s &lt;abbr id="dnsDefinition"&gt;آدرس DNS&lt;/abbr&gt; پیدا نشد. درحال بررسی برای تشخیص مشکل.</translation>
-<translation id="8741995161408053644">â€Ù…Ù…Ú©Ù† است حساب Google شما اشکال سابقه مرور دیگری در <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> داشته باشد.</translation>
<translation id="8790007591277257123">&amp;انجام مجدد حذÙ</translation>
-<translation id="8790687370365610530">â€Ø¨Ø±Ø§ÛŒ دریاÙت محتوای شخصی‌سازی‌شده پیشنهادی GoogleØŒ همگام‌سازی سابقه را روشن کنید.</translation>
<translation id="8798099450830957504">پیش‌Ùرض</translation>
<translation id="8804164990146287819">خط‌مشی رازداری</translation>
<translation id="8820817407110198400">نشانک‌ها</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">گواهی سرور منقضی شده است.</translation>
<translation id="8987927404178983737">ماه</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">سرور گواهی‌ای را ارائه کرده است Ú©Ù‡ با استÙاده از خط‌مشی Ø´ÙاÙیت گواهینامه به‌صورت عمومی نشان داده نشده است. برای برخی گواهی‌ها این یک مسئله ضروری است تا از قابل اعتماد بودن آن‌ها Ùˆ محاÙظت دربرابر مهاجمین اطمینان حاصل شود.</translation>
<translation id="9001074447101275817">پروکسی <ph name="DOMAIN" /> به نام کاربری و گذرواژه نیاز دارد.</translation>
<translation id="901974403500617787">پرچم‌هایی Ú©Ù‡ در تمام سیستم اعمال می‌شوند Ùقط توسط مالک قابل تنظیم هستند: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">این صÙحه به <ph name="TARGET_LANGUAGE" /> ترجمه شده است</translation>
<translation id="9038649477754266430">استÙاده از یک سرویس پیش‌بینی برای بار کردن سریع‌تر صÙحه‌ها</translation>
<translation id="9039213469156557790">علاوه بر این، این صÙحه دارای منابع دیگری است Ú©Ù‡ امن نیستند. دیگران می‌توانند در حین انتقال، این منابع را ببینند Ùˆ این منابع می‌توانند برای تغییر رÙتار صÙحه، توسط یک مهاجم تغییر داده شوند.</translation>
-<translation id="9049981332609050619">شما سعی کردید به <ph name="DOMAIN" /> دسترسی داشته باشید، اما سرور یک گواهی نامعتبر را نشان داد.</translation>
<translation id="9050666287014529139">عبارت عبور</translation>
<translation id="9065203028668620118">ویرایش</translation>
<translation id="9092364396508701805">صÙحه <ph name="HOST_NAME" /> کار نمی‌کند</translation>
diff --git a/chromium/components/strings/components_strings_fi.xtb b/chromium/components/strings/components_strings_fi.xtb
index ffec6e7641a..08e08caf598 100644
--- a/chromium/components/strings/components_strings_fi.xtb
+++ b/chromium/components/strings/components_strings_fi.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fi">
+<translation id="1008557486741366299">Ei nyt</translation>
<translation id="1015730422737071372">Lisätietoja</translation>
<translation id="1032854598605920125">Käännä myötäpäivään</translation>
<translation id="1038842779957582377">tuntematon nimi</translation>
+<translation id="1053591932240354961">Et voi siirtyä juuri nyt sivustolle <ph name="SITE" />, sillä se lähetti sekoitettuja tunnistetietoja, joita Google Chrome ei voi käsitellä. Verkkovirheet ja ‑hyökkäykset ovat yleensä väliaikaisia, joten voit todennäköisesti vierailla sivustolla myöhemmin. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">K&amp;umoa lisäys</translation>
<translation id="10614374240317010">Ei tallenneta</translation>
-<translation id="1064422015032085147">Verkkosivua isännöivä palvelin voi olla ylikuormitettu tai huollettavana.
- Jotta liiallinen liikenne ei pahentaisi tilannetta,
- pyynnöt tähän URL-osoitteeseen on estetty tilapäisesti.</translation>
<translation id="106701514854093668">Työpöytäkirjanmerkit</translation>
<translation id="1080116354587839789">Sovita leveyteen</translation>
+<translation id="1103124106085518534">Valmista toistaiseksi</translation>
<translation id="1103523840287552314">Käännä <ph name="LANGUAGE" /> aina</translation>
<translation id="1107591249535594099">Jos tämä ruutu on valittu, Chrome tallentaa kortin kopion tälle laitteelle, jotta lomakkeiden täyttö nopeutuu.</translation>
+<translation id="1111153019813902504">Uusimmat kirjanmerkit</translation>
<translation id="1113869188872983271">K&amp;umoa uudelleenjärjestely</translation>
+<translation id="1126551341858583091">Paikallisen tallennustilan koko on <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Käytännön välimuisti on OK</translation>
<translation id="113188000913989374">Viesti osoitteesta <ph name="SITE" />:</translation>
<translation id="1132774398110320017">Chromen automaattisen täytön asetukset…</translation>
-<translation id="1150979032973867961">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; tietokoneesi käyttöjärjestelmä ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="1152921474424827756">Käytä osoitteen <ph name="URL" /> <ph name="BEGIN_LINK" />välimuistiversiota<ph name="END_LINK" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> katkaisi yhteyden yllättäen.</translation>
<translation id="1161325031994447685">Muodosta yhteys Wi-Fi-verkkoon uudelleen.</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Poista</translation>
<translation id="1201402288615127009">Seuraava</translation>
<translation id="1201895884277373915">Lisää tästä sivustosta</translation>
-<translation id="121201262018556460">Yritit yhdistää verkkotunnukseen <ph name="DOMAIN" />, mutta palvelin esitti varmenteen, joka käyttää heikkoa avainta. Hakkeri on saattanut murtaa avaimen. Palvelin ei siis välttämättä ole tavoittelemasi palvelin, vaan saatat viestiä hakkerin kanssa.</translation>
+<translation id="1206967143813997005">Virheellinen alkuperäinen allekirjoitus</translation>
+<translation id="1209206284964581585">Piilota toistaiseksi</translation>
<translation id="1219129156119358924">Järjestelmän suojaus</translation>
<translation id="1227224963052638717">Tuntematon käytäntö.</translation>
<translation id="1227633850867390598">Piilota arvo</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Kyllä</translation>
<translation id="1430915738399379752">Tulosta</translation>
<translation id="1442912890475371290">Estetty yritys <ph name="BEGIN_LINK" /> siirtyä sivulle <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Et voi siirtyä juuri nyt sivustolle <ph name="SITE" />, sillä se käyttää varmenteiden kiinnittämistä. Verkkovirheet ja ‑hyökkäykset ovat yleensä väliaikaisia, joten voit todennäköisesti vierailla sivustolla myöhemmin. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">Näytä tallennettu (eli vanhentuneeksi tiedetty) kopio tästä sivusta.</translation>
<translation id="1519264250979466059">Koontipäivä</translation>
<translation id="1549470594296187301">Tämän ominaisuuden käyttö edellyttää JavaScriptiä.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Verkkoasetukset ovat virheelliset eikä niitä voi tuoda.</translation>
<translation id="1644574205037202324">Historia</translation>
<translation id="1645368109819982629">Protokollaa ei tueta</translation>
-<translation id="1655462015569774233">{1,plural, =1{Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne vanhentui eilen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä. Tietokoneesi kellonaika on tällä hetkellä <ph name="CURRENT_DATE" />. Onko se oikein? Jos ei, korjaa järjestelmän kellonaika ja päivitä sivu.}other{Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne vanhentui # päivää sitten. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä. Tietokoneesi kellonaika on tällä hetkellä <ph name="CURRENT_DATE" />. Onko se oikein? Jos ei, korjaa järjestelmän kellonaika ja päivitä sivu.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> suojaa tietosi normaalisti salauksen avulla. Kun Chrome yritti tällä kertaa yhdistää sivustoon <ph name="SITE" />, sivusto palautti epätavalliset ja virheelliset kirjautumistiedot. Hyökkääjä saattaa yrittää esiintyä sivustona <ph name="SITE" />, tai Wi-Fi-kirjautumisruutu on keskeyttänyt yhteyden. Tietosi ovat edelleen turvassa, sillä Google Chrome katkaisi yhteyden, ennen kuin mitään tietoja vaihdettiin.</translation>
<translation id="168841957122794586">Palvelinvarmenne sisältää heikon salausavaimen.</translation>
<translation id="1701955595840307032">Lisää suositeltua sisältöä</translation>
-<translation id="1706954506755087368">{1,plural, =1{Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne on päivätty huomiselle. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.}other{Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne on päivätty # päivää tulevaisuuteen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.}}</translation>
<translation id="1710259589646384581">Käyttöjärjestelmä</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Ota yhteyttä järjestelmänvalvojaan.</translation>
<translation id="17513872634828108">Avoimet välilehdet</translation>
<translation id="1753706481035618306">Sivunumero</translation>
-<translation id="1761412452051366565">Ota synkronointi käyttöön, niin voit lisätä Googlen suosittelemaa sisältöä.</translation>
-<translation id="1763864636252898013">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; laitteesi käyttöjärjestelmä ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Kokeile Windowsin verkon diagnostiikkaa<ph name="END_LINK" /></translation>
<translation id="1783075131180517613">Päivitä synkronoinnin tunnuslause.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Viimeksi käyttämäsi kirjanmerkit näkyvät tässä.</translation>
<translation id="1821930232296380041">Pyyntö on virheellinen tai pyynnön parametrit ovat virheelliset</translation>
<translation id="1838667051080421715">Katselet verkkosivun lähdekoodia.</translation>
<translation id="1871208020102129563">Välityspalvelin on asetettu käyttämään kiinteitä välityspalvelimia, ei .pac-URL-osoitetta.</translation>
<translation id="1883255238294161206">Tiivistä luettelo</translation>
<translation id="1898423065542865115">Suodatus</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> ei hyväksynyt kirjautumisvarmennettasi, tai kirjautumisvarmenteesi on voinut vanhentua.</translation>
<translation id="194030505837763158">Siirry osoitteeseen <ph name="LINK" /></translation>
<translation id="1962204205936693436">Verkkotunnuksen <ph name="DOMAIN" /> kirjanmerkit</translation>
<translation id="1973335181906896915">Sarjaesittämisen virhe</translation>
<translation id="1974060860693918893">Lisäasetukset</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{ja 1 muu}other{ja # muuta}}</translation>
<translation id="2025186561304664664">Välityspalvelimen asetus: automaattisesti määritetty.</translation>
<translation id="2030481566774242610">Tarkoititko: <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Tämä viesti näytetään, koska vanhempiesi täytyy hyväksyä uudet sivustot ennen ensimmäistä lataamista.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Tarkista välityspalvelimen ja palomuurin määritykset.<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Postinumero</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 ehdotus}other{# ehdotusta}}</translation>
<translation id="2065985942032347596">Käyttöoikeustarkistus pakollinen</translation>
<translation id="2079545284768500474">Kumoa</translation>
<translation id="20817612488360358">Järjestelmän välityspalvelinasetukset on määritetty käytettäviksi, mutta erilliset välityspalvelimen asetukset on myös määritetty.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Muokkaa kirjanmerkkiä</translation>
<translation id="2166049586286450108">Järjestelmänvalvojan täydet käyttöoikeudet</translation>
<translation id="2166378884831602661">Tämä sivusto ei voi tarjota suojattua yhteyttä</translation>
-<translation id="2171101176734966184">Yritit yhdistää verkkotunnukseen <ph name="DOMAIN" />, mutta palvelin esitti varmenteen, joka käyttää heikkoa allekirjoitusalgoritmia. Tämä tarkoittaa sitä, että palvelimen esittämät tunnistetiedot saattavat olla väärennettyjä. Palvelin ei siis välttämättä ole tavoittelemasi palvelin, vaan saatat viestiä hakkerin kanssa.</translation>
<translation id="2181821976797666341">Käytännöt</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 osoite}other{# osoitetta}}</translation>
<translation id="2212735316055980242">Käytäntöä ei löydy</translation>
<translation id="2213606439339815911">Noudetaan merkintöjä…</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> ei ole käytettävissä</translation>
<translation id="2230458221926704099">Korjaa yhteytesi käyttämällä <ph name="BEGIN_LINK" />diagnostiikkasovellusta<ph name="END_LINK" />.</translation>
+<translation id="2239100178324503013">Lähetä nyt</translation>
<translation id="225207911366869382">Tämän käytännön arvo on vanhentunut.</translation>
<translation id="2262243747453050782">HTTP-virhe</translation>
<translation id="2282872951544483773">Ei käytettävissä olevat kokeilut</translation>
<translation id="2292556288342944218">Internetyhteytesi on estetty</translation>
<translation id="229702904922032456">Pää- tai keskitason varmenne on vanhentunut.</translation>
<translation id="230155334948463882">Uusi kortti?</translation>
+<translation id="2305919008529760154">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />. Sen suojausvarmenne on ehkä myönnetty vilpillisesti. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> pyytää käyttäjänimeä ja salasanaa.</translation>
+<translation id="2318774815570432836">Et juuri nyt voi siirtyä sivustolle <ph name="SITE" />, sillä se käyttää HSTS:ää. Verkkovirheet ja ‑hyökkäykset ovat yleensä väliaikaisia, joten voit todennäköisesti vierailla sivustolla myöhemmin. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">Ohitettiin virheellinen kirjanmerkki kohdassa <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Muut kirjanmerkit</translation>
<translation id="2359808026110333948">Jatka</translation>
<translation id="2365563543831475020">Kaatumisraportti tallennettu <ph name="CRASH_TIME" />, ei vielä lähetetty</translation>
<translation id="2367567093518048410">Taso</translation>
+<translation id="2371153335857947666">{1,plural, =1{Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenne vanhentui eilen. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. Tietokoneesi kellonaika on tällä hetkellä <ph name="CURRENT_DATE" />. Onko se oikein? Jos ei, korjaa järjestelmän kellonaika ja päivitä sivu. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" />}other{Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenne vanhentui # päivää sitten. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. Tietokoneesi kellonaika on tällä hetkellä <ph name="CURRENT_DATE" />. Onko se oikein? Jos ei, korjaa järjestelmän kellonaika ja päivitä sivu. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">Käyttöliittymävaihtoehtoja ei ole saatavilla</translation>
<translation id="2384307209577226199">Yrityksen oletus</translation>
-<translation id="238526402387145295">Et voi siirtyä sivustoon <ph name="SITE" /> juuri nyt, koska sivusto <ph name="BEGIN_LINK" />käyttää HSTS:ää<ph name="END_LINK" />. Verkkovirheet ja hyökkäykset ovat yleensä väliaikaisia, joten sivu luultavasti toimii myöhemmin.</translation>
<translation id="2386255080630008482">Palvelimen varmenne on kumottu.</translation>
<translation id="2392959068659972793">Näytä käytännöt, joille ei ole asetettu arvoa</translation>
<translation id="2396249848217231973">K&amp;umoa poisto</translation>
-<translation id="2413528052993050574">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne ei välttämättä ole voimassa. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="2455981314101692989">Tämä verkkosivu on poistanut tämän lomakkeen automaattisen täytön käytöstä.</translation>
+<translation id="2463739503403862330">Täytä</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />verkon diagnostiikkaa<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Virheellinen hakukoneen URL-osoite.</translation>
<translation id="2491120439723279231">Palvelimen varmenteessa on virheitä.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Lähetä</translation>
<translation id="2674170444375937751">Haluatko varmasti poistaa nämä sivut historiastasi?</translation>
<translation id="2677748264148917807">Poistu</translation>
+<translation id="269990154133806163">Palvelimen lähettämän varmenteen tietoja ei ole annettu yleiseen käyttöön Certificate Transparency ‑käytännön mukaisesti. Tietojen antamista edellytetään joitakin varmenteita käytettäessä, jotta niiden luotettavuus voidaan varmistaa ja käyttäjiä voidaan suojella hakkereilta. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">Arvo ei vastaa muotoa.</translation>
<translation id="2704951214193499422">Chromium ei voinut vahvistaa korttiasi. Yritä myöhemmin uudelleen.</translation>
<translation id="2705137772291741111">Tämän sivuston välimuistiin tallennettu kopio oli lukukelvoton.</translation>
<translation id="2709516037105925701">Automaattinen täyttö</translation>
+<translation id="2712118517637785082">Yritit muodostaa yhteyden verkkotunnukseen <ph name="DOMAIN" />, mutta varmenteen myöntäjä on peruuttanut palvelimen esittämän varmenteen. Palvelimen esittämiin tunnistetietoihin ei missään tapauksessa tule luottaa. Saatat olla tekemisissä hakkerin kanssa. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">Pyydä käyttölupaa</translation>
<translation id="2721148159707890343">Pyyntö onnistui</translation>
<translation id="2728127805433021124">Palvelimen varmenne on allekirjoitettu heikolla allekirjoitusalgoritmilla.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Osoite- ja hakupalkki</translation>
<translation id="2826760142808435982">Yhteys on salattu ja todennettu <ph name="CIPHER" />:n avulla ja se käyttää menetelmää <ph name="KX" /> avainvaihtomekanismina.</translation>
<translation id="2835170189407361413">Tyhjennä lomake</translation>
-<translation id="2837049386027881519">Yhteyden muodostamista täytyi yrittää uudelleen TLS- tai SSL-protokollan vanhemmalla versiolla. Yleensä tämä johtuu siitä, että palvelin käyttää vanhentunutta ohjelmistoa. Palvelimen suojaus ei välttämättä ole ajan tasalla.</translation>
<translation id="284702764277384724">Sivustolla <ph name="HOST_NAME" /> oleva palvelimen varmenne vaikuttaa väärennökseltä.</translation>
<translation id="2889159643044928134">Älä päivitä</translation>
-<translation id="2896499918916051536">Tätä laajennusta ei tueta.</translation>
+<translation id="2900469785430194048">Google Chromen muisti loppui verkkosivua näytettäessä.</translation>
<translation id="2909946352844186028">Verkossa havaittiin muutos.</translation>
-<translation id="2915500479781995473">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne on vanhentunut. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä. Tietokoneesi kellon aika on tällä hetkellä <ph name="CURRENT_TIME" />. Onko se oikeassa? Jos ei, siirrä kello oikeaan aikaan ja päivitä sivu.</translation>
<translation id="2922350208395188000">Palvelimen varmennetta ei voi tarkistaa.</translation>
-<translation id="2941952326391522266">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne on verkkotunnuksesta <ph name="DOMAIN2" />. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="2948083400971632585">Voit poistaa yhteydelle määritetyt välityspalvelimet käytöstä asetussivulla.</translation>
<translation id="2955913368246107853">Sulje hakupalkki</translation>
<translation id="2958431318199492670">Verkkoasetukset eivät noudata ONC-standardia. Kaikkia asetuksia ei välttämättä tuoda.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Väärä käytäntötyyppi</translation>
<translation id="3032412215588512954">Haluatko päivittää tämän sivuston?</translation>
<translation id="3037605927509011580">Voi räkä!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{vähintään 1 kohde synkronoiduilla laitteilla}=1{1 kohde (ja lisää synkronoiduilla laitteilla)}other{# kohdetta (ja lisää synkronoiduilla laitteilla)}}</translation>
<translation id="3041612393474885105">Varmenteen tiedot</translation>
<translation id="3063697135517575841">Chrome ei voinut vahvistaa korttiasi. Yritä myöhemmin uudelleen.</translation>
<translation id="3093245981617870298">Olet offline-tilassa.</translation>
@@ -207,15 +210,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Uusin</translation>
<translation id="3207960819495026254">Kirjanmerkeissä</translation>
-<translation id="3225919329040284222">Palvelin esitti varmenteen, joka ei vastaa sisäänrakennettuja odotuksia. Tietyillä tehokkaasti suojatuilla sivustoilla on odotuksia, joilla suojataan käyttäjiä.</translation>
<translation id="3226128629678568754">Paina päivityspainiketta, niin sivun lataukseen tarvittavat tiedot lähetetään uudelleen.</translation>
<translation id="3228969707346345236">Käännös epäonnistui, koska sivun kieli on jo <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Anna kortin <ph name="CREDIT_CARD" /> CVC</translation>
<translation id="3254409185687681395">Luo kirjanmerkki tälle sivulle</translation>
<translation id="3270847123878663523">K&amp;umoa uudelleenjärjestely</translation>
<translation id="3286538390144397061">Käynnistä uudelleen</translation>
+<translation id="3303855915957856445">Ei hakutuloksia</translation>
<translation id="3305707030755673451">Tietosi salattiin synkronoinnin tunnuslauseesi avulla <ph name="TIME" />. Aloita synkronointi antamalla tunnuslause.</translation>
<translation id="333371639341676808">Estä tätä sivua luomasta muita viestejä.</translation>
+<translation id="3338095232262050444">Turvallinen</translation>
<translation id="3340978935015468852">asetuksissa</translation>
<translation id="3345135638360864351">Tämän sivuston käyttöpyyntöä ei voitu lähettää henkilölle <ph name="NAME" />. Yritä uudelleen.</translation>
<translation id="3355823806454867987">Muuta välityspalvelimen asetuksia...</translation>
@@ -233,6 +237,7 @@
<translation id="3452404311384756672">Hakuväli:</translation>
<translation id="3462200631372590220">Piilota lisäasetukset</translation>
<translation id="3479539252931486093">Etkö odottanut tätä? <ph name="BEGIN_LINK" />Kerro siitä meille.<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Ei nyt</translation>
<translation id="348000606199325318">Kaatumistunnus: <ph name="CRASH_LOCAL_ID" /> (palvelintunnus: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Emme tavoittaneet vanhempaasi. Yritä uudelleen.</translation>
<translation id="3527085408025491307">Kansio</translation>
@@ -241,6 +246,7 @@
<translation id="3542684924769048008">Käytä salasanaa kohteeseen:</translation>
<translation id="3549644494707163724">Salaa kaikki synkronoidut tiedot oman synkronoinnin tunnuslauseesi avulla</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> lisää…</translation>
+<translation id="3555561725129903880">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenne on peräisin verkkotunnukselta <ph name="DOMAIN2" />. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">Yhteytesi ei ole salattu</translation>
<translation id="3583757800736429874">&amp;Toista siirto</translation>
<translation id="3586931643579894722">Piilota lisätiedot</translation>
@@ -252,12 +258,15 @@
<translation id="3623476034248543066">Näytä arvo</translation>
<translation id="3630155396527302611">Jos sillä on jo verkon käyttöoikeus, kokeile sen poistamista
sallittujen ohjelmien luettelosta ja lisäämistä sitten uudelleen.</translation>
+<translation id="3638794133396384728">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenne on vanhentunut. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. Tietokoneesi kellonaika on tällä hetkellä <ph name="CURRENT_TIME" />. Onko se oikein? Jos ei, korjaa järjestelmän kellonaika ja päivitä sivu. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">Nämä kokeelliset ominaisuudet voivat muuttua, rikkoutua tai kadota milloin tahansa. Emme takaa mitä tapahtuu, jos otat kokeiluja käyttöön – selaimesi saattaa jopa syttyä palamaan. Vitsit sikseen: selaimesi voi oikeasti poistaa kaikki tietosi, tai tietosuojasi voi vaarantua arvaamattomilla tavoilla. Kaikki tämän selaimen käyttäjät voivat käyttää käyttöön ottamiasi kokeiluita. Jatka omalla vastuullasi.</translation>
<translation id="3650584904733503804">Todennus onnistui</translation>
<translation id="3655670868607891010">Jos näet tämän usein, kokeile näitä <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Päivitetty versio</translation>
+<translation id="3678029195006412963">Pyynnön allekirjoittaminen epäonnistui.</translation>
<translation id="3681007416295224113">Varmenteen tiedot</translation>
<translation id="3693415264595406141">Salasana:</translation>
+<translation id="3696411085566228381">ei mitään</translation>
<translation id="3700528541715530410">Vaikuttaa siltä, että sinulla ei ole lupaa käyttää tätä sivua.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Ladataan...</translation>
@@ -265,7 +274,6 @@
<translation id="3714780639079136834">Ota mobiilidata tai Wi-Fi käyttöön.</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Tarkista välityspalvelimen, palomuurin ja nimipalvelun määritykset<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">Kopioimasi linkki</translation>
-<translation id="3744899669254331632">Et voi siirtyä sivustoon <ph name="SITE" /> tällä hetkellä, koska sivusto lähetti salatut kirjautumistiedot, joita Chromium ei osaa käsitellä. Verkkovirheet ja hyökkäykset ovat yleensä väliaikaisia, joten sivu toimii luultavasti myöhemmin.</translation>
<translation id="375403751935624634">Käännös epäonnistui palvelinvirheen vuoksi.</translation>
<translation id="3759461132968374835">Ei viimeaikaisia kaatumisilmoituksia. Jos selain kaatui kaatumisilmoitusten ollessa pois käytöstä, ilmoituksia ei näytetä täällä.</translation>
<translation id="3788090790273268753">Tämän sivuston varmenne vanhenee vuonna 2016, ja varmenneketju sisältää varmenteen, joka on allekirjoitettu SHA-1:llä.</translation>
@@ -277,19 +285,25 @@
<translation id="3884278016824448484">Ristiriitainen laitteen tunnus</translation>
<translation id="3885155851504623709">Kunta</translation>
<translation id="3901925938762663762">Kortti on vanhentunut.</translation>
+<translation id="3910267023907260648">Yritit muodostaa yhteyden verkkotunnukseen <ph name="DOMAIN" />, mutta palvelimen esittämä varmenne käyttää heikkoa allekirjoitusalgoritmia. Palvelimen esittämät tunnistetiedot on ehkä väärennetty, eikä palvelin välttämättä ole tavoittelemasi palvelin (saatat olla tekemisissä hakkerin kanssa). <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenne on päivätty huomiselle. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" />}other{Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenne on päivätty # päivää tulevaisuuteen. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">PDF-asiakirjan lataaminen epäonnistui</translation>
<translation id="3963721102035795474">Lukijatila</translation>
+<translation id="397105322502079400">Lasketaan...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> on estetty</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 verkkosivu lähistöllä}other{# verkkosivua lähistöllä}}</translation>
<translation id="4021036232240155012">DNS on verkkopalvelu, joka kääntää verkkosivuston nimen sen internetosoitteeksi.</translation>
<translation id="4030383055268325496">K&amp;umoa lisäys</translation>
-<translation id="4032534284272647190">Pääsy sivulle <ph name="URL" /> kielletty.</translation>
<translation id="404928562651467259">Varoitus</translation>
<translation id="4058922952496707368">Avain <ph name="SUBKEY" />: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Asiakassovellus ja palvelin eivät tue samaa SSL-protokollaversiota tai salaustekniikkaa.</translation>
<translation id="4079302484614802869">Välityspalvelinmääritykset on asetettu käyttämään .pac-URL-osoitteita, ei kiinteitä välityspalvelimia.</translation>
<translation id="4103249731201008433">Laitteen sarjanumero on virheellinen</translation>
<translation id="4103763322291513355">Voit lukea listan kielletyistä URL-osoitteista ja muut järjestelmänvalvojasi määräämät käytännöt osoitteessa &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
+<translation id="4110615724604346410">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenteessa on virheitä. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">Käytännön laajuutta ei tueta.</translation>
+<translation id="4118212371799607889">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä Chromium ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 muu}other{# muuta}}</translation>
<translation id="4130226655945681476">Tarkista verkkojohdot, modeemi ja reititin.</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Haluatko, että Chromium tallentaa tämän kortin?</translation>
@@ -297,6 +311,7 @@
<translation id="4176463684765177261">Pois käytöstä</translation>
<translation id="4196861286325780578">&amp;Toista siirto</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Tarkista palomuurin ja virustorjuntaohjelmiston määritykset.<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{ei yhtään}=1{1 sovellus ($1)}=2{2 sovellusta ($1 ja $2)}other{# sovellusta ($1, $2 $3)}}</translation>
<translation id="4220128509585149162">Kaatuu</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Kokeile verkon diagnostiikkaa<ph name="END_LINK" /></translation>
<translation id="4250680216510889253">Ei</translation>
@@ -305,14 +320,15 @@
<translation id="4269787794583293679">(Ei käyttäjänimeä)</translation>
<translation id="4300246636397505754">Ylätason ehdotukset</translation>
<translation id="4304224509867189079">Kirjaudu sisään</translation>
+<translation id="432290197980158659">Palvelimen esittämä varmenne ei vastaa sisäänrakennettuja odotuksia. Tietyillä tehokkaasti suojatuilla verkkosivustoilla on odotuksia, joilla suojataan käyttäjiä. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">Artikkelia ei löydy</translation>
+<translation id="4331708818696583467">Ei turvallinen</translation>
<translation id="4372948949327679948">Odotettu <ph name="VALUE_TYPE" />-arvo.</translation>
-<translation id="4377125064752653719">Yritit yhdistää sivustoon <ph name="DOMAIN" />, mutta varmenteen myöntäjä on kumonnut palvelimen esittämän varmenteen. Palvelimen esittämiin suojaustietoihin ei siis tule luottaa. Saatat olla tekemisissä hakkerin kanssa.</translation>
<translation id="4381091992796011497">Käyttäjätunnus:</translation>
<translation id="4394049700291259645">Poista käytöstä</translation>
<translation id="4395129973926795186"><ph name="START_DATE" />–<ph name="END_DATE" /></translation>
<translation id="4406896451731180161">hakutulokset</translation>
-<translation id="4424024547088906515">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; Chrome ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> ei hyväksynyt kirjautumisvarmennettasi, tai varmennetta ei annettu.</translation>
<translation id="443673843213245140">Välityspalvelinta ei saa käyttää, mutta erilliset välityspalvelimen asetukset on määritetty.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Tämä viesti näytetään, koska Google SafeSites on käytössä.</translation>
@@ -324,12 +340,12 @@
<translation id="4522570452068850558">Tiedot</translation>
<translation id="4558551763791394412">Poista laajennukset käytöstä.</translation>
<translation id="4587425331216688090">Poistetaanko osoite Chromen tiedoista?</translation>
+<translation id="4589078953350245614">Yritit muodostaa yhteyden verkkotunnukseen <ph name="DOMAIN" />, mutta palvelin esitti virheellisen varmenteen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459">Yhteytesi kohteeseen <ph name="DOMAIN" /> on salattu nykyaikaisella salaustekniikalla.</translation>
<translation id="4594403342090139922">K&amp;umoa poisto</translation>
+<translation id="4627442949885028695">Jatka siitä, mihin jäit toisella laitteella</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Katselet laajennussivua.</translation>
-<translation id="467662567472608290">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne sisältää virheitä. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> estettiin</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Yhteys keskeytyi</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windowsin verkon diagnostiikkaa<ph name="END_LINK" /></translation>
@@ -337,21 +353,26 @@
<translation id="4728558894243024398">Käyttöympäristö</translation>
<translation id="4744603770635761495">Suoritettavan tiedoston polku</translation>
<translation id="4756388243121344051">&amp;Historia</translation>
+<translation id="4759238208242260848">Lataukset</translation>
<translation id="4764776831041365478">Osoitteessa <ph name="URL" /> oleva sivu saattaa olla väliaikaisesti pois käytöstä tai se on voitu siirtää pysyvästi uuteen osoitteeseen.</translation>
<translation id="4771973620359291008">Tapahtui tuntematon virhe.</translation>
<translation id="4782449893814226250">Pyysit vanhemmiltasi lupaa käydä tällä sivulla.</translation>
<translation id="4800132727771399293">Tarkista vanhenemispäivä ja CVC ja yritä uudelleen.</translation>
-<translation id="4807049035289105102">Et voi siirtyä sivustoon <ph name="SITE" /> juuri nyt, koska sivusto lähetti sekoitetut kirjautumistiedot, joita Google Chrome ei voi käsitellä. Verkkovirheet ja hyökkäykset ovat yleensä väliaikaisia, joten sivu luultavasti toimii myöhemmin.</translation>
<translation id="4813512666221746211">Verkkovirhe</translation>
<translation id="4816492930507672669">Sovita sivulle</translation>
<translation id="4850886885716139402">Näytä</translation>
<translation id="4880827082731008257">Haku historiasta</translation>
+<translation id="4884656795097055129">Muita artikkeleita tulee näkyviin myöhemmin.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{ja 1 muu verkkosivu}other{ja # muuta verkkosivua}}</translation>
<translation id="4923417429809017348">Tämä sivu on käännetty tuntemattomasta kielestä kielelle <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">On määritettävä.</translation>
<translation id="4930497775425430760">Tämä viesti näytetään, koska vanhempasi täytyy hyväksyä uudet sivustot ennen ensimmäistä lataamista.</translation>
<translation id="495170559598752135">Toiminnot</translation>
<translation id="4958444002117714549">Laajenna luettelo</translation>
+<translation id="4962322354953122629">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä Chrome ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911">Käännetäänkö kielestä <ph name="ORIGINAL_LANGUAGE" /> kielelle <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Tätä laajennusta ei tueta.</translation>
<translation id="5002932099480077015">Kun tämä vaihtoehto on käytössä, Chrome nopeuttaa lomakkeiden täyttämistä tallentamalla kortin tiedot tälle laittelle.</translation>
<translation id="5019198164206649151">Tallennustila on virheellisessä tilassa</translation>
<translation id="5023310440958281426">Tarkista järjestelmänvalvojan käytännöt</translation>
@@ -359,13 +380,12 @@
<translation id="5031870354684148875">Tietoja Google-kääntäjästä</translation>
<translation id="5040262127954254034">Tietosuoja</translation>
<translation id="5045550434625856497">Väärä salasana</translation>
+<translation id="5056549851600133418">Sinulle valitut artikkelit</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Tarkista välityspalvelimen osoite.<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Palvelimen varmenne ei ole tällä hetkellä kelvollinen.</translation>
<translation id="5089810972385038852">Osavaltio/alue</translation>
-<translation id="5094747076828555589">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; Chromium ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="5095208057601539847">Provinssi</translation>
<translation id="5115563688576182185">(64-bittinen)</translation>
-<translation id="5122371513570456792">Haku <ph name="SEARCH_STRING" /> tuotti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" />.</translation>
<translation id="5141240743006678641">Salaa synkronoidut salasanat Google-kirjautumistietojesi avulla</translation>
<translation id="5145883236150621069">Käytäntövastaus sisältää virhekoodin</translation>
<translation id="5171045022955879922">Kirjoita hakusanoja tai URL-osoite</translation>
@@ -374,18 +394,18 @@
<translation id="5190835502935405962">Kirjanmerkkipalkki</translation>
<translation id="5199729219167945352">Kokeilut</translation>
<translation id="5251803541071282808">Pilvi</translation>
+<translation id="5277279256032773186">Käytätkö Chromea töissä? Yritykset voivat hallita Chromen asetuksia työntekijöidensä puolesta. Lisätietoja</translation>
<translation id="5299298092464848405">Virhe jäsennettäessä käytäntöä</translation>
<translation id="5300589172476337783">Näytä</translation>
<translation id="5308689395849655368">Kaatumisraportit on poistettu käytöstä.</translation>
<translation id="5317780077021120954">Tallenna</translation>
<translation id="5327248766486351172">Nimi</translation>
+<translation id="5359637492792381994">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenne ei ole tällä hetkellä voimassa. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Käytännön asetuksien tallentaminen epäonnistui</translation>
-<translation id="540969355065856584">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenne ei tällä hetkellä ole kelvollinen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="5421136146218899937">Poista selaustiedot...</translation>
<translation id="5430298929874300616">Poista kirjanmerkki</translation>
<translation id="5431657950005405462">Tiedostoasi ei löydy</translation>
<translation id="5435775191620395718">Näytetään tämän laitteen historia. <ph name="BEGIN_LINK" />Lisätietoja<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">Yksilölliset sisältöehdotukset eivät ole tällä hetkellä käytössä, koska synkronoidut tietosi on suojattu omalla tunnuslauseella.</translation>
<translation id="5439770059721715174">Mallin todennusvirhe kohdassa <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Tätä sivuston <ph name="HOST_NAME" /> sivua ei löydy.</translation>
<translation id="5455374756549232013">Virheellinen käytännön aikaleima</translation>
@@ -408,14 +428,18 @@
<translation id="5622887735448669177">Haluatko poistua tältä sivustolta?</translation>
<translation id="5629630648637658800">Käytännön asetuksien lataaminen epäonnistui</translation>
<translation id="5631439013527180824">Laitteenhallintatunnus on virheellinen</translation>
-<translation id="5650551054760837876">Hakutuloksia ei löytynyt.</translation>
<translation id="5677928146339483299">Estetty</translation>
<translation id="5710435578057952990">Tämän sivuston identiteettiä ei ole vahvistettu.</translation>
<translation id="5720705177508910913">Nykyinen käyttäjä</translation>
+<translation id="572328651809341494">Hiljattain suljetut välilehdet</translation>
<translation id="5784606427469807560">Korttia vahvistettaessa tapahtui virhe. Tarkista internetyhteys ja yritä uudelleen.</translation>
<translation id="5785756445106461925">Tällä sivulla on kuitenkin muita osia, jotka eivät ole suojattuja. Muut voivat tarkastella näitä osia siirron aikana, ja hyökkääjä voi muuttaa sivun ulkoasua muokkaamalla näitä osia.</translation>
+<translation id="5786044859038896871">Täytetäänkö kortin tiedot?</translation>
+<translation id="5803412860119678065">Täytetäänkö kortin <ph name="CARD_DETAIL" /> tiedot?</translation>
<translation id="5810442152076338065">Yhteytesi kohteeseen <ph name="DOMAIN" /> on salattu vanhentuneella salaustekniikalla.</translation>
<translation id="5813119285467412249">&amp;Toista lisäys</translation>
+<translation id="5814352347845180253">Saatat menettää esim. sivuston <ph name="SITE" /> maksullisen sisällön käyttöoikeuden.</translation>
+<translation id="5843436854350372569">Yritit muodostaa yhteyden verkkotunnukseen <ph name="DOMAIN" />, mutta palvelimen esittämä varmenne sisältää heikon avaimen. Hakkeri on ehkä murtanut yksityisen avaimen, eikä palvelin välttämättä ole tavoittelemasi palvelin (saatat olla tekemisissä hakkerin kanssa). <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">Tämä viesti näytetään, koska ylläpitäjä esti tämän sivuston.</translation>
<translation id="5857090052475505287">Uusi kansio</translation>
<translation id="5869405914158311789">Sivustoon ei saada yhteyttä</translation>
@@ -423,6 +447,7 @@
<translation id="5872918882028971132">Ylätason ehdotukset</translation>
<translation id="59107663811261420">Google Payments ei tue tämän tyyppisen kortin käyttämistä ostoksien tekemiseen tältä myyjältä. Valitse eri kortti.</translation>
<translation id="59174027418879706">Käytössä</translation>
+<translation id="5926846154125914413">Saatat menettää joidenkin sivustojen maksullisen sisällön käyttöoikeuden.</translation>
<translation id="5966707198760109579">Viikko</translation>
<translation id="5967867314010545767">Poista historiasta</translation>
<translation id="5975083100439434680">Loitonna</translation>
@@ -434,12 +459,12 @@
<translation id="604124094241169006">Automaattinen</translation>
<translation id="6042308850641462728">Lisää</translation>
<translation id="6060685159320643512">Varoitus, nämä kokeilut saattavat puraista</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{ei yhtään}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Tarkista kaikki kaapelit ja käynnistä uudelleen reitittimet, modeemit ja muut
käytössä olevat verkkolaitteet.</translation>
<translation id="614940544461990577">Kokeile seuraavia toimenpiteitä:</translation>
<translation id="6150607114729249911">Hups! Sinun on pyydettävä vanhempiesi lupa tällä sivulla käymiseen.</translation>
<translation id="6151417162996330722">Palvelimen varmenteen voimassaoloaika on liian pitkä.</translation>
-<translation id="6154808779448689242">Palautettu käytännön tunnus ei vastaa nykyistä tunnusta</translation>
<translation id="6165508094623778733">Lisätietoja</translation>
<translation id="6203231073485539293">Tarkista internetyhteytesi</translation>
<translation id="6218753634732582820">Poistetaanko osoite Chromiumista?</translation>
@@ -452,24 +477,30 @@
<translation id="6328639280570009161">Kokeile verkon ennakoinnin poistamista käytöstä.</translation>
<translation id="6337534724793800597">Suodata käytäntöjä nimen mukaan</translation>
<translation id="6342069812937806050">Valmistui juuri</translation>
+<translation id="6345221851280129312">tuntematon koko</translation>
<translation id="6355080345576803305">Julkisen istunnon ohitus</translation>
<translation id="6358450015545214790">Mitä nämä tarkoittavat?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 muu ehdotus}other{# muuta ehdotusta}}</translation>
<translation id="6387478394221739770">Oletko kiinnostunut Chromen uusista jännittävistä ominaisuuksista? Kokeile beta-kanavaa osoitteessa chrome.com/beta.</translation>
-<translation id="641480858134062906"><ph name="URL" />-lataus epäonnistui</translation>
+<translation id="6389758589412724634">Chromiumin muisti loppui verkkosivua näytettäessä.</translation>
+<translation id="6416403317709441254">Et voi juuri nyt siirtyä sivustolle <ph name="SITE" />, sillä se lähetti sekoitettuja tunnistetietoja, joita Chromium ei voi käsitellä. Verkkovirheet ja ‑hyökkäykset ovat yleensä väliaikaisia, joten voit todennäköisesti vierailla sivustolla myöhemmin. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">Ei voida tarkistaa, onko varmenne kumottu.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> kieltäytyi muodostamasta yhteyttä.</translation>
<translation id="6445051938772793705">Maa</translation>
<translation id="6451458296329894277">Vahvista lomakkeen uudelleenlähetys</translation>
<translation id="6458467102616083041">Ohitettu, koska oletushaku on poistettu käytöstä käytännön mukaan.</translation>
+<translation id="6462969404041126431">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />. Sen suojausvarmenne on ehkä peruutettu. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Laitekäytännöt</translation>
<translation id="6489534406876378309">Aloita kaatumistietojen lähettäminen</translation>
<translation id="6529602333819889595">&amp;Toista poisto</translation>
+<translation id="6534179046333460208">Fyysisen webin ehdotukset</translation>
<translation id="6550675742724504774">Asetukset</translation>
+<translation id="6593753688552673085">alle <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Salausasetukset</translation>
<translation id="662080504995468778">Jää</translation>
<translation id="6628463337424475685"><ph name="ENGINE" />-haku</translation>
-<translation id="6634865548447745291">Et voi siirtyä sivustoon <ph name="SITE" /> juuri nyt, koska <ph name="BEGIN_LINK" />tämä varmenne on kumottu<ph name="END_LINK" />. Verkkovirheet ja hyökkäykset ovat yleensä väliaikaisia, joten sivu luultavasti toimii myöhemmin.</translation>
<translation id="6644283850729428850">Tämä käytäntö on vanhentunut.</translation>
+<translation id="6652240803263749613">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä tietokoneesi käyttöjärjestelmä ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">Muokkaa kansiota</translation>
<translation id="6660210980321319655">Ilmoitus tehtiin automaattisesti <ph name="CRASH_TIME" />.</translation>
<translation id="6671697161687535275">Poistetaanko lomake-ehdotus Chromiumista?</translation>
@@ -477,6 +508,7 @@
<translation id="6710213216561001401">Edellinen</translation>
<translation id="6710594484020273272">&lt;Anna hakukysely&gt;</translation>
<translation id="6711464428925977395">Välityspalvelimessa on jotain vikaa tai osoite on virheellinen.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{ei yhtään}=1{1 kohde}other{# kohdetta}}</translation>
<translation id="674375294223700098">Tuntematon palvelimen varmennevirhe.</translation>
<translation id="6753269504797312559">Käytännön arvo</translation>
<translation id="6757797048963528358">Laitteesi siirtyi virransäästötilaan.</translation>
@@ -488,7 +520,6 @@
<translation id="6891596781022320156">Käytännön tasoa ei tueta.</translation>
<translation id="6895330447102777224">Korttisi vahvistettiin.</translation>
<translation id="6897140037006041989">User agent</translation>
-<translation id="6903907808598579934">Ota synkronointi käyttöön</translation>
<translation id="6915804003454593391">Käyttäjä:</translation>
<translation id="6957887021205513506">Palvelimen varmenne näyttää olevan väärennös.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -496,9 +527,11 @@
<translation id="6970216967273061347">Alue</translation>
<translation id="6973656660372572881">Sekä kiinteät välityspalvelimet että .pac-URL-osoite on määritetty.</translation>
<translation id="6989763994942163495">Näytä lisäasetukset...</translation>
+<translation id="7000990526846637657">Historiamerkintöjä ei löytynyt</translation>
+<translation id="7009986207543992532">Yritit muodostaa yhteyden verkkotunnukseen <ph name="DOMAIN" />, mutta palvelimen esittämän varmenteen voimassaoloaika on epäilyttävän pitkä. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Google-tililläsi voi olla muita selaushistoriatietoja osoitteessa <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="7029809446516969842">Salasanat</translation>
-<translation id="7050187094878475250">Yritit muodostaa yhteyden verkkotunnukseen <ph name="DOMAIN" />, mutta palvelin esitti varmenteen, joka on voimassa liian kauan ollakseen luotettava.</translation>
<translation id="7087282848513945231">Kunta</translation>
<translation id="7088615885725309056">Vanhempi</translation>
<translation id="7090678807593890770">Tee Google-haku: <ph name="LINK" /></translation>
@@ -517,13 +550,13 @@
<translation id="7246609911581847514">Tämä viesti näytetään, koska ylläpitäjän täytyy hyväksyä uudet sivustot ennen ensimmäistä lataamista.</translation>
<translation id="724975217298816891">Päivitä kortin <ph name="CREDIT_CARD" /> tiedot antamalla sen CVC ja vanhenemispäivämäärä. Vahvistamisen jälkeen korttisi tiedot jaetaan sivuston kanssa.</translation>
<translation id="725866823122871198">Verkkotunnukseen <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ei voi muodostaa salattua yhteyttä, koska tietokoneesi aika ja päivämäärä (<ph name="DATE_AND_TIME" />) ovat virheelliset.</translation>
-<translation id="7265986070661382626">Et voi siirtyä sivustoon <ph name="SITE" /> juuri nyt, koska sivusto <ph name="BEGIN_LINK" />käyttää varmenteiden kiinnittämistä<ph name="END_LINK" />. Verkkovirheet ja hyökkäykset ovat yleensä väliaikaisia, joten sivu luultavasti toimii myöhemmin.</translation>
<translation id="7269802741830436641">Tällä verkkosivulla on uudelleenohjaussilmukka</translation>
<translation id="7275334191706090484">Hallinnoidut kirjanmerkit</translation>
<translation id="7298195798382681320">Suositus</translation>
-<translation id="7301833672208172928">Ota historian synkronointi käyttöön</translation>
+<translation id="7309308571273880165">Kaatumisraportti tallennettu <ph name="CRASH_TIME" /> (käyttäjä pyysi latausta, ei vielä ladattu)</translation>
<translation id="7334320624316649418">&amp;Toista uudelleenjärjestely</translation>
<translation id="733923710415886693">Palvelimen varmenteesta ei ole saatu Certificate Transparencyn vaatimia tietoja.</translation>
+<translation id="7351800657706554155">Et voi juuri nyt siirtyä sivustolle <ph name="SITE" />, sillä sen varmenne on peruutettu. Verkkovirheet ja ‑hyökkäykset ovat yleensä väliaikaisia, joten voit todennäköisesti vierailla sivustolla myöhemmin. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">Komentorivi</translation>
<translation id="7372973238305370288">hakutulos</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -542,16 +575,17 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="7469372306589899959">Vahvistetaan korttia</translation>
<translation id="7481312909269577407">Seuraava</translation>
<translation id="7485870689360869515">Tietoja ei löydy.</translation>
+<translation id="7508255263130623398">Palautettu käytännön laitetunnus on tyhjä tai ei vastaa nykyistä laitetunnusta.</translation>
<translation id="7514365320538308">Lataa</translation>
<translation id="7518003948725431193">Verkkosivua ei löytynyt osoitteelle: <ph name="URL" /></translation>
<translation id="7537536606612762813">Pakollinen</translation>
<translation id="7542995811387359312">Automaattinen luottokortin tietojen täyttäminen on poistettu käytöstä, koska tämä lomake ei käytä suojattua yhteyttä.</translation>
<translation id="7549584377607005141">Tämän sivun näyttäminen oikein edellyttää aiemmin lähetettyjä tietoja. Voit lähettää tiedot uudelleen, mutta tällöin sivulla mahdollisesti suoritettu toiminto toistetaan.</translation>
<translation id="7554791636758816595">Uusi välilehti</translation>
-<translation id="7567204685887185387">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne on ehkä luotu vilpillisesti. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="7568593326407688803">Tämä sivu on kirjoitettu kielellä<ph name="ORIGINAL_LANGUAGE" />Haluatko kääntää sen?</translation>
<translation id="7569952961197462199">Poistetaanko luottokortti Chromen tiedoista?</translation>
<translation id="7578104083680115302">Voit maksaa sivustoilla ja sovelluksissa nopeasti eri laitteillasi käyttämällä Googleen tallennettuja kortteja.</translation>
+<translation id="7588950540487816470">Fyysinen web</translation>
<translation id="7592362899630581445">Palvelimen varmenne rikkoo nimirajoituksia.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ei voi käsitellä tätä pyyntöä tällä hetkellä.</translation>
<translation id="7600965453749440009">Älä koskaan käännä kieltä <ph name="LANGUAGE" /></translation>
@@ -562,6 +596,7 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="7637571805876720304">Poistetaanko luottokortti Chromiumista?</translation>
<translation id="765676359832457558">Piilota lisäasetukset...</translation>
<translation id="7658239707568436148">Peruuta</translation>
+<translation id="7667346355482952095">Palautettu käytäntötunnus on tyhjä tai ei vastaa nykyistä tunnusta.</translation>
<translation id="7668654391829183341">Tuntematon laite</translation>
<translation id="7674629440242451245">Oletko kiinnostunut Chromen uusista jännittävistä ominaisuuksista? Kokeile kehittäjäkanavaa osoitteessa chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Siirry sivustoon <ph name="SITE" /> (tämä ei ole turvallista)<ph name="END_LINK" /></translation>
@@ -578,10 +613,10 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="780301667611848630">Ei kiitos</translation>
<translation id="7805768142964895445">Tila</translation>
<translation id="7813600968533626083">Poistetaanko lomake-ehdotus Chromen tiedoista?</translation>
+<translation id="7815407501681723534">Haku <ph name="SEARCH_STRING" /> tuotti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" />.</translation>
<translation id="785549533363645510">Et ole kuitenkaan näkymätön. Incognito-tilan käyttäminen ei kätke selaamistasi työnantajaltasi, internetpalveluntarjoajaltasi tai käyttämiltäsi sivustoilta.</translation>
<translation id="7887683347370398519">Tarkista CVC ja yritä uudelleen.</translation>
<translation id="7894616681410591072">Hups! Tarvitset ylläpitäjän <ph name="NAME" /> luvan tälle sivulle siirtymiseen.</translation>
-<translation id="790025292736025802"><ph name="URL" /> ei löydy</translation>
<translation id="7912024687060120840">Kansiossa:</translation>
<translation id="7920092496846849526">Pyysit vanhemmiltasi lupaa käydä tällä sivulla.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -594,9 +629,10 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="7995512525968007366">Ei määritetty</translation>
<translation id="8012647001091218357">Emme tavoittaneet vanhempiasi. Yritä uudelleen.</translation>
<translation id="8034522405403831421">Sivu on kirjoitettu kielellä <ph name="SOURCE_LANGUAGE" />. Haluatko kääntää sen kielelle <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Historiamerkintöjä ei löytynyt.</translation>
<translation id="8088680233425245692">Artikkelin näyttäminen epäonnistui.</translation>
+<translation id="8089520772729574115">alle 1 Mt</translation>
<translation id="8091372947890762290">Aktivointi odottaa palvelimella</translation>
+<translation id="8129262335948759431">tuntematon määrä</translation>
<translation id="8131740175452115882">Vahvista</translation>
<translation id="8134994873729925007">Isäntänimen <ph name="HOST_NAME" /> palvelimen <ph name="BEGIN_ABBR" />DNS-osoitetta<ph name="END_ABBR" /> ei löytynyt.</translation>
<translation id="8149426793427495338">Tietokoneesi siirtyi virransäästötilaan.</translation>
@@ -605,6 +641,7 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="8201077131113104583">Laajennuksella, jonka tunnus on <ph name="EXTENSION_ID" />, on virheellinen päivitys-URL-osoite.</translation>
<translation id="8218327578424803826">Määrätty sijainti:</translation>
<translation id="8225771182978767009">Tämän tietokoneen määrittänyt henkilö on estänyt tämän sivuston.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Etsimäsi sivu käytti antamiasi tietoja. Sivulle palaaminen voi johtaa jokaisen tekemäsi toiminnon toistamiseen. Haluatko jatkaa?</translation>
<translation id="8249320324621329438">Viimeksi haettu:</translation>
<translation id="8261506727792406068">Poista</translation>
@@ -617,12 +654,17 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="8349305172487531364">Kirjanmerkkipalkki</translation>
<translation id="8363502534493474904">Poista lentokonetila käytöstä.</translation>
<translation id="8364627913115013041">Ei määritetty.</translation>
+<translation id="8380941800586852976">Vaarallinen</translation>
<translation id="8412145213513410671">Kaatumiset (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Kirjoita sama tunnuslause kahdesti.</translation>
<translation id="8428213095426709021">Asetukset</translation>
+<translation id="8433057134996913067">Sinut kirjataan ulos useimmilta verkkosivustoilta.</translation>
<translation id="8437238597147034694">K&amp;umoa siirto</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 luottokortti}other{# luottokorttia}}</translation>
+<translation id="8483780878231876732">Jos haluat käyttää Google-tilillesi tallennettuja kortteja, kirjaudu Chromeen</translation>
<translation id="8488350697529856933">Käyttöalue</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ei vastannut riittävän nopeasti.</translation>
+<translation id="852346902619691059">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä laitteesi käyttöjärjestelmä ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai hyökkäyksestä, jonka tavoitteena on verkkoyhteytesi sieppaaminen. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Google Payments ei tue tämän tyyppistä korttia. Valitse eri kortti.</translation>
<translation id="8550022383519221471">Synkronointipalvelu ei ole käytettävissä verkkotunnuksessasi.</translation>
<translation id="8553075262323480129">Käännös epäonnistui, sillä sivun kieltä ei voitu määrittää.</translation>
@@ -634,15 +676,12 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="8647750283161643317">Palauta kaikki oletusarvoon</translation>
<translation id="8680787084697685621">Tilin kirjautumistiedot ovat vanhentuneet.</translation>
<translation id="8703575177326907206">Yhteyttäsi verkkotunnukseen <ph name="DOMAIN" /> ei ole salattu.</translation>
-<translation id="8713130696108419660">Virheelliset nimikirjaimet</translation>
<translation id="8725066075913043281">Yritä uudelleen</translation>
<translation id="8728672262656704056">Olet muuttunut näkymättömäksi</translation>
<translation id="8730621377337864115">Valmis</translation>
<translation id="8738058698779197622">Kellosi täytyy asettaa oikeaan aikaan, jotta salattu yhteys voidaan muodostaa. Tämä johtuu siitä, että verkkosivustojen tunnistamisessa käytettävät varmenteet ovat voimassa vain tiettyinä ajanjaksoina. Chromium ei voi vahvistaa varmenteita, koska laitteesi kello on väärässä ajassa.</translation>
<translation id="8740359287975076522">Sivuston <ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS-osoitetta&lt;/abbr&gt; ei löydy. Ongelmaa diagnosoidaan.</translation>
-<translation id="8741995161408053644">Google-tililläsi voi olla muita selaushistoriatietoja osoitteessa <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Toista poisto</translation>
-<translation id="8790687370365610530">Ota historian synkronointi käyttöön, niin voit lisätä Googlen suosittelemaa sisältöä.</translation>
<translation id="8798099450830957504">Oletus</translation>
<translation id="8804164990146287819">Tietosuojakäytäntö</translation>
<translation id="8820817407110198400">Kirjanmerkit</translation>
@@ -664,13 +703,11 @@ Psst! Suosittelemme käyttämään ensi kerralla incognito-tilaa <ph name="SHORT
<translation id="8971063699422889582">Palvelimen varmenne on vanhentunut.</translation>
<translation id="8987927404178983737">Kuukausi</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Palvelimen lähettämän varmenteen tietoja ei ole annettu yleiseen käyttöön Certificate Transparency ‑käytännön mukaisesti. Tietojen antamista edellytetään joiltakin varmenteilta, jotta niiden luotettavuus voidaan varmistaa ja käyttäjiä suojella hyökkääjiltä.</translation>
<translation id="9001074447101275817">Välityspalvelin <ph name="DOMAIN" /> vaatii käyttäjänimen ja salasanan.</translation>
<translation id="901974403500617787">Koko järjestelmään vaikuttavat merkinnät voi tehdä vain omistaja: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Sivu on käännetty kielelle <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Ennakointipalvelun avulla voit ladata sivuja nopeammin</translation>
<translation id="9039213469156557790">Tällä sivulla on kuitenkin muita osia, jotka eivät ole suojattuja. Muut voivat tarkastella näitä osia siirron aikana, ja hyökkääjä voi muuttaa sivun käyttäytymistä muokkaamalla näitä osia.</translation>
-<translation id="9049981332609050619">Yritit muodostaa yhteyden verkkotunnukseen <ph name="DOMAIN" />, mutta palvelin esitti virheellisen varmenteen.</translation>
<translation id="9050666287014529139">Tunnuslause</translation>
<translation id="9065203028668620118">Muokkaa</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" />-sivu ei toimi</translation>
diff --git a/chromium/components/strings/components_strings_fil.xtb b/chromium/components/strings/components_strings_fil.xtb
index a06597af2d9..da243c3ae72 100644
--- a/chromium/components/strings/components_strings_fil.xtb
+++ b/chromium/components/strings/components_strings_fil.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fil">
+<translation id="1008557486741366299">Hindi Ngayon</translation>
<translation id="1015730422737071372">Magbigay ng mga karagdagang detalye</translation>
<translation id="1032854598605920125">I-rotate pakanan</translation>
<translation id="1038842779957582377">Hindi kilalang pangalan</translation>
+<translation id="1053591932240354961">Hindi mo mabibisita ang <ph name="SITE" /> sa ngayon dahil nagpadala ang website ng mga pinaghalo-halong kredensyal na hindi maproseso ng Google Chrome. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;I-undo ang Pagdagdag</translation>
<translation id="10614374240317010">Hindi kailanman nag-save</translation>
-<translation id="1064422015032085147">Maaaring na-overload o kasalukuyang inaayos ang server na nagho-host sa webpage.
- Upang hindi makabuo ng masyadong maraming trapiko at lumala ang
- sitwasyon, hindi muna pinahihintulutan ang mga kahilingan sa URL na ito.</translation>
<translation id="106701514854093668">Mga Bookmark sa Desktop</translation>
<translation id="1080116354587839789">Pagkasyahin sa lapad</translation>
+<translation id="1103124106085518534">Tapos na sa ngayon</translation>
<translation id="1103523840287552314">Palaging i-translate ang <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Kung lalagyan ng check, mag-iimbak ang Chrome ng kopya ng iyong card sa device na ito para sa mas mabilis na pagsagot sa form.</translation>
+<translation id="1111153019813902504">Mga kamakailang bookmark</translation>
<translation id="1113869188872983271">&amp;I-undo ang pagbabago sa ayos</translation>
+<translation id="1126551341858583091">Ang laki sa lokal na storage ay <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">OK ang cache ng patakaran</translation>
<translation id="113188000913989374">Isinasaad ng <ph name="SITE" /> na:</translation>
<translation id="1132774398110320017">Mga setting ng Autofill ng Chrome...</translation>
-<translation id="1150979032973867961">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng operating system ng iyong computer ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="1152921474424827756">Mag-access ng <ph name="BEGIN_LINK" />naka-cache na kopya<ph name="END_LINK" /> ng <ph name="URL" /></translation>
<translation id="1158211211994409885">Pinutol ng <ph name="HOST_NAME" /> ang koneksyon nang hindi inaasahan.</translation>
<translation id="1161325031994447685">Muling kumonekta sa Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Alisin</translation>
<translation id="1201402288615127009">Susunod</translation>
<translation id="1201895884277373915">Higit pa mula sa site na ito</translation>
-<translation id="121201262018556460">Tinangka mong maabot ang <ph name="DOMAIN" />, ngunit nagpakita ang server ng isang certificate na naglalaman ng isang mahinang key. Maaaring sinira ng isang nang-aatake ang pribadong key, at ang server ay maaaring hindi ang server na iyong inaasahan (maaaring nakikipag-ugnay ka sa isang nang-aatake).</translation>
+<translation id="1206967143813997005">Hindi magandang paunang signature</translation>
+<translation id="1209206284964581585">Itago sa ngayon</translation>
<translation id="1219129156119358924">Seguridad ng System</translation>
<translation id="1227224963052638717">Hindi kilalang patakaran</translation>
<translation id="1227633850867390598">Itago ang halaga</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Oo</translation>
<translation id="1430915738399379752">I-print</translation>
<translation id="1442912890475371290">Na-block na pagtangkang <ph name="BEGIN_LINK" /> bumisita ng isang pahina sa <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Hindi mo mabibisita ang <ph name="SITE" /> sa ngayon dahil gumagamit ang website ng pagpi-pin ng certificate. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Magpakita ng naka-save (ibigsabihin alam na hindi napapanahon) na kopya ng page na ito.</translation>
<translation id="1519264250979466059">Petsa ng Build</translation>
<translation id="1549470594296187301">Dapat naka-enable ang JavaScript upang magamit ang feature na ito.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Di-wasto ang configuration ng network at hindi maaaring i-import.</translation>
<translation id="1644574205037202324">History</translation>
<translation id="1645368109819982629">Hindi sinusuportahang protocol</translation>
-<translation id="1655462015569774233">{1,plural, =1{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; nag-expire na ang certificate ng seguridad nito kahapon. Maaaring resulta ito ng maling configuration o kaya ng isang attacker na humahadlang sa iyong koneksyon. Sa kasalukuyan, nakatakda ang orasan ng iyong computer sa <ph name="CURRENT_DATE" />. Mukha bang tama iyon? Kung hindi, dapat mong ayusin ang orasan ng iyong system at pagkatapos ay i-refresh ang page na ito.}one{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; nag-expire na ang certificate ng seguridad nito # araw na ang nakalipas. Maaaring resulta ito ng maling configuration o kaya ng isang attacker na humahadlang sa iyong koneksyon. Sa kasalukuyan, nakatakda ang orasan ng iyong computer sa <ph name="CURRENT_DATE" />. Mukha bang tama iyon? Kung hindi, dapat mong ayusin ang orasan ng iyong system at pagkatapos ay i-refresh ang page na ito.}other{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; nag-expire na ang certificate ng seguridad nito # na araw na ang nakalipas. Maaaring resulta ito ng maling configuration o kaya ng isang attacker na humahadlang sa iyong koneksyon. Sa kasalukuyan, nakatakda ang orasan ng iyong computer sa <ph name="CURRENT_DATE" />. Mukha bang tama iyon? Kung hindi, dapat mong ayusin ang orasan ng iyong system at pagkatapos ay i-refresh ang page na ito.}}</translation>
<translation id="1676269943528358898">Karaniwang gumagamit ang <ph name="SITE" /> ng pag-encrypt upang protektahan ang iyong impormasyon. Noong sinubukang kumonekta ng Chrome sa <ph name="SITE" /> sa pagkakataong ito, nagbalik ang website ng mga hindi pangkaraniwan at maling kredensyal. Maaari itong mangyari kapag sinusubukan ng isang attacker na magpanggap bilang <ph name="SITE" />, o naputol ang koneksyon dahil sa isang screen ng pag-sign in sa Wi-Fi. Secure pa rin ang iyong impormasyon dahil inihinto ng Google Chrome ang koneksyon bago magkaroon ng palitan ng anumang data.</translation>
<translation id="168841957122794586">Naglalaman ang server certificate ng isang mahinang cryptographic key.</translation>
<translation id="1701955595840307032">Kumuha ng iminumungkahing content</translation>
-<translation id="1706954506755087368">{1,plural, =1{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; tinatayang mula sa susunod na araw ang certificate ng seguridad nito. Maaaring resulta ito ng maling configuration o kaya ng isang attacker na humahadlang sa iyong koneksyon.}one{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; tinatayang mula sa # araw sa hinaharap ang certificate ng seguridad nito. Maaaring resulta ito ng maling configuration o kaya ng isang attacker na humahadlang sa iyong koneksyon.}other{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; tinatayang mula sa # na araw sa hinaharap ang certificate ng seguridad nito. Maaaring resulta ito ng maling configuration o kaya ng isang attacker na humahadlang sa iyong koneksyon.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Subukang makipag-ugnayan sa admin ng system.</translation>
<translation id="17513872634828108">Mga bukas na tab</translation>
<translation id="1753706481035618306">Numero ng page</translation>
-<translation id="1761412452051366565">Upang makakuha ng naka-personalize na content na iminumungkahi ng Google, i-on ang pag-sync.</translation>
-<translation id="1763864636252898013">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng operating system ng iyong device ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Subukang patakbuhin ang Windows Network Diagnostics<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Mangyaring i-update ang iyong passphrase ng pag-sync.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Lalabas dito ang iyong mga kamakailang binisitang bookmark.</translation>
<translation id="1821930232296380041">Di-wastong kahilingan o mga parameter ng kahilingan</translation>
<translation id="1838667051080421715">Tinitingnan mo ang pinagmumulan ng isang web page.</translation>
<translation id="1871208020102129563">Nakatakda ang proxy upang gumamit ng mga hindi nababagong proxy server, hindi ng isang .pac script URL.</translation>
<translation id="1883255238294161206">Tiklupin ang listahan</translation>
<translation id="1898423065542865115">Pagfi-filter</translation>
-<translation id="1911837502049945214">Hindi tinanggap ng <ph name="HOST_NAME" /> ang iyong certificate sa pag-log in, o maaaring nag-expire na ang iyong certificate sa pag-log in.</translation>
<translation id="194030505837763158">Pumunta sa <ph name="LINK" /></translation>
<translation id="1962204205936693436">Mga Bookmark ng <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Error sa serialization</translation>
<translation id="1974060860693918893">Advanced</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{at 1 pa}one{at # pa}other{at # pa}}</translation>
<translation id="2025186561304664664">Nakatakda sa awtomatikong naka-configure ang proxy.</translation>
<translation id="2030481566774242610">Ang ibig mo bang sabihin ay <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Nakikita mo ang mensaheng ito dahil kailangang aprubahan ng iyong mga magulang ang mga bagong site sa una mong pagbisita.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Suriin ang proxy at ang firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ZIP code</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 suhestyon}one{# suhestyon}other{# na suhestyon}}</translation>
<translation id="2065985942032347596">Kinakailangan na Pagpapatunay</translation>
<translation id="2079545284768500474">I-undo</translation>
<translation id="20817612488360358">Itinatakda ang mga setting ng proxy ng system upang magamit ngunit tinutukoy rin ang isang tahasang configuration ng proxy.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">I-edit ang Bookmark</translation>
<translation id="2166049586286450108">Ganap na Access ng Admin</translation>
<translation id="2166378884831602661">Hindi makakapagbigay ng secure na koneksyon ang site na ito</translation>
-<translation id="2171101176734966184">Tinangka mong maabot ang <ph name="DOMAIN" />, ngunit nagpakita ang server ng certificate na nilagdaan gamit ang isang mahinang signature algorithm. Nangangahulugan ito na ang mga kredensyal na pangseguridad na ipinakita ng server ay maaaring pineke, at ang server ay maaaring hindi ang server na iyong inaasahan (maaaring nakikipag-ugnay ka sa isang nang-aatake).</translation>
<translation id="2181821976797666341">Mga Patakaran</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 address}one{# address}other{# na address}}</translation>
<translation id="2212735316055980242">Hindi nahanap ang patakaran</translation>
<translation id="2213606439339815911">Kinukuha ang mga entry...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> ay hindi magagamit</translation>
<translation id="2230458221926704099">Ayusin ang iyong koneksyon gamit ang <ph name="BEGIN_LINK" />diagnostics app<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Ipadala ngayon</translation>
<translation id="225207911366869382">Hindi na gimagamit ang halagang ito para sa patakarang ito.</translation>
<translation id="2262243747453050782">Error sa HTTP</translation>
<translation id="2282872951544483773">Mga Eksperimentong Hindi Available</translation>
<translation id="2292556288342944218">Naka-block ang iyong access sa Internet</translation>
<translation id="229702904922032456">Nag-expire na ang isang pinagmulan o intermediate na certificate.</translation>
<translation id="230155334948463882">Bagong card?</translation>
+<translation id="2305919008529760154">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; maaaring mapanlokong ibinigay ang certificate na panseguridad. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">Kailangan ng <ph name="DOMAIN" /> ng username at password.</translation>
+<translation id="2318774815570432836">Hindi mo mabibisita ang <ph name="SITE" /> sa ngayon dahil gumagamit ang website ng HSTS. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Binalewalang di-wastong bookmark sa index <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Iba pang mga bookmark</translation>
<translation id="2359808026110333948">Magpatuloy</translation>
<translation id="2365563543831475020">Hindi na-upload ang nakuhang ulat ng pag-crash noong <ph name="CRASH_TIME" /></translation>
<translation id="2367567093518048410">Antas</translation>
+<translation id="2371153335857947666">{1,plural, =1{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; nag-expire kahapon ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. Sa kasalukuyan, nakatakda ang orasan ng iyong computer sa <ph name="CURRENT_DATE" />. Mukha bang tama iyon? Kung hindi, dapat mong ayusin ang orasan ng iyong system at i-refresh ang page na ito pagkatapos. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.}one{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; nag-expire na ang certificate na panseguridad nito # araw na ang nakalipas. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. Sa kasalukuyan, nakatakda ang orasan ng iyong computer sa <ph name="CURRENT_DATE" />. Mukha bang tama iyon? Kung hindi, dapat mong ayusin ang orasan ng iyong system at i-refresh ang page na ito pagkatapos. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.}other{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; nag-expire na ang certificate na panseguridad nito # na araw na ang nakalipas. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. Sa kasalukuyan, nakatakda ang orasan ng iyong computer sa <ph name="CURRENT_DATE" />. Mukha bang tama iyon? Kung hindi, dapat mong ayusin ang orasan ng iyong system at i-refresh ang page na ito pagkatapos. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Walang mga available na alternatibo sa UI</translation>
<translation id="2384307209577226199">Default ng enterprise</translation>
-<translation id="238526402387145295">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil ang website ay <ph name="BEGIN_LINK" />gumagamit ng HSTS<ph name="END_LINK" />. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon.</translation>
<translation id="2386255080630008482">Nabawi ang certificate ng server.</translation>
<translation id="2392959068659972793">Ipakita ang mga patakarang walang nakatakdang halaga</translation>
<translation id="2396249848217231973">&amp;I-undo ang pagtanggal</translation>
-<translation id="2413528052993050574">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; maaaring binawi ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="2455981314101692989">Hindi pinagana ng webpage na ito ang awtomatikong pagpuno para sa form na ito.</translation>
+<translation id="2463739503403862330">Punan</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Magpatakbo ng Network Diagnostics<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Di-wastong URL ng paghahanap.</translation>
<translation id="2491120439723279231">Naglalaman ng mga error ang certificate ng server.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Isumite</translation>
<translation id="2674170444375937751">Sigurado ka bang nais mong tanggalin ang mga pahinang ito mula sa iyong history?</translation>
<translation id="2677748264148917807">Umalis</translation>
+<translation id="269990154133806163">Nagpakita ang server ng certificate na hindi ibinunyag sa publiko gamit ang patakaran sa Transparency ng Certificate. Kinakailangan ito para sa ilang certificate, upang siguraduhing mapagkakatiwalaan ang mga ito at upang maprotektahan laban sa mga nang-aatake. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Hindi tumutugma ang format sa halaga.</translation>
<translation id="2704951214193499422">Hindi nakumpirma ng Chromium ang iyong card sa pagkakataong ito. Pakisubukang muli sa ibang pagkakataon.</translation>
<translation id="2705137772291741111">Hindi mabasa ang naka-save (naka-cache) na kopya ng site na ito.</translation>
<translation id="2709516037105925701">AutoFill</translation>
+<translation id="2712118517637785082">Tinangka mong makakonekta sa <ph name="DOMAIN" />, ngunit ang ipinakitang certificate ng server ay binawi ng nagbigay. Nangangahulugan ito na malinaw na hindi dapat pagkatiwalaan ang mga kredensyal na panseguridad na ipinakita ng server. Maaaring nakikipag-ugnayan ka sa isang nang-aatake. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Humingi ng pahintulot</translation>
<translation id="2721148159707890343">Matagumpay ang kahilingan</translation>
<translation id="2728127805433021124">Nilagdaan ang certificate ng server gamit ang mahinang algorithm ng lagda.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Address bar at bar sa paghahanap</translation>
<translation id="2826760142808435982">Ine-encrypt at pinapatotoo ang koneksyon gamit ang <ph name="CIPHER" /> at ginagamit ang <ph name="KX" /> bilang key exchange mechanism.</translation>
<translation id="2835170189407361413">I-clear ang form</translation>
-<translation id="2837049386027881519">Kinailangang subukang muli ang koneksyon gamit ang mas lumang bersyon ng protocol ng TLS o SSL. Kadasalan ay nangangahulugan ito na ang server ay gumagamit ng napakalumang software at maaaring may iba pang mga isyu sa seguridad.</translation>
<translation id="284702764277384724">Mukhang peke ang certificate ng server sa <ph name="HOST_NAME" />.</translation>
<translation id="2889159643044928134">Huwag I-reload</translation>
-<translation id="2896499918916051536">Hindi sinusuportahan ang plugin na ito.</translation>
+<translation id="2900469785430194048">Naubusan ng memory ang Google Chrome habang sinusubukang ipakita ang webpage na ito.</translation>
<translation id="2909946352844186028">May nakitang pagbabago sa network.</translation>
-<translation id="2915500479781995473">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; nag-expire na ang certificate ng seguridad nito. Maaaring sanhi ito ng maling configuration o ng panghihimasok ng isang attacker sa iyong koneksyon. Kasalukuyang nakatakda ang orasan ng iyong computer sa <ph name="CURRENT_TIME" />. Mukha bang tama ito? Kung hindi, dapat mong iwasto ang orasan ng iyong system at pagkatapos ay i-refresh ang page na ito.</translation>
<translation id="2922350208395188000">Hindi masuri ang certificate ng server.</translation>
-<translation id="2941952326391522266">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; mula sa <ph name="DOMAIN2" /> ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="2948083400971632585">Maaari mong i-disable ang anumang mga proxy na naka-configure para sa isang koneksyon mula sa pahina ng mga setting.</translation>
<translation id="2955913368246107853">Isara ang bar sa paghahanap</translation>
<translation id="2958431318199492670">Hindi sumusunod ang configuration ng network sa pamantayan ng ONC. Hindi maaaring i-import ang mga bahagi ng configuration.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Maling uri ng patakaran</translation>
<translation id="3032412215588512954">Gusto mo bang i-reload ang site na ito?</translation>
<translation id="3037605927509011580">Ay, Naku!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{kahit 1 item sa mga naka-sync na device}=1{1 item (at higit pa sa mga naka-sync na device)}one{# item (at higit pa sa mga naka-sync na device)}other{# na item (at higit pa sa mga naka-sync na device)}}</translation>
<translation id="3041612393474885105">Impormasyon sa Certificate</translation>
<translation id="3063697135517575841">Hindi nakumpirma ng Chrome ang iyong card sa pagkakataong ito. Pakisubukang muli sa ibang pagkakataon.</translation>
<translation id="3093245981617870298">Offline ka.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Pinakabago</translation>
<translation id="3207960819495026254">Naka-bookmark</translation>
-<translation id="3225919329040284222">Nagpakita ang server ng certificate na hindi tumutugma sa mga built-in na inaasahan. Ang mga inaasahang ito ay isinama para sa ilang partikular na website na may mataas na antas ng seguridad upang maprotektahan ka.</translation>
<translation id="3226128629678568754">Pindutin ang button na i-reload upang isumiteng muli ang data na kailangan upang ma-load ang pahina.</translation>
<translation id="3228969707346345236">Nabigo ang pag-translate dahil nasa <ph name="LANGUAGE" /> na ang pahina.</translation>
<translation id="323107829343500871">Ilagay ang iyong CVC para sa <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">I-bookmark ang page na ito</translation>
<translation id="3270847123878663523">&amp;I-undo ang Pagbabago sa Ayos</translation>
<translation id="3286538390144397061">I-restart Ngayon</translation>
+<translation id="3303855915957856445">Walang nakitang resulta ng paghahanap</translation>
<translation id="3305707030755673451">Na-encrypt ang iyong data gamit ang iyong passphrase sa pag-sync noong <ph name="TIME" />. Ilagay ito upang simulan ang pag-sync.</translation>
<translation id="333371639341676808">Iwasan ang pahinang ito mula sa paglikha ng karagdagang mga dialog.</translation>
+<translation id="3338095232262050444">Secure</translation>
<translation id="3340978935015468852">mga setting</translation>
<translation id="3345135638360864351">Hindi maipadala kay <ph name="NAME" /> ang iyong kahilingang i-access ang site na ito. Pakisubukang muli.</translation>
<translation id="3355823806454867987">Baguhin ang mga setting ng proxy...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Kunin ang agwat:</translation>
<translation id="3462200631372590220">Itago ang advanced</translation>
<translation id="3479539252931486093">Hindi mo ba ito inaasahan? <ph name="BEGIN_LINK" />Ipaalam sa amin<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Hindi ngayon</translation>
<translation id="348000606199325318">Crash ID <ph name="CRASH_LOCAL_ID" /> (Server ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Hindi namin makaugnayan ang iyong magulang sa sandaling ito. Pakisubukang muli.</translation>
<translation id="3527085408025491307">Folder</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Gamitin ang password para sa:</translation>
<translation id="3549644494707163724">I-encrypt ang lahat ng naka-sync na data gamit ang sarili mong passphrase sa pag-sync</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> pa...</translation>
+<translation id="3555561725129903880">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; ang certificate na panseguridad nito ay nanggaling sa <ph name="DOMAIN2" />. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Hindi pribado ang iyong koneksyon</translation>
<translation id="3583757800736429874">&amp;Gawing Muli ang Paglilipat</translation>
<translation id="3586931643579894722">Magtago ng mga detalye</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Ipakita ang halaga</translation>
<translation id="3630155396527302611">Kung nakalista na ito bilang isang programang pinapahintulutang i-access ang network, subukang
alisin ito mula sa listahan at muli itong idagdag.</translation>
+<translation id="3638794133396384728">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; nag-expire na ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng nang-aatake na humahadlang sa iyong koneksyon. Sa kasalukuyan, nakatakda ang orasan ng iyong computer sa <ph name="CURRENT_TIME" />. Mukha bang tama iyon? Kung hindi, dapat mong ayusin ang orasan ng iyong system at i-refresh ang page na ito pagkatapos. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Maaaring mabago, masira, o mawala anumang oras ang mga pang-eksperimentong tampok na ito. Ganap kaming walang garantiya tungkol sa kung ano ang maaaring mangyari kung bubuksan mo ang isa sa mga eksperimentong ito, at maaari pang biglang masunog ang iyong browser. Walang halong pagbibiro, maaaring tanggalin ng iyong browser ang lahat ng iyong data, o maaaring makompromiso sa mga hindi inaasahang paraan ang iyong seguridad at privacy. Anumang mga eksperimento na iyong papaganahin ay mapapagana para sa lahat ng mga user sa browser na ito. Mangyaring maingat na magpatuloy.</translation>
<translation id="3650584904733503804">Matagumpay ang pagpapatunay</translation>
<translation id="3655670868607891010">Kung madalas mo itong nakikita, subukan ang mga ito <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Rebisyon</translation>
+<translation id="3678029195006412963">Hindi malagdaan ang kahilingan</translation>
<translation id="3681007416295224113">Impormasyon sa certificate</translation>
<translation id="3693415264595406141">Password:</translation>
+<translation id="3696411085566228381">wala</translation>
<translation id="3700528541715530410">Oops, mukhang wala kang pahintulot na i-access ang pahinang ito.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Kumakarga...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">I-on ang mobile data o Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Suriin ang configuration ng proxy, firewall at DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Link na kinopya mo</translation>
-<translation id="3744899669254331632">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil nagpadala ang website ng mga pinaghalong kredensyal na hindi maproseso ng Chromium. Karaniwang pansamantala ang mga error at pag-atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon.</translation>
<translation id="375403751935624634">Nabigo ang translation dahil sa error sa server.</translation>
<translation id="3759461132968374835">Wala kang kamakailang iniulat na mga pag-crash. Hindi lilitaw dito ang mga pag-crash na naganap kapag hindi pinagana ang pag-uulat ng pag-crash.</translation>
<translation id="3788090790273268753">Mag-e-expire ang certificate para sa site na ito sa 2016, at naglalaman ang chain ng certificate ng isang certificate na naka-sign gamit ang SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Sumasalungat na tagatukoy ng device</translation>
<translation id="3885155851504623709">Parokya</translation>
<translation id="3901925938762663762">Na-expire na ang card</translation>
+<translation id="3910267023907260648">Tinangka mong makakonekta sa <ph name="DOMAIN" />, ngunit ang certificate na ipinakita ng server ay nilagdaan gamit ang mahinang signature algorithm. Nangangahulugan ito na maaaring napeke ang kredensyal na panseguridad na ipinakita ng server, at maaaring ang server ay hindi ang inaasahan mong server (maaaring nakikipag-ugnayan ka sa isang nang-aatake). <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; tinatayang mula sa susunod na araw ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.}one{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; tinatayang mula sa # araw sa hinaharap ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.}other{Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; tinatayang mula sa # na araw sa hinaharap ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Nabigong i-load ang dokumentong PDF</translation>
<translation id="3963721102035795474">Reader Mode</translation>
+<translation id="397105322502079400">Kinakalkula...</translation>
<translation id="3973234410852337861">Naka-block ang <ph name="HOST_NAME" /></translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 web page ang malapit}one{# web page ang malapit}other{# na web page ang malapit}}</translation>
<translation id="4021036232240155012">Ang DNS ay ang serbisyo sa network na nagta-translate ng pangalan ng isang website sa Internet address nito.</translation>
<translation id="4030383055268325496">&amp;I-undo ang pagdagdag</translation>
-<translation id="4032534284272647190">Tinanggihan ang pag-access sa <ph name="URL" />.</translation>
<translation id="404928562651467259">BABALA</translation>
<translation id="4058922952496707368">Key "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Hindi sinusuportahan ng client at server ang isang karaniwang bersyon o cipher suite ng SSL protocol.</translation>
<translation id="4079302484614802869">Nakatakda ang configuration ng proxy upang gumamit ng isang .pac script URL, hindi ng mga hindi nababagong proxy server.</translation>
<translation id="4103249731201008433">Di-wasto ang serial number ng device</translation>
<translation id="4103763322291513355">Bisitahin ang &lt;strong&gt;chrome://policy&lt;/strong&gt; upang makita ang listahan ng mga naka-blacklist na URL at iba pang mga patakaran na ipinapatupad ng iyong system administrator.</translation>
+<translation id="4110615724604346410">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; naglalaman ng mga error ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Hindi sinusuportahan ang saklaw ng patakaran.</translation>
+<translation id="4118212371799607889">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng Chromium ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 pa}one{# pa}other{# pa}}</translation>
<translation id="4130226655945681476">Suriin ang mga cable, modem at router ng network</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Gusto mo bang i-save ng Chromium ang card na ito?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Hindi Pinagana</translation>
<translation id="4196861286325780578">&amp;Gawing muli ang paglilipat</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Suriin ang mga configuration ng firewall at antivirus<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{wala}=1{1 app ($1)}=2{2 app ($1, $2)}one{# app ($1, $2, $3)}other{# na app ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Mga Pag-crash</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Subukang magpatakbo ng Network Diagnostics<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Hindi</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Walang username)</translation>
<translation id="4300246636397505754">Mga suhestyon ng magulang</translation>
<translation id="4304224509867189079">Mag-log In</translation>
+<translation id="432290197980158659">Nagpakita ang server ng isang certificate na hindi tumutugma sa mga inaasahang built-in. Ang mga inaasahang ito ay isinama para sa ilang partikular na website na mahigpit sa seguridad upang maprotektahan ka. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Hindi nahanap ang artikulo</translation>
+<translation id="4331708818696583467">Hindi Secure</translation>
<translation id="4372948949327679948">Inaasahang <ph name="VALUE_TYPE" /> na halaga.</translation>
-<translation id="4377125064752653719">Tinangka mong maabot ang <ph name="DOMAIN" />, subalit ang certificate na ipinakita ng server ay binawi ng nagbigay nito. Nangangahulugan ito na ang mga kredensyal sa seguridad na ipinakita ng server ay talagang hindi dapat pagkatiwalaan. Maaaring nakikipag-ugnay ka sa isang nang-aatake.</translation>
<translation id="4381091992796011497">User Name:</translation>
<translation id="4394049700291259645">Huwag paganahin</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> hanggang <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">mga resulta ng paghahanap</translation>
-<translation id="4424024547088906515">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng Chrome ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
+<translation id="4432688616882109544">Hindi tinanggap ng <ph name="HOST_NAME" /> ang iyong certificate sa pag-log in o maaaring walang ibinigay.</translation>
<translation id="443673843213245140">Hindi pinagana ang paggamit ng isang proxy ngunit tinutukoy ang isang tahasang configuration ng proxy.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Nakikita mo ang mensaheng ito dahil naka-enable ang Google SafeSites.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Mga Detalye</translation>
<translation id="4558551763791394412">Subukang i-disable ang iyong mga extension.</translation>
<translation id="4587425331216688090">Alisin ang address sa Chrome?</translation>
+<translation id="4589078953350245614">Tinangka mong makakonekta sa <ph name="DOMAIN" />, ngunit nagpakita ang server ng di-wastong certificate. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Naka-encrypt ang iyong koneksyon sa <ph name="DOMAIN" /> gamit ang isang makabagong cipher suite.</translation>
<translation id="4594403342090139922">&amp;I-undo ang Pagtanggal</translation>
+<translation id="4627442949885028695">Magpatuloy mula sa ibang device</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Isang page ng extension ang iyong tinitingnan.</translation>
-<translation id="467662567472608290">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; naglalaman ng mga error ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
-<translation id="4697214168136963651">Na-block ang <ph name="URL" /></translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Naputol ang iyong koneksyon</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Magpatakbo ng Windows Network Diagnostics<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Platform</translation>
<translation id="4744603770635761495">Naipapatupad na Path</translation>
<translation id="4756388243121344051">&amp;History</translation>
+<translation id="4759238208242260848">Mga Download </translation>
<translation id="4764776831041365478">Ang webpage sa <ph name="URL" /> ay maaaring pansamantalang hindi gumagana o maaaring permanente itong inilipat sa isang bagong web address.</translation>
<translation id="4771973620359291008">Isang hindi alam na error ang nangyari.</translation>
<translation id="4782449893814226250">Tinanong mo sa iyong mga magulang kung maaari mong bisitahin ang page na ito.</translation>
<translation id="4800132727771399293">Tingnan ang iyong petsa ng pag-expire at CVC at subukang muli</translation>
-<translation id="4807049035289105102">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil nagpadala ang website ng mga gulu-gulong kredensyal na hindi maproseso ng Google Chrome. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon.</translation>
<translation id="4813512666221746211">Error sa network</translation>
<translation id="4816492930507672669">Pagkasyahin sa pahina</translation>
<translation id="4850886885716139402">View</translation>
<translation id="4880827082731008257">History ng paghahanap</translation>
+<translation id="4884656795097055129">Higit pang artikulo ang lalabas sa tamang panahon.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{at 1 pang web page}one{at # pang web page}other{at # pang web page}}</translation>
<translation id="4923417429809017348">Na-translate ang pahinang ito mula sa hindi kilalang wika patungo sa <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Dapat na tukuyin.</translation>
<translation id="4930497775425430760">Nakikita mo ang mensaheng ito dahil kailangang aprubahan ng iyong magulang ang mga bagong site sa una mong pagbisita.</translation>
<translation id="495170559598752135">Mga Pagkilos</translation>
<translation id="4958444002117714549">Palawakin ang listahan</translation>
+<translation id="4962322354953122629">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng Chrome ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">I-translate mula <ph name="ORIGINAL_LANGUAGE" /> patungong <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Hindi sinusuportahan ang plugin na ito</translation>
<translation id="5002932099480077015">Kung naka-enable, mag-iimbak ang Chrome ng kopya ng iyong card sa device na ito para sa mas mabilis na pagsagot sa form.</translation>
<translation id="5019198164206649151">Hindi maganda ang katayuan ng backing store</translation>
<translation id="5023310440958281426">Suriin ang mga patakaran ng iyong administrator</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Tungkol sa Google Translate</translation>
<translation id="5040262127954254034">Privacy</translation>
<translation id="5045550434625856497">Hindi wastong password</translation>
+<translation id="5056549851600133418">Mga artikulo para sa iyo</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Suriin ang proxy address<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Hindi angkop ang certificate ng server sa oras na ito.</translation>
<translation id="5089810972385038852">Estado</translation>
-<translation id="5094747076828555589">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng Chromium ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="5095208057601539847">Probinsya</translation>
<translation id="5115563688576182185">(64-bit)</translation>
-<translation id="5122371513570456792">Nakakita ng <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para sa '<ph name="SEARCH_STRING" />'.</translation>
<translation id="5141240743006678641">I-encrypt ang mga naka-sync na password gamit ang iyong mga kredensyal sa Google</translation>
<translation id="5145883236150621069">May code ng error sa tugon sa patakaran</translation>
<translation id="5171045022955879922">Hanapin o i-type ang URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Bar ng Mga Bookmark</translation>
<translation id="5199729219167945352">Mga Eksperimento</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">Ginagamit mo ba ang Chrome sa trabaho? Maaaring pamahalaan ng mga negosyo ang mga setting ng Chrome para sa kanilang mga empleyado. Matuto pa</translation>
<translation id="5299298092464848405">Error sa pag-parse ng patakaran</translation>
<translation id="5300589172476337783">Ipakita</translation>
<translation id="5308689395849655368">Hindi pinagana ang pag-uulat ng pag-crash.</translation>
<translation id="5317780077021120954">I-save</translation>
<translation id="5327248766486351172">Pangalan</translation>
+<translation id="5359637492792381994">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; walang bisa ang certificate na panseguridad nito sa ngayon. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Nabigo i-load ang mga setting ng patakaran sa store</translation>
-<translation id="540969355065856584">Hindi mapatunayan ng server na ito ay ang <ph name="DOMAIN" />; walang bisa ang certificate sa seguridad nito sa pagkakataong ito. Maaaring dahil ito sa isang maling pag-configure o may isang attacker na humahadlang sa iyong koneksyon.</translation>
<translation id="5421136146218899937">I-clear ang data sa pagba-browse...</translation>
<translation id="5430298929874300616">Alisin ang bookmark</translation>
<translation id="5431657950005405462">Hindi nakita ang iyong file</translation>
<translation id="5435775191620395718">Ipinapakita ang history mula sa device na ito. <ph name="BEGIN_LINK" />Matuto nang higit pa<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Kasalukuyang naka-disable ang mga naka-personalize na suhestyon sa content, dahil pinoprotektahan ng custom na passphrase ang iyong naka-sync na data.</translation>
<translation id="5439770059721715174">Error sa pagpapatunay ng schema sa "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Hindi makita ang <ph name="HOST_NAME" /> page na ito</translation>
<translation id="5455374756549232013">Maling timestamp ng patakaran</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Gusto mo bang umalis sa site na ito?</translation>
<translation id="5629630648637658800">Nabigong i-load ang mga setting ng patakaran</translation>
<translation id="5631439013527180824">Di-wastong token sa pamamahala ng device</translation>
-<translation id="5650551054760837876">Walang nahanap na mga resulta sa paghahanap</translation>
<translation id="5677928146339483299">Naka-block</translation>
<translation id="5710435578057952990">Ang pagkilala ng website na ito ay hindi natukoy.</translation>
<translation id="5720705177508910913">Kasalukuyang user</translation>
+<translation id="572328651809341494">Mga kamakailang tab</translation>
<translation id="5784606427469807560">Nagkaroon ng problema sa pagkumpirma ng iyong card. Suriin ang koneksyon sa internet at subukang muli.</translation>
<translation id="5785756445106461925">Bukod pa rito, ang page na ito ay may iba pang mga mapagkukunang hindi secure. Makikita ng iba ang mga mapagkukunang ito habang ipinadadala, at maaaring baguhin ng isang umaatake upang baguhin ang hitsura ng page.</translation>
+<translation id="5786044859038896871">Gusto mo bang ilagay ang impormasyon ng iyong card?</translation>
+<translation id="5803412860119678065">Gusto mo bang ilagay ang iyong <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Naka-encrypt ang iyong koneksyon sa <ph name="DOMAIN" /> gamit ang isang hindi na ginagamit na cipher suite.</translation>
<translation id="5813119285467412249">&amp;Gawing Muli ang Pagdagdag</translation>
+<translation id="5814352347845180253">Maaari kang mawalan ng access sa premium na content mula sa <ph name="SITE" /> at ilan pang ibang site.</translation>
+<translation id="5843436854350372569">Tinangka mong makakonekta sa <ph name="DOMAIN" />, ngunit nagpakita ang server ng certificate na naglalaman ng isang mahinang key. Maaaring sinira ng isang nang-aatake ang pribadong key, at maaaring ang server ay hindi ang inaasahan mong server (maaaring nakikipag-ugnayan ka sa isang nang-aatake). <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Nakikita mo ang mensaheng ito dahil na-block ng iyong manager ang site na ito.</translation>
<translation id="5857090052475505287">Bagong Folder</translation>
<translation id="5869405914158311789">Hindi makakonekta sa site na ito</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Mga Suhestyon ng Magulang</translation>
<translation id="59107663811261420">Ang ganitong uri ng card ay hindi sinusuportahan ng Google Payments para sa merchant na ito. Mangyaring pumili ng ibang card.</translation>
<translation id="59174027418879706">Naka-enable</translation>
+<translation id="5926846154125914413">Maaari kang mawalan ng access sa premium na content mula sa ilang site.</translation>
<translation id="5966707198760109579">Linggo</translation>
<translation id="5967867314010545767">Alisin sa history</translation>
<translation id="5975083100439434680">Mag-zoom out</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Awtomatiko</translation>
<translation id="6042308850641462728">Higit pa</translation>
<translation id="6060685159320643512">Mag-ingat, maaaring makahamak ang mga eksperimentong ito</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{wala}=1{1}one{#}other{#}}</translation>
<translation id="6146055958333702838">Tingnan ang anumang mga kable at i-reboot ang anumang mga router, modem o iba
pang mga network device na maaaring ginagamit mo.</translation>
<translation id="614940544461990577">Subukang:</translation>
<translation id="6150607114729249911">Oops! Kailangan mong tanungin ang iyong mga magulang kung OK lang na bisitahin ang page na ito.</translation>
<translation id="6151417162996330722">Masyadong mahaba ang panahon ng pagkakaroon ng bisa ng certificate ng server.</translation>
-<translation id="6154808779448689242">Hindi tumutugma ang ibinalik na token sa patakaran sa kasalukuyang token</translation>
<translation id="6165508094623778733">Matuto nang higit pa</translation>
<translation id="6203231073485539293">Suriin ang iyong koneksyon sa Internet</translation>
<translation id="6218753634732582820">Gusto mo bang alisin ang address sa Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Subukang i-disable ang paghula ng network</translation>
<translation id="6337534724793800597">I-filter ang mga patakaran ayon sa pangalan</translation>
<translation id="6342069812937806050">Ngayon lang</translation>
+<translation id="6345221851280129312">hindi pa natutukoy na laki</translation>
<translation id="6355080345576803305">Override sa pampublikong session</translation>
<translation id="6358450015545214790">Ano ang ibig sabihin ng mga ito?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 pang suhestyon}one{# pang suhestyon}other{# pang suhestyon}}</translation>
<translation id="6387478394221739770">Interesado sa mga astig at bagong tampok sa Chrome? Subukan ang aming beta channel sa chrome.com/beta.</translation>
-<translation id="641480858134062906">Nabigo sa pagload ang <ph name="URL" /></translation>
+<translation id="6389758589412724634">Naubusan ng memory ang Chromium habang sinusubukang ipakita ang webpage na ito.</translation>
+<translation id="6416403317709441254">Hindi mo mabibisita ang <ph name="SITE" /> sa ngayon dahil nagpadala ang website ng mga pinaghalu-halong kredensyal na hindi maproseso ng Chromium. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Hindi nagawang masuri kung nabawi na ang certificate.</translation>
<translation id="6433595998831338502">Tumangging kumonekta ang <ph name="HOST_NAME" />.</translation>
<translation id="6445051938772793705">Bansa</translation>
<translation id="6451458296329894277">Muling pagsusumite ng Form sa Pagkumpirma</translation>
<translation id="6458467102616083041">Binalewala dahil hindi pinagana ng patakaran ang default na paghahanap.</translation>
+<translation id="6462969404041126431">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; maaaring mabawi ang certificate na panseguridad nito. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Mga patakaran sa device</translation>
<translation id="6489534406876378309">Simulang mag-upload ng mga pag-crash</translation>
<translation id="6529602333819889595">&amp;Gawing Muli ang Pagtanggal</translation>
+<translation id="6534179046333460208">Mga suhestyon sa Pisikal na Web</translation>
<translation id="6550675742724504774">Mga Pagpipilian</translation>
+<translation id="6593753688552673085">wala pang <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Mga pagpipilian sa pag-encrypt</translation>
<translation id="662080504995468778">Manatili</translation>
<translation id="6628463337424475685">Paghahanap ng <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil <ph name="BEGIN_LINK" />binawi na ang certificate na ito<ph name="END_LINK" />. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon.</translation>
<translation id="6644283850729428850">Hindi na ginagamit ang patakarang ito.</translation>
+<translation id="6652240803263749613">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; ang certificate na panseguridad nito ay hindi pinagkakatiwalaan ng operating system ng iyong computer. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">I-edit ang Folder</translation>
<translation id="6660210980321319655">Awtomatikong naiulat noong <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Gusto mo bang alisin ang form para sa suhestyon sa Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Nakaraan</translation>
<translation id="6710594484020273272">&lt;I-type ang termino para sa paghahanap&gt;</translation>
<translation id="6711464428925977395">May problema sa proxy server, o mali ang address.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{wala}=1{1 item}one{# item}other{# na item}}</translation>
<translation id="674375294223700098">Hindi alam na error sa certificate ng server</translation>
<translation id="6753269504797312559">Halaga ng patakaran</translation>
<translation id="6757797048963528358">Nag-sleep ang iyong device.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Hindi sinusuportahan ang antas ng patakaran.</translation>
<translation id="6895330447102777224">Nakumpirma na ang iyong card</translation>
<translation id="6897140037006041989">User Agent</translation>
-<translation id="6903907808598579934">I-on ang pag-sync</translation>
<translation id="6915804003454593391">User:</translation>
<translation id="6957887021205513506">Lumilitaw na isang pamamalsipika ang certificate ng server.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Distrito</translation>
<translation id="6973656660372572881">Tinukoy ang parehong mga hindi nababagong proxy server at isang .pac script URL.</translation>
<translation id="6989763994942163495">Ipakita ang mga advanced na setting...</translation>
+<translation id="7000990526846637657">Walang nakitang mga entry sa history</translation>
+<translation id="7009986207543992532">Tinangka mong makakonekta sa <ph name="DOMAIN" />, ngunit ang server ay nagpakita ng certificate na masyadong matagal ang panahon ng pagkabisa, dahilan upang hindi maging katiwa-katiwala ito. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Ang iyong Google Account ay maaaring may iba pang mga form ng history ng pagba-browse sa <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Mga Password</translation>
-<translation id="7050187094878475250">Sinubukan mong puntahan ang <ph name="DOMAIN" />, ngunit nagpakita ang server ng certificate na masyadong mahaba ang panahon ng pagkakaroon ng bisa upang maging mapagkakatiwalaan.</translation>
<translation id="7087282848513945231">County</translation>
<translation id="7088615885725309056">Mas Nauna</translation>
<translation id="7090678807593890770">Hanapin sa Google ang <ph name="LINK" /></translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Nakikita mo ang mensaheng ito dahil kailangang aprubahan ng iyong manager ang mga bagong site sa una mong pagbisita.</translation>
<translation id="724975217298816891">Ilagay ang petsa ng expiration at CVC para sa <ph name="CREDIT_CARD" /> upang i-update ang mga detalye ng iyong card. Kapag nagkumpirma ka na, ibabahagi ang mga detalye ng iyong card sa site na ito.</translation>
<translation id="725866823122871198">Hindi makapagtatag ng pribadong koneksyon sa <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> dahil mali ang petsa at oras ng iyong computer (<ph name="DATE_AND_TIME" />).</translation>
-<translation id="7265986070661382626">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil ang website ay <ph name="BEGIN_LINK" />gumagamit ng pagpi-pin ng certificate<ph name="END_LINK" />. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon.</translation>
<translation id="7269802741830436641">Ang webpage na ito ay may loop na pag-redirect</translation>
<translation id="7275334191706090484">Mga Pinamamahalaang Bookmark</translation>
<translation id="7298195798382681320">Inirerekomenda</translation>
-<translation id="7301833672208172928">I-on ang pag-sync ng history</translation>
+<translation id="7309308571273880165">Ulat ng pag-crash na nakuha noong <ph name="CRASH_TIME" /> (humiling ng pag-upload ang user, hindi pa naa-upload)</translation>
<translation id="7334320624316649418">&amp;Gawing muli ang pagbabago sa ayos</translation>
<translation id="733923710415886693">Ang certificate ng server ay hindi ibinunyag sa pamamagitan ng Transparency ng Certificate.</translation>
+<translation id="7351800657706554155">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil binawi na ang certificate nito. Karaniwang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Command Line</translation>
<translation id="7372973238305370288">resulta ng paghahanap</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="7469372306589899959">Kinukumpirma ang card</translation>
<translation id="7481312909269577407">Sumulong</translation>
<translation id="7485870689360869515">Walang nahanap na data.</translation>
+<translation id="7508255263130623398">Walang laman ang ibinalik na device id ng patakaran o hindi ito tumutugma sa kasalukuyang device id</translation>
<translation id="7514365320538308">I-download</translation>
<translation id="7518003948725431193">Walang webpage na nahanap para sa web address:<ph name="URL" /></translation>
<translation id="7537536606612762813">Kinakailangan</translation>
<translation id="7542995811387359312">Hindi pinagana ang awtomatikong pagpuno ng credit card dahil ang form na ito ay hindi gumagamit ng secure na koneksyon.</translation>
<translation id="7549584377607005141">Kinakailangan ng webpage na ito ng data na inilagay mo dati upang maipakita nang maayos. Maipapadala mong muli ang data na ito, ngunit kapag ginawa mo iyon, mauulit ang anumang pagkilos na isinagawa dati ng pahinang ito.</translation>
<translation id="7554791636758816595">Bagong Tab</translation>
-<translation id="7567204685887185387">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; maaaring mapanlokong ibinigay ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="7568593326407688803">Ang pahinang ito ay nasa<ph name="ORIGINAL_LANGUAGE" />Gusto mong isalin ito?</translation>
<translation id="7569952961197462199">Alisin ang credit card sa Chrome?</translation>
<translation id="7578104083680115302">Magbayad nang mabilis sa mga site at app sa iba't ibang device gamit ang mga card na na-save mo sa Google.</translation>
+<translation id="7588950540487816470">Pisikal na Web</translation>
<translation id="7592362899630581445">Lumabag ang certificate ng server sa limitasyon sa pangalan.</translation>
<translation id="759889825892636187">Sa kasalukuyan, hindi magagawa ng <ph name="HOST_NAME" /> ang kahilingang ito.</translation>
<translation id="7600965453749440009">Huwag isalin kailanman ang <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="7637571805876720304">Gusto mo bang alisin ang credit card sa Chromium?</translation>
<translation id="765676359832457558">Itago ang mga advanced na setting...</translation>
<translation id="7658239707568436148">Ikansela</translation>
+<translation id="7667346355482952095">Walang laman ang ibinalik na token ng patakaran o hindi tumutugma sa kasalukuyang token</translation>
<translation id="7668654391829183341">Hindi kilalang device</translation>
<translation id="7674629440242451245">Interesado sa mga astig at bagong tampok sa Chrome? Subukan ang aming dev channel sa chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Magpatuloy sa <ph name="SITE" /> (hindi ligtas)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="780301667611848630">Hindi salamat</translation>
<translation id="7805768142964895445">Katayuan</translation>
<translation id="7813600968533626083">Alisin ang suhestyon sa Chrome?</translation>
+<translation id="7815407501681723534">Nakakita ng <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para sa '<ph name="SEARCH_STRING" />'</translation>
<translation id="785549533363645510">Gayunpaman, hindi ka invisible. Kahit mag-incognito ka, hindi matatago ang iyong pagba-browse mula sa iyong employer, sa iyong internet service provider o sa mga website na binibisita mo.</translation>
<translation id="7887683347370398519">Tingnan ang iyong CVC at subukang muli</translation>
<translation id="7894616681410591072">Oops! Kailangan mo ng pahintulot mula kay <ph name="NAME" /> upang ma-access ang page na ito.</translation>
-<translation id="790025292736025802">Hindi nahanap ang <ph name="URL" /></translation>
<translation id="7912024687060120840">Sa Folder:</translation>
<translation id="7920092496846849526">Tinanong mo ang iyong magulang kung maaari mong bisitahin ang page na ito.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="7995512525968007366">Hindi Tinukoy</translation>
<translation id="8012647001091218357">Hindi namin makaugnayan ang iyong mga magulang sa sandaling ito. Pakisubukang muli.</translation>
<translation id="8034522405403831421">Nasa <ph name="SOURCE_LANGUAGE" /> ang pahinang ito. Isalin ito sa <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Walang nakitang mga entry ng kasaysayan.</translation>
<translation id="8088680233425245692">Hindi natingnan ang artikulo.</translation>
+<translation id="8089520772729574115">wala pang 1 MB</translation>
<translation id="8091372947890762290">Nakabinbin sa server ang pag-activate</translation>
+<translation id="8129262335948759431">hindi pa natutukoy na dami</translation>
<translation id="8131740175452115882">Kumpirmahin</translation>
<translation id="8134994873729925007">Hindi makita ang <ph name="BEGIN_ABBR" />DNS address<ph name="END_ABBR" /> ng server ng <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Nag-sleep ang iyong computer.</translation>
@@ -604,6 +640,7 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="8201077131113104583">Di-wastong URL ng update para sa extension na may ID na "<ph name="EXTENSION_ID" />."</translation>
<translation id="8218327578424803826">Itinakdang Lokasyon:</translation>
<translation id="8225771182978767009">Pinili ng taong nag-set up ng computer na ito na i-block ang site na ito.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Ang pahina na hinahanap mo para sa paggamit ng impormasyon na ipinasok mo. Ang pagbalik sa pahinang iyon maaaring magsanhi ng anumang aksyon na akalo mo ay naulit. Nais mo bang ipagpatuloy?</translation>
<translation id="8249320324621329438">Huling kinuha:</translation>
<translation id="8261506727792406068">Burahin</translation>
@@ -616,12 +653,17 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="8349305172487531364">Bookmarks bar</translation>
<translation id="8363502534493474904">I-off ang airplane mode</translation>
<translation id="8364627913115013041">Hindi nakatakda.</translation>
+<translation id="8380941800586852976">Mapanganib</translation>
<translation id="8412145213513410671">Mga Pag-crash (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Dapat mong ilagay ang parehong passphrase nang dalawang beses.</translation>
<translation id="8428213095426709021">Mga Setting</translation>
+<translation id="8433057134996913067">Masa-sign out ka sa karamihan ng mga website.</translation>
<translation id="8437238597147034694">&amp;I-undo ang paglilipat</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 credit card}one{# credit card}other{# na credit card}}</translation>
+<translation id="8483780878231876732">Upang gumamit ng mga card mula sa iyong Google Account, mag-sign in sa Chrome</translation>
<translation id="8488350697529856933">Nalalapat sa</translation>
<translation id="8498891568109133222">Masyadong matagal bago nakatugon ang <ph name="HOST_NAME" />.</translation>
+<translation id="852346902619691059">Hindi mapatunayan ng server na ito na ito ang <ph name="DOMAIN" />; ang certificate na panseguridad nito ay hindi pinagkakatiwalaan ng operating system ng iyong device. Maaaring sanhi ito ng maling pag-configure o ng isang nang-aatake na humahadlang sa iyong koneksyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto nang higit pa<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Ang ganitong uri ng card ay hindi sinusuportahan ng Google Payments. Mangyaring pumili ng ibang card.</translation>
<translation id="8550022383519221471">Hindi available ang serbisyo ng pag-sync para sa iyong domain.</translation>
<translation id="8553075262323480129">Nabigo ang pag-translate dahil hindi matukoy ang wika ng pahina.</translation>
@@ -633,15 +675,12 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="8647750283161643317">I-reset ang lahat sa default</translation>
<translation id="8680787084697685621">Wala sa panahon ang mga detalye sa pag-sign-in sa account.</translation>
<translation id="8703575177326907206">Ang iyong koneksyon sa <ph name="DOMAIN" /> ay hindi naka-encrypt.</translation>
-<translation id="8713130696108419660">Maling lagda ng inisyal</translation>
<translation id="8725066075913043281">Muling subukan</translation>
<translation id="8728672262656704056">Naging incognito ka</translation>
<translation id="8730621377337864115">Tapos na</translation>
<translation id="8738058698779197622">Upang makapagtatag ng secure na koneksyon, kailangang itakda nang tama ang iyong orasan. Ito ay dahil sa may-bisa lang ang mga certificate na ginagamit ng mga website upang tukuyin ang mga sarili ng mga ito sa loob ng mga partikular na tagal ng panahon. Dahil mali ang orasan ng iyong device, hindi ma-verify ng Chromium ang mga certificate na ito.</translation>
<translation id="8740359287975076522">Hindi makita ang &lt;abbr id="dnsDefinition"&gt;DNS address&lt;/abbr&gt; ng <ph name="HOST_NAME" />. Dina-diagnose ang problema.</translation>
-<translation id="8741995161408053644">Maaaring may iba pang mga uri ng history ng pagba-browse ang iyong Google Account sa <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Gawing muli ang pagtanggal</translation>
-<translation id="8790687370365610530">Upang kumuha ng naka-personalize na content na iminumungkahi ng Google, i-on ang pag-sync ng history.</translation>
<translation id="8798099450830957504">Default</translation>
<translation id="8804164990146287819">Patakaran sa Privacy</translation>
<translation id="8820817407110198400">Mga Bookmark</translation>
@@ -663,13 +702,11 @@ Psst! Maaaring maging kapaki-pakinabang ang mode na incognito <ph name="SHORTCUT
<translation id="8971063699422889582">Nag-expire na ang certificate ng server.</translation>
<translation id="8987927404178983737">Buwan</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Nagpakita ang server ng certificate na hindi ibinunyag sa publiko gamit ang patakaran sa Transparency ng Certificate. Kinakailangan ito para sa ilang certificate, upang matiyak na mapagkakatiwalaan ang mga ito at maprotektahan laban sa mga umaatake.</translation>
<translation id="9001074447101275817">Nangangailangan ang proxy na <ph name="DOMAIN" /> ng username at password.</translation>
<translation id="901974403500617787">Ang may-ari lang ang maaaring magtakda ng mga flag na nalalapat sa buong system: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Na-translate sa <ph name="TARGET_LANGUAGE" /> ang pahinang ito</translation>
<translation id="9038649477754266430">Gumamit ng serbisyo sa paghula upang ma-load ang mga page nang mas mabilis</translation>
<translation id="9039213469156557790">Bukod pa rito, ang page na ito ay may iba pang mga mapagkukunang hindi secure. Makikita ng iba ang mga mapagkukunang ito habang ipinadadala, at maaaring baguhin ng isang umaatake upang baguhin ang gawi ng page.</translation>
-<translation id="9049981332609050619">Tinangka mong maabot ang <ph name="DOMAIN" />, ngunit nagpakita ang server ng isang di-wastong certificate.</translation>
<translation id="9050666287014529139">Passphrase</translation>
<translation id="9065203028668620118">I-edit</translation>
<translation id="9092364396508701805">Hindi gumagana ang <ph name="HOST_NAME" /> page</translation>
diff --git a/chromium/components/strings/components_strings_fr.xtb b/chromium/components/strings/components_strings_fr.xtb
index 9fb392ce738..2ea580e3aa7 100644
--- a/chromium/components/strings/components_strings_fr.xtb
+++ b/chromium/components/strings/components_strings_fr.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fr">
+<translation id="1008557486741366299">Pas maintenant</translation>
<translation id="1015730422737071372">Fournir des informations supplémentaires</translation>
<translation id="1032854598605920125">Faire pivoter vers la droite</translation>
<translation id="1038842779957582377">Nom inconnu</translation>
+<translation id="1053591932240354961">Vous ne pouvez pas consulter le site Web <ph name="SITE" /> pour le moment, car il a envoyĂ© des identifiants brouillĂ©s qui ne peuvent Ăªtre traitĂ©s par Google Chrome. Les attaques et les erreurs rĂ©seau sont gĂ©nĂ©ralement temporaires. Vous devriez donc pouvoir accĂ©der Ă  cette page ultĂ©rieurement. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">&amp;Annuler l'ajout</translation>
<translation id="10614374240317010">Jamais enregistrés</translation>
-<translation id="1064422015032085147">Le serveur qui hĂ©berge la page Web peut Ăªtre surchargĂ© ou en cours de maintenance.
- Afin d'éviter de générer trop de trafic et d'aggraver la situation,
- les requĂªtes Ă  cette URL ont Ă©tĂ© temporairement interdites.</translation>
<translation id="106701514854093668">Favoris sur l'ordinateur</translation>
<translation id="1080116354587839789">Ajuster Ă  la largeur</translation>
+<translation id="1103124106085518534">Terminé pour le moment</translation>
<translation id="1103523840287552314">Toujours traduire les pages en <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Si cette case est cochée, une copie de votre carte est stockée sur cet appareil pour compléter les formulaires plus rapidement.</translation>
+<translation id="1111153019813902504">Favoris consultés récemment</translation>
<translation id="1113869188872983271">&amp;Annuler la réorganisation</translation>
+<translation id="1126551341858583091">La taille sur l'espace de stockage local est de <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache de la règle valide.</translation>
<translation id="113188000913989374"><ph name="SITE" /> indique :</translation>
<translation id="1132774398110320017">Paramètres de saisie automatique de Chrome…</translation>
-<translation id="1150979032973867961">Impossible de vĂ©rifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© n'est pas considĂ©rĂ© comme fiable par le système d'exploitation de votre ordinateur. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.</translation>
<translation id="1152921474424827756">Accédez à une <ph name="BEGIN_LINK" />copie mise en cache<ph name="END_LINK" /> de <ph name="URL" />.</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> a mis fin à la connexion de manière inattendue.</translation>
<translation id="1161325031994447685">Se reconnecter au réseau Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Supprimer</translation>
<translation id="1201402288615127009">Suivant</translation>
<translation id="1201895884277373915">Plus de résultats pour ce site</translation>
-<translation id="121201262018556460">Vous avez tenté d'accéder à <ph name="DOMAIN" />, mais le serveur a présenté un certificat contenant une clé faible. Il est possible qu'un pirate ait compromis la clé privée. Il est donc possible que le serveur auquel vous avez accédé ne soit pas celui que vous croyez, et que vous soyez en train de communiquer avec un pirate informatique.</translation>
+<translation id="1206967143813997005">Signature initiale incorrecte</translation>
+<translation id="1209206284964581585">Masquer pour le moment</translation>
<translation id="1219129156119358924">Sécurité du système</translation>
<translation id="1227224963052638717">Règle inconnue</translation>
<translation id="1227633850867390598">Masquer la valeur</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Oui</translation>
<translation id="1430915738399379752">Imprimer</translation>
<translation id="1442912890475371290">Une tentative de <ph name="BEGIN_LINK" />consultation d'une page sur <ph name="DOMAIN" /><ph name="END_LINK" /> a été bloquée.</translation>
+<translation id="1491663344921578213">Vous ne pouvez pas consulter le site Web <ph name="SITE" /> pour le moment, car les certificats y sont épinglés. Les attaques et les erreurs réseau sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page ultérieurement. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">Afficher une copie enregistrée (non actualisée) de cette page</translation>
<translation id="1519264250979466059">Date de création</translation>
<translation id="1549470594296187301">Vous devez activer JavaScript pour utiliser cette fonctionnalité.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Impossible d'importer la configuration du réseau : elle n'est pas valide.</translation>
<translation id="1644574205037202324">Historique</translation>
<translation id="1645368109819982629">Protocole incompatible</translation>
-<translation id="1655462015569774233">{1,plural, =1{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© a expirĂ© hier. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. L'horloge de votre ordinateur indique actuellement : <ph name="CURRENT_DATE" />. Cela vous semble-t-il correct ? Si ce n'est pas le cas, vous devez corriger l'horloge de votre système, puis actualiser la page.}one{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© a expirĂ© il y a # jour. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. L'horloge de votre ordinateur indique actuellement : <ph name="CURRENT_DATE" />. Cela vous semble-t-il correct ? Si ce n'est pas le cas, vous devez corriger l'horloge de votre système, puis actualiser la page.}other{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© a expirĂ© il y a # jours. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. L'horloge de votre ordinateur indique actuellement : <ph name="CURRENT_DATE" />. Cela vous semble-t-il correct ? Si ce n'est pas le cas, vous devez corriger l'horloge de votre système, puis actualiser la page.}}</translation>
<translation id="1676269943528358898">Un chiffrement est normalement utilisĂ© sur le site <ph name="SITE" /> pour protĂ©ger vos informations. Lors de la dernière tentative de connexion de Google Chrome au site <ph name="SITE" />, des identifiants inhabituels et incorrects ont Ă©tĂ© retournĂ©s. Il est possible qu'un individu malveillant tente de se faire passer pour <ph name="SITE" /> ou qu'un Ă©cran de connexion Wi-Fi ait interrompu la connexion. Vos informations restent sĂ©curisĂ©es, car nous avons arrĂªtĂ© la connexion avant l'Ă©change des donnĂ©es.</translation>
<translation id="168841957122794586">Le certificat du serveur contient une clé de chiffrement faible.</translation>
<translation id="1701955595840307032">Obtenir une recommandation de contenu</translation>
-<translation id="1706954506755087368">{1,plural, =1{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car la date d'Ă©mission de son certificat de sĂ©curitĂ© est fixĂ©e Ă  demain. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.}one{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car la date d'Ă©mission de son certificat de sĂ©curitĂ© est ultĂ©rieure de # jour Ă  la date du jour. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.}other{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car la date d'Ă©mission de son certificat de sĂ©curitĂ© est ultĂ©rieure de # jours Ă  la date du jour. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.}}</translation>
<translation id="1710259589646384581">Système d'exploitation</translation>
<translation id="1734864079702812349">American Express</translation>
<translation id="1734878702283171397">Essayez de contacter l'administrateur système.</translation>
<translation id="17513872634828108">Onglets ouverts</translation>
<translation id="1753706481035618306">Numéro de page</translation>
-<translation id="1761412452051366565">Pour obtenir une recommandation de contenu personnalisé de la part de Google, activez la synchronisation.</translation>
-<translation id="1763864636252898013">Impossible de vĂ©rifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© n'est pas considĂ©rĂ© comme fiable par le système d'exploitation de votre appareil. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Essayez d'exécuter les diagnostics réseau de Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Mettre à jour votre phrase secrète de synchronisation</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Vos favoris récemment consultés s'afficheront ici.</translation>
<translation id="1821930232296380041">La demande ou ses paramètres ne sont pas valides.</translation>
<translation id="1838667051080421715">Vous consultez actuellement la source d'une page Web.</translation>
<translation id="1871208020102129563">Le proxy est configuré pour utiliser des serveurs proxy déterminés, pas une URL de script .pac.</translation>
<translation id="1883255238294161206">RĂ©duire la liste</translation>
<translation id="1898423065542865115">Filtrage</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> n'a pas acceptĂ© votre certificat de connexion, ou ce dernier a peut-Ăªtre expirĂ©.</translation>
<translation id="194030505837763158">Accédez à <ph name="LINK" /></translation>
<translation id="1962204205936693436">Favoris du domaine <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Erreur de sérialisation.</translation>
<translation id="1974060860693918893">Paramètres avancés</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{et 1 autre}one{et # autre}other{et # autres}}</translation>
<translation id="2025186561304664664">Le proxy est défini sur la configuration automatique.</translation>
<translation id="2030481566774242610">Essayez avec <ph name="LINK" /></translation>
<translation id="2031925387125903299">Ce message s'affiche, car tes parents doivent approuver les nouveaux sites lorsque tu les consultes pour la première fois.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />VĂ©rifier le proxy et le pare-feu<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Code postal</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 suggestion}one{# suggestion}other{# suggestions}}</translation>
<translation id="2065985942032347596">Authentification requise</translation>
<translation id="2079545284768500474">Annuler</translation>
<translation id="20817612488360358">Les paramètres de proxy du système sont configurĂ©s pour Ăªtre utilisĂ©s, mais une configuration de proxy explicite est Ă©galement spĂ©cifiĂ©e.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Modifier le favori</translation>
<translation id="2166049586286450108">Accès administrateur complet</translation>
<translation id="2166378884831602661">Ce site ne peut pas fournir de connexion sécurisée</translation>
-<translation id="2171101176734966184">Vous avez tenté d'accéder à <ph name="DOMAIN" />, mais le serveur a présenté un certificat signé à l'aide d'un algorithme de signature faible. Il est possible que le certificat fourni par le serveur ait été falsifié. Il se peut donc que le serveur ne soit pas celui auquel vous souhaitez accéder, et qu'il s'agisse d'une tentative de piratage.</translation>
<translation id="2181821976797666341">Règles</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}one{# adresse}other{# adresses}}</translation>
<translation id="2212735316055980242">Règle introuvable.</translation>
<translation id="2213606439339815911">Obtention des entrées en cours…</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> n'est pas accessible</translation>
<translation id="2230458221926704099">VĂ©rifiez la connexion Ă  l'aide de l'<ph name="BEGIN_LINK" />application de diagnostic<ph name="END_LINK" />.</translation>
+<translation id="2239100178324503013">Envoyer maintenant</translation>
<translation id="225207911366869382">Cette valeur n'est plus utilisée dans le cadre de cette règle.</translation>
<translation id="2262243747453050782">Erreur HTTP.</translation>
<translation id="2282872951544483773">Tests non disponibles.</translation>
<translation id="2292556288342944218">Votre accès à Internet est bloqué</translation>
<translation id="229702904922032456">Un certificat racine ou intermédiaire a expiré.</translation>
<translation id="230155334948463882">Nouvelle carte ?</translation>
+<translation id="2305919008529760154">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car il se peut que son certificat de sĂ©curitĂ© ait Ă©tĂ© Ă©mis de manière frauduleuse. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> nécessite un nom d'utilisateur et un mot de passe.</translation>
+<translation id="2318774815570432836">Vous ne pouvez pas consulter le site Web <ph name="SITE" /> pour le moment, car la technologie HSTS y est utilisée. Les attaques et les erreurs réseau sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page ultérieurement. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">Favori non valide ignoré (index <ph name="ENTRY_INDEX" />)</translation>
<translation id="2354001756790975382">Autres favoris</translation>
<translation id="2359808026110333948">Continuer</translation>
<translation id="2365563543831475020">Le rapport d'erreur enregistré le <ph name="CRASH_TIME" /> n'a pas été importé.</translation>
<translation id="2367567093518048410">Niveau</translation>
+<translation id="2371153335857947666">{1,plural, =1{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© a expirĂ© hier. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. L'horloge de votre ordinateur indique actuellement : <ph name="CURRENT_DATE" />. Cela vous semble-t-il correct ? Si ce n'est pas le cas, vous devez corriger l'horloge de votre système, puis actualiser la page. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" />}one{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© a expirĂ© il y a # jour. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. L'horloge de votre ordinateur indique actuellement : <ph name="CURRENT_DATE" />. Cela vous semble-t-il correct ? Si ce n'est pas le cas, vous devez corriger l'horloge de votre système, puis actualiser la page. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" />}other{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© a expirĂ© il y a # jours. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. L'horloge de votre ordinateur indique actuellement : <ph name="CURRENT_DATE" />. Cela vous semble-t-il correct ? Si ce n'est pas le cas, vous devez corriger l'horloge de votre système, puis actualiser la page. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">Aucune alternative disponible pour l'interface utilisateur</translation>
<translation id="2384307209577226199">Valeur par défaut définie par l'entreprise</translation>
-<translation id="238526402387145295">Vous ne pouvez pas consulter le site <ph name="SITE" /> pour le moment, car la <ph name="BEGIN_LINK" />technologie HSTS<ph name="END_LINK" /> y est utilisée. Les erreurs réseau et les attaques sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page ultérieurement.</translation>
<translation id="2386255080630008482">Le certificat du serveur a été révoqué.</translation>
<translation id="2392959068659972793">Afficher les règles non paramétrées</translation>
<translation id="2396249848217231973">&amp;Annuler la suppression</translation>
-<translation id="2413528052993050574">Impossible de vĂ©rifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />. Il se peut que son certificat de sĂ©curitĂ© ait Ă©tĂ© rĂ©voquĂ©. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.</translation>
<translation id="2455981314101692989">Cette page Web a désactivé la saisie automatique dans ce formulaire.</translation>
+<translation id="2463739503403862330">Remplir</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Exécuter les diagnostics du réseau<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL de recherche incorrecte</translation>
<translation id="2491120439723279231">Le certificat du serveur contient des erreurs.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Valider</translation>
<translation id="2674170444375937751">Voulez-vous vraiment supprimer ces pages de votre historique ?</translation>
<translation id="2677748264148917807">Quitter</translation>
+<translation id="269990154133806163">Le certificat prĂ©sentĂ© par le serveur n'a pas Ă©tĂ© communiquĂ© au public. Selon le règlement de transparence des certificats, certains certificats doivent obligatoirement Ăªtre communiquĂ©s publiquement pour garantir qu'ils sont dignes de confiance et qu'ils protègent contre les individus malveillants. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">La valeur ne respecte pas le format requis.</translation>
<translation id="2704951214193499422">Impossible de valider votre carte dans Chromium pour le moment. Veuillez réessayer plus tard.</translation>
<translation id="2705137772291741111">La copie enregistrée (en cache) de ce site est illisible.</translation>
<translation id="2709516037105925701">Saisie automatique</translation>
+<translation id="2712118517637785082">Vous avez tenté d'accéder à <ph name="DOMAIN" />, mais le certificat présenté par le serveur a été révoqué par son émetteur. Cela signifie qu'il ne faut en aucun cas faire confiance aux identifiants de sécurité présentés par le serveur. Il est possible que vous communiquiez avec un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">Demander l'autorisation</translation>
<translation id="2721148159707890343">Demande réussie.</translation>
<translation id="2728127805433021124">Le certificat du serveur a été signé avec un algorithme de signature faible.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Barre d'adresse et de recherche</translation>
<translation id="2826760142808435982">La connexion est chiffrée et authentifiée avec la clé <ph name="CIPHER" />. La méthode d'échange de clés utilisé est <ph name="KX" />.</translation>
<translation id="2835170189407361413">Effacer le formulaire</translation>
-<translation id="2837049386027881519">Une nouvelle tentative de connexion a dĂ» Ăªtre effectuĂ©e Ă  l'aide d'une ancienne version du protocole TLS ou SSL. Cela signifie gĂ©nĂ©ralement que le serveur utilise un logiciel obsolète, et qu'il est possible qu'il rencontre d'autres problèmes de sĂ©curitĂ©.</translation>
<translation id="284702764277384724">Le certificat du serveur relatif Ă  <ph name="HOST_NAME" /> semble Ăªtre contrefait.</translation>
<translation id="2889159643044928134">Ne pas actualiser</translation>
-<translation id="2896499918916051536">Ce plug-in n'est pas compatible.</translation>
+<translation id="2900469785430194048">Google Chrome n'avait pas suffisamment de mémoire pour afficher cette page Web.</translation>
<translation id="2909946352844186028">Un changement de réseau a été détecté.</translation>
-<translation id="2915500479781995473">Nous n'avons pas pu vĂ©rifier qu'il s'agissait du domaine <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© a expirĂ©. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou Ă  une tentative d'interception de la connexion par un pirate informatique. L'horloge de votre ordinateur indique actuellement : <ph name="CURRENT_TIME" />. Cela vous semble-t-il correct ? Si ce n'est pas le cas, vous devez corriger l'horloge de votre système, puis rĂ©initialiser la page.</translation>
<translation id="2922350208395188000">Impossible de vérifier le certificat du serveur.</translation>
-<translation id="2941952326391522266">Impossible de vĂ©rifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© provient du domaine <ph name="DOMAIN2" />. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.</translation>
<translation id="2948083400971632585">Vous pouvez désactiver tout proxy configuré pour une connexion à partir de la page des paramètres.</translation>
<translation id="2955913368246107853">Fermer la barre de recherche</translation>
<translation id="2958431318199492670">La configuration du réseau ne respecte pas les normes de l'ONC. Il est possible que des parties de la configuration ne soient pas importées.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Type de règle incorrect.</translation>
<translation id="3032412215588512954">Voulez-vous actualiser ce site ?</translation>
<translation id="3037605927509011580">Aie aie aie</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{au moins 1 élément sur les appareils synchronisés}=1{1 élément (et plus sur appareils synchronisés)}one{# élément (et plus sur appareils synchronisés)}other{# éléments (et plus sur appareils synchronisés)}}</translation>
<translation id="3041612393474885105">Informations relatives au certificat</translation>
<translation id="3063697135517575841">Impossible de valider votre carte dans Chrome pour le moment. Veuillez réessayer plus tard.</translation>
<translation id="3093245981617870298">Vous Ăªtes actuellement hors connexion</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Le plus récent</translation>
<translation id="3207960819495026254">Favori</translation>
-<translation id="3225919329040284222">Le serveur dispose d'un certificat qui ne répond pas aux exigences intégrées. Celles-ci sont incluses dans certains sites Web très sécurisés afin de vous protéger.</translation>
<translation id="3226128629678568754">Veuillez appuyer sur le bouton d'actualisation pour renvoyer les données nécessaires au chargement de la page.</translation>
<translation id="3228969707346345236">La traduction a échoué, car la page est déjà en <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Saisir le code CVC de la carte <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Ajouter cette page aux favoris</translation>
<translation id="3270847123878663523">&amp;Annuler la réorganisation</translation>
<translation id="3286538390144397061">Redémarrer maintenant</translation>
+<translation id="3303855915957856445">Aucun résultat de recherche n'a été trouvé.</translation>
<translation id="3305707030755673451">Vos données ont été chiffrées avec votre phrase secrète de synchronisation le <ph name="TIME" />. Saisissez-la pour lancer la synchronisation.</translation>
<translation id="333371639341676808">EmpĂªcher cette page de gĂ©nĂ©rer des boĂ®tes de dialogue supplĂ©mentaires</translation>
+<translation id="3338095232262050444">Sécurisé</translation>
<translation id="3340978935015468852">paramètres</translation>
<translation id="3345135638360864351">Impossible d'envoyer votre demande d'accès au site à <ph name="NAME" />. Veuillez réessayer.</translation>
<translation id="3355823806454867987">Modifier les paramètres du proxy...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Intervalle de récupération :</translation>
<translation id="3462200631372590220">Masquer les paramètres avancés</translation>
<translation id="3479539252931486093">S'agit-il d'une erreur inattendue ? <ph name="BEGIN_LINK" />Signalez-nous ce problème.<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Pas maintenant</translation>
<translation id="348000606199325318">Identifiant de plantage <ph name="CRASH_LOCAL_ID" /> (identifiant de serveur : <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Impossible de joindre votre parent pour le moment. Veuillez réessayer.</translation>
<translation id="3527085408025491307">Dossier</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Utiliser un mot de passe pour :</translation>
<translation id="3549644494707163724">Chiffrer toutes les données synchronisées avec votre propre phrase secrète de synchronisation</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> autres onglets…</translation>
+<translation id="3555561725129903880">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© provient du domaine <ph name="DOMAIN2" />. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">Votre connexion n'est pas privée</translation>
<translation id="3583757800736429874">&amp;Rétablir le déplacement</translation>
<translation id="3586931643579894722">Masquer les détails</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Afficher la valeur</translation>
<translation id="3630155396527302611">S'il est déjà répertorié en tant que programme autorisé à accéder au réseau,
essayez de le supprimer de la liste, puis de le rajouter.</translation>
+<translation id="3638794133396384728">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© a expirĂ©. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. L'horloge de votre ordinateur indique actuellement : <ph name="CURRENT_TIME" />. Cela vous semble-t-il correct ? Si ce n'est pas le cas, vous devez corriger l'horloge de votre système, puis actualiser la page. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">Ces fonctionnalitĂ©s expĂ©rimentales sont susceptibles d'Ăªtre modifiĂ©es, de cesser de fonctionner ou de disparaĂ®tre Ă  tout moment. Nous ne garantissons en aucun cas les consĂ©quences de l'activation de l'une d'entre elles. Il est mĂªme possible que votre navigateur s'auto-dĂ©truise ! Plus sĂ©rieusement, votre navigateur risque de supprimer toutes vos donnĂ©es. Votre sĂ©curitĂ© et la confidentialitĂ© de vos donnĂ©es peuvent Ă©galement Ăªtre compromises de manière inattendue. Toute fonctionnalitĂ© expĂ©rimentale que vous activez le sera pour tous les utilisateurs de ce navigateur. Faites donc attention.</translation>
<translation id="3650584904733503804">Validation réussie.</translation>
<translation id="3655670868607891010">Si ce message s'affiche régulièrement, essayez ces <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">RĂ©vision</translation>
+<translation id="3678029195006412963">Impossible de signer la demande</translation>
<translation id="3681007416295224113">Informations relatives au certificat</translation>
<translation id="3693415264595406141">Mot de passe :</translation>
+<translation id="3696411085566228381">aucune</translation>
<translation id="3700528541715530410">Petit problème… Vous n'Ăªtes pas autorisĂ© Ă  accĂ©der Ă  cette page.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Chargement...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Activer les données mobiles ou le réseau Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />VĂ©rifier les configurations du proxy, du pare-feu et du DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Lien copié</translation>
-<translation id="3744899669254331632"><ph name="SITE" /> est actuellement inaccessible. Le site Web a envoyé des identifiants brouillés inutilisables par Chromium. Les erreurs de réseau et les attaques étant généralement temporaires, cette page devrait à nouveau fonctionner ultérieurement.</translation>
<translation id="375403751935624634">Échec de la traduction en raison d'une erreur de serveur</translation>
<translation id="3759461132968374835">Aucune erreur n'a été signalée récemment. Les erreurs n'apparaissent ici que lorsque l'envoi de rapports d'erreur est activé.</translation>
<translation id="3788090790273268753">Le certificat de ce site arrive à expiration en 2016, et la chaîne de certificats contient un certificat signé avec SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Identifiant de l'appareil en conflit.</translation>
<translation id="3885155851504623709">Paroisse</translation>
<translation id="3901925938762663762">La carte a expiré.</translation>
+<translation id="3910267023907260648">Vous avez essayĂ© d'accĂ©der Ă  <ph name="DOMAIN" />, mais le serveur a prĂ©sentĂ© un certificat signĂ© avec un algorithme de signature faible. Il se peut que les identifiants de sĂ©curitĂ© prĂ©sentĂ©s par le serveur aient Ă©tĂ© falsifiĂ©s. Le serveur n'est peut-Ăªtre pas celui auquel vous souhaitez accĂ©der (il peut s'agir d'une tentative de piratage). <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car la date d'Ă©mission de son certificat de sĂ©curitĂ© est fixĂ©e Ă  demain. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" />}one{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car la date d'Ă©mission de son certificat de sĂ©curitĂ© est ultĂ©rieure de # jour Ă  la date du jour. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" />}other{Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car la date d'Ă©mission de son certificat de sĂ©curitĂ© est ultĂ©rieure de # jours Ă  la date du jour. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">Échec du chargement du document PDF</translation>
<translation id="3963721102035795474">Mode lecture</translation>
+<translation id="397105322502079400">Calcul en cours…</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> est bloqué</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 page Web à proximité}one{# page Web à proximité}other{# pages Web à proximité}}</translation>
<translation id="4021036232240155012">DNS est le service Web qui convertit les noms de sites Web en adresses Internet.</translation>
<translation id="4030383055268325496">&amp;Annuler l'ajout</translation>
-<translation id="4032534284272647190">Accès à <ph name="URL" /> refusé.</translation>
<translation id="404928562651467259">AVERTISSEMENT</translation>
<translation id="4058922952496707368">Clé "<ph name="SUBKEY" />" : <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Le client et le serveur ne sont pas compatibles avec une version de protocole ou une méthode de chiffrement SSL commune.</translation>
<translation id="4079302484614802869">La configuration du proxy est définie pour utiliser une URL de script .pac, et non pas des serveurs proxy déterminés.</translation>
<translation id="4103249731201008433">Le numéro de série de l'appareil n'est pas valide.</translation>
<translation id="4103763322291513355">Accédez à &lt;strong&gt;chrome://policy&lt;/strong&gt; pour consulter une liste des URL ajoutées à la liste noire et des autres règles définies par votre administrateur système.</translation>
+<translation id="4110615724604346410">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© contient des erreurs. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">La portée de la règle n'est pas compatible.</translation>
+<translation id="4118212371799607889">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© n'est pas considĂ©rĂ© comme fiable par Chromium. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 autre}one{# autre}other{# autres}}</translation>
<translation id="4130226655945681476">VĂ©rifiez les cĂ¢bles rĂ©seau, le modem et le routeur.</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Voulez-vous que cette carte soit enregistrée dans Chromium ?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Désactivé</translation>
<translation id="4196861286325780578">&amp;Rétablir le déplacement</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />VĂ©rifier les configurations du pare-feu et de l'antivirus<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{aucune}=1{1 application ($1)}=2{2 applications ($1, $2)}one{# application ($1, $2 $3)}other{# applications ($1, $2 $3)}}</translation>
<translation id="4220128509585149162">Plantages</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Essayez d'exécuter les diagnostics réseau<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Non</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(aucun nom d'utilisateur)</translation>
<translation id="4300246636397505754">Suggestions des parents</translation>
<translation id="4304224509867189079">Se connecter</translation>
+<translation id="432290197980158659">Le serveur a présenté un certificat qui ne répond pas aux exigences intégrées. Celles-ci sont incluses dans certains sites Web très sécurisés afin de vous protéger. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">Échec de la recherche de l'article.</translation>
+<translation id="4331708818696583467">Non sécurisé</translation>
<translation id="4372948949327679948">Valeur attendue : <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">Vous avez tentĂ© d'accĂ©der Ă  <ph name="DOMAIN" />, mais le certificat prĂ©sentĂ© par le serveur a Ă©tĂ© rĂ©voquĂ© par son Ă©metteur. Cela signifie que le certificat prĂ©sentĂ© par le serveur ne doit pas Ăªtre approuvĂ©. Il est donc possible que vous communiquiez avec un pirate informatique.</translation>
<translation id="4381091992796011497">Nom d'utilisateur :</translation>
<translation id="4394049700291259645">DĂ©sactiver</translation>
<translation id="4395129973926795186">Du <ph name="START_DATE" /> au <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">résultats de recherche</translation>
-<translation id="4424024547088906515">Impossible de vĂ©rifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© n'est pas considĂ©rĂ© comme fiable par Chrome. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> n'a pas accepté votre certificat de connexion, ou vous ne l'avez pas fourni.</translation>
<translation id="443673843213245140">L'utilisation d'un proxy est désactivée, mais une configuration de proxy explicite est spécifiée.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Ce message s'affiche, car Google SafeSites est activé.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">DĂ©tails</translation>
<translation id="4558551763791394412">Essayez de désactiver les extensions.</translation>
<translation id="4587425331216688090">Supprimer l'adresse de Chrome ?</translation>
+<translation id="4589078953350245614">Vous avez tenté d'accéder à <ph name="DOMAIN" />, mais le certificat présenté par le serveur est incorrect. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459">Votre connexion à <ph name="DOMAIN" /> est chiffrée à l'aide d'une méthode de chiffrement récente.</translation>
<translation id="4594403342090139922">&amp;Annuler la suppression</translation>
+<translation id="4627442949885028695">Continuer sur un autre appareil</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Vous consultez actuellement une page d'extension.</translation>
-<translation id="467662567472608290">Impossible de vĂ©rifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© contient des erreurs. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.</translation>
-<translation id="4697214168136963651">L'adresse <ph name="URL" /> a été bloquée</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Votre connexion a été interrompue</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Exécuter les diagnostics réseau de Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Plate-forme</translation>
<translation id="4744603770635761495">Chemin d'accès exécutable</translation>
<translation id="4756388243121344051">&amp;Historique</translation>
+<translation id="4759238208242260848">Téléchargements</translation>
<translation id="4764776831041365478">Il se peut que la page Web à l'adresse <ph name="URL" /> soit temporairement inaccessible ou qu'elle ait été déplacée de façon permanente à une autre adresse Web.</translation>
<translation id="4771973620359291008">Une erreur inconnue s'est produite.</translation>
<translation id="4782449893814226250">Une demande d'autorisation a été envoyée à tes parents pour la consultation de cette page.</translation>
<translation id="4800132727771399293">Veuillez vérifier la date d'expiration et le code CVC, puis réessayez.</translation>
-<translation id="4807049035289105102"><ph name="SITE" /> est actuellement inaccessible. Le site Web a envoyé des identifiants brouillés inutilisables par Google Chrome. Les erreurs de réseau et les attaques étant généralement temporaires, cette page devrait à nouveau fonctionner ultérieurement.</translation>
<translation id="4813512666221746211">Erreur réseau.</translation>
<translation id="4816492930507672669">Ajuster Ă  la page</translation>
<translation id="4850886885716139402">Afficher</translation>
<translation id="4880827082731008257">Rechercher dans l'historique</translation>
+<translation id="4884656795097055129">D'autres articles s'afficheront au moment opportun.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{et 1 autre page Web}one{et # autre page Web}other{et # autres pages Web}}</translation>
<translation id="4923417429809017348">Cette page rédigée dans une langue non identifiée a été traduite en <ph name="LANGUAGE_LANGUAGE" />.</translation>
<translation id="4926049483395192435">Doit Ăªtre spĂ©cifiĂ©.</translation>
<translation id="4930497775425430760">Ce message s'affiche, car ton papa/ta maman doit approuver les nouveaux sites lorsque tu les consultes pour la première fois.</translation>
<translation id="495170559598752135">Actions</translation>
<translation id="4958444002117714549">DĂ©velopper la liste</translation>
+<translation id="4962322354953122629">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© n'est pas considĂ©rĂ© comme fiable par Chrome. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911">Traduire en <ph name="TARGET_LANGUAGE" /> cette page affichée en <ph name="ORIGINAL_LANGUAGE" /> ?</translation>
+<translation id="4989809363548539747">Ce plug-in n'est pas compatible.</translation>
<translation id="5002932099480077015">Si cette option est activée, Chrome enregistre une copie de votre carte sur cet appareil pour vous permettre de remplir plus rapidement les formulaires.</translation>
<translation id="5019198164206649151">L'espace de stockage destiné à la sauvegarde est en mauvais état.</translation>
<translation id="5023310440958281426">Vérifiez les règles définies par votre administrateur</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">À propos de Google Traduction</translation>
<translation id="5040262127954254034">Confidentialité</translation>
<translation id="5045550434625856497">Mot de passe incorrect</translation>
+<translation id="5056549851600133418">Articles pour vous</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />VĂ©rifier l'adresse du proxy<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Le certificat actuel du serveur n'est pas valide.</translation>
<translation id="5089810972385038852">État</translation>
-<translation id="5094747076828555589">Impossible de vĂ©rifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© n'est pas considĂ©rĂ© comme fiable par Chromium. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.</translation>
<translation id="5095208057601539847">Province</translation>
<translation id="5115563688576182185">(64 bits)</translation>
-<translation id="5122371513570456792"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ont été trouvés pour "<ph name="SEARCH_STRING" />".</translation>
<translation id="5141240743006678641">Chiffrer les mots de passe synchronisés avec vos certificats Google</translation>
<translation id="5145883236150621069">Code d'erreur présent dans la réponse de la règle.</translation>
<translation id="5171045022955879922">Rechercher ou saisir une URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Barre de favoris</translation>
<translation id="5199729219167945352">Prototypes</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">Vous utilisez Chrome au travail ? Les entreprises peuvent gérer les paramètres Chrome de leurs employés. En savoir plus</translation>
<translation id="5299298092464848405">Erreur d'analyse de la règle.</translation>
<translation id="5300589172476337783">Afficher</translation>
<translation id="5308689395849655368">L'envoi de rapports d'erreur est désactivé.</translation>
<translation id="5317780077021120954">Enregistrer</translation>
<translation id="5327248766486351172">Nom</translation>
+<translation id="5359637492792381994">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© actuel n'est pas valide. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Échec du stockage des paramètres de la règle.</translation>
-<translation id="540969355065856584">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© actuel n'est pas valide. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.</translation>
<translation id="5421136146218899937">Effacer les données de navigation...</translation>
<translation id="5430298929874300616">Supprimer le favori</translation>
<translation id="5431657950005405462">Votre fichier est introuvable</translation>
<translation id="5435775191620395718">Affichage de l'historique de cet appareil. <ph name="BEGIN_LINK" />En savoir plus<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">Les recommandations de contenu personnalisé sont actuellement désactivées, car vos informations synchronisées sont protégées par une phrase secrète personnalisée.</translation>
<translation id="5439770059721715174">Erreur de validation du schéma au niveau de "<ph name="ERROR_PATH" />" : <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Cette page du site <ph name="HOST_NAME" /> est introuvable</translation>
<translation id="5455374756549232013">Horodatage de la règle incorrect.</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Voulez-vous quitter ce site ?</translation>
<translation id="5629630648637658800">Échec du chargement des paramètres de la règle.</translation>
<translation id="5631439013527180824">Jeton de gestion de l'appareil non valide.</translation>
-<translation id="5650551054760837876">Aucun résultat de recherche trouvé</translation>
<translation id="5677928146339483299">Bloqué</translation>
<translation id="5710435578057952990">L'identité de ce site Web n'a pas été vérifiée.</translation>
<translation id="5720705177508910913">Utilisateur actuel</translation>
+<translation id="572328651809341494">Onglets récents</translation>
<translation id="5784606427469807560">Un problème est survenu lors de la validation de votre carte. Vérifiez votre connexion Internet, puis réessayez.</translation>
<translation id="5785756445106461925">De plus, cette page inclut d'autres ressources qui ne sont pas sĂ©curisĂ©es. Ces ressources peuvent Ăªtre consultĂ©es par des tiers pendant leur transfert, et modifiĂ©es par un pirate informatique dans le but de changer l'aspect de cette page.</translation>
+<translation id="5786044859038896871">Souhaitez-vous indiquer vos informations de carte de paiement ?</translation>
+<translation id="5803412860119678065">Souhaitez-vous indiquer les informations "<ph name="CARD_DETAIL" />" ?</translation>
<translation id="5810442152076338065">Votre connexion à <ph name="DOMAIN" /> est chiffrée à l'aide d'une méthode de chiffrement obsolète.</translation>
<translation id="5813119285467412249">&amp;RĂ©tablir l'ajout</translation>
+<translation id="5814352347845180253">Vous risquez de ne plus avoir accès au contenu premium de <ph name="SITE" /> et de certains autres sites.</translation>
+<translation id="5843436854350372569">Vous avez tenté d'accéder à <ph name="DOMAIN" />, mais le serveur a présenté un certificat contenant une clé faible. Il est possible qu'un pirate informatique ait compromis la clé privée, que le serveur auquel vous avez accédé ne soit pas celui que vous croyez et que vous soyez en train de communiquer avec un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">Ce message s'affiche, car votre responsable a bloqué ce site.</translation>
<translation id="5857090052475505287">Nouveau dossier</translation>
<translation id="5869405914158311789">Ce site est inaccessible</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Suggestions des parents</translation>
<translation id="59107663811261420">Ce type de carte n'est pas compatible avec Google Payments pour ce marchand. Veuillez sélectionner une autre carte.</translation>
<translation id="59174027418879706">Activée</translation>
+<translation id="5926846154125914413">Vous risquez de ne plus avoir accès au contenu premium de certains sites.</translation>
<translation id="5966707198760109579">Semaine</translation>
<translation id="5967867314010545767">Supprimer de l'historique</translation>
<translation id="5975083100439434680">Zoom arrière</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Automatique</translation>
<translation id="6042308850641462728">Plus</translation>
<translation id="6060685159320643512">Attention, ces fonctionnalités expérimentales peuvent mordre.</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{aucun}=1{1}one{#}other{#}}</translation>
<translation id="6146055958333702838">VĂ©rifiez les cĂ¢bles et redĂ©marrez votre routeur, votre modem
ou tout autre périphérique réseau utilisé.</translation>
<translation id="614940544461990577">Essayez les suggestions ci-dessous :</translation>
<translation id="6150607114729249911">Petit problème… Tu dois demander à tes parents l'autorisation de consulter cette page.</translation>
<translation id="6151417162996330722">La durée de validité du certificat du serveur est trop longue.</translation>
-<translation id="6154808779448689242">Le jeton de la règle renvoyé ne correspond pas au jeton actuel.</translation>
<translation id="6165508094623778733">En savoir plus</translation>
<translation id="6203231073485539293">VĂ©rifiez votre connexion Internet</translation>
<translation id="6218753634732582820">Supprimer l'adresse de Chromium ?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Essayez de désactiver la prédiction réseau</translation>
<translation id="6337534724793800597">Filtrer les règles par nom</translation>
<translation id="6342069812937806050">Ă€ l'instant</translation>
+<translation id="6345221851280129312">taille inconnue</translation>
<translation id="6355080345576803305">Contournement dĂ» Ă  la session publique</translation>
<translation id="6358450015545214790">Qu'est-ce que c'est ?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 autre suggestion}one{# autre suggestion}other{# autres suggestions}}</translation>
<translation id="6387478394221739770">Vous souhaitez bĂ©nĂ©ficier de nouvelles fonctionnalitĂ©s Chrome passionnantes ? Essayez notre version bĂªta Ă  l'adresse chrome.com/beta.</translation>
-<translation id="641480858134062906">Échec du chargement de la page <ph name="URL" /></translation>
+<translation id="6389758589412724634">Chromium n'avait pas suffisamment de mémoire pour afficher cette page Web.</translation>
+<translation id="6416403317709441254">Vous ne pouvez pas consulter le site Web <ph name="SITE" /> pour le moment, car il a envoyĂ© des identifiants brouillĂ©s qui ne peuvent Ăªtre traitĂ©s par Chromium. Les attaques et les erreurs rĂ©seau sont gĂ©nĂ©ralement temporaires. Vous devriez donc pouvoir accĂ©der Ă  cette page ultĂ©rieurement. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">Impossible de vérifier si le certificat a été révoqué.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> n'autorise pas la connexion.</translation>
<translation id="6445051938772793705">Pays</translation>
<translation id="6451458296329894277">Confirmer le nouvel envoi du formulaire</translation>
<translation id="6458467102616083041">Ignoré parce que la recherche par défaut est désactivée par une règle.</translation>
+<translation id="6462969404041126431">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car il se peut que son certificat de sĂ©curitĂ© ait Ă©tĂ© rĂ©voquĂ©. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">Règles relatives aux appareils</translation>
<translation id="6489534406876378309">Lancer l'importation des plantages</translation>
<translation id="6529602333819889595">&amp;RĂ©tablir la suppression</translation>
+<translation id="6534179046333460208">Suggestions pour le Web physique</translation>
<translation id="6550675742724504774">Options</translation>
+<translation id="6593753688552673085">moins de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Options de chiffrement</translation>
<translation id="662080504995468778">Rester</translation>
<translation id="6628463337424475685">Recherche <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Vous ne pouvez pas consulter le site <ph name="SITE" /> pour le moment, car ce <ph name="BEGIN_LINK" />certificat a été révoqué<ph name="END_LINK" />. Les erreurs réseau et les attaques sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page ultérieurement.</translation>
<translation id="6644283850729428850">Cette règle est obsolète.</translation>
+<translation id="6652240803263749613">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© n'est pas considĂ©rĂ© comme fiable par le système d'exploitation de votre ordinateur. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">Modifier le dossier</translation>
<translation id="6660210980321319655">Signalé automatiquement le <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Supprimer la suggestion de saisie de formulaire de Chromium ?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Précédent</translation>
<translation id="6710594484020273272">&lt;Saisissez le terme de recherche&gt;</translation>
<translation id="6711464428925977395">Le serveur proxy présente une erreur, ou l'adresse est incorrecte.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{aucun}=1{1 élément}one{# élément}other{# éléments}}</translation>
<translation id="674375294223700098">Erreur inconnue liée au certificat du serveur.</translation>
<translation id="6753269504797312559">Valeur de la règle</translation>
<translation id="6757797048963528358">Votre appareil s'est mis en veille.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Le niveau de la règle n'est pas accepté.</translation>
<translation id="6895330447102777224">Carte validée</translation>
<translation id="6897140037006041989">Agent utilisateur</translation>
-<translation id="6903907808598579934">Activer la synchronisation</translation>
<translation id="6915804003454593391">Utilisateur :</translation>
<translation id="6957887021205513506">Le certificat du serveur semble Ăªtre contrefait.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">District</translation>
<translation id="6973656660372572881">Les serveurs proxy déterminés et une URL de script .pac sont spécifiés tous les deux.</translation>
<translation id="6989763994942163495">Afficher les paramètres avancés…</translation>
+<translation id="7000990526846637657">Aucune entrée d'historique trouvée</translation>
+<translation id="7009986207543992532">Vous avez essayĂ© d'accĂ©der Ă  <ph name="DOMAIN" />, mais la durĂ©e de validitĂ© du certificat du serveur est trop longue pour Ăªtre fiable. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Votre compte Google conserve peut-Ăªtre d'autres formes d'historique de navigation sur la page <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="7029809446516969842">Mots de passe</translation>
-<translation id="7050187094878475250">Vous avez essayĂ© d'accĂ©der Ă  <ph name="DOMAIN" />, mais la durĂ©e de validitĂ© du certificat du serveur est trop longue pour Ăªtre fiable.</translation>
<translation id="7087282848513945231">Comté</translation>
<translation id="7088615885725309056">Ancien</translation>
<translation id="7090678807593890770">Effectuez une recherche Google sur <ph name="LINK" />.</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Ce message s'affiche, car votre responsable doit approuver les nouveaux sites lorsque vous les consultez pour la première fois.</translation>
<translation id="724975217298816891">Saisissez la date d'expiration et le code CVC de la carte <ph name="CREDIT_CARD" /> pour mettre à jour les informations relatives à celle-ci. Une fois la validation effectuée, les informations seront partagées avec ce site.</translation>
<translation id="725866823122871198">Impossible d'établir une connexion privée à <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> : la date et l'heure de votre ordinateur (<ph name="DATE_AND_TIME" />) sont incorrectes.</translation>
-<translation id="7265986070661382626">Vous ne pouvez pas consulter le site <ph name="SITE" /> pour le moment, car l'<ph name="BEGIN_LINK" />épinglage des certificats<ph name="END_LINK" /> y est utilisé. Les erreurs réseau et les attaques sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page ultérieurement.</translation>
<translation id="7269802741830436641">Cette page Web présente une boucle de redirection.</translation>
<translation id="7275334191706090484">Favoris gérés</translation>
<translation id="7298195798382681320">Recommandé</translation>
-<translation id="7301833672208172928">Activer la synchronisation de l'historique</translation>
+<translation id="7309308571273880165">Rapport d'erreur enregistré le <ph name="CRASH_TIME" /> (importation demandée par l'utilisateur, mais non effectuée)</translation>
<translation id="7334320624316649418">&amp;Rétablir la réorganisation</translation>
<translation id="733923710415886693">Le certificat du serveur n'a pas été communiqué tel que le prévoient les règles de transparence des certificats.</translation>
+<translation id="7351800657706554155">Vous ne pouvez pas consulter le site <ph name="SITE" /> pour le moment, car le certificat correspondant a été révoqué. Les attaques et les erreurs réseau sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page plus tard. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">Ligne de commande</translation>
<translation id="7372973238305370288">résultat de recherche</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Conseil : Le mode navigation privĂ©e (<ph name="SHORTCUT_KEY" />) pourra vous Ă
<translation id="7469372306589899959">Validation de la carte…</translation>
<translation id="7481312909269577407">Avancer</translation>
<translation id="7485870689360869515">Aucune donnée n'a été trouvée.</translation>
+<translation id="7508255263130623398">L'ID d'appareil de la règle renvoyé est vide ou ne correspond pas à l'ID d'appareil actuel.</translation>
<translation id="7514365320538308">Télécharger</translation>
<translation id="7518003948725431193">Aucune page Web trouvée à l'adresse :<ph name="URL" /></translation>
<translation id="7537536606612762813">Obligatoire</translation>
<translation id="7542995811387359312">La saisie automatique des numéros de carte de paiement est désactivée, car la connexion utilisée par ce formulaire n'est pas sécurisée.</translation>
<translation id="7549584377607005141">Pour s'afficher correctement, cette page Web a besoin des données que vous avez saisies précédemment. Vous pouvez envoyer de nouveau ces données. Cependant, en procédant ainsi, vous répéterez toute action déjà effectuée sur cette page.</translation>
<translation id="7554791636758816595">Nouvel onglet</translation>
-<translation id="7567204685887185387">Impossible de vĂ©rifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />. Il se peut que son certificat de sĂ©curitĂ© ait Ă©tĂ© Ă©mis de manière frauduleuse. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique.</translation>
<translation id="7568593326407688803">Cette page est en<ph name="ORIGINAL_LANGUAGE" />Voulez-vous la traduire ?</translation>
<translation id="7569952961197462199">Supprimer les données de carte de paiement de Chrome ?</translation>
<translation id="7578104083680115302">Payez rapidement sur des sites et dans des applications sur tous vos appareils au moyen de cartes que vous avez enregistrées sur Google.</translation>
+<translation id="7588950540487816470">Web physique</translation>
<translation id="7592362899630581445">Le certificat du serveur ne respecte pas les restrictions de noms.</translation>
<translation id="759889825892636187">Impossible de traiter cette demande via <ph name="HOST_NAME" /> Ă  l'heure actuelle.</translation>
<translation id="7600965453749440009">Ne jamais traduire les pages rédigées en <ph name="LANGUAGE" /> </translation>
@@ -561,6 +595,7 @@ Conseil : Le mode navigation privĂ©e (<ph name="SHORTCUT_KEY" />) pourra vous Ă
<translation id="7637571805876720304">Supprimer les données de carte de paiement de Chromium ?</translation>
<translation id="765676359832457558">Masquer les paramètres avancés…</translation>
<translation id="7658239707568436148">Annuler</translation>
+<translation id="7667346355482952095">Le jeton de règle renvoyé est vide ou ne correspond pas au jeton actuel.</translation>
<translation id="7668654391829183341">Appareil inconnu</translation>
<translation id="7674629440242451245">Vous souhaitez bénéficier de nouvelles fonctionnalités Chrome passionnantes ? Essayez notre version en développement à l'adresse chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Continuer vers le site <ph name="SITE" /> (dangereux)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Conseil : Le mode navigation privĂ©e (<ph name="SHORTCUT_KEY" />) pourra vous Ă
<translation id="780301667611848630">Non merci</translation>
<translation id="7805768142964895445">État</translation>
<translation id="7813600968533626083">Supprimer la suggestion de saisie de formulaire de Chrome ?</translation>
+<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> trouvé(s) pour "<ph name="SEARCH_STRING" />"</translation>
<translation id="785549533363645510">Cependant, cela ne vous rend pas invisible. Si vous passez en mode navigation privée, votre employeur, votre fournisseur d'accès à Internet ou les sites Web que vous consultez pourront toujours avoir accès à votre historique de navigation.</translation>
<translation id="7887683347370398519">Veuillez vérifier votre code CVC et réessayer.</translation>
<translation id="7894616681410591072">Petit problème… Vous devez posséder l'autorisation du responsable <ph name="NAME" /> pour accéder à cette page.</translation>
-<translation id="790025292736025802"><ph name="URL" /> introuvable</translation>
<translation id="7912024687060120840">Dans le dossier :</translation>
<translation id="7920092496846849526">Une demande d'autorisation a été envoyée à tes parents pour la consultation de cette page.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ Conseil : Le mode navigation privĂ©e (<ph name="SHORTCUT_KEY" />) pourra vous Ă
<translation id="7995512525968007366">Non spécifié</translation>
<translation id="8012647001091218357">Impossible de joindre vos parents pour le moment. Veuillez réessayer.</translation>
<translation id="8034522405403831421">Cette page est rédigée en <ph name="SOURCE_LANGUAGE" />. Voulez-vous la traduire en <ph name="TARGET_LANGUAGE" /> ?</translation>
-<translation id="8034955203865359138">Aucune entrée d'historique trouvée.</translation>
<translation id="8088680233425245692">Échec de l'affichage de l'article.</translation>
+<translation id="8089520772729574115">moins de 1 Mo</translation>
<translation id="8091372947890762290">Activation en attente sur le serveur.</translation>
+<translation id="8129262335948759431">montant inconnu</translation>
<translation id="8131740175452115882">Confirmer</translation>
<translation id="8134994873729925007">Impossible de trouver l'<ph name="BEGIN_ABBR" />adresse DNS<ph name="END_ABBR" /> du serveur <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Votre ordinateur s'est mis en veille.</translation>
@@ -604,6 +640,7 @@ Conseil : Le mode navigation privĂ©e (<ph name="SHORTCUT_KEY" />) pourra vous Ă
<translation id="8201077131113104583">URL de mise à jour non valide pour l'extension associée à l'identifiant "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Position attribuée :</translation>
<translation id="8225771182978767009">La personne qui a configuré cet ordinateur a choisi de bloquer ce site.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">La page que vous recherchez a utilisé des informations que vous avez envoyées. Si vous revenez sur cette page, chaque action précédemment effectuée sera répétée. Souhaitez-vous continuer ?</translation>
<translation id="8249320324621329438">Dernière récupération :</translation>
<translation id="8261506727792406068">Supprimer</translation>
@@ -616,12 +653,17 @@ Conseil : Le mode navigation privĂ©e (<ph name="SHORTCUT_KEY" />) pourra vous Ă
<translation id="8349305172487531364">Barre de favoris</translation>
<translation id="8363502534493474904">DĂ©sactiver le mode Avion</translation>
<translation id="8364627913115013041">Non définie</translation>
+<translation id="8380941800586852976">Dangereux</translation>
<translation id="8412145213513410671">Erreurs (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Vous devez saisir deux fois la mĂªme phrase secrète.</translation>
<translation id="8428213095426709021">Paramètres</translation>
+<translation id="8433057134996913067">Vous serez déconnecté de la plupart des sites.</translation>
<translation id="8437238597147034694">&amp;Annuler le déplacement</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 carte de paiement}one{# carte de paiement}other{# cartes de paiement}}</translation>
+<translation id="8483780878231876732">Pour utiliser les cartes de votre compte Google, connectez-vous Ă  Chrome.</translation>
<translation id="8488350697529856933">S'applique Ă </translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> a mis trop de temps à répondre.</translation>
+<translation id="852346902619691059">Impossible de vĂ©rifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sĂ©curitĂ© n'est pas considĂ©rĂ© comme fiable par le système d'exploitation de votre appareil. Cela peut Ăªtre dĂ» Ă  une mauvaise configuration ou bien Ă  l'interception de votre connexion par un pirate informatique. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Ce type de carte n'est pas compatible avec Google Payments. Veuillez sélectionner une autre carte.</translation>
<translation id="8550022383519221471">Le service de synchronisation n'est pas disponible pour votre domaine.</translation>
<translation id="8553075262323480129">La traduction a échoué, car nous n'avons pas pu déterminer la langue de la page.</translation>
@@ -633,15 +675,12 @@ Conseil : Le mode navigation privĂ©e (<ph name="SHORTCUT_KEY" />) pourra vous Ă
<translation id="8647750283161643317">Rétablir tous les tests par défaut</translation>
<translation id="8680787084697685621">Les informations de connexion au compte sont obsolètes.</translation>
<translation id="8703575177326907206">Votre connexion à <ph name="DOMAIN" /> n'est pas chiffrée.</translation>
-<translation id="8713130696108419660">Signature initiale incorrecte.</translation>
<translation id="8725066075913043281">RĂ©essayer</translation>
<translation id="8728672262656704056">Vous Ăªtes passĂ© en mode navigation privĂ©e</translation>
<translation id="8730621377337864115">OK</translation>
<translation id="8738058698779197622">Afin d'Ă©tablir une connexion sĂ©curisĂ©e, votre horloge doit Ăªtre rĂ©glĂ©e correctement. Les certificats permettant aux sites Web de s'identifier sont en effet valides pendant une pĂ©riode prĂ©cise. Si l'horloge de votre appareil est incorrecte, Chromium n'est pas en mesure de vĂ©rifier la validitĂ© des certificats.</translation>
<translation id="8740359287975076522">L'&lt;abbr id="dnsDefinition"&gt;adresse DNS&lt;/abbr&gt; de <ph name="HOST_NAME" /> est introuvable. Identification du problème…</translation>
-<translation id="8741995161408053644">Votre compte Google conserve peut-Ăªtre d'autres formes d'historique de navigation sur la page <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;RĂ©tablir la suppression</translation>
-<translation id="8790687370365610530">Pour obtenir une recommandation de contenu personnalisé de la part de Google, activez la synchronisation de l'historique.</translation>
<translation id="8798099450830957504">Par défaut</translation>
<translation id="8804164990146287819">Règles de confidentialité</translation>
<translation id="8820817407110198400">Favoris</translation>
@@ -663,13 +702,11 @@ Conseil : Le mode navigation privĂ©e (<ph name="SHORTCUT_KEY" />) pourra vous Ă
<translation id="8971063699422889582">Le certificat du serveur a expiré.</translation>
<translation id="8987927404178983737">Mois</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Le certificat prĂ©sentĂ© par le serveur n'a pas Ă©tĂ© communiquĂ© au public. Selon les règles de transparence des certificats, certains certificats doivent obligatoirement Ăªtre communiquĂ©s publiquement pour garantir qu'ils sont dignes de confiance et qu'ils protègent contre les individus malveillants.</translation>
<translation id="9001074447101275817">Le proxy <ph name="DOMAIN" /> nécessite un nom d'utilisateur et un mot de passe.</translation>
<translation id="901974403500617787">Seul le propriétaire suivant peut définir les options qui s'appliquent à tout le système : <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Cette page a été traduite en <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="9038649477754266430">Utiliser un service de prédiction pour charger les pages plus rapidement</translation>
<translation id="9039213469156557790">De plus, cette page inclut d'autres ressources qui ne sont pas sĂ©curisĂ©es. Ces ressources peuvent Ăªtre consultĂ©es par des tiers pendant leur transfert, et modifiĂ©es par un pirate informatique dans le but de changer le comportement de cette page.</translation>
-<translation id="9049981332609050619">Vous avez tenté de contacter <ph name="DOMAIN" />, mais le certificat présenté par le serveur est incorrect.</translation>
<translation id="9050666287014529139">Phrase secrète</translation>
<translation id="9065203028668620118">Modifier</translation>
<translation id="9092364396508701805">La page <ph name="HOST_NAME" /> ne fonctionne pas</translation>
diff --git a/chromium/components/strings/components_strings_gu.xtb b/chromium/components/strings/components_strings_gu.xtb
index 7eae575cd88..e7f47530208 100644
--- a/chromium/components/strings/components_strings_gu.xtb
+++ b/chromium/components/strings/components_strings_gu.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="gu">
+<translation id="1008557486741366299">હમણાં નહીં</translation>
<translation id="1015730422737071372">અતિરિકà«àª¤ વિગતો પà«àª°àª¦àª¾àª¨ કરો</translation>
<translation id="1032854598605920125">ઘડિયાળની દિશામાં ફેરવો</translation>
<translation id="1038842779957582377">અજà«àªàª¾àª¤ નામ</translation>
+<translation id="1053591932240354961">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે વેબસાઇટે સમજાય નહીં તેવા ઓળખપતà«àª° મોકલà«àª¯àª¾àª‚ છે જેની પર Google Chrome પà«àª°àª•à«àª°àª¿àª¯àª¾ કરી શકતà«àª‚ નથી. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પૃષà«àª  સંભવિત રૂપે પછીથી કારà«àª¯ કરશે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;ઉમેરવà«àª‚ પૂરà«àªµàªµàª¤à« કરો</translation>
<translation id="10614374240317010">કà«àª¯àª¾àª°à«‡àª¯ ન સàªàªµàª¾àª¯à«‡àª²à«àª‚</translation>
-<translation id="1064422015032085147">વેબપૃષà«àª àª¨à«‡ હોસà«àªŸ કરતà«àª‚ સરà«àªµàª° ઓવરલોડ થઇ ગયà«àª‚ હોઇ શકે અથવા જાળવણી હેઠળ હોઇ શકે. 
- વધૠપડતો ટà«àª°àª¾àª«àª¿àª• ઉતà«àªªàª¨à«àª¨ થતો અને પરિસà«àª¥àª¿àª¤àª¿àª¨à«‡ વણસતી અટકાવવા માટે, આ URL ને
- કરાયેલ વિનંતીઓને અસà«àª¥àª¾àª¯à«€ રૂપે નામંજૂર કરવામાં આવી છે.</translation>
<translation id="106701514854093668">ડેસà«àª•àªŸà«‰àªª બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
<translation id="1080116354587839789">પહોળાઈ પà«àª°àª®àª¾àª£à«‡ ફિટ કરો</translation>
+<translation id="1103124106085518534">હમણાં પૂરતà«àª‚ થઈ ગયà«àª‚</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> નો હંમેશાં અનà«àªµàª¾àª¦ કરો</translation>
<translation id="1107591249535594099">જો àªà«‡àª• કરેલà«àª‚ હોય, તો àªàª¡àªªàª¥à«€ ફોરà«àª® ભરવા માટે Chrome આ ઉપકરણ પર તમારા કારà«àª¡àª¨à«€ àªàª• કૉપિ સંગà«àª°àª¹àª¶à«‡.</translation>
+<translation id="1111153019813902504">હાલનાં બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
<translation id="1113869188872983271">&amp;પà«àª¨àªƒàª•à«àª°àª®àª¾àª‚કિત કરવà«àª‚ પૂરà«àªµàªµàª¤à« કરો</translation>
+<translation id="1126551341858583091">સà«àª¥àª¾àª¨àª¿àª• સà«àªŸà«‹àª°à«‡àªœ પરનà«àª‚ કદ <ph name="CRASH_SIZE" /> છે.</translation>
<translation id="112840717907525620">નીતિ કેશ ઓકે</translation>
<translation id="113188000913989374"><ph name="SITE" /> આ કહે છે:</translation>
<translation id="1132774398110320017">Chrome સà«àªµàª¤àªƒàª­àª°àª£ સેટિંગà«àª¸...</translation>
-<translation id="1150979032973867961">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઑપરેટિંગ સિસà«àªŸàª® દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
<translation id="1152921474424827756"><ph name="URL" /> ની <ph name="BEGIN_LINK" />કેશ કરેલ કૉપિ<ph name="END_LINK" /> àªàª•à«àª¸à«‡àª¸ કરો</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ઠઅનપેકà«àª·àª¿àª¤ રીતે કનેકà«àª¶àª¨ બંધ કરà«àª¯à«àª‚.</translation>
<translation id="1161325031994447685">Wi-Fi સાથે ફરીથી કનેકà«àªŸ કરીને</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">દૂર કરો</translation>
<translation id="1201402288615127009">આગલà«àª‚</translation>
<translation id="1201895884277373915">આ સાઇટથી વધà«</translation>
-<translation id="121201262018556460">તમે <ph name="DOMAIN" /> સà«àª§à«€ પહોંàªàªµàª¾àª¨à«‹ પà«àª°àª¯àª¾àª¸ કરà«àª¯à«‹, પણ પà«àª°àª®àª¾àª£àªªàª¤à«àª° રજૂ કરતા સરà«àªµàª° પાસે નબળી કી છે. હà«àª®àª²àª¾àª–ોરે ખાનગી કી તોડી હોઈ શકે છે, અને બને કે સરà«àªµàª° તમારà«àª‚ અપેકà«àª·àª¿àª¤ સરà«àªµàª° ન હોય (તમે કોઈ હà«àª®àª²àª¾àª–ોર સાથે વારà«àª¤àª¾àª²àª¾àªª કરી રહà«àª¯àª¾àª‚ હોઈ શકો છો).</translation>
+<translation id="1206967143813997005">ખોટી નાની સહી</translation>
+<translation id="1209206284964581585">હમણાં માટે છà«àªªàª¾àªµà«‹</translation>
<translation id="1219129156119358924">સિસà«àªŸàª® સà«àª°àª•à«àª·àª¾</translation>
<translation id="1227224963052638717">અજà«àªàª¾àª¤ નીતિ.</translation>
<translation id="1227633850867390598">મૂલà«àª¯ છà«àªªàª¾àªµà«‹</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">હા</translation>
<translation id="1430915738399379752">છાપો</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /><ph name="DOMAIN" /> પર પૃષà«àª àª¨à«€ મà«àª²àª¾àª•àª¾àª¤ લેવા<ph name="END_LINK" /> માટેનો પà«àª°àª¯àª¤à«àª¨ અવરોધિત કરà«àª¯à«‹.</translation>
+<translation id="1491663344921578213">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે વેબસાઇટ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પિનિંગનો ઉપયોગ કરે છે. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પૃષà«àª  સંભવિત રૂપે પછીથી કારà«àª¯ કરશે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">આ પૃષà«àª àª¨à«€ સાàªàªµà«‡àª²à«€ (àªàªŸàª²à«‡ કે જૂની થઈ ગયેલી તરીકે ઓળખાતી) કૉપિ દરà«àª¶àª¾àªµà«‹.</translation>
<translation id="1519264250979466059">નિરà«àª®àª¾àª£ તારીખ</translation>
<translation id="1549470594296187301">આ સà«àªµàª¿àª§àª¾àª¨à«‹ ઉપયોગ કરવા માટે JavaScript સકà«àª·àª® કરેલ હોવી આવશà«àª¯àª• છે.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">નેટવરà«àª• ગોઠવણી અમાનà«àª¯ છે અને આયાત કરી શકાઇ નથી.</translation>
<translation id="1644574205037202324">ઇતિહાસ</translation>
<translation id="1645368109819982629">અસમરà«àª¥àª¿àª¤ પà«àª°à«‹àªŸà«‹àª•à«‹àª²</translation>
-<translation id="1655462015569774233">{1,plural, =1{આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમય સીમા ગઈકાલે સમાપà«àª¤ થઈ ગઈ. આ કોઇ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઇ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે. તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઘડિયાળને હાલમાં <ph name="CURRENT_DATE" /> પર સેટ કરવામાં આવી છે. શà«àª‚ તે બરાબર લાગે છે? જો ઠીક ન લાગતી હોય, તો તમારે તમારી સિસà«àªŸàª®àª¨à«€ ઘડિયાળને ઠીક કરવી જોઈઠઅને પછી આ પૃષà«àª  તાજà«àª‚ કરવà«àª‚ જોઈàª.}one{આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમય સીમા # દિવસ પહેલાં સમાપà«àª¤ થઈ ગઈ. આ કોઇ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઇ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે. તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઘડિયાળને હાલમાં <ph name="CURRENT_DATE" /> પર સેટ કરવામાં આવી છે. શà«àª‚ તે બરાબર લાગે છે? જો ઠીક ન લાગતી હોય, તો તમારે તમારી સિસà«àªŸàª®àª¨à«€ ઘડિયાળને ઠીક કરવી જોઈઠઅને પછી આ પૃષà«àª  તાજà«àª‚ કરવà«àª‚ જોઈàª.}other{આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમય સીમા # દિવસ પહેલાં સમાપà«àª¤ થઈ ગઈ. આ કોઇ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઇ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે. તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઘડિયાળને હાલમાં <ph name="CURRENT_DATE" /> પર સેટ કરવામાં આવી છે. શà«àª‚ તે બરાબર લાગે છે? જો ઠીક ન લાગતી હોય, તો તમારે તમારી સિસà«àªŸàª®àª¨à«€ ઘડિયાળને ઠીક કરવી જોઈઠઅને પછી આ પૃષà«àª  તાજà«àª‚ કરવà«àª‚ જોઈàª.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> સામાનà«àª¯ રીતે તમારી માહિતીને સà«àª°àª•à«àª·àª¿àª¤ રાખવા માટે àªàª¨à«àª•à«àª°àª¿àªªà«àª¶àª¨àª¨à«‹ ઉપયોગ કરે છે. જà«àª¯àª¾àª°à«‡ આ સમયે Google Chrome દà«àªµàª¾àª°àª¾ <ph name="SITE" /> થી કનેકà«àªŸ કરવાનો પà«àª°àª¯àª¾àª¸ થયો, તà«àª¯àª¾àª°à«‡ વેબસાઇટે અસામાનà«àª¯ અને ખોટા ઓળખાણપતà«àª°à«‹àª¨à«‡ પાછા મોકલà«àª¯àª¾àª‚. આવà«àª‚ તà«àª¯àª¾àª°à«‡ થઇ શકે જà«àª¯àª¾àª°à«‡ કોઈ હà«àª®àª²àª¾àª–ોર <ph name="SITE" /> હોવાનો ડોળ કરવાનો પà«àª°àª¯àª¾àª¸ કરી રહà«àª¯à«‹ હોય અથવા કોઈ Wi-Fi સાઇન-ઇન સà«àª•à«àª°à«€àª¨à«‡ કનેકà«àª¶àª¨àª®àª¾àª‚ વિકà«àª·à«‡àªª પાડà«àª¯à«‹ હોય. તમારી માહિતી હજી પણ સà«àª°àª•à«àª·àª¿àª¤ છે કારણ કે Google Chrome ઠકોઈપણ ડેટા વિનિમય થાય તે પહેલાં જ કનેકà«àª¶àª¨ રોકી દીધà«àª‚.</translation>
<translation id="168841957122794586">સરà«àªµàª° પà«àª°àª®àª¾àª£àªªàª¤à«àª° àªàª• નબળી કà«àª°àª¿àªªà«àªŸà«‹àª—à«àª°àª¾àª«àª¿àª• કી ધરાવે છે.</translation>
<translation id="1701955595840307032">સૂàªàªµà«‡àª² સામગà«àª°à«€ મેળવો</translation>
-<translation id="1706954506755087368">{1,plural, =1{આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° આવતીકાલથી માનવામાં આવે છે તે પà«àª°àª®àª¾àª£à«‡ છે. આ કોઇ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઇ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.}one{આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° માનવામાં આવે છે તે પà«àª°àª®àª¾àª£à«‡ ભવિષà«àª¯àª®àª¾àª‚ # દિવસથી છે. આ કોઇ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઇ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.}other{આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° માનવામાં આવે છે તે પà«àª°àª®àª¾àª£à«‡ ભવિષà«àª¯àª®àª¾àª‚ # દિવસથી છે. આ કોઇ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઇ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">સિસà«àªŸàª® વà«àª¯àªµàª¸à«àª¥àª¾àªªàª•àª¨à«‹ સંપરà«àª• કરવાનો પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="17513872634828108">ટેબà«àª¸ ખોલો</translation>
<translation id="1753706481035618306">પૃષà«àª  નંબર</translation>
-<translation id="1761412452051366565">Google દà«àªµàª¾àª°àª¾ સૂàªàªµà«‡àª² વà«àª¯àª•à«àª¤àª¿àª—ત કરેલ સામગà«àª°à«€ મેળવવા માટે, સમનà«àªµàª¯àª¨ àªàª¾àª²à« કરો.</translation>
-<translation id="1763864636252898013">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તમારા ઉપકરણની ઑપરેટિંગ સિસà«àªŸàª® દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows નેટવરà«àª• ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ àªàª²àª¾àªµàªµàª¾àª¨à«‹ પà«àª°àª¯àª¾àª¸ કરો<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">કૃપા કરી તમારા સમનà«àªµàª¯àª¨ પાસફà«àª°à«‡àªàª¨à«‡ અપડેટ કરો.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">તમારા તાજેતરમાં મà«àª²àª¾àª•àª¾àª¤ લીધેલ બà«àª•àª®àª¾àª°à«àª•à«àª¸ અહીં દેખાશે.</translation>
<translation id="1821930232296380041">અમાનà«àª¯ વિનંતી અથવા વિનંતી પરિમાણો</translation>
<translation id="1838667051080421715">તમે વેબ પૃષà«àª àª¨à«‹ સà«àª°à«‹àª¤ જોઈ રહà«àª¯àª¾àª‚ છો.</translation>
<translation id="1871208020102129563">પà«àª°à«‹àª•à«àª¸à«€ નિયત કરેલા પà«àª°à«‹àª•à«àª¸à«€ સરà«àªµàª°àª¨à«‹ ઉપયોગ કરવા માટે સેટ કરેલી છે, .pac સà«àª•à«àª°àª¿àªªà«àªŸ URL નથી.</translation>
<translation id="1883255238294161206">સૂàªàª¿ સંકà«àªàª¿àª¤ કરો</translation>
<translation id="1898423065542865115">ફિલà«àªŸàª°àª¿àª‚ગ</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> ઠતમારà«àª‚ લોગિન પà«àª°àª®àª¾àª£àªªàª¤à«àª° સà«àªµà«€àª•àª¾àª°à«àª¯à«àª‚ ન હતà«àª‚ અથવા કદાઠતમારા લોગિન પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમયસીમા સમાપà«àª¤ થઈ ગઈ છે.</translation>
<translation id="194030505837763158"><ph name="LINK" /> પર જાઓ</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
<translation id="1973335181906896915">અનà«àª•à«àª°àª®àª¾àª‚કન ભૂલ</translation>
<translation id="1974060860693918893">વિગતવાર</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{અને 1 વધà«}one{અને # વધà«}other{અને # વધà«}}</translation>
<translation id="2025186561304664664">પà«àª°à«‹àª•à«àª¸à«€ સà«àªµàª¤àªƒ ગોઠવાયેલી પર સેટ છે.</translation>
<translation id="2030481566774242610">શà«àª‚ તમારો અરà«àª¥ <ph name="LINK" /> છે?</translation>
<translation id="2031925387125903299">તમે આ સંદેશ જોઇ રહà«àª¯àª¾àª‚ છો કારણ કે નવી સાઇટà«àª¸àª¨à«€ તમારી પà«àª°àª¥àª® મà«àª²àª¾àª•àª¾àª¤ પર તમારા માતાપિતાઠમંજૂરી આપવી જરૂરી છે.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />પà«àª°à«‹àª•à«àª¸à«€ અને ફાયરવોલ તપાસીને<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">પિન કોડ</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 સૂàªàª¨}one{# સૂàªàª¨}other{# સૂàªàª¨}}</translation>
<translation id="2065985942032347596">પà«àª°àª®àª¾àª£à«€àª•àª°àª£ આવશà«àª¯àª•</translation>
<translation id="2079545284768500474">પૂરà«àªµàªµàª¤à« કરો</translation>
<translation id="20817612488360358">સિસà«àªŸàª® પà«àª°à«‹àª•à«àª¸à«€ સેટિંગà«àª¸ ઉપયોગમાં લેવા માટે સેટ છે પણ àªàª• સà«àªªàª·à«àªŸ પà«àª°à«‹àª•à«àª¸à«€ ગોઠવણી પણ ઉલà«àª²à«‡àª–િત કરેલી છે.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">બà«àª•àª®àª¾àª°à«àª• સંપાદિત કરો</translation>
<translation id="2166049586286450108">સંપૂરà«àª£ વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• àªàª•à«àª¸à«‡àª¸</translation>
<translation id="2166378884831602661">આ સાઇટ àªàª• સà«àª°àª•à«àª·àª¿àª¤ કનેકà«àª¶àª¨ આપી શકતી નથી</translation>
-<translation id="2171101176734966184">તમે <ph name="DOMAIN" /> પર પહોંàªàªµàª¾àª¨à«‹ પà«àª°àª¯àª¾àª¸ કરà«àª¯à«‹, પરંતૠસરà«àªµàª°à«‡ નબળા હસà«àª¤àª¾àª•à«àª·àª° અલà«àª—ોરિધમનો ઉપયોગ કરીને હસà«àª¤àª¾àª•à«àª·àª°àª¿àª¤ કરેલà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚. આનો અરà«àª¥ ઠછે કે સરà«àªµàª°à«‡ પà«àª°àª¸à«àª¤à«àª¤ કરેલા સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹ બનાવટી હોઈ શકે છે અને તે સરà«àªµàª° તમારà«àª‚ અપેકà«àª·àª¿àª¤ સરà«àªµàª° (તમે કોઈ હà«àª®àª²àª¾àª–ોર સાથે વારà«àª¤àª¾àª²àª¾àªª કરી શકો છો) ન પણ હોય.</translation>
<translation id="2181821976797666341">નીતિઓ</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 સરનામà«àª‚}one{# સરનામાં}other{# સરનામાં}}</translation>
<translation id="2212735316055980242">નીતિ મળી નથી</translation>
<translation id="2213606439339815911">પà«àª°àªµàª¿àª·à«àªŸàª¿àª“નà«àª‚ આનયન કરી રહà«àª¯àª¾àª‚ છે...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> ઉપલબà«àª§ નથી.</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨<ph name="END_LINK" />નો ઉપયોગ કરીને તમારà«àª‚ કનેકà«àª¶àª¨ ઠીક કરો</translation>
+<translation id="2239100178324503013">હમણાં મોકલો</translation>
<translation id="225207911366869382">આ નીતિ માટે આ મૂલà«àª¯àª¨à«‡ નાપસંદ કરેલà«àª‚ છે.</translation>
<translation id="2262243747453050782">HTTP ભૂલ</translation>
<translation id="2282872951544483773">અનà«àªªàª²àª¬à«àª§ પà«àª°àª¯à«‹àª—à«‹</translation>
<translation id="2292556288342944218">તમારી ઇનà«àªŸàª°àª¨à«‡àªŸ àªàª•à«àª¸à«‡àª¸ અવરોધિત છે</translation>
<translation id="229702904922032456">રૂટ અથવા મધà«àª¯àªµàª°à«àª¤à«€ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમય-સીમા સમાપà«àª¤ થઈ.</translation>
<translation id="230155334948463882">નવà«àª‚ કારà«àª¡?</translation>
+<translation id="2305919008529760154">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° કપટપૂરà«àª£ રીતે જારી કરવામાં આવà«àª¯à«àª‚ હોઈ શકે છે. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> માટે વપરાશકરà«àª¤àª¾àª¨àª¾àª® અને પાસવરà«àª¡ આવશà«àª¯àª• છે.</translation>
+<translation id="2318774815570432836">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે વેબસાઇટ HSTS નો ઉપયોગ કરે છે. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પૃષà«àª  સંભવિત રૂપે પછીથી કારà«àª¯ કરશે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155"><ph name="ENTRY_INDEX" /> અનà«àª•à«àª°àª®àª£àª¿àª•àª¾ પર અમાનà«àª¯ બà«àª•àª®àª¾àª°à«àª• અવગà«àª£à«àª¯à«‹</translation>
<translation id="2354001756790975382">અનà«àª¯ બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
<translation id="2359808026110333948">àªàª¾àª²à« રાખો</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" /> ઠકૅપà«àªàª° કરેલ કà«àª°à«‡àª¶ રિપોરà«àªŸ અપલોડ કરી ન હતી</translation>
<translation id="2367567093518048410">સà«àª¤àª°</translation>
+<translation id="2371153335857947666">{1,plural, =1{આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમય સીમા ગઈકાલે સમાપà«àª¤ થઈ ગઈ. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઘડિયાળને હાલમાં <ph name="CURRENT_DATE" /> પર સેટ કરવામાં આવી છે. શà«àª‚ તે બરાબર લાગે છે? જો ઠીક ન લાગતી હોય, તો તમારે તમારી સિસà«àªŸàª®àª¨à«€ ઘડિયાળને ઠીક કરી અને પછી આ પૃષà«àª  તાજà«àª‚ કરવà«àª‚ જોઈàª. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.}one{આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમય સીમા # દિવસ પહેલાં સમાપà«àª¤ થઈ ગઈ. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઘડિયાળને હાલમાં <ph name="CURRENT_DATE" /> પર સેટ કરવામાં આવી છે. શà«àª‚ તે બરાબર લાગે છે? જો ઠીક ન લાગતી હોય, તો તમારે તમારી સિસà«àªŸàª®àª¨à«€ ઘડિયાળને ઠીક કરી અને પછી આ પૃષà«àª  તાજà«àª‚ કરવà«àª‚ જોઈàª. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.}other{આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમય સીમા # દિવસ પહેલાં સમાપà«àª¤ થઈ ગઈ. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઘડિયાળને હાલમાં <ph name="CURRENT_DATE" /> પર સેટ કરવામાં આવી છે. શà«àª‚ તે બરાબર લાગે છે? જો ઠીક ન લાગતી હોય, તો તમારે તમારી સિસà«àªŸàª®àª¨à«€ ઘડિયાળને ઠીક કરી અને પછી આ પૃષà«àª  તાજà«àª‚ કરવà«àª‚ જોઈàª. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">કોઈ UI વિકલà«àªªà«‹ ઉપલબà«àª§ નથી</translation>
<translation id="2384307209577226199">àªàª¨à«àªŸàª°àªªà«àª°àª¾àª‡àª ડિફોલà«àªŸ</translation>
-<translation id="238526402387145295">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે વેબસાઇટ <ph name="BEGIN_LINK" />HSTS નો ઉપયોગ કરે છે<ph name="END_LINK" />. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પૃષà«àª  સંભવિત રૂપે પછીથી કારà«àª¯ કરશે.</translation>
<translation id="2386255080630008482">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° રદ કરવામાં આવà«àª¯à«àª‚ છે.</translation>
<translation id="2392959068659972793">કોઈ કિંમત સેટ નહીં સાથે નીતિઓ બતાવો</translation>
<translation id="2396249848217231973">&amp;કાઢી નાખવà«àª‚ પૂરà«àªµàªµàª¤à«â€Œ કરો</translation>
-<translation id="2413528052993050574">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° રદબાતલ થયà«àª‚ હશે. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
<translation id="2455981314101692989">આ વેબપૃષà«àª à«‡ આ ફોરà«àª®àª¨à«àª‚ આપમેળે ભરણ અકà«àª·àª® કરà«àª¯à«àª‚ છે.</translation>
+<translation id="2463739503403862330">ભરો</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />નેટવરà«àª• ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ àªàª²àª¾àªµà«€ રહà«àª¯àª¾àª‚ છે<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">અમાનà«àª¯ શોધ URL.</translation>
<translation id="2491120439723279231">સરà«àªµàª°àª¨àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª®àª¾àª‚ ભૂલો છે.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">સબમિટ કરો</translation>
<translation id="2674170444375937751">શà«àª‚ તમે ખરેખર તમારા ઇતિહાસમાંથી આ પૃષà«àª à«‹àª¨à«‡ કાઢી નાખવા માંગો છો?</translation>
<translation id="2677748264148917807">છોડો</translation>
+<translation id="269990154133806163">સરà«àªµàª°à«‡ àªàªµà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚ કે જે પà«àª°àª®àª¾àª£àªªàª¤à«àª° પારદરà«àª¶àª¿àª¤àª¾ નીતિનો ઉપયોગ કરીને સારà«àªµàªœàª¨àª¿àª• રીતે જાહેર કરà«àª¯à«àª‚ ન હતà«àª‚. આ કેટલાક પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹ માટે ઠખાતરી કરવા હેતૠઆવશà«àª¯àª• છે કે તેઓ વિશà«àªµàª¸àª¨à«€àª¯ છે અને હà«àª®àª²àª¾àª–ોરો સામે રકà«àª·àª£ કરે છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">મૂલà«àª¯ ફોરà«àª®à«‡àªŸàª¥à«€ મેળ ખાતà«àª‚ નથી.</translation>
<translation id="2704951214193499422">આ સમયે Chromium તમારા કારà«àª¡àª¨à«€ પà«àª·à«àªŸàª¿ કરવામાં અસમરà«àª¥ હતà«àª‚. કૃપા કરીને પછીથી ફરી પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="2705137772291741111">આ સાઇટની સાàªàªµà«‡àª² (કૅશ કરેલ) કૉપિ વાંàªàªµàª¾ યોગà«àª¯ ન હતી.</translation>
<translation id="2709516037105925701">સà«àªµàª¤àªƒàª­àª°à«‹</translation>
+<translation id="2712118517637785082">તમે <ph name="DOMAIN" /> પર પહોંàªàªµàª¾àª¨à«‹ પà«àª°àª¯àª¤à«àª¨ કરà«àª¯à«‹, પરંતૠસરà«àªµàª° દà«àªµàª¾àª°àª¾ પà«àª°àª¸à«àª¤à«àª¤ કરવામાં આવેલà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તેના રજૂકરà«àª¤àª¾ દà«àªµàª¾àª°àª¾ જ રદ કરવામાં આવà«àª¯à«àª‚ છે. આનો અરà«àª¥ છે કે સરà«àªµàª°à«‡ પà«àª°àª¸à«àª¤à«àª¤ કરેલા સà«àª°àª•à«àª·àª¾ ઓળખપતà«àª° પર પૂરà«àª£àªªàª£à«‡ વિશà«àªµàª¾àª¸ કરવો જોઈઠનહીં. તમે કોઈ હà«àª®àª²àª¾àª–ોર સાથે વારà«àª¤àª¾àª²àª¾àªª કરી રહà«àª¯àª¾àª‚ હોઈ શકો છો. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">પરવાનગી માગો</translation>
<translation id="2721148159707890343">વિનંતી સફળ થઇ</translation>
<translation id="2728127805433021124">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° àªàª• નબળા હસà«àª¤àª¾àª•à«àª·àª° અલà«àª—ોરિધમનો ઉપયોગ કરીને હસà«àª¤àª¾àª•à«àª·àª°àª¿àª¤ કરેલà«àª‚ છે.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">સરનામà«àª‚ અને શોધ બાર</translation>
<translation id="2826760142808435982">કનેકà«àª¶àª¨ <ph name="CIPHER" /> નો ઉપયોગ કરીને àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ અને પà«àª°àª®àª¾àª£àª¿àª¤ કરેલૠછે અને મà«àª–à«àª¯ àªàª•à«àª¸àªà«‡àª¨à«àªœ મેકેનિàªà«àª® તરીકે <ph name="KX" /> નો ઉપયોગ કરે છે.</translation>
<translation id="2835170189407361413">ફોરà«àª® સાફ કરો</translation>
-<translation id="2837049386027881519">TLS અથવા SSL પà«àª°à«‹àªŸà«‹àª•à«‹àª²àª¨àª¾àª‚ જૂના સંસà«àª•àª°àª£àª¨à«‹ ઉપયોગ કરીને કનેકà«àª¶àª¨ માટે ફરીથી પà«àª°àª¯àª¾àª¸ કરવાની જરૂર હતી. સામાનà«àª¯ રીતે આનો અરà«àª¥ ઠથાય છે કે સરà«àªµàª° ખૂબ જૂના સૉફà«àªŸàªµà«‡àª°àª¨à«‹ ઉપયોગ કરે છે અને તેમાં અનà«àª¯ સà«àª°àª•à«àª·àª¾ સમસà«àª¯àª¾àª“ હોઈ શકે છે.</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> પરનà«àª‚ સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° બનાવટી હોય àªàªµà«àª‚ લાગે છે.</translation>
<translation id="2889159643044928134">ફરીથી લોડ કરશો નહીં</translation>
-<translation id="2896499918916051536">આ પà«àª²àª—િન સમરà«àª¥àª¿àª¤ નથી.</translation>
+<translation id="2900469785430194048">આ વેબ પૃષà«àª  પà«àª°àª¦àª°à«àª¶àª¿àª¤ કરવાનો પà«àª°àª¯àª¾àª¸ કરતી વખતે Google Chrome ની મેમરી સમાપà«àª¤ થઈ ગઈ.</translation>
<translation id="2909946352844186028">નેટવરà«àª• ફેરફાર મળà«àª¯à«‹ હતો.</translation>
-<translation id="2915500479781995473">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમયસીમા સમાપà«àª¤ થઈ છે. આ કોઈ ગેરગોઠવણના કારણે થયà«àª‚ છે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે. તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઘડિયાળ હાલમાં <ph name="CURRENT_TIME" /> પર સેટ છે. શà«àª‚ તે બરાબર છે? જો નહીં, તો તમારે તમારા સિસà«àªŸàª®àª¨à«€ ઘડિયાળને ઠીક કરવી જોઈઠઅને તે પછી આ પૃષà«àª àª¨à«‡ ફરી તાજà«àª‚ કરો.</translation>
<translation id="2922350208395188000">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તપાસી શકાતà«àª‚ નથી.</translation>
-<translation id="2941952326391522266">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° <ph name="DOMAIN2" /> નà«àª‚ છે. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
<translation id="2948083400971632585">તમે સેટિંગà«àª¸ પૃષà«àª àª®àª¾àª‚થી કનેકà«àª¶àª¨ માટે ગોઠવવામાં આવેલ કોઇપણ પà«àª°à«‹àª•à«àª¸à«€àª“ અકà«àª·àª® કરી શકો છો.</translation>
<translation id="2955913368246107853">શોધ બાર બંધ કરો</translation>
<translation id="2958431318199492670">નેટવરà«àª• ગોઠવણી ONC માનકનà«àª‚ પાલન કરતી નથી. ગોઠવણીના ભાગો આયાત કરી શકાશે નહીં.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">ખોટો નીતિ પà«àª°àª•àª¾àª°</translation>
<translation id="3032412215588512954">શà«àª‚ તમે આ સાઇટ ફરીથી લોડ કરવા માંગો છો?</translation>
<translation id="3037605927509011580">અરર કંઇક ભà«àª² થઇ!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{સમનà«àªµàª¯àª¿àª¤ ઉપકરણો પર ઓછામાં ઓછી 1 આઇટમ}=1{1 આઇટમ (અને સમનà«àªµàª¯àª¿àª¤ ઉપકરણો પર વધà«)}one{# આઇટમ (અને સમનà«àªµàª¯àª¿àª¤ ઉપકરણો પર વધà«)}other{# આઇટમ (અને સમનà«àªµàª¯àª¿àª¤ ઉપકરણો પર વધà«)}}</translation>
<translation id="3041612393474885105">પà«àª°àª®àª¾àª£àªªàª¤à«àª° માહિતી</translation>
<translation id="3063697135517575841">આ સમયે Chrome તમારા કારà«àª¡àª¨à«€ પà«àª·à«àªŸàª¿ કરવામાં અસમરà«àª¥ હતà«àª‚. કૃપા કરીને પછીથી ફરી પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="3093245981617870298">તમે ઑફલાઇન છો</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">સૌથી નવà«àª‚</translation>
<translation id="3207960819495026254">બà«àª•àª®àª¾àª°à«àª• કરેલ</translation>
-<translation id="3225919329040284222">સરà«àªµàª° àªàª• પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરે છે જે બિલà«àªŸ-ઇન અપેકà«àª·àª¾àª“ સાથે મેળ ખાતà«àª‚ નથી. આ અપેકà«àª·àª¾àª“માં તમને સà«àª°àª•à«àª·àª¿àª¤ રાખવા માટે અમà«àª• àªà«‹àª•à«àª•àª¸, ઉàªà«àª-સà«àª°àª•à«àª·àª¾ વેબસાઇટà«àª¸àª¨à«‹ સમાવેશ થાય છે.</translation>
<translation id="3226128629678568754">પૃષà«àª àª¨à«‡ લોડ કરવા માટે જરૂરી ડેટા ફરીથી સબમિટ કરવા માટે ફરીથી લોડ કરો બટન દબાવો.</translation>
<translation id="3228969707346345236">ભાષાંતર નિષà«àª«àª³ રહà«àª¯à«àª‚ કારણ કે પૃષà«àª  પહેલાથી જ <ph name="LANGUAGE" /> માં છે.</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" /> માટે CVC દાખલ કરો</translation>
<translation id="3254409185687681395">આ પૃષà«àª àª¨à«‡ બà«àª•àª®àª¾àª°à«àª• કરો</translation>
<translation id="3270847123878663523">&amp;પà«àª¨àªƒàª•à«àª°àª®àª¾àª‚કિત કરવà«àª‚ પૂરà«àªµàªµàª¤à« કરો</translation>
<translation id="3286538390144397061">હવે ફરીથી પà«àª°àª¾àª°àª‚ભ કરો</translation>
+<translation id="3303855915957856445">કોઈ શોધ પરિણામો મળà«àª¯àª¾àª‚ નથી</translation>
<translation id="3305707030755673451">તમારો ડેટા <ph name="TIME" /> ના રોજ તમારા સમનà«àªµàª¯àª¨ પાસફà«àª°à«‡àª સાથે àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ કરવામાં આવà«àª¯à«‹ હતો. સમનà«àªµàª¯àª¨ શરૂ કરવા માટે તે દાખલ કરો.</translation>
<translation id="333371639341676808">આ પૃષà«àª àª¨à«‡ વધારાનાં સંવાદો બનાવવાથી રોકો.</translation>
+<translation id="3338095232262050444">સà«àª°àª•à«àª·àª¿àª¤</translation>
<translation id="3340978935015468852">સેટિંગà«àª¸</translation>
<translation id="3345135638360864351">આ સાઇટને àªàª•à«àª¸à«‡àª¸ કરવાની તમારી વિનંતી <ph name="NAME" /> ને મોકલી શકાઈ નથી. કૃપા કરીને ફરી પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="3355823806454867987">પà«àª°à«‹àª•à«àª¸à«€ સેટિંગà«àª¸ બદલો...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">આનયન અંતરાલ:</translation>
<translation id="3462200631372590220">વિગતવાર છà«àªªàª¾àªµà«‹</translation>
<translation id="3479539252931486093">શà«àª‚ આ અનપેકà«àª·àª¿àª¤ હતà«àª‚? <ph name="BEGIN_LINK" />અમને જણાવો<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">હમણાં નહીં</translation>
<translation id="348000606199325318">કà«àª°à«‡àª¶ ID <ph name="CRASH_LOCAL_ID" /> (સરà«àªµàª° ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">અમે આ પળે તમારા વાલી સà«àª§à«€ પહોંàªà«€ શકà«àª¯àª¾àª‚ નથી. કૃપા કરીને ફરી પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="3527085408025491307">ફોલà«àª¡àª°</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">આ માટે પાસવરà«àª¡àª¨à«‹ ઉપયોગ કરો:</translation>
<translation id="3549644494707163724">તમારા પોતાના સમનà«àªµàª¯àª¨ પાસફà«àª°à«‡àª સાથે તમામ સમનà«àªµàª¯àª¿àª¤ ડેટા àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ કરો</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> વધà«...</translation>
+<translation id="3555561725129903880">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° <ph name="DOMAIN2" /> નà«àª‚ છે. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">તમારà«àª‚ કનેકà«àª¶àª¨ ખાનગી નથી</translation>
<translation id="3583757800736429874">&amp;ખસેડવà«àª‚ ફરી કરો</translation>
<translation id="3586931643579894722">વિગતો છà«àªªàª¾àªµà«‹</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">કિંમત બતાવો</translation>
<translation id="3630155396527302611">જો તે પહેલાંથી જ નેટવરà«àª• àªàª•à«àª¸à«‡àª¸ કરવા માટે મંજૂર પà«àª°à«‹àª—à«àª°àª¾àª® તરીકે સૂàªàª¿àª¬àª¦à«àª§ હોય, તો
તેને સૂàªàª¿àª®àª¾àª‚થી દૂર કરી અને તેને ફરીથી ઉમેરવાનો પà«àª°àª¯àª¾àª¸ કરો.</translation>
+<translation id="3638794133396384728">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમયસીમા સમાપà«àª¤ થઈ છે. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઘડિયાળ હાલમાં <ph name="CURRENT_TIME" /> પર સેટ છે. શà«àª‚ તે બરાબર છે? જો નહીં, તો તમારે તમારા સિસà«àªŸàª®àª¨à«€ ઘડિયાળ ઠીક કરી અને તે પછી આ પૃષà«àª àª¨à«‡ ફરી તાજà«àª‚ કરવà«àª‚ જોઈàª. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">આ પà«àª°àª¾àª¯à«‹àª—િક સà«àªµàª¿àª§àª¾àª“ કોઈપણ સમયે બદલાઈ, ભંગ અથવા અદૃશà«àª¯ થઈ શકે છે. જો તમે આમાંના કોઈ àªàª• પà«àª°àª¯à«‹àª—ને àªàª¾àª²à« કરો છો તો તેનà«àª‚ શà«àª‚ થશે તેની અમે કોઈ ગેરેંટી આપી શકતા નથી, બને કે તમારà«àª‚ બà«àª°àª¾àª‰àªàª° પણ ભડકી ઉઠે. તમારà«àª‚ બà«àª°àª¾àª‰àªàª° તમારા ડેટાને કાઢી નાખી શકે છે, અથવા તમારી સà«àª°àª•à«àª·àª¾ અને ગોપનીયતા સાથે અનપેકà«àª·àª¿àª¤ રીતે àªà«‡àª¡àª¾ થઈ શકે છે. તમે જે પà«àª°àª¯à«‹àª—ોને અકà«àª·àª® કરો છો તે આ બà«àª°àª¾àª‰àªàª°àª¨àª¾ બધા વપરાશકરà«àª¤àª¾àª“ માટે સકà«àª·àª® થશે. કૃપા કરીને સાવધાનીપૂરà«àªµàª• આગળ વધો.</translation>
<translation id="3650584904733503804">માનà«àª¯àª¤àª¾ સફળ</translation>
<translation id="3655670868607891010">જો તમે આ વારંવાર જોઈ રહà«àª¯àª¾àª‚ છો, તો આ <ph name="HELP_LINK" /> અજમાવી જà«àª“.</translation>
<translation id="3658742229777143148">પà«àª¨àª°àª¾àªµàª°à«àª¤àª¨</translation>
+<translation id="3678029195006412963">વિનંતી પર સહી કરી શકà«àª¯àª¾àª‚ નથી</translation>
<translation id="3681007416295224113">પà«àª°àª®àª¾àª£àªªàª¤à«àª° માહિતી</translation>
<translation id="3693415264595406141">પાસવરà«àª¡:</translation>
+<translation id="3696411085566228381">કોઈ નહીં</translation>
<translation id="3700528541715530410">અરેરે, àªàªµà«àª‚ લાગે છે કે તમને આ પૃષà«àª  àªàª•à«àª¸à«‡àª¸ કરવાની પરવાનગી નથી.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">લોડ કરી રહà«àª¯à«àª‚ છે...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">મોબાઇલ ડેટા અથવા Wi-Fi àªàª¾àª²à« કરીને</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />પà«àª°à«‹àª•à«àª¸à«€, ફાયરવોલ અને DNS ગોઠવણી તપાસીને<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">તમે કૉપિ કરેલ લિંક</translation>
-<translation id="3744899669254331632">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતા નથી કારણ કે વેબસાઇટે સà«àª•à«àª°à«…મà«àª¬àª² કરેલ ઓળખાણપતà«àª°à«‹ મોકલà«àª¯àª¾àª‚ છે જેના પર Chromium પà«àª°àª•à«àª°àª¿àª¯àª¾ કરી શકતà«àª‚ નથી. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾àª“ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ હોય છે, તેથી આ પૃષà«àª  સંભવતઃ પછીથી કારà«àª¯ કરશે.</translation>
<translation id="375403751935624634">સરà«àªµàª° ભૂલને કારણે ભાષાંતર નિષà«àª«àª³ રહà«àª¯à«àª‚.</translation>
<translation id="3759461132968374835">તમે હાલમાં કà«àª°à«‡àª¶àª¨à«€ જાણ કરી નથી. કà«àª°à«‡àª¶àª¨à«€ જાણ કરવાનà«àª‚ અકà«àª·àª® હતà«àª‚ તà«àª¯àª¾àª°à«‡ થયેલા કà«àª°à«‡àª¶ અહીં દેખાશે નહીં.</translation>
<translation id="3788090790273268753">આ સાઇટ માટેનà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° 2016 માં સમાપà«àª¤ થાય છે અને પà«àª°àª®àª¾àª£àªªàª¤à«àª° શà«àª°à«ƒàª‚ખલા SHA-1 નો ઉપયોગ કરીને સહી કરેલ પà«àª°àª®àª¾àª£àªªàª¤à«àª° ધરાવે છે.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">વિરોધાભાસી ઉપકરણ ઓળખકરà«àª¤àª¾</translation>
<translation id="3885155851504623709">પૅરિશ</translation>
<translation id="3901925938762663762">કારà«àª¡àª¨à«€ સમયસીમા સમાપà«àª¤ થઇ ગઈ છે</translation>
+<translation id="3910267023907260648">તમે <ph name="DOMAIN" /> પર પહોંàªàªµàª¾àª¨à«‹ પà«àª°àª¯àª¤à«àª¨ કરà«àª¯à«‹, પરંતૠસરà«àªµàª°à«‡ નબળા હસà«àª¤àª¾àª•à«àª·àª° અલà«àª—ોરિધમનો ઉપયોગ કરીને સહી કરેલà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚. આનો અરà«àª¥ ઠછે કે સરà«àªµàª°à«‡ પà«àª°àª¸à«àª¤à«àª¤ કરેલા સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹ બનાવટી હોઈ શકે છે અને તે સરà«àªµàª° તમારà«àª‚ અપેકà«àª·àª¿àª¤ સરà«àªµàª° ન પણ હોય (તમે કોઈ હà«àª®àª²àª¾àª–ોર સાથે વારà«àª¤àª¾àª²àª¾àªª કરી રહà«àª¯àª¾àª‚ હોઈ શકો છો). <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° સંભવિત રૂપે આવતીકાલથી લાગૠથાય. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.}one{આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° ભવિષà«àª¯àª®àª¾àª‚ # દિવસમાં લાગૠથાય. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.}other{આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° ભવિષà«àª¯àª®àª¾àª‚ # દિવસમાં લાગૠથાય. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF દસà«àª¤àª¾àªµà«‡àªœ લોડ કરવામાં નિષà«àª«àª³ રહà«àª¯àª¾</translation>
<translation id="3963721102035795474">રીડર મોડ</translation>
+<translation id="397105322502079400">ગણના કરી રહà«àª¯à«àª‚ છે...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> અવરોધિત છે</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{નજીકમાં 1 વેબ પૃષà«àª }one{નજીકમાં # વેબ પૃષà«àª }other{નજીકમાં # વેબ પૃષà«àª }}</translation>
<translation id="4021036232240155012">DNS ઠનેટવરà«àª• સેવા છે કે જે વેબસાઇટના નામનો અનà«àªµàª¾àª¦ તેના ઇનà«àªŸàª°àª¨à«‡àªŸ સરનામાં પર કરે છે.</translation>
<translation id="4030383055268325496">&amp;ઉમેરવà«àª‚ પૂરà«àªµàªµàª¤à« કરો</translation>
-<translation id="4032534284272647190"><ph name="URL" /> ની àªàª•à«àª¸à«‡àª¸ નકારાઈ. </translation>
<translation id="404928562651467259">àªà«‡àª¤àªµàª£à«€</translation>
<translation id="4058922952496707368">કી "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">કà«àª²àª¾àª‡àª¨à«àªŸ અને સરà«àªµàª° સામાનà«àª¯ SSL પà«àª°à«‹àªŸà«‹àª•à«‹àª² સંસà«àª•àª°àª£ અથવા સાઇફર સà«àª¯à«‚ટનà«àª‚ સમરà«àª¥àª¨ કરતાં નથી.</translation>
<translation id="4079302484614802869">પà«àª°à«‹àª•à«àª¸à«€ ગોઠવણી .pac સà«àª•à«àª°àª¿àªªà«àªŸ URL નો ઉપયોગ કરવા માટે સેટ છે, નિયત પà«àª°à«‹àª•à«àª¸à«€ સરà«àªµàª°à«àª¸ માટે નહીં.</translation>
<translation id="4103249731201008433">ઉપકરણ અનà«àª•à«àª°à«àª®àª¾àª‚ક નંબર અમાનà«àª¯ છે</translation>
<translation id="4103763322291513355">બà«àª²à«‡àª•àª²àª¿àª¸à«àªŸ કરેલા URL ની સૂàªàª¿ અને તમારા સિસà«àªŸàª® વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• દà«àªµàª¾àª°àª¾ લાગૠઅનà«àª¯ નીતિઓ જોવા માટે &lt;strong&gt;chrome://policy&lt;/strong&gt; ની મà«àª²àª¾àª•àª¾àª¤ લો.</translation>
+<translation id="4110615724604346410">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª®àª¾àª‚ ભૂલો છે. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">નીતિ મરà«àª¯àª¾àª¦àª¾ સમરà«àª¥àª¿àª¤ નથી.</translation>
+<translation id="4118212371799607889">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°, Chromium દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 અનà«àª¯}one{# અનà«àª¯}other{# અનà«àª¯}}</translation>
<translation id="4130226655945681476">નેટવરà«àª• કેબલà«àª¸, મૉડેમ અને રાઉટર તપાસીને</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">શà«àª‚ તમે ઇàªà«àª›à«‹ છો કે Chromium આ કારà«àª¡ સાàªàªµà«‡?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">અકà«àª·àª® કરેલà«àª‚</translation>
<translation id="4196861286325780578">&amp;ખસેડવà«àª‚ ફરી કરો</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ફાયરવોલ અને àªàª¨à«àªŸà«€àªµàª¾àª‡àª°àª¸ ગોઠવણી તપાસીને<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{કોઈ નહીં}=1{1 àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ($1)}=2{2 àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ($1, $2)}one{# àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ($1, $2, $3)}other{# àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">કà«àª°à«‡àª¶à«‡àª¸</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />નેટવરà«àª• ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ àªàª²àª¾àªµàªµàª¾àª¨à«‹ પà«àª°àª¯àª¾àª¸ કરો<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">નહીં</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(કોઇ વપરાશકરà«àª¤àª¾àª¨àª¾àª® નથી)</translation>
<translation id="4300246636397505754">પેરેનà«àªŸ સૂàªàª¨à«‹</translation>
<translation id="4304224509867189079">લૉગ ઇન કરો</translation>
+<translation id="432290197980158659">સરà«àªµàª°à«‡ àªàªµà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚ કે જે બિલà«àªŸ-ઇન અપવાદો સાથે મેળ ખાતà«àª‚ નથી. તમને સà«àª°àª•à«àª·àª¿àª¤ રાખવા માટે, આ અપેકà«àª·àª¾àª“ અમà«àª• àªà«‹àª•à«àª•àª¸, ઉàªà«àª-સà«àª°àª•à«àª·àª¾ વેબસાઇટà«àª¸ માટે શામેલ કરવામાં આવી છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">લેખ શોધવામાં નિષà«àª«àª³ થયાં</translation>
+<translation id="4331708818696583467">સà«àª°àª•à«àª·àª¿àª¤ નથી</translation>
<translation id="4372948949327679948">અપેકà«àª·àª¿àª¤ <ph name="VALUE_TYPE" /> મૂલà«àª¯.</translation>
-<translation id="4377125064752653719">તમે <ph name="DOMAIN" /> પર પહોંàªàªµàª¾àª¨à«‹ પà«àª°àª¯àª¾àª¸ કરà«àª¯à«‹, પણ સરà«àªµàª° દà«àªµàª¾àª°àª¾ પà«àª°àª¸à«àª¤à«àª¤ કરવામાં આવેલà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તેના રજૂકરà«àª¤àª¾ દà«àªµàª¾àª°àª¾ જ રદ કરવામાં આવà«àª¯à«àª‚ છે. આનો અરà«àª¥ છે કે સરà«àªµàª°à«‡ પà«àª°àª¸à«àª¤à«àª¤ કરેલા સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹ પૂરà«àª£àªªàª£à«‡ વિશà«àªµàª¸àª¨à«€àª¯ નથી. તમે કોઈ હà«àª®àª²àª¾àª–ોર જોડે વાત કરતા હોઈ શકો છો.</translation>
<translation id="4381091992796011497">વપરાશકરà«àª¤àª¾àª¨à«àª‚ નામ:</translation>
<translation id="4394049700291259645">અકà«àª·àª® કરો</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> થી <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">શોધ પરિણામો</translation>
-<translation id="4424024547088906515">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° Chrome દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> ઠતમારà«àª‚ લોગિન પà«àª°àª®àª¾àª£àªªàª¤à«àª° સà«àªµà«€àª•àª¾àª°à«àª¯à«àª‚ ન હતà«àª‚ અથવા કદાઠકોઈ àªàª• પà«àª°àª¦àª¾àª¨ કરવામાં આવà«àª¯à«àª‚ નથી.</translation>
<translation id="443673843213245140">પà«àª°à«‹àª•à«àª¸à«€àª¨à«‹ ઉપયોગ અકà«àª·àª® કરેલો છે પણ àªàª• સà«àªªàª·à«àªŸ પà«àª°à«‹àª•à«àª¸à«€ ગોઠવણી ઉલà«àª²à«‡àª–િત છે.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">તમે આ સંદેશ જોઇ રહà«àª¯àª¾àª‚ છો કારણ કે Google SafeSites સકà«àª·àª® કરેલ છે.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">વિગતો</translation>
<translation id="4558551763791394412">તમારા àªàª•à«àª¸à«àªŸà«‡àª¨à«àª¶àª¨à«àª¸àª¨à«‡ અકà«àª·àª® કરવાનો પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="4587425331216688090">Chrome માંથી સરનામà«àª‚ દૂર કરીàª?</translation>
+<translation id="4589078953350245614">તમે <ph name="DOMAIN" /> પર પહોંàªàªµàª¾àª¨à«‹ પà«àª°àª¯àª¤à«àª¨ કરà«àª¯à«‹, પરંતૠસરà«àªµàª°à«‡ અમાનà«àª¯ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">આધà«àª¨àª¿àª• સાઇફર સà«àª¯à«‚ટનો ઉપયોગ કરીને <ph name="DOMAIN" /> સાથેનà«àª‚ તમારà«àª‚ કનેકà«àª¶àª¨ àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ કરાયà«àª‚ છે.</translation>
<translation id="4594403342090139922">&amp;કાઢી નાખવà«àª‚ પૂરà«àªµàªµàª¤à«â€Œ કરો</translation>
+<translation id="4627442949885028695">બીજા ઉપકરણમાંથી àªàª¾àª²à« કરો</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">તમે àªàª•à«àª¸à«àªŸà«‡àª¨à«àª¶àª¨ પૃષà«àª  જોઈ રહà«àª¯àª¾àª‚ છો.</translation>
-<translation id="467662567472608290">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª®àª¾àª‚ ભૂલો છે. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> ને અવરોધિત કરવામાં આવà«àª¯à«àª‚ હતà«àª‚</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">તમારà«àª‚ કનેકà«àª¶àª¨ અવરોધાયà«àª‚ હતà«àª‚</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows નેટવરà«àª• ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ àªàª²àª¾àªµà«€ રહà«àª¯àª¾àª‚ છે<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">પà«àª²à«‡àªŸàª«à«‹àª°à«àª®</translation>
<translation id="4744603770635761495">અમલ કરવાયોગà«àª¯ પાથ</translation>
<translation id="4756388243121344051">&amp;ઇતિહાસ</translation>
+<translation id="4759238208242260848">ડાઉનલોડà«àª¸</translation>
<translation id="4764776831041365478"><ph name="URL" /> પરનાં વેબપેજ અસà«àª¥àª¾àª¯à«€ ધોરણે બંધ હોઈ શકે છે અથવા તે કાયમ માટે નવા વેબ સરનામાં પર ખસેડવામાં આવà«àª¯àª¾ હોઈ શકે છે.</translation>
<translation id="4771973620359291008">કોઈ અજà«àªàª¾àª¤ ભૂલ આવી.</translation>
<translation id="4782449893814226250">તમે આ પૃષà«àª àª¨à«€ મà«àª²àª¾àª•àª¾àª¤ લો તે ઠીક છે કે કેમ તેવà«àª‚ તમે તમારા માતાપિતાને પૂછà«àª¯à«àª‚.</translation>
<translation id="4800132727771399293">તમારી સમાપà«àª¤àª¿ તારીખ અને CVC તપાસો અને ફરીથી પà«àª°àª¯àª¾àª¸ કરો</translation>
-<translation id="4807049035289105102">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે વેબસાઇટે સમજાય નહીં તેવા ઓળખપતà«àª° મોકલà«àª¯àª¾àª‚ છે જેની પર Google Chrome પà«àª°àª•à«àª°àª¿àª¯àª¾ કરી શકતà«àª‚ નથી. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પૃષà«àª  સંભવિત રૂપે પછીથી કારà«àª¯ કરશે.</translation>
<translation id="4813512666221746211">નેટવરà«àª• ભૂલ</translation>
<translation id="4816492930507672669">પૃષà«àª  પર ફિટ</translation>
<translation id="4850886885716139402">જà«àª“</translation>
<translation id="4880827082731008257">ઇતિહાસ શોધ</translation>
+<translation id="4884656795097055129">યોગà«àª¯ સમયે વધૠલેખ દેખાશે.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{અને 1 વધૠવેબ પૃષà«àª }one{અને # વધૠવેબ પૃષà«àª }other{અને # વધૠવેબ પૃષà«àª }}</translation>
<translation id="4923417429809017348">આ પૃષà«àª  કોઈ અજà«àªàª¾àª¤ ભાષામાંથી <ph name="LANGUAGE_LANGUAGE" /> માં અનà«àªµàª¾àª¦àª¿àª¤ કરવામાં આવà«àª¯à«àª‚ છે</translation>
<translation id="4926049483395192435">ઉલà«àª²à«‡àª–િત હોવà«àª‚ આવશà«àª¯àª• છે.</translation>
<translation id="4930497775425430760">તમે આ સંદેશ જોઇ રહà«àª¯àª¾àª‚ છો કારણ કે નવી સાઇટà«àª¸àª¨à«€ તમારી પà«àª°àª¥àª® મà«àª²àª¾àª•àª¾àª¤ પર તમારા માતાપિતાઠમંજૂરી આપવી જરૂરી છે.</translation>
<translation id="495170559598752135">કà«àª°àª¿àª¯àª¾àª“</translation>
<translation id="4958444002117714549">સૂàªàª¿ વિસà«àª¤à«ƒàª¤ કરો</translation>
+<translation id="4962322354953122629">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°, Chrome દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">શà«àª‚ <ph name="ORIGINAL_LANGUAGE" /> માંથી <ph name="TARGET_LANGUAGE" /> માં અનà«àªµàª¾àª¦ કરીàª?</translation>
+<translation id="4989809363548539747">આ પà«àª²àª—-ઇન સમરà«àª¥àª¿àª¤ નથી</translation>
<translation id="5002932099480077015">જો સકà«àª·àª® કરેલà«àª‚ હોય, તો àªàª¡àªªàª¥à«€ ફોરà«àª® ભરવા માટે Chrome આ ઉપકરણ પર તમારા કારà«àª¡àª¨à«€ àªàª• કૉપિ સંગà«àª°àª¹àª¶à«‡.</translation>
<translation id="5019198164206649151">બેકઅપ સà«àªŸà«‹àª° કરવà«àª‚ ખરાબ સà«àª¥àª¿àª¤àª¿àª®àª¾àª‚ છે</translation>
<translation id="5023310440958281426">તમારા વà«àª¯àªµàª¸à«àª¥àª¾àªªàª•àª¨à«€ નીતિઓ તપાસો</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Google અનà«àªµàª¾àª¦ વિશે</translation>
<translation id="5040262127954254034">ગોપનીયતા</translation>
<translation id="5045550434625856497">ખોટો પાસવરà«àª¡</translation>
+<translation id="5056549851600133418">તમારા માટે લેખ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />પà«àª°à«‹àª•à«àª¸à«€ સરનામà«àª‚ તપાસીને<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° આ સમયે માનà«àª¯ નથી.</translation>
<translation id="5089810972385038852">રાજà«àª¯</translation>
-<translation id="5094747076828555589">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° Chromium દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
<translation id="5095208057601539847">પà«àª°àª¾àª‚ત</translation>
<translation id="5115563688576182185">(64-બિટ)</translation>
-<translation id="5122371513570456792">'<ph name="SEARCH_STRING" />' માટે <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> મળà«àª¯àª¾àª‚.</translation>
<translation id="5141240743006678641">તમારા Google ઓળખપતà«àª°à«‹ સાથે સમનà«àªµàª¯àª¿àª¤ પાસવરà«àª¡à«àª¸àª¨à«‡ àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ કરો</translation>
<translation id="5145883236150621069">નીતિ પà«àª°àª¤àª¿àª•à«àª°àª¿àª¯àª¾àª®àª¾àª‚ ભૂલ કોડ હાજર</translation>
<translation id="5171045022955879922">URL શોધો અથવા લખો</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">બà«àª•àª®àª¾àª°à«àª•à«àª¸ બાર</translation>
<translation id="5199729219167945352">પà«àª°àª¯à«‹àª—à«‹</translation>
<translation id="5251803541071282808">મેઘ</translation>
+<translation id="5277279256032773186">કારà«àª¯ પર Chrome નો ઉપયોગ કરી રહà«àª¯àª¾àª‚ છો? વà«àª¯àªµàª¸àª¾àª¯à«‹ તેમના કરà«àª®àªàª¾àª°à«€àª“ માટે Chrome સેટિંગà«àª¸àª¨à«‡ સંàªàª¾àª²àª¿àª¤ કરી શકે છે. વધૠજાણો</translation>
<translation id="5299298092464848405">ભૂલ વિશà«àª²à«‡àª·àª£ નીતિ</translation>
<translation id="5300589172476337783">બતાવો</translation>
<translation id="5308689395849655368">કà«àª°à«‡àª¶àª¨à«€ જાણ કરવાનà«àª‚ અકà«àª·àª® કરà«àª¯à«àª‚ છે.</translation>
<translation id="5317780077021120954">સાàªàªµà«‹</translation>
<translation id="5327248766486351172">નામ</translation>
+<translation id="5359637492792381994">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° આ સમયે માનà«àª¯ નથી. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">નીતિ સેટિંગà«àª¸ સà«àªŸà«‹àª° કરવામાં નિષà«àª«àª³ થયાં</translation>
-<translation id="540969355065856584">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° આ સમયે માનà«àª¯ નથી. આ કોઇ ખોટી ગોઠવણીને કારણે થયà«àª‚ હોય અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોઇ શકે છે.</translation>
<translation id="5421136146218899937">બà«àª°àª¾àª‰àªàª¿àª‚ગ ડેટા સાફ કરો...</translation>
<translation id="5430298929874300616">બà«àª•àª®àª¾àª°à«àª• દૂર કરો</translation>
<translation id="5431657950005405462">તમારી ફાઇલ મળી ન હતી</translation>
<translation id="5435775191620395718">આ ઉપકરણમાંથી ઇતિહાસ બતાવી રહà«àª¯àª¾àª‚ છે. <ph name="BEGIN_LINK" />વધૠજાણો<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">વà«àª¯àª•à«àª¤àª¿àª—ત કરેલ સામગà«àª°à«€ સૂàªàª¨à«‹ વરà«àª¤àª®àª¾àª¨àª®àª¾àª‚ અકà«àª·àª® કરેલ છે, કારણ કે તમારો સમનà«àªµàª¯àª¿àª¤ ડેટા કસà«àªŸàª® પાસફà«àª°à«‡àª વડે સà«àª°àª•à«àª·àª¿àª¤ કરેલ છે.</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" પર સà«àª•à«€àª®àª¾ માનà«àª¯àª¤àª¾ ભૂલ: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">આ <ph name="HOST_NAME" /> પૃષà«àª  શોધી શકાતà«àª‚ નથી</translation>
<translation id="5455374756549232013">ખરાબ નીતિ સમયનોંધ</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">શà«àª‚ તમે આ સાઇટ છોડવા માંગો છો?</translation>
<translation id="5629630648637658800">નીતિ સેટિંગà«àª¸ લોડ કરવામાં નિષà«àª«àª³ થયાં</translation>
<translation id="5631439013527180824">અમાનà«àª¯ ઉપકરણ સંàªàª¾àª²àª¨ ટોકન</translation>
-<translation id="5650551054760837876">કોઈ શોધ પરિણામ મળà«àª¯àª¾ નથી.</translation>
<translation id="5677928146339483299">અવરોધિત</translation>
<translation id="5710435578057952990">આ વેબસાઇટની ઓળખ àªàª•àª¾àª¸àªµàª¾àª®àª¾àª‚ આવી નથી.</translation>
<translation id="5720705177508910913">વરà«àª¤àª®àª¾àª¨ વપરાશકરà«àª¤àª¾</translation>
+<translation id="572328651809341494">તાજેતરના ટેબà«àª¸</translation>
<translation id="5784606427469807560">તમારા કારà«àª¡àª¨à«€ પà«àª·à«àªŸàª¿ કરવામાં àªàª• સમસà«àª¯àª¾ આવી હતી. તમારà«àª‚ ઇનà«àªŸàª°àª¨à«‡àªŸ કનેકà«àª¶àª¨ તપાસો અને ફરીથી પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="5785756445106461925">વળી, આ પૃષà«àª àª®àª¾àª‚ અનà«àª¯ àªàªµàª¾ સાધનો છે જે સà«àª°àª•à«àª·àª¿àª¤ નથી. ટà«àª°àª¾àª‚àªàª¿àªŸàª®àª¾àª‚ હોવા પર અનà«àª¯ લોકો દà«àªµàª¾àª°àª¾ આ સાધનો જોઈ શકાય છે અને પૃષà«àª àª¨à«‹ દેખાવ બદલવા માટે હà«àª®àª²àª¾àª–ોર દà«àªµàª¾àª°àª¾ સંશોધિત કરવામાં આવી શકે છે.</translation>
+<translation id="5786044859038896871">શà«àª‚ તમે તમારી કારà«àª¡ માહિતી ભરવા માગો છો?</translation>
+<translation id="5803412860119678065">શà«àª‚ તમે તમારી <ph name="CARD_DETAIL" /> માહિતી ભરવા માગો છો?</translation>
<translation id="5810442152076338065"><ph name="DOMAIN" /> સાથેના તમારા કનેકà«àª¶àª¨àª¨à«‡ ઑબà«àª¸à«‹àª²àª¿àªŸ સાઇફર સà«àª¯à«‚ટનો ઉપયોગ કરીને àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ કરાયà«àª‚ છે.</translation>
<translation id="5813119285467412249">&amp;ઉમેરવà«àª‚ ફરી કરો</translation>
+<translation id="5814352347845180253">તમે <ph name="SITE" /> અને કેટલીક અનà«àª¯ સાઇટà«àª¸àª¨à«€ પà«àª°à«€àª®àª¿àª¯àª® સામગà«àª°à«€àª¨à«€ àªàª•à«àª¸à«‡àª¸ ગà«àª®àª¾àªµà«€ શકો છો.</translation>
+<translation id="5843436854350372569">તમે <ph name="DOMAIN" /> પર પહોંàªàªµàª¾àª¨à«‹ પà«àª°àª¯àª¤à«àª¨ કરà«àª¯à«‹, પરંતૠસરà«àªµàª°à«‡ નબળી કી ધરાવતà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚. હà«àª®àª²àª¾àª–ોરે ખાનગી કી તોડી હોઈ શકે છે અને બને કે સરà«àªµàª° તમારà«àª‚ અપેકà«àª·àª¿àª¤ સરà«àªµàª° ન હોય (તમે કોઈ હà«àª®àª²àª¾àª–ોર સાથે વારà«àª¤àª¾àª²àª¾àªª કરી રહà«àª¯àª¾àª‚ હોઈ શકો છો). <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">તમે આ સંદેશ જોઇ રહà«àª¯àª¾àª‚ છો કારણ કે તમારા સંàªàª¾àª²àª•à«‡ આ સાઇટ અવરોધિત કરી છે.</translation>
<translation id="5857090052475505287">નવà«àª‚ ફોલà«àª¡àª°</translation>
<translation id="5869405914158311789">આ સાઇટ પર પહોંàªà«€ શકાતà«àª‚ નથી</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">પેરેનà«àªŸ સૂàªàª¨à«‹</translation>
<translation id="59107663811261420">આ વેપારી માટે Google Payments દà«àªµàª¾àª°àª¾ આ પà«àª°àª•àª¾àª°àª¨àª¾ કારà«àª¡àª¨à«‡ સમરà«àª¥àª¨ નથી. કૃપા કરીને બીજà«àª‚ કારà«àª¡ પસંદ કરો.</translation>
<translation id="59174027418879706">સકà«àª·àª®</translation>
+<translation id="5926846154125914413">તમે કેટલીક સાઇટà«àª¸àª¨à«€ પà«àª°à«€àª®àª¿àª¯àª® સામગà«àª°à«€àª¨à«€ àªàª•à«àª¸à«‡àª¸ ગà«àª®àª¾àªµà«€ શકો છો.</translation>
<translation id="5966707198760109579">અઠવાડિયà«àª‚</translation>
<translation id="5967867314010545767">ઇતિહાસમાંથી દૂર કરો</translation>
<translation id="5975083100439434680">àªà«‚મ ઘટાડો</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">સà«àªµàªàª²àª¿àª¤</translation>
<translation id="6042308850641462728">વધà«</translation>
<translation id="6060685159320643512">સાવàªà«‡àª¤à«€ રાખો, આ પà«àª°àª¯à«‹àª—à«‹ નà«àª•àª¸àª¾àª¨àª•àª¾àª°àª• હોઈ શકે છે</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{કોઈ નહીં}=1{1}one{#}other{#}}</translation>
<translation id="6146055958333702838">કોઈપણ કેબલà«àª¸ તપાસો અને તમે કદાઠઉપયોગમાં લઇ રહà«àª¯àª¾àª‚ હોય તેવા કોઇપણ રાઉટરà«àª¸, મૉડેમà«àª¸Â 
અથવા અનà«àª¯ નેટવરà«àª• ઉપકરણોને રીબૂટ કરો.</translation>
<translation id="614940544461990577">પà«àª°àª¯àª¾àª¸ કરો:</translation>
<translation id="6150607114729249911">અરેરે! આ પૃષà«àª àª¨à«€ મà«àª²àª¾àª•àª¾àª¤ લો તે ઠીક છે કે કેમ તે તમારે તમારા માતાપિતાને પૂછવાની જરૂર છે.</translation>
<translation id="6151417162996330722">સરà«àªµàª° પà«àª°àª®àª¾àª£àªªàª¤à«àª° પાસે ખૂબ લાંબી હોય àªàªµà«€ માનà«àª¯àª¤àª¾ અવધિ છે.</translation>
-<translation id="6154808779448689242">પરત થયેલ નીતિ ટોકન વરà«àª¤àª®àª¾àª¨ ટોકનથી મેળ ખાતો નથી</translation>
<translation id="6165508094623778733">વધૠજાણો</translation>
<translation id="6203231073485539293">તમારà«àª‚ ઇનà«àªŸàª°àª¨à«‡àªŸ કનેકà«àª¶àª¨ તપાસો</translation>
<translation id="6218753634732582820">Chromium માંથી સરનામà«àª‚ દૂર કરીàª?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">નેટવરà«àª• પૂરà«àªµàª¾àª¨à«àª®àª¾àª¨àª¨à«‡ અકà«àª·àª® કરવાનો પà«àª°àª¯àª¾àª¸ કરો</translation>
<translation id="6337534724793800597">નામ દà«àªµàª¾àª°àª¾ નીતિઓને ફિલà«àªŸàª° કરો</translation>
<translation id="6342069812937806050">હમણાં જ</translation>
+<translation id="6345221851280129312">અનામ કદ</translation>
<translation id="6355080345576803305">સારà«àªµàªœàª¨àª¿àª• સતà«àª° ઓવરરાઇડ</translation>
<translation id="6358450015545214790">આનો અરà«àª¥ શà«àª‚ છે?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 અનà«àª¯ સૂàªàª¨}one{# અનà«àª¯ સૂàªàª¨}other{# અનà«àª¯ સૂàªàª¨}}</translation>
<translation id="6387478394221739770">શà«àª‚ કૂલ નવી Chrome સà«àªµàª¿àª§àª¾àª“માં રà«àªàª¿ ધરાવો છો? chrome.com/beta પર અમારી બીટા àªà«‡àª¨àª² અજમાવી જà«àª“.</translation>
-<translation id="641480858134062906"><ph name="URL" /> લોડ થવામાં નિષà«àª«àª³</translation>
+<translation id="6389758589412724634">આ વેબ પૃષà«àª  પà«àª°àª¦àª°à«àª¶àª¿àª¤ કરવાનો પà«àª°àª¯àª¾àª¸ કરતી વખતે Chromium ની મેમરી સમાપà«àª¤ થઈ ગઈ.</translation>
+<translation id="6416403317709441254">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે વેબસાઇટે સમજાય નહીં તેવા ઓળખપતà«àª° મોકલà«àª¯àª¾àª‚ છે જેની પર Chromium પà«àª°àª•à«àª°àª¿àª¯àª¾ કરી શકતà«àª‚ નથી. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પૃષà«àª  સંભવિત રૂપે પછીથી કારà«àª¯ કરશે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">પà«àª°àª®àª¾àª£àªªàª¤à«àª° રદ કરવામાં આવà«àª¯à«àª‚ છે કે નહીં તે તપાસવામાં અકà«àª·àª® છે.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ઠકનેકà«àªŸ કરવાનો ઇનકાર કરà«àª¯à«‹.</translation>
<translation id="6445051938772793705">દેશ</translation>
<translation id="6451458296329894277">ફોરà«àª®àª¨àª¾àª‚ ફરી સબમિશનની પà«àª·à«àªŸàª¿ કરો</translation>
<translation id="6458467102616083041">અવગણો કારણ કે નીતિ દà«àªµàª¾àª°àª¾ ડિફૉલà«àªŸ શોધ અકà«àª·àª® કરેલી છે.</translation>
+<translation id="6462969404041126431">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° રદબાતલ કરà«àª¯à«àª‚ હોઈ શકે છે. આ કદાઠકોઈ ખોટી ગોઠવણી અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોવાને કારણે થયà«àª‚ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">ઉપકરણ નીતિઓ</translation>
<translation id="6489534406876378309">કà«àª°à«‡àª¶ અપલોડ કરવાનà«àª‚ શરૂ કરો</translation>
<translation id="6529602333819889595">&amp;કાઢી નાખવà«àª‚ ફરી કરો</translation>
+<translation id="6534179046333460208">વાસà«àª¤àªµàª¿àª• વેબ સૂàªàª¨à«‹</translation>
<translation id="6550675742724504774">વિકલà«àªªà«‹</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" /> કરતાં ઓછà«àª‚</translation>
<translation id="6596325263575161958">àªàª¨à«àª•à«àª°àª¿àªªà«àª¶àª¨ વિકલà«àªªà«‹</translation>
<translation id="662080504995468778">પૃષà«àª  પર રહો</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> શોધ</translation>
-<translation id="6634865548447745291">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે <ph name="BEGIN_LINK" />આ પà«àª°àª®àª¾àª£àªªàª¤à«àª° રદબાતલ કરવામાં આવà«àª¯à«àª‚ છે<ph name="END_LINK" />. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પૃષà«àª  સંભવિત રૂપે પછીથી કારà«àª¯ કરશે.</translation>
<translation id="6644283850729428850">આ નીતિ દૂર કરવામાં આવેલી છે.</translation>
+<translation id="6652240803263749613">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઓપરેટિંગ સિસà«àªŸàª® દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">ફોલà«àª¡àª° સંપાદિત કરો</translation>
<translation id="6660210980321319655">આપમેળે જાણ કરી <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Chromium માંથી ફોરà«àª® સૂàªàª¨ દૂર કરીàª?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">પહેલાનà«àª‚</translation>
<translation id="6710594484020273272">&lt;શોધ શબà«àª¦ લખો&gt;</translation>
<translation id="6711464428925977395">પà«àª°à«‹àª•à«àª¸à«€ સરà«àªµàª°àª®àª¾àª‚ કંઈક ખોટà«àª‚ થયà«àª‚ છે અથવા તો સરનામà«àª‚ ખોટà«àª‚ છે.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{કોઈ નહીં}=1{1 આઇટમ}one{# આઇટમ}other{# આઇટમ}}</translation>
<translation id="674375294223700098">અજà«àªàª¾àª¤ સરà«àªµàª° પà«àª°àª®àª¾àª£àªªàª¤à«àª° ભૂલ.</translation>
<translation id="6753269504797312559">નીતિ મૂલà«àª¯</translation>
<translation id="6757797048963528358">તમારà«àª‚ ઉપકરણ નિષà«àª•à«àª°àª¿àª¯ થઈ ગયà«àª‚ હતà«àª‚.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">નીતિ સà«àª¤àª° સમરà«àª¥àª¿àª¤ નથી.</translation>
<translation id="6895330447102777224">તમારા કારà«àª¡àª¨à«€ પà«àª·à«àªŸàª¿ કરવામાં આવી છે</translation>
<translation id="6897140037006041989">વપરાશકરà«àª¤àª¾ àªàªœàª¨à«àªŸ</translation>
-<translation id="6903907808598579934">સમનà«àªµàª¯àª¨ àªàª¾àª²à« કરો</translation>
<translation id="6915804003454593391">વપરાશકરà«àª¤àª¾: </translation>
<translation id="6957887021205513506">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° બનાવટી હોય àªàªµà«àª‚ લાગે છે.</translation>
<translation id="6965382102122355670">ઓકે</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">જીલà«àª²à«‹</translation>
<translation id="6973656660372572881">નિયત પà«àª°à«‹àª•à«àª¸à«€ સરà«àªµàª°à«àª¸ અને .pac script URL બનà«àª¨à«‡àª¨à«‹ ઉલà«àª²à«‡àª– કરેલો છે.</translation>
<translation id="6989763994942163495">વિગતવાર સેટિંગà«àª¸ બતાવો...</translation>
+<translation id="7000990526846637657">કોઈ ઇતિહાસ પà«àª°àªµàª¿àª·à«àªŸàª¿àª“ મળી નથી</translation>
+<translation id="7009986207543992532">તમે <ph name="DOMAIN" /> પર પહોંàªàªµàª¾àª¨à«‹ પà«àª°àª¯àª¤à«àª¨ કરà«àª¯à«‹, પરંતૠસરà«àªµàª°à«‡ àªàªµà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚ કે જેની માનà«àª¯àª¤àª¾ અવધિ àªàªŸàª²à«€ લાંબી છે કે તે વિશà«àªµàª¸àª¨à«€àª¯ લાગતી નથી. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> પર બà«àª°àª¾àª‰àªàª¿àª‚ગ ઇતિહાસના અનà«àª¯ સà«àªµàª°à«‚પો હોઇ શકે છે.</translation>
<translation id="7029809446516969842">પાસવરà«àª¡à«àª¸</translation>
-<translation id="7050187094878475250">તમે <ph name="DOMAIN" /> પર પહોંàªàªµàª¾àª¨à«‹ પà«àª°àª¯àª¾àª¸ કરેલો, પરંતૠસરà«àªµàª°à«‡ àªàªµà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚ જેની માનà«àª¯àª¤àª¾ અવધિ, વિશà«àªµàª¸àª¨à«€àª¯ હોવા માટે ખૂબ લાંબી છે.</translation>
<translation id="7087282848513945231">પરગણà«àª‚</translation>
<translation id="7088615885725309056">વધૠજૂનà«àª‚</translation>
<translation id="7090678807593890770"><ph name="LINK" /> માટે Google પર શોધો</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">તમે આ સંદેશ જોઇ રહà«àª¯àª¾àª‚ છો કારણ કે નવી સાઇટà«àª¸àª¨à«€ તમારી પà«àª°àª¥àª® મà«àª²àª¾àª•àª¾àª¤ પર તમારા સંàªàª¾àª²àª•à«‡ મંજૂરી આપવી જરૂરી છે.</translation>
<translation id="724975217298816891">તમારા કારà«àª¡àª¨à«€ વિગતોને અપડેટ કરવા <ph name="CREDIT_CARD" /> માટે સમાપà«àª¤àª¿ તારીખ અને CVC દાખલ કરો. àªàª•àªµàª¾àª° તમે પà«àª·à«àªŸàª¿ કરી લો, તે પછી આ સાઇટ સાથે તમારા કારà«àª¡àª¨à«€ વિગતો શેર કરવામાં આવશે.</translation>
<translation id="725866823122871198"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> પર ખાનગી કનેકà«àª¶àª¨ સà«àª¥àª¾àªªàª¿àª¤ કરી શકાતà«àª‚ નથી કારણ કે તમારા ઉપકરણની તારીખ અને સમય (<ph name="DATE_AND_TIME" />) અયોગà«àª¯ છે.</translation>
-<translation id="7265986070661382626">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે વેબસાઇટ <ph name="BEGIN_LINK" />પà«àª°àª®àª¾àª£àªªàª¤à«àª° પિનિંગનો ઉપયોગ કરે છે<ph name="END_LINK" />. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પૃષà«àª  સંભવિત રૂપે પછીથી કારà«àª¯ કરશે.</translation>
<translation id="7269802741830436641">આ વેબ પૃષà«àª àª®àª¾àª‚ àªàª• રીડાયરેકà«àªŸ લૂપ છે</translation>
<translation id="7275334191706090484">સંàªàª¾àª²àª¿àª¤ બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
<translation id="7298195798382681320">ભલામણ કરેલ</translation>
-<translation id="7301833672208172928">ઇતિહાસ સમનà«àªµàª¯àª¨ àªàª¾àª²à« કરો</translation>
+<translation id="7309308571273880165">કà«àª°à«‡àª¶ રિપોરà«àªŸ <ph name="CRASH_TIME" /> ઠકૅપà«àªàª° કરવામાં આવી (વપરાશકરà«àª¤àª¾ દà«àªµàª¾àª°àª¾ અપલોડની વિનંતી કરવામાં આવી, હજી સà«àª§à«€ અપલોડ કરેલ નથી)</translation>
<translation id="7334320624316649418">&amp;પà«àª¨àªƒàª•à«àª°àª®àª¾àª‚કિત કરવà«àª‚ ફરી કરો</translation>
<translation id="733923710415886693">પà«àª°àª®àª¾àª£àªªàª¤à«àª° પારદરà«àª¶àª¿àª¤àª¾ દà«àªµàª¾àª°àª¾ સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° જાહેર કરવામાં આવà«àª¯à«àª‚ ન હતà«àª‚.</translation>
+<translation id="7351800657706554155">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" /> ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે આ પà«àª°àª®àª¾àª£àªªàª¤à«àª° રદબાતલ કરવામાં આવà«àª¯à«àª‚ છે. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પૃષà«àª  સંભવિત રૂપે પછીથી કારà«àª¯ કરશે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">આદેશ પંકà«àª¤àª¿</translation>
<translation id="7372973238305370288">શોધ પરિણામ</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">કારà«àª¡àª¨à«€ પà«àª·à«àªŸàª¿ કરી રહà«àª¯àª¾àª‚ છે</translation>
<translation id="7481312909269577407">ફોરà«àªµàª°à«àª¡ કરો</translation>
<translation id="7485870689360869515">કોઈ ડેટા મળà«àª¯à«‹ નથી.</translation>
+<translation id="7508255263130623398">પરત થયેલ નીતિ ઉપકરણ id ખાલી છે અથવા વરà«àª¤àª®àª¾àª¨ ટોકન સાથે મેળ ખાતà«àª‚ નથી</translation>
<translation id="7514365320538308">ડાઉનલોડ કરો</translation>
<translation id="7518003948725431193">વેબ સરનામાં માટે કોઈ વેબપેજ મળà«àª¯à«àª‚ નથી: <ph name="URL" /></translation>
<translation id="7537536606612762813">ફરજિયાત</translation>
<translation id="7542995811387359312">આપમેળે કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡ ભરણ અકà«àª·àª® કરà«àª¯à«àª‚ છે કારણ કે આ ફોરà«àª® સà«àª°àª•à«àª·àª¿àª¤ કનેકà«àª¶àª¨àª¨à«‹ ઉપયોગ કરતà«àª‚ નથી.</translation>
<translation id="7549584377607005141">આ વેબપૃષà«àª àª¨à«‡ તે ડેટાની જરૂર છે જે તમે પહેલા બરાબર રીતે પà«àª°àª¦àª°à«àª¶àª¿àª¤ થાય તે માટે દાખલ કરà«àª¯à«‹ હતો. તમે આ ડેટા ફરીથી મોકલી શકો છો, પણ આમ કરીને તમે કોઈપણ કà«àª°àª¿àª¯àª¾ કે જે પૃષà«àª  પહેલા જ કરી àªà«àª•à«àª¯à«àª‚ છે તેનà«àª‚ પà«àª¨àª°àª¾àªµàª°à«àª¤àª¨ કરશો.</translation>
<translation id="7554791636758816595">નવà«àª‚ ટૅબ</translation>
-<translation id="7567204685887185387">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° કપટપૂરà«àªµàª• રજૂ કરવામાં આવેલ હોઈ શકે છે. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
<translation id="7568593326407688803">આ પૃષà«àª <ph name="ORIGINAL_LANGUAGE" />માં છે શà«àª‚ તમે તેને અનà«àªµàª¾àª¦àª¿àª¤ કરવા માંગો છો?</translation>
<translation id="7569952961197462199">Chrome માંથી કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡ દૂર કરીàª?</translation>
<translation id="7578104083680115302">તમે Google સાથે સાàªàªµà«àª¯àª¾àª‚ છે તે કારà«àª¡à«àª¸àª¨à«‹ ઉપયોગ કરીને સમગà«àª° ઉપકરણોમાં સાઇટà«àª¸ અને àªàªªà«àª²àª¿àª•à«‡àª¶àª¨à«‹ પર àªàª¡àªªàª¥à«€ àªà«àª•àªµàª£à«€ કરો.</translation>
+<translation id="7588950540487816470">વાસà«àª¤àªµàª¿àª• વેબ</translation>
<translation id="7592362899630581445">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª°, નામ નિગà«àª°àª¹à«‹àª¨à«àª‚ ઉલà«àª²àª‚ઘન કરે છે.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" />, હાલમાં આ વિનંતીને હેનà«àª¡àª² કરવામાં અસમરà«àª¥ છે.</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" /> નà«àª‚ કà«àª¯àª¾àª°à«‡àª¯ અનà«àªµàª¾àª¦ કરશો નહીં</translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">Chromium માંથી કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡ દૂર કરીàª?</translation>
<translation id="765676359832457558">વિગતવાર સેટિંગà«àª¸ છà«àªªàª¾àªµà«‹...</translation>
<translation id="7658239707568436148">રદ કરો</translation>
+<translation id="7667346355482952095">પરત થયેલ નીતિ ટોકન ખાલી છે અથવા વરà«àª¤àª®àª¾àª¨ ટોકન સાથે મેળ ખાતà«àª‚ નથી</translation>
<translation id="7668654391829183341">અજà«àªàª¾àª¤ ઉપકરણ</translation>
<translation id="7674629440242451245">શà«àª‚ કૂલ નવી Chrome સà«àªµàª¿àª§àª¾àª“માં રà«àªàª¿ ધરાવો છો? chrome.com/dev પર અમારી dev àªà«…નલ અજમાવી જà«àª“.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> પર આગળ વધો (અસલામત)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">નહીં, આભાર</translation>
<translation id="7805768142964895445">સà«àª¥àª¿àª¤àª¿</translation>
<translation id="7813600968533626083">Chrome માંથી ફોરà«àª® સૂàªàª¨à«‹ દૂર કરીàª?</translation>
+<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' માટે <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> મળà«àª¯àª¾àª‚</translation>
<translation id="785549533363645510">જો કે, તમે અદૃશà«àª¯ નથી. છà«àªªàª¾àª®àª¾àª‚ જવà«àª‚ તમારા નિયોકà«àª¤àª¾, તમારા ઇનà«àªŸàª°àª¨à«‡àªŸ સેવા પà«àª°àª¦àª¾àª¤àª¾ અથવા તમે મà«àª²àª¾àª•àª¾àª¤ લો છો તે વેબસાઇટà«àª¸àª¥à«€ તમારા બà«àª°àª¾àª‰àªàª¿àª‚ગને છà«àªªàª¾àªµàª¤à«àª‚ નથી.</translation>
<translation id="7887683347370398519">તમારà«àª‚ CVC તપાસો અને ફરીથી પà«àª°àª¯àª¾àª¸ કરો</translation>
<translation id="7894616681410591072">અરેરે! આ પૃષà«àª àª¨à«‡ àªàª•à«àª¸à«‡àª¸ કરવા માટે તમને <ph name="NAME" /> ની પરવાનગીની જરૂર છે.</translation>
-<translation id="790025292736025802"><ph name="URL" /> મળà«àª¯à«àª‚ નથી</translation>
<translation id="7912024687060120840">ફોલà«àª¡àª°àª®àª¾àª‚:</translation>
<translation id="7920092496846849526">આ પૃષà«àª à«€ મà«àª²àª¾àª•àª¾àª¤ લો તે ઠીક છે તેવà«àª‚ તમે તમારા માતાપિતાને પૂછà«àª¯à«àª‚ છે કે કેમ.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">નિરà«àª¦àª¿àª·à«àªŸ કરાયેલ નથી</translation>
<translation id="8012647001091218357">અમે આ પળે તમારા વાલીઓ સà«àª§à«€ પહોંàªà«€ શકà«àª¯àª¾àª‚ નથી. કૃપા કરીને ફરી પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="8034522405403831421">આ પૃષà«àª  <ph name="SOURCE_LANGUAGE" /> માં છે. શà«àª‚ તેનો અનà«àªµàª¾àª¦ <ph name="TARGET_LANGUAGE" /> માં કરીàª?</translation>
-<translation id="8034955203865359138">કોઈ ઇતિહાસ પà«àª°àªµàª¿àª·à«àªŸàª¿àª“ મળી નથી.</translation>
<translation id="8088680233425245692">લેખ જોવામાં નિષà«àª«àª³ થયાં.</translation>
+<translation id="8089520772729574115">1 MB કરતાં ઓછà«àª‚</translation>
<translation id="8091372947890762290">સકà«àª°àª¿àª¯àª¤àª¾ સરà«àªµàª° પર બાકી છે</translation>
+<translation id="8129262335948759431">અનામ રકમ</translation>
<translation id="8131740175452115882">પà«àª·à«àªŸàª¿ કરો</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> નà«àª‚ સરà«àªµàª° <ph name="BEGIN_ABBR" />DNS સરનામà«àª‚<ph name="END_ABBR" /> શોધી શકાયà«àª‚ નથી.</translation>
<translation id="8149426793427495338">તમારà«àª‚ કમà«àªªà«àª¯à«àªŸàª° નિષà«àª•à«àª°àª¿àª¯ થઈ ગયà«àª‚ હતà«àª‚.</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">ID "<ph name="EXTENSION_ID" />" સાથેના àªàª•à«àª¸àªŸà«‡àª¨à«àª¶àª¨ માટે અમાનà«àª¯ અપડેટ URL.</translation>
<translation id="8218327578424803826">સોંપાયેલ સà«àª¥àª¾àª¨:</translation>
<translation id="8225771182978767009">આ કમà«àªªà«àª¯à«àªŸàª°àª¨à«‡ સેટ કરનાર વà«àª¯àª•à«àª¤àª¿àª આ સાઇટને અવરોધિત કરવાનà«àª‚ પસંદ કરà«àª¯à«àª‚ છે.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">તમારા દà«àªµàª¾àª°àª¾ દાખલ કરાયેલી વપરાયેલી માહિતી માટે આ પાનà«àª‚ તમે જોઈ રહà«àª¯àª¾ છો. તે પૃષà«àª  પર પાછા જવાથી àªàªµà«€ કોઈપણ કà«àª°àª¿àª¯àª¾ ફરીથી થઈ શકે છે જે તમે પહેલા કરી હતી. શà«àª‚ તમે àªàª¾àª²à« રાખવા માંગો છો?</translation>
<translation id="8249320324621329438">છેલà«àª²à«àª‚ આનયન:</translation>
<translation id="8261506727792406068">કાઢી નાખો</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">બà«àª•àª®àª¾àª°à«àª•à«àª¸ બાર</translation>
<translation id="8363502534493474904">àªàª°àªªà«àª²à«‡àª¨ મોડ બંધ કરીને</translation>
<translation id="8364627913115013041">સેટ નથી.</translation>
+<translation id="8380941800586852976">જોખમી</translation>
<translation id="8412145213513410671">કà«àª°à«‡àª¶à«‡àª¸ (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">તમારે તે જ પાસફà«àª°à«‡àª બે વાર દાખલ કરવો આવશà«àª¯àª• છે.</translation>
<translation id="8428213095426709021">સેટિંગà«àª¸</translation>
+<translation id="8433057134996913067">આ તમને મોટાભાગની વેબસાઇટà«àª¸àª®àª¾àª‚થી સાઇન આઉટ કરશે.</translation>
<translation id="8437238597147034694">&amp;ખસેડવà«àª‚ પૂરà«àªµàªµàª¤à«â€Œ કરો</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡}one{# કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡}other{# કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡}}</translation>
+<translation id="8483780878231876732">તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚થી કારà«àª¡à«àª¸àª¨à«‹ ઉપયોગ કરવા માટે, Chrome માં સાઇન ઇન કરો</translation>
<translation id="8488350697529856933">આમને લાગà«</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ઠપà«àª°àª¤àª¿àª¸àª¾àª¦ આપવા માટે ઘણો સમય લીધો.</translation>
+<translation id="852346902619691059">આ સરà«àªµàª° ઠસાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તમારા ઉપકરણની ઓપરેટિંગ સિસà«àªŸàª® દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Google Payments દà«àªµàª¾àª°àª¾ આ પà«àª°àª•àª¾àª°àª¨àª¾ કારà«àª¡àª¨à«‡ સમરà«àª¥àª¨ નથી. કૃપા કરીને બીજà«àª‚ કારà«àª¡ પસંદ કરો.</translation>
<translation id="8550022383519221471">સમનà«àªµàª¯àª¨ સેવા તમારા ડોમેન માટે ઉપલબà«àª§ નથી.</translation>
<translation id="8553075262323480129">ભાષાંતર નિષà«àª«àª³ રહà«àª¯à«àª‚ કારણ કે પૃષà«àª àª¨à«€ ભાષા નિરà«àª§àª¾àª°àª¿àª¤ થઈ શકી નથી.</translation>
@@ -633,15 +675,12 @@
<translation id="8647750283161643317">બધાને ડિફોલà«àªŸ પર ફરીથી સેટ કરો</translation>
<translation id="8680787084697685621">àªàª•àª¾àª‰àª¨à«àªŸ સાઇન-ઇન વિગતો જૂની થઈ ગઈ છે.</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> સાથેનà«àª‚ તમારà«àª‚ કનેકà«àª¶àª¨ àªàª¨à«àª•à«àª°àª¿àªªà«àªŸà«‡àª¡ નથી.</translation>
-<translation id="8713130696108419660">ખોટી ટૂંકી સહી</translation>
<translation id="8725066075913043281">ફરી પà«àª°àª¯àª¾àª¸ કરો</translation>
<translation id="8728672262656704056">તમે છà«àªªàª¾ મોડમાં ગયા છો</translation>
<translation id="8730621377337864115">થઈ ગયà«àª‚</translation>
<translation id="8738058698779197622">àªàª• સà«àª°àª•à«àª·àª¿àª¤ કનેકà«àª¶àª¨ સà«àª¥àª¾àªªàª¿àª¤ કરવા માટે, તમારà«àª‚ ઘડિયાળ યોગà«àª¯ રીતે સેટ હોવà«àª‚ જરૂરી છે. આનà«àª‚ કારણ ઠકે વેબસાઇટà«àª¸ તેઓને ઓળખવા માટે જે પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹àª¨à«‹ ઉપયોગ કરે છે તે àªà«‹àª•à«àª•àª¸ સમય અવધિ માટે જ માનà«àª¯ હોય છે. તમારા ઉપકરણની ઘડિયાળ ખોટી હોવાને લીધે, Chromium આ પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹àª¨à«‡ àªàª•àª¾àª¸à«€ શકતà«àª‚ નથી.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> નà«àª‚ &lt;abbr id="dnsDefinition"&gt;DNS સરનામà«àª‚&lt;/abbr&gt; શોધી શકાયà«àª‚ નથી. સમસà«àª¯àª¾àª¨à«àª‚ નિદાન કરી રહà«àª¯àª¾àª‚ છીàª.</translation>
-<translation id="8741995161408053644">તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> પર બà«àª°àª¾àª‰àªàª¿àª‚ગ ઇતિહાસના અનà«àª¯ સà«àªµàª°à«‚પો હોઇ શકે છે.</translation>
<translation id="8790007591277257123">&amp;કાઢી નાખવà«àª‚ ફરી કરો</translation>
-<translation id="8790687370365610530">Google દà«àªµàª¾àª°àª¾ સૂàªàªµà«‡àª² વà«àª¯àª•à«àª¤àª¿àª—ત કરેલ સામગà«àª°à«€ મેળવવા માટે, ઇતિહાસ સમનà«àªµàª¯àª¨ àªàª¾àª²à« કરો.</translation>
<translation id="8798099450830957504">ડિફૉલà«àªŸ</translation>
<translation id="8804164990146287819">ગોપનીયતા નીતિ</translation>
<translation id="8820817407110198400">બà«àª•àª®àª¾àª°à«àª•à«àª¸</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">સરà«àªµàª°àª¨àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«€ સમયસીમા સમાપà«àª¤ થઈ છે.</translation>
<translation id="8987927404178983737">મહિનો</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">સરà«àªµàª°à«‡ àªàªµà«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚ કે જે પà«àª°àª®àª¾àª£àªªàª¤à«àª° પારદરà«àª¶àª¿àª¤àª¾ નીતિનો ઉપયોગ કરીને સારà«àªµàªœàª¨àª¿àª• રીતે જાહેર કરà«àª¯à«àª‚ ન હતà«àª‚. આ કેટલાક પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹ માટે ઠખાતરી કરવા હેતૠઆવશà«àª¯àª• છે કે તેઓ વિશà«àªµàª¸àª¨à«€àª¯ છે અને હà«àª®àª²àª¾àª–ારો સામે રકà«àª·àª£ કરે છે.</translation>
<translation id="9001074447101275817">પà«àª°à«‹àª•à«àª¸à«€ <ph name="DOMAIN" /> ને વપરાશકરà«àª¤àª¾àª¨àª¾àª® અને પાસવરà«àª¡àª¨à«€ જરૂર છે.</translation>
<translation id="901974403500617787">ધà«àªµàªœà«‹ કે જે સિસà«àªŸàª®-વà«àª¯àª¾àªªà«€ લાગૠછે તે ફકà«àª¤ માલિક દà«àªµàª¾àª°àª¾ જ સેટ કરી શકાય છે: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">આ પૃષà«àª àª¨à«‹ <ph name="TARGET_LANGUAGE" /> માં અનà«àªµàª¾àª¦ કરવામાં આવà«àª¯à«‹ છે</translation>
<translation id="9038649477754266430">પૃષà«àª à«‹àª¨à«‡ વધૠàªàª¡àªªàª¥à«€ લોડ કરવા માટે પૂરà«àªµàª¾àª¨à«àª®àª¾àª¨ સેવાનો ઉપયોગ કરો</translation>
<translation id="9039213469156557790">વળી, આ પૃષà«àª àª®àª¾àª‚ અનà«àª¯ àªàªµàª¾ સાધનો છે જે સà«àª°àª•à«àª·àª¿àª¤ નથી. ટà«àª°àª¾àª‚àªàª¿àªŸàª®àª¾àª‚ હોવા પર અનà«àª¯ લોકો દà«àªµàª¾àª°àª¾ આ સાધનો જોઈ શકાય છે અને પૃષà«àª àª¨à«‹ વà«àª¯àªµàª¹àª¾àª° બદલવા માટે હà«àª®àª²àª¾àª–ોર દà«àªµàª¾àª°àª¾ સંશોધિત કરવામાં આવી શકે છે.</translation>
-<translation id="9049981332609050619">તમે <ph name="DOMAIN" /> સà«àª§à«€ પહોંàªàªµàª¾àª¨à«‹ પà«àª°àª¯àª¾àª¸ કરà«àª¯à«‹, પરંતૠસરà«àªµàª°à«‡ અમાનà«àª¯ પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરà«àª¯à«àª‚. </translation>
<translation id="9050666287014529139">પાસફà«àª°à«‡àª</translation>
<translation id="9065203028668620118">સંપાદન</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> પૃષà«àª  કામ કરી રહà«àª¯à«àª‚ નથી</translation>
diff --git a/chromium/components/strings/components_strings_hi.xtb b/chromium/components/strings/components_strings_hi.xtb
index 9b85ad12b5d..26334cb8ee1 100644
--- a/chromium/components/strings/components_strings_hi.xtb
+++ b/chromium/components/strings/components_strings_hi.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hi">
+<translation id="1008557486741366299">अभी नहीं</translation>
<translation id="1015730422737071372">अतिरिकà¥à¤¤ विवरण पà¥à¤°à¤¦à¤¾à¤¨ करें</translation>
<translation id="1032854598605920125">घड़ी की दिशा में घà¥à¤®à¤¾à¤à¤‚</translation>
<translation id="1038842779957582377">अजà¥à¤à¤¾à¤¤ नाम</translation>
+<translation id="1053591932240354961">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते कà¥à¤¯à¥‹à¤‚कि वेबसाइट ने à¤à¤¸à¥‡ अवà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल भेजे हैं जिनà¥à¤¹à¥‡à¤‚ Google Chrome संसाधित नहीं कर सकता. नेटवरà¥à¤• की गड़बड़ियां और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: यह पृषà¥à¤  बाद में काम करेगा. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;जोड़ना वापस लाà¤à¤‚</translation>
<translation id="10614374240317010">कभी नहीं सहेजा गया</translation>
-<translation id="1064422015032085147">वेबपृषà¥à¤  को होसà¥à¤Ÿ करने वाले सरà¥à¤µà¤° पर अतà¥à¤¯à¤§à¤¿à¤• लोड हो सकता है या हो सकता है उसका रखरखाव à¤à¤² रहा हो.
- बहà¥à¤¤ अधिक टà¥à¤°à¥ˆà¥à¤¿à¤• जेनरेट होने और सà¥à¤¥à¤¿à¤¤à¤¿ के और भी खराब होने से बà¤à¤¨à¥‡ के लिà¤,
- इस URL के अनà¥à¤°à¥‹à¤§à¥‹à¤‚ को असà¥à¤¥à¤¾à¤¯à¥€ रूप से असà¥à¤µà¥€à¤•à¥ƒà¤¤ कर दिया गया है.</translation>
<translation id="106701514854093668">डेसà¥à¤•à¤Ÿà¥‰à¤ª बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="1080116354587839789">à¤à¥Œà¥œà¤¾à¤ˆ में à¥à¤¿à¤Ÿ करें</translation>
+<translation id="1103124106085518534">अभी के लिठहो गया</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> का हमेशा अनà¥à¤µà¤¾à¤¦ करें</translation>
<translation id="1107591249535594099">à¤à¥‡à¤• किठहोने पर, अधिक तेज़ फ़ॉरà¥à¤® भरने के लिठChrome इस डिवाइस पर आपके कारà¥à¤¡ की पà¥à¤°à¤¤à¤¿à¤²à¤¿à¤ªà¤¿ संगà¥à¤°à¤¹à¥€à¤¤ कर लेगा.</translation>
+<translation id="1111153019813902504">हाल के बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="1113869188872983271">&amp;पà¥à¤¨: कà¥à¤°à¤®à¤¿à¤¤ करना वापस लाà¤à¤‚</translation>
+<translation id="1126551341858583091">सà¥à¤¥à¤¾à¤¨à¥€à¤¯ जगह का आकार <ph name="CRASH_SIZE" /> है.</translation>
<translation id="112840717907525620">नीति संà¤à¤¯ ठीक है</translation>
<translation id="113188000913989374"><ph name="SITE" /> का कहना है:</translation>
<translation id="1132774398110320017">Chrome ऑटोमैटिक भरने वाली सेटिंग...</translation>
-<translation id="1150979032973867961">यह सरà¥à¤µà¤° यह नहीं पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपके कंपà¥à¤¯à¥‚टर के ऑपरेटिंग सिसà¥à¤Ÿà¤® दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¥à¤¿à¤—रेशन या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="1152921474424827756"><ph name="URL" /> की <ph name="BEGIN_LINK" />संà¤à¤¿à¤¤ पà¥à¤°à¤¤à¤¿<ph name="END_LINK" /> à¤à¤•à¥à¤¸à¥‡à¤¸ करें</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ने अनपेकà¥à¤·à¤¿à¤¤ रूप से कनेकà¥à¤¶à¤¨ बंद कर दिया है.</translation>
<translation id="1161325031994447685">वाई-à¥à¤¾à¤ˆ से फिर से कनेकà¥à¤Ÿ करें</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">निकालें</translation>
<translation id="1201402288615127009">अगला</translation>
<translation id="1201895884277373915">इस साइट की ओर से अधिक</translation>
-<translation id="121201262018556460">आपने <ph name="DOMAIN" /> तक पहà¥à¤‚à¤à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ किया, लेकिन लेकिन सरà¥à¤µà¤° ने कमज़ोर कà¥à¤‚जी वाला पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥â€à¤¤à¥à¤¤ किया. संभवत: हमलावर ने निजी कà¥à¤‚जी का पता लगा लिया है, और हो सकता है कि सरà¥à¤µà¤° आपका अपेकà¥à¤·à¤¿à¤¤ सरà¥à¤µà¤° न हो (हो सकता है कि आप किसी हमलावर से बातà¤à¥€à¤¤ कर रहे हों).</translation>
+<translation id="1206967143813997005">नाम के पहले अकà¥à¤·à¤° के गलत हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°</translation>
+<translation id="1209206284964581585">अभी छिपाà¤à¤‚</translation>
<translation id="1219129156119358924">सिसà¥â€à¤Ÿà¤® सà¥à¤°à¤•à¥à¤·à¤¾</translation>
<translation id="1227224963052638717">अजà¥à¤à¤¾à¤¤ नीति.</translation>
<translation id="1227633850867390598">मान छिपाà¤à¤‚</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">हां</translation>
<translation id="1430915738399379752">पà¥à¤°à¤¿à¤‚ट करें</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /><ph name="DOMAIN" /> के किसी पृषà¥à¤  पर जाने का <ph name="END_LINK" /> पà¥à¤°à¤¯à¤¾à¤¸ अवरोधित किया गया.</translation>
+<translation id="1491663344921578213">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते कà¥à¤¯à¥‹à¤‚कि वेबसाइट पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पिनिंग का उपयोग करती है. नेटवरà¥à¤• की गड़बड़ियां और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: यह पृषà¥à¤  बाद में काम करेगा. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">इस पृषà¥â€à¤  की सहेजी गई (अरà¥à¤¥à¤¾à¤¤ जिसे पà¥à¤°à¤¾à¤¨à¤¾ माना जाता है) कॉपी दिखाà¤à¤‚.</translation>
<translation id="1519264250979466059">बिलà¥à¤¡ दिनांक</translation>
<translation id="1549470594296187301">इस सà¥à¤µà¤¿à¤§à¤¾ का उपयोग करने के लिठJavaScript को सकà¥à¤·à¤® किया जाना à¤à¤¾à¤¹à¤¿à¤.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">नेटवरà¥à¤• कॉनà¥à¤«à¤¼à¤¿à¤—रेशन अमानà¥à¤¯ है और उसे आयात नहीं किया जा सकेगा.</translation>
<translation id="1644574205037202324">इतिहास</translation>
<translation id="1645368109819982629">असमरà¥à¤¥à¤¿à¤¤ पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤²</translation>
-<translation id="1655462015569774233">{1,plural, =1{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय सीमा कल समापà¥à¤¤ हो गई थी. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ को बाधित करने के कारण हो सकता है. आपके कंपà¥à¤¯à¥‚टर की घड़ी वरà¥à¤¤à¤®à¤¾à¤¨ में <ph name="CURRENT_DATE" /> पर सेट है. कà¥â€à¤¯à¤¾ यह सही है? यदि नहीं, तो आपको अपने सिसà¥à¤Ÿà¤® की घड़ी सही करनी à¤à¤¾à¤¹à¤¿à¤ और फिर इस पृषà¥à¤  को रीफà¥à¤°à¥‡à¤¶ करना à¤à¤¾à¤¹à¤¿à¤.}one{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय सीमा # दिन पहले समापà¥à¤¤ हो गई है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ को बाधित करने के कारण हो सकता है. आपके कंपà¥à¤¯à¥‚टर की घड़ी वरà¥à¤¤à¤®à¤¾à¤¨ में <ph name="CURRENT_DATE" /> पर सेट है. कà¥â€à¤¯à¤¾ यह सही है? यदि नहीं, तो आपको अपने सिसà¥à¤Ÿà¤® की घड़ी सही करनी à¤à¤¾à¤¹à¤¿à¤ और फिर इस पृषà¥à¤  को रीफà¥à¤°à¥‡à¤¶ करना à¤à¤¾à¤¹à¤¿à¤.}other{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय सीमा # दिन पहले समापà¥à¤¤ हो गई है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ को बाधित करने के कारण हो सकता है. आपके कंपà¥à¤¯à¥‚टर की घड़ी वरà¥à¤¤à¤®à¤¾à¤¨ में <ph name="CURRENT_DATE" /> पर सेट है. कà¥â€à¤¯à¤¾ यह सही है? यदि नहीं, तो आपको अपने सिसà¥à¤Ÿà¤® की घड़ी सही करनी à¤à¤¾à¤¹à¤¿à¤ और फिर इस पृषà¥à¤  को रीफà¥à¤°à¥‡à¤¶ करना à¤à¤¾à¤¹à¤¿à¤.}}</translation>
<translation id="1676269943528358898">आपकी जानकारी की सà¥à¤°à¤•à¥à¤·à¤¾ करने के लिठ<ph name="SITE" /> आमतौर पर à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤¶à¤¨ का उपयोग करती है. जब Google Chrome ने इस बार <ph name="SITE" /> से कनेकà¥à¤Ÿ करने का पà¥à¤°à¤¯à¤¾à¤¸ किया, तो वेबसाइट ने असामानà¥à¤¯ और गलत कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल वापस भेजे. à¤à¤¸à¤¾ तब हो सकता है जब कोई हमलावर <ph name="SITE" /> होने का दावा करने का पà¥à¤°à¤¯à¤¾à¤¸ कर रहा हो या किसी वाई-à¥à¤¾à¤ˆ पà¥à¤°à¤µà¥‡à¤¶ सà¥à¤•à¥à¤°à¥€à¤¨ ने कनेकà¥à¤¶à¤¨ को बाधित कर दिया हो. आपकी जानकारी अभी भी सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ है कà¥à¤¯à¥‹à¤‚कि किसी भी डेटा के आदान-पà¥à¤°à¤¦à¤¾à¤¨ से पहले ही Google Chrome ने कनेकà¥à¤¶à¤¨ को रोक दिया था.</translation>
<translation id="168841957122794586">सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° में कमज़ोर कà¥à¤°à¤¿à¤ªà¥à¤Ÿà¥‹à¤—à¥à¤°à¤¾à¤«à¤¼à¤¿à¤• कà¥à¤‚जी है.</translation>
<translation id="1701955595840307032">सà¥à¤à¤¾à¤ˆ गई सामगà¥à¤°à¥€ पà¥à¤°à¤¾à¤ªà¥à¤¤ करें</translation>
-<translation id="1706954506755087368">{1,plural, =1{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कल से माना जाà¤à¤—ा. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ को बाधित करने के कारण हो सकता है.}one{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° # दिन बाद से माना जाà¤à¤—ा. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ को बाधित करने के कारण हो सकता है.}other{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° # दिन बाद से माना जाà¤à¤—ा. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ को बाधित करने के कारण हो सकता है.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">सिसà¥à¤Ÿà¤® वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤• से संपरà¥à¤• करने का पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
<translation id="17513872634828108">टैब खोलें</translation>
<translation id="1753706481035618306">पृषà¥â€à¤  संखà¥â€à¤¯à¤¾</translation>
-<translation id="1761412452051366565">Google दà¥à¤µà¤¾à¤°à¤¾ सà¥à¤à¤¾à¤ˆ गई वैयकà¥à¤¤à¤¿à¤•à¥ƒà¤¤ सामगà¥à¤°à¥€ पà¥à¤°à¤¾à¤ªà¥à¤¤ करने के लिà¤, समनà¥à¤µà¤¯à¤¨ à¤à¤¾à¤²à¥‚ करें.</translation>
-<translation id="1763864636252898013">यह सरà¥à¤µà¤° यह नहीं पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपके डिवाइस के ऑपरेटिंग सिसà¥à¤Ÿà¤® दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¥à¤¿à¤—रेशन या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows नेटवरà¥à¤• निदान à¤à¤²à¤¾à¤•à¤° देखें<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">कृपया अपना समनà¥â€à¤µà¤¯à¤¨ पासफà¥à¤°à¥‡à¤œà¤¼ अपडेट करें.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">आपके दà¥à¤µà¤¾à¤°à¤¾ हाल में विज़िट किठगठबà¥à¤•à¤®à¤¾à¤°à¥à¤• यहां दिखाई देंगे.</translation>
<translation id="1821930232296380041">अमानà¥à¤¯ अनà¥à¤°à¥‹à¤§ या अनà¥à¤°à¥‹à¤§ पैरामीटर</translation>
<translation id="1838667051080421715">आप à¤à¤• वेब पृषà¥à¤  का सà¥à¤°à¥‹à¤¤ देख रहे हैं.</translation>
<translation id="1871208020102129563">पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ को फ़िकà¥â€à¤¸à¥â€à¤¡ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सरà¥à¤µà¤° का उपयोग करने के लिठसेट किया गया है, .pac सà¥â€à¤•à¥à¤°à¤¿à¤ªà¥â€à¤Ÿ फ़ाइल का उपयोग करने के लिठनहीं.</translation>
<translation id="1883255238294161206">सूà¤à¥€ संकà¥à¤·à¤¿à¤ªà¥à¤¤ करें</translation>
<translation id="1898423065542865115">à¥à¤¿à¤²à¥à¤Ÿà¤° किया जा रहा है</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> ने आपका लॉगिन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सà¥à¤µà¥€à¤•à¤¾à¤° नहीं किया या हो सकता है कि आपके लॉगिन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय सीमा समापà¥à¤¤ हो गई हो.</translation>
<translation id="194030505837763158"><ph name="LINK" /> पर जाà¤à¤‚</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="1973335181906896915">कà¥à¤°à¤®à¤¬à¤¦à¥à¤§ करने में तà¥à¤°à¥à¤Ÿà¤¿</translation>
<translation id="1974060860693918893">उनà¥à¤¨à¤¤</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{और 1 अधिक}one{और # अधिक}other{और # अधिक}}</translation>
<translation id="2025186561304664664">पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सà¥â€à¤µà¤¤: कॉनà¥â€à¤«à¤¼â€à¤¿à¤—र पर सेट है.</translation>
<translation id="2030481566774242610">कà¥à¤¯à¤¾ आप मतलब <ph name="LINK" /> से है?</translation>
<translation id="2031925387125903299">आपको यह संदेश इसलिठदिखाई दे रहा है कà¥à¤¯à¥‹à¤‚कि किसी नई साइट पर आपके पहली बार जाने से पहले आपके अभिभावकों को उसे सà¥à¤µà¥€à¤•à¥ƒà¤¤à¤¿ देनी होगी.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ और फायरवॉल की जांठकरें<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ज़िप कोड</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 सà¥à¤à¤¾à¤µ}one{# सà¥à¤à¤¾à¤µ}other{# सà¥à¤à¤¾à¤µ}}</translation>
<translation id="2065985942032347596">पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£ आवशà¥à¤¯à¤•</translation>
<translation id="2079545284768500474">पूरà¥à¤µà¤µà¤¤à¥ करें</translation>
<translation id="20817612488360358">सिसà¥â€à¤Ÿà¤® पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सेटिंग उपयोग किठजाने के लिठसेट हैं लेकिन कोई सà¥à¤ªà¤·à¥â€à¤Ÿ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ कॉनà¥à¥à¤¿à¤—रेशन भी निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ है.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">बà¥à¤•à¤®à¤¾à¤°à¥à¤• संपादित करें</translation>
<translation id="2166049586286450108">पूरà¥à¤£ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤•à¥€à¤¯ à¤à¤•à¥à¤¸à¥‡à¤¸</translation>
<translation id="2166378884831602661">यह साइट सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥à¤¶à¤¨ पà¥à¤°à¤¦à¤¾à¤¨ नहीं कर सकती</translation>
-<translation id="2171101176734966184">आपने <ph name="DOMAIN" /> तक पहà¥à¤‚à¤à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ किया, लेकिन सरà¥à¤µà¤° ने कमज़ोर हसà¥à¤¤à¤¾à¤•à¥à¤·à¤° à¤à¤²à¥â€à¤—ोरिदम का उपयोग करते हà¥à¤ हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°à¤¿à¤¤ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किया. इसका अरà¥à¤¥ यह है कि सरà¥à¤µà¤° दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किठगठसà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤¿à¤•à¤¤à¤¾ नकली हो सकते हैं, और हो सकता है कि सरà¥à¤µà¤° आपका अपेकà¥à¤·à¤¿à¤¤ सरà¥à¤µà¤° न हो (हो सकता है कि आप किसी हमलावर से बातà¤à¥€à¤¤ कर रहे हों).</translation>
<translation id="2181821976797666341">नीतियां</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 पता}one{# पते}other{# पते}}</translation>
<translation id="2212735316055980242">नीति नहीं मिली</translation>
<translation id="2213606439339815911">पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ फ़ेठकी जा रही हैं...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> उपलबà¥à¤§ नहीं है</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />निदान à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨<ph name="END_LINK" /> का उपयोग करके अपने कनेकà¥à¤¶à¤¨ को ठीक करें</translation>
+<translation id="2239100178324503013">अभी भेजें</translation>
<translation id="225207911366869382">यह मान इस नीति के लिठहटा दिया गया है.</translation>
<translation id="2262243747453050782">HTTP तà¥à¤°à¥à¤Ÿà¤¿</translation>
<translation id="2282872951544483773">अनà¥à¤ªà¤²à¤¬à¥à¤§ पà¥à¤°à¤¯à¥‹à¤—</translation>
<translation id="2292556288342944218">आपका इंटरनेट कनेकà¥à¤¶à¤¨ अवरà¥à¤¦à¥à¤§ है</translation>
<translation id="229702904922032456">किसी रूट या मधà¥à¤¯à¤µà¤°à¥à¤¤à¥€ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की अवधि समापà¥à¤¤ हो गई है.</translation>
<translation id="230155334948463882">नया कारà¥à¤¡?</translation>
+<translation id="2305919008529760154">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; हो सकता है कि उसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कपटपूरà¥à¤µà¤• जारी किया गया हो. à¤à¤¸à¤¾ किसी गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> के लिठउपयोगकरà¥à¤¤à¤¾ नाम और पासवरà¥à¤¡ आवशà¥à¤¯à¤• है.</translation>
+<translation id="2318774815570432836">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते कà¥à¤¯à¥‹à¤‚कि वेबसाइट HSTS का उपयोग करती है. नेटवरà¥à¤• की गड़बड़ियां और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: यह पृषà¥à¤  बाद में काम करेगा. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155"><ph name="ENTRY_INDEX" /> अनà¥à¤•à¥à¤°à¤®à¤£à¤¿à¤•à¤¾ पर अमानà¥à¤¯ बà¥à¤•à¤®à¤¾à¤°à¥à¤• को अनदेखा किया गया</translation>
<translation id="2354001756790975382">अनà¥à¤¯ बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="2359808026110333948">जारी रखें</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" /> पर कैपà¥à¤à¤° की गई ख़राबी रिपोरà¥à¤Ÿ अपलोड नहीं की गई</translation>
<translation id="2367567093518048410">सà¥à¤¤à¤°</translation>
+<translation id="2371153335857947666">{1,plural, =1{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय सीमा कल ही समापà¥à¤¤ हà¥à¤ˆ है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. आपके कंपà¥à¤¯à¥‚टर की घड़ी वरà¥à¤¤à¤®à¤¾à¤¨ में <ph name="CURRENT_DATE" /> पर सेट है. कà¥â€à¤¯à¤¾ वह सही है? यदि नहीं, तो आपको अपने सिसà¥à¤Ÿà¤® की घड़ी सही करनी à¤à¤¾à¤¹à¤¿à¤ और इस पृषà¥à¤  को रीफà¥à¤°à¥‡à¤¶ करना à¤à¤¾à¤¹à¤¿à¤. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.}one{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय सीमा # दिन पहले समापà¥à¤¤ हà¥à¤ˆ है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. आपके कंपà¥à¤¯à¥‚टर की घड़ी वरà¥à¤¤à¤®à¤¾à¤¨ में <ph name="CURRENT_DATE" /> पर सेट है. कà¥â€à¤¯à¤¾ वह सही है? यदि नहीं, तो आपको अपने सिसà¥à¤Ÿà¤® की घड़ी सही करनी à¤à¤¾à¤¹à¤¿à¤ और इस पृषà¥à¤  को रीफà¥à¤°à¥‡à¤¶ करना à¤à¤¾à¤¹à¤¿à¤. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.}other{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय सीमा # दिन पहले समापà¥à¤¤ हà¥à¤ˆ है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. आपके कंपà¥à¤¯à¥‚टर की घड़ी वरà¥à¤¤à¤®à¤¾à¤¨ में <ph name="CURRENT_DATE" /> पर सेट है. कà¥â€à¤¯à¤¾ वह सही है? यदि नहीं, तो आपको अपने सिसà¥à¤Ÿà¤® की घड़ी सही करनी à¤à¤¾à¤¹à¤¿à¤ और इस पृषà¥à¤  को रीफà¥à¤°à¥‡à¤¶ करना à¤à¤¾à¤¹à¤¿à¤. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">कोई UI विकलà¥à¤ª उपलबà¥à¤§ नहीं है</translation>
<translation id="2384307209577226199">à¤à¤‚टरपà¥à¤°à¤¾à¤‡à¤œà¤¼ डिà¥à¥‰à¤²à¥à¤Ÿ</translation>
-<translation id="238526402387145295">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते कà¥à¤¯à¥‹à¤‚कि वेबसाइट <ph name="BEGIN_LINK" />HSTS का उपयोग करती है<ph name="END_LINK" />. नेटवरà¥à¤• की तà¥à¤°à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: पृषà¥à¤  बाद में काम करेगा.</translation>
<translation id="2386255080630008482">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ कर दिया गया है.</translation>
<translation id="2392959068659972793">कोई भी मान सेट नहीं की गई नीतियां दिखाà¤à¤‚</translation>
<translation id="2396249848217231973">&amp;हटाना वापस लाà¤à¤‚</translation>
-<translation id="2413528052993050574">यह सरà¥à¤µà¤° यह पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" />; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ कर दिया गया है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="2455981314101692989">इस वेब पृषà¥â€à¤  पर इस फ़ॉरà¥à¤® को सà¥â€à¤µà¤¤: भरना अकà¥à¤·à¤® किया गया है.</translation>
+<translation id="2463739503403862330">भरें</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />नेटवरà¥à¤• निदान à¤à¤²à¤¾à¤•à¤° देखें<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">अमानà¥â€à¤¯ खोज URL.</translation>
<translation id="2491120439723279231">सरà¥à¤µà¤° के पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° में तà¥à¤°à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ हैं.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">सबमिट करें</translation>
<translation id="2674170444375937751">कà¥à¤¯à¤¾ आप वाकई अपने इतिहास से इन पृषà¥à¤ à¥‹à¤‚ को हटाना à¤à¤¾à¤¹à¤¤à¥‡ हैं?</translation>
<translation id="2677748264148917807">छोड़ें</translation>
+<translation id="269990154133806163">सरà¥à¤µà¤° ने à¤à¤¸à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किया है जिसे पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पारदरà¥à¤¶à¤¿à¤¤à¤¾ नीति का उपयोग करके सारà¥à¤µà¤œà¤¨à¤¿à¤• रूप से पà¥à¤°à¤•à¤Ÿ नहीं किया गया था. कà¥à¤› पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‹à¤‚ के लिठयह सà¥à¤¨à¤¿à¤¶à¥à¤à¤¿à¤¤ करना आवशà¥à¤¯à¤• है कि वे विशà¥à¤µà¤¸à¤¨à¥€à¤¯ हैं और हमलावरों से सà¥à¤°à¤•à¥à¤·à¤¾ करते हैं. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">मान का पà¥à¤°à¤¾à¤°à¥‚प से मिलान नहीं होता.</translation>
<translation id="2704951214193499422">कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® इस समय आपके कारà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ नहीं कर सका. कृपया बाद में पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
<translation id="2705137772291741111">इस साइट की सहेजी गई (संà¤à¤¿à¤¤) कॉपी पढ़ने योगà¥à¤¯ नहीं थी.</translation>
<translation id="2709516037105925701">ऑटोमैटिक भरना</translation>
+<translation id="2712118517637785082">आपने <ph name="DOMAIN" /> पर पहà¥à¤‚à¤à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ किया, लेकिन सरà¥à¤µà¤° दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किठगठपà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° को उसके जारीकरà¥à¤¤à¤¾ ने निरसà¥à¤¤ कर दिया है. इसका अरà¥à¤¥ है कि सरà¥à¤µà¤° दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ सà¥à¤°à¤•à¥à¤·à¤¾ कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल पर बिलà¥à¤•à¥à¤² भी विशà¥à¤µà¤¾à¤¸ नहीं किया जाना à¤à¤¾à¤¹à¤¿à¤. हो सकता है आप किसी हमलावर से बातà¤à¥€à¤¤ कर रहे हों. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">अनà¥à¤®à¤¤à¤¿ मांगें</translation>
<translation id="2721148159707890343">अनà¥à¤°à¥‹à¤§ सफल रहा</translation>
<translation id="2728127805433021124">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° à¤à¤• कमज़ोर हसà¥à¤¤à¤¾à¤•à¥à¤·à¤° à¤à¤²à¥à¤—ोरिदम का उपयोग करके हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°à¤¿à¤¤ किया गया है.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">पता और खोज बार</translation>
<translation id="2826760142808435982">कनेकà¥à¤¶à¤¨ को <ph name="CIPHER" /> का उपयोग करके à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ और पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ किया गया है और यह कà¥à¤‚जी विनिमय तकनीक के रूप में <ph name="KX" /> का उपयोग करता है.</translation>
<translation id="2835170189407361413">à¥à¥‰à¤°à¥à¤® साॠकरें</translation>
-<translation id="2837049386027881519">TLS या SSL पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤² के किसी पà¥à¤°à¤¾à¤¨à¥‡ वरà¥à¤¶à¤¨ का उपयोग करके कनेकà¥à¤¶à¤¨ का फिर से पà¥à¤°à¤¯à¤¾à¤¸ किया जाना à¤à¤¾à¤¹à¤¿à¤ था. आमतौर पर इसका अरà¥à¤¥ है कि सरà¥à¤µà¤° बहà¥à¤¤ पà¥à¤°à¤¾à¤¨à¥‡ सॉफ़à¥à¤Ÿà¤µà¥‡à¤¯à¤° का उपयोग कर रहा है और उसमें अनà¥à¤¯ सà¥à¤°à¤•à¥à¤·à¤¾ समसà¥à¤¯à¤¾à¤à¤‚ हो सकती हैं.</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> पर सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° फरà¥à¤œà¥€ दिखाई देता है.</translation>
<translation id="2889159643044928134">पà¥à¤¨: लोड ना करें</translation>
-<translation id="2896499918916051536">यह पà¥à¤²à¤— इन समरà¥à¤¥à¤¿à¤¤ नहीं है.</translation>
+<translation id="2900469785430194048">यह वेबपृषà¥à¤  दिखाते समय Google Chrome में जगह नहीं बà¤à¥€.</translation>
<translation id="2909946352844186028">नेटवरà¥à¤• में बदलाव का पता à¤à¤²à¤¾.</translation>
-<translation id="2915500479781995473">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि वह <ph name="DOMAIN" /> है; उसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° समापà¥à¤¤ हो गया था. à¤à¤¸à¤¾ गलत कॉनà¥à¥à¤¿à¤—रेशन या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपका कनेकà¥à¤¶à¤¨ अवरोधित करने के कारण हो सकता है. अभी आपके कंपà¥à¤¯à¥‚टर की घड़ी <ph name="CURRENT_TIME" /> पर सेट है. कà¥à¤¯à¤¾ यह सही लग रहा है? यदि नहीं, तो आपको अपने सिसà¥à¤Ÿà¤® की घड़ी सही करनी à¤à¤¾à¤¹à¤¿à¤ और फिर इस पृषà¥à¤  को रीफà¥à¤°à¥‡à¤¶ करना à¤à¤¾à¤¹à¤¿à¤.</translation>
<translation id="2922350208395188000">सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की जांठनहीं की जा सकती.</translation>
-<translation id="2941952326391522266">यह सरà¥à¤µà¤° यह पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° <ph name="DOMAIN2" /> की ओर से है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="2948083400971632585">आप किसी कनेकà¥à¤¶à¤¨ के लिठकॉनà¥à¤«à¤¼à¤¿à¤—र की गई किसी भी पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ को सेटिंग पृषà¥à¤  से अकà¥à¤·à¤® कर सकते हैं.</translation>
<translation id="2955913368246107853">खोज बार बंद करें</translation>
<translation id="2958431318199492670">नेटवरà¥à¤• कॉनà¥à¤«à¤¼à¤¿à¤—रेशन ONC मानक का पालन नहीं करता. कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कà¥à¤› भाग आयात नहीं किठजा सकते हैं.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">गलत नीति पà¥à¤°à¤•à¤¾à¤°</translation>
<translation id="3032412215588512954">कà¥à¤¯à¤¾ आप इस साइट को फिर से लोड करना à¤à¤¾à¤¹à¤¤à¥‡ हैं?</translation>
<translation id="3037605927509011580">हे भगवान!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{समनà¥à¤µà¤¯à¤¿à¤¤ डिवाइस पर कम से कम 1 आइटम}=1{1 आइटम (समनà¥à¤µà¤¯à¤¿à¤¤ डिवाइस पर और भी)}one{# आइटम (समनà¥à¤µà¤¯à¤¿à¤¤ डिवाइस पर और भी)}other{# आइटम (समनà¥à¤µà¤¯à¤¿à¤¤ डिवाइस पर और भी)}}</translation>
<translation id="3041612393474885105">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° जानकारी</translation>
<translation id="3063697135517575841">Chrome इस समय आपके कारà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ नहीं कर सका. कृपया बाद में पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
<translation id="3093245981617870298">आप ऑफ़लाइन हैं.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">नवीनतम</translation>
<translation id="3207960819495026254">बà¥à¤•à¤®à¤¾à¤°à¥à¤• किया गया</translation>
-<translation id="3225919329040284222">सरà¥à¤µà¤° दà¥à¤µà¤¾à¤°à¤¾ कोई पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥â€à¤¤à¥à¤¤ किया गया, जो बिलà¥â€à¤Ÿ-इन अपेकà¥à¤·à¤¾à¤“ं से मिलान नहीं करता. इन अपेकà¥à¤·à¤¾à¤“ं को आपकी सà¥à¤°à¤•à¥à¤·à¤¾ करने के लिठकà¥à¤›, उà¤à¥â€à¤-सà¥à¤°à¤•à¥à¤·à¤¾ वेबसाइटों के लिठशामिल किया गया है.</translation>
<translation id="3226128629678568754">पृषà¥à¤  को लोड करने के लिठआवशà¥à¤¯à¤• डेटा पà¥à¤¨: सबमिट करने के लिठपà¥à¤¨: लोड करें बटन दबाà¤à¤‚.</translation>
<translation id="3228969707346345236">अनà¥à¤µà¤¾à¤¦ विफल हो गया कà¥à¤¯à¥‹à¤‚कि पृषà¥à¤  पहले से ही <ph name="LANGUAGE" /> में है.</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" /> का CVC डालें.</translation>
<translation id="3254409185687681395">इस पृषà¥à¤  को बà¥à¤•à¤®à¤¾à¤°à¥à¤• करें</translation>
<translation id="3270847123878663523">&amp;पà¥à¤¨: कà¥à¤°à¤®à¤¿à¤¤ करना वापस लाà¤à¤‚</translation>
<translation id="3286538390144397061">अभी फिर से पà¥à¤°à¤¾à¤°à¤‚भ करें</translation>
+<translation id="3303855915957856445">कोई खोज परिणाम नहीं मिला</translation>
<translation id="3305707030755673451">आपका डेटा आपके समनà¥à¤µà¤¯à¤¨ पासà¥à¥à¤°à¥‡à¥› के साथ <ph name="TIME" /> को à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ किया गया था. समनà¥à¤µà¤¯à¤¨ शà¥à¤°à¥‚ करने के लिठइसे डालें.</translation>
<translation id="333371639341676808">इस पृषà¥à¤  को अतिरिकà¥à¤¤ बà¥à¤²à¥‰à¤— बनाने से रोकें.</translation>
+<translation id="3338095232262050444">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤</translation>
<translation id="3340978935015468852">सेटिंग</translation>
<translation id="3345135638360864351">इस साइट को à¤à¤•à¥â€à¤¸à¥‡à¤¸ करने का आपका अनà¥à¤°à¥‹à¤§ <ph name="NAME" /> को नहीं भेजा जा सका. कृपया पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
<translation id="3355823806454867987">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सेटिंग बदलें...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">पà¥à¤°à¤¾à¤ªà¥à¤¤à¤¿ अंतराल:</translation>
<translation id="3462200631372590220">उनà¥à¤¨à¤¤ को छिपाà¤à¤‚</translation>
<translation id="3479539252931486093">कà¥à¤¯à¤¾ यह अनपेकà¥à¤·à¤¿à¤¤ था? <ph name="BEGIN_LINK" />हमें बताà¤à¤‚<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">अभी नहीं</translation>
<translation id="348000606199325318">कà¥à¤°à¥ˆà¤¶ आईडी <ph name="CRASH_LOCAL_ID" /> (सरà¥à¤µà¤° आईडी: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">हम इस समय आपके अभिभावक तक नहीं पहà¥à¤‚ठपा रहे हैं. कृपया पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
<translation id="3527085408025491307">फ़ोलà¥à¤¡à¤°</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">इसके लिठपासवरà¥à¤¡ का उपयोग करें:</translation>
<translation id="3549644494707163724">सभी समनà¥à¤µà¤¯à¤¿à¤¤ डेटा को अपने सà¥à¤µà¤¯à¤‚ के समनà¥à¤µà¤¯à¤¨ पासफ़à¥à¤°à¥‡à¤œà¤¼ के साथ à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ करें</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> अधिक...</translation>
+<translation id="3555561725129903880">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; उसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° <ph name="DOMAIN2" /> का है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">आपका कनेकà¥à¤¶à¤¨ निजी नहीं है</translation>
<translation id="3583757800736429874">&amp;ले जाना फिर से करें</translation>
<translation id="3586931643579894722">विवरण छà¥à¤ªà¤¾à¤à¤‚</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">मान दिखाà¤à¤‚</translation>
<translation id="3630155396527302611">यदि वह नेटवरà¥à¤• à¤à¤•à¥à¤¸à¥‡à¤¸ करने की अनà¥à¤®à¤¤à¤¿ पà¥à¤°à¤¾à¤ªà¥à¤¤ पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® के रूप में पहले से सूà¤à¥€à¤¬à¤¦à¥à¤§ है, तो
उसे सूà¤à¥€ से निकालें और पà¥à¤¨: जोड़कर देखें.</translation>
+<translation id="3638794133396384728">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; उसके पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय सीमा समापà¥à¤¤ हो गई है. à¤à¤¸à¤¾ किसी गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है. आपके कंपà¥à¤¯à¥‚टर की घड़ी अभी <ph name="CURRENT_TIME" /> पर सेट है. कà¥à¤¯à¤¾ वह सही है? यदि नहीं, तो आपको अपने सिसà¥à¤Ÿà¤® की घड़ी सही करनी à¤à¤¾à¤¹à¤¿à¤ और यह पृषà¥à¤  रीफà¥à¤°à¥‡à¤¶ करना à¤à¤¾à¤¹à¤¿à¤. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">ये पà¥à¤°à¤¾à¤¯à¥‹à¤—िक विशेषताà¤à¤‚ किसी भी समय बदल, अनिरंतर या गायब हो सकती हैं. हम इस बात की कोई भी गारंटी नहीं दे सकते कि आपके दà¥à¤µà¤¾à¤°à¤¾ इनमें से किसी भी पà¥à¤°à¤¯à¥‹à¤— को à¤à¤¾à¤²à¥‚ करने पर कà¥à¤¯à¤¾ हो सकता है, और यहां तक कि आपका बà¥à¤°à¤¾à¤‰à¥›à¤° नषà¥à¤Ÿ भी हो सकता है. मज़ाक छोड़ें, आपका बà¥à¤°à¤¾à¤‰à¥›à¤° आपका पूरा डेटा हटा सकता है, या आपकी सà¥à¤°à¤•à¥à¤·à¤¾ और निजता अपà¥à¤°à¤¤à¥à¤¯à¤¾à¤¶à¤¿à¤¤ रूप से ख़तरे में पड़ सकती है. आपके दà¥à¤µà¤¾à¤°à¤¾ सकà¥à¤·à¤® किठगठकोई भी पà¥à¤°à¤¯à¥‹à¤— इस बà¥à¤°à¤¾à¤‰à¥›à¤° के सभी उपयोगकरà¥à¤¤à¤¾à¤“ं के लिठसकà¥à¤·à¤® होंगे. कृपया सावधानी से आगे बà¥à¥‡à¤‚.</translation>
<translation id="3650584904733503804">मानà¥à¤¯à¤•à¤°à¤£ सफल</translation>
<translation id="3655670868607891010">यदि आपको यह बार-बार दिखाई दे रहा हो, तो इन <ph name="HELP_LINK" /> को आज़माà¤à¤‚.</translation>
<translation id="3658742229777143148">पà¥à¤¨à¤°à¥€à¤•à¥à¤·à¤£</translation>
+<translation id="3678029195006412963">अनà¥à¤°à¥‹à¤§ पर हसà¥à¤¤à¤¾à¤•à¥à¤·à¤° नहीं किया जा सका</translation>
<translation id="3681007416295224113">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° जानकारी</translation>
<translation id="3693415264595406141">पासवरà¥à¤¡:</translation>
+<translation id="3696411085566228381">कोई नहीं</translation>
<translation id="3700528541715530410">ओह, à¤à¤¸à¤¾ लगता है कि आपको इस पृषà¥à¤  को à¤à¤•à¥à¤¸à¥‡à¤¸ करने की अनà¥à¤®à¤¤à¤¿ नहीं है.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">लोड हो रहा है...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">मोबाइल डेटा या वाई-à¥à¤¾à¤ˆ à¤à¤¾à¤²à¥‚ करें</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€, फायरवॉल और DNS कॉनà¥à¥à¤¿à¤—रेशन की जांठकरें<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">काॅपी किया गया लिंक</translation>
-<translation id="3744899669254331632">आप इस समय <ph name="SITE" /> पर नहीं जा सकते कà¥â€à¤¯à¥‹à¤‚कि वेबसाइट ने à¤à¤¸à¥€ अवà¥â€à¤¯à¤µà¤¸à¥â€à¤¥à¤¿à¤¤ पà¥à¤°à¤®à¤¾à¤£à¤¿à¤•à¤¤à¤¾à¤à¤‚ भेजी थीं जिनà¥â€à¤¹à¥‡à¤‚ कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® संसाधित नहीं कर सकता. नेटवरà¥à¤• की तà¥à¤°à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ और हमले आमतौर पर असà¥â€à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: यह पृषà¥â€à¤  बाद में काम करेगा.</translation>
<translation id="375403751935624634">सरà¥à¤µà¤° तà¥à¤°à¥à¤Ÿà¤¿ के कारण अनà¥à¤µà¤¾à¤¦ विफल.</translation>
<translation id="3759461132968374835">आपके पास हाल ही में रिपोरà¥à¤Ÿ किठगठकà¥à¤°à¥ˆà¤¶ नहीं हैं. कà¥à¤°à¥ˆà¤¶ रिपोरà¥à¤Ÿà¤¿à¤‚ग अकà¥à¤·à¤® होने के दौरान होने वाले कà¥à¤°à¥ˆà¤¶ यहां दिखाई नहीं देंगे.</translation>
<translation id="3788090790273268753">इस साइट के लिठपà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय-सीमा 2016 में समापà¥à¤¤ होगी और पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की शà¥à¤°à¥ƒà¤‚खला में, SHA-1 का उपयोग करके हसà¥à¤¤à¤¾à¤•à¥à¤·à¤° किया गया पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° शामिल है.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">विरोधाभासी डिवाइस पहà¤à¤¾à¤¨à¤•à¤°à¥à¤¤à¤¾</translation>
<translation id="3885155851504623709">पैरिश</translation>
<translation id="3901925938762663762">इस कारà¥à¤¡ की समय सीमा समापà¥â€à¤¤ हो गई है</translation>
+<translation id="3910267023907260648">आपने <ph name="DOMAIN" /> पर पहà¥à¤‚à¤à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ किया, लेकिन सरà¥à¤µà¤° ने कमज़ोर हसà¥à¤¤à¤¾à¤•à¥à¤·à¤° à¤à¤²à¥à¤—ोरिदम के उपयोग से हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°à¤¿à¤¤ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किया. इसका अरà¥à¤¥ है कि सरà¥à¤µà¤° दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ सà¥à¤°à¤•à¥à¤·à¤¾ कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल नकली हो सकते हैं और हो सकता है कि सरà¥à¤µà¤° आपका अपेकà¥à¤·à¤¿à¤¤ सरà¥à¤µà¤° ना हो (हो सकता है आप किसी हमलावर से बातà¤à¥€à¤¤ कर रहे हों). <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° संभवत: कल से मानà¥à¤¯ हो. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.}one{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° संभवत: # दिन बाद से मानà¥à¤¯ हो. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.}other{यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° संभवत: # दिन बाद से मानà¥à¤¯ हो. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF दसà¥à¤¤à¤¾à¤µà¥‡à¥› लोड करने में विफल</translation>
<translation id="3963721102035795474">रीडर मोड</translation>
+<translation id="397105322502079400">गणना की जा रही है...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> अवरà¥à¤¦à¥à¤§ है</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{आस-पास 1 वेब पृषà¥à¤  है}one{आस-पास # वेब पृषà¥à¤  हैं}other{आस-पास # वेब पृषà¥à¤  हैं}}</translation>
<translation id="4021036232240155012">DNS à¤à¤• नेटवरà¥à¤• सेवा है जो किसी वेबसाइट के नाम को उसके इंटरनेट पते में बदलती है.</translation>
<translation id="4030383055268325496">&amp;जोड़ना वापस लाà¤à¤‚</translation>
-<translation id="4032534284272647190"><ph name="URL" /> पर पहà¥à¤‚ठअसà¥à¤µà¥€à¤•à¥ƒà¤¤.</translation>
<translation id="404928562651467259">à¤à¥‡à¤¤à¤¾à¤µà¤¨à¥€</translation>
<translation id="4058922952496707368">कà¥à¤‚जी "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">कà¥à¤²à¤¾à¤‡à¤‚ट और सरà¥à¤µà¤°, सामानà¥à¤¯ SSL पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤² वरà¥à¤¶à¤¨ या सिफ़र सà¥à¤‡à¤Ÿ का समरà¥à¤¥à¤¨ नहीं करते हैं.</translation>
<translation id="4079302484614802869">पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ कॉनà¥â€à¤«à¤¼à¤¿à¤—रेशन को .pac सà¥â€à¤•à¥à¤°à¤¿à¤ªà¥â€à¤Ÿ URL का उपयोग करने के लिठसेट किया जाता है, फ़िकà¥â€à¤¸à¥â€à¤¡ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सरà¥à¤µà¤° के लिठनहीं.</translation>
<translation id="4103249731201008433">डिवाइस की कà¥à¤°à¤® संखà¥à¤¯à¤¾ अमानà¥à¤¯ है</translation>
<translation id="4103763322291513355">काली सूà¤à¥€ में डाले गठURL तथा आपके सिसà¥à¤Ÿà¤® वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤• दà¥à¤µà¤¾à¤°à¤¾ लागू की गई अनà¥à¤¯ नीतियों को देखने के लिठ&lt;strong&gt;chrome://policy&lt;/strong&gt; पर जाà¤à¤‚.</translation>
+<translation id="4110615724604346410">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° में गड़बड़ियां हैं. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">नीति कà¥à¤·à¥‡à¤¤à¥à¤° समरà¥à¤¥à¤¿à¤¤ नहीं है.</translation>
+<translation id="4118212371799607889">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 अनà¥à¤¯}one{# अनà¥â€à¤¯}other{# अनà¥â€à¤¯}}</translation>
<translation id="4130226655945681476">नेटवरà¥à¤• केबल, मोडेम और राउटर की जांठकरें</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">कà¥à¤¯à¤¾ आप à¤à¤¾à¤¹à¤¤à¥‡ हैं कि कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® इस कारà¥à¤¡ को सहेजे?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">अकà¥à¤·à¤®</translation>
<translation id="4196861286325780578">&amp;ले जाना फिर से करें</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />फायरवॉल और à¤à¤‚टीवायरस कॉनà¥à¥à¤¿à¤—रेशन की जांठकरें<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{कोई नहीं}=1{1 à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ ($1)}=2{2 à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ ($1, $2)}one{# à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ ($1, $2, $3)}other{# à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">कà¥à¤°à¥ˆà¤¶</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />नेटवरà¥à¤• निदान à¤à¤²à¤¾à¤•à¤° देखें<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">नहीं</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(कोई उपयोगकरà¥à¤¤à¤¾ नाम नहीं)</translation>
<translation id="4300246636397505754">अभिभावक सà¥à¤à¤¾à¤µ</translation>
<translation id="4304224509867189079">पà¥à¤°à¤µà¥‡à¤¶ करें</translation>
+<translation id="432290197980158659">सरà¥à¤µà¤° ने à¤à¤¸à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किया जिसका मिलान अंतरà¥à¤¨à¤¿à¤¹à¤¿à¤¤ अपेकà¥à¤·à¤¾à¤“ं से नहीं होता. आपकी सà¥à¤°à¤•à¥à¤·à¤¾ करने के लिà¤, ये अपेकà¥à¤·à¤¾à¤à¤‚ कà¥à¤› निशà¥à¤à¤¿à¤¤, उà¤à¥à¤-सà¥à¤°à¤•à¥à¤·à¤¾ वेबसाइट के लिठशामिल की गई हैं. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">लेख ढूंà¥à¤¨à¥‡ में विफल</translation>
+<translation id="4331708818696583467">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है</translation>
<translation id="4372948949327679948">अपेकà¥à¤·à¤¿à¤¤ <ph name="VALUE_TYPE" /> मान.</translation>
-<translation id="4377125064752653719">आपने <ph name="DOMAIN" /> तक पहà¥à¤‚à¤à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ किया, लेकिन सरà¥à¤µà¤° दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° को उसके जारीकरà¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ रदà¥à¤¦ कर दिया गया है. इसका अरà¥à¤¥ है कि सरà¥à¤µà¤° दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤¿à¤•à¤¤à¤¾ पर पूरà¥à¤£à¤¤à¤¯à¤¾ विशà¥à¤µà¤¾à¤¸ नहीं करना à¤à¤¾à¤¹à¤¿à¤. हो सकता है कि आप किसी हमलावर से बातà¤à¥€à¤¤ कर रहे हों.</translation>
<translation id="4381091992796011497">उपयोगकरà¥à¤¤à¤¾ नाम:</translation>
<translation id="4394049700291259645">अकà¥à¤·à¤® करें</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> से <ph name="END_DATE" /> तक</translation>
<translation id="4406896451731180161">खोज परिणाम</translation>
-<translation id="4424024547088906515">यह सरà¥à¤µà¤° यह नहीं पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° Chrome दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¥à¤¿à¤—रेशन या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> ने आपका लॉगिन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सà¥à¤µà¥€à¤•à¤¾à¤° नहीं किया है या हो सकता है कि पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° उपलबà¥à¤§ नहीं कराया गया हो.</translation>
<translation id="443673843213245140">पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ का उपयोग अकà¥à¤·à¤® है लेकिन कोई सà¥â€à¤ªà¤·à¥à¤Ÿ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ कॉनà¥à¥à¤¿à¤—रेशन निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ किया गया है.</translation>
<translation id="4458874409874303848">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ साइट</translation>
<translation id="4461847750548395463">आपको यह संदेश इसलिठदिखाई दे रहा है कà¥à¤¯à¥‹à¤‚कि Google सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ साइट सकà¥à¤·à¤® है.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">विवरण</translation>
<translation id="4558551763791394412">अपने à¤à¤•à¥à¤¸à¤Ÿà¥‡à¤‚शन अकà¥à¤·à¤® करके देखें.</translation>
<translation id="4587425331216688090">Chrome से पता निकालें?</translation>
+<translation id="4589078953350245614">आपने <ph name="DOMAIN" /> में पहà¥à¤‚à¤à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ किया, लेकिन सरà¥à¤µà¤° ने अमानà¥à¤¯ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किया. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459"><ph name="DOMAIN" /> से आपके कनेकà¥à¤¶à¤¨ को किसी आधà¥à¤¨à¤¿à¤• सिà¥à¤° सà¥à¤‡à¤Ÿ का उपयोग करके à¤à¤¨à¥â€à¤•à¥à¤°à¤¿à¤ªà¥â€à¤Ÿ किया गया है.</translation>
<translation id="4594403342090139922">&amp;हटाना वापस लाà¤à¤‚</translation>
+<translation id="4627442949885028695">किसी अनà¥à¤¯ डिवाइस से जारी रखें</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">आप à¤à¤• à¤à¤•à¥à¤¸à¤Ÿà¥‡à¤‚शन पृषà¥à¤  देख रहे हैं.</translation>
-<translation id="467662567472608290">यह सरà¥à¤µà¤° यह पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° में तà¥à¤°à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ हैं. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> को अवरोधित किया गया था</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">आपका कनेकà¥à¤¶à¤¨ बाधित था</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows नेटवरà¥à¤• निदान à¤à¤²à¤¾à¤•à¤° देखें<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">पà¥à¤²à¥‡à¤Ÿà¤«à¤¼à¥‰à¤°à¥à¤®</translation>
<translation id="4744603770635761495">निषà¥à¤ªà¤¾à¤¦à¤¨-योगà¥à¤¯ पथ</translation>
<translation id="4756388243121344051">&amp;इतिहास</translation>
+<translation id="4759238208242260848">डाउनलोड</translation>
<translation id="4764776831041365478"><ph name="URL" /> पर मौजूद वेबपृषà¥à¤  संभवतः असà¥à¤¥à¤¾à¤¯à¥€ रूप से बंद है या उसे सà¥à¤¥à¤¾à¤¯à¥€ रूप से किसी नठवेब पते पर ले जाया गया है.</translation>
<translation id="4771973620359291008">अजà¥à¤à¤¾à¤¤ तà¥à¤°à¥à¤Ÿà¤¿ आई.</translation>
<translation id="4782449893814226250">आपने अपने अभिभावकों से पूछा था कि इस पृषà¥â€à¤  पर जाना ठीक है या नहीं.</translation>
<translation id="4800132727771399293">अपना अवधि समापà¥â€à¤¤à¤¿ दिनांक और CVC जांà¤à¥‡à¤‚ और पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें</translation>
-<translation id="4807049035289105102">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते हैं कà¥à¤¯à¥‹à¤‚कि वेबसाइट ने à¤à¤¸à¥‡ अवà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल भेजे हैं जिनà¥à¤¹à¥‡à¤‚ Google Chrome संसाधित नहीं कर सकता. नेटवरà¥à¤• की तà¥à¤°à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: यह पृषà¥à¤  बाद में काम करेगा.</translation>
<translation id="4813512666221746211">नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¤¿</translation>
<translation id="4816492930507672669">पृषà¥à¤  में à¥à¤¿à¤Ÿ करें</translation>
<translation id="4850886885716139402">देखें</translation>
<translation id="4880827082731008257">खोज इतिहास</translation>
+<translation id="4884656795097055129">सही समय पर और अधिक लेख दिखाई देंगे.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{1 और वेब पृषà¥à¤ }one{# और वेब पृषà¥à¤ }other{# और वेब पृषà¥à¤ }}</translation>
<translation id="4923417429809017348">इस पृषà¥à¤  का à¤à¤• अजà¥à¤à¤¾à¤¤ भाषा से <ph name="LANGUAGE_LANGUAGE" /> में अनà¥à¤µà¤¾à¤¦ किया गया है</translation>
<translation id="4926049483395192435">निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ किया जाना à¤à¤¾à¤¹à¤¿à¤.</translation>
<translation id="4930497775425430760">आपको यह संदेश इसलिठदिखाई दे रहा है कà¥à¤¯à¥‹à¤‚कि किसी नई साइट पर आपके पहली बार जाने से पहले आपके अभिभावक को उसे सà¥à¤µà¥€à¤•à¥ƒà¤¤à¤¿ देनी होगी.</translation>
<translation id="495170559598752135">कà¥à¤°à¤¿à¤¯à¤¾à¤à¤‚</translation>
<translation id="4958444002117714549">सूà¤à¥€ विसà¥à¤¤à¥ƒà¤¤ करें</translation>
+<translation id="4962322354953122629">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° Chrome दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911"><ph name="ORIGINAL_LANGUAGE" /> से <ph name="TARGET_LANGUAGE" /> में अनà¥à¤µà¤¾à¤¦ करें?</translation>
+<translation id="4989809363548539747">यह पà¥à¤²à¤— इन समरà¥à¤¥à¤¿à¤¤ नहीं है</translation>
<translation id="5002932099480077015">यदि सकà¥à¤·à¤® किया हà¥à¤† हो, तो Chrome फ़ॉरà¥à¤® को तेज़ी से भरने के लिठइस डिवाइस पर आपके कारà¥à¤¡ की à¤à¤• पà¥à¤°à¤¤à¤¿ संगà¥à¤°à¤¹à¥€à¤¤ करेगा.</translation>
<translation id="5019198164206649151">बैकिंग संगà¥à¤°à¤¹ खराब सà¥à¤¥à¤¿à¤¤à¤¿ में है</translation>
<translation id="5023310440958281426">अपने वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤• की नीतियां देखें</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Google अनà¥à¤µà¤¾à¤¦ के बारे में</translation>
<translation id="5040262127954254034">निजता</translation>
<translation id="5045550434625856497">ग़लत पासवरà¥à¤¡</translation>
+<translation id="5056549851600133418">आपके लिठलेख</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ पते की जांठकरें<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£ पतà¥à¤° इस समय मानà¥à¤¯ नहीं है.</translation>
<translation id="5089810972385038852">राजà¥à¤¯</translation>
-<translation id="5094747076828555589">यह सरà¥à¤µà¤° यह नहीं पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° Chromium दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¥à¤¿à¤—रेशन या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="5095208057601539847">पà¥à¤°à¤¾à¤‚त</translation>
<translation id="5115563688576182185">(64-बिट)</translation>
-<translation id="5122371513570456792">'<ph name="SEARCH_STRING" />' के लिठ<ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> मिले.</translation>
<translation id="5141240743006678641">समनà¥à¤µà¤¯à¤¿à¤¤ पासवरà¥à¤¡ अपने Google पà¥à¤°à¤®à¤¾à¤£à¤¿à¤•à¤¤à¤¾ के साथ à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ करें</translation>
<translation id="5145883236150621069">नीति पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦ में तà¥à¤°à¥à¤Ÿà¤¿ कोड मौजूद है</translation>
<translation id="5171045022955879922">URL खोजें या लिखें</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">बà¥à¤•à¤®à¤¾à¤°à¥à¤• बार</translation>
<translation id="5199729219167945352">पà¥à¤°à¤¯à¥‹à¤—</translation>
<translation id="5251803541071282808">कà¥à¤²à¤¾à¤‰à¤¡</translation>
+<translation id="5277279256032773186">कारà¥à¤¯à¤¸à¥à¤¥à¤² पर Chrome का उपयोग कर रहे हैं? कंपनियां अपने करà¥à¤®à¤à¤¾à¤°à¤¿à¤¯à¥‹à¤‚ के लिठChrome सेटिंग पà¥à¤°à¤¬à¤‚धित कर सकती हैं. और जानें</translation>
<translation id="5299298092464848405">नीति पारà¥à¤¸ करने में तà¥à¤°à¥à¤Ÿà¤¿</translation>
<translation id="5300589172476337783">दिखाà¤à¤‚</translation>
<translation id="5308689395849655368">कà¥à¤°à¥ˆà¤¶ की रिपोरà¥à¤Ÿ करना अकà¥à¤·à¤® कर दिया गया है.</translation>
<translation id="5317780077021120954">सहेजें</translation>
<translation id="5327248766486351172">नाम</translation>
+<translation id="5359637492792381994">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° इस समय मानà¥à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">नीति सेटिंग संगà¥à¤°à¤¹à¥€à¤¤ करने में विफल</translation>
-<translation id="540969355065856584">यह सरà¥à¤µà¤° यह पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£ पतà¥à¤° इस समय मानà¥à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¥à¤¿à¤—रेशन या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="5421136146218899937">बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग डेटा साफ़ करें...</translation>
<translation id="5430298929874300616">बà¥à¤•à¤®à¤¾à¤°à¥à¤• निकालें</translation>
<translation id="5431657950005405462">आपकी à¥à¤¾à¤‡à¤² नहीं मिली</translation>
<translation id="5435775191620395718">इस डिवाइस का इतिहास दिखाया जा रहा है. <ph name="BEGIN_LINK" />अधिक जानें<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">वैयकà¥à¤¤à¤¿à¤•à¥ƒà¤¤ सामगà¥à¤°à¥€ सà¥à¤à¤¾à¤µ वरà¥à¤¤à¤®à¤¾à¤¨ में अकà¥à¤·à¤® हैं, कà¥à¤¯à¥‹à¤‚कि आपका समनà¥à¤µà¤¯à¤¿à¤¤ डेटा किसी कसà¥à¤Ÿà¤® पासफ़à¥à¤°à¥‡à¤œà¤¼ से रकà¥à¤·à¤¿à¤¤ है.</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" पर सà¥à¤•à¥€à¤®à¤¾ सतà¥à¤¯à¤¾à¤ªà¤¨ तà¥à¤°à¥à¤Ÿà¤¿: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">यह <ph name="HOST_NAME" /> पृषà¥à¤  पà¥à¤°à¤¾à¤ªà¥à¤¤ नहीं किया जा सकता</translation>
<translation id="5455374756549232013">खराब नीति टाइमसà¥à¤Ÿà¥ˆà¤®à¥à¤ª</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">कà¥à¤¯à¤¾ आप इस साइट को छोड़ना à¤à¤¾à¤¹à¤¤à¥‡ हैं?</translation>
<translation id="5629630648637658800">नीति सेटिंग लोड करने में विफल</translation>
<translation id="5631439013527180824">अमानà¥à¤¯ डिवाइस पà¥à¤°à¤¬à¤‚धन टोकन</translation>
-<translation id="5650551054760837876">कोई खोज परिणाम नहीं मिले.</translation>
<translation id="5677928146339483299">अवरोधित</translation>
<translation id="5710435578057952990">इस वेबसाइट की पहà¤à¤¾à¤¨ सतà¥à¤¯à¤¾à¤ªà¤¿à¤¤ नहीं की गई है.</translation>
<translation id="5720705177508910913">वरà¥à¤¤à¤®à¤¾à¤¨ उपयोगकरà¥à¤¤à¤¾</translation>
+<translation id="572328651809341494">हाल ही के टैब</translation>
<translation id="5784606427469807560">आपके कारà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ करते समय समसà¥â€à¤¯à¤¾ हà¥à¤ˆ. अपना इंटरनेट कनेकà¥â€à¤¶à¤¨ जांà¤à¥‡à¤‚ और पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
<translation id="5785756445106461925">इसके अतिरिकà¥à¤¤, इस पृषà¥à¤  में à¤à¤¸à¥‡ अनà¥à¤¯ संसाधन भी शामिल हैं, जो सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं हैं. टà¥à¤°à¤¾à¤‚ज़िट में होने के दौरान ये संसाधन अनà¥à¤¯ लोगों दà¥à¤µà¤¾à¤°à¤¾ देखे जा सकते हैं और पृषà¥à¤  का सà¥à¤µà¤°à¥‚प बदलने के लिठकिसी हमवलावर दà¥à¤µà¤¾à¤°à¤¾ इनमें बदलाव किठजा सकते हैं.</translation>
+<translation id="5786044859038896871">कà¥à¤¯à¤¾ अपनी कारà¥à¤¡ जानकारी भरना à¤à¤¾à¤¹à¤¤à¥‡ हैं?</translation>
+<translation id="5803412860119678065">कà¥à¤¯à¤¾ आप अपनी <ph name="CARD_DETAIL" /> भरना à¤à¤¾à¤¹à¤¤à¥‡ हैं?</translation>
<translation id="5810442152076338065"><ph name="DOMAIN" /> से आपके कनेकà¥à¤¶à¤¨ को किसी अपà¥à¤°à¤à¤²à¤¿à¤¤ सिà¥à¤° सà¥à¤‡à¤Ÿ का उपयोग करके à¤à¤¨à¥â€à¤•à¥à¤°à¤¿à¤ªà¥â€à¤Ÿ किया गया है.</translation>
<translation id="5813119285467412249">&amp;जोड़ना फिर से करें</translation>
+<translation id="5814352347845180253">आप <ph name="SITE" /> और कà¥à¤› अनà¥à¤¯ साइटों से पà¥à¤°à¥€à¤®à¤¿à¤¯à¤® सामगà¥à¤°à¥€ की à¤à¤•à¥à¤¸à¥‡à¤¸ खो सकते हैं.</translation>
+<translation id="5843436854350372569">आपने <ph name="DOMAIN" /> तक पहà¥à¤‚à¤à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ किया, लेकिन सरà¥à¤µà¤° ने कमज़ोर कà¥à¤‚जी वाला पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥â€à¤¤à¥à¤¤ किया. संभवत: हमलावर ने निजी कà¥à¤‚जी का पता लगा लिया है और हो सकता है कि सरà¥à¤µà¤° आपका अपेकà¥à¤·à¤¿à¤¤ सरà¥à¤µà¤° ना हो (हो सकता है कि आप किसी हमलावर से बातà¤à¥€à¤¤ कर रहे हों). <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">आपको यह संदेश इसलिठदिखाई दे रहा है कà¥à¤¯à¥‹à¤‚कि आपके पà¥à¤°à¤¬à¤‚धक ने यह साइट अवरà¥à¤¦à¥à¤§ कर दी है.</translation>
<translation id="5857090052475505287">नया फ़ोलà¥à¤¡à¤°</translation>
<translation id="5869405914158311789">इस साइट तक नहीं पहà¥à¤‚à¤à¤¾ जा सकता</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">अभिभावक सà¥à¤à¤¾à¤µ</translation>
<translation id="59107663811261420">कारà¥à¤¡ का यह पà¥à¤°à¤•à¤¾à¤° Google पेमेंटà¥à¤¸ दà¥à¤µà¤¾à¤°à¤¾ इस वà¥à¤¯à¤¾à¤ªà¤¾à¤°à¥€ के लिठसमरà¥à¤¥à¤¿à¤¤ नहीं है. कृपया कोई भिनà¥à¤¨ कारà¥à¤¡ à¤à¥à¤¨à¥‡à¤‚.</translation>
<translation id="59174027418879706">सकà¥à¤·à¤® किया गया</translation>
+<translation id="5926846154125914413">आप कà¥à¤› साइटों से पà¥à¤°à¥€à¤®à¤¿à¤¯à¤® सामगà¥à¤°à¥€ की à¤à¤•à¥à¤¸à¥‡à¤¸ खो सकते हैं.</translation>
<translation id="5966707198760109579">सपà¥à¤¤à¤¾à¤¹</translation>
<translation id="5967867314010545767">इतिहास से निकालें</translation>
<translation id="5975083100439434680">ज़ूम आउट</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">सà¥à¤µà¤à¤¾à¤²à¤¿à¤¤</translation>
<translation id="6042308850641462728">अधिक</translation>
<translation id="6060685159320643512">सावधान, ये पà¥à¤°à¤¯à¥‹à¤— नà¥à¤•à¤¸à¤¾à¤¨ पहà¥à¤‚à¤à¤¾ सकते हैं</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{कोई नहीं}=1{1}one{#}other{#}}</translation>
<translation id="6146055958333702838">सभी केबल जांà¤à¥‡à¤‚ और आपके दà¥à¤µà¤¾à¤°à¤¾ उपयोग किठजा रहे सभी राउटर, मॉडेम या अनà¥à¤¯ नेटवरà¥à¤•
डिवाइस को रीबूट करें.</translation>
<translation id="614940544461990577">यह आज़माकर देखें:</translation>
<translation id="6150607114729249911">ओह! आपको अपने अभिभावकों से पूछना होगा कि इस पृषà¥â€à¤  पर जाना ठीक है या नहीं.</translation>
<translation id="6151417162996330722">सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की मानà¥â€à¤¯à¤¤à¤¾ अवधि बहà¥à¤¤ लंबी है.</translation>
-<translation id="6154808779448689242">वापस लौटे नीति टोकन का मिलान वरà¥à¤¤à¤®à¤¾à¤¨ टोकन से नहीं होता</translation>
<translation id="6165508094623778733">अधिक जानें</translation>
<translation id="6203231073485539293">अपना इंटरनेट कनेकà¥à¤¶à¤¨ जांà¤à¥‡à¤‚</translation>
<translation id="6218753634732582820">कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® से पता निकालें?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">नेटवरà¥à¤• पूरà¥à¤µà¤¾à¤¨à¥à¤®à¤¾à¤¨ को अकà¥à¤·à¤® करके देखें</translation>
<translation id="6337534724793800597">नाम के अनà¥à¤¸à¤¾à¤° नीतियां फ़िलà¥à¤Ÿà¤° करें</translation>
<translation id="6342069812937806050">अभी</translation>
+<translation id="6345221851280129312">अजà¥à¤à¤¾à¤¤ आकार</translation>
<translation id="6355080345576803305">सारà¥à¤µà¤œà¤¨à¤¿à¤• सतà¥à¤° ओवरराइड</translation>
<translation id="6358450015545214790">इनका कà¥â€à¤¯à¤¾ अरà¥à¤¥ है?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 अनà¥â€à¤¯ सà¥à¤à¤¾à¤µ}one{# अनà¥â€à¤¯ सà¥à¤à¤¾à¤µ}other{# अनà¥â€à¤¯ सà¥à¤à¤¾à¤µ}}</translation>
<translation id="6387478394221739770">बेहतरीन नई Chrome सà¥à¤µà¤¿à¤§à¤¾à¤“ं में रूà¤à¤¿ है? chrome.com/beta पर हमारा बीटा à¤à¥ˆà¤¨à¤² आज़माà¤à¤‚.</translation>
-<translation id="641480858134062906"><ph name="URL" /> लोड करने में असफ़ल</translation>
+<translation id="6389758589412724634">यह वेबपृषà¥à¤  दिखाते समय कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® में जगह नहीं बà¤à¥€.</translation>
+<translation id="6416403317709441254">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते कà¥à¤¯à¥‹à¤‚कि वेबसाइट ने à¤à¤¸à¥‡ अवà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल भेजे हैं जिनà¥à¤¹à¥‡à¤‚ कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® संसाधित नहीं कर सकता. नेटवरà¥à¤• की गड़बड़ियां और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: पृषà¥à¤  बाद में काम करेगा. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° को रदà¥à¤¦ किया गया है या नहीं यह जांठकरने में असमररà¥à¤¥.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ने कनेकà¥à¤Ÿ करने से मना कर दिया है.</translation>
<translation id="6445051938772793705">देश</translation>
<translation id="6451458296329894277">फ़ारà¥à¤® पà¥à¤¨: जमा करने की दà¥à¤¬à¤¾à¤°à¤¾ पूछें</translation>
<translation id="6458467102616083041">नीति के दà¥à¤µà¤¾à¤°à¤¾ डिफ़ॉलà¥â€à¤Ÿ खोज अकà¥à¤·à¤® कर दिठजाने के कारण उपेकà¥à¤·à¤¿à¤¤.</translation>
+<translation id="6462969404041126431">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; हो सकता है इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ कर दिया गया हो. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">डिवाइस नीतियां</translation>
<translation id="6489534406876378309">कà¥à¤°à¥ˆà¤¶ अपलोड करना पà¥à¤°à¤¾à¤°à¤‚भ करें</translation>
<translation id="6529602333819889595">&amp;हटाना फिर से करें</translation>
+<translation id="6534179046333460208">जीता-जागता वेब के सà¥à¤à¤¾à¤µ</translation>
<translation id="6550675742724504774">विकलà¥à¤ª</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" /> से कम</translation>
<translation id="6596325263575161958">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ तरीका विकलà¥à¤ª</translation>
<translation id="662080504995468778">इसपर रहें</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> खोज</translation>
-<translation id="6634865548447745291">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते कà¥à¤¯à¥‹à¤‚कि <ph name="BEGIN_LINK" />यह पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ कर दिया गया है<ph name="END_LINK" />. नेटवरà¥à¤• की तà¥à¤°à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: पृषà¥à¤  बाद में काम करने लगेगा.</translation>
<translation id="6644283850729428850">यह नीति हटा दी गई है.</translation>
+<translation id="6652240803263749613">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपके कंपà¥à¤¯à¥‚टर के ऑपरेटिंग सिसà¥à¤Ÿà¤® दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">फ़ोलà¥â€à¤¡à¤° संपादित करें</translation>
<translation id="6660210980321319655"><ph name="CRASH_TIME" /> बजे अपने आप रिपोरà¥à¤Ÿ की गई</translation>
<translation id="6671697161687535275">कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® से à¥à¥‰à¤°à¥à¤® सà¥à¤à¤¾à¤µ निकालें?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">पिछला</translation>
<translation id="6710594484020273272">&lt;खोज शबà¥à¤¦ लिखें&gt;</translation>
<translation id="6711464428925977395">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¤° के साथ कà¥à¤› गलत है या पता गलत है.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{कोई नहीं}=1{1 आइटम}one{# आइटम}other{# आइटम}}</translation>
<translation id="674375294223700098">अजà¥à¤à¤¾à¤¤ सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° तà¥à¤°à¥à¤Ÿà¤¿.</translation>
<translation id="6753269504797312559">नीति मान</translation>
<translation id="6757797048963528358">आपका डिवाइस निषà¥à¤•à¥à¤°à¤¿à¤¯ हो गया है.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">नीति सà¥à¤¤à¤° समरà¥à¤¥à¤¿à¤¤ नहीं है.</translation>
<translation id="6895330447102777224">आपके कारà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ हो गई है</translation>
<translation id="6897140037006041989">उपयोगकरà¥à¤¤à¤¾ à¤à¤œà¥‡à¤‚ट</translation>
-<translation id="6903907808598579934">समनà¥à¤µà¤¯à¤¨ à¤à¤¾à¤²à¥‚ करें</translation>
<translation id="6915804003454593391">उपयोगकरà¥à¤¤à¤¾:</translation>
<translation id="6957887021205513506">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° फरà¥à¤œà¥€ दिखाई देता है.</translation>
<translation id="6965382102122355670">ठीक</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">जिला</translation>
<translation id="6973656660372572881">फ़िकà¥â€à¤¸à¥â€à¤¡ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सरà¥à¤µà¤° और .pac सà¥â€à¤•à¥à¤°à¤¿à¤ªà¥â€à¤Ÿ URL दोनों ही निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ हैं.</translation>
<translation id="6989763994942163495">अतिरिकà¥à¤¤ सेटिंग दिखाà¤à¤‚...</translation>
+<translation id="7000990526846637657">कोई इतिहास पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ नहीं मिली</translation>
+<translation id="7009986207543992532">आपने <ph name="DOMAIN" /> पर पहà¥à¤‚à¤à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ किया, लेकिन सरà¥à¤µà¤° ने à¤à¤¸à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किया जिसकी सतà¥à¤¯à¤¾à¤ªà¤¨ अवधि इतनी लंबी है कि वह विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं लगती है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">आपके Google खाते में <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> पर बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग इतिहास के अनà¥à¤¯ रूप उपलबà¥à¤§ हो सकते हैं</translation>
<translation id="7029809446516969842">पासवरà¥à¤¡</translation>
-<translation id="7050187094878475250">आपने <ph name="DOMAIN" /> तक पहà¥à¤‚à¤à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ किया था, लेकिन सरà¥à¤µà¤° ने à¤à¤¸à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥â€à¤¤à¥à¤¤ किया जिसकी मानà¥â€à¤¯à¤¤à¤¾ अवधि विशà¥â€à¤µà¤¸à¤¨à¥€à¤¯ होने के लिठबहà¥à¤¤ लंबी है.</translation>
<translation id="7087282848513945231">काउंटी</translation>
<translation id="7088615885725309056">इससे पà¥à¤°à¤¾à¤¨à¥‡</translation>
<translation id="7090678807593890770"><ph name="LINK" /> के लिठGoogle में खोज करें</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">आपको यह संदेश इसलिठदिखाई दे रहा है कà¥à¤¯à¥‹à¤‚कि किसी नई साइट पर आपके पहली बार जाने से पहले आपके पà¥à¤°à¤¬à¤‚धक को उसे सà¥à¤µà¥€à¤•à¥ƒà¤¤à¤¿ देनी होगी.</translation>
<translation id="724975217298816891">अपने कारà¥à¤¡ विवरण अपडेट करने के लिठ<ph name="CREDIT_CARD" /> का समय समापà¥à¤¤à¤¿ दिनांक और CVC डालें. आपकी तरफ से पà¥à¤·à¥à¤Ÿà¤¿ हो जाने पर, आपके कारà¥à¤¡ के विवरण इस साइट के साथ साà¤à¤¾ किठजाà¤à¤‚गे.</translation>
<translation id="725866823122871198"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> से à¤à¤• निजी कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ नहीं किया जा सकता कà¥â€à¤¯à¥‹à¤‚कि आपके कंपà¥â€à¤¯à¥‚टर का दिनांक और समय (<ph name="DATE_AND_TIME" />) गलत है.</translation>
-<translation id="7265986070661382626">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते कà¥à¤¯à¥‹à¤‚कि वेबसाइट <ph name="BEGIN_LINK" />पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पिनिंग का उपयोग<ph name="END_LINK" /> करती है. नेटवरà¥à¤• की तà¥à¤°à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: यह पृषà¥à¤  बाद में काम करेगा.</translation>
<translation id="7269802741830436641">इस वेबपृषà¥à¤  में à¤à¤• रीडायरेकà¥à¤Ÿ लूप है</translation>
<translation id="7275334191706090484">पà¥à¤°à¤¬à¤‚धित बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="7298195798382681320">सà¥à¤à¤¾à¤ गà¤</translation>
-<translation id="7301833672208172928">इतिहास समनà¥à¤µà¤¯à¤¨ à¤à¤¾à¤²à¥‚ करें</translation>
+<translation id="7309308571273880165">कà¥à¤°à¥ˆà¥ˆà¤¶ रिपोरà¥à¤Ÿ <ph name="CRASH_TIME" /> बजे कैपà¥à¤à¤° की गई (उपयोगकरà¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ अपलोड करने का अनà¥à¤°à¥‹à¤§ किया गया, अभी तक अपलोड नहीं किया गया)</translation>
<translation id="7334320624316649418">&amp;पà¥à¤¨: कà¥à¤°à¤®à¤¿à¤¤ करना फिर से करें</translation>
<translation id="733923710415886693">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पारदरà¥à¤¶à¤¿à¤¤à¤¾ के माधà¥à¤¯à¤® से सरà¥à¤µà¤° के पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° को पà¥à¤°à¤•à¤Ÿ नहीं किया गया.</translation>
+<translation id="7351800657706554155">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते कà¥à¤¯à¥‹à¤‚कि उसका पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ कर दिया गया है. नेटवरà¥à¤• की गड़बड़ियां और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: यह पृषà¥à¤  बाद में काम करने लगेगा. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">आदेश पंकà¥à¤¤à¤¿</translation>
<translation id="7372973238305370288">खोज परिणाम</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -539,16 +572,17 @@
<translation id="7469372306589899959">कारà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ की जा रही है</translation>
<translation id="7481312909269577407">आगे भेजें</translation>
<translation id="7485870689360869515">कोई डेटा नहीं मिला</translation>
+<translation id="7508255263130623398">वापस लौटाया हà¥à¤† नीति डिवाइस आईडी खाली है या उसका मिलान वरà¥à¤¤à¤®à¤¾à¤¨ डिवाइस आईडी से नहीं होता है</translation>
<translation id="7514365320538308">डाउनलोड करें</translation>
<translation id="7518003948725431193">इस वेब पते के लिठकोई वेब पृषà¥à¤  नहीं मिला था: <ph name="URL" /></translation>
<translation id="7537536606612762813">आवशà¥à¤¯à¤•</translation>
<translation id="7542995811387359312">सà¥à¤µà¤¤à¤ƒ कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ भरना अकà¥à¤·à¤® किया गया है कà¥à¤¯à¥‹à¤‚कि यह à¥à¥‰à¤°à¥à¤® किसी सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥à¤¶à¤¨ का उपयोग नहीं करता है.</translation>
<translation id="7549584377607005141">इस वेबपृषà¥à¤  को आपके दà¥à¤µà¤¾à¤°à¤¾ पहले दरà¥à¤œ किठगठडेटा की आवशà¥à¤¯à¤•à¤¤à¤¾ है, ताकि इसे सही रूप में पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ किया जा सके. आप यह डेटा पà¥à¤¨: भेज सकते हैं, लेकिन à¤à¤¸à¤¾ करके आप इस पृषà¥à¤  दà¥à¤µà¤¾à¤°à¤¾ पहले की जा à¤à¥à¤•à¥€ कोई कारà¥à¤¯à¤µà¤¾à¤¹à¥€ दोहराà¤à¤‚गे.</translation>
<translation id="7554791636758816595">नया टैब</translation>
-<translation id="7567204685887185387">यह सरà¥à¤µà¤° यह पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; हो सकता है इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° धोखे से जारी किया गया हो. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="7568593326407688803">यह पृषà¥à¤ <ph name="ORIGINAL_LANGUAGE" />में है कà¥à¤¯à¤¾ आप इसका अनà¥à¤µà¤¾à¤¦ करना à¤à¤¾à¤¹à¥‡à¤‚गे?</translation>
<translation id="7569952961197462199">Chrome से कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ निकालें?</translation>
<translation id="7578104083680115302">Google के साथ सहेजे गठकारà¥à¤¡ का उपयोग करके डिवाइसों में मौजूद साइटों और à¤à¤ªà¥â€à¤¸ पर तà¥à¤°à¤‚त भà¥à¤—तान करें.</translation>
+<translation id="7588950540487816470">जीता-जागता वेब</translation>
<translation id="7592362899630581445">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° नाम संबंधी पà¥à¤°à¤¤à¤¿à¤¬à¤‚धों का उलà¥à¤²à¤‚घन करता है.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> वरà¥à¤¤à¤®à¤¾à¤¨ में इस अनà¥à¤°à¥‹à¤§ का पà¥à¤°à¤¬à¤‚धन कर पाने में असमरà¥à¤¥ है.</translation>
<translation id="7600965453749440009">कभी भी <ph name="LANGUAGE" /> का अनà¥à¤µà¤¾à¤¦ न करें</translation>
@@ -559,6 +593,7 @@
<translation id="7637571805876720304">कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® से कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ निकालें?</translation>
<translation id="765676359832457558">उनà¥à¤¨à¤¤ सेटिंगà¥à¤¸ छिपाà¤à¤‚...</translation>
<translation id="7658239707568436148">अभी नहीं</translation>
+<translation id="7667346355482952095">वापस लौटा हà¥à¤† नीति टोकन खाली है या उसका मिलान वरà¥à¤¤à¤®à¤¾à¤¨ टोकन से नहीं होता</translation>
<translation id="7668654391829183341">अजà¥à¤à¤¾à¤¤ डिवाइस</translation>
<translation id="7674629440242451245">शानदार नई Chrome सà¥à¤µà¤¿à¤§à¤¾à¤“ं में रूà¤à¤¿ है? तो chrome.com/dev पर हमारा डेव à¤à¥ˆà¤¨à¤² आज़माà¤à¤‚.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> में आगे बढ़ें (असà¥à¤°à¤•à¥à¤·à¤¿à¤¤)<ph name="END_LINK" /></translation>
@@ -575,10 +610,10 @@
<translation id="780301667611848630">जी नहीं, रहने दें </translation>
<translation id="7805768142964895445">सà¥à¤¥à¤¿à¤¤à¤¿</translation>
<translation id="7813600968533626083">Chrome से फ़ॉरà¥à¤® सà¥à¤à¤¾à¤µ को निकालें?</translation>
+<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' के लिठ<ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> मिले</translation>
<translation id="785549533363645510">हालांकि, आप अदृशà¥à¤¯ नहीं हैं. गà¥à¤ªà¥à¤¤ मोड में रहने से आपकी बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग आपके नियोकà¥à¤¤à¤¾, आपके इंटरनेट सेवा पà¥à¤°à¤¦à¤¾à¤¤à¤¾ या आपके दà¥à¤µà¤¾à¤°à¤¾ देखी जाने वाली वेबसाइट से छिपती नहीं है.</translation>
<translation id="7887683347370398519">अपना CVC जांà¤à¥‡à¤‚ और पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें</translation>
<translation id="7894616681410591072">ओह! आपको यह पृषà¥à¤  à¤à¤•à¥à¤¸à¥‡à¤¸ करने के लिठ<ph name="NAME" /> से अनà¥à¤®à¤¤à¤¿ लेनी होगी.</translation>
-<translation id="790025292736025802"><ph name="URL" /> नहीं मिला</translation>
<translation id="7912024687060120840">इस फ़ोलà¥à¤¡à¤° में:</translation>
<translation id="7920092496846849526">आपने अपने अभिभावक से पूछा था कि इस पृषà¥â€à¤  पर जाना ठीक है या नहीं.</translation>
<translation id="7935318582918952113">DOM डिसà¥à¤Ÿà¤¿à¤²à¤°</translation>
@@ -591,9 +626,10 @@
<translation id="7995512525968007366">निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ नहीं किया गया</translation>
<translation id="8012647001091218357">हम इस समय आपके अभिभावकों तक नहीं पहà¥à¤‚ठपा रहे हैं. कृपया पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें.</translation>
<translation id="8034522405403831421">यह पृषà¥à¤  <ph name="SOURCE_LANGUAGE" /> में है. इसका <ph name="TARGET_LANGUAGE" /> में अनà¥à¤µà¤¾à¤¦ करें?</translation>
-<translation id="8034955203865359138">कोई इतिहास पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ नहीं मिली.</translation>
<translation id="8088680233425245692">लेख देखने में विफल रहा.</translation>
+<translation id="8089520772729574115">1 MB से कम</translation>
<translation id="8091372947890762290">सरà¥à¤µà¤° पर सकà¥à¤°à¤¿à¤¯à¤£ लंबित है</translation>
+<translation id="8129262335948759431">अजà¥à¤à¤¾à¤¤ मातà¥à¤°à¤¾</translation>
<translation id="8131740175452115882">दà¥à¤¬à¤¾à¤°à¤¾ पूछें</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> का सरà¥à¤µà¤° <ph name="BEGIN_ABBR" />DNS पता<ph name="END_ABBR" /> नहीं ढूंà¥à¤¾ जा सका.</translation>
<translation id="8149426793427495338">आपका कंपà¥à¤¯à¥‚टर निषà¥à¤•à¥à¤°à¤¿à¤¯ हो गया है.</translation>
@@ -602,6 +638,7 @@
<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" आईडी वाले à¤à¤•à¥â€à¤¸à¤Ÿà¥‡à¤‚शन का अमानà¥â€à¤¯ अपडेट URL.</translation>
<translation id="8218327578424803826">सौंपा गया सà¥â€à¤¥à¤¾à¤¨:</translation>
<translation id="8225771182978767009">जिस वà¥à¤¯à¤•à¥à¤¤à¤¿ ने इस कंपà¥à¤¯à¥‚टर को सेट किया है, उसने इस साइट को अवरà¥à¤¦à¥à¤§ करना à¤à¥à¤¨à¤¾ है.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">आपके दà¥à¤µà¤¾à¤°à¤¾ खोजे जा रहे पृषà¥à¤  ने आपके दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ की गई जानकारी का उपयोग किया है. उस पृषà¥à¤  पर वापस जाने से आपके दà¥à¤µà¤¾à¤°à¤¾ की गई किसी कà¥à¤°à¤¿à¤¯à¤¾ को दोहराने की आवशà¥à¤¯à¤•à¤¤à¤¾ हो सकती है. कà¥à¤¯à¤¾ आप जारी रखना à¤à¤¾à¤¹à¤¤à¥‡ हैं?</translation>
<translation id="8249320324621329438">पिछली बार पà¥à¤°à¤¾à¤ªà¥à¤¤ किया गया:</translation>
<translation id="8261506727792406068">हटाà¤à¤‚</translation>
@@ -614,12 +651,17 @@
<translation id="8349305172487531364">बà¥à¤•à¤®à¤¾à¤°à¥à¤• बार</translation>
<translation id="8363502534493474904">हवाई जहाज़ मोड बंद करें</translation>
<translation id="8364627913115013041">सेट नहीं है.</translation>
+<translation id="8380941800586852976">खतरनाक</translation>
<translation id="8412145213513410671">कà¥à¤°à¥ˆà¤¶ (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">आपको वही पासà¥à¥à¤°à¥‡à¥› दोबारा दरà¥à¤œ करना होगा.</translation>
<translation id="8428213095426709021">सेटिंगà¥à¤¸</translation>
+<translation id="8433057134996913067">इससे आप अधिकांश वेबसाइट से पà¥à¤°à¤¸à¥à¤¥à¤¾à¤¨ कर जाà¤à¤‚गे.</translation>
<translation id="8437238597147034694">&amp;ले जाना वापस लाà¤à¤‚</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}one{# कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}other{# कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}}</translation>
+<translation id="8483780878231876732">कारà¥à¤¡ का उपयोग अपने Google खाते से करने के लिà¤, Chrome में पà¥à¤°à¤µà¥‡à¤¶ करें</translation>
<translation id="8488350697529856933">इस पर लागू होती है</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ने पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦ देने में अतà¥à¤¯à¤§à¤¿à¤• समय लिया.</translation>
+<translation id="852346902619691059">यह सरà¥à¤µà¤° पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपके कंपà¥à¤¯à¥‚टर के ऑपरेटिंग सिसà¥à¤Ÿà¤® दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी हमलावर दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में बाधा डालने के कारण हो सकता है. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">कारà¥à¤¡ का यह पà¥à¤°à¤•à¤¾à¤° Google पेमेंटà¥à¤¸ दà¥à¤µà¤¾à¤°à¤¾ समरà¥à¤¥à¤¿à¤¤ नहीं है. कृपया कोई भिनà¥à¤¨ कारà¥à¤¡ à¤à¥à¤¨à¥‡à¤‚.</translation>
<translation id="8550022383519221471">आपके डोमेन के लिठसमनà¥â€à¤µà¤¯à¤¨ सेवा उपलबà¥â€à¤§ नहीं है.</translation>
<translation id="8553075262323480129">अनà¥à¤µà¤¾à¤¦ विफल हो गया कà¥à¤¯à¥‹à¤‚कि पृषà¥à¤  की भाषा निरà¥à¤§à¤¾à¤°à¤¿à¤¤ नहीं की जा सकी.</translation>
@@ -631,15 +673,12 @@
<translation id="8647750283161643317">सभी को डिफ़ॉलà¥à¤Ÿ पर रीसेट करें</translation>
<translation id="8680787084697685621">खाता साइन-इन विवरण पà¥à¤°à¤¾à¤¨à¥‡ हैं.</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> से आपके कनेकà¥à¤¶à¤¨ को à¤à¤¨à¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ नहीं किया गया है.</translation>
-<translation id="8713130696108419660">खराब आरंभिक हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°</translation>
<translation id="8725066075913043281">पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ करें</translation>
<translation id="8728672262656704056">आप गà¥à¤ªà¥à¤¤ मोड में à¤à¤²à¥‡ गठहैं</translation>
<translation id="8730621377337864115">पूरà¥à¤£</translation>
<translation id="8738058698779197622">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ करने के लिà¤, आपकी घड़ी को ठीक से सेट किठजाने की आवशà¥â€à¤¯à¤•à¤¤à¤¾ है. à¤à¤¸à¤¾ इसलिठकà¥â€à¤¯à¥‹à¤‚कि वेबसाइटों दà¥à¤µà¤¾à¤°à¤¾ सà¥â€à¤µà¤¯à¤‚ की पहà¤à¤¾à¤¨ करने के लिठउपयोग किठजाने वाले पà¥à¤°à¤®à¤¾à¤£ पतà¥à¤° केवल विशिषà¥â€à¤Ÿ समयावधियों के लिठही मानà¥â€à¤¯ होते हैं. à¤à¥‚ंकि आपके डिवाइस की घड़ी गलत है, इसलिठकà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® इन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‹à¤‚ को सतà¥â€à¤¯à¤¾à¤ªà¤¿à¤¤ नहीं कर सकता.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> का &lt;abbr id="dnsDefinition"&gt;DNS पता&lt;/abbr&gt; पà¥à¤°à¤¾à¤ªà¥à¤¤ नहीं किया जा सका. समसà¥à¤¯à¤¾ का निदान किया जा रहा है.</translation>
-<translation id="8741995161408053644">आपके Google खाते में <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> पर बà¥à¤°à¤¾à¤‰à¥›à¤¿à¤‚ग इतिहास के अनà¥à¤¯ पà¥à¤°à¤•à¤¾à¤° हो सकते हैं.</translation>
<translation id="8790007591277257123">&amp;हटाना फिर से करें</translation>
-<translation id="8790687370365610530">Google दà¥à¤µà¤¾à¤°à¤¾ सà¥à¤à¤¾à¤ˆ गई वैयकà¥à¤¤à¤¿à¤•à¥ƒà¤¤ सामगà¥à¤°à¥€ पà¥à¤°à¤¾à¤ªà¥à¤¤ करने के लिà¤, इतिहास समनà¥à¤µà¤¯à¤¨ à¤à¤¾à¤²à¥‚ करें.</translation>
<translation id="8798099450830957504">सामानà¥à¤¯</translation>
<translation id="8804164990146287819">निजता नीति</translation>
<translation id="8820817407110198400">बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
@@ -661,13 +700,11 @@
<translation id="8971063699422889582">सरà¥à¤µà¤° के पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की समय-सीमा समापà¥à¤¤ हो à¤à¥à¤•à¥€ है.</translation>
<translation id="8987927404178983737">माह</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">सरà¥à¤µà¤° ने à¤à¤• पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किया है, जिसे पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पारदरà¥à¤¶à¤¿à¤¤à¤¾ पॉलिसी का उपयोग करके सारà¥à¤µà¤œà¤¨à¤¿à¤• रूप से पà¥à¤°à¤•à¤Ÿ नहीं किया गया था. कà¥à¤› पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‹à¤‚ के लिठयह सà¥à¤¨à¤¿à¤¶à¥à¤à¤¿à¤¤ करना आवशà¥à¤¯à¤• है कि वे विशà¥à¤µà¤¸à¤¨à¥€à¤¯ हैं और आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾à¤“ं से रकà¥à¤·à¤¾ करते हैं.</translation>
<translation id="9001074447101275817">पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ <ph name="DOMAIN" /> के लिठउपयोगकरà¥à¤¤à¤¾ नाम और पासवरà¥à¤¡ की आवशà¥à¤¯à¤•à¤¤à¤¾ है.</translation>
<translation id="901974403500617787">सिसà¥à¤Ÿà¤®-वà¥à¤¯à¤¾à¤ªà¥€ रूप से लागू होने वाले फ़à¥à¤²à¥ˆà¤— केवल मालिक दà¥à¤µà¤¾à¤°à¤¾ ही सेट किठजा सकते हैं: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">इस पृषà¥à¤  का <ph name="TARGET_LANGUAGE" /> में अनà¥à¤µà¤¾à¤¦ कर दिया गया है</translation>
<translation id="9038649477754266430">अधिक तेज़ी से पृषà¥à¤  लोड करने के लिठकिसी पूरà¥à¤µà¤¾à¤¨à¥à¤®à¤¾à¤¨ सेवा का उपयोग करें</translation>
<translation id="9039213469156557790">इसके अतिरिकà¥à¤¤, इस पृषà¥à¤  में à¤à¤¸à¥‡ अनà¥à¤¯ संसाधन भी शामिल हैं, जो सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं हैं. टà¥à¤°à¤¾à¤‚ज़िट में होने के दौरान ये संसाधन अनà¥à¤¯ लोगों दà¥à¤µà¤¾à¤°à¤¾ देखे जा सकते हैं और पृषà¥à¤  का वà¥à¤¯à¤µà¤¹à¤¾à¤° बदलने के लिठकिसी हमवलावर दà¥à¤µà¤¾à¤°à¤¾ इनमें बदलाव किठजा सकते हैं.</translation>
-<translation id="9049981332609050619">आपने <ph name="DOMAIN" /> पर पहà¥à¤‚à¤à¤¨à¥‡ का पà¥à¤°à¤¯à¤¾à¤¸ किया, लेकिन सरà¥à¤µà¤° ने à¤à¤• अमानà¥â€à¤¯ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ किया.</translation>
<translation id="9050666287014529139">पासफ़à¥à¤°à¥‡à¤œà¤¼</translation>
<translation id="9065203028668620118">संपादित करें</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> पृषà¥à¤  काम नहीं कर रहा है</translation>
diff --git a/chromium/components/strings/components_strings_hr.xtb b/chromium/components/strings/components_strings_hr.xtb
index ff3c51ea870..f1b0276b8b6 100644
--- a/chromium/components/strings/components_strings_hr.xtb
+++ b/chromium/components/strings/components_strings_hr.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hr">
+<translation id="1008557486741366299">Ne sada</translation>
<translation id="1015730422737071372">Navedite dodatne pojedinosti</translation>
<translation id="1032854598605920125">Zakretanje u smjeru kazaljke na satu</translation>
<translation id="1038842779957582377">nepoznati naziv</translation>
+<translation id="1053591932240354961">TrenutaÄno ne možete otvoriti <ph name="SITE" /> jer je web-lokacija poslala kodirane vjerodajnice koje Google Chrome ne može obraditi. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će ta stranica vjerojatno kasnije funkcionirati. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Poništi dodavanje</translation>
<translation id="10614374240317010">Zaporke se nikad ne spremaju</translation>
-<translation id="1064422015032085147">Poslužitelj web-stranice možda je preopterećen ili je u tijeku održavanje.
- Da ne bi došlo do prevelikog prometa i pogoršanja situacije,
- zahtjevi za taj URL trenutaÄno se ne odobravaju.</translation>
<translation id="106701514854093668">Oznake radne površine</translation>
<translation id="1080116354587839789">Prilagođavanje širini</translation>
+<translation id="1103124106085518534">Gotovo zasad</translation>
<translation id="1103523840287552314">Uvijek prevedi <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Ako je oznaÄeno, Chrome će pohraniti kopiju vaÅ¡e kartice na ureÄ‘aj radi bržeg popunjavanja obrazaca.</translation>
+<translation id="1111153019813902504">Najnovije oznake</translation>
<translation id="1113869188872983271">&amp;Poništi promjenu rasporeda</translation>
+<translation id="1126551341858583091">VeliÄina na lokalnoj pohrani iznosi <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Predmemorija pravila ispravna je</translation>
<translation id="113188000913989374"><ph name="SITE" /> navodi sljedeće:</translation>
<translation id="1132774398110320017">Postavke Automatskog popunjavanja u Chromeu...</translation>
-<translation id="1150979032973867961">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; operativni sustav vaÅ¡eg raÄunala smatra da njegov sigurnosni certifikat nije pouzdan. To može biti uzrokovano pogreÅ¡nom konfiguracijom ili napadom na vaÅ¡u vezu.</translation>
<translation id="1152921474424827756">Pristupite <ph name="BEGIN_LINK" />predmemoriranoj kopiji<ph name="END_LINK" /> stranice <ph name="URL" /></translation>
<translation id="1158211211994409885">Host <ph name="HOST_NAME" /> neoÄekivano je prekinuo vezu.</translation>
<translation id="1161325031994447685">Ponovo se povežite s Wi-Fi mrežom</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Ukloni</translation>
<translation id="1201402288615127009">Sljedeće</translation>
<translation id="1201895884277373915">Više s ove web-lokacije</translation>
-<translation id="121201262018556460">PokuÅ¡ali ste doseći domenu <ph name="DOMAIN" />, ali poslužitelj je predstavio certifikat potpisan slabim kljuÄem. NapadaÄ je možda otkrio privatni kljuÄ, a poslužitelj možda nije oÄekivani poslužitelj (možda ste u komunikaciji s napadaÄem).</translation>
+<translation id="1206967143813997005">Potpis inicijalima nije ispravan</translation>
+<translation id="1209206284964581585">Sakrij za sad</translation>
<translation id="1219129156119358924">Sigurnost sustava</translation>
<translation id="1227224963052638717">Nepoznato pravilo.</translation>
<translation id="1227633850867390598">Skrivanje vrijednosti</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Da</translation>
<translation id="1430915738399379752">Ispis</translation>
<translation id="1442912890475371290">Blokiran je pokušaj <ph name="BEGIN_LINK" />posjeta stranici na domeni <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">TrenutaÄno ne možete otvoriti <ph name="SITE" /> jer web-lokacija upotrebljava prikvaÄivanje certifikata. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će ta stranica vjerojatno kasnije funkcionirati. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Prikaži spremljenu kopiju te stranice (tj., onu za koju se zna da je zastarjela).</translation>
<translation id="1519264250979466059">Datum međuverzije</translation>
<translation id="1549470594296187301">Za upotrebu te znaÄajke mora biti omogućen JavaScript.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Mrežna konfiguracija nije važeća i nije ju bilo moguće uvesti.</translation>
<translation id="1644574205037202324">Povijest</translation>
<translation id="1645368109819982629">Protokol nije podržan</translation>
-<translation id="1655462015569774233">{1,plural, =1{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat istekao juÄer. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. Sat vaÅ¡eg raÄunala trenutaÄno je postavljen na <ph name="CURRENT_DATE" />. Je li to u redu? Ako nije, ispravite vrijeme na satu sustava, a zatim osvježite ovu stranicu.}one{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat istekao prije # dan. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. Sat vaÅ¡eg raÄunala trenutaÄno je postavljen na <ph name="CURRENT_DATE" />. Je li to u redu? Ako nije, ispravite vrijeme na satu sustava, a zatim osvježite ovu stranicu.}few{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat istekao prije # dana. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. Sat vaÅ¡eg raÄunala trenutaÄno je postavljen na <ph name="CURRENT_DATE" />. Je li to u redu? Ako nije, ispravite vrijeme na satu sustava, a zatim osvježite ovu stranicu.}other{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat istekao prije # dana. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. Sat vaÅ¡eg raÄunala trenutaÄno je postavljen na <ph name="CURRENT_DATE" />. Je li to u redu? Ako nije, ispravite vrijeme na satu sustava, a zatim osvježite ovu stranicu.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> obiÄno upotrebljava enkripciju radi zaÅ¡tite vaÅ¡ih podataka. Prilikom ovog pokuÅ¡aja povezivanja Google Chromea s web-lokacijom <ph name="SITE" /> ta je web-lokacija vratila neuobiÄajene i netoÄne vjerodajnice. To može znaÄiti da se neki napadaÄ pokuÅ¡ava predstaviti kao <ph name="SITE" /> ili je zaslon za prijavu na Wi-Fi prekinuo vezu. VaÅ¡i su podaci joÅ¡ uvijek sigurni jer je Google Chrome zaustavio povezivanje prije razmjene podataka.</translation>
<translation id="168841957122794586">Certifikat poslužitelja sadrži slab kriptografski kljuÄ!</translation>
<translation id="1701955595840307032">Prikaz predloženog sadržaja</translation>
-<translation id="1706954506755087368">{1,plural, =1{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan sutra. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu.}one{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan # dan u budućnosti. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu.}few{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan # dana u budućnosti. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu.}other{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan # dana u budućnosti. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Pokušajte kontaktirati administratora sustava.</translation>
<translation id="17513872634828108">Otvorene kartice</translation>
<translation id="1753706481035618306">Broj stranice</translation>
-<translation id="1761412452051366565">UkljuÄite sinkronizaciju ako želite da vam Google predlaže sadržaje.</translation>
-<translation id="1763864636252898013">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; operativni sustav vašeg uređaja smatra da njegov sigurnosni certifikat nije pouzdan. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Pokušajte pokrenuti Mrežnu dijagnostiku sustava Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Ažurirajte zaporku za sinkronizaciju.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Ovdje će se pojaviti oznake koje ste nedavno posjetili.</translation>
<translation id="1821930232296380041">Nevažeći zahtjev ili parametri zahtjeva</translation>
<translation id="1838667051080421715">Gledate izvor web-stranice.</translation>
<translation id="1871208020102129563">Proxy poslužitelj postavljen je na upotrebu fiksnih proxy poslužitelja, a ne URL .pac skripte.</translation>
<translation id="1883255238294161206">Sažmi popis</translation>
<translation id="1898423065542865115">Filtriranje</translation>
-<translation id="1911837502049945214">Host <ph name="HOST_NAME" /> nije prihvatio certifikat za prijavu ili je certifikat za prijavu možda istekao.</translation>
<translation id="194030505837763158">Posjetite <ph name="LINK" /></translation>
<translation id="1962204205936693436">Oznake s domene <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Pogreška postavljanja u seriju</translation>
<translation id="1974060860693918893">Napredno</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{i još 1}one{i još #}few{i još #}other{i još #}}</translation>
<translation id="2025186561304664664">Proxy je postavljen na automatsko konfiguriranje.</translation>
<translation id="2030481566774242610">Jeste li mislili <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Ova ti se poruka prikazuje zato što tvoji roditelji moraju odobriti web-lokacije koje posjećuješ prvi put.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />provjerite proxy i vatrozid<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ZIP kĂ´d</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 prijedlog}one{# prijedlog}few{# prijedloga}other{# prijedloga}}</translation>
<translation id="2065985942032347596">Potrebna autentikacija</translation>
<translation id="2079545284768500474">Poništi</translation>
<translation id="20817612488360358">Postavljena je upotreba sistemskih postavki proxy poslužitelja, ali takoÄ‘er je odreÄ‘ena izriÄita konfiguracija proxy poslužitelja.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Uredi oznaku</translation>
<translation id="2166049586286450108">Potpuni administratorski pristup</translation>
<translation id="2166378884831602661">Web-lokacija ne može pružiti sigurnu vezu</translation>
-<translation id="2171101176734966184">PokuÅ¡ali ste doseći domenu <ph name="DOMAIN" />, ali poslužitelj je predstavio certifikat potpisan slabim algoritmom potpisa. ZnaÄi da su sigurnosne vjerodajnice koje je poslužitelj predstavio možda krivotvorene, a poslužitelj možda nije poslužitelj koji oÄekujete (možda ste u komunikaciji s napadaÄem).</translation>
<translation id="2181821976797666341">Pravila</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}one{# adresa}few{# adrese}other{# adresa}}</translation>
<translation id="2212735316055980242">Pravilo nije pronađeno</translation>
<translation id="2213606439339815911">Dohvaćanje unosa...</translation>
-<translation id="2214283295778284209">Web lokacija <ph name="SITE" /> nije dostupna</translation>
<translation id="2230458221926704099">RijeÅ¡ite problem s povezivanjem pomoću <ph name="BEGIN_LINK" />dijagnostiÄke aplikacije<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Pošalji sad</translation>
<translation id="225207911366869382">Ta je vrijednost obustavljena za to pravilo.</translation>
<translation id="2262243747453050782">HTTP pogreška</translation>
<translation id="2282872951544483773">Nedostupni eksperimenti</translation>
<translation id="2292556288342944218">Internetski je pristup blokiran</translation>
<translation id="229702904922032456">Korijenski ili posredniÄki certifikat je istekao.</translation>
<translation id="230155334948463882">Nova kartica?</translation>
+<translation id="2305919008529760154">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat možda lažan. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> zahtijeva korisniÄko ime i zaporku.</translation>
+<translation id="2318774815570432836">TrenutaÄno ne možete otvoriti <ph name="SITE" /> jer web-lokacija upotrebljava HSTS. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će ta stranica vjerojatno kasnije funkcionirati. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Zanemarena nevažeća oznaka u indeksu <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Druge oznake</translation>
<translation id="2359808026110333948">Nastavi</translation>
<translation id="2365563543831475020">Izvješće o rušenju programa generirano <ph name="CRASH_TIME" /> još nije preneseno</translation>
<translation id="2367567093518048410">Razina</translation>
+<translation id="2371153335857947666">{1,plural, =1{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat istekao juÄer. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. Sat vaÅ¡eg raÄunala trenutaÄno je postavljen na <ph name="CURRENT_DATE" />. Je li to u redu? Ako nije, ispravite vrijeme na satu sustava, a zatim osvježite ovu stranicu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.}one{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat istekao prije # dan. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. Sat vaÅ¡eg raÄunala trenutaÄno je postavljen na <ph name="CURRENT_DATE" />. Je li to u redu? Ako nije, ispravite vrijeme na satu sustava, a zatim osvježite ovu stranicu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.}few{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat istekao prije # dana. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. Sat vaÅ¡eg raÄunala trenutaÄno je postavljen na <ph name="CURRENT_DATE" />. Je li to u redu? Ako nije, ispravite vrijeme na satu sustava, a zatim osvježite ovu stranicu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.}other{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat istekao prije # dana. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. Sat vaÅ¡eg raÄunala trenutaÄno je postavljen na <ph name="CURRENT_DATE" />. Je li to u redu? Ako nije, ispravite vrijeme na satu sustava, a zatim osvježite ovu stranicu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Nema zamjenskih korisniÄkih suÄelja</translation>
<translation id="2384307209577226199">Zadano pravilo organizacije</translation>
-<translation id="238526402387145295">TrenutaÄno ne možete posjetiti <ph name="SITE" /> jer ta web-lokacija <ph name="BEGIN_LINK" />upotrebljava HSTS<ph name="END_LINK" />. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će stranica vjerojatno kasnije funkcionirati.</translation>
<translation id="2386255080630008482">Opozvan je certifikat poslužitelja.</translation>
<translation id="2392959068659972793">Prikaži pravila bez postavljenih vrijednosti</translation>
<translation id="2396249848217231973">&amp;Poništi brisanje</translation>
-<translation id="2413528052993050574">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; njegov sigurnosni certifikat možda je opozvan. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="2455981314101692989">Ova web-stranica ima onemogućeno automatsko popunjavanje za taj obrazac.</translation>
+<translation id="2463739503403862330">Ispuni</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />pokrenuti Mrežnu dijagnostiku<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Nevažeći URL pretraživanja.</translation>
<translation id="2491120439723279231">Certifikat poslužitelja sadrži pogreške.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Pošalji</translation>
<translation id="2674170444375937751">Jeste li sigurni da te stranice želite izbrisati iz Vaše povijesti?</translation>
<translation id="2677748264148917807">Napusti</translation>
+<translation id="269990154133806163">Poslužitelj je prikazao certifikat koji nije javno otkriven putem pravila Transparentnost certifikata. Taj se zahtjev postavlja za neke certifikate radi provjere njihove pouzdanosti i zaštite od napada. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">Vrijednost ne odgovara formatu.</translation>
<translation id="2704951214193499422">Chromium nije uspio potvrditi vašu karticu. Pokušajte ponovo kasnije.</translation>
<translation id="2705137772291741111">Spremljena (predmemorirana) kopija web-lokacije nije Äitljiva.</translation>
<translation id="2709516037105925701">Automatsko popunjavanje</translation>
+<translation id="2712118517637785082">PokuÅ¡ali ste otvoriti <ph name="DOMAIN" />, ali izdavaÄ je povukao certifikat koji je poslužitelj prikazao. To znaÄi da sigurnosne vjerodajnice koje je poslužitelj prikazao nikako ne biste trebali smatrati pouzdanima. Možda komunicirate s napadaÄem. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Traži dopuštenje</translation>
<translation id="2721148159707890343">Zahtjev je uspio</translation>
<translation id="2728127805433021124">Certifikat poslužitelja potpisan je slabim algoritmom potpisa.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Adresna traka i traka za pretraživanje</translation>
<translation id="2826760142808435982">Veza je kriptirana i autentificirana Å¡ifrom <ph name="CIPHER" />, a <ph name="KX" /> služi za mehanizam razmjene kljuÄeva.</translation>
<translation id="2835170189407361413">Obriši obrazac</translation>
-<translation id="2837049386027881519">Bio je nužan ponovni pokuÅ¡aj povezivanja starijom verzijom protokola TLS ili SSL. To uobiÄajeno znaÄi da poslužitelj upotrebljava vrlo stari softver te da može imati druge sigurnosne probleme.</translation>
<translation id="284702764277384724">Certifikat poslužitelja na hostu <ph name="HOST_NAME" /> izgleda kao falsifikat.</translation>
<translation id="2889159643044928134">Ne uÄitavaj ponovo</translation>
-<translation id="2896499918916051536">Taj dodatak nije podržan.</translation>
+<translation id="2900469785430194048">Google Chrome ostao je bez memorije dok je pokušavao prikazati ovu web-stranicu.</translation>
<translation id="2909946352844186028">Otkrivena je promjena mreže.</translation>
-<translation id="2915500479781995473">Poslužitelj nije mogao dokazati da se radi o domeni <ph name="DOMAIN" />. Njezin je sigurnosni certifikat istekao. Uzrok može biti pogreÅ¡na konfiguracija ili napadaÄ koji ometa vaÅ¡u vezu. Sat vaÅ¡eg raÄunala trenutaÄno je postavljen na <ph name="CURRENT_TIME" />. Je li to u redu? Ako nije, podesite sat svog sustava, a zatim osvježite ovu stranicu.</translation>
<translation id="2922350208395188000">Certifikat poslužitelja nije moguće provjeriti.</translation>
-<translation id="2941952326391522266">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; njegov je sigurnosni certifikat s domene <ph name="DOMAIN2" />. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="2948083400971632585">Možete onemogućiti sve proxyje konfigurirane za vezu sa stranice postavki.</translation>
<translation id="2955913368246107853">Zatvori traku za traženje</translation>
<translation id="2958431318199492670">Mrežna konfiguracija nije u skladu sa standardima ONC. Dijelove konfiguracije nije moguće uvesti.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Pogrešna vrsta pravila</translation>
<translation id="3032412215588512954">Želite li ponovo uÄitati tu web-lokaciju?</translation>
<translation id="3037605927509011580">O, ne!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{najmanje 1 stavka na sinkroniziranim uređajima}=1{1 stavka (i više njih na sinkroniziranim uređajima)}one{# stavka (i više njih na sinkroniziranim uređajima)}few{# stavke (i više njih na sinkroniziranim uređajima)}other{# stavki (i više njih na sinkroniziranim uređajima)}}</translation>
<translation id="3041612393474885105">Podaci o certifikatu</translation>
<translation id="3063697135517575841">Chrome nije uspio potvrditi vašu karticu. Pokušajte ponovo kasnije.</translation>
<translation id="3093245981617870298">Izvan mreže ste.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Najnovije</translation>
<translation id="3207960819495026254">OznaÄeno</translation>
-<translation id="3225919329040284222">Poslužitelj je pokazao certifikat koji ne odgovara ugraÄ‘enim oÄekivanjima. Ta su oÄekivanja ukljuÄena za odreÄ‘ene web-lokacije s visokim stupnjem sigurnosti radi vaÅ¡e zaÅ¡tite.</translation>
<translation id="3226128629678568754">Pritisnite gumb za ponovno uÄitavanje da biste ponovo poslali podatke koji su potrebni za uÄitavanje stranice.</translation>
<translation id="3228969707346345236">Prijevod nije uspio jer stranica već je na jeziku: <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Unesite CVC za karticu <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">OznaÄi ovu stranicu</translation>
<translation id="3270847123878663523">&amp;Poništi promjenu rasporeda</translation>
<translation id="3286538390144397061">Ponovo pokreni sad</translation>
+<translation id="3303855915957856445">Nisu pronađeni rezultati pretraživanja</translation>
<translation id="3305707030755673451">Vaši su podaci šifrirani vašom šifrom za sinkronizaciju <ph name="TIME" />. Unesite je da biste pokrenuli sinkronizaciju.</translation>
<translation id="333371639341676808">SprijeÄite ovu stranicu od stvaranja dodatnih dijaloga.</translation>
+<translation id="3338095232262050444">Sigurno</translation>
<translation id="3340978935015468852">postavke</translation>
<translation id="3345135638360864351">Slanje zahtjeva za pristup ovoj web-lokaciji korisniku <ph name="NAME" /> nije uspjelo. Pokušaj ponovo.</translation>
<translation id="3355823806454867987">Promijeni proxy postavke...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Dohvati interval:</translation>
<translation id="3462200631372590220">Sakrij napredno</translation>
<translation id="3479539252931486093">Niste to oÄekivali? <ph name="BEGIN_LINK" />Javite nam<ph name="END_LINK" />.</translation>
+<translation id="3479552764303398839">Ne sada</translation>
<translation id="348000606199325318">ID rušenja <ph name="CRASH_LOCAL_ID" /> (ID poslužitelja: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Nismo uspjeli stupiti u kontakt s tvojim roditeljem. Pokušaj ponovo.</translation>
<translation id="3527085408025491307">Mapa</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Upotrijebite zaporku za:</translation>
<translation id="3549644494707163724">Å ifriranje svih sinkroniziranih podataka vlastitom zaporkom za sinkronizaciju</translation>
<translation id="3549761410225185768">Još <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer sigurnosni certifikat potjeÄe s domene <ph name="DOMAIN2" />. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Vaša veza nije privatna</translation>
<translation id="3583757800736429874">&amp;Ponovi premještanje</translation>
<translation id="3586931643579894722">Sakrij detalje</translation>
@@ -250,12 +256,15 @@
<translation id="362276910939193118">Pokaži cijelu povijest</translation>
<translation id="3623476034248543066">Prikaži vrijednost</translation>
<translation id="3630155396527302611">Ako je već navedena kao program koji smije pristupiti mreži, pokušajte je ukloniti s popisa pa je ponovo dodati.</translation>
+<translation id="3638794133396384728">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat istekao. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. Sat raÄunala trenutaÄno je postavljen na <ph name="CURRENT_TIME" />. Je li to toÄno? Ako nije, trebali biste ispraviti sat sustava i osvježiti stranicu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Te eksperimentalne znaÄajke mogu se promijeniti, pokvariti ili nestati u bilo kojem trenutku. Ne dajemo apsolutno nikakva jamstva o tome Å¡to se može dogoditi ako ukljuÄite jedan od tih eksperimenata, a vaÅ¡ preglednik Äak može spontano sagorjeti. Å alu na stranu, vaÅ¡ preglednik može izbrisati sve vaÅ¡e podatke ili vaÅ¡a sigurnost i privatnost mogu biti ugrožene na neoÄekivane naÄine. Svi eksperimenti koje omogućite bit će omogućeni za sve korisnike ovog preglednika. Nastavite uz oprez.</translation>
<translation id="3650584904733503804">Valjanost je uspješna</translation>
<translation id="3655670868607891010">Ako se to Äesto prikazuje, pokuÅ¡ajte <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Izmjena</translation>
+<translation id="3678029195006412963">Zahtjev nije bilo moguće potpisati</translation>
<translation id="3681007416295224113">Podaci o certifikatu</translation>
<translation id="3693415264595406141">Zaporka:</translation>
+<translation id="3696411085566228381">ništa</translation>
<translation id="3700528541715530410">Ups, Äini se da nemate dozvolu za pristup toj stranici.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">UÄitavanje...</translation>
@@ -263,7 +272,6 @@
<translation id="3714780639079136834">ukljuÄite mobilne podatke ili Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />provjerite proxy, vatrozid i konfiguraciju DNS-a<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Veza koju ste kopirali</translation>
-<translation id="3744899669254331632">TrenutaÄno ne možete otvoriti <ph name="SITE" /> jer je web-lokacija poslala Å¡ifrirane vjerodajnice koje Chromium ne može obraditi. Mrežne pogreÅ¡ke i napadi obiÄno su privremeni, tako da će stranica kasnije vjerojatno funkcionirati.</translation>
<translation id="375403751935624634">Prijevod nije uspio zbog poslužiteljske pogreške.</translation>
<translation id="3759461132968374835">Nemate nedavnih izvješća o padu. Ovdje se neće prikazati padovi do kojih je došlo kada je izvješćivanje o padovima onemogućeno.</translation>
<translation id="3788090790273268753">Certifikat za ovu web-lokaciju istjeÄe 2016., a lanac certifikata sadrži certifikat s SHA-1 potpisom.</translation>
@@ -275,19 +283,25 @@
<translation id="3884278016824448484">Identifikator uređaja sukobljen je</translation>
<translation id="3885155851504623709">Župa</translation>
<translation id="3901925938762663762">Kartica je istekla</translation>
+<translation id="3910267023907260648">PokuÅ¡ali ste otvoriti <ph name="DOMAIN" />, ali poslužitelj je prikazao certifikat potpisan slabim algoritmom potpisa. To znaÄi da su sigurnosne vjerodajnice koje je poslužitelj prikazao možda krivotvorene, a poslužitelj možda nije onaj koji oÄekujete (možda komunicirate s napadaÄem). <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan sutra. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.}one{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan # dan u budućnosti. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.}few{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan # dana u budućnosti. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.}other{Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer je sigurnosni certifikat navodno izdan # dana u budućnosti. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">UÄitavanje dokumenta PDF nije uspjelo</translation>
<translation id="3963721102035795474">NaÄin ÄitaÄa</translation>
+<translation id="397105322502079400">IzraÄun u tijeku…</translation>
<translation id="3973234410852337861">Host <ph name="HOST_NAME" /> je blokiran</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 web-stranica u blizini}one{# web-stranica u blizini}few{# web-stranice u blizini}other{# web-stranica u blizini}}</translation>
<translation id="4021036232240155012">DNS je mrežna usluga koja prevodi naziv web-lokacije u njezinu internetsku adresu.</translation>
<translation id="4030383055268325496">&amp;Poništi dodavanje</translation>
-<translation id="4032534284272647190">Odbijen je pristup na <ph name="URL" />.</translation>
<translation id="404928562651467259">UPOZORENJE</translation>
<translation id="4058922952496707368">Stavka "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Klijent i poslužitelj ne podržavaju uobiÄajenu verziju SSL protokola ili paket Å¡ifri.</translation>
<translation id="4079302484614802869">Konfiguracija proxy poslužitelja postavljena je za upotrebu URL-a .pac skripte, a ne fiksnih proxy poslužitelja.</translation>
<translation id="4103249731201008433">Serijski broj uređaja nije važeći</translation>
<translation id="4103763322291513355">Posjetite &lt;strong&gt;chrome://policy&lt;/strong&gt; da biste vidjeli popis nedopuštenih URL-ova i druga pravila koja je nametnuo vaš administrator sustava.</translation>
+<translation id="4110615724604346410">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer sigurnosni certifikat sadrži pogreške. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Opseg pravila nije podržan.</translation>
+<translation id="4118212371799607889">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer Chromium sigurnosni certifikat ne smatra pouzdanim. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 druga stavka}one{# druga stavka}few{# druge stavke}other{# drugih stavki}}</translation>
<translation id="4130226655945681476">provjerite mrežne kabele, modem i usmjerivaÄ</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Želite li da Chromium spremi tu karticu?</translation>
@@ -295,6 +309,7 @@
<translation id="4176463684765177261">Onemogućeno</translation>
<translation id="4196861286325780578">&amp;Ponovi premještanje</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />provjerite vatrozid i konfiguraciju antivirusnog programa<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{ništa}=1{1 aplikacija ($1)}=2{2 aplikacije ($1, $2)}one{# aplikacija ($1, $2, $3)}few{# aplikacije ($1, $2, $3)}other{# aplikacija ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Padovi programa</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Pokušajte pokrenuti Mrežnu dijagnostiku<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Ne</translation>
@@ -303,14 +318,15 @@
<translation id="4269787794583293679">(Nema korisniÄkog imena)</translation>
<translation id="4300246636397505754">Nadređeni prijedlozi</translation>
<translation id="4304224509867189079">Prijavi se</translation>
+<translation id="432290197980158659">Poslužitelj je prikazao certifikat koji ne odgovara ugraÄ‘enim oÄekivanjima. Ta su oÄekivanja ukljuÄena za odreÄ‘ene web-lokacije visoke razine sigurnosti radi vaÅ¡e zaÅ¡tite. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Članak nije pronađen</translation>
+<translation id="4331708818696583467">Nije sigurno</translation>
<translation id="4372948949327679948">OÄekivana vrijednost vrste <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">PokuÅ¡ali ste doseći domenu <ph name="DOMAIN" />, ali certifikat koji je poslužitelj predstavio povuÄen je od strane izdavaÄa. Prema tome nikako ne biste trebali vjerovati sigurnosnim certifikatima koje predstavlja poslužitelj. Možda komunicirate s napadaÄem.</translation>
<translation id="4381091992796011497">Ime korisnika:</translation>
<translation id="4394049700291259645">Onemogući</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> – <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">rezultati pretraživanja</translation>
-<translation id="4424024547088906515">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; Chrome smatra da njegov sigurnosni certifikat nije pouzdan. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
+<translation id="4432688616882109544">Host <ph name="HOST_NAME" /> nije prihvatio vaš certifikat za prijavu ili certifikat nije poslan.</translation>
<translation id="443673843213245140">Upotreba proxy poslužitelja onemogućena je, ali odreÄ‘ena je izriÄita konfiguracija proxy poslužitelja.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Ova ti se poruka prikazuje zato što je omogućen Google SafeSites.</translation>
@@ -322,12 +338,12 @@
<translation id="4522570452068850558">Detalji</translation>
<translation id="4558551763791394412">Pokušajte onemogućiti proširenja.</translation>
<translation id="4587425331216688090">Želite li s Chromea ukloniti adresu?</translation>
+<translation id="4589078953350245614">Pokušali ste otvoriti <ph name="DOMAIN" />, ali poslužitelj je prikazao nevažeći certifikat. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Vaša veza s domenom <ph name="DOMAIN" /> kriptirana je modernim kriptografskim paketom.</translation>
<translation id="4594403342090139922">&amp;Poništi brisanje</translation>
+<translation id="4627442949885028695">Nastavite na drugom uređaju</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Gledate stranicu proširenja.</translation>
-<translation id="467662567472608290">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; njegov sigurnosni certifikat sadrži pogreške. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
-<translation id="4697214168136963651">Zahtjev <ph name="URL" /> bio je blokiran</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Veza je prekinuta</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />pokrenuti Mrežnu dijagnostiku sustava Windows<ph name="END_LINK" /></translation>
@@ -335,21 +351,26 @@
<translation id="4728558894243024398">Platforma</translation>
<translation id="4744603770635761495">Izvršna putanja</translation>
<translation id="4756388243121344051">&amp;Povijest</translation>
+<translation id="4759238208242260848">Preuzimanje</translation>
<translation id="4764776831041365478">Web-stranica na adresi <ph name="URL" /> možda privremeno nije dostupna ili je trajno preseljena na novu web-adresu.</translation>
<translation id="4771973620359291008">Došlo je do nepoznate pogreške.</translation>
<translation id="4782449893814226250">Pitao si roditelje smiješ li otvoriti tu stranicu.</translation>
<translation id="4800132727771399293">Provjerite datum isteka i CVC pa pokušajte ponovo</translation>
-<translation id="4807049035289105102">TrenutaÄno ne možete posjetiti <ph name="SITE" /> jer je web-lokacija poslala kodirane vjerodajnice koje Google Chrome ne može obraditi. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će ta stranica vjerojatno kasnije funkcionirati.</translation>
<translation id="4813512666221746211">Pogreška mreže</translation>
<translation id="4816492930507672669">Prilagodi stranici</translation>
<translation id="4850886885716139402">Prikaz</translation>
<translation id="4880827082731008257">Pretraži povijest</translation>
+<translation id="4884656795097055129">U odgovarajućem će se trenutku prikazati viÅ¡e Älanaka.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{i još 1 web-stranica}one{i još # web-stranica}few{i još # web-stranice}other{i još # web-stranica}}</translation>
<translation id="4923417429809017348">Ova je stranica prevedena s nepoznatog jezika na <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Mora biti određeno.</translation>
<translation id="4930497775425430760">Ova ti se poruka prikazuje zato što tvoj roditelj mora odobriti web-lokacije koje posjećuješ prvi put.</translation>
<translation id="495170559598752135">Radnje</translation>
<translation id="4958444002117714549">Proširi popis</translation>
+<translation id="4962322354953122629">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer Chrome sigurnosni certifikat ne smatra pouzdanim. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Želite li prijevod s jezika <ph name="ORIGINAL_LANGUAGE" /> na <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Taj dodatak nije podržan</translation>
<translation id="5002932099480077015">Ako je to omogućeno, Chrome će pohraniti kopiju vaše kartice na ovom uređaju radi bržeg ispunjavanja obrazaca.</translation>
<translation id="5019198164206649151">Sigurnosno pohranjivanje u neispravnom je stanju</translation>
<translation id="5023310440958281426">Provjerite pravila svojeg administratora</translation>
@@ -357,13 +378,12 @@
<translation id="5031870354684148875">O Google Prevoditelju</translation>
<translation id="5040262127954254034">Privatnost</translation>
<translation id="5045550434625856497">Pogrešna zaporka</translation>
+<translation id="5056549851600133418">PreporuÄeni Älanci</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />provjerite proxy adresu<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Certifikat poslužitelja trenutaÄno nije važeći.</translation>
<translation id="5089810972385038852">Država</translation>
-<translation id="5094747076828555589">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; Chromium smatra da njegov sigurnosni certifikat nije pouzdan. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="5095208057601539847">Provincija</translation>
<translation id="5115563688576182185">(64-bitni)</translation>
-<translation id="5122371513570456792">Pronađeno <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> za "<ph name="SEARCH_STRING" />".</translation>
<translation id="5141240743006678641">Å ifriranje sinkroniziranih zaporki s vjerodajnicama za Google</translation>
<translation id="5145883236150621069">Odgovor na pravilo sadrži kĂ´d pogreÅ¡ke</translation>
<translation id="5171045022955879922">Pretražite ili upišite URL</translation>
@@ -372,18 +392,18 @@
<translation id="5190835502935405962">Traka oznaka</translation>
<translation id="5199729219167945352">Eksperimenti</translation>
<translation id="5251803541071282808">Oblak</translation>
+<translation id="5277279256032773186">Upotrebljavate li Chrome na poslu? Tvrtke mogu upravljati Chromeovim postavkama za svoje zaposlenike. Saznajte više</translation>
<translation id="5299298092464848405">Pogreška u pravilu analize</translation>
<translation id="5300589172476337783">Prikaži</translation>
<translation id="5308689395849655368">Onemogućeno je izvješćivanje o padu.</translation>
<translation id="5317780077021120954">Spremi</translation>
<translation id="5327248766486351172">Naziv</translation>
+<translation id="5359637492792381994">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer sigurnosni certifikat trenutaÄno nije važeći. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Pohrana postavki pravila nije uspjela</translation>
-<translation id="540969355065856584">Poslužitelj nije uspio dokazati da je <ph name="DOMAIN" />; njegov sigurnosni certifikat trenutaÄno nije važeći. Uzrok tomu može biti pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vaÅ¡u vezu.</translation>
<translation id="5421136146218899937">Obriši podatke pregledavanja...</translation>
<translation id="5430298929874300616">Ukloni oznaku</translation>
<translation id="5431657950005405462">Datoteka nije pronađena</translation>
<translation id="5435775191620395718">Prikazuje se povijest s ovog uređaja. <ph name="BEGIN_LINK" />Saznajte više<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Prijedlozi prilagoÄ‘enog sadržaja trenutaÄno su onemogućeni jer su sinkronizirani podaci zaÅ¡tićeni prilagoÄ‘enom zaporkom.</translation>
<translation id="5439770059721715174">Pogreška provjere sheme na lokaciji "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Tu stranicu na <ph name="HOST_NAME" /> nije moguće pronaći</translation>
<translation id="5455374756549232013">Vremenska oznaka pravila koje nije valjano</translation>
@@ -406,14 +426,18 @@
<translation id="5622887735448669177">Želite li zatvoriti tu web-lokaciju?</translation>
<translation id="5629630648637658800">UÄitavanje postavki pravila nije uspjelo</translation>
<translation id="5631439013527180824">Token za upravljanje uređajem nije važeći</translation>
-<translation id="5650551054760837876">Nisu pronađeni rezultati pretraživanja.</translation>
<translation id="5677928146339483299">Blokirano</translation>
<translation id="5710435578057952990">Identitet ove web lokacije nije ovjeren.</translation>
<translation id="5720705177508910913">TrenutaÄni korisnik:</translation>
+<translation id="572328651809341494">Nedavne kartice</translation>
<translation id="5784606427469807560">Pojavio se problem prilikom potvrđivanja kartice. Provjerite internetsku vezu i pokušajte ponovo.</translation>
<translation id="5785756445106461925">Nadalje, ova stranica sadrži druge resurse koji nisu sigurni. Te resurse mogu vidjeti drugi tijekom prijenosa i napadaÄ ih može izmijeniti kako bi promijenio izgled stranice.</translation>
+<translation id="5786044859038896871">Želite li ispuniti podatke o kartici?</translation>
+<translation id="5803412860119678065">Želite li ispuniti podatke o kartici <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Vaša veza s domenom <ph name="DOMAIN" /> kriptirana je zastarjelim kriptografskim paketom.</translation>
<translation id="5813119285467412249">&amp;Ponovi dodavanje</translation>
+<translation id="5814352347845180253">Možda ćete izgubiti pristup premium sadržaju s web-lokacije <ph name="SITE" /> i nekih drugih web-lokacija.</translation>
+<translation id="5843436854350372569">PokuÅ¡ali ste otvoriti <ph name="DOMAIN" />, ali poslužitelj je prikazao certifikat sa slabim kljuÄem. Privatni je kljuÄ možda otkriven, a poslužitelj možda nije onaj koji oÄekujete (možda komunicirate s napadaÄem). <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Ova ti se poruka prikazuje zato Å¡to je tvoj upravitelj blokirao ovu web-lokaciju.</translation>
<translation id="5857090052475505287">Nova mapa</translation>
<translation id="5869405914158311789">Web-lokacija ne može se dohvatiti</translation>
@@ -421,6 +445,7 @@
<translation id="5872918882028971132">Nadređeni prijedlozi</translation>
<translation id="59107663811261420">Google Payments ne podržava tu vrstu kartice za ovog trgovca. Odaberite neku drugu karticu.</translation>
<translation id="59174027418879706">Omogućeno</translation>
+<translation id="5926846154125914413">Možda ćete izgubiti pristup premium sadržaju s nekih web-lokacija.</translation>
<translation id="5966707198760109579">Tjedan</translation>
<translation id="5967867314010545767">Ukloni iz povijesti</translation>
<translation id="5975083100439434680">Smanji</translation>
@@ -432,12 +457,12 @@
<translation id="604124094241169006">Automatski</translation>
<translation id="6042308850641462728">Više</translation>
<translation id="6060685159320643512">Oprez, ovi eksperimenti mogu ugristi</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{ništa}=1{1}one{#}few{#}other{#}}</translation>
<translation id="6146055958333702838">Provjerite kabele i ponovo pokrenite usmjerivaÄe, modeme ili druge mrežne
uređaje koje možda upotrebljavate.</translation>
<translation id="614940544461990577">Pokušajte sljedeće:</translation>
<translation id="6150607114729249911">Ups! Moraš pitati roditelje smiješ li otvoriti ovu stranicu.</translation>
<translation id="6151417162996330722">Certifikat poslužitelja ima predugo razdoblje valjanosti.</translation>
-<translation id="6154808779448689242">Vraćeni token pravila ne odgovara trenutaÄnom tokenu</translation>
<translation id="6165508094623778733">Saznajte više</translation>
<translation id="6203231073485539293">Provjerite internetsku vezu</translation>
<translation id="6218753634732582820">Želite li ukloniti adresu iz Chromiuma?</translation>
@@ -450,24 +475,30 @@
<translation id="6328639280570009161">Pokušajte onemogućiti predviđanja mreže</translation>
<translation id="6337534724793800597">Filtriranje pravila prema nazivu</translation>
<translation id="6342069812937806050">Samo sad</translation>
+<translation id="6345221851280129312">nepoznata veliÄina</translation>
<translation id="6355080345576803305">NadjaÄavanje javne sesije</translation>
<translation id="6358450015545214790">Å to to znaÄi?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 drugi prijedlog}one{# drugi prijedlog}few{# druga prijedloga}other{# drugih prijedloga}}</translation>
<translation id="6387478394221739770">Zanimaju li vas nove, kul znaÄajke preglednika Chrome? Isprobajte naÅ¡ beta kanal na stranici chrome.com/beta.</translation>
-<translation id="641480858134062906">Adresa <ph name="URL" /> nije uÄitana</translation>
+<translation id="6389758589412724634">Chromium je ostao bez memorije dok je pokušavao prikazati ovu web-stranicu.</translation>
+<translation id="6416403317709441254">TrenutaÄno ne možete otvoriti <ph name="SITE" /> jer je web-lokacija poslala kodirane vjerodajnice koje Chromium ne može obraditi. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će ta stranica vjerojatno kasnije funkcionirati. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Nije moguće provjeriti je li certifikat opozvan.</translation>
<translation id="6433595998831338502">Host <ph name="HOST_NAME" /> odbio je povezivanje.</translation>
<translation id="6445051938772793705">Zemlja</translation>
<translation id="6451458296329894277">Potvrdi ponovno slanje obrasca</translation>
<translation id="6458467102616083041">Zanemareno jer je zadano pretraživanje onemogućeno pravilom.</translation>
+<translation id="6462969404041126431">Poslužitelj ne može dokazati da je to <ph name="DOMAIN" /> jer bi sigurnosni certifikat mogao biti opozvan. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Pravila uređaja</translation>
<translation id="6489534406876378309">Pokreni prijenos rušenja</translation>
<translation id="6529602333819889595">&amp;Ponovi brisanje</translation>
+<translation id="6534179046333460208">Prijedlozi FiziÄkog weba</translation>
<translation id="6550675742724504774">Opcije</translation>
+<translation id="6593753688552673085">manje od <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opcije Å¡ifriranja</translation>
<translation id="662080504995468778">Ostani</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Pretraživanje</translation>
-<translation id="6634865548447745291">TrenutaÄno ne možete posjetiti <ph name="SITE" /> jer je <ph name="BEGIN_LINK" />taj certifikat opozvan<ph name="END_LINK" />. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni i ta bi stranica kasnije trebala funkcionirati.</translation>
<translation id="6644283850729428850">Ovo je pravilo zastarjelo.</translation>
+<translation id="6652240803263749613">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer operativni sustav raÄunala sigurnosni certifikat ne smatra pouzdanim. Razlog može biti pogreÅ¡na konfiguracija ili napad na vaÅ¡u vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Uređivanje mape</translation>
<translation id="6660210980321319655">Automatski prijavljeno <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Želite li ukloniti prijedlog iz Chromiuma?</translation>
@@ -475,6 +506,7 @@
<translation id="6710213216561001401">Prethodno</translation>
<translation id="6710594484020273272">&lt;Upišite pojam za pretraživanje&gt;</translation>
<translation id="6711464428925977395">NeÅ¡to nije u redu s proxy poslužiteljem ili adresa nije toÄna.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{ništa}=1{1 stavka}one{# stavka}few{# stavke}other{# stavki}}</translation>
<translation id="674375294223700098">Nepoznata pogreška certifikata poslužitelja</translation>
<translation id="6753269504797312559">Vrijednost pravila</translation>
<translation id="6757797048963528358">Uređaj je u stanju mirovanja.</translation>
@@ -486,7 +518,6 @@
<translation id="6891596781022320156">Razina pravila nije podržana.</translation>
<translation id="6895330447102777224">Kartica je potvrđena</translation>
<translation id="6897140037006041989">KorisniÄki agent</translation>
-<translation id="6903907808598579934">UkljuÄi sinkronizaciju</translation>
<translation id="6915804003454593391">Korisnik:</translation>
<translation id="6957887021205513506">Certifikat poslužitelja izgleda kao falsifikat.</translation>
<translation id="6965382102122355670">U redu</translation>
@@ -494,9 +525,11 @@
<translation id="6970216967273061347">Distrikt</translation>
<translation id="6973656660372572881">Određeni su fiksni proxy poslužitelji i URL .pac skripte.</translation>
<translation id="6989763994942163495">Pokaži napredne postavke...</translation>
+<translation id="7000990526846637657">Unosi povijesti nisu pronađeni</translation>
+<translation id="7009986207543992532">PokuÅ¡ali ste otvoriti <ph name="DOMAIN" />, ali poslužitelj je prikazao certifikat Äije je razdoblje valjanosti predugo da bi bilo vjerodostojno. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Na Google raÄunu možda postoje drugi oblici povijesti pregledavanja na stranici <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Zaporke</translation>
-<translation id="7050187094878475250">Pokušali ste pristupiti domeni <ph name="DOMAIN" />, ali je poslužitelj pružio certifikat koji nije pouzdan zbog predugog razdoblja valjanosti.</translation>
<translation id="7087282848513945231">Županija</translation>
<translation id="7088615885725309056">Starije</translation>
<translation id="7090678807593890770">Potražite upit <ph name="LINK" /> na Googleu</translation>
@@ -515,13 +548,13 @@
<translation id="7246609911581847514">Ova ti se poruka prikazuje jer tvoj upravitelj mora odobriti web-lokacije koje posjećuješ prvi put.</translation>
<translation id="724975217298816891">Unesite datum isteka i CVC za karticu <ph name="CREDIT_CARD" /> da biste ažurirali podatke o kartici. Nakon što ih potvrdite, podaci o kartici dijelit će se s ovom web-lokacijom.</translation>
<translation id="725866823122871198">Sigurnu vezu s domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nije moguće uspostaviti jer datum i vrijeme na raÄunalu (<ph name="DATE_AND_TIME" />) nisu toÄni.</translation>
-<translation id="7265986070661382626">TrenutaÄno ne možete posjetiti <ph name="SITE" /> jer web-lokacija <ph name="BEGIN_LINK" />upotrebljava prikvaÄivanje certifikata<ph name="END_LINK" />. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će stranica vjerojatno kasnije funkcionirati.</translation>
<translation id="7269802741830436641">Ova web-stranica ima petlju za preusmjeravanje</translation>
<translation id="7275334191706090484">Upravljane oznake</translation>
<translation id="7298195798382681320">PreporuÄeno</translation>
-<translation id="7301833672208172928">UkljuÄi sinkronizaciju povijesti</translation>
+<translation id="7309308571273880165">Izvješće o rušenju programa generirano <ph name="CRASH_TIME" /> (prijenos zatražio korisnik, još nije preneseno)</translation>
<translation id="7334320624316649418">&amp;Ponovi promjenu rasporeda</translation>
<translation id="733923710415886693">Certifikat poslužitelja nije otkriven putem Transparentnosti certifikata.</translation>
+<translation id="7351800657706554155">TrenutaÄno ne možete otvoriti <ph name="SITE" /> jer je certifikat te web-lokacije opozvan. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će stranica vjerojatno kasnije funkcionirati. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Naredbeni redak</translation>
<translation id="7372973238305370288">rezultat pretraživanja</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -540,16 +573,17 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="7469372306589899959">Potvrđivanje kartice</translation>
<translation id="7481312909269577407">Naprijed</translation>
<translation id="7485870689360869515">Nema pronađenih podataka.</translation>
+<translation id="7508255263130623398">Vraćeni ID ureÄ‘aja pravila prazan je ili ne odgovara trenutaÄnom ID-u ureÄ‘aja</translation>
<translation id="7514365320538308">Preuzmi</translation>
<translation id="7518003948725431193">Za web-adresu nije pronađena web-stranica:<ph name="URL" /></translation>
<translation id="7537536606612762813">Obavezno</translation>
<translation id="7542995811387359312">Automatsko popunjavanje kreditne kartice onemogućeno je jer se ovaj obrazac ne služi sigurnom vezom.</translation>
<translation id="7549584377607005141">Ova web-stranica zahtijeva podatke koje ste ranije unijeli da bi se pravilno prikazala. Te podatke možete poslati ponovo, ali time ćete ponoviti sve radnje koje je ta stranica prethodno izvela.</translation>
<translation id="7554791636758816595">Nova kartica</translation>
-<translation id="7567204685887185387">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; njegov sigurnosni certifikat možda je lažan. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="7568593326407688803">Ova je stranica na ovom jeziku:<ph name="ORIGINAL_LANGUAGE" />Želite li je prevesti?</translation>
<translation id="7569952961197462199">Želite li s Chromea ukloniti kreditnu karticu?</translation>
<translation id="7578104083680115302">Plaćajte brzo na web-lokacijama i u aplikacijama na više uređaja karticama koje ste spremili na Google.</translation>
+<translation id="7588950540487816470">FiziÄki web</translation>
<translation id="7592362899630581445">Certifikat poslužitelja krÅ¡i ograniÄenja naziva.</translation>
<translation id="759889825892636187">Host <ph name="HOST_NAME" /> trenutaÄno ne može obraditi zahtjev.</translation>
<translation id="7600965453749440009">Nikad ne prevodi <ph name="LANGUAGE" /></translation>
@@ -560,6 +594,7 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="7637571805876720304">Želite li ukloniti kreditnu karticu iz Chromiuma?</translation>
<translation id="765676359832457558">Skrivanje naprednih postavki...</translation>
<translation id="7658239707568436148">Odustani</translation>
+<translation id="7667346355482952095">Vraćeni token pravila prazan je ili ne odgovara trenutaÄnom tokenu</translation>
<translation id="7668654391829183341">Nepoznati uređaj</translation>
<translation id="7674629440242451245">Zanimaju li vas nove, kul znaÄajke preglednika Chrome? Isprobajte naÅ¡ razvojni kanal na stranici chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Idi na web-lokaciju <ph name="SITE" /> (nije sigurno)<ph name="END_LINK" /></translation>
@@ -576,10 +611,10 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="780301667611848630">Ne, hvala</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7813600968533626083">Želite li s Chromea ukloniti prijedlog za obrasce?</translation>
+<translation id="7815407501681723534">Pronađeno <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> za "<ph name="SEARCH_STRING" />"</translation>
<translation id="785549533363645510">Niste nevidljivi. Anonimni naÄin ne sakriva vaÅ¡e pregledavanje od poslodavca, davatelja internetskih usluga ili posjećenih web-lokacija.</translation>
<translation id="7887683347370398519">Provjerite CVC i pokušajte ponovo</translation>
<translation id="7894616681410591072">Ups! <ph name="NAME" /> mora odobriti pristup ovoj stranici.</translation>
-<translation id="790025292736025802"><ph name="URL" /> nije pronađena</translation>
<translation id="7912024687060120840">U mapi:</translation>
<translation id="7920092496846849526">Pitao si roditelja smiješ li otvoriti tu stranicu.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -592,9 +627,10 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="7995512525968007366">Nije navedeno</translation>
<translation id="8012647001091218357">Nismo uspjeli stupiti u kontakt s tvojim roditeljima. Pokušaj ponovo.</translation>
<translation id="8034522405403831421">Jezik ove stranice jest <ph name="SOURCE_LANGUAGE" />. Želite li je prevesti na <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Unosi povijesti nisu pronađeni.</translation>
<translation id="8088680233425245692">Prikaz Älanka nije uspio.</translation>
+<translation id="8089520772729574115">manje od 1 MB</translation>
<translation id="8091372947890762290">Aktivacija je na Äekanju na poslužitelju</translation>
+<translation id="8129262335948759431">nepoznata koliÄina</translation>
<translation id="8131740175452115882">Potvrdi</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />DNS adresa<ph name="END_ABBR" /> poslužitelja hosta <ph name="HOST_NAME" /> nije pronađena.</translation>
<translation id="8149426793427495338">RaÄunalo je u stanju mirovanja.</translation>
@@ -603,6 +639,7 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="8201077131113104583">Nevažeći URL ažuriranja za proširenje s ID-om "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Dodijeljena lokacija:</translation>
<translation id="8225771182978767009">Osoba koja je postavila raÄunalo blokirala je tu web-lokaciju.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Stranica koju ste tražili koristila je podatke koje ste unijeli. Vraćanje na tu stranicu može dovesti do ponavljanja poduzete radnje. Želite li nastaviti?</translation>
<translation id="8249320324621329438">Zadnje dohvaćanje:</translation>
<translation id="8261506727792406068">Izbriši</translation>
@@ -615,12 +652,17 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="8349305172487531364">Traka oznaka</translation>
<translation id="8363502534493474904">iskljuÄite naÄin rada u zrakoplovu</translation>
<translation id="8364627913115013041">Nije postavljeno.</translation>
+<translation id="8380941800586852976">Opasno</translation>
<translation id="8412145213513410671">Padovi (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Morate dvaput unijeti istu zaporku.</translation>
<translation id="8428213095426709021">Postavke</translation>
+<translation id="8433057134996913067">Time ćete se odjaviti s većine web-lokacija.</translation>
<translation id="8437238597147034694">&amp;Poništi premještanje</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kreditna kartica}one{# kreditna kartica}few{# kreditne kartice}other{# kreditnih kartica}}</translation>
+<translation id="8483780878231876732">Da biste upotrebljavali kartice sa svojeg Google raÄuna, prijavite se na Chrome</translation>
<translation id="8488350697529856933">Primjenjuje se na</translation>
<translation id="8498891568109133222">Hostu <ph name="HOST_NAME" /> bilo je potrebno previše vremena za odgovor.</translation>
+<translation id="852346902619691059">Poslužitelj nije mogao dokazati da je to <ph name="DOMAIN" /> jer operativni sustav uređaja sigurnosni certifikat ne smatra pouzdanim. Razlog može biti pogrešna konfiguracija ili napad na vašu vezu. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Google Payments ne podržava tu vrstu kartice. Odaberite neku drugu karticu.</translation>
<translation id="8550022383519221471">Usluga sinkroniziranja nije dostupna za vašu domenu.</translation>
<translation id="8553075262323480129">Prijevod nije uspio jer nije bilo moguće odrediti jezik stranice.</translation>
@@ -632,15 +674,12 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="8647750283161643317">Vrati sve na zadano</translation>
<translation id="8680787084697685621">Pojedinosti prijave na raÄun su zastarjele.</translation>
<translation id="8703575177326907206">Vaša veza s <ph name="DOMAIN" /> nije šifrirana.</translation>
-<translation id="8713130696108419660">PogreÅ¡an poÄetni potpis</translation>
<translation id="8725066075913043281">Pokušajte ponovo</translation>
<translation id="8728672262656704056">Radite u anonimnom naÄinu</translation>
<translation id="8730621377337864115">Gotovo</translation>
<translation id="8738058698779197622">Za uspostavu sigurne veze sat mora biti toÄno postavljen. To je zato Å¡to certifikati koje web-lokacije upotrebljavaju za meÄ‘usobnu identifikaciju vrijede samo odreÄ‘eno vrijeme. Budući da sat na vaÅ¡em ureÄ‘aju nije toÄan, Chromium ne može potvrditi te certifikate.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS adresa&lt;/abbr&gt; hosta <ph name="HOST_NAME" /> nije pronađena. U tijeku je dijagnosticiranje problema.</translation>
-<translation id="8741995161408053644">Na Google raÄunu možda postoje drugi oblici povijesti pregledavanja na stranici <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Ponovi brisanje</translation>
-<translation id="8790687370365610530">UkljuÄite sinkronizaciju povijesti ako želite da vam Google predlaže sadržaje.</translation>
<translation id="8798099450830957504">Zadano</translation>
<translation id="8804164990146287819">Pravila o privatnosti</translation>
<translation id="8820817407110198400">Knjižne oznake</translation>
@@ -662,13 +701,11 @@ Psst! Sljedeći bi vam put mogao koristiti anonimni naÄin <ph name="SHORTCUT_KE
<translation id="8971063699422889582">Istekao je certifikat poslužitelja.</translation>
<translation id="8987927404178983737">Mjesec</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Poslužitelj je prikazao certifikat koji nije javno otkriven putem pravila Transparentnost certifikata. Taj se zahtjev postavlja za neke certifikate radi provjere njihove pouzdanosti i zaštite od napada.</translation>
<translation id="9001074447101275817">Proxy <ph name="DOMAIN" /> zahtijeva korisniÄko ime i zaporku.</translation>
<translation id="901974403500617787">Oznake koje se primjenjuju na razini sustava može postaviti samo vlasnik: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Ova je stranica prevedena na <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Upotreba usluge predviÄ‘anja za brže uÄitavanje stranica</translation>
<translation id="9039213469156557790">Nadalje, ova stranica sadrži druge resurse koji nisu sigurni. Te resurse mogu vidjeti drugi tijekom prijenosa i napadaÄ ih može izmijeniti kako bi promijenio ponaÅ¡anje stranice.</translation>
-<translation id="9049981332609050619">Pokušali ste pristupiti domeni <ph name="DOMAIN" />, ali poslužitelj je prikazao nevažeći certifikat.</translation>
<translation id="9050666287014529139">Zaporka</translation>
<translation id="9065203028668620118">Uredi</translation>
<translation id="9092364396508701805">Stranica hosta <ph name="HOST_NAME" /> ne funkcionira</translation>
diff --git a/chromium/components/strings/components_strings_hu.xtb b/chromium/components/strings/components_strings_hu.xtb
index 183e64cabac..ee1cda82171 100644
--- a/chromium/components/strings/components_strings_hu.xtb
+++ b/chromium/components/strings/components_strings_hu.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hu">
+<translation id="1008557486741366299">Ne most</translation>
<translation id="1015730422737071372">TovĂ¡bbi rĂ©szletek megadĂ¡sa</translation>
<translation id="1032854598605920125">ForgatĂ¡s jobbra</translation>
<translation id="1038842779957582377">Ismeretlen név</translation>
+<translation id="1053591932240354961">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mivel a webhely olyan titkosĂ­tott hitelesĂ­tĂ©si adatokat kĂ¼ldött, amelyeket a Google Chrome nem tud feldolgozni. A hĂ¡lĂ³zati hibĂ¡k Ă©s tĂ¡madĂ¡sok rendszerint Ă¡tmenetiek, ezĂ©rt az emlĂ­tett oldal kĂ©sÅ‘bb valĂ³szĂ­nűleg mĂ¡r működni fog. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;HozzĂ¡adĂ¡s visszavonĂ¡sa</translation>
<translation id="10614374240317010">Az alĂ¡bbi oldalakrĂ³l soha ne mentsen jelszavakat</translation>
-<translation id="1064422015032085147">A weboldalt tĂ¡rolĂ³ szerver tĂºlterhelt, vagy javĂ­tĂ¡s alatt lehet.
- A tĂºl nagy forgalom Ă©s a helyzet sĂºlyosbĂ­tĂ¡sĂ¡nak elkerĂ¼lĂ©se Ă©rdekĂ©ben
- az erre az URL-re irĂ¡nyulĂ³ kĂ©rĂ©sek Ă¡tmenetileg le lettek tiltva.</translation>
<translation id="106701514854093668">Asztali könyvjelzÅ‘k</translation>
<translation id="1080116354587839789">SzĂ©lessĂ©ghez igazĂ­tĂ¡s</translation>
+<translation id="1103124106085518534">Egyelőre ennyi</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> - mindig legyen lefordĂ­tva</translation>
<translation id="1107591249535594099">Ha be van jelölve, a Chrome ezen az eszközön tĂ¡rolja a kĂ¡rtya egy pĂ©ldĂ¡nyĂ¡t az űrlapok gyorsabb kitöltĂ©sĂ©hez.</translation>
+<translation id="1111153019813902504">LegutĂ³bbi könyvjelzÅ‘k</translation>
<translation id="1113869188872983271">&amp;ĂtrendezĂ©s visszavonĂ¡sa</translation>
+<translation id="1126551341858583091">A helyi tĂ¡rolĂ³ban lĂ©vÅ‘ fĂ¡jl mĂ©rete <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">IrĂ¡nyelv-gyorsĂ­tĂ³tĂ¡r OK</translation>
<translation id="113188000913989374">A(z) <ph name="SITE" /> közlendÅ‘je:</translation>
<translation id="1132774398110320017">A Chrome Automatikus kitöltĂ©si beĂ¡llĂ­tĂ¡sai…</translation>
-<translation id="1150979032973867961">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya az Ă–n szĂ¡mĂ­tĂ³gĂ©pĂ©nek operĂ¡ciĂ³s rendszere szerint nem megbĂ­zhatĂ³. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t.</translation>
<translation id="1152921474424827756">A(z) <ph name="URL" /> egy <ph name="BEGIN_LINK" />tĂ¡rolt vĂ¡ltozatĂ¡nak<ph name="END_LINK" /> megtekintĂ©se</translation>
<translation id="1158211211994409885">A(z) <ph name="HOST_NAME" /> vĂ¡ratlanul megszakĂ­totta a kapcsolatot.</translation>
<translation id="1161325031994447685">ĂjracsatlakozĂ¡s Wi-Fi-hĂ¡lĂ³zathoz</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">EltĂ¡volĂ­tĂ¡s</translation>
<translation id="1201402288615127009">KövetkezÅ‘</translation>
<translation id="1201895884277373915">TovĂ¡bbiak errÅ‘l a webhelyrÅ‘l</translation>
-<translation id="121201262018556460">MegprĂ³bĂ¡lta elĂ©rni a(z) <ph name="DOMAIN" /> webhelyet, de a szerver egy gyenge kulccsal rendelkezÅ‘ tanĂºsĂ­tvĂ¡nyt adott. Egy tĂ¡madĂ³ feltörhette a privĂ¡t kulcsot, Ă©s lehet, hogy a szerver nem a vĂ¡rt kiszolgĂ¡lĂ³ (lehet, hogy Ă–n egy tĂ¡madĂ³val kommunikĂ¡l).</translation>
+<translation id="1206967143813997005">HibĂ¡s alapĂ©rtelmezett alĂ¡Ă­rĂ¡s</translation>
+<translation id="1209206284964581585">Elrejtés most</translation>
<translation id="1219129156119358924">RendszerbiztonsĂ¡g</translation>
<translation id="1227224963052638717">Ismeretlen hĂ¡zirend</translation>
<translation id="1227633850867390598">Érték elrejtése</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Igen</translation>
<translation id="1430915738399379752">NyomtatĂ¡s</translation>
<translation id="1442912890475371290">Letiltott kĂ­sĂ©rlet <ph name="BEGIN_LINK" /> egy oldal felkeresĂ©sĂ©re a következÅ‘ domainen: <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mivel a webhely tanĂºsĂ­tvĂ¡nyrögzĂ­tĂ©st hasznĂ¡l. A hĂ¡lĂ³zati hibĂ¡k Ă©s tĂ¡madĂ¡sok rendszerint Ă¡tmenetiek, ezĂ©rt az emlĂ­tett oldal kĂ©sÅ‘bb valĂ³szĂ­nűleg mĂ¡r működni fog. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Az oldal mentett (pl. köztudottan rĂ©gi) vĂ¡ltozatĂ¡nak megjelenĂ­tĂ©se.</translation>
<translation id="1519264250979466059">Build dĂ¡tuma</translation>
<translation id="1549470594296187301">A funkciĂ³ hasznĂ¡latĂ¡hoz engedĂ©lyezni kell a JavaScriptet.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">A hĂ¡lĂ³zati konfigurĂ¡ciĂ³ Ă©rvĂ©nytelen Ă©s nem importĂ¡lhatĂ³.</translation>
<translation id="1644574205037202324">ElÅ‘zmĂ©nyek</translation>
<translation id="1645368109819982629">Nem tĂ¡mogatott protokoll</translation>
-<translation id="1655462015569774233">{1,plural, =1{A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya tegnap lejĂ¡rt. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, de az is lehet, hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t. SzĂ¡mĂ­tĂ³gĂ©pĂ©nek Ă³rĂ¡ja jelenleg a következÅ‘re van Ă¡llĂ­tva: <ph name="CURRENT_DATE" />. Ez megfelelÅ‘nek tűnik? Ha nem, Ă¡llĂ­tsa be megfelelÅ‘en a rendszer Ă³rĂ¡jĂ¡t, majd frissĂ­tse az oldalt.}other{A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya # nappal ezelÅ‘tt lejĂ¡rt. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, de az is lehet, hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t. SzĂ¡mĂ­tĂ³gĂ©pĂ©nek Ă³rĂ¡ja jelenleg a következÅ‘re van Ă¡llĂ­tva: <ph name="CURRENT_DATE" />. Ez megfelelÅ‘nek tűnik? Ha nem, Ă¡llĂ­tsa be megfelelÅ‘en a rendszer Ă³rĂ¡jĂ¡t, majd frissĂ­tse az oldalt.}}</translation>
<translation id="1676269943528358898">A(z) <ph name="SITE" /> webhely rendes esetben titkosĂ­tĂ¡st alkalmaz az Ă–n adatainak vĂ©delme Ă©rdekĂ©ben. Amikor a Google Chrome most csatlakozni prĂ³bĂ¡lt, a(z) <ph name="SITE" /> webhely szokatlan Ă©s helytelen hitelesĂ­tĂ©si adatokat kĂ¼ldött vissza. Ez olyankor fordulhat elÅ‘, amikor egy tĂ¡madĂ³ megprĂ³bĂ¡lja magĂ¡t kiadni a(z) <ph name="SITE" /> webhelynek, vagy valamilyen Wi-Fi-bejelentkezĂ©si kĂ©pernyÅ‘ megszakĂ­totta a kapcsolatot. Adatai tovĂ¡bbra is biztonsĂ¡gban vannak, mivel a Google Chrome mĂ©g azt megelÅ‘zÅ‘en megszakĂ­totta a kapcsolatot, hogy bĂ¡rmifĂ©le adatcserĂ©re sor kerĂ¼lhetett volna.</translation>
<translation id="168841957122794586">A szervertanĂºsĂ­tvĂ¡ny gyenge titkosĂ­tĂ¡si kulcsot tartalmaz.</translation>
<translation id="1701955595840307032">Javasolt tartalmak fogadĂ¡sa</translation>
-<translation id="1706954506755087368">{1,plural, =1{A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya elmĂ©letileg holnaptĂ³l Ă©rvĂ©nyes. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, de az is lehet, hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t.}other{A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya elmĂ©letileg # nap mĂºlva lĂ©p Ă©rvĂ©nybe. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, de az is lehet, hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">American Express</translation>
<translation id="1734878702283171397">PrĂ³bĂ¡lja felvenni a kapcsolatot a rendszergazdĂ¡val.</translation>
<translation id="17513872634828108">Megnyitott lapok</translation>
<translation id="1753706481035618306">OldalszĂ¡m</translation>
-<translation id="1761412452051366565">A Google Ă¡ltal javasolt, szemĂ©lyre szabott tartalmak fogadĂ¡sĂ¡hoz kapcsolja be a szinkronizĂ¡lĂ¡st.</translation>
-<translation id="1763864636252898013">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya az Ă–n eszközĂ©nek operĂ¡ciĂ³s rendszere szerint nem megbĂ­zhatĂ³. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />PrĂ³bĂ¡lkozzon a Windows HĂ¡lĂ³zati diagnosztika futtatĂ¡sĂ¡val<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">KĂ©rjĂ¼k, frissĂ­tse szinkronizĂ¡lĂ¡si összetett jelszavĂ¡t.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">A közelmĂºltban megnyitott könyvjelzÅ‘k fognak itt megjelenni.</translation>
<translation id="1821930232296380041">Érvénytelen kérés vagy kérésparaméter</translation>
<translation id="1838667051080421715">Jelenleg egy weboldal forrĂ¡sĂ¡t lĂ¡tja.</translation>
<translation id="1871208020102129563">A proxy fix proxyszerverek hasznĂ¡latĂ¡ra van beĂ¡llĂ­tva, nem pedig .pac tĂ­pusĂº szkript URL cĂ­mĂ©nek hasznĂ¡latĂ¡ra.</translation>
<translation id="1883255238294161206">Lista bezĂ¡rĂ¡sa</translation>
<translation id="1898423065542865115">SzűrĂ©s</translation>
-<translation id="1911837502049945214">A(z) <ph name="HOST_NAME" /> nem fogadta el az Ă–n bejelentkezĂ©si tanĂºsĂ­tvĂ¡nyĂ¡t, vagy a bejelentkezĂ©si tanĂºsĂ­tvĂ¡ny lejĂ¡rt.</translation>
<translation id="194030505837763158">UgrĂ¡s ide: <ph name="LINK" /></translation>
<translation id="1962204205936693436">A(z) <ph name="DOMAIN" /> könyvjelzÅ‘i</translation>
<translation id="1973335181906896915">SzerializĂ¡lĂ¡si hiba</translation>
<translation id="1974060860693918893">SpeciĂ¡lis</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{Ă©s 1 tovĂ¡bbi}other{Ă©s # tovĂ¡bbi}}</translation>
<translation id="2025186561304664664">Automatikusan konfigurĂ¡lhatĂ³ra beĂ¡llĂ­tott proxy.</translation>
<translation id="2030481566774242610">Erre gondolt: <ph name="LINK" />?</translation>
<translation id="2031925387125903299">AzĂ©rt kapta ezt az Ă¼zenetet, mert szĂ¼leinek jĂ³vĂ¡ kell hagynia az Ăºj webhelyeket az elsÅ‘ lĂ¡togatĂ¡skor.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />A proxy Ă©s a tűzfal ellenÅ‘rzĂ©se<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">IrĂ¡nyĂ­tĂ³szĂ¡m</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 javaslat}other{# javaslat}}</translation>
<translation id="2065985942032347596">HitelesĂ­tĂ©s szĂ¼ksĂ©ges</translation>
<translation id="2079545284768500474">VisszavonĂ¡s</translation>
<translation id="20817612488360358">A rendszer proxybeĂ¡llĂ­tĂ¡sai konfigurĂ¡lva vannak a hasznĂ¡lathoz, de kifejezett proxykonfigurĂ¡ciĂ³ is meg van adva.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">KönyvjelzÅ‘ szerkesztĂ©se</translation>
<translation id="2166049586286450108">Teljes rendszergazdai hozzĂ¡fĂ©rĂ©s</translation>
<translation id="2166378884831602661">A webhely nem kĂ©pes biztonsĂ¡gos kapcsolatot nyĂºjtani</translation>
-<translation id="2171101176734966184">MegprĂ³bĂ¡lta elĂ©rni a(z) <ph name="DOMAIN" /> webhelyet, de a szerver egy gyenge alĂ¡Ă­rĂ¡si algoritmust hasznĂ¡lĂ³ tanĂºsĂ­tvĂ¡nyt adott. Ez alapjĂ¡n elkĂ©pzelhetÅ‘, hogy a szerver Ă¡ltal megadott biztonsĂ¡gi tanĂºsĂ­tvĂ¡nyt meghamisĂ­tottĂ¡k, Ă©s a szerver nem az, amelyikre szĂ¡mĂ­tott (lehet, hogy Ă©ppen egy tĂ¡madĂ³val kommunikĂ¡l).</translation>
<translation id="2181821976797666341">HĂ¡zirendek</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 cĂ­m}other{# cĂ­m}}</translation>
<translation id="2212735316055980242">Nem talĂ¡lhatĂ³k irĂ¡nyelvek</translation>
<translation id="2213606439339815911">Bejegyzések lekérése...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> nem Ă©rhetÅ‘ el</translation>
<translation id="2230458221926704099">JavĂ­tsa meg kapcsolatĂ¡t a <ph name="BEGIN_LINK" />diagnosztikai alkalmazĂ¡s<ph name="END_LINK" /> segĂ­tsĂ©gĂ©vel</translation>
+<translation id="2239100178324503013">KĂ¼ldĂ©s most</translation>
<translation id="225207911366869382">Ez az Ă©rtĂ©k elavult ennĂ©l a hĂ¡zirendnĂ©l.</translation>
<translation id="2262243747453050782">HTTP hiba</translation>
<translation id="2282872951544483773">Nem elĂ©rhetÅ‘ kĂ­sĂ©rletek</translation>
<translation id="2292556288342944218">Az internethez valĂ³ hozzĂ¡fĂ©rĂ©st a rendszer letiltotta</translation>
<translation id="229702904922032456">LejĂ¡rt egy gyökĂ©r- vagy köztes tanĂºsĂ­tvĂ¡ny.</translation>
<translation id="230155334948463882">Ăj kĂ¡rtya?</translation>
+<translation id="2305919008529760154">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nyĂ¡t csalĂ¡ssal Ă¡llĂ­thattĂ¡k ki. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">A(z) <ph name="DOMAIN" /> felhasznĂ¡lĂ³nevet Ă©s jelszĂ³t kĂ©r.</translation>
+<translation id="2318774815570432836">A(z) <ph name="SITE" /> webhelyet pillanatnyilag nem tudja felkeresni, mert a webhely HSTS-t hasznĂ¡l. A hĂ¡lĂ³zati hibĂ¡k Ă©s tĂ¡madĂ¡sok rendszerint Ă¡tmenetiek, ezĂ©rt az emlĂ­tett oldal kĂ©sÅ‘bb valĂ³szĂ­nűleg mĂ¡r működni fog. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">MellÅ‘zött Ă©rvĂ©nytelen könyvjelzÅ‘ a(z) <ph name="ENTRY_INDEX" />. indexnĂ©l</translation>
<translation id="2354001756790975382">TovĂ¡bbi könyvjelzÅ‘k</translation>
<translation id="2359808026110333948">FolytatĂ¡s</translation>
<translation id="2365563543831475020">A(z) <ph name="CRASH_TIME" /> idÅ‘pontban kĂ©szĂ¼lt hibajelentĂ©s nincs feltöltve</translation>
<translation id="2367567093518048410">Szint</translation>
+<translation id="2371153335857947666">{1,plural, =1{A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya tegnap lejĂ¡rt. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, de az is lehet, hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. SzĂ¡mĂ­tĂ³gĂ©pĂ©nek Ă³rĂ¡ja jelenleg a következÅ‘re van Ă¡llĂ­tva: <ph name="CURRENT_DATE" />. Ez megfelelÅ‘nek tűnik? Ha nem, Ă¡llĂ­tsa be megfelelÅ‘en a rendszer Ă³rĂ¡jĂ¡t, majd frissĂ­tse az oldalt. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.}other{A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya # nappal ezelÅ‘tt lejĂ¡rt. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, de az is lehet, hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. SzĂ¡mĂ­tĂ³gĂ©pĂ©nek Ă³rĂ¡ja jelenleg a következÅ‘re van Ă¡llĂ­tva: <ph name="CURRENT_DATE" />. Ez megfelelÅ‘nek tűnik? Ha nem, Ă¡llĂ­tsa be megfelelÅ‘en a rendszer Ă³rĂ¡jĂ¡t, majd frissĂ­tse az oldalt. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Nincsenek alternatĂ­v kezelÅ‘felĂ¼letek</translation>
<translation id="2384307209577226199">VĂ¡llalati alapĂ©rtelmezett</translation>
-<translation id="238526402387145295">A(z) <ph name="SITE" /> webhelyet pillanatnyilag nem tudja felkeresni, mert a webhely <ph name="BEGIN_LINK" />HSTS-t hasznĂ¡l<ph name="END_LINK" />. A hĂ¡lĂ³zati hibĂ¡k Ă©s tĂ¡madĂ¡sok rendszerint Ă¡tmenetiek, ezĂ©rt az emlĂ­tett oldal kĂ©sÅ‘bb valĂ³szĂ­nűleg mĂ¡r működni fog.</translation>
<translation id="2386255080630008482">A szerver tanĂºsĂ­tvĂ¡nyĂ¡t visszavontĂ¡k.</translation>
<translation id="2392959068659972793">BeĂ¡llĂ­tott Ă©rtĂ©kkel nem rendelkezÅ‘ hĂ¡zirendek megjelenĂ­tĂ©se</translation>
<translation id="2396249848217231973">&amp;TörlĂ©s visszavonĂ¡sa</translation>
-<translation id="2413528052993050574">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nyĂ¡t visszavonhattĂ¡k. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t.</translation>
<translation id="2455981314101692989">A weboldal letiltotta az automatikus kitöltĂ©st erre az űrlapra.</translation>
+<translation id="2463739503403862330">Kitöltés</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />HĂ¡lĂ³zati diagnosztika futtatĂ¡sa<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Érvénytelen keresési URL</translation>
<translation id="2491120439723279231">A szervezet tanĂºsĂ­tvĂ¡nya hibĂ¡kat tartalmaz.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">ElkĂ¼ldĂ©s</translation>
<translation id="2674170444375937751">Biztosan törölni szeretnĂ© ezeket az oldalakat az elÅ‘zmĂ©nyek közĂ¼l?</translation>
<translation id="2677748264148917807">Lap elhagyĂ¡sa</translation>
+<translation id="269990154133806163">A szerver olyan tanĂºsĂ­tvĂ¡nyt mutatott be, amelyet nem A tanĂºsĂ­tvĂ¡nyok Ă¡tlĂ¡thatĂ³sĂ¡ga keretrendszer segĂ­tsĂ©gĂ©vel hoztak nyilvĂ¡nossĂ¡gra. Ez egyes tanĂºsĂ­tvĂ¡nyoknĂ¡l követelmĂ©ny annak biztosĂ­tĂ¡sa Ă©rdekĂ©ben, hogy az adott tanĂºsĂ­tvĂ¡nyok megbĂ­zhatĂ³k, Ă©s vĂ©delmet nyĂºjtanak a tĂ¡madĂ³k ellen. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Az Ă©rtĂ©k nem egyezik a formĂ¡tummal.</translation>
<translation id="2704951214193499422">A Chromium ez alkalommal nem tudta ellenÅ‘rizni az Ă–n kĂ¡rtyĂ¡jĂ¡t. PrĂ³bĂ¡lja Ăºjra kĂ©sÅ‘bb.</translation>
<translation id="2705137772291741111">A webhely mentett (gyorsĂ­tĂ³tĂ¡razott) pĂ©ldĂ¡nya nem olvashatĂ³.</translation>
<translation id="2709516037105925701">Automatikus kitöltés</translation>
+<translation id="2712118517637785082">A(z) <ph name="DOMAIN" /> webhelyet prĂ³bĂ¡lta megnyitni, de a kiĂ¡llĂ­tĂ³ visszavonta a szerver Ă¡ltal bemutatott tanĂºsĂ­tvĂ¡nyt. Ez azt jelenti, hogy a szerver biztonsĂ¡gi tanĂºsĂ­tvĂ¡nyĂ¡ban egyĂ¡ltalĂ¡n nem lehet megbĂ­zni. Lehet, hogy tĂ¡madĂ³val Ă¡ll kapcsolatban. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Engedély kérése</translation>
<translation id="2721148159707890343">Sikeres kérés</translation>
<translation id="2728127805433021124">A szerver tanĂºsĂ­tvĂ¡nya gyenge alĂ¡Ă­rĂ¡si algoritmussal van alĂ¡Ă­rva.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">CĂ­m- Ă©s keresÅ‘sĂ¡v</translation>
<translation id="2826760142808435982">A kapcsolat <ph name="KX" /> algoritmust hasznĂ¡l kulcscserĂ©lÅ‘ mechanizmuskĂ©nt, kĂ³dolĂ¡sa pedig <ph name="CIPHER" /> hasznĂ¡latĂ¡val törtĂ©nt.</translation>
<translation id="2835170189407361413">Å°rlap törlĂ©se</translation>
-<translation id="2837049386027881519">A kapcsolat felĂ©pĂ­tĂ©sĂ©t Ăºjra meg kellett prĂ³bĂ¡lni egy rĂ©gebbi verziĂ³jĂº TLS- vagy SSL-protokoll hasznĂ¡latĂ¡val. Ez Ă¡ltalĂ¡ban azt jelenti, hogy a szerver nagyon rĂ©gi szoftvert hasznĂ¡l, Ă©s lehetnek vele mĂ¡s biztonsĂ¡gi problĂ©mĂ¡k is.</translation>
<translation id="284702764277384724">A(z) <ph name="HOST_NAME" /> szervertanĂºsĂ­tvĂ¡nya hamisĂ­tvĂ¡nynak tűnik.</translation>
<translation id="2889159643044928134">Ne töltse Ăºjra</translation>
-<translation id="2896499918916051536">Ez a beĂ©pĂ¼lÅ‘ modul nem tĂ¡mogatott.</translation>
+<translation id="2900469785430194048">Elfogyott a memĂ³ria, miközben a Google Chrome megprĂ³bĂ¡lta megjelenĂ­teni ezt a weboldalt.</translation>
<translation id="2909946352844186028">VĂ¡ltozĂ¡st Ă©rzĂ©keltĂ¼nk a hĂ¡lĂ³zatban.</translation>
-<translation id="2915500479781995473">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya lejĂ¡rt. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t. SzĂ¡mĂ­tĂ³gĂ©pĂ©nek Ă³rĂ¡ja jelenleg <ph name="CURRENT_TIME" /> idÅ‘re van Ă¡llĂ­tva. Ez helyesnek tűnik? Ha nem, Ă¡llĂ­tsa be megfelelÅ‘en a rendszer Ă³rĂ¡jĂ¡t, majd frissĂ­tse az oldalt.</translation>
<translation id="2922350208395188000">A szerver tanĂºsĂ­tvĂ¡nyĂ¡t nem sikerĂ¼lt leellenÅ‘rizni.</translation>
-<translation id="2941952326391522266">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya a következÅ‘rÅ‘l szĂ¡rmazik: <ph name="DOMAIN2" />. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t.</translation>
<translation id="2948083400971632585">BĂ¡rmelyik kapcsolatlĂ©tesĂ­tĂ©sre hasznĂ¡lt proxyt letilthatja a beĂ¡llĂ­tĂ¡sok oldalon.</translation>
<translation id="2955913368246107853">KeresÅ‘sĂ¡v bezĂ¡rĂ¡sa</translation>
<translation id="2958431318199492670">A hĂ¡lĂ³zati konfigurĂ¡ciĂ³ nem felel meg az ONC szabvĂ¡nynak. A konfigurĂ¡ciĂ³ egyes rĂ©szeit nem lehet importĂ¡lni.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Nem megfelelÅ‘ irĂ¡nyelvtĂ­pus</translation>
<translation id="3032412215588512954">SzeretnĂ© Ăºjratölteni a webhelyet?</translation>
<translation id="3037605927509011580">A manĂ³ba!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{legalĂ¡bb 1 elem van a szinkronizĂ¡lt eszközökön}=1{1 elem (Ă©s mĂ©g több a szinkronizĂ¡lt eszközökön)}other{# elem (Ă©s mĂ©g több a szinkronizĂ¡lt eszközökön)}}</translation>
<translation id="3041612393474885105">TanĂºsĂ­tvĂ¡ny adatai</translation>
<translation id="3063697135517575841">A Chrome ez alkalommal nem tudta ellenÅ‘rizni az Ă–n kĂ¡rtyĂ¡jĂ¡t. PrĂ³bĂ¡lja Ăºjra kĂ©sÅ‘bb.</translation>
<translation id="3093245981617870298">Ă–n jelenleg offline.</translation>
@@ -204,15 +207,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">LegĂºjabb</translation>
<translation id="3207960819495026254">KönyvjelzÅ‘zött</translation>
-<translation id="3225919329040284222">A szerver tanĂºsĂ­tvĂ¡nya nem felel meg a beĂ©pĂ­tett elvĂ¡rĂ¡soknak. Ezek a beĂ©pĂ­tett elvĂ¡rĂ¡sok bizonyos nagy biztonsĂ¡gĂº webhelyekre vonatkoznak az Ă–n vĂ©delme Ă©rdekĂ©ben.</translation>
<translation id="3226128629678568754">Nyomja meg a frissĂ­tĂ©s gombot az oldal betöltĂ©sĂ©hez szĂ¼ksĂ©ges adatok ĂºjrakĂ¼ldĂ©sĂ©hez.</translation>
<translation id="3228969707346345236">A fordĂ­tĂ¡s nem sikerĂ¼lt, mert az oldal mĂ¡r ezen a nyelven van: <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Adja meg a(z) <ph name="CREDIT_CARD" /> kĂ¡rtya CVC-kĂ³djĂ¡t</translation>
<translation id="3254409185687681395">KönyvjelzÅ‘ hozzĂ¡adĂ¡sa ehhez az oldalhoz</translation>
<translation id="3270847123878663523">&amp;ĂtrendezĂ©s visszavonĂ¡sa</translation>
<translation id="3286538390144397061">ĂjraindĂ­tĂ¡s most</translation>
+<translation id="3303855915957856445">Nincs talĂ¡lat</translation>
<translation id="3305707030755673451">Adatainak titkosĂ­tĂ¡sa megtörtĂ©nt összetett szinkronizĂ¡lĂ¡si jelszavĂ¡val a következÅ‘ idÅ‘pontban: <ph name="TIME" />. Adja meg a jelszĂ³t a szinkronizĂ¡lĂ¡s megkezdĂ©sĂ©hez.</translation>
<translation id="333371639341676808">Ez az oldal ne nyisson meg tovĂ¡bbi pĂ¡rbeszĂ©dablakokat.</translation>
+<translation id="3338095232262050444">BiztonsĂ¡gos</translation>
<translation id="3340978935015468852">beĂ¡llĂ­tĂ¡sok</translation>
<translation id="3345135638360864351">A webhelyhez valĂ³ hozzĂ¡fĂ©rĂ©sre irĂ¡nyulĂ³ kĂ©relme nem jutott el <ph name="NAME" /> felhasznĂ¡lĂ³hoz. KĂ©rjĂ¼k, prĂ³bĂ¡lkozzon Ăºjra.</translation>
<translation id="3355823806454867987">ProxybeĂ¡llĂ­tĂ¡sok mĂ³dosĂ­tĂ¡sa...</translation>
@@ -230,6 +234,7 @@
<translation id="3452404311384756672">Lekérési intervallum:</translation>
<translation id="3462200631372590220">SpeciĂ¡lis beĂ¡llĂ­tĂ¡sok elrejtĂ©se</translation>
<translation id="3479539252931486093">Ez vĂ¡ratlanul Ă©rte Ă–nt? <ph name="BEGIN_LINK" />Tudassa velĂ¼nk.<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Ne most</translation>
<translation id="348000606199325318">HibaazonosĂ­tĂ³: <ph name="CRASH_LOCAL_ID" /> (szerverazonosĂ­tĂ³: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Jelenleg nem tudjuk elĂ©rni szĂ¼leidet. PrĂ³bĂ¡lkozz Ăºjra.</translation>
<translation id="3527085408025491307">Mappa</translation>
@@ -238,6 +243,7 @@
<translation id="3542684924769048008">JelszĂ³ hasznĂ¡lata a következÅ‘re:</translation>
<translation id="3549644494707163724">Az összes szinkronizĂ¡lt adat titkosĂ­tĂ¡sa sajĂ¡t összetett szinkronizĂ¡lĂ¡si jelszĂ³val</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> tovĂ¡bbi...</translation>
+<translation id="3555561725129903880">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya a(z) <ph name="DOMAIN2" /> domainrÅ‘l szĂ¡rmazik. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Az Ă–n kapcsolata nem privĂ¡t</translation>
<translation id="3583757800736429874">&amp;ĂthelyezĂ©s Ăºjra</translation>
<translation id="3586931643579894722">Részletek elrejtése</translation>
@@ -249,12 +255,15 @@
<translation id="3623476034248543066">Érték megjelenítése</translation>
<translation id="3630155396527302611">Ha mĂ¡r megjelenik a hĂ¡lĂ³zat elĂ©rĂ©sĂ©re engedĂ©lyezett programkĂ©nt, prĂ³bĂ¡lkozzon
az eltĂ¡volĂ­tĂ¡sĂ¡val, majd a listĂ¡ra valĂ³ ismĂ©telt felvĂ©telĂ©vel.</translation>
+<translation id="3638794133396384728">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya lejĂ¡rt. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. SzĂ¡mĂ­tĂ³gĂ©pĂ©nek Ă³rĂ¡ja jelenleg a következÅ‘re van Ă¡llĂ­tva: <ph name="CURRENT_TIME" />. Ez megfelelÅ‘nek tűnik? Ha nem, Ă¡llĂ­tsa be megfelelÅ‘en a rendszer Ă³rĂ¡jĂ¡t, majd frissĂ­tse az oldalt. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Ezek a kĂ­sĂ©rleti funkciĂ³k bĂ¡rmikor megvĂ¡ltozhatnak, elromolhatnak vagy eltűnhetnek. Nem vĂ¡llalunk semmilyen garanciĂ¡t az ezen kĂ­sĂ©rleti funkciĂ³k bekapcsolĂ¡sĂ¡bĂ³l szĂ¡rmazĂ³ esemĂ©nyekĂ©rt; tovĂ¡bbĂ¡ böngĂ©szÅ‘je vĂ¡ratlanul összeomolhat. A viccet fĂ©lretĂ©ve, a böngĂ©szÅ‘je törölheti az összes adatot, valamint kĂ¼lönbözÅ‘ mĂ³dokon veszĂ©lyeztetheti biztonsĂ¡gĂ¡t Ă©s adatvĂ©delmĂ©t. Ha bĂ¡rmilyen kĂ­sĂ©rleti funkciĂ³t engedĂ©lyez, az a böngĂ©szÅ‘ minden felhasznĂ¡lĂ³ja szĂ¡mĂ¡ra engedĂ©lyezve lesz. KĂ©rjĂ¼k, Ă³vatosan lĂ©pjen tovĂ¡bb.</translation>
<translation id="3650584904733503804">Sikeres érvényesítés</translation>
<translation id="3655670868607891010">Ha gyakran lĂ¡tja ezt, prĂ³bĂ¡lja ki a következÅ‘t: <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">EllenÅ‘rzĂ©s</translation>
+<translation id="3678029195006412963">A kĂ©rĂ©st nem lehetett alĂ¡Ă­rni</translation>
<translation id="3681007416295224113">TanĂºsĂ­tvĂ¡ny adatai</translation>
<translation id="3693415264595406141">JelszĂ³:</translation>
+<translation id="3696411085566228381">nincs</translation>
<translation id="3700528541715530410">HoppĂ¡! Nincs jogosultsĂ¡ga ennek a lapnak a megtekintĂ©sĂ©hez.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Betöltés…</translation>
@@ -262,7 +271,6 @@
<translation id="3714780639079136834">A mobiladatok vagy a Wi-Fi bekapcsolĂ¡sa</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />A proxy, a tűzfal Ă©s a DNS-konfigurĂ¡ciĂ³ ellenÅ‘rzĂ©se<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">ĂtmĂ¡solt link</translation>
-<translation id="3744899669254331632">Most nem keresheti fel a(z) <ph name="SITE" /> webhelyet, mert az zavaros, a Chromium Ă¡ltal nem feldolgozhatĂ³ hitelesĂ­tÅ‘ adatokat kĂ¼ldött. A hĂ¡lĂ³zati hibĂ¡k Ă©s tĂ¡madĂ¡sok Ă¡ltalĂ¡ban ideiglenesek, Ăºgyhogy az oldal kĂ©sÅ‘bb valĂ³szĂ­nűleg megfelelÅ‘en fog működni.</translation>
<translation id="375403751935624634">A fordĂ­tĂ¡s a szerver hibĂ¡ja miatt nem sikerĂ¼lt.</translation>
<translation id="3759461132968374835">Nincs a közelmĂºltban bejelentett rendszerösszeomlĂ¡s. A kikapcsolt jelentĂ©skĂ¼ldĂ©s sorĂ¡n törtĂ©nt összeomlĂ¡sok nem jelennek meg itt.</translation>
<translation id="3788090790273268753">A webhely tanĂºsĂ­tvĂ¡nya 2016-ban jĂ¡r le, a tanĂºsĂ­tvĂ¡nylĂ¡nc pedig tartalmaz egy SHA-1 titkosĂ­tĂ¡ssal alĂ¡Ă­rt tanĂºsĂ­tvĂ¡nyt.</translation>
@@ -274,19 +282,25 @@
<translation id="3884278016824448484">EszközazonosĂ­tĂ³-Ă¼tközĂ©s</translation>
<translation id="3885155851504623709">Körzet</translation>
<translation id="3901925938762663762">A kĂ¡rtya lejĂ¡rt</translation>
+<translation id="3910267023907260648">MegprĂ³bĂ¡lta elĂ©rni a(z) <ph name="DOMAIN" /> webhelyet, de a szerver gyenge alĂ¡Ă­rĂ¡si algoritmust hasznĂ¡lĂ³ tanĂºsĂ­tvĂ¡nyt mutatott be. Ez alapjĂ¡n elkĂ©pzelhetÅ‘, hogy a szerver Ă¡ltal megadott biztonsĂ¡gi tanĂºsĂ­tvĂ¡nyt hamisĂ­tottĂ¡k, Ă©s a szerver nem az, amelyikre szĂ¡mĂ­tott (lehet, hogy Ă©ppen a tĂ¡madĂ³val Ă¡ll kapcsolatban). <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya Ă¡llĂ­tĂ³lag holnaptĂ³l Ă©rvĂ©nyes. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, de az is lehet, hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.}other{A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya elmĂ©letileg # nap mĂºlva lĂ©p Ă©rvĂ©nybe. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, de az is lehet, hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF dokumentum betöltése sikertelen</translation>
<translation id="3963721102035795474">OlvasĂ¡si mĂ³d</translation>
+<translation id="397105322502079400">SzĂ¡mĂ­tĂ¡s…</translation>
<translation id="3973234410852337861">A(z) <ph name="HOST_NAME" /> le van tiltva</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 közeli weboldal}other{# közeli weboldal}}</translation>
<translation id="4021036232240155012">A DNS az a hĂ¡lĂ³zati szolgĂ¡ltatĂ¡s, amely a webhelynevet az adott webhely internetes cĂ­mĂ©re fordĂ­tja le.</translation>
<translation id="4030383055268325496">&amp;HozzĂ¡adĂ¡s visszavonĂ¡sa</translation>
-<translation id="4032534284272647190">HozzĂ¡fĂ©rĂ©s a(z) <ph name="URL" /> URL-hez megtagadva.</translation>
<translation id="404928562651467259">FIGYELMEZTETÉS</translation>
<translation id="4058922952496707368">"<ph name="SUBKEY" />" kulcs: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Az Ă¼gyfĂ©l Ă©s a szerver nem tĂ¡mogat ugyanolyan SSL-protokollverziĂ³t vagy rejtjelezĂ©si csomagot.</translation>
<translation id="4079302484614802869">A proxykonfigurĂ¡ciĂ³ a .pac tĂ­pusĂº szkript URL-cĂ­m, nem pedig a fix proxyszerverek hasznĂ¡latĂ¡ra van beĂ¡llĂ­tva.</translation>
<translation id="4103249731201008433">Az eszköz sorozatszĂ¡ma Ă©rvĂ©nytelen</translation>
<translation id="4103763322291513355">LĂ¡togasson el a &lt;strong&gt;chrome://policy&lt;/strong&gt; oldalra a feketelistĂ¡n lĂ©vÅ‘ URL-ek Ă©s egyĂ©b, a rendszergazda Ă¡ltal elÅ‘Ă­rt szabĂ¡lyok megtekintĂ©sĂ©hez.</translation>
+<translation id="4110615724604346410">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya hibĂ¡kat tartalmaz. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Az irĂ¡nyelv hatĂ¡sköre nem tĂ¡mogatott.</translation>
+<translation id="4118212371799607889">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya a Chromium szerint nem megbĂ­zhatĂ³. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 egyéb}other{# egyéb}}</translation>
<translation id="4130226655945681476">A hĂ¡lĂ³zati kĂ¡belek, a modem Ă©s a router ellenÅ‘rzĂ©se</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">SzeretnĂ©, hogy a Chromium mentse ezt a kĂ¡rtyĂ¡t?</translation>
@@ -294,6 +308,7 @@
<translation id="4176463684765177261">Kikapcsolva</translation>
<translation id="4196861286325780578">&amp;ĂthelyezĂ©s Ăºjra</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />A tűzfal Ă©s a vĂ­rusirtĂ³ konfigurĂ¡ciĂ³jĂ¡nak ellenÅ‘rzĂ©se<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{nincsen}=1{1 alkalmazĂ¡s ($1)}=2{2 alkalmazĂ¡s ($1, $2)}other{# alkalmazĂ¡s ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Ă–sszeomlĂ¡sok</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />PrĂ³bĂ¡lkozzon a HĂ¡lĂ³zati diagnosztika futtatĂ¡sĂ¡val<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Nem</translation>
@@ -302,14 +317,15 @@
<translation id="4269787794583293679">(Nincs felhasznĂ¡lĂ³nĂ©v)</translation>
<translation id="4300246636397505754">SzĂ¼lÅ‘i javaslatok</translation>
<translation id="4304224509867189079">Bejelentkezés</translation>
+<translation id="432290197980158659">A szerver tanĂºsĂ­tvĂ¡nya nem felel meg a beĂ©pĂ­tett elvĂ¡rĂ¡soknak. Ezek a beĂ©pĂ­tett elvĂ¡rĂ¡sok bizonyos nagy biztonsĂ¡gĂº webhelyekre vonatkozĂ³an talĂ¡lhatĂ³k meg az Ă–n vĂ©delmĂ©nek Ă©rdekĂ©ben. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Nem sikerĂ¼lt megtalĂ¡lni a cikket</translation>
+<translation id="4331708818696583467">Nem biztonsĂ¡gos</translation>
<translation id="4372948949327679948">VĂ¡rt <ph name="VALUE_TYPE" /> Ă©rtĂ©k.</translation>
-<translation id="4377125064752653719">A(z) <ph name="DOMAIN" /> webhelyet prĂ³bĂ¡lta megnyitni, de a kiĂ¡llĂ­tĂ³ visszavonta a szerver Ă¡ltal bemutatott tanĂºsĂ­tvĂ¡nyt. Ez azt jelenti, hogy a szerver biztonsĂ¡gi igazolĂ¡saiban egyĂ¡ltalĂ¡n nem lehet megbĂ­zni. Lehet, hogy egy tĂ¡madĂ³val Ă¡ll kapcsolatban.</translation>
<translation id="4381091992796011497">FelhasznĂ¡lĂ³nĂ©v:</translation>
<translation id="4394049700291259645">KikapcsolĂ¡s</translation>
<translation id="4395129973926795186"><ph name="START_DATE" />–<ph name="END_DATE" /></translation>
<translation id="4406896451731180161">keresĂ©si talĂ¡lat</translation>
-<translation id="4424024547088906515">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya a Chrome szerint nem megbĂ­zhatĂ³. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t.</translation>
+<translation id="4432688616882109544">A(z) <ph name="HOST_NAME" /> nem fogadta el az Ă–n bejelentkezĂ©si tanĂºsĂ­tvĂ¡nyĂ¡t, vagy nem talĂ¡lt ilyet.</translation>
<translation id="443673843213245140">A proxy hasznĂ¡lata le van tiltva, de kifejezett proxykonfigurĂ¡ciĂ³ van megadva.</translation>
<translation id="4458874409874303848">BiztonsĂ¡gos webhelyek</translation>
<translation id="4461847750548395463">AzĂ©rt lĂ¡tja ezt az Ă¼zenetet, mert a Google BiztonsĂ¡gos webhelyek szolgĂ¡ltatĂ¡s be van kapcsolva.</translation>
@@ -321,12 +337,12 @@
<translation id="4522570452068850558">RĂ©szletek</translation>
<translation id="4558551763791394412">PrĂ³bĂ¡lkozzon a bÅ‘vĂ­tmĂ©nyek letiltĂ¡sĂ¡val.</translation>
<translation id="4587425331216688090">EltĂ¡volĂ­tja a cĂ­met a Chrome-bĂ³l?</translation>
+<translation id="4589078953350245614">MegprĂ³bĂ¡lta elĂ©rni a(z) <ph name="DOMAIN" /> webhelyet, de a szerver Ă©rvĂ©nytelen tanĂºsĂ­tvĂ¡nyt mutatott be. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">A(z) <ph name="DOMAIN" /> domainnel valĂ³ kapcsolata modern kriptogrĂ¡fiĂ¡val van titkosĂ­tva.</translation>
<translation id="4594403342090139922">&amp;TörlĂ©s visszavonĂ¡sa</translation>
+<translation id="4627442949885028695">FolytatĂ¡s mĂ¡sik eszközrÅ‘l</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Egy bÅ‘vĂ­tmĂ©nyoldalt tekint meg.</translation>
-<translation id="467662567472608290">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya hibĂ¡kat tartalmaz. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> blokkolva volt</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Kapcsolata megszakadt</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />A Windows HĂ¡lĂ³zati diagnosztika futtatĂ¡sa<ph name="END_LINK" /></translation>
@@ -334,21 +350,26 @@
<translation id="4728558894243024398">Platform</translation>
<translation id="4744603770635761495">VĂ©grehajthatĂ³ fĂ¡jl Ăºtvonala</translation>
<translation id="4756388243121344051">&amp;ElÅ‘zmĂ©nyek</translation>
+<translation id="4759238208242260848">Letöltések</translation>
<translation id="4764776831041365478">A <ph name="URL" /> weboldal lehet, hogy ideiglenesen nem Ă©rhetÅ‘ el, vagy vĂ©glegesen Ăºj cĂ­mre költözött.</translation>
<translation id="4771973620359291008">Ismeretlen hiba történt.</translation>
<translation id="4782449893814226250">MegkĂ©rdezted a szĂ¼leidet, hogy meg szabad-e lĂ¡togatnod ezt az oldalt.</translation>
<translation id="4800132727771399293">EllenÅ‘rizze a lejĂ¡rati dĂ¡tumot Ă©s a CVC-t, majd prĂ³bĂ¡lja Ăºjra</translation>
-<translation id="4807049035289105102">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mivel az olyan titkosĂ­tott hitelesĂ­tĂ©si adatokat kĂ¼ldött, amelyeket a Google Chrome nem tud feldolgozni. A hĂ¡lĂ³zati hibĂ¡k Ă©s tĂ¡madĂ¡sok rendszerint Ă¡tmenetiek, ezĂ©rt az emlĂ­tett oldal kĂ©sÅ‘bb valĂ³szĂ­nűleg mĂ¡r működni fog.</translation>
<translation id="4813512666221746211">HĂ¡lĂ³zati hiba</translation>
<translation id="4816492930507672669">IgazĂ­tĂ¡s az oldalmĂ©rethez</translation>
<translation id="4850886885716139402">NĂ©zet</translation>
<translation id="4880827082731008257">KeresĂ©s az elÅ‘zmĂ©nyek között</translation>
+<translation id="4884656795097055129">TovĂ¡bbi cikkek jelennek meg a megfelelÅ‘ idÅ‘pontban.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> Ă©s <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{Ă©s egy tovĂ¡bbi weboldal}other{Ă©s # tovĂ¡bbi weboldal}}</translation>
<translation id="4923417429809017348">Ezt az oldalt lefordĂ­tottĂ¡k egy ismeretlen nyelvrÅ‘l <ph name="LANGUAGE_LANGUAGE" /> nyelvre</translation>
<translation id="4926049483395192435">Meg kell hatĂ¡rozni.</translation>
<translation id="4930497775425430760">AzĂ©rt lĂ¡tja ezt az Ă¼zenetet, mert szĂ¼lÅ‘jĂ©nek jĂ³vĂ¡ kell hagynia az Ăºj webhelyeket az elsÅ‘ lĂ¡togatĂ¡skor.</translation>
<translation id="495170559598752135">Műveletek</translation>
<translation id="4958444002117714549">Lista részletes nézete</translation>
+<translation id="4962322354953122629">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya a Chrome szerint nem megbĂ­zhatĂ³. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">LefordĂ­tja <ph name="ORIGINAL_LANGUAGE" /> nyelvrÅ‘l <ph name="TARGET_LANGUAGE" /> nyelvre?</translation>
+<translation id="4989809363548539747">Ez a beĂ©pĂ¼lÅ‘ modul nem tĂ¡mogatott</translation>
<translation id="5002932099480077015">Ha engedĂ©lyezi, a Chrome megÅ‘rzi a kĂ¡rtya mĂ¡solatĂ¡t ezen az eszközön a gyorsabb űrlapkitöltĂ©s Ă©rdekĂ©ben.</translation>
<translation id="5019198164206649151">A hĂ¡ttĂ©rtĂ¡rolĂ³ Ă¡llapota nem megfelelÅ‘</translation>
<translation id="5023310440958281426">EllenÅ‘rizze rendszergazdai hĂ¡zirendjeit</translation>
@@ -356,13 +377,12 @@
<translation id="5031870354684148875">A Google FordĂ­tĂ³ leĂ­rĂ¡sa</translation>
<translation id="5040262127954254034">Adatvédelem</translation>
<translation id="5045550434625856497">Helytelen jelszĂ³</translation>
+<translation id="5056549851600133418">Cikkek Ă–nnek</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />A proxy cĂ­mĂ©nek ellenÅ‘rzĂ©se<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">A szerver tanĂºsĂ­tvĂ¡nya jelenleg nem Ă©rvĂ©nyes.</translation>
<translation id="5089810972385038852">Ăllam</translation>
-<translation id="5094747076828555589">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya a Chromium szerint nem megbĂ­zhatĂ³. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t.</translation>
<translation id="5095208057601539847">TartomĂ¡ny</translation>
<translation id="5115563688576182185">(64 bites)</translation>
-<translation id="5122371513570456792"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> talĂ¡lhatĂ³ a(z) â€<ph name="SEARCH_STRING" />†kifejezĂ©sre.</translation>
<translation id="5141240743006678641">A szinkronizĂ¡lt jelszavak titkosĂ­tĂ¡sa a Google hitelesĂ­tĂ©si adataival</translation>
<translation id="5145883236150621069">Az irĂ¡nyelv vĂ¡lasza hibakĂ³dot tartalmaz</translation>
<translation id="5171045022955879922">Keressen vagy Ă­rjon be egy URL-t</translation>
@@ -371,18 +391,18 @@
<translation id="5190835502935405962">KönyvjelzÅ‘sĂ¡v</translation>
<translation id="5199729219167945352">Kísérletek</translation>
<translation id="5251803541071282808">Felhő</translation>
+<translation id="5277279256032773186">A munkahelyĂ©n hasznĂ¡lja a Chrome-ot? A cĂ©gek kezelhetik a Chrome-beĂ¡llĂ­tĂ¡sokat alkalmazottaik szĂ¡mĂ¡ra. TovĂ¡bbi informĂ¡ciĂ³.</translation>
<translation id="5299298092464848405">IrĂ¡nyelv-elÅ‘feldolgozĂ¡si hiba</translation>
<translation id="5300589172476337783">Megjelenítés</translation>
<translation id="5308689395849655368">A hibabejelentés ki van kapcsolva.</translation>
<translation id="5317780077021120954">Mentés</translation>
<translation id="5327248766486351172">NĂ©v</translation>
+<translation id="5359637492792381994">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya jelenleg nem Ă©rvĂ©nyes. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolatĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Az irĂ¡nyelv-beĂ¡llĂ­tĂ¡sok tĂ¡rolĂ¡sa sikertelen</translation>
-<translation id="540969355065856584">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya jelenleg nem Ă©rvĂ©nyes. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolatĂ¡t.</translation>
<translation id="5421136146218899937">Böngészési adatok törlése...</translation>
<translation id="5430298929874300616">KönyvjelzÅ‘ törlĂ©se</translation>
<translation id="5431657950005405462">A fĂ¡jl nem talĂ¡lhatĂ³</translation>
<translation id="5435775191620395718">ElÅ‘zmĂ©nyek megjelenĂ­tĂ©se errÅ‘l az eszközrÅ‘l. <ph name="BEGIN_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">A szemĂ©lyre szabott tartalomjavaslatok jelenleg ki vannak kapcsolva, mert szinkronizĂ¡lt adatait egyedi összetett jelszĂ³ vĂ©di.</translation>
<translation id="5439770059721715174">SĂ©maĂ©rvĂ©nyesĂ­tĂ©si hiba a következÅ‘nĂ©l: â€<ph name="ERROR_PATH" />â€: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Ez a(z) <ph name="HOST_NAME" /> oldal nem talĂ¡lhatĂ³</translation>
<translation id="5455374756549232013">HibĂ¡s az irĂ¡nyelv idÅ‘bĂ©lyege</translation>
@@ -405,14 +425,18 @@
<translation id="5622887735448669177">Szeretné elhagyni ezt a webhelyet?</translation>
<translation id="5629630648637658800">Az irĂ¡nyelv-beĂ¡llĂ­tĂ¡sok betöltĂ©se sikertelen</translation>
<translation id="5631439013527180824">Érvénytelen eszközkezelési token</translation>
-<translation id="5650551054760837876">Nincs talĂ¡lat</translation>
<translation id="5677928146339483299">Letiltva</translation>
<translation id="5710435578057952990">A webhely valĂ³disĂ¡gĂ¡t nem ellenÅ‘riztĂ¼k.</translation>
<translation id="5720705177508910913">Jelenlegi felhasznĂ¡lĂ³</translation>
+<translation id="572328651809341494">Nemrég megnyitott lapok</translation>
<translation id="5784606427469807560">A kĂ¡rtya ellenÅ‘rzĂ©se sorĂ¡n hiba törtĂ©nt. EllenÅ‘rizze az internetkapcsolatot, majd prĂ³bĂ¡lkozzon Ăºjra.</translation>
<translation id="5785756445106461925">Emellett az oldal azonban mĂ¡s forrĂ¡sokat is tartalmaz, amelyek nem biztonsĂ¡gosak. Ezeket a forrĂ¡sokat mĂ¡sok is megtekinthetik Ă¡tvitel közben, Ă©s megvĂ¡ltoztatĂ¡sukkal a tĂ¡madĂ³k mĂ³dosĂ­thatjĂ¡k az oldal viselkedĂ©sĂ©t.</translation>
+<translation id="5786044859038896871">Ki szeretnĂ© tölteni a kĂ¡rtyaadatait?</translation>
+<translation id="5803412860119678065">Ki szeretnĂ© tölteni <ph name="CARD_DETAIL" /> kĂ¡rtyĂ¡jĂ¡nak adataival?</translation>
<translation id="5810442152076338065">A(z) <ph name="DOMAIN" /> domainnel valĂ³ kapcsolata elavult kriptogrĂ¡fiĂ¡val van titkosĂ­tva.</translation>
<translation id="5813119285467412249">&amp;HozzĂ¡adĂ¡s Ăºjra</translation>
+<translation id="5814352347845180253">ElveszĂ­theti hozzĂ¡fĂ©rĂ©sĂ©t a(z) <ph name="SITE" /> Ă©s mĂ¡s webhelyek prĂ©mium tartalmaihoz.</translation>
+<translation id="5843436854350372569">MegprĂ³bĂ¡lta elĂ©rni a(z) <ph name="DOMAIN" /> webhelyet, de a szerver gyenge kulccsal rendelkezÅ‘ tanĂºsĂ­tvĂ¡nyt mutatott be. ElÅ‘fordulhat, hogy tĂ¡madĂ³ törte fel a privĂ¡t kulcsot, Ă©s lehet, hogy a szerver nem a vĂ¡rt kiszolgĂ¡lĂ³ (lehet, hogy Ă–n a tĂ¡madĂ³val Ă¡ll kapcsolatban). <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">AzĂ©rt lĂ¡tja ezt az Ă¼zenetet, mert kezelÅ‘je letiltotta ezt a webhelyet.</translation>
<translation id="5857090052475505287">Ăj mappa</translation>
<translation id="5869405914158311789">A webhely nem Ă©rhetÅ‘ el</translation>
@@ -420,6 +444,7 @@
<translation id="5872918882028971132">SzĂ¼lÅ‘i javaslatok</translation>
<translation id="59107663811261420">A Google Payments ennĂ©l a kereskedÅ‘nĂ©l nem tĂ¡mogatja az ilyen tĂ­pusĂº kĂ¡rtyĂ¡kat. KĂ©rjĂ¼k, vĂ¡lasszon mĂ¡sik kĂ¡rtyĂ¡t.</translation>
<translation id="59174027418879706">Engedélyezve</translation>
+<translation id="5926846154125914413">ElveszĂ­theti hozzĂ¡fĂ©rĂ©sĂ©t az egyes webhelyek prĂ©mium tartalmaihoz.</translation>
<translation id="5966707198760109579">HĂ©t</translation>
<translation id="5967867314010545767">EltĂ¡volĂ­tĂ¡s az elÅ‘zmĂ©nyek közĂ¼l</translation>
<translation id="5975083100439434680">Kicsinyítés</translation>
@@ -431,12 +456,12 @@
<translation id="604124094241169006">Automatikus</translation>
<translation id="6042308850641462728">Hosszabban</translation>
<translation id="6060685159320643512">Óvatosan, ezek a kísérletek haraphatnak</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{nincsen}=1{1}other{#}}</translation>
<translation id="6146055958333702838">EllenÅ‘rizze a kĂ¡beleket, majd indĂ­tsa Ăºjra a routert, modemet vagy mĂ¡s
hĂ¡lĂ³zati eszközt, amelyet hasznĂ¡l.</translation>
<translation id="614940544461990577">PrĂ³bĂ¡lja ki a következÅ‘ket:</translation>
<translation id="6150607114729249911">HoppĂ¡! Meg kell kĂ©rdeznie a szĂ¼lÅ‘ket, hogy meg szabad-e lĂ¡togatnia ezt az oldalt.</translation>
<translation id="6151417162996330722">A szervertanĂºsĂ­tvĂ¡ny Ă©rvĂ©nyessĂ©gi ideje tĂºl hosszĂº.</translation>
-<translation id="6154808779448689242">A visszaadott irĂ¡nyelvtoken nem egyezik az aktuĂ¡lis tokennel</translation>
<translation id="6165508094623778733">TovĂ¡bbi informĂ¡ciĂ³</translation>
<translation id="6203231073485539293">Ellenőrizze az internetkapcsolatot</translation>
<translation id="6218753634732582820">EltĂ¡volĂ­tja a cĂ­met a ChromiumbĂ³l?</translation>
@@ -449,24 +474,30 @@
<translation id="6328639280570009161">PrĂ³bĂ¡lkozzon a hĂ¡lĂ³zati elÅ‘rejelzĂ©sek kikapcsolĂ¡sĂ¡val</translation>
<translation id="6337534724793800597">HĂ¡zirendek szűrĂ©se nĂ©v szerint</translation>
<translation id="6342069812937806050">Éppen most</translation>
+<translation id="6345221851280129312">ismeretlen méret</translation>
<translation id="6355080345576803305">NyilvĂ¡nos munkamenet Ă¡ltali felĂ¼lbĂ­rĂ¡lĂ¡s</translation>
<translation id="6358450015545214790">Mit jelent ez?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 egyéb javaslat}other{# egyéb javaslat}}</translation>
<translation id="6387478394221739770">Érdekli nĂ©hĂ¡ny remek Ăºj Chrome-funkciĂ³? PrĂ³bĂ¡lja ki a BĂ©ta csatornĂ¡nkat a chrome.com/beta webhelyen.</translation>
-<translation id="641480858134062906"><ph name="URL" /> nem töltÅ‘dött be</translation>
+<translation id="6389758589412724634">Elfogyott a memĂ³ria, miközben a Chromium megprĂ³bĂ¡lta megjelenĂ­teni ezt a weboldalt.</translation>
+<translation id="6416403317709441254">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mivel az olyan titkosĂ­tott hitelesĂ­tĂ©si adatokat kĂ¼ldött, amelyeket a Chromium nem tud feldolgozni. A hĂ¡lĂ³zati hibĂ¡k Ă©s tĂ¡madĂ¡sok rendszerint Ă¡tmenetiek, ezĂ©rt az emlĂ­tett oldal kĂ©sÅ‘bb valĂ³szĂ­nűleg mĂ¡r működni fog. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Nem lehet ellenÅ‘rizni, hogy a tanĂºsĂ­tvĂ¡nyt visszavontĂ¡k-e.</translation>
<translation id="6433595998831338502">A(z) <ph name="HOST_NAME" /> visszautasĂ­totta a csatlakozĂ¡st.</translation>
<translation id="6445051938772793705">OrszĂ¡g</translation>
<translation id="6451458296329894277">KĂ©pernyÅ‘ ĂºjrakĂ¼ldĂ©sĂ©nek megerÅ‘sĂ­tĂ©se</translation>
<translation id="6458467102616083041">A rendszer figyelmen kĂ­vĂ¼l hagyja, mivel az alapĂ©rtelmezett keresĂ©st hĂ¡zirend tiltja le.</translation>
+<translation id="6462969404041126431">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nyĂ¡t visszavonhattĂ¡k. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">EszközhĂ¡zirendek</translation>
<translation id="6489534406876378309">FeltöltĂ©si összeomlĂ¡sok indĂ­tĂ¡sa</translation>
<translation id="6529602333819889595">&amp;TörlĂ©s Ăºjra</translation>
+<translation id="6534179046333460208">Fizikai web – javaslatok</translation>
<translation id="6550675742724504774">BeĂ¡llĂ­tĂ¡sok</translation>
+<translation id="6593753688552673085">kevesebb, mint <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">TitkosĂ­tĂ¡si lehetÅ‘sĂ©gek</translation>
<translation id="662080504995468778">MĂ©gse</translation>
<translation id="6628463337424475685">Keresés: <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mert <ph name="BEGIN_LINK" />ezt a tanĂºsĂ­tvĂ¡nyt visszavontĂ¡k<ph name="END_LINK" />. A hĂ¡lĂ³zati hibĂ¡k Ă©s tĂ¡madĂ¡sok rendszerint Ă¡tmenetiek, ezĂ©rt az emlĂ­tett oldal kĂ©sÅ‘bb valĂ³szĂ­nűleg mĂ¡r működni fog.</translation>
<translation id="6644283850729428850">Ez a hĂ¡zirend mĂ¡r elavult.</translation>
+<translation id="6652240803263749613">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya a szĂ¡mĂ­tĂ³gĂ©p operĂ¡ciĂ³s rendszere szerint nem megbĂ­zhatĂ³. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Mappa szerkesztése</translation>
<translation id="6660210980321319655">Automatikusan jelentve ekkor: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">EltĂ¡volĂ­tja az űrlapjavaslatot a ChromiumbĂ³l?</translation>
@@ -474,6 +505,7 @@
<translation id="6710213216561001401">Előző</translation>
<translation id="6710594484020273272">&lt;Ărja be a keresĂ©si kifejezĂ©st&gt;</translation>
<translation id="6711464428925977395">Valami gond van a proxyszerverrel, vagy a cĂ­m nem megfelelÅ‘.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{nincsen}=1{1 elem}other{# elem}}</translation>
<translation id="674375294223700098">Ismeretlen szervertanĂºsĂ­tvĂ¡ny-hiba.</translation>
<translation id="6753269504797312559">HĂ¡zirend Ă©rtĂ©ke</translation>
<translation id="6757797048963528358">Eszköze alvĂ³ Ă¼zemmĂ³dba vĂ¡ltott.</translation>
@@ -485,7 +517,6 @@
<translation id="6891596781022320156">Ezt a hĂ¡zirendszintet a rendszer nem tĂ¡mogatja.</translation>
<translation id="6895330447102777224">KĂ¡rtyĂ¡jĂ¡t ellenÅ‘riztĂ¼k</translation>
<translation id="6897140037006041989">User agent</translation>
-<translation id="6903907808598579934">SzinkronizĂ¡lĂ¡s bekapcsolĂ¡sa</translation>
<translation id="6915804003454593391">FelhasznĂ¡lĂ³:</translation>
<translation id="6957887021205513506">A szerver tanĂºsĂ­tvĂ¡nya hamisĂ­tvĂ¡nynak tűnik.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -493,9 +524,11 @@
<translation id="6970216967273061347">KerĂ¼let</translation>
<translation id="6973656660372572881">MindkĂ©t fix proxyszerver Ă©s egy .Pac tĂ­pusĂº szkript URL-cĂ­me meg van adva.</translation>
<translation id="6989763994942163495">SpeciĂ¡lis beĂ¡llĂ­tĂ¡sok megjelenĂ­tĂ©se...</translation>
+<translation id="7000990526846637657">Nincsenek elÅ‘zmĂ©nybejegyzĂ©sek</translation>
+<translation id="7009986207543992532">Ă–n megprĂ³bĂ¡lta elĂ©rni a(z) <ph name="DOMAIN" /> domaint, de a szerver olyan tanĂºsĂ­tvĂ¡nyt mutatott be, amelynek Ă©rvĂ©nyessĂ©gi ideje tĂºl hosszĂº ahhoz, hogy megbĂ­zhatĂ³ legyen. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">ElÅ‘fordulhat, hogy a böngĂ©szĂ©si elÅ‘zmĂ©nyek mĂ¡s formĂ¡i megtalĂ¡lhatĂ³k Google-fiĂ³kjĂ¡ban a <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> cĂ­men</translation>
<translation id="7029809446516969842">Jelszavak</translation>
-<translation id="7050187094878475250">Ă–n megprĂ³bĂ¡lta elĂ©rni a(z) <ph name="DOMAIN" /> domaint, de a szerver olyan tanĂºsĂ­tvĂ¡nyt kĂ¼ldött, amelynek Ă©rvĂ©nyessĂ©gi ideje tĂºl hosszĂº ahhoz, hogy megbĂ­zhatĂ³ legyen.</translation>
<translation id="7087282848513945231">Megye</translation>
<translation id="7088615885725309056">RĂ©gebbi</translation>
<translation id="7090678807593890770">KeresĂ©s a Google-on a következÅ‘re: <ph name="LINK" /></translation>
@@ -514,13 +547,13 @@
<translation id="7246609911581847514">AzĂ©rt lĂ¡tja ezt az Ă¼zenetet, mert kezelÅ‘jĂ©nek jĂ³vĂ¡ kell hagynia az Ăºj webhelyeket az elsÅ‘ lĂ¡togatĂ¡skor.</translation>
<translation id="724975217298816891">Adja meg a(z) <ph name="CREDIT_CARD" /> kĂ¡rtya lejĂ¡rati dĂ¡tumĂ¡t Ă©s CVC-kĂ³djĂ¡t. Az ellenÅ‘rzĂ©st követÅ‘en a böngĂ©szÅ‘ megosztja kĂ¡rtyaadatait ezzel a webhellyel.</translation>
<translation id="725866823122871198">Nem hozhatĂ³ lĂ©tre privĂ¡t kapcsolat a következÅ‘vel: <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, mert a szĂ¡mĂ­tĂ³gĂ©p dĂ¡tum- Ă©s idÅ‘beĂ¡llĂ­tĂ¡sa helytelen (<ph name="DATE_AND_TIME" />).</translation>
-<translation id="7265986070661382626">Pillanatnyilag nem keresheti fel a(z) <ph name="SITE" /> webhelyet, mivel a webhely <ph name="BEGIN_LINK" />tanĂºsĂ­tvĂ¡nyrögzĂ­tĂ©st<ph name="END_LINK" /> hasznĂ¡l. A hĂ¡lĂ³zati hibĂ¡k Ă©s tĂ¡madĂ¡sok rendszerint Ă¡tmenetiek, ezĂ©rt az emlĂ­tett oldal kĂ©sÅ‘bb valĂ³szĂ­nűleg mĂ¡r működni fog.</translation>
<translation id="7269802741830436641">Ez a weboldal Ă¡tirĂ¡nyĂ­tĂ¡si körbe kerĂ¼lt</translation>
<translation id="7275334191706090484">Kezelt könyvjelzÅ‘k</translation>
<translation id="7298195798382681320">AjĂ¡nlott</translation>
-<translation id="7301833672208172928">Az elÅ‘zmĂ©nyek szinkronizĂ¡lĂ¡sĂ¡nak bekapcsolĂ¡sa</translation>
+<translation id="7309308571273880165">HibajelentĂ©s kĂ©szĂ¼lt: <ph name="CRASH_TIME" /> (a felhasznĂ¡lĂ³ Ă¡ltal kĂ©rt feltöltĂ©s – mĂ©g nincs feltöltve)</translation>
<translation id="7334320624316649418">&amp;ĂtrendezĂ©s Ăºjra</translation>
<translation id="733923710415886693">A szerver tanĂºsĂ­tvĂ¡nyĂ¡t nem A tanĂºsĂ­tvĂ¡nyok Ă¡tlĂ¡thatĂ³sĂ¡ga keretrendszeren keresztĂ¼l hoztĂ¡k nyilvĂ¡nossĂ¡gra.</translation>
+<translation id="7351800657706554155">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mert a tanĂºsĂ­tvĂ¡nyĂ¡t visszavontĂ¡k. A hĂ¡lĂ³zati hibĂ¡k Ă©s tĂ¡madĂ¡sok rendszerint Ă¡tmenetiek, ezĂ©rt az emlĂ­tett oldal kĂ©sÅ‘bb valĂ³szĂ­nűleg mĂ¡r működni fog. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Parancssor</translation>
<translation id="7372973238305370288">keresĂ©si talĂ¡lat</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -539,16 +572,17 @@ Pszt! Az inkognitĂ³mĂ³d (<ph name="SHORTCUT_KEY" />) hasznos lehet a következÅ‘
<translation id="7469372306589899959">KĂ¡rtya igazolĂ¡sa…</translation>
<translation id="7481312909269577407">Előre</translation>
<translation id="7485870689360869515">Nem talĂ¡lhatĂ³ adat.</translation>
+<translation id="7508255263130623398">A visszakapott hĂ¡zirend eszközazonosĂ­tĂ³ja Ă¼res, vagy nem felel meg a jelenlegi eszközazonosĂ­tĂ³nak</translation>
<translation id="7514365320538308">Letöltés</translation>
<translation id="7518003948725431193">Nem talĂ¡lhatĂ³ weboldal az internetcĂ­men:<ph name="URL" /></translation>
<translation id="7537536606612762813">KötelezÅ‘</translation>
<translation id="7542995811387359312">Az automatikus bankkĂ¡rtya-kitöltĂ©s le van tiltva, mivel ez az űrlap nem biztonsĂ¡gos kapcsolatot hasznĂ¡l.</translation>
<translation id="7549584377607005141">Ez a weboldal korĂ¡bban megadott adatokat kĂ©r ahhoz, hogy megfelelÅ‘en jelenjen meg. Az adatokat Ăºjra elkĂ¼ldheti, de ezzel meg fog ismĂ©telni minden olyan műveletet, amelyet ez az oldal korĂ¡bban vĂ©grehajtott.</translation>
<translation id="7554791636758816595">Ăj lap</translation>
-<translation id="7567204685887185387">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nyĂ¡t csalĂ¡ssal Ă¡llĂ­thattĂ¡k ki. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy egy tĂ¡madĂ³ eltĂ©rĂ­tette az Ă–n kapcsolĂ³dĂ¡sĂ¡t.</translation>
<translation id="7568593326407688803">Az oldal nyelve<ph name="ORIGINAL_LANGUAGE" />KĂ­vĂ¡nja lefordĂ­tani?</translation>
<translation id="7569952961197462199">EltĂ¡volĂ­tja a hitelkĂ¡rtyĂ¡t a Chrome-bĂ³l?</translation>
<translation id="7578104083680115302">A Google rendszerĂ©ben mentett kĂ¡rtyĂ¡kkal gyorsan fizethet webhelyeken Ă©s alkalmazĂ¡sokban bĂ¡rmelyik eszközĂ©n.</translation>
+<translation id="7588950540487816470">Fizikai web</translation>
<translation id="7592362899630581445">A szervertanĂºsĂ­tvĂ¡ny sĂ©rti a nĂ©vre vonatkozĂ³ megkötĂ©seket.</translation>
<translation id="759889825892636187">A(z) <ph name="HOST_NAME" /> jelenleg nem tudja kezelni ezt a kérést.</translation>
<translation id="7600965453749440009">Soha ne fordĂ­tsa le a(z) <ph name="LANGUAGE" /> nyelvű szöveget</translation>
@@ -559,6 +593,7 @@ Pszt! Az inkognitĂ³mĂ³d (<ph name="SHORTCUT_KEY" />) hasznos lehet a következÅ‘
<translation id="7637571805876720304">EltĂ¡volĂ­tja a hitelkĂ¡rtyĂ¡t a ChromiumbĂ³l?</translation>
<translation id="765676359832457558">SpeciĂ¡lis beĂ¡llĂ­tĂ¡sok elrejtĂ©se...</translation>
<translation id="7658239707568436148">MĂ©gse</translation>
+<translation id="7667346355482952095">A visszaadott irĂ¡nyelvtoken Ă¼res vagy nem egyezik az aktuĂ¡lis tokennel</translation>
<translation id="7668654391829183341">Ismeretlen eszköz</translation>
<translation id="7674629440242451245">Érdekli nĂ©hĂ¡ny remek Ăºj Chrome-funkciĂ³? PrĂ³bĂ¡lja ki a fejlesztÅ‘i csatornĂ¡nkat a chrome.com/dev webhelyen.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />TovĂ¡bb a(z) <ph name="SITE" /> webhelyre (nem biztonsĂ¡gos)<ph name="END_LINK" /></translation>
@@ -575,10 +610,10 @@ Pszt! Az inkognitĂ³mĂ³d (<ph name="SHORTCUT_KEY" />) hasznos lehet a következÅ‘
<translation id="780301667611848630">Köszönöm, nem</translation>
<translation id="7805768142964895445">Ăllapot</translation>
<translation id="7813600968533626083">EltĂ¡volĂ­tja a javaslatot a Chrome-bĂ³l?</translation>
+<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> talĂ¡lhatĂ³ a(z) â€<ph name="SEARCH_STRING" />†kifejezĂ©sre</translation>
<translation id="785549533363645510">Azonban Ă–n nem teljesen lĂ¡thatatlan. Az inkognitĂ³mĂ³d hasznĂ¡lata nem rejti el böngĂ©szĂ©si műveleteit munkĂ¡ltatĂ³ja, az internetszolgĂ¡ltatĂ³ja Ă©s a felkeresett webhelyek elÅ‘l.</translation>
<translation id="7887683347370398519">EllenÅ‘rizze a CVC-t, majd prĂ³bĂ¡lja Ăºjra</translation>
<translation id="7894616681410591072">HoppĂ¡! <ph name="NAME" /> engedĂ©lyĂ©re van szĂ¼ksĂ©ge ahhoz, hogy elĂ©rhesse ezt az oldalt.</translation>
-<translation id="790025292736025802"><ph name="URL" /> nem talĂ¡lhatĂ³</translation>
<translation id="7912024687060120840">Ebben a mappĂ¡ban:</translation>
<translation id="7920092496846849526">MegkĂ©rdezted a szĂ¼lÅ‘t, hogy meg szabad-e lĂ¡togatnod ezt az oldalt.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -591,9 +626,10 @@ Pszt! Az inkognitĂ³mĂ³d (<ph name="SHORTCUT_KEY" />) hasznos lehet a következÅ‘
<translation id="7995512525968007366">Nincs megadva</translation>
<translation id="8012647001091218357">Jelenleg nem tudjuk elĂ©rni szĂ¼leidet. PrĂ³bĂ¡lkozz Ăºjra.</translation>
<translation id="8034522405403831421">Ez az oldal <ph name="SOURCE_LANGUAGE" /> nyelven van. LefordĂ­tja <ph name="TARGET_LANGUAGE" /> nyelvre?</translation>
-<translation id="8034955203865359138">Nincsenek elÅ‘zmĂ©nybejegyzĂ©sek.</translation>
<translation id="8088680233425245692">Nem sikerĂ¼lt megtekinteni a cikket.</translation>
+<translation id="8089520772729574115">kevesebb mint 1 MB</translation>
<translation id="8091372947890762290">Az aktivĂ¡lĂ¡s fĂ¼ggÅ‘ben van a szerveren</translation>
+<translation id="8129262335948759431">ismeretlen mennyiség</translation>
<translation id="8131740175452115882">MegerÅ‘sĂ­tĂ©s</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> szerverĂ©nek <ph name="BEGIN_ABBR" />DNS-cĂ­me<ph name="END_ABBR" /> nem talĂ¡lhatĂ³.</translation>
<translation id="8149426793427495338">SzĂ¡mĂ­tĂ³gĂ©pe alvĂ³ Ă¼zemmĂ³dba vĂ¡ltott.</translation>
@@ -602,6 +638,7 @@ Pszt! Az inkognitĂ³mĂ³d (<ph name="SHORTCUT_KEY" />) hasznos lehet a következÅ‘
<translation id="8201077131113104583">A(z) â€<ph name="EXTENSION_ID" />†azonosĂ­tĂ³jĂº bÅ‘vĂ­tmĂ©ny frissĂ­tĂ©si URL-je Ă©rvĂ©nytelen.</translation>
<translation id="8218327578424803826">HozzĂ¡rendelt helyszĂ­n:</translation>
<translation id="8225771182978767009">A szĂ¡mĂ­tĂ³gĂ©pet beĂ¡llĂ­tĂ³ szemĂ©ly a webhely letiltĂ¡sa mellett döntött.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" /> Ă©s <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">A keresett oldal a megadott informĂ¡ciĂ³t hasznĂ¡lta. Ha visszatĂ©r arra az oldalra, akkor lehet, hogy az egyszer mĂ¡r megtett mozdulatok ismĂ©tlĂ©sre kerĂ¼lnek. MĂ©gis tovĂ¡bblĂ©p?</translation>
<translation id="8249320324621329438">UtolsĂ³ lekĂ©rĂ©s:</translation>
<translation id="8261506727792406068">Törlés</translation>
@@ -614,12 +651,17 @@ Pszt! Az inkognitĂ³mĂ³d (<ph name="SHORTCUT_KEY" />) hasznos lehet a következÅ‘
<translation id="8349305172487531364">KönyvjelzÅ‘sĂ¡v</translation>
<translation id="8363502534493474904">RepĂ¼lÅ‘s Ă¼zemmĂ³d kikapcsolĂ¡sa</translation>
<translation id="8364627913115013041">Nincs beĂ¡llĂ­tva.</translation>
+<translation id="8380941800586852976">Veszélyes</translation>
<translation id="8412145213513410671">RendszerösszeomlĂ¡sok ( <ph name="CRASH_COUNT" /> )</translation>
<translation id="8412392972487953978">MindkĂ©t alkalommal ugyanazt az összetett jelszĂ³t kell megadnia.</translation>
<translation id="8428213095426709021">BeĂ¡llĂ­tĂ¡sok</translation>
+<translation id="8433057134996913067">Ezzel kijelentkezik a legtöbb webhelyrÅ‘l.</translation>
<translation id="8437238597147034694">&amp;ĂthelyezĂ©s visszavonĂ¡sa</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 hitelkĂ¡rtya}other{# hitelkĂ¡rtya}}</translation>
+<translation id="8483780878231876732">Jelentkezzen be a Chrome-ba, hogy hasznĂ¡lhassa a kĂ¡rtyĂ¡kat Google-fiĂ³kjĂ¡bĂ³l.</translation>
<translation id="8488350697529856933">A következÅ‘re Ă©rvĂ©nyes</translation>
<translation id="8498891568109133222">A(z) <ph name="HOST_NAME" /> tĂºl hosszĂº ideje nem vĂ¡laszol.</translation>
+<translation id="852346902619691059">A szerver nem tudta bizonyĂ­tani, hogy valĂ³ban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsĂ¡gi tanĂºsĂ­tvĂ¡nya az eszköz operĂ¡ciĂ³s rendszere szerint nem megbĂ­zhatĂ³. Ennek oka lehet konfigurĂ¡ciĂ³s hiba, vagy hogy tĂ¡madĂ³ tĂ©rĂ­tette el az Ă–n kapcsolĂ³dĂ¡sĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />TovĂ¡bbi informĂ¡ciĂ³<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">A Google Payments nem tĂ¡mogatja az ilyen tĂ­pusĂº kĂ¡rtyĂ¡kat. KĂ©rjĂ¼k, vĂ¡lasszon egy mĂ¡sikat.</translation>
<translation id="8550022383519221471">A szinkronizĂ¡lĂ¡si szolgĂ¡ltatĂ¡s az Ă–n domainjĂ©n nem Ă©rhetÅ‘ el.</translation>
<translation id="8553075262323480129">A fordĂ­tĂ¡s nem sikerĂ¼lt, mivel az oldal nyelvĂ©t nem lehet megĂ¡llapĂ­tani.</translation>
@@ -631,15 +673,12 @@ Pszt! Az inkognitĂ³mĂ³d (<ph name="SHORTCUT_KEY" />) hasznos lehet a következÅ‘
<translation id="8647750283161643317">Minden visszaĂ¡llĂ­tĂ¡sa az alapĂ©rtĂ©kre</translation>
<translation id="8680787084697685621">A fiĂ³k bejelentkezĂ©si rĂ©szletei elavultak.</translation>
<translation id="8703575177326907206">A kapcsolat (<ph name="DOMAIN" />) nem titkosĂ­tott.</translation>
-<translation id="8713130696108419660">Helytelen elsÅ‘ alĂ¡Ă­rĂ¡s</translation>
<translation id="8725066075913043281">ĂjraprĂ³bĂ¡lĂ¡s</translation>
<translation id="8728672262656704056">Ă–n inkognitĂ³mĂ³dra vĂ¡ltott</translation>
<translation id="8730621377337864115">KĂ©sz</translation>
<translation id="8738058698779197622">BiztonsĂ¡gos kapcsolat lĂ©trehozĂ¡sĂ¡hoz az Ă³rĂ¡t pontosan be kell Ă¡llĂ­tani. Ez azĂ©rt szĂ¼ksĂ©ges, mert a webhelyek Ă¡ltal az azonosĂ­tĂ¡sukra hasznĂ¡lt tanĂºsĂ­tvĂ¡nyok csak adott ideig Ă©rvĂ©nyesek. Mivel az eszköz Ă³rĂ¡ja nem pontos, a Chromium nem tudja ellenÅ‘rizni ezeket a tanĂºsĂ­tvĂ¡nyokat.</translation>
<translation id="8740359287975076522">A(z) <ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS-cĂ­me&lt;/abbr&gt; nem talĂ¡lhatĂ³. A problĂ©ma diagnosztizĂ¡lĂ¡sa folyamatban van.</translation>
-<translation id="8741995161408053644">ElÅ‘fordulhat, hogy a böngĂ©szĂ©si elÅ‘zmĂ©nyek mĂ¡s formĂ¡i mĂ©g megtalĂ¡lhatĂ³k Google-fiĂ³kjĂ¡ban a <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> cĂ­men.</translation>
<translation id="8790007591277257123">&amp;TörlĂ©s Ăºjra</translation>
-<translation id="8790687370365610530">A Google Ă¡ltal javasolt, szemĂ©lyre szabott tartalmak fogadĂ¡sĂ¡hoz kapcsolja be az elÅ‘zmĂ©nyek szinkronizĂ¡lĂ¡sĂ¡t.</translation>
<translation id="8798099450830957504">Alapértelmezett</translation>
<translation id="8804164990146287819">AdatvĂ©delmi irĂ¡nyelvek</translation>
<translation id="8820817407110198400">KönyvjelzÅ‘k</translation>
@@ -661,13 +700,11 @@ Pszt! Az inkognitĂ³mĂ³d (<ph name="SHORTCUT_KEY" />) hasznos lehet a következÅ‘
<translation id="8971063699422889582">A szerver tanĂºsĂ­tvĂ¡nya lejĂ¡rt.</translation>
<translation id="8987927404178983737">hĂ³nap</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">A szerver olyan tanĂºsĂ­tvĂ¡nyt mutatott be, amelyet nem A tanĂºsĂ­tvĂ¡nyok Ă¡tlĂ¡thatĂ³sĂ¡ga keretrendszer segĂ­tsĂ©gĂ©vel hoztak nyilvĂ¡nossĂ¡gra. Ez egyes tanĂºsĂ­tvĂ¡nyoknĂ¡l követelmĂ©ny annak biztosĂ­tĂ¡sa Ă©rdekĂ©ben, hogy az adott tanĂºsĂ­tvĂ¡nyok megbĂ­zhatĂ³k, Ă©s vĂ©delmet nyĂºjtanak a tĂ¡madĂ³k ellen.</translation>
<translation id="9001074447101275817">A(z) <ph name="DOMAIN" /> proxy felhasznĂ¡lĂ³nevet Ă©s jelszĂ³t kĂ©r.</translation>
<translation id="901974403500617787">Rendszerszinten Ă©rvĂ©nyes jelölÅ‘ket csak a tulajdonos (<ph name="OWNER_EMAIL" />) Ă¡llĂ­that be.</translation>
<translation id="9020542370529661692">Az oldalt lefordĂ­tottuk <ph name="TARGET_LANGUAGE" /> nyelvre.</translation>
<translation id="9038649477754266430">A vĂ¡rhatĂ³ kifejezĂ©s szolgĂ¡ltatĂ¡s hasznĂ¡lata az oldalak gyorsabb betöltĂ©se Ă©rdekĂ©ben</translation>
<translation id="9039213469156557790">Emellett az oldal mĂ¡s forrĂ¡sokat is tartalmaz, amelyek nem biztonsĂ¡gosak. Ezeket a forrĂ¡sokat mĂ¡sok is megtekinthetik Ă¡tvitel közben, Ă©s megvĂ¡ltoztatĂ¡sukkal a tĂ¡madĂ³k mĂ³dosĂ­thatjĂ¡k az oldal viselkedĂ©sĂ©t.</translation>
-<translation id="9049981332609050619">MegprĂ³bĂ¡lta elĂ©rni a(z) <ph name="DOMAIN" /> webhelyet, de a szerver Ă©rvĂ©nytelen tanĂºsĂ­tvĂ¡nyt mutatott be.</translation>
<translation id="9050666287014529139">Ă–sszetett jelszĂ³</translation>
<translation id="9065203028668620118">Szerkesztés</translation>
<translation id="9092364396508701805">A(z) <ph name="HOST_NAME" /> oldal nem működik</translation>
diff --git a/chromium/components/strings/components_strings_id.xtb b/chromium/components/strings/components_strings_id.xtb
index e85b829165a..2608fa1fa6d 100644
--- a/chromium/components/strings/components_strings_id.xtb
+++ b/chromium/components/strings/components_strings_id.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="id">
+<translation id="1008557486741366299">Jangan Sekarang</translation>
<translation id="1015730422737071372">Berikan detail tambahan</translation>
<translation id="1032854598605920125">Putar searah jarum jam</translation>
<translation id="1038842779957582377">nama tidak diketahui</translation>
+<translation id="1053591932240354961">Saat ini, Anda tidak dapat mengunjungi <ph name="SITE" /> karena situs web ini mengirimkan kredensial acak yang tidak dapat diproses oleh Google Chrome. Kesalahan dan serangan jaringan biasanya bersifat sementara, jadi laman ini mungkin akan bekerja nanti. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Urungkan Penambahan</translation>
<translation id="10614374240317010">Jangan pernah disimpan</translation>
-<translation id="1064422015032085147">Server yang menghosting laman web mungkin kelebihan muatan atau sedang diperbaiki.
- Untuk menghindari munculnya lalu lintas yang terlalu banyak dan memperburuk keadaan,
- permintaan untuk URL ini tidak diizinkan untuk sementara.</translation>
<translation id="106701514854093668">Bookmark Desktop</translation>
<translation id="1080116354587839789">Paskan dengan lebar</translation>
+<translation id="1103124106085518534">Sudah tidak ada konten baru</translation>
<translation id="1103523840287552314">Selalu terjemahkan <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Apabila dicentang, Chrome akan menyimpan salinan kartu Anda pada perangkat ini untuk pengisian formulir yang lebih cepat.</translation>
+<translation id="1111153019813902504">Bookmark yang baru dibuka</translation>
<translation id="1113869188872983271">&amp;Urungkan pengaturan ulang</translation>
+<translation id="1126551341858583091">Ukuran di penyimpanan lokal adalah <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache kebijakan Oke</translation>
<translation id="113188000913989374"><ph name="SITE" /> menyatakan:</translation>
<translation id="1132774398110320017">Setelan IsiOtomatis Chrome...</translation>
-<translation id="1150979032973867961">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh sistem operasi komputer Anda. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="1152921474424827756">Akses <ph name="BEGIN_LINK" />salinan yang disimpan dalam cache<ph name="END_LINK" /> dari <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> tiba-tiba menutup sambungan.</translation>
<translation id="1161325031994447685">Menyambungkan ulang ke Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Hapus</translation>
<translation id="1201402288615127009">Berikutnya</translation>
<translation id="1201895884277373915">Lainnya dari situs ini</translation>
-<translation id="121201262018556460">Anda bermaksud membuka <ph name="DOMAIN" />, namun server menyajikan sertifikat yang berisi kunci yang lemah. Penyerang mungkin telah merusak kunci pribadi, dan server mungkin bukan yang diharapkan (Anda mungkin sedang berkomunikasi dengan penyerang).</translation>
+<translation id="1206967143813997005">Tanda tangan awal tidak valid</translation>
+<translation id="1209206284964581585">Sembunyikan sekarang</translation>
<translation id="1219129156119358924">Keamanan Sistem</translation>
<translation id="1227224963052638717">Kebijakan tidak dikenal.</translation>
<translation id="1227633850867390598">Sembunyikan nilai</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Ya</translation>
<translation id="1430915738399379752">Cetak</translation>
<translation id="1442912890475371290">Usaha yang diblokir <ph name="BEGIN_LINK" /> untuk mengunjungi laman di <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Saat ini, Anda tidak dapat mengunjungi <ph name="SITE" /> karena situs web ini menggunakan penyematan sertifikat. Kesalahan dan serangan jaringan biasanya bersifat sementara, jadi laman ini mungkin akan bekerja nanti. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Tampilkan salinan tersimpan (yang diketahui telah habis masa berlakunya) dari laman ini.</translation>
<translation id="1519264250979466059">Tanggal Dibuat</translation>
<translation id="1549470594296187301">JavaScript harus diaktifkan untuk menggunakan fitur ini.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Konfigurasi cadangan tidak valid dan tidak dapat diimpor.</translation>
<translation id="1644574205037202324">Riwayat</translation>
<translation id="1645368109819982629">Protokol yang tidak didukung</translation>
-<translation id="1655462015569774233">{1,plural, =1{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; masa berlaku sertifikat keamanannya telah berakhir kemarin. Hal ini mungkin disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang memintas sambungan internet Anda. Jam komputer Anda saat ini diatur ke <ph name="CURRENT_DATE" />. Apakah terlihat sesuai? Jika tidak, Anda harus membenarkan jam sistem dan menyegarkan laman ini.}other{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; masa berlaku sertifikat keamanannya telah berakhir # hari yang lalu. Hal ini mungkin disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang memintas sambungan internet Anda. Jam komputer Anda saat ini diatur ke <ph name="CURRENT_DATE" />. Apakah terlihat sesuai? Jika tidak, Anda harus membenarkan jam sistem dan menyegarkan laman ini.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> biasanya menggunakan enkripsi untuk melindungi informasi Anda. Saat Google Chrome mencoba menyambung ke <ph name="SITE" /> kali ini, situs web mengembalikan kredensial yang salah dan tidak biasa. Hal ini dapat terjadi jika ada penyerang yang berpura-pura menjadi <ph name="SITE" />, atau layar masuk Wi-Fi mengganggu sambungan. Informasi Anda masih aman karena Google Chrome menghentikan sambungan sebelum terjadi pertukaran data apa pun.</translation>
<translation id="168841957122794586">Sertifikat server berisi kunci kriptografis yang lemah.</translation>
<translation id="1701955595840307032">Dapatkan konten yang disarankan</translation>
-<translation id="1706954506755087368">{1,plural, =1{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya sepertinya dari esok hari. Hal ini mungkin disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang memintas sambungan internet Anda.}other{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya sepertinya dari # hari mendatang. Hal ini mungkin disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang memintas sambungan internet Anda.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Coba hubungi admin sistem.</translation>
<translation id="17513872634828108">Buka tab</translation>
<translation id="1753706481035618306">Nomor laman</translation>
-<translation id="1761412452051366565">Untuk mendapatkan konten hasil personalisasi yang disarankan oleh Google, aktifkan sinkronisasi.</translation>
-<translation id="1763864636252898013">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh sistem operasi perangkat Anda. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Coba jalankan Diagnostik Jaringan Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Perbarui frasa sandi sinkronisasi Anda.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Bookmark yang baru-baru ini dikunjungi akan muncul di sini.</translation>
<translation id="1821930232296380041">Permintaan atau parameter permintaan tidak valid</translation>
<translation id="1838667051080421715">Anda sedang melihat sumber laman web.</translation>
<translation id="1871208020102129563">Proxy disetel untuk menggunakan server proxy tetap, bukan URL skrip .pac.</translation>
<translation id="1883255238294161206">Ciutkan daftar</translation>
<translation id="1898423065542865115">Pemfilteran</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> tidak menerima sertifikat masuk Anda, atau sertifikat masuk mungkin telah habis masa berlakunya.</translation>
<translation id="194030505837763158">Buka <ph name="LINK" /></translation>
<translation id="1962204205936693436">Bookmark <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Kesalahan serialisasi</translation>
<translation id="1974060860693918893">Lanjutan</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{dan 1 lainnya}other{dan # lainnya}}</translation>
<translation id="2025186561304664664">Proxy disetel ke konfigurasi otomatis.</translation>
<translation id="2030481566774242610">Mungkin maksud Anda <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Anda melihat pesan ini karena Anda baru pertama kali mengunjungi situs ini dan orang tua harus menyetujuinya terlebih dahulu.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Memeriksa proxy dan firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Kode pos</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 saran}other{# saran}}</translation>
<translation id="2065985942032347596">Diperlukan Otentikasi</translation>
<translation id="2079545284768500474">Batalkan</translation>
<translation id="20817612488360358">Setelan proxy sistem disetel untuk digunakan namun konfigurasi proxy eksplisit juga ditentukan.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Edit Bookmark</translation>
<translation id="2166049586286450108">Akses Penuh Admin</translation>
<translation id="2166378884831602661">Situs ini tidak dapat menyediakan sambungan aman</translation>
-<translation id="2171101176734966184">Anda berusaha menjangkau <ph name="DOMAIN" />, tetapi server menyajikan sertifikat yang ditandatangani menggunakan algoritme tanda tangan yang lemah. Artinya kredensial keamanan yang disajikan server mungkin telah dipalsukan, dan server tersebut mungkin bukan yang diharapkan (Anda mungkin sedang berkomunikasi dengan penyerang).</translation>
<translation id="2181821976797666341">Kebijakan</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 alamat}other{# alamat}}</translation>
<translation id="2212735316055980242">Kebijakan tidak ditemukan</translation>
<translation id="2213606439339815911">Mengambil entri...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> tidak tersedia</translation>
<translation id="2230458221926704099">Perbaiki sambungan menggunakan <ph name="BEGIN_LINK" />aplikasi diagnosis<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Kirim sekarang</translation>
<translation id="225207911366869382">Nilai ini sudah usang untuk kebijakan ini.</translation>
<translation id="2262243747453050782">Kesalahan HTTP</translation>
<translation id="2282872951544483773">Eksperimen Tidak Tersedia</translation>
<translation id="2292556288342944218">Akses Internet Anda diblokir</translation>
<translation id="229702904922032456">Masa berlaku sertifikat akar atau menengah telah berakhir.</translation>
<translation id="230155334948463882">Kartu baru?</translation>
+<translation id="2305919008529760154">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya mungkin telah dikeluarkan secara tidak sah. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut <ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> memerlukan nama pengguna dan sandi.</translation>
+<translation id="2318774815570432836">Saat ini, Anda tidak dapat mengunjungi <ph name="SITE" /> karena situs web tersebut menggunakan HSTS. Kesalahan dan serangan jaringan biasanya bersifat sementara, jadi laman ini mungkin akan bekerja nanti. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Mengabaikan bookmark tidak valid di indeks <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Bookmark lain</translation>
<translation id="2359808026110333948">Lanjut</translation>
<translation id="2365563543831475020">Laporan kerusakan yang diambil pada pukul <ph name="CRASH_TIME" /> tidak diunggah</translation>
<translation id="2367567093518048410">Tingkat</translation>
+<translation id="2371153335857947666">{1,plural, =1{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; masa berlaku sertifikat keamanannya telah berakhir kemarin. Hal ini dapat disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang mencegat sambungan Anda. Jam komputer Anda saat ini disetel ke <ph name="CURRENT_DATE" />. Apakah sudah sesuai? Jika belum sesuai, Anda harus membenarkan jam sistem dan menyegarkan laman ini. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.}other{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; masa berlaku sertifikat keamanannya telah berakhir # hari yang lalu. Hal ini dapat disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang mencegat sambungan Anda. Jam komputer Anda saat ini disetel ke <ph name="CURRENT_DATE" />. Apakah sudah sesuai? Jika belum sesuai, Anda harus membenarkan jam sistem dan menyegarkan laman ini. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Tidak tersedia alternatif UI</translation>
<translation id="2384307209577226199">Default perusahaan</translation>
-<translation id="238526402387145295">Anda tidak dapat mengunjungi <ph name="SITE" /> saat ini karena situs web tersebut <ph name="BEGIN_LINK" />menggunakan HSTS<ph name="END_LINK" />. Kesalahan jaringan dan penyerang biasanya bersifat sementara, jadi laman ini mungkin akan bekerja nanti.</translation>
<translation id="2386255080630008482">Sertifikat server telah dicabut.</translation>
<translation id="2392959068659972793">Tampilkan kebijakan tanpa nilai yang disetel</translation>
<translation id="2396249848217231973">&amp;Urungkan penghapusan</translation>
-<translation id="2413528052993050574">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya mungkin dicabut. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="2455981314101692989">Laman web ini telah menonaktifkan pengisian otomatis untuk formulir ini.</translation>
+<translation id="2463739503403862330">Isi</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Jalankan Diagnostik Jaringan<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL penelusuran tidak valid.</translation>
<translation id="2491120439723279231">Sertifikat server mengandung kesalahan.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Kirim</translation>
<translation id="2674170444375937751">Yakin ingin menghapus laman ini dari riwayat?</translation>
<translation id="2677748264148917807">Keluar</translation>
+<translation id="269990154133806163">Server menunjukkan sertifikat yang tidak diungkapkan secara publik menggunakan kebijakan Transparansi Sertifikat. Ini adalah persyaratan untuk beberapa sertifikat, guna memastikan bahwa sertifikat tersebut dapat dipercaya dan melindungi dari penyerang. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Nilai tidak sesuai format.</translation>
<translation id="2704951214193499422">Saat ini Chromium tidak dapat mengonfirmasi kartu. Coba lagi nanti.</translation>
<translation id="2705137772291741111">Salinan tersimpan (dalam cache) situs ini tidak dapat dibaca.</translation>
<translation id="2709516037105925701">Isi-Otomatis</translation>
+<translation id="2712118517637785082">Anda berusaha menjangkau <ph name="DOMAIN" />, tetapi sertifikat yang ditunjukkan oleh server telah dicabut oleh penerbitnya. Artinya, kredensial keamanan yang ditunjukkan server tidak dapat dipercaya. Anda mungkin sedang berkomunikasi dengan penyerang. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Minta izin</translation>
<translation id="2721148159707890343">Permintaan berhasil</translation>
<translation id="2728127805433021124">Sertifikat server ditandai menggunakan algoritme yang lemah.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Bilah penelusuran dan alamat</translation>
<translation id="2826760142808435982">Sambungan dienkripsi dan diautentikasi menggunakan <ph name="CIPHER" /> dan menggunakan <ph name="KX" /> sebagai mekanisme pertukaran kunci.</translation>
<translation id="2835170189407361413">Hapus formulir</translation>
-<translation id="2837049386027881519">Sambungan harus dicoba lagi menggunakan versi yang lebih lama dari protokol TLS atau SSL. Biasanya, ini artinya server menggunakan perangkat lunak yang amat lawas dan mungkin mengalami masalah keamanan lainnya.</translation>
<translation id="284702764277384724">Sertifikat server di <ph name="HOST_NAME" /> tampaknya palsu.</translation>
<translation id="2889159643044928134">Jangan Muat Ulang</translation>
-<translation id="2896499918916051536">Plugin ini tidak didukung.</translation>
+<translation id="2900469785430194048">Google Chrome kehabisan memori saat mencoba menampilkan laman web ini.</translation>
<translation id="2909946352844186028">Perubahan jaringan terdeteksi.</translation>
-<translation id="2915500479781995473">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; masa berlaku sertifikat keamanannya telah habis. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda. Saat ini jam komputer Anda disetel ke <ph name="CURRENT_TIME" />. Apakah sudah benar? Jika belum, sebaiknya perbaiki jam sistem kemudian segarkan laman ini.</translation>
<translation id="2922350208395188000">Sertifikat server tidak dapat diperiksa.</translation>
-<translation id="2941952326391522266">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya dari <ph name="DOMAIN2" />. Hal ini disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="2948083400971632585">Anda dapat menonaktifkan proxy apa pun yang dikonfigurasi untuk sambungan dari laman setelan.</translation>
<translation id="2955913368246107853">Tutup bilah cari</translation>
<translation id="2958431318199492670">Konfigurasi jaringan tidak mematuhi standar ONC. Bagian dari konfigurasi mungkin tidak diimpor.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Jenis kebijakan salah</translation>
<translation id="3032412215588512954">Ingin memuat ulang situs ini?</translation>
<translation id="3037605927509011580">Yah!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{minimal 1 item pada perangkat yang disinkronkan}=1{1 item (dan beberapa di perangkat yang disinkronkan)}other{# item (dan beberapa di perangkat yang disinkronkan)}}</translation>
<translation id="3041612393474885105">Informasi Sertifikat</translation>
<translation id="3063697135517575841">Saat ini Chrome tidak dapat mengonfirmasi kartu. Coba lagi nanti.</translation>
<translation id="3093245981617870298">Anda sedang offline.</translation>
@@ -204,17 +207,18 @@
memastikan bahwa server proxy bekerja. Jika Anda tidak yakin harus
menggunakan server proxy:
<ph name="PLATFORM_TEXT" /></translation>
-<translation id="3202578601642193415">Teranyar</translation>
+<translation id="3202578601642193415">Terbaru</translation>
<translation id="3207960819495026254">Diberi bookmark</translation>
-<translation id="3225919329040284222">Server menunjukkan sertifikat yang tidak sesuai dengan harapan terpasang. Harapan ini disertakan untuk situs web tertentu dengan keamanan tinggi guna melindungi Anda.</translation>
<translation id="3226128629678568754">Tekan tombol muat ulang untuk mengirimkan lagi data yang dibutuhkan untuk memuat laman ini.</translation>
<translation id="3228969707346345236">Terjemahan gagal karena laman sudah dalam bahasa <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Masukkan CVC untuk <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Bookmark laman ini</translation>
<translation id="3270847123878663523">&amp;Urungkan Pengaturan Ulang</translation>
<translation id="3286538390144397061">Mulai Ulang Sekarang</translation>
+<translation id="3303855915957856445">Hasil penelusuran tidak ditemukan</translation>
<translation id="3305707030755673451">Data Anda dienkripsi dengan frasa sandi sinkronisasi pada tanggal <ph name="TIME" />. Masukkan frasa sandi untuk memulai sinkronisasi.</translation>
<translation id="333371639341676808">Cegah dialog lain dari laman ini.</translation>
+<translation id="3338095232262050444">Aman</translation>
<translation id="3340978935015468852">setelan</translation>
<translation id="3345135638360864351">Permintaan Anda untuk mengakses situs ini tidak dapat dikirimkan ke <ph name="NAME" />. Coba lagi.</translation>
<translation id="3355823806454867987">Ubah setelan proxy...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Interval pengambilan:</translation>
<translation id="3462200631372590220">Sembunyikan lanjutan</translation>
<translation id="3479539252931486093">Apakah hal ini tidak diharapkan? <ph name="BEGIN_LINK" />Beri tahu kami<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Jangan sekarang</translation>
<translation id="348000606199325318">ID Kerusakan <ph name="CRASH_LOCAL_ID" /> (ID Server: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Orang tua Anda saat ini tidak dapat dihubungi. Coba lagi.</translation>
<translation id="3527085408025491307">Folder</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Gunakan sandi untuk:</translation>
<translation id="3549644494707163724">Enkripsikan data yang disinkronkan dengan frasa sandi sinkronisasi Anda</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> lainnya...</translation>
+<translation id="3555561725129903880">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya berasal dari <ph name="DOMAIN2" />. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Sambungan Anda tidak pribadi</translation>
<translation id="3583757800736429874">&amp;Ulangi Pemindahan</translation>
<translation id="3586931643579894722">Sembunyikan detail</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Tampilkan nilai</translation>
<translation id="3630155396527302611">Jika sudah tercantum sebagai program yang diizinkan untuk mengakses jaringan,
coba hapus dari daftar dan tambahkan lagi.</translation>
+<translation id="3638794133396384728">Server tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; masa berlaku sertifikat keamanannya sudah berakhir. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. Jam komputer Anda saat ini disetel ke <ph name="CURRENT_TIME" />. Apakah sudah benar? Jika belum sesuai, Anda harus membenarkan jam sistem dan menyegarkan laman ini. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Fitur eksperimental ini bisa berubah, rusak, atau hilang kapan saja. Kami sama sekali tidak menjamin apa yang akan terjadi saat eksperimen ini dinyalakan, siapa tahu browser Anda tiba-tiba hangus terbakar! Becanda! Tapi bisa jadi browser akan menghapus semua data, atau keamanan dan privasi Anda akan disusupi secara tak terduga. Eksperimen yang Anda aktifkan akan diaktifkan untuk semua pengguna browser ini. Lanjutkan dengan hati-hati.</translation>
<translation id="3650584904733503804">Validasi berhasil</translation>
<translation id="3655670868607891010">Jika Anda sering melihatnya, coba <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Revisi</translation>
+<translation id="3678029195006412963">Permintaan tidak dapat ditandatangani</translation>
<translation id="3681007416295224113">Informasi sertifikat</translation>
<translation id="3693415264595406141">Sandi:</translation>
+<translation id="3696411085566228381">tidak ada</translation>
<translation id="3700528541715530410">Ups, sepertinya Anda tidak memiliki izin untuk mengakses laman ini.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Membuka...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Aktifkan data seluler atau Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Periksa proxy, firewall, dan konfigurasi DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Tautan yang Anda salin</translation>
-<translation id="3744899669254331632">Anda tidak dapat mengunjungi <ph name="SITE" /> sekarang karena situs web mengirim kredensial tak beraturan yang tidak dapat diproses Chromium. Kesalahan jaringan dan serangan biasanya bersifat sementara, sehingga laman ini mungkin akan bekerja nanti.</translation>
<translation id="375403751935624634">Terjemahan gagal karena kesalahan server.</translation>
<translation id="3759461132968374835">Tidak ada laporan kondisi ngadat saat ini. Kondisi ngadat yang terjadi saat pelaporan kondisi ngadat tidak diaktifkan tidak akan tampil di sini.</translation>
<translation id="3788090790273268753">Sertifikat untuk situs ini berakhir masa berlakunya pada tahun 2016, dan rantai sertifikat tersebut berisi sertifikat yang ditandatangani menggunakan SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Pengenal perangkat bertentangan</translation>
<translation id="3885155851504623709">Parish</translation>
<translation id="3901925938762663762">Kartu telah habis masa berlakunya</translation>
+<translation id="3910267023907260648">Anda berusaha menjangkau <ph name="DOMAIN" />, tetapi server menunjukkan sertifikat yang ditandatangani menggunakan algoritme tanda tangan yang lemah. Artinya, kredensial keamanan yang ditunjukkan server mungkin telah dipalsukan dan server tersebut mungkin bukan server yang diharapkan (Anda mungkin sedang berkomunikasi dengan penyerang). <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya sepertinya dari esok hari. Hal ini dapat disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.}other{Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya sepertinya dari # hari mendatang. Hal ini dapat disebabkan oleh kesalahan konfigurasi, atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Gagal memuat dokumen PDF</translation>
<translation id="3963721102035795474">Mode Pembaca</translation>
+<translation id="397105322502079400">Menghitung...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> diblokir.</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 laman web di sekitar}other{# laman web di sekitar}}</translation>
<translation id="4021036232240155012">DNS adalah layanan jaringan yang menerjemahkan nama situs web ke alamat Internet-nya.</translation>
<translation id="4030383055268325496">&amp;Urungkan penambahan</translation>
-<translation id="4032534284272647190">Akses ke <ph name="URL" /> ditolak.</translation>
<translation id="404928562651467259">PERINGATAN</translation>
<translation id="4058922952496707368">Kunci "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Klien dan server tidak mendukung versi protokol SSL umum atau cipher suite.</translation>
<translation id="4079302484614802869">Konfigurasi proxy disetel untuk menggunakan URL skrip .pac, bukan server proxy yang tetap.</translation>
<translation id="4103249731201008433">Nomor seri perangkat tidak valid</translation>
<translation id="4103763322291513355">Kunjungi &lt;strong&gt;chrome://policy&lt;/strong&gt; untuk melihat daftar URL yang masuk daftar hitam dan kebijakan lain yang diterapkan oleh administrator sistem Anda.</translation>
+<translation id="4110615724604346410">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya berisi berbagai kesalahan. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Lingkup kebijakan tidak didukung.</translation>
+<translation id="4118212371799607889">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh Chromium. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 lainnya}other{# lainnya}}</translation>
<translation id="4130226655945681476">Periksa kabel jaringan, modem, dan router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Ingin Chromium menyimpan kartu ini?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Dinonaktifkan</translation>
<translation id="4196861286325780578">&amp;Ulangi pemindahan</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Periksa konfigurasi antivirus dan firewall<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{tidak ada}=1{1 aplikasi ($1)}=2{2 aplikasi ($1, $2)}other{# aplikasi ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Kerusakan</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Coba jalankan Diagnostik Jaringan<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Tidak</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Tidak ada nama pengguna)</translation>
<translation id="4300246636397505754">Saran induk</translation>
<translation id="4304224509867189079">Log In</translation>
+<translation id="432290197980158659">Server menunjukkan sertifikat yang tidak sesuai dengan perkiraan yang ada. Perkiraan ini disertakan untuk situs web tertentu dengan keamanan tingkat tinggi untuk melindungi Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Gagal menemukan artikel</translation>
+<translation id="4331708818696583467">Tidak Aman</translation>
<translation id="4372948949327679948">Nilai <ph name="VALUE_TYPE" /> yang diharapkan.</translation>
-<translation id="4377125064752653719">Anda berusaha menjangkau <ph name="DOMAIN" />, tetapi sertifikat yang disajikan oleh server telah dibatalkan oleh penerbitnya. Artinya informasi rahasia keamanan yang disajikan tidak dapat dipercaya. Anda mungkin sedang berkomunikasi dengan penyerang.</translation>
<translation id="4381091992796011497">Nama Pengguna:</translation>
<translation id="4394049700291259645">Nonaktifkan</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> sampai <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">hasil penelusuran</translation>
-<translation id="4424024547088906515">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh Chrome. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> tidak menerima sertifikat masuk Anda, atau sertifikat masuk mungkin tidak diberikan.</translation>
<translation id="443673843213245140">Penggunaan proxy dinonaktifkan tetapi konfigurasi proxy yang eksplisit ditentukan.</translation>
<translation id="4458874409874303848">SitusAman</translation>
<translation id="4461847750548395463">Anda melihat pesan ini karena Google SitusAman aktif.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Detail</translation>
<translation id="4558551763791394412">Coba nonaktifkan ekstensi.</translation>
<translation id="4587425331216688090">Hapus alamat dari Chrome?</translation>
+<translation id="4589078953350245614">Anda berusaha menjangkau <ph name="DOMAIN" />, tetapi server menunjukkan sertifikat yang tidak valid. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Sambungan Anda ke <ph name="DOMAIN" /> dienkripsi menggunakan cipher suite modern.</translation>
<translation id="4594403342090139922">&amp;Urungkan Penghapusan</translation>
+<translation id="4627442949885028695">Lanjutkan dari perangkat lain</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Anda sedang melihat laman ekstensi.</translation>
-<translation id="467662567472608290">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya berisi kesalahan. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> dicekal</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Sambungan Anda terganggu</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Jalankan Diagnostik Jaringan Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Platform</translation>
<translation id="4744603770635761495">Jalur Yang Dapat Dijalankan</translation>
<translation id="4756388243121344051">&amp;Riwayat</translation>
+<translation id="4759238208242260848">Unduhan</translation>
<translation id="4764776831041365478">Laman web di <ph name="URL" /> mungkin sedang tidak aktif untuk sementara atau dipindahkan secara permanen ke alamat web baru.</translation>
<translation id="4771973620359291008">Terjadi kesalahan yang tidak diketahui.</translation>
<translation id="4782449893814226250">Anda telah meminta izin kepada orang tua untuk mengunjungi laman ini.</translation>
<translation id="4800132727771399293">Periksa tanggal masa berlaku habis dan CVC, lalu coba lagi</translation>
-<translation id="4807049035289105102">Saat ini Anda tidak dapat mengunjungi <ph name="SITE" /> karena situs web tersebut mengirim kredensial acak yang tidak dapat diproses oleh Google Chrome. Kesalahan jaringan dan serangan biasanya bersifat sementara, jadi laman ini mungkin akan bekerja nanti.</translation>
<translation id="4813512666221746211">Kesalahan jaringan</translation>
<translation id="4816492930507672669">Paskan dengan halaman</translation>
<translation id="4850886885716139402">Lihat</translation>
<translation id="4880827082731008257">Telusuri riwayat</translation>
+<translation id="4884656795097055129">Artikel lainnya akan muncul di waktu yang tepat.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{dan 1 laman web lainnya}other{dan # laman web lainnya}}</translation>
<translation id="4923417429809017348">Laman ini telah diterjemahkan dari bahasa yang tidak diketahui ke bahasa <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Harus ditentukan.</translation>
<translation id="4930497775425430760">Anda melihat pesan ini karena Anda baru pertama kali mengunjungi situs ini dan orang tua harus menyetujuinya terlebih dahulu.</translation>
<translation id="495170559598752135">Tindakan</translation>
<translation id="4958444002117714549">Luaskan daftar</translation>
+<translation id="4962322354953122629">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh Chrome. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Terjemahkan dari <ph name="ORIGINAL_LANGUAGE" /> ke <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Plugin ini tidak didukung</translation>
<translation id="5002932099480077015">Jika diaktifkan, Chrome akan menyimpan salinan kartu Anda di perangkat ini untuk pengisian formulir yang lebih cepat.</translation>
<translation id="5019198164206649151">Penyimpanan cadangan dalam kondisi buruk</translation>
<translation id="5023310440958281426">Periksa kebijakan administrator Anda</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Tentang Google Terjemahan</translation>
<translation id="5040262127954254034">Privasi</translation>
<translation id="5045550434625856497">Sandi salah</translation>
+<translation id="5056549851600133418">Artikel untuk Anda</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Periksa alamat proxy<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Sertifikat server saat ini tidak valid.</translation>
<translation id="5089810972385038852">Negara bagian</translation>
-<translation id="5094747076828555589">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh Chromium. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="5095208057601539847">Provinsi</translation>
<translation id="5115563688576182185">(64 bit)</translation>
-<translation id="5122371513570456792">Ditemukan <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> hasil untuk '<ph name="SEARCH_STRING" />'.</translation>
<translation id="5141240743006678641">Enkripsikan sandi yang disinkronkan dengan kredensial Google Anda</translation>
<translation id="5145883236150621069">Ada kode kesalahan dalam tanggapan kebijakan</translation>
<translation id="5171045022955879922">Telusuri atau ketik URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Bilah Bookmark</translation>
<translation id="5199729219167945352">Eksperimen</translation>
<translation id="5251803541071282808">Awan</translation>
+<translation id="5277279256032773186">Menggunakan Chrome di kantor? Perusahaan dapat mengelola setelan Chrome untuk karyawan mereka. Pelajari lebih lanjut</translation>
<translation id="5299298092464848405">Kebijakan kesalahan penguraian</translation>
<translation id="5300589172476337783">Tampilkan</translation>
<translation id="5308689395849655368">Pelaporan kondisi ngadat dinonaktifkan.</translation>
<translation id="5317780077021120954">Simpan</translation>
<translation id="5327248766486351172">Nama</translation>
+<translation id="5359637492792381994">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak valid untuk saat ini. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Gagal menyimpan setelan kebijakan</translation>
-<translation id="540969355065856584">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya saat ini tidak valid. Hal ini mungkin disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mengganggu sambungan internet Anda.</translation>
<translation id="5421136146218899937">Hapus data penjelajahan...</translation>
<translation id="5430298929874300616">Buang bookmark</translation>
<translation id="5431657950005405462">File Anda tidak ditemukan</translation>
<translation id="5435775191620395718">Menampilkan riwayat dari perangkat ini. <ph name="BEGIN_LINK" />Pelajari lebih lanjut<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Saat ini saran konten hasil personalisasi dinonaktifkan, karena data yang disinkronkan dilindungi frasa sandi khusus.</translation>
<translation id="5439770059721715174">Kesalahan validasi skema di "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Laman <ph name="HOST_NAME" /> ini tidak dapat ditemukan</translation>
<translation id="5455374756549232013">Stempel waktu kebijakan salah</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Ingin keluar dari situs ini?</translation>
<translation id="5629630648637658800">Gagal memuat setelan kebijakan</translation>
<translation id="5631439013527180824">Token pengelolaan perangkat tidak valid</translation>
-<translation id="5650551054760837876">Tak ada hasil penelusuran yang ditemukan.</translation>
<translation id="5677928146339483299">Dicekal</translation>
<translation id="5710435578057952990">Identitas situs Web ini belum diverifikasi.</translation>
<translation id="5720705177508910913">Pengguna saat ini</translation>
+<translation id="572328651809341494">Tab baru-baru ini</translation>
<translation id="5784606427469807560">Terjadi masalah saat mengonfirmasi kartu. Periksa sambungan internet Anda dan coba lagi.</translation>
<translation id="5785756445106461925">Selain itu, laman ini berisi sumber daya lainnya yang tidak aman. Sumber daya ini dapat dilihat oleh orang lain saat transit dan dapat dimodifikasi oleh penyerang untuk mengubah tampilan perangkat.</translation>
+<translation id="5786044859038896871">Ingin mengisi informasi kartu?</translation>
+<translation id="5803412860119678065">Ingin mengisi <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Sambungan Anda ke <ph name="DOMAIN" /> dienkripsi menggunakan cipher suite yang sudah usang.</translation>
<translation id="5813119285467412249">&amp;Ulangi Penambahan</translation>
+<translation id="5814352347845180253">Anda dapat kehilangan akses ke konten premium dari <ph name="SITE" /> dan beberapa situs lain.</translation>
+<translation id="5843436854350372569">Anda mencoba menjangkau <ph name="DOMAIN" />, tetapi server menunjukkan sertifikat yang berisi kunci lemah. Penyerang mungkin telah merusak kunci pribadi dan server tersebut mungkin bukan server yang diharapkan (Anda mungkin sedang berkomunikasi dengan penyerang). <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Anda melihat pesan ini karena pengelola memblokir situs ini.</translation>
<translation id="5857090052475505287">Folder Baru</translation>
<translation id="5869405914158311789">Situs ini tidak dapat dijangkau</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Saran Induk</translation>
<translation id="59107663811261420">Kartu jenis ini tidak didukung oleh Google Payments untuk pedagang ini. Pilih kartu lain.</translation>
<translation id="59174027418879706">Diaktifkan</translation>
+<translation id="5926846154125914413">Anda dapat kehilangan akses ke konten premium dari beberapa situs.</translation>
<translation id="5966707198760109579">Minggu</translation>
<translation id="5967867314010545767">Hapus dari riwayat</translation>
<translation id="5975083100439434680">Perkecil</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Otomatis</translation>
<translation id="6042308850641462728">Lainnya</translation>
<translation id="6060685159320643512">Hati-hati, eksperimen ini dapat menimbulkan masalah</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{tidak ada}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Periksa semua kabel dan boot ulang router, modem, atau perangkat
jaringan lain yang mungkin Anda gunakan.</translation>
<translation id="614940544461990577">Coba:</translation>
<translation id="6150607114729249911">Ups! Anda perlu izin dari orang tua untuk mengunjungi laman ini.</translation>
<translation id="6151417162996330722">Sertifikat server memiliki masa berlaku yang terlalu panjang.</translation>
-<translation id="6154808779448689242">Token kebijakan yang dikembalikan tidak cocok dengan token saat ini</translation>
<translation id="6165508094623778733">Pelajari lebih lanjut</translation>
<translation id="6203231073485539293">Periksa sambungan internet Anda</translation>
<translation id="6218753634732582820">Hapus alamat dari Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Coba nonaktifkan prediksi jaringan</translation>
<translation id="6337534724793800597">Filter kebijakan menurut nama</translation>
<translation id="6342069812937806050">Baru saja</translation>
+<translation id="6345221851280129312">ukuran tak diketahui</translation>
<translation id="6355080345576803305">Diganti oleh sesi publik</translation>
<translation id="6358450015545214790">Apakah maksud ini?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 saran lain}other{# saran lain}}</translation>
<translation id="6387478394221739770">Tertarik dengan fitur Chrome baru yang keren? Coba saluran beta kami di chrome.com/beta.</translation>
-<translation id="641480858134062906"><ph name="URL" /> gagal dimuat</translation>
+<translation id="6389758589412724634">Chromium kehabisan memori saat mencoba menampilkan laman web ini.</translation>
+<translation id="6416403317709441254">Saat ini, Anda tidak dapat mengunjungi <ph name="SITE" /> karena situs web ini mengirimkan kredensial acak yang tidak dapat diproses oleh Chromium. Kesalahan dan serangan jaringan biasanya bersifat sementara, jadi laman ini mungkin akan bekerja nanti. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Tidak dapat memeriksa apakah sertifikat telah ditarik.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> menolak untuk tersambung.</translation>
<translation id="6445051938772793705">Negara</translation>
<translation id="6451458296329894277">Konfirmasikan Pengiriman Ulang Formulir</translation>
<translation id="6458467102616083041">Diabaikan karena penelusuran default dinonaktifkan oleh kebijakan.</translation>
+<translation id="6462969404041126431">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya mungkin sudah dicabut. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Kebijakan perangkat</translation>
<translation id="6489534406876378309">Mulai mengunggah kerusakan</translation>
<translation id="6529602333819889595">&amp;Ulangi Penghapusan</translation>
+<translation id="6534179046333460208">Saran Web Fisik</translation>
<translation id="6550675742724504774">Opsi</translation>
+<translation id="6593753688552673085">kurang dari <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opsi enkripsi</translation>
<translation id="662080504995468778">Tinggal</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Penelusuran</translation>
-<translation id="6634865548447745291">Saat ini, Anda tidak dapat mengunjungi <ph name="SITE" /> karena <ph name="BEGIN_LINK" />sertifikat ini telah dicabut<ph name="END_LINK" />. Kesalahan jaringan dan serangan biasanya bersifat sementara, jadi laman ini mungkin akan bekerja nanti.</translation>
<translation id="6644283850729428850">Kebijakan ini telah usang.</translation>
+<translation id="6652240803263749613">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh sistem operasi komputer. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Edit Folder</translation>
<translation id="6660210980321319655">Otomatis dilaporkan pada <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Hapus saran formulir dari Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Sebelumnya</translation>
<translation id="6710594484020273272">&lt;Ketik istilah penelusuran&gt;</translation>
<translation id="6711464428925977395">Ada yang salah dengan server proxy, atau alamat tidak benar.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{tidak ada}=1{1 item}other{# item}}</translation>
<translation id="674375294223700098">Kesalahan sertifikat server tidak dikenal.</translation>
<translation id="6753269504797312559">Nilai kebijakan</translation>
<translation id="6757797048963528358">Perangkat Anda sedang dalam mode tidur.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Tingkat kebijakan tidak didukung.</translation>
<translation id="6895330447102777224">Kartu telah dikonfirmasi</translation>
<translation id="6897140037006041989">Agen Pengguna</translation>
-<translation id="6903907808598579934">Aktifkan sinkronisasi</translation>
<translation id="6915804003454593391">Pengguna:</translation>
<translation id="6957887021205513506">Sertifikat server tampaknya palsu.</translation>
<translation id="6965382102122355670">Oke</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Distrik</translation>
<translation id="6973656660372572881">Server proxy tetap dan URL skrip .pac telah ditentukan.</translation>
<translation id="6989763994942163495">Tampilkan setelan lanjutan...</translation>
+<translation id="7000990526846637657">Entri riwayat tidak ditemukan</translation>
+<translation id="7009986207543992532">Anda berusaha menjangkau <ph name="DOMAIN" />, tetapi server menunjukkan sertifikat yang masa berlakunya terlalu lama untuk dapat dipercaya. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Akun Google Anda mungkin memiliki bentuk riwayat penjelajahan lainnya di <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Sandi</translation>
-<translation id="7050187094878475250">Anda berusaha menjangkau <ph name="DOMAIN" />, namun server memberikan sertifikat yang masa berlakunya terlalu lama untuk dapat dipercaya.</translation>
<translation id="7087282848513945231">County</translation>
<translation id="7088615885725309056">Lawas</translation>
<translation id="7090678807593890770">Telusuri <ph name="LINK" /> di Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Anda melihat pesan ini karena Anda baru pertama kali mengunjungi situs ini dan pengelola harus menyetujuinya terlebih dahulu.</translation>
<translation id="724975217298816891">Masukkan tanggal habis masa berlaku dan CVC untuk <ph name="CREDIT_CARD" /> guna memperbarui detail kartu. Setelah mengonfirmasi, detail kartu Anda akan dibagikan dengan situs ini.</translation>
<translation id="725866823122871198">Sambungan pribadi ke <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak dapat dibuat karena tanggal dan waktu (<ph name="DATE_AND_TIME" />) komputer Anda tidak benar.</translation>
-<translation id="7265986070661382626">Anda tidak dapat mengunjungi <ph name="SITE" /> saat ini karena situs web <ph name="BEGIN_LINK" />menggunakan penyematan sertifikat<ph name="END_LINK" />. Kesalahan jaringan dan serangan biasanya bersifat sementara, jadi laman ini mungkin akan bekerja nanti.</translation>
<translation id="7269802741830436641">Laman web ini memiliki simpul pengalihan</translation>
<translation id="7275334191706090484">Bookmark yang Terkelola</translation>
<translation id="7298195798382681320">Direkomendasikan</translation>
-<translation id="7301833672208172928">Aktifkan sinkronisasi riwayat</translation>
+<translation id="7309308571273880165">Laporan kerusakan diambil pada <ph name="CRASH_TIME" /> (upload yang diminta pengguna, belum diupload)</translation>
<translation id="7334320624316649418">&amp;Ulangi pengaturan ulang</translation>
<translation id="733923710415886693">Sertifikat server tidak diungkapkan melalui Transparansi Sertifikat.</translation>
+<translation id="7351800657706554155">Saat ini, Anda tidak dapat mengunjungi <ph name="SITE" /> karena sertifikatnya telah dicabut. Kesalahan dan serangan jaringan biasanya bersifat sementara, jadi laman ini mungkin akan berfungsi nanti. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Baris Perintah</translation>
<translation id="7372973238305370288">hasil penelusuran</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="7469372306589899959">Mengonfirmasi kartu</translation>
<translation id="7481312909269577407">Maju</translation>
<translation id="7485870689360869515">Tidak ada data yang ditemukan.</translation>
+<translation id="7508255263130623398">ID perangkat kebijakan yang dikembalikan kosong atau tidak cocok dengan ID perangkat saat ini</translation>
<translation id="7514365320538308">Unduh</translation>
<translation id="7518003948725431193">Tidak ada laman web yang ditemukan untuk alamat web:<ph name="URL" /></translation>
<translation id="7537536606612762813">Wajib</translation>
<translation id="7542995811387359312">Pengisian kartu kredit otomatis dinonaktifkan karena formulir ini tidak menggunakan sambungan aman.</translation>
<translation id="7549584377607005141">Laman web ini membutuhkan data yang Anda masukkan sebelumnya agar dapat ditampilkan dengan benar. Anda dapat mengirimkan data ini lagi, namun dengan begitu Anda akan mengulangi tindakan apa pun yang sebelumnya dilakukan oleh laman ini.</translation>
<translation id="7554791636758816595">Tab Baru</translation>
-<translation id="7567204685887185387">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya mungkin telah dikeluarkan dengan curang. Hal ini disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="7568593326407688803">Laman ini dalam bahasa<ph name="ORIGINAL_LANGUAGE" />Ingin diterjemahkan?</translation>
<translation id="7569952961197462199">Hapus kartu kredit dari Chrome?</translation>
<translation id="7578104083680115302">Bayar di situs dan aplikasi di semua perangkat dengan cepat menggunakan kartu yang disimpan dengan Google.</translation>
+<translation id="7588950540487816470">Web Fisik</translation>
<translation id="7592362899630581445">Sertifikat server melanggar batasan nama.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> saat ini tidak dapat menangani permintaan ini.</translation>
<translation id="7600965453749440009">Jangan pernah terjemahkan bahasa <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="7637571805876720304">Hapus kartu kredit dari Chromium?</translation>
<translation id="765676359832457558">Sembunyikan setelan lanjutan...</translation>
<translation id="7658239707568436148">Batal</translation>
+<translation id="7667346355482952095">Token kebijakan yang dikembalikan kosong atau tidak cocok dengan token saat ini</translation>
<translation id="7668654391829183341">Perangkat tidak dikenal</translation>
<translation id="7674629440242451245">Tertarik dengan fitur Chrome baru yang keren? Coba saluran dev kami di chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Lanjutkan ke <ph name="SITE" /> (tidak aman)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="780301667611848630">Lain kali</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7813600968533626083">Hapus sebagai saran dari Chrome?</translation>
+<translation id="7815407501681723534">Ditemukan <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> hasil untuk '<ph name="SEARCH_STRING" />'</translation>
<translation id="785549533363645510">Namun, Anda masih dapat terlihat. Masuk ke mode penyamaran tidak menyembunyikan penjelajahan Anda dari atasan, penyedia layanan internet, atau situs web yang Anda kunjungi.</translation>
<translation id="7887683347370398519">Periksa CVC dan coba lagi</translation>
<translation id="7894616681410591072">Ups! Anda perlu izin dari <ph name="NAME" /> untuk mengakses laman ini.</translation>
-<translation id="790025292736025802"><ph name="URL" /> tidak ditemukan</translation>
<translation id="7912024687060120840">Dalam Folder:</translation>
<translation id="7920092496846849526">Anda telah meminta izin kepada orang tua untuk mengunjungi laman ini.</translation>
<translation id="7935318582918952113">Penyaring DOM</translation>
@@ -593,9 +628,10 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="7995512525968007366">Tidak Ditentukan</translation>
<translation id="8012647001091218357">Orang tua Anda saat ini tidak dapat dihubungi. Coba lagi.</translation>
<translation id="8034522405403831421">Laman ini berbahasa <ph name="SOURCE_LANGUAGE" />. Terjemahkan ke <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Tidak ditemukan entri riwayat.</translation>
<translation id="8088680233425245692">Gagal melihat artikel.</translation>
+<translation id="8089520772729574115">kurang dari 1 MB</translation>
<translation id="8091372947890762290">Aktivasi ditunda di server</translation>
+<translation id="8129262335948759431">jumlah tak diketahui</translation>
<translation id="8131740175452115882">Konfirmasi</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Alamat DNS<ph name="END_ABBR" /> server <ph name="HOST_NAME" /> tidak dapat ditemukan.</translation>
<translation id="8149426793427495338">Komputer Anda sedang dalam mode tidur.</translation>
@@ -604,6 +640,7 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="8201077131113104583">URL pembaruan tidak valid untuk ekstensi dengan ID "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Lokasi yang Ditetapkan:</translation>
<translation id="8225771182978767009">Orang yang menyiapkan komputer ini telah memilih untuk memblokir situs ini.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Laman yang dicari menggunakan informasi yang Anda masukkan. Kembali ke laman tersebut dapat menyebabkan pengulangan tindakan apa pun yang Anda lakukan. Apakah Anda ingin melanjutkan?</translation>
<translation id="8249320324621329438">Terakhir diambil:</translation>
<translation id="8261506727792406068">Hapus</translation>
@@ -616,12 +653,17 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="8349305172487531364">Bilah bookmark</translation>
<translation id="8363502534493474904">Nonaktifkan mode pesawat</translation>
<translation id="8364627913115013041">Tidak disetel.</translation>
+<translation id="8380941800586852976">Berbahaya</translation>
<translation id="8412145213513410671">Ngadat (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Anda harus memasukkan frasa sandi yang sama dua kali.</translation>
<translation id="8428213095426709021">Setelan</translation>
+<translation id="8433057134996913067">Tindakan ini akan mengeluarkan Anda dari sebagian besar situs web.</translation>
<translation id="8437238597147034694">&amp;Urungkan pemindahan</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kartu kredit}other{# kartu kredit}}</translation>
+<translation id="8483780878231876732">Untuk menggunakan kartu dari Akun Google Anda, masuk ke Chrome</translation>
<translation id="8488350697529856933">Berlaku untuk</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> membutuhkan terlalu banyak waktu untuk merespons.</translation>
+<translation id="852346902619691059">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh sistem operasi perangkat. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mencegat sambungan Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Kartu jenis ini tidak didukung oleh Google Payments. Pilih kartu lain.</translation>
<translation id="8550022383519221471">Layanan sinkronisasi tidak tersedia untuk domain Anda.</translation>
<translation id="8553075262323480129">Terjemahan gagal karena bahasa laman tidak dapat ditentukan.</translation>
@@ -633,15 +675,12 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="8647750283161643317">Setel ulang semua ke default</translation>
<translation id="8680787084697685621">Detail proses masuk akun sudah usang.</translation>
<translation id="8703575177326907206">Sambungan ke <ph name="DOMAIN" /> tidak dienkripsi.</translation>
-<translation id="8713130696108419660">Tanda tangan awal yang buruk</translation>
<translation id="8725066075913043281">Coba lagi</translation>
<translation id="8728672262656704056">Anda masuk mode penyamaran</translation>
<translation id="8730621377337864115">Selesai</translation>
<translation id="8738058698779197622">Untuk membuat sambungan aman, jam perlu disetel dengan benar. Hal ini karena sertifikat yang digunakan situs web untuk mengidentifikasi situs web tersebut hanya valid untuk jangka waktu tertentu. Karena jam perangkat tidak benar, Chromium tidak dapat memverifikasi sertifikat ini.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Alamat DNS&lt;/abbr&gt; <ph name="HOST_NAME" /> tidak dapat ditemukan. Mendiagnosis masalah.</translation>
-<translation id="8741995161408053644">Akun Google Anda mungkin memiliki bentuk riwayat penjelajahan lainnya di <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Ulangi penghapusan</translation>
-<translation id="8790687370365610530">Untuk mendapatkan konten hasil personalisasi yang disarankan oleh Google, aktifkan sinkronisasi riwayat.</translation>
<translation id="8798099450830957504">Default</translation>
<translation id="8804164990146287819">Kebijakan Privasi</translation>
<translation id="8820817407110198400">Bookmark</translation>
@@ -663,13 +702,11 @@ Ssst! <ph name="SHORTCUT_KEY" /> mode penyamaran mungkin berguna suatu saat nant
<translation id="8971063699422889582">Sertifikat server telah kedaluwarsa.</translation>
<translation id="8987927404178983737">Bulan</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Server menampilkan sertifikat yang tidak diungkapkan ke publik melalui kebijakan Transparansi Sertifikat. Ini adalah persyaratan untuk beberapa sertifikat, untuk memastikan bahwa sertifikat dapat dipercaya agar terlindung dari penyerang.</translation>
<translation id="9001074447101275817">Proxy <ph name="DOMAIN" /> memerlukan nama pengguna dan sandi.</translation>
<translation id="901974403500617787">Tanda yang berlaku bagi sistem secara luas hanya dapat disetel oleh pemilik: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Laman ini telah diterjemahkan ke <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Gunakan layanan prediksi agar laman dimuat dengan lebih cepat</translation>
<translation id="9039213469156557790">Selain itu, laman ini berisi sumber daya lainnya yang tidak aman. Sumber daya ini dapat dilihat oleh orang lain saat transit dan dapat dimodifikasi oleh penyerang untuk mengubah perilaku laman.</translation>
-<translation id="9049981332609050619">Anda berupaya menjangkau <ph name="DOMAIN" />, tetapi server menyajikan sertifikat yang tidak valid.</translation>
<translation id="9050666287014529139">Frasa sandi</translation>
<translation id="9065203028668620118">Edit</translation>
<translation id="9092364396508701805">Laman <ph name="HOST_NAME" /> tidak bekerja</translation>
diff --git a/chromium/components/strings/components_strings_it.xtb b/chromium/components/strings/components_strings_it.xtb
index ac6d9dd57b8..4180d6a3164 100644
--- a/chromium/components/strings/components_strings_it.xtb
+++ b/chromium/components/strings/components_strings_it.xtb
@@ -1,21 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="it">
+<translation id="1008557486741366299">Non adesso</translation>
<translation id="1015730422737071372">Fornisci ulteriori dettagli</translation>
<translation id="1032854598605920125">Ruota in senso orario</translation>
<translation id="1038842779957582377">nome sconosciuto</translation>
+<translation id="1053591932240354961">Al momento non puoi visitare il sito <ph name="SITE" /> perchĂ© ha inviato credenziali criptate che Google Chrome non è in grado di elaborare. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare piĂ¹ tardi. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Annulla aggiunta</translation>
<translation id="10614374240317010">Mai salvate</translation>
-<translation id="1064422015032085147">Il server che ospita la pagina web potrebbe essere sovraccarico o in fase di manutenzione. Per evitare di generare troppo traffico e di peggiorare la situazione, le richieste relative all'URL in questione sono state temporaneamente disattivate.</translation>
<translation id="106701514854093668">Preferiti desktop</translation>
<translation id="1080116354587839789">Adatta in larghezza</translation>
+<translation id="1103124106085518534">Finito per ora</translation>
<translation id="1103523840287552314">Traduci sempre <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Se questa opzione viene selezionata, Chrome memorizza una copia della carta sul dispositivo per velocizzare la compilazione dei moduli.</translation>
+<translation id="1111153019813902504">Preferiti aggiunti di recente</translation>
<translation id="1113869188872983271">&amp;Annulla ridisposizione</translation>
+<translation id="1126551341858583091">Le dimensioni nello spazio di archiviazione locale sono pari a <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache dei criteri integra</translation>
<translation id="113188000913989374"><ph name="SITE" /> dice:</translation>
<translation id="1132774398110320017">Impostazioni di Compilazione automatica Chrome...</translation>
-<translation id="1150979032973867961">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile dal sistema operativo del computer. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="1152921474424827756">Accedi a una <ph name="BEGIN_LINK" />copia memorizzata nella cache<ph name="END_LINK" /> di <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ha chiuso in modo imprevisto la connessione.</translation>
<translation id="1161325031994447685">Riconnessione alla rete Wi-Fi</translation>
@@ -23,7 +26,8 @@
<translation id="1181037720776840403">Rimuovi</translation>
<translation id="1201402288615127009">Avanti</translation>
<translation id="1201895884277373915">Altri dal sito</translation>
-<translation id="121201262018556460">Hai tentato di accedere a <ph name="DOMAIN" /> ma il server ha presentato un certificato contenente una chiave debole. Un utente malitenzionato potrebbe avere decifrato la chiave privata e il server potrebbe non essere quello previsto (è possibile che tu stia comunicando con un utente malintenzionato).</translation>
+<translation id="1206967143813997005">Firma iniziale non valida</translation>
+<translation id="1209206284964581585">Nascondi per ora</translation>
<translation id="1219129156119358924">Sicurezza del sistema</translation>
<translation id="1227224963052638717">Norma sconosciuta.</translation>
<translation id="1227633850867390598">Nascondi valore</translation>
@@ -44,6 +48,7 @@
<translation id="1426410128494586442">Sì</translation>
<translation id="1430915738399379752">Stampa</translation>
<translation id="1442912890475371290">Tentativo <ph name="BEGIN_LINK" />di visitare una pagina su <ph name="DOMAIN" /><ph name="END_LINK" /> bloccato.</translation>
+<translation id="1491663344921578213">Al momento non puoi visitare il sito <ph name="SITE" /> perchĂ© utilizza il blocco dei certificati. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare piĂ¹ tardi. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Mostra una copia salvata (cioè che è noto sia obsoleta) di questa pagina.</translation>
<translation id="1519264250979466059">Data build</translation>
<translation id="1549470594296187301">JavaScript deve essere attivato per utilizzare questa funzione.</translation>
@@ -58,36 +63,34 @@
<translation id="1644184664548287040">La configurazione di rete non è valida e non puĂ² essere importata.</translation>
<translation id="1644574205037202324">Cronologia</translation>
<translation id="1645368109819982629">Protocollo non supportato</translation>
-<translation id="1655462015569774233">{1,plural, =1{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto ieri. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. L'orologio del computer è attualmente impostato su <ph name="CURRENT_DATE" />. Ăˆ corretto? Se è sbagliato, dovresti regolare l'orologio e aggiornare la pagina.}other{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto # giorni fa. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. L'orologio del computer è attualmente impostato su <ph name="CURRENT_DATE" />. Ăˆ corretto? Se è sbagliato, dovresti regolare l'orologio e aggiornare la pagina.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> in genere utilizza la crittografia per proteggere le tue informazioni. Questa volta, quando Google Chrome ha provato a connettersi a <ph name="SITE" />, il sito web ha restituito credenziali insolite e sbagliate. Ăˆ possibile che un malintenzionato stia cercando di spacciarsi per il sito <ph name="SITE" /> oppure che una schermata di accesso alla rete Wi-Fi abbia interrotto la connessione. Le tue informazioni sono ancora al sicuro perchĂ© Google Chrome ha interrotto la connessione prima che avvenissero scambi di dati.</translation>
<translation id="168841957122794586">Il certificato del server contiene una chiave crittografica debole.</translation>
<translation id="1701955595840307032">Ricevi contenuti suggeriti</translation>
-<translation id="1706954506755087368">{1,plural, =1{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere attivo da domani. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.}other{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere attivo tra # giorni. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.}}</translation>
<translation id="1710259589646384581">Sistema operativo</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Prova a contattare l'amministratore di sistema.</translation>
<translation id="17513872634828108">Schede aperte</translation>
<translation id="1753706481035618306">Numero di pagina</translation>
-<translation id="1761412452051366565">Per ricevere contenuti suggeriti appositamente per te da Google, attiva la sicronizzazione.</translation>
-<translation id="1763864636252898013">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile dal sistema operativo del dispositivo. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Prova a eseguire lo strumento Diagnostica di rete Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Aggiorna la tua passphrase di sincronizzazione.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">I preferiti che visiti piĂ¹ spesso verranno visualizzati qui.</translation>
<translation id="1821930232296380041">Richiesta o parametri della richiesta non validi</translation>
<translation id="1838667051080421715">Ăˆ visualizzata la sorgente di una pagina web.</translation>
<translation id="1871208020102129563">L'impostazione del proxy prevede l'utilizzo di server proxy fissi, non di un URL script .pac.</translation>
<translation id="1883255238294161206">Comprimi elenco</translation>
<translation id="1898423065542865115">Filtri</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> non ha accettato il certificato di accesso oppure il certificato di accesso potrebbe essere scaduto.</translation>
<translation id="194030505837763158">Vai al link: <ph name="LINK" /></translation>
<translation id="1962204205936693436">Segnalibri di <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Errore di serializzazione</translation>
<translation id="1974060860693918893">Avanzate</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{e un'altra}other{e altre #}}</translation>
<translation id="2025186561304664664">Ăˆ stata impostata la configurazione automatica del proxy.</translation>
<translation id="2030481566774242610">Forse cercavi <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Visualizzi questo messaggio perché i tuoi genitori devono approvare i nuovi siti alla tua prima visita.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Controllare il proxy e firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ZIP</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 suggerimento}other{# suggerimenti}}</translation>
<translation id="2065985942032347596">Autenticazione richiesta</translation>
<translation id="2079545284768500474">Annulla</translation>
<translation id="20817612488360358">Devono essere utilizzate le impostazioni del proxy di sistema ma è stata specificata anche una configurazione proxy esplicita.</translation>
@@ -103,32 +106,34 @@
<translation id="2149973817440762519">Modifica Preferito</translation>
<translation id="2166049586286450108">Accesso amministrativo completo</translation>
<translation id="2166378884831602661">Il sito non puĂ² fornire una connessione protetta</translation>
-<translation id="2171101176734966184">Hai tentato di accedere a <ph name="DOMAIN" /> ma il server ha presentato un certificato firmato utilizzando un algoritmo di firma debole. CiĂ² significa che le credenziali di sicurezza presentate dal server potrebbero essere state falsificate e il server potrebbe non essere quello previsto (è possibile che tu stia comunicando con un utente malintenzionato).</translation>
<translation id="2181821976797666341">Criteri</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 indirizzo}other{# indirizzi}}</translation>
<translation id="2212735316055980242">Criterio non trovato</translation>
<translation id="2213606439339815911">Recupero voci...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> non disponibile</translation>
<translation id="2230458221926704099">Correggi la connessione con l'<ph name="BEGIN_LINK" />app diagnostica<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Invia ora</translation>
<translation id="225207911366869382">Il valore specificato per la norma è obsoleto.</translation>
<translation id="2262243747453050782">Errore HTTP</translation>
<translation id="2282872951544483773">Esperimenti non disponibili</translation>
<translation id="2292556288342944218">L'accesso a Internet è bloccato</translation>
<translation id="229702904922032456">Un certificato principale o intermedio è scaduto.</translation>
<translation id="230155334948463882">Nuova carta?</translation>
+<translation id="2305919008529760154">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere stato rilasciato in maniera fraudolenta. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> richiede un nome utente e una password.</translation>
+<translation id="2318774815570432836">Al momento non puoi visitare il sito <ph name="SITE" /> perchĂ© utilizza HSTS. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare piĂ¹ tardi. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Preferito non valido dell'indice <ph name="ENTRY_INDEX" /> ignorato</translation>
<translation id="2354001756790975382">Altri Preferiti</translation>
<translation id="2359808026110333948">Continua</translation>
<translation id="2365563543831475020">Il rapporto sugli arresti anomali generato il giorno <ph name="CRASH_TIME" /> non è stato caricato</translation>
<translation id="2367567093518048410">Livello</translation>
+<translation id="2371153335857947666">{1,plural, =1{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto ieri. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. L'orologio del computer è attualmente impostato su <ph name="CURRENT_DATE" />. Ăˆ corretto? Se è sbagliato, devi regolare l'orologio di sistema e aggiornare la pagina. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.}other{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto # giorni fa. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. L'orologio del computer è attualmente impostato su <ph name="CURRENT_DATE" />. Ăˆ corretto? Se è sbagliato, devi regolare l'orologio di sistema e aggiornare la pagina. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Nessuna alternativa UI disponibile</translation>
<translation id="2384307209577226199">Valore predefinito aziendale</translation>
-<translation id="238526402387145295">Al momento non puoi visitare il sito web all'indirizzo <ph name="SITE" /> perchĂ© <ph name="BEGIN_LINK" />utilizza HSTS<ph name="END_LINK" />. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare piĂ¹ tardi.</translation>
<translation id="2386255080630008482">Il certificato del server è stato revocato.</translation>
<translation id="2392959068659972793">Mostra norme senza valori</translation>
<translation id="2396249848217231973">&amp;Annulla eliminazione</translation>
-<translation id="2413528052993050574">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere revocato. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="2455981314101692989">La pagina web ha disattivato la compilazione automatica per questo modulo.</translation>
+<translation id="2463739503403862330">Compila</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Eseguire lo strumento Diagnostica di rete<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL ricerca non valido.</translation>
<translation id="2491120439723279231">Il certificato del server contiene degli errori.</translation>
@@ -150,10 +155,12 @@
<translation id="2653659639078652383">Invia</translation>
<translation id="2674170444375937751">Eliminare le pagine dalla cronologia?</translation>
<translation id="2677748264148917807">Esci</translation>
+<translation id="269990154133806163">Il server ha presentato un certificato che non è stato reso pubblico tramite le norme di Certificate Transparency, la cui applicazione costituisce un requisito di alcuni certificati al fine di garantire la loro attendibilità nonché la sicurezza nei confronti dei malintenzionati. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Il valore non corrisponde al formato.</translation>
<translation id="2704951214193499422">Al momento non è possibile confermare la carta in Chromium. Riprova piĂ¹ tardi.</translation>
<translation id="2705137772291741111">La copia del sito salvata (nella cache) era illeggibile.</translation>
<translation id="2709516037105925701">Compilazione automatica</translation>
+<translation id="2712118517637785082">Hai tentato di accedere a <ph name="DOMAIN" />, tuttavia il server ha presentato un certificato revocato dall'autoritĂ  di certificazione. CiĂ² significa che le credenziali di sicurezza presentate dal server non sono assolutamente attendibili. Potresti avere stabilito una comunicazione con un malintenzionato. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Chiedi autorizzazione</translation>
<translation id="2721148159707890343">Richiesta riuscita</translation>
<translation id="2728127805433021124">Il certificato del server è stato firmato utilizzando un algoritmo di firma debole.</translation>
@@ -165,14 +172,11 @@
<translation id="2824775600643448204">Barra degli indirizzi e di ricerca</translation>
<translation id="2826760142808435982">La connessione è stata crittografata e autenticata utilizzando <ph name="CIPHER" /> e <ph name="KX" /> come meccanismo di scambio delle chiavi.</translation>
<translation id="2835170189407361413">Cancella modulo</translation>
-<translation id="2837049386027881519">Ăˆ stato necessario ritentare la connessione utilizzando una versione precedente del protocollo TLS o SSL. In genere questo significa che il server utilizza software molto obsoleto e che potrebbe avere altri problemi di sicurezza.</translation>
<translation id="284702764277384724">Il certificato del server <ph name="HOST_NAME" /> risulta essere un falso.</translation>
<translation id="2889159643044928134">Non ricaricare</translation>
-<translation id="2896499918916051536">Questo plug-in non è supportato.</translation>
+<translation id="2900469785430194048">Google Chrome ha esaurito la memoria mentre cercava di visualizzare questa pagina web.</translation>
<translation id="2909946352844186028">Ăˆ stato rilevato un cambio di rete.</translation>
-<translation id="2915500479781995473">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto. Il problema potrebbe essere dovuto a un'errata configurazione o a un malitenzionato che ha intercettato la connessione. L'orologio del tuo computer è attualmente impostato sul giorno <ph name="CURRENT_TIME" />. Ăˆ corretto? In caso contrario dovresti regolare l'orologio del sistema e aggiornare la pagina.</translation>
<translation id="2922350208395188000">Il certificato del server non puĂ² essere verificato.</translation>
-<translation id="2941952326391522266">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza proviene da <ph name="DOMAIN2" />. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="2948083400971632585">Puoi disattivare tutti i proxy configurati per una connessione dalla pagina delle impostazioni.</translation>
<translation id="2955913368246107853">Chiudi la barra di ricerca</translation>
<translation id="2958431318199492670">La configurazione di rete non è conforme allo standard ONC. Parti della configurazione potrebbero non essere importate.</translation>
@@ -186,6 +190,7 @@
<translation id="3024663005179499861">Tipo di criterio errato</translation>
<translation id="3032412215588512954">Vuoi ricaricare questo sito?</translation>
<translation id="3037605927509011580">Uffa!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{almeno 1 elemento sui dispositivi sincronizzati}=1{1 elemento (e altri sui dispositivi sincronizzati)}other{# elementi (e altri sui dispositivi sincronizzati)}}</translation>
<translation id="3041612393474885105">Informazioni certificato</translation>
<translation id="3063697135517575841">Al momento non è possibile confermare la carta in Chrome. Riprova piĂ¹ tardi.</translation>
<translation id="3093245981617870298">Sei offline.</translation>
@@ -201,15 +206,16 @@
<translation id="3176929007561373547">Controlla le impostazioni del proxy o contatta il tuo amministratore di rete per verificare che il server proxy funzioni. Se non ritieni di dover utilizzare un server proxy: <ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Ultimo</translation>
<translation id="3207960819495026254">Aggiunto ai Preferiti</translation>
-<translation id="3225919329040284222">Il server ha presentato un certificato che non corrisponde alle previsioni integrate. Queste previsioni sono incluse per determinati siti web con protezione elevata allo scopo di proteggerti.</translation>
<translation id="3226128629678568754">Premi il pulsante Ricarica per inviare di nuovo i dati necessari per caricare la pagina.</translation>
<translation id="3228969707346345236">La traduzione non è riuscita perché la pagina è già in <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Inserisci il codice CVC della carta <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Aggiungi ai Preferiti</translation>
<translation id="3270847123878663523">&amp;Annulla ridisposizione</translation>
<translation id="3286538390144397061">Riavvia adesso</translation>
+<translation id="3303855915957856445">Nessun risultato di ricerca trovato</translation>
<translation id="3305707030755673451">I tuoi dati sono stati crittografati con la tua passphrase di sincronizzazione in data <ph name="TIME" />. Inseriscila per avviare la sincronizzazione.</translation>
<translation id="333371639341676808">Impedisci alla pagina di creare altre finestre di dialogo.</translation>
+<translation id="3338095232262050444">Sicuro</translation>
<translation id="3340978935015468852">impostazioni</translation>
<translation id="3345135638360864351">Impossibile inviare a <ph name="NAME" /> la richiesta di accesso a questo sito. Riprova.</translation>
<translation id="3355823806454867987">Modifica impostazioni proxy...</translation>
@@ -227,6 +233,7 @@
<translation id="3452404311384756672">Intervallo recupero:</translation>
<translation id="3462200631372590220">Nascondi avanzate</translation>
<translation id="3479539252931486093">Non era previsto? <ph name="BEGIN_LINK" />Contattaci<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Non adesso</translation>
<translation id="348000606199325318">ID arresto anomalo <ph name="CRASH_LOCAL_ID" /> (ID server: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">In questo momento, non è possibile raggiungere il tuo genitore. Riprova.</translation>
<translation id="3527085408025491307">Cartella</translation>
@@ -235,6 +242,7 @@
<translation id="3542684924769048008">Utilizza password per:</translation>
<translation id="3549644494707163724">Crittografa tutti i dati sincronizzati con la tua passphrase di sincronizzazione</translation>
<translation id="3549761410225185768">Altre <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza proviene da <ph name="DOMAIN2" />. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">La connessione non è privata</translation>
<translation id="3583757800736429874">&amp;Ripeti spostamento</translation>
<translation id="3586931643579894722">Nascondi dettagli</translation>
@@ -246,12 +254,15 @@
<translation id="3623476034248543066">Mostra valore</translation>
<translation id="3630155396527302611">Se è già elencato come programma autorizzato ad accedere alla rete, prova a
rimuoverlo dall'elenco e ad aggiungerlo di nuovo.</translation>
+<translation id="3638794133396384728">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. Al momento l'orologio del tuo computer è impostato su <ph name="CURRENT_TIME" />. Ăˆ corretto? Se è sbagliato, devi regolare l'orologio di sistema e aggiornare la pagina. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Queste funzioni sperimentali potrebbero essere modificate, essere interrotte o scomparire in qualsiasi momento. Non offriamo assolutamente alcuna garanzia su ciĂ² potrebbe accadere se attivi uno di questi esperimenti: il tuo browser potrebbe persino andare in autocombustione! Scherzi a parte, il browser potrebbe eliminare tutti i tuoi dati oppure la tua sicurezza e la tua privacy potrebbero essere compromesse in modi inaspettati. Tutti gli esperimenti che attivi saranno abilitati per tutti gli utenti di questo browser. Procedi con cautela.</translation>
<translation id="3650584904733503804">Convalida riuscita</translation>
<translation id="3655670868607891010">Se questo problema si verifica spesso, prova questi <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Revisione</translation>
+<translation id="3678029195006412963">Impossibile firmare la richiesta</translation>
<translation id="3681007416295224113">Informazioni certificato</translation>
<translation id="3693415264595406141">Password:</translation>
+<translation id="3696411085566228381">nessuno</translation>
<translation id="3700528541715530410">Spiacenti, sembra che tu non sia autorizzato ad accedere a questa pagina.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Caricamento in corso...</translation>
@@ -259,7 +270,6 @@
<translation id="3714780639079136834">Attivare la rete dati mobile o Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Controllare la configurazione del proxy, firewall e DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Link che hai copiato</translation>
-<translation id="3744899669254331632">Al momento non puoi visitare il sito <ph name="SITE" /> perchĂ© tale sito web ha inviato credenziali criptate che Chromium non è riuscito a elaborare. Gli attacchi e gli errori di rete in genere sono temporanei, pertanto è possibile che questa pagina funzioni piĂ¹ tardi.</translation>
<translation id="375403751935624634">La traduzione non è riuscita a causa di un errore del server.</translation>
<translation id="3759461132968374835">Non hai segnalato arresti anomali di recente. Quelli che si sono verificati quando la segnalazione degli arresti anomali era disabilitata non verranno visualizzati qui.</translation>
<translation id="3788090790273268753">Il certificato di questo sito scade nel 2016 e la catena di certificati contiene un certificato che è stato firmato utilizzando SHA-1.</translation>
@@ -271,19 +281,25 @@
<translation id="3884278016824448484">Identificativo del dispositivo in conflitto</translation>
<translation id="3885155851504623709">Parrocchia</translation>
<translation id="3901925938762663762">La carta è scaduta</translation>
+<translation id="3910267023907260648">Hai tentato di accedere a <ph name="DOMAIN" />, tuttavia il server ha presentato un certificato firmato utilizzando un algoritmo di firma debole. CiĂ² significa che le credenziali di sicurezza presentate dal server potrebbero essere state falsificate e il server potrebbe non essere quello previsto (è possibile che tu stia comunicando con un malintenzionato). <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere attivo da domani. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.}other{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere attivo tra # giorni. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Caricamento del documento PDF non riuscito</translation>
<translation id="3963721102035795474">ModalitĂ  Reader</translation>
+<translation id="397105322502079400">Calcolo in corso...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> è bloccato</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{Una pagina web nelle vicinanze}other{# pagine web nelle vicinanze}}</translation>
<translation id="4021036232240155012">DNS è il servizio di rete che traduce il nome di un sito web nel relativo indirizzo Internet.</translation>
<translation id="4030383055268325496">&amp;Annulla aggiunta</translation>
-<translation id="4032534284272647190">Accesso a <ph name="URL" /> negato.</translation>
<translation id="404928562651467259">AVVISO</translation>
<translation id="4058922952496707368">Chiave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Il client e il server non supportano un pacchetto di crittografia o una versione del protocollo SSL comuni.</translation>
<translation id="4079302484614802869">L'impostazione della configurazione proxy prevede l'utilizzo di un URL script .pac, non di server proxy fissi.</translation>
<translation id="4103249731201008433">Il numero di serie del dispositivo non è valido</translation>
<translation id="4103763322291513355">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; per visualizzare l'elenco di URL inseriti nella blacklist e altre norme applicate dall'amministratore di sistema.</translation>
+<translation id="4110615724604346410">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza contiene errori. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">L'ambito della norma non è supportato.</translation>
+<translation id="4118212371799607889">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile da Chromium. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 altro}other{# altri}}</translation>
<translation id="4130226655945681476">Controllare i cavi di rete, il modem e il router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Vuoi che Chromium salvi questa carta?</translation>
@@ -291,6 +307,7 @@
<translation id="4176463684765177261">Disabilitato</translation>
<translation id="4196861286325780578">&amp;Ripeti spostamento</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Controllare le configurazioni del firewall e antivirus<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{nessuna}=1{1 app ($ 1)}=2{2 app ($ 1, $ 2)}other{# app ($ 1, $ 2, $ 3)}}</translation>
<translation id="4220128509585149162">Arresti anomali</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Prova a eseguire lo strumento Diagnostica di rete<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">No</translation>
@@ -299,14 +316,15 @@
<translation id="4269787794583293679">(Nessun nome utente)</translation>
<translation id="4300246636397505754">Suggerimenti per i genitori</translation>
<translation id="4304224509867189079">Accedi</translation>
+<translation id="432290197980158659">Il server ha presentato un certificato che non corrisponde alle previsioni integrate. Queste previsioni sono incluse per determinati siti web con protezione elevata allo scopo di proteggerti. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Impossibile trovare l'articolo</translation>
+<translation id="4331708818696583467">Non sicuro</translation>
<translation id="4372948949327679948">Ăˆ previsto il valore <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">Hai tentato di accedere a <ph name="DOMAIN" /> ma il server ha presentato un certificato revocato dall'autoritĂ  di certificazione. CiĂ² significa che le credenziali di sicurezza presentate dal server non sono assolutamente attendibili. Potresti avere stabilito una comunicazione con un utente malintenzionato.</translation>
<translation id="4381091992796011497">Nome utente:</translation>
<translation id="4394049700291259645">Disabilita</translation>
<translation id="4395129973926795186">Da <ph name="START_DATE" /> a <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">risultati di ricerca</translation>
-<translation id="4424024547088906515">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile da Chrome. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> non ha accettato il certificato di accesso oppure non ne è stato fornito uno.</translation>
<translation id="443673843213245140">L'utilizzo di un proxy è stato disattivato ma è stata specificata una configurazione proxy esplicita.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Visualizzi questo messaggio perché è stato attivato Google SafeSites.</translation>
@@ -318,12 +336,12 @@
<translation id="4522570452068850558">Dettagli</translation>
<translation id="4558551763791394412">Prova a disattivare le estensioni.</translation>
<translation id="4587425331216688090">Rimuovere l'indirizzo da Chrome?</translation>
+<translation id="4589078953350245614">Hai tentato di accedere a <ph name="DOMAIN" />, tuttavia il server ha presentato un certificato non valido. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">La connessione a <ph name="DOMAIN" /> è crittografata tramite un pacchetto di crittografia moderno.</translation>
<translation id="4594403342090139922">&amp;Annulla eliminazione</translation>
+<translation id="4627442949885028695">Continua da un altro dispositivo</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Ăˆ visualizzata la pagina di un'estensione.</translation>
-<translation id="467662567472608290">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza contiene errori. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> è stato bloccato</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">La connessione è stata interrotta</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Eseguire lo strumento Diagnostica di rete Windows<ph name="END_LINK" /></translation>
@@ -331,21 +349,26 @@
<translation id="4728558894243024398">Piattaforma</translation>
<translation id="4744603770635761495">Percorso eseguibile</translation>
<translation id="4756388243121344051">&amp;Cronologia</translation>
+<translation id="4759238208242260848">Download</translation>
<translation id="4764776831041365478">La pagina web all'indirizzo <ph name="URL" /> potrebbe essere temporaneamente non disponibile oppure è stata permanentemente spostata a un nuovo indirizzo web.</translation>
<translation id="4771973620359291008">Si è verificato un errore sconosciuto.</translation>
<translation id="4782449893814226250">Hai chiesto ai tuoi genitori se puoi visitare questa pagina.</translation>
<translation id="4800132727771399293">Controlla la data di scadenza e il codice CVC, poi riprova</translation>
-<translation id="4807049035289105102">Al momento non puoi visitare il sito web <ph name="SITE" /> perchĂ© ha inviato strane credenziali che Google Chrome non riesce a elaborare. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare piĂ¹ tardi.</translation>
<translation id="4813512666221746211">Errore di rete</translation>
<translation id="4816492930507672669">Adatta alla pagina</translation>
<translation id="4850886885716139402">Visualizza</translation>
<translation id="4880827082731008257">Cerca nella cronologia</translation>
+<translation id="4884656795097055129">Verranno visualizzati altri articoli al momento giusto.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{e un'altra pagina web}other{e altre # pagine web}}</translation>
<translation id="4923417429809017348">Questa pagina è stata tradotta da una lingua sconosciuta in <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Deve essere specificato.</translation>
<translation id="4930497775425430760">Visualizzi questo messaggio perché il tuo genitore deve approvare i nuovi siti alla tua prima visita.</translation>
<translation id="495170559598752135">Azioni</translation>
<translation id="4958444002117714549">Espandi elenco</translation>
+<translation id="4962322354953122629">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile da Chrome. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Tradurre da <ph name="ORIGINAL_LANGUAGE" /> in <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Questo plug-in non è supportato</translation>
<translation id="5002932099480077015">Se questa opzione viene attivata, Chrome memorizza una copia della carta sul dispositivo per velocizzare la compilazione dei moduli.</translation>
<translation id="5019198164206649151">Archivio di backup in stato non valido</translation>
<translation id="5023310440958281426">Consulta le norme dell'amministratore</translation>
@@ -353,13 +376,12 @@
<translation id="5031870354684148875">Informazioni su Google Traduttore</translation>
<translation id="5040262127954254034">Privacy</translation>
<translation id="5045550434625856497">Password non corretta</translation>
+<translation id="5056549851600133418">Articoli per te</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Controllare l'indirizzo proxy<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Il certificato del server non è valido in questa fase.</translation>
<translation id="5089810972385038852">Provincia</translation>
-<translation id="5094747076828555589">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile da Chromium. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="5095208057601539847">Provincia</translation>
<translation id="5115563688576182185">(a 64 bit)</translation>
-<translation id="5122371513570456792"><ph name="SEARCH_RESULTS" /> per "<ph name="SEARCH_STRING" />": <ph name="NUMBER_OF_RESULTS" /></translation>
<translation id="5141240743006678641">Crittografa le password sincronizzate con le tue credenziali Google</translation>
<translation id="5145883236150621069">Codice di errore presente nella risposta del criterio</translation>
<translation id="5171045022955879922">Cerca o digita un URL</translation>
@@ -368,18 +390,18 @@
<translation id="5190835502935405962">Barra dei Preferiti</translation>
<translation id="5199729219167945352">Esperimenti</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">Utilizzi Chrome al lavoro? Le aziende possono gestire le impostazioni di Chrome per conto dei propri dipendenti. Ulteriori informazioni</translation>
<translation id="5299298092464848405">Errore durante l'analisi del criterio</translation>
<translation id="5300589172476337783">Mostra</translation>
<translation id="5308689395849655368">La segnalazione degli arresti anomali è disattivata.</translation>
<translation id="5317780077021120954">Salva</translation>
<translation id="5327248766486351172">Nome</translation>
+<translation id="5359637492792381994">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza al momento non è valido. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Archiviazione delle impostazioni criterio non riuscita</translation>
-<translation id="540969355065856584">Questo server non è riuscito a verificare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato valido in questa fase. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che ha intercettato la connessione.</translation>
<translation id="5421136146218899937">Cancella dati di navigazione...</translation>
<translation id="5430298929874300616">Rimuovi preferito</translation>
<translation id="5431657950005405462">Il file non è stato trovato</translation>
<translation id="5435775191620395718">Ăˆ visualizzata la cronologia di questo dispositivo. <ph name="BEGIN_LINK" />Ulteriori informazioni<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">Al momento i suggerimenti personalizzati sui contenuti sono disattivati poiché i tuoi dati sincronizzati sono protetti da una passphrase personalizzata.</translation>
<translation id="5439770059721715174">Errore di convalida dello schema in "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Impossibile trovare la pagina <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">Timestamp del criterio errato</translation>
@@ -402,14 +424,18 @@
<translation id="5622887735448669177">Vuoi uscire da questo sito?</translation>
<translation id="5629630648637658800">Caricamento delle impostazioni criterio non riuscito</translation>
<translation id="5631439013527180824">Token di gestione del dispositivo non valido</translation>
-<translation id="5650551054760837876">Nessun risultato di ricerca trovato.</translation>
<translation id="5677928146339483299">Bloccati</translation>
<translation id="5710435578057952990">L'identità di questo sito web non è stata verificata.</translation>
<translation id="5720705177508910913">Utente corrente</translation>
+<translation id="572328651809341494">Schede recenti</translation>
<translation id="5784606427469807560">Si è verificato un problema durante la conferma della carta. Controlla la connessione Internet e riprova.</translation>
<translation id="5785756445106461925">Inoltre, questa pagina include altre risorse che non sono sicure. Tali risorse possono essere visualizzate da altri durante il transito dei dati e possono essere modificate da un utente malintenzionato al fine di modificare l'aspetto della pagina.</translation>
+<translation id="5786044859038896871">Vuoi inserire automaticamente i dati della carta?</translation>
+<translation id="5803412860119678065">Vuoi inserire automaticamente <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">La connessione a <ph name="DOMAIN" /> è crittografata tramite un pacchetto di crittografia obsoleto.</translation>
<translation id="5813119285467412249">&amp;Ripeti aggiunta</translation>
+<translation id="5814352347845180253">Potresti perdere l'accesso ai contenuti premium del sito <ph name="SITE" /> e di altri siti.</translation>
+<translation id="5843436854350372569">Hai tentato di accedere a <ph name="DOMAIN" />, tuttavia il server ha presentato un certificato contenente una chiave debole. Un malintenzionato potrebbe avere decifrato la chiave privata e il server potrebbe non essere quello previsto (è possibile che tu stia comunicando con un malintenzionato). <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Visualizzi questo messaggio perché il gestore ha bloccato questo sito.</translation>
<translation id="5857090052475505287">Nuova cartella</translation>
<translation id="5869405914158311789">Impossibile raggiungere il sito</translation>
@@ -417,6 +443,7 @@
<translation id="5872918882028971132">Suggerimenti per i genitori</translation>
<translation id="59107663811261420">Questo tipo di carta non è supportato in Google Payments per questo commerciante. Seleziona un'altra carta.</translation>
<translation id="59174027418879706">Attiva</translation>
+<translation id="5926846154125914413">Potresti perdere l'accesso ai contenuti premium di alcuni siti.</translation>
<translation id="5966707198760109579">Settimana</translation>
<translation id="5967867314010545767">Rimuovi da cronologia</translation>
<translation id="5975083100439434680">Diminuisci lo zoom</translation>
@@ -428,11 +455,11 @@
<translation id="604124094241169006">Automatica</translation>
<translation id="6042308850641462728">PiĂ¹</translation>
<translation id="6060685159320643512">Attenzione, prova questi esperimenti a tuo rischio e pericolo</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{nessuna}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Controlla eventuali cavi e riavvia eventuali router, modem o altri dispositivi di rete in uso.</translation>
<translation id="614940544461990577">Prova a:</translation>
<translation id="6150607114729249911">Spiacenti. Devi chiedere ai tuoi genitori se puoi visitare la pagina.</translation>
<translation id="6151417162996330722">Il certificato del server ha un periodo di validitĂ  troppo lungo.</translation>
-<translation id="6154808779448689242">Il token del criterio restituito non corrisponde al token corrente</translation>
<translation id="6165508094623778733">Ulteriori informazioni</translation>
<translation id="6203231073485539293">Controlla la connessione a Internet</translation>
<translation id="6218753634732582820">Rimuovere l'indirizzo da Chromium?</translation>
@@ -445,24 +472,30 @@
<translation id="6328639280570009161">Prova a disattivare la previsione della rete</translation>
<translation id="6337534724793800597">Filtra i criteri per nome</translation>
<translation id="6342069812937806050">In questo momento</translation>
+<translation id="6345221851280129312">dimensioni sconosciute</translation>
<translation id="6355080345576803305">Sostituzione sessione pubblica</translation>
<translation id="6358450015545214790">Che cosa significano?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 altro suggerimento}other{# altri suggerimenti}}</translation>
<translation id="6387478394221739770">Ti interessano le nuove e straordinarie funzioni di Chrome? Prova il nostro canale beta all'indirizzo chrome.com/beta.</translation>
-<translation id="641480858134062906">Caricamento <ph name="URL" /> non riuscito</translation>
+<translation id="6389758589412724634">Chromium ha esaurito la memoria mentre cercava di visualizzare questa pagina web.</translation>
+<translation id="6416403317709441254">Al momento non puoi visitare il sito <ph name="SITE" /> perchĂ© ha inviato credenziali criptate che Chromium non è in grado di elaborare. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare piĂ¹ tardi. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Impossibile controllare se il certificato è stato revocato.</translation>
<translation id="6433595998831338502">Connessione negata da <ph name="HOST_NAME" />.</translation>
<translation id="6445051938772793705">Paese</translation>
<translation id="6451458296329894277">Conferma reinvio modulo</translation>
<translation id="6458467102616083041">Ignorato perché la ricerca predefinita è stata disattivata secondo la norma.</translation>
+<translation id="6462969404041126431">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere stato revocato. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Norme dispositivo</translation>
<translation id="6489534406876378309">Avvia caricamento arresti anomali</translation>
<translation id="6529602333819889595">&amp;Ripeti eliminazione</translation>
+<translation id="6534179046333460208">Suggerimenti relativi al Physical Web</translation>
<translation id="6550675742724504774">Opzioni</translation>
+<translation id="6593753688552673085">meno di <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opzioni di crittografia</translation>
<translation id="662080504995468778">Rimani</translation>
<translation id="6628463337424475685">Ricerca <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Al momento non puoi visitare il sito <ph name="SITE" /> perchĂ© <ph name="BEGIN_LINK" />questo certificato è stato revocato<ph name="END_LINK" />. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare piĂ¹ tardi.</translation>
<translation id="6644283850729428850">Questa norma è obsoleta.</translation>
+<translation id="6652240803263749613">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile dal sistema operativo del computer. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Modifica cartella</translation>
<translation id="6660210980321319655">Data/ora arresto anomalo: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Rimuovere il suggerimento per i moduli da Chromium?</translation>
@@ -470,6 +503,7 @@
<translation id="6710213216561001401">Indietro</translation>
<translation id="6710594484020273272">&lt;Digita un termine di ricerca&gt;</translation>
<translation id="6711464428925977395">Si è verificato un problema con il server proxy oppure l'indirizzo non è corretto.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{nessuno}=1{1 elemento}other{# elementi}}</translation>
<translation id="674375294223700098">Errore sconosciuto del certificato del server.</translation>
<translation id="6753269504797312559">Valore norma</translation>
<translation id="6757797048963528358">Il dispositivo è entrato in modalità sospensione.</translation>
@@ -481,7 +515,6 @@
<translation id="6891596781022320156">Il livello della norma non è supportato.</translation>
<translation id="6895330447102777224">La carta è stata confermata</translation>
<translation id="6897140037006041989">User-agent</translation>
-<translation id="6903907808598579934">Attiva la sincronizzazione</translation>
<translation id="6915804003454593391">Utente:</translation>
<translation id="6957887021205513506">Il certificato del server risulta essere un falso.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -489,9 +522,11 @@
<translation id="6970216967273061347">Distretto</translation>
<translation id="6973656660372572881">Sono stati specificati sia i server proxy fissi che un URL script .pac.</translation>
<translation id="6989763994942163495">Mostra impostazioni avanzate...</translation>
+<translation id="7000990526846637657">Nessuna voce della cronologia trovata</translation>
+<translation id="7009986207543992532">Hai tentato di accedere a <ph name="DOMAIN" />, tuttavia il server ha presentato un certificato il cui periodo di validità è troppo lungo per essere considerato attendibile. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Il tuo account Google potrebbe avere altre forme di cronologia di navigazione all'indirizzo <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Password</translation>
-<translation id="7050187094878475250">Hai tentato di visitare il sito <ph name="DOMAIN" />, ma il server ha presentato un certificato con periodo di validitĂ  troppo lungo per poter essere ritenuto attendibile.</translation>
<translation id="7087282848513945231">Contea</translation>
<translation id="7088615885725309056">Meno recente</translation>
<translation id="7090678807593890770">Cerca <ph name="LINK" /> con Google</translation>
@@ -510,13 +545,13 @@
<translation id="7246609911581847514">Visualizzi questo messaggio perché il gestore deve approvare i nuovi siti alla tua prima visita.</translation>
<translation id="724975217298816891">Inserisci la data di scadenza e il codice CVC della carta <ph name="CREDIT_CARD" /> per aggiornare i relativi dettagli. Dopo essere stati confermati, i dettagli della carta saranno condivisi con questo sito.</translation>
<translation id="725866823122871198">Impossibile stabilire una connessione privata con il sito <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> perché data e ora del computer (<ph name="DATE_AND_TIME" />) sono sbagliate.</translation>
-<translation id="7265986070661382626">Al momento non puoi visitare il sito web <ph name="SITE" /> perchĂ© <ph name="BEGIN_LINK" />utilizza il blocco dei certificati<ph name="END_LINK" />. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare piĂ¹ tardi.</translation>
<translation id="7269802741830436641">La pagina web ha generato un loop di reindirizzamento</translation>
<translation id="7275334191706090484">Preferiti gestiti</translation>
<translation id="7298195798382681320">Consigliate</translation>
-<translation id="7301833672208172928">Attiva sincronizzazione della cronologia</translation>
+<translation id="7309308571273880165">Rapporto sugli arresti anomali generato <ph name="CRASH_TIME" /> (caricamento richiesto dall'utente, ma non ancora eseguito)</translation>
<translation id="7334320624316649418">&amp;Ripeti ridisposizione</translation>
<translation id="733923710415886693">Il certificato del server non è stato reso pubblico tramite Certificate Transparency.</translation>
+<translation id="7351800657706554155">Al momento non puoi visitare il sito <ph name="SITE" /> perchĂ© il relativo certificato è stato revocato. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe riprendere a funzionare piĂ¹ tardi. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Riga di comando</translation>
<translation id="7372973238305370288">risultato della ricerca</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -535,16 +570,17 @@ Psst! La prossima volta potrebbe esserti utile la modalitĂ  di navigazione in in
<translation id="7469372306589899959">Conferma della carta…</translation>
<translation id="7481312909269577407">Avanti</translation>
<translation id="7485870689360869515">Nessun dato trovato.</translation>
+<translation id="7508255263130623398">L'ID dispositivo della norma restituito è vuoto o non corrisponde all'ID dispositivo corrente</translation>
<translation id="7514365320538308">Scarica</translation>
<translation id="7518003948725431193">Nessuna pagina web trovata per l'indirizzo web: <ph name="URL" /></translation>
<translation id="7537536606612762813">Obbligatoria</translation>
<translation id="7542995811387359312">La compilazione automatica della carta di credito è disattivata perché questo modulo non utilizza una connessione sicura.</translation>
<translation id="7549584377607005141">Questa pagina web richiede dati che hai inserito in precedenza per poter essere visualizzata correttamente. Puoi inviare di nuovo i dati, ma in questo caso ripeterai l'azione precedentemente eseguita nella pagina.</translation>
<translation id="7554791636758816595">Nuova scheda</translation>
-<translation id="7567204685887185387">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere stato emesso in modo fraudolento. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="7568593326407688803">Questa pagina è in<ph name="ORIGINAL_LANGUAGE" />Vuoi tradurla?</translation>
<translation id="7569952961197462199">Rimuovere la carta di credito da Chrome?</translation>
<translation id="7578104083680115302">Paga velocemente su siti e app su piĂ¹ dispositivi utilizzando le carte salvate su Google.</translation>
+<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Il certificato del server vìola i vincoli relativi ai nomi.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> al momento non è in grado di gestire la richiesta.</translation>
<translation id="7600965453749440009">Non tradurre mai <ph name="LANGUAGE" /></translation>
@@ -555,6 +591,7 @@ Psst! La prossima volta potrebbe esserti utile la modalitĂ  di navigazione in in
<translation id="7637571805876720304">Rimuovere la carta di credito da Chromium?</translation>
<translation id="765676359832457558">Nascondi impostazioni avanzate...</translation>
<translation id="7658239707568436148">Annulla</translation>
+<translation id="7667346355482952095">Il token della norma restituito è vuoto o non corrisponde al token corrente</translation>
<translation id="7668654391829183341">Dispositivo sconosciuto</translation>
<translation id="7674629440242451245">Ti interessano le nuove e straordinarie funzioni di Chrome? Prova il nostro canale Dev all'indirizzo chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Procedi su <ph name="SITE" /> (non sicuro)<ph name="END_LINK" /></translation>
@@ -571,10 +608,10 @@ Psst! La prossima volta potrebbe esserti utile la modalitĂ  di navigazione in in
<translation id="780301667611848630">No grazie</translation>
<translation id="7805768142964895445">Stato</translation>
<translation id="7813600968533626083">Rimuovere il suggerimento per i moduli da Chrome?</translation>
+<translation id="7815407501681723534"><ph name="SEARCH_RESULTS" /> per "<ph name="SEARCH_STRING" />": <ph name="NUMBER_OF_RESULTS" /></translation>
<translation id="785549533363645510">Non sei completamente invisibile: se navighi in incognito, la tua navigazione non viene nascosta al tuo datore di lavoro, al provider di servizi Internet o ai siti web che visiti.</translation>
<translation id="7887683347370398519">Controlla il tuo codice CVC e riprova</translation>
<translation id="7894616681410591072">Spiacenti. Per accedere a questa pagina devi avere l'autorizzazione di <ph name="NAME" />.</translation>
-<translation id="790025292736025802"><ph name="URL" /> non trovato</translation>
<translation id="7912024687060120840">Nella cartella:</translation>
<translation id="7920092496846849526">Hai chiesto ai tuoi genitori l'autorizzazione per visitare questa pagina.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -587,9 +624,10 @@ Psst! La prossima volta potrebbe esserti utile la modalitĂ  di navigazione in in
<translation id="7995512525968007366">Non specificato</translation>
<translation id="8012647001091218357">In questo momento, non è possibile raggiungere i tuoi genitori. Riprova.</translation>
<translation id="8034522405403831421">Questa pagina è in <ph name="SOURCE_LANGUAGE" />. Tradurla in <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Nessuna voce della cronologia trovata.</translation>
<translation id="8088680233425245692">Impossibile visualizzare l'articolo.</translation>
+<translation id="8089520772729574115">meno di 1 MB</translation>
<translation id="8091372947890762290">Attivazione in attesa sul server</translation>
+<translation id="8129262335948759431">importo sconosciuto</translation>
<translation id="8131740175452115882">Conferma</translation>
<translation id="8134994873729925007">Impossibile trovare l'<ph name="BEGIN_ABBR" />indirizzo DNS<ph name="END_ABBR" /> del server <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Il computer è entrato in modalità sospensione.</translation>
@@ -598,6 +636,7 @@ Psst! La prossima volta potrebbe esserti utile la modalitĂ  di navigazione in in
<translation id="8201077131113104583">URL di aggiornamento non valido per l'estensione con ID "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Posizione assegnata:</translation>
<translation id="8225771182978767009">La persona che ha configurato il computer ha deciso di bloccare questo sito.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">La pagina a cui stai tentando di accedere utilizzava informazioni inserite da te. Tornando a quella pagina, è possibile che eventuali azioni che hai eseguito vengano ripetute. Continuare?</translation>
<translation id="8249320324621329438">Ultimo recupero:</translation>
<translation id="8261506727792406068">Elimina</translation>
@@ -610,12 +649,17 @@ Psst! La prossima volta potrebbe esserti utile la modalitĂ  di navigazione in in
<translation id="8349305172487531364">Barra dei Preferiti</translation>
<translation id="8363502534493474904">Disattivare la modalitĂ  aereo</translation>
<translation id="8364627913115013041">Non impostata.</translation>
+<translation id="8380941800586852976">Pericolosa</translation>
<translation id="8412145213513410671">Arresti anomali (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Devi inserire la stessa passphrase due volte.</translation>
<translation id="8428213095426709021">Impostazioni</translation>
+<translation id="8433057134996913067">In questo modo uscirai dalla maggior parte dei siti web.</translation>
<translation id="8437238597147034694">&amp;Annulla spostamento</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 carta di credito}other{# carte di credito}}</translation>
+<translation id="8483780878231876732">Accedi a Chrome per usare le carte memorizzate nel tuo account Google</translation>
<translation id="8488350697529856933">Si applica a</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ha impiegato troppo tempo a rispondere.</translation>
+<translation id="852346902619691059">Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile dal sistema operativo del dispositivo. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Questo tipo di carta non è supportato in Google Payments. Seleziona un'altra carta.</translation>
<translation id="8550022383519221471">Il servizio di sincronizzazione non è disponibile per il tuo dominio.</translation>
<translation id="8553075262323480129">La traduzione non è riuscita perché non è stato possibile determinare la lingua della pagina.</translation>
@@ -627,18 +671,15 @@ Psst! La prossima volta potrebbe esserti utile la modalitĂ  di navigazione in in
<translation id="8647750283161643317">Ripristina i valori predefiniti per tutto</translation>
<translation id="8680787084697685621">I dati di accesso dell'account sono obsoleti.</translation>
<translation id="8703575177326907206">La connessione a <ph name="DOMAIN" /> non è crittografata.</translation>
-<translation id="8713130696108419660">Firma iniziale non valida</translation>
<translation id="8725066075913043281">Riprova</translation>
<translation id="8728672262656704056">Sei passato alla navigazione in incognito</translation>
<translation id="8730621377337864115">Fine</translation>
<translation id="8738058698779197622">Per poter stabilire una connessione protetta, l'orologio deve essere impostato correttamente perchĂ© i certificati utilizzati dai siti web per identificarsi sono validi soltanto per determinati periodi di tempo. L'orologio del dispositivo è sbagliato, pertanto Chromium non puĂ² verificare i certificati.</translation>
<translation id="8740359287975076522">Impossibile trovare l'&lt;abbr id="dnsDefinition"&gt;indirizzo DNS&lt;/abbr&gt; di <ph name="HOST_NAME" />. Stiamo analizzando il problema.</translation>
-<translation id="8741995161408053644">Il tuo account Google potrebbe avere altre forme di cronologia di navigazione all'indirizzo <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Ripeti eliminazione</translation>
-<translation id="8790687370365610530">Per ricevere contenuti suggeriti appositamente per te da Google, attiva la sicronizzazione della cronologia.</translation>
<translation id="8798099450830957504">Predefinito</translation>
<translation id="8804164990146287819">Norme sulla privacy</translation>
-<translation id="8820817407110198400">Segnalibri</translation>
+<translation id="8820817407110198400">Preferiti</translation>
<translation id="8834246243508017242">Attiva Compilazione automatica utilizzando Contatti…</translation>
<translation id="883848425547221593">Altri Preferiti</translation>
<translation id="884923133447025588">Nessun sistema di revoca trovato.</translation>
@@ -657,13 +698,11 @@ Psst! La prossima volta potrebbe esserti utile la modalitĂ  di navigazione in in
<translation id="8971063699422889582">Il certificato del server è scaduto.</translation>
<translation id="8987927404178983737">Mese</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Il server ha presentato un certificato che non è stato reso pubblico tramite le norme di Certificate Transparency, la cui applicazione costituisce un requisito di alcuni certificati al fine di garantire la loro attendibilità nonché la sicurezza nei confronti dei malintenzionati.</translation>
<translation id="9001074447101275817">Il proxy <ph name="DOMAIN" /> richiede un nome utente e una password.</translation>
<translation id="901974403500617787">I contrassegni che si applicano a livello di sistema possono essere impostati solo dal proprietario: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Questa pagina è stata tradotta in <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Utilizza un servizio di previsione per velocizzare il caricamento delle pagine</translation>
<translation id="9039213469156557790">Inoltre, questa pagina include altre risorse che non sono sicure. Tali risorse possono essere visualizzate da altri durante il transito dei dati e possono essere modificate da un utente malintenzionato al fine di modificare il comportamento della pagina.</translation>
-<translation id="9049981332609050619">Hai tentato di connetterti a <ph name="DOMAIN" />, ma il server ha presentato un certificato scaduto.</translation>
<translation id="9050666287014529139">Passphrase</translation>
<translation id="9065203028668620118">Modifica</translation>
<translation id="9092364396508701805">La pagina <ph name="HOST_NAME" /> non funziona</translation>
diff --git a/chromium/components/strings/components_strings_iw.xtb b/chromium/components/strings/components_strings_iw.xtb
index 24879d8e1f5..6fe5c9c4325 100644
--- a/chromium/components/strings/components_strings_iw.xtb
+++ b/chromium/components/strings/components_strings_iw.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="iw">
+<translation id="1008557486741366299">×œ× ×¢×›×©×™×•</translation>
<translation id="1015730422737071372">ספק ×¤×¨×˜×™× × ×•×¡×¤×™×</translation>
<translation id="1032854598605920125">סובב בכיוון השעון</translation>
<translation id="1038842779957582377">×©× ×œ× ×™×“×•×¢</translation>
+<translation id="1053591932240354961">â€×œ× ניתן לבקר עכשיו ב×תר <ph name="SITE" /> ×כיוון ×©×”×•× ×©×œ×— ××™×©×•×¨×™× ×œ× ×ª×§×™× ×™× ×©-Google Chrome ×ינו יכול לעבד. שגי×ות רשת ותקיפות × ×שכות ×‘×“×¨× ×›×œ×œ ×–×ן ×וגבל, ולכן סביר להניח שדף ×–×” יחזור לפעול ××וחר יותר. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;ביטול הוספה</translation>
<translation id="10614374240317010">×¤×¨×™×˜×™× ×©××£ ×¤×¢× ×œ× × ×©×רו</translation>
-<translation id="1064422015032085147">ייתכן שיש עו×ס יתר בשרת שבו דף ×”×ינטרנט ×ת×רח ×ו ש×בוצעות בו עבודות תחזוקה.
- כדי ל×נוע עו×ס תנועה רב ×די שעלול להח×יר ×ת ×”×צב,
- שליחת בקשות ×ל כתובת ×”×תר הזו × ×סרה ב×ופן ×–×× ×™.</translation>
<translation id="106701514854093668">סי×ניות שולחן עבודה</translation>
<translation id="1080116354587839789">הת×× ×œ×¨×•×—×‘</translation>
+<translation id="1103124106085518534">סיי×ת</translation>
<translation id="1103523840287552314">×ª×¨×’× <ph name="LANGUAGE" /> ת×יד</translation>
<translation id="1107591249535594099">â€×× ×”×פשרות הזו ×סו×נת, Chrome יש×ור עותק של הכרטיס ב×כשיר ×”×–×” כדי ל××œ× ×˜×¤×¡×™× ×‘×הירות רבה יותר.</translation>
+<translation id="1111153019813902504">סי×ניות ×חרונות</translation>
<translation id="1113869188872983271">&amp;ביטול של שינוי סדר</translation>
+<translation id="1126551341858583091">גודל ×”×חסון ×”×קו××™ ×”×•× <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">הקובץ הש×ור של ×”×דיניות תקין</translation>
<translation id="113188000913989374"><ph name="SITE" /> ×ו×ר:</translation>
<translation id="1132774398110320017">â€×”גדרות ×ילוי ×וטו×טי של Chrome...</translation>
-<translation id="1150979032973867961">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />. ×ישור ×”×בטחה שלו ×œ× × ×—×©×‘ ×›××”×™×ן על ידי ×ערכת ההפעלה של ×”×חשב. ייתכן שהסיבה ×œ×›× ×”×™× ×ª×¦×•×¨×” שגויה ×ו תוקף ×”×יירט ×ת החיבור של×.</translation>
<translation id="1152921474424827756">גש ×ל <ph name="BEGIN_LINK" />עותק בקובץ ש×ור<ph name="END_LINK" /> של <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> סגר ×ת החיבור ב×ופן בלתי צפוי.</translation>
<translation id="1161325031994447685">â€×œ×”תחבר ×חדש ×ל ×”-Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">הסר</translation>
<translation id="1201402288615127009">הב×</translation>
<translation id="1201895884277373915">עוד ××תר ×–×”</translation>
-<translation id="121201262018556460">ניסית להגיע ×ל <ph name="DOMAIN" />, ×× ×”×©×¨×ª הציג ×ישור ×”×כיל ×פתח חלש. ייתכן שתוקף פרץ ×ת ×”×פתח הפרטי, והשרת ×ינו השרת שרצית (ייתכן ש×תה ×תקשר ×¢× ×ª×•×§×£).</translation>
+<translation id="1206967143813997005">חתי××” ר×שונית ×œ× ×—×•×§×™×ª</translation>
+<translation id="1209206284964581585">הסתר בינתיי×</translation>
<translation id="1219129156119358924">×בטחת ×ערכת</translation>
<translation id="1227224963052638717">×דיניות ×œ× ×™×“×•×¢×”.</translation>
<translation id="1227633850867390598">הסתר ער×</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">כן</translation>
<translation id="1430915738399379752">הדפס</translation>
<translation id="1442912890475371290">× ×—×¡× × ×™×¡×™×•×Ÿ <ph name="BEGIN_LINK" /> לביקור בדף ב-<ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">×œ× × ×™×ª×Ÿ לבקר עכשיו ב×תר <ph name="SITE" /> ×כיוון ×©×”×•× ×שת×ש בהצ×דת ×ישורי×. שגי×ות רשת ותקיפות ×תרחשות ×‘×“×¨× ×›×œ×œ לז×ן ×וגבל, ולכן סביר להניח שדף ×–×” יחזור לפעול ××וחר יותר. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">הצג עותק ש×ור (כלו×ר, ידוע ×©×”×•× ×¢×“×›× ×™) של הדף ×”×–×”.</translation>
<translation id="1519264250979466059">â€×ª××¨×™× ×”-Build</translation>
<translation id="1549470594296187301">â€JavaScript ×¦×¨×™× ×œ×”×™×•×ª ×ופעל כדי להשת×ש בתכונה זו.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">תצורת הרשת ××™× ×” חוקית ×•×œ× × ×™×ª×Ÿ ×œ×™×™×‘× ×ותה.</translation>
<translation id="1644574205037202324">היסטוריה</translation>
<translation id="1645368109819982629">פרוטוקול ×œ× × ×ª××</translation>
-<translation id="1655462015569774233">{1,plural, =1{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; התוקף של ×ישור ×”×בטחה שלו פג ×ת×ול. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. הת××¨×™× ×”×וגדר כעת בשעון ×”×חשב ×©×œ× ×”×•× <ph name="CURRENT_DATE" />. ×”×× ×–×” נכון? ×× ×œ×, ×¢×œ×™× ×œ×›×•×•×Ÿ ×ת שעון ×”×ערכת ול×חר ×כן לרענן ×ת הדף ×”×–×”.}two{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; התוקף של ×ישור ×”×בטחה שלו פג לפני יו××™×™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. הת××¨×™× ×”×וגדר כעת בשעון ×”×חשב ×©×œ× ×”×•× <ph name="CURRENT_DATE" />. ×”×× ×–×” נכון? ×× ×œ×, ×¢×œ×™× ×œ×›×•×•×Ÿ ×ת שעון ×”×ערכת ול×חר ×כן לרענן ×ת הדף ×”×–×”.}many{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; התוקף של ×ישור ×”×בטחה שלו פג לפני # ×™××™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. הת××¨×™× ×”×וגדר כעת בשעון ×”×חשב ×©×œ× ×”×•× <ph name="CURRENT_DATE" />. ×”×× ×–×” נכון? ×× ×œ×, ×¢×œ×™× ×œ×›×•×•×Ÿ ×ת שעון ×”×ערכת ול×חר ×כן לרענן ×ת הדף ×”×–×”.}other{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; התוקף של ×ישור ×”×בטחה שלו פג לפני # ×™××™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. הת××¨×™× ×”×וגדר כעת בשעון ×”×חשב ×©×œ× ×”×•× <ph name="CURRENT_DATE" />. ×”×× ×–×” נכון? ×× ×œ×, ×¢×œ×™× ×œ×›×•×•×Ÿ ×ת שעון ×”×ערכת ול×חר ×כן לרענן ×ת הדף ×”×–×”.}}</translation>
<translation id="1676269943528358898">â€×”×תר <ph name="SITE" /> ×שת×ש ×‘×“×¨× ×›×œ×œ בהצפנה כדי להגן על ×”×ידע של×. ×›×שר Google Chrome ניסה ×”×¤×¢× ×œ×”×ª×—×‘×¨ ל-<ph name="SITE" />, ×”×תר שלח חזרה ××™×©×•×¨×™× ×—×¨×™×’×™× ×•×©×’×•×™×™×. ייתכן שתוקף ×נסה להתחזות ל×תר <ph name="SITE" />, ×ו ש××¡× ×›× ×™×¡×” ל-Wi-Fi הפריע לחיבור. ×”×ידע ×©×œ× ×¢×“×™×™×Ÿ ××ובטח ×כיוון ש-Google Chrome הפסיק ×ת החיבור לפני חילופי הנתוני×.</translation>
<translation id="168841957122794586">×ישור השרת ×כיל ×פתח הצפנה חלש.</translation>
<translation id="1701955595840307032">קבל הצעות לתוכן</translation>
-<translation id="1706954506755087368">{1,plural, =1{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ××ור להיכנס לתוקף רק ×חר. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×.}two{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ××ור להיכנס לתוקף רק בעוד יו××™×™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×.}many{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ××ור להיכנס לתוקף רק בעוד # ×™××™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×.}other{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ××ור להיכנס לתוקף רק בעוד # ×™××™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×.}}</translation>
<translation id="1710259589646384581">×ערכת הפעלה</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">נסה לפנות ×ל ×נהל ×”×ערכת.</translation>
<translation id="17513872634828108">כרטיסיות פתוחות</translation>
<translation id="1753706481035618306">×ספר דף</translation>
-<translation id="1761412452051366565">â€×›×“×™ לקבל ×-Google הצעות לתוכן ×ות×× ×ישית, הפעל ×ת הסינכרון.</translation>
-<translation id="1763864636252898013">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />. ×ישור ×”×בטחה שלו ×œ× × ×—×©×‘ ×›××”×™×ן על ידי ×ערכת ההפעלה של ×”×כשיר. ייתכן שהסיבה ×œ×›× ×”×™× ×ª×¦×•×¨×” שגויה ×ו תוקף ×”×יירט ×ת החיבור של×.</translation>
<translation id="1768211456781949159">â€<ph name="BEGIN_LINK" />נסה להפעיל ×ת ×בחון הרשת של Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">עדכן ×ת ×שפט-הסיס××” של הסינכרון.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">הסי×ניות ש×ליהן נכנסת ל×חרונה יופיעו ×›×ן.</translation>
<translation id="1821930232296380041">הבקשה ×ו הפר××˜×¨×™× ×©×œ הבקשה ××™× × ×—×•×§×™×™×</translation>
<translation id="1838667051080421715">×תה ×ציג ×ת ×”×קור של דף ×ינטרנט.</translation>
<translation id="1871208020102129563">â€×©×¨×ª ×”-Proxy ×וגדר להשת×ש בשרתי Proxy קבועי×, ×œ× ×‘×›×ª×•×‘×ª ×תר של סקריפט â€.Pac</translation>
<translation id="1883255238294161206">כווץ רשי××”</translation>
<translation id="1898423065542865115">סינון</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> ×œ× ×ישר ×ת ×ישור ההתחברות של×, ×ו שפג תוקפו של ×ישור ההתחברות.</translation>
<translation id="194030505837763158">עבור ל-<ph name="LINK" /></translation>
<translation id="1962204205936693436">סי×ניות של <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">שגי××” בעריכה בסידרה</translation>
<translation id="1974060860693918893">×תקד×</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{ו×פליקציה ×חת נוספת}two{ושתי ×פליקציות נוספות}many{ו-# ×פליקציות נוספות}other{ו-# ×פליקציות נוספות}}</translation>
<translation id="2025186561304664664">â€×©×¨×ª Proxy נקבע ל×וגדר ×וטו×טית.</translation>
<translation id="2030481566774242610">×”×× ×”×ª×›×•×•× ×ª ל-<ph name="LINK" />?</translation>
<translation id="2031925387125903299">×תה רו××” ×ת ההודעה הזו ×פני ×©×”×”×•×¨×™× ×©×œ× ×¦×¨×™×›×™× ×œ×שר ××ª×¨×™× ×—×“×©×™× ×‘×‘×™×§×•×¨ הר×שון של×.</translation>
<translation id="2032962459168915086">â€<ph name="BEGIN_LINK" />לבדוק ×ת שרת ×”-Proxy ו×ת חו×ת ×”×ש<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">×ספר / ×יקוד</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{הצעה ×חת}two{שתי הצעות}many{# הצעות}other{# הצעות}}</translation>
<translation id="2065985942032347596">נדרש ××™×ות</translation>
<translation id="2079545284768500474">בטל</translation>
<translation id="20817612488360358">â€× ×§×‘×¢ שי×וש בהגדרות שרת Proxy של ×ערכת ×× ×‘× ×•×¡×£ ×צוינת ×’× ×ª×¦×•×¨×” ×פורשת של שרת Proxy.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">×¢×¨×•× ×¡×™×ניות</translation>
<translation id="2166049586286450108">גישה ×ל××” של ×נהל ×”×ערכת</translation>
<translation id="2166378884831602661">×תר ×–×” ×œ× ×™×›×•×œ לספק חיבור ××ובטח</translation>
-<translation id="2171101176734966184">ניסית להגיע ×ל <ph name="DOMAIN" /> ×× ×”×©×¨×ª הציג ×ישור ×©× ×—×ª× ×‘××צעות ××œ×’×•×¨×™×ª× ×—×ª×™××” חלש. כלו×ר, ייתכן שהרש×ות ×”×בטחה שהשרת הציג זויפו, וכן ייתכן שהשרת ×ינו השרת שרצית (ייתכן ש×תה ×תקשר ×¢× ×ª×•×§×£).</translation>
<translation id="2181821976797666341">×דיניות</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{כתובת ×חת}two{שתי כתובות}many{# כתובות}other{# כתובות}}</translation>
<translation id="2212735316055980242">×œ× × ×צ××” ×דיניות</translation>
<translation id="2213606439339815911">××חזר רשו×ות...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> ×ינו ×–×ין</translation>
<translation id="2230458221926704099">תקן ×ת החיבור ב××צעות <ph name="BEGIN_LINK" />×פליקציית הבדיקה<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">שלח עכשיו</translation>
<translation id="225207911366869382">×¢×¨× ×–×” ×”×•×¦× ×שי×וש עבור ×דיניות זו.</translation>
<translation id="2262243747453050782">â€×©×’×™×ת HTTP</translation>
<translation id="2282872951544483773">× ×™×¡×•×™×™× ×œ× ×–××™× ×™×</translation>
<translation id="2292556288342944218">הגישה ל×ינטרנט חסו××”</translation>
<translation id="229702904922032456">פג תוקפו של ×ישור שורש ×ו ×ישור ביניי×.</translation>
<translation id="230155334948463882">כרטיס חדש?</translation>
+<translation id="2305919008529760154">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ייתכן ש×ישור ×”×בטחה שלו ×זויף. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> דורש ×©× ×שת×ש וסיס××”.</translation>
+<translation id="2318774815570432836">â€×œ× ניתן לבקר עכשיו ב×תר <ph name="SITE" /> ×כיוון ×©×”×•× ×שת×ש ב-HSTSâ€. שגי×ות רשת ותקיפות ×תרחשות ×‘×“×¨× ×›×œ×œ לז×ן ×וגבל, ולכן סביר להניח שדף ×–×” יחזור לפעול ××וחר יותר. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">×”×ערכת התעל××” ×סי×× ×™×” ×œ× ×—×•×§×™×ª ב×ינדקס <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">סי×ניות ×חרות</translation>
<translation id="2359808026110333948">×”×ש×</translation>
<translation id="2365563543831475020">דוח הקריסה שתועד ב-<ph name="CRASH_TIME" /> ×œ× ×”×•×¢×œ×”</translation>
<translation id="2367567093518048410">ר××”</translation>
+<translation id="2371153335857947666">{1,plural, =1{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; התוקף של ×ישור ×”×בטחה שלו פג ×ת×ול. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. הת××¨×™× ×”×וגדר עכשיו בשעון ×”×חשב ×©×œ× ×”×•× <ph name="CURRENT_DATE" />. ×”×× ×–×” נכון? ×× ×œ×, ×¢×œ×™× ×œ×›×•×•×Ÿ ×ת שעון ×”×ערכת ול×חר ×כן לרענן ×ת הדף ×”×–×”. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.}two{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; התוקף של ×ישור ×”×בטחה שלו פג לפני יו××™×™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. הת××¨×™× ×”×וגדר עכשיו בשעון ×”×חשב ×©×œ× ×”×•× <ph name="CURRENT_DATE" />. ×”×× ×–×” נכון? ×× ×œ×, ×¢×œ×™× ×œ×›×•×•×Ÿ ×ת שעון ×”×ערכת ול×חר ×כן לרענן ×ת הדף ×”×–×”. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.}many{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; התוקף של ×ישור ×”×בטחה שלו פג לפני # ×™××™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. הת××¨×™× ×”×וגדר עכשיו בשעון ×”×חשב ×©×œ× ×”×•× <ph name="CURRENT_DATE" />. ×”×× ×–×” נכון? ×× ×œ×, ×¢×œ×™× ×œ×›×•×•×Ÿ ×ת שעון ×”×ערכת ול×חר ×כן לרענן ×ת הדף ×”×–×”. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.}other{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; התוקף של ×ישור ×”×בטחה שלו פג לפני # ×™××™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. הת××¨×™× ×”×וגדר עכשיו בשעון ×”×חשב ×©×œ× ×”×•× <ph name="CURRENT_DATE" />. ×”×× ×–×” נכון? ×× ×œ×, ×¢×œ×™× ×œ×›×•×•×Ÿ ×ת שעון ×”×ערכת ול×חר ×כן לרענן ×ת הדף ×”×–×”. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">×ין חלופות ×–×ינות עבור ××שק ×”×שת×ש</translation>
<translation id="2384307209577226199">ברירת ×חדל של ×רגון</translation>
-<translation id="238526402387145295">â€×œ× ניתן לבקר כעת ב×תר <ph name="SITE" /> ×כיוון שה×תר <ph name="BEGIN_LINK" />×שת×ש ב-HSTSâ€<ph name="END_LINK" />â€. שגי×ות רשת ותקיפות ×תרחשות ×‘×“×¨× ×›×œ×œ לז×ן ×וגבל, ולכן סביר להניח שדף ×–×” יפעל ××וחר יותר.</translation>
<translation id="2386255080630008482">×ישור השרת נשלל.</translation>
<translation id="2392959068659972793">הצגת ×דיניות ×œ×œ× ×¢×¨× ×וגדר</translation>
<translation id="2396249848217231973">&amp;ביטול ×חיקה</translation>
-<translation id="2413528052993050574">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />. ייתכן ש×ישור ×”×בטחה שלו בוטל. הסיבה ×œ×›× ×¢×©×•×™×” להיות הגדרה שגויה ×ו תוקף ×”×יירט ×ת החיבור של×.</translation>
<translation id="2455981314101692989">דף ×ינטרנט ×–×” השבית ×ילוי ×וטו×טי של טופס ×–×”.</translation>
+<translation id="2463739503403862330">×ל×</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />×פעיל ×ת ×בחון הרשת<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">כתובת ×תר ×œ× ×—×•×§×™×ª של חיפוש</translation>
<translation id="2491120439723279231">×ישור השרת ×כיל שגי×ות.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">שלח</translation>
<translation id="2674170444375937751">×”×× ×תה בטוח ×©×‘×¨×¦×•× × ×œ×”×¡×™×¨ ×“×¤×™× ×לו ×ההיסטוריה של×?</translation>
<translation id="2677748264148917807">צ×</translation>
+<translation id="269990154133806163">השרת הציג ×ישור ×©×œ× × ×—×©×£ ב×ופן ציבורי על פי ×דיניות שקיפות ×”×ישורי×. החשיפה הזו ×”×™× ×“×¨×™×©×ª חובה בחלק ××”×ישורי×, כדי להבטיח ×©×”× ××”×™×× ×™× ×•×›×“×™ להגן ×פני תוקפי×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">×”×¢×¨× ×œ× ×ª×•×× ×œ×¤×•×¨×ט.</translation>
<translation id="2704951214193499422">â€×œ-Chromium ×ין כרגע ×פשרות ל×שר ×ת הכרטיס. נסה שוב ××וחר יותר.</translation>
<translation id="2705137772291741111">העותק הש×ור (בקובץ הש×ור) של ×”×תר ×”×–×” ×”×™×” בלתי קרי×.</translation>
<translation id="2709516037105925701">×ילוי ×וטו×טי</translation>
+<translation id="2712118517637785082">ניסית להגיע ×ל <ph name="DOMAIN" />, ×× ×”×ישור שהשרת הציג בוטל על-ידי ×”×נפיק שלו. פירוש הדבר ×”×•× ×©×ין לתת ××ון ב×ישורי ×”×בטחה שהשרת הציג. ייתכן ש×תה ×תקשר ×¢× ×ª×•×§×£. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">בקש רשות</translation>
<translation id="2721148159707890343">הבקשה בוצעה בהצלחה</translation>
<translation id="2728127805433021124">×”×ישור של השרת × ×—×ª× ×‘××צעות ××œ×’×•×¨×™×ª× ×©×œ חתי××” חלשה.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">סרגל חיפוש וכתובות</translation>
<translation id="2826760142808435982">החיבור ×וצפן ו××ו×ת ב××צעות <ph name="CIPHER" /> ו×שת×ש ב-<ph name="KX" /> ×›×נגנון להחלפת ×פתחות.</translation>
<translation id="2835170189407361413">נקה טופס</translation>
-<translation id="2837049386027881519">â€×”×™×” ×¦×•×¨× ×œ× ×¡×•×ª שוב ×ת החיבור ב××צעות גרסה ישנה יותר של פרוטוקול TLS ×ו SSL. לרוב, פירוש הדבר ×”×•× ×©×”×©×¨×ª ×שת×ש בתוכנה ישנה ××וד וייתכן שיש לו בעיות ×בטחה ×חרות.</translation>
<translation id="284702764277384724">×ישור השרת ב-<ph name="HOST_NAME" /> נר××” ×זויף.</translation>
<translation id="2889159643044928134">×ל תטען ×חדש</translation>
-<translation id="2896499918916051536">הפל×גין ×”×–×” ×ינו נת××.</translation>
+<translation id="2900469785430194048">â€×זל הזיכרון ×”×–×ין ל-Google Chrome בניסיון להציג ×ת דף ×”×ינטרנט ×”×–×”.</translation>
<translation id="2909946352844186028">×ותר שינוי ברשת.</translation>
-<translation id="2915500479781995473">לשרת ×–×” ×œ× ×”×™×™×ª×” ×פשרות להוכיח ×©×”×•× <ph name="DOMAIN" />; פג תוקפו של ×ישור ×”×בטחה שלו. ייתכן ש×צב ×–×” × ×’×¨× ×‘×©×œ תצורה שגויה ×ו שתוקף ×יירט ×ת החיבור של×. שעון ×”×חשב ×©×œ× ×וגדר כעת ל-<ph name="CURRENT_TIME" />. ×”×× ×”×©×¢×” נכונה? ×× ×œ×, ×¢×œ×™× ×œ×›×•×•×Ÿ ×ת שעון ×”×ערכת ול×חר ×כן לרענן דף ×–×”.</translation>
<translation id="2922350208395188000">×œ× × ×™×ª×Ÿ לבדוק ×ת ×ישור השרת.</translation>
-<translation id="2941952326391522266">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />. ×ישור ×”×בטחה שלו ×”×•× ×-<ph name="DOMAIN2" />. ייתכן שהסיבה ×œ×›× ×”×™× ×ª×¦×•×¨×” שגויה ×ו תוקף ×”×יירט ×ת החיבור של×.</translation>
<translation id="2948083400971632585">â€× ×™×ª×Ÿ להשבית כל שרת proxy ×”×וגדר לחיבור ×דף ההגדרות.</translation>
<translation id="2955913368246107853">סגור ×ת חלונית החיפוש</translation>
<translation id="2958431318199492670">â€×ª×¦×•×¨×ª הרשת ××™× ×” תו××ת לתקן ONC. ייתכן ×©×—×œ×§×™× ×התצורה ×œ× ×™×™×›×œ×œ×• בייבו×.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">סוג ×”×דיניות שגוי</translation>
<translation id="3032412215588512954">×”×× ×‘×¨×¦×•× × ×œ×˜×¢×•×Ÿ ×חדש ×ת ×”×תר?</translation>
<translation id="3037605927509011580">×וי, ל×!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{לפחות פריט ×חד ב××›×©×™×¨×™× ×סונכרני×}=1{פריט ×חד (×•×¤×¨×™×˜×™× × ×•×¡×¤×™× ×‘××›×©×™×¨×™× ×סונכרני×)}two{שני ×¤×¨×™×˜×™× (×•×¤×¨×™×˜×™× × ×•×¡×¤×™× ×‘××›×©×™×¨×™× ×סונכרני×)}many{# ×¤×¨×™×˜×™× (×•×¤×¨×™×˜×™× × ×•×¡×¤×™× ×‘××›×©×™×¨×™× ×סונכרני×)}other{# ×¤×¨×™×˜×™× (×•×¤×¨×™×˜×™× × ×•×¡×¤×™× ×‘××›×©×™×¨×™× ×סונכרני×)}}</translation>
<translation id="3041612393474885105">פרטי ×ישור</translation>
<translation id="3063697135517575841">â€Chrome ×œ× ×”×¦×œ×™×— ל×שר ×ת הכרטיס ×©×œ× ×”×¤×¢×. נסה שוב ××וחר יותר.</translation>
<translation id="3093245981617870298">×תה ב×צב ×œ× ×קוון.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">החדש ביותר</translation>
<translation id="3207960819495026254">×סו×ן בסי×× ×™×”</translation>
-<translation id="3225919329040284222">השרת הציג ×ישור ש×ינו תו×× ×ת הציפיות ×”×ובנות. ציפיות ×לה נכללות עבור ×תרי ×ינטרנט ×סוי××™× ×‘×¢×œ×™ ×בטחה גבוהה כדי להגן עלי×.</translation>
<translation id="3226128629678568754">לחץ על לחצן הטעינה ×חדש כדי לשלוח ×חדש ×ת ×”× ×ª×•× ×™× ×”×“×¨×•×©×™× ×œ×˜×¢×™× ×ª הדף.</translation>
<translation id="3228969707346345236">×”×ª×¨×’×•× × ×›×©×œ כיוון שהדף כבר ב<ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">הזן ×ת קוד ×”××™×ות של הכרטיס <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">הוסף ×ת הדף לסי×ניות</translation>
<translation id="3270847123878663523">&amp;ביטול של שינוי סדר</translation>
<translation id="3286538390144397061">הפעל ×חדש כעת</translation>
+<translation id="3303855915957856445">×œ× × ×צ×ו תוצ×ות חיפוש</translation>
<translation id="3305707030755673451">×”× ×ª×•× ×™× ×©×œ× ×”×•×¦×¤× ×• ב-<ph name="TIME" /> ב××צעות ביטוי הסיס××” לסינכרון. הזן ×ותו כדי להתחיל בסינכרון.</translation>
<translation id="333371639341676808">×× ×¢ ×דף ×–×” ליצור די××œ×•×’×™× × ×•×¡×¤×™×.</translation>
+<translation id="3338095232262050444">××ובטח</translation>
<translation id="3340978935015468852">הגדרות</translation>
<translation id="3345135638360864351">×œ× × ×™×ª×Ÿ ×”×™×” לשלוח ×ל <ph name="NAME" /> ×ת הבקשה ×©×œ× ×œ×’×©×ª ל×תר ×”×–×”. נסה שוב.</translation>
<translation id="3355823806454867987">â€×©× ×” הגדרות שרת Proxy...</translation>
@@ -222,7 +226,7 @@
<translation id="337363190475750230">ניהול התצורה בוטל</translation>
<translation id="3377188786107721145">שגי××” בניתוח ×”×דיניות</translation>
<translation id="3380365263193509176">שגי××” ×œ× ×™×“×•×¢×”</translation>
-<translation id="3380864720620200369">××–×”×” לקוח:</translation>
+<translation id="3380864720620200369">×ספר לקוח:</translation>
<translation id="340013220407300675">ייתכן ×©×ª×•×§×¤×™× ×× ×¡×™× ×œ×’× ×•×‘ ×ת ×”×ידע ×©×œ× ×-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (לדוג××”: סיס××ות, הודעות ×ו כרטיסי ×שר××™).</translation>
<translation id="3422472998109090673">×œ× × ×™×ª×Ÿ לגשת כרגע ×ל <ph name="HOST_NAME" />.</translation>
<translation id="3427342743765426898">&amp;ביצוע ×חדש של עריכה</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">×רווח ×חזור:</translation>
<translation id="3462200631372590220">הסתר ×¤×¨×˜×™× ×תקד××™×</translation>
<translation id="3479539252931486093">×”×× ×–×” קרה ב×ופן בלתי צפוי? <ph name="BEGIN_LINK" />ספר לנו על ×›×<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">×œ× ×¢×›×©×™×•</translation>
<translation id="348000606199325318">××–×”×” קריסה <ph name="CRASH_LOCAL_ID" /> (××–×”×” שרת: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">×œ× ×”×¦×œ×—× ×• ליצור קשר ×¢× ×”×”×•×¨×” של×. נסה שוב ××וחר יותר.</translation>
<translation id="3527085408025491307">תיקיה</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">השת×ש בסיס××” עבור:</translation>
<translation id="3549644494707163724">הצפן ×ת כל ×”× ×ª×•× ×™× ×”××¡×•× ×›×¨× ×™× ×‘××צעות ×שפט הסיס××” ×©×œ× ×œ×¡× ×›×¨×•×Ÿ</translation>
<translation id="3549761410225185768">עוד <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו נופק על-ידי <ph name="DOMAIN2" />. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">החיבור ×©×œ× ×ינו פרטי</translation>
<translation id="3583757800736429874">&amp;ביצוע ×חדש של העברה</translation>
<translation id="3586931643579894722">הסתר פרטי×</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">הצג ער×</translation>
<translation id="3630155396527302611">×× ×”×™× ×›×‘×¨ רשו××” כתוכנית ×”×ורשית לגשת לרשת, נסה
להסיר ×ותה ×הרשי××” ולהוסיף ×ותה שוב.</translation>
+<translation id="3638794133396384728">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; תוקף ×ישור ×”×בטחה שלו פג. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. הת××¨×™× ×”×וגדר עכשיו בשעון ×”×חשב ×©×œ× ×”×•× <ph name="CURRENT_TIME" />. ×”×× ×–×” נכון? ×× ×œ×, ×¢×œ×™× ×œ×›×•×•×Ÿ ×ת שעון ×”×ערכת ול×חר ×כן לרענן ×ת הדף ×”×–×”. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">תכונות ניסיוניות ×לה עשויות להשתנות, להפסיק לעבוד ×ו ×œ×”×™×¢×œ× ×‘×›×œ עת. ×יננו ××‘×™×¢×™× ×›×œ ×חריות לגבי ההשלכות של הפעלה של ×חד ×× ×™×¡×•×™×™× ×לה, וייתכן ××£ שהדפדפן ×©×œ× ×™×ª×œ×§×— ב×ופן ספונטני. צחוק בצד, הדפדפן עלול ל×חוק ×ת כל ×”× ×ª×•× ×™× ×©×œ×, ×ו שה×בטחה והפרטיות ×©×œ× ×™×™×¤×’×¢×• ×‘×“×¨×›×™× ×œ× ×¦×¤×•×™×•×ª. כל ניסוי שת×פשר ×™×”×¤×•× ×œ×¤×¢×™×œ עבור כל ×”×שת××©×™× ×‘×“×¤×“×¤×Ÿ ×–×”. ×”××©× ×‘×–×”×™×¨×•×ª.</translation>
<translation id="3650584904733503804">×”××™×ות בוצע בהצלחה</translation>
<translation id="3655670868607891010">×× ×תה רו××” ×–×ת ×œ×¢×ª×™× ×§×¨×•×‘×•×ª, נסה ×ת ×”<ph name="HELP_LINK" /> ×”×לה.</translation>
<translation id="3658742229777143148">גרסה קוד×ת</translation>
+<translation id="3678029195006412963">×œ× × ×™×ª×Ÿ ×”×™×” ×œ×—×ª×•× ×¢×œ הבקשה</translation>
<translation id="3681007416295224113">פרטי ×ישור</translation>
<translation id="3693415264595406141">סיס××”:</translation>
+<translation id="3696411085566228381">לל×</translation>
<translation id="3700528541715530410">×צטערי×, נר××” ש×ין ×œ× ×”×¨×©××” לגשת לדף ×–×”.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">טוען...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">â€×œ×”פעיל × ×ª×•× ×™× ×œ× ×™×™×“ ×ו ×ת ×”-Wi-Fi</translation>
<translation id="3717027428350673159">â€<ph name="BEGIN_LINK" />לבדוק ×ת תצורת ×”-DNS, חו×ת ×”×ש ושרת ×”-Proxy<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">קישור שהעתקת</translation>
-<translation id="3744899669254331632">â€××™× × ×™×›×•×œ לבקר כרגע ב-<ph name="SITE" /> ×פני שה×תר שלח פרטי כניסה ××¢×•×¨×‘×œ×™× ×©-Chromium ×ינו יכול לעבד. שגי×ות רשת והתקפות הן ×‘×“×¨× ×›×œ×œ ×–×ניות, לכן סביר להניח שדף ×–×” יפעל כהלכה בה×ש×.</translation>
<translation id="375403751935624634">×”×ª×¨×’×•× × ×›×©×œ עקב שגי×ת שרת.</translation>
<translation id="3759461132968374835">×œ× ×”×ª×§×‘×œ×• ×“×™×•×•×—×™× ×¢×œ קריסות ל×חרונה. קריסות שהתרחשו בז×ן ש×פשרות הדיווח על קריסות היתה ×ושבתת ×œ× ×™×•×¤×™×¢×• ×›×ן.</translation>
<translation id="3788090790273268753">â€×ª×•×§×£ ×”×ישור של ×”×תר ×”×–×” יפוג ב-2016 ושרשרת ×”××™×©×•×¨×™× ×כילה ×ישור ×©× ×—×ª× ×‘××צעות SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">××–×”×” ×כשיר ×תנגש</translation>
<translation id="3885155851504623709">קהילה</translation>
<translation id="3901925938762663762">תוקף הכרטיס פג</translation>
+<translation id="3910267023907260648">ניסית להגיע ×ל <ph name="DOMAIN" />, ×בל השרת הציג ×ישור ×©× ×—×ª× ×¢×œ-ידי ××œ×’×•×¨×™×ª× ×—×ª×™××” בר×ת ×בטחה חלשה. ×ש×עות הדבר ×”×™× ×©×™×™×ª×›×Ÿ ×›×™ ×ישורי ×”×בטחה שהשרת הציג ×זויפי×, ×•×©×œ× ×דובר בשרת שציפית לו (ייתכן ש×תה ×תקשר ×¢× ×ª×•×§×£). <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ××ור להיכנס לתוקף רק ×חר. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.}two{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ××ור להיכנס לתוקף רק בעוד יו××™×™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.}many{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ××ור להיכנס לתוקף רק בעוד # ×™××™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.}other{השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ××ור להיכנס לתוקף רק בעוד # ×™××™×. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">â€×”טעינה של ×ס×× PDF נכשלה</translation>
<translation id="3963721102035795474">×צב קור×</translation>
+<translation id="397105322502079400">×חשב...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> חסו×</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{דף ×ינטרנט קרוב ×חד}two{# דפי ×ינטרנט קרובי×}many{# דפי ×ינטרנט קרובי×}other{# דפי ×ינטרנט קרובי×}}</translation>
<translation id="4021036232240155012">â€DNS ×”×•× ×©×™×¨×•×ª הרשת ש××ª×¨×’× ×©× ×©×œ ×תר לכתובת ×”×ינטרנט שלו.</translation>
<translation id="4030383055268325496">&amp;ביטול הוספה</translation>
-<translation id="4032534284272647190">הגישה ×ל <ph name="URL" /> נדחתה.</translation>
<translation id="404928562651467259">×זהרה</translation>
<translation id="4058922952496707368">×פתח "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">â€×”לקוח והשרת ××™× × ×ª×•××›×™× ×‘×’×¨×¡×” נפוצה של פרוטוקול SSL ×ו בחבילת צפני×.</translation>
<translation id="4079302484614802869">â€×ª×¦×•×¨×ª ×”-Proxy ×וגדרת להשת×ש בכתובת ×תר של סקריפט ×סוג â€.Pac ×•×œ× ×‘×©×¨×ª×™ Proxy קבועי×.</translation>
<translation id="4103249731201008433">×”×ספר הסידורי של ×”×כשיר ×ינו חוקי</translation>
<translation id="4103763322291513355">â€×”יכנס לכתובת &lt;strong&gt;chrome://policy&lt;/strong&gt; כדי לר×ות רשי××” של כתובות ××ª×¨×™× ×©× ×× ×¢×” ××œ×™×”× ×”×’×™×©×”, ×›×ו ×’× ×ª×§× ×•× ×™× ××—×¨×™× ×©× ×כפו על ידי ×נהל ×”×ערכת של×.</translation>
+<translation id="4110615724604346410">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ×כיל שגי×ות. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">היקף ×”×דיניות ×ינו נת××.</translation>
+<translation id="4118212371799607889">â€×”שרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; Chromium ×ינו בוטח ב×ישור ×”×בטחה שלו. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{×חד נוסף}two{×©× ×™×™× × ×•×¡×¤×™×}many{# נוספי×}other{# נוספי×}}</translation>
<translation id="4130226655945681476">בדוק ×ת כבלי הרשת, ×ת ×”××•×“× ×•×ת הנתב</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">â€×”×× ×ª×¨×¦×” ש-Chromium יש×ור ×ת הכרטיס ×”×–×”?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">×ושבת</translation>
<translation id="4196861286325780578">&amp;ביצוע ×חדש של העברה</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />לבדוק ×ת תצורת ×”×נטי-וירוס וחו×ת ×”×ש<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{לל×}=1{×פליקציה ×חת ($1)}=2{שתי ×פליקציות ($1, $2)}many{# ×פליקציות ($1, $2, $3)}other{# ×פליקציות ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">קריסה</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />נסה להפעיל ×ת ×בחון הרשת<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">ל×</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(×ין ×©× ×שת×ש)</translation>
<translation id="4300246636397505754">הצעות להורי×</translation>
<translation id="4304224509867189079">היכנס</translation>
+<translation id="432290197980158659">השרת הציג ×ישור ש×ינו עו×ד בציפיות ×”×ובנות ב×ערכת. הציפיות ×”×לה ×וגדרות על ×נת ל×פשר גישה רק ×ל ××ª×¨×™× ×‘×¢×œ×™ ר×ת ×בטחה גבוהה כדי לש×ור על ביטחונ×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">×œ× × ×™×ª×Ÿ ×”×™×” ל××¦×•× ×ת הפריט</translation>
+<translation id="4331708818696583467">×œ× ××ובטח</translation>
<translation id="4372948949327679948">צפוי ×¢×¨× ×סוג <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">ניסית להשיג ×ת <ph name="DOMAIN" />, ×× ×”×ישור שהשרת הציג בוטל על ידי ×”×נפיק שלו. פירוש הדבר ש×ין כל ×פשרות לתת ××ון ב×ישורי ×”×בטחה שהשרת הציג. ייתכן ש×תה ×תקשר ×¢× ×ª×•×§×£.</translation>
<translation id="4381091992796011497">×©× ×שת×ש:</translation>
<translation id="4394049700291259645">השבת</translation>
<translation id="4395129973926795186">×-<ph name="START_DATE" /> עד <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">תוצ×ות חיפוש</translation>
-<translation id="4424024547088906515">â€×”שרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />. ×ישור ×”×בטחה שלו ×œ× × ×—×©×‘ ×›××”×™×ן על ידי Chrome. ייתכן שהסיבה ×œ×›× ×”×™× ×ª×¦×•×¨×” שגויה ×ו תוקף ×”×יירט ×ת החיבור של×.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> ×œ× ×ישר ×ת ×ישור ההתחברות של×, ×ו ×©×œ× ×¡×•×¤×§ ×ישור התחברות.</translation>
<translation id="443673843213245140">â€×”שי×וש בשרת Proxy הושבת, ×× ×¦×•×™×™× ×” תצורת שרת Proxy ×פורשת.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">â€×תה רו××” ×ת ההודעה הזו ×פני ששירות Google SafeSites ×ופעל.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">פרטי×</translation>
<translation id="4558551763791394412">נסה להשבית ×ת התוספי×.</translation>
<translation id="4587425331216688090">â€×”×× ×œ×”×¡×™×¨ ×ת הכתובת ×-Chrome?</translation>
+<translation id="4589078953350245614">ניסית להגיע ×ל <ph name="DOMAIN" />, ×× ×”×©×¨×ª הציג ×ישור ×œ× ×—×•×§×™. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">החיבור ×©×œ× ×ל <ph name="DOMAIN" /> ×וצפן ב××צעות חבילת צופן ×תקד×ת.</translation>
<translation id="4594403342090139922">&amp;ביטול ×חיקה</translation>
+<translation id="4627442949885028695">×”××©× ×‘×כשיר ×חר</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">×תה צופה בדף של תוסף.</translation>
-<translation id="467662567472608290">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ×כיל שגי×ות. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו תוקף ×”×יירט ×ת החיבור של×.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> היתה חסו××”</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">החיבור נקטע</translation>
<translation id="4722547256916164131">â€<ph name="BEGIN_LINK" />×פעיל ×ת ×בחון הרשת של Windows<ph name="END_LINK" /></translation>
@@ -336,6 +352,7 @@
<translation id="4728558894243024398">פלטפור××”</translation>
<translation id="4744603770635761495">נתיב להפעלה</translation>
<translation id="4756388243121344051">&amp;היסטוריה</translation>
+<translation id="4759238208242260848">הורדות</translation>
<translation id="4764776831041365478">ייתכן שדף ×”×ינטרנט בכתובת <ph name="URL" /> ×ינו פעיל ×–×נית, ×ו שהועבר לכתובת ×ינטרנט חדשה לצ×יתות.</translation>
<translation id="4771973620359291008">â€×ירעה שגי××” ×œ× ×וכרת.
@@ -344,17 +361,21 @@
Del</translation>
<translation id="4782449893814226250">ש×לת ×ת ×”×•×¨×™× ×× ×–×” בסדר להיכנס לדף ×–×”.</translation>
<translation id="4800132727771399293">â€×‘דוק ×ת ת××¨×™× ×”×ª×¤×•×’×” ו×ת ×”-CVC ונסה שוב</translation>
-<translation id="4807049035289105102">â€×œ× ניתן לבקר כעת ב×תר <ph name="SITE" /> ×כיוון שה×תר שלח ××™×©×•×¨×™× ××©×•×‘×©×™× ×©-Google Chrome ×ינו יכול לעבד. שגי×ות רשת ותקיפות ×תרחשות ×‘×“×¨× ×›×œ×œ לז×ן ×וגבל, ×›× ×©×¡×‘×™×¨ להניח שהדף ×”×–×” יפעל ××וחר יותר.</translation>
<translation id="4813512666221746211">שגי×ת רשת</translation>
<translation id="4816492930507672669">הת×××” לדף</translation>
<translation id="4850886885716139402">הצג</translation>
<translation id="4880827082731008257">חפש בהיסטוריה</translation>
+<translation id="4884656795097055129">××××¨×™× × ×•×¡×¤×™× ×™×•×¤×™×¢×• לפי הצור×.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{ועוד דף ×ינטרנט ×חד}two{ועוד # דפי ×ינטרנט}many{ועוד # דפי ×ינטרנט}other{ועוד # דפי ×ינטרנט}}</translation>
<translation id="4923417429809017348">דף ×–×” ×ª×•×¨×’× ×שפה ×œ× ×™×“×•×¢×” ל<ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">יש לציין ×¢×¨× ×–×”.</translation>
<translation id="4930497775425430760">×תה רו××” ×ת ההודעה הזו ×פני שההורה ×©×œ× ×¦×¨×™× ×œ×שר ××ª×¨×™× ×—×“×©×™× ×‘×‘×™×§×•×¨ הר×שון של×.</translation>
<translation id="495170559598752135">פעולות</translation>
<translation id="4958444002117714549">הרחב רשי××”</translation>
+<translation id="4962322354953122629">â€×”שרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; Chrome ×ינו סו×× ×¢×œ ×ישור ×”×בטחה שלו. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">×”×× ×œ×ª×¨×’× ×<ph name="ORIGINAL_LANGUAGE" /> ל<ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">הפל×גין ×”×–×” ×ינו נת××</translation>
<translation id="5002932099480077015">â€×× ×”×פשרות הזו תופעל, Chrome ×™×חסן עותק של הכרטיס ×©×œ× ×‘×כשיר ×”×–×” ל×ילוי ×היר יותר של טפסי×.</translation>
<translation id="5019198164206649151">×”×חסון ×”×ש×ש כגיבוי ×ינו תקין</translation>
<translation id="5023310440958281426">בדוק ×ת תקנון ×נהל ×”×ערכת של×</translation>
@@ -362,13 +383,12 @@ Del</translation>
<translation id="5031870354684148875">â€×ידע על Google Translate</translation>
<translation id="5040262127954254034">פרטיות</translation>
<translation id="5045550434625856497">סיס××” שגויה</translation>
+<translation id="5056549851600133418">××××¨×™× ×©×¢×©×•×™×™× ×œ×¢× ×™×™×Ÿ ×ות×</translation>
<translation id="5070335125961472645">â€<ph name="BEGIN_LINK" />לבדוק ×ת כתובת שרת ×”-Proxy<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">×”×ישור של השרת ×ינו תקף כעת.</translation>
<translation id="5089810972385038852">×דינה</translation>
-<translation id="5094747076828555589">â€×”שרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />. ×ישור ×”×בטחה שלו ×œ× × ×—×©×‘ ×›××”×™×ן על ידי Chromium. ייתכן שהסיבה ×œ×›× ×”×™× ×ª×¦×•×¨×” שגויה ×ו תוקף ×”×יירט ×ת החיבור של×.</translation>
<translation id="5095208057601539847">פרובינציה</translation>
<translation id="5115563688576182185">(64 סיביות)</translation>
-<translation id="5122371513570456792">× ×צ×ו <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> לגבי '<ph name="SEARCH_STRING" />'.</translation>
<translation id="5141240743006678641">â€×”צפן סיס××ות ×סונכרנות ב××צעות פרטי הכניסה ×©×œ× ×œ-Google</translation>
<translation id="5145883236150621069">×§×™×™× ×§×•×“ שגי××” בתגובת ×”×דיניות</translation>
<translation id="5171045022955879922">חפש ×ו הקלד כתובת ×תר</translation>
@@ -377,18 +397,18 @@ Del</translation>
<translation id="5190835502935405962">סרגל הסי×ניות</translation>
<translation id="5199729219167945352">ניסויי×</translation>
<translation id="5251803541071282808">ענן</translation>
+<translation id="5277279256032773186">â€×שת×ש ב-Chrome בעבודה? ×¢×¡×§×™× ×™×›×•×œ×™× ×œ× ×”×œ ×ת ההגדרות של Chrome עבור העובדי×. ל×ידע נוסף</translation>
<translation id="5299298092464848405">שגי××” בניתוח ×”×דיניות</translation>
<translation id="5300589172476337783">הצג</translation>
<translation id="5308689395849655368">דיווח קריסות ×ושבת.</translation>
<translation id="5317780077021120954">ש×ור</translation>
<translation id="5327248766486351172">ש×</translation>
+<translation id="5359637492792381994">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ×ינו חוקי כעת. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">×חסון הגדרות ×”×דיניות נכשל</translation>
-<translation id="540969355065856584">שרת ×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ×ינו תקף כעת. הסיבה ×œ×›× ×¢×©×•×™×” להיות תצורה שגויה ×ו שתוקף ×יירט ×ת החיבור של×.</translation>
<translation id="5421136146218899937">נקה נתוני גלישה...</translation>
<translation id="5430298929874300616">הסר סי×× ×™×”</translation>
<translation id="5431657950005405462">הקובץ ×œ× × ×צ×</translation>
<translation id="5435775191620395718">×ציג היסטוריה ××”×כשיר ×”×–×”. <ph name="BEGIN_LINK" />ל×ידע נוסף<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">×”×לצות לתוכן בהת×××” ×ישית ×ושבתות כרגע, ×פני ×©×”× ×ª×•× ×™× ×”××¡×•× ×›×¨× ×™× ×©×œ× ××•×’× ×™× ×‘××צעות ביטוי סיס××” ×ות×× ×ישית.</translation>
<translation id="5439770059721715174">שגי×ת ××™×ות סכי××” ב-"<ph name="ERROR_PATH" />"â€: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">×œ× × ×™×ª×Ÿ ל××¦×•× ×ת הדף של <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">חות×ת ×”×–×ן של ×”×דיניות שגויה</translation>
@@ -412,14 +432,18 @@ Del</translation>
<translation id="5622887735448669177">×”×× ×‘×¨×¦×•× × ×œ×¢×–×•×‘ ×ת ×”×תר?</translation>
<translation id="5629630648637658800">טעינת הגדרות ×”×דיניות נכשלה</translation>
<translation id="5631439013527180824">×סי×ון ניהול ×”×כשיר ×ינו חוקי</translation>
-<translation id="5650551054760837876">×œ× × ×צ×ו תוצ×ות חיפוש.</translation>
<translation id="5677928146339483299">ב×צב חסו×</translation>
<translation id="5710435578057952990">הזהות של ×תר ×–×” ×œ× ×ו×תה.</translation>
<translation id="5720705177508910913">×שת×ש נוכחי:</translation>
+<translation id="572328651809341494">כרטיסיות ×חרונות</translation>
<translation id="5784606427469807560">הייתה בעיה ב×ישור הכרטיס. בדוק ×ת החיבור ל×ינטרנט ונסה שוב.</translation>
<translation id="5785756445106461925">×›×ו כן, דף ×–×” כולל ×ש××‘×™× × ×•×¡×¤×™× ×©××™× × ××ובטחי×. גור××™× ××—×¨×™× ×¢×œ×•×œ×™× ×œ×¨×ות ×ת ×”×ש××‘×™× ×”×לה ב××”×œ× ×”×¢×‘×¨×ª×, ותוקף עלול לשנות ××•×ª× ×‘×ופן שישנה ×ת ×ר××” הדף.</translation>
+<translation id="5786044859038896871">×”×× ×‘×¨×¦×•× × ×œ××œ× ×ת פרטי הכרטיס של×?</translation>
+<translation id="5803412860119678065">×”×× ×‘×¨×¦×•× × ×œ××œ× ×ת פרטי הכרטיס <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">החיבור ×©×œ× ×ל <ph name="DOMAIN" /> ×וצפן ב××צעות חבילת צופן ×יושנת.</translation>
<translation id="5813119285467412249">&amp;ביצוע ×חדש של הוספה</translation>
+<translation id="5814352347845180253">×תה עשוי ל×בד גישה ×ל תוכן פר××™×•× ×-<ph name="SITE" /> ו×××ª×¨×™× ×חרי×.</translation>
+<translation id="5843436854350372569">ניסית להגיע ×ל <ph name="DOMAIN" />, ×בל השרת הציג ×ישור ×”×כיל ×פתח חלש. ייתכן שתוקף פרץ ×ת ×”×פתח הפרטי וזהו ×ינו השרת ש×תה ×צפה לו (ייתכן ש×תה ×תקשר ×¢× ×ª×•×§×£). <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">×תה רו××” ×ת ההודעה הזו ×פני שה×נהל ×©×œ× ×—×¡× ×ת ×”×תר ×”×–×”.</translation>
<translation id="5857090052475505287">תיקייה חדשה</translation>
<translation id="5869405914158311789">×œ× × ×™×ª×Ÿ לגשת ל×תר ×”×–×”</translation>
@@ -427,6 +451,7 @@ Del</translation>
<translation id="5872918882028971132">הצעות להורי×</translation>
<translation id="59107663811261420">â€×¡×•×’ הכרטיס ×”×–×” ×ינו נת×× ×¢×œ ידי Google Payments ×צל הסוחר ×”×–×”. בחר כרטיס ×חר.</translation>
<translation id="59174027418879706">×ופעל</translation>
+<translation id="5926846154125914413">×תה עשוי ל×בד גישה ×ל תוכן פר××™×•× ×××ª×¨×™× ×סוי××™×.</translation>
<translation id="5966707198760109579">שבוע</translation>
<translation id="5967867314010545767">הסר ×ההיסטוריה</translation>
<translation id="5975083100439434680">התרחק</translation>
@@ -438,12 +463,12 @@ Del</translation>
<translation id="604124094241169006">×וטו×טי</translation>
<translation id="6042308850641462728">עוד</translation>
<translation id="6060685159320643512">זהירות, × ×™×¡×•×™×™× ×לה ×¢×œ×•×œ×™× ×œ× ×©×•×</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{לל×}=1{×חת}two{שתיי×}many{#}other{#}}</translation>
<translation id="6146055958333702838">בדוק ×ת ×”×›×‘×œ×™× ×•×”×¤×¢×œ ×חדש ×ת הנתבי×, ×”×וד××™× ×•×©×ר התקני הרשת
ש×תה ×שת×ש בה×.</translation>
<translation id="614940544461990577">נסה:</translation>
<translation id="6150607114729249911">×ופס! ×¢×œ×™× ×œ×©×ול ×ת ×”×”×•×¨×™× ×©×œ× ×× ×תה יכול להיכנס לדף ×”×–×”.</translation>
<translation id="6151417162996330722">תקופת התוקף של ×ישור השרת ×רוכה ×די.</translation>
-<translation id="6154808779448689242">×סי×ון ×”×דיניות שהוחזר ×ינו תו×× ×œ×סי×ון הנוכחי</translation>
<translation id="6165508094623778733">ל×ידע נוסף</translation>
<translation id="6203231073485539293">בדוק ×ת חיבור ×”×ינטרנט</translation>
<translation id="6218753634732582820">â€×”×× ×œ×”×¡×™×¨ ×-Chromium ×ת הכתובת?</translation>
@@ -456,24 +481,30 @@ Del</translation>
<translation id="6328639280570009161">נסה להשבית ×ת חיזוי הרשת</translation>
<translation id="6337534724793800597">סנן ×דיניות לפי ש×</translation>
<translation id="6342069812937806050">זה עתה</translation>
+<translation id="6345221851280129312">גודל ×œ× ×™×“×•×¢</translation>
<translation id="6355080345576803305">שינוי הפעלה ציבורית</translation>
<translation id="6358450015545214790">××” ×–×” ×ו×ר?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{הצעה ×חת נוספת}two{שתי הצעות נוספות}many{# הצעות נוספות}other{# הצעות נוספות}}</translation>
<translation id="6387478394221739770">â€×עוניין בתכונות חדשות ו×גניבות של Chrome? נסה ×ת ערוץ ×”×‘×™×˜× ×©×œ× ×• בכתובת chrome.com/beta.</translation>
-<translation id="641480858134062906">נכשלה הטעינה של <ph name="URL" /></translation>
+<translation id="6389758589412724634">â€×זל הזיכרון ×”×–×ין ל-Chromium בניסיון להציג ×ת דף ×”×ינטרנט ×”×–×”.</translation>
+<translation id="6416403317709441254">â€×œ× ניתן לבקר עכשיו ב-<ph name="SITE" /> ×כיוון שה×תר שלח ××™×©×•×¨×™× ×œ× ×ª×§×™× ×™× ×©-Chromium ×œ× ×צליח לעבד. שגי×ות רשת ותקיפות ×תרחשות ×‘×“×¨× ×›×œ×œ לז×ן ×וגבל, ולכן סביר להניח שדף ×–×” יחזור לפעול ××וחר יותר. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">×œ× × ×™×ª×Ÿ לבדוק ×× ×”×ישור נשלל.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> סירב להתחבר.</translation>
<translation id="6445051938772793705">×רץ</translation>
<translation id="6451458296329894277">×שר שליחה-×חדש של הטופס</translation>
<translation id="6458467102616083041">×”×ערכת התעל××” ××¢×¨× ×דיניות ×–×”, ××©×•× ×©×œ×¤×™ ×”×דיניות, חיפוש ברירת ×”×חדל ×ושבת.</translation>
+<translation id="6462969404041126431">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ייתכן ש×ישור ×”×בטחה שלו בוטל. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">×דיניות ×”×כשיר</translation>
<translation id="6489534406876378309">התחל להעלות קריסות</translation>
<translation id="6529602333819889595">&amp;ביצוע ×חדש של ×חיקה</translation>
+<translation id="6534179046333460208">הצעות ל×ינטרנט הווירטופיזי</translation>
<translation id="6550675742724504774">×פשרויות</translation>
+<translation id="6593753688552673085">פחות ×-<ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">×פשרויות הצפנה</translation>
<translation id="662080504995468778">היש×ר</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> חיפוש</translation>
-<translation id="6634865548447745291">×œ× × ×™×ª×Ÿ לבקר כעת ב×תר <ph name="SITE" /> ×כיוון ש<ph name="BEGIN_LINK" />פג התוקף של ×ישור ×–×”<ph name="END_LINK" />. שגי×ות רשת ותקיפות ×תרחשות ×‘×“×¨× ×›×œ×œ לז×ן ×וגבל, ×›× ×©×¡×‘×™×¨ להניח שדף ×–×” יפעל ××וחר יותר.</translation>
<translation id="6644283850729428850">×דיניות זו ××™× ×” בתוקף.</translation>
+<translation id="6652240803263749613">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ערכת ההפעלה של ×”×חשב ×œ× ×¡×•×כת על ×ישור ×”×בטחה שלו. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">×¢×¨×•× ×ª×™×§×™×™×”</translation>
<translation id="6660210980321319655">דיווח ×וטו×טי <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">â€×”×× ×œ×”×¡×™×¨ ×-Chromium הצעות לטפסי×?</translation>
@@ -481,6 +512,7 @@ Del</translation>
<translation id="6710213216561001401">הקוד×</translation>
<translation id="6710594484020273272">&lt;הקלד ×ונח חיפוש&gt;</translation>
<translation id="6711464428925977395">â€×שהו ×ינו תקין בשרת ×”-proxy, ×ו שהכתובת שגויה.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{לל×}=1{פריט ×חד}two{שני פריטי×}many{# פריטי×}other{# פריטי×}}</translation>
<translation id="674375294223700098">שגי×ת ×ישור שרת ×œ× ×™×“×•×¢.</translation>
<translation id="6753269504797312559">×¢×¨× ×דיניות</translation>
<translation id="6757797048963528358">×”×כשיר עבר ל×צב שינה.</translation>
@@ -492,7 +524,6 @@ Del</translation>
<translation id="6891596781022320156">ר×ת ×”×דיניות ××™× ×” נת×כת.</translation>
<translation id="6895330447102777224">הכרטיס ×©×œ× ××ושר</translation>
<translation id="6897140037006041989">User agent</translation>
-<translation id="6903907808598579934">הפעל סנכרון</translation>
<translation id="6915804003454593391">×שת×ש:</translation>
<translation id="6957887021205513506">נר××” שה×ישור של השרת ×זויף.</translation>
<translation id="6965382102122355670">×ישור</translation>
@@ -500,9 +531,11 @@ Del</translation>
<translation id="6970216967273061347">×חוז</translation>
<translation id="6973656660372572881">â€×¦×•×™× ×• שרתי Proxy ×§×‘×•×¢×™× ×•×›×ª×•×‘×ª ×תר של הסקריפט ×סוג â€.Pac</translation>
<translation id="6989763994942163495">הצג הגדרות ×תקד×ות...</translation>
+<translation id="7000990526846637657">×œ× × ×צ×ו רשו×ות היסטוריה</translation>
+<translation id="7009986207543992532">ניסית להגיע ×ל <ph name="DOMAIN" />, ×בל השרת הציג ×ישור ×¢× ×ª×§×•×¤×ª תוקף ×רוכה ב×ופן ×חשיד. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">â€×™×™×ª×›×Ÿ שלחשבון Google ×©×œ× ×™×© ×¡×•×’×™× ××—×¨×™× ×©×œ היסטוריית גלישה שז××™× ×™× ×‘×›×ª×•×‘×ª <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">סיס××ות</translation>
-<translation id="7050187094878475250">ניסית להגיע ×ל <ph name="DOMAIN" />, ×× ×”×©×¨×ª הציג ×ישור שתקופת התוקף שלו ×רוכה ×די ולכן ×ינו ××”×™×ן.</translation>
<translation id="7087282848513945231">×חוז (בבריטניה וב×ירלנד)</translation>
<translation id="7088615885725309056">ישן יותר</translation>
<translation id="7090678807593890770">â€×—פש ב-Google ×ת <ph name="LINK" /></translation>
@@ -521,13 +554,13 @@ Del</translation>
<translation id="7246609911581847514">×תה רו××” ×ת ההודעה הזו ×פני שה×נהל ×©×œ× ×¦×¨×™× ×œ×שר ××ª×¨×™× ×—×“×©×™× ×¢× ×”×‘×™×§×•×¨ הר×שון של×.</translation>
<translation id="724975217298816891">הזן ×ת ת××¨×™× ×”×ª×¤×•×’×” ו×ת קוד ×”××™×ות של <ph name="CREDIT_CARD" /> כדי לעדכן ×ת פרטי הכרטיס. ברגע שת×שר, פרטי הכרטיס ×©×œ× ×™×©×•×ª×¤×• ×¢× ×”×תר ×”×–×”.</translation>
<translation id="725866823122871198">×œ× × ×™×ª×Ÿ ליצור חיבור פרטי ×ל <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ×פני שהת××¨×™× ×•×”×©×¢×” (<ph name="DATE_AND_TIME" />) ב×חשב ×©×œ× ×©×’×•×™×™×.</translation>
-<translation id="7265986070661382626">×œ× × ×™×ª×Ÿ לבקר כעת ב-<ph name="SITE" /> ×כיוון שה×תר <ph name="BEGIN_LINK" />×שת×ש בהצ×דת ×ישורי×<ph name="END_LINK" />. שגי×ות רשת ותקיפות ×תרחשות ×‘×“×¨× ×›×œ×œ לז×ן ×וגבל, ×›× ×©×¡×‘×™×¨ להניח שהדף יפעל ××וחר יותר.</translation>
<translation id="7269802741830436641">דף ×ינטרנט ×–×” ×כיל לול×ת כתובת ×תר להפניה ×חדש</translation>
<translation id="7275334191706090484">סי×ניות ×נוהלות</translation>
<translation id="7298195798382681320">×ו×לצי×</translation>
-<translation id="7301833672208172928">הפעל סינכרון היסטוריה</translation>
+<translation id="7309308571273880165">דוח הקריסה תועד ב<ph name="CRASH_TIME" /> (×”×שת×ש ביקש העל××”, הדוח עדיין ×œ× ×”×•×¢×œ×”)</translation>
<translation id="7334320624316649418">&amp;ביצוע ×חדש של שינוי סדר</translation>
<translation id="733923710415886693">×ישור השרת ×œ× × ×—×©×£ ×“×¨× 'שקיפות ×ישורי×'.</translation>
+<translation id="7351800657706554155">×œ× × ×™×ª×Ÿ להיכנס כרגע ל×תר <ph name="SITE" /> ×›×™ ×”×ישור שלו בוטל. שגי×ות רשת ו×תקפות הן ×‘×“×¨× ×›×œ×œ ×–×ניות, ×›× ×©×”×“×£ ×”×–×” ככל הנר××” יחזור לפעול ××וחר יותר. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">שורת פקודה </translation>
<translation id="7372973238305370288">תוצ×ת חיפוש</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -546,16 +579,17 @@ Del</translation>
<translation id="7469372306589899959">××שר ×ת הכרטיס</translation>
<translation id="7481312909269577407">קדי××”</translation>
<translation id="7485870689360869515">×œ× × ×צ×ו נתוני×.</translation>
+<translation id="7508255263130623398">××–×”×” ×”×כשיר ב×דיניות שהוחזר ריק ×ו ש×ינו תו×× ×œ××–×”×” ×”×כשיר הנוכחי</translation>
<translation id="7514365320538308">הורד</translation>
<translation id="7518003948725431193">×œ× × ××¦× ×“×£ ×ינטרנט עבור כתובת ×”×ינטרנט: <ph name="URL" /></translation>
<translation id="7537536606612762813">הכרחי</translation>
<translation id="7542995811387359312">×ילוי ×וטו×טי של פרטי כרטיס ×שר××™ ×ושבת כיוון שטופס ×–×” ×ינו ×שת×ש בחיבור ××ובטח.</translation>
<translation id="7549584377607005141">דף ×ינטרנט ×–×” זקוק ×œ× ×ª×•× ×™× ×©×”×–× ×ª ×§×•×“× ×œ×›×Ÿ כדי ×©×”×•× ×™×•×¦×’ כר×וי. ×תה יכול לשלוח שוב ×ת הנתוני×, ×× ×¤×¢×•×œ×” זו ×ª×’×¨×•× ×œ×—×–×¨×” על כל פעולה שדף ×–×” ביצע בעבר.</translation>
<translation id="7554791636758816595">כרטיסייה חדשה</translation>
-<translation id="7567204685887185387">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />. ייתכן ש×ישור ×”×בטחה שלו נופק כהונ××”. הסיבה ×œ×›× ×¢×©×•×™×” להיות הגדרה שגויה ×ו תוקף ×”×יירט ×ת החיבור של×.</translation>
<translation id="7568593326407688803">זהו דף ב<ph name="ORIGINAL_LANGUAGE" />×”×× ×‘×¨×¦×•× × ×œ×ª×¨×’× ×ותו?</translation>
<translation id="7569952961197462199">â€×”×× ×œ×”×¡×™×¨ ×ת כרטיס ×”×שר××™ ×-Chrome?</translation>
<translation id="7578104083680115302">â€×©×œ× ב×הירות ב××ª×¨×™× ×•×‘×פליקציות בכל ×”××›×©×™×¨×™× ×‘××צעות ×›×¨×˜×™×¡×™× ×©×©×רת ב-Google.</translation>
+<translation id="7588950540487816470">×”×ינטרנט הווירטופיזי</translation>
<translation id="7592362899630581445">×ישור השרת ×פר ×ת ×ילוצי הש×ות.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ×œ× ×™×›×•×œ לטפל כרגע בבקשה הזו.</translation>
<translation id="7600965453749440009">×ל ×ª×ª×¨×’× ×œ×¢×•×œ× <ph name="LANGUAGE" /></translation>
@@ -566,6 +600,7 @@ Del</translation>
<translation id="7637571805876720304">â€×”×× ×œ×”×¡×™×¨ ×-Chromium ×ת כרטיס ×”×שר××™?</translation>
<translation id="765676359832457558">הסתר הגדרות ×תקד×ות...</translation>
<translation id="7658239707568436148">ביטול</translation>
+<translation id="7667346355482952095">×סי×ון ×”×דיניות שהוחזר ×”×•× ×¨×™×§ ×ו ש×ינו תו×× ×œ×סי×ון הנוכחי</translation>
<translation id="7668654391829183341">×כשיר ×œ× ×™×“×•×¢</translation>
<translation id="7674629440242451245">â€×עוניין בתכונות חדשות ו×גניבות של Chrome? נסה ×ת הערוץ שלנו ל××¤×ª×—×™× ×‘×›×ª×•×‘×ª chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />×”××©× ×ל <ph name="SITE" /> (×œ× ×‘×˜×•×—)<ph name="END_LINK" /></translation>
@@ -582,10 +617,10 @@ Del</translation>
<translation id="780301667611848630">×œ× ×ª×•×“×”</translation>
<translation id="7805768142964895445">סטטוס</translation>
<translation id="7813600968533626083">â€×”×× ×œ×”×¡×™×¨ ×-Chrome הצעות בשביל טפסי×?</translation>
+<translation id="7815407501681723534">× ×צ×ו <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ×‘× ×•×©× '<ph name="SEARCH_STRING" />'</translation>
<translation id="785549533363645510">×¢× ×–×ת, ××™× × ×‘×œ×ª×™ נר××”. ×”×עבר ל×צב גלישה בסתר ×œ× ×סתיר ×ת הגלישה ×©×œ× ××”×עסיק, ×ספק ×”×ינטרנט ×ו ××”××ª×¨×™× ×©××œ×™×”× ×תה נכנס.</translation>
<translation id="7887683347370398519">â€×‘דוק ×ת ×”-CVC ונסה שוב</translation>
<translation id="7894616681410591072">×ופס! ×תה ×¦×¨×™× ×ישור ×<ph name="NAME" /> כדי לגשת לדף ×”×–×”.</translation>
-<translation id="790025292736025802"><ph name="URL" /> ×œ× × ×צ×</translation>
<translation id="7912024687060120840">בתיקייה:</translation>
<translation id="7920092496846849526">ש×לת ×ת ×”×”×•×¨×™× ×× ×–×” בסדר להיכנס לדף ×–×”.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -598,9 +633,10 @@ Del</translation>
<translation id="7995512525968007366">×œ× ×¦×•×™×Ÿ</translation>
<translation id="8012647001091218357">×œ× ×”×¦×œ×—× ×• ליצור קשר ×¢× ×”×”×•×¨×™× ×©×œ×. נסה שוב ××וחר יותר.</translation>
<translation id="8034522405403831421">דף ×–×” ×וצג ב<ph name="SOURCE_LANGUAGE" />. ×”×× ×œ×ª×¨×’× ×ותו ל<ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">×œ× × ×צ×ו רשו×ות היסטוריה.</translation>
<translation id="8088680233425245692">הצגת הפריט נכשלה.</translation>
+<translation id="8089520772729574115">â€×¤×—ות ×-â€1 MB</translation>
<translation id="8091372947890762290">ההפעלה ××תינה בשרת</translation>
+<translation id="8129262335948759431">×¡×›×•× ×œ× ×™×“×•×¢</translation>
<translation id="8131740175452115882">×ישור</translation>
<translation id="8134994873729925007">â€×œ× ניתן ×”×™×” ל××¦×•× ×ת <ph name="BEGIN_ABBR" />כתובת ×”-DNS<ph name="END_ABBR" /> של השרת של <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">×”×חשב עבר ל×צב שינה.</translation>
@@ -609,6 +645,7 @@ Del</translation>
<translation id="8201077131113104583">כתובת ×תר ×œ× ×—×•×§×™×ª לעדכון עבור תוסף ×¢× ×”××–×”×” "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">××™×§×•× ×וקצה:</translation>
<translation id="8225771182978767009">×”××“× ×©×”×’×“×™×¨ ×ת ×”×חשב ×”×–×” בחר ×œ×—×¡×•× ×ת ×”×תר ×”×–×”.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">הדף ש×תה ×חפש השת×ש ב×ידע שהזנת. החזרה לדף ×–×” עלולה ×œ×’×¨×•× ×œ×›×¤×™×œ×•×ª בפעולות שביצעת. ×”×× ×‘×¨×¦×•× × ×œ×”×שי×?</translation>
<translation id="8249320324621329438">×וחזר ל×חרונה:</translation>
<translation id="8261506727792406068">×חק</translation>
@@ -621,12 +658,17 @@ Del</translation>
<translation id="8349305172487531364">סרגל סי×ניות</translation>
<translation id="8363502534493474904">לכבות ×ת ×צב הטיסה</translation>
<translation id="8364627913115013041">×œ× ×וגדר.</translation>
+<translation id="8380941800586852976">×סוכן</translation>
<translation id="8412145213513410671">קריסות (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">×¢×œ×™× ×œ×”×–×™×Ÿ ×ת ×ותו ×שפט-סיס××” פע××™×™×.</translation>
<translation id="8428213095426709021">הגדרות</translation>
+<translation id="8433057134996913067">פעולה זו ×ª×•×¦×™× ××•×ª× ×החשבון ברוב ×”×תרי×.</translation>
<translation id="8437238597147034694">&amp;ביטול העברה</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{כרטיס ×שר××™ ×חד}two{שני כרטיסי ×שר××™}many{# כרטיסי ×שר××™}other{# כרטיסי ×שר××™}}</translation>
+<translation id="8483780878231876732">â€×›×“×™ להשת×ש ×‘×›×¨×˜×™×¡×™× ×חשבון Google, היכנס ×ל Chrome</translation>
<translation id="8488350697529856933">חל על</translation>
<translation id="8498891568109133222">ל-<ph name="HOST_NAME" /> נדרש ×–×ן רב ×די להגיב.</translation>
+<translation id="852346902619691059">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ערכת ההפעלה של ×”×כשיר ×œ× ×¡×•×כת על ×ישור ×”×בטחה שלו. ייתכן שהסיבה ×œ×›× ×”×™× ×”×’×“×¨×” שגויה ×ו שתוקף ×יירט ×ת החיבור של×. <ph name="BEGIN_LEARN_MORE_LINK" />ל×ידע נוסף<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">â€×¡×•×’ הכרטיס ×”×–×” ×ינו נת×× ×¢×œ ידי Google Payments. בחר כרטיס ×חר.</translation>
<translation id="8550022383519221471">שירות הסינכרון ×ינו ×–×ין לדו×יין של×.</translation>
<translation id="8553075262323480129">×”×ª×¨×’×•× × ×›×©×œ כיוון ×©×œ× ×”×™×™×ª×” ×פשרות לקבוע ×ת שפת הדף.</translation>
@@ -638,15 +680,12 @@ Del</translation>
<translation id="8647750283161643317">×פס הכל לברירת ×”×חדל</translation>
<translation id="8680787084697685621">פרטי הכניסה לחשבון ××™× × ×עודכני×.</translation>
<translation id="8703575177326907206">ההתחברות ×©×œ× ×ל <ph name="DOMAIN" /> ××™× ×” ×וצפנת.</translation>
-<translation id="8713130696108419660">חתי××” ר×שונית פגו××”</translation>
<translation id="8725066075913043281">נסה שוב</translation>
<translation id="8728672262656704056">עברת ל×צב גלישה בסתר</translation>
<translation id="8730621377337864115">בוצע</translation>
<translation id="8738058698779197622">â€×›×“×™ ליצור חיבור ××ובטח, השעון ×¦×¨×™× ×œ×”×™×•×ª ×וגדר כהלכה. הסיבה ×œ×›× ×”×™× ×©×”××™×©×•×¨×™× ×©×‘×”× ××ª×¨×™× ×שת××©×™× ×›×“×™ לזהות ×ת עצ×× ×ª×§×¤×™× ×¨×§ ל××©× ×¤×¨×§×™ ×–×ן ×סוי××™×. ××חר שהשעון ב×כשיר ×©×œ× ×©×’×•×™, Chromium ×œ× ×™×›×•×œ ל××ת ×ת ×”××™×©×•×¨×™× ×”×לו.</translation>
<translation id="8740359287975076522">â€×œ× ניתן ×”×™×” ל××¦×•× ×ת &lt;abbr id="dnsDefinition"&gt;כתובת ×”-DNS&lt;/abbr&gt; של <ph name="HOST_NAME" />. ××בחן ×ת הבעיה.</translation>
-<translation id="8741995161408053644">â€×™×™×ª×›×Ÿ שתוכל לגשת ×œ×¡×•×’×™× ××—×¨×™× ×©×œ היסטוריית גלישה בחשבון Google בכתובת <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;ביצוע ×חדש של ×חיקה</translation>
-<translation id="8790687370365610530">â€×›×“×™ לקבל ×-Google ×”×לצות לתוכן ×ות×× ×ישית, הפעל ×ת סינכרון ההיסטוריה.</translation>
<translation id="8798099450830957504">ברירת ×חדל</translation>
<translation id="8804164990146287819">×דיניות פרטיות</translation>
<translation id="8820817407110198400">סי×ניות</translation>
@@ -668,13 +707,11 @@ Del</translation>
<translation id="8971063699422889582">פג תוקפו של ×ישור השרת.</translation>
<translation id="8987927404178983737">חודש</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">השרת הציג ×ישור ×©×œ× × ×—×©×£ ב×ופן ציבורי בעזרת ×דיניות 'שקיפות ×ישורי×'. זוהי דרישה עבור חלק ××”×ישורי×, ו×טרתה ×œ×•×•×“× ×©×”× ××”×™×× ×™× ×•×›×“×™ להגן ×פני תוקפי×.</translation>
<translation id="9001074447101275817">â€×©×¨×ª ×”-proxy â€<ph name="DOMAIN" /> ××¦×¨×™× ×©× ×שת×ש וסיס××”.</translation>
<translation id="901974403500617787">רק ×”×‘×¢×œ×™× ×™×›×•×œ להגדיר סי××•× ×™× ×”×—×œ×™× ×¢×œ כל ×”×ערכת: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">הדף ×”×–×” ×ª×•×¨×’× ×œ<ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">השת×ש בשירות חיזוי כדי לטעון ×“×¤×™× ×הר יותר</translation>
<translation id="9039213469156557790">×›×ו כן, דף ×–×” כולל ×ש××‘×™× × ×•×¡×¤×™× ×©××™× × ××ובטחי×. גור××™× ××—×¨×™× ×¢×œ×•×œ×™× ×œ×¨×ות ×ת ×”×ש××‘×™× ×”×לה ב××”×œ× ×”×¢×‘×¨×ª×, ותוקף עלול לשנות ××•×ª× ×‘×ופן שישנה ×ת התנהגות הדף.</translation>
-<translation id="9049981332609050619">ניסית להגיע ל-<ph name="DOMAIN" />, ×× ×”×©×¨×ª הציג ×ישור ×œ× ×—×•×§×™.</translation>
<translation id="9050666287014529139">×שפט-סיס××”</translation>
<translation id="9065203028668620118">ערו×</translation>
<translation id="9092364396508701805">הדף של <ph name="HOST_NAME" /> ×œ× ×¤×•×¢×œ</translation>
diff --git a/chromium/components/strings/components_strings_ja.xtb b/chromium/components/strings/components_strings_ja.xtb
index 233ee62c608..50fd76bb52a 100644
--- a/chromium/components/strings/components_strings_ja.xtb
+++ b/chromium/components/strings/components_strings_ja.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ja">
+<translation id="1008557486741366299">後ă§</translation>
<translation id="1015730422737071372">è©³ç´°ă‚’å ±å‘ă™ă‚‹</translation>
<translation id="1032854598605920125">時計å›ă‚ă«å›è»¢</translation>
<translation id="1038842779957582377">ä¸æ˜ăªåå‰</translation>
+<translation id="1053591932240354961"><ph name="SITE" /> ă‹ă‚‰ă€Google Chrome ă§å‡¦ç†ă§ăăªă„æ—å·åŒ–ă•ă‚ŒăŸèªè¨¼æƒ…å ±ăŒè¿”ă•ă‚ŒăŸăŸă‚ă€ç¾åœ¨ă“ă®ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă«ă¯ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“。é€å¸¸ă€ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼ă‚„ä¸æ­£ăªæ“作ă¯ä¸€æ™‚ç„ăªă‚‚ă®ă§ă™ă€‚å°‘ă—æ™‚é–“ă‚’ăăă¨ă€ăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă‚‹ă‚ˆă†ă«ăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">追å ă®å–ă‚消ă—(&amp;U)</translation>
<translation id="10614374240317010">未ä¿å­˜</translation>
-<translation id="1064422015032085147">ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸ă®ăƒ›ă‚¹ăƒˆă‚µăƒ¼ăƒăƒ¼ăŒăƒ“ă‚¸ăƒ¼ă§ă‚ă‚‹ă‹ăƒ¡ăƒ³ăƒ†ăƒăƒ³ă‚¹ä¸­ă®å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚
- é剰ăªăƒˆăƒ©ăƒ•ă‚£ăƒƒă‚¯ă«ă‚ˆă‚ç¶æ³ăŒæ‚ªåŒ–ă™ă‚‹ă®ă‚’防ăăŸă‚ă€ă“ă® URL ă¸ă®ăƒªă‚¯ă‚¨ă‚¹ăƒˆă¯
- 一時ç„ă«ç„¡å¹ă«ăªă£ă¦ă„ă¾ă™ă€‚</translation>
<translation id="106701514854093668">ăƒ‘ă‚½ă‚³ăƒ³ă®ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯</translation>
<translation id="1080116354587839789">ă‚¦ă‚£ăƒ³ăƒ‰ă‚¦å¹…ă«åˆă‚ă›ă‚‹</translation>
+<translation id="1103124106085518534">æ–°ă—ă„ă‚³ăƒ³ăƒ†ăƒ³ăƒ„ă¯ă‚ă‚ă¾ă›ă‚“</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" />ă‚’å¸¸ă«ç¿»è¨³</translation>
<translation id="1107591249535594099">ăƒă‚§ăƒƒă‚¯ăƒœăƒƒă‚¯ă‚¹ă‚’ă‚ªăƒ³ă«ă™ă‚‹ă¨ă€Chrome ă¯ăƒ•ă‚©ăƒ¼ăƒ ă«è¿…速ă«å…¥å›ă™ă‚‹ăŸă‚ă«ă€ă‚«ăƒ¼ăƒ‰æƒ…å ±ă®ă‚³ăƒ”ăƒ¼ă‚’ă“ă®ăƒ‡ăƒă‚¤ă‚¹ă«ä¿å­˜ă—ă¾ă™ă€‚</translation>
+<translation id="1111153019813902504">æœ€è¿‘ă‚¢ă‚¯ă‚»ă‚¹ă—ăŸăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯</translation>
<translation id="1113869188872983271">é †åºå¤‰æ›´ă®å–ă‚消ă—(&amp;U)</translation>
+<translation id="1126551341858583091">ăƒ­ăƒ¼ă‚«ăƒ« ă‚¹ăƒˆăƒ¬ăƒ¼ă‚¸ä¸ă®ă‚µă‚¤ă‚ºă¯ <ph name="CRASH_SIZE" /> ă§ă™ă€‚</translation>
<translation id="112840717907525620">ăƒăƒªă‚·ăƒ¼ ă‚­ăƒ£ăƒƒă‚·ăƒ¥ă¯æ­£å¸¸ă§ă™</translation>
<translation id="113188000913989374"><ph name="SITE" /> ă®å†…容:</translation>
<translation id="1132774398110320017">Chrome ă®è‡ªå‹•å…¥å›è¨­å®...</translation>
-<translation id="1150979032973867961">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ă€ă”使用ă®ăƒ‘ă‚½ă‚³ăƒ³ă®ă‚ªăƒăƒ¬ăƒ¼ăƒ†ă‚£ăƒ³ă‚° ă‚·ă‚¹ăƒ†ăƒ ă«ă‚ˆă£ă¦ä¿¡é ¼ă•ă‚Œă¦ă„ă‚‹ă‚‚ă®ă§ă¯ă‚ă‚ă¾ă›ă‚“。åŸå› ă¨ă—ă¦ă¯ă€ä¸é©åˆ‡ăªè¨­å®ă‚„ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă‚‹æ¥ç¶å¦¨å®³ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚</translation>
<translation id="1152921474424827756"><ph name="URL" /> ă®<ph name="BEGIN_LINK" />ă‚­ăƒ£ăƒƒă‚·ăƒ¥ ă‚³ăƒ”ăƒ¼<ph name="END_LINK" />ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă¾ă™</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ă«ă‚ˆă‚途中ă§æ¥ç¶ăŒåˆ‡æ–­ă•ă‚Œă¾ă—ăŸă€‚</translation>
<translation id="1161325031994447685">Wi-Fi ă«å†åº¦æ¥ç¶ă™ă‚‹</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">å‰é™¤</translation>
<translation id="1201402288615127009">次ă¸</translation>
<translation id="1201895884277373915">ă“ă®ă‚µă‚¤ăƒˆă‹ă‚‰ă®ä»–ă®å±¥æ­´</translation>
-<translation id="121201262018556460"><ph name="DOMAIN" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸè¨¼æ˜æ›¸ă«ă¯è„†å¼±ăªæ—å·éµăŒå«ă¾ă‚Œă¦ă„ă¾ă™ă€‚悪æ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă£ă¦ç§˜å¯†éµăŒç ´ă‚‰ă‚ŒăŸå¯èƒ½æ€§ăŒă‚ă‚ă€ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ăŸă‚µăƒ¼ăƒăƒ¼ă¨ă¯ç•°ăªă‚‹ă‚µăƒ¼ăƒăƒ¼ă§ă‚ă‚‹ăăă‚ŒăŒă‚ă‚ă¾ă™ï¼ˆæ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă¨é€ä¿¡ă—ă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ï¼‰ă€‚</translation>
+<translation id="1206967143813997005">最åˆă®ç½²åă«å•é¡ŒăŒă‚ă‚ă¾ă™</translation>
+<translation id="1209206284964581585">ä»ă¯è¡¨ç¤ºă—ăªă„</translation>
<translation id="1219129156119358924">ă‚·ă‚¹ăƒ†ăƒ  ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£</translation>
<translation id="1227224963052638717">ä¸æ˜ăªăƒăƒªă‚·ăƒ¼ă€‚</translation>
<translation id="1227633850867390598">å€¤ă‚’é表示</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">ă¯ă„</translation>
<translation id="1430915738399379752">å°åˆ·</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /><ph name="DOMAIN" /> ă®ăƒăƒ¼ă‚¸ă¸ă®ă‚¢ă‚¯ă‚»ă‚¹<ph name="END_LINK" />ăŒăƒ–ăƒ­ăƒƒă‚¯ă•ă‚Œă¾ă—ăŸă€‚</translation>
+<translation id="1491663344921578213"><ph name="SITE" /> ă§ă¯è¨¼æ˜æ›¸ă®ăƒ”ăƒ³ç•™ă‚ăŒä½¿ç”¨ă•ă‚Œă¦ă„ă‚‹ăŸă‚ă€ç¾åœ¨ă“ă®ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă«ă¯ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“。é€å¸¸ă€ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼ă‚„ä¸æ­£ăªæ“作ă¯ä¸€æ™‚ç„ăªă‚‚ă®ă§ă™ă€‚å°‘ă—æ™‚é–“ă‚’ăăă¨ă€ăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă‚‹ă‚ˆă†ă«ăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">ă“ă®ăƒăƒ¼ă‚¸ă®ä¿å­˜ă•ă‚Œă¦ă„ă‚‹ă‚³ăƒ”ăƒ¼ï¼ˆå¤ă„ăƒăƒ¼ă‚¸ăƒ§ăƒ³ï¼‰ă‚’表示ă—ă¾ă™ă€‚</translation>
<translation id="1519264250979466059">ăƒ“ăƒ«ăƒ‰æ—¥</translation>
<translation id="1549470594296187301">ă“ă®æ©Ÿèƒ½ă‚’使用ă™ă‚‹ă«ă¯ JavaScript ă‚’æœ‰å¹ă«ă™ă‚‹å¿…è¦ăŒă‚ă‚ă¾ă™ă€‚</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯è¨­å®ăŒç„¡å¹ăªăŸă‚ă‚¤ăƒ³ăƒăƒ¼ăƒˆă§ăă¾ă›ă‚“ă§ă—ăŸă€‚</translation>
<translation id="1644574205037202324">履歴</translation>
<translation id="1645368109819982629">サăƒăƒ¼ăƒˆă•ă‚Œă¦ă„ăªă„ăƒ—ăƒ­ăƒˆă‚³ăƒ«ă§ă™</translation>
-<translation id="1655462015569774233">{1,plural, =1{ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă®æœ‰å¹æœŸé™ăŒæ˜¨æ—¥ä»˜ă‘ă§åˆ‡ă‚Œă¦ă„ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚ăƒ‘ă‚½ă‚³ăƒ³ă®æ™‚計ă¯ç¾åœ¨ <ph name="CURRENT_DATE" />ă«è¨­å®ă•ă‚Œă¦ă„ă¾ă™ă€‚ă“ă®æ™‚刻ăŒæ­£ă—ăăªă„å ´åˆă¯ă€ă‚·ă‚¹ăƒ†ăƒ ă®æ™‚è¨ˆă‚’ä¿®æ­£ă—ăŸå¾Œă“ă®ăƒăƒ¼ă‚¸ă‚’æ›´æ–°ă—ă¦ăă ă•ă„。}other{ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă®æœ‰å¹æœŸé™ăŒ # æ—¥å‰ă«åˆ‡ă‚Œă¦ă„ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚ăƒ‘ă‚½ă‚³ăƒ³ă®æ™‚計ă¯ç¾åœ¨ <ph name="CURRENT_DATE" />ă«è¨­å®ă•ă‚Œă¦ă„ă¾ă™ă€‚ă“ă®æ™‚刻ăŒæ­£ă—ăăªă„å ´åˆă¯ă€ă‚·ă‚¹ăƒ†ăƒ ă®æ™‚è¨ˆă‚’ä¿®æ­£ă—ăŸå¾Œă“ă®ăƒăƒ¼ă‚¸ă‚’æ›´æ–°ă—ă¦ăă ă•ă„。}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> ă§ă¯é€å¸¸ă€æ—å·åŒ–ă—ă¦æƒ…å ±ă‚’ä¿è­·ă—ă¦ă„ă¾ă™ă€‚ä»å›ă€Google Chrome ă‹ă‚‰ <ph name="SITE" /> ă¸ă®æ¥ç¶è©¦è¡Œæ™‚ă«ă€ă“ă®ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă‹ă‚‰ă„ă¤ă‚‚ă¨ă¯ç•°ăªă‚‹èª¤ă£ăŸèªè¨¼æƒ…å ±ăŒè¿”ă•ă‚Œă¾ă—ăŸă€‚悪æ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒ <ph name="SITE" /> ă«ăªă‚ă™ă¾ăă†ă¨ă—ă¦ă„ă‚‹ă‹ă€Wi-Fi ăƒ­ă‚°ă‚¤ăƒ³ç”»é¢ă§æ¥ç¶ăŒä¸­æ–­ă•ă‚ŒăŸå¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚ăƒ‡ăƒ¼ă‚¿ă®ă‚„ă‚å–ă‚ăŒè¡Œă‚ă‚Œă‚‹å‰ă« Google Chrome ă«ă‚ˆă£ă¦æ¥ç¶ăŒåœæ­¢ă•ă‚ŒăŸăŸă‚ă€æƒ…å ±ă¯å¼•ăç¶ăä¿è­·ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="168841957122794586">ă‚µăƒ¼ăƒăƒ¼è¨¼æ˜æ›¸ă«è„†å¼±ăªæ—å·éµăŒå«ă¾ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="1701955595840307032">ăă™ă™ă‚ă‚³ăƒ³ăƒ†ăƒ³ăƒ„ă‚’è¡¨ç¤º</translation>
-<translation id="1706954506755087368">{1,plural, =1{ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ăăらăæ˜æ—¥ä»¥é™ă«åˆ©ç”¨ă§ăă‚‹ă‚ˆă†ă«ăªă‚ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚}other{ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ăăらă # 日後ă‹ă‚‰åˆ©ç”¨ă§ăă‚‹ă‚ˆă†ă«ăªă‚ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">AMEX</translation>
<translation id="1734878702283171397">ă‚·ă‚¹ăƒ†ăƒ ç®¡ç†è€…ă«ăå•ă„åˆă‚ă›ăă ă•ă„。</translation>
<translation id="17513872634828108">é–‹ă„ă¦ă„ă‚‹ă‚¿ăƒ–</translation>
<translation id="1753706481035618306">ăƒăƒ¼ă‚¸ç•ªå·</translation>
-<translation id="1761412452051366565">ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«åˆă‚ă›ăŸ Google ă‹ă‚‰ă®ăă™ă™ă‚ă‚³ăƒ³ăƒ†ăƒ³ăƒ„ă‚’è¡¨ç¤ºă™ă‚‹ă«ă¯ă€åŒæœŸă‚’有å¹ă«ă—ă¾ă™ă€‚</translation>
-<translation id="1763864636252898013">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ă€ă”使用ă®ăƒ‡ăƒă‚¤ă‚¹ă®ă‚ªăƒăƒ¬ăƒ¼ăƒ†ă‚£ăƒ³ă‚° ă‚·ă‚¹ăƒ†ăƒ ă«ă‚ˆă£ă¦ä¿¡é ¼ă•ă‚Œă¦ă„ă‚‹ă‚‚ă®ă§ă¯ă‚ă‚ă¾ă›ă‚“。åŸå› ă¨ă—ă¦ă¯ă€ä¸é©åˆ‡ăªè¨­å®ă‚„ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă‚‹æ¥ç¶å¦¨å®³ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯è¨ºæ–­ăƒ„ăƒ¼ăƒ«ă‚’å®Ÿè¡Œă—ă¦ă¿ă¦ăă ă•ă„<ph name="END_LINK" />。</translation>
<translation id="1783075131180517613">åŒæœŸăƒ‘ă‚¹ăƒ•ăƒ¬ăƒ¼ă‚ºă‚’æ›´æ–°ă—ă¦ăă ă•ă„。</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">æœ€è¿‘ă‚¢ă‚¯ă‚»ă‚¹ă—ăŸăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯ăŒă“ă“ă«è¡¨ç¤ºă•ă‚Œă¾ă™ă€‚</translation>
<translation id="1821930232296380041">ç„¡å¹ăªăƒªă‚¯ă‚¨ă‚¹ăƒˆă¾ăŸă¯ăƒªă‚¯ă‚¨ă‚¹ăƒˆ ăƒ‘ăƒ©ăƒ¡ăƒ¼ă‚¿ă§ă™</translation>
<translation id="1838667051080421715">ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸ă®ă‚½ăƒ¼ă‚¹ă‚’表示ă—ă¦ă„ă¾ă™ă€‚</translation>
<translation id="1871208020102129563">ăƒ—ăƒ­ă‚­ă‚·ă¯ .pac ă‚¹ă‚¯ăƒªăƒ—ăƒˆ URL ă§ă¯ăªă固å®ăƒ—ăƒ­ă‚­ă‚· ă‚µăƒ¼ăƒăƒ¼ă‚’使用ă™ă‚‹ă‚ˆă†ă«è¨­å®ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="1883255238294161206">ăƒªă‚¹ăƒˆă‚’æ˜ă‚ăŸăŸă‚€</translation>
<translation id="1898423065542865115">ăƒ•ă‚£ăƒ«ă‚¿</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> ă§ăƒ­ă‚°ă‚¤ăƒ³è¨¼æ˜æ›¸ăŒæ‰¿èªă•ă‚Œăªă‹ă£ăŸă€ă¾ăŸă¯ăƒ­ă‚°ă‚¤ăƒ³è¨¼æ˜æ›¸ă®æœ‰å¹æœŸé™ăŒåˆ‡ă‚Œă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="194030505837763158"><ph name="LINK" /> ă«ç§»å‹•ă—ă¾ă™</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> ă®ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯</translation>
<translation id="1973335181906896915">ă‚·ăƒªă‚¢ăƒ«åŒ–ă‚¨ăƒ©ăƒ¼ă§ă™</translation>
<translation id="1974060860693918893">詳細設å®</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{他 1 個}other{他 # 個}}</translation>
<translation id="2025186561304664664">ăƒ—ăƒ­ă‚­ă‚·ă¯è‡ªå‹•è¨­å®ă«ăªă£ă¦ă„ă¾ă™ă€‚</translation>
<translation id="2030481566774242610">ă‚‚ă—ă‹ă—ă¦: <ph name="LINK" /></translation>
<translation id="2031925387125903299">æ–°ă—ă„ă‚µă‚¤ăƒˆă«åˆă‚ă¦è¨ªå•ă™ă‚‹é›ă¯ä¿è­·è€…ă®æ‰¿èªăŒå¿…è¦ă§ă™ă€‚</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />ăƒ—ăƒ­ă‚­ă‚·ă¨ăƒ•ă‚¡ă‚¤ă‚¢ă‚¦ă‚©ăƒ¼ăƒ«ă‚’確èªă™ă‚‹<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">郵便番å·</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 件ă®å€™è£œ}other{# 件ă®å€™è£œ}}</translation>
<translation id="2065985942032347596">èªè¨¼ăŒå¿…è¦</translation>
<translation id="2079545284768500474">å–ă‚消ă™</translation>
<translation id="20817612488360358">ă‚·ă‚¹ăƒ†ăƒ  ăƒ—ăƒ­ă‚­ă‚·è¨­å®ă‚’使用ă™ă‚‹ă‚ˆă†ă«è¨­å®ă•ă‚Œă¦ă„ă¾ă™ăŒă€æ˜ç¤ºç„ăªăƒ—ăƒ­ă‚­ă‚·ă®è¨­å®ă‚‚指å®ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯ă‚’編集</translation>
<translation id="2166049586286450108">ă™ă¹ă¦ă®ăƒ‡ăƒ¼ă‚¿ă¸ă®ç®¡ç†è€…ă‚¢ă‚¯ă‚»ă‚¹</translation>
<translation id="2166378884831602661">ă“ă®ă‚µă‚¤ăƒˆă¯å®‰å…¨ă«æ¥ç¶ă§ăă¾ă›ă‚“</translation>
-<translation id="2171101176734966184"><ph name="DOMAIN" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸè¨¼æ˜æ›¸ă¯è„†å¼±ăªç½²åă‚¢ăƒ«ă‚´ăƒªă‚ºăƒ ă‚’ä½¿ç”¨ă—ă¦ç½²åă•ă‚Œă¦ă„ă¾ă™ă€‚ă“ă‚Œă¯ă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£èªè¨¼æƒ…å ±ăŒå½è£…ă•ă‚Œă¦ă„ă‚‹å¯èƒ½æ€§ă‚’示ă—ă¦ăă‚ă€ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ăŸă‚µăƒ¼ăƒăƒ¼ă¨ă¯ç•°ăªă‚‹ă‚µăƒ¼ăƒăƒ¼ă§ă‚ă‚‹ăăă‚ŒăŒă‚ă‚ă¾ă™ï¼ˆæ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă¨é€ä¿¡ă—ă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ï¼‰ă€‚</translation>
<translation id="2181821976797666341">ăƒăƒªă‚·ăƒ¼</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 件ă®ă‚¢ăƒ‰ăƒ¬ă‚¹}other{# 件ă®ă‚¢ăƒ‰ăƒ¬ă‚¹}}</translation>
<translation id="2212735316055980242">ăƒăƒªă‚·ăƒ¼ăŒè¦‹ă¤ă‹ă‚ă¾ă›ă‚“</translation>
<translation id="2213606439339815911">ă‚¨ăƒ³ăƒˆăƒªă‚’å–å¾—ă—ă¦ă„ă¾ă™...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> ă«æ¥ç¶ă§ăă¾ă›ă‚“</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />è¨ºæ–­ă‚¢ăƒ—ăƒª<ph name="END_LINK" />ă‚’ä½¿ç”¨ă—ă¦æ¥ç¶ă‚’修正ă—ă¦ăă ă•ă„</translation>
+<translation id="2239100178324503013">é€ä¿¡</translation>
<translation id="225207911366869382">ă“ă®å€¤ă¯ă€ă“ă®ăƒăƒªă‚·ăƒ¼ă§ă¯ă‚µăƒăƒ¼ăƒˆăŒçµ‚了ă—ă¦ă„ă¾ă™ă€‚</translation>
<translation id="2262243747453050782">HTTP ă‚¨ăƒ©ăƒ¼ă§ă™</translation>
<translation id="2282872951544483773">利用ă§ăăªă„試験é‹ç”¨æ©Ÿèƒ½</translation>
<translation id="2292556288342944218">ă‚¤ăƒ³ă‚¿ăƒ¼ăƒăƒƒăƒˆ ă‚¢ă‚¯ă‚»ă‚¹ăŒăƒ–ăƒ­ăƒƒă‚¯ă•ă‚Œă¦ă„ă¾ă™</translation>
<translation id="229702904922032456">ăƒ«ăƒ¼ăƒˆè¨¼æ˜æ›¸ă¾ăŸă¯ä¸­é–“証æ˜æ›¸ă®æœŸé™ăŒåˆ‡ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="230155334948463882">ă‚«ăƒ¼ăƒ‰æƒ…å ±ă‚’æ›´æ–°</translation>
+<translation id="2305919008529760154">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ä¸æ­£ă«ç™ºè¡Œă•ă‚ŒăŸă‚‚ă®ă§ă‚ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> ă«ă¯ăƒ¦ăƒ¼ă‚¶ăƒ¼åă¨ăƒ‘ă‚¹ăƒ¯ăƒ¼ăƒ‰ăŒå¿…è¦ă§ă™ă€‚</translation>
+<translation id="2318774815570432836"><ph name="SITE" /> ă§ă¯ HSTS ăŒä½¿ç”¨ă•ă‚Œă¦ă„ă‚‹ăŸă‚ă€ç¾åœ¨ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“。é€å¸¸ă€ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼ă‚„ä¸æ­£ăªæ“作ă¯ä¸€æ™‚ç„ăªă‚‚ă®ă§ă™ă€‚å°‘ă—æ™‚é–“ă‚’ăăă¨ă€ă¾ăŸăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă‚‹ă‚ˆă†ă«ăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">ă‚¤ăƒ³ăƒ‡ăƒƒă‚¯ă‚¹ <ph name="ENTRY_INDEX" /> ă®ç„¡å¹ăªăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯ă‚’無視ă—ă¾ă—ăŸ</translation>
<translation id="2354001756790975382">ăă®ä»–ă®ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯</translation>
<translation id="2359808026110333948">ç¶è¡Œ</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" /> ă«ä½œæˆă•ă‚ŒăŸă‚¯ăƒ©ăƒƒă‚·ăƒ¥ ăƒ¬ăƒăƒ¼ăƒˆă¯ă‚¢ăƒƒăƒ—ăƒ­ăƒ¼ăƒ‰ă•ă‚Œă¾ă›ă‚“ă§ă—ăŸ</translation>
<translation id="2367567093518048410">ăƒ¬ăƒ™ăƒ«</translation>
+<translation id="2371153335857947666">{1,plural, =1{ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă®æœ‰å¹æœŸé™ăŒæ˜¨æ—¥ä»˜ă‘ă§åˆ‡ă‚Œă¦ă„ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚ăƒ‘ă‚½ă‚³ăƒ³ă®æ™‚計ă¯ç¾åœ¨ <ph name="CURRENT_DATE" />ă«è¨­å®ă•ă‚Œă¦ă„ă¾ă™ă€‚ă“ă®æ™‚刻ăŒæ­£ă—ăăªă„å ´åˆă¯ă€ă‚·ă‚¹ăƒ†ăƒ ă®æ™‚è¨ˆă‚’ä¿®æ­£ă—ă¦ă€ă“ă®ăƒăƒ¼ă‚¸ă‚’æ›´æ–°ă—ă¦ăă ă•ă„。<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" />}other{ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă®æœ‰å¹æœŸé™ăŒ # æ—¥å‰ă«åˆ‡ă‚Œă¦ă„ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚ăƒ‘ă‚½ă‚³ăƒ³ă®æ™‚計ă¯ç¾åœ¨ <ph name="CURRENT_DATE" />ă«è¨­å®ă•ă‚Œă¦ă„ă¾ă™ă€‚ă“ă®æ™‚刻ăŒæ­£ă—ăăªă„å ´åˆă¯ă€ă‚·ă‚¹ăƒ†ăƒ ă®æ™‚è¨ˆă‚’ä¿®æ­£ă—ă¦ă€ă“ă®ăƒăƒ¼ă‚¸ă‚’æ›´æ–°ă—ă¦ăă ă•ă„。<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">ä»£æ›¿ăƒ¦ăƒ¼ă‚¶ăƒ¼ă‚¤ăƒ³ă‚¿ăƒ¼ăƒ•ă‚§ăƒ¼ă‚¹ă¯ă‚ă‚ă¾ă›ă‚“</translation>
<translation id="2384307209577226199">ä¼æ¥­ă®ăƒ‡ăƒ•ă‚©ăƒ«ăƒˆ</translation>
-<translation id="238526402387145295"><ph name="SITE" /> ă§ă¯ <ph name="BEGIN_LINK" />HSTS ăŒä½¿ç”¨ă•ă‚Œă¦ă„ă‚‹<ph name="END_LINK" />ăŸă‚ă€ç¾åœ¨ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“。é€å¸¸ă€ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼ă‚„ä¸æ­£ăªæ“作ă¯ä¸€æ™‚ç„ăªă‚‚ă®ă§ă™ă€‚å°‘ă—æ™‚é–“ă‚’ăăă¨ă€ă¾ăŸăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă‚‹ă‚ˆă†ă«ăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="2386255080630008482">ă‚µăƒ¼ăƒăƒ¼ă®è¨¼æ˜æ›¸ă¯å–ă‚消ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="2392959068659972793">値ăŒè¨­å®ă•ă‚Œă¦ă„ăªă„ăƒăƒªă‚·ăƒ¼ă‚’表示ă™ă‚‹</translation>
<translation id="2396249848217231973">å‰é™¤ă®å–ă‚消ă—(&amp;U)</translation>
-<translation id="2413528052993050574">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯å–ă‚消ă•ă‚Œă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă¯ă€ä¸é©åˆ‡ăªè¨­å®ă‚„ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă‚‹æ¥ç¶å¦¨å®³ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚</translation>
<translation id="2455981314101692989">ă“ă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸ă§ă¯ă€ăƒ•ă‚©ăƒ¼ăƒ ă¸ă®è‡ªå‹•å…¥å›ăŒç„¡å¹ă«ăªă£ă¦ă„ă¾ă™ă€‚</translation>
+<translation id="2463739503403862330">å…¥å›ă™ă‚‹</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯è¨ºæ–­ăƒ„ăƒ¼ăƒ«ă‚’å®Ÿè¡Œă™ă‚‹<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">検索 URL ăŒç„¡å¹ă§ă™ă€‚</translation>
<translation id="2491120439723279231">ă‚µăƒ¼ăƒăƒ¼ă®è¨¼æ˜æ›¸ă«ă‚¨ăƒ©ăƒ¼ăŒă‚ă‚ă¾ă™ă€‚</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">é€ä¿¡</translation>
<translation id="2674170444375937751">履歴ă‹ă‚‰ă“ă‚Œă‚‰ă®ăƒăƒ¼ă‚¸ă‚’å‰é™¤ă—ă¦ă‚‚ă‚ˆă‚ă—ă„ă§ă™ă‹ï¼Ÿ</translation>
<translation id="2677748264148917807">ă“ă®ăƒăƒ¼ă‚¸ă‚’é›¢ă‚Œă‚‹</translation>
+<translation id="269990154133806163">ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸè¨¼æ˜æ›¸ă¯ă€è¨¼æ˜æ›¸ă®é€æ˜æ€§ăƒăƒªă‚·ăƒ¼ă‚’介ă—ă¦å…¬é–‹ă•ă‚Œă¦ă„ă¾ă›ă‚“ă€‚ä¸€éƒ¨ă®è¨¼æ˜æ›¸ă¯ă€ä¿¡é ¼æ€§ă®ç¢ºä¿ă¨æ”»æ’ƒè€…ă‹ă‚‰ă®ä¿è­·ă®ăŸă‚ă€è¨¼æ˜æ›¸ă®é€æ˜æ€§ăƒăƒªă‚·ăƒ¼ă‚’介ă—ă¦å…¬é–‹ă•ă‚Œă‚‹ă“ă¨ăŒè¦ä»¶ă¨ăªă£ă¦ă„ă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">値ăŒæœ‰å¹ăªå½¢å¼ă§ă¯ă‚ă‚ă¾ă›ă‚“。</translation>
<translation id="2704951214193499422">Chromium ă§ă‚«ăƒ¼ăƒ‰ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă—ă°ă‚‰ăă—ă¦ă‹ă‚‰ă‚‚ă†ä¸€åº¦ă試ă—ăă ă•ă„。</translation>
<translation id="2705137772291741111">ă“ă®ă‚µă‚¤ăƒˆă®ä¿å­˜ï¼ˆă‚­ăƒ£ăƒƒă‚·ăƒ¥ï¼‰ă•ă‚ŒăŸă‚³ăƒ”ăƒ¼ă‚’èª­ă¿å–ă‚Œă¾ă›ă‚“ă§ă—ăŸă€‚</translation>
<translation id="2709516037105925701">自動入å›</translation>
+<translation id="2712118517637785082"><ph name="DOMAIN" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸè¨¼æ˜æ›¸ă¯ç™ºè¡Œå…ƒă«ă‚ˆă‚å–ă‚消ă•ă‚Œă¦ă„ă¾ă™ă€‚ă“ă‚Œă¯ă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£èªè¨¼æƒ…å ±ăŒä¿¡é ¼ă§ăăªă„ă“ă¨ă‚’示ă—ă¦ăă‚ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă¨é€ä¿¡ă—ă‚ˆă†ă¨ă—ă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">権é™ă‚’ăƒªă‚¯ă‚¨ă‚¹ăƒˆ</translation>
<translation id="2721148159707890343">ăƒªă‚¯ă‚¨ă‚¹ăƒˆă‚’æ­£å¸¸ă«é€ä¿¡ă—ă¾ă—ăŸ</translation>
<translation id="2728127805433021124">ă‚µăƒ¼ăƒăƒ¼ă®è¨¼æ˜æ›¸ă¯è„†å¼±ăªç½²åă‚¢ăƒ«ă‚´ăƒªă‚ºăƒ ă‚’ä½¿ç”¨ă—ă¦ç½²åă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">ă‚¢ăƒ‰ăƒ¬ă‚¹æ¤œç´¢ăƒăƒ¼</translation>
<translation id="2826760142808435982">æ¥ç¶ă¯ <ph name="CIPHER" /> ă‚’ä½¿ç”¨ă—ă¦æ—å·åŒ–ăă‚ˆă³èªè¨¼ă•ă‚Œă¦ăă‚ă€<ph name="KX" /> ăŒéµäº¤æ›ăƒ¡ă‚«ăƒ‹ă‚ºăƒ ă¨ă—ă¦ä½¿ç”¨ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="2835170189407361413">ăƒ•ă‚©ăƒ¼ăƒ ă‚’ă‚¯ăƒªă‚¢</translation>
-<translation id="2837049386027881519">æ—§ăƒăƒ¼ă‚¸ăƒ§ăƒ³ă® TLS ă¾ăŸă¯ SSL ăƒ—ăƒ­ăƒˆă‚³ăƒ«ă§æ¥ç¶ă‚’å†è©¦è¡Œă™ă‚‹å¿…è¦ăŒă‚ă‚ă¾ă—ăŸă€‚ă“ă‚Œă¯é€å¸¸ă€ă‚µăƒ¼ăƒăƒ¼ă®ă‚½ăƒ•ăƒˆă‚¦ă‚§ă‚¢ăŒé常ă«å¤ăă€ä»–ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£å•é¡ŒăŒç™ºç”Ÿă—ă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚‹ă¨ă„ă†ă“ă¨ă§ă™ă€‚</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> ă®ă‚µăƒ¼ăƒăƒ¼è¨¼æ˜æ›¸ă¯å½é€ ă•ă‚ŒăŸă‚‚ă®ă®ă‚ˆă†ă§ă™ă€‚</translation>
<translation id="2889159643044928134">å†èª­ă¿è¾¼ă¿ă‚’中止</translation>
-<translation id="2896499918916051536">ă“ă®ăƒ—ăƒ©ă‚°ă‚¤ăƒ³ă¯ă‚µăƒăƒ¼ăƒˆă•ă‚Œă¦ă„ă¾ă›ă‚“。</translation>
+<translation id="2900469785430194048">ă“ă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸ă‚’表示ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€Google Chrome ă®ăƒ¡ăƒ¢ăƒªăŒä¸è¶³ă—ă¦ă„ă¾ă™ă€‚</translation>
<translation id="2909946352844186028">ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ă®å¤‰æ›´ăŒæ¤œå‡ºă•ă‚Œă¾ă—ăŸă€‚</translation>
-<translation id="2915500479781995473">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă®æœŸé™ăŒåˆ‡ă‚Œă¦ă„ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚ăƒ‘ă‚½ă‚³ăƒ³ă®æ™‚計ă¯ç¾åœ¨ <ph name="CURRENT_TIME" /> ă«è¨­å®ă•ă‚Œă¦ă„ă¾ă™ă€‚ă“ă®æ™‚刻ăŒæ­£ă—ăăªă„å ´åˆă¯ă€ă‚·ă‚¹ăƒ†ăƒ ă®æ™‚è¨ˆă‚’ä¿®æ­£ă—ă¦ă€ă“ă®ăƒăƒ¼ă‚¸ă‚’æ›´æ–°ă—ă¦ăă ă•ă„。</translation>
<translation id="2922350208395188000">ă‚µăƒ¼ăƒăƒ¼ă®è¨¼æ˜æ›¸ă‚’確èªă§ăă¾ă›ă‚“。</translation>
-<translation id="2941952326391522266">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ <ph name="DOMAIN2" /> ă‹ă‚‰ç™ºè¡Œă•ă‚Œă¦ă„ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă¯ă€ä¸é©åˆ‡ăªè¨­å®ă‚„ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă‚‹æ¥ç¶å¦¨å®³ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚</translation>
<translation id="2948083400971632585">æ¥ç¶ç”¨ă«è¨­å®ă•ă‚ŒăŸăƒ—ăƒ­ă‚­ă‚·ă¯ă€è¨­å®ăƒăƒ¼ă‚¸ă§ç„¡å¹ă«ă§ăă¾ă™ă€‚</translation>
<translation id="2955913368246107853">検索ăƒăƒ¼ă‚’é–‰ă˜ă‚‹</translation>
<translation id="2958431318199492670">ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯è¨­å®ăŒ ONC 標準ă«æº–æ‹ ă—ă¦ă„ă¾ă›ă‚“ă€‚è¨­å®ă®ä¸€éƒ¨ăŒă‚¤ăƒ³ăƒăƒ¼ăƒˆă•ă‚Œăªă„å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">ăƒăƒªă‚·ăƒ¼ ă‚¿ă‚¤ăƒ—ăŒé–“é•ă£ă¦ă„ă¾ă™</translation>
<translation id="3032412215588512954">ă“ă®ă‚µă‚¤ăƒˆă‚’å†èª­ă¿è¾¼ă¿ă—ă¾ă™ă‹ï¼Ÿ</translation>
<translation id="3037605927509011580">ă‚¨ăƒ©ăƒ¼</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{åŒæœŸăƒ‡ăƒă‚¤ă‚¹ă§ 1 件以ä¸ă®ă‚¢ă‚¤ăƒ†ăƒ }=1{1 件ă®ă‚¢ă‚¤ăƒ†ăƒ ï¼ˆåŒæœŸăƒ‡ăƒă‚¤ă‚¹ă§ă¯ăă‚Œä»¥ä¸ă®ă‚¢ă‚¤ăƒ†ăƒ ï¼‰}other{# 件ă®ă‚¢ă‚¤ăƒ†ăƒ ï¼ˆåŒæœŸăƒ‡ăƒă‚¤ă‚¹ă§ă¯ăă‚Œä»¥ä¸ă®ă‚¢ă‚¤ăƒ†ăƒ ï¼‰}}</translation>
<translation id="3041612393474885105">証æ˜æ›¸æƒ…å ±</translation>
<translation id="3063697135517575841">Chrome ă§ă‚«ăƒ¼ăƒ‰ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă—ă°ă‚‰ăă—ă¦ă‹ă‚‰ă‚‚ă†ä¸€åº¦ă試ă—ăă ă•ă„。</translation>
<translation id="3093245981617870298">ç¾åœ¨ă‚ªăƒ•ăƒ©ă‚¤ăƒ³ă§ă™ă€‚</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">最新</translation>
<translation id="3207960819495026254">ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯ă—ă¾ă—ăŸ</translation>
-<translation id="3225919329040284222">ă‚µăƒ¼ăƒăƒ¼ă®æ示ă—ăŸè¨¼æ˜æ›¸ăŒă€çµ„ă¿è¾¼ă¾ă‚Œă¦ă„ă‚‹æƒ³å®ă®è¨¼æ˜æ›¸ă¨ä¸€è‡´ă—ă¾ă›ă‚“。ă“ă‚Œă‚‰ă®æƒ³å®ă®è¨¼æ˜æ›¸ă¯ă€ăƒ¦ăƒ¼ă‚¶ăƒ¼ä¿è­·ă®ăŸă‚ă€ç‰¹å®ă®å®‰å…¨æ€§ă®é«˜ă„ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă«ă¤ă„ă¦ç”¨æ„ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="3226128629678568754">ăƒăƒ¼ă‚¸ă®èª­ă¿è¾¼ă¿ă«å¿…è¦ăªăƒ‡ăƒ¼ă‚¿ă‚’å†é€ä¿¡ă™ă‚‹ă«ă¯ă€å†èª­ă¿è¾¼ă¿ăƒœă‚¿ăƒ³ă‚’æ¼ă—ă¦ăă ă•ă„。</translation>
<translation id="3228969707346345236">ă“ă®ăƒăƒ¼ă‚¸ă¯æ—¢ă«<ph name="LANGUAGE" />ăªă®ă§ă€ç¿»è¨³ă§ăă¾ă›ă‚“。</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" /> ă® CVC ă‚’å…¥å›</translation>
<translation id="3254409185687681395">ă“ă®ăƒăƒ¼ă‚¸ă‚’ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯ă«è¿½å ă—ă¾ă™</translation>
<translation id="3270847123878663523">é †åºå¤‰æ›´ă®å–ă‚消ă—(&amp;U)</translation>
<translation id="3286538390144397061">ä»ă™ăå†èµ·å‹•</translation>
+<translation id="3303855915957856445">一致ă™ă‚‹çµæœă¯è¦‹ă¤ă‹ă‚ă¾ă›ă‚“ă§ă—ăŸ</translation>
<translation id="3305707030755673451">ăƒ‡ăƒ¼ă‚¿ă¯ <ph name="TIME" /> ă«åŒæœŸăƒ‘ă‚¹ăƒ•ăƒ¬ăƒ¼ă‚ºă§æ—å·åŒ–ă•ă‚Œă¾ă—ăŸă€‚åŒæœŸă‚’開始ă™ă‚‹ă«ă¯ă€åŒæœŸăƒ‘ă‚¹ăƒ•ăƒ¬ăƒ¼ă‚ºă‚’å…¥å›ă—ă¦ăă ă•ă„。</translation>
<translation id="333371639341676808">ă“ă®ăƒăƒ¼ă‚¸ă§ă“ă‚Œä»¥ä¸ăƒ€ă‚¤ă‚¢ăƒ­ă‚°ăƒœăƒƒă‚¯ă‚¹ă‚’生æˆă—ăªă„</translation>
+<translation id="3338095232262050444">ä¿è­·ă•ă‚ŒăŸé€ä¿¡</translation>
<translation id="3340978935015468852">設å®</translation>
<translation id="3345135638360864351">ă“ă®ă‚µă‚¤ăƒˆă«ă‚¢ă‚¯ă‚»ă‚¹ă™ă‚‹ăŸă‚ă®ăƒªă‚¯ă‚¨ă‚¹ăƒˆă‚’ <ph name="NAME" /> ă«é€ä¿¡ă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚‚ă†ä¸€åº¦ă試ă—ăă ă•ă„。</translation>
<translation id="3355823806454867987">ăƒ—ăƒ­ă‚­ă‚·è¨­å®ă®å¤‰æ›´...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">å–å¾—é–“é”:</translation>
<translation id="3462200631372590220">è©³ç´°æƒ…å ±ă‚’è¡¨ç¤ºă—ăªă„</translation>
<translation id="3479539252931486093">想å®å¤–ă®å‹•ä½œă§ă‚ă‚‹å ´åˆă¯ă€<ph name="BEGIN_LINK" />å•é¡Œă‚’å ±å‘<ph name="END_LINK" />ă—ă¦ăă ă•ă„。</translation>
+<translation id="3479552764303398839">後ă§</translation>
<translation id="348000606199325318">ă‚¯ăƒ©ăƒƒă‚·ăƒ¥ ID <ph name="CRASH_LOCAL_ID" />ï¼ˆă‚µăƒ¼ăƒăƒ¼ ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">ç¾åœ¨ă€ä¿è­·è€…ă«ăŸăă­ă‚‹ă“ă¨ăŒă§ăă¾ă›ă‚“。もă†ä¸€åº¦ă試ă—ăă ă•ă„。</translation>
<translation id="3527085408025491307">ăƒ•ă‚©ăƒ«ăƒ€</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">次ă®ăƒ‘ă‚¹ăƒ¯ăƒ¼ăƒ‰ă‚’ä½¿ç”¨:</translation>
<translation id="3549644494707163724">åŒæœŸăƒ‘ă‚¹ăƒ•ăƒ¬ăƒ¼ă‚ºă§åŒæœŸăƒ‡ăƒ¼ă‚¿ă‚’ă™ă¹ă¦æ—å·åŒ–ă™ă‚‹</translation>
<translation id="3549761410225185768">ä»– <ph name="NUM_TABS_MORE" /> 個ă®ă‚¿ăƒ–...</translation>
+<translation id="3555561725129903880">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ <ph name="DOMAIN2" /> ă‹ă‚‰ç™ºè¡Œă•ă‚Œă¦ă„ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">ă“ă®æ¥ç¶ă§ă¯ăƒ—ăƒ©ă‚¤ăƒă‚·ăƒ¼ăŒä¿è­·ă•ă‚Œă¾ă›ă‚“</translation>
<translation id="3583757800736429874">移動ă®ă‚„ă‚ç›´ă—(&amp;R)</translation>
<translation id="3586931643579894722">è©³ç´°ă‚’é表示</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">å€¤ă‚’è¡¨ç¤º</translation>
<translation id="3630155396527302611">ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ă¸ă®ă‚¢ă‚¯ă‚»ă‚¹ă‚’許å¯ă•ă‚ŒăŸăƒ—ăƒ­ă‚°ăƒ©ăƒ ă¨ă—ă¦æ—¢ă«è¡¨ç¤ºă•ă‚Œă¦ă„ă‚‹å ´åˆă¯ă€
ă„ă£ăŸă‚“ăƒªă‚¹ăƒˆă‹ă‚‰å‰é™¤ă—ă€ă‚‚ă†ä¸€åº¦è¿½å ă—ă¦ă¿ă¦ăă ă•ă„。</translation>
+<translation id="3638794133396384728">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă®æœŸé™ăŒåˆ‡ă‚Œă¦ă„ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚ăƒ‘ă‚½ă‚³ăƒ³ă®æ™‚計ă¯ç¾åœ¨ <ph name="CURRENT_TIME" />ă«è¨­å®ă•ă‚Œă¦ă„ă¾ă™ă€‚ă“ă®æ™‚刻ăŒæ­£ă—ăăªă„å ´åˆă¯ă€ă‚·ă‚¹ăƒ†ăƒ ă®æ™‚è¨ˆă‚’ä¿®æ­£ă—ă¦ă€ă“ă®ăƒăƒ¼ă‚¸ă‚’æ›´æ–°ă—ă¦ăă ă•ă„。<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">ă“ă®è©¦é¨“é‹ç”¨æ©Ÿèƒ½ă¯ă€é時変更ă€ä¸­æ–­ă€æ供中止ă•ă‚Œă‚‹ă“ă¨ăŒă‚ă‚ă¾ă™ă€‚ă“ă‚Œă‚‰ă®æ©Ÿèƒ½ă®ă„ăă‚Œă‹ă‚’有å¹ă«ă—ăŸå ´åˆă«ç”Ÿă˜ă‚‹çµæœă«ă¤ă„ă¦ă€Google ă¯ä¸€åˆ‡ä¿è¨¼ă—ă¾ă›ă‚“ă€‚ăƒ–ăƒ©ă‚¦ă‚¶ă«ă‚ˆă£ă¦ă™ă¹ă¦ă®ăƒ‡ăƒ¼ă‚¿ăŒå‰é™¤ă•ă‚ŒăŸă‚ă€äºˆæœŸă›ă¬æ–¹æ³•ă§ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£ă‚„ăƒ—ăƒ©ă‚¤ăƒă‚·ăƒ¼ăŒä¾µå®³ă•ă‚ŒăŸă‚ă™ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚有å¹ă«ă—ăŸè©¦é¨“é‹ç”¨æ©Ÿèƒ½ă¯åŒă˜ăƒ–ăƒ©ă‚¦ă‚¶ă‚’ä½¿ç”¨ă™ă‚‹å…¨ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«å¯¾ă—ă¦æœ‰å¹ă«ăªă‚ă¾ă™ă€‚ç¶è¡Œă™ă‚‹å ´åˆă¯å分ă”注æ„ăă ă•ă„。</translation>
<translation id="3650584904733503804">検証ăŒæ­£å¸¸ă«å®Œäº†ă—ă¾ă—ăŸ</translation>
<translation id="3655670868607891010">ă“ă®ă‚¨ăƒ©ăƒ¼ăŒé »ç¹ă«è¡¨ç¤ºă•ă‚Œă‚‹å ´åˆă¯ă€ă“ă¡ă‚‰ă®<ph name="HELP_LINK" />ă‚’ă試ă—ăă ă•ă„。</translation>
<translation id="3658742229777143148">変更履歴</translation>
+<translation id="3678029195006412963">ăƒªă‚¯ă‚¨ă‚¹ăƒˆă«ç½²åă§ăă¾ă›ă‚“ă§ă—ăŸ</translation>
<translation id="3681007416295224113">証æ˜æ›¸æƒ…å ±</translation>
<translation id="3693415264595406141">ăƒ‘ă‚¹ăƒ¯ăƒ¼ăƒ‰:</translation>
+<translation id="3696411085566228381">ăªă—</translation>
<translation id="3700528541715530410">ă“ă®ăƒăƒ¼ă‚¸ă¸ă®ă‚¢ă‚¯ă‚»ă‚¹ăŒè¨±å¯ă•ă‚Œă¦ă„ăªă„ă‚ˆă†ă§ă™ă€‚</translation>
<translation id="3704609568417268905"><ph name="TIME" />ă€<ph name="TITLE" />(<ph name="DOMAIN" />ï¼‰ă‚’<ph name="BOOKMARKED" /></translation>
<translation id="370665806235115550">読ă¿è¾¼ă¿ä¸­...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">ăƒ¢ăƒă‚¤ăƒ«ăƒ‡ăƒ¼ă‚¿ă¾ăŸă¯ Wi-Fi ă‚’æœ‰å¹ă«ă™ă‚‹</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ăƒ—ăƒ­ă‚­ă‚·ă€ăƒ•ă‚¡ă‚¤ă‚¢ă‚¦ă‚©ăƒ¼ăƒ«ă€DNS ă®è¨­å®ă‚’確èªă™ă‚‹<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">ă‚³ăƒ”ăƒ¼ă—ăŸăƒªăƒ³ă‚¯</translation>
-<translation id="3744899669254331632"><ph name="SITE" /> ă‹ă‚‰é€ä¿¡ă•ă‚ŒăŸæ—å·åŒ–済ă¿ă®èªè¨¼æƒ…å ±ă‚’ Chromium ă§å‡¦ç†ă§ăăªă„ăŸă‚ă€ç¾åœ¨ă“ă®ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“。é€å¸¸ă€ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼ă‚„ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ă¸ă®æ”»æ’ƒă¯ä¸€æ™‚ç„ăªă‚‚ă®ă§ă™ă€‚ă—ă°ă‚‰ăă™ă‚‹ă¨ăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă‚‹ă‚ˆă†ă«ăªă‚ă¾ă™ă€‚</translation>
<translation id="375403751935624634">ă‚µăƒ¼ăƒăƒ¼ ă‚¨ăƒ©ăƒ¼ă®ăŸă‚翻訳ă§ăă¾ă›ă‚“ă§ă—ăŸă€‚</translation>
<translation id="3759461132968374835">最近発生ă—ăŸéœå®³ă¯ă‚ă‚ă¾ă›ă‚“。éœå®³ăƒ¬ăƒăƒ¼ăƒˆăŒç„¡å¹ă«ăªă£ă¦ă„ă‚‹ă¨ăă«ç™ºç”Ÿă—ăŸéœå®³ă¯ă€ă“ă“ă«ă¯è¡¨ç¤ºă•ă‚Œă¾ă›ă‚“。</translation>
<translation id="3788090790273268753">ă“ă®ă‚µă‚¤ăƒˆă®è¨¼æ˜æ›¸ă¯ 2016 å¹´ă¾ă§æœ‰å¹ă§ă€è¨¼æ˜æ›¸ăƒă‚§ăƒ¼ăƒ³ă«ă¯ SHA-1 ă‚’ä½¿ă£ă¦ç½²åă•ă‚ŒăŸè¨¼æ˜æ›¸ăŒå«ă¾ă‚Œă¦ă„ă¾ă™ă€‚</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">競åˆă™ă‚‹ăƒ‡ăƒă‚¤ă‚¹è­˜åˆ¥å­ă§ă™</translation>
<translation id="3885155851504623709">教区</translation>
<translation id="3901925938762663762">ă‚«ăƒ¼ăƒ‰ă®æœ‰å¹æœŸé™ăŒåˆ‡ă‚Œă¦ă„ă¾ă™</translation>
+<translation id="3910267023907260648"><ph name="DOMAIN" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸè¨¼æ˜æ›¸ă¯è„†å¼±ăªç½²åă‚¢ăƒ«ă‚´ăƒªă‚ºăƒ ă‚’ä½¿ç”¨ă—ă¦ç½²åă•ă‚Œă¦ă„ă¾ă™ă€‚ă“ă‚Œă¯ă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£èªè¨¼æƒ…å ±ăŒå½è£…ă•ă‚Œă¦ă„ă‚‹å¯èƒ½æ€§ă‚’示ă—ă¦ăă‚ă€ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ăŸă‚µăƒ¼ăƒăƒ¼ă¨ă¯ç•°ăªă‚‹ă‚µăƒ¼ăƒăƒ¼ă§ă‚ă‚‹ăăă‚ŒăŒă‚ă‚ă¾ă™ï¼ˆæ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă¨é€ä¿¡ă—ă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ï¼‰ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ăăらăæ˜æ—¥ä»¥é™ă«åˆ©ç”¨ă§ăă‚‹ă‚ˆă†ă«ăªă‚ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" />}other{ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ăăらă # 日後ă‹ă‚‰åˆ©ç”¨ă§ăă‚‹ă‚ˆă†ă«ăªă‚ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">PDF ăƒ‰ă‚­ăƒ¥ăƒ¡ăƒ³ăƒˆă‚’èª­ă¿è¾¼ă‚€ă“ă¨ăŒă§ăă¾ă›ă‚“ă§ă—ăŸ</translation>
<translation id="3963721102035795474">ăƒªăƒ¼ăƒ€ăƒ¼ăƒ¢ăƒ¼ăƒ‰</translation>
+<translation id="397105322502079400">計算ă—ă¦ă„ă¾ă™...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> ă¯ăƒ–ăƒ­ăƒƒă‚¯ă•ă‚Œă¦ă„ă¾ă™</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 件ă®è¿‘ăă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸}other{# 件ă®è¿‘ăă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸}}</translation>
<translation id="4021036232240155012">DNS ă¯ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă®åå‰ă‚’ă‚¤ăƒ³ă‚¿ăƒ¼ăƒăƒƒăƒˆ ă‚¢ăƒ‰ăƒ¬ă‚¹ă«å¤‰æ›ă™ă‚‹ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚µăƒ¼ăƒ“ă‚¹ă§ă™ă€‚</translation>
<translation id="4030383055268325496">追å ă®å–ă‚消ă—(&amp;U)</translation>
-<translation id="4032534284272647190"><ph name="URL" /> ă¸ă®ă‚¢ă‚¯ă‚»ă‚¹ăŒæ‹’å¦ă•ă‚Œă¾ă—ăŸă€‚</translation>
<translation id="404928562651467259">è­¦å‘</translation>
<translation id="4058922952496707368">ă‚­ăƒ¼ă€Œ<ph name="SUBKEY" />ă€: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">ă‚¯ăƒ©ă‚¤ă‚¢ăƒ³ăƒˆă¨ă‚µăƒ¼ăƒăƒ¼ă§ă€å…±é€ă® SSL ăƒ—ăƒ­ăƒˆă‚³ăƒ« ăƒăƒ¼ă‚¸ăƒ§ăƒ³ă¾ăŸă¯æ—å·ă‚¹ă‚¤ăƒ¼ăƒˆăŒă‚µăƒăƒ¼ăƒˆă•ă‚Œă¦ă„ă¾ă›ă‚“。</translation>
<translation id="4079302484614802869">ăƒ—ăƒ­ă‚­ă‚·ă¯å›ºå®ăƒ—ăƒ­ă‚­ă‚· ă‚µăƒ¼ăƒăƒ¼ă§ă¯ăªă .pac ă‚¹ă‚¯ăƒªăƒ—ăƒˆ URL ă‚’ä½¿ç”¨ă™ă‚‹ă‚ˆă†ă«è¨­å®ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="4103249731201008433">ăƒ‡ăƒă‚¤ă‚¹ă®ă‚·ăƒªă‚¢ăƒ«ç•ªå·ăŒç„¡å¹ă§ă™</translation>
<translation id="4103763322291513355">&lt;strong&gt;chrome://policy&lt;/strong&gt; ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă¦ă€ăƒ–ăƒ©ăƒƒă‚¯ăƒªă‚¹ăƒˆă«ç™»éŒ²ă•ă‚Œă¦ă„ă‚‹ URL ă¨ă‚·ă‚¹ăƒ†ăƒ ç®¡ç†è€…ăŒè¨­å®ă—ăŸä»–ă®ăƒăƒªă‚·ăƒ¼ă‚’確èªă§ăă¾ă™ă€‚</translation>
+<translation id="4110615724604346410">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă«ă¯ă‚¨ăƒ©ăƒ¼ăŒă‚ă‚ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">ăƒăƒªă‚·ăƒ¼ă®é©ç”¨ç¯„囲ăŒă‚µăƒăƒ¼ăƒˆă•ă‚Œă¦ă„ă¾ă›ă‚“。</translation>
+<translation id="4118212371799607889">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ Chromium ă«ă‚ˆă£ă¦ä¿¡é ¼ă•ă‚Œă¦ă„ă‚‹ă‚‚ă®ă§ă¯ă‚ă‚ă¾ă›ă‚“。åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{他 1 件}other{他 # 件}}</translation>
<translation id="4130226655945681476">ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚±ăƒ¼ăƒ–ăƒ«ă€ăƒ¢ăƒ‡ăƒ ă€ăƒ«ăƒ¼ă‚¿ăƒ¼ă‚’確èªă™ă‚‹</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromium ă«ă“ă®ă‚«ăƒ¼ăƒ‰ă‚’ä¿å­˜ă—ă¾ă™ă‹ï¼Ÿ</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">ç„¡å¹</translation>
<translation id="4196861286325780578">移動ă®ă‚„ă‚ç›´ă—(&amp;R)</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ăƒ•ă‚¡ă‚¤ă‚¢ă‚¦ă‚©ăƒ¼ăƒ«ă¨ă‚¦ă‚¤ăƒ«ă‚¹å¯¾ç­–ă®è¨­å®ă‚’確èªă™ă‚‹<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{ăªă—}=1{1 個ă®ă‚¢ăƒ—ăƒªï¼ˆ$1)}=2{2 個ă®ă‚¢ăƒ—ăƒªï¼ˆ$1ă€$2)}other{# 個ă®ă‚¢ăƒ—ăƒªï¼ˆ$1ă€$2ă€$3)}}</translation>
<translation id="4220128509585149162">ă‚¯ăƒ©ăƒƒă‚·ăƒ¥</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯è¨ºæ–­ăƒ„ăƒ¼ăƒ«ă‚’å®Ÿè¡Œă—ă¦ă¿ă¦ăă ă•ă„<ph name="END_LINK" />。</translation>
<translation id="4250680216510889253">ă„ă„ăˆ</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">ï¼ˆăƒ¦ăƒ¼ă‚¶ăƒ¼åăªă—)</translation>
<translation id="4300246636397505754">ä¿è­·è€…ă‹ă‚‰ă®ăă™ă™ă‚</translation>
<translation id="4304224509867189079">ăƒ­ă‚°ă‚¤ăƒ³</translation>
+<translation id="432290197980158659">ă‚µăƒ¼ăƒăƒ¼ă®æ示ă—ăŸè¨¼æ˜æ›¸ăŒă€çµ„ă¿è¾¼ă¾ă‚Œă¦ă„ă‚‹æƒ³å®ă®è¨¼æ˜æ›¸ă¨ä¸€è‡´ă—ă¾ă›ă‚“。ă“ă‚Œă‚‰ă®æƒ³å®ă®è¨¼æ˜æ›¸ă¯ă€ăƒ¦ăƒ¼ă‚¶ăƒ¼ä¿è­·ă®ăŸă‚ă€ç‰¹å®ă®å®‰å…¨æ€§ă®é«˜ă„ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă«ă¤ă„ă¦ç”¨æ„ă•ă‚Œă¦ă„ă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">記事ăŒè¦‹ă¤ă‹ă‚ă¾ă›ă‚“ă§ă—ăŸ</translation>
+<translation id="4331708818696583467">ä¿è­·ă•ă‚Œă¦ă„ăªă„é€ä¿¡</translation>
<translation id="4372948949327679948"><ph name="VALUE_TYPE" /> 値ăŒæƒ³å®ă•ă‚Œă¾ă™ă€‚</translation>
-<translation id="4377125064752653719"><ph name="DOMAIN" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸè¨¼æ˜æ›¸ă¯ç™ºè¡Œå…ƒă«ă‚ˆă‚å–ă‚消ă•ă‚Œă¦ă„ă¾ă™ă€‚ă“ă‚Œă¯ă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£èªè¨¼æƒ…å ±ăŒä¿¡é ¼ă§ăăªă„ă“ă¨ă‚’示ă—ă¦ăă‚ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă¨é€ä¿¡ă—ă‚ˆă†ă¨ă—ă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="4381091992796011497">ăƒ¦ăƒ¼ă‚¶ăƒ¼å:</translation>
<translation id="4394049700291259645">ç„¡å¹ă«ă™ă‚‹</translation>
<translation id="4395129973926795186"><ph name="START_DATE" />ï½<ph name="END_DATE" /></translation>
<translation id="4406896451731180161">検索çµæœ</translation>
-<translation id="4424024547088906515">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ Chrome ă«ă‚ˆă£ă¦ä¿¡é ¼ă•ă‚Œă¦ă„ă‚‹ă‚‚ă®ă§ă¯ă‚ă‚ă¾ă›ă‚“。åŸå› ă¨ă—ă¦ă¯ă€ä¸é©åˆ‡ăªè¨­å®ă‚„ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă‚‹æ¥ç¶å¦¨å®³ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> ă§ăƒ­ă‚°ă‚¤ăƒ³è¨¼æ˜æ›¸ăŒæ‰¿èªă•ă‚Œăªă‹ă£ăŸă‹ă€ăƒ­ă‚°ă‚¤ăƒ³è¨¼æ˜æ›¸ăŒæ示ă•ă‚Œă¦ă„ăªă„å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="443673843213245140">ăƒ—ăƒ­ă‚­ă‚·ă®ä½¿ç”¨ă¯ç„¡å¹ă§ă™ăŒă€ăƒ—ăƒ­ă‚­ă‚·ă®è¨­å®ăŒæ˜ç¤ºç„ă«æŒ‡å®ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="4458874409874303848">ă‚»ăƒ¼ăƒ•ă‚µă‚¤ăƒˆ</translation>
<translation id="4461847750548395463">Google ă‚»ăƒ¼ăƒ•ă‚µă‚¤ăƒˆăŒæœ‰å¹ă«ăªă£ă¦ă„ă¾ă™ă€‚</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">詳細</translation>
<translation id="4558551763791394412">æ‹¡å¼µæ©Ÿèƒ½ă‚’ç„¡å¹ă«ă—ă¦ă¿ă¦ăă ă•ă„。</translation>
<translation id="4587425331216688090">Chrome ă‹ă‚‰ă‚¢ăƒ‰ăƒ¬ă‚¹ă‚’å‰é™¤ă—ă¦ă‚‚ă‚ˆă‚ă—ă„ă§ă™ă‹ï¼Ÿ</translation>
+<translation id="4589078953350245614"><ph name="DOMAIN" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰ç„¡å¹ăªè¨¼æ˜æ›¸ăŒæ示ă•ă‚Œă¾ă—ăŸă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459"><ph name="DOMAIN" /> ă¸ă®æ¥ç¶ă¯æ–°ă—ă„æ—å·ă‚¹ă‚¤ăƒ¼ăƒˆă«ă‚ˆă‚æ—å·åŒ–ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="4594403342090139922">å‰é™¤ă®å–ă‚消ă—(&amp;U)</translation>
+<translation id="4627442949885028695">ä»–ă®ç«¯æœ«ă§é–‹ă„ăŸă‚¿ăƒ–</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">拡張機能ă®ăƒăƒ¼ă‚¸ă‚’表示ă—ă¦ă„ă¾ă™ă€‚</translation>
-<translation id="467662567472608290">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă«ă¯ă‚¨ăƒ©ăƒ¼ăŒă‚ă‚ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă¯ă€ä¸é©åˆ‡ăªè¨­å®ă‚„ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă‚‹æ¥ç¶å¦¨å®³ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚</translation>
-<translation id="4697214168136963651"><ph name="URL" /> ă¯ăƒ–ăƒ­ăƒƒă‚¯ă•ă‚Œă¾ă—ăŸ</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">æ¥ç¶ăŒä¸­æ–­ă•ă‚Œă¾ă—ăŸ</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯è¨ºæ–­ăƒ„ăƒ¼ăƒ«ă‚’å®Ÿè¡Œă™ă‚‹<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">ăƒ—ăƒ©ăƒƒăƒˆăƒ•ă‚©ăƒ¼ăƒ </translation>
<translation id="4744603770635761495">å®Ÿè¡Œăƒ•ă‚¡ă‚¤ăƒ«ă®ăƒ‘ă‚¹</translation>
<translation id="4756388243121344051">履歴(&amp;H)</translation>
+<translation id="4759238208242260848">ăƒ€ă‚¦ăƒ³ăƒ­ăƒ¼ăƒ‰</translation>
<translation id="4764776831041365478"><ph name="URL" /> ă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸ă¯ä¸€æ™‚ç„ă«åœæ­¢ă—ă¦ă„ă‚‹ă‹ă€æ–°ă—ă„ă‚¦ă‚§ăƒ–ă‚¢ăƒ‰ăƒ¬ă‚¹ă«ç§»å‹•ă—ăŸå¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="4771973620359291008">ä¸æ˜ăªă‚¨ăƒ©ăƒ¼ăŒç™ºç”Ÿă—ă¾ă—ăŸă€‚</translation>
<translation id="4782449893814226250">ă“ă®ăƒăƒ¼ă‚¸ă‚’é–‹ă„ă¦ă‚‚ă‚ˆă„ă‹ä¿è­·è€…ă«ăŸăă­ă¾ă—ăŸă€‚</translation>
<translation id="4800132727771399293">有å¹æœŸé™ă¨ CVC ă‚’ç¢ºèªă—ă¦ă‹ă‚‰ă‚‚ă†ä¸€åº¦ă試ă—ăă ă•ă„</translation>
-<translation id="4807049035289105102"><ph name="SITE" /> ă‹ă‚‰ă€Google Chrome ă§å‡¦ç†ă§ăăªă„æ—å·åŒ–ă•ă‚ŒăŸèªè¨¼æƒ…å ±ăŒè¿”ă•ă‚ŒăŸăŸă‚ă€ç¾åœ¨ă“ă®ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă«ă¯ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“。é€å¸¸ă€ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼ă‚„ä¸æ­£ăªæ“作ă¯ä¸€æ™‚ç„ăªă‚‚ă®ă§ă™ă€‚å°‘ă—æ™‚é–“ă‚’ăăă¨ă€ăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă‚‹ă‚ˆă†ă«ăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="4813512666221746211">ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼</translation>
<translation id="4816492930507672669">ăƒăƒ¼ă‚¸ă‚µă‚¤ă‚ºă«åˆă‚ă›ă‚‹</translation>
<translation id="4850886885716139402">表示</translation>
<translation id="4880827082731008257">å±¥æ­´ă‚’æ¤œç´¢</translation>
+<translation id="4884656795097055129">準備ăŒă§ă次第ă€è¿½å ă®è¨˜äº‹ăŒè¡¨ç¤ºă•ă‚Œă¾ă™ă€‚</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />ă€<ph name="TYPE_2" />ă€<ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{ä»– 1 件ă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸}other{ä»– # 件ă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸}}</translation>
<translation id="4923417429809017348">ă“ă®ăƒăƒ¼ă‚¸ă¯ă€ä¸æ˜ăªè¨€èªă‹ă‚‰<ph name="LANGUAGE_LANGUAGE" />ă«ç¿»è¨³ă•ă‚Œă¾ă—ăŸă€‚</translation>
<translation id="4926049483395192435">指å®ă™ă‚‹å¿…è¦ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="4930497775425430760">æ–°ă—ă„ă‚µă‚¤ăƒˆă«åˆă‚ă¦è¨ªå•ă™ă‚‹é›ă¯ä¿è­·è€…ă®æ‰¿èªăŒå¿…è¦ă§ă™ă€‚</translation>
<translation id="495170559598752135">æ“作</translation>
<translation id="4958444002117714549">ăƒªă‚¹ăƒˆă‚’å±•é–‹ă™ă‚‹</translation>
+<translation id="4962322354953122629">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ Chrome ă«ă‚ˆă£ă¦ä¿¡é ¼ă•ă‚Œă¦ă„ă‚‹ă‚‚ă®ă§ă¯ă‚ă‚ă¾ă›ă‚“。åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911"><ph name="ORIGINAL_LANGUAGE" />ă‹ă‚‰<ph name="TARGET_LANGUAGE" />ă«ç¿»è¨³ă—ă¾ă™ă‹ï¼Ÿ</translation>
+<translation id="4989809363548539747">ă“ă®ăƒ—ăƒ©ă‚°ă‚¤ăƒ³ă¯ă‚µăƒăƒ¼ăƒˆă•ă‚Œă¦ă„ă¾ă›ă‚“</translation>
<translation id="5002932099480077015">有å¹ă«ă™ă‚‹ă¨ă€Chrome ă§ă¯ă“ă®ç«¯æœ«ă«ă‚«ăƒ¼ăƒ‰ă®ă‚³ăƒ”ăƒ¼ăŒä¿å­˜ă•ă‚Œă¾ă™ă€‚ă“ă‚Œă«ă‚ˆă‚ă€ăƒ•ă‚©ăƒ¼ăƒ ă«ă™ă°ă‚„ăå…¥å›ă§ăă‚‹ă‚ˆă†ă«ăªă‚ă¾ă™ă€‚</translation>
<translation id="5019198164206649151">ä»£æ›¿ă‚¹ăƒˆă‚¢ă®ç¶æ…‹ăŒä¸é©åˆ‡ă§ă™</translation>
<translation id="5023310440958281426">管ç†è€…ă®ăƒăƒªă‚·ăƒ¼ă‚’確èªă—ă¦ăă ă•ă„</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Google 翻訳ă«ă¤ă„ă¦</translation>
<translation id="5040262127954254034">ăƒ—ăƒ©ă‚¤ăƒă‚·ăƒ¼</translation>
<translation id="5045550434625856497">ăƒ‘ă‚¹ăƒ¯ăƒ¼ăƒ‰ăŒæ­£ă—ăă‚ă‚ă¾ă›ă‚“</translation>
+<translation id="5056549851600133418">ăă™ă™ă‚ă®è¨˜äº‹</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />ăƒ—ăƒ­ă‚­ă‚· ă‚¢ăƒ‰ăƒ¬ă‚¹ă‚’ç¢ºèªă™ă‚‹<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">ă‚µăƒ¼ăƒăƒ¼ă®è¨¼æ˜æ›¸ăŒç¾åœ¨æœ‰å¹ă§ă¯ă‚ă‚ă¾ă›ă‚“。</translation>
<translation id="5089810972385038852">都é“府県 / å·</translation>
-<translation id="5094747076828555589">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ Chromium ă«ă‚ˆă£ă¦ä¿¡é ¼ă•ă‚Œă¦ă„ă‚‹ă‚‚ă®ă§ă¯ă‚ă‚ă¾ă›ă‚“。åŸå› ă¨ă—ă¦ă¯ă€ä¸é©åˆ‡ăªè¨­å®ă‚„ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă‚‹æ¥ç¶å¦¨å®³ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚</translation>
<translation id="5095208057601539847">地方</translation>
<translation id="5115563688576182185">(64 ăƒ“ăƒƒăƒˆï¼‰</translation>
-<translation id="5122371513570456792">ă€Œ<ph name="SEARCH_STRING" />ă€ă«å¯¾ă— <ph name="NUMBER_OF_RESULTS" /> 件ă®<ph name="SEARCH_RESULTS" />ăŒè¦‹ă¤ă‹ă‚ă¾ă—ăŸă€‚</translation>
<translation id="5141240743006678641">Google ă®èªè¨¼æƒ…å ±ă§åŒæœŸăƒ‘ă‚¹ăƒ¯ăƒ¼ăƒ‰ă‚’æ—å·åŒ–ă™ă‚‹</translation>
<translation id="5145883236150621069">ăƒăƒªă‚·ăƒ¼å¿œç­”内ă«ă‚¨ăƒ©ăƒ¼ ă‚³ăƒ¼ăƒ‰ăŒă‚ă‚ă¾ă™</translation>
<translation id="5171045022955879922">検索ă¾ăŸă¯ URL ă‚’å…¥å›</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯ ăƒăƒ¼</translation>
<translation id="5199729219167945352">試験é‹ç”¨æ©Ÿèƒ½</translation>
<translation id="5251803541071282808">ă‚¯ăƒ©ă‚¦ăƒ‰</translation>
+<translation id="5277279256032773186">ä¼ç¤¾ă§ Chrome ă‚’ä½¿ç”¨ă™ă‚‹å ´åˆă¯ă€å¾“æ¥­å“¡ç”¨ă« Chrome ă®è¨­å®ă‚’管ç†ă§ăă¾ă™ă€‚詳細</translation>
<translation id="5299298092464848405">ăƒăƒªă‚·ăƒ¼ă®è§£æ中ă«ă‚¨ăƒ©ăƒ¼ăŒç™ºç”Ÿă—ă¾ă—ăŸ</translation>
<translation id="5300589172476337783">表示</translation>
<translation id="5308689395849655368">éœå®³ăƒ¬ăƒăƒ¼ăƒˆăŒç„¡å¹ă«ăªă£ă¦ă„ă¾ă™ă€‚</translation>
<translation id="5317780077021120954">ä¿å­˜</translation>
<translation id="5327248766486351172">åå‰</translation>
+<translation id="5359637492792381994">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ç¾åœ¨æœ‰å¹ă§ă¯ă‚ă‚ă¾ă›ă‚“ă€‚è¨­å®ăŒä¸é©åˆ‡ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă£ă¦æ¥ç¶ăŒå¦¨å®³ă•ă‚Œă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">ăƒăƒªă‚·ăƒ¼è¨­å®ă‚’ä¿å­˜ă§ăă¾ă›ă‚“ă§ă—ăŸ</translation>
-<translation id="540969355065856584">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ç¾åœ¨æœ‰å¹ă§ă¯ă‚ă‚ă¾ă›ă‚“ă€‚è¨­å®ăŒä¸é©åˆ‡ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă£ă¦æ¥ç¶ăŒå¦¨å®³ă•ă‚Œă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="5421136146218899937">é–²è¦§å±¥æ­´ăƒ‡ăƒ¼ă‚¿ă®æ¶ˆå»...</translation>
<translation id="5430298929874300616">ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯ă‚’å‰é™¤</translation>
<translation id="5431657950005405462">ăƒ•ă‚¡ă‚¤ăƒ«ăŒè¦‹ă¤ă‹ă‚ă¾ă›ă‚“ă§ă—ăŸ</translation>
<translation id="5435775191620395718">ă“ă®ç«¯æœ«ă®å±¥æ­´ă‚’表示ă—ă¦ă„ă¾ă™ă€‚<ph name="BEGIN_LINK" />詳細<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">åŒæœŸăƒ‡ăƒ¼ă‚¿ăŒă‚«ă‚¹ă‚¿ăƒ  ăƒ‘ă‚¹ăƒ•ăƒ¬ăƒ¼ă‚ºă§ä¿è­·ă•ă‚Œă¦ă„ă‚‹ăŸă‚ă€ăă™ă™ă‚ă‚³ăƒ³ăƒ†ăƒ³ăƒ„ă®è¡¨ç¤ºæ©Ÿèƒ½ă¯ç¾åœ¨ç„¡å¹ă«ăªă£ă¦ă„ă¾ă™ă€‚</translation>
<translation id="5439770059721715174">ă€Œ<ph name="ERROR_PATH" />ă€ă§ă‚¹ă‚­ăƒ¼ăƒç¢ºèªă‚¨ăƒ©ăƒ¼: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">ă“ă® <ph name="HOST_NAME" /> ăƒăƒ¼ă‚¸ăŒè¦‹ă¤ă‹ă‚ă¾ă›ă‚“</translation>
<translation id="5455374756549232013">ăƒăƒªă‚·ăƒ¼ă®ă‚¿ă‚¤ăƒ ă‚¹ă‚¿ăƒ³ăƒ—ăŒä¸é©åˆ‡ă§ă™</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">ă“ă®ă‚µă‚¤ăƒˆă‚’é›¢ă‚Œă¦ă‚‚ă‚ˆă‚ă—ă„ă§ă™ă‹ï¼Ÿ</translation>
<translation id="5629630648637658800">ăƒăƒªă‚·ăƒ¼è¨­å®ă‚’読ă¿è¾¼ă‚ă¾ă›ă‚“ă§ă—ăŸ</translation>
<translation id="5631439013527180824">ç„¡å¹ăªăƒ‡ăƒă‚¤ă‚¹ç®¡ç†ăƒˆăƒ¼ă‚¯ăƒ³ă§ă™</translation>
-<translation id="5650551054760837876">一致ă™ă‚‹æƒ…å ±ă¯ă‚ă‚ă¾ă›ă‚“。</translation>
<translation id="5677928146339483299">ăƒ–ăƒ­ăƒƒă‚¯</translation>
<translation id="5710435578057952990">ă“ă®ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă® ID ă¯ç¢ºèªă•ă‚Œă¦ă„ă¾ă›ă‚“。</translation>
<translation id="5720705177508910913">ç¾åœ¨ă®ăƒ¦ăƒ¼ă‚¶ăƒ¼</translation>
+<translation id="572328651809341494">最近使ă£ăŸă‚¿ăƒ–</translation>
<translation id="5784606427469807560">ă‚«ăƒ¼ăƒ‰ă®ç¢ºèªä¸­ă«å•é¡ŒăŒç™ºç”Ÿă—ă¾ă—ăŸă€‚ă‚¤ăƒ³ă‚¿ăƒ¼ăƒăƒƒăƒˆæ¥ç¶ă‚’確èªă—ă¦ă‚‚ă†ä¸€åº¦ă試ă—ăă ă•ă„。</translation>
<translation id="5785756445106461925">å ăˆă¦ă€ă“ă®ăƒăƒ¼ă‚¸ă«ă¯å®‰å…¨ă§ăªă„ä»–ă®ăƒªă‚½ăƒ¼ă‚¹ăŒå«ă¾ă‚Œă¦ă„ă¾ă™ă€‚ă“ă®ăƒªă‚½ăƒ¼ă‚¹ă¯é€ä¿¡ä¸­ă«ä»–ă®ăƒ¦ăƒ¼ă‚¶ăƒ¼ă‹ă‚‰è¦‹ă‚‰ă‚Œă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚ă¾ăŸă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă£ă¦æ”¹å¤‰ă•ă‚Œăƒăƒ¼ă‚¸ă®è¦‹ăŸç›®ăŒå¤‰ă‚ă‚‹å¯èƒ½æ€§ă‚‚ă‚ă‚ă¾ă™ă€‚</translation>
+<translation id="5786044859038896871">ă‚«ăƒ¼ăƒ‰æƒ…å ±ă‚’å…¥å›ă—ă¾ă™ă‹ï¼Ÿ</translation>
+<translation id="5803412860119678065"><ph name="CARD_DETAIL" /> ă‚’å…¥å›ă—ă¾ă™ă‹ï¼Ÿ</translation>
<translation id="5810442152076338065"><ph name="DOMAIN" /> ă¸ă®æ¥ç¶ă¯å¤ă„æ—å·ă‚¹ă‚¤ăƒ¼ăƒˆă«ă‚ˆă‚æ—å·åŒ–ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="5813119285467412249">追å ă®ă‚„ă‚ç›´ă—(&amp;R)</translation>
+<translation id="5814352347845180253"><ph name="SITE" /> ă¨ä»–ă®ä¸€éƒ¨ă®ă‚µă‚¤ăƒˆă®ăƒ—ăƒ¬ăƒŸă‚¢ăƒ  ă‚³ăƒ³ăƒ†ăƒ³ăƒ„ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăăªăăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
+<translation id="5843436854350372569"><ph name="DOMAIN" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸè¨¼æ˜æ›¸ă«ă¯è„†å¼±ăªæ—å·éµăŒå«ă¾ă‚Œă¦ă„ă¾ă™ă€‚悪æ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă£ă¦ç§˜å¯†éµăŒç ´ă‚‰ă‚ŒăŸå¯èƒ½æ€§ăŒă‚ă‚ă€ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ăŸă‚µăƒ¼ăƒăƒ¼ă¨ă¯ç•°ăªă‚‹ă‚µăƒ¼ăƒăƒ¼ă§ă‚ă‚‹ăăă‚ŒăŒă‚ă‚ă¾ă™ï¼ˆæ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă¨é€ä¿¡ă—ă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ï¼‰ă€‚<ph name="BEGIN_LEARN_MORE_LINK" /><ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">ă“ă®ă‚µă‚¤ăƒˆă¯ç®¡ç†è€…ă«ă‚ˆă£ă¦ăƒ–ăƒ­ăƒƒă‚¯ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="5857090052475505287">æ–°ă—ă„ăƒ•ă‚©ăƒ«ăƒ€</translation>
<translation id="5869405914158311789">ă“ă®ă‚µă‚¤ăƒˆă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">ä¿è­·è€…ă‹ă‚‰ă®ăă™ă™ă‚</translation>
<translation id="59107663811261420">ă“ă®è²©å£²è€…ă«å¯¾ă—ă€ă“ă®ç¨®é¡ă®ă‚«ăƒ¼ăƒ‰ă¯ Google ăƒă‚¤ăƒ¡ăƒ³ăƒˆă§ă”利用ă„ăŸă ă‘ă¾ă›ă‚“ă€‚åˆ¥ă®ă‚«ăƒ¼ăƒ‰ă‚’é¸æă—ă¦ăă ă•ă„。</translation>
<translation id="59174027418879706">有å¹</translation>
+<translation id="5926846154125914413">一部ă®ă‚µă‚¤ăƒˆă®ăƒ—ăƒ¬ăƒŸă‚¢ăƒ  ă‚³ăƒ³ăƒ†ăƒ³ăƒ„ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăăªăăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="5966707198760109579">週</translation>
<translation id="5967867314010545767">履歴ă‹ă‚‰å‰é™¤</translation>
<translation id="5975083100439434680">縮å°ă™ă‚‹</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">自動設å®</translation>
<translation id="6042308850641462728">詳細表示</translation>
<translation id="6060685159320643512">ă“ă‚Œă‚‰ă®è©¦é¨“é‹ç”¨ç‰ˆă¯å•é¡ŒăŒç™ºç”Ÿă™ă‚‹å¯èƒ½æ€§ăŒă‚ă‚‹ăŸă‚ă€ă”利用ă®é›ă«ă¯å分ă”注æ„ăă ă•ă„</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{ăªă—}=1{1 件}other{# 件}}</translation>
<translation id="6146055958333702838">ă‚±ăƒ¼ăƒ–ăƒ«ă‚’ç¢ºèªă—ă€ä½¿ç”¨ă—ă¦ă„ă‚‹ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ăƒ‡ăƒă‚¤ă‚¹ï¼ˆăƒ«ăƒ¼ă‚¿ăƒ¼ă€ăƒ¢ăƒ‡ăƒ ăªă©ï¼‰ă‚’
å†èµ·å‹•ă—ă¦ăă ă•ă„。</translation>
<translation id="614940544461990577">æ¬¡ă‚’ă試ă—ăă ă•ă„:</translation>
<translation id="6150607114729249911">ă“ă®ăƒăƒ¼ă‚¸ă‚’é–‹ă„ă¦ă‚‚ă‚ˆă„ă‹ä¿è­·è€…ă«ăŸăă­ă‚‹å¿…è¦ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="6151417162996330722">ă‚µăƒ¼ăƒăƒ¼è¨¼æ˜æ›¸ă®æœ‰å¹æœŸé™ăŒé•·ă™ăă¾ă™ă€‚</translation>
-<translation id="6154808779448689242">è¿”ă•ă‚ŒăŸăƒăƒªă‚·ăƒ¼ ăƒˆăƒ¼ă‚¯ăƒ³ă¯ç¾åœ¨ă®ăƒˆăƒ¼ă‚¯ăƒ³ă¨ä¸€è‡´ă—ă¾ă›ă‚“</translation>
<translation id="6165508094623778733">詳ă—ăè¦‹ă‚‹</translation>
<translation id="6203231073485539293">ă‚¤ăƒ³ă‚¿ăƒ¼ăƒăƒƒăƒˆæ¥ç¶ă‚’確èªă—ă¦ăă ă•ă„</translation>
<translation id="6218753634732582820">Chromium ă‹ă‚‰ă‚¢ăƒ‰ăƒ¬ă‚¹ă‚’å‰é™¤ă—ă¦ă‚‚ă‚ˆă‚ă—ă„ă§ă™ă‹ï¼Ÿ</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯äºˆæ¸¬ă‚’ç„¡å¹ă«ă—ă¦ă¿ă¦ăă ă•ă„</translation>
<translation id="6337534724793800597">ăƒăƒªă‚·ăƒ¼ă‚’åå‰ă§ăƒ•ă‚£ăƒ«ă‚¿</translation>
<translation id="6342069812937806050">ăŸă£ăŸä»</translation>
+<translation id="6345221851280129312">ä¸æ˜ăªă‚µă‚¤ă‚º</translation>
<translation id="6355080345576803305">å…¬é–‹ă‚»ăƒƒă‚·ăƒ§ăƒ³ă®ă‚ªăƒ¼ăƒăƒ¼ăƒ©ă‚¤ăƒ‰</translation>
<translation id="6358450015545214790">ăƒ˜ăƒ«ăƒ—</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{ä»– 1 件ă®å€™è£œ}other{ä»– # 件ă®å€™è£œ}}</translation>
<translation id="6387478394221739770">Chrome ă®æ–°ă—ă„機能ă«é–¢å¿ƒă‚’ăæŒă¡ă§ă—ăŸă‚‰ă€chrome.com/beta ă‹ă‚‰ Beta ăƒăƒ£ăƒ³ăƒăƒ«ă‚’ă試ă—ăă ă•ă„。</translation>
-<translation id="641480858134062906"><ph name="URL" /> ă®èª­ă¿è¾¼ă¿ă«å¤±æ•—ă—ă¾ă—ăŸ</translation>
+<translation id="6389758589412724634">ă“ă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸ă‚’表示ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€Chromium ă®ăƒ¡ăƒ¢ăƒªăŒä¸è¶³ă—ă¦ă„ă¾ă™ă€‚</translation>
+<translation id="6416403317709441254"><ph name="SITE" /> ă‹ă‚‰é€ä¿¡ă•ă‚ŒăŸæ—å·åŒ–済ă¿ă®èªè¨¼æƒ…å ±ă‚’ Chromium ă§å‡¦ç†ă§ăăªă„ăŸă‚ă€ç¾åœ¨ă“ă®ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“。é€å¸¸ă€ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼ă‚„ä¸æ­£ăªæ“作ă¯ä¸€æ™‚ç„ăªă‚‚ă®ă§ă™ă€‚å°‘ă—æ™‚é–“ă‚’ăăă¨ă€ă¾ăŸăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă‚‹ă‚ˆă†ă«ăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">証æ˜æ›¸ăŒå–ă‚消ă•ă‚ŒăŸă‹ă©ă†ă‹ă‚’確èªă§ăă¾ă›ă‚“。</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ă§æ¥ç¶ăŒæ‹’å¦ă•ă‚Œă¾ă—ăŸă€‚</translation>
<translation id="6445051938772793705">国</translation>
<translation id="6451458296329894277">ăƒ•ă‚©ăƒ¼ăƒ å†é€ä¿¡ă®ç¢ºèª</translation>
<translation id="6458467102616083041">ăƒăƒªă‚·ăƒ¼ă«ă‚ˆă£ă¦ăƒ‡ăƒ•ă‚©ăƒ«ăƒˆă®æ¤œç´¢ăŒç„¡å¹ă«ă•ă‚Œă¦ă„ă‚‹ăŸă‚無視ă•ă‚Œă¾ă™ă€‚</translation>
+<translation id="6462969404041126431">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯å–ă‚消ă•ă‚Œă¦ă„ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">ăƒ‡ăƒă‚¤ă‚¹ ăƒăƒªă‚·ăƒ¼</translation>
<translation id="6489534406876378309">ă‚¯ăƒ©ăƒƒă‚·ăƒ¥ă®ă‚¢ăƒƒăƒ—ăƒ­ăƒ¼ăƒ‰ă‚’é–‹å§‹</translation>
<translation id="6529602333819889595">å‰é™¤ă®ă‚„ă‚ç›´ă—(&amp;R)</translation>
+<translation id="6534179046333460208">ăƒ•ă‚£ă‚¸ă‚«ăƒ« ă‚¦ă‚§ăƒ–ă‹ă‚‰ă® URL</translation>
<translation id="6550675742724504774">ă‚ªăƒ—ă‚·ăƒ§ăƒ³</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" /> 未満</translation>
<translation id="6596325263575161958">æ—å·åŒ–ă‚ªăƒ—ă‚·ăƒ§ăƒ³</translation>
<translation id="662080504995468778">ă¨ă©ă¾ă‚‹</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> 検索</translation>
-<translation id="6634865548447745291"><ph name="BEGIN_LINK" />証æ˜æ›¸ăŒå–ă‚消ă•ă‚Œă¦ă„ă‚‹<ph name="END_LINK" />ăŸă‚ă€ç¾åœ¨ <ph name="SITE" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“。é€å¸¸ă€ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼ă‚„ä¸æ­£ăªæ“作ă¯ä¸€æ™‚ç„ăªă‚‚ă®ă§ă™ă€‚å°‘ă—æ™‚é–“ă‚’ăăă¨ă€ă¾ăŸăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă‚‹ă‚ˆă†ă«ăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="6644283850729428850">ă“ă®ăƒăƒªă‚·ăƒ¼ă¯å»ƒæ­¢ă•ă‚Œă¾ă—ăŸă€‚</translation>
+<translation id="6652240803263749613">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ă€ă”使用ă®ăƒ‘ă‚½ă‚³ăƒ³ă®ă‚ªăƒăƒ¬ăƒ¼ăƒ†ă‚£ăƒ³ă‚° ă‚·ă‚¹ăƒ†ăƒ ă«ă‚ˆă£ă¦ä¿¡é ¼ă•ă‚Œă¦ă„ă‚‹ă‚‚ă®ă§ă¯ă‚ă‚ă¾ă›ă‚“。åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">ăƒ•ă‚©ăƒ«ăƒ€ă®ç·¨é›†</translation>
<translation id="6660210980321319655"><ph name="CRASH_TIME" /> ă«ăƒ¬ăƒăƒ¼ăƒˆă‚’自動é€ä¿¡ă—ă¾ă—ăŸ</translation>
<translation id="6671697161687535275">Chromium ă‹ă‚‰å€™è£œă‚’å‰é™¤ă—ă¦ă‚‚ă‚ˆă‚ă—ă„ă§ă™ă‹ï¼Ÿ</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">å‰ă¸</translation>
<translation id="6710594484020273272">&lt;æ¤œç´¢ă‚­ăƒ¼ăƒ¯ăƒ¼ăƒ‰ă‚’å…¥å›&gt;</translation>
<translation id="6711464428925977395">ăƒ—ăƒ­ă‚­ă‚· ă‚µăƒ¼ăƒăƒ¼ă«å•é¡ŒăŒă‚ă‚‹ă€ă¾ăŸă¯ă‚¢ăƒ‰ăƒ¬ă‚¹ăŒæ­£ă—ăă‚ă‚ă¾ă›ă‚“。</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{ăªă—}=1{1 件ă®ă‚¢ă‚¤ăƒ†ăƒ }other{# 件ă®ă‚¢ă‚¤ăƒ†ăƒ }}</translation>
<translation id="674375294223700098">ä¸æ˜ăªă‚µăƒ¼ăƒăƒ¼è¨¼æ˜æ›¸ă‚¨ăƒ©ăƒ¼</translation>
<translation id="6753269504797312559">ăƒăƒªă‚·ăƒ¼ă®å€¤</translation>
<translation id="6757797048963528358">ăƒ‡ăƒă‚¤ă‚¹ăŒă‚¹ăƒªăƒ¼ăƒ—ç¶æ…‹ă§ă™ă€‚</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">ăƒăƒªă‚·ăƒ¼ăƒ¬ăƒ™ăƒ«ăŒă‚µăƒăƒ¼ăƒˆă•ă‚Œă¦ă„ă¾ă›ă‚“。</translation>
<translation id="6895330447102777224">ă‚«ăƒ¼ăƒ‰ă‚’ç¢ºèªă—ă¾ă—ăŸ</translation>
<translation id="6897140037006041989">ăƒ¦ăƒ¼ă‚¶ăƒ¼ ă‚¨ăƒ¼ă‚¸ă‚§ăƒ³ăƒˆ</translation>
-<translation id="6903907808598579934">åŒæœŸă‚’有å¹ă«ă™ă‚‹</translation>
<translation id="6915804003454593391">ăƒ¦ăƒ¼ă‚¶ăƒ¼:</translation>
<translation id="6957887021205513506">ă‚µăƒ¼ăƒăƒ¼ă®è¨¼æ˜æ›¸ăŒå½é€ ă•ă‚ŒăŸă‚‚ă®ă®ă‚ˆă†ă§ă™ă€‚</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">地区</translation>
<translation id="6973656660372572881">固å®ăƒ—ăƒ­ă‚­ă‚· ă‚µăƒ¼ăƒăƒ¼ă¨ .pac ă‚¹ă‚¯ăƒªăƒ—ăƒˆ URL ă®ä¸¡æ–¹ăŒæŒ‡å®ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="6989763994942163495">詳細設å®ă‚’表示...</translation>
+<translation id="7000990526846637657">履歴項目ăŒè¦‹ă¤ă‹ă‚ă¾ă›ă‚“</translation>
+<translation id="7009986207543992532"><ph name="DOMAIN" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€ă‚µăƒ¼ăƒăƒ¼ă«æ示ă•ă‚ŒăŸè¨¼æ˜æ›¸ă®æœ‰å¹æœŸé™ăŒé•·ă™ăă¦ä¿¡é ¼æ€§ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">中国é€è¯</translation>
+<translation id="7012372675181957985">Google ă‚¢ă‚«ă‚¦ăƒ³ăƒˆă§ă®ä»–ă®å½¢å¼ă®é–²è¦§å±¥æ­´ăŒ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ă«æ®‹ă‚‹ă“ă¨ăŒă‚ă‚ă¾ă™</translation>
<translation id="7029809446516969842">ăƒ‘ă‚¹ăƒ¯ăƒ¼ăƒ‰</translation>
-<translation id="7050187094878475250"><ph name="DOMAIN" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€ă‚µăƒ¼ăƒăƒ¼ă«æ示ă•ă‚ŒăŸè¨¼æ˜æ›¸ă®æœ‰å¹æœŸé™ăŒé•·ă™ăă¦ä¿¡é ¼æ€§ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚</translation>
<translation id="7087282848513945231">郡</translation>
<translation id="7088615885725309056">å¤ă„</translation>
<translation id="7090678807593890770"><ph name="LINK" /> ă‚’ Google ă§æ¤œç´¢ă—ă¦ăă ă•ă„</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">æ–°ă—ă„ă‚µă‚¤ăƒˆă«åˆă‚ă¦è¨ªå•ă™ă‚‹é›ă¯ç®¡ç†è€…ă®æ‰¿èªăŒå¿…è¦ă§ă™ă€‚</translation>
<translation id="724975217298816891">ă‚«ăƒ¼ăƒ‰ă®è©³ç´°ă‚’æ›´æ–°ă™ă‚‹ă«ă¯ <ph name="CREDIT_CARD" /> ă®æœ‰å¹æœŸé™ă¨ CVC ă‚’å…¥å›ă—ă¾ă™ă€‚確èªă‚’è¡Œă†ă¨ă€ă‚«ăƒ¼ăƒ‰ă®è©³ç´°ăŒă“ă®ă‚µă‚¤ăƒˆă¨å…±æœ‰ă•ă‚Œă¾ă™ă€‚</translation>
<translation id="725866823122871198">ăƒ‘ă‚½ă‚³ăƒ³ă®æ—¥æ™‚(<ph name="DATE_AND_TIME" />)ăŒæ­£ă—ăăªă„ăŸă‚ă€<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ă¸ă®ăƒ—ăƒ©ă‚¤ăƒ™ăƒ¼ăƒˆæ¥ç¶ă‚’確立ă§ăă¾ă›ă‚“。</translation>
-<translation id="7265986070661382626"><ph name="SITE" /> ă§ă¯<ph name="BEGIN_LINK" />証æ˜æ›¸ă®ăƒ”ăƒ³ç•™ă‚ăŒä½¿ç”¨ă•ă‚Œă¦ă„ă‚‹<ph name="END_LINK" />ăŸă‚ă€ç¾åœ¨ă“ă®ă‚µă‚¤ăƒˆă«ă¯ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“。é€å¸¸ă€ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼ă‚„ä¸æ­£ăªæ“作ă¯ä¸€æ™‚ç„ăªă‚‚ă®ă§ă™ă€‚å°‘ă—æ™‚é–“ă‚’ăăă¨ă€ă¾ăŸăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă‚‹ă‚ˆă†ă«ăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="7269802741830436641">ă“ă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸ă«ă¯ăƒªăƒ€ă‚¤ăƒ¬ă‚¯ăƒˆ ăƒ«ăƒ¼ăƒ—ăŒå«ă¾ă‚Œă¦ă„ă¾ă™</translation>
<translation id="7275334191706090484">管ç†å¯¾è±¡ă®ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯</translation>
<translation id="7298195798382681320">æ¨å¥¨</translation>
-<translation id="7301833672208172928">履歴ă®åŒæœŸă‚’有å¹ă«ă™ă‚‹</translation>
+<translation id="7309308571273880165"><ph name="CRASH_TIME" /> ă«ă‚¯ăƒ©ăƒƒă‚·ăƒ¥ ăƒ¬ăƒăƒ¼ăƒˆăŒä½œæˆă•ă‚Œă¾ă—ăŸï¼ˆăƒ¦ăƒ¼ă‚¶ăƒ¼ă‹ă‚‰ă‚¢ăƒƒăƒ—ăƒ­ăƒ¼ăƒ‰ăŒăƒªă‚¯ă‚¨ă‚¹ăƒˆă•ă‚Œă¾ă—ăŸăŒă€ă¾ă ă‚¢ăƒƒăƒ—ăƒ­ăƒ¼ăƒ‰ă•ă‚Œă¦ă„ă¾ă›ă‚“)</translation>
<translation id="7334320624316649418">é †åºå¤‰æ›´ă®ă‚„ă‚ç›´ă—(&amp;R)</translation>
<translation id="733923710415886693">ă‚µăƒ¼ăƒăƒ¼ă®è¨¼æ˜æ›¸ă¯ă€è¨¼æ˜æ›¸ă®é€æ˜æ€§ăƒăƒªă‚·ăƒ¼ă‚’介ă—ă¦å…¬é–‹ă•ă‚Œă¦ă„ă¾ă›ă‚“。</translation>
+<translation id="7351800657706554155">証æ˜æ›¸ăŒå–ă‚消ă•ă‚Œă¦ă„ă‚‹ăŸă‚ă€ç¾åœ¨ <ph name="SITE" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă¾ă›ă‚“。é€å¸¸ă€ăƒăƒƒăƒˆăƒ¯ăƒ¼ă‚¯ ă‚¨ăƒ©ăƒ¼ă‚„ä¸æ­£ăªæ“作ă¯ä¸€æ™‚ç„ăªă‚‚ă®ă§ă™ă€‚å°‘ă—æ™‚é–“ă‚’ăăă¨ă€ă¾ăŸăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă§ăă‚‹ă‚ˆă†ă«ăªă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">ă‚³ăƒăƒ³ăƒ‰ăƒ©ă‚¤ăƒ³</translation>
<translation id="7372973238305370288">検索çµæœ</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">ă‚«ăƒ¼ăƒ‰ă‚’ç¢ºèªä¸­ă§ă™</translation>
<translation id="7481312909269577407">é€²ă‚€</translation>
<translation id="7485870689360869515">ăƒ‡ăƒ¼ă‚¿ăŒè¦‹ă¤ă‹ă‚ă¾ă›ă‚“。</translation>
+<translation id="7508255263130623398">è¿”ă•ă‚ŒăŸăƒăƒªă‚·ăƒ¼ă®ç«¯æœ« ID ăŒç©ºă§ă‚ă‚‹ă‹ă€ç¾åœ¨ă®ç«¯æœ« ID ă¨ä¸€è‡´ă—ă¾ă›ă‚“</translation>
<translation id="7514365320538308">ăƒ€ă‚¦ăƒ³ăƒ­ăƒ¼ăƒ‰</translation>
<translation id="7518003948725431193">æ¬¡ă® URL ă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸ă¯è¦‹ă¤ă‹ă‚ă¾ă›ă‚“ă§ă—ăŸ:<ph name="URL" /></translation>
<translation id="7537536606612762813">å¿…é ˆ</translation>
<translation id="7542995811387359312">ă“ă®ăƒ•ă‚©ăƒ¼ăƒ ă¯å®‰å…¨ăªæ¥ç¶ă‚’使用ă—ă¦ă„ăªă„ăŸă‚ă€ă‚¯ăƒ¬ă‚¸ăƒƒăƒˆă‚«ăƒ¼ăƒ‰ă®è‡ªå‹•å…¥å›ăŒç„¡å¹ă«ăªă£ă¦ă„ă¾ă™ă€‚</translation>
<translation id="7549584377607005141">ă“ă®ă‚¦ă‚§ăƒ–ăƒăƒ¼ă‚¸ă‚’æ­£ă—ă表示ă™ă‚‹ă«ă¯ă€å…ˆă»ă©å…¥å›ă—ăŸăƒ‡ăƒ¼ă‚¿ăŒå¿…è¦ă§ă™ă€‚ăƒ‡ăƒ¼ă‚¿ă¯å†é€ä¿¡ă§ăă¾ă™ăŒă€ă“ă®ăƒăƒ¼ă‚¸ă§å…ˆă»ă©è¡Œă£ăŸæ“ä½œă‚’ç¹°ă‚è¿”ă™ă“ă¨ă«ăªă‚ă¾ă™ă€‚</translation>
<translation id="7554791636758816595">æ–°ă—ă„ă‚¿ăƒ–</translation>
-<translation id="7567204685887185387">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ä¸æ­£ă«ç™ºè¡Œă•ă‚ŒăŸă‚‚ă®ă§ă‚ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚åŸå› ă¨ă—ă¦ă¯ă€ä¸é©åˆ‡ăªè¨­å®ă‚„ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă‚‹æ¥ç¶å¦¨å®³ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚</translation>
<translation id="7568593326407688803">ă“ă‚Œă¯<ph name="ORIGINAL_LANGUAGE" />ă®ăƒăƒ¼ă‚¸ă§ă™ă€‚翻訳ă—ă¾ă™ă‹ï¼Ÿ</translation>
<translation id="7569952961197462199">Chrome ă‹ă‚‰ă‚¯ăƒ¬ă‚¸ăƒƒăƒˆ ă‚«ăƒ¼ăƒ‰ă‚’å‰é™¤ă—ă¦ă‚‚ă‚ˆă‚ă—ă„ă§ă™ă‹ï¼Ÿ</translation>
<translation id="7578104083680115302">ă©ă®ç«¯æœ«ă§ă‚‚ă€Google ă«ä¿å­˜ă—ăŸă‚«ăƒ¼ăƒ‰ă‚’使ă£ă¦ă‚µă‚¤ăƒˆă‚„ă‚¢ăƒ—ăƒªă®æ”¯æ‰•ă„ă‚’ă™ă°ă‚„ăè¡Œă†ă“ă¨ăŒă§ăă¾ă™ă€‚</translation>
+<translation id="7588950540487816470">ăƒ•ă‚£ă‚¸ă‚«ăƒ«ă‚¦ă‚§ăƒ–</translation>
<translation id="7592362899630581445">ă‚µăƒ¼ăƒăƒ¼ă®è¨¼æ˜æ›¸ăŒåå‰ă®åˆ¶ç´„ă«é•åă—ă¦ă„ă¾ă™ă€‚</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ă§ă¯ç¾åœ¨ă“ă®ăƒªă‚¯ă‚¨ă‚¹ăƒˆă‚’処ç†ă§ăă¾ă›ă‚“。</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" />ă‚’ç¿»è¨³ă—ăªă„</translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">Chromium ă‹ă‚‰ă‚¯ăƒ¬ă‚¸ăƒƒăƒˆ ă‚«ăƒ¼ăƒ‰ă‚’å‰é™¤ă—ă¦ă‚‚ă‚ˆă‚ă—ă„ă§ă™ă‹ï¼Ÿ</translation>
<translation id="765676359832457558">詳細設å®ă‚’表示ă—ăªă„...</translation>
<translation id="7658239707568436148">ă‚­ăƒ£ăƒ³ă‚»ăƒ«</translation>
+<translation id="7667346355482952095">è¿”ă•ă‚ŒăŸăƒăƒªă‚·ăƒ¼ă®ăƒˆăƒ¼ă‚¯ăƒ³ăŒç©ºă§ă‚ă‚‹ă‹ă€ç¾åœ¨ă®ăƒˆăƒ¼ă‚¯ăƒ³ă¨ä¸€è‡´ă—ă¾ă›ă‚“</translation>
<translation id="7668654391829183341">ä¸æ˜ăªăƒ‡ăƒă‚¤ă‚¹</translation>
<translation id="7674629440242451245">Chrome ă®æ–°ă—ă„機能ă«é–¢å¿ƒă‚’ăæŒă¡ă§ă—ăŸă‚‰ă€chrome.com/dev ă‹ă‚‰ Dev ăƒăƒ£ăƒ³ăƒăƒ«ă‚’ă試ă—ăă ă•ă„。</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă™ă‚‹ï¼ˆå®‰å…¨ă§ă¯ă‚ă‚ă¾ă›ă‚“)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">ă„ă„ăˆ</translation>
<translation id="7805768142964895445">ă‚¹ăƒ†ăƒ¼ă‚¿ă‚¹</translation>
<translation id="7813600968533626083">Chrome ă‹ă‚‰å€™è£œă‚’å‰é™¤ă—ă¦ă‚‚ă‚ˆă‚ă—ă„ă§ă™ă‹ï¼Ÿ</translation>
+<translation id="7815407501681723534">ă€Œ<ph name="SEARCH_STRING" />ă€ă«å¯¾ă— <ph name="NUMBER_OF_RESULTS" /> 件㮠<ph name="SEARCH_RESULTS" />ăŒè¦‹ă¤ă‹ă‚ă¾ă—ăŸ</translation>
<translation id="785549533363645510">ă‚ă‚‰ă‚†ă‚‹å ´æ‰€ă«è¨˜éŒ²ăŒä¸€åˆ‡æ®‹ă‚‰ăªă„ă‚ă‘ă§ă¯ă‚ă‚ă¾ă›ă‚“ă€‚ă‚·ăƒ¼ă‚¯ăƒ¬ăƒƒăƒˆ ăƒ¢ăƒ¼ăƒ‰ă‚’ä½¿ă£ă¦ă‚‚ă€é›‡ç”¨ä¸»ă€ă‚¤ăƒ³ă‚¿ăƒ¼ăƒăƒƒăƒˆ ă‚µăƒ¼ăƒ“ă‚¹ ăƒ—ăƒ­ăƒă‚¤ăƒ€ă€è¨ªå•å…ˆă®ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă«é–²è¦§å†…容ăŒçŸ¥ă‚‰ă‚Œă‚‹å¯èƒ½æ€§ă¯ă‚ă‚ă¾ă™ă€‚</translation>
<translation id="7887683347370398519">CVC ă‚’ç¢ºèªă—ă¦ă‹ă‚‰ă‚‚ă†ä¸€åº¦ă試ă—ăă ă•ă„</translation>
<translation id="7894616681410591072">ă“ă®ăƒăƒ¼ă‚¸ă«ă‚¢ă‚¯ă‚»ă‚¹ă™ă‚‹ă«ă¯ <ph name="NAME" /> ă•ă‚“ă®è¨±å¯ăŒå¿…è¦ă§ă™ă€‚</translation>
-<translation id="790025292736025802"><ph name="URL" /> ăŒè¦‹ă¤ă‹ă‚ă¾ă›ă‚“</translation>
<translation id="7912024687060120840">ăƒ•ă‚©ăƒ«ăƒ€ă®å†…容:</translation>
<translation id="7920092496846849526">ă“ă®ăƒăƒ¼ă‚¸ă‚’é–‹ă„ă¦ă‚‚ă‚ˆă„ă‹ä¿è­·è€…ă«ăŸăă­ă¾ă—ăŸă€‚</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">指å®ăªă—</translation>
<translation id="8012647001091218357">ç¾åœ¨ă€ä¿è­·è€…ă«ăŸăă­ă‚‹ă“ă¨ăŒă§ăă¾ă›ă‚“。もă†ä¸€åº¦ă試ă—ăă ă•ă„。</translation>
<translation id="8034522405403831421">ă“ă®ăƒăƒ¼ă‚¸ă®è¨€èªă¯<ph name="SOURCE_LANGUAGE" />ă§ă™ă€‚<ph name="TARGET_LANGUAGE" />ă«ç¿»è¨³ă—ă¾ă™ă‹ï¼Ÿ</translation>
-<translation id="8034955203865359138">å±¥æ­´ă‚¨ăƒ³ăƒˆăƒªăŒè¦‹ă¤ă‹ă‚ă¾ă›ă‚“。</translation>
<translation id="8088680233425245692">è¨˜äº‹ă‚’è¡¨ç¤ºă§ăă¾ă›ă‚“ă§ă—ăŸă€‚</translation>
+<translation id="8089520772729574115">1 MB 未満</translation>
<translation id="8091372947890762290">ă‚µăƒ¼ăƒăƒ¼ă§æœ‰å¹åŒ–ăŒä¿ç•™ă«ăªă£ă¦ă„ă¾ă™</translation>
+<translation id="8129262335948759431">ä¸æ˜ăªæ•°é‡</translation>
<translation id="8131740175452115882">確èª</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> ă®ă‚µăƒ¼ăƒăƒ¼ă® <ph name="BEGIN_ABBR" />DNS ă‚¢ăƒ‰ăƒ¬ă‚¹<ph name="END_ABBR" />ăŒè¦‹ă¤ă‹ă‚ă¾ă›ă‚“ă§ă—ăŸă€‚</translation>
<translation id="8149426793427495338">ăƒ‘ă‚½ă‚³ăƒ³ăŒă‚¹ăƒªăƒ¼ăƒ—ç¶æ…‹ă§ă™ă€‚</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">IDă€Œ<ph name="EXTENSION_ID" />ă€ă®æ‹¡å¼µæ©Ÿèƒ½ă«å¯¾ă™ă‚‹ç„¡å¹ăªæ›´æ–° URL ă§ă™ă€‚</translation>
<translation id="8218327578424803826">割ă‚当ă¦ă‚‰ă‚ŒăŸå ´æ‰€:</translation>
<translation id="8225771182978767009">ă“ă®ă‚µă‚¤ăƒˆă¯ă€ă“ă®ăƒ‘ă‚½ă‚³ăƒ³ă‚’è¨­å®ă—ăŸăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă£ă¦ăƒ–ăƒ­ăƒƒă‚¯ă•ă‚Œă¦ă„ă¾ă™ă€‚</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />ă€<ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">検索ă—ă¦ă„ă‚‹ăƒăƒ¼ă‚¸ă¯ă€å…¥å›ă—ăŸæƒ…å ±ă‚’ä½¿ç”¨ă—ă¦ă„ă¾ă™ă€‚ă“ă®ăƒăƒ¼ă‚¸ă«æˆ»ă£ăŸå ´åˆă€æ“作ă®ă‚„ă‚ç›´ă—ăŒç™ºç”Ÿă™ă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚ç¶è¡Œă—ă¾ă™ă‹ï¼Ÿ</translation>
<translation id="8249320324621329438">å‰å›ă®å–å¾—:</translation>
<translation id="8261506727792406068">å‰é™¤</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯ ăƒăƒ¼</translation>
<translation id="8363502534493474904">æ©Ÿå†…ăƒ¢ăƒ¼ăƒ‰ă‚’ă‚ªăƒ•ă«ă™ă‚‹</translation>
<translation id="8364627913115013041">未設å®</translation>
+<translation id="8380941800586852976">å±é™º</translation>
<translation id="8412145213513410671">éœå®³æ•°ï¼ˆ<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">åŒă˜ăƒ‘ă‚¹ăƒ•ăƒ¬ăƒ¼ă‚ºă‚’ 2 å›å…¥å›ă™ă‚‹å¿…è¦ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="8428213095426709021">設å®</translation>
+<translation id="8433057134996913067">ă»ă¨ă‚“ă©ă®ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă‹ă‚‰ăƒ­ă‚°ă‚¢ă‚¦ăƒˆă—ă¾ă™ă€‚</translation>
<translation id="8437238597147034694">移動ă®å–ă‚消ă—(&amp;U)</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 件ă®ă‚¯ăƒ¬ă‚¸ăƒƒăƒˆ ă‚«ăƒ¼ăƒ‰}other{# 件ă®ă‚¯ăƒ¬ă‚¸ăƒƒăƒˆ ă‚«ăƒ¼ăƒ‰}}</translation>
+<translation id="8483780878231876732">Google ă‚¢ă‚«ă‚¦ăƒ³ăƒˆă«ä¿å­˜ă—ăŸă‚«ăƒ¼ăƒ‰ă‚’使用ă™ă‚‹ă«ă¯ Chrome ă«ăƒ­ă‚°ă‚¤ăƒ³ă—ă¦ăă ă•ă„</translation>
<translation id="8488350697529856933">é©ç”¨å…ˆ</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ă‹ă‚‰ă®å¿œç­”時間ăŒé•·ă™ăă¾ă™ă€‚</translation>
+<translation id="852346902619691059">ă“ă®ă‚µăƒ¼ăƒăƒ¼ăŒ <ph name="DOMAIN" /> ă§ă‚ă‚‹ă“ă¨ă‚’確èªă§ăă¾ă›ă‚“ă§ă—ăŸă€‚ă“ă®ă‚µăƒ¼ăƒăƒ¼ă®ă‚»ă‚­ăƒ¥ăƒªăƒ†ă‚£è¨¼æ˜æ›¸ă¯ă€ă”使用ă®ăƒ‡ăƒă‚¤ă‚¹ă®ă‚ªăƒăƒ¬ăƒ¼ăƒ†ă‚£ăƒ³ă‚° ă‚·ă‚¹ăƒ†ăƒ ă«ă‚ˆă£ă¦ä¿¡é ¼ă•ă‚Œă¦ă„ă‚‹ă‚‚ă®ă§ă¯ă‚ă‚ă¾ă›ă‚“。åŸå› ă¨ă—ă¦ă€è¨­å®ăŒä¸é©åˆ‡ă§ă‚ă‚‹ă‹ă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ăŒæ¥ç¶ă‚’妨害ă—ă¦ă„ă‚‹ă“ă¨ăŒè€ƒăˆă‚‰ă‚Œă¾ă™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">ă“ă®ç¨®é¡ă®ă‚«ăƒ¼ăƒ‰ă¯ Google ăƒă‚¤ăƒ¡ăƒ³ăƒˆă§ă”利用ă„ăŸă ă‘ă¾ă›ă‚“ă€‚åˆ¥ă®ă‚«ăƒ¼ăƒ‰ă‚’é¸æă—ă¦ăă ă•ă„。</translation>
<translation id="8550022383519221471">ă客様ă®ăƒ‰ăƒ¡ă‚¤ăƒ³ă§ă¯åŒæœŸă‚µăƒ¼ăƒ“ă‚¹ă‚’ă”利用ă„ăŸă ă‘ă¾ă›ă‚“。</translation>
<translation id="8553075262323480129">ăƒăƒ¼ă‚¸ă®è¨€èªă‚’検出ă§ăăªă„ăŸă‚翻訳ă§ăă¾ă›ă‚“。</translation>
@@ -633,15 +675,12 @@
<translation id="8647750283161643317">ă™ă¹ă¦ăƒ‡ăƒ•ă‚©ăƒ«ăƒˆă«æˆ»ă™</translation>
<translation id="8680787084697685621">ă‚¢ă‚«ă‚¦ăƒ³ăƒˆă®ăƒ­ă‚°ă‚¤ăƒ³æƒ…å ±ăŒå¤ăăªă£ă¦ă„ă¾ă™ă€‚</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> ă¸ă®æ¥ç¶ă¯æ—å·åŒ–ă•ă‚Œă¦ă„ă¾ă›ă‚“。</translation>
-<translation id="8713130696108419660">ç„¡å¹ăªă‚¤ăƒ‹ă‚·ăƒ£ăƒ«ç½²åă§ă™</translation>
<translation id="8725066075913043281">ă‚„ă‚ç›´ă—</translation>
<translation id="8728672262656704056">ă‚·ăƒ¼ă‚¯ăƒ¬ăƒƒăƒˆ ăƒ¢ăƒ¼ăƒ‰ă§ă™</translation>
<translation id="8730621377337864115">完了</translation>
<translation id="8738058698779197622">安全ăªæ¥ç¶ă‚’確立ă™ă‚‹ă«ă¯æ™‚計ăŒæ­£ă—ă設å®ă•ă‚Œă¦ă„ă‚‹å¿…è¦ăŒă‚ă‚ă¾ă™ă€‚ă“ă®ç†ç”±ă¯ă€æœ¬ç‰©ă®ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă§ă‚ă‚‹ă“ă¨ă‚’示ă™ăŸă‚ă«ă‚¦ă‚§ăƒ–ă‚µă‚¤ăƒˆă§ä½¿ç”¨ă•ă‚Œă‚‹è¨¼æ˜æ›¸ă«ă¯ă€æœ‰å¹æœŸé–“(発å¹æ—¥æ™‚ă¨å¤±å¹æ—¥æ™‚)ăŒè¨­å®ă•ă‚Œă¦ă„ă‚‹ăŸă‚ă§ă™ă€‚ăƒ‡ăƒă‚¤ă‚¹ă®æ™‚計ăŒæ­£ă—ăăªă„ăŸă‚ă€Chromium ă§ă¯ă“ă‚Œă‚‰ă®è¨¼æ˜æ›¸ă‚’確èªă§ăă¾ă›ă‚“。</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> ă® &lt;abbr id="dnsDefinition"&gt;DNS ă‚¢ăƒ‰ăƒ¬ă‚¹&lt;/abbr&gt;ăŒè¦‹ă¤ă‹ă‚ă¾ă›ă‚“ă§ă—ăŸă€‚å•é¡Œă‚’診断ă—ă¦ă„ă¾ă™ă€‚</translation>
-<translation id="8741995161408053644">Google ă‚¢ă‚«ă‚¦ăƒ³ăƒˆă§ă®ä»–ă®å½¢å¼ă®é–²è¦§å±¥æ­´ăŒ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ă«æ®‹ă‚‹ă“ă¨ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="8790007591277257123">å‰é™¤ă®ă‚„ă‚ç›´ă—(&amp;R)</translation>
-<translation id="8790687370365610530">ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«åˆă‚ă›ăŸ Google ă‹ă‚‰ă®ăă™ă™ă‚ă‚³ăƒ³ăƒ†ăƒ³ăƒ„ă‚’è¡¨ç¤ºă™ă‚‹ă«ă¯ă€å±¥æ­´ă®åŒæœŸă‚’有å¹ă«ă—ă¾ă™ă€‚</translation>
<translation id="8798099450830957504">æ—¢å®</translation>
<translation id="8804164990146287819">ăƒ—ăƒ©ă‚¤ăƒă‚·ăƒ¼ ăƒăƒªă‚·ăƒ¼</translation>
<translation id="8820817407110198400">ăƒ–ăƒƒă‚¯ăƒăƒ¼ă‚¯</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">ă‚µăƒ¼ăƒăƒ¼ă®è¨¼æ˜æ›¸ă®æœ‰å¹æœŸé™ăŒåˆ‡ă‚Œă¦ă„ă¾ă™ă€‚</translation>
<translation id="8987927404178983737">月</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰æ示ă•ă‚ŒăŸè¨¼æ˜æ›¸ă¯ă€è¨¼æ˜æ›¸ă®é€æ˜æ€§ăƒăƒªă‚·ăƒ¼ă‚’介ă—ă¦å…¬é–‹ă•ă‚Œă¦ă„ă¾ă›ă‚“ă€‚ä¸€éƒ¨ă®è¨¼æ˜æ›¸ă¯ă€ä¿¡é ¼æ€§ă®ç¢ºä¿ă¨æ”»æ’ƒè€…ă‹ă‚‰ă®ä¿è­·ă®ăŸă‚ă€è¨¼æ˜æ›¸ă®é€æ˜æ€§ăƒăƒªă‚·ăƒ¼ă‚’介ă—ă¦å…¬é–‹ă•ă‚Œă‚‹ă“ă¨ăŒè¦ä»¶ă¨ăªă£ă¦ă„ă¾ă™ă€‚</translation>
<translation id="9001074447101275817">ăƒ—ăƒ­ă‚­ă‚· <ph name="DOMAIN" /> ă«ă¯ăƒ¦ăƒ¼ă‚¶ăƒ¼åă¨ăƒ‘ă‚¹ăƒ¯ăƒ¼ăƒ‰ă‚’æŒ‡å®ă™ă‚‹å¿…è¦ăŒă‚ă‚ă¾ă™ă€‚</translation>
<translation id="901974403500617787">ă‚·ă‚¹ăƒ†ăƒ å…¨ä½“ă«é©ç”¨ă•ă‚Œă‚‹ăƒ•ăƒ©ă‚°ă¯æ‰€æœ‰è€…(<ph name="OWNER_EMAIL" />)ă®ă¿ăŒè¨­å®ă§ăă¾ă™ă€‚</translation>
<translation id="9020542370529661692">ă“ă®ăƒăƒ¼ă‚¸ă¯<ph name="TARGET_LANGUAGE" />ă«ç¿»è¨³ă•ă‚Œă¦ă„ă¾ă™</translation>
<translation id="9038649477754266430">äºˆæ¸¬ă‚µăƒ¼ăƒ“ă‚¹ă‚’ä½¿ç”¨ă—ă¦ăƒăƒ¼ă‚¸ă‚’ă‚ˆă‚迅速ă«èª­ă¿è¾¼ă‚€</translation>
<translation id="9039213469156557790">å ăˆă¦ă€ă“ă®ăƒăƒ¼ă‚¸ă«ă¯å®‰å…¨ă§ăªă„ä»–ă®ăƒªă‚½ăƒ¼ă‚¹ăŒå«ă¾ă‚Œă¦ă„ă¾ă™ă€‚ă“ă®ăƒªă‚½ăƒ¼ă‚¹ă¯é€ä¿¡ä¸­ă«ä»–ă®ăƒ¦ăƒ¼ă‚¶ăƒ¼ă‹ă‚‰è¦‹ă‚‰ă‚Œă‚‹å¯èƒ½æ€§ăŒă‚ă‚ă¾ă™ă€‚ă¾ăŸă€æ‚ªæ„ă®ă‚ă‚‹ăƒ¦ăƒ¼ă‚¶ăƒ¼ă«ă‚ˆă£ă¦æ”¹å¤‰ă•ă‚Œăƒăƒ¼ă‚¸ă®å‹•ä½œăŒå¤‰ă‚ă‚‹å¯èƒ½æ€§ă‚‚ă‚ă‚ă¾ă™ă€‚</translation>
-<translation id="9049981332609050619"><ph name="DOMAIN" /> ă«ă‚¢ă‚¯ă‚»ă‚¹ă—ă‚ˆă†ă¨ă—ă¾ă—ăŸăŒă€ă‚µăƒ¼ăƒăƒ¼ă‹ă‚‰ç„¡å¹ăªè¨¼æ˜æ›¸ăŒæ示ă•ă‚Œă¾ă—ăŸă€‚</translation>
<translation id="9050666287014529139">ăƒ‘ă‚¹ăƒ•ăƒ¬ăƒ¼ă‚º</translation>
<translation id="9065203028668620118">編集</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> ăƒăƒ¼ă‚¸ă¯æ©Ÿèƒ½ă—ă¦ă„ă¾ă›ă‚“</translation>
diff --git a/chromium/components/strings/components_strings_kn.xtb b/chromium/components/strings/components_strings_kn.xtb
index b285930efc7..669a8a6fe1a 100644
--- a/chromium/components/strings/components_strings_kn.xtb
+++ b/chromium/components/strings/components_strings_kn.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="kn">
+<translation id="1008557486741366299">ಈಗಲೇ ಅಲà³à²²</translation>
<translation id="1015730422737071372">ಹೆà²à³à²à³à²µà²°à²¿ ವಿವರಗಳನà³à²¨à³ ಒದಗಿಸಿ</translation>
<translation id="1032854598605920125">ಪà³à²°à²¦à²•à³à²·à²¿à²£à²¾à²•à²¾à²°à²¦à²²à³à²²à²¿ ತಿರà³à²—ಿಸà³</translation>
<translation id="1038842779957582377">ಆಜà³à²à²¾à²¤ ಹೆಸರà³</translation>
+<translation id="1053591932240354961">Google Chrome ಪà³à²°à²•à³à²°à²¿à²¯à³†à²—à³à²³à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¿à²²à³à²²à²¦ ಅವà³à²¯à²µà²¸à³à²¥à²¿à²¤ ರà³à²œà³à²µà²¾à²¤à³à²—ಳನà³à²¨à³ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³ ಕಳà³à²¹à²¿à²¸à²¿à²¦ ಕಾರಣ ಇದೀಗ ನೀವೠ<ph name="SITE" /> ಭೇಟಿ ಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ದಾಳಿಗಳೠಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿರà³à²¤à³à²¤à²µà³†, ಹೀಗಾಗಿ ಈ ಪà³à²Ÿà²µà³ ನಂತರ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;ಸೇರಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—à³à²³à²¿à²¸à²¿</translation>
<translation id="10614374240317010">ಉಳಿಸಿಯೇ ಇಲà³à²²</translation>
-<translation id="1064422015032085147">ವೆಬà³â€Œà²ªà³à²Ÿà²µà²¨à³à²¨à³ ಹೋಸà³à²Ÿà³ ಮಾಡà³à²¤à³à²¤à²¿à²°à³à²µ ಸರà³à²µà²°à³ ಓವರà³â€Œà²²à³‹à²¡à³ ಆಗಿರಬಹà³à²¦à³ ಅಥವಾ ನಿರà³à²µà²¹à²£à³†à²¯à²²à³à²²à²¿à²°à²¬à²¹à³à²¦à³.
- ಹೆà²à³à²à³ ಟà³à²°à²¾à²«à²¿à²•à³â€Œ ಸೃಷà³à²Ÿà²¿à²¯à²¾à²—ಿ ಪರಿಸà³à²¥à²¿à²¤à²¿ ಹದಗೆಡà³à²µà³à²¦à²¨à³à²¨à³ ತಪà³à²ªà²¿à²¸à²²à³, ಈ URL ಗೆ ವಿನಂತಿಗಳನà³à²¨à³
- ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿ ಅನà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿಲà³à²².</translation>
<translation id="106701514854093668">ಡೆಸà³à²•à³â€Œà²Ÿà²¾à²ªà³ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
<translation id="1080116354587839789">ಅಗಲಕà³à²•à³† ಹೊಂದಿಸಿ</translation>
+<translation id="1103124106085518534">ಇದೀಗ ಮà³à²—ಿದಿದೆ</translation>
<translation id="1103523840287552314">ಯಾವಾಗಲೂ ಅನà³à²µà²¾à²¦à²¿à²¸à²¿ <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">ಪರಿಶೀಲಿಸಿದರೆ, ವೇಗವಾಗಿ ಫಾರà³à²®à³ ಭರà³à²¤à²¿ ಮಾಡಲೠChrome ಈ ಸಾಧನದಲà³à²²à²¿ ನಿಮà³à²® ಕಾರà³à²¡à³â€Œà²¨ ಪà³à²°à²¤à²¿à²¯à²¨à³à²¨à³ ಸಂಗà³à²°à²¹à²¿à²¸à³à²¤à³à²¤à²¦à³†.</translation>
+<translation id="1111153019813902504">ಇತà³à²¤à³€à²à²¿à²¨ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
<translation id="1113869188872983271">&amp;ಮರà³à²•à³à²°à²®à²—ೊಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—à³à²³à²¿à²¸à²¿</translation>
+<translation id="1126551341858583091">ಸà³à²¥à²³à³€à²¯ ಸಂಗà³à²°à²¹à²£à³†à²¯à²²à³à²²à²¿à²°à³à²µ ಗಾತà³à²° <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">ನೀತಿಯ ಸಂಗà³à²°à²¹ ಸರಿಯಾಗಿದೆ</translation>
<translation id="113188000913989374"><ph name="SITE" /> ಹೀಗೆ ಹೇಳà³à²¤à³à²¤à²¦à³†:</translation>
<translation id="1132774398110320017">Chrome ಸà³à²µà²¯à²‚ತà³à²‚ಬà³à²µà²¿à²•à³† ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳà³...</translation>
-<translation id="1150979032973867961">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಿಮà³à²® ಸಾಧನದ ಆಪರೇಟಿಂಗೠಸಿಸà³à²Ÿà²®à³â€Œ ಪà³à²°à²•à²¾à²° ವಿಶà³à²µà²¾à²¸à²¾à²°à³à²¹à²µà²¾à²—ಿಲà³à²². ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="1152921474424827756"><ph name="URL" /> ನ <ph name="BEGIN_LINK" />ಸಂಗà³à²°à²¹à²¿à²¸à²²à²¾à²—ಿರà³à²µ ನಕಲನà³à²¨à³<ph name="END_LINK" /> ಪà³à²°à²µà³‡à²¶à²¿à²¸à²¿</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ಅನಿರೀಕà³à²·à²¿à²¤à²µà²¾à²—ಿ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಮà³à²à³à²à²¿à²¦à³†.</translation>
<translation id="1161325031994447685">ವೈ-ಫೈಗೆ ಮರà³à²¸à²‚ಪರà³à²•à²¿à²¸à²²à²¾à²—à³à²¤à³à²¤à²¿à²¦à³†</translation>
@@ -25,9 +26,10 @@
<translation id="1181037720776840403">ತೆಗೆದà³à²¹à²¾à²•à³</translation>
<translation id="1201402288615127009">ಮà³à²‚ದೆ</translation>
<translation id="1201895884277373915">ಈ ಸೈಟà³â€Œà²¨à²¿à²‚ದ ಇನà³à²¨à²·à³à²Ÿà³</translation>
-<translation id="121201262018556460">ನೀವೠ<ph name="DOMAIN" /> ಅನà³à²¨à³ ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²¦à³à²¦à³€à²°à²¿, ಆದರೆ ದà³à²°à³à²¬à²² ಕೀಲಿಯನà³à²¨à³ ಹà³à²‚ದಿರà³à²µ ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಒದಗಿಸಿದೆ. ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ಖಾಸಗಿ ಕೀಲಿಯನà³à²¨à³ ಮà³à²°à²¿à²¦à³à²¹à²¾à²•à²¿à²°à²¬à²¹à³à²¦à³, ಮತà³à²¤à³ ನೀವೠನಿರೀಕà³à²·à²¿à²¸à²¿à²¦ ಸರà³à²µà²°à³ ಅದಾಗಿರದೇ ಇರಬಹà³à²¦à³. (ನೀವೠದಾಳಿಕೋರರà³à²‚ದಿಗೆ ಸಂವಹನ ಮಾಡà³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³)</translation>
+<translation id="1206967143813997005">ತಪà³à²ªà³ ಪà³à²°à²¾à²°à²‚ಭಿಕ ಸಹಿ</translation>
+<translation id="1209206284964581585">ಸದà³à²¯à²•à³à²•à³† ಮರೆಮಾಡಿ</translation>
<translation id="1219129156119358924">ಸಿಸà³à²Ÿà²‚ ಭದà³à²°à²¤à³†</translation>
-<translation id="1227224963052638717">ಅಜà³à²à²¾à²¤ ನೀತಿ.</translation>
+<translation id="1227224963052638717">ಅಪರಿà²à²¿à²¤ ನೀತಿ.</translation>
<translation id="1227633850867390598">ಮೌಲà³à²¯à²µà²¨à³à²¨à³ ಮರೆಮಾಡಿ</translation>
<translation id="1228893227497259893">ತಪà³à²ªà²¾à²¦ ಅಸà³à²¤à²¿à²¤à³à²µà²¦ ಗà³à²°à³à²¤à³</translation>
<translation id="1232569758102978740">ಶೀರà³à²·à²¿à²•à³†à²°à²¹à²¿à²¤</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">ಹೌದà³</translation>
<translation id="1430915738399379752">ಮà³à²¦à³à²°à²¿à²¸à³</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /> <ph name="DOMAIN" /> ನಲà³à²²à²¿ ಪà³à²Ÿà²•à³à²•à³† ಭೇಟಿ ನೀಡà³à²µ<ph name="END_LINK" /> ಪà³à²°à²¯à²¤à³à²¨à²µà²¨à³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ.</translation>
+<translation id="1491663344921578213">ವೆಬà³â€Œà²¸à³ˆà²Ÿà³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಪಿನೠಮಾಡà³à²µà²¿à²•à³†à²¯à²¨à³à²¨à³ ಬಳಸà³à²µ ಕಾರಣ ಇದೀಗ ನೀವೠ<ph name="SITE" /> ಭೇಟಿ ಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ದಾಳಿಗಳೠಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿರà³à²¤à³à²¤à²µà³†, ಹೀಗಾಗಿ ಈ ಪà³à²Ÿà²µà³ ನಂತರ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">ಈ ಪà³à²Ÿà²¦ ಉಳಿಸಲಾದ (ಉದಾ. ಹಳೆಯದೠà²à²‚ದೠಕರೆಯಲಾಗà³à²µ) ನಕಲನà³à²¨à³ ತೋರಿಸಿ.</translation>
<translation id="1519264250979466059">ಬಿಲà³à²¡à³ ಡೇಟಾ</translation>
<translation id="1549470594296187301">ಈ ವೈಶಿಷà³à²Ÿà³à²¯à²µà²¨à³à²¨à³ ಬಳಸಲೠJavaScript ಸಕà³à²°à²¿à²¯à²—ೊಳಿಸಬೇಕà³.</translation>
@@ -60,38 +63,36 @@
<translation id="1644184664548287040">ನೆಟà³â€Œà²µà²°à³à²•à³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œ ಅಮಾನà³à²¯à²µà²¾à²—ಿದೆ ಹಾಗೂ ಆಮದೠಮಾಡಲಾಗà³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="1644574205037202324">ಇತಿಹಾಸ</translation>
<translation id="1645368109819982629">ಬೆಂಬಲವಿಲà³à²²à²¦ ಪà³à²°à³†à³‚ಟೋಕಾಲà³</translation>
-<translation id="1655462015569774233">{1,plural, =1{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿಯೠನಿನà³à²¨à³† ಮà³à²—ಿದಿದೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ಗಡಿಯಾರವನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ <ph name="CURRENT_DATE" /> ಗೆ ಹà³à²‚ದಿಸಲಾಗಿದೆ. ಅದೠಸರಿಯಾಗಿದೆಯೇ? ಇಲà³à²²à²¦à²¿à²¦à³à²¦à²°à³†, ನಿಮà³à²® ಸಿಸà³à²Ÿà²‚ನ ಗಡಿಯಾರವನà³à²¨à³ ನೀವೠಸರಿಪಡಿಸಿ ಹಾಗೂ ನಂತರ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ರಿಫà³à²°à³†à²¶à³ ಮಾಡಿ.}one{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿಯೠ# ದಿನಗಳ ಹಿಂದೆ ಮà³à²—ಿದಿದೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ಗಡಿಯಾರವನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ <ph name="CURRENT_DATE" /> ಗೆ ಹà³à²‚ದಿಸಲಾಗಿದೆ. ಅದೠಸರಿಯಾಗಿದೆಯೇ? ಇಲà³à²²à²¦à²¿à²¦à³à²¦à²°à³†, ನಿಮà³à²® ಸಿಸà³à²Ÿà²‚ನ ಗಡಿಯಾರವನà³à²¨à³ ನೀವೠಸರಿಪಡಿಸಿ ಹಾಗೂ ನಂತರ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ರಿಫà³à²°à³†à²¶à³ ಮಾಡಿ.}other{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿಯೠ# ದಿನಗಳ ಹಿಂದೆ ಮà³à²—ಿದಿದೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ಗಡಿಯಾರವನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ <ph name="CURRENT_DATE" /> ಗೆ ಹà³à²‚ದಿಸಲಾಗಿದೆ. ಅದೠಸರಿಯಾಗಿದೆಯೇ? ಇಲà³à²²à²¦à²¿à²¦à³à²¦à²°à³†, ನಿಮà³à²® ಸಿಸà³à²Ÿà²‚ನ ಗಡಿಯಾರವನà³à²¨à³ ನೀವೠಸರಿಪಡಿಸಿ ಹಾಗೂ ನಂತರ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ರಿಫà³à²°à³†à²¶à³ ಮಾಡಿ.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> ಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ನಿಮà³à²® ಮಾಹಿತಿಯನà³à²¨à³ ಸಂರಕà³à²·à²¿à²¸à²²à³ à²à²¨à³â€Œà²•à³à²°à²¿à²ªà³à²¶à²¨à³ ಪà³à²°à²¯à³‹à²œà²¨à²µà²¨à³à²¨à³ ಬಳಸಿಕà³à²³à³à²³à³à²¤à³à²¤à²¦à³†. ಈ ಸಂದರà³à²­à²¦à²²à³à²²à²¿ Google Chrome <ph name="SITE" /> ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ೆ ಸಂಪರà³à²•à²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²¦à²¾à²—, ಆ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œâ€Œ ಅಸಹಜ ಮತà³à²¤à³ ತಪà³à²ªà³ ರà³à²œà³à²µà²¾à²¤à³à²—ಳನà³à²¨à³ ಹಿಂತಿರà³à²—ಿಸಿದೆ. ದಾಳಿಕೋರರೠ<ph name="SITE" /> ರೂಪದಲà³à²²à²¿ ಸೋಗೠಹಾಕಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¾à²— ಅಥವಾ ವೈ-ಫೈ ಸೈನà³-ಇನೠಪರದೆಯೠಸಂಪರà³à²•à²•à³à²•à³† ಅಡà³à²¡à²¿à²¯à³à²‚ಟೠಮಾಡಿದಾಗ ಇದೠಕಂಡà³à²¬à²°à²¬à²¹à³à²¦à³. ಯಾವà³à²¦à³‡ ಡೇಟಾವನà³à²¨à³ ವಿನಿಮಯ ಮಾಡಿಕà³à²³à³à²³à³à²µ ಮà³à²¦à²²à³‡ Google Chrome ಸಂಪರà³à²• ಕಡಿತಗà³à²³à²¿à²¸à²¿à²°à³à²µ ಕಾರಣ, ನಿಮà³à²® ಮಾಹಿತಿ ಈಗಲೂ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿದೆ.</translation>
<translation id="168841957122794586">ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ದà³à²°à³à²¬à²² ಕà³à²°à²¿à²ªà³à²Ÿà³‹à²—à³à²°à²¾à²«à²¿à²•à³ ಕೀಯನà³à²¨à³ ಹà³à²‚ದಿದೆ.</translation>
<translation id="1701955595840307032">ಸಲಹೆ ನೀಡಿದ ವಿಷಯ ಪಡೆದà³à²•à³à²³à³à²³à²¿</translation>
-<translation id="1706954506755087368">{1,plural, =1{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ; ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಬಹà³à²¶à²ƒ ನಾಳೆಯಿಂದ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.}one{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಬಹà³à²¶à²ƒ ಭವಿಷà³à²¯à²¦à²²à³à²²à²¿ # ದಿನಗಳಲà³à²²à²¿ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.}other{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಬಹà³à²¶à²ƒ ಭವಿಷà³à²¯à²¦à²²à³à²²à²¿ # ದಿನಗಳಲà³à²²à²¿ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">ಸಿಸà³à²Ÿà²‚ ನಿರà³à²µà²¾à²¹à²•à²°à²¨à³à²¨à³ ಸಂಪರà³à²•à²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="17513872634828108">ತೆರೆದ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳà³</translation>
<translation id="1753706481035618306">ಪà³à²Ÿ ಸಂಖà³à²¯à³†</translation>
-<translation id="1761412452051366565">Google ಸಲಹೆ ನೀಡಿದ ವೈಯಕà³à²¤à³€à²•à²°à²¿à²¸à²²à²¾à²¦ ವಿಷಯವನà³à²¨à³ ಪಡೆದà³à²•à³à²³à³à²³à²²à³, ಸಿಂಕೠಆನೠಮಾಡಿ.</translation>
-<translation id="1763864636252898013">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಿಮà³à²® ಸಾಧನದ ಆಪರೇಟಿಂಗೠಸಿಸà³à²Ÿà²®à³â€Œ ಪà³à²°à²•à²¾à²° ವಿಶà³à²µà²¾à²¸à²¾à²°à³à²¹à²µà²¾à²—ಿಲà³à²². ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows ನೆಟà³â€Œà²µà²°à³à²•à³ ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³â€Œ ರನೠಮಾಡಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿â€Œ<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">ದಯವಿಟà³à²Ÿà³ ನಿಮà³à²® ಸಿಂಕೠಪಾಸà³â€Œà²«à³à²°à³‡à²¸à³ ಅನà³à²¨à³ ನವೀಕರಿಸಿ.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">ನೀವೠಇತà³à²¤à³€à²à²¿à²—ೆ ಭೇಟಿ ನೀಡಿದ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳೠಇಲà³à²²à²¿ ಕಾಣಿಸಿಕà³à²³à³à²³à³à²¤à³à²¤à²µà³†.</translation>
<translation id="1821930232296380041">ಅಮಾನà³à²¯à²µà²¾à²¦ ವಿನಂತಿ ಅಥವಾ ವಿನಂತಿ ಪà³à²¯à²¾à²°à²¾à²®à³€à²Ÿà²°à³â€Œà²—ಳà³</translation>
<translation id="1838667051080421715">ನೀವೠವೆಬೠಪà³à²Ÿà²¦ ಮೂಲವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿.</translation>
<translation id="1871208020102129563">.pac ಸà³à²•à³à²°à²¿à²ªà³à²Ÿà³ URL ಅಲà³à²²à²¦à³†, ನಿಗಧಿತ ಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³â€Œà²—ಳನà³à²¨à³ ಬಳಸಲೠಪà³à²°à²¾à²•à³à²¸à²¿à²¯à²¨à³à²¨à³ ಹà³à²‚ದಿಸಲಾಗಿದೆ.</translation>
<translation id="1883255238294161206">ಪಟà³à²Ÿà²¿à²¯à²¨à³à²¨à³ ಸಂಕà³à²à²¿à²¸à²¿</translation>
<translation id="1898423065542865115">ಫಿಲà³à²Ÿà²°à²¿à²‚ಗà³</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> ನಿಮà³à²® ಲಾಗಿನೠಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸà³à²µà³€à²•à²°à²¿à²¸à²²à²¿à²²à³à²² ಅಥವಾ ನಿಮà³à²® ಲಾಗಿನೠಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ಅವಧಿ ಮೀರಿರಬಹà³à²¦à³.</translation>
<translation id="194030505837763158"><ph name="LINK" /> ಗೆ ಹೋಗಿ</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
<translation id="1973335181906896915">ಅನà³à²•à³à²°à²®à²—à³à²³à²¿à²¸à³à²µà²¿à²•à³†à²¯ ದೋಷ</translation>
<translation id="1974060860693918893">ಸà³à²§à²¾à²°à²¿à²¤</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{ಮತà³à²¤à³ 1 ಇನà³à²¨à²·à³à²Ÿà³}one{ಮತà³à²¤à³ # ಇನà³à²¨à²·à³à²Ÿà³}other{ಮತà³à²¤à³ # ಇನà³à²¨à²·à³à²Ÿà³}}</translation>
<translation id="2025186561304664664">ಪà³à²°à²¾à²•à³à²¸à²¿à²¯à²¨à³à²¨à³ ಸà³à²µà²¯à²‚ ಕಾನà³à²«à²¿à²—ರೠಆಗಿ ಹà³à²‚ದಿಸಲಾಗಿದೆ.</translation>
<translation id="2030481566774242610">ನಿಮà³à²® ಮಾತಿನ ಅರà³à²¥ <ph name="LINK" />?</translation>
<translation id="2031925387125903299">ನಿಮà³à²® ಮà³à²¦à²² ಭೇಟಿಯಲà³à²²à²¿ ನಿಮà³à²® ಪೋಷಕರೠಹà³à²¸ ಸೈಟà³â€Œà²—ಳನà³à²¨à³ ಅಂಗೀಕರಿಸಬೇಕಾಗಿರà³à²µ ಕಾರಣ ನೀವೠಈ ಸಂದೇಶವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />ಪà³à²°à²¾à²•à³à²¸à²¿ ಮತà³à²¤à³ ಫೈರà³â€Œà²µà²¾à²²à³ ಅನà³à²¨à³ ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ಪಿನೠಕೋಡà³</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 ಸಲಹೆ}one{# ಸಲಹೆಗಳà³}other{# ಸಲಹೆಗಳà³}}</translation>
<translation id="2065985942032347596">ದೃಢೀಕರಣದ ಅವಶà³à²¯à²•à²¤à³†à²¯à²¿à²¦à³†</translation>
-<translation id="2079545284768500474">ರದà³à²¦à³à²®à²¾à²¡à³</translation>
+<translation id="2079545284768500474">ರದà³à²¦à³à²®à²¾à²¡à²¿</translation>
<translation id="20817612488360358">ಸಿಸà³à²Ÿà²‚ ಪà³à²°à²¾à²•à³à²¸à²¿ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಬಳಸಲೠಹà³à²‚ದಿಸಲಾಗಿದೆ ಆದರೆ ಬಹಿರಂಗವಾದ ಪà³à²°à²¾à²•à³à²¸à²¿ ಕಾನà³à²«à²¿à²—ರೇಶನೠಅನà³à²¨à³ ಸಹ ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="2086652334978798447">Google ಸಲಹೆ ನೀಡಲಾದ ವೈಯಕà³à²¤à³€à²•à²°à²¿à²¸à²²à²¾à²¦ ವಿಷಯವನà³à²¨à³ ಪಡೆದà³à²•à³à²³à³à²³à²²à³, Chrome ಗೆ ಸೈನೠಇನೠಮಾಡಿ.</translation>
<translation id="2089090684895656482">ಕಡಿಮೆ</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³ à²à²¡à²¿à²Ÿà³ ಮಾಡಿ</translation>
<translation id="2166049586286450108">ಪೂರà³à²£ ನಿರà³à²µà²¾à²¹à²• ಪà³à²°à²µà³‡à²¶</translation>
<translation id="2166378884831602661">ಈ ಸೈಟà³â€Œà²—ೆ ಸà³à²°à²•à³à²·à²¿à²¤ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಒದಗಿಸಲಾಗà³à²µà³à²¦à²¿à²²à³à²²</translation>
-<translation id="2171101176734966184">ನೀವೠ<ph name="DOMAIN" /> ಅನà³à²¨à³ ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²¦à²¿à²°à²¿, ಆದರೆ ದà³à²°à³à²¬à²² ಸಹಿ ಅಲà³à²—ಾರಿದಮೠಬಳಸಿಕà³à²‚ಡೠಸಹಿ ಮಾಡಿದ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಒದಗಿಸಿದೆ. ಇದರರà³à²¥ ಸರà³à²µà²°à³ ಒದಗಿಸಿದ ಸà³à²°à²•à³à²·à²¤à³† ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳನà³à²¨à³ ಖೋಟಾ ತಯಾರಿಸಿರಬಹà³à²¦à³, ಮತà³à²¤à³ ನೀವೠನಿರೀಕà³à²·à²¿à²¸à²¿à²¦ ಸರà³à²µà²°à³ ಅದಾಗಿರದೇ ಇರಬಹà³à²¦à³ (ನೀವೠದಾಳಿಕೋರರà³à²‚ದಿಗೆ ಸಂವಹನ ಮಾಡà³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³).</translation>
<translation id="2181821976797666341">ನಿಯಮಗಳà³</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 ವಿಳಾಸ}one{# ವಿಳಾಸಗಳà³}other{# ವಿಳಾಸಗಳà³}}</translation>
<translation id="2212735316055980242">ನೀತಿ ಕಂಡೠಬಂದಿಲà³à²²</translation>
<translation id="2213606439339815911">ನಮೂದà³à²—ಳನà³à²¨à³ ಪಡೆಯಲಾಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> ಲಭà³à²¯à²µà²¿à²²à³à²²</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ಡಯಾಗà³à²¨à²¸à³à²Ÿà²¿à²•à³à²¸à³â€Œâ€Œ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œ<ph name="END_LINK" /> ಬಳಸಿಕà³à²‚ಡೠನಿಮà³à²® ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸರಿಪಡಿಸಿ</translation>
+<translation id="2239100178324503013">ಈಗ ಕಳà³à²¹à²¿à²¸à²¿</translation>
<translation id="225207911366869382">ಈ ನೀತಿಗಾಗಿ ಈ ಮೌಲà³à²¯à²µà²¨à³à²¨à³ ಅಸಮà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="2262243747453050782">HTTP ದೋಷ</translation>
<translation id="2282872951544483773">ಲಭà³à²¯à²µà²¿à²²à³à²²à²¦ ಪà³à²°à²¯à³‹à²—ಗಳà³</translation>
<translation id="2292556288342944218">ನಿಮà³à²® ಇಂಟರà³à²¨à³†à²Ÿà³ ಪà³à²°à²µà³‡à²¶ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="229702904922032456">ಮೂಲ ಅಥವಾ ಮಧà³à²¯à²‚ತರ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿ ಮà³à²—ಿದಿದೆ.</translation>
<translation id="230155334948463882">ಹೊಸ ಕಾರà³à²¡à³?</translation>
+<translation id="2305919008529760154">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಕಲಿ ಇರಬಹà³à²¦à³. ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> ಗೆ ಬಳಕೆದಾರಹೆಸರೠಮತà³à²¤à³ ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅಗತà³à²¯à²µà²¿à²¦à³†.</translation>
+<translation id="2318774815570432836">ವೆಬà³â€Œà²¸à³ˆà²Ÿà³ HSTS ಬಳಸà³à²µ ಕಾರಣ ಇದೀಗ ನೀವೠ<ph name="SITE" /> ಗೆ ಭೇಟಿ ಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ದಾಳಿಗಳೠಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿರà³à²¤à³à²¤à²µà³†, ಹೀಗಾಗಿ ಈ ಪà³à²Ÿà²µà³ ನಂತರ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">ಸೂà²à³à²¯à²‚ಕದಲà³à²²à²¿ <ph name="ENTRY_INDEX" /> ನಿರà³à²²à²•à³à²·à²¿à²¸à²²à²¾à²¦ ಅಮಾನà³à²¯ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œ</translation>
<translation id="2354001756790975382">ಇತರ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
<translation id="2359808026110333948">ಮà³à²‚ದà³à²µà²°à²¿à²¸à³</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" /> ನಲà³à²²à²¿ ಸೆರೆಹಿಡಿಯಲಾದ ಕà³à²°à³à²¯à²¾à²¶à³ ವರದಿಯನà³à²¨à³ ಅಪà³â€Œà²²à³‹à²¡à³ ಮಾಡಲಾಗಿಲà³à²²</translation>
<translation id="2367567093518048410">ಹಂತ</translation>
+<translation id="2371153335857947666">{1,plural, =1{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿಯೠನಿನà³à²¨à³† ಮà³à²—ಿದಿದೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ಗಡಿಯಾರವನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ <ph name="CURRENT_DATE" /> ಗೆ ಹà³à²‚ದಿಸಲಾಗಿದೆ. ಅದೠಸರಿಯಾಗಿದೆಯೇ? ಇಲà³à²²à²¦à²¿à²¦à³à²¦à²°à³†, ನಿಮà³à²® ಸಿಸà³à²Ÿà²‚ನ ಗಡಿಯಾರವನà³à²¨à³ ನೀವೠಸರಿಪಡಿಸಿ ಹಾಗೂ ನಂತರ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ರಿಫà³à²°à³†à²¶à³ ಮಾಡಿ. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.}one{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿಯೠ# ದಿನಗಳ ಹಿಂದೆ ಮà³à²—ಿದಿದೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ಗಡಿಯಾರವನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ <ph name="CURRENT_DATE" /> ಗೆ ಹà³à²‚ದಿಸಲಾಗಿದೆ. ಅದೠಸರಿಯಾಗಿದೆಯೇ? ಇಲà³à²²à²¦à²¿à²¦à³à²¦à²°à³†, ನಿಮà³à²® ಸಿಸà³à²Ÿà²‚ನ ಗಡಿಯಾರವನà³à²¨à³ ನೀವೠಸರಿಪಡಿಸಿ ಹಾಗೂ ನಂತರ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ರಿಫà³à²°à³†à²¶à³ ಮಾಡಿ. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.}other{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿಯೠ# ದಿನಗಳ ಹಿಂದೆ ಮà³à²—ಿದಿದೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ಗಡಿಯಾರವನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ <ph name="CURRENT_DATE" /> ಗೆ ಹà³à²‚ದಿಸಲಾಗಿದೆ. ಅದೠಸರಿಯಾಗಿದೆಯೇ? ಇಲà³à²²à²¦à²¿à²¦à³à²¦à²°à³†, ನಿಮà³à²® ಸಿಸà³à²Ÿà²‚ನ ಗಡಿಯಾರವನà³à²¨à³ ನೀವೠಸರಿಪಡಿಸಿ ಹಾಗೂ ನಂತರ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ರಿಫà³à²°à³†à²¶à³ ಮಾಡಿ. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">ಯಾವà³à²¦à³‡ UI ಪರà³à²¯à²¾à²¯à²—ಳೠಲಭà³à²¯à²µà²¿à²²à³à²²</translation>
<translation id="2384307209577226199">à²à²‚ಟರà³â€Œà²ªà³à²°à³ˆà²¸à³ ಡಿಫಾಲà³à²Ÿà³</translation>
-<translation id="238526402387145295">ನೀವೠಸದà³à²¯à²•à³à²•à³† <ph name="SITE" /> ಗೆ ಭೇಟಿ ನೀಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². à²à²•à³†à²‚ದರೆ, ಆ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³ <ph name="BEGIN_LINK" />HSTS ಬಳಸà³à²¤à³à²¤à²¦à³†<ph name="END_LINK" />. ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ಆಕà³à²°à²®à²£à²—ಳೠತಾತà³à²•à²¾à²²à²¿à²•, ಹಾಗಾಗಿ ಇದೠಸà³à²µà²²à³à²ª ಸಮಯದ ನಂತರ ಕಾರà³à²¯ ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="2386255080630008482">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಹಿಂಪಡೆಯಲಾಗಿದೆ.</translation>
<translation id="2392959068659972793">ಯಾವà³à²¦à³‡ ಮೌಲà³à²¯ ಹà³à²‚ದಿಸಿಲà³à²²à²¦ ನೀತಿಗಳನà³à²¨à³ ತೋರಿಸಿ</translation>
<translation id="2396249848217231973">&amp;ಅಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—ೊಳಿಸà³</translation>
-<translation id="2413528052993050574">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಹಿಂತೆಗೆದà³à²•à³à²³à³à²³à²²à²¾à²—ಿರಬಹà³à²¦à³. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="2455981314101692989">ಈ ಫಾರà³à²®à³ ಅನà³à²¨à³ ಭರà³à²¤à²¿ ಮಾಡà³à²µ ಸಲà³à²µà²¾à²—ಿ ಈ ವೆಬà³â€Œà²ªà³à²Ÿà²µà²¨à³à²¨à³ ಸà³à²µà²¯à²‚à²à²¾à²²à²¿à²¤à²µà²¾à²—ಿ ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
+<translation id="2463739503403862330">ಭರà³à²¤à²¿ ಮಾಡà³</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ನೆಟà³â€Œà²µà²°à³à²•à³ ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³â€Œ ರನೠಆಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">ಅಮಾನà³à²¯à²µà²¾à²¦ ಹà³à²¡à³à²•à²¾à²Ÿ URL.</translation>
<translation id="2491120439723279231">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ದೋಷಗಳನà³à²¨à³ ಹà³à²‚ದಿದೆ.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">ಸಲà³à²²à²¿à²¸à³</translation>
<translation id="2674170444375937751">ನಿಮà³à²® ಇತಿಹಾಸದಿಂದ ನೀವೠಈ ಪà³à²Ÿà²—ಳನà³à²¨à³ ಖà²à²¿à²¤à²µà²¾à²—ಿ ಅಳಿಸಲೠಬಯಸà³à²¤à³à²¤à²¿à²¦à³à²¦à³€à²°à²¾?</translation>
<translation id="2677748264148917807">ತà³à²°à³†à²¯à²¿à²°à²¿</translation>
+<translation id="269990154133806163">ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಪಾರದರà³à²¶à²•à²¤à³† ನೀತಿಯನà³à²¨à³ ಬಳಸಿಕà³à²‚ಡೠಸಾರà³à²µà²œà²¨à²¿à²•à²µà²¾à²—ಿ ಬಹಿರಂಗಗà³à²³à²¿à²¸à²¦ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಪà³à²°à²¸à³à²¤à³à²¤à²ªà²¡à²¿à²¸à²¿à²¦à³†. ಇದೠಅವà³à²—ಳೠವಿಶà³à²µà²¾à²¸à²¾à²°à³à²¹à²µà²¾à²—ಿವೆ ಮತà³à²¤à³ ಆಕà³à²°à²®à²£à²•à²¾à²°à²° ವಿರà³à²¦à³à²§ ರಕà³à²·à²£à³†à²¯à²¨à³à²¨à³ ನೀಡà³à²¤à³à²¤à²µà³† à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಖà²à²¿à²¤à²ªà²¡à²¿à²¸à²¿à²•à³à²³à³à²³à²²à³ ಕೆಲವೠಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳಿಗೆ ಅಗತà³à²¯à²µà²¾à²—ಿದೆ. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">ಮೌಲà³à²¯à²µà³ ಸà³à²µà²°à³‚ಪಕà³à²•à³† ಹà³à²‚ದಿಕೆಯಾಗà³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="2704951214193499422">ಈ ಸಮಯದಲà³à²²à²¿ Chromium ಗೆ ನಿಮà³à²® ಕಾರà³à²¡à³ ಖà²à²¿à²¤à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²². ದಯವಿಟà³à²Ÿà³ ನಂತರ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="2705137772291741111">ಈ ಸೈಟà³â€Œà²¨ ಉಳಿಸಿದ (ಸಂಗà³à²°à²¹à²µà²¾à²—ಿರà³à²µ) ನಕಲನà³à²¨à³ ಓದಲಾಗà³à²¤à³à²¤à²¿à²²à³à²².</translation>
<translation id="2709516037105925701">ಸà³à²µà²¯à²‚ತà³à²‚ಬà³à²µà²¿à²•à³†</translation>
+<translation id="2712118517637785082">ನೀವೠ<ph name="DOMAIN" /> ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²°à³à²µà²¿à²°à²¿, ಆದರೆ ಸರà³à²µà²°à³ ನೀಡಿದ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಅದನà³à²¨à³ ನೀಡಿದವರೠಹಿಂತೆಗೆದà³à²•à³à²‚ಡಿದà³à²¦à²¾à²°à³†. ಇದರರà³à²¥ ಸರà³à²µà²°à³ ಒದಗಿಸಿದ ಸà³à²°à²•à³à²·à²¤à²¾ ರà³à²œà³à²µà²¾à²¤à³à²—ಳನà³à²¨à³ ಯಾವ ಕಾರಣಕà³à²•à³‚ ನಂಬಲಾಗà³à²µà³à²¦à²¿à²²à³à²². ನೀವೠಆಕà³à²°à²®à²£à²•à²¾à²°à²° ಜà³à²¤à³†à²—ೆ ಸಂವಹನ ಮಾಡà³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">ಅನà³à²®à²¤à²¿ ಕೇಳಿ</translation>
<translation id="2721148159707890343">ವಿನಂತಿಯನà³à²¨à³ ಯಶಸà³à²µà²¿à²—à³à²³à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
<translation id="2728127805433021124">ಕà³à²·à³€à²£à²µà²¾à²¦ ಸಹಿ ಅಲà³à²—ಾರಿದಮೠಬಳಸಿಕà³à²‚ಡೠಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²•à³à²•à³† ಸಹಿ ಮಾಡಲಾಗಿದೆ.</translation>
@@ -167,16 +172,13 @@
<translation id="2824775600643448204">ವಿಳಾಸ ಹಾಗೂ ಹà³à²¡à³à²•à²¾à²Ÿ ಪಟà³à²Ÿà²¿</translation>
<translation id="2826760142808435982"><ph name="CIPHER" /> ಬಳಸಿಕà³à²‚ಡೠಸಂಪರà³à²•à²µà²¨à³à²¨à³ à²à²¨à³â€Œà²•à³à²°à²¿à²ªà³à²Ÿà³ ಮಾಡಲಾಗಿದೆ ಮತà³à²¤à³ ದೃಢೀಕರಿಸಲಾಗಿದೆ ಮತà³à²¤à³ <ph name="KX" /> ಅನà³à²¨à³ ಕೀ ವಿನಿಮಯ ಯಾಂತà³à²°à²¿à²•à²¤à³†à²¯à²‚ತೆ ಬಳಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="2835170189407361413">ಫಾರà³à²®à³ ತೆರವà³à²—à³à²³à²¿à²¸à³</translation>
-<translation id="2837049386027881519">TLS ಅಥವಾ SSL ಪà³à²°à³à²Ÿà³à²•à²¾à²²à³â€Œà²¨ ಹಳೆಯ ಆವೃತà³à²¤à²¿à²¯à²¨à³à²¨à³ ಬಳಸà³à²¤à³à²¤à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಮರà³à²ªà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¬à³‡à²•à²¾à²—ಿದೆ. ಪà³à²°à²¾à²¤à²¿à²¨à²¿à²§à²¿à²•à²µà²¾à²—ಿ ಇದರರà³à²¥à²µà³‡à²¨à³†à²‚ದರೆ ಸರà³à²µà²°à³ ತà³à²‚ಬಾ ಹಳೆಯ ಸಾಫà³à²Ÿà³â€Œà²µà³‡à²°à³ ಅನà³à²¨à³ ಬಳಸà³à²¤à³à²¤à²¿à²¦à³† ಮತà³à²¤à³ ಇತರ ಭದà³à²°à²¤à²¾ ಸಮಸà³à²¯à³†à²—ಳನà³à²¨à³ ಹà³à²‚ದಿರಬಹà³à²¦à³.</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> ನಲà³à²²à²¿à²°à³à²µ ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಕಲಿ à²à²‚ದೠತೋರà³à²¤à³à²¤à²¿à²¦à³†.</translation>
<translation id="2889159643044928134">ಮರà³à²²à³‹à²¡à³ ಮಾಡಬೇಡ</translation>
-<translation id="2896499918916051536">ಈ ಪà³à²²à²—à³-ಇನೠಬೆಂಬಲಿಸà³à²µà³à²¦à²¿à²²à³à²².</translation>
+<translation id="2900469785430194048">ಈ ವೆಬà³â€Œà²ªà³à²Ÿ ಪà³à²°à²¦à²°à³à²¶à²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²µà²¾à²— Google Chrome ಮೆಮà³à²°à²¿ ಖಾಲಿಯಾಗಿದೆ.</translation>
<translation id="2909946352844186028">ನೆಟà³â€Œà²µà²°à³à²•à³ ಬದಲಾವಣೆಯನà³à²¨à³ ಪತà³à²¤à³† ಮಾಡಲಾಗಿದೆ.</translation>
-<translation id="2915500479781995473">ಈ ಸರà³à²µà²°à³â€Œâ€Œ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿ ಮà³à²—ಿದಿದೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ಗಡಿಯಾರವನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ <ph name="CURRENT_TIME" /> ಗೆ ಹà³à²‚ದಿಸಲಾಗಿದೆ. ಅದೠಸರಿಯಾಗಿ ತೋರà³à²¤à³à²¤à²¿à²¦à³†à²¯à³†? ಇಲà³à²²à²µà²¾à²¦à²°à³†, ನಿಮà³à²® ಸಿಸà³à²Ÿà²®à³â€Œà²¨ ಗಡಿಯಾರವನà³à²¨à³ ನೀವೠಸರಿಪಡಿಸಬೇಕೠಹಾಗೂ ನಂತರ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ರೀಫà³à²°à³†à²¶à³ ಮಾಡಿ.</translation>
<translation id="2922350208395188000">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಪರಿಶೀಲಿಸಲಾಗà³à²µà³à²¦à²¿à²²à³à²².</translation>
-<translation id="2941952326391522266">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ <ph name="DOMAIN2" /> ದಿಂದ ಆಗಿದೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="2948083400971632585">ಸಂಪರà³à²•à²•à³à²•à²¾à²—ಿ ಕಾನà³à²«à²¿à²—ರೠಮಾಡಲಾಗಿರà³à²µ ಯಾವà³à²¦à³‡ ಪà³à²°à²¾à²•à³à²¸à²¿à²—ಳನà³à²¨à³ ನೀವೠಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳ ಪà³à²Ÿà²¦à²¿à²‚ದ ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
-<translation id="2955913368246107853">ಹà³à²¡à³à²•à³ ಬಾರೠಅನà³à²¨à³ ಮà³à²à³à²à²¿</translation>
+<translation id="2955913368246107853">ಹà³à²¡à³à²•à²¿ ಬಾರೠಅನà³à²¨à³ ಮà³à²à³à²à²¿</translation>
<translation id="2958431318199492670">ONC ಪà³à²°à²®à²¾à²£à²¿à²¤à²•à³à²•à³† ನೆಟà³â€Œà²µà²°à³à²•à³ ಕಾನà³à²«à²¿à²—ರೇಶನೠಅನà³à²¸à²°à²£à³†à²¯à²¾à²—à³à²µà³à²¦à²¿à²²à³à²². ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨ ಭಾಗಗಳನà³à²¨à³ ಆಮದೠಮಾಡಲಾಗದಿರಬಹà³à²¦à³.</translation>
<translation id="2969319727213777354">ಸà³à²°à²•à³à²·à²¿à²¤ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³, ನಿಮà³à²® ಗಡಿಯಾರವನà³à²¨à³ ಸರಿಯಾಗಿ ಹà³à²‚ದಿಸಬೇಕಾದ ಅಗತà³à²¯à²µà²¿à²¦à³†. ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳೠತಮà³à²®à²¨à³à²¨à³ ಗà³à²°à³à²¤à²¿à²¸à²²à³ ಬಳಸà³à²µ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳೠನಿರà³à²¦à²¿à²·à³à²Ÿ ಅವಧಿಗಳಲà³à²²à²¿ ಮಾತà³à²° ಮಾನà³à²¯à²µà²¾à²—ಿರà³à²µ ಕಾರಣ ಹೀಗಾಗà³à²¤à³à²¤à²¦à³†. ನಿಮà³à²® ಸಾಧನದ ಗಡಿಯಾರವೠತಪà³à²ªà²¾à²—ಿರà³à²µ ಕಾರಣ, Google Chrome ಗೆ ಈ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲೠಸಾಧà³à²¯à²µà²¾à²—à³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="2972581237482394796">&amp;ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">ತಪà³à²ªà²¾à²¦ ನೀತಿಯ ಪà³à²°à²•à²¾à²°</translation>
<translation id="3032412215588512954">ನೀವೠಈ ಸೈಟೠಮರà³à²²à³‹à²¡à³ ಮಾಡಲೠಬಯಸà³à²µà²¿à²°à²¾?</translation>
<translation id="3037605927509011580">ಓಹà³, ಹೋಯà³à²¤à³!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{ಸಿಂಕೠಮಾಡಿದ ಸಾಧನಗಳಲà³à²²à²¿ ಕನಿಷà³à²Ÿ 1 à²à²Ÿà²‚}=1{1 à²à²Ÿà²‚ (ಮತà³à²¤à³ ಸಿಂಕೠಮಾಡಿದ ಸಾಧನಗಳಲà³à²²à²¿ ಇನà³à²¨à²·à³à²Ÿà³)}one{# à²à²Ÿà²‚ಗಳೠ(ಮತà³à²¤à³ ಸಿಂಕೠಮಾಡಿದ ಸಾಧನಗಳಲà³à²²à²¿ ಇನà³à²¨à²·à³à²Ÿà³)}other{# à²à²Ÿà²‚ಗಳೠ(ಮತà³à²¤à³ ಸಿಂಕೠಮಾಡಿದ ಸಾಧನಗಳಲà³à²²à²¿ ಇನà³à²¨à²·à³à²Ÿà³)}}</translation>
<translation id="3041612393474885105">ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಮಾಹಿತಿ</translation>
<translation id="3063697135517575841">ಈ ಸಮಯದಲà³à²²à²¿ Chrome ಗೆ ನಿಮà³à²® ಕಾರà³à²¡à³ ಅನà³à²¨à³ ಖà²à²¿à²¤à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²². ದಯವಿಟà³à²Ÿà³ ನಂತರ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="3093245981617870298">ನೀವೠಆಫà³â€Œà²²à³ˆà²¨à³â€Œà²¨à²²à³à²²à²¿à²°à³à²µà²¿à²°à²¿.</translation>
@@ -197,29 +200,30 @@
<translation id="3145945101586104090">ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à³†à²¯à²¨à³à²¨à³ ಡೀಕೋಡೠಮಾಡಲೠವಿಫಲವಾಗಿದೆ</translation>
<translation id="3150653042067488994">ತಾತà³à²•à²¾à²²à²¿à²• ಸರà³à²µà²°à³ ದೋಷ</translation>
<translation id="3157931365184549694">ಮರà³à²¸à³à²¥à²¾à²ªà²¨à³†</translation>
-<translation id="3167968892399408617">ನಿಮà³à²® à²à²²à³à²²à²¾ ಅಜà³à²à²¾à²¤ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳನà³à²¨à³ ಮà³à²à³à²à²¿à²¦ ಬಳಿಕ ನೀವೠಅಜà³à²à²¾à²¤ ಮೋಡà³â€Œà²¨à²²à³à²²à²¿ ವೀಕà³à²·à²¿à²¸à²¿à²¦ ಪà³à²Ÿà²—ಳೠಬà³à²°à³Œà²¸à²°à³ ಇತಿಹಾಸದಲà³à²²à²¿, ಕà³à²•à³€ ಸಂಗà³à²°à²¹à²¦à²²à³à²²à²¿ ಅಥವಾ ಹà³à²¡à³à²•à²¾à²Ÿ ಇತಿಹಾಸದಲà³à²²à²¿ ಉಳಿಯà³à²µà³à²¦à²¿à²²à³à²². ನೀವೠಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡà³à²µ ಯಾವà³à²¦à³‡ ಫೈಲà³â€Œà²—ಳೠಇಲà³à²²à²µà³‡ ನೀವೠರà²à²¿à²¸à³à²µ ಯಾವà³à²¦à³‡ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳನà³à²¨à³ ಹಾಗೆಯೇ ಇರಿಸಲಾಗà³à²¤à³à²¤à²¦à³†.</translation>
+<translation id="3167968892399408617">ನಿಮà³à²® à²à²²à³à²²à²¾ ಅಪರಿà²à²¿à²¤ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳನà³à²¨à³ ಮà³à²à³à²à²¿à²¦ ಬಳಿಕ ನೀವೠಅಪರಿà²à²¿à²¤ ಮೋಡà³â€Œà²¨à²²à³à²²à²¿ ವೀಕà³à²·à²¿à²¸à²¿à²¦ ಪà³à²Ÿà²—ಳೠಬà³à²°à³Œà²¸à²°à³ ಇತಿಹಾಸದಲà³à²²à²¿, ಕà³à²•à³€ ಸಂಗà³à²°à²¹à²¦à²²à³à²²à²¿ ಅಥವಾ ಹà³à²¡à³à²•à²¾à²Ÿ ಇತಿಹಾಸದಲà³à²²à²¿ ಉಳಿಯà³à²µà³à²¦à²¿à²²à³à²². ನೀವೠಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡà³à²µ ಯಾವà³à²¦à³‡ ಫೈಲà³â€Œà²—ಳೠಇಲà³à²²à²µà³‡ ನೀವೠರà²à²¿à²¸à³à²µ ಯಾವà³à²¦à³‡ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳನà³à²¨à³ ಹಾಗೆಯೇ ಇರಿಸಲಾಗà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">ದà³à²µà³€à²ª</translation>
<translation id="3176929007561373547">ಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³ ಕಾರà³à²¯à²µà²¨à²¿à²°à³à²µà²¹à²¿à²¸à³à²¤à³à²¤à²¿à²¦à³†à²¯à³‡ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಖà²à²¿à²¤à²ªà²¡à²¿à²¸à²¿à²•à³à²³à³à²³à²²à³ ನಿಮà³à²® ಪà³à²°à²¾à²•à³à²¸à²¿ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಿ ಮತà³à²¤à³ ನಿಮà³à²® ನೆಟà³â€Œà²µà²°à³à²•à³ ನಿರà³à²µà²¾à²¹à²•à²°à²¨à³à²¨à³ ಸಂಪರà³à²•à²¿à²¸à²¿. ನೀವೠಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³ ಅನà³à²¨à³ ಬಳಸà³à²¤à³à²¤à²¿à²²à³à²² à²à²‚ಬ ಅನà³à²®à²¾à²¨ ನಿಮಗಿದà³à²¦à²°à³†:
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">ನವನವೀನ</translation>
<translation id="3207960819495026254">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œ ಮಾಡಲಾಗಿದೆ</translation>
-<translation id="3225919329040284222">ಆಂತರಿಕ ಮಾನದಂಡಗಳಿಗೆ ಹà³à²‚ದಿಕೆಯಾಗದ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಹಾಜರಿಪಡಿಸಿದೆ. ನಿಮà³à²® ಸà³à²°à²•à³à²·à²¤à³†à²¯ ಸಲà³à²µà²¾à²—ಿ ಕೆಲವೠಹೆà²à³à²à³ ಸà³à²°à²•à³à²·à²¿à²¤ ವೆಬೠಸೈಟà³â€Œà²—ಳಲà³à²²à²¿ ಈ ಮಾನದಂಡಗಳನà³à²¨à³ ಸೇರà³à²ªà²¡à³†à²—à³à²³à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="3226128629678568754">ಪà³à²Ÿà²µà²¨à³à²¨à³ ಲೋಡೠಮಾಡà³à²µà³à²¦à²•à³à²•à³† ಅಗತà³à²¯à²µà²¿à²°à³à²µ ಡೇಟಾವನà³à²¨à³ ಮರà³à²¸à²²à³à²²à²¿à²¸à²²à³ ಮರà³à²²à³‹à²¡à³ ಬಟನೠಒತà³à²¤à²¿à²°à²¿.</translation>
<translation id="3228969707346345236">ಪà³à²Ÿà²µà³ ಈಗಾಗಲೇ <ph name="LANGUAGE" /> ರಲà³à²²à²¿ ಇರà³à²µà³à²¦à²° ಕಾರಣ ಭಾಷಾಂತರವೠವಿಫಲವಾಗಿದೆ.</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" /> ಗೆ CVC ಅನà³à²¨à³ ನಮೂದಿಸಿ</translation>
<translation id="3254409185687681395">ಈ ಪà³à²Ÿ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³ ಮಾಡಿ</translation>
<translation id="3270847123878663523">&amp;ಮರà³à²•à³à²°à²®à²—ೊಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—à³à²³à²¿à²¸à³</translation>
<translation id="3286538390144397061">ಈಗ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸಿ</translation>
+<translation id="3303855915957856445">ಯಾವà³à²¦à³‡ ಹà³à²¡à³à²•à²¾à²Ÿ ಫಲಿತಾಂಶಗಳೠಕಂಡà³à²¬à²‚ದಿಲà³à²²</translation>
<translation id="3305707030755673451">ನಿಮà³à²® ಡೇಟಾವನà³à²¨à³ <ph name="TIME" /> ರಂದೠನಿಮà³à²® ಸಿಂಕೠಪಾಸà³â€Œà²«à³à²°à³‡à²¸à³â€Œà²¨à³†à³‚ಂದಿಗೆ à²à²¨à³â€Œà²•à³à²°à²¿à²ªà³à²Ÿà³ ಮಾಡಲಾಗಿದೆ. ಸಿಂಕೠಪà³à²°à²¾à²°à²‚ಭಿಸಲೠಅದನà³à²¨à³ ನಮೂದಿಸಿ.</translation>
<translation id="333371639341676808">ಈ ಪà³à²Ÿ ಹೆà²à³à²à³à²µà²°à²¿ ಸಂವಾದಗಳನà³à²¨à³ ರà²à²¿à²¸à³à²µà³à²¦à²¨à³à²¨à³ ತಡೆಯಿರಿ.</translation>
+<translation id="3338095232262050444">ಸà³à²°à²•à³à²·à²¿à²¤</translation>
<translation id="3340978935015468852">ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳà³</translation>
<translation id="3345135638360864351">ಈ ಸೈಟೠಅನà³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ ನೀವೠಸಲà³à²²à²¿à²¸à²¿à²¦ ವಿನಂತಿಯನà³à²¨à³ <ph name="NAME" /> ಗೆ ಕಳà³à²¹à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²². ದಯವಿಟà³à²Ÿà³ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="3355823806454867987">ಪà³à²°à²¾à²•à³à²¸à²¿ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಬದಲಿಸಿ...</translation>
<translation id="3369192424181595722">ಗಡಿಯಾರ ದೋಷ</translation>
<translation id="337363190475750230">ಅನà³à²®à²¤à²¿ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="3377188786107721145">ನೀತಿಯ ಪಾರà³à²¸à³ ದೋಷ</translation>
-<translation id="3380365263193509176">ಅಜà³à²à²¾à²¤ ದೋಷ</translation>
+<translation id="3380365263193509176">ಅಪರಿà²à²¿à²¤ ದೋಷ</translation>
<translation id="3380864720620200369">ಕà³à²²à³ˆà²‚ಟೠID:</translation>
<translation id="340013220407300675"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ರಿಂದ ದಾಳಿಕೋರರೠನಿಮà³à²® ಮಾಹಿತಿಯನà³à²¨à³ ಕಳà³à²³à²¤à²¨ ಮಾಡಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³ (ಉದಾಹರಣೆಗೆ, ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳà³, ಸಂದೇಶಗಳà³, ಅಥವಾ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³â€Œà²—ಳà³).</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ಅನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ ತಲà³à²ªà²²à²¾à²—à³à²¤à³à²¤à²¿à²²à³à²².</translation>
@@ -230,6 +234,7 @@
<translation id="3452404311384756672">ವಿರಾಮವನà³à²¨à³ ಪಡೆಯಿರಿ:</translation>
<translation id="3462200631372590220">ಸà³à²§à²¾à²°à²¿à²¤ ಆಯà³à²•à³†à²®à²¾à²¡à²¿</translation>
<translation id="3479539252931486093">ಇದೠಅನಿರೀಕà³à²·à²¿à²¤à²µà³†à³•? <ph name="BEGIN_LINK" />ನಮಗೆ ತಿಳಿಸಿ<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">ಈಗ ಬೇಡ</translation>
<translation id="348000606199325318">ಕà³à²°à³à²¯à²¾à²¶à³ à²à²¡à²¿ <ph name="CRASH_LOCAL_ID" /> (ಸರà³à²µà²°à³ à²à²¡à²¿: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">ಈ ಕà³à²·à²£à²¦à²²à³à²²à²¿ ನಿಮà³à²® ಪೋಷಕರನà³à²¨à³ ತಲà³à²ªà²²à³ ನಮಗೆ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²². ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="3527085408025491307">ಫೋಲà³à²¡à²°à³</translation>
@@ -238,6 +243,7 @@
<translation id="3542684924769048008">ಇದಕà³à²•à³† ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಬಳಸಿ:</translation>
<translation id="3549644494707163724">ನಿಮà³à²® ಸà³à²µà²‚ತ ಸಿಂಕೠಪಾಸà³â€Œà²«à³à²°à³‡à²¸à³â€Œà²¨à³†à³‚ಂದಿಗೆ ಸಿಂಕೠಆದ à²à²²à³à²²à²¾ ಡೇಟಾವನà³à²¨à³ à²à²¨à³â€Œà²•à³à²°à²¿à²ªà³à²Ÿà³ ಮಾಡಿ</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> ಇನà³à²¨à²·à³à²Ÿà³...</translation>
+<translation id="3555561725129903880">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ <ph name="DOMAIN2" /> ರಿಂದ ಆಗಿರಬಹà³à²¦à³. ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">ನಿಮà³à²® ಸಂಪರà³à²•à²µà³ ಖಾಸಗಿಯಲà³à²²</translation>
<translation id="3583757800736429874">&amp;ಸರಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
<translation id="3586931643579894722">ವಿವರಗಳನà³à²¨à³ ಮರೆಮಾಡಿ</translation>
@@ -248,12 +254,15 @@
<translation id="362276910939193118">ಪೂರà³à²£ ಇತಿಹಾಸ ತೋರಿಸಿ</translation>
<translation id="3623476034248543066">ಮೌಲà³à²¯à²µà²¨à³à²¨à³ ತೋರಿಸಿ</translation>
<translation id="3630155396527302611">ಒಂದೠವೇಳೆ ನೆಟà³â€Œà²µà²°à³à²•à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ ಅನà³à²®à²¤à²¿à²¸à³à²µ ಒಂದೠಪà³à²°à³à²—à³à²°à²¾à²‚ನಂತೆ ಇದನà³à²¨à³ ಈಗಾಗಲೇ ಪಟà³à²Ÿà²¿ ಮಾಡಲಾಗಿದà³à²¦à²°à³†, ಅದನà³à²¨à³ ಪಟà³à²Ÿà²¿à²¯à²¿à²‚ದ ತೆಗೆಯಲೠಮತà³à²¤à³ ಪà³à²¨à²ƒ ಅದನà³à²¨à³ ಸೇರಿಸಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
+<translation id="3638794133396384728">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿ ಮà³à²—ಿದಿದೆ. ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ಗಡಿಯಾರವನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ <ph name="CURRENT_TIME" /> ಗೆ ಹà³à²‚ದಿಸಲಾಗಿದೆ. ಅದೠಸರಿಯಾಗಿ ತೋರà³à²¤à³à²¤à²¿à²¦à³†à²¯à³†? ಇಲà³à²²à²µà²¾à²¦à²°à³†, ನಿಮà³à²® ಸಿಸà³à²Ÿà²‚ನ ಗಡಿಯಾರವನà³à²¨à³ ನೀವೠಸರಿಪಡಿಸಬೇಕೠಹಾಗೂ ನಂತರ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ರಿಫà³à²°à³†à²¶à³ ಮಾಡಿ. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">ಈ ಪà³à²°à²¾à²¯à³‹à²—ಿಕ ವೈಶಿಷà³à²Ÿà³à²¯à²—ಳೠಯಾವà³à²¦à³‡ ಸಮಯದಲà³à²²à²¾à²¦à²°à³‚ ಬದಲಾಗಬಹà³à²¦à³, ಒಡೆಯಬಹà³à²¦à³, ಅಥವಾ ಕಾಣೆಯಾಗಬಹà³à²¦à³. ಒಂದೠಪà³à²°à²¯à³‹à²—ವನà³à²¨à³ ಆನೠಮಾಡಿದರೆ à²à²¨à³ ಆಗಬಹà³à²¦à³ à²à²‚ಬà³à²µà³à²¦à²° ಬಗà³à²—ೆ ನಾವೠಯಾವà³à²¦à³‡ ಖಾತà³à²°à²¿à²—ಳನà³à²¨à³ ನೀಡà³à²µà³à²¦à²¿à²²à³à²², ಮತà³à²¤à³ ನಿಮà³à²® ಬà³à²°à³Œà²¸à²°à³ ನಿರಂತರವಾಗಿ ದಹನಕà³à²•à³à²³à²—ಾಗಬಹà³à²¦à³. ಜೋಕà³â€Œà²—ಳೠಆ ಕಡೆ ಇರಲಿ, ನಿಮà³à²® ಬà³à²°à³Œà²¸à²°à³ ನಿಮà³à²® à²à²²à³à²² ಡೇಟಾವನà³à²¨à³ ಅಳಿಸಿ ಹಾಕಬಹà³à²¦à³, ಅಥವಾ ನಿಮà³à²® ಸà³à²°à²•à³à²·à²¿à²¤ ಮತà³à²¤à³ ಗೌಪà³à²¯à²¤à³†à²¯à³ ಅನಿರೀಕà³à²·à²¿à²¤ ರೀತಿಯಲà³à²²à²¿ ಧಕà³à²•à³†à²¯à³à²‚ಟಾಗಬಹà³à²¦à³. ಯಾವà³à²¦à³‡ ಪà³à²°à²¯à³‹à²—ಗಳನà³à²¨à³ ನೀವೠಸಕà³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²¿à²¦à²²à³à²²à²¿ ಈ ಬà³à²°à³Œà²¸à²°à³â€Œà²¨ à²à²²à³à²² ಬಳಕೆದಾರರಿಗೂ ಸಕà³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à²¾à²—à³à²µà³à²¦à³. ದಯವಿಟà³à²Ÿà³ à²à²à³à²à²°à²¿à²•à³†à²¯à²¿à²‚ದ ಮà³à²‚ದà³à²µà²°à²¿à²¯à²¿à²°à²¿.</translation>
<translation id="3650584904733503804">à²à²°à³à²œà²¿à²¤à²—à³à²³à²¿à²¸à³à²µà²¿à²•à³†à²¯à³ ಯಶಸà³à²µà²¿à²¯à²¾à²—ಿದೆ</translation>
<translation id="3655670868607891010">ಇದೠನಿಮಗೆ ಪದೇ ಪದೇ à²à²¦à³à²°à²¾à²—à³à²¤à³à²¤à²¿à²¦à³à²¦à²°à³†, <ph name="HELP_LINK" /> ಇವà³à²—ಳನà³à²¨à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="3658742229777143148">ಪರಿಷà³à²•à²°à²£à³†</translation>
+<translation id="3678029195006412963">ವಿನಂತಿಗೆ ಸಹಿ ಮಾಡಲಾಗà³à²µà³à²¦à²¿à²²à³à²²</translation>
<translation id="3681007416295224113">ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಮಾಹಿತಿ</translation>
<translation id="3693415264595406141">ಪಾಸà³â€Œà²µà²°à³à²¡à³:</translation>
+<translation id="3696411085566228381">ಯಾವà³à²¦à³‚ ಇಲà³à²²</translation>
<translation id="3700528541715530410">ಓಹà³â€Œ, ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ ನಿಮಗೆ ಅನà³à²®à²¤à²¿ ಇಲà³à²² à²à²‚ದೠತೋರà³à²¤à³à²¤à²¿à²¦à³†.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">ಲೋಡೠಮಾಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
@@ -261,7 +270,6 @@
<translation id="3714780639079136834">ಮà³à²¬à³ˆà²²à³ ಡೇಟಾ ಅಥವಾ ವೈ-ಫೈ ಆನೠಮಾಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ಪà³à²°à²¾à²•à³à²¸à²¿, ಫೈರà³â€Œà²µà²¾à²²à³ ಮತà³à²¤à³ DNS ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œâ€Œ ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">ನೀವೠನಕಲಿಸಿದ ಲಿಂಕà³</translation>
-<translation id="3744899669254331632">ನೀವೠಇದೀಗ <ph name="SITE" /> ಗೆ ಭೇಟಿ ನೀಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²² à²à²•à³†à²‚ದರೆ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³ Chromium ಗೆ ಪà³à²°à²•à³à²°à²¿à²¯à³†à²—à³à²³à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ದ ಅವà³à²¯à²µà²¸à³à²¥à²¿à²¤ ರà³à²œà³à²µà²¾à²¤à³à²—ಳನà³à²¨à³ ಕಳà³à²¹à²¿à²¸à²¿à²¦à³†. ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ಆಕà³à²°à²®à²£à²—ಳೠಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿರà³à²¤à³à²¤à²µà³†, ಆದà³à²¦à²°à²¿à²‚ದ ಈ ಪà³à²Ÿà²µà³ ಬಹà³à²¶à²ƒ ನಂತರ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="375403751935624634">ಸರà³à²µà²°à³ ದೋಷದ ಕಾರಣ ಅನà³à²µà²¾à²¦à²µà³ ವಿಫಲವಾಗಿದೆ.</translation>
<translation id="3759461132968374835">ಇತà³à²¤à³€à²à³†à²—ೆ ನೀವೠಯಾವà³à²¦à³‡ ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œà²—ಳನà³à²¨à³ ವರದಿ ಮಾಡಿಲà³à²². ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œâ€Œ ಅನà³à²¨à³ ವರದಿಮಾಡà³à²µà²¿à²•à³†à²¯à²¨à³à²¨à³ ಉಂಟಾಗಿರà³à²µ ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œà²—ಳೠಇಲà³à²²à²¿ ಗೋà²à²°à²¿à²¸à³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="3788090790273268753">ಈ ಸೈಟà³â€Œà²—ೆ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿಯೠ2016 ರಲà³à²²à²¿ ಮà³à²•à³à²¤à²¾à²¯à²—à³à²³à³à²³à³à²¤à³à²¤à²¦à³† ಮತà³à²¤à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಸರಣಿಯೠSHA-1 ಬಳಸಿಕà³à²‚ಡೠಸಹಿ ಮಾಡಲಾದ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಒಳಗೊಂಡಿರà³à²¤à³à²¤à²¦à³†.</translation>
@@ -273,19 +281,25 @@
<translation id="3884278016824448484">ಸಂಘರà³à²·à²—à³à²³à³à²³à³à²¤à³à²¤à²¿à²°à³à²µ ಸಾಧನ ಗà³à²°à³à²¤à²¿à²¸à³à²µà²¿à²•à³†</translation>
<translation id="3885155851504623709">ಪಾರಿಷà³</translation>
<translation id="3901925938762663762">ಕಾರà³à²¡à³ ಅವಧಿಯೠಮà³à²—ಿದಿದೆ</translation>
+<translation id="3910267023907260648">ನೀವೠ<ph name="DOMAIN" /> ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²°à³à²µà²¿à²°à²¿, ಆದರೆ ದà³à²°à³à²¬à²² ಸಹಿ ಅಲà³à²—ಾರಿದಮೠಬಳಸಿಕà³à²‚ಡೠಸಹಿ ಮಾಡಿದ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಪà³à²°à²¸à³à²¤à³à²¤à²ªà²¡à²¿à²¸à²¿à²¦à³†. ಇದರರà³à²¥ ಸರà³à²µà²°à³ ಪà³à²°à²¸à³à²¤à³à²¤à²ªà²¡à²¿à²¸à²¿à²¦ ಸà³à²°à²•à³à²·à²¤à²¾ ರà³à²œà³à²µà²¾à²¤à³à²—ಳೠನಕಲಿ ಆಗಿರಬಹà³à²¦à³ ಮತà³à²¤à³ ನೀವೠನಿರೀಕà³à²·à²¿à²¸à²¿à²¦ ಸರà³à²µà²°à³ ಅದಾಗಿರದೇ ಇರಬಹà³à²¦à³ (ನೀವೠಆಕà³à²°à²®à²£à²•à²¾à²°à²° ಜà³à²¤à³†à²—ೆ ಸಂವಹನ ಮಾಡà³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³). <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ; ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಬಹà³à²¶à²ƒ ನಾಳೆಯಿಂದ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.}one{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಬಹà³à²¶à²ƒ ಭವಿಷà³à²¯à²¦à²²à³à²²à²¿ # ದಿನಗಳಲà³à²²à²¿ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.}other{ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಬಹà³à²¶à²ƒ ಭವಿಷà³à²¯à²¦à²²à³à²²à²¿ # ದಿನಗಳಲà³à²²à²¿ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF ಡಾಕà³à²¯à³à²®à³†à²‚ಟೠಅನà³à²¨à³ ಲೋಡೠಮಾಡಲೠವಿಫಲವಾಗಿದೆ</translation>
<translation id="3963721102035795474">ರೀಡರà³â€Œ ಮೋಡà³â€Œ</translation>
+<translation id="397105322502079400">à²à²£à²¿à²¸à²²à²¾à²—à³à²¤à³à²¤à²¿à²¦à³†...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> ಅನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{ಹತà³à²¤à²¿à²°à²¦ 1 ವೆಬೠಪà³à²Ÿ}one{ಹತà³à²¤à²¿à²°à²¦ # ವೆಬೠಪà³à²Ÿà²—ಳà³}other{ಹತà³à²¤à²¿à²°à²¦ # ವೆಬೠಪà³à²Ÿà²—ಳà³}}</translation>
<translation id="4021036232240155012">DNS à²à²¨à³à²¨à³à²µà³à²¦à³ ನೆಟà³â€Œà²µà²°à³à²•à³ ಸೇವೆಯಾಗಿದà³à²¦à³ ಇದೠವೆಬà³â€Œà²¸à³ˆà²Ÿà³ ಹೆಸರನà³à²¨à³ ಅದರ ಇಂಟರà³à²¨à³†à²Ÿà³ ವಿಳಾಸವಾಗಿ ಪರಿವರà³à²¤à²¿à²¸à³à²¤à³à²¤à²¦à³†.</translation>
<translation id="4030383055268325496">&amp;ಸೇರಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—à³à²³à²¿à²¸à²¿</translation>
-<translation id="4032534284272647190"><ph name="URL" /> ಗೆ ಪà³à²°à²µà³‡à²¶à²µà²¨à³à²¨à³ ನಿರಾಕರಿಸಲಾಗಿದೆ.</translation>
<translation id="404928562651467259">à²à²à³à²à²°à²¿à²•à³†</translation>
<translation id="4058922952496707368">ಕೀ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">ಸಾಮಾನà³à²¯ SSL ಪà³à²°à³à²Ÿà³‹à²•à²¾à²²à³ ಆವೃತà³à²¤à²¿ ಅಥವಾ ಸೈಫರೠಸà³à²¯à³‚ಟೠಅನà³à²¨à³ ಕà³à²²à³ˆà²‚ಟೠಮತà³à²¤à³ ಸರà³à²µà²°à³ ಬೆಂಬಲಿಸà³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="4079302484614802869">ಪà³à²°à²¾à²•à³à²¸à²¿ ಕಾನà³à²«à²¿à²—ರೇಶನೠಅನà³à²¨à³ .pac ಸà³à²•à³à²°à²¿à²ªà³à²Ÿà³ URL ಬಳಸà³à²µà²‚ತೆ ಹà³à²‚ದಿಸಲಾಗಿದೆ, ಹà³à²‚ದಿಸಿದ ಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³â€Œà²—ಳಲà³à²².</translation>
<translation id="4103249731201008433">ಸಾಧನದ ಸರಣಿಯ ಸಂಖà³à²¯à³† ಅಮಾನà³à²¯à²µà²¾à²—ಿದೆ</translation>
<translation id="4103763322291513355">ನಿಮà³à²® ಸಿಸà³à²Ÿà²‚ ನಿರà³à²µà²¾à²¹à²•à²°à³ ವಿಧಿಸಿರà³à²µ ಕಪà³à²ªà³à²ªà²Ÿà³à²Ÿà²¿à²¯ URLಗಳೠಮತà³à²¤à³ ಇತರ ನೀತಿಗಳನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³ &lt;strong&gt;chrome://policy&lt;/strong&gt; ಗೆ ಭೇಟಿ ನೀಡಿ.</translation>
+<translation id="4110615724604346410">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ದೋಷಗಳನà³à²¨à³ ಹà³à²‚ದಿರಬಹà³à²¦à³. ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">ನೀತಿಯ ವà³à²¯à²¾à²ªà³à²¤à²¿à²¯à³ ಬೆಂಬಲಿತವಾಗಿಲà³à²².</translation>
+<translation id="4118212371799607889">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ Chromium ನಿಂದ ವಿಶà³à²µà²¾à²¸à²¹à³à²‚ದಿಲà³à²². ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 ಇತರೆ}one{# ಇತರೆ}other{# ಇತರೆ}}</translation>
<translation id="4130226655945681476">ನೆಟà³â€Œà²µà²°à³à²•à³ ಕೇಬಲà³â€Œà²—ಳà³, ಮà³à²¡à³†à²®à³ ಮತà³à²¤à³ ರೂಟರೠಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">ಈ ಕಾರà³à²¡à³ ಅನà³à²¨à³ Chromium ಉಳಿಸಬೇಕೆಂದೠನೀವೠಬಯಸà³à²µà²¿à²°à²¾?</translation>
@@ -293,6 +307,7 @@
<translation id="4176463684765177261">ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
<translation id="4196861286325780578">&amp;ಸರಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ಫೈರà³â€Œà²µà²¾à²²à³ ಮತà³à²¤à³ ಆಂಟಿವೈರಸೠಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œâ€Œà²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{ಯಾವà³à²¦à³‚ ಇಲà³à²²}=1{1 ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œ ($1)}=2{2 ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳೠ($1, $2)}one{# ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳೠ($1, $2, $3)}other{# ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳೠ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">ವಿಫಲತೆಗಳà³</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />ನೆಟà³â€Œà²µà²°à³à²•à³ ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³â€Œ ರನೠಮಾಡಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">ಇಲà³à²²</translation>
@@ -301,14 +316,15 @@
<translation id="4269787794583293679">(ಯಾವà³à²¦à³ ಬಳಕೆದಾರಹೆಸರಿಲà³à²²)</translation>
<translation id="4300246636397505754">ಪೋಷಕ ಸಲಹೆಗಳà³</translation>
<translation id="4304224509867189079">ಲಾಗೠಇನà³</translation>
+<translation id="432290197980158659">ಅಂತರà³â€Œà²¨à²¿à²°à³à²®à²¿à²¤ ನಿರೀಕà³à²·à³†à²—ಳಿಗೆ ಹà³à²‚ದಿಕೆಯಾಗದ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಪà³à²°à²¸à³à²¤à³à²¤à²ªà²¡à²¿à²¸à²¿à²¦à³†. ಈ ನಿರೀಕà³à²·à³†à²—ಳೠನಿಮà³à²®à²¨à³à²¨à³ ರಕà³à²·à²¿à²¸à³à²µ ಸಲà³à²µà²¾à²—ಿ ಕೆಲವೠಉನà³à²¨à²¤ ಸà³à²°à²•à³à²·à²¤à²¾ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳನà³à²¨à³ ಒಳಗà³à²‚ಡಿವೆ. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">ಲೇಖನ ಕಂಡà³à²¬à²°à²²à²¿à²²à³à²²</translation>
+<translation id="4331708818696583467">ಸà³à²°à²•à³à²·à²¿à²¤à²µà²²à³à²²</translation>
<translation id="4372948949327679948">ನಿರೀಕà³à²·à²¿à²¤ <ph name="VALUE_TYPE" /> ಮೌಲà³à²¯.</translation>
-<translation id="4377125064752653719">ನೀವೠ<ph name="DOMAIN" /> ಅನà³à²¨à³ ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²¦à²¿à²°à²¿, ಆದರೆ ಸರà³à²µà²°à³ ನೀಡಿದ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಅದರ ನೀಡà³à²µà²µà²°à³ ಹಿಂತೆಗೆದà³à²•à³à²‚ಡಿದà³à²¦à²¾à²°à³†. ಇದರರà³à²¥ ಸರà³à²µà²°à³ ನೀಡಿದ ಸà³à²°à²•à³à²·à²¤à³† ರà³à²œà³à²µà²¾à²¤à³à²—ಳನà³à²¨à³ ಖಂಡಿತವಾಗಿ ನಂಬಲಾಗà³à²µà³à²¦à²¿à²²à³à²². ನೀವೠಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³à²‚ದಿಗೆ ಸಂವಹಿಸà³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³.</translation>
<translation id="4381091992796011497">ಬಳಕೆದಾರ ಹೆಸರೠ:</translation>
<translation id="4394049700291259645">ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²¿</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> ನಿಂದ <ph name="END_DATE" /> ವರೆಗೆ</translation>
<translation id="4406896451731180161">ಹà³à²¡à³à²•à²¾à²Ÿà²¦ ಫಲಿತಾಂಶಗಳà³</translation>
-<translation id="4424024547088906515">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ Chrome ಪಾಲಿಗೆ ವಿಶà³à²µà²¾à²¸à²¾à²°à³à²¹à²µà²¾à²—ಿಲà³à²². ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> ನಿಮà³à²® ಲಾಗಿನೠಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸà³à²µà³€à²•à²°à²¿à²¸à²²à²¿à²²à³à²² ಅಥವಾ ಅದನà³à²¨à³ ಒದಗಿಸದೆ ಇರಬಹà³à²¦à³.</translation>
<translation id="443673843213245140">ಪà³à²°à²¾à²•à³à²¸à²¿à²¯ ಬಳಕೆಯನà³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à²¾à²—ಿದೆ ಆದರೆ ಬಹಿರಂಗ ಪà³à²°à²¾à²•à³à²¸à²¿ ಕಾನà³à²«à²¿à²—ರೇಶನೠಅನà³à²¨à³ ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Google SafeSites ಸಕà³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದಾಗಿ ನೀವೠಈ ಸಂದೇಶ ವೀಕà³à²·à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿.</translation>
@@ -320,12 +336,12 @@
<translation id="4522570452068850558">ವಿವರಗಳà³</translation>
<translation id="4558551763791394412">ನಿಮà³à²® ವಿಸà³à²¤à²°à²£à³†à²—ಳನà³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="4587425331216688090">Chrome ನಿಂದ ವಿಳಾಸವನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
+<translation id="4589078953350245614">ನೀವೠ<ph name="DOMAIN" /> ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²°à³à²µà²¿à²°à²¿, ಆದರೆ ಮಾನà³à²¯à²µà²²à³à²²à²¦ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಪà³à²°à²¸à³à²¤à³à²¤à²ªà²¡à²¿à²¸à²¿à²¦à³†. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">ಆಧà³à²¨à²¿à²• ಸೈಫರೠಸೂಟೠಬಳಸà³à²µ ಮೂಲಕ <ph name="DOMAIN" /> ಗೆ ನಿಮà³à²® ಸಂಪರà³à²•à²µà²¨à³à²¨à³ à²à²¨à³â€Œà²•à³à²°à²¿à²ªà³à²Ÿà³ ಮಾಡಲಾಗಿದೆ.</translation>
<translation id="4594403342090139922">&amp;ಅಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—ೊಳಿಸಿ</translation>
+<translation id="4627442949885028695">ಬೇರೆ ಸಾಧನದಿಂದ ಮà³à²‚ದà³à²µà²°à²¿à²¸à²¿</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">ನೀವೠವಿಸà³à²¤à²°à²£à³†à²¯ ಪà³à²Ÿà²µà²¨à³à²¨à³ ವೀಕà³à²·à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿.</translation>
-<translation id="467662567472608290">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦à²²à³à²²à²¿ ಸಾಕಷà³à²Ÿà³ ದೋಷಗಳಿವೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> ಅನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">ನಿಮà³à²® ಸಂಪರà³à²•à²•à³à²•à³† ಅಡà³à²¡à²¿à²¯à²¾à²—ಿದೆ</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows ನೆಟà³â€Œà²µà²°à³à²•à³ ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³ ರನೠಮಾಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
@@ -333,21 +349,26 @@
<translation id="4728558894243024398">ಪà³à²²à²¾à²Ÿà³â€Œà²«à²¾à²°à³à²®à³</translation>
<translation id="4744603770635761495">ಪà³à²°à²¦à²°à³à²¶à²¨à²—à³à²³à³à²³à³à²µà²‚ತಹ ಹಾದಿ</translation>
<translation id="4756388243121344051">&amp;ಇತಿಹಾಸ</translation>
+<translation id="4759238208242260848">ಡೌನà³â€Œà²²à³‹à²¡à³â€Œà²—ಳà³</translation>
<translation id="4764776831041365478"><ph name="URL" /> ನಲà³à²²à²¿à²°à³à²µ ವೆಬà³â€Œà²ªà³à²Ÿà²µà³ ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¦à³‡ ಇರಬಹà³à²¦à³ ಅಥವಾ ಅದನà³à²¨à³ ಶಾಶà³à²µà²¤à²µà²¾à²—ಿ ಹà³à²¸ ವೆಬೠವಿಳಾಸಕà³à²•à³† ಸರಿಸಲಾಗಿರಬಹà³à²¦à³.</translation>
-<translation id="4771973620359291008">ಅಜà³à²à²¾à²¤ ದೋಷವà³à²‚ದೠà²à²¦à³à²°à²¾à²—ಿದೆ.</translation>
+<translation id="4771973620359291008">ಅಪರಿà²à²¿à²¤ ದೋಷವà³à²‚ದೠà²à²¦à³à²°à²¾à²—ಿದೆ.</translation>
<translation id="4782449893814226250">ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ಭೇಟಿ ಮಾಡಬಹà³à²¦à³ à²à²‚ದೠನಿಮà³à²® ಪೋಷಕರಿಗೆ ನೀವೠಕೇಳಿರà³à²µà²¿à²°à²¿.</translation>
<translation id="4800132727771399293">ನಿಮà³à²® ಮà³à²•à³à²¤à²¾à²¯à²¦ ದಿನಾಂಕ ಮತà³à²¤à³ CVC ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿</translation>
-<translation id="4807049035289105102">ನಿಮಗೆ ಸದà³à²¯à²•à³à²•à³† <ph name="SITE" /> ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œâ€Œà²—ೆ ಭೇಟಿ ನೀಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². à²à²•à³†à²‚ದರೆ, ಈ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œâ€Œ Google Chrome ಪà³à²°à²•à³à²°à²¿à²¯à³†à²—à³à²³à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ದಂಥ ರà³à²œà³à²µà²¾à²¤à³à²—ಳನà³à²¨à³ ರವಾನಿಸಿದೆ. ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ಆಕà³à²°à²®à²£à²—ಳೠತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿರà³à²¤à³à²¤à²µà³†. ಹೀಗಾಗಿ ಈ ಪà³à²Ÿà²µà³ ಬಹà³à²¶à²ƒ ನಂತರ ಕಾರà³à²¯ ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="4813512666221746211">ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷ</translation>
<translation id="4816492930507672669">ಪà³à²Ÿà²•à³à²•à³† ಹà³à²‚ದಿಸà³</translation>
<translation id="4850886885716139402">ವೀಕà³à²·à²£à³†</translation>
<translation id="4880827082731008257">ಹà³à²¡à³à²•à²¾à²Ÿ ಇತಿಹಾಸ</translation>
+<translation id="4884656795097055129">ಸಮಯವೠಸರಿಯಾಗಿರà³à²µà²¾à²— ಹೆà²à³à²à³ ಲೇಖನಗಳೠಕಾಣಿಸಿಕà³à²³à³à²³à³à²¤à³à²¤à²µà³†.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{ಮತà³à²¤à³ 1 ಹೆà²à³à²à²¿à²¨ ವೆಬೠಪà³à²Ÿ}one{ಮತà³à²¤à³ # ಹೆà²à³à²à²¿à²¨ ವೆಬೠಪà³à²Ÿà²—ಳà³}other{ಮತà³à²¤à³ # ಹೆà²à³à²à²¿à²¨ ವೆಬೠಪà³à²Ÿà²—ಳà³}}</translation>
<translation id="4923417429809017348">ಗà³à²¤à³à²¤à²¿à²²à³à²²à²¦ ಭಾಷೆಯಿಂದ <ph name="LANGUAGE_LANGUAGE" /> ಗೆ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ಭಾಷಾಂತರಿಸಲಾಗಿದೆ</translation>
<translation id="4926049483395192435">ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²¬à³‡à²•à²¾à²—ಿದೆ.</translation>
<translation id="4930497775425430760">ನಿಮà³à²® ಮà³à²¦à²² ಭೇಟಿಯಲà³à²²à²¿ ನಿಮà³à²® ಪೋಷಕರೠಹà³à²¸ ಸೈಟà³â€Œà²—ಳನà³à²¨à³ ಅಂಗೀಕರಿಸಬೇಕಾಗಿರà³à²µ ಕಾರಣ ನೀವೠಈ ಸಂದೇಶವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿.</translation>
<translation id="495170559598752135">ಕà³à²°à²¿à²¯à³†à²—ಳà³</translation>
<translation id="4958444002117714549">ಪಟà³à²Ÿà²¿à²¯à²¨à³à²¨à³ ವಿಸà³à²¤à²°à²¿à²¸à²¿</translation>
+<translation id="4962322354953122629">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ Chrome ನಿಂದ ವಿಶà³à²µà²¾à²¸à²¹à³à²‚ದಿಲà³à²². ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911"><ph name="ORIGINAL_LANGUAGE" /> ರಿಂದ <ph name="TARGET_LANGUAGE" /> ಗೆ ಅನà³à²µà²¾à²¦à²¿à²¸à²¬à³‡à²•à³‡?</translation>
+<translation id="4989809363548539747">ಈ ಪà³à²²à²—ಿನೠಬೆಂಬಲಿಸà³à²µà³à²¦à²¿à²²à³à²²</translation>
<translation id="5002932099480077015">ಸಕà³à²°à²¿à²¯à²µà²¾à²—ಿದà³à²¦à²°à³†, ವೇಗವಾಗಿ ಫಾರà³à²®à³ ಭರà³à²¤à²¿ ಮಾಡಲೠChrome ಈ ಸಾಧನದಲà³à²²à²¿ ನಿಮà³à²® ಕಾರà³à²¡à³â€Œà²¨ ಪà³à²°à²¤à²¿à²¯à²¨à³à²¨à³ ಸಂಗà³à²°à²¹à²¿à²¸à³à²¤à³à²¤à²¦à³†.</translation>
<translation id="5019198164206649151">ಕಳಪೆ ಸà³à²¥à²¿à²¤à²¿à²¯à²²à³à²²à²¿ ಸಂಗà³à²°à²¹à²£à³†à²¯à²¨à³à²¨à³ ಹಿಂತಿರà³à²—ಿಸಲಾಗಿದೆ</translation>
<translation id="5023310440958281426">ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²• ನೀತಿಗಳನà³à²¨à³ ಪರಿಶೀಲಿಸಿ</translation>
@@ -355,13 +376,12 @@
<translation id="5031870354684148875">Google ಅನà³à²µà²¾à²¦à²¦ ಕà³à²°à²¿à²¤à³</translation>
<translation id="5040262127954254034">ಗೌಪà³à²¯à²¤à³†</translation>
<translation id="5045550434625856497">ತಪà³à²ªà³ ಪಾಸà³â€Œà²µà²°à³à²¡à³</translation>
+<translation id="5056549851600133418">ನಿಮಗಾಗಿ ಲೇಖನಗಳà³</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />ಪà³à²°à²¾à²•à³à²¸à²¿ ವಿಳಾಸವನà³à²¨à³ ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">ಈ ಸಮಯದಲà³à²²à²¿ ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಮಾನà³à²¯à²µà²¾à²—ಿಲà³à²².</translation>
<translation id="5089810972385038852">ರಾಜà³à²¯</translation>
-<translation id="5094747076828555589">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ Chromium ಮೂಲಕ ವಿಶà³à²µà²¾à²¸à²¾à²°à³à²¹à²µà²¾à²—ಿಲà³à²². ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="5095208057601539847">ಪà³à²°à²¾à²‚ತà³à²¯</translation>
<translation id="5115563688576182185">(64-ಬಿಟà³)</translation>
-<translation id="5122371513570456792">'<ph name="SEARCH_STRING" />' ಗೆ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ನà³à²¨à³ ಹà³à²¡à³à²•à²²à²¾à²—ಿದೆ.</translation>
<translation id="5141240743006678641">ನಿಮà³à²® Google ರà³à²œà³à²µà²¾à²¤à³à²—ಳ ಜೊತೆಗೆ ಸಿಂಕೠಮಾಡಿದ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ à²à²¨à³â€Œà²•à³à²°à²¿à²«à³à²Ÿà³ ಮಾಡಿ</translation>
<translation id="5145883236150621069">ನೀತಿ ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à³†à²¯à²²à³à²²à²¿ ದೋಷದ ಕೋಡೠಅಸà³à²¤à²¿à²¤à³à²µà²¦à²²à³à²²à²¿à²¦à³†</translation>
<translation id="5171045022955879922">ಹà³à²¡à³à²•à²¾à²Ÿ ನಡೆಸಿ ಅಥವಾ URL ಅನà³à²¨à³ ಟೈಪà³â€Œ ಮಾಡಿ</translation>
@@ -370,18 +390,18 @@
<translation id="5190835502935405962">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳ ಬಾರà³</translation>
<translation id="5199729219167945352">ಪà³à²°à²¯à³‹à²—ಗಳà³</translation>
<translation id="5251803541071282808">ಮೇಘ</translation>
+<translation id="5277279256032773186">ಕೆಲಸದಲà³à²²à²¿ Chrome ಬಳಸà³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¾? ತಮà³à²® ಉದà³à²¯à³‹à²—ಿಗಳಿಗಾಗಿ ವà³à²¯à²µà²¹à²¾à²°à²—ಳಲà³à²²à²¿ Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳೠನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ</translation>
<translation id="5299298092464848405">ನೀತಿಯ ಪಾರà³à²¸à²¿à²‚ಗà³â€Œà²¨à²²à³à²²à²¿ ದೋಷ</translation>
<translation id="5300589172476337783">ಪà³à²°à²¦à²°à³à²¶à²¿à²¸à²¿</translation>
<translation id="5308689395849655368">ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œâ€Œ ವರದಿಯನà³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="5317780077021120954">ಉಳಿಸà³</translation>
<translation id="5327248766486351172">ಹೆಸರà³</translation>
+<translation id="5359637492792381994">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ಈ ಸಮಯದಲà³à²²à²¿ ಮಾನà³à²¯à²µà²¾à²—ಿಲà³à²². ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">ನೀತಿಯ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಸಂಗà³à²°à²¹à²¿à²¸à³à²µà²²à³à²²à²¿ ವಿಫಲವಾಗಿದೆ</translation>
-<translation id="540969355065856584">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಈ ಸಮಯದಲà³à²²à²¿ ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ಮಾನà³à²¯à²µà²¾à²—ಿಲà³à²². ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="5421136146218899937">ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಡೇಟಾವನà³à²¨à³ ತೆರವà³à²—à³à²³à²¿à²¸à²¿...</translation>
<translation id="5430298929874300616">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œ ತೆಗೆದà³à²¹à²¾à²•à²¿</translation>
<translation id="5431657950005405462">ನಿಮà³à²® ಫೈಲೠಕಂಡà³à²¬à²‚ದಿಲà³à²²</translation>
<translation id="5435775191620395718">ಈ ಸಾಧನದಿಂದ ಇತಿಹಾಸವನà³à²¨à³ ತೋರಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†. <ph name="BEGIN_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">ನಿಮà³à²® ಸಿಂಕೠಮಾಡಲಾದ ಡೇಟಾವೠಕಸà³à²Ÿà²®à³ ಪಾಸà³â€Œà²«à³à²°à³‡à²¸à³â€Œà²¨à²¿à²‚ದ ರಕà³à²·à²¿à²¤à²µà²¾à²—ಿರà³à²µ ಕಾರಣದಿಂದ ವೈಯಕà³à²¤à³€à²•à²°à²¿à²¸à²¿à²¦ ವಿಷಯ ಸಲಹೆಗಳನà³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤ ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" ನಲà³à²²à²¿ ಸà³à²•à³€à²®à²¾ ಮೌಲà³à²µà³€à²•à²°à²£ ದೋಷ: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">ಈ <ph name="HOST_NAME" /> ಪà³à²Ÿ ಕಂಡà³à²¬à²°à³à²µà³à²¦à²¿à²²à³à²²</translation>
<translation id="5455374756549232013">ತಪà³à²ªà²¾à²¦ ನೀತಿಯ ಸಮಯಸà³à²Ÿà³à²¯à²¾à²‚ಪà³</translation>
@@ -404,14 +424,18 @@
<translation id="5622887735448669177">ನೀವೠಈ ಸೈಟೠತà³à²°à³†à²¯à²²à³ ಬಯಸà³à²¤à³à²¤à³€à²°à²¾?</translation>
<translation id="5629630648637658800">ನೀತಿಯ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಲೋಡೠಮಾಡà³à²µà²²à³à²²à²¿ ವಿಫಲವಾಗಿದೆ</translation>
<translation id="5631439013527180824">ಅಮಾನà³à²¯à²µà²¾à²¦ ಸಾಧನ ನಿರà³à²µà²¹à²£à³† ಟೋಕನà³</translation>
-<translation id="5650551054760837876">ಯಾವà³à²¦à³‡ ಫಲಿತಾಂಶಗಳೠಕಂಡà³à²¬à²‚ದಿಲà³à²².</translation>
<translation id="5677928146339483299">ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="5710435578057952990">ಈ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²¨ ಗà³à²°à³à²¤à²¿à²¸à³à²µà²¿à²•à³†à²¯à²¨à³à²¨à³ ಇನà³à²¨à³‚ ಪರಿಶೀಲಿಸಲಾಗಿಲà³à²².</translation>
<translation id="5720705177508910913">ಪà³à²°à²¸à³à²¤à³à²¤ ಬಳಕೆದಾರ</translation>
+<translation id="572328651809341494">ಇತà³à²¤à³€à²à²¿à²¨ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳà³</translation>
<translation id="5784606427469807560">ನಿಮà³à²® ಕಾರà³à²¡à³ ಅನà³à²¨à³ ದೃಢೀಕರಿಸà³à²µà²²à³à²²à²¿ ಸಮಸà³à²¯à³† ಇದೆ. ನಿಮà³à²® ಇಂಟರà³à²¨à³†à²Ÿà³ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="5785756445106461925">ಅಲà³à²²à²¦à³‡, ಸà³à²°à²•à³à²·à²¿à²¤à²µà²²à³à²²à²¦ ಸಂಪನà³à²®à³‚ಲಗಳನà³à²¨à³ ಈ ಪà³à²Ÿ ಒಳಗà³à²‚ಡಿದೆ. ಪà³à²°à²¯à²¾à²£à²¦ ಸಂದರà³à²­à²¦à²²à³à²²à²¿ ಈ ಸಂಪನà³à²®à³‚ಲಗಳನà³à²¨à³ ಇತರರೂ ವೀಕà³à²·à²¿à²¸à²¬à²¹à³à²¦à²¾à²—ಿದೆ ಮತà³à²¤à³ ಪà³à²Ÿà²¦ ನೋಟವೇ ಬದಲಾಗà³à²µà²‚ತೆ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ಅದನà³à²¨à³ ತಿದà³à²¦à²¬à²¹à³à²¦à²¾à²—ಿದೆ.</translation>
+<translation id="5786044859038896871">ನಿಮà³à²® ಕಾರà³à²¡à³ ಮಾಹಿತಿ ಭರà³à²¤à²¿ ಮಾಡಲೠನೀವೠಬಯಸà³à²µà²¿à²°à²¾?</translation>
+<translation id="5803412860119678065">ನಿಮà³à²® <ph name="CARD_DETAIL" /> ಭರà³à²¤à²¿ ಮಾಡಲೠನೀವೠಬಯಸà³à²µà²¿à²°à²¾?</translation>
<translation id="5810442152076338065">ಬಳಕೆಯಲà³à²²à²¿à²²à³à²²à²¦ ಸೈಫರೠಸೂಟೠಬಳಸà³à²µ ಮೂಲಕ <ph name="DOMAIN" /> ಗೆ ನಿಮà³à²® ಸಂಪರà³à²•à²µà²¨à³à²¨à³ à²à²¨à³â€Œà²•à³à²°à²¿à²ªà³à²Ÿà³ ಮಾಡಲಾಗಿದೆ.</translation>
<translation id="5813119285467412249">&amp;ಸೇರಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
+<translation id="5814352347845180253"><ph name="SITE" /> ಮತà³à²¤à³ ಕೆಲವೠಇತರ ಸೈಟà³â€Œà²—ಳಿಂದ ಪà³à²°à³€à²®à²¿à²¯à²‚ ವಿಷಯಕà³à²•à³† ಪà³à²°à²µà³‡à²¶à²µà²¨à³à²¨à³ ನೀವೠಕಳೆದà³à²•à³à²³à³à²³à²¬à²¹à³à²¦à³.</translation>
+<translation id="5843436854350372569">ನೀವೠ<ph name="DOMAIN" /> ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²°à³à²µà²¿à²°à²¿, ಆದರೆ ದà³à²°à³à²¬à²² ಕೀಯನà³à²¨à³ ಹà³à²‚ದಿರà³à²µ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಪà³à²°à²¸à³à²¤à³à²¤à²ªà²¡à²¿à²¸à²¿à²¦à³†. ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ಖಾಸಗಿ ಕೀಯನà³à²¨à³ ನಾಶ ಪಡಿಸಿರಬಹà³à²¦à³ ಮತà³à²¤à³ ನೀವೠನಿರೀಕà³à²·à²¿à²¸à²¿à²¦ ಸರà³à²µà²°à³ ಅದಾಗಿರದೇ ಇರಬಹà³à²¦à³ (ನೀವೠಆಕà³à²°à²®à²£à²•à²¾à²°à²° ಜà³à²¤à³†à²—ೆ ಸಂವಹನ ಮಾಡà³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³). <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">ನಿಮà³à²® ವà³à²¯à²µà²¸à³à²¥à²¾à²ªà²•à²°à³ ಈ ಸೈಟೠಅನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿರà³à²µ ಕಾರಣ ನೀವೠಈ ಸಂದೇಶವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿.</translation>
<translation id="5857090052475505287">ಹà³à²¸ ಫೋಲà³à²¡à²°à³</translation>
<translation id="5869405914158311789">ಈ ಸೈಟೠತಲà³à²ªà²²à²¾à²—à³à²µà³à²¦à²¿à²²à³à²²</translation>
@@ -419,6 +443,7 @@
<translation id="5872918882028971132">ಪೋಷಕ ಸಲಹೆಗಳà³</translation>
<translation id="59107663811261420">ಈ ವರà³à²¤à²•à²°à²¿à²—ೆ Google Payments ನಿಂದ ಈ ಪà³à²°à²•à²¾à²°à²¦ ಕಾರà³à²¡à³ ಬೆಂಬಲಿತವಾಗಿಲà³à²². ದಯವಿಟà³à²Ÿà³ ಬೇರೆಯ ಕಾರà³à²¡à³ ಆಯà³à²•à³†à²®à²¾à²¡à²¿.</translation>
<translation id="59174027418879706">ಸಕà³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
+<translation id="5926846154125914413">ಕೆಲವೠಸೈಟà³â€Œà²—ಳ ಪà³à²°à³€à²®à²¿à²¯à²‚ ವಿಷಯಕà³à²•à³† ಪà³à²°à²µà³‡à²¶à²µà²¨à³à²¨à³ ನೀವೠಕಳೆದà³à²•à³à²³à³à²³à²¬à²¹à³à²¦à³.</translation>
<translation id="5966707198760109579">ವಾರ</translation>
<translation id="5967867314010545767">ಇತಿಹಾಸದಿಂದ ತೆಗೆದà³à²¹à²¾à²•à²¿</translation>
<translation id="5975083100439434680">à²à³‚ಮೠಔಟà³</translation>
@@ -430,11 +455,11 @@
<translation id="604124094241169006">ಸà³à²µà²¯à²‚à²à²¾à²²à²¿à²¤</translation>
<translation id="6042308850641462728">ಇನà³à²¨à²·à³à²Ÿà³</translation>
<translation id="6060685159320643512">ಜಾಗà³à²°à²¤à³†, ಈ ಪà³à²°à²¯à³‹à²—ಗಳೠವಿಫಲವಾಗಬಹà³à²¦à³</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{ಯಾವà³à²¦à³‚ ಇಲà³à²²}=1{1}one{#}other{#}}</translation>
<translation id="6146055958333702838">ಯಾವà³à²¦à³‡ ಕೇಬಲà³â€Œà²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಿ. ನೀವೠಬಳಸà³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à²¾à²¦ ಯಾವà³à²¦à³‡ ರೂಟರà³â€Œà²—ಳà³, ಮೋಡೆಮà³â€Œà²—ಳೠಅಥವಾ ಇತರ ನೆಟà³â€Œà²µà²°à³à²•à³ ಸಾಧನಗಳನà³à²¨à³ ರೀಬೂಟೠಮಾಡಿ.</translation>
<translation id="614940544461990577">ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿:</translation>
<translation id="6150607114729249911">ಓಹà³! ಈ ಪà³à²Ÿà²•à³à²•à³† ಭೇಟಿ ನೀಡಲೠನಿಮà³à²® ಪೋಷಕರ ಒಪà³à²ªà²¿à²—ೆ ಅಗತà³à²¯à²µà²¿à²¦à³à²¦à³ ಅವರೠಸರಿ à²à²‚ದೠಹೇಳಿದರೆ ನೀವೠಈ ಪà³à²Ÿà²•à³à²•à³† ಭೇಟಿ ನೀಡಬಹà³à²¦à³.</translation>
<translation id="6151417162996330722">ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ತà³à²‚ಬಾ ಉದà³à²¦à²µà²¾à²¦ ವಾಯಿದೆ ಅವಧಿಯನà³à²¨à³ ಹà³à²‚ದಿದೆ.</translation>
-<translation id="6154808779448689242">ಹಿಂತಿರà³à²—ಿಸಲಾದ ನೀತಿಯ ಟೋಕನà³â€Œà²—ೆ ಪà³à²°à²¸à³à²¤à³à²¤ ಟೋಕನೠಹà³à²‚ದಾಣಿಕೆಯಾಗà³à²µà³à²¦à²¿à²²à³à²²</translation>
<translation id="6165508094623778733">ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ</translation>
<translation id="6203231073485539293">ನಿಮà³à²® ಇಂಟರà³à²¨à³†à²Ÿà³ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಪರಿಶೀಲಿಸಿ</translation>
<translation id="6218753634732582820">Chromium ನಿಂದ ವಿಳಾಸವನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
@@ -447,24 +472,30 @@
<translation id="6328639280570009161">ನೆಟà³â€Œà²µà²°à³à²•à³ ಮà³à²¨à³à²¸à³‚à²à²¨à³†à²¯à²¨à³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿</translation>
<translation id="6337534724793800597">ಹೆಸರಿನ ಪà³à²°à²•à²¾à²°à²µà²¾à²—ಿ ನೀತಿಗಳನà³à²¨à³ ಫಿಲà³à²Ÿà²°à³ ಮಾಡಿ</translation>
<translation id="6342069812937806050">ಇದೀಗ</translation>
+<translation id="6345221851280129312">ಅಪರಿà²à²¿à²¤ ಗಾತà³à²°</translation>
<translation id="6355080345576803305">ಸಾರà³à²µà²œà²¨à²¿à²• ಸೆಷನೠಅತಿಕà³à²°à²®à²¿à²¸à³à²µà²¿à²•à³†</translation>
<translation id="6358450015545214790">ಇವà³à²—ಳ ಅರà³à²¥à²µà³‡à²¨à³?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 ಇತರ ಸಲಹೆ}one{# ಇತರ ಸಲಹೆಗಳà³}other{# ಇತರ ಸಲಹೆಗಳà³}}</translation>
<translation id="6387478394221739770">ಉತà³à²¤à²®à²µà²¾à²¦ ಹà³à²¸ Chrome ವೈಶಿಷà³à²Ÿà³à²¯à²—ಳಲà³à²²à²¿ ಆಸಕà³à²¤à²¿ ಇದೆಯೇ? chrome.com/beta ನಲà³à²²à²¿ ನಮà³à²® ಬೀಟಾ à²à²¾à²¨à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
-<translation id="641480858134062906"><ph name="URL" /> ಲೋಡೠಆಗಲೠವಿಫಲವಾಗಿದೆ</translation>
+<translation id="6389758589412724634">ಈ ವೆಬà³â€Œà²ªà³à²Ÿ ಪà³à²°à²¦à²°à³à²¶à²¿à²¸à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²µà²¾à²— Chromium ಮೆಮà³à²°à²¿ ಖಾಲಿಯಾಗಿದೆ.</translation>
+<translation id="6416403317709441254">Chromium ಪà³à²°à²•à³à²°à²¿à²¯à³†à²—à³à²³à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¿à²²à³à²²à²¦ ಅವà³à²¯à²µà²¸à³à²¥à²¿à²¤ ರà³à²œà³à²µà²¾à²¤à³à²—ಳನà³à²¨à³ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³ ಕಳà³à²¹à²¿à²¸à²¿à²¦ ಕಾರಣ ಇದೀಗ ನೀವೠ<ph name="SITE" /> ಭೇಟಿ ಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ದಾಳಿಗಳೠಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿರà³à²¤à³à²¤à²µà³†, ಹೀಗಾಗಿ ಈ ಪà³à²Ÿà²µà³ ನಂತರ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಹಿಂತೆಗೆದà³à²•à³à²³à³à²³à²²à²¾à²—ಿದೆಯೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಪರಿಶೀಲಿಸಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²².</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ಸಂಪರà³à²•à²—à³à²³à³à²³à²²à³ ನಿರಾಕರಿಸಿದೆ.</translation>
<translation id="6445051938772793705">ರಾಷà³à²Ÿà³à²°</translation>
<translation id="6451458296329894277">ಮರà³à²¸à²²à³à²²à²¿à²•à³† ಫಾರà³à²®à³ ಅನà³à²¨à³ ಖà²à²¿à²¤à²ªà²¡à²¿à²¸à²¿à²•à³à²³à³à²³à²¿</translation>
<translation id="6458467102616083041">ಡಿಫಾಲà³à²Ÿà³ ಹà³à²¡à³à²•à²¾à²Ÿà²µà²¨à³à²¨à³ ನೀತಿಯಿಂದ ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à²¾à²—ಿರà³à²µà³à²¦à²°à²¿à²‚ದ ನಿರà³à²²à²•à³à²·à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
+<translation id="6462969404041126431">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಹಿಂಪಡೆದà³à²•à³à²‚ಡಿರಬಹà³à²¦à³. ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">ಸಾಧನ ನೀತಿಗಳà³</translation>
<translation id="6489534406876378309">ವಿಫಲತೆಗಳನà³à²¨à³ ಅಪà³â€Œà²²à³‹à²¡à³â€Œ ಮಾಡà³à²µà³à²¦à²¨à³à²¨à³ ಪà³à²°à²¾à²°à²‚ಭಿಸà³</translation>
<translation id="6529602333819889595">&amp;ಅಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
+<translation id="6534179046333460208">ಭೌತಿಕ ವೆಬೠಸಲಹೆಗಳà³</translation>
<translation id="6550675742724504774">ಆಯà³à²•à³†à²—ಳà³</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" /> ಗಿಂತ ಕಡಿಮೆ</translation>
<translation id="6596325263575161958">à²à²¨à³â€Œà²•à³à²°à²¿à²«à³à²¶à²¨à³ ಆಯà³à²•à³†à²—ಳà³</translation>
<translation id="662080504995468778">ಉಳಿಯಿರಿ</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> ಹà³à²¡à³à²•à²¾à²Ÿ</translation>
-<translation id="6634865548447745291">ನೀವೠ<ph name="SITE" /> ಗೆ ಭೇಟಿ ನೀಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². à²à²•à³†à²‚ದರೆ <ph name="BEGIN_LINK" />ಈ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಹಿಂಪಡೆದà³à²•à³à²³à³à²³à²²à²¾à²—ಿದೆ<ph name="END_LINK" />. ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ಆಕà³à²°à²®à²£à²—ಳೠತಾತà³à²•à²¾à²²à²¿à²•, ಹೀಗಾಗಿ ಈ ಪà³à²Ÿà²µà³ ಸà³à²µà²²à³à²ª ಸಮಯದ ನಂತರ ಕಾರà³à²¯ ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="6644283850729428850">ಈ ನೀತಿಯನà³à²¨à³ ವಿನಂತಿಸಲಾಗಿದೆ.</translation>
+<translation id="6652240803263749613">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ಆಪರೇಟಿಂಗೠಸಿಸà³à²Ÿà²‚ನಿಂದ ವಿಶà³à²µà²¾à²¸à²¹à³à²‚ದಿಲà³à²². ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">ಫೋಲà³à²¡à²°à³ à²à²¡à²¿à²Ÿà³ ಮಾಡಿ</translation>
<translation id="6660210980321319655"><ph name="CRASH_TIME" /> ಸಮಯಕà³à²•à³† ಸà³à²µà²¯à²‚à²à²¾à²²à²¿à²¤à²µà²¾à²—ಿ ವರದಿ ಮಾಡಲಾಗಿದೆ</translation>
<translation id="6671697161687535275">Chromium ನಿಂದ ಫಾರà³à²®à³ ಸಲಹೆಯನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
@@ -472,7 +503,8 @@
<translation id="6710213216561001401">ಹಿಂದೆ</translation>
<translation id="6710594484020273272">&lt;ಹà³à²¡à³à²•à²¾à²Ÿà²¦ ಪದ ಟೈಪೠಮಾಡಿ&gt;</translation>
<translation id="6711464428925977395">ಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³â€Œâ€Œà²¨à²²à³à²²à²¿ à²à²¨à³‹ ದೋಷವಿದೆ ಅಥವಾ ವಿಳಾಸವೠತಪà³à²ªà²¾à²—ಿದೆ.</translation>
-<translation id="674375294223700098">ಅಜà³à²à²¾à²¤ ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ದೋಷ.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{ಯಾವà³à²¦à³‚ ಇಲà³à²²}=1{1 à²à²Ÿà²‚}one{# à²à²Ÿà²‚ಗಳà³}other{# à²à²Ÿà²‚ಗಳà³}}</translation>
+<translation id="674375294223700098">ಅಪರಿà²à²¿à²¤ ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ದೋಷ.</translation>
<translation id="6753269504797312559">ನೀತಿ ಮೌಲà³à²¯</translation>
<translation id="6757797048963528358">ನಿಮà³à²® ಸಾಧನವೠನಿದà³à²°à²¾à²µà²¸à³à²¥à³†à²—ೆ ಹೋಗಿದೆ.</translation>
<translation id="6820686453637990663">CVC</translation>
@@ -483,7 +515,6 @@
<translation id="6891596781022320156">ನೀತಿಯ ಮಟà³à²Ÿà²µà³ ಬೆಂಬಲಿತವಾಗಿಲà³à²².</translation>
<translation id="6895330447102777224">ನಿಮà³à²® ಕಾರà³à²¡à³ ಅನà³à²¨à³ ದೃಢೀಕರಿಸಲಾಗಿದೆ</translation>
<translation id="6897140037006041989">ಬಳಕೆದಾರ à²à²œà³†à²‚ಟà³</translation>
-<translation id="6903907808598579934">ಸಿಂಕà³â€Œ ಆನà³â€Œ ಮಾಡಿ</translation>
<translation id="6915804003454593391">ಬಳಕೆದಾರ:</translation>
<translation id="6957887021205513506">ಸರà³à²µà²°à³â€Œà²—ಳ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಕಲಿಯಾಗಿ ಗೋà²à²°à²¿à²¸à³à²¤à³à²¤à²¦à³†.</translation>
<translation id="6965382102122355670">ಸರಿ</translation>
@@ -491,9 +522,11 @@
<translation id="6970216967273061347">ಜಿಲà³à²²à³†</translation>
<translation id="6973656660372572881">ಹà³à²‚ದಿಸಿದ ಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³â€Œà²—ಳೠಮತà³à²¤à³ .pac ಸà³à²•à³à²°à²¿à²ªà³à²Ÿà³ URL à²à²°à²¡à²¨à³à²¨à³‚ ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="6989763994942163495">ಸà³à²§à²¾à²°à²¿à²¤ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ತೋರಿಸà³...</translation>
+<translation id="7000990526846637657">ಯಾವà³à²¦à³‡ ಇತಿಹಾಸ ದಾಖಲೆಗಳೠಕಂಡà³à²¬à²‚ದಿಲà³à²²</translation>
+<translation id="7009986207543992532">ನೀವೠ<ph name="DOMAIN" /> ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²°à³à²µà²¿à²°à²¿, ಆದರೆ ವಾಯಿದೆ ಅವಧಿ ದೀರà³à²˜à²µà²¾à²—ಿರà³à²µ ವಿಶà³à²µà²¾à²¸à²¾à²°à³à²¹à²µà²¾à²¦ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಪà³à²°à²¸à³à²¤à³à²¤à²ªà²¡à²¿à²¸à²¿à²¦à³†. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">ನಿಮà³à²® Google ಖಾತೆಯೠ<ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ನಲà³à²²à²¿ ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಇತಿಹಾಸದ ಇತರ ಪà³à²°à²•à²¾à²°à²—ಳನà³à²¨à³ ಹà³à²‚ದಿರಬಹà³à²¦à³</translation>
<translation id="7029809446516969842">ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳà³</translation>
-<translation id="7050187094878475250">ನೀವೠ<ph name="DOMAIN" /> ಅನà³à²¨à³ ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²°à³à²µà²¿à²°à²¿, ಆದರೆ ಸರà³à²µà²°à³ ವಿಶà³à²µà²¾à²¸à²¾à²°à³à²¹à²µà²¾à²—ಿರಲೠತà³à²‚ಬ ಉದà³à²¦à²µà²¾à²¦ ವಾಯಿದೆ ಅವಧಿಯನà³à²¨à³ ಹà³à²‚ದಿರà³à²µ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸಲà³à²²à²¿à²¸à²¿à²¦à³†.</translation>
<translation id="7087282848513945231">ರಾಷà³à²Ÿà³à²°</translation>
<translation id="7088615885725309056">ಹಳೆಯದà³</translation>
<translation id="7090678807593890770"><ph name="LINK" /> ಗೆ Google ಹà³à²¡à³à²•à²¾à²Ÿ</translation>
@@ -512,13 +545,13 @@
<translation id="7246609911581847514">ನಿಮà³à²® ಮà³à²¦à²² ಭೇಟಿಯಲà³à²²à²¿ ನಿಮà³à²® ವà³à²¯à²µà²¸à³à²¥à²¾à²ªà²•à²°à³ ಹà³à²¸ ಸೈಟà³â€Œà²—ಳನà³à²¨à³ ಅಂಗೀಕರಿಸಬೇಕಾಗಿರà³à²µ ಕಾರಣ ನೀವೠಈ ಸಂದೇಶವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿.</translation>
<translation id="724975217298816891">ನಿಮà³à²® ಕಾರà³à²¡à³â€Œ ವಿವರಗಳನà³à²¨à³ ಅಪà³â€Œà²¡à³‡à²Ÿà³â€Œ ಮಾಡಲೠ<ph name="CREDIT_CARD" /> ಗೆ ಮà³à²•à³à²¤à²¾à²¯ ದಿನಾಂಕ ಮತà³à²¤à³ CVC ಅನà³à²¨à³ ನಮೂದಿಸಿ. ನೀವೠಒಮà³à²®à³† ಖà²à²¿à²¤à²ªà²¡à²¿à²¸à²¿à²¦à²°à³†, ನಿಮà³à²® ಕಾರà³à²¡à³ ವಿವರಗಳನà³à²¨à³ ಈ ಸೈಟೠಜà³à²¤à³†à²—ೆ ಹಂà²à²¿à²•à³à²³à³à²³à²²à²¾à²—à³à²¤à³à²¤à²¦à³†.</translation>
<translation id="725866823122871198">ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರà³â€Œà²¨ ದಿನಾಂಕ ಮತà³à²¤à³ ಸಮಯ (<ph name="DATE_AND_TIME" />) ತಪà³à²ªà²¾à²—ಿರà³à²µà³à²¦à²°à²¿à²‚ದ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ಗೆ ಖಾಸಗಿ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¿à²²à³à²².</translation>
-<translation id="7265986070661382626">ನೀವೠಸದà³à²¯à²•à³à²•à³† <ph name="SITE" /> ಗೆ ಭೇಟಿ ನೀಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². à²à²•à³†à²‚ದರೆ, ವೆಬà³â€Œà²¸à³ˆà²Ÿà³ <ph name="BEGIN_LINK" />ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಪಿನೠಮಾಡà³à²µà²¿à²•à³†à²¯à²¨à³à²¨à³ ಬಳಸà³à²¤à³à²¤à²¦à³†<ph name="END_LINK" />. ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ಆಕà³à²°à²®à²£à²—ಳೠತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿರà³à²¤à³à²¤à²µà³†, ಹೀಗಾಗಿ ಈ ಪà³à²Ÿà²µà³ ಸà³à²µà²²à³à²ª ಸಮಯದ ನಂತರ ಕಾರà³à²¯ ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="7269802741830436641">ಈ ವೆಬà³â€Œà²ªà³à²Ÿà²µà³ ಮರà³à²¨à²¿à²°à³à²¦à³‡à²¶à²¿à²¸à³à²µà²¿à²•à³† ಲೂಪೠಅನà³à²¨à³ ಹà³à²‚ದಿದೆ</translation>
<translation id="7275334191706090484">ನಿರà³à²µà²¹à²¿à²¸à²¿à²¦ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
<translation id="7298195798382681320">ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ</translation>
-<translation id="7301833672208172928">ಇತಿಹಾಸ ಸಿಂಕೠಆನೠಮಾಡಿ</translation>
+<translation id="7309308571273880165">ಕà³à²°à³à²¯à²¾à²¶à³ ವರದಿಯನà³à²¨à³ <ph name="CRASH_TIME" /> ರಲà³à²²à²¿ ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ (ಬಳಕೆದಾರರ ಮೂಲಕ ವಿನಂತಿಸಲಾದ ಅಪà³â€Œà²²à³‹à²¡à³ ಅನà³à²¨à³, ಇನà³à²¨à³‚ ಅಪà³â€Œà²²à³‹à²¡à³ ಮಾಡಿಲಾಗಿಲà³à²²)</translation>
<translation id="7334320624316649418">&amp;ಮರà³à²•à³à²°à²®à²—ೊಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
<translation id="733923710415886693">ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಪಾರದರà³à²¶à²•à²¤à³†à²¯ ಮೂಲಕ ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಬಹಿರಂಗಪಡಿಸಲಾಗಿಲà³à²².</translation>
+<translation id="7351800657706554155">ಇದೀಗ ನೀವೠ<ph name="SITE" /> ಗೆ ಭೇಟಿ ಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²² à²à²•à³†à²‚ದರೆ ಇದರ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಹಿಂಪಡೆಯಲಾಗಿದೆ. ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ದಾಳಿಗಳೠಸಾಮಾನà³à²¯à²µà²¾à²—ಿ ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿರà³à²¤à³à²¤à²µà³†, ಹೀಗಾಗಿ ಈ ಪà³à²Ÿà²µà³ ನಂತರ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">ಆದೇಶ ಸಾಲà³</translation>
<translation id="7372973238305370288">ಹà³à²¡à³à²•à²¾à²Ÿ ಫಲಿತಾಂಶ</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -527,7 +560,7 @@
<translation id="7390545607259442187">ಕಾರà³à²¡à³ ಅನà³à²¨à³ ದೃಢೀಕರಿಸಿ</translation>
<translation id="7394102162464064926">ನಿಮà³à²® ಇತಿಹಾಸದಿಂದ ಈ ಪà³à²Ÿà²—ಳನà³à²¨à³ ಅಳಿಸà³à²µà³à²¦à³ ಖà²à²¿à²¤à²µà³‡?
-ಛೆ! ಅಜà³à²à²¾à²¤ ಮೋಡೠ<ph name="SHORTCUT_KEY" /> ಮà³à²‚ದಿನ ಬಾರಿಯಾದರೂ ಸಮಯಕà³à²•à³† ಸರಿಯಾಗಿ ಸಹಾಯಕà³à²•à³† ಬರಬಹà³à²¦à³.</translation>
+ಛೆ! ಅದೃಶà³à²¯ ಮೋಡೠ<ph name="SHORTCUT_KEY" /> ಮà³à²‚ದಿನ ಬಾರಿಯಾದರೂ ಸಮಯಕà³à²•à³† ಸರಿಯಾಗಿ ಸಹಾಯಕà³à²•à³† ಬರಬಹà³à²¦à³.</translation>
<translation id="7400418766976504921">URL</translation>
<translation id="7419106976560586862">ಪà³à²°à³à²«à³ˆà²²à³ ಹಾದಿ</translation>
<translation id="7424977062513257142">ಈ ವೆಬà³â€Œà²ªà³à²Ÿà²¦à²²à³à²²à²¿ à²à²‚ಬೆಡೠಮಾಡಲಾದ ಪà³à²Ÿà²µà³ ಹೀಗೆ ಹೇಳà³à²¤à³à²¤à²¦à³†:</translation>
@@ -537,16 +570,17 @@
<translation id="7469372306589899959">ಕಾರà³à²¡à³â€Œ ದೃಢೀಕರಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="7481312909269577407">ಫಾರà³à²µà²°à³à²¡à³</translation>
<translation id="7485870689360869515">ಯಾವà³à²¦à³‡ ಡೇಟಾ ಕಂಡà³à²¬à²‚ದಿಲà³à²².</translation>
+<translation id="7508255263130623398">ಹಿಂತಿರà³à²—ಿಸಲಾದ ನೀತಿಯ ಸಾಧನ à²à²¡à²¿ ಖಾಲಿ ಇದೆ ಅಥವಾ ಪà³à²°à²¸à³à²¤à³à²¤ ಸಾಧನ à²à²¡à²¿à²—ೆ ಹà³à²‚ದಾಣಿಕೆಯಾಗà³à²µà³à²¦à²¿à²²à³à²²</translation>
<translation id="7514365320538308">ಡೌನà³â€Œà²²à³‹à²¡à³</translation>
<translation id="7518003948725431193">ಈ ವೆಬೠವಿಳಾಸಕà³à²•à²¾à²—ಿ ಯಾವà³à²¦à³‡ ವೆಬೠಪà³à²Ÿà²µà³ ಕಂಡà³à²¬à²°à²²à²¿à²²à³à²²: <ph name="URL" /></translation>
<translation id="7537536606612762813">ಕಡà³à²¡à²¾à²¯</translation>
<translation id="7542995811387359312">ಈ ಫಾರà³à²®à³ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²¦ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಬಳಸà³à²¤à³à²¤à²¿à²²à³à²²à²µà²¾à²¦ ಕಾರಣ ಸà³à²µà²¯à²‚à²à²¾à²²à²¿à²¤ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³ ಭರà³à²¤à²¿ ಮಾಡà³à²µà²¿à²•à³†à²¯à²¨à³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—à³à²³à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="7549584377607005141">ಈ ವೆಬà³â€Œà²ªà³à²Ÿà²µà³ ಸರಿಯಾಗಿ ಪà³à²°à²¦à²°à³à²¶à²¨à²—à³à²³à³à²³à²²à³ ಈ ಮà³à²¦à²²à³ ನೀವೠನಮೂದಿಸಿದ ಡೇಟಾದ ಅಗತà³à²¯à²µà²¿à²¦à³†. ನೀವೠಈ ಡೇಟಾವನà³à²¨à³ ಮತà³à²¤à³† ಕಳà³à²¹à²¿à²¸à²¬à²¹à³à²¦à³, ಆದರೆ ಹಾಗೆ ಮಾಡà³à²µà³à²¦à²°à²¿à²‚ದ ಈ ಪà³à²Ÿà²µà³ ಈ ಮà³à²¦à²²à³ ಪೂರೈಸಿದ ಯಾವà³à²¦à³‡ ಕà³à²°à²¿à²¯à³†à²¯à²¨à³à²¨à³ ನೀವೠಪà³à²¨à²°à²¾à²µà²°à³à²¤à²¿à²¸à³à²¤à³à²¤à³€à²°à²¿.</translation>
<translation id="7554791636758816595">ಹà³à²¸ ಟà³à²¯à²¾à²¬à³</translation>
-<translation id="7567204685887185387">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ವಂà²à²¨à³†à²¯à²¿à²‚ದ ನೀಡಿರಬಹà³à²¦à³. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="7568593326407688803">ಈ ಪà³à²Ÿà²µà³<ph name="ORIGINAL_LANGUAGE" />ನಲà³à²²à²¿à²¦à³† ನೀವೠಅದನà³à²¨à³ ಭಾಷಾಂತರಿಸಲೠಬಯಸà³à²µà²¿à²°à²¾?</translation>
<translation id="7569952961197462199">Chrome ನಿಂದ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
<translation id="7578104083680115302">Google ನà³à²‚ದಿಗೆ ನೀವೠಉಳಿಸಲಾದ ಕಾರà³à²¡à³â€Œà²—ಳನà³à²¨à³ ಬಳಸಿಕà³à²‚ಡೠಸಾಧನಗಳಾದà³à²¯à²‚ತ ಸೈಟà³â€Œà²—ಳೠಮತà³à²¤à³ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳಲà³à²²à²¿ ತà³à²µà²°à²¿à²¤à²µà²¾à²—ಿ ಪಾವತಿಸಿ.</translation>
+<translation id="7588950540487816470">ಭೌತಿಕ ವೆಬà³</translation>
<translation id="7592362899630581445">ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ಹೆಸರಿನ ನಿರà³à²¬à²‚ಧನೆಗಳನà³à²¨à³ ಉಲà³à²²à²‚ಘಿಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ಗೆ ಪà³à²°à²¸à³à²¤à³à²¤ ಈ ವಿನಂತಿಯನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—à³à²¤à³à²¤à²¿à²²à³à²².</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" /> ಅನà³à²¨à³ à²à²‚ದಿಗೂ ಅನà³à²µà²¾à²¦à²¿à²¸à²¬à³‡à²¡</translation>
@@ -556,8 +590,9 @@
<translation id="7634554953375732414">ಈ ಸೈಟà³â€Œà²—ೆ ನಿಮà³à²® ಸಂಪರà³à²•à²µà³ ಖಾಸಗಿಯಾಗಿಲà³à²².</translation>
<translation id="7637571805876720304">Chromium ನಿಂದ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
<translation id="765676359832457558">ಸà³à²§à²¾à²°à²¿à²¤ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಮರೆಮಾಡà³...</translation>
-<translation id="7658239707568436148">ರದà³à²¦à³à²®à²¾à²¡à³</translation>
-<translation id="7668654391829183341">ಅಜà³à²à²¾à²¤ ಸಾಧನ</translation>
+<translation id="7658239707568436148">ರದà³à²¦à³à²®à²¾à²¡à²¿</translation>
+<translation id="7667346355482952095">ಹಿಂತಿರà³à²—ಿಸಲಾದ ನೀತಿಯ ಟೋಕನà³â€Œ ಖಾಲಿ ಇದೆ ಅಥವಾ ಪà³à²°à²¸à³à²¤à³à²¤ ಟೋಕನà³â€Œà²—ೆ ಹà³à²‚ದಾಣಿಕೆಯಾಗà³à²µà³à²¦à²¿à²²à³à²²</translation>
+<translation id="7668654391829183341">ಅಪರಿà²à²¿à²¤ ಸಾಧನ</translation>
<translation id="7674629440242451245">ಉತà³à²¤à²®à²µà²¾à²¦ ಹà³à²¸ Chrome ವೈಶಿಷà³à²Ÿà³à²¯à²—ಳಲà³à²²à²¿ ಆಸಕà³à²¤à²¿ ಇದೆಯೇ? chrome.com/dev ನಲà³à²²à²¿ ನಮà³à²® dev à²à²¾à²¨à²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> ಗೆ (ಅಸà³à²°à²•à³à²·à²¿à²¤) ಮà³à²‚ದà³à²µà²°à³†à²¸à³<ph name="END_LINK" /></translation>
<translation id="7716424297397655342">ಸಂಗà³à²°à²¹à²¦à²¿à²‚ದ ಈ ಸೈಟೠಲೋಡೠಮಾಡಲಾಗà³à²µà³à²¦à²¿à²²à³à²²</translation>
@@ -573,10 +608,10 @@
<translation id="780301667611848630">ಬೇಡ, ಧನà³à²¯à²µà²¾à²¦à²—ಳà³</translation>
<translation id="7805768142964895445">ಸà³à²¥à²¿à²¤à²¿</translation>
<translation id="7813600968533626083">Chrome ನಿಂದ ಫಾರà³à²®à³ ಸಲಹೆಯನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
+<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ಗೆ '<ph name="SEARCH_STRING" />' ಕಂಡà³à²¬à²‚ದಿದೆ</translation>
<translation id="785549533363645510">ಆದರೆ, ನೀವೠಅದೃಶà³à²¯à²°à²¾à²—ಿರà³à²µà³à²¦à²¿à²²à³à²². ಅಜà³à²à²¾à²¤à²µà²¾à²—ಿ ಹೋಗà³à²µà³à²¦à²°à²¿à²‚ದ ನಿಮà³à²® ಉದà³à²¯à³‹à²—ದಾತರà³, ನಿಮà³à²® ಇಂಟರà³à²¨à³†à²Ÿà³ ಸೇವಾ ಪೂರೈಕೆದಾರರೠಇಲà³à²²à²µà³‡ ನೀವೠಭೇಟಿ ನೀಡà³à²µ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳಿಂದ ನಿಮà³à²® ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಮರೆ ಮಾಡಲಾಗà³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="7887683347370398519">ನಿಮà³à²® CVC ಅನà³à²¨à³ ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿</translation>
<translation id="7894616681410591072">ಓಹà³! ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ <ph name="NAME" /> ಅವರಿಂದ ನಿಮಗೆ ಅನà³à²®à²¤à²¿ ಅಗತà³à²¯à²µà²¿à²°à³à²¤à³à²¤à²¦à³†.</translation>
-<translation id="790025292736025802"><ph name="URL" /> ಪತà³à²¤à³†à²¯à²¾à²—ಿಲà³à²²</translation>
<translation id="7912024687060120840">ಫೋಲà³à²¡à²°à³â€Œà²¨à²²à³à²²à²¿:</translation>
<translation id="7920092496846849526">ಈ ಪà³à²Ÿà²•à³à²•à³† ಭೇಟಿ ನೀಡà³à²µà³à²¦à³ ಸರಿಯೇ à²à²‚ದೠನೀವೠನಿಮà³à²® ಪೋಷಕರನà³à²¨à³ ಕೇಳಿರà³à²µà²¿à²°à²¿</translation>
<translation id="7935318582918952113">DOM ಡಿಸà³à²Ÿà²¿à²²à²°à³</translation>
@@ -589,9 +624,10 @@
<translation id="7995512525968007366">ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿಲà³à²²</translation>
<translation id="8012647001091218357">ಈ ಕà³à²·à²£à²¦à²²à³à²²à²¿ ನಿಮà³à²® ಪೋಷಕರನà³à²¨à³ ತಲà³à²ªà²²à³ ನಮಗೆ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²². ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="8034522405403831421">ಈ ಪà³à²Ÿà²µà³ <ph name="SOURCE_LANGUAGE" /> ನಲà³à²²à²¿ ಇದೆ. ಇದನà³à²¨à³ <ph name="TARGET_LANGUAGE" /> ಗೆ ಅನà³à²µà²¾à²¦à²¿à²¸à³à²µà³à²¦à³‡?</translation>
-<translation id="8034955203865359138">ಯಾವà³à²¦à³‡ ಇತಿಹಾಸ ದಾಖಲೆಗಳೠಕಂಡà³à²¬à²‚ದಿಲà³à²².</translation>
<translation id="8088680233425245692">ಲೇಖನವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³ ವಿಫಲವಾಗಿದೆ.</translation>
+<translation id="8089520772729574115">1 MB ಗಿಂತ ಕಡಿಮೆ</translation>
<translation id="8091372947890762290">ಸರà³à²µà²°à³â€Œà²¨à²²à³à²²à²¿ ಸಕà³à²°à²¿à²¯à²¤à³† ಬಾಕಿ ಉಳಿದಿದೆ</translation>
+<translation id="8129262335948759431">ಅಪರಿà²à²¿à²¤ ಪà³à²°à²®à²¾à²£</translation>
<translation id="8131740175452115882">ದೃಢೀಕರಿಸà³</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> ಅವರ ಸರà³à²µà²°à³â€Œ <ph name="BEGIN_ABBR" />DNS ವಿಳಾಸ<ph name="END_ABBR" /> ಕಂಡà³à²¬à²‚ದಿಲà³à²².</translation>
<translation id="8149426793427495338">ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರೠನಿದà³à²°à²¾à²µà²¸à³à²¥à³†à²—ೆ ಹೋಗಿದೆ.</translation>
@@ -600,6 +636,7 @@
<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" ID ಜà³à²¤à³†à²—ಿನ ವಿಸà³à²¤à²°à²£à³†à²—ೆ ಅಮಾನà³à²¯à²µà²¾à²¦ ಅಪà³â€Œà²¡à³‡à²Ÿà³â€Œâ€Œ URL.</translation>
<translation id="8218327578424803826">ನಿಯೋಜಿಸಲಾದ ಸà³à²¥à²³:</translation>
<translation id="8225771182978767009">ಈ ಕಂಪà³à²¯à³‚ಟರೠಹà³à²‚ದಿಸಿರà³à²µ ವà³à²¯à²•à³à²¤à²¿à²¯à³ ಈ ಸೈಟೠನಿರà³à²¬à²‚ಧಿಸಲೠಆಯà³à²•à³†à²®à²¾à²¡à²¿à²¦à³à²¦à²¾à²°à³†.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">ನೀವೠà²à²¦à³à²°à³ ನೋಡà³à²¤à³à²¤à²¿à²°à³à²µ ಪà³à²Ÿ ನೀವೠನಮೂದಿಸಿದ ಮಾಹಿತಿಯನà³à²¨à³ ಬಳಸಿದೆ. ಆ ಪà³à²Ÿà²•à³à²•à³† ಹಿಂದಿರà³à²—à³à²µà³à²¦à²°à²¿à²‚ದ ನೀವೠಮಾಡಿದ ಯಾವà³à²¦à³‡ ಕà³à²°à²¿à²¯à³† ಪà³à²¨à²°à²¾à²µà²°à³à²¤à²¿à²¸à³à²µà²‚ತೆ ಮಾಡà³à²¤à³à²¤à²¦à³†. ನೀವೠಮà³à²‚ದà³à²µà²°à²¿à²¸à²²à³ ಬಯಸà³à²¤à³à²¤à³€à²°à²¾?</translation>
<translation id="8249320324621329438">ಕಳೆದ ಬಾರಿ ಪಡೆದಿರà³à²µà³à²¦à³:</translation>
<translation id="8261506727792406068">ಅಳಿಸà³</translation>
@@ -612,12 +649,17 @@
<translation id="8349305172487531364">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳ ಬಾರà³</translation>
<translation id="8363502534493474904">à²à²°à³â€Œà²ªà³à²²à³‡à²¨à³ ಮೋಡೠಆಫà³â€Œ ಮಾಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="8364627913115013041">ಹà³à²‚ದಿಸಿಲà³à²².</translation>
+<translation id="8380941800586852976">ಅಪಾಯಕಾರಿ</translation>
<translation id="8412145213513410671">(<ph name="CRASH_COUNT" />) ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œà²—ಳೠ</translation>
<translation id="8412392972487953978">ನೀವೠಒಂದೇ ರೀತಿಯ ಪಾಸà³â€Œà²«à³à²°à³‡à²¸à³ ಅನà³à²¨à³ à²à²°à²¡à³ ಬಾರಿ ನಮೂದಿಸಬೇಕà³.</translation>
<translation id="8428213095426709021">ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳà³</translation>
+<translation id="8433057134996913067">ಇದೠನಿಮà³à²®à²¨à³à²¨à³ ಹೆà²à³à²à²¿à²¨ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳಿಂದ ಸೈನà³â€Œ ಔಟà³â€Œ ಮಾಡà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="8437238597147034694">&amp;ಸರಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—à³à²³à²¿à²¸à²¿</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³}one{# ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³â€Œà²—ಳà³}other{# ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³â€Œà²—ಳà³}}</translation>
+<translation id="8483780878231876732">ನಿಮà³à²® Google ಖಾತೆಯಿಂದ ಕಾರà³à²¡à³â€Œà²—ಳನà³à²¨à³ ಬಳಸಲà³, Chrome ಗೆ ಸೈನೠಇನೠಮಾಡಿ</translation>
<translation id="8488350697529856933">ಇದಕà³à²•à³† ಅನà³à²µà²¯à²¿à²¸à²²à²¾à²—à³à²¤à³à²¤à²¦à³†</translation>
<translation id="8498891568109133222">ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à²¿à²¸à²²à³ <ph name="HOST_NAME" /> ಹೆà²à³à²à³ ಸಮಯ ತೆಗೆದà³à²•à³à²‚ಡಿದೆ.</translation>
+<translation id="852346902619691059">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಿಮà³à²® ಸಾಧನದ ಆಪರೇಟಿಂಗೠಸಿಸà³à²Ÿà²‚ನಿಂದ ವಿಶà³à²µà²¾à²¸à²¹à³à²‚ದಿಲà³à²². ಇದೠತಪà³à²ªà²¾à²¦ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">ಈ ಪà³à²°à²•à²¾à²°à²¦ ಕಾರà³à²¡à³ ಅನà³à²¨à³ Google Payments ಬೆಂಬಲಿಸà³à²µà³à²¦à²¿à²²à³à²². ದಯವಿಟà³à²Ÿà³ ಬೇರೆ ಕಾರà³à²¡à³ ಆಯà³à²•à³†à²®à²¾à²¡à²¿.</translation>
<translation id="8550022383519221471">ಸಿಂಕೠಸೇವೆಯೠನಿಮà³à²® ಡà³à²®à³‡à²¨à³â€Œà²—ೆ ಲಭà³à²¯à²µà²¿à²²à³à²².</translation>
<translation id="8553075262323480129">ಪà³à²Ÿà²¦ ಭಾಷೆಯನà³à²¨à³ ಗà³à²°à³à²¤à²¿à²¸à²²à³ ಅಸಾಧà³à²¯à²µà²¾à²¦ ಕಾರಣ ಭಾಷಾಂತರವೠವಿಫಲವಾಗಿದೆ.</translation>
@@ -629,15 +671,12 @@
<translation id="8647750283161643317">à²à²²à³à²²à²µà²¨à³à²¨à³‚ ಡೀಫಾಲà³à²Ÿà³â€Œà²—ೆ ಮರà³à²¹à³à²‚ದಿಸಿ</translation>
<translation id="8680787084697685621">ಖಾತೆಯ ಸೈನà³-ಇನೠವಿವರಗಳೠಹಳೆಯದಾಗಿವೆ.</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> ಗೆ ನಿಮà³à²® ಸಂಪರà³à²•à²µà³ à²à²¨à³â€Œà²•à³à²°à²¿à²ªà³à²Ÿà³ ಆಗಿಲà³à²².</translation>
-<translation id="8713130696108419660">ತಪà³à²ªà²¾à²¦ ಇನಿಷಿಯಲೠಸಹಿ</translation>
<translation id="8725066075913043281">ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿</translation>
<translation id="8728672262656704056">ನೀವೠಈಗ ಅಜà³à²à²¾à²¤à²°à²¾à²—ಿರà³à²µà²¿à²°à²¿</translation>
<translation id="8730621377337864115">ಮà³à²—ಿದಿದೆ</translation>
<translation id="8738058698779197622">ಸà³à²°à²•à³à²·à²¿à²¤ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³, ನಿಮà³à²® ಗಡಿಯಾರವನà³à²¨à³ ಸರಿಯಾಗಿ ಹà³à²‚ದಿಸà³à²µ ಅಗತà³à²¯à²µà²¿à²¦à³†. ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳೠತಮà³à²®à²¨à³à²¨à³ ಗà³à²°à³à²¤à²¿à²¸à²²à³ ಬಳಸà³à²µ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳೠಸಮಯದ ನಿರà³à²¦à²¿à²·à³à²Ÿ ಅವಧಿಗಳಲà³à²²à²¿ ಮಾತà³à²° ಮಾನà³à²¯à²µà²¾à²—ಿರà³à²µ ಕಾರಣ ಹೀಗಾಗà³à²¤à³à²¤à²¦à³†. ನಿಮà³à²® ಸಾಧನದ ಗಡಿಯಾರವೠತಪà³à²ªà²¾à²—ಿರà³à²µ ಕಾರಣ, Chromium ಗೆ ಈ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²².</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> ನ &lt;abbr id="dnsDefinition"&gt;DNS ವಿಳಾಸ&lt;/abbr&gt; ಕಂಡà³à²¬à²°à²²à²¿à²²à³à²². ಸಮಸà³à²¯à³†à²¯à²¨à³à²¨à³ ಪತà³à²¤à³†à²¹à²à³à²à²²à²¾à²—à³à²¤à³à²¤à²¿à²¦à³†.</translation>
-<translation id="8741995161408053644">ನಿಮà³à²® Google ಖಾತೆಯೠ<ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ನಲà³à²²à²¿ ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಇತಿಹಾಸದ ಇತರ ಪà³à²°à²•à²¾à²°à²—ಳನà³à²¨à³ ಹà³à²‚ದಿರಬಹà³à²¦à³.</translation>
<translation id="8790007591277257123">&amp;ಅಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
-<translation id="8790687370365610530">Google ಸಲಹೆ ನೀಡಿದ ವೈಯಕà³à²¤à³€à²•à²°à²¿à²¸à²²à²¾à²¦ ವಿಷಯವನà³à²¨à³ ಪಡೆಯಲà³, ಇತಿಹಾಸ ಸಿಂಕೠಆನೠಮಾಡಿ.</translation>
<translation id="8798099450830957504">ಡಿಫಾಲà³à²Ÿà³</translation>
<translation id="8804164990146287819">ಗೌಪà³à²¯à²¤à²¾ ನೀತಿ</translation>
<translation id="8820817407110198400">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
@@ -659,13 +698,11 @@
<translation id="8971063699422889582">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²•à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಅವಧಿ ಮà³à²•à³à²¤à²¾à²¯à²—à³à²‚ಡಿದೆ.</translation>
<translation id="8987927404178983737">ತಿಂಗಳà³</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಪಾರದರà³à²¶à²•à²¤à³† ನೀತಿಯನà³à²¨à³ ಬಳಸಿಕà³à²‚ಡೠಸಾರà³à²µà²œà²¨à²¿à²•à²µà²¾à²—ಿ ಬಹಿರಂಗಗà³à²³à²¿à²¸à²¦ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಪà³à²°à²¸à³à²¤à³à²¤à²ªà²¡à²¿à²¸à²¿à²¦à³†. ಇದೠಅವà³à²—ಳೠವಿಶà³à²µà²¾à²¸à²¾à²°à³à²¹à²µà²¾à²—ಿವೆ ಮತà³à²¤à³ ಆಕà³à²°à²®à²£à²—ಾರರ ವಿರà³à²¦à³à²§ ರಕà³à²·à²£à³†à²¯à²¨à³à²¨à³ ನೀಡà³à²¤à³à²¤à²µà³† à²à²‚ಬà³à²¦à²¨à³à²¨à³ ಖà²à²¿à²¤à²ªà²¡à²¿à²¸à²¿à²•à³à²³à³à²³à²²à³ ಕೆಲವೠಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳಿಗೆ ಅಗತà³à²¯à²µà²¾à²—ಿದೆ.</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> ಪà³à²°à²¾à²•à³à²¸à²¿à²—ೆ ಬಳಕೆದಾರಹೆಸರೠಮತà³à²¤à³ ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅಗತà³à²¯à²µà²¿à²°à³à²¤à³à²¤à²¦à³†.</translation>
<translation id="901974403500617787">ಸಿಸà³à²Ÿà²‚ನಾದà³à²¯à²‚ತ ಅನà³à²µà²¯à²µà²¾à²—à³à²µ ಫà³à²²à³à²¯à²¾à²—à³â€Œà²—ಳನà³à²¨à³ ಮಾಲೀಕರಿಂದ ಮಾತà³à²° ಹà³à²‚ದಿಸಲೠಸಾಧà³à²¯: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ <ph name="TARGET_LANGUAGE" /> ಗೆ ಅನà³à²µà²¾à²¦à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
<translation id="9038649477754266430">ಪà³à²Ÿà²—ಳನà³à²¨à³ ಹೆà²à³à²à³ ವೇಗವಾಗಿ ಲೋಡೠಮಾಡಲೠಮà³à²¨à³à²¨à³‹à²Ÿà²—ಳನà³à²¨à³ ಬಳಸಿ</translation>
<translation id="9039213469156557790">ಅಲà³à²²à²¦à³‡, ಸà³à²°à²•à³à²·à²¿à²¤à²µà²²à³à²²à²¦ ಸಂಪನà³à²®à³‚ಲಗಳನà³à²¨à³ ಈ ಪà³à²Ÿ ಹà³à²‚ದಿದೆ. ಸà³à²¥à²¿à²¤à³à²¯à²‚ತರಗà³à²³à³à²³à³à²µ ಸಂದರà³à²­à²¦à²²à³à²²à²¿ ಈ ಸಂಪನà³à²®à³‚ಲಗಳನà³à²¨à³ ಇತರರೂ ವೀಕà³à²·à²¿à²¸à²¬à²¹à³à²¦à²¾à²—ಿದೆ ಮತà³à²¤à³ ಪà³à²Ÿà²¦ ಹà³à²°à²¨à³‹à²Ÿà²µà³‡ ಬದಲಾಗà³à²µà²‚ತೆ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ಅದನà³à²¨à³ ತಿದà³à²¦à²¬à²¹à³à²¦à²¾à²—ಿದೆ.</translation>
-<translation id="9049981332609050619">ನೀವೠ<ph name="DOMAIN" /> ಅನà³à²¨à³ ತಲà³à²ªà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿à²°à³à²µà²¿à²°à²¿, ಆದರೆ ಸರà³à²µà²°à³ ಅಮಾನà³à²¯ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ನೀಡಿದೆ.</translation>
<translation id="9050666287014529139">ಪಾಸà³â€Œà²«à³à²°à³‡à²¸à³</translation>
<translation id="9065203028668620118">à²à²¡à²¿à²Ÿà³</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> ಪà³à²Ÿ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à³à²¤à³à²¤à²¿à²²à³à²²</translation>
diff --git a/chromium/components/strings/components_strings_ko.xtb b/chromium/components/strings/components_strings_ko.xtb
index ed71e83b206..17387fb8b3e 100644
--- a/chromium/components/strings/components_strings_ko.xtb
+++ b/chromium/components/strings/components_strings_ko.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ko">
+<translation id="1008557486741366299">나́¤‘́— 하기</translation>
<translation id="1015730422737071372">́¶”ê°€ ́„¸ë¶€́ •ë³´ ́ œê³µ</translation>
<translation id="1032854598605920125">́‹œê³„ ë°©í–¥́œ¼ë¡œ íŒ́ „</translation>
<translation id="1038842779957582377">́•Œ ́ˆ˜ ́—†ë” ́´ë¦„</translation>
+<translation id="1053591932240354961">현́¬ <ph name="SITE" />́—́„œ Chromé´ ́²˜ë¦¬í•  ́ˆ˜ ́—†ë” ́•”í˜¸í™”ëœ ́격́¦ëª… ́ •ë³´ë¥¼ ́ „́†¡í–ˆê¸° 때문́— 방문할 ́ˆ˜ ́—†́µë‹ˆë‹¤. 네í¸́›Œí¬ ́˜¤ë¥˜́™€ 공격́€ 대부분 ́¼́‹œ́ ́´ë¯€ë¡œ ́ ́‹œ 후 í˜́´́§€ê°€ ́ •́ƒí™”ë  ê²ƒ́…니다. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">́¶”ê°€ ́‹¤í–‰ ́·΅†Œ(&amp;U)</translation>
<translation id="10614374240317010">비밀번호를 ́ €́¥í•˜́§€ ́•́€ ́‚¬́´í¸</translation>
-<translation id="1064422015032085147">́›¹í˜́´́§€ë¥¼ 호́¤íŒ…í•˜ë” ́„œë²„́— 과부하가 ë°œ́ƒí–ˆê±°ë‚˜ ë³´́ˆ˜ ́¤‘́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.
- ́§€ë‚˜́¹œ í¸ë˜í”½ ë°œ́ƒê³¼ ́ƒí™© ́•…화를 ë°©́§€í•˜ê¸° ́œ„í•´ ́´ URĹ— 대한 ́”́²­́´
- ́¼́‹œ́ ́œ¼ë¡œ í—ˆ́©ë˜́§€ ́•ê³  ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="106701514854093668">ë°́¤í¬í†± ë¶ë§ˆí¬</translation>
<translation id="1080116354587839789">너비́— ë§́¶¤</translation>
+<translation id="1103124106085518534">́¹´ë“œë¥¼ ë‹«́•˜́µë‹ˆë‹¤.</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> í•­́ƒ 번́—­</translation>
<translation id="1107591249535594099">́„ íƒí•˜ë©´ Chromé—́„œ ́–‘́‹́„ ë” ë¹ ë¥´ê²Œ ́…력할 ́ˆ˜ ́ˆë„ë¡ ́´ 기기́— ́¹´ë“œ ́‚¬ë³¸́„ ́ €́¥í•©ë‹ˆë‹¤.</translation>
+<translation id="1111153019813902504">́µœê·¼ ë¶ë§ˆí¬</translation>
<translation id="1113869188872983271">́¬́ •ë ¬ ́‹¤í–‰ ́·΅†Œ(&amp;U)</translation>
+<translation id="1126551341858583091">ë¡œ́»¬ ́ €́¥́†Œë” <ph name="CRASH_SIZE" />́…니다.</translation>
<translation id="112840717907525620">́ •́±… ́º́‹œ 확́¸</translation>
<translation id="113188000913989374"><ph name="SITE" /> ë‚´́©:</translation>
<translation id="1132774398110320017">Chrome ́ë™́™„́„± ́„¤́ •...</translation>
-<translation id="1150979032973867961">́´ ́„œë²„ê°€ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́œ¼ë©° ́»´í“¨í„°́˜ ́´́˜́²´́ œ́—́„œ ́‹ ë¢°í•˜ë” ë³´́•ˆ ́¸́¦́„œê°€ ́•„닙니다. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="1152921474424827756"><ph name="URL" />́˜ <ph name="BEGIN_LINK" />́º́‹œëœ ́‚¬ë³¸<ph name="END_LINK" />́— ́•¡́„¸́¤</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" />́™€(ê³¼)́˜ ́—°ê²°́´ ́˜ˆê¸°́¹˜ ́•ê²Œ ́¢…료ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="1161325031994447685">Wi-Fí— 다́‹œ ́—°ê²°</translation>
@@ -25,14 +26,15 @@
<translation id="1181037720776840403">́‚­́ œ</translation>
<translation id="1201402288615127009">다́Œ</translation>
<translation id="1201895884277373915">́´ ́‚¬́´í¸́—́„œ ë”보기</translation>
-<translation id="121201262018556460"><ph name="DOMAIN" />́— ́ ‘́†í•˜ë ¤ í–ˆ́œ¼ë‚˜ ́„œë²„ê°€ ́•ˆ́ „́„±́´ ë‚®́€ 키가 í¬í•¨ëœ ́¸́¦́„œë¥¼ ́ „달했́µë‹ˆë‹¤. 공격́ê°€ 비공개 키를 ́†́ƒ́‹œ́¼°́„ ́ˆ˜ ́ˆ́œ¼ë©° ́„œë²„를 ê°€́¥í•œ 공격́́™€ 통́‹  ́¤‘́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
+<translation id="1206967143813997005">́˜ëª»ëœ ́´ˆê¸° ́„œëª…</translation>
+<translation id="1209206284964581585">́§€ê¸ˆ ́ˆ¨ê¸°ê¸°</translation>
<translation id="1219129156119358924">́‹œ́¤í…œ ë³´́•ˆ</translation>
<translation id="1227224963052638717">́•Œ ́ˆ˜ ́—†ë” ́ •́±…́…니다.</translation>
<translation id="1227633850867390598">ê°’ ́ˆ¨ê¸°ê¸°</translation>
<translation id="1228893227497259893">́˜ëª»ëœ ê°œ́²´ ́‹ë³„́</translation>
<translation id="1232569758102978740">́ œëª© ́—†́Œ</translation>
<translation id="1254117744268754948">í´ë” ́„ íƒ</translation>
-<translation id="1264126396475825575"><ph name="CRASH_TIME" />́— ́º¡́²˜ëœ ́˜¤ë¥˜ ë³´ê³ ́„œ(́•„́§ ́—…로드 ë˜ë” 무́‹œë˜́§€ ́•́Œ)</translation>
+<translation id="1264126396475825575"><ph name="CRASH_TIME" />́— ́º¡́²˜ëœ 비́ •́ƒ ́¢…료 ë³´ê³ ́„œ(́•„́§ ́—…로드 ë˜ë” 무́‹œë˜́§€ ́•́Œ)</translation>
<translation id="1285320974508926690">́´ ́‚¬́´í¸ 번́—­ ́•ˆí•¨</translation>
<translation id="129553762522093515">́µœê·¼́— ë‹«́€ 탭</translation>
<translation id="129863573139666797"><ph name="BEGIN_LINK" />́¿ í‚¤ ́‚­́ œí•´ 보기<ph name="END_LINK" /></translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">́˜ˆ</translation>
<translation id="1430915738399379752">́¸́‡„</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /><ph name="DOMAIN" /> í˜́´́§€ë¥¼ 방문<ph name="END_LINK" />í•˜ë ¤ë” ́‹œë„ê°€ ́°¨ë‹¨ë˜́—ˆ́µë‹ˆë‹¤.</translation>
+<translation id="1491663344921578213">현́¬ <ph name="SITE" />́—́„œ ́¸́¦́„œ ê³ ́ •́„ ́‚¬́©í•˜ê¸° 때문́— 방문할 ́ˆ˜ ́—†́µë‹ˆë‹¤. 네í¸́›Œí¬ ́˜¤ë¥˜́™€ 공격́€ 대부분 ́¼́‹œ́ ́´ë¯€ë¡œ ́ ́‹œ 후 í˜́´́§€ê°€ ́ •́ƒí™”ë  ê²ƒ́…니다. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">́˜¤ë˜ëœ 것́œ¼ë¡œ ́•Œë ¤́§„ ́´ í˜́´́§€́˜ ́ €́¥ëœ ́‚¬ë³¸́„ í‘œ́‹œí•©ë‹ˆë‹¤.</translation>
<translation id="1519264250979466059">́ƒ́„± ë‚ ́§œ</translation>
<translation id="1549470594296187301">́´ 기ë¥́„ ́´́©í•˜ë ¤ë©´ ́ë°”́¤í¬ë¦½í¸ë¥¼ ́‚¬́©í•˜ë„ë¡ ́„¤́ •í•´́•¼ 합니다.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">네í¸́›Œí¬ 구́„±́´ ́˜ëª»ë˜́–´ ê°€́ ¸́˜¬ ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="1644574205037202324">방문 기ë¡</translation>
<translation id="1645368109819982629">́§€́›ë˜́§€ ́•ë” 프로토́½œ</translation>
-<translation id="1655462015569774233">{1,plural, =1{́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ ́–´́ œ 만료ë˜́–´ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. 현́¬ ́»´í“¨í„°́˜ ́‹œê³„ê°€ <ph name="CURRENT_DATE" />ë¡œ ́„¤́ •ë˜́–´ ́ˆ́µë‹ˆë‹¤. ́‹œê°„́´ ́ •í™•í•˜́§€ ́•́œ¼ë©´ ́‹œ́¤í…œ ́‹œê³„를 ́ˆ˜́ •í•œ ë’¤ ́´ í˜́´́§€ë¥¼ ́ƒˆë¡œê³ ́¹¨í•˜́„¸́”.}other{́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ #́¼ ́ „́— 만료ë˜́–´ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. 현́¬ ́»´í“¨í„°́˜ ́‹œê³„ê°€ <ph name="CURRENT_DATE" />ë¡œ ́„¤́ •ë˜́–´ ́ˆ́µë‹ˆë‹¤. ́‹œê°„́´ ́ •í™•í•˜́§€ ́•́œ¼ë©´ ́‹œ́¤í…œ ́‹œê³„를 ́ˆ˜́ •í•œ ë’¤ ́´ í˜́´́§€ë¥¼ ́ƒˆë¡œê³ ́¹¨í•˜́„¸́”.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" />́—́„œë” ́‚¬́©́ ́ •ë³´ë¥¼ 보호하기 ́œ„í•´ ́¼ë°˜́ ́œ¼ë¡œ ́•”호화를 ́‚¬́©í•©ë‹ˆë‹¤. ́´ë²ˆ́— Chromé—́„œ <ph name="SITE" />́— ́—°ê²°́„ ́‹œë„í–ˆ́„ ë•Œ ́›¹́‚¬́´í¸́—́„œ 비́ •́ƒ́ ́´ê³  ́˜ëª»ëœ ́‚¬́©́ ́¸́¦ ́ •ë³´ë¥¼ 반환했́µë‹ˆë‹¤. ́´ë” 공격́ê°€ <ph name="SITE" />́¸ 것́²˜ëŸ¼ ê°€́¥í•˜ë ¤ê³  하거나 Wi-Fi 로그́¸ 화면́´ ́—°ê²°́„ 방해했기 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. ë°́´í„° êµí™˜́´ ë°œ́ƒí•˜ê¸° ́ „́— Chromé—́„œ ́—°ê²°́„ ́¤‘단했기 때문́— ́‚¬́©́ ́ •ë³´ë” ́•ˆ́ „합니다.</translation>
<translation id="168841957122794586">́„œë²„ ́¸́¦́„œ́— ́•ˆ́ „́„±́´ ë‚®́€ ́•”호화 키가 í¬í•¨ë˜́–´ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="1701955595840307032">́¶”́²œ ́½˜í…́¸  받기</translation>
-<translation id="1706954506755087368">{1,plural, =1{́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ ë‚´́¼ ë°œí¨ë  ́˜ˆ́ •́´ë©° ́´́— ë”°ë¼ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.}other{́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ #́¼ 후 ë°œí¨ë  ́˜ˆ́ •́´ë©° ́´́— ë”°ë¼ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">́‹œ́¤í…œ 관리́́—게 문́˜í•˜́„¸́”.</translation>
<translation id="17513872634828108">́—´ë¦° 탭</translation>
<translation id="1753706481035618306">í˜́´́§€ 번호</translation>
-<translation id="1761412452051366565">Googlé—́„œ ́¶”́²œí•œ ë§́¶¤́„¤́ • ́½˜í…́¸ ë¥¼ ë°›́œ¼ë ¤ë©´ ë™ê¸°í™”를 ́‚¬́© ́„¤́ •í•©ë‹ˆë‹¤.</translation>
-<translation id="1763864636252898013">́´ ́„œë²„ê°€ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́œ¼ë©° 기기́˜ ́´́˜́²´́ œ́—́„œ ́‹ ë¢°í•˜ë” ë³´́•ˆ ́¸́¦́„œê°€ ́•„닙니다. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows 네í¸́›Œí¬ ́§„단 프로그ë΅„ ́‹¤í–‰<ph name="END_LINK" />í•´ ë³´́„¸́”.</translation>
<translation id="1783075131180517613">ë™ê¸°í™” ́•”호를 ́—…ë°́´í¸í•˜́„¸́”.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">́µœê·¼ 방문한 ë¶ë§ˆí¬ê°€ ́—¬ê¸°́— í‘œ́‹œë©ë‹ˆë‹¤.</translation>
<translation id="1821930232296380041">́˜ëª»ëœ ́”́²­ ë˜ë” ́”́²­ 매개변́ˆ˜</translation>
<translation id="1838667051080421715">́§€ê¸ˆ ́›¹í˜́´́§€́˜ ́†Œ́¤ë¥¼ ë³´ê³  ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="1871208020102129563">프ë¡́‹œê°€ .pac ́¤í¬ë¦½í¸ URĹ´ ́•„ë‹Œ ê³ ́ • 프ë¡́‹œ ́„œë²„를 ́‚¬́©í•˜ë„ë¡ ́„¤́ •ë©ë‹ˆë‹¤.</translation>
<translation id="1883255238294161206">́ ‘기 목ë¡</translation>
<translation id="1898423065542865115">í•„í„°ë§</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" />́—́„œ 로그́¸ ́¸́¦́„œë¥¼ ́¹́¸í•˜́§€ ́•́•˜ê±°ë‚˜ 로그́¸ ́¸́¦́„œê°€ 만료ë˜́—ˆ́„ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="194030505837763158"><ph name="LINK" />(́œ¼)ë¡œ ́´ë™</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> ë¶ë§ˆí¬</translation>
<translation id="1973335181906896915">́¼ë ¨í™” ́˜¤ë¥˜</translation>
<translation id="1974060860693918893">고급</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{́™¸ 1ê°œ}other{́™¸ #ê°œ}}</translation>
<translation id="2025186561304664664">프ë¡́‹œê°€ ́ë™ ́„¤́ •ë˜ë„ë¡ ́§€́ •ë©ë‹ˆë‹¤.</translation>
<translation id="2030481566774242610"><ph name="LINK" />́„(를) ́°¾́œ¼́…¨ë‚˜́”?</translation>
<translation id="2031925387125903299">́´ ́•Œë¦¼́€ ́ƒˆë¡œ́´ ́‚¬́´í¸ë¥¼ ́²˜́Œ́œ¼ë¡œ 방문할 ë•Œ 부모님́˜ ́¹́¸́´ í•„́”하므로 í‘œ́‹œë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />프ë¡́‹œ ë° ë°©í™”ë²½ 확́¸<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">́°í¸ë²ˆí˜¸</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{́ œ́•ˆ 1ê°œ}other{́ œ́•ˆ #ê°œ}}</translation>
<translation id="2065985942032347596">́¸́¦ í•„́”</translation>
<translation id="2079545284768500474">́‹¤í–‰ ́·΅†Œ</translation>
<translation id="20817612488360358">́‹œ́¤í…œ 프ë¡́‹œ ́„¤́ •́´ ́‚¬́©í•˜ë„ë¡ ́„¤́ •ë˜́—ˆ́§€ë§Œ 명́‹œ́  프ë¡́‹œ ́„¤́ •ë„ ́§€́ •ë˜́–´ ́ˆ́µë‹ˆë‹¤.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">ë¶ë§ˆí¬ ́ˆ˜́ •</translation>
<translation id="2166049586286450108">́ „́²´ 관리́ ́•¡́„¸́¤</translation>
<translation id="2166378884831602661">́‚¬́´í¸́— ë³´́•ˆ ́—°ê²°í•  ́ˆ˜ ́—†́Œ</translation>
-<translation id="2171101176734966184"><ph name="DOMAIN" />́— ́ ‘́†í•˜ë ¤ í–ˆ́œ¼ë‚˜ ́„œë²„́—́„œ ́•ˆ́ „́„±́´ ë‚®́€ ́„œëª… ́•Œê³ ë¦¬́¦˜́„ ́‚¬́©í•˜́—¬ ́„œëª…ëœ ́¸́¦́„œë¥¼ ́ „달했́µë‹ˆë‹¤. ́´ë” ́„œë²„́—́„œ ́ „달한 ë³´́•ˆ ́격́¦ëª… ́ •ë³´ê°€ ́œ„́¡°ë˜́—ˆ́„ ́ˆ˜ ́ˆ́œ¼ë©° ́„œë²„를 ê°€́¥í•œ 공격́́™€ 통́‹  ́¤‘́¼ ́ˆ˜ ́ˆ́Œ́„ ́˜ë¯¸í•©ë‹ˆë‹¤.</translation>
<translation id="2181821976797666341">́ •́±…</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{́£¼́†Œ 1ê°œ}other{́£¼́†Œ #ê°œ}}</translation>
<translation id="2212735316055980242">́ •́±…́„ ́°¾́„ ́ˆ˜ ́—†́Œ</translation>
<translation id="2213606439339815911">항목́„ ê°€́ ¸́˜¤ë” ́¤‘...</translation>
-<translation id="2214283295778284209"><ph name="SITE" />́„(를) ́‚¬́©í•  ́ˆ˜ ́—†́Œ</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />́§„단 ́•±<ph name="END_LINK" />́„ ́‚¬́©í•˜́—¬ ́—°ê²° 문́ œë¥¼ 해결하́„¸́”.</translation>
+<translation id="2239100178324503013">́§€ê¸ˆ 보내기</translation>
<translation id="225207911366869382">́´ ê°’́€ ́´ ́ •́±…́— ́‚¬́©ë˜́§€ ́•́µë‹ˆë‹¤.</translation>
<translation id="2262243747453050782">HTTP ́˜¤ë¥˜</translation>
<translation id="2282872951544483773">́‚¬́©í•  ́ˆ˜ ́—†ë” ́‹¤í—˜</translation>
<translation id="2292556288342944218">́¸í„°ë„· ́•¡́„¸́¤ê°€ ́°¨ë‹¨ë¨</translation>
<translation id="229702904922032456">ë£¨í¸ ë˜ë” ́¤‘ê°œ ́¸́¦́„œê°€ 만료ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="230155334948463882">́ƒˆ ́¹´ë“œ́¸ê°€́”?</translation>
+<translation id="2305919008529760154">́„œë²„ ë„ë©”́¸́´ <ph name="DOMAIN" />́„́„ ́¦ëª…í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ë³´́•ˆ ́¸́¦́„œê°€ 부́ •í•œ ë°©́‹́œ¼ë¡œ 발급ë˜́—ˆ́„ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535"><ph name="DOMAIN" />́— ́‚¬́©́ ́´ë¦„ê³¼ 비밀번호를 ́…력해́•¼ 합니다.</translation>
+<translation id="2318774815570432836"><ph name="SITE" />́—́„œ HSTS를 ́‚¬́©í•˜ê³  ́ˆê¸° 때문́— 방문할 ́ˆ˜ ́—†́µë‹ˆë‹¤. 네í¸́›Œí¬ ́˜¤ë¥˜́™€ 공격́€ 대부분 ́¼́‹œ́ ́´ë¯€ë¡œ ́ ́‹œ 후 í˜́´́§€ê°€ ́ •́ƒí™”ë  ê²ƒ́…니다. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155"><ph name="ENTRY_INDEX" /> ́ƒ‰́¸́˜ ́˜ëª»ëœ ë¶ë§ˆí¬ 무́‹œë¨</translation>
<translation id="2354001756790975382">기타 ë¶ë§ˆí¬</translation>
<translation id="2359808026110333948">계́†</translation>
-<translation id="2365563543831475020"><ph name="CRASH_TIME" />́— ́º¡́²˜ëœ ́˜¤ë¥˜ ë³´ê³ ́„œê°€ ́—…로드ë˜́§€ ́•́•˜́µë‹ˆë‹¤.</translation>
+<translation id="2365563543831475020"><ph name="CRASH_TIME" />́— ́º¡́²˜ëœ 비́ •́ƒ ́¢…료 ë³´ê³ ́„œê°€ ́—…로드ë˜́§€ ́•́•˜́µë‹ˆë‹¤.</translation>
<translation id="2367567093518048410">́ˆ˜́¤€</translation>
+<translation id="2371153335857947666">{1,plural, =1{́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ ́–´́ œ 만료ë˜́–´ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. 현́¬ ́»´í“¨í„°́˜ ́‹œê³„ê°€ <ph name="CURRENT_DATE" />ë¡œ ́„¤́ •ë˜́–´ ́ˆ́µë‹ˆë‹¤. ́‹œê°„́´ ́ •í™•í•˜́§€ ́•́œ¼ë©´ ́‹œ́¤í…œ ́‹œê³„를 ́ˆ˜́ •í•œ ë’¤ ́´ í˜́´́§€ë¥¼ ́ƒˆë¡œê³ ́¹¨í•˜́„¸́”. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" />}other{́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ #́¼ ́ „́— 만료ë˜́–´ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. 현́¬ ́»´í“¨í„°́˜ ́‹œê³„ê°€ <ph name="CURRENT_DATE" />ë¡œ ́„¤́ •ë˜́–´ ́ˆ́µë‹ˆë‹¤. ́‹œê°„́´ ́ •í™•í•˜́§€ ́•́œ¼ë©´ ́‹œ́¤í…œ ́‹œê³„를 ́ˆ˜́ •í•œ ë’¤ ́´ í˜́´́§€ë¥¼ ́ƒˆë¡œê³ ́¹¨í•˜́„¸́”. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">́‚¬́© ê°€ë¥í•œ 대́²´ UI ́—†́Œ</translation>
<translation id="2384307209577226199">́—”터프ë¼́´́¦ˆ 기본값</translation>
-<translation id="238526402387145295"><ph name="SITE" /> ́‚¬́´í¸́—́„œ <ph name="BEGIN_LINK" />HSTS를 ́‚¬́©<ph name="END_LINK" />하고 ́ˆê¸° 때문́— 방문할 ́ˆ˜ ́—†́µë‹ˆë‹¤. 네í¸́›Œí¬ ́˜¤ë¥˜́™€ 공격́€ 대부분 ́¼́‹œ́ ́´ë¯€ë¡œ ́ ́‹œ 후 í˜́´́§€ê°€ ́ •́ƒí™”ë  ê²ƒ́…니다.</translation>
<translation id="2386255080630008482">́„œë²„ ́¸́¦́„œê°€ í기ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="2392959068659972793">ê°’́´ ́„¤́ •ë˜́§€ ́•́€ ́ •́±… í‘œ́‹œ</translation>
<translation id="2396249848217231973">́‚­́ œ ́‹¤í–‰ ́·΅†Œ(&amp;U)</translation>
-<translation id="2413528052993050574">́´ ́„œë²„ê°€ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́œ¼ë©° ́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ ́·΅†Œë  ́ˆ˜ ́ˆ́µë‹ˆë‹¤. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="2455981314101692989">́´ ́›¹í˜́´́§€́—́„œë” ́´ ́–‘́‹́— 대한 ́ë™́™„́„± 기ë¥́„ ́‚¬́©í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
+<translation id="2463739503403862330">́…ë ¥</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />네í¸́›Œí¬ ́§„단 í”„ë¡œê·¸ë¨ ́‹¤í–‰<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">ê²€́ƒ‰ URĹ´ ́˜ëª»ë¨</translation>
<translation id="2491120439723279231">́„œë²„ ́¸́¦́„œ́— ́˜¤ë¥˜ê°€ ́ˆ́µë‹ˆë‹¤.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">́ œ́¶œ</translation>
<translation id="2674170444375937751">방문 기ë¡́—́„œ ́´ í˜́´́§€ë¥¼ ́‚­́ œí•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
<translation id="2677748264148917807">나가기</translation>
+<translation id="269990154133806163">́„œë²„́—́„œ ́¸́¦́„œ 투명́„± ́ •́±…́„ ́‚¬́©í•˜́—¬ ê³µê°œëœ ́¸́¦́„œê°€ ́•„ë‹Œ 다른 비공개 ́¸́¦́„œë¥¼ ́ œ́‹œí–ˆ́µë‹ˆë‹¤. ́¸́¦́„œ 투명́„± ́ •́±…́€ ́¸́¦́„œê°€ ́‹ ë¢°í•  ́ˆ˜ ́ˆ́œ¼ë©° 공격́로부터 ́‚¬́©́를 보호하고 ́ˆ́Œ́„ ë³´́¥í•˜ê¸° ́œ„í•œ 것́œ¼ë¡œ ́¼ë¶€ ́¸́¦́„œ́˜ ê²½́° í•„́ˆ˜́‚¬í•­́…니다. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">ê°’́´ 형́‹ê³¼ ́¼́¹˜í•˜́§€ ́•́µë‹ˆë‹¤.</translation>
<translation id="2704951214193499422">현́¬ Chromiuḿ—́„œ ́¹´ë“œë¥¼ 확́¸í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. 나́¤‘́— 다́‹œ ́‹œë„í•´ ́£¼́„¸́”.</translation>
<translation id="2705137772291741111">́‚¬́´í¸́˜ ́ €́¥ëœ(́º́‹œëœ) ́‚¬ë³¸́„ ́½́„ ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="2709516037105925701">́ë™́™„́„±</translation>
+<translation id="2712118517637785082"><ph name="DOMAIN" />́— ́ ‘́†í•˜ë ¤ í–ˆ́œ¼ë‚˜ 발행기관́—́„œ ́„œë²„ê°€ ́ œ́‹œí•œ ́¸́¦́„œë¥¼ í기했́µë‹ˆë‹¤. ́´ë” ́„œë²„ê°€ ́ œ́‹œí•œ ë³´́•ˆ ́격́¦ëª… ́ •ë³´ë” ́ ˆëŒ€ ́‹ ë¢°í•  ́ˆ˜ ́—†́Œ́„ ́˜ë¯¸í•©ë‹ˆë‹¤. 현́¬ í•´́»¤́™€ 통́‹  ́¤‘́¼ ́ˆ˜ë„ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">권한 ́”́²­</translation>
<translation id="2721148159707890343">́”́²­ ́„±ê³µ</translation>
<translation id="2728127805433021124">́„œë²„́˜ ́¸́¦́„œê°€ ́•ˆ́ „́„±́´ ë‚®́€ ́„œëª… ́•Œê³ ë¦¬́¦˜́„ ́‚¬́©í•˜́—¬ ́„œëª…ë˜́–´ ́ˆ́µë‹ˆë‹¤.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">́£¼́†Œ́°½ ë° ê²€́ƒ‰́°½</translation>
<translation id="2826760142808435982">́´ ́—°ê²°́€ <ph name="CIPHER" />́„(를) ́‚¬́©í•˜́—¬ ́•”호화ë˜ê³  ́¸́¦ë˜ë©° <ph name="KX" />́„(를) 키 êµí™˜ 매́»¤ë‹ˆ́¦˜́œ¼ë¡œ ́‚¬́©í•©ë‹ˆë‹¤.</translation>
<translation id="2835170189407361413">́„œ́‹ ́§€́°ê¸°</translation>
-<translation id="2837049386027881519">TLS ë˜ë” SSL 프로토́½œ́˜ ́´́ „ 버́ „́„ ́‚¬́©í•˜́—¬ 다́‹œ ́—°ê²°́„ ́‹œë„í–ˆ́µë‹ˆë‹¤. ́¼ë°˜́ ́œ¼ë¡œ ́„œë²„ê°€ ́•„́£¼ ́˜¤ë˜ëœ ́†Œí”„í¸́›΅–´ë¥¼ ́‚¬́© ́¤‘́´ë©° 기타 ë³´́•ˆ 문́ œê°€ ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" />́˜ ́„œë²„ ́¸́¦́„œê°€ ́œ„́¡°ëœ 것 ê°™́µë‹ˆë‹¤.</translation>
<translation id="2889159643044928134">́ƒˆë¡œê³ ́¹¨ ́•ˆí•¨</translation>
-<translation id="2896499918916051536">́´ 플러그́¸́€ ́§€́›ë˜́§€ ́•́µë‹ˆë‹¤.</translation>
+<translation id="2900469785430194048">́´ ́›¹í˜́´́§€ë¥¼ í‘œ́‹œí•˜ë ¤ê³  í–ˆ́œ¼ë‚˜ Chrome 메모리가 부́¡±í•©ë‹ˆë‹¤.</translation>
<translation id="2909946352844186028">네í¸́›Œí¬ 변경́´ ê°́§€ë˜́—ˆ́µë‹ˆë‹¤.</translation>
-<translation id="2915500479781995473">́´ ́„œë²„ê°€ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́œ¼ë©° ́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ 만료ë˜́—ˆ́µë‹ˆë‹¤. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. ́»´í“¨í„°́˜ ́‹œê³„ê°€ 현́¬ <ph name="CURRENT_TIME" />(́œ¼)ë¡œ ́„¤́ •ë˜́–´ ́ˆ́µë‹ˆë‹¤. ́‹œê°„́´ ́ •í™•í•˜́§€ ́•́œ¼ë©´ ́‹œ́¤í…œ ́‹œê³„를 ́ˆ˜́ •í•œ 다́Œ ́´ í˜́´́§€ë¥¼ ́ƒˆë¡œê³ ́¹¨í•˜́„¸́”.</translation>
<translation id="2922350208395188000">́„œë²„ ́¸́¦́„œë¥¼ 확́¸í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
-<translation id="2941952326391522266">́´ ́„œë²„ê°€ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́œ¼ë©° ́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ <ph name="DOMAIN2" />́—́„œ ́ œê³µí•œ 것́…니다. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="2948083400971632585">́„¤́ • í˜́´́§€́˜ ́—°ê²°́„ 구́„±í•˜ë” 프ë¡́‹œë¥¼ ́‚¬́© ́¤‘́§€í•  ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="2955913368246107853">ê²€́ƒ‰ ë°” 닫기</translation>
<translation id="2958431318199492670">네í¸́›Œí¬ ́„¤́ •́´ ONC í‘œ́¤€́„ ́¤€́ˆ˜í•˜́§€ ́•́µë‹ˆë‹¤. ́¼ë¶€ ́„¤́ •́„ ê°€́ ¸́˜¬ ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">́˜ëª»ëœ ́ •́±… ́œ í˜•</translation>
<translation id="3032412215588512954">́´ ́‚¬́´í¸ë¥¼ ́ƒˆë¡œê³ ́¹¨í•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
<translation id="3037605927509011580">́•—, ́´ëŸ°!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{ë™ê¸°í™”ëœ ê¸°ê¸°́— ́µœ́†Œ 1ê°œ}=1{1ê°œ(ë™ê¸°í™”ëœ ê¸°ê¸°́—ë” ê·¸ ́´́ƒ)}other{#ê°œ(ë™ê¸°í™”ëœ ê¸°ê¸°́—ë” ê·¸ ́´́ƒ)}}</translation>
<translation id="3041612393474885105">́¸́¦́„œ ́ •ë³´</translation>
<translation id="3063697135517575841">현́¬ Chromé—́„œ ́¹´ë“œë¥¼ 확́¸í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. 나́¤‘́— 다́‹œ ́‹œë„í•´ ́£¼́„¸́”.</translation>
<translation id="3093245981617870298">́˜¤í”„ë¼́¸ ́ƒíƒœ́…니다.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">́µœê·¼</translation>
<translation id="3207960819495026254">ë¶ë§ˆí¬ë¨</translation>
-<translation id="3225919329040284222">́„œë²„ê°€ ë‚´́¥ëœ 기대́¹˜́™€ ́¼́¹˜í•˜́§€ ́•ë” ́¸́¦́„œë¥¼ ́ „달했́µë‹ˆë‹¤. ́´ëŸ¬í•œ 기대́¹˜ë” ́‚¬́©́를 보호하기 ́œ„í•´ ë³´́•ˆ́´ ́—„격한 í¹́ • ́›¹́‚¬́´í¸́— í¬í•¨ë©ë‹ˆë‹¤.</translation>
<translation id="3226128629678568754">í˜́´́§€ 로드́— í•„́”í•œ ë°́´í„°ë¥¼ 다́‹œ ́ œ́¶œí•˜ë ¤ë©´ ́ƒˆë¡œê³ ́¹¨ 버í¼́„ 누릅니다.</translation>
<translation id="3228969707346345236">í˜́´́§€ê°€ <ph name="LANGUAGE" />(́œ¼)ë¡œ ë˜́–´ ́ˆ́œ¼ë¯€ë¡œ 번́—­í•˜́§€ 못했́µë‹ˆë‹¤.</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" /> ́¹´ë“œ́˜ CVC를 ́…력하́„¸́”.</translation>
-<translation id="3254409185687681395">í˜́´́§€ ë¶ë§ˆí¬</translation>
+<translation id="3254409185687681395">현́¬ í˜́´́§€ë¥¼ ë¶ë§ˆí¬́— ́¶”ê°€</translation>
<translation id="3270847123878663523">́¬́ •ë ¬ ́‹¤í–‰ ́·΅†Œ(&amp;U)</translation>
<translation id="3286538390144397061">́§€ê¸ˆ 다́‹œ ́‹œ́‘</translation>
+<translation id="3303855915957856445">ê²€́ƒ‰ê²°ê³¼ ́—†́Œ</translation>
<translation id="3305707030755673451"><ph name="TIME" />́— ë™ê¸°í™” ́•”호로 ë°́´í„°ê°€ ́•”호화ë˜́—ˆ́µë‹ˆë‹¤. ë™ê¸°í™”를 ́‹œ́‘하려면 ́…력하́„¸́”.</translation>
<translation id="333371639341676808">́´ í˜́´́§€ê°€ ́¶”ê°€́ ́¸ 대화를 ́ƒ́„±í•˜́§€ ́•ë„ë¡ ́°¨ë‹¨í•©ë‹ˆë‹¤.</translation>
+<translation id="3338095232262050444">́•ˆ́ „함</translation>
<translation id="3340978935015468852">́„¤́ •</translation>
<translation id="3345135638360864351">́´ ́‚¬́´í¸́— 대한 ́•¡́„¸́¤ ́”́²­́„ <ph name="NAME" />님́—게 ë³´ë‚´́§€ 못했́µë‹ˆë‹¤. 나́¤‘́— 다́‹œ ́‹œë„í•´ ́£¼́„¸́”.</translation>
<translation id="3355823806454867987">프ë¡́‹œ ́„¤́ • 변경...</translation>
@@ -232,7 +236,8 @@
<translation id="3452404311384756672">ê°€́ ¸́˜¤ê¸° 간격:</translation>
<translation id="3462200631372590220">́„¸ë¶€́ •ë³´ ́ˆ¨ê¸°ê¸°</translation>
<translation id="3479539252931486093">́˜ˆê¸°́¹˜ ́•́€ 문́ œê°€ ë°œ́ƒí–ˆë‚˜́”? <ph name="BEGIN_LINK" />Googlé— ́•Œë¦¬ê¸°<ph name="END_LINK" /></translation>
-<translation id="348000606199325318">́˜¤ë¥˜ ID <ph name="CRASH_LOCAL_ID" />(́„œë²„ ID: <ph name="CRASH_ID" />)</translation>
+<translation id="3479552764303398839">나́¤‘́—</translation>
+<translation id="348000606199325318">비́ •́ƒ ́¢…료 ID <ph name="CRASH_LOCAL_ID" />(́„œë²„ ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">현́¬ 부모님께 ́—°ë½í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. 나́¤‘́— 다́‹œ ́‹œë„í•´ ́£¼́„¸́”.</translation>
<translation id="3527085408025491307">í´ë”</translation>
<translation id="3528171143076753409">́„œë²„́˜ ́¸́¦́„œë¥¼ ́‹ ë¢°í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">비밀번호 ́‚¬́© 항목:</translation>
<translation id="3549644494707163724">나만́˜ ë™ê¸°í™” ́•”호로 모든 ë™ê¸°í™” ë°́´í„° ́•”호화</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" />ê°œ ë”보기</translation>
+<translation id="3555561725129903880">ë³´́•ˆ ́¸́¦́„œ́˜ ́¶œ́²˜ê°€ <ph name="DOMAIN2" />́´ë¯€ë¡œ ́„œë²„ ë„ë©”́¸́´ <ph name="DOMAIN" />́„́„ ́¦ëª…í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">́—°ê²°́´ 비공개로 ́„¤́ •ë˜́–´ ́ˆ́§€ ́•́µë‹ˆë‹¤.</translation>
<translation id="3583757800736429874">́´ë™ 다́‹œ ́‹¤í–‰(&amp;R)</translation>
<translation id="3586931643579894722">́„¸ë¶€́ •ë³´ ́ˆ¨ê¸°ê¸°</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">ê°’ í‘œ́‹œ</translation>
<translation id="3630155396527302611">́´ë¯¸ 네í¸́›Œí¬ ́•¡́„¸́¤ê°€ í—ˆ́©ëœ 프로그ë΅œ¼ë¡œ ë˜́–´ ́ˆë” ê²½́°
목ë¡́—́„œ ́‚­́ œí•œ ë’¤ 다́‹œ ́¶”가합니다.</translation>
+<translation id="3638794133396384728">́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ 만료ë˜́–´ ë„ë©”́¸́´ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. 현́¬ ́»´í“¨í„°́˜ ́‹œê³„ê°€ <ph name="CURRENT_TIME" />ë¡œ ́„¤́ •ë˜́–´ ́ˆ́µë‹ˆë‹¤. ́‹œê°„́´ ́ •í™•í•˜́§€ ́•́œ¼ë©´ ́‹œ́¤í…œ ́‹œê³„를 ́ˆ˜́ •í•œ ë’¤ ́´ í˜́´́§€ë¥¼ ́ƒˆë¡œê³ ́¹¨í•˜́„¸́”. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">해당 ́‹¤í—˜́© 기ë¥́€ ́–¸́ œë“ ́§€ 변경, ́¤‘́§€ ë° ́·΅†Œë  ́ˆ˜ ́ˆ́µë‹ˆë‹¤. 해당 ́‹¤í—˜́© 기ë¥́„ ́‚¬́©í•  ë•Œ ë°œ́ƒí•˜ë” ́¼́— 대해 Googlé€ ë³´́¥í•˜́§€ ́•́µë‹ˆë‹¤. ë°́´í„°ê°€ ́‚­́ œë˜ê±°ë‚˜ ê°œ́¸ ́ •ë³´ê°€ ́˜ˆê¸°́¹˜ ́•́€ 방법́œ¼ë¡œ ́œ ́¶œë  ́ˆ˜ ́ˆ́µë‹ˆë‹¤. 본́¸́´ ́‚¬́© ́„¤́ •í•œ 모든 ́‹¤í—˜ 기ë¥́€ 해당 브ë¼́°́ €́˜ 다른 ́‚¬́©́ë„ ́‚¬́©í•˜ê²Œ ë©ë‹ˆë‹¤. ́£¼́˜í•´́„œ ́§„행하́‹œê¸° ë°”ë니다.</translation>
<translation id="3650584904733503804">́œ í΅„± ê²€́‚¬ ́„±ê³µ</translation>
<translation id="3655670868607891010">́´ ë©”́‹œ́§€ê°€ ́́£¼ í‘œ́‹œëœë‹¤ë©´ 다́Œ́„ ́‹œë„í•´ ë³´́„¸́”. <ph name="HELP_LINK" /></translation>
<translation id="3658742229777143148">ê°œ́ •</translation>
+<translation id="3678029195006412963">́”́²­́„ ́„œëª…í•  ́ˆ˜ ́—†́Œ</translation>
<translation id="3681007416295224113">́¸́¦́„œ ́ •ë³´</translation>
<translation id="3693415264595406141">비밀번호:</translation>
+<translation id="3696411085566228381">́—†́Œ</translation>
<translation id="3700528541715530410">́£„́†¡í•©ë‹ˆë‹¤. ́´ í˜́´́§€́— ́•¡́„¸́¤í•  ́ˆ˜ ́ˆë” 권한́´ ́—†́µë‹ˆë‹¤.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">로드 ́¤‘...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">모바́¼ ë°́´í„° ë˜ë” Wi-Fi ́‚¬́© ́„¤́ •</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />프ë¡́‹œ, 방화벽, DNS ́„¤́ • 확́¸<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">ë³µ́‚¬í•œ ë§í¬</translation>
-<translation id="3744899669254331632">́›¹́‚¬́´í¸ê°€ Chromiuḿ´ ́²˜ë¦¬í•  ́ˆ˜ ́—†ë” ́•”í˜¸í™”ëœ ́‚¬́©́ ́¸́¦ ́ •ë³´ë¥¼ ́ „́†¡í•˜́˜€́œ¼ë¯€ë¡œ ́§€ê¸ˆ́€ <ph name="SITE" />́— 방문할 ́ˆ˜ ́—†́µë‹ˆë‹¤. 네í¸́›Œí¬ ́˜¤ë¥˜́™€ 공격́€ 대́²´ë¡œ ́¼́‹œ́ ́¸ 문́ œ́´ê¸° 때문́— ́´í›„́—ë” ́´ í˜́´́§€ê°€ ́ œëŒ€ë¡œ ́‘ë™í•  ê°€ë¥́„±́´ 높́µë‹ˆë‹¤.</translation>
<translation id="375403751935624634">́„œë²„ ́˜¤ë¥˜ê°€ ë°œ́ƒí•˜́—¬ 번́—­í•˜́§€ 못했́µë‹ˆë‹¤.</translation>
<translation id="3759461132968374835">́µœê·¼́— ë³´ê³ ëœ ë¹„́ •́ƒ ́¢…료가 ́—†́µë‹ˆë‹¤. 비́ •́ƒ ́¢…료 보고를 ́‚¬́© ́¤‘́§€í–ˆ́„ ë•Œ ë°œ́ƒí•œ 비́ •́ƒ ́¢…ë£Œë” ́—¬ê¸°́— í‘œ́‹œë˜́§€ ́•́µë‹ˆë‹¤.</translation>
<translation id="3788090790273268753">́´ ́‚¬́´í¸́˜ ́¸́¦́„œë” 2016ë…„́— 만료ë˜ë©° ́¸́¦́„œ ́²´́¸́—ë” SHA-1́„ ́‚¬́©í•˜́—¬ ́„œëª…ëœ ́¸́¦́„œê°€ í¬í•¨ë˜́–´ ́ˆ́µë‹ˆë‹¤.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">기기 ́‹ë³„́ ́¶©ëŒ</translation>
<translation id="3885155851504623709">êµêµ¬</translation>
<translation id="3901925938762663762">ë§Œë£Œëœ ́¹´ë“œ́…니다.</translation>
+<translation id="3910267023907260648"><ph name="DOMAIN" />́— ́ ‘́†í•˜ë ¤ í–ˆ́œ¼ë‚˜ ́„œë²„́—́„œ ́•ˆ́ „́„±́´ ë‚®́€ ́„œëª… ́•Œê³ ë¦¬́¦˜́„ ́‚¬́©í•˜́—¬ ́„œëª…ëœ ́¸́¦́„œë¥¼ ́ œ́‹œí–ˆ́µë‹ˆë‹¤. ́´ë” ́„œë²„́—́„œ ́ œ́‹œí•œ ë³´́•ˆ ́격́¦ëª… ́ •ë³´ê°€ ́œ„́¡°ë˜́—ˆ́„ ́ˆ˜ ́ˆ́œ¼ë©° ́„œë²„를 ê°€́¥í•œ 공격́́™€ 통́‹  ́¤‘́¼ ́ˆ˜ ́ˆ́Œ́„ ́˜ë¯¸í•©ë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ ë‚´́¼ë¶€í„° ́œ í¨í•˜ë¯€ë¡œ 현́¬ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" />}other{́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ #́¼ 후부터 ́œ í¨í•˜ë¯€ë¡œ 현́¬ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">PDF 문́„œë¥¼ 로드하́§€ 못했́µë‹ˆë‹¤.</translation>
<translation id="3963721102035795474">ë¦¬ë” ëª¨ë“œ</translation>
+<translation id="397105322502079400">계́‚° ́¤‘...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" />́´(ê°€) ́°¨ë‹¨ë¨</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{́£¼ë³€ ́›¹í˜́´́§€ 1ê°œ}other{́£¼ë³€ ́›¹í˜́´́§€ #ê°œ}}</translation>
<translation id="4021036232240155012">DNSë” ́›¹́‚¬́´í¸ ́´ë¦„́„ ́¸í„°ë„· ́£¼́†Œë¡œ ë³€í™˜í•˜ë” ë„¤í¸́›Œí¬ ́„œë¹„́¤́…니다.</translation>
<translation id="4030383055268325496">́¶”ê°€ ́‹¤í–‰ ́·΅†Œ(&amp;U)</translation>
-<translation id="4032534284272647190"><ph name="URL" />́— 대한 ́—‘́„¸́¤ê°€ 거부ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="404928562651467259">경고</translation>
<translation id="4058922952496707368">'<ph name="SUBKEY" />' 키: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">í´ë¼́´́–¸í¸́™€ ́„œë²„ê°€ ́¼ë°˜́ ́¸ SSL 프로토́½œ 버́ „ ë˜ë” ́•”호화 ́ œí’ˆêµ°́„ ́§€́›í•˜́§€ ́•́µë‹ˆë‹¤.</translation>
<translation id="4079302484614802869">프ë¡́‹œ ́„¤́ •́´ ê³ ́ • 프ë¡́‹œ ́„œë²„ê°€ ́•„ë‹Œ .pac ́¤í¬ë¦½í¸ URĹ„ ́‚¬́©í•˜ë„ë¡ ́„¤́ •ë©ë‹ˆë‹¤.</translation>
<translation id="4103249731201008433">기기 ́¼ë ¨ë²ˆí˜¸ê°€ ́˜ëª»ë¨</translation>
<translation id="4103763322291513355">́°¨ë‹¨ëœ URL ë° ́‹œ́¤í…œ 관리́ê°€ ́„¤́ •í•œ 기타 ́ •́±… 목ë¡́„ 확́¸í•˜ë ¤ë©´ &lt;strong&gt;chrome://policy&lt;/strong&gt;를 방문하́„¸́”.</translation>
+<translation id="4110615724604346410">ë³´́•ˆ ́¸́¦́„œ́— ́˜¤ë¥˜ê°€ ́ˆ́–´́„œ ́„œë²„ ë„ë©”́¸́´ <ph name="DOMAIN" />́„́„ ́¦ëª…í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">́§€́›ë˜́§€ ́•ë” ́ •́±… ë²”́œ„́…니다.</translation>
+<translation id="4118212371799607889">Chromiuḿ—́„œ ́‹ ë¢°í•˜́§€ ́•ë” 기관́—́„œ 발행한 ́¸́¦́„œë¥¼ ́ œê³µí•˜́—¬ ́„œë²„ ë„ë©”́¸́´ <ph name="DOMAIN" />́„́„ ́¦ëª…í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{́™¸ 1ê°œ}other{́™¸ #ê°œ}}</translation>
<translation id="4130226655945681476">네í¸́›Œí¬ ́¼€́´ë¸”, 모ë€, ë¼́°í„° 확́¸</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromiuḿ—́„œ ́´ ́¹´ë“œë¥¼ ́ €́¥í•˜ë„ë¡ í•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">́‚¬́© ́¤‘́§€</translation>
<translation id="4196861286325780578">́´ë™ 다́‹œ ́‹¤í–‰(&amp;R)</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />방화벽 ë° ë°”́´ëŸ¬́¤ ë°±́‹  ́†Œí”„í¸́›΅–´ ́„¤́ • 확́¸<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{́—†́Œ}=1{́•± 1ê°œ($1)}=2{́•± 2ê°œ($1, $2)}other{́•± #ê°œ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">비́ •́ƒ ́¢…료</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />네í¸́›Œí¬ ́§„단 프로그ë΅„ ́‹¤í–‰<ph name="END_LINK" />í•´ ë³´́„¸́”.</translation>
<translation id="4250680216510889253">́•„니́”</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(́‚¬́©́ ́´ë¦„ ́—†́Œ)</translation>
<translation id="4300246636397505754">́ƒ́œ„ ́¶”́²œ</translation>
<translation id="4304224509867189079">로그́¸</translation>
+<translation id="432290197980158659">́„œë²„ê°€ ë‚´́¥ëœ 기́¤€́— ́¼́¹˜í•˜́§€ ́•ë” ́¸́¦́„œë¥¼ ́ œ́‹œí–ˆ́µë‹ˆë‹¤. ́´ëŸ¬í•œ 기́¤€́€ ë³´́•ˆ́´ ́—„격한 í¹́ • ́›¹́‚¬́´í¸́—́„œ ́‚¬́©́를 보호하기 ́œ„í•´ ́ ́©ë©ë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">ë„́›€ë§́„ ́°¾́§€ 못했́µë‹ˆë‹¤.</translation>
+<translation id="4331708818696583467">́•ˆ́ „하́§€ ́•́Œ</translation>
<translation id="4372948949327679948">́˜ˆ́ƒ <ph name="VALUE_TYPE" /> ê°’́…니다.</translation>
-<translation id="4377125064752653719"><ph name="DOMAIN" />́— ́ ‘́†í•˜ë ¤ í–ˆ́œ¼ë‚˜ 발행기관́—́„œ ́„œë²„ê°€ ́ „달한 ́¸́¦́„œë¥¼ í기했́µë‹ˆë‹¤. ́´ë” ́„œë²„ê°€ ́ œ́‹œí•œ ë³´́•ˆ ́격́¦ëª… ́ •ë³´ë¥¼ ́‹ ë¢°í•  ́ˆ˜ ́—†́Œ́„ ́˜ë¯¸í•©ë‹ˆë‹¤. ́‚¬́©́ë” í˜„́¬ 공격́́™€ 통́‹  ́¤‘́¼ ́ˆ˜ë„ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="4381091992796011497">́‚¬́©́ ́´ë¦„:</translation>
<translation id="4394049700291259645">́‚¬́© ́¤‘́§€</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> - <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">ê²€́ƒ‰ê²°ê³¼</translation>
-<translation id="4424024547088906515">́´ ́„œë²„ê°€ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́œ¼ë©° Chromé—́„œ ́‹ ë¢°í•˜ë” ë³´́•ˆ ́¸́¦́„œê°€ ́•„닙니다. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" />́—́„œ 로그́¸ ́¸́¦́„œë¥¼ ́¹́¸í•˜́§€ ́•́•˜ê±°ë‚˜ 로그́¸ ́¸́¦́„œê°€ ́ œê³µë˜́§€ ́•́•˜́„ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="443673843213245140">프ë¡́‹œ ́‚¬́©́€ ́¤‘́§€ë˜́—ˆ́§€ë§Œ 명́‹œ́  프ë¡́‹œ ́„¤́ •́´ ́§€́ •ë˜́–´ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Google SafeSitesê°€ ́‚¬́© ́„¤́ •ë˜́–´ ́ˆ́–´ ́´ ́•Œë¦¼́´ í‘œ́‹œë˜́—ˆ́µë‹ˆë‹¤.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">́„¸ë¶€́ •ë³´</translation>
<translation id="4558551763791394412">확́¥ í”„ë¡œê·¸ë¨ ́‚¬́© ́¤‘́§€í•´ 보기</translation>
<translation id="4587425331216688090">Chromé—́„œ ́£¼́†Œë¥¼ ́‚­́ œí•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
+<translation id="4589078953350245614"><ph name="DOMAIN" />́— ́ ‘́†í•˜ë ¤ê³  ́‹œë„í–ˆ́§€ë§Œ ́„œë²„́—́„œ ́˜ëª»ëœ ́¸́¦́„œë¥¼ ́ œ́‹œí–ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459"><ph name="DOMAIN" />́— 대한 ́—°ê²°́€ ́µœ́‹  ́•”호화 기́ˆ ́„ ́‚¬́©í•˜́—¬ ́•”호화ë©ë‹ˆë‹¤.</translation>
<translation id="4594403342090139922">́‚­́ œ ́‹¤í–‰ ́·΅†Œ(&amp;U)</translation>
+<translation id="4627442949885028695">다른 기기́—́„œ 계́†</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">́§€ê¸ˆ 확́¥ í”„ë¡œê·¸ë¨ í˜́´́§€ë¥¼ ë³´ê³  ́ˆ́µë‹ˆë‹¤.</translation>
-<translation id="467662567472608290">́´ ́„œë²„ê°€ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́œ¼ë©° ́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œ́— ́˜¤ë¥˜ê°€ ́ˆ́µë‹ˆë‹¤. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
-<translation id="4697214168136963651"><ph name="URL" />́´(ê°€) ́°¨ë‹¨ë¨</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">́—°ê²°́´ ëê¹€</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows 네í¸́›Œí¬ ́§„단 í”„ë¡œê·¸ë¨ ́‹¤í–‰<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">플ë«í¼</translation>
<translation id="4744603770635761495">́‹¤í–‰ ê°€ë¥ ê²½ë¡œ</translation>
<translation id="4756388243121344051">방문 기ë¡(&amp;H)</translation>
+<translation id="4759238208242260848">다́´ë¡œë“œ</translation>
<translation id="4764776831041365478"><ph name="URL" />́˜ ́›¹í˜́´́§€ê°€ ́¼́‹œ́ ́œ¼ë¡œ 다́´ë˜́—ˆê±°ë‚˜ ́ƒˆ ́›¹ ́£¼́†Œë¡œ ́™„́ „íˆ ́´ë™í–ˆ́„ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="4771973620359291008">́•Œ ́ˆ˜ ́—†ë” ́˜¤ë¥˜ê°€ ë°œ́ƒí–ˆ́µë‹ˆë‹¤.</translation>
<translation id="4782449893814226250">́´ í˜́´́§€ë¥¼ ë°©ë¬¸í•´ë„ ê´œ́°®́€́§€ 부모님께 문́˜í–ˆ́µë‹ˆë‹¤.</translation>
<translation id="4800132727771399293">́œ í¨ê¸°ê°„ê³¼ CVC를 확́¸í•œ 후 다́‹œ ́‹œë„í•´ ́£¼́„¸́”.</translation>
-<translation id="4807049035289105102">현́¬ <ph name="SITE" />́—́„œ Chromé´ ́²˜ë¦¬í•  ́ˆ˜ ́—†ë” ́•”í˜¸í™”ëœ ́격́¦ëª… ́ •ë³´ë¥¼ ́ „́†¡í–ˆê¸° 때문́— 방문할 ́ˆ˜ ́—†́µë‹ˆë‹¤. 네í¸́›Œí¬ ́˜¤ë¥˜́™€ 공격́€ 대부분 ́¼́‹œ́ ́´ë¯€ë¡œ ́ ́‹œ 후 í˜́´́§€ê°€ ́ •́ƒí™”ë  ê²ƒ́…니다.</translation>
<translation id="4813512666221746211">네í¸́›Œí¬ ́˜¤ë¥˜</translation>
<translation id="4816492930507672669">í˜́´́§€ ë§́¶¤</translation>
<translation id="4850886885716139402">보기</translation>
<translation id="4880827082731008257">ê¸°ë¡ ê²€́ƒ‰</translation>
+<translation id="4884656795097055129">́•́œ¼ë¡œ ́—¬ê¸°́—́„œ ë” ë§́€ ë„́›€ë§́„ ë³¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{́™¸ ́›¹í˜́´́§€ 1ê°œ}other{́™¸ ́›¹í˜́´́§€ #ê°œ}}</translation>
<translation id="4923417429809017348">í˜́´́§€ê°€ ́•Œ ́ˆ˜ ́—†ë” ́–¸́–´́—́„œ <ph name="LANGUAGE_LANGUAGE" />(́œ¼)ë¡œ 번́—­ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="4926049483395192435">́§€́ •í•´́•¼ 합니다.</translation>
<translation id="4930497775425430760">́´ ë©”́‹œ́§€ë” ́ƒˆë¡œ́´ ́‚¬́´í¸ë¥¼ ́²˜́Œ́œ¼ë¡œ 방문할 ë•Œ 부모님́˜ ́¹́¸́´ í•„́”하므로 í‘œ́‹œë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="495170559598752135">́‘́—…</translation>
<translation id="4958444002117714549">í¼́¹˜ê¸° 목ë¡</translation>
+<translation id="4962322354953122629">Chromé—́„œ ́‹ ë¢°í•˜́§€ ́•ë” 기관́—́„œ 발행한 ́¸́¦́„œë¥¼ ́ œê³µí•˜́—¬ ́„œë²„ ë„ë©”́¸́´ <ph name="DOMAIN" />́„́„ ́¦ëª…í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911"><ph name="ORIGINAL_LANGUAGE" />́—́„œ <ph name="TARGET_LANGUAGE" />ë¡œ 번́—­í•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
+<translation id="4989809363548539747">́´ 플러그́¸́€ ́§€́›ë˜́§€ ́•́µë‹ˆë‹¤.</translation>
<translation id="5002932099480077015">́„ íƒí•˜ë©´ Chromé—́„œ ́–‘́‹́„ ë” ë¹ ë¥´ê²Œ ́‘́„±í•  ́ˆ˜ ́ˆë„ë¡ ́´ 기기́— ́¹´ë“œ ́‚¬ë³¸́„ ́ €́¥í•©ë‹ˆë‹¤.</translation>
<translation id="5019198164206649151">ë³´́¡° 기́–µ ́¥́¹˜ ́ƒíƒœê°€ ́˜ëª»ë¨</translation>
<translation id="5023310440958281426">관리́ ́ •́±…́„ 확́¸í•˜́„¸́”.</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Google 번́—­ ́ •ë³´</translation>
<translation id="5040262127954254034">ê°œ́¸́ •ë³´</translation>
<translation id="5045550434625856497">비밀번호가 ́˜ëª»ë˜́—ˆ́µë‹ˆë‹¤.</translation>
+<translation id="5056549851600133418">́¶”́²œ ë„́›€ë§</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />프ë¡́‹œ ́£¼́†Œ 확́¸<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">́„œë²„́˜ ́¸́¦́„œê°€ 현́¬ ́œ í¨í•˜́§€ ́•́µë‹ˆë‹¤.</translation>
<translation id="5089810972385038852">́£¼</translation>
-<translation id="5094747076828555589">́´ ́„œë²„ê°€ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́œ¼ë©° Chromiuḿ—́„œ ́‹ ë¢°í•˜ë” ë³´́•ˆ ́¸́¦́„œê°€ ́•„닙니다. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="5095208057601539847">́£¼/ë„</translation>
<translation id="5115563688576182185">(64비í¸)</translation>
-<translation id="5122371513570456792">'<ph name="SEARCH_STRING" />'́— 대해 <ph name="NUMBER_OF_RESULTS" />ê°œ́˜ <ph name="SEARCH_RESULTS" />́„(를) ́°¾́•˜́µë‹ˆë‹¤.</translation>
<translation id="5141240743006678641">ë™ê¸°í™” 비밀번호를 Google ́격́¦ëª…́œ¼ë¡œ ́•”호화</translation>
<translation id="5145883236150621069">́ •́±… ́‘답́— ́˜¤ë¥˜ ́½”드가 í¬í•¨ë˜́–´ ́ˆ́Œ</translation>
<translation id="5171045022955879922">ê²€́ƒ‰ ë˜ë” URL ́…ë ¥</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">ë¶ë§ˆí¬ë°”</translation>
<translation id="5199729219167945352">́‹¤í—˜́‹¤ 기ë¥</translation>
<translation id="5251803541071282808">í´ë¼́°ë“œ</translation>
+<translation id="5277279256032773186">́§́¥́—́„œ Chromé„ ́‚¬́©í•˜́‹œë‚˜́”? 기́—…́€ ́§́›́˜ Chrome ́„¤́ •́„ 관리할 ́ˆ˜ ́ˆ́µë‹ˆë‹¤. ́́„¸íˆ ́•Œ́•„보기</translation>
<translation id="5299298092464848405">́ •́±…́„ 파́‹±í•˜ë” ́¤‘ ́˜¤ë¥˜ ë°œ́ƒ</translation>
<translation id="5300589172476337783">í‘œ́‹œ</translation>
-<translation id="5308689395849655368">́¶©ëŒ ë³´ê³ ê°€ ́‚¬́© ́¤‘́§€ë˜́—ˆ́µë‹ˆë‹¤.</translation>
+<translation id="5308689395849655368">비́ •́ƒ ́¢…료 ë³´ê³ ê°€ ́‚¬́© ́¤‘́§€ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="5317780077021120954">́ €́¥</translation>
<translation id="5327248766486351172">́´ë¦„</translation>
+<translation id="5359637492792381994">현́¬ ́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ ́œ í¨í•˜́§€ ́•́•„ ́„œë²„ ë„ë©”́¸́´ <ph name="DOMAIN" />́„́„ ́¦ëª…í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">́ •́±… ́„¤́ • ́ €́¥ ́‹¤íŒ¨</translation>
-<translation id="540969355065856584">́´ ́„œë²„ê°€ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ 현́¬ ́œ í¨í•˜́§€ ́•́µë‹ˆë‹¤. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="5421136146218899937">́¸í„°ë„· ́‚¬́© ê¸°ë¡ ́‚­́ œ...</translation>
<translation id="5430298929874300616">ë¶ë§ˆí¬ ́‚­́ œ</translation>
<translation id="5431657950005405462">파́¼́„ ́°¾́„ ́ˆ˜ ́—†́Œ</translation>
<translation id="5435775191620395718">́´ 기기́˜ 방문 기ë¡́„ í‘œ́‹œí•©ë‹ˆë‹¤. <ph name="BEGIN_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">ë™ê¸°í™”ëœ ë°́´í„°ê°€ ë§́¶¤ ́•”호로 보호ë˜ê³  ́ˆê¸° 때문́— 현́¬ ë§́¶¤ ́½˜í…́¸  ́¶”́²œ́„ ́‚¬́©í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="5439770059721715174">'<ph name="ERROR_PATH" />'́—́„œ ́¤í‚¤ë§ˆ ́œ í΅„± ê²€́‚¬ ́˜¤ë¥˜: <ph name="ERROR" /></translation>
<translation id="5452270690849572955"><ph name="HOST_NAME" /> í˜́´́§€ë¥¼ ́°¾́„ ́ˆ˜ ́—†́Œ</translation>
<translation id="5455374756549232013">́˜ëª»ëœ ́ •́±… 타́„́¤íƒ¬í”„</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">́´ ́‚¬́´í¸́—́„œ 나가́‹œê² ́µë‹ˆê¹Œ?</translation>
<translation id="5629630648637658800">́ •́±… ́„¤́ • 로드 ́‹¤íŒ¨</translation>
<translation id="5631439013527180824">́˜ëª»ëœ 기기 관리 토í°</translation>
-<translation id="5650551054760837876">ê²€́ƒ‰ê²°ê³¼ë¥¼ ́°¾́§€ 못했́µë‹ˆë‹¤.</translation>
<translation id="5677928146339483299">́°¨ë‹¨ë¨</translation>
<translation id="5710435578057952990">́´ ́›¹́‚¬́´í¸́˜ ́£¼́†Œê°€ 확́¸ë˜́§€ ́•́•˜́µë‹ˆë‹¤.</translation>
<translation id="5720705177508910913">현́¬ ́‚¬́©́</translation>
+<translation id="572328651809341494">́µœê·¼ 탭</translation>
<translation id="5784606427469807560">́¹´ë“œ 확́¸ ́¤‘́— 문́ œê°€ ë°œ́ƒí–ˆ́µë‹ˆë‹¤. ́¸í„°ë„· ́—°ê²°́„ 확́¸í•˜ê³  다́‹œ ́‹œë„하́„¸́”.</translation>
<translation id="5785756445106461925">ë˜í•œ ́´ í˜́´́§€́—ë” ́•ˆ́ „하́§€ ́•́€ 다른 리́†Œ́¤ê°€ í¬í•¨ë˜́–´ ́ˆ́µë‹ˆë‹¤. ́´ëŸ¬í•œ 리́†Œ́¤ë” ́ „́†¡ ́¤‘́— 다른 ́‚¬ëŒ́´ ë³¼ ́ˆ˜ ́ˆ́œ¼ë©° í˜́´́§€́˜ 모́–‘́„ 변경하기 ́œ„í•´ 공격́ê°€ ́ˆ˜́ •í•  ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
+<translation id="5786044859038896871">́¹´ë“œ ́ •ë³´ë¥¼ ́…력하́‹œê² ́µë‹ˆê¹Œ?</translation>
+<translation id="5803412860119678065"><ph name="CARD_DETAIL" />́„(를) ́…력하́‹œê² ́µë‹ˆê¹Œ?</translation>
<translation id="5810442152076338065"><ph name="DOMAIN" />́— 대한 ́—°ê²°́´ ë” ́´́ƒ ́‚¬́©ë˜́§€ ́•ë” ́•”호화 기́ˆ ́„ ́‚¬́©í•˜́—¬ ́•”호화ë©ë‹ˆë‹¤.</translation>
<translation id="5813119285467412249">́¶”ê°€ 다́‹œ ́‹¤í–‰(&amp;R)</translation>
+<translation id="5814352347845180253"><ph name="SITE" /> ë° ê¸°íƒ€ ́¼ë¶€ ́‚¬́´í¸́˜ 프리미́—„ ́½˜í…́¸ ë¥¼ ́•¡́„¸́¤í•˜́§€ 못할 ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
+<translation id="5843436854350372569"><ph name="DOMAIN" />́— ́ ‘́†í•˜ë ¤ í–ˆ́œ¼ë‚˜ ́„œë²„ê°€ ́•ˆ́ „́„±́´ ë‚®́€ 키가 í¬í•¨ëœ ́¸́¦́„œë¥¼ ́ œ́‹œí–ˆ́µë‹ˆë‹¤. 공격́ê°€ 비공개 키를 ́†́ƒ́‹œ́¼°́„ ́ˆ˜ ́ˆ́œ¼ë©° ́„œë²„를 ê°€́¥í•œ 공격́́™€ 통́‹  ́¤‘́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">관리́ê°€ ́´ ́‚¬́´í¸ë¥¼ ́°¨ë‹¨í•´ ́´ ë©”́‹œ́§€ê°€ í‘œ́‹œë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="5857090052475505287">́ƒˆ í´ë”</translation>
<translation id="5869405914158311789">́‚¬́´í¸́— ́—°ê²°í•  ́ˆ˜ ́—†́Œ</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">́ƒ́œ„ ́¶”́²œ</translation>
<translation id="59107663811261420">́´ íŒë§¤́́˜ Google Paymentś—́„œ ́§€́›í•˜́§€ ́•ë” ́¹´ë“œ ́œ í˜•́…니다. 다른 ́¹´ë“œë¥¼ ́„ íƒí•´ ́£¼́„¸́”.</translation>
<translation id="59174027418879706">́‚¬́© ́„¤́ •ë¨</translation>
+<translation id="5926846154125914413">́¼ë¶€ ́‚¬́´í¸́˜ 프리미́—„ ́½˜í…́¸ ë¥¼ ́•¡́„¸́¤í•˜́§€ 못할 ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="5966707198760109579">́£¼</translation>
<translation id="5967867314010545767">기ë¡́—́„œ ́‚­́ œ</translation>
<translation id="5975083100439434680">́¶•́†Œ</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">́ë™</translation>
<translation id="6042308850641462728">ë”보기</translation>
<translation id="6060685159320643512">́´ëŸ¬í•œ ́‹¤í—˜́‹¤ 기ë¥́€ 문́ œë¥¼ ́¼́œ¼í‚¬ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{́—†́Œ}=1{1ê°œ}other{#ê°œ}}</translation>
<translation id="6146055958333702838">́¼€́´ë¸”́„ 확́¸í•˜ê³  ́‚¬́© ́¤‘́¸ ë¼́°í„°, ëª¨ë€ ë˜ë” 기타 네í¸́›Œí¬ 기기를
́¬ë¶€íŒ…하́‹œê¸° ë°”ë니다.</translation>
<translation id="614940544461990577">다́Œ́„ ́‹œë„:</translation>
<translation id="6150607114729249911">́´ í˜́´́§€ë¥¼ ë°©ë¬¸í•´ë„ ê´œ́°®́€́§€ 부모님께 확́¸í•´́•¼ 합니다.</translation>
<translation id="6151417162996330722">́„œë²„ ́¸́¦́„œ́˜ ́œ í¨ 기간́´ 너무 ê¹ë‹ˆë‹¤.</translation>
-<translation id="6154808779448689242">ë°˜í™˜ëœ ́ •́±… 토í°́´ 현́¬ 토í°ê³¼ ́¼́¹˜í•˜́§€ ́•́Œ</translation>
<translation id="6165508094623778733">́́„¸íˆ ́•Œ́•„보기</translation>
<translation id="6203231073485539293">́¸í„°ë„· ́—°ê²°́„ 확́¸í•˜́„¸́”.</translation>
<translation id="6218753634732582820">Chromiuḿ—́„œ ́£¼́†Œë¥¼ ́‚­́ œí•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">네í¸́›Œí¬ ́˜ˆ́¸¡́„ ́‚¬́© ́¤‘́§€í•´ ë³´́„¸́”.</translation>
<translation id="6337534724793800597">́´ë¦„별로 ́ •́±… í•„í„°ë§</translation>
<translation id="6342069812937806050">́™„료ë¨</translation>
+<translation id="6345221851280129312">í¬ê¸°ë¥¼ ́•Œ ́ˆ˜ ́—†́Œ</translation>
<translation id="6355080345576803305">공개 ́„¸́…˜ 무́‹œ</translation>
<translation id="6358450015545214790">́́„¸íˆ ́•Œ́•„보기</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{ê·¸ ́™¸ ́ œ́•ˆ 1ê±´}other{ê·¸ ́™¸ ́ œ́•ˆ #ê±´}}</translation>
<translation id="6387478394221739770">Chromé˜ ë©‹́§„ ́ƒˆ 기ë¥́— ê´€́‹¬́´ ́ˆ́œ¼́‹­ë‹ˆê¹Œ? chrome.com/beta í˜́´́§€́—́„œ 베타 ́±„ë„́„ 방문해 ë³´́„¸́”.</translation>
-<translation id="641480858134062906"><ph name="URL" />́„(를) 로드하́§€ 못했́µë‹ˆë‹¤.</translation>
+<translation id="6389758589412724634">́´ ́›¹í˜́´́§€ë¥¼ í‘œ́‹œí•˜ë ¤ê³  í–ˆ́œ¼ë‚˜ Chromium 메모리가 부́¡±í•©ë‹ˆë‹¤.</translation>
+<translation id="6416403317709441254">현́¬ <ph name="SITE" />́—́„œ ́²˜ë¦¬í•  ́ˆ˜ ́—†ë” ́•”í˜¸í™”ëœ ́격́¦ëª… ́ •ë³´ë¥¼ ́ „́†¡í–ˆê¸° 때문́— 방문할 ́ˆ˜ ́—†́µë‹ˆë‹¤. 네í¸́›Œí¬ ́˜¤ë¥˜́™€ 공격́€ 대부분 ́¼́‹œ́ ́´ë¯€ë¡œ ́ ́‹œ 후 í˜́´́§€ê°€ ́ •́ƒí™”ë  ê²ƒ́…니다. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">́¸́¦́„œê°€ ́·΅†Œë˜́—ˆë”́§€ 확́¸í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" />́—́„œ ́—°ê²°́„ 거부했́µë‹ˆë‹¤.</translation>
<translation id="6445051938772793705">êµ­ê°€</translation>
<translation id="6451458296329894277">́–‘́‹ 다́‹œ ́ œ́¶œ 확́¸</translation>
<translation id="6458467102616083041">́ •́±…́— ́˜í•´ 기본 ê²€́ƒ‰́˜ ́‚¬́©́´ ́¤‘́§€ë˜́—ˆê¸° 때문́— 무́‹œë¨</translation>
+<translation id="6462969404041126431">ë³´́•ˆ ́¸́¦́„œê°€ ́·΅†Œë˜́—ˆ́„ ́ˆ˜ ́ˆ́–´́„œ ́„œë²„ ë„ë©”́¸́´ <ph name="DOMAIN" />́„́„ ́¦ëª…í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">기기 ́ •́±…</translation>
<translation id="6489534406876378309">비́ •́ƒ ́¢…료 ́—…로드 ́‹œ́‘하기</translation>
<translation id="6529602333819889595">́‚­́ œ 다́‹œ ́‹¤í–‰(&amp;R)</translation>
+<translation id="6534179046333460208">피́§€́»¬ ́›¹ ́ œ́•ˆ</translation>
<translation id="6550675742724504774">́˜µ́…˜</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" /> 미만</translation>
<translation id="6596325263575161958">́•”호화 ́˜µ́…˜</translation>
<translation id="662080504995468778">머무르기</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> ê²€́ƒ‰</translation>
-<translation id="6634865548447745291"><ph name="BEGIN_LINK" />́´ ́¸́¦́„œê°€ ́·΅†Œë˜́—ˆê¸° 때문́—<ph name="END_LINK" /> 현́¬ <ph name="SITE" />́— 방문할 ́ˆ˜ ́—†́µë‹ˆë‹¤. 네í¸́›Œí¬ ́˜¤ë¥˜́™€ 공격́€ 대부분 ́¼́‹œ́ ́´ë¯€ë¡œ ́ ́‹œ 후 í˜́´́§€ê°€ ́‘ë™ë  것́…니다.</translation>
<translation id="6644283850729428850">́´ ́ •́±…́€ ́‚¬́©ë˜́§€ ́•́µë‹ˆë‹¤.</translation>
+<translation id="6652240803263749613">́»´í“¨í„°́˜ ́´́˜́²´́ œ́—́„œ ë³´́•ˆ ́¸́¦́„œë¥¼ ́‹ ë¢°í•˜́§€ ́•́•„́„œ ́„œë²„ ë„ë©”́¸́´ <ph name="DOMAIN" />́„́„ ́¦ëª…í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">í´ë” ́ˆ˜́ •</translation>
<translation id="6660210980321319655"><ph name="CRASH_TIME" />́— ́ë™́œ¼ë¡œ ́‹ ê³ ë¨</translation>
<translation id="6671697161687535275">Chromiuḿ—́„œ ́ë™́™„́„± 항목 ́¶”́²œ́„ ́‚­́ œí•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">́´́ „</translation>
<translation id="6710594484020273272">&lt;ê²€́ƒ‰́–´ ́…ë ¥&gt;</translation>
<translation id="6711464428925977395">프ë¡́‹œ ́„œë²„́— 문́ œê°€ ë°œ́ƒí–ˆê±°ë‚˜ ́£¼́†Œê°€ ́˜ëª»ë˜́—ˆ́µë‹ˆë‹¤.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{́—†́Œ}=1{항목 1ê°œ}other{항목 #ê°œ}}</translation>
<translation id="674375294223700098">́•Œ ́ˆ˜ ́—†ë” ́„œë²„ ́¸́¦́„œ ́˜¤ë¥˜́…니다.</translation>
<translation id="6753269504797312559">́ •́±… ê°’</translation>
<translation id="6757797048963528358">기기가 ́ ˆ́ „ 모드 ́ƒíƒœ́…니다.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">́ •́±… ́ˆ˜́¤€́´ ́§€́›ë˜́§€ ́•́µë‹ˆë‹¤.</translation>
<translation id="6895330447102777224">́¹´ë“œê°€ 확́¸ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="6897140037006041989">́‚¬́©́ ́—́´́ „í¸</translation>
-<translation id="6903907808598579934">ë™ê¸°í™” ́‚¬́© ́„¤́ •</translation>
<translation id="6915804003454593391">́‚¬́©́:</translation>
<translation id="6957887021205513506">́„œë²„́˜ ́¸́¦́„œê°€ ́œ„́¡°ëœ 것 ê°™́µë‹ˆë‹¤.</translation>
<translation id="6965382102122355670">확́¸</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">구</translation>
<translation id="6973656660372572881">ê³ ́ • 프ë¡́‹œ ́„œë²„́™€ .pac ́¤í¬ë¦½í¸ URĹ´ ëª¨ë‘ ́§€́ •ë˜́–´ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="6989763994942163495">고급 ́„¤́ • í‘œ́‹œ</translation>
+<translation id="7000990526846637657">기ë¡́´ ́—†́µë‹ˆë‹¤.</translation>
+<translation id="7009986207543992532"><ph name="DOMAIN" />́— ́ ‘́†í•˜ë ¤ í–ˆ́œ¼ë‚˜ ́„œë²„́—́„œ ́¸́¦ 기간́´ 너무 길́–´́„œ ́‹ ë¢°í•  ́ˆ˜ ́—†ë” ́¸́¦́„œë¥¼ ́ œ́‹œí–ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Google 계́ •́— 다른 형́‹́˜ íƒ́ƒ‰ 기ë¡́´ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />́— 남́•„́ˆ́„ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="7029809446516969842">비밀번호</translation>
-<translation id="7050187094878475250"><ph name="DOMAIN" />́— ́ ‘́†í•˜ë ¤ê³  í–ˆ́§€ë§Œ ́„œë²„ê°€ ́ œ́‹œí•œ ́¸́¦́„œ́˜ ́œ í¨ 기간́´ 너무 길́–´́„œ ́‹ ë¢°í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="7087282848513945231">́¹´́´í‹°</translation>
<translation id="7088615885725309056">다́Œ</translation>
<translation id="7090678807593890770">Googlé—́„œ <ph name="LINK" /> ê²€́ƒ‰</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">́´ ́•Œë¦¼́€ ́ƒˆë¡œ́´ ́‚¬́´í¸ë¥¼ ́²˜́Œ́œ¼ë¡œ 방문할 ë•Œ 관리́́˜ ́¹́¸́´ í•„́”하므로 í‘œ́‹œë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="724975217298816891">́¹´ë“œ ́„¸ë¶€́ •ë³´ë¥¼ ́—…ë°́´í¸í•˜ë ¤ë©´ <ph name="CREDIT_CARD" /> ́¹´ë“œ́˜ 만료́¼ê³¼ CVC를 ́…력하́„¸́”. ́¹´ë“œë¥¼ 확́¸í•˜ë©´ ́¹´ë“œ ́„¸ë¶€́ •ë³´ê°€ ́´ ́‚¬́´í¸́™€ ê³µ́œ ë©ë‹ˆë‹¤.</translation>
<translation id="725866823122871198">́»´í“¨í„°́˜ ë‚ ́§œ́™€ ́‹œê°„(<ph name="DATE_AND_TIME" />)́´ ́˜ëª»ë˜́–´ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />́— 대한 비공개 ́—°ê²°́„ ́„¤́ •í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
-<translation id="7265986070661382626">현́¬ <ph name="SITE" />́—́„œ <ph name="BEGIN_LINK" />́¸́¦́„œ ê³ ́ •́„ ́‚¬́©<ph name="END_LINK" />하기 때문́— 방문할 ́ˆ˜ ́—†́µë‹ˆë‹¤. 네í¸́›Œí¬ ́˜¤ë¥˜́™€ 공격́€ 대부분 ́¼́‹œ́ ́´ë¯€ë¡œ ́ ́‹œ 후 í˜́´́§€ê°€ ́ •́ƒí™”ë  ê²ƒ́…니다.</translation>
<translation id="7269802741830436641">́´ ́›¹í˜́´́§€́— 리디렉́…˜ ́ˆœí™˜ ́˜¤ë¥˜ê°€ ́ˆ́µë‹ˆë‹¤</translation>
<translation id="7275334191706090484">관리 ë¶ë§ˆí¬</translation>
<translation id="7298195798382681320">권́¥</translation>
-<translation id="7301833672208172928">ê¸°ë¡ ë™ê¸°í™” ́‚¬́©</translation>
+<translation id="7309308571273880165"><ph name="CRASH_TIME" />́— ́º¡́²˜ëœ 비́ •́ƒ ́¢…료 ë³´ê³ ́„œ(́‚¬́©́ê°€ ́—…로드를 ́”́²­í–ˆ́œ¼ë‚˜ ́•„́§ ́—…로드ë˜́§€ ́•́Œ)</translation>
<translation id="7334320624316649418">́¬́ •ë ¬ 다́‹œ ́‹¤í–‰(&amp;R)</translation>
<translation id="733923710415886693">́„œë²„ ́¸́¦́„œê°€ ́¸́¦́„œ 투명́„± ́ •́±…́„ ́‚¬́©í•˜́—¬ 공개ë˜́§€ ́•́•˜́µë‹ˆë‹¤.</translation>
+<translation id="7351800657706554155">́´ ́¸́¦́„œê°€ ́·΅†Œë˜́—ˆê¸° 때문́— 현́¬ <ph name="SITE" />́— 방문할 ́ˆ˜ ́—†́µë‹ˆë‹¤. 네í¸́›Œí¬ ́˜¤ë¥˜́™€ 공격́€ 대부분 ́¼́‹œ́ ́´ë¯€ë¡œ ́ ́‹œ 후 í˜́´́§€ê°€ ́‘ë™ë  것́…니다. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">명령́¤„</translation>
<translation id="7372973238305370288">ê²€́ƒ‰ê²°ê³¼</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">́¹´ë“œ 확́¸ ́¤‘</translation>
<translation id="7481312909269577407">́•́œ¼ë¡œ</translation>
<translation id="7485870689360869515">ë°́´í„° ́—†́Œ</translation>
+<translation id="7508255263130623398">ë°˜í™˜ëœ ́ •́±… 기기 IDê°€ 비́—ˆê±°ë‚˜ 현́¬ 기기 ID́™€ ́¼́¹˜í•˜́§€ ́•́Œ</translation>
<translation id="7514365320538308">다́´ë¡œë“œ</translation>
<translation id="7518003948725431193">다́Œ ́›¹ ́£¼́†Œ(<ph name="URL" />)́— 대해 ë°œê²¬ëœ ́›¹í˜́´́§€ê°€ ́—†́µë‹ˆë‹¤.</translation>
<translation id="7537536606612762813">í•„́ˆ˜</translation>
<translation id="7542995811387359312">́–‘́‹́— ë³´́•ˆ ́—°ê²°́´ ́‚¬́©ë˜́§€ ́•́•„ ́‹ ́©́¹´ë“œ ́ë™ ́±„́°ê¸°ê°€ ́‚¬́© ́¤‘́§€ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="7549584377607005141">́´ ́›¹í˜́´́§€ë¥¼ ́ œëŒ€ë¡œ í‘œ́‹œí•˜ë ¤ë©´ ́´́ „́— ́…력한 ë°́´í„°ê°€ í•„́”합니다. ́´ ë°́´í„°ë¥¼ 다́‹œ 보낼 ́ˆ˜ ́ˆ́§€ë§Œ ́´ ê²½́° 해당 í˜́´́§€́—́„œ ́´́ „́— ́ˆ˜í–‰í•œ ́‘́—…́´ 반복ë©ë‹ˆë‹¤.</translation>
<translation id="7554791636758816595">́ƒˆ 탭</translation>
-<translation id="7567204685887185387">́´ ́„œë²„ê°€ <ph name="DOMAIN" />́„́„ ́…́¦í•  ́ˆ˜ ́—†́œ¼ë©° ́„œë²„́˜ ë³´́•ˆ ́¸́¦́„œê°€ 부́ •í•œ ë°©́‹́œ¼ë¡œ 발행ë˜́—ˆ́„ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. ́„œë²„를 ́˜ëª» ́„¤́ •í–ˆê±°ë‚˜ 불법 ́‚¬́©́ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="7568593326407688803">́´ í˜́´́§€ë”<ph name="ORIGINAL_LANGUAGE" />ë¡œ ë˜́–´ ́ˆ́µë‹ˆë‹¤. 번́—­í•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
<translation id="7569952961197462199">Chromé—́„œ ́‹ ́©́¹´ë“œë¥¼ ́‚­́ œí•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
<translation id="7578104083680115302">Googlé— ́ €́¥í•œ ́¹´ë“œë¥¼ ́‚¬́©í•˜́—¬ ́–´ë–¤ 기기́—́„œë“ ́§€ ́‚¬́´í¸ ë° ́•±́—́„œ 빠르게 ́§€ë¶ˆí•  ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
+<translation id="7588950540487816470">피́§€́»¬ ́›¹</translation>
<translation id="7592362899630581445">́„œë²„́˜ ́¸́¦́„œê°€ ́´ë¦„ ́ œ́•½ ́¡°ê±´́„ ́œ„반합니다.</translation>
<translation id="759889825892636187">현́¬ <ph name="HOST_NAME" />́—́„œ ́”́²­́„ ́²˜ë¦¬í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" /> 번́—­ ́•ˆí•¨</translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">Chromiuḿ—́„œ ́‹ ́©́¹´ë“œë¥¼ ́‚­́ œí•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
<translation id="765676359832457558">고급 ́„¤́ • ́ˆ¨ê¸°ê¸°</translation>
<translation id="7658239707568436148">́·΅†Œ</translation>
+<translation id="7667346355482952095">ë°˜í™˜ëœ ́ •́±… 토í°́´ 비́—ˆê±°ë‚˜ 현́¬ 토í°ê³¼ ́¼́¹˜í•˜́§€ ́•́Œ</translation>
<translation id="7668654391829183341">́•Œ ́ˆ˜ ́—†ë” 기기</translation>
<translation id="7674629440242451245">Chromé˜ ë©‹́§„ ́ƒˆ 기ë¥́— ê´€́‹¬́´ ́ˆ́œ¼́‹­ë‹ˆê¹Œ? chrome.com/dev í˜́´́§€́—́„œ 개발́ ́±„ë„́— 방문해 ë³´́„¸́”.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" />(́•ˆ́ „하́§€ ́•́Œ)<ph name="END_LINK" />(́œ¼)ë¡œ ́´ë™</translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">́•„니́”, ê´œ́°®́µë‹ˆë‹¤.</translation>
<translation id="7805768142964895445">́ƒíƒœ</translation>
<translation id="7813600968533626083">Chromé—́„œ ́¶”́²œê²€́ƒ‰́–´ë¥¼ ́‚­́ œí•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
+<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />'́— 대해 <ph name="SEARCH_RESULTS" /> <ph name="NUMBER_OF_RESULTS" />ê°œ́˜ ê²€́ƒ‰ 결과를 ́°¾́•˜́µë‹ˆë‹¤.</translation>
<translation id="785549533363645510">하́§€ë§Œ í”́ ́´ ́•„́˜ˆ 남́§€ ́•ë” 것́€ ́•„닙니다. ́‹œí¬ë¦¿ 모드로 íƒ́ƒ‰í•´ë„ íŒ́‚¬, ́¸í„°ë„· ́„œë¹„́¤ ́ œê³µ́—…́²´ ë˜ë” 방문한 ́›¹́‚¬́´í¸́— ́ €́¥ëœ í”́ ê¹Œ́§€ ́—†́•¨ ́ˆ˜ë” ́—†́µë‹ˆë‹¤.</translation>
<translation id="7887683347370398519">CVC를 확́¸í•œ 후 다́‹œ ́‹œë„하́„¸́”.</translation>
<translation id="7894616681410591072">́´ í˜́´́§€́— ́•¡́„¸́¤í•˜ë ¤ë©´ <ph name="NAME" />님́˜ ́¹́¸́´ í•„́”합니다.</translation>
-<translation id="790025292736025802"><ph name="URL" />́„(를) ́°¾́„ ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="7912024687060120840">í´ë”:</translation>
<translation id="7920092496846849526">́´ í˜́´́§€ë¥¼ ë°©ë¬¸í•´ë„ ê´œ́°®́€́§€ 부모님께 문́˜í–ˆ́µë‹ˆë‹¤.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -588,14 +623,15 @@
<translation id="7951415247503192394">(32비í¸)</translation>
<translation id="7956713633345437162">모바́¼ ë¶ë§ˆí¬</translation>
<translation id="7961015016161918242">́‚¬́©í•˜́§€ ́•́Œ</translation>
-<translation id="7962083544045318153">́˜¤ë¥˜ ID <ph name="CRASH_LOCAL_ID" /></translation>
+<translation id="7962083544045318153">비́ •́ƒ ́¢…료 ID <ph name="CRASH_LOCAL_ID" /></translation>
<translation id="7983301409776629893"><ph name="ORIGINAL_LANGUAGE" />를 í•­́ƒ <ph name="TARGET_LANGUAGE" />ë¡œ 번́—­</translation>
<translation id="7995512525968007366">́§€́ •ë˜́§€ ́•́Œ</translation>
<translation id="8012647001091218357">현́¬ 부모님께 ́—°ë½í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. 나́¤‘́— 다́‹œ ́‹œë„í•´ ́£¼́„¸́”.</translation>
<translation id="8034522405403831421">́´ í˜́´́§€ë” <ph name="SOURCE_LANGUAGE" />ë¡œ ë˜́–´ ́ˆ́µë‹ˆë‹¤. <ph name="TARGET_LANGUAGE" />ë¡œ 번́—­í•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
-<translation id="8034955203865359138">ê¸°ë¡ í•­ëª©́´ ́—†́µë‹ˆë‹¤.</translation>
<translation id="8088680233425245692">글́„ ́¡°íŒí•˜́§€ 못했́µë‹ˆë‹¤.</translation>
+<translation id="8089520772729574115">1MB 미만</translation>
<translation id="8091372947890762290">활́„±í™” ́”́²­́´ ́„œë²„́—́„œ 대기 ́¤‘</translation>
+<translation id="8129262335948759431">́•Œ ́ˆ˜ ́—†́Œ</translation>
<translation id="8131740175452115882">확́¸</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />́˜ ́„œë²„ <ph name="BEGIN_ABBR" />DNS ́£¼́†Œ<ph name="END_ABBR" />를 ́°¾́„ ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="8149426793427495338">́»´í“¨í„°ê°€ ́ ˆ́ „ 모드 ́ƒíƒœ́…니다.</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">IDê°€ '<ph name="EXTENSION_ID" />'́¸ 확́¥ 프로그ë΅— 대한 ́˜ëª»ëœ ́—…ë°́´í¸ URL</translation>
<translation id="8218327578424803826">́§€́ •ëœ ́œ„́¹˜:</translation>
<translation id="8225771182978767009">́»´í“¨í„°ë¥¼ ́„¤́ •í•œ ́‚¬́©́ê°€ ́´ ́‚¬́´í¸ë¥¼ ́°¨ë‹¨í–ˆ́µë‹ˆë‹¤.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">́°¾ê³  ́ˆë” í˜́´́§€́—́„œ ́‚¬́©́ê°€ ́…력한 ́ •ë³´ë¥¼ ́‚¬́©í–ˆ́µë‹ˆë‹¤. 해당 í˜́´́§€ë¡œ ëŒ́•„가면 기́¡´ ́‘́—…́„ 반복할 ́ˆ˜ ́ˆ́µë‹ˆë‹¤. 계́†í•˜́‹œê² ́µë‹ˆê¹Œ?</translation>
<translation id="8249320324621329438">마́§€ë§‰́œ¼ë¡œ ê°€́ ¸́˜¨ ́‹œê°„:</translation>
<translation id="8261506727792406068">́‚­́ œ</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">ë¶ë§ˆí¬ë°”</translation>
<translation id="8363502534493474904">비행기 모드 ́‚¬́© ́¤‘́§€</translation>
<translation id="8364627913115013041">́„¤́ • ́•ˆë¨</translation>
+<translation id="8380941800586852976">́œ„í—˜</translation>
<translation id="8412145213513410671">비́ •́ƒ ́¢…료(<ph name="CRASH_COUNT" />íŒ)</translation>
<translation id="8412392972487953978">ë™́¼í•œ ́•”호를 ë‘ ë²ˆ ́…력해́•¼ 합니다.</translation>
<translation id="8428213095426709021">́„¤́ •</translation>
+<translation id="8433057134996913067">́´ ́‘́—…́„ ́ˆ˜í–‰í•˜ë©´ 대부분́˜ ́›¹́‚¬́´í¸́—́„œ 로그́•„́›ƒë©ë‹ˆë‹¤.</translation>
<translation id="8437238597147034694">́´ë™ ́‹¤í–‰ ́·΅†Œ(&amp;U)</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{́‹ ́©́¹´ë“œ 1ê°œ}other{́‹ ́©́¹´ë“œ #ê°œ}}</translation>
+<translation id="8483780878231876732">Google 계́ •́—́„œ ́¹´ë“œë¥¼ ́‚¬́©í•˜ë ¤ë©´ Chromé— 로그́¸í•˜́„¸́”.</translation>
<translation id="8488350697529856933">́ ́© 대́ƒ</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" />́—́„œ ́‘ë‹µí•˜ë” ë° ́‹œê°„́´ 너무 ́˜¤ë˜ 걸립니다.</translation>
+<translation id="852346902619691059">기기́˜ ́´́˜́²´́ œ́—́„œ ë³´́•ˆ ́¸́¦́„œë¥¼ ́‹ ë¢°í•˜́§€ ́•́•„́„œ ́„œë²„ ë„ë©”́¸́´ <ph name="DOMAIN" />́„́„ ́¦ëª…í•  ́ˆ˜ ́—†́µë‹ˆë‹¤. ́„¤́ •́´ ́˜ëª»ë˜́—ˆê±°ë‚˜ í•´́»¤ê°€ ́—°ê²°́„ 가로́±„ê³  ́ˆê¸° 때문́¼ ́ˆ˜ ́ˆ́µë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />́́„¸íˆ ́•Œ́•„보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Google Paymentś—́„œ ́§€́›í•˜́§€ ́•ë” ́¹´ë“œ ́œ í˜•́…니다. 다른 ́¹´ë“œë¥¼ ́„ íƒí•´ ́£¼́„¸́”.</translation>
<translation id="8550022383519221471">ë„ë©”́¸́— 대해 ë™ê¸°í™” ́„œë¹„́¤ë¥¼ ́‚¬́©í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="8553075262323480129">í˜́´́§€́˜ ́–¸́–´ë¥¼ ê²°́ •í•  ́ˆ˜ ́—†́œ¼ë¯€ë¡œ 번́—­í•˜́§€ 못했́µë‹ˆë‹¤.</translation>
@@ -633,17 +675,14 @@
<translation id="8647750283161643317">기본값́œ¼ë¡œ ́¬́„¤́ •</translation>
<translation id="8680787084697685621">계́ • 로그́¸ ́„¸ë¶€́ •ë³´́˜ ́œ í¨ê¸°ê°„́´ 만료ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" />ë¡œ́˜ ́—°ê²°́€ ́•”호화ë˜́§€ ́•́µë‹ˆë‹¤.</translation>
-<translation id="8713130696108419660">́˜ëª»ëœ ́´ˆê¸° ́„œëª…</translation>
<translation id="8725066075913043281">다́‹œ ́‹œë„하́„¸́”</translation>
<translation id="8728672262656704056">́‹œí¬ë¦¿ 모드로 ́ „환ë¨</translation>
<translation id="8730621377337864115">́™„료</translation>
<translation id="8738058698779197622">ë³´́•ˆ ́—°ê²°́„ ́„¤́ •í•˜ë ¤ë©´ ́‹œê³„ê°€ ́˜¬ë°”ë¡œ ́„¤́ •ë˜́–´ ́ˆ́–´́•¼ 합니다. ́›¹́‚¬́´í¸ê°€ ́́‹ ́„ ́‹ë³„í•˜ë” ë° ́‚¬́©í•˜ë” ́¸́¦́„œê°€ í¹́ • 기간́—만 ́œ í¨í•˜ê¸° 때문́…니다. 기기́˜ ́‹œê³„ê°€ ́˜ëª» ́„¤́ •ë˜́–´ Chromiuḿ—́„œ ́´ ́¸́¦́„œë¥¼ 확́¸í•  ́ˆ˜ ́—†́µë‹ˆë‹¤.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />́˜ &lt;abbr id="dnsDefinition"&gt;DNS ́£¼́†Œ&lt;/abbr&gt;를 ́°¾́„ ́ˆ˜ ́—†́µë‹ˆë‹¤. 문́ œë¥¼ ́§„ë‹¨í•˜ë” ́¤‘́…니다.</translation>
-<translation id="8741995161408053644"><ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />́—́„œ ë‚´ Google 계́ •́— ́ˆë” 다른 형́‹́˜ íƒ́ƒ‰ 기ë¡́„ 확́¸í•  ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="8790007591277257123">́‚­́ œ 다́‹œ ́‹¤í–‰(&amp;R)</translation>
-<translation id="8790687370365610530">Googlé—́„œ ́¶”́²œí•œ ë§́¶¤ ́½˜í…́¸ ë¥¼ ë°›́•„보려면 ê¸°ë¡ ë™ê¸°í™”를 ́‚¬́© ́„¤́ •í•©ë‹ˆë‹¤.</translation>
<translation id="8798099450830957504">기본값</translation>
-<translation id="8804164990146287819">ê°œ́¸́ •ë³´́·¨ê¸‰ë°©́¹¨</translation>
+<translation id="8804164990146287819">ê°œ́¸́ •ë³´́²˜ë¦¬ë°©́¹¨</translation>
<translation id="8820817407110198400">ë¶ë§ˆí¬</translation>
<translation id="8834246243508017242">́£¼́†Œë¡́„ ́‚¬́©í•´ ́ë™́™„́„± ê¸°ë¥ ́‚¬́© ́„¤́ •â€¦</translation>
<translation id="883848425547221593">기타 ë¶ë§ˆí¬</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">́„œë²„ ́¸́¦́„œê°€ 만료ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="8987927404178983737">́›”</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">́„œë²„́—́„œ ́¸́¦́„œ 투명́„± ́ •́±…́„ ́‚¬́©í•˜́—¬ 공개ë˜́§€ ́•́€ ́¸́¦́„œë¥¼ ́ œ́‹œí–ˆ́µë‹ˆë‹¤. ́¸́¦́„œ 투명́„± ́ •́±…́€ ́¸́¦́„œê°€ ́‹ ë¢°í•  ́ˆ˜ ́ˆ́œ¼ë©° 공격́로부터 ́‚¬́©́를 보호하고 ́ˆ́Œ́„ ë³´́¥í•˜ê¸° ́œ„í•œ 것́œ¼ë¡œ ́¼ë¶€ ́¸́¦́„œ́˜ ê²½́° í•„́ˆ˜́‚¬í•­́…니다.</translation>
<translation id="9001074447101275817">프ë¡́‹œ <ph name="DOMAIN" />́— ́‚¬́©́ ́´ë¦„ ë° ë¹„ë°€ë²ˆí˜¸ë¥¼ ́…력해́•¼ 합니다.</translation>
<translation id="901974403500617787">́‹œ́¤í…œ ́ „́²´́— ́ ́©ë˜ë” 플ë˜ê·¸ë” ́†Œ́œ ́(<ph name="OWNER_EMAIL" />)만 ́„¤́ •í•  ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
<translation id="9020542370529661692">́´ í˜́´́§€ë” <ph name="TARGET_LANGUAGE" />ë¡œ 번́—­ë˜́—ˆ́µë‹ˆë‹¤.</translation>
<translation id="9038649477754266430">빠른 í˜́´́§€ 로드를 ́œ„í•´ ́˜ˆ́ƒ ê²€́ƒ‰́–´ ́„œë¹„́¤ ́‚¬́©</translation>
<translation id="9039213469156557790">ë˜í•œ ́´ í˜́´́§€́—ë” ́•ˆ́ „하́§€ ́•́€ 다른 리́†Œ́¤ê°€ í¬í•¨ë˜́–´ ́ˆ́µë‹ˆë‹¤. ́´ëŸ¬í•œ 리́†Œ́¤ë” ́ „́†¡ ́¤‘́— 다른 ́‚¬ëŒ́´ ë³¼ ́ˆ˜ ́ˆ́œ¼ë©° í˜́´́§€́˜ ́‘ë™́„ 변경하기 ́œ„í•´ 공격́ê°€ ́ˆ˜́ •í•  ́ˆ˜ ́ˆ́µë‹ˆë‹¤.</translation>
-<translation id="9049981332609050619"><ph name="DOMAIN" />́— ́ ‘́†í•˜ë ¤ í–ˆ́§€ë§Œ ́„œë²„ê°€ ́˜ëª»ëœ ́¸́¦́„œë¥¼ ́ „달했́µë‹ˆë‹¤.</translation>
<translation id="9050666287014529139">́•”호</translation>
<translation id="9065203028668620118">́ˆ˜́ •</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> í˜́´́§€ê°€ ́‘ë™í•˜́§€ ́•́Œ</translation>
diff --git a/chromium/components/strings/components_strings_lt.xtb b/chromium/components/strings/components_strings_lt.xtb
index c3ee85b658f..d4f8ac574c4 100644
--- a/chromium/components/strings/components_strings_lt.xtb
+++ b/chromium/components/strings/components_strings_lt.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="lt">
+<translation id="1008557486741366299">Ne dabar</translation>
<translation id="1015730422737071372">Pateikti papildomos išsamios informacijos</translation>
<translation id="1032854598605920125">Pasukti pagal laikrodžio rodyklę</translation>
<translation id="1038842779957582377">nežinomas pavadinimas</translation>
+<translation id="1053591932240354961">Å iuo metu negalite apsilankyti <ph name="SITE" />, nes svetainÄ— atsiuntÄ— užšifruotus prisijungimo duomenis, kurių â€Google Chrome“ negali apdoroti. Tinklo klaidos ir iÅ¡puoliai dažniausiai yra laikini, todÄ—l Å¡is puslapis tikriausiai veiks vÄ—liau. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Anuliuoti pridÄ—jimÄ…</translation>
<translation id="10614374240317010">Niekada neišsaugota</translation>
-<translation id="1064422015032085147">Serveris, priglobiantis tinklalapį, gali būti perkrautas arba vykdomi jo techninės priežiūros darbai.
- Kad negeneruotumÄ—te per daug srauto ir nepablogintumÄ—te situacijos,
- užklausos šiuo URL laikinai neleidžiamos.</translation>
<translation id="106701514854093668">Žymės staliniame kompiuteryje</translation>
<translation id="1080116354587839789">Pritaikyti pagal plotį</translation>
+<translation id="1103124106085518534">Atlikta</translation>
<translation id="1103523840287552314">Visada versti <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Jei pažymÄ—ta, â€Chrome“ iÅ¡saugos kortelÄ—s kopijÄ… įrenginyje, kad galÄ—tumÄ—te greiÄiau užpildyti formas.</translation>
+<translation id="1111153019813902504">Naujausios žymės</translation>
<translation id="1113869188872983271">&amp;Anuliuoti pertvarkymÄ…</translation>
+<translation id="1126551341858583091">Dydis vietinÄ—je saugykloje yra <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Gera politikos talpykla</translation>
<translation id="113188000913989374"><ph name="SITE" /> sakoma:</translation>
<translation id="1132774398110320017">â€Chrome“ automatinio pildymo nustatymai...</translation>
-<translation id="1150979032973867961">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas nėra patikimas kompiuterio operacinei sistemai. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="1152921474424827756">Pasiekite <ph name="BEGIN_LINK" />talpykloje saugomÄ… <ph name="URL" /> kopijÄ…<ph name="END_LINK" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> netikėtai nutraukė ryšį.</translation>
<translation id="1161325031994447685">IÅ¡ naujo prisijungti prie â€Wi-Fi“</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Pašalinti</translation>
<translation id="1201402288615127009">Toliau</translation>
<translation id="1201895884277373915">Daugiau iš šios svetainės</translation>
-<translation id="121201262018556460">Bandėte pasiekti <ph name="DOMAIN" />, bet serveris pateikė nesudėtingą raktą turintį sertifikatą. Užpuolikas galėjo nulaužti privatųjį raktą, o šis serveris gali būti ne tas, kurio tikėjotės (gali būti, kad bendraujate su užpuoliku).</translation>
+<translation id="1206967143813997005">Netinkamas pirminis parašas</translation>
+<translation id="1209206284964581585">SlÄ—pti dabar</translation>
<translation id="1219129156119358924">Sistemos sauga</translation>
<translation id="1227224963052638717">Nežinoma politika.</translation>
<translation id="1227633850867390598">SlÄ—pti vertÄ™</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Taip</translation>
<translation id="1430915738399379752">Spausdinti</translation>
<translation id="1442912890475371290">Užblokuotas bandymas <ph name="BEGIN_LINK" />apsilankyti puslapyje, esanÄiame <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Šiuo metu negalite apsilankyti <ph name="SITE" />, nes svetainėje naudojamas sertifikatų prisegimas. Tinklo klaidos ir išpuoliai dažniausiai yra laikini, todėl šis puslapis tikriausiai veiks vėliau. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Rodyti išsaugotą šio puslapio kopiją (kuri yra pasenusi).</translation>
<translation id="1519264250979466059">Sukūrimo data</translation>
<translation id="1549470594296187301">Norint naudoti Å¡iÄ… funkcijÄ…, reikia įgalinti â€JavaScript“.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Tinklo konfigūracija netinkama ir jos neįmanoma importuoti.</translation>
<translation id="1644574205037202324">Istorija</translation>
<translation id="1645368109819982629">Nepalaikomas protokolas</translation>
-<translation id="1655462015569774233">{1,plural, =1{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikato galiojimas baigėsi vakar. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_DATE" />. Ar tai tinkama? Jei netinkama, turėtumėte koreguoti sistemos laikrodį ir atnaujinti šį puslapį.}one{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikato galiojimas baigėsi prieš # dieną. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_DATE" />. Ar tai tinkama? Jei netinkama, turėtumėte koreguoti sistemos laikrodį ir atnaujinti šį puslapį.}few{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikato galiojimas baigėsi prieš # dienas. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_DATE" />. Ar tai tinkama? Jei netinkama, turėtumėte koreguoti sistemos laikrodį ir atnaujinti šį puslapį.}many{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikato galiojimas baigėsi prieš # dienos. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_DATE" />. Ar tai tinkama? Jei netinkama, turėtumėte koreguoti sistemos laikrodį ir atnaujinti šį puslapį.}other{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikato galiojimas baigėsi prieš # dienų. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_DATE" />. Ar tai tinkama? Jei netinkama, turėtumėte koreguoti sistemos laikrodį ir atnaujinti šį puslapį.}}</translation>
<translation id="1676269943528358898">SvetainÄ—je <ph name="SITE" /> įprastai naudojama Å¡ifruotÄ— informacijai apsaugoti. Šį kartÄ… â€Google Chrome“ bandant prisijungti prie <ph name="SITE" />, ji pateikÄ— neįprastus ir netinkamus prisijungimo duomenis. Gali bÅ«ti, kad užpuolÄ—jas bando apsimesti svetaine <ph name="SITE" /> arba â€Wi-Fi“ prisijungimo ekrane nutrÅ«ko ryÅ¡ys. JÅ«sų informacija vis tiek liko apsaugota, nes â€Google Chrome“ sustabdÄ— prisijungimÄ… prieÅ¡ apsikeitimÄ… bet kokiais duomenimis.</translation>
<translation id="168841957122794586">Serverio sertifikate yra nesudÄ—tingas kriptografinis raktas.</translation>
<translation id="1701955595840307032">Siūlomo turinio gavimas</translation>
-<translation id="1706954506755087368">{1,plural, =1{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios nuo rytojaus. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko.}one{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienos. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko.}few{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienų. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko.}many{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienos. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko.}other{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienų. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Pabandykite susisiekti su sistemos administratoriumi.</translation>
<translation id="17513872634828108">Atidaryti skirtukai</translation>
<translation id="1753706481035618306">Puslapio numeris</translation>
-<translation id="1761412452051366565">Jei norite gauti â€Google“ siÅ«lomo suasmeninto turinio, įjunkite sinchronizavimÄ….</translation>
-<translation id="1763864636252898013">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas nėra patikimas įrenginio operacinei sistemai. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Pabandykite paleisti â€Windows Network Diagnostics“<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Atnaujinkite sinchronizavimo slaptafrazÄ™.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Čia bus rodomos žymės, kurias naudojote pastaruoju metu.</translation>
<translation id="1821930232296380041">Netinkama užklausa arba jos parametrai</translation>
<translation id="1838667051080421715">Peržiūrite tinklalapio šaltinį.</translation>
<translation id="1871208020102129563">Įgaliotasis serveris nustatytas naudoti fiksuotų įgaliotųjų serverių, o ne .pac scenarijaus URL.</translation>
<translation id="1883255238294161206">Sutraukti sąrašą</translation>
<translation id="1898423065542865115">Filtravimas</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> nepriėmė jūsų prisijungimo sertifikato arba prisijungimo sertifikato galiojimas gali būti pasibaigęs.</translation>
<translation id="194030505837763158">Apsilankykite <ph name="LINK" /></translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> žymės</translation>
<translation id="1973335181906896915">Serijinio rengimo klaida</translation>
<translation id="1974060860693918893">IÅ¡plÄ—stiniai</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{ir dar 1}one{ir dar #}few{ir dar #}many{ir dar #}other{ir dar #}}</translation>
<translation id="2025186561304664664">Nustatytas automatinis įgaliotojo serverio konfigūravimas.</translation>
<translation id="2030481566774242610">Ar turÄ—jote omenyje <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Matote šį pranešimą, nes tėvai turi patvirtinti naujas svetaines, kai lankotės pirmą kartą.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Patikrinti tarpinį serverį ir užkardą<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Pašto kodas</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 pasiūlymas}one{# pasiūlymas}few{# pasiūlymai}many{# pasiūlymo}other{# pasiūlymų}}</translation>
<translation id="2065985942032347596">Reikalingas tapatybÄ—s nustatymas</translation>
<translation id="2079545284768500474">Anuliuoti</translation>
<translation id="20817612488360358">Sistemos įgaliotojo serverio nustatymai nustatyti kaip naudotini, bet taip pat nurodyta tiksli įgaliotojo serverio konfigūracija.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Redaguoti žymes</translation>
<translation id="2166049586286450108">VisateisÄ— administratoriaus prieiga</translation>
<translation id="2166378884831602661">Ši svetainė negali užtikrinti saugaus ryšio</translation>
-<translation id="2171101176734966184">Bandėte pasiekti <ph name="DOMAIN" />, bet serveris pateikė sertifikatą, kuris pasirašytas naudojant nesudėtingą parašo algoritmą. Tai reiškia, kad serverio pateikti saugos kredencialai galėjo būti suklastoti ir serveris gali būti ne tas, kurio tikėjotės (gali būti, kad bendraujate su užpuoliku).</translation>
<translation id="2181821976797666341">Politika</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adresas}one{# adresas}few{# adresai}many{# adreso}other{# adresų}}</translation>
<translation id="2212735316055980242">Politika nerasta</translation>
<translation id="2213606439339815911">Gaunami įrašai...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> neprieinamas</translation>
<translation id="2230458221926704099">Išspręskite ryšio problemas naudodami <ph name="BEGIN_LINK" />diagnostikos programą<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Siųsti dabar</translation>
<translation id="225207911366869382">Pagal Å¡iÄ… politikÄ… Å¡i vertÄ— nepatvirtinta.</translation>
<translation id="2262243747453050782">HTTP klaida</translation>
<translation id="2282872951544483773">Nepasiekiami eksperimentai</translation>
<translation id="2292556288342944218">Interneto prieiga užblokuota</translation>
<translation id="229702904922032456">BaigÄ—si Å¡akninio ar tarpinio sertifikato galiojimas.</translation>
<translation id="230155334948463882">Nauja kortelÄ—?</translation>
+<translation id="2305919008529760154">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas galėjo būti išduotas neteisėtai. Taip gali būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> būtina įvesti naudotojo vardą ir slaptažodį.</translation>
+<translation id="2318774815570432836">Šiuo metu negalite apsilankyti <ph name="SITE" />, nes svetainėje naudojama HSTS. Tinklo klaidos ir išpuoliai dažniausiai yra laikini, todėl šis puslapis tikriausiai veiks vėliau. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Nepaisoma netinkama žymė indekse <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Kitos žymės</translation>
<translation id="2359808026110333948">Tęsti</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" /> užfiksuota strigÄių ataskaita nebuvo įkelta</translation>
<translation id="2367567093518048410">Lygis</translation>
+<translation id="2371153335857947666">{1,plural, =1{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikato galiojimas baigėsi vakar. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_DATE" />. Ar šis laikas tinkamas? Jeigu ne, turėtumėte pakoreguoti sistemos laikrodį ir atnaujinti šį puslapį. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.}one{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikato galiojimas baigėsi prieš # dieną. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_DATE" />. Ar šis laikas tinkamas? Jeigu ne, turėtumėte pakoreguoti sistemos laikrodį ir atnaujinti šį puslapį. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.}few{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikato galiojimas baigėsi prieš # dienas. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_DATE" />. Ar šis laikas tinkamas? Jeigu ne, turėtumėte pakoreguoti sistemos laikrodį ir atnaujinti šį puslapį. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.}many{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikato galiojimas baigėsi prieš # dienos. Taip gali būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_DATE" />. Ar šis laikas tinkamas? Jei jis netinkamas, turėtumėte koreguoti sistemos laikrodį ir atnaujinti šį puslapį. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.}other{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikato galiojimas baigėsi prieš # dienų. Taip gali būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_DATE" />. Ar šis laikas tinkamas? Jeigu ne, turėtumėte pakoreguoti sistemos laikrodį ir atnaujinti šį puslapį. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Nėra jokių galimų NS alternatyvų</translation>
<translation id="2384307209577226199">Numatytieji įmonės nustatymai</translation>
-<translation id="238526402387145295">Negalite dabar apsilankyti svetainėje <ph name="SITE" />, nes joje <ph name="BEGIN_LINK" />naudojamas HSTS<ph name="END_LINK" />. Tinklo klaidos ir užpuolimai dažniausiai yra laikini, todėl šis puslapis tikriausiai vėliau veiks.</translation>
<translation id="2386255080630008482">Serverio sertifikatas panaikintas.</translation>
<translation id="2392959068659972793">Rodyti politikÄ… su nenustatyta verte</translation>
<translation id="2396249848217231973">&amp;Anuliuoti ištrynimą</translation>
-<translation id="2413528052993050574">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas gali būti atšauktas. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="2455981314101692989">Šiame tinklalapyje neleidžiamas automatinis šios formos pildymas.</translation>
+<translation id="2463739503403862330">Užpildyti</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Paleistas įrankis â€Windows Network Diagnostics“<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Netinkamas paieškos URL.</translation>
<translation id="2491120439723279231">Serverio sertifikate yra klaidų.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Pateikti</translation>
<translation id="2674170444375937751">Ar tikrai norite pašalinti šiuos puslapius iš savo istorijos?</translation>
<translation id="2677748264148917807">IÅ¡eiti</translation>
+<translation id="269990154133806163">Serveris pateikė sertifikatą, kuris nebuvo viešai atskleistas naudojant sertifikato skaidrumo politiką. Tai yra tam tikriems sertifikatams taikomas reikalavimas, siekiant užtikrinti, kad jie patikimi ir apsaugo nuo užpuolikų. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">VertÄ— neatitinka formato.</translation>
<translation id="2704951214193499422">Å iuo metu â€Chromium“ negali patvirtinti jÅ«sų kortelÄ—s. VÄ—liau bandykite dar kartÄ….</translation>
<translation id="2705137772291741111">IÅ¡saugotos (talpykloje esanÄios) Å¡ios svetainÄ—s kopijos negalima skaityti.</translation>
<translation id="2709516037105925701">Automatinis pildymas</translation>
+<translation id="2712118517637785082">Bandėte pasiekti <ph name="DOMAIN" />, bet sertifikatą, kurį pateikė serveris, anuliavo jo išdavėjas. Tai reiškia, kad serverio pateikti saugos prisijungimo duomenys yra visiškai nepatikimi. Gali būti, kad bendraujate su užpuoliku. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Prašyti leidimo</translation>
<translation id="2721148159707890343">Užklausa sėkminga</translation>
<translation id="2728127805433021124">Serverio sertifikatas pasirašytas naudojant nepatikimą parašo algoritmą.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Adreso ir paieškos juosta</translation>
<translation id="2826760142808435982">Ryšys užšifruotas ir tapatybė nustatyta naudojant <ph name="CIPHER" />. <ph name="KX" /> naudojamas kaip pagrindinis mainų mechanizmas.</translation>
<translation id="2835170189407361413">Valyti formÄ…</translation>
-<translation id="2837049386027881519">Buvo bandyta prisijungti iš naujo naudojant senesnės versijos TLS arba SSL protokolą. Tai paprastai reiškia, kad serveryje naudojama labai sena programinė įranga ir jame gali būti kitų saugumo problemų.</translation>
<translation id="284702764277384724">Panašu, kad <ph name="HOST_NAME" /> serverio sertifikatas yra suklastotas.</translation>
<translation id="2889159643044928134">Neįkelti iš naujo</translation>
-<translation id="2896499918916051536">Å is papildinys nepalaikomas.</translation>
+<translation id="2900469785430194048">â€Google Chrome“ trÅ«ksta atminties Å¡iam tinklalapiui pateikti.</translation>
<translation id="2909946352844186028">Aptiktas tinklo pasikeitimas.</translation>
-<translation id="2915500479781995473">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas nebegalioja. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo. Šiuo metu jūsų kompiuterio laikrodis nustatytas į <ph name="CURRENT_TIME" />. Ar tai tinkamas laikas? Jei netinkamas, turėtumėte pakeisti sistemos laikrodžio laiką ir atnaujinti šį puslapį.</translation>
<translation id="2922350208395188000">Neįmanoma patikrinti serverio sertifikato.</translation>
-<translation id="2941952326391522266">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas yra iš <ph name="DOMAIN2" />. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="2948083400971632585">Galite neleisti visų tarpinių serverių, jungimasis prie kurių sukonfigūruotas nustatymų puslapyje.</translation>
<translation id="2955913368246107853">Uždaryti paieškos juostą</translation>
<translation id="2958431318199492670">Tinklo konfigūracija neatitinka ONC standarto. Kai kurių konfigūracijos dalių neįmanoma importuoti.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Netinkamas politikos tipas</translation>
<translation id="3032412215588512954">Ar norite iš naujo įkelti šią svetainę?</translation>
<translation id="3037605927509011580">Oi!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{mažiausiai 1 elementas sinchronizuotuose įrenginiuose}=1{1 elementas (ir dar daugiau sinchronizuotuose įrenginiuose)}one{# elementas (ir dar daugiau sinchronizuotuose įrenginiuose)}few{# elementai (ir dar daugiau sinchronizuotuose įrenginiuose)}many{# elemento (ir dar daugiau sinchronizuotuose įrenginiuose)}other{# elementų (ir dar daugiau sinchronizuotuose įrenginiuose)}}</translation>
<translation id="3041612393474885105">Sertifikato informacija</translation>
<translation id="3063697135517575841">Å iuo metu â€Chrome“ negali patvirtinti jÅ«sų kortelÄ—s. VÄ—liau bandykite dar kartÄ….</translation>
<translation id="3093245981617870298">Esate neprisijungÄ™.</translation>
@@ -207,15 +210,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Naujausia</translation>
<translation id="3207960819495026254">Pažymėta</translation>
-<translation id="3225919329040284222">Serveris pateikė sertifikatą, kuris neatitinka numatytų reikalavimų. Šie reikalavimai taikomi tam tikrose itin saugiose svetainėse, kad jūs būtumėte saugūs.</translation>
<translation id="3226128629678568754">Spustelėkite įkėlimo iš naujo mygtuką, kad iš naujo pateiktumėte duomenis, reikalingus puslapiui įkelti.</translation>
<translation id="3228969707346345236">IÅ¡versti nepavyko, nes puslapis jau yra <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Ä®veskite â€<ph name="CREDIT_CARD" />“ kortelÄ—s saugos kodÄ… (CVC)</translation>
<translation id="3254409185687681395">Įtraukti šį puslapį į žymes</translation>
<translation id="3270847123878663523">&amp;Anuliuoti pertvarkymÄ…</translation>
<translation id="3286538390144397061">Paleisti iš naujo dabar</translation>
+<translation id="3303855915957856445">Nerasta jokių paieškos rezultatų</translation>
<translation id="3305707030755673451"><ph name="TIME" /> duomenys buvo užšifruoti naudojant sinchronizavimo slaptafrazę. Įveskite ją, kad pradėtumėte sinchronizuoti.</translation>
<translation id="333371639341676808">Neleiskite šiam puslapiui kurti papildomų dialogo langų.</translation>
+<translation id="3338095232262050444">Saugi</translation>
<translation id="3340978935015468852">nustatymų</translation>
<translation id="3345135638360864351">Nepavyko <ph name="NAME" /> išsiųsti jūsų prieigos prie šios svetainės užklausos. Bandykite dar kartą.</translation>
<translation id="3355823806454867987">Pakeisti įgaliotojo serverio nustatymus...</translation>
@@ -233,6 +237,7 @@
<translation id="3452404311384756672">Gauti intervalÄ…:</translation>
<translation id="3462200631372590220">Slėpti išsamią informaciją</translation>
<translation id="3479539252931486093">Ar tai buvo netikėta? <ph name="BEGIN_LINK" />Praneškime mums apie tai<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Ne dabar</translation>
<translation id="348000606199325318">Strigties ID <ph name="CRASH_LOCAL_ID" /> (serverio ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Šiuo metu nepavyko susisiekti su jūsų tėvu. Bandykite dar kartą.</translation>
<translation id="3527085408025491307">Aplankas</translation>
@@ -241,6 +246,7 @@
<translation id="3542684924769048008">Slaptažodį naudoti:</translation>
<translation id="3549644494707163724">Å ifruoti visus sinchronizuotus duomenis naudojant sinchronizavimo slaptafrazÄ™</translation>
<translation id="3549761410225185768">Dar <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas yra iš <ph name="DOMAIN2" />. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Jūsų ryšys nėra privatus</translation>
<translation id="3583757800736429874">&amp;Perkelti dar kartÄ…</translation>
<translation id="3586931643579894722">Slėpti išsamią informaciją</translation>
@@ -252,12 +258,15 @@
<translation id="3623476034248543066">Rodyti vertÄ™</translation>
<translation id="3630155396527302611">Jei ji nurodyta kaip programa, kuriai leidžiama pasiekti tinklą, pabandykite
ją pašalinti iš sąrašo ir vėl pridėti.</translation>
+<translation id="3638794133396384728">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; baigėsi jo saugos sertifikato galiojimas. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. Šiuo metu kompiuterio laikrodis nustatytas į <ph name="CURRENT_TIME" />. Ar šis laikas tinkamas? Jeigu ne, turėtumėte pakoreguoti sistemos laikrodį ir atnaujinti šį puslapį. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Šios eksperimentinės funkcijos gali bet kada pasikeisti, neveikti ar išnykti. Negarantuojame, kas nutiks, kai įjungsite šiuo eksperimentus. Jūsų naršyklė gali netgi savaime sudegti. Kalbant rimtai, naršyklė gali ištrinti visus duomenis arba jūsų saugumas ir privatumas gali būti pažeisti netikėtais būdais. Visi eksperimentai, kuriuos įgalinsite, bus įgalinti visiems naudotojams. Elkitės atsargiai.</translation>
<translation id="3650584904733503804">Tikrinimas sÄ—kmingas</translation>
<translation id="3655670868607891010">Jei tai rodoma dažnai, išbandykite <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Peržiūrėtas ir pataisytas leidimas</translation>
+<translation id="3678029195006412963">Nepavyko pasirašyti užklausos</translation>
<translation id="3681007416295224113">Sertifikato informacija</translation>
<translation id="3693415264595406141">Slaptažodis:</translation>
+<translation id="3696411085566228381">nÄ—ra</translation>
<translation id="3700528541715530410">Oi, tikriausiai neturite leidimo pasiekti šį puslapį.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Įkeliama...</translation>
@@ -265,7 +274,6 @@
<translation id="3714780639079136834">Ä®jungti mobiliojo ryÅ¡io duomenis arba â€Wi-Fi“</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Patikrinti tarpinio serverio, užkardos ir DNS konfigūraciją<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Nukopijuota nuoroda</translation>
-<translation id="3744899669254331632">Negalite dabar apsilankyti svetainÄ—je <ph name="SITE" />, nes ji atsiuntÄ— užšifruotus prisijungimo duomenis, kurių â€Chromium“ negali apdoroti. Tinklo klaidos ir užpuolimai dažniausiai yra laikini, todÄ—l Å¡is puslapis vÄ—liau tikriausiai veiks.</translation>
<translation id="375403751935624634">Vertimas nepavyko dÄ—l serverio klaidos.</translation>
<translation id="3759461132968374835">NÄ—ra strigÄių, apie kurias buvo neseniai praneÅ¡ta. Strigtys, įvykusios tuo metu, kai strigÄių ataskaitų teikimas buvo iÅ¡jungtas, Äia rodomos nebus.</translation>
<translation id="3788090790273268753">Šios svetainės sertifikato galiojimo laikas baigiasi 2016 m., o sertifikatų grandinėje yra sertifikatas, pasirašytas naudojant SHA-1.</translation>
@@ -277,19 +285,25 @@
<translation id="3884278016824448484">Nesuderinamas įrenginio identifikatorius</translation>
<translation id="3885155851504623709">ApylinkÄ—</translation>
<translation id="3901925938762663762">KortelÄ— nebegalioja</translation>
+<translation id="3910267023907260648">Bandėte pasiekti <ph name="DOMAIN" />, bet serveris pateikė sertifikatą, kuris pasirašytas naudojant nesudėtingą parašo algoritmą. Tai reiškia, kad serverio pateikti saugos prisijungimo duomenys galėjo būti suklastoti ir serveris gali būti ne tas, kurio tikėjotės (gali būti, kad bendraujate su užpuoliku). <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios nuo rytojaus. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.}one{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienos. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.}few{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienų. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.}many{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienos. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.}other{Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas įsigalios po # dienų. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Nepavyko įkelti PDF dokumento</translation>
<translation id="3963721102035795474">Skaitytojo režimas</translation>
+<translation id="397105322502079400">SkaiÄiuojama...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> užblokuota.</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 tinklalapis netoliese}one{# tinklalapis netoliese}few{# tinklalapiai netoliese}many{# tinklalapio netoliese}other{# tinklalapių netoliese}}</translation>
<translation id="4021036232240155012">DNS – tai tinklo paslauga, verÄianti svetainÄ—s pavadinimÄ… į interneto adresÄ….</translation>
<translation id="4030383055268325496">&amp;Anuliuoti pridÄ—jimÄ…</translation>
-<translation id="4032534284272647190">Prieiga prie <ph name="URL" /> atmesta.</translation>
<translation id="404928562651467259">ĮSPĖJIMAS</translation>
<translation id="4058922952496707368">Raktas â€<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Kliento programa ir serveris nepalaiko įprasto SSL protokolo versijos ar šifruotojo programų komplekto.</translation>
<translation id="4079302484614802869">Įgaliotojo serverio konfigūracijoje nustatyta naudoti .pac scenarijaus URL, o ne fiksuotus įgaliotuosius serverius.</translation>
<translation id="4103249731201008433">Netinkamas įrenginio serijos numeris</translation>
<translation id="4103763322291513355">Apsilankykite &lt;strong&gt;chrome://policy&lt;/strong&gt;, kad peržiūrėtumėte į juodąjį sąrašą įtrauktų URL sąrašą ir kitą politiką, kurią priverstinai paleido sistemos administratorius.</translation>
+<translation id="4110615724604346410">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikate yra klaidų. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Politikos aprÄ—ptis nepalaikoma.</translation>
+<translation id="4118212371799607889">Å iam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; â€Chromium“ negali pasitikÄ—ti jo saugos sertifikatu. Taip galÄ—jo bÅ«ti dÄ—l netinkamos konfigÅ«racijos ar dÄ—l ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{Dar 1}one{Dar #}few{Dar #}many{Dar #}other{Dar #}}</translation>
<translation id="4130226655945681476">Patikrinti tinklo laidus, modemą ir maršruto parinktuvą</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Ar norite, kad â€Chromium“ iÅ¡saugotų Å¡iÄ… kortelÄ™?</translation>
@@ -297,6 +311,7 @@
<translation id="4176463684765177261">Neleista</translation>
<translation id="4196861286325780578">&amp;Perkelti dar kartÄ…</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Patikrinti užkardos ir antivirusinės sistemos konfigūracijas<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{nÄ—ra}=1{1 programa (â€$1“)}=2{2 programos (â€$1“, â€$2“)}one{# programa (â€$1“, â€$2“, â€$3“)}few{# programos (â€$1“, â€$2“, â€$3“)}many{# programos (â€$1“, â€$2“, â€$3“)}other{# programų (â€$1“, â€$2“, â€$3“)}}</translation>
<translation id="4220128509585149162">Gedimai</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Pabandykite paleisti â€Windows Network Diagnostics“<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Ne</translation>
@@ -305,14 +320,15 @@
<translation id="4269787794583293679">(NÄ—ra naudotojo vardo)</translation>
<translation id="4300246636397505754">Pasiūlymai tėvams</translation>
<translation id="4304224509867189079">Prisijungti</translation>
+<translation id="432290197980158659">Serveris pateikė sertifikatą, kuris neatitinka integruotų reikalavimų. Šie reikalavimai taikomi tam tikrose aukšto saugos lygio svetainėse, kad būtumėte saugūs. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Nepavyko rasti straipsnio</translation>
+<translation id="4331708818696583467">Nesaugi</translation>
<translation id="4372948949327679948">Numatyta â€<ph name="VALUE_TYPE" />“ vertÄ—.</translation>
-<translation id="4377125064752653719">BandÄ—te pasiekti svetainÄ™ â€<ph name="DOMAIN" />“, bet sertifikatÄ…, kurį pateikÄ— serveris, anuliavo jo iÅ¡davÄ—jas. Tai reiÅ¡kia, kad saugos kredencialais, kuriuos pateikÄ— serveris, visiÅ¡kai negalima pasitikÄ—ti. GalbÅ«t bendraujate su užpuoliku.</translation>
<translation id="4381091992796011497">Naudotojo vardas:</translation>
<translation id="4394049700291259645">Neleisti</translation>
<translation id="4395129973926795186"><ph name="START_DATE" />–<ph name="END_DATE" /></translation>
<translation id="4406896451731180161">paieškos rezultatai</translation>
-<translation id="4424024547088906515">Å iam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas nÄ—ra patikimas â€Chrome“. Taip gali nutikti dÄ—l netinkamos konfigÅ«racijos ar dÄ—l ryšį pertraukusio užgrobÄ—jo.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> nepriėmė jūsų prisijungimo sertifikato arba prisijungimo sertifikatas nebuvo pateiktas.</translation>
<translation id="443673843213245140">Įgaliotojo serverio naudojimas neleidžiamas, bet nurodyta aiški įgaliotojo serverio konfigūracija.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Matote šį praneÅ¡imÄ…, nes â€Google SafeSites“ yra įgalinta.</translation>
@@ -324,12 +340,12 @@
<translation id="4522570452068850558">IÅ¡sami informacija</translation>
<translation id="4558551763791394412">Pabandykite išjungti plėtinius.</translation>
<translation id="4587425331216688090">PaÅ¡alinti adresÄ… iÅ¡ â€Chrome“?</translation>
+<translation id="4589078953350245614">Bandėte pasiekti <ph name="DOMAIN" />, bet serveris pateikė netinkamą sertifikatą. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Ryšys su <ph name="DOMAIN" /> užšifruotas naudojant modernų šifravimo paketą.</translation>
<translation id="4594403342090139922">&amp;Anuliuoti ištrynimą</translation>
+<translation id="4627442949885028695">Tęsiama kitu įrenginiu</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Peržiūrite plėtinio puslapį.</translation>
-<translation id="467662567472608290">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikate yra klaidų. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> užblokuotas</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Ryšys nutrauktas</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Paleistas įrankis â€Windows Network Diagnostics“<ph name="END_LINK" />.</translation>
@@ -337,21 +353,26 @@
<translation id="4728558894243024398">Platforma</translation>
<translation id="4744603770635761495">Vykdomasis kelias</translation>
<translation id="4756388243121344051">&amp;Istorija</translation>
+<translation id="4759238208242260848">Atsisiuntimai</translation>
<translation id="4764776831041365478">Tinklalapis šiuo adresu <ph name="URL" /> gali laikinai neveikti arba visam laikui būti perkeltas kitu žiniatinklio adresu.</translation>
<translation id="4771973620359291008">Įvyko nežinoma klaida.</translation>
<translation id="4782449893814226250">Paprašėte tėvų leidimo apsilankyti šiame puslapyje.</translation>
<translation id="4800132727771399293">Patikrinkite kortelÄ—s galiojimo pabaigos datÄ… bei saugos kodÄ… (CVC) ir bandykite dar kart</translation>
-<translation id="4807049035289105102">Negalite dabar apsilankyti svetainÄ—je <ph name="SITE" />, nes ji atsiuntÄ— užšifruotus prisijungimo duomenis, kurių â€Google Chrome“ negali apdoroti. Tinklo klaidos ir užpuolimai dažniausiai yra laikini, todÄ—l Å¡is puslapis vÄ—liau tikriausiai veiks.</translation>
<translation id="4813512666221746211">Tinklo klaida</translation>
<translation id="4816492930507672669">Pritaikyti pagal puslapį</translation>
<translation id="4850886885716139402">Žiūrėti</translation>
<translation id="4880827082731008257">Ieškoti istorijoje</translation>
+<translation id="4884656795097055129">Tinkamu metu bus rodoma daugiau straipsnių.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{ir dar 1 tinklalapis}one{ir dar # tinklalapis}few{ir dar # tinklalapiai}many{ir dar # tinklalapio}other{ir dar # tinklalapių}}</translation>
<translation id="4923417429809017348">Šis puslapis išverstas iš nežinomos kalbos į <ph name="LANGUAGE_LANGUAGE" /> k.</translation>
<translation id="4926049483395192435">Turi būti nurodyta.</translation>
<translation id="4930497775425430760">Matote šį pranešimą, nes vienas iš tėvų turi patvirtinti naujas svetaines, kai lankotės pirmą kartą.</translation>
<translation id="495170559598752135">Veiksmai</translation>
<translation id="4958444002117714549">Išskleisti sąrašą</translation>
+<translation id="4962322354953122629">Å iam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; â€Chrome“ negali pasitikÄ—ti jo saugos sertifikatu. Taip galÄ—jo bÅ«ti dÄ—l netinkamos konfigÅ«racijos ar dÄ—l ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Versti iš <ph name="ORIGINAL_LANGUAGE" /> į <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Å is papildinys nepalaikomas</translation>
<translation id="5002932099480077015">Jei Å¡is nustatymas įgalintas, â€Chrome“ saugos kortelÄ—s kopijÄ… Å¡iame įrenginyje, kad bÅ«tų galima greiÄiau užpildyti formas.</translation>
<translation id="5019198164206649151">Bloga atsarginio atminties įrenginio būsena</translation>
<translation id="5023310440958281426">Patikrinkite savo administratoriaus politikÄ…</translation>
@@ -359,13 +380,12 @@
<translation id="5031870354684148875">Apie â€Google“ vertÄ—jÄ…</translation>
<translation id="5040262127954254034">Privatumas</translation>
<translation id="5045550434625856497">Neteisingas slaptažodis</translation>
+<translation id="5056549851600133418">Jums skirti straipsniai</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Patikrinti tarpinio serverio adresÄ…<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Å iuo metu serverio sertifikatas negalioja.</translation>
<translation id="5089810972385038852">Valstija</translation>
-<translation id="5094747076828555589">Å iam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas nÄ—ra patikimas â€Chromium“. Taip gali nutikti dÄ—l netinkamos konfigÅ«racijos ar dÄ—l ryšį pertraukusio užgrobÄ—jo.</translation>
<translation id="5095208057601539847">Provincija</translation>
<translation id="5115563688576182185">(64 bitų)</translation>
-<translation id="5122371513570456792">Pagal terminÄ… â€<ph name="SEARCH_STRING" />“ surasta tiek <ph name="SEARCH_RESULTS" />: <ph name="NUMBER_OF_RESULTS" /></translation>
<translation id="5141240743006678641">Å ifruoti sinchronizuotus slaptažodžius naudojant â€Google“ prisijungimo duomenis</translation>
<translation id="5145883236150621069">Politikos atsakyme yra klaidos kodas</translation>
<translation id="5171045022955879922">Ieškokite ar įveskite URL</translation>
@@ -374,18 +394,18 @@
<translation id="5190835502935405962">Žymių juosta</translation>
<translation id="5199729219167945352">Bandymai</translation>
<translation id="5251803541071282808">Debesis</translation>
+<translation id="5277279256032773186">Naudojate â€Chrome“ darbe? Ä®monÄ—s gali tvarkyti darbuotojų â€Chrome“ nustatymus. Sužinokite daugiau</translation>
<translation id="5299298092464848405">Analizuojant politiką įvyko klaida</translation>
<translation id="5300589172476337783">Rodyti</translation>
<translation id="5308689395849655368">StrigÄių ataskaitų teikimas neleidžiamas.</translation>
<translation id="5317780077021120954">IÅ¡saugoti</translation>
<translation id="5327248766486351172">Pavadinimas</translation>
+<translation id="5359637492792381994">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas šiuo metu negalioja. Taip gali būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Išsaugant politikos nustatymus įvyko klaida</translation>
-<translation id="540969355065856584">Šiam serveriui nepavyko patvirtinti, kad jis yra <ph name="DOMAIN" />; šiuo metu jo saugos sertifikatas negalioja. Tai gali būti dėl netinkamos konfigūracijos arba dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="5421136146218899937">Išvalyti naršymo duomenis...</translation>
<translation id="5430298929874300616">Pašalinti žymę</translation>
<translation id="5431657950005405462">Failas nerastas</translation>
<translation id="5435775191620395718">Rodoma šio įrenginio istorija. <ph name="BEGIN_LINK" />Sužinokite daugiau<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Suasmeninto turinio pasiūlymai šiuo metu išjungti, nes jūsų sinchronizuojami duomenys apsaugoti taikant tinkintą slaptafrazę.</translation>
<translation id="5439770059721715174">Schemos patvirtinimo klaida â€<ph name="ERROR_PATH" />“: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Nepavyksta rasti Å¡io <ph name="HOST_NAME" /> puslapio</translation>
<translation id="5455374756549232013">Bloga politikos laiko žymė</translation>
@@ -408,14 +428,18 @@
<translation id="5622887735448669177">Ar norite išeiti iš šios svetainės?</translation>
<translation id="5629630648637658800">Įkeliant politikos nustatymus įvyko klaida</translation>
<translation id="5631439013527180824">Netinkamas įrenginio tvarkymo prieigos raktas</translation>
-<translation id="5650551054760837876">Nerasta paieškos rezultatų.</translation>
<translation id="5677928146339483299">Užblokuota</translation>
<translation id="5710435578057952990">Å io tinklalapio tapatybÄ— nenustatyta.</translation>
<translation id="5720705177508910913">Dabartinis naudotojas</translation>
+<translation id="572328651809341494">Naujausi skirtukai</translation>
<translation id="5784606427469807560">Patvirtinant kortelę kilo problema. Patikrinkite interneto ryšį ir bandykite dar kartą.</translation>
<translation id="5785756445106461925">Be to, šiame puslapyje yra kitų nesaugių išteklių. Perduodant duomenis šiuos išteklius gali peržiūrėti kiti asmenys ir keisti atakuojanti programa, siekianti pakeisti puslapio išvaizdą.</translation>
+<translation id="5786044859038896871">Ar norite, kad būtų įvesta jūsų kredito kortelės informacija?</translation>
+<translation id="5803412860119678065">Ar norite, kad būtų įvesta <ph name="CARD_DETAIL" /> informacija?</translation>
<translation id="5810442152076338065">Ryšys su <ph name="DOMAIN" /> užšifruotas naudojant pasenusį šifravimo paketą.</translation>
<translation id="5813119285467412249">&amp;PridÄ—ti dar kartÄ…</translation>
+<translation id="5814352347845180253">Galite prarasti prieigÄ… prie aukÅ¡Äiausios kokybÄ—s turinio iÅ¡ <ph name="SITE" /> ir kelių kitų svetainių.</translation>
+<translation id="5843436854350372569">Bandėte pasiekti <ph name="DOMAIN" />, bet serveris pateikė nesudėtingą raktą turintį sertifikatą. Užpuolikas galėjo užvaldyti privatų raktą, o šis serveris gali būti ne tas, kurio tikėjotės (gali būti, kad bendraujate su užpuoliku). <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Matote šį parnešimą, nes valdytojas užblokavo šią svetainę.</translation>
<translation id="5857090052475505287">Naujas aplankas</translation>
<translation id="5869405914158311789">Nepavyksta pasiekti Å¡ios svetainÄ—s</translation>
@@ -423,6 +447,7 @@
<translation id="5872918882028971132">Pasiūlymai tėvams</translation>
<translation id="59107663811261420">â€Google Payments“ nepalaiko Å¡io tipo kortelÄ—s naudojantis Å¡io prekybininko paslaugomis. Pasirinkite kitÄ… kortelÄ™.</translation>
<translation id="59174027418879706">Įgalinta</translation>
+<translation id="5926846154125914413">Galite prarasti prieigÄ… prie aukÅ¡Äiausios kokybÄ—s turinio iÅ¡ kelių svetainių.</translation>
<translation id="5966707198760109579">SavaitÄ—</translation>
<translation id="5967867314010545767">Pašalinti iš istorijos</translation>
<translation id="5975083100439434680">Tolinti</translation>
@@ -434,12 +459,12 @@
<translation id="604124094241169006">Automatinis</translation>
<translation id="6042308850641462728">Daugiau</translation>
<translation id="6060685159320643512">Atsargiai, šie bandymai gali būti pavojingi</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{nÄ—ra}=1{1}one{#}few{#}many{#}other{#}}</translation>
<translation id="6146055958333702838">Patikrinkite laidus ir iš naujo paleiskite maršruto parinktuvus, modemus ar kitus
naudojamus tinklo įrenginius.</translation>
<translation id="614940544461990577">Pabandykite atlikti toliau nurodytus veiksmus.</translation>
<translation id="6150607114729249911">Oi, turite paprašyti tėvų leidimo apsilankyti šiame puslapyje.</translation>
<translation id="6151417162996330722">Serverio sertifikato galiojimo laikotarpis per ilgas.</translation>
-<translation id="6154808779448689242">Sugrąžintas politikos prieigos raktas neatitinka dabartinio prieigos rakto</translation>
<translation id="6165508094623778733">Sužinokite daugiau</translation>
<translation id="6203231073485539293">Patikrinkite interneto ryšį</translation>
<translation id="6218753634732582820">PaÅ¡alinti adresÄ… iÅ¡ â€Chromium“?</translation>
@@ -452,24 +477,30 @@
<translation id="6328639280570009161">Bandykite neleisti tinklo numatymo</translation>
<translation id="6337534724793800597">Filtruoti politikÄ… pagal pavadinimÄ…</translation>
<translation id="6342069812937806050">KÄ… tik</translation>
+<translation id="6345221851280129312">nežinomas dydis</translation>
<translation id="6355080345576803305">Viešosios sesijos nepaisymas</translation>
<translation id="6358450015545214790">Ką tai reiškia?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{Dar 1 pasiūlymas}one{Dar # pasiūlymas}few{Dar # pasiūlymai}many{Dar # pasiūlymo}other{Dar # pasiūlymų}}</translation>
<translation id="6387478394221739770">Domina naujos â€Chrome“ funkcijos? IÅ¡bandykite mÅ«sų beta kanalÄ… adresu chrome.com/beta.</translation>
-<translation id="641480858134062906"><ph name="URL" /> nepavyko įkelti</translation>
+<translation id="6389758589412724634">â€Chromium“ trÅ«ksta atminties Å¡iam tinklalapiui pateikti.</translation>
+<translation id="6416403317709441254">Å iuo metu negalite apsilankyti <ph name="SITE" />, nes svetainÄ— atsiuntÄ— užšifruotus prisijungimo duomenis, kurių â€Chromium“ negali apdoroti. Tinklo klaidos ir iÅ¡puoliai dažniausiai yra laikini, todÄ—l Å¡is puslapis tikriausiai veiks vÄ—liau. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Nepavyksta patikrinti, ar sertifikatas buvo panaikintas.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> atsisakÄ— prisijungti.</translation>
<translation id="6445051938772793705">Å alis</translation>
<translation id="6451458296329894277">Patvirtinkite pakartotinÄ… formos pateikimÄ…</translation>
<translation id="6458467102616083041">Nepaisoma, nes numatytoji paieška neleidžiama pagal politiką.</translation>
+<translation id="6462969404041126431">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; gali būti, kad jo saugos sertifikatas atšauktas. Taip galėjo nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Įrenginio politika</translation>
<translation id="6489534406876378309">Pradėti įkelti strigtis</translation>
<translation id="6529602333819889595">&amp;IÅ¡trinti dar kartÄ…</translation>
+<translation id="6534179046333460208">Fizinio žiniatinklio pasiūlymai</translation>
<translation id="6550675742724504774">Parinktys</translation>
+<translation id="6593753688552673085">mažiau nei <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Å ifravimo parinktys</translation>
<translation id="662080504995468778">Likti</translation>
<translation id="6628463337424475685">â€<ph name="ENGINE" />“ paieÅ¡ka</translation>
-<translation id="6634865548447745291">Negalite dabar apsilankyti svetainėje <ph name="SITE" />, nes <ph name="BEGIN_LINK" />šis sertifikatas buvo anuliuotas<ph name="END_LINK" />. Paprastai tinklo klaidos ir užpuolimai yra laikini, todėl šis puslapis vėliau tikriausiai veiks.</translation>
<translation id="6644283850729428850">Å i politika nepatvirtinta.</translation>
+<translation id="6652240803263749613">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; kompiuterio operacinė sistema negali pasitikėti jo saugos sertifikatu. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Redaguoti aplankÄ…</translation>
<translation id="6660210980321319655">Automatiškai pranešta <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">PaÅ¡alinti formos pasiÅ«lymÄ… iÅ¡ â€Chromium“?</translation>
@@ -477,6 +508,7 @@
<translation id="6710213216561001401">Ankstesnis</translation>
<translation id="6710594484020273272">&lt;Įveskite paieškos terminą&gt;</translation>
<translation id="6711464428925977395">Kažkas negerai su tarpiniu serveriu arba adresas netinkamas.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{nėra}=1{1 elementas}one{# elementas}few{# elementai}many{# elemento}other{# elementų}}</translation>
<translation id="674375294223700098">Nežinoma serverio sertifikato klaida.</translation>
<translation id="6753269504797312559">Politikos vertÄ—</translation>
<translation id="6757797048963528358">Įjungta įrenginio miego būsena.</translation>
@@ -488,7 +520,6 @@
<translation id="6891596781022320156">Politikos lygis nepalaikomas.</translation>
<translation id="6895330447102777224">KortelÄ— patvirtinta</translation>
<translation id="6897140037006041989">Naudotojo atstovas</translation>
-<translation id="6903907808598579934">Įjungti sinchronizavimą</translation>
<translation id="6915804003454593391">Naudotojas:</translation>
<translation id="6957887021205513506">Panašu, kad serverio sertifikatas yra suklastotas.</translation>
<translation id="6965382102122355670">Gerai</translation>
@@ -496,9 +527,11 @@
<translation id="6970216967273061347">Rajonas</translation>
<translation id="6973656660372572881">Nurodyti fiksuoti įgaliotieji serveriai ir .pac scenarijaus URL.</translation>
<translation id="6989763994942163495">Rodyti išplėstinius nustatymus...</translation>
+<translation id="7000990526846637657">Nerasta jokių istorijos įrašų</translation>
+<translation id="7009986207543992532">Bandėte pasiekti <ph name="DOMAIN" />, bet serveris pateikė sertifikatą, kurio galiojimo laikotarpis per ilgas, kad juo būtų galima pasitikėti. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Adresu <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> gali bÅ«ti pateikta kitų formų jÅ«sų â€Google“ paskyros narÅ¡ymo istorija</translation>
<translation id="7029809446516969842">Slaptažodžiai</translation>
-<translation id="7050187094878475250">Bandėte pasiekti <ph name="DOMAIN" />, bet serveris pateikė sertifikatą, kurio galiojimo laikotarpis per ilgas, kad būtų patikimas.</translation>
<translation id="7087282848513945231">Apygarda</translation>
<translation id="7088615885725309056">AnkstesnÄ—</translation>
<translation id="7090678807593890770">Sistemoje â€Google“ atlikite paieÅ¡kÄ… pagal užklausÄ… â€<ph name="LINK" />“</translation>
@@ -517,13 +550,13 @@
<translation id="7246609911581847514">Matote šį pranešimą, nes valdytojas turi patvirtinti naujas svetaines, kai lankotės pirmą kartą.</translation>
<translation id="724975217298816891">Jei norite atnaujinti iÅ¡samiÄ… kortelÄ—s informacijÄ…, įveskite â€<ph name="CREDIT_CARD" />“ galiojimo pabaigos datÄ… ir kortelÄ—s saugos kodÄ… (CVC). Kai patvirtinsite, iÅ¡sami kortelÄ—s informacija bus bendrinama su Å¡ia svetaine.</translation>
<translation id="725866823122871198">Nepavyksta užmegzti privataus ryšio su <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, nes kompiuterio data ir laikas (<ph name="DATE_AND_TIME" />) yra netinkami.</translation>
-<translation id="7265986070661382626">Negalite dabar apsilankyti svetainėje <ph name="SITE" />, nes joje <ph name="BEGIN_LINK" />naudojamas sertifikato prisegimas<ph name="END_LINK" />. Tinklo klaidos ir užpuolimai dažniausiai yra laikini, todėl šis puslapis vėliau tikriausiai veiks.</translation>
<translation id="7269802741830436641">Å iam tinklalapiui taikomas peradresavimo ciklas</translation>
<translation id="7275334191706090484">Tvarkomos žymės</translation>
<translation id="7298195798382681320">Rekomenduojama</translation>
-<translation id="7301833672208172928">Įjungti istorijos sinchronizavimą</translation>
+<translation id="7309308571273880165">StrigÄių ataskaita užfiksuota <ph name="CRASH_TIME" /> (įkÄ—limo užklausÄ… pateikÄ— naudotojas, dar neįkelta)</translation>
<translation id="7334320624316649418">&amp;Pertvarkyti dar kartÄ…</translation>
<translation id="733923710415886693">Serverio sertifikatas nebuvo atskleistas taikant sertifikato skaidrumÄ….</translation>
+<translation id="7351800657706554155">Šiuo metu negalite apsilankyti svetainėje <ph name="SITE" />, nes jos sertifikatas anuliuotas. Tinklo klaidos ir išpuoliai dažniausiai laikini, todėl šis puslapis tikriausiai veiks vėliau. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Komandos eilutÄ—</translation>
<translation id="7372973238305370288">paieškos rezultatas</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -542,16 +575,17 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="7469372306589899959">KortelÄ— patvirtinama</translation>
<translation id="7481312909269577407">Persiųsti</translation>
<translation id="7485870689360869515">Nerasta jokių duomenų.</translation>
+<translation id="7508255263130623398">Sugrąžinto politikos įrenginio ID nenurodytas arba neatitinka dabartinio įrenginio ID</translation>
<translation id="7514365320538308">Atsisiųsti</translation>
<translation id="7518003948725431193">Nerasta nė vieno tinklalapio šiuo žiniatinklio adresu: <ph name="URL" /></translation>
<translation id="7537536606612762813">Privaloma</translation>
<translation id="7542995811387359312">Automatinis kredito kortelės informacijos pildymas neleidžiamas, nes šiai formai nenaudojamas saugus ryšys.</translation>
<translation id="7549584377607005141">Jei norite, kad Å¡is tinklalapis bÅ«tų tinkamai pateikiamas, reikalingi anksÄiau įvesti duomenys. Galite nusiųsti Å¡iuos duomenis iÅ¡ naujo, bet taip pakartosite visus anksÄiau Å¡iame puslapyje įvykdytus veiksmus.</translation>
<translation id="7554791636758816595">Naujas skirtukas</translation>
-<translation id="7567204685887185387">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas gali būti neteisėtai išduotas. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="7568593326407688803">Šis puslapis yra<ph name="ORIGINAL_LANGUAGE" />Ar norėtumėte jį išversti?</translation>
<translation id="7569952961197462199">PaÅ¡alinti kredito kortelÄ—s informacijÄ… iÅ¡ â€Chrome“?</translation>
<translation id="7578104083680115302">Greitai mokÄ—kite svetainÄ—se ir programose įvairiuose įrenginiuose naudodami korteles, kurias iÅ¡saugojote â€Google“.</translation>
+<translation id="7588950540487816470">Fizinis žiniatinklis</translation>
<translation id="7592362899630581445">Serverio sertifikatas pažeidžia pavadinimų apribojimus.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> šiuo metu negalima apdoroti šios užklausos.</translation>
<translation id="7600965453749440009">Niekada neversti <ph name="LANGUAGE" /></translation>
@@ -562,6 +596,7 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="7637571805876720304">PaÅ¡alinti kredito kortelÄ—s informacijÄ… iÅ¡ â€Chromium“?</translation>
<translation id="765676359832457558">Slėpti išplėstinius nustatymus...</translation>
<translation id="7658239707568436148">Atšaukti</translation>
+<translation id="7667346355482952095">Sugrąžintas politikos prieigos raktas yra tuÅ¡Äias arba neatitinka dabartinio prieigos rakto</translation>
<translation id="7668654391829183341">Nežinomas įrenginys</translation>
<translation id="7674629440242451245">Domina naujos â€Chrome“ funkcijos? IÅ¡bandykite mÅ«sų kuriamÄ… kanalÄ… adresu chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Eiti į svetainę <ph name="SITE" /> (nesaugu)<ph name="END_LINK" /></translation>
@@ -578,10 +613,10 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="780301667611848630">AÄiÅ«, ne</translation>
<translation id="7805768142964895445">BÅ«sena</translation>
<translation id="7813600968533626083">PaÅ¡alinti formos pasiÅ«lymÄ… iÅ¡ â€Chrome“?</translation>
+<translation id="7815407501681723534">Pagal terminÄ… â€<ph name="SEARCH_STRING" />“ surasta tiek <ph name="SEARCH_RESULTS" />: <ph name="NUMBER_OF_RESULTS" /></translation>
<translation id="785549533363645510">TaÄiau nesate nematomi. Ä®jungus inkognito režimÄ…, narÅ¡ymo veiksmai vis tiek matomi darbdaviui, interneto paslaugų teikÄ—jui ar svetainÄ—ms, kuriose lankotÄ—s.</translation>
<translation id="7887683347370398519">Patikrinkite kortelÄ—s saugos kodÄ… (CVC) ir bandykite dar kartÄ…</translation>
<translation id="7894616681410591072">Oi, jums reikia <ph name="NAME" /> leidimo, kad galėtumėte pasiekti šį puslapį.</translation>
-<translation id="790025292736025802"><ph name="URL" /> nerastas</translation>
<translation id="7912024687060120840">Aplanke:</translation>
<translation id="7920092496846849526">Paprašėte vieno iš tėvų leidimo apsilankyti šiame puslapyje.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -594,9 +629,10 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="7995512525968007366">Nenurodytas</translation>
<translation id="8012647001091218357">Šiuo metu nepavyko susisiekti su jūsų tėvais. Bandykite dar kartą.</translation>
<translation id="8034522405403831421">Šis puslapis yra <ph name="SOURCE_LANGUAGE" /> k. Išversti į <ph name="TARGET_LANGUAGE" /> k.?</translation>
-<translation id="8034955203865359138">Nerasta jokių istorijos įrašų.</translation>
<translation id="8088680233425245692">Nepavyko peržiūrėti straipsnio.</translation>
+<translation id="8089520772729574115">mažiau nei 1 MB</translation>
<translation id="8091372947890762290">Laukiama aktyvinimo serveryje</translation>
+<translation id="8129262335948759431">nežinomas kiekis</translation>
<translation id="8131740175452115882">Patvirtinti</translation>
<translation id="8134994873729925007">Nepavyko rasti <ph name="HOST_NAME" /> serverio <ph name="BEGIN_ABBR" />DNS adreso<ph name="END_ABBR" />.</translation>
<translation id="8149426793427495338">Įjungta kompiuterio miego būsena.</translation>
@@ -605,6 +641,7 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="8201077131113104583">Netinkamas plÄ—tinio, kurio ID â€<ph name="EXTENSION_ID" />“, atnaujinimo URL.</translation>
<translation id="8218327578424803826">Priskirta vieta:</translation>
<translation id="8225771182978767009">Šį kompiuterį nustatęs asmuo pasirinko blokuoti šią svetainę.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Jūsų ieškomas puslapis ieškojo informacijos, kurią įvedėte. Grįžus į tą puslapį bet kokie jūsų atliekami veiksmai gali būti kartojami. Ar norite tęsti?</translation>
<translation id="8249320324621329438">Paskutinį kartą gauta:</translation>
<translation id="8261506727792406068">Panaikinti</translation>
@@ -617,12 +654,17 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="8349305172487531364">Žymių juosta</translation>
<translation id="8363502534493474904">Išjungti lėktuvo režimą</translation>
<translation id="8364627913115013041">Nenustatyta.</translation>
+<translation id="8380941800586852976">Pavojingas</translation>
<translation id="8412145213513410671">Strigtys (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Reikia du kartus įvesti tÄ… paÄiÄ… slaptafrazÄ™.</translation>
<translation id="8428213095426709021">Nustatymai</translation>
+<translation id="8433057134996913067">Tai atlikę atsijungsite nuo daugumos svetainių.</translation>
<translation id="8437238597147034694">&amp;Anuliuoti perkÄ—limÄ…</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kredito kortelė}one{# kredito kortelė}few{# kredito kortelės}many{# kredito kortelės}other{# kredito kortelių}}</translation>
+<translation id="8483780878231876732">Jei norite naudoti korteles iÅ¡ â€Google“ paskyros, prisijunkite prie â€Chrome“</translation>
<translation id="8488350697529856933">Taikoma</translation>
<translation id="8498891568109133222">Per ilgai laukta <ph name="HOST_NAME" /> atsako.</translation>
+<translation id="852346902619691059">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; įrenginio operacinė sistema negali pasitikėti jo saugos sertifikatu. Taip galėjo būti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užpuoliko. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">â€Google Payments“ nepalaiko Å¡io tipo kortelÄ—s. Pasirinkite kitÄ… kortelÄ™.</translation>
<translation id="8550022383519221471">Sinchronizavimo paslauga negalima jūsų domenui.</translation>
<translation id="8553075262323480129">IÅ¡versti negalima, nes nepavyko nustatyti puslapio kalbos.</translation>
@@ -634,15 +676,12 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="8647750283161643317">Viską nustatyti į numatytuosius nustatymus</translation>
<translation id="8680787084697685621">IÅ¡sami prisijungimo prie paskyros informacija pasenusi.</translation>
<translation id="8703575177326907206">Jūsų ryšys su <ph name="DOMAIN" /> nekoduotas.</translation>
-<translation id="8713130696108419660">Netinkamas pradinis parašas</translation>
<translation id="8725066075913043281">Bandyti dar kartÄ…</translation>
<translation id="8728672262656704056">Veikia inkognito režimas</translation>
<translation id="8730621377337864115">Atlikta</translation>
<translation id="8738058698779197622">Jei norite užmegzti saugų ryšį, turÄ—site tinkamai nustatyti laikrodį. To reikalaujama todÄ—l, kad svetainių tapatybei įrodyti naudojami sertifikatai galioja tik tam tikrÄ… laikotarpį. Kadangi įrenginio laikrodis nustatytas netinkamai, â€Chromium“ negali tinkamai patvirtinti sertifikatų.</translation>
<translation id="8740359287975076522">Nepavyko rasti <ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS adreso&lt;/abbr&gt;. Nustatoma problema.</translation>
-<translation id="8741995161408053644">Adresu <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> gali bÅ«ti pateikta kitų formų jÅ«sų â€Google“ paskyros istorija.</translation>
<translation id="8790007591277257123">&amp;IÅ¡trinti dar kartÄ…</translation>
-<translation id="8790687370365610530">Jei norite gauti â€Google“ siÅ«lomo suasmeninto turinio, įjunkite istorijos sinchronizavimÄ….</translation>
<translation id="8798099450830957504">Numatytasis</translation>
<translation id="8804164990146287819">Privatumo politika</translation>
<translation id="8820817407110198400">Žymės</translation>
@@ -664,13 +703,11 @@ Ei! Kitą kartą gali būti naudinga naudoti inkognito režimą (<ph name="SHORT
<translation id="8971063699422889582">BaigÄ—si serverio sertifikato galiojimo laikas.</translation>
<translation id="8987927404178983737">MÄ—nuo</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Serveris pateikė sertifikatą, kuris nebuvo viešai atskleistas naudojant sertifikato skaidrumo politiką. Tai yra tam tikriems sertifikatams taikomas reikalavimas, siekiant užtikrinti, jog jie patikimi ir apsaugo nuo įsilaužėlių.</translation>
<translation id="9001074447101275817">Tarpiniame serveryje <ph name="DOMAIN" /> būtina įvesti naudotojo vardą ir slaptažodį.</translation>
<translation id="901974403500617787">Visoje sistemoje taikomas žymas gali nustatyti tik savininkas: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Šis puslapis išverstas į <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Naudokite numatymo paslaugÄ…, kad puslapiai bÅ«tų įkeliami greiÄiau</translation>
<translation id="9039213469156557790">Be to, šiame puslapyje yra kitų nesaugių išteklių. Perduodant duomenis šiuos išteklius gali peržiūrėti kiti asmenys ir keisti atakuojanti programa, siekianti pakeisti puslapio veikimą.</translation>
-<translation id="9049981332609050619">BandÄ—te pasiekti <ph name="DOMAIN" />, bet serveris pateikÄ— neteisingÄ… sertifikatÄ….</translation>
<translation id="9050666287014529139">SlaptafrazÄ—</translation>
<translation id="9065203028668620118">Redaguoti</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> puslapis neveikia</translation>
diff --git a/chromium/components/strings/components_strings_lv.xtb b/chromium/components/strings/components_strings_lv.xtb
index f4d3dcff28f..5c90eee93b8 100644
--- a/chromium/components/strings/components_strings_lv.xtb
+++ b/chromium/components/strings/components_strings_lv.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="lv">
+<translation id="1008557486741366299">VÄ“lÄk</translation>
<translation id="1015730422737071372">Sniegt papildu informÄciju</translation>
<translation id="1032854598605920125">Pagriezt pulksteņrÄdÄ«tÄju kustÄ«bas virzienÄ</translation>
<translation id="1038842779957582377">nezinÄms nosaukums</translation>
+<translation id="1053591932240354961">Å obrÄ«d nevarat apmeklÄ“t vietni <ph name="SITE" />, jo no tÄs tika nosÅ«tÄ«ti sajaukti akreditÄcijas dati, kurus nevar apstrÄdÄt pÄrlÅ«kÄ Google Chrome. TÄ«kla kļūdas un brÄ«dinÄjumi parasti ir Ä«slaicÄ«gi, tÄpÄ“c Å¡Ä« lapa vÄ“lÄk, visticamÄk, darbosies. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Pievienošanas atsaukšana</translation>
<translation id="10614374240317010">Netiek saglabÄtas</translation>
-<translation id="1064422015032085147">Serveris, kurÄ tiek mitinÄta tÄ«mekļa lapa, iespÄ“jams, ir pÄrslogots vai notiek tÄ tehniskÄ apkope.
- Lai neradÄ«tu pÄrÄk lielu datplÅ«smas apjomu un nepasliktinÄtu paÅ¡reizÄ“jo situÄciju,
- īslaicīgi tiks noraidīti šī URL pieprasījumi.</translation>
<translation id="106701514854093668">Datora grÄmatzÄ«mes</translation>
<translation id="1080116354587839789">IetilpinÄt pÄ“c platuma</translation>
+<translation id="1103124106085518534">PagaidÄm gatavs!</translation>
<translation id="1103523840287552314">Vienmēr tulkot <ph name="LANGUAGE" /> valodas saturu</translation>
<translation id="1107591249535594099">Ja Å¡Ä« izvÄ“les rÅ«tiņa ir atzÄ«mÄ“ta, pÄrlÅ«ks Chrome saglabÄs jÅ«su kartes kopiju Å¡ajÄ ierÄ«cÄ“, lai nodroÅ¡inÄtu ÄtrÄku veidlapu aizpildi.</translation>
+<translation id="1111153019813902504">Nesenas grÄmatzÄ«mes</translation>
<translation id="1113869188872983271">&amp;Atsaukt pÄrkÄrtoÅ¡anu</translation>
+<translation id="1126551341858583091">Lielums vietÄ“jÄ krÄtuvÄ“ ir <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Politikas keÅ¡atmiņa ir labÄ stÄvoklÄ«.</translation>
<translation id="113188000913989374">Vietnē <ph name="SITE" /> ir rakstīts:</translation>
<translation id="1132774398110320017">Chrome automÄtiskÄs aizpildes iestatÄ«jumi...</translation>
-<translation id="1150979032973867961">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄts netiek uzskatÄ«ts par uzticamu jÅ«su datora operÄ“tÄjsistÄ“mÄ. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
<translation id="1152921474424827756">Piekļūstiet vietnes <ph name="URL" /> <ph name="BEGIN_LINK" />keÅ¡atmiÅ†Ä saglabÄtajai kopijai<ph name="END_LINK" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> negaidÄ«ti pÄrtrauca savienojumu.</translation>
<translation id="1161325031994447685">AtkÄrtoti izveidojiet savienojumu ar Wi-Fi tÄ«klu.</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Noņemt</translation>
<translation id="1201402288615127009">NÄkamais</translation>
<translation id="1201895884277373915">VairÄk no Å¡Ä«s vietnes</translation>
-<translation id="121201262018556460">JÅ«s centÄties sasniegt <ph name="DOMAIN" />, bet servera uzrÄdÄ«tais sertifikÄts satur vÄju atslÄ“gu. IespÄ“jams, uzbrucÄ“js ir uzlauzis privÄto atslÄ“gu un serveris var nebÅ«t tas, ko centÄties sasniegt (iespÄ“jams, jÅ«s sazinÄties ar uzbrucÄ“ju).</translation>
+<translation id="1206967143813997005">SÄkotnÄ“jais paraksts nav derÄ«gs</translation>
+<translation id="1209206284964581585">PagaidÄm slÄ“pt</translation>
<translation id="1219129156119358924">Sistēmas drošība</translation>
<translation id="1227224963052638717">NezinÄma politika.</translation>
<translation id="1227633850867390598">Slēpt vērtību</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">JÄ</translation>
<translation id="1430915738399379752">DrukÄt</translation>
<translation id="1442912890475371290">Tika bloÄ·Ä“ts mÄ“Ä£inÄjums <ph name="BEGIN_LINK" />apmeklÄ“t lapu domÄ“nÄ <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Å obrÄ«d nevarat apmeklÄ“t vietni <ph name="SITE" />, jo tajÄ tiek izmantota sertifikÄtu piesprauÅ¡ana. TÄ«kla kļūdas un brÄ«dinÄjumi parasti ir Ä«slaicÄ«gi, tÄpÄ“c Å¡Ä« lapa vÄ“lÄk, visticamÄk, darbosies. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">RÄdÄ«t saglabÄtu (t.i., novecojuÅ¡u) Å¡Ä«s lapas versiju.</translation>
<translation id="1519264250979466059">Būvējuma datums</translation>
<translation id="1549470594296187301">Lai izmantotu Å¡o funkciju, ir jÄbÅ«t iespÄ“jotai valodai JavaScript.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">TÄ«kla konfigurÄcija nav derÄ«ga, un to nevarÄ“ja importÄ“t.</translation>
<translation id="1644574205037202324">VÄ“sture</translation>
<translation id="1645368109819982629">Neatbalstīts protokols</translation>
-<translation id="1655462015569774233">{1,plural, =1{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄta derÄ«guma termiņš beidzÄs vakar. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. JÅ«su datora pulkstenÄ« paÅ¡laik ir iestatÄ«ts Å¡Äds datums: <ph name="CURRENT_DATE" />. Vai tas ir pareizs? Ja datums nav pareizs, mainiet sistÄ“mas pulksteni un pÄ“c tam atsvaidziniet Å¡o lapu.}zero{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄta derÄ«guma termiņš beidzÄs pirms # dienÄm. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. JÅ«su datora pulkstenÄ« paÅ¡laik ir iestatÄ«ts Å¡Äds datums: <ph name="CURRENT_DATE" />. Vai tas ir pareizs? Ja datums nav pareizs, mainiet sistÄ“mas pulksteni un pÄ“c tam atsvaidziniet Å¡o lapu.}one{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄta derÄ«guma termiņš beidzÄs pirms # dienas. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. JÅ«su datora pulkstenÄ« paÅ¡laik ir iestatÄ«ts Å¡Äds datums: <ph name="CURRENT_DATE" />. Vai tas ir pareizs? Ja datums nav pareizs, mainiet sistÄ“mas pulksteni un pÄ“c tam atsvaidziniet Å¡o lapu.}other{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄta derÄ«guma termiņš beidzÄs pirms # dienÄm. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. JÅ«su datora pulkstenÄ« paÅ¡laik ir iestatÄ«ts Å¡Äds datums: <ph name="CURRENT_DATE" />. Vai tas ir pareizs? Ja datums nav pareizs, mainiet sistÄ“mas pulksteni un pÄ“c tam atsvaidziniet Å¡o lapu.}}</translation>
<translation id="1676269943528358898">VietnÄ“ <ph name="SITE" /> informÄcijas aizsargÄÅ¡anai parasti tiek izmantota Å¡ifrÄ“Å¡ana. Kad pÄrlÅ«kÄ Google Chrome tika mÄ“Ä£inÄts izveidot savienojumu ar vietni <ph name="SITE" />, Å¡oreiz tÄ nosÅ«tÄ«ja neparastus un nepareizus akreditÄcijas datus. IespÄ“jams, tas notika, jo uzbrucÄ“js mÄ“Ä£inÄja uzdoties par vietni <ph name="SITE" />, vai arÄ« Wi-Fi pierakstÄ«Å¡anÄs ekrÄns pÄrtrauc savienojumu. JÅ«su informÄcija joprojÄm ir droÅ¡Ä«bÄ, jo pÄrlÅ«ks Google Chrome pÄrtrauca savienojumu, pirms tika veikta jebkÄdu datu apmaiņa.</translation>
<translation id="168841957122794586">Servera sertifikÄts ietver vÄju kriptogrÄfisko atslÄ“gu.</translation>
<translation id="1701955595840307032">Iegūt ieteikto saturu</translation>
-<translation id="1706954506755087368">{1,plural, =1{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; Å¡Ä·iet, ka tÄ droÅ¡Ä«bas sertifikÄts sÄks darboties rÄ«t. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu.}zero{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; Å¡Ä·iet, ka tÄ droÅ¡Ä«bas sertifikÄts sÄks darboties pÄ“c # dienÄm. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu.}one{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; Å¡Ä·iet, ka tÄ droÅ¡Ä«bas sertifikÄts sÄks darboties pÄ“c # dienas. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu.}other{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; Å¡Ä·iet, ka tÄ droÅ¡Ä«bas sertifikÄts sÄks darboties pÄ“c # dienÄm. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu.}}</translation>
<translation id="1710259589646384581">OperÄ“tÄjsistÄ“ma</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Sazinieties ar sistēmas administratoru.</translation>
<translation id="17513872634828108">Atvērt cilnes</translation>
<translation id="1753706481035618306">Lapas numurs</translation>
-<translation id="1761412452051366565">Lai saņemtu Google ieteikto personalizÄ“to saturu, ieslÄ“dziet sinhronizÄciju.</translation>
-<translation id="1763864636252898013">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄts netiek uzskatÄ«ts par uzticamu jÅ«su ierÄ«ces operÄ“tÄjsistÄ“mÄ. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Mēģiniet palaist Windows tīkla diagnostiku<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Atjauniniet savu sinhronizÄcijas ieejas frÄzi.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Å eit tiks parÄdÄ«tas nesen izmantotÄs grÄmatzÄ«mes.</translation>
<translation id="1821930232296380041">PieprasÄ«jums vai tÄ parametri nebija derÄ«gi.</translation>
<translation id="1838667051080421715">JÅ«s skatÄt tÄ«mekļa lapas avotu.</translation>
<translation id="1871208020102129563">Starpniekserveris ir iestatīts, lai tas lietotu fiksētus starpniekserverus, nevis .pac skripta URL.</translation>
<translation id="1883255238294161206">Sakļaut sarakstu</translation>
<translation id="1898423065542865115">Filtrēšana</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> nepieņēma jÅ«su pieteikÅ¡anÄs sertifikÄtu, vai arÄ« pieteikÅ¡anÄs sertifikÄta derÄ«gums ir beidzies.</translation>
<translation id="194030505837763158">Apmeklējiet vietni <ph name="LINK" /></translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> grÄmatzÄ«mes</translation>
<translation id="1973335181906896915">RadÄs serializÄ“Å¡anas kļūda.</translation>
<translation id="1974060860693918893">Papildu</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{un vēl 1}zero{un vēl #}one{un vēl #}other{un vēl #}}</translation>
<translation id="2025186561304664664">Starpniekserverim ir iestatÄ«ta autokonfigurÄcija.</translation>
<translation id="2030481566774242610">Vai domÄjÄt <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Å is ziņojums tiek rÄdÄ«ts, jo pirmÄ apmeklÄ“juma laikÄ jÅ«su vecÄkiem ir jÄapstiprina jaunas vietnes.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />PÄrbaudiet starpniekserveri un ugunsmÅ«ri<ph name="END_LINK" />.</translation>
<translation id="2053553514270667976">Pasta indekss</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 ieteikums}zero{# ieteikumi}one{# ieteikums}other{# ieteikumi}}</translation>
<translation id="2065985942032347596">Nepieciešama autentiskuma noteikšana</translation>
<translation id="2079545284768500474">Atsaukt</translation>
<translation id="20817612488360358">Ir iestatÄ«ta datora starpniekserveru iestatÄ«jumu lietoÅ¡ana, bet ir norÄdÄ«ta arÄ« atklÄta starpniekservera konfigurÄcija.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Rediģēt grÄmatzÄ«mes</translation>
<translation id="2166049586286450108">Pilna administratora piekļuve</translation>
<translation id="2166378884831602661">Šī vietne nevar garantēt drošu savienojumu</translation>
-<translation id="2171101176734966184">JÅ«s mÄ“Ä£inÄjÄt sasniegt domÄ“nu <ph name="DOMAIN" />, bet serveris uzrÄdÄ«ja sertifikÄtu, kas ir parakstÄ«ts, izmantojot vÄju paraksta algoritmu. Tas nozÄ«mÄ“, ka servera norÄdÄ«tie droÅ¡Ä«bas akreditÄcijas dati var bÅ«t viltoti un Å¡is serveris var nebÅ«t tas serveris, kuru mÄ“Ä£inÄt sasniegt (iespÄ“jams, jÅ«s sazinÄties ar uzbrucÄ“ju).</translation>
<translation id="2181821976797666341">Politikas</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adrese}zero{# adreses}one{# adrese}other{# adreses}}</translation>
<translation id="2212735316055980242">Politika netika atrasta.</translation>
<translation id="2213606439339815911">Notiek ierakstu ienešana...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> nav pieejama</translation>
<translation id="2230458221926704099">Labojiet savienojumu, izmantojot <ph name="BEGIN_LINK" />diagnostikas lietotni<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Sūtīt tūlīt</translation>
<translation id="225207911366869382">Šī vērtība vairs netiek atbalstīta šai politikai.</translation>
<translation id="2262243747453050782">HTTP kļūda</translation>
<translation id="2282872951544483773">Nepieejamie eksperimenti</translation>
<translation id="2292556288342944218">Piekļuve internetam ir bloķēta</translation>
<translation id="229702904922032456">Saknes sertifikÄts vai starpnieksertifikÄts vairs nav derÄ«gs.</translation>
<translation id="230155334948463882">Vai jums ir jauna karte?</translation>
+<translation id="2305919008529760154">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts, iespÄ“jams, ir izveidots krÄpnieciski. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">VietnÄ“ <ph name="DOMAIN" /> ir jÄievada lietotÄjvÄrds un parole.</translation>
+<translation id="2318774815570432836">Å obrÄ«d nevarat apmeklÄ“t vietni <ph name="SITE" />, jo tajÄ tiek izmantota politika HSTS. TÄ«kla kļūdas un uzbrukumi parasti ir Ä«slaicÄ«gi, tÄpÄ“c Å¡Ä« lapa vÄ“lÄk, visticamÄk, darbosies. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">NederÄ«ga grÄmatzÄ«me ignorÄ“ta <ph name="ENTRY_INDEX" />. rÄdÄ«tÄjÄ</translation>
<translation id="2354001756790975382">Citas grÄmatzÄ«mes</translation>
<translation id="2359808026110333948">TurpinÄt</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" /> notverts ziņojums par avÄriju; netika lejupielÄdÄ“ts</translation>
<translation id="2367567093518048410">LÄ«menis</translation>
+<translation id="2371153335857947666">{1,plural, =1{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄta derÄ«guma termiņš beidzÄs vakar. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. JÅ«su datora pulkstenÄ« paÅ¡laik ir iestatÄ«ts Å¡Äds datums: <ph name="CURRENT_DATE" />. Vai tas ir pareizs? Ja datums nav pareizs, mainiet sistÄ“mas pulksteni un pÄ“c tam atsvaidziniet Å¡o lapu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.}zero{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄta derÄ«guma termiņš beidzÄs pirms # dienÄm. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. JÅ«su datora pulkstenÄ« paÅ¡laik ir iestatÄ«ts Å¡Äds datums: <ph name="CURRENT_DATE" />. Vai tas ir pareizs? Ja datums nav pareizs, mainiet sistÄ“mas pulksteni un pÄ“c tam atsvaidziniet Å¡o lapu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.}one{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄta derÄ«guma termiņš beidzÄs pirms # dienas. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. JÅ«su datora pulkstenÄ« paÅ¡laik ir iestatÄ«ts Å¡Äds datums: <ph name="CURRENT_DATE" />. Vai tas ir pareizs? Ja datums nav pareizs, mainiet sistÄ“mas pulksteni un pÄ“c tam atsvaidziniet Å¡o lapu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.}other{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄta derÄ«guma termiņš beidzÄs pirms # dienÄm. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. JÅ«su datora pulkstenÄ« paÅ¡laik ir iestatÄ«ts Å¡Äds datums: <ph name="CURRENT_DATE" />. Vai tas ir pareizs? Ja datums nav pareizs, mainiet sistÄ“mas pulksteni un pÄ“c tam atsvaidziniet Å¡o lapu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Nav pieejamas alternatÄ«vas lietotÄja saskarnes</translation>
<translation id="2384307209577226199">Uzņēmuma noklusējuma politika</translation>
-<translation id="238526402387145295">PaÅ¡laik nevarat apmeklÄ“t vietni <ph name="SITE" />, jo tajÄ <ph name="BEGIN_LINK" />tiek izmantota politika HSTS<ph name="END_LINK" />. TÄ«kla kļūdas un uzbrukumi parasti ir Ä«slaicÄ«gi, tÄdÄ“jÄdi Å¡Ä« lapa vÄ“lÄk, visticamÄk, darbosies.</translation>
<translation id="2386255080630008482">Servera sertifikÄts ir atsaukts.</translation>
<translation id="2392959068659972793">RÄdÄ«t politikas, kuru vÄ“rtÄ«ba nav iestatÄ«ta</translation>
<translation id="2396249848217231973">&amp;Atsaukt dzēšanu</translation>
-<translation id="2413528052993050574">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄts, iespÄ“jams, ir atsaukts. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
<translation id="2455981314101692989">Å ajÄ tÄ«mekļa lapÄ ir atspÄ“jota Å¡Ä«s veidlapas automÄtiskÄ aizpilde.</translation>
+<translation id="2463739503403862330">Aizpildīt</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Palaist tīkla diagnostiku<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Nederīgs meklēšanas URL.</translation>
<translation id="2491120439723279231">Servera sertifikÄtÄ ir kļūdas.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Iesniegt</translation>
<translation id="2674170444375937751">Vai tieÅ¡Äm vÄ“laties dzÄ“st Å¡Ä«s lapas no savas vÄ“stures?</translation>
<translation id="2677748264148917807">Iziet</translation>
+<translation id="269990154133806163">Serveris uzrÄdÄ«ja sertifikÄtu, kas netika publiski atklÄts, izmantojot Certificate Transparency politiku. Å Ä« ir prasÄ«ba noteiktiem sertifikÄtiem, lai nodroÅ¡inÄtu to uzticamÄ«bu un aizsardzÄ«bu pret uzbrucÄ“jiem. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">VÄ“rtÄ«ba neatbilst formÄtam.</translation>
<translation id="2704951214193499422">PÄrlÅ«kÄ Chromium paÅ¡laik nevar apstiprinÄt jÅ«su karti. LÅ«dzu, vÄ“lÄk mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="2705137772291741111">Nevar nolasÄ«t Å¡Ä«s vietnes saglabÄto (keÅ¡atmiÅ†Ä ievietoto) kopiju.</translation>
<translation id="2709516037105925701">AutomÄtiskÄ aizpilde</translation>
+<translation id="2712118517637785082">JÅ«s mÄ“Ä£inÄjÄt sasniegt domÄ“nu <ph name="DOMAIN" />, bet izdevÄ“js atsauca servera uzrÄdÄ«to sertifikÄtu. Tas nozÄ«mÄ“, ka servera uzrÄdÄ«tie droÅ¡Ä«bas akreditÄcijas dati nemaz nav uzticami. IespÄ“jams, jÅ«s sazinÄties ar uzbrucÄ“ju. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Lūgt atļauju</translation>
<translation id="2721148159707890343">Pieprasījums bija veiksmīgs.</translation>
<translation id="2728127805433021124">Servera sertifikÄts ir parakstÄ«ts, izmantojot vÄju paraksta algoritmu.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Adreses un meklēšanas josla</translation>
<translation id="2826760142808435982">Savienojums ir Å¡ifrÄ“ts un autentificÄ“ts, izmantojot <ph name="CIPHER" />, un tajÄ tiek izmantots <ph name="KX" /> kÄ atslÄ“gu apmaiņas mehÄnisms.</translation>
<translation id="2835170189407361413">Notīrīt veidlapu</translation>
-<translation id="2837049386027881519">Savienojums bija jÄizveido vÄ“lreiz, izmantojot vecÄku TLS vai SSL protokola versiju. Parasti tas nozÄ«mÄ“, ka servera programmatÅ«ra ir novecojusi un ir iespÄ“jamas citas ar droÅ¡Ä«bu saistÄ«tas problÄ“mas.</translation>
<translation id="284702764277384724">Å Ä·iet, ka servera sertifikÄts vietnÄ“ <ph name="HOST_NAME" /> ir viltojums.</translation>
<translation id="2889159643044928134">NeielÄdÄ“t atkÄrtoti</translation>
-<translation id="2896499918916051536">Šis spraudnis netiek atbalstīts.</translation>
+<translation id="2900469785430194048">MÄ“Ä£inot parÄdÄ«t Å¡o tÄ«mekļa lapu, pÄrlÅ«ka Google Chrome atmiÅ†Ä nepietika vietas.</translation>
<translation id="2909946352844186028">Konstatētas tīkla izmaiņas.</translation>
-<translation id="2915500479781995473">Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts vairs nav derÄ«gs. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. JÅ«su datora pulkstenÄ« paÅ¡laik ir iestatÄ«ts Å¡Äds datums: <ph name="CURRENT_TIME" />. Vai tas ir pareizs? Ja datums nav pareizs, mainiet sistÄ“mas pulksteni un pÄ“c tam atsvaidziniet Å¡o lapu.</translation>
<translation id="2922350208395188000">Servera sertifikÄtu nevar pÄrbaudÄ«t.</translation>
-<translation id="2941952326391522266">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄts ir saistÄ«ts ar domÄ“nu <ph name="DOMAIN2" />. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
<translation id="2948083400971632585">IestatÄ«jumu lapÄ varat atspÄ“jot jebkurus starpniekserverus, kas konfigurÄ“ti savienojuma izveidei.</translation>
<translation id="2955913368246107853">Aizvērt atrašanas joslu</translation>
<translation id="2958431318199492670">TÄ«kla konfigurÄcija neatbilst standartam ONC. IespÄ“jams, konfigurÄcijas daļas netiks importÄ“tas.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Politikas tips nav pareizs.</translation>
<translation id="3032412215588512954">Vai vÄ“laties atkÄrtoti ielÄdÄ“t Å¡o vietni?</translation>
<translation id="3037605927509011580">Cilnes avÄrija.</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{vismaz 1 vienums sinhronizÄ“tÄs ierÄ«cÄ“s}=1{1 vienums (un vÄ“l citi sinhronizÄ“tÄs ierÄ«cÄ“s)}zero{# vienumi (un vÄ“l citi sinhronizÄ“tÄs ierÄ«cÄ“s)}one{# vienums (un vÄ“l citi sinhronizÄ“tÄs ierÄ«cÄ“s)}other{# vienumi (un vÄ“l citi sinhronizÄ“tÄs ierÄ«cÄ“s)}}</translation>
<translation id="3041612393474885105">SertifikÄta informÄcija</translation>
<translation id="3063697135517575841">PÄrlÅ«kÄ Chrome paÅ¡laik nevar apstiprinÄt jÅ«su karti. LÅ«dzu, vÄ“lÄk mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="3093245981617870298">Esat bezsaistē</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">JaunÄkÄ</translation>
<translation id="3207960819495026254">AtzÄ«mÄ“ts kÄ grÄmatzÄ«me</translation>
-<translation id="3225919329040284222">Serveris uzrÄdÄ«ja sertifikÄtu, kas neatbilst iebÅ«vÄ“tajÄm cerÄ«bÄm. Å Ä«s cerÄ«bas ir ietvertas konkrÄ“tÄm, augstas droÅ¡Ä«bas vietnÄ“m, lai aizsargÄtu jÅ«s.</translation>
<translation id="3226128629678568754">Nospiediet atkÄrtotas ielÄdes pogu, lai atkÄrtoti iesniegtu datus, kas nepiecieÅ¡ami lapas ielÄdei.</translation>
<translation id="3228969707346345236">TulkoÅ¡ana neizdevÄs, jo lapa jau ir <ph name="LANGUAGE" /> valodÄ.</translation>
<translation id="323107829343500871">Ievadiet kredītkartes <ph name="CREDIT_CARD" /> CVC</translation>
<translation id="3254409185687681395">GrÄmatot Å¡o lapu</translation>
<translation id="3270847123878663523">&amp;PÄrkÄrtoÅ¡anas atsaukÅ¡ana</translation>
<translation id="3286538390144397061">Restartēt tūlīt</translation>
+<translation id="3303855915957856445">Netika atrasts neviens meklÄ“Å¡anas rezultÄts.</translation>
<translation id="3305707030755673451">JÅ«su dati tika Å¡ifrÄ“ti, izmantojot jÅ«su sinhronizÄcijas ieejas frÄzi Å¡ÄdÄ datumÄ: <ph name="TIME" />. Lai sÄktu sinhronizÄciju, ievadiet ieejas frÄzi.</translation>
<translation id="333371639341676808">Neļaujiet šai lapai veidot papildu dialogus.</translation>
+<translation id="3338095232262050444">Droši</translation>
<translation id="3340978935015468852">Iestatījumi</translation>
<translation id="3345135638360864351">LietotÄjam <ph name="NAME" /> nevarÄ“ja nosÅ«tÄ«t jÅ«su pieprasÄ«jumu piekļūt Å¡ai vietnei. LÅ«dzu, mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="3355823806454867987">Mainīt starpniekservera iestatījumus...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">PirmsielÄdes intervÄls:</translation>
<translation id="3462200631372590220">SlÄ“pt papildu informÄciju</translation>
<translation id="3479539252931486093">Vai tas bija negaidīti? <ph name="BEGIN_LINK" />Informējiet mūs<ph name="END_LINK" />!</translation>
+<translation id="3479552764303398839">VÄ“lÄk</translation>
<translation id="348000606199325318">AvÄrijas ID <ph name="CRASH_LOCAL_ID" /> (servera ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">MÄ“s nevarÄ“jÄm sasniegt jÅ«su mÄti/tÄ“vu. LÅ«dzu, mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="3527085408025491307">Mape</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Izmantot paroli:</translation>
<translation id="3549644494707163724">Å ifrÄ“t visus sinhronizÄ“tos datus, izmantojot sinhronizÄcijas ieejas frÄzi</translation>
<translation id="3549761410225185768">Vēl <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts ir no domÄ“na <ph name="DOMAIN2" />. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">JÅ«su savienojums nav privÄts</translation>
<translation id="3583757800736429874">&amp;PÄrvietoÅ¡anas atsaukuma atcelÅ¡ana</translation>
<translation id="3586931643579894722">Slēpt detaļas</translation>
@@ -250,12 +256,15 @@
<translation id="362276910939193118">RÄdÄ«t pilnu vÄ“sturi</translation>
<translation id="3623476034248543066">RÄdÄ«t vÄ“rtÄ«bu</translation>
<translation id="3630155396527302611">Ja tÄ jau ir norÄdÄ«ta kÄ programma, kurai ir atļauts piekļūt tÄ«klam, noņemiet to no saraksta un pievienojiet vÄ“lreiz.</translation>
+<translation id="3638794133396384728">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄtam ir beidzies derÄ«guma termiņš. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. JÅ«su datora pulkstenÄ« paÅ¡laik ir iestatÄ«ts Å¡Äds laiks: <ph name="CURRENT_TIME" />. Vai tas ir pareizs? Ja tÄ nav, mainiet sistÄ“mas pulksteni un pÄ“c tam atsvaidziniet Å¡o lapu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Å Ä«s eksperimentÄlÄs funkcijas jebkurÄ laikÄ var mainÄ«ties, pÄrstÄt darboties vai pazust. MÄ“s nesniedzam pilnÄ«gi nekÄdas garantijas tam, kas var notikt, ja jÅ«s ieslÄ“dzat vienu no Å¡iem eksperimentiem. JÅ«su pÄrlÅ«ks var pat sabrukt. Nopietni runÄjot, pÄrlÅ«ks var izdzÄ“st visus jÅ«su datus vai arÄ« neparedzamÄ veidÄ var tikt pÄrkÄpti droÅ¡Ä«bas un konfidencialitÄtes noteikumi. Visi jÅ«su aktivizÄ“tie eksperimenti tiks aktivizÄ“ti visiem Å¡Ä« pÄrlÅ«ka lietotÄjiem. LÅ«dzu, esiet uzmanÄ«gs!</translation>
<translation id="3650584904733503804">ValidÄcija bija veiksmÄ«ga.</translation>
<translation id="3655670868607891010">Ja šo redzat bieži, izmēģiniet šos <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">PÄrskatÄ«Å¡ana</translation>
+<translation id="3678029195006412963">Pieprasījumu nevarēja parakstīt.</translation>
<translation id="3681007416295224113">SertifikÄta informÄcija</translation>
<translation id="3693415264595406141">Parole:</translation>
+<translation id="3696411085566228381">nav</translation>
<translation id="3700528541715530410">Šķiet, ka jums nav atļaujas, lai piekļūtu šai lapai.</translation>
<translation id="3704609568417268905"><ph name="TIME" />, <ph name="BOOKMARKED" />, <ph name="TITLE" />, <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Notiek ielÄde...</translation>
@@ -263,7 +272,6 @@
<translation id="3714780639079136834">Ieslēdziet mobilo datu savienojumu vai Wi-Fi.</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />PÄrbaudiet starpniekserveri, ugunsmÅ«ri un DNS konfigurÄciju<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">JÅ«su kopÄ“tÄ saite</translation>
-<translation id="3744899669254331632">PaÅ¡laik jÅ«s nevarat apmeklÄ“t vietni <ph name="SITE" />, jo Å¡Ä« vietne nosÅ«tÄ«ja kodÄ“tus akreditÄcijas datus, kurus Chromium nevar apstrÄdÄt. TÄ kÄ tÄ«kla kļūdas un uzbrukumi parasti ir Ä«slaicÄ«ga problÄ“ma, iespÄ“jams, vÄ“lÄk Å¡Ä« lapa atkal darbosies.</translation>
<translation id="375403751935624634">Tulkojums neizdevÄs servera kļūdas dēļ.</translation>
<translation id="3759461132968374835">PÄ“dÄ“jÄ laikÄ neesat ziņojis par avÄrijÄm. Å eit nebÅ«s redzamas avÄrijas, kas radÄs laikÄ, kad avÄriju pÄrskatu izveide bija atspÄ“jota.</translation>
<translation id="3788090790273268753">Å Ä«s vietnes sertifikÄta derÄ«gums beidzas 2016. gadÄ, un sertifikÄtu Ä·Ä“dÄ“ ir iekļauts sertifikÄts, kas ir parakstÄ«ts, izmantojot SHA-1.</translation>
@@ -275,19 +283,25 @@
<translation id="3884278016824448484">Ierīces identifikators rada konfliktu.</translation>
<translation id="3885155851504623709">Pagasts</translation>
<translation id="3901925938762663762">Kartes derīguma termiņš ir beidzies.</translation>
+<translation id="3910267023907260648">JÅ«s mÄ“Ä£inÄjÄt sasniegt domÄ“nu <ph name="DOMAIN" />, bet serveris uzrÄdÄ«ja sertifikÄtu, kas ir parakstÄ«ts, izmantojot vÄju paraksta algoritmu. Tas nozÄ«mÄ“, ka servera norÄdÄ«tie droÅ¡Ä«bas akreditÄcijas dati var bÅ«t viltoti un Å¡is serveris var nebÅ«t tas serveris, kuru mÄ“Ä£inÄt sasniegt (iespÄ“jams, jÅ«s sazinÄties ar uzbrucÄ“ju). <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; Å¡Ä·iet, ka tÄ droÅ¡Ä«bas sertifikÄts sÄks darboties rÄ«t. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.}zero{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; Å¡Ä·iet, ka tÄ droÅ¡Ä«bas sertifikÄts sÄks darboties pÄ“c # dienÄm. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.}one{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; Å¡Ä·iet, ka tÄ droÅ¡Ä«bas sertifikÄts sÄks darboties pÄ“c # dienas. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.}other{Å is serveris nevarÄ“ja pierÄdÄ«t, ka ir <ph name="DOMAIN" />; Å¡Ä·iet, ka tÄ droÅ¡Ä«bas sertifikÄts sÄks darboties pÄ“c # dienÄm. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">NeizdevÄs ielÄdÄ“t PDF dokumentu</translation>
<translation id="3963721102035795474">LasÄ«tÄja režīms</translation>
+<translation id="397105322502079400">Aprēķina...</translation>
<translation id="3973234410852337861">Vietne <ph name="HOST_NAME" /> ir bloÄ·Ä“ta</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{TuvumÄ ir 1 tÄ«mekļa lapa}zero{TuvumÄ ir # tÄ«mekļa lapas}one{TuvumÄ ir # tÄ«mekļa lapa}other{TuvumÄ ir # tÄ«mekļa lapas}}</translation>
<translation id="4021036232240155012">DNS ir tÄ«kla pakalpojums, kurÄ vietnes nosaukums tiek tulkots uz tÄs interneta adresi.</translation>
<translation id="4030383055268325496">&amp;Atsaukt pievienošanu</translation>
-<translation id="4032534284272647190">Piekļuve vietnei <ph name="URL" /> noraidīta.</translation>
<translation id="404928562651467259">BRĪDINĀJUMS</translation>
<translation id="4058922952496707368">Atslēga <ph name="SUBKEY" />: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Klients un serveris neatbalsta bieži lietoto SSL protokola versiju vai šifra komplektu.</translation>
<translation id="4079302484614802869">Starpniekserveris ir iestatīts, lai tas lietotu .pac skripta URL, nevis fiksētus starpniekserverus.</translation>
<translation id="4103249731201008433">Ierīces sērijas numurs nav derīgs.</translation>
<translation id="4103763322291513355">ApmeklÄ“jiet vietni &lt;strong&gt;chrome://policy&lt;/strong&gt;, lai skatÄ«tu melnajÄ sarakstÄ iekļautos vietrÄžus URL, kÄ arÄ« citas politikas, ko noteicis sistÄ“mas administrators.</translation>
+<translation id="4110615724604346410">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄtÄ ir kļūdas. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Politikas diapazons netiek atbalstīts.</translation>
+<translation id="4118212371799607889">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts nav uzticams pÄrlÅ«kÄ Chromium. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{vēl 1}zero{vēl #}one{vēl #}other{vēl #}}</translation>
<translation id="4130226655945681476">PÄrbaudiet tÄ«kla kabeļus, modemu un marÅ¡rutÄ“tÄju</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Vai vÄ“laties, lai Chromium saglabÄtu Å¡o karti?</translation>
@@ -295,6 +309,7 @@
<translation id="4176463684765177261">Atspējots</translation>
<translation id="4196861286325780578">&amp;Atcelt pÄrvietoÅ¡anas atsaukÅ¡anu</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />PÄrbaudiet ugunsmÅ«ri un pretvÄ«rusu programmu konfigurÄcijas<ph name="END_LINK" />.</translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{nav}=1{1 lietotne ($1)}=2{2 lietotnes ($1, $2)}zero{# lietotnes ($1, $2, $3)}one{# lietotne ($1, $2, $3)}other{# lietotnes ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">AvÄrijas</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Mēģiniet palaist tīkla diagnostiku<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">NÄ“</translation>
@@ -303,14 +318,15 @@
<translation id="4269787794583293679">(Nav lietotÄjvÄrda)</translation>
<translation id="4300246636397505754">VecÄku ieteikumi</translation>
<translation id="4304224509867189079">PieteikÅ¡anÄs</translation>
+<translation id="432290197980158659">Serveris uzrÄdÄ«ja sertifikÄtu, kas neatbilst iebÅ«vÄ“tajÄm prasÄ«bÄm. Å Ä«s prasÄ«bas ir paredzÄ“tas noteiktÄm augsta droÅ¡Ä«bas lÄ«meņa vietnÄ“m, lai jÅ«s aizsargÄtu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Rakstu neizdevÄs atrast.</translation>
+<translation id="4331708818696583467">Nav droši</translation>
<translation id="4372948949327679948">Tika gaidīta vērtība <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">JÅ«s mÄ“Ä£inÄjÄt sasniegt <ph name="DOMAIN" />, bet izdevÄ“js atsauca servera uzrÄdÄ«to sertifikÄtu. Tas nozÄ«mÄ“, ka servera uzrÄdÄ«tie droÅ¡Ä«bas akreditÄcijas dati itin nemaz nav uzticami. IespÄ“jams, jÅ«s sazinÄties ar uzbrucÄ“ju.</translation>
<translation id="4381091992796011497">LietotÄjvÄrds:</translation>
<translation id="4394049700291259645">Atspējot</translation>
<translation id="4395129973926795186">(<ph name="START_DATE" />–<ph name="END_DATE" />)</translation>
<translation id="4406896451731180161">meklÄ“Å¡anas rezultÄti</translation>
-<translation id="4424024547088906515">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄts netiek uzskatÄ«ts par uzticamu pÄrlÅ«kÄ Chrome. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> nepieņēma jÅ«su pieteikÅ¡anÄs sertifikÄtu, vai arÄ« pieteikÅ¡anÄs sertifikÄts netika iesniegts.</translation>
<translation id="443673843213245140">Starpniekservera lietoÅ¡ana ir atspÄ“jota, bet ir norÄdÄ«ta atklÄta starpniekservera konfigurÄcija.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Å is ziņojums tiek rÄdÄ«ts, jo ir iespÄ“jota funkcija Google SafeSites.</translation>
@@ -322,12 +338,12 @@
<translation id="4522570452068850558">InformÄcija</translation>
<translation id="4558551763791394412">AtspÄ“jojiet paplaÅ¡inÄjumus.</translation>
<translation id="4587425331216688090">Vai noņemt adresi no pÄrlÅ«ka Chrome?</translation>
+<translation id="4589078953350245614">JÅ«s mÄ“Ä£inÄjÄt sasniegt domÄ“nu <ph name="DOMAIN" />, taÄu serveris uzrÄdÄ«ja nederÄ«gu sertifikÄtu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Savienojums ar domēnu <ph name="DOMAIN" /> ir šifrēts, izmantojot mūsdienīgu šifra komplektu.</translation>
<translation id="4594403342090139922">&amp;Dzēšanas atsaukšana</translation>
+<translation id="4627442949885028695">Turpiniet citÄ ierÄ«cÄ“</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">JÅ«s skatÄt paplaÅ¡inÄjumu lapu.</translation>
-<translation id="467662567472608290">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄtÄ ir kļūdas. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> tika bloÄ·Ä“ts</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Savienojums tika pÄrtraukts</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Palaist Windows tīkla diagnostiku<ph name="END_LINK" /></translation>
@@ -335,21 +351,26 @@
<translation id="4728558894243024398">Platforma</translation>
<translation id="4744603770635761495">IzpildÄms ceļš</translation>
<translation id="4756388243121344051">VÄ“sture</translation>
+<translation id="4759238208242260848">LejupielÄdes</translation>
<translation id="4764776831041365478">TÄ«mekļa lapa vietnÄ“ <ph name="URL" /> var Ä«slaicÄ«gi nebÅ«t pieejama, vai tÄ var bÅ«t pÄrvietota uz jaunu tÄ«mekļa adresi.</translation>
<translation id="4771973620359291008">RadÄs nezinÄma kļūda.</translation>
<translation id="4782449893814226250">JÅ«s lÅ«dzÄt vecÄkiem atļauju apmeklÄ“t Å¡o lapu.</translation>
<translation id="4800132727771399293">PÄrbaudiet derÄ«guma termiņu un CVC kodu un mÄ“Ä£iniet vÄ“lreiz.</translation>
-<translation id="4807049035289105102">PaÅ¡laik nevarat apmeklÄ“t vietni <ph name="SITE" />, jo tÄ nosÅ«tÄ«ja bojÄtus akreditÄcijas datus, ko nevar apstrÄdÄt pÄrlÅ«kÄ Google Chrome. TÄ«kla kļūdas un uzbrukumi parasti ir Ä«slaicÄ«gi, tÄpÄ“c Å¡Ä« lapa vÄ“lÄk, visticamÄk, darbosies.</translation>
<translation id="4813512666221746211">Tīkla kļūda</translation>
<translation id="4816492930507672669">IetilpinÄt lapÄ</translation>
<translation id="4850886885716139402">Skatīt</translation>
<translation id="4880827082731008257">Meklēšanas vēsture</translation>
+<translation id="4884656795097055129">Citi raksti tiks parÄdÄ«ti piemÄ“rotÄ brÄ«dÄ«.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{un vēl 1 tīmekļa lapa}zero{un vēl # tīmekļa lapas}one{un vēl # tīmekļa lapa}other{un vēl # tīmekļa lapas}}</translation>
<translation id="4923417429809017348">Å Ä« lapa ir tulkota no nezinÄmas valodas valodÄ: <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">JÄbÅ«t norÄdÄ«tai.</translation>
<translation id="4930497775425430760">Å is ziņojums tiek rÄdÄ«ts, jo pirmÄ apmeklÄ“juma laikÄ vienam no vecÄkiem ir jÄapstiprina jaunas vietnes.</translation>
<translation id="495170559598752135">Darbības</translation>
<translation id="4958444002117714549">Izvērst sarakstu</translation>
+<translation id="4962322354953122629">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts nav uzticams pÄrlÅ«kÄ Chrome. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Vai tulkot no <ph name="ORIGINAL_LANGUAGE" /> valodas <ph name="TARGET_LANGUAGE" /> valodÄ?</translation>
+<translation id="4989809363548539747">Šis spraudnis netiek atbalstīts</translation>
<translation id="5002932099480077015">IespÄ“jojot Å¡o opciju, Chrome saglabÄs jÅ«su kartes informÄciju Å¡ajÄ ierÄ«cÄ“, lai jÅ«s varÄ“tu ÄtrÄk aizpildÄ«t veidlapas.</translation>
<translation id="5019198164206649151">DublÄ“jumu krÄtuve nav labÄ stÄvoklÄ«.</translation>
<translation id="5023310440958281426">Administratora politiku pÄrbaude</translation>
@@ -357,13 +378,12 @@
<translation id="5031870354684148875">Par Google tulkotÄju</translation>
<translation id="5040262127954254034">KonfidencialitÄte</translation>
<translation id="5045550434625856497">Nepareiza parole</translation>
+<translation id="5056549851600133418">Jums piemeklēti raksti</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />PÄrbaudiet starpniekservera adresi<ph name="END_LINK" />.</translation>
<translation id="5087286274860437796">Servera sertifikÄts Å¡obrÄ«d nav derÄ«gs.</translation>
<translation id="5089810972385038852">Å tats</translation>
-<translation id="5094747076828555589">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄts netiek uzskatÄ«ts par uzticamu Chromium sistÄ“mÄ. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
<translation id="5095208057601539847">Province</translation>
<translation id="5115563688576182185">(64 bitu)</translation>
-<translation id="5122371513570456792">MeklÄ“jot pÄ“c virknes “<ph name="SEARCH_STRING" />â€, tika atrasti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /></translation>
<translation id="5141240743006678641">Å ifrÄ“t sinhronizÄ“tÄs paroles, izmantojot Google akreditÄcijas datus</translation>
<translation id="5145883236150621069">Politikas atbildē ir kļūdas kods.</translation>
<translation id="5171045022955879922">Meklējiet vai ievadiet URL.</translation>
@@ -372,18 +392,18 @@
<translation id="5190835502935405962">GrÄmatzÄ«mju josla</translation>
<translation id="5199729219167945352">Eksperimenti</translation>
<translation id="5251803541071282808">MÄkonis</translation>
+<translation id="5277279256032773186">Vai izmantojat Chrome darbÄ? Uzņēmumi var pÄrvaldÄ«t darbinieku Chrome iestatÄ«jumus. Uzziniet vairÄk.</translation>
<translation id="5299298092464848405">ParsÄ“jot politiku, radÄs kļūda.</translation>
<translation id="5300589172476337783">RÄdÄ«t</translation>
<translation id="5308689395849655368">AvÄriju pÄrskatu izveide ir atspÄ“jota.</translation>
<translation id="5317780077021120954">SaglabÄt</translation>
<translation id="5327248766486351172">Nosaukums</translation>
+<translation id="5359637492792381994">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts Å¡obrÄ«d nav uzticams. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu.<ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">NeizdevÄs saglabÄt politikas iestatÄ«jumus.</translation>
-<translation id="540969355065856584">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts Å¡obrÄ«d nav derÄ«gs. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ļaunprÄtÄ«gi izmanto jÅ«su savienojumu.</translation>
<translation id="5421136146218899937">NotÄ«rÄ«t pÄrlÅ«koÅ¡anas datus</translation>
<translation id="5430298929874300616">Noņemt grÄmatzÄ«mi</translation>
<translation id="5431657950005405462">Fails nav atrasts</translation>
<translation id="5435775191620395718">Tiek rÄdÄ«ta vÄ“sture no Å¡Ä«s ierÄ«ces. <ph name="BEGIN_LINK" />Uzziniet vairÄk<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">PersonalizÄ“ta satura ieteikumi paÅ¡laik ir atspÄ“joti, jo jÅ«su sinhronizÄ“tie dati tiek aizsargÄti ar pielÄgotu ieejas frÄzi.</translation>
<translation id="5439770059721715174">Å eit tika atklÄta shÄ“mas validÄ“Å¡anas kļūda: <ph name="ERROR_PATH" />. Kļūdas ziņojums: <ph name="ERROR" />.</translation>
<translation id="5452270690849572955">Å o vietnes <ph name="HOST_NAME" /> lapu nevar atrast</translation>
<translation id="5455374756549232013">Politikas laikspiedols nav derīgs.</translation>
@@ -406,14 +426,18 @@
<translation id="5622887735448669177">Vai vēlaties pamest šo vietni?</translation>
<translation id="5629630648637658800">NeizdevÄs ielÄdÄ“t politikas iestatÄ«jumus.</translation>
<translation id="5631439013527180824">IerÄ«ces pÄrvaldÄ«bas marÄ·ieris nav derÄ«gs.</translation>
-<translation id="5650551054760837876">MeklÄ“Å¡anas rezultÄti nav atrasti.</translation>
<translation id="5677928146339483299">BloÄ·Ä“ts</translation>
<translation id="5710435578057952990">TÄ«mekļa vietnes identitÄte nav apstiprinÄta.</translation>
<translation id="5720705177508910913">PaÅ¡reizÄ“jais lietotÄjs</translation>
+<translation id="572328651809341494">Nesen atvērtas cilnes</translation>
<translation id="5784606427469807560">Apstiprinot karti, radÄs problÄ“ma. PÄrbaudiet interneta savienojumu un mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="5785756445106461925">TurklÄt Å¡ajÄ lapÄ ir citi resursi, kas nav droÅ¡i. KamÄ“r Å¡ie resursi tiek pÄrsÅ«tÄ«ti, tos var aplÅ«kot citi, kÄ arÄ« uzbrucÄ“js var tos pÄrveidot, lai mainÄ«tu lapas izskatu.</translation>
+<translation id="5786044859038896871">Vai vÄ“laties aizpildÄ«t laukus ar kartes informÄciju?</translation>
+<translation id="5803412860119678065">Vai vÄ“laties aizpildÄ«t lauku ar informÄciju “<ph name="CARD_DETAIL" />â€?</translation>
<translation id="5810442152076338065">Savienojums ar domēnu <ph name="DOMAIN" /> ir šifrēts, izmantojot novecojušu šifra komplektu.</translation>
<translation id="5813119285467412249">&amp;Pievienošanas atsaukuma atcelšana</translation>
+<translation id="5814352347845180253">Varat zaudÄ“t piekļuvi maksas saturam no vietnes <ph name="SITE" /> un dažÄm citÄm vietnÄ“m.</translation>
+<translation id="5843436854350372569">JÅ«s mÄ“Ä£inÄjÄt sasniegt domÄ“nu <ph name="DOMAIN" />, taÄu serveris uzrÄdÄ«ja sertifikÄtu ar nedroÅ¡u atslÄ“gu. IespÄ“jams, uzbrucÄ“js ir uzlauzis privÄto atslÄ“gu un Å¡is serveris var nebÅ«t tas serveris, kuru mÄ“Ä£inÄt sasniegt (iespÄ“jams, jÅ«s sazinÄties ar uzbrucÄ“ju). <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Å is ziņojums tiek rÄdÄ«ts, jo pÄrvaldnieks bloÄ·Ä“ja Å¡o vietni.</translation>
<translation id="5857090052475505287">Jauna mape</translation>
<translation id="5869405914158311789">Å Ä« vietne nav sasniedzama</translation>
@@ -421,6 +445,7 @@
<translation id="5872918882028971132">VecÄku ieteikumi</translation>
<translation id="59107663811261420">Å is kartes veids Å¡im tirgotÄjam pakalpojumÄ Google Payments netiek atbalstÄ«ts. LÅ«dzu, atlasiet citu karti.</translation>
<translation id="59174027418879706">Iespējots</translation>
+<translation id="5926846154125914413">Varat zaudÄ“t piekļuvi maksas saturam no noteiktÄm vietnÄ“m.</translation>
<translation id="5966707198760109579">Nedēļa</translation>
<translation id="5967867314010545767">Noņemt no vēstures</translation>
<translation id="5975083100439434680">TÄlinÄt</translation>
@@ -432,12 +457,12 @@
<translation id="604124094241169006">AutomÄtiski</translation>
<translation id="6042308850641462728">VairÄk</translation>
<translation id="6060685159320643512">Esiet uzmanīgs! Šie eksperimenti var jums kaitēt</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{nav}=1{1}zero{#}one{#}other{#}}</translation>
<translation id="6146055958333702838">PÄrbaudiet vadus un atkÄrtoti palaidiet marÅ¡rutÄ“tÄjus, modemus vai citas
izmantotÄs tÄ«kla ierÄ«ces.</translation>
<translation id="614940544461990577">Veiciet tÄlÄk norÄdÄ«tÄs darbÄ«bas.</translation>
<translation id="6150607114729249911">Lai apmeklÄ“tu Å¡o lapu, jums ir jÄlÅ«dz atļauja vecÄkiem.</translation>
<translation id="6151417162996330722">Å Ä« servera sertifikÄta derÄ«guma periods ir pÄrÄk ilgs.</translation>
-<translation id="6154808779448689242">Atgrieztais politikas marķieris neatbilst pašreizējam marķierim.</translation>
<translation id="6165508094623778733">Uzziniet vairÄk</translation>
<translation id="6203231073485539293">Interneta savienojuma pÄrbaude</translation>
<translation id="6218753634732582820">Vai noņemt adresi no pÄrlÅ«ka Chromium?</translation>
@@ -450,24 +475,30 @@
<translation id="6328639280570009161">Tīkla prognožu atspējošana</translation>
<translation id="6337534724793800597">Filtrēt politikas pēc nosaukuma</translation>
<translation id="6342069812937806050">Tikko</translation>
+<translation id="6345221851280129312">nezinÄms lielums</translation>
<translation id="6355080345576803305">Publiskas sesijas ignorēšana</translation>
<translation id="6358450015545214790">Ko tas nozīmē?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{vēl 1 ieteikums}zero{vēl # ieteikumi}one{vēl # ieteikums}other{vēl # ieteikumi}}</translation>
<translation id="6387478394221739770">Vai jūs interesē jaunas Chrome funkcijas? Izmēģiniet mūsu Beta versiju, kas pieejama vietnē chrome.com/beta.</translation>
-<translation id="641480858134062906"><ph name="URL" /> neizdevÄs ielÄdÄ“t</translation>
+<translation id="6389758589412724634">MÄ“Ä£inot parÄdÄ«t Å¡o tÄ«mekļa lapu, pÄrlÅ«ka Chromium atmiÅ†Ä nepietika vietas.</translation>
+<translation id="6416403317709441254">Å obrÄ«d nevarat apmeklÄ“t vietni <ph name="SITE" />, jo no tÄs tika nosÅ«tÄ«ti sajaukti akreditÄcijas dati, kurus nevar apstrÄdÄt pÄrlÅ«kÄ Chromium. TÄ«kla kļūdas un brÄ«dinÄjumi parasti ir Ä«slaicÄ«gi, tÄpÄ“c Å¡Ä« lapa vÄ“lÄk, visticamÄk, darbosies. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Nevar pÄrbaudÄ«t, vai sertifikÄts ir atsaukts.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> noraidīja savienojuma izveidi.</translation>
<translation id="6445051938772793705">Valsts</translation>
<translation id="6451458296329894277">ApstiprinÄt veidlapas atkÄrtotu iesniegÅ¡anu</translation>
<translation id="6458467102616083041">Ignorēta, jo ar politiku ir atspējota noklusējuma meklēšana.</translation>
+<translation id="6462969404041126431">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts, iespÄ“jams, ir atsaukts. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Ierīces politikas</translation>
<translation id="6489534406876378309">SÄkt avÄriju datu augÅ¡upielÄdi</translation>
<translation id="6529602333819889595">&amp;Dzēšanas atsaukuma atcelšana</translation>
+<translation id="6534179046333460208">FiziskÄ tÄ«mekļa ieteikumi</translation>
<translation id="6550675742724504774">Opcijas</translation>
+<translation id="6593753688552673085">mazÄk nekÄ <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Šifrēšanas opcijas</translation>
<translation id="662080504995468778">Palikt</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> meklēšana</translation>
-<translation id="6634865548447745291">PaÅ¡laik nevarat apmeklÄ“t vietni <ph name="SITE" />, jo <ph name="BEGIN_LINK" />Å¡is sertifikÄts ir atsaukts<ph name="END_LINK" />. TÄ«kla kļūdas un uzbrukumi parasti ir Ä«slaicÄ«gi, tÄdÄ“jÄdi Å¡Ä« lapa vÄ“lÄk, visticamÄk, darbosies.</translation>
<translation id="6644283850729428850">Å Ä« politika ir izbeigta.</translation>
+<translation id="6652240803263749613">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts nav uzticams jÅ«su datora operÄ“tÄjsistÄ“mÄ. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Mapes rediģēšana</translation>
<translation id="6660210980321319655">AutomÄtiski ziņots: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Vai noņemt veidlapas ieteikumu no pÄrlÅ«ka Chromium?</translation>
@@ -475,6 +506,7 @@
<translation id="6710213216561001401">Iepriekšējais</translation>
<translation id="6710594484020273272">&lt;Ierakstiet meklēšanas vienumu&gt;</translation>
<translation id="6711464428925977395">StarpniekserverÄ« radÄs kļūda, vai arÄ« adrese nav pareiza.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{nav}=1{1 vienums}zero{# vienumi}one{# vienums}other{# vienumi}}</translation>
<translation id="674375294223700098">NezinÄma servera sertifikÄta kļūda.</translation>
<translation id="6753269504797312559">Politikas vērtība</translation>
<translation id="6757797048963528358">IerÄ«ce tika pÄrslÄ“gta miega režīmÄ.</translation>
@@ -486,7 +518,6 @@
<translation id="6891596781022320156">Politikas līmenis netiek atbalstīts.</translation>
<translation id="6895330447102777224">Karte ir apstiprinÄta</translation>
<translation id="6897140037006041989">LietotÄja aÄ£ents</translation>
-<translation id="6903907808598579934">IeslÄ“gt sinhronizÄciju</translation>
<translation id="6915804003454593391">LietotÄjs:</translation>
<translation id="6957887021205513506">Å Ä·iet, ka servera sertifikÄts ir viltojums.</translation>
<translation id="6965382102122355670">Labi</translation>
@@ -494,9 +525,11 @@
<translation id="6970216967273061347">Rajons</translation>
<translation id="6973656660372572881">Ir norÄdÄ«ti gan fiksÄ“ti starpniekserveri, gan .pac skripta URL.</translation>
<translation id="6989763994942163495">RÄdÄ«t papildu iestatÄ«jumus...</translation>
+<translation id="7000990526846637657">Netika atrasts neviens vēstures ieraksts.</translation>
+<translation id="7009986207543992532">JÅ«s mÄ“Ä£inÄjÄt sasniegt domÄ“nu <ph name="DOMAIN" />, taÄu serveris uzrÄdÄ«ja sertifikÄtu, kura derÄ«guma periods ir pÄrÄk ilgs, lai bÅ«tu uzticams. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">JÅ«su Google kontam var bÅ«t cita veida pÄrlÅ«koÅ¡anas vÄ“stures dati vietnÄ“ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="7029809446516969842">Paroles</translation>
-<translation id="7050187094878475250">JÅ«s mÄ“Ä£inÄjÄt sasniegt domÄ“nu <ph name="DOMAIN" />, bet serveris uzrÄdÄ«ja sertifikÄtu, kura derÄ«guma periods ir pÄrÄk ilgs, lai bÅ«tu uzticams.</translation>
<translation id="7087282848513945231">GrÄfiste</translation>
<translation id="7088615885725309056">VecÄka</translation>
<translation id="7090678807593890770">Veiciet Google meklÄ“Å¡anu, izmantojot vaicÄjumu “<ph name="LINK" />â€</translation>
@@ -515,13 +548,13 @@
<translation id="7246609911581847514">Å is ziņojums tiek rÄdÄ«ts, jo pirmÄ apmeklÄ“juma laikÄ pÄrvaldniekam ir jÄapstiprina jaunas vietnes.</translation>
<translation id="724975217298816891">Lai atjauninÄtu kartes informÄciju, ievadiet kredÄ«tkartes <ph name="CREDIT_CARD" /> derÄ«guma termiņu un CVC. PÄ“c apstiprinÄÅ¡anas kartes informÄcija tiks kopÄ«gota ar Å¡o vietni.</translation>
<translation id="725866823122871198">Nevar izveidot privÄtu savienojumu ar <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, jo jÅ«su datora datums un laiks (<ph name="DATE_AND_TIME" />) nav pareizs.</translation>
-<translation id="7265986070661382626">PaÅ¡laik nevarat apmeklÄ“t vietni <ph name="SITE" />, jo tajÄ <ph name="BEGIN_LINK" />tiek izmantota sertifikÄtu piesprauÅ¡ana<ph name="END_LINK" />. TÄ«kla kļūdas un brÄ«dinÄjumi parasti ir Ä«slaicÄ«gi, tÄpÄ“c Å¡Ä« lapa vÄ“lÄk, visticamÄk, darbosies.</translation>
<translation id="7269802741830436641">TÄ«mekļa lapai ir pÄrvirzes cilpa</translation>
<translation id="7275334191706090484">PÄrvaldÄ«tÄs grÄmatzÄ«mes</translation>
<translation id="7298195798382681320">Ieteicams</translation>
-<translation id="7301833672208172928">Ieslēgt vēstures sinhronizēšanu</translation>
+<translation id="7309308571273880165">AvÄrijas pÄrskats notverts: <ph name="CRASH_TIME" /> (augÅ¡upielÄdi pieprasÄ«jis lietotÄjs; augÅ¡upielÄde vÄ“l nav veikta)</translation>
<translation id="7334320624316649418">&amp;Atcelt pÄrkÄrtoÅ¡anas atsaukÅ¡anu</translation>
<translation id="733923710415886693">Servera sertifikÄts netika atklÄts, izmantojot Certificate Transparency.</translation>
+<translation id="7351800657706554155">PaÅ¡laik nevarat apmeklÄ“t vietni <ph name="SITE" />, jo Å¡is sertifikÄts ir atsaukts. TÄ«kla kļūdas un uzbrukumi parasti ir Ä«slaicÄ«gi, tÄpÄ“c Å¡Ä« lapa ,visticamÄk, vÄ“lÄk darbosies. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Komandrinda</translation>
<translation id="7372973238305370288">meklÄ“Å¡anas rezultÄts</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -540,16 +573,17 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="7469372306589899959">Notiek kartes apstiprinÄÅ¡ana</translation>
<translation id="7481312909269577407">PÄrsÅ«tÄ«t</translation>
<translation id="7485870689360869515">Dati netika atrasti.</translation>
+<translation id="7508255263130623398">Atgrieztais politikas ierīces ID ir tukšs vai neatbilst pašreizējam ierīces ID.</translation>
<translation id="7514365320538308">LejupielÄdÄ“t</translation>
<translation id="7518003948725431193">Å ÄdÄ tÄ«mekļa adresÄ“ netika atrasta neviena tÄ«mekļa lapa: <ph name="URL" /></translation>
<translation id="7537536606612762813">ObligÄti</translation>
<translation id="7542995811387359312">AutomÄtiska kredÄ«tkartes numura ievadÄ«Å¡ana ir atspÄ“jota, jo Å¡ai veidlapai netiek izmantots droÅ¡s savienojums.</translation>
<translation id="7549584377607005141">Lai tÄ«mekļa lapu varÄ“tu attÄ“lot pareizi, tai nepiecieÅ¡ami jÅ«su iepriekÅ¡ ievadÄ«tie dati. Varat atkÄrtoti nosÅ«tÄ«t Å¡os datus, taÄu tÄdÄ gadÄ«jumÄ tiks atkÄrtota ikviena darbÄ«ba, ko pirms tam veica lapa.</translation>
<translation id="7554791636758816595">Jauna cilne</translation>
-<translation id="7567204685887185387">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄts, iespÄ“jams, ir izveidots krÄpnieciski. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
<translation id="7568593326407688803">Å Ä« lapa ir rakstÄ«ta<ph name="ORIGINAL_LANGUAGE" />valodÄ. Vai vÄ“laties to tulkot?</translation>
<translation id="7569952961197462199">Vai noņemt kredÄ«tkarti no pÄrlÅ«ka Chrome?</translation>
<translation id="7578104083680115302">Ä€tri apmaksÄjiet pirkumus vietnÄ“s un lietotnÄ“s no dažÄdÄm ierÄ«cÄ“m, izmantojot kartes, ko esat saglabÄjis Google sistÄ“mÄ.</translation>
+<translation id="7588950540487816470">Fiziskais tīmeklis</translation>
<translation id="7592362899630581445">Servera sertifikÄtÄ ir pÄrkÄpti nosaukuma ierobežojumi.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> paÅ¡laik nevar apstrÄdÄt Å¡o pieprasÄ«jumu.</translation>
<translation id="7600965453749440009">Nekad netulkot saturu, kas rakstÄ«ts <ph name="LANGUAGE" /> valodÄ</translation>
@@ -560,6 +594,7 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="7637571805876720304">Vai noņemt kredÄ«tkarti no pÄrlÅ«ka Chromium?</translation>
<translation id="765676359832457558">Slēpt papildu iestatījumus...</translation>
<translation id="7658239707568436148">Atcelt</translation>
+<translation id="7667346355482952095">Atgrieztais politikas marķieris ir tukšs vai neatbilst pašreizējam marķierim</translation>
<translation id="7668654391829183341">NezinÄma ierÄ«ce</translation>
<translation id="7674629440242451245">Vai jÅ«s interesÄ“ jaunas Chrome funkcijas? IzmÄ“Ä£iniet izstrÄdÄtÄja versiju vietnÄ“ chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Apmeklēt vietni <ph name="SITE" /> (nav droša)<ph name="END_LINK" /></translation>
@@ -576,10 +611,10 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="780301667611848630">NÄ“, paldies</translation>
<translation id="7805768142964895445">Statuss</translation>
<translation id="7813600968533626083">Vai noņemt veidlapas ieteikumu no pÄrlÅ«ka Chrome?</translation>
+<translation id="7815407501681723534">MeklÄ“jot pÄ“c virknes “<ph name="SEARCH_STRING" />â€, tika atrasti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /></translation>
<translation id="785549533363645510">TomÄ“r jÅ«s neesat neredzams. PÄrlÅ«kojot inkognito režīmÄ, jÅ«su pÄrlÅ«koÅ¡anas darbÄ«bas netiek slÄ“ptas no jÅ«su darba devÄ“ja, interneta pakalpojumu sniedzÄ“ja vai apmeklÄ“tajÄm vietnÄ“m.</translation>
<translation id="7887683347370398519">PÄrbaudiet CVC kodu un mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="7894616681410591072">Lai apmeklÄ“tu Å¡o lapu, jums ir jÄsaņem atļauja no lietotÄja <ph name="NAME" />.</translation>
-<translation id="790025292736025802"><ph name="URL" /> nav atrasts</translation>
<translation id="7912024687060120840">Mapē:</translation>
<translation id="7920092496846849526">JÅ«s lÅ«dzÄt vienam no vecÄkiem atļauju apmeklÄ“t Å¡o lapu.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -592,9 +627,10 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="7995512525968007366">Nav norÄdÄ«ts</translation>
<translation id="8012647001091218357">MÄ“s nevarÄ“jÄm sasniegt jÅ«su vecÄkus. LÅ«dzu, mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="8034522405403831421">Å Ä« lapas saturs ir Å¡ÄdÄ valodÄ: <ph name="SOURCE_LANGUAGE" />. Vai tulkot Å¡ÄdÄ valodÄ: <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Netika atrasts neviens vēstures ieraksts.</translation>
<translation id="8088680233425245692">Rakstu neizdevÄs skatÄ«t.</translation>
+<translation id="8089520772729574115">mazÄk nekÄ 1 MB</translation>
<translation id="8091372947890762290">AktivizÄcija vÄ“l nav apstiprinÄta serverÄ«.</translation>
+<translation id="8129262335948759431">nezinÄms skaits</translation>
<translation id="8131740175452115882">ApstiprinÄt</translation>
<translation id="8134994873729925007">Nevarēja atrast <ph name="HOST_NAME" /> servera <ph name="BEGIN_ABBR" />DNS adresi<ph name="END_ABBR" />.</translation>
<translation id="8149426793427495338">Dators tika pÄrslÄ“gts miega režīmÄ.</translation>
@@ -603,6 +639,7 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="8201077131113104583">NederÄ«gs atjauninÄÅ¡anas URL paplaÅ¡inÄjumam ar ID “<ph name="EXTENSION_ID" />â€.</translation>
<translation id="8218327578424803826">PieÅ¡Ä·irtÄ atraÅ¡anÄs vieta:</translation>
<translation id="8225771182978767009">Persona, kura iestatÄ«ja Å¡o datoru, izvÄ“lÄ“jÄs bloÄ·Ä“t Å¡o vietni.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Lapa, ko meklÄ“jÄt, izmantoja jÅ«su ievadÄ«to informÄciju. AtgrieÅ¡anÄs lapÄ var radÄ«t jebkuras jÅ«su darbÄ«bas atkÄrtojumu. Vai vÄ“laties turpinÄt?</translation>
<translation id="8249320324621329438">PÄ“dÄ“jÄs pirmsielÄdes laiks:</translation>
<translation id="8261506727792406068">Dzēst</translation>
@@ -615,12 +652,17 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="8349305172487531364">GrÄmatzÄ«mju josla</translation>
<translation id="8363502534493474904">Izslēdziet lidojuma režīmu.</translation>
<translation id="8364627913115013041">Nav iestatīta.</translation>
+<translation id="8380941800586852976">BÄ«stama</translation>
<translation id="8412145213513410671">AvÄrijas (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Viena un tÄ pati ieejas frÄze jÄievada divreiz.</translation>
<translation id="8428213095426709021">Iestatījumi</translation>
+<translation id="8433057134996913067">Å Ädi tiksiet izrakstÄ«ts no lielÄkÄs daļas vietņu.</translation>
<translation id="8437238597147034694">&amp;Atsaukt pÄrvietoÅ¡anu</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kredītkarte}zero{# kredītkartes}one{# kredītkarte}other{# kredītkartes}}</translation>
+<translation id="8483780878231876732">Lai izmantotu kartes no sava Google konta, pierakstieties pÄrlÅ«kÄ Chrome!</translation>
<translation id="8488350697529856933">Attiecas uz</translation>
<translation id="8498891568109133222">Vietne <ph name="HOST_NAME" /> pÄrÄk ilgi nereaģēja.</translation>
+<translation id="852346902619691059">Å is serveris nevarÄ“ja pierÄdÄ«t, ka tas ir domÄ“ns <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts nav uzticams jÅ«su ierÄ«ces operÄ“tÄjsistÄ“mÄ. Å Ä« problÄ“ma var rasties nepareizas konfigurÄcijas dēļ vai tÄdēļ, ka kÄds uzbrucÄ“js ir pÄrtvÄ“ris jÅ«su savienojumu. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Å is kartes veids netiek atbalstÄ«ts pakalpojumÄ Google Payments. LÅ«dzu, atlasiet citu karti.</translation>
<translation id="8550022383519221471">SinhronizÄcijas ierÄ«ce jÅ«su domÄ“nam nav pieejama.</translation>
<translation id="8553075262323480129">TulkoÅ¡ana neizdevÄs, jo lapas valoda nav nosakÄma.</translation>
@@ -632,15 +674,12 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="8647750283161643317">Atiestatīt visiem to noklusējuma iestatījumus</translation>
<translation id="8680787084697685621">Konta pierakstÄ«Å¡anÄs informÄcija ir novecojusi.</translation>
<translation id="8703575177326907206">Jūsu savienojums ar <ph name="DOMAIN" /> nav kodēts.</translation>
-<translation id="8713130696108419660">NederÄ«gs sÄkotnÄ“jais paraksts</translation>
<translation id="8725066075913043281">MÄ“Ä£inÄt vÄ“lreiz</translation>
<translation id="8728672262656704056">Jūs esat atvēris inkognito režīmu</translation>
<translation id="8730621377337864115">Gatavs</translation>
<translation id="8738058698779197622">Lai izveidotu droÅ¡u savienojumu, ir jÄiestata pareizs pulksteņa laiks. Tas ir nepiecieÅ¡ams, jo sertifikÄti, kurus vietnes izmanto, lai tiktu identificÄ“tas, ir derÄ«gi tikai noteiktos laika periodos. TÄ kÄ jÅ«su ierÄ«ces pulkstenis nav pareizi iestatÄ«ts, Chromium nevar verificÄ“t Å¡os sertifikÄtus.</translation>
<translation id="8740359287975076522">Nevarēja atrast <ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS adresi&lt;/abbr&gt;. Notiek problēmas diagnosticēšana.</translation>
-<translation id="8741995161408053644">JÅ«su Google kontam var bÅ«t cita veida pÄrlÅ«koÅ¡anas vÄ“stures dati vietnÄ“ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Atcelt dzēšanas atsaukšanu</translation>
-<translation id="8790687370365610530">Lai saņemtu Google ieteikto personalizÄ“to saturu, ieslÄ“dziet vÄ“stures sinhronizÄciju.</translation>
<translation id="8798099450830957504">Noklusējums</translation>
<translation id="8804164990146287819">KonfidencialitÄtes politika</translation>
<translation id="8820817407110198400">GrÄmatzÄ«mes</translation>
@@ -662,13 +701,11 @@ NÄkamreiz jums varÄ“tu noderÄ“t inkognito režīms (<ph name="SHORTCUT_KEY" />)
<translation id="8971063699422889582">Servera sertifikÄtam ir beidzies derÄ«guma termiņš.</translation>
<translation id="8987927404178983737">MÄ“nesis</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Serveris uzrÄdÄ«ja sertifikÄtu, kas netika publiski atklÄts, izmantojot Certificate Transparency politiku. Å Ä« ir prasÄ«ba noteiktiem sertifikÄtiem, lai nodroÅ¡inÄtu to uzticamÄ«bu un aizsardzÄ«bu pret uzbrucÄ“jiem.</translation>
<translation id="9001074447101275817">Starpniekserveris <ph name="DOMAIN" /> pieprasa lietotÄjvÄrdu un paroli.</translation>
<translation id="901974403500617787">Atzīmes, kas attiecas uz visu sistēmu, var iestatīt tikai īpašnieks: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Å Ä« lapa ir tulkota <ph name="TARGET_LANGUAGE" /> valodÄ.</translation>
<translation id="9038649477754266430">Ieteikumu pakalpojuma izmantoÅ¡ana ÄtrÄkai lapu ielÄdei</translation>
<translation id="9039213469156557790">TurklÄt Å¡ajÄ lapÄ ir citi resursi, kas nav droÅ¡i. KamÄ“r Å¡ie resursi tiek pÄrsÅ«tÄ«ti, tos var aplÅ«kot citi, kÄ arÄ« uzbrucÄ“js var tos pÄrveidot, lai mainÄ«tu lapas uzvedÄ«bu.</translation>
-<translation id="9049981332609050619">JÅ«s centÄties piekļūt <ph name="DOMAIN" />, bet serveris piedÄvÄja nederÄ«gu sertifikÄtu.</translation>
<translation id="9050666287014529139">Ieejas frÄze</translation>
<translation id="9065203028668620118">Labot</translation>
<translation id="9092364396508701805">Vietnes <ph name="HOST_NAME" /> lapa nedarbojas</translation>
diff --git a/chromium/components/strings/components_strings_ml.xtb b/chromium/components/strings/components_strings_ml.xtb
index ee0c10f735f..99e5f731cd5 100644
--- a/chromium/components/strings/components_strings_ml.xtb
+++ b/chromium/components/strings/components_strings_ml.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ml">
+<translation id="1008557486741366299">ഇപàµà´ªàµ‹à´´à´²àµà´²</translation>
<translation id="1015730422737071372">കൂടàµà´¤àµ½ വിശദാംശങàµà´™àµ¾ നൽകàµà´•</translation>
<translation id="1032854598605920125">ഘടികാരദിശയിൽ‌ തിരികàµà´•àµà´•</translation>
<translation id="1038842779957582377">à´…à´œàµà´à´¾à´¤ നാമം</translation>
+<translation id="1053591932240354961">Google Chrome-നൠപàµà´°àµ‹à´¸à´¸àµà´¸àµà´àµ†à´¯àµà´¯à´¾à´¨à´¾à´•à´¾à´¤àµà´¤ രൂപമാറàµà´±à´‚ വരàµà´¤àµà´¤à´¿à´¯ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´•àµ¾ വെബàµà´¸àµˆà´±àµà´±àµ അയയàµâ€Œà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´².നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´• à´ªàµà´°à´¶àµâ€Œà´¨à´™àµà´™àµ¾ ആയതിനാൽ, à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´‚. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;à´àµ‡àµ¼à´•àµà´•àµà´¨àµà´¨à´¤àµ പഴയപടിയാകàµà´•àµà´•</translation>
<translation id="10614374240317010">à´’à´°à´¿à´•àµà´•à´²àµà´‚ സംരകàµà´·à´¿à´àµà´à´¿à´²àµà´²</translation>
-<translation id="1064422015032085147">വെബàµâ€Œà´ªàµ‡à´œàµ ഹോസàµà´±àµà´±àµà´àµ†à´¯àµâ€Œà´¤à´¿à´•àµà´•àµà´¨àµà´¨ സെർവർ ഓവർലോഡായിരികàµà´•à´¾à´‚ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ à´…à´±àµà´±à´•àµà´±àµà´±à´ªàµà´ªà´£à´¿à´¯à´¿à´²à´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚.
- വളരെയധികം à´Ÿàµà´°à´¾à´«à´¿à´•àµ സൃഷàµâ€Œà´Ÿà´¿à´àµà´àµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´‚ കൂടàµà´¤àµ½ സങàµà´•àµ€àµ¼à´£àµà´£à´®à´¾à´•àµà´•àµà´¨àµà´¨à´¤àµ
- ഒഴിവാകàµà´•à´¾àµ», à´ˆ URL-ലേകàµà´•àµà´³àµà´³ à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨à´•àµ¾ താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¿ റദàµà´¦à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="106701514854093668">ഡെസàµâ€Œà´•àµâ€Œà´Ÿàµ‹à´ªàµà´ªàµ à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•àµ¾</translation>
<translation id="1080116354587839789">à´…à´¨àµà´¯àµ‹à´œàµà´¯à´®à´¾à´¯ വീതിയിലാകàµà´•àµà´•</translation>
+<translation id="1103124106085518534">ഇപàµà´ªàµ‹à´´à´¤àµà´¤àµ‡à´•àµà´•àµ പൂർതàµà´¤à´¿à´¯à´¾à´•àµà´•à´¿</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> à´à´²àµà´²à´¾à´¯àµà´ªàµà´ªàµ‹à´´àµà´‚ വിവരàµâ€à´¤àµà´¤à´¨à´‚ à´àµ†à´¯àµà´¯àµà´• </translation>
<translation id="1107591249535594099">പരിശോധിà´àµà´àµ†à´™àµà´•à´¿àµ½, വേഗതേറിയ ഫോം പൂരിപàµà´ªà´¿à´•àµà´•à´²à´¿à´¨à´¾à´¯à´¿ à´ˆ ഉപകരണതàµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† കാർഡിനàµà´±àµ† ഒരൠപകർപàµà´ªàµ Chrome സംഭരികàµà´•àµà´‚.</translation>
+<translation id="1111153019813902504">à´…à´Ÿàµà´¤àµà´¤à´¿à´Ÿàµ† ഉപയോഗിà´àµà´ à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•àµ¾</translation>
<translation id="1113869188872983271">&amp;à´ªàµà´¨à´ƒà´•àµà´°à´®àµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ പഴയപടിയാകàµà´•àµà´•</translation>
+<translation id="1126551341858583091">ലോകàµà´•àµ½ à´¸àµâ€Œâ€Œà´±àµà´±àµ‹à´±àµ‡à´œà´¿à´¨àµà´±àµ† വലàµà´ªàµà´ªà´‚ <ph name="CRASH_SIZE" /> ആണàµ.</translation>
<translation id="112840717907525620">നയ കാഷെ ശരി</translation>
<translation id="113188000913989374"><ph name="SITE" /> സൈറàµà´±àµ പറയàµà´¨àµà´¨à´¤àµ:</translation>
<translation id="1132774398110320017">Chrome à´“à´Ÿàµà´Ÿàµ‹à´«à´¿àµ½ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾...</translation>
-<translation id="1150979032973867961">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´· സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† à´“à´ªàµà´ªà´±àµ‡à´±àµà´±à´¿à´‚ഗൠസിസàµâ€Œà´±àµà´±à´¤àµà´¤à´¿à´¨àµ പരിà´à´¯à´®à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.</translation>
<translation id="1152921474424827756"><ph name="URL" />-à´¨àµà´±àµ† <ph name="BEGIN_LINK" />കാഷെ à´àµ†à´¯àµâ€Œà´¤ പകർപàµà´ªàµ<ph name="END_LINK" /> ആകàµâ€Œà´¸à´¸àµà´¸àµà´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> à´…à´ªàµà´°à´¤àµ€à´•àµà´·à´¿à´¤à´®à´¾à´¯à´¿ കണകàµà´·àµ» à´…à´Ÿà´àµà´àµ.</translation>
<translation id="1161325031994447685">Wi-Fi-ലേകàµà´•àµ വീണàµà´Ÿàµà´‚ കണകàµà´±àµà´±àµà´àµ†à´¯àµà´¯àµà´¨àµà´¨àµ</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">നീകàµà´•à´‚à´àµ†à´¯àµà´¯àµ‚</translation>
<translation id="1201402288615127009">à´…à´Ÿàµà´¤àµà´¤à´¤àµ</translation>
<translation id="1201895884277373915">à´ˆ സൈറàµà´±à´¿àµ½ നിനàµà´¨àµà´‚ കൂടàµà´¤àµ½</translation>
-<translation id="121201262018556460">നിങàµà´™à´³àµâ€â€Œ <ph name="DOMAIN" /> à´à´¨àµà´¨à´¤à´¿à´²àµâ€ à´à´¤àµà´¤à´¾à´¨àµâ€â€Œ à´¶àµà´°à´®à´¿à´àµà´àµ, പകàµà´·àµ† സെർവർ ഹാജരാകàµà´•à´¿à´¯ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿àµ½ ഒരൠദàµàµ¼à´¬à´²à´®à´¾à´¯ കീ ഉൾപàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ. ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿à´•àµà´•àµ à´¸àµà´µà´•à´¾à´°àµà´¯ കീ നശിപàµà´ªà´¿à´àµà´à´¿à´°à´¿à´•àµà´•à´¾à´‚, കൂടാതെ സെർവർ നിങàµà´™àµ¾ à´ªàµà´°à´¤àµ€à´•àµà´·à´¿à´àµà´ സെർവർ ആയിരികàµà´•à´¿à´²àµà´² (നിങàµà´™àµ¾ ആശയവിനിമയം നടതàµà´¤àµà´¨àµà´¨à´¤àµ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿à´¯àµà´®à´¾à´¯à´¿à´Ÿàµà´Ÿà´¾à´•à´¾à´‚).</translation>
+<translation id="1206967143813997005">à´ªàµà´°à´¾à´°à´‚à´­ സിഗàµà´¨àµ‡à´àµà´àµ¼ ശരിയലàµà´²</translation>
+<translation id="1209206284964581585">ഇപàµà´ªàµ‹à´´à´¤àµà´¤àµ‡à´¯àµâ€Œà´•àµà´•àµ മറയàµâ€Œà´•àµà´•àµà´•</translation>
<translation id="1219129156119358924">സിസàµâ€Œà´±àµà´±à´‚ à´¸àµà´°à´•àµà´·</translation>
<translation id="1227224963052638717">അറിയപàµà´ªàµ†à´Ÿà´¾à´¤àµà´¤ നയം.</translation>
<translation id="1227633850867390598">മൂലàµà´¯à´‚ മറയàµâ€Œà´•àµà´•àµà´•</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">അതെ</translation>
<translation id="1430915738399379752">à´…à´àµà´à´Ÿà´¿à´•àµà´•àµà´•</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /><ph name="DOMAIN" /> à´à´¨àµà´¨à´¤à´¿à´²àµ† ഒരൠപേജൠസനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨àµà´³àµà´³ <ph name="END_LINK" /> à´¶àµà´°à´®à´‚ തടà´àµà´àµ.</translation>
+<translation id="1491663344921578213">വെബàµà´¸àµˆà´±àµà´±àµ, സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ പിനàµà´¨à´¿à´‚ഗൠഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´². നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´• à´ªàµà´°à´¶àµâ€Œà´¨à´™àµà´™à´³à´¾à´¯à´¤à´¿à´¨à´¾àµ½, à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´‚. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">à´ˆ പേജിനàµà´±àµ† സംരകàµà´·à´¿à´àµà´ (അതായതàµ. അതൠകാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿà´¤à´¾à´¯à´¿ അറിയികàµà´•àµà´¨àµà´¨àµ) പകർപàµà´ªàµ കാണികàµà´•àµà´•</translation>
<translation id="1519264250979466059">ബിൽഡൠതീയതി</translation>
<translation id="1549470594296187301">à´ˆ ഫീà´àµà´àµ¼ ഉപയോഗികàµà´•à´¾àµ» JavaScript à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´®à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•à´£à´‚.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ കോൺഫിഗറേഷൻ അസാധàµà´µà´¾à´¯à´¤à´¿à´¨à´¾àµ½ ഇമàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµà´àµ†à´¯àµà´¯à´¾àµ» à´•à´´à´¿à´àµà´à´¿à´²àµà´².</translation>
<translation id="1644574205037202324">à´à´°à´¿à´¤àµà´°à´‚</translation>
<translation id="1645368109819982629">à´ªàµà´°àµ‡à´¾à´Ÿàµà´Ÿàµ‡à´¾à´•àµà´•àµ‡à´¾àµ¾ പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
-<translation id="1655462015569774233">{1,plural, =1{à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ഇനàµà´¨à´²àµ† കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ നിലവിൽ <ph name="CURRENT_DATE" /> à´à´¨àµà´¨àµ സജàµà´œà´®à´¾à´•àµà´•à´¿. അതൠശരിയാണോ? à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½, നിങàµà´™àµ¾ സിസàµà´±àµà´±à´¤àµà´¤à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ ശരിയാകàµà´•à´¿ à´ˆ പേജൠപàµà´¤àµà´•àµà´•àµà´•.}other{à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; ഇതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ # ദിവസം à´®àµà´®àµà´ªàµ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ നിലവിൽ <ph name="CURRENT_DATE" /> à´à´¨àµà´¨àµ സജàµà´œà´®à´¾à´•àµà´•à´¿. അതൠശരിയാണോ? à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½, നിങàµà´™àµ¾ സിസàµà´±àµà´±à´¤àµà´¤à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ ശരിയാകàµà´•à´¿ à´ˆ പേജൠപàµà´¤àµà´•àµà´•àµà´•.}}</translation>
<translation id="1676269943528358898">നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ പരിരകàµà´·à´¿à´•àµà´•à´¾àµ» സാധാരണയായി <ph name="SITE" />, à´àµ»à´•àµà´°à´¿à´ªàµâ€Œà´·àµ» ഉപയോഗികàµà´•àµà´¨àµà´¨àµ. ഇപàµà´ªàµ‹àµ¾ <ph name="SITE" /> സൈറàµà´±à´¿à´²àµ‡à´•àµà´•àµ കണകàµâ€Œà´±àµà´±àµà´àµ†à´¯àµà´¯à´¾àµ» Google Chrome à´¶àµà´°à´®à´¿à´àµà´à´ªàµà´ªàµ‹àµ¾, അസാധാരണമായതàµà´‚ തെറàµà´±à´¾à´¯à´¤àµà´®à´¾à´¯ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´•àµ¾ വെബàµâ€Œà´¸àµˆà´±àµà´±àµ തിരികെ à´…à´¯à´àµà´àµ. ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿, <ph name="SITE" /> à´à´¨àµà´¨à´¤à´¾à´¯à´¿ ഭാവികàµà´•à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´®àµà´ªàµ‹à´´àµ‹ Wi-Fi സൈൻ ഇൻ à´¸àµâ€Œà´•àµà´°àµ€àµ», കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´®àµà´ªàµ‹à´´àµ‹ ആണൠഇങàµà´™à´¨àµ† സംഭവികàµà´•à´¾à´¨à´¿à´Ÿà´¯àµà´³àµà´³à´¤àµ. à´à´¤àµ†à´™àµà´•à´¿à´²àµà´‚ ഡാറàµà´± കൈമാറàµà´¨àµà´¨à´¤à´¿à´¨àµà´®àµà´®àµà´ªàµ Google Chrome കണകàµà´·àµ» അവസാനിപàµà´ªà´¿à´àµà´à´¤à´¿à´¨à´¾àµ½, നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ à´¤àµà´Ÿàµ¼à´¨àµà´¨àµà´‚ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´¯à´¿à´°à´¿à´•àµà´•àµà´‚.</translation>
<translation id="168841957122794586">സെർവർ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿àµ½ ഒരൠദàµàµ¼à´¬à´²à´®à´¾à´¯ ഗൂഢഭാഷ കീ ഉൾപàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ.</translation>
<translation id="1701955595840307032">നിർദàµà´¦àµ‡à´¶à´¿à´àµà´ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´¸àµà´µà´¨àµà´¤à´®à´¾à´•àµà´•àµà´•</translation>
-<translation id="1706954506755087368">{1,plural, =1{à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ഇനàµà´¨à´²àµ† à´®àµà´¤àµ½ സാധàµà´µà´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.}other{à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ # ദിവസം à´®àµà´¤àµ½ സാധàµà´µà´¾à´¯à´¿à´°à´¿à´•àµà´•à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">സിസàµà´±àµà´±à´‚ à´…à´¡àµâ€Œà´®à´¿à´¨àµ† ബനàµà´§à´ªàµà´ªàµ†à´Ÿà´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
<translation id="17513872634828108">à´“à´ªàµà´ªàµº ടാബàµà´•àµ¾</translation>
<translation id="1753706481035618306">പേജൠനമàµà´ªàµ¼</translation>
-<translation id="1761412452051366565">Google നിർദàµà´¦àµ‡à´¶à´¿à´àµà´, à´µàµà´¯à´•àµà´¤à´¿à´ªà´°à´®à´¾à´•àµà´•à´¿à´¯ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´¸àµà´µà´¨àµà´¤à´®à´¾à´•àµà´•à´¾àµ», സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´• ഓണാകàµà´•àµà´•.</translation>
-<translation id="1763864636252898013">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´· സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† à´“à´ªàµà´ªà´±àµ‡à´±àµà´±à´¿à´‚ഗൠസിസàµâ€Œà´±àµà´±à´¤àµà´¤à´¿à´¨àµ പരിà´à´¯à´®à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ à´àµ†à´¯àµâ€Œà´¤àµà´¨àµ‹à´•àµà´•àµ‚<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">നിങàµà´™à´³àµà´Ÿàµ† സമനàµà´µà´¯ പാസàµâ€Œà´«àµà´°àµ‡à´¸àµ ദയവായി à´…à´ªàµâ€Œà´¡àµ‡à´±àµà´±àµ à´àµ†à´¯àµà´¯àµà´•.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">നിങàµà´™à´³àµà´Ÿàµ† à´…à´Ÿàµà´¤àµà´¤à´¿à´Ÿàµ† സനàµà´¦àµ¼à´¶à´¿à´àµà´ à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•àµ¾ ഇവിടെ ദൃശàµà´¯à´®à´¾à´•àµà´‚.</translation>
<translation id="1821930232296380041">à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ പാരാമീറàµà´±à´±àµà´•àµ¾ അസാധàµà´µà´¾à´£àµ</translation>
<translation id="1838667051080421715">നിങàµà´™àµ¾ ഒരൠവെബൠപേജിനàµà´±àµ† ഉറവിടമാണൠകാണàµà´¨àµà´¨à´¤àµ.</translation>
<translation id="1871208020102129563">à´¸àµà´¥à´¿à´°à´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സെർവറàµà´•àµ¾ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´¿ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സജàµà´œàµ€à´•à´°à´¿à´àµà´à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, ഒരൠ.pac à´¸àµâ€Œà´•àµà´°à´¿à´ªàµà´±àµà´±àµ URL ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´²àµà´².</translation>
<translation id="1883255238294161206">ലിസàµà´±àµà´±àµ à´àµà´°àµà´•àµà´•àµà´•</translation>
<translation id="1898423065542865115">ഫിൽടàµà´Ÿàµ¼ à´àµ†à´¯àµà´¯àµà´¨àµà´¨àµ</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" />, നിങàµà´™à´³àµà´Ÿàµ† ലോഗിൻ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ അംഗീകരിà´àµà´à´¿à´²àµà´² à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ ലോഗിൻ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿà´¤à´¾à´•à´¾à´‚.</translation>
<translation id="194030505837763158"><ph name="LINK" />-ലേകàµà´•àµ പോകàµà´•</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•àµ¾</translation>
<translation id="1973335181906896915">സീരിയലൈസേഷൻ പിശകàµ</translation>
<translation id="1974060860693918893">നൂതനം</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{കൂടാതെ 1 കൂടി}other{à´à´¨àµà´¨à´¿à´µà´¯àµà´‚ # à´à´£àµà´£à´µàµà´‚ കൂടി}}</translation>
<translation id="2025186561304664664">à´ªàµà´°àµ‹à´•àµà´¸à´¿ à´¸àµà´µà´¯à´®àµ‡à´µ കോൺഫിഗർ à´àµ†à´¯àµà´¯à´¾àµ» സജàµà´œà´®à´¾à´•àµà´•à´¿.</translation>
<translation id="2030481566774242610">നിങàµà´™àµ¾ ഉദàµà´¦àµ‡à´¶à´¿à´àµà´à´¤àµ <ph name="LINK" /> ആണോ?</translation>
<translation id="2031925387125903299">à´ªàµà´¤à´¿à´¯ സൈറàµà´±àµà´•à´³à´¿àµ½ ആദàµà´¯à´®à´¾à´¯à´¿ പോകàµà´®àµà´ªàµ‹àµ¾ അവയàµâ€Œà´•àµà´•àµ നിങàµà´™àµ¾à´•àµà´•àµ à´°à´•àµà´·à´¿à´¤à´¾à´•àµà´•à´³àµà´Ÿàµ† അംഗീകാരം ആവശàµà´¯à´®à´¾à´¯à´¤à´¿à´¨à´¾à´²à´¾à´£àµ à´ˆ സനàµà´¦àµ‡à´¶à´‚ കാണàµà´¨àµà´¨à´¤àµ.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿à´¯àµà´‚ ഫയർവാളàµà´‚ പരിശോധികàµà´•àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">തപാൽ കോഡàµ</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{ഒരൠനിർദàµà´¦àµ‡à´¶à´‚}other{# നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾}}</translation>
<translation id="2065985942032347596">ആധികാരികത ആവശàµà´¯à´®à´¾à´£àµ</translation>
<translation id="2079545284768500474">പൂരàµâ€â€Œà´µàµà´µà´¾à´µà´¸àµà´¥à´¯à´¿à´²à´¾à´•àµà´•àµà´•</translation>
<translation id="20817612488360358">സിസàµà´±àµà´±à´‚ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ à´•àµà´°à´®àµ€à´•à´°à´£à´‚ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´¿ സജàµà´œà´®à´¾à´•àµà´•à´¿, പകàµà´·àµ† ഒരൠസàµâ€Œà´ªà´·àµâ€Œà´Ÿà´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ കോൺഫിഗറേഷനàµà´‚ അതോടàµà´ªàµà´ªà´‚ നിർദàµà´¦àµ‡à´¶à´¿à´àµà´à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">à´¬àµà´•àµà´®à´¾à´°àµâ€à´•àµà´•àµ à´à´¡à´¿à´±àµà´±àµ à´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="2166049586286450108">പൂർണàµà´£à´®à´¾à´¯ à´…à´¡àµâ€Œà´®à´¿àµ» ആകàµâ€Œà´¸à´¸àµà´¸àµ</translation>
<translation id="2166378884831602661">à´ˆ സൈറàµà´±à´¿à´¨àµ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´¯ കണകàµà´·àµ» നൽകാനാകിലàµà´²</translation>
-<translation id="2171101176734966184">നിങàµà´™à´³àµâ€â€Œ <ph name="DOMAIN" /> à´à´¨àµà´¨à´¤à´¿à´²àµâ€ à´à´¤àµà´¤à´¾à´¨àµâ€â€Œ à´¶àµà´°à´®à´¿à´àµà´àµ, പകàµà´·àµ‡ ഒരൠദàµàµ¼à´¬à´²à´®à´¾à´¯ സിഗàµâ€Œà´¨àµ‡à´àµà´à´°àµâ€â€Œ à´…à´²àµâ€â€Œà´—ോരിതം ഉപയോഗിà´àµà´àµ à´’à´ªàµà´ªà´¿à´Ÿàµà´Ÿ ഒരൠസരàµâ€â€Œà´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ സെരàµâ€â€Œà´µà´°àµâ€â€Œ നലàµâ€â€Œà´•à´¿. ഇതിനരàµâ€â€Œà´¤àµà´¥à´‚ സെരàµâ€â€Œà´µà´°àµâ€â€Œ നലàµâ€â€Œà´•à´¿à´¯ à´¸àµà´°à´•àµà´·à´¾ à´•àµà´°àµ†à´¡à´¨àµâ€â€Œà´·àµà´¯à´²àµà´•à´³àµâ€â€Œ à´µàµà´¯à´¾à´œà´®à´¾à´•à´¾à´®àµ†à´¨àµà´¨àµà´‚ സെരàµâ€â€Œà´µà´°àµâ€â€Œ നിങàµà´™à´³àµâ€â€Œ ഉദàµà´¦àµ‡à´¶à´¿à´àµà´ സെരàµâ€â€Œà´µà´±à´¾à´¯à´¿à´°à´¿à´•àµà´•à´¿à´²àµà´²àµ†à´¨àµà´¨àµà´®à´¾à´£àµ (നിങàµà´™à´³àµâ€â€Œ ആകàµà´°à´®à´£à´•à´¾à´°à´¿à´¯àµà´®à´¾à´¯à´¿à´Ÿàµà´Ÿà´¾à´•à´¾à´‚ ആശയവിനിമയം നടതàµà´¤àµà´¨àµà´¨à´¤àµ).</translation>
<translation id="2181821976797666341">നയങàµà´™àµ¾</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{ഒരൠവിലാസം}other{# വിലാസങàµà´™àµ¾}}</translation>
<translation id="2212735316055980242">നയം à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´²</translation>
<translation id="2213606439339815911">à´àµ»à´Ÿàµà´°à´¿à´•àµ¾ ലഭàµà´¯à´®à´¾à´•àµà´•àµà´¨àµà´¨àµ...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> ലഭàµà´¯à´®à´²àµà´²</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ ആപàµà´ªàµ<ph name="END_LINK" /> ഉപയോഗിà´àµà´àµ കണകഷൻ à´ªàµà´°à´¶àµâ€Œà´¨à´‚ പരിഹരികàµà´•àµà´•</translation>
+<translation id="2239100178324503013">ഇപàµà´ªàµ‹àµ¾ അയയàµâ€Œà´•àµà´•àµà´•</translation>
<translation id="225207911366869382">à´ˆ നയതàµà´¤à´¿à´¨à´¾à´¯à´¿ à´ˆ മൂലàµà´¯à´¤àµà´¤àµ† ഒഴിവാകàµà´•à´¿.</translation>
<translation id="2262243747453050782">HTTP പിശകàµ</translation>
<translation id="2282872951544483773">ലഭàµà´¯à´®à´²àµà´²à´¾à´¤àµà´¤ പരീകàµà´·à´£à´™àµà´™àµ¾</translation>
<translation id="2292556288342944218">നിങàµà´™à´³àµà´Ÿàµ† ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ ആകàµâ€Œà´¸à´¸àµà´¸àµ à´¬àµà´²àµ‹à´•àµà´•àµà´àµ†à´¯àµâ€Œà´¤àµ</translation>
<translation id="229702904922032456">ഒരൠറൂടàµà´Ÿàµ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ ഇനàµà´±àµ¼à´®àµ€à´¡à´¿à´¯à´±àµà´±àµ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
<translation id="230155334948463882">à´ªàµà´¤à´¿à´¯ കാർഡാണോ?</translation>
+<translation id="2305919008529760154">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´µàµà´¯à´¾à´œà´®à´¾à´¯à´¿ നൽകിയതായിരികàµà´•à´¾à´‚. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨àµ ഒരൠഉപയോകàµà´¤àµƒà´¨à´¾à´®à´µàµà´‚ പാസàµâ€Œà´µàµ‡à´¡àµà´‚ വേണം.</translation>
+<translation id="2318774815570432836">വെബàµà´¸àµˆà´±àµà´±àµ HSTS ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•àµ ഇപàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´². നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´• à´ªàµà´°à´¶àµâ€Œà´¨à´™àµà´™à´³à´¾à´¯à´¤à´¿à´¨à´¾àµ½ à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´‚. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155"><ph name="ENTRY_INDEX" /> സൂà´à´¿à´•à´¯à´¿àµ½ അസാധàµà´µà´¾à´¯ à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµ അവഗണിà´àµà´àµ</translation>
<translation id="2354001756790975382">മറàµà´±àµ à´¬àµà´•àµâ€Œà´®à´¾à´°àµâ€à´•àµà´•àµà´•à´³àµâ€</translation>
<translation id="2359808026110333948">à´¤àµà´Ÿà´°àµ‚</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" />-നൠകàµà´¯à´¾à´ªàµâ€Œà´àµà´àµ¼ à´àµ†à´¯àµâ€Œà´¤ à´•àµà´°à´¾à´·àµ റിപàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµ à´…à´ªàµâ€Œà´²àµ‹à´¡àµà´àµ†à´¯àµâ€Œà´¤à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²</translation>
<translation id="2367567093518048410">നില</translation>
+<translation id="2371153335857947666">{1,plural, =1{à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ഇനàµà´¨à´²àµ† കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ നിലവിൽ <ph name="CURRENT_DATE" /> à´à´¨àµà´¨àµ സജàµà´œà´®à´¾à´•àµà´•à´¿. അതൠശരിയാണോ? à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½, നിങàµà´™àµ¾ സിസàµà´±àµà´±à´¤àµà´¤à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ ശരിയാകàµà´•à´¿ à´ˆ പേജൠപàµà´¤àµà´•àµà´•àµà´•. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.}other{à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; ഇതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ # ദിവസം à´®àµà´®àµà´ªàµ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ നിലവിൽ <ph name="CURRENT_DATE" /> à´à´¨àµà´¨àµ സജàµà´œà´®à´¾à´•àµà´•à´¿. അതൠശരിയാണോ? à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½, നിങàµà´™àµ¾ സിസàµà´±àµà´±à´¤àµà´¤à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ ശരിയാകàµà´•à´¿ à´ˆ പേജൠപàµà´¤àµà´•àµà´•àµà´•. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">UI ഇതരമാർഗങàµà´™à´³àµà´¨àµà´¨àµà´‚ ലഭàµà´¯à´®à´²àµà´²</translation>
<translation id="2384307209577226199">à´à´¨àµà´±à´°àµâ€à´ªàµà´°àµˆà´¸àµ ഡിഫോൾടàµà´Ÿàµ</translation>
-<translation id="238526402387145295">വെബàµà´¸àµˆà´±àµà´±àµ <ph name="BEGIN_LINK" /> HSTS ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ <ph name="END_LINK" /> നിങàµà´™àµ¾à´•àµà´•àµ ഇപàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´². നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¤à´¿à´¨à´¾àµ½ à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¾à´£àµ.</translation>
<translation id="2386255080630008482">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ അസാധàµà´µà´¾à´•àµà´•à´¿.</translation>
<translation id="2392959068659972793">മൂലàµà´¯à´®àµà´¨àµà´¨àµà´‚ സജàµà´œà´®à´¾à´•àµà´•à´¾à´¤àµà´¤ നയങàµà´™àµ¾ കാണികàµà´•àµà´•</translation>
<translation id="2396249848217231973">&amp;ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµ½ പഴയപടിയാകàµà´•àµà´•</translation>
-<translation id="2413528052993050574">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; സെർവറിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ റദàµà´¦à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.</translation>
<translation id="2455981314101692989">à´ˆ വെബàµà´ªàµ‡à´œàµ à´ˆ ഫോമിനായàµà´³àµà´³ à´¸àµà´µà´ªàµà´°àµ‡à´°à´¿à´¤ à´«à´¿à´²àµà´²à´¿à´‚ഗിനെ à´…à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•à´¿.</translation>
+<translation id="2463739503403862330">പൂരിപàµà´ªà´¿à´•àµà´•àµà´•</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ à´àµ†à´¯àµà´¯àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">തിരയൽ URL അസാധàµà´µà´¾à´£àµ.</translation>
<translation id="2491120439723279231">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´²àµâ€ പിശകàµà´•à´³àµâ€ à´…à´Ÿà´™àµà´™à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">സമരàµâ€à´ªàµà´ªà´¿à´•àµà´•àµ‚</translation>
<translation id="2674170444375937751">നിങàµà´™à´³àµà´Ÿàµ† à´à´°à´¿à´¤àµà´°à´¤àµà´¤à´¿à´²àµâ€ നിനàµà´¨àµà´‚ à´ˆ പേജàµà´•à´³àµâ€ മായàµà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ നിങàµà´™à´³àµâ€ താലàµà´ªà´°àµà´¯à´®àµà´£àµà´Ÿàµ‹?</translation>
<translation id="2677748264148917807">ഉപേകàµà´·à´¿à´•àµà´•àµà´•</translation>
+<translation id="269990154133806163">സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´¸àµà´¤à´¾à´°àµà´¯à´¤à´¾ നയം ഉപയോഗിà´àµà´àµ സെർവർ, à´à´²àµà´²à´¾à´µàµ¼à´•àµà´•àµà´®à´¾à´¯à´¿ വെളàµà´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²à´¾à´¤àµà´¤ ഒരൠസർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ലഭàµà´¯à´®à´¾à´•àµà´•à´¿. à´à´¿à´² സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµà´•àµ¾ വിശàµà´µà´¾à´¸à´¯àµ‹à´—àµà´¯à´®à´¾à´£àµ†à´¨àµà´¨àµà´‚ à´…à´•àµà´°à´®à´•à´¾à´°à´¿à´•à´³à´¿àµ½ നിനàµà´¨àµà´‚ പരിരകàµà´·à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¾à´£àµ†à´¨àµà´¨àµà´‚ ഉറപàµà´ªà´¾à´•àµà´•à´¾àµ» അവയàµâ€Œà´•àµà´•àµ ഇതൠആവശàµà´¯à´®à´¾à´£àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">മൂലàµà´¯à´‚ ഫോർമാറàµà´±àµà´®à´¾à´¯à´¿ à´ªàµà´°àµà´¤àµà´¤à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨à´¿à´²àµà´².</translation>
<translation id="2704951214193499422">Chromium-à´¤àµà´¤à´¿à´¨àµ ഇപàµà´ªàµ‹àµ¾ നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠസàµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´². പിനàµà´¨àµ€à´Ÿàµ വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
<translation id="2705137772291741111">à´ˆ സൈറàµà´±à´¿à´¨àµà´±àµ† സംരകàµà´·à´¿à´àµà´ (കാഷെ à´àµ†à´¯àµâ€Œà´¤) പതിപàµà´ªàµ വായികàµà´•à´¾à´¨à´¾à´•à´¾à´¤àµà´¤à´¤à´¾à´£àµ.</translation>
<translation id="2709516037105925701">à´“à´Ÿàµà´Ÿàµ‹à´«à´¿à´²àµâ€</translation>
+<translation id="2712118517637785082">നിങàµà´™àµ¾â€Œ <ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¿àµ½â€Œ à´à´¤àµà´¤à´¾à´¨àµâ€â€Œ à´¶àµà´°à´®à´¿à´àµà´àµ, പകàµà´·àµ‡ സെർവർ‌ നൽകിയ സർ‌ടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† അതിനàµà´±àµ† ഇഷàµà´¯àµ‚വർ റദàµà´¦à´¾à´•àµà´•à´¿. സെർവർ നൽ‌കിയ à´¸àµà´°à´•àµà´·à´¾ à´•àµà´°àµ†à´¡à´¨àµâ€â€Œà´·àµà´¯à´²àµà´•àµ¾ തികà´àµà´àµà´‚ വിശàµà´µà´¾â€à´¸à´¯àµ‹à´—àµà´¯à´®à´²àµà´² à´à´¨àµà´¨à´¾à´£àµ ഇതിനരàµâ€â€Œà´¤àµà´¥à´‚. നിങàµà´™àµ¾ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿à´¯àµà´®à´¾à´¯à´¿à´Ÿàµà´Ÿà´¾à´•à´¾à´‚ ആശയവിനിമയം നടതàµà´¤àµà´¨àµà´¨à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">à´…à´¨àµà´®à´¤à´¿ à´àµ‹à´¦à´¿à´•àµà´•àµà´•</translation>
<translation id="2721148159707890343">à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ വിജയിà´àµà´àµ</translation>
<translation id="2728127805433021124">ഒരൠദàµà´°àµâ€à´¬àµà´¬à´² സിഗàµà´¨àµ‡à´àµà´à´°àµâ€ à´…à´²àµâ€à´—ോരിതം ഉപയോഗിà´àµà´àµà´•àµà´£àµà´Ÿàµ സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´’à´ªàµà´ªàµà´µà´àµà´àµ.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">വിലാസവàµà´‚ തിരയൽ ബാറàµà´‚</translation>
<translation id="2826760142808435982"><ph name="CIPHER" /> ഉപയോഗിà´àµà´àµ കണകàµà´·àµ» à´àµ»à´•àµà´°à´¿à´ªàµâ€Œà´±àµà´±àµà´àµ†à´¯àµâ€Œà´¤àµ à´ªàµà´°à´¾à´®à´¾à´£àµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, à´’à´ªàµà´ªà´‚ à´ªàµà´°à´§à´¾à´¨ à´à´•àµâ€Œà´¸àµ‡à´àµà´àµ മെകàµà´•à´¾à´¨à´¿à´¸à´®à´¾à´¯à´¿ <ph name="KX" /> ഉപയോഗികàµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="2835170189407361413">ഫോം മായàµâ€Œà´•àµà´•àµà´•</translation>
-<translation id="2837049386027881519">TLS à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ SSL à´ªàµà´°àµ‹à´Ÿàµà´Ÿàµ‹à´•àµà´•àµ‹à´³à´¿à´¨àµà´±àµ† ഒരൠപഴയ പതിപàµà´ªàµ ഉപയോഗിà´àµà´àµ കണകàµà´·à´¨à´¾à´¯à´¿ വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµ‡à´£àµà´Ÿà´¤àµà´£àµà´Ÿàµ. സെർവർ വളരെ പഴയ ഒരൠസോഫàµà´±àµà´±àµâ€Œà´µàµ†à´¯àµ¼ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ à´¸àµà´°à´•àµà´·à´¾ à´ªàµà´°à´¶àµâ€Œà´¨à´™àµà´™àµ¾à´•àµà´•àµ ഇടയàµà´£àµà´Ÿà´¾à´•à´¾à´®àµ†à´¨àµà´¨à´¤à´¾à´£àµ സാധാരണ ഗതിയിൽ ഇതിനർതàµà´¥à´‚.</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> ഹോസàµâ€Œà´±àµà´±à´¿à´²àµ† സെർവർ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ വിശàµà´µà´¾à´¸à´¯àµ‹à´—àµà´¯à´®à´²àµà´²àµ†à´¨àµà´¨àµ തോനàµà´¨àµà´¨àµà´¨àµ.</translation>
<translation id="2889159643044928134">റീലോഡàµà´àµ†à´¯àµà´¯à´°àµà´¤àµ</translation>
-<translation id="2896499918916051536">à´ˆ à´ªàµà´²à´—ിൻ പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´².</translation>
+<translation id="2900469785430194048">à´ˆ വെബàµâ€Œà´ªàµ‡à´œàµ à´ªàµà´°à´¦àµ¼à´¶à´¿à´ªàµà´ªà´¿à´•àµà´•à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¿à´Ÿà´¯à´¿àµ½ Google Chrome-à´¨àµà´±àµ† മെമàµà´®à´±à´¿ നിറà´àµà´àµ.</translation>
<translation id="2909946352844186028">ഒരൠനെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ മാറàµà´±à´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿.</translation>
-<translation id="2915500479781995473">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. നിലവിൽ നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† സമയം <ph name="CURRENT_TIME" /> à´à´¨àµà´¨à´¾à´¯à´¿ സജàµà´œàµ€à´•à´°à´¿à´àµà´à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ. അതൠശരിയലàµà´²àµ‡? ശരിയലàµà´²àµ†à´™àµà´•à´¿àµ½, സിസàµâ€Œà´±àµà´±à´¤àµà´¤à´¿à´¨àµà´±àµ† സമയം ശരിയാകàµà´•à´¿à´¯à´¤à´¿à´¨àµà´¶àµ‡à´·à´‚ à´ˆ പേജൠപàµà´¤àµà´•àµà´•àµà´•.</translation>
<translation id="2922350208395188000">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ പരിശോധികàµà´•à´¾à´¨àµâ€ കഴിയിലàµà´².</translation>
-<translation id="2941952326391522266">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; <ph name="DOMAIN2" /> à´à´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµà´³àµà´³à´¤à´¾à´£àµ അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.</translation>
<translation id="2948083400971632585">കണകàµà´·à´¨à´¾à´¯à´¿ കോൺഫിഗർ à´àµ†à´¯àµâ€Œà´¤ à´à´¤àµà´°àµ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿à´•à´³àµà´‚ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ പേജിൽ നിനàµà´¨àµ നിങàµà´™àµ¾à´•àµà´•àµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´•àµà´•à´¾à´¨à´¾à´•àµà´‚.</translation>
<translation id="2955913368246107853">ഫൈനàµâ€à´¡àµ ബാരàµâ€ à´…à´Ÿà´¯àµà´•àµà´•àµà´•</translation>
<translation id="2958431318199492670">നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ കോൺഫിഗറേഷൻ ONC à´¸àµà´±àµà´±à´¾àµ»à´¡àµ‡àµ¼à´¡à´¿à´¨àµ à´…à´¨àµà´¸àµƒà´¤à´®à´¾à´¯à´¿ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². കോൺഫിഗറേഷൻ ഭാഗങàµà´™àµ¾ ഇമàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµà´àµ†à´¯àµâ€Œà´¤àµ‡à´•àµà´•à´¿à´²àµà´².</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">തെറàµà´±à´¾à´¯ നയ തരം</translation>
<translation id="3032412215588512954">à´ˆ സൈറàµà´±àµ റീലോഡàµà´àµ†à´¯àµà´¯à´£àµ‹?</translation>
<translation id="3037605927509011580">à´•à´·àµà´Ÿà´‚!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´àµà´ ഉപകരണങàµà´™à´³à´¿àµ½ ഒരൠഇനമെങàµà´•à´¿à´²àµà´‚}=1{ഒരൠഇനം (à´’à´ªàµà´ªà´‚ സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´àµà´ ഉപകരണങàµà´™à´³à´¿àµ½ അതിൽ കൂടàµà´¤à´²àµà´‚)}other{# ഇനങàµà´™àµ¾ (à´’à´ªàµà´ªà´‚ സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´àµà´ ഉപകരണങàµà´™à´³à´¿àµ½ അതിൽ കൂടàµà´¤à´²àµà´‚)}}</translation>
<translation id="3041612393474885105">സരàµâ€â€Œà´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ വിവരങàµà´™à´³àµâ€â€Œ</translation>
<translation id="3063697135517575841">Chrome-നൠഇപàµà´ªàµ‹àµ¾ നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠസàµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´². പിനàµà´¨àµ€à´Ÿàµ വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
<translation id="3093245981617870298">നിങàµà´™àµ¾ à´“à´«àµâ€Œà´²àµˆà´¨à´¿à´²à´¾à´£àµ.</translation>
@@ -205,15 +208,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">à´à´±àµà´±à´µàµà´‚ à´ªàµà´¤à´¿à´¯</translation>
<translation id="3207960819495026254">à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´àµ†à´¯àµâ€Œà´¤àµ</translation>
-<translation id="3225919329040284222">ബിൽടàµà´Ÿàµ-ഇൻ à´ªàµà´°à´¤àµ€à´•àµà´·à´•à´³àµâ€à´•àµà´•àµ à´ªàµà´°àµà´¤àµà´¤à´ªàµà´ªàµ†à´Ÿà´¾à´¤àµà´¤ സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¾à´£àµ സെരàµâ€à´µà´°àµâ€ അവതരിപàµà´ªà´¿à´àµà´à´¤àµ. നിങàµà´™à´³àµ† സംരകàµà´·à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•à´¾à´¯àµà´³àµà´³ നിശàµà´à´¿à´¤, ഉനàµà´¨à´¤-à´¸àµà´°à´•àµà´·à´¾ വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•àµ¾à´•àµà´•à´¾à´¯à´¾à´£àµ à´ˆ à´ªàµà´°à´¤àµ€à´•àµà´·à´•àµ¾ ഉൾപàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ.</translation>
<translation id="3226128629678568754">പേജൠലോഡàµà´àµ†à´¯àµà´¯àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´µà´¶àµà´¯à´®à´¾à´¯ ഡാറàµà´± വീണàµà´Ÿàµà´‚ സമർപàµà´ªà´¿à´•àµà´•à´¾àµ» വീണàµà´Ÿàµà´‚ ലോഡàµà´àµ†à´¯àµà´¯àµà´• ബടàµà´Ÿàµº അമർതàµà´¤àµà´•.</translation>
<translation id="3228969707346345236"><ph name="LANGUAGE" /> à´²àµâ€â€Œ à´ˆ പേജൠഇതിനകം ഉളàµà´³à´¤à´¿à´¨à´¾à´²àµâ€â€Œ വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" />-à´¨àµà´±àµ† CVC നൽകàµà´•</translation>
<translation id="3254409185687681395">à´ˆ പേജൠബàµà´•àµâ€Œà´®à´¾à´°àµâ€à´•àµà´•àµ à´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="3270847123878663523">&amp;à´ªàµà´¨à´ƒà´•àµà´°à´®àµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ പഴയപടിയാകàµà´•àµà´•</translation>
<translation id="3286538390144397061">ഇപàµà´ªàµ‹à´³àµâ€ à´ªàµà´¨à´°à´¾à´°à´‚à´­à´¿à´•àµà´•àµà´•</translation>
+<translation id="3303855915957856445">തിരയൽ ഫലങàµà´™à´³àµà´¨àµà´¨àµà´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´²</translation>
<translation id="3305707030755673451"><ph name="TIME" />-നൠനിങàµà´™à´³àµà´Ÿàµ† സമനàµà´µà´¯ പാസàµâ€Œà´«àµà´°àµ†à´¯àµâ€Œà´¸àµ ഉപയോഗിà´àµà´àµ ഡാറàµà´± à´àµ»à´•àµà´°à´¿à´ªàµâ€Œà´±àµà´±àµà´àµ†à´¯àµâ€Œà´¤àµ. സമനàµà´µà´¯à´‚ ആരംഭികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ ഇതൠനൽകàµà´•.</translation>
<translation id="333371639341676808">അധികമàµà´³àµà´³ ഡയലോഗàµà´•à´³àµâ€ സൃഷàµà´Ÿà´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´²àµâ€ നിനàµà´¨àµ à´ˆ പേജിനെ തടയൂ.</translation>
+<translation id="3338095232262050444">à´¸àµà´°à´•àµà´·à´¿à´¤à´‚</translation>
<translation id="3340978935015468852">à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾</translation>
<translation id="3345135638360864351">à´ˆ സൈറàµà´±àµ ആകàµâ€Œà´¸à´¸àµà´¸àµ à´àµ†à´¯àµà´¯à´¾à´¨àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨, <ph name="NAME" /> à´à´¨àµà´¨à´¯à´¾àµ¾à´•àµà´•àµ അയയàµâ€Œà´•àµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´². വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
<translation id="3355823806454867987">à´ªàµà´°àµ‹à´•àµà´¸à´¿ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™à´³àµâ€ മാറàµà´±àµà´•...</translation>
@@ -231,6 +235,7 @@
<translation id="3452404311384756672">ഇടവേള ലഭàµà´¯à´®à´¾à´•àµà´•àµà´•:</translation>
<translation id="3462200631372590220">വിപàµà´²à´®à´¾à´¯à´µ മറയàµà´•àµà´•àµà´•</translation>
<translation id="3479539252931486093">ഇതൠഅപàµà´°à´¤àµ€à´•àµà´·à´¿à´¤à´®à´¾à´¯à´¿à´°àµà´¨àµà´¨àµ‹? <ph name="BEGIN_LINK" />à´à´™àµà´™à´³àµ† അറിയികàµà´•àµà´•<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">ഇപàµà´ªàµ‹à´´à´²àµà´²</translation>
<translation id="348000606199325318">à´•àµà´°à´¾à´·àµ à´à´¡à´¿, <ph name="CRASH_LOCAL_ID" /> (സെർവർ à´à´¡à´¿: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">ഇപàµà´ªàµ‹àµ¾ à´à´™àµà´™àµ¾à´•àµà´•àµ നിങàµà´™à´³àµà´Ÿàµ† à´°à´•àµà´·à´•àµ¼à´¤àµà´¤à´¾à´µà´¿à´¨àµ† ബനàµà´§à´ªàµà´ªàµ†à´Ÿà´¾à´¨à´¾à´¯à´¿à´²àµà´². വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
<translation id="3527085408025491307">ഫോൾഡർ</translation>
@@ -239,6 +244,7 @@
<translation id="3542684924769048008">ഇതിനായി പാസàµâ€Œà´µàµ‡à´¡àµ ഉപയോഗികàµà´•àµà´•:</translation>
<translation id="3549644494707163724">നിങàµà´™à´³àµà´Ÿàµ† à´¸àµà´µà´¨àµà´¤à´‚ പാസàµâ€Œà´«àµà´°àµ†à´¯àµâ€Œà´¸àµ ഉപയോഗിà´àµà´àµ à´à´²àµà´²à´¾ സമനàµà´µà´¿à´¤ ഡാറàµà´±à´¯àµà´‚ à´àµ»à´•àµà´°à´¿à´ªàµà´±àµà´±àµà´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> à´à´£àµà´£à´‚ കൂടി...</translation>
+<translation id="3555561725129903880">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ <ph name="DOMAIN2" /> à´à´¨àµà´¨ à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¿àµ½ നിനàµà´¨àµà´³àµà´³à´¤à´¾à´£àµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·àµ» à´¸àµà´µà´•à´¾à´°àµà´¯à´®à´²àµà´²</translation>
<translation id="3583757800736429874">&amp;നീകàµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ à´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="3586931643579894722">വിശദാംശങàµà´™àµ¾ മറയàµâ€Œà´•àµà´•àµà´•â€â€Œ</translation>
@@ -250,12 +256,15 @@
<translation id="3623476034248543066">മൂലàµà´¯à´‚ കാണികàµà´•àµà´•</translation>
<translation id="3630155396527302611">ഇതിനെ നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ആകàµâ€Œà´¸à´¸àµà´¸àµà´àµ†à´¯àµà´¯à´¾àµ» à´…à´¨àµà´®à´¤à´¿à´¯àµà´³àµà´³ ഒരൠപàµà´°àµ‹à´—àµà´°à´¾à´®à´¾à´¯à´¿ നിലവിൽ ലിസàµà´±àµà´±àµà´àµ†à´¯àµâ€Œà´¤à´¿à´Ÿàµà´Ÿàµà´£àµà´Ÿàµ†à´™àµà´•à´¿àµ½,
അതിനെ ലിസàµà´±àµà´±à´¿àµ½ നിനàµà´¨àµ നീകàµà´•à´‚à´àµ†à´¯àµâ€Œà´¤àµ, വീണàµà´Ÿàµà´‚ à´àµ‡àµ¼à´•àµà´•à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
+<translation id="3638794133396384728">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•àµ¼ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. നിലവിൽ നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† സമയം <ph name="CURRENT_TIME" /> à´à´¨àµà´¨àµ സജàµà´œà´®à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ. അതൠശരിയലàµà´²àµ‡? ശരിയലàµà´²àµ†à´™àµà´•à´¿àµ½, സിസàµâ€Œà´±àµà´±à´¤àµà´¤à´¿à´¨àµà´±àµ† സമയം ശരിയാകàµà´•à´¿à´¯à´¤à´¿à´¨àµà´¶àµ‡à´·à´‚ à´ˆ പേജൠപàµà´¤àµà´•àµà´•à´¿à´¯àµ†à´Ÿàµà´•àµà´•àµà´•. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">à´ˆ പരീകàµà´·à´£ സവിശേഷതകൾ à´à´¤àµ സമയതàµà´¤àµà´‚ മാറàµà´•à´¯àµ‹ തകരാറിലാകàµà´•à´¯àµ‹ à´…à´ªàµà´°à´¤àµà´¯à´•àµà´·à´®à´¾à´µàµà´•à´¯àµ‹ à´àµ†à´¯àµà´¯à´¾à´‚. നിങàµà´™àµ¾ à´ˆ പരീകàµà´·à´£à´™àµà´™à´³à´¿à´²àµà´¨àµà´¨àµ ഓൺ à´àµ†à´¯àµà´¤à´¾àµ½ à´à´¨àµà´¤àµ സംഭവികàµà´•àµà´®àµ†à´¨àµà´¨à´¤àµ സംബനàµà´§à´¿à´àµà´àµ à´à´™àµà´™àµ¾ പൂർണàµà´£à´®à´¾à´¯ ഒരൠഉറപàµà´ªàµà´‚ നൽകിലàµà´², മാതàµà´°à´®à´²àµà´² നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´°àµŒà´¸àµ¼ ആകàµà´¸àµà´®à´¿à´•à´®à´¾à´¯à´¿ തകരാറിലാകàµà´• പോലàµà´‚ à´àµ†à´¯àµà´¤àµ‡à´•àµà´•à´¾à´‚. തമാശ നിർതàµà´¤àµ‚, നിങàµà´™à´³àµà´Ÿàµ† à´à´²àµà´²à´¾ ഡാറàµà´±à´¯àµ†à´¯àµà´‚ à´¬àµà´°àµŒà´¸àµ¼ ഇലàµà´²à´¾à´¤à´¾à´•àµà´•à´¿à´¯àµ‡à´•àµà´•à´¾à´‚, à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† à´¸àµà´°à´•àµà´·à´¯àµà´‚ à´¸àµà´µà´•à´¾à´°àµà´¯à´¤à´¯àµà´‚ à´…à´ªàµà´°à´¤àµ€à´•àµà´·à´¿à´¤à´®à´¾à´¯ രീതിയിൽ തകരാറിലായേകàµà´•à´¾à´‚. നിങàµà´™àµ¾ à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•àµà´¨àµà´¨ à´à´¤àµ പരീകàµà´·à´£à´™àµà´™à´³àµà´‚ à´ˆ à´¬àµà´°àµ—സറിനàµà´±àµ† à´à´²àµà´²à´¾ ഉപയോകàµà´¤à´¾à´•àµà´•àµ¾à´•àµà´•àµà´®à´¾à´¯à´¿ à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´‚. ദയവായി à´¶àµà´°à´¦àµà´§à´¯àµ‹à´Ÿàµ† à´¤àµà´Ÿà´°àµà´•.</translation>
<translation id="3650584904733503804">മൂലàµà´¯à´¨à´¿àµ¼à´£àµà´£à´¯à´‚ വിജയകരം</translation>
<translation id="3655670868607891010">നിങàµà´™àµ¾ ഇതൠപതിവായി കാണàµà´¨àµà´¨àµà´£àµà´Ÿàµ†à´™àµà´•à´¿àµ½, à´ˆ <ph name="HELP_LINK" /> പരീകàµà´·à´¿à´•àµà´•àµ‚.</translation>
<translation id="3658742229777143148">à´ªàµà´¨à´°à´µà´²àµ‹à´•à´¨à´‚</translation>
+<translation id="3678029195006412963">à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ സൈൻ à´àµ†à´¯àµà´¯à´¾à´¨à´¾à´¯à´¿à´²àµà´²</translation>
<translation id="3681007416295224113">സരàµâ€â€Œà´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ വിവരങàµà´™à´³àµâ€â€Œ</translation>
<translation id="3693415264595406141">പാസàµâ€Œà´µàµ‡à´¡àµ:</translation>
+<translation id="3696411085566228381">à´’à´¨àµà´¨àµà´®à´¿à´²àµà´²</translation>
<translation id="3700528541715530410">à´•àµà´·à´®à´¿à´•àµà´•à´£à´‚, à´ˆ പേജൠആകàµâ€Œà´¸à´¸àµà´¸àµà´àµ†à´¯àµà´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ നിങàµà´™àµ¾à´•àµà´•àµ à´…à´¨àµà´®à´¤à´¿à´¯à´¿à´²àµà´²àµ†à´¨àµà´¨àµ തോനàµà´¨àµà´¨àµà´¨àµ.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">ലോഡàµà´àµ†à´¯àµà´¯àµà´¨àµà´¨àµ...</translation>
@@ -263,7 +272,6 @@
<translation id="3714780639079136834">à´®àµà´¬àµˆàµ½ ഡാറàµà´± à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ Wi-Fi ഓണാകàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿à´¯àµà´‚ ഫയർവാളàµà´‚ DNS കോൺഫിഗറേഷനàµà´‚ പരിശോധികàµà´•àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">നിങàµà´™àµ¾ പകർതàµà´¤à´¿à´¯ ലിങàµà´•àµ</translation>
-<translation id="3744899669254331632">Chromium-നൠപàµà´°àµ‹à´¸à´¸àµà´¸àµà´àµ†à´¯àµà´¯à´¾à´¨à´¾à´•à´¾à´¤àµà´¤ രൂപമാറàµà´±à´‚ വരàµà´¤àµà´¤à´¿à´¯ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´•àµ¾ വെബàµà´¸àµˆà´±àµà´±àµ അയയàµà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´². നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¤à´¿à´¨à´¾àµ½ à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´‚.</translation>
<translation id="375403751935624634">ഒരൠസെരàµâ€à´µà´°àµâ€ പിശകൠകാരണം വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
<translation id="3759461132968374835">നിങàµà´™à´³àµâ€à´•àµà´•àµ സമീപകാലതàµà´¤àµ റിപàµà´ªàµ‹à´°àµâ€à´Ÿàµà´Ÿàµà´àµ†à´¯àµà´¤ à´•àµà´°à´¾à´·àµà´•à´³àµà´¨àµà´¨àµà´®à´¿à´²àµà´². à´•àµà´°à´¾à´·àµ റിപàµà´ªàµ‹à´°àµâ€à´Ÿàµà´Ÿàµà´àµ†à´¯àµà´¯àµà´¨àµà´¨ സമയതàµà´¤àµ സംഭവിà´àµà´ à´•àµà´°à´¾à´·àµà´•à´³àµ† à´…à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•à´¿, ഇവിടെ ദൃശàµà´¯à´®à´¾à´•à´¿à´²àµà´².</translation>
<translation id="3788090790273268753">à´ˆ സൈറàµà´±à´¿à´¨à´¾à´¯àµà´³àµà´³ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ 2016-ൽ കാലഹരണപàµà´ªàµ†à´Ÿàµà´‚ à´’à´ªàµà´ªà´‚ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´àµ†à´¯à´¿à´¨à´¿àµ½ SHA-1 ഉപയോഗിà´àµà´àµ സൈൻ à´àµ†à´¯àµâ€Œà´¤ ഒരൠസർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´…à´Ÿà´™àµà´™à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´•à´¯àµà´‚ à´àµ†à´¯àµà´¯àµà´¨àµà´¨àµ.</translation>
@@ -275,19 +283,25 @@
<translation id="3884278016824448484">വിരàµà´¦àµà´§ ഉപകരണ à´à´¡à´¨àµà´±à´¿à´«à´¯àµ¼</translation>
<translation id="3885155851504623709">പാരിഷàµ</translation>
<translation id="3901925938762663762">കാർഡൠകാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
+<translation id="3910267023907260648">നിങàµà´™à´³àµâ€â€Œ <ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¿àµ½ à´à´¤àµà´¤à´¾à´¨àµâ€â€Œ à´¶àµà´°à´®à´¿à´àµà´àµ, പകàµà´·àµ‡ ഒരൠദàµàµ¼à´¬à´²à´®à´¾à´¯ സിഗàµâ€Œà´¨àµ‡à´àµà´à´°àµâ€â€Œ à´…à´²àµâ€â€Œà´—ോരിതം ഉപയോഗിà´àµà´àµ സൈൻ à´àµ†à´¯àµâ€Œà´¤ സരàµâ€â€Œà´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¾à´£àµ സെരàµâ€â€Œà´µà´°àµâ€â€Œ നലàµâ€â€Œà´•à´¿à´¯à´¤àµ. ഇതിനരàµâ€â€Œà´¤àµà´¥à´‚ സെരàµâ€â€Œà´µà´°àµâ€â€Œ നലàµâ€â€Œà´•à´¿à´¯ à´¸àµà´°à´•àµà´·à´¾ à´•àµà´°àµ†à´¡à´¨àµâ€â€Œà´·àµà´¯à´²àµà´•à´³àµâ€â€Œ à´µàµà´¯à´¾à´œà´®à´¾à´•à´¾à´®àµ†à´¨àµà´¨àµà´‚ സെരàµâ€â€Œà´µà´°àµâ€â€Œ നിങàµà´™à´³àµâ€â€Œ à´ªàµà´°à´¤àµ€à´•àµà´·à´¿à´àµà´ സെരàµâ€â€Œà´µà´±à´¾à´¯à´¿à´°à´¿à´•àµà´•à´¿à´²àµà´²àµ†à´¨àµà´¨àµà´®à´¾à´£àµ (നിങàµà´™à´³àµâ€â€Œ ആകàµà´°à´®à´£à´•à´¾à´°à´¿à´¯àµà´®à´¾à´¯à´¿à´Ÿàµà´Ÿà´¾à´•à´¾à´‚ ആശയവിനിമയം നടതàµà´¤àµà´¨àµà´¨à´¤àµ). <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ഇനàµà´¨à´²àµ† à´®àµà´¤àµ½ സാധàµà´µà´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.}other{à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ # ദിവസം à´®àµà´¤àµ½ സാധàµà´µà´¾à´¯à´¿à´°à´¿à´•àµà´•à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF à´ªàµà´°à´®à´¾à´£à´‚ ലോഡàµà´àµ†à´¯àµà´¯àµà´¨àµà´¨à´¤àµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="3963721102035795474">റീഡർ മോഡàµ</translation>
+<translation id="397105322502079400">കണകàµà´•à´¾à´•àµà´•àµà´¨àµà´¨àµ...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> à´¬àµà´²àµ‹à´•àµà´•àµà´àµ†à´¯àµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{സമീപതàµà´¤àµ ഒരൠവെബàµâ€Œà´ªàµ‡à´œàµà´£àµà´Ÿàµ}other{സമീപതàµà´¤àµ # വെബàµâ€Œà´ªàµ‡à´œàµà´•à´³àµà´£àµà´Ÿàµ}}</translation>
<translation id="4021036232240155012">ഒരൠവെബàµâ€Œà´¸àµˆà´±àµà´±à´¿à´¨àµà´±àµ† പേരൠഅതിനàµà´±àµ† ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ വിലാസതàµà´¤à´¿à´²àµ‡à´•àµà´•àµ വിവർതàµà´¤à´¨à´‚ à´àµ†à´¯àµà´¯àµà´¨àµà´¨ നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ സേവനമാണൠDNS.</translation>
<translation id="4030383055268325496">&amp;à´àµ‡àµ¼à´•àµà´•àµà´¨àµà´¨à´¤àµ പഴയപടിയാകàµà´•àµà´•</translation>
-<translation id="4032534284272647190"><ph name="URL" /> à´à´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµ ആകàµà´¸à´¸àµà´¸àµ നിരസിà´àµà´àµ.</translation>
<translation id="404928562651467259">à´®àµà´¨àµà´¨à´±à´¿à´¯à´¿à´ªàµà´ªàµ</translation>
<translation id="4058922952496707368">കീ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">ഒരൠസാധാരണ SSL à´ªàµà´°àµ‹à´Ÿàµà´Ÿàµ‹à´•àµà´•àµ‹àµ¾ പതിപàµà´ªà´¿à´¨àµ†à´¯àµ‹ സൈഫർ à´¸àµà´¯àµ‚à´Ÿàµà´Ÿà´¿à´¨àµ†à´¯àµ‹ à´•àµà´²à´¯à´¨àµà´±àµà´‚ സെർവറàµà´‚ പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•à´¿à´²àµà´².</translation>
<translation id="4079302484614802869">à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ കോൺഫിഗറേഷൻ .pac à´¸àµâ€Œà´•àµà´°à´¿à´ªàµà´±àµà´±àµ URL ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´¿ സജàµà´œàµ€à´•à´°à´¿à´àµà´à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, à´¸àµà´¥à´¿à´°à´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സെർവറàµà´•àµ¾ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´²àµà´².</translation>
<translation id="4103249731201008433">ഉപകരണ സീരിയൽ നമàµà´ªàµ¼ അസാധàµà´µà´¾à´£àµ</translation>
<translation id="4103763322291513355">à´¬àµà´²à´¾à´•àµà´•àµâ€Œà´²à´¿à´¸àµà´±àµà´±à´¿àµ½à´ªàµà´ªàµ†à´Ÿàµà´Ÿ URL-à´•à´³àµà´Ÿàµ† ലിസàµà´±àµà´±àµà´‚ നിങàµà´™à´³àµà´Ÿàµ† സിസàµà´±àµà´±à´‚ à´…à´¡àµâ€Œà´®à´¿à´¨à´¿à´¸àµâ€Œà´Ÿàµà´°àµ‡à´±àµà´±àµ¼ നടപàµà´ªà´¿à´²à´¾à´•àµà´•à´¿à´¯ മറàµà´±àµ നയങàµà´™à´³àµà´‚ കാണàµà´¨àµà´¨à´¤à´¿à´¨àµ &lt;strong&gt;chrome://policy&lt;/strong&gt; സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´•.</translation>
+<translation id="4110615724604346410">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿àµ½ പിശകàµà´•à´³àµà´£àµà´Ÿàµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">നയ à´¸àµâ€Œà´•àµ‹à´ªàµà´ªàµ പിനàµà´¤àµà´£à´¯àµà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´².</translation>
+<translation id="4118212371799607889">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† Chromium വിശàµà´µà´¸à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{മറàµà´±àµà´°àµ†à´£àµà´£à´‚}other{മറàµà´±àµ # à´à´£àµà´£à´‚}}</translation>
<translation id="4130226655945681476">നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ കേബിളàµà´•à´³àµà´‚ മോഡവàµà´‚ റൂടàµà´Ÿà´±àµà´‚ പരിശോധികàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromium à´ˆ കാർഡൠസംരകàµà´·à´¿à´•àµà´•à´£àµ‹?</translation>
@@ -295,6 +309,7 @@
<translation id="4176463684765177261">à´…à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•à´¿</translation>
<translation id="4196861286325780578">&amp;നീകàµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ à´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ഫയർവാളàµà´‚ ആനàµà´±à´¿à´µàµˆà´±à´¸àµ കോൺഫിഗറേഷനàµà´•à´³àµà´‚ പരിശോധികàµà´•àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{à´’à´¨àµà´¨àµà´®à´¿à´²àµà´²}=1{ഒരൠആപàµà´ªàµ ($1)}=2{2 ആപàµâ€Œà´¸àµ ($1, $2)}other{# ആപàµâ€Œà´¸àµ ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">à´•àµà´°à´¾à´·àµà´•à´³àµâ€</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ à´àµ†à´¯àµâ€Œà´¤àµà´¨àµ‹à´•àµà´•àµ‚<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">ഇലàµà´²</translation>
@@ -303,14 +318,15 @@
<translation id="4269787794583293679">(ഉപയോകàµà´¤àµƒà´¨à´¾à´®à´®à´¿à´²àµà´²)</translation>
<translation id="4300246636397505754">പാരനàµà´±àµ നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾</translation>
<translation id="4304224509867189079">ലോഗൠഇനàµâ€ à´àµ†à´¯àµà´¯àµà´•</translation>
+<translation id="432290197980158659">സെർവർ നൽകിയ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´…à´¨àµà´¤àµ¼à´¨à´¿àµ¼à´®àµà´®à´¿à´¤ ആവശàµà´¯à´•à´¤à´•à´³àµà´®à´¾à´¯à´¿ യോജികàµà´•àµà´¨àµà´¨à´¿à´²àµà´². നിങàµà´™à´³àµ† പരിരകàµà´·à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´¿ ഉയർനàµà´¨ à´¸àµà´°à´•àµà´·à´¯àµà´³àµà´³ à´à´¿à´² വെബàµà´¸àµˆà´±àµà´±àµà´•àµ¾à´•àµà´•à´¾à´¯à´¾à´£àµ à´ˆ ആവശàµà´¯à´•à´¤à´•à´³àµ† ഉൾപàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">ലേഖനം à´•à´£àµà´Ÿàµ†à´¤àµà´¤àµà´¨àµà´¨à´¤àµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
+<translation id="4331708818696583467">à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²</translation>
<translation id="4372948949327679948">à´ªàµà´°à´¤àµ€à´•àµà´·à´¿à´àµà´ <ph name="VALUE_TYPE" /> മൂലàµà´¯à´‚.</translation>
-<translation id="4377125064752653719">നിങàµà´™à´³àµâ€â€Œ <ph name="DOMAIN" /> à´à´¨àµà´¨à´¤à´¿à´²àµâ€â€Œ à´à´¤àµà´¤à´¾à´¨àµâ€â€Œ à´¶àµà´°à´®à´¿à´àµà´àµ, പകàµà´·àµ‡ സെരàµâ€â€Œà´µà´°àµâ€â€Œ നൽകിയ സരàµâ€â€Œà´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ അതൠനലàµâ€â€Œà´•à´¿à´¯ ആളàµâ€â€Œ അസാധàµà´µà´¾à´•àµà´•à´¿. സെരàµâ€â€Œà´µà´°àµâ€â€Œ നലàµâ€â€Œà´•à´¿à´¯ à´¸àµà´°à´•àµà´·à´¾ à´•àµà´°àµ†à´¡à´¨àµâ€â€Œà´·àµà´¯à´²àµà´•à´³àµâ€â€Œ തികà´àµà´àµà´‚ വിശàµà´µà´¾â€à´¸à´¯àµ‹à´—àµà´¯à´®à´²àµà´² à´à´¨àµà´¨à´¾à´£àµ ഇതിനരàµâ€â€Œà´¤àµà´¥à´‚. നിങàµà´™à´³àµâ€â€Œ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿à´¯àµà´®à´¾à´¯à´¿à´Ÿàµà´Ÿà´¾à´•à´¾à´‚ ആശയവിനിമയം നടതàµà´¤àµà´¨àµà´¨à´¤àµ.</translation>
<translation id="4381091992796011497">ഉപയോകàµà´¤àµƒ നാമം:</translation>
<translation id="4394049700291259645">à´…à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•àµà´•</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> à´®àµà´¤àµ½ <ph name="END_DATE" /> വരെ</translation>
<translation id="4406896451731180161">തിരയൽ ഫലങàµà´™àµ¾</translation>
-<translation id="4424024547088906515">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ Chrome-നൠപരിà´à´¯à´®à´¿à´²àµà´²à´¾à´¤àµà´¤à´¤à´¾à´£àµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" />, നിങàµà´™à´³àµà´Ÿàµ† ലോഗിൻ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ അംഗീകരിà´àµà´à´¿à´Ÿàµà´Ÿà´¿à´²àµà´², à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ à´…à´™àµà´™à´¨àµ†à´¯àµà´°àµ†à´£àµà´£à´‚ നൽകിയിടàµà´Ÿà´¿à´²àµà´²à´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚.</translation>
<translation id="443673843213245140">à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ ഉപയോഗം à´…à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•à´¿ പകàµà´·àµ† ഒരൠവàµà´¯à´•àµà´¤à´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ കോൺഫിഗറേഷൻ നിർദàµà´¦àµ‡à´¶à´¿à´àµà´àµ.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Google SafeSites à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´®à´¾à´•àµà´•à´¿à´¯à´¤à´¿à´¨à´¾à´²à´¾à´£àµ à´ˆ സനàµà´¦àµ‡à´¶à´‚ കാണàµà´¨àµà´¨à´¤àµ.</translation>
@@ -322,12 +338,12 @@
<translation id="4522570452068850558">വിശദാംശങàµà´™àµ¾â€Œ</translation>
<translation id="4558551763791394412">നിങàµà´™à´³àµà´Ÿàµ† വിപàµà´²àµ€à´•à´°à´£à´™àµà´™àµ¾ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´•àµà´•àµà´¨àµà´¨à´¤àµ പരീകàµà´·à´¿à´•àµà´•àµà´•.</translation>
<translation id="4587425331216688090">Chrome-ൽ നിനàµà´¨àµ വിലാസം നീകàµà´•à´‚à´àµ†à´¯àµà´¯à´£àµ‹?</translation>
+<translation id="4589078953350245614">നിങàµà´™àµ¾ <ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¿àµ½ à´à´¤àµà´¤à´¾àµ» à´¶àµà´°à´®à´¿à´àµà´àµ†à´™àµà´•à´¿à´²àµà´‚ സെർവർ അസാധàµà´µà´¾à´¯ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¾à´£àµ നൽകിയതàµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459"><ph name="DOMAIN" /> à´à´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† ആധàµà´¨à´¿à´• സൈഫർ à´¸àµà´¯àµ‚à´Ÿàµà´Ÿàµ ഉപയോഗിà´àµà´àµ à´àµ»à´•àµà´°à´¿à´ªàµà´±àµà´±àµà´àµ†à´¯àµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="4594403342090139922">&amp;ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµà´¨àµà´¨à´¤àµ പഴയപടിയാകàµà´•àµà´•</translation>
+<translation id="4627442949885028695">മറàµà´±àµà´°àµ ഉപകരണതàµà´¤à´¿àµ½ നിനàµà´¨àµ à´¤àµà´Ÿà´°àµà´•</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">നിങàµà´™àµ¾ വിപàµà´²àµ€à´•à´°à´£ പേജാണൠകാണàµà´¨àµà´¨à´¤àµ.</translation>
-<translation id="467662567472608290">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿àµ½ പിശകàµà´•àµ¾ à´…à´Ÿà´™àµà´™à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> à´à´¨àµà´¨à´¤à´¿à´¨àµ† തടà´àµà´à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·àµ» തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ à´àµ†à´¯àµà´¯àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
@@ -335,21 +351,26 @@
<translation id="4728558894243024398">à´ªàµà´²à´¾à´±àµà´±àµà´«àµ‹à´‚</translation>
<translation id="4744603770635761495">നിരàµâ€à´µàµà´µà´¹à´¿à´•àµà´•à´¾à´µàµà´¨àµà´¨ പാത</translation>
<translation id="4756388243121344051">&amp;à´à´°à´¿à´¤àµà´°à´‚</translation>
+<translation id="4759238208242260848">ഡൌണàµâ€à´²àµ‹à´¡àµà´•à´³àµâ€</translation>
<translation id="4764776831041365478"><ph name="URL" /> ലെ വെബàµâ€Œà´ªàµ‡à´œàµ താലàµâ€â€Œà´•àµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¿ à´ªàµà´°à´µà´°àµâ€â€Œà´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚, à´…à´²àµà´²àµ†à´™àµà´•à´¿à´²àµâ€â€Œ ഒരൠപàµà´¤à´¿à´¯ വെബൠവിലാസതàµà´¤à´¿à´²àµ‡à´•àµà´•àµ ശാശàµà´µà´¤à´®à´¾à´¯à´¿ നീകàµà´•à´‚à´àµ†à´¯àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´Ÿà´¿à´°à´¿à´•àµà´•à´¾à´‚.</translation>
<translation id="4771973620359291008">ഒരൠഅജàµà´à´¾à´¤ പിശകൠസംഭവിà´àµà´àµ.</translation>
<translation id="4782449893814226250">നിങàµà´™à´³àµà´Ÿàµ† à´°à´•àµà´·à´¿à´¤à´¾à´•àµà´•à´³àµ‹à´Ÿàµ à´àµ‹à´¦à´¿à´àµà´àµ à´…à´¨àµà´µà´¾à´¦à´‚ ലഭികàµà´•àµà´•à´¯à´¾à´£àµ†à´™àµà´•à´¿àµ½ à´ˆ പേജൠസനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´•.</translation>
<translation id="4800132727771399293">നിങàµà´™à´³àµà´Ÿàµ† കാലഹരണ തീയതിയàµà´‚ CVC à´¯àµà´‚ പരിശോധിà´àµà´àµ വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•</translation>
-<translation id="4807049035289105102">Google Chrome-നൠപàµà´°àµ‹à´¸à´¸àµà´¸àµà´àµ†à´¯àµà´¯à´¾à´¨à´¾à´•à´¾à´¤àµà´¤ രൂപമാറàµà´±à´‚ വരàµà´¤àµà´¤à´¿à´¯ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´•àµ¾ വെബàµà´¸àµˆà´±àµà´±àµ അയയàµà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´².നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¤à´¿à´¨à´¾àµ½, à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´‚.</translation>
<translation id="4813512666221746211">നെറàµà´±àµâ€Œà´µà´°àµâ€à´•àµà´•àµ പിശകàµ</translation>
<translation id="4816492930507672669">പേജിനൠയàµà´•àµà´¤à´®à´¾à´•àµà´•àµà´•</translation>
<translation id="4850886885716139402">കാണàµà´•</translation>
<translation id="4880827082731008257">തിരയൽ à´à´°à´¿à´¤àµà´°à´‚</translation>
+<translation id="4884656795097055129">ആവശàµà´¯à´®àµà´³àµà´³ സമയതàµà´¤àµ കൂടàµà´¤àµ½ ലേഖനങàµà´™àµ¾ ദൃശàµà´¯à´®à´¾à´•àµà´‚.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{ഒരൠവെബàµâ€Œà´ªàµ‡à´œàµ കൂടിയàµà´£àµà´Ÿàµ}other{# വെബàµâ€Œà´ªàµ‡à´œàµà´•àµ¾ കൂടിയàµà´£àµà´Ÿàµ}}</translation>
<translation id="4923417429809017348">à´ˆ പേജിനെ അറിയപàµà´ªàµ†à´Ÿà´¾à´¤àµà´¤ ഒരൠഭാഷയിലàµâ€â€Œ നിനàµà´¨àµà´‚ <ph name="LANGUAGE_LANGUAGE" /> à´à´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµ വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ à´àµ†à´¯àµà´¤àµ</translation>
<translation id="4926049483395192435">à´µàµà´¯à´•àµà´¤à´®à´¾à´•àµà´•àµ‡à´£àµà´Ÿà´¤à´¾à´£àµ.</translation>
<translation id="4930497775425430760">à´ªàµà´¤à´¿à´¯ സൈറàµà´±àµà´•à´³à´¿àµ½ ആദàµà´¯à´®à´¾à´¯à´¿ പോകàµà´®àµà´ªàµ‹àµ¾ അവയàµâ€Œà´•àµà´•àµ à´°à´•àµà´·à´¿à´¤à´¾à´µà´¿à´¨àµà´±àµ† അംഗീകാരം ആവശàµà´¯à´®à´¾à´¯à´¤à´¿à´¨à´¾à´²à´¾à´£àµ à´ˆ സനàµà´¦àµ‡à´¶à´‚ കാണàµà´¨àµà´¨à´¤àµ.</translation>
<translation id="495170559598752135">à´ªàµà´°à´µà´°àµâ€à´¤àµà´¤à´¨à´™àµà´™à´³àµâ€</translation>
<translation id="4958444002117714549">ലിസàµà´±àµà´±àµ വിപàµà´²àµ€à´•à´°à´¿à´•àµà´•àµà´•</translation>
+<translation id="4962322354953122629">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† Chrome വിശàµà´µà´¸à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911"><ph name="ORIGINAL_LANGUAGE" />-ൽ നിനàµà´¨àµ <ph name="TARGET_LANGUAGE" />-ലേകàµà´•àµ വിവർതàµà´¤à´¨à´‚ à´àµ†à´¯àµà´¯à´£àµ‹?</translation>
+<translation id="4989809363548539747">à´ˆ à´ªàµà´²à´—ിൻ പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
<translation id="5002932099480077015">à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´®à´¾à´•àµà´•à´¿à´¯àµ†à´™àµà´•à´¿àµ½, വേഗതàµà´¤à´¿àµ½ ഫോം പൂരിപàµà´ªà´¿à´•àµà´•à´¾àµ» Chrome à´ˆ ഉപകരണതàµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† കാർഡിനàµà´±àµ† ഒരൠപകർപàµà´ªàµ സൂകàµà´·à´¿à´•àµà´•àµà´‚.</translation>
<translation id="5019198164206649151">ബാകàµà´•à´¿à´‚ഗൠസംഭരണം മോശം അവസàµà´¥à´¯à´¿à´²à´¾à´£àµ</translation>
<translation id="5023310440958281426">നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿à´¨à´¿à´¸àµà´Ÿàµà´°àµ‡à´±àµà´±à´±àµà´Ÿàµ† നയങàµà´™àµ¾ പരിശോധികàµà´•àµà´•</translation>
@@ -357,13 +378,12 @@
<translation id="5031870354684148875">Google വിവരàµâ€à´¤àµà´¤à´¨à´‚ à´à´¨àµà´¨à´¤à´¿à´¨àµ†à´•àµà´•àµà´±à´¿à´àµà´àµ </translation>
<translation id="5040262127954254034">à´¸àµà´µà´•à´¾à´°àµà´¯à´¤</translation>
<translation id="5045550434625856497">ശരിയലàµà´²à´¾à´¤àµà´¤ രഹസàµà´¯à´µà´¾à´•àµà´•àµ</translation>
+<translation id="5056549851600133418">നിങàµà´™àµ¾à´•àµà´•àµà´³àµà´³ ലേഖനങàµà´™àµ¾</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ വിലാസം പരിശോധികàµà´•àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">സെർവറിനàµà´±àµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ ഇപàµà´ªàµ‹àµ¾ സാധàµà´¤à´¯à´¿à´²àµà´².</translation>
<translation id="5089810972385038852">à´¸àµà´±àµà´±àµ‡à´±àµà´±àµ</translation>
-<translation id="5094747076828555589">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´· സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† Chromium-à´¤àµà´¤à´¿à´¨àµà´¨àµ പരിà´à´¯à´®à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.</translation>
<translation id="5095208057601539847">à´ªàµà´°à´µà´¿à´¶àµà´¯</translation>
<translation id="5115563688576182185">(64-ബിറàµà´±àµ)</translation>
-<translation id="5122371513570456792">'<ph name="SEARCH_STRING" />' à´à´¨àµà´¨à´¤à´¿à´¨àµà´³àµà´³ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿.</translation>
<translation id="5141240743006678641">Google à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´•àµ¾ ഉപയോഗിà´àµà´àµ സമനàµà´µà´¿à´¤ പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾ à´àµ»à´•àµà´°à´¿à´ªàµà´±àµà´±àµà´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="5145883236150621069">നയ à´ªàµà´°à´¤à´¿à´•à´°à´£à´¤àµà´¤à´¿àµ½ പിശകൠകോഡൠഉണàµà´Ÿàµ</translation>
<translation id="5171045022955879922">തിരയàµà´• à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ URL ടൈപàµà´ªàµà´àµ†à´¯àµà´¯àµà´•</translation>
@@ -372,18 +392,18 @@
<translation id="5190835502935405962">à´¬àµà´•àµà´•àµâ€Œà´®à´¾à´°àµâ€â€Œà´•àµà´•àµà´•à´³àµâ€â€Œ ബാരàµâ€â€Œ</translation>
<translation id="5199729219167945352">പരീകàµà´·à´£à´™àµà´™à´³àµâ€</translation>
<translation id="5251803541071282808">à´•àµà´²àµ—à´¡àµ</translation>
+<translation id="5277279256032773186">ജോലിസàµà´¥à´²à´¤àµà´¤àµà´³àµà´³ Chrome ഉപയോഗികàµà´•àµà´•à´¯à´¾à´£àµ‹? ബിസിനസൠസàµà´¥à´¾à´ªà´¨à´™àµà´™àµ¾à´•àµà´•àµ അവരàµà´Ÿàµ† ജീവനകàµà´•à´¾àµ¼à´•àµà´•àµ വേണàµà´Ÿà´¿ Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´‚ മാനേജàµà´àµ†à´¯àµà´¯à´¾à´¨à´¾à´•àµà´‚. കൂടàµà´¤à´²à´±à´¿à´¯àµà´•</translation>
<translation id="5299298092464848405">നയം പാഴàµâ€Œà´¸àµà´àµ†à´¯àµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ പിശകàµ</translation>
<translation id="5300589172476337783">കാണികàµà´•àµà´•</translation>
<translation id="5308689395849655368">à´•àµà´°à´¾à´·àµ റിപàµà´ªàµ‹à´°àµâ€à´Ÿàµà´Ÿàµà´àµ†à´¯àµà´¯à´²àµâ€ à´…à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•à´¿.</translation>
<translation id="5317780077021120954">സംരകàµà´·à´¿à´•àµà´•àµà´•</translation>
<translation id="5327248766486351172">പേരàµ</translation>
+<translation id="5359637492792381994">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ഇപàµà´ªàµ‹àµ¾ സാധàµà´µà´¾à´¯à´¤à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">നയ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ സംഭരികàµà´•àµà´¨àµà´¨à´¤à´¿àµ½ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
-<translation id="540969355065856584">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´· സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ ഇപàµà´ªàµ‹àµ¾ സാധàµà´¤à´¯àµà´³àµà´³à´¤à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.</translation>
-<translation id="5421136146218899937">à´¬àµà´°àµŒà´¸à´¿à´‚ഗൠഡാറàµà´±à´¾ മായàµâ€Œà´•àµà´•àµà´¨àµà´¨àµ</translation>
+<translation id="5421136146218899937">à´¬àµà´°àµ—സിംഗൠഡാറàµà´± മായàµâ€Œà´•àµà´•àµà´•...</translation>
<translation id="5430298929874300616">à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµ നീകàµà´•à´‚à´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="5431657950005405462">നിങàµà´™à´³àµà´Ÿàµ† ഫയൽ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´²</translation>
<translation id="5435775191620395718">à´ˆ ഉപകരണതàµà´¤à´¿àµ½ നിനàµà´¨àµà´³àµà´³ à´à´°à´¿à´¤àµà´°à´‚ കാണികàµà´•àµà´¨àµà´¨àµ. <ph name="BEGIN_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">നിങàµà´™à´³àµà´Ÿàµ† സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´àµà´ വിവരങàµà´™à´³àµ† ഒരൠഇഷàµâ€Œà´Ÿà´¾à´¨àµà´¸àµƒà´¤ പാസàµâ€Œà´«àµà´°àµ†à´¯àµâ€Œà´¸àµ ഉപയോഗിà´àµà´àµ പരിരകàµà´·à´¿à´àµà´à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½, à´µàµà´¯à´•àµà´¤à´¿à´ªà´°à´®à´¾à´•àµà´•à´¿à´¯ ഉളàµà´³à´Ÿà´•àµà´• നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾ നിലവിൽ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´•à´¯à´¾à´£àµ.</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" à´à´¨àµà´¨à´¤à´¿àµ½ à´¸àµâ€Œà´•àµ€à´® മൂലàµà´²àµà´¯à´¨à´¿àµ¼à´£àµà´£à´¯ പിശകàµ: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">à´ˆ <ph name="HOST_NAME" /> പേജൠകണàµà´Ÿàµ†à´¤àµà´¤à´¾à´¨à´¾à´¯à´¿à´²àµà´²</translation>
<translation id="5455374756549232013">മോശം നയ ടൈംസàµà´±àµà´±à´¾à´®àµà´ªàµ</translation>
@@ -406,14 +426,18 @@
<translation id="5622887735448669177">നിങàµà´™àµ¾à´•àµà´•àµ à´ˆ സൈറàµà´±àµ വിടണോ?</translation>
<translation id="5629630648637658800">നയ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ ലോഡàµà´àµ†à´¯àµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="5631439013527180824">ഉപകരണ മാനേജàµà´®àµ†à´¨àµà´±àµ ടോകàµà´•àµº അസാധàµà´µà´¾à´£àµ</translation>
-<translation id="5650551054760837876">തിരയൽ ഫലങàµà´™à´³àµâ€ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´².</translation>
<translation id="5677928146339483299">തടà´àµà´àµ</translation>
<translation id="5710435578057952990">à´ˆ വെബàµà´¸àµˆà´±àµà´±à´¿à´¨àµà´±àµ† à´µàµà´¯à´•àµà´¤à´¿à´¤àµà´µà´‚ പരിശോധിà´àµà´à´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
<translation id="5720705177508910913">നിലവിലെ ഉപയോകàµà´¤à´¾à´µàµ</translation>
+<translation id="572328651809341494">à´…à´Ÿàµà´¤àµà´¤à´¿à´Ÿàµ†à´¯àµà´³àµà´³ ടാബàµà´•àµ¾</translation>
<translation id="5784606427469807560">നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠസàµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿àµ½ à´ªàµà´°à´¶àµâ€Œà´¨à´®àµà´£àµà´Ÿà´¾à´¯à´¿. ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ കണകàµà´·àµ» പരിശോധിà´àµà´àµ, വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
<translation id="5785756445106461925">കൂടാതെ, à´ˆ പേജിൽ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²à´¾à´¤àµà´¤ മറàµà´±àµ ഉറവിടങàµà´™àµ¾ ഉൾപàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ. à´ˆ ഉറവിടങàµà´™àµ¾ കൈമാറàµà´¨àµà´¨à´¤à´¿à´¨à´¿à´Ÿàµ† മറàµà´±àµà´³àµà´³à´µàµ¼à´•àµà´•àµ കാണാനàµà´‚ പേജിനàµà´±àµ† രൂപം മാറàµà´±àµà´¨àµà´¨ തരതàµà´¤à´¿àµ½ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿à´¯àµâ€Œà´•àµà´•àµ പരിഷàµâ€Œà´•àµà´•à´°à´¿à´•àµà´•à´¾à´¨àµà´®à´¾à´¯àµ‡à´•àµà´•àµà´‚.</translation>
+<translation id="5786044859038896871">നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠവിവരം പൂരിപàµà´ªà´¿à´•àµà´•à´£àµ‹?</translation>
+<translation id="5803412860119678065">നിങàµà´™à´³àµà´Ÿàµ† <ph name="CARD_DETAIL" /> പൂരിപàµà´ªà´¿à´•àµà´•à´£àµ‹?</translation>
<translation id="5810442152076338065"><ph name="DOMAIN" /> à´à´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·àµ» കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿ സൈഫർ à´¸àµà´¯àµ‚à´Ÿàµà´Ÿàµ ഉപയോഗിà´àµà´àµ à´àµ»à´•àµà´°à´¿à´ªàµà´±àµà´±àµà´àµ†à´¯àµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="5813119285467412249">&amp;à´àµ‡àµ¼à´•àµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ à´àµ†à´¯àµà´¯àµà´•</translation>
+<translation id="5814352347845180253">നിങàµà´™àµ¾à´•àµà´•àµ, <ph name="SITE" /> സൈറàµà´±à´¿àµ½ നിനàµà´¨àµà´‚ മറàµà´±àµà´¸àµˆà´±àµà´±àµà´•à´³à´¿àµ½ നിനàµà´¨àµà´®àµà´³àµà´³ à´ªàµà´°àµ€à´®à´¿à´¯à´‚ ഉളàµà´³à´Ÿà´•àµà´•à´¤àµà´¤à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ ആകàµâ€Œà´¸à´¸àµ നഷàµâ€Œà´Ÿà´®à´¾à´¯àµ‡à´•àµà´•à´¾à´‚.</translation>
+<translation id="5843436854350372569">നിങàµà´™à´³àµâ€â€Œ <ph name="DOMAIN" /> à´à´¨àµà´¨à´¤à´¿à´²àµâ€ à´à´¤àµà´¤à´¾à´¨àµâ€â€Œ à´¶àµà´°à´®à´¿à´àµà´àµ, പകàµà´·àµ† സെർവർ ഹാജരാകàµà´•à´¿à´¯ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿àµ½ à´¦àµàµ¼à´¬à´²à´®à´¾à´¯ കീ ഉൾപàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ. ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ à´¸àµà´µà´•à´¾à´°àµà´¯ കീ നശിപàµà´ªà´¿à´àµà´à´¿à´°à´¿à´•àµà´•à´¾à´‚, കൂടാതെ സെർവർ നിങàµà´™àµ¾ à´ªàµà´°à´¤àµ€à´•àµà´·à´¿à´àµà´ സെർവർ ആയിരികàµà´•à´¿à´²àµà´² (നിങàµà´™àµ¾ ആശയവിനിമയം നടതàµà´¤àµà´¨àµà´¨à´¤àµ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿à´¯àµà´®à´¾à´¯à´¿à´Ÿàµà´Ÿà´¾à´•à´¾à´‚). <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">നിങàµà´™à´³àµà´Ÿàµ† മാനേജർ à´ˆ സൈറàµà´±àµ à´¬àµà´²àµ‹à´•àµà´•àµà´àµ†à´¯àµâ€Œà´¤à´¤à´¿à´¨à´¾à´²à´¾à´£àµ à´ˆ സനàµà´¦àµ‡à´¶à´‚ കാണàµà´¨àµà´¨à´¤àµ.</translation>
<translation id="5857090052475505287">à´ªàµà´¤à´¿à´¯ ഫോളàµâ€à´¡à´°àµâ€</translation>
<translation id="5869405914158311789">à´ˆ സൈറàµà´±àµ ലഭàµà´¯à´®à´¾à´•àµà´•à´¾à´¨à´¾à´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
@@ -421,6 +445,7 @@
<translation id="5872918882028971132">പാരനàµà´±àµ നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾</translation>
<translation id="59107663811261420">à´ˆ à´µàµà´¯à´¾à´ªà´°à´¿à´¯àµâ€Œà´•àµà´•à´¾à´¯à´¿ à´ˆ തരതàµà´¤à´¿à´²àµà´³àµà´³ കാർഡൠGoogle പേയàµâ€Œà´®àµ†à´¨àµà´±àµ പിനàµà´¤àµà´£à´¯àµà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². മറàµà´±àµà´°àµ കാർഡൠതിരà´àµà´àµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="59174027418879706">à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•à´¿</translation>
+<translation id="5926846154125914413">നിങàµà´™àµ¾à´•àµà´•àµ à´à´¿à´² സൈറàµà´±àµà´•à´³à´¿àµ½ നിനàµà´¨àµà´³àµà´³ à´ªàµà´°àµ€à´®à´¿à´¯à´‚ ഉളàµà´³à´Ÿà´•àµà´•à´¤àµà´¤à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ ആകàµâ€Œà´¸à´¸àµ നഷàµâ€Œà´Ÿà´®à´¾à´¯àµ‡à´•àµà´•à´¾à´‚.</translation>
<translation id="5966707198760109579">ആഴàµâ€Œà´</translation>
<translation id="5967867314010545767">à´à´°à´¿à´¤àµà´°à´¤àµà´¤à´¿àµ½ നിനàµà´¨àµà´‚ നീകàµà´•à´‚à´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="5975083100439434680">സൂം ഔടàµà´Ÿàµ</translation>
@@ -432,12 +457,12 @@
<translation id="604124094241169006">à´¸àµà´µà´ªàµà´°àµ‡à´°à´¿à´¤à´‚</translation>
<translation id="6042308850641462728">കൂടàµà´¤àµ½</translation>
<translation id="6060685159320643512">à´¶àµà´°à´¦àµà´§à´¿à´•àµà´•àµ‚, à´ˆ പരീകàµà´·à´£à´™àµà´™à´³àµâ€ പാളിയേകàµà´•à´¾à´‚†</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{à´’à´¨àµà´¨àµà´®à´¿à´²àµà´²}=1{1}other{#}}</translation>
<translation id="6146055958333702838">à´à´²àµà´²à´¾ കേബിളàµà´•à´³àµà´‚ പരിശോധികàµà´•àµà´• à´’à´ªàµà´ªà´‚ à´à´¤àµ†à´™àµà´•à´¿à´²àµà´‚ റൂടàµà´Ÿà´±àµà´•àµ¾, മോഡങàµà´™àµ¾ നിങàµà´™àµ¾ ഉപയോഗികàµà´•à´¾à´¨à´¿à´Ÿà´¯àµà´³àµà´³
മറàµà´±àµ നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഉപകരണങàµà´™àµ¾ à´à´¨àµà´¨à´¿à´µ റീബൂടàµà´Ÿàµà´àµ†à´¯àµà´¯àµà´•.</translation>
<translation id="614940544461990577">പരീകàµà´·à´¿à´àµà´àµà´¨àµ‹à´•àµà´•àµ‚:</translation>
<translation id="6150607114729249911">à´•àµà´·à´®à´¿à´•àµà´•à´£à´‚! à´ˆ പേജൠസനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾àµ» à´°à´•àµà´·à´¿à´¤à´¾à´•àµà´•àµ¾à´•àµà´•àµ സമàµà´®à´¤à´®à´¾à´£àµ‹à´¯àµ†à´¨àµà´¨àµ à´àµ‹à´¦à´¿à´•àµà´•àµ‡à´£àµà´Ÿà´¤àµà´£àµà´Ÿàµ.</translation>
<translation id="6151417162996330722">സെർവർ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ ദൈർഘàµà´¯à´®àµ‡à´±à´¿à´¯ ഒരൠകാലയളവൠഉണàµà´Ÿàµ.</translation>
-<translation id="6154808779448689242">മടങàµà´™à´¿à´¯ നയ ടോകàµà´•àµº നിലവിലàµà´³àµà´³ ടോകàµà´•à´£àµà´®à´¾à´¯à´¿ à´ªàµà´°àµà´¤àµà´¤à´ªàµà´ªàµ†à´Ÿà´¿à´²àµà´²</translation>
<translation id="6165508094623778733">കൂടàµà´¤àµ½â€ മനസിലാകàµà´•àµà´•</translation>
<translation id="6203231073485539293">നിങàµà´™à´³àµà´Ÿàµ† ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ കണകàµà´·àµ» പരിശോധികàµà´•àµà´•</translation>
<translation id="6218753634732582820">Chromium-à´¤àµà´¤à´¿àµ½ നിനàµà´¨àµ വിലാസം നീകàµà´•à´‚à´àµ†à´¯àµà´¯à´£àµ‹?</translation>
@@ -450,24 +475,30 @@
<translation id="6328639280570009161">നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ à´ªàµà´°à´µà´à´¨à´‚ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´•àµà´•à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´•</translation>
<translation id="6337534724793800597">പേരിനàµà´±àµ† à´•àµà´°à´®à´¤àµà´¤à´¿àµ½ നയങàµà´™àµ¾ ഫിൽടàµà´Ÿàµ¼ à´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="6342069812937806050">ഇപàµà´ªàµ‹à´³àµâ€â€Œ</translation>
+<translation id="6345221851280129312">വലàµà´ªàµà´ªà´‚ à´à´¤àµà´°à´¯à´¾à´£àµ†à´¨àµà´¨àµ അറിയിലàµà´²</translation>
<translation id="6355080345576803305">à´ªàµà´¤àµ സെഷൻ അസാധàµà´µà´¾à´•àµà´•à´¿</translation>
<translation id="6358450015545214790">ഇതൠഅരàµâ€à´¤àµà´¥à´®à´¾à´•àµà´•àµà´¨àµà´¨à´¤àµ†à´¨àµà´¤à´¾à´£àµ?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{മറàµà´±àµà´°àµ നിർദàµà´¦àµ‡à´¶à´‚}other{മറàµà´±àµ # നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾}}</translation>
<translation id="6387478394221739770">Chrome-à´¨àµà´±àµ† രസകരമായ à´ªàµà´¤à´¿à´¯ സവിശേഷതകളിൽ താൽപàµà´ªà´°àµà´¯à´®àµà´£àµà´Ÿàµ‹? chrome.com/beta-യിൽ à´à´™àµà´™à´³àµà´Ÿàµ† ബീറàµà´± à´à´¾à´¨àµ½ പരീകàµà´·à´¿à´•àµà´•àµà´•.</translation>
-<translation id="641480858134062906"><ph name="URL" /> ലോഡàµà´àµ†à´¯àµà´¯à´²àµâ€ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
+<translation id="6389758589412724634">à´ˆ വെബàµâ€Œà´ªàµ‡à´œàµ à´ªàµà´°à´¦àµ¼à´¶à´¿à´ªàµà´ªà´¿à´•àµà´•à´¾àµ» à´¶àµà´°à´®à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¿à´Ÿà´¯à´¿àµ½ Chromium-à´¤àµà´¤à´¿à´¨àµà´±àµ† മെമàµà´®à´±à´¿ നിറà´àµà´àµ.</translation>
+<translation id="6416403317709441254">Chrome-നൠപàµà´°àµ‹à´¸à´¸àµà´¸àµà´àµ†à´¯àµà´¯à´¾à´¨à´¾à´•à´¾à´¤àµà´¤ രൂപമാറàµà´±à´‚ വരàµà´¤àµà´¤à´¿à´¯ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´•àµ¾ വെബàµà´¸àµˆà´±àµà´±àµ അയയàµâ€Œà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ <ph name="SITE" /> സൈറàµà´±àµ സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´². നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´• à´ªàµà´°à´¶àµâ€Œà´¨à´™àµà´™à´³à´¾à´¯à´¤à´¿à´¨à´¾àµ½ à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´‚. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ അസാധàµà´µà´¾à´•àµà´•à´¿à´¯àµ‹ à´à´¨àµà´¨àµ പരിശോധികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´¿à´²àµà´².</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> കണകàµâ€Œà´±àµà´±àµà´àµ†à´¯àµà´¯àµ½ നിരസിà´àµà´àµ.</translation>
<translation id="6445051938772793705">രാജàµà´¯à´‚</translation>
<translation id="6451458296329894277">വീണàµà´Ÿàµà´‚ സമരàµâ€à´ªàµà´ªà´¿à´•àµà´•à´²àµâ€ അപേകàµà´· ഉറപàµà´ªà´¾à´•àµà´•àµà´•</translation>
<translation id="6458467102616083041">à´¸àµà´¥à´¿à´°à´¸àµà´¥à´¿à´¤à´¿ തിരയൽ നയ à´ªàµà´°à´•à´¾à´°à´‚ ദൃശàµà´¯à´®à´¾à´¯à´¤à´¿à´¨à´¾àµ½ അവഗണികàµà´•à´ªàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
+<translation id="6462969404041126431">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ റദàµà´¦à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">ഉപകരണ നയങàµà´™àµ¾</translation>
<translation id="6489534406876378309">à´•àµà´°à´¾à´·àµà´•àµ¾ à´…à´ªàµâ€Œà´²àµ‹à´¡àµà´àµ†à´¯àµà´¯àµà´¨àµà´¨à´¤àµ ആരംഭികàµà´•àµà´•</translation>
<translation id="6529602333819889595">&amp;ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ à´àµ†à´¯àµà´¯àµà´•</translation>
+<translation id="6534179046333460208">ഫിസികàµà´•àµ½ വെബൠനിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾</translation>
<translation id="6550675742724504774">à´“à´ªàµà´·à´¨àµà´•àµ¾</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" />-യിൽ താഴെ</translation>
<translation id="6596325263575161958">à´àµ»à´•àµà´°à´¿à´ªàµâ€Œà´·àµ» à´“à´ªàµâ€Œà´·à´¨àµà´•àµ¾</translation>
<translation id="662080504995468778">à´¤àµà´Ÿà´°àµà´•</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> തിരയൽ</translation>
-<translation id="6634865548447745291"><ph name="BEGIN_LINK" />à´ˆ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ റദàµà´¦à´¾à´•àµà´•à´¿à´¯à´¤à´¿à´¨à´¾àµ½<ph name="END_LINK" /> നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´². നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¤à´¿à´¨à´¾àµ½ à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•à´¾à´‚.</translation>
<translation id="6644283850729428850">à´ˆ നയം ഒഴിവാകàµà´•à´¿.</translation>
+<translation id="6652240803263749613">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† à´“à´ªàµà´ªà´±àµ‡à´±àµà´±à´¿à´‚ഗൠസിസàµà´±àµà´±à´‚ വിശàµà´µà´¸à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">ഫോൾഡർ à´à´¡à´¿à´±àµà´±àµà´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="6660210980321319655">à´¸àµà´µà´¯à´®àµ‡à´µ റിപàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµà´àµ†à´¯àµâ€Œà´¤à´¤àµ <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Chromium-à´¤àµà´¤à´¿àµ½ നിനàµà´¨àµ ഫോം നിർദàµà´¦àµ‡à´¶à´‚ നീകàµà´•à´‚à´àµ†à´¯àµà´¯à´£àµ‹?</translation>
@@ -475,6 +506,7 @@
<translation id="6710213216561001401">à´•à´´à´¿à´àµà´</translation>
<translation id="6710594484020273272">&lt;തിരയൽ പദം നൽകàµà´•&gt;</translation>
<translation id="6711464428925977395">à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സെർവറിൽ à´à´¨àµà´¤àµ‹ à´ªàµà´°à´¶àµâ€Œà´¨à´®àµà´£àµà´Ÿàµ, à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ വിലാസം തെറàµà´±à´¾à´£àµ.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{à´’à´¨àµà´¨àµà´®à´¿à´²àµà´²}=1{ഒരൠഇനം}other{# ഇനങàµà´™àµ¾}}</translation>
<translation id="674375294223700098">അറിയപàµà´ªàµ†à´Ÿà´¾à´¤àµà´¤ സെരàµâ€à´µà´°àµâ€ സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ പിശകàµ.</translation>
<translation id="6753269504797312559">നയ മൂലàµà´¯à´‚</translation>
<translation id="6757797048963528358">നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം à´¸àµà´·àµà´ªàµâ€Œà´¤à´¿à´¯à´¿à´²à´¾à´¯à´¿.</translation>
@@ -486,7 +518,6 @@
<translation id="6891596781022320156">നയ നില പിനàµà´¤àµà´£à´¯àµà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´².</translation>
<translation id="6895330447102777224">നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠസàµà´¥à´¿à´°àµ€à´•à´°à´¿à´àµà´àµ</translation>
<translation id="6897140037006041989">ഉപയോകàµà´¤àµƒ à´à´œà´¨àµâ€à´±àµ</translation>
-<translation id="6903907808598579934">സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´•àµà´•àµ½ ഓണാകàµà´•àµà´•</translation>
<translation id="6915804003454593391">ഉപയോകàµà´¤à´¾à´µàµ:</translation>
<translation id="6957887021205513506">സെർവറിനàµà´±àµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ വിശàµà´µà´¸à´¿à´•àµà´•à´¾àµ» à´•àµà´³àµà´³à´¾à´¤àµà´¤ à´’à´¨àµà´¨à´¾à´¯à´¿ തോനàµà´¨àµà´¨àµà´¨àµ.</translation>
<translation id="6965382102122355670">ശരി</translation>
@@ -494,9 +525,11 @@
<translation id="6970216967273061347">ജിലàµà´²</translation>
<translation id="6973656660372572881">à´¸àµà´¥à´¿à´°à´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സെർവറàµà´•à´³àµà´‚ ഒരൠസàµâ€Œà´•àµà´°à´¿à´ªàµà´±àµà´±àµ URL-ഉം à´µàµà´¯à´•àµà´¤à´®à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="6989763994942163495">വിപàµà´²à´®à´¾à´¯ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ കാണികàµà´•àµà´•...</translation>
+<translation id="7000990526846637657">à´à´°à´¿à´¤àµà´° à´àµ»à´Ÿàµà´°à´¿à´•à´³àµà´¨àµà´¨àµà´‚ à´•à´£àµà´Ÿà´¿à´²àµà´²</translation>
+<translation id="7009986207543992532">നിങàµà´™àµ¾ <ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¿àµ½ à´à´¤àµà´¤à´¿à´àµà´àµ‡à´°à´¾àµ» à´¶àµà´°à´®à´¿à´àµà´àµ†à´™àµà´•à´¿à´²àµà´‚, വിശàµà´µà´¾à´¸à´¯àµ‹à´—àµà´¯à´®à´²àµà´²à´¾à´¤àµà´¤ തരതàµà´¤à´¿àµ½ ദൈർഘàµà´¯à´®àµ‡à´±à´¿à´¯ സാധàµà´¤à´¾ കാലയളവàµà´³àµà´³ ഒരൠസർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ സെർവർ നൽകി. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">à´àµˆà´¨ UnionPay</translation>
+<translation id="7012372675181957985">നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿à´¨àµ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> à´à´¨àµà´¨à´¤à´¿àµ½ മറàµà´±àµ തരതàµà´¤à´¿à´²àµà´³àµà´³ à´¬àµà´°àµ—സിംഗൠà´à´°à´¿à´¤àµà´°à´®àµà´£àµà´Ÿà´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚</translation>
<translation id="7029809446516969842">പാസàµâ€Œà´µàµ‡à´¡àµà´•à´³àµâ€</translation>
-<translation id="7050187094878475250">നിങàµà´™àµ¾ <ph name="DOMAIN" /> à´à´¨àµà´¨à´¤à´¿à´²àµ†à´¤àµà´¤à´¾àµ» à´¶àµà´°à´®à´¿à´àµà´àµ, à´à´¨àµà´¨à´¾àµ½ തീരെ വിശàµà´µà´¾à´¸à´¯àµ‹à´—àµà´¯à´®à´²àµà´²à´¾à´¤àµà´¤ ഒരൠകാലാവധിയàµà´³àµà´³ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¾à´£àµ സെർവർ കാണികàµà´•àµà´¨àµà´¨à´¤àµ.</translation>
<translation id="7087282848513945231">രാജàµà´¯à´‚</translation>
<translation id="7088615885725309056">വളരെ പഴയ</translation>
<translation id="7090678807593890770">Google-ൽ <ph name="LINK" /> തിരയàµà´•</translation>
@@ -515,13 +548,13 @@
<translation id="7246609911581847514">à´ªàµà´¤à´¿à´¯ സൈറàµà´±àµà´•à´³à´¿àµ½ ആദàµà´¯à´®à´¾à´¯à´¿ പോകàµà´®àµà´ªàµ‹àµ¾ അവയàµâ€Œà´•àµà´•àµ മാനേജറിനàµà´±àµ† അംഗീകാരം ആവശàµà´¯à´®à´¾à´¯à´¤à´¿à´¨à´¾à´²à´¾à´£àµ à´ˆ സനàµà´¦àµ‡à´¶à´‚ കാണàµà´¨àµà´¨à´¤àµ.</translation>
<translation id="724975217298816891">നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠവിശദാംശങàµà´™àµ¾ à´…à´ªàµâ€Œà´¡àµ‡à´±àµà´±àµà´àµ†à´¯àµà´¯à´¾àµ» <ph name="CREDIT_CARD" />-à´¨àµà´±àµ† കാലാവധി തീരàµà´¨àµà´¨ തീയതിയàµà´‚ CVC-à´¯àµà´‚ നൽകàµà´•. à´¸àµà´¥à´¿à´°àµ€à´•à´°à´¿à´àµà´àµ à´•à´´à´¿à´àµà´à´¾àµ½, à´ˆ സൈറàµà´±àµà´®à´¾à´¯à´¿ കാർഡൠവിശദാംശങàµà´™àµ¾ പങàµà´•à´¿à´Ÿàµà´‚.</translation>
<translation id="725866823122871198">നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† തീയതിയàµà´‚ സമയവàµà´‚ (<ph name="DATE_AND_TIME" />) തെറàµà´±à´¾à´¯à´¤à´¿à´¨à´¾àµ½ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> à´à´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ à´¸àµà´µà´•à´¾à´°àµà´¯ കണകàµà´·àµ» à´¸àµà´¥à´¾à´ªà´¿à´•àµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´².</translation>
-<translation id="7265986070661382626">വെബàµà´¸àµˆà´±àµà´±àµ <ph name="BEGIN_LINK" /> സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ പിനàµà´¨à´¿à´‚ഗൠ<ph name="END_LINK" /> ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´². നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¤à´¿à´¨à´¾àµ½, à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•à´¾à´‚.</translation>
<translation id="7269802741830436641">à´ˆ വെബàµà´ªàµ‡à´œà´¿à´¨àµ ഒരൠറീഡയറകàµà´Ÿàµ ലൂപàµà´ªàµ ഉണàµà´Ÿàµ</translation>
<translation id="7275334191706090484">നിയനàµà´¤àµà´°à´¿à´¤ à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•àµ¾</translation>
<translation id="7298195798382681320">à´¶àµà´ªà´¾àµ¼à´¶à´àµ†à´¯àµà´¯àµà´¨àµà´¨à´¤àµ</translation>
-<translation id="7301833672208172928">à´à´°à´¿à´¤àµà´°à´‚ സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´•àµà´•àµ½ ഓണാകàµà´•àµà´•</translation>
+<translation id="7309308571273880165"><ph name="CRASH_TIME" />-നൠകàµà´¯à´¾à´ªàµâ€Œà´àµ¼ à´àµ†à´¯àµâ€Œà´¤ à´•àµà´°à´¾à´·àµ റിപàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµà´•àµ¾ (ഉപയോകàµà´¤à´¾à´µàµ à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¿à´àµà´ à´…à´ªàµâ€Œà´²àµ‹à´¡àµ, ഇതàµà´µà´°àµ† à´…à´ªàµâ€Œà´²àµ‹à´¡àµà´àµ†à´¯àµâ€Œà´¤à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²)</translation>
<translation id="7334320624316649418">&amp;à´ªàµà´¨à´ƒà´•àµà´°à´®àµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ à´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="733923710415886693">സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´¸àµà´¤à´¾à´°àµà´¯à´¤à´¯à´¿à´²àµ‚ടെ സെർവറàµà´Ÿàµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ വെളിപàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
+<translation id="7351800657706554155"><ph name="SITE" /> സൈറàµà´±à´¿à´¨àµà´±àµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ റദàµà´¦à´¾à´•àµà´•à´¿à´¯à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ ഇതൠസനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´². നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´• à´ªàµà´°à´¶àµâ€Œà´¨à´™àµà´™à´³à´¾à´¯à´¤à´¿à´¨à´¾àµ½, à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´‚. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">കമാനàµâ€à´±àµ ലൈനàµâ€â€Œ</translation>
<translation id="7372973238305370288">തിരയൽ ഫലം</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -540,16 +573,17 @@
<translation id="7469372306589899959">കാർഡൠസàµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="7481312909269577407">à´®àµà´¨àµà´¨àµ‹à´Ÿàµà´Ÿàµ</translation>
<translation id="7485870689360869515">ഡാറàµà´±à´•à´³àµà´¨àµà´¨àµà´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´².</translation>
+<translation id="7508255263130623398">നൽകിയ നയ ഉപകരണ à´à´¡à´¿ ശൂനàµà´¯à´®à´¾à´£àµ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ നിലവിലെ ഉപകരണ à´à´¡à´¿à´¯àµà´®à´¾à´¯à´¿ യോജികàµà´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
<translation id="7514365320538308">ഡൗൺലോഡàµà´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="7518003948725431193">വെബൠവിലാസതàµà´¤à´¿à´¨à´¾à´¯à´¿ വെബàµâ€Œà´ªàµ‡à´œàµà´¨àµà´¨àµà´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´²: <ph name="URL" /></translation>
<translation id="7537536606612762813">നിർബനàµà´§à´¿à´¤à´‚</translation>
<translation id="7542995811387359312">à´ˆ ഫോം ഒരൠസàµà´°à´•àµà´·à´¿à´¤ കണകàµà´·à´¨àµâ€ ഉപയോഗികàµà´•à´¾à´¤àµà´¤à´¤à´¿à´¨à´¾à´²àµâ€ à´¸àµà´µà´ªàµà´°àµ‡à´°à´¿à´¤ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാരàµâ€à´¡àµ പൂരിപàµà´ªà´¿à´•àµà´•à´²àµâ€ à´…à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•à´¿.</translation>
<translation id="7549584377607005141">ശരിയായി à´ªàµà´°à´¦àµ¼à´¶à´¿à´ªàµà´ªà´¿à´•àµà´•à´¾àµ» à´ˆ വെബàµâ€Œ പേജിനൠനിങàµà´™àµ¾ à´®àµà´®àµà´ªàµ നൽകിയ ഡാറàµà´± ആവശàµà´¯à´®à´¾à´£àµ. നിങàµà´™àµ¾à´•àµà´•àµ à´ˆ ഡാറàµà´± വീണàµà´Ÿàµà´‚ അയയàµâ€Œà´•àµà´•à´¾à´¨à´¾à´•àµà´®àµ†à´™àµà´•à´¿à´²àµà´‚, à´…à´™àµà´™à´¨àµ† à´àµ†à´¯àµà´¯àµà´¨àµà´¨à´¤àµ à´ˆ പേജിൽ à´®àµà´®àµà´ªàµ à´àµ†à´¯àµâ€Œà´¤ à´à´¤àµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´µàµà´‚ നിങàµà´™àµ¾à´•àµà´•àµ ആവർതàµà´¤à´¿à´•àµà´•àµ‡à´£àµà´Ÿà´¤à´¾à´¯à´¿ വരàµà´‚.</translation>
<translation id="7554791636758816595">à´ªàµà´¤à´¿à´¯ ടാബàµ</translation>
-<translation id="7567204685887185387">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; സെർവറിനàµà´±àµ† à´¸àµà´°à´•àµà´· സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´µà´àµà´à´¨à´¾à´ªà´°à´®à´¾à´¯à´¿ ഇഷàµà´¯àµ‚ à´àµ†à´¯àµâ€Œà´¤à´¿à´°à´¿à´•àµà´•à´¾à´‚. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ à´•àµà´£àµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ.</translation>
<translation id="7568593326407688803">à´ˆ പേജàµ<ph name="ORIGINAL_LANGUAGE" />ലാണൠനിങàµà´™à´³à´¤àµ വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ à´àµ†à´¯àµà´¯à´¾à´¨àµâ€â€Œ താലàµâ€â€Œà´ªàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ‹?</translation>
<translation id="7569952961197462199">Chrome-ൽ നിനàµà´¨àµ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡൠനീകàµà´•à´‚à´àµ†à´¯àµà´¯à´£àµ‹?</translation>
<translation id="7578104083680115302">നിങàµà´™àµ¾ Google-ൽ സംരകàµà´·à´¿à´àµà´ കാർഡàµà´•àµ¾ ഉപയോഗിà´àµà´àµ ഉപകരണങàµà´™à´³à´¿à´²àµà´Ÿà´¨àµ€à´³à´®àµà´³àµà´³ സൈറàµà´±àµà´•à´³à´¿à´²àµà´‚ ആപàµâ€Œà´¸à´¿à´²àµà´‚ പെടàµà´Ÿàµ†à´¨àµà´¨àµ പണമടയàµâ€Œà´•àµà´•àµà´•.</translation>
+<translation id="7588950540487816470">ഫിസികàµà´•àµ½ വെബàµ</translation>
<translation id="7592362899630581445">സെർവറിനàµà´±àµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ പേരിനàµà´±àµ† പരിധി ലംഘികàµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" />-നൠനിലവിൽ à´ˆ à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ കൈകാരàµà´¯à´‚ à´àµ†à´¯àµà´¯à´¾à´¨à´¾à´•àµà´¨àµà´¨à´¿à´²àµà´².</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" /> à´’à´°à´¿à´•àµà´•à´²àµà´‚ വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ à´àµ†à´¯àµà´¯à´°àµà´¤àµ</translation>
@@ -560,6 +594,7 @@
<translation id="7637571805876720304">Chromium-à´¤àµà´¤à´¿àµ½ നിനàµà´¨àµ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡൠനീകàµà´•à´‚à´àµ†à´¯àµà´¯à´£àµ‹?</translation>
<translation id="765676359832457558">വിപàµà´²à´®à´¾à´¯ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ മറയàµâ€Œà´•àµà´•àµà´•...</translation>
<translation id="7658239707568436148">റദàµà´¦à´¾à´•àµà´•àµ‚</translation>
+<translation id="7667346355482952095">നൽകിയ നയ ടോകàµà´•àµº ശൂനàµà´¯à´®à´¾à´£àµ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ നിലവിലെ ടോകàµà´•à´£àµà´®à´¾à´¯à´¿ യോജികàµà´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
<translation id="7668654391829183341">à´…à´œàµà´à´¾à´¤à´®à´¾à´¯ ഉപകരണം</translation>
<translation id="7674629440242451245">à´ªàµà´¤à´¿à´¯ Chrome-à´¨àµà´±àµ† രസകരമായ സവിശേഷതകളിൽ താൽപàµà´ªà´°àµà´¯à´®àµà´£àµà´Ÿàµ‹? chrome.com/dev-ൽ à´à´™àµà´™à´³àµà´Ÿàµ† ഡെവലപàµà´ªàµ¼ à´à´¾à´¨àµ½ പരീകàµà´·à´¿à´àµà´àµà´¨àµ‹à´•àµà´•àµà´•.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /> <ph name="SITE" /> à´à´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµ പോകàµà´• (à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²)<ph name="END_LINK" /></translation>
@@ -576,10 +611,10 @@
<translation id="780301667611848630">വേണàµà´Ÿ നനàµà´¦à´¿</translation>
<translation id="7805768142964895445">നില</translation>
<translation id="7813600968533626083">Chrome-ൽ നിനàµà´¨àµà´³àµà´³ നിർദàµà´¦àµ‡à´¶à´‚ നീകàµà´•à´‚à´àµ†à´¯àµà´¯à´£àµ‹?</translation>
+<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' à´à´¨àµà´¨à´¤à´¿à´¨àµà´±àµ† <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> à´•à´£àµà´Ÿàµ</translation>
<translation id="785549533363645510">à´à´¨àµà´¨à´¿à´°àµà´¨àµà´¨à´¾à´²àµà´‚ നിങàµà´™àµ¾ അദൃശàµà´¯à´¨à´²àµà´². ആൾമാറാടàµà´Ÿà´¤àµà´¤à´¿à´²àµ‡à´¯àµâ€Œà´•àµà´•àµ പോകàµà´¨àµà´¨à´¤àµ, നിങàµà´™à´³àµà´Ÿàµ† à´¤àµà´´à´¿àµ½ ദാതാവിൽ നിനàµà´¨àµ‹ ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ സേവന ദാതാവിൽ നിനàµà´¨àµ‹ നിങàµà´™àµ¾ സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´¨àµà´¨ വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•à´³à´¿àµ½ നിനàµà´¨àµ‹ ഉളàµà´³ à´¬àµà´°àµ—സിംഗിനെ മറയàµâ€Œà´•àµà´•à´¿à´²àµà´².</translation>
<translation id="7887683347370398519">നിങàµà´™à´³àµà´Ÿàµ† CVC പരിശോധിà´àµà´àµ വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•</translation>
<translation id="7894616681410591072">à´•àµà´·à´®à´¿à´•àµà´•à´£à´‚! à´ˆ പേജൠആകàµâ€Œà´¸à´¸àµà´¸àµà´àµ†à´¯àµà´¯à´¾àµ», നിങàµà´™àµ¾à´•àµà´•àµ <ph name="NAME" /> à´à´¨àµà´¨à´¯à´¾à´³à´¿àµ½ നിനàµà´¨àµà´‚ à´…à´¨àµà´®à´¤à´¿ ആവശàµà´¯à´®à´¾à´£àµ.</translation>
-<translation id="790025292736025802"><ph name="URL" /> à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´²</translation>
<translation id="7912024687060120840">ഫോൾഡറിൽ:</translation>
<translation id="7920092496846849526">à´ˆ പേജൠസനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾àµ» à´°à´•àµà´·à´•àµ¼à´¤àµà´¤à´¾à´•àµà´•àµ¾à´•àµà´•àµ സമàµà´®à´¤à´®à´¾à´£àµ‹à´¯àµ†à´¨àµà´¨àµ നിങàµà´™àµ¾ à´àµ‹à´¦à´¿à´àµà´àµ.</translation>
<translation id="7935318582918952113">DOM à´¡à´¿à´¸àµâ€Œà´±àµà´±à´¿à´²àµ¼</translation>
@@ -592,9 +627,10 @@
<translation id="7995512525968007366">à´µàµà´¯à´•àµà´¤à´®à´¾à´•àµà´•à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²</translation>
<translation id="8012647001091218357">ഇപàµà´ªàµ‹àµ¾ à´à´™àµà´™àµ¾à´•àµà´•àµ നിങàµà´™à´³àµà´Ÿàµ† à´°à´•àµà´·à´•àµ¼à´¤àµà´¤à´¾à´•àµà´•à´³àµ† ബനàµà´§à´ªàµà´ªàµ†à´Ÿà´¾à´¨à´¾à´¯à´¿à´²àµà´². വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•.</translation>
<translation id="8034522405403831421">à´ˆ പേജൠ<ph name="SOURCE_LANGUAGE" />-ലാണàµ. <ph name="TARGET_LANGUAGE" />-ലേകàµà´•àµ വിവർതàµà´¤à´¨à´‚ à´àµ†à´¯àµà´¯à´£àµ‹?</translation>
-<translation id="8034955203865359138">à´à´°à´¿à´¤àµà´° à´àµ»à´Ÿàµà´°à´¿à´•à´³àµà´¨àµà´¨àµà´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´².</translation>
<translation id="8088680233425245692">ലേഖനം കാണàµà´¨àµà´¨à´¤àµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
+<translation id="8089520772729574115">ഒരൠMB-യിൽ à´•àµà´±à´µà´¾à´£àµ</translation>
<translation id="8091372947890762290">സെർവറിൽ സജീവമാകàµà´•àµ½ തീർപàµà´ªà´¾à´•àµà´•à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²</translation>
+<translation id="8129262335948759431">ഡാറàµà´± ഉപയോഗ അളവൠഅറിയിലàµà´²</translation>
<translation id="8131740175452115882">à´¸àµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•àµà´•</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> à´à´¨àµà´¨à´¤à´¿à´¨àµà´±àµ† സെർവർ <ph name="BEGIN_ABBR" />DNS വിലാസം<ph name="END_ABBR" /> à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¾à´¨à´¾à´¯à´¿à´²àµà´².</translation>
<translation id="8149426793427495338">നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿàµ¼ à´¸àµà´·àµà´ªàµâ€Œà´¤à´¿à´¯à´¿à´²à´¾à´¯à´¿.</translation>
@@ -603,6 +639,7 @@
<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" à´à´¨àµà´¨ à´à´¡à´¿à´¯àµà´³àµà´³ വിപàµà´²àµ€à´•à´°à´£à´¤àµà´¤à´¿à´¨àµà´±àµ† à´…à´ªàµâ€Œà´¡àµ‡à´±àµà´±àµ URL അസാധàµà´µà´¾à´£àµ.</translation>
<translation id="8218327578424803826">നൽകിയിരികàµà´•àµà´¨àµà´¨ à´²àµà´•àµà´•àµ‡à´·àµ»:</translation>
<translation id="8225771182978767009">à´ˆ à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿàµ¼ സജàµà´œà´®à´¾à´•àµà´•à´¿à´¯ à´µàµà´¯à´•àµà´¤à´¿, à´ˆ സൈറàµà´±àµ à´¬àµà´²àµ‹à´•àµà´•àµà´àµ†à´¯àµà´¯à´¾àµ» തീരàµà´®à´¾à´¨à´¿à´àµà´à´¿à´°àµà´¨àµà´¨àµ.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">നിങàµà´™à´³àµâ€ à´…à´¨àµà´µàµ‡à´·à´¿à´•àµà´•àµà´¨àµà´¨ പേജൠനിങàµà´™à´³àµâ€ രേഖപàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯ വിവരങàµà´™à´³àµâ€ ഉപയോഗികàµà´•àµà´¨àµà´¨àµ. à´† പേജിലേകàµà´•àµ മടങàµà´™àµà´¨àµà´¨à´¤àµ നിങàµà´™à´³àµâ€ ആവരàµâ€à´¤àµà´¤à´¿à´•àµà´•à´¾à´µàµà´¨àµà´¨ à´à´¤àµ†à´™àµà´•à´¿à´²àµà´‚ à´ªàµà´°à´µàµƒà´¤àµà´¤à´¿à´•àµà´•àµ കാരണമായേകàµà´•àµà´‚. à´¤àµà´Ÿà´°à´¾à´¨àµâ€ നിങàµà´™à´³àµâ€ ആഗàµà´°à´¹à´¿à´•àµà´•àµà´¨àµà´¨àµà´£àµà´Ÿàµ‹?</translation>
<translation id="8249320324621329438">അവസാനം ലഭàµà´¯à´®à´¾à´¯à´¤àµ:</translation>
<translation id="8261506727792406068">ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµ‚</translation>
@@ -615,12 +652,17 @@
<translation id="8349305172487531364">à´¬àµà´•àµà´®à´¾à´°àµâ€à´•àµà´•àµ ബാരàµâ€</translation>
<translation id="8363502534493474904">à´«àµà´²àµˆà´±àµà´±àµ മോഡൠഓഫാകàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="8364627913115013041">സജàµà´œà´®à´¾à´•àµà´•à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
+<translation id="8380941800586852976">അപകടകരമായതàµ</translation>
<translation id="8412145213513410671">à´•àµà´°à´¾à´·àµà´•à´³àµâ€ <ph name="CRASH_COUNT" /></translation>
<translation id="8412392972487953978">നിങàµà´™à´³àµâ€ സമാന പാസàµà´«àµà´°àµ†à´¯àµà´¸àµ à´°à´£àµà´Ÿàµà´¤à´µà´£ നലàµâ€à´•à´£à´‚.</translation>
<translation id="8428213095426709021">à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™à´³àµâ€</translation>
+<translation id="8433057134996913067">ഇതൠനിങàµà´™à´³àµ† മികàµà´• വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•à´³à´¿àµ½ നിനàµà´¨àµà´‚ സൈൻ ഔടàµà´Ÿàµ à´àµ†à´¯àµà´¯à´¿à´•àµà´•àµà´‚.</translation>
<translation id="8437238597147034694">&amp;നീകàµà´•àµà´¨àµà´¨à´¤àµ പഴയപടിയാകàµà´•àµà´•</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{ഒരൠകàµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµ}other{# à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµà´•àµ¾}}</translation>
+<translation id="8483780878231876732">നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿àµ½ നിനàµà´¨àµ കാർഡàµà´•àµ¾ ഉപയോഗികàµà´•à´¾àµ», Chrome-ൽ സൈൻ ഇൻ à´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="8488350697529856933">ഇതിനൠബാധകമാകàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> à´ªàµà´°à´¤à´¿à´•à´°à´¿à´•àµà´•à´¾àµ» കൂടàµà´¤àµ½ സമയമെടàµà´¤àµà´¤àµ.</translation>
+<translation id="852346902619691059">à´ˆ സെർവറിനൠഇതൠ<ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¾à´£àµ†à´¨àµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† à´“à´ªàµà´ªà´±àµ‡à´±àµà´±à´¿à´‚ഗൠസിസàµà´±àµà´±à´‚ വിശàµà´µà´¸à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´²àµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിà´àµà´à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Google പേയàµâ€Œà´®àµ†à´¨àµà´±àµ ഇതàµà´¤à´°à´‚ കാർഡിനെ പിനàµà´¤àµà´£à´¯àµà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´². മറàµà´±àµà´¨àµà´¨àµ തിരà´àµà´àµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="8550022383519221471">à´ˆ സേവനം നിങàµà´™à´³àµà´Ÿàµ† à´¡àµà´®àµ†à´¯àµà´¨à´¿à´¨àµ ലഭàµà´¯à´®à´²àµà´².</translation>
<translation id="8553075262323480129">പേജിനàµâ€à´±àµ† ഭാഷ നിരàµâ€â€Œà´£àµà´£à´¯à´¿à´•àµà´•à´¾à´¨àµâ€â€Œ കഴിയാതàµà´¤à´¤à´¿à´¨à´¾à´²àµâ€â€Œ വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
@@ -632,15 +674,12 @@
<translation id="8647750283161643317">à´à´²àµà´²à´¾à´‚ à´¸àµà´¥à´¿à´°à´®à´¾à´¯à´¿ à´ªàµà´¨à´ƒà´¸à´œàµà´œà´®à´¾à´•àµà´•àµà´•</translation>
<translation id="8680787084697685621">à´…à´•àµà´•àµ—à´£àµà´Ÿàµ à´ªàµà´°à´µàµ‡à´¶à´¨ വിവരങàµà´™à´³àµâ€ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿà´¤à´¾à´£àµ.</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> ലേകàµà´•àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµâ€ à´à´¨àµâ€â€Œà´•àµà´°à´¿à´ªàµà´±àµà´±àµ à´àµ†à´¯àµà´¤à´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
-<translation id="8713130696108419660">ഇനിഷàµà´¯àµ½ സിഗàµà´¨àµ‡à´àµà´àµ¼ മോശമാണàµ</translation>
<translation id="8725066075913043281">വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•</translation>
<translation id="8728672262656704056">നിങàµà´™àµ¾ ആൾമാറാടàµà´Ÿà´¤àµà´¤à´¿à´²àµ‡à´•àµà´•àµ പോയി</translation>
<translation id="8730621377337864115">പൂർതàµà´¤à´¿à´¯à´¾à´•àµà´•à´¿</translation>
<translation id="8738058698779197622">ഒരൠസàµà´°à´•àµà´·à´¿à´¤ കണകàµà´·àµ» à´¸àµà´¥à´¾à´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ, നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´²àµ‹à´•àµà´•àµ ശരിയായി സജàµà´œàµ€à´•à´°à´¿à´•àµà´•àµ‡à´£àµà´Ÿà´¤àµà´£àµà´Ÿàµ. വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•àµ¾ à´¸àµà´µà´¯à´‚ തിരിà´àµà´à´±à´¿à´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ ഉപയോഗികàµà´•àµà´¨àµà´¨ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµà´•àµ¾, നിർദàµà´¦à´¿à´·àµâ€Œà´Ÿ സമയ പരിധിയàµâ€Œà´•àµà´•àµ മാതàµà´°à´®à´¾à´¯à´¿ സാധàµà´¤à´¯àµà´³àµà´³à´¤à´¿à´¨à´¾à´²à´¾à´£à´¿à´¤àµ. നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ തെറàµà´±à´¾à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½, Chromium-നൠഈ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµà´•àµ¾ പരിശോധിà´àµà´àµà´±à´ªàµà´ªà´¿à´•àµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´².</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> ഹോസàµâ€Œà´±àµà´±à´¿à´¨àµà´±àµ† &lt;abbr id="dnsDefinition"&gt;DNS വിലാസം&lt;/abbr&gt; à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¾à´¨à´¾à´¯à´¿à´²àµà´². à´ªàµà´°à´¶àµâ€Œà´¨à´‚ നിർണàµà´£à´¯à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
-<translation id="8741995161408053644">നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿à´¨àµ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> à´à´¨àµà´¨à´¤à´¿àµ½ മറàµà´±àµ തരതàµà´¤à´¿à´²àµà´³àµà´³ à´¬àµà´°àµ—സിംഗൠà´à´°à´¿à´¤àµà´°à´®àµà´£àµà´Ÿà´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚.</translation>
<translation id="8790007591277257123">&amp;ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ à´àµ†à´¯àµà´¯àµà´•</translation>
-<translation id="8790687370365610530">Google നിർദàµà´¦àµ‡à´¶à´¿à´àµà´, à´µàµà´¯à´•àµà´¤à´¿à´ªà´°à´®à´¾à´•àµà´•à´¿à´¯ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´¸àµà´µà´¨àµà´¤à´®à´¾à´•àµà´•à´¾àµ», à´à´°à´¿à´¤àµà´°à´‚ സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´•àµà´•àµ½ ഓണാകàµà´•àµà´•.</translation>
<translation id="8798099450830957504">à´¸àµà´¥à´¿à´°à´¸àµà´¥à´¿à´¤à´¿</translation>
<translation id="8804164990146287819">à´¸àµà´µà´•à´¾à´°àµà´¯à´¤ നയം</translation>
<translation id="8820817407110198400">à´¬àµà´•àµà´•àµâ€Œà´®à´¾à´°àµâ€à´•àµà´•àµà´•à´³àµâ€</translation>
@@ -662,13 +701,11 @@
<translation id="8971063699422889582">സെരàµâ€à´µà´±à´¿à´¨àµâ€à´±àµ† സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ.</translation>
<translation id="8987927404178983737">മാസം</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´¸àµà´¤à´¾à´°àµà´¯à´¤à´¾ നയം ഉപയോഗിà´àµà´àµ സെർവർ, à´à´²àµà´²à´¾à´µàµ¼à´•àµà´•àµà´®à´¾à´¯à´¿ വെളàµà´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²à´¾à´¤àµà´¤ ഒരൠസർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ലഭàµà´¯à´®à´¾à´•àµà´•à´¿. à´à´¿à´² സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµà´•àµ¾ വിശàµà´µà´¾à´¸à´¯àµ‹à´—àµà´¯à´®à´¾à´£àµ†à´¨àµà´¨àµà´‚ à´…à´•àµà´°à´®à´•à´¾à´°à´¿à´•à´³à´¿àµ½ നിനàµà´¨àµà´‚ പരിരകàµà´·à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¾à´£àµ†à´¨àµà´¨àµà´‚ ഉറപàµà´ªà´¾à´•àµà´•à´¾àµ» അവയàµâ€Œà´•àµà´•àµ ഇതൠആവശàµà´¯à´®à´¾à´£àµ.</translation>
<translation id="9001074447101275817">à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ <ph name="DOMAIN" /> à´¡àµà´®àµ†à´¯àµâ€Œà´¨à´¿à´¨àµ ഉപയോകàµà´¤àµƒà´¨à´¾à´®à´µàµà´‚ പാസàµâ€Œà´µàµ‡à´¡àµà´‚ ആവശàµà´¯à´®à´¾à´£àµ.</translation>
<translation id="901974403500617787">ഉടമയàµâ€Œà´•àµà´•àµ മാതàµà´°à´®àµ‡ സിസàµà´±àµà´±à´¤àµà´¤à´¿à´²à´¾à´•à´®à´¾à´¨à´‚ ബാധകമാകàµà´•à´¾à´µàµà´¨àµà´¨ à´«àµà´²à´¾à´—ൠസജàµà´œà´®à´¾à´•àµà´•à´¾à´¨à´¾à´•àµ‚: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">à´ˆ പേജൠ<ph name="TARGET_LANGUAGE" />-ലേകàµà´•àµ വിവർതàµà´¤à´¨à´‚ à´àµ†à´¯àµâ€Œà´¤àµ</translation>
<translation id="9038649477754266430">പേജàµà´•àµ¾ കൂടàµà´¤àµ½ വേഗതàµà´¤à´¿àµ½ ലോഡàµà´àµ†à´¯àµà´¯à´¾àµ» ഒരൠപàµà´°à´µà´à´¨ സേവനം ഉപയോഗികàµà´•àµà´•</translation>
<translation id="9039213469156557790">à´ˆ പേജിൽ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²à´¾à´¤àµà´¤ മറàµà´±àµ ഉറവിടങàµà´™àµ¾ ഉൾപàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ. à´ˆ ഉറവിടങàµà´™àµ¾ കൈമാറàµà´¨àµà´¨à´¤à´¿à´¨à´¿à´Ÿàµ† മറàµà´±àµà´³àµà´³à´µàµ¼à´•àµà´•àµ കാണാനàµà´‚ പേജിനàµà´±àµ† à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´°àµ€à´¤à´¿ മാറàµà´±àµà´¨àµà´¨ തരതàµà´¤à´¿àµ½ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿à´¯àµâ€Œà´•àµà´•àµ പരിഷàµâ€Œà´•àµà´•à´°à´¿à´•àµà´•à´¾à´¨àµà´®à´¾à´¯àµ‡à´•àµà´•àµà´‚.</translation>
-<translation id="9049981332609050619">നിങàµà´™à´³àµâ€ <ph name="DOMAIN" /> à´à´¨àµà´¨à´¤à´¿à´²àµâ€ à´à´¤àµà´¤à´¾à´¨àµâ€ à´¶àµà´°à´®à´¿à´àµà´àµ, പകàµà´·àµ‡ സെരàµâ€à´µà´°àµâ€ ഒരൠഅസാധàµà´µà´¾à´¯ സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ അവതരിപàµà´ªà´¿à´àµà´àµ.</translation>
<translation id="9050666287014529139">പാസàµà´«àµà´°àµ†à´¯àµà´¸àµ</translation>
<translation id="9065203028668620118">à´à´¡à´¿à´±àµà´±àµà´àµ†à´¯àµà´¯àµà´•</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> പേജൠപàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
diff --git a/chromium/components/strings/components_strings_mr.xtb b/chromium/components/strings/components_strings_mr.xtb
index 44f5ab3df53..8d3592912c7 100644
--- a/chromium/components/strings/components_strings_mr.xtb
+++ b/chromium/components/strings/components_strings_mr.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="mr">
+<translation id="1008557486741366299">सधà¥à¤¯à¤¾ नाही</translation>
<translation id="1015730422737071372">अतिरिकà¥à¤¤ तपशील पà¥à¤°à¤¦à¤¾à¤¨ करा</translation>
<translation id="1032854598605920125">घडà¥à¤¯à¤¾à¤³à¤¾à¤à¥à¤¯à¤¾ दिशेने फिरवा</translation>
<translation id="1038842779957582377">अजà¥à¤à¤¾à¤¤ नाव</translation>
+<translation id="1053591932240354961">Google Chrome पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾ करू शकत नाही असे न समजणारे कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤² वेबसाइटने पाठविलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ आपण आतà¥à¤¤à¤¾ <ph name="SITE" /> ला भेट देठशकत नाही. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥‡ असतात, यामà¥à¤³à¥‡ हे पृषà¥à¤  कदाà¤à¤¿à¤¤ नंतर कारà¥à¤¯ करेल. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;जोडा पूरà¥à¤µà¤µà¤¤ करा</translation>
<translation id="10614374240317010">कधीही जतन न केलेले</translation>
-<translation id="1064422015032085147">वेबपृषà¥â€à¤  होसà¥à¤Ÿ करणारà¥â€à¤¯à¤¾ सरà¥à¤µà¥â€à¤¹à¤°à¤µà¤° कदाà¤à¤¿à¤¤ अतà¥à¤¯à¤¾à¤§à¤¿à¤• भार आहे किंवा तà¥à¤¯à¤¾à¤à¥€ देखरेख केली जात असावी.
- खूप रहदारी आणि परिसà¥à¤¥à¤¿à¤¤à¥€ आणखी बिघडविणे टाळणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€,
- या URL ला विनंती पाठविणà¥à¤¯à¤¾à¤à¥€ अनà¥à¤®à¤¤à¥€ तातà¥à¤ªà¥à¤°à¤¤à¥€ रदà¥à¤¦ केली गेली आहे.</translation>
<translation id="106701514854093668">डेसà¥â€à¤•à¤Ÿà¥‰à¤ª बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="1080116354587839789">रूंदीत फिट करा</translation>
+<translation id="1103124106085518534">आता साठी पूरà¥à¤£ à¤à¤¾à¤²à¥‡</translation>
<translation id="1103523840287552314">नेहमी भाषांतर करा <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">à¤à¥‡à¤• केलà¥à¤¯à¤¾à¤¸, अधिक जलद फॉरà¥à¤® भरणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° Chrome आपलà¥à¤¯à¤¾ कारà¥à¤¡à¤à¥€ à¤à¤• पà¥à¤°à¤¤ संà¤à¤¯à¤¿à¤¤ करेल.</translation>
+<translation id="1111153019813902504">अलीकडील बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="1113869188872983271">&amp;पà¥à¤¨à¤°à¥à¤•à¥à¤°à¤®à¤¿à¤¤ करा पूरà¥à¤µà¤µà¤¤ करा</translation>
+<translation id="1126551341858583091">सà¥à¤¥à¤¾à¤¨à¤¿à¤• संà¤à¤¯à¤¾à¤µà¤°à¥€à¤² आकार <ph name="CRASH_SIZE" /> आहे.</translation>
<translation id="112840717907525620">धोरण कॅशे ठीक</translation>
<translation id="113188000913989374"><ph name="SITE" /> मà¥à¤¹à¤£à¤¤à¥‡:</translation>
<translation id="1132774398110320017">Chrome सà¥à¤µà¤¯à¤‚भरण सेटिंगà¥à¤œ...</translation>
-<translation id="1150979032973867961">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपलà¥à¤¯à¤¾ संगणकाà¤à¥à¤¯à¤¾ ऑपरेटिंग पà¥à¤°à¤£à¤¾à¤²à¥€à¤¦à¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
<translation id="1152921474424827756"><ph name="URL" /> à¤à¥à¤¯à¤¾ <ph name="BEGIN_LINK" />कॅशे केलेलà¥à¤¯à¤¾ कॉपीवर<ph name="END_LINK" /> पà¥à¤°à¤µà¥‡à¤¶ करा</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> नी कनेकà¥à¤¶à¤¨ अनपेकà¥à¤·à¤¿à¤¤à¤°à¤¿à¤¤à¥à¤¯à¤¾ बंद केले.</translation>
<translation id="1161325031994447685">Wi-Fi शी पà¥à¤¨à¥à¤¹à¤¾ कनेकà¥à¤Ÿ करीत आहे</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">काढा</translation>
<translation id="1201402288615127009">पà¥à¤¢à¥€à¤²</translation>
<translation id="1201895884277373915">या साइटकडून अधिक</translation>
-<translation id="121201262018556460">आपण <ph name="DOMAIN" /> वर पोहोà¤à¤£à¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केलात, परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ à¤à¤• कमकà¥à¤µà¤¤ की असलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले. आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ गोपनीय की तोडलेली असू शकते आणि सरà¥à¤µà¥à¤¹à¤° हे आपलà¥à¤¯à¤¾à¤²à¤¾ अपेकà¥à¤·à¤¿à¤¤ असणारे सरà¥à¤µà¥à¤¹à¤° नसू शकते (आपण कदाà¤à¤¿à¤¤ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¶à¥€ संपà¥à¤°à¥‡à¤·à¤£ करत असाल).</translation>
+<translation id="1206967143813997005">खराब पà¥à¤°à¤¾à¤°à¤‚भिक सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€</translation>
+<translation id="1209206284964581585">आतासाठी लपवा</translation>
<translation id="1219129156119358924">सिसà¥à¤Ÿà¥€à¤® सà¥à¤°à¤•à¥à¤·à¤¾</translation>
<translation id="1227224963052638717">अजà¥à¤à¤¾à¤¤ धोरण.</translation>
<translation id="1227633850867390598">मूलà¥à¤¯ लपवा</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">होय</translation>
<translation id="1430915738399379752">मà¥à¤¦à¥à¤°à¤£</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /> <ph name="DOMAIN" /> वरील à¤à¤•à¤¾ पृषà¥à¤ à¤¾à¤¸ भेट देणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€à¤à¤¾<ph name="END_LINK" /> पà¥à¤°à¤¯à¤¤à¥à¤¨ अवरोधित केला.</translation>
+<translation id="1491663344921578213">वेबसाइट पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पिनिंग वापरत असलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ आपण <ph name="SITE" /> ला आतà¥à¤¤à¤¾ भेट देठशकत नाही. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥‡ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥‡ असतात, यामà¥à¤³à¥‡ हे पृषà¥à¤  कदाà¤à¤¿à¤¤ नंतर कारà¥à¤¯ करेल. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">या पृषà¥à¤ à¤¾à¤à¥€ जतन केलेली (उदा. कालबाहà¥à¤¯ होणारे जà¥à¤à¤¾à¤¤) पà¥à¤°à¤¤ दरà¥à¤¶à¤µà¤¾.</translation>
<translation id="1519264250979466059">बिलà¥à¤¡ तारीख</translation>
<translation id="1549470594296187301">हे वैशिषà¥â€à¤Ÿà¥à¤¯ वापरणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ JavaScript सकà¥à¤·à¤® करणे आवशà¥â€à¤¯à¤• आहे.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">नेटवरà¥à¤• कॉनà¥à¤«à¤¿à¤—रेशन अवैध आहे आणि आयात केले जाठशकले नाही.</translation>
<translation id="1644574205037202324">इतिहास</translation>
<translation id="1645368109819982629">असमरà¥à¤¥à¤¿à¤¤ पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤²</translation>
-<translation id="1655462015569774233">{1,plural, =1{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° काल कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. आपले संगणक सधà¥à¤¯à¤¾ <ph name="CURRENT_DATE" /> वर सेट आहे. ते योगà¥à¤¯ दिसते आहे? नसलà¥à¤¯à¤¾à¤¸, आपण आपलà¥à¤¯à¤¾ सिसà¥à¤Ÿà¥€à¤®à¤à¥‡ घडà¥à¤¯à¤¾à¤³ दà¥à¤°à¥‚सà¥à¤¤ करावे आणि तà¥à¤¯à¤¾à¤¨à¤‚तर हे पृषà¥à¤  रीफà¥à¤°à¥‡à¤¶ करा.}one{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" />असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° # दिवसांपूरà¥à¤µà¥€ कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. आपले संगणक सधà¥à¤¯à¤¾ <ph name="CURRENT_DATE" /> वर सेट आहे. ते योगà¥à¤¯ दिसते आहे? नसलà¥à¤¯à¤¾à¤¸, आपण आपलà¥à¤¯à¤¾ सिसà¥à¤Ÿà¥€à¤®à¤à¥‡ घडà¥à¤¯à¤¾à¤³ दà¥à¤°à¥‚सà¥à¤¤ करावे आणि तà¥à¤¯à¤¾à¤¨à¤‚तर हे पृषà¥à¤  रीफà¥à¤°à¥‡à¤¶ करा.}other{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" />असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° # दिवसांपूरà¥à¤µà¥€ कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. आपले संगणक सधà¥à¤¯à¤¾ <ph name="CURRENT_DATE" /> वर सेट आहे. ते योगà¥à¤¯ दिसते आहे? नसलà¥à¤¯à¤¾à¤¸, आपण आपलà¥à¤¯à¤¾ सिसà¥à¤Ÿà¥€à¤®à¤à¥‡ घडà¥à¤¯à¤¾à¤³ दà¥à¤°à¥‚सà¥à¤¤ करावे आणि तà¥à¤¯à¤¾à¤¨à¤‚तर हे पृषà¥à¤  रीफà¥à¤°à¥‡à¤¶ करा.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> आपली माहिती संरकà¥à¤·à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ सामानà¥à¤¯à¤¤à¤ƒ कूटबदà¥à¤§à¥€à¤•à¤°à¤£ वापरते. Google Chrome ने यावेळी <ph name="SITE" /> शी कनेकà¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला तेवà¥â€à¤¹à¤¾, वेबसाइटने असामानà¥à¤¯ आणि अयोगà¥à¤¯ कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤² परत पाठविले. à¤à¤•à¤¤à¤° आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ <ph name="SITE" /> असलà¥à¤¯à¤¾à¤à¥€ बतावणी करणà¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करतो तेवà¥â€à¤¹à¤¾ किंवा Wi-Fi साइन इन सà¥à¤•à¥à¤°à¥€à¤¨à¤¨à¥‡ कनेकà¥à¤¶à¤¨à¤®à¤§à¥à¤¯à¥‡ वà¥à¤¯à¤¤à¥à¤¯à¤¯ आणले तेवà¥â€à¤¹à¤¾ हे घडू शकते. कोणतà¥à¤¯à¤¾à¤¹à¥€ डेटाà¤à¥€ अदलाबदल करणà¥à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ Google Chrome ने कनेकà¥à¤¶à¤¨ थांबविलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ आपली माहिती अदà¥à¤¯à¤¾à¤ª सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ आहे.</translation>
<translation id="168841957122794586">सरà¥à¤µà¥à¤¹à¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤¾à¤¤ à¤à¤• कमकà¥à¤µà¤¤ कà¥à¤°à¤¿à¤ªà¥à¤Ÿà¥‹à¤—à¥à¤°à¤¾à¤«à¤¿à¤• की आहे.</translation>
<translation id="1701955595840307032">सà¥à¤à¤µà¤¿à¤²à¥‡à¤²à¥€ सामगà¥à¤°à¥€ मिळवा</translation>
-<translation id="1706954506755087368">{1,plural, =1{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° उदà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न मानले जाईल. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.}one{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤¢à¥€à¤² # दिवसांपासून मानले जाईल. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.}other{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤¢à¥€à¤² # दिवसांपासून मानले जाईल. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">सिसà¥à¤Ÿà¥€à¤® पà¥à¤°à¤¶à¤¾à¤¸à¤•à¤¾à¤¶à¥€ संपरà¥à¤• साधणà¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="17513872634828108">खà¥à¤²à¥‡ टॅब</translation>
<translation id="1753706481035618306">पृषà¥à¤  कà¥à¤°à¤®à¤¾à¤‚क</translation>
-<translation id="1761412452051366565">Google दà¥à¤µà¤¾à¤°à¥‡ सà¥à¤à¤µà¤¿à¤²à¥‡à¤²à¥€ वैयकà¥à¤¤à¥€à¤•à¥ƒà¤¤ सामगà¥à¤°à¥€ मिळविणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, संकालन à¤à¤¾à¤²à¥‚ करा.</translation>
-<translation id="1763864636252898013">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपलà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤à¥à¤¯à¤¾ ऑपरेटिंग पà¥à¤°à¤£à¤¾à¤²à¥€à¤¦à¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows नेटवरà¥à¤• निदान à¤à¤¾à¤²à¤µà¥‚न पहा<ph name="END_LINK" />.</translation>
-<translation id="1783075131180517613">कृपया आपले समकà¥à¤°à¤®à¤¿à¤¤ सांकेतिक वाकà¥à¤¯à¤¾à¤‚श अदà¥à¤¯à¤¤à¤¨à¤¿à¤¤ करा.</translation>
+<translation id="1783075131180517613">कृपया आपले संंकालित सांकेतिक वाकà¥à¤¯à¤¾à¤‚श अदà¥à¤¯à¤¤à¤¨à¤¿à¤¤ करा.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">आपले अलीकडे भेट दिलेले बà¥à¤•à¤®à¤¾à¤°à¥à¤• येथे दिसतील.</translation>
<translation id="1821930232296380041">अवैध विनंती किंवा विनंती मापदंड</translation>
<translation id="1838667051080421715">आपण वेब पृषà¥à¤ à¤¾à¤à¤¾ सà¥à¤¤à¥à¤°à¥‹à¤¤ पहात आहात.</translation>
<translation id="1871208020102129563">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ निशà¥à¤à¤¿à¤¤ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤° वापरणà¥â€à¤¯à¤¾à¤¸ सेट करणà¥â€à¤¯à¤¾à¤¤ आले आहे, .pac सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ URL नवà¥à¤¹à¥‡.</translation>
<translation id="1883255238294161206">सूà¤à¥€ संकà¥à¤à¤¿à¤¤ करा</translation>
<translation id="1898423065542865115">फिलà¥à¤Ÿà¤° करणे</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> नी आपले लॉग इन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सà¥à¤µà¥€à¤•à¤¾à¤°à¤²à¥‡ नाही किंवा कदाà¤à¤¿à¤¤ आपले लॉग इन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡ असावे.</translation>
<translation id="194030505837763158"><ph name="LINK" /> दà¥à¤µà¥à¤¯à¤¾à¤•à¤¡à¥‡ जा</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="1973335181906896915">कà¥à¤°à¤®à¥€à¤•à¤°à¤£ तà¥à¤°à¥à¤Ÿà¥€</translation>
<translation id="1974060860693918893">पà¥à¤°à¤—त</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{आणि 1 अधिक}one{आणि # अधिक}other{आणि # अधिक}}</translation>
<translation id="2025186561304664664">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सà¥à¤µà¤¯à¤‚à¤à¤²à¤¿à¤¤ â€à¤•à¥‰à¤¨à¥à¤«à¤¿à¤—रेशनवर सेट करणà¥â€à¤¯à¤¾à¤¤ आली.</translation>
<translation id="2030481566774242610">आपलà¥à¤¯à¤¾à¤²à¤¾ असे मà¥à¤¹à¤£à¤¾à¤¯à¤à¥‡ होते <ph name="LINK" />?</translation>
<translation id="2031925387125903299">आपलà¥à¤¯à¤¾à¤²à¤¾ हा संदेश दिसत आहे कारण नवीन साइटà¤à¥à¤¯à¤¾ आपलà¥à¤¯à¤¾ पà¥à¤°à¤¥à¤® भेटीवर आपलà¥à¤¯à¤¾ पालकांनी मंजूरी देणे आवशà¥à¤¯à¤• आहे.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ आणि फायरवॉल तपासणे<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">पिनकोड</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 सूà¤à¤¨à¤¾}one{# सूà¤à¤¨à¤¾}other{# सूà¤à¤¨à¤¾}}</translation>
<translation id="2065985942032347596">पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£ आवशà¥à¤¯à¤•</translation>
<translation id="2079545284768500474">पूरà¥à¤µà¤µà¤¤ करा</translation>
<translation id="20817612488360358">सिसà¥à¤Ÿà¤® पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सेटिंगà¥à¤œ वापरणà¥â€à¤¯à¤¾à¤¸ सेट करणà¥â€à¤¯à¤¾à¤¤ आलà¥à¤¯à¤¾ परंतॠà¤à¤• सà¥à¤¸à¥à¤ªà¤·à¥â€à¤Ÿ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉनà¥à¤«à¤¿à¤—रेशन देखील निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤¤ आले.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">बà¥à¤•à¤®à¤¾à¤°à¥à¤• संपादित करा</translation>
<translation id="2166049586286450108">पूरà¥à¤£ पà¥à¤°à¤¶à¤¾à¤¸à¤¨ पà¥à¤°à¤µà¥‡à¤¶</translation>
<translation id="2166378884831602661">ही साइट सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥à¤¶à¤¨ पà¥à¤°à¤¦à¤¾à¤¨ करू शकत नाही</translation>
-<translation id="2171101176734966184">आपण <ph name="DOMAIN" /> वर पोहोà¤à¤£à¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ à¤à¤–ादà¥à¤¯à¤¾ कमकूवत सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€ अलà¥à¤—ोरिदमà¤à¤¾ वापर करून सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€à¤•à¥ƒà¤¤ केलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले. याà¤à¤¾ अरà¥à¤¥ असा आहे की सरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ सादर केलेली सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤² बनावट असू शकतात आणि आपण अपेकà¥à¤·à¤¾ करीत असलेला सरà¥à¤µà¥à¤¹à¤° हा नसावा (आपण कदाà¤à¤¿à¤¤ à¤à¤–ादà¥à¤¯à¤¾ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¸à¤¹ संपà¥à¤°à¥‡à¤·à¤£ करीत आहात).</translation>
<translation id="2181821976797666341">धोरणे</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 पतà¥à¤¤à¤¾}one{# पतà¥à¤¤à¤¾}other{# पतà¥à¤¤à¥‡}}</translation>
<translation id="2212735316055980242">धोरण आढळले नाही</translation>
<translation id="2213606439339815911">पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¥à¤¯à¤¾ आणत आहे...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> उपलबà¥à¤§ नाही</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />निदान अॅप<ph name="END_LINK" /> वापरून आपलà¥à¤¯à¤¾ कनेकà¥à¤¶à¤¨à¤à¥‡ निराकरण करा</translation>
+<translation id="2239100178324503013">आता पाठवा</translation>
<translation id="225207911366869382">हे मूलà¥à¤¯ या धोरणासाठी नापसंत करणà¥â€à¤¯à¤¾à¤¤ आले आहे.</translation>
<translation id="2262243747453050782">HTTP तà¥à¤°à¥à¤Ÿà¥€</translation>
<translation id="2282872951544483773">अनà¥à¤ªà¤²à¤¬à¥à¤§ पà¥à¤°à¤¯à¥‹à¤—</translation>
<translation id="2292556288342944218">आपला इंटरनेट पà¥à¤°à¤µà¥‡à¤¶ अवरोधित केला आहे</translation>
<translation id="229702904922032456">अंतसà¥à¤¥ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤¾à¤à¤¾ रूट कालबाहà¥à¤¯ à¤à¤¾à¤²à¤¾ आहे.</translation>
<translation id="230155334948463882">नवीन कारà¥à¤¡?</translation>
+<translation id="2305919008529760154">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° फसवणà¥à¤•à¥€à¤¨à¥‡ जारी केले असावे. हे कदाà¤à¤¿à¤¤ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ आपलà¥à¤¯à¤¾ कनेकà¥à¤¶à¤¨à¤®à¤§à¥à¤¯à¥‡ वà¥à¤¯à¤¤à¥à¤¯à¤¯ आणत असलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असावे. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> साठी वापरकरà¥à¤¤à¤¾à¤¨à¤¾à¤µ आणि संकेतशबà¥à¤¦ आवशà¥à¤¯à¤• आहेत.</translation>
+<translation id="2318774815570432836">आपण <ph name="SITE" /> ला आतà¥à¤¤à¤¾ भेट देठशकत नाही कारण वेबसाइट HSTS वापरते. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£à¥‡ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥€ असतात, यामà¥à¤³à¥‡ हे पृषà¥à¤  कदाà¤à¤¿à¤¤ नंतर कारà¥à¤¯ करेल. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155"><ph name="ENTRY_INDEX" /> अनà¥à¤•à¥à¤°à¤®à¤£à¤¿à¤•à¥‡à¤®à¤§à¥€à¤² अवैध बà¥à¤•à¤®à¤¾à¤°à¥à¤•à¤•à¤¡à¥‡ दà¥à¤°à¥à¤²à¤•à¥à¤· केले</translation>
<translation id="2354001756790975382">इतर बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="2359808026110333948">सà¥à¤°à¥‚ ठेवा</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" /> वाजता कॅपà¥à¤à¤° केलेला कà¥à¤°à¥…श अहवाल अपलोड केला नाही</translation>
<translation id="2367567093518048410">दरà¥à¤œà¤¾</translation>
+<translation id="2371153335857947666">{1,plural, =1{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° काल कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. आपलà¥à¤¯à¤¾ संगणकाà¤à¥‡ घडà¥à¤¯à¤¾à¤³ सधà¥à¤¯à¤¾ <ph name="CURRENT_DATE" /> वर सेट आहे. ते बरोबर आहे? नसलà¥à¤¯à¤¾à¤¸, आपण आपलà¥à¤¯à¤¾ सिसà¥à¤Ÿà¥€à¤®à¤à¥‡ घडà¥à¤¯à¤¾à¤³ दà¥à¤°à¥‚सà¥à¤¤ आणि तà¥à¤¯à¤¾à¤¨à¤‚तर हे पृषà¥à¤  रीफà¥à¤°à¥‡à¤¶ करणे आवशà¥à¤¯à¤• आहे. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.}one{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" />असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° # दिवसांपूरà¥à¤µà¥€ कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. आपलà¥à¤¯à¤¾ संगणकाà¤à¥‡ घडà¥à¤¯à¤¾à¤³ सधà¥à¤¯à¤¾ <ph name="CURRENT_DATE" /> वर सेट आहे. ते बरोबर आहे? नसलà¥à¤¯à¤¾à¤¸, आपण आपलà¥à¤¯à¤¾ सिसà¥à¤Ÿà¥€à¤®à¤à¥‡ घडà¥à¤¯à¤¾à¤³ दà¥à¤°à¥‚सà¥à¤¤ आणि तà¥à¤¯à¤¾à¤¨à¤‚तर हे पृषà¥à¤  रीफà¥à¤°à¥‡à¤¶ करणे आवशà¥à¤¯à¤• आहे. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.}other{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" />असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° # दिवसांपूरà¥à¤µà¥€ कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. आपलà¥à¤¯à¤¾ संगणकाà¤à¥‡ घडà¥à¤¯à¤¾à¤³ सधà¥à¤¯à¤¾ <ph name="CURRENT_DATE" /> वर सेट आहे. ते बरोबर आहे? नसलà¥à¤¯à¤¾à¤¸, आपण आपलà¥à¤¯à¤¾ सिसà¥à¤Ÿà¥€à¤®à¤à¥‡ घडà¥à¤¯à¤¾à¤³ दà¥à¤°à¥‚सà¥à¤¤ आणि तà¥à¤¯à¤¾à¤¨à¤‚तर हे पृषà¥à¤  रीफà¥à¤°à¥‡à¤¶ करणे आवशà¥à¤¯à¤• आहे. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">कोणतेही UI विकलà¥à¤ª उपलबà¥à¤§ नाहीत</translation>
<translation id="2384307209577226199">à¤à¤‚टरपà¥à¤°à¤¾à¤‡à¤ डीफॉलà¥à¤Ÿ</translation>
-<translation id="238526402387145295">आपण <ph name="SITE" /> ला आतà¥à¤¤à¤¾ भेट देठशकत नाही कारण वेबसाइट <ph name="BEGIN_LINK" />HSTS वापरते<ph name="END_LINK" />. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£à¥‡ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥€ असतात, यामà¥à¤³à¥‡ हे पृषà¥à¤  कदाà¤à¤¿à¤¤ नंतर कारà¥à¤¯ करेल.</translation>
<translation id="2386255080630008482">सरà¥à¤µà¥à¤¹à¤°à¤à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ केले गेले.</translation>
<translation id="2392959068659972793">कोणतेही मूलà¥à¤¯ सेट केलà¥à¤¯à¤¾à¤¶à¤¿à¤µà¤¾à¤¯ धोरणे दरà¥à¤¶à¤µà¤¾</translation>
<translation id="2396249848217231973">&amp;हटवा पूरà¥à¤µà¤µà¤¤ करा</translation>
-<translation id="2413528052993050574">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कदाà¤à¤¿à¤¤ रदà¥à¤¦ केले असू शकते. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
<translation id="2455981314101692989">या वेबपृषà¥à¤ à¤¾à¤¨à¥‡ या फॉरà¥à¤®à¤•à¤°à¤¿à¤¤à¤¾ सà¥à¤µà¤¯à¤‚à¤à¤²à¤¿à¤¤à¤°à¤¿à¤¤à¥à¤¯à¤¾ भरणे अकà¥à¤·à¤® केले आहे.</translation>
+<translation id="2463739503403862330">भरून टाका</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />नेटवरà¥à¤• निदान à¤à¤¾à¤²à¤µà¤¿à¤£à¥‡<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">अवैध शोध URL.</translation>
<translation id="2491120439723279231">सरà¥à¤µà¥à¤¹à¤°à¤à¥à¤¯à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤¾à¤¤ तà¥à¤°à¥à¤Ÿà¥€ आहेत.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">सबमिट करा</translation>
<translation id="2674170444375937751">आपली खातà¥à¤°à¥€ आहे की आपण ही पृषà¥à¤ à¥‡ आपलà¥â€à¤¯à¤¾ इतिहासातून हटवू इà¤à¥à¤›à¤¿à¤¤à¤¾?</translation>
<translation id="2677748264148917807">सोडा</translation>
+<translation id="269990154133806163">सरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पारदरà¥à¤¶à¤•à¤¤à¤¾ धोरणाà¤à¤¾ वापर करून सारà¥à¤µà¤œà¤¨à¤¿à¤•à¤°à¤¿à¤¤à¥à¤¯à¤¾ उघड न केलेले à¤à¤• पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले. काही पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ आहेत आणि आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤‚विरूदà¥à¤§ संरकà¥à¤·à¤£ करतात हे सà¥à¤¨à¤¿à¤¶à¥à¤à¤¿à¤¤ करणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ तà¥à¤¯à¤¾à¤‚à¤à¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ ही à¤à¤• आवशà¥à¤¯à¤•à¤¤à¤¾ आहे. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">मूलà¥à¤¯ सà¥à¤µà¤°à¥à¤ªà¤¨à¤¾à¤¶à¥€ जà¥à¤³à¤¤ नाही.</translation>
<translation id="2704951214193499422">Chromium यावेळी आपलà¥à¤¯à¤¾ कारà¥à¤¡à¤à¥€ पà¥à¤·à¥à¤Ÿà¥€ करणà¥à¤¯à¤¾à¤¤ अकà¥à¤·à¤® होते. कृपया नंतर पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="2705137772291741111">या साइटà¤à¥€ जतन (कॅशे केलेली) केलेली पà¥à¤°à¤¤ वाà¤à¤£à¥à¤¯à¤¾à¤œà¥‹à¤—ी नवà¥à¤¹à¤¤à¥€.</translation>
<translation id="2709516037105925701">ऑटोफिल</translation>
+<translation id="2712118517637785082">आपण <ph name="DOMAIN" /> वर पोहोà¤à¤£à¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला, परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ सादर केलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° तà¥à¤¯à¤¾à¤à¥à¤¯à¤¾ जारीकरà¥à¤¤à¥à¤¯à¤¾à¤¦à¥à¤µà¤¾à¤°à¥‡ मागे घेतले गेले आहे. याà¤à¤¾ अरà¥à¤¥ सरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ सादर केलेलà¥à¤¯à¤¾ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤²à¤µà¤° अजिबात विशà¥à¤µà¤¾à¤¸ ठेठनये. आपण कदाà¤à¤¿à¤¤ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¶à¥€ संपà¥à¤°à¥‡à¤·à¤£ करत आहात. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">परवानगी मागा</translation>
<translation id="2721148159707890343">विनंती यशसà¥à¤µà¥€</translation>
<translation id="2728127805433021124">सरà¥à¤µà¥à¤¹à¤°à¤à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कमकà¥à¤µà¤¤ सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€ अलà¥à¤—ोरिदम वापरून सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¤¿à¤¤ केले आहे.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">पतà¥à¤¤à¤¾ आणि शोध बार</translation>
<translation id="2826760142808435982">कनेकà¥à¤¶à¤¨ <ph name="CIPHER" /> वापरून आणि की विनिमय तंतà¥à¤° मà¥à¤¹à¤£à¥‚न <ph name="KX" /> वापर कूटबदà¥à¤§ आणि पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¥ƒà¤¤ केले आहे.</translation>
<translation id="2835170189407361413">फॉरà¥à¤® कà¥à¤²à¤¿à¤…र करा</translation>
-<translation id="2837049386027881519">TLS किंवा SSL पà¥à¤°à¥‹à¤Ÿà¥‰à¤•à¥‰à¤²à¤à¥€ जà¥à¤¨à¥€ आवृतà¥à¤¤à¥€ वापरून कनेकà¥à¤¶à¤¨ पà¥à¤¨à¤°à¥à¤ªà¥à¤°à¤¯à¤¤à¥à¤¨ केला. असे विशेषकरून तेवà¥à¤¹à¤¾à¤ होते जेवà¥à¤¹à¤¾ सरà¥à¤µà¥à¤¹à¤° खूपठजà¥à¤¨à¥‡ सॉफà¥à¤Ÿà¤µà¥‡à¤…र वापरत आहे आणि इतर सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ समसà¥à¤¯à¤¾ येत असू शकतात.</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> वरील सरà¥à¤µà¥à¤¹à¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° खोटे असलà¥à¤¯à¤¾à¤à¥‡ दिसते.</translation>
<translation id="2889159643044928134">रीलोड करॠनका</translation>
-<translation id="2896499918916051536">हे पà¥à¤²à¤—िन समरà¥à¤¥à¤¿à¤¤ नाही.</translation>
+<translation id="2900469785430194048">हे वेबपृषà¥à¤  पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ करणà¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करताना Google Chrome à¤à¥€ मेमरी संपली आहे.</translation>
<translation id="2909946352844186028">à¤à¤• नेटवरà¥à¤• बदल आढळला.</translation>
-<translation id="2915500479781995473">हे सरà¥à¤µà¥à¤¹à¤° ते <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकले नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡ आहे. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. आपलà¥à¤¯à¤¾ संगणकाà¤à¥‡ घडà¥à¤¯à¤¾à¤³ सधà¥à¤¯à¤¾ <ph name="CURRENT_TIME" /> वर सेट केले आहे. ते बरोबर वाटते आहे? नसलà¥à¤¯à¤¾à¤¸, आपण आपलà¥à¤¯à¤¾ पà¥à¤°à¤£à¤¾à¤²à¥€à¤à¥‡ घडà¥à¤¯à¤¾à¤³ दà¥à¤°à¥à¤¸à¥à¤¤ करावे आणि नंतर हे पृषà¥à¤  रीफà¥à¤°à¥‡à¤¶ करावे.</translation>
<translation id="2922350208395188000">सरà¥à¤µà¥à¤¹à¤°à¤à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° तपासणे शकà¥à¤¯ नाही.</translation>
-<translation id="2941952326391522266">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° <ph name="DOMAIN2" /> वरील आहे. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
<translation id="2948083400971632585">आपण सेटिंगà¥à¤œ पृषà¥à¤ à¤¾à¤µà¤°à¥‚न à¤à¤•à¤¾ कनेकà¥à¤¶à¤¨à¤¸à¤¾à¤ à¥€ कॉनà¥à¤«à¤¿à¤—र केलेले कोणतेही पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ अकà¥à¤·à¤® करू शकता.</translation>
<translation id="2955913368246107853">शोध बार बंद करा</translation>
<translation id="2958431318199492670">नेटवरà¥à¤• कॉनà¥à¤«à¤¿à¤—रेशन ONC मानकाà¤à¥‡ पालन करत नाही. कॉनà¥à¤«à¤¿à¤—रेशनà¤à¥‡ भाग आयात केले जाठशकत नाहीत.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">à¤à¥à¤•à¥€à¤à¤¾ धोरण पà¥à¤°à¤•à¤¾à¤°</translation>
<translation id="3032412215588512954">आपण ही साइट पà¥à¤¨à¥à¤¹à¤¾ रीलोड करू इà¤à¥à¤›à¤¿à¤¤à¤¾?</translation>
<translation id="3037605927509011580">à¤à¥à¤à¤•!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{संकालित डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤µà¤° किमान 1 आयटम}=1{1 आयटम (आणि संकालित डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤µà¤° आणखी)}one{# आयटम (आणि संकालित डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤µà¤° आणखी)}other{# आयटम (आणि संकालित डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤µà¤° आणखी)}}</translation>
<translation id="3041612393474885105">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° माहिती...</translation>
<translation id="3063697135517575841">Chrome यावेळी आपलà¥à¤¯à¤¾ कारà¥à¤¡à¤à¥€ पà¥à¤·à¥à¤Ÿà¥€ करणà¥à¤¯à¤¾à¤¤ अकà¥à¤·à¤® होते. कृपया नंतर पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="3093245981617870298">आपण ऑफलाइन आहात.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">नवीनâ€à¤¤à¤®</translation>
<translation id="3207960819495026254">बà¥à¤•à¤®à¤¾à¤°à¥à¤• केलेली</translation>
-<translation id="3225919329040284222">सरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ असे पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले आहे जे अंगभूत अपेकà¥à¤·à¤¾à¤‚शी जà¥à¤³à¤¤ नाही. या अपेकà¥à¤·à¤¾ आपलà¥à¤¯à¤¾à¤²à¤¾ संरकà¥à¤·à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ विशिषà¥à¤Ÿ, उà¤à¥à¤-सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¥‡à¤à¥à¤¯à¤¾ वेबसाइटसाठी समाविषà¥à¤Ÿ केलà¥à¤¯à¤¾ आहेत.</translation>
<translation id="3226128629678568754">पृषà¥à¤  लोड करणà¥à¤¯à¤¾à¤¸ आवशà¥à¤¯à¤• असलेला डेटा पà¥à¤¨à¥à¤¹à¤¾ सबमिट करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ रीलोड बटण दाबा.</translation>
<translation id="3228969707346345236">वà¥à¤¯à¤µà¤¹à¤¾à¤° अयशसà¥à¤µà¥€ à¤à¤¾à¤²à¤¾ कारण पृषà¥à¤  पूरà¥à¤µà¥€à¤ªà¤¾à¤¸à¥‚न <ph name="LANGUAGE" /> मधà¥à¤¯à¥‡ आहे.</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" /> साठी CVC पà¥à¤°à¤µà¤¿à¤·à¥â€à¤Ÿ करा</translation>
<translation id="3254409185687681395">या पृषà¥à¤ à¤¾à¤¸ बà¥à¤•à¤®à¤¾à¤°à¥à¤• करा</translation>
<translation id="3270847123878663523">&amp;पà¥à¤¨à¤°à¥à¤•à¥à¤°à¤®à¤¿à¤¤ करा पूरà¥à¤µà¤µà¤¤ करा</translation>
<translation id="3286538390144397061">तà¥à¤µà¤°à¤¿à¤¤ रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करा</translation>
+<translation id="3303855915957856445">कोणतेही शोध परिणाम आढळले नाहीत</translation>
<translation id="3305707030755673451">आपला डेटा आपलà¥à¤¯à¤¾ संकालन सांकेतिक वाकà¥à¤¯à¤¾à¤‚शासह <ph name="TIME" /> वाजता कूटबदà¥à¤§ केला होता. संकालन सà¥à¤°à¥ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ तो पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा.</translation>
<translation id="333371639341676808">अतिरिकà¥à¤¤ संवाद तयार करणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न या पृषà¥à¤ à¤¾à¤²à¤¾ पà¥à¤°à¤¤à¤¿à¤¬à¤‚धित करा.</translation>
+<translation id="3338095232262050444">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤</translation>
<translation id="3340978935015468852">सेटिंगà¥à¤œ</translation>
<translation id="3345135638360864351">या साइटवर पà¥à¤°à¤µà¥‡à¤¶ करणà¥à¤¯à¤¾à¤à¥€ आपली विनंती <ph name="NAME" /> कडे पाठविली जाठशकली नाही. कृपया पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="3355823806454867987">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सेटिंगà¥à¤œ बदला...</translation>
@@ -232,14 +236,16 @@
<translation id="3452404311384756672">मधà¥à¤¯à¤‚तर पà¥à¤°à¤¾à¤ªà¥à¤¤ करा:</translation>
<translation id="3462200631372590220">पà¥à¤°à¤—त लपवा</translation>
<translation id="3479539252931486093">हे अनपेकà¥à¤·à¤¿à¤¤ होते? <ph name="BEGIN_LINK" />आमà¥à¤¹à¤¾à¤²à¤¾ कळवा<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">सधà¥à¤¯à¤¾ नाही</translation>
<translation id="348000606199325318">कà¥à¤°à¥…श ID <ph name="CRASH_LOCAL_ID" /> (सरà¥à¤µà¥à¤¹à¤° ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">याकà¥à¤·à¤£à¥€ आमà¥à¤¹à¥€ आपलà¥à¤¯à¤¾ पालकांपरà¥à¤¯à¤‚त पोहोà¤à¥‚ शकलो नाही. कृपया पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="3527085408025491307">फोलà¥à¤¡à¤°</translation>
<translation id="3528171143076753409">सरà¥à¤µà¥à¤¹à¤°à¤à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° विशà¥à¤µà¤¾à¤¸à¤¨à¥€à¤¯ नाही.</translation>
<translation id="3539171420378717834">या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° या कारà¥à¤¡à¤à¥€ à¤à¤• पà¥à¤°à¤¤ ठेवा</translation>
<translation id="3542684924769048008">यासाठी संकेतशबà¥à¤¦ वापरा:</translation>
-<translation id="3549644494707163724">आपलà¥à¤¯à¤¾ सà¥à¤µà¤¤à¤ƒà¤à¥à¤¯à¤¾ वाकà¥à¤¯à¤¾à¤‚शासह सरà¥à¤µ समकà¥à¤°à¤®à¤¿à¤¤ केलेला डेटा कूटबदà¥à¤§ करा</translation>
+<translation id="3549644494707163724">आपलà¥à¤¯à¤¾ सà¥à¤µà¤¤à¤ƒà¤à¥à¤¯à¤¾ वाकà¥à¤¯à¤¾à¤‚शासह सरà¥à¤µ संंकालित केलेला डेटा कूटबदà¥à¤§ करा</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> अधिक...</translation>
+<translation id="3555561725129903880">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; याà¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° <ph name="DOMAIN2" /> कडून आलेले आहे. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">आपले कनेकà¥à¤¶à¤¨ खाजगी नाही</translation>
<translation id="3583757800736429874">&amp;हलवा पà¥à¤¨à¥à¤¹à¤¾ करा</translation>
<translation id="3586931643579894722">तपशील लपवा</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">मूलà¥à¤¯ दरà¥à¤¶à¤µà¤¾</translation>
<translation id="3630155396527302611">नेटवरà¥à¤•à¤µà¤° पà¥à¤°à¤µà¥‡à¤¶ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ अनà¥à¤®à¤¤à¥€ दिलेला पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® मà¥à¤¹à¤£à¥‚न तो आधीपासून सूà¤à¥€à¤¬à¤¦à¥à¤§ केला असलà¥à¤¯à¤¾à¤¸
तो सूà¤à¥€à¤®à¤§à¥‚न काढा आणि पà¥à¤¨à¥à¤¹à¤¾ जोडून पहा.</translation>
+<translation id="3638794133396384728">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡ आहे. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. आपलà¥à¤¯à¤¾ संगणकाà¤à¥‡ घडà¥à¤¯à¤¾à¤³ सधà¥à¤¯à¤¾ <ph name="CURRENT_TIME" /> वर सेट केले आहे. ते बरोबर वाटते आहे? नसलà¥à¤¯à¤¾à¤¸, आपण आपलà¥à¤¯à¤¾ पà¥à¤°à¤£à¤¾à¤²à¥€à¤à¥‡ घडà¥à¤¯à¤¾à¤³ दà¥à¤°à¥à¤¸à¥à¤¤ करावे आणि नंतर हे पृषà¥à¤  रीफà¥à¤°à¥‡à¤¶ करावे. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">ही पà¥à¤°à¤¾à¤¯à¥‹à¤—िक वैशिषà¥à¤Ÿà¥à¤¯à¥‡ कधीही बदलू, खंडित होठकिंवा अदृशà¥à¤¯ होठशकतात. आपण या पà¥à¤°à¤¯à¥‹à¤—ांपैकी à¤à¤•à¤¹à¥€ à¤à¤¾à¤²à¥‚ ठेवलà¥à¤¯à¤¾à¤¸ काय होठशकते याबदà¥à¤¦à¤² आमà¥à¤¹à¥€ निशà¥à¤à¤¿à¤¤à¤ªà¤£à¥‡ कोणतीही हमी वà¥à¤¯à¤•à¥à¤¤ करत नाही आणि आपला बà¥à¤°à¤¾à¤‰à¤à¤° कदाà¤à¤¿à¤¤ आपोआप पेटू शकतो. à¤à¥‡à¤·à¥à¤Ÿà¤¾ सोडून दà¥à¤¯à¤¾, आपला बà¥à¤°à¤¾à¤‰à¤à¤° आपला सरà¥à¤µ डेटा हटवू शकतो, किंवा आपली सà¥à¤°à¤•à¥à¤·à¤¾ आणि गोपनीयतेशी अनपेकà¥à¤·à¤¿à¤¤ मारà¥à¤—ांनी तडजोड केली जाठशकते. आपण सकà¥à¤·à¤® केलेले कोणतेही पà¥à¤°à¤¯à¥‹à¤— या बà¥à¤°à¤¾à¤‰à¤à¤°à¤à¥à¤¯à¤¾ सरà¥à¤µ वापरकरà¥à¤¤à¥à¤¯à¤¾à¤‚साठी सकà¥à¤·à¤® केले जातील. कृपया सावधगिरीने पà¥à¤¢à¥‡ जा.</translation>
<translation id="3650584904733503804">पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£ यशसà¥à¤µà¥€</translation>
<translation id="3655670868607891010">आपण हे वारंवार पहात असलà¥à¤¯à¤¾à¤¸, हे वापरून पहा <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">पà¥à¤¨à¤°à¤¾à¤µà¥ƒà¤¤à¥à¤¤à¥€</translation>
+<translation id="3678029195006412963">विनंती सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€à¤•à¥ƒà¤¤ करणे शकà¥à¤¯ à¤à¤¾à¤²à¥‡ नाही</translation>
<translation id="3681007416295224113">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° माहिती...</translation>
<translation id="3693415264595406141">संकेतशबà¥à¤¦:</translation>
+<translation id="3696411085566228381">काहीही नाही</translation>
<translation id="3700528541715530410">अरेरे, असे दिसते की आपलà¥à¤¯à¤¾à¤²à¤¾ या पृषà¥à¤ à¤¾à¤µà¤° पà¥à¤°à¤µà¥‡à¤¶ करणà¥à¤¯à¤¾à¤¸ परवानगी नाही.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">लोड करीत आहे...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">मोबाइल डेटा किंवा Wi-Fi à¤à¤¾à¤²à¥‚ करणे</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€, फायरवॉल आणि DNS कॉनà¥à¤«à¤¿à¤—रेशन तपासणे<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">आपण कॉपी केलेलà¥à¤¯à¤¾à¤à¤¾ दà¥à¤µà¤¾ जोडा</translation>
-<translation id="3744899669254331632">Chromium पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾ करू शकत नसलेले सरमिसळ केलेले कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥â€à¤¶à¤¿à¤¯à¤² वेबसाइटने पाठविलà¥â€à¤¯à¤¾à¤¨à¥‡ आपण आतà¥à¤¤à¤¾ <ph name="SITE" /> ला भेट देठशकत नाही. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£ सहसा तातà¥à¤ªà¥à¤°à¤¤à¥‡ आहेत तà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ संभवत: हे पृषà¥â€à¤  नंतर कारà¥à¤¯ करेल.</translation>
<translation id="375403751935624634">सरà¥à¤µà¥à¤¹à¤° तà¥à¤°à¥à¤Ÿà¥€à¤®à¥à¤³à¥‡ भाषांतर अयशसà¥à¤µà¥€ à¤à¤¾à¤²à¤¾.</translation>
<translation id="3759461132968374835">आपण अलीकडे कोणतेही कà¥à¤°à¥…श नोंदवले नाहीत. कà¥à¤°à¥…श नोंदवणे अकà¥à¤·à¤® असताना à¤à¤¾à¤²à¥‡à¤²à¥‡ कà¥à¤°à¥…श येथे दिसून येणार नाहीत.</translation>
<translation id="3788090790273268753">या साइटसाठी असलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° 2016 मधà¥â€à¤¯à¥‡ कालबाहà¥à¤¯ होते आणि पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° शà¥à¤°à¥ƒà¤‚खलेमधà¥â€à¤¯à¥‡ SHA-1 वापरून सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€ केलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° असते.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">संघरà¥à¤· करणारा डिवà¥à¤¹à¤¾à¤‡à¤¸ अभिजà¥à¤à¤¾à¤ªà¤•</translation>
<translation id="3885155851504623709">पॅरिश</translation>
<translation id="3901925938762663762">कारà¥à¤¡ कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡ आहे</translation>
+<translation id="3910267023907260648">आपण <ph name="DOMAIN" /> वर पोहोà¤à¤£à¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ à¤à¤–ादà¥à¤¯à¤¾ कमकूवत सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€ अलà¥à¤—ोरिदमà¤à¤¾ वापर करून सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€à¤•à¥ƒà¤¤ केलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले. याà¤à¤¾ अरà¥à¤¥ असा आहे की सरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ सादर केलेली सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤² बनावट असू शकतात आणि आपण अपेकà¥à¤·à¤¾ करीत असलेला सरà¥à¤µà¥à¤¹à¤° हा नसावा (आपण कदाà¤à¤¿à¤¤ à¤à¤–ादà¥à¤¯à¤¾ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¸à¤¹ संपà¥à¤°à¥‡à¤·à¤£ करीत आहात). <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° उदà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न मानले जाईल. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.}one{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤¢à¥€à¤² # दिवसांपासून मानले जाईल. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.}other{हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤¢à¥€à¤² # दिवसांपासून मानले जाईल. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF दसà¥à¤¤à¤à¤µà¤œ लोड करणे अयशसà¥à¤µà¥€</translation>
<translation id="3963721102035795474">वाà¤à¤• मोड</translation>
+<translation id="397105322502079400">गणना करत आहे...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> अवरोधित केले आहे</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{जवळपास 1 वेब पृषà¥â€à¤ }one{जवळपास # वेब पृषà¥â€à¤ }other{जवळपास # वेब पृषà¥à¤ à¥‡}}</translation>
<translation id="4021036232240155012">DNS ही नेटवरà¥à¤• सेवा आहे जी वेबसाइटà¤à¥‡ नाव तिà¤à¥à¤¯à¤¾ इंटरनेट पतà¥à¤¤à¥à¤¯à¤¾à¤®à¤§à¥â€à¤¯à¥‡ भाषांतरित करते.</translation>
<translation id="4030383055268325496">&amp;जोडा पूरà¥à¤µà¤µà¤¤ करा</translation>
-<translation id="4032534284272647190"><ph name="URL" /> वर पà¥à¤°à¤µà¥‡à¤¶ नाकारला.</translation>
<translation id="404928562651467259">à¤à¥‡à¤¤à¤¾à¤µà¤£à¥€:</translation>
<translation id="4058922952496707368">की "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">कà¥à¤²à¤¾à¤¯à¤‚ट आणि सरà¥à¤µà¥à¤¹à¤° à¤à¤• सामानà¥à¤¯ SSL पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤² आवृतà¥à¤¤à¥€ किंवा सायफर संà¤à¤¾à¤à¥‡ समरà¥à¤¥à¤¨ करीत नाही.</translation>
<translation id="4079302484614802869">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉनà¥à¤«à¤¿à¤—रेशन .pac सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ URL वापरणà¥â€à¤¯à¤¾à¤¸ सेट करणà¥â€à¤¯à¤¾à¤¤ आले आहे, निशà¥à¤à¤¿à¤¤ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤° नवà¥à¤¹à¥‡.</translation>
<translation id="4103249731201008433">डिवà¥à¤¹à¤¾à¤‡à¤¸ सिरीयल कà¥à¤°à¤®à¤¾à¤‚क अवैध आहे</translation>
<translation id="4103763322291513355">आपलà¥à¤¯à¤¾ सिसà¥à¤Ÿà¥€à¤® पà¥à¤°à¤¶à¤¾à¤¸à¤•à¤¾à¤¦à¥à¤µà¤¾à¤°à¥‡ पà¥à¤°à¤µà¤°à¥à¤¤à¤¿à¤¤ काळà¥à¤¯à¤¾à¤¸à¥‚à¤à¥€à¤¤à¥€à¤² URLs आणि अनà¥à¤¯ धोरणांà¤à¥€ सूà¤à¥€ पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ &lt;strong&gt;chrome://policy&lt;/strong&gt; ला भेट दà¥à¤¯à¤¾.</translation>
+<translation id="4110615724604346410">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; याà¤à¥à¤¯à¤¾ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤¾à¤®à¤§à¥à¤¯à¥‡ तà¥à¤°à¥à¤Ÿà¥€ आहेत. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">धोरण ककà¥à¤·à¤¾ समरà¥à¤¥à¤¿à¤¤ नाही.</translation>
+<translation id="4118212371799607889">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> हे असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; याà¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° Chromium दà¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही; हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{अनà¥à¤¯ 1}one{अनà¥à¤¯ #}other{अनà¥à¤¯ #}}</translation>
<translation id="4130226655945681476">नेटवरà¥à¤• केबल, मोडेम आणि राउटर तपासत आहे</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromium ने हे कारà¥à¤¡ जतन करावे असे आपण इà¤à¥à¤›à¤¿à¤¤à¤¾?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">अकà¥à¤·à¤®</translation>
<translation id="4196861286325780578">&amp;हलवा पà¥à¤¨à¥à¤¹à¤¾ करा</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />फायरवॉल आणि अà¤à¤Ÿà¥€à¤µà¥à¤¹à¤¾à¤¯à¤°à¤¸ कॉनà¥à¤«à¤¿à¤—रेशन तपासणे<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{काहीही नाही}=1{1 अâ€à¥…प ($1)}=2{2 अâ€à¥…पà¥à¤¸ ($1, $2)}one{# अâ€à¥…पà¥à¤¸ ($1, $2, $3)}other{# अâ€à¥…पà¥à¤¸ ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">कà¥à¤°à¥…श होते</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />नेटवरà¥à¤• निदान à¤à¤¾à¤²à¤µà¥‚न पहा<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">नाही</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(वापरकरà¥à¤¤à¤¾à¤¨à¤¾à¤µ नाही)</translation>
<translation id="4300246636397505754">पालक सूà¤à¤¨à¤¾</translation>
<translation id="4304224509867189079">लॉग इन</translation>
+<translation id="432290197980158659">सरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले जे अंगभूत अपेकà¥à¤·à¤¾à¤‚शी जà¥à¤³à¤¤ नाही. या अपेकà¥à¤·à¤¾ आपलà¥à¤¯à¤¾à¤²à¤¾ संरकà¥à¤·à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ विशिषà¥à¤Ÿ, उà¤à¥à¤-सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¥‡à¤à¥à¤¯à¤¾ वेबसाइटसाठी समाविषà¥à¤Ÿ केलà¥à¤¯à¤¾ आहेत. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">लेख शोधणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€</translation>
+<translation id="4331708818696583467">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नाही</translation>
<translation id="4372948949327679948">अपेकà¥à¤·à¤¿à¤¤ <ph name="VALUE_TYPE" /> मूलà¥à¤¯.</translation>
-<translation id="4377125064752653719">आपण <ph name="DOMAIN" /> वर पोहोà¤à¤£à¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला, परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ सादर केलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° तà¥à¤¯à¤¾à¤à¥à¤¯à¤¾ जारीकरà¥à¤¤à¥à¤¯à¤¾à¤¦à¥à¤µà¤¾à¤°à¥‡ मागे घेतले गेले आहे. याà¤à¤¾ अरà¥à¤¥ सरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ सादर केलेलà¥à¤¯à¤¾ सà¥à¤°à¤•à¥à¤·à¤¾ कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤²à¤µà¤° अजिबात ठेवला जाठनये. आपण कदाà¤à¤¿à¤¤ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¶à¥€ संपà¥à¤°à¥‡à¤·à¤£ करत आहात.</translation>
<translation id="4381091992796011497">वापरकरà¥à¤¤à¤¾ नाव:</translation>
<translation id="4394049700291259645">अकà¥à¤·à¤® करा</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> ते <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">शोध परिणाम</translation>
-<translation id="4424024547088906515">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° Chrome दà¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> ने आपले लॉग इन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सà¥à¤µà¥€à¤•à¤¾à¤°à¤²à¥‡ नाही किंवा कदाà¤à¤¿à¤¤ पà¥à¤°à¤¦à¤¾à¤¨ केले गेले नसावे.</translation>
<translation id="443673843213245140">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€à¤à¤¾ वापर अकà¥à¤·à¤® करणà¥â€à¤¯à¤¾à¤¤ आला आहे पण à¤à¤• सà¥à¤¸à¥à¤ªà¤·à¥â€à¤Ÿ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉनà¥â€à¤«à¤¿à¤—रेशन निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤¤ आले आहे.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">आपलà¥à¤¯à¤¾à¤²à¤¾ हा संदेश दिसत आहे कारण Google SafeSites सकà¥à¤·à¤® केलेली आहे.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">तपशील</translation>
<translation id="4558551763791394412">आपले विसà¥à¤¤à¤¾à¤° अकà¥à¤·à¤® करून पहा.</translation>
<translation id="4587425331216688090">Chrome मधून पतà¥à¤¤à¤¾ काढायà¤à¤¾?</translation>
+<translation id="4589078953350245614">आपण <ph name="DOMAIN" /> येथे पोहोà¤à¤£à¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला, परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ अवैध पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">आपले <ph name="DOMAIN" /> वरील कनेकà¥à¤¶à¤¨ आधà¥à¤¨à¤¿à¤• सायफर सूट वापरून कूटबदà¥à¤§ केलेले आहे.</translation>
<translation id="4594403342090139922">&amp;हटवा पूरà¥à¤µà¤µà¤¤ करा</translation>
+<translation id="4627442949885028695">दà¥à¤¸à¤°à¥â€à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸ वरून सà¥à¤°à¥ ठेवा</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">आपण à¤à¤• विसà¥à¤¤à¤¾à¤° पृषà¥à¤  पाहत आहात.</translation>
-<translation id="467662567472608290">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥à¤¯à¤¾ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤¾à¤¤ तà¥à¤°à¥à¤Ÿà¥€ आहेत. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> अवरोधित करणà¥â€à¤¯à¤¾à¤¤ आली</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">आपलà¥à¤¯à¤¾ कनेकà¥à¤¶à¤¨à¤®à¤§à¥à¤¯à¥‡ वà¥à¤¯à¤¤à¥à¤¯à¤¯ आला</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows नेटवरà¥à¤• निदान à¤à¤¾à¤²à¤µà¤¿à¤£à¥‡<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">पà¥à¤²à¥…टफॉरà¥à¤®</translation>
<translation id="4744603770635761495">कारà¥à¤¯à¤µà¤¾à¤¹à¥€à¤¯à¥‹à¤—à¥à¤¯ पथ</translation>
<translation id="4756388243121344051">&amp;इतिहास</translation>
+<translation id="4759238208242260848">डाउनलोड</translation>
<translation id="4764776831041365478"><ph name="URL" /> येथील वेबपृषà¥à¤  कदाà¤à¤¿à¤¤ तातà¥à¤ªà¥à¤°à¤¤à¥‡ बंद आहे किंवा ते कदाà¤à¤¿à¤¤ कायमà¤à¥‡ नवीन वेब पतà¥à¤¤à¥à¤¯à¤¾à¤µà¤° हलवले आहे.</translation>
<translation id="4771973620359291008">à¤à¤• अजà¥à¤à¤¾à¤¤ तà¥à¤°à¥à¤Ÿà¥€ आली आहे.</translation>
<translation id="4782449893814226250">या पृषà¥â€à¤ à¤¾à¤¸ भेट देणे ठीक आहे का ते आपण आपलà¥â€à¤¯à¤¾ पालकांना विà¤à¤¾à¤°à¤²à¥‡.</translation>
<translation id="4800132727771399293">आपली कालबाहà¥à¤¯à¤¤à¤¾ तारीख आणि CVC तपासा आणि पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा</translation>
-<translation id="4807049035289105102">Google Chrome पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾ करू शकत नाही असे न समजणारे कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤² वेबसाइटने पाठविलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ आपण आतà¥à¤¤à¤¾ <ph name="SITE" /> ला भेट देठशकत नाही. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥‡ असतात, यामà¥à¤³à¥‡ हे पृषà¥à¤  कदाà¤à¤¿à¤¤ नंतर कारà¥à¤¯ करेल.</translation>
<translation id="4813512666221746211">नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€</translation>
<translation id="4816492930507672669">पृषà¥â€à¤ à¤¾à¤¨à¥à¤°à¥à¤ª करा</translation>
<translation id="4850886885716139402">पहा</translation>
<translation id="4880827082731008257">इतिहास शोध</translation>
+<translation id="4884656795097055129">योगà¥à¤¯ वेळ असते तेवà¥à¤¹à¤¾ आणखी लेख दिसतील.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{आणि 1 आणखी वेब पृषà¥à¤ }one{आणि # आणखी वेब पृषà¥â€à¤ }other{आणि # आणखी वेब पृषà¥à¤ à¥‡}}</translation>
<translation id="4923417429809017348">हे पृषà¥à¤  अजà¥à¤à¤¾à¤¤ भाषेतून <ph name="LANGUAGE_LANGUAGE" /> मधà¥à¤¯à¥‡ अनà¥à¤µà¤¾à¤¦à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¤ आले</translation>
<translation id="4926049483395192435">निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ केले जाणे आवशà¥â€à¤¯à¤• आहे.</translation>
<translation id="4930497775425430760">आपलà¥à¤¯à¤¾à¤²à¤¾ हा संदेश दिसत आहे कारण नवीन साइटà¤à¥à¤¯à¤¾ आपलà¥à¤¯à¤¾ पà¥à¤°à¤¥à¤® भेटीवर आपलà¥à¤¯à¤¾ पालकाने मंजूरी देणे आवशà¥à¤¯à¤• आहे.</translation>
<translation id="495170559598752135">कà¥à¤°à¤¿à¤¯à¤¾</translation>
<translation id="4958444002117714549">सूà¤à¥€ विसà¥à¤¤à¥ƒà¤¤ करा</translation>
+<translation id="4962322354953122629">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; याà¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° Chrome दà¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही; हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911"><ph name="ORIGINAL_LANGUAGE" /> मधून <ph name="TARGET_LANGUAGE" /> मधà¥à¤¯à¥‡ भाषांतरित करायà¤à¥‡?</translation>
+<translation id="4989809363548539747">हे पà¥à¤²à¤—िन समरà¥à¤¥à¤¿à¤¤ नाही</translation>
<translation id="5002932099480077015">सकà¥à¤·à¤® केलà¥â€à¤¯à¤¾à¤¸, Chrome जलदपणे फॉरà¥à¤® भरणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ आपलà¥â€à¤¯à¤¾ कारà¥à¤¡à¤à¥€ à¤à¤• पà¥à¤°à¤¤ या डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¤µà¤° संगà¥à¤°à¤¹à¤¿à¤¤ करेल.</translation>
<translation id="5019198164206649151">समरà¥à¤¥à¤¨ संà¤à¤¯à¤¨ खराब सà¥à¤¥à¤¿à¤¤à¥€à¤¤</translation>
<translation id="5023310440958281426">आपलà¥à¤¯à¤¾ पà¥à¤°à¤¶à¤¾à¤¸à¤•à¤¾à¤à¥€ धोरणे तपासा</translation>
@@ -358,14 +379,13 @@
<translation id="5031870354684148875">Google भाषांतर बदà¥à¤¦à¤²</translation>
<translation id="5040262127954254034">गोपनीयता</translation>
<translation id="5045550434625856497">अयोगà¥à¤¯ संकेतशबà¥à¤¦</translation>
+<translation id="5056549851600133418">आपलà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ लेख</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ पतà¥à¤¤à¤¾ तपासणे<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">यावेळी सरà¥à¤µà¥à¤¹à¤°à¤à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° वैध नाही.</translation>
<translation id="5089810972385038852">राजà¥à¤¯</translation>
-<translation id="5094747076828555589">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° Chromium दà¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
<translation id="5095208057601539847">पà¥à¤°à¤¾à¤‚त</translation>
<translation id="5115563688576182185">(64-बिट)</translation>
-<translation id="5122371513570456792">'<ph name="SEARCH_STRING" />' साठी <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> आढळले.</translation>
-<translation id="5141240743006678641">आपलà¥à¤¯à¤¾ Google कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤²à¤¸à¤¹ समकà¥à¤°à¤®à¤¿à¤¤ केलेले संकेतशबà¥à¤¦ कूटबदà¥à¤§ करा</translation>
+<translation id="5141240743006678641">आपलà¥à¤¯à¤¾ Google कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤²à¤¸à¤¹ संंकालित केलेले संकेतशबà¥à¤¦ कूटबदà¥à¤§ करा</translation>
<translation id="5145883236150621069">धोरण पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦à¤¾à¤®à¤§à¥à¤¯à¥‡ तà¥à¤°à¥à¤Ÿà¥€ कोड असà¥à¤¤à¤¿à¤¤à¥à¤µà¤¾à¤¤ आहे</translation>
<translation id="5171045022955879922">URL शोधा किंवा टाइप करा</translation>
<translation id="5172758083709347301">मशीन</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">बà¥à¤•à¤®à¤¾à¤°à¥à¤• बार</translation>
<translation id="5199729219167945352">पà¥à¤°à¤¯à¥‹à¤—</translation>
<translation id="5251803541071282808">मेघ</translation>
+<translation id="5277279256032773186">कारà¥à¤¯à¤¸à¥à¤¥à¤¾à¤¨à¥€ Chrome वापरत आहात? वà¥à¤¯à¤µà¤¸à¤¾à¤¯ तà¥à¤¯à¤¾à¤‚à¤à¥à¤¯à¤¾ करà¥à¤®à¤à¤¾à¤°à¥â€à¤¯à¤¾à¤‚ंसाठी Chrome सेटिंगà¥à¤œ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करू शकतात. अधिक जाणनू घà¥à¤¯à¤¾</translation>
<translation id="5299298092464848405">धोरण विशà¥à¤²à¥‡à¤·à¤¿à¤¤ करताना तà¥à¤°à¥à¤Ÿà¥€</translation>
<translation id="5300589172476337783">दरà¥à¤¶à¤µà¤¾</translation>
<translation id="5308689395849655368">कà¥à¤°à¥…श अहवाल अकà¥à¤·à¤® केला गेला आहे.</translation>
<translation id="5317780077021120954">जतन करा</translation>
<translation id="5327248766486351172">नाव</translation>
+<translation id="5359637492792381994">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> हे असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; याà¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° यावेळी वैध नाही हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">धोरण सेटिंगà¥à¤œ संà¤à¤¯à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€</translation>
-<translation id="540969355065856584">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° यावेळी वैध नाही. हे कदाà¤à¤¿à¤¤ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित करीत असलà¥â€à¤¯à¤¾à¤®à¥à¤³à¥‡ होठशकते.</translation>
<translation id="5421136146218899937">बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग डेटा साफ करा...</translation>
<translation id="5430298929874300616">बà¥à¤•à¤®à¤¾à¤°à¥à¤• काढा</translation>
<translation id="5431657950005405462">आपली फाईल आढळली नाही</translation>
<translation id="5435775191620395718">या डिवà¥à¤¹à¤¾à¤‡à¤¸ वरील इतिहास दरà¥à¤¶à¤µà¤¿à¤¤ आहे. <ph name="BEGIN_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">आपला संकालित केलेला डेटा सानà¥à¤•à¥‚लित सांकेतिक वाकà¥à¤¯à¤¾à¤‚शाने संरकà¥à¤·à¤¿à¤¤ केला असलà¥à¤¯à¤¾à¤¨à¥‡ वैयकà¥à¤¤à¥€à¤•à¥ƒà¤¤ सामगà¥à¤°à¥€ सूà¤à¤¨à¤¾ सधà¥à¤¯à¤¾ अकà¥à¤·à¤® केलà¥à¤¯à¤¾ आहेत.</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" वर सà¥à¤•à¥€à¤®à¤¾ पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£ तà¥à¤°à¥à¤Ÿà¥€: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">हे <ph name="HOST_NAME" /> पृषà¥à¤  शोधले जाठशकत नाही</translation>
<translation id="5455374756549232013">खराब धोरण टाइमसà¥à¤Ÿà¤à¤ª</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">आपण ही साइट सोडू इà¤à¥à¤›à¤¿à¤¤à¤¾?</translation>
<translation id="5629630648637658800">धोरण सेटिंगà¥à¤œ लोड करणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€</translation>
<translation id="5631439013527180824">अवैध डिवà¥à¤¹à¤¾à¤‡à¤¸ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ टोकन</translation>
-<translation id="5650551054760837876">शोध परिणाम आढळले नाहीत.</translation>
<translation id="5677928146339483299">अवरोधित</translation>
<translation id="5710435578057952990">या वेबसाइटà¤à¥€ ओळख सतà¥à¤¯à¤¾à¤ªà¤¿à¤¤ केली गेली नाही.</translation>
<translation id="5720705177508910913">वरà¥à¤¤à¤®à¤¾à¤¨ वापरकरà¥à¤¤à¤¾</translation>
+<translation id="572328651809341494">अलीकडील टॅब</translation>
<translation id="5784606427469807560">आपलà¥à¤¯à¤¾ कारà¥à¤¡à¤à¥€ पà¥à¤·à¥à¤Ÿà¥€ करताना समसà¥à¤¯à¤¾ आली. आपले इंटरनेट कनेकà¥à¤¶à¤¨ तपासा आणि पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="5785756445106461925">पà¥à¤¢à¥‡, या पृषà¥à¤ à¤¾à¤¤ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नसलेली इतर संसाधने समाविषà¥à¤Ÿ आहेत. ही संसाधने संकà¥à¤°à¤®à¤£à¤¾à¤¤ असताना इतरांदà¥à¤µà¤¾à¤°à¥‡ पाहिली जाठशकतात आणि पृषà¥à¤ à¤¾à¤à¥‡ सà¥à¤µà¤°à¥‚प बदलणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¦à¥à¤µà¤¾à¤°à¥‡ सà¥à¤§à¤¾à¤°à¤¿à¤¤ केली जाठशकतात.</translation>
+<translation id="5786044859038896871">आपण आपली कारà¥à¤¡ माहिती भरू इà¤à¥à¤›à¤¿à¤¤ आहात?</translation>
+<translation id="5803412860119678065">आपण आपले <ph name="CARD_DETAIL" /> भरू इà¤à¥à¤›à¤¿à¤¤ आहात?</translation>
<translation id="5810442152076338065">आपले <ph name="DOMAIN" /> वरील कनेकà¥à¤¶à¤¨ अपà¥à¤°à¤à¤²à¤¿à¤¤ सायफर सूट वापरून कूटबदà¥à¤§ केलेले आहे.</translation>
<translation id="5813119285467412249">&amp;जोडा पà¥à¤¨à¥à¤¹à¤¾ करा</translation>
+<translation id="5814352347845180253">आपण <ph name="SITE" /> आणि काही अनà¥à¤¯ साइट मधील मà¥à¤–à¥à¤¯ सामगà¥à¤°à¥€ मधील पà¥à¤°à¤µà¥‡à¤¶ कदाà¤à¤¿à¤¤ गमवाल.</translation>
+<translation id="5843436854350372569">आपण <ph name="DOMAIN" /> वर पोहोà¤à¤£à¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला, परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ à¤à¤• कमकà¥à¤µà¤¤ की असलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले. आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ खाजगी की तोडलेली असू शकते आणि सरà¥à¤µà¥à¤¹à¤° हे आपलà¥à¤¯à¤¾à¤²à¤¾ अपेकà¥à¤·à¤¿à¤¤ असणारे सरà¥à¤µà¥à¤¹à¤° नसू शकते (आपण कदाà¤à¤¿à¤¤ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¶à¥€ संपà¥à¤°à¥‡à¤·à¤£ करत असाल) <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">आपलà¥à¤¯à¤¾à¤²à¤¾ हा संदेश दिसत आहे कारण आपलà¥à¤¯à¤¾ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤•à¤¾à¤¨à¥‡ ही साइट अवरोधित केली आहे.</translation>
<translation id="5857090052475505287">नवीन फोलà¥à¤¡à¤°</translation>
<translation id="5869405914158311789">या साइटवर पोहà¤à¤£à¥‡ शकà¥à¤¯ नाही</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">पालक सूà¤à¤¨à¤¾</translation>
<translation id="59107663811261420">कारà¥à¤¡à¤à¤¾ हा पà¥à¤°à¤•à¤¾à¤° या वà¥à¤¯à¤¾à¤ªà¤¾à¤°à¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ Google Payments दà¥à¤µà¤¾à¤°à¥‡ समरà¥à¤¥à¤¿à¤¤ नाही. कृपया à¤à¤• भिनà¥à¤¨ कारà¥à¤¡ निवडा.</translation>
<translation id="59174027418879706">सकà¥à¤·à¤® केलेले</translation>
+<translation id="5926846154125914413">आपण काही साइट मधील मà¥à¤–à¥à¤¯ सामगà¥à¤°à¥€ मधील पà¥à¤°à¤µà¥‡à¤¶ कदाà¤à¤¿à¤¤ गमवाल.</translation>
<translation id="5966707198760109579">आठवडा</translation>
<translation id="5967867314010545767">इतिहासातून काढा</translation>
<translation id="5975083100439434680">à¤à¥‚म कमी करा</translation>
@@ -433,13 +458,13 @@
<translation id="604124094241169006">सà¥à¤µà¤¯à¤‚à¤à¤²à¤¿à¤¤</translation>
<translation id="6042308850641462728">अधिक</translation>
<translation id="6060685159320643512">सावधगिरी बाळगा, या पà¥à¤°à¤¯à¥‹à¤—ांमà¥à¤³à¥‡ हानी होठशकते</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{काहीही नाही}=1{1}one{#}other{#}}</translation>
<translation id="6146055958333702838">कोणतà¥à¤¯à¤¾à¤¹à¥€ केबल तपासा आणि कोणतेही राउटर, मोडेम किंवा आपण
वापरत असलेले
अनà¥à¤¯ नेटवरà¥à¤• डिवà¥à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸ रीबूट करा.</translation>
<translation id="614940544461990577">हे करून पहा:</translation>
<translation id="6150607114729249911">अरेरे! या पृषà¥â€à¤ à¤¾à¤¸ भेट देणे ठीक आहे का ते आपलà¥â€à¤¯à¤¾ पालकांना विà¤à¤¾à¤°à¤£à¥â€à¤¯à¤¾à¤à¥€ आपलà¥â€à¤¯à¤¾à¤²à¤¾ आवशà¥â€à¤¯à¤•à¤¤à¤¾ आहे.</translation>
<translation id="6151417162996330722">सरà¥à¤µà¥à¤¹à¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤¾à¤¸ वैधता कालावधी आहे जो खूप मोठा आहे.</translation>
-<translation id="6154808779448689242">परत केलेले धोरण टोकन वरà¥à¤¤à¤®à¤¾à¤¨ टोकनशी जà¥à¤³à¤¤ नाही</translation>
<translation id="6165508094623778733">अधिक जाणून घà¥à¤¯à¤¾</translation>
<translation id="6203231073485539293">आपले इंटरनेट कनेकà¥à¤¶à¤¨ तपासा</translation>
<translation id="6218753634732582820">Chromium वरून पतà¥à¤¤à¤¾ काढायà¤à¤¾?</translation>
@@ -452,24 +477,30 @@
<translation id="6328639280570009161">नेटवरà¥à¤• पूरà¥à¤µà¤¾à¤¨à¥à¤®à¤¾à¤¨ अकà¥à¤·à¤® करून पहा</translation>
<translation id="6337534724793800597">धोरणे नावानà¥à¤¸à¤¾à¤° फिलà¥à¤Ÿà¤° करा</translation>
<translation id="6342069812937806050">आतà¥à¤¤à¤¾à¤</translation>
+<translation id="6345221851280129312">अजà¥à¤à¤¾à¤¤ आकार</translation>
<translation id="6355080345576803305">सारà¥à¤µà¤œà¤¨à¤¿à¤• सतà¥à¤° अधिशूनà¥à¤¯</translation>
<translation id="6358450015545214790">याà¤à¤¾ अरà¥à¤¥ काय आहे?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 अनà¥à¤¯ सूà¤à¤¨à¤¾}one{# अनà¥à¤¯ सूà¤à¤¨à¤¾}other{# अनà¥à¤¯ सूà¤à¤¨à¤¾}}</translation>
<translation id="6387478394221739770">छान नवीन Chrome वैशिषà¥à¤Ÿà¥à¤¯à¤¾à¤‚मधà¥à¤¯à¥‡ सà¥à¤µà¤¾à¤°à¤¸à¥à¤¯ आहे? chrome.com/beta वरील आमà¤à¥‡ बीटा à¤à¥…नेल वापरून पहा.</translation>
-<translation id="641480858134062906"><ph name="URL" /> लोड करणà¥â€à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€</translation>
+<translation id="6389758589412724634">हे वेबपृषà¥à¤  पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ करणà¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करताना Chromium à¤à¥€ मेमरी संपली आहे.</translation>
+<translation id="6416403317709441254">Chromium पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾ करू शकत नसलेले न समजणारे कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤² वेबसाइटने पाठविलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ आपण आतà¥à¤¤à¤¾ <ph name="SITE" /> ला भेट देठशकत नाही. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥‡ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥‡ असतात, यामà¥à¤³à¥‡ हे पृषà¥à¤  कदाà¤à¤¿à¤¤ नंतर कारà¥à¤¯ करेल. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° मागे घेतले की नाही हे तपासणà¥à¤¯à¤¾à¤¤ अकà¥à¤·à¤®.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> नी कनेकà¥à¤Ÿ करणà¥à¤¯à¤¾à¤¸ नकार दिला.</translation>
<translation id="6445051938772793705">देश</translation>
<translation id="6451458296329894277">फॉरà¥à¤® रीसबमिशनà¤à¥€ पà¥à¤·à¥à¤Ÿà¥€ करा</translation>
<translation id="6458467102616083041">धोरणानà¥à¤¸à¤¾à¤° डीफॉलà¥à¤Ÿ शोध अकà¥à¤·à¤® केलà¥à¤¯à¤¾à¤¨à¥‡ दà¥à¤°à¥à¤²à¤•à¥à¤· करणà¥â€à¤¯à¤¾à¤¤ आले.</translation>
+<translation id="6462969404041126431">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> हे असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; याà¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ केले असावे. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">डिवà¥à¤¹à¤¾à¤‡à¤¸ धोरणे</translation>
<translation id="6489534406876378309">कà¥à¤°à¥…श अपलोड करणे पà¥à¤°à¤¾à¤°à¤‚भ करा</translation>
<translation id="6529602333819889595">&amp;पà¥à¤¨à¥à¤¹à¤¾ करा हटवा</translation>
+<translation id="6534179046333460208">वासà¥à¤¤à¤µà¤¿à¤• वेब सूà¤à¤¨à¤¾</translation>
<translation id="6550675742724504774">परà¥à¤¯à¤¾à¤¯</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" /> पेकà¥à¤·à¤¾ कमी</translation>
<translation id="6596325263575161958">कूटबदà¥à¤§à¤¤à¤¾ परà¥à¤¯à¤¾à¤¯</translation>
<translation id="662080504995468778">यावर रहा</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> शोध</translation>
-<translation id="6634865548447745291"><ph name="BEGIN_LINK" />हे पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° रदà¥à¤¦ केले गेलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡<ph name="END_LINK" /> आपण आतà¥à¤¤à¤¾ <ph name="SITE" /> ला भेट देठशकत नाही. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£à¥‡ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥€ असतात, यामà¥à¤³à¥‡ हे पृषà¥à¤  कदाà¤à¤¿à¤¤ नंतर कारà¥à¤¯ करेल.</translation>
<translation id="6644283850729428850">हे धोरण नापसंत आहे.</translation>
+<translation id="6652240803263749613">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> हे असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; याà¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपलà¥à¤¯à¤¾ संगणकाà¤à¥à¤¯à¤¾ ऑपरेटिंग पà¥à¤°à¤£à¤¾à¤²à¥€à¤¦à¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही; हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">फोलà¥à¤¡à¤° संपादित करा</translation>
<translation id="6660210980321319655">सà¥à¤µà¤¯à¤‚à¤à¤²à¤¿à¤¤à¤ªà¤£à¥‡ <ph name="CRASH_TIME" /> वाजता अहवाल दिला</translation>
<translation id="6671697161687535275">Chromium वरून फॉरà¥à¤® सूà¤à¤¨à¤¾ काढायà¤à¥à¤¯à¤¾?</translation>
@@ -477,6 +508,7 @@
<translation id="6710213216561001401">मागील</translation>
<translation id="6710594484020273272">&lt;शोध संजà¥à¤à¤¾ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा&gt;</translation>
<translation id="6711464428925977395">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤°à¤®à¤§à¥à¤¯à¥‡ काहीतरी à¤à¥à¤•à¥€à¤à¥‡ आहे किंवा पतà¥à¤¤à¤¾ à¤à¥à¤•à¥€à¤à¤¾ आहे.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{काहीही नाही}=1{1 आयटम}one{# आयटम}other{# आयटम}}</translation>
<translation id="674375294223700098">अजà¥à¤à¤¾à¤¤ सरà¥à¤µà¥à¤¹à¤° पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° तà¥à¤°à¥à¤Ÿà¥€.</translation>
<translation id="6753269504797312559">धोरण मूलà¥à¤¯</translation>
<translation id="6757797048963528358">आपले डिवà¥à¤¹à¤¾à¤‡à¤¸ निषà¥à¤•à¥à¤°à¥€à¤¯ à¤à¤¾à¤²à¥‡.</translation>
@@ -488,7 +520,6 @@
<translation id="6891596781022320156">धोरण सà¥à¤¤à¤° समरà¥à¤¥à¤¿à¤¤ नाही.</translation>
<translation id="6895330447102777224">आपलà¥à¤¯à¤¾ कारà¥à¤¡à¤à¥€ पà¥à¤·à¥à¤Ÿà¥€ केली</translation>
<translation id="6897140037006041989">वापरकरà¥à¤¤à¤¾ à¤à¤œà¤‚ट</translation>
-<translation id="6903907808598579934">सिंक à¤à¤¾à¤²à¥‚ करा</translation>
<translation id="6915804003454593391">वापरकरà¥à¤¤à¤¾:</translation>
<translation id="6957887021205513506">सरà¥à¤µà¥à¤¹à¤°à¤à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° खोटे असलà¥à¤¯à¤¾à¤à¥‡ दिसून येते.</translation>
<translation id="6965382102122355670">ठीक आहे</translation>
@@ -496,9 +527,11 @@
<translation id="6970216967273061347">â€à¤œà¤¿à¤²à¥â€à¤¹à¤¾</translation>
<translation id="6973656660372572881">निशà¥à¤à¤¿à¤¤ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤° आणि .pac सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ URL निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤¤ आले आहेत.</translation>
<translation id="6989763994942163495">पà¥à¤°à¤—त सेटिंगà¥à¤œ दरà¥à¤¶à¤µà¤¾...</translation>
+<translation id="7000990526846637657">कोणतà¥à¤¯à¤¾à¤¹à¥€ इतिहास पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¥€ सापडलà¥à¤¯à¤¾ नाहीत</translation>
+<translation id="7009986207543992532">आपण <ph name="DOMAIN" /> येथे पोहोà¤à¤£à¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला, परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ असे पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले जà¥à¤¯à¤¾à¤à¤¾ वैधता कालावधी विशà¥à¤µà¤¾à¤¸à¤¾à¤°à¥à¤¹à¤¤à¥‡à¤¸à¤¾à¤ à¥€ खूप मोठा आहे. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">आपलà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤¤ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> वर बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग इतिहासाà¤à¥€ अनà¥à¤¯ सà¥à¤µà¤°à¥‚पे असू शकतात</translation>
<translation id="7029809446516969842">संकेतशबà¥à¤¦</translation>
-<translation id="7050187094878475250">आपण <ph name="DOMAIN" /> वर पोहोà¤à¤£à¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला, परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ à¤à¤• पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले आहे जà¥à¤¯à¤¾à¤à¤¾ वैधता कालावधी हा विशà¥à¤µà¤¾à¤¸à¤¾à¤°à¥à¤¹à¤¤à¥‡à¤¸à¤¾à¤ à¥€ खूप मोठा आहे.</translation>
<translation id="7087282848513945231">परगणा</translation>
<translation id="7088615885725309056">थोडा जà¥à¤¨à¤¾</translation>
<translation id="7090678807593890770">Google वर <ph name="LINK" /> शोधा</translation>
@@ -517,13 +550,13 @@
<translation id="7246609911581847514">आपलà¥à¤¯à¤¾à¤²à¤¾ हा संदेश दिसत आहे कारण नवीन साइटà¤à¥à¤¯à¤¾ आपलà¥à¤¯à¤¾ पà¥à¤°à¤¥à¤® भेटीवर आपलà¥à¤¯à¤¾ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤•à¤¾à¤¨à¥‡ मंजूरी देणे आवशà¥à¤¯à¤• आहे.</translation>
<translation id="724975217298816891">आपले कारà¥à¤¡ तपशील अदà¥à¤¯à¤¤à¤¨à¤¿à¤¤ करणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ <ph name="CREDIT_CARD" /> करिता कालबाहà¥à¤¯à¤¤à¤¾ तारीख आणि CVC पà¥à¤°à¤µà¤¿à¤·à¥â€à¤Ÿ करा. आपण पà¥à¤·à¥à¤Ÿà¥€ केलà¥à¤¯à¤¾à¤µà¤°, आपले कारà¥à¤¡ तपशील या साइटसह सामायिक केले जातील.</translation>
<translation id="725866823122871198">आपलà¥à¤¯à¤¾ संगणकाà¤à¥€ तारीख आणि वेळ (<ph name="DATE_AND_TIME" />) à¤à¥à¤•à¥€à¤à¥€ असलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> सह खाजगी कनेकà¥à¤¶à¤¨ सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ केले जाठशकत नाही.</translation>
-<translation id="7265986070661382626">वेबसाइट <ph name="BEGIN_LINK" />पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पिनिंग वापरत असलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡<ph name="END_LINK" /> आपण <ph name="SITE" /> ला आतà¥à¤¤à¤¾ भेट देठशकत नाही. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥‡ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥‡ असतात, यामà¥à¤³à¥‡ हे पृषà¥à¤  कदाà¤à¤¿à¤¤ नंतर कारà¥à¤¯ करेल.</translation>
<translation id="7269802741830436641">या वेबपृषà¥à¤ à¤¾à¤²à¤¾ पà¥à¤¨à¤°à¥à¤¨à¤¿à¤°à¥à¤¦à¥‡à¤¶à¤¿à¤¤ पळवाट आहे</translation>
<translation id="7275334191706090484">वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ केलेले बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="7298195798382681320">शिफारस केलेले</translation>
-<translation id="7301833672208172928">इतिहास संकालन à¤à¤¾à¤²à¥‚ करा</translation>
+<translation id="7309308571273880165"><ph name="CRASH_TIME" /> वाजता कà¥à¤°à¥…श अहवाल कॅपà¥à¤à¤° केला (वापरकरà¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ विनंती केलेले अपलोड, अदà¥à¤¯à¤¾à¤ª अपलोड केलेले नाही)</translation>
<translation id="7334320624316649418">&amp;पà¥à¤¨à¤°à¥à¤•à¥à¤°à¤®à¤¿à¤¤ करा पà¥à¤¨à¥à¤¹à¤¾ करा</translation>
<translation id="733923710415886693">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पारदरà¥à¤¶à¤•à¤¤à¥‡à¤¦à¥à¤µà¤¾à¤°à¥‡ सरà¥à¤µà¥à¤¹à¤°à¤à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° उघड केले नाही.</translation>
+<translation id="7351800657706554155">हे पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ केले गेलà¥à¤¯à¤¾à¤¨à¥‡ आपण आतà¥à¤¤à¤¾ <ph name="SITE" /> ला भेट देठशकत नाही. नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¥€ आणि आकà¥à¤°à¤®à¤£à¥‡ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥€ असतात, तà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ हे पृषà¥à¤  कदाà¤à¤¿à¤¤ नंतर कारà¥à¤¯ करेल. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">कमांड लाइन</translation>
<translation id="7372973238305370288">शोध परिणाम</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -542,16 +575,17 @@
<translation id="7469372306589899959">कारà¥à¤¡à¤à¥€ पà¥à¤·à¥à¤Ÿà¥€ करीत आहे</translation>
<translation id="7481312909269577407">पà¥à¤¢à¥€à¤²</translation>
<translation id="7485870689360869515">डेटा आढळला नाही.</translation>
+<translation id="7508255263130623398">परत केलेला धोरण डिवà¥à¤¹à¤¾à¤‡à¤¸ ID रिकà¥à¤¤ आहे किंवा वरà¥à¤¤à¤®à¤¾à¤¨ डिवà¥à¤¹à¤¾à¤‡à¤¸ ID शी जà¥à¤³à¤¤ नाही</translation>
<translation id="7514365320538308">डाउनलोड करा</translation>
<translation id="7518003948725431193">या वेबपतà¥à¤¤à¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ वेबपृषà¥à¤  आढळले नाही: <ph name="URL" /></translation>
<translation id="7537536606612762813">अनिवारà¥à¤¯</translation>
<translation id="7542995811387359312">सà¥à¤µà¤¯à¤‚à¤à¤²à¤¿à¤¤ कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ भरणे अकà¥à¤·à¤® à¤à¤¾à¤²à¥‡ आहे कारण हा फॉरà¥à¤® सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥à¤¶à¤¨ वापरत नाही.</translation>
<translation id="7549584377607005141">हे वेबपृषà¥à¤  योगà¥à¤¯à¤°à¤¿à¤¤à¥€à¤¨à¥‡ पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ केले जाणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ आपण पूरà¥à¤µà¥€ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ केलेला डेटा आवशà¥à¤¯à¤• आहे. आपण हा डेटा पà¥à¤¨à¥à¤¹à¤¾ पाठवू शकता, परंतॠअसे केलà¥à¤¯à¤¾à¤¨à¥‡ या पृषà¥à¤ à¤¾à¤¨à¥‡ मागे केलेली कोणतà¥à¤¯à¤¾à¤¹à¥€ कà¥à¤°à¤¿à¤¯à¥‡à¤à¥€ पà¥à¤¨à¤°à¤¾à¤µà¥ƒà¤¤à¥à¤¤à¥€ आपण कराल.</translation>
<translation id="7554791636758816595">नवीन टॅब</translation>
-<translation id="7567204685887185387">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कदाà¤à¤¿à¤¤ लबाडीने जारी केले असावे. हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
<translation id="7568593326407688803">हे पृषà¥à¤ <ph name="ORIGINAL_LANGUAGE" />मधà¥à¤¯à¥‡ आहे आपण याà¤à¤¾ भाषांतर करॠइà¤à¥à¤›à¤¿à¤¤à¤¾?</translation>
<translation id="7569952961197462199">Chrome मधून कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ काढायà¤à¥‡?</translation>
<translation id="7578104083680115302">आपण Google सह जतन केलेलà¥à¤¯à¤¾ कारà¥à¤¡à¤à¤¾ वापर करून डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤µà¤°à¥‚न दà¥à¤°à¥à¤¤à¤ªà¤£à¥‡ साइट आणि अॅपà¥à¤¸à¤µà¤° देय दà¥à¤¯à¤¾.</translation>
+<translation id="7588950540487816470">भौतिक वेब</translation>
<translation id="7592362899630581445">सरà¥à¤µà¥à¤¹à¤°à¤à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° नाव मरà¥à¤¯à¤¾à¤¦à¤¾à¤‚à¤à¥‡ उलà¥à¤²à¤‚घन करते.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> सधà¥à¤¯à¤¾ ही विनंती हाताळणà¥à¤¯à¤¾à¤¤ अकà¥à¤·à¤® आहे.</translation>
<translation id="7600965453749440009">कधीही <ph name="LANGUAGE" /> à¤à¤¾ भाषांतर करॠनका</translation>
@@ -562,6 +596,7 @@
<translation id="7637571805876720304">Chromium वरून कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ काढायà¤à¥‡?</translation>
<translation id="765676359832457558">पà¥à¤°à¤—त सेटिंगà¥à¤œ लपवा...</translation>
<translation id="7658239707568436148">रदà¥à¤¦ करा</translation>
+<translation id="7667346355482952095">परत केलेले धोरण टोकन रिकà¥à¤¤ आहे किंवा वरà¥à¤¤à¤®à¤¾à¤¨ टोकनशी जà¥à¤³à¤¤ नाही</translation>
<translation id="7668654391829183341">अजà¥à¤à¤¾à¤¤ डिवà¥à¤¹à¤¾à¤‡à¤¸</translation>
<translation id="7674629440242451245">छान नवीन Chrome वैशिषà¥à¤Ÿà¥à¤¯à¤¾à¤‚मधà¥à¤¯à¥‡ सà¥à¤µà¤¾à¤°à¤¸à¥à¤¯ आहे? chrome.com/dev येथे आमà¤à¥‡ dev à¤à¥…नेल वापरून पहा.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /> <ph name="SITE" /> (असà¥à¤°à¤•à¥à¤·à¤¿à¤¤) वर सà¥à¤°à¥ ठेवा<ph name="END_LINK" /></translation>
@@ -578,10 +613,10 @@
<translation id="780301667611848630">नाही, धनà¥à¤¯à¤µà¤¾à¤¦</translation>
<translation id="7805768142964895445">सà¥à¤¥à¤¿à¤¤à¥€</translation>
<translation id="7813600968533626083">Chrome मधून सूà¤à¤¨à¤¾ फॉरà¥à¤® काढायà¤à¤¾?</translation>
+<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' साठी <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> सापडले</translation>
<translation id="785549533363645510">तथापि, आपण अदृशà¥à¤¯ नाही. गà¥à¤ªà¥à¤¤ à¤à¤¾à¤²à¥à¤¯à¤¾à¤¨à¥‡ आपले बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग आपला नियोकà¥à¤¤à¤¾, आपला इंटरनेट सेवा पà¥à¤°à¤¦à¤¾à¤¤à¤¾, किंवा आपण भेट देता तà¥à¤¯à¤¾ वेबसाइटपासून लपत नाही.</translation>
<translation id="7887683347370398519">आपले CVC तपासा आणि पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा</translation>
<translation id="7894616681410591072">अरेरे, या पृषà¥à¤ à¤¾à¤µà¤° पà¥à¤°à¤µà¥‡à¤¶ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ <ph name="NAME" /> दà¥à¤µà¤¾à¤°à¥‡ आपलà¥à¤¯à¤¾à¤²à¤¾ परवानगी आवशà¥à¤¯à¤• आहे.</translation>
-<translation id="790025292736025802"><ph name="URL" /> आढळली नाही</translation>
<translation id="7912024687060120840">फोलà¥à¤¡à¤°à¤®à¤§à¥â€à¤¯à¥‡:</translation>
<translation id="7920092496846849526">या पृषà¥â€à¤ à¤¾à¤¸ भेट देणे ठीक आहे का हे आपण आपलà¥â€à¤¯à¤¾ पालकांना विà¤à¤¾à¤°à¤²à¥‡.</translation>
<translation id="7935318582918952113">DOM डिसà¥à¤Ÿà¤¿à¤²à¤°</translation>
@@ -594,9 +629,10 @@
<translation id="7995512525968007366">निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ केलेले नाही</translation>
<translation id="8012647001091218357">आमà¥à¤¹à¥€ याकà¥à¤·à¤£à¥€ आपलà¥à¤¯à¤¾ पालकांपरà¥à¤¯à¤‚त पोहोà¤à¥‚ शकलो नाही. कृपया पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="8034522405403831421">हे पृषà¥â€à¤  <ph name="SOURCE_LANGUAGE" /> मधà¥à¤¯à¥‡ आहे. तà¥à¤¯à¤¾à¤¸ <ph name="TARGET_LANGUAGE" /> मधà¥à¤¯à¥‡ भाषांतरीत करायà¤à¥‡?</translation>
-<translation id="8034955203865359138">कोणतà¥à¤¯à¤¾à¤¹à¥€ इतिहास पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¥à¤¯à¤¾ आढळलà¥à¤¯à¤¾ नाहीत.</translation>
<translation id="8088680233425245692">लेख पाहणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€.</translation>
+<translation id="8089520772729574115">1 MB पेकà¥à¤·à¤¾ कमी</translation>
<translation id="8091372947890762290">सकà¥à¤°à¤¿à¤¯à¤•à¤°à¤£ सरà¥à¤µà¥à¤¹à¤°à¤µà¤° पà¥à¤°à¤²à¤‚बित आहे</translation>
+<translation id="8129262335948759431">अजà¥à¤à¤¾à¤¤ पà¥à¤°à¤®à¤¾à¤£</translation>
<translation id="8131740175452115882">पà¥à¤·à¥à¤Ÿà¥€ करा</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />à¤à¥‡ सरà¥à¤µà¥à¤¹à¤° <ph name="BEGIN_ABBR" />DNS पतà¥à¤¤à¤¾<ph name="END_ABBR" /> शोधणे शकà¥à¤¯ à¤à¤¾à¤²à¥‡ नाही.</translation>
<translation id="8149426793427495338">आपला संगणक निषà¥à¤•à¥à¤°à¥€à¤¯ à¤à¤¾à¤²à¤¾.</translation>
@@ -605,6 +641,7 @@
<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" ID असलेलà¥à¤¯à¤¾ विसà¥à¤¤à¤¾à¤°à¤¾à¤¸à¤¾à¤ à¥€ अवैध अदà¥à¤¯à¤¤à¤¨ URL.</translation>
<translation id="8218327578424803826">नियà¥à¤•à¥à¤¤ केलेले सà¥à¤¥à¤¾à¤¨:</translation>
<translation id="8225771182978767009">जà¥à¤¯à¤¾ वà¥à¤¯à¤•à¥à¤¤à¥€à¤¨à¥‡ हा संगणक सेट केला तà¥à¤¯à¤¾ वà¥à¤¯à¤•à¥à¤¤à¥€à¤¨à¥‡ ही साइट अवरोधित करणà¥à¤¯à¤¾à¤à¥‡ निवडले आहे.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">आपण जे पृषà¥à¤  शोधत आहत ते आपण पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ केलेली माहिती वापरत आहे. तà¥à¤¯à¤¾ पृषà¥à¤ à¤¾à¤•à¤¡à¥‡ परत गेलà¥à¤¯à¤¾à¤¸ कदाà¤à¤¿à¤¤ आपण केलेलà¥à¤¯à¤¾ कोणतà¥à¤¯à¤¾à¤¹à¥€ कà¥à¤°à¤¿à¤¯à¥‡à¤à¥€ पà¥à¤¨à¤°à¤¾à¤µà¥ƒà¤¤à¥à¤¤à¥€ होईल. आपण सà¥à¤°à¥‚ ठेवू इà¤à¥à¤›à¤¿à¤¤à¤¾?</translation>
<translation id="8249320324621329438">अंतिम पà¥à¤°à¤¾à¤ªà¥à¤¤ केलेले:</translation>
<translation id="8261506727792406068">हटवा</translation>
@@ -617,14 +654,19 @@
<translation id="8349305172487531364">बà¥à¤•à¤®à¤¾à¤°à¥à¤• बार</translation>
<translation id="8363502534493474904">विमान मोड बंद करा</translation>
<translation id="8364627913115013041">सेट केलेले नाही.</translation>
+<translation id="8380941800586852976">धोकादायक</translation>
<translation id="8412145213513410671">कà¥à¤°à¥…श (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">आपण समान सांकेतिक वाकà¥à¤¯à¤¾à¤‚श दोनदा पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करणे आवशà¥à¤¯à¤• आहे.</translation>
<translation id="8428213095426709021">सेटिंगà¥à¤œ</translation>
+<translation id="8433057134996913067">हे आपलà¥à¤¯à¤¾à¤²à¤¾ बहà¥à¤¤à¤¾à¤‚श वेबसाइट वरून साइन आउट करेल.</translation>
<translation id="8437238597147034694">&amp;हलवा पूरà¥à¤µà¤µà¤¤ करा</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}one{# कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}other{# कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡}}</translation>
+<translation id="8483780878231876732">आपलà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤µà¤°à¥‚न कारà¥à¤¡ वापरणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ Chrome मधà¥à¤¯à¥‡ साइन इन करा</translation>
<translation id="8488350697529856933">यावर लागू होते</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> नी पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦ देणà¥à¤¯à¤¾à¤¤ बराठवेळ घेतला.</translation>
+<translation id="852346902619691059">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> हे असलà¥à¤¯à¤¾à¤à¥‡ सिदà¥à¤§ करू शकला नाही; याà¤à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपलà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤à¥à¤¯à¤¾ ऑपरेटिंग पà¥à¤°à¤£à¤¾à¤²à¥€à¤¦à¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही; हे कदाà¤à¤¿à¤¤ à¤à¤•à¤¾ à¤à¥à¤•à¥€à¤à¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ आपले कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">या पà¥à¤°à¤•à¤¾à¤°à¤à¥‡ कारà¥à¤¡ Google Payments दà¥à¤µà¤¾à¤°à¥‡ समरà¥à¤¥à¤¿à¤¤ नाही. कृपया à¤à¤• भिनà¥à¤¨ कारà¥à¤¡ निवडा.</translation>
-<translation id="8550022383519221471">समकà¥à¤°à¤®à¤¿à¤¤ सेवा आपलà¥à¤¯à¤¾ डोमेनसाठी उपलबà¥à¤§ नाही.</translation>
+<translation id="8550022383519221471">संंकालित सेवा आपलà¥à¤¯à¤¾ डोमेनसाठी उपलबà¥à¤§ नाही.</translation>
<translation id="8553075262323480129">भाषांतर करणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€ कारण पृषà¥à¤ à¤¾à¤à¥€ भाषा निरà¥à¤§à¤¾à¤°à¤¿à¤¤ करणे शकà¥à¤¯ नाही.</translation>
<translation id="8559762987265718583">आपलà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤à¥€ तारीख आणि वेळ (<ph name="DATE_AND_TIME" />) à¤à¥à¤•à¥€à¤à¥€ असलà¥à¤¯à¤¾à¤¨à¥‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> सह खाजगी कनेकà¥à¤¶à¤¨ सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ केले जाठशकले नाही.</translation>
<translation id="856992080682148">या साइटसाठी असलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° 2017 किंवा तà¥à¤¯à¤¾à¤¨à¤‚तर कालबाहà¥à¤¯ होते आणि पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° शà¥à¤°à¥ƒà¤‚खलेमधà¥â€à¤¯à¥‡ SHA-1 वापरून सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€ केलेले पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° असते.</translation>
@@ -634,15 +676,12 @@
<translation id="8647750283161643317">सरà¥à¤µ डीफॉलà¥à¤Ÿà¤®à¤§à¥à¤¯à¥‡ रीसेट करा</translation>
<translation id="8680787084697685621">खाते साइन-इन तपशील कालबाहà¥à¤¯ à¤à¤¾à¤²à¤¾.</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> à¤à¥‡ आपले कनेकà¥à¤¶à¤¨ कूटबदà¥à¤§ केलेले नाही.</translation>
-<translation id="8713130696108419660">खराब मूळ सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€</translation>
<translation id="8725066075913043281">पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा</translation>
<translation id="8728672262656704056">आपण गà¥à¤ªà¥à¤¤ à¤à¤¾à¤²à¤¾ आहात</translation>
<translation id="8730621377337864115">पूरà¥à¤£ à¤à¤¾à¤²à¥‡</translation>
<translation id="8738058698779197622">à¤à¤• सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥â€à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€, आपले घडà¥â€à¤¯à¤¾à¤³ योगà¥à¤¯à¤°à¤¿à¤¤à¥à¤¯à¤¾ सेट केले असणे आवशà¥à¤¯à¤• आहे. कारण वेबसाइट तà¥à¤¯à¤¾à¤‚ना सà¥â€à¤µà¤¤:ला ओळखणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ वापरतात ती पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‡ केवळ निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ केलेलà¥â€à¤¯à¤¾ कालावधीसाठी वैध असतात. आपलà¥â€à¤¯à¤¾ डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¤à¥‡ घडà¥â€à¤¯à¤¾à¤³ à¤à¥à¤•à¥€à¤à¥‡ असलà¥â€à¤¯à¤¾à¤®à¥à¤³à¥‡, Chromium ही पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‡ सतà¥à¤¯à¤¾à¤ªà¤¿à¤¤ करू शकत नाही.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />à¤à¤¾ &lt;abbr id="dnsDefinition"&gt;DNS पतà¥à¤¤à¤¾&lt;/abbr&gt; शोधणे शकà¥à¤¯ à¤à¤¾à¤²à¥‡ नाही. समसà¥à¤¯à¥‡à¤à¥‡ निराकरण करीत आहे.</translation>
-<translation id="8741995161408053644">आपलà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤¤ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग इतिहासाà¤à¥€ इतर सà¥à¤µà¤°à¥‚पे <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> वर असू शकतात.</translation>
<translation id="8790007591277257123">&amp;पà¥à¤¨à¥à¤¹à¤¾ करा हटवा</translation>
-<translation id="8790687370365610530">Google ने सà¥à¤à¤µà¤¿à¤²à¥‡à¤²à¥€ वैयकà¥à¤¤à¥€à¤•à¥ƒà¤¤ सामगà¥à¤°à¥€ मिळविणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, इतिहास संकालन à¤à¤¾à¤²à¥‚ करा.</translation>
<translation id="8798099450830957504">डीफॉलà¥à¤Ÿ</translation>
<translation id="8804164990146287819">गोपनीयता धोरण</translation>
<translation id="8820817407110198400">Bookmarks</translation>
@@ -664,13 +703,11 @@
<translation id="8971063699422889582">सरà¥à¤µà¥à¤¹à¤°à¤à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡ आहे.</translation>
<translation id="8987927404178983737">महिना</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">सरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पारदरà¥à¤¶à¤•à¤¤à¤¾ धोरणाà¤à¤¾ वापर करून सारà¥à¤µà¤œà¤¨à¤¿à¤•à¤°à¤¿à¤¤à¥à¤¯à¤¾ उघड न केलेले à¤à¤• पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले. काही पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ आहेत आणि आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤‚विरूदà¥à¤§ संरकà¥à¤·à¤£ करतात हे सà¥à¤¨à¤¿à¤¶à¥à¤à¤¿à¤¤ करणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ तà¥à¤¯à¤¾à¤‚à¤à¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ ही à¤à¤• आवशà¥à¤¯à¤•à¤¤à¤¾ आहे.</translation>
<translation id="9001074447101275817">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ <ph name="DOMAIN" /> ला वापरकरà¥à¤¤à¤¾à¤¨à¤¾à¤µ आणि संकेतशबà¥à¤¦ आवशà¥à¤¯à¤• आहेत.</translation>
<translation id="901974403500617787">सिसà¥à¤Ÿà¥€à¤®-वà¥à¤¯à¤¾à¤ªà¥à¤¤ लागू होणारी धà¥à¤µà¤œà¤¾à¤‚कने केवळ मालकादà¥à¤µà¤¾à¤°à¥‡ सेट केली जाठशकतात: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">हे पृषà¥à¤  <ph name="TARGET_LANGUAGE" /> मधà¥à¤¯à¥‡ भाषांतरित केले गेले आहे.</translation>
<translation id="9038649477754266430">पृषà¥à¤ à¥‡ अधिक दà¥à¤°à¥à¤¤à¤ªà¤£à¥‡ लोड करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ पूरà¥à¤µà¤¾à¤¨à¥à¤®à¤¾à¤¨ सेवेà¤à¤¾ वापर करा</translation>
<translation id="9039213469156557790">पà¥à¤¢à¥‡, या पृषà¥à¤ à¤¾à¤¤ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नसलेली इतर संसाधने समाविषà¥à¤Ÿ आहेत. ही संसाधने संकà¥à¤°à¤®à¤£à¤¾à¤¤ असताना इतरांदà¥à¤µà¤¾à¤°à¥‡ पाहिली जाठशकतात आणि पृषà¥à¤ à¤¾à¤à¥‡ वरà¥à¤¤à¤¨ बदलणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¦à¥à¤µà¤¾à¤°à¥‡ सà¥à¤§à¤¾à¤°à¤¿à¤¤ केली जाठशकतात.</translation>
-<translation id="9049981332609050619">आपण <ph name="DOMAIN" /> वर पोहोà¤à¤£à¥à¤¯à¤¾à¤à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ केला, परंतॠसरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ अवैध पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सादर केले आहे.</translation>
<translation id="9050666287014529139">सांकेतिक वाकà¥à¤¯à¤¾à¤‚श</translation>
<translation id="9065203028668620118">संपादन</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> पृषà¥à¤  कारà¥à¤¯ करीत नाही</translation>
diff --git a/chromium/components/strings/components_strings_ms.xtb b/chromium/components/strings/components_strings_ms.xtb
index e49d35e1a6e..0b4fcf1adfb 100644
--- a/chromium/components/strings/components_strings_ms.xtb
+++ b/chromium/components/strings/components_strings_ms.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ms">
+<translation id="1008557486741366299">Bukan Sekarang</translation>
<translation id="1015730422737071372">Berikan butiran tambahan</translation>
<translation id="1032854598605920125">Putar ikut arah jam</translation>
<translation id="1038842779957582377">nama tidak diketahui</translation>
+<translation id="1053591932240354961">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini menghantar bukti kelayakan yang dicampuradukkan sehingga tidak dapat diproses oleh Google Chrome. Ralat rangkaian dan serangan biasanya bersifat sementara, oleh itu halaman ini mungkin akan berfungsi sebentar lagi. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Buat Asal Tambahkan</translation>
<translation id="10614374240317010">Tidak pernah disimpan</translation>
-<translation id="1064422015032085147">Pelayan yang mengehos halaman web mungkin sarat atau sedang diselenggara.
- Untuk mengelakkan penjanaan trafik yang terlalu banyak dan menyebabkan situasi ini semakin buruk,
- permintaan ke URL ini tidak dibenarkan untuk sementara waktu.</translation>
<translation id="106701514854093668">Penanda Halaman Desktop</translation>
<translation id="1080116354587839789">Muat ikut lebar</translation>
+<translation id="1103124106085518534">Selesai buat masa ini</translation>
<translation id="1103523840287552314">Sentiasa terjemahkan <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Jika ditandai, Chrome akan menyimpan salinan kad anda pada peranti ini untuk pengisian borang yang lebih cepat.</translation>
+<translation id="1111153019813902504">Penanda halaman terbaharu dilawati</translation>
<translation id="1113869188872983271">&amp;Buat asal susun semula</translation>
+<translation id="1126551341858583091">Saiz pada storan setempat ialah <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache dasar OK</translation>
<translation id="113188000913989374"><ph name="SITE" /> menyatakan:</translation>
<translation id="1132774398110320017">Tetapan Auto Isi Chrome...</translation>
-<translation id="1150979032973867961">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh sistem pengendalian komputer anda. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
<translation id="1152921474424827756">Akses <ph name="BEGIN_LINK" />salinan cache<ph name="END_LINK" /> <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> menutup sambungan tanpa di jangka.</translation>
<translation id="1161325031994447685">Menyambung semula kepada Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Buang</translation>
<translation id="1201402288615127009">Seterusnya</translation>
<translation id="1201895884277373915">Lagi dari tapak ini</translation>
-<translation id="121201262018556460">Anda cuba untuk mencapai <ph name="DOMAIN" /> , tetapi pelayan memberi sijil yang mengandungi kunci yang lemah, Penyerang mungkin telah merosakkan kunci peribadi dan pelayan tersebut mungkin bukan pelayan yang anda jangkakan (anda mungkin berkomunikasi dengan penyerang).</translation>
+<translation id="1206967143813997005">Tandatangan awal tidak sah</translation>
+<translation id="1209206284964581585">Sorok sementara</translation>
<translation id="1219129156119358924">Keselamatan Sistem</translation>
<translation id="1227224963052638717">Dasar tidak diketahui.</translation>
<translation id="1227633850867390598">Sembunyikan nilai</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Ya</translation>
<translation id="1430915738399379752">Cetak</translation>
<translation id="1442912890475371290">Percubaan <ph name="BEGIN_LINK" />untuk melawat halaman di <ph name="DOMAIN" /><ph name="END_LINK" /> disekat.</translation>
+<translation id="1491663344921578213">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini menggunakan penyematan sijil. Ralat rangkaian dan serangan biasanya bersifat sementara, oleh itu halaman ini mungkin akan berfungsi sebentar lagi. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Tunjukkan salinan yang disimpan (iaitu diketahui telah lapuk) bagi halaman ini.</translation>
<translation id="1519264250979466059">Tarikh Bina</translation>
<translation id="1549470594296187301">Javascript mesti didayakan untuk menggunakan ciri ini.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Konfigurasi rangkaian tidak sah dan tidak boleh diimport.</translation>
<translation id="1644574205037202324">Sejarah</translation>
<translation id="1645368109819982629">Protokol tidak disokong</translation>
-<translation id="1655462015569774233">{1,plural, =1{Pelayan ini tidak dapat membuktikan bahawa <ph name="DOMAIN" />; sijil keselamatannya tamat tempoh semalam. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. Jam komputer anda ditetapkan kepada <ph name="CURRENT_DATE" /> pada masa ini. Adakah itu betul? Jika tidak, anda perlu membetulkan jam sistem anda dan kemudian muat semula halaman ini.}other{Pelayan ini tidak dapat membuktikan bahawa <ph name="DOMAIN" />; sijil keselamatannya tamat tempoh # hari yang lalu. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. Jam komputer anda ditetapkan kepada <ph name="CURRENT_DATE" /> pada masa ini. Adakah itu betul? Jika tidak, anda perlu membetulkan jam sistem anda dan kemudian muat semula halaman ini.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> biasanya menggunakan penyulitan untuk melindungi maklumat anda. Apabila Google Chrome cuba menyambung ke <ph name="SITE" /> pada kali ini, tapak web tersebut mengembalikan bukti kelayakan yang luar biasa dan salah. Hal ini boleh berlaku apabila penyerang sedang cuba menyamar sebagai <ph name="SITE" /> atau skrin log masuk Wi-Fi telah memutuskan sambungan. Maklumat anda masih selamat kerana Google Chrome menghentikan sambungan sebelum sebarang pertukaran data berlaku.</translation>
<translation id="168841957122794586">Sijil pelayan mengandungi kunci kriptografi yang lemah.</translation>
<translation id="1701955595840307032">Dapatkan kandungan yang dicadangkan</translation>
-<translation id="1706954506755087368">{1,plural, =1{Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />;sijil keselamatannya sepatutnya bermula esok. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda.}other{Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya sepatutnya bermula # hari lagi. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Cuba hubungi pentadbir sistem.</translation>
<translation id="17513872634828108">Buka tab</translation>
<translation id="1753706481035618306">Nombor halaman</translation>
-<translation id="1761412452051366565">Untuk mendapatkan kandungan diperibadikan yang dicadangkan oleh Google, hidupkan penyegerakan.</translation>
-<translation id="1763864636252898013">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh sistem pengendalian peranti anda. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Cuba jalankan Diagnostik Rangkaian Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Sila kemas kini frasa laluan segerak anda.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Penanda halaman anda yang terbaharu dilawati dipaparkan di sini.</translation>
<translation id="1821930232296380041">Permintaan atau parameter permintaan tidak sah</translation>
<translation id="1838667051080421715">Anda sedang melihat sumber halaman web.</translation>
<translation id="1871208020102129563">Proksi ditetapkan untuk menggunakan pelayan proksi tetap, bukannya URL skrip .pac.</translation>
<translation id="1883255238294161206">Runtuhkan senarai</translation>
<translation id="1898423065542865115">Penapisan</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> tidak menerima sijil log masuk anda atau sijil log masuk anda telah tamat tempoh.</translation>
<translation id="194030505837763158">Pergi ke <ph name="LINK" /></translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> Penanda halaman</translation>
<translation id="1973335181906896915">Ralat penyirian</translation>
<translation id="1974060860693918893">Lanjutan</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{dan 1 lagi}other{dan # lagi}}</translation>
<translation id="2025186561304664664">Proksi ditetapkan kepada auto konfigurasi.</translation>
<translation id="2030481566774242610">Adakah anda maksudkan <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Anda melihat mesej ini kerana ibu bapa anda perlu meluluskan tapak baharu pada lawatan pertama anda.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Menyemak proksi dan tembok api<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Poskod</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 cadangan}other{# cadangan}}</translation>
<translation id="2065985942032347596">Pengesahan Diperlukan</translation>
<translation id="2079545284768500474">Buat asal</translation>
<translation id="20817612488360358">Tetapan proksi sistem telah sedia untuk digunakan tetapi konfigurasi proksi jelas juga telah ditentukan.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Edit Penanda Halaman</translation>
<translation id="2166049586286450108">Akses Penuh Pentadbir</translation>
<translation id="2166378884831602661">Tapak ini tidak dapat menyediakan sambungan yang selamat</translation>
-<translation id="2171101176734966184">Anda cuba untuk mencapai <ph name="DOMAIN" />, tetapi pelayan memberikan sijil yang ditandatangani menggunakan algoritma tandatangan yang lemah. Ini bermakna bahawa bukti kelayakan keselamatan yang diberi pelayan mungkin dipalsukan dan pelayan tersebut bukan seperti yang anda jangkakan (anda mungkin berkomunikasi dengan penyerang).</translation>
<translation id="2181821976797666341">Dasar</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 alamat}other{# alamat}}</translation>
<translation id="2212735316055980242">Dasar tidak dijumpai</translation>
<translation id="2213606439339815911">Mengambil entri…</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> tidak tersedia</translation>
<translation id="2230458221926704099">Betulkan sambungan anda menggunakan <ph name="BEGIN_LINK" />apl diagnostik<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Hantar sekarang</translation>
<translation id="225207911366869382">Nilai ini tidak lagi digunakan untuk dasar ini.</translation>
<translation id="2262243747453050782">Ralat HTTP</translation>
<translation id="2282872951544483773">Eksperimen Tidak Tersedia</translation>
<translation id="2292556288342944218">Akses Internet anda disekat</translation>
<translation id="229702904922032456">Sijil akar atau perantara telah tamat tempoh.</translation>
<translation id="230155334948463882">Kad baharu?</translation>
+<translation id="2305919008529760154">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya mungkin telah dikeluarkan secara penipuan. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> memerlukan nama pengguna dan kata laluan.</translation>
+<translation id="2318774815570432836">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini menggunakan HSTS. Ralat rangkaian dan serangan biasanya bersifat sementara, oleh itu halaman ini mungkin akan berfungsi sebentar lagi. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Mengabaikan penanda halaman tidak sah pada indeks <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Penanda halaman lain</translation>
<translation id="2359808026110333948">Teruskan</translation>
<translation id="2365563543831475020">Laporan ranap sistem yang dirakam pada <ph name="CRASH_TIME" /> tidak dimuat naik</translation>
<translation id="2367567093518048410">Tahap</translation>
+<translation id="2371153335857947666">{1,plural, =1{Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tamat tempoh semalam. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. Jam komputer anda ditetapkan kepada <ph name="CURRENT_DATE" /> pada masa ini. Adakah itu betul? Jika tidak, anda perlu membetulkan jam sistem anda dan kemudian muatkan semula halaman ini. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.}other{Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tamat tempoh # hari yang lalu. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. Jam komputer anda ditetapkan kepada <ph name="CURRENT_DATE" /> pada masa ini. Adakah itu betul? Jika tidak, anda perlu membetulkan jam sistem anda dan kemudian muatkan semula halaman ini. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Tiada alternatif UI tersedia</translation>
<translation id="2384307209577226199">Lalai perusahaan</translation>
-<translation id="238526402387145295">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini <ph name="BEGIN_LINK" />menggunakan HSTS<ph name="END_LINK" />. Ralat rangkaian dan serangan biasanya bersifat sementara oleh itu, halaman ini mungkin akan berfungsi sebentar lagi.</translation>
<translation id="2386255080630008482">Sijil pelayan telah dibatalkan.</translation>
<translation id="2392959068659972793">Paparkan dasar tanpa nilai yang ditetapkan</translation>
<translation id="2396249848217231973">&amp;Buat asal pemadaman</translation>
-<translation id="2413528052993050574">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya mungkin dibatalkan. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
<translation id="2455981314101692989">Halaman web ini melumpuhkan pengisian automatik untuk borang ini.</translation>
+<translation id="2463739503403862330">Isi</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Jalankan Diagnostik Rangkaian<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL carian tidak sah.</translation>
<translation id="2491120439723279231">Sijil pelayan mengandungi ralat.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Serah</translation>
<translation id="2674170444375937751">Adakah anda pasti anda mahu memadamkan halaman ini daripada sejarah anda?</translation>
<translation id="2677748264148917807">Tinggalkan</translation>
+<translation id="269990154133806163">Pelayan memberikan sijil yang tidak didedahkan kepada umum menggunakan dasar Ketelusan Sijil. Ini merupakan keperluan bagi sesetengah sijil, untuk memastikan bahawa sijil itu boleh dipercayai dan menyediakan perlindungan daripada penyerang.<ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Nilai tidak sepadan dengan format.</translation>
<translation id="2704951214193499422">Chromium tidak dapat mengesahkan kad anda pada masa ini. Sila cuba lagi nanti.</translation>
<translation id="2705137772291741111">Salinan tapak ini yang disimpan (cache) tidak boleh dibaca.</translation>
<translation id="2709516037105925701">Autoisi</translation>
+<translation id="2712118517637785082">Anda cuba mencapai <ph name="DOMAIN" />, tetapi sijil yang diberi pelayan telah dibatalkan oleh pengeluarnya. Ini bermakna bukti kelayakan keselamatan yang diberi pelayan sememangnya tidak boleh dipercayai. Anda mungkin berkomunikasi dengan penyerang. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Minta kebenaran</translation>
<translation id="2721148159707890343">Permintaan berjaya</translation>
<translation id="2728127805433021124">Sijil pelayan ditandatangani menggunakan algoritma tandatangan yang lemah.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Bar alamat dan carian</translation>
<translation id="2826760142808435982">Sambungan disulitkan dan disahkan menggunakan <ph name="CIPHER" /> dan menggunakan <ph name="KX" /> sebagai mekanisme pertukaran kunci.</translation>
<translation id="2835170189407361413">Kosongkan borang</translation>
-<translation id="2837049386027881519">Sambungan perlu dicuba semula menggunakan versi protokol TLS atau SSL yang lebih lama. Biasanya, perkara ini bermaksud bahawa pelayan menggunakan perisian yang sangat lama dan mungkin mempunyai isu keselamatan yang lain.</translation>
<translation id="284702764277384724">Sijil pelayan di <ph name="HOST_NAME" /> nampaknya palsu.</translation>
<translation id="2889159643044928134">Jangan Muat Semula</translation>
-<translation id="2896499918916051536">Pemalam ini tidak disokong.</translation>
+<translation id="2900469785430194048">Google Chrome kehabisan memori semasa cuba memaparkan halaman web ini.</translation>
<translation id="2909946352844186028">Perubahan rangkaian dikesan.</translation>
-<translation id="2915500479781995473">Pelayan ini tidak dapat membuktikan bahawa ia adalah <ph name="DOMAIN" /> ; sijil keselamatannya tamat tempoh. Ini mungkin disebabkan oleh salah konfigurasi atau penyerang memintas sambungan anda. Jam komputer anda buat masa ini ditetapkan kepada <ph name="CURRENT_TIME" />. Betulkah itu? Jika tidak, anda perlu membetulkan jam sistem anda dan kemudian muatkan semula halaman ini.</translation>
<translation id="2922350208395188000">Sijil pelayan tidak boleh diperiksa.</translation>
-<translation id="2941952326391522266">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya adalah dari <ph name="DOMAIN2" />. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
<translation id="2948083400971632585">Anda boleh melumpuhkan sebarang proksi yang dikonfigurasi untuk sambungan dari halaman tetapan.</translation>
<translation id="2955913368246107853">Tutup bar cari</translation>
<translation id="2958431318199492670">Konfigurasi rangkaian tidak mematuhi piawaian ONC. Sebahagian konfigurasi tidak boleh diimport.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Jenis dasar salah</translation>
<translation id="3032412215588512954">Adakah anda ingin memuat semula tapak ini?</translation>
<translation id="3037605927509011580">Oh, Tidak!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{sekurang-kurangnya 1 item pada peranti yang disegerakkan}=1{1 item (dan beberapa lagi pada peranti yang disegerakkan)}other{# item (dan beberapa lagi pada peranti yang disegerakkan)}}</translation>
<translation id="3041612393474885105">Maklumat Sijil</translation>
<translation id="3063697135517575841">Chrome tidak dapat mengesahkan kad anda pada masa ini. Sila cuba sebentar lagi.</translation>
<translation id="3093245981617870298">Anda di luar talian.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Terbaru</translation>
<translation id="3207960819495026254">Ditandai halaman</translation>
-<translation id="3225919329040284222">Pelayan memberikan sijil yang tidak sepadan dengan jangkaan terbina dalam. Jangkaan ini disertakan untuk tapak web dengan keselamatan tinggi tertentu untuk melindungi anda.</translation>
<translation id="3226128629678568754">Tekan butang muat semula untuk menyerahkan kembali data yang diperlukan untuk memuatkan halaman.</translation>
<translation id="3228969707346345236">Gagal terjemah kerana halaman sudah dalam <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Masukkan CVC untuk <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Tanda halaman ini</translation>
<translation id="3270847123878663523">&amp;Buat asal Susun semula</translation>
<translation id="3286538390144397061">Mulakan Semula Sekarang</translation>
+<translation id="3303855915957856445">Tiada hasil carian ditemui</translation>
<translation id="3305707030755673451">Data anda disulitkan dengan ungkapan laluan segerak anda pada <ph name="TIME" />. Masukkannya untuk memulakan penyegerakan.</translation>
<translation id="333371639341676808">Halang halaman ini daripada mencipta dialog tambahan.</translation>
+<translation id="3338095232262050444">Selamat</translation>
<translation id="3340978935015468852">tetapan</translation>
<translation id="3345135638360864351">Permintaan anda untuk mengakses tapak web ini tidak boleh dihantar kepada <ph name="NAME" />. Sila cuba lagi.</translation>
<translation id="3355823806454867987">Tukar tetapan proksi...</translation>
@@ -232,14 +236,16 @@
<translation id="3452404311384756672">Selang masa ambil:</translation>
<translation id="3462200631372590220">Menyembunyikan butiran</translation>
<translation id="3479539252931486093">Adakah hal ini tidak dijangka? <ph name="BEGIN_LINK" />Beritahu kami<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Bukan sekarang</translation>
<translation id="348000606199325318">ID Ranap Sistem <ph name="CRASH_LOCAL_ID" /> (ID Pelayan: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Kami tidak dapat menghubungi ibu bapa anda pada masa ini. Sila cuba lagi.</translation>
<translation id="3527085408025491307">Folder</translation>
<translation id="3528171143076753409">Sijil pelayan tidak dipercayai.</translation>
<translation id="3539171420378717834">Simpan salinan kad ini pada peranti ini</translation>
<translation id="3542684924769048008">Gunakan kata laluan untuk:</translation>
-<translation id="3549644494707163724">Sulitkan semua data yang disegerakkan dengan frasa laluan segerak anda sendiri</translation>
+<translation id="3549644494707163724">Sulitkan semua data yang disegerakkan dengan ungkapan laluan segerak anda sendiri</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> lagi...</translation>
+<translation id="3555561725129903880">Pelayan ini tidak dapat membuktikan bahawa iitu <ph name="DOMAIN" />; sijil keselamatannya berasal daripada <ph name="DOMAIN2" />. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Sambungan anda tidak diperibadikan</translation>
<translation id="3583757800736429874">&amp;Buat Semula Pindahkan</translation>
<translation id="3586931643579894722">Sembunyikan butiran</translation>
@@ -252,12 +258,15 @@
<translation id="3630155396527302611">Jika apl telah disenaraikan sebagai atur cara yang dibenarkan untuk mengakses
rangkaian, cuba alihkannya keluar daripada senarai dan tambahkannya  
semula.</translation>
+<translation id="3638794133396384728">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya telah tamat tempoh. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. Jam komputer anda ditetapkan kepada <ph name="CURRENT_TIME" /> pada masa ini. Adakah tetapan ini betul? Jika tidak, anda harus membetulkan jam sistem anda dan kemudian muatkan semula halaman ini. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Ciri percubaan ini mungkin berubah, pecah atau hilang pada bila-bila masa. Kami sama sekali tidak menjamin mengenai apa yang akan berlaku jika anda menghidupkan salah satu percubaan ini, dan penyemak imbas anda juga mungkin terbakar secara spontan. Saya tidak melawak, penyemak imbas anda boleh memadamkan semua data, atau keselamatan dan privasi anda boleh terjejas dalam cara yang tidak dijangka. Sebarang percubaan yang anda dayakan akan dilumpuhkan untuk semua pengguna penyemak imbas ini. Sila teruskan dengan berhati-hati.</translation>
<translation id="3650584904733503804">Pengesahan berjaya</translation>
<translation id="3655670868607891010">Jika anda kerap melihatnya, cuba <ph name="HELP_LINK" /> ini.</translation>
<translation id="3658742229777143148">Semakan</translation>
+<translation id="3678029195006412963">Permintaan tidak dapat ditandatangani</translation>
<translation id="3681007416295224113">Maklumat sijil</translation>
<translation id="3693415264595406141">Kata laluan:</translation>
+<translation id="3696411085566228381">tiada</translation>
<translation id="3700528541715530410">Op, nampaknya anda tidak mendapat kebenaran untuk mengakses halaman ini.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Memuatkan...</translation>
@@ -265,7 +274,6 @@
<translation id="3714780639079136834">Menghidupkan data mudah alih atau Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Menyemak proksi, tembok api dan konfigurasi DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Pautan yang anda salin</translation>
-<translation id="3744899669254331632">Anda tidak boleh melawat <ph name="SITE" /> sekarang kerana tapak web telah menghantar bukti kelayakan hancur yang tidak boleh diproses oleh Chromium. Ralat dan serangan rangkaian biasanya sementara. Oleh itu halaman ini mungkin akan berfungsi kemudian.</translation>
<translation id="375403751935624634">Gagal menterjemah disebabkan ralat pelayan.</translation>
<translation id="3759461132968374835">Tiada laporan nahas yang dibuat baru-baru ini. Nahas yang berlaku apabila laporan nahas dilumpuhkan tidak akan kelihatan di sini.</translation>
<translation id="3788090790273268753">Sijil untuk tapak web ini tamat tempoh pada tahun 2016 dan rantaian sijil ini mengandungi sijil yang ditandatangani menggunakan SHA-1.</translation>
@@ -277,19 +285,25 @@
<translation id="3884278016824448484">Pengecam peranti bercanggah</translation>
<translation id="3885155851504623709">Mukim</translation>
<translation id="3901925938762663762">Kad telah tamat tempoh</translation>
+<translation id="3910267023907260648">Anda cuba mencapai <ph name="DOMAIN" />, tetapi pelayan memberikan sijil yang ditandatangani menggunakan algoritma tandatangan yang lemah. Ini bermakna bukti kelayakan keselamatan yang diberi pelayan mungkin dipalsukan dan pelayan tersebut bukan pelayan yang anda jangkakan (anda mungkin berkomunikasi dengan penyerang). <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya sepatutnya bermula esok. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.}other{Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya sepatutnya bermula # hari lagi. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Gagal untuk memuatkan dokumen PDF</translation>
<translation id="3963721102035795474">Mod Pembaca</translation>
+<translation id="397105322502079400">Mengira...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> disekat</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 halaman web berdekatan}other{# halaman web berdekatan}}</translation>
<translation id="4021036232240155012">DNS ialah perkhidmatan rangkaian yang menterjemahkan nama tapak web kepada alamat Internetnya.</translation>
<translation id="4030383055268325496">&amp;Buat asal tambahkan</translation>
-<translation id="4032534284272647190">Akses ke <ph name="URL" /> dinafikan.</translation>
<translation id="404928562651467259">AMARAN</translation>
<translation id="4058922952496707368">Kekunci "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Pelanggan dan pelayan tidak menyokong versi protokol SSL atau set sifer biasa.</translation>
<translation id="4079302484614802869">Konfigurasi proksi ditetapkan kepada penggunaaan URL skrip .pac, bukannya pelayan proksi tetap.</translation>
<translation id="4103249731201008433">Nombor siri peranti tidak sah</translation>
<translation id="4103763322291513355">Lawati &lt;strong&gt;chrome://policy&lt;/strong&gt; untuk melihat senarai URL yang disenarai hitam dan dasar lain yang dikuatkuasakan oleh pentadbir sistem anda.</translation>
+<translation id="4110615724604346410">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya mengandungi ralat. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Skop dasar tidak disokong.</translation>
+<translation id="4118212371799607889">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh Chromium. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 yang lain}other{# yang lain}}</translation>
<translation id="4130226655945681476">Memeriksa kabel rangkaian, modem dan penghala</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Adakah anda mahu Chromium menyimpan kad ini?</translation>
@@ -297,6 +311,7 @@
<translation id="4176463684765177261">Dilumpuhkan</translation>
<translation id="4196861286325780578">&amp;Buat semula pindahkan</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Menyemak konfigurasi tembok api dan antivirus<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{tiada}=1{1 apl ($1)}=2{2 apl ($1, $2)}other{# apl ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Nahas</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Cuba jalankan Diagnostik Rangkaian<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Tidak</translation>
@@ -305,14 +320,15 @@
<translation id="4269787794583293679">(Tiada nama pengguna)</translation>
<translation id="4300246636397505754">Cadangan ibu bapa</translation>
<translation id="4304224509867189079">Log Masuk</translation>
+<translation id="432290197980158659">Pelayan memberikan sijil yang tidak sepadan dengan jangkaan terbina dalam. Jangkaan ini disertakan untuk tapak web keselamatan tinggi yang tertentu untuk melindungi anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Gagal menemui artikel</translation>
+<translation id="4331708818696583467">Tidak Selamat</translation>
<translation id="4372948949327679948">Nilai <ph name="VALUE_TYPE" /> yang dijangka.</translation>
-<translation id="4377125064752653719">Anda cuba untuk mencapai <ph name="DOMAIN" />, tetapi sijil yang diberi pelayan telah dibatalkan oleh pengeluarnya. Ini bermakna bahawa bukti kelayakan keselamatan yang diberi pelayan sememangnya tidak harus dipercayai. Anda mungkin berkomunikasi dengan penyerang.</translation>
<translation id="4381091992796011497">Nama Pengguna:</translation>
<translation id="4394049700291259645">Lumpuhkan</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> hingga <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">hasil carian</translation>
-<translation id="4424024547088906515">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh Chrome. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang memintasi sambungan anda.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> tidak menerima sijil log masuk anda atau sijil log masuk mungkin tidak diberikan.</translation>
<translation id="443673843213245140">Penggunaan proksi dilumpuhkan tetapi konfigurasi proksi yang jelas dinyatakan.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Anda melihat mesej ini kerana Google SafeSites didayakan.</translation>
@@ -324,12 +340,12 @@
<translation id="4522570452068850558">Butiran</translation>
<translation id="4558551763791394412">Cuba lumpuhkan sambungan anda.</translation>
<translation id="4587425331216688090">Alih keluar alamat daripada Chrome?</translation>
+<translation id="4589078953350245614">Anda cuba mencapai <ph name="DOMAIN" />, tetapi pelayan memberikan sijil yang tidak sah. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Sambungan anda ke <ph name="DOMAIN" /> disulitkan menggunakan suit sifer moden.</translation>
<translation id="4594403342090139922">&amp;Buat asal Pemadaman</translation>
+<translation id="4627442949885028695">Teruskan daripada peranti lain</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Anda sedang melihat halaman sambungan.</translation>
-<translation id="467662567472608290">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya mengandungi ralat. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> telah disekat</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Sambungan anda tergendala</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Jalankan Diagnostik Rangkaian Windows<ph name="END_LINK" /></translation>
@@ -337,21 +353,26 @@
<translation id="4728558894243024398">Platform</translation>
<translation id="4744603770635761495">Laluan Boleh Laku</translation>
<translation id="4756388243121344051">&amp;Sejarah</translation>
+<translation id="4759238208242260848">Muat turun</translation>
<translation id="4764776831041365478">Laman web di <ph name="URL" /> mungkin tergendala buat sementara waktu atau ia mungkin dpindahkan secara kekal ke alamat web baharu.</translation>
<translation id="4771973620359291008">Ralat tidak diketahui telah berlaku.</translation>
<translation id="4782449893814226250">Anda telah bertanya kepada ibu bapa anda sama ada ok untuk melawat halaman ini.</translation>
<translation id="4800132727771399293">Semak tarikh tamat tempoh serta CVC anda dan cuba lagi</translation>
-<translation id="4807049035289105102">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini menghantar bukti kelayakan yang dicampuradukkan yang tidak boleh diproses oleh Google Chrome. Ralat rangkaian dan serangan biasanya bersifat sementara, oleh itu halaman ini mungkin akan berfungsi sebentar lagi.</translation>
<translation id="4813512666221746211">Ralat rangkaian</translation>
<translation id="4816492930507672669">Muat halaman</translation>
<translation id="4850886885716139402">Lihat</translation>
<translation id="4880827082731008257">Sejarah carian</translation>
+<translation id="4884656795097055129">Lebih banyak artikel akan muncul apabila tiba masa yang sesuai.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{dan 1 lagi halaman web}other{dan # lagi halaman web}}</translation>
<translation id="4923417429809017348">Halaman ini diterjemahkan dari bahasa yang tidak diketahui ke <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Mesti ditentukan.</translation>
<translation id="4930497775425430760">Anda melihat mesej ini kerana ibu bapa anda perlu meluluskan tapak baharu pada lawatan pertama anda.</translation>
<translation id="495170559598752135">Tindakan</translation>
<translation id="4958444002117714549">Kembangkan senarai</translation>
+<translation id="4962322354953122629">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh Chrome. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Terjemahkan daripada <ph name="ORIGINAL_LANGUAGE" /> kepada <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Pemalam ini tidak disokong</translation>
<translation id="5002932099480077015">Jika didayakan, Chrome akan menyimpan salinan kad anda pada peranti ini untuk pengisian borang yang lebih cepat.</translation>
<translation id="5019198164206649151">Simpanan penyandaran dalam keadaan buruk</translation>
<translation id="5023310440958281426">Semak dasar pentadbir anda</translation>
@@ -359,13 +380,12 @@
<translation id="5031870354684148875">Perihal Google Terjemah</translation>
<translation id="5040262127954254034">Privasi</translation>
<translation id="5045550434625856497">Kata laluan tidak sah</translation>
+<translation id="5056549851600133418">Artikel untuk anda</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Menyemak alamat proksi<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Sijil pelayan tidak sah pada masa ini.</translation>
<translation id="5089810972385038852">Negeri</translation>
-<translation id="5094747076828555589">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh Chromium. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
<translation id="5095208057601539847">Wilayah</translation>
<translation id="5115563688576182185">(64-bit)</translation>
-<translation id="5122371513570456792">Menemui <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> untuk '<ph name="SEARCH_STRING" />'.</translation>
<translation id="5141240743006678641">Sulitkan kata laluan yang disegerakkan dengan bukti kelayakan Google anda</translation>
<translation id="5145883236150621069">Terdapat kod ralat dalam balasan dasar</translation>
<translation id="5171045022955879922">Buat carian atau taipkan URL</translation>
@@ -374,18 +394,18 @@
<translation id="5190835502935405962">Bar Penanda Halaman</translation>
<translation id="5199729219167945352">Eksperimen</translation>
<translation id="5251803541071282808">Awan</translation>
+<translation id="5277279256032773186">Menggunakan Chrome di tempat kerja? Perniagaan boleh mengurus tetapan Chrome untuk pekerja mereka. Ketahui lebih lanjut</translation>
<translation id="5299298092464848405">Ralat semasa menghuraikan dasar</translation>
<translation id="5300589172476337783">Paparkan</translation>
<translation id="5308689395849655368">Pelaporan nahas dilumpuhkan.</translation>
<translation id="5317780077021120954">Simpan</translation>
<translation id="5327248766486351172">Nama</translation>
+<translation id="5359637492792381994">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tidak sah pada masa ini. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Gagal menyimpan tetapan dasar</translation>
-<translation id="540969355065856584">Pelayan ini tidak dapat membuktikan bahawa pelayan adalah <ph name="DOMAIN" />; sijil keselamatan pelayan tidak sah pada masa ini. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang memintas sambungan anda.</translation>
<translation id="5421136146218899937">Kosongkan data semakan imbas...</translation>
<translation id="5430298929874300616">Alih keluar penanda halaman</translation>
<translation id="5431657950005405462">Fail anda tidak ditemui</translation>
<translation id="5435775191620395718">Menunjukkan sejarah daripada peranti ini. <ph name="BEGIN_LINK" />Ketahui lebih lanjut<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Cadangan kandungan diperibadikan kini dilumpuhkan kerana data yang disegerakkan dilindungi menggunakan ungkapan laluan tersuai.</translation>
<translation id="5439770059721715174">Ralat pengesahan skema di "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Halaman <ph name="HOST_NAME" /> ini tidak ditemui</translation>
<translation id="5455374756549232013">Cap waktu dasar tidak elok</translation>
@@ -408,14 +428,18 @@
<translation id="5622887735448669177">Adakah anda ingin meninggalkan tapak ini?</translation>
<translation id="5629630648637658800">Gagal memuatkan tetapan dasar</translation>
<translation id="5631439013527180824">Token pengurusan peranti tidak sah</translation>
-<translation id="5650551054760837876">Tiada hasil carian ditemui.</translation>
<translation id="5677928146339483299">Disekat</translation>
<translation id="5710435578057952990">Identiti tapak web ini belum disahkan.</translation>
<translation id="5720705177508910913">Pengguna semasa</translation>
+<translation id="572328651809341494">Tab terbaharu</translation>
<translation id="5784606427469807560">Terdapat masalah mengesahkan kad anda. Semak sambungan Internet anda dan cuba lagi.</translation>
<translation id="5785756445106461925">Selain itu, halaman ini mengandungi sumber lain yang tidak selamat. Sumber ini boleh dilihat oleh orang lain semasa dalam transit dan boleh diubah oleh penyerang untuk menukar penampilan halaman.</translation>
+<translation id="5786044859038896871">Adakah anda ingin mengisi maklumat kad anda?</translation>
+<translation id="5803412860119678065">Adakah anda ingin mengisi <ph name="CARD_DETAIL" /> anda?</translation>
<translation id="5810442152076338065">Sambungan anda ke <ph name="DOMAIN" /> disulitkan menggunakan suit sifer yang sudah usang.</translation>
<translation id="5813119285467412249">&amp;Buat Semula Tambahkan</translation>
+<translation id="5814352347845180253">Anda mungkin kehilangan akses kepada kandungan premium daripada <ph name="SITE" /> dan sesetengah tapak web lain.</translation>
+<translation id="5843436854350372569">Anda cuba mencapai <ph name="DOMAIN" />, tetapi pelayan memberi sijil yang mengandungi kunci yang lemah, Penyerang mungkin telah merosakkan kunci peribadi dan pelayan tersebut mungkin bukan pelayan yang anda jangkakan (anda mungkin berkomunikasi dengan penyerang). <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Anda melihat mesej ini kerana pengurus anda menyekat tapak ini.</translation>
<translation id="5857090052475505287">Folder Baharu</translation>
<translation id="5869405914158311789">Tapak ini tidak dapat dicapai</translation>
@@ -423,6 +447,7 @@
<translation id="5872918882028971132">Cadangan Ibu Bapa</translation>
<translation id="59107663811261420">Kad jenis ini tidak disokong oleh Google Payments untuk pedagang ini. Sila pilih kad yang lain.</translation>
<translation id="59174027418879706">Didayakan</translation>
+<translation id="5926846154125914413">Anda mungkin kehilangan akses kepada kandungan premium daripada sesetengah tapak web.</translation>
<translation id="5966707198760109579">Minggu</translation>
<translation id="5967867314010545767">Buang daripada sejarah</translation>
<translation id="5975083100439434680">Zum keluar</translation>
@@ -434,12 +459,12 @@
<translation id="604124094241169006">Automatik</translation>
<translation id="6042308850641462728">Lagi</translation>
<translation id="6060685159320643512">Berhati-hati, percubaan ini mungkin memudaratkan</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{tiada}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Periksa mana-mana kabel dan but semula mana-mana penghala, modem atau peranti
rangkaian lain yang mungkin anda gunakan.</translation>
<translation id="614940544461990577">Cuba:</translation>
<translation id="6150607114729249911">Op! Anda perlu bertanya kepada ibu bapa anda sama ada anda boleh melawat halaman ini.</translation>
<translation id="6151417162996330722">Sijil pelayan mempunyai tempoh sah yang terlalu panjang.</translation>
-<translation id="6154808779448689242">Token dasar yang dikembalikan tidak sepadan dengan token semasa</translation>
<translation id="6165508094623778733">Ketahui lebih lanjut</translation>
<translation id="6203231073485539293">Semak sambungan Internet anda</translation>
<translation id="6218753634732582820">Alih keluar alamat daripada Chromium?</translation>
@@ -452,24 +477,30 @@
<translation id="6328639280570009161">Cuba lumpuhkan ramalan rangkaian</translation>
<translation id="6337534724793800597">Tapis dasar mengikut nama</translation>
<translation id="6342069812937806050">Sebentar tadi</translation>
+<translation id="6345221851280129312">saiz tidak diketahui</translation>
<translation id="6355080345576803305">Pembatalan sesi awam</translation>
<translation id="6358450015545214790">Apakah maksudnya?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 cadangan lain}other{# cadangan lain}}</translation>
<translation id="6387478394221739770">Berminat dengan ciri Chrome baharu yang hebat? Cuba saluran beta kami di chrome.com/beta.</translation>
-<translation id="641480858134062906"><ph name="URL" /> gagal untuk muatkan</translation>
+<translation id="6389758589412724634">Chromium kehabisan memori semasa cuba memaparkan halaman web ini.</translation>
+<translation id="6416403317709441254">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini menghantar bukti kelayakan yang dicampuradukkan sehingga tidak dapat diproses oleh Chromium. Ralat rangkaian dan serangan biasanya bersifat sementara, oleh itu halaman ini mungkin akan berfungsi sebentar lagi. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Tidak dapat memeriksa sama ada sijil telah dibatalkan.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> enggan menyambung.</translation>
<translation id="6445051938772793705">Negara</translation>
<translation id="6451458296329894277">Sahkan Penyerahan Semula Borang</translation>
<translation id="6458467102616083041">Diabaikan kerana carian lalai dilumpuhkan oleh dasar.</translation>
+<translation id="6462969404041126431">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya telah dibatalkan. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Dasar peranti</translation>
<translation id="6489534406876378309">Mulakan muat naik ranap sistem</translation>
<translation id="6529602333819889595">&amp;Buat Semula Pemadaman</translation>
+<translation id="6534179046333460208">Cadangan Web Fizikal</translation>
<translation id="6550675742724504774">Pilihan</translation>
+<translation id="6593753688552673085">kurang daripada <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Pilihan penyulitan</translation>
<translation id="662080504995468778">Kekal di sini</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Carian</translation>
-<translation id="6634865548447745291">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana <ph name="BEGIN_LINK" />sijil ini telah dibatalkan<ph name="END_LINK" />. Ralat rangkaian dan serangan biasanya bersifat sementara oleh itu, halaman ini mungkin akan berfungsi sebentar lagi.</translation>
<translation id="6644283850729428850">Dasar ini telah dikecam.</translation>
+<translation id="6652240803263749613">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh sistem pengendalian komputer anda. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Edit Folder</translation>
<translation id="6660210980321319655">Dilaporkan secara automatik pada <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Alih keluar cadangan borang daripada Chromium?</translation>
@@ -477,6 +508,7 @@
<translation id="6710213216561001401">Sebelumnya</translation>
<translation id="6710594484020273272">&lt;Taip istilah carian&gt;</translation>
<translation id="6711464428925977395">Ada sesuatu yang tidak kena dengan pelayan proksi atau alamat tidak betul.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{tiada}=1{1 item}other{# item}}</translation>
<translation id="674375294223700098">Ralat sijil pelayan tidak diketahui.</translation>
<translation id="6753269504797312559">Nilai dasar</translation>
<translation id="6757797048963528358">Peranti anda tidak aktif.</translation>
@@ -488,7 +520,6 @@
<translation id="6891596781022320156">Tahap dasar tidak disokong.</translation>
<translation id="6895330447102777224">Kad anda telah disahkan</translation>
<translation id="6897140037006041989">Ejen Pengguna</translation>
-<translation id="6903907808598579934">Hidupkan penyegerakan</translation>
<translation id="6915804003454593391">Pengguna:</translation>
<translation id="6957887021205513506">Sijil pelayan rupanya adalah pemalsuan.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -496,9 +527,11 @@
<translation id="6970216967273061347">Daerah</translation>
<translation id="6973656660372572881">Pelayan proksi tetap dan juga URL skrip .pac tidak ditetapkan.</translation>
<translation id="6989763994942163495">Paparkan tetapan lanjutan...</translation>
+<translation id="7000990526846637657">Tiada masukan sejarah ditemui</translation>
+<translation id="7009986207543992532">Anda cuba mencapai <ph name="DOMAIN" />, tetapi pelayan memberikan sijil yang tempoh sahnya terlalu panjang untuk dipercayai. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Akaun Google anda mungkin mempunyai sejarah penyemakan imbas dalam bentuk lain di <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Kata laluan</translation>
-<translation id="7050187094878475250">Anda cuba untuk mencapai <ph name="DOMAIN" />, tetapi pelayan memberikan sijil yang tempoh sahnya terlalu panjang untuk boleh dipercayai.</translation>
<translation id="7087282848513945231">Daerah</translation>
<translation id="7088615885725309056">Lebih lama</translation>
<translation id="7090678807593890770">Cari <ph name="LINK" /> di Google</translation>
@@ -517,13 +550,13 @@
<translation id="7246609911581847514">Anda melihat mesej ini kerana pengurus anda perlu meluluskan tapak baharu pada lawatan pertama anda.</translation>
<translation id="724975217298816891">Masukkan tarikh tamat tempoh dan CVC untuk <ph name="CREDIT_CARD" /> bagi mengemas kini butiran kad anda. Setelah anda mengesahkan, butiran kad anda akan dikongsi dengan tapak ini.</translation>
<translation id="725866823122871198">Sambungan peribadi ke <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak boleh diwujudkan kerana tarikh dan masa komputer anda (<ph name="DATE_AND_TIME" />) tidak betul.</translation>
-<translation id="7265986070661382626">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini <ph name="BEGIN_LINK" />menggunakan penyematan sijil<ph name="END_LINK" />. Ralat rangkaian dan serangan biasanya bersifat sementara oleh itu, halaman ini mungkin akan berfungsi sebentar lagi.</translation>
<translation id="7269802741830436641">Halaman web ini mempunyai gelung ubah hala</translation>
<translation id="7275334191706090484">Penanda Halaman Terurus</translation>
<translation id="7298195798382681320">Disyorkan</translation>
-<translation id="7301833672208172928">Hidupkan penyegerakan sejarah</translation>
+<translation id="7309308571273880165">Laporan ranap sistem dirakam pada <ph name="CRASH_TIME" /> (muat naik diminta oleh pengguna, belum dimuat naik lagi)</translation>
<translation id="7334320624316649418">&amp;Buat semula susun semula</translation>
<translation id="733923710415886693">Sijil pelayan tidak didedahkan melalui Ketelusan Sijil.</translation>
+<translation id="7351800657706554155">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana sijilnya telah dibatalkan. Ralat rangkaian dan serangan biasanya bersifat sementara, maka halaman ini mungkin akan berfungsi sebentar lagi. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Baris Perintah</translation>
<translation id="7372973238305370288">hasil carian</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -542,16 +575,17 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="7469372306589899959">Mengesahkan kad</translation>
<translation id="7481312909269577407">Majukan</translation>
<translation id="7485870689360869515">Tiada data dijumpai.</translation>
+<translation id="7508255263130623398">Id peranti yang dikembalikan kosong atau tidak sepadan dengan id peranti semasa</translation>
<translation id="7514365320538308">Muat Turun</translation>
<translation id="7518003948725431193">Tiada halaman web dijumpai untuk alamat web: <ph name="URL" /></translation>
<translation id="7537536606612762813">Wajib</translation>
<translation id="7542995811387359312">Pengisian kad kredit automatik dilumpuhkan kerana borang ini tidak menggunakan sambungan selamat.</translation>
<translation id="7549584377607005141">Halaman web ini memerlukan data yang anda masukkan sebelum ini agar dapat dipaparkan dengan betul. Anda boleh menghantar data ini semula, tetapi dengan berbuat demikian anda akan mengulangi sebarang tindakan terdahulu yang telah dilakukan oleh halaman ini.</translation>
<translation id="7554791636758816595">Tab Baharu</translation>
-<translation id="7567204685887185387">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya mungkin telah dikeluarkan melalui penipuan. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
<translation id="7568593326407688803">Halaman ini adalah dalam<ph name="ORIGINAL_LANGUAGE" />Adakah anda ingin menterjemahkannya?</translation>
<translation id="7569952961197462199">Alih keluar kad kredit daripada Chrome?</translation>
<translation id="7578104083680115302">Bayar dengan cepat di tapak dan apl merentas peranti menggunakan kad yang telah disimpan dengan Google.</translation>
+<translation id="7588950540487816470">Web Fizikal</translation>
<translation id="7592362899630581445">Sijil pelayan melanggar kekangan nama.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> tidak dapat mengendalikan permintaan ini pada masa ini.</translation>
<translation id="7600965453749440009">Jangan sekali-kali terjemahkan <ph name="LANGUAGE" /></translation>
@@ -562,6 +596,7 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="7637571805876720304">Alih keluar kad kredit daripada Chromium?</translation>
<translation id="765676359832457558">Sembunyikan tetapan lanjutan...</translation>
<translation id="7658239707568436148">Batal</translation>
+<translation id="7667346355482952095">Token dasar yang dikembalikan kosong atau tidak sepadan dengan token semasa</translation>
<translation id="7668654391829183341">Peranti tidak diketahui</translation>
<translation id="7674629440242451245">Berminat dengan ciri Chrome baharu yang hebat? Cuba saluran pembangun kami di chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Teruskan ke <ph name="SITE" /> (tidak selamat)<ph name="END_LINK" /></translation>
@@ -578,10 +613,10 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="780301667611848630">Tidak, terima kasih</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7813600968533626083">Alih keluar cadangan borang daripada Chrome?</translation>
+<translation id="7815407501681723534">Menemui <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> untuk '<ph name="SEARCH_STRING" />'</translation>
<translation id="785549533363645510">Walau bagaimanapun, anda tidak halimunan. Apabila anda menggunakan mod inkognito, penyemakan imbas anda tidak akan disembunyikan daripada majikan anda, penyedia perkhidmatan Internet anda atau tapak web yang anda lawati.</translation>
<translation id="7887683347370398519">Semak CVC anda dan cuba lagi</translation>
<translation id="7894616681410591072">Op! Anda memerlukan kebenaran daripada <ph name="NAME" /> untuk mengakses halaman ini.</translation>
-<translation id="790025292736025802"><ph name="URL" /> tidak dijumpai</translation>
<translation id="7912024687060120840">Dalam Folder:</translation>
<translation id="7920092496846849526">Anda telah bertanya kepada ibu bapa anda sama ada ok untuk melawat halaman ini.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -594,9 +629,10 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="7995512525968007366">Tidak Ditentukan</translation>
<translation id="8012647001091218357">Kami tidak dapat menghubungi ibu bapa anda pada masa ini. Sila cuba lagi.</translation>
<translation id="8034522405403831421">Halaman ini dalam <ph name="SOURCE_LANGUAGE" />. Terjemahkannya kepada <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Tiada masukan sejarah dijumpai.</translation>
<translation id="8088680233425245692">Gagal melihat artikel.</translation>
+<translation id="8089520772729574115">kurang daripada 1 MB</translation>
<translation id="8091372947890762290">Pengaktifan belum selesai pada pelayan</translation>
+<translation id="8129262335948759431">jumlah tidak diketahui</translation>
<translation id="8131740175452115882">Sahkan</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Alamat DNS<ph name="END_ABBR" /> pelayan <ph name="HOST_NAME" /> tidak ditemui.</translation>
<translation id="8149426793427495338">Komputer anda dalam mod tidur.</translation>
@@ -605,6 +641,7 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="8201077131113104583">URL kemas kini tidak sah untuk sambungan dengan ID "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Lokasi yang Ditentukan:</translation>
<translation id="8225771182978767009">Orang yang menyediakan komputer ini telah memilih untuk menyekat tapak ini.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Halaman yang anda cari untuk maklumat terpakai yang anda masukkan. Kembali ke halaman tersebut mungkin menyebabkan mana-mana tindakan yang anda ambil akan diulang. Adakah anda mahu teruskan?</translation>
<translation id="8249320324621329438">Diambil kali terakhir:</translation>
<translation id="8261506727792406068">Padam</translation>
@@ -617,12 +654,17 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="8349305172487531364">Bar penanda halaman</translation>
<translation id="8363502534493474904">Matikan mod pesawat</translation>
<translation id="8364627913115013041">Tidak ditetapkan.</translation>
+<translation id="8380941800586852976">Berbahaya</translation>
<translation id="8412145213513410671">Nahas (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Anda mesti memasukkan frasa laluan yang sama dua kali.</translation>
<translation id="8428213095426709021">Tetapan</translation>
+<translation id="8433057134996913067">Pemadaman ini akan membuatkan anda dilog keluar daripada kebanyakan tapak web.</translation>
<translation id="8437238597147034694">&amp;Buat asal pindahkan</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kad kredit}other{# kad kredit}}</translation>
+<translation id="8483780878231876732">Log masuk ke Chrome untuk menggunakan kad daripada Akaun Google anda</translation>
<translation id="8488350697529856933">Diguna pakai untuk</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> mengambil masa terlalu lama untuk bertindak balas.</translation>
+<translation id="852346902619691059">Pelayan ini tidak dapat membuktikan bahawa itu <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh sistem pengendalian peranti anda. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Kad jenis ini tidak disokong oleh Google Payments. Sila pilih kad yang lain.</translation>
<translation id="8550022383519221471">Perkhidmatan segerak tidak tersedia untuk domain anda.</translation>
<translation id="8553075262323480129">Gagal terjemahan kerana bahasa halaman tidak dapat ditentukan.</translation>
@@ -634,15 +676,12 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="8647750283161643317">Tetapkan semula semua kepada lalai</translation>
<translation id="8680787084697685621">Butiran log masuk akaun sudah lapuk.</translation>
<translation id="8703575177326907206">Sambungan anda ke <ph name="DOMAIN" /> tidak disulitkan.</translation>
-<translation id="8713130696108419660">Tandatangan parap tidak elok</translation>
<translation id="8725066075913043281">Cuba lagi</translation>
<translation id="8728672262656704056">Anda menggunakan mod inkognito</translation>
<translation id="8730621377337864115">Selesai</translation>
<translation id="8738058698779197622">Untuk mewujudkan sambungan yang selamat, jam anda perlu ditetapkan dengan betul. Ini kerana sijil yang digunakan oleh tapak web untuk mengenal pastinya hanya sah untuk tempoh masa yang tertentu. Memandangkan jam peranti anda tidak betul, Chromium tidak boleh mengesahkan sijil-sijil ini.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Alamat DNS&lt;/abbr&gt; <ph name="HOST_NAME" /> tidak ditemui. Masalah sedang didiagnosis.</translation>
-<translation id="8741995161408053644">Akaun Google anda mungkin mempunyai sejarah penyemakan imbas dalam bentuk lain di <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Buat semula pemadaman</translation>
-<translation id="8790687370365610530">Untuk mendapatkan kandungan diperibadikan yang dicadangkan oleh Google, hidupkan penyegerakan sejarah.</translation>
<translation id="8798099450830957504">Lalai</translation>
<translation id="8804164990146287819">Dasar Privasi</translation>
<translation id="8820817407110198400">Penanda buku</translation>
@@ -664,13 +703,11 @@ Psst! <ph name="SHORTCUT_KEY" /> mod Inkognito mungkin akan berguna pada masa ak
<translation id="8971063699422889582">Sijil pelayan telah tamat tempoh.</translation>
<translation id="8987927404178983737">Bulan</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Pelayan memberikan sijil yang tidak didedahkan kepada umum menggunakan dasar Ketelusan Sijil. Ini merupakan keperluan bagi sesetengah sijil untuk memastikan sijil itu boleh dipercayai dan untuk melindungi pengguna daripada penyerang.</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> proksi memerlukan nama pengguna dan kata laluan.</translation>
<translation id="901974403500617787">Bendera yang diguna pakai di seluruh sistem hanya boleh ditetapkan oleh pemilik: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Halaman ini telah diterjemahkan kepada <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Gunakan perkhidmatan ramalan untuk memuatkan halaman lebih cepat</translation>
<translation id="9039213469156557790">Selain itu, halaman ini mengandungi sumber lain yang tidak selamat. Sumber ini boleh dilihat oleh orang lain semasa dalam transit dan boleh diubah oleh penyerang untuk menukar kelakuan halaman.</translation>
-<translation id="9049981332609050619">Anda cuba untuk mencapai <ph name="DOMAIN" />, tetapi pelayan memberikan sijil tidak sah.</translation>
<translation id="9050666287014529139">Frasa laluan</translation>
<translation id="9065203028668620118">Edit</translation>
<translation id="9092364396508701805">Halaman <ph name="HOST_NAME" /> tidak berfungsi</translation>
diff --git a/chromium/components/strings/components_strings_nl.xtb b/chromium/components/strings/components_strings_nl.xtb
index a5cdd2da2ee..94b8fe19cc6 100644
--- a/chromium/components/strings/components_strings_nl.xtb
+++ b/chromium/components/strings/components_strings_nl.xtb
@@ -1,21 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="nl">
+<translation id="1008557486741366299">Niet nu</translation>
<translation id="1015730422737071372">Aanvullende gegevens verzenden</translation>
<translation id="1032854598605920125">Rechtsom draaien</translation>
<translation id="1038842779957582377">onbekende naam</translation>
+<translation id="1053591932240354961">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website gecodeerde inloggegevens heeft verzonden die niet door Google Chrome kunnen worden verwerkt. Aangezien netwerkfouten en aanvallen meestal van tijdelijke aard zijn, zal deze pagina later waarschijnlijk weer correct werken. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Toevoegen ongedaan maken</translation>
<translation id="10614374240317010">Nooit opgeslagen</translation>
-<translation id="1064422015032085147">Het is mogelijk dat de server waarop de webpagina wordt gehost, overbelast is of wordt onderhouden. Verzoeken naar deze URL zijn tijdelijk stopgezet, om te voorkomen dat er te veel verkeer wordt gegenereerd en dat het probleem nog erger wordt.</translation>
<translation id="106701514854093668">Desktopbladwijzers</translation>
<translation id="1080116354587839789">Aanpassen aan breedte</translation>
+<translation id="1103124106085518534">Klaar voor nu</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> altijd vertalen</translation>
<translation id="1107591249535594099">Als deze optie is aangevinkt, bewaart Chrome een exemplaar van je kaart op dit apparaat om formulieren sneller te kunnen invullen.</translation>
+<translation id="1111153019813902504">Onlangs bezochte bladwijzers</translation>
<translation id="1113869188872983271">&amp;Volgorde wijzigen ongedaan maken</translation>
+<translation id="1126551341858583091">De grootte in de lokale opslag is <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cachegeheugen van beleid is OK</translation>
<translation id="113188000913989374"><ph name="SITE" /> meldt het volgende:</translation>
<translation id="1132774398110320017">Instellingen voor automatisch aanvullen in Chrome...</translation>
-<translation id="1150979032973867961">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door het besturingssysteem van je computer. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="1152921474424827756">Een <ph name="BEGIN_LINK" />gecacht exemplaar<ph name="END_LINK" /> van <ph name="URL" /> openen</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> heeft de verbinding onverwacht verbroken.</translation>
<translation id="1161325031994447685">Maak opnieuw verbinding met wifi</translation>
@@ -23,7 +26,8 @@
<translation id="1181037720776840403">Verwijderen</translation>
<translation id="1201402288615127009">Volgende</translation>
<translation id="1201895884277373915">Meer van deze site</translation>
-<translation id="121201262018556460">Je probeert <ph name="DOMAIN" /> te bereiken, maar de server heeft een certificaat geretourneerd met een zwakke sleutel. Een hacker kan de persoonlijke sleutel hebben aangepast en het is mogelijk dat de server zelf een imitatie is (wellicht een server die je schade probeert te berokkenen).</translation>
+<translation id="1206967143813997005">Onjuiste eerste handtekening</translation>
+<translation id="1209206284964581585">Voorlopig verbergen</translation>
<translation id="1219129156119358924">Systeembeveiliging</translation>
<translation id="1227224963052638717">Onbekend beleid.</translation>
<translation id="1227633850867390598">Waarde verbergen</translation>
@@ -44,6 +48,7 @@
<translation id="1426410128494586442">Ja</translation>
<translation id="1430915738399379752">Afdrukken</translation>
<translation id="1442912890475371290">Geblokkeerde poging <ph name="BEGIN_LINK" /> om een pagina op <ph name="DOMAIN" /><ph name="END_LINK" /> te bezoeken.</translation>
+<translation id="1491663344921578213">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website gebruikmaakt van certificaatpinning. Aangezien netwerkfouten en aanvallen meestal van tijdelijke aard zijn, zal deze pagina later waarschijnlijk weer correct werken. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Een opgeslagen (verouderde) kopie van deze pagina weergeven.</translation>
<translation id="1519264250979466059">Datum van build</translation>
<translation id="1549470594296187301">JavaScript moet zijn ingeschakeld om deze functie te kunnen gebruiken.</translation>
@@ -58,36 +63,34 @@
<translation id="1644184664548287040">De netwerkconfiguratie is ongeldig en kan niet worden geĂ¯mporteerd.</translation>
<translation id="1644574205037202324">Geschiedenis</translation>
<translation id="1645368109819982629">Niet-ondersteund protocol</translation>
-<translation id="1655462015569774233">{1,plural, =1{Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het bijbehorende beveiligingscertificaat is gisteren verlopen. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. De klok van je computer is momenteel ingesteld op <ph name="CURRENT_DATE" />. Is dat correct? Zo niet, dan moet je de klok van je systeem aanpassen en vervolgens deze pagina vernieuwen.}other{Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het bijbehorende beveiligingscertificaat is # dagen geleden verlopen. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. De klok van je computer is momenteel ingesteld op <ph name="CURRENT_DATE" />. Is dat correct? Zo niet, dan moet je de klok van je systeem aanpassen en vervolgens deze pagina vernieuwen.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> gebruikt gewoonlijk versleuteling om je gegevens te beschermen. Toen Google Chrome deze keer probeerde verbinding te maken met <ph name="SITE" />, retourneerde de website ongewone en onjuiste inloggegevens. Dit kan gebeuren als een aanvaller probeert zich als <ph name="SITE" /> voor te doen of als een wifi-inlogscherm de verbinding heeft verbroken. Je gegevens zijn nog steeds veilig omdat Google Chrome de verbinding heeft beëindigd voordat er gegevens konden worden uitgewisseld.</translation>
<translation id="168841957122794586">Het servercertificaat bevat een zwakke cryptografische sleutel.</translation>
<translation id="1701955595840307032">Voorgestelde content ophalen</translation>
-<translation id="1706954506755087368">{1,plural, =1{Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het bijbehorende beveiligingscertificaat is zogenaamd van morgen. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.}other{Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het bijbehorende beveiligingscertificaat is zogenaamd van # dagen in de toekomst. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.}}</translation>
<translation id="1710259589646384581">Besturingssysteem</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Probeer contact op te nemen met de systeembeheerder.</translation>
<translation id="17513872634828108">Geopende tabbladen</translation>
<translation id="1753706481035618306">Paginanummer</translation>
-<translation id="1761412452051366565">Schakel synchronisatie in om suggesties met gepersonaliseerde content van Google te ontvangen.</translation>
-<translation id="1763864636252898013">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door het besturingssysteem van je apparaat. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Voer Windows Netwerkcontrole uit<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Update je wachtwoordzin voor synchronisatie.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Je onlangs bezochte bladwijzers worden hier weergegeven.</translation>
<translation id="1821930232296380041">Ongeldige aanvraag of aanvraagparameters</translation>
<translation id="1838667051080421715">Je bekijkt de bron van een webpagina.</translation>
<translation id="1871208020102129563">Proxy is ingesteld op het gebruik van vaste proxyservers, niet op een script-URL van het PAC-type.</translation>
<translation id="1883255238294161206">Lijst samenvouwen</translation>
<translation id="1898423065542865115">Filteren</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> heeft je inlogcertificaat niet geaccepteerd of je inlogcertificaat is mogelijk verlopen.</translation>
<translation id="194030505837763158">Ga naar <ph name="LINK" /></translation>
<translation id="1962204205936693436">Bladwijzers voor <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Serialisatiefout</translation>
<translation id="1974060860693918893">Geavanceerd</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{en 1 andere}other{en # andere}}</translation>
<translation id="2025186561304664664">Proxy is ingesteld op automatische configuratie.</translation>
<translation id="2030481566774242610">Bedoelde je <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Dit bericht wordt weergegeven omdat je ouders nieuwe sites moeten goedkeuren wanneer je ze voor het eerst bezoekt.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Controleer de proxy en firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Postcode</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 suggestie}other{# suggesties}}</translation>
<translation id="2065985942032347596">Verificatie vereist</translation>
<translation id="2079545284768500474">Ongedaan maken</translation>
<translation id="20817612488360358">De proxyinstellingen van het systeem moeten worden gebruikt, maar er is ook een expliciete proxyconfiguratie opgegeven.</translation>
@@ -103,32 +106,34 @@
<translation id="2149973817440762519">Bladwijzer bewerken</translation>
<translation id="2166049586286450108">Volledige beheerderstoegang</translation>
<translation id="2166378884831602661">Deze site kan geen beveiligde verbinding leveren</translation>
-<translation id="2171101176734966184">Je probeert <ph name="DOMAIN" /> te bereiken. De server heeft echter een certificaat geretourneerd dat een zwak ondertekeningsalgoritme gebruikt. Dit houdt in dat de betrouwbaarheidsverklaring van de server kan zijn vervalst. Het is mogelijk dat de server zelf een imitatie is (wellicht een server die je schade probeert te berokkenen).</translation>
<translation id="2181821976797666341">Beleid</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}other{# adressen}}</translation>
<translation id="2212735316055980242">Beleid niet gevonden</translation>
<translation id="2213606439339815911">Items ophalen…</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> is niet beschikbaar</translation>
<translation id="2230458221926704099">Los problemen met je verbinding op met de <ph name="BEGIN_LINK" />diagnose-app<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Nu verzenden</translation>
<translation id="225207911366869382">Deze waarde is verouderd voor dit beleid.</translation>
<translation id="2262243747453050782">HTTP-fout</translation>
<translation id="2282872951544483773">Onbeschikbare experimenten</translation>
<translation id="2292556288342944218">Je toegang tot internet wordt geblokkeerd</translation>
<translation id="229702904922032456">Een root- of tussenliggend certificaat is verlopen.</translation>
<translation id="230155334948463882">Nieuwe kaart?</translation>
+<translation id="2305919008529760154">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is mogelijk frauduleus verstrekt. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">Voor <ph name="DOMAIN" /> zijn een gebruikersnaam en een wachtwoord vereist.</translation>
+<translation id="2318774815570432836">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website gebruikmaakt van HSTS. Aangezien netwerkfouten en aanvallen meestal van tijdelijke aard zijn, zal deze pagina later waarschijnlijk weer correct werken. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Ongeldige bladwijzer genegeerd bij index <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Andere bladwijzers</translation>
<translation id="2359808026110333948">Doorgaan</translation>
<translation id="2365563543831475020">Het crashrapport dat is vastgelegd op <ph name="CRASH_TIME" />, is niet geĂ¼pload</translation>
<translation id="2367567093518048410">Niveau</translation>
+<translation id="2371153335857947666">{1,plural, =1{Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het bijbehorende beveiligingscertificaat is gisteren verlopen. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. De klok van je computer is momenteel ingesteld op <ph name="CURRENT_DATE" />. Is dat correct? Zo niet, dan moet je de klok van je systeem aanpassen en vervolgens deze pagina vernieuwen. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.}other{Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het bijbehorende beveiligingscertificaat is # dagen geleden verlopen. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. De klok van je computer is momenteel ingesteld op <ph name="CURRENT_DATE" />. Is dat correct? Zo niet, dan moet je de klok van je systeem aanpassen en vervolgens deze pagina vernieuwen. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Geen UI-alternatieven beschikbaar</translation>
<translation id="2384307209577226199">Standaardinstelling van bedrijf</translation>
-<translation id="238526402387145295">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website <ph name="BEGIN_LINK" />gebruikmaakt van HSTS<ph name="END_LINK" />. Netwerkfouten en aanvallen zijn doorgaans tijdelijk, dus deze pagina werkt later waarschijnlijk correct.</translation>
<translation id="2386255080630008482">Het servercertificaat is ingetrokken.</translation>
<translation id="2392959068659972793">Beleid weergeven zonder waarde ingesteld</translation>
<translation id="2396249848217231973">&amp;Verwijderen ongedaan maken</translation>
-<translation id="2413528052993050574">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is mogelijk ingetrokken. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="2455981314101692989">Deze webpagina heeft Automatisch aanvullen uitgeschakeld voor dit formulier.</translation>
+<translation id="2463739503403862330">Invullen</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Netwerkcontrole uitvoeren<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ongeldige zoek-URL.</translation>
<translation id="2491120439723279231">Het servercertificaat bevat fouten.</translation>
@@ -150,10 +155,12 @@
<translation id="2653659639078652383">Verzenden</translation>
<translation id="2674170444375937751">Weet je zeker dat u deze pagina's uit je geschiedenis wilt verwijderen?</translation>
<translation id="2677748264148917807">Verlaten</translation>
+<translation id="269990154133806163">De server heeft een certificaat gepresenteerd dat niet openbaar bekend is gemaakt via het beleid voor Certificaattransparantie. Dit is voor bepaalde certificaten een vereiste om er zeker van te zijn dat ze betrouwbaar zijn en bescherming bieden tegen aanvallers. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Waarde komt niet overeen met notatie.</translation>
<translation id="2704951214193499422">Chromium kan je creditcard momenteel niet bevestigen. Probeer het later opnieuw.</translation>
<translation id="2705137772291741111">De in het cachegeheugen opgeslagen versie van deze site is niet bereikbaar.</translation>
<translation id="2709516037105925701">Automatisch aanvullen</translation>
+<translation id="2712118517637785082">Je probeert <ph name="DOMAIN" /> te bereiken, maar het certificaat dat door de server is geretourneerd, is ingetrokken door de uitgever. Dit betekent dat de beveiligingsreferenties die de server heeft geretourneerd absoluut niet kunnen worden vertrouwd. Het is mogelijk dat je met een hacker communiceert. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Toestemming vragen</translation>
<translation id="2721148159707890343">Verzoek geslaagd</translation>
<translation id="2728127805433021124">Het certificaat van de server is ondertekend met een zwak ondertekeningsalgoritme.</translation>
@@ -165,14 +172,11 @@
<translation id="2824775600643448204">Adres- en zoekbalk</translation>
<translation id="2826760142808435982">De verbinding is gecodeerd en geverifieerd met <ph name="CIPHER" /> en gebruikt <ph name="KX" /> als mechanisme voor sleuteluitwisseling.</translation>
<translation id="2835170189407361413">Formulier leegmaken</translation>
-<translation id="2837049386027881519">Er moest opnieuw worden geprobeerd verbinding te maken met een oudere versie van het TLS- of SSL-protocol. Dit betekent meestal dat de server zeer oude software gebruikt en mogelijk andere beveiligingsproblemen heeft.</translation>
<translation id="284702764277384724">Het servercertificaat op <ph name="HOST_NAME" /> lijkt vals te zijn.</translation>
<translation id="2889159643044928134">Niet opnieuw laden</translation>
-<translation id="2896499918916051536">Deze plug-in wordt niet ondersteund.</translation>
+<translation id="2900469785430194048">Google Chrome beschikt over onvoldoende geheugen om deze webpagina weer te geven.</translation>
<translation id="2909946352844186028">Er is een netwerkwijziging gedetecteerd.</translation>
-<translation id="2915500479781995473">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is verlopen. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. De klok van je computer is momenteel ingesteld op <ph name="CURRENT_TIME" />. Klopt dat? Zo niet, dan moet je de klok van het systeem corrigeren en deze pagina vernieuwen.</translation>
<translation id="2922350208395188000">Het servercertificaat kan niet worden gecontroleerd.</translation>
-<translation id="2941952326391522266">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is afkomstig van <ph name="DOMAIN2" />. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="2948083400971632585">Via de instellingenpagina kun je proxyservers uitschakelen die voor een verbinding zijn geconfigureerd.</translation>
<translation id="2955913368246107853">Zoekbalk sluiten</translation>
<translation id="2958431318199492670">De netwerkconfiguratie voldoet niet aan de ONC-standaard. Delen van de configuratie worden mogelijk niet geĂ¯mporteerd.</translation>
@@ -186,6 +190,7 @@
<translation id="3024663005179499861">Onjuist beleidstype</translation>
<translation id="3032412215588512954">Wil je deze site opnieuw laden?</translation>
<translation id="3037605927509011580">Helaas.</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{ten minste 1 item op gesynchroniseerde apparaten}=1{1 item (en meer op gesynchroniseerde apparaten)}other{# items (en meer op gesynchroniseerde apparaten)}}</translation>
<translation id="3041612393474885105">Certificaatgegevens</translation>
<translation id="3063697135517575841">Chrome kan je creditcard momenteel niet bevestigen. Probeer het later opnieuw.</translation>
<translation id="3093245981617870298">Je bent offline.</translation>
@@ -201,15 +206,16 @@
<translation id="3176929007561373547">Controleer je proxyinstellingen of neem contact op met je netwerkbeheerder om te controleren of de proxyserver werkt. Als je denkt dat je geen proxyserver zou moeten gebruiken: <ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Nieuwste</translation>
<translation id="3207960819495026254">Toegevoegd aan 'Bladwijzers'</translation>
-<translation id="3225919329040284222">De server heeft een certificaat gepresenteerd dat niet overeenkomt met de ingebouwde verwachtingen. Deze verwachtingen zijn opgenomen voor bepaalde websites om je te beschermen.</translation>
<translation id="3226128629678568754">Klik op de knop 'Opnieuw laden' om de gegevens opnieuw te verzenden die nodig zijn om de pagina te laden.</translation>
<translation id="3228969707346345236">De vertaling is mislukt omdat de pagina al in het <ph name="LANGUAGE" /> is.</translation>
<translation id="323107829343500871">De CVC-code voor <ph name="CREDIT_CARD" /> opgeven</translation>
<translation id="3254409185687681395">Bladwijzer instellen voor deze pagina</translation>
<translation id="3270847123878663523">&amp;Volgorde wijzigen ongedaan maken</translation>
<translation id="3286538390144397061">Nu herstarten</translation>
+<translation id="3303855915957856445">Geen zoekresultaten gevonden</translation>
<translation id="3305707030755673451">Je gegevens zijn op <ph name="TIME" /> versleuteld met je wachtwoordzin voor synchronisatie. Geef deze op om de synchronisatie te starten.</translation>
<translation id="333371639341676808">Voorkom dat deze pagina extra dialoogvensters weergeeft.</translation>
+<translation id="3338095232262050444">Veilig</translation>
<translation id="3340978935015468852">instellingen</translation>
<translation id="3345135638360864351">Je verzoek om toegang tot deze site kan niet worden verzonden naar <ph name="NAME" />. Probeer het opnieuw.</translation>
<translation id="3355823806454867987">Proxyinstellingen wijzigen...</translation>
@@ -227,6 +233,7 @@
<translation id="3452404311384756672">Ophaalinterval:</translation>
<translation id="3462200631372590220">Gedetailleerde informatie verbergen</translation>
<translation id="3479539252931486093">Wat dit onverwacht? <ph name="BEGIN_LINK" />Laat het ons weten<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Niet nu</translation>
<translation id="348000606199325318">Crash-ID <ph name="CRASH_LOCAL_ID" /> (Server-ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">We kunnen je ouder momenteel niet bereiken. Probeer het opnieuw.</translation>
<translation id="3527085408025491307">Map</translation>
@@ -235,6 +242,7 @@
<translation id="3542684924769048008">Wachtwoord gebruiken voor:</translation>
<translation id="3549644494707163724">Alle gesynchroniseerde gegevens versleutelen met je eigen wachtwoordzin voor synchronisatie</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> meer...</translation>
+<translation id="3555561725129903880">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is afkomstig van <ph name="DOMAIN2" />. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Je verbinding is niet privé</translation>
<translation id="3583757800736429874">&amp;Opnieuw verplaatsen</translation>
<translation id="3586931643579894722">Details verbergen</translation>
@@ -245,12 +253,15 @@
<translation id="362276910939193118">Volledige geschiedenis weergeven</translation>
<translation id="3623476034248543066">Waarde weergeven</translation>
<translation id="3630155396527302611">Als dit programma al wordt vermeld als een programma dat toegang heeft tot het netwerk, kun je proberen het uit de lijst te verwijderen en het opnieuw toe te voegen.</translation>
+<translation id="3638794133396384728">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is verlopen. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. De klok van je computer is momenteel ingesteld op <ph name="CURRENT_TIME" />. Is dat correct? Zo niet, dan moet je de klok van je systeem aanpassen en vervolgens deze pagina vernieuwen. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Deze experimentele functies kunnen op elk moment worden aangepast, vastlopen of verdwijnen. We bieden geen enkele garantie aangaande wat er gebeurt als je een van deze experimenten inschakelt: je browser kan zelfs spontaan in brand vliegen. Alle gekheid op een stokje, het is mogelijk dat alle gegevens in je browser worden gewist, of dat je veiligheid en privacy op onverwachte manieren risico lopen. Experimenten die je inschakelt, worden ingeschakeld voor alle gebruikers van deze browser. Let dus goed op wat je doet.</translation>
<translation id="3650584904733503804">Validatie geslaagd</translation>
<translation id="3655670868607891010">Als je deze melding vaker ziet, probeer je deze <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Revisie</translation>
+<translation id="3678029195006412963">Verzoek kan niet worden ondertekend</translation>
<translation id="3681007416295224113">Certificaatgegevens</translation>
<translation id="3693415264595406141">Wachtwoord:</translation>
+<translation id="3696411085566228381">geen</translation>
<translation id="3700528541715530410">Het lijkt erop dat je geen toestemming hebt om deze pagina te openen.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Laden...</translation>
@@ -258,7 +269,6 @@
<translation id="3714780639079136834">Schakel mobiele data of wifi in</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Controleer de proxy, firewall en DNS-configuratie<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Link die je hebt gekopieerd</translation>
-<translation id="3744899669254331632">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website gecodeerde inloggegevens heeft verstuurd die niet door Chromium kunnen worden verwerkt. Aangezien netwerkfouten en aanvallen doorgaans van tijdelijke aard zijn, zal deze pagina later waarschijnlijk wel werken.</translation>
<translation id="375403751935624634">Het vertalen is mislukt wegens een serverfout.</translation>
<translation id="3759461132968374835">Je hebt geen onlangs gemelde crashes. Crashes die zich voordeden toen de crashrapportage was uitgeschakeld, worden hier niet weergegeven.</translation>
<translation id="3788090790273268753">Het certificaat voor deze site verloopt in 2016 en de certificaatketen bevat een certificaat dat is ondertekend met SHA-1.</translation>
@@ -270,19 +280,25 @@
<translation id="3884278016824448484">Conflicterende apparaat-ID's</translation>
<translation id="3885155851504623709">Gemeente</translation>
<translation id="3901925938762663762">De kaart is verlopen</translation>
+<translation id="3910267023907260648">Je probeert <ph name="DOMAIN" /> te bereiken. De server heeft echter een certificaat geretourneerd dat een zwak ondertekeningsalgoritme gebruikt. Dit betekent dat de beveiligingsreferenties die de server heeft geretourneerd mogelijk zijn vervalst en de server zelf een imitatie is (wellicht een server die je schade probeert te berokkenen). <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het bijbehorende beveiligingscertificaat is zogenaamd van morgen. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.}other{Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het bijbehorende beveiligingscertificaat is zogenaamd van # dagen in de toekomst. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF-document kan niet worden geladen</translation>
<translation id="3963721102035795474">Lezermodus</translation>
+<translation id="397105322502079400">Berekenen...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> wordt geblokkeerd</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 webpagina in de buurt}other{# webpagina's in de buurt}}</translation>
<translation id="4021036232240155012">DNS is de netwerkservice die de naam van een website omzet naar het bijbehorende internetadres.</translation>
<translation id="4030383055268325496">&amp;Toevoegen ongedaan maken</translation>
-<translation id="4032534284272647190">Toegang tot <ph name="URL" /> geweigerd.</translation>
<translation id="404928562651467259">WAARSCHUWING</translation>
<translation id="4058922952496707368">Sleutel '<ph name="SUBKEY" />': <ph name="ERROR" /></translation>
<translation id="4075732493274867456">De client en server ondersteunen geen algemene SSL-protocolversie of coderingssuite.</translation>
<translation id="4079302484614802869">Proxyconfiguratie is ingesteld op het gebruik van een pac-script-URL, niet op het gebruik van vaste proxyservers.</translation>
<translation id="4103249731201008433">Serienummer van apparaat is ongeldig</translation>
<translation id="4103763322291513355">Ga naar &lt;strong&gt;chrome://policy&lt;/strong&gt; om de lijst met URL's op de zwarte lijst en andere beleidsregels te bekijken die worden afgedwongen door je systeembeheerder.</translation>
+<translation id="4110615724604346410">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server bevat fouten. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Beleidsbereik wordt niet ondersteund.</translation>
+<translation id="4118212371799607889">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door Chromium. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 andere persoon}other{# andere mensen}}</translation>
<translation id="4130226655945681476">Controleer de netwerkkabels, modem en router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Wil je dat Chromium deze kaart opslaat?</translation>
@@ -290,6 +306,7 @@
<translation id="4176463684765177261">Uitgeschakeld</translation>
<translation id="4196861286325780578">&amp;Opnieuw verplaatsen</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Controleer firewall- en antivirusconfiguraties<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{geen}=1{1 app ($1)}=2{2 apps ($1, $2)}other{# apps ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Crashes</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Voer Netwerkcontrole uit<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Nee</translation>
@@ -298,14 +315,15 @@
<translation id="4269787794583293679">(Geen gebruikersnaam)</translation>
<translation id="4300246636397505754">Bovenliggende suggesties</translation>
<translation id="4304224509867189079">Inloggen</translation>
+<translation id="432290197980158659">De server heeft een certificaat gepresenteerd dat niet overeenkomt met de ingebouwde verwachtingen. Deze verwachtingen zijn opgenomen voor bepaalde zwaar beveiligde websites om je te beschermen. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Kan artikel niet vinden</translation>
+<translation id="4331708818696583467">Niet veilig</translation>
<translation id="4372948949327679948">Verwachte <ph name="VALUE_TYPE" /> waarde.</translation>
-<translation id="4377125064752653719">Je probeert <ph name="DOMAIN" /> te bereiken, maar het certificaat dat de server heeft geretourneerd, is ingetrokken door de uitgever. Dat betekent dat de veiligheidsgaranties die de server heeft geretourneerd, absoluut niet kunnen worden vertrouwd. Het kan zijn dat je met een hacker aan het communiceren bent.</translation>
<translation id="4381091992796011497">Gebruikersnaam:</translation>
<translation id="4394049700291259645">Uitschakelen</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> tot <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">zoekresultaten</translation>
-<translation id="4424024547088906515">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door Chrome. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> heeft je inlogcertificaat niet geaccepteerd of er is geen inlogcertificaat geleverd.</translation>
<translation id="443673843213245140">Het gebruik van een proxy is uitgeschakeld, maar er is wel een expliciete proxyconfiguratie opgegeven.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Dit bericht wordt weergegeven omdat Google SafeSites is ingeschakeld.</translation>
@@ -317,12 +335,12 @@
<translation id="4522570452068850558">Details</translation>
<translation id="4558551763791394412">Probeer je extensies uit te schakelen.</translation>
<translation id="4587425331216688090">Adres verwijderen uit Chrome?</translation>
+<translation id="4589078953350245614">Je probeert <ph name="DOMAIN" /> te bereiken, maar de server heeft een ongeldig certificaat geretourneerd. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Je verbinding met <ph name="DOMAIN" /> is versleuteld via een moderne Cipher Suite.</translation>
<translation id="4594403342090139922">&amp;Verwijderen ongedaan maken</translation>
+<translation id="4627442949885028695">Doorgaan vanaf een ander apparaat</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Je bekijkt nu een extensiepagina.</translation>
-<translation id="467662567472608290">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server bevat fouten. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> wordt geblokkeerd</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Je verbinding is onderbroken</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows Netwerkcontrole uitvoeren<ph name="END_LINK" /></translation>
@@ -330,21 +348,26 @@
<translation id="4728558894243024398">Platform</translation>
<translation id="4744603770635761495">Uitvoerbaar pad</translation>
<translation id="4756388243121344051">Gesc&amp;hiedenis</translation>
+<translation id="4759238208242260848">Downloads</translation>
<translation id="4764776831041365478">De webpagina op <ph name="URL" /> is mogelijk tijdelijk uitgeschakeld of permanent verplaatst naar een nieuw webadres.</translation>
<translation id="4771973620359291008">Er is een onbekende fout opgetreden.</translation>
<translation id="4782449893814226250">Je hebt je ouders gevraagd of je deze pagina mag bezoeken.</translation>
<translation id="4800132727771399293">Controleer je vervaldatum en CVC-code en probeer het opnieuw</translation>
-<translation id="4807049035289105102">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website gecodeerde inloggegevens heeft verzonden die niet door Google Chrome kunnen worden verwerkt. Netwerkfouten en aanvallen zijn meestal tijdelijk, dus deze pagina werkt later waarschijnlijk weer correct.</translation>
<translation id="4813512666221746211">Netwerkfout</translation>
<translation id="4816492930507672669">Aanpassen aan pagina</translation>
<translation id="4850886885716139402">Weergave</translation>
<translation id="4880827082731008257">Geschiedenis doorzoeken</translation>
+<translation id="4884656795097055129">Er worden meer artikelen weergegeven wanneer deze beschikbaar zijn.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{en nog 1 webpagina}other{en nog # webpagina's}}</translation>
<translation id="4923417429809017348">Deze pagina is vertaald uit een onbekende taal naar het <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Moet worden opgegeven.</translation>
<translation id="4930497775425430760">Dit bericht wordt weergegeven omdat je vader of moeder nieuwe sites moet goedkeuren wanneer je ze voor het eerst bezoekt.</translation>
<translation id="495170559598752135">Acties</translation>
<translation id="4958444002117714549">Lijst uitvouwen</translation>
+<translation id="4962322354953122629">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door Chrome. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Vertalen uit het <ph name="ORIGINAL_LANGUAGE" /> naar het <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Deze plug-in wordt niet ondersteund</translation>
<translation id="5002932099480077015">Indien ingeschakeld, slaat Chrome een kopie van je kaart op dit apparaat op zodat formulieren sneller kunnen worden ingevuld.</translation>
<translation id="5019198164206649151">Backend-opslag in slechte staat</translation>
<translation id="5023310440958281426">Neem het beleid van je beheerder door</translation>
@@ -352,13 +375,12 @@
<translation id="5031870354684148875">Over Google Translate</translation>
<translation id="5040262127954254034">Privacy</translation>
<translation id="5045550434625856497">Onjuist wachtwoord</translation>
+<translation id="5056549851600133418">Artikelen voor jou</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Het proxy-adres controleren<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Het servercertificaat is momenteel niet geldig.</translation>
<translation id="5089810972385038852">Staat</translation>
-<translation id="5094747076828555589">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door Chromium. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="5095208057601539847">Provincie</translation>
<translation id="5115563688576182185">(64-bits)</translation>
-<translation id="5122371513570456792"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> gevonden voor '<ph name="SEARCH_STRING" />'.</translation>
<translation id="5141240743006678641">Gesynchroniseerde wachtwoorden versleutelen met je Google-aanmeldingsgegevens</translation>
<translation id="5145883236150621069">Foutcode aanwezig in de beleidsreactie</translation>
<translation id="5171045022955879922">Zoek of typ een URL</translation>
@@ -367,18 +389,18 @@
<translation id="5190835502935405962">Bladwijzerbalk</translation>
<translation id="5199729219167945352">Experimenten</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">Gebruik je Chrome op het werk? Bedrijven kunnen Chrome-instellingen beheren voor hun werknemers. Meer informatie</translation>
<translation id="5299298092464848405">Fout bij het parseren van het beleid</translation>
<translation id="5300589172476337783">Weergeven</translation>
<translation id="5308689395849655368">Crashrapportage is uitgeschakeld.</translation>
<translation id="5317780077021120954">Opslaan</translation>
<translation id="5327248766486351172">Naam</translation>
+<translation id="5359637492792381994">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat is momenteel niet geldig. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Opslaan van beleidsinstellingen is mislukt</translation>
-<translation id="540969355065856584">Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat is momenteel niet geldig. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="5421136146218899937">Browsegegevens wissen...</translation>
<translation id="5430298929874300616">Bladwijzer verwijderen</translation>
<translation id="5431657950005405462">Je bestand is niet gevonden</translation>
<translation id="5435775191620395718">Geschiedenis van dit apparaat wordt weergegeven. <ph name="BEGIN_LINK" />Meer informatie<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Je ontvangt momenteel geen suggesties voor gepersonaliseerde content, omdat je gesynchroniseerde gegevens zijn beveiligd met een wachtwoordzin.</translation>
<translation id="5439770059721715174">Schemavalidatiefout op '<ph name="ERROR_PATH" />': <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Deze pagina op <ph name="HOST_NAME" /> kan niet worden gevonden</translation>
<translation id="5455374756549232013">Onjuist tijdstempel van beleid</translation>
@@ -401,14 +423,18 @@
<translation id="5622887735448669177">Wil je deze site verlaten?</translation>
<translation id="5629630648637658800">Laden van beleidsinstellingen is mislukt</translation>
<translation id="5631439013527180824">Ongeldige token voor apparaatbeheer</translation>
-<translation id="5650551054760837876">Geen zoekresultaten gevonden.</translation>
<translation id="5677928146339483299">Geblokkeerd</translation>
<translation id="5710435578057952990">De identiteit van deze website is niet geverifieerd.</translation>
<translation id="5720705177508910913">Huidige gebruiker</translation>
+<translation id="572328651809341494">Recent gebruikte tabbladen</translation>
<translation id="5784606427469807560">Er is een probleem opgetreden bij het bevestigen van je creditcard. Controleer je internetverbinding en probeer het opnieuw.</translation>
<translation id="5785756445106461925">Bovendien bevat deze pagina bronnen die niet beveiligd zijn. Deze bronnen kunnen tijdens verzending door anderen worden bekeken en kunnen door een aanvaller worden gewijzigd om het uiterlijk van de pagina aan te passen.</translation>
+<translation id="5786044859038896871">Wil je de gegevens van je creditcard laten invullen?</translation>
+<translation id="5803412860119678065">Wil je de gegevens van je <ph name="CARD_DETAIL" /> laten invullen?</translation>
<translation id="5810442152076338065">Je verbinding met <ph name="DOMAIN" /> is versleuteld via een verouderde Cipher Suite.</translation>
<translation id="5813119285467412249">&amp;Opnieuw toevoegen</translation>
+<translation id="5814352347845180253">Mogelijk heb je geen toegang meer tot premium content van <ph name="SITE" /> en enkele andere sites.</translation>
+<translation id="5843436854350372569">Je probeert <ph name="DOMAIN" /> te bereiken, maar de server heeft een certificaat geretourneerd met een zwakke sleutel. Een hacker kan de persoonlijke sleutel hebben aangepast en het is mogelijk dat de server zelf een imitatie is (wellicht een server die je schade probeert te berokkenen). <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Dit bericht wordt weergegeven omdat je beheerder deze site heeft geblokkeerd.</translation>
<translation id="5857090052475505287">Nieuwe map</translation>
<translation id="5869405914158311789">Deze site is niet bereikbaar</translation>
@@ -416,6 +442,7 @@
<translation id="5872918882028971132">Bovenliggende suggesties</translation>
<translation id="59107663811261420">Dit type kaart wordt voor deze verkoper niet ondersteund door Google Payments. Selecteer een andere kaart.</translation>
<translation id="59174027418879706">Ingeschakeld</translation>
+<translation id="5926846154125914413">Mogelijk heb je geen toegang meer tot premium content van bepaalde sites.</translation>
<translation id="5966707198760109579">Week</translation>
<translation id="5967867314010545767">Verwijderen uit geschiedenis</translation>
<translation id="5975083100439434680">Uitzoomen</translation>
@@ -427,11 +454,11 @@
<translation id="604124094241169006">Automatisch</translation>
<translation id="6042308850641462728">Meer</translation>
<translation id="6060685159320643512">Pas op, dit zijn geen experimenten om zonder handschoenen aan te pakken</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{geen}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Controleer alle kabels en start alle routers, modems of andere netwerkapparaten die je gebruikt, opnieuw op.</translation>
<translation id="614940544461990577">Probeer het volgende:</translation>
<translation id="6150607114729249911">Je moet je ouders vragen of je deze pagina mag bezoeken.</translation>
<translation id="6151417162996330722">Het servercertificaat heeft een te lange geldigheidsperiode.</translation>
-<translation id="6154808779448689242">Geretourneerde beleidstoken komt niet overeen met huidige token</translation>
<translation id="6165508094623778733">Meer informatie</translation>
<translation id="6203231073485539293">Controleer je internetverbinding</translation>
<translation id="6218753634732582820">Adres verwijderen uit Chromium?</translation>
@@ -444,24 +471,30 @@
<translation id="6328639280570009161">Probeer netwerkvoorspelling uit te schakelen</translation>
<translation id="6337534724793800597">Beleid filteren op naam</translation>
<translation id="6342069812937806050">Zojuist</translation>
+<translation id="6345221851280129312">onbekende grootte</translation>
<translation id="6355080345576803305">Overschrijving voor openbare sessie</translation>
<translation id="6358450015545214790">Wat betekent dit?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 andere suggestie}other{# andere suggesties}}</translation>
<translation id="6387478394221739770">Ben je geĂ¯nteresseerd in nieuwe, coole Chrome-functies? Probeer ons bèta-kanaal op chrome.com/beta.</translation>
-<translation id="641480858134062906">Kan <ph name="URL" /> niet laden</translation>
+<translation id="6389758589412724634">Chromium beschikt over onvoldoende geheugen om deze webpagina weer te geven.</translation>
+<translation id="6416403317709441254">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website gecodeerde inloggegevens heeft verstuurd die niet door Chromium kunnen worden verwerkt. Aangezien netwerkfouten en aanvallen meestal van tijdelijke aard zijn, zal deze pagina later waarschijnlijk weer correct werken. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Kan niet controleren of het certificaat is ingetrokken.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> heeft de verbinding geweigerd.</translation>
<translation id="6445051938772793705">Land</translation>
<translation id="6451458296329894277">Opnieuw indienen bevestigen</translation>
<translation id="6458467102616083041">Genegeerd omdat de standaardzoekoptie door het beleid is uitgeschakeld.</translation>
+<translation id="6462969404041126431">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is mogelijk ingetrokken. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Apparaatbeleid</translation>
<translation id="6489534406876378309">Uploaden van crashes starten</translation>
<translation id="6529602333819889595">&amp;Opnieuw verwijderen</translation>
+<translation id="6534179046333460208">Fysieke web-suggesties</translation>
<translation id="6550675742724504774">Opties</translation>
+<translation id="6593753688552673085">minder dan <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opties voor encryptie</translation>
<translation id="662080504995468778">Blijven</translation>
<translation id="6628463337424475685">Zoeken via <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat <ph name="BEGIN_LINK" />dit certificaat is ingetrokken<ph name="END_LINK" />. Netwerkfouten en aanvallen zijn doorgaans tijdelijk, dus deze pagina werkt later waarschijnlijk correct.</translation>
<translation id="6644283850729428850">Dit beleid is verouderd.</translation>
+<translation id="6652240803263749613">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door het besturingssysteem van je computer. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Map bewerken</translation>
<translation id="6660210980321319655">Automatisch gemeld: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Formuliersuggestie verwijderen uit Chromium?</translation>
@@ -469,6 +502,7 @@
<translation id="6710213216561001401">Vorige</translation>
<translation id="6710594484020273272">&lt;Typ een zoekterm&gt;</translation>
<translation id="6711464428925977395">Er is iets mis met de proxyserver of het adres is onjuist.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{geen}=1{1 item}other{# items}}</translation>
<translation id="674375294223700098">Onbekende fout met servercertificaat.</translation>
<translation id="6753269504797312559">Beleidswaarde</translation>
<translation id="6757797048963528358">De slaapstand van je apparaat is geactiveerd.</translation>
@@ -480,7 +514,6 @@
<translation id="6891596781022320156">Beleidsniveau wordt niet ondersteund.</translation>
<translation id="6895330447102777224">Je creditcard is bevestigd</translation>
<translation id="6897140037006041989">User-agent</translation>
-<translation id="6903907808598579934">Synchronisatie inschakelen</translation>
<translation id="6915804003454593391">Gebruiker:</translation>
<translation id="6957887021205513506">Het certificaat van de server lijkt vals te zijn.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -488,9 +521,11 @@
<translation id="6970216967273061347">District</translation>
<translation id="6973656660372572881">Zowel vaste proxyservers als een pac-script-URL worden gespecificeerd.</translation>
<translation id="6989763994942163495">Geavanceerde instellingen weergeven...</translation>
+<translation id="7000990526846637657">Geen geschiedenisitems gevonden</translation>
+<translation id="7009986207543992532">Je probeert <ph name="DOMAIN" /> te bereiken, maar de server heeft een certificaat geretourneerd waarvan de geldigheidsperiode te lang is om betrouwbaar te zijn. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Voor je Google-account kunnen andere vormen van browsegeschiedenis beschikbaar zijn via <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Wachtwoorden</translation>
-<translation id="7050187094878475250">Je hebt geprobeerd <ph name="DOMAIN" /> te bereiken, maar de server heeft een certificaat gepresenteerd waarvan de geldigheidsperiode te lang is om betrouwbaar te zijn.</translation>
<translation id="7087282848513945231">County</translation>
<translation id="7088615885725309056">Ouder</translation>
<translation id="7090678807593890770">Zoek op Google naar <ph name="LINK" /></translation>
@@ -509,13 +544,13 @@
<translation id="7246609911581847514">Dit bericht wordt weergegeven omdat je beheerder nieuwe sites moet goedkeuren wanneer je ze voor het eerst bezoekt.</translation>
<translation id="724975217298816891">Geef de vervaldatum en CVC-code voor <ph name="CREDIT_CARD" /> op om je creditcardgegevens te updaten. Zodra je bevestigt, worden je creditcardgegevens gedeeld met deze site.</translation>
<translation id="725866823122871198">Er kan geen privéverbinding met <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tot stand worden gebracht, omdat de datum en tijd van de computer (<ph name="DATE_AND_TIME" />) onjuist zijn.</translation>
-<translation id="7265986070661382626">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website <ph name="BEGIN_LINK" />gebruikmaakt van certificaatpinning<ph name="END_LINK" />. Netwerkfouten en aanvallen zijn doorgaans tijdelijk, dus deze pagina werkt later waarschijnlijk correct.</translation>
<translation id="7269802741830436641">Deze webpagina bevat een omleidingslus</translation>
<translation id="7275334191706090484">Beheerde bladwijzers</translation>
<translation id="7298195798382681320">Aanbevolen</translation>
-<translation id="7301833672208172928">Synchronisatie van geschiedenis inschakelen</translation>
+<translation id="7309308571273880165">Crashrapport vastgelegd op <ph name="CRASH_TIME" /> (upload aangevraagd door gebruiker, nog niet geĂ¼pload)</translation>
<translation id="7334320624316649418">&amp;Opnieuw volgorde wijzigen</translation>
<translation id="733923710415886693">Het certificaat van de server is niet bekendgemaakt via Certificaattransparantie.</translation>
+<translation id="7351800657706554155">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat het bijbehorende certificaat is ingetrokken. Aangezien netwerkfouten en aanvallen meestal van tijdelijke aard zijn, werkt deze pagina later waarschijnlijk weer correct. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Opdrachtregel</translation>
<translation id="7372973238305370288">zoekresultaat</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -534,16 +569,17 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="7469372306589899959">Creditcard bevestigen</translation>
<translation id="7481312909269577407">Vooruit</translation>
<translation id="7485870689360869515">Geen gegevens gevonden.</translation>
+<translation id="7508255263130623398">Geretourneerde apparaat-ID voor beleid is leeg of komt niet overeen met de huidige apparaat-ID</translation>
<translation id="7514365320538308">Downloaden</translation>
<translation id="7518003948725431193">Er is geen webpagina gevonden voor het webadres: <ph name="URL" /></translation>
<translation id="7537536606612762813">Verplicht</translation>
<translation id="7542995811387359312">Het automatisch invullen van creditcardnummers is uitgeschakeld, omdat dit formulier geen beveiligde verbinding gebruikt.</translation>
<translation id="7549584377607005141">Deze webpagina kan alleen correct worden weergegeven op basis van gegevens die je eerder hebt opgegeven. Je kunt deze gegevens opnieuw verzenden, maar hierdoor worden de acties herhaald die eerder op deze pagina zijn uitgevoerd.</translation>
<translation id="7554791636758816595">Nieuw tabblad</translation>
-<translation id="7567204685887185387">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is mogelijk frauduleus verstrekt. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="7568593326407688803">Deze pagina is geschreven in het<ph name="ORIGINAL_LANGUAGE" />Wil je deze laten vertalen?</translation>
<translation id="7569952961197462199">Creditcard verwijderen uit Chrome?</translation>
<translation id="7578104083680115302">Betaal op verschillende apparaten snel op sites en in apps met kaarten die je hebt opgeslagen via Google.</translation>
+<translation id="7588950540487816470">Fysieke web</translation>
<translation id="7592362899630581445">Het certificaat van de server is in strijd met naambeperkingen.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> kan dit verzoek momenteel niet verwerken.</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" /> nooit vertalen</translation>
@@ -554,6 +590,7 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="7637571805876720304">Creditcard verwijderen uit Chromium?</translation>
<translation id="765676359832457558">Geavanceerde instellingen verbergen...</translation>
<translation id="7658239707568436148">Annuleren</translation>
+<translation id="7667346355482952095">Geretourneerde beleidstoken is leeg of komt niet overeen met huidige token</translation>
<translation id="7668654391829183341">Onbekend apparaat</translation>
<translation id="7674629440242451245">Ben je geĂ¯nteresseerd in nieuwe, coole Chrome-functies? Probeer ons ontwikkelaarskanaal op chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Doorgaan naar <ph name="SITE" /> (onveilig)<ph name="END_LINK" /></translation>
@@ -570,10 +607,10 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="780301667611848630">Nee, bedankt</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7813600968533626083">Formuliersuggestie verwijderen uit Chrome?</translation>
+<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> gevonden voor '<ph name="SEARCH_STRING" />'</translation>
<translation id="785549533363645510">Je bent echter niet onzichtbaar. Als je incognito bent, wordt je browsegeschiedenis niet verborgen voor je werkgever, je internetprovider of de websites die je bezoekt.</translation>
<translation id="7887683347370398519">Controleer je CVC-code en probeer het opnieuw</translation>
<translation id="7894616681410591072">Je hebt toestemming van <ph name="NAME" /> nodig om deze pagina te openen.</translation>
-<translation id="790025292736025802">Kan <ph name="URL" /> niet vinden</translation>
<translation id="7912024687060120840">In map:</translation>
<translation id="7920092496846849526">Je hebt je vader of moeder gevraagd of je deze pagina mag bezoeken.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -586,9 +623,10 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="7995512525968007366">Niet opgegeven</translation>
<translation id="8012647001091218357">We kunnen je ouders momenteel niet bereiken. Probeer het opnieuw.</translation>
<translation id="8034522405403831421">Deze pagina is in het <ph name="SOURCE_LANGUAGE" />. Vertalen naar het <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Geen items gevonden.</translation>
<translation id="8088680233425245692">Kan artikel niet bekijken.</translation>
+<translation id="8089520772729574115">minder dan 1 MB</translation>
<translation id="8091372947890762290">Activering is in behandeling op de server</translation>
+<translation id="8129262335948759431">onbekende hoeveelheid</translation>
<translation id="8131740175452115882">Bevestigen</translation>
<translation id="8134994873729925007">Het <ph name="BEGIN_ABBR" />DNS-adres<ph name="END_ABBR" /> van de server van <ph name="HOST_NAME" /> kan niet worden gevonden.</translation>
<translation id="8149426793427495338">De slaapstand van je computer is geactiveerd.</translation>
@@ -597,6 +635,7 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="8201077131113104583">Ongeldige update-URL voor de extensie met de ID '<ph name="EXTENSION_ID" />'.</translation>
<translation id="8218327578424803826">Toegewezen locatie:</translation>
<translation id="8225771182978767009">De persoon die deze computer heeft geconfigureerd, heeft deze site geblokkeerd.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">De pagina die je zoekt, heeft informatie gebruikt die je hebt opgegeven Als je terugkeert naar deze pagina, worden acties die je hebt uitgevoerd, mogelijk herhaald. Wil je doorgaan?</translation>
<translation id="8249320324621329438">Laatst opgehaald:</translation>
<translation id="8261506727792406068">Verwijderen</translation>
@@ -609,12 +648,17 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="8349305172487531364">Bladwijzerbalk</translation>
<translation id="8363502534493474904">Schakel de vliegtuigmodus uit</translation>
<translation id="8364627913115013041">Niet ingesteld.</translation>
+<translation id="8380941800586852976">Gevaarlijk</translation>
<translation id="8412145213513410671">Crashes (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Je moet twee keer dezelfde wachtwoordzin opgeven.</translation>
<translation id="8428213095426709021">Instellingen</translation>
+<translation id="8433057134996913067">Hiermee word je uitgelogd van de meeste websites.</translation>
<translation id="8437238597147034694">&amp;Verplaatsen ongedaan maken</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 creditcard}other{# creditcards}}</translation>
+<translation id="8483780878231876732">Log in bij Chrome om kaarten uit je Google-account te gebruiken</translation>
<translation id="8488350697529856933">Van toepassing op</translation>
<translation id="8498891568109133222">Het duurt te lang voordat <ph name="HOST_NAME" /> reageert.</translation>
+<translation id="852346902619691059">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door het besturingssysteem van je apparaat. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Dit type kaart wordt niet ondersteund door Google Payments. Selecteer een andere kaart.</translation>
<translation id="8550022383519221471">De synchronisatieservice is niet beschikbaar voor je domein.</translation>
<translation id="8553075262323480129">De vertaling is mislukt omdat de taal van de pagina niet kan worden bepaald.</translation>
@@ -626,15 +670,12 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="8647750283161643317">Alle standaardinstellingen herstellen</translation>
<translation id="8680787084697685621">De inloggegevens voor het account zijn verouderd.</translation>
<translation id="8703575177326907206">Je verbinding met <ph name="DOMAIN" /> is niet gecodeerd.</translation>
-<translation id="8713130696108419660">Onjuiste eerste handtekening</translation>
<translation id="8725066075913043281">Opnieuw proberen</translation>
<translation id="8728672262656704056">Je bent incognito</translation>
<translation id="8730621377337864115">Gereed</translation>
<translation id="8738058698779197622">Als je een veilige verbinding tot stand wilt brengen, moet je klok goed zijn ingesteld. Dit moet omdat de certificaten die deze websites gebruiken om zichzelf te identificeren, slechts gedurende bepaalde perioden geldig zijn. Aangezien de klok van je apparaat niet goed is ingesteld, kan Chromium deze certificaten niet verifiëren.</translation>
<translation id="8740359287975076522">Het &lt;abbr id="dnsDefinition"&gt;DNS-adres&lt;/abbr&gt; van <ph name="HOST_NAME" /> kan niet worden gevonden. Er wordt een diagnose van het probleem uitgevoerd.</translation>
-<translation id="8741995161408053644">Voor je Google-account kunnen andere vormen van browsegeschiedenis beschikbaar zijn via <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Opnieuw verwijderen</translation>
-<translation id="8790687370365610530">Schakel synchronisatie van de geschiedenis in om suggesties met gepersonaliseerde content van Google te ontvangen.</translation>
<translation id="8798099450830957504">Standaard</translation>
<translation id="8804164990146287819">Privacybeleid</translation>
<translation id="8820817407110198400">Bladwijzers</translation>
@@ -656,13 +697,11 @@ De volgende keer kan het handig zijn de incognitomodus <ph name="SHORTCUT_KEY" /
<translation id="8971063699422889582">Het servercertificaat is verlopen.</translation>
<translation id="8987927404178983737">Maand</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">De server heeft een certificaat gepresenteerd dat niet openbaar bekend is gemaakt via het beleid voor Certificaattransparantie. Dit is voor bepaalde certificaten een vereiste om er zeker van te zijn dat ze betrouwbaar zijn en bescherming bieden tegen aanvallers.</translation>
<translation id="9001074447101275817">Voor de proxy <ph name="DOMAIN" /> zijn een gebruikersnaam en wachtwoord vereist.</translation>
<translation id="901974403500617787">Markeringen die op het hele systeem van toepassing zijn, kunnen alleen worden ingesteld door de eigenaar: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Deze pagina is vertaald naar het <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Een voorspellingsservice gebruiken om pagina's sneller te laden</translation>
<translation id="9039213469156557790">Bovendien bevat deze pagina bronnen die niet beveiligd zijn. Deze bronnen kunnen tijdens verzending door anderen worden bekeken en kunnen door een aanvaller worden gewijzigd om het gedrag van de pagina aan te passen.</translation>
-<translation id="9049981332609050619">Je probeert <ph name="DOMAIN" /> te bereiken, maar de server heeft een ongeldig certificaat geretourneerd.</translation>
<translation id="9050666287014529139">Wachtwoordzin</translation>
<translation id="9065203028668620118">Bewerken</translation>
<translation id="9092364396508701805">De pagina op <ph name="HOST_NAME" /> werkt niet</translation>
diff --git a/chromium/components/strings/components_strings_no.xtb b/chromium/components/strings/components_strings_no.xtb
index 4da87546931..b16904e7012 100644
--- a/chromium/components/strings/components_strings_no.xtb
+++ b/chromium/components/strings/components_strings_no.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="no">
+<translation id="1008557486741366299">Ikke nĂ¥</translation>
<translation id="1015730422737071372">Oppgi flere detaljer</translation>
<translation id="1032854598605920125">Rotér med klokken</translation>
<translation id="1038842779957582377">ukjent navn</translation>
+<translation id="1053591932240354961">Du kan ikke gĂ¥ til <ph name="SITE" /> akkurat nĂ¥, fordi nettstedet sendte kryptert legitimasjon som Google Chrome ikke kan behandle. Nettverksfeil og -angrep er som regel kortvarige, sĂ¥ denne siden fungerer nok igjen senere. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Angre tilleggingen</translation>
<translation id="10614374240317010">Aldri lagret</translation>
-<translation id="1064422015032085147">Det kan hende tjeneren som er vert for nettsiden, er overbelastet, eller at det utføres vedlikehold pĂ¥ den.
- Forespørsler til denne nettadressen er midlertidig stanset for Ă¥ unngĂ¥ at
- det genereres for mye trafikk og situasjonen forverres.</translation>
<translation id="106701514854093668">Bokmerker pĂ¥ datamaskinen</translation>
<translation id="1080116354587839789">Tilpass til vindusbredden</translation>
+<translation id="1103124106085518534">Ferdig inntil videre</translation>
<translation id="1103523840287552314">Oversett alltid <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Hvis det er merket av for dette alternativet, lagrer Chrome en kopi av kortet ditt pĂ¥ denne enheten, slik at det gĂ¥r raskere Ă¥ fylle ut skjemaer.</translation>
+<translation id="1111153019813902504">Nylige bokmerker</translation>
<translation id="1113869188872983271">&amp;Angre omorganiseringen</translation>
+<translation id="1126551341858583091">Størrelsen pĂ¥ den lokale lagringsplassen er <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Bufferen for enhetsinnstillinger er OK</translation>
<translation id="113188000913989374"><ph name="SITE" /> sier:</translation>
<translation id="1132774398110320017">Innstillinger for autofyll i Chrome</translation>
-<translation id="1150979032973867961">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren er ikke klarert av datamaskinens operativsystem. Dette kan være forĂ¥rsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="1152921474424827756">Ă…pne en <ph name="BEGIN_LINK" />bufret kopi<ph name="END_LINK" /> av <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> avsluttet tilkoblingen uventet.</translation>
<translation id="1161325031994447685">Koble til Wi-Fi pĂ¥ nytt</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Fjern</translation>
<translation id="1201402288615127009">Neste</translation>
<translation id="1201895884277373915">Mer fra dette nettstedet</translation>
-<translation id="121201262018556460">Du forsøkte Ă¥ gĂ¥ til <ph name="DOMAIN" />, men tjeneren presenterte et sertifikat som inneholder en svak nøkkel. En angriper kan ha løst den private nøkkelen, og tjeneren er kanskje ikke den tjeneren du forventet (det kan hende at du kommuniserer med en angriper).</translation>
+<translation id="1206967143813997005">Ugyldig start pĂ¥ signaturen</translation>
+<translation id="1209206284964581585">Skjul for øyeblikket</translation>
<translation id="1219129156119358924">Systemsikkerhet</translation>
<translation id="1227224963052638717">Ukjent innstilling.</translation>
<translation id="1227633850867390598">Skjul verdien</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Ja</translation>
<translation id="1430915738399379752">Skriv ut</translation>
<translation id="1442912890475371290">Blokkerte forsøket <ph name="BEGIN_LINK" /> pĂ¥ Ă¥ besøke en side pĂ¥ <ph name="DOMAIN" /><ph name="END_LINK" /></translation>
+<translation id="1491663344921578213">Du kan ikke gĂ¥ til <ph name="SITE" /> akkurat nĂ¥, fordi nettstedet bruker sertifikatfesting. Nettverksfeil og -angrep er som regel kortvarige, sĂ¥ denne siden fungerer nok igjen senere. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Vis en lagret kopi av denne siden (dvs. en kopi du vet at er utdatert).</translation>
<translation id="1519264250979466059">Versjonsdato</translation>
<translation id="1549470594296187301">Denne funksjonen kan ikke brukes nĂ¥r JavaScript er slĂ¥tt av.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Nettverkskonfigurasjonen er ugyldig og kan ikke importeres.</translation>
<translation id="1644574205037202324">Logg</translation>
<translation id="1645368109819982629">Protokollen støttes ikke</translation>
-<translation id="1655462015569774233">{1,plural, =1{Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet utløp i gĂ¥r. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen mellom deg og nettstedet. Klokken pĂ¥ datamaskinen din er stilt til <ph name="CURRENT_DATE" />. Er det riktig? Hvis ikke bør du stille klokken pĂ¥ systemet og laste inn denne siden pĂ¥ nytt.}other{Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet utløp for # dager siden. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen mellom deg og nettstedet. Klokken pĂ¥ datamaskinen din er stilt til <ph name="CURRENT_DATE" />. Er det riktig? Hvis ikke bør du stille klokken pĂ¥ systemet og laste inn denne siden pĂ¥ nytt.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> bruker vanligvis kryptering for Ă¥ beskytte informasjonen din. Da Chrome prøvde Ă¥ koble til <ph name="SITE" /> denne gangen, sendte nettstedet tilbake uvanlig og feil legitimasjon. Dette kan skje hvis en angriper prøver Ă¥ utgi seg for Ă¥ være <ph name="SITE" />, eller hvis en Wi-Fi-pĂ¥loggingsskjerm har avbrutt tilkoblingen. Informasjonen din er likevel sikker fordi Chrome stoppet tilkoblingen før det ble utvekslet noen data.</translation>
<translation id="168841957122794586">Tjenersertifikatet inneholder en svak kryptografisk nøkkel.</translation>
<translation id="1701955595840307032">FĂ¥ foreslĂ¥tt innhold</translation>
-<translation id="1706954506755087368">{1,plural, =1{Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ser ut til Ă¥ være fra i morgen. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen mellom deg og nettstedet.}other{Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ser ut til Ă¥ være fra # dager frem i tid. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen mellom deg og nettstedet.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Prøv Ă¥ kontakte systemadministratoren.</translation>
<translation id="17513872634828108">Ă…pne faner</translation>
<translation id="1753706481035618306">Sidenummer</translation>
-<translation id="1761412452051366565">For Ă¥ fĂ¥ forslag om personlig tilpasset innhold fra Google, slĂ¥ pĂ¥ synkronisering.</translation>
-<translation id="1763864636252898013">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren er ikke klarert av enhetens operativsystem. Dette kan være forĂ¥rsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Prøv Ă¥ kjøre Windows Nettverksdiagnose<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Oppdater passordfrasen for synkronisering.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">De nylig besøkte bokmerkene dine vises her.</translation>
<translation id="1821930232296380041">Ugyldig forespørsel eller forespørselsparametere</translation>
<translation id="1838667051080421715">Du ser pĂ¥ kildekoden for en nettside.</translation>
<translation id="1871208020102129563">Mellomtjeneren er angitt til Ă¥ bruke statiske proxytjenere, ikke en nettadresse med .pac-skript.</translation>
<translation id="1883255238294161206">Skjul liste</translation>
<translation id="1898423065542865115">Filtrering</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> godtok ikke pĂ¥loggingssertifikatet ditt, eller pĂ¥loggingssertifikatet kan ha utløpt.</translation>
<translation id="194030505837763158">GĂ¥ til <ph name="LINK" /></translation>
<translation id="1962204205936693436"><ph name="DOMAIN" />-bokmerker</translation>
<translation id="1973335181906896915">Serialiseringsfeil</translation>
<translation id="1974060860693918893">Avansert</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{og 1 til}other{og # til}}</translation>
<translation id="2025186561304664664">Mellomtjeneren er innstilt pĂ¥ automatisk konfigurasjon.</translation>
<translation id="2030481566774242610">Mener du <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Du ser denne meldingen fordi foreldrene dine mĂ¥ godkjenne nye nettsteder den første gangen du Ă¥pner dem.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Sjekk proxy-tjeneren og brannmuren<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Postnummer</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 forslag}other{# forslag}}</translation>
<translation id="2065985942032347596">Godkjenning kreves</translation>
<translation id="2079545284768500474">Angre</translation>
<translation id="20817612488360358">Innstillinger for systemmellomtjener er stilt inn pĂ¥ Ă¥ brukes, men en uttrykkelig mellomtjenerkonfigurasjon er ogsĂ¥ angitt.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Rediger bokmerke</translation>
<translation id="2166049586286450108">Full administratortilgang</translation>
<translation id="2166378884831602661">Dette nettstedet tilbyr ikke sikre tilkoblinger</translation>
-<translation id="2171101176734966184">Du forsøkte Ă¥ gĂ¥ til <ph name="DOMAIN" />, men tjeneren presenterte et sertifikat som er signert med en usikker signaturalgoritme. Dette betyr at sikkerhetslegitimasjonen tjeneren har presentert kan være forfalsket. Tjeneren kan med andre ord være enn annen tjener enn du tror (det vil si at du kanskje kommuniserer med en angriper).</translation>
<translation id="2181821976797666341">Retningslinjer</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}other{# adresser}}</translation>
<translation id="2212735316055980242">Innstillingene ble ikke funnet</translation>
<translation id="2213606439339815911">Henter oppføringer …</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> er ikke tilgjengelig</translation>
<translation id="2230458221926704099">Løs tilkoblingsproblemene med <ph name="BEGIN_LINK" />diagnostikkappen<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Send nĂ¥</translation>
<translation id="225207911366869382">Denne verdien er foreldet for denne innstillingen.</translation>
<translation id="2262243747453050782">HTTP-feil</translation>
<translation id="2282872951544483773">Utilgjengelige eksperimenter</translation>
<translation id="2292556288342944218">Internett-tilgangen din er blokkert</translation>
<translation id="229702904922032456">Et rotsertifikat eller mellomliggende sertifikat er utløpt.</translation>
<translation id="230155334948463882">Nytt kort?</translation>
+<translation id="2305919008529760154">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet kan ha blitt utstedt pĂ¥ uredelig vis. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> krever brukernavn og passord.</translation>
+<translation id="2318774815570432836">Du kan ikke gĂ¥ til <ph name="SITE" /> akkurat nĂ¥, fordi nettstedet bruker HSTS. Nettverksfeil og -angrep er som regel kortvarige, sĂ¥ denne siden fungerer nok igjen senere. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Ignorerte ugyldig bokmerke ved indeks <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Andre bokmerker</translation>
<translation id="2359808026110333948">Fortsett</translation>
<translation id="2365563543831475020">Programstopprapporten fra <ph name="CRASH_TIME" /> ble ikke lastet opp</translation>
<translation id="2367567093518048410">NivĂ¥</translation>
+<translation id="2371153335857947666">{1,plural, =1{Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet utløp i gĂ¥r. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. Klokken pĂ¥ datamaskinen din er stilt til <ph name="CURRENT_DATE" />. Er det riktig? Hvis ikke bør du stille klokken pĂ¥ systemet og laste inn denne siden pĂ¥ nytt. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.}other{Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet utløp for # dager siden. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. Klokken pĂ¥ datamaskinen din er stilt til <ph name="CURRENT_DATE" />. Er det riktig? Hvis ikke bør du stille klokken pĂ¥ systemet og laste inn denne siden pĂ¥ nytt. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Det er ingen tilgjengelige alternativer for brukergrensesnitt</translation>
<translation id="2384307209577226199">Bedriftsstandard</translation>
-<translation id="238526402387145295">Du kan ikke gĂ¥ til <ph name="SITE" /> akkurat nĂ¥, fordi nettstedet <ph name="BEGIN_LINK" />bruker HSTS<ph name="END_LINK" />. Nettverksfeil og -angrep er som regel kortvarige, sĂ¥ denne siden fungerer nok igjen senere.</translation>
<translation id="2386255080630008482">Tjenerens sertifikat er tilbakekalt.</translation>
<translation id="2392959068659972793">Vis innstillinger uten verdi</translation>
<translation id="2396249848217231973">&amp;Angre slettingen</translation>
-<translation id="2413528052993050574">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Tjenerens sikkerhetssertifikat kan være trukket tilbake. Dette kan være forĂ¥rsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="2455981314101692989">Denne nettsiden har deaktivert automatisk utfylling for dette skjemaet.</translation>
+<translation id="2463739503403862330">Fyll ut</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Kjør Nettverksdiagnose<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ugyldig nettadresse for søk.</translation>
<translation id="2491120439723279231">Tjenerens sertifikat inneholder feil.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Send</translation>
<translation id="2674170444375937751">Er du sikker pĂ¥ at du vil slette disse sidene fra loggen?</translation>
<translation id="2677748264148917807">GĂ¥ ut</translation>
+<translation id="269990154133806163">Tjeneren presenterte et sertifikat som ikke er offentlig vist i henhold til retningslinjene for sertifikatĂ¥penhet. Dette er et krav for enkelte sertifikater, for Ă¥ sikre at de er pĂ¥litelige, og bidrar til Ă¥ beskytte mot angrep. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Verdien samsvarer ikke med formatet.</translation>
<translation id="2704951214193499422">Chromium kunne ikke bekrefte kortet ditt akkurat nĂ¥. Prøv igjen senere.</translation>
<translation id="2705137772291741111">Den lagrede (bufrede) kopien av dette nettstedet kunne ikke leses.</translation>
<translation id="2709516037105925701">Autofyll</translation>
+<translation id="2712118517637785082">Du prøvde Ă¥ gĂ¥ til <ph name="DOMAIN" />, men tjeneren presenterte et sertifikat som er trukket tilbake av utstederen. Dette innebærer at sikkerhetsinformasjonen tjeneren presenterte, ikke er klarert. Det kan hende at du kommuniserer med en angriper. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Be om tillatelse</translation>
<translation id="2721148159707890343">Forespørselen var vellykket</translation>
<translation id="2728127805433021124">Tjenerens sertifikat er signert med en usikker signaturalgoritme.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Adresse- og søkefelt</translation>
<translation id="2826760142808435982">Tilkoblingen er kryptert ved hjelp av <ph name="CIPHER" />, og bruker <ph name="KX" /> som mekanisme for nøkkelutveksling.</translation>
<translation id="2835170189407361413">Slett skjemaet</translation>
-<translation id="2837049386027881519">Tilkoblingen mĂ¥tte mĂ¥tte prøves pĂ¥ nytt ved hjelp av en eldre versjon av TLS- eller SSL-protokollen. Dette betyr vanligvis at tjeneren bruker veldig gammel programvare og kan ha andre sikkerhetsproblemer.</translation>
<translation id="284702764277384724">Tjenersertifikatet pĂ¥ <ph name="HOST_NAME" /> ser ut til Ă¥ være forfalsket.</translation>
<translation id="2889159643044928134">Ikke last inn pĂ¥ nytt</translation>
-<translation id="2896499918916051536">Dette programtillegget støttes ikke.</translation>
+<translation id="2900469785430194048">Google Chrome gikk tom for minne under forsøket pĂ¥ Ă¥ vise denne nettsiden.</translation>
<translation id="2909946352844186028">En nettverksendring ble oppdaget.</translation>
-<translation id="2915500479781995473">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Tjenerens sikkerhetssertifikat er utløpt. Dette kan være forĂ¥rsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din. Datamaskinens klokke er for øyeblikket satt til <ph name="CURRENT_TIME" />. Ser det riktig ut? Hvis det ikke gjør det, bør du korrigere systemets klokke og deretter laste inn denne siden pĂ¥ nytt.</translation>
<translation id="2922350208395188000">Tjenerens sertifikat kan ikke kontrolleres.</translation>
-<translation id="2941952326391522266">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Tjenerens sikkerhetssertifikat er fra <ph name="DOMAIN2" />. Dette kan være forĂ¥rsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="2948083400971632585">PĂ¥ innstillingssiden kan du deaktivere eventuelle mellomtjenere for tilkoblinger.</translation>
<translation id="2955913368246107853">Lukk søkefelt</translation>
<translation id="2958431318199492670">Nettverkskonfigurasjonen overholder ikke ONC-standarden. Deler av konfigurasjonen kan muligens ikke importeres.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Feil type enhetsinnstillinger</translation>
<translation id="3032412215588512954">Vil du laste inn dette nettstedet pĂ¥ nytt?</translation>
<translation id="3037605927509011580">Æsj!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{minst 1 element pĂ¥ synkroniserte enheter}=1{1 element (og flere pĂ¥ synkroniserte enheter)}other{# elementer (og flere pĂ¥ synkroniserte enheter)}}</translation>
<translation id="3041612393474885105">Sertifikatinformasjon</translation>
<translation id="3063697135517575841">Chrome kunne ikke bekrefte kortet ditt akkurat nĂ¥. Prøv igjen senere.</translation>
<translation id="3093245981617870298">Du er ikke tilkoblet Internett.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Nyeste</translation>
<translation id="3207960819495026254">Bokmerket</translation>
-<translation id="3225919329040284222">Tjeneren oppga et sertifikat som ikke samsvarte med innebygde forventninger. Disse forventningene benyttes for visse nettsteder med høy sikkerhet, og brukes for Ă¥ beskytte deg.</translation>
<translation id="3226128629678568754">Trykk pĂ¥ knappen for Ă¥ laste inn pĂ¥ nytt, for Ă¥ sende inn dataene som trengs for Ă¥ laste inn siden pĂ¥ nytt.</translation>
<translation id="3228969707346345236">Oversettelsen mislyktes fordi siden allerede er pĂ¥ <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Skriv inn verifiseringskoden for <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Legg til bokmerke for denne siden</translation>
<translation id="3270847123878663523">&amp;Angre omorganiseringen</translation>
<translation id="3286538390144397061">Start pĂ¥ nytt nĂ¥</translation>
+<translation id="3303855915957856445">Søket ga ingen treff</translation>
<translation id="3305707030755673451">Dataene dine er kryptert med passordfrasen din for synkronisering <ph name="TIME" />. Skriv den inn for Ă¥ starte synkroniseringen.</translation>
<translation id="333371639341676808">Hindre denne siden i Ă¥ opprette flere dialogbokser.</translation>
+<translation id="3338095232262050444">Sikker</translation>
<translation id="3340978935015468852">innstillinger</translation>
<translation id="3345135638360864351">Forespørselen om tilgang til dette nettstedet kunne ikke sendes til <ph name="NAME" />. Prøv igjen.</translation>
<translation id="3355823806454867987">Endre innstillinger for mellomtjener</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Hentingsintervall:</translation>
<translation id="3462200631372590220">Skjul detaljer</translation>
<translation id="3479539252931486093">Var dette uventet? <ph name="BEGIN_LINK" />Si fra til oss<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Ikke nĂ¥</translation>
<translation id="348000606199325318">Kræsj-ID <ph name="CRASH_LOCAL_ID" /> (Tjener-ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Vi kunne ikke nĂ¥ foreldrene dine akkurat nĂ¥. Prøv igjen.</translation>
<translation id="3527085408025491307">Mappe</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Bruk passord for:</translation>
<translation id="3549644494707163724">Kryptér alle synkroniserte data med din egen passordfrase for synkronisering</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> flere</translation>
+<translation id="3555561725129903880">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet tilhører <ph name="DOMAIN2" />. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Tilkoblingen din er ikke privat</translation>
<translation id="3583757800736429874">&amp;Flytt likevel</translation>
<translation id="3586931643579894722">Skjul detaljer</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Vis verdien</translation>
<translation id="3630155396527302611">Hvis programmet allerede har fĂ¥tt tillatelse til Ă¥ bruke nettverket, kan du prøve
Ă¥ fjerne det fra listen og sĂ¥ legge det til pĂ¥ nytt.</translation>
+<translation id="3638794133396384728">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet er utløpt. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. Klokken pĂ¥ datamaskinen din er stilt til <ph name="CURRENT_TIME" />. Er det riktig? Hvis ikke bør du stille klokken pĂ¥ systemet og laste inn denne siden pĂ¥ nytt. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Disse eksperimentelle funksjonene kan bli endret, satt pĂ¥ pause eller forsvinne nĂ¥r som helst. Vi gir absolutt ingen garantier om hva som kan skje hvis du slĂ¥r pĂ¥ et av disse eksperimentene – nettleseren kan til og med spontanantenne. Spøk til side: Nettleseren kan komme til Ă¥ slette alle dataene dine eller sikkerheten og personvernet kan bli kompromittert pĂ¥ uventede mĂ¥ter. Eventuelle eksperimenter du aktiverer bli aktivert for alle brukere av denne nettleseren. Vær forsiktig hvis du fortsetter.</translation>
<translation id="3650584904733503804">Valideringen var vellykket</translation>
<translation id="3655670868607891010">Hvis du ser denne meldingen ofte, kan du prøve disse <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Versjon</translation>
+<translation id="3678029195006412963">Forespørselen kunne ikke undertegnes</translation>
<translation id="3681007416295224113">Sertifikatinformasjon</translation>
<translation id="3693415264595406141">Passord:</translation>
+<translation id="3696411085566228381">ingen</translation>
<translation id="3700528541715530410">Beklager. Det ser ut til at du ikke har tillatelse til Ă¥ Ă¥pne denne siden.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Laster inn...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">SlĂ¥ pĂ¥ mobildata eller Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Sjekk proxy-tjener-, brannmur- og DNS-konfigurasjonen<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">En link du kopierte</translation>
-<translation id="3744899669254331632">Du kan ikke gĂ¥ til <ph name="SITE" /> akkurat nĂ¥, fordi nettstedet sendte kryptert legitimasjon som Chromium ikke kan behandle. Nettverksfeil og -angrep er vanligvis forbigĂ¥ende, sĂ¥ siden kommer sikkert til Ă¥ virke senere.</translation>
<translation id="375403751935624634">Oversettelsen mislyktes pĂ¥ grunn av en tjenerfeil.</translation>
<translation id="3759461132968374835">Du har ingen nylig rapportert programstopp. Programstopp som inntraff nĂ¥r rapportering om programstopp var deaktivert, blir ikke vist her.</translation>
<translation id="3788090790273268753">Sertifikatet for dette nettstedet utløper i 2016, og sertifikatkjeden inneholder et sertifikat som er signert med SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Motstridende enhetsidentifikator</translation>
<translation id="3885155851504623709">Kommune</translation>
<translation id="3901925938762663762">Kortet er utløpt</translation>
+<translation id="3910267023907260648">Du prøvde Ă¥ gĂ¥ til <ph name="DOMAIN" />, men tjeneren presenterte et sertifikat som er signert med en usikker signaturalgoritme. Dette betyr at sikkerhetslegitimasjonen tjeneren har presentert, kan være forfalsket. Tjeneren kan med andre ord være en annen tjener enn du tror (og du kommuniserer kanskje med en angriper). <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ser ut til Ă¥ være fra i morgen. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.}other{Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ser ut til Ă¥ være fra # dager frem i tid. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Kan ikke laste inn PDF-dokument</translation>
<translation id="3963721102035795474">Lesermodus</translation>
+<translation id="397105322502079400">Beregner …</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> er blokkert</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 Like ved-nettside}other{# Like ved-nettsider}}</translation>
<translation id="4021036232240155012">DNS er nettverkstjenesten som oversetter navnene pĂ¥ nettsteder til Internett-adressene deres.</translation>
<translation id="4030383055268325496">&amp;Angre tilleggingen</translation>
-<translation id="4032534284272647190">Tilgang til <ph name="URL" /> ble avvist.</translation>
<translation id="404928562651467259">ADVARSEL</translation>
<translation id="4058922952496707368">Nøkkel – «<ph name="SUBKEY" />»: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Klienten og tjeneren støtter ingen felles SSL-protokollversjon eller -chifferserie.</translation>
<translation id="4079302484614802869">Konfigurasjonen av proxytjeneren er angitt til Ă¥ bruke en nettadresse med .pac-skript, ikke statiske proxytjenere.</translation>
<translation id="4103249731201008433">Enhetens serienummer er ugyldig</translation>
<translation id="4103763322291513355">GĂ¥ til &lt;strong&gt;chrome://policy&lt;/strong&gt; for Ă¥ se listen over sperrede nettadresser og andre innstillinger aktivert av systemadministratoren din.</translation>
+<translation id="4110615724604346410">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet inneholder feil. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Omfanget for innstillingen støttes ikke.</translation>
+<translation id="4118212371799607889">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ikke er regnet som pĂ¥litelig av Chromium. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 til}other{# til}}</translation>
<translation id="4130226655945681476">Sjekk nettverkskablene, modemet og ruteren</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Vil du at Chromium skal lagre dette kortet?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Deaktivert</translation>
<translation id="4196861286325780578">&amp;Flytt likevel</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Sjekk brannmur- og antiviruskonfigurasjonen<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{ingen}=1{1 app ($1)}=2{2 apper ($1, $2)}other{# apper ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Kræsj</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Prøv Ă¥ kjøre Nettverksdiagnose<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Nei</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Uten brukernavn)</translation>
<translation id="4300246636397505754">Overordnede forslag</translation>
<translation id="4304224509867189079">Logg pĂ¥</translation>
+<translation id="432290197980158659">Tjeneren presenterte et sertifikat som ikke samsvarer med innebygde forventninger. Disse forventningene benyttes for visse nettsteder med høy sikkerhet og brukes for Ă¥ beskytte deg. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Artikkelen ble ikke funnet</translation>
+<translation id="4331708818696583467">Ikke sikker</translation>
<translation id="4372948949327679948">Forventet <ph name="VALUE_TYPE" />-verdi.</translation>
-<translation id="4377125064752653719">Du forsøkte Ă¥ gĂ¥ til <ph name="DOMAIN" />, men sertifikatet tjeneren presenterte har blitt trukket tilbake av utstederen. Dette innebærer at sikkerhetsinformasjonen tjeneren presenterte ikke er klarert. Det kan hende at du kommuniserer med en angriper.</translation>
<translation id="4381091992796011497">Brukernavn:</translation>
<translation id="4394049700291259645">SlĂ¥ av</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> til <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">søkeresultater</translation>
-<translation id="4424024547088906515">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren er ikke klarert av Chrome. Dette kan være forĂ¥rsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
+<translation id="4432688616882109544">Enten godtok ikke <ph name="HOST_NAME" /> pĂ¥loggingssertifikatet ditt, eller sĂ¥ ble det ikke oppgitt.</translation>
<translation id="443673843213245140">Bruk av mellomtjener er deaktivert, men det er angitt en uttrykkelig mellomtjenerkonfigurasjon.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Du ser denne meldingen fordi Google SafeSites er slĂ¥tt pĂ¥.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Detaljer</translation>
<translation id="4558551763791394412">Prøv Ă¥ slĂ¥ av utvidelsene dine.</translation>
<translation id="4587425331216688090">Vil du fjerne adressen fra Chrome?</translation>
+<translation id="4589078953350245614">Du prøvde Ă¥ gĂ¥ til <ph name="DOMAIN" />, men tjeneren presenterte et ugyldig sertifikat. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Tilkoblingen til <ph name="DOMAIN" /> er kryptert med en moderne chifferserie.</translation>
<translation id="4594403342090139922">&amp;Angre slettingen</translation>
+<translation id="4627442949885028695">Fortsett pĂ¥ en annen enhet</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Dette er en utvidelsesside.</translation>
-<translation id="467662567472608290">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren inneholder feil. Dette kan være forĂ¥rsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> ble blokkert</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Tilkoblingen ble avbrutt</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Kjør Windows Nettverksdiagnose<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Plattform</translation>
<translation id="4744603770635761495">Kjørbar sti</translation>
<translation id="4756388243121344051">&amp;Logg</translation>
+<translation id="4759238208242260848">Nedlastinger</translation>
<translation id="4764776831041365478">Det kan hende at nettsiden pĂ¥ <ph name="URL" /> er midlertidig nede eller flyttet permanent til en ny nettadresse.</translation>
<translation id="4771973620359291008">Det har oppstĂ¥tt en ukjent feil.</translation>
<translation id="4782449893814226250">Du spurte foreldrene dine om det er greit Ă¥ besøke denne siden.</translation>
<translation id="4800132727771399293">Kontrollér utløpsdatoen og CVC-koden, og prøv igjen.</translation>
-<translation id="4807049035289105102">Du kan ikke gĂ¥ til <ph name="SITE" /> akkurat nĂ¥, fordi nettstedet sendte kryptert legitimasjon som Google Chrome ikke kan behandle. Nettverksfeil og -angrep er vanligvis forbigĂ¥ende, sĂ¥ siden kommer sikkert til Ă¥ virke senere.</translation>
<translation id="4813512666221746211">Nettverksfeil</translation>
<translation id="4816492930507672669">Tilpass til siden</translation>
<translation id="4850886885716139402">Visning</translation>
<translation id="4880827082731008257">Søk i loggen</translation>
+<translation id="4884656795097055129">Flere artikler vises nĂ¥r tiden er inne.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{og 1 nettside til}other{og # nettsider til}}</translation>
<translation id="4923417429809017348">Denne siden er oversatt til <ph name="LANGUAGE_LANGUAGE" /> fra et ukjent sprĂ¥k</translation>
<translation id="4926049483395192435">MĂ¥ angis.</translation>
<translation id="4930497775425430760">Du ser denne meldingen fordi en av foreldrene dine mĂ¥ godkjenne nye nettsteder den første gangen du Ă¥pner dem.</translation>
<translation id="495170559598752135">Handlinger</translation>
<translation id="4958444002117714549">Utvid liste</translation>
+<translation id="4962322354953122629">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom skkerhetssertifikatet ikke er regnet som pĂ¥litelig av Chrome. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Vil du oversette fra <ph name="ORIGINAL_LANGUAGE" /> til <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Dette programtillegget støttes ikke</translation>
<translation id="5002932099480077015">Hvis du slĂ¥r pĂ¥ dette alternativet, lagrer Chrome en kopi av kortet ditt pĂ¥ denne enheten, slik at det blir raskere Ă¥ fylle ut skjemaer i fremtiden.</translation>
<translation id="5019198164206649151">Ugyldig funksjonalitet for sikkerhetskopiering</translation>
<translation id="5023310440958281426">Kontrollér retningslinjene til administratoren din</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Om Google Oversett</translation>
<translation id="5040262127954254034">Personvern</translation>
<translation id="5045550434625856497">Feil passord</translation>
+<translation id="5056549851600133418">Artikler for deg</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Sjekk proxy-tjeneradressen<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Sertifikatet til tjeneren er ikke gyldig for øyeblikket.</translation>
<translation id="5089810972385038852">Fylke / delstat</translation>
-<translation id="5094747076828555589">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren er ikke klarert av Chromium. Dette kan være forĂ¥rsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="5095208057601539847">Provins</translation>
<translation id="5115563688576182185">(64-bit)</translation>
-<translation id="5122371513570456792">Funnet <ph name="NUMBER_OF_RESULTS" /><ph name="SEARCH_RESULTS" /> for «<ph name="SEARCH_STRING" />».</translation>
<translation id="5141240743006678641">Kryptér synkroniserte passord med Google-legitimasjonen din</translation>
<translation id="5145883236150621069">Feilkode i responsen for enhetsinnstillinger</translation>
<translation id="5171045022955879922">Søk, eller skriv inn en nettadresse</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Bokmerkerad</translation>
<translation id="5199729219167945352">Eksperimenter</translation>
<translation id="5251803541071282808">Nettsky</translation>
+<translation id="5277279256032773186">Bruker du Chrome pĂ¥ jobben? Bedrifter kan administrere Chrome-innstillingene for de ansatte. Finn ut mer</translation>
<translation id="5299298092464848405">Feil under analysen av enhetsinnstillingene</translation>
<translation id="5300589172476337783">Vis</translation>
<translation id="5308689395849655368">Rapportering av programstopp er deaktivert.</translation>
<translation id="5317780077021120954">Lagre</translation>
<translation id="5327248766486351172">Navn</translation>
+<translation id="5359637492792381994">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ikke er gyldig for øyeblikket. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Kunne ikke lagre angivelsen for enhetsinnstillinger</translation>
-<translation id="540969355065856584">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren er ikke gyldig for øyeblikket. Dette kan være forĂ¥rsaket av en feilkonfigurasjon eller en angriper som lytter pĂ¥ tilkoblingen din.</translation>
<translation id="5421136146218899937">Slett nettleserdata</translation>
<translation id="5430298929874300616">Fjern bokmerke</translation>
<translation id="5431657950005405462">Filen ble ikke funnet</translation>
<translation id="5435775191620395718">Viser loggen fra denne enheten. <ph name="BEGIN_LINK" />Finn ut mer<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Forslag om personlig tilpasset innhold er for øyeblikket slĂ¥tt av, fordi de synkroniserte dataene dine er beskyttet med en egendefinert passordfrase.</translation>
<translation id="5439770059721715174">Skjemavalideringsfeil i «<ph name="ERROR_PATH" />»: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Denne siden pĂ¥ <ph name="HOST_NAME" /> ble ikke funnet</translation>
<translation id="5455374756549232013">Feil tidsstempel for enhetsinnstillinger</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Vil du forlate dette nettstedet?</translation>
<translation id="5629630648637658800">Kunne ikke laste in angivelsen for enhetsinnstillinger</translation>
<translation id="5631439013527180824">Ugyldig token for enhetsadministrering</translation>
-<translation id="5650551054760837876">Ingen søkeresultater funnet.</translation>
<translation id="5677928146339483299">Blokkert</translation>
<translation id="5710435578057952990">Identiteten til dette nettstedet er ikke verifisert.</translation>
<translation id="5720705177508910913">Gjeldende bruker</translation>
+<translation id="572328651809341494">Nylige faner</translation>
<translation id="5784606427469807560">Det oppsto et problem under forsøket pĂ¥ Ă¥ bekrefte kortet ditt. KontrollĂ©r Internett-tilkoblingen din, og prøv igjen.</translation>
<translation id="5785756445106461925">Denne siden inneholder i tillegg andre ressurser som ikke er sikre. Disse ressursene er synlige for andre mens de sendes frem og tilbake, og eventuelle angripere kan modifisere dem for Ă¥ endre pĂ¥ utseendet til siden.</translation>
+<translation id="5786044859038896871">Vil du fylle ut kortinformasjonen?</translation>
+<translation id="5803412860119678065">Vil du fylle ut informasjonen knyttet til <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Tilkoblingen til <ph name="DOMAIN" /> er kryptert med en foreldet chifferserie.</translation>
<translation id="5813119285467412249">&amp;Legg til likevel</translation>
+<translation id="5814352347845180253">Det kan hende du mister tilgang til premium-innhold fra <ph name="SITE" /> og andre nettsteder.</translation>
+<translation id="5843436854350372569">Du prøvde Ă¥ gĂ¥ til <ph name="DOMAIN" />, men tjeneren presenterte et sertifikat som inneholder en usikker nøkkel. En angriper kan ha brutt sikkerheten i den private nøkkelen, og tjeneren er kanskje ikke den tjeneren du forventet (det kan hende at du kommuniserer med en angriper). <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Du ser denne meldingen fordi administratoren din har blokkert dette nettstedet.</translation>
<translation id="5857090052475505287">Ny mappe</translation>
<translation id="5869405914158311789">Dette nettstedet er ikke tilgjengelig</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Overordnede forslag</translation>
<translation id="59107663811261420">Denne korttypen støttes ikke av Google Payments for denne selgeren. Velg et annet kort.</translation>
<translation id="59174027418879706">Aktivert</translation>
+<translation id="5926846154125914413">Det kan hende du mister tilgang til premium-innhold fra enkelte nettsteder.</translation>
<translation id="5966707198760109579">Uke</translation>
<translation id="5967867314010545767">Fjern fra loggen</translation>
<translation id="5975083100439434680">Zoom ut</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Automatisk</translation>
<translation id="6042308850641462728">Mer</translation>
<translation id="6060685159320643512">Vær forsiktig. Disse eksperimentene kan bite</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{ingen}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Sjekk alle kabler, og start rutere, modemer eller andre nettverksenheter
du bruker, pĂ¥ nytt.</translation>
<translation id="614940544461990577">Prøv dette:</translation>
<translation id="6150607114729249911">Beklager, du mĂ¥ spørre foreldrene dine om det er greit at du besøker denne siden.</translation>
<translation id="6151417162996330722">Tjenersertifikatet har en gyldighetsperiode som er for lang.</translation>
-<translation id="6154808779448689242">Det returnerte tokenet for enhetsinnstillinger samsvarer ikke med det gjeldende tokenet</translation>
<translation id="6165508094623778733">Les mer</translation>
<translation id="6203231073485539293">Kontrollér Internett-tilkoblingen</translation>
<translation id="6218753634732582820">Vil du fjerne adressen fra Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Prøv Ă¥ slĂ¥ av nettverksforutsigelse</translation>
<translation id="6337534724793800597">Filtrér retningslinjer etter navn</translation>
<translation id="6342069812937806050">Akkurat nĂ¥</translation>
+<translation id="6345221851280129312">ukjent størrelse</translation>
<translation id="6355080345576803305">Offentlig økt-overstyring</translation>
<translation id="6358450015545214790">Hva innebærer dette?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 annet forslag}other{# andre forslag}}</translation>
<translation id="6387478394221739770">Interessert i nye kule Chrome-funksjoner? Prøv betakanalen vĂ¥r pĂ¥ chrome.com/beta</translation>
-<translation id="641480858134062906">Fikk ikke lastet inn <ph name="URL" /></translation>
+<translation id="6389758589412724634">Chromium gikk tom for minne under forsøket pĂ¥ Ă¥ vise denne nettsiden.</translation>
+<translation id="6416403317709441254">Du kan ikke gĂ¥ til <ph name="SITE" /> akkurat nĂ¥ fordi nettstedet sendte kryptert legitimasjon som Chromium ikke kan behandle. Nettverksfeil og -angrep er som regel kortvarige, sĂ¥ denne siden fungerer nok igjen senere. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Kan ikke kontrollere hvorvidt sertifikatet har blitt tilbakekalt.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> avviste tilkoblingsforsøket.</translation>
<translation id="6445051938772793705">Land</translation>
<translation id="6451458296329894277">Bekreft ny innsending av skjema</translation>
<translation id="6458467102616083041">Ignorert fordi standardsøk er deaktivert i henhold til retningslinje.</translation>
+<translation id="6462969404041126431">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet kan ha blitt trukket tilbake. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Enhetsinnstillinger</translation>
<translation id="6489534406876378309">Start opplastingen av krasj</translation>
<translation id="6529602333819889595">&amp;Slett likevel</translation>
+<translation id="6534179046333460208">Fysisk nett-forslag</translation>
<translation id="6550675742724504774">Alternativer</translation>
+<translation id="6593753688552673085">mindre enn <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Krypteringsalternativer</translation>
<translation id="662080504995468778">Bli her</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Søk</translation>
-<translation id="6634865548447745291">Du kan ikke gĂ¥ til <ph name="SITE" /> akkurat nĂ¥ fordi <ph name="BEGIN_LINK" />dette sertifikatet er tilbakekalt<ph name="END_LINK" />. Nettverksfeil og -angrep er som regel kortvarige, sĂ¥ denne siden fungerer nok igjen senere.</translation>
<translation id="6644283850729428850">Denne retningslinjen er foreldet.</translation>
+<translation id="6652240803263749613">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ikke er regnet som pĂ¥litelig av operativsystemet pĂ¥ datamaskinen din. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Mapperedigering</translation>
<translation id="6660210980321319655">Automatisk rapportert <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Vil du fjerne forslaget fra Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Forrige</translation>
<translation id="6710594484020273272">&lt;Skriv inn en søketerm&gt;</translation>
<translation id="6711464428925977395">Det er noe galt med proxy-tjeneren, eller adressen er feil.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{ingen}=1{1 element}other{# elementer}}</translation>
<translation id="674375294223700098">Ukjent feil med tjenersertifikat.</translation>
<translation id="6753269504797312559">Retningslinjeverdi</translation>
<translation id="6757797048963528358">Enheten din gikk inn i hvilemodus.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">InnstillingsnivĂ¥et støttes ikke.</translation>
<translation id="6895330447102777224">Kortet ditt er bekreftet</translation>
<translation id="6897140037006041989">Brukeragent</translation>
-<translation id="6903907808598579934">SlĂ¥ pĂ¥ synkronisering</translation>
<translation id="6915804003454593391">Bruker:</translation>
<translation id="6957887021205513506">Tjenersertifikatet ser ut til Ă¥ være forfalsket.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">OmrĂ¥de</translation>
<translation id="6973656660372572881">BĂ¥de statiske proxytjenere og en .pac-skriptnettadresse er angitt.</translation>
<translation id="6989763994942163495">Vis avanserte innstillinger</translation>
+<translation id="7000990526846637657">Fant ingen loggoppføringer</translation>
+<translation id="7009986207543992532">Du prøvde Ă¥ gĂ¥ til <ph name="DOMAIN" />, men tjeneren presenterte et sertifikat hvor gyldighetsperioden er oppgitt som for lang til Ă¥ være pĂ¥litelig. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Google-kontoen din kan ha andre typer nettlesingslogger pĂ¥ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Passord</translation>
-<translation id="7050187094878475250">Du prøvde Ă¥ nĂ¥ <ph name="DOMAIN" />. Tjeneren presenterte et sertifikat som har en gyldighetsperiode som er for lang til Ă¥ være pĂ¥litelig.</translation>
<translation id="7087282848513945231">Fylke</translation>
<translation id="7088615885725309056">Eldre</translation>
<translation id="7090678807593890770">Søk pĂ¥ Google etter <ph name="LINK" /></translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Du ser denne meldingen fordi administratoren din mĂ¥ godkjenne nye nettsteder den første gangen du Ă¥pner dem.</translation>
<translation id="724975217298816891">Skriv inn utløpsdatoen og verifiseringskoden for <ph name="CREDIT_CARD" /> for Ă¥ oppdatere kortinformasjonen din. NĂ¥r du bekrefter, deles denne informasjonen med dette nettstedet.</translation>
<translation id="725866823122871198">En privat forbindelse til <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> kan ikke opprettes fordi datoen og klokkeslettet (<ph name="DATE_AND_TIME" />) pĂ¥ datamaskinen er feil.</translation>
-<translation id="7265986070661382626">Du kan ikke gĂ¥ til <ph name="SITE" /> akkurat nĂ¥, fordi nettstedet <ph name="BEGIN_LINK" />bruker sertifikatfesting<ph name="END_LINK" />. Nettverksfeil og -angrep er som regel kortvarige, sĂ¥ denne siden fungerer nok igjen senere.</translation>
<translation id="7269802741830436641">Denne nettsiden har en omdirigeringsloop</translation>
<translation id="7275334191706090484">Administrerte bokmerker</translation>
<translation id="7298195798382681320">Anbefalt</translation>
-<translation id="7301833672208172928">SlĂ¥ pĂ¥ synkronisering av loggen</translation>
+<translation id="7309308571273880165">Programstopprapport opprettet <ph name="CRASH_TIME" /> (opplasting er forespurt av brukeren, men den har ikke blitt utført ennĂ¥)</translation>
<translation id="7334320624316649418">&amp;Omorganiser likevel</translation>
<translation id="733923710415886693">Tjenerens sertifikat er ikke vist i henhold til regelen for sertifikatĂ¥penhet.</translation>
+<translation id="7351800657706554155">Du kan ikke gĂ¥ til <ph name="SITE" /> akkurat nĂ¥ fordi dette sertifikatet er trukket tilbake. Nettverksfeil og nettangrep er som regel kortvarige, sĂ¥ denne siden fungerer nok igjen senere. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Kommandolinje </translation>
<translation id="7372973238305370288">søkeresultat</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> – <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="7469372306589899959">Bekrefter kortet</translation>
<translation id="7481312909269577407">Frem</translation>
<translation id="7485870689360869515">Ingen data ble funnet.</translation>
+<translation id="7508255263130623398">Den returnerte enhets-ID-en for regelen er tom eller samsvarer ikke med den faktiske enhets-ID-en</translation>
<translation id="7514365320538308">Last ned</translation>
<translation id="7518003948725431193">Finner ingen nettside for denne nettadressen: <ph name="URL" /></translation>
<translation id="7537536606612762813">Obligatorisk</translation>
<translation id="7542995811387359312">Automatisk utfylling av kredittkort er deaktivert fordi dette skjemaet ikke bruker en sikker tilkobling.</translation>
<translation id="7549584377607005141">Denne nettsiden krever data som du har skrevet inn tidligere for Ă¥ vises korrekt. Du kan sende inn dataene pĂ¥ nytt, men hvis du gjør det, gjentas eventuelle handlinger denne siden utførte.</translation>
<translation id="7554791636758816595">Ny fane</translation>
-<translation id="7567204685887185387">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Tjenerens sikkerhetssertifikat kan ha blitt utstedt pĂ¥ uredelig vis. Dette kan være forĂ¥rsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="7568593326407688803">Denne siden er pĂ¥<ph name="ORIGINAL_LANGUAGE" />Vil du ha den oversatt?</translation>
<translation id="7569952961197462199">Vil du fjerne kredittkortet fra Chrome?</translation>
<translation id="7578104083680115302">NĂ¥r du lagrer kort med Google, kan du bruke dem til Ă¥ betale raskt pĂ¥ nettsteder og i apper – uansett hvilken enhet du bruker.</translation>
+<translation id="7588950540487816470">Fysisk nett</translation>
<translation id="7592362899630581445">Tjenerens sertifikat bryter navnereglene.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> kan for øyeblikket ikke behandle denne forespørselen.</translation>
<translation id="7600965453749440009">Oversett aldri <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="7637571805876720304">Vil du fjerne kredittkortet fra Chromium?</translation>
<translation id="765676359832457558">Skjul avanserte innstillinger</translation>
<translation id="7658239707568436148">Avbryt</translation>
+<translation id="7667346355482952095">Det returnerte regeltokenet er tomt eller samsvarer ikke med det nĂ¥værende tokenet</translation>
<translation id="7668654391829183341">Ukjent enhet</translation>
<translation id="7674629440242451245">Interessert i nye kule Chrome-funksjoner? Prøv utviklerkanalen vĂ¥r pĂ¥ chrome.com/dev</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Fortsett til <ph name="SITE" /> (usikker side)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="780301667611848630">Nei takk</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7813600968533626083">Vil du fjerne skjemaforslaget fra Chrome?</translation>
+<translation id="7815407501681723534">Fant <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for «<ph name="SEARCH_STRING" />»</translation>
<translation id="785549533363645510">Du er imidlertid ikke usynlig. Inkognitomodus skjuler ikke surfingen din for arbeidsgiveren din, Internett-leverandøren eller nettstedene du besøker.</translation>
<translation id="7887683347370398519">Kontrollér CVC-koden din, og prøv igjen.</translation>
<translation id="7894616681410591072">Beklager, du mĂ¥ ha tillatelse fra <ph name="NAME" /> for Ă¥ fĂ¥ tilgang til denne siden.</translation>
-<translation id="790025292736025802">Finner ikke <ph name="URL" /></translation>
<translation id="7912024687060120840">I mappen:</translation>
<translation id="7920092496846849526">Du spurte foreldrene dine om det er greit Ă¥ besøke denne siden.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="7995512525968007366">Ikke spesifisert</translation>
<translation id="8012647001091218357">Vi kunne ikke nĂ¥ foreldrene dine akkurat nĂ¥. Prøv igjen.</translation>
<translation id="8034522405403831421">Denne siden er pĂ¥ <ph name="SOURCE_LANGUAGE" />. Vil du oversette den til <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Fant ingen loggoppføringer.</translation>
<translation id="8088680233425245692">Kunne ikke Ă¥pne artikkelen.</translation>
+<translation id="8089520772729574115">under 1 MB</translation>
<translation id="8091372947890762290">Aktivering venter pĂ¥ tjeneren</translation>
+<translation id="8129262335948759431">ukjent antall</translation>
<translation id="8131740175452115882">Bekreft</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" />-tjenerens <ph name="BEGIN_ABBR" />DNS-adresse<ph name="END_ABBR" /> ble ikke funnet.</translation>
<translation id="8149426793427495338">Datamaskinen din gikk inn i hvilemodus.</translation>
@@ -604,6 +640,7 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="8201077131113104583">Ugyldig oppdaterings-URL for utvidelse med ID «<ph name="EXTENSION_ID" />».</translation>
<translation id="8218327578424803826">Tilordnet posisjon:</translation>
<translation id="8225771182978767009">Personen som konfigurerte denne datamaskinen, har valgt Ă¥ blokkere dette nettstedet.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Siden du ser etter, brukte informasjon som du anga. Hvis du gĂ¥r tilbake til denne siden, kan det føre til at handlinger som er utført, blir gjentatt. Vil du fortsette?</translation>
<translation id="8249320324621329438">Sist hentet:</translation>
<translation id="8261506727792406068">Slett</translation>
@@ -616,12 +653,17 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="8349305172487531364">Bokmerkerad</translation>
<translation id="8363502534493474904">SlĂ¥ av flymodus</translation>
<translation id="8364627913115013041">Ikke angitt.</translation>
+<translation id="8380941800586852976">Farlig</translation>
<translation id="8412145213513410671">Kræsj (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Du mĂ¥ angi den samme passordfrasen to ganger.</translation>
<translation id="8428213095426709021">Innstillinger</translation>
+<translation id="8433057134996913067">Dette logger deg av de fleste nettsteder.</translation>
<translation id="8437238597147034694">&amp;Angre flyttingen</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kredittkort}other{# kredittkort}}</translation>
+<translation id="8483780878231876732">For Ă¥ bruke kredittkort du har lagret i Google-kontoen din, logg pĂ¥ Chrome</translation>
<translation id="8488350697529856933">Gjelder for</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> brukte for lang tid pĂ¥ Ă¥ svare.</translation>
+<translation id="852346902619691059">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />, ettersom sikkerhetssertifikatet ikke er regnet som pĂ¥litelig av operativsystemet pĂ¥ enheten din. Dette kan skyldes en feilkonfigurasjon eller at en angriper avskjærer tilkoblingen din. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Denne korttypen støttes ikke av Google Payments. Velg et annet kort.</translation>
<translation id="8550022383519221471">Synkroniseringstjeneste er ikke tilgjengelig for ditt domene.</translation>
<translation id="8553075262323480129">Oversettelsen mislyktes fordi sidens sprĂ¥k ikke kunne fastslĂ¥s.</translation>
@@ -633,15 +675,12 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="8647750283161643317">Tilbakestill alle til standard</translation>
<translation id="8680787084697685621">Kontoens pĂ¥loggingsdetaljer er utdaterte.</translation>
<translation id="8703575177326907206">Tilkoblingen til <ph name="DOMAIN" /> er ikke kryptert.</translation>
-<translation id="8713130696108419660">Feil innledende signatur</translation>
<translation id="8725066075913043281">Prøv igjen</translation>
<translation id="8728672262656704056">Du er nĂ¥ i inkognitomodus</translation>
<translation id="8730621377337864115">Ferdig</translation>
<translation id="8738058698779197622">Klokken din mĂ¥ være riktig stilt for at du skal kunne opprette en sikker forbindelse. Sertifikatene som nettsteder bruker til Ă¥ identifisere seg med, er nemlig bare gyldige i en viss tid. Siden enhetens klokke er feil, kan ikke Chromium kontrollere disse sertifikatene.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS-adressen&lt;/abbr&gt; til <ph name="HOST_NAME" /> ble ikke funnet. Problemet diagnostiseres.</translation>
-<translation id="8741995161408053644">Google-kontoen din kan ha andre typer nettlesingslogger pĂ¥ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Slett likevel</translation>
-<translation id="8790687370365610530">For Ă¥ fĂ¥ personlig tilpasset innhold fra Google, slĂ¥ pĂ¥ synkronisering av loggen.</translation>
<translation id="8798099450830957504">Standard</translation>
<translation id="8804164990146287819">Personvernregler</translation>
<translation id="8820817407110198400">Bokmerker</translation>
@@ -663,15 +702,13 @@ Forresten: Inkognitomodus (<ph name="SHORTCUT_KEY" />) kan være kjekt neste gan
<translation id="8971063699422889582">Tjenerens sertifikat er utløpt.</translation>
<translation id="8987927404178983737">MĂ¥ned</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Tjeneren har presentert et sertifikat som ikke er offentlig vist i henhold til regelen om sertifikatĂ¥penhet. Dette er et krav for enkelte sertifikater for Ă¥ sikre at de er pĂ¥litelige, og bidrar til Ă¥ beskytte mot angrep.</translation>
<translation id="9001074447101275817">Proxy-tjeneren <ph name="DOMAIN" /> krever brukernavn og passord.</translation>
<translation id="901974403500617787">Rapporteringer som gjelder for hele systemet kan bare angis av eieren: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Denne siden har blitt oversatt til <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Bruk en prediksjonstjeneste for Ă¥ laste inn sider raskere</translation>
<translation id="9039213469156557790">Denne siden inneholder i tillegg andre ressurser som ikke er sikre. Disse ressursene er synlige for andre mens de sendes frem og tilbake, og eventuelle angripere kan modifisere dem for Ă¥ endre pĂ¥ atferden til siden.</translation>
-<translation id="9049981332609050619">Du forsøkte Ă¥ nĂ¥ <ph name="DOMAIN" />, men tjeneren oppga et ugyldig sertifikat.</translation>
<translation id="9050666287014529139">Passordfrase</translation>
-<translation id="9065203028668620118">Rediger</translation>
+<translation id="9065203028668620118">Endre</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" />-siden fungerer ikke</translation>
<translation id="9103872766612412690"><ph name="SITE" /> bruker vanligvis kryptering for Ă¥ beskytte informasjonen din. Da Chromium prøvde Ă¥ koble til <ph name="SITE" /> denne gangen, sendte nettstedet tilbake uvanlig og feil legitimasjon. Dette kan skje hvis en angriper prøver Ă¥ utgi seg for Ă¥ være <ph name="SITE" />, eller hvis en Wi-Fi-pĂ¥loggingsskjerm har avbrutt tilkoblingen. Informasjonen din er likevel sikker fordi Chromium stoppet tilkoblingen før det ble utvekslet noen data.</translation>
<translation id="9137013805542155359">Vis original</translation>
diff --git a/chromium/components/strings/components_strings_pl.xtb b/chromium/components/strings/components_strings_pl.xtb
index faef686fae0..44349c031b0 100644
--- a/chromium/components/strings/components_strings_pl.xtb
+++ b/chromium/components/strings/components_strings_pl.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pl">
+<translation id="1008557486741366299">Nie teraz</translation>
<translation id="1015730422737071372">Podaj dodatkowe informacje</translation>
<translation id="1032854598605920125">ObrĂ³Ä‡ w prawo</translation>
<translation id="1038842779957582377">nieznana nazwa</translation>
+<translation id="1053591932240354961">Nie możesz teraz wejść na <ph name="SITE" />, bo ta witryna wysÅ‚aÅ‚a zaszyfrowane dane logowania, ktĂ³rych Google Chrome nie może przetworzyć. BÅ‚Ä™dy sieci i ataki sÄ… zazwyczaj przejÅ›ciowe, wiÄ™c prawdopodobnie pĂ³Åºniej strona bÄ™dzie dziaÅ‚ać. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Cofnij dodanie</translation>
<translation id="10614374240317010">Nigdy nie zapisane</translation>
-<translation id="1064422015032085147">Serwer hostujący tę stronę może być przeciążony lub w trakcie konserwacji.
- Żądania do tego adresu URL zostały tymczasowo zablokowane, by uniknąć
- nadmiernego ruchu i nie pogarszać dodatkowo sytuacji.</translation>
<translation id="106701514854093668">Zakładki na komputerze</translation>
<translation id="1080116354587839789">Dopasuj do szerokości</translation>
+<translation id="1103124106085518534">Na razie to wszystko</translation>
<translation id="1103523840287552314">Zawsze tłumacz z języka: <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Po zaznaczeniu tej opcji Chrome będzie zapisywać kopię danych karty na tym urządzeniu, by szybciej wypełniać formularze.</translation>
+<translation id="1111153019813902504">Ostatnio używane zakładki</translation>
<translation id="1113869188872983271">&amp;Cofnij zmianę kolejności</translation>
+<translation id="1126551341858583091">Rozmiar w pamięci lokalnej: <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Pamięć podręczna zasad: OK</translation>
<translation id="113188000913989374">Komunikat ze strony <ph name="SITE" />:</translation>
<translation id="1132774398110320017">Ustawienia autouzupełniania Chrome...</translation>
-<translation id="1150979032973867961">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa nie jest zaufany w systemie operacyjnym tego komputera. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego.</translation>
<translation id="1152921474424827756">Przejdź do <ph name="BEGIN_LINK" />kopii<ph name="END_LINK" /> <ph name="URL" /> w pamięci podręcznej</translation>
<translation id="1158211211994409885">Serwer <ph name="HOST_NAME" /> nieoczekiwanie zakończył połączenie.</translation>
<translation id="1161325031994447685">Ponownie połącz się z Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Usuń</translation>
<translation id="1201402288615127009">Dalej</translation>
<translation id="1201895884277373915">Więcej z tej witryny</translation>
-<translation id="121201262018556460">PrĂ³bujesz wejść na <ph name="DOMAIN" />, ale serwer przedstawiÅ‚ certyfikat ze sÅ‚abym kluczem. Intruz mĂ³gÅ‚ uzyskać klucz prywatny, a serwer może nie być tym, ktĂ³rego oczekujesz (możliwe, że komunikujesz siÄ™ z intruzem).</translation>
+<translation id="1206967143813997005">Nieprawidłowy podpis wstępny</translation>
+<translation id="1209206284964581585">Na razie ukryj</translation>
<translation id="1219129156119358924">Zabezpieczenia systemu</translation>
<translation id="1227224963052638717">Nieznana zasada.</translation>
<translation id="1227633850867390598">Ukryj wartość</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Tak</translation>
<translation id="1430915738399379752">Drukuj</translation>
<translation id="1442912890475371290">Zablokowano prĂ³bÄ™ <ph name="BEGIN_LINK" />wejÅ›cia na stronÄ™ w domenie <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Nie możesz teraz wejść na stronÄ™ <ph name="SITE" />, bo stosuje ona przypinanie certyfikatĂ³w. BÅ‚Ä™dy sieci i ataki sÄ… zazwyczaj przejÅ›ciowe, wiÄ™c prawdopodobnie pĂ³Åºniej strona bÄ™dzie dziaÅ‚ać. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Pokaż zapisaną (tzn. nieaktualną) kopię tej strony.</translation>
<translation id="1519264250979466059">Data kompilacji</translation>
<translation id="1549470594296187301">Aby można było korzystać z tej funkcji, musi być włączony JavaScript.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Konfiguracja sieci jest nieprawidłowa i nie można jej zaimportować.</translation>
<translation id="1644574205037202324">Historia</translation>
<translation id="1645368109819982629">NieobsÅ‚ugiwany protokĂ³Å‚</translation>
-<translation id="1655462015569774233">{1,plural, =1{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa wygasÅ‚ wczoraj. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. Zegar komputera jest obecnie ustawiony na <ph name="CURRENT_DATE" />. Czy to prawidÅ‚owa data? JeÅ›li nie, musisz skorygować zegar systemu, a nastÄ™pnie odÅ›wieżyć tÄ™ stronÄ™.}few{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa wygasÅ‚ # dni temu. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. Zegar komputera jest obecnie ustawiony na <ph name="CURRENT_DATE" />. Czy to prawidÅ‚owa data? JeÅ›li nie, musisz skorygować zegar systemu, a nastÄ™pnie odÅ›wieżyć tÄ™ stronÄ™.}many{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa wygasÅ‚ # dni temu. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. Zegar komputera jest obecnie ustawiony na <ph name="CURRENT_DATE" />. Czy to prawidÅ‚owa data? JeÅ›li nie, musisz skorygować zegar systemu, a nastÄ™pnie odÅ›wieżyć tÄ™ stronÄ™.}other{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa wygasÅ‚ # dnia temu. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. Zegar komputera jest obecnie ustawiony na <ph name="CURRENT_DATE" />. Czy to prawidÅ‚owa data? JeÅ›li nie, musisz skorygować zegar systemu, a nastÄ™pnie odÅ›wieżyć tÄ™ stronÄ™.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> zazwyczaj używa szyfrowania do ochrony Twoich informacji. Gdy tym razem Google Chrome prĂ³bowaÅ‚ poÅ‚Ä…czyć siÄ™ ze stronÄ… <ph name="SITE" />, odesÅ‚aÅ‚a ona nietypowe i nieprawidÅ‚owe dane logowania. Może siÄ™ tak zdarzyć, gdy pod stronÄ™ <ph name="SITE" /> podszywa siÄ™ atakujÄ…ca osoba albo gdy ekran logowania do sieci Wi-Fi przerwie poÅ‚Ä…czenie. Twoje informacje sÄ… nadal bezpieczne, bo poÅ‚Ä…czenie w Google Chrome zakoÅ„czyÅ‚o siÄ™ przed wymianÄ… jakichkolwiek danych.</translation>
<translation id="168841957122794586">Certyfikat serwera ma słaby klucz kryptograficzny.</translation>
<translation id="1701955595840307032">Uzyskaj dostęp do proponowanej treści</translation>
-<translation id="1706954506755087368">{1,plural, =1{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa przypuszczalnie zacznie obowiÄ…zywać od jutra. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia.}few{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa przypuszczalnie zacznie obowiÄ…zywać za # dni. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia.}many{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa przypuszczalnie zacznie obowiÄ…zywać za # dni. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia.}other{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa przypuszczalnie zacznie obowiÄ…zywać za # dnia. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia.}}</translation>
<translation id="1710259589646384581">System operacyjny</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Skontaktuj siÄ™ z administratorem systemu.</translation>
<translation id="17513872634828108">Otwarte karty</translation>
<translation id="1753706481035618306">Numer strony</translation>
-<translation id="1761412452051366565">Aby uzyskać dostęp do spersonalizowanej treści proponowanej przez Google, włącz synchronizację.</translation>
-<translation id="1763864636252898013">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa nie jest zaufany w systemie operacyjnym tego urzÄ…dzenia. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Uruchom DiagnostykÄ™ sieci systemu Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Zaktualizuj swoje hasło synchronizacji.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Tu pojawią się ostatnio otwierane zakładki.</translation>
<translation id="1821930232296380041">Nieprawidłowe żądanie lub jego parametry</translation>
<translation id="1838667051080421715">PrzeglÄ…dasz źrĂ³dÅ‚o strony internetowej.</translation>
<translation id="1871208020102129563">Proxy skonfigurowano do używania staÅ‚ych serwerĂ³w proxy, a nie URL-a skryptu PAC.</translation>
<translation id="1883255238294161206">Zwiń listę</translation>
<translation id="1898423065542865115">Filtrowanie</translation>
-<translation id="1911837502049945214">Serwer <ph name="HOST_NAME" /> nie zaakceptował Twojego certyfikatu logowania albo ten certyfikat wygasł.</translation>
<translation id="194030505837763158">Wejdź na <ph name="LINK" /></translation>
<translation id="1962204205936693436">Zakładki z <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Podczas przekształcania do postaci szeregowej wystąpił błąd</translation>
<translation id="1974060860693918893">Zaawansowane</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{i jeszcze 1}few{i jeszcze #}many{i jeszcze #}other{i jeszcze #}}</translation>
<translation id="2025186561304664664">Ustawiono automatyczne konfigurowanie proxy.</translation>
<translation id="2030481566774242610">Czy chodziło Ci o <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Ten komunikat pojawia się, ponieważ Twoi rodzice muszą zatwierdzić nowe strony, zanim po raz pierwszy je otworzysz.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Sprawdź serwer proxy i zaporę sieciową<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Kod pocztowy</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 podpowiedź}few{# podpowiedzi}many{# podpowiedzi}other{# podpowiedzi}}</translation>
<translation id="2065985942032347596">Wymagane uwierzytelnienie</translation>
<translation id="2079545284768500474">Cofnij</translation>
<translation id="20817612488360358">Skonfigurowano używanie systemowych ustawień proxy, ale podano też jawną konfigurację proxy.</translation>
@@ -105,33 +106,35 @@
<translation id="2149973817440762519">Edytuj zakładkę</translation>
<translation id="2166049586286450108">Pełny dostęp administratora</translation>
<translation id="2166378884831602661">Ta witryna nie umożliwia bezpiecznego połączenia</translation>
-<translation id="2171101176734966184">PrĂ³bujesz wejść na <ph name="DOMAIN" />, ale serwer przedstawiÅ‚ certyfikat podpisany sÅ‚abym algorytmem. Oznacza to, że dane uwierzytelniajÄ…ce podane przez serwer mogÅ‚y zostać sfaÅ‚szowane, a serwer może nie być tym, ktĂ³rego oczekujesz (możliwe, że komunikujesz siÄ™ z intruzem).</translation>
<translation id="2181821976797666341">Zasady</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}few{# adresy}many{# adresĂ³w}other{# adresu}}</translation>
<translation id="2212735316055980242">Nie znaleziono zasady</translation>
<translation id="2213606439339815911">Pobieram wpisy...</translation>
-<translation id="2214283295778284209">Witryna <ph name="SITE" /> jest niedostępna</translation>
<translation id="2230458221926704099">Napraw połączenie, używając <ph name="BEGIN_LINK" />aplikacji diagnostycznej<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Wyślij teraz</translation>
<translation id="225207911366869382">Ta wartość tej zasady została wycofana.</translation>
<translation id="2262243747453050782">BÅ‚Ä…d HTTP</translation>
<translation id="2282872951544483773">Niedostępne eksperymenty</translation>
<translation id="2292556288342944218">Masz zablokowany dostęp do internetu</translation>
<translation id="229702904922032456">WygasÅ‚ certyfikat gÅ‚Ă³wny lub poÅ›redniczÄ…cy.</translation>
<translation id="230155334948463882">Nowa karta?</translation>
+<translation id="2305919008529760154">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat mĂ³gÅ‚ zostać wydany w celu dokonania oszustwa. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> wymaga nazwy użytkownika i hasła.</translation>
+<translation id="2318774815570432836">Nie możesz teraz wejść na stronÄ™ <ph name="SITE" />, bo używa ona HSTS. BÅ‚Ä™dy sieci i ataki sÄ… zazwyczaj przejÅ›ciowe, wiÄ™c prawdopodobnie pĂ³Åºniej strona bÄ™dzie dziaÅ‚ać. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Zignorowano nieprawidłową zakładkę w indeksie <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Inne zakładki</translation>
<translation id="2359808026110333948">Dalej</translation>
<translation id="2365563543831475020">Raport o awarii utworzony w dniu: <ph name="CRASH_TIME" /> nie został przesłany</translation>
<translation id="2367567093518048410">Poziom</translation>
+<translation id="2371153335857947666">{1,plural, =1{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa wygasÅ‚ wczoraj. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. Zegar komputera jest obecnie ustawiony na <ph name="CURRENT_DATE" />. Czy to prawidÅ‚owa data? JeÅ›li nie, musisz skorygować zegar systemu, a nastÄ™pnie odÅ›wieżyć tÄ™ stronÄ™. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.}few{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa wygasÅ‚ # dni temu. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. Zegar komputera jest obecnie ustawiony na <ph name="CURRENT_DATE" />. Czy to prawidÅ‚owa data? JeÅ›li nie, musisz skorygować zegar systemu, a nastÄ™pnie odÅ›wieżyć tÄ™ stronÄ™. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.}many{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa wygasÅ‚ # dni temu. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. Zegar komputera jest obecnie ustawiony na <ph name="CURRENT_DATE" />. Czy to prawidÅ‚owa data? JeÅ›li nie, musisz skorygować zegar systemu, a nastÄ™pnie odÅ›wieżyć tÄ™ stronÄ™. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.}other{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa wygasÅ‚ # dnia temu. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. Zegar komputera jest obecnie ustawiony na <ph name="CURRENT_DATE" />. Czy to prawidÅ‚owa data? JeÅ›li nie, musisz skorygować zegar systemu, a nastÄ™pnie odÅ›wieżyć tÄ™ stronÄ™. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Brak dostÄ™pnych alternatywnych interfejsĂ³w</translation>
<translation id="2384307209577226199">Domyślne zasady przedsiębiorstwa</translation>
-<translation id="238526402387145295">Nie możesz teraz odwiedzić strony <ph name="SITE" />, bo <ph name="BEGIN_LINK" />używa ona HSTS<ph name="END_LINK" />. BÅ‚Ä™dy sieci i ataki sÄ… zazwyczaj przejÅ›ciowe, wiÄ™c prawdopodobnie strona bÄ™dzie wkrĂ³tce dziaÅ‚ać.</translation>
<translation id="2386255080630008482">Certyfikat serwera został unieważniony.</translation>
<translation id="2392959068659972793">Pokaż zasady bez ustawionej wartości</translation>
<translation id="2396249848217231973">&amp;Cofnij usunięcie</translation>
-<translation id="2413528052993050574">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa mĂ³gÅ‚ zostać odwoÅ‚any. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego.</translation>
<translation id="2455981314101692989">Automatyczne wypełnianie tego formularza zostało wyłączone przez stronę internetową.</translation>
-<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Uruchomienie diagnostyki sieci<ph name="END_LINK" /></translation>
+<translation id="2463739503403862330">Wpisz</translation>
+<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Uruchom diagnostykÄ™ sieci<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Nieprawidłowy URL wyszukiwania</translation>
<translation id="2491120439723279231">Certyfikat serwera zawiera błędy.</translation>
<translation id="2495083838625180221">Parser JSON</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Prześlij</translation>
<translation id="2674170444375937751">Czy na pewno chcesz usunąć te strony z historii?</translation>
<translation id="2677748264148917807">Wyjdź</translation>
+<translation id="269990154133806163">Serwer przedstawiÅ‚ certyfikat, ktĂ³ry nie zostaÅ‚ opublikowany za pomocÄ… zasad Certificate Transparency. W przypadku niektĂ³rych certyfikatĂ³w to wymaganie musi być speÅ‚nione, ponieważ gwarantuje, że można im ufać i że chroniÄ… one przed atakami. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Wartość nie pasuje do formatu.</translation>
<translation id="2704951214193499422">Chromium nie może obecnie potwierdzić karty. SprĂ³buj ponownie pĂ³Åºniej.</translation>
<translation id="2705137772291741111">Zapisana w pamięci podręcznej kopia tej strony jest uszkodzona.</translation>
<translation id="2709516037105925701">Autouzupełnianie</translation>
+<translation id="2712118517637785082">PrĂ³bujesz poÅ‚Ä…czyć siÄ™ z <ph name="DOMAIN" />, ale serwer przedstawiÅ‚ certyfikat unieważniony przez wystawcÄ™. Oznacza to, że dane logowania podane przez serwer sÄ… zupeÅ‚nie niewiarygodne. Możliwe, że komunikujesz siÄ™ z intruzem. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">PoproÅ› o pozwolenie</translation>
<translation id="2721148159707890343">Żądanie wykonane pomyślnie</translation>
<translation id="2728127805433021124">Certyfikat serwera został podpisany przy użyciu słabego algorytmu podpisu.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Pasek adresu i wyszukiwania</translation>
<translation id="2826760142808435982">Połączenie jest szyfrowane i uwierzytelniane algorytmem <ph name="CIPHER" />, a mechanizm wymiany kluczy to <ph name="KX" />.</translation>
<translation id="2835170189407361413">Wyczyść formularz</translation>
-<translation id="2837049386027881519">Konieczne byÅ‚o ponowienie prĂ³by poÅ‚Ä…czenia przy użyciu starszej wersji protokoÅ‚u TLS lub SSL. To zwykle oznacza, że serwer używa bardzo starego oprogramowania i może zawierać inne luki w zabezpieczeniach.</translation>
<translation id="284702764277384724">Certyfikat serwera <ph name="HOST_NAME" /> wydaje się sfałszowany.</translation>
<translation id="2889159643044928134">Nie Å‚aduj ponownie</translation>
-<translation id="2896499918916051536">Ta wtyczka nie jest obsługiwana.</translation>
+<translation id="2900469785430194048">Podczas prĂ³by wyÅ›wietlenia tej strony w Google Chrome zabrakÅ‚o pamiÄ™ci.</translation>
<translation id="2909946352844186028">Wykryto zmianÄ™ sieci.</translation>
-<translation id="2915500479781995473">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa wygasÅ‚. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. Zegar Twojego komputera jest obecnie ustawiony na <ph name="CURRENT_TIME" />. Czy to poprawny czas? JeÅ›li nie, ustaw go, a nastÄ™pnie odÅ›wież stronÄ™.</translation>
<translation id="2922350208395188000">Nie można sprawdzić certyfikatu serwera.</translation>
-<translation id="2941952326391522266">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat pochodzi z <ph name="DOMAIN2" />. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego.</translation>
<translation id="2948083400971632585">Możesz wyłączyć dowolne serwery proxy skonfigurowane dla połączenia na stronie ustawień.</translation>
<translation id="2955913368246107853">Zamknij pasek wyszukiwania</translation>
<translation id="2958431318199492670">Konfiguracja sieci jest niezgodna ze standardem ONC. Jej fragmenty mogły nie zostać zaimportowane.</translation>
@@ -188,11 +190,12 @@
<translation id="3024663005179499861">Nieprawidłowy typ zasady</translation>
<translation id="3032412215588512954">Chcesz ponownie załadować tę stronę?</translation>
<translation id="3037605927509011580">Kurza twarz!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{co najmniej 1 element na synchronizowanych urzÄ…dzeniach}=1{1 element (i wiÄ™cej na synchronizowanych urzÄ…dzeniach)}few{# elementy (i wiÄ™cej na synchronizowanych urzÄ…dzeniach)}many{# elementĂ³w (i wiÄ™cej na synchronizowanych urzÄ…dzeniach)}other{# elementu (i wiÄ™cej na synchronizowanych urzÄ…dzeniach)}}</translation>
<translation id="3041612393474885105">Informacje o certyfikacie</translation>
<translation id="3063697135517575841">Chrome nie może obecnie potwierdzić karty. SprĂ³buj ponownie pĂ³Åºniej.</translation>
<translation id="3093245981617870298">JesteÅ› offline.</translation>
<translation id="3105172416063519923">Identyfikator zasobu:</translation>
-<translation id="3109728660330352905">Nie masz autoryzacji do wyświetlania tej strony.</translation>
+<translation id="3109728660330352905">Nie masz uprawnień do wyświetlania tej strony.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Uruchom diagnostykę połączeń<ph name="END_LINK" />.</translation>
<translation id="3145945101586104090">Dekodowanie odpowiedzi nie powiodło się</translation>
<translation id="3150653042067488994">Tymczasowy błąd serwera</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Najnowsze</translation>
<translation id="3207960819495026254">Dodano do zakładek</translation>
-<translation id="3225919329040284222">Serwer przedstawiÅ‚ certyfikat, ktĂ³ry nie pasuje do zaprogramowanych oczekiwaÅ„. Oczekiwania majÄ… chronić CiÄ™ w okreÅ›lonych witrynach o wysokim poziomie zabezpieczeÅ„.</translation>
<translation id="3226128629678568754">Naciśnij przycisk ponownego załadowania, by przesłać dane wymagane do wczytania strony.</translation>
<translation id="3228969707346345236">Tłumaczenie nie powiodło się, ponieważ strona jest już w języku: <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Wpisz kod CVC karty <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Dodaj stronę do zakładek</translation>
<translation id="3270847123878663523">&amp;Cofnij zmianę kolejności</translation>
<translation id="3286538390144397061">Uruchom ponownie teraz</translation>
+<translation id="3303855915957856445">Brak wynikĂ³w wyszukiwania</translation>
<translation id="3305707030755673451">Twoje dane zostały zaszyfrowane z użyciem hasła synchronizacji w dniu <ph name="TIME" />. Wpisz je, by rozpocząć synchronizację.</translation>
<translation id="333371639341676808">Zapobiegaj wyświetlaniu dodatkowych okien dialogowych na tej stronie.</translation>
+<translation id="3338095232262050444">Bezpieczna</translation>
<translation id="3340978935015468852">ustawienia</translation>
<translation id="3345135638360864351">Nie udaÅ‚o siÄ™ wysÅ‚ać żądania dostÄ™pu do strony do <ph name="NAME" />. SprĂ³buj ponownie.</translation>
<translation id="3355823806454867987">Zmień ustawienia serwera proxy...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Okres pobierania:</translation>
<translation id="3462200631372590220">Ukryj zaawansowane</translation>
<translation id="3479539252931486093">Zaskoczyło Cię to? <ph name="BEGIN_LINK" />Daj nam znać<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Nie teraz</translation>
<translation id="348000606199325318">Identyfikator awarii: <ph name="CRASH_LOCAL_ID" /> (identyfikator serwera: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Obecnie nie możemy siÄ™ skontaktować z Twoim rodzicem. SprĂ³buj ponownie.</translation>
<translation id="3527085408025491307">Folder</translation>
@@ -240,23 +245,27 @@
<translation id="3542684924769048008">Używaj hasła dla:</translation>
<translation id="3549644494707163724">Szyfruj wszystkie synchronizowane dane za pomocą hasła synchronizacji</translation>
<translation id="3549761410225185768">Jeszcze <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat pochodzi z <ph name="DOMAIN2" />. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Połączenie nie jest prywatne</translation>
<translation id="3583757800736429874">&amp;PonĂ³w przeniesienie</translation>
<translation id="3586931643579894722">Ukryj szczegĂ³Å‚y</translation>
<translation id="3587482841069643663">Wszystkie</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3609138628363401169">Serwer nie obsługuje rozszerzenia ponownej negocjacji protokołu TLS.</translation>
-<translation id="36224234498066874">Wyczyść dane przeglądarki...</translation>
+<translation id="36224234498066874">Wyczyść dane przeglądania...</translation>
<translation id="362276910939193118">Wyświetl całą historię</translation>
<translation id="3623476034248543066">Pokaż wartość</translation>
<translation id="3630155396527302611">JeÅ›li ten program jest już na liÅ›cie programĂ³w mogÄ…cych korzystać z sieci,
sprĂ³buj go z niej usunąć i dodać ponownie.</translation>
+<translation id="3638794133396384728">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat wygasÅ‚. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. Zegar w Twoim komputerze jest obecnie ustawiony na <ph name="CURRENT_TIME" />. Czy to poprawny czas? JeÅ›li nie, ustaw poprawny czas w systemie, a nastÄ™pnie odÅ›wież tÄ™ stronÄ™. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Funkcje eksperymentalne mogÄ… w dowolnej chwili ulec zmianie, awarii lub też zostać wycofane. Nie dajemy absolutnie żadnych gwarancji dotyczÄ…cych tego, co siÄ™ może stać po wÅ‚Ä…czeniu jednego z tych eksperymentĂ³w – rĂ³wnie dobrze może dojść do samozapÅ‚onu przeglÄ…darki. Å»arty żartami, ale teoretycznie jest możliwe na przykÅ‚ad usuniÄ™cie wszystkich Twoich danych przez przeglÄ…darkÄ™ lub nieprzewidziane naruszenie Twojego bezpieczeÅ„stwa i prywatnoÅ›ci. Każdy wÅ‚Ä…czony eksperyment zostanie wÅ‚Ä…czony dla wszystkich użytkownikĂ³w tej przeglÄ…darki. Prosimy o zachowanie ostrożnoÅ›ci.</translation>
<translation id="3650584904733503804">Weryfikacja powiodła się</translation>
<translation id="3655670868607891010">Jeśli często widzisz ten komunikat, przeczytaj <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Wersja</translation>
+<translation id="3678029195006412963">Nie udało się podpisać żądania</translation>
<translation id="3681007416295224113">Informacje o certyfikacie</translation>
<translation id="3693415264595406141">Hasło:</translation>
+<translation id="3696411085566228381">brak</translation>
<translation id="3700528541715530410">Ups, wygląda na to, że nie masz uprawnień, by otworzyć tę stronę.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Åadowanie...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">WÅ‚Ä…cz komĂ³rkowÄ… transmisjÄ™ danych lub Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Sprawdź serwer proxy, zaporę sieciową i konfigurację DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Skopiowany link</translation>
-<translation id="3744899669254331632">Nie możesz teraz odwiedzić strony <ph name="SITE" />, ponieważ wysÅ‚aÅ‚a ona zaszyfrowane dane logowania, ktĂ³rych Chromium nie może przetworzyć. BÅ‚Ä™dy sieciowe i ataki sÄ… zazwyczaj tymczasowe, wiÄ™c prawdopodobnie strona bÄ™dzie dostÄ™pna pĂ³Åºniej.</translation>
<translation id="375403751935624634">Tłumaczenie nie powiodło się z powodu błędu serwera.</translation>
<translation id="3759461132968374835">Brak ostatnio zgÅ‚oszonych awarii. Awarie, ktĂ³re nastÄ…piÅ‚y wĂ³wczas, gdy funkcja zgÅ‚aszania awarii byÅ‚a wyÅ‚Ä…czona, nie sÄ… tutaj wymienione.</translation>
<translation id="3788090790273268753">Certyfikat tej witryny wygasa w 2016 roku, a Å‚aÅ„cuch certyfikatĂ³w zawiera certyfikat podpisany algorytmem SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Konflikt identyfikatorĂ³w urzÄ…dzeÅ„</translation>
<translation id="3885155851504623709">Gmina</translation>
<translation id="3901925938762663762">Karta straciła ważność</translation>
+<translation id="3910267023907260648">PrĂ³bujesz poÅ‚Ä…czyć siÄ™ z <ph name="DOMAIN" />, ale serwer przedstawiÅ‚ certyfikat podpisany sÅ‚abym algorytmem. Oznacza to, że dane logowania podane przez serwer mogÅ‚y zostać sfaÅ‚szowane, a serwer może nie być tym, ktĂ³rego oczekujesz (możliwe, że komunikujesz siÄ™ z intruzem). <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa przypuszczalnie zacznie obowiÄ…zywać od jutra. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.}few{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa przypuszczalnie zacznie obowiÄ…zywać za # dni. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.}many{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa przypuszczalnie zacznie obowiÄ…zywać za # ni. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.}other{Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa przypuszczalnie zacznie obowiÄ…zywać za # dnia. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Nie można wczytać dokumentu PDF</translation>
<translation id="3963721102035795474">Tryb czytnika</translation>
+<translation id="397105322502079400">Obliczanie...</translation>
<translation id="3973234410852337861">Strona <ph name="HOST_NAME" /> jest zablokowana</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 strona w pobliżu}few{# strony w pobliżu}many{# stron w pobliżu}other{# strony w pobliżu}}</translation>
<translation id="4021036232240155012">DNS to usługa sieciowa tłumacząca nazwę serwera na jego adres internetowy.</translation>
<translation id="4030383055268325496">&amp;Cofnij dodanie</translation>
-<translation id="4032534284272647190">OdmĂ³wiono dostÄ™pu do <ph name="URL" />.</translation>
<translation id="404928562651467259">OSTRZEŻENIE</translation>
<translation id="4058922952496707368">Klucz â€<ph name="SUBKEY" />â€: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Klient i serwer nie obsÅ‚ugujÄ… wspĂ³lnej wersji protokoÅ‚u SSL lub mechanizmu szyfrowania.</translation>
<translation id="4079302484614802869">Proxy skonfigurowano do używania URL-a skryptu PAC, a nie ustalonych serwerĂ³w proxy.</translation>
<translation id="4103249731201008433">Numer seryjny urządzenia jest nieprawidłowy</translation>
<translation id="4103763322291513355">Wejdź na stronę &lt;strong&gt;chrome://policy&lt;/strong&gt;, aby wyświetlić czarną listę URL-i oraz inne zasady egzekwowane przez administratora systemu.</translation>
+<translation id="4110615724604346410">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat zawiera bÅ‚Ä™dy. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Ten zakres zasad nie jest obsługiwany.</translation>
+<translation id="4118212371799607889">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat nie jest zaufany w Chromium. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 inny wpis}few{# inne wpisy}many{# innych wpisĂ³w}other{# innego wpisu}}</translation>
<translation id="4130226655945681476">Sprawdź kable sieciowe, modem i router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Czy Chromium ma zapisać tę kartę?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Wyłączone</translation>
<translation id="4196861286325780578">&amp;PonĂ³w przeniesienie</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Sprawdź konfigurację zapory sieciowej i oprogramowania antywirusowego<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{brak}=1{1 aplikacja ($1)}=2{2 aplikacje ($1, $2)}few{# aplikacje ($1, $2, $3)}many{# aplikacji ($1, $2, $3)}other{# aplikacji ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Awarie</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Uruchom diagnostykÄ™ sieci<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Nie</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Brak nazwy użytkownika)</translation>
<translation id="4300246636397505754">Propozycje rodzicĂ³w</translation>
<translation id="4304224509867189079">Zaloguj siÄ™</translation>
+<translation id="432290197980158659">Serwer przedstawiÅ‚ certyfikat, ktĂ³ry nie speÅ‚nia wbudowanych warunkĂ³w. PrzeglÄ…darka sprawdza je w przypadku okreÅ›lonych witryn wymagajÄ…cych wysokiego poziomu bezpieczeÅ„stwa. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Nie udało się znaleźć artykułu</translation>
+<translation id="4331708818696583467">Niebezpieczna</translation>
<translation id="4372948949327679948">Oczekiwano wartości typu <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">PrĂ³bujesz wejść na <ph name="DOMAIN" />, ale serwer przedstawiÅ‚ certyfikat unieważniony przez wystawcÄ™. Oznacza to, że dane uwierzytelniajÄ…ce podane przez serwer sÄ… zupeÅ‚nie niewiarygodne. Możliwe, że komunikujesz siÄ™ z intruzem.</translation>
<translation id="4381091992796011497">Nazwa użytkownika:</translation>
<translation id="4394049700291259645">Wyłącz</translation>
<translation id="4395129973926795186">Od <ph name="START_DATE" /> do <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">wyniki wyszukiwania</translation>
-<translation id="4424024547088906515">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa nie jest zaufany w Chrome. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego.</translation>
+<translation id="4432688616882109544">Serwer <ph name="HOST_NAME" /> nie zaakceptował lub nie otrzymał Twojego certyfikatu logowania.</translation>
<translation id="443673843213245140">Korzystanie z serwera proxy jest wyłączone, ale podano konfigurację proxy.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Ten komunikat pojawia się, ponieważ włączony jest filtr Google SafeSites.</translation>
@@ -323,34 +339,39 @@
<translation id="4522570452068850558">SzczegĂ³Å‚y</translation>
<translation id="4558551763791394412">SprĂ³buj wyÅ‚Ä…czyć rozszerzenia.</translation>
<translation id="4587425331216688090">Usunąć ten adres z Chrome?</translation>
+<translation id="4589078953350245614">PrĂ³bujesz wejść na <ph name="DOMAIN" />, ale serwer przedstawiÅ‚ nieprawidÅ‚owy certyfikat. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">PoÅ‚Ä…czenie z <ph name="DOMAIN" /> jest szyfrowane przy użyciu nowoczesnego zestawu szyfrĂ³w.</translation>
<translation id="4594403342090139922">&amp;Cofnij usunięcie</translation>
+<translation id="4627442949885028695">Kontynuuj z innego urzÄ…dzenia</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">PrzeglÄ…dasz stronÄ™ rozszerzenia.</translation>
-<translation id="467662567472608290">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa ma bÅ‚Ä™dy. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> został zablokowany</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Połączenie zostało przerwane</translation>
-<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Uruchomienie Diagnostyki sieci systemu Windows<ph name="END_LINK" /></translation>
+<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Uruchom DiagnostykÄ™ sieci systemu Windows<ph name="END_LINK" /></translation>
<translation id="4726672564094551039">Odśwież zasady</translation>
<translation id="4728558894243024398">Platforma</translation>
<translation id="4744603770635761495">Åcieżka pliku wykonywalnego</translation>
<translation id="4756388243121344051">&amp;Historia</translation>
+<translation id="4759238208242260848">Pobrane pliki</translation>
<translation id="4764776831041365478">Strona internetowa pod adresem <ph name="URL" /> może być tymczasowo niedostępna lub została na stałe przeniesiona pod nowy adres internetowy.</translation>
<translation id="4771973620359291008">Wystąpił nieznany błąd.</translation>
<translation id="4782449893814226250">ZapytaÅ‚eÅ› rodzicĂ³w, czy możesz wejść na tÄ™ stronÄ™.</translation>
<translation id="4800132727771399293">Sprawdź datÄ™ ważnoÅ›ci i kod CVC, a potem sprĂ³buj ponownie</translation>
-<translation id="4807049035289105102">Nie możesz teraz wejść na stronÄ™ <ph name="SITE" />, bo wysÅ‚aÅ‚a ona zaszyfrowane dane logowania, ktĂ³rych Google Chrome nie może przetworzyć. BÅ‚Ä™dy sieci i ataki sÄ… zazwyczaj przejÅ›ciowe, wiÄ™c prawdopodobnie strona bÄ™dzie wkrĂ³tce dziaÅ‚ać.</translation>
<translation id="4813512666221746211">BÅ‚Ä…d sieci</translation>
-<translation id="4816492930507672669">Dopasuj do strony.</translation>
+<translation id="4816492930507672669">Dopasuj do strony</translation>
<translation id="4850886885716139402">Widok</translation>
<translation id="4880827082731008257">Przeszukaj historiÄ™</translation>
+<translation id="4884656795097055129">WiÄ™cej artykuÅ‚Ă³w pojawi siÄ™ w odpowiednim czasie.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{i jeszcze 1 strona}few{i jeszcze # strony}many{i jeszcze # stron}other{i jeszcze # strony}}</translation>
<translation id="4923417429809017348">Ta strona została przetłumaczona z nieznanego języka na język <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Musi być określona.</translation>
<translation id="4930497775425430760">Ten komunikat pojawia siÄ™, ponieważ TwĂ³j rodzic musi zatwierdzić nowe strony, zanim po raz pierwszy je otworzysz.</translation>
<translation id="495170559598752135">Czynności</translation>
<translation id="4958444002117714549">Rozwiń listę</translation>
+<translation id="4962322354953122629">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat nie jest zaufany w Chrome. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Przetłumaczyć z języka: <ph name="ORIGINAL_LANGUAGE" /> na <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Ta wtyczka nie jest obsługiwana</translation>
<translation id="5002932099480077015">Jeśli włączysz tę opcję, Chrome zapisze kopię Twojej karty na tym urządzeniu, by umożliwić Ci szybsze wypełnianie formularzy.</translation>
<translation id="5019198164206649151">Nieprawidłowy stan magazynu wspomagającego</translation>
<translation id="5023310440958281426">Sprawdź zasady administratora</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Tłumacz Google – informacje</translation>
<translation id="5040262127954254034">Prywatność</translation>
<translation id="5045550434625856497">Nieprawidłowe hasło</translation>
+<translation id="5056549851600133418">Artykuły dla Ciebie</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Sprawdź adres serwera proxy<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Certyfikat serwera nie jest obecnie ważny.</translation>
<translation id="5089810972385038852">Stan</translation>
-<translation id="5094747076828555589">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa nie jest zaufany w Chromium. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego.</translation>
<translation id="5095208057601539847">Prowincja</translation>
<translation id="5115563688576182185">(64-bitowa)</translation>
-<translation id="5122371513570456792">Znaleziono <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> dla â€<ph name="SEARCH_STRING" />â€.</translation>
<translation id="5141240743006678641">Szyfruj synchronizowane hasła za pomocą danych logowania Google</translation>
<translation id="5145883236150621069">W odebranej polityce znajduje się kod błędu</translation>
<translation id="5171045022955879922">Wyszukaj lub wpisz URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Pasek zakładek</translation>
<translation id="5199729219167945352">Eksperymenty</translation>
<translation id="5251803541071282808">Chmura</translation>
+<translation id="5277279256032773186">Korzystasz z Chrome w pracy? Firmy mogÄ… zarzÄ…dzać ustawieniami Chrome swoich pracownikĂ³w. WiÄ™cej informacji</translation>
<translation id="5299298092464848405">Podczas przetwarzania zasady wystąpił błąd</translation>
<translation id="5300589172476337783">Pokaż</translation>
<translation id="5308689395849655368">Funkcja zgłaszania awarii jest wyłączona.</translation>
<translation id="5317780077021120954">Zapisz</translation>
<translation id="5327248766486351172">Nazwa</translation>
+<translation id="5359637492792381994">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa nie jest obecnie ważny. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Zapisanie ustawień zasady nie powiodło się</translation>
-<translation id="540969355065856584">Ten serwer nie może udowodnić, że należy do domeny <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa nie jest obecnie ważny. Może to być spowodowane nieprawidłową konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
<translation id="5421136146218899937">Wyczyść dane przeglądania...</translation>
<translation id="5430298929874300616">Usuń zakładkę</translation>
<translation id="5431657950005405462">Nie znaleziono pliku</translation>
<translation id="5435775191620395718">Wyświetlam historię z tego urządzenia. <ph name="BEGIN_LINK" />Więcej informacji<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">Personalizacja polecanych treści jest obecnie wyłączona, ponieważ synchronizowane dane są chronione niestandardowym hasłem.</translation>
<translation id="5439770059721715174">BÅ‚Ä…d podczas sprawdzania poprawnoÅ›ci schematu – â€<ph name="ERROR_PATH" />â€: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Nie można znaleźć tej strony na <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">Nieprawidłowy czas zasady</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Chcesz opuścić tę stronę?</translation>
<translation id="5629630648637658800">Åadowanie ustawieÅ„ zasady nie powiodÅ‚o siÄ™</translation>
<translation id="5631439013527180824">Nieprawidłowy token zarządzania urządzeniem</translation>
-<translation id="5650551054760837876">Nie znaleziono wynikĂ³w wyszukiwania.</translation>
<translation id="5677928146339483299">Zablokowane</translation>
<translation id="5710435578057952990">Tożsamość witryny nie została zweryfikowana.</translation>
<translation id="5720705177508910913">Bieżący użytkownik</translation>
+<translation id="572328651809341494">Ostatnie karty</translation>
<translation id="5784606427469807560">Podczas potwierdzania karty wystÄ…piÅ‚ problem. Sprawdź poÅ‚Ä…czenie internetowe i sprĂ³buj ponownie.</translation>
<translation id="5785756445106461925">Ta strona zawiera także niezabezpieczone zasoby. Podczas przesyłania mogą je wyświetlić inni użytkownicy, a osoby atakujące mogą je zmodyfikować, by zmienić wygląd strony.</translation>
+<translation id="5786044859038896871">Chcesz wpisać dane swojej karty?</translation>
+<translation id="5803412860119678065">Chcesz wpisać dane swojej karty (<ph name="CARD_DETAIL" />)?</translation>
<translation id="5810442152076338065">PoÅ‚Ä…czenie z <ph name="DOMAIN" /> jest szyfrowane przy użyciu przestarzaÅ‚ego zestawu szyfrĂ³w.</translation>
<translation id="5813119285467412249">&amp;PonĂ³w dodanie</translation>
+<translation id="5814352347845180253">Możesz stracić dostÄ™p do pÅ‚atnych treÅ›ci w <ph name="SITE" /> i na niektĂ³rych innych stronach.</translation>
+<translation id="5843436854350372569">PrĂ³bujesz poÅ‚Ä…czyć siÄ™ z <ph name="DOMAIN" />, ale serwer przedstawiÅ‚ certyfikat ze sÅ‚abym kluczem. Intruz mĂ³gÅ‚ zÅ‚amać klucz prywatny, a serwer może nie być tym, ktĂ³rego oczekujesz (możliwe, że komunikujesz siÄ™ z intruzem). <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Ten komunikat pojawia siÄ™, ponieważ TwĂ³j menedżer zablokowaÅ‚ tÄ™ stronÄ™.</translation>
<translation id="5857090052475505287">Nowy folder</translation>
<translation id="5869405914158311789">Ta witryna jest nieosiÄ…galna</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Propozycje rodzicĂ³w</translation>
<translation id="59107663811261420">Karty tego typu nie są obsługiwane w Google Payments w przypadku tego sprzedawcy. Wybierz inną.</translation>
<translation id="59174027418879706">WÅ‚Ä…czone</translation>
+<translation id="5926846154125914413">Możesz stracić dostÄ™p do pÅ‚atnych treÅ›ci na niektĂ³rych stronach.</translation>
<translation id="5966707198760109579">Tydzień</translation>
<translation id="5967867314010545767">Usuń z historii</translation>
<translation id="5975083100439434680">Pomniejsz</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Automatyczne</translation>
<translation id="6042308850641462728">Więcej</translation>
<translation id="6060685159320643512">Ostrożnie, na tych eksperymentach można się sparzyć</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{brak}=1{1}few{#}many{#}other{#}}</translation>
<translation id="6146055958333702838">Sprawdź wszystkie kable i uruchom ponownie wszelkie używane routery, modemy
i inne urzÄ…dzenia sieciowe.</translation>
<translation id="614940544461990577">WyprĂ³buj te rozwiÄ…zania:</translation>
<translation id="6150607114729249911">Ups! Musisz spytać rodzicĂ³w, czy możesz wejść na tÄ™ stronÄ™.</translation>
<translation id="6151417162996330722">Certyfikat serwera ma za długi okres ważności.</translation>
-<translation id="6154808779448689242">ZwrĂ³cony token zasady jest niezgodny z bieżącym</translation>
<translation id="6165508094623778733">Więcej informacji</translation>
<translation id="6203231073485539293">Sprawdź połączenie z internetem</translation>
<translation id="6218753634732582820">Usunąć ten adres z Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Wyłącz przewidywanie działań sieciowych</translation>
<translation id="6337534724793800597">Filtruj zasady według nazwy</translation>
<translation id="6342069812937806050">Przed momentem</translation>
+<translation id="6345221851280129312">nieznany rozmiar</translation>
<translation id="6355080345576803305">ZastÄ…pienie sesji publicznej</translation>
<translation id="6358450015545214790">Co to oznacza?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 inna podpowiedź}few{# inne podpowiedzi}many{# innych podpowiedzi}other{# innej podpowiedzi}}</translation>
<translation id="6387478394221739770">InteresujÄ… CiÄ™ nowe, przydatne funkcje Chrome? WyprĂ³buj wersjÄ™ beta ze strony chrome.com/beta.</translation>
-<translation id="641480858134062906">Nie można załadować adresu <ph name="URL" /></translation>
+<translation id="6389758589412724634">Podczas prĂ³by wyÅ›wietlenia tej strony w Chromium zabrakÅ‚o pamiÄ™ci.</translation>
+<translation id="6416403317709441254">Nie możesz teraz wejść na <ph name="SITE" />, bo ta witryna wysÅ‚aÅ‚a zaszyfrowane dane logowania, ktĂ³rych Chromium nie może przetworzyć. BÅ‚Ä™dy sieci i ataki sÄ… zazwyczaj przejÅ›ciowe, wiÄ™c prawdopodobnie pĂ³Åºniej strona bÄ™dzie dziaÅ‚ać. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Nie można sprawdzić, czy certyfikat został unieważniony.</translation>
<translation id="6433595998831338502">Serwer <ph name="HOST_NAME" /> odrzucił połączenie.</translation>
<translation id="6445051938772793705">Kraj</translation>
<translation id="6451458296329894277">Potwierdź ponowne przesłanie formularza</translation>
<translation id="6458467102616083041">Ignorowana, ponieważ wyszukiwarka domyślna jest wyłączona przez zasadę.</translation>
+<translation id="6462969404041126431">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat mĂ³gÅ‚ zostać unieważniony. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Zasady dotyczące urządzeń</translation>
<translation id="6489534406876378309">Rozpocznij przesyłanie informacji o awariach</translation>
<translation id="6529602333819889595">&amp;PonĂ³w usuniÄ™cie</translation>
+<translation id="6534179046333460208">Sugestie dotyczÄ…ce internetu rzeczy</translation>
<translation id="6550675742724504774">Opcje</translation>
+<translation id="6593753688552673085">mniej niż <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opcje szyfrowania</translation>
<translation id="662080504995468778">Zostań</translation>
<translation id="6628463337424475685">Wyszukiwarka <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Nie możesz teraz odwiedzić strony <ph name="SITE" />, bo <ph name="BEGIN_LINK" />ten certyfikat zostaÅ‚ unieważniony<ph name="END_LINK" />. BÅ‚Ä™dy sieci i ataki sÄ… zazwyczaj przejÅ›ciowe, wiÄ™c prawdopodobnie strona bÄ™dzie wkrĂ³tce dziaÅ‚ać.</translation>
<translation id="6644283850729428850">Zasada jest przestarzała.</translation>
+<translation id="6652240803263749613">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat nie jest zaufany w systemie operacyjnym Twojego komputera. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Folder edytora</translation>
<translation id="6660210980321319655">Automatyczne zgłoszenie: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Usunąć tę podpowiedź do formularza z Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Wstecz</translation>
<translation id="6710594484020273272">&lt;Wpisz wyszukiwane słowa&gt;</translation>
<translation id="6711464428925977395">Serwer proxy działa nieprawidłowo albo adres jest błędny.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{brak}=1{1 element}few{# elementy}many{# elementĂ³w}other{# elementu}}</translation>
<translation id="674375294223700098">Nieznany błąd certyfikatu serwera.</translation>
<translation id="6753269504797312559">Wartość zasady</translation>
<translation id="6757797048963528358">Twoje urządzenie przeszło w tryb uśpienia.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Ten poziom zasad nie jest obsługiwany.</translation>
<translation id="6895330447102777224">Karta została potwierdzona</translation>
<translation id="6897140037006041989">Klient</translation>
-<translation id="6903907808598579934">WÅ‚Ä…cz synchronizacjÄ™</translation>
<translation id="6915804003454593391">Użytkownik:</translation>
<translation id="6957887021205513506">Certyfikat serwera wydaje się sfałszowany.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Okręg</translation>
<translation id="6973656660372572881">OkreÅ›lono zarĂ³wno staÅ‚e serwery proxy, jak i URL skryptu PAC.</translation>
<translation id="6989763994942163495">Pokaż ustawienia zaawansowane...</translation>
+<translation id="7000990526846637657">Brak wpisĂ³w historii</translation>
+<translation id="7009986207543992532">PrĂ³bujesz poÅ‚Ä…czyć siÄ™ z <ph name="DOMAIN" />, ale serwer przedstawiÅ‚ certyfikat, ktĂ³rego okres ważnoÅ›ci jest za dÅ‚ugi, by byÅ‚ wiarygodny. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Inne rodzaje historii przeglądania mogą być nadal dostępne na Twoim koncie Google na <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Hasła</translation>
-<translation id="7050187094878475250">PrĂ³bujesz poÅ‚Ä…czyć siÄ™ z domenÄ… <ph name="DOMAIN" />, ale serwer przedstawiÅ‚ certyfikat, ktĂ³rego okres ważnoÅ›ci jest za dÅ‚ugi, by byÅ‚ wiarygodny.</translation>
<translation id="7087282848513945231">Hrabstwo</translation>
<translation id="7088615885725309056">Starsze</translation>
<translation id="7090678807593890770">Wyszukaj w Google: <ph name="LINK" /></translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Ten komunikat pojawia siÄ™, ponieważ TwĂ³j menedżer musi zatwierdzić nowe strony, zanim po raz pierwszy je otworzysz.</translation>
<translation id="724975217298816891">Wpisz datÄ™ ważnoÅ›ci i kod CVC karty <ph name="CREDIT_CARD" />, by zaktualizować jej szczegĂ³Å‚owe dane. Po potwierdzeniu zostanÄ… one udostÄ™pnione tej stronie.</translation>
<translation id="725866823122871198">Nie można nawiązać prywatnego połączenia z <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, ponieważ data i godzina (<ph name="DATE_AND_TIME" />) ustawione na komputerze są nieprawidłowe.</translation>
-<translation id="7265986070661382626">Nie możesz teraz odwiedzić strony <ph name="SITE" />, bo <ph name="BEGIN_LINK" />stosuje ona przypinanie certyfikatĂ³w<ph name="END_LINK" />. BÅ‚Ä™dy sieci i ataki sÄ… zazwyczaj przejÅ›ciowe, wiÄ™c prawdopodobnie strona bÄ™dzie wkrĂ³tce dziaÅ‚ać.</translation>
<translation id="7269802741830436641">Ta strona internetowa zawiera pętlę przekierowań</translation>
<translation id="7275334191706090484">Zakładki zarządzane</translation>
<translation id="7298195798382681320">Zalecane</translation>
-<translation id="7301833672208172928">WÅ‚Ä…cz synchronizacjÄ™ historii</translation>
+<translation id="7309308571273880165">Raport o awarii utworzony w dniu: <ph name="CRASH_TIME" /> (użytkownik zażądał przesłania raportu, ale nie został on jeszcze przesłany)</translation>
<translation id="7334320624316649418">&amp;PonĂ³w zmianÄ™ kolejnoÅ›ci</translation>
<translation id="733923710415886693">Certyfikat serwera nie zostaÅ‚ ujawniony przez protokĂ³Å‚ Certificate Transparency.</translation>
+<translation id="7351800657706554155">Nie możesz teraz wejść na stronÄ™ <ph name="SITE" />, bo jej certyfikat zostaÅ‚ unieważniony. BÅ‚Ä™dy sieci i ataki sÄ… zazwyczaj przejÅ›ciowe, wiÄ™c prawdopodobnie pĂ³Åºniej strona bÄ™dzie dziaÅ‚ać. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Wiersz poleceń</translation>
<translation id="7372973238305370288">wynik wyszukiwania</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> – <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="7469372306589899959">Potwierdzam kartÄ™</translation>
<translation id="7481312909269577407">Dalej</translation>
<translation id="7485870689360869515">Nie znaleziono danych.</translation>
+<translation id="7508255263130623398">ZwrĂ³cony identyfikator urzÄ…dzenia dla zasad jest pusty lub nie pasuje do bieżącego identyfikatora urzÄ…dzenia</translation>
<translation id="7514365320538308">Pobierz</translation>
<translation id="7518003948725431193">Nie znaleziono strony internetowej pod adresem <ph name="URL" /></translation>
<translation id="7537536606612762813">ObowiÄ…zkowe</translation>
<translation id="7542995811387359312">Automatyczne wypełnianie danych karty kredytowej jest wyłączone, ponieważ ten formularz nie korzysta z bezpiecznego połączenia.</translation>
<translation id="7549584377607005141">Do poprawnego wyÅ›wietlenia tej strony internetowej wymagane sÄ… dane wpisane przez Ciebie wczeÅ›niej. Możesz wysÅ‚ać je ponownie, ale spowoduje to powtĂ³rzenie wszystkich dziaÅ‚aÅ„ wykonanych poprzednio przez stronÄ™.</translation>
<translation id="7554791636758816595">Nowa karta</translation>
-<translation id="7567204685887185387">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeÅ„stwa mĂ³gÅ‚ zostać wydany w celu oszustwa. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego.</translation>
<translation id="7568593326407688803">Język strony:<ph name="ORIGINAL_LANGUAGE" />Chcesz ją przetłumaczyć?</translation>
<translation id="7569952961197462199">Usunąć tę kartę kredytową z Chrome?</translation>
<translation id="7578104083680115302">Używaj swoich kart zapisanych w Google, by Å‚atwiej dokonywać pÅ‚atnoÅ›ci na stronach i w aplikacjach na rĂ³Å¼nych urzÄ…dzeniach.</translation>
+<translation id="7588950540487816470">Internet rzeczy</translation>
<translation id="7592362899630581445">Certyfikat serwera narusza ograniczenia dotyczÄ…ce nazw.</translation>
<translation id="759889825892636187">Serwer <ph name="HOST_NAME" /> nie może teraz obsłużyć tego żądania.</translation>
<translation id="7600965453749440009">Nigdy nie tłumacz z języka: <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="7637571805876720304">Usunąć tę kartę kredytową z Chromium?</translation>
<translation id="765676359832457558">Ukryj ustawienia zaawansowane...</translation>
<translation id="7658239707568436148">Anuluj</translation>
+<translation id="7667346355482952095">ZwrĂ³cony token zasad jest pusty lub nie pasuje do bieżącego tokenu</translation>
<translation id="7668654391829183341">Nieznane urzÄ…dzenie</translation>
<translation id="7674629440242451245">InteresujÄ… CiÄ™ nowe, przydatne funkcje Chrome? WyprĂ³buj wersjÄ™ deweloperskÄ… ze strony chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />OtwĂ³rz stronÄ™ <ph name="SITE" /> (niebezpiecznÄ…)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="780301667611848630">Nie, dziękuję</translation>
<translation id="7805768142964895445">Stan</translation>
<translation id="7813600968533626083">Usunąć tę podpowiedź do formularza z Chrome?</translation>
+<translation id="7815407501681723534">Znalezione <ph name="SEARCH_RESULTS" /> dla zapytania â€<ph name="SEARCH_STRING" />â€: <ph name="NUMBER_OF_RESULTS" /></translation>
<translation id="785549533363645510">To jednak nie znaczy, że CiÄ™ nie widać. Nawet gdy przejdziesz w tryb incognito, TwĂ³j pracodawca, dostawca usÅ‚ug internetowych czy webmasterzy stron, na ktĂ³re wchodzisz, mogÄ… dowiedzieć siÄ™, co przeglÄ…dasz.</translation>
<translation id="7887683347370398519">Sprawdź kod CVC i sprĂ³buj ponownie</translation>
<translation id="7894616681410591072">Ups! Jeśli chcesz wejść na tę stronę, <ph name="NAME" /> musi wyrazić na to zgodę.</translation>
-<translation id="790025292736025802">Nie znaleziono adresu <ph name="URL" /></translation>
<translation id="7912024687060120840">W folderze:</translation>
<translation id="7920092496846849526">Zapytałeś rodzica, czy możesz wejść na tę stronę.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="7995512525968007366">Nie określono</translation>
<translation id="8012647001091218357">Obecnie nie możemy siÄ™ skontaktować z Twoimi rodzicami. SprĂ³buj ponownie.</translation>
<translation id="8034522405403831421">Język tej strony to <ph name="SOURCE_LANGUAGE" />. Przetłumaczyć ją na <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Brak wpisĂ³w historii.</translation>
<translation id="8088680233425245692">Nie udało się wyświetlić artykułu.</translation>
+<translation id="8089520772729574115">mniej niż 1 MB</translation>
<translation id="8091372947890762290">Aktywacja oczekuje na serwerze</translation>
+<translation id="8129262335948759431">nieznana ilość</translation>
<translation id="8131740175452115882">Potwierdź</translation>
<translation id="8134994873729925007">Nie udało się znaleźć <ph name="BEGIN_ABBR" />adresu DNS<ph name="END_ABBR" /> serwera <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">TwĂ³j komputer przeszedÅ‚ w tryb uÅ›pienia.</translation>
@@ -604,6 +640,7 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="8201077131113104583">NieprawidÅ‚owy URL aktualizowania dla rozszerzenia o identyfikatorze â€<ph name="EXTENSION_ID" />â€.</translation>
<translation id="8218327578424803826">Przypisana lokalizacja:</translation>
<translation id="8225771182978767009">Administrator tego komputera zablokował tę witrynę.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Strona, na ktĂ³rej wyszukiwane sÄ… wprowadzone przez Ciebie informacje. PowrĂ³t do tej strony może spowodować konieczność powtĂ³rzenia wykonanych czynnoÅ›ci. Czy chcesz kontynuować?</translation>
<translation id="8249320324621329438">Ostatnie pobieranie:</translation>
<translation id="8261506727792406068">Usuń</translation>
@@ -616,12 +653,17 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="8349305172487531364">Pasek zakładek</translation>
<translation id="8363502534493474904">Wyłącz tryb samolotowy</translation>
<translation id="8364627913115013041">Nie ustawiono.</translation>
+<translation id="8380941800586852976">Niebezpieczna</translation>
<translation id="8412145213513410671">Awarie (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Musisz dwukrotnie wpisać to samo hasło.</translation>
<translation id="8428213095426709021">Ustawienia</translation>
+<translation id="8433057134996913067">Zostaniesz wylogowany z większości stron internetowych.</translation>
<translation id="8437238597147034694">&amp;Cofnij przeniesienie</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 karta kredytowa}few{# karty kredytowe}many{# kart kredytowych}other{# karty kredytowej}}</translation>
+<translation id="8483780878231876732">Aby użyć kart z konta Google, zaloguj się w Chrome</translation>
<translation id="8488350697529856933">Dotyczy</translation>
<translation id="8498891568109133222">Serwer <ph name="HOST_NAME" /> potrzebował zbyt wiele czasu na odpowiedź.</translation>
+<translation id="852346902619691059">Ten serwer nie mĂ³gÅ‚ udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat nie jest zaufany w systemie operacyjnym Twojego urzÄ…dzenia. Może to być spowodowane bÅ‚Ä™dnÄ… konfiguracjÄ… lub przechwyceniem poÅ‚Ä…czenia przez atakujÄ…cego. <ph name="BEGIN_LEARN_MORE_LINK" />Dowiedz siÄ™ wiÄ™cej<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Karty tego typu nie są obsługiwane w Google Payments. Wybierz inną.</translation>
<translation id="8550022383519221471">Usługa synchronizacji nie jest dostępna w Twojej domenie.</translation>
<translation id="8553075262323480129">Tłumaczenie nie powiodło się, ponieważ nie można określić języka strony.</translation>
@@ -633,15 +675,12 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="8647750283161643317">PrzywrĂ³Ä‡ wszystkie ustawienia domyÅ›lne</translation>
<translation id="8680787084697685621">Dane logowania na konto sÄ… nieaktualne.</translation>
<translation id="8703575177326907206">Połączenie z witryną <ph name="DOMAIN" /> nie jest szyfrowane.</translation>
-<translation id="8713130696108419660">Błędny podpis wstępny</translation>
<translation id="8725066075913043281">SprĂ³buj ponownie</translation>
<translation id="8728672262656704056">JesteÅ› w trybie incognito</translation>
<translation id="8730621377337864115">Gotowe</translation>
<translation id="8738058698779197622">Aby nawiÄ…zać bezpieczne poÅ‚Ä…czenie, TwĂ³j zegar musi mieć ustawionÄ… prawidÅ‚owÄ… godzinÄ™. Jest to wymagane, ponieważ certyfikaty używane do identyfikacji stron internetowych sÄ… ważne tylko przez okreÅ›lony czas. Ponieważ zegar Twojego urzÄ…dzenia nie jest ustawiony prawidÅ‚owo, Chromium nie może zweryfikować tych certyfikatĂ³w.</translation>
<translation id="8740359287975076522">Nie znaleziono &lt;abbr id="dnsDefinition"&gt;adresu DNS&lt;/abbr&gt; serwera <ph name="HOST_NAME" />. Diagnozujemy problem.</translation>
-<translation id="8741995161408053644">Inne rodzaje historii przeglądania mogą być nadal dostępne na Twoim koncie Google na <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;PonĂ³w usuniÄ™cie</translation>
-<translation id="8790687370365610530">Aby uzyskać dostęp do spersonalizowanej treści proponowanej przez Google, włącz synchronizację historii.</translation>
<translation id="8798099450830957504">Domyślny</translation>
<translation id="8804164990146287819">Polityka prywatności</translation>
<translation id="8820817407110198400">Zakładki</translation>
@@ -663,13 +702,11 @@ Psst! Następnym razem możesz użyć trybu incognito <ph name="SHORTCUT_KEY" />
<translation id="8971063699422889582">Ważność certyfikatu serwera wygasła.</translation>
<translation id="8987927404178983737">MiesiÄ…c</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Certyfikat przesÅ‚any przez serwer nie zostaÅ‚ publicznie ujawniony przez protokĂ³Å‚ Certificate Transparency. Jest to wymagane w przypadku niektĂ³rych certyfikatĂ³w jako potwierdzenie, że sÄ… one zaufane i zabezpieczone przed atakami.</translation>
<translation id="9001074447101275817">Serwer proxy <ph name="DOMAIN" /> wymaga nazwy użytkownika i hasła.</translation>
<translation id="901974403500617787">Flagi stosowane w całym systemie może ustawić tylko właściciel: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Ta strona została przetłumaczona na <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="9038649477754266430">Użyj usługi podpowiedzi, by strony ładowały się szybciej</translation>
<translation id="9039213469156557790">Ta strona zawiera także niezabezpieczone zasoby. Podczas przesyÅ‚ania mogÄ… je wyÅ›wietlić inni użytkownicy, a osoby atakujÄ…ce mogÄ… je zmodyfikować, by zmienić sposĂ³b dziaÅ‚ania strony.</translation>
-<translation id="9049981332609050619">PodjÄ™to prĂ³bÄ™ nawiÄ…zania poÅ‚Ä…czenia z witrynÄ… <ph name="DOMAIN" />, jednak serwer przedstawiÅ‚ nieprawidÅ‚owy certyfikat.</translation>
<translation id="9050666287014529139">Hasło</translation>
<translation id="9065203028668620118">Edycja</translation>
<translation id="9092364396508701805">Strona <ph name="HOST_NAME" /> nie działa</translation>
diff --git a/chromium/components/strings/components_strings_pt-BR.xtb b/chromium/components/strings/components_strings_pt-BR.xtb
index fe58b17c9e1..9ce1d6f3922 100644
--- a/chromium/components/strings/components_strings_pt-BR.xtb
+++ b/chromium/components/strings/components_strings_pt-BR.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pt-BR">
+<translation id="1008557486741366299">NĂ£o agora</translation>
<translation id="1015730422737071372">Forneça detalhes adicionais</translation>
<translation id="1032854598605920125">Girar no sentido horĂ¡rio</translation>
<translation id="1038842779957582377">nome desconhecido</translation>
+<translation id="1053591932240354961">NĂ£o Ă© possĂ­vel visitar <ph name="SITE" /> no momento, porque o website enviou credenciais codificadas que o Google Chrome nĂ£o consegue processar. Ataques e erros de rede costumam ser temporĂ¡rios. Portanto, essa pĂ¡gina deve voltar a funcionar mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Desfazer adicionar</translation>
<translation id="10614374240317010">Nunca salvam</translation>
-<translation id="1064422015032085147">O servidor que hospeda a pĂ¡gina da Web pode estar sobrecarregado ou em manutenĂ§Ă£o.
- Para evitar a geraĂ§Ă£o de muito trĂ¡fego, o que pode piorar a situaĂ§Ă£o,
- as solicitações para esse URL foram suspensas temporariamente.</translation>
<translation id="106701514854093668">Favoritos em computador</translation>
<translation id="1080116354587839789">Ajustar Ă  largura</translation>
+<translation id="1103124106085518534">ConcluĂ­do por enquanto</translation>
<translation id="1103523840287552314">Sempre traduzir do <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Se esta opĂ§Ă£o for selecionada, o Chrome armazenarĂ¡ uma cĂ³pia do seu cartĂ£o neste dispositivo para preenchimento de formulĂ¡rios mais rapidamente.</translation>
+<translation id="1111153019813902504">Favoritos recentes</translation>
<translation id="1113869188872983271">&amp;Desfazer reordenar</translation>
+<translation id="1126551341858583091">O tamanho no armazenamento local Ă© de <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache da polĂ­tica OK</translation>
<translation id="113188000913989374"><ph name="SITE" /> diz:</translation>
<translation id="1132774398110320017">Configurações de preenchimento automĂ¡tico do Google Chrome...</translation>
-<translation id="1150979032973867961">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança nĂ£o Ă© confiĂ¡vel para o sistema operacional do seu computador. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.</translation>
<translation id="1152921474424827756">Acessar uma <ph name="BEGIN_LINK" />cĂ³pia em cache<ph name="END_LINK" /> de <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> encerrou a conexĂ£o inesperadamente.</translation>
<translation id="1161325031994447685">Conectar-se Ă  rede Wi-Fi novamente</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Remover</translation>
<translation id="1201402288615127009">PrĂ³xima</translation>
<translation id="1201895884277373915">Mais deste site</translation>
-<translation id="121201262018556460">VocĂª tentou acessar <ph name="DOMAIN" />, mas o servidor apresentou um certificado que contĂ©m uma chave fraca. Um invasor pode ter violado a chave privada, e o servidor pode nĂ£o ser o servidor que vocĂª esperava (vocĂª pode estar se comunicando com um invasor).</translation>
+<translation id="1206967143813997005">Assinatura inicial invĂ¡lida</translation>
+<translation id="1209206284964581585">Ocultar por enquanto</translation>
<translation id="1219129156119358924">Sistema de segurança</translation>
<translation id="1227224963052638717">PolĂ­tica desconhecida.</translation>
<translation id="1227633850867390598">Ocultar valor</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Sim</translation>
<translation id="1430915738399379752">Imprimir</translation>
<translation id="1442912890475371290">Tentativa bloqueada de <ph name="BEGIN_LINK" />visitar uma pĂ¡gina em <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">NĂ£o Ă© possĂ­vel visitar <ph name="SITE" /> no momento, porque o website utiliza fixaĂ§Ă£o de certificados. Ataques e erros de rede costumam ser temporĂ¡rios. Portanto, essa pĂ¡gina deve voltar a funcionar mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Mostrar uma cĂ³pia salva (ou seja, reconhecidamente desatualizada) desta pĂ¡gina.</translation>
<translation id="1519264250979466059">Data da versĂ£o</translation>
<translation id="1549470594296187301">O JavaScript deve ser ativado para usar este recurso.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">A configuraĂ§Ă£o de rede Ă© invĂ¡lida e nĂ£o pĂ´de ser importada.</translation>
<translation id="1644574205037202324">HistĂ³rico</translation>
<translation id="1645368109819982629">Protocolo nĂ£o compatĂ­vel</translation>
-<translation id="1655462015569774233">{1,plural, =1{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o certificado de segurança dele expirou ontem. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor. O relĂ³gio do seu computador estĂ¡ definido para <ph name="CURRENT_DATE" />. Essa data estĂ¡ correta? Se nĂ£o estiver, corrija o relĂ³gio do sistema e depois atualize esta pĂ¡gina.}one{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele expirou hĂ¡ # dias. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor. O relĂ³gio do seu computador estĂ¡ definido para <ph name="CURRENT_DATE" />. Essa data estĂ¡ correta? Se nĂ£o estiver, corrija o relĂ³gio do sistema e depois atualize esta pĂ¡gina.}other{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele expirou hĂ¡ # dias. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor. O relĂ³gio do seu computador estĂ¡ definido para <ph name="CURRENT_DATE" />. Essa data estĂ¡ correta? Se nĂ£o estiver, corrija o relĂ³gio do sistema e depois atualize esta pĂ¡gina.}}</translation>
<translation id="1676269943528358898">O site <ph name="SITE" /> geralmente usa criptografia para proteger suas informações. Quando o Google Chrome tentou se conectar a <ph name="SITE" /> dessa vez, o website retornou credenciais incomuns e incorretas. Isso pode acontecer quando um invasor estĂ¡ fingindo ser <ph name="SITE" /> ou quando uma tela de login por Wi-Fi interrompeu a conexĂ£o. Suas informações ainda estĂ£o protegidas, porque o Google Chrome interrompeu a conexĂ£o antes que os dados fossem trocados.</translation>
<translation id="168841957122794586">O certificado do servidor contém uma chave de criptografia fraca.</translation>
<translation id="1701955595840307032">Ver conteĂºdo sugerido</translation>
-<translation id="1706954506755087368">{1,plural, =1{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele estĂ¡ com a data de amanhĂ£. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.}one{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele estĂ¡ com uma data de # dias depois de hoje. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.}other{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele estĂ¡ com uma data de # dias depois de hoje. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.}}</translation>
<translation id="1710259589646384581">SO</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Tente entrar em contato com o administrador do sistema.</translation>
<translation id="17513872634828108">Guias abertas</translation>
<translation id="1753706481035618306">Numero da pĂ¡gina</translation>
-<translation id="1761412452051366565">Para receber conteĂºdo personalizado sugerido pelo Google, ative a sincronizaĂ§Ă£o.</translation>
-<translation id="1763864636252898013">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança nĂ£o Ă© confiĂ¡vel para o sistema operacional do seu dispositivo. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Tente executar o DiagnĂ³stico de Rede do Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Favor atualizar sua senha de sincronizaĂ§Ă£o.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Os favoritos visitados recentemente serĂ£o exibidos aqui.</translation>
<translation id="1821930232296380041">SolicitaĂ§Ă£o ou parĂ¢metros de solicitaĂ§Ă£o invĂ¡lidos</translation>
<translation id="1838667051080421715">VocĂª estĂ¡ vendo o cĂ³digo-fonte de uma pĂ¡gina da Web.</translation>
<translation id="1871208020102129563">O proxy foi configurado para utilizar servidores de proxy fixo e nĂ£o um URL de script .pac.</translation>
<translation id="1883255238294161206">Recolher lista</translation>
<translation id="1898423065542865115">Filtragem</translation>
-<translation id="1911837502049945214">O cetificado de login nĂ£o foi aceito por <ph name="HOST_NAME" /> ou talvez tenha expirado.</translation>
<translation id="194030505837763158">Ir para <ph name="LINK" /></translation>
<translation id="1962204205936693436">Favoritos de <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Erro de serializaĂ§Ă£o</translation>
<translation id="1974060860693918893">Avançado</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{e mais um}one{e mais #}other{e mais #}}</translation>
<translation id="2025186561304664664">O proxy estĂ¡ configurado em configuraĂ§Ă£o automĂ¡tica.</translation>
<translation id="2030481566774242610">VocĂª quis dizer <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Esta mensagem estĂ¡ sendo exibida porque seus pais precisam aprovar novos sites na sua primeira visita.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Verificar o proxy e o firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">CEP</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 sugestĂ£o}one{# sugestĂ£o}other{# sugestões}}</translation>
<translation id="2065985942032347596">AutenticaĂ§Ă£o obrigatĂ³ria</translation>
<translation id="2079545284768500474">Desfazer</translation>
<translation id="20817612488360358">As configurações de proxy do sistema sĂ£o definidas para serem utilizadas, mas uma configuraĂ§Ă£o explĂ­cita de proxy tambĂ©m foi especificada.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Editar favoritos</translation>
<translation id="2166049586286450108">Acesso completo de administrador</translation>
<translation id="2166378884831602661">NĂ£o foi possĂ­vel estabelecer uma conexĂ£o segura com este site</translation>
-<translation id="2171101176734966184">VocĂª tentou acessar <ph name="DOMAIN" />, mas o servidor apresentou um certificado assinado usando um algoritmo de assinatura fraco. Isso significa que as credenciais de segurança apresentadas pelo servidor podem ter sido forjadas, e talvez o servidor nĂ£o seja o esperado (talvez vocĂª esteja se comunicando com um invasor).</translation>
<translation id="2181821976797666341">PolĂ­ticas</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}one{# endereço}other{# endereços}}</translation>
<translation id="2212735316055980242">PolĂ­tica nĂ£o encontrada</translation>
<translation id="2213606439339815911">Buscando entradas...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> nĂ£o estĂ¡ disponĂ­vel</translation>
<translation id="2230458221926704099">Corrija sua conexĂ£o usando o <ph name="BEGIN_LINK" />app de diagnĂ³stico<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Enviar agora</translation>
<translation id="225207911366869382">Este valor estĂ¡ obsoleto para esta polĂ­tica.</translation>
<translation id="2262243747453050782">Erro HTTP</translation>
<translation id="2282872951544483773">ExperiĂªncias nĂ£o disponĂ­veis</translation>
<translation id="2292556288342944218">O seu acesso Ă  Internet estĂ¡ bloqueado</translation>
<translation id="229702904922032456">Um certificado de raiz ou intermediĂ¡rio expirou.</translation>
<translation id="230155334948463882">Novo cartĂ£o?</translation>
+<translation id="2305919008529760154">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. É possĂ­vel que o certificado de segurança dele tenha sido emitido de forma fraudulenta. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> exige um nome de usuĂ¡rio e uma senha.</translation>
+<translation id="2318774815570432836">NĂ£o Ă© possĂ­vel visitar <ph name="SITE" /> no momento, porque o website usa HSTS. Ataques e erros de rede costumam ser temporĂ¡rios. Portanto, essa pĂ¡gina deve voltar a funcionar mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Favorito invĂ¡lido ignorado no Ă­ndice <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Outros favoritos</translation>
<translation id="2359808026110333948">Continuar</translation>
<translation id="2365563543831475020">O relatĂ³rio de erros registrado em <ph name="CRASH_TIME" /> nĂ£o foi enviado</translation>
<translation id="2367567093518048410">NĂ­vel</translation>
+<translation id="2371153335857947666">{1,plural, =1{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele expirou ontem. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. O relĂ³gio do seu computador estĂ¡ definido para <ph name="CURRENT_DATE" />. Essa data estĂ¡ correta? Se nĂ£o estiver, corrija o relĂ³gio do sistema e depois atualize esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}one{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele expirou hĂ¡ # dia. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. O relĂ³gio do seu computador estĂ¡ definido para <ph name="CURRENT_DATE" />. Essa data estĂ¡ correta? Se nĂ£o estiver, corrija o relĂ³gio do sistema e depois atualize esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}other{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele expirou hĂ¡ # dias. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. O relĂ³gio do seu computador estĂ¡ definido para <ph name="CURRENT_DATE" />. Essa data estĂ¡ correta? Se nĂ£o estiver, corrija o relĂ³gio do sistema e depois atualize esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Nenhuma IU alternativa disponĂ­vel</translation>
<translation id="2384307209577226199">PadrĂ£o da empresa</translation>
-<translation id="238526402387145295">NĂ£o Ă© possĂ­vel acessar <ph name="SITE" /> no momento, porque o website <ph name="BEGIN_LINK" />usa HSTS<ph name="END_LINK" />. Ataques e erros de rede geralmente sĂ£o temporĂ¡rios. Portanto, essa pĂ¡gina deve funcionar mais tarde.</translation>
<translation id="2386255080630008482">O certificado do servidor foi revogado.</translation>
<translation id="2392959068659972793">Mostrar polĂ­ticas sem valor definido</translation>
<translation id="2396249848217231973">&amp;Desfazer exclusĂ£o</translation>
-<translation id="2413528052993050574">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança pode ter sido revogado. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.</translation>
<translation id="2455981314101692989">Esta pĂ¡gina da web desativou o preenchimento automĂ¡tico para este formulĂ¡rio.</translation>
+<translation id="2463739503403862330">Preencher</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Executar o DiagnĂ³stico de Rede<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL de pesquisa invĂ¡lido.</translation>
<translation id="2491120439723279231">O certificado do servidor contém erros.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Enviar</translation>
<translation id="2674170444375937751">Tem certeza de que deseja excluir essas pĂ¡ginas do seu histĂ³rico?</translation>
<translation id="2677748264148917807">Sair</translation>
+<translation id="269990154133806163">O servidor apresentou um certificado que nĂ£o foi divulgado publicamente por meio da polĂ­tica de TransparĂªncia dos certificados. Essa Ă© uma exigĂªncia para alguns certificados, a fim de garantir que eles sejam confiĂ¡veis e protejam vocĂª contra invasores. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">O valor nĂ£o corresponde ao formato.</translation>
<translation id="2704951214193499422">NĂ£o foi possĂ­vel confirmar seu cartĂ£o com o Chromium no momento. Tente novamente mais tarde.</translation>
<translation id="2705137772291741111">NĂ£o foi possĂ­vel ler a cĂ³pia armazenada em cache deste site.</translation>
<translation id="2709516037105925701">Preenchimento automĂ¡tico</translation>
+<translation id="2712118517637785082">VocĂª tentou acessar <ph name="DOMAIN" />, mas o certificado que o servidor apresentou foi revogado pelo emissor. Isso significa que as credenciais de segurança que o servidor apresentou nĂ£o sĂ£o nem um pouco seguras. VocĂª pode estar se comunicando com um invasor. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Pedir permissĂ£o</translation>
<translation id="2721148159707890343">SolicitaĂ§Ă£o bem-sucedida</translation>
<translation id="2728127805433021124">O certificado do servidor Ă© assinado com um algoritmo de assinatura fraco.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Barra de endereço e de pesquisa</translation>
<translation id="2826760142808435982">A conexĂ£o foi criptografada e autenticada utilizando <ph name="CIPHER" /> e usa <ph name="KX" /> como o mecanismo de troca de chave.</translation>
<translation id="2835170189407361413">Limpar formulĂ¡rio</translation>
-<translation id="2837049386027881519">Foi necessĂ¡rio fazer uma nova tentativa de conexĂ£o usando uma versĂ£o mais antiga do protocolo TLS ou SSL. Isso normalmente significa que o servidor estĂ¡ usando software muito antigo e pode apresentar outros problemas de segurança.</translation>
<translation id="284702764277384724">O certificado do servidor em <ph name="HOST_NAME" /> parece ser falsificado.</translation>
<translation id="2889159643044928134">NĂ£o atualizar</translation>
-<translation id="2896499918916051536">Este plug-in nĂ£o Ă© compatĂ­vel.</translation>
+<translation id="2900469785430194048">O Google Chrome ficou sem memĂ³ria ao tentar exibir essa pĂ¡gina da Web.</translation>
<translation id="2909946352844186028">Foi detectada uma alteraĂ§Ă£o na rede.</translation>
-<translation id="2915500479781995473">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança do servidor expirou. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor. O relĂ³gio do seu computador estĂ¡ definido para <ph name="CURRENT_TIME" /> no momento. Ele estĂ¡ certo? Caso nĂ£o esteja, corrija o relĂ³gio do seu sistema e depois recarregue esta pĂ¡gina.</translation>
<translation id="2922350208395188000">O certificado do servidor nĂ£o pode ser verificado.</translation>
-<translation id="2941952326391522266">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança Ă© de <ph name="DOMAIN2" />. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.</translation>
<translation id="2948083400971632585">Na pĂ¡gina "Configurações", vocĂª pode desativar quaisquer proxies configurados para uma conexĂ£o.</translation>
<translation id="2955913368246107853">Fechar barra de localizaĂ§Ă£o</translation>
<translation id="2958431318199492670">A configuraĂ§Ă£o de rede nĂ£o estĂ¡ de acordo com o padrĂ£o ONC. Partes da configuraĂ§Ă£o podem nĂ£o ser importadas.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Tipo de polĂ­tica incorreto</translation>
<translation id="3032412215588512954">Deseja atualizar este site?</translation>
<translation id="3037605927509011580">Ah, nĂ£o!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{pelo menos 1 item em dispositivos sincronizados}=1{1 item (e mais em dispositivos sincronizados)}other{# itens (e mais em dispositivos sincronizados)}}</translation>
<translation id="3041612393474885105">Informações do certificado</translation>
<translation id="3063697135517575841">NĂ£o foi possĂ­vel confirmar seu cartĂ£o com o Chrome no momento. Tente novamente mais tarde.</translation>
<translation id="3093245981617870298">VocĂª estĂ¡ off-line.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Mais recente</translation>
<translation id="3207960819495026254">Adicionada aos favoritos</translation>
-<translation id="3225919329040284222">O servidor apresentou um certificado que nĂ£o coincide com as expectativas incorporadas. Estas expectativas sĂ£o incluĂ­das para determinados websites de alta segurança com a finalidade de oferecer proteĂ§Ă£o a vocĂª.</translation>
<translation id="3226128629678568754">Pressione o botĂ£o "Atualizar" para reenviar os dados necessĂ¡rios para carregar a pĂ¡gina.</translation>
<translation id="3228969707346345236">A traduĂ§Ă£o falhou porque a pĂ¡gina jĂ¡ estĂ¡ em <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Digite o CVC do <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Adicionar esta pĂ¡gina aos favoritos</translation>
<translation id="3270847123878663523">&amp;Desfazer reordenar</translation>
<translation id="3286538390144397061">Reiniciar agora</translation>
+<translation id="3303855915957856445">Nenhum resultado de pesquisa encontrado</translation>
<translation id="3305707030755673451">Seus dados foram criptografados com sua senha longa de sincronizaĂ§Ă£o no dia <ph name="TIME" />. Informe-a para começar a sincronizaĂ§Ă£o.</translation>
<translation id="333371639341676808">Impedir que esta pĂ¡gina crie caixas de diĂ¡logo adicionais.</translation>
+<translation id="3338095232262050444">Seguro</translation>
<translation id="3340978935015468852">configurações</translation>
<translation id="3345135638360864351">NĂ£o foi possĂ­vel enviar sua solicitaĂ§Ă£o a <ph name="NAME" /> para acessar este site. Tente novamente.</translation>
<translation id="3355823806454867987">Alterar configurações de proxy...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Buscar intervalo:</translation>
<translation id="3462200631372590220">Ocultar detalhes</translation>
<translation id="3479539252931486093">Isso foi inesperado? <ph name="BEGIN_LINK" />Informe-nos<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">NĂ£o agora</translation>
<translation id="348000606199325318">CĂ³digo de falha <ph name="CRASH_LOCAL_ID" /> (cĂ³digo do servidor: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">NĂ£o foi possĂ­vel contatar seu pai/mĂ£e no momento. Tente novamente.</translation>
<translation id="3527085408025491307">Pasta</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Usar senha para:</translation>
<translation id="3549644494707163724">Criptografar todos os dados sincronizados com sua senha de sincronizaĂ§Ă£o</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> mais...</translation>
+<translation id="3555561725129903880">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele Ă© de <ph name="DOMAIN2" />. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Sua conexĂ£o nĂ£o Ă© particular</translation>
<translation id="3583757800736429874">&amp;Refazer mover</translation>
<translation id="3586931643579894722">Ocultar detalhes</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Mostrar valor</translation>
<translation id="3630155396527302611">Se ele jĂ¡ estiver listado como um programa que tem permissĂ£o para acessar a rede, tente
removĂª-lo da lista e adicionĂ¡-lo novamente.</translation>
+<translation id="3638794133396384728">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele expirou. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. O relĂ³gio do seu computador estĂ¡ definido para <ph name="CURRENT_TIME" /> no momento. Ele estĂ¡ certo? Se nĂ£o estiver, corrija o relĂ³gio do seu sistema e atualize esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Estes recursos experimentais podem ser alterados, cancelados ou desaparecer a qualquer momento. NĂ£o oferecemos qualquer garantia sobre o que possa acontecer ao ativar algum desses experimentos: seu navegador pode inclusive entrar em combustĂ£o espontĂ¢nea. Brincadeiras Ă  parte, o navegador pode excluir todos seus dados ou comprometer sua segurança e privacidade de maneira inesperada. Experimentos ativados serĂ£o habilitados para todos os usuĂ¡rios do navegador, portanto tenha cautela ao prosseguir.</translation>
<translation id="3650584904733503804">ValidaĂ§Ă£o bem-sucedida</translation>
<translation id="3655670868607891010">Caso veja esta pĂ¡gina com frequĂªncia, tente <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">RevisĂ£o</translation>
+<translation id="3678029195006412963">NĂ£o foi possĂ­vel assinar a solicitaĂ§Ă£o</translation>
<translation id="3681007416295224113">Informações do certificado</translation>
<translation id="3693415264595406141">Senha:</translation>
+<translation id="3696411085566228381">nenhum</translation>
<translation id="3700528541715530410">Parece que vocĂª nĂ£o tem permissĂ£o para acessar esta pĂ¡gina.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Carregando...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Ativar os dados da rede celular ou o Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Verificar a configuraĂ§Ă£o de DNS, proxy e firewall<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Link que vocĂª copiou</translation>
-<translation id="3744899669254331632">VocĂª nĂ£o pode visitar <ph name="SITE" /> agora porque o website enviou credenciais embaralhadas que o Chromium nĂ£o consegue processar. Erros de rede e ataques sĂ£o geralmente temporĂ¡rios, de modo que esta pĂ¡gina provavelmente funcionarĂ¡ mais tarde.</translation>
<translation id="375403751935624634">A traduĂ§Ă£o falhou devido a um erro no servidor.</translation>
<translation id="3759461132968374835">VocĂª nĂ£o relatou falhas recentemente. As falhas que ocorreram quando o relatĂ³rio de erros estava desativado nĂ£o aparecerĂ£o aqui.</translation>
<translation id="3788090790273268753">O certificado deste site expira em 2016. A cadeia de certificados contém um certificado assinado com SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Identificador de dispositivo em conflito</translation>
<translation id="3885155851504623709">ParĂ³quia</translation>
<translation id="3901925938762663762">O cartĂ£o expirou</translation>
+<translation id="3910267023907260648">VocĂª tentou acessar <ph name="DOMAIN" />, mas o servidor apresentou um certificado assinado por meio de um algoritmo de assinatura fraco. Isso significa que as credenciais de segurança apresentadas pelo servidor podem ter sido forjadas, e talvez o servidor nĂ£o seja o esperado (vocĂª pode estar se comunicando com um invasor). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele estĂ¡ com a data de amanhĂ£. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}one{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele estĂ¡ com uma data de # dia depois de hoje. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}other{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele estĂ¡ com uma data de # dias depois de hoje. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Falha ao carregar o documento PDF</translation>
<translation id="3963721102035795474">Modo leitor</translation>
+<translation id="397105322502079400">Calculando...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> estĂ¡ bloqueado</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 pĂ¡gina da Web por perto}one{# pĂ¡gina da Web por perto}other{# pĂ¡ginas da Web por perto}}</translation>
<translation id="4021036232240155012">O DNS Ă© o serviço de rede que converte o nome de um website para o prĂ³prio endereço de Internet.</translation>
<translation id="4030383055268325496">&amp;Desfazer adicionar</translation>
-<translation id="4032534284272647190">O acesso a <ph name="URL" /> foi negado.</translation>
<translation id="404928562651467259">AVISO</translation>
<translation id="4058922952496707368">Chave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">O cliente e o servidor nĂ£o sĂ£o compatĂ­veis com uma versĂ£o do protocolo SSL comum ou com o pacote de criptografia.</translation>
<translation id="4079302484614802869">A configuraĂ§Ă£o do proxy definida utiliza um URL de script .pac, e nĂ£o servidores proxy fixos.</translation>
<translation id="4103249731201008433">O nĂºmero de sĂ©rie do dispositivo Ă© invĂ¡lido</translation>
<translation id="4103763322291513355">Visite &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver a lista de URLs adicionados Ă  lista negra e outras polĂ­ticas aplicadas pelo administrador do seu sistema.</translation>
+<translation id="4110615724604346410">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele contĂ©m erros. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">O escopo da polĂ­tica nĂ£o Ă© suportado.</translation>
+<translation id="4118212371799607889">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele nĂ£o Ă© confiĂ¡vel para o Chromium. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{mais 1}one{mais #}other{mais #}}</translation>
<translation id="4130226655945681476">Verificar os cabos de rede, modem e roteador</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Deseja que o Chromium salve este cartĂ£o?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Desativado</translation>
<translation id="4196861286325780578">&amp;Refazer mover</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Verificar as configurações do antivírus e firewall<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{nenhum}=1{1 app ($1)}=2{2 apps ($1, $2)}other{# apps ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Falhas</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Tente executar o DiagnĂ³stico de Rede<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">NĂ£o</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">Sem nome de usuĂ¡rio</translation>
<translation id="4300246636397505754">Sugestões para pais</translation>
<translation id="4304224509867189079">Fazer login</translation>
+<translation id="432290197980158659">O servidor apresentou um certificado que nĂ£o corresponde Ă s expectativas incorporadas. Essas expectativas sĂ£o incluĂ­das para determinados websites de alta segurança para proteger vocĂª. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Falha ao encontrar artigo</translation>
+<translation id="4331708818696583467">NĂ£o seguro</translation>
<translation id="4372948949327679948">Valor <ph name="VALUE_TYPE" /> esperado.</translation>
-<translation id="4377125064752653719">VocĂª tentou acessar <ph name="DOMAIN" />, mas o certificado que o servidor apresentou foi revogado pelo seu emissor. Isso significa que as credenciais de segurança que o servidor apresentou nĂ£o sĂ£o nem um pouco seguras. Talvez vocĂª esteja se comunicando com um invasor.</translation>
<translation id="4381091992796011497">Nome de usuĂ¡rio:</translation>
<translation id="4394049700291259645">Desativar</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> a <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">resultados da pesquisa</translation>
-<translation id="4424024547088906515">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança nĂ£o Ă© confiĂ¡vel para o Chrome. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.</translation>
+<translation id="4432688616882109544">O certificado de login nĂ£o foi aceito por <ph name="HOST_NAME" /> ou nĂ£o foi fornecido.</translation>
<translation id="443673843213245140">O uso de um proxy estĂ¡ desativado, mas uma configuraĂ§Ă£o explĂ­cita de proxy Ă© especificada.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Esta mensagem estĂ¡ sendo exibida porque o Google SafeSites estĂ¡ ativado.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Detalhes</translation>
<translation id="4558551763791394412">Tente desativar suas extensões.</translation>
<translation id="4587425331216688090">Remover endereço do Chrome?</translation>
+<translation id="4589078953350245614">VocĂª tentou acessar <ph name="DOMAIN" />, mas o servidor apresentou um certificado invĂ¡lido. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Sua conexĂ£o com <ph name="DOMAIN" /> foi criptografada usando um pacote de criptografia moderno.</translation>
<translation id="4594403342090139922">&amp;Desfazer exclusĂ£o</translation>
+<translation id="4627442949885028695">Continuar de outro dispositivo</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">VocĂª estĂ¡ vendo uma pĂ¡gina de extensões.</translation>
-<translation id="467662567472608290">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança contĂ©m erros. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> foi bloqueado</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">A conexĂ£o foi interrompida</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Executar o DiagnĂ³stico de Rede do Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Plataforma</translation>
<translation id="4744603770635761495">Caminho do executĂ¡vel</translation>
<translation id="4756388243121344051">&amp;HistĂ³rico</translation>
+<translation id="4759238208242260848">Downloads</translation>
<translation id="4764776831041365478">A pĂ¡gina da web em <ph name="URL" /> pode estar temporariamente indisponĂ­vel ou pode ter sido movida permanentemente para um novo endereço da web.</translation>
<translation id="4771973620359291008">Ocorreu um erro desconhecido.</translation>
<translation id="4782449893814226250">VocĂª perguntou a seus pais se podia visitar esta pĂ¡gina.</translation>
<translation id="4800132727771399293">Verifique sua data de validade e seu CVC e tente novamente</translation>
-<translation id="4807049035289105102">NĂ£o Ă© possĂ­vel acessar <ph name="SITE" /> no momento, porque o website enviou credenciais codificadas que o Google Chrome nĂ£o pode processar. Ataques e erros de rede geralmente sĂ£o temporĂ¡rios. Portanto, essa pĂ¡gina provavelmente funcionarĂ¡ mais tarde.</translation>
<translation id="4813512666221746211">Erro na rede</translation>
<translation id="4816492930507672669">Ajustar Ă  pĂ¡gina</translation>
<translation id="4850886885716139402">Visualizar</translation>
<translation id="4880827082731008257">HistĂ³rico de pesquisa</translation>
+<translation id="4884656795097055129">Mais artigos serĂ£o exibidos quando for a hora certa.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{e mais 1 pĂ¡gina da Web}one{e mais # pĂ¡gina da Web}other{e mais # pĂ¡ginas da Web}}</translation>
<translation id="4923417429809017348">Esta pĂ¡gina foi traduzida de um idioma desconhecido para o <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Deve ser especificado.</translation>
<translation id="4930497775425430760">Esta mensagem estĂ¡ sendo exibida porque seu pai/mĂ£e precisa aprovar novos sites na sua primeira visita.</translation>
<translation id="495170559598752135">Ações</translation>
<translation id="4958444002117714549">Expandir lista</translation>
+<translation id="4962322354953122629">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele nĂ£o Ă© confiĂ¡vel para o Chrome. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Traduzir de <ph name="ORIGINAL_LANGUAGE" /> para <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Este plug-in nĂ£o Ă© compatĂ­vel</translation>
<translation id="5002932099480077015">Se ativado, o Chrome armazenarĂ¡ uma cĂ³pia do seu cartĂ£o neste dispositivo para preencher formulĂ¡rios mais rapidamente.</translation>
<translation id="5019198164206649151">Armazenamento de backup em estado invĂ¡lido</translation>
<translation id="5023310440958281426">Verifique as polĂ­ticas do administrador</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Sobre o Google Tradutor</translation>
<translation id="5040262127954254034">Privacidade</translation>
<translation id="5045550434625856497">Senha incorreta</translation>
+<translation id="5056549851600133418">Artigos para vocĂª</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Verificar o endereço do proxy<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">O certificado do servidor nĂ£o Ă© vĂ¡lido no momento.</translation>
<translation id="5089810972385038852">Estado</translation>
-<translation id="5094747076828555589">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança nĂ£o Ă© confiĂ¡vel para o Chromium. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.</translation>
<translation id="5095208057601539847">ProvĂ­ncia</translation>
<translation id="5115563688576182185">64 bits</translation>
-<translation id="5122371513570456792">Localizados <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para '<ph name="SEARCH_STRING" />'.</translation>
<translation id="5141240743006678641">Criptografar senhas sincronizadas com suas credenciais do Google</translation>
<translation id="5145883236150621069">CĂ³digo de erro presente na resposta da polĂ­tica</translation>
<translation id="5171045022955879922">Pesquisar ou digitar URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Barra de favoritos</translation>
<translation id="5199729219167945352">Experimentos</translation>
<translation id="5251803541071282808">Nuvem</translation>
+<translation id="5277279256032773186">VocĂª usa o Chrome no trabalho? As empresas podem gerenciar as configurações do Chrome para seus funcionĂ¡rios. Saiba mais</translation>
<translation id="5299298092464848405">PolĂ­tica de anĂ¡lise de erros</translation>
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5308689395849655368">O relatĂ³rio de erros estĂ¡ desativado.</translation>
<translation id="5317780077021120954">Salvar</translation>
<translation id="5327248766486351172">Nome</translation>
+<translation id="5359637492792381994">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele nĂ£o Ă© vĂ¡lido no momento. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Falha ao armazenar as configurações da política</translation>
-<translation id="540969355065856584">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele nĂ£o Ă© vĂ¡lido no momento. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.</translation>
<translation id="5421136146218899937">Limpar dados de navegaĂ§Ă£o...</translation>
<translation id="5430298929874300616">Remover favorito</translation>
<translation id="5431657950005405462">O arquivo nĂ£o foi encontrado</translation>
<translation id="5435775191620395718">Exibindo histĂ³rico deste dispositivo. <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">As sugestões personalizadas de conteĂºdo estĂ£o desativadas no momento, pois seus dados sincronizados estĂ£o protegidos com uma senha personalizada.</translation>
<translation id="5439770059721715174">Erro de validaĂ§Ă£o de esquema em "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">NĂ£o foi possĂ­vel encontrar a pĂ¡gina deste <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">Carimbo de data e hora da polĂ­tica invĂ¡lido</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Deseja sair deste site?</translation>
<translation id="5629630648637658800">Falha ao carregar as configurações da política</translation>
<translation id="5631439013527180824">Token de gerenciamento de dispositivo invĂ¡lido</translation>
-<translation id="5650551054760837876">Nenhum resultado de pesquisa encontrado.</translation>
<translation id="5677928146339483299">Bloqueados</translation>
<translation id="5710435578057952990">A identidade deste site nĂ£o foi confirmada.</translation>
<translation id="5720705177508910913">UsuĂ¡rio atual</translation>
+<translation id="572328651809341494">Guias recentes</translation>
<translation id="5784606427469807560">Ocorreu um problema ao confirmar seu cartĂ£o. Verifique a conexĂ£o com a Internet e tente novamente.</translation>
<translation id="5785756445106461925">AlĂ©m disso, esta pĂ¡gina inclui outros recursos que nĂ£o sĂ£o seguros. Esses recursos podem ser visualizados por outros usuĂ¡rios enquanto eles navegam e podem ser modificados por um invasor para alterar o comportamento da pĂ¡gina.</translation>
+<translation id="5786044859038896871">Deseja preencher as informações do cartĂ£o?</translation>
+<translation id="5803412860119678065">Deseja preencher as informações do seu cartĂ£o <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Sua conexĂ£o com <ph name="DOMAIN" /> estĂ¡ criptografada com um pacote de criptografia obsoleto.</translation>
<translation id="5813119285467412249">&amp;Refazer adicionar</translation>
+<translation id="5814352347845180253">É possĂ­vel que vocĂª perca o acesso a conteĂºdos premier de <ph name="SITE" /> e alguns outros sites.</translation>
+<translation id="5843436854350372569">VocĂª tentou acessar <ph name="DOMAIN" />, mas o servidor apresentou um certificado que contĂ©m uma chave fraca. É possĂ­vel que um invasor tenha violado a chave particular, e talvez o servidor nĂ£o seja o esperado (vocĂª pode estar se comunicando com um invasor). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Esta mensagem estĂ¡ sendo exibida porque seu gerente bloqueou este site.</translation>
<translation id="5857090052475505287">Nova pasta</translation>
<translation id="5869405914158311789">NĂ£o Ă© possĂ­vel acessar esse site</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Sugestões para pais</translation>
<translation id="59107663811261420">Este tipo de cartĂ£o nĂ£o Ă© aceito pelo Google Payments para este comerciante. Selecione outro cartĂ£o.</translation>
<translation id="59174027418879706">Ativada</translation>
+<translation id="5926846154125914413">É possĂ­vel que vocĂª perca o acesso a conteĂºdos premier de alguns sites.</translation>
<translation id="5966707198760109579">Semana</translation>
<translation id="5967867314010545767">Remover do histĂ³rico</translation>
<translation id="5975083100439434680">Diminuir zoom</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">AutomĂ¡tico</translation>
<translation id="6042308850641462728">Mais</translation>
<translation id="6060685159320643512">Tome cuidado, esses experimentos podem morder</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{nenhum}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Verifique todos os cabos e reinicie todos os roteadores, modens ou outros
dispositivos de rede que vocĂª estiver usando.</translation>
<translation id="614940544461990577">Tente:</translation>
<translation id="6150607114729249911">Ops! É preciso permissĂ£o dos seus pais para visitar esta pĂ¡gina.</translation>
<translation id="6151417162996330722">O certificado do servidor tem um perĂ­odo de validade excessivamente longo.</translation>
-<translation id="6154808779448689242">O token da polĂ­tica retornado nĂ£o corresponde ao token atual</translation>
<translation id="6165508094623778733">Saiba mais</translation>
<translation id="6203231073485539293">Verifique sua conexĂ£o com a Internet</translation>
<translation id="6218753634732582820">Remover endereço do Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Tente desativar a previsĂ£o de rede</translation>
<translation id="6337534724793800597">Filtrar polĂ­ticas por nome</translation>
<translation id="6342069812937806050">Neste instante</translation>
+<translation id="6345221851280129312">tamanho desconhecido</translation>
<translation id="6355080345576803305">ModificaĂ§Ă£o de sessĂ£o pĂºblica</translation>
<translation id="6358450015545214790">O que sĂ£o essas informações?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 outra sugestĂ£o}one{# outra sugestĂ£o}other{# outras sugestões}}</translation>
<translation id="6387478394221739770">Interessado em novos recursos interessantes do Google Chrome? Veja nosso Canal Beta em chrome.com/beta.</translation>
-<translation id="641480858134062906">Falha ao carregar <ph name="URL" /></translation>
+<translation id="6389758589412724634">O Chromium ficou sem memĂ³ria ao tentar exibir essa pĂ¡gina da Web.</translation>
+<translation id="6416403317709441254">NĂ£o Ă© possĂ­vel visitar <ph name="SITE" /> no momento porque o website enviou credenciais codificadas que o Chromium nĂ£o consegue processar. Ataques e erros de rede costumam ser temporĂ¡rios. Portanto, esta pĂ¡gina deve voltar a funcionar mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">NĂ£o foi possĂ­vel verificar se o certificado foi revogado</translation>
<translation id="6433595998831338502">A conexĂ£o com <ph name="HOST_NAME" /> foi recusada.</translation>
<translation id="6445051938772793705">PaĂ­s</translation>
<translation id="6451458296329894277">Confirmar reenvio do formulĂ¡rio</translation>
<translation id="6458467102616083041">Ignorado porque a pesquisa padrĂ£o foi desativada por uma polĂ­tica.</translation>
+<translation id="6462969404041126431">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele pode ter sido revogado. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">PolĂ­ticas de dispositivos</translation>
<translation id="6489534406876378309">Iniciar upload de falhas</translation>
<translation id="6529602333819889595">&amp;Refazer excluir</translation>
+<translation id="6534179046333460208">Sugestões da Web física</translation>
<translation id="6550675742724504774">Opções</translation>
+<translation id="6593753688552673085">menos que <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opções de criptografia</translation>
<translation id="662080504995468778">Ficar</translation>
<translation id="6628463337424475685">Pesquisa do <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">NĂ£o Ă© possĂ­vel acessar <ph name="SITE" /> no momento, porque <ph name="BEGIN_LINK" />este certificado foi revogado<ph name="END_LINK" />. Ataques e erros de rede geralmente sĂ£o temporĂ¡rios. Portanto, essa pĂ¡gina provavelmente funcionarĂ¡ mais tarde.</translation>
<translation id="6644283850729428850">Esta polĂ­tica foi encerrada.</translation>
+<translation id="6652240803263749613">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele nĂ£o Ă© confiĂ¡vel para o sistema operacional do seu computador. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Editar pasta</translation>
<translation id="6660210980321319655">Denunciada automaticamente Ă s <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Remover sugestĂ£o de formulĂ¡rio do Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Digitar termo de pesquisa&gt;</translation>
<translation id="6711464428925977395">HĂ¡ algo errado com o servidor proxy, ou o endereço estĂ¡ incorreto.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{nenhum}=1{1 item}other{# itens}}</translation>
<translation id="674375294223700098">Erro, certificado de servidor desconhecido.</translation>
<translation id="6753269504797312559">Valor da polĂ­tica</translation>
<translation id="6757797048963528358">O dispositivo entrou em modo de suspensĂ£o.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">O nĂ­vel da polĂ­tica nĂ£o Ă© suportado.</translation>
<translation id="6895330447102777224">Seu cartĂ£o foi confirmado</translation>
<translation id="6897140037006041989">Agente do usuĂ¡rio</translation>
-<translation id="6903907808598579934">Ativar a sincronizaĂ§Ă£o</translation>
<translation id="6915804003454593391">UsuĂ¡rio:</translation>
<translation id="6957887021205513506">O certificado do servidor parece ser falsificado.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Distrito</translation>
<translation id="6973656660372572881">Ambos os servidores proxy fixo e um URL de script .pac foram especificados.</translation>
<translation id="6989763994942163495">Mostrar configurações avançadas...</translation>
+<translation id="7000990526846637657">Nenhum entrada de histĂ³rico encontrada</translation>
+<translation id="7009986207543992532">VocĂª tentou acessar <ph name="DOMAIN" />, mas o servidor apresentou um certificado cujo perĂ­odo de validade Ă© longo demais para ser confiĂ¡vel. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Sua Conta do Google pode ter outras formas de histĂ³rico de navegaĂ§Ă£o em <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Senhas</translation>
-<translation id="7050187094878475250">VocĂª tentou acessar <ph name="DOMAIN" />, mas o servidor apresentou um certificado cujo perĂ­odo de validade Ă© extremamente longo, o que nĂ£o Ă© confiĂ¡vel.</translation>
<translation id="7087282848513945231">Condado</translation>
<translation id="7088615885725309056">Mais antigo</translation>
<translation id="7090678807593890770">Pesquise <ph name="LINK" /> no Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Esta mensagem estĂ¡ sendo exibida porque Ă© preciso aprovaĂ§Ă£o do seu gerente para novos sites na sua primeira visita.</translation>
<translation id="724975217298816891">Digite a data de validade e o CVC do <ph name="CREDIT_CARD" /> para atualizar os detalhes do cartĂ£o. Depois da confirmaĂ§Ă£o, os detalhes do cartĂ£o serĂ£o compartilhados com esse site.</translation>
<translation id="725866823122871198">NĂ£o Ă© possĂ­vel estabelecer uma conexĂ£o privada com <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, porque a data e a hora do seu computador (<ph name="DATE_AND_TIME" />) estĂ£o incorretas.</translation>
-<translation id="7265986070661382626">NĂ£o Ă© possĂ­vel acessar <ph name="SITE" /> no momento porque o website <ph name="BEGIN_LINK" />usa a fixaĂ§Ă£o de certificados<ph name="END_LINK" />. Ataques e erros de rede, muitas vezes, sĂ£o temporĂ¡rios. Portanto, essa pĂ¡gina provavelmente funcionarĂ¡ mais tarde.</translation>
<translation id="7269802741830436641">Esta pĂ¡gina da web tem um loop de redirecionamento</translation>
<translation id="7275334191706090484">Favoritos gerenciados</translation>
<translation id="7298195798382681320">Recomendada</translation>
-<translation id="7301833672208172928">Ativar a sincronizaĂ§Ă£o de histĂ³ricos</translation>
+<translation id="7309308571273880165">RelatĂ³rio de erros capturado em <ph name="CRASH_TIME" /> (upload solicitado pelo usuĂ¡rio, upload ainda nĂ£o realizado)</translation>
<translation id="7334320624316649418">&amp;Refazer reordenar</translation>
<translation id="733923710415886693">O certificado do servidor nĂ£o foi divulgado por meio da TransparĂªncia dos certificados.</translation>
+<translation id="7351800657706554155">NĂ£o Ă© possĂ­vel visitar <ph name="SITE" /> no momento, porque o certificado desse site foi revogado. Ataques e erros de rede costumam ser temporĂ¡rios. Portanto, esta pĂ¡gina deve voltar a funcionar mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Linha de comando</translation>
<translation id="7372973238305370288">resultado da pesquisa</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Dica: o modo de navegaĂ§Ă£o anĂ´nimo <ph name="SHORTCUT_KEY" /> pode ser Ăºtil d
<translation id="7469372306589899959">Confirmando cartĂ£o</translation>
<translation id="7481312909269577407">Avançar</translation>
<translation id="7485870689360869515">Nenhum dado encontrado</translation>
+<translation id="7508255263130623398">O cĂ³digo do dispositivo da polĂ­tica retornado estĂ¡ em branco ou nĂ£o corresponde ao cĂ³digo do dispositivo atual</translation>
<translation id="7514365320538308">Fazer o download</translation>
<translation id="7518003948725431193">Nenhuma pĂ¡gina da web foi encontrada para o endereço da web:<ph name="URL" /></translation>
<translation id="7537536606612762813">ObrigatĂ³ria</translation>
<translation id="7542995811387359312">O preenchimento automĂ¡tico do cartĂ£o de crĂ©dito estĂ¡ desativado porque este formulĂ¡rio nĂ£o usa uma conexĂ£o segura.</translation>
<translation id="7549584377607005141">Esta pĂ¡gina da Web requer os dados inseridos anteriormente para ser exibida de modo correto. É possĂ­vel enviĂ¡-los novamente mas, ao fazer isso, vocĂª repete qualquer aĂ§Ă£o realizada anteriormente na pĂ¡gina.</translation>
<translation id="7554791636758816595">Nova guia</translation>
-<translation id="7567204685887185387">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança pode ter sido emitido de forma fraudulenta. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou pela interceptaĂ§Ă£o da sua conexĂ£o por um invasor.</translation>
<translation id="7568593326407688803">Esta pĂ¡gina estĂ¡ em<ph name="ORIGINAL_LANGUAGE" />Deseja traduzi-la?</translation>
<translation id="7569952961197462199">Remover cartĂ£o de crĂ©dito do Chrome?</translation>
<translation id="7578104083680115302">Pague rapidamente em sites e aplicativos em vĂ¡rios dispositivos usando os cards que vocĂª salvou com o Google.</translation>
+<translation id="7588950540487816470">Web fĂ­sica</translation>
<translation id="7592362899630581445">O certificado do servidor viola as restrições de nome.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> nĂ£o consegue atender a esta solicitaĂ§Ă£o no momento.</translation>
<translation id="7600965453749440009">Nunca traduzir do <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Dica: o modo de navegaĂ§Ă£o anĂ´nimo <ph name="SHORTCUT_KEY" /> pode ser Ăºtil d
<translation id="7637571805876720304">Remover cartĂ£o de crĂ©dito do Chromium?</translation>
<translation id="765676359832457558">Ocultar configurações avançadas...</translation>
<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7667346355482952095">O token da polĂ­tica retornado estĂ¡ vazio ou nĂ£o corresponde ao token atual</translation>
<translation id="7668654391829183341">Dispositivo desconhecido</translation>
<translation id="7674629440242451245">Interessado em novos recursos interessantes do Google Chrome? Veja nosso Canal Dev em chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Ir para <ph name="SITE" /> (nĂ£o seguro)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Dica: o modo de navegaĂ§Ă£o anĂ´nimo <ph name="SHORTCUT_KEY" /> pode ser Ăºtil d
<translation id="780301667611848630">NĂ£o</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7813600968533626083">Remover sugestĂ£o de formulĂ¡rio do Chrome?</translation>
+<translation id="7815407501681723534">Localizados <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
<translation id="785549533363645510">O modo invisĂ­vel NĂƒO oculta seus dados de navegaĂ§Ă£o. Seu empregador, seu provedor de Internet e os websites visitados continuam tendo acesso a essas informações.</translation>
<translation id="7887683347370398519">Verifique seu CVC e tente novamente</translation>
<translation id="7894616681410591072">Ops! É preciso permissĂ£o de <ph name="NAME" /> para acessar esta pĂ¡gina.</translation>
-<translation id="790025292736025802"><ph name="URL" /> nĂ£o encontrado</translation>
<translation id="7912024687060120840">Na pasta:</translation>
<translation id="7920092496846849526">VocĂª pediu aos seus pais se podia visitar esta pĂ¡gina.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ Dica: o modo de navegaĂ§Ă£o anĂ´nimo <ph name="SHORTCUT_KEY" /> pode ser Ăºtil d
<translation id="7995512525968007366">NĂ£o especificado</translation>
<translation id="8012647001091218357">NĂ£o foi possĂ­vel contatar seus pais. Tente novamente.</translation>
<translation id="8034522405403831421">Esta pĂ¡gina estĂ¡ escrita em <ph name="SOURCE_LANGUAGE" />. Traduzi-la para <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Nenhum entrada de histĂ³rico encontrada.</translation>
<translation id="8088680233425245692">Falha ao exibir artigo.</translation>
+<translation id="8089520772729574115">menos de 1 MB</translation>
<translation id="8091372947890762290">A ativaĂ§Ă£o estĂ¡ pendente no servidor</translation>
+<translation id="8129262335948759431">quantidade desconhecida</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">NĂ£o foi possĂ­vel encontrar o <ph name="BEGIN_ABBR" />endereço DNS<ph name="END_ABBR" /> do servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Seu computador entrou em modo de suspensĂ£o.</translation>
@@ -604,6 +640,7 @@ Dica: o modo de navegaĂ§Ă£o anĂ´nimo <ph name="SHORTCUT_KEY" /> pode ser Ăºtil d
<translation id="8201077131113104583">URL de atualizaĂ§Ă£o invĂ¡lido para extensĂ£o com ID "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Local designado:</translation>
<translation id="8225771182978767009">A pessoa que configurou este computador optou por bloquear esse site.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">A pĂ¡gina que vocĂª estĂ¡ procurando usou as informações inseridas. Voltar Ă  essa pĂ¡gina poderĂ¡ fazer com que todas as ações realizadas antes sejam repetidas. Deseja continuar?</translation>
<translation id="8249320324621329438">Ăltima busca:</translation>
<translation id="8261506727792406068">Excluir</translation>
@@ -616,12 +653,17 @@ Dica: o modo de navegaĂ§Ă£o anĂ´nimo <ph name="SHORTCUT_KEY" /> pode ser Ăºtil d
<translation id="8349305172487531364">Barra de favoritos</translation>
<translation id="8363502534493474904">Desativar modo aviĂ£o</translation>
<translation id="8364627913115013041">NĂ£o definida.</translation>
+<translation id="8380941800586852976">Perigoso</translation>
<translation id="8412145213513410671">Falhas (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">VocĂª deve inserir a mesma senha duas vezes.</translation>
<translation id="8428213095426709021">Configurações</translation>
+<translation id="8433057134996913067">Essa opĂ§Ă£o desconecta vocĂª da maioria dos websites.</translation>
<translation id="8437238597147034694">&amp;Desfazer mover</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 cartĂ£o de crĂ©dito}one{# cartĂ£o de crĂ©dito}other{# cartões de crĂ©dito}}</translation>
+<translation id="8483780878231876732">Para usar os cards da sua Conta do Google, faça login no Google Chrome</translation>
<translation id="8488350697529856933">AplicĂ¡vel a</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> demorou muito para responder.</translation>
+<translation id="852346902619691059">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />. O certificado de segurança dele nĂ£o Ă© confiĂ¡vel para o sistema operacional do seu dispositivo. Isso pode ser causado por uma configuraĂ§Ă£o incorreta ou por um invasor que interceptou sua conexĂ£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Este tipo de cartĂ£o nĂ£o Ă© aceito pelo Google Payments. Selecione outro cartĂ£o.</translation>
<translation id="8550022383519221471">O serviço de sincronizaĂ§Ă£o nĂ£o estĂ¡ disponĂ­vel para seu domĂ­nio.</translation>
<translation id="8553075262323480129">A traduĂ§Ă£o falhou porque nĂ£o foi possĂ­vel determinar o idioma da pĂ¡gina.</translation>
@@ -633,15 +675,12 @@ Dica: o modo de navegaĂ§Ă£o anĂ´nimo <ph name="SHORTCUT_KEY" /> pode ser Ăºtil d
<translation id="8647750283161643317">Redefinir tudo para o padrĂ£o</translation>
<translation id="8680787084697685621">Os detalhes de login da conta estĂ£o desatualizados.</translation>
<translation id="8703575177326907206">Sua conexĂ£o com <ph name="DOMAIN" /> nĂ£o estĂ¡ criptografada.</translation>
-<translation id="8713130696108419660">Assinatura inicial invĂ¡lida</translation>
<translation id="8725066075913043281">Tentar novamente</translation>
<translation id="8728672262656704056">VocĂª entrou no modo de navegaĂ§Ă£o anĂ´nima</translation>
<translation id="8730621377337864115">ConcluĂ­do</translation>
<translation id="8738058698779197622">Para estabelecer uma conexĂ£o segura, o relĂ³gio precisa ser ajustado corretamente. Isso ocorre porque os certificados que os websites usam para se identificar sĂ£o vĂ¡lidos apenas por perĂ­odos especĂ­ficos. Como o relĂ³gio do seu dispositivo estĂ¡ incorreto, o Chromium nĂ£o pode verificar esses certificados.</translation>
<translation id="8740359287975076522">NĂ£o foi possĂ­vel encontrar o &lt;abbr id="dnsDefinition"&gt;endereço DNS&lt;/abbr&gt; de <ph name="HOST_NAME" />. Diagnosticando o problema.</translation>
-<translation id="8741995161408053644">Sua Conta do Google pode ter outras formas de histĂ³rico de navegaĂ§Ă£o em <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Refazer excluir</translation>
-<translation id="8790687370365610530">Para ver conteĂºdo personalizado sugerido pelo Google, ative o histĂ³rico de sincronizaĂ§Ă£o.</translation>
<translation id="8798099450830957504">PadrĂ£o</translation>
<translation id="8804164990146287819">PolĂ­tica de Privacidade</translation>
<translation id="8820817407110198400">Favoritos</translation>
@@ -663,13 +702,11 @@ Dica: o modo de navegaĂ§Ă£o anĂ´nimo <ph name="SHORTCUT_KEY" /> pode ser Ăºtil d
<translation id="8971063699422889582">O certificado do servidor expirou.</translation>
<translation id="8987927404178983737">MĂªs</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">O servidor apresentou um certificado que nĂ£o foi divulgado publicamente usando a polĂ­tica de TransparĂªncia dos certificados. Esse Ă© um requisito para alguns certificados, a fim de garantir que eles sejam confiĂ¡veis e protejam vocĂª contra invasores.</translation>
<translation id="9001074447101275817">O proxy <ph name="DOMAIN" /> exige um nome de usuĂ¡rio e uma senha.</translation>
<translation id="901974403500617787">Sinalizações aplicĂ¡veis a todo o sistema podem ser definidas apenas pelo proprietĂ¡rio: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Esta pĂ¡gina foi traduzida para <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Usar um serviço de previsĂ£o para carregar pĂ¡ginas mais rapidamente</translation>
<translation id="9039213469156557790">AlĂ©m disso, esta pĂ¡gina inclui outros recursos que nĂ£o sĂ£o seguros. Esses recursos podem ser visualizados por outros usuĂ¡rios enquanto eles navegam e podem ser modificados por um invasor para alterar o comportamento da pĂ¡gina.</translation>
-<translation id="9049981332609050619">VocĂª tentou acessar <ph name="DOMAIN" />, mas o servidor apresentou um certificado invĂ¡lido.</translation>
<translation id="9050666287014529139">Senha</translation>
<translation id="9065203028668620118">Editar</translation>
<translation id="9092364396508701805">A pĂ¡gina de <ph name="HOST_NAME" /> nĂ£o estĂ¡ funcionando</translation>
diff --git a/chromium/components/strings/components_strings_pt-PT.xtb b/chromium/components/strings/components_strings_pt-PT.xtb
index 2568f756acd..3b00337b469 100644
--- a/chromium/components/strings/components_strings_pt-PT.xtb
+++ b/chromium/components/strings/components_strings_pt-PT.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pt-PT">
+<translation id="1008557486741366299">Agora nĂ£o</translation>
<translation id="1015730422737071372">Forneça mais detalhes</translation>
<translation id="1032854598605920125">Rodar para a direita</translation>
<translation id="1038842779957582377">nome desconhecido</translation>
+<translation id="1053591932240354961">De momento, nĂ£o Ă© possĂ­vel aceder a <ph name="SITE" /> porque o Website enviou credenciais codificadas que o Google Chrome nĂ£o consegue processar. Geralmente, os erros de rede e os ataques sĂ£o temporĂ¡rios, pelo que Ă© provĂ¡vel que esta pĂ¡gina funcione mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Anular adiĂ§Ă£o</translation>
<translation id="10614374240317010">Nunca guardadas</translation>
-<translation id="1064422015032085147">O servidor que aloja a pĂ¡gina Web pode estar sobrecarregado ou em manutenĂ§Ă£o.
- Para evitar gerar demasiado trĂ¡fego e piorar a situaĂ§Ă£o,
- os pedidos a este URL foram temporariamente proibidos.</translation>
<translation id="106701514854093668">Marcadores do Ambiente de Trabalho</translation>
<translation id="1080116354587839789">Ajustar Ă  largura</translation>
+<translation id="1103124106085518534">ConcluĂ­do por agora</translation>
<translation id="1103523840287552314">Traduzir sempre <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Se marcada, o Chrome armazena uma cĂ³pia do seu cartĂ£o neste dispositivo para preencher formulĂ¡rios mais rapidamente.</translation>
+<translation id="1111153019813902504">Marcadores recentes</translation>
<translation id="1113869188872983271">&amp;Anular reordenaĂ§Ă£o</translation>
+<translation id="1126551341858583091">O tamanho no armazenamento local Ă© de <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache da polĂ­tica OK</translation>
<translation id="113188000913989374"><ph name="SITE" /> diz:</translation>
<translation id="1132774398110320017">Definições de Preenchimento automĂ¡tico do Chrome...</translation>
-<translation id="1150979032973867961">Este servidor nĂ£o conseguiu provar que Ă© o domĂ­nio <ph name="DOMAIN" />; o sistema operativo do seu computador nĂ£o confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o.</translation>
<translation id="1152921474424827756">Aceda a uma <ph name="BEGIN_LINK" />cĂ³pia em cache<ph name="END_LINK" /> de <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> fechou a ligaĂ§Ă£o inesperadamente.</translation>
<translation id="1161325031994447685">Ligar novamente Ă  rede Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Remover</translation>
<translation id="1201402288615127009">Seguinte</translation>
<translation id="1201895884277373915">Mais a partir deste Web site</translation>
-<translation id="121201262018556460">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado que contĂ©m uma chave fraca. Um utilizador mal intencionado poderĂ¡ ter quebrado a chave privada e o servidor pode nĂ£o ser o servidor esperado (pode estar a comunicar com um utilizador mal intencionado).</translation>
+<translation id="1206967143813997005">Assinatura com inicial incorreta</translation>
+<translation id="1209206284964581585">Ocultar para jĂ¡</translation>
<translation id="1219129156119358924">Segurança do sistema</translation>
<translation id="1227224963052638717">PolĂ­tica desconhecida.</translation>
<translation id="1227633850867390598">Esconder o valor</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Sim</translation>
<translation id="1430915738399379752">Imprimir</translation>
<translation id="1442912890475371290">Tentativa bloqueada <ph name="BEGIN_LINK" /> de visitar uma pĂ¡gina em <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">De momento, nĂ£o Ă© possĂ­vel aceder a <ph name="SITE" /> porque o Website utiliza a afixaĂ§Ă£o de certificados. Geralmente, os erros de rede e os ataques sĂ£o temporĂ¡rios, pelo que Ă© provĂ¡vel que esta pĂ¡gina funcione mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Mostrar uma cĂ³pia guardada desta pĂ¡gina (isto Ă©, uma cĂ³pia desatualizada).</translation>
<translation id="1519264250979466059">Data da CompilaĂ§Ă£o</translation>
<translation id="1549470594296187301">É necessĂ¡rio ativar o JavaScript para utilizar esta funcionalidade.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">A configuraĂ§Ă£o de rede Ă© invĂ¡lida e nĂ£o pode ser importada.</translation>
<translation id="1644574205037202324">HistĂ³rico</translation>
<translation id="1645368109819982629">Protocolo nĂ£o suportado</translation>
-<translation id="1655462015569774233">{1,plural, =1{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o seu certificado de segurança expirou ontem. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o. O relĂ³gio do seu computador estĂ¡ atualmente configurado para <ph name="CURRENT_DATE" />. SerĂ¡ que isso estĂ¡ correto? Em caso negativo, deve corrigir o relĂ³gio do seu sistema e depois atualizar esta pĂ¡gina.}other{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o seu certificado de segurança expirou hĂ¡ # dias. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o. O relĂ³gio do seu computador estĂ¡ atualmente configurado para <ph name="CURRENT_DATE" />. SerĂ¡ que isso estĂ¡ correto? Em caso negativo, deve corrigir o relĂ³gio do seu sistema e depois atualizar esta pĂ¡gina.}}</translation>
<translation id="1676269943528358898">Normalmente, o site <ph name="SITE" /> utiliza a encriptaĂ§Ă£o para proteger as suas informações. Quando o Google Chrome tentou estabelecer ligaĂ§Ă£o a <ph name="SITE" /> desta vez, o Website devolveu credenciais invulgares e incorretas. Isto pode acontecer quando um utilizador mal intencionado tenta simular ser <ph name="SITE" /> ou quando um ecrĂ£ de inĂ­cio de sessĂ£o Wi-Fi interrompe a ligaĂ§Ă£o. As suas informações continuam seguras porque o Google Chrome interrompeu a ligaĂ§Ă£o antes de qualquer troca de dados.</translation>
<translation id="168841957122794586">O certificado do servidor contĂ©m uma chave criptogrĂ¡fica fraca.</translation>
<translation id="1701955595840307032">Obter conteĂºdo sugerido</translation>
-<translation id="1706954506755087368">{1,plural, =1{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o seu certificado de segurança Ă© supostamente de amanhĂ£. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o.}other{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; a data do seu certificado de segurança Ă© supostamente daqui a # dias. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o.}}</translation>
<translation id="1710259589646384581">SO</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Experimente contactar o administrador do sistema.</translation>
<translation id="17513872634828108">Separadores abertos</translation>
<translation id="1753706481035618306">NĂºmero de pĂ¡gina</translation>
-<translation id="1761412452051366565">Para obter conteĂºdo personalizado sugerido pelo Google, ative a sincronizaĂ§Ă£o.</translation>
-<translation id="1763864636252898013">Este servidor nĂ£o conseguiu provar que Ă© o domĂ­nio <ph name="DOMAIN" />; o sistema operativo do seu dispositivo nĂ£o confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Experimente executar o DiagnĂ³stico de rede do Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Atualize a frase de acesso de sincronizaĂ§Ă£o.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Os seus marcadores visitados recentemente sĂ£o apresentados aqui.</translation>
<translation id="1821930232296380041">Pedido ou parĂ¢metros do pedido invĂ¡lidos</translation>
<translation id="1838667051080421715">EstĂ¡ a ver a fonte de uma pĂ¡gina Web.</translation>
<translation id="1871208020102129563">O proxy estĂ¡ definido para utilizar servidores proxy fixos e nĂ£o um URL de script .pac.</translation>
<translation id="1883255238294161206">Fechar lista</translation>
<translation id="1898423065542865115">Filtragem</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> nĂ£o aceitou o certificado de inĂ­cio de sessĂ£o ou o certificado de inĂ­cio de sessĂ£o pode ter expirado.</translation>
<translation id="194030505837763158">Aceder a <ph name="LINK" /></translation>
<translation id="1962204205936693436">Marcadores de <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Erro de serializaĂ§Ă£o</translation>
<translation id="1974060860693918893">Avançadas</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{e mais 1}other{e mais #}}</translation>
<translation id="2025186561304664664">O proxy estĂ¡ definido para configuraĂ§Ă£o automĂ¡tica.</translation>
<translation id="2030481566774242610">SerĂ¡ que quis dizer <ph name="LINK" />?</translation>
<translation id="2031925387125903299">EstĂ¡s a ver esta mensagem porque os teus pais necessitam de aprovar os sites novos sempre que os visitas pela primeira vez.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Verificar o proxy e a firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">CĂ³digo postal</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 sugestĂ£o}other{# sugestões}}</translation>
<translation id="2065985942032347596">AutenticaĂ§Ă£o necessĂ¡ria</translation>
<translation id="2079545284768500474">Anular</translation>
<translation id="20817612488360358">As definições de proxy do sistema estĂ£o definidas para serem utilizadas, mas tambĂ©m estĂ¡ especificada uma configuraĂ§Ă£o de proxy explĂ­cita.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Editar marcador</translation>
<translation id="2166049586286450108">Acesso de administrador total</translation>
<translation id="2166378884831602661">Este site nĂ£o consegue fornecer uma ligaĂ§Ă£o segura</translation>
-<translation id="2171101176734966184">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado assinado utilizando um algoritmo de assinatura fraco. Significa que as credenciais de segurança apresentadas pelo servidor podem ter sido falsificadas e que o servidor pode nĂ£o ser aquele que pretende (pode estar a comunicar com um utilizador mal intencionado).</translation>
<translation id="2181821976797666341">PolĂ­ticas</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}other{# endereços}}</translation>
<translation id="2212735316055980242">PolĂ­tica nĂ£o encontrada</translation>
<translation id="2213606439339815911">A obter entradas...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> nĂ£o estĂ¡ disponĂ­vel</translation>
<translation id="2230458221926704099">Utilize a <ph name="BEGIN_LINK" />aplicaĂ§Ă£o de diagnĂ³stico<ph name="END_LINK" /> para corrigir a ligaĂ§Ă£o</translation>
+<translation id="2239100178324503013">Enviar agora</translation>
<translation id="225207911366869382">Este valor estĂ¡ desatualizado para esta polĂ­tica.</translation>
<translation id="2262243747453050782">Erro HTTP</translation>
<translation id="2282872951544483773">ExperiĂªncias IndisponĂ­veis</translation>
<translation id="2292556288342944218">O acesso Ă  Internet estĂ¡ bloqueado</translation>
<translation id="229702904922032456">Um certificado de raiz ou intermédio expirou.</translation>
<translation id="230155334948463882">Tem um cartĂ£o novo?</translation>
+<translation id="2305919008529760154">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o respetivo certificado de segurança pode ter sido emitido de forma fraudulenta. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">O domĂ­nio <ph name="DOMAIN" /> requer um nome de utilizador e uma palavra-passe.</translation>
+<translation id="2318774815570432836">De momento, nĂ£o Ă© possĂ­vel aceder a <ph name="SITE" /> porque o Website utiliza HSTS. Geralmente, os erros de rede e os ataques sĂ£o temporĂ¡rios, pelo que Ă© provĂ¡vel que esta pĂ¡gina funcione mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Marcador invĂ¡lido ignorado no Ă­ndice <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Outros marcadores</translation>
<translation id="2359808026110333948">Continuar</translation>
<translation id="2365563543831475020">O relatĂ³rio de falhas capturado <ph name="CRASH_TIME" /> nĂ£o foi carregado</translation>
<translation id="2367567093518048410">NĂ­vel</translation>
+<translation id="2371153335857947666">{1,plural, =1{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o respetivo certificado de segurança expirou ontem. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. O relĂ³gio do seu computador estĂ¡ atualmente definido para <ph name="CURRENT_DATE" />. Esta definiĂ§Ă£o parece-lhe correta? Caso contrĂ¡rio, deve corrigir o relĂ³gio do seu sistema e, em seguida, atualizar esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}other{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o respetivo certificado de segurança expirou hĂ¡ # dias. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. O relĂ³gio do seu computador estĂ¡ atualmente definido para <ph name="CURRENT_DATE" />. Esta definiĂ§Ă£o parece-lhe correta? Caso contrĂ¡rio, deve corrigir o relĂ³gio do seu sistema e, em seguida, atualizar esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Nenhuma alternativa da interface disponĂ­vel</translation>
<translation id="2384307209577226199">PredefiniĂ§Ă£o empresarial</translation>
-<translation id="238526402387145295">De momento nĂ£o Ă© possĂ­vel visitar <ph name="SITE" /> porque o Website <ph name="BEGIN_LINK" />utiliza HSTS<ph name="END_LINK" />. Os erros de rede e os ataques normalmente sĂ£o temporĂ¡rios, por isso, esta pĂ¡gina voltarĂ¡ provavelmente a funcionar.</translation>
<translation id="2386255080630008482">O certificado do servidor foi revogado.</translation>
<translation id="2392959068659972793">Apresentar polĂ­ticas sem valor definido</translation>
<translation id="2396249848217231973">&amp;Anular eliminaĂ§Ă£o</translation>
-<translation id="2413528052993050574">Este servidor nĂ£o conseguiu provar que Ă© o domĂ­nio <ph name="DOMAIN" />; o respetivo certificado de segurança poderĂ¡ ser revogado. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o.</translation>
<translation id="2455981314101692989">Esta pĂ¡gina Web desactivou o preenchimento automĂ¡tico para este formulĂ¡rio.</translation>
+<translation id="2463739503403862330">Preencher</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Executar o DiagnĂ³stico de rede<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL de pesquisa invĂ¡lido.</translation>
<translation id="2491120439723279231">O certificado do servidor contém erros.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Submeter</translation>
<translation id="2674170444375937751">Tem a certeza de que pretende eliminar estas pĂ¡ginas do seu histĂ³rico?</translation>
<translation id="2677748264148917807">Sair</translation>
+<translation id="269990154133806163">O servidor apresentou um certificado que nĂ£o foi publicamente divulgado atravĂ©s da polĂ­tica de TransparĂªncia de certificados. Isto Ă© um requisito para alguns certificados para garantir que sĂ£o fidedignos e para a proteĂ§Ă£o contra utilizadores mal-intencionados. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">O valor nĂ£o corresponde ao formato.</translation>
<translation id="2704951214193499422">O Chromium nĂ£o conseguiu confirmar o seu cartĂ£o neste momento. Tente novamente mais tarde.</translation>
<translation id="2705137772291741111">A cĂ³pia guardada (em cache) deste site era ilegĂ­vel.</translation>
<translation id="2709516037105925701">Preenchimento automĂ¡tico</translation>
+<translation id="2712118517637785082">Tentou aceder a <ph name="DOMAIN" />, mas o certificado que o servidor apresentou foi revogado pelo respetivo emissor. Isto significa que as credenciais de segurança que o servidor apresentou nĂ£o devem, em circunstĂ¢ncia alguma, ser consideradas fidedignas. Pode estar a comunicar com um utilizador mal-intencionado. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Pedir autorizaĂ§Ă£o</translation>
<translation id="2721148159707890343">Pedido com Ăªxito</translation>
<translation id="2728127805433021124">O certificado do servidor foi assinado utilizando um algoritmo de assinatura fraco.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Barra de pesquisa e endereço</translation>
<translation id="2826760142808435982">A ligaĂ§Ă£o Ă© encriptada e autenticada com <ph name="CIPHER" /> e utiliza <ph name="KX" /> como mecanismo de troca de chaves.</translation>
<translation id="2835170189407361413">Limpar formulĂ¡rio</translation>
-<translation id="2837049386027881519">A ligaĂ§Ă£o tinha de ser repetida utilizando uma versĂ£o mais antiga do protocolo TLS ou SSL. Isso normalmente significa que o servidor estĂ¡ a utilizar um software muito antigo e pode ter outros problemas de segurança.</translation>
<translation id="284702764277384724">O certificado do servidor de <ph name="HOST_NAME" /> parece ser uma falsificaĂ§Ă£o.</translation>
<translation id="2889159643044928134">NĂ£o atualizar</translation>
-<translation id="2896499918916051536">Este plug-in nĂ£o Ă© compatĂ­vel.</translation>
+<translation id="2900469785430194048">O Google Chrome ficou sem memĂ³ria ao tentar apresentar esta pĂ¡gina Web.</translation>
<translation id="2909946352844186028">Foi detetada uma alteraĂ§Ă£o de rede.</translation>
-<translation id="2915500479781995473">Este servidor nĂ£o conseguir provar que Ă© o domĂ­nio <ph name="DOMAIN" />; o respetivo certificado de segurança expirou. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um atacante a intercetar a sua ligaĂ§Ă£o. Atualmente, o relĂ³gio do computador estĂ¡ definido para as <ph name="CURRENT_TIME" />. Esta hora parece-lhe correta? Em caso negativo, corrija o relĂ³gio do sistema e, em seguida, atualize esta pĂ¡gina.</translation>
<translation id="2922350208395188000">NĂ£o Ă© possĂ­vel verificar o certificado do servidor.</translation>
-<translation id="2941952326391522266">Este servidor nĂ£o conseguiu provar que Ă© o domĂ­nio <ph name="DOMAIN" />; o respetivo certificado de segurança Ă© do domĂ­nio <ph name="DOMAIN2" />. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o.</translation>
<translation id="2948083400971632585">Pode desativar qualquer proxy configurado para uma ligaĂ§Ă£o a partir da pĂ¡gina de definições.</translation>
<translation id="2955913368246107853">Fechar barra de localizaĂ§Ă£o</translation>
<translation id="2958431318199492670">A configuraĂ§Ă£o de rede nĂ£o cumpre a norma ONC. Partes da configuraĂ§Ă£o podem nĂ£o ser importadas.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Tipo de polĂ­tica incorreto</translation>
<translation id="3032412215588512954">Pretende atualizar este site?</translation>
<translation id="3037605927509011580">Ah, bolas!!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{pelo menos 1 item em dispositivos sincronizados}=1{1 item (e mais em dispositivos sincronizados)}other{# itens (e mais em dispositivos sincronizados)}}</translation>
<translation id="3041612393474885105">Informações do certificado</translation>
<translation id="3063697135517575841">O Chrome nĂ£o conseguiu confirmar o seu cartĂ£o neste momento. Tente novamente mais tarde.</translation>
<translation id="3093245981617870298">O utilizador estĂ¡ em modo offline.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">O mais recente</translation>
<translation id="3207960819495026254">Adicionado aos marcadores</translation>
-<translation id="3225919329040284222">O servidor apresentou um certificado que nĂ£o corresponde Ă s expectativas existentes. Estas expectativas sĂ£o incluĂ­das para determinados Web sites de alta segurança para sua proteĂ§Ă£o.</translation>
<translation id="3226128629678568754">Prima o botĂ£o de atualizaĂ§Ă£o para enviar novamente os dados necessĂ¡rios para carregar a pĂ¡gina.</translation>
<translation id="3228969707346345236">NĂ£o foi possĂ­vel traduzir, porque a pĂ¡gina jĂ¡ estĂ¡ em <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Introduzir o CĂ³digo de Segurança/CVC de <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Marcar esta pĂ¡gina</translation>
<translation id="3270847123878663523">&amp;Anular reordenaĂ§Ă£o</translation>
<translation id="3286538390144397061">Reiniciar agora</translation>
+<translation id="3303855915957856445">NĂ£o foram encontrados resultados da pesquisa</translation>
<translation id="3305707030755673451">Os dados foram encriptados com a sua frase de acesso de sincronizaĂ§Ă£o em <ph name="TIME" />. Introduza-a para iniciar a sincronizaĂ§Ă£o.</translation>
<translation id="333371639341676808">Evitar que esta pĂ¡gina crie caixas de diĂ¡logo adicionais.</translation>
+<translation id="3338095232262050444">Seguro</translation>
<translation id="3340978935015468852">definições</translation>
<translation id="3345135638360864351">NĂ£o Ă© possĂ­vel enviar o seu pedido de acesso a este site a <ph name="NAME" />. Tente novamente.</translation>
<translation id="3355823806454867987">Alterar definições de proxy...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Intervalo de obtenĂ§Ă£o:</translation>
<translation id="3462200631372590220">Ocultar avançadas</translation>
<translation id="3479539252931486093">Esta aĂ§Ă£o foi inesperada? <ph name="BEGIN_LINK" />Informe-nos<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Agora nĂ£o</translation>
<translation id="348000606199325318">ID de falha <ph name="CRASH_LOCAL_ID" /> (ID do servidor: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">NĂ£o conseguimos falar com o(a) seu (sua) pai/mĂ£e de momento. Tente novamente.</translation>
<translation id="3527085408025491307">Pasta</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Utilizar palavra-passe para:</translation>
<translation id="3549644494707163724">Encriptar todos os dados sincronizados com a sua prĂ³pria frase de acesso de sincronizaĂ§Ă£o</translation>
<translation id="3549761410225185768">Mais <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o respetivo certificado de segurança Ă© de <ph name="DOMAIN2" />. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">A sua ligaĂ§Ă£o nĂ£o Ă© privada</translation>
<translation id="3583757800736429874">&amp;Refazer movimentaĂ§Ă£o</translation>
<translation id="3586931643579894722">Ocultar detalhes</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Apresentar o valor</translation>
<translation id="3630155396527302611">Se jĂ¡ estiver indicado na lista como sendo um programa com permissĂ£o para aceder Ă  rede, experimente
removĂª-lo da lista e adicionĂ¡-lo novamente.</translation>
+<translation id="3638794133396384728">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o respetivo certificado de segurança expirou. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. O relĂ³gio do seu computador estĂ¡ atualmente definido para <ph name="CURRENT_TIME" />. Esta definiĂ§Ă£o parece-lhe correta? Caso contrĂ¡rio, deve corrigir o relĂ³gio do seu sistema e, em seguida, atualizar esta pĂ¡gina. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Estas funcionalidades experimentais podem mudar, deixar de funcionar ou desaparecer a qualquer momento. NĂ£o nos responsabilizamos pelo que possa acontecer se ativar uma destas funcionalidades experimentais e o navegador pode atĂ© entrar em combustĂ£o espontĂ¢nea. Brincadeiras Ă  parte, o navegador pode eliminar todos os dados ou a sua segurança e privacidade podem ficar comprometidas de formas inesperadas. Todas as experiĂªncias que ativar serĂ£o ativadas para todos os utilizadores deste navegador. Continue com cuidado.</translation>
<translation id="3650584904733503804">ValidaĂ§Ă£o com Ăªxito</translation>
<translation id="3655670868607891010">Se vĂª isto com frequĂªncia, experimente <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">RevisĂ£o</translation>
+<translation id="3678029195006412963">NĂ£o foi possĂ­vel assinar o pedido</translation>
<translation id="3681007416295224113">Informações do certificado</translation>
<translation id="3693415264595406141">Palavra-passe:</translation>
+<translation id="3696411085566228381">nenhuns</translation>
<translation id="3700528541715530410">Ups! Aparentemente, nĂ£o tem autorizaĂ§Ă£o para aceder a esta pĂ¡gina.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">A carregar...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Ativar os dados mĂ³veis ou o Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Verificar a configuraĂ§Ă£o do proxy, da firewall e de DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Link copiado por si</translation>
-<translation id="3744899669254331632">NĂ£o pode visitar <ph name="SITE" /> neste momento, porque o Website enviou credenciais baralhadas que o Chromium nĂ£o consegue processar. Os erros de rede e os ataques sĂ£o geralmente temporĂ¡rios, pelo que esta pĂ¡gina deverĂ¡ funcionar mais tarde.</translation>
<translation id="375403751935624634">A traduĂ§Ă£o falhou devido a um erro do servidor.</translation>
<translation id="3759461132968374835">NĂ£o tem comunicado falhas recentemente. As falhas que tenham ocorrido enquanto a criaĂ§Ă£o de relatĂ³rios de falha esteve desativada nĂ£o surgem aqui.</translation>
<translation id="3788090790273268753">O certificado deste site expira em 2016 e a cadeia de certificados inclui um certificado assinado através de SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Identificador do dispositivo em conflito</translation>
<translation id="3885155851504623709">Freguesia</translation>
<translation id="3901925938762663762">O cartĂ£o expirou</translation>
+<translation id="3910267023907260648">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado assinado com um algoritmo de assinatura fraco. Isto significa que as credenciais de segurança que o servidor apresentou podem ter sido falsificadas e que o servidor pode nĂ£o ser o servidor esperado (pode estar a comunicar com um utilizador mal-intencionado). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o respetivo certificado de segurança Ă© supostamente de amanhĂ£. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}other{Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o respetivo certificado de segurança Ă© supostamente de daqui a # dias. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Falha ao carregar o documento em PDF</translation>
<translation id="3963721102035795474">Modo de leitor</translation>
+<translation id="397105322502079400">A calcular...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> estĂ¡ bloqueado</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 pĂ¡gina Web prĂ³xima}other{# pĂ¡ginas Web prĂ³ximas}}</translation>
<translation id="4021036232240155012">O DNS é o serviço de rede que converte o nome de um Website no respetivo endereço de Internet.</translation>
<translation id="4030383055268325496">&amp;Anular adiĂ§Ă£o</translation>
-<translation id="4032534284272647190">O acesso a <ph name="URL" /> foi negado.</translation>
<translation id="404928562651467259">AVISO</translation>
<translation id="4058922952496707368">Chave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">O cliente e o servidor nĂ£o suportam uma versĂ£o do protocolo SSL ou um conjunto de cifras comum.</translation>
<translation id="4079302484614802869">A configuraĂ§Ă£o do proxy estĂ¡ definida para utilizar um URL de script .pac e nĂ£o servidores proxy fixos.</translation>
<translation id="4103249731201008433">NĂºmero de sĂ©rie do dispositivo Ă© invĂ¡lido</translation>
<translation id="4103763322291513355">Visite &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver os URLs que foram colocados na lista negra e outras polĂ­ticas aplicadas pelo administrador do sistema.</translation>
+<translation id="4110615724604346410">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o respetivo certificado de segurança contĂ©m erros. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">O Ă¢mbito da polĂ­tica nĂ£o Ă© suportado.</translation>
+<translation id="4118212371799607889">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o Chromium nĂ£o confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 outro}other{# outros}}</translation>
<translation id="4130226655945681476">Verificar os cabos de rede, o modem e o router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Pretende que o Chromium guarde este cartĂ£o?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Desativado</translation>
<translation id="4196861286325780578">&amp;Refazer movimentaĂ§Ă£o</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Verificar as configurações da firewall e de antivírus<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{nenhuma}=1{1 aplicaĂ§Ă£o ($1)}=2{2 aplicações ($1, $2)}other{# aplicações ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Erros</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Experimente executar o DiagnĂ³stico de rede<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">NĂ£o</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Sem nome de utilizador)</translation>
<translation id="4300246636397505754">Sugestões superiores</translation>
<translation id="4304224509867189079">Iniciar sessĂ£o</translation>
+<translation id="432290197980158659">O servidor apresentou um certificado que nĂ£o corresponde Ă s expetativas existentes. Estas expetativas estĂ£o incluĂ­das em determinados Websites de alta segurança para o proteger. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Falha ao encontrar o artigo</translation>
+<translation id="4331708818696583467">Inseguro</translation>
<translation id="4372948949327679948">Valor <ph name="VALUE_TYPE" /> esperado.</translation>
-<translation id="4377125064752653719">Tentou aceder a <ph name="DOMAIN" />, mas o certificado que o servidor apresentou foi revogado pelo emissor. Isto significa que as credenciais de segurança apresentadas pelo servidor nĂ£o deverĂ£o, em circunstĂ¢ncia alguma, ser consideradas fidedignas. Pode estar a comunicar com um utilizador mal intencionado.</translation>
<translation id="4381091992796011497">Nome do utilizador:</translation>
<translation id="4394049700291259645">Desactivar</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> a <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">resultados da pesquisa</translation>
-<translation id="4424024547088906515">Este servidor nĂ£o conseguiu provar que Ă© o domĂ­nio <ph name="DOMAIN" />; o Chrome nĂ£o confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> nĂ£o aceitou o seu certificado de inĂ­cio de sessĂ£o ou este pode nĂ£o ter sido fornecido.</translation>
<translation id="443673843213245140">A utilizaĂ§Ă£o de um proxy estĂ¡ desativada, mas existe uma configuraĂ§Ă£o de proxy explĂ­cita especificada.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">EstĂ¡ a ver esta mensagem porque o Google SafeSites estĂ¡ ativado.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Detalhes</translation>
<translation id="4558551763791394412">Experimente desativar as extensões.</translation>
<translation id="4587425331216688090">Pretende remover o endereço do Chrome?</translation>
+<translation id="4589078953350245614">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado invĂ¡lido. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">A sua ligaĂ§Ă£o a <ph name="DOMAIN" /> estĂ¡ encriptada atravĂ©s de um conjunto de cifras moderno.</translation>
<translation id="4594403342090139922">&amp;Anular eliminaĂ§Ă£o</translation>
+<translation id="4627442949885028695">Continuar a partir de outro dispositivo</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">EstĂ¡ a ver a pĂ¡gina de uma extensĂ£o.</translation>
-<translation id="467662567472608290">Este servidor nĂ£o conseguiu provar que Ă© o domĂ­nio <ph name="DOMAIN" />; o respetivo certificado de segurança contĂ©m erros. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> foi bloqueado</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">A ligaĂ§Ă£o foi interrompida</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Executar o DiagnĂ³stico de rede do Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Plataforma</translation>
<translation id="4744603770635761495">Caminho do ExecutĂ¡vel</translation>
<translation id="4756388243121344051">&amp;HistĂ³rico</translation>
+<translation id="4759238208242260848">TransferĂªncias</translation>
<translation id="4764776831041365478">A pĂ¡gina Web em <ph name="URL" /> poderĂ¡ estar temporariamente inactiva ou poderĂ¡ ter sido movida permanentemente para um novo endereço Web.</translation>
<translation id="4771973620359291008">Ocorreu um erro desconhecido.</translation>
<translation id="4782449893814226250">Perguntaste aos teus pais se podes aceder a esta pĂ¡gina.</translation>
<translation id="4800132727771399293">Verifique a data de validade e o CĂ³digo de Segurança/CVC e tente novamente</translation>
-<translation id="4807049035289105102">De momento, nĂ£o pode aceder a <ph name="SITE" /> porque o Website enviou credenciais codificadas que o Google Chrome nĂ£o consegue processar. Geralmente, os erros de rede e os ataques sĂ£o temporĂ¡rios, pelo que Ă© provĂ¡vel que esta pĂ¡gina volte a funcionar mais tarde.</translation>
<translation id="4813512666221746211">Erro de rede</translation>
<translation id="4816492930507672669">Ajustar Ă  pĂ¡gina</translation>
<translation id="4850886885716139402">Ver</translation>
<translation id="4880827082731008257">Pesquisar histĂ³rico</translation>
+<translation id="4884656795097055129">SĂ£o apresentados mais artigos no momento certo.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{e mais 1 pĂ¡gina Web}other{e mais # pĂ¡ginas Web}}</translation>
<translation id="4923417429809017348">Esta pĂ¡gina foi traduzida de um idioma desconhecido para <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Tem de ser especificado.</translation>
<translation id="4930497775425430760">EstĂ¡s a ver esta mensagem porque o teu encarregado de educaĂ§Ă£o necessita de aprovar os sites novos sempre que os visitas pela primeira vez.</translation>
<translation id="495170559598752135">Ações</translation>
<translation id="4958444002117714549">Expandir lista</translation>
+<translation id="4962322354953122629">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o Chrome nĂ£o confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Traduzir de <ph name="ORIGINAL_LANGUAGE" /> para <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Este plug-in nĂ£o Ă© compatĂ­vel</translation>
<translation id="5002932099480077015">Quando esta opĂ§Ă£o estĂ¡ ativada, o Chrome armazena uma cĂ³pia do seu cartĂ£o neste dispositivo para preencher formulĂ¡rios mais rapidamente.</translation>
<translation id="5019198164206649151">Armazenamento de segurança em mau estado</translation>
<translation id="5023310440958281426">Verificar as polĂ­ticas do administrador</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Acerca do Google Tradutor</translation>
<translation id="5040262127954254034">Privacidade</translation>
<translation id="5045550434625856497">Palavra-passe incorrecta</translation>
+<translation id="5056549851600133418">Artigos para si</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Verificar o endereço proxy<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">De momento, o certificado do servidor nĂ£o Ă© vĂ¡lido.</translation>
<translation id="5089810972385038852">Estado</translation>
-<translation id="5094747076828555589">Este servidor nĂ£o conseguiu provar que Ă© o domĂ­nio <ph name="DOMAIN" />; o Chromium nĂ£o confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o.</translation>
<translation id="5095208057601539847">ProvĂ­ncia</translation>
<translation id="5115563688576182185">(64 bits)</translation>
-<translation id="5122371513570456792">Encontrados <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />".</translation>
<translation id="5141240743006678641">Encriptar palavras-passe sincronizadas com as credenciais Google</translation>
<translation id="5145883236150621069">CĂ³digo de erro presente na resposta da polĂ­tica</translation>
<translation id="5171045022955879922">Pesquisar ou escrever URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Barra de marcadores</translation>
<translation id="5199729219167945352">ExperiĂªncias</translation>
<translation id="5251803541071282808">Nuvem</translation>
+<translation id="5277279256032773186">Utiliza o Chrome no trabalho? As empresas podem gerir as definições do Chrome para os seus funcionĂ¡rios. Saiba mais</translation>
<translation id="5299298092464848405">Erro ao analisar a polĂ­tica</translation>
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5308689395849655368">O relatĂ³rio de falha estĂ¡ desativado.</translation>
<translation id="5317780077021120954">Guardar</translation>
<translation id="5327248766486351172">Nome</translation>
+<translation id="5359637492792381994">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o respetivo certificado de segurança nĂ£o Ă© vĂ¡lido neste momento. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Falha ao armazenar as definições da política</translation>
-<translation id="540969355065856584">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; de momento, o respetivo certificado de segurança nĂ£o Ă© vĂ¡lido. Isto pode ser provocado por uma configuraĂ§Ă£o incorreta ou por um atacante que esteja a intercetar a sua ligaĂ§Ă£o.</translation>
<translation id="5421136146218899937">Limpar dados de navegaĂ§Ă£o...</translation>
<translation id="5430298929874300616">Remover marcador</translation>
<translation id="5431657950005405462">O ficheiro nĂ£o foi encontrado</translation>
<translation id="5435775191620395718">A mostrar o histĂ³rico deste dispositivo. <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">As sugestões de conteĂºdo personalizado estĂ£o atualmente desativadas porque os seus dados sincronizados estĂ£o protegidos por uma frase de acesso personalizada.</translation>
<translation id="5439770059721715174">Erro de validaĂ§Ă£o de esquema em "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">NĂ£o Ă© possĂ­vel encontrar esta pĂ¡gina de <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">Carimbo de data/hora da polĂ­tica incorreto</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Pretende sair deste site?</translation>
<translation id="5629630648637658800">Falha ao carregar as definições da política</translation>
<translation id="5631439013527180824">Token de gestĂ£o do dispositivo invĂ¡lido</translation>
-<translation id="5650551054760837876">Nenhum resultado de pesquisa encontrado.</translation>
<translation id="5677928146339483299">Bloqueado</translation>
<translation id="5710435578057952990">A identidade deste Web site nĂ£o foi verificada.</translation>
<translation id="5720705177508910913">Utilizador atual</translation>
+<translation id="572328651809341494">Separadores recentes</translation>
<translation id="5784606427469807560">Ocorreu um erro ao confirmar o cartĂ£o. Verifique a sua ligaĂ§Ă£o Ă  Internet e tente novamente.</translation>
<translation id="5785756445106461925">AlĂ©m disso, esta pĂ¡gina inclui outros recursos que nĂ£o sĂ£o seguros. Estes recursos podem ser vistos por outros utilizadores em trĂ¢nsito e modificados por um utilizador mal intencionado com o intuito de alterar o aspeto da pĂ¡gina.</translation>
+<translation id="5786044859038896871">Pretende preencher as informações do cartĂ£o?</translation>
+<translation id="5803412860119678065">Pretende preencher o seu cartĂ£o <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">A sua ligaĂ§Ă£o a <ph name="DOMAIN" /> estĂ¡ encriptada atravĂ©s de um conjunto de cifras obsoleto.</translation>
<translation id="5813119285467412249">&amp;Refazer adiĂ§Ă£o</translation>
+<translation id="5814352347845180253">Pode perder o acesso ao conteĂºdo premium de <ph name="SITE" /> e de outros sites.</translation>
+<translation id="5843436854350372569">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado que contĂ©m uma chave fraca. Um utilizador mal-intencionado pode ter quebrado a chave privada e o servidor pode nĂ£o ser o servidor esperado (pode estar a comunicar com um utilizador mal-intencionado). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">EstĂ¡ a ver esta mensagem porque o seu gestor bloqueou este site.</translation>
<translation id="5857090052475505287">Nova pasta</translation>
<translation id="5869405914158311789">NĂ£o Ă© possĂ­vel aceder a este site</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Sugestões superiores</translation>
<translation id="59107663811261420">O Google Payments nĂ£o Ă© compatĂ­vel com este tipo de cartĂ£o para este comerciante. Selecione outro cartĂ£o.</translation>
<translation id="59174027418879706">Ativada</translation>
+<translation id="5926846154125914413">Pode perder o acesso ao conteĂºdo premium de alguns sites.</translation>
<translation id="5966707198760109579">Semana</translation>
<translation id="5967867314010545767">Remover do histĂ³rico</translation>
<translation id="5975083100439434680">Reduzir</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">AutomĂ¡tico</translation>
<translation id="6042308850641462728">Mais</translation>
<translation id="6060685159320643512">Tenha cuidado, estas experiĂªncias podem morder</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{nenhuma}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Verifique os cabos e reinicie todos os routers, modems ou outros
dispositivos de rede que possa estar a utilizar.</translation>
<translation id="614940544461990577">Experimente:</translation>
<translation id="6150607114729249911">Ups! Tens de perguntar aos teus pais se podes aceder a esta pĂ¡gina.</translation>
<translation id="6151417162996330722">O certificado do servidor tem um perĂ­odo de validade demasiado longo.</translation>
-<translation id="6154808779448689242">O token da polĂ­tica devolvido nĂ£o corresponde ao token atual</translation>
<translation id="6165508094623778733">Saiba mais</translation>
<translation id="6203231073485539293">Verificar a ligaĂ§Ă£o Ă  Internet</translation>
<translation id="6218753634732582820">Pretende remover o endereço do Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Tente desativar a previsĂ£o de rede</translation>
<translation id="6337534724793800597">Filtrar polĂ­ticas pelo nome</translation>
<translation id="6342069812937806050">Mesmo agora</translation>
+<translation id="6345221851280129312">tamanho desconhecido</translation>
<translation id="6355080345576803305">SubstituiĂ§Ă£o da sessĂ£o pĂºblica</translation>
<translation id="6358450015545214790">O que significam?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 outra sugestĂ£o}other{# outras sugestões}}</translation>
<translation id="6387478394221739770">EstĂ¡ interessado nas novas e fantĂ¡sticas funcionalidades do Chrome? Experimente o nosso canal beta em chrome.com/beta.</translation>
-<translation id="641480858134062906">Falha ao carregar <ph name="URL" /></translation>
+<translation id="6389758589412724634">O Chromium ficou sem memĂ³ria ao tentar apresentar esta pĂ¡gina Web.</translation>
+<translation id="6416403317709441254">De momento, nĂ£o Ă© possĂ­vel aceder a <ph name="SITE" /> porque o Website enviou credenciais codificadas que o Chromium nĂ£o consegue processar. Geralmente, os erros de rede e os ataques sĂ£o temporĂ¡rios, pelo que Ă© provĂ¡vel que esta pĂ¡gina funcione mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">NĂ£o Ă© possĂ­vel verificar se o certificado foi revogado.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> recusou estabelecer ligaĂ§Ă£o.</translation>
<translation id="6445051938772793705">PaĂ­s</translation>
<translation id="6451458296329894277">Confirmar nova submissĂ£o de formulĂ¡rio</translation>
<translation id="6458467102616083041">Ignorado porque a pesquisa predefinida foi desativada pela polĂ­tica.</translation>
+<translation id="6462969404041126431">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o respetivo certificado de segurança pode ser revogado. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">PolĂ­ticas do dispositivo</translation>
<translation id="6489534406876378309">Começar a carregar falhas</translation>
<translation id="6529602333819889595">&amp;Refazer eliminaĂ§Ă£o</translation>
+<translation id="6534179046333460208">Sugestões da Web física</translation>
<translation id="6550675742724504774">Opções</translation>
+<translation id="6593753688552673085">menos de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opções de encriptaĂ§Ă£o</translation>
<translation id="662080504995468778">Ficar</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Pesquisar</translation>
-<translation id="6634865548447745291">De momento, nĂ£o Ă© possĂ­vel visitar <ph name="SITE" /> porque <ph name="BEGIN_LINK" />este certificado foi revogado<ph name="END_LINK" />. Os erros de rede e os ataques normalmente sĂ£o temporĂ¡rios, por isso, esta pĂ¡gina voltarĂ¡ provavelmente a funcionar.</translation>
<translation id="6644283850729428850">Esta polĂ­tica estĂ¡ obsoleta.</translation>
+<translation id="6652240803263749613">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o sistema operativo do seu computador nĂ£o confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Editar Pasta</translation>
<translation id="6660210980321319655">RelatĂ³rio enviado automaticamente em: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Pretende remover a sugestĂ£o do formulĂ¡rio do Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Anterior</translation>
<translation id="6710594484020273272">&lt;Introduzir termo de pesquisa&gt;</translation>
<translation id="6711464428925977395">Existe um problema com o servidor proxy ou o endereço estĂ¡ incorreto.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{nenhuma}=1{1 item}other{# itens}}</translation>
<translation id="674375294223700098">Erro de certificado de servidor desconhecido.</translation>
<translation id="6753269504797312559">Valor da polĂ­tica</translation>
<translation id="6757797048963528358">O dispositivo entrou em suspensĂ£o.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">O nĂ­vel da polĂ­tica nĂ£o Ă© suportado.</translation>
<translation id="6895330447102777224">O seu cartĂ£o foi confirmado</translation>
<translation id="6897140037006041989">Agente do utilizador</translation>
-<translation id="6903907808598579934">Ativar sincronizaĂ§Ă£o</translation>
<translation id="6915804003454593391">Utilizador:</translation>
<translation id="6957887021205513506">O certificado do servidor parece ser uma falsificaĂ§Ă£o.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Distrito</translation>
<translation id="6973656660372572881">Foram especificados servidores proxy fixos e um URL de script .pac.</translation>
<translation id="6989763994942163495">Mostrar definições avançadas...</translation>
+<translation id="7000990526846637657">NĂ£o foram encontradas entradas no histĂ³rico</translation>
+<translation id="7009986207543992532">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado cujo perĂ­odo de validade Ă© demasiado longo para ser fidedigno. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">A sua Conta Google pode ter outras formas do histĂ³rico de navegaĂ§Ă£o em <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Palavras-passe</translation>
-<translation id="7050187094878475250">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado cujo perĂ­odo de validade Ă© demasiado longo para ser fidedigno.</translation>
<translation id="7087282848513945231">Condado</translation>
<translation id="7088615885725309056">Mais antigo</translation>
<translation id="7090678807593890770">Pesquisar <ph name="LINK" /> no Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">EstĂ¡ a ver esta mensagem porque o seu gestor necessita de aprovar os sites novos sempre que o visita pela primeira vez.</translation>
<translation id="724975217298816891">Introduza a data de validade e o CĂ³digo de Segurança/CVC de <ph name="CREDIT_CARD" /> para atualizar os detalhes do cartĂ£o. Ao confirmar, os detalhes do cartĂ£o sĂ£o partilhados com este site.</translation>
<translation id="725866823122871198">NĂ£o Ă© possĂ­vel estabelecer uma ligaĂ§Ă£o privada a <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, porque a data e a hora do computador (<ph name="DATE_AND_TIME" />) estĂ£o incorretas.</translation>
-<translation id="7265986070661382626">De momento nĂ£o Ă© possĂ­vel visitar <ph name="SITE" /> porque o Website <ph name="BEGIN_LINK" />utiliza a afixaĂ§Ă£o de certificados<ph name="END_LINK" />. Os erros de rede e os ataques normalmente sĂ£o temporĂ¡rios, por isso, esta pĂ¡gina voltarĂ¡ provavelmente a funcionar.</translation>
<translation id="7269802741830436641">Esta pĂ¡gina Web tem um ciclo de redireccionamento</translation>
<translation id="7275334191706090484">Marcadores Geridos</translation>
<translation id="7298195798382681320">Recomendado</translation>
-<translation id="7301833672208172928">Ativar sincronizaĂ§Ă£o do histĂ³rico</translation>
+<translation id="7309308571273880165">RelatĂ³rio de falhas capturado no(a) <ph name="CRASH_TIME" /> (carregamento pedido pelo utilizador, ainda nĂ£o carregado)</translation>
<translation id="7334320624316649418">&amp;Refazer reordenaĂ§Ă£o</translation>
<translation id="733923710415886693">O certificado do servidor nĂ£o foi divulgado atravĂ©s da TransparĂªncia de certificados.</translation>
+<translation id="7351800657706554155">De momento, nĂ£o Ă© possĂ­vel aceder a <ph name="SITE" /> porque este certificado foi revogado. Geralmente, os erros de rede e os ataques sĂ£o temporĂ¡rios, pelo que Ă© provĂ¡vel que esta pĂ¡gina funcione mais tarde. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Linha de comandos</translation>
<translation id="7372973238305370288">resultado da pesquisa</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ O modo de navegaĂ§Ă£o anĂ³nima <ph name="SHORTCUT_KEY" /> pode ser Ăºtil da prĂ³
<translation id="7469372306589899959">A confirmar o cartĂ£o...</translation>
<translation id="7481312909269577407">Avançar</translation>
<translation id="7485870689360869515">NĂ£o foram encontrados dados.</translation>
+<translation id="7508255263130623398">O ID do dispositivo da polĂ­tica devolvido estĂ¡ vazio ou nĂ£o corresponde ao ID do dispositivo atual</translation>
<translation id="7514365320538308">Transferir</translation>
<translation id="7518003948725431193">NĂ£o foi encontrada qualquer pĂ¡gina Web para o endereço Web: <ph name="URL" /></translation>
<translation id="7537536606612762813">ObrigatĂ³rio</translation>
<translation id="7542995811387359312">O preenchimento automĂ¡tico de cartões de crĂ©dito estĂ¡ desactivado, porque este formulĂ¡rio nĂ£o utiliza uma ligaĂ§Ă£o segura.</translation>
<translation id="7549584377607005141">Esta pĂ¡gina Web requer os dados introduzidos anteriormente para ser corretamente apresentada. Pode enviar novamente esses dados, mas ao fazĂª-lo, irĂ¡ repetir as ações que esta pĂ¡gina executou anteriormente.</translation>
<translation id="7554791636758816595">Novo separador</translation>
-<translation id="7567204685887185387">Este servidor nĂ£o conseguiu provar que Ă© o domĂ­nio <ph name="DOMAIN" />; o respetivo certificado de segurança poderĂ¡ ter sido emitido de forma fraudulenta. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um invasor a intercetar a sua ligaĂ§Ă£o.</translation>
<translation id="7568593326407688803">Esta pĂ¡gina estĂ¡ em<ph name="ORIGINAL_LANGUAGE" />Pretende traduzi-la?</translation>
<translation id="7569952961197462199">Pretende remover o cartĂ£o de crĂ©dito do Chrome?</translation>
<translation id="7578104083680115302">Pague rapidamente em sites e aplicações em todos os dispositivos com cartões que tenha guardado com o Google.</translation>
+<translation id="7588950540487816470">Web fĂ­sica</translation>
<translation id="7592362899630581445">O certificado do servidor viola as restrições de nome.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> nĂ£o consegue processar este pedido de momento.</translation>
<translation id="7600965453749440009">Nunca traduzir do <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ O modo de navegaĂ§Ă£o anĂ³nima <ph name="SHORTCUT_KEY" /> pode ser Ăºtil da prĂ³
<translation id="7637571805876720304">Pretende remover o cartĂ£o de crĂ©dito do Chromium?</translation>
<translation id="765676359832457558">Ocultar definições avançadas...</translation>
<translation id="7658239707568436148">Cancelar</translation>
+<translation id="7667346355482952095">O sĂ­mbolo da polĂ­tica devolvido estĂ¡ vazio ou nĂ£o corresponde ao sĂ­mbolo atual</translation>
<translation id="7668654391829183341">Dispositivo desconhecido</translation>
<translation id="7674629440242451245">EstĂ¡ interessado nas novas e fantĂ¡sticas funcionalidades do Chrome? Experimente o nosso canal para programadores em chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Prosseguir para <ph name="SITE" /> (nĂ£o seguro)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ O modo de navegaĂ§Ă£o anĂ³nima <ph name="SHORTCUT_KEY" /> pode ser Ăºtil da prĂ³
<translation id="780301667611848630">NĂ£o, obrigado</translation>
<translation id="7805768142964895445">Estado</translation>
<translation id="7813600968533626083">Pretende remover a sugestĂ£o do formulĂ¡rio do Chrome?</translation>
+<translation id="7815407501681723534">Encontrados <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
<translation id="785549533363645510">No entanto, a navegaĂ§Ă£o nĂ£o Ă© invisĂ­vel. Passar para o modo de navegaĂ§Ă£o anĂ³nima nĂ£o oculta a navegaĂ§Ă£o do empregador ou do fornecedor de serviços de Internet, nem dos Websites que visitar.</translation>
<translation id="7887683347370398519">Verifique o CĂ³digo de Segurança/CVC e tente novamente</translation>
<translation id="7894616681410591072">Ups! Necessita da autorizaĂ§Ă£o de <ph name="NAME" /> para aceder a esta pĂ¡gina.</translation>
-<translation id="790025292736025802">NĂ£o Ă© possĂ­vel localizar <ph name="URL" /></translation>
<translation id="7912024687060120840">Na Pasta:</translation>
<translation id="7920092496846849526">Perguntaste aos teus pais se nĂ£o havia problema em aceder a esta pĂ¡gina.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ O modo de navegaĂ§Ă£o anĂ³nima <ph name="SHORTCUT_KEY" /> pode ser Ăºtil da prĂ³
<translation id="7995512525968007366">NĂ£o especificado</translation>
<translation id="8012647001091218357">NĂ£o conseguimos falar com os seus pais de momento. Tente novamente.</translation>
<translation id="8034522405403831421">Esta pĂ¡gina estĂ¡ em <ph name="SOURCE_LANGUAGE" />. Pretende traduzi-la para <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">NĂ£o foram encontradas entradas no histĂ³rico.</translation>
<translation id="8088680233425245692">Falha ao ver o artigo.</translation>
+<translation id="8089520772729574115">menos de 1 MB</translation>
<translation id="8091372947890762290">AtivaĂ§Ă£o pendente no servidor</translation>
+<translation id="8129262335948759431">quantidade desconhecida</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8134994873729925007">NĂ£o foi possĂ­vel encontrar o <ph name="BEGIN_ABBR" />endereço DNS<ph name="END_ABBR" /> do servidor de <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">O computador entrou em suspensĂ£o.</translation>
@@ -604,6 +640,7 @@ O modo de navegaĂ§Ă£o anĂ³nima <ph name="SHORTCUT_KEY" /> pode ser Ăºtil da prĂ³
<translation id="8201077131113104583">Atualizar URL invĂ¡lido para a extensĂ£o com o ID "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">LocalizaĂ§Ă£o atribuĂ­da:</translation>
<translation id="8225771182978767009">A pessoa que configurou este computador optou por bloquear este site.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">A pĂ¡gina que procura utilizou informações introduzidas por si. Regressar a essa pĂ¡gina poderĂ¡ originar a repetiĂ§Ă£o de qualquer acĂ§Ă£o que tenha efetuado. Pretende continuar?</translation>
<translation id="8249320324621329438">Ăltima obtenĂ§Ă£o:</translation>
<translation id="8261506727792406068">Eliminar</translation>
@@ -616,12 +653,17 @@ O modo de navegaĂ§Ă£o anĂ³nima <ph name="SHORTCUT_KEY" /> pode ser Ăºtil da prĂ³
<translation id="8349305172487531364">Barra de marcadores</translation>
<translation id="8363502534493474904">Desativar o modo de aviĂ£o</translation>
<translation id="8364627913115013041">NĂ£o definida.</translation>
+<translation id="8380941800586852976">Perigosa</translation>
<translation id="8412145213513410671">Falhas (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Tem de introduzir a mesma frase de acesso duas vezes.</translation>
<translation id="8428213095426709021">Definições</translation>
+<translation id="8433057134996913067">Esta opĂ§Ă£o termina a sessĂ£o na maioria dos Websites.</translation>
<translation id="8437238597147034694">&amp;Anular movimentaĂ§Ă£o</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 cartĂ£o de crĂ©dito}other{# cartões de crĂ©dito}}</translation>
+<translation id="8483780878231876732">Para utilizar cartões da sua Conta Google, inicie sessĂ£o no Chrome.</translation>
<translation id="8488350697529856933">Aplica-se a</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> demorou demasiado tempo a responder.</translation>
+<translation id="852346902619691059">Este servidor nĂ£o conseguiu provar que Ă© <ph name="DOMAIN" />; o sistema operativo do seu dispositivo nĂ£o confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuraĂ§Ă£o incorreta ou de um utilizador mal-intencionado que intercetou a sua ligaĂ§Ă£o. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">O Google Payments nĂ£o Ă© compatĂ­vel com este tipo de cartĂ£o. Selecione outro cartĂ£o.</translation>
<translation id="8550022383519221471">O serviço de sincronizaĂ§Ă£o nĂ£o estĂ¡ disponĂ­vel para o seu domĂ­nio.</translation>
<translation id="8553075262323480129">A traduĂ§Ă£o falhou porque nĂ£o foi possĂ­vel determinar o idioma da pĂ¡gina.</translation>
@@ -633,15 +675,12 @@ O modo de navegaĂ§Ă£o anĂ³nima <ph name="SHORTCUT_KEY" /> pode ser Ăºtil da prĂ³
<translation id="8647750283161643317">Repor todas as predefinições</translation>
<translation id="8680787084697685621">Os detalhes de inĂ­cio de sessĂ£o na conta estĂ£o desactualizados.</translation>
<translation id="8703575177326907206">A sua ligaĂ§Ă£o a <ph name="DOMAIN" /> nĂ£o estĂ¡ encriptada.</translation>
-<translation id="8713130696108419660">Rubrica incorreta</translation>
<translation id="8725066075913043281">Tentar novamente</translation>
<translation id="8728672262656704056">EstĂ¡ anĂ³nimo</translation>
<translation id="8730621377337864115">ConcluĂ­do</translation>
<translation id="8738058698779197622">Para estabelecer uma ligaĂ§Ă£o segura, o relĂ³gio tem de ser definido corretamente. Isto deve-se ao facto de os certificados que os Websites utilizam para se identificarem serem apenas vĂ¡lidos para perĂ­odos de tempo especĂ­ficos. Uma vez que o relĂ³gio do seu dispositivo estĂ¡ incorreto, o Chromium nĂ£o consegue validar estes certificados.</translation>
<translation id="8740359287975076522">NĂ£o foi possĂ­vel encontrar o &lt;abbr id="dnsDefinition"&gt;endereço DNS&lt;/abbr&gt; de <ph name="HOST_NAME" />. Estamos a diagnosticar o problema.</translation>
-<translation id="8741995161408053644">A sua Conta Google pode ter outras formas do histĂ³rico de navegaĂ§Ă£o em <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Refazer eliminaĂ§Ă£o</translation>
-<translation id="8790687370365610530">Para obter conteĂºdo personalizado sugerido pelo Google, ative a sincronizaĂ§Ă£o do histĂ³rico.</translation>
<translation id="8798099450830957504">PredefiniĂ§Ă£o</translation>
<translation id="8804164990146287819">PolĂ­tica de Privacidade</translation>
<translation id="8820817407110198400">Marcadores</translation>
@@ -663,13 +702,11 @@ O modo de navegaĂ§Ă£o anĂ³nima <ph name="SHORTCUT_KEY" /> pode ser Ăºtil da prĂ³
<translation id="8971063699422889582">O certificado do servidor expirou.</translation>
<translation id="8987927404178983737">MĂªs</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">O servidor apresentou um certificado que nĂ£o foi divulgado publicamente atravĂ©s da polĂ­tica de TransparĂªncia de certificados. Trata-se de um requisito para alguns certificados de modo a assegurar que sĂ£o fidedignos e protegem contra utilizadores mal intencionados.</translation>
<translation id="9001074447101275817">O proxy <ph name="DOMAIN" /> necessita de um nome de utilizador e de uma palavra-passe.</translation>
<translation id="901974403500617787">Os sinalizadores que se aplicam a todo o sistema apenas podem ser definidos pelo proprietĂ¡rio: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Esta pĂ¡gina foi traduzida para <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Utilizar um serviço de previsĂ£o para carregar pĂ¡ginas mais rapidamente</translation>
<translation id="9039213469156557790">AlĂ©m disso, esta pĂ¡gina inclui outros recursos que nĂ£o sĂ£o seguros. Estes recursos podem ser vistos por outros utilizadores em trĂ¢nsito e modificados por um utilizador mal intencionado com o intuito de alterar o comportamento da pĂ¡gina.</translation>
-<translation id="9049981332609050619">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado invĂ¡lido.</translation>
<translation id="9050666287014529139">Frase de acesso</translation>
<translation id="9065203028668620118">Editar</translation>
<translation id="9092364396508701805">A pĂ¡gina de <ph name="HOST_NAME" /> nĂ£o estĂ¡ a funcionar</translation>
diff --git a/chromium/components/strings/components_strings_ro.xtb b/chromium/components/strings/components_strings_ro.xtb
index cbf3eca41b0..2b7d4e1eafc 100644
--- a/chromium/components/strings/components_strings_ro.xtb
+++ b/chromium/components/strings/components_strings_ro.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ro">
+<translation id="1008557486741366299">Nu acum</translation>
<translation id="1015730422737071372">Specifică detalii suplimentare</translation>
<translation id="1032854598605920125">RoteÈ™te Ă®n sensul acelor de ceasornic</translation>
<translation id="1038842779957582377">nume necunoscut</translation>
+<translation id="1053591932240354961">Momentan, nu poÈ›i accesa site-ul <ph name="SITE" />, deoarece acesta a trimis date de conectare Ă®ntr-un format necunoscut, pe care Google Chrome nu le poate procesa. Erorile de reÈ›ea È™i atacurile sunt de obicei temporare È™i probabil că această pagină va funcÈ›iona mai tĂ¢rziu. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Anulați adăugarea</translation>
<translation id="10614374240317010">Nu se salvează niciodată</translation>
-<translation id="1064422015032085147">Serverul care găzduieÈ™te pagina web poate fi supraĂ®ncărcat sau Ă®n curs de Ă®ntreÈ›inere.
- Pentru a nu genera prea mult trafic, Ă®nrăutățind astfel situaÈ›ia,
- solicitările către această adresă URL au fost dezactivate temporar.</translation>
<translation id="106701514854093668">Marcaje desktop</translation>
<translation id="1080116354587839789">Ăncadrează pe lățime</translation>
+<translation id="1103124106085518534">Gata pentru moment</translation>
<translation id="1103523840287552314">Tradu întotdeauna din <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Dacă este bifată opțiunea, Chrome va stoca o copie a cardului pe dispozitiv pentru a completa formularul mai rapid.</translation>
+<translation id="1111153019813902504">Marcaje accesate recent</translation>
<translation id="1113869188872983271">&amp;Anulați reordonarea</translation>
+<translation id="1126551341858583091">Dimensiunea spațiului de stocare local este <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Memoria cache pentru politică este OK</translation>
<translation id="113188000913989374"><ph name="SITE" /> afișează mesajul:</translation>
<translation id="1132774398110320017">Setări de completare automată Ă®n Chrome...</translation>
-<translation id="1150979032973867961">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; sistemul de operare al computerului nu consideră că certificatul său de securitate este de Ă®ncredere. Cauza poate fi o configurare greÈ™ită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="1152921474424827756">AccesaÈ›i o <ph name="BEGIN_LINK" />copie păstrată Ă®n memoria cache<ph name="END_LINK" /> a site-ului <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> a Ă®nchis conexiunea Ă®n mod neaÈ™teptat.</translation>
<translation id="1161325031994447685">să te reconectezi la Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Elimină</translation>
<translation id="1201402288615127009">Ănainte</translation>
<translation id="1201895884277373915">Mai multe de la acest site</translation>
-<translation id="121201262018556460">AÈ›i Ă®ncercat să accesaÈ›i <ph name="DOMAIN" />, dar serverul a furnizat un certificat care conÈ›ine o cheie slabă. Un atacator ar fi putut sparge cheia privată È™i este posibil ca serverul să nu fie cel aÈ™teptat de dvs. (este posibil să comunicaÈ›i cu un atacator).</translation>
+<translation id="1206967143813997005">Semnătură inițială nevalidă</translation>
+<translation id="1209206284964581585">Ascunde momentan</translation>
<translation id="1219129156119358924">Securitatea sistemului</translation>
<translation id="1227224963052638717">Politică necunoscută.</translation>
<translation id="1227633850867390598">Ascundeți valoarea</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Da</translation>
<translation id="1430915738399379752">Printează</translation>
<translation id="1442912890475371290">Ăncercarea <ph name="BEGIN_LINK" /> de a accesa o pagină de pe <ph name="DOMAIN" /><ph name="END_LINK" /> a fost blocată.</translation>
+<translation id="1491663344921578213">Momentan, nu poÈ›i accesa site-ul <ph name="SITE" />, deoarece acesta foloseÈ™te fixarea certificatelor. Erorile de reÈ›ea È™i atacurile sunt de obicei temporare È™i probabil că această pagină va funcÈ›iona mai tĂ¢rziu. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">AfiÈ™ează o copie salvată (adică despre care se È™tie că este Ă®nvechită) a acestei pagini.</translation>
<translation id="1519264250979466059">Dată versiune:</translation>
<translation id="1549470594296187301">Trebuie să activezi JavaScript pentru a folosi această funcție.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Configurația rețelei este nevalidă și nu a putut fi importată.</translation>
<translation id="1644574205037202324">Istoric</translation>
<translation id="1645368109819982629">Protocol neacceptat</translation>
-<translation id="1655462015569774233">{1,plural, =1{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Certificatul său de securitate a expirat ieri. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. Ăn prezent, ora computerului este setată la <ph name="CURRENT_DATE" />. Este corect? Dacă nu este, corectează ora sistemului È™i actualizează pagina.}few{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Certificatul său de securitate a expirat acum # zile. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. Ăn prezent, ora computerului este setată la <ph name="CURRENT_DATE" />. Este corect? Dacă nu este, corectează ora sistemului È™i actualizează pagina.}other{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Certificatul său de securitate a expirat acum # de zile. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. Ăn prezent, ora computerului este setată la <ph name="CURRENT_DATE" />. Este corect? Dacă nu este, corectează ora sistemului È™i actualizează pagina.}}</translation>
<translation id="1676269943528358898">Site-ul <ph name="SITE" /> foloseÈ™te Ă®n mod obiÈ™nuit criptarea pentru a-È›i proteja informaÈ›iile. CĂ¢nd Google Chrome a Ă®ncercat să se conecteze la <ph name="SITE" /> de această dată, site-ul a returnat date de conectare neobiÈ™nuite È™i incorecte. Acest lucru s-a Ă®ntĂ¢mplat fie pentru că un atacator Ă®ncearcă să falsifice site-ul <ph name="SITE" />, fie pentru că un ecran de conectare Wi-Fi a Ă®ntrerupt conexiunea. Securitatea informaÈ›iilor tale nu a fost afectată, deoarece Google Chrome a oprit conexiunea Ă®nainte ca datele să fie transferate.</translation>
<translation id="168841957122794586">Certificatul de server conține o cheie criptografică slabă.</translation>
<translation id="1701955595840307032">Obține sugestii de conținut</translation>
-<translation id="1706954506755087368">{1,plural, =1{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Data de emitere a certificatului său de securitate este mĂ¢ine. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator.}few{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Data de emitere a certificatului său de securitate este Ă®n viitor, peste # zile. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator.}other{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Data de emitere a certificatului său de securitate este Ă®n viitor, peste # de zile. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator.}}</translation>
<translation id="1710259589646384581">Sistem de operare</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Ăncearcă să contactezi administratorul sistemului.</translation>
<translation id="17513872634828108">File deschise</translation>
<translation id="1753706481035618306">Numărul paginii</translation>
-<translation id="1761412452051366565">Pentru a obține sugestii de conținut personalizat de la Google, activează sincronizarea.</translation>
-<translation id="1763864636252898013">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; sistemul de operare al dispozitivului nu consideră că certificatul său de securitate este de Ă®ncredere. Cauza poate fi o configurare greÈ™ită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Rulează Diagnostice rețea Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Actualizează expresia de acces pentru sincronizare.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Marcajele accesate recent vor apărea aici.</translation>
<translation id="1821930232296380041">Solicitarea sau parametrii săi sunt greșiți</translation>
<translation id="1838667051080421715">Se afișează sursa unei pagini web.</translation>
<translation id="1871208020102129563">Configurația proxy este setată să utilizeze servere proxy fixe, și nu o adresă URL pentru scripturi .pac.</translation>
<translation id="1883255238294161206">RestrĂ¢ngeÈ›i lista</translation>
<translation id="1898423065542865115">Filtrarea</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> nu a acceptat certificatul de conectare sau certificatul de conectare a expirat.</translation>
<translation id="194030505837763158">Accesați <ph name="LINK" /></translation>
<translation id="1962204205936693436">Marcaje <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Eroare de serializare</translation>
<translation id="1974060860693918893">Avansate</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{È™i Ă®ncă una}few{È™i Ă®ncă #}other{È™i Ă®ncă #}}</translation>
<translation id="2025186561304664664">Proxy-ul este setat la Configurat automat.</translation>
<translation id="2030481566774242610">Ați dorit să scrieți <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Ai primit acest mesaj deoarece este necesar ca părinții să aprobe site-urile noi la prima accesare.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />să verifici proxy-ul și firewallul;<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Cod zip</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 sugestie}few{# sugestii}other{# de sugestii}}</translation>
<translation id="2065985942032347596">Autentificare obligatorie</translation>
<translation id="2079545284768500474">Anulează</translation>
<translation id="20817612488360358">Setările proxy de sistem sunt setate pentru a fi utilizate, dar o configurație explicită pentru proxy este, de asemenea, specificată.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Editați marcajul</translation>
<translation id="2166049586286450108">Acces complet de administrare</translation>
<translation id="2166378884831602661">Acest site nu poate oferi o conexiune sigură</translation>
-<translation id="2171101176734966184">AÈ›i Ă®ncercat să accesaÈ›i <ph name="DOMAIN" />, dar serverul a furnizat un certificat semnat utilizĂ¢nd un algoritm de semnare slab. Aceasta Ă®nsemnă că este posibil ca acreditările de securitate furnizate de server să fie falsificate, iar serverul să nu fie cel aÈ™teptat (este posibil să comunicaÈ›i cu un atacator).</translation>
<translation id="2181821976797666341">Politici</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adresă}few{# adrese}other{# de adrese}}</translation>
<translation id="2212735316055980242">Politica nu a fost găsită</translation>
<translation id="2213606439339815911">Se preiau intrările...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> nu este disponibil</translation>
<translation id="2230458221926704099">Remediază conexiunea folosind <ph name="BEGIN_LINK" />aplicația de diagnosticare<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Trimite acum</translation>
<translation id="225207911366869382">Valoarea este Ă®nvechită pentru această politică.</translation>
<translation id="2262243747453050782">Eroare HTTP</translation>
<translation id="2282872951544483773">Experimente indisponibile</translation>
<translation id="2292556288342944218">Accesul la internet este blocat</translation>
<translation id="229702904922032456">Un certificat rădăcină sau intermediar a expirat.</translation>
<translation id="230155334948463882">Card nou?</translation>
+<translation id="2305919008529760154">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Este posibil ca certificatul său de securitate să fi fost emis fraudulos. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> necesită un nume de utilizator și o parolă.</translation>
+<translation id="2318774815570432836">Momentan, nu poÈ›i accesa site-ul <ph name="SITE" />, deoarece acesta foloseÈ™te HSTS. Erorile de reÈ›ea È™i atacurile sunt de obicei temporare È™i probabil că această pagină va funcÈ›iona mai tĂ¢rziu. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Marcaj nevalid ignorat la indexul <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Alte marcaje</translation>
<translation id="2359808026110333948">Continuă</translation>
<translation id="2365563543831475020">Raportul de blocare creat <ph name="CRASH_TIME" /> nu a fost Ă®ncărcat</translation>
<translation id="2367567093518048410">Nivel</translation>
+<translation id="2371153335857947666">{1,plural, =1{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Certificatul său de securitate a expirat ieri. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. Ăn prezent, ora computerului este setată la <ph name="CURRENT_DATE" />. Este corect? Dacă nu este, corectează ora sistemului È™i actualizează pagina. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.}few{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Certificatul său de securitate a expirat acum # zile. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. Ăn prezent, ora computerului este setată la <ph name="CURRENT_DATE" />. Este corect? Dacă nu este, corectează ora sistemului È™i actualizează pagina. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.}other{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Certificatul său de securitate a expirat acum # de zile. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. Ăn prezent, ora computerului este setată la <ph name="CURRENT_DATE" />. Este corect? Dacă nu este, corectează ora sistemului È™i actualizează pagina. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Nu sunt disponibile interfețe de utilizare alternative</translation>
<translation id="2384307209577226199">Setare prestabilită la nivel de companie</translation>
-<translation id="238526402387145295">Nu puteÈ›i accesa acum site-ul <ph name="SITE" />, deoarece acesta <ph name="BEGIN_LINK" />foloseÈ™te HSTS<ph name="END_LINK" />. Erorile de reÈ›ea È™i atacurile sunt de obicei temporare È™i probabil că această pagină va funcÈ›iona mai tĂ¢rziu.</translation>
<translation id="2386255080630008482">Certificatul serverului a fost revocat.</translation>
<translation id="2392959068659972793">Afișați politicile care nu au valori setate</translation>
<translation id="2396249848217231973">&amp;Anulați ștergerea</translation>
-<translation id="2413528052993050574">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; este posibil ca certificatul său de securitate să fie revocat. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="2455981314101692989">Această pagină web a dezactivat completarea automată a formularului.</translation>
+<translation id="2463739503403862330">Completează</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />să rulezi Diagnostice rețea<ph name="END_LINK" />;</translation>
<translation id="2479410451996844060">Adresă URL de căutare nevalidă.</translation>
<translation id="2491120439723279231">Certificatul serverului conține erori.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Trimite</translation>
<translation id="2674170444375937751">Sigur doriți să ștergeți aceste pagini din istoric?</translation>
<translation id="2677748264148917807">Ieși</translation>
+<translation id="269990154133806163">Serverul a prezentat un certificat care nu a fost dezvăluit public folosind politica privind TransparenÈ›a certificatului. Aceasta este o cerință pentru anumite certificate, pentru a se asigura că sunt de Ă®ncredere È™i pentru protecÈ›ie Ă®mpotriva atacatorilor. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Valoarea nu se potrivește cu formatul.</translation>
<translation id="2704951214193499422">Momentan, Chromium nu a putut confirma cardul. Ăncearcă din nou mai tĂ¢rziu.</translation>
<translation id="2705137772291741111">Copia salvată (Ă®n memoria cache) a acestui site nu a putut fi citită.</translation>
<translation id="2709516037105925701">Completare automată</translation>
+<translation id="2712118517637785082">Ai Ă®ncercat să accesezi <ph name="DOMAIN" />, dar certificatul prezentat de server a fost revocat de emitentul său. Acest lucru Ă®nseamnă că datele de conectare de securitate prezentate de server nu sunt deloc de Ă®ncredere. Este posibil să comunici cu un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Solicită permisiunea</translation>
<translation id="2721148159707890343">Solicitarea a reușit</translation>
<translation id="2728127805433021124">Certificatul serverului este semnat utilizĂ¢nd un algoritm de semnătură slab.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Bara de adrese și de căutare</translation>
<translation id="2826760142808435982">Conexiunea este criptată È™i autentificată utilizĂ¢nd <ph name="CIPHER" /> È™i foloseÈ™te <ph name="KX" /> ca mecanism de schimb al cheii.</translation>
<translation id="2835170189407361413">Golește formularul</translation>
-<translation id="2837049386027881519">A fost necesar să se Ă®ncerce din nou realizarea conexiunii, utilizĂ¢nd o versiune mai veche a protocolului TSL sau SSL. Ăn mod obiÈ™nuit, acest lucru Ă®nseamnă că serverul utilizează un software foarte vechi È™i că poate avea È™i alte probleme de securitate.</translation>
<translation id="284702764277384724">Se pare că certificatul de server pentru <ph name="HOST_NAME" /> este un fals.</translation>
<translation id="2889159643044928134">Nu reĂ®ncărca</translation>
-<translation id="2896499918916051536">Acest plugin nu este acceptat.</translation>
+<translation id="2900469785430194048">Google Chrome nu a avut suficientă memorie la afișarea paginii web.</translation>
<translation id="2909946352844186028">A fost detectată o schimbare a rețelei.</translation>
-<translation id="2915500479781995473">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; certificatul său de securitate a expirat. Cauza poate fi o configurare greÈ™ită sau interceptarea conexiunii de către un atacator. Ăn prezent, ceasul computerului este setat la <ph name="CURRENT_TIME" />. Este corect? Dacă nu, trebuie să corectezi ora sistemului, apoi să actualizezi pagina.</translation>
<translation id="2922350208395188000">Certificatul serverului nu poate fi verificat.</translation>
-<translation id="2941952326391522266">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; certificatul său de securitate provine de la <ph name="DOMAIN2" />. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="2948083400971632585">Puteți să dezactivați serverele proxy configurate pentru o conexiune din pagina de setări.</translation>
<translation id="2955913368246107853">Ănchide Bara de căutare</translation>
<translation id="2958431318199492670">Configurația rețelei nu respectă standardul ONC. Este posibil ca anumite părți ale configurației să nu fie importate.</translation>
@@ -188,9 +190,10 @@
<translation id="3024663005179499861">Tip de politică greșit</translation>
<translation id="3032412215588512954">DoreÈ™ti să reĂ®ncarci acest site?</translation>
<translation id="3037605927509011580">Of, nu mai merge!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{cel puțin un element pe dispozitivele sincronizate}=1{un element (și mai multe pe dispozitivele sincronizate)}few{# elemente (și mai multe pe dispozitivele sincronizate)}other{# de elemente (și mai multe pe dispozitivele sincronizate)}}</translation>
<translation id="3041612393474885105">Informații despre certificat</translation>
<translation id="3063697135517575841">Momentan, Chrome nu a putut confirma cardul. Ăncearcă din nou mai tĂ¢rziu.</translation>
-<translation id="3093245981617870298">Sunteți offline.</translation>
+<translation id="3093245981617870298">Ești offline.</translation>
<translation id="3105172416063519923">ID articol:</translation>
<translation id="3109728660330352905">Nu ești autorizat(ă) să vezi această pagină.</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Rulează Diagnostice conectivitate<ph name="END_LINK" />.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Cele mai noi</translation>
<translation id="3207960819495026254">Marcată</translation>
-<translation id="3225919329040284222">Serverul a prezentat un certificat care nu se potriveÈ™te cu aÈ™teptările Ă®ncorporate. Aceste aÈ™teptări sunt incluse pentru anumite site-uri web, cu un grad sporit de securitate, pentru a vă proteja.</translation>
<translation id="3226128629678568754">ApăsaÈ›i butonul de reĂ®ncărcare pentru a retrimite datele necesare pentru Ă®ncărcarea paginii.</translation>
<translation id="3228969707346345236">Pagina nu a fost tradusă, deoarece aceasta este deja Ă®n <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Introdu codul CVC pentru <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Marcați această pagină</translation>
<translation id="3270847123878663523">&amp;Anulați reordonarea</translation>
<translation id="3286538390144397061">Repornește acum</translation>
+<translation id="3303855915957856445">Nu s-au găsit rezultate de căutare</translation>
<translation id="3305707030755673451">Datele au fost criptate cu expresia de acces pentru sincronizare la <ph name="TIME" />. Introdu-o pentru a începe sincronizarea.</translation>
<translation id="333371639341676808">Ămpiedică această pagină să creeze alte casete de dialog.</translation>
+<translation id="3338095232262050444">Securizat</translation>
<translation id="3340978935015468852">setări</translation>
<translation id="3345135638360864351">Solicitarea de a accesa acest site nu a putut fi trimisă la <ph name="NAME" />. Ăncearcă din nou.</translation>
<translation id="3355823806454867987">Modifica setările proxy...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Interval de preluare:</translation>
<translation id="3462200631372590220">Ascundeți detaliile avansate</translation>
<translation id="3479539252931486093">A fost o situație neașteptată? <ph name="BEGIN_LINK" />Anunță-ne<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Nu acum</translation>
<translation id="348000606199325318">ID blocare <ph name="CRASH_LOCAL_ID" /> (ID server: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Momentan, nu È›i-am putut contacta părintele. Ăncearcă din nou.</translation>
<translation id="3527085408025491307">Dosar</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Folosește parola pentru:</translation>
<translation id="3549644494707163724">Criptați toate datele sincronizate cu parola dvs. de acces pentru sincronizare</translation>
<translation id="3549761410225185768">Ăncă <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Certificatul său de securitate provine de la <ph name="DOMAIN2" />. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Conexiunea nu este privată</translation>
<translation id="3583757800736429874">&amp;Repetați mutarea</translation>
<translation id="3586931643579894722">Ascunde detaliile</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Afișați valoarea</translation>
<translation id="3630155396527302611">Dacă este deja inclus ca program căruia i se permite să acceseze reÈ›eaua, Ă®ncearcă
să Ă®l elimini din listă È™i să Ă®l adaugi din nou.</translation>
+<translation id="3638794133396384728">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Certificatul său de securitate a expirat. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. Ăn prezent, ora computerului este setată la <ph name="CURRENT_TIME" />. Este corect? Dacă nu este, corectează ora sistemului È™i actualizează pagina. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Aceste funcÈ›ii experimentale pot oricĂ¢nd să se schimbe, să nu mai funcÈ›ioneze sau să dispară. Nu oferim absolut nicio garanÈ›ie cu privire la efectele activării acestor experimente. Se poate chiar ca browserul să se defecteze brusc. LăsĂ¢nd gluma la o parte, browserul poate să È™teargă toate datele sau securitatea È™i confidenÈ›ialitatea datelor se pot compromite Ă®ntr-un mod neaÈ™teptat. Toate experimentele pe care le activezi vor fi activate pentru toÈ›i utilizatorii acestui browser. Continuă cu prudență.</translation>
<translation id="3650584904733503804">Validarea a reușit</translation>
<translation id="3655670868607891010">Dacă această pagină se afiÈ™ează Ă®n mod frecvent, Ă®ncercaÈ›i <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Versiune</translation>
+<translation id="3678029195006412963">Solicitarea nu a putut fi semnată</translation>
<translation id="3681007416295224113">Informații despre certificat</translation>
<translation id="3693415264595406141">Parolă:</translation>
+<translation id="3696411085566228381">niciuna</translation>
<translation id="3700528541715530410">Hopa, se pare că nu aveți permisiunea de a accesa această pagină.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Se Ă®ncarcă…</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">să activezi datele mobile sau conexiunea Wi-Fi;</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />să verifici configurarea pentru proxy, firewall și DNS;<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Linkul copiat de tine</translation>
-<translation id="3744899669254331632">Nu poÈ›i accesa acum <ph name="SITE" />, deoarece site-ul a trimis date de conectare Ă®ntr-un format necunoscut pe care Chromium nu le poate procesa. Erorile de reÈ›ea È™i atacurile sunt de obicei temporare È™i probabil că această pagină va funcÈ›iona mai tĂ¢rziu.</translation>
<translation id="375403751935624634">Traducerea nu a reușit din cauza unei erori de server.</translation>
<translation id="3759461132968374835">Nu există blocări raportate recent. Blocările care au avut loc cĂ¢nd raportarea blocărilor era dezactivată nu vor apărea aici.</translation>
<translation id="3788090790273268753">Certificatul pentru acest site expiră Ă®n 2016, iar lanÈ›ul de certificate conÈ›ine un certificat semnat cu SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Identificator de gadget în conflict</translation>
<translation id="3885155851504623709">Parohie</translation>
<translation id="3901925938762663762">Cardul este expirat</translation>
+<translation id="3910267023907260648">Ai Ă®ncercat să accesezi <ph name="DOMAIN" />, dar serverul a prezentat un certificat semnat folosind un algoritm de semnare slab. Acest lucru Ă®nseamnă că este posibil ca datele de conectare de securitate prezentate de server să fie falsificate sau ca serverul să nu fie cel aÈ™teptat (este posibil să comunici cu un atacator). <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Data de emitere a certificatului său de securitate este mĂ¢ine. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.}few{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Data de emitere a certificatului său de securitate este Ă®n viitor, peste # zile. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.}other{Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Data de emitere a certificatului său de securitate este Ă®n viitor, peste # de zile. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Documentul PDF nu a fost Ă®ncărcat</translation>
<translation id="3963721102035795474">Modul Cititor</translation>
+<translation id="397105322502079400">Se calculează...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> este blocat</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 pagină web Ă®n apropiere}few{# pagini web Ă®n apropiere}other{# de pagini web Ă®n apropiere}}</translation>
<translation id="4021036232240155012">DNS este serviciul de reÈ›ea care translatează numele unui site Ă®n adresa sa de internet.</translation>
<translation id="4030383055268325496">&amp;Anulați adăugarea</translation>
-<translation id="4032534284272647190">Accesul la <ph name="URL" /> nu este permis.</translation>
<translation id="404928562651467259">AVERTISMENT</translation>
<translation id="4058922952496707368">Cheie â€<ph name="SUBKEY" />â€: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Clientul și serverul nu acceptă o versiune a protocolului SSL sau o suită de codificare obișnuită.</translation>
<translation id="4079302484614802869">Configurația pentru proxy este setată să utilizeze o adresă URL pentru scripturi .pac, și nu servere proxy fixe.</translation>
<translation id="4103249731201008433">Numărul de serie al gadgetului este nevalid</translation>
<translation id="4103763322291513355">Accesați &lt;strong&gt;chrome://policy&lt;/strong&gt; pentru a vedea adresele URL introduse pe lista neagră și alte politici impuse de către administratorul de sistem.</translation>
+<translation id="4110615724604346410">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Certificatul său de securitate conține erori. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Domeniul politicii nu este acceptat.</translation>
+<translation id="4118212371799607889">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Chromium nu consideră că certificatul său de securitate este de Ă®ncredere. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{Ă®ncă 1}few{Ă®ncă #}other{Ă®ncă #}}</translation>
<translation id="4130226655945681476">să verifici cablurile de rețea, modemul și routerul;</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">DoreÈ™ti ca acest card să fie salvat Ă®n Chromium?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Dezactivat</translation>
<translation id="4196861286325780578">&amp;Repetați mutarea</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />să verifici configurarea pentru firewall și antivirus;<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{niciuna}=1{1 aplicație ($1)}=2{2 aplicații ($1, $2)}few{# aplicații ($1, $2, $3)}other{# de aplicații ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Blocări</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Rulează Diagnostice rețea<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Nu</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Niciun nume de utilizator)</translation>
<translation id="4300246636397505754">Sugestii parentale</translation>
<translation id="4304224509867189079">Conectează-te</translation>
+<translation id="432290197980158659">Serverul a prezentat un certificat care nu se potriveÈ™te cu aÈ™teptările Ă®ncorporate. Aceste aÈ™teptări sunt incluse pentru anumite site-uri, cu un grad sporit de securitate, pentru a te proteja. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Articolul nu a fost găsit</translation>
+<translation id="4331708818696583467">Nesecurizat</translation>
<translation id="4372948949327679948">Se aștepta valoarea <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">AÈ›i Ă®ncercat să accesaÈ›i <ph name="DOMAIN" />, dar certificatul furnizat de server a fost revocat de emitentul său. Aceasta Ă®nseamnă că acreditările de securitate furnizate de server nu sunt deloc de Ă®ncredere. Este posibil să comunicaÈ›i cu un atacator.</translation>
<translation id="4381091992796011497">Nume de utilizator:</translation>
<translation id="4394049700291259645">Dezactivează</translation>
<translation id="4395129973926795186">Ăntre <ph name="START_DATE" /> È™i <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">rezultate ale căutării</translation>
-<translation id="4424024547088906515">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; Chrome nu consideră că certificatul său de securitate este de Ă®ncredere. Cauza poate fi o configurare greÈ™ită sau interceptarea conexiunii de către un atacator.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> nu a acceptat certificatul de conectare sau un astfel de certificat nu a fost oferit.</translation>
<translation id="443673843213245140">Utilizarea unui proxy este dezactivată, dar o configurare proxy este specificată Ă®n mod explicit.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Ai primit acest mesaj deoarece este activat filtrul Google SafeSites.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Detalii</translation>
<translation id="4558551763791394412">Dezactivează extensiile.</translation>
<translation id="4587425331216688090">Elimini adresa din Chrome?</translation>
+<translation id="4589078953350245614">Ai Ă®ncercat să accesezi <ph name="DOMAIN" />, dar serverul a prezentat un certificat nevalid. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Conexiunea la <ph name="DOMAIN" /> este criptată folosind o suită de codificare modernă.</translation>
<translation id="4594403342090139922">&amp;Anulați ștergerea</translation>
+<translation id="4627442949885028695">Continuă de pe un alt dispozitiv</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Se afișează pagina extensiei.</translation>
-<translation id="467662567472608290">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; certificatul său de securitate conține erori. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
-<translation id="4697214168136963651">Adresa <ph name="URL" /> a fost blocată</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Conexiunea a fost Ă®ntreruptă</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />să rulezi Diagnostice rețea Windows<ph name="END_LINK" />;</translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Platformă</translation>
<translation id="4744603770635761495">Cale executabilă</translation>
<translation id="4756388243121344051">&amp;Istoric</translation>
+<translation id="4759238208242260848">Descărcări</translation>
<translation id="4764776831041365478">Pagina web de la <ph name="URL" /> poate fi temporar nefuncțională sau a fost mutată definitiv la o nouă adresă web.</translation>
<translation id="4771973620359291008">A apărut o eroare necunoscută.</translation>
<translation id="4782449893814226250">Ai Ă®ntrebat părinÈ›ii dacă poÈ›i accesa această pagină.</translation>
<translation id="4800132727771399293">Verifică data de expirare È™i codul CVC È™i Ă®ncearcă din nou</translation>
-<translation id="4807049035289105102">Nu poÈ›i accesa acum site-ul <ph name="SITE" />, deoarece acesta a trimis date de conectare Ă®ntr-un format necunoscut, pe care Google Chrome nu le poate procesa. Erorile de reÈ›ea È™i atacurile sunt de obicei temporare È™i probabil că această pagină va funcÈ›iona mai tĂ¢rziu.</translation>
<translation id="4813512666221746211">Eroare de rețea</translation>
<translation id="4816492930507672669">ĂncadraÈ›i Ă®n pagină</translation>
<translation id="4850886885716139402">Afișează</translation>
<translation id="4880827082731008257">Caută Ă®n istoric</translation>
+<translation id="4884656795097055129">La momentul potrivit vor apărea mai multe articole.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{È™i Ă®ncă 1 pagină web}few{È™i Ă®ncă # pagini web}other{È™i Ă®ncă # de pagini web}}</translation>
<translation id="4923417429809017348">Această pagină a fost tradusă dintr-o limbă necunoscută Ă®n <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Valoarea trebuie specificată.</translation>
<translation id="4930497775425430760">Ai primit acest mesaj deoarece este necesar ca părintele tău să aprobe site-urile noi la prima accesare.</translation>
<translation id="495170559598752135">Acțiuni</translation>
<translation id="4958444002117714549">Extindeți lista</translation>
+<translation id="4962322354953122629">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Chrome nu consideră că certificatul său de securitate este de Ă®ncredere. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Se traduce din <ph name="ORIGINAL_LANGUAGE" /> în <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Acest plugin nu este acceptat</translation>
<translation id="5002932099480077015">Dacă este activată, Chrome va stoca o copie a cardului pe acest dispozitiv, pentru completarea mai rapidă a formularelor.</translation>
<translation id="5019198164206649151">Depozit de fundal Ă®n stare nevalidă</translation>
<translation id="5023310440958281426">Consultați politicile administratorului</translation>
@@ -358,33 +379,32 @@
<translation id="5031870354684148875">Despre Google Traducere</translation>
<translation id="5040262127954254034">Confidențialitate</translation>
<translation id="5045550434625856497">Parolă incorectă</translation>
+<translation id="5056549851600133418">Articole pentru tine</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />să verifici adresa proxy-ului;<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Momentan, certificatul serverului este nevalid.</translation>
<translation id="5089810972385038852">Stat</translation>
-<translation id="5094747076828555589">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; Chromium nu consideră că certificatul său de securitate este de Ă®ncredere. Cauza poate fi o configurare greÈ™ită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="5095208057601539847">Provincie</translation>
<translation id="5115563688576182185">(64 de biți)</translation>
-<translation id="5122371513570456792">S-au găsit <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> pentru â€<ph name="SEARCH_STRING" />â€.</translation>
<translation id="5141240743006678641">Criptează parolele sincronizate cu datele de conectare Google</translation>
<translation id="5145883236150621069">Răspunsul pentru politică include un cod de eroare</translation>
-<translation id="5171045022955879922">Căutați sau introduceți adresa URL</translation>
+<translation id="5171045022955879922">Caută sau introdu adresa URL</translation>
<translation id="5172758083709347301">Computer</translation>
<translation id="5179510805599951267">Nu este Ă®n <ph name="ORIGINAL_LANGUAGE" />? Semnalează această eroare.</translation>
<translation id="5190835502935405962">Bară de marcaje</translation>
<translation id="5199729219167945352">Experimente</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">Folosești Chrome la serviciu? Companiile pot gestiona setările Chrome pentru angajații lor. Află mai multe</translation>
<translation id="5299298092464848405">Eroare la analizarea politicii</translation>
<translation id="5300589172476337783">Afișează</translation>
<translation id="5308689395849655368">Raportarea blocărilor este dezactivată.</translation>
<translation id="5317780077021120954">Salvează</translation>
<translation id="5327248766486351172">Nume</translation>
+<translation id="5359637492792381994">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Momentan, certificatul său de securitate nu este valid. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Setările pentru politică nu au putut fi stocate</translation>
-<translation id="540969355065856584">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; momentan, certificatul de securitate nu este valid. Cauza poate fi o configurare greșită sau interceptarea conexiunii de un atacator.</translation>
<translation id="5421136146218899937">Șterge datele de navigare...</translation>
<translation id="5430298929874300616">Elimină marcajul</translation>
<translation id="5431657950005405462">Fișierul nu a fost găsit</translation>
<translation id="5435775191620395718">Se afișează istoricul de pe acest dispozitiv. <ph name="BEGIN_LINK" />Află mai multe<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Momentan, sugestiile de conținut personalizat sunt dezactivate, deoarece datele sincronizate sunt protejate cu o expresie de acces personalizată.</translation>
<translation id="5439770059721715174">Eroare de validare a schemei la â€<ph name="ERROR_PATH" />â€: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Această pagină de pe <ph name="HOST_NAME" /> nu poate fi găsită</translation>
<translation id="5455374756549232013">Marcaj temporal greșit pentru politică</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Dorești să părăsești acest site?</translation>
<translation id="5629630648637658800">Setările pentru politică nu au putut fi Ă®ncărcate</translation>
<translation id="5631439013527180824">Indicativ nevalid pentru gestionarea gadgetului</translation>
-<translation id="5650551054760837876">Nu au fost găsite rezultate de căutare.</translation>
<translation id="5677928146339483299">Blocat</translation>
<translation id="5710435578057952990">Identitatea acestui site nu a fost confirmată.</translation>
<translation id="5720705177508910913">Utilizator curent</translation>
+<translation id="572328651809341494">File recente</translation>
<translation id="5784606427469807560">A apărut o eroare la confirmarea cardului. Verifică conexiunea la internet È™i Ă®ncearcă din nou.</translation>
<translation id="5785756445106461925">Ăn plus, această pagină include alte resurse care nu sunt securizate. Aceste resurse sunt vizibile pentru alÈ›i utilizatori Ă®n cursul transferului È™i pot fi modificate de un atacator pentru a schimba aspectul paginii.</translation>
+<translation id="5786044859038896871">Dorești să completezi datele cardului de credit?</translation>
+<translation id="5803412860119678065">Dorești să completezi datele <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Conexiunea la <ph name="DOMAIN" /> este criptată folosind o suită de codificare Ă®nvechită.</translation>
<translation id="5813119285467412249">&amp;Repetați adăugarea</translation>
+<translation id="5814352347845180253">Este posibil să pierzi accesul la conținutul premium de pe <ph name="SITE" /> și de pe alte site-uri.</translation>
+<translation id="5843436854350372569">Ai Ă®ncercat să accesezi <ph name="DOMAIN" />, dar serverul a prezentat un certificat care conÈ›ine o cheie slabă. Un atacator ar fi putut sparge cheia privată È™i este posibil ca serverul să nu fie cel care crezi (este posibil să comunici cu un atacator). <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Ai primit acest mesaj deoarece administratorul a blocat acest site.</translation>
<translation id="5857090052475505287">Dosar nou</translation>
<translation id="5869405914158311789">Acest site nu poate fi accesat</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Sugestii parentale</translation>
<translation id="59107663811261420">Acest tip de card nu este acceptat de Google Payments pentru acest comerciant. Selectează alt card.</translation>
<translation id="59174027418879706">Activat</translation>
+<translation id="5926846154125914413">Este posibil să pierzi accesul la conținutul premium de pe anumite site-uri.</translation>
<translation id="5966707198760109579">SăptămĂ¢nă</translation>
<translation id="5967867314010545767">Eliminați din istoric</translation>
<translation id="5975083100439434680">Micșorează</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Automat</translation>
<translation id="6042308850641462728">Mai multe</translation>
<translation id="6060685159320643512">Atenție, aceste experimente pot produce daune</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{niciuna}=1{1}few{#}other{#}}</translation>
<translation id="6146055958333702838">Verifică toate cablurile și repornește routerele, modemurile sau alte
dispozitive de rețea pe care le folosești.</translation>
<translation id="614940544461990577">Ăncearcă:</translation>
<translation id="6150607114729249911">Hopa! Trebuie să-È›i Ă®ntrebi părinÈ›ii dacă poÈ›i accesa această pagină.</translation>
<translation id="6151417162996330722">Certificatul de server are o perioadă de validitate prea lungă.</translation>
-<translation id="6154808779448689242">Indicativul returnat pentru politică nu corespunde cu indicativul actual</translation>
<translation id="6165508094623778733">Află mai multe</translation>
<translation id="6203231073485539293">Verificați conexiunea la internet</translation>
<translation id="6218753634732582820">Elimini adresa din Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">ĂncercaÈ›i să dezactivaÈ›i anticiparea reÈ›elei</translation>
<translation id="6337534724793800597">Filtrați politicile după nume</translation>
<translation id="6342069812937806050">Adineauri</translation>
+<translation id="6345221851280129312">dimensiune necunoscută</translation>
<translation id="6355080345576803305">Modificarea sesiunii publice</translation>
<translation id="6358450015545214790">Ce Ă®nseamnă acestea?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{o altă sugestie}few{alte # sugestii}other{alte # de sugestii}}</translation>
<translation id="6387478394221739770">DoriÈ›i să utilizaÈ›i funcÈ›ii Chrome noi È™i interesante? ĂncercaÈ›i canalul nostru beta de la chrome.com/beta.</translation>
-<translation id="641480858134062906">Adresa <ph name="URL" /> nu s-a Ă®ncărcat</translation>
+<translation id="6389758589412724634">Chromium nu a avut suficientă memorie la afișarea paginii web.</translation>
+<translation id="6416403317709441254">Momentan, nu poÈ›i accesa site-ul <ph name="SITE" />, deoarece acesta a trimis date de conectare Ă®ntr-un format necunoscut pe care Chromium nu le poate procesa. Erorile de reÈ›ea È™i atacurile sunt de obicei temporare È™i probabil că această pagină va funcÈ›iona mai tĂ¢rziu. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Nu se poate verifica dacă certificatul a fost revocat.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> a refuzat conexiunea.</translation>
<translation id="6445051938772793705">Èară</translation>
<translation id="6451458296329894277">Confirmă retrimiterea formularului</translation>
<translation id="6458467102616083041">Valoare ignorată, deoarece politica a dezactivat căutarea prestabilită.</translation>
+<translation id="6462969404041126431">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Este posibil ca certificatul său de securitate să fi fost revocat. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Politici privind dispozitivele</translation>
<translation id="6489534406876378309">ĂncepeÈ›i Ă®ncărcarea rapoartelor de blocare</translation>
<translation id="6529602333819889595">&amp;Repetați ștergerea</translation>
+<translation id="6534179046333460208">Sugestii pentru Webul material</translation>
<translation id="6550675742724504774">Opțiuni</translation>
+<translation id="6593753688552673085">mai puțin de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Opțiuni de criptare</translation>
<translation id="662080504995468778">RămĂ¢i pe pagină</translation>
<translation id="6628463337424475685">Căutare <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Nu puteÈ›i accesa acum site-ul <ph name="SITE" />, deoarece <ph name="BEGIN_LINK" />acest certificat a fost revocat<ph name="END_LINK" />. Erorile de reÈ›ea È™i atacurile sunt de obicei temporare È™i probabil că această pagină va funcÈ›iona mai tĂ¢rziu.</translation>
<translation id="6644283850729428850">Această politică este Ă®nvechită.</translation>
+<translation id="6652240803263749613">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Sistemul de operare al computerului nu consideră că certificatul său de securitate este de Ă®ncredere. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Modificați dosarul</translation>
<translation id="6660210980321319655">Raportată automat <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Elimini sugestia pentru formular din Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Ănapoi</translation>
<translation id="6710594484020273272">&lt;Introdu termenul de căutare&gt;</translation>
<translation id="6711464428925977395">A apărut o problemă la serverul proxy sau adresa nu este corectă.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{niciuna}=1{1 element}few{# elemente}other{# de elemente}}</translation>
<translation id="674375294223700098">Eroare de certificat de server necunoscută.</translation>
<translation id="6753269504797312559">Valoarea politicii</translation>
<translation id="6757797048963528358">Dispozitivul este inactiv.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Nivelul politicii nu este acceptat.</translation>
<translation id="6895330447102777224">Cardul tău este confirmat</translation>
<translation id="6897140037006041989">User Agent</translation>
-<translation id="6903907808598579934">Activează sincronizarea</translation>
<translation id="6915804003454593391">Utilizator:</translation>
<translation id="6957887021205513506">Certificatul serverului pare a fi un fals.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">JudeÈ›</translation>
<translation id="6973656660372572881">Sunt specificate atĂ¢t servere proxy fixe, cĂ¢t È™i o adresă URL pentru scripturi .pac.</translation>
<translation id="6989763994942163495">Afișează setările avansate...</translation>
+<translation id="7000990526846637657">Nu s-au găsit intrări Ă®n istoric</translation>
+<translation id="7009986207543992532">Ai Ă®ncercat să accesezi <ph name="DOMAIN" />, dar serverul a prezentat un certificat a cărui perioadă de valabilitate este prea mare pentru a fi de Ă®ncredere. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Contul Google poate să ofere alte forme ale istoricului de navigare la <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Parole</translation>
-<translation id="7050187094878475250">Ai Ă®ncercat să accesezi <ph name="DOMAIN" />, dar serverul a prezentat un certificat a cărui perioadă de validitate este prea lungă pentru a fi de Ă®ncredere.</translation>
<translation id="7087282848513945231">Comitat</translation>
<translation id="7088615885725309056">Mai vechi</translation>
<translation id="7090678807593890770">Caută <ph name="LINK" /> pe Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Ai primit acest mesaj deoarece este necesar ca administratorul să aprobe site-urile noi la prima accesare.</translation>
<translation id="724975217298816891">Introdu data de expirare și codul CVC pentru <ph name="CREDIT_CARD" />, pentru a actualiza detaliile cardului. După ce confirmi, acest site va avea acces la detaliile cardului tău.</translation>
<translation id="725866823122871198">O conexiune privată la <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nu poate fi stabilită, deoarece data și ora computerului (<ph name="DATE_AND_TIME" />) sunt incorecte.</translation>
-<translation id="7265986070661382626">Nu puteÈ›i accesa acum site-ul <ph name="SITE" />, deoarece acesta <ph name="BEGIN_LINK" />foloseÈ™te fixarea certificatelor<ph name="END_LINK" />. Erorile de reÈ›ea È™i atacurile sunt de obicei temporare È™i probabil că această pagină va funcÈ›iona mai tĂ¢rziu.</translation>
<translation id="7269802741830436641">Această pagină web are o buclă de redirecționare</translation>
<translation id="7275334191706090484">Marcaje gestionate</translation>
<translation id="7298195798382681320">Recomandate</translation>
-<translation id="7301833672208172928">Activează sincronizarea istoricului</translation>
+<translation id="7309308571273880165">Raportul de blocare creat <ph name="CRASH_TIME" /> (utilizatorul a solicitat Ă®ncărcarea, dar nu a fost Ă®ncărcat Ă®ncă)</translation>
<translation id="7334320624316649418">&amp;Repetați reordonarea</translation>
<translation id="733923710415886693">Certificatul serverului nu a fost dezvăluit folosind Transparența certificatului.</translation>
+<translation id="7351800657706554155">Momentan, nu poÈ›i accesa site-ul <ph name="SITE" />, deoarece certificatul acestuia a fost revocat. Erorile de reÈ›ea È™i atacurile sunt de obicei temporare È™i probabil că această pagină va funcÈ›iona mai tĂ¢rziu. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Linie de comandă</translation>
<translation id="7372973238305370288">rezultat al căutării</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="7469372306589899959">Se confirmă cardul</translation>
<translation id="7481312909269577407">Ănainte</translation>
<translation id="7485870689360869515">Nu s-au găsit date.</translation>
+<translation id="7508255263130623398">ID-ul de dispozitiv returnat pentru politică este gol sau nu corespunde cu ID-ul de dispozitiv actual</translation>
<translation id="7514365320538308">Descarcă</translation>
<translation id="7518003948725431193">Nu a fost găsită nicio pagină web pentru adresa: <ph name="URL" /></translation>
<translation id="7537536606612762813">Obligatorie</translation>
<translation id="7542995811387359312">Completarea automată a cardului de credit este dezactivată, deoarece acest formular nu utilizează o conexiune sigură.</translation>
<translation id="7549584377607005141">Pentru a fi afișată corespunzător, această pagină web necesită date pe care le-ați introdus anterior. Puteți trimite aceste date din nou, dar astfel veți repeta orice acțiuni realizate anterior de această pagină.</translation>
<translation id="7554791636758816595">Filă nouă</translation>
-<translation id="7567204685887185387">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; este posibil ca certificatul său de securitate să fi fost emis fraudulos. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="7568593326407688803">Această pagină este Ă®n <ph name="ORIGINAL_LANGUAGE" /> Vrei să fie tradusă?</translation>
<translation id="7569952961197462199">Elimini cardul de credit din Chrome?</translation>
<translation id="7578104083680115302">PlăteÈ™te rapid pe site-uri È™i Ă®n aplicaÈ›ii pe diferite dispozitive folosind cardurile pe care le-ai salvat pe Google.</translation>
+<translation id="7588950540487816470">Web material</translation>
<translation id="7592362899630581445">Certificatul serverului Ă®ncalcă limitările privind numele.</translation>
<translation id="759889825892636187">Momentan, <ph name="HOST_NAME" /> nu poate procesa această solicitare.</translation>
<translation id="7600965453749440009">Nu traduce niciodată din <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="7637571805876720304">Elimini cardul de credit din Chromium?</translation>
<translation id="765676359832457558">Ascundeți setările avansate...</translation>
<translation id="7658239707568436148">Anulează</translation>
+<translation id="7667346355482952095">Indicativul returnat pentru politică este gol sau nu corespunde cu indicativul actual</translation>
<translation id="7668654391829183341">Dispozitiv necunoscut</translation>
<translation id="7674629440242451245">DoriÈ›i să utilizaÈ›i funcÈ›ii Chrome noi È™i interesante? ĂncercaÈ›i canalul nostru pentru dezvoltatori, de la chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Accesați <ph name="SITE" /> (nesigur)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="780301667611848630">Nu, mulțumesc</translation>
<translation id="7805768142964895445">Stare</translation>
<translation id="7813600968533626083">Elimini sugestia pentru formular din Chrome?</translation>
+<translation id="7815407501681723534">S-au găsit <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> pentru â€<ph name="SEARCH_STRING" />â€</translation>
<translation id="785549533363645510">Cu toate acestea, nu eÈ™ti invizibil(ă). Trecerea Ă®n modul incognito nu ascunde activitatea de navigare față de angajator, față de furnizorul de servicii de internet sau față de site-urile pe care le accesezi.</translation>
<translation id="7887683347370398519">Verifică codul CVC È™i Ă®ncearcă din nou</translation>
<translation id="7894616681410591072">Hopa! Este nevoie ca <ph name="NAME" /> să Ă®È›i acorde permisiunea de a accesa această pagină.</translation>
-<translation id="790025292736025802">Adresa <ph name="URL" /> nu a fost găsită</translation>
<translation id="7912024687060120840">Ăn dosarul:</translation>
<translation id="7920092496846849526">Ai Ă®ntrebat părintele dacă poÈ›i accesa această pagină.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="7995512525968007366">Nespecificată</translation>
<translation id="8012647001091218357">Momentan, nu È›i-am putut contacta părinÈ›ii. Ăncearcă din nou.</translation>
<translation id="8034522405403831421">Această pagină este Ă®n <ph name="SOURCE_LANGUAGE" />. DoriÈ›i traducere Ă®n <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Nu au fost găsite intrări Ă®n istoric.</translation>
<translation id="8088680233425245692">Articolul nu a fost vizualizat.</translation>
+<translation id="8089520772729574115">mai puțin de 1 MB</translation>
<translation id="8091372947890762290">Se așteaptă activarea pe server</translation>
+<translation id="8129262335948759431">cantitate necunoscută</translation>
<translation id="8131740175452115882">Confirmați</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Adresa DNS<ph name="END_ABBR" /> pentru serverul <ph name="HOST_NAME" /> nu a putut fi găsită.</translation>
<translation id="8149426793427495338">Computerul este inactiv.</translation>
@@ -604,6 +640,7 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="8201077131113104583">Adresa URL pentru actualizarea extensiei cu ID-ul â€<ph name="EXTENSION_ID" />†nu este validă.</translation>
<translation id="8218327578424803826">Locație atribuită:</translation>
<translation id="8225771182978767009">Persoana care a configurat computerul a ales să blocheze acest site.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Pagina pe care o cauÈ›i a utilizat informaÈ›iile pe care le-ai introdus. Ăntoarcerea la acea pagină ar putea face ca orice acÈ›iune să fie repetată. Vrei să continui?</translation>
<translation id="8249320324621329438">Ultima preluare:</translation>
<translation id="8261506727792406068">Șterge</translation>
@@ -616,12 +653,17 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="8349305172487531364">Bara de marcaje</translation>
<translation id="8363502534493474904">să dezactivezi modul Avion.</translation>
<translation id="8364627913115013041">Nesetată.</translation>
+<translation id="8380941800586852976">Periculos</translation>
<translation id="8412145213513410671">Blocări (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Trebuie să introduci aceeași expresie de acces de două ori.</translation>
<translation id="8428213095426709021">Setări</translation>
+<translation id="8433057134996913067">Astfel, te vei deconecta de pe majoritatea site-urilor.</translation>
<translation id="8437238597147034694">&amp;Anulați mutarea</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 card de credit}few{# carduri de credit}other{# de carduri de credit}}</translation>
+<translation id="8483780878231876732">Pentru a folosi cardurile din Contul Google, conectează-te la Chrome</translation>
<translation id="8488350697529856933">Se aplică pentru</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> a răspuns prea tĂ¢rziu.</translation>
+<translation id="852346902619691059">Acest server nu a putut dovedi că este <ph name="DOMAIN" />. Sistemul de operare al dispozitivului nu consideră că certificatul său de securitate este de Ă®ncredere. Cauza poate fi o eroare de configurare sau interceptarea conexiunii de către un atacator. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Acest tip de card nu este acceptat de Google Payments. Selectează alt card.</translation>
<translation id="8550022383519221471">Serviciul de sincronizare nu este disponibil pentru domeniul tău.</translation>
<translation id="8553075262323480129">Traducerea nu a reușit, deoarece nu a putut fi stabilită limba paginii.</translation>
@@ -633,15 +675,12 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="8647750283161643317">Resetați-le pe toate la valorile prestabilite</translation>
<translation id="8680787084697685621">Datele de conectare la cont au expirat.</translation>
<translation id="8703575177326907206">Conexiunea la <ph name="DOMAIN" /> nu este criptată.</translation>
-<translation id="8713130696108419660">Semnătură inițială incorectă</translation>
<translation id="8725066075913043281">Ăncearcă din nou</translation>
<translation id="8728672262656704056">AÈ›i trecut Ă®n modul incognito</translation>
<translation id="8730621377337864115">Terminat</translation>
<translation id="8738058698779197622">Pentru a stabili o conexiune securizată, ceasul trebuie să fie setat corect. Aceasta deoarece certificatele pe care site-urile le folosesc pentru a se identifica sunt valabile numai pentru anumite intervale de timp. Din moment ce ora de pe dispozitiv este incorectă, Chromium nu poate verifica aceste certificate.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Adresa DNS&lt;/abbr&gt; pentru <ph name="HOST_NAME" /> nu a putut fi găsită. Se diagnostichează problema.</translation>
-<translation id="8741995161408053644">Contul Google poate să ofere alte forme ale istoricului de navigare la <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Repetați ștergerea</translation>
-<translation id="8790687370365610530">Pentru a obține sugestii de conținut personalizat de la Google, activează sincronizarea istoricului.</translation>
<translation id="8798099450830957504">Prestabilit</translation>
<translation id="8804164990146287819">Politica de confidențialitate</translation>
<translation id="8820817407110198400">Marcaje</translation>
@@ -663,13 +702,11 @@ Data viitoare ați putea utiliza combinația <ph name="SHORTCUT_KEY" /> pentru a
<translation id="8971063699422889582">Certificatul serverului a expirat.</translation>
<translation id="8987927404178983737">Lună</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Serverul a prezentat un certificat care nu a fost dezvăluit public folosind politica privind TransparenÈ›a certificatului. Aceasta este o cerință pentru anumite certificate, pentru a se asigura că sunt de Ă®ncredere È™i pentru protecÈ›ie Ă®mpotriva atacatorilor.</translation>
<translation id="9001074447101275817">Pentru a accesa proxy-ul <ph name="DOMAIN" />, trebuie să introduci un nume de utilizator și o parolă.</translation>
<translation id="901974403500617787">Marcajele care se aplică la nivel de sistem pot fi create numai de proprietar: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Această pagină a fost tradusă Ă®n <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">FoloseÈ™te un serviciu de predicÈ›ii pentru a Ă®ncărca paginile mai rapid</translation>
<translation id="9039213469156557790">Ăn plus, această pagină include alte resurse care nu sunt securizate. Aceste resurse sunt vizibile pentru alÈ›i utilizatori Ă®n cursul transferului È™i pot fi modificate de un atacator pentru a schimba comportamentul paginii.</translation>
-<translation id="9049981332609050619">Ai Ă®ncercat să accesezi <ph name="DOMAIN" />, dar serverul a prezentat un certificat nevalid.</translation>
<translation id="9050666287014529139">Expresie de acces</translation>
<translation id="9065203028668620118">Editează</translation>
<translation id="9092364396508701805">Pagina de pe <ph name="HOST_NAME" /> nu funcționează</translation>
diff --git a/chromium/components/strings/components_strings_ru.xtb b/chromium/components/strings/components_strings_ru.xtb
index 4f5976978dc..c842536bd96 100644
--- a/chromium/components/strings/components_strings_ru.xtb
+++ b/chromium/components/strings/components_strings_ru.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ru">
+<translation id="1008557486741366299">Đе ÑĐµĐ¹Ñ‡Đ°Ñ</translation>
<translation id="1015730422737071372">Đ¡Đ¾Đ¾Đ±Ñ‰Đ¸Ñ‚ÑŒ Đ´Đ¾Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ĐµĐ»ÑŒĐ½ÑƒÑ Đ¸Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ</translation>
<translation id="1032854598605920125">ĐŸĐ¾Đ²ĐµÑ€Đ½ÑƒÑ‚ÑŒ Đ¿Đ¾ Ñ‡Đ°ÑĐ¾Đ²Đ¾Đ¹ ÑÑ‚Ñ€ĐµĐ»ĐºĐµ</translation>
<translation id="1038842779957582377">Đ½ĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ¾Đµ Đ¸Đ¼Ñ</translation>
+<translation id="1053591932240354961">Веб-ÑĐ°Đ¹Ñ‚Â <ph name="SITE" /> Đ¾Ñ‚Đ¿Ñ€Đ°Đ²Đ»ÑĐµÑ‚ Chrome Đ½ĐµĐºĐ¾Ñ€Ñ€ĐµĐºÑ‚Đ½Ñ‹Đµ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ, Đ¿Đ¾ÑÑ‚Đ¾Đ¼Ñƒ Đ¾Ñ‚ĐºÑ€Ñ‹Ñ‚ÑŒ ĐµĐ³Đ¾ Đ² Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐµ Đ²Ñ€ĐµĐ¼Ñ Đ½ĐµĐ»ÑŒĐ·Ñ. Đ¡Đ±Đ¾Đ¹ Đ¼Đ¾Đ³ Đ±Ñ‹Ñ‚ÑŒ Đ²Ñ‹Đ·Đ²Đ°Đ½ ÑĐµÑ‚ĐµĐ²Đ¾Đ¹ Đ¾ÑˆĐ¸Đ±ĐºĐ¾Đ¹ или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ². Đ¡ĐºĐ¾Ñ€ĐµĐµ Đ²ÑĐµĐ³Đ¾, ÑĐ°Đ¹Ñ‚ Đ·Đ°Ñ€Đ°Đ±Đ¾Ñ‚Đ°ĐµÑ‚ Ñ‡ĐµÑ€ĐµĐ· Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ²Ñ€ĐµĐ¼Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">&amp;ĐÑ‚Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ Đ´Đ¾Đ±Đ°Đ²Đ»ĐµĐ½Đ¸Đµ</translation>
<translation id="10614374240317010">Đ¡Đ°Đ¹Ñ‚Ñ‹, Đ¿Đ°Ñ€Đ¾Đ»Đ¸ Đ´Đ»Ñ ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Ñ… Đ½Đµ ÑĐ¾Ñ…Ñ€Đ°Đ½ÑÑÑ‚ÑÑ</translation>
-<translation id="1064422015032085147">Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€, Đ½Đ° ĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đ¼ Ñ€Đ°Đ·Đ¼ĐµÑ‰ĐµĐ½Đ° Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°, Đ¿ĐµÑ€ĐµĐ³Ñ€ÑƒĐ¶ĐµĐ½ или Đ½Đ° Đ½ĐµĐ¼ Đ²ĐµĐ´ÑƒÑ‚ÑÑ Ñ€Đ°Đ±Đ¾Ñ‚Ñ‹.
- Đ§Ñ‚Đ¾Đ±Ñ‹ Đ¸Đ·Đ±ĐµĐ¶Đ°Ñ‚ÑŒ ÑƒĐ²ĐµĐ»Đ¸Ñ‡ĐµĐ½Đ¸Ñ Ñ‚Ñ€Đ°Ñ„Đ¸ĐºĐ° и ÑƒÑ…ÑƒĐ´ÑˆĐµĐ½Đ¸Ñ ÑĐ¸Ñ‚ÑƒĐ°Ñ†Đ¸Đ¸,
- Đ·Đ°Đ¿Ñ€Đ¾ÑÑ‹ Đº ÑÑ‚Đ¾Đ¼Ñƒ URL Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¾ Đ·Đ°Đ¿Ñ€ĐµÑ‰ĐµĐ½Ñ‹.</translation>
<translation id="106701514854093668">Đ—Đ°ĐºĐ»Đ°Đ´ĐºĐ¸ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ</translation>
<translation id="1080116354587839789">Đ’Ñ‹Ñ€Đ¾Đ²Đ½ÑÑ‚ÑŒ Đ¿Đ¾ ÑˆĐ¸Ñ€Đ¸Đ½Đµ Đ¾ĐºĐ½Đ°</translation>
+<translation id="1103124106085518534">ĐĐ¾Đ²Ñ‹Ñ… Đ·Đ°ĐºĐ»Đ°Đ´Đ¾Đº Đ½ĐµÑ‚</translation>
<translation id="1103523840287552314">Đ’ÑĐµĐ³Đ´Đ° Đ¿ĐµÑ€ĐµĐ²Đ¾Đ´Đ¸Ñ‚ÑŒ <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Đ•Ñли Ñ„Đ»Đ°Đ¶Đ¾Đº уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½, Chrome Đ±ÑƒĐ´ĐµÑ‚ Ñ…Ñ€Đ°Đ½Đ¸Ñ‚ÑŒ Đ½Đ° ÑÑ‚Đ¾Đ¼ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ ĐºĐ°Ñ€Ñ‚Ñ‹ Đ´Đ»Ñ Đ±Ñ‹ÑÑ‚Ñ€Đ¾Đ³Đ¾ Đ·Đ°Đ¿Đ¾Đ»Đ½ĐµĐ½Đ¸Ñ Ñ„Đ¾Ñ€Đ¼.</translation>
+<translation id="1111153019813902504">ĐĐµĐ´Đ°Đ²Đ½Đ¸Đµ Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
<translation id="1113869188872983271">&amp;ĐÑ‚Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ Đ¸Đ·Đ¼ĐµĐ½ĐµĐ½Đ¸Đµ Đ¿Đ¾Ñ€ÑĐ´ĐºĐ°</translation>
+<translation id="1126551341858583091">ĐœĐµÑÑ‚Đ¾ Đ½Đ° ĐºĐ°Ñ€Ñ‚Đµ Đ¿Đ°Đ¼ÑÑ‚Đ¸: <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Đ’ ĐºĐµÑˆĐµ Đ¿Đ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ¸ Đ¾ÑˆĐ¸Đ±Đ¾Đº Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾</translation>
<translation id="113188000913989374">ĐŸĐ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đµ Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Đµ Đ½Đ° <ph name="SITE" />:</translation>
<translation id="1132774398110320017">ĐĐ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ°Đ²Ñ‚Đ¾Đ·Đ°Đ¿Đ¾Đ»Đ½ĐµĐ½Đ¸Ñ Đ² Chrome...</translation>
-<translation id="1150979032973867961">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. ĐĐ¿ĐµÑ€Đ°Ñ†Đ¸Đ¾Đ½Đ½Đ°Ñ ÑиÑÑ‚ĐµĐ¼Đ° ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đ° Đ½Đµ Đ´Đ¾Đ²ĐµÑ€ÑĐµÑ‚ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Ñƒ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.</translation>
<translation id="1152921474424827756">ĐÑ‚ĐºÑ€Ñ‹Ñ‚ÑŒ <ph name="BEGIN_LINK" />ĐºĐµÑˆĐ¸Ñ€Đ¾Đ²Đ°Đ½Đ½ÑƒÑ Đ²ĐµÑ€ÑиÑ<ph name="END_LINK" /> ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹ <ph name="URL" /></translation>
<translation id="1158211211994409885">Đ¡Đ°Đ¹Ñ‚ <ph name="HOST_NAME" /> Đ½ĐµĐ¾Đ¶Đ¸Đ´Đ°Đ½Đ½Đ¾ Ñ€Đ°Đ·Đ¾Ñ€Đ²Đ°Đ» ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ.</translation>
<translation id="1161325031994447685">ĐŸĐ¾Đ´ĐºĐ»ÑÑ‡Đ¸Ñ‚ĐµÑÑŒ Đº ÑĐµÑ‚Đ¸ Wi-Fi ĐµÑ‰Ñ‘ Ñ€Đ°Đ·.</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ</translation>
<translation id="1201402288615127009">Далее</translation>
<translation id="1201895884277373915">Đ”Ñ€ÑƒĐ³Đ¸Đµ Đ·Đ°Đ¿Đ¸Ñи Đ¿Đ¾ ÑÑ‚Đ¾Đ¼Ñƒ ÑĐ°Đ¹Ñ‚Ñƒ</translation>
-<translation id="121201262018556460">Đ’Ñ‹ Đ¿Đ¾Đ¿Ñ‹Ñ‚Đ°Đ»Đ¸ÑÑŒ Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="DOMAIN" />, Đ½Đ¾ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸Đ» ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ Đ½ĐµĐ½Đ°Đ´ĐµĐ¶Đ½Ñ‹Đ¼ ĐºĐ»ÑÑ‡Đ¾Đ¼. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Ñ‡Đ°ÑÑ‚Đ½Ñ‹Đ¹ ĐºĐ»Ñч Đ±Ñ‹Đ» Đ²Đ·Đ»Đ¾Đ¼Đ°Đ½ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ¼, Đ° ÑĐµÑ€Đ²ĐµÑ€ Đ²Ñ‹Đ´Đ°ĐµÑ‚ ÑĐµĐ±Ñ Đ·Đ° Đ´Ñ€ÑƒĐ³Đ¾Đ¹ (Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾, ÑÑ‚Đ¾ Đ°Ñ‚Đ°ĐºĐ°).</translation>
+<translation id="1206967143813997005">ĐĐ°Ñ‡Đ°Đ»ÑŒĐ½Đ°Ñ Đ¿Đ¾Đ´Đ¿Đ¸ÑÑŒ Đ½ĐµĐ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ‚ĐµĐ»ÑŒĐ½Đ°</translation>
+<translation id="1209206284964581585">Đ¡ĐºÑ€Ñ‹Ñ‚ÑŒ</translation>
<translation id="1219129156119358924">Đ‘ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚ÑŒ ÑиÑÑ‚ĐµĐ¼Ñ‹</translation>
<translation id="1227224963052638717">ĐĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ¾Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾.</translation>
<translation id="1227633850867390598">Đ¡ĐºÑ€Ñ‹Ñ‚ÑŒ Đ·Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Да</translation>
<translation id="1430915738399379752">ĐŸĐµÑ‡Đ°Ñ‚ÑŒ</translation>
<translation id="1442912890475371290">Đ—Đ°Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ¾Đ²Đ°Đ½Đ° Đ¿Đ¾Đ¿Ñ‹Ñ‚ĐºĐ° <ph name="BEGIN_LINK" />Đ¿ĐµÑ€ĐµÑ…Đ¾Đ´Đ° Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ<ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Веб-ÑĐ°Đ¹Ñ‚Â <ph name="SITE" /> иÑĐ¿Đ¾Đ»ÑŒĐ·ÑƒĐµÑ‚ Đ¼ĐµÑ…Đ°Đ½Đ¸Đ·Đ¼ Certificate Pinning, Đ¿Đ¾ÑÑ‚Đ¾Đ¼Ñƒ Đ½Đ° Đ½ĐµĐ¼ Đ¼Đ¾Đ³Đ»Đ° Đ¿Ñ€Đ¾Đ¸Đ·Đ¾Đ¹Ñ‚Đ¸ Đ¿Đ¾Đ´Đ¼ĐµĐ½Đ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°. ĐÑ‚ĐºÑ€Ñ‹Ñ‚ÑŒ ÑĐ°Đ¹Ñ‚ Đ² Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐµ Đ²Ñ€ĐµĐ¼Ñ Đ½ĐµĐ»ÑŒĐ·Ñ. Đ¡Đ±Đ¾Đ¹ Đ¼Đ¾Đ³ Đ±Ñ‹Ñ‚ÑŒ Đ²Ñ‹Đ·Đ²Đ°Đ½ ÑĐµÑ‚ĐµĐ²Đ¾Đ¹ Đ¾ÑˆĐ¸Đ±ĐºĐ¾Đ¹ или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ². Đ¡ĐºĐ¾Ñ€ĐµĐµ Đ²ÑĐµĐ³Đ¾, ÑĐ°Đ¹Ñ‚ Đ·Đ°Ñ€Đ°Đ±Đ¾Ñ‚Đ°ĐµÑ‚ Ñ‡ĐµÑ€ĐµĐ· Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ²Ñ€ĐµĐ¼Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">ĐŸĐ¾ĐºĐ°Đ·Ñ‹Đ²Đ°ĐµÑ‚ Đ¿Ñ€ĐµĐ´Ñ‹Đ´ÑƒÑ‰ÑƒÑ ÑĐ¾Ñ…Ñ€Đ°Đ½ĐµĐ½Đ½ÑƒÑ ĐºĐ¾Đ¿Đ¸Ñ ÑÑ‚Đ¾Đ¹ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹.</translation>
<translation id="1519264250979466059">Đ”Đ°Ñ‚Đ° ÑĐ±Đ¾Ñ€ĐºĐ¸</translation>
<translation id="1549470594296187301">Đ”Đ»Ñ Đ¸ÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Đ½Đ¸Ñ ÑÑ‚Đ¾Đ¹ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¸ Đ½ĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ¾ Đ²ĐºĐ»ÑÑ‡Đ¸Ñ‚ÑŒ JavaScript.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Đ˜Đ¼Đ¿Đ¾Ñ€Ñ‚ Đ½ĐµĐ²Đ¾Đ·Đ¼Đ¾Đ¶ĐµĐ½: Đ½ĐµĐ´Đ¾Đ¿ÑƒÑÑ‚Đ¸Đ¼Đ°Ñ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ ÑĐµÑ‚Đ¸.</translation>
<translation id="1644574205037202324">Đ˜ÑÑ‚Đ¾Ñ€Đ¸Ñ</translation>
<translation id="1645368109819982629">ĐĐµĐ¿Đ¾Đ´Đ´ĐµÑ€Đ¶Đ¸Đ²Đ°ĐµĐ¼Ñ‹Đ¹ Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»</translation>
-<translation id="1655462015569774233">{1,plural, =1{Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº Đ²Ñ‡ĐµÑ€Đ°. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ. ĐĐ±Ñ€Đ°Ñ‚Đ¸Ñ‚Đµ Đ²Đ½Đ¸Đ¼Đ°Đ½Đ¸Đµ, Ñ‡Ñ‚Đ¾ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ²Ñ€ĐµĐ¼Ñ <ph name="CURRENT_DATE" />. Đ•Ñли Đ¾Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.}one{Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº #Â Đ´ĐµĐ½ÑŒ Đ½Đ°Đ·Đ°Đ´. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ. ĐĐ±Ñ€Đ°Ñ‚Đ¸Ñ‚Đµ Đ²Đ½Đ¸Đ¼Đ°Đ½Đ¸Đµ, Ñ‡Ñ‚Đ¾ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ²Ñ€ĐµĐ¼Ñ <ph name="CURRENT_DATE" />. Đ•Ñли Đ¾Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.}few{Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº #Â Đ´Đ½Ñ Đ½Đ°Đ·Đ°Đ´. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ. ĐĐ±Ñ€Đ°Ñ‚Đ¸Ñ‚Đµ Đ²Đ½Đ¸Đ¼Đ°Đ½Đ¸Đµ, Ñ‡Ñ‚Đ¾ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ²Ñ€ĐµĐ¼Ñ <ph name="CURRENT_DATE" />. Đ•Ñли Đ¾Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.}many{Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº #Â Đ´Đ½ĐµĐ¹ Đ½Đ°Đ·Đ°Đ´. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ. ĐĐ±Ñ€Đ°Ñ‚Đ¸Ñ‚Đµ Đ²Đ½Đ¸Đ¼Đ°Đ½Đ¸Đµ, Ñ‡Ñ‚Đ¾ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ²Ñ€ĐµĐ¼Ñ <ph name="CURRENT_DATE" />. Đ•Ñли Đ¾Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.}other{Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº #Â Đ´Đ½Ñ Đ½Đ°Đ·Đ°Đ´. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ. ĐĐ±Ñ€Đ°Ñ‚Đ¸Ñ‚Đµ Đ²Đ½Đ¸Đ¼Đ°Đ½Đ¸Đµ, Ñ‡Ñ‚Đ¾ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ²Ñ€ĐµĐ¼Ñ <ph name="CURRENT_DATE" />. Đ•Ñли Đ¾Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.}}</translation>
<translation id="1676269943528358898">ĐĐ° ÑĐ°Đ¹Ñ‚Đµ <ph name="SITE" /> Đ´Đ»Ñ Đ·Đ°Ñ‰Đ¸Ñ‚Ñ‹ Đ²Đ°ÑˆĐ¸Ñ… Đ´Đ°Đ½Đ½Ñ‹Ñ… Đ¾Đ±Ñ‹Ñ‡Đ½Đ¾ иÑĐ¿Đ¾Đ»ÑŒĐ·ÑƒĐµÑ‚ÑÑ ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¸Đµ. ĐĐ´Đ½Đ°ĐºĐ¾ ÑƒÑ‡ĐµÑ‚Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ, ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¼Ñ‹ Đ¿Đ¾Đ»ÑƒÑ‡Đ¸Đ»Đ¸ Đ¾Ñ‚ ÑĐ°Đ¹Ñ‚Đ° <ph name="SITE" /> ÑĐµĐ¹Ñ‡Đ°Ñ, Đ¾Ñ‚Đ»Đ¸Ñ‡Đ°ÑÑ‚ÑÑ Đ¾Ñ‚ Ñ‚ĐµÑ…, ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¾Đ½ Đ¾Ñ‚Đ¿Ñ€Đ°Đ²Đ»ÑĐµÑ‚ Đ¾Đ±Ñ‹Ñ‡Đ½Đ¾. Đ’ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾, Đ²Ñ€ĐµĐ´Đ¾Đ½Đ¾ÑĐ½Ñ‹Đ¹ ÑĐ°Đ¹Ñ‚ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ²Ñ‹Đ´Đ°Ñ‚ÑŒ ÑĐµĐ±Ñ Đ·Đ° <ph name="SITE" />, Đ»Đ¸Đ±Đ¾ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ¿Đ¾Đ´ĐºĐ»ÑÑ‡ĐµĐ½Đ¸Ñ Đº ÑĐµÑ‚Đ¸ Wi-Fi Đ¿Ñ€ĐµÑ€Đ²Đ°Đ»Đ° ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. Đ’Đ°ÑˆĐ° Đ¸Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ Đ¿Đ¾-Đ¿Ñ€ĐµĐ¶Đ½ĐµĐ¼Ñƒ Đ² Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸, Ñ‚Đ°Đº ĐºĐ°Đº Đ±Ñ€Đ°ÑƒĐ·ĐµÑ€ Google Chrome Ñ€Đ°Đ·Đ¾Ñ€Đ²Đ°Đ» ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ Đ´Đ¾ Ñ‚Đ¾Đ³Đ¾, ĐºĐ°Đº Đ¿Ñ€Đ¾Đ¸Đ·Đ¾ÑˆĐµĐ» Đ¾Đ±Đ¼ĐµĐ½ Đ´Đ°Đ½Đ½Ñ‹Đ¼Đ¸.</translation>
<translation id="168841957122794586">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° ÑĐ¾Đ´ĐµÑ€Đ¶Đ¸Ñ‚ Đ½ĐµĐ½Đ°Đ´ĐµĐ¶Đ½Ñ‹Đ¹ ĐºÑ€Đ¸Đ¿Ñ‚Đ¾Đ³Ñ€Đ°Ñ„Đ¸Ñ‡ĐµÑĐºĐ¸Đ¹ ĐºĐ»Ñч.</translation>
<translation id="1701955595840307032">ĐŸĐ¾Đ»ÑƒÑ‡Đ°Đ¹Ñ‚Đµ Ñ€ĐµĐºĐ¾Đ¼ĐµĐ½Đ´Đ°Ñ†Đ¸Đ¸</translation>
-<translation id="1706954506755087368">{1,plural, =1{Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²ÑÑ‚ÑƒĐ¿Đ¸Ñ‚ Đ² ÑĐ¸Đ»Ñƒ Đ·Đ°Đ²Ñ‚Ñ€Đ°. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.}one{Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²ÑÑ‚ÑƒĐ¿Đ¸Ñ‚ Đ² ÑĐ¸Đ»Ñƒ Ñ‡ĐµÑ€ĐµĐ· #Â Đ´ĐµĐ½ÑŒ. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.}few{Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²ÑÑ‚ÑƒĐ¿Đ¸Ñ‚ Đ² ÑĐ¸Đ»Ñƒ Ñ‡ĐµÑ€ĐµĐ· #Â Đ´Đ½Ñ. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.}many{Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²ÑÑ‚ÑƒĐ¿Đ¸Ñ‚ Đ² ÑĐ¸Đ»Ñƒ Ñ‡ĐµÑ€ĐµĐ· #Â Đ´Đ½ĐµĐ¹. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.}other{Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²ÑÑ‚ÑƒĐ¿Đ¸Ñ‚ Đ² ÑĐ¸Đ»Ñƒ Ñ‡ĐµÑ€ĐµĐ· #Â Đ´Đ½Ñ. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.}}</translation>
<translation id="1710259589646384581">ĐĐ¡</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">ĐĐ±Ñ€Đ°Ñ‚Đ¸Ñ‚ĐµÑÑŒ Đ·Đ° Đ¿Đ¾Đ¼Đ¾Ñ‰ÑŒÑ Đº ÑиÑÑ‚ĐµĐ¼Đ½Đ¾Đ¼Ñƒ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Ñƒ.</translation>
<translation id="17513872634828108">ĐÑ‚ĐºÑ€Ñ‹Ñ‚Ñ‹Đµ Đ²ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
<translation id="1753706481035618306">ĐĐ¾Đ¼ĐµÑ€ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹</translation>
-<translation id="1761412452051366565">Đ§Ñ‚Đ¾Đ±Ñ‹ Đ¼Ñ‹ Đ¼Đ¾Đ³Đ»Đ¸ Ñ€ĐµĐºĐ¾Đ¼ĐµĐ½Đ´Đ¾Đ²Đ°Ñ‚ÑŒ Đ²Đ°Đ¼ Đ¸Đ½Ñ‚ĐµÑ€ĐµÑĐ½Ñ‹Đ¹ ĐºĐ¾Đ½Ñ‚ĐµĐ½Ñ‚, Đ²ĐºĐ»ÑÑ‡Đ¸Ñ‚Đµ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ.</translation>
-<translation id="1763864636252898013">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. ĐĐ¿ĐµÑ€Đ°Ñ†Đ¸Đ¾Đ½Đ½Đ°Ñ ÑиÑÑ‚ĐµĐ¼Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ° Đ½Đµ Đ´Đ¾Đ²ĐµÑ€ÑĐµÑ‚ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Ñƒ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Đ’Ñ‹Đ¿Đ¾Đ»Đ½Đ¸Ñ‚Đµ Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ ÑĐµÑ‚Đ¸ Đ² Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">ĐĐ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ĐºĐ¾Đ´Đ¾Đ²ÑƒÑ Ñ„Ñ€Đ°Đ·Ñƒ Đ´Đ»Ñ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Đ¸.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">ЗдеÑÑŒ Đ¿Đ¾ÑĐ²ÑÑ‚ÑÑ Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ¸, ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ²Ñ‹ Đ½ĐµĐ´Đ°Đ²Đ½Đ¾ Đ¾Ñ‚ĐºÑ€Ñ‹Đ²Đ°Đ»Đ¸.</translation>
<translation id="1821930232296380041">ĐĐµĐ´Đ¾Đ¿ÑƒÑÑ‚Đ¸Đ¼Ñ‹Đ¹ Đ·Đ°Đ¿Ñ€Đ¾Ñ Đ¸Đ»Đ¸ Đ½ĐµĐ²ĐµÑ€Đ½Ñ‹Đµ Đ¿Đ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Ñ‹ Đ·Đ°Đ¿Ñ€Đ¾ÑĐ°</translation>
<translation id="1838667051080421715">Đ’Ñ‹ Đ¿Ñ€Đ¾ÑĐ¼Đ°Ñ‚Ñ€Đ¸Đ²Đ°ĐµÑ‚Đµ ĐºĐ¾Đ´ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹.</translation>
<translation id="1871208020102129563">Đ’Ñ‹Đ±Ñ€Đ°Đ½Đ¾ иÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Đ½Đ¸Đµ Ñ„Đ¸ĐºÑĐ¸Ñ€Đ¾Đ²Đ°Đ½Đ½Ñ‹Ñ… Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ², Đ° Đ½Đµ URL PAC-ÑĐºÑ€Đ¸Đ¿Ñ‚Đ°.</translation>
<translation id="1883255238294161206">Đ¡Đ²ĐµÑ€Đ½ÑƒÑ‚ÑŒ ÑĐ¿Đ¸ÑĐ¾Đº</translation>
<translation id="1898423065542865115">Đ¤Đ¸Đ»ÑŒÑ‚Ñ€Ñ‹</translation>
-<translation id="1911837502049945214">Đ’Đ°Ñˆ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¾Ñ‚ĐºĐ»Đ¾Đ½ĐµĐ½ ÑĐ°Đ¹Ñ‚Đ¾Đ¼ <ph name="HOST_NAME" /> или Đ¿Ñ€Đ¾ÑÑ€Đ¾Ñ‡ĐµĐ½.</translation>
<translation id="194030505837763158">ĐŸĐµÑ€ĐµĐ¹Đ´Đ¸Ñ‚Đµ Đ¿Đ¾ ÑÑÑ‹Đ»ĐºĐµ: <ph name="LINK" /></translation>
<translation id="1962204205936693436">Đ—Đ°ĐºĐ»Đ°Đ´ĐºĐ¸ <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ²Ñ‹Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ÑŒ ÑĐµÑ€Đ¸Đ°Đ»Đ¸Đ·Đ°Ñ†Đ¸Ñ</translation>
<translation id="1974060860693918893">Đ”Đ¾Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ĐµĐ»ÑŒĐ½Ñ‹Đµ</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{и ĐµÑ‰Ñ‘Â 1}one{и ĐµÑ‰Ñ‘Â #}few{и ĐµÑ‰Ñ‘Â #}many{и ĐµÑ‰Ñ‘Â #}other{и ĐµÑ‰Ñ‘Â #}}</translation>
<translation id="2025186561304664664">ĐŸÑ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ°Đ¸Đ²Đ°ĐµÑ‚ÑÑ Đ°Đ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡ĐµÑĐºĐ¸.</translation>
<translation id="2030481566774242610">Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ²Ñ‹ Đ¸Đ¼ĐµĐ»Đ¸ Đ² Đ²Đ¸Đ´Ñƒ <ph name="LINK" />.</translation>
<translation id="2031925387125903299">Đ’Đ°ÑˆĐ¸ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»Đ¸ Đ´Đ¾Đ»Đ¶Đ½Ñ‹ Đ¾Đ´Đ¾Đ±Ñ€Đ¸Ñ‚ÑŒ Đ½Đ¾Đ²Ñ‹Đµ ÑĐ°Đ¹Ñ‚Ñ‹, Ñ‡Ñ‚Đ¾Đ±Ñ‹ Đ²Ñ‹ Đ¼Đ¾Đ³Đ»Đ¸ Đ¸Ñ… Đ¿Đ¾ÑĐµÑ‰Đ°Ñ‚ÑŒ.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Đ° и Đ±Ñ€Đ°Đ½Đ´Đ¼Đ°ÑƒÑÑ€Đ°<ph name="END_LINK" />.</translation>
<translation id="2053553514270667976">ĐŸĐ¾Ñ‡Ñ‚Đ¾Đ²Ñ‹Đ¹ Đ¸Đ½Đ´ĐµĐºÑ</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚}one{#Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚}few{#Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚Đ°}many{#Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚Đ¾Đ²}other{#Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚Đ°}}</translation>
<translation id="2065985942032347596">ĐĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ° Đ°Đ²Ñ‚Đ¾Ñ€Đ¸Đ·Đ°Ñ†Đ¸Ñ</translation>
<translation id="2079545284768500474">ĐÑ‚Đ¼ĐµĐ½Đ°</translation>
<translation id="20817612488360358">Đ’ĐºĐ»ÑÑ‡ĐµĐ½Ñ‹ ÑиÑÑ‚ĐµĐ¼Đ½Ñ‹Đµ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Đ°, Đ½Đ¾ Đ¿Ñ€Đ¸ ÑÑ‚Đ¾Đ¼ ĐµĐ³Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ Đ·Đ°Đ´Đ°Đ½Đ° ÑĐ²Đ½Ñ‹Đ¼ Đ¾Đ±Ñ€Đ°Đ·Đ¾Đ¼.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Đ—Đ°ĐºĐ»Đ°Đ´ĐºĐ°</translation>
<translation id="2166049586286450108">Đ”Đ¾ÑÑ‚ÑƒĐ¿ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Đ° ĐºĐ¾ Đ²ÑĐµĐ¼ Đ´Đ°Đ½Đ½Ñ‹Đ¼</translation>
<translation id="2166378884831602661">Đ­Ñ‚Đ¾Ñ‚ ÑĐ°Đ¹Ñ‚ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¾Đ±ĐµÑĐ¿ĐµÑ‡Đ¸Ñ‚ÑŒ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾Đµ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ</translation>
-<translation id="2171101176734966184">Đ’Ñ‹ Đ¿Đ¾Đ¿Ñ‹Ñ‚Đ°Đ»Đ¸ÑÑŒ Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="DOMAIN" />, Đ¾Đ´Đ½Đ°ĐºĐ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ»ĐµĐ½Đ½Ñ‹Đ¹ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼, Đ¿Đ¾Đ´Đ¿Đ¸ÑĐ°Đ½ Ñ Đ¸ÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Đ½Đ¸ĐµĐ¼ Đ½ĐµĐ½Đ°Đ´ĐµĐ¶Đ½Đ¾Đ³Đ¾ Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚Đ¼Đ°. Đ­Ñ‚Đ¾ Đ¾Đ·Đ½Đ°Ñ‡Đ°ĐµÑ‚, Ñ‡Ñ‚Đ¾ ÑƒÑ‡ĐµÑ‚Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ¼Đ¾Đ³ÑƒÑ‚ Đ±Ñ‹Ñ‚ÑŒ Đ¿Đ¾Đ´Đ´ĐµĐ»ÑŒĐ½Ñ‹Đ¼Đ¸, Đ° ÑĐµÑ€Đ²ĐµÑ€ Đ¼Đ¾Đ¶ĐµÑ‚ Đ²Ñ‹Đ´Đ°Đ²Đ°Ñ‚ÑŒ ÑĐµĐ±Ñ Đ·Đ° Đ´Ñ€ÑƒĐ³Đ¾Đ¹ (Đ²ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾, ÑÑ‚Đ¾ Đ°Ñ‚Đ°ĐºĐ°).</translation>
<translation id="2181821976797666341">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ°</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1Â Đ°Đ´Ñ€ĐµÑ}one{#Â Đ°Đ´Ñ€ĐµÑ}few{#Â Đ°Đ´Ñ€ĐµÑĐ°}many{#Â Đ°Đ´Ñ€ĐµÑĐ¾Đ²}other{#Â Đ°Đ´Ñ€ĐµÑĐ°}}</translation>
<translation id="2212735316055980242">ĐŸĐ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ° Đ´Đ»Ñ ÑƒÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ° Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½Đ°</translation>
<translation id="2213606439339815911">Đ˜Đ·Đ²Đ»ĐµÑ‡ĐµĐ½Đ¸Đµ Đ·Đ°Đ¿Đ¸ÑĐµĐ¹â€¦</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> Đ½ĐµĐ´Đ¾ÑÑ‚ÑƒĐ¿ĐµĐ½</translation>
<translation id="2230458221926704099">Đ§Ñ‚Đ¾Đ±Ñ‹ уÑÑ‚Ñ€Đ°Đ½Đ¸Ñ‚ÑŒ Đ½ĐµĐ¿Đ¾Đ»Đ°Đ´ĐºĐ¸, Đ¿Ñ€Đ¾Đ²ĐµĐ´Đ¸Ñ‚Đµ <ph name="BEGIN_LINK" />Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ<ph name="END_LINK" /> Đ¿Đ¾Đ´ĐºĐ»ÑÑ‡ĐµĐ½Đ¸Ñ.</translation>
+<translation id="2239100178324503013">ĐÑ‚Đ¿Ñ€Đ°Đ²Đ¸Ñ‚ÑŒ</translation>
<translation id="225207911366869382">Đ­Ñ‚Đ¾ Đ·Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ Đ´Đ»Ñ Đ´Đ°Đ½Đ½Đ¾Đ³Đ¾ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ° Đ±Đ¾Đ»ÑŒÑˆĐµ Đ½Đµ иÑĐ¿Đ¾Đ»ÑŒĐ·ÑƒĐµÑ‚ÑÑ.</translation>
<translation id="2262243747453050782">ĐÑˆĐ¸Đ±ĐºĐ° HTTP</translation>
<translation id="2282872951544483773">ĐĐµĐ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Ñ‹Đµ Ñ€Đ°ÑÑˆĐ¸Ñ€ĐµĐ½Đ¸Ñ</translation>
<translation id="2292556288342944218">Đ”Đ¾ÑÑ‚ÑƒĐ¿ Đ² Đ˜Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ·Đ°ĐºÑ€Ñ‹Ñ‚</translation>
<translation id="229702904922032456">Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐºĐ¾Ñ€Đ½ĐµĐ²Đ¾Đ³Đ¾ или Đ¿Ñ€Đ¾Đ¼ĐµĐ¶ÑƒÑ‚Đ¾Ñ‡Đ½Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° иÑÑ‚ĐµĐº.</translation>
<translation id="230155334948463882">Đ”Đ¾Đ±Đ°Đ²Đ¸Ñ‚ÑŒ ĐºĐ°Ñ€Ñ‚Ñƒ?</translation>
+<translation id="2305919008529760154">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ¼Đ¾Đ³ Đ±Ñ‹Ñ‚ÑŒ Đ²Ñ‹Đ¿ÑƒÑ‰ĐµĐ½ Đ¼Đ¾ÑˆĐµĐ½Đ½Đ¸ĐºĐ°Đ¼Đ¸. ĐŸÑ€Đ¾Đ±Đ»ĐµĐ¼Đ° Ñ‚Đ°ĐºĐ¶Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ±Ñ‹Ñ‚ÑŒ ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535">Đ”Đ»Ñ Đ´Đ¾ÑÑ‚ÑƒĐ¿Đ° Đº Đ´Đ¾Đ¼ĐµĐ½Ñƒ <ph name="DOMAIN" /> Đ½ĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ¾ ÑƒĐºĐ°Đ·Đ°Ñ‚ÑŒ Đ¸Đ¼Ñ Đ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ĐµĐ»Ñ Đ¸ Đ¿Đ°Ñ€Đ¾Đ»ÑŒ.</translation>
+<translation id="2318774815570432836">Đ¡Đ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ Ñ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚Đ¾Đ¼ <ph name="SITE" />, иÑĐ¿Đ¾Đ»ÑŒĐ·ÑƒÑÑ‰Đ¸Đ¼ Đ¼ĐµÑ…Đ°Đ½Đ¸Đ·Đ¼ HSTS, Đ¼Đ¾Đ³Đ»Đ¾ Đ±Ñ‹Ñ‚ÑŒ ÑĐºĐ¾Đ¼Đ¿Ñ€Đ¾Đ¼ĐµÑ‚Đ¸Ñ€Đ¾Đ²Đ°Đ½Đ¾, Đ¿Đ¾ÑÑ‚Đ¾Đ¼Ñƒ ĐµĐ³Đ¾ Đ½ĐµĐ»ÑŒĐ·Ñ Đ¾Ñ‚ĐºÑ€Ñ‹Ñ‚ÑŒ Đ² Đ½Đ°ÑÑ‚Đ¾ÑÑ‰Đ¸Đ¹ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚. ĐŸÑ€Đ¾Đ±Đ»ĐµĐ¼Đ° Ñ‚Đ°ĐºĐ¶Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ±Ñ‹Ñ‚ÑŒ ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ². Đ¡ĐºĐ¾Ñ€ĐµĐµ Đ²ÑĐµĐ³Đ¾, ÑĐ°Đ¹Ñ‚ Đ·Đ°Ñ€Đ°Đ±Đ¾Ñ‚Đ°ĐµÑ‚ Ñ‡ĐµÑ€ĐµĐ· Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ²Ñ€ĐµĐ¼Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">ĐŸÑ€Đ¾Đ¿ÑƒÑ‰ĐµĐ½Đ° Đ½ĐµĐ´Đ¾Đ¿ÑƒÑÑ‚Đ¸Đ¼Đ°Ñ Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ°, Đ¸Đ½Đ´ĐµĐºÑ <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Đ”Ñ€ÑƒĐ³Đ¸Đµ Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
<translation id="2359808026110333948">Далее</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" />: Đ¿Đ¾Đ»ÑƒÑ‡ĐµĐ½ Đ¾Ñ‚Ñ‡ĐµÑ‚ Đ¾ ÑĐ±Đ¾Đµ (Đ½Đµ Đ·Đ°Đ³Ñ€ÑƒĐ¶ĐµĐ½)</translation>
<translation id="2367567093518048410">Đ£Ñ€Đ¾Đ²ĐµĐ½ÑŒ</translation>
+<translation id="2371153335857947666">{1,plural, =1{Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº Đ²Ñ‡ĐµÑ€Đ°. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. ЧаÑÑ‹ Đ½Đ° Đ²Đ°ÑˆĐµĐ¼ ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Ñ‹ Đ½Đ°Â <ph name="CURRENT_DATE" />. Đ•Ñли Đ²Ñ€ĐµĐ¼Ñ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" />}one{Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº #Â Đ´ĐµĐ½ÑŒ Đ½Đ°Đ·Đ°Đ´. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. ЧаÑÑ‹ Đ½Đ° Đ²Đ°ÑˆĐµĐ¼ ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Ñ‹ Đ½Đ°Â <ph name="CURRENT_DATE" />. Đ•Ñли Đ²Ñ€ĐµĐ¼Ñ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" />}few{Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº #Â Đ´Đ½Ñ Đ½Đ°Đ·Đ°Đ´. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. ЧаÑÑ‹ Đ½Đ° Đ²Đ°ÑˆĐµĐ¼ ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Ñ‹ Đ½Đ°Â <ph name="CURRENT_DATE" />. Đ•Ñли Đ²Ñ€ĐµĐ¼Ñ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" />}many{Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº #Â Đ´Đ½ĐµĐ¹ Đ½Đ°Đ·Đ°Đ´. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. ЧаÑÑ‹ Đ½Đ° Đ²Đ°ÑˆĐµĐ¼ ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Ñ‹ Đ½Đ°Â <ph name="CURRENT_DATE" />. Đ•Ñли Đ²Ñ€ĐµĐ¼Ñ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" />}other{Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº #Â Đ´Đ½Ñ Đ½Đ°Đ·Đ°Đ´. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. ЧаÑÑ‹ Đ½Đ° Đ²Đ°ÑˆĐµĐ¼ ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Ñ‹ Đ½Đ°Â <ph name="CURRENT_DATE" />. Đ•Ñли Đ²Ñ€ĐµĐ¼Ñ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">ĐĐ¸Ñ‡ĐµĐ³Đ¾ Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾</translation>
<translation id="2384307209577226199">Đ”Đ»Ñ Đ¿Ñ€ĐµĐ´Đ¿Ñ€Đ¸ÑÑ‚Đ¸Đ¹ (Đ¿Đ¾ ÑƒĐ¼Đ¾Đ»Ñ‡Đ°Đ½Đ¸Ñ)</translation>
-<translation id="238526402387145295">ĐŸĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="SITE" /> Đ½ĐµĐ²Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Ñ‚Đ°Đº ĐºĐ°Đº Đ¾Đ½ иÑĐ¿Đ¾Đ»ÑŒĐ·ÑƒĐµÑ‚ <ph name="BEGIN_LINK" />Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ» HSTS<ph name="END_LINK" />. Đ­Ñ‚Đ¾ Đ¼Đ¾Đ³Đ»Đ¾ Đ¿Ñ€Đ¾Đ¸Đ·Đ¾Đ¹Ñ‚Đ¸ из-Đ·Đ° Đ¾ÑˆĐ¸Đ±ĐºĐ¸ ÑĐµÑ‚Đ¸ или Đ°Ñ‚Đ°ĐºĐ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚. Đ¡ĐºĐ¾Ñ€ĐµĐµ Đ²ÑĐµĐ³Đ¾, Đ¾Đ½ Đ·Đ°Ñ€Đ°Đ±Đ¾Ñ‚Đ°ĐµÑ‚ Ñ‡ĐµÑ€ĐµĐ· Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ²Ñ€ĐµĐ¼Ñ.</translation>
<translation id="2386255080630008482">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ¾Ñ‚Đ¾Đ·Đ²Đ°Đ½.</translation>
<translation id="2392959068659972793">ĐŸĐ¾ĐºĐ°Đ·Ñ‹Đ²Đ°Ñ‚ÑŒ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°, Đ·Đ½Đ°Ñ‡ĐµĐ½Đ¸Ñ ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Ñ… Đ½Đµ Đ·Đ°Đ´Đ°Đ½Ñ‹</translation>
<translation id="2396249848217231973">&amp;ĐÑ‚Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ ÑƒĐ´Đ°Đ»ĐµĐ½Đ¸Đµ</translation>
-<translation id="2413528052993050574">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ¼Đ¾Đ¶ĐµÑ‚ Đ±Ñ‹Ñ‚ÑŒ Đ¾Ñ‚Đ¾Đ·Đ²Đ°Đ½. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.</translation>
<translation id="2455981314101692989">ĐĐ° ÑÑ‚Đ¾Đ¹ Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ Đ¾Ñ‚ĐºĐ»ÑÑ‡ĐµĐ½Đ¾ Đ°Đ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡ĐµÑĐºĐ¾Đµ Đ·Đ°Đ¿Đ¾Đ»Đ½ĐµĐ½Đ¸Đµ Ñ„Đ¾Ñ€Đ¼Ñ‹.</translation>
+<translation id="2463739503403862330">Đ—Đ°Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ÑŒ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Đ’Ñ‹Đ¿Đ¾Đ»Đ½Đ¸Ñ‚Đµ Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ ÑĐµÑ‚Đ¸<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">ĐĐµĐ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ‚ĐµĐ»ÑŒĐ½Ñ‹Đ¹ URL Đ¿Đ¾Đ¸ÑĐºĐ¾Đ²Đ¾Đ¹ ÑиÑÑ‚ĐµĐ¼Ñ‹.</translation>
<translation id="2491120439723279231">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° ÑĐ¾Đ´ĐµÑ€Đ¶Đ¸Ñ‚ Đ¾ÑˆĐ¸Đ±ĐºĐ¸.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">ĐÑ‚Đ¿Ñ€Đ°Đ²Đ¸Ñ‚ÑŒ</translation>
<translation id="2674170444375937751">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ ÑÑ‚Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹ из иÑÑ‚Đ¾Ñ€Đ¸Đ¸ Đ¿Đ¾ÑĐµÑ‰ĐµĐ½Đ¸Đ¹?</translation>
<translation id="2677748264148917807">Đ—Đ°ĐºÑ€Ñ‹Ñ‚ÑŒ</translation>
+<translation id="269990154133806163">ĐŸÑ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ»ĐµĐ½Đ½Ñ‹Đ¹ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ½Đµ Đ¿Ñ€Đ¾Ñ…Đ¾Đ´Đ¸Đ» Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐºÑƒ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸. Đ’ Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Ñ… ÑĐ»ÑƒÑ‡Đ°ÑÑ… Đ¾Đ½Đ° Đ½ĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ°, Ñ‡Ñ‚Đ¾Đ±Ñ‹ Đ¾Đ±ĐµÑĐ¿ĐµÑ‡Đ¸Ñ‚ÑŒ Đ½Đ°Đ´ĐµĐ¶Đ½Đ¾ÑÑ‚ÑŒ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° и Đ·Đ°Ñ‰Đ¸Ñ‚Ñƒ Đ¾Ñ‚ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ². <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">Đ—Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ Đ½Đµ ÑĐ¾Đ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²ÑƒĐµÑ‚ Ñ„Đ¾Ñ€Đ¼Đ°Ñ‚Ñƒ.</translation>
<translation id="2704951214193499422">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ Đ´Đ°Đ½Đ½Ñ‹Đµ ĐºĐ°Ñ€Ñ‚Ñ‹. ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ Đ¿Đ¾Đ¿Ñ‹Ñ‚ĐºÑƒ Đ¿Đ¾Đ·Đ¶Đµ.</translation>
<translation id="2705137772291741111">ĐĐµĐ²Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾ Đ¿Ñ€Đ¾Ñ‡Đ¸Ñ‚Đ°Ñ‚ÑŒ ĐºĐ¾Đ¿Đ¸Ñ ÑĐ°Đ¹Ñ‚Đ°, ÑĐ¾Ñ…Ñ€Đ°Đ½ĐµĐ½Đ½ÑƒÑ Đ² ĐºĐµÑˆĐµ.</translation>
<translation id="2709516037105925701">ĐĐ²Ñ‚Đ¾Đ·Đ°Đ¿Đ¾Đ»Đ½ĐµĐ½Đ¸Đµ</translation>
+<translation id="2712118517637785082">Đ’Ñ‹ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ĐµÑÑŒ Đ¾Đ±Ñ€Đ°Ñ‚Đ¸Ñ‚ÑŒÑÑ Đº ÑĐµÑ€Đ²ĐµÑ€Ñƒ Đ² Đ´Đ¾Đ¼ĐµĐ½ĐµÂ <ph name="DOMAIN" />, Đ½Đ¾ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±Ñ‹Đ» Đ¾Ñ‚Đ¾Đ·Đ²Đ°Đ½ Đ¸Đ·Đ´Đ°Ñ‚ĐµĐ»ĐµĐ¼. Đ­Ñ‚Đ¾ Đ¾Đ·Đ½Đ°Ñ‡Đ°ĐµÑ‚, Ñ‡Ñ‚Đ¾ Đ´Đ¾Đ²ĐµÑ€ÑÑ‚ÑŒ Đ¸Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Đ¸ Ñ Đ´Đ°Đ½Đ½Đ¾Đ³Đ¾ Ñ€ĐµÑурÑĐ° Đ½ĐµĐ»ÑŒĐ·Ñ. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ²Ñ‹ Đ¸Đ¼ĐµĐµÑ‚Đµ Đ´ĐµĐ»Đ¾ ÑĐ¾ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ°Đ¼Đ¸. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">ĐŸĐ¾Đ¿Ñ€Đ¾ÑĐ¸Ñ‚ÑŒ Ñ€Đ°Đ·Ñ€ĐµÑˆĐµĐ½Đ¸Ñ</translation>
<translation id="2721148159707890343">Đ—Đ°Đ¿Ñ€Đ¾Ñ Đ²Ñ‹Đ¿Đ¾Đ»Đ½ĐµĐ½ уÑĐ¿ĐµÑˆĐ½Đ¾</translation>
<translation id="2728127805433021124">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ¿Đ¾Đ´Đ¿Đ¸ÑĐ°Đ½ Ñ Đ¸ÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Đ½Đ¸ĐµĐ¼ Đ½ĐµĐ½Đ°Đ´ĐµĐ¶Đ½Đ¾Đ³Đ¾ Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚Đ¼Đ°.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">ĐĐ´Ñ€ĐµÑĐ½Đ°Ñ ÑÑ‚Ñ€Đ¾ĐºĐ° и ÑÑ‚Ñ€Đ¾ĐºĐ° Đ¿Đ¾Đ¸ÑĐºĐ°</translation>
<translation id="2826760142808435982">Đ¡Đ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¾ и Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐµĐ½Đ¾ Ñ Đ¿Đ¾Đ¼Đ¾Ñ‰ÑŒÑ <ph name="CIPHER" />. Đ’ ĐºĐ°Ñ‡ĐµÑÑ‚Đ²Đµ Đ¼ĐµÑ…Đ°Đ½Đ¸Đ·Đ¼Đ° Đ¾Đ±Đ¼ĐµĐ½Đ° ĐºĐ»ÑÑ‡Đ°Đ¼Đ¸ иÑĐ¿Đ¾Đ»ÑŒĐ·ÑƒĐµÑ‚ÑÑ <ph name="KX" />.</translation>
<translation id="2835170189407361413">ĐÑ‡Đ¸ÑÑ‚Đ¸Ñ‚ÑŒ Ñ„Đ¾Ñ€Đ¼Ñƒ</translation>
-<translation id="2837049386027881519">ĐŸÑ€Đ¸ÑˆĐ»Đ¾ÑÑŒ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ½Đ¾ уÑÑ‚Đ°Đ½Đ¾Đ²Đ¸Ñ‚ÑŒ Đ¿Đ¾Đ´ĐºĐ»ÑÑ‡ĐµĐ½Đ¸Đµ Ñ Đ¸ÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Đ½Đ¸ĐµĐ¼ Đ±Đ¾Đ»ĐµĐµ ÑÑ‚Đ°Ñ€Đ¾Đ¹ Đ²ĐµÑ€Ñии Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»Đ° TLS или SSL. ĐĐ±Ñ‹Ñ‡Đ½Đ¾ ÑÑ‚Đ¾ Đ·Đ½Đ°Ñ‡Đ¸Ñ‚, Ñ‡Ñ‚Đ¾ Đ½Đ° ÑĐµÑ€Đ²ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ¾Ñ‡ĐµĐ½ÑŒ ÑÑ‚Đ°Ñ€Đ¾Đµ Đ¿Ñ€Đ¾Đ³Ñ€Đ°Đ¼Đ¼Đ½Đ¾Đµ Đ¾Đ±ĐµÑĐ¿ĐµÑ‡ĐµĐ½Đ¸Đµ, ĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ±Ñ‹Ñ‚ÑŒ Đ½ĐµĐ½Đ°Đ´ĐµĐ¶Đ½Ñ‹Đ¼.</translation>
<translation id="284702764277384724">Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° <ph name="HOST_NAME" /> Ñ„Đ°Đ»ÑŒÑĐ¸Ñ„Đ¸Ñ†Đ¸Ñ€Đ¾Đ²Đ°Đ½.</translation>
<translation id="2889159643044928134">Đе Đ¾Đ±Đ½Đ¾Đ²Đ»ÑÑ‚ÑŒ</translation>
-<translation id="2896499918916051536">ĐŸĐ»Đ°Đ³Đ¸Đ½ Đ½Đµ Đ¿Đ¾Đ´Đ´ĐµÑ€Đ¶Đ¸Đ²Đ°ĐµÑ‚ÑÑ.</translation>
+<translation id="2900469785430194048">Chrome Đ½Đµ Ñ…Đ²Đ°Ñ‚Đ°ĐµÑ‚ Đ¿Đ°Đ¼ÑÑ‚Đ¸ Đ´Đ»Ñ Đ¿Đ¾ĐºĐ°Đ·Đ° ÑÑ‚Đ¾Đ¹ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹.</translation>
<translation id="2909946352844186028">ĐŸĐ¾Ñ…Đ¾Đ¶Đµ, Đ²Ñ‹ Đ¿Đ¾Đ´ĐºĐ»ÑÑ‡Đ¸Đ»Đ¸ÑÑŒ Đº Đ´Ñ€ÑƒĐ³Đ¾Đ¹ ÑĐµÑ‚Đ¸.</translation>
-<translation id="2915500479781995473">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ иÑÑ‚ĐµĐº. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ. ĐĐ±Ñ€Đ°Ñ‚Đ¸Ñ‚Đµ Đ²Đ½Đ¸Đ¼Đ°Đ½Đ¸Đµ, Ñ‡Ñ‚Đ¾ Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ²Ñ€ĐµĐ¼Ñ <ph name="CURRENT_TIME" />. Đ•Ñли Đ¾Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.</translation>
<translation id="2922350208395188000">Đе ÑƒĐ´Đ°ĐµÑ‚ÑÑ Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚ÑŒ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ°.</translation>
-<translation id="2941952326391522266">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ¾Ñ‚Đ½Đ¾ÑĐ¸Ñ‚ÑÑ Đº <ph name="DOMAIN2" />. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.</translation>
<translation id="2948083400971632585">ĐŸÑ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Ñ‹, иÑĐ¿Đ¾Đ»ÑŒĐ·ÑƒĐµĐ¼Ñ‹Đµ Đ´Đ»Ñ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Ñ, Đ¼Đ¾Đ¶Đ½Đ¾ Đ¾Ñ‚ĐºĐ»ÑÑ‡Đ¸Ñ‚ÑŒ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐº.</translation>
<translation id="2955913368246107853">Đ—Đ°ĐºÑ€Ñ‹Ñ‚ÑŒ Đ¿Đ°Đ½ĐµĐ»ÑŒ Đ¿Đ¾Đ¸ÑĐºĐ°</translation>
<translation id="2958431318199492670">ĐĐµĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ ÑĐ»ĐµĐ¼ĐµĐ½Ñ‚Ñ‹ ÑĐµÑ‚ĐµĐ²Đ¾Đ¹ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Đ¸ Đ½ĐµĐ²Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾ Đ¸Đ¼Đ¿Đ¾Ñ€Ñ‚Đ¸Ñ€Đ¾Đ²Đ°Ñ‚ÑŒ, Đ¿Đ¾ÑĐºĐ¾Đ»ÑŒĐºÑƒ Đ¾Đ½Đ° Đ½Đµ ÑĐ¾Đ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²ÑƒĐµÑ‚ ÑÑ‚Đ°Đ½Đ´Đ°Ñ€Ñ‚Ñƒ ONC.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">ĐĐµĐ²ĐµÑ€Đ½Ñ‹Đ¹ Ñ‚Đ¸Đ¿ Đ¿Đ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ¸</translation>
<translation id="3032412215588512954">ĐĐ±Đ½Đ¾Đ²Đ¸Ñ‚ÑŒ Ñту ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ?</translation>
<translation id="3037605927509011580">ĐĐ¿Đ°Đ½ÑŒĐºĐ¸...</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{Đ¿Đ¾ Đ¼ĐµĐ½ÑŒÑˆĐµĐ¹ Đ¼ĐµÑ€Đµ 1Â Đ·Đ°Đ¿Đ¸ÑÑŒ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€ÑƒĐµĐ¼Ñ‹Ñ… уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°Ñ…}=1{1Â Đ·Đ°Đ¿Đ¸ÑÑŒ (Đ½Đµ ÑÑ‡Đ¸Ñ‚Đ°Ñ Đ´Đ°Đ½Đ½Ñ‹Ñ… Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€ÑƒĐµĐ¼Ñ‹Ñ… уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°Ñ…)}one{#Â Đ·Đ°Đ¿Đ¸ÑÑŒ (Đ½Đµ ÑÑ‡Đ¸Ñ‚Đ°Ñ Đ´Đ°Đ½Đ½Ñ‹Ñ… Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€ÑƒĐµĐ¼Ñ‹Ñ… уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°Ñ…)}few{#Â Đ·Đ°Đ¿Đ¸Ñи (Đ½Đµ ÑÑ‡Đ¸Ñ‚Đ°Ñ Đ´Đ°Đ½Đ½Ñ‹Ñ… Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€ÑƒĐµĐ¼Ñ‹Ñ… уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°Ñ…)}many{#Â Đ·Đ°Đ¿Đ¸ÑĐµĐ¹ (Đ½Đµ ÑÑ‡Đ¸Ñ‚Đ°Ñ Đ´Đ°Đ½Đ½Ñ‹Ñ… Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€ÑƒĐµĐ¼Ñ‹Ñ… уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°Ñ…)}other{#Â Đ·Đ°Đ¿Đ¸ÑĐµĐ¹ (Đ½Đµ ÑÑ‡Đ¸Ñ‚Đ°Ñ Đ´Đ°Đ½Đ½Ñ‹Ñ… Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€ÑƒĐµĐ¼Ñ‹Ñ… уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°Ñ…)}}</translation>
<translation id="3041612393474885105">Đ”Đ°Đ½Đ½Ñ‹Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°</translation>
<translation id="3063697135517575841">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ Đ´Đ°Đ½Đ½Ñ‹Đµ ĐºĐ°Ñ€Ñ‚Ñ‹. ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ Đ¿Đ¾Đ¿Ñ‹Ñ‚ĐºÑƒ Đ¿Đ¾Đ·Đ¶Đµ.</translation>
<translation id="3093245981617870298">ĐĐµÑ‚ Đ¿Đ¾Đ´ĐºĐ»ÑÑ‡ĐµĐ½Đ¸Ñ Đº ÑĐµÑ‚Đ¸</translation>
@@ -205,15 +208,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">ĐŸĐ¾ÑĐ»ĐµĐ´Đ½Đ¸Đµ</translation>
<translation id="3207960819495026254">Đ”Đ¾Đ±Đ°Đ²Đ»ĐµĐ½Đ¾ Đ² Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
-<translation id="3225919329040284222">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ½Đµ ÑĐ¾Đ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²ÑƒĐµÑ‚ Đ²ÑÑ‚Ñ€Đ¾ĐµĐ½Đ½Ñ‹Đ¼ Đ¿Đ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ°Đ¼ Đ¾Đ¿Ñ€ĐµĐ´ĐµĐ»ĐµĐ½Đ½Ñ‹Ñ… ÑĐ°Đ¹Ñ‚Đ¾Đ² Ñ Đ²Ñ‹ÑĐ¾ĐºĐ¸Đ¼ ÑƒÑ€Đ¾Đ²Đ½ĐµĐ¼ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸.</translation>
<translation id="3226128629678568754">Đ§Ñ‚Đ¾Đ±Ñ‹ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ½Đ¾ Đ²Đ²ĐµÑÑ‚Đ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ, Đ½ĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Ñ‹Đµ Đ´Đ»Ñ Đ·Đ°Đ³Ñ€ÑƒĐ·ĐºĐ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹, Đ½Đ°Đ¶Đ¼Đ¸Ñ‚Đµ "ĐĐ±Đ½Đ¾Đ²Đ¸Ñ‚ÑŒ".</translation>
<translation id="3228969707346345236">ĐŸĐµÑ€ĐµĐ²Đ¾Đ´ Đ½Đµ ÑƒĐ´Đ°Đ»ÑÑ, Ñ‚Đ°Đº ĐºĐ°Đº ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° ÑƒĐ¶Đµ Đ½Đ°Đ¿Đ¸ÑĐ°Đ½Đ° Đ½Đ° ÑĐ»ĐµĐ´ÑƒÑÑ‰ĐµĐ¼ ÑĐ·Ñ‹ĐºĐµ: <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Đ’Đ²ĐµĐ´Đ¸Ñ‚Đµ CVC-ĐºĐ¾Đ´ ĐºĐ°Ñ€Ñ‚Ñ‹ <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Đ”Đ¾Đ±Đ°Đ²Đ¸Ñ‚ÑŒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ Đ² Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
<translation id="3270847123878663523">&amp;ĐÑ‚Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ Đ¸Đ·Đ¼ĐµĐ½ĐµĐ½Đ¸Đµ Đ¿Đ¾Ñ€ÑĐ´ĐºĐ°</translation>
<translation id="3286538390144397061">ĐŸĐµÑ€ĐµĐ·Đ°Đ¿ÑƒÑÑ‚Đ¸Ñ‚ÑŒ ÑĐµĐ¹Ñ‡Đ°Ñ</translation>
+<translation id="3303855915957856445">ĐĐ¸Ñ‡ĐµĐ³Đ¾ Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾</translation>
<translation id="3305707030755673451">Đ”Đ°Đ½Đ½Ñ‹Đµ Đ±Ñ‹Đ»Đ¸ Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Ñ‹ Ñ Đ¿Đ¾Đ¼Đ¾Ñ‰ÑŒÑ ĐºĐ¾Đ´Đ¾Đ²Đ¾Đ¹ Ñ„Ñ€Đ°Đ·Ñ‹ <ph name="TIME" />. Đ’Đ²ĐµĐ´Đ¸Ñ‚Đµ ее, Ñ‡Ñ‚Đ¾Đ±Ñ‹ Đ½Đ°Ñ‡Đ°Ñ‚ÑŒ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ.</translation>
<translation id="333371639341676808">ĐŸÑ€ĐµĐ´Đ¾Ñ‚Đ²Ñ€Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾Đ·Đ´Đ°Đ½Đ¸Đµ Đ´Đ¾Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ĐµĐ»ÑŒĐ½Ñ‹Ñ… Đ´Đ¸Đ°Đ»Đ¾Đ³Đ¾Đ²Ñ‹Ñ… Đ¾ĐºĐ¾Đ½ Đ½Đ° ÑÑ‚Đ¾Đ¹ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ.</translation>
+<translation id="3338095232262050444">ĐĐ°Đ´ĐµĐ¶Đ½Ñ‹Đ¹</translation>
<translation id="3340978935015468852">Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Ñ…</translation>
<translation id="3345135638360864351">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¾Ñ‚Đ¿Ñ€Đ°Đ²Đ¸Ñ‚ÑŒ Đ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ĐµĐ»Ñ <ph name="NAME" /> Đ·Đ°Đ¿Ñ€Đ¾Ñ Đ½Đ° Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đº ÑÑ‚Đ¾Đ¼Ñƒ ÑĐ°Đ¹Ñ‚Ñƒ. ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ Đ¿Đ¾Đ¿Ñ‹Ñ‚ĐºÑƒ.</translation>
<translation id="3355823806454867987">Đ˜Đ·Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Đ°...</translation>
@@ -231,6 +235,7 @@
<translation id="3452404311384756672">Đ’Ñ‹Đ±ĐµÑ€Đ¸Ñ‚Đµ Đ¸Đ½Ñ‚ĐµÑ€Đ²Đ°Đ»:</translation>
<translation id="3462200631372590220">Đ¡ĐºÑ€Ñ‹Ñ‚ÑŒ Đ¿Đ¾Đ´Ñ€Đ¾Đ±Đ½Đ¾ÑÑ‚Đ¸</translation>
<translation id="3479539252931486093">Đ­Ñ‚Đ¾Ñ‚ ÑĐ°Đ¹Ñ‚ Đ½Đµ Đ´Đ¾Đ»Đ¶ĐµĐ½ Đ±Ñ‹Ñ‚ÑŒ Đ·Đ°Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ¾Đ²Đ°Đ½? <ph name="BEGIN_LINK" />Đ¡Đ¾Đ¾Đ±Ñ‰Đ¸Ñ‚Đµ Đ½Đ°Đ¼ Đ¾Đ± ÑÑ‚Đ¾Đ¼<ph name="END_LINK" />.</translation>
+<translation id="3479552764303398839">Đе ÑĐµĐ¹Ñ‡Đ°Ñ</translation>
<translation id="348000606199325318">Đ˜Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¾Ñ€ ÑĐ±Đ¾Ñ: <ph name="CRASH_LOCAL_ID" /> (Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¾Ñ€ ÑĐµÑ€Đ²ĐµÑ€Đ°: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ ÑĐ²ÑĐ·Đ°Ñ‚ÑŒÑÑ Ñ Đ²Đ°ÑˆĐ¸Đ¼Đ¸ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»ÑĐ¼Đ¸. ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ Đ¿Đ¾Đ¿Ñ‹Ñ‚ĐºÑƒ.</translation>
<translation id="3527085408025491307">ĐŸĐ°Đ¿ĐºĐ°</translation>
@@ -239,6 +244,7 @@
<translation id="3542684924769048008">Đ˜ÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ÑŒ Đ¿Đ°Ñ€Đ¾Đ»ÑŒ Đ´Đ»Ñ:</translation>
<translation id="3549644494707163724">Đ¨Đ¸Ñ„Ñ€Đ¾Đ²Đ°Ñ‚ÑŒ Đ²Ñе ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ¾Đ²Đ°Đ½Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ Ñ Đ¿Đ¾Đ¼Đ¾Ñ‰ÑŒÑ ĐºĐ¾Đ´Đ¾Đ²Đ¾Đ¹ Ñ„Ñ€Đ°Đ·Ñ‹</translation>
<translation id="3549761410225185768">Đ•Ñ‰Ñ‘ <ph name="NUM_TABS_MORE" />…</translation>
+<translation id="3555561725129903880">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²Ñ‹Đ¿ÑƒÑ‰ĐµĐ½ Đ´Đ»Ñ Đ´Đ¾Đ¼ĐµĐ½Đ°Â <ph name="DOMAIN2" />. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">Đ’Đ°ÑˆĐµ Đ¿Đ¾Đ´ĐºĐ»ÑÑ‡ĐµĐ½Đ¸Đµ Đ½Đµ Đ·Đ°Ñ‰Đ¸Ñ‰ĐµĐ½Đ¾</translation>
<translation id="3583757800736429874">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚ÑŒ Đ¿ĐµÑ€ĐµĐ¼ĐµÑ‰ĐµĐ½Đ¸Đµ</translation>
<translation id="3586931643579894722">Đ¡ĐºÑ€Ñ‹Ñ‚ÑŒ Đ¿Đ¾Đ´Ñ€Đ¾Đ±Đ½Đ¾ÑÑ‚Đ¸</translation>
@@ -250,12 +256,15 @@
<translation id="3623476034248543066">ĐŸĐ¾ĐºĐ°Đ·Đ°Ñ‚ÑŒ Đ·Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ</translation>
<translation id="3630155396527302611">Đ•Ñли Đ¿Ñ€Đ¾Đ³Ñ€Đ°Đ¼Đ¼Đ° Đ²Ñ…Đ¾Đ´Đ¸Ñ‚ Đ² ÑĐ¿Đ¸ÑĐ¾Đº Ñ‚ĐµÑ…, ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đ¼ Ñ€Đ°Đ·Ñ€ĐµÑˆĐµĐ½ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đº ÑĐµÑ‚Đ¸,
ÑƒĐ´Đ°Đ»Đ¸Ñ‚Đµ ее из ÑĐ¿Đ¸ÑĐºĐ° и Đ´Đ¾Đ±Đ°Đ²ÑŒÑ‚Đµ Ñ‚ÑƒĐ´Đ° ÑĐ½Đ¾Đ²Đ°.</translation>
+<translation id="3638794133396384728">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° иÑÑ‚ĐµĐº. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. ЧаÑÑ‹ Đ½Đ° Đ²Đ°ÑˆĐµĐ¼ ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Ñ‹ Đ½Đ° <ph name="CURRENT_TIME" />. Đ•Ñли Đ²Ñ€ĐµĐ¼Ñ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾Đµ, Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ ĐµĐ³Đ¾ и Đ¾Đ±Đ½Đ¾Đ²Đ¸Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">Đ­Ñ‚Đ¸ ÑĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ°Đ»ÑŒĐ½Ñ‹Đµ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¸ Đ² Đ»ÑĐ±Đ¾Đ¹ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚ Đ¼Đ¾Đ³ÑƒÑ‚ Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚ÑŒÑÑ, Đ¿Ñ€ĐµĐºÑ€Đ°Ñ‚Đ¸Ñ‚ÑŒ Ñ€Đ°Đ±Đ¾Ñ‚Ñƒ или иÑÑ‡ĐµĐ·Đ½ÑƒÑ‚ÑŒ. ĐœÑ‹ Đ½Đµ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ»ÑĐµĐ¼ Đ½Đ¸ĐºĐ°ĐºĐ¸Ñ… Đ³Đ°Ñ€Đ°Đ½Ñ‚Đ¸Đ¹ Đ¾Ñ‚Đ½Đ¾ÑĐ¸Ñ‚ĐµĐ»ÑŒĐ½Đ¾ Đ²Đ¾Đ·Đ¼Đ¾Đ¶Đ½Ñ‹Ñ… Đ¿Đ¾ÑледÑÑ‚Đ²Đ¸Đ¹ Đ¸Ñ… Đ°ĐºÑ‚Đ¸Đ²Đ°Ñ†Đ¸Đ¸, ĐºÑ€Đ¾Đ¼Đµ Ñ‚Đ¾Đ³Đ¾, Đ¾Đ½Đ¸ Đ¼Đ¾Đ³ÑƒÑ‚ Đ¿Ñ€Đ¸Đ²ĐµÑÑ‚Đ¸ Đº ÑĐ±Đ¾Ñ Đ±Ñ€Đ°ÑƒĐ·ĐµÑ€Đ°. Đ‘Ñ€Đ°ÑƒĐ·ĐµÑ€ Đ¼Đ¾Đ¶ĐµÑ‚ ÑƒĐ´Đ°Đ»Đ¸Ñ‚ÑŒ Đ²Ñе Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ, Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚ÑŒ и ĐºĐ¾Đ½Ñ„Đ¸Đ´ĐµĐ½Ñ†Đ¸Đ°Đ»ÑŒĐ½Đ¾ÑÑ‚ÑŒ Đ´Đ°Đ½Đ½Ñ‹Ñ… Đ¼Đ¾Đ³ÑƒÑ‚ Đ±Ñ‹Ñ‚ÑŒ Đ½Đ°Ñ€ÑƒÑˆĐµĐ½Ñ‹ Đ½ĐµĐ¾Đ¶Đ¸Đ´Đ°Đ½Đ½Ñ‹Ñ… Đ¾Đ±Ñ€Đ°Đ·Đ¾Đ¼. Đ­ĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ°Đ»ÑŒĐ½Ñ‹Đµ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¸, Đ²Ñ‹Đ±Ñ€Đ°Đ½Đ½Ñ‹Đµ Đ¾Đ´Đ½Đ¸Đ¼ Đ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ĐµĐ»ĐµĐ¼, Đ²ĐºĐ»ÑÑ‡Đ°ÑÑ‚ÑÑ Đ´Đ»Ñ Đ²ÑĐµÑ… Đ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ĐµĐ»ĐµĐ¹ Đ±Ñ€Đ°ÑƒĐ·ĐµÑ€Đ° Đ½Đ° ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đµ. Đ¡Đ¾Đ±Đ»ÑĐ´Đ°Đ¹Ñ‚Đµ Đ¾ÑÑ‚Đ¾Ñ€Đ¾Đ¶Đ½Đ¾ÑÑ‚ÑŒ.</translation>
<translation id="3650584904733503804">ĐŸÑ€Đ¾Đ²ĐµÑ€ĐºĐ° Đ²Ñ‹Đ¿Đ¾Đ»Đ½ĐµĐ½Đ° уÑĐ¿ĐµÑˆĐ½Đ¾</translation>
<translation id="3655670868607891010">Đ•Ñли ÑÑ‚Đ° Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° Đ²Đ¾Đ·Đ½Đ¸ĐºĐ°ĐµÑ‚ Ñ‡Đ°ÑÑ‚Đ¾, Đ¸Đ·ÑƒÑ‡Đ¸Ñ‚Đµ <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Đ’ĐµÑ€ÑиÑ</translation>
+<translation id="3678029195006412963">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Đ¿Đ¸ÑĐ°Ñ‚ÑŒ Đ·Đ°Đ¿Ñ€Đ¾Ñ</translation>
<translation id="3681007416295224113">Đ”Đ°Đ½Đ½Ñ‹Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°</translation>
<translation id="3693415264595406141">ĐŸĐ°Ñ€Đ¾Đ»ÑŒ:</translation>
+<translation id="3696411085566228381">Đ½ĐµÑ‚</translation>
<translation id="3700528541715530410">ĐŸĐ¾Ñ…Đ¾Đ¶Đµ, у Đ²Đ°Ñ Đ½ĐµÑ‚ Đ¿Ñ€Đ°Đ² Đ´Đ»Ñ Đ´Đ¾ÑÑ‚ÑƒĐ¿Đ° Đº Đ´Đ°Đ½Đ½Đ¾Đ¹ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Đ—Đ°Đ³Ñ€ÑƒĐ·ĐºĐ°...</translation>
@@ -263,7 +272,6 @@
<translation id="3714780639079136834">Đ’ĐºĐ»ÑÑ‡Đ¸Ñ‚Đµ Wi-Fi или Đ¿ĐµÑ€ĐµĐ´Đ°Ñ‡Ñƒ Đ´Đ°Đ½Đ½Ñ‹Ñ… Đ¿Đ¾ Đ¼Đ¾Đ±Đ¸Đ»ÑŒĐ½Đ¾Đ¹ ÑĐµÑ‚Đ¸.</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Đ°, Đ±Ñ€Đ°Đ½Đ´Đ¼Đ°ÑƒÑÑ€Đ° и DNS<ph name="END_LINK" />.</translation>
<translation id="3739623965217189342">Đ¡ĐºĐ¾Đ¿Đ¸Ñ€Đ¾Đ²Đ°Đ½Đ½Đ°Ñ ÑÑÑ‹Đ»ĐºĐ°</translation>
-<translation id="3744899669254331632">ĐŸĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="SITE" /> Đ½ĐµĐ²Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Ñ‚Đ°Đº ĐºĐ°Đº ĐµĐ³Đ¾ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Ñ‹, и Chrome Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¸Ñ… Đ¾Đ±Ñ€Đ°Đ±Đ¾Ñ‚Đ°Ñ‚ÑŒ. Đ­Ñ‚Đ¾ Đ¼Đ¾Đ³Đ»Đ¾ Đ¿Ñ€Đ¾Đ¸Đ·Đ¾Đ¹Ñ‚Đ¸ из-Đ·Đ° Đ¾ÑˆĐ¸Đ±ĐºĐ¸ ÑĐµÑ‚Đ¸ или Đ°Ñ‚Đ°ĐºĐ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚. Đ¡ĐºĐ¾Ñ€ĐµĐµ Đ²ÑĐµĐ³Đ¾, Đ¾Đ½ Đ·Đ°Ñ€Đ°Đ±Đ¾Ñ‚Đ°ĐµÑ‚ Ñ‡ĐµÑ€ĐµĐ· Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ²Ñ€ĐµĐ¼Ñ.</translation>
<translation id="375403751935624634">Đ¡Đ±Đ¾Đ¹ Đ¿Ñ€Đ¸ Đ¿ĐµÑ€ĐµĐ²Đ¾Đ´Đµ Đ²ÑледÑÑ‚Đ²Đ¸Đµ Đ¾ÑˆĐ¸Đ±ĐºĐ¸ ÑĐµÑ€Đ²ĐµÑ€Đ°.</translation>
<translation id="3759461132968374835">ĐĐµÑ‚ Đ·Đ°Đ¿Đ¸ÑĐµĐ¹ Đ¾ Đ½ĐµĐ´Đ°Đ²Đ½Đ¸Ñ… ÑĐ±Đ¾ÑÑ…. Đ¡Đ±Đ¾Đ¸, ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ€Đ¾Đ¸Đ·Đ¾ÑˆĐ»Đ¸ Đ¿Ñ€Đ¸ Đ¾Ñ‚ĐºĐ»ÑÑ‡ĐµĐ½Đ½Đ¾Đ¹ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¸ Đ·Đ°Đ¿Đ¸Ñи ÑĐ±Đ¾ĐµĐ², здеÑÑŒ Đ½Đµ Đ¾Ñ‚Đ¾Đ±Ñ€Đ°Đ¶Đ°ÑÑ‚ÑÑ.</translation>
<translation id="3788090790273268753">Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Đ´Đ»Ñ ÑÑ‚Đ¾Đ³Đ¾ ÑĐ°Đ¹Ñ‚Đ° иÑÑ‚ĐµĐºĐ°ĐµÑ‚ Đ² 2016Â Đ³Đ¾Đ´Ñƒ. ĐÑ€Đ¾Đ¼Đµ Ñ‚Đ¾Đ³Đ¾, Đ² Ñ†ĐµĐ¿Đ¾Ñ‡ĐºĐµ Đ¿Ñ€Đ¸ÑутÑÑ‚Đ²ÑƒĐµÑ‚ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ Đ¿Đ¾Đ´Đ¿Đ¸ÑÑŒÑ SHA-1.</translation>
@@ -275,19 +283,25 @@
<translation id="3884278016824448484">ĐĐ¾Đ½Ñ„Đ»Đ¸ĐºÑ‚ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¾Ñ€Đ¾Đ² уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²</translation>
<translation id="3885155851504623709">ĐĐºÑ€ÑƒĐ³</translation>
<translation id="3901925938762663762">Đ¡Ñ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ĐºĐ°Ñ€Ñ‚Ñ‹ иÑÑ‚ĐµĐº</translation>
+<translation id="3910267023907260648">Đ’Ñ‹ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ĐµÑÑŒ Đ¾Đ±Ñ€Đ°Ñ‚Đ¸Ñ‚ÑŒÑÑ Đº ÑĐµÑ€Đ²ĐµÑ€Ñƒ Đ² Đ´Đ¾Đ¼ĐµĐ½ĐµÂ <ph name="DOMAIN" />, Đ½Đ¾ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¿Đ¾Đ´Đ¿Đ¸ÑĐ°Đ½ Ñ Đ¿Đ¾Đ¼Đ¾Ñ‰ÑŒÑ Đ½ĐµĐ½Đ°Đ´ĐµĐ¶Đ½Đ¾Đ³Đ¾ Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚Đ¼Đ°. Đ­Ñ‚Đ¾ Đ¾Đ·Đ½Đ°Ñ‡Đ°ĐµÑ‚, Ñ‡Ñ‚Đ¾ ÑƒÑ‡ĐµÑ‚Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ и ÑĐ°Đ¼ ÑĐµÑ€Đ²ĐµÑ€ Đ¼Đ¾Đ³ÑƒÑ‚ Đ¾ĐºĐ°Đ·Đ°Ñ‚ÑŒÑÑ Ñ„Đ°Đ»ÑŒÑˆĐ¸Đ²Ñ‹Đ¼Đ¸. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ²Ñ‹ Đ¸Đ¼ĐµĐµÑ‚Đµ Đ´ĐµĐ»Đ¾ ÑĐ¾ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ°Đ¼Đ¸. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²ÑÑ‚ÑƒĐ¿Đ¸Ñ‚ Đ² ÑĐ¸Đ»Ñƒ Ñ‚Đ¾Đ»ÑŒĐºĐ¾ Đ·Đ°Đ²Ñ‚Ñ€Đ°. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" />}one{Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²ÑÑ‚ÑƒĐ¿Đ¸Ñ‚ Đ² ÑĐ¸Đ»Ñƒ Ñ‚Đ¾Đ»ÑŒĐºĐ¾ Ñ‡ĐµÑ€ĐµĐ· #Â Đ´ĐµĐ½ÑŒ. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" />}few{Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²ÑÑ‚ÑƒĐ¿Đ¸Ñ‚ Đ² ÑĐ¸Đ»Ñƒ Ñ‚Đ¾Đ»ÑŒĐºĐ¾ Ñ‡ĐµÑ€ĐµĐ· #Â Đ´Đ½Ñ. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" />}many{Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²ÑÑ‚ÑƒĐ¿Đ¸Ñ‚ Đ² ÑĐ¸Đ»Ñƒ Ñ‚Đ¾Đ»ÑŒĐºĐ¾ Ñ‡ĐµÑ€ĐµĐ· #Â Đ´Đ½ĐµĐ¹. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" />}other{Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ²ÑÑ‚ÑƒĐ¿Đ¸Ñ‚ Đ² ÑĐ¸Đ»Ñƒ Ñ‚Đ¾Đ»ÑŒĐºĐ¾ Ñ‡ĐµÑ€ĐµĐ· #Â Đ´Đ½Ñ. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ·Đ°Đ³Ñ€ÑƒĐ·Đ¸Ñ‚ÑŒ Đ´Đ¾ĐºÑƒĐ¼ĐµĐ½Ñ‚ PDF</translation>
<translation id="3963721102035795474">Đ ĐµĐ¶Đ¸Đ¼ Ñ‡Ñ‚ĐµĐ½Đ¸Ñ</translation>
+<translation id="397105322502079400">Đ’Ñ‹Ñ‡Đ¸ÑĐ»ĐµĐ½Đ¸Đµâ€¦</translation>
<translation id="3973234410852337861">Đ¡Đ°Đ¹Ñ‚ <ph name="HOST_NAME" /> Đ·Đ°Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ¾Đ²Đ°Đ½</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1Â Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ¿Đ¾Đ±Đ»Đ¸Đ·Đ¾ÑÑ‚Đ¸}one{#Â Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ¿Đ¾Đ±Đ»Đ¸Đ·Đ¾ÑÑ‚Đ¸}few{#Â Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹ Đ¿Đ¾Đ±Đ»Đ¸Đ·Đ¾ÑÑ‚Đ¸}many{#Â Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ† Đ¿Đ¾Đ±Đ»Đ¸Đ·Đ¾ÑÑ‚Đ¸}other{#Â Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹ Đ¿Đ¾Đ±Đ»Đ¸Đ·Đ¾ÑÑ‚Đ¸}}</translation>
<translation id="4021036232240155012">DNS – ÑÑ‚Đ¾ ÑĐµÑ‚ĐµĐ²Đ°Ñ ÑĐ»ÑƒĐ¶Đ±Đ°, Đ¿Ñ€ĐµĐ¾Đ±Ñ€Đ°Đ·ÑƒÑÑ‰Đ°Ñ Đ½Đ°Đ·Đ²Đ°Đ½Đ¸Đµ ÑĐ°Đ¹Ñ‚Đ° Đ² IP-Đ°Đ´Ñ€ĐµÑ.</translation>
<translation id="4030383055268325496">&amp;ĐÑ‚Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ Đ´Đ¾Đ±Đ°Đ²Đ»ĐµĐ½Đ¸Đµ</translation>
-<translation id="4032534284272647190">Đ”Đ¾ÑÑ‚ÑƒĐ¿ Đº <ph name="URL" /> Đ·Đ°Đ¿Ñ€ĐµÑ‰ĐµĐ½.</translation>
<translation id="404928562651467259">Đ’Đ½Đ¸Đ¼Đ°Đ½Đ¸Đµ!</translation>
<translation id="4058922952496707368">ĐĐ»Ñч "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">ĐĐ»Đ¸ĐµĐ½Ñ‚ и ÑĐµÑ€Đ²ĐµÑ€ Đ¿Đ¾Đ´Đ´ĐµÑ€Đ¶Đ¸Đ²Đ°ÑÑ‚ Ñ€Đ°Đ·Đ½Ñ‹Đµ Đ²ĐµÑ€Ñии Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»Đ° SSL или Đ½Đ°Đ±Đ¾Ñ€Đ° ÑˆĐ¸Ñ„Ñ€Đ¾Đ².</translation>
<translation id="4079302484614802869">ĐĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Đ° Đ¿Ñ€ĐµĐ´ÑƒÑĐ¼Đ°Ñ‚Ñ€Đ¸Đ²Đ°ĐµÑ‚ иÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Đ½Đ¸Đµ URL PAC-ÑĐºÑ€Đ¸Đ¿Ñ‚Đ¾Đ² Đ²Đ¼ĐµÑÑ‚Đ¾ Ñ„Đ¸ĐºÑĐ¸Ñ€Đ¾Đ²Đ°Đ½Đ½Ñ‹Ñ… Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ².</translation>
<translation id="4103249731201008433">Đ¡ĐµÑ€Đ¸Đ¹Đ½Ñ‹Đ¹ Đ½Đ¾Đ¼ĐµÑ€ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ° Đ½ĐµĐ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ‚ĐµĐ»ĐµĐ½</translation>
<translation id="4103763322291513355">Đ§Ñ‚Đ¾Đ±Ñ‹ Đ¿Ñ€Đ¾ÑĐ¼Đ¾Ñ‚Ñ€ĐµÑ‚ÑŒ URL, Đ²Đ½ĐµÑĐµĐ½Đ½Ñ‹Đµ Đ² Ñ‡ĐµÑ€Đ½Ñ‹Đ¹ ÑĐ¿Đ¸ÑĐ¾Đº, и Đ´Ñ€ÑƒĐ³Đ¸Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°, Đ·Đ°Đ´Đ°Đ½Đ½Ñ‹Đµ ÑиÑÑ‚ĐµĐ¼Đ½Ñ‹Đ¼ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Đ¾Đ¼, Đ¿ĐµÑ€ĐµĐ¹Đ´Đ¸Ñ‚Đµ Đ¿Đ¾ Đ°Đ´Ñ€ĐµÑу: &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
+<translation id="4110615724604346410">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ ÑĐ¾Đ´ĐµÑ€Đ¶Đ¸Ñ‚ Đ¾ÑˆĐ¸Đ±ĐºĐ¸. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">ĐблаÑÑ‚ÑŒ Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ Đ¿Ñ€Đ°Đ²Đ¸Đ» Đ½Đµ Đ¿Đ¾Đ´Đ´ĐµÑ€Đ¶Đ¸Đ²Đ°ĐµÑ‚ÑÑ.</translation>
+<translation id="4118212371799607889">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Chromium Đ½Đµ ÑÑ‡Đ¸Ñ‚Đ°ĐµÑ‚ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ½Đ°Đ´ĐµĐ¶Đ½Ñ‹Đ¼. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{ĐµÑ‰Ñ‘ 1Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚}one{ĐµÑ‰Ñ‘ #Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚}few{ĐµÑ‰Ñ‘ #Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚Đ°}many{ĐµÑ‰Ñ‘ #Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚Đ¾Đ²}other{ĐµÑ‰Ñ‘ #Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚Đ°}}</translation>
<translation id="4130226655945681476">ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ ÑĐµÑ‚ĐµĐ²Ñ‹Đµ ĐºĐ°Đ±ĐµĐ»Đ¸, Đ¼Đ¾Đ´ĐµĐ¼ и Đ¼Đ°Ñ€ÑˆÑ€ÑƒÑ‚Đ¸Đ·Đ°Ñ‚Đ¾Ñ€.</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Đ¡Đ¾Ñ…Ñ€Đ°Đ½Đ¸Ñ‚ÑŒ Ñту ĐºĐ°Ñ€Ñ‚Ñƒ Đ² Chromium?</translation>
@@ -295,6 +309,7 @@
<translation id="4176463684765177261">ĐÑ‚ĐºĐ»ÑÑ‡ĐµĐ½Đ¾</translation>
<translation id="4196861286325780578">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚ÑŒ Đ¿ĐµÑ€ĐµĐ¼ĐµÑ‰ĐµĐ½Đ¸Đµ</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ±Ñ€Đ°Đ½Đ´Đ¼Đ°ÑƒÑÑ€Đ° и Đ°Đ½Ñ‚Đ¸Đ²Đ¸Ñ€ÑƒÑĐ½Đ¾Đ³Đ¾ ĐŸĐ<ph name="END_LINK" />.</translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{Đ½ĐµÑ‚}=1{1Â Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Đµ ($1)}=2{2Â Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ ($1 и $2)}one{#Â Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Đµ ($1, $2, $3)}few{#Â Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ ($1, $2, $3)}many{#Â Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Đ¹ ($1, $2, $3)}other{#Â Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Ñ ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Đ—Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ¸Đµ Ñ€Đ°Đ±Đ¾Ñ‚Ñ‹ Đ¿Ñ€Đ¾Đ³Ñ€Đ°Đ¼Đ¼Ñ‹</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Đ’Ñ‹Đ¿Đ¾Đ»Đ½Đ¸Ñ‚Đµ Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ ÑĐµÑ‚Đ¸<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">ĐĐµÑ‚</translation>
@@ -303,14 +318,15 @@
<translation id="4269787794583293679">(Đе ÑƒĐºĐ°Đ·Đ°Đ½Đ¾)</translation>
<translation id="4300246636397505754">ĐŸĐ¾Đ´ÑĐºĐ°Đ·ĐºĐ¸ Đ´Đ»Ñ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»ÑŒÑĐºĐ¸Ñ… ÑĐ»ĐµĐ¼ĐµĐ½Ñ‚Đ¾Đ²</translation>
<translation id="4304224509867189079">Đ’Ñ…Đ¾Đ´</translation>
+<translation id="432290197980158659">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸Đ» ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đ¹ Đ½Đµ ÑĐ¾Đ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²ÑƒĐµÑ‚ Ñ‚Ñ€ĐµĐ±Đ¾Đ²Đ°Đ½Đ¸ÑĐ¼ Đ±Ñ€Đ°ÑƒĐ·ĐµÑ€Đ°. Đ­Ñ‚Đ¸ Ñ‚Ñ€ĐµĐ±Đ¾Đ²Đ°Đ½Đ¸Ñ Đ²Ñ‹Đ´Đ²Đ¸Đ³Đ°ÑÑ‚ÑÑ Đ´Đ»Ñ Ñ‚Đ¾Đ³Đ¾, Ñ‡Ñ‚Đ¾Đ±Ñ‹ Đ¾Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ¸Ñ‚ÑŒ Đ²Đ°Ñ Đ¾Ñ‚ иÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Đ½Đ¸Ñ Đ½ĐµĐ½Đ°Đ´ĐµĐ¶Đ½Ñ‹Ñ… ÑĐ°Đ¹Ñ‚Đ¾Đ². <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ½Đ°Đ¹Ñ‚Đ¸ ÑÑ‚Đ°Ñ‚ÑŒÑ</translation>
+<translation id="4331708818696583467">ĐĐµĐ½Đ°Đ´ĐµĐ¶Đ½Ñ‹Đ¹</translation>
<translation id="4372948949327679948">ĐĐ¶Đ¸Đ´Đ°ĐµĐ¼Đ¾Đµ Đ·Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ: <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">Đ’Ñ‹ Đ¿Đ¾Đ¿Ñ‹Ñ‚Đ°Đ»Đ¸ÑÑŒ Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="DOMAIN" />, Đ¾Đ´Đ½Đ°ĐºĐ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚, Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ»ĐµĐ½Đ½Ñ‹Đ¹ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼, Đ±Ñ‹Đ» Đ¾Ñ‚Đ¾Đ·Đ²Đ°Đ½ Đ¸Đ·Đ´Đ°Ñ‚ĐµĐ»ĐµĐ¼. Đ­Ñ‚Đ¾ Đ¾Đ·Đ½Đ°Ñ‡Đ°ĐµÑ‚, Ñ‡Ñ‚Đ¾ ÑƒÑ‡ĐµÑ‚Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸, Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ»ĐµĐ½Đ½Ñ‹Đµ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼, Đ½Đµ Đ·Đ°ÑĐ»ÑƒĐ¶Đ¸Đ²Đ°ÑÑ‚ Đ´Đ¾Đ²ĐµÑ€Đ¸Ñ. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ²Ñ‹ Đ¸Đ¼ĐµĐµÑ‚Đµ Đ´ĐµĐ»Đ¾ ÑĐ¾ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ°Đ¼Đ¸.</translation>
<translation id="4381091992796011497">Đ˜Đ¼Ñ Đ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ĐµĐ»Ñ:</translation>
<translation id="4394049700291259645">ĐÑ‚ĐºĐ»ÑÑ‡Đ¸Ñ‚ÑŒ</translation>
<translation id="4395129973926795186">Đ¡ <ph name="START_DATE" /> Đ¿Đ¾ <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">Đ ĐµĐ·ÑƒĐ»ÑŒÑ‚Đ°Ñ‚Ñ‹ Đ¿Đ¾Đ¸ÑĐºĐ°</translation>
-<translation id="4424024547088906515">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Chrome Đ½Đµ Đ´Đ¾Đ²ĐµÑ€ÑĐµÑ‚ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Ñƒ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.</translation>
+<translation id="4432688616882109544">Đ’Đ°Ñˆ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¾Ñ‚ĐºĐ»Đ¾Đ½ĐµĐ½ ÑĐ°Đ¹Ñ‚Đ¾Đ¼ <ph name="HOST_NAME" /> или Đ½Đµ Đ±Ñ‹Đ» Đ²Ñ‹Đ´Đ°Đ½.</translation>
<translation id="443673843213245140">ĐŸÑ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€ Đ¾Ñ‚ĐºĐ»ÑÑ‡ĐµĐ½, Đ½Đ¾ Đ¿Ñ€Đ¸ ÑÑ‚Đ¾Đ¼ ĐµĐ³Đ¾ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ Đ·Đ°Đ´Đ°Đ½Đ° ÑĐ²Đ½Ñ‹Đ¼ Đ¾Đ±Ñ€Đ°Đ·Đ¾Đ¼.</translation>
<translation id="4458874409874303848">Đ¡Đ°Đ¹Ñ‚ Đ·Đ°Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ¾Đ²Đ°Đ½</translation>
<translation id="4461847750548395463">Đ¡Đ¸ÑÑ‚ĐµĐ¼Đ° Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾Đ³Đ¾ Đ¿Đ¾Đ¸ÑĐºĐ° Google Đ·Đ°Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ¾Đ²Đ°Đ»Đ° ÑÑ‚Đ¾Ñ‚ ÑĐ°Đ¹Ñ‚.</translation>
@@ -322,12 +338,12 @@
<translation id="4522570452068850558">ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµ</translation>
<translation id="4558551763791394412">ĐÑ‚ĐºĐ»ÑÑ‡Đ¸Ñ‚Đµ Ñ€Đ°ÑÑˆĐ¸Ñ€ĐµĐ½Đ¸Ñ.</translation>
<translation id="4587425331216688090">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ Đ°Đ´Ñ€ĐµÑ Đ¸Đ· Chrome?</translation>
+<translation id="4589078953350245614">Đ’Ñ‹ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ĐµÑÑŒ Đ¾Đ±Ñ€Đ°Ñ‚Đ¸Ñ‚ÑŒÑÑ ÑĐµÑ€Đ²ĐµÑ€Ñƒ Đ² Đ´Đ¾Đ¼ĐµĐ½ĐµÂ <ph name="DOMAIN" />, Đ½Đ¾ Đ¾Đ½ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸Đ» Đ½ĐµĐ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ‚ĐµĐ»ÑŒĐ½Ñ‹Đ¹ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459">Đ¡Đ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ Ñ <ph name="DOMAIN" /> Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¾ Ñ Đ¿Đ¾Đ¼Đ¾Ñ‰ÑŒÑ ÑĐ¾Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Ñ‹Ñ… Đ½Đ°Đ±Đ¾Ñ€Đ¾Đ² ÑˆĐ¸Ñ„Ñ€Đ¾Đ².</translation>
<translation id="4594403342090139922">&amp;ĐÑ‚Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ ÑƒĐ´Đ°Đ»ĐµĐ½Đ¸Đµ</translation>
+<translation id="4627442949885028695">ĐŸÑ€Đ¾Đ´Đ¾Đ»Đ¶Đ¸Ñ‚ÑŒ Đ½Đ° Đ´Ñ€ÑƒĐ³Đ¾Đ¼ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đµ</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Đ’Ñ‹ Đ¿Ñ€Đ¾ÑĐ¼Đ°Ñ‚Ñ€Đ¸Đ²Đ°ĐµÑ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ Ñ€Đ°ÑÑˆĐ¸Ñ€ĐµĐ½Đ¸Ñ</translation>
-<translation id="467662567472608290">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ ÑĐ¾Đ´ĐµÑ€Đ¶Đ¸Ñ‚ Đ¾ÑˆĐ¸Đ±ĐºĐ¸. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.</translation>
-<translation id="4697214168136963651">ĐĐ´Ñ€ĐµÑ <ph name="URL" /> Đ·Đ°Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ¾Đ²Đ°Đ½</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Đ¡Đ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ Đ¿Ñ€ĐµÑ€Đ²Đ°Đ½Đ¾</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Đ’Ñ‹Đ¿Đ¾Đ»Đ½Đ¸Ñ‚Đµ Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ ÑĐµÑ‚Đ¸ Đ² Windows<ph name="END_LINK" /></translation>
@@ -335,21 +351,26 @@
<translation id="4728558894243024398">ĐŸĐ»Đ°Ñ‚Ñ„Đ¾Ñ€Đ¼Đ°</translation>
<translation id="4744603770635761495">ĐŸÑƒÑ‚ÑŒ Đº иÑĐ¿Đ¾Đ»Đ½ÑĐµĐ¼Đ¾Đ¼Ñƒ Ñ„Đ°Đ¹Đ»Ñƒ</translation>
<translation id="4756388243121344051">&amp;Đ˜ÑÑ‚Đ¾Ñ€Đ¸Ñ</translation>
+<translation id="4759238208242260848">Đ¡ĐºĐ°Ñ‡Đ°Đ½Đ½Ñ‹Đµ Ñ„Đ°Đ¹Đ»Ñ‹</translation>
<translation id="4764776831041365478">Веб-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ¿Đ¾ Đ°Đ´Ñ€ĐµÑу <ph name="URL" />, Đ²Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ¾ Đ½ĐµĐ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Đ° или Đ¿Đ¾ÑÑ‚Đ¾ÑĐ½Đ½Đ¾ Đ¿ĐµÑ€ĐµĐ¼ĐµÑ‰ĐµĐ½Đ° Đ¿Đ¾ Đ½Đ¾Đ²Đ¾Đ¼Ñƒ Đ°Đ´Ñ€ĐµÑу.</translation>
<translation id="4771973620359291008">ĐŸÑ€Đ¾Đ¸Đ·Đ¾ÑˆĐ»Đ° Đ½ĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ°Ñ Đ¾ÑˆĐ¸Đ±ĐºĐ°.</translation>
<translation id="4782449893814226250">Đ’Đ°ÑˆĐ¸Đ¼ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»ÑĐ¼ Đ¾Ñ‚Đ¿Ñ€Đ°Đ²Đ»ĐµĐ½ Đ·Đ°Đ¿Ñ€Đ¾Ñ Đ½Đ° Đ¿Ñ€Đ¾ÑĐ¼Đ¾Ñ‚Ñ€ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹.</translation>
<translation id="4800132727771399293">ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ ÑÑ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ Đ¸ CVC-ĐºĐ¾Đ´, Đ° Đ·Đ°Ñ‚ĐµĐ¼ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ Đ¿Đ¾Đ¿Ñ‹Ñ‚ĐºÑƒ</translation>
-<translation id="4807049035289105102">ĐŸĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="SITE" /> Đ½ĐµĐ²Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Ñ‚Đ°Đº ĐºĐ°Đº ĐµĐ³Đ¾ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Ñ‹, и Google Chrome Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¸Ñ… Đ¾Đ±Ñ€Đ°Đ±Đ¾Ñ‚Đ°Ñ‚ÑŒ. Đ­Ñ‚Đ¾ Đ¼Đ¾Đ³Đ»Đ¾ Đ¿Ñ€Đ¾Đ¸Đ·Đ¾Đ¹Ñ‚Đ¸ из-Đ·Đ° Đ¾ÑˆĐ¸Đ±ĐºĐ¸ ÑĐµÑ‚Đ¸ или Đ°Ñ‚Đ°ĐºĐ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚. Đ¡ĐºĐ¾Ñ€ĐµĐµ Đ²ÑĐµĐ³Đ¾, Đ¾Đ½ Đ·Đ°Ñ€Đ°Đ±Đ¾Ñ‚Đ°ĐµÑ‚ Ñ‡ĐµÑ€ĐµĐ· Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ²Ñ€ĐµĐ¼Ñ.</translation>
<translation id="4813512666221746211">ĐÑˆĐ¸Đ±ĐºĐ° ÑĐµÑ‚Đ¸</translation>
<translation id="4816492930507672669">ĐŸĐ¾ Ñ€Đ°Đ·Đ¼ĐµÑ€Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹</translation>
<translation id="4850886885716139402">ĐŸĐ¾ÑĐ¼Đ¾Ñ‚Ñ€ĐµÑ‚ÑŒ</translation>
<translation id="4880827082731008257">Đ˜ÑĐºĐ°Ñ‚ÑŒ Đ² иÑÑ‚Đ¾Ñ€Đ¸Đ¸</translation>
+<translation id="4884656795097055129">Đ¡ĐºĐ¾Ñ€Đ¾ здеÑÑŒ Đ¿Đ¾ÑĐ²ÑÑ‚ÑÑ Đ´Ñ€ÑƒĐ³Đ¸Đµ ÑÑ‚Đ°Ñ‚ÑŒĐ¸.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> и <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{и ĐµÑ‰Ñ‘ 1Â Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°}one{и ĐµÑ‰Ñ‘ #Â Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°}few{и ĐµÑ‰Ñ‘ #Â Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹}many{и ĐµÑ‰Ñ‘ #Â Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†}other{и ĐµÑ‰Ñ‘ #Â Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹}}</translation>
<translation id="4923417429809017348">Đ­Ñ‚Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ±Ñ‹Đ»Đ° Đ°Đ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡ĐµÑĐºĐ¸ Đ¿ĐµÑ€ĐµĐ²ĐµĐ´ĐµĐ½Đ° Ñ Đ½ĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ¾Đ³Đ¾ ÑĐ·Ñ‹ĐºĐ° Đ½Đ° <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Đ£ĐºĐ°Đ¶Đ¸Ñ‚Đµ Đ·Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ.</translation>
<translation id="4930497775425430760">Đ’Đ°Ñˆ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»ÑŒ Đ´Đ¾Đ»Đ¶ĐµĐ½ Đ¾Đ´Đ¾Đ±Ñ€Đ¸Ñ‚ÑŒ Đ½Đ¾Đ²Ñ‹Đµ ÑĐ°Đ¹Ñ‚Ñ‹, Ñ‡Ñ‚Đ¾Đ±Ñ‹ Đ²Ñ‹ Đ¼Đ¾Đ³Đ»Đ¸ Đ¸Ñ… Đ¿Đ¾ÑĐµÑ‰Đ°Ñ‚ÑŒ.</translation>
<translation id="495170559598752135">Đ”ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ</translation>
<translation id="4958444002117714549">Đ Đ°Đ·Đ²ĐµÑ€Đ½ÑƒÑ‚ÑŒ ÑĐ¿Đ¸ÑĐ¾Đº</translation>
+<translation id="4962322354953122629">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Chrome Đ½Đµ ÑÑ‡Đ¸Ñ‚Đ°ĐµÑ‚ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ½Đ°Đ´ĐµĐ¶Đ½Ñ‹Đ¼. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911">Đ’Ñ‹Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ÑŒ Đ¿ĐµÑ€ĐµĐ²Đ¾Đ´ (<ph name="ORIGINAL_LANGUAGE" /> &gt; <ph name="TARGET_LANGUAGE" />)?</translation>
+<translation id="4989809363548539747">ĐŸĐ»Đ°Đ³Đ¸Đ½ Đ½Đµ Đ¿Đ¾Đ´Đ´ĐµÑ€Đ¶Đ¸Đ²Đ°ĐµÑ‚ÑÑ</translation>
<translation id="5002932099480077015">Chrome Đ±ÑƒĐ´ĐµÑ‚ Ñ…Ñ€Đ°Đ½Đ¸Ñ‚ÑŒ Đ½Đ° ÑÑ‚Đ¾Đ¼ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ ĐºĐ°Ñ€Ñ‚Ñ‹ Đ´Đ»Ñ Đ±Ñ‹ÑÑ‚Ñ€Đ¾Đ³Đ¾ Đ·Đ°Đ¿Đ¾Đ»Đ½ĐµĐ½Đ¸Ñ Ñ„Đ¾Ñ€Đ¼.</translation>
<translation id="5019198164206649151">Đ”Đ°Đ½Đ½Ñ‹Đµ Đ² Ñ…Ñ€Đ°Đ½Đ¸Đ»Đ¸Ñ‰Đµ Đ¿Đ¾Đ²Ñ€ĐµĐ¶Đ´ĐµĐ½Ñ‹</translation>
<translation id="5023310440958281426">ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°, уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ½Ñ‹Đµ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Đ¾Đ¼</translation>
@@ -357,13 +378,12 @@
<translation id="5031870354684148875">Đ ĐŸĐµÑ€ĐµĐ²Đ¾Đ´Ñ‡Đ¸ĐºĐµ Google</translation>
<translation id="5040262127954254034">Đ›Đ¸Ñ‡Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ</translation>
<translation id="5045550434625856497">ĐĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Ñ‹Đ¹ Đ¿Đ°Ñ€Đ¾Đ»ÑŒ</translation>
+<translation id="5056549851600133418">Đ¡Ñ‚Đ°Ñ‚ÑŒĐ¸ Đ´Đ»Ñ Đ²Đ°Ñ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ Đ°Đ´Ñ€ĐµÑ Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Đ°<ph name="END_LINK" />.</translation>
<translation id="5087286274860437796">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½Đµ Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ‚ĐµĐ»ĐµĐ½ Đ² Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐµ Đ²Ñ€ĐµĐ¼Ñ.</translation>
<translation id="5089810972385038852">Đ¨Ñ‚Đ°Ñ‚</translation>
-<translation id="5094747076828555589">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Chromium Đ½Đµ Đ´Đ¾Đ²ĐµÑ€ÑĐµÑ‚ ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Ñƒ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.</translation>
<translation id="5095208057601539847">ĐŸÑ€Đ¾Đ²Đ¸Đ½Ñ†Đ¸Ñ</translation>
<translation id="5115563688576182185">(64Â Đ±Đ¸Ñ‚)</translation>
-<translation id="5122371513570456792"><ph name="SEARCH_RESULTS" /> Đ¿Đ¾ Đ·Đ°Đ¿Ñ€Đ¾Ñу "<ph name="SEARCH_STRING" />" (<ph name="NUMBER_OF_RESULTS" />).</translation>
<translation id="5141240743006678641">Đ¨Đ¸Ñ„Ñ€Đ¾Đ²Đ°Ñ‚ÑŒ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€Đ¾Đ²Đ°Đ½Đ½Ñ‹Đµ Đ¿Đ°Ñ€Đ¾Đ»Đ¸ Ñ Đ¿Đ¾Đ¼Đ¾Ñ‰ÑŒÑ ÑƒÑ‡ĐµÑ‚Đ½Ñ‹Ñ… Đ´Đ°Đ½Đ½Ñ‹Ñ… Google</translation>
<translation id="5145883236150621069">ĐŸÑ€Đ¸ Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐºĐµ Đ¿Đ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ¸ Đ²Đ¾Đ·Đ²Ñ€Đ°Ñ‰ĐµĐ½ ĐºĐ¾Đ´ Đ¾ÑˆĐ¸Đ±ĐºĐ¸</translation>
<translation id="5171045022955879922">Đ’Đ²ĐµĐ´Đ¸Ñ‚Đµ Đ·Đ°Đ¿Ñ€Đ¾Ñ Đ¸Đ»Đ¸ URL</translation>
@@ -372,18 +392,18 @@
<translation id="5190835502935405962">ĐŸĐ°Đ½ĐµĐ»ÑŒ Đ·Đ°ĐºĐ»Đ°Đ´Đ¾Đº</translation>
<translation id="5199729219167945352">Đ­ĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ°Đ»ÑŒĐ½Ñ‹Đµ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¸</translation>
<translation id="5251803541071282808">ĐĐ±Đ»Đ°ĐºĐ¾</translation>
+<translation id="5277279256032773186">Đ˜ÑĐ¿Đ¾Đ»ÑŒĐ·ÑƒĐµÑ‚Đµ Chrome Đ½Đ° Ñ€Đ°Đ±Đ¾Ñ‚Đµ? Đ£Đ·Đ½Đ°Đ¹Ñ‚Đµ, ĐºĐ°Đº ĐºĐ¾Đ¼Đ¿Đ°Đ½Đ¸Đ¸ Đ¼Đ¾Đ³ÑƒÑ‚ ÑƒĐ¿Ñ€Đ°Đ²Đ»ÑÑ‚ÑŒ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ Chrome Đ½Đ° ĐºĐ¾Ñ€Đ¿Đ¾Ñ€Đ°Ñ‚Đ¸Đ²Đ½Ñ‹Ñ… уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°Ñ….</translation>
<translation id="5299298092464848405">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ²Ñ‹Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ÑŒ Đ°Đ½Đ°Đ»Đ¸Đ· Đ¿Đ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ¸</translation>
<translation id="5300589172476337783">ĐŸĐ¾ĐºĐ°Đ·Đ°Ñ‚ÑŒ</translation>
<translation id="5308689395849655368">ĐÑ‚Ñ‡ĐµÑ‚Ñ‹ Đ¾ ÑĐ±Đ¾ÑÑ… Đ¾Ñ‚ĐºĐ»ÑÑ‡ĐµĐ½Ñ‹.</translation>
<translation id="5317780077021120954">Đ¡Đ¾Ñ…Ñ€Đ°Đ½Đ¸Ñ‚ÑŒ</translation>
<translation id="5327248766486351172">ĐĐ°Đ·Đ²Đ°Đ½Đ¸Đµ</translation>
+<translation id="5359637492792381994">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />, ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ² Đ½Đ°ÑÑ‚Đ¾ÑÑ‰Đ¸Đ¹ Đ¼Đ¾Đ¼ĐµĐ½Ñ‚ Đ½ĐµĐ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ‚ĐµĐ»ĐµĐ½. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ ÑĐ¾Ñ…Ñ€Đ°Đ½Đ¸Ñ‚ÑŒ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ¿Đ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ¸</translation>
-<translation id="540969355065856584">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ¼Đ¾Đ¶ĐµÑ‚ Đ±Ñ‹Ñ‚ÑŒ Đ½ĐµĐ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ‚ĐµĐ»ĐµĐ½ Đ² Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐµ Đ²Ñ€ĐµĐ¼Ñ. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.</translation>
<translation id="5421136146218899937">ĐÑ‡Đ¸ÑÑ‚Đ¸Ñ‚ÑŒ иÑÑ‚Đ¾Ñ€Đ¸Ñ...</translation>
<translation id="5430298929874300616">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ Đ·Đ°ĐºĐ»Đ°Đ´ĐºÑƒ</translation>
<translation id="5431657950005405462">Đ¤Đ°Đ¹Đ» Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½</translation>
<translation id="5435775191620395718">ĐŸĐ¾ĐºĐ°Đ·Đ°Đ½Đ° иÑÑ‚Đ¾Ñ€Đ¸Ñ Ñ‚Đ¾Đ»ÑŒĐºĐ¾ Ñ ÑÑ‚Đ¾Đ³Đ¾ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°. <ph name="BEGIN_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">Đ’Ñ‹ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ¿Đ¾Đ»ÑƒÑ‡Đ°Ñ‚ÑŒ Ñ€ĐµĐºĐ¾Đ¼ĐµĐ½Đ´Đ°Ñ†Đ¸Đ¸ Đ¿Đ¾ ĐºĐ¾Đ½Ñ‚ĐµĐ½Ñ‚Ñƒ, Đ¿Đ¾ÑĐºĐ¾Đ»ÑŒĐºÑƒ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¸Ñ€ÑƒĐµĐ¼Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ Đ·Đ°Ñ‰Đ¸Ñ‰ĐµĐ½Ñ‹ ĐºĐ¾Đ´Đ¾Đ²Đ¾Đ¹ Ñ„Ñ€Đ°Đ·Đ¾Đ¹.</translation>
<translation id="5439770059721715174">ĐÑˆĐ¸Đ±ĐºĐ° Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐºĐ¸ ÑÑ…ĐµĐ¼Ñ‹, <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Đ¡Ñ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° <ph name="HOST_NAME" /> Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½Đ°</translation>
<translation id="5455374756549232013">ĐĐµĐ²ĐµÑ€Đ½Đ°Ñ Đ²Ñ€ĐµĐ¼ĐµĐ½Đ½Đ°Ñ Đ¼ĐµÑ‚ĐºĐ° Đ¿Đ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ¸</translation>
@@ -406,14 +426,18 @@
<translation id="5622887735448669177">ĐŸĐ¾ĐºĐ¸Đ½ÑƒÑ‚ÑŒ Ñту ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ?</translation>
<translation id="5629630648637658800">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Ñ€Đ¸Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ¿Đ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ¸</translation>
<translation id="5631439013527180824">Đ¢Đ¾ĐºĐµĐ½ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ° Đ½ĐµĐ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ‚ĐµĐ»ĐµĐ½</translation>
-<translation id="5650551054760837876">ĐĐ¸Ñ‡ĐµĐ³Đ¾ Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾.</translation>
<translation id="5677928146339483299">Đ—Đ°Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ¾Đ²Đ°Đ½Đ¾</translation>
<translation id="5710435578057952990">Đ˜Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ ÑÑ‚Đ¾Đ³Đ¾ ÑĐ°Đ¹Ñ‚Đ° Đ½Đµ Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐµĐ½Ñ‹.</translation>
<translation id="5720705177508910913">Đ¢ĐµĐºÑƒÑ‰Đ¸Đ¹ Đ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ĐµĐ»ÑŒ</translation>
+<translation id="572328651809341494">ĐĐµĐ´Đ°Đ²Đ½Đ¸Đµ Đ²ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
<translation id="5784606427469807560">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ Đ´Đ°Đ½Đ½Ñ‹Đµ ĐºĐ°Ñ€Ñ‚Ñ‹. ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ Đ¿Đ¾Đ´ĐºĐ»ÑÑ‡ĐµĐ½Đ¸Đµ Đº Đ˜Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚Ñƒ и Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ Đ¿Đ¾Đ¿Ñ‹Ñ‚ĐºÑƒ.</translation>
<translation id="5785756445106461925">ĐĐ±Ñ€Đ°Ñ‚Đ¸Ñ‚Đµ Đ²Đ½Đ¸Đ¼Đ°Đ½Đ¸Đµ, Ñ‡Ñ‚Đ¾ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ Đ¾Đ±Đ½Đ°Ñ€ÑƒĐ¶ĐµĐ½ Đ½ĐµĐ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Ñ‹Đ¹ ĐºĐ¾Đ½Ñ‚ĐµĐ½Ñ‚. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¸ Đ¿ĐµÑ€ĐµĐ´Đ°Ñ‡Đµ Ñ€ĐµÑурÑÑ‹ Đ¿Ñ€Đ¾ÑĐ¼Đ°Ñ‚Ñ€Đ¸Đ²Đ°ÑÑ‚ÑÑ Ñ‚Ñ€ĐµÑ‚ÑŒĐ¸Đ¼Đ¸ Đ»Đ¸Ñ†Đ°Đ¼Đ¸, Đ° Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¸ Đ¼Đ¾Đ³ÑƒÑ‚ Đ¿Đ¾Đ»ÑƒÑ‡Đ¸Ñ‚ÑŒ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đº ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ и Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ ее Đ¿Đ¾Đ²ĐµĐ´ĐµĐ½Đ¸Đµ или Đ²Đ½ĐµÑˆĐ½Đ¸Đ¹ Đ²Đ¸Đ´.</translation>
+<translation id="5786044859038896871">Đ—Đ°Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ÑŒ Đ´Đ°Đ½Đ½Ñ‹Đµ Đ±Đ°Đ½ĐºĐ¾Đ²ÑĐºĐ¾Đ¹ ĐºĐ°Ñ€Ñ‚Ñ‹?</translation>
+<translation id="5803412860119678065">Đ—Đ°Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ÑŒ Đ´Đ°Đ½Đ½Ñ‹Đµ Đ±Đ°Đ½ĐºĐ¾Đ²ÑĐºĐ¾Đ¹ ĐºĐ°Ñ€Ñ‚Ñ‹ <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Đ¡Đ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ Ñ <ph name="DOMAIN" /> Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¾ Ñ Đ¿Đ¾Đ¼Đ¾Ñ‰ÑŒÑ ÑƒÑÑ‚Đ°Ñ€ĐµĐ²ÑˆĐµĐ³Đ¾ Đ½Đ°Đ±Đ¾Ñ€Đ° ÑˆĐ¸Ñ„Ñ€Đ¾Đ².</translation>
<translation id="5813119285467412249">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚ÑŒ Đ´Đ¾Đ±Đ°Đ²Đ»ĐµĐ½Đ¸Đµ</translation>
+<translation id="5814352347845180253">Đ’Ñ‹ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ¿Đ¾Ñ‚ĐµÑ€ÑÑ‚ÑŒ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đº Đ¿Ñ€ĐµĐ¼Đ¸ÑƒĐ¼-ĐºĐ¾Đ½Ñ‚ĐµĐ½Ñ‚Ñƒ Đ½Đ° <ph name="SITE" /> и Đ´Ñ€ÑƒĐ³Đ¸Ñ… ÑĐ°Đ¹Ñ‚Đ°Ñ….</translation>
+<translation id="5843436854350372569">Đ’Ñ‹ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ĐµÑÑŒ Đ¾Đ±Ñ€Đ°Ñ‚Đ¸Ñ‚ÑŒÑÑ Đº ÑĐµÑ€Đ²ĐµÑ€Ñƒ Đ² Đ´Đ¾Đ¼ĐµĐ½ĐµÂ <ph name="DOMAIN" />, Đ½Đ¾ Đ¾Đ½ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸Đ» ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ Đ½ĐµĐ½Đ°Đ´ĐµĐ¶Đ½Ñ‹Đ¼ ĐºĐ»ÑÑ‡Đ¾Đ¼. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ²Ñ‹ Đ¸Đ¼ĐµĐµÑ‚Đµ Đ´ĐµĐ»Đ¾ ÑĐ¾ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ¼, ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đ¹ Đ²Đ·Đ»Đ¾Đ¼Đ°Đ» Đ·Đ°ĐºÑ€Ñ‹Ñ‚Ñ‹Đ¹ ĐºĐ»Ñч. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">Đ­Ñ‚Đ¾Ñ‚ ÑĐ°Đ¹Ñ‚ Đ·Đ°Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ¾Đ²Đ°Đ½ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Đ¾Đ¼.</translation>
<translation id="5857090052475505287">ĐĐ¾Đ²Đ°Ñ Đ¿Đ°Đ¿ĐºĐ°</translation>
<translation id="5869405914158311789">Đе ÑƒĐ´Đ°ĐµÑ‚ÑÑ Đ¿Đ¾Đ»ÑƒÑ‡Đ¸Ñ‚ÑŒ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đº ÑĐ°Đ¹Ñ‚Ñƒ</translation>
@@ -421,6 +445,7 @@
<translation id="5872918882028971132">ĐŸĐ¾Đ´ÑĐºĐ°Đ·ĐºĐ¸ Đ´Đ»Ñ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»ÑŒÑĐºĐ¸Ñ… ÑĐ»ĐµĐ¼ĐµĐ½Ñ‚Đ¾Đ²</translation>
<translation id="59107663811261420">Đ¡ĐµÑ€Đ²Đ¸Ñ Google Payments Đ½Đµ Đ¿Đ¾Đ´Đ´ĐµÑ€Đ¶Đ¸Đ²Đ°ĐµÑ‚ ĐºĐ°Ñ€Ñ‚Ñ‹ ÑÑ‚Đ¾Đ³Đ¾ Ñ‚Đ¸Đ¿Đ° Đ´Đ»Ñ Đ´Đ°Đ½Đ½Đ¾Đ³Đ¾ Đ¿Ñ€Đ¾Đ´Đ°Đ²Ñ†Đ°. Đ’Ñ‹Đ±ĐµÑ€Đ¸Ñ‚Đµ Đ´Ñ€ÑƒĐ³ÑƒÑ ĐºĐ°Ñ€Ñ‚Ñƒ.</translation>
<translation id="59174027418879706">Đ’ĐºĐ»ÑÑ‡ĐµĐ½Đ¾</translation>
+<translation id="5926846154125914413">Đ’Ñ‹ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ¿Đ¾Ñ‚ĐµÑ€ÑÑ‚ÑŒ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đº Đ¿Ñ€ĐµĐ¼Đ¸ÑƒĐ¼-ĐºĐ¾Đ½Ñ‚ĐµĐ½Ñ‚Ñƒ Đ½Đ° Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Ñ… ÑĐ°Đ¹Ñ‚Đ°Ñ….</translation>
<translation id="5966707198760109579">ĐеделÑ</translation>
<translation id="5967867314010545767">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ из иÑÑ‚Đ¾Ñ€Đ¸Đ¸</translation>
<translation id="5975083100439434680">Đ£Đ¼ĐµĐ½ÑŒÑˆĐ¸Ñ‚ÑŒ</translation>
@@ -432,12 +457,12 @@
<translation id="604124094241169006">ĐĐ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡ĐµÑĐºĐ¸</translation>
<translation id="6042308850641462728">ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµ...</translation>
<translation id="6060685159320643512">Đ‘ÑƒĐ´ÑŒÑ‚Đµ Đ¾ÑÑ‚Đ¾Ñ€Đ¾Đ¶Đ½Ñ‹ Đ¿Ñ€Đ¸ Ñ€Đ°Đ±Đ¾Ñ‚Đµ Ñ ÑĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ°Đ»ÑŒĐ½Đ¾Đ¹ Đ²ĐµÑ€ÑĐ¸ĐµĐ¹</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{Đ½ĐµÑ‚}=1{1}one{#}few{#}many{#}other{#}}</translation>
<translation id="6146055958333702838">ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ ĐºĐ°Đ±ĐµĐ»ĐµĐ¹, Đ¿ĐµÑ€ĐµĐ·Đ°Đ³Ñ€ÑƒĐ·Đ¸Ñ‚Đµ Đ¼Đ°Ñ€ÑˆÑ€ÑƒÑ‚Đ¸Đ·Đ°Ñ‚Đ¾Ñ€Ñ‹, Đ¼Đ¾Đ´ĐµĐ¼Ñ‹ и Đ´Ñ€ÑƒĐ³Đ¸Đµ
ÑĐµÑ‚ĐµĐ²Ñ‹Đµ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°.</translation>
<translation id="614940544461990577">ĐŸĐ¾Đ¿Ñ€Đ¾Đ±ÑƒĐ¹Ñ‚Đµ ÑĐ´ĐµĐ»Đ°Ñ‚ÑŒ ÑĐ»ĐµĐ´ÑƒÑÑ‰ĐµĐµ:</translation>
<translation id="6150607114729249911">Đ§Ñ‚Đ¾Đ±Ñ‹ Đ¿Ñ€Đ¾ÑĐ¼Đ¾Ñ‚Ñ€ĐµÑ‚ÑŒ Ñту ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ, Đ¿Đ¾Đ¿Ñ€Đ¾ÑĐ¸Ñ‚Đµ Ñ€Đ°Đ·Ñ€ĐµÑˆĐµĐ½Đ¸Ñ Ñƒ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»ĐµĐ¹.</translation>
<translation id="6151417162996330722">Đ¡Đ»Đ¸ÑˆĐºĐ¾Đ¼ Đ´Đ¾Đ»Đ³Đ¸Đ¹ ÑÑ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°, Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ»ĐµĐ½Đ½Đ¾Đ³Đ¾ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼.</translation>
-<translation id="6154808779448689242">Đ’Đ¾Đ·Đ²Ñ€Đ°Ñ‰ĐµĐ½Đ½Ñ‹Đ¹ Ñ‚Đ¾ĐºĐµĐ½ Đ½Đµ ÑĐ¾Đ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²ÑƒĐµÑ‚ Đ¸Đ¼ĐµÑÑ‰ĐµĐ¼ÑƒÑÑ</translation>
<translation id="6165508094623778733">ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµ...</translation>
<translation id="6203231073485539293">ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ Đ¿Đ¾Đ´ĐºĐ»ÑÑ‡ĐµĐ½Đ¸Đµ Đº Đ˜Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚Ñƒ</translation>
<translation id="6218753634732582820">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ Đ°Đ´Ñ€ĐµÑ Đ¸Đ· Chromium?</translation>
@@ -450,24 +475,30 @@
<translation id="6328639280570009161">ĐÑ‚ĐºĐ»ÑÑ‡Đ¸Ñ‚Đµ Đ¿Ñ€ĐµĐ´ÑĐºĐ°Đ·Đ°Đ½Đ¸Đµ ÑĐµÑ‚ĐµĐ²Ñ‹Ñ… Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Đ¹</translation>
<translation id="6337534724793800597">Đ¤Đ¸Đ»ÑŒÑ‚Ñ€Đ¾Đ²Đ°Ñ‚ÑŒ Đ¿Đ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ¸ Đ¿Đ¾ Đ½Đ°Đ·Đ²Đ°Đ½Đ¸Ñ</translation>
<translation id="6342069812937806050">Ñ‚Đ¾Đ»ÑŒĐºĐ¾ Ñ‡Ñ‚Đ¾</translation>
+<translation id="6345221851280129312">Ñ€Đ°Đ·Đ¼ĐµÑ€ Đ½ĐµĐ¸Đ·Đ²ĐµÑÑ‚ĐµĐ½</translation>
<translation id="6355080345576803305">Đ¡ĐµĐ°Đ½Ñ Đ¾Đ±Ñ‰ĐµĐ³Đ¾ Đ´Đ¾ÑÑ‚ÑƒĐ¿Đ° (Đ¿ĐµÑ€ĐµĐ¾Đ¿Ñ€ĐµĐ´ĐµĐ»ĐµĐ½Đ¾)</translation>
<translation id="6358450015545214790">Đ§Ñ‚Đ¾ ÑÑ‚Đ¾ Đ·Đ½Đ°Ñ‡Đ¸Ñ‚?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{ĐµÑ‰Ñ‘ 1Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚}one{ĐµÑ‰Ñ‘ #Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚}few{ĐµÑ‰Ñ‘ #Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚Đ°}many{ĐµÑ‰Ñ‘ #Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚Đ¾Đ²}other{ĐµÑ‰Ñ‘ #Â Đ²Đ°Ñ€Đ¸Đ°Đ½Ñ‚Đ°}}</translation>
<translation id="6387478394221739770">Đ¥Đ¾Ñ‚Đ¸Ñ‚Đµ Đ±Ñ‹Ñ‚ÑŒ Đ² ĐºÑƒÑ€Ñе Đ½Đ¾Đ²Đ¸Đ½Đ¾Đº Chrome? Đ’Ñ‹Đ±ĐµÑ€Đ¸Ñ‚Đµ Đ±ĐµÑ‚Đ°-ĐºĐ°Đ½Đ°Đ» Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ "chrome.com/beta".</translation>
-<translation id="641480858134062906">ĐĐµĐ²Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾ Đ¾Ñ‚Đ¾Đ±Ñ€Đ°Đ·Đ¸Ñ‚ÑŒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ <ph name="URL" /></translation>
+<translation id="6389758589412724634">Chromium Đ½Đµ Ñ…Đ²Đ°Ñ‚Đ°ĐµÑ‚ Đ¿Đ°Đ¼ÑÑ‚Đ¸ Đ´Đ»Ñ Đ¿Đ¾ĐºĐ°Đ·Đ° ÑÑ‚Đ¾Đ¹ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹.</translation>
+<translation id="6416403317709441254">Веб-ÑĐ°Đ¹Ñ‚Â <ph name="SITE" /> Đ¾Ñ‚Đ¿Ñ€Đ°Đ²Đ»ÑĐµÑ‚ Chromium Đ½ĐµĐºĐ¾Ñ€Ñ€ĐµĐºÑ‚Đ½Ñ‹Đµ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¾Đ½Đ½Ñ‹Đµ Đ´Đ°Đ½Đ½Ñ‹Đµ, Đ¿Đ¾ÑÑ‚Đ¾Đ¼Ñƒ Đ¾Ñ‚ĐºÑ€Ñ‹Ñ‚ÑŒ ĐµĐ³Đ¾ Đ² Đ½Đ°ÑÑ‚Đ¾ÑÑ‰ĐµĐµ Đ²Ñ€ĐµĐ¼Ñ Đ½ĐµĐ»ÑŒĐ·Ñ. Đ¡Đ±Đ¾Đ¹ Đ¼Đ¾Đ³ Đ±Ñ‹Ñ‚ÑŒ Đ²Ñ‹Đ·Đ²Đ°Đ½ ÑĐµÑ‚ĐµĐ²Đ¾Đ¹ Đ¾ÑˆĐ¸Đ±ĐºĐ¾Đ¹ или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ². Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐ°Đ¹Ñ‚ Đ·Đ°Ñ€Đ°Đ±Đ¾Ñ‚Đ°ĐµÑ‚ Ñ‡ĐµÑ€ĐµĐ· Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ²Ñ€ĐµĐ¼Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">Đе ÑƒĐ´Đ°ĐµÑ‚ÑÑ Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚ÑŒ, Đ±Ñ‹Đ» ли Đ¾Ñ‚Đ¾Đ·Đ²Đ°Đ½ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚.</translation>
<translation id="6433595998831338502">Đ¡Đ°Đ¹Ñ‚ <ph name="HOST_NAME" /> Đ½Đµ Đ¿Đ¾Đ·Đ²Đ¾Đ»ÑĐµÑ‚ уÑÑ‚Đ°Đ½Đ¾Đ²Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ.</translation>
<translation id="6445051938772793705">Đ¡Ñ‚Ñ€Đ°Đ½Đ°</translation>
<translation id="6451458296329894277">ĐŸĐ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đµ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ½ÑƒÑ Đ¾Ñ‚Đ¿Ñ€Đ°Đ²ĐºÑƒ Ñ„Đ¾Ñ€Đ¼Ñ‹</translation>
<translation id="6458467102616083041">Đ˜Đ³Đ½Đ¾Ñ€Đ¸Ñ€ÑƒĐµÑ‚ÑÑ, Ñ‚Đ°Đº ĐºĐ°Đº Đ¿Đ¾Đ¸ÑĐº Đ¿Đ¾ ÑƒĐ¼Đ¾Đ»Ñ‡Đ°Đ½Đ¸Ñ Đ·Đ°Đ¿Ñ€ĐµÑ‰ĐµĐ½ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°Đ¼Đ¸.</translation>
+<translation id="6462969404041126431">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ’ĐµÑ€Đ¾ÑÑ‚Đ½Đ¾, ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±Ñ‹Đ» Đ¾Ñ‚Đ¾Đ·Đ²Đ°Đ½. ĐŸÑ€Đ¾Đ±Đ»ĐµĐ¼Đ° Ñ‚Đ°ĐºĐ¶Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ±Ñ‹Ñ‚ÑŒ ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°</translation>
<translation id="6489534406876378309">ĐĐ°Ñ‡Đ°Ñ‚ÑŒ Đ·Đ°Đ³Ñ€ÑƒĐ·ĐºÑƒ ÑĐ²ĐµĐ´ĐµĐ½Đ¸Đ¹ Đ¾Đ± Đ¾ÑˆĐ¸Đ±ĐºĐ°Ñ…</translation>
<translation id="6529602333819889595">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚ÑŒ ÑƒĐ´Đ°Đ»ĐµĐ½Đ¸Đµ</translation>
+<translation id="6534179046333460208">Đ˜Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ²Đ¾ĐºÑ€ÑƒĐ³ Đ½Đ°Ñ: Ñ€ĐµĐºĐ¾Đ¼ĐµĐ½Đ´Đ°Ñ†Đ¸Đ¸</translation>
<translation id="6550675742724504774">ĐŸĐ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Ñ‹</translation>
+<translation id="6593753688552673085">Đ¼ĐµĐ½ĐµĐµÂ <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">ĐŸĐ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Ñ‹ ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¸Ñ</translation>
<translation id="662080504995468778">ĐÑÑ‚Đ°Ñ‚ÑŒÑÑ</translation>
<translation id="6628463337424475685">ĐŸĐ¾Đ¸ÑĐº <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">ĐŸĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="SITE" /> Đ½ĐµĐ²Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Ñ‚Đ°Đº ĐºĐ°Đº <ph name="BEGIN_LINK" />ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¾Ñ‚Đ¾Đ·Đ²Đ°Đ½<ph name="END_LINK" />. Đ­Ñ‚Đ¾ Đ¼Đ¾Đ³Đ»Đ¾ Đ¿Ñ€Đ¾Đ¸Đ·Đ¾Đ¹Ñ‚Đ¸ из-Đ·Đ° Đ¾ÑˆĐ¸Đ±ĐºĐ¸ ÑĐµÑ‚Đ¸ или Đ°Ñ‚Đ°ĐºĐ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚. Đ¡ĐºĐ¾Ñ€ĐµĐµ Đ²ÑĐµĐ³Đ¾, Đ¾Đ½ Đ·Đ°Ñ€Đ°Đ±Đ¾Ñ‚Đ°ĐµÑ‚ Ñ‡ĐµÑ€ĐµĐ· Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ²Ñ€ĐµĐ¼Ñ.</translation>
<translation id="6644283850729428850">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ¾ уÑÑ‚Đ°Ñ€ĐµĐ»Đ¾.</translation>
+<translation id="6652240803263749613">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ½Đµ Đ¿Ñ€Đ¸Đ½Đ¸Đ¼Đ°ĐµÑ‚ÑÑ Đ¾Đ¿ĐµÑ€Đ°Ñ†Đ¸Đ¾Đ½Đ½Đ¾Đ¹ ÑиÑÑ‚ĐµĐ¼Đ¾Đ¹ Đ²Đ°ÑˆĐµĐ³Đ¾ ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€Đ°. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">Đ ĐµĐ´Đ°ĐºÑ‚Đ¸Ñ€Đ¾Đ²Đ°Ñ‚ÑŒ Đ¿Đ°Đ¿ĐºÑƒ</translation>
<translation id="6660210980321319655">ĐÑ‚Ñ‡ĐµÑ‚ Đ¾ ÑĐ±Đ¾Đµ Đ¾Ñ‚Đ¿Ñ€Đ°Đ²Đ»ĐµĐ½ Đ°Đ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡ĐµÑĐºĐ¸. Đ’Ñ€ĐµĐ¼Ñ Đ²Đ¾Đ·Đ½Đ¸ĐºĐ½Đ¾Đ²ĐµĐ½Đ¸Ñ ÑĐ±Đ¾Ñ: <ph name="CRASH_TIME" />.</translation>
<translation id="6671697161687535275">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ Đ¿Đ¾Đ´ÑĐºĐ°Đ·ĐºÑƒ из Chromium?</translation>
@@ -475,6 +506,7 @@
<translation id="6710213216561001401">ĐĐ°Đ·Đ°Đ´</translation>
<translation id="6710594484020273272">&lt;Đ’Đ²ĐµĐ´Đ¸Ñ‚Đµ Đ¿Đ¾Đ¸ÑĐºĐ¾Đ²Ñ‹Đ¹ Đ·Đ°Đ¿Ñ€Đ¾Ñ&gt;</translation>
<translation id="6711464428925977395">ĐĐ° Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Đµ Đ²Đ¾Đ·Đ½Đ¸ĐºĐ»Đ° Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° или Đ°Đ´Ñ€ĐµÑ ÑƒĐºĐ°Đ·Đ°Đ½ Đ½ĐµĐ²ĐµÑ€Đ½Đ¾.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{Đ½ĐµÑ‚}=1{1Â Đ·Đ°Đ¿Đ¸ÑÑŒ}one{#Â Đ·Đ°Đ¿Đ¸ÑÑŒ}few{#Â Đ·Đ°Đ¿Đ¸Ñи}many{#Â Đ·Đ°Đ¿Đ¸ÑĐµĐ¹}other{#Â Đ·Đ°Đ¿Đ¸Ñи}}</translation>
<translation id="674375294223700098">ĐĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ°Ñ Đ¾ÑˆĐ¸Đ±ĐºĐ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° ÑĐµÑ€Đ²ĐµÑ€Đ°.</translation>
<translation id="6753269504797312559">Đ—Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°</translation>
<translation id="6757797048963528358">Đ£ÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾ Đ½Đ°Ñ…Đ¾Đ´Đ¸Ñ‚ÑÑ Đ² ÑĐ¿ÑÑ‰ĐµĐ¼ Ñ€ĐµĐ¶Đ¸Đ¼Đµ.</translation>
@@ -486,7 +518,6 @@
<translation id="6891596781022320156">Đ—Đ½Đ°Ñ‡ĐµĐ½Đ¸Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ° Đ½Đµ Đ¿Đ¾Đ´Đ´ĐµÑ€Đ¶Đ¸Đ²Đ°ĐµÑ‚ÑÑ.</translation>
<translation id="6895330447102777224">Đ’Đ°ÑˆĐ° ĐºĐ°Ñ€Ñ‚Đ° Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ¶Đ´ĐµĐ½Đ°</translation>
<translation id="6897140037006041989">User Agent</translation>
-<translation id="6903907808598579934">Đ’ĐºĐ»ÑÑ‡Đ¸Ñ‚ÑŒ</translation>
<translation id="6915804003454593391">ĐŸĐ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ĐµĐ»ÑŒ:</translation>
<translation id="6957887021205513506">Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Ñ„Đ°Đ»ÑŒÑĐ¸Ñ„Đ¸Ñ†Đ¸Ñ€Đ¾Đ²Đ°Đ½.</translation>
<translation id="6965382102122355670">ĐĐ</translation>
@@ -494,9 +525,11 @@
<translation id="6970216967273061347">Đ Đ°Đ¹Đ¾Đ½</translation>
<translation id="6973656660372572881">Đ£ĐºĐ°Đ·Đ°Đ½Ñ‹ ĐºĐ°Đº Ñ„Đ¸ĐºÑĐ¸Ñ€Đ¾Đ²Đ°Đ½Đ½Ñ‹Đµ Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€Ñ‹, Ñ‚Đ°Đº и URL PAC-ÑĐºÑ€Đ¸Đ¿Ñ‚Đ¾Đ².</translation>
<translation id="6989763994942163495">ĐŸĐ¾ĐºĐ°Đ·Đ°Ñ‚ÑŒ Đ´Đ¾Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ĐµĐ»ÑŒĐ½Ñ‹Đµ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸</translation>
+<translation id="7000990526846637657">Đ”Đ°Đ½Đ½Ñ‹Đµ из иÑÑ‚Đ¾Ñ€Đ¸Đ¸ Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½Ñ‹</translation>
+<translation id="7009986207543992532">Đ’Ñ‹ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ĐµÑÑŒ Đ¾Đ±Ñ€Đ°Ñ‚Đ¸Ñ‚ÑŒÑÑ Đº ÑĐµÑ€Đ²ĐµÑ€Ñƒ Đ² Đ´Đ¾Đ¼ĐµĐ½ĐµÂ <ph name="DOMAIN" />, Đ½Đ¾ Đ¾Đ½ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸Đ» ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ Đ¿Đ¾Đ´Đ¾Đ·Ñ€Đ¸Ñ‚ĐµĐ»ÑŒĐ½Đ¾ Đ´Đ¾Đ»Đ³Đ¸Đ¼ ÑÑ€Đ¾ĐºĐ¾Đ¼ Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Đ˜ÑÑ‚Đ¾Ñ€Đ¸Ñ Đ¿Ñ€Đ¾ÑĐ¼Đ¾Ñ‚Ñ€Đ° Ñ‚Đ°ĐºĐ¶Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Ñ…Ñ€Đ°Đ½Đ¸Ñ‚ÑŒÑÑ Đ² Đ²Đ°ÑˆĐµĐ¼ Đ°ĐºĐºĐ°ÑƒĐ½Ñ‚Đµ Google: <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="7029809446516969842">ĐŸĐ°Ñ€Đ¾Đ»Đ¸</translation>
-<translation id="7050187094878475250">Đ’Ñ‹ Đ¿Đ¾Đ¿Ñ‹Ñ‚Đ°Đ»Đ¸ÑÑŒ Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="DOMAIN" />, Đ½Đ¾ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Ñ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ¸Đ» Đ½Đµ Đ·Đ°ÑĐ»ÑƒĐ¶Đ¸Đ²Đ°ÑÑ‰Đ¸Đ¹ Đ´Đ¾Đ²ĐµÑ€Đ¸Ñ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐ¾ ÑĐ»Đ¸ÑˆĐºĐ¾Đ¼ Đ´Đ¾Đ»Đ³Đ¸Đ¼ ÑÑ€Đ¾ĐºĐ¾Đ¼ Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ.</translation>
<translation id="7087282848513945231">Đ“Ñ€Đ°Ñ„ÑÑ‚Đ²Đ¾</translation>
<translation id="7088615885725309056">Đ Đ°Đ½ÑŒÑˆĐµ</translation>
<translation id="7090678807593890770">Đ’Ñ‹Đ¿Đ¾Đ»Đ½Đ¸Ñ‚Đµ Đ¿Đ¾Đ¸ÑĐº Đ¿Đ¾ Đ·Đ°Đ¿Ñ€Đ¾Ñу <ph name="LINK" /> Đ² Google</translation>
@@ -515,13 +548,13 @@
<translation id="7246609911581847514">Đ’Đ°Ñˆ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€ Đ´Đ¾Đ»Đ¶ĐµĐ½ Đ¾Đ´Đ¾Đ±Ñ€Đ¸Ñ‚ÑŒ Đ½Đ¾Đ²Ñ‹Đµ ÑĐ°Đ¹Ñ‚Ñ‹, Ñ‡Ñ‚Đ¾Đ±Ñ‹ Đ²Ñ‹ Đ¼Đ¾Đ³Đ»Đ¸ Đ¸Ñ… Đ¿Đ¾ÑĐµÑ‰Đ°Ñ‚ÑŒ.</translation>
<translation id="724975217298816891">Đ’Đ²ĐµĐ´Đ¸Ñ‚Đµ ÑÑ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ Đ¸ CVC-ĐºĐ¾Đ´ ĐºĐ°Ñ€Ñ‚Ñ‹ <ph name="CREDIT_CARD" />. ĐŸĐ¾Ñле ÑÑ‚Đ¾Đ³Đ¾ ее Đ´Đ°Đ½Đ½Ñ‹Đµ Đ±ÑƒĐ´ÑƒÑ‚ Đ¿ĐµÑ€ĐµĐ´Đ°Đ½Ñ‹ ÑĐ°Đ¹Ñ‚Ñƒ.</translation>
<translation id="725866823122871198">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ уÑÑ‚Đ°Đ½Đ¾Đ²Đ¸Ñ‚ÑŒ Đ·Đ°Ñ‰Đ¸Ñ‰ĐµĐ½Đ½Đ¾Đµ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> из-Đ·Đ° Đ½ĐµĐ²ĐµÑ€Đ½Ñ‹Ñ… Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐº ÑиÑÑ‚ĐµĐ¼Đ½Ñ‹Ñ… Ñ‡Đ°ÑĐ¾Đ² и ĐºĐ°Đ»ĐµĐ½Đ´Đ°Ñ€Ñ (<ph name="DATE_AND_TIME" />).</translation>
-<translation id="7265986070661382626">ĐŸĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="SITE" /> Đ½ĐµĐ²Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Ñ‚Đ°Đº ĐºĐ°Đº Đ¾Đ½ иÑĐ¿Đ¾Đ»ÑŒĐ·ÑƒĐµÑ‚ <ph name="BEGIN_LINK" />Đ·Đ°ĐºÑ€ĐµĐ¿Đ»ĐµĐ½Đ¸Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°<ph name="END_LINK" />. Đ­Ñ‚Đ¾ Đ¼Đ¾Đ³Đ»Đ¾ Đ¿Ñ€Đ¾Đ¸Đ·Đ¾Đ¹Ñ‚Đ¸ из-Đ·Đ° Đ¾ÑˆĐ¸Đ±ĐºĐ¸ ÑĐµÑ‚Đ¸ или Đ°Ñ‚Đ°ĐºĐ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚. Đ¡ĐºĐ¾Ñ€ĐµĐµ Đ²ÑĐµĐ³Đ¾, Đ¾Đ½ Đ·Đ°Ñ€Đ°Đ±Đ¾Ñ‚Đ°ĐµÑ‚ Ñ‡ĐµÑ€ĐµĐ· Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ²Ñ€ĐµĐ¼Ñ.</translation>
<translation id="7269802741830436641">ĐĐ° ÑÑ‚Đ¾Đ¹ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ Đ¾Đ±Đ½Đ°Ñ€ÑƒĐ¶ĐµĐ½Đ° Ñ†Đ¸ĐºĐ»Đ¸Ñ‡ĐµÑĐºĐ°Ñ Đ¿ĐµÑ€ĐµĐ°Đ´Ñ€ĐµÑĐ°Ñ†Đ¸Ñ</translation>
<translation id="7275334191706090484">Đ£Đ¿Ñ€Đ°Đ²Đ»ÑĐµĐ¼Ñ‹Đµ Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
<translation id="7298195798382681320">Đ ĐµĐºĐ¾Đ¼ĐµĐ½Đ´Đ¾Đ²Đ°Đ½Đ½Ñ‹Đµ</translation>
-<translation id="7301833672208172928">Đ’ĐºĐ»ÑÑ‡Đ¸Ñ‚ÑŒ</translation>
+<translation id="7309308571273880165"><ph name="CRASH_TIME" />: Đ¾Ñ‚Ñ‡ĐµÑ‚ Đ¾ ÑĐ±Đ¾Đµ ÑĐ¾Ñ…Ñ€Đ°Đ½ĐµĐ½, Đ½Đ¾ ĐµÑ‰Ñ‘ Đ½Đµ Đ·Đ°Đ³Ñ€ÑƒĐ¶ĐµĐ½ (Đ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ĐµĐ»ÑŒ Đ·Đ°Đ¿Ñ€Đ¾Ñил Đ·Đ°Đ³Ñ€ÑƒĐ·ĐºÑƒ)</translation>
<translation id="7334320624316649418">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚ÑŒ Đ¸Đ·Đ¼ĐµĐ½ĐµĐ½Đ¸Đµ Đ¿Đ¾Ñ€ÑĐ´ĐºĐ°</translation>
<translation id="733923710415886693">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½Đµ Đ¿Ñ€Đ¾Ñ…Đ¾Đ´Đ¸Đ» Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐºÑƒ.</translation>
+<translation id="7351800657706554155">ĐÑ‚ĐºÑ€Ñ‹Ñ‚ÑŒ ÑĐ°Đ¹Ñ‚ <ph name="SITE" /> ÑĐµĐ¹Ñ‡Đ°Ñ Đ½ĐµĐ»ÑŒĐ·Ñ, Ñ‚Đ°Đº ĐºĐ°Đº ĐµĐ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¾Ñ‚Đ¾Đ·Đ²Đ°Đ½. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐ±Đ¾Đ¹ Đ²Ñ‹Đ·Đ²Đ°Đ½ ÑĐµÑ‚ĐµĐ²Đ¾Đ¹ Đ¾ÑˆĐ¸Đ±ĐºĐ¾Đ¹ или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ². Đ¡Đ°Đ¹Ñ‚ Đ¼Đ¾Đ¶ĐµÑ‚ Đ·Đ°Ñ€Đ°Đ±Đ¾Ñ‚Đ°Ñ‚ÑŒ Ñ‡ĐµÑ€ĐµĐ· Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Đ¾Đµ Đ²Ñ€ĐµĐ¼Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">ĐĐ¾Đ¼Đ°Đ½Đ´Đ½Đ°Ñ ÑÑ‚Ñ€Đ¾ĐºĐ°</translation>
<translation id="7372973238305370288">Ñ€ĐµĐ·ÑƒĐ»ÑŒÑ‚Đ°Ñ‚ Đ¿Đ¾Đ¸ÑĐºĐ°</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -540,16 +573,17 @@
<translation id="7469372306589899959">ĐŸĐ¾Đ´Ñ‚Đ²ĐµÑ€Đ¶Đ´ĐµĐ½Đ¸Đµ ĐºĐ°Ñ€Ñ‚Ñ‹â€¦</translation>
<translation id="7481312909269577407">Đ’Đ¿ĐµÑ€ĐµĐ´</translation>
<translation id="7485870689360869515">Đ”Đ°Đ½Đ½Ñ‹Đµ Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½Ñ‹.</translation>
+<translation id="7508255263130623398">Đ’Đ¾Đ·Đ²Ñ€Đ°Ñ‰ĐµĐ½Đ½Ñ‹Đ¹ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¾Ñ€ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ° Đ¿ÑƒÑÑ‚ или Đ½Đµ ÑĐ¾Đ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²ÑƒĐµÑ‚ Đ¸Đ¼ĐµÑÑ‰ĐµĐ¼ÑƒÑÑ</translation>
<translation id="7514365320538308">Đ¡ĐºĐ°Ñ‡Đ°Ñ‚ÑŒ</translation>
<translation id="7518003948725431193">Đе Đ½Đ°Đ¹Đ´ĐµĐ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ´Đ»Ñ Đ²ĐµĐ±-Đ°Đ´Ñ€ĐµÑĐ° <ph name="URL" /></translation>
<translation id="7537536606612762813">ĐбÑĐ·Đ°Ñ‚ĐµĐ»ÑŒĐ½Đ°Ñ</translation>
<translation id="7542995811387359312">ĐĐ²Ñ‚Đ¾Đ·Đ°Đ¿Đ¾Đ»Đ½ĐµĐ½Đ¸Đµ Đ¾Ñ‚ĐºĐ»ÑÑ‡ĐµĐ½Đ¾ – Đ½ĐµĐ·Đ°Ñ‰Đ¸Ñ‰ĐµĐ½Đ½Đ¾Đµ Đ¿Đ¾Đ´ĐºĐ»ÑÑ‡ĐµĐ½Đ¸Đµ.</translation>
<translation id="7549584377607005141">Đ”Đ»Ñ ĐºĐ¾Ñ€Ñ€ĐµĐºÑ‚Đ½Đ¾Đ³Đ¾ Đ¾Ñ‚Đ¾Đ±Ñ€Đ°Đ¶ĐµĐ½Đ¸Ñ Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹ Ñ‚Ñ€ĐµĐ±ÑƒÑÑ‚ÑÑ Đ²Đ²ĐµĐ´ĐµĐ½Đ½Ñ‹Đµ Ñ€Đ°Đ½ĐµĐµ Đ´Đ°Đ½Đ½Ñ‹Đµ. Đ˜Ñ… Đ¼Đ¾Đ¶Đ½Đ¾ Đ¾Ñ‚Đ¿Ñ€Đ°Đ²Đ¸Ñ‚ÑŒ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ½Đ¾, Đ½Đ¾ Đ² ÑÑ‚Đ¾Đ¼ ÑĐ»ÑƒÑ‡Đ°Đµ Đ²Ñе Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ Đ±ÑƒĐ´ÑƒÑ‚ Đ²Ñ‹Đ¿Đ¾Đ»Đ½ĐµĐ½Ñ‹ ÑĐ½Đ¾Đ²Đ°.</translation>
<translation id="7554791636758816595">ĐĐ¾Đ²Đ°Ñ Đ²ĐºĐ»Đ°Đ´ĐºĐ°</translation>
-<translation id="7567204685887185387">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑÑ‚Đ¾ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ¼Đ¾Đ³ Đ±Ñ‹Ñ‚ÑŒ Đ²Ñ‹Đ´Đ°Đ½ Đ¾Đ±Đ¼Đ°Đ½Đ½Ñ‹Đ¼ Đ¿ÑƒÑ‚ĐµĐ¼. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°ÑÑ‚Ñ€Đ¾ĐµĐ½ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ или ĐºÑ‚Đ¾-Ñ‚Đ¾ Đ¿Ñ‹Ñ‚Đ°ĐµÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ Đ²Đ°ÑˆĐ¸ Đ´Đ°Đ½Đ½Ñ‹Đµ.</translation>
<translation id="7568593326407688803">Đ¯Đ·Ñ‹Đº ÑÑ‚Đ¾Đ¹ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹<ph name="ORIGINAL_LANGUAGE" />Đ¥Đ¾Ñ‚Đ¸Ñ‚Đµ Đ¿ĐµÑ€ĐµĐ²ĐµÑÑ‚Đ¸ ее?</translation>
<translation id="7569952961197462199">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½ÑƒÑ ĐºĐ°Ñ€Ñ‚Ñƒ из Chrome?</translation>
<translation id="7578104083680115302">Đ‘Ñ‹ÑÑ‚Ñ€Đ¾ Đ¾Đ¿Đ»Đ°Ñ‡Đ¸Đ²Đ°Đ¹Ñ‚Đµ Đ¿Đ¾ĐºÑƒĐ¿ĐºĐ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚Đ°Ñ… и Đ² Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸ÑÑ… Ñ Đ¿Đ¾Đ¼Đ¾Ñ‰ÑŒÑ ĐºĐ°Ñ€Ñ‚, ÑĐ¾Ñ…Ñ€Đ°Đ½ĐµĐ½Đ½Ñ‹Ñ… Đ² Google Payments. ĐĐ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ° Đ±ÑƒĐ´ĐµÑ‚ Đ´ĐµĐ¹ÑÑ‚Đ²Đ¾Đ²Đ°Ñ‚ÑŒ Đ½Đ° Đ²ÑĐµÑ… Đ²Đ°ÑˆĐ¸Ñ… уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°Ñ….</translation>
+<translation id="7588950540487816470">Đ˜Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ²Đ¾ĐºÑ€ÑƒĐ³ Đ½Đ°Ñ</translation>
<translation id="7592362899630581445">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½Đµ ÑĐ¾Đ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²ÑƒĐµÑ‚ Đ¾Đ³Ñ€Đ°Đ½Đ¸Ñ‡ĐµĐ½Đ¸ÑĐ¼ Đ² Đ¾Ñ‚Đ½Đ¾ÑˆĐµĐ½Đ¸Đ¸ Đ¸Đ¼ĐµĐ½.</translation>
<translation id="759889825892636187">Đ¡Đ°Đ¹Ñ‚ <ph name="HOST_NAME" /> Đ¿Đ¾ĐºĐ° Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¾Đ±Ñ€Đ°Đ±Đ¾Ñ‚Đ°Ñ‚ÑŒ ÑÑ‚Đ¾Ñ‚ Đ·Đ°Đ¿Ñ€Đ¾Ñ.</translation>
<translation id="7600965453749440009">ĐĐ¸ĐºĐ¾Đ³Đ´Đ° Đ½Đµ Đ¿ĐµÑ€ĐµĐ²Đ¾Đ´Đ¸Ñ‚ÑŒ <ph name="LANGUAGE" /></translation>
@@ -560,6 +594,7 @@
<translation id="7637571805876720304">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½ÑƒÑ ĐºĐ°Ñ€Ñ‚Ñƒ из Chromium?</translation>
<translation id="765676359832457558">Đ¡ĐºÑ€Ñ‹Ñ‚ÑŒ Đ´Đ¾Đ¿Đ¾Đ»Đ½Đ¸Ñ‚ĐµĐ»ÑŒĐ½Ñ‹Đµ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸</translation>
<translation id="7658239707568436148">ĐÑ‚Đ¼ĐµĐ½Đ°</translation>
+<translation id="7667346355482952095">Đ’Đ¾Đ·Đ²Ñ€Đ°Ñ‰ĐµĐ½Đ½Ñ‹Đ¹ Ñ‚Đ¾ĐºĐµĐ½ Đ¿ÑƒÑÑ‚ или Đ½Đµ ÑĐ¾Đ¾Ñ‚Đ²ĐµÑ‚ÑÑ‚Đ²ÑƒĐµÑ‚ Đ¸Đ¼ĐµÑÑ‰ĐµĐ¼ÑƒÑÑ</translation>
<translation id="7668654391829183341">ĐĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ¾Đµ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ¾</translation>
<translation id="7674629440242451245">Đ¥Đ¾Ñ‚Đ¸Ñ‚Đµ Đ±Ñ‹Ñ‚ÑŒ Đ² ĐºÑƒÑ€Ñе Đ½Đ¾Đ²Đ¸Đ½Đ¾Đº Chrome? Đ’Ñ‹Đ±ĐµÑ€Đ¸Ñ‚Đµ ĐºĐ°Đ½Đ°Đ» Đ¾Đ±Đ½Đ¾Đ²Đ»ĐµĐ½Đ¸Ñ Đ´Đ»Ñ Ñ€Đ°Đ·Ñ€Đ°Đ±Đ¾Ñ‚Ñ‡Đ¸ĐºĐ¾Đ² Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ "chrome.com/dev".</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ĐŸĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="SITE" /> (Đ½ĐµĐ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾)<ph name="END_LINK" /></translation>
@@ -576,10 +611,10 @@
<translation id="780301667611848630">Đ¡Đ¿Đ°ÑĐ¸Đ±Đ¾, Đ½Đµ Đ½Đ°Đ´Đ¾</translation>
<translation id="7805768142964895445">Đ¡Đ¾ÑÑ‚Đ¾ÑĐ½Đ¸Đµ</translation>
<translation id="7813600968533626083">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ Đ¿Đ¾Đ´ÑĐºĐ°Đ·ĐºÑƒ из Chrome?</translation>
+<translation id="7815407501681723534"><ph name="SEARCH_RESULTS" /> Đ¿Đ¾ Đ·Đ°Đ¿Ñ€Đ¾Ñу "<ph name="SEARCH_STRING" />" (<ph name="NUMBER_OF_RESULTS" />)</translation>
<translation id="785549533363645510">Đ¢ĐµĐ¼ Đ½Đµ Đ¼ĐµĐ½ĐµĐµ Đ²Đ°ÑˆĐ¸ Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ Đ±ÑƒĐ´ÑƒÑ‚ Đ²Đ¸Đ´Đ½Ñ‹ ÑиÑÑ‚ĐµĐ¼Đ½Đ¾Đ¼Ñƒ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Ñƒ и Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚-Đ¿Ñ€Đ¾Đ²Đ°Đ¹Đ´ĐµÑ€Ñƒ, Đ° Ñ‚Đ°ĐºĐ¶Đµ Đ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Ñ‹ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚Đ°Đ¼, ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ²Ñ‹ Đ¿Đ¾ÑĐµÑ‰Đ°ĐµÑ‚Đµ.</translation>
<translation id="7887683347370398519">ĐŸÑ€Đ¾Đ²ĐµÑ€ÑŒÑ‚Đµ CVC-ĐºĐ¾Đ´ и Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ Đ¿Đ¾Đ¿Ñ‹Ñ‚ĐºÑƒ</translation>
<translation id="7894616681410591072">ĐĐ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€ (<ph name="NAME" />) Đ´Đ¾Đ»Đ¶ĐµĐ½ Ñ€Đ°Đ·Ñ€ĐµÑˆĐ¸Ñ‚ÑŒ Đ²Đ°Đ¼ Đ¿Ñ€Đ¾ÑĐ¼Đ¾Ñ‚Ñ€ ÑÑ‚Đ¾Đ¹ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹.</translation>
-<translation id="790025292736025802"><ph name="URL" /> Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½</translation>
<translation id="7912024687060120840">Đ’ Đ¿Đ°Đ¿ĐºĐµ:</translation>
<translation id="7920092496846849526">Đ’Đ°ÑˆĐ¸Đ¼ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»ÑĐ¼ Đ¾Ñ‚Đ¿Ñ€Đ°Đ²Đ»ĐµĐ½ Đ·Đ°Đ¿Ñ€Đ¾Ñ Đ½Đ° Đ¿Ñ€Đ¾ÑĐ¼Đ¾Ñ‚Ñ€ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -592,9 +627,10 @@
<translation id="7995512525968007366">Đе ÑƒĐºĐ°Đ·Đ°Đ½Đ¾</translation>
<translation id="8012647001091218357">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ ÑĐ²ÑĐ·Đ°Ñ‚ÑŒÑÑ Ñ Đ²Đ°ÑˆĐ¸Đ¼Đ¸ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµĐ»ÑĐ¼Đ¸. ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ Đ¿Đ¾Đ¿Ñ‹Ñ‚ĐºÑƒ.</translation>
<translation id="8034522405403831421">Đ¯Đ·Ñ‹Đº ÑÑ‚Đ¾Đ¹ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹: <ph name="SOURCE_LANGUAGE" />. ĐŸĐµÑ€ĐµĐ²ĐµÑÑ‚Đ¸ ее Đ½Đ° <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Đ­Đ»ĐµĐ¼ĐµĐ½Ñ‚Ñ‹ иÑÑ‚Đ¾Ñ€Đ¸Đ¸ Đ½Đµ Đ½Đ°Đ¹Đ´ĐµĐ½Ñ‹.</translation>
<translation id="8088680233425245692">Đе ÑƒĐ´Đ°Đ»Đ¾ÑÑŒ Đ¿Đ¾ĐºĐ°Đ·Đ°Ñ‚ÑŒ ÑÑ‚Đ°Ñ‚ÑŒÑ</translation>
+<translation id="8089520772729574115">Đ¼ĐµĐ½ĐµĐµ 1Â ĐœĐ‘</translation>
<translation id="8091372947890762290">ĐĐºÑ‚Đ¸Đ²Đ°Ñ†Đ¸Ñ ÑƒĐ¿Ñ€Đ°Đ²Đ»ĐµĐ½Đ¸Ñ ÑƒÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°Đ¼Đ¸ Đ½Đµ Đ·Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ°</translation>
+<translation id="8129262335948759431">ĐºĐ¾Đ»Đ¸Ñ‡ĐµÑÑ‚Đ²Đ¾ Đ½ĐµĐ¸Đ·Đ²ĐµÑÑ‚Đ½Đ¾</translation>
<translation id="8131740175452115882">ĐŸĐ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ</translation>
<translation id="8134994873729925007">Đе ÑƒĐ´Đ°ĐµÑ‚ÑÑ Đ½Đ°Đ¹Ñ‚Đ¸ <ph name="BEGIN_ABBR" />DNS-Đ°Đ´Ñ€ĐµÑ<ph name="END_ABBR" /> ÑĐµÑ€Đ²ĐµÑ€Đ° <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Đ’Đ°Ñˆ ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€ Đ¿ĐµÑ€ĐµÑˆĐµĐ» Đ² ÑĐ¿ÑÑ‰Đ¸Đ¹ Ñ€ĐµĐ¶Đ¸Đ¼.</translation>
@@ -603,6 +639,7 @@
<translation id="8201077131113104583">ĐĐµĐ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ‚ĐµĐ»ÑŒĐ½Ñ‹Đ¹ URL Đ´Đ»Ñ Đ¾Đ±Đ½Đ¾Đ²Đ»ĐµĐ½Đ¸Ñ Ñ€Đ°ÑÑˆĐ¸Ñ€ĐµĐ½Đ¸Ñ Ñ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¾Ñ€Đ¾Đ¼ <ph name="EXTENSION_ID" />.</translation>
<translation id="8218327578424803826">ĐĐ°Đ·Đ½Đ°Ñ‡ĐµĐ½Đ½Đ¾Đµ Đ¼ĐµÑÑ‚Đ¾Đ¿Đ¾Đ»Đ¾Đ¶ĐµĐ½Đ¸Đµ:</translation>
<translation id="8225771182978767009">Đ¢Đ¾Ñ‚, ĐºÑ‚Đ¾ Đ½Đ°ÑÑ‚Ñ€Đ°Đ¸Đ²Đ°Đ» ĐºĐ¾Đ¼Đ¿ÑŒÑÑ‚ĐµÑ€, Đ·Đ°Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ¾Đ²Đ°Đ» ÑÑ‚Đ¾Ñ‚ ÑĐ°Đ¹Ñ‚.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" /> и <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">ĐĐ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ, ĐºĐ¾Ñ‚Đ¾Ñ€ÑƒÑ Đ²Ñ‹ Đ¸Ñ‰ĐµÑ‚Đµ, иÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Đ»Đ°ÑÑŒ Đ²Đ²ĐµĐ´ĐµĐ½Đ½Đ°Ñ Đ²Đ°Đ¼Đ¸ Đ¸Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ. ĐŸÑ€Đ¸ Đ²Đ¾Đ·Đ²Ñ€Đ°Ñ‚Đµ Đ½Đ° Ñту ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¾Đ²Đ°Ñ‚ÑŒÑÑ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚ÑŒ Đ²Ñ‹Đ¿Đ¾Đ»Đ½ĐµĐ½Đ½Ñ‹Đµ Ñ€Đ°Đ½ĐµĐµ Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ. ĐŸÑ€Đ¾Đ´Đ¾Đ»Đ¶Đ¸Ñ‚ÑŒ?</translation>
<translation id="8249320324621329438">Đ’Ñ€ĐµĐ¼Ñ Đ¿Đ¾ÑĐ»ĐµĐ´Đ½ĐµĐ¹ Đ·Đ°Đ³Ñ€ÑƒĐ·ĐºĐ¸:</translation>
<translation id="8261506727792406068">Đ£Đ´Đ°Đ»Đ¸Ñ‚ÑŒ</translation>
@@ -615,12 +652,17 @@
<translation id="8349305172487531364">ĐŸĐ°Đ½ĐµĐ»ÑŒ Đ·Đ°ĐºĐ»Đ°Đ´Đ¾Đº</translation>
<translation id="8363502534493474904">ĐÑ‚ĐºĐ»ÑÑ‡Đ¸Ñ‚Đµ Ñ€ĐµĐ¶Đ¸Đ¼ Đ¿Đ¾Đ»ĐµÑ‚Đ°.</translation>
<translation id="8364627913115013041">Đе Đ·Đ°Đ´Đ°Đ½Đ¾</translation>
+<translation id="8380941800586852976">ĐĐ¿Đ°ÑĐ½Đ¾</translation>
<translation id="8412145213513410671">Đ¡Đ±Đ¾Đ¸ (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">ĐĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ¾ Đ´Đ²Đ°Đ¶Đ´Ñ‹ Đ²Đ²ĐµÑÑ‚Đ¸ Đ¾Đ´Đ½Ñƒ и ту же ĐºĐ¾Đ´Đ¾Đ²ÑƒÑ Ñ„Ñ€Đ°Đ·Ñƒ.</translation>
<translation id="8428213095426709021">ĐĐ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸</translation>
+<translation id="8433057134996913067">ĐĐ° Đ±Đ¾Đ»ÑŒÑˆĐ¸Đ½ÑÑ‚Đ²Đµ ÑĐ°Đ¹Ñ‚Đ¾Đ² Đ±ÑƒĐ´ĐµÑ‚ Đ²Ñ‹Đ¿Đ¾Đ»Đ½ĐµĐ½ Đ²Ñ‹Ñ…Đ¾Đ´ из Đ°ĐºĐºĐ°ÑƒĐ½Ñ‚Đ°.</translation>
<translation id="8437238597147034694">&amp;ĐÑ‚Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ Đ¿ĐµÑ€ĐµĐ¼ĐµÑ‰ĐµĐ½Đ¸Đµ</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1Â Đ±Đ°Đ½ĐºĐ¾Đ²ÑĐºĐ°Ñ ĐºĐ°Ñ€Ñ‚Đ°}one{#Â Đ±Đ°Đ½ĐºĐ¾Đ²ÑĐºĐ°Ñ ĐºĐ°Ñ€Ñ‚Đ°}few{#Â Đ±Đ°Đ½ĐºĐ¾Đ²ÑĐºĐ¸Đµ ĐºĐ°Ñ€Ñ‚Ñ‹}many{#Â Đ±Đ°Đ½ĐºĐ¾Đ²ÑĐºĐ¸Ñ… ĐºĐ°Ñ€Ñ‚}other{#Â Đ±Đ°Đ½ĐºĐ¾Đ²ÑĐºĐ¾Đ¹ ĐºĐ°Ñ€Ñ‚Ñ‹}}</translation>
+<translation id="8483780878231876732">Đ§Ñ‚Đ¾Đ±Ñ‹ иÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ÑŒ ĐºĐ°Ñ€Ñ‚Ñ‹, Đ¿Ñ€Đ¸Đ²ÑĐ·Đ°Đ½Đ½Ñ‹Đµ Đº Đ°ĐºĐºĐ°ÑƒĐ½Ñ‚Ñƒ Google Account, Đ²Đ¾Đ¹Đ´Đ¸Ñ‚Đµ Đ² Chrome</translation>
<translation id="8488350697529856933">ĐбÑĐµĐºÑ‚ Đ¿Ñ€Đ¸Đ¼ĐµĐ½ĐµĐ½Đ¸Ñ</translation>
<translation id="8498891568109133222">ĐŸÑ€ĐµĐ²Ñ‹ÑˆĐµĐ½Đ¾ Đ²Ñ€ĐµĐ¼Ñ Đ¾Đ¶Đ¸Đ´Đ°Đ½Đ¸Ñ Đ¾Ñ‚Đ²ĐµÑ‚Đ° Đ¾Ñ‚ ÑĐ°Đ¹Ñ‚Đ° <ph name="HOST_NAME" />.</translation>
+<translation id="852346902619691059">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Đ¾Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚ÑŒ ÑĐ²ÑĐ·ÑŒ Ñ Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼Â <ph name="DOMAIN" />. Đ•Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸ Đ½Đµ Đ¿Ñ€Đ¸Đ½Đ¸Đ¼Đ°ĐµÑ‚ÑÑ Đ¾Đ¿ĐµÑ€Đ°Ñ†Đ¸Đ¾Đ½Đ½Đ¾Đ¹ ÑиÑÑ‚ĐµĐ¼Đ¾Đ¹ Đ²Đ°ÑˆĐµĐ³Đ¾ уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đ°. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° ÑĐ²ÑĐ·Đ°Đ½Đ° Ñ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ°Đ¼Đ¸ ÑĐµÑ€Đ²ĐµÑ€Đ° или Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸ÑĐ¼Đ¸ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ², ĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Đµ Đ¿Ñ‹Ñ‚Đ°ÑÑ‚ÑÑ Đ¿ĐµÑ€ĐµÑ…Đ²Đ°Ñ‚Đ¸Ñ‚ÑŒ ÑĐ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />ĐŸĐ¾Đ´Ñ€Đ¾Đ±Đ½ĐµĐµâ€¦<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Đ­Ñ‚Đ¾Ñ‚ Ñ‚Đ¸Đ¿ ĐºĐ°Ñ€Ñ‚ Đ½Đµ Đ¿Đ¾Đ´Đ´ĐµÑ€Đ¶Đ¸Đ²Đ°ĐµÑ‚ÑÑ Đ² Google Payments. Đ’Ñ‹Đ±ĐµÑ€Đ¸Ñ‚Đµ Đ´Ñ€ÑƒĐ³ÑƒÑ ĐºĐ°Ñ€Ñ‚Ñƒ.</translation>
<translation id="8550022383519221471">Đ’ Đ²Đ°ÑˆĐµĐ¼ Đ´Đ¾Đ¼ĐµĐ½Đµ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ Đ½ĐµĐ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Đ°.</translation>
<translation id="8553075262323480129">ĐŸĐµÑ€ĐµĐ²Đ¾Đ´ Đ½Đµ ÑƒĐ´Đ°Đ»ÑÑ, Ñ‚Đ°Đº ĐºĐ°Đº Đ½Đµ ÑƒĐ´Đ°ĐµÑ‚ÑÑ Đ¾Đ¿Ñ€ĐµĐ´ĐµĐ»Đ¸Ñ‚ÑŒ ÑĐ·Ñ‹Đº ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñ‹.</translation>
@@ -632,15 +674,12 @@
<translation id="8647750283161643317">Đ’Đ¾ÑÑÑ‚Đ°Đ½Đ¾Đ²Đ¸Ñ‚ÑŒ Đ½Đ°ÑÑ‚Ñ€Đ¾Đ¹ĐºĐ¸ Đ¿Đ¾ ÑƒĐ¼Đ¾Đ»Ñ‡Đ°Đ½Đ¸Ñ</translation>
<translation id="8680787084697685621">Đ”Đ°Đ½Đ½Ñ‹Đµ Đ´Đ»Ñ Đ²Ñ…Đ¾Đ´Đ° Đ² Đ°ĐºĐºĐ°ÑƒĐ½Ñ‚ уÑÑ‚Đ°Ñ€ĐµĐ»Đ¸.</translation>
<translation id="8703575177326907206">Đ¡Đ¾ĐµĐ´Đ¸Đ½ĐµĐ½Đ¸Đµ Ñ <ph name="DOMAIN" /> Đ½Đµ Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¾.</translation>
-<translation id="8713130696108419660">ĐĐµĐ´Đ¾Đ¿ÑƒÑÑ‚Đ¸Đ¼Đ°Ñ Đ½Đ°Ñ‡Đ°Đ»ÑŒĐ½Đ°Ñ Đ¿Đ¾Đ´Đ¿Đ¸ÑÑŒ</translation>
<translation id="8725066075913043281">ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚ÑŒ Đ¿Đ¾Đ¿Ñ‹Ñ‚ĐºÑƒ</translation>
<translation id="8728672262656704056">Đ’Ñ‹ Đ¿ĐµÑ€ĐµÑˆĐ»Đ¸ Đ² Ñ€ĐµĐ¶Đ¸Đ¼ Đ¸Đ½ĐºĐ¾Đ³Đ½Đ¸Ñ‚Đ¾</translation>
<translation id="8730621377337864115">Đ“Đ¾Ñ‚Đ¾Đ²Đ¾</translation>
<translation id="8738058698779197622">Đ”Đ»Ñ ÑĐ¾Đ·Đ´Đ°Đ½Đ¸Ñ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾Đ³Đ¾ Đ¿Đ¾Đ´ĐºĐ»ÑÑ‡ĐµĐ½Đ¸Ñ Đ½ĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ¾, Ñ‡Ñ‚Đ¾Đ±Ñ‹ Đ¿Đ¾ĐºĐ°Đ·Đ°Đ½Đ¸Ñ ÑиÑÑ‚ĐµĐ¼Đ½Ñ‹Ñ… Ñ‡Đ°ÑĐ¾Đ² Đ±Ñ‹Đ»Đ¸ Đ²ĐµÑ€Đ½Ñ‹. ĐŸÑ€Đ¸Ñ‡Đ¸Đ½Đ° Đ² Ñ‚Đ¾Đ¼, Ñ‡Ñ‚Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Ñ‹ Đ´Đ»Ñ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Đ¸ ÑĐ°Đ¹Ñ‚Đ¾Đ² Đ¸Đ¼ĐµÑÑ‚ Đ¾Đ³Ñ€Đ°Đ½Đ¸Ñ‡ĐµĐ½Đ½Ñ‹Đ¹ ÑÑ€Đ¾Đº Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ. Đ•Ñли Ñ‡Đ°ÑÑ‹ Đ½Đ° уÑÑ‚Ñ€Đ¾Đ¹ÑÑ‚Đ²Đµ Đ½ĐµÑ‚Đ¾Ñ‡Đ½Ñ‹, Chromium Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚ÑŒ Đ°ĐºÑ‚ÑƒĐ°Đ»ÑŒĐ½Đ¾ÑÑ‚ÑŒ ÑÑ‚Đ¸Ñ… ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¾Đ².</translation>
<translation id="8740359287975076522">Đе ÑƒĐ´Đ°ĐµÑ‚ÑÑ Đ½Đ°Đ¹Ñ‚Đ¸ &lt;abbr id="dnsDefinition"&gt;DNS-Đ°Đ´Ñ€ĐµÑ&lt;/abbr&gt; ÑĐ°Đ¹Ñ‚Đ° <ph name="HOST_NAME" />. Đ’Ñ‹Đ¿Đ¾Đ»Đ½ÑĐµÑ‚ÑÑ Đ´Đ¸Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºĐ°.</translation>
-<translation id="8741995161408053644">Đ˜ÑÑ‚Đ¾Ñ€Đ¸Ñ Đ¿Ñ€Đ¾ÑĐ¼Đ¾Ñ‚Ñ€Đ° Ñ‚Đ°ĐºĐ¶Đµ Đ¼Đ¾Đ¶ĐµÑ‚ Ñ…Ñ€Đ°Đ½Đ¸Ñ‚ÑŒÑÑ Đ² Đ²Đ°ÑˆĐµĐ¼ Đ°ĐºĐºĐ°ÑƒĐ½Ñ‚Đµ Google: <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚ÑŒ ÑƒĐ´Đ°Đ»ĐµĐ½Đ¸Đµ</translation>
-<translation id="8790687370365610530">Đ§Ñ‚Đ¾Đ±Ñ‹ Đ¼Ñ‹ Đ¼Đ¾Đ³Đ»Đ¸ Ñ€ĐµĐºĐ¾Đ¼ĐµĐ½Đ´Đ¾Đ²Đ°Ñ‚ÑŒ Đ²Đ°Đ¼ Đ¸Đ½Ñ‚ĐµÑ€ĐµÑĐ½Ñ‹Đ¹ ĐºĐ¾Đ½Ñ‚ĐµĐ½Ñ‚, Đ²ĐºĐ»ÑÑ‡Đ¸Ñ‚Đµ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ Đ¸ÑÑ‚Đ¾Ñ€Đ¸Đ¸.</translation>
<translation id="8798099450830957504">ĐŸĐ¾ ÑƒĐ¼Đ¾Đ»Ñ‡Đ°Đ½Đ¸Ñ</translation>
<translation id="8804164990146287819">ĐŸĐ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ° ĐºĐ¾Đ½Ñ„Đ¸Đ´ĐµĐ½Ñ†Đ¸Đ°Đ»ÑŒĐ½Đ¾ÑÑ‚Đ¸</translation>
<translation id="8820817407110198400">Đ—Đ°ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
@@ -662,13 +701,11 @@
<translation id="8971063699422889582">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° уÑÑ‚Đ°Ñ€ĐµĐ».</translation>
<translation id="8987927404178983737">ĐœĐµÑÑц</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">ĐŸÑ€ĐµĐ´Đ¾ÑÑ‚Đ°Đ²Đ»ĐµĐ½Đ½Ñ‹Đ¹ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ½Đµ Đ¿Ñ€Đ¾Ñ…Đ¾Đ´Đ¸Đ» Đ¿Ñ€Đ¾Đ²ĐµÑ€ĐºÑƒ Đ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Đ¾ÑÑ‚Đ¸. ĐĐ½Đ° Đ½ĐµĐ¾Đ±Ñ…Đ¾Đ´Đ¸Đ¼Đ° Đ² Đ½ĐµĐºĐ¾Ñ‚Đ¾Ñ€Ñ‹Ñ… ÑĐ»ÑƒÑ‡Đ°ÑÑ…, Ñ‡Ñ‚Đ¾Đ±Ñ‹ Đ´Đ¾ĐºĐ°Đ·Đ°Ñ‚ÑŒ, Ñ‡Ñ‚Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ½Đ°Đ´ĐµĐ¶ĐµĐ½ и Đ·Đ°Ñ‰Đ¸Ñ‰Đ°ĐµÑ‚ Đ¾Ñ‚ Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¾Đ².</translation>
<translation id="9001074447101275817">Đ”Đ»Ñ Đ´Đ¾ÑÑ‚ÑƒĐ¿Đ° Đ½Đ° Đ¿Ñ€Đ¾ĐºÑи-ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" /> Ñ‚Ñ€ĐµĐ±ÑƒĐµÑ‚ÑÑ ÑƒĐºĐ°Đ·Đ°Ñ‚ÑŒ Đ¸Đ¼Ñ Đ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ĐµĐ»Ñ Đ¸ Đ¿Đ°Ñ€Đ¾Đ»ÑŒ.</translation>
<translation id="901974403500617787">Đ¡Đ¸ÑÑ‚ĐµĐ¼Đ½Ñ‹Đµ Ñ„Đ»Đ°Đ³Đ¸ Đ¼Đ¾Đ¶ĐµÑ‚ уÑÑ‚Đ°Đ½Đ°Đ²Đ»Đ¸Đ²Đ°Ñ‚ÑŒ Ñ‚Đ¾Đ»ÑŒĐºĐ¾ Đ²Đ»Đ°Đ´ĐµĐ»ĐµÑ† (<ph name="OWNER_EMAIL" />).</translation>
<translation id="9020542370529661692">Đ­Ñ‚Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ¿ĐµÑ€ĐµĐ²ĐµĐ´ĐµĐ½Đ° Đ½Đ° <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="9038649477754266430">Đ˜ÑĐ¿Đ¾Đ»ÑŒĐ·Đ¾Đ²Đ°Ñ‚ÑŒ Đ¿Đ¾Đ´ÑĐºĐ°Đ·ĐºĐ¸ Đ´Đ»Ñ ÑƒÑĐºĐ¾Ñ€ĐµĐ½Đ¸Ñ Đ·Đ°Đ³Ñ€ÑƒĐ·ĐºĐ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†</translation>
<translation id="9039213469156557790">ĐĐ±Ñ€Đ°Ñ‚Đ¸Ñ‚Đµ Đ²Đ½Đ¸Đ¼Đ°Đ½Đ¸Đµ, Ñ‡Ñ‚Đ¾ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ Đ¾Đ±Đ½Đ°Ñ€ÑƒĐ¶ĐµĐ½ Đ½ĐµĐ±ĐµĐ·Đ¾Đ¿Đ°ÑĐ½Ñ‹Đ¹ ĐºĐ¾Đ½Ñ‚ĐµĐ½Ñ‚. Đ’Đ¾Đ·Đ¼Đ¾Đ¶Đ½Đ¾, Đ¿Ñ€Đ¸ Đ¿ĐµÑ€ĐµĐ´Đ°Ñ‡Đµ Ñ€ĐµÑурÑÑ‹ Đ¿Ñ€Đ¾ÑĐ¼Đ°Ñ‚Ñ€Đ¸Đ²Đ°ÑÑ‚ÑÑ Ñ‚Ñ€ĐµÑ‚ÑŒĐ¸Đ¼Đ¸ Đ»Đ¸Ñ†Đ°Đ¼Đ¸, Đ° Đ·Đ»Đ¾ÑƒĐ¼Ñ‹ÑˆĐ»ĐµĐ½Đ½Đ¸ĐºĐ¸ Đ¼Đ¾Đ³ÑƒÑ‚ Đ¿Đ¾Đ»ÑƒÑ‡Đ¸Ñ‚ÑŒ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đº ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ и Đ¸Đ·Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ ее Đ¿Đ¾Đ²ĐµĐ´ĐµĐ½Đ¸Đµ.</translation>
-<translation id="9049981332609050619">Đ’Ñ‹ Đ¿Đ¾Đ¿Ñ‹Ñ‚Đ°Đ»Đ¸ÑÑŒ Đ¾Ñ‚ĐºÑ€Ñ‹Ñ‚ÑŒ <ph name="DOMAIN" />, Đ¾Đ´Đ½Đ°ĐºĐ¾ Đ¿Ñ€ĐµĐ´ÑÑ‚Đ°Đ²Đ»ĐµĐ½Đ½Ñ‹Đ¹ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ½ĐµĐ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ‚ĐµĐ»ĐµĐ½.</translation>
<translation id="9050666287014529139">ĐĐ¾Đ´Đ¾Đ²Đ°Ñ Ñ„Ñ€Đ°Đ·Đ°</translation>
<translation id="9065203028668620118">Đ˜Đ·Đ¼ĐµĐ½Đ¸Ñ‚ÑŒ</translation>
<translation id="9092364396508701805">Đ¡Ñ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° <ph name="HOST_NAME" /> Đ½Đµ Ñ€Đ°Đ±Đ¾Ñ‚Đ°ĐµÑ‚</translation>
diff --git a/chromium/components/strings/components_strings_sk.xtb b/chromium/components/strings/components_strings_sk.xtb
index 8eda247d120..96c06949dc3 100644
--- a/chromium/components/strings/components_strings_sk.xtb
+++ b/chromium/components/strings/components_strings_sk.xtb
@@ -1,21 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sk">
+<translation id="1008557486741366299">Teraz nie</translation>
<translation id="1015730422737071372">Poskytnite ÄalÅ¡ie podrobnosti</translation>
<translation id="1032854598605920125">OtoÄiÅ¥ v smere hodinovĂ½ch ruÄiÄiek</translation>
<translation id="1038842779957582377">neznĂ¡my nĂ¡zov</translation>
+<translation id="1053591932240354961">Web <ph name="SITE" /> momentĂ¡lne nemĂ´Å¾ete navÅ¡tĂ­viÅ¥, pretože vrĂ¡til zakĂ³dovanĂ© poverenia, ktorĂ© Google Chrome nedokĂ¡Å¾e spracovaÅ¥. Chyby siete aÂ Ăºtoky sĂº zvyÄajne doÄasnĂ©, takže by tĂ¡to strĂ¡nka mala neskĂ´r pravdepodobne fungovaÅ¥. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">&amp;VrĂ¡tiÅ¥ spĂ¤Å¥ pridanie</translation>
<translation id="10614374240317010">NeuloženĂ©</translation>
-<translation id="1064422015032085147">Server, ktorĂ½ hostĂ­ tĂºto webovĂº strĂ¡nku, mĂ´Å¾e byÅ¥ preÅ¥aženĂ½ alebo na ňom prebieha Ăºdržba. S cieľom zabrĂ¡niÅ¥ vytvĂ¡raniu prĂ­liÅ¡ veľkej nĂ¡vÅ¡tevnosti, ktorĂ¡ by situĂ¡ciu eÅ¡te zhorÅ¡ila, boli žiadosti na tĂºto webovĂº adresu doÄasne zakĂ¡zanĂ©.</translation>
<translation id="106701514854093668">ZĂ¡ložky plochy</translation>
<translation id="1080116354587839789">PrispĂ´sobiÅ¥ Å¡Ă­rke</translation>
+<translation id="1103124106085518534">Zatiaľ hotovo</translation>
<translation id="1103523840287552314">Vždy preložiÅ¥ nasledujĂºci jazyk: <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Ak je toto nastavenie zaÄiarknutĂ©, Chrome uloÅ¾Ă­ kĂ³piu karty na toto zariadenie, aby ste mohli vypĺňaÅ¥ formulĂ¡re rĂ½chlejÅ¡ie.</translation>
+<translation id="1111153019813902504">NajnovÅ¡ie zĂ¡ložky</translation>
<translation id="1113869188872983271">&amp;VrĂ¡tiÅ¥ spĂ¤Å¥ zmenu poradia</translation>
+<translation id="1126551341858583091">VeľkosÅ¥ sĂºboru v lokĂ¡lnom Ăºložisku je <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">VyrovnĂ¡vacia pamĂ¤Å¥ pravidla je v poriadku</translation>
<translation id="113188000913989374">Web <ph name="SITE" /> hovorĂ­:</translation>
<translation id="1132774398110320017">Nastavenia AutomatickĂ©ho dopĺňania prehliadaÄa Chrome...</translation>
-<translation id="1150979032973867961">Server nedokĂ¡Å¾e overiÅ¥, Äi ide o domĂ©nu <ph name="DOMAIN" />, operaÄnĂ½ systĂ©m vĂ¡Å¡ho poÄĂ­taÄa nedĂ´veruje jej bezpeÄnostnĂ©mu certifikĂ¡tu. MĂ´Å¾e to byÅ¥ spĂ´sobenĂ© nesprĂ¡vnou konfigurĂ¡ciou alebo tĂ½m, že vaÅ¡e pripojenie zachytil ĂºtoÄnĂ­k.</translation>
<translation id="1152921474424827756">PrĂ­stup ku <ph name="BEGIN_LINK" />kĂ³pii vo vyrovnĂ¡vacej pamäti<ph name="END_LINK" /> strĂ¡nky <ph name="URL" /></translation>
<translation id="1158211211994409885">HostiteľskĂ½ web <ph name="HOST_NAME" /> neoÄakĂ¡vane ukonÄil pripojenie.</translation>
<translation id="1161325031994447685">Znovu sa pripojiť k sieti Wi-Fi</translation>
@@ -23,7 +26,8 @@
<translation id="1181037720776840403">OdstrĂ¡niÅ¥</translation>
<translation id="1201402288615127009">Äalej</translation>
<translation id="1201895884277373915">Viac z tĂ½chto strĂ¡nok</translation>
-<translation id="121201262018556460">PokĂºsili ste sa o prĂ­stup na strĂ¡nky <ph name="DOMAIN" />, server vÅ¡ak predložil certifikĂ¡t obsahujĂºci slabĂ½ kÄ¾ĂºÄ. ĂtoÄnĂ­k mohol tento sĂºkromnĂ½ kÄ¾ĂºÄ prelomiÅ¥ a mĂ´Å¾e Ă­sÅ¥ o inĂ½ server, než ste oÄakĂ¡vali (mĂ´Å¾ete komunikovaÅ¥ s ĂºtoÄnĂ­kom).</translation>
+<translation id="1206967143813997005">ChybnĂ½ ĂºvodnĂ½ podpis</translation>
+<translation id="1209206284964581585">Skryť</translation>
<translation id="1219129156119358924">ZabezpeÄenie systĂ©mu</translation>
<translation id="1227224963052638717">NeznĂ¡me pravidlo.</translation>
<translation id="1227633850867390598">Skryť hodnotu</translation>
@@ -44,6 +48,7 @@
<translation id="1426410128494586442">Ăno</translation>
<translation id="1430915738399379752">TlaÄiÅ¥</translation>
<translation id="1442912890475371290">ZablokovanĂ½ pokus <ph name="BEGIN_LINK" /> o nĂ¡vÅ¡tevu strĂ¡nky na domĂ©ne <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Web <ph name="SITE" /> momentĂ¡lne nemĂ´Å¾ete navÅ¡tĂ­viÅ¥, pretože pouÅ¾Ă­va pripĂ­nanie certifikĂ¡tov. Chyby siete aÂ Ăºtoky sĂº zvyÄajne doÄasnĂ©, takže by tĂ¡to strĂ¡nka mala neskĂ´r pravdepodobne fungovaÅ¥. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">ZobrazĂ­ sa uloženĂ¡ (t. j. neaktuĂ¡lna) kĂ³pia tejto strĂ¡nky.</translation>
<translation id="1519264250979466059">DĂ¡tum zostavenia</translation>
<translation id="1549470594296187301">Ak chcete použiÅ¥ tĂºto funkciu, musĂ­te povoliÅ¥ JavaScript.</translation>
@@ -58,36 +63,34 @@
<translation id="1644184664548287040">KonfigurĂ¡cia siete je neplatnĂ¡ a nepodarilo sa ju importovaÅ¥.</translation>
<translation id="1644574205037202324">HistĂ³ria</translation>
<translation id="1645368109819982629">NepodporovanĂ½ protokol</translation>
-<translation id="1655462015569774233">{1,plural, =1{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; platnosÅ¥ jej bezpeÄnostnĂ©ho certifikĂ¡tu vyprÅ¡ala vÄera. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. Hodiny vĂ¡Å¡ho poÄĂ­taÄa sĂº momentĂ¡lne nastavenĂ© na <ph name="CURRENT_DATE" />. Je tento Äas sprĂ¡vny? Ak nie, opravte Äas na hodinĂ¡ch systĂ©mu a potom obnovte tĂºto strĂ¡nku.}few{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; platnosÅ¥ jej bezpeÄnostnĂ©ho certifikĂ¡tu vyprÅ¡ala pred # dňami. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. Hodiny vĂ¡Å¡ho poÄĂ­taÄa sĂº momentĂ¡lne nastavenĂ© na <ph name="CURRENT_DATE" />. Je tento Äas sprĂ¡vny? Ak nie, opravte Äas na hodinĂ¡ch systĂ©mu a potom obnovte tĂºto strĂ¡nku.}many{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; platnosÅ¥ jej bezpeÄnostnĂ©ho certifikĂ¡tu vyprÅ¡ala pred # dňom. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. Hodiny vĂ¡Å¡ho poÄĂ­taÄa sĂº momentĂ¡lne nastavenĂ© na <ph name="CURRENT_DATE" />. Je tento Äas sprĂ¡vny? Ak nie, opravte Äas na hodinĂ¡ch systĂ©mu a potom obnovte tĂºto strĂ¡nku.}other{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; platnosÅ¥ jej bezpeÄnostnĂ©ho certifikĂ¡tu vyprÅ¡ala pred # dňami. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. Hodiny vĂ¡Å¡ho poÄĂ­taÄa sĂº momentĂ¡lne nastavenĂ© na <ph name="CURRENT_DATE" />. Je tento Äas sprĂ¡vny? Ak nie, opravte Äas na hodinĂ¡ch systĂ©mu a potom obnovte tĂºto strĂ¡nku.}}</translation>
<translation id="1676269943528358898">Web <ph name="SITE" /> zvyÄajne chrĂ¡ni vaÅ¡e informĂ¡cie pomocou Å¡ifrovania. KeÄ sa Chrome tentokrĂ¡t pokĂºsil pripojiÅ¥ k webu <ph name="SITE" />, odoslal spĂ¤Å¥ nezvyÄajnĂ© a nesprĂ¡vne poverenia. MĂ´Å¾e sa to staÅ¥ vtedy, keÄ sa za web <ph name="SITE" /> snaÅ¾Ă­ vydĂ¡vaÅ¥ ĂºtoÄnĂ­k alebo keÄ pripojenie preruÅ¡Ă­ prihlasovacia obrazovka siete Wi-Fi. VaÅ¡e informĂ¡cie sĂº stĂ¡le zabezpeÄenĂ©, pretože Chrome zastavil pripojenie eÅ¡te pred vĂ½menou dĂ¡t.</translation>
<translation id="168841957122794586">CertifikĂ¡t servera obsahuje slabĂ½ kryptografickĂ½ kÄ¾ĂºÄ.</translation>
<translation id="1701955595840307032">Získanie navrhovaného obsahu</translation>
-<translation id="1706954506755087368">{1,plural, =1{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej certifikĂ¡t by mal zaÄaÅ¥ platiÅ¥ od zajtra. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom.}few{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej certifikĂ¡t by mal zaÄaÅ¥ platiÅ¥ o # dni. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom.}many{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej certifikĂ¡t by mal zaÄaÅ¥ platiÅ¥ o # dňa. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom.}other{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej certifikĂ¡t by mal zaÄaÅ¥ platiÅ¥ o # dnĂ­. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">SkĂºste kontaktovaÅ¥ sprĂ¡vcu systĂ©mu.</translation>
<translation id="17513872634828108">Otvorené karty</translation>
<translation id="1753706481035618306">ÄŒĂ­slo strĂ¡nky</translation>
-<translation id="1761412452051366565">Ak chcete zĂ­skavaÅ¥ prispĂ´sobenĂ½ obsah navrhnutĂ½ Googlom, zapnite synchronizĂ¡ciu.</translation>
-<translation id="1763864636252898013">Server nedokĂ¡Å¾e overiÅ¥, Äi ide o domĂ©nu <ph name="DOMAIN" />, operaÄnĂ½ systĂ©m vĂ¡Å¡ho zariadenia nedĂ´veruje jej bezpeÄnostnĂ©mu certifikĂ¡tu. MĂ´Å¾e to byÅ¥ spĂ´sobenĂ© nesprĂ¡vnou konfigurĂ¡ciou alebo tĂ½m, že vaÅ¡e pripojenie zachytil ĂºtoÄnĂ­k.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />SkĂºste spustiÅ¥ nĂ¡stroj Diagnostika siete systĂ©mu Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Aktualizujte prĂ­stupovĂº frĂ¡zu na synchronizĂ¡ciu.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Tu sa objavia vaÅ¡e nedĂ¡vno navÅ¡tĂ­venĂ© zĂ¡ložky.</translation>
<translation id="1821930232296380041">NeplatnĂ¡ žiadosÅ¥ alebo parametre žiadosti</translation>
<translation id="1838667051080421715">Zobrazuje sa vĂ¡m zdroj webovej strĂ¡nky.</translation>
<translation id="1871208020102129563">Proxy je nastavenĂ© na použitie pevne danĂ½ch serverov proxy, nie skriptov PAC webovej adresy.</translation>
<translation id="1883255238294161206">Zbaliť zoznam</translation>
<translation id="1898423065542865115">Filtrovanie</translation>
-<translation id="1911837502049945214">Web <ph name="HOST_NAME" /> neakceptoval vĂ¡Å¡ prihlasovacĂ­ certifikĂ¡t alebo platnosÅ¥ certifikĂ¡tu vyprÅ¡ala.</translation>
<translation id="194030505837763158">Prejdite na strĂ¡nku <ph name="LINK" /></translation>
<translation id="1962204205936693436">ZĂ¡ložky (<ph name="DOMAIN" />)</translation>
<translation id="1973335181906896915">Chyba serializĂ¡cie</translation>
<translation id="1974060860693918893">RozÅ¡Ă­renĂ©</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{a 1 ÄalÅ¡ia}few{a # ÄalÅ¡ie}many{a # ÄalÅ¡ej}other{a # ÄalÅ¡Ă­ch}}</translation>
<translation id="2025186561304664664">Proxy je nastavenĂ© na automatickĂº konfigurĂ¡ciu.</translation>
<translation id="2030481566774242610">Mysleli ste strĂ¡nku <ph name="LINK" />?</translation>
<translation id="2031925387125903299">TĂ¡to sprĂ¡va sa vĂ¡m zobrazila, pretože novĂ© weby musia pri prvej nĂ¡vÅ¡teve schvĂ¡liÅ¥ vaÅ¡i rodiÄia.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />SkontrolovaÅ¥ proxy server a brĂ¡nu firewall<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">PSČ</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 nĂ¡vrh}few{# nĂ¡vrhy}many{# nĂ¡vrhu}other{# nĂ¡vrhov}}</translation>
<translation id="2065985942032347596">Vyžaduje sa autentifikĂ¡cia</translation>
<translation id="2079545284768500474">SpĂ¤Å¥</translation>
<translation id="20817612488360358">PouÅ¾Ă­vanie systĂ©movĂ½ch nastavenĂ­ servera proxy je nastavenĂ©, avÅ¡ak je urÄenĂ¡ aj explicitnĂ¡ konfigurĂ¡cia servera proxy.</translation>
@@ -103,32 +106,34 @@
<translation id="2149973817440762519">UpraviÅ¥ zĂ¡ložku</translation>
<translation id="2166049586286450108">ĂplnĂ½ prĂ­stup sprĂ¡vcu</translation>
<translation id="2166378884831602661">Tento web nedokĂ¡Å¾e poskytnĂºÅ¥ zabezpeÄenĂ© pripojenie</translation>
-<translation id="2171101176734966184">PokĂºsili ste sa o prĂ­stup na strĂ¡nky <ph name="DOMAIN" />, server vÅ¡ak predložil certifikĂ¡t podpĂ­sanĂ½ slabĂ½m algoritmom podpisu. ZnamenĂ¡ to, že predloženĂ© poverenia zabezpeÄenia mohli byÅ¥ sfalÅ¡ovanĂ© a mĂ´Å¾e Ă­sÅ¥ o Ăºplne inĂ½ server, než ste oÄakĂ¡vali (mĂ´Å¾ete komunikovaÅ¥ s ĂºtoÄnĂ­kom).</translation>
<translation id="2181821976797666341">PravidlĂ¡</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}few{# adresy}many{# adresy}other{# adries}}</translation>
<translation id="2212735316055980242">Pravidlo sa nenašlo</translation>
<translation id="2213606439339815911">NaÄĂ­tavanie zĂ¡znamov...</translation>
-<translation id="2214283295778284209">StrĂ¡nka <ph name="SITE" /> je nedostupnĂ¡.</translation>
<translation id="2230458221926704099">Opravte svoje pripojenie pomocou <ph name="BEGIN_LINK" />diagnostickej aplikĂ¡cie<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Odoslať</translation>
<translation id="225207911366869382">TĂ¡to hodnota už pre toto pravidlo nie je podporovanĂ¡.</translation>
<translation id="2262243747453050782">Chyba protokolu HTTP</translation>
<translation id="2282872951544483773">Nedostupné experimenty</translation>
<translation id="2292556288342944218">VĂ¡Å¡ prĂ­stup k internetu je blokovanĂ½</translation>
<translation id="229702904922032456">PlatnosÅ¥ certifikĂ¡tu na odomknutie alebo sprostredkovanie vyprÅ¡ala.</translation>
<translation id="230155334948463882">NovĂ¡ karta?</translation>
+<translation id="2305919008529760154">Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; bezpeÄnostnĂ½ certifikĂ¡t mohol byÅ¥ vydanĂ½ podvodnĂ½m spĂ´sobom. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535">DomĂ©na <ph name="DOMAIN" /> vyžaduje pouÅ¾Ă­vateľskĂ© meno a heslo.</translation>
+<translation id="2318774815570432836">Web <ph name="SITE" /> momentĂ¡lne nemĂ´Å¾ete navÅ¡tĂ­viÅ¥, pretože pouÅ¾Ă­va pravidlo HSTS. Chyby siete aÂ Ăºtoky sĂº zvyÄajne doÄasnĂ©, takže by tĂ¡to strĂ¡nka mala neskĂ´r pravdepodobne fungovaÅ¥. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">NeplatnĂ¡ zĂ¡ložka v indexe <ph name="ENTRY_INDEX" /> bola ignorovanĂ¡</translation>
<translation id="2354001756790975382">InĂ© zĂ¡ložky</translation>
<translation id="2359808026110333948">PokraÄovaÅ¥</translation>
<translation id="2365563543831475020">SprĂ¡va o zlyhanĂ­ zaznamenanĂ¡ v Äase <ph name="CRASH_TIME" /> nebola nahranĂ¡</translation>
<translation id="2367567093518048410">Ăroveň</translation>
+<translation id="2371153335857947666">{1,plural, =1{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; platnosÅ¥ jej bezpeÄnostnĂ©ho certifikĂ¡tu vyprÅ¡ala vÄera. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. Hodiny vĂ¡Å¡ho poÄĂ­taÄa sĂº momentĂ¡lne nastavenĂ© na <ph name="CURRENT_DATE" />. Je tento Äas sprĂ¡vny? Ak nie, opravte Äas na hodinĂ¡ch systĂ©mu a potom obnovte tĂºto strĂ¡nku. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" />}few{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; platnosÅ¥ jej bezpeÄnostnĂ©ho certifikĂ¡tu vyprÅ¡ala pred # dňami. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. Hodiny vĂ¡Å¡ho poÄĂ­taÄa sĂº momentĂ¡lne nastavenĂ© na <ph name="CURRENT_DATE" />. Je tento Äas sprĂ¡vny? Ak nie, opravte Äas na hodinĂ¡ch systĂ©mu a potom obnovte tĂºto strĂ¡nku. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" />}many{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; platnosÅ¥ jej bezpeÄnostnĂ©ho certifikĂ¡tu vyprÅ¡ala pred # dňom. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. Hodiny vĂ¡Å¡ho poÄĂ­taÄa sĂº momentĂ¡lne nastavenĂ© na <ph name="CURRENT_DATE" />. Je tento Äas sprĂ¡vny? Ak nie, opravte Äas na hodinĂ¡ch systĂ©mu a potom obnovte tĂºto strĂ¡nku. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" />}other{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; platnosÅ¥ jej bezpeÄnostnĂ©ho certifikĂ¡tu vyprÅ¡ala pred # dňami. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. Hodiny vĂ¡Å¡ho poÄĂ­taÄa sĂº momentĂ¡lne nastavenĂ© na <ph name="CURRENT_DATE" />. Je tento Äas sprĂ¡vny? Ak nie, opravte Äas na hodinĂ¡ch systĂ©mu a potom obnovte tĂºto strĂ¡nku. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">Nie sĂº k dispozĂ­cii žiadne alternatĂ­vy pouÅ¾Ă­vateľskĂ©ho rozhrania</translation>
<translation id="2384307209577226199">PredvolenĂ© nastavenie na podnikovej Ăºrovni</translation>
-<translation id="238526402387145295">Adresu <ph name="SITE" /> momentĂ¡lne nemĂ´Å¾ete navÅ¡tĂ­viÅ¥, pretože danĂ½ web <ph name="BEGIN_LINK" />pouÅ¾Ă­va pravidlo HSTS<ph name="END_LINK" />. Chyby siete a Ăºtoky sĂº zvyÄajne doÄasnĂ©, takže by tĂ¡to strĂ¡nka mala neskĂ´r pravdepodobne fungovaÅ¥.</translation>
<translation id="2386255080630008482">CertifikĂ¡t servera bol zruÅ¡enĂ½.</translation>
<translation id="2392959068659972793">ZobraziÅ¥ pravidlĂ¡ bez nastavenej hodnoty</translation>
<translation id="2396249848217231973">&amp;VrĂ¡tiÅ¥ spĂ¤Å¥ odstrĂ¡nenie</translation>
-<translation id="2413528052993050574">Server nedokĂ¡Å¾e overiÅ¥, Äi ide o domĂ©nu <ph name="DOMAIN" />, jej bezpeÄnostnĂ½ certifikĂ¡t bol zrejme zruÅ¡enĂ½. MĂ´Å¾e to byÅ¥ spĂ´sobenĂ© nesprĂ¡vnou konfigurĂ¡ciou alebo tĂ½m, že vaÅ¡e pripojenie zachytil ĂºtoÄnĂ­k.</translation>
<translation id="2455981314101692989">TĂ¡to webovĂ¡ strĂ¡nka zakĂ¡zala automatickĂ© dopĺňanie tohto formulĂ¡ra.</translation>
+<translation id="2463739503403862330">Vyplniť</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />SpustiÅ¥ nĂ¡stroj Diagnostika siete<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">NeplatnĂ¡ webovĂ¡ adresa vyhľadĂ¡vania.</translation>
<translation id="2491120439723279231">CertifikĂ¡t servera obsahuje chyby.</translation>
@@ -150,10 +155,12 @@
<translation id="2653659639078652383">Odoslať</translation>
<translation id="2674170444375937751">Naozaj chcete odstrĂ¡niÅ¥ tieto strĂ¡nky zo svojej histĂ³rie?</translation>
<translation id="2677748264148917807">Opustiť</translation>
+<translation id="269990154133806163">Server predložil certifikĂ¡t, ktorĂ½ nebol zverejnenĂ½ pomocou pravidla transparentnosti certifikĂ¡tov. V prĂ­pade niektorĂ½ch certifikĂ¡tov sa tĂ¡to podmienka vyžaduje s cieľom zaistiÅ¥ ich dĂ´veryhodnosÅ¥ a ochranu proti ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">Hodnota nezodpovedĂ¡ formĂ¡tu.</translation>
<translation id="2704951214193499422">PrehliadaÄu Chromium sa nepodarilo overiÅ¥ vaÅ¡u kartu. SkĂºste to znova neskĂ´r.</translation>
<translation id="2705137772291741111">UloženĂ¡ kĂ³pia tohto webu (vo vyrovnĂ¡vacej pamäti) bola neÄitateľnĂ¡.</translation>
<translation id="2709516037105925701">AutomatickĂ© dopĺňanie</translation>
+<translation id="2712118517637785082">PokĂºsili ste sa prejsÅ¥ do domĂ©ny <ph name="DOMAIN" />, ale certifikĂ¡t predloženĂ½ serverom bol zruÅ¡enĂ½ vydavateľom. ZnamenĂ¡ to, že povereniam zabezpeÄenia predloženĂ½m serverom sa nedĂ¡ celkom dĂ´verovaÅ¥. Je možnĂ©, že komunikujete sÂ ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">Požiadať o povolenie</translation>
<translation id="2721148159707890343">ŽiadosÅ¥ bola ĂºspeÅ¡nĂ¡</translation>
<translation id="2728127805433021124">CertifikĂ¡t servera je podpĂ­sanĂ½ pomocou slabĂ©ho podpisovĂ©ho algoritmu.</translation>
@@ -165,14 +172,11 @@
<translation id="2824775600643448204">Panel s adresou a vyhľadĂ¡vacĂ­ panel</translation>
<translation id="2826760142808435982">Pripojenie je Å¡ifrovanĂ© pomocou Å¡tandardu <ph name="CIPHER" /> a pouÅ¾Ă­va mechanizmus vĂ½meny kÄ¾ĂºÄov <ph name="KX" />.</translation>
<translation id="2835170189407361413">VymazaÅ¥ formulĂ¡r</translation>
-<translation id="2837049386027881519">Pokus o pripojenie pomocou starÅ¡ej verzie protokolu TLS alebo SSL musel prebehnĂºÅ¥ opakovane. Obvykle to znamenĂ¡, že server pouÅ¾Ă­va zastaranĂ½ softvĂ©r a mĂ´Å¾e maÅ¥ inĂ© problĂ©my so zabezpeÄenĂ­m.</translation>
<translation id="284702764277384724">ZdĂ¡ sa, že certifikĂ¡t servera na webe <ph name="HOST_NAME" /> je faloÅ¡nĂ½.</translation>
<translation id="2889159643044928134">NenaÄĂ­taÅ¥ znova</translation>
-<translation id="2896499918916051536">Tento doplnok nie je podporovanĂ½</translation>
+<translation id="2900469785430194048">Pri pokuse o zobrazenie tejto webovej strĂ¡nky doÅ¡lo miesto v pamäti prehliadaÄa Google Chrome.</translation>
<translation id="2909946352844186028">Zistila sa zmena siete.</translation>
-<translation id="2915500479781995473">Tento server nedokĂ¡zal potvrdiÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />, pretože vyprÅ¡ala platnosÅ¥ bezpeÄnostnĂ©ho certifikĂ¡tu. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. Hodiny vĂ¡Å¡ho poÄĂ­taÄa sĂº momentĂ¡lne nastavenĂ© na <ph name="CURRENT_TIME" />. Je tento Äas sprĂ¡vny? Ak nie, opravte Äas na hodinĂ¡ch systĂ©mu a potom obnovte tĂºto strĂ¡nku.</translation>
<translation id="2922350208395188000">CertifikĂ¡t servera sa nedĂ¡ overiÅ¥.</translation>
-<translation id="2941952326391522266">Server nedokĂ¡Å¾e overiÅ¥, Äi ide o domĂ©nu <ph name="DOMAIN" />, jej bezpeÄnostnĂ½ certifikĂ¡t pochĂ¡dza z domĂ©ny <ph name="DOMAIN2" />. MĂ´Å¾e to byÅ¥ spĂ´sobenĂ© nesprĂ¡vnou konfigurĂ¡ciou alebo tĂ½m, že vaÅ¡e pripojenie zachytil ĂºtoÄnĂ­k.</translation>
<translation id="2948083400971632585">MĂ´Å¾ete zakĂ¡zaÅ¥ ktorĂ©koľvek servery proxy nakonfigurovanĂ© na pripojenie na strĂ¡nke nastavenĂ­.</translation>
<translation id="2955913368246107853">ZatvoriÅ¥ panel pre vyhľadĂ¡vanie</translation>
<translation id="2958431318199492670">KonfigurĂ¡cia siete nie je v sĂºlade so Å¡tandardom ONC. NiektorĂ© Äasti konfigurĂ¡cie sa nemusia importovaÅ¥.</translation>
@@ -186,6 +190,7 @@
<translation id="3024663005179499861">ChybnĂ½ typ pravidla</translation>
<translation id="3032412215588512954">Chcete tento web naÄĂ­taÅ¥ znova?</translation>
<translation id="3037605927509011580">Aj, chyba!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{aspoň jedna položka v synchronizovanĂ½ch zariadeniach}=1{1 položka (a ÄalÅ¡ie v synchronizovanĂ½ch zariadeniach)}few{# položky (a ÄalÅ¡ie v synchronizovanĂ½ch zariadeniach)}many{# položky (a ÄalÅ¡ie v synchronizovanĂ½ch zariadeniach)}other{# položiek (a ÄalÅ¡ie v synchronizovanĂ½ch zariadeniach)}}</translation>
<translation id="3041612393474885105">InformĂ¡cie o certifikĂ¡te</translation>
<translation id="3063697135517575841">Chromu sa nepodarilo overiÅ¥ vaÅ¡u kartu. SkĂºste to znova neskĂ´r.</translation>
<translation id="3093245981617870298">Ste v režime offline.</translation>
@@ -201,15 +206,16 @@
<translation id="3176929007561373547">Skontrolujte nastavenia proxy servera alebo kontaktujte sprĂ¡vcu siete a požiadajte ho, aby skontroloval, Äi proxy server funguje. Ak sa domnievate, že by ste nemali pouÅ¾Ă­vaÅ¥ proxy server: <ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Najnovšie</translation>
<translation id="3207960819495026254">PridanĂ© medzi zĂ¡ložky</translation>
-<translation id="3225919329040284222">Server sa preukĂ¡zal certifikĂ¡tom, ktorĂ½ nezodpovedĂ¡ integrovanĂ½m oÄakĂ¡vaniam. Tieto oÄakĂ¡vania sĂº kvĂ´li vaÅ¡ej ochrane zahrnutĂ© pri urÄitĂ½ch webovĂ½ch strĂ¡nkach s vysokou Ăºrovňou zabezpeÄenia.</translation>
<translation id="3226128629678568754">StlaÄenĂ­m tlaÄidla opakovanĂ©ho spustenia znova odoÅ¡lete Ăºdaje potrebnĂ© na naÄĂ­tanie strĂ¡nky.</translation>
<translation id="3228969707346345236">Prekladanie zlyhalo, pretože strĂ¡nka už je v jazyku: <ph name="LANGUAGE" /></translation>
<translation id="323107829343500871">Zadajte kĂ³d CVC karty <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">VytvoriÅ¥ zĂ¡ložku pre tĂºto strĂ¡nku</translation>
<translation id="3270847123878663523">&amp;VrĂ¡tiÅ¥ spĂ¤Å¥ zmenu poradia</translation>
<translation id="3286538390144397061">Reštartovať</translation>
+<translation id="3303855915957856445">NenaÅ¡li sa žiadne vĂ½sledky vyhľadĂ¡vania</translation>
<translation id="3305707030755673451">VaÅ¡e Ăºdaje boli <ph name="TIME" /> zaÅ¡ifrovanĂ© pomocou vlastnej prĂ­stupovej frĂ¡zy synchronizĂ¡cie. KeÄ ju zadĂ¡te, synchronizĂ¡cia sa spustĂ­.</translation>
<translation id="333371639341676808">ZakĂ¡zaÅ¥ tejto strĂ¡nke otvĂ¡raÅ¥ ÄalÅ¡ie dialĂ³govĂ© oknĂ¡.</translation>
+<translation id="3338095232262050444">ZabezpeÄenĂ©</translation>
<translation id="3340978935015468852">nastavenia</translation>
<translation id="3345135638360864351">VaÅ¡u žiadosÅ¥ o prĂ­stup k tĂ½mto webovĂ½m strĂ¡nkam sa pouÅ¾Ă­vateľovi <ph name="NAME" /> neporadilo odoslaÅ¥. SkĂºste to znova neskĂ´r.</translation>
<translation id="3355823806454867987">Zmeniť nastavenia proxy...</translation>
@@ -227,6 +233,7 @@
<translation id="3452404311384756672">Interval naÄĂ­tania:</translation>
<translation id="3462200631372590220">SkryÅ¥ rozÅ¡Ă­renĂ© podrobnosti</translation>
<translation id="3479539252931486093">NeoÄakĂ¡vali ste to? <ph name="BEGIN_LINK" />Dajte nĂ¡m vedieÅ¥<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Teraz nie</translation>
<translation id="348000606199325318">ID zlyhania <ph name="CRASH_LOCAL_ID" /> (ID servera: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">V tejto chvĂ­li sa nĂ¡m nepodarilo spojiÅ¥ s vaÅ¡Ă­m rodiÄom. SkĂºste to znova neskĂ´r.</translation>
<translation id="3527085408025491307">PrieÄinok</translation>
@@ -235,6 +242,7 @@
<translation id="3542684924769048008">Použiť heslo pre:</translation>
<translation id="3549644494707163724">Å ifrovaÅ¥ vÅ¡etky synchronizovanĂ© Ăºdaje pomocou vlastnej prĂ­stupovej frĂ¡zy pre synchronizĂ¡ciu</translation>
<translation id="3549761410225185768">ÄalÅ¡ie: <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej bezpeÄnostnĂ½ certifikĂ¡t pochĂ¡dza z domĂ©ny <ph name="DOMAIN2" />. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">VaÅ¡e pripojenie nie je sĂºkromnĂ©</translation>
<translation id="3583757800736429874">&amp;Znova presunĂºÅ¥</translation>
<translation id="3586931643579894722">Skryť podrobnosti</translation>
@@ -245,12 +253,15 @@
<translation id="362276910939193118">ZobraziÅ¥ celĂº histĂ³riu</translation>
<translation id="3623476034248543066">Zobraziť hodnotu</translation>
<translation id="3630155396527302611">Ak je už uvedenĂ½ ako program s prĂ­stupom k sieti, skĂºste ho odstrĂ¡niÅ¥ zo zoznamu a znova ho pridaÅ¥.</translation>
+<translation id="3638794133396384728">Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; platnosÅ¥ jej bezpeÄnostnĂ©ho certifikĂ¡tu vyprÅ¡ala. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. Hodiny vĂ¡Å¡ho poÄĂ­taÄa sĂº momentĂ¡lne nastavenĂ© na <ph name="CURRENT_TIME" />. Je tento Äas sprĂ¡vny? Ak nie, opravte Äas na hodinĂ¡ch systĂ©mu a potom obnovte tĂºto strĂ¡nku. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">Tieto experimentĂ¡lne funkcie sa mĂ´Å¾u kedykoľvek zmeniÅ¥, pokaziÅ¥ alebo zmiznĂºÅ¥. Za dĂ´sledky pouÅ¾Ă­vania tĂ½chto experimentov neruÄĂ­me. VĂ¡Å¡ prehliadaÄ sa mĂ´Å¾e samovoľne vznietiÅ¥. Ale teraz vĂ¡Å¾ne. PrehliadaÄ mĂ´Å¾e odstrĂ¡niÅ¥ vÅ¡etky vaÅ¡e dĂ¡ta alebo neÄakanĂ½mi spĂ´sobmi naruÅ¡iÅ¥ zabezpeÄenie Äi ochranu osobnĂ½ch Ăºdajov. Experimenty, ktorĂ© povolĂ­te, budĂº k dispozĂ­cii vÅ¡etkĂ½m pouÅ¾Ă­vateľom tohto prehliadaÄa. BuÄte preto opatrnĂ­.</translation>
<translation id="3650584904733503804">Overenie bolo ĂºspeÅ¡nĂ©</translation>
<translation id="3655670868607891010">Ak sa vĂ¡m tĂ¡to strĂ¡nka zobrazuje Äasto, skĂºste použiÅ¥ tieto strĂ¡nky <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Verzia</translation>
+<translation id="3678029195006412963">Požiadavku sa nepodarilo podpĂ­saÅ¥</translation>
<translation id="3681007416295224113">InformĂ¡cie o certifikĂ¡te</translation>
<translation id="3693415264595406141">Heslo:</translation>
+<translation id="3696411085566228381">žiadne</translation>
<translation id="3700528541715530410">Ojoj! ZdĂ¡ sa, že nemĂ¡te povolenie na prĂ­stup k tejto strĂ¡nke.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">NaÄĂ­tava sa...</translation>
@@ -258,7 +269,6 @@
<translation id="3714780639079136834">ZapnĂºÅ¥ mobilnĂ© dĂ¡ta alebo Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />SkontrolovaÅ¥ proxy server, brĂ¡nu firewall a konfigurĂ¡ciu DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">SkopĂ­rovanĂ½ odkaz</translation>
-<translation id="3744899669254331632">WebovĂ© strĂ¡nky <ph name="SITE" /> momentĂ¡lne nemĂ´Å¾ete navÅ¡tĂ­viÅ¥, pretože odoslali zakĂ³dovanĂ© poverenia, ktorĂ© Chromium neodkĂ¡Å¾e spracovaÅ¥. Chyby siete a Ăºtoky sĂº zvyÄajne doÄasnĂ©, takže tĂ¡to strĂ¡nka by mala pravdepodobne neskĂ´r fungovaÅ¥.</translation>
<translation id="375403751935624634">Preklad zlyhal v dĂ´sledku chyby servera.</translation>
<translation id="3759461132968374835">NemĂ¡te žiadne nedĂ¡vno nahlĂ¡senĂ© zlyhania. Na tejto strĂ¡nke sa nezobrazujĂº zlyhania, ktorĂ© nastali pri zakĂ¡zanej možnosti hlĂ¡senĂ­ zlyhanĂ­.</translation>
<translation id="3788090790273268753">PlatnosÅ¥ certifikĂ¡tu pre tieto strĂ¡nky vyprÅ¡Ă­ v roku 2016 a reÅ¥azec certifikĂ¡tu obsahuje certifikĂ¡t podpĂ­sanĂ½ pomocou funkcie SHA-1.</translation>
@@ -270,19 +280,25 @@
<translation id="3884278016824448484">KolidujĂºci identifikĂ¡tor zariadenia</translation>
<translation id="3885155851504623709">Okrsok</translation>
<translation id="3901925938762663762">Platnosť karty vypršala</translation>
+<translation id="3910267023907260648">PokĂºsili ste sa prejsÅ¥ do domĂ©ny <ph name="DOMAIN" />, ale server predložil certifikĂ¡t podpĂ­sanĂ½ slabĂ½m algoritmom podpisu. ZnamenĂ¡ to, že predloženĂ© poverenia zabezpeÄenia mohli byÅ¥ sfalÅ¡ovanĂ© a mĂ´Å¾e Ă­sÅ¥ oÂ Ăºplne inĂ½ server, než ste oÄakĂ¡vali (je možnĂ©, že komunikujete sÂ ĂºtoÄnĂ­kom) <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej certifikĂ¡t by mal zaÄaÅ¥ platiÅ¥ od zajtra. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" />}few{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej certifikĂ¡t by mal zaÄaÅ¥ platiÅ¥ o # dni. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" />}many{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej certifikĂ¡t by mal zaÄaÅ¥ platiÅ¥ o # dňa. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" />}other{Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej certifikĂ¡t by mal zaÄaÅ¥ platiÅ¥ o # dnĂ­. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">NaÄĂ­tanie dokumentu PDF zlyhalo</translation>
<translation id="3963721102035795474">Režim ÄĂ­taÄky</translation>
+<translation id="397105322502079400">Prebieha vĂ½poÄet...</translation>
<translation id="3973234410852337861">Web <ph name="HOST_NAME" /> je zablokovanĂ½</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 webovĂ¡ strĂ¡nka v okolĂ­}few{# webovĂ© strĂ¡nky v okolĂ­}many{# webovej strĂ¡nky v okolĂ­}other{# webovĂ½ch strĂ¡nok v okolĂ­}}</translation>
<translation id="4021036232240155012">DNS je sieÅ¥ovĂ¡ služba, ktorĂ¡ preloÅ¾Ă­ nĂ¡zov webu do jeho internetovej adresy.</translation>
<translation id="4030383055268325496">&amp;VrĂ¡tiÅ¥ spĂ¤Å¥ pridanie</translation>
-<translation id="4032534284272647190">PrĂ­stup na strĂ¡nku <ph name="URL" /> bol odmietnutĂ½.</translation>
<translation id="404928562651467259">UPOZORNENIE</translation>
<translation id="4058922952496707368">KÄ¾ĂºÄ <ph name="SUBKEY" />: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Klient a server nepodporujĂº spoloÄnĂº verziu protokolu SSL ani Å¡ifrovaciu sĂºpravu.</translation>
<translation id="4079302484614802869">KonfigurĂ¡cia proxy je nastavenĂ¡ na použitie skriptu PAC webovej adresy, nie pevne danĂ½ch serverov proxy.</translation>
<translation id="4103249731201008433">SĂ©riovĂ© ÄĂ­slo zariadenia je neplatnĂ©</translation>
<translation id="4103763322291513355">Na strĂ¡nke &lt;strong&gt;chrome://policy&lt;/strong&gt; nĂ¡jdete zoznam zakĂ¡zanĂ½ch webovĂ½ch adries a ÄalÅ¡ie pravidlĂ¡ vynĂºtenĂ© vaÅ¡Ă­m sprĂ¡vcom systĂ©mu.</translation>
+<translation id="4110615724604346410">Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej bezpeÄnostnĂ½ certifikĂ¡t obsahuje chyby. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">Rozsah pravidla nie je podporovanĂ½.</translation>
+<translation id="4118212371799607889">Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; Chromium nedĂ´veruje jej bezpeÄnostnĂ©mu certifikĂ¡tu. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 ÄalÅ¡ia}few{# ÄalÅ¡ie}many{# ÄalÅ¡ej}other{# ÄalÅ¡Ă­ch}}</translation>
<translation id="4130226655945681476">SkontrolovaÅ¥ sieÅ¥ovĂ© kĂ¡ble, modem a smerovaÄ</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chcete, aby Chromium uložil tĂºto kartu?</translation>
@@ -290,6 +306,7 @@
<translation id="4176463684765177261">ZakĂ¡zanĂ©</translation>
<translation id="4196861286325780578">&amp;Znova presunĂºÅ¥</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />SkontrolovaÅ¥ konfigurĂ¡ciu brĂ¡ny firewall a antivĂ­rusovĂ©ho softvĂ©ru<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{žiadne}=1{1 aplikĂ¡cia ($1)}=2{2 aplikĂ¡cie ($1, $2)}few{# aplikĂ¡cie ($1, $2, $3)}many{# aplikĂ¡cie ($1, $2, $3)}other{# aplikĂ¡ciĂ­ ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Zlyhania</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />SkĂºste spustiÅ¥ nĂ¡stroj Diagnostika siete<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Nie</translation>
@@ -298,14 +315,15 @@
<translation id="4269787794583293679">(Žiadne pouÅ¾Ă­vateľskĂ© meno)</translation>
<translation id="4300246636397505754">NĂ¡vrhy rodiÄa</translation>
<translation id="4304224509867189079">PrihlĂ¡siÅ¥</translation>
+<translation id="432290197980158659">Server predložil certifikĂ¡t, ktorĂ½ nezodpovedĂ¡ vstavanĂ½m požiadavkĂ¡m. Tieto požiadavky sĂº zahrnutĂ© v prĂ­pade konkrĂ©tnych webov s vysokĂ½m zabezpeÄenĂ­m, aby sa zaistila vaÅ¡a ochrana. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">ÄŒlĂ¡nok sa nepodarilo nĂ¡jsÅ¥</translation>
+<translation id="4331708818696583467">NezabezpeÄenĂ©</translation>
<translation id="4372948949327679948">OÄakĂ¡vanĂ¡ hodnota <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">PokĂºsili ste sa o prĂ­stup na strĂ¡nky <ph name="DOMAIN" />, avÅ¡ak certifikĂ¡t poskytnutĂ½ serverom bol vydavateľom zruÅ¡enĂ½. ZnamenĂ¡ to, že povereniam zabezpeÄenia, ktorĂ© predložil server, sa celkom nedĂ¡ dĂ´verovaÅ¥. Je možnĂ©, že komunikujete s ĂºtoÄnĂ­kom.</translation>
<translation id="4381091992796011497">Meno pouÅ¾Ă­vateľa:</translation>
<translation id="4394049700291259645">ZakĂ¡zaÅ¥</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> – <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">vĂ½sledky vyhľadĂ¡vania</translation>
-<translation id="4424024547088906515">Server nedokĂ¡Å¾e overiÅ¥, Äi ide o domĂ©nu <ph name="DOMAIN" />, Chrome nedĂ´veruje jej bezpeÄnostnĂ©mu certifikĂ¡tu. MĂ´Å¾e to byÅ¥ spĂ´sobenĂ© nesprĂ¡vnou konfigurĂ¡ciou alebo tĂ½m, že vaÅ¡e pripojenie zachytil ĂºtoÄnĂ­k.</translation>
+<translation id="4432688616882109544">Web <ph name="HOST_NAME" /> neakceptoval vĂ¡Å¡ prihlasovacĂ­ certifikĂ¡t alebo nebol žiadny poskytnutĂ½.</translation>
<translation id="443673843213245140">Použitie servera proxy je zakĂ¡zanĂ©, ale je urÄenĂ¡ explicitnĂ¡ konfigurĂ¡cia servera proxy.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">TĂ¡to sprĂ¡va sa vĂ¡m zobrazila, pretože je povolenĂ¡ funkcia Google SafeSites.</translation>
@@ -317,12 +335,12 @@
<translation id="4522570452068850558">Podrobnosti</translation>
<translation id="4558551763791394412">SkĂºste deaktivovaÅ¥ rozÅ¡Ă­renia.</translation>
<translation id="4587425331216688090">Chcete adresu odstrĂ¡niÅ¥ z prehliadaÄa Chrome?</translation>
+<translation id="4589078953350245614">PokĂºsili ste sa prejsÅ¥ do domĂ©ny <ph name="DOMAIN" />, ale server predložil neplatnĂ½ certifikĂ¡t. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459">VaÅ¡e pripojenie k domĂ©ne <ph name="DOMAIN" /> je Å¡ifrovanĂ© pomocou modernej Å¡ifrovacej sĂºpravy.</translation>
<translation id="4594403342090139922">&amp;VrĂ¡tiÅ¥ spĂ¤Å¥ odstrĂ¡nenie</translation>
+<translation id="4627442949885028695">PokraÄovaÅ¥ na inom zariadenĂ­</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">PrezerĂ¡te si strĂ¡nku s rozÅ¡Ă­reniami.</translation>
-<translation id="467662567472608290">Server nedokĂ¡Å¾e overiÅ¥, Äi ide o domĂ©nu <ph name="DOMAIN" />, jej bezpeÄnostnĂ½ certifikĂ¡t obsahuje chyby. MĂ´Å¾e to byÅ¥ spĂ´sobenĂ© nesprĂ¡vnou konfigurĂ¡ciou alebo tĂ½m, že vaÅ¡e pripojenie zachytil ĂºtoÄnĂ­k.</translation>
-<translation id="4697214168136963651">Adresa <ph name="URL" /> bola zablokovanĂ¡</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Pripojenie bolo preruÅ¡enĂ©</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />SpustiÅ¥ nĂ¡stroj Diagnostika siete systĂ©mu Windows<ph name="END_LINK" /></translation>
@@ -330,21 +348,26 @@
<translation id="4728558894243024398">Platforma</translation>
<translation id="4744603770635761495">SpustiteľnĂ¡ cesta</translation>
<translation id="4756388243121344051">&amp;HistĂ³ria</translation>
+<translation id="4759238208242260848">Stiahnuté</translation>
<translation id="4764776831041365478">WebovĂ© strĂ¡nky na adrese <ph name="URL" /> mĂ´Å¾u byÅ¥ doÄasne nedostupnĂ© alebo sa mohli natrvalo premiestniÅ¥ na novĂº webovĂº adresu.</translation>
<translation id="4771973620359291008">Vyskytla sa neznĂ¡ma chyba.</translation>
<translation id="4782449893814226250">Požiadali ste rodiÄov o povolenie nĂ¡vÅ¡tevy tejto strĂ¡nky.</translation>
<translation id="4800132727771399293">Skontrolujte dĂ¡tum vyprÅ¡ania platnosti aj kĂ³d CVC a skĂºste to znova</translation>
-<translation id="4807049035289105102">Web <ph name="SITE" /> momentĂ¡lne nemĂ´Å¾ete navÅ¡tĂ­viÅ¥, pretože vrĂ¡til zakĂ³dovanĂ© poverenia, ktorĂ© Google Chrome nedokĂ¡Å¾e spracovaÅ¥. Chyby siete aÂ Ăºtoky sĂº zvyÄajne doÄasnĂ©, takže by tĂ¡to strĂ¡nka mala neskĂ´r pravdepodobne fungovaÅ¥.</translation>
<translation id="4813512666221746211">Chyba siete</translation>
<translation id="4816492930507672669">PrispĂ´sobiÅ¥ strĂ¡nke</translation>
<translation id="4850886885716139402">Zobraziť</translation>
<translation id="4880827082731008257">HľadaÅ¥ v histĂ³rii</translation>
+<translation id="4884656795097055129">KeÄ nastane sprĂ¡vny Äas, zobrazia sa ÄalÅ¡ie ÄlĂ¡nky.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{a 1 ÄalÅ¡ia webovĂ¡ strĂ¡nka}few{a # ÄalÅ¡ie webovĂ© strĂ¡nky}many{a # ÄalÅ¡ej webovej strĂ¡nky}other{a # ÄalÅ¡Ă­ch webovĂ½ch strĂ¡nok}}</translation>
<translation id="4923417429809017348">TĂ¡to strĂ¡nka bola preloženĂ¡ z neznĂ¡meho jazyka do jazyka <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">MusĂ­ byÅ¥ urÄenĂ¡.</translation>
<translation id="4930497775425430760">TĂ¡to sprĂ¡va sa vĂ¡m zobrazila, pretože novĂ½ web musĂ­ pri prvej nĂ¡vÅ¡teve schvĂ¡liÅ¥ vĂ¡Å¡ rodiÄ.</translation>
<translation id="495170559598752135">Akcie</translation>
<translation id="4958444002117714549">Rozbaliť zoznam</translation>
+<translation id="4962322354953122629">Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; Chrome jej bezpeÄnostnĂ©mu certifikĂ¡tu nedĂ´veruje. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911">Preložiť z jazyka <ph name="ORIGINAL_LANGUAGE" /> do jazyka <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Tento doplnok nie je podporovanĂ½</translation>
<translation id="5002932099480077015">Ak tĂºto možnosÅ¥ povolĂ­te, Chrome bude uchovĂ¡vaÅ¥ kĂ³piu vaÅ¡ej karty na tomto zariadenĂ­ na ĂºÄely rĂ½chlejÅ¡ieho dopĺňania formulĂ¡rov.</translation>
<translation id="5019198164206649151">ZlĂ½ stav zĂ¡ložnĂ©ho ukladacieho priestoru</translation>
<translation id="5023310440958281426">Skontrolujte pravidlĂ¡ sprĂ¡vcu</translation>
@@ -352,13 +375,12 @@
<translation id="5031870354684148875">O službe PrekladaÄ Google</translation>
<translation id="5040262127954254034">Ochrana sĂºkromia</translation>
<translation id="5045550434625856497">NesprĂ¡vne heslo</translation>
+<translation id="5056549851600133418">ÄŒlĂ¡nky pre vĂ¡s</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Skontrolovať adresu proxy servera<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">CertifikĂ¡t servera je momentĂ¡lne neplatnĂ½</translation>
<translation id="5089810972385038852">Å tĂ¡t</translation>
-<translation id="5094747076828555589">Server nedokĂ¡Å¾e overiÅ¥, Äi ide o domĂ©nu <ph name="DOMAIN" />, Chromium nedĂ´veruje jej bezpeÄnostnĂ©mu certifikĂ¡tu. MĂ´Å¾e to byÅ¥ spĂ´sobenĂ© nesprĂ¡vnou konfigurĂ¡ciou alebo tĂ½m, že vaÅ¡e pripojenie zachytil ĂºtoÄnĂ­k.</translation>
<translation id="5095208057601539847">Provincia</translation>
<translation id="5115563688576182185">(64-bitovĂ¡ verzia)</translation>
-<translation id="5122371513570456792">NĂ¡jdenĂ© vĂ½sledky (poÄet: <ph name="NUMBER_OF_RESULTS" />) pre dopyt â€<ph name="SEARCH_STRING" />“: <ph name="SEARCH_RESULTS" /></translation>
<translation id="5141240743006678641">Å ifrovaÅ¥ synchronizovanĂ© heslĂ¡ pomocou poverenĂ­ Google</translation>
<translation id="5145883236150621069">V odpovedi na pravidlo sa nachĂ¡dza kĂ³d chyby</translation>
<translation id="5171045022955879922">Vyhľadajte alebo zadajte webovĂº adresu</translation>
@@ -367,18 +389,18 @@
<translation id="5190835502935405962">Panel so zĂ¡ložkami</translation>
<translation id="5199729219167945352">Experimenty</translation>
<translation id="5251803541071282808">Cloud</translation>
+<translation id="5277279256032773186">PouÅ¾Ă­vate Chrome v prĂ¡ci? Firmy mĂ´Å¾u spravovaÅ¥ nastavenia prehliadaÄa Chrome pre svojich zamestnancov. ÄalÅ¡ie informĂ¡cie</translation>
<translation id="5299298092464848405">Pri analĂ½ze pravidla sa vyskytla chyba</translation>
<translation id="5300589172476337783">Zobraziť</translation>
<translation id="5308689395849655368">HlĂ¡senie zlyhanĂ­ je zakĂ¡zanĂ©.</translation>
<translation id="5317780077021120954">Uložiť</translation>
<translation id="5327248766486351172">NĂ¡zov</translation>
+<translation id="5359637492792381994">Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej bezpeÄnostnĂ½ certifikĂ¡t je momentĂ¡lne neplatnĂ½. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">Nastavenia pravidla sa nepodarilo uložiť</translation>
-<translation id="540969355065856584">Server nedokĂ¡Å¾e overiÅ¥, Äi ide o domĂ©nu <ph name="DOMAIN" /> – jej bezpeÄnostnĂ½ certifikĂ¡t je momentĂ¡lne neplatnĂ½. MĂ´Å¾e to byÅ¥ spĂ´sobenĂ© nesprĂ¡vnou konfigurĂ¡ciou alebo tĂ½m, že vaÅ¡e pripojenie napadol ĂºtoÄnĂ­k.</translation>
<translation id="5421136146218899937">OdstrĂ¡niÅ¥ dĂ¡ta prehliadania…</translation>
<translation id="5430298929874300616">OdstrĂ¡niÅ¥ zĂ¡ložku</translation>
<translation id="5431657950005405462">SĂºbor sa nenaÅ¡iel</translation>
<translation id="5435775191620395718">Zobrazuje sa histĂ³ria z tohto zariadenia. <ph name="BEGIN_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">PrispĂ´sobenĂ© nĂ¡vrhy obsahu sĂº momentĂ¡lne zakĂ¡zanĂ©, pretože vaÅ¡e synchronizovanĂ© Ăºdaje sĂº chrĂ¡nenĂ© vlastnou prĂ­stupovou frĂ¡zou.</translation>
<translation id="5439770059721715174">Pri overení schémy sa vyskytla chyba na mieste <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">TĂ¡to strĂ¡nka webu <ph name="HOST_NAME" /> sa nenaÅ¡la</translation>
<translation id="5455374756549232013">ChybnĂ¡ ÄasovĂ¡ peÄiatka pravidla</translation>
@@ -401,14 +423,18 @@
<translation id="5622887735448669177">Chcete tento web opustiť?</translation>
<translation id="5629630648637658800">Nastavenia pravidla sa nepodarilo naÄĂ­taÅ¥</translation>
<translation id="5631439013527180824">NeplatnĂ½ token sprĂ¡vy zariadenia</translation>
-<translation id="5650551054760837876">NenaÅ¡li sa žiadne vĂ½sledky vyhľadĂ¡vania.</translation>
<translation id="5677928146339483299">Zablokované</translation>
<translation id="5710435578057952990">Identita tejto webovej strĂ¡nky nebola overenĂ¡.</translation>
<translation id="5720705177508910913">AktuĂ¡lny pouÅ¾Ă­vateľ</translation>
+<translation id="572328651809341494">NedĂ¡vne karty</translation>
<translation id="5784606427469807560">Pri overovanĂ­ karty sa vyskytol problĂ©m. Skontrolujte pripojenie k internetu a skĂºste to znova.</translation>
<translation id="5785756445106461925">TĂ¡to strĂ¡nka obsahuje aj inĂ© zdroje, ktorĂ© nie sĂº zabezpeÄenĂ©. Tieto zdroje mĂ´Å¾u pri prenose vidieÅ¥ ostatnĂ­ pouÅ¾Ă­vatelia a ĂºtoÄnĂ­k ich mĂ´Å¾e upraviÅ¥ tak, aby zmenil vzhľad strĂ¡nky.</translation>
+<translation id="5786044859038896871">Chcete vyplniÅ¥ informĂ¡cie o karte?</translation>
+<translation id="5803412860119678065">Chcete vyplniÅ¥ informĂ¡cie o karte <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">VaÅ¡e pripojenie k domĂ©ne <ph name="DOMAIN" /> je Å¡ifrovanĂ© pomocou zastaranej Å¡ifrovacej sĂºpravy.</translation>
<translation id="5813119285467412249">&amp;Znova pridať</translation>
+<translation id="5814352347845180253">MĂ´Å¾ete stratiÅ¥ prĂ­stup k prĂ©miovĂ©mu obsahu z webu <ph name="SITE" /> a niektorĂ½ch ÄalÅ¡Ă­ch webov.</translation>
+<translation id="5843436854350372569">PokĂºsili ste sa prejsÅ¥ do domĂ©ny <ph name="DOMAIN" />, ale server predložil certifikĂ¡t obsahujĂºci slabĂ½ kÄ¾ĂºÄ. ĂtoÄnĂ­k mohol tento sĂºkromnĂ½ kÄ¾ĂºÄ prelomiÅ¥ a mĂ´Å¾e Ă­sÅ¥ o inĂ½ server, než ste oÄakĂ¡vali (je možnĂ©, že komunikujete sÂ ĂºtoÄnĂ­kom). <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">TĂ¡to sprĂ¡va sa vĂ¡m zobrazila, pretože vĂ¡Å¡ sprĂ¡vca zablokoval tento web.</translation>
<translation id="5857090052475505287">NovĂ½ prieÄinok</translation>
<translation id="5869405914158311789">K tomuto webu sa nedĂ¡ pripojiÅ¥</translation>
@@ -416,6 +442,7 @@
<translation id="5872918882028971132">NĂ¡vrhy rodiÄa</translation>
<translation id="59107663811261420">Služba Google Payments nepodporuje v prĂ­pade tohto obchodnĂ­ka tento typ karty. Vyberte inĂº kartu.</translation>
<translation id="59174027418879706">Povolené</translation>
+<translation id="5926846154125914413">MĂ´Å¾ete stratiÅ¥ prĂ­stup k prĂ©miovĂ©mu obsahu z niektorĂ½ch webov.</translation>
<translation id="5966707198760109579">TĂ½Å¾deň</translation>
<translation id="5967867314010545767">OdstrĂ¡niÅ¥ z histĂ³rie</translation>
<translation id="5975083100439434680">Oddialiť</translation>
@@ -427,11 +454,11 @@
<translation id="604124094241169006">Automatické</translation>
<translation id="6042308850641462728">Viac</translation>
<translation id="6060685159320643512">Opatrne, tieto experimenty mĂ´Å¾u spĂ´sobiÅ¥ problĂ©my</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{žiadne}=1{1}few{#}many{#}other{#}}</translation>
<translation id="6146055958333702838">Skontrolujte vÅ¡etky kĂ¡ble a reÅ¡tartujte vÅ¡etky pouÅ¾Ă­vanĂ© smerovaÄe, modemy alebo inĂ© sieÅ¥ovĂ© zariadenia.</translation>
<translation id="614940544461990577">VyskĂºÅ¡ajte:</translation>
<translation id="6150607114729249911">Ojoj! Na nĂ¡vÅ¡tevu tejto strĂ¡nky potrebujete sĂºhlas rodiÄov.</translation>
<translation id="6151417162996330722">Obdobie platnosti certifikĂ¡tu servera je prĂ­liÅ¡ dlhĂ©</translation>
-<translation id="6154808779448689242">VrĂ¡tenĂ½ token pravidla sa nezhoduje s aktuĂ¡lnym tokenom</translation>
<translation id="6165508094623778733">Viac informĂ¡ciĂ­</translation>
<translation id="6203231073485539293">Skontrolujte internetové pripojenie</translation>
<translation id="6218753634732582820">Chcete adresu odstrĂ¡niÅ¥ z prehliadaÄa Chromium?</translation>
@@ -444,24 +471,30 @@
<translation id="6328639280570009161">SkĂºste zakĂ¡zaÅ¥ predpovede siete</translation>
<translation id="6337534724793800597">FiltrovaÅ¥ pravidlĂ¡ podľa mena</translation>
<translation id="6342069812937806050">PrĂ¡ve teraz</translation>
+<translation id="6345221851280129312">neznĂ¡ma veľkosÅ¥</translation>
<translation id="6355080345576803305">PrepĂ­sanie verejnej relĂ¡cie</translation>
<translation id="6358450015545214790">ÄŒo znamenajĂº tieto položky?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 ÄalÅ¡Ă­ nĂ¡vrh}few{# ÄalÅ¡ie nĂ¡vrhy}many{# ÄalÅ¡ieho nĂ¡vrhu}other{# ÄalÅ¡Ă­ch nĂ¡vrhov}}</translation>
<translation id="6387478394221739770">MĂ¡te zĂ¡ujem o skvelĂ© novĂ© funkcie prehliadaÄa Chrome? VyskĂºÅ¡ajte verziu beta na strĂ¡nke chrome.com/beta.</translation>
-<translation id="641480858134062906">Adresu <ph name="URL" /> sa nepodarilo naÄĂ­taÅ¥</translation>
+<translation id="6389758589412724634">Pri pokuse o zobrazenie tejto webovej strĂ¡nky doÅ¡lo miesto v pamäti prehliadaÄa Google Chromium.</translation>
+<translation id="6416403317709441254">Web <ph name="SITE" /> momentĂ¡lne nemĂ´Å¾ete navÅ¡tĂ­viÅ¥, pretože odoslal zakĂ³dovanĂ© poverenia, ktorĂ© Chromium neodkĂ¡Å¾e spracovaÅ¥. Chyby siete aÂ Ăºtoky sĂº zvyÄajne doÄasnĂ©, takže tĂ¡to strĂ¡nka by mala pravdepodobne neskĂ´r fungovaÅ¥. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">Nie je možnĂ© skontrolovaÅ¥, Äi bol certifikĂ¡t odmietnutĂ½.</translation>
<translation id="6433595998831338502">Web <ph name="HOST_NAME" /> zamietol pripojenie.</translation>
<translation id="6445051938772793705">Krajina</translation>
<translation id="6451458296329894277">PotvrdiÅ¥ opakovanĂ© odoslanie formulĂ¡ra</translation>
<translation id="6458467102616083041">IgnorovanĂ©, pretože predvolenĂ½ vyhľadĂ¡vaÄ je podľa pravidla zakĂ¡zanĂ½.</translation>
+<translation id="6462969404041126431">Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; jej bezpeÄnostnĂ½ certifikĂ¡t bol zrejme odvolanĂ½. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">PravidlĂ¡ zariadenia</translation>
<translation id="6489534406876378309">SpustiÅ¥ nahrĂ¡vanie sprĂ¡v o zlyhanĂ­</translation>
<translation id="6529602333819889595">&amp;Znova odstrĂ¡niÅ¥</translation>
+<translation id="6534179046333460208">NĂ¡vrhy FyzickĂ©ho webu</translation>
<translation id="6550675742724504774">Možnosti</translation>
+<translation id="6593753688552673085">menej ako <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Možnosti šifrovania</translation>
<translation id="662080504995468778">Zostať</translation>
<translation id="6628463337424475685">VyhľadĂ¡vanie <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">StrĂ¡nky <ph name="SITE" /> momentĂ¡lne nemĂ´Å¾ete navÅ¡tĂ­viÅ¥, pretože <ph name="BEGIN_LINK" />tento certifikĂ¡t bol odvolanĂ½<ph name="END_LINK" />. Chyby siete a Ăºtoky sĂº zvyÄajne doÄasnĂ©, takže by tĂ¡to strĂ¡nka mala neskĂ´r pravdepodobne fungovaÅ¥.</translation>
<translation id="6644283850729428850">Toto pravidlo bolo oznaÄenĂ© ako zastaranĂ©.</translation>
+<translation id="6652240803263749613">Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; operaÄnĂ½ systĂ©m vĂ¡Å¡ho poÄĂ­taÄa nedĂ´veruje jej bezpeÄnostnĂ©mu certifikĂ¡tu. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">UpraviÅ¥ prieÄinok</translation>
<translation id="6660210980321319655">Automaticky nahlĂ¡senĂ© <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Chcete nĂ¡vrh položky formulĂ¡ra odstrĂ¡niÅ¥ z prehliadaÄa Chromium?</translation>
@@ -469,6 +502,7 @@
<translation id="6710213216561001401">Dozadu</translation>
<translation id="6710594484020273272">&lt;Zadajte hľadanĂ½ vĂ½raz&gt;</translation>
<translation id="6711464428925977395">Vyskytol sa problĂ©m s proxy serverom alebo je adresa nesprĂ¡vna.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{žiadne}=1{1 položka}few{# položky}many{# položky}other{# položiek}}</translation>
<translation id="674375294223700098">NeznĂ¡ma chyba spĂ´sobenĂ¡ certifikĂ¡tom servera.</translation>
<translation id="6753269504797312559">Hodnota pravidla</translation>
<translation id="6757797048963528358">VaÅ¡e zariadenie preÅ¡lo do režimu spĂ¡nku.</translation>
@@ -480,7 +514,6 @@
<translation id="6891596781022320156">Ăroveň pravidla nie je podporovanĂ¡.</translation>
<translation id="6895330447102777224">VaÅ¡a karta je overenĂ¡</translation>
<translation id="6897140037006041989">PouÅ¾Ă­vateľskĂ½ agent</translation>
-<translation id="6903907808598579934">ZapnĂºÅ¥ synchronizĂ¡ciu</translation>
<translation id="6915804003454593391">PouÅ¾Ă­vateľ:</translation>
<translation id="6957887021205513506">ZdĂ¡ sa, že certifikĂ¡t servera je faloÅ¡nĂ½.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -488,9 +521,11 @@
<translation id="6970216967273061347">Obvod</translation>
<translation id="6973656660372572881">UrÄenĂ© sĂº pevne danĂ© servery proxy aj skript PAC webovej adresy.</translation>
<translation id="6989763994942163495">ZobraziÅ¥ rozÅ¡Ă­renĂ© nastavenia...</translation>
+<translation id="7000990526846637657">V histĂ³rii sa nenaÅ¡li žiadne zĂ¡znamy</translation>
+<translation id="7009986207543992532">PokĂºsili ste sa prejsÅ¥ do domĂ©ny <ph name="DOMAIN" />, ale server poskytol certifikĂ¡t, ktorĂ©ho obdobie platnosti je prĂ­liÅ¡ dlhĂ© a preto nedĂ´veryhodnĂ©.<ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">VĂ¡Å¡ ĂºÄet Google mĂ´Å¾e maÅ¥ ÄalÅ¡ie formy histĂ³rie prehliadania na adrese <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">HeslĂ¡</translation>
-<translation id="7050187094878475250">PokĂºsili ste sa prejsÅ¥ do domĂ©ny <ph name="DOMAIN" />, ale server udelil certifikĂ¡t, ktorĂ©ho obdobie platnosti je prĂ­liÅ¡ dlhĂ©, a preto nie je dĂ´veryhodnĂ½</translation>
<translation id="7087282848513945231">GrĂ³fstvo</translation>
<translation id="7088615885725309056">Staršie</translation>
<translation id="7090678807593890770">Vyhľadajte na Googli vĂ½raz <ph name="LINK" /></translation>
@@ -509,13 +544,13 @@
<translation id="7246609911581847514">TĂ¡to sprĂ¡va sa vĂ¡m zobrazila, pretože novĂ© weby musĂ­ pri prvej nĂ¡vÅ¡teve schvĂ¡liÅ¥ vĂ¡Å¡ sprĂ¡vca.</translation>
<translation id="724975217298816891">Ak chcete aktualizovaÅ¥ podrobnosti o karte <ph name="CREDIT_CARD" />, zadajte dĂ¡tum vyprÅ¡ania platnosti a kĂ³d CVC. Po potvrdenĂ­ budĂº podrobnosti o karte zdieľanĂ© s tĂ½mto webom.</translation>
<translation id="725866823122871198">SĂºkromnĂ© pripojenie k domĂ©ne <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> sa nedĂ¡ nadviazaÅ¥, pretože dĂ¡tum a Äas (<ph name="DATE_AND_TIME" />) vĂ¡Å¡ho poÄĂ­taÄa sĂº nesprĂ¡vne.</translation>
-<translation id="7265986070661382626">WebovĂ© strĂ¡nky <ph name="SITE" /> momentĂ¡lne nemĂ´Å¾ete navÅ¡tĂ­viÅ¥, pretože <ph name="BEGIN_LINK" />pouÅ¾Ă­vajĂº pripĂ­nanie certifikĂ¡tov<ph name="END_LINK" />. Chyby siete a Ăºtoky sĂº zvyÄajne doÄasnĂ©, takže by tĂ¡to strĂ¡nka mala neskĂ´r pravdepodobne fungovaÅ¥.</translation>
<translation id="7269802741830436641">TĂ¡to webovĂ¡ strĂ¡nka obsahuje cyklickĂ© presmerovanie</translation>
<translation id="7275334191706090484">SpravovanĂ© zĂ¡ložky</translation>
<translation id="7298195798382681320">OdporĂºÄanĂ©</translation>
-<translation id="7301833672208172928">ZapnĂºÅ¥ synchronizĂ¡ciu histĂ³rie</translation>
+<translation id="7309308571273880165">SprĂ¡va o zlyhanĂ­ zaznamenanĂ¡ v Äase <ph name="CRASH_TIME" /> (nahranie vyžiadanĂ© pouÅ¾Ă­vateľom, zatiaľ nebola nahranĂ¡)</translation>
<translation id="7334320624316649418">&amp;Znova zmeniť poradie</translation>
<translation id="733923710415886693">CertifikĂ¡t servera nebol zverejnenĂ½ prostrednĂ­ctvom pravidla transparentnosti certifikĂ¡tov.</translation>
+<translation id="7351800657706554155">NemĂ´Å¾ete prejsÅ¥ na web <ph name="SITE" />, pretože jeho certifikĂ¡t bol odvolanĂ½. Chyby siete aÂ Ăºtoky sĂº zvyÄajne doÄasnĂ©, takže zrejme bude neskĂ´r opĂ¤Å¥ fungovaÅ¥. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">PrĂ­kazovĂ½ riadok</translation>
<translation id="7372973238305370288">vĂ½sledok vyhľadĂ¡vania</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> – <ph name="FULL_DATE" /></translation>
@@ -534,16 +569,17 @@ NabudĂºce by sa vĂ¡m mohol hodiÅ¥ režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="7469372306589899959">Overovanie karty</translation>
<translation id="7481312909269577407">Dopredu</translation>
<translation id="7485870689360869515">NenaÅ¡li sa žiadne Ăºdaje.</translation>
+<translation id="7508255263130623398">IdentifikĂ¡tor zariadenia vrĂ¡tenĂ©ho v rĂ¡mci zĂ¡ruky je prĂ¡zdny alebo sa nezhoduje s identifikĂ¡torom aktuĂ¡lneho zariadenia</translation>
<translation id="7514365320538308">Stiahnuť</translation>
<translation id="7518003948725431193">Na webovej adrese <ph name="URL" /> sa nepodarilo nĂ¡jsÅ¥ žiadne webovĂ© strĂ¡nky</translation>
<translation id="7537536606612762813">Povinné</translation>
<translation id="7542995811387359312">AutomatickĂ© dopĺňanie Ăºdajov o kreditnej karte je zakĂ¡zanĂ©, pretože tento formulĂ¡r nepouÅ¾Ă­va zabezpeÄenĂ© pripojenie.</translation>
<translation id="7549584377607005141">SprĂ¡vne zobrazenie tejto webovej strĂ¡nky si vyžaduje Ăºdaje, ktorĂ© ste zadali v minulosti. Tieto Ăºdaje mĂ´Å¾ete poslaÅ¥ znova, ale v tom prĂ­pade zopakujete vÅ¡etky akcie, ktorĂ© sa na tejto strĂ¡nke vykonali v minulosti.</translation>
<translation id="7554791636758816595">NovĂ¡ karta</translation>
-<translation id="7567204685887185387">Server nedokĂ¡Å¾e overiÅ¥, Äi ide o domĂ©nu <ph name="DOMAIN" />, bol zrejme vydanĂ½ faloÅ¡nĂ½ bezpeÄnostnĂ½ certifikĂ¡t. MĂ´Å¾e to byÅ¥ spĂ´sobenĂ© nesprĂ¡vnou konfigurĂ¡ciou alebo tĂ½m, že vaÅ¡e pripojenie zachytil ĂºtoÄnĂ­k.</translation>
<translation id="7568593326407688803">TĂ¡to strĂ¡nka je v jazyku<ph name="ORIGINAL_LANGUAGE" />Chceli by ste ju preložiÅ¥?</translation>
<translation id="7569952961197462199">Chcete kreditnĂº kartu odstrĂ¡niÅ¥ z prehliadaÄa Chrome?</translation>
<translation id="7578104083680115302">ZaplaÅ¥te rĂ½chlejÅ¡ie na strĂ¡nkach a v aplikĂ¡ciĂ¡ch v rĂ´znych službĂ¡ch pomocou kariet, ktorĂ© ste si uložili na Googli.</translation>
+<translation id="7588950540487816470">FyzickĂ½ web</translation>
<translation id="7592362899630581445">CertifikĂ¡t servera poruÅ¡uje obmedzenia nĂ¡zvov.</translation>
<translation id="759889825892636187">Web <ph name="HOST_NAME" /> momentĂ¡lne nemĂ´Å¾e spracovaÅ¥ tĂºto žiadosÅ¥.</translation>
<translation id="7600965453749440009">Nikdy neprekladať jazyk <ph name="LANGUAGE" /></translation>
@@ -554,6 +590,7 @@ NabudĂºce by sa vĂ¡m mohol hodiÅ¥ režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="7637571805876720304">Chcete kreditnĂº kartu odstrĂ¡niÅ¥ z prehliadaÄa Chromium?</translation>
<translation id="765676359832457558">SkryÅ¥ rozÅ¡Ă­renĂ© nastavenia...</translation>
<translation id="7658239707568436148">Zrušiť</translation>
+<translation id="7667346355482952095">VrĂ¡tenĂ½ token pravidla je prĂ¡zdny alebo sa nezhoduje s aktuĂ¡lnym tokenom</translation>
<translation id="7668654391829183341">NeznĂ¡me zariadenie</translation>
<translation id="7674629440242451245">MĂ¡te zĂ¡ujem o skvelĂ© novĂ© funkcie prehliadaÄa Chrome? VyskĂºÅ¡ajte verziu pre vĂ½vojĂ¡rov na strĂ¡nke chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />PrejsÅ¥ na strĂ¡nky <ph name="SITE" /> (nebezpeÄnĂ©)<ph name="END_LINK" /></translation>
@@ -570,10 +607,10 @@ NabudĂºce by sa vĂ¡m mohol hodiÅ¥ režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="780301667611848630">Nie, Äakujem</translation>
<translation id="7805768142964895445">Stav</translation>
<translation id="7813600968533626083">Chcete nĂ¡vrh odstrĂ¡niÅ¥ z prehliadaÄa Chrome?</translation>
+<translation id="7815407501681723534">NĂ¡jdenĂ© vĂ½sledky (poÄet: <ph name="NUMBER_OF_RESULTS" />) pre dopyt â€<ph name="SEARCH_STRING" />“: <ph name="SEARCH_RESULTS" /></translation>
<translation id="785549533363645510">Nie ste vÅ¡ak neviditeľnĂ½/-Ă¡. PrejdenĂ­m do režimu inkognito neskryjete svoje prehliadanie pred zamestnĂ¡vateľom, poskytovateľom internetovĂ½ch služieb ani pred navÅ¡tĂ­venĂ½mi webmi.</translation>
<translation id="7887683347370398519">Skontrolujte svoj kĂ³d CVC a skĂºste to znova</translation>
<translation id="7894616681410591072">Ojoj! Na nĂ¡vÅ¡tevu tejto strĂ¡nky potrebujete sĂºhlas od nasledujĂºcej osoby: <ph name="NAME" />.</translation>
-<translation id="790025292736025802">Adresa <ph name="URL" /> sa nenašla</translation>
<translation id="7912024687060120840">V prieÄinku:</translation>
<translation id="7920092496846849526">OpĂ½tali ste sa svojho rodiÄa, Äi mĂ´Å¾ete navÅ¡tĂ­viÅ¥ tĂºto strĂ¡nku.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -586,9 +623,10 @@ NabudĂºce by sa vĂ¡m mohol hodiÅ¥ režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="7995512525968007366">Nie je upresnené</translation>
<translation id="8012647001091218357">V tejto chvĂ­li sa nĂ¡m nepodarilo spojiÅ¥ s vaÅ¡imi rodiÄmi. SkĂºste to znova neskĂ´r.</translation>
<translation id="8034522405403831421">TĂ¡to strĂ¡nka je v jazyku <ph name="SOURCE_LANGUAGE" />. Chcete ju preložiÅ¥ do jazyka <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">V histĂ³rii sa nenaÅ¡li žiadne zĂ¡znamy.</translation>
<translation id="8088680233425245692">ÄŒlĂ¡nok sa nepodarilo zobraziÅ¥.</translation>
+<translation id="8089520772729574115">menej ako 1 MB</translation>
<translation id="8091372947890762290">AktivĂ¡cia ÄakĂ¡ na server</translation>
+<translation id="8129262335948759431">neznĂ¡me množstvo</translation>
<translation id="8131740175452115882">Potvrdiť</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Adresu DNS<ph name="END_ABBR" /> servera <ph name="HOST_NAME" /> sa nepodarilo nĂ¡jsÅ¥.</translation>
<translation id="8149426793427495338">VĂ¡Å¡ poÄĂ­taÄ preÅ¡iel do režimu spĂ¡nku.</translation>
@@ -597,6 +635,7 @@ NabudĂºce by sa vĂ¡m mohol hodiÅ¥ režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="8201077131113104583">NeplatnĂ¡ webovĂ¡ adresa aktualizĂ¡cie pre rozÅ¡Ă­renie s ID <ph name="EXTENSION_ID" />.</translation>
<translation id="8218327578424803826">PridelenĂ¡ poloha:</translation>
<translation id="8225771182978767009">Osoba, ktorĂ¡ nastavila tento poÄĂ­taÄ, sa rozhodla danĂ½ web blokovaÅ¥.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Vami hľadanĂ¡ strĂ¡nka použila informĂ¡cie, ktorĂ© ste zadali. NĂ¡vrat na tĂºto strĂ¡nku mĂ´Å¾e spĂ´sobiÅ¥ zopakovanie akcie, ktorĂº ste vykonali. Chcete pokraÄovaÅ¥?</translation>
<translation id="8249320324621329438">Naposledy naÄĂ­tanĂ©:</translation>
<translation id="8261506727792406068">OdstrĂ¡niÅ¥</translation>
@@ -609,12 +648,17 @@ NabudĂºce by sa vĂ¡m mohol hodiÅ¥ režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="8349305172487531364">Panel so zĂ¡ložkami</translation>
<translation id="8363502534493474904">VypnĂºÅ¥ režim v lietadle</translation>
<translation id="8364627913115013041">Nenastavené.</translation>
+<translation id="8380941800586852976">NebezpeÄnĂ¡</translation>
<translation id="8412145213513410671">Zlyhania (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">RovnakĂº prĂ­stupovĂº frĂ¡zu musĂ­te zadaÅ¥ dvakrĂ¡t.</translation>
<translation id="8428213095426709021">Nastavenia</translation>
+<translation id="8433057134996913067">TĂ¡to možnosÅ¥ vĂ¡s odhlĂ¡si z väÄÅ¡iny webov.</translation>
<translation id="8437238597147034694">&amp;VrĂ¡tiÅ¥ spĂ¤Å¥ presunutie</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kreditnĂ¡ karta}few{# kreditnĂ© karty}many{# kreditnej karty}other{# kreditnĂ½ch kariet}}</translation>
+<translation id="8483780878231876732">Ak chcete pouÅ¾Ă­vaÅ¥ karty zÂ ĂºÄtu Google, prihlĂ¡ste sa do Chromu</translation>
<translation id="8488350697529856933">PlatĂ­ pre</translation>
<translation id="8498891568109133222">Web <ph name="HOST_NAME" /> prĂ­liÅ¡ dlho neodpovedal.</translation>
+<translation id="852346902619691059">Tomuto serveru sa nepodarilo dokĂ¡zaÅ¥, že ide o domĂ©nu <ph name="DOMAIN" />; operaÄnĂ½ systĂ©m vĂ¡Å¡ho zariadenia nedĂ´veruje jej bezpeÄnostnĂ©mu certifikĂ¡tu. MĂ´Å¾e to byÅ¥ nĂ¡sledok nesprĂ¡vnej konfigurĂ¡cie alebo napadnutia vĂ¡Å¡ho pripojenia ĂºtoÄnĂ­kom. <ph name="BEGIN_LEARN_MORE_LINK" />ÄalÅ¡ie informĂ¡cie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Služba Google Payments nepodporuje tento typ karty. Vyberte inĂº kartu.</translation>
<translation id="8550022383519221471">Služba synchronizĂ¡cie nie je pre vaÅ¡u domĂ©nu k dispozĂ­cii.</translation>
<translation id="8553075262323480129">Prekladanie zlyhalo, pretože sa nepodarilo urÄiÅ¥ jazyk strĂ¡nky.</translation>
@@ -626,15 +670,12 @@ NabudĂºce by sa vĂ¡m mohol hodiÅ¥ režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="8647750283161643317">ObnoviÅ¥ predvolenĂ© nastavenia vÅ¡etkĂ½ch experimentov</translation>
<translation id="8680787084697685621">InformĂ¡cie o prihlĂ¡senĂ­ do ĂºÄtu sĂº neaktuĂ¡lne.</translation>
<translation id="8703575177326907206">VaÅ¡e pripojenie k domĂ©ne <ph name="DOMAIN" /> sa neÅ¡ifruje.</translation>
-<translation id="8713130696108419660">NesprĂ¡vny poÄiatoÄnĂ½ podpis</translation>
<translation id="8725066075913043281">SkĂºsiÅ¥ znova</translation>
<translation id="8728672262656704056">Ste v režime inkognito</translation>
<translation id="8730621377337864115">Hotovo</translation>
<translation id="8738058698779197622">Ak chcete nadviazaÅ¥ zabezpeÄenĂ© pripojenie, vaÅ¡e hodiny musia byÅ¥ nastavenĂ© sprĂ¡vne. Je to preto, že certifikĂ¡ty, ktorĂ© webovĂ© strĂ¡nky pouÅ¾Ă­vajĂº na vlastnĂº identifikĂ¡ciu, sĂº platnĂ© iba urÄitĂ½ Äas. KeÄže nie sĂº hodiny vĂ¡Å¡ho zariadenia nastavenĂ© sprĂ¡vne, Chromium nemĂ´Å¾e tieto certifikĂ¡ty overiÅ¥.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Adresa DNS&lt;/abbr&gt; webu <ph name="HOST_NAME" /> sa nenaÅ¡la. ProblĂ©m sa diagnostikuje.</translation>
-<translation id="8741995161408053644">VĂ¡Å¡ ĂºÄet Google mĂ´Å¾e maÅ¥ ÄalÅ¡ie formy histĂ³rie prehliadania na adrese <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Znova vymazať</translation>
-<translation id="8790687370365610530">Ak chcete zĂ­skavaÅ¥ prispĂ´sobenĂ½ obsah navrhnutĂ½ Googlom, zapnite synchronizĂ¡ciu histĂ³rie.</translation>
<translation id="8798099450830957504">Predvolené</translation>
<translation id="8804164990146287819">PravidlĂ¡ ochrany sĂºkromia</translation>
<translation id="8820817407110198400">ZĂ¡ložky</translation>
@@ -656,13 +697,11 @@ NabudĂºce by sa vĂ¡m mohol hodiÅ¥ režim inkognito (<ph name="SHORTCUT_KEY" />).
<translation id="8971063699422889582">PlatnosÅ¥ certifikĂ¡tu servera vyprÅ¡ala.</translation>
<translation id="8987927404178983737">Mesiac</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Server prezentoval certifikĂ¡t, ktorĂ½ nebol zverejnenĂ½ pomocou pravidla transparentnosti certifikĂ¡tov. V prĂ­pade niektorĂ½ch certifikĂ¡tov sa tĂ¡to podmienka vyžaduje s cieľom zaistiÅ¥ ich dĂ´veryhodnosÅ¥ a ochranu proti ĂºtoÄnĂ­kom.</translation>
<translation id="9001074447101275817">Proxy server <ph name="DOMAIN" /> vyžaduje pouÅ¾Ă­vateľskĂ© meno a heslo.</translation>
<translation id="901974403500617787">PrĂ­znaky, ktorĂ© platia v celom systĂ©me, mĂ´Å¾e nastaviÅ¥ iba vlastnĂ­k: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">TĂ¡to strĂ¡nka bola preloženĂ¡ do jazyka <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">PouÅ¾Ă­vaÅ¥ službu predpovedĂ­ na rĂ½chlejÅ¡ie naÄĂ­tanie strĂ¡nok</translation>
<translation id="9039213469156557790">TĂ¡to strĂ¡nka obsahuje aj inĂ© zdroje, ktorĂ© nie sĂº zabezpeÄenĂ©. Tieto zdroje mĂ´Å¾u pri prenose vidieÅ¥ ostatnĂ­ pouÅ¾Ă­vatelia a ĂºtoÄnĂ­k ich mĂ´Å¾e upraviÅ¥ tak, aby zmenil sprĂ¡vanie strĂ¡nky.</translation>
-<translation id="9049981332609050619">PokĂºÅ¡ate sa otvoriÅ¥ domĂ©nu <ph name="DOMAIN" />, ale server predložil neplatnĂ½ certifikĂ¡t.</translation>
<translation id="9050666287014529139">PrĂ­stupovĂ¡ frĂ¡za</translation>
<translation id="9065203028668620118">Upraviť</translation>
<translation id="9092364396508701805">TĂ¡to strĂ¡nka webu <ph name="HOST_NAME" /> nefunguje</translation>
diff --git a/chromium/components/strings/components_strings_sl.xtb b/chromium/components/strings/components_strings_sl.xtb
index ddcb4499574..b55ada33866 100644
--- a/chromium/components/strings/components_strings_sl.xtb
+++ b/chromium/components/strings/components_strings_sl.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sl">
+<translation id="1008557486741366299">Ne zdaj</translation>
<translation id="1015730422737071372">Navedite dodatne podrobnosti</translation>
<translation id="1032854598605920125">Sukanje v smeri urnega kazalca</translation>
<translation id="1038842779957582377">neznano ime</translation>
+<translation id="1053591932240354961">Spletnega mesta <ph name="SITE" /> trenutno ni mogoÄe obiskati, saj je poslalo Å¡ifrirane poverilnice, ki jih Google Chrome ne more obdelati. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Razveljavi dodajanje</translation>
<translation id="10614374240317010">Nikoli shranjeno</translation>
-<translation id="1064422015032085147">Strežnik, ki gosti spletno stran, je morda preobremenjen ali poteka njegovo vzdrževanje.
- V izogib ustvarjanja preveÄ prometa in poslabÅ¡anja položaja,
- zahteve za ta URL zaÄasno niso dovoljene.</translation>
<translation id="106701514854093668">Zaznamki namizja</translation>
<translation id="1080116354587839789">Prilagoditev prikaza Å¡irini</translation>
+<translation id="1103124106085518534">KonÄano za zdaj</translation>
<translation id="1103523840287552314">Vedno prevedi ta jezik: <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Če je izbrana ta možnost, bo shranil kopijo kartice v tej napravi za hitrejše izpolnjevanje obrazcev.</translation>
+<translation id="1111153019813902504">Nedavni zaznamki</translation>
<translation id="1113869188872983271">&amp;Razveljavi razvrstitev</translation>
+<translation id="1126551341858583091">Velikosti v lokalni shrambi je <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Predpomnilnik pravilnika ustrezen</translation>
<translation id="113188000913989374"><ph name="SITE" /> sporoÄa:</translation>
<translation id="1132774398110320017">Nastavitve samodejnega izpolnjevanja v Chromu …</translation>
-<translation id="1150979032973867961">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; operacijski sistem vaÅ¡ega raÄunalnika ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="1152921474424827756">Odprite <ph name="BEGIN_LINK" />predpomnjeno kopijo<ph name="END_LINK" /> strani na naslovu <ph name="URL" /></translation>
<translation id="1158211211994409885">Spletno mesto <ph name="HOST_NAME" /> je nepriÄakovano prekinilo povezavo.</translation>
<translation id="1161325031994447685">znova vzpostaviti povezavo z omrežjem Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Odstrani</translation>
<translation id="1201402288615127009">Naprej</translation>
<translation id="1201895884277373915">VeÄ s tega mesta</translation>
-<translation id="121201262018556460">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar ima strežnik potrdilo s Å¡ibkim kljuÄem. Napadalec je morda deÅ¡ifriral zasebni kljuÄ in strežnik morda ni tisti, ki ste ga priÄakovali (morda komunicirate z napadalcem).</translation>
+<translation id="1206967143813997005">Neveljaven prvotni podpis</translation>
+<translation id="1209206284964581585">Zaenkrat skrij</translation>
<translation id="1219129156119358924">Varnost sistema</translation>
<translation id="1227224963052638717">Neznan pravilnik</translation>
<translation id="1227633850867390598">Skrij vrednost</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Da</translation>
<translation id="1430915738399379752">Natisni</translation>
<translation id="1442912890475371290">PrepreÄen poskus <ph name="BEGIN_LINK" />dostopa do strani v domeni <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Spletnega mesta <ph name="SITE" /> trenutno ni mogoÄe obiskati, ker uporablja pripenjanje potrdil. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">Prikaži shranjeno (zastarelo) kopijo te strani.</translation>
<translation id="1519264250979466059">Datum gradnje</translation>
<translation id="1549470594296187301">ÄŒe želite uporabljati to funkcijo, mora biti omogoÄen JavaScript.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Omrežna konfiguracija ni veljavna in je ni mogoÄe uvoziti.</translation>
<translation id="1644574205037202324">Zgodovina</translation>
<translation id="1645368109819982629">Nepodprt protokol</translation>
-<translation id="1655462015569774233">{1,plural, =1{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo vÄeraj. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_DATE" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran.}one{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo pred # dnevom. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_DATE" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran.}two{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo pred # dnevoma. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_DATE" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran.}few{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo pred # dnevi. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_DATE" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran.}other{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo pred # dnevi. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_DATE" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran.}}</translation>
<translation id="1676269943528358898">Spletno mesto <ph name="SITE" /> za zaÅ¡Äito vaÅ¡ih podatkov obiÄajno uporablja Å¡ifriranje. Ko se je Google Chrome tokrat poskusil povezati s spletnim mestom <ph name="SITE" />, je to vrnilo nenavadne in nepravilne poverilnice. Do tega lahko pride, Äe se napadalec lažno predstavlja za spletno mesto <ph name="SITE" /> ali Äe je povezavo prekinil zaslon za prijavo v omrežje Wi-Fi. VaÅ¡i podatki so Å¡e vedno varni, saj je Google Chrome pred izmenjavo podatkov prekinil povezavo.</translation>
<translation id="168841957122794586">Potrdilo strežnika vsebuje Å¡ibek Å¡ifrirni kljuÄ.</translation>
<translation id="1701955595840307032">Prejemanje predlagane vsebine</translation>
-<translation id="1706954506755087368">{1,plural, =1{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo jutriÅ¡nji datum. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.}one{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dan od danes. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.}two{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dneva od danes. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.}few{Strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dni od danes. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.}other{Strežniku ni uspelo dokazati, dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dni od danes. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.}}</translation>
<translation id="1710259589646384581">Operacijski sistem</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Poskusite se obrniti na skrbnika sistema.</translation>
<translation id="17513872634828108">Odpri zavihke</translation>
<translation id="1753706481035618306">Å tevilka strani</translation>
-<translation id="1761412452051366565">Če želite prejemati prilagojeno vsebino, ki jo predlaga Google, vklopite sinhronizacijo.</translation>
-<translation id="1763864636252898013">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; operacijski sistem vaÅ¡e naprave ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Poskušajte zagnati orodje Omrežna diagnostika Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Posodobite geslo za sinhronizacijo.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Tu bodo prikazani nedavno obiskani zaznamki</translation>
<translation id="1821930232296380041">Neveljavna zahteva ali parametri zahteve</translation>
<translation id="1838667051080421715">Ogledujete si vir spletne strani.</translation>
<translation id="1871208020102129563">Proxy je nastavljen na uporabo stalnih strežnikov proxy, ne na URL skripta .pac.</translation>
<translation id="1883255238294161206">Strni seznam</translation>
<translation id="1898423065542865115">Filtriranje</translation>
-<translation id="1911837502049945214">Spletno mesto <ph name="HOST_NAME" /> ni sprejelo potrdila za prijavo ali pa je to poteklo.</translation>
<translation id="194030505837763158">Pojdite na <ph name="LINK" /></translation>
<translation id="1962204205936693436">Zaznamki domene <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Napaka pri serializaciji</translation>
<translation id="1974060860693918893">Dodatno</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{in Å¡e 1}one{in Å¡e #}two{in Å¡e #}few{in Å¡e #}other{in Å¡e #}}</translation>
<translation id="2025186561304664664">Strežnik proxy je nastavljen na samodejno konfiguriranje.</translation>
<translation id="2030481566774242610">Ali ste mislili <ph name="LINK" />?</translation>
<translation id="2031925387125903299">To sporoÄilo je prikazano, ker morajo starÅ¡i odobriti nova spletna mesta ob prvem obisku.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />preveriti strežnik proxy in požarni zid<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Poštna številka</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 predlog}one{# predlog}two{# predloga}few{# predlogi}other{# predlogov}}</translation>
<translation id="2065985942032347596">Zahtevano je preverjanje pristnosti</translation>
<translation id="2079545284768500474">Razveljavi</translation>
<translation id="20817612488360358">Za uporabo so nastavljene sistemske nastavitve strežnika proxy, vendar je navedena tudi izrecna konfiguracija proxyja.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Uredi zaznamek</translation>
<translation id="2166049586286450108">Polni skrbniški dostop</translation>
<translation id="2166378884831602661">To spletno mesto ne more zagotoviti varne povezave</translation>
-<translation id="2171101176734966184">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar ima strežnik potrdilo, podpisano s Å¡ibkim podpisnim algoritmom. To pomeni, da so varnostne poverilnice, ki jih je poslal strežnik, morda ponarejene in strežnik morda ni tisti, ki ga priÄakujete (morda komunicirate z napadalcem).</translation>
<translation id="2181821976797666341">Pravilniki</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 naslov}one{# naslov}two{# naslova}few{# naslovi}other{# naslovov}}</translation>
<translation id="2212735316055980242">Pravilnika ni mogoÄe najti</translation>
<translation id="2213606439339815911">Prenos vnosov ...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> ni na voljo</translation>
<translation id="2230458221926704099">Odpravite težave s povezavo z <ph name="BEGIN_LINK" />aplikacijo za diagnostiko<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Pošlji</translation>
<translation id="225207911366869382">Vrednost za ta pravilnik je zastarela.</translation>
<translation id="2262243747453050782">Napaka HTTP</translation>
<translation id="2282872951544483773">Preizkusi, ki niso na voljo</translation>
<translation id="2292556288342944218">Internetni dostop je blokiran</translation>
<translation id="229702904922032456">Korensko ali vmesno potrdilo je poteklo.</translation>
<translation id="230155334948463882">Nova kartica?</translation>
+<translation id="2305919008529760154">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je bilo morda izdano z goljufijo. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">Domena <ph name="DOMAIN" /> zahteva uporabniško ime in geslo.</translation>
+<translation id="2318774815570432836">Spletnega mesta <ph name="SITE" /> trenutno ni mogoÄe obiskati, saj uporablja protokol HSTS. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">Neveljaveni zaznamek na indeksu <ph name="ENTRY_INDEX" /> je bil prezrt</translation>
<translation id="2354001756790975382">Drugi zaznamki</translation>
<translation id="2359808026110333948">Nadaljuj</translation>
<translation id="2365563543831475020">PoroÄilo o zruÅ¡itvi, zajeto takrat: <ph name="CRASH_TIME" />, ni bilo naloženo</translation>
<translation id="2367567093518048410">Raven</translation>
+<translation id="2371153335857947666">{1,plural, =1{Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo vÄeraj. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_DATE" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.}one{Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo pred # dnevom. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_DATE" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.}two{Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo pred # dnevoma. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_DATE" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.}few{Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo pred # dnevi. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_DATE" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.}other{Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo pred # dnevi. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_DATE" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Ni nadomestnih uporabniških vmesnikov</translation>
<translation id="2384307209577226199">Privzeto za podjetja</translation>
-<translation id="238526402387145295">Spletnega mesta <ph name="SITE" /> trenutno ni mogoÄe obiskati, saj <ph name="BEGIN_LINK" />uporablja protokol HSTS<ph name="END_LINK" />. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje.</translation>
<translation id="2386255080630008482">Potrdilo strežnika je bilo preklicano.</translation>
<translation id="2392959068659972793">Pokaži pravilnike brez nastavljene vrednosti</translation>
<translation id="2396249848217231973">&amp;Razveljavi izbris</translation>
-<translation id="2413528052993050574">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; njegovo varnostno potrdilo je bilo morda preklicano. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="2455981314101692989">Spletna stran je onemogoÄila samodejno izpolnjevanje za ta obrazec.</translation>
+<translation id="2463739503403862330">Izpolni</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Izvajanje orodja za omrežno diagnostiko<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Neveljaven URL iskanja.</translation>
<translation id="2491120439723279231">V potrdilu strežnika so napake.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Pošlji</translation>
<translation id="2674170444375937751">Ali ste prepriÄani, da želite te strani izbrisati iz svoje zgodovine?</translation>
<translation id="2677748264148917807">Zapusti</translation>
+<translation id="269990154133806163">Strežnik je posredoval potrdilo, ki ni bilo javno razkrito na podlagi pravilnika o preglednosti potrdila. To je obvezno za nekatera potrdila zaradi zagotavljanja, da so zaupanja vredna in Å¡Äitijo pred napadalci. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Vrednost se ne ujema z obliko.</translation>
<translation id="2704951214193499422">Chromium trenutno ni mogel potrditi vaše kartice. Poskusite znova pozneje.</translation>
<translation id="2705137772291741111">Shranjena (predpomnjena) kopija tega spletnega mesta je bila neberljiva.</translation>
<translation id="2709516037105925701">Samodejno izpolnjevanje</translation>
+<translation id="2712118517637785082">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar je izdajatelj preklical potrdilo, ki ga je posredoval strežnik. To pomeni, da varnostnim poverilnicam, ki jih je posredoval strežnik, nikakor ne smete zaupati. Morda komunicirate z napadalcem. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">Zahtevaj dovoljenje</translation>
<translation id="2721148159707890343">Zahteva je uspela</translation>
<translation id="2728127805433021124">Strežnikovo potrdilo je podpisano s šibkim podpisnim algoritmom.</translation>
@@ -167,15 +172,11 @@
<translation id="2824775600643448204">Naslovna in iskalna vrstica</translation>
<translation id="2826760142808435982">Za Å¡ifriranje in preverjanje pristnosti povezave se uporablja <ph name="CIPHER" />, kot mehanizem za izmenjavo kljuÄev pa <ph name="KX" />.</translation>
<translation id="2835170189407361413">PoÄisti obrazec</translation>
-<translation id="2837049386027881519">Potrebna je bila vnoviÄna povezava s starejÅ¡o razliÄico protokola TLS ali SSL. To navadno pomeni, da strežnik uporablja zastarelo programsko opremo ali ima druge varnostne težave.</translation>
<translation id="284702764277384724">Videti je, da je potrdilo strežnika na <ph name="HOST_NAME" /> ponarejeno.</translation>
<translation id="2889159643044928134">Ne naloži znova</translation>
-<translation id="2896499918916051536">Ta vtiÄnik ni podprt.</translation>
+<translation id="2900469785430194048">Google Chromu je med poskusom prikazovanja te spletne strani zmanjkalo pomnilnika.</translation>
<translation id="2909946352844186028">Zaznana je bila sprememba omrežja.</translation>
-<translation id="2915500479781995473">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura v raÄunalniku je trenutno nastavljena na <ph name="CURRENT_TIME" />. Je to pravilno? ÄŒe ni, popravite uro v sistemu in osvežite stran.
-</translation>
<translation id="2922350208395188000">Potrdila strežnika ni mogoÄe preveriti.</translation>
-<translation id="2941952326391522266">Strežniku ni uspelo dokazati, da je res <ph name="DOMAIN" />; njegovo varnostno potrdilo je od <ph name="DOMAIN2" />. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="2948083400971632585">NamestniÅ¡ke strežnike, konfigurirane za povezavo, lahko onemogoÄite na strani z nastavitvami.</translation>
<translation id="2955913368246107853">Zapri vrstico za iskanje</translation>
<translation id="2958431318199492670">Omrežna konfiguracija ne ustreza standardu ONC. Deli konfiguracije morda niso bili uvoženi.</translation>
@@ -189,6 +190,7 @@
<translation id="3024663005179499861">NapaÄna vrsta pravilnika</translation>
<translation id="3032412215588512954">Ali želite znova naložiti to spletno mesto?</translation>
<translation id="3037605927509011580">Ti Å¡ment!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{vsaj en element v sinhroniziranih napravah}=1{1 element (in veÄ v sinhroniziranih napravah)}one{# element (in veÄ v sinhroniziranih napravah)}two{# elementa (in veÄ v sinhroniziranih napravah)}few{# elementi (in veÄ v sinhroniziranih napravah)}other{# elementov (in veÄ v sinhroniziranih napravah)}}</translation>
<translation id="3041612393474885105">Informacije o potrdilu</translation>
<translation id="3063697135517575841">Chrome trenutno ni mogel potrditi vaše kartice. Poskusite znova pozneje.</translation>
<translation id="3093245981617870298">Povezava ni vzpostavljena.</translation>
@@ -207,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Najnovejše</translation>
<translation id="3207960819495026254">Zaznamovano</translation>
-<translation id="3225919329040284222">Strežnik je poslal potrdilo, ki se ne ujema z vgrajenimi priÄakovanji. Ta priÄakovanja so zaradi vaÅ¡e varnosti vkljuÄena za nekatera strogo zavarovana spletna mesta.</translation>
<translation id="3226128629678568754">Pritisnite gumb za vnoviÄno nalaganje, da znova poÅ¡ljete podatke za nalaganje strani.</translation>
<translation id="3228969707346345236">Prevod ni uspel, ker je stran že v jeziku <ph name="LANGUAGE" /></translation>
<translation id="323107829343500871">Vnesite CVC za <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Zaznamujte to stran</translation>
<translation id="3270847123878663523">&amp;Razveljavi razvrstitev</translation>
<translation id="3286538390144397061">Znova zaženi</translation>
+<translation id="3303855915957856445">Ni rezultatov iskanja</translation>
<translation id="3305707030755673451">Podatki so bili Å¡ifrirani z vaÅ¡im geslom za sinhronizacijo <ph name="TIME" />. Vnesite ga, Äe želite zaÄeti sinhronizacijo.</translation>
<translation id="333371639341676808">Tej strani prepreÄite, da bi ustvarila dodatna pogovorna okna.</translation>
+<translation id="3338095232262050444">Varno</translation>
<translation id="3340978935015468852">nastavitve</translation>
<translation id="3345135638360864351">Zahteve za dostop do tega spletnega mesta ni bilo mogoÄe poslati osebi <ph name="NAME" />. Poskusite znova.</translation>
<translation id="3355823806454867987">Spremeni nastavitve proxyja ...</translation>
@@ -233,6 +236,7 @@
<translation id="3452404311384756672">Interval prejemanja:</translation>
<translation id="3462200631372590220">Skrij podrobnosti</translation>
<translation id="3479539252931486093">Ali tega niste priÄakovali? <ph name="BEGIN_LINK" />SporoÄite nam<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Ne zdaj</translation>
<translation id="348000606199325318">ID zrušitve <ph name="CRASH_LOCAL_ID" /> (ID strežnika: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Trenutno ni mogoÄe vzpostaviti stika s starÅ¡em. Poskusi znova pozneje.</translation>
<translation id="3527085408025491307">Mapa</translation>
@@ -241,6 +245,7 @@
<translation id="3542684924769048008">Uporaba gesla za:</translation>
<translation id="3549644494707163724">Å ifrirajte vse sinhronizirane podatke s svojim geslom</translation>
<translation id="3549761410225185768">In Å¡e <ph name="NUM_TABS_MORE" /> ...</translation>
+<translation id="3555561725129903880">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je od <ph name="DOMAIN2" />. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Vaša povezava ni zasebna</translation>
<translation id="3583757800736429874">&amp;Uveljavi premik</translation>
<translation id="3586931643579894722">Skrij podrobnosti</translation>
@@ -252,12 +257,15 @@
<translation id="3623476034248543066">Pokaži vrednost</translation>
<translation id="3630155396527302611">Če je že na seznamu programov, ki jim je dovoljen dostop do omrežja, ga poskusite
odstraniti s seznama in znova dodati.</translation>
+<translation id="3638794133396384728">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je poteklo. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. Ura vaÅ¡ega raÄunalnika je trenutno nastavljena na <ph name="CURRENT_TIME" />. Je to videti v redu? ÄŒe ni, pravilno nastavite sistemsko uro in nato osvežite stran. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Te poskusne funkcije se lahko kadar koli spremenijo, odpovedo ali izginejo. Ne dajemo nikakrÅ¡nih jamstev o tem, kaj se lahko zgodi, Äe omogoÄite katerega od teh poskusov, vaÅ¡ brskalnik pa lahko celo spontano zagori. Å alo na stran, vaÅ¡ brskalnik lahko izbriÅ¡e vse vaÅ¡e podatke ali pa sta lahko varnost in zasebnost ogrožena na nepriÄakovane naÄine. Vsi poskusi, ki jih omogoÄite vi, bodo omogoÄeni za vse uporabnike tega brskalnika. Nadaljujte previdno.</translation>
<translation id="3650584904733503804">Preverjanje veljavnosti uspešno</translation>
<translation id="3655670868607891010">Če se to pogosto pokaže, poskusite <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">RazliÄica</translation>
+<translation id="3678029195006412963">Zahteve ni bilo mogoÄe podpisati</translation>
<translation id="3681007416295224113">Informacije o potrdilu</translation>
<translation id="3693415264595406141">Geslo:</translation>
+<translation id="3696411085566228381">brez</translation>
<translation id="3700528541715530410">Videti je, da nimate pravice za dostop do te strani.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Nalagam ...</translation>
@@ -265,7 +273,6 @@
<translation id="3714780639079136834">vklopiti prenos podatkov v mobilnih omrežjih ali Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />preveriti strežnik proxy, požarni zid in konfiguracijo DNS-ja<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Povezava, ki ste jo kopirali</translation>
-<translation id="3744899669254331632">Spletnega mesta <ph name="SITE" /> trenutno ne morete obiskati, ker je poslalo Å¡ifrirane poverilnice, ki jih Chromium ne more obdelati. Napake v omrežju in napadi so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje.</translation>
<translation id="375403751935624634">Prevajanje ni uspelo zaradi napake strežnika.</translation>
<translation id="3759461132968374835">Nimate nedavnih poroÄil o zruÅ¡itvah. ZruÅ¡itve, do katerih je priÅ¡lo, ko je bilo poroÄanje onemogoÄeno, ne bodo prikazane zukaj.</translation>
<translation id="3788090790273268753">Potrdilo za to spletno mesto poteÄe leta 2016 in veriga potrdil vsebuje potrdilo, podpisano z algoritmom SHA-1.</translation>
@@ -277,19 +284,25 @@
<translation id="3884278016824448484">Identifikator naprave je v sporu</translation>
<translation id="3885155851504623709">Okrožje</translation>
<translation id="3901925938762663762">Kartica je potekla</translation>
+<translation id="3910267023907260648">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar je strežnik posredoval potrdilo, podpisano s Å¡ibkim podpisnim algoritmom. To pomeni, da so varnostne poverilnice, ki jih je posredoval strežnik, morda ponarejene in strežnik morda ni tisti, ki ga priÄakujete (morda komunicirate z napadalcem). <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo jutriÅ¡nji datum. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.}one{Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dan od danes. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.}two{Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dneva od danes. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.}few{Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dni od danes. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.}other{Temu strežniku ni uspelo dokazati, dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo naj bi imelo datum v prihodnosti – # dni od danes. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Dokumenta PDF ni bilo mogoÄe naložiti</translation>
<translation id="3963721102035795474">NaÄin bralnika</translation>
+<translation id="397105322502079400">IzraÄunavanje …</translation>
<translation id="3973234410852337861">Spletno mesto <ph name="HOST_NAME" /> je blokirano</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 spletna stran v bližini}one{# spletna stran v bližini}two{# spletni strani v bližini}few{# spletne strani v bližini}other{# spletnih strani v bližini}}</translation>
<translation id="4021036232240155012">DNS je omrežna storitev, ki ime spletnega mesta prevede v njegov internetni naslov.</translation>
<translation id="4030383055268325496">&amp;Razveljavi dodajanje</translation>
-<translation id="4032534284272647190">Dostop do spletnega mesta <ph name="URL" /> zavrnjen.</translation>
<translation id="404928562651467259">OPOZORILO</translation>
<translation id="4058922952496707368">KljuÄ Â»<ph name="SUBKEY" />«: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Odjemalec in strežnik ne podpirata skupne razliÄice protokola SSL ali Å¡ifrirne zbirke.</translation>
<translation id="4079302484614802869">Konfiguracija strežnika proxy je nastavljena na uporabo URL-ja skripta .pac, ne na stalne strežnike proxy.</translation>
<translation id="4103249731201008433">Neveljavna serijska Å¡tevilka naprave</translation>
<translation id="4103763322291513355">Na &lt;strong&gt;chrome://policy&lt;/strong&gt; si lahko ogledate seznam blokiranih URL-jev in drugih pravilnikov, ki jih uveljavlja skrbnik sistema.</translation>
+<translation id="4110615724604346410">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo vsebuje napake. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Obseg pravilnika ni podprt.</translation>
+<translation id="4118212371799607889">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; Chromium ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{in Å¡e 1 drug}one{in Å¡e # drug}two{in Å¡e # druga}few{in Å¡e # drugi}other{in Å¡e # drugih}}</translation>
<translation id="4130226655945681476">preveriti omrežne kable, modem in usmerjevalnik</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Ali želite, da Chromium shrani to kartico?</translation>
@@ -297,6 +310,7 @@
<translation id="4176463684765177261">OnemogoÄeno</translation>
<translation id="4196861286325780578">&amp;Uveljavi premik</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />preveriti požarni zid in konfiguracije protivirusnega programa<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{niÄ}=1{1 aplikacija ($1)}=2{2 aplikaciji ($1, $2)}one{# aplikacija ($1, $2, $3)}two{# aplikaciji ($1, $2, $3)}few{# aplikacije ($1, $2, $3)}other{# aplikacij ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Zrušitve</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Poskušajte zagnati orodje za omrežno diagnostiko<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Ne</translation>
@@ -305,14 +319,15 @@
<translation id="4269787794583293679">(Ni uporabniškega imena)</translation>
<translation id="4300246636397505754">Predlogi staršev</translation>
<translation id="4304224509867189079">Prijava</translation>
+<translation id="432290197980158659">Strežnik je poslal potrdilo, ki se ne ujema z vgrajenimi priÄakovanji. Ta priÄakovanja so zaradi vaÅ¡e varnosti vkljuÄena za nekatera strogo zavarovana spletna mesta. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">ÄŒlanka ni bilo mogoÄe najti</translation>
+<translation id="4331708818696583467">Ni varno</translation>
<translation id="4372948949327679948">PriÄakovana vrednost je vrste <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar je izdajatelj preklical potrdilo, ki ga je poslal strežnik. To pomeni, da varnostnim poverilnicam, ki jih je poslal strežnik, nikakor ne smete zaupati. Morda komunicirate z napadalcem.</translation>
<translation id="4381091992796011497">Uporabniško ime:</translation>
<translation id="4394049700291259645">OnemogoÄi</translation>
<translation id="4395129973926795186"><ph name="START_DATE" />–<ph name="END_DATE" /></translation>
<translation id="4406896451731180161">rezultati iskanja</translation>
-<translation id="4424024547088906515">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; Chrome ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
+<translation id="4432688616882109544">Spletno mesto <ph name="HOST_NAME" /> ni sprejelo potrdila za prijavo ali pa to ni bilo posredovano.</translation>
<translation id="443673843213245140">Uporaba strežnika proxy je onemogoÄena, vendar je njegova konfiguracija izrecno doloÄena.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">To sporoÄilo je prikazano, ker je omogoÄena funkcija Google SafeSites.</translation>
@@ -324,12 +339,12 @@
<translation id="4522570452068850558">Podrobnosti</translation>
<translation id="4558551763791394412">Poskusite onemogoÄiti razÅ¡iritve.</translation>
<translation id="4587425331216688090">Želite odstraniti naslov iz Chroma?</translation>
+<translation id="4589078953350245614">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar je strežnik posredoval neveljavno potrdilo. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Povezava z domeno <ph name="DOMAIN" /> je Å¡ifrirana s sodobno Å¡ifrirno zbirko.</translation>
<translation id="4594403342090139922">&amp;Razveljavi izbris</translation>
+<translation id="4627442949885028695">Nadaljevanje iz druge naprave</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Ogledujete si stran z razširitvami.</translation>
-<translation id="467662567472608290">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; njegovo varnostno potrdilo vsebuje napake. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> je bil blokiran</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Povezava je bila prekinjena</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Izvajanje orodja Omrežna diagnostika Windows<ph name="END_LINK" /></translation>
@@ -337,21 +352,26 @@
<translation id="4728558894243024398">Okolje</translation>
<translation id="4744603770635761495">Pot do izvedljive datoteke</translation>
<translation id="4756388243121344051">&amp;Zgodovina</translation>
+<translation id="4759238208242260848">Prenosi</translation>
<translation id="4764776831041365478">Spletna stran na naslovu <ph name="URL" /> morda zaÄasno ne deluje ali pa je trajno premaknjena na novi spletni naslov.</translation>
<translation id="4771973620359291008">Prišlo je do neznane napake.</translation>
<translation id="4782449893814226250">Starše si vprašal, ali smeš obiskati to stran.</translation>
<translation id="4800132727771399293">Preverite datum poteka in Å¡tevilko CVC ter poskusite znova</translation>
-<translation id="4807049035289105102">Spletnega mesta <ph name="SITE" /> trenutno ne morete obiskati, saj je poslalo Å¡ifrirane poverilnice, ki jih Google Chrome ne more obdelati. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje.</translation>
<translation id="4813512666221746211">Napaka v omrežju</translation>
<translation id="4816492930507672669">Prilagodi strani</translation>
<translation id="4850886885716139402">Pogled</translation>
<translation id="4880827082731008257">Zgodovina iskanja</translation>
+<translation id="4884656795097055129">Ob pravem Äasu bo prikazanih veÄ Älankov.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{in Å¡e 1 spletna stran}one{in Å¡e # spletna stran}two{in Å¡e # spletni strani}few{in Å¡e # spletne strani}other{in Å¡e # spletnih strani}}</translation>
<translation id="4923417429809017348">Stran je bila iz neznanega jezika prevedena v jezik »<ph name="LANGUAGE_LANGUAGE" />«</translation>
<translation id="4926049483395192435">Vrednost mora biti doloÄena.</translation>
<translation id="4930497775425430760">To sporoÄilo je prikazano, ker mora starÅ¡ odobriti nova spletna mesta ob prvem obisku.</translation>
<translation id="495170559598752135">Dejanja</translation>
<translation id="4958444002117714549">Razširi seznam</translation>
+<translation id="4962322354953122629">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; Chrome ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Želite prevesti iz jezika <ph name="ORIGINAL_LANGUAGE" /> v jezik <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Ta vtiÄnik ni podprt</translation>
<translation id="5002932099480077015">ÄŒe je to omogoÄeno, Chrome shrani kopijo kartice v tej napravi zaradi hitrejÅ¡ega izpolnjevanja obrazcev.</translation>
<translation id="5019198164206649151">Neprimerno stanje rezervne shrambe</translation>
<translation id="5023310440958281426">Preverite skrbnikove pravilnike</translation>
@@ -359,13 +379,12 @@
<translation id="5031870354684148875">Google Prevajalnik – vizitka</translation>
<translation id="5040262127954254034">Zasebnost</translation>
<translation id="5045550434625856497">Nepravilno geslo</translation>
+<translation id="5056549851600133418">ÄŒlanki za vas</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />preveriti naslov strežnika proxy<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Potrdilo strežnika trenutno ni veljavno.</translation>
<translation id="5089810972385038852">Zvezna država</translation>
-<translation id="5094747076828555589">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; Chromium ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="5095208057601539847">Provinca</translation>
<translation id="5115563688576182185">(64-bitno)</translation>
-<translation id="5122371513570456792">Za »<ph name="SEARCH_STRING" />« je bilo najdenih toliko <ph name="SEARCH_RESULTS" />: <ph name="NUMBER_OF_RESULTS" />.</translation>
<translation id="5141240743006678641">Å ifrirajte sinhronizirana gesla s poverilnicami za Google</translation>
<translation id="5145883236150621069">Koda napake v odzivu pravilnika</translation>
<translation id="5171045022955879922">PoiÅ¡Äite ali vnesite URL</translation>
@@ -374,18 +393,18 @@
<translation id="5190835502935405962">Vrstica z zaznamki</translation>
<translation id="5199729219167945352">Poskusi</translation>
<translation id="5251803541071282808">Oblak</translation>
+<translation id="5277279256032773186">Uporabljate Chrome v službi? Podjetja lahko upravljajo nastavitve Chroma za zaposlene. Preberite veÄ o tem.</translation>
<translation id="5299298092464848405">Napaka pri razÄlenjevanju pravilnika</translation>
<translation id="5300589172476337783">Pokaži</translation>
<translation id="5308689395849655368">PoroÄanje o zruÅ¡itvah je onemogoÄeno.</translation>
<translation id="5317780077021120954">Shrani</translation>
<translation id="5327248766486351172">Ime</translation>
+<translation id="5359637492792381994">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo trenutno ni veljavno. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Nastavitev pravilnika ni bilo mogoÄe shraniti</translation>
-<translation id="540969355065856584">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; njegovo varnostno potrdilo trenutno ni veljavno. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="5421136146218899937">Izbriši podatke brskanja ...</translation>
<translation id="5430298929874300616">Odstrani zaznamek</translation>
<translation id="5431657950005405462">Datoteke ni bilo mogoÄe najti</translation>
<translation id="5435775191620395718">Prikazana je zgodovina iz te naprave. <ph name="BEGIN_LINK" />VeÄ o tem<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">Prilagojeni predlogi za vsebino so trenutno onemogoÄeni, ker so sinhronizirani podatki zaÅ¡Äiteni z geslom po meri.</translation>
<translation id="5439770059721715174">Napaka preverjanja sheme pri »<ph name="ERROR_PATH" />«: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Te strani spletnega mesta <ph name="HOST_NAME" /> ni mogoÄe najti</translation>
<translation id="5455374756549232013">NapaÄen Äasovni žig pravilnika</translation>
@@ -408,14 +427,18 @@
<translation id="5622887735448669177">Ali želite zapustiti to spletno mesto?</translation>
<translation id="5629630648637658800">Nastavitev pravilnika ni bilo mogoÄe naložiti</translation>
<translation id="5631439013527180824">Neveljaven žeton za upravljanje naprave</translation>
-<translation id="5650551054760837876">Najden ni bil noben rezultat iskanja.</translation>
<translation id="5677928146339483299">Blokirano</translation>
<translation id="5710435578057952990">Identiteta tega spletnega mesta ni bila potrjena.</translation>
<translation id="5720705177508910913">Trenutni uporabnik</translation>
+<translation id="572328651809341494">Nedavni zavihki</translation>
<translation id="5784606427469807560">Težava pri potrditvi kartice. Preverite internetno povezavo in poskusite znova.</translation>
<translation id="5785756445106461925">Poleg tega so na tej strani druga sredstva, ki niso varna. Ta sredstva lahko med prenosom pregledujejo drugi, morebitni napadalec pa jih lahko spremeni, tako da se spremeni videz strani.</translation>
+<translation id="5786044859038896871">Ali želite izpolniti podatke kreditne kartice?</translation>
+<translation id="5803412860119678065">Ali želite izpolniti podatke za kartico <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Povezava z domeno <ph name="DOMAIN" /> je Å¡ifrirana z zastarelo Å¡ifrirno zbirko.</translation>
<translation id="5813119285467412249">&amp;Uveljavi dodajanje</translation>
+<translation id="5814352347845180253">Morda boste izgubili dostop do plaÄljive vsebine na spletnem mestu <ph name="SITE" /> in drugih spletnih mestih.</translation>
+<translation id="5843436854350372569">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar ima strežnik potrdilo s Å¡ibkim kljuÄem. Napadalec je morda deÅ¡ifriral zasebni kljuÄ in strežnik morda ni tisti, ki ste ga priÄakovali (morda komunicirate z napadalcem). <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">To sporoÄilo je prikazano, ker je skrbnik blokiral to spletno mesto.</translation>
<translation id="5857090052475505287">Nova mapa</translation>
<translation id="5869405914158311789">Tega spletnega mesta ni mogoÄe doseÄi</translation>
@@ -423,6 +446,7 @@
<translation id="5872918882028971132">Predlogi staršev</translation>
<translation id="59107663811261420">Ta vrsta kartice ni podprta v storitvi Google Payments pri tem trgovcu. Izberite drugo kartico.</translation>
<translation id="59174027418879706">OmogoÄena</translation>
+<translation id="5926846154125914413">Morda boste izgubili dostop do plaÄljive vsebine na nekaterih spletnih mestih.</translation>
<translation id="5966707198760109579">Teden</translation>
<translation id="5967867314010545767">Odstrani iz zgodovine</translation>
<translation id="5975083100439434680">Pomanjšaj</translation>
@@ -434,12 +458,12 @@
<translation id="604124094241169006">Samodejno</translation>
<translation id="6042308850641462728">VeÄ</translation>
<translation id="6060685159320643512">Previdno, ti poskusi lahko Å¡kodujejo</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{niÄ}=1{1}one{#}two{#}few{#}other{#}}</translation>
<translation id="6146055958333702838">Preverite kable in znova zaženite usmerjevalnike, modeme ali druge omrežne
naprave, ki jih uporabljate.</translation>
<translation id="614940544461990577">Poskusite:</translation>
<translation id="6150607114729249911">Ojoj! Vprašaj starše, ali smeš obiskati to stran.</translation>
<translation id="6151417162996330722">Potrdilo strežnika ima predolgo obdobje veljavnosti.</translation>
-<translation id="6154808779448689242">Vrnjen žeton pravilnika se ne ujema s trenutnim žetonom</translation>
<translation id="6165508094623778733">VeÄ o tem</translation>
<translation id="6203231073485539293">Preverite internetno povezavo</translation>
<translation id="6218753634732582820">Želite naslov odstraniti iz Chromiuma?</translation>
@@ -452,24 +476,30 @@
<translation id="6328639280570009161">Poskusite onemogoÄiti omrežno predvidevanje</translation>
<translation id="6337534724793800597">Filtriraj pravilnike po imenu</translation>
<translation id="6342069812937806050">Pravkar</translation>
+<translation id="6345221851280129312">neznana velikost</translation>
<translation id="6355080345576803305">Preglasitev javne seje</translation>
<translation id="6358450015545214790">VeÄ o teh nastavitvah</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{in Å¡e 1 predlog}one{in Å¡e # predlog}two{in Å¡e # predloga}few{in Å¡e # predlogi}other{in Å¡e # predlogov}}</translation>
<translation id="6387478394221739770">Vas zanimajo super nove funkcije Chroma? Preskusite naÅ¡ kanal za razliÄice beta na chrome.com/beta.</translation>
-<translation id="641480858134062906">Nalaganje <ph name="URL" /> ni uspelo</translation>
+<translation id="6389758589412724634">Chromiumu je med poskusom prikazovanja te spletne strani zmanjkalo pomnilnika.</translation>
+<translation id="6416403317709441254">Spletnega mesta <ph name="SITE" /> trenutno ne morete obiskati, saj je poslalo Å¡ifrirane poverilnice, ki jih Chromium ne more obdelati. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Ni mogoÄe preveriti, ali je bilo potrdilo preklicano.</translation>
<translation id="6433595998831338502">Spletno mesto <ph name="HOST_NAME" /> ni dovolilo povezave.</translation>
<translation id="6445051938772793705">Država</translation>
<translation id="6451458296329894277">Potrdite ponovno pošiljanje obrazca</translation>
<translation id="6458467102616083041">Prezrto, ker je pravilnik onemogoÄil privzeto iskanje.</translation>
+<translation id="6462969404041126431">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; njegovo varnostno potrdilo je bilo morda preklicano. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Pravilniki za naprave</translation>
<translation id="6489534406876378309">ZaÄetek prenaÅ¡anja zruÅ¡itev v storitev</translation>
<translation id="6529602333819889595">&amp;Uveljavi izbris</translation>
+<translation id="6534179046333460208">Predlogi za FiziÄni splet</translation>
<translation id="6550675742724504774">Možnosti</translation>
+<translation id="6593753688552673085">manj kot <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Možnosti šifriranja</translation>
<translation id="662080504995468778">Ostani</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Iskanje</translation>
-<translation id="6634865548447745291">Spletnega mesta <ph name="SITE" /> trenutno ni mogoÄe obiskati, saj <ph name="BEGIN_LINK" />je to potrdilo preklicano<ph name="END_LINK" />. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje.</translation>
<translation id="6644283850729428850">Ta pravilnik je zastarel.</translation>
+<translation id="6652240803263749613">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; operacijski sistem vaÅ¡ega raÄunalnika ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Urejanje mape</translation>
<translation id="6660210980321319655">Samodejno sporoÄeno: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Želite predlog obrazca odstraniti iz Chromiuma?</translation>
@@ -477,6 +507,7 @@
<translation id="6710213216561001401">Nazaj</translation>
<translation id="6710594484020273272">&lt;Vnesite iskalno poizvedbo&gt;</translation>
<translation id="6711464428925977395">Nekaj je narobe s strežnikom proxy ali pa naslov ni pravilen.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{niÄ}=1{1 element}one{# element}two{# elementa}few{# elementi}other{# elementov}}</translation>
<translation id="674375294223700098">Neznana napaka potrdila strežnika.</translation>
<translation id="6753269504797312559">Vrednost pravilnika</translation>
<translation id="6757797048963528358">Naprava je preklopila v stanje pripravljenosti.</translation>
@@ -488,7 +519,6 @@
<translation id="6891596781022320156">Raven pravilnika ni podprta.</translation>
<translation id="6895330447102777224">Kartica je potrjena.</translation>
<translation id="6897140037006041989">Uporabnikov posrednik</translation>
-<translation id="6903907808598579934">Vklopi sinhronizacijo</translation>
<translation id="6915804003454593391">Uporabnik:</translation>
<translation id="6957887021205513506">Potrdilo strežnika je oÄitno ponaredek.</translation>
<translation id="6965382102122355670">V redu</translation>
@@ -496,9 +526,11 @@
<translation id="6970216967273061347">Okraj</translation>
<translation id="6973656660372572881">DoloÄeni so stalni strežniki proxy in URL skripta .pac.</translation>
<translation id="6989763994942163495">Prikaži dodatne nastavitve ...</translation>
+<translation id="7000990526846637657">Ni vnosov v zgodovino</translation>
+<translation id="7009986207543992532">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar je strežnik uporabil potrdilo, ki ima predolgo obdobje veljavnosti, da bi bilo verodostojno. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">V Google RaÄunu so morda druge vrste zgodovine brskanja na <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Gesla</translation>
-<translation id="7050187094878475250">Poskusili ste odpreti <ph name="DOMAIN" />, vendar je strežnik uporabil potrdilo, ki ima predolgo obdobje veljavnosti, da bi bilo verodostojno.</translation>
<translation id="7087282848513945231">Okraj</translation>
<translation id="7088615885725309056">Starejše</translation>
<translation id="7090678807593890770">IÅ¡Äite v Googlu s poizvedbo <ph name="LINK" /></translation>
@@ -517,13 +549,13 @@
<translation id="7246609911581847514">To sporoÄilo je prikazano, ker mora skrbnik odobriti nova spletna mesta ob prvem obisku.</translation>
<translation id="724975217298816891">Vnesite datum poteka in CVC za <ph name="CREDIT_CARD" />, da posodobite podatke o kartici. Ko potrdite, bodo temu spletnemu mestu razkriti podatki o kartici.</translation>
<translation id="725866823122871198">Zasebne povezave z domeno <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ni mogoÄe vzpostaviti, ker sta datum in ura (<ph name="DATE_AND_TIME" />) v raÄunalniku nepravilna.</translation>
-<translation id="7265986070661382626">Spletnega mesta <ph name="SITE" /> trenutno ne morete obiskati, ker <ph name="BEGIN_LINK" />uporablja pripenjanje potrdil<ph name="END_LINK" />. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje.</translation>
<translation id="7269802741830436641">Ta spletna stran ima preusmeritveno zanko</translation>
<translation id="7275334191706090484">Upravljani zaznamki</translation>
<translation id="7298195798382681320">PriporoÄeni</translation>
-<translation id="7301833672208172928">Vklop sinhronizacije zgodovine</translation>
+<translation id="7309308571273880165">PoroÄilo o zruÅ¡itvi, zajeto takrat: <ph name="CRASH_TIME" /> (uporabnik je zahteval nalaganje; ni Å¡e bilo naloženo)</translation>
<translation id="7334320624316649418">&amp;Uveljavi razvrstitev</translation>
<translation id="733923710415886693">Potrdilo strežnika ni bilo razkrito na podlagi pravilnika o preglednosti potrdila.</translation>
+<translation id="7351800657706554155">Spletnega mesta <ph name="SITE" /> trenutno ni mogoÄe obiskati, saj je to potrdilo preklicano. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Ukazna vrstica</translation>
<translation id="7372973238305370288">rezultat iskanja</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> – <ph name="FULL_DATE" /></translation>
@@ -542,16 +574,17 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="7469372306589899959">Potrjevanje kartice</translation>
<translation id="7481312909269577407">Naprej</translation>
<translation id="7485870689360869515">Ni podatkov.</translation>
+<translation id="7508255263130623398">Vrnjen ID naprave pravilnika je prazen ali se ne ujema s trenutnim ID-jem naprave</translation>
<translation id="7514365320538308">Prenos</translation>
<translation id="7518003948725431193">Za ta spletni naslov in bilo mogoÄe najti nobene spletne strani:<ph name="URL" /></translation>
<translation id="7537536606612762813">Obvezen</translation>
<translation id="7542995811387359312">Samodejno izpolnjevanje podatkov o kreditni kartici je onemogoÄeno, ker ta obrazec ne uporablja varne povezave.</translation>
<translation id="7549584377607005141">Za pravilen prikaz te strani so potrebni podatki, ki ste jih vnesli prej. Podatke lahko pošljete še enkrat, vendar se bodo s tem ponovila vsa prejšnja dejanja strani.</translation>
<translation id="7554791636758816595">Nov zavihek</translation>
-<translation id="7567204685887185387">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; njegovo varnostno potrdilo je bilo morda izdano z goljufijo. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="7568593326407688803">Ta stran je v jeziku:<ph name="ORIGINAL_LANGUAGE" />Jo želite prevesti?</translation>
<translation id="7569952961197462199">Želite odstraniti kreditno kartico iz Chroma?</translation>
<translation id="7578104083680115302">Hitro plaÄevanje na spletnih mestih in v aplikacijah v vseh napravah s karticami, ki ste jih shranili v Googlu.</translation>
+<translation id="7588950540487816470">FiziÄni splet</translation>
<translation id="7592362899630581445">Strežnikovo potrdilo krši omejitve imen.</translation>
<translation id="759889825892636187">Spletno mesto <ph name="HOST_NAME" /> trenutno ne more obdelati te zahteve.</translation>
<translation id="7600965453749440009">Nikoli ne prevedi iz jezika: <ph name="LANGUAGE" /></translation>
@@ -562,6 +595,7 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="7637571805876720304">Želite kreditno kartico odstraniti iz Chromiuma?</translation>
<translation id="765676359832457558">Skrij dodatne nastavitve ...</translation>
<translation id="7658239707568436148">PrekliÄi</translation>
+<translation id="7667346355482952095">Vrnjen žeton pravilnika je prazen ali se ne ujema s trenutnim žetonom</translation>
<translation id="7668654391829183341">Neznana naprava</translation>
<translation id="7674629440242451245">Vas zanimajo super nove funkcije Chroma? Preskusite naš kanal za razvijalce na chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Nadaljuj na spletno mesto <ph name="SITE" /> (ni varno)<ph name="END_LINK" /></translation>
@@ -578,10 +612,10 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="780301667611848630">Ne, hvala</translation>
<translation id="7805768142964895445">Stanje</translation>
<translation id="7813600968533626083">Želite odstraniti predlog obrazca iz Chroma?</translation>
+<translation id="7815407501681723534">Za »<ph name="SEARCH_STRING" />« je bilo najdenih toliko <ph name="SEARCH_RESULTS" />: <ph name="NUMBER_OF_RESULTS" />.</translation>
<translation id="785549533363645510">Kljub temu pa niste nevidni. Z uporabo naÄina brez beleženja zgodovine brskanja ne skrijete pred delodajalcem, ponudnikom internetnih storitev ali spletnimi mesti, ki jih obiÅ¡Äete.</translation>
<translation id="7887683347370398519">Preverite CVC in poskusite znova</translation>
<translation id="7894616681410591072">Ojoj! Če želite dostop do te strani, potrebujete dovoljenje te osebe: <ph name="NAME" />.</translation>
-<translation id="790025292736025802"><ph name="URL" /> ni mogoÄe najti</translation>
<translation id="7912024687060120840">V mapi:</translation>
<translation id="7920092496846849526">Starša si vprašal, ali smeš obiskati to stran.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -594,9 +628,10 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="7995512525968007366">Ni navedeno</translation>
<translation id="8012647001091218357">Trenutno ni mogoÄe vzpostaviti stika s starÅ¡i. Poskusi znova pozneje.</translation>
<translation id="8034522405403831421">Ta stran je v jeziku <ph name="SOURCE_LANGUAGE" />. Jo želite prevesti v jezik <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Ni vnosov v zgodovino.</translation>
<translation id="8088680233425245692">ÄŒlanka si ni bilo mogoÄe ogledati.</translation>
+<translation id="8089520772729574115">manj kot 1 MB</translation>
<translation id="8091372947890762290">Čakanje na aktivacijo v strežniku</translation>
+<translation id="8129262335948759431">neznana koliÄina</translation>
<translation id="8131740175452115882">Potrdi</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Naslova DNS<ph name="END_ABBR" /> strežnika spletnega mesta <ph name="HOST_NAME" /> ni bilo mogoÄe najti.</translation>
<translation id="8149426793427495338">RaÄunalnik je preklopil v stanje pripravljenosti.</translation>
@@ -605,6 +640,7 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="8201077131113104583">Neveljaven posodobitveni URL za razširitev z ID-jem »<ph name="EXTENSION_ID" />«.</translation>
<translation id="8218327578424803826">Dodeljena lokacija:</translation>
<translation id="8225771182978767009">Oseba, ki je nastavila ta raÄunalnik, je blokirala to spletno mesto.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Stran, ki jo iÅ¡Äete, je uporabila informacije, ki ste jih vnesli. Z vrnitvijo na to stran se bodo morda ponovila vsa vaÅ¡a dejanja, ki ste jih opravili. Ali želite nadaljevati?</translation>
<translation id="8249320324621329438">Nazadnje preneseno:</translation>
<translation id="8261506727792406068">Izbriši</translation>
@@ -617,12 +653,17 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="8349305172487531364">Vrstica z zaznamki</translation>
<translation id="8363502534493474904">izklopiti naÄin za letalo</translation>
<translation id="8364627913115013041">Ni nastavljen.</translation>
+<translation id="8380941800586852976">Nevarno</translation>
<translation id="8412145213513410671">Zrušitve (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Dvakrat morate vnesti isto geslo.</translation>
<translation id="8428213095426709021">Nastavitve</translation>
+<translation id="8433057134996913067">S tem boste odjavljeni z veÄine spletnih mest.</translation>
<translation id="8437238597147034694">&amp;Razveljavi premik</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kreditna kartica}one{# kreditna kartica}two{# kreditni kartici}few{# kreditne kartice}other{# kreditnih kartic}}</translation>
+<translation id="8483780878231876732">ÄŒe želite uporabljati kartice iz Google RaÄuna, se prijavite v Chrome</translation>
<translation id="8488350697529856933">Velja za</translation>
<translation id="8498891568109133222">Spletno mesto <ph name="HOST_NAME" /> se ni odzvalo v ustreznem Äasu.</translation>
+<translation id="852346902619691059">Temu strežniku ni uspelo dokazati, da je domena <ph name="DOMAIN" />; operacijski sistem vaÅ¡e naprave ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Ta vrsta kartice ni podprta v storitvi Google Payments. Izberite drugo kartico.</translation>
<translation id="8550022383519221471">Sinhronizacija ni na voljo za vašo domeno.</translation>
<translation id="8553075262323480129">Prevod ni uspel, ker ni mogoÄe doloÄiti jezika strani.</translation>
@@ -634,15 +675,12 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="8647750283161643317">Ponastavi vse na privzete</translation>
<translation id="8680787084697685621">Podrobnosti prijave v raÄun so zastarele.</translation>
<translation id="8703575177326907206">Vaša povezava z <ph name="DOMAIN" /> ni kodirana.</translation>
-<translation id="8713130696108419660">NapaÄen zaÄetni podpis</translation>
<translation id="8725066075913043281">Poskusite znova</translation>
<translation id="8728672262656704056">Uporabljate naÄin brez beleženja zgodovine</translation>
<translation id="8730621377337864115">KonÄano</translation>
<translation id="8738058698779197622">ÄŒe želite vzpostaviti varno povezavo, mora biti ura pravilno nastavljena. Potrdila, ki jih uporabljajo spletna mesta za prepoznavanje, namreÄ veljajo samo doloÄen Äas. Ker je ura sistema nepravilna, Chromium teh potrdil ne more preveriti.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Naslova DNS&lt;/abbr&gt; spletnega mesta <ph name="HOST_NAME" /> ni bilo mogoÄe najti. Poteka diagnosticiranje težave.</translation>
-<translation id="8741995161408053644">V Google RaÄunu so morda druge vrste zgodovine brskanja na <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Uveljavi izbris</translation>
-<translation id="8790687370365610530">Če želite prejemati prilagojeno vsebino, ki jo predlaga Google, vklopite sinhronizacijo zgodovine.</translation>
<translation id="8798099450830957504">Privzeto</translation>
<translation id="8804164990146287819">Pravilnik o zasebnosti</translation>
<translation id="8820817407110198400">Zaznamki</translation>
@@ -664,13 +702,11 @@ Pst! NaslednjiÄ vam lahko pride prav bližnjica <ph name="SHORTCUT_KEY" /> za n
<translation id="8971063699422889582">Potrdilo strežnika je poteklo.</translation>
<translation id="8987927404178983737">Mesec</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Strežnik je posredoval potrdilo, ki ni bilo javno razkrito na podlagi pravilnika o preglednosti potrdila. To je obvezno za nekatera potrdila zaradi zagotavljanja, da so zaupanja vredna in Å¡Äitijo pred napadalci.</translation>
<translation id="9001074447101275817">Strežnik proxy <ph name="DOMAIN" /> zahteva uporabniško ime in geslo.</translation>
<translation id="901974403500617787">Zastavice, ki se uporabijo v celotnem sistemu, lahko nastavi samo lastnik: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Ta stran je prevedena v jezik <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Uporaba storitve predvidevanja za hitrejše nalaganje strani</translation>
<translation id="9039213469156557790">Poleg tega so na tej strani druga sredstva, ki niso varna. Ta sredstva lahko med prenosom pregledujejo drugi, morebitni napadalec pa jih lahko spremeni, tako da se spremeni naÄin delovanja strani.</translation>
-<translation id="9049981332609050619">Skušali ste dostopati do domene <ph name="DOMAIN" />, vendar je strežnik predložil neveljavno potrdilo.</translation>
<translation id="9050666287014529139">Geslo</translation>
<translation id="9065203028668620118">Uredi</translation>
<translation id="9092364396508701805">Stran spletnega mesta <ph name="HOST_NAME" /> ne deluje</translation>
diff --git a/chromium/components/strings/components_strings_sr.xtb b/chromium/components/strings/components_strings_sr.xtb
index df1e276c6de..3b83bb1c3e4 100644
--- a/chromium/components/strings/components_strings_sr.xtb
+++ b/chromium/components/strings/components_strings_sr.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sr">
+<translation id="1008557486741366299">Đе ÑĐ°Đ´Đ°</translation>
<translation id="1015730422737071372">ĐĐ°Đ²ĐµĐ´Đ¸Ñ‚Đµ Đ´Đ¾Đ´Đ°Ñ‚Đ½Đµ Đ´ĐµÑ‚Đ°Ñ™Đµ</translation>
<translation id="1032854598605920125">ĐĐºÑ€ĐµĐ½Đ¸Ñ‚Đµ у ÑĐ¼ĐµÑ€Ñƒ ĐºĐ°Đ·Đ°Ñ™ĐºĐµ Đ½Đ° ÑĐ°Ñ‚Ñƒ</translation>
<translation id="1038842779957582377">Đ½ĐµĐ¿Đ¾Đ·Đ½Đ°Ñ‚Đ¾ Đ¸Đ¼Đµ</translation>
+<translation id="1053591932240354961">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" /> Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ Ñ˜Đµ Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚ Đ¿Đ¾ÑĐ»Đ°Đ¾ ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đµ Đ°ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ¸Đ²Đµ ĐºĐ¾Ñ˜Đµ Google Chrome Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾Đ±Ñ€Đ°Đ´Đ¸. Đ“Ñ€ĐµÑˆĐºĐµ и Đ½Đ°Đ¿Đ°Đ´Đ¸ Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸ Ñу Đ¾Đ±Đ¸Ñ‡Đ½Đ¾ Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¸, Đ¿Đ° Ñ›Đµ Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑĐ°Ñ‚Đ¸ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;ĐĐ¿Đ¾Đ·Đ¾Đ²Đ¸ Đ´Đ¾Đ´Đ°Đ²Đ°Ñе</translation>
<translation id="10614374240317010">ĐĐ¸ĐºĐ°Đ´Đ° Ñе Đ½Đµ Ñ‡ÑƒĐ²Đ°</translation>
-<translation id="1064422015032085147">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đ° ĐºĐ¾Đ¼ Ñе Ñ…Đ¾ÑÑ‚ÑƒÑ˜Đµ Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Ñ˜Đµ Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Đ¿Ñ€ĐµĐ¾Đ¿Ñ‚ĐµÑ€ĐµÑ›ĐµĐ½ или Ñе Đ¿Đ¾Đ¿Ñ€Đ°Đ²Ñ™Đ°.
- Да би Ñе Đ¸Đ·Đ±ĐµĐ³Đ»Đ¾ Đ³ĐµĐ½ĐµÑ€Đ¸ÑĐ°Ñе Đ¿Ñ€ĐµĐ²Đ¸ÑˆĐµ ÑĐ°Đ¾Đ±Ñ€Đ°Ñ›Đ°Ñ˜Đ° и Đ¿Đ¾Đ³Đ¾Ñ€ÑˆĐ°Đ²Đ°Ñе ÑĐ¸Ñ‚ÑƒĐ°Ñ†Đ¸Ñ˜Đµ,
- Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¾ ÑĐ¼Đ¾ Đ¾Đ½ĐµĐ¼Đ¾Đ³ÑƒÑ›Đ¸Đ»Đ¸ Đ·Đ°Ñ…Ñ‚ĐµĐ²Đµ Đ·Đ° Đ¾Đ²Đ°Ñ˜ URL.</translation>
<translation id="106701514854093668">ĐĐ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡Đ¸ Đ½Đ° Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Ñƒ</translation>
<translation id="1080116354587839789">Đ£ĐºĐ»Đ¾Đ¿Đ¸Ñ‚Đµ Đ¿Đ¾ ÑˆĐ¸Ñ€Đ¸Đ½Đ¸</translation>
+<translation id="1103124106085518534">Đ“Đ¾Ñ‚Đ¾Đ²Đ¾ Đ·Đ° ÑĐ°Đ´Đ°</translation>
<translation id="1103523840287552314">Đ£Đ²ĐµĐº Đ¿Ñ€ĐµĐ²Đ¾Đ´Đ¸ <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">ĐĐºĐ¾ Đ¾Đ·Đ½Đ°Ñ‡Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ Đ¾Đ¿Ñ†Đ¸Ñ˜Ñƒ, Chrome Ñ›Đµ ÑĐºĐ»Đ°Đ´Đ¸ÑˆÑ‚Đ¸Ñ‚Đ¸ ĐºĐ¾Đ¿Đ¸Ñ˜Ñƒ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ Đ½Đ° Đ¾Đ²Đ¾Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Ñƒ Ñ€Đ°Đ´Đ¸ Đ±Ñ€Đ¶ĐµĐ³ Đ¿Đ¾Đ¿ÑƒÑĐ°Đ²Đ°ÑĐ° Đ¾Đ±Ñ€Đ°Đ·Đ°Ñ†Đ°.</translation>
+<translation id="1111153019813902504">ĐĐµĐ´Đ°Đ²Đ½Đ¾ ĐºĐ¾Ñ€Đ¸ÑˆÑ›ĐµĐ½Đ¸ Đ¾Đ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡Đ¸</translation>
<translation id="1113869188872983271">&amp;ĐĐ¿Đ¾Đ·Đ¾Đ²Đ¸ Đ¿Ñ€Đ¾Đ¼ĐµĐ½Ñƒ Ñ€ĐµĐ´Đ¾Ñледа</translation>
+<translation id="1126551341858583091">Đ’ĐµĐ»Đ¸Ñ‡Đ¸Đ½Đ° у Đ»Đ¾ĐºĐ°Đ»Đ½Đ¾Đ¼ Đ¼ĐµĐ¼Đ¾Ñ€Đ¸Ñ˜ÑĐºĐ¾Đ¼ Đ¿Ñ€Đ¾ÑÑ‚Đ¾Ñ€Ñƒ Ñ˜Đµ <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">ĐĐµÑˆ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ° Ñ˜Đµ у Ñ€ĐµĐ´Ñƒ</translation>
<translation id="113188000913989374"><ph name="SITE" /> ĐºĐ°Đ¶Đµ:</translation>
<translation id="1132774398110320017">ĐŸĐ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ° Chrome Đ°ÑƒÑ‚Đ¾Đ¼Đ°Ñ‚ÑĐºĐ¾Đ³ Đ¿Đ¾Đ¿ÑƒÑĐ°Đ²Đ°ÑĐ°...</translation>
-<translation id="1150979032973867961">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Đ¾Đ¿ĐµÑ€Đ°Ñ‚Đ¸Đ²Đ½Đ¸ ÑиÑÑ‚ĐµĐ¼ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Đ½ĐµĐ¼Đ° Đ¿Đ¾Đ²ĐµÑ€ĐµÑĐ° у ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.</translation>
<translation id="1152921474424827756">ĐŸÑ€Đ¸ÑÑ‚ÑƒĐ¿Đ¸Ñ‚Đµ <ph name="BEGIN_LINK" />ĐºĐµÑˆĐ¸Ñ€Đ°Đ½Đ¾Ñ˜ ĐºĐ¾Đ¿Đ¸Ñ˜Đ¸<ph name="END_LINK" /> ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ <ph name="URL" /></translation>
<translation id="1158211211994409885">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Ñ˜Đµ Đ½ĐµĐ¾Ñ‡ĐµĐºĐ¸Đ²Đ°Đ½Đ¾ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.</translation>
<translation id="1161325031994447685">Đ¿Đ¾Đ½Đ¾Đ²Đ¾ Đ´Đ° Ñе Đ¿Đ¾Đ²ĐµĐ¶ĐµÑ‚Đµ ÑĐ° Wi-Fi Đ¼Ñ€ĐµĐ¶Đ¾Đ¼</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Đ£ĐºĐ»Đ¾Đ½Đ¸</translation>
<translation id="1201402288615127009">Đ”Đ°Ñ™Đµ</translation>
<translation id="1201895884277373915">Đ’Đ¸ÑˆĐµ ÑĐ° Đ¾Đ²Đ¾Đ³ ÑĐ°Ñ˜Ñ‚Đ°</translation>
-<translation id="121201262018556460">ĐŸĐ¾ĐºÑƒÑˆĐ°Đ»Đ¸ ÑÑ‚Đµ Đ´Đ° ĐºĐ¾Đ½Ñ‚Đ°ĐºÑ‚Đ¸Ñ€Đ°Ñ‚Đµ <ph name="DOMAIN" />, али Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Đ¾ÑĐ»Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ĐºĐ¾Ñ˜Đ¸ ÑĐ°Đ´Ñ€Đ¶Đ¸ Ñлаб ĐºÑ™ÑƒÑ‡. ĐœĐ¾Đ³ÑƒÑ›Đµ Ñ˜Đµ Đ´Đ° Ñ˜Đµ Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ Đ¾Ñ‚ĐºÑ€Đ¸Đ¾ Đ¿Ñ€Đ¸Đ²Đ°Ñ‚Đ½Đ¸ ĐºÑ™ÑƒÑ‡ и Đ´Đ° ÑĐµÑ€Đ²ĐµÑ€ Đ¼Đ¾Đ¶Đ´Đ° Đ½Đ¸Ñ˜Đµ Đ¾Đ½Đ°Ñ˜ ĐºĐ¾Ñ˜Đ¸ Đ¼Đ¸ÑĐ»Đ¸Ñ‚Đµ Đ´Đ° Ñ˜ĐµÑÑ‚Đµ (Đ¼Đ¾Đ¶Đ´Đ° ĐºĐ¾Đ¼ÑƒĐ½Đ¸Ñ†Đ¸Ñ€Đ°Ñ‚Đµ ÑĐ° Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ĐµĐ¼).</translation>
+<translation id="1206967143813997005">ĐеиÑĐ¿Ñ€Đ°Đ²Đ°Đ½ Đ¿Đ¾Ñ‚Đ¿Đ¸Ñ Đ¸Đ½Đ¸Ñ†Đ¸Ñ˜Đ°Đ»Đ¸Đ¼Đ°</translation>
+<translation id="1209206284964581585">Đ¡Đ°ĐºÑ€Đ¸Ñ˜ Đ·Đ° ÑĐ°Đ´Đ°</translation>
<translation id="1219129156119358924">Đ‘ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑÑ‚ ÑиÑÑ‚ĐµĐ¼Đ°</translation>
<translation id="1227224963052638717">ĐĐµĐ¿Đ¾Đ·Đ½Đ°Ñ‚Đµ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ.</translation>
<translation id="1227633850867390598">Đ¡Đ°ĐºÑ€Đ¸Ñ˜ Đ²Ñ€ĐµĐ´Đ½Đ¾ÑÑ‚</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Да</translation>
<translation id="1430915738399379752">Đ¨Ñ‚Đ°Đ¼Đ¿Đ°Ñ˜</translation>
<translation id="1442912890475371290">Đ‘Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½ Ñ˜Đµ Đ¿Đ¾ĐºÑƒÑˆĐ°Ñ˜ <ph name="BEGIN_LINK" />Đ¿Đ¾ÑĐµÑ›Đ¸Đ²Đ°ÑĐ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ Đ½Đ° Đ´Đ¾Đ¼ĐµĐ½Ñƒ <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" /> Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚ ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸ Đ¿Ñ€Đ¾Đ²ĐµÑ€Ñƒ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°. Đ“Ñ€ĐµÑˆĐºĐµ и Đ½Đ°Đ¿Đ°Đ´Đ¸ Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸ Ñу Đ¾Đ±Đ¸Ñ‡Đ½Đ¾ Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¸, Đ¿Đ° Ñ›Đµ Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑĐ°Ñ‚Đ¸ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">ĐŸÑ€Đ¸ĐºĐ°Đ¶Đ¸Ñ‚Đµ ÑĐ°Ñ‡ÑƒĐ²Đ°Đ½ÑƒÂ ĐºĐ¾Đ¿Đ¸Ñ˜Ñƒ Đ¾Đ²Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ (тј. ĐºĐ¾Đ¿Đ¸Ñ˜Ñƒ Đ·Đ° ĐºĐ¾Ñ˜Ñƒ Ñе Đ·Đ½Đ° Đ´Đ° Ñ˜Đµ Đ·Đ°ÑÑ‚Đ°Ñ€ĐµĐ»Đ°).</translation>
<translation id="1519264250979466059">Đ”Đ°Ñ‚ÑƒĐ¼ Đ²ĐµÑ€Đ·Đ¸Ñ˜Đµ</translation>
<translation id="1549470594296187301">JavaScript Đ¼Đ¾Ñ€Đ° Đ´Đ° Đ±ÑƒĐ´Đµ Đ¾Đ¼Đ¾Đ³ÑƒÑ›ĐµĐ½ Đ´Đ° биÑÑ‚Đµ ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸Đ»Đ¸ Đ¾Đ²Ñƒ Ñ„ÑƒĐ½ĐºÑ†Đ¸Ñ˜Ñƒ.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">ĐĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° Đ¼Ñ€ĐµĐ¶Đµ Ñ˜Đµ Đ½ĐµĐ²Đ°Đ¶ĐµÑ›Đ° и Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе ÑƒĐ²ĐµĐ·Đµ.</translation>
<translation id="1644574205037202324">Đ˜ÑÑ‚Đ¾Ñ€Đ¸Ñ˜Đ°</translation>
<translation id="1645368109819982629">ĐĐµĐ¿Đ¾Đ´Ñ€Đ¶Đ°Đ½Đ¸ Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»</translation>
-<translation id="1655462015569774233">{1,plural, =1{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾ Ñ˜ÑƒÑ‡Đµ. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ¡Đ°Ñ‚ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Ñ˜Đµ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ½Đ° <ph name="CURRENT_DATE" />. Да ли Ñ˜Đµ Ñ‚Đ¾ Ñ‚Đ°Ñ‡Đ½Đ¾? ĐĐºĐ¾ Đ½Đ¸Ñ˜Đµ, Ñ‚Ñ€ĐµĐ±Đ°Đ»Đ¾ би Đ´Đ° иÑĐ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ ÑĐ°Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ° и Đ´Đ° Đ·Đ°Ñ‚Đ¸Đ¼ Đ¾ÑĐ²ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.}one{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾ Đ¿Ñ€Đµ # Đ´Đ°Đ½Đ°. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ¡Đ°Ñ‚ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Ñ˜Đµ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ½Đ° <ph name="CURRENT_DATE" />. Да ли Ñ˜Đµ Ñ‚Đ¾ Ñ‚Đ°Ñ‡Đ½Đ¾? ĐĐºĐ¾ Đ½Đ¸Ñ˜Đµ, Ñ‚Ñ€ĐµĐ±Đ°Đ»Đ¾ би Đ´Đ° иÑĐ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ ÑĐ°Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ° и Đ´Đ° Đ·Đ°Ñ‚Đ¸Đ¼ Đ¾ÑĐ²ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.}few{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾ Đ¿Ñ€Đµ # Đ´Đ°Đ½Đ°. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ¡Đ°Ñ‚ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Ñ˜Đµ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ½Đ° <ph name="CURRENT_DATE" />. Да ли Ñ˜Đµ Ñ‚Đ¾ Ñ‚Đ°Ñ‡Đ½Đ¾? ĐĐºĐ¾ Đ½Đ¸Ñ˜Đµ, Ñ‚Ñ€ĐµĐ±Đ°Đ»Đ¾ би Đ´Đ° иÑĐ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ ÑĐ°Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ° и Đ´Đ° Đ·Đ°Ñ‚Đ¸Đ¼ Đ¾ÑĐ²ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.}other{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾ Đ¿Ñ€Đµ # Đ´Đ°Đ½Đ°. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ¡Đ°Ñ‚ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Ñ˜Đµ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ½Đ° <ph name="CURRENT_DATE" />. Да ли Ñ˜Đµ Ñ‚Đ¾ Ñ‚Đ°Ñ‡Đ½Đ¾? ĐĐºĐ¾ Đ½Đ¸Ñ˜Đµ, Ñ‚Ñ€ĐµĐ±Đ°Đ»Đ¾ би Đ´Đ° иÑĐ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ ÑĐ°Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ° и Đ´Đ° Đ·Đ°Ñ‚Đ¸Đ¼ Đ¾ÑĐ²ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> Đ¾Đ±Đ¸Ñ‡Đ½Đ¾ ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸ ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Ñе Đ´Đ° би Đ·Đ°ÑˆÑ‚Đ¸Ñ‚Đ¸Đ¾ Đ¸Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ˜Đµ. ĐĐ°Đ´Đ° Ñ˜Đµ Google Chrome Đ¾Đ²Đ¾Đ³ Đ¿ÑƒÑ‚Đ° Đ¿Đ¾ĐºÑƒÑˆĐ°Đ¾ Đ´Đ° Ñе Đ¿Đ¾Đ²ĐµĐ¶Đµ ÑĐ° <ph name="SITE" />, Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚ Ñ˜Đµ Đ²Ñ€Đ°Ñ‚Đ¸Đ¾ Đ½ĐµĐ¾Đ±Đ¸Ñ‡Đ½Đµ и Đ½ĐµÑ‚Đ°Ñ‡Đ½Đµ Đ°ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ¸Đ²Đµ. Đ˜Đ»Đ¸ Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ Đ¿Đ¾ĐºÑƒÑˆĐ°Đ²Đ° Đ´Đ° Ñе Đ¿Ñ€ĐµĐ´ÑÑ‚Đ°Đ²Đ¸ ĐºĐ°Đ¾ <ph name="SITE" /> или Ñ˜Đµ ĐµĐºÑ€Đ°Đ½ Đ·Đ° Wi-Fi Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Ñ™Đ¸Đ²Đ°Ñе Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ˜Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ˜Đµ Ñу и Đ´Đ°Ñ™Đµ Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đµ Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ Ñ˜Đµ Google Chrome Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ Đ¿Ñ€Đµ Đ½ĐµĐ³Đ¾ ÑˆÑ‚Đ¾ Ñу Ñ€Đ°Đ·Đ¼ĐµÑĐµĐ½Đ¸ Đ±Đ¸Đ»Đ¾ ĐºĐ°ĐºĐ²Đ¸ Đ¿Đ¾Đ´Đ°Ñ†Đ¸.</translation>
<translation id="168841957122794586">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° ÑĐ°Đ´Ñ€Đ¶Đ¸ Ñлаб ĐºÑ€Đ¸Đ¿Ñ‚Đ¾Đ³Ñ€Đ°Ñ„ÑĐºĐ¸ ĐºÑ™ÑƒÑ‡.</translation>
<translation id="1701955595840307032">Đ”Đ¾Đ±Đ¸Ñ˜Đ°Ñ˜Ñ‚Đµ Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ¶ĐµĐ½Đ¸ ÑĐ°Đ´Ñ€Đ¶Đ°Ñ˜</translation>
-<translation id="1706954506755087368">{1,plural, =1{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Đ´Đ°Ñ‚ÑƒĐ¼ ÑĐµĐ³Đ¾Đ²Đ¾Đ³ Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¾Đ³ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Ñ˜Đµ Đ½Đ°Đ²Đ¾Đ´Đ½Đ¾ ÑÑƒÑ‚Ñ€Đ°ÑˆÑи. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.}one{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ Đ½Đ°Đ²Đ¾Đ´Đ½Đ¾ Đ´Đ°Ñ‚Đ¸Ñ€Đ°Đ½ у Đ±ÑƒĐ´ÑƒÑ›Đ½Đ¾ÑÑ‚Đ¸ (Đ·Đ° # Đ´Đ°Đ½). Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.}few{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ Đ½Đ°Đ²Đ¾Đ´Đ½Đ¾ Đ´Đ°Ñ‚Đ¸Ñ€Đ°Đ½ у Đ±ÑƒĐ´ÑƒÑ›Đ½Đ¾ÑÑ‚Đ¸ (Đ·Đ° # Đ´Đ°Đ½Đ°). Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.}other{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ Đ½Đ°Đ²Đ¾Đ´Đ½Đ¾ Đ´Đ°Ñ‚Đ¸Ñ€Đ°Đ½ у Đ±ÑƒĐ´ÑƒÑ›Đ½Đ¾ÑÑ‚Đ¸ (Đ·Đ° # Đ´Đ°Đ½Đ°). Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.}}</translation>
<translation id="1710259589646384581">ĐĐ¡</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ´Đ° ĐºĐ¾Đ½Ñ‚Đ°ĐºÑ‚Đ¸Ñ€Đ°Ñ‚Đµ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Đ° ÑиÑÑ‚ĐµĐ¼Đ°.</translation>
<translation id="17513872634828108">ĐÑ‚Đ²Đ¾Ñ€ĐµĐ½Đµ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ</translation>
<translation id="1753706481035618306">Đ‘Ñ€Đ¾Ñ˜ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ</translation>
-<translation id="1761412452051366565">Да биÑÑ‚Đµ Đ´Đ¾Đ±Đ¸Ñ˜Đ°Đ»Đ¸ Đ¿ĐµÑ€ÑĐ¾Đ½Đ°Đ»Đ¸Đ·Đ¾Đ²Đ°Đ½Đ¸ ÑĐ°Đ´Ñ€Đ¶Đ°Ñ˜ ĐºĐ¾Ñ˜Đ¸ Đ¿Ñ€ĐµĐ´Đ»Đ°Đ¶Đµ Google, ÑƒĐºÑ™ÑƒÑ‡Đ¸Ñ‚Đµ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ˜Ñƒ.</translation>
-<translation id="1763864636252898013">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Đ¾Đ¿ĐµÑ€Đ°Ñ‚Đ¸Đ²Đ½Đ¸ ÑиÑÑ‚ĐµĐ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ° Đ½ĐµĐ¼Đ° Đ¿Đ¾Đ²ĐµÑ€ĐµÑĐ° у ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ´Đ° Đ¿Đ¾ĐºÑ€ĐµĐ½ĐµÑ‚Đµ Windows Đ´Đ¸Ñ˜Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ Đ¼Ñ€ĐµĐ¶Đµ<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">ĐĐ¶ÑƒÑ€Đ¸Ñ€Đ°Ñ˜ Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿Đ½Ñƒ Ñ„Ñ€Đ°Đ·Ñƒ Đ·Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ˜Ñƒ</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">ĐĐµĐ´Đ°Đ²Đ½Đ¾ Đ¿Đ¾ÑĐµÑ›ĐµĐ½Đ¸ Đ¾Đ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡Đ¸ Ñ›Đµ Ñе Đ¿Đ¾Ñ˜Đ°Đ²Đ¸Ñ‚Đ¸ Đ¾Đ²Đ´Đµ.</translation>
<translation id="1821930232296380041">ĐĐµĐ²Đ°Đ¶ĐµÑ›Đ¸ Đ·Đ°Ñ…Ñ‚ĐµĐ² или Đ¿Đ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ¸ Đ·Đ°Ñ…Ñ‚ĐµĐ²Đ°</translation>
<translation id="1838667051080421715">ĐŸÑ€ĐµĐ³Đ»ĐµĐ´Đ°Ñ‚Đµ Đ¸Đ·Đ²Đ¾Ñ€ Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ.</translation>
<translation id="1871208020102129563">ĐŸÑ€Đ¾ĐºÑи Ñ˜Đµ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ´Đ° ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸ Ñ„Đ¸ĐºÑĐ½Đµ Đ¿Ñ€Đ¾ĐºÑи ÑĐµÑ€Đ²ĐµÑ€Đµ, Đ° Đ½Đµ URL Đ°Đ´Ñ€ĐµÑу .pac ÑĐºÑ€Đ¸Đ¿Ñ‚Đµ.</translation>
<translation id="1883255238294161206">Đ¡ĐºÑƒĐ¿Đ¸ лиÑту</translation>
<translation id="1898423065542865115">Đ¤Đ¸Đ»Ñ‚Ñ€Đ¸Ñ€Đ°Ñе</translation>
-<translation id="1911837502049945214">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Đ½Đ¸Ñ˜Đµ Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‚Đ¸Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ·Đ° Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Ñ™Đ¸Đ²Đ°Ñе или Ñ˜Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ·Đ° Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Ñ™Đ¸Đ²Đ°Ñе Đ¼Đ¾Đ¶Đ´Đ° иÑÑ‚ĐµĐºĐ°Đ¾.</translation>
<translation id="194030505837763158">Đ˜Đ´Đ¸Ñ‚Đµ Đ½Đ° <ph name="LINK" /></translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> – Đ¾Đ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡Đ¸</translation>
<translation id="1973335181906896915">Đ“Ñ€ĐµÑˆĐºĐ° Đ¿Ñ€Đ¸ ÑĐµÑ€Đ¸Ñ˜Đ°Đ»Đ¸Đ·Đ°Ñ†Đ¸Ñ˜Đ¸</translation>
<translation id="1974060860693918893">ĐĐ°Đ¿Ñ€ĐµĐ´Đ½Đµ Đ¾Đ¿Ñ†Đ¸Ñ˜Đµ</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{ и Ñ˜Đ¾Ñˆ 1}one{и Ñ˜Đ¾Ñˆ #}few{и Ñ˜Đ¾Ñˆ #}other{и Ñ˜Đ¾Ñˆ #}}</translation>
<translation id="2025186561304664664">ĐŸÑ€Đ¾ĐºÑи Ñ˜Đµ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ´Đ° Đ±ÑƒĐ´Đµ Đ°ÑƒÑ‚Đ¾Đ¼Đ°Ñ‚ÑĐºĐ¸ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸ÑĐ°Đ½.</translation>
<translation id="2030481566774242610">Да ли ÑÑ‚Đµ Đ¼Đ¸Ñлили <ph name="LINK" />?</translation>
<translation id="2031925387125903299">ĐĐ²Ñƒ Đ¿Đ¾Ñ€ÑƒĐºÑƒ Đ²Đ¸Đ´Đ¸Ñ‚Đµ Ñ˜ĐµÑ€ Đ²Đ°ÑˆĐ¸ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™Đ¸ Ñ‚Ñ€ĐµĐ±Đ° Đ´Đ° Đ¾Đ´Đ¾Đ±Ñ€Đµ Đ½Đ¾Đ²Đµ ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đµ Đ¿Ñ€Đ¸ Đ¿Ñ€Đ²Đ¾Ñ˜ Đ¿Đ¾ÑĐµÑ‚Đ¸.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Đ´Đ° Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ Đ¿Ñ€Đ¾ĐºÑи и Đ·Đ°ÑˆÑ‚Đ¸Ñ‚Đ½Đ¸ зид<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ĐŸĐ¾ÑˆÑ‚Đ°Đ½ÑĐºĐ¸ Đ±Ñ€Đ¾Ñ˜</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ³}one{# Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ³}few{# Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ³Đ°}other{# Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ³Đ°}}</translation>
<translation id="2065985942032347596">ĐŸĐ¾Ñ‚Ñ€ĐµĐ±Đ½Đ° Ñ˜Đµ Đ¿Đ¾Ñ‚Đ²Ñ€Đ´Đ° Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ‚ĐµÑ‚Đ°</translation>
<translation id="2079545284768500474">ĐĐ¿Đ¾Đ·Đ¾Đ²Đ¸</translation>
<translation id="20817612488360358">ĐŸĐ¾Đ´ĐµÑˆĐµĐ½Đ¾ Ñ˜Đµ Đ´Đ° Ñе ĐºĐ¾Ñ€Đ¸ÑÑ‚Đµ ÑиÑÑ‚ĐµĐ¼ÑĐºĐ° Đ¿Đ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ° Đ¿Ñ€Đ¾ĐºÑĐ¸Ñ˜Đ°, али Ñ˜Đµ Đ½Đ°Đ²ĐµĐ´ĐµĐ½Đ° ĐµĐºÑĐ¿Đ»Đ¸Ñ†Đ¸Ñ‚Đ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° Đ¿Ñ€Đ¾ĐºÑĐ¸Ñ˜Đ°.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Đ˜Đ·Đ¼ĐµĐ½Đ¸Ñ‚Đµ Đ¾Đ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡</translation>
<translation id="2166049586286450108">ĐŸĐ¾Ñ‚Đ¿ÑƒĐ½Đ¸ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€ÑĐºĐ¸ Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿</translation>
<translation id="2166378884831602661">ĐĐ²Đ°Ñ˜ ÑĐ°Ñ˜Ñ‚ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¿Ñ€ÑƒĐ¶Đ¸ Đ±ĐµĐ·Đ±ĐµĐ´Đ½Ñƒ Đ²ĐµĐ·Ñƒ</translation>
-<translation id="2171101176734966184">ĐŸĐ¾ĐºÑƒÑˆĐ°Đ»Đ¸ ÑÑ‚Đµ Đ´Đ° ĐºĐ¾Đ½Ñ‚Đ°ĐºÑ‚Đ¸Ñ€Đ°Ñ‚Đµ <ph name="DOMAIN" />, али ÑĐµÑ€Đ²ĐµÑ€ Ñ˜Đµ Đ¿Đ¾ÑĐ»Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¿Đ¾Ñ‚Đ¿Đ¸ÑĐ°Đ½ ÑĐ»Đ°Đ±Đ¸Đ¼ Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚Đ¼Đ¾Đ¼. Đ¢Đ¾ Đ·Đ½Đ°Ñ‡Đ¸ Đ´Đ° би Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ Đ°ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ¸Đ²Đ¸ ĐºĐ¾Ñ˜Đµ Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Đ¾ÑĐ»Đ°Đ¾ Đ¼Đ¾Đ³Đ»Đ¸ Đ´Đ° Đ±ÑƒĐ´Ñƒ ĐºÑ€Đ¸Đ²Đ¾Ñ‚Đ²Đ¾Ñ€ĐµĐ½Đ¸ Ñ‚Đ°ĐºĐ¾ Đ´Đ° ÑĐµÑ€Đ²ĐµÑ€ Đ¼Đ¾Đ¶Đ´Đ° Đ½Đ¸Ñ˜Đµ Đ¾Đ½Đ°Ñ˜ ĐºĐ¾Ñ˜Đ¸ Đ¼Đ¸ÑĐ»Đ¸Ñ‚Đµ Đ´Đ° Ñ˜ĐµÑÑ‚Đµ (Đ¼Đ¾Đ¶Đ´Đ° ĐºĐ¾Đ¼ÑƒĐ½Đ¸Ñ†Đ¸Ñ€Đ°Ñ‚Đµ ÑĐ° Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ĐµĐ¼).</translation>
<translation id="2181821976797666341">Đ¡Đ¼ĐµÑ€Đ½Đ¸Ñ†Đµ</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 Đ°Đ´Ñ€ĐµÑĐ°}one{# Đ°Đ´Ñ€ĐµÑĐ°}few{# Đ°Đ´Ñ€ĐµÑе}other{# Đ°Đ´Ñ€ĐµÑĐ°}}</translation>
<translation id="2212735316055980242">Đ¡Đ¼ĐµÑ€Đ½Đ¸Ñ†Đµ Đ½Đ¸Ñу Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ½Đµ</translation>
<translation id="2213606439339815911">ĐŸÑ€ĐµÑƒĐ·Đ¸Đ¼Đ°Ñе ÑƒĐ½Đ¾ÑĐ°...</translation>
-<translation id="2214283295778284209">Đ¡Đ°Ñ˜Ñ‚ <ph name="SITE" /> Đ½Đ¸Ñ˜Đµ Đ´Đ¾ÑÑ‚ÑƒĐ¿Đ°Đ½</translation>
<translation id="2230458221926704099">ĐŸĐ¾Đ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ Đ²ĐµĐ·Ñƒ Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ <ph name="BEGIN_LINK" />Đ°Đ¿Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ˜Đµ Đ·Đ° Đ´Đ¸Ñ˜Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">ĐŸĐ¾ÑˆĐ°Ñ™Đ¸ Đ¾Đ´Đ¼Đ°Ñ…</translation>
<translation id="225207911366869382">ĐĐ²Đ° Đ²Ñ€ĐµĐ´Đ½Đ¾ÑÑ‚ Ñ˜Đµ Đ·Đ°ÑÑ‚Đ°Ñ€ĐµĐ»Đ° Đ·Đ° Đ¾Đ²Đµ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ.</translation>
<translation id="2262243747453050782">HTTP Đ³Ñ€ĐµÑˆĐºĐ°</translation>
<translation id="2282872951544483773">ĐĐµĐ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Đ¸ ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ¸</translation>
<translation id="2292556288342944218">ĐŸÑ€Đ¸ÑÑ‚ÑƒĐ¿ Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚Ñƒ Ñ˜Đµ Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½</translation>
<translation id="229702904922032456">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¾ÑĐ½Đ¾Đ²Đ½Đ¾Đ³ или ÑÑ€ĐµĐ´ÑĐµĐ³ Đ½Đ¸Đ²Đ¾Đ° Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾.</translation>
<translation id="230155334948463882">ĐĐ¾Đ²Đ° ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đ°?</translation>
+<translation id="2305919008529760154">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Đ¼Đ¾Đ³ÑƒÑ›Đµ Ñ˜Đµ Đ´Đ° Ñ˜Đµ ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ»Đ°Đ¶Đ½Đ¾ Đ¸Đ·Đ´Đ°Ñ‚. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> Đ·Đ°Ñ…Ñ‚ĐµĐ²Đ° ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸Ñ‡ĐºĐ¾ Đ¸Đ¼Đµ и Đ»Đ¾Đ·Đ¸Đ½ĐºÑƒ.</translation>
+<translation id="2318774815570432836">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" /> Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚ ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸ HSTS. Đ“Ñ€ĐµÑˆĐºĐµ и Đ½Đ°Đ¿Đ°Đ´Đ¸ Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸ Ñу Đ¾Đ±Đ¸Ñ‡Đ½Đ¾ Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¸, Đ¿Đ° Ñ›Đµ Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑĐ°Ñ‚Đ¸ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">ĐĐµĐ²Đ°Đ¶ĐµÑ›Đ¸ Đ¾Đ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡ Ñ˜Đµ Đ¸Đ³Đ½Đ¾Ñ€Đ¸ÑĐ°Đ½ у Đ¸Đ½Đ´ĐµĐºÑу <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">ĐÑÑ‚Đ°Đ»Đ¸ Đ¾Đ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡Đ¸</translation>
<translation id="2359808026110333948">ĐĐ°ÑÑ‚Đ°Đ²Đ¸</translation>
<translation id="2365563543831475020">Đ˜Đ·Đ²ĐµÑˆÑ‚Đ°Ñ˜ Đ¾ Đ¾Ñ‚ĐºĐ°Đ·Đ¸Đ²Đ°Ñу ÑĐ½Đ¸Đ¼Ñ™ĐµĐ½ у <ph name="CRASH_TIME" /> Đ½Đ¸Ñ˜Đµ Đ¾Ñ‚Đ¿Ñ€ĐµĐ¼Ñ™ĐµĐ½</translation>
<translation id="2367567093518048410">ĐĐ¸Đ²Đ¾</translation>
+<translation id="2371153335857947666">{1,plural, =1{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾ Ñ˜ÑƒÑ‡Đµ. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ¡Đ°Ñ‚ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Ñ˜Đµ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ½Đ° <ph name="CURRENT_DATE" />. Да ли Ñ˜Đµ Ñ‚Đ¾ Ñ‚Đ°Ñ‡Đ½Đ¾? ĐĐºĐ¾ Đ½Đ¸Ñ˜Đµ, Ñ‚Ñ€ĐµĐ±Đ°Đ»Đ¾ би Đ´Đ° иÑĐ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ ÑĐ°Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ° и Đ´Đ° Đ·Đ°Ñ‚Đ¸Đ¼ Đ¾ÑĐ²ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}one{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾ Đ¿Ñ€Đµ # Đ´Đ°Đ½Đ°. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ¡Đ°Ñ‚ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Ñ˜Đµ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ½Đ° <ph name="CURRENT_DATE" />. Да ли Ñ˜Đµ Ñ‚Đ¾ Ñ‚Đ°Ñ‡Đ½Đ¾? ĐĐºĐ¾ Đ½Đ¸Ñ˜Đµ, Ñ‚Ñ€ĐµĐ±Đ°Đ»Đ¾ би Đ´Đ° иÑĐ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ ÑĐ°Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ° и Đ´Đ° Đ·Đ°Ñ‚Đ¸Đ¼ Đ¾ÑĐ²ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}few{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾ Đ¿Ñ€Đµ # Đ´Đ°Đ½Đ°. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ¡Đ°Ñ‚ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Ñ˜Đµ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ½Đ° <ph name="CURRENT_DATE" />. Да ли Ñ˜Đµ Ñ‚Đ¾ Ñ‚Đ°Ñ‡Đ½Đ¾? ĐĐºĐ¾ Đ½Đ¸Ñ˜Đµ, Ñ‚Ñ€ĐµĐ±Đ°Đ»Đ¾ би Đ´Đ° иÑĐ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ ÑĐ°Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ° и Đ´Đ° Đ·Đ°Ñ‚Đ¸Đ¼ Đ¾ÑĐ²ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}other{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾ Đ¿Ñ€Đµ # Đ´Đ°Đ½Đ°. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ¡Đ°Ñ‚ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Ñ˜Đµ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ½Đ° <ph name="CURRENT_DATE" />. Да ли Ñ˜Đµ Ñ‚Đ¾ Ñ‚Đ°Ñ‡Đ½Đ¾? ĐĐºĐ¾ Đ½Đ¸Ñ˜Đµ, Ñ‚Ñ€ĐµĐ±Đ°Đ»Đ¾ би Đ´Đ° иÑĐ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ ÑĐ°Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ° и Đ´Đ° Đ·Đ°Ñ‚Đ¸Đ¼ Đ¾ÑĐ²ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">ĐĐµĐ¼Đ° Đ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Đ¸Ñ… Đ°Đ»Ñ‚ĐµÑ€Đ½Đ°Ñ‚Đ¸Đ²Đ° ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸Ñ‡ĐºĐ¾Đ³ Đ¸Đ½Ñ‚ĐµÑ€Ñ„ĐµÑ˜ÑĐ°</translation>
<translation id="2384307209577226199">ĐŸĐ¾Đ´Ñ€Đ°Đ·ÑƒĐ¼ĐµĐ²Đ°Đ½Đµ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ Đ·Đ° Đ¿Ñ€ĐµĐ´ÑƒĐ·ĐµÑ›Đµ</translation>
-<translation id="238526402387145295">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" /> Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚ <ph name="BEGIN_LINK" />ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸ HSTS<ph name="END_LINK" />. Đ“Ñ€ĐµÑˆĐºĐµ и Đ½Đ°Đ¿Đ°Đ´Đ¸ Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸ Ñу Đ¾Đ±Đ¸Ñ‡Đ½Đ¾ Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¸, Đ¿Đ° Ñ›Đµ Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑĐ°Ñ‚Đ¸ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ.</translation>
<translation id="2386255080630008482">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Ñ˜Đµ Đ¾Đ¿Đ¾Đ·Đ²Đ°Đ½.</translation>
<translation id="2392959068659972793">ĐŸÑ€Đ¸ĐºĐ°Đ¶Đ¸ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ без Đ¿Đ¾Đ´ĐµÑˆĐµĐ½Đ¸Ñ… Đ²Ñ€ĐµĐ´Đ½Đ¾ÑÑ‚Đ¸</translation>
<translation id="2396249848217231973">&amp;ĐĐ¿Đ¾Đ·Đ¾Đ²Đ¸ Đ±Ñ€Đ¸ÑĐ°Ñе</translation>
-<translation id="2413528052993050574">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ›Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ±Đ¸Ñ‚Đ¸ Đ¾Đ¿Đ¾Đ·Đ²Đ°Đ½. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.</translation>
<translation id="2455981314101692989">ĐĐ²Đ° Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Ñ˜Đµ Đ¾Đ½ĐµĐ¼Đ¾Đ³ÑƒÑ›Đ¸Đ»Đ° Đ°ÑƒÑ‚Đ¾Đ¼Đ°Ñ‚ÑĐºĐ¾ Đ¿Đ¾Đ¿ÑƒÑĐ°Đ²Đ°Ñе Đ·Đ° Đ¾Đ²Đ°Ñ˜ Đ¾Đ±Ñ€Đ°Đ·Đ°Ñ†.</translation>
+<translation id="2463739503403862330">ĐŸĐ¾Đ¿ÑƒĐ½Đ¸</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Đ´Đ° Đ¿Đ¾ĐºÑ€ĐµĐ½ĐµÑ‚Đµ Đ´Đ¸Ñ˜Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ Đ¼Ñ€ĐµĐ¶Đµ<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">ĐĐµĐ²Đ°Đ¶ĐµÑ›Đ° URL Đ°Đ´Ñ€ĐµÑĐ° Đ¿Ñ€ĐµÑ‚Ñ€Đ°Đ³Đµ.</translation>
<translation id="2491120439723279231">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° ÑĐ°Đ´Ñ€Đ¶Đ¸ Đ³Ñ€ĐµÑˆĐºĐµ.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">ĐŸĐ¾ÑˆĐ°Ñ™Đ¸</translation>
<translation id="2674170444375937751">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли ÑÑ‚Đ²Đ°Ñ€Đ½Đ¾ Đ´Đ° Đ¸Đ·Đ±Ñ€Đ¸ÑˆĐµÑ‚Đµ Đ¾Đ²Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ из иÑÑ‚Đ¾Ñ€Đ¸Ñ˜Đµ?</translation>
<translation id="2677748264148917807">ĐĐ°Đ¿ÑƒÑÑ‚Đ¸</translation>
+<translation id="269990154133806163">Đ¡ĐµÑ€Đ²ĐµÑ€ Ñ˜Đµ Đ¿Đ¾ÑĐ»Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ĐºĐ¾Ñ˜Đ¸ Đ½Đ¸Ñ˜Đµ Ñ˜Đ°Đ²Đ½Đ¾ Đ¾Ñ‚ĐºÑ€Đ¸Đ²ĐµĐ½ Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ° Đ·Đ° Ñ‚Ñ€Đ°Đ½ÑĐ¿Đ°Ñ€ĐµĐ½Ñ‚Đ½Đ¾ÑÑ‚ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°. Đ¢Đ¾ Ñ˜Đµ Đ¾Đ±Đ°Đ²ĐµĐ·Đ½Đ¾ Đ·Đ° Đ½ĐµĐºĐµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đµ Đ´Đ° биÑĐ¼Đ¾ Ñе ÑƒĐ²ĐµÑ€Đ¸Đ»Đ¸ Đ´Đ° Ñу Đ¿Đ¾ÑƒĐ·Đ´Đ°Đ½Đ¸ и Đ´Đ° ÑˆÑ‚Đ¸Ñ‚Đµ Đ¾Đ´ Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡Đ°. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Đ’Ñ€ĐµĐ´Đ½Đ¾ÑÑ‚ Ñе Đ½Đµ Đ¿Đ¾Đ´ÑƒĐ´Đ°Ñ€Đ° ÑĐ° Ñ„Đ¾Ñ€Đ¼Đ°Ñ‚Đ¾Đ¼.</translation>
-<translation id="2704951214193499422">Chromium Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ¾ Đ´Đ° Đ¿Đ¾Ñ‚Đ²Ñ€Đ´Đ¸ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ. ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ.</translation>
+<translation id="2704951214193499422">Chromium Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ¾ Đ´Đ° Đ¿Đ¾Ñ‚Đ²Ñ€Đ´Đ¸ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ. ĐŸÑ€Đ¾Đ±Đ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ.</translation>
<translation id="2705137772291741111">Đ¡Đ°Ñ‡ÑƒĐ²Đ°Đ½Đ° (ĐºĐµÑˆĐ¸Ñ€Đ°Đ½Đ°) ĐºĐ¾Đ¿Đ¸Ñ˜Đ° Đ¾Đ²Đ¾Đ³ ÑĐ°Ñ˜Ñ‚Đ° Đ½Đ¸Ñ˜Đµ Đ¼Đ¾Đ³Đ»Đ° Đ´Đ° Ñе Ñ‡Đ¸Ñ‚Đ°.</translation>
<translation id="2709516037105925701">ĐÑƒÑ‚Đ¾Đ¼Đ°Ñ‚ÑĐºĐ¾ Đ¿Đ¾Đ¿ÑƒÑĐ°Đ²Đ°Ñе</translation>
+<translation id="2712118517637785082">ĐŸĐ¾ĐºÑƒÑˆĐ°Đ»Đ¸ ÑÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="DOMAIN" />, али Ñ˜Đµ Đ¸Đ·Đ´Đ°Đ²Đ°Ñ‡ Đ¾Đ¿Đ¾Đ·Đ²Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Đ¾ÑĐ»Đ°Đ¾. Đ¢Đ¾ Đ·Đ½Đ°Ñ‡Đ¸ Đ´Đ° Đ½Đ¸ĐºĐ°ĐºĐ¾ Đ½Đµ Ñ‚Ñ€ĐµĐ±Đ° Đ´Đ° Đ¸Đ¼Đ°Ñ‚Đµ Đ¿Đ¾Đ²ĐµÑ€ĐµÑĐ° у Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đµ Đ°ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ¸Đ²Đµ ĐºĐ¾Ñ˜Đµ Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Đ¾ÑĐ»Đ°Đ¾. ĐœĐ¾Đ³ÑƒÑ›Đµ Ñ˜Đµ Đ´Đ° ĐºĐ¾Đ¼ÑƒĐ½Đ¸Ñ†Đ¸Ñ€Đ°Ñ‚Đµ ÑĐ° Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ĐµĐ¼. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Đ—Đ°Ñ‚Ñ€Đ°Đ¶Đ¸ Đ´Đ¾Đ·Đ²Đ¾Đ»Ñƒ</translation>
<translation id="2721148159707890343">Đ—Đ°Ñ…Ñ‚ĐµĐ² Ñ˜Đµ уÑĐ¿ĐµĐ¾</translation>
<translation id="2728127805433021124">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Ñ˜Đµ Đ¿Đ¾Ñ‚Đ¿Đ¸ÑĐ°Đ½ ÑĐ»Đ°Đ±Đ¸Đ¼ Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚Đ¼Đ¾Đ¼.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Đ¢Ñ€Đ°ĐºĐ° Đ·Đ° Đ°Đ´Ñ€ĐµÑу и Đ¿Ñ€ĐµÑ‚Ñ€Đ°Đ³Ñƒ</translation>
<translation id="2826760142808435982">Веза Ñ˜Đµ ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ° и ÑĐµĐ½Đ° Đ°ÑƒÑ‚ĐµĐ½Ñ‚Đ¸Ñ‡Đ½Đ¾ÑÑ‚ Ñ˜Đµ Đ¿Đ¾Ñ‚Đ²Ñ€Ñ’ĐµĐ½Đ° Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ <ph name="CIPHER" /> и ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸ <ph name="KX" /> ĐºĐ°Đ¾ Đ¼ĐµÑ…Đ°Đ½Đ¸Đ·Đ°Đ¼ Đ·Đ° Ñ€Đ°Đ·Đ¼ĐµĐ½Ñƒ ÑˆĐ¸Ñ„Đ°Ñ€Đ°.</translation>
<translation id="2835170189407361413">ĐĐ±Ñ€Đ¸ÑˆĐ¸ Đ¾Đ±Ñ€Đ°Đ·Đ°Ñ†</translation>
-<translation id="2837049386027881519">Đ£ÑĐ¿Đ¾ÑÑ‚Đ°Đ²Ñ™Đ°Ñе Đ²ĐµĐ·Đµ Ñ˜Đµ Đ¼Đ¾Ñ€Đ°Đ»Đ¾ Đ´Đ° Đ±ÑƒĐ´Đµ Đ¿Đ¾Đ½Đ¾Đ²Ñ™ĐµĐ½Đ¾ Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ ÑÑ‚Đ°Ñ€Đ¸Ñ˜Đµ Đ²ĐµÑ€Đ·Đ¸Ñ˜Đµ TLS или SSL Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»Đ°. ĐĐ²Đ¾ Đ¾Đ±Đ¸Ñ‡Đ½Đ¾ Đ·Đ½Đ°Ñ‡Đ¸ Đ´Đ° ÑĐµÑ€Đ²ĐµÑ€ ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸ Đ²ĐµĐ¾Đ¼Đ° ÑÑ‚Đ°Ñ€ ÑĐ¾Ñ„Ñ‚Đ²ĐµÑ€ и Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¸Đ¼Đ° Đ´Ñ€ÑƒĐ³Đ¸Ñ… Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸Ñ… Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ°.</translation>
<translation id="284702764277384724">Đ˜Đ·Đ³Đ»ĐµĐ´Đ° Đ´Đ° Ñ˜Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½Đ° Ñ…Đ¾Ñту <ph name="HOST_NAME" /> Ñ„Đ°Đ»ÑĐ¸Ñ„Đ¸ĐºĐ°Ñ‚.</translation>
<translation id="2889159643044928134">Đе ÑƒÑ‡Đ¸Ñ‚Đ°Đ²Đ°Ñ˜ Đ¿Đ¾Đ½Đ¾Đ²Đ¾</translation>
-<translation id="2896499918916051536">ĐĐ²Đ° Đ´Đ¾Đ´Đ°Ñ‚Đ½Đ° ĐºĐ¾Đ¼Đ¿Đ¾Đ½ĐµĐ½Ñ‚Đ° Đ½Đ¸Ñ˜Đµ Đ¿Đ¾Đ´Ñ€Đ¶Đ°Đ½Đ°.</translation>
+<translation id="2900469785430194048">Google Chrome-у Ñ˜Đµ Đ¿Đ¾Đ½ĐµÑÑ‚Đ°Đ»Đ¾ Đ¼ĐµĐ¼Đ¾Ñ€Đ¸Ñ˜Đµ Đ´Đ¾Đº Ñ˜Đµ Đ¿Đ¾ĐºÑƒÑˆĐ°Đ²Đ°Đ¾ Đ´Đ° Đ¿Ñ€Đ¸ĐºĐ°Đ¶Đµ Đ¾Đ²Ñƒ Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.</translation>
<translation id="2909946352844186028">ĐÑ‚ĐºÑ€Đ¸Đ²ĐµĐ½Đ° Ñ˜Đµ Đ¿Ñ€Đ¾Đ¼ĐµĐ½Đ° Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸.</translation>
-<translation id="2915500479781995473">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ¡Đ°Ñ‚ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Ñ˜Đµ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ½Đ° <ph name="CURRENT_TIME" />. Да ли Đ²Đ°Đ¼ Ñ‚Đ¾ Đ´ĐµĐ»ÑƒÑ˜Đµ Ñ‚Đ°Ñ‡Đ½Đ¾? ĐĐºĐ¾ Đ½Đµ Đ´ĐµĐ»ÑƒÑ˜Đµ, Ñ‚Ñ€ĐµĐ±Đ° Đ´Đ° иÑĐ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ ÑĐ°Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ° и Đ¾ÑĐ²ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.</translation>
<translation id="2922350208395188000">ĐĐ¸Ñ˜Đµ Đ¼Đ¾Đ³ÑƒÑ›Đµ Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ°.</translation>
-<translation id="2941952326391522266">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ ÑĐ° Đ´Đ¾Đ¼ĐµĐ½Đ° <ph name="DOMAIN2" />. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.</translation>
<translation id="2948083400971632585">ĐĐ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ¸ ĐŸĐ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ° Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¾Đ½ĐµĐ¼Đ¾Đ³ÑƒÑ›Đ¸Ñ‚Đµ ÑĐ²Đµ Đ¿Ñ€Đ¾ĐºÑĐ¸Ñ˜Đµ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ¸ÑĐ°Đ½Đµ Đ·Đ° Đ²ĐµĐ·Ñƒ.</translation>
<translation id="2955913368246107853">Đ—Đ°Ñ‚Đ²Đ¾Ñ€Đ¸Ñ‚Đµ Ñ‚Ñ€Đ°ĐºÑƒ Đ·Đ° Đ¿Ñ€Đ¾Đ½Đ°Đ»Đ°Đ¶ĐµÑе</translation>
<translation id="2958431318199492670">ĐĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° Đ¼Ñ€ĐµĐ¶Đµ Đ½Đ¸Ñ˜Đµ у ÑĐºĐ»Đ°Đ´Ñƒ ÑĐ° ONC ÑÑ‚Đ°Đ½Đ´Đ°Ñ€Đ´Đ¾Đ¼. Đ”ĐµĐ»Đ¾Đ²Đ¸ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đµ Đ½Đµ Đ¼Đ¾Đ³Ñƒ Đ´Đ° Ñе ÑƒĐ²ĐµĐ·Ñƒ.</translation>
@@ -188,8 +190,9 @@
<translation id="3024663005179499861">ĐŸĐ¾Đ³Ñ€ĐµÑˆĐ°Đ½ Ñ‚Đ¸Đ¿ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ°</translation>
<translation id="3032412215588512954">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ¿Đ¾Đ½Đ¾Đ²Đ¾ Đ´Đ° ÑƒÑ‡Đ¸Ñ‚Đ°Ñ‚Đµ Đ¾Đ²Đ°Ñ˜ ÑĐ°Ñ‚?</translation>
<translation id="3037605927509011580">Đ, Đ½Đµ!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{Đ½Đ°Ñ˜Đ¼Đ°Ñе 1 ÑÑ‚Đ°Đ²ĐºĐ° Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¾Đ²Đ°Đ½Đ¸Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ¸Đ¼Đ°}=1{1 ÑÑ‚Đ°Đ²ĐºĐ° (и Ñ˜Đ¾Ñˆ ÑÑ‚Đ°Đ²ĐºĐ¸ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¾Đ²Đ°Đ½Đ¸Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ¸Đ¼Đ°)}one{# ÑÑ‚Đ°Đ²ĐºĐ° (и Ñ˜Đ¾Ñˆ ÑÑ‚Đ°Đ²ĐºĐ¸ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¾Đ²Đ°Đ½Đ¸Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ¸Đ¼Đ°)}few{# ÑÑ‚Đ°Đ²ĐºĐµ (и Ñ˜Đ¾Ñˆ ÑÑ‚Đ°Đ²ĐºĐ¸ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¾Đ²Đ°Đ½Đ¸Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ¸Đ¼Đ°)}other{# ÑÑ‚Đ°Đ²ĐºĐ¸ (и Ñ˜Đ¾Ñˆ ÑÑ‚Đ°Đ²ĐºĐ¸ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¾Đ²Đ°Đ½Đ¸Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ¸Đ¼Đ°)}}</translation>
<translation id="3041612393474885105">Đ˜Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ˜Đµ Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Ñƒ</translation>
-<translation id="3063697135517575841">Chrome Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ¾ Đ´Đ° Đ¿Đ¾Ñ‚Đ²Ñ€Đ´Đ¸ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ. ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ.</translation>
+<translation id="3063697135517575841">Chrome Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ¾ Đ´Đ° Đ¿Đ¾Ñ‚Đ²Ñ€Đ´Đ¸ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ. ĐŸÑ€Đ¾Đ±Đ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ.</translation>
<translation id="3093245981617870298">ĐÑ„Đ»Đ°Ñ˜Đ½ ÑÑ‚Đµ.</translation>
<translation id="3105172416063519923">Đ˜Đ” ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚Đ°:</translation>
<translation id="3109728660330352905">ĐĐµĐ¼Đ°Ñ‚Đµ Đ¾Đ²Đ»Đ°ÑˆÑ›ĐµÑе Đ´Đ° Đ¿Ñ€ĐµĐ³Đ»ĐµĐ´Đ°Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.</translation>
@@ -206,17 +209,18 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">ĐĐ°Ñ˜Đ½Đ¾Đ²Đ¸Ñ˜Đµ</translation>
<translation id="3207960819495026254">ĐĐ±ĐµĐ»ĐµĐ¶ĐµĐ½Đ¾</translation>
-<translation id="3225919329040284222">Đ¡ĐµÑ€Đ²ĐµÑ€ Ñ˜Đµ Đ¿Ñ€Đ¸ĐºĐ°Đ·Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ĐºĐ¾Ñ˜Đ¸ Ñе Đ½Đµ Đ¿Đ¾Đ´ÑƒĐ´Đ°Ñ€Đ° ÑĐ° ÑƒĐ³Ñ€Đ°Ñ’ĐµĐ½Đ¸Đ¼ Đ¾Ñ‡ĐµĐºĐ¸Đ²Đ°ÑĐ¸Đ¼Đ°. Đ¢Đ° Đ¾Ñ‡ĐµĐºĐ¸Đ²Đ°ÑĐ° Ñу Đ¾Đ±ÑƒÑ…Đ²Đ°Ñ›ĐµĐ½Đ° Đ·Đ° Đ¾Đ´Ñ€ĐµÑ’ĐµĐ½Đµ Đ²ĐµĐ± ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đµ ÑĐ° Ñ˜Đ°ĐºĐ¸Đ¼ Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸Đ¼ Đ¼ĐµÑ€Đ°Đ¼Đ° ĐºĐ°ĐºĐ¾ би Đ²Đ°Ñ Đ·Đ°ÑˆÑ‚Đ¸Ñ‚Đ¸Đ»Đ°.</translation>
<translation id="3226128629678568754">ĐŸÑ€Đ¸Ñ‚Đ¸ÑĐ½Đ¸Ñ‚Đµ Đ´ÑƒĐ³Đ¼Đµ ĐŸĐ¾Đ½Đ¾Đ²Đ¾ ÑƒÑ‡Đ¸Ñ‚Đ°Ñ˜ Đ´Đ° биÑÑ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾ Đ¿Đ¾Ñлали Đ¿Đ¾Đ´Đ°Ñ‚ĐºĐµ Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ½Đµ Đ·Đ° ÑƒÑ‡Đ¸Ñ‚Đ°Đ²Đ°Ñе ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ.</translation>
<translation id="3228969707346345236">ĐŸÑ€ĐµĐ²Đ¾Đ´ Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ¾ Ñ˜ĐµÑ€ Ñ˜Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ› Đ½Đ° Ñ˜ĐµĐ·Đ¸ĐºÑƒ <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Đ£Đ½ĐµÑĐ¸Ñ‚Đµ CVC Đ·Đ° ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">ĐĐ±ĐµĐ»ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ</translation>
<translation id="3270847123878663523">&amp;ĐĐ¿Đ¾Đ·Đ¾Đ²Đ¸ Đ¿Ñ€Đ¾Đ¼ĐµĐ½Ñƒ Ñ€ĐµĐ´Đ¾Ñледа</translation>
<translation id="3286538390144397061">ĐŸĐ¾Đ½Đ¾Đ²Đ¾ Đ¿Đ¾ĐºÑ€ĐµĐ½Đ¸ Đ¾Đ´Đ¼Đ°Ñ…</translation>
+<translation id="3303855915957856445">ĐиÑу Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ½Đ¸ Ñ€ĐµĐ·ÑƒĐ»Ñ‚Đ°Ñ‚Đ¸ Đ¿Ñ€ĐµÑ‚Ñ€Đ°Đ³Đµ</translation>
<translation id="3305707030755673451">ĐŸĐ¾Đ´Đ°Ñ†Đ¸ Ñу ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¸ Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿Đ½Đµ Ñ„Ñ€Đ°Đ·Đµ Đ·Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ˜Ñƒ <ph name="TIME" />. Đ£Đ½ĐµÑĐ¸Ñ‚Đµ Ñ˜Đµ Đ´Đ° биÑÑ‚Đµ Đ·Đ°Đ¿Đ¾Ñ‡ĐµĐ»Đ¸ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ˜Ñƒ.</translation>
<translation id="333371639341676808">Đ¡Đ¿Ñ€ĐµÑ‡Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ Đ´Đ° Đ¿Ñ€Đ°Đ²Đ¸ Đ´Đ¾Đ´Đ°Ñ‚Đ½Đµ Đ´Đ¸Ñ˜Đ°Đ»Đ¾Đ³Đµ.</translation>
+<translation id="3338095232262050444">Đ‘ĐµĐ·Đ±ĐµĐ´Đ°Đ½</translation>
<translation id="3340978935015468852">Đ¿Đ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ°</translation>
-<translation id="3345135638360864351">Đ¡Đ»Đ°Ñе Đ·Đ°Ñ…Ñ‚ĐµĐ²Đ° Đ·Đ° Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿ Đ¾Đ²Đ¾Đ¼ ÑĐ°Ñ˜Ñ‚Ñƒ ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸ĐºÑƒ <ph name="NAME" /> Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ»Đ¾. ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾.</translation>
+<translation id="3345135638360864351">Đ¡Đ»Đ°Ñе Đ·Đ°Ñ…Ñ‚ĐµĐ²Đ° Đ·Đ° Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿ Đ¾Đ²Đ¾Đ¼ ÑĐ°Ñ˜Ñ‚Ñƒ ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸ĐºÑƒ <ph name="NAME" /> Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ»Đ¾. ĐŸÑ€Đ¾Đ±Đ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾.</translation>
<translation id="3355823806454867987">ĐŸÑ€Đ¾Đ¼ĐµĐ½Đ¸ Đ¿Đ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ° Đ¿Ñ€Đ¾ĐºÑĐ¸Ñ˜Đ°...</translation>
<translation id="3369192424181595722">Đ“Ñ€ĐµÑˆĐºĐ° Đ½Đ° ÑĐ°Ñ‚Ñƒ</translation>
<translation id="337363190475750230">ĐĐ½ĐµĐ¼Đ¾Đ³ÑƒÑ›ĐµĐ½ Ñ˜Đµ</translation>
@@ -232,14 +236,16 @@
<translation id="3452404311384756672">Đ˜Đ½Ñ‚ĐµÑ€Đ²Đ°Đ» ÑƒÑ‡Đ¸Ñ‚Đ°Đ²Đ°ÑĐ°:</translation>
<translation id="3462200631372590220">Đ¡Đ°ĐºÑ€Đ¸Ñ˜ Đ½Đ°Đ¿Ñ€ĐµĐ´Đ½Đ¾</translation>
<translation id="3479539252931486093">Да ли Ñ˜Đµ Đ¾Đ²Đ¾ Đ±Đ¸Đ»Đ¾ Đ½ĐµĐ¾Ñ‡ĐµĐºĐ¸Đ²Đ°Đ½Đ¾? <ph name="BEGIN_LINK" />ĐĐ±Đ°Đ²ĐµÑÑ‚Đ¸Ñ‚Đµ Đ½Đ°Ñ<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Đе ÑĐ°Đ´Đ°</translation>
<translation id="348000606199325318">Đ˜Đ” Đ¾Ñ‚ĐºĐ°Đ·Đ¸Đ²Đ°ÑĐ° <ph name="CRASH_LOCAL_ID" /> (Đ˜Đ” ÑĐµÑ€Đ²ĐµÑ€Đ°: <ph name="CRASH_ID" />)</translation>
-<translation id="3498215018399854026">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµĐ¼Đ¾ Đ´Đ° ĐºĐ¾Đ½Ñ‚Đ°ĐºÑ‚Đ¸Ñ€Đ°Đ¼Đ¾ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™Đ°. ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜ Đ¿Đ¾Đ½Đ¾Đ²Đ¾.</translation>
+<translation id="3498215018399854026">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµĐ¼Đ¾ Đ´Đ° ĐºĐ¾Đ½Ñ‚Đ°ĐºÑ‚Đ¸Ñ€Đ°Đ¼Đ¾ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™Đ°. ĐŸÑ€Đ¾Đ±Đ°Ñ˜ Đ¿Đ¾Đ½Đ¾Đ²Đ¾.</translation>
<translation id="3527085408025491307">Đ”Đ¸Ñ€ĐµĐºÑ‚Đ¾Ñ€Đ¸Ñ˜ÑƒĐ¼</translation>
<translation id="3528171143076753409">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½Đ¸Ñ˜Đµ Đ¿Đ¾ÑƒĐ·Đ´Đ°Đ½.</translation>
<translation id="3539171420378717834">Đ—Đ°Đ´Ñ€Đ¶Đ¸ ĐºĐ¾Đ¿Đ¸Ñ˜Ñƒ Đ¾Đ²Đµ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ Đ½Đ° Đ¾Đ²Đ¾Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Ñƒ</translation>
<translation id="3542684924769048008">ĐĐ¾Ñ€Đ¸ÑÑ‚Đ¸ Đ»Đ¾Đ·Đ¸Đ½ĐºÑƒ Đ·Đ°:</translation>
<translation id="3549644494707163724">Đ¨Đ¸Ñ„Ñ€ÑƒÑ˜ ÑĐ²Đµ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¾Đ²Đ°Đ½Đµ Đ¿Đ¾Đ´Đ°Ñ‚ĐºĐµ Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ Đ¼Đ¾Ñ˜Đµ Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿Đ½Đµ Ñ„Ñ€Đ°Đ·Đµ Đ·Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ˜Ñƒ</translation>
<translation id="3549761410225185768">ĐˆĐ¾Ñˆ <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ ÑĐ° <ph name="DOMAIN2" />. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Веза Đ½Đ¸Ñ˜Đµ Đ¿Ñ€Đ¸Đ²Đ°Ñ‚Đ½Đ°</translation>
<translation id="3583757800736429874">&amp;ĐŸĐ¾Đ½Đ¾Đ²Đ¸ Đ¿Ñ€ĐµĐ¼ĐµÑˆÑ‚Đ°Ñе</translation>
<translation id="3586931643579894722">Đ¡Đ°ĐºÑ€Đ¸Ñ˜ Đ´ĐµÑ‚Đ°Ñ™Đµ</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">ĐŸÑ€Đ¸ĐºĐ°Đ¶Đ¸ Đ²Ñ€ĐµĐ´Đ½Đ¾ÑÑ‚</translation>
<translation id="3630155396527302611">ĐĐºĐ¾ Ñ˜Đµ Đ²ĐµÑ› Đ½Đ°Đ²ĐµĐ´ĐµĐ½ ĐºĐ°Đ¾ Đ¿Ñ€Đ¾Đ³Ñ€Đ°Đ¼ ĐºĐ¾Đ¼Đµ Ñ˜Đµ Đ´Đ¾Đ·Đ²Đ¾Ñ™ĐµĐ½ Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿ Đ¼Ñ€ĐµĐ¶Đ¸, Đ¿Đ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ´Đ° Đ³Đ°
ÑƒĐºĐ»Đ¾Đ½Đ¸Ñ‚Đµ ÑĐ° лиÑÑ‚Đµ и Đ´Đ° Đ³Đ° Đ¿Đ¾Đ½Đ¾Đ²Đ¾ Đ´Đ¾Đ´Đ°Ñ‚Đµ.</translation>
+<translation id="3638794133396384728">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. Đ¡Đ°Ñ‚ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Ñ˜Đµ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½ Đ½Đ° <ph name="CURRENT_TIME" />. Да ли Ñ˜Đµ Ñ‚Đ¾ Ñ‚Đ°Ñ‡Đ½Đ¾? ĐĐºĐ¾ Đ½Đ¸Ñ˜Đµ, иÑĐ¿Ñ€Đ°Đ²Đ¸Ñ‚Đµ ÑĐ°Ñ‚ ÑиÑÑ‚ĐµĐ¼Đ° и Đ¾ÑĐ²ĐµĐ¶Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">ĐĐ²Đµ ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ°Đ»Đ½Đµ Ñ„ÑƒĐ½ĐºÑ†Đ¸Ñ˜Đµ у ÑĐ²Đ°ĐºĐ¾Đ¼ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚ĐºÑƒ Đ¼Đ¾Đ³Ñƒ Đ´Đ° Ñе Đ¿Ñ€Đ¾Đ¼ĐµĐ½Đµ, Đ½ĐµÑÑ‚Đ°Đ½Ñƒ или Đ¿Ñ€ĐµÑÑ‚Đ°Đ½Ñƒ Đ´Đ° Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑˆÑƒ. Đе Đ´Đ°Ñ˜ĐµĐ¼Đ¾ Đ½Đ¸ĐºĐ°ĐºĐ²Đµ Đ³Đ°Ñ€Đ°Đ½Ñ†Đ¸Ñ˜Đµ у Đ²ĐµĐ·Đ¸ ÑĐ° Ñ‚Đ¸Đ¼ ÑˆÑ‚Đ° Đ¼Đ¾Đ¶Đµ Đ´Đ° Ñе деÑи Đ°ĐºĐ¾ ÑƒĐºÑ™ÑƒÑ‡Đ¸Ñ‚Đµ Đ½ĐµĐºĐ¸ Đ¾Đ´ Đ¾Đ²Đ¸Ñ… ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Đ°Ñ‚Đ° и Đ¿Ñ€ĐµĐ³Đ»ĐµĐ´Đ°Ñ‡ Đ²Đ°Đ¼ ÑĐ¿Đ¾Đ½Ñ‚Đ°Đ½Đ¾ ĐµĐºÑĐ¿Đ»Đ¾Đ´Đ¸Ñ€Đ°. Đ¨Đ°Đ»Ñƒ Đ½Đ° ÑÑ‚Ñ€Đ°Đ½Ñƒ, Đ¿Ñ€ĐµĐ³Đ»ĐµĐ´Đ°Ñ‡ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ²Đ°Đ¼ Đ¸Đ·Đ±Ñ€Đ¸ÑˆĐµ ÑĐ²Đµ Đ¿Đ¾Đ´Đ°Ñ‚ĐºĐµ и Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑÑ‚ и Đ¿Ñ€Đ¸Đ²Đ°Ñ‚Đ½Đ¾ÑÑ‚ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ±ÑƒĐ´Đµ ÑƒĐ³Ñ€Đ¾Đ¶ĐµĐ½Đ° Đ½Đ° Đ½ĐµĐ¾Ñ‡ĐµĐºĐ¸Đ²Đ°Đ½Đµ Đ½Đ°Ñ‡Đ¸Đ½Đµ. Đ¡Đ²Đ¸ ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ¸ ĐºĐ¾Ñ˜Đµ Đ¾Đ¼Đ¾Đ³ÑƒÑ›Đ¸Ñ‚Đµ Đ±Đ¸Ñ›Đµ Đ¾Đ¼Đ¾Đ³ÑƒÑ›ĐµĐ½Đ¸ Đ·Đ° ÑĐ²Đµ ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸ĐºĐµ Đ¿Ñ€ĐµĐ³Đ»ĐµĐ´Đ°Ñ‡Đ°. Đ‘ÑƒĐ´Đ¸Ñ‚Đµ Đ¾Đ¿Ñ€ĐµĐ·Đ½Đ¸.</translation>
<translation id="3650584904733503804">ĐŸĐ¾Ñ‚Đ²Ñ€Đ´Đ° Đ²Đ°Ñ™Đ°Đ½Đ¾ÑÑ‚Đ¸ Ñ˜Đµ уÑĐ¿ĐµĐ»Đ°</translation>
<translation id="3655670868607891010">ĐĐºĐ¾ Đ²Đ°Đ¼ Ñе Đ¾Đ²Đ¾ Ñ‡ĐµÑÑ‚Đ¾ Đ¿Ñ€Đ¸ĐºĐ°Đ·ÑƒÑ˜Đµ, Đ¼Đ¾Đ¶Đ´Đ° Đ²Đ°Đ¼ Đ¿Đ¾Đ¼Đ¾Đ³Đ½Ñƒ ÑĐ»ĐµĐ´ĐµÑ›Đ¸ <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Đ ĐµĐ²Đ¸Đ·Đ¸Ñ˜Đ°</translation>
+<translation id="3678029195006412963">ĐŸĐ¾Ñ‚Đ¿Đ¸ÑĐ¸Đ²Đ°Ñе Đ·Đ°Ñ…Ñ‚ĐµĐ²Đ° Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ»Đ¾</translation>
<translation id="3681007416295224113">Đ˜Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ˜Đµ Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Ñƒ</translation>
<translation id="3693415264595406141">Đ›Đ¾Đ·Đ¸Đ½ĐºĐ°:</translation>
+<translation id="3696411085566228381">Đ½Đ¸ÑˆÑ‚Đ°</translation>
<translation id="3700528541715530410">Đ£Đ¿Ñ, Đ¸Đ·Đ³Đ»ĐµĐ´Đ° Đ´Đ° Đ½ĐµĐ¼Đ°Ñ‚Đµ Đ´Đ¾Đ·Đ²Đ¾Đ»Ñƒ Đ·Đ° Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿ Đ¾Đ²Đ¾Ñ˜ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ¸.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Đ£Ñ‡Đ¸Ñ‚Đ°Đ²Đ° Ñе...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Đ´Đ° ÑƒĐºÑ™ÑƒÑ‡Đ¸Ñ‚Đµ Đ¿Đ¾Đ´Đ°Ñ‚ĐºĐµ Đ·Đ° Đ¼Đ¾Đ±Đ¸Đ»Đ½Đµ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đµ или Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Đ´Đ° Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Ñƒ Đ¿Ñ€Đ¾ĐºÑĐ¸Ñ˜Đ°, Đ·Đ°ÑˆÑ‚Đ¸Ñ‚Đ½Đ¾Đ³ зида и DNS-Đ°<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Đ›Đ¸Đ½Đº ĐºĐ¾Ñ˜Đ¸ ÑÑ‚Đµ ĐºĐ¾Đ¿Đ¸Ñ€Đ°Đ»Đ¸</translation>
-<translation id="3744899669254331632">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" /> Ñ˜ĐµÑ€ Ñ˜Đµ Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚ Đ¿Đ¾ÑĐ»Đ°Đ¾ ĐºĐ¾Đ´Đ¸Ñ€Đ°Đ½Đµ Đ°ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ¸Đ²Đµ ĐºĐ¾Ñ˜Đµ Chromium Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾Đ±Ñ€Đ°Đ´Đ¸. Đ“Ñ€ĐµÑˆĐºĐµ Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸ и Đ½Đ°Đ¿Đ°Đ´Đ¸ Ñу ÑƒĐ³Đ»Đ°Đ²Đ½Đ¾Đ¼ Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¸, Đ¿Đ° Ñ›Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Đ¿Ñ€Đ¾Ñ€Đ°Đ´Đ¸Ñ‚Đ¸ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ.</translation>
<translation id="375403751935624634">ĐŸÑ€ĐµĐ²Đ¾Ñ’ĐµÑе Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ»Đ¾ Đ·Đ±Đ¾Đ³ Đ³Ñ€ĐµÑˆĐºĐµ ÑĐµÑ€Đ²ĐµÑ€Đ°.</translation>
<translation id="3759461132968374835">ĐĐµĐ¼Đ°Ñ‚Đµ Đ½Đ¸Ñ˜ĐµĐ´Đ½Đ¾ Đ½ĐµĐ´Đ°Đ²Đ½Đ¾ Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Ñ™ĐµĐ½Đ¾ Đ¾Ñ‚ĐºĐ°Đ·Đ¸Đ²Đ°Ñе. ĐÑ‚ĐºĐ°Đ·Đ¸Đ²Đ°ÑĐ° ĐºĐ¾Ñ˜Đ° Ñу Ñе деÑила Đ´Đ¾Đº Ñ˜Đµ Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Ñ™Đ¸Đ²Đ°Ñе Đ¾Ñ‚ĐºĐ°Đ·Đ¸Đ²Đ°ÑĐ° Đ±Đ¸Đ»Đ¾ Đ¾Đ½ĐµĐ¼Đ¾Đ³ÑƒÑ›ĐµĐ½Đ¾ Đ½ĐµÑ›Đµ Ñе Đ¾Đ²Đ´Đµ Đ¿Ñ€Đ¸ĐºĐ°Đ·Đ°Ñ‚Đ¸.</translation>
<translation id="3788090790273268753">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ·Đ° Đ¾Đ²Đ°Ñ˜ ÑĐ°Ñ˜Ñ‚ иÑÑ‚Đ¸Ñ‡Đµ 2016, Đ° Đ»Đ°Đ½Đ°Ñ† ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° ÑĐ°Đ´Ñ€Đ¶Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¿Đ¾Ñ‚Đ¿Đ¸ÑĐ°Đ½ Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚Đ¼Đ° SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">ĐĐµÑƒÑĐ°Đ³Đ»Đ°ÑˆĐµĐ½Đ¸ Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¾Ñ€ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ°</translation>
<translation id="3885155851504623709">ĐŸĐ°Ñ€Đ¾Ñ…Đ¸Ñ˜Đ°</translation>
<translation id="3901925938762663762">ĐĐ°Ñ€Ñ‚Đ¸Ñ†Đ° Ñ˜Đµ иÑÑ‚ĐµĐºĐ»Đ°</translation>
+<translation id="3910267023907260648">ĐŸĐ¾ĐºÑƒÑˆĐ°Đ»Đ¸ ÑÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="DOMAIN" />, али ÑĐµÑ€Đ²ĐµÑ€ Ñ˜Đµ Đ¿Đ¾ÑĐ»Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¿Đ¾Ñ‚Đ¿Đ¸ÑĐ°Đ½ ÑĐ»Đ°Đ±Đ¸Đ¼ Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚Đ¼Đ¾Đ¼. Đ¢Đ¾ Đ·Đ½Đ°Ñ‡Đ¸ Đ´Đ° Ñу Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ Đ°ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ¸Đ²Đ¸ ĐºĐ¾Ñ˜Đµ Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Đ¾ÑĐ»Đ°Đ¾ Đ¼Đ¾Đ¶Đ´Đ° ĐºÑ€Đ¸Đ²Đ¾Ñ‚Đ²Đ¾Ñ€ĐµĐ½Đ¸ и ÑĐµÑ€Đ²ĐµÑ€ Đ¼Đ¾Đ¶Đ´Đ° Đ½Đ¸Ñ˜Đµ Đ¾Đ½Đ°Ñ˜ ĐºĐ¾Ñ˜Đ¸ Đ¼Đ¸ÑĐ»Đ¸Ñ‚Đµ Đ´Đ° Ñ˜ĐµÑÑ‚Đµ (Đ¼Đ¾Đ¶Đ´Đ° ĐºĐ¾Đ¼ÑƒĐ½Đ¸Ñ†Đ¸Ñ€Đ°Ñ‚Đµ ÑĐ° Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ĐµĐ¼). <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Đ´Đ°Ñ‚ÑƒĐ¼ ÑĐµĐ³Đ¾Đ²Đ¾Đ³ Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¾Đ³ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° Ñ˜Đµ Đ½Đ°Đ²Đ¾Đ´Đ½Đ¾ ÑÑƒÑ‚Ñ€Đ°. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}one{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ Đ½Đ°Đ²Đ¾Đ´Đ½Đ¾ Đ´Đ°Ñ‚Đ¸Ñ€Đ°Đ½ у Đ±ÑƒĐ´ÑƒÑ›Đ½Đ¾ÑÑ‚Đ¸ (Đ·Đ° # Đ´Đ°Đ½). Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}few{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ Đ½Đ°Đ²Đ¾Đ´Đ½Đ¾ Đ´Đ°Ñ‚Đ¸Ñ€Đ°Đ½ у Đ±ÑƒĐ´ÑƒÑ›Đ½Đ¾ÑÑ‚Đ¸ (Đ·Đ° # Đ´Đ°Đ½Đ°). Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}other{ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ Đ½Đ°Đ²Đ¾Đ´Đ½Đ¾ Đ´Đ°Ñ‚Đ¸Ñ€Đ°Đ½ у Đ±ÑƒĐ´ÑƒÑ›Đ½Đ¾ÑÑ‚Đ¸ (Đ·Đ° # Đ´Đ°Đ½Đ°). Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Đ£Ñ‡Đ¸Ñ‚Đ°Đ²Đ°Ñе PDF Đ´Đ¾ĐºÑƒĐ¼ĐµĐ½Ñ‚Đ° Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ»Đ¾</translation>
<translation id="3963721102035795474">Đ ĐµĐ¶Đ¸Đ¼ Ñ‡Đ¸Ñ‚Đ°Đ¾Ñ†Đ°</translation>
+<translation id="397105322502079400">Đ˜Đ·Ñ€Đ°Ñ‡ÑƒĐ½Đ°Đ²Đ°Ñе...</translation>
<translation id="3973234410852337861">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Ñ˜Đµ Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° у Đ¾ĐºĐ¾Đ»Đ¸Đ½Đ¸}one{# Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° у Đ¾ĐºĐ¾Đ»Đ¸Đ½Đ¸}few{# Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ у Đ¾ĐºĐ¾Đ»Đ¸Đ½Đ¸}other{# Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° у Đ¾ĐºĐ¾Đ»Đ¸Đ½Đ¸}}</translation>
<translation id="4021036232240155012">DNS Ñ˜Đµ Đ¼Ñ€ĐµĐ¶Đ½Đ° уÑĐ»ÑƒĐ³Đ° ĐºĐ¾Ñ˜Đ° Đ¿Ñ€ĐµĐ²Đ¾Đ´Đ¸ Đ½Đ°Đ·Đ¸Đ² Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚Đ° у ÑĐµĐ³Đ¾Đ²Ñƒ Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ°Đ´Ñ€ĐµÑу.</translation>
<translation id="4030383055268325496">&amp;ĐĐ¿Đ¾Đ·Đ¾Đ²Đ¸ Đ´Đ¾Đ´Đ°Đ²Đ°Ñе</translation>
-<translation id="4032534284272647190">ĐŸÑ€Đ¸ÑÑ‚ÑƒĐ¿ Đ°Đ´Ñ€ĐµÑи <ph name="URL" /> Ñ˜Đµ Đ¾Đ´Đ±Đ¸Ñ˜ĐµĐ½.</translation>
<translation id="404928562651467259">Đ£ĐŸĐĐ—ĐĐ Đ•ĐĐ•</translation>
<translation id="4058922952496707368">Đључ â€<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">ĐĐ»Đ¸Ñ˜ĐµĐ½Ñ‚ и ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¿Đ¾Đ´Ñ€Đ¶Đ°Đ²Đ°Ñ˜Ñƒ иÑту Đ²ĐµÑ€Đ·Đ¸Ñ˜Ñƒ SSL Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»Đ° или Đ¿Đ°ĐºĐµÑ‚ Đ·Đ° ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Ñе.</translation>
<translation id="4079302484614802869">ĐĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° Đ¿Ñ€Đ¾ĐºÑĐ¸Ñ˜Đ° Ñ˜Đµ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½Đ° Đ´Đ° ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸ URL Đ°Đ´Ñ€ĐµÑу .pac ÑĐºÑ€Đ¸Đ¿Ñ‚Đµ, Đ° Đ½Đµ Ñ„Đ¸ĐºÑĐ½Đµ Đ¿Ñ€Đ¾ĐºÑи ÑĐµÑ€Đ²ĐµÑ€Đµ.</translation>
<translation id="4103249731201008433">Đ¡ĐµÑ€Đ¸Ñ˜ÑĐºĐ¸ Đ±Ñ€Đ¾Ñ˜ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ° Ñ˜Đµ Đ½ĐµĐ²Đ°Đ¶ĐµÑ›Đ¸</translation>
<translation id="4103763322291513355">ĐŸĐ¾ÑĐµÑ‚Đ¸Ñ‚Đµ &lt;strong&gt;chrome://policy&lt;/strong&gt; Đ´Đ° биÑÑ‚Đµ Đ²Đ¸Đ´ĐµĐ»Đ¸ лиÑту URL-Đ¾Đ²Đ° ÑÑ‚Đ°Đ²Ñ™ĐµĐ½Đ¸Ñ… Đ½Đ° Ñ†Ñ€Đ½Ñƒ лиÑту и Đ´Ñ€ÑƒĐ³Đµ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ ĐºĐ¾Ñ˜Đµ Ñ˜Đµ Đ½Đ°Đ¼ĐµÑ‚Đ½ÑƒĐ¾ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€ ÑиÑÑ‚ĐµĐ¼Đ°.</translation>
+<translation id="4110615724604346410">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐ°Đ´Ñ€Đ¶Đ¸ Đ³Ñ€ĐµÑˆĐºĐµ. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">ĐĐ¿ÑĐµĐ³ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ° Đ½Đ¸Ñ˜Đµ Đ¿Đ¾Đ´Ñ€Đ¶Đ°Đ½.</translation>
+<translation id="4118212371799607889">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Chromium Đ½ĐµĐ¼Đ° Đ¿Đ¾Đ²ĐµÑ€ĐµÑĐ° у ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{Ñ˜Đ¾Ñˆ 1}one{Ñ˜Đ¾Ñˆ #}few{Ñ˜Đ¾Ñˆ #}other{Ñ˜Đ¾Ñˆ #}}</translation>
<translation id="4130226655945681476">Đ´Đ° Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ Đ¼Ñ€ĐµĐ¶Đ½Đµ ĐºĐ°Đ±Đ»Đ¾Đ²Đµ, Đ¼Đ¾Đ´ĐµĐ¼ и Ñ€ÑƒÑ‚ĐµÑ€</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° Chromium ÑĐ°Ñ‡ÑƒĐ²Đ° Đ¾Đ²Ñƒ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">ĐĐ½ĐµĐ¼Đ¾Đ³ÑƒÑ›ĐµĐ½Đ¾</translation>
<translation id="4196861286325780578">&amp;ĐŸĐ¾Đ½Đ¾Đ²Đ¸ Đ¿Ñ€ĐµĐ¼ĐµÑˆÑ‚Đ°Ñе</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Đ´Đ° Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Ñƒ Đ·Đ°ÑˆÑ‚Đ¸Ñ‚Đ½Đ¾Đ³ зида и Đ°Đ½Ñ‚Đ¸Đ²Đ¸Ñ€ÑƒÑĐ°<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{Đ½Đ¸Ñ˜ĐµĐ´Đ½Đ°}=1{1 Đ°Đ¿Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ˜Đ° ($1)}=2{2 Đ°Đ¿Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ˜Đµ ($1, $2)}one{# Đ°Đ¿Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ˜Đ° ($1, $2, $3)}few{# Đ°Đ¿Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ˜Đµ ($1, $2, $3)}other{# Đ°Đ¿Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ˜Đ° ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">ĐÑ‚ĐºĐ°Đ·Đ¸Đ²Đ°ÑĐ°</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ´Đ° Đ¿Đ¾ĐºÑ€ĐµĐ½ĐµÑ‚Đµ Đ´Đ¸Ñ˜Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ Đ¼Ñ€ĐµĐ¶Đµ<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Đе</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Без ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸Ñ‡ĐºĐ¾Đ³ Đ¸Đ¼ĐµĐ½Đ°)</translation>
<translation id="4300246636397505754">ĐŸÑ€ĐµĐ´Đ»Đ¾Đ·Đ¸ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™Đ°</translation>
<translation id="4304224509867189079">ĐŸÑ€Đ¸Ñ˜Đ°Đ²Ñ™Đ¸Đ²Đ°Ñе</translation>
+<translation id="432290197980158659">Đ¡ĐµÑ€Đ²ĐµÑ€ Ñ˜Đµ Đ¿Đ¾ÑĐ»Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ĐºĐ¾Ñ˜Đ¸ Ñе Đ½Đµ Đ¿Đ¾Đ´ÑƒĐ´Đ°Ñ€Đ° ÑĐ° ÑƒĐ³Ñ€Đ°Ñ’ĐµĐ½Đ¸Đ¼ Đ¾Ñ‡ĐµĐºĐ¸Đ²Đ°ÑĐ¸Đ¼Đ°. Đ¢Đ° Đ¾Ñ‡ĐµĐºĐ¸Đ²Đ°ÑĐ° Ñу Đ¾Đ±ÑƒÑ…Đ²Đ°Ñ›ĐµĐ½Đ° Đ·Đ±Đ¾Đ³ Đ¾Đ´Ñ€ĐµÑ’ĐµĐ½Đ¸Ñ… Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đ° ÑĐ° Ñ˜Đ°ĐºĐ¸Đ¼ Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸Đ¼ Đ¼ĐµÑ€Đ°Đ¼Đ° ĐºĐ°ĐºĐ¾ би Đ²Đ°Ñ Đ·Đ°ÑˆÑ‚Đ¸Ñ‚Đ¸Đ»Đ°. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">ĐиÑĐ¼Đ¾ уÑĐ¿ĐµĐ»Đ¸ Đ´Đ° Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ¼Đ¾ Ñ‡Đ»Đ°Đ½Đ°Đº</translation>
+<translation id="4331708818696583467">ĐĐ¸Ñ˜Đµ Đ±ĐµĐ·Đ±ĐµĐ´Đ°Đ½</translation>
<translation id="4372948949327679948">ĐÑ‡ĐµĐºĐ¸Đ²Đ°Đ½Đ° Đ²Ñ€ĐµĐ´Đ½Đ¾ÑÑ‚ je <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">ĐŸĐ¾ĐºÑƒÑˆĐ°Đ»Đ¸ ÑÑ‚Đµ Đ´Đ° ĐºĐ¾Đ½Ñ‚Đ°ĐºÑ‚Đ¸Ñ€Đ°Ñ‚Đµ <ph name="DOMAIN" />, али Ñ˜Đµ Đ¸Đ·Đ´Đ°Đ²Đ°Ñ‡ Đ¾Đ¿Đ¾Đ·Đ²Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ²ĐµĐ¾. Đ¢Đ¾ Đ·Đ½Đ°Ñ‡Đ¸ Đ´Đ° Đ½Đ¸ĐºĐ°ĐºĐ¾ Đ½Đµ Ñ‚Ñ€ĐµĐ±Đ° Đ¸Đ¼Đ°Ñ‚Đ¸ Đ¿Đ¾Đ²ĐµÑ€ĐµÑĐ° у Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đµ Đ°ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ¸Đ²Đµ ĐºĐ¾Ñ˜Đµ Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ²ĐµĐ¾. ĐœĐ¾Đ³ÑƒÑ›Đµ Ñ˜Đµ Đ´Đ° ĐºĐ¾Đ¼ÑƒĐ½Đ¸Ñ†Đ¸Ñ€Đ°Ñ‚Đµ ÑĐ° Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ĐµĐ¼.</translation>
<translation id="4381091992796011497">Đ˜Đ¼Đµ ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸ĐºĐ°:</translation>
<translation id="4394049700291259645">ĐĐ½ĐµĐ¼Đ¾Đ³ÑƒÑ›Đ¸</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> – <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">Ñ€ĐµĐ·ÑƒĐ»Ñ‚Đ°Ñ‚Đ¸ Đ¿Ñ€ĐµÑ‚Ñ€Đ°Đ³Đµ</translation>
-<translation id="4424024547088906515">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Chrome Đ½ĐµĐ¼Đ° Đ¿Đ¾Đ²ĐµÑ€ĐµÑĐ° у ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> Đ½Đ¸Ñ˜Đµ Đ¿Ñ€Đ¸Ñ…Đ²Đ°Ñ‚Đ¸Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ·Đ° Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Ñ™Đ¸Đ²Đ°Ñе или ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ·Đ° Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Ñ™Đ¸Đ²Đ°Ñе Đ½Đ¸Ñ˜Đµ Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½.</translation>
<translation id="443673843213245140">ĐĐ¾Ñ€Đ¸ÑˆÑ›ĐµÑе Đ¿Ñ€Đ¾ĐºÑĐ¸Ñ˜Đ° Ñ˜Đµ Đ¾Đ½ĐµĐ¼Đ¾Đ³ÑƒÑ›ĐµĐ½Đ¾, али Ñ˜Đµ Đ½Đ°Đ²ĐµĐ´ĐµĐ½Đ° ĐµĐºÑĐ¿Đ»Đ¸Ñ†Đ¸Ñ‚Đ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° Đ¿Ñ€Đ¾ĐºÑĐ¸Ñ˜Đ°.</translation>
<translation id="4458874409874303848">Đ‘ĐµĐ·Đ±ĐµĐ´Đ½Đ¸ ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đ¸</translation>
<translation id="4461847750548395463">ĐĐ²Ñƒ Đ¿Đ¾Ñ€ÑƒĐºÑƒ Đ²Đ¸Đ´Đ¸Ñ‚Đµ Ñ˜ĐµÑ€ Ñу Google Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¸ ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đ¸ Đ¾Đ¼Đ¾Đ³ÑƒÑ›ĐµĐ½Đ¸.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Đ”ĐµÑ‚Đ°Ñ™Đ¸</translation>
<translation id="4558551763791394412">ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ´Đ° Đ¾Đ½ĐµĐ¼Đ¾Đ³ÑƒÑ›Đ¸Ñ‚Đµ Đ´Đ¾Đ´Đ°Ñ‚ĐºĐµ.</translation>
<translation id="4587425331216688090">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° ÑƒĐºĐ»Đ¾Đ½Đ¸Ñ‚Đµ Đ°Đ´Ñ€ĐµÑу из Chrome-Đ°?</translation>
+<translation id="4589078953350245614">ĐŸĐ¾ĐºÑƒÑˆĐ°Đ»Đ¸ ÑÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="DOMAIN" />, али Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Đ¾ÑĐ»Đ°Đ¾ Đ½ĐµĐ²Đ°Đ¶ĐµÑ›Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Веза ÑĐ° Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" /> Ñ˜Đµ ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ° Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ Đ¼Đ¾Đ´ĐµÑ€Đ½Đ¾Đ³ Đ¿Đ°ĐºĐµÑ‚Đ° Đ·Đ° ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Ñе.</translation>
<translation id="4594403342090139922">&amp;ĐĐ¿Đ¾Đ·Đ¾Đ²Đ¸ Đ±Ñ€Đ¸ÑĐ°Ñе</translation>
+<translation id="4627442949885028695">ĐĐ°ÑÑ‚Đ°Đ²Đ¸Ñ‚Đµ Đ½Đ° Đ´Ñ€ÑƒĐ³Đ¾Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Ñƒ</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">ĐŸÑ€ĐµĐ³Đ»ĐµĐ´Đ°Ñ‚Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ ÑĐ° Đ´Đ¾Đ´Đ°Ñ†Đ¸Đ¼Đ°.</translation>
-<translation id="467662567472608290">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐ°Đ´Ñ€Đ¶Đ¸ Đ³Ñ€ĐµÑˆĐºĐµ. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.</translation>
-<translation id="4697214168136963651">ĐĐ´Ñ€ĐµÑĐ° <ph name="URL" /> Ñ˜Đµ Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½Đ°</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Веза Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒÑ‚Đ°</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Đ´Đ° Đ¿Đ¾ĐºÑ€ĐµĐ½ĐµÑ‚Đµ Windows Đ´Đ¸Ñ˜Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ Đ¼Ñ€ĐµĐ¶Đµ<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">ĐŸĐ»Đ°Ñ‚Ñ„Đ¾Ñ€Đ¼Đ°</translation>
<translation id="4744603770635761495">ĐŸÑƒÑ‚Đ°ÑĐ° Đ¸Đ·Đ²Ñ€ÑˆĐ½Đµ Đ´Đ°Ñ‚Đ¾Ñ‚ĐµĐºĐµ</translation>
<translation id="4756388243121344051">&amp;Đ˜ÑÑ‚Đ¾Ñ€Đ¸Ñ˜Đ°</translation>
+<translation id="4759238208242260848">ĐŸÑ€ĐµÑƒĐ·Đ¸Đ¼Đ°ÑĐ°</translation>
<translation id="4764776831041365478">ĐœĐ¾Đ³ÑƒÑ›Đµ Ñ˜Đµ Đ´Đ° Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ½Đ° Đ°Đ´Ñ€ĐµÑи <ph name="URL" /> Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¾ Đ½Đµ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑˆĐµ или Đ´Đ° Ñ˜Đµ Ñ‚Ñ€Đ°Ñ˜Đ½Đ¾ Đ¿Ñ€ĐµĐ¼ĐµÑˆÑ‚ĐµĐ½Đ° Đ½Đ° Đ½Đ¾Đ²Ñƒ Đ²ĐµĐ± Đ°Đ´Ñ€ĐµÑу.</translation>
<translation id="4771973620359291008">Đ”Đ¾ÑˆĐ»Đ¾ Ñ˜Đµ Đ´Đ¾ Đ½ĐµĐ¿Đ¾Đ·Đ½Đ°Ñ‚Đµ Đ³Ñ€ĐµÑˆĐºĐµ.</translation>
<translation id="4782449893814226250">ĐŸĐ¸Ñ‚Đ°Đ¾/ла Ñи Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™Đµ Đ´Đ° ли ÑĐ¼ĐµÑˆ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñˆ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.</translation>
<translation id="4800132727771399293">ĐŸÑ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ Đ´Đ°Ñ‚ÑƒĐ¼ иÑÑ‚ĐµĐºĐ° и CVC и Đ¿Đ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾</translation>
-<translation id="4807049035289105102">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" /> Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ Ñ˜Đµ Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚ Đ¿Đ¾ÑĐ»Đ°Đ¾ ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đµ Đ°ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ¸Đ²Đµ ĐºĐ¾Ñ˜Đµ Google Chrome Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾Đ±Ñ€Đ°Đ´Đ¸. Đ“Ñ€ĐµÑˆĐºĐµ и Đ½Đ°Đ¿Đ°Đ´Đ¸ Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸ Ñу Đ¾Đ±Đ¸Ñ‡Đ½Đ¾ Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¸, Đ¿Đ° Ñ›Đµ Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑĐ°Ñ‚Đ¸ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ.</translation>
<translation id="4813512666221746211">Đ“Ñ€ĐµÑˆĐºĐ° Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸</translation>
<translation id="4816492930507672669">Đ£ĐºĐ»Đ¾Đ¿Đ¸ у ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ</translation>
<translation id="4850886885716139402">ĐŸÑ€Đ¸ĐºĐ°Đ·</translation>
<translation id="4880827082731008257">ĐŸÑ€ĐµÑ‚Ñ€Đ°Đ¶Đ¸ иÑÑ‚Đ¾Ñ€Đ¸Ñ˜Ñƒ</translation>
+<translation id="4884656795097055129">ĐˆĐ¾Ñˆ Ñ‡Đ»Đ°Đ½Đ°ĐºĐ° Ñ›Đµ Ñе Đ¿Đ¾Ñ˜Đ°Đ²Đ¸Ñ‚Đ¸ у Đ¾Đ´Đ³Đ¾Đ²Đ°Ñ€Đ°Ñ˜ÑƒÑ›Đµ Đ²Ñ€ĐµĐ¼Đµ.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{и Ñ˜Đ¾Ñ˜ 1 Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°}one{и Ñ˜Đ¾Ñˆ # Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°}few{и Ñ˜Đ¾Ñˆ # Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ}other{и Ñ˜Đ¾Ñˆ # Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ°}}</translation>
<translation id="4923417429809017348">ĐĐ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Ñ˜Đµ Đ¿Ñ€ĐµĐ²ĐµĐ´ĐµĐ½Đ° ÑĐ° Đ½ĐµĐ¿Đ¾Đ·Đ½Đ°Ñ‚Đ¾Đ³ Ñ˜ĐµĐ·Đ¸ĐºĐ° Đ½Đ° <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">ĐœĐ¾Ñ€Đ° Đ´Đ° Đ±ÑƒĐ´Đµ Đ½Đ°Đ²ĐµĐ´ĐµĐ½Đ¾.</translation>
<translation id="4930497775425430760">ĐĐ²Ñƒ Đ¿Đ¾Ñ€ÑƒĐºÑƒ Đ²Đ¸Đ´Đ¸Ñ‚Đµ Ñ˜ĐµÑ€ Đ²Đ°Ñˆ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™ Ñ‚Ñ€ĐµĐ±Đ° Đ´Đ° Đ¾Đ´Đ¾Đ±Ñ€Đ¸ Đ½Đ¾Đ²Đµ ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đµ Đ¿Ñ€Đ¸ Đ¿Ñ€Đ²Đ¾Ñ˜ Đ¿Đ¾ÑĐµÑ‚Đ¸.</translation>
<translation id="495170559598752135">Đ Đ°Đ´Ñе</translation>
<translation id="4958444002117714549">ĐŸÑ€Đ¾ÑˆĐ¸Ñ€Đ¸ лиÑту</translation>
+<translation id="4962322354953122629">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Chrome Đ½ĐµĐ¼Đ° Đ¿Đ¾Đ²ĐµÑ€ĐµÑĐ° у ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° Đ¿Ñ€ĐµĐ²ĐµĐ´ĐµÑ‚Đµ ÑĐ° Ñ˜ĐµĐ·Đ¸ĐºĐ° <ph name="ORIGINAL_LANGUAGE" /> Đ½Đ° <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">ĐĐ²Đ° Đ´Đ¾Đ´Đ°Ñ‚Đ½Đ° ĐºĐ¾Đ¼Đ¿Đ¾Đ½ĐµĐ½Ñ‚Đ° Đ½Đ¸Ñ˜Đµ Đ¿Đ¾Đ´Ñ€Đ¶Đ°Đ½Đ°</translation>
<translation id="5002932099480077015">ĐĐºĐ¾ Ñ˜Đµ Đ¾Đ²Đ° Đ¾Đ¿Ñ†Đ¸Ñ˜Đ° Đ¾Đ¼Đ¾Đ³ÑƒÑ›ĐµĐ½Đ°, Chrome Ñ›Đµ ÑĐºĐ»Đ°Đ´Đ¸ÑˆÑ‚Đ¸Ñ‚Đ¸ ĐºĐ¾Đ¿Đ¸Ñ˜Ñƒ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ Đ½Đ° Đ¾Đ²Đ¾Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Ñƒ Ñ€Đ°Đ´Đ¸ Đ±Ñ€Đ¶ĐµĐ³ Đ¿Đ¾Đ¿ÑƒÑĐ°Đ²Đ°ÑĐ° Đ¾Đ±Ñ€Đ°Đ·Đ°Ñ†Đ°.</translation>
<translation id="5019198164206649151">Đ¡ĐºĐ»Đ°Đ´Đ¸ÑˆÑ‚Đµ Ñ‚Đ¾ĐºĐ° Đ¿Đ¾Đ´Đ°Ñ‚Đ°ĐºĐ° Ñ˜Đµ у Đ»Đ¾ÑˆĐµĐ¼ ÑÑ‚Đ°Ñу</translation>
<translation id="5023310440958281426">ĐŸÑ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ Đ°Đ´Đ¼Đ¸Đ½Đ¸ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Đ°</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Đ Google Đ¿Ñ€ĐµĐ²Đ¾Đ´Đ¸Đ¾Ñ†Ñƒ</translation>
<translation id="5040262127954254034">ĐŸÑ€Đ¸Đ²Đ°Ñ‚Đ½Đ¾ÑÑ‚</translation>
<translation id="5045550434625856497">ĐеиÑĐ¿Ñ€Đ°Đ²Đ½Đ° Đ»Đ¾Đ·Đ¸Đ½ĐºĐ°</translation>
+<translation id="5056549851600133418">Đ§Đ»Đ°Đ½Ñ†Đ¸ Đ·Đ° Đ²Đ°Ñ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Đ´Đ° Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ Đ°Đ´Ñ€ĐµÑу Đ¿Ñ€Đ¾ĐºÑĐ¸Ñ˜Đ°<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đ¸Ñ˜Đµ Đ²Đ°Đ¶ĐµÑ›Đ¸.</translation>
<translation id="5089810972385038852">Đ”Ñ€Đ¶Đ°Đ²Đ°</translation>
-<translation id="5094747076828555589">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Chromium Đ½ĐµĐ¼Đ° Đ¿Đ¾Đ²ĐµÑ€ĐµÑĐ° у ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.</translation>
<translation id="5095208057601539847">ĐŸÑ€Đ¾Đ²Đ¸Đ½Ñ†Đ¸Ñ˜Đ°</translation>
<translation id="5115563688576182185">(64-Đ±Đ¸Ñ‚Đ½Đ¸)</translation>
-<translation id="5122371513570456792">ĐŸÑ€Đ¾Đ½Đ°ÑˆĐ»Đ¸ ÑĐ¼Đ¾ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> Đ·Đ° â€<ph name="SEARCH_STRING" />“.</translation>
<translation id="5141240743006678641">Đ¨Đ¸Ñ„Ñ€ÑƒÑ˜ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¾Đ²Đ°Đ½Đµ Đ»Đ¾Đ·Đ¸Đ½ĐºĐµ Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ Google Đ°ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ¸Đ²Đ°</translation>
<translation id="5145883236150621069">ĐĂ´Đ´ Đ³Ñ€ĐµÑˆĐºĐµ Ñ˜Đµ Đ¿Ñ€Đ¸ÑÑƒÑ‚Đ°Đ½ у Đ¾Đ´Đ³Đ¾Đ²Đ¾Ñ€Ñƒ Đ½Đ° ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ</translation>
<translation id="5171045022955879922">ĐŸÑ€ĐµÑ‚Ñ€Đ°Đ¶Đ¸Ñ‚Đµ или ÑƒĐ½ĐµÑĐ¸Ñ‚Đµ URL Đ°Đ´Ñ€ĐµÑу</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Đ¢Ñ€Đ°ĐºĐ° ÑĐ° Đ¾Đ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡Đ¸Đ¼Đ°</translation>
<translation id="5199729219167945352">Đ•ĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ¸</translation>
<translation id="5251803541071282808">ĐĐ»Đ°ÑƒĐ´</translation>
+<translation id="5277279256032773186">Да ли ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸Ñ‚Đµ Chrome Đ½Đ° Đ¿Đ¾ÑĐ»Ñƒ? ĐŸÑ€ĐµĐ´ÑƒĐ·ĐµÑ›Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° ÑƒĐ¿Ñ€Đ°Đ²Ñ™Đ° Đ¿Đ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ¸Đ¼Đ° Chrome-Đ° Đ·Đ° Đ·Đ°Đ¿Đ¾ÑĐ»ĐµĐ½Đµ. Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ</translation>
<translation id="5299298092464848405">Đ“Ñ€ĐµÑˆĐºĐ° Đ¿Ñ€Đ¸ Ñ€Đ°ÑˆÑ‡Đ»Đ°ÑĐ¸Đ²Đ°Ñу ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ°</translation>
<translation id="5300589172476337783">ĐŸÑ€Đ¸ĐºĐ°Đ¶Đ¸</translation>
<translation id="5308689395849655368">Đ˜Đ·Đ²ĐµÑˆÑ‚Đ°Đ²Đ°Ñе Đ¾ Đ¾Ñ‚ĐºĐ°Đ·Đ¸Đ²Đ°Ñу Ñ˜Đµ Đ¾Đ½ĐµĐ¼Đ¾Đ³ÑƒÑ›ĐµĐ½Đ¾.</translation>
<translation id="5317780077021120954">Đ¡Đ°Ñ‡ÑƒĐ²Đ°Ñ˜</translation>
<translation id="5327248766486351172">ĐĐ°Đ·Đ¸Đ²</translation>
+<translation id="5359637492792381994">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đ¸Ñ˜Đµ Đ²Đ°Đ¶ĐµÑ›Đ¸. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Đ¡ĐºĐ»Đ°Đ´Đ¸ÑˆÑ‚ĐµÑе Đ¿Đ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ° ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ° Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ»Đ¾</translation>
-<translation id="540969355065856584">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đ¸Ñ˜Đµ Đ²Đ°Đ¶ĐµÑ›Đ¸. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.</translation>
<translation id="5421136146218899937">ĐĐ±Ñ€Đ¸ÑˆĐ¸ Đ¿Đ¾Đ´Đ°Ñ‚ĐºĐµ Đ¿Ñ€ĐµĐ³Đ»ĐµĐ´Đ°ÑĐ°...</translation>
<translation id="5430298929874300616">Đ£ĐºĐ»Đ¾Đ½Đ¸Ñ‚Đµ Đ¾Đ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡</translation>
<translation id="5431657950005405462">Đ”Đ°Ñ‚Đ¾Ñ‚ĐµĐºĐ° Đ½Đ¸Ñ˜Đµ Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ½Đ°</translation>
<translation id="5435775191620395718">ĐŸÑ€Đ¸ĐºĐ°Đ·ÑƒÑ˜ĐµĐ¼Đ¾ иÑÑ‚Đ¾Ñ€Đ¸Ñ˜Ñƒ ÑĐ° Đ¾Đ²Đ¾Đ³ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ°. <ph name="BEGIN_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">ĐŸÑ€ĐµĐ´Đ»Đ¾Đ·Đ¸ Đ·Đ° Đ¿ĐµÑ€ÑĐ¾Đ½Đ°Đ»Đ¸Đ·Đ¾Đ²Đ°Đ½Đ¸ ÑĐ°Đ´Ñ€Đ¶Đ°Ñ˜ Ñу Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ¾Đ½ĐµĐ¼Đ¾Đ³ÑƒÑ›ĐµĐ½Đ¸ Ñ˜ĐµÑ€ Ñу ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ¾Đ²Đ°Đ½Đ¸ Đ¿Đ¾Đ´Đ°Ñ†Đ¸ Đ·Đ°ÑˆÑ‚Đ¸Ñ›ĐµĐ½Đ¸ Đ¿Ñ€Đ¸Đ»Đ°Đ³Đ¾Ñ’ĐµĐ½Đ¾Đ¼ Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿Đ½Đ¾Đ¼ Ñ„Ñ€Đ°Đ·Đ¾Đ¼.</translation>
<translation id="5439770059721715174">Đ“Ñ€ĐµÑˆĐºĐ° у Đ²Đ°Đ»Đ¸Đ´Đ°Ñ†Đ¸Ñ˜Đ¸ ÑˆĐµĐ¼Đµ Đ½Đ° â€<ph name="ERROR_PATH" />“: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">ĐĐ¸Ñ˜Đµ Đ¼Đ¾Đ³ÑƒÑ›Đµ Đ¿Ñ€Đ¾Đ½Đ°Ñ›Đ¸ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ Ñ…Đ¾ÑÑ‚Đ° <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">ĐеиÑĐ¿Ñ€Đ°Đ²Đ½Đ° Đ²Ñ€ĐµĐ¼ĐµĐ½ÑĐºĐ° Đ¾Đ·Đ½Đ°ĐºĐ° ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ°</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° Đ½Đ°Đ¿ÑƒÑÑ‚Đ¸Ñ‚Đµ Đ¾Đ²Đ°Ñ˜ ÑĐ°Ñ˜Ñ‚?</translation>
<translation id="5629630648637658800">Đ£Ñ‡Đ¸Ñ‚Đ°Đ²Đ°Ñе Đ¿Đ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ° ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ° Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ»Đ¾</translation>
<translation id="5631439013527180824">ĐĐµĐ²Đ°Đ¶ĐµÑ›Đ¸ Ñ‚Đ¾ĐºĐµĐ½ Đ·Đ° ÑƒĐ¿Ñ€Đ°Đ²Ñ™Đ°Ñе ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ¸Đ¼Đ°</translation>
-<translation id="5650551054760837876">ĐĐ¸Ñ˜Đµ Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ½ Đ½Đ¸Ñ˜ĐµĐ´Đ°Đ½ Ñ€ĐµĐ·ÑƒĐ»Ñ‚Đ°Ñ‚.</translation>
<translation id="5677928146339483299">Đ‘Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½Đ¾</translation>
<translation id="5710435578057952990">Đ˜Đ´ĐµĐ½Ñ‚Đ¸Ñ‚ĐµÑ‚ Đ¾Đ²Đ¾Đ³ Đ²ĐµĐ± ÑĐ°Ñ˜Ñ‚Đ° Đ½Đ¸Ñ˜Đµ Đ²ĐµÑ€Đ¸Ñ„Đ¸ĐºĐ¾Đ²Đ°Đ½.</translation>
<translation id="5720705177508910913">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¸ ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸Đº</translation>
+<translation id="572328651809341494">ĐĐµĐ´Đ°Đ²Đ½Đ¾ ĐºĐ¾Ñ€Đ¸ÑˆÑ›ĐµĐ½Đµ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ</translation>
<translation id="5784606427469807560">Đ”Đ¾ÑˆĐ»Đ¾ Ñ˜Đµ Đ´Đ¾ Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ° Đ¿Ñ€Đ¸ Đ¿Đ¾Ñ‚Đ²Ñ€Đ´Đ¸ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ. ĐŸÑ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ²ĐµĐ·Ñƒ и Đ¿Đ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾.</translation>
<translation id="5785756445106461925">ĐŸĐ¾Ñ€ĐµĐ´ Ñ‚Đ¾Đ³Đ°, Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° ÑĐ°Đ´Ñ€Đ¶Đ¸ и Đ´Ñ€ÑƒĐ³Đµ Ñ€ĐµÑурÑе ĐºĐ¾Ñ˜Đ¸ Đ½Đ¸Ñу Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¸. ĐĐ²Đµ Ñ€ĐµÑурÑе Đ¼Đ¾Đ³Ñƒ Đ´Đ° Đ²Đ¸Đ´Đµ и Đ´Ñ€ÑƒĐ³Đ¸ Đ´Đ¾Đº Ñу у Đ¿Ñ€Đ¾Đ»Đ°Đ·Ñƒ и Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¸Ñ… Đ¸Đ·Đ¼ĐµĐ½Đ¸ ĐºĐ°ĐºĐ¾ би Đ¿Ñ€Đ¾Đ¼ĐµĐ½Đ¸Đ¾ Đ¸Đ·Đ³Đ»ĐµĐ´ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ.</translation>
+<translation id="5786044859038896871">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° Đ¿Đ¾Đ¿ÑƒĐ½Đ¸Ñ‚Đµ Đ¸Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ˜Đµ Đ¾ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đ¸?</translation>
+<translation id="5803412860119678065">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° Đ¿Đ¾Đ¿ÑƒĐ½Đ¸Ñ‚Đµ Đ¿Đ¾Đ´Đ°Ñ†Đ¸Đ¼Đ° <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Веза ÑĐ° Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" /> Ñ˜Đµ ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ° Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ Đ·Đ°ÑÑ‚Đ°Ñ€ĐµĐ»Đ¾Đ³ Đ¿Đ°ĐºĐµÑ‚Đ° Đ·Đ° ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Ñе.</translation>
<translation id="5813119285467412249">&amp;ĐŸĐ¾Đ½Đ¾Đ²Đ¸ Đ´Đ¾Đ´Đ°Đ²Đ°Ñе</translation>
+<translation id="5814352347845180253">ĐœĐ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¸Đ·Đ³ÑƒĐ±Đ¸Ñ‚Đµ Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿ Đ¿Ñ€ĐµĐ¼Đ¸Ñ˜ÑƒĐ¼ ÑĐ°Đ´Ñ€Đ¶Đ°Ñ˜Ñƒ ÑĐ° ÑĐ°Ñ˜Ñ‚Đ° <ph name="SITE" /> и Đ½ĐµĐºĐ¸Ñ… Đ´Ñ€ÑƒĐ³Đ¸Ñ… ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đ°.</translation>
+<translation id="5843436854350372569">ĐŸĐ¾ĐºÑƒÑˆĐ°Đ»Đ¸ ÑÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="DOMAIN" />, али Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Đ¾ÑĐ»Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ĐºĐ¾Ñ˜Đ¸ ÑĐ°Đ´Ñ€Đ¶Đ¸ Ñлаб ĐºÑ™ÑƒÑ‡. ĐœĐ¾Đ³ÑƒÑ›Đµ Ñ˜Đµ Đ´Đ° Ñ˜Đµ Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ Đ¾Ñ‚ĐºÑ€Đ¸Đ¾ Đ¿Ñ€Đ¸Đ²Đ°Ñ‚Đ½Đ¸ ĐºÑ™ÑƒÑ‡ и Đ´Đ° ÑĐµÑ€Đ²ĐµÑ€ Đ¼Đ¾Đ¶Đ´Đ° Đ½Đ¸Ñ˜Đµ Đ¾Đ½Đ°Ñ˜ ĐºĐ¾Ñ˜Đ¸ Đ¼Đ¸ÑĐ»Đ¸Ñ‚Đµ Đ´Đ° Ñ˜ĐµÑÑ‚Đµ (Đ¼Đ¾Đ¶Đ´Đ° ĐºĐ¾Đ¼ÑƒĐ½Đ¸Ñ†Đ¸Ñ€Đ°Ñ‚Đµ ÑĐ° Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ĐµĐ¼). <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">ĐĐ²Ñƒ Đ¿Đ¾Ñ€ÑƒĐºÑƒ Đ²Đ¸Đ´Đ¸Ñ‚Đµ Ñ˜ĐµÑ€ Ñ˜Đµ Đ²Đ°Ñˆ Đ¼ĐµĐ½Đ°ÑŸĐµÑ€ Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ¾ Đ¾Đ²Đ°Ñ˜ ÑĐ°Ñ˜Ñ‚.</translation>
<translation id="5857090052475505287">ĐĐ¾Đ²Đ¸ Đ´Đ¸Ñ€ĐµĐºÑ‚Đ¾Ñ€Đ¸Ñ˜ÑƒĐ¼</translation>
<translation id="5869405914158311789">ĐĐ²Đ°Ñ˜ ÑĐ°Ñ˜Ñ‚ Đ½Đ¸Ñ˜Đµ Đ´Đ¾ÑÑ‚ÑƒĐ¿Đ°Đ½</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">ĐŸÑ€ĐµĐ´Đ»Đ¾Đ·Đ¸ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™Đ°</translation>
<translation id="59107663811261420">Google Payments Đ½Đµ Đ¿Đ¾Đ´Ñ€Đ¶Đ°Đ²Đ° Đ¾Đ²Đ°Ñ˜ Ñ‚Đ¸Đ¿ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ Đ·Đ° Đ¾Đ²Đ¾Đ³ Đ¿Ñ€Đ¾Đ´Đ°Đ²Ñ†Đ°. Đ˜Đ·Đ°Đ±ĐµÑ€Đ¸Ñ‚Đµ Đ½ĐµĐºÑƒ Đ´Ñ€ÑƒĐ³Ñƒ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ.</translation>
<translation id="59174027418879706">ĐĐ¼Đ¾Đ³ÑƒÑ›ĐµĐ½Đ¾</translation>
+<translation id="5926846154125914413">ĐœĐ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¸Đ·Đ³ÑƒĐ±Đ¸Ñ‚Đµ Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿ Đ¿Ñ€ĐµĐ¼Đ¸Ñ˜ÑƒĐ¼ ÑĐ°Đ´Ñ€Đ¶Đ°Ñ˜Ñƒ ÑĐ° Đ½ĐµĐºĐ¸Ñ… ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đ°.</translation>
<translation id="5966707198760109579">ĐĐµĐ´ĐµÑ™Đ°</translation>
<translation id="5967867314010545767">Đ£ĐºĐ»Đ¾Đ½Đ¸ из иÑÑ‚Đ¾Ñ€Đ¸Ñ˜Đµ</translation>
<translation id="5975083100439434680">Đ£Đ¼Đ°ÑĐ¸Đ²Đ°Ñе</translation>
@@ -433,11 +458,11 @@
<translation id="604124094241169006">ĐÑƒÑ‚Đ¾Đ¼Đ°Ñ‚ÑĐºĐ¸</translation>
<translation id="6042308850641462728">Đ’Đ¸ÑˆĐµ</translation>
<translation id="6060685159320643512">ĐŸĐ°Đ·Đ¸Ñ‚Đµ, Đ¾Đ²Đ¸ ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ¸ Đ¼Đ¾Đ³Ñƒ Đ±Đ¸Ñ‚Đ¸ Đ¾Đ¿Đ°ÑĐ½Đ¸</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{Đ½Đ¸Ñ˜ĐµĐ´Đ½Đ°}=1{1}one{#}few{#}other{#}}</translation>
<translation id="6146055958333702838">ĐŸÑ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ ÑĐ²Đµ ĐºĐ°Đ±Đ»Đ¾Đ²Đµ и Ñ€ĐµÑÑ‚Đ°Ñ€Ñ‚ÑƒÑ˜Ñ‚Đµ ÑĐ²Đµ Ñ€ÑƒÑ‚ĐµÑ€Đµ, Đ¼Đ¾Đ´ĐµĐ¼Đµ или Đ´Ñ€ÑƒĐ³Đµ Đ¼Ñ€ĐµĐ¶Đ½Đµ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đµ ĐºĐ¾Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸Ñ‚Đµ.</translation>
<translation id="614940544461990577">ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ:</translation>
<translation id="6150607114729249911">Đ£Đ¿Ñ! Đ¢Ñ€ĐµĐ±Đ° Đ´Đ° Đ¿Đ¸Ñ‚Đ°Ñ‚Đµ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™Đµ Đ´Đ° ли Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.</translation>
<translation id="6151417162996330722">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ¸Đ¼Đ° Đ¿Ñ€ĐµĐ´ÑƒĐ³Đ°Ñ‡Đ°Đº Đ¿ĐµÑ€Đ¸Đ¾Đ´ Đ²Đ°Đ¶ĐµÑĐ°.</translation>
-<translation id="6154808779448689242">Đ’Ñ€Đ°Ñ›ĐµĐ½Đ¸ Ñ‚Đ¾ĐºĐµĐ½ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ° Ñе Đ½Đµ Đ¿Đ¾Đ´ÑƒĐ´Đ°Ñ€Đ° ÑĐ° Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¸Đ¼ Ñ‚Đ¾ĐºĐµĐ½Đ¾Đ¼</translation>
<translation id="6165508094623778733">Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ</translation>
<translation id="6203231073485539293">ĐŸÑ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ²ĐµĐ·Ñƒ</translation>
<translation id="6218753634732582820">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° ÑƒĐºĐ»Đ¾Đ½Đ¸Ñ‚Đµ Đ°Đ´Ñ€ĐµÑу из Chromium-Đ°?</translation>
@@ -450,24 +475,30 @@
<translation id="6328639280570009161">ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ´Đ° Đ¾Đ½ĐµĐ¼Đ¾Đ³ÑƒÑ›Đ¸Ñ‚Đµ Đ¿Ñ€ĐµĐ´Đ²Đ¸Ñ’Đ°Ñе Đ¼Ñ€ĐµĐ¶Đµ</translation>
<translation id="6337534724793800597">Đ¤Đ¸Đ»Ñ‚Ñ€Đ¸Ñ€Đ°Ñ˜ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ Đ¿Ñ€ĐµĐ¼Đ° Đ½Đ°Đ·Đ¸Đ²Ñƒ</translation>
<translation id="6342069812937806050">ĐœĐ°Đ»Đ¾Đ¿Ñ€Đµ</translation>
+<translation id="6345221851280129312">Đ½ĐµĐ¿Đ¾Đ·Đ½Đ°Ñ‚Đ° Đ²ĐµĐ»Đ¸Ñ‡Đ¸Đ½Đ°</translation>
<translation id="6355080345576803305">Đ—Đ°Đ¼ĐµĐ½Đ° Ñ˜Đ°Đ²Đ½Đµ ÑеÑĐ¸Ñ˜Đµ</translation>
<translation id="6358450015545214790">Đ¨Ñ‚Đ° Đ¾Đ²Đ¾ Đ·Đ½Đ°Ñ‡Đ¸?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{Ñ˜Đ¾Ñˆ 1 Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ³}one{Ñ˜Đ¾Ñˆ # Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ³}few{Ñ˜Đ¾Ñˆ # Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ³Đ°}other{Ñ˜Đ¾Ñˆ # Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ³Đ°}}</translation>
<translation id="6387478394221739770">Đ˜Đ½Ñ‚ĐµÑ€ĐµÑују Đ²Đ°Ñ Đ½Đ¾Đ²Đµ Đ·Đ°Đ½Đ¸Đ¼Ñ™Đ¸Đ²Đµ Chrome Ñ„ÑƒĐ½ĐºÑ†Đ¸Ñ˜Đµ? Đ˜ÑĐ¿Ñ€Đ¾Đ±Đ°Ñ˜Ñ‚Đµ Đ±ĐµÑ‚Đ° ĐºĐ°Đ½Đ°Đ» Đ½Đ° chrome.com/beta.</translation>
-<translation id="641480858134062906">ĐĐ¸Ñ˜Đµ уÑĐ¿ĐµĐ»Đ¾ ÑƒÑ‡Đ¸Ñ‚Đ°Đ²Đ°Ñе ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ <ph name="URL" /></translation>
+<translation id="6389758589412724634">Chromium-у Ñ˜Đµ Đ¿Đ¾Đ½ĐµÑÑ‚Đ°Đ»Đ¾ Đ¼ĐµĐ¼Đ¾Ñ€Đ¸Ñ˜Đµ Đ´Đ¾Đº Ñ˜Đµ Đ¿Đ¾ĐºÑƒÑˆĐ°Đ²Đ°Đ¾ Đ´Đ° Đ¿Ñ€Đ¸ĐºĐ°Đ¶Đµ Đ¾Đ²Ñƒ Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.</translation>
+<translation id="6416403317709441254">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" /> Ñ˜ĐµÑ€ Ñ˜Đµ Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚ Đ¿Đ¾ÑĐ»Đ°Đ¾ ĐºĐ¾Đ´Đ¸Ñ€Đ°Đ½Đµ Đ°ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ¸Đ²Đµ ĐºĐ¾Ñ˜Đµ Chromium Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾Đ±Ñ€Đ°Đ´Đ¸. Đ“Ñ€ĐµÑˆĐºĐµ Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸ и Đ½Đ°Đ¿Đ°Đ´Đ¸ Ñу ÑƒĐ³Đ»Đ°Đ²Đ½Đ¾Đ¼ Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¸, Đ¿Đ° Ñ›Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑĐ°Ñ‚Đ¸ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">ĐĐ¸Ñ˜Đµ Đ¼Đ¾Đ³ÑƒÑ›Đµ Đ¿Ñ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đ¸ Đ´Đ° ли Ñ˜Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¾Đ¿Đ¾Đ·Đ²Đ°Đ½.</translation>
<translation id="6433595998831338502">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Ñ˜Đµ Đ¾Đ´Đ±Đ¸Đ¾ Đ¿Đ¾Đ²ĐµĐ·Đ¸Đ²Đ°Ñе.</translation>
<translation id="6445051938772793705">Đ—ĐµĐ¼Ñ™Đ°</translation>
<translation id="6451458296329894277">ĐŸĐ¾Ñ‚Đ²Ñ€Ñ’Đ¸Đ²Đ°Ñе Đ¿Đ¾Đ½Đ¾Đ²Đ½Đ¾Đ³ ÑлаÑĐ° Đ¾Đ±Ñ€Đ°ÑÑ†Đ°</translation>
<translation id="6458467102616083041">Đ—Đ°Đ½ĐµĐ¼Đ°Ñ€ÑƒÑ˜Đµ Ñе Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ Đ¾Đ²Đµ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ Đ¾Đ½ĐµĐ¼Đ¾Đ³ÑƒÑ›Đ°Đ²Đ°Ñ˜Ñƒ Đ¿Đ¾Đ´Ñ€Đ°Đ·ÑƒĐ¼ĐµĐ²Đ°Đ½Ñƒ Đ¿Ñ€ĐµÑ‚Ñ€Đ°Đ³Ñƒ.</translation>
+<translation id="6462969404041126431">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¾Đ¿Đ¾Đ·Đ²Đ°Đ½. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Đ¡Đ¼ĐµÑ€Đ½Đ¸Ñ†Đµ Đ·Đ° ÑƒÑ€ĐµÑ’Đ°Ñ˜</translation>
<translation id="6489534406876378309">ĐŸĐ¾ĐºÑ€ĐµĐ½Đ¸ Đ¾Ñ‚Đ¿Ñ€ĐµĐ¼Đ°Ñе Đ¾Ñ‚ĐºĐ°Đ·Đ¸Đ²Đ°ÑĐ°</translation>
<translation id="6529602333819889595">&amp;ĐŸĐ¾Đ½Đ¾Đ²Đ¸ Đ±Ñ€Đ¸ÑĐ°Ñе</translation>
+<translation id="6534179046333460208">ĐŸÑ€ĐµĐ´Đ»Đ¾Đ·Đ¸ Đ˜Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚Đ° Đ¾ĐºĐ¾ Đ½Đ°Ñ</translation>
<translation id="6550675742724504774">ĐĐ¿Ñ†Đ¸Ñ˜Đµ</translation>
+<translation id="6593753688552673085">Đ¼Đ°Ñе Đ¾Đ´ <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">ĐĐ¿Ñ†Đ¸Ñ˜Đµ ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°ÑĐ°</translation>
<translation id="662080504995468778">Đе Đ½Đ°Đ¿ÑƒÑˆÑ‚Đ°Ñ˜</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Đ¿Ñ€ĐµÑ‚Ñ€Đ°Đ³Đ°</translation>
-<translation id="6634865548447745291">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" /> Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ Ñ˜Đµ <ph name="BEGIN_LINK" />Đ¾Đ²Đ°Ñ˜ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¾Đ¿Đ¾Đ·Đ²Đ°Đ½<ph name="END_LINK" />. Đ“Ñ€ĐµÑˆĐºĐµ и Đ½Đ°Đ¿Đ°Đ´Đ¸ Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸ Ñу Đ¾Đ±Đ¸Ñ‡Đ½Đ¾ Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¸, Đ¿Đ° Ñ›Đµ Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑĐ°Ñ‚Đ¸ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ.</translation>
<translation id="6644283850729428850">ĐĐ²Đµ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ Ñу Đ·Đ°ÑÑ‚Đ°Ñ€ĐµĐ»Đµ.</translation>
+<translation id="6652240803263749613">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Đ¾Đ¿ĐµÑ€Đ°Ñ‚Đ¸Đ²Đ½Đ¸ ÑиÑÑ‚ĐµĐ¼ Đ²Đ°ÑˆĐµĐ³ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Đ° Đ½ĐµĐ¼Đ° Đ¿Đ¾Đ²ĐµÑ€ĐµÑĐ° у ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Đ˜Đ·Đ¼ĐµĐ½Đ° Đ´Đ¸Ñ€ĐµĐºÑ‚Đ¾Ñ€Đ¸Ñ˜ÑƒĐ¼Đ°</translation>
<translation id="6660210980321319655">ĐÑƒÑ‚Đ¾Đ¼Đ°Ñ‚ÑĐºĐ¸ Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Ñ™ĐµĐ½Đ¾ <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° ÑƒĐºĐ»Đ¾Đ½Đ¸Ñ‚Đµ Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ³ из Chromium-Đ°?</translation>
@@ -475,6 +506,7 @@
<translation id="6710213216561001401">ĐŸÑ€ĐµÑ‚Ñ…Đ¾Đ´Đ½Đ¾</translation>
<translation id="6710594484020273272">&lt;Đ£Đ½ĐµÑĐ¸Ñ‚Đµ Ñ‚ĐµÑ€Đ¼Đ¸Đ½ Đ·Đ° Đ¿Ñ€ĐµÑ‚Ñ€Đ°Đ³Ñƒ&gt;</translation>
<translation id="6711464428925977395">ĐĐµÑˆÑ‚Đ¾ Đ½Đ¸Ñ˜Đµ у Ñ€ĐµĐ´Ñƒ ÑĐ° Đ¿Ñ€Đ¾ĐºÑи ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼ или Ñ˜Đµ Đ°Đ´Ñ€ĐµÑĐ° Đ½ĐµÑ‚Đ°Ñ‡Đ½Đ°.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{Đ½Đ¸Ñ˜ĐµĐ´Đ½Đ°}=1{1 ÑÑ‚Đ°Đ²ĐºĐ°}one{# ÑÑ‚Đ°Đ²ĐºĐ°}few{# ÑÑ‚Đ°Đ²ĐºĐµ}other{# ÑÑ‚Đ°Đ²ĐºĐ¸}}</translation>
<translation id="674375294223700098">ĐĐµĐ¿Đ¾Đ·Đ½Đ°Ñ‚Đ° Đ³Ñ€ĐµÑˆĐºĐ° ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ° ÑĐµÑ€Đ²ĐµÑ€Đ°.</translation>
<translation id="6753269504797312559">Đ’Ñ€ĐµĐ´Đ½Đ¾ÑÑ‚ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ°</translation>
<translation id="6757797048963528358">Đ£Ñ€ĐµÑ’Đ°Ñ˜ Ñ˜Đµ Đ¿Ñ€ĐµÑˆĐ°Đ¾ у Ñ€ĐµĐ¶Đ¸Đ¼ ÑĐ¿Đ°Đ²Đ°ÑĐ°.</translation>
@@ -486,7 +518,6 @@
<translation id="6891596781022320156">ĐĐ¸Đ²Đ¾ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ° Đ½Đ¸Ñ˜Đµ Đ¿Đ¾Đ´Ñ€Đ¶Đ°Đ½.</translation>
<translation id="6895330447102777224">ĐĐ°Ñ€Ñ‚Đ¸Ñ†Đ° Ñ˜Đµ Đ¿Đ¾Ñ‚Đ²Ñ€Ñ’ĐµĐ½Đ°</translation>
<translation id="6897140037006041989">ĐĐ¾Ñ€Đ¸ÑĐ½Đ¸Ñ‡ĐºĐ¸ Đ°Đ³ĐµĐ½Ñ‚</translation>
-<translation id="6903907808598579934">Đ£ĐºÑ™ÑƒÑ‡Đ¸ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ˜Ñƒ</translation>
<translation id="6915804003454593391">ĐĐ¾Ñ€Đ¸ÑĐ½Đ¸Đº:</translation>
<translation id="6957887021205513506">Đ˜Đ·Đ³Đ»ĐµĐ´Đ° Đ´Đ° Ñ˜Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Ñ„Đ°Đ»ÑĐ¸Ñ„Đ¸ĐºĐ¾Đ²Đ°Đ½.</translation>
<translation id="6965382102122355670">ĐŸĐ¾Ñ‚Đ²Ñ€Đ´Đ¸</translation>
@@ -494,9 +525,11 @@
<translation id="6970216967273061347">ДиÑÑ‚Ñ€Đ¸ĐºÑ‚</translation>
<translation id="6973656660372572881">ĐĐ°Đ²ĐµĐ´ĐµĐ½Đ¸ Ñу и Ñ„Đ¸ĐºÑĐ½Đ¸ Đ¿Ñ€Đ¾ĐºÑи ÑĐµÑ€Đ²ĐµÑ€Đ¸ и URL Đ°Đ´Ñ€ĐµÑĐ° .pac ÑĐºÑ€Đ¸Đ¿Ñ‚Đµ.</translation>
<translation id="6989763994942163495">ĐŸÑ€Đ¸ĐºĐ°Đ¶Đ¸ Đ½Đ°Đ¿Ñ€ĐµĐ´Đ½Đ° Đ¿Đ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ°...</translation>
+<translation id="7000990526846637657">ĐĐ¸Ñ˜Đµ Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ½ Đ½Đ¸Ñ˜ĐµĐ´Đ°Đ½ ÑƒĐ½Đ¾Ñ Ñƒ иÑÑ‚Đ¾Ñ€Đ¸Ñ˜Đ¸</translation>
+<translation id="7009986207543992532">ĐŸĐ¾ĐºÑƒÑˆĐ°Đ»Đ¸ ÑÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="DOMAIN" />, али Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Đ¾ÑĐ»Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐ° Đ¿ĐµÑ€Đ¸Đ¾Đ´Đ¾Đ¼ Đ²Đ°Đ¶ĐµÑĐ° ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐ´ÑƒĐ³Đ°Ñ‡Đ°Đº Đ´Đ° би Đ±Đ¸Đ¾ Đ¿Đ¾ÑƒĐ·Đ´Đ°Đ½. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Google Đ½Đ°Đ»Đ¾Đ³ Đ¸Đ¼Đ° Đ´Ñ€ÑƒĐ³Đµ Đ¾Đ±Đ»Đ¸ĐºĐµ иÑÑ‚Đ¾Ñ€Đ¸Ñ˜Đµ Đ¿Ñ€ĐµĐ³Đ»ĐµĐ´Đ°ÑĐ° Đ½Đ° <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Đ›Đ¾Đ·Đ¸Đ½ĐºĐµ</translation>
-<translation id="7050187094878475250">ĐŸĐ¾ĐºÑƒÑˆĐ°Đ»Đ¸ ÑÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="DOMAIN" />, али Ñ˜Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ¿Ñ€ĐµĐ´ÑÑ‚Đ°Đ²Đ¸Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐ° Đ¿ĐµÑ€Đ¸Đ¾Đ´Đ¾Đ¼ Đ²Đ°Đ¶ĐµÑĐ° ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐ´ÑƒĐ³Đ°Ñ‡Đ°Đº Đ´Đ° би Đ±Đ¸Đ¾ Đ¿Đ¾ÑƒĐ·Đ´Đ°Đ½.</translation>
<translation id="7087282848513945231">ĐĐºÑ€ÑƒĐ³</translation>
<translation id="7088615885725309056">Đ¡Ñ‚Đ°Ñ€Đ¸Ñ˜Đµ</translation>
<translation id="7090678807593890770">ĐŸĐ¾Ñ‚Ñ€Đ°Đ¶Đ¸Ñ‚Đµ <ph name="LINK" /> Đ½Đ° Google-у</translation>
@@ -515,13 +548,13 @@
<translation id="7246609911581847514">ĐĐ²Ñƒ Đ¿Đ¾Ñ€ÑƒĐºÑƒ Đ²Đ¸Đ´Đ¸Ñ‚Đµ Ñ˜ĐµÑ€ Đ²Đ°Ñˆ Đ¼ĐµĐ½Đ°ÑŸĐµÑ€ Ñ‚Ñ€ĐµĐ±Đ° Đ´Đ° Đ¾Đ´Đ¾Đ±Ñ€Đ¸ Đ½Đ¾Đ²Đµ ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đµ Đ¿Ñ€Đ¸ Đ¿Ñ€Đ²Đ¾Ñ˜ Đ¿Đ¾ÑĐµÑ‚Đ¸.</translation>
<translation id="724975217298816891">Đ£Đ½ĐµÑĐ¸Ñ‚Đµ Ñ€Đ¾Đº Ñ‚Ñ€Đ°Ñ˜Đ°ÑĐ° и CVC Đ·Đ° ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ <ph name="CREDIT_CARD" /> Đ´Đ° биÑÑ‚Đµ Đ°Đ¶ÑƒÑ€Đ¸Ñ€Đ°Đ»Đ¸ Đ¿Đ¾Đ´Đ°Ñ‚ĐºĐµ Đ¾ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đ¸. ĐĐ°Đ´Đ° Đ±ÑƒĐ´ĐµÑ‚Đµ Đ¿Đ¾Ñ‚Đ²Ñ€Đ´Đ¸Đ»Đ¸, Đ¿Đ¾Đ´Đ°Ñ†Đ¸ Đ¾ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đ¸ Ñ›Đµ Đ±Đ¸Ñ‚Đ¸ Đ¿Đ¾ÑĐ»Đ°Ñ‚Đ¸ Đ¾Đ²Đ¾Đ¼ ÑĐ°Ñ˜Ñ‚Ñƒ.</translation>
<translation id="725866823122871198">ĐĐ¸Ñ˜Đµ Đ¼Đ¾Đ³ÑƒÑ›Đµ уÑĐ¿Đ¾ÑÑ‚Đ°Đ²Đ¸Ñ‚Đ¸ Đ¿Ñ€Đ¸Đ²Đ°Ñ‚Đ½Ñƒ Đ²ĐµĐ·Ñƒ ÑĐ° Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> Ñ˜ĐµÑ€ Đ²Ñ€ĐµĐ¼Đµ и Đ´Đ°Ñ‚ÑƒĐ¼ Đ½Đ° Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€Ñƒ (<ph name="DATE_AND_TIME" />) Đ½Đ¸Ñу Ñ‚Đ°Ñ‡Đ½Đ¸.</translation>
-<translation id="7265986070661382626">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" /> Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚ <ph name="BEGIN_LINK" />ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸ Đ¿Ñ€Đ¾Đ²ĐµÑ€Ñƒ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°<ph name="END_LINK" />. Đ“Ñ€ĐµÑˆĐºĐµ и Đ½Đ°Đ¿Đ°Đ´Đ¸ Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸ Ñу Đ¾Đ±Đ¸Ñ‡Đ½Đ¾ Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¸, Đ¿Đ° Ñ›Đµ Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑĐ°Ñ‚Đ¸ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ.</translation>
<translation id="7269802741830436641">ĐĐ²Đ° Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ¸Đ¼Đ° Đ¿ĐµÑ‚Ñ™Ñƒ Đ·Đ° Đ¿Ñ€ĐµÑƒÑĐ¼ĐµÑ€Đ°Đ²Đ°Ñе</translation>
<translation id="7275334191706090484">ĐĐ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡Đ¸ ĐºĐ¾Ñ˜Đ¸Đ¼ Ñе ÑƒĐ¿Ñ€Đ°Đ²Ñ™Đ°</translation>
<translation id="7298195798382681320">ĐŸÑ€ĐµĐ¿Đ¾Ñ€ÑƒÑ‡ĐµĐ½Đ¾</translation>
-<translation id="7301833672208172928">Đ£ĐºÑ™ÑƒÑ‡Đ¸ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ˜Ñƒ иÑÑ‚Đ¾Ñ€Đ¸Ñ˜Đµ</translation>
+<translation id="7309308571273880165">Đ˜Đ·Đ²ĐµÑˆÑ‚Đ°Ñ˜ Đ¾ Đ¾Ñ‚ĐºĐ°Đ·Đ¸Đ²Đ°Ñу Ñ˜Đµ ÑĐ½Đ¸Đ¼Ñ™ĐµĐ½ <ph name="CRASH_TIME" /> (ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸Đº Ñ‚Ñ€ĐµĐ±Đ° Đ´Đ° Đ³Đ° Đ¾Ñ‚Đ¿Ñ€ĐµĐ¼Đ¸, Ñ˜Đ¾Ñˆ ÑƒĐ²ĐµĐº Đ½Đ¸Ñ˜Đµ Đ¾Ñ‚Đ¿Ñ€ĐµĐ¼Ñ™ĐµĐ½)</translation>
<translation id="7334320624316649418">&amp;ĐŸĐ¾Đ½Đ¾Đ²Đ¸ Đ¿Ñ€Đ¾Đ¼ĐµĐ½Ñƒ Ñ€ĐµĐ´Đ¾Ñледа</translation>
<translation id="733923710415886693">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½Đ¸Ñ˜Đµ Đ¾Ñ‚ĐºÑ€Đ¸Đ²ĐµĐ½ Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ Đ¢Ñ€Đ°Đ½ÑĐ¿Đ°Ñ€ĐµĐ½Ñ‚Đ½Đ¾ÑÑ‚Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°.</translation>
+<translation id="7351800657706554155">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñ‚Đµ <ph name="SITE" /> Ñ˜ĐµÑ€ Ñ˜Đµ ÑĐµĐ³Đ¾Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Đ¾Đ¿Đ¾Đ·Đ²Đ°Đ½. Đ“Ñ€ĐµÑˆĐºĐµ и Đ½Đ°Đ¿Đ°Đ´Đ¸ Đ½Đ° Đ¼Ñ€ĐµĐ¶Đ¸ Ñу Đ¾Đ±Đ¸Ñ‡Đ½Đ¾ Đ¿Ñ€Đ¸Đ²Ñ€ĐµĐ¼ĐµĐ½Đ¸, Đ¿Đ° Ñ›Đµ Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ²ĐµÑ€Đ¾Đ²Đ°Ñ‚Đ½Đ¾ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑĐ°Ñ‚Đ¸ ĐºĐ°ÑĐ½Đ¸Ñ˜Đµ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">ĐĐ¾Đ¼Đ°Đ½Đ´Đ½Đ° Đ»Đ¸Đ½Đ¸Ñ˜Đ°</translation>
<translation id="7372973238305370288">Ñ€ĐµĐ·ÑƒĐ»Ñ‚Đ°Ñ‚ Đ¿Ñ€ĐµÑ‚Ñ€Đ°Đ³Đµ</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -540,16 +573,17 @@
<translation id="7469372306589899959">ĐŸĐ¾Ñ‚Đ²Ñ€Ñ’Đ¸Đ²Đ°Ñе ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ</translation>
<translation id="7481312909269577407">ĐŸÑ€Đ¾Ñледи</translation>
<translation id="7485870689360869515">ĐиÑу Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ½Đ¸ Đ¿Đ¾Đ´Đ°Ñ†Đ¸.</translation>
+<translation id="7508255263130623398">Đ’Ñ€Đ°Ñ›ĐµĐ½Đ¸ Đ˜Đ” ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ° Đ·Đ° ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đµ Ñ˜Đµ Đ¿Ñ€Đ°Đ·Đ°Đ½ или Ñе Đ½Đµ Đ¿Đ¾Đ´ÑƒĐ´Đ°Ñ€Đ° ÑĐ° Đ°ĐºÑ‚ÑƒĐµĐ»Đ½Đ¸Đ¼ Đ˜Đ”-Đ¾Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ°</translation>
<translation id="7514365320538308">ĐŸÑ€ĐµÑƒĐ·Đ¼Đ¸</translation>
<translation id="7518003948725431193">ĐĐ¸Ñ˜ĐµĐ´Đ½Đ° Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ½Đ¸Ñ˜Đµ Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ½Đ° Đ·Đ° Đ²ĐµĐ± Đ°Đ´Ñ€ĐµÑу: <ph name="URL" /></translation>
<translation id="7537536606612762813">ĐĐ±Đ°Đ²ĐµĐ·Đ½Đ¾</translation>
<translation id="7542995811387359312">ĐĐ½ĐµĐ¼Đ¾Đ³ÑƒÑ›ĐµĐ½Đ¾ Ñ˜Đµ Đ°ÑƒÑ‚Đ¾Đ¼Đ°Ñ‚ÑĐºĐ¾ Đ¿Đ¾Đ¿ÑƒÑĐ°Đ²Đ°Ñе ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đµ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ Đ¾Đ²Đ°Ñ˜ Đ¾Đ±Ñ€Đ°Đ·Đ°Ñ† Đ½Đµ ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸ Đ±ĐµĐ·Đ±ĐµĐ´Đ½Ñƒ Đ²ĐµĐ·Ñƒ.</translation>
<translation id="7549584377607005141">ĐĐ²Đ° Đ²ĐµĐ±-ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ·Đ°Ñ…Ñ‚ĐµĐ²Đ° Đ¿Đ¾Đ´Đ°Ñ‚ĐºĐµ ĐºĐ¾Ñ˜Đµ ÑÑ‚Đµ ÑƒĐ½ĐµĐ»Đ¸ Ñ€Đ°Đ½Đ¸Ñ˜Đµ Đ´Đ° би Ñе Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ½Đ¾ Đ¿Ñ€Đ¸ĐºĐ°Đ·Đ°Đ»Đ°. ĐœĐ¾Đ¶ĐµÑ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾ Đ´Đ° Đ¿Đ¾ÑˆĐ°Ñ™ĐµÑ‚Đµ Ñ‚Đµ Đ¿Đ¾Đ´Đ°Ñ‚ĐºĐµ, али Đ°ĐºĐ¾ Ñ‚Đ¾ ÑƒÑ€Đ°Đ´Đ¸Ñ‚Đµ, Đ¿Đ¾Đ½Đ¾Đ²Đ¸Ñ›ĐµÑ‚Đµ Đ±Đ¸Đ»Đ¾ ĐºĐ¾Ñ˜Ñƒ Ñ€Đ°Đ´Ñу ĐºĐ¾Ñ˜Ñƒ Ñ˜Đµ Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Đ¿Ñ€ĐµÑ‚Ñ…Đ¾Đ´Đ½Đ¾ Đ¾Đ±Đ°Đ²Đ¸Đ»Đ°.</translation>
<translation id="7554791636758816595">ĐĐ¾Đ²Đ° ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đ°</translation>
-<translation id="7567204685887185387">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ»Đ°Đ¶Đ½Đ¾ Đ¸Đ·Đ´Đ°Ñ‚. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ.</translation>
<translation id="7568593326407688803">ĐĐ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Ñ˜Đµ Đ½Đ° Ñ˜ĐµĐ·Đ¸ĐºÑƒ:<ph name="ORIGINAL_LANGUAGE" />Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° Ñ˜Đµ Đ¿Ñ€ĐµĐ²ĐµĐ´ĐµÑ‚Đµ?</translation>
<translation id="7569952961197462199">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° ÑƒĐºĐ»Đ¾Đ½Đ¸Ñ‚Đµ ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Ñƒ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ из Chrome-Đ°?</translation>
<translation id="7578104083680115302">ĐŸĐ»Đ°Ñ›Đ°Ñ˜Ñ‚Đµ Đ±Ñ€Đ·Đ¾ Đ½Đ° ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đ¸Đ¼Đ° и у Đ°Đ¿Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ˜Đ°Đ¼Đ° Đ½Đ° ÑĐ²Đ¸Đ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ¸Đ¼Đ° Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đ° ĐºĐ¾Ñ˜Đµ ÑÑ‚Đµ ÑĐ°Ñ‡ÑƒĐ²Đ°Đ»Đ¸ Đ½Đ° Google-у.</translation>
+<translation id="7588950540487816470">Đ˜Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ¾ĐºĐ¾ Đ½Đ°Ñ</translation>
<translation id="7592362899630581445">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° ĐºÑ€ÑˆĐ¸ Đ¾Đ³Ñ€Đ°Đ½Đ¸Ñ‡ĐµÑĐ° Đ·Đ° Đ¸Đ¼Đµ.</translation>
<translation id="759889825892636187">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Ñ‚Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¾Đ±Ñ€Đ°Đ´Đ¸ Đ¾Đ²Đ°Ñ˜ Đ·Đ°Ñ…Ñ‚ĐµĐ².</translation>
<translation id="7600965453749440009">ĐĐ¸ĐºĐ°Đ´ Đ½Đµ Đ¿Ñ€ĐµĐ²Đ¾Đ´Đ¸ <ph name="LANGUAGE" /></translation>
@@ -560,6 +594,7 @@
<translation id="7637571805876720304">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° ÑƒĐºĐ»Đ¾Đ½Đ¸Ñ‚Đµ ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Ñƒ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ из Chromium-Đ°?</translation>
<translation id="765676359832457558">Đ¡Đ°ĐºÑ€Đ¸Ñ˜ Đ½Đ°Đ¿Ñ€ĐµĐ´Đ½Đ° Đ¿Đ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ°...</translation>
<translation id="7658239707568436148">ĐÑ‚ĐºĐ°Đ¶Đ¸</translation>
+<translation id="7667346355482952095">Đ’Ñ€Đ°Ñ›ĐµĐ½Đ¸ Ñ‚Đ¾ĐºĐµĐ½ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ° Ñ˜Đµ Đ¿Ñ€Đ°Đ·Đ°Đ½ или Ñе Đ½Đµ Đ¿Đ¾Đ´ÑƒĐ´Đ°Ñ€Đ° ÑĐ° Đ°ĐºÑ‚ÑƒĐµĐ»Đ½Đ¸Đ¼ Ñ‚Đ¾ĐºĐµĐ½Đ¾Đ¼</translation>
<translation id="7668654391829183341">ĐĐµĐ¿Đ¾Đ·Đ½Đ°Ñ‚ ÑƒÑ€ĐµÑ’Đ°Ñ˜</translation>
<translation id="7674629440242451245">Đ˜Đ½Ñ‚ĐµÑ€ĐµÑују Đ²Đ°Ñ Đ½Đ¾Đ²Đµ Đ·Đ°Đ½Đ¸Đ¼Ñ™Đ¸Đ²Đµ Chrome Ñ„ÑƒĐ½ĐºÑ†Đ¸Ñ˜Đµ? Đ˜ÑĐ¿Ñ€Đ¾Đ±Đ°Ñ˜Ñ‚Đµ Đ¿Ñ€Đ¾Đ³Ñ€Đ°Đ¼ĐµÑ€ÑĐºĐ¸ ĐºĐ°Đ½Đ°Đ» Đ½Đ° chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ĐĐ°ÑÑ‚Đ°Đ²Đ¸ Đ½Đ° <ph name="SITE" /> (Đ½Đ¸Ñ˜Đµ Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾)<ph name="END_LINK" /></translation>
@@ -576,10 +611,10 @@
<translation id="780301667611848630">Đе, Ñ…Đ²Đ°Đ»Đ°</translation>
<translation id="7805768142964895445">Đ¡Ñ‚Đ°Ñ‚ÑƒÑ</translation>
<translation id="7813600968533626083">Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° ÑƒĐºĐ»Đ¾Đ½Đ¸Ñ‚Đµ Đ¿Ñ€ĐµĐ´Đ»Đ¾Đ³ из Chrome-Đ°?</translation>
+<translation id="7815407501681723534">ĐŸÑ€Đ¾Đ½Đ°ÑˆĐ»Đ¸ ÑĐ¼Đ¾ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> Đ·Đ° â€<ph name="SEARCH_STRING" />“</translation>
<translation id="785549533363645510">Đли, Đ½Đ¸ÑÑ‚Đµ Đ½ĐµĐ²Đ¸Đ´Ñ™Đ¸Đ²Đ¸. ĐŸÑ€ĐµĐ»Đ°ÑĐºĐ¾Đ¼ у Ñ€ĐµĐ¶Đ¸Đ¼ без Đ°Ñ€Ñ…Đ¸Đ²Đ¸Ñ€Đ°ÑĐ° Đ½ĐµÑ›ĐµÑ‚Đµ ÑĐ°ĐºÑ€Đ¸Ñ‚Đ¸ Đ¿Ñ€ĐµĐ³Đ»ĐµĐ´Đ°Ñе Đ¾Đ´ Đ¿Đ¾ÑĐ»Đ¾Đ´Đ°Đ²Ñ†Đ°, Đ¸Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ¿Ñ€Đ¾Đ²Đ°Ñ˜Đ´ĐµÑ€Đ° или Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đ° ĐºĐ¾Ñ˜Đµ Đ¿Đ¾ÑĐµÑ›ÑƒÑ˜ĐµÑ‚Đµ.</translation>
<translation id="7887683347370398519">ĐŸÑ€Đ¾Đ²ĐµÑ€Đ¸Ñ‚Đµ CVC и Đ¿Đ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾</translation>
<translation id="7894616681410591072">Đ£Đ¿Ñ! ĐŸĐ¾Ñ‚Ñ€ĐµĐ±Đ½Đ° Đ²Đ°Đ¼ Ñ˜Đµ Đ´Đ¾Đ·Đ²Đ¾Đ»Đ° ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸ĐºĐ° <ph name="NAME" /> Đ´Đ° биÑÑ‚Đµ Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿Đ¸Đ»Đ¸ Đ¾Đ²Đ¾Ñ˜ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ¸.</translation>
-<translation id="790025292736025802">AĐ´Ñ€ĐµÑĐ° <ph name="URL" /> Đ½Đ¸Ñ˜Đµ Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ½Đ°</translation>
<translation id="7912024687060120840">Đ£ Đ´Đ¸Ñ€ĐµĐºÑ‚Đ¾Ñ€Đ¸Ñ˜ÑƒĐ¼Ñƒ:</translation>
<translation id="7920092496846849526">ĐŸĐ¸Ñ‚Đ°Đ¾/ла Ñи Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™Đ° Đ´Đ° ли ÑĐ¼ĐµÑˆ Đ´Đ° Đ¿Đ¾ÑĐµÑ‚Đ¸Ñˆ Đ¾Đ²Ñƒ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -590,11 +625,12 @@
<translation id="7962083544045318153">Đ˜Đ” Đ¾Ñ‚ĐºĐ°Đ·Đ¸Đ²Đ°ÑĐ° <ph name="CRASH_LOCAL_ID" /></translation>
<translation id="7983301409776629893">Đ£Đ²ĐµĐº Đ¿Ñ€ĐµĐ²Đ¾Đ´Đ¸ ÑĐ° Ñ˜ĐµĐ·Đ¸ĐºĐ°: <ph name="ORIGINAL_LANGUAGE" /> Đ½Đ° <ph name="TARGET_LANGUAGE" /></translation>
<translation id="7995512525968007366">ĐĐ¸Ñ˜Đµ Đ½Đ°Đ²ĐµĐ´ĐµĐ½Đ¾</translation>
-<translation id="8012647001091218357">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµĐ¼Đ¾ Đ´Đ° ĐºĐ¾Đ½Ñ‚Đ°ĐºÑ‚Đ¸Ñ€Đ°Đ¼Đ¾ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™Đµ. ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜ Đ¿Đ¾Đ½Đ¾Đ²Đ¾.</translation>
+<translation id="8012647001091218357">Đ¢Ñ€ĐµĐ½ÑƒÑ‚Đ½Đ¾ Đ½Đµ Đ¼Đ¾Đ¶ĐµĐ¼Đ¾ Đ´Đ° ĐºĐ¾Đ½Ñ‚Đ°ĐºÑ‚Đ¸Ñ€Đ°Đ¼Đ¾ Ñ€Đ¾Đ´Đ¸Ñ‚ĐµÑ™Đµ. ĐŸÑ€Đ¾Đ±Đ°Ñ˜ Đ¿Đ¾Đ½Đ¾Đ²Đ¾.</translation>
<translation id="8034522405403831421">ĐˆĐµĐ·Đ¸Đº Đ¾Đ²Đµ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ Ñ˜Đµ <ph name="SOURCE_LANGUAGE" />. Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° Ñ˜Đµ Đ¿Ñ€ĐµĐ²ĐµĐ´ĐµÑ‚Đµ Đ½Đ° <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">ĐĐ¸Ñ˜Đµ Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ½ Đ½Đ¸Ñ˜ĐµĐ´Đ°Đ½ ÑƒĐ½Đ¾Ñ Ñƒ иÑÑ‚Đ¾Ñ€Đ¸Ñ˜Đ¸.</translation>
<translation id="8088680233425245692">ĐŸÑ€ĐµĐ³Đ»ĐµĐ´Đ°Ñе Ñ‡Đ»Đ°Đ½ĐºĐ° Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ»Đ¾.</translation>
+<translation id="8089520772729574115">Đ¼Đ°Ñе Đ¾Đ´ 1 MB</translation>
<translation id="8091372947890762290">ĐĐºÑ‚Đ¸Đ²Đ°Ñ†Đ¸Ñ˜Đ° Ñ˜Đµ Đ½Đ° Ñ‡ĐµĐºĐ°Ñу Đ½Đ° ÑĐµÑ€Đ²ĐµÑ€Ñƒ</translation>
+<translation id="8129262335948759431">Đ½ĐµĐ¿Đ¾Đ·Đ½Đ°Ñ‚Đ° ĐºĐ¾Đ»Đ¸Ñ‡Đ¸Đ½Đ°</translation>
<translation id="8131740175452115882">ĐŸĐ¾Ñ‚Đ²Ñ€Đ´Đ¸</translation>
<translation id="8134994873729925007">ĐиÑĐ¼Đ¾ уÑĐ¿ĐµĐ»Đ¸ Đ´Đ° Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ¼Đ¾ <ph name="BEGIN_ABBR" />DNS Đ°Đ´Ñ€ĐµÑу<ph name="END_ABBR" /> ÑĐµÑ€Đ²ĐµÑ€Đ° Ñ…Đ¾ÑÑ‚Đ° <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Đ Đ°Ñ‡ÑƒĐ½Đ°Ñ€ Ñ˜Đµ Đ¿Ñ€ĐµÑˆĐ°Đ¾ у Ñ€ĐµĐ¶Đ¸Đ¼ ÑĐ¿Đ°Đ²Đ°ÑĐ°.</translation>
@@ -603,6 +639,7 @@
<translation id="8201077131113104583">ĐĐµĐ²Đ°Đ¶ĐµÑ›Đ¸ URL Đ·Đ° Đ°Đ¶ÑƒÑ€Đ¸Ñ€Đ°Ñе Đ·Đ° Đ´Đ¾Đ´Đ°Ñ‚Đ°Đº ÑĐ° Đ˜Đ”-Đ¾Đ¼ â€<ph name="EXTENSION_ID" />“.</translation>
<translation id="8218327578424803826">Đ”Đ¾Đ´ĐµÑ™ĐµĐ½Đ° Đ»Đ¾ĐºĐ°Ñ†Đ¸Ñ˜Đ°:</translation>
<translation id="8225771182978767009">ĐÑĐ¾Đ±Đ° ĐºĐ¾Ñ˜Đ° Ñ˜Đµ Đ¿Đ¾Đ´ĐµÑила Đ¾Đ²Đ°Ñ˜ Ñ€Đ°Ñ‡ÑƒĐ½Đ°Ñ€ Ñ˜Đµ Đ¾Đ´Đ»ÑƒÑ‡Đ¸Đ»Đ° Đ´Đ° Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ° Đ¾Đ²Đ°Ñ˜ ÑĐ°Ñ˜Ñ‚.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Đ¡Ñ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° ĐºĐ¾Ñ˜Ñƒ Ñ‚Ñ€Đ°Đ¶Đ¸Ñ‚Đµ ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸Đ»Đ° Ñ˜Đµ Đ¸Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Đ¸Ñ˜Đµ ĐºĐ¾Ñ˜Đµ ÑÑ‚Đµ ÑƒĐ½ĐµĐ»Đ¸. ĐŸĐ¾Đ²Ñ€Đ°Ñ‚Đ°Đº Đ½Đ° ту ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Ñƒ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¿Ñ€Đ¾ÑƒĐ·Ñ€Đ¾ĐºÑƒÑ˜Đµ Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ½Ñƒ Đ¿Đ¾Đ½Đ°Đ²Ñ™Đ°ÑĐ° Ñ€Đ°Đ´Ñи ĐºĐ¾Ñ˜Đµ ÑÑ‚Đµ Đ¸Đ·Đ²Ñ€ÑˆĐ¸Đ»Đ¸. Đ–ĐµĐ»Đ¸Ñ‚Đµ ли Đ´Đ° Đ½Đ°ÑÑ‚Đ°Đ²Đ¸Ñ‚Đµ?</translation>
<translation id="8249320324621329438">ĐŸĐ¾ÑледÑе ÑƒÑ‡Đ¸Ñ‚Đ°Đ½Đ¾:</translation>
<translation id="8261506727792406068">Đ˜Đ·Đ±Ñ€Đ¸ÑˆĐ¸</translation>
@@ -615,12 +652,17 @@
<translation id="8349305172487531364">Đ¢Ñ€Đ°ĐºĐ° ÑĐ° Đ¾Đ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡Đ¸Đ¼Đ°</translation>
<translation id="8363502534493474904">Đ´Đ° иÑĐºÑ™ÑƒÑ‡Đ¸Ñ‚Đµ Ñ€ĐµĐ¶Đ¸Đ¼ Ñ€Đ°Đ´Đ° у Đ°Đ²Đ¸Đ¾Đ½Ñƒ</translation>
<translation id="8364627913115013041">ĐĐ¸Ñ˜Đµ Đ¿Đ¾Đ´ĐµÑˆĐµĐ½Đ¾.</translation>
+<translation id="8380941800586852976">ĐĐ¿Đ°ÑĐ½Đ¾</translation>
<translation id="8412145213513410671">ĐÑ‚ĐºĐ°Đ·Đ¸Đ²Đ°ÑĐ° (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">ĐŸĐ¾Ñ‚Ñ€ĐµĐ±Đ½Đ¾ Ñ˜Đµ Đ´Đ° Đ´Đ²Đ°Đ¿ÑƒÑ‚ ÑƒĐ½ĐµÑĐµÑ‚Đµ иÑту Đ¿Ñ€Đ¸ÑÑ‚ÑƒĐ¿Đ½Ñƒ Ñ„Ñ€Đ°Đ·Ñƒ.</translation>
<translation id="8428213095426709021">ĐŸĐ¾Đ´ĐµÑˆĐ°Đ²Đ°ÑĐ°</translation>
+<translation id="8433057134996913067">ĐĐ²Đ°ĐºĐ¾ Ñ›ĐµÑ‚Đµ Ñе Đ¾Đ´Ñ˜Đ°Đ²Đ¸Ñ‚Đ¸ ÑĐ° Đ²ĐµÑ›Đ¸Đ½Đµ Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đ°.</translation>
<translation id="8437238597147034694">&amp;ĐĐ¿Đ¾Đ·Đ¾Đ²Đ¸ Đ¿Ñ€ĐµĐ¼ĐµÑˆÑ‚Đ°Ñе</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ° ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đ°}one{# ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ° ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đ°}few{# ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đµ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ}other{# ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ¸Ñ… ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đ°}}</translation>
+<translation id="8483780878231876732">Да биÑÑ‚Đµ ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¸Đ»Đ¸ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ ÑĐ° Google Đ½Đ°Đ»Đ¾Đ³Đ°, Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Đ¸Ñ‚Đµ Ñе у Chrome</translation>
<translation id="8488350697529856933">ĐĐ´Đ½Đ¾Ñе Ñе Đ½Đ°</translation>
<translation id="8498891568109133222">ĐĐ´Đ³Đ¾Đ²Đ¾Ñ€ Ñ…Đ¾ÑÑ‚Đ° <ph name="HOST_NAME" /> Ñ˜Đµ Ñ‚Ñ€Đ°Ñ˜Đ°Đ¾ Đ¿Ñ€ĐµĐ´ÑƒĐ³Đ¾.</translation>
+<translation id="852346902619691059">ĐĐ²Đ°Ñ˜ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ´Đ¾ĐºĐ°Đ¶Đµ Đ´Đ° Ñ˜Đµ <ph name="DOMAIN" />; Đ¾Đ¿ĐµÑ€Đ°Ñ‚Đ¸Đ²Đ½Đ¸ ÑиÑÑ‚ĐµĐ¼ Đ²Đ°ÑˆĐµĐ³ ÑƒÑ€ĐµÑ’Đ°Ñ˜Đ° Đ½ĐµĐ¼Đ° Đ¿Đ¾Đ²ĐµÑ€ĐµÑĐ° у ÑĐµĐ³Đ¾Đ² Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¾ÑĐ½Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚. Đ£Đ·Ñ€Đ¾Đº Ñ‚Đ¾Đ¼Đµ Ñ˜Đµ Đ¼Đ¾Đ¶Đ´Đ° Đ¿Đ¾Đ³Ñ€ĐµÑˆĐ½Đ° ĐºĐ¾Đ½Ñ„Đ¸Đ³ÑƒÑ€Đ°Ñ†Đ¸Ñ˜Đ° или Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ ĐºĐ¾Ñ˜Đ¸ Ñ˜Đµ Đ¿Ñ€ĐµĐºĐ¸Đ½ÑƒĐ¾ Đ²ĐµĐ·Ñƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ¡Đ°Đ·Đ½Đ°Ñ˜Ñ‚Đµ Đ²Đ¸ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Google Payments Đ½Đµ Đ¿Đ¾Đ´Ñ€Đ¶Đ°Đ²Đ° Đ¾Đ²Đ°Ñ˜ Ñ‚Đ¸Đ¿ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Đµ. Đ˜Đ·Đ°Đ±ĐµÑ€Đ¸Ñ‚Đµ Đ½ĐµĐºÑƒ Đ´Ñ€ÑƒĐ³Ñƒ ĐºĐ°Ñ€Ñ‚Đ¸Ñ†Ñƒ.</translation>
<translation id="8550022383519221471">Đ£ÑĐ»ÑƒĐ³Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ˜Đµ Đ½Đ¸Ñ˜Đµ Đ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Đ° Đ·Đ° Đ²Đ°Ñˆ Đ´Đ¾Đ¼ĐµĐ½.</translation>
<translation id="8553075262323480129">ĐŸÑ€ĐµĐ²Đ¾Đ´ Đ½Đ¸Ñ˜Đµ уÑĐ¿ĐµĐ¾ Ñ˜ĐµÑ€ Ñ˜ĐµĐ·Đ¸Đº ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ Đ½Đ¸Ñ˜Đµ Đ¼Đ¾Đ³Đ°Đ¾ Đ´Đ° Đ±ÑƒĐ´Đµ ÑƒÑ‚Đ²Ñ€Ñ’ĐµĐ½.</translation>
@@ -632,15 +674,12 @@
<translation id="8647750283161643317">Đ’Ñ€Đ°Ñ‚Đ¸ ÑĐ²Đµ Đ½Đ° Đ¿Đ¾Đ´Ñ€Đ°Đ·ÑƒĐ¼ĐµĐ²Đ°Đ½Đ¾</translation>
<translation id="8680787084697685621">Đ”ĐµÑ‚Đ°Ñ™Đ¸ Đ·Đ° Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Ñ™Đ¸Đ²Đ°Ñе Đ½Đ° Đ½Đ°Đ»Đ¾Đ³ Ñу Đ·Đ°ÑÑ‚Đ°Ñ€ĐµĐ»Đ¸.</translation>
<translation id="8703575177326907206">Đ’Đ°ÑˆĐ° Đ²ĐµĐ·Đ° ÑĐ° Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" /> Đ½Đ¸Ñ˜Đµ ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ°.</translation>
-<translation id="8713130696108419660">ĐеиÑĐ¿Ñ€Đ°Đ²Đ°Đ½ Đ¿Đ¾Ñ‚Đ¿Đ¸Ñ Đ¸Đ½Đ¸Ñ†Đ¸Ñ˜Đ°Đ»Đ¸Đ¼Đ°</translation>
-<translation id="8725066075913043281">ĐŸĐ¾ĐºÑƒÑˆĐ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾</translation>
+<translation id="8725066075913043281">ĐŸÑ€Đ¾Đ±Đ°Ñ˜Ñ‚Đµ Đ¿Đ¾Đ½Đ¾Đ²Đ¾</translation>
<translation id="8728672262656704056">ĐŸÑ€ĐµÑˆĐ»Đ¸ ÑÑ‚Đµ у Ñ€ĐµĐ¶Đ¸Đ¼ Без Đ°Ñ€Ñ…Đ¸Đ²Đ¸Ñ€Đ°ÑĐ°</translation>
<translation id="8730621377337864115">Đ“Đ¾Ñ‚Đ¾Đ²Đ¾</translation>
<translation id="8738058698779197622">Да биÑÑ‚Đµ уÑĐ¿Đ¾ÑÑ‚Đ°Đ²Đ¸Đ»Đ¸ Đ±ĐµĐ·Đ±ĐµĐ´Đ½Ñƒ Đ²ĐµĐ·Ñƒ, ÑĐ°Ñ‚ Đ½Đ° ÑƒÑ€ĐµÑ’Đ°Ñ˜Ñƒ Đ¼Đ¾Ñ€Đ° Đ´Đ° Đ±ÑƒĐ´Đµ Ñ‚Đ°Ñ‡Đ°Đ½. Đ¢Đ¾ Ñ˜Đµ Đ·Đ°Ñ‚Đ¾ ÑˆÑ‚Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ¸ ĐºĐ¾Ñ˜Đµ Đ²ĐµĐ±-ÑĐ°Ñ˜Ñ‚Đ¾Đ²Đ¸ ĐºĐ¾Ñ€Đ¸ÑÑ‚Đµ Đ·Đ° Đ¸Đ´ĐµĐ½Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ†Đ¸Ñ˜Ñƒ Đ²Đ°Đ¶Đµ ÑĐ°Đ¼Đ¾ Đ¾Đ´Ñ€ĐµÑ’ĐµĐ½Đ¸ Đ²Ñ€ĐµĐ¼ĐµĐ½ÑĐºĐ¸ Đ¿ĐµÑ€Đ¸Đ¾Đ´. ĐŸĐ¾ÑˆÑ‚Đ¾ ÑĐ°Ñ‚ Đ½Đ° Đ²Đ°ÑˆĐµĐ¼ ÑƒÑ€ĐµÑ’Đ°Ñ˜Ñƒ Đ½Đ¸Ñ˜Đµ Ñ‚Đ°Ñ‡Đ°Đ½, Chromium Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ²ĐµÑ€Đ¸Ñ„Đ¸ĐºÑƒÑ˜Đµ Đ¾Đ²Đµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đµ.</translation>
<translation id="8740359287975076522">ĐиÑĐ¼Đ¾ уÑĐ¿ĐµĐ»Đ¸ Đ´Đ° Đ¿Ñ€Đ¾Đ½Đ°Ñ’ĐµĐ¼Đ¾ &lt;abbr id="dnsDefinition"&gt;DNS Đ°Đ´Ñ€ĐµÑу&lt;/abbr&gt; Ñ…Đ¾ÑÑ‚Đ° <ph name="HOST_NAME" />. ĐŸĐ¾ĐºÑƒÑˆĐ°Đ²Đ°Đ¼Đ¾ Đ´Đ° ÑƒÑ‚Đ²Ñ€Đ´Đ¸Đ¼Đ¾ у Ñ‡ĐµĐ¼Ñƒ Ñ˜Đµ Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼.</translation>
-<translation id="8741995161408053644">Google Đ½Đ°Đ»Đ¾Đ³ Đ¸Đ¼Đ° Đ´Ñ€ÑƒĐ³Đµ Đ¾Đ±Đ»Đ¸ĐºĐµ иÑÑ‚Đ¾Ñ€Đ¸Ñ˜Đµ Đ¿Ñ€ĐµĐ³Đ»ĐµĐ´Đ°ÑĐ° Đ½Đ° <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;ĐŸĐ¾Đ½Đ¾Đ²Đ¸ Đ±Ñ€Đ¸ÑĐ°Ñе</translation>
-<translation id="8790687370365610530">Да биÑÑ‚Đµ Đ´Đ¾Đ±Đ¸Ñ˜Đ°Đ»Đ¸ Đ¿ĐµÑ€ÑĐ¾Đ½Đ°Đ»Đ¸Đ·Đ¾Đ²Đ°Đ½Đ¸ ÑĐ°Đ´Ñ€Đ¶Đ°Ñ˜ ĐºĐ¾Ñ˜Đ¸ Đ¿Ñ€ĐµĐ´Đ»Đ°Đ¶Đµ Google, ÑƒĐºÑ™ÑƒÑ‡Đ¸Ñ‚Đµ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Đ¸Đ·Đ°Ñ†Đ¸Ñ˜Ñƒ иÑÑ‚Đ¾Ñ€Đ¸Ñ˜Đµ.</translation>
<translation id="8798099450830957504">ĐŸĐ¾Đ´Ñ€Đ°Đ·ÑƒĐ¼ĐµĐ²Đ°Đ½Đ¾</translation>
<translation id="8804164990146287819">ĐŸĐ¾Đ»Đ¸Ñ‚Đ¸ĐºĐ° Đ¿Ñ€Đ¸Đ²Đ°Ñ‚Đ½Đ¾ÑÑ‚Đ¸</translation>
<translation id="8820817407110198400">ĐĐ±ĐµĐ»ĐµĐ¶Đ¸Đ²Đ°Ñ‡Đ¸</translation>
@@ -662,13 +701,11 @@
<translation id="8971063699422889582">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Ñ˜Đµ иÑÑ‚ĐµĐºĐ°Đ¾.</translation>
<translation id="8987927404178983737">ĐœĐµÑĐµÑ†</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Đ¡ĐµÑ€Đ²ĐµÑ€ Ñ˜Đµ Đ¿Ñ€Đ¸ĐºĐ°Đ·Đ°Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚ ĐºĐ¾Ñ˜Đ¸ Đ½Đ¸Ñ˜Đµ Ñ˜Đ°Đ²Đ½Đ¾ Đ¾Ñ‚ĐºÑ€Đ¸Đ²ĐµĐ½ Đ¿Đ¾Đ¼Đ¾Ñ›Ñƒ ÑĐ¼ĐµÑ€Đ½Đ¸Ñ†Đ° Đ¢Ñ€Đ°Đ½ÑĐ¿Đ°Ñ€ĐµĐ½Ñ‚Đ½Đ¾ÑÑ‚ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đ°. Đ¢Đ¾ Ñ˜Đµ Đ¾Đ±Đ°Đ²ĐµĐ·Đ½Đ¾ Đ·Đ° Đ½ĐµĐºĐµ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚Đµ Đ´Đ° биÑĐ¼Đ¾ Ñе ÑƒĐ²ĐµÑ€Đ¸Đ»Đ¸ Đ´Đ° Ñу Đ¿Đ¾ÑƒĐ·Đ´Đ°Đ½Đ¸ и Đ´Đ° ÑˆÑ‚Đ¸Ñ‚Đµ Đ¾Đ´ Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡Đ°.</translation>
<translation id="9001074447101275817">ĐŸÑ€Đ¾ĐºÑи <ph name="DOMAIN" /> Đ·Đ°Ñ…Ñ‚ĐµĐ²Đ° ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸Ñ‡ĐºĐ¾ Đ¸Đ¼Đµ и Đ»Đ¾Đ·Đ¸Đ½ĐºÑƒ.</translation>
<translation id="901974403500617787">ĐĐ·Đ½Đ°ĐºĐµ ĐºĐ¾Ñ˜Đµ Ñе Đ¿Ñ€Đ¸Đ¼ĐµÑују у Ñ†ĐµĐ»Đ¾Đ¼ ÑиÑÑ‚ĐµĐ¼Ñƒ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¿Đ¾Đ´ĐµÑи ÑĐ°Đ¼Đ¾ Đ²Đ»Đ°ÑĐ½Đ¸Đº: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">ĐĐ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Ñ˜Đµ Đ¿Ñ€ĐµĐ²ĐµĐ´ĐµĐ½Đ° Đ½Đ° <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">ĐĐ¾Ñ€Đ¸ÑÑ‚Đ¸Ñ‚Đµ уÑĐ»ÑƒĐ³Ñƒ Đ¿Ñ€ĐµĐ´Đ²Đ¸Ñ’Đ°ÑĐ° Đ´Đ° биÑÑ‚Đµ Đ±Ñ€Đ¶Đµ ÑƒÑ‡Đ¸Ñ‚Đ°Đ²Đ°Đ»Đ¸ ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ</translation>
<translation id="9039213469156557790">ĐŸĐ¾Ñ€ĐµĐ´ Ñ‚Đ¾Đ³Đ°, Đ¾Đ²Đ° ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° ÑĐ°Đ´Ñ€Đ¶Đ¸ и Đ´Ñ€ÑƒĐ³Đµ Ñ€ĐµÑурÑе ĐºĐ¾Ñ˜Đ¸ Đ½Đ¸Ñу Đ±ĐµĐ·Đ±ĐµĐ´Đ½Đ¸. ĐĐ²Đµ Ñ€ĐµÑурÑе Đ¼Đ¾Đ³Ñƒ Đ´Đ° Đ²Đ¸Đ´Đµ и Đ´Ñ€ÑƒĐ³Đ¸ Đ´Đ¾Đº Ñу у Đ¿Ñ€Đ¾Đ»Đ°Đ·Ñƒ и Đ½Đ°Đ¿Đ°Đ´Đ°Ñ‡ Đ¼Đ¾Đ¶Đµ Đ´Đ° Đ¸Ñ… Đ¸Đ·Đ¼ĐµĐ½Đ¸ ĐºĐ°ĐºĐ¾ би Đ¿Ñ€Đ¾Đ¼ĐµĐ½Đ¸Đ¾ Đ¿Đ¾Đ½Đ°ÑˆĐ°Ñе ÑÑ‚Ñ€Đ°Đ½Đ¸Ñ†Đµ.</translation>
-<translation id="9049981332609050619">ĐŸĐ¾ĐºÑƒÑˆĐ°Đ»Đ¸ ÑÑ‚Đµ Đ´Đ° Đ´Đ¾Ñ’ĐµÑ‚Đµ Đ´Đ¾ Đ´Đ¾Đ¼ĐµĐ½Đ° <ph name="DOMAIN" />, али ÑĐµÑ€Đ²ĐµÑ€ Ñ˜Đµ Đ¿Đ¾ÑĐ»Đ°Đ¾ Đ½ĐµĐ²Đ°Đ¶ĐµÑ›Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Đ¸ĐºĐ°Ñ‚.</translation>
<translation id="9050666287014529139">ĐŸÑ€Đ¸ÑÑ‚ÑƒĐ¿Đ½Đ° Ñ„Ñ€Đ°Đ·Đ°</translation>
<translation id="9065203028668620118">Đ˜Đ·Đ¼ĐµĐ½Đ¸</translation>
<translation id="9092364396508701805">Đ¡Ñ‚Ñ€Đ°Đ½Đ¸Ñ†Đ° Ñ…Đ¾ÑÑ‚Đ° <ph name="HOST_NAME" /> Đ½Đµ Ñ„ÑƒĐ½ĐºÑ†Đ¸Đ¾Đ½Đ¸ÑˆĐµ</translation>
diff --git a/chromium/components/strings/components_strings_sv.xtb b/chromium/components/strings/components_strings_sv.xtb
index 0000288bce2..9877fa65c05 100644
--- a/chromium/components/strings/components_strings_sv.xtb
+++ b/chromium/components/strings/components_strings_sv.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sv">
+<translation id="1008557486741366299">Inte nu</translation>
<translation id="1015730422737071372">Ange ytterligare information</translation>
<translation id="1032854598605920125">Rotera medurs</translation>
<translation id="1038842779957582377">okänt namn</translation>
+<translation id="1053591932240354961">Det gĂ¥r inte att besöka <ph name="SITE" /> just nu eftersom webbplatsen skickade förvrängda användaruppgifter som Google Chrome inte kan behandla. Nätverksfel och attacker är vanligtvis tillfälliga, sĂ¥ sidan fungerar troligen senare. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Ångra Lägg till</translation>
<translation id="10614374240317010">Aldrig sparad</translation>
-<translation id="1064422015032085147">Eventuellt pĂ¥gĂ¥r underhĂ¥ll pĂ¥ servern som webbsidan finns pĂ¥, eller sĂ¥ kan servern vara överbelastad.
- För att undvika överbelastning och för att förhindra att situationen förvärras,
- har begäranden till den här webbadressen stoppats tillfälligt.</translation>
<translation id="106701514854093668">Bokmärken pĂ¥ skrivbordet</translation>
<translation id="1080116354587839789">Anpassa till fönstrets bredd</translation>
+<translation id="1103124106085518534">Klar för tillfället</translation>
<translation id="1103523840287552314">Översätt alltid <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Om alternativet är markerat sparas en kopia av kortet pĂ¥ enheten sĂ¥ att det gĂ¥r snabbare att fylla i formulär.</translation>
+<translation id="1111153019813902504">Nya bokmärken</translation>
<translation id="1113869188872983271">&amp;Ă…ngra Ă„ndra ordning</translation>
+<translation id="1126551341858583091">Storleken pĂ¥ det lokala lagringsutrymmet är <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cacheminnet för policyn är OK</translation>
<translation id="113188000913989374"><ph name="SITE" /> säger:</translation>
<translation id="1132774398110320017">Inställningar för Autofyll i Chrome …</translation>
-<translation id="1150979032973867961">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom datorns operativsystem inte litar pĂ¥ dess säkerhetscertifikat. Detta kan orsakas av en felaktig konfigurering eller att nĂ¥gon spärrar anslutningen.</translation>
<translation id="1152921474424827756">Ă–ppna en <ph name="BEGIN_LINK" />cachad kopia<ph name="END_LINK" /> av <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> stängde oväntat ner anslutningen.</translation>
<translation id="1161325031994447685">Ă¥teransluta till Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Ta bort</translation>
<translation id="1201402288615127009">Nästa</translation>
<translation id="1201895884277373915">Mer frĂ¥n den här webbplatsen</translation>
-<translation id="121201262018556460">Du försökte öppna <ph name="DOMAIN" />, men servern visade ett certifikat som signerats med en svag nyckel. Det innebär att den privata nyckeln som servern visar kan vara en förfalskning och att servern kanske inte är den server du tror (du kanske kommunicerar med en skadlig server).</translation>
+<translation id="1206967143813997005">Felaktig första signatur</translation>
+<translation id="1209206284964581585">Dölj för tillfället</translation>
<translation id="1219129156119358924">Systemsäkerhet</translation>
<translation id="1227224963052638717">Okänd policy.</translation>
<translation id="1227633850867390598">Dölj värde</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Ja</translation>
<translation id="1430915738399379752">Skriv ut</translation>
<translation id="1442912890475371290">Blockerade ett försök <ph name="BEGIN_LINK" />att besöka en sida pĂ¥ <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Det gĂ¥r inte att besöka <ph name="SITE" /> just nu pĂ¥ grund av att fäste av certifikat förekommer pĂ¥ webbplatsen. Nätverksfel och attacker är vanligtvis tillfälliga, sĂ¥ den här sidan fungerar troligen senare. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Visa en sparad kopia av sidan (en som vi vet är inaktuell).</translation>
<translation id="1519264250979466059">Programversionsdatum</translation>
<translation id="1549470594296187301">JavaScript mĂ¥ste aktiveras för att du ska kunna använda den här funktionen.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Nätverkskonfigurationen är ogiltig och kan inte importeras.</translation>
<translation id="1644574205037202324">Historik</translation>
<translation id="1645368109819982629">Det finns inget stöd för protokollet</translation>
-<translation id="1655462015569774233">{1,plural, =1{Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat gick ut i gĂ¥r. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. Dagens datum är <ph name="CURRENT_DATE" /> enligt datorklockan. GĂ¥r den rätt? I annat fall bör du ställa om datorklockan och sedan uppdatera sidan.}other{Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat gick ut för # dagar sedan. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. Dagens datum är <ph name="CURRENT_DATE" /> enligt datorklockan. GĂ¥r den rätt? I annat fall bör du ställa om datorklockan och sedan uppdatera sidan.}}</translation>
<translation id="1676269943528358898">PĂ¥ <ph name="SITE" /> används vanligtvis kryptering (SSL) för att skydda din information. När Chrome försökte ansluta till <ph name="SITE" /> den här gĂ¥ngen skickade webbplatsen tillbaka ovanliga och felaktiga uppgifter. SĂ¥dant kan hända när en angripare utger sig för att vara <ph name="SITE" /> eller när anslutningen har avbrutits av en Wi-Fi-inloggningsskärm. Din information är fortfarande säker eftersom Chrome avbröt anslutningen innan nĂ¥gon data utbyttes.</translation>
<translation id="168841957122794586">Servercertifikatet innehĂ¥ller en svag kryptografisk nyckel.</translation>
<translation id="1701955595840307032">FĂ¥ förslag pĂ¥ innehĂ¥ll</translation>
-<translation id="1706954506755087368">{1,plural, =1{Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat uppges börja gälla i morgon. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad.}other{Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat uppges börja gälla om # dagar. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Kontakta systemadministratören.</translation>
<translation id="17513872634828108">Ă–ppna flikar</translation>
<translation id="1753706481035618306">Sidnummer</translation>
-<translation id="1761412452051366565">Aktivera synkronisering om du vill fĂ¥ förslag pĂ¥ anpassat innehĂ¥ll frĂ¥n Google.</translation>
-<translation id="1763864636252898013">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom enhetens operativsystem inte litar pĂ¥ dess säkerhetscertifikat. Detta kan orsakas av en felaktig konfigurering eller att nĂ¥gon spärrar anslutningen.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Testa att köra nätverksdiagnostik för Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Uppdatera lösenfrasen för synkroniseringen.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Här visas dina senast besökta bokmärken.</translation>
<translation id="1821930232296380041">Begäran eller parametrar i begäran var ogiltiga</translation>
<translation id="1838667051080421715">Du tittar pĂ¥ källkoden till en webbsida.</translation>
<translation id="1871208020102129563">Proxyn är inställd pĂ¥ att använda fasta proxyservrar, inte en webbadress med PAC-skript.</translation>
<translation id="1883255238294161206">Komprimera lista</translation>
<translation id="1898423065542865115">Filtrering</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> godkände inte inloggningscertifikatet eller sĂ¥ har inloggningscertifikatet upphört att gälla.</translation>
<translation id="194030505837763158">Ă–ppna <ph name="LINK" /></translation>
<translation id="1962204205936693436">Bokmärken pĂ¥ <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Serieproduktionsfel</translation>
<translation id="1974060860693918893">Avancerat</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{och 1 till}other{och # till}}</translation>
<translation id="2025186561304664664">Proxyn är inställd pĂ¥ automatisk konfiguration.</translation>
<translation id="2030481566774242610">Menade du <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Det här meddelandet visas eftersom dina föräldrar mĂ¥ste godkänna nya webbplatser första gĂ¥ngen du besöker dem.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />kontrollera proxyn och brandväggen<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ZIP</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 förslag}other{# förslag}}</translation>
<translation id="2065985942032347596">Verifiering krävs</translation>
<translation id="2079545284768500474">Ă…ngra</translation>
<translation id="20817612488360358">Datorns proxyinställningar är inställda pĂ¥ att användas, men det finns ocksĂ¥ en explicit proxykonfiguration.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Redigera bokmärke</translation>
<translation id="2166049586286450108">Fullständig administrativ Ă¥tkomst</translation>
<translation id="2166378884831602661">Webbplatsen kan inte tillhandahĂ¥lla en säker anslutning</translation>
-<translation id="2171101176734966184">Du försökte öppna <ph name="DOMAIN" />, men servern visade ett certifikat som signerats med en svag signaturalgoritm. Det innebär att säkerhetsuppgifterna som servern visar kan vara en förfalskning och att servern kanske inte är den server du tror (du kanske kommunicerar med en skadlig server).</translation>
<translation id="2181821976797666341">Policyer</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adress}other{# adresser}}</translation>
<translation id="2212735316055980242">Policyn hittades inte</translation>
<translation id="2213606439339815911">Hämtar poster …</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> är inte tillgängligt</translation>
<translation id="2230458221926704099">Åtgärda anslutningsproblemet med hjälp av <ph name="BEGIN_LINK" />diagnostiseringsappen<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Skicka nu</translation>
<translation id="225207911366869382">Värdet är inte längre giltigt för policyn.</translation>
<translation id="2262243747453050782">HTTP-fel</translation>
<translation id="2282872951544483773">Otillgängliga experiment</translation>
<translation id="2292556288342944218">Internetanslutningen har blockerats</translation>
<translation id="229702904922032456">Ett rotcertifikat eller indirekt certifikat har upphört att gälla.</translation>
<translation id="230155334948463882">Har du ett nytt kort?</translation>
+<translation id="2305919008529760154">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kan ha utfärdats utan behörighet. Detta kan orsakas av en felaktig konfigurering eller att nĂ¥gon spärrar anslutningen.. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> kräver användarnamn och lösenord.</translation>
+<translation id="2318774815570432836">Det gĂ¥r inte att besöka <ph name="SITE" /> just nu pĂ¥ grund av att HSTS används pĂ¥ webbplatsen. Nätverksfel och attacker är vanligtvis tillfälliga, sĂ¥ den här sidan fungerar troligen senare. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Ignorerade ogiltigt bokmärke vid index <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Övriga bokmärken</translation>
<translation id="2359808026110333948">Fortsätt</translation>
<translation id="2365563543831475020">Felrapport som skapades <ph name="CRASH_TIME" /> laddades inte upp</translation>
<translation id="2367567093518048410">NivĂ¥</translation>
+<translation id="2371153335857947666">{1,plural, =1{Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat gick ut i gĂ¥r. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. Dagens datum är <ph name="CURRENT_DATE" /> enligt datorklockan. GĂ¥r den rätt? I annat fall bör du ställa om datorklockan och sedan uppdatera sidan. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.}other{Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat gick ut för # dagar sedan. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. Dagens datum är <ph name="CURRENT_DATE" /> enligt datorklockan. GĂ¥r den rätt? I annat fall bör du ställa om datorklockan och sedan uppdatera sidan. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Det finns inga användargränssnittsalternativ</translation>
<translation id="2384307209577226199">Standardinställning i företaget</translation>
-<translation id="238526402387145295">Det gĂ¥r inte att besöka <ph name="SITE" /> just nu pĂ¥ grund av att <ph name="BEGIN_LINK" />HSTS används<ph name="END_LINK" /> pĂ¥ webbplatsen. Nätverksfel och attacker är vanligtvis tillfälliga sĂ¥ den här sidan fungerar troligen senare.</translation>
<translation id="2386255080630008482">Servercertifikatet har Ă¥terkallats.</translation>
<translation id="2392959068659972793">Visa policyer utan inställt värde</translation>
<translation id="2396249848217231973">&amp;Ă…ngra Ta bort</translation>
-<translation id="2413528052993050574">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kan ha Ă¥terkallats. Detta kan orsakas av en felaktig konfigurering eller att nĂ¥gon spärrar anslutningen.</translation>
<translation id="2455981314101692989">Webbsidan har inaktiverat Autofyll för det här formuläret.</translation>
+<translation id="2463739503403862330">Fyll i</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />att köra nätverksdiagnostik<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Ogiltig sökadress.</translation>
<translation id="2491120439723279231">Servercertifikatet innehĂ¥ller fel.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Skicka</translation>
<translation id="2674170444375937751">Vill du ta bort de här sidorna frĂ¥n historiken?</translation>
<translation id="2677748264148917807">Lämna</translation>
+<translation id="269990154133806163">Servern angav ett certifikat som inte har lämnats ut enligt policyn Certifikattransparens. Detta krävs för vissa certifikat för att säkerställa att de är tillförlitliga och skyddar mot hackare. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Värdet matchar inte formatet.</translation>
<translation id="2704951214193499422">Chromium kunde inte bekräfta kortet. Försök igen senare.</translation>
<translation id="2705137772291741111">Det gick inte att läsa den sparade (cachelagrade) kopian av webbplatsen.</translation>
<translation id="2709516037105925701">Autofyll</translation>
+<translation id="2712118517637785082">Du försökte öppna <ph name="DOMAIN" />, men servern angav ett certifikat som har Ă¥terkallats av utfärdaren. Det innebär att säkerhetsuppgifterna som servern anger inte är tillförlitliga. Du kanske kommunicerar med en angripare. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Begär behörighet</translation>
<translation id="2721148159707890343">Begäran genomfördes</translation>
<translation id="2728127805433021124">Serverns certifikat är signerat med en svag signaturalgoritm.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Adress- och sökfält</translation>
<translation id="2826760142808435982">Anslutningen är krypterad och verifieras med <ph name="CIPHER" /> och använder <ph name="KX" /> som nyckelutbytesmekanism.</translation>
<translation id="2835170189407361413">Rensa formuläret</translation>
-<translation id="2837049386027881519">Anslutningen var tvungen att Ă¥terupprättas via en äldre version av TLS- eller SSL-protokollet. Detta innebär vanligtvis att servern använder mycket gammal programvara och kanske har andra säkerhetsproblem.</translation>
<translation id="284702764277384724">Servercertifikatet pĂ¥ <ph name="HOST_NAME" /> verkar vara falskt.</translation>
<translation id="2889159643044928134">Läs inte in sidan igen</translation>
-<translation id="2896499918916051536">Det här pluginprogrammet stöds inte.</translation>
+<translation id="2900469785430194048">Minnet tog slut när den här webbsidan skulle visas i Google Chrome.</translation>
<translation id="2909946352844186028">En nätverksförändring upptäcktes.</translation>
-<translation id="2915500479781995473">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat har upphört att gälla. Detta kan bero pĂ¥ en felaktig inställning eller att en angripare har manipulerat anslutningen. Klockan pĂ¥ datorn är för närvarande inställd pĂ¥ <ph name="CURRENT_TIME" />. Stämmer det inte? Korrigera systemets klocka och uppdatera sedan sidan.</translation>
<translation id="2922350208395188000">Servercertifikatet kan inte kontrolleras.</translation>
-<translation id="2941952326391522266">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kommer frĂ¥n <ph name="DOMAIN2" />. Detta kan orsakas av en felaktig konfigurering eller att nĂ¥gon spärrar anslutningen.</translation>
<translation id="2948083400971632585">Du kan inaktivera alla proxyservrar som har konfigurerats för en anslutning frĂ¥n sidan Inställningar.</translation>
<translation id="2955913368246107853">Stäng sökfältet</translation>
<translation id="2958431318199492670">Nätverkskonfigurationen uppfyller inte ONC-standarden. Det kan hända att delar av konfigurationen inte kan importeras.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Felaktig policytyp</translation>
<translation id="3032412215588512954">Vill du läsa in den här webbplatsen igen?</translation>
<translation id="3037605927509011580">Oj, ett fel har uppstĂ¥tt!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{minst 1 objekt pĂ¥ synkroniserade enheter}=1{1 objekt (och fler pĂ¥ synkroniserade enheter)}other{# objekt (och fler pĂ¥ synkroniserade enheter)}}</translation>
<translation id="3041612393474885105">Certifikatinformation</translation>
<translation id="3063697135517575841">Det gick inte att bekräfta kortet. Försök igen senare.</translation>
<translation id="3093245981617870298">Du är offline.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Senaste</translation>
<translation id="3207960819495026254">Bokmärkt</translation>
-<translation id="3225919329040284222">Ett certifikat som inte överensstämmer med inbyggda förväntningar presenterades pĂ¥ servern. Förväntningarna gäller för webbplatser med hög säkerhet för att skydda dig.</translation>
<translation id="3226128629678568754">Om du pĂ¥ nytt vill skicka datan som behövs för att läsa in sidan trycker du pĂ¥ knappen Läs in igen.</translation>
<translation id="3228969707346345236">Det gick inte att översätta eftersom sidan redan är pĂ¥ <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Ange CVC-koden för <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Bokmärk sidan</translation>
<translation id="3270847123878663523">&amp;Ă…ngra Ă„ndra ordning</translation>
<translation id="3286538390144397061">Starta om nu</translation>
+<translation id="3303855915957856445">Inga sökresultat hittades</translation>
<translation id="3305707030755673451">Din data krypterades med din lösenfras för synkronisering den <ph name="TIME" />. Ange den om du vill starta synkroniseringen.</translation>
<translation id="333371639341676808">Förhindra att den här sidan öppnar ytterligare dialogrutor.</translation>
+<translation id="3338095232262050444">Säkert</translation>
<translation id="3340978935015468852">inställningar</translation>
<translation id="3345135638360864351">Det gick inte att skicka begäran om Ă¥tkomst till den här webbplatsen till <ph name="NAME" />. Försök igen.</translation>
<translation id="3355823806454867987">Ändra proxyinställningar...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Hämta intervall:</translation>
<translation id="3462200631372590220">Dölja avancerade uppgifter</translation>
<translation id="3479539252931486093">Var det här oväntat? <ph name="BEGIN_LINK" />Meddela oss<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Inte nu</translation>
<translation id="348000606199325318">Krasch-id <ph name="CRASH_LOCAL_ID" /> (server-id: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Vi kunde inte nĂ¥ din förälder just nu. Försök igen.</translation>
<translation id="3527085408025491307">Mapp</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Använd lösenord för:</translation>
<translation id="3549644494707163724">Kryptera alla synkroniserade data med en egen lösenfras</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> till ...</translation>
+<translation id="3555561725129903880">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kommer frĂ¥n <ph name="DOMAIN2" />. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Anslutningen är inte privat</translation>
<translation id="3583757800736429874">&amp;Gör om Flytta</translation>
<translation id="3586931643579894722">Dölj detaljerad information</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Visa värde</translation>
<translation id="3630155396527302611">Om den redan finns med pĂ¥ listan över program som har tillgĂ¥ng till nätverket
kan du prova att ta bort den frĂ¥n listan och sedan lägga till den igen.</translation>
+<translation id="3638794133396384728">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat har löpt ut. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. Datorklockan är för närvarande inställd pĂ¥ <ph name="CURRENT_TIME" />. GĂ¥r den rätt? I annat fall bör du ställa om datorklockan och sedan uppdatera sidan. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Dessa experimentella funktioner kan ändras, avbrytas eller försvinna när som helst. Vi lämnar inga som helst garantier om vad som kan ske om du aktiverar nĂ¥got av dessa experiment. Webbläsaren kanske t.o.m. gĂ¥r upp i rök. Skämt Ă¥sido, alla data i webbläsaren kan raderas och säkerheten och sekretessen kan äventyras pĂ¥ oväntade sätt. Experiment som du aktiverar kommer att aktiveras för alla som använder webbläsaren. Var försiktig.</translation>
<translation id="3650584904733503804">Valideringen har genomförts</translation>
<translation id="3655670868607891010">Om du ser detta ofta provar du <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Version</translation>
+<translation id="3678029195006412963">Begäran kunde inte signeras</translation>
<translation id="3681007416295224113">Certifikatinformation</translation>
<translation id="3693415264595406141">Lösenord:</translation>
+<translation id="3696411085566228381">ingen</translation>
<translation id="3700528541715530410">Du har tyvärr inte behörighet att öppna den här sidan.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Laddar...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">aktivera mobildata eller Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />kontrollera proxyn, brandväggen och DNS-konfigureringen<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Länk som du har kopierat</translation>
-<translation id="3744899669254331632">Du kan inte besöka <ph name="SITE" /> just nu eftersom webbplatsen skickade krypterade användaruppgifter som Chromium inte kan bearbeta. Nätverksfel och attacker är ofta tillfälliga, sĂ¥ sidan kommer förmodligen fungera senare.</translation>
<translation id="375403751935624634">Det gick inte att översätta pĂ¥ grund av ett serverfel.</translation>
<translation id="3759461132968374835">Inga krascher har rapporterats nyligen. Krascher som uppstod när kraschrapporteringen var inaktiverad visas inte här.</translation>
<translation id="3788090790273268753">Certifikatet för den här webbplatsen gĂ¥r ut 2016. Certifikatkedjan innehĂ¥ller ett certifikat som signerades med SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Motstridiga enhetsidentifierare</translation>
<translation id="3885155851504623709">Församling</translation>
<translation id="3901925938762663762">Kortet gäller inte längre</translation>
+<translation id="3910267023907260648">Du försökte öppna <ph name="DOMAIN" />, men servern angav ett certifikat som har signerats med en svag signaturalgoritm. Det innebär att säkerhetsuppgifterna som servern anger kan vara en förfalskning och att servern kanske inte är den server du tror (du kanske kommunicerar med en angripare). <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat uppges börja gälla i morgon. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.}other{Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat uppges börja gälla om # dagar. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Det gick inte att läsa in PDF-dokumentet</translation>
<translation id="3963721102035795474">Läsarläge</translation>
+<translation id="397105322502079400">Beräknar ...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> har blockerats</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 webbsida i närheten}other{# webbsidor i närheten}}</translation>
<translation id="4021036232240155012">DNS är en webbtjänst som översätter namnet pĂ¥ en webbplats till motsvarande internetadress.</translation>
<translation id="4030383055268325496">&amp;Ångra Lägg till</translation>
-<translation id="4032534284272647190">Ă…tkomst nekad till <ph name="URL" />.</translation>
<translation id="404928562651467259">VARNING</translation>
<translation id="4058922952496707368">Nyckel <ph name="SUBKEY" />: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Klienten och servern har inte stöd för en gemensam SSL-protokollversion eller chiffersvit.</translation>
<translation id="4079302484614802869">Proxykonfigurationen är inställd pĂ¥ att använda en webbadress med PAC-skript, inte fasta proxyservrar.</translation>
<translation id="4103249731201008433">Enhetens serienummer är ogiltigt</translation>
<translation id="4103763322291513355">Besök &lt;strong&gt;chrome://policy&lt;/strong&gt; om du vill visa listan med webbadresser som inte är godkända och andra policyer som angetts av systemadministratören.</translation>
+<translation id="4110615724604346410">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat innehĂ¥ller fel. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Principens omfattning stöds inte.</translation>
+<translation id="4118212371799607889">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom Chromium inte litar pĂ¥ dess säkerhetscertifikat. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 till}other{# till}}</translation>
<translation id="4130226655945681476">Kontrollera nätverkskablar, modem och router</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Vill du att Chromium sparar det här kortet?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Inaktiverad</translation>
<translation id="4196861286325780578">&amp;Gör om Flytta</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />kontrollera konfigureringarna för brandväggen och antivirusprogram<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{inga}=1{1 app ($1)}=2{2 appar ($1, $2)}other{# appar ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Kraschar</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Testa att köra nätverksdiagnostik<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Nej</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Inget användarnamn)</translation>
<translation id="4300246636397505754">Föräldratips</translation>
<translation id="4304224509867189079">Logga in</translation>
+<translation id="432290197980158659">Ett certifikat som inte överensstämmer med inbyggda förväntningar angavs av servern. Förväntningarna gäller för webbplatser med hög säkerhet för att skydda dig. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Det gick inte att hitta artikeln</translation>
+<translation id="4331708818696583467">Inte säkert</translation>
<translation id="4372948949327679948">Ett <ph name="VALUE_TYPE" />-värde förväntades.</translation>
-<translation id="4377125064752653719">Du försökte öppna <ph name="DOMAIN" />, men servern visade ett certifikat som har Ă¥terkallats av utfärdaren. Det innebär att säkerhetsuppgifterna som servern visar inte är absolut tillförlitliga. Du kanske kommunicerar med en skadlig server.</translation>
<translation id="4381091992796011497">Användarnamn:</translation>
<translation id="4394049700291259645">Inaktivera</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> till <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">sökresultat</translation>
-<translation id="4424024547088906515">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom Chrome inte litar pĂ¥ dess säkerhetscertifikat. Detta kan orsakas av en felaktig konfigurering eller att nĂ¥gon spärrar anslutningen.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> godkände inte inloggningscertifikatet eller sĂ¥ har inget inloggningscertifikat angetts.</translation>
<translation id="443673843213245140">Användning av proxy är inaktiverad men en explicit proxykonfiguration har angetts.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Det här meddelandet visas eftersom Google SafeSites är aktiverat.</translation>
@@ -323,34 +339,39 @@
<translation id="4522570452068850558">Info</translation>
<translation id="4558551763791394412">Testa att inaktivera tilläggen.</translation>
<translation id="4587425331216688090">Vill du ta bort adressen frĂ¥n Chrome?</translation>
+<translation id="4589078953350245614">Du försökte öppna <ph name="DOMAIN" />, men servern angav ett ogiltigt certifikat. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Anslutningen till <ph name="DOMAIN" /> är krypterad med en modern krypteringssvit.</translation>
<translation id="4594403342090139922">&amp;Ă…ngra Ta bort</translation>
+<translation id="4627442949885028695">Fortsätta pĂ¥ en annan enhet</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">En tilläggssida visas.</translation>
-<translation id="467662567472608290">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat innehĂ¥ller fel. Detta kan orsakas av en felaktig konfigurering eller att nĂ¥gon spärrar anslutningen.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> blockerades</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Anslutningen avbröts</translation>
-<translation id="4722547256916164131"><ph name="BEGIN_LINK" />att köra nätverksdiagnostik för Windows<ph name="END_LINK" /></translation>
+<translation id="4722547256916164131"><ph name="BEGIN_LINK" /> köra nätverksdiagnostik för Windows<ph name="END_LINK" /></translation>
<translation id="4726672564094551039">Läs in policyer pĂ¥ nytt</translation>
<translation id="4728558894243024398">Plattform</translation>
<translation id="4744603770635761495">Sökväg till körbar fil</translation>
<translation id="4756388243121344051">&amp;Historik</translation>
+<translation id="4759238208242260848">Nedladdningar</translation>
<translation id="4764776831041365478">Webbsidan pĂ¥ <ph name="URL" /> kan ligga nere för tillfället eller kan ha flyttats permanent till en ny webbadress.</translation>
<translation id="4771973620359291008">Ett okänt fel uppstod.</translation>
<translation id="4782449893814226250">Du har frĂ¥gat dina föräldrar om lov att besöka den här sidan.</translation>
<translation id="4800132727771399293">Kontrollera utgĂ¥ngsdatum och CVC-kod och försök igen</translation>
-<translation id="4807049035289105102">Du kan inte besöka <ph name="SITE" /> just nu eftersom webbplatsen skickade krypterade användaruppgifter som Chromium inte kan bearbeta. Nätverksfel och attacker är ofta tillfälliga, sĂ¥ sidan fungerar förmodligen senare.</translation>
<translation id="4813512666221746211">Nätverksfel</translation>
<translation id="4816492930507672669">Anpassa till sida</translation>
<translation id="4850886885716139402">Visa</translation>
<translation id="4880827082731008257">Sök i historiken</translation>
+<translation id="4884656795097055129">Fler artiklar visas sĂ¥ smĂ¥ningom.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{och en till webbsida}other{och # till webbsidor}}</translation>
<translation id="4923417429809017348">Sidan har översatts frĂ¥n ett okänt sprĂ¥k till <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Värdet mĂ¥ste anges.</translation>
<translation id="4930497775425430760">Det här meddelandet visas eftersom en förälder mĂ¥ste godkänna nya webbplatser första gĂ¥ngen du besöker dem.</translation>
<translation id="495170559598752135">Åtgärder</translation>
<translation id="4958444002117714549">Expandera lista</translation>
+<translation id="4962322354953122629">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom Chrome inte litar pĂ¥ dess säkerhetscertifikat. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Vill du översätta frĂ¥n <ph name="ORIGINAL_LANGUAGE" /> till <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Det här pluginprogrammet stöds inte</translation>
<translation id="5002932099480077015">Om alternativet är aktiverat sparar Chrome en kopia av kortet pĂ¥ enheten sĂ¥ att det gĂ¥r snabbare att fylla i formulär.</translation>
<translation id="5019198164206649151">Säkerhetskopian har dĂ¥lig status</translation>
<translation id="5023310440958281426">Kontrollera administratörsprinciperna</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Om Google Översätt</translation>
<translation id="5040262127954254034">Sekretess</translation>
<translation id="5045550434625856497">Felaktigt lösenord</translation>
+<translation id="5056549851600133418">Artiklar för dig</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />kontrollera proxyadressen<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Servercertifikatet är inte giltigt för närvarande.</translation>
<translation id="5089810972385038852">Delstat</translation>
-<translation id="5094747076828555589">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom Chromium inte litar pĂ¥ dess säkerhetscertifikat. Detta kan orsakas av en felaktig konfigurering eller att nĂ¥gon spärrar anslutningen.</translation>
<translation id="5095208057601539847">Provins</translation>
<translation id="5115563688576182185">(64 bitar)</translation>
-<translation id="5122371513570456792">Hittade <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> för <ph name="SEARCH_STRING" />.</translation>
<translation id="5141240743006678641">Kryptera synkroniserade lösenord med dina inloggningsuppgifter för Google</translation>
<translation id="5145883236150621069">Felkoden ingĂ¥r i policysvaret</translation>
<translation id="5171045022955879922">Ange eller sök efter webbadress</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Bokmärkesfältet</translation>
<translation id="5199729219167945352">Experiment</translation>
<translation id="5251803541071282808">Moln</translation>
+<translation id="5277279256032773186">Använder du Chrome pĂ¥ jobbet? Företag kan hantera de anställdas inställningar i Chrome. Läs mer</translation>
<translation id="5299298092464848405">Det uppstod ett fel när policyn analyserades</translation>
<translation id="5300589172476337783">Visa</translation>
<translation id="5308689395849655368">Krashrapportering har inaktiverats.</translation>
<translation id="5317780077021120954">Spara</translation>
<translation id="5327248766486351172">Namn</translation>
+<translation id="5359637492792381994">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" />. Dess säkerhetscertifikat är inte giltigt för närvarande. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Det gick inte att spara policyinställningarna</translation>
-<translation id="540969355065856584">Servern kunde inte bevisa att det är <ph name="DOMAIN" />. Dess säkerhetscertifikat är inte giltigt för närvarande. Detta kan bero pĂ¥ en felaktig konfiguration eller att nĂ¥gon kapat din anslutning.</translation>
<translation id="5421136146218899937">Ta bort webbinformation...</translation>
<translation id="5430298929874300616">Ta bort bokmärke</translation>
<translation id="5431657950005405462">Filen hittades inte</translation>
<translation id="5435775191620395718">Historik frĂ¥n den här enheten visas. <ph name="BEGIN_LINK" />Läs mer<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Förslag pĂ¥ anpassat innehĂ¥ll är inte aktiverat eftersom din synkroniserade data skyddas med en anpassad lösenfras.</translation>
<translation id="5439770059721715174">Schemavalideringsfel i <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Sidan pĂ¥ <ph name="HOST_NAME" /> kan inte hittas</translation>
<translation id="5455374756549232013">Felaktig tidsstämpel för policy</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Vill du lämna den här webbplatsen?</translation>
<translation id="5629630648637658800">Det gick inte att läsa in policyinställningarna</translation>
<translation id="5631439013527180824">Ogiltig enhetshanteringstoken</translation>
-<translation id="5650551054760837876">Inga sökresultat hittades.</translation>
<translation id="5677928146339483299">Blockerad</translation>
<translation id="5710435578057952990">Webbplatsens identitet har inte verifierats.</translation>
<translation id="5720705177508910913">Aktuell användare</translation>
+<translation id="572328651809341494">Senaste flikarna</translation>
<translation id="5784606427469807560">Det gick inte att bekräfta kortet. Kontrollera internetanslutningen och försök igen.</translation>
<translation id="5785756445106461925">Den här sidan innehĂ¥ller emellertid andra resurser som inte är säkra. Andra kan se resurserna när de överförs och hackare kan ändra resurserna sĂ¥ att sidan fĂ¥r ett annat utseende.</translation>
+<translation id="5786044859038896871">Vill du att kortuppgifterna ska fyllas i?</translation>
+<translation id="5803412860119678065">Vill du att uppgifterna om <ph name="CARD_DETAIL" /> ska fyllas i?</translation>
<translation id="5810442152076338065">Anslutningen till <ph name="DOMAIN" /> är krypterad med en gammal krypteringssvit.</translation>
<translation id="5813119285467412249">&amp;Gör om Lägg till</translation>
+<translation id="5814352347845180253">Du kan förlora tillgĂ¥ng till premiuminnehĂ¥ll frĂ¥n <ph name="SITE" /> och nĂ¥gra andra webbplatser.</translation>
+<translation id="5843436854350372569">Du försökte öppna <ph name="DOMAIN" />, men servern angav ett certifikat som signerats med en svag nyckel. Det innebär att den privata nyckeln som servern anger kan vara en förfalskning och att servern kanske inte är den server du tror (du kanske kommunicerar med en angripare). <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Det här meddelandet visas eftersom din chef har blockerat den här webbplatsen.</translation>
<translation id="5857090052475505287">Ny mapp</translation>
<translation id="5869405914158311789">Webbplatsen kan inte nĂ¥s</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Föräldratips</translation>
<translation id="59107663811261420">Den här korttypen stöds inte i Google Payments för den här säljaren. Välj ett annat kort.</translation>
<translation id="59174027418879706">Aktiverat</translation>
+<translation id="5926846154125914413">Du kan förlora tillgĂ¥ng till premiuminnehĂ¥ll frĂ¥n vissa webbplatser.</translation>
<translation id="5966707198760109579">Vecka</translation>
<translation id="5967867314010545767">Ta bort frĂ¥n historiken</translation>
<translation id="5975083100439434680">Zooma ut</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Automatisk</translation>
<translation id="6042308850641462728">Mer</translation>
<translation id="6060685159320643512">Försiktigt, experimenten kan vara skadliga</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{inga}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Kontrollera kablar och starta om routrar, modem och andra nätverksenheter
som används.</translation>
<translation id="614940544461990577">Testa att</translation>
<translation id="6150607114729249911">Du mĂ¥ste frĂ¥ga dina föräldrar om du fĂ¥r besöka den här sidan.</translation>
<translation id="6151417162996330722">Servercertifikatet har för lĂ¥ng giltighetstid.</translation>
-<translation id="6154808779448689242">Returnerad policytoken matchade inte den aktuella token</translation>
<translation id="6165508094623778733">Läs mer</translation>
<translation id="6203231073485539293">Kontrollera internetanslutningen</translation>
<translation id="6218753634732582820">Vill du ta bort adressen frĂ¥n Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Prova att inaktivera nätverksförslag</translation>
<translation id="6337534724793800597">Filtrera policy efter namn</translation>
<translation id="6342069812937806050">Alldeles nyss</translation>
+<translation id="6345221851280129312">okänd storlek</translation>
<translation id="6355080345576803305">Åsidosätt offentlig session</translation>
<translation id="6358450015545214790">Vad innebär dessa?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 annat förslag}other{# andra förslag}}</translation>
<translation id="6387478394221739770">Ă„r du intresserad av häftiga nya funktioner i Chrome? Pröva vĂ¥r betakanal pĂ¥ chrome.com/beta.</translation>
-<translation id="641480858134062906"><ph name="URL" /> kunde inte laddas</translation>
+<translation id="6389758589412724634">Minnet tog slut när den här webbsidan skulle visas i Chromium.</translation>
+<translation id="6416403317709441254">Det gĂ¥r inte att besöka <ph name="SITE" /> just nu eftersom webbplatsen skickade förvrängda användaruppgifter som Chromium inte kan behandla. Nätverksfel och attacker är vanligtvis tillfälliga, sĂ¥ sidan fungerar troligen senare. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Det gick inte att kontrollera om certifikatet har Ă¥terkallats.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> avvisade anslutningen.</translation>
<translation id="6445051938772793705">Land</translation>
<translation id="6451458296329894277">Bekräfta Ă¥tersändning av formulär</translation>
<translation id="6458467102616083041">Ignoreras eftersom standardsökmotorn är inaktiverad av en policy.</translation>
+<translation id="6462969404041126431">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kan ha Ă¥terkallats. Detta kan orsakas av en felaktig konfigurering eller att nĂ¥gon spärrar anslutningen. <ph name="BEGIN_LEARN_MORE_LINK" />Lär mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Enhetspolicyer</translation>
<translation id="6489534406876378309">Börja överföra information om krascher</translation>
<translation id="6529602333819889595">&amp;Gör om Ta bort</translation>
+<translation id="6534179046333460208">Förslag frĂ¥n Physical Web</translation>
<translation id="6550675742724504774">Alternativ</translation>
+<translation id="6593753688552673085">mindre än <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Krypteringsalternativ</translation>
<translation id="662080504995468778">Stanna kvar</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Sök</translation>
-<translation id="6634865548447745291">Det gĂ¥r inte att besöka <ph name="SITE" /> just nu pĂ¥ grund av att <ph name="BEGIN_LINK" />det här certifikatet har Ă¥terkallats<ph name="END_LINK" />. Nätverksfel och attacker är vanligtvis tillfälliga sĂ¥ sidan fungerar troligen senare.</translation>
<translation id="6644283850729428850">Policyn är förĂ¥ldrad.</translation>
+<translation id="6652240803263749613">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom datorns operativsystem inte litar pĂ¥ dess säkerhetscertifikat. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Redigera mapp</translation>
<translation id="6660210980321319655">Rapporterades automatiskt <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Vill du ta bort formulärförslaget frĂ¥n Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">FöregĂ¥ende</translation>
<translation id="6710594484020273272">&lt;Ange sökterm&gt;</translation>
<translation id="6711464428925977395">NĂ¥got är fel med proxyservern eller sĂ¥ är adressen felaktig.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{inga}=1{1 objekt}other{# objekt}}</translation>
<translation id="674375294223700098">Fel - okänt servercertifikat.</translation>
<translation id="6753269504797312559">Policyvärde</translation>
<translation id="6757797048963528358">Enheten gick i viloläge.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">PolicynivĂ¥n stöds inte.</translation>
<translation id="6895330447102777224">Kortet har bekräftats</translation>
<translation id="6897140037006041989">Användaragent</translation>
-<translation id="6903907808598579934">Aktivera synkronisering</translation>
<translation id="6915804003454593391">Användare:</translation>
<translation id="6957887021205513506">Serverns certifikat verkar vara falskt.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Distrikt</translation>
<translation id="6973656660372572881">BĂ¥de fasta proxyservrar och en webbadress för PAC-skript anges.</translation>
<translation id="6989763994942163495">Visa avancerade inställningar ...</translation>
+<translation id="7000990526846637657">Inga historikposter hittades</translation>
+<translation id="7009986207543992532">Du försökte öppna <ph name="DOMAIN" />, men servern angav ett certifikat vars giltighetstid är för lĂ¥ng för att det ska vara trovärdigt. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Andra former av webbhistorik för Google-kontot kan finnas pĂ¥ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Lösenord</translation>
-<translation id="7050187094878475250">Du försökte nĂ¥ <ph name="DOMAIN" />, men servern svarade med ett certifikat vars giltighetstid är för lĂ¥ng för att det ska vara trovärdigt.</translation>
<translation id="7087282848513945231">Grevskap</translation>
<translation id="7088615885725309056">Ă„ldre</translation>
<translation id="7090678807593890770">Sök efter <ph name="LINK" /> pĂ¥ Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Det här meddelandet visas eftersom din chef mĂ¥ste godkänna nya webbplatser första gĂ¥ngen du besöker dem.</translation>
<translation id="724975217298816891">Ange utgĂ¥ngsdatum och CVC-kod för <ph name="CREDIT_CARD" /> om du vill uppdatera kortinformationen. När du bekräftar delas kortinformationen med den här webbplatsen.</translation>
<translation id="725866823122871198">Det gick inte att upprätta en privat anslutning till <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> eftersom datorns datum och tid (<ph name="DATE_AND_TIME" />) inte stämmer.</translation>
-<translation id="7265986070661382626">Det gĂ¥r inte att besöka <ph name="SITE" /> just nu pĂ¥ grund av att <ph name="BEGIN_LINK" />fäste av certifikat<ph name="END_LINK" /> förekommer pĂ¥ webbplatsen. Nätverksfel och attacker är vanligtvis tillfälliga, sĂ¥ den här sidan fungerar troligen senare.</translation>
<translation id="7269802741830436641">Den här webbsidan innehĂ¥ller en omdirigeringsslinga</translation>
<translation id="7275334191706090484">Hanterade bokmärken</translation>
<translation id="7298195798382681320">Rekommenderas</translation>
-<translation id="7301833672208172928">Aktivera historiksynkronisering</translation>
+<translation id="7309308571273880165">Felrapport som skapades <ph name="CRASH_TIME" /> (uppladdning begärdes av användaren, har ännu inte laddats upp)</translation>
<translation id="7334320624316649418">&amp;Gör om Ändra ordning</translation>
<translation id="733923710415886693">Servercertifikatet har inte lämnats ut via Certifikattransparens.</translation>
+<translation id="7351800657706554155">Det gĂ¥r inte att besöka <ph name="SITE" /> just nu pĂ¥ grund av att det här certifikatet har Ă¥terkallats. Nätverksfel och attacker är vanligtvis tillfälliga sĂ¥ sidan fungerar troligen senare. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Kommandorad</translation>
<translation id="7372973238305370288">sökresultat</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Psst! Nästa gĂ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nĂ
<translation id="7469372306589899959">Kortet bekräftas</translation>
<translation id="7481312909269577407">FramĂ¥t</translation>
<translation id="7485870689360869515">Ingen data hittades.</translation>
+<translation id="7508255263130623398">Enhets-id för returnerad princip är tomt eller matchar inte nuvarande enhets-id</translation>
<translation id="7514365320538308">Ladda ned</translation>
<translation id="7518003948725431193">Det fanns ingen webbsida pĂ¥ webbadressen: <ph name="URL" /></translation>
<translation id="7537536606612762813">Obligatorisk</translation>
<translation id="7542995811387359312">Automatisk ifyllning av kreditkort har inaktiverats eftersom formulärets anslutning inte är säker.</translation>
<translation id="7549584377607005141">Den här webbsidan kräver uppgifter som du har angett tidigare för att kunna visas korrekt. Du kan skicka uppgifterna igen, men om du gör det upprepas de Ă¥tgärder som har utförts av sidan tidigare.</translation>
<translation id="7554791636758816595">Ny flik</translation>
-<translation id="7567204685887185387">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kan ha utfärdats utan behörighet. Detta kan orsakas av en felaktig konfigurering eller att nĂ¥gon spärrar anslutningen.</translation>
<translation id="7568593326407688803">Den här sidan är pĂ¥<ph name="ORIGINAL_LANGUAGE" />Vill du översätta den?</translation>
<translation id="7569952961197462199">Vill du ta bort kreditkortet frĂ¥n Chrome?</translation>
<translation id="7578104083680115302">Betala snabbt pĂ¥ webbplatser och i appar pĂ¥ olika enheter med kort som du har sparat hos Google.</translation>
+<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Serverns certifikat strider mot namnrestriktionerna.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> kan för närvarande inte hantera förfrĂ¥gan.</translation>
<translation id="7600965453749440009">Ă–versätt aldrig frĂ¥n <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Psst! Nästa gĂ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nĂ
<translation id="7637571805876720304">Vill du ta bort kreditkortet frĂ¥n Chromium?</translation>
<translation id="765676359832457558">Dölj avancerade inställningar ...</translation>
<translation id="7658239707568436148">Avbryt</translation>
+<translation id="7667346355482952095">Policytoken som returnerades är tom eller matchade inte den aktuella token</translation>
<translation id="7668654391829183341">Okänd enhet</translation>
<translation id="7674629440242451245">Ă„r du intresserad av häftiga nya funktioner i Chrome? Pröva vĂ¥r utvecklarkanal pĂ¥ chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Fortsätt till <ph name="SITE" /> (osäkert)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Psst! Nästa gĂ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nĂ
<translation id="780301667611848630">Nej tack</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7813600968533626083">Vill du ta bort formulärförslaget frĂ¥n Chrome?</translation>
+<translation id="7815407501681723534">Hittade <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> för <ph name="SEARCH_STRING" /></translation>
<translation id="785549533363645510">Men du är inte osynlig. Inkognitoläget döljer inte webbhistoriken för din arbetsgivare, internetleverantören eller webbplatserna du besöker.</translation>
<translation id="7887683347370398519">Kontrollera CVC-koden och försök igen</translation>
<translation id="7894616681410591072">Du behöver tillstĂ¥nd frĂ¥n <ph name="NAME" /> om du vill komma Ă¥t den här sidan.</translation>
-<translation id="790025292736025802"><ph name="URL" /> hittades inte</translation>
<translation id="7912024687060120840">I mappen:</translation>
<translation id="7920092496846849526">Du har frĂ¥gat en förälder om lov att besöka den här sidan.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ Psst! Nästa gĂ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nĂ
<translation id="7995512525968007366">Inte specificerad</translation>
<translation id="8012647001091218357">Vi kunde inte nĂ¥ dina föräldrar just nu. Försök igen.</translation>
<translation id="8034522405403831421">Den här sidan är skriven pĂ¥ <ph name="SOURCE_LANGUAGE" />. Vill du översätta den till <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Inga historikposter hittades.</translation>
<translation id="8088680233425245692">Det gick inte att visa artikeln.</translation>
+<translation id="8089520772729574115">mindre än 1 MB</translation>
<translation id="8091372947890762290">Aktiveringen väntar pĂ¥ servern</translation>
+<translation id="8129262335948759431">okänd mängd</translation>
<translation id="8131740175452115882">Bekräfta</translation>
<translation id="8134994873729925007">Det gick inte att hitta <ph name="BEGIN_ABBR" />DNS-adressen<ph name="END_ABBR" /> till servern för <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Datorn gick i viloläge.</translation>
@@ -604,6 +640,7 @@ Psst! Nästa gĂ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nĂ
<translation id="8201077131113104583">Ogiltig webbadress för uppdatering för tillägg med id <ph name="EXTENSION_ID" />.</translation>
<translation id="8218327578424803826">Tilldelad plats:</translation>
<translation id="8225771182978767009">Personen som konfigurerade datorn har valt att blockera den här webbplatsen.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Ă–nskad sida använder information som du har angett. Om du Ă¥tergĂ¥r till sidan kan eventuella Ă¥tgärder pĂ¥ sidan upprepas. Vill du fortsätta?</translation>
<translation id="8249320324621329438">Senast hämtad:</translation>
<translation id="8261506727792406068">Radera</translation>
@@ -616,12 +653,17 @@ Psst! Nästa gĂ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nĂ
<translation id="8349305172487531364">Bokmärkesfältet</translation>
<translation id="8363502534493474904">inaktivera flygplansläget</translation>
<translation id="8364627913115013041">Inte angiven.</translation>
+<translation id="8380941800586852976">Farlig</translation>
<translation id="8412145213513410671">Krascher (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Du mĂ¥ste ange samma lösenfras tvĂ¥ gĂ¥nger.</translation>
<translation id="8428213095426709021">Inställningar</translation>
+<translation id="8433057134996913067">Alternativet innebär att du loggas ut frĂ¥n de flesta webbplatser.</translation>
<translation id="8437238597147034694">&amp;Ă…ngra Flytta</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kreditkort}other{# kreditkort}}</translation>
+<translation id="8483780878231876732">Logga in i Chrome om du vill använda kort i Google-kontot</translation>
<translation id="8488350697529856933">Gäller för</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> tog för lĂ¥ng tid pĂ¥ sig att svara.</translation>
+<translation id="852346902619691059">Det gick inte att bevisa att serverns identitet är <ph name="DOMAIN" /> eftersom datorns operativsystem inte litar pĂ¥ dess säkerhetscertifikat. Det kan bero pĂ¥ att servern är felkonfigurerad eller att anslutningen har blivit kapad. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Den här korttypen stöds inte i Google Payments. Välj ett annat kort.</translation>
<translation id="8550022383519221471">Synkroniseringstjänsten är inte tillgänglig för din domän.</translation>
<translation id="8553075262323480129">Det gick inte att översätta eftersom det inte gick att avgöra vilket sprĂ¥k som användes pĂ¥ sidan.</translation>
@@ -633,15 +675,12 @@ Psst! Nästa gĂ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nĂ
<translation id="8647750283161643317">Återställ alla till standardvärden</translation>
<translation id="8680787084697685621">Inloggningsuppgifterna för kontot är inte aktuella.</translation>
<translation id="8703575177326907206">Din anslutning till <ph name="DOMAIN" /> är inte krypterad.</translation>
-<translation id="8713130696108419660">DĂ¥lig initial signatur</translation>
<translation id="8725066075913043281">Försök igen</translation>
<translation id="8728672262656704056">Du surfar inkognito.</translation>
<translation id="8730621377337864115">Klart</translation>
<translation id="8738058698779197622">Om du vill upprätta en säker anslutning mĂ¥ste klockan vara rätt inställd. Det beror pĂ¥ att certifikaten som webbplatserna använder för att identifiera sig endast är giltiga under vissa tidsperioder. Chromium kan inte verifiera certifikaten eftersom klockan pĂ¥ enheten inte stämmer.</translation>
<translation id="8740359287975076522">Det gick inte att hitta <ph name="HOST_NAME" />s &lt;abbr id="dnsDefinition"&gt;DNS-adress&lt;/abbr&gt;. Diagnostiserar problemet.</translation>
-<translation id="8741995161408053644">Andra former av webbhistorik för Google-kontot kan finnas pĂ¥ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;Gör om Ta bort</translation>
-<translation id="8790687370365610530">Aktivera synkronisering om du vill fĂ¥ förslag pĂ¥ anpassat innehĂ¥ll frĂ¥n Google.</translation>
<translation id="8798099450830957504">Standard</translation>
<translation id="8804164990146287819">Sekretesspolicy</translation>
<translation id="8820817407110198400">Bokmärken</translation>
@@ -663,13 +702,11 @@ Psst! Nästa gĂ¥ng kanske inkognitoläget <ph name="SHORTCUT_KEY" /> kan vara nĂ
<translation id="8971063699422889582">Servercertifikatet har gĂ¥tt ut.</translation>
<translation id="8987927404178983737">MĂ¥nad</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Servern visade ett certifikat som inte lämnats ut via principen Certifikattransparens. Detta är ett krav för vissa certifikat för att säkerställa att de är pĂ¥litliga och skyddar mot hackare.</translation>
<translation id="9001074447101275817">Proxyservern <ph name="DOMAIN" /> kräver användarnamn och lösenord.</translation>
<translation id="901974403500617787">Flaggor som gäller hela systemet kan endast ställas in av ägaren: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Den här sidan har översatts till <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Använd en förslagstjänst om du vill läsa in sidor snabbare</translation>
<translation id="9039213469156557790">Den här sidan innehĂ¥ller emellertid andra resurser som inte är säkra. Andra kan se resurserna när de överförs och hackare kan ändra resurserna sĂ¥ att sidan fĂ¥r ett annat beteende.</translation>
-<translation id="9049981332609050619">Du försökte nĂ¥ <ph name="DOMAIN" /> men servern angav ett ogiltigt certifikat.</translation>
<translation id="9050666287014529139">Lösenfras</translation>
<translation id="9065203028668620118">Redigera</translation>
<translation id="9092364396508701805">Sidan pĂ¥ <ph name="HOST_NAME" /> fungerar inte</translation>
diff --git a/chromium/components/strings/components_strings_sw.xtb b/chromium/components/strings/components_strings_sw.xtb
index 316458baf0a..ae69aab656c 100644
--- a/chromium/components/strings/components_strings_sw.xtb
+++ b/chromium/components/strings/components_strings_sw.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sw">
+<translation id="1008557486741366299">Sio Sasa</translation>
<translation id="1015730422737071372">Toa maelezo ya ziada</translation>
<translation id="1032854598605920125">Zungusha kwenye mwendo wa saa</translation>
<translation id="1038842779957582377">jina lisilojulikana</translation>
+<translation id="1053591932240354961">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti ilituma kitambulisho kilichoharibika ambacho Google Chrome haiwezi kuchakata. Hitilafu na uvamizi wa mtandao kwa kawaida huwa wa muda, kwa hivyo ukurasa huu huenda utafanya kazi baadaye. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">Tendua Kuongeza</translation>
<translation id="10614374240317010">Haijahifadhiwa kamwe</translation>
-<translation id="1064422015032085147">Huenda seva inayopangisha ukurasa huo wa wavuti imejaa au inakarabatiwa.
- Ili uepuke kuzalisha maelezo mengi na kuharibu hali zaidi,
- maombi yanayotumwa kwenye URL hii yamesimamishwa kwa muda.</translation>
<translation id="106701514854093668">Alamisho za Eneokazi</translation>
<translation id="1080116354587839789">Fanya itoshe kwenye upana</translation>
+<translation id="1103124106085518534">Umekamilisha kwa sasa</translation>
<translation id="1103523840287552314">Tafsiri <ph name="LANGUAGE" /> kila wakati</translation>
<translation id="1107591249535594099">Ikiteuliwa, Chrome itahifadhi nakala ya kadi yako kwenye kifaa hiki kwa ajili ya kujaza fomu haraka.</translation>
+<translation id="1111153019813902504">Alamisho za hivi majuzi</translation>
<translation id="1113869188872983271">Tendua kupanga upya</translation>
+<translation id="1126551341858583091">Ukubwa kwenye nafasi ya hifadhi ya ndani ya kifaa ni <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Akiba ya sera ni SAWA</translation>
<translation id="113188000913989374"><ph name="SITE" /> unasema:</translation>
<translation id="1132774398110320017">Mipangilio ya Kujaza otomatiki ya Chrome...</translation>
-<translation id="1150979032973867961">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na mfumo wa uendeshaji wa kompyuta yako. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="1152921474424827756">Fikia <ph name="BEGIN_LINK" />nakala iliyowekwa kwenye akiba<ph name="END_LINK" /> ya <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ilifunga muunganisho bila kutarajia.</translation>
<translation id="1161325031994447685">Kuunganisha tena kwenye Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Ondoa</translation>
<translation id="1201402288615127009">Ifuatayo</translation>
<translation id="1201895884277373915">Zaidi kutoka kwenye tovuti hii</translation>
-<translation id="121201262018556460">Umejaribu kufikia <ph name="DOMAIN" />, lakini seva iliwasilisha cheti kikiwa na ufunguo duni. Huenda mshambulizi alivunja ufunguo wa siri, na huenda seva isiwe seva ulioitarajia (unaweza kuwa unawasiliana na mshambulizi).</translation>
+<translation id="1206967143813997005">Sahihi mbaya ya mwanzo</translation>
+<translation id="1209206284964581585">Ficha kwa sasa</translation>
<translation id="1219129156119358924">Usalama wa Mfumo</translation>
<translation id="1227224963052638717">Sera isiyojulikana.</translation>
<translation id="1227633850867390598">Ficha thamani</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Ndio</translation>
<translation id="1430915738399379752">Chapisha</translation>
<translation id="1442912890475371290">Imezuia jaribio <ph name="BEGIN_LINK" /> la kutembelea ukurasa kwenye <ph name="DOMAIN" /> <ph name="END_LINK" /> .</translation>
+<translation id="1491663344921578213">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti hutumia ubandikaji vyeti. Hitilafu na uvamizi wa mtandao kwa kawaida huwa wa muda, kwa hivyo ukurasa huu huenda utafanya kazi baadaye.<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Onyesha nakala iliyohifadhiwa (yaani inayojulikana kwisha muda) ya ukurasa huu.</translation>
<translation id="1519264250979466059">Unda Tarehe</translation>
<translation id="1549470594296187301">Lazima JavaScript iwashwe ili utumie kipengele hiki.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Usanidi wa mtandao ni batili na usingeweza kuingizwa.</translation>
<translation id="1644574205037202324">Historia</translation>
<translation id="1645368109819982629">Itifaki haitumiki</translation>
-<translation id="1655462015569774233">{1,plural, =1{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kilikwisha muda jana. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako. Saa ya kompyuta kwa sasa imewekwa kuwa <ph name="CURRENT_DATE" />. Je, hiyo ni sahihi? Ikiwa si sahihi, rekebisha saa ya mfumo wako kisha uonyeshe upya ukurasa huu.}other{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kilikwisha muda siku # zilizopita. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako. Saa ya kompyuta kwa sasa imewekwa kuwa <ph name="CURRENT_DATE" />. Je, hiyo ni sahihi? Ikiwa si sahihi, rekebisha saa ya mfumo wako kisha uonyeshe upya ukurasa huu.}}</translation>
<translation id="1676269943528358898">Kwa kawaida <ph name="SITE" /> hutumia usimbaji fiche ili kulinda maelezo yako. Google Chrome ilipojaribu kuunganisha kwenye <ph name="SITE" /> wakati huu, tovuti ilituma kitambulisho kisicho cha kawaida na kisicho sahihi. Hili linaweza kutokea mvamizi anapojaribu kujifanya kuwa <ph name="SITE" />, au uchanganuzi wa kuingia katika Wi-Fi umeingilia muunganisho. Maelezo yako yangali salama kwa sababu Google Chrome ilisimamisha muunganisho kabla data yoyote itumwe.</translation>
<translation id="168841957122794586">Cheti cha seva kina kitufe dhaifu cha kifichua msimbo.</translation>
<translation id="1701955595840307032">Pata maudhui yanayopendekezwa</translation>
-<translation id="1706954506755087368">{1,plural, =1{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kitakwisha muda kuanzia kesho. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.}other{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kitakwisha muda kuanzia siku # zijazo. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Kuwasiliana na msimamizi wa mfumo.</translation>
<translation id="17513872634828108">Vichupo vilivyo wazi</translation>
<translation id="1753706481035618306">Nambari ya ukurasa</translation>
-<translation id="1761412452051366565">Ili Google ikupendekezee maudhui yanayokufaa, washa kipengele cha usawazishaji.</translation>
-<translation id="1763864636252898013">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na mfumo wa uendeshaji wa kifaa chako. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Jaribu kutumia zana ya Kuchunguza Mtandao wa Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Tafadhali sasisha kaulisiri yako iliyolandanishwa.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Alamisho ulizotembelea hivi majuzi zitaonekana hapa.</translation>
<translation id="1821930232296380041">Ombi au vigezo vya ombi batili</translation>
<translation id="1838667051080421715">Unaangalia chanzo cha ukurasa wa wavuti.</translation>
<translation id="1871208020102129563">Proksi imewekwa ili kutumia seva za proksi thabiti, siyo URL ya hati .pac.</translation>
<translation id="1883255238294161206">Kunja orodha</translation>
<translation id="1898423065542865115">Kuchuja</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> haikukubali cheti chako cha kuingia katika akaunti, au huenda muda wa cheti chako cha kuingia katika akaunti umekwisha.</translation>
<translation id="194030505837763158">Nenda kwenye <ph name="LINK" /></translation>
<translation id="1962204205936693436">Alamisho za <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Hitilafu ya namba tambulishi</translation>
<translation id="1974060860693918893">Mipangilio ya kina</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{na nyingine 1}other{na nyingine #}}</translation>
<translation id="2025186561304664664">Proksi imewekwa katika usanidi otomatiki.</translation>
<translation id="2030481566774242610">Je, ulimaanisha <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Unaona ujumbe huu kwa sababu wazazi wako wanahitaji kuidhinisha tovuti mpya unapotembelea kwa mara ya kwanza.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Kuangalia seva mbadala na kinga-mtandao<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Msimbo wa eneo</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{Pendekezo 1}other{Mapendekezo #}}</translation>
<translation id="2065985942032347596">Uthibitishaji Unahitajika</translation>
<translation id="2079545284768500474">Tendua</translation>
<translation id="20817612488360358">Mipangilio ya mfumo ya proksi imewekwa ili kutumiwa lakini usanidi dhahiri wa proksi pia umebainishwa.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Badilisha Alamisho</translation>
<translation id="2166049586286450108">Idhini Kamili ya Kufikia ya Msimamizi</translation>
<translation id="2166378884831602661">Tovuti hii haiwezi kutoa muunganisho salama</translation>
-<translation id="2171101176734966184">Umejaribu kufikia <ph name="DOMAIN" />, lakini seva iliwasilisha cheti kilichotiwa sahihi na kanuni duni. Hii inamaanisha kuwa stakabadhi za usalama zilizowasilishwa na seva hiyo zinaweza kuwa bandia, na seva hiyo huenda ikawa sio ile uliyotarajia (unaweza kuwa unawasiliana na mshambulizi).</translation>
<translation id="2181821976797666341">Sera</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{Anwani 1}other{Anwani #}}</translation>
<translation id="2212735316055980242">Sera haikupatikana</translation>
<translation id="2213606439339815911">Inachukua viingizo...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> haipatikani</translation>
<translation id="2230458221926704099">Weka muunganisho wako kwa kutumia <ph name="BEGIN_LINK" />programu ya kuchunguza<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Tuma sasa</translation>
<translation id="225207911366869382">Thamani hii inapingwa kwa sera hii.</translation>
<translation id="2262243747453050782">Hitilfau ya HTTP</translation>
<translation id="2282872951544483773">Majaribio Yasiyopatikana</translation>
<translation id="2292556288342944218">Ufikiaji wako wa intaneti umezuiwa</translation>
<translation id="229702904922032456">Kitambulisho cha mzizi au kati kimekwisha muda.</translation>
<translation id="230155334948463882">Je, ni kadi mpya?</translation>
+<translation id="2305919008529760154">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; huenda cheti chake cha usalama kilitolewa kwa ulaghai. Huenda hali hii ilitokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako.<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> inahitaji jina la mtumiaji na nenosiri.</translation>
+<translation id="2318774815570432836">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti hii hutumia HSTS. Hitilafu na uvamizi wa mtandao kwa kawaida huwa wa muda tu, kwa hivyo ukurasa huu huenda utafanya kazi baadaye.<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">Imepuuzia alamisho batili katika farahasa <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Alamisho zingine</translation>
<translation id="2359808026110333948">Endelea</translation>
<translation id="2365563543831475020">Ripoti ya kuacha kufanya kazi iliyochukuliwa <ph name="CRASH_TIME" /> haikupakiwa</translation>
<translation id="2367567093518048410">Kiwango</translation>
+<translation id="2371153335857947666">{1,plural, =1{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kilikwisha muda jana. Huenda hali hii ilitokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. Saa ya kompyuta kwa sasa imewekwa kuwa <ph name="CURRENT_DATE" />. Je, hiyo ni sahihi? Ikiwa si sahihi, rekebisha saa ya mfumo wako kisha uonyeshe upya ukurasa huu. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.}other{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kilikwisha muda siku # zilizopita. Huenda hali hii ilitokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako Saa ya kompyuta kwa sasa imewekwa kuwa <ph name="CURRENT_DATE" />. Je, hiyo ni sahihi? Ikiwa si sahihi, rekebisha saa ya mfumo wako kisha uonyeshe upya ukurasa huu. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Hakuna UI mbadala zinazopatikana</translation>
<translation id="2384307209577226199">Biashara chaguo-msingi</translation>
-<translation id="238526402387145295">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti hiyo <ph name="BEGIN_LINK" />hutumia HSTS<ph name="END_LINK" />. Hitilafu na uvamizi wa mtandao kwa kawaida huwa wa muda tu, kwa hivyo ukurasa huu huenda utafanya kazi baadaye.</translation>
<translation id="2386255080630008482">Cheti cha seva kimebatilishwa.</translation>
<translation id="2392959068659972793">Onyesha sera zisizowekwa thamani</translation>
<translation id="2396249848217231973">Tendua kufuta</translation>
-<translation id="2413528052993050574">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; huenda cheti chake cha usalama kimebatilishwa. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="2455981314101692989">Ukurasa wavuti huu umelemaza mjazo otomatiki kwa fomu hii.</translation>
+<translation id="2463739503403862330">Jaza</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Inaendesha Zana ya Kuchunguza Mtandao<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL batili ya utafutaji.</translation>
<translation id="2491120439723279231">Cheti cha seva kina hitilafu.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Wasilisha</translation>
<translation id="2674170444375937751">Je, una hakika kuwa ungependa kufuta kurasa hizi kutoka historia yako?</translation>
<translation id="2677748264148917807">Ondoka</translation>
+<translation id="269990154133806163">Seva imewasilisha cheti ambacho hakikuonyeshwa hadharani kwa kutumia sera ya Uwazi wa Cheti. Baadhi ya vyeti huwa na masharti haya, ili kuhakikisha kwamba ni vya kuaminika na kulinda dhidi ya wavamizi.<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Thamani haioani na umbizo.</translation>
<translation id="2704951214193499422">Chromium haikuweza kuthibitisha kadi yako wakati huu. Tafadhali jaribu tena baadaye.</translation>
<translation id="2705137772291741111">Nakala iliyohifadhiwa (iliyowekwa katika akiba) ya tovuti hii haikusomeka.</translation>
<translation id="2709516037105925701">Kujaza Kiotomatiki</translation>
+<translation id="2712118517637785082">Ulijaribu kufikia <ph name="DOMAIN" />, lakini cheti kilichowasilishwa na seva kimebatilishwa na mtoaji wacho. Inamaanisha kuwa stakabadhi za usalama zilizowasilishwa na seva hii hazifai kuaminiwa kabisa. Huenda unawasiliana na mvamizi.<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Omba ruhusa</translation>
<translation id="2721148159707890343">Ombi limefanikiwa</translation>
<translation id="2728127805433021124">Cheti cha seva kimetiwa sahihi kwa kutumia algoriti dhaifu ya sahihi.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Upau wa anwani na utafutaji</translation>
<translation id="2826760142808435982">Muunganisho umesimbwa kwa njia fiche na kuthibitishwa kupitia <ph name="CIPHER" /> na unatumia <ph name="KX" /> kama utaratibu msingi wa ubadilishaji.</translation>
<translation id="2835170189407361413">Futa fomu</translation>
-<translation id="2837049386027881519">Muunganisho ulihitajika kujaribiwa upya kwa kutumia toleo la zamani la itifaki ya TSL au SSL. Hii kwa kawaida inamaanisha kuwa seva inatumia programu ya zamani zaidi na huenda ikawa na masuala mengine ya usalama.</translation>
<translation id="284702764277384724">Cheti cha seva kilchopo kwenye <ph name="HOST_NAME" /> kinaonekana ghushi.</translation>
<translation id="2889159643044928134">Usipakie Upya</translation>
-<translation id="2896499918916051536">Programu-jalizi hii haitumiki.</translation>
+<translation id="2900469785430194048">Nafasi ya kuhifadhi kwenye Google Chrome iliisha ilipokuwa ikijaribu kuonyesha ukurasa huu wa wavuti.</translation>
<translation id="2909946352844186028">Mabadiliko ya mtandao yamegunduliwa.</translation>
-<translation id="2915500479781995473">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kilikwisha muda. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako. Saa ya kompyuta yako imewekwa kwenye saa <ph name="CURRENT_TIME" /> kwa sasa. Hiyo ni sawa? Ikiwa si sawa, unapaswa kurekebisha mfumo wako wa saa kisha uonyeshe upya ukurasa huu.</translation>
<translation id="2922350208395188000">Cheti cha seva hakiwezi kukaguliwa.</translation>
-<translation id="2941952326391522266">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kinatoka <ph name="DOMAIN2" />. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="2948083400971632585">Unaweza kuzima proksi zozote zilizosanidiwa kwa muunganisho kutoka kwenye ukurasa wa mipangilio.</translation>
<translation id="2955913368246107853">Funga upau wa kupata</translation>
<translation id="2958431318199492670">Usanidi wa mtandao hautii kiwango cha ONC. Sehemu za usanidi haziwezi kuingizwa.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Aina mbaya ya sera</translation>
<translation id="3032412215588512954">Ungependa kupakia upya tovuti hii?</translation>
<translation id="3037605927509011580">Lo!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{angalau kipengee 1 kwenye vifaa vilivyosawazishwa}=1{Kipengee 1 (na zaidi kwenye vifaa vilivyosawazishwa)}other{Vipengee # (na zaidi kwenye vifaa vilivyosawazishwa)}}</translation>
<translation id="3041612393474885105">Maelezo ya Cheti</translation>
<translation id="3063697135517575841">Chrome haikuweza kuthibitisha kadi yako wakati huu. Tafadhali jaribu tena baadaye.</translation>
<translation id="3093245981617870298">Uko nje ya mtandao.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Mpya kuliko zote</translation>
<translation id="3207960819495026254">Imealamishwa</translation>
-<translation id="3225919329040284222">Seva imewasilisha cheti kisicholingana na matarajio ya kijenzi cha ndani. Matarajio haya yanajumlishwa kwa baadhi ya tovuti za usalama wa juu ili kukulinda.</translation>
<translation id="3226128629678568754">Bonyeza kitufe cha kupakia upya ili kuwasilisha upya data inayohitajika kupakia ukurasa.</translation>
<translation id="3228969707346345236">Tafsiri ilishindikana kwa sababu ukurasa tayari upo katika <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Weka CVC ya <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Alamisha ukurasa huu</translation>
<translation id="3270847123878663523">Tendua Kupanga upya</translation>
<translation id="3286538390144397061">Zima na uwashe sasa</translation>
+<translation id="3303855915957856445">Hakuna matokeo ya utafutaji yaliyopatikana</translation>
<translation id="3305707030755673451">Data yako ilisimbwa kwa njia fiche kwa kauli yako ya siri ya kusawazisha mnamo <ph name="TIME" />. Iweke ili uanze kusawazisha.</translation>
<translation id="333371639341676808">Zuia ukurasa huu usiulize maswali zaidi.</translation>
+<translation id="3338095232262050444">Salama</translation>
<translation id="3340978935015468852">mipangilio</translation>
<translation id="3345135638360864351">Ombi lako la kufikia tovuti hii halikutumwa kwa <ph name="NAME" />. Tafadhali jaribu tena.</translation>
<translation id="3355823806454867987">Badilisha mipangilio ya seva mbadala...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Muda unaotumika kuleta:</translation>
<translation id="3462200631372590220">Ficha mahiri</translation>
<translation id="3479539252931486093">Je, hukutarajia tukio hili? <ph name="BEGIN_LINK" />Tujulishe<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Sio sasa</translation>
<translation id="348000606199325318">Kitambulisho cha kuacha kufanya kazi <ph name="CRASH_LOCAL_ID" /> (Kitambulisho cha Seva: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Hatukuweza kufikia mzazi wako wakati huu. Tafadhali jaribu tena.</translation>
<translation id="3527085408025491307">Folda</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Tumia nenosiri kwa:</translation>
<translation id="3549644494707163724">Simba kwa njia fiche data yote iliyosawazishwa kwa kaulisiri yako binafsi ya usawazishaji</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> zaidi...</translation>
+<translation id="3555561725129903880">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama kinatoka katika <ph name="DOMAIN2" />. Hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Muunganisho wako si wa faragha</translation>
<translation id="3583757800736429874">Rudia Hatua</translation>
<translation id="3586931643579894722">Ficha maelezo</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Onyesha thamani</translation>
<translation id="3630155396527302611">Ikiwa tayari imeorodheshwa kuwa programu inayoruhusiwa kufikia mtandao, jaribu
kuiondoa kwenye orodha kisha uiongeze tena.</translation>
+<translation id="3638794133396384728">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama kimekwisha muda. Hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. Saa ya kompyuta yako imewekwa kuwa <ph name="CURRENT_TIME" /> kwa sasa. Je, ni sahihi? Ikiwa sivyo, unapaswa kurekebisha saa ya mfumo wako kisha uonyeshe upya ukurasa huu. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Hivi vipengele vya jaribio vinaweza kubadilika, kuvunjika, au kutoweka wakati wowote. Hatuhakikishi kabisa kuhusu kile kinachoweza kutokea ikiwa utawasha mojawapo ya majaribio haya, na hata kivinjari chako kinaweza kuchoma kighafla. Bila utani, kivinjari kinaweza kufuta data yako yote, au usalama na faragha yako inaweza kuathirika katika njia isiyotarajiwa. Majaribio yote unayoyawezesha yatawezeshwa kwa watumiaji wote wa kivinjari hiki. Tafadhali endelea kwa tahadhari.</translation>
<translation id="3650584904733503804">Uhalalishaji umefanikiwa</translation>
<translation id="3655670868607891010">Ikiwa unaliona tatizo hili mara kwa mara, jaribu <ph name="HELP_LINK" /> haya.</translation>
<translation id="3658742229777143148">Marekebisho</translation>
+<translation id="3678029195006412963">Ombi halikutiwa sahihi</translation>
<translation id="3681007416295224113">Maelezo ya cheti</translation>
<translation id="3693415264595406141">Nenosiri:</translation>
+<translation id="3696411085566228381">hamna</translation>
<translation id="3700528541715530410">Lo! Inaonekana huna ruhusa ya kufikia ukurasa huu.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Inapakia...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Kuwasha data ya simu au Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Kuangalia seva mbadala, kinga-mtandao na mipangilio ya DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Kiungo ulichonakili</translation>
-<translation id="3744899669254331632">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti ilituma kitambulisho kilichoharibika ambacho Chromium haiwezi kuchakata. Hitilafu na uvamizi wa mtandao kwa kawaida huwa vya muda, kwa hivyo ukurasa huu huenda utafanya kazi baadaye.</translation>
<translation id="375403751935624634">Utafsiri haukufanikiwa kwa sababu ya hitilafu ya seva.</translation>
<translation id="3759461132968374835">Huna uharibifu ulioripotiwa hivi karibuni. Uharibifu uliotokea wakati kuripoti kwa uharibifu kulipolemazwa hakutaonekana hapa.</translation>
<translation id="3788090790273268753">Cheti cha tovuti hii kitakwisha muda mwaka wa 2016, na msururu wa cheti una cheti kilichotiwa sahihi kwa kutumia SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Kitambulisho cha kifaa kinachokinzana</translation>
<translation id="3885155851504623709">Parish</translation>
<translation id="3901925938762663762">Kadi imekwisha muda</translation>
+<translation id="3910267023907260648">Umejaribu kufikia <ph name="DOMAIN" />, lakini seva iliwasilisha cheti kilichowekwa sahihi kwa kutumia algoriti dhaifu ya sahihi. Hii inamaanisha kuwa huenda stakabadhi za usalama za seva zilizowasilishwa ni za kughushi, na huenda seva siyo uliyoitarajia (huenda unawasiliana na mvamizi).<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama kitakwisha muda kuanzia kesho. Huenda hali hii ilitokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.}other{Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kitakwisha muda kuanzia siku # zijazo. Huenda hali hii ilitokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Imeshindwa kupakia hati ya PDF</translation>
<translation id="3963721102035795474">Hali ya Usomaji</translation>
+<translation id="397105322502079400">Inakokotoa...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> imezuiwa.</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{ukurasa 1 wa wavuti ulio karibu}other{kurasa # za wavuti zilizo karibu}}</translation>
<translation id="4021036232240155012">DNS ni huduma za mtandao ambazo hubadilisha jina la tovuti kuwa anwani yake ya Intaneti.</translation>
<translation id="4030383055268325496">Tendua kuongeza</translation>
-<translation id="4032534284272647190">Ufikiaji katika <ph name="URL" /> umekataliwa.</translation>
<translation id="404928562651467259">ONYO</translation>
<translation id="4058922952496707368">Kitufe "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Mteja na seva hazitumii toleo la kawaida la itifaki ya SSL au mipangilio ya kriptografia.</translation>
<translation id="4079302484614802869">Usanidi wa proksi umewekwa kutumia URL hati ya .pac, siyo seva proksi za kudumu.</translation>
<translation id="4103249731201008433">Namabari tambulishi ya kifaa ni batili</translation>
<translation id="4103763322291513355">Tembelea &lt;strong&gt;chrome://policy&lt;/strong&gt; ili kuona orodha ya URL zilizoondolewa idhini na sera zingine zinazosimamiwa na msimamizi wako wa mfumo.</translation>
+<translation id="4110615724604346410">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama kina hitilafu. Hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Upeo wa sera hauwezi kutumika.</translation>
+<translation id="4118212371799607889">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na Chromium. Hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{Nyingine 1 }other{Nyingine #}}</translation>
<translation id="4130226655945681476">Kukagua kebo za mtandao, modemu au kisambaza data</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Je, unataka Chromium ihifadhi kadi hii?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Kimelemazwa</translation>
<translation id="4196861286325780578">Rudia hatua</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Kuangalia mipangilio ya kinga-mtandao na kinga-virusi<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{hamna}=1{Programu 1 ($1)}=2{Programu 2 ($1, $2)}other{Programu # ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Mivurugo</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Jaribu kutumia zana ya Kuchunguza Mtandao<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">La</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Hakuna jina la mtumiaji)</translation>
<translation id="4300246636397505754">Mapendekezo ya wazazi</translation>
<translation id="4304224509867189079">Ingia</translation>
+<translation id="432290197980158659">Seva hii iliwasilisha cheti ambacho hakilingani na vipengele vilivyojengewa ndani. Vipengele hivi vimejumuishwa kwenye baadhi ya tovuti za usalama wa juu ili kukulinda. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Haikupata makala</translation>
+<translation id="4331708818696583467">Si Salama</translation>
<translation id="4372948949327679948">Thamani <ph name="VALUE_TYPE" /> inayotarajiwa.</translation>
-<translation id="4377125064752653719">Ulijaribu kufikia <ph name="DOMAIN" />, lakini cheti kilichowasilishwa na seva kimebatilishwa na mtoaji wacho. Huku ni kumaanisha kuwa stakabadhi za usalama zilizowasilishwa na seva hii hazifai kuaminiwa kabisa. Huenda ukawa unawasiliana na mshabulizi.</translation>
<translation id="4381091992796011497">Jina la mtumiaji:</translation>
<translation id="4394049700291259645">Zima</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> hadi <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">matokeo ya utafutaji</translation>
-<translation id="4424024547088906515">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na Chrome. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> haikukubali cheti chako cha kuingia katika akaunti, au huenda hukutoa cheti.</translation>
<translation id="443673843213245140">Matumizi ya proksi yamelemazwa lakini usanidi wa proksi wazi umebainishwa.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Unaona ujumbe huu kwa sababu Google SafeSites imewashwa.</translation>
@@ -323,34 +339,39 @@
<translation id="4522570452068850558">Maelezo</translation>
<translation id="4558551763791394412">Jaribu kuzima viendelezi vyako.</translation>
<translation id="4587425331216688090">Ungependa kuondoa anwani kutoka kwenye Chrome?</translation>
+<translation id="4589078953350245614">Umejaribu kufikia <ph name="DOMAIN" />, lakini seva imewasilisha cheti kisicho sahihi. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Muunganisho wako kwenye <ph name="DOMAIN" /> umesimbwa kwa njia fiche kwa kutumia mipangilio ya kriptografia ya kisasa.</translation>
<translation id="4594403342090139922">Tendua Kufuta</translation>
+<translation id="4627442949885028695">Endelea kutoka kwenye kifaa kingine</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Unaangalia ukurasa wa kiendelezi.</translation>
-<translation id="467662567472608290">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kina hitilafu. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> ilizuiwa</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Muunganisho wako umekatizwa</translation>
-<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Inaendesha Zana ya Kuchunguza Mtandao wa Windows<ph name="END_LINK" /></translation>
+<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Kuendesha Zana ya Windows ya Kuchunguza Mtandao<ph name="END_LINK" /></translation>
<translation id="4726672564094551039">Pakia sera upya</translation>
<translation id="4728558894243024398">Mfumo wa uendeshaji</translation>
<translation id="4744603770635761495">Njia Tekelezi</translation>
<translation id="4756388243121344051">&amp;Historia</translation>
+<translation id="4759238208242260848">Vipakuliwa</translation>
<translation id="4764776831041365478">Ukurasa wa wavuti ulio <ph name="URL" /> unaweza kuwa haupatikani kwa muda au unaweza kuwa umehamishwa kabisa hadi anwani mpya ya wavuti.</translation>
<translation id="4771973620359291008">Hitilafu isiyojulikana imetokea.</translation>
<translation id="4782449893814226250">Uliwauliza wazazi wako ikiwa ni sawa kuutembelea ukurasa huu.</translation>
<translation id="4800132727771399293">Angalia tarehe yako ya kuisha muda na CVC na ujaribu tena</translation>
-<translation id="4807049035289105102">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti ilituma kitambulisho kilichoharibika ambacho Google Chrome haiwezi kushughulikia. Hitilafu na uvamizi wa mtandao kwa kawaida huwa vya muda, kwa hivyo ukurasa huu huenda ukafanya kazi baadaye.</translation>
<translation id="4813512666221746211">Hitilafu ya mtandao</translation>
<translation id="4816492930507672669">Sawazisha kwenye ukurasa</translation>
<translation id="4850886885716139402">Mwonekano</translation>
<translation id="4880827082731008257">Tafuta katika historia</translation>
+<translation id="4884656795097055129">Makala zaidi yataonekana muda ukifika.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{na ukurasa 1 zaidi wa wavuti}other{na kurasa # zaidi za wavuti}}</translation>
<translation id="4923417429809017348">Ukurasa huu umetafsiriwa kutoka katika lugha ambayo haijulikani hadi <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Sharti ibainishwe.</translation>
<translation id="4930497775425430760">Unaona ujumbe huu kwa sababu mzazi wako anahitaji kuidhinisha tovuti mpya unapotembelea kwa mara ya kwanza.</translation>
<translation id="495170559598752135">Vitendo</translation>
<translation id="4958444002117714549">Panua orodha</translation>
+<translation id="4962322354953122629">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na Chrome. Hii inatokana na uwekaji mipangilio usiofaa, au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Je, ungependa kutafsiri kutoka <ph name="ORIGINAL_LANGUAGE" /> kwenda <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Programu-jalizi hii haitumiki</translation>
<translation id="5002932099480077015">Ikiwashwa, Chrome itahifadhi nakala ya kadi yako kwenye kifaa hiki kwa ajili ya kujaza fomu haraka zaidi.</translation>
<translation id="5019198164206649151">Hifadhi la kucheleza liko katika hali mbaya</translation>
<translation id="5023310440958281426">Angalia sera za msimamizi wako</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Kuhusu Google Tafsiri</translation>
<translation id="5040262127954254034">Faragha</translation>
<translation id="5045550434625856497">Nenosiri lisilo sahihi</translation>
+<translation id="5056549851600133418">Makala kwa ajili yako</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Kuangalia anwani mbadala<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Cheti cha seva si sahihi kwa sasa.</translation>
<translation id="5089810972385038852">Jimbo</translation>
-<translation id="5094747076828555589">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na Chromium. Hii inaweza kusababishwa na kusanidi kusikofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="5095208057601539847">Mkoa</translation>
<translation id="5115563688576182185">(biti 64)</translation>
-<translation id="5122371513570456792">Imepata <ph name="NUMBER_OF_RESULTS" /><ph name="SEARCH_RESULTS" /> kwa '<ph name="SEARCH_STRING" />'.</translation>
<translation id="5141240743006678641">Simba kwa njia fiche manenosiri yaliyosawazishwa ukitumia stakabadhi zako za Google</translation>
<translation id="5145883236150621069">Msimbo wa hitilafu uko katika jibu la sera</translation>
<translation id="5171045022955879922">Tafuta au charaza URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Sehemu ya Alamisho</translation>
<translation id="5199729219167945352">Majaribio</translation>
<translation id="5251803541071282808">Wingu</translation>
+<translation id="5277279256032773186">Je, unatumia Chrome kazini? Kampuni zinaweza kudhibiti mipangilio ya Chrome ya wafanyikazi wao. Pata maelezo zaidi</translation>
<translation id="5299298092464848405">Hitilafu wakati wa kuchanganua sera</translation>
<translation id="5300589172476337783">Onyesha</translation>
<translation id="5308689395849655368">Kuripoti uharibifu kumelemazwa.</translation>
<translation id="5317780077021120954">Hifadhi</translation>
<translation id="5327248766486351172">Jina</translation>
+<translation id="5359637492792381994">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama si sahihi. Hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Imeshindwa kuhifadhi mipangilio ya sera</translation>
-<translation id="540969355065856584">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama si sahihi kwa sasa. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="5421136146218899937">Futa data ya kuvinjari...</translation>
<translation id="5430298929874300616">Ondoa alamisho</translation>
<translation id="5431657950005405462">Faili yako haikupatikana</translation>
<translation id="5435775191620395718">Inaonyesha historia kutoka kifaa hiki. <ph name="BEGIN_LINK" />Pata maelezo zaidi<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Kwa sasa mapendekezo ya maudhui yaliyowekwa mapendeleo yamezimwa, kwa sababu data yako iliyosawazishwa inalindwa kwa kauli ya siri maalum.</translation>
<translation id="5439770059721715174">Hitilafu katika uhalalishaji wa Skima " <ph name="ERROR_PATH" /> ": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Ukurasa wa <ph name="HOST_NAME" /> hii haukupatikana</translation>
<translation id="5455374756549232013">Muhuri wa muda wa sera mbaya</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Ungependa kuondoka kwenye tovuti hii?</translation>
<translation id="5629630648637658800">Imeshindwa kupakia mipangilio ya sera</translation>
<translation id="5631439013527180824">Ishara ya usimamizi wa kifaa batili</translation>
-<translation id="5650551054760837876">Matokeo ya utafutaji hayakupatikana.</translation>
<translation id="5677928146339483299">Vilivyozuiwa</translation>
<translation id="5710435578057952990">Utambulisho wa tovuti hii haujathibitishwa.</translation>
<translation id="5720705177508910913">Mtumiaji wa sasa</translation>
+<translation id="572328651809341494">Vichupo vya hivi majuzi</translation>
<translation id="5784606427469807560">Kulikuwa na tatizo wakati wa kuthibitisha kadi yako. Angalia muunganisho wako wa intaneti kisha ujaribu tena.</translation>
<translation id="5785756445106461925">Mbali na hayo, ukurasa huu una rasilimali nyingine zisizo salama. Rasilimali hizi zinaweza kuangaliwa na watu wengine wanaosafiri, na zinaweza kurekebishwa na mvamizi kubadilisha mwonekano wa ukurasa.</translation>
+<translation id="5786044859038896871">Ungependa kujaza maelezo ya kadi yako?</translation>
+<translation id="5803412860119678065">Ungependa kujaza maelezo ya <ph name="CARD_DETAIL" /> yako?</translation>
<translation id="5810442152076338065">Muunganisho wako kwenye <ph name="DOMAIN" /> umesimbwa kwa njia fiche kwa kutumia mipangilio ya kriptografia ya zamani.</translation>
<translation id="5813119285467412249">Rudia Kuongeza</translation>
+<translation id="5814352347845180253">Utapoteza idhini ya kufikia maudhui ya kulipiwa kutoka kwenye <ph name="SITE" /> na tovuti nyingine.</translation>
+<translation id="5843436854350372569">Umejaribu kufikia <ph name="DOMAIN" />, lakini seva iliwasilisha cheti chenye ufunguo duni. Huenda mvamizi alivunja ufunguo wa faragha, na huenda seva si ile uliyoitarajia (huenda unawasiliana na mvamizi).<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Unaona ujumbe huu kwa sababu msimamizi wako amezuia tovuti hii.</translation>
<translation id="5857090052475505287">Folda Mpya</translation>
<translation id="5869405914158311789">Tovuti hii haiwezi kufikiwa</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Mapendekezo ya Wazazi</translation>
<translation id="59107663811261420">Aina hii ya kadi haiwezi kutumiwa na Google Payments kwa muuzaji huyu. Tafadhali teua kadi tofauti.</translation>
<translation id="59174027418879706">Imewashwa</translation>
+<translation id="5926846154125914413">Utapoteza idhini ya kufikia maudhui ya kulipiwa kutoka kwenye tovuti nyingine.</translation>
<translation id="5966707198760109579">Juma</translation>
<translation id="5967867314010545767">Ondoa kwenye historia</translation>
<translation id="5975083100439434680">Fifiza</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Otomatiki</translation>
<translation id="6042308850641462728">Zaidi</translation>
<translation id="6060685159320643512">Tahadhari, majaribio haya yanaweza kusumbua</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{hamna}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Angalia kebo zozote na uwashe tena kisambaza data, modemu, au vifaa vingine vyovyote vya
mtandao ambavyo huenda unavitumia.</translation>
<translation id="614940544461990577">Jaribu:</translation>
<translation id="6150607114729249911">Lo! Unahitaji kuwauliza wazazi wako ikiwa ni sawa kuutembelea ukurasa huu.</translation>
<translation id="6151417162996330722">Cheti cha seva kina muda sahihi ambao ni mrefu sana.</translation>
-<translation id="6154808779448689242">Ishara ya sera iliyorejeshwa hailingani na ishara ya sasa</translation>
<translation id="6165508094623778733">Pata maelezo zaidi</translation>
<translation id="6203231073485539293">Angalia muunganisho wako wa Intaneti</translation>
<translation id="6218753634732582820">Je, ungependa kuondoa anwani kwenye Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Jaribu kuzima utabiri wa mtandao</translation>
<translation id="6337534724793800597">Chuja sera kwa jina</translation>
<translation id="6342069812937806050">Sasa hivi tu</translation>
+<translation id="6345221851280129312">ukubwa usiojulikana</translation>
<translation id="6355080345576803305">Kipindi cha umma kimebatilishwa</translation>
<translation id="6358450015545214790">Je, hii inamaanisha nini?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{Pendekezo jingine 1}other{Mapendekezo mengine #}}</translation>
<translation id="6387478394221739770">Unavutiwa na vipengee vipya vizuri vya Chrome? Jaribu kituo chetu cha beta katika chrome.com/beta.</translation>
-<translation id="641480858134062906"><ph name="URL" /> ilishindwa kupakia</translation>
+<translation id="6389758589412724634">Nafasi ya kuhifadhi kwenye Chromium iliisha ilipokuwa ikijaribu kuonyesha ukurasa huu wa wavuti.</translation>
+<translation id="6416403317709441254">Huwezi kutembelea <ph name="SITE" /> hivi sasa kwa sababu tovuti ilituma kitambulisho kilichoharibika ambacho Chromium haiwezi kuchakata. Hitilafu na uvamizi wa mtandao kwa kawaida huwa wa muda, kwa hivyo ukurasa huu huenda utafanya kazi baadaye. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Haiwezi kukagua ikiwa cheti kimebatilishwa.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> imekataa kuunganisha.</translation>
<translation id="6445051938772793705">Nchi</translation>
<translation id="6451458296329894277">Thibitisha kuwa Fomu Iwasilishwe Tena</translation>
<translation id="6458467102616083041">Imepuuzwa kwa sababu utafutaji chaguo-msingi unalemazwa kwa sera.</translation>
+<translation id="6462969404041126431">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama huenda kimebatilishwa. Huenda hali hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Sera za kifaa</translation>
<translation id="6489534406876378309">Anza kupakia matukio ya kuacha kufanya kazi</translation>
<translation id="6529602333819889595">Rudia Kufuta</translation>
+<translation id="6534179046333460208">Mapendekezo ya Wavuti kila Mahali</translation>
<translation id="6550675742724504774">Chaguo</translation>
+<translation id="6593753688552673085">chini ya <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">Chaguo za usimbaji fiche</translation>
<translation id="662080504995468778">Usiondoke</translation>
<translation id="6628463337424475685">Utafutaji wa <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu <ph name="BEGIN_LINK" />cheti hiki kimebatilishwa<ph name="END_LINK" />. Hitilafu na uvamizi wa mtandao kwa kawaida huwa wa muda, kwa hivyo ukurasa huu huenda utafanya kazi baadaye.</translation>
<translation id="6644283850729428850">Sera hii imepingwa.</translation>
+<translation id="6652240803263749613">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na mfumo wa uendeshaji wa kompyuta yako. Hali hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Badilisha Folda</translation>
<translation id="6660210980321319655">Imeripoti kiotomatiki <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Je, ungependa kuondoa pendekezo la fomu kwenye Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Iliyotangulia</translation>
<translation id="6710594484020273272">&lt;Andika neno unalotaka kutafuta&gt;</translation>
<translation id="6711464428925977395">Kuna hitilafu katika seva mbadala, au anwani siyo sahihi.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{hamna}=1{Kipengee 1}other{Vipengee #}}</translation>
<translation id="674375294223700098">Hitilafu isiyojulikana ya cheti cha seva.</translation>
<translation id="6753269504797312559">Thamani ya sera</translation>
<translation id="6757797048963528358">Kifaa chako kiko katika hali tuli.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Kiwango cha sera hakitumiki.</translation>
<translation id="6895330447102777224">Kadi yako imethibitishwa</translation>
<translation id="6897140037006041989">Programu ya Mtumiaji</translation>
-<translation id="6903907808598579934">Washa kipengele cha kusawazisha</translation>
<translation id="6915804003454593391">Mtumiaji:</translation>
<translation id="6957887021205513506">Cheti cha seva kinaonekana kuwa ghushi.</translation>
<translation id="6965382102122355670">Sawa</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Wilaya</translation>
<translation id="6973656660372572881">Seva zote za proksi thabiti na URL ya hati ya .pac zimebainishwa.</translation>
<translation id="6989763994942163495">Onyesha mipangilio ya kina...</translation>
+<translation id="7000990526846637657">Hakuna historia ya mambo uliyovinjari inayopatikana</translation>
+<translation id="7009986207543992532">Umejaribu kufikia <ph name="DOMAIN" />, lakini seva iliwasilisha cheti ambacho muda wake wa kutumika ni mrefu sana hivi kwamba hauaminiki. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">Huenda Akaunti yako ya Google ina aina nyingine za historia ya kuvinjari kwenye <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Manenosiri</translation>
-<translation id="7050187094878475250">Ulijaribu kufikia <ph name="DOMAIN" />, lakini seva ikawasilisha cheti ambacho muda wake sahihi ni mrefu sana wa kuweza kuaminika.</translation>
<translation id="7087282848513945231">Nchi</translation>
<translation id="7088615885725309056">Za awali</translation>
<translation id="7090678807593890770">Tafuta <ph name="LINK" /> kwenye Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Unaona ujumbe huu kwa sababu msimamizi wako anahitaji kuidhinisha tovuti mpya unapotembelea kwa mara ya kwanza.</translation>
<translation id="724975217298816891">Weka tarehe ya kuisha kwa muda wa matumizi na CVC ya <ph name="CREDIT_CARD" /> ili usasishe maelezo ya kadi yako. Baada ya kuthibitisha, maelezo ya kadi yako yatashirikiwa na tovuti hii.</translation>
<translation id="725866823122871198">Muunganisho wa faragha kwenye <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hauwezi kutambuliwa kwa sababu tarehe na wakati wa kompyuta yako (<ph name="DATE_AND_TIME" />) si sahihi.</translation>
-<translation id="7265986070661382626">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti <ph name="BEGIN_LINK" />hutumia ubandikaji wa cheti<ph name="END_LINK" />. Hitilafu na uvamizi wa mtandao kwa kawaida huwa wa muda, kwa hivyo ukurasa huu huenda utafanya kazi baadaye.</translation>
<translation id="7269802741830436641">Ukurasa huu wa wavuti una kitanzi cha kuelekeza upya</translation>
<translation id="7275334191706090484">Alamisho Zinazosimamiwa</translation>
<translation id="7298195798382681320">Zinazopendekezwa</translation>
-<translation id="7301833672208172928">Washa kipengele cha usawazishaji wa historia</translation>
+<translation id="7309308571273880165">Ripoti ya kuacha kufanya kazi iliyochukuliwa <ph name="CRASH_TIME" /> (kipakiwa kilichoombwa na mtumiaji bado hakijapakiwa)</translation>
<translation id="7334320624316649418">Rudia Kupanga Upya</translation>
<translation id="733923710415886693">Cheti cha seva hakikufichuliwa kupitia Uwazi wa Cheti.</translation>
+<translation id="7351800657706554155">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu cheti hiki kimebatilishwa. Hitilafu na uvamizi wa mtandao kwa kawaida huwa wa muda, kwa hivyo ukurasa huu huenda utafanya kazi baadaye. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Mbinu ya Amri</translation>
<translation id="7372973238305370288">matokeo ya utafutaji</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="7469372306589899959">Inathibitisha kadi</translation>
<translation id="7481312909269577407">Mbele</translation>
<translation id="7485870689360869515">Hakuna data iliyopatikana.</translation>
+<translation id="7508255263130623398">Kitambulisho cha sera ya kifaa kilichorejeshwa hakina kitu au hakilingani na kitambulisho cha kifaa kilichopo</translation>
<translation id="7514365320538308">Pakua</translation>
<translation id="7518003948725431193">Hakuna ukurasa wa wavuti uliopatikana kwa anwani hii ya wavuti: <ph name="URL" /></translation>
<translation id="7537536606612762813">Lazima</translation>
<translation id="7542995811387359312">Mjazo otomatiki wa kadi ya mkopo umelemazwa kwa sababu fomu hii haitumii muunganisho salama.</translation>
<translation id="7549584377607005141">Ukurasa huu wa wavuti unahitaji data ambayo uliingiza mapema ili ionyeshwe inavyostahili. Unaweza kutuma tena data hii, lakini kwa kufanya hivyo utarudia hatua yoyote ambayo ukurasa huu ulifanya hapo awali.</translation>
<translation id="7554791636758816595">Kichupo Kipya</translation>
-<translation id="7567204685887185387">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; huenda cheti chake cha usalama kimetolewa kwa njia ya ulaghai. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="7568593326407688803">Ukurasa huu umeandikwa kwa<ph name="ORIGINAL_LANGUAGE" />Je, ungependa kuutafsiri?</translation>
<translation id="7569952961197462199">Ungependa kuondoa kadi ya malipo kutoka kwenye Chrome?</translation>
<translation id="7578104083680115302">Lipa haraka kwenye tovuti na programu katika vifaa vyote ukitumia kadi ulizohifadhi kwenye Google.</translation>
+<translation id="7588950540487816470">Wavuti Kila Mahali</translation>
<translation id="7592362899630581445">Cheti cha seva kinakiuka vikwazo vya jina.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> haiwezi kushughulikia ombi hili kwa sasa.</translation>
<translation id="7600965453749440009">Kamwe usitafsiri <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="7637571805876720304">Je, ungependa kuondoa kadi ya mikopo kwenye Chromium?</translation>
<translation id="765676359832457558">Ficha mipangilio ya kina...</translation>
<translation id="7658239707568436148">Ghairi</translation>
+<translation id="7667346355482952095">Tokeni ya sera iliyoletwa haina chochote au hailingani na tokeni ya sasa</translation>
<translation id="7668654391829183341">Kifaa kisichojulikana</translation>
<translation id="7674629440242451245">Unavutiwa na vipengee vipya vizuri vya Chrome? Jaribu kituo chetu cha dev katika chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Nenda kwenye <ph name="SITE" /> (isiyo salama)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="780301667611848630">Sitaki</translation>
<translation id="7805768142964895445">Hali</translation>
<translation id="7813600968533626083">Ungependa kuondoa pendekezo la fomu kutoka kwenye Chrome?</translation>
+<translation id="7815407501681723534">Imepata matokeo <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ya '<ph name="SEARCH_STRING" />'</translation>
<translation id="785549533363645510">Hata hivyo, huonekani. Kuvinjari katika hali fiche hakufichi kuvinjari kwako kusionekane na mwajiri, mtoaji huduma wako wa intaneti, au tovuti unazotembelea.</translation>
<translation id="7887683347370398519">Angalia CVC yako na ujaribu tena</translation>
<translation id="7894616681410591072">Lo! Unahitaji ruhusa kutoka kwa <ph name="NAME" /> ili ufikie ukurasa huu.</translation>
-<translation id="790025292736025802"><ph name="URL" /> haikupatikana</translation>
<translation id="7912024687060120840">Katika Folda:</translation>
<translation id="7920092496846849526">Uliwauliza wazazi wako ikiwa ni sawa kuutembelea ukurasa huu.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="7995512525968007366">Hakijabainishwa</translation>
<translation id="8012647001091218357">Hatukuweza kuwafikia wazazi wako wakati huu. Tafadhali jaribu tena.</translation>
<translation id="8034522405403831421">Ukurasa huu ni wa lugha ya <ph name="SOURCE_LANGUAGE" />. Je, ungependa kuutasfiri kuwa <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Hakuna maingizo ya historia yaliyopatikana.</translation>
<translation id="8088680233425245692">Haikufaulu kuangalia makala.</translation>
+<translation id="8089520772729574115">chini ya MB 1</translation>
<translation id="8091372947890762290">Uwashaji unasubiri kwenye seva</translation>
+<translation id="8129262335948759431">kiasi kisichojulikana</translation>
<translation id="8131740175452115882">Thibitisha</translation>
<translation id="8134994873729925007"><ph name="BEGIN_ABBR" />Anwani ya DNS <ph name="END_ABBR" /> ya seva ya <ph name="HOST_NAME" /> haikupatikana.</translation>
<translation id="8149426793427495338">Kompyuta yako iko katika hali tuli.</translation>
@@ -604,6 +640,7 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="8201077131113104583">URL ya sasisho si sahihi kwa kiendelezi chenye Kitambulisho "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Mahali Palipohawilishwa:</translation>
<translation id="8225771182978767009">Mtu ambaye aliweka mipangilio ya kompyuta hii ameamua kuzuia tovuti hii.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Ukurasa unaotafuta ulitumia maelezo uliyoyaingiza. Kurudi kwenye ukurasa huo huenda kukasababisha tendo lolote ulilofanya lirudiwe. Je, ungependa kuendelea?</translation>
<translation id="8249320324621329438">Iliyoletwa mwisho:</translation>
<translation id="8261506727792406068">Futa</translation>
@@ -616,12 +653,17 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="8349305172487531364">Sehemu ya Alamisho</translation>
<translation id="8363502534493474904">Kuzima hali ya ndegeni</translation>
<translation id="8364627913115013041">Haijawekwa.</translation>
+<translation id="8380941800586852976">Hatari</translation>
<translation id="8412145213513410671">Mivurugo ( <ph name="CRASH_COUNT" /> )</translation>
<translation id="8412392972487953978">Lazima uingize kaulisiri ile ile mara mbili.</translation>
<translation id="8428213095426709021">Mipangilio</translation>
+<translation id="8433057134996913067">Kufanya hivyo kutakuondoa kwenye tovuti nyingi.</translation>
<translation id="8437238597147034694">Tendua hatua</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{Kadi 1 ya mikopo}other{Kadi # za mikopo}}</translation>
+<translation id="8483780878231876732">Ili utumie kadi kutoka kwenye Akaunti yako ya Google, ingia katika Chrome</translation>
<translation id="8488350697529856933">Inatumika kwenye</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> imechukua muda mrefu kupakia.</translation>
+<translation id="852346902619691059">Seva hii haikuweza kuthibitisha kwamba ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na mfumo wa uendeshaji wa kifaa chako. Hii inatokana na uwekaji mipangilio usiofaa au mvamizi kuingilia muunganisho wako. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Aina hii ya kadi haiwezi kutumiwa na Google Payments. Tafadhali teua kadi tofauti.</translation>
<translation id="8550022383519221471">Huduma ya ulinganishaji haipatikani kwa kikoa chako.</translation>
<translation id="8553075262323480129">Tafsiri imeshindwa kwa sababu lugha ya ukurasa isingeweza kuthibitishwa.</translation>
@@ -633,15 +675,12 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="8647750283161643317">Weka upya zote kwa chaguo-msingi</translation>
<translation id="8680787084697685621">Maelezo ya kuingia kwenye akaunti yamechina.</translation>
<translation id="8703575177326907206">Muunganisho wako kwa <ph name="DOMAIN" /> haujasimbwa.</translation>
-<translation id="8713130696108419660">Sahihi mbaya ya mwanzo</translation>
<translation id="8725066075913043281">Jaribu tena</translation>
<translation id="8728672262656704056">Unavinjari katika hali fiche.</translation>
<translation id="8730621377337864115">Nimemaliza</translation>
<translation id="8738058698779197622">Ili kutambua muunganisho salama, saa yako inahitaji kuwekwa sahihi. Hii ni kwa sababu vyeti ambavyo tovuti hutumia kujitambua ni sahihi kwa vipindi mahususi pekee. Kwa kuwa saa ya kifaa chako si sahihi, Chromium haiwezi kuthibitisha vyeti hivi.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;anwani ya DNS&lt;/abbr&gt; haikupatikana. Tatizo linachunguzwa.</translation>
-<translation id="8741995161408053644">Huenda Akaunti yako ya Google ina aina nyingine za historia ya kuvinjari kwenye <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">Rudia kufuta</translation>
-<translation id="8790687370365610530">Ili upate maudhui yanayokufaa yanayopendekezwa na Google, washa kipengele cha usawazishaji wa historia.</translation>
<translation id="8798099450830957504">Chaguo Msingi</translation>
<translation id="8804164990146287819">Sera ya Faragha</translation>
<translation id="8820817407110198400">Alamisho</translation>
@@ -663,13 +702,11 @@ Hebu! Huenda hali fiche <ph name="SHORTCUT_KEY" /> ikakufaa wakati ujao.</transl
<translation id="8971063699422889582">Cheti cha seva kimechina.</translation>
<translation id="8987927404178983737">Mwezi</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Seva imewasilisha cheti ambacho hakikufichuliwa hadharani kwa kutumia sera ya Uwazi wa Cheti. Hili ni hitaji kwa baadhi ya vyeti, ili kuhakikisha kwamba ni cha kuaminika na kulinda dhidi ya wavamizi.</translation>
<translation id="9001074447101275817">Seva mbadala ya <ph name="DOMAIN" /> inahitaji jina la mtumiaji na nenosiri.</translation>
<translation id="901974403500617787">Alama zinazotumika katika mfumo mzima zinaweza kuwekwa na mmiliki pekee: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Ukurasa huu umetafsiriwa kwenda <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">Tumia huduma ya kutabiri ili upakie kurasa kwa haraka zaidi</translation>
<translation id="9039213469156557790">Mbali na hayo, ukurasa huu una rasilimali nyingine zisizo salama. Rasilimali hizi zinaweza kuangaliwa na watu wengine wanaosafiri, na zinaweza kurekebishwa na mvamizi kubadilisha tabia ya ukurasa.</translation>
-<translation id="9049981332609050619">Ulijaribu kufikia <ph name="DOMAIN" />, lakini seva iliwasilisha cheti batili.</translation>
<translation id="9050666287014529139">Kaulisiri</translation>
<translation id="9065203028668620118">Badilisha</translation>
<translation id="9092364396508701805">Ukurasa wa <ph name="HOST_NAME" /> haufanyi kazi</translation>
diff --git a/chromium/components/strings/components_strings_ta.xtb b/chromium/components/strings/components_strings_ta.xtb
index 6b327a1af53..6a38fc5eb2c 100644
--- a/chromium/components/strings/components_strings_ta.xtb
+++ b/chromium/components/strings/components_strings_ta.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ta">
+<translation id="1008557486741366299">இபà¯à®ªà¯‹à®¤à¯ இலà¯à®²à¯ˆ </translation>
<translation id="1015730422737071372">கூடà¯à®¤à®²à¯ விவரஙà¯à®•à®³à¯ˆ வழஙà¯à®•à®µà¯à®®à¯</translation>
<translation id="1032854598605920125">கடிகாரதà¯à®¤à®¿à®à¯ˆà®¯à®¿à®²à¯ à®à¯à®´à®±à¯à®±à¯</translation>
<translation id="1038842779957582377">அறியபà¯à®ªà®Ÿà®¾à®¤ பெயரà¯</translation>
+<translation id="1053591932240354961">Google Chrome ஆல௠à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®¾à®¤ à®à®¿à®¤à¯ˆà®¨à¯à®¤ அனà¯à®®à®¤à®¿à®à¯ à®à®¾à®©à¯à®±à¯à®•à®³à¯ˆ இணையதளம௠அனà¯à®ªà¯à®ªà®¿à®¯à¯à®³à¯à®³à®¤à®¾à®²à¯, இபà¯à®ªà¯‹à®¤à¯ <ph name="SITE" />கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. பà¯à®¤à¯à®µà®¾à®• நெடà¯à®µà¯à®°à¯à®•à¯ பிழைகளà¯à®®à¯ பாதிபà¯à®ªà¯à®•à®³à¯à®®à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à¯‡. இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®¿à®±à®¿à®¤à¯ நேரம௠கழிதà¯à®¤à¯à®à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;à®à¯‡à®°à¯à®¤à¯à®¤à®²à¯ˆà®à¯ à®à¯†à®¯à®²à¯à®¤à®µà®¿à®°à¯</translation>
<translation id="10614374240317010">à®à®ªà¯à®ªà¯‹à®¤à¯à®®à¯ à®à¯‡à®®à®¿à®•à¯à®•à®¾à®¤à®µà¯ˆ</translation>
-<translation id="1064422015032085147">இணையபà¯à®ªà®•à¯à®•à®®à¯ ஹோஸà¯à®Ÿà¯ à®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ பணிà®à¯à®à¯à®®à¯ˆà®¯à®¾à®²à¯ பாதிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ பராமரிபà¯à®ªà¯à®ªà¯ பணி நடைபெறà¯à®±à¯à®•à¯ கà¯à®£à¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.
- மிகà¯à®¤à®¿à®¯à®¾à®© டà¯à®°à®¾à®ƒà®ªà®¿à®•à¯ உரà¯à®µà®¾à®µà®¤à¯ˆà®¤à¯ தடà¯à®•à¯à®•à®µà¯à®®à¯, நிலைமை மோà®à®®à®Ÿà¯ˆà®µà®¤à¯ˆà®¤à¯ தவிரà¯à®•à¯à®•à®µà¯à®®à¯,
- இநà¯à®¤ URLகà¯à®•à®¾à®© கோரிகà¯à®•à¯ˆà®•à®³à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®•à®¤à¯ தடைà®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®©.</translation>
<translation id="106701514854093668">டெஸà¯à®•à¯à®Ÿà®¾à®ªà¯ பà¯à®•à¯à®®à®¾à®°à¯à®•à¯à®•à¯à®•à®³à¯</translation>
<translation id="1080116354587839789">அகலதà¯à®¤à®¿à®±à¯à®•à¯à®ªà¯ பà¯à®°à¯à®¤à¯à®¤à¯</translation>
+<translation id="1103124106085518534">இபà¯à®ªà¯‹à®¤à¯ à®®à¯à®Ÿà®¿à®¨à¯à®¤à®¤à¯</translation>
<translation id="1103523840287552314">à®à®ªà¯à®ªà¯‡à®¾à®¤à¯à®®à¯ இநà¯à®¤ à®®à¯à®´à®¿à®¯à¯ˆ மொழிபெயர௠<ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">இத௠தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¾à®²à¯, விரைவாக படிவஙà¯à®•à®³à¯ˆ நிரபà¯à®ªà¯à®µà®¤à®±à¯à®•à®¾à®•, Chrome இநà¯à®¤ காரà¯à®Ÿà®¿à®©à¯ பிரதியை à®à®¾à®¤à®©à®¤à¯à®¤à®¿à®²à¯ à®à¯‡à®®à®¿à®•à¯à®•à¯à®®à¯.</translation>
+<translation id="1111153019813902504">à®à®®à¯€à®ªà®¤à¯à®¤à®¿à®¯ பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®•à®³à¯</translation>
<translation id="1113869188872983271">&amp;மறà¯à®µà®°à®¿à®à¯ˆà®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à¯ˆà®à¯ à®à¯†à®¯à®²à¯à®¤à®µà®¿à®°à¯</translation>
+<translation id="1126551341858583091">அகà®à¯ à®à¯‡à®®à®¿à®ªà¯à®ªà®•à®¤à¯à®¤à®¿à®²à¯ <ph name="CRASH_SIZE" /> அளவ௠உளà¯à®³à®¤à¯.</translation>
<translation id="112840717907525620">கà¯à®³à¯à®•à¯ˆ தறà¯à®•à®¾à®²à®¿à®• à®à¯‡à®®à®¿à®ªà¯à®ªà¯ à®à®°à®¿à®¯à®¾à®• உளà¯à®³à®¤à¯</translation>
<translation id="113188000913989374"><ph name="SITE" /> தெரிவிபà¯à®ªà®¤à¯:</translation>
<translation id="1132774398110320017">Chrome தனà¯à®©à®¿à®°à®ªà¯à®ªà®¿ அமைபà¯à®ªà¯à®•à®³à¯...</translation>
-<translation id="1150979032973867961">இத௠<ph name="DOMAIN" /> தான௠à®à®©à¯à®ªà®¤à¯ˆ இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ உஙà¯à®•à®³à¯ கணினியின௠இயகà¯à®• à®®à¯à®±à¯ˆà®®à¯ˆ நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="1152921474424827756"><ph name="URL" /> இன௠<ph name="BEGIN_LINK" />உரà¯à®µà®¾à®•à¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à®¾à®© தறà¯à®•à®¾à®²à®¿à®•à®à¯ à®à¯‡à®®à®¿à®ªà¯à®ªà¯ நகலை<ph name="END_LINK" /> அணà¯à®•à®µà¯à®®à¯</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> à®à®¤à®¿à®°à¯à®ªà®¾à®°à®¾à®¤ விதமாக இணைபà¯à®ªà¯ˆ நிறà¯à®¤à¯à®¤à®¿à®¯à®¤à¯.</translation>
<translation id="1161325031994447685">வைஃபையà¯à®Ÿà®©à¯ மீணà¯à®Ÿà¯à®®à¯ இணைதà¯à®¤à®²à¯</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">அகறà¯à®±à¯</translation>
<translation id="1201402288615127009">அடà¯à®¤à¯à®¤à®¤à¯</translation>
<translation id="1201895884277373915">இநà¯à®¤à®¤à¯ தளம௠கூடà¯à®¤à®²à®¾à®• வழஙà¯à®•à¯à®ªà®µà¯ˆ</translation>
-<translation id="121201262018556460">நீஙà¯à®•à®³à¯ <ph name="DOMAIN" /> ஠அடைய à®®à¯à®¯à®±à¯à®à®¿à®¤à¯à®¤à¯€à®°à¯à®•à®³à¯ ஆனால௠à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ ஒர௠வலà¯à®µà®±à¯à®± விà®à¯ˆ கொணà¯à®Ÿ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ வழஙà¯à®•à®¿à®¯à®¤à¯. தனிபà¯à®ªà®Ÿà¯à®Ÿ விà®à¯ˆà®¯à¯ˆ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ களவாடி இரà¯à®ªà¯à®ªà®¤à®¾à®²à¯, à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ நீஙà¯à®•à®³à¯ à®à®¤à®¿à®°à¯à®ªà®¾à®°à¯à®¤à¯à®¤ (தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯à®Ÿà®©à¯ நீஙà¯à®•à®³à¯ தகவல௠பரிமாறà¯à®±à®®à¯ à®à¯†à®¯à¯à®¤à¯à®•à¯à®£à¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯) à®à¯‡à®µà¯ˆà®¯à®•à®®à®¾à®• இலà¯à®²à®¾à®®à®²à¯ இரà¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
+<translation id="1206967143813997005">தà¯à®Ÿà®•à¯à®•à®•à¯ கையà¯à®ªà¯à®ªà®®à¯ à®à®°à®¿à®¯à®¾à®©à®¤à®²à¯à®²</translation>
+<translation id="1209206284964581585">இபà¯à®ªà¯‹à®¤à¯ˆà®•à¯à®•à¯ மறை</translation>
<translation id="1219129156119358924">à®®à¯à®±à¯ˆà®®à¯ˆà®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà¯</translation>
<translation id="1227224963052638717">அறியாத கà¯à®³à¯à®•à¯ˆ.</translation>
<translation id="1227633850867390598">மதிபà¯à®ªà¯ˆ மறை</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">ஆமà¯</translation>
<translation id="1430915738399379752">à®…à®à¯à®à®¿à®Ÿà¯à®•</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /><ph name="DOMAIN" /> இல௠பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®µà®¤à®±à¯à®•à®¾à®©<ph name="END_LINK" /> à®®à¯à®¯à®±à¯à®à®¿à®¯à¯ˆ தடà¯à®¤à¯à®¤à®¤à¯.</translation>
+<translation id="1491663344921578213">இணையதளமானத௠à®à®°à¯à®Ÿà®¿à®ƒà®ªà®¿à®•à¯‡à®Ÿà¯ பினà¯à®©à®¿à®™à¯à®•à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®µà®¤à®¾à®²à¯, இபà¯à®ªà¯‹à®¤à¯ <ph name="SITE" />கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. பà¯à®¤à¯à®µà®¾à®• நெடà¯à®µà¯à®°à¯à®•à¯ பிழைகளà¯à®®à¯ பாதிபà¯à®ªà¯à®•à®³à¯à®®à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à¯‡. இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®¿à®±à®¿à®¤à¯ நேரம௠கழிதà¯à®¤à¯à®à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à®¿à®©à¯ à®à¯‡à®®à®¿à®¤à¯à®¤ நகலைக௠காடà¯à®Ÿà¯ (அதாவதà¯, காலாவதியானத௠à®à®© அறியபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯).</translation>
<translation id="1519264250979466059">உரà¯à®µà®¾à®•à¯à®•à®¿à®¯ தேதி</translation>
<translation id="1549470594296187301">இநà¯à®¤ à®…à®®à¯à®à®¤à¯à®¤à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ JavaScript இயகà¯à®•à®ªà¯à®ªà®Ÿ வேணà¯à®Ÿà¯à®®à¯.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">பிணைய உளà¯à®³à®®à¯ˆà®µà¯ தவறானத௠மேலà¯à®®à¯ அதை இறகà¯à®•à¯à®®à®¤à®¿ à®à¯†à®¯à¯à®¯ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="1644574205037202324">வரலாறà¯</translation>
<translation id="1645368109819982629">ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ நெறிமà¯à®±à¯ˆ</translation>
-<translation id="1655462015569774233">{1,plural, =1{இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ தான௠<ph name="DOMAIN" /> à®à®©à¯à®ªà®¤à¯ˆ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ நேறà¯à®±à¯ காலாவதியானதà¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. உஙà¯à®•à®³à¯ கணினியின௠கடிகாரம௠தறà¯à®ªà¯‹à®¤à¯ <ph name="CURRENT_DATE" /> à®à®© அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. அத௠à®à®°à®¿à®¯à®¾à®• இரà¯à®•à¯à®•à®¿à®±à®¤à®¾? இலà¯à®²à¯ˆ à®à®©à¯à®±à®¾à®²à¯, உஙà¯à®•à®³à¯ à®®à¯à®±à¯ˆà®®à¯ˆà®¯à®¿à®©à¯ கடிகாரதà¯à®¤à¯ˆà®à¯ à®à®°à®¿à®à¯†à®¯à¯à®¤à¯, பினà¯à®©à®°à¯ இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯.}other{இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ தான௠<ph name="DOMAIN" /> à®à®©à¯à®ªà®¤à¯ˆ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ # நாடà¯à®•à®³à¯à®•à¯à®•à¯ à®®à¯à®©à¯à®ªà¯ காலாவதியானதà¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. உஙà¯à®•à®³à¯ கணினியின௠கடிகாரம௠தறà¯à®ªà¯‹à®¤à¯ <ph name="CURRENT_DATE" /> à®à®© அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. அத௠à®à®°à®¿à®¯à®¾à®• இரà¯à®•à¯à®•à®¿à®±à®¤à®¾? இலà¯à®²à¯ˆ à®à®©à¯à®±à®¾à®²à¯, உஙà¯à®•à®³à¯ à®®à¯à®±à¯ˆà®®à¯ˆà®¯à®¿à®©à¯ கடிகாரதà¯à®¤à¯ˆà®à¯ à®à®°à®¿à®à¯†à®¯à¯à®¤à¯, பினà¯à®©à®°à¯ இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯.}}</translation>
<translation id="1676269943528358898">வழகà¯à®•à®®à®¾à®•, <ph name="SITE" /> உஙà¯à®•à®³à¯ தகவலைப௠பாதà¯à®•à®¾à®ªà¯à®ªà®¤à®±à¯à®•à®¾à®• à®®à¯à®±à¯ˆà®®à¯ˆà®¯à®¾à®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯. இநà¯à®¤ à®®à¯à®±à¯ˆ <ph name="SITE" /> உடன௠இணைவதறà¯à®•à¯ Google Chrome à®®à¯à®¯à®±à¯à®à®¿à®¤à¯à®¤à®ªà¯‹à®¤à¯ வழகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ மாறான மறà¯à®±à¯à®®à¯ தவறான நறà¯à®à®¾à®©à¯à®±à®¿à®¤à®´à¯à®•à®³à¯ˆ இணையதளம௠வழஙà¯à®•à®¿à®¯à®¤à¯. தாகà¯à®•à¯à®ªà®µà®°à¯ தனà¯à®©à¯ˆ <ph name="SITE" /> ஆகக௠காடà¯à®Ÿ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à¯à®®à¯ போத௠அலà¯à®²à®¤à¯ இணைபà¯à®ªà¯ˆ வைஃபை உளà¯à®¨à¯à®´à¯ˆà®µà¯à®¤à¯ திரை கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®®à¯ போத௠இத௠à®à®±à¯à®ªà®Ÿà®²à®¾à®®à¯. இரà¯à®ªà¯à®ªà®¿à®©à¯à®®à¯, தரவ௠à®à®¤à¯à®µà¯à®®à¯ பரிமாறà¯à®±à®ªà¯à®ªà®Ÿà¯à®µà®¤à®±à¯à®•à¯ à®®à¯à®©à¯ Google Chrome இணைபà¯à®ªà¯ˆ நிறà¯à®¤à¯à®¤à®¿à®¯à®¤à®¾à®²à¯ உஙà¯à®•à®³à¯ தகவல௠பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®•à®µà¯‡ இரà¯à®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="168841957122794586">à®à¯‡à®µà¯ˆà®¯à®• à®à®¾à®©à¯à®±à®¿à®¤à®´à®¿à®²à¯ வலà¯à®µà®±à¯à®± கà¯à®±à®¿à®¯à¯€à®Ÿà¯à®Ÿà®¾à®•à¯à®• விà®à¯ˆ இரà¯à®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="1701955595840307032">பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பெறà¯à®•</translation>
-<translation id="1706954506755087368">{1,plural, =1{இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ தான௠<ph name="DOMAIN" /> à®à®©à¯à®ªà®¤à¯ˆ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ நாளை à®®à¯à®¤à®²à¯‡ à®à¯†à®²à¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à¯à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.}other{இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ தான௠<ph name="DOMAIN" /> à®à®©à¯à®ªà®¤à¯ˆ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ à®à®¤à®¿à®°à¯à®•à®¾à®²à®¤à¯à®¤à®¿à®²à¯ # நாடà¯à®•à®³à®¿à®²à¯ à®à®±à¯à®±à¯à®•à¯à®•à¯à®³à¯à®³à®ªà¯à®ªà®Ÿà¯à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">கணினி நிரà¯à®µà®¾à®•à®¿à®¯à¯ˆà®¤à¯ தொடரà¯à®ªà¯à®•à¯à®³à¯à®³à®µà¯à®®à¯</translation>
<translation id="17513872634828108">தாவலà¯à®•à®³à¯ˆà®¤à¯ திற</translation>
<translation id="1753706481035618306">பகà¯à®• à®à®£à¯</translation>
-<translation id="1761412452051366565">Google பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à¯à®®à¯ தனிபà¯à®ªà®¯à®©à®¾à®•à¯à®•à®¿à®¯ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பெற, ஒதà¯à®¤à®¿à®à¯ˆà®µà¯ˆ இயகà¯à®•à®µà¯à®®à¯.</translation>
-<translation id="1763864636252898013">இத௠<ph name="DOMAIN" /> தான௠à®à®©à¯à®ªà®¤à¯ˆ இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ உஙà¯à®•à®³à¯ à®à®¾à®¤à®©à®¤à¯à®¤à®¿à®©à¯ இயகà¯à®• à®®à¯à®±à¯ˆà®®à¯ˆ நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows நெடà¯à®µà¯à®°à¯à®•à¯ டயகà¯à®©à®¸à¯à®Ÿà®¿à®•à¯à®¸à¯ கரà¯à®µà®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">உஙà¯à®•à®³à®¿à®©à¯ ஒதà¯à®¤à®¿à®à¯ˆ à®à¯à®±à¯à®±à¯à®Ÿà®°à¯ˆà®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">நீஙà¯à®•à®³à¯ à®à®®à¯€à®ªà®¤à¯à®¤à®¿à®²à¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®Ÿ பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®•à®³à¯ இஙà¯à®•à¯‡ தோனà¯à®±à¯à®®à¯.</translation>
<translation id="1821930232296380041">தவறான கோரிகà¯à®•à¯ˆ அலà¯à®²à®¤à¯ கோரிகà¯à®•à¯ˆ அளவà¯à®°à¯à®•à¯à®•à®³à¯</translation>
<translation id="1838667051080421715">இணையப௠பகà¯à®•à®¤à¯à®¤à®¿à®©à¯ மூலதà¯à®¤à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯.</translation>
<translation id="1871208020102129563">நிலையான பà¯à®°à®¾à®•à¯à®¸à®¿ à®à¯‡à®µà¯ˆà®¯à®•à®™à¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ பà¯à®°à®¾à®•à¯à®¸à®¿ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯, .pac ஸà¯à®•à®¿à®°à®¿à®ªà¯à®Ÿà¯ URL அலà¯à®².</translation>
<translation id="1883255238294161206">படà¯à®Ÿà®¿à®¯à®²à¯ˆà®à¯ à®à¯à®°à¯à®•à¯à®•à¯</translation>
<translation id="1898423065542865115">வடிகடà¯à®Ÿà¯à®¤à®²à¯</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> உஙà¯à®•à®³à¯ உளà¯à®¨à¯à®´à¯ˆà®µà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ à®à®±à¯à®•à®µà®¿à®²à¯à®²à¯ˆ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ உளà¯à®¨à¯à®´à¯ˆà®µà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ காலாவதியாகியிரà¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="194030505837763158"><ph name="LINK" /> கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®•</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®•à®³à¯</translation>
<translation id="1973335181906896915">தà¯à®Ÿà®°à®¾à®•à¯à®• பிழை</translation>
<translation id="1974060860693918893">மேமà¯à®ªà®Ÿà¯à®Ÿà®µà¯ˆ</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{மேலà¯à®®à¯ 1}other{மேலà¯à®®à¯ #}}</translation>
<translation id="2025186561304664664">பà¯à®°à®¾à®•à¯à®¸à®¿, தானியஙà¯à®•à®¿ உளà¯à®³à®®à¯ˆà®µà¯à®•à¯à®•à¯ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
<translation id="2030481566774242610"><ph name="LINK" /> à®à®•à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾?</translation>
<translation id="2031925387125903299">à®®à¯à®¤à®²à¯ à®®à¯à®±à¯ˆ நீஙà¯à®•à®³à¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®®à¯ பà¯à®¤à®¿à®¯ தளஙà¯à®•à®³à¯ˆ உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯à®•à®³à¯ அனà¯à®®à®¤à®¿à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯ à®à®©à¯à®ªà®¤à®¾à®²à¯ இநà¯à®¤à®à¯ à®à¯†à®¯à¯à®¤à®¿à®¯à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />பà¯à®°à®¾à®•à¯à®¸à®¿ மறà¯à®±à¯à®®à¯ ஃபயரà¯à®µà®¾à®²à¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®¤à¯à®¤à®²à¯<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ஜிப௠கà¯à®±à®¿à®¯à¯€à®Ÿà¯</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 பரிநà¯à®¤à¯à®°à¯ˆ}other{# பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯}}</translation>
<translation id="2065985942032347596">à®…à®™à¯à®•à¯€à®•à®¾à®°à®®à¯ தேவைபà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯</translation>
<translation id="2079545284768500474">à®à¯†à®¯à®²à¯à®¤à®µà®¿à®°à¯</translation>
<translation id="20817612488360358">கணினி பà¯à®°à®¾à®•à¯à®¸à®¿ அமைபà¯à®ªà¯à®•à®³à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. வெளிபà¯à®ªà®Ÿà¯ˆà®¯à®¾à®© பà¯à®°à®¾à®•à¯à®¸à®¿ உளà¯à®³à®®à¯ˆà®µà¯à®®à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">பà¯à®•à¯à®®à®¾à®°à¯à®•à¯à®•à¯ˆ மாறà¯à®±à¯à®•</translation>
<translation id="2166049586286450108">à®®à¯à®´à¯ நிரà¯à®µà®¾à®•à®¿ அணà¯à®•à®²à¯</translation>
<translation id="2166378884831602661">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¾à®²à¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© இணைபà¯à®ªà¯ˆ வழஙà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
-<translation id="2171101176734966184"><ph name="DOMAIN" /> ஠அடைய à®®à¯à®¯à®±à¯à®à®¿ à®à¯†à®¯à¯à®¤à¯€à®°à¯à®•à®³à¯. ஆனால௠வலிமையறà¯à®± கையà¯à®ªà¯à®ª அலà¯à®•à®¾à®°à®¿à®¤à®®à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ கையà¯à®ªà¯à®ªà®®à®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯à®¤à¯. அதாவதà¯, à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯ பாதà¯à®•à®¾à®ªà¯à®ªà¯ நமà¯à®ªà®¿à®•à¯à®•à¯ˆà®à¯à®à®¾à®©à¯à®±à¯à®•à®³à¯ போலியானதாகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ மேலà¯à®®à¯ நீஙà¯à®•à®³à¯ à®à®¤à®¿à®°à¯à®ªà®¾à®°à¯à®¤à¯à®¤ (போலியான ஒனà¯à®±à¯à®Ÿà®©à¯ நீஙà¯à®•à®³à¯ தகவல௠பரிமாறà¯à®±à®®à¯ à®à¯†à®¯à¯à®¤à®¿à®°à¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯) à®à¯‡à®µà¯ˆà®¯à®•à®®à®¾à®• அநà¯à®¤ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ இலà¯à®²à®¾à®®à®²à®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="2181821976797666341">கà¯à®³à¯à®•à¯ˆà®•à®³à¯</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 à®®à¯à®•à®µà®°à®¿}other{# à®®à¯à®•à®µà®°à®¿à®•à®³à¯}}</translation>
<translation id="2212735316055980242">கà¯à®³à¯à®•à¯ˆ காணபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="2213606439339815911">உளà¯à®³à¯€à®Ÿà¯à®•à®³à¯ˆà®ªà¯ பெறà¯à®•à®¿à®±à®¤à¯...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> கிடைகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />கணà¯à®Ÿà®±à®¿à®¯à¯à®®à¯ பயனà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆà®ªà¯<ph name="END_LINK" /> பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ இணைபà¯à®ªà¯ˆà®à¯ à®à®°à®¿à®à¯†à®¯à¯à®¯à®µà¯à®®à¯</translation>
+<translation id="2239100178324503013">இபà¯à®ªà¯‹à®¤à¯‡ அனà¯à®ªà¯à®ªà¯</translation>
<translation id="225207911366869382">இநà¯à®¤ கà¯à®³à¯à®•à¯ˆà®•à¯à®•à®¾à®© மதிபà¯à®ªà¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="2262243747453050782">HTTP பிழை</translation>
<translation id="2282872951544483773">கிடைகà¯à®•à®¾à®¤ பரிà®à¯‹à®¤à®©à¯ˆà®•à®³à¯</translation>
<translation id="2292556288342944218">உஙà¯à®•à®³à¯ இணைய அணà¯à®•à®²à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="229702904922032456">ரூட௠அலà¯à®²à®¤à¯ இனà¯à®Ÿà®°à¯à®®à¯€à®Ÿà®¿à®¯à®Ÿà¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ காலாவதியானதà¯.</translation>
<translation id="230155334948463882">பà¯à®¤à®¿à®¯ அடà¯à®Ÿà¯ˆà®¯à®¾?</translation>
+<translation id="2305919008529760154"><ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. அதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ தவறான à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ வழஙà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" />கà¯à®•à¯à®ªà¯ பயனரà¯à®ªà¯†à®¯à®°à¯à®®à¯ கடவà¯à®à¯à®à¯à®²à¯à®²à¯à®®à¯ தேவை.</translation>
+<translation id="2318774815570432836"><ph name="SITE" /> இணையதளம௠HSTSà®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®µà®¤à®¾à®²à¯, இபà¯à®ªà¯‹à®¤à¯ அதà¯à®¤à®³à®¤à¯à®¤à®¿à®±à¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. நெடà¯à®µà¯à®°à¯à®•à¯ பிழைகளà¯à®®à¯ பாதிபà¯à®ªà¯à®•à®³à¯à®®à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à¯‡. இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®¿à®±à®¿à®¤à¯ நேரம௠கழிதà¯à®¤à¯à®à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155"><ph name="ENTRY_INDEX" /> அடà¯à®Ÿà®µà®£à¯ˆà®¯à®¿à®²à¯ தவறான பà¯à®•à¯à®®à®¾à®°à¯à®•à¯ பà¯à®±à®•à¯à®•à®£à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="2354001756790975382">பிற பà¯à®•à¯à®®à®¾à®°à¯à®•à¯à®¸à¯</translation>
<translation id="2359808026110333948">தà¯à®Ÿà®°à¯à®•</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" /> அனà¯à®±à¯ பெறà¯à®± à®à®¿à®¤à¯ˆà®µà¯ அறிகà¯à®•à¯ˆ பதிவேறà¯à®±à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="2367567093518048410">நிலை</translation>
+<translation id="2371153335857947666">{1,plural, =1{<ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ நேறà¯à®±à¯ காலாவதியாகிவிடà¯à®Ÿà®¤à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. உஙà¯à®•à®³à¯ கணினியின௠கடிகாரம௠தறà¯à®ªà¯‹à®¤à¯ <ph name="CURRENT_DATE" /> à®à®© அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. அத௠à®à®°à®¿à®¯à®¾à®• உளà¯à®³à®¤à®¾? இலà¯à®²à¯ˆà®¯à¯†à®©à®¿à®²à¯, கணினியின௠கடிகாரதà¯à®¤à¯ˆà®à¯ à®à®°à®¿à®à¯†à®¯à¯à®¤à¯, இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®µà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.}other{<ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ # நாடà¯à®•à®³à¯à®•à¯à®•à¯ à®®à¯à®©à¯ காலாவதியாகிவிடà¯à®Ÿà®¤à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. உஙà¯à®•à®³à¯ கணினியின௠கடிகாரம௠தறà¯à®ªà¯‹à®¤à¯ <ph name="CURRENT_DATE" /> à®à®© அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. அத௠à®à®°à®¿à®¯à®¾à®• உளà¯à®³à®¤à®¾? இலà¯à®²à¯ˆà®¯à¯†à®©à®¿à®²à¯,கணினியின௠கடிகாரதà¯à®¤à¯ˆà®à¯ à®à®°à®¿à®à¯†à®¯à¯à®¤à¯, இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®µà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">UI மாறà¯à®±à¯à®•à®³à¯ இலà¯à®²à¯ˆ</translation>
<translation id="2384307209577226199">நிறà¯à®µà®© இயலà¯à®ªà¯à®¨à®¿à®²à¯ˆ</translation>
-<translation id="238526402387145295">இபà¯à®ªà¯‹à®¤à¯ உஙà¯à®•à®³à®¾à®²à¯ <ph name="SITE" /> தளதà¯à®¤à¯ˆà®ªà¯ பாரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯, à®à®©à¯†à®©à®¿à®²à¯ இணையதளமானத௠<ph name="BEGIN_LINK" />HSTS à®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯<ph name="END_LINK" />. நெடà¯à®µà¯à®°à¯à®•à¯ பிழைகள௠மறà¯à®±à¯à®®à¯ தாகà¯à®•à¯à®¤à®²à¯à®•à®³à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à®¾à®•à¯à®®à¯, à®à®©à®µà¯‡ இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®¿à®±à®¿à®¤à¯ நேரம௠கழிதà¯à®¤à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="2386255080630008482">à®à¯‡à®µà¯ˆà®¯à®•à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ திரà¯à®®à¯à®ªà®ªà¯ பெறபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="2392959068659972793">மதிபà¯à®ªà¯à®®à¯ à®à®¤à¯à®µà¯à®®à¯ அமைகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ கà¯à®³à¯à®•à¯ˆà®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯</translation>
<translation id="2396249848217231973">&amp;நீகà¯à®•à¯à®¤à®²à¯ˆà®à¯ à®à¯†à®¯à®²à¯à®¤à®µà®¿à®°à¯</translation>
-<translation id="2413528052993050574">இத௠<ph name="DOMAIN" /> தான௠à®à®©à¯à®ªà®¤à¯ˆ இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ திரà¯à®®à¯à®ªà®ªà¯à®ªà¯†à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="2455981314101692989">இநà¯à®¤à®ªà¯ படிவதà¯à®¤à®¿à®±à¯à®•à®¾à®© தானியஙà¯à®•à¯ நிரபà¯à®ªà¯à®¤à®²à¯ˆ இநà¯à®¤ வலைபà¯à®ªà®•à¯à®•à®®à¯ à®®à¯à®Ÿà®•à¯à®•à®¿à®¯à¯à®³à¯à®³à®¤à¯.</translation>
+<translation id="2463739503403862330">நிரபà¯à®ªà¯</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />நெடà¯à®µà¯à®°à¯à®•à¯ டயகà¯à®©à®¸à¯à®Ÿà®¿à®•à¯à®¸à¯ கரà¯à®µà®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">தவறான தேடல௠URL.</translation>
<translation id="2491120439723279231">à®à¯‡à®µà¯ˆà®¯à®•à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à®¿à®²à¯ பிழைகள௠உளà¯à®³à®©.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">à®à®®à®°à¯à®ªà¯à®ªà®¿</translation>
<translation id="2674170444375937751">உஙà¯à®•à®³à¯ வரலாறà¯à®±à®¿à®²à®¿à®°à¯à®•à¯à®•à¯à®®à¯ பகà¯à®•à®™à¯à®•à®³à¯ˆ நிà®à¯à®à®¯à®®à®¾à®• நீகà¯à®• விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾?</translation>
<translation id="2677748264148917807">வெளியேறà¯</translation>
+<translation id="269990154133806163">à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ வெளிபà¯à®ªà®Ÿà¯ˆà®¤à¯à®¤à®©à¯à®®à¯ˆ கà¯à®³à¯à®•à¯ˆà®¯à®¿à®©à¯à®ªà®Ÿà®¿ பà¯à®¤à¯à®µà®¿à®²à¯ வெளியிடபà¯à®ªà®Ÿà®¾à®¤ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯à¯à®³à¯à®³à®¤à¯. à®à®¿à®² à®à®¾à®©à¯à®±à®¿à®¤à®´à¯à®•à®³à®¿à®©à¯ நமà¯à®ªà®•à®¤à¯à®¤à®©à¯à®®à¯ˆà®¯à¯ˆà®¯à¯à®®à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯à®•à®³à¯à®•à¯à®•à¯ à®à®¤à®¿à®°à®¾à®© பாதà¯à®•à®¾à®ªà¯à®ªà¯ˆà®¯à¯à®®à¯ உறà¯à®¤à®¿à®à¯†à®¯à¯à®¯, இத௠அவà®à®¿à®¯à®®à®¾à®•à¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">மதிபà¯à®ªà®¾à®©à®¤à¯ வடிவமைபà¯à®ªà®¿à®±à¯à®•à¯à®ªà¯ பà¯à®°à¯à®¨à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="2704951214193499422">இபà¯à®ªà¯‹à®¤à¯ உஙà¯à®•à®³à¯ காரà¯à®Ÿà¯ˆ உறà¯à®¤à®¿à®à¯†à®¯à¯à®¯ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. பிறக௠மà¯à®¯à®²à®µà¯à®®à¯.</translation>
<translation id="2705137772291741111">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®©à¯ à®à¯‡à®®à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ (தறà¯à®•à®¾à®²à®¿à®•à®à¯ à®à¯‡à®®à®¿à®ªà¯à®ªà¯) நகலைப௠படிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="2709516037105925701">தானாகநிரபà¯à®ªà¯</translation>
+<translation id="2712118517637785082"><ph name="DOMAIN" />கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®¯à®©à¯à®±à¯€à®°à¯à®•à®³à¯, ஆனால௠à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ அதன௠வழஙà¯à®•à¯à®¨à®°à®¾à®²à¯ ரதà¯à®¤à¯à®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯. ஆகையாலà¯, à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯ அனà¯à®®à®¤à®¿à®à¯ à®à®¾à®©à¯à®±à¯à®•à®³à¯ˆ நமà¯à®ª வேணà¯à®Ÿà®¾à®®à¯. நீஙà¯à®•à®³à¯ தà¯à®Ÿà®°à¯à®ªà¯à®•à¯à®£à¯à®Ÿà®¿à®°à¯à®ªà¯à®ªà®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®¾à®³à®°à®¾à®• இரà¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">அனà¯à®®à®¤à®¿ கேளà¯</translation>
<translation id="2721148159707890343">கோரிகà¯à®•à¯ˆ வெறà¯à®±à®¿</translation>
<translation id="2728127805433021124">à®à¯‡à®µà¯ˆà®¯à®•à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ ஒர௠வலà¯à®µà®±à¯à®± கையà¯à®ªà¯à®ª அலà¯à®•à®¾à®°à®¿à®¤à®®à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ கையà¯à®ªà¯à®ªà®®à®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">à®®à¯à®•à®µà®°à®¿ மறà¯à®±à¯à®®à¯ தேடல௠படà¯à®Ÿà®¿</translation>
<translation id="2826760142808435982">இநà¯à®¤ இணைபà¯à®ªà¯ <ph name="CIPHER" /> à®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ கà¯à®±à®¿à®¯à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯, à®…à®™à¯à®•à¯€à®•à®°à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯, ஒர௠மà¯à®•à¯à®•à®¿à®¯ பரிமாறà¯à®± à®à¯†à®¯à®²à¯à®®à¯à®±à¯ˆà®¯à®¾à®• <ph name="KX" /> à®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="2835170189407361413">படிவதà¯à®¤à¯ˆ அழி</translation>
-<translation id="2837049386027881519">TLS அலà¯à®²à®¤à¯ SSL நெறிமà¯à®±à¯ˆà®¯à®¿à®©à¯ பழைய பதிபà¯à®ªà®¿à®©à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿, இணைபà¯à®ªà¯ˆ மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯. இத௠பà¯à®¤à¯à®µà®¾à®•, à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ மிகபà¯à®ªà®´à¯ˆà®¯ மெனà¯à®ªà¯à®°à¯à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯ மறà¯à®±à¯à®®à¯ பிற பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¿à®•à¯à®•à®²à¯à®•à®³à¯ இரà¯à®•à¯à®•à®²à®¾à®®à¯†à®©à¯à®±à¯ பà¯à®°à¯à®³à®¾à®•à¯à®®à¯.</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> இல௠உளà¯à®³ à®à¯‡à®µà¯ˆà®¯à®•à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ போலியானத௠போல௠தெரிகிறதà¯.</translation>
<translation id="2889159643044928134">மீணà¯à®Ÿà¯à®®à¯ à®à®±à¯à®± வேணà¯à®Ÿà®¾à®®à¯</translation>
-<translation id="2896499918916051536">à®à¯†à®°à¯à®•à¯à®¨à®¿à®°à®²à¯ ஆதரிகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="2900469785430194048">நினைவகப௠பறà¯à®±à®¾à®•à¯à®•à¯à®±à¯ˆà®¯à®¿à®©à®¾à®²à¯, Google Chrome இநà¯à®¤ இணையபà¯à®ªà®•à¯à®•à®¤à¯à®¤à¯ˆà®•à¯ காடà¯à®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="2909946352844186028">பிணைய மாறà¯à®±à®®à¯ கணà¯à®Ÿà®±à®¿à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
-<translation id="2915500479781995473">இத௠<ph name="DOMAIN" /> தான௠à®à®©à¯à®ªà®¤à¯ˆ இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ காலாவதியாகிவிடà¯à®Ÿà®¤à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. உஙà¯à®•à®³à¯ கணினியின௠கடிகாரம௠இபà¯à®ªà¯‹à®¤à¯ <ph name="CURRENT_TIME" />கà¯à®•à¯ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. இத௠à®à®°à®¿à®¯à®¾à®• உளà¯à®³à®¤à®¾? தவற௠à®à®©à®¿à®²à¯, உஙà¯à®•à®³à¯ கணினியின௠கடிகாரதà¯à®¤à¯ˆà®à¯ à®à®°à®¿à®à¯†à®¯à¯à®¤à¯, இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="2922350208395188000">à®à¯‡à®µà¯ˆà®¯à®•à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ à®à¯‹à®¤à®¿à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
-<translation id="2941952326391522266">இத௠<ph name="DOMAIN" /> தான௠à®à®©à¯à®ªà®¤à¯ˆ இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ <ph name="DOMAIN2" /> இலிரà¯à®¨à¯à®¤à¯ பெறபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="2948083400971632585">இணைபà¯à®ªà®¿à®±à¯à®•à®¾à®• உளà¯à®³à®®à¯ˆà®¤à¯à®¤ à®à®¨à¯à®¤ பிராகà¯à®à®¿à®•à®³à¯ˆà®¯à¯à®®à¯ நீஙà¯à®•à®³à¯ அமைபà¯à®ªà¯à®•à®³à¯ பகà¯à®•à®¤à¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ à®®à¯à®Ÿà®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="2955913368246107853">தேடல௠பெடà¯à®Ÿà®¿à®¯à¯ˆ மூடà¯à®•</translation>
<translation id="2958431318199492670">பிணைய உளà¯à®³à®®à¯ˆà®ªà¯à®ªà®¾à®©à®¤à¯ ONC தரதà¯à®¤à¯à®Ÿà®©à¯ இணஙà¯à®•à®µà®¿à®²à¯à®²à¯ˆ. உளà¯à®³à®®à¯ˆà®µà®¿à®©à¯ பகà¯à®¤à®¿à®•à®³à¯ இறகà¯à®•à¯à®®à®¤à®¿à®¯à®¾à®•à®¾à®®à®²à¯ போககà¯à®•à¯‚டà¯à®®à¯.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">தவறான கà¯à®³à¯à®•à¯ˆ வகை</translation>
<translation id="3032412215588512954">தளதà¯à®¤à¯ˆ மீணà¯à®Ÿà¯à®®à¯ à®à®±à¯à®±à®µà®¾?</translation>
<translation id="3037605927509011580">à®…à®à¯à®à®à¯à®à¯‹!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{ஒதà¯à®¤à®¿à®à¯ˆà®¤à¯à®¤ à®à®¾à®¤à®©à®™à¯à®•à®³à®¿à®²à¯ கà¯à®±à¯ˆà®¨à¯à®¤à®¤à¯ 1 உரà¯à®ªà¯à®ªà®Ÿà®¿ உளà¯à®³à®¤à¯}=1{1 உரà¯à®ªà¯à®ªà®Ÿà®¿ (ஒதà¯à®¤à®¿à®à¯ˆà®¤à¯à®¤ à®à®¾à®¤à®©à®™à¯à®•à®³à®¿à®²à¯ இதறà¯à®•à¯ மேல௠உளà¯à®³à®©)}other{# உரà¯à®ªà¯à®ªà®Ÿà®¿à®•à®³à¯ (ஒதà¯à®¤à®¿à®à¯ˆà®¤à¯à®¤ à®à®¾à®¤à®©à®™à¯à®•à®³à®¿à®²à¯ இதறà¯à®•à¯ மேல௠உளà¯à®³à®©)}}</translation>
<translation id="3041612393474885105">à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ தகவலà¯</translation>
<translation id="3063697135517575841">இபà¯à®ªà¯‹à®¤à¯ உஙà¯à®•à®³à¯ காரà¯à®Ÿà¯ˆ உறà¯à®¤à®¿à®à¯†à®¯à¯à®¯ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. பிறக௠மà¯à®¯à®²à®µà¯à®®à¯.</translation>
<translation id="3093245981617870298">ஆஃபà¯à®²à¯ˆà®©à®¿à®²à¯ உளà¯à®³à¯€à®°à¯à®•à®³à¯.</translation>
@@ -203,15 +206,16 @@
<translation id="3176929007561373547">பிராகà¯à®à®¿ à®à®°à¯à®µà®°à¯ இயகà¯à®•à®¤à¯à®¤à®¿à®²à¯ உளà¯à®³à®¤à¯ à®à®©à¯à®ªà®¤à¯ˆ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤ உஙà¯à®•à®³à¯ பிராகà¯à®à®¿ அமைபà¯à®ªà¯à®•à®³à¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®•à¯à®•à®µà¯à®®à¯ அலà¯à®²à®¤à¯ நெடà¯à®µà¯à®°à¯à®•à¯ நிரà¯à®µà®¾à®•à®¿à®¯à¯ˆà®¤à¯ தà¯à®Ÿà®°à¯à®ªà¯à®•à¯à®³à¯à®³à®µà¯à®®à¯. நீஙà¯à®•à®³à¯ பிராகà¯à®à®¿ à®à®°à¯à®µà®°à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯ à®à®©à¯à®ªà®¤à¯ˆ நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ à®à®©à¯à®±à®¾à®²à¯, பினà¯à®µà®°à¯à®µà®¤à¯ˆà®à¯ à®à¯†à®¯à¯à®¯à®µà¯à®®à¯:<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">பà¯à®¤à¯à®¤à®®à¯ பà¯à®¤à®¿à®¤à¯</translation>
<translation id="3207960819495026254">பà¯à®•à¯à®®à®¾à®°à¯à®•à¯ à®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
-<translation id="3225919329040284222">உளà¯à®³à®®à¯ˆà®¨à¯à®¤ à®à®¤à®¿à®°à¯à®ªà®¾à®°à¯à®ªà¯à®ªà¯à®•à®³à¯à®Ÿà®©à¯ பà¯à®°à¯à®¨à¯à®¤à®¾à®¤ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯à®¤à¯. à®à®¿à®² உயரà¯-பாதà¯à®•à®¾à®ªà¯à®ªà¯ வலைதà¯à®¤à®³à®™à¯à®•à®³à®¿à®²à¯ உஙà¯à®•à®³à¯ˆà®ªà¯ பாதà¯à®•à®¾à®•à¯à®•à®µà¯‡ இநà¯à®¤ à®à®¤à®¿à®°à¯à®ªà®¾à®°à¯à®ªà¯à®ªà¯à®•à®³à¯ à®à¯‡à®°à¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®©à¯à®±à®©.</translation>
<translation id="3226128629678568754">பகà¯à®•à®¤à¯à®¤à¯ˆ à®à®±à¯à®± தேவைபà¯à®ªà®Ÿà¯à®®à¯ தரவை மறà¯à®®à¯à®±à¯ˆà®à¯ à®à®®à®°à¯à®ªà¯à®ªà®¿à®ªà¯à®ªà®¤à®±à¯à®•à¯ மீணà¯à®Ÿà¯à®®à¯ à®à®±à¯à®±à¯ à®à®©à¯à®± பà¯à®¤à¯à®¤à®¾à®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®•.</translation>
<translation id="3228969707346345236">பகà¯à®•à®®à¯ à®®à¯à®©à¯à®ªà¯‡ <ph name="LANGUAGE" /> இல௠இரà¯à®ªà¯à®ªà®¤à®¾à®²à¯ மொழிபெயரà¯à®ªà¯à®ªà¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯.</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" /> இன௠CVC à®à®£à¯à®£à¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
<translation id="3254409185687681395">இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆ பà¯à®•à¯à®®à®¾à®°à¯à®•à¯ à®à¯†à®¯à¯à®•</translation>
<translation id="3270847123878663523">&amp;மறà¯à®µà®°à®¿à®à¯ˆà®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à¯ˆà®à¯ à®à¯†à®¯à®²à¯à®¤à®µà®¿à®°à¯</translation>
<translation id="3286538390144397061">இபà¯à®ªà¯‹à®¤à¯ மறà¯à®¤à¯à®Ÿà®•à¯à®•à®®à¯ à®à¯†à®¯à¯à®•</translation>
+<translation id="3303855915957856445">தேடல௠மà¯à®Ÿà®¿à®µà¯à®•à®³à¯ à®à®¤à¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ</translation>
<translation id="3305707030755673451"><ph name="TIME" /> அனà¯à®±à¯ உஙà¯à®•à®³à¯ தரவ௠உஙà¯à®•à®³à¯ ஒதà¯à®¤à®¿à®à¯ˆà®µà¯ கடவà¯à®à¯à®à¯à®±à¯à®±à¯à®Ÿà®°à¯ˆà®•à¯ கà¯à®£à¯à®Ÿà¯ à®®à¯à®±à¯ˆà®®à¯ˆà®¯à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯. ஒதà¯à®¤à®¿à®à¯ˆà®µà¯ˆà®¤à¯ தà¯à®Ÿà®™à¯à®•, அதை உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯.</translation>
<translation id="333371639341676808">இநà¯à®¤ பகà¯à®•à®®à¯ கூடà¯à®¤à®²à¯ உரையாடலà¯à®•à®³à¯ˆ உரà¯à®µà®¾à®•à¯à®•à¯à®µà®¤à¯ˆà®¤à¯ தடà¯.</translation>
+<translation id="3338095232262050444">பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®©à®¤à¯</translation>
<translation id="3340978935015468852">அமைபà¯à®ªà¯à®•à®³à¯</translation>
<translation id="3345135638360864351">இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆ அணà¯à®•à¯à®µà®¤à®±à¯à®•à®¾à®© கோரிகà¯à®•à¯ˆà®¯à¯ˆ <ph name="NAME" />கà¯à®•à¯ அனà¯à®ªà¯à®ª à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="3355823806454867987">பà¯à®°à®¾à®•à¯à®¸à®¿ அமைபà¯à®ªà¯à®•à®³à¯ˆ மாறà¯à®±à¯à®•...</translation>
@@ -229,6 +233,7 @@
<translation id="3452404311384756672">à®à®Ÿà¯à®ªà¯à®ªà®¤à®±à¯à®•à®¾à®© இடைவேளை:</translation>
<translation id="3462200631372590220">மேமà¯à®ªà®Ÿà¯à®Ÿà®µà¯ˆà®¯à¯ˆ மறை</translation>
<translation id="3479539252931486093">இதை à®à®¤à®¿à®°à¯à®ªà®¾à®°à¯à®•à¯à®•à®µà®¿à®²à¯à®²à¯ˆà®¯à®¾? <ph name="BEGIN_LINK" />à®à®™à¯à®•à®³à¯à®•à¯à®•à¯à®¤à¯ தெரியபà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">இபà¯à®ªà¯à®´à¯à®¤à¯ இலà¯à®²à¯ˆ</translation>
<translation id="348000606199325318">à®à®¿à®¤à¯ˆà®µà¯ à®à®Ÿà®¿ <ph name="CRASH_LOCAL_ID" /> (à®à¯‡à®µà¯ˆà®¯à®• à®à®Ÿà®¿: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">தறà¯à®ªà¯‹à®¤à¯ உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯ˆà®¤à¯ தà¯à®Ÿà®°à¯à®ªà¯à®•à¯à®³à¯à®³ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="3527085408025491307">கோபà¯à®ªà¯à®±à¯ˆ</translation>
@@ -237,6 +242,7 @@
<translation id="3542684924769048008">இதறà¯à®•à®¾à®• கடவà¯à®à¯à®à¯à®²à¯à®²à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯:</translation>
<translation id="3549644494707163724">உஙà¯à®•à®³à¯ à®à¯à®¨à¯à®¤ ஒதà¯à®¤à®¿à®à¯ˆà®µà¯ கடவà¯à®à¯à®à¯à®±à¯à®±à¯à®Ÿà®°à¯ மூலம௠à®à®²à¯à®²à®¾ தரவையà¯à®®à¯ à®à®©à¯à®•à¯à®°à®¿à®ªà¯à®Ÿà¯ à®à¯†à®¯à¯à®¯à®µà¯à®®à¯</translation>
<translation id="3549761410225185768">மேலà¯à®®à¯ <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880"><ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ <ph name="DOMAIN2" /> இலிரà¯à®¨à¯à®¤à¯ பெறபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">உஙà¯à®•à®³à¯ இணைபà¯à®ªà¯ தனிபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ அலà¯à®²</translation>
<translation id="3583757800736429874">&amp;நகரà¯à®¤à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ à®à¯†à®¯à¯</translation>
<translation id="3586931643579894722">விவரஙà¯à®•à®³à¯ˆ மறை</translation>
@@ -248,12 +254,15 @@
<translation id="3623476034248543066">மதிபà¯à®ªà¯ˆà®•à¯ காடà¯à®Ÿà¯</translation>
<translation id="3630155396527302611">இத௠நெடà¯à®µà¯à®°à¯à®•à¯à®•à¯ˆ அணà¯à®•à¯à®µà®¤à®±à¯à®•à¯ அனà¯à®®à®¤à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ நிரலாக à®à®±à¯à®•à®©à®µà¯‡ படà¯à®Ÿà®¿à®¯à®²à®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®¨à¯à®¤à®¾à®²à¯,
இதைப௠படà¯à®Ÿà®¿à®¯à®²à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ அகறà¯à®±à®¿, மீணà¯à®Ÿà¯à®®à¯ à®à¯‡à®°à¯à®ªà¯à®ªà®¤à®±à¯à®•à¯ à®®à¯à®¯à®²à®µà¯à®®à¯.</translation>
+<translation id="3638794133396384728"><ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ காலாவதியாகிவிடà¯à®Ÿà®¤à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. உஙà¯à®•à®³à¯ கணினியின௠கடிகாரம௠தறà¯à®ªà¯‹à®¤à¯ <ph name="CURRENT_TIME" /> à®à®© அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. அத௠à®à®°à®¿à®¯à®¾à®• உளà¯à®³à®¤à®¾? இலà¯à®²à¯ˆà®¯à¯†à®©à®¿à®²à¯, கணினியின௠கடிகாரதà¯à®¤à¯ˆà®à¯ à®à®°à®¿à®à¯†à®¯à¯à®¤à¯, இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">இநà¯à®¤à®à¯ à®à¯‹à®¤à®©à¯ˆ à®…à®®à¯à®à®™à¯à®•à®³à¯, à®à®ªà¯à®ªà¯‹à®¤à¯ வேணà¯à®Ÿà¯à®®à®¾à®©à®¾à®²à¯à®®à¯ மாறலாமà¯, தà¯à®£à¯à®Ÿà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯ அலà¯à®²à®¤à¯ மறைநà¯à®¤à¯ விடலாமà¯. இநà¯à®¤ à®…à®®à¯à®à®™à¯à®•à®³à®¿à®²à¯ à®à®¤à¯‡à®©à¯à®®à¯ ஒனà¯à®±à¯ˆ நீஙà¯à®•à®³à¯ இயகà¯à®•à¯à®µà®¤à®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®®à¯ நிகழà¯à®µà¯à®•à®³à¯à®•à¯à®•à¯ நாஙà¯à®•à®³à¯ à®à®µà¯à®µà®•à¯ˆà®¯à®¿à®²à¯à®®à¯ à®à®¨à¯à®¤à®µà®¿à®¤ உதà¯à®¤à®°à®µà®¾à®¤à®®à¯à®®à¯ அளிகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ. மேலà¯à®®à¯ உஙà¯à®•à®³à¯ உலாவியானத௠திடீரெனà¯à®±à¯ à®à¯†à®¯à®²à®¿à®´à®¨à¯à®¤à¯ விடகà¯à®•à¯‚டà¯à®®à¯. உணà¯à®®à¯ˆà®¯à®¿à®²à¯ உஙà¯à®•à®³à¯ உலாவியின௠தரவ௠அனைதà¯à®¤à¯ˆà®¯à¯à®®à¯ நீகà¯à®•à®µà®¿à®Ÿà®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ பாதà¯à®•à®¾à®ªà¯à®ªà¯, தனியà¯à®°à®¿à®®à¯ˆà®¯à®¾à®©à®¤à¯ à®à®¤à®¿à®°à¯à®ªà®¾à®°à®¾à®¤ வழிகளில௠மாறà¯à®±à®¿à®¯à®®à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯. நீஙà¯à®•à®³à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ à®à®¨à¯à®¤ à®à¯‹à®¤à®©à¯ˆà®•à®³à¯à®®à¯ இநà¯à®¤ உலாவியின௠à®à®²à¯à®²à®¾ பயனரà¯à®•à®³à¯à®•à¯à®•à¯à®®à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®®à¯. à®à®à¯à®à®°à®¿à®•à¯à®•à¯ˆà®¯à®¾à®•à®¤à¯ தà¯à®Ÿà®°à¯à®•.</translation>
<translation id="3650584904733503804">à®à®°à®¿à®ªà®¾à®°à¯à®ªà¯à®ªà¯ வெறà¯à®±à®¿</translation>
<translation id="3655670868607891010">இதை அடிகà¯à®•à®Ÿà®¿ காணà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯ à®à®©à®¿à®²à¯, <ph name="HELP_LINK" /> à® à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="3658742229777143148">மீளà¯à®¤à®¿à®°à¯à®¤à¯à®¤à®™à¯à®•à®³à¯</translation>
+<translation id="3678029195006412963">கோரிகà¯à®•à¯ˆà®¯à®¿à®²à¯ கையà¯à®ªà¯à®ªà®®à®¿à®Ÿ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="3681007416295224113">à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ தகவலà¯</translation>
<translation id="3693415264595406141">கடவà¯à®à¯à®à¯à®²à¯:</translation>
+<translation id="3696411085566228381">à®à®¤à¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ</translation>
<translation id="3700528541715530410">à®…à®à¯à®à®à¯à®à¯‹, இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆ அணà¯à®• உஙà¯à®•à®³à¯à®•à¯à®•à¯ அனà¯à®®à®¤à®¿ இலà¯à®²à®¾à®¤à®¤à¯ˆà®ªà¯à®ªà¯‹à®²à¯ தெரிகிறதà¯.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">நினைவேறà¯à®•à®¿à®±à®¤à¯...</translation>
@@ -261,7 +270,6 @@
<translation id="3714780639079136834">மொபைல௠தரவ௠அலà¯à®²à®¤à¯ வைஃபையை இயகà¯à®•à¯à®¤à®²à¯</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />பà¯à®°à®¾à®•à¯à®¸à®¿, ஃபயரà¯à®µà®¾à®²à¯ மறà¯à®±à¯à®®à¯ DNS உளà¯à®³à®®à¯ˆà®µà¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®¤à¯à®¤à®²à¯<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">நீஙà¯à®•à®³à¯ நகலெடà¯à®¤à¯à®¤ இணைபà¯à®ªà¯</translation>
-<translation id="3744899669254331632">இணையதளம௠Chromium ஆல௠à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®¾à®¤ தவறான நறà¯à®à®¾à®©à¯à®±à¯à®•à®³à¯ˆ அனà¯à®ªà¯à®ªà®¿à®¯à¯à®³à¯à®³à®¤à®¾à®²à¯, இபà¯à®ªà¯‹à®¤à¯ <ph name="SITE" />à®à®ªà¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. பà¯à®¤à¯à®µà®¾à®• நெடà¯à®µà¯à®°à¯à®•à¯ பிழைகளà¯à®®à¯ தாகà¯à®•à¯à®¤à®²à¯à®•à®³à¯à®®à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®•à®µà¯‡ இரà¯à®•à¯à®•à¯à®®à¯, à®à®¿à®±à®¿à®¤à¯à®¨à¯‡à®°à®®à¯ கழிதà¯à®¤à¯ இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®°à®¿à®¯à®¾à®•à®à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
<translation id="375403751935624634">ஒர௠à®à¯‡à®µà¯ˆà®¯à®•à®ªà¯ பிழையின௠காரணமாக மொழிபெயரà¯à®ªà¯à®ªà¯à®¤à¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯.</translation>
<translation id="3759461132968374835">உஙà¯à®•à®³à®¿à®Ÿà®®à¯ à®à®®à¯€à®ªà®¤à¯à®¤à®¿à®²à¯ à®à¯†à®¯à®²à®¿à®´à®ªà¯à®ªà¯à®•à®³à¯ à®à®¤à¯à®µà¯à®®à¯ பà¯à®•à®¾à®°à®³à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ. à®à¯†à®¯à®²à®¿à®´à®ªà¯à®ªà¯ பà¯à®•à®¾à®°à®³à®¿à®¤à¯à®¤à®²à¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®¨à¯à®¤à®ªà¯‹à®¤à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿ à®à¯†à®¯à®²à®¿à®´à®ªà¯à®ªà¯à®•à®³à¯ இஙà¯à®•à¯ காணà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯.</translation>
<translation id="3788090790273268753">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®±à¯à®•à®¾à®© à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ 2016 ஆம௠ஆணà¯à®Ÿà¯ காலாவதியாகà¯à®®à¯, மேலà¯à®®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ à®à®™à¯à®•à®¿à®²à®¿à®¯à®¿à®²à¯ SHA-1à®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®•à¯ கையà¯à®ªà¯à®ªà®®à®¿à®Ÿà¯à®Ÿ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ உளà¯à®³à®¤à¯.</translation>
@@ -273,19 +281,25 @@
<translation id="3884278016824448484">à®®à¯à®°à®£à¯à®ªà®¾à®Ÿà®¾à®© à®à®¾à®¤à®© அடையாளஙà¯à®•à®¾à®Ÿà¯à®Ÿà®¿</translation>
<translation id="3885155851504623709">வடà¯à®Ÿà®¾à®°à®®à¯</translation>
<translation id="3901925938762663762">காரà¯à®Ÿà¯ காலாவதியானதà¯</translation>
+<translation id="3910267023907260648"><ph name="DOMAIN" />கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®¯à®©à¯à®±à¯€à®°à¯à®•à®³à¯, ஆனால௠à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வலிமையறà¯à®± கையà¯à®ªà¯à®ª அலà¯à®•à®¾à®°à®¿à®¤à®®à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ கையà¯à®ªà¯à®ªà®®à®¿à®Ÿà¯à®Ÿ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ வழஙà¯à®•à®¿à®¯à¯à®³à¯à®³à®¤à¯. அதாவதà¯, à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯à¯à®³à¯à®³ பாதà¯à®•à®¾à®ªà¯à®ªà¯ அனà¯à®®à®¤à®¿à®à¯ à®à®¾à®©à¯à®±à¯à®•à®³à¯ போலியாக உரà¯à®µà®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯, மேலà¯à®®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ நீஙà¯à®•à®³à¯ à®à®¤à®¿à®°à¯à®ªà®¾à®°à¯à®¤à¯à®¤ à®à¯‡à®µà¯ˆà®¯à®•à®®à®¾à®• இலà¯à®²à®¾à®®à®²à¯ இரà¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯ (நீஙà¯à®•à®³à¯ தà¯à®Ÿà®°à¯à®ªà¯à®•à¯à®£à¯à®Ÿà®¿à®°à¯à®ªà¯à®ªà®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®¾à®³à®°à®¾à®• இரà¯à®•à¯à®•à®²à®¾à®®à¯). <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{<ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ நாளை à®®à¯à®¤à®²à¯ à®à®±à¯à®±à¯à®•à¯à®•à¯à®³à¯à®³à®ªà¯à®ªà®Ÿà¯à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.}other{<ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ à®à®¤à®¿à®°à¯à®•à®¾à®²à®¤à¯à®¤à®¿à®²à¯ # நாடà¯à®•à®³à¯ à®®à¯à®¤à®²à¯ à®à®±à¯à®±à¯à®•à¯à®•à¯à®³à¯à®³à®ªà¯à®ªà®Ÿà¯à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF ஆவணதà¯à®¤à¯ˆ à®à®±à¯à®±à¯à®µà®¤à¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯</translation>
<translation id="3963721102035795474">படிதà¯à®¤à®²à¯ பயனà¯à®®à¯à®±à¯ˆ</translation>
+<translation id="397105322502079400">கணகà¯à®•à®¿à®Ÿà¯à®•à®¿à®±à®¤à¯...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{à®…à®°à¯à®•à®¿à®²à¯ ஒர௠இணையப௠பகà¯à®•à®®à¯ உளà¯à®³à®¤à¯}other{à®…à®°à¯à®•à®¿à®²à¯ # இணையப௠பகà¯à®•à®™à¯à®•à®³à¯ உளà¯à®³à®©}}</translation>
<translation id="4021036232240155012">DNS à®à®©à¯à®ªà®¤à¯ இணையதளதà¯à®¤à®¿à®©à¯ பெயரை அதன௠இணைய à®®à¯à®•à®µà®°à®¿à®¯à®¾à®• மாறà¯à®±à¯à®®à¯ நெடà¯à®µà¯à®°à¯à®•à¯ à®à¯‡à®µà¯ˆà®¯à®¾à®•à¯à®®à¯.</translation>
<translation id="4030383055268325496">&amp;à®à¯‡à®°à¯à®¤à¯à®¤à®²à¯ˆà®à¯ à®à¯†à®¯à®²à¯à®¤à®µà®¿à®°à¯</translation>
-<translation id="4032534284272647190"><ph name="URL" /> கà¯à®•à®¾à®© அணà¯à®•à®²à¯ மறà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="404928562651467259">à®à®à¯à®à®°à®¿à®•à¯à®•à¯ˆ</translation>
<translation id="4058922952496707368">விà®à¯ˆ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">கà¯à®³à¯ˆà®¯à®©à¯à®Ÿà¯à®Ÿà¯à®®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯à®®à¯ பà¯à®¤à¯à®µà®¾à®© SSL நெறிமà¯à®±à¯ˆà®ªà¯ பதிபà¯à®ªà¯ˆà®¯à¯‹ à®à¯ˆà®ƒà®ªà®°à¯ பà¯à®¤à®¿à®¯à¯ˆà®¯à¯‹ ஆதரிகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="4079302484614802869">பà¯à®°à®¾à®•à¯à®¸à®¿ உளà¯à®³à®®à¯ˆà®µà®¾à®©à®¤à¯, .pac ஸà¯à®•à®¿à®°à®¿à®ªà¯à®Ÿà¯ URL à®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯à®ªà®Ÿà®¿ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®¿à®±à®¤à¯, நிலையான பà¯à®°à®¾à®•à¯à®¸à®¿ à®à¯‡à®µà¯ˆà®¯à®•à®™à¯à®•à®³à¯à®•à¯à®•à¯ அலà¯à®².</translation>
<translation id="4103249731201008433">à®à®¾à®¤à®© à®à¯€à®°à®¿à®¯à®²à¯ à®à®£à¯ தவறானதà¯</translation>
<translation id="4103763322291513355">à®à®±à¯à®•à®¤à¯à®¤à®•à®¾à®¤ URLகளின௠படà¯à®Ÿà®¿à®¯à®²à¯ˆà®¯à¯à®®à¯ உஙà¯à®•à®³à¯ கணினி நிரà¯à®µà®¾à®•à®¿à®¯à®¾à®²à¯ à®à¯†à®¯à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®®à¯ பிற கà¯à®³à¯à®•à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ காண &lt;strong&gt;chrome://policy&lt;/strong&gt; à®à®ªà¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà®µà¯à®®à¯.</translation>
+<translation id="4110615724604346410"><ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à®¿à®²à¯ பிழைகள௠உளà¯à®³à®©. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">கà¯à®³à¯à®•à¯ˆà®¯à®¿à®©à¯ நோகà¯à®•à®®à¯ ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="4118212371799607889"><ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ Chromium நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{மேலà¯à®®à¯ ஒனà¯à®±à¯}other{மேலà¯à®®à¯ #}}</translation>
<translation id="4130226655945681476">நெடà¯à®µà¯à®°à¯à®•à¯ கேபிளà¯à®•à®³à¯, மோடமà¯, ரூடà¯à®Ÿà®°à¯ ஆகியவறà¯à®±à¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">இநà¯à®¤à®•à¯ காரà¯à®Ÿà¯ˆ Chromium à®à¯‡à®®à®¿à®•à¯à®• வேணà¯à®Ÿà¯à®®à®¾?</translation>
@@ -293,6 +307,7 @@
<translation id="4176463684765177261">à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="4196861286325780578">&amp;நகரà¯à®¤à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ à®à¯†à®¯à¯</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ஃபயரà¯à®µà®¾à®²à¯ மறà¯à®±à¯à®®à¯ ஆணà¯à®Ÿà®¿à®µà¯ˆà®°à®¸à¯ உளà¯à®³à®®à¯ˆà®µà¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®¤à¯à®¤à®²à¯<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ இலà¯à®²à¯ˆ}=1{1 பயனà¯à®ªà®¾à®Ÿà¯ ($1)}=2{2 பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ ($1, $2)}other{# பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">à®à¯†à®¯à®²à®¿à®´à®ªà¯à®ªà¯à®•à®³à¯</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />நெடà¯à®µà¯à®°à¯à®•à¯ டயகà¯à®©à®¸à¯à®Ÿà®¿à®•à¯à®¸à¯ கரà¯à®µà®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">இலà¯à®²à¯ˆ</translation>
@@ -301,14 +316,15 @@
<translation id="4269787794583293679">(பயனரà¯à®ªà¯†à®¯à®°à¯ இலà¯à®²à¯ˆ)</translation>
<translation id="4300246636397505754">மூலப௠பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯</translation>
<translation id="4304224509867189079">உளà¯à®¨à¯à®´à¯ˆ</translation>
+<translation id="432290197980158659">உளà¯à®³à®®à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ à®à®¤à®¿à®°à¯à®ªà®¾à®°à¯à®ªà¯à®ªà¯à®•à®³à¯à®Ÿà®©à¯ பà¯à®°à¯à®¨à¯à®¤à®¾à®¤à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯à¯à®³à¯à®³à®¤à¯. உஙà¯à®•à®³à¯ˆà®ªà¯ பாதà¯à®•à®¾à®•à¯à®•à¯à®®à¯ நோகà¯à®•à®¤à¯à®¤à®¿à®²à¯, கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ அதிக பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© இணையதளஙà¯à®•à®³à®¿à®²à¯ இநà¯à®¤ à®à®¤à®¿à®°à¯à®ªà®¾à®°à¯à®ªà¯à®ªà¯à®•à®³à¯ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®©à¯à®±à®©. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">கடà¯à®Ÿà¯à®°à¯ˆà®¯à¯ˆà®•à¯ கணà¯à®Ÿà®±à®¿à®¯ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
+<translation id="4331708818696583467">பாதà¯à®•à®¾à®ªà¯à®ªà®±à¯à®±à®¤à¯</translation>
<translation id="4372948949327679948">à®à®¤à®¿à®°à¯à®ªà®¾à®°à¯à®¤à¯à®¤ <ph name="VALUE_TYPE" /> மதிபà¯à®ªà¯.</translation>
-<translation id="4377125064752653719"><ph name="DOMAIN" /> ஠அடைய à®®à¯à®¯à®±à¯à®à®¿ à®à¯†à®¯à¯à®¤à¯€à®°à¯à®•à®³à¯. ஆனால௠à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à®¾à®©à®¤à¯ அதன௠வழஙà¯à®•à¯à®¨à®°à®¾à®²à¯ நிராகரிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯. அதாவதà¯, à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯ பாதà¯à®•à®¾à®ªà¯à®ªà¯ நமà¯à®ªà®¿à®•à¯à®•à¯ˆà®à¯à®à®¾à®©à¯à®±à¯à®•à®³à¯ˆ நிà®à¯à®à®¯à®®à®¾à®• à®à®•à¯à®•à®¾à®°à®£à®¤à¯à®¤à¯ˆà®•à¯à®•à¯à®£à¯à®Ÿà¯à®®à¯ நமà¯à®ªà®•à¯à®•à¯‚டாதà¯. போலியான ஒனà¯à®±à¯à®Ÿà®©à¯ நீஙà¯à®•à®³à¯ தகவல௠பரிமாறà¯à®±à®®à¯ à®à¯†à®¯à¯à®¤à¯à®•à¯à®£à¯à®Ÿà®¿à®°à¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯.</translation>
<translation id="4381091992796011497">பயனர௠பெயரà¯:</translation>
<translation id="4394049700291259645">à®®à¯à®Ÿà®•à¯à®•à¯</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> à®®à¯à®¤à®²à¯ <ph name="END_DATE" /> வரை</translation>
<translation id="4406896451731180161">தேடல௠மà¯à®Ÿà®¿à®µà¯à®•à®³à¯</translation>
-<translation id="4424024547088906515">இத௠<ph name="DOMAIN" /> தான௠à®à®©à¯à®ªà®¤à¯ˆ இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ Chrome நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> உஙà¯à®•à®³à¯ உளà¯à®¨à¯à®´à¯ˆà®µà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ à®à®±à¯à®•à®µà®¿à®²à¯à®²à¯ˆ அலà¯à®²à®¤à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ வழஙà¯à®•à®ªà¯à®ªà®Ÿà®¾à®®à®²à¯ இரà¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯.</translation>
<translation id="443673843213245140">பà¯à®°à®¾à®•à¯à®¸à®¿ பயனà¯à®ªà®¾à®Ÿà¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. ஆனால௠வெளிபà¯à®ªà®Ÿà¯ˆà®¯à®¾à®© பà¯à®°à®¾à®•à¯à®¸à®¿ உளà¯à®³à®®à¯ˆà®µà¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Google SafeSites இயகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à®¾à®²à¯ இநà¯à®¤à®à¯ à®à¯†à®¯à¯à®¤à®¿à®¯à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯.</translation>
@@ -320,12 +336,12 @@
<translation id="4522570452068850558">விவரஙà¯à®•à®³à¯</translation>
<translation id="4558551763791394412">நீடà¯à®Ÿà®¿à®ªà¯à®ªà¯à®•à®³à¯ˆ à®®à¯à®Ÿà®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="4587425331216688090">Chrome இலிரà¯à®¨à¯à®¤à¯ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ அகறà¯à®±à®µà®¾?</translation>
+<translation id="4589078953350245614"><ph name="DOMAIN" />கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®¯à®©à¯à®±à¯€à®°à¯à®•à®³à¯, ஆனால௠à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ தவறான à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ வழஙà¯à®•à®¿à®¯à¯à®³à¯à®³à®¤à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">நவீன à®à¯ˆà®ªà®°à¯ à®à¯‚டà¯à®Ÿà¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ <ph name="DOMAIN" /> உடனான உஙà¯à®•à®³à¯ இணைபà¯à®ªà¯ à®à®©à¯à®•à¯à®°à®¿à®ªà¯à®Ÿà¯ à®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="4594403342090139922">&amp;நீகà¯à®•à¯à®¤à®²à¯ˆà®à¯ à®à¯†à®¯à®²à¯à®¤à®µà®¿à®°à¯</translation>
+<translation id="4627442949885028695">மறà¯à®±à¯à®°à¯ à®à®¾à®¤à®©à®¤à¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ பாரà¯à®¤à¯à®¤à®µà¯ˆ</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">நீடà¯à®Ÿà®¿à®ªà¯à®ªà¯à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯.</translation>
-<translation id="467662567472608290">இத௠<ph name="DOMAIN" /> தான௠à®à®©à¯à®ªà®¤à¯ˆ இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à®¿à®²à¯ பிழைகள௠உளà¯à®³à®©. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தடஙà¯à®•à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows நெடà¯à®µà¯à®°à¯à®•à¯ டயகà¯à®©à®¸à¯à®Ÿà®¿à®•à¯à®¸à¯ கரà¯à®µà®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯<ph name="END_LINK" /></translation>
@@ -333,21 +349,26 @@
<translation id="4728558894243024398">பà¯à®³à®¾à®Ÿà¯à®ƒà®ªà®¾à®°à¯à®®à¯</translation>
<translation id="4744603770635761495">இயகà¯à®•à®¨à®¿à®°à®²à¯ பாதை</translation>
<translation id="4756388243121344051">&amp;வரலாறà¯</translation>
+<translation id="4759238208242260848">பதிவிறகà¯à®•à®™à¯à®•à®³à¯</translation>
<translation id="4764776831041365478"><ph name="URL" /> இல௠உளà¯à®³ வலைபà¯à®ªà®•à¯à®•à®®à®¾à®©à®¤à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®• இயஙà¯à®•à®¾à®®à®²à¯ இரà¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ அத௠ஒர௠பà¯à®¤à®¿à®¯ வலை à®®à¯à®•à®µà®°à®¿à®•à¯à®•à¯ நிரநà¯à®¤à®°à®®à®¾à®• நகரà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="4771973620359291008">அறியபà¯à®ªà®Ÿà®¾à®¤ பிழை à®à®±à¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
<translation id="4782449893814226250">இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà®²à®¾à®®à®¾ à®à®©, நீஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯à®•à®³à®¿à®Ÿà®®à¯ கேடà¯à®Ÿà¯à®³à¯à®³à¯€à®°à¯à®•à®³à¯.</translation>
<translation id="4800132727771399293">காலாவதியாகà¯à®®à¯ நேரதà¯à®¤à¯ˆà®¯à¯à®®à¯, CVCà®à®¯à¯à®®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®¤à¯à®¤à¯, மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à®µà¯à®®à¯</translation>
-<translation id="4807049035289105102">இணையதளமானத௠Google Chrome ஆல௠à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®¾à®¤ à®à®¿à®¤à¯ˆà®¨à¯à®¤ நறà¯à®à®¾à®©à¯à®±à¯à®•à®³à¯ˆ அனà¯à®ªà¯à®ªà®¿à®¯à¯à®³à¯à®³à®¤à®¾à®²à¯, நீஙà¯à®•à®³à¯ இபà¯à®ªà¯‹à®¤à¯ <ph name="SITE" />கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯, பà¯à®¤à¯à®µà®¾à®• நெடà¯à®µà¯à®°à¯à®•à¯ பிழைகளà¯à®®à¯ தாகà¯à®•à¯à®¤à®²à¯à®•à®³à¯à®®à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à¯‡, à®à®©à®µà¯‡ இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®¿à®±à®¿à®¤à¯ நேரம௠கழிதà¯à®¤à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="4813512666221746211">பிணைய பிழை</translation>
<translation id="4816492930507672669">பகà¯à®•à®¤à¯à®¤à®¿à®²à¯ பà¯à®°à¯à®¤à¯à®¤à¯</translation>
<translation id="4850886885716139402">காடà¯à®à®¿</translation>
<translation id="4880827082731008257">வரலாறà¯à®±à®¿à®²à¯ தேடà¯</translation>
+<translation id="4884656795097055129">à®à®°à®¿à®¯à®¾à®© நேரதà¯à®¤à®¿à®²à¯ அதிக கடà¯à®Ÿà¯à®°à¯ˆà®•à®³à¯ காடà¯à®Ÿà®ªà¯à®ªà®Ÿà¯à®®à¯.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{மேலà¯à®®à¯ ஒர௠இணையப௠பகà¯à®•à®®à¯}other{மேலà¯à®®à¯ # இணையப௠பகà¯à®•à®™à¯à®•à®³à¯}}</translation>
<translation id="4923417429809017348">ஒர௠அறியபà¯à®ªà®Ÿà®¾à®¤ மொழியிலிரà¯à®¨à¯à®¤à¯ <ph name="LANGUAGE_LANGUAGE" /> -கà¯à®•à¯ இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ மொழிபெயரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
<translation id="4926049483395192435">கடà¯à®Ÿà®¾à®¯à®®à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿ வேணà¯à®Ÿà¯à®®à¯.</translation>
<translation id="4930497775425430760">à®®à¯à®¤à®²à¯ à®®à¯à®±à¯ˆ நீஙà¯à®•à®³à¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®®à¯ பà¯à®¤à®¿à®¯ தளஙà¯à®•à®³à¯ˆ உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯ அனà¯à®®à®¤à®¿à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯ à®à®©à¯à®ªà®¤à®¾à®²à¯ இநà¯à®¤à®à¯ à®à¯†à®¯à¯à®¤à®¿à®¯à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯.</translation>
<translation id="495170559598752135">à®à¯†à®¯à®²à¯à®•à®³à¯</translation>
<translation id="4958444002117714549">படà¯à®Ÿà®¿à®¯à®²à¯ˆ விரி</translation>
+<translation id="4962322354953122629"><ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ Chrome நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911"><ph name="ORIGINAL_LANGUAGE" /> இலிரà¯à®¨à¯à®¤à¯ <ph name="TARGET_LANGUAGE" /> கà¯à®•à¯ à®®à¯à®´à®¿à®ªà¯†à®¯à®°à¯à®•à¯à®•à®µà®¾?</translation>
+<translation id="4989809363548539747">இநà¯à®¤à®à¯ à®à¯†à®°à¯à®•à¯à®¨à®¿à®°à®²à¯ ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="5002932099480077015">இயகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¾à®²à¯, விரைவாகப௠படிவதà¯à®¤à¯ˆ நிரபà¯à®ª உஙà¯à®•à®³à¯ காரà¯à®Ÿà®¿à®©à¯ நகலை இà®à¯à®à®¾à®¤à®©à®¤à¯à®¤à®¿à®²à¯ Chrome à®à¯‡à®®à®¿à®¤à¯à®¤à¯ வைகà¯à®•à¯à®®à¯.</translation>
<translation id="5019198164206649151">தவறான நிலையில௠மீடà¯à®ªà¯ à®à¯‡à®®à®¿à®ªà¯à®ªà¯ உளà¯à®³à®¤à¯</translation>
<translation id="5023310440958281426">உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿à®¯à®¿à®©à¯ கà¯à®³à¯à®•à¯ˆà®•à®³à¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®•à¯à®•à®µà¯à®®à¯</translation>
@@ -355,13 +376,12 @@
<translation id="5031870354684148875">Google à®®à¯à®´à®¿à®¯à®¾à®•à¯à®•à®®à¯ ஓர௠அறிமà¯à®•à®®à¯</translation>
<translation id="5040262127954254034">தனியà¯à®°à®¿à®®à¯ˆ</translation>
<translation id="5045550434625856497">தவறான கடவà¯à®à¯à®à¯à®²à¯</translation>
+<translation id="5056549851600133418">உஙà¯à®•à®³à¯à®•à¯à®•à®¾à®© கடà¯à®Ÿà¯à®°à¯ˆà®•à®³à¯</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />பà¯à®°à®¾à®•à¯à®¸à®¿ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®¤à¯à®¤à®²à¯<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">தறà¯à®ªà¯‹à®¤à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¿à®©à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ à®à¯†à®²à¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à®¾à®¤à¯.</translation>
<translation id="5089810972385038852">மாநிலமà¯</translation>
-<translation id="5094747076828555589">இத௠<ph name="DOMAIN" /> தான௠à®à®©à¯à®ªà®¤à¯ˆ இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ Chromium நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="5095208057601539847">பிராநà¯à®¤à®¿à®¯à®®à¯</translation>
<translation id="5115563688576182185">(64-பிடà¯)</translation>
-<translation id="5122371513570456792">'<ph name="SEARCH_STRING" />'கà¯à®•à®¾à®• <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> கிடைதà¯à®¤à®©.</translation>
<translation id="5141240743006678641">ஒதà¯à®¤à®¿à®à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ கடவà¯à®à¯à®à¯à®±à¯à®•à®³à¯ˆ உஙà¯à®•à®³à¯ Google நறà¯à®à®¾à®©à¯à®±à¯à®•à®³à¯ மூலம௠à®à®©à¯à®•à¯à®°à®¿à®ªà¯à®Ÿà¯ à®à¯†à®¯à¯à®¯à®µà¯à®®à¯</translation>
<translation id="5145883236150621069">கà¯à®³à¯à®•à¯ˆà®ªà¯ பதிலில௠பிழைக௠கà¯à®±à®¿à®¯à¯€à®Ÿà¯ உளà¯à®³à®¤à¯</translation>
<translation id="5171045022955879922">தேடà¯à®• அலà¯à®²à®¤à¯ URL-à®à®¤à¯ தடà¯à®Ÿà®à¯à®à¯ à®à¯†à®¯à¯à®•</translation>
@@ -370,18 +390,18 @@
<translation id="5190835502935405962">பà¯à®•à¯à®®à®¾à®°à¯à®•à¯à®•à¯à®•à®³à¯ படà¯à®Ÿà®¿</translation>
<translation id="5199729219167945352">à®à¯‹à®¤à®©à¯ˆà®•à®³à¯</translation>
<translation id="5251803541071282808">மேககà¯à®•à®£à®¿</translation>
+<translation id="5277279256032773186">பணியில௠Chromeà®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾? வணிக நிறà¯à®µà®©à®™à¯à®•à®³à¯ தஙà¯à®•à®³à®¿à®©à¯ பணியாளரà¯à®•à®³à¯à®•à¯à®•à®¾à®© Chrome அமைபà¯à®ªà¯à®•à®³à¯ˆ நிரà¯à®µà®•à®¿à®•à¯à®•à®²à®¾à®®à¯. மேலà¯à®®à¯ அறிக</translation>
<translation id="5299298092464848405">கà¯à®³à¯à®•à¯ˆà®¯à¯ˆ அலà®à¯à®µà®¤à®¿à®²à¯ பிழை</translation>
<translation id="5300589172476337783">காணà¯à®ªà®¿</translation>
<translation id="5308689395849655368">à®à¯†à®¯à®²à®¿à®´à®ªà¯à®ªà¯ பà¯à®•à®¾à®°à®³à®¿à®¤à¯à®¤à®²à¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
<translation id="5317780077021120954">à®à¯‡à®®à®¿</translation>
<translation id="5327248766486351172">பெயரà¯</translation>
+<translation id="5359637492792381994"><ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ இபà¯à®ªà¯‹à®¤à¯ à®à¯†à®²à¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">கà¯à®³à¯à®•à¯ˆ அமைபà¯à®ªà¯à®•à®³à¯ˆà®à¯ à®à¯‡à®®à®¿à®ªà¯à®ªà®¤à®¿à®²à¯ தோலà¯à®µà®¿</translation>
-<translation id="540969355065856584"><ph name="DOMAIN" /> டà¯à®®à¯ˆà®©à¯ˆ, à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; அதறà¯à®•à®¾à®© காரணஙà¯à®•à®³à¯: இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ தறà¯à®ªà¯‹à®¤à¯ à®à¯†à®²à¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®©à®¤à®²à¯à®². இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¿à®©à®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="5421136146218899937">உலாவல௠தரவை அழி...</translation>
<translation id="5430298929874300616">பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®¯à¯ˆ அகறà¯à®±à¯</translation>
<translation id="5431657950005405462">உஙà¯à®•à®³à¯ கோபà¯à®ªà¯ இலà¯à®²à¯ˆ</translation>
<translation id="5435775191620395718">இநà¯à®¤à®à¯ à®à®¾à®¤à®©à®¤à¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ வரலாறà¯à®±à¯ˆà®•à¯ காடà¯à®Ÿà¯à®•à®¿à®±à®¤à¯. <ph name="BEGIN_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">ஒதà¯à®¤à®¿à®à¯ˆà®¤à¯à®¤ தரவானத௠தனிபà¯à®ªà®¯à®©à¯ கடவà¯à®à¯à®à¯à®±à¯à®±à¯à®Ÿà®°à¯ மூலம௠பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®µà®¤à®¾à®²à¯, தனிபà¯à®ªà®Ÿà¯à®Ÿ உளà¯à®³à®Ÿà®•à¯à®•à®ªà¯ பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯ தறà¯à®ªà¯‹à®¤à¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®©.</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" திடà¯à®Ÿà®®à¯à®±à¯ˆ à®à®°à®¿à®ªà®¾à®°à¯à®ªà¯à®ªà¯à®ªà¯ பிழை: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">இநà¯à®¤ <ph name="HOST_NAME" /> பகà¯à®•à®¤à¯à®¤à¯ˆà®•à¯ கணà¯à®Ÿà®±à®¿à®¯ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="5455374756549232013">தவறான கà¯à®³à¯à®•à¯ˆ நேரமà¯à®¤à¯à®¤à®¿à®°à¯ˆ</translation>
@@ -404,14 +424,18 @@
<translation id="5622887735448669177">தளதà¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ வெளியேறவா?</translation>
<translation id="5629630648637658800">கà¯à®³à¯à®•à¯ˆ அமைபà¯à®ªà¯à®•à®³à¯ˆ à®à®±à¯à®±à¯à®µà®¤à®¿à®²à¯ தோலà¯à®µà®¿</translation>
<translation id="5631439013527180824">தவறான à®à®¾à®¤à®© நிரà¯à®µà®¾à®• டோகà¯à®•à®©à¯</translation>
-<translation id="5650551054760837876">தேடல௠மà¯à®Ÿà®¿à®µà¯à®•à®³à¯ à®à®¤à¯à®µà¯à®®à¯ காணபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="5677928146339483299">தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="5710435578057952990">இநà¯à®¤ தளதà¯à®¤à®¿à®©à¯ அடையாளம௠à®à®°à®¿à®ªà®¾à®°à¯à®•à¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="5720705177508910913">நடபà¯à®ªà¯à®ªà¯ பயனரà¯</translation>
+<translation id="572328651809341494">à®à®®à¯€à®ªà®¤à¯à®¤à®¿à®¯ தாவலà¯à®•à®³à¯</translation>
<translation id="5784606427469807560">காரà¯à®Ÿà¯ˆ உறà¯à®¤à®¿à®à¯†à®¯à¯à®µà®¤à®¿à®²à¯ à®à®¿à®•à¯à®•à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯. இணைய இணைபà¯à®ªà¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®¤à¯à®¤à¯, மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®²à®µà¯à®®à¯.</translation>
<translation id="5785756445106461925">மேலà¯à®®à¯, பாதà¯à®•à®¾à®ªà¯à®ªà®±à¯à®± பிற ஆதாரஙà¯à®•à®³à¯ இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à®¿à®²à¯ உளà¯à®³à®©. இநà¯à®¤ ஆதாரஙà¯à®•à®³à¯ˆ டà¯à®°à®¾à®©à¯à®¸à®¿à®Ÿà¯à®Ÿà®¿à®²à¯ இரà¯à®•à¯à®•à¯à®®à¯à®ªà¯‹à®¤à¯à®®à¯ பிறர௠பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà®²à®¾à®®à¯, மேலà¯à®®à¯ பகà¯à®•à®¤à¯à®¤à®¿à®©à¯ தோறà¯à®±à®¤à¯à®¤à¯ˆ மாறà¯à®±, தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ அதை மாறà¯à®±à®¿à®¯à®®à¯ˆà®•à¯à®•à®²à®¾à®®à¯.</translation>
+<translation id="5786044859038896871">காரà¯à®Ÿà¯ தகவலை நிரபà¯à®ª விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾?</translation>
+<translation id="5803412860119678065"><ph name="CARD_DETAIL" />஠நிரபà¯à®ª விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾?</translation>
<translation id="5810442152076338065"><ph name="DOMAIN" />கà¯à®•à®¾à®© உஙà¯à®•à®³à¯ இணைபà¯à®ªà¯, நடைமà¯à®±à¯ˆà®¯à®¿à®²à¯ இலà¯à®²à®¾à®¤ à®à¯ˆà®ªà®°à¯ à®à¯‚டà¯à®Ÿà¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ à®à®©à¯à®•à¯à®°à®¿à®ªà¯à®Ÿà¯ à®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="5813119285467412249">&amp;à®à¯‡à®°à¯à®¤à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ à®à¯†à®¯à¯</translation>
+<translation id="5814352347845180253"><ph name="SITE" /> மறà¯à®±à¯à®®à¯ à®à®¿à®² தளஙà¯à®•à®³à®¿à®©à¯ பிரீமிய உளà¯à®³à®Ÿà®•à¯à®• அணà¯à®•à®²à¯ˆ நீஙà¯à®•à®³à¯ இழகà¯à®•à®•à¯à®•à¯‚டà¯à®®à¯.</translation>
+<translation id="5843436854350372569"><ph name="DOMAIN" />கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®¯à®©à¯à®±à¯€à®°à¯à®•à®³à¯, ஆனால௠à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வலà¯à®µà®±à¯à®± கà¯à®±à®¿à®¯à¯€à®Ÿà¯à®Ÿà¯ˆà®•à¯ கà¯à®£à¯à®Ÿ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ வழஙà¯à®•à®¿à®¯à¯à®³à¯à®³à®¤à¯. தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ கà¯à®±à®¿à®¯à¯€à®Ÿà¯à®Ÿà¯ˆà®¤à¯ திரà¯à®Ÿà®¿à®¯à®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯, மேலà¯à®®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ நீஙà¯à®•à®³à¯ à®à®¤à®¿à®°à¯à®ªà®¾à®°à¯à®¤à¯à®¤ à®à¯‡à®µà¯ˆà®¯à®•à®®à®¾à®• இலà¯à®²à®¾à®®à®²à¯ இரà¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯ (நீஙà¯à®•à®³à¯ தà¯à®Ÿà®°à¯à®ªà¯à®•à¯à®£à¯à®Ÿà®¿à®°à¯à®ªà¯à®ªà®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®¾à®³à®°à®¾à®• இரà¯à®•à¯à®•à®²à®¾à®®à¯). <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆà®¤à¯ தடà¯à®¤à¯à®¤à¯à®³à¯à®³à®¤à®¾à®²à¯ இநà¯à®¤à®à¯ à®à¯†à®¯à¯à®¤à®¿à®¯à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯.</translation>
<translation id="5857090052475505287">பà¯à®¤à®¿à®¯ கோபà¯à®ªà¯à®±à¯ˆ</translation>
<translation id="5869405914158311789">இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆ அணà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
@@ -419,6 +443,7 @@
<translation id="5872918882028971132">மூலப௠பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯</translation>
<translation id="59107663811261420">இநà¯à®¤ வியாபாரிகà¯à®•à¯ Google Payments இல௠இநà¯à®¤ வகையான காரà¯à®Ÿà¯ ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯. வேறà¯à®°à¯ காரà¯à®Ÿà¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="59174027418879706">à®à¯†à®¯à®²à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
+<translation id="5926846154125914413">à®à®¿à®² தளஙà¯à®•à®³à®¿à®©à¯ பிரீமிய உளà¯à®³à®Ÿà®•à¯à®• அணà¯à®•à®²à¯ˆ நீஙà¯à®•à®³à¯ இழகà¯à®•à®•à¯à®•à¯‚டà¯à®®à¯.</translation>
<translation id="5966707198760109579">வாரமà¯</translation>
<translation id="5967867314010545767">வரலாறà¯à®±à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ அகறà¯à®±à¯</translation>
<translation id="5975083100439434680">à®à®¿à®±à®¿à®¤à®¾à®•à¯à®•à¯</translation>
@@ -430,11 +455,11 @@
<translation id="604124094241169006">தானியஙà¯à®•à¯</translation>
<translation id="6042308850641462728">மேலà¯à®®à¯</translation>
<translation id="6060685159320643512">கவனமà¯, இநà¯à®¤ à®à¯‹à®¤à®©à¯ˆà®•à®³à¯ பாதிபà¯à®ªà¯ˆ à®à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à®¾à®®à¯</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{கடவà¯à®à¯à®à¯à®±à¯à®•à®³à¯ இலà¯à®²à¯ˆ}=1{1}other{#}}</translation>
<translation id="6146055958333702838">கேபிளà¯à®•à®³à¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®¤à¯à®¤à¯, நீஙà¯à®•à®³à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®•à¯à®•à¯‚டிய ரூடà¯à®Ÿà®°à¯à®•à®³à¯, மோடமà¯à®•à®³à¯ அலà¯à®²à®¤à¯ பிற நெடà¯à®µà¯à®°à¯à®•à¯ à®à®¾à®¤à®©à®™à¯à®•à®³à¯ˆ மறà¯à®¤à¯à®Ÿà®•à¯à®•à®®à¯ à®à¯†à®¯à¯à®¯à®µà¯à®®à¯.</translation>
<translation id="614940544461990577">இவறà¯à®±à¯ˆà®à¯ à®à¯†à®¯à¯à®¤à¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯:</translation>
<translation id="6150607114729249911">à®…à®à¯à®à®à¯à®à¯‡à®¾! இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà®²à®¾à®®à®¾ à®à®©, உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯à®•à®³à®¿à®Ÿà®®à¯ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯.</translation>
<translation id="6151417162996330722">à®à¯‡à®µà¯ˆ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ நீணà¯à®Ÿ à®à¯†à®²à¯à®²à¯à®ªà®Ÿà®¿à®•à¯ காலதà¯à®¤à¯ˆà®•à¯ கà¯à®£à¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
-<translation id="6154808779448689242">கிடைதà¯à®¤ கà¯à®³à¯à®•à¯ˆ டோகà¯à®•à®©à¯, தறà¯à®ªà¯‹à®¤à¯à®³à¯à®³ டோகà¯à®•à®©à¯à®Ÿà®©à¯ பà¯à®°à¯à®¨à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="6165508094623778733">மேலà¯à®®à¯ அறிக</translation>
<translation id="6203231073485539293">உஙà¯à®•à®³à¯ இணைய இணைபà¯à®ªà¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="6218753634732582820">Chromium இலிரà¯à®¨à¯à®¤à¯ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ அகறà¯à®±à®µà®¾?</translation>
@@ -447,24 +472,30 @@
<translation id="6328639280570009161">பிணைய யூகதà¯à®¤à¯ˆ à®®à¯à®Ÿà®•à¯à®•à¯à®µà®¤à®±à¯à®•à¯ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="6337534724793800597">பெயரினà¯à®ªà®Ÿà®¿ கà¯à®³à¯à®•à¯ˆà®•à®³à¯ˆ வடி</translation>
<translation id="6342069812937806050">இபà¯à®ªà¯‹à®¤à¯</translation>
+<translation id="6345221851280129312">அறியபà¯à®ªà®Ÿà®¾à®¤ அளவà¯</translation>
<translation id="6355080345576803305">பà¯à®¤à¯ அமரà¯à®µà¯ மேலெழà¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="6358450015545214790">இவறà¯à®±à®¿à®©à¯ பà¯à®°à¯à®³à¯ à®à®©à¯à®©?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{மேலà¯à®®à¯ 1 பரிநà¯à®¤à¯à®°à¯ˆ}other{மேலà¯à®®à¯ # பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯}}</translation>
<translation id="6387478394221739770">பà¯à®¤à®¿à®¯ Chrome à®…à®®à¯à®à®™à¯à®•à®³à®¿à®²à¯ ஆரà¯à®µà®®à¯ உளà¯à®³à®¤à®¾? chrome.com/beta இல௠à®à®™à¯à®•à®³à¯à®Ÿà¯ˆà®¯ பீடà¯à®Ÿà®¾ அலைவரிà®à¯ˆà®¯à¯ˆ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
-<translation id="641480858134062906"><ph name="URL" /> நினவேறà¯à®µà®¤à®¿à®²à¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯</translation>
+<translation id="6389758589412724634">நினைவகப௠பறà¯à®±à®¾à®•à¯à®•à¯à®±à¯ˆà®¯à®¿à®©à®¾à®²à¯, Chromium இநà¯à®¤ இணையபà¯à®ªà®•à¯à®•à®¤à¯à®¤à¯ˆà®•à¯ காடà¯à®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="6416403317709441254">Chromium ஆல௠à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®¾à®¤ à®à®¿à®¤à¯ˆà®¨à¯à®¤ அனà¯à®®à®¤à®¿à®à¯ à®à®¾à®©à¯à®±à¯à®•à®³à¯ˆ இணையதளம௠அனà¯à®ªà¯à®ªà®¿à®¯à¯à®³à¯à®³à®¤à®¾à®²à¯, இபà¯à®ªà¯‹à®¤à¯ <ph name="SITE" />கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. பà¯à®¤à¯à®µà®¾à®• நெடà¯à®µà¯à®°à¯à®•à¯ பிழைகளà¯à®®à¯ பாதிபà¯à®ªà¯à®•à®³à¯à®®à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à¯‡. இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®¿à®±à®¿à®¤à¯ நேரம௠கழிதà¯à®¤à¯à®à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ திரà¯à®®à¯à®ªà®ªà¯à®ªà¯†à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à®¾ à®à®©à¯à®±à¯ à®à¯‹à®¤à®¿à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> இணைகà¯à®• மறà¯à®¤à¯à®¤à®¤à¯.</translation>
<translation id="6445051938772793705">நாடà¯</translation>
<translation id="6451458296329894277">படிவ மறà¯à®à®®à®°à¯à®ªà¯à®ªà®¿à®ªà¯à®ªà¯ˆ உறà¯à®¤à®¿à®à¯†à®¯à¯à®•</translation>
<translation id="6458467102616083041">கà¯à®³à¯à®•à¯ˆ மூலம௠இயலà¯à®ªà¯à®¨à®¿à®²à¯ˆ தேடல௠மà¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à®¾à®²à¯, பாலிà®à®¿à®¯à®¿à®©à¯ மதிபà¯à®ªà¯ பà¯à®±à®•à¯à®•à®£à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
+<translation id="6462969404041126431"><ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ ரதà¯à®¤à¯à®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">à®à®¾à®¤à®©à®•à¯ கà¯à®³à¯à®•à¯ˆà®•à®³à¯</translation>
<translation id="6489534406876378309">à®à®¿à®¤à¯ˆà®µà¯à®•à®³à¯ˆà®ªà¯ பதிவேறà¯à®±à¯à®µà®¤à¯ˆà®¤à¯ தà¯à®Ÿà®™à¯à®•à¯</translation>
<translation id="6529602333819889595">&amp;நீகà¯à®•à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ à®à¯†à®¯à¯</translation>
+<translation id="6534179046333460208">இயலà¯à®¨à®¿à®²à¯ˆ இணையப௠பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯</translation>
<translation id="6550675742724504774">விரà¯à®ªà¯à®ªà®¤à¯à®¤à¯‡à®°à¯à®µà¯à®•à®³à¯</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" />கà¯à®•à¯à®®à¯ கà¯à®±à¯ˆà®µà®¾à®• உளà¯à®³à®¤à¯</translation>
<translation id="6596325263575161958">கà¯à®±à®¿à®¯à®¾à®•à¯à®• விரà¯à®ªà¯à®ªà®™à¯à®•à®³à¯</translation>
<translation id="662080504995468778">வேணà¯à®Ÿà®¾à®®à¯</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> தேடலà¯</translation>
-<translation id="6634865548447745291">இபà¯à®ªà¯‹à®¤à¯ <ph name="SITE" /> à®à®ªà¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯, à®à®©à¯†à®©à®¿à®²à¯ <ph name="BEGIN_LINK" />இநà¯à®¤à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ திரà¯à®®à¯à®ªà®ªà¯ பெறபà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯<ph name="END_LINK" />. நெடà¯à®µà¯à®°à¯à®•à¯ பிழைகள௠மறà¯à®±à¯à®®à¯ தாகà¯à®•à¯à®¤à®²à¯à®•à®³à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à®¾à®•à¯à®®à¯, à®à®©à®µà¯‡ இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®¿à®±à®¿à®¤à¯ நேரம௠கழிதà¯à®¤à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="6644283850729428850">இநà¯à®¤à®•à¯ கà¯à®³à¯à®•à¯ˆ தவிரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
+<translation id="6652240803263749613"><ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ உஙà¯à®•à®³à¯ கணினியின௠இயகà¯à®• à®®à¯à®±à¯ˆà®®à¯ˆ நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">கோபà¯à®ªà¯à®±à¯ˆà®¯à¯ˆà®¤à¯ திரà¯à®¤à¯à®¤à¯</translation>
<translation id="6660210980321319655">தானாக அறிவிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Chromium இலிரà¯à®¨à¯à®¤à¯ படிவப௠பரிநà¯à®¤à¯à®°à¯ˆà®¯à¯ˆ அகறà¯à®±à®µà®¾?</translation>
@@ -472,6 +503,7 @@
<translation id="6710213216561001401">à®®à¯à®¨à¯à®¤à¯ˆà®¯à®¤à¯</translation>
<translation id="6710594484020273272">&lt;தேடல௠வாரà¯à®¤à¯à®¤à¯ˆà®¯à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®•&gt;</translation>
<translation id="6711464428925977395">பà¯à®°à®¾à®•à¯à®¸à®¿ à®à®°à¯à®µà®°à®¿à®²à¯ à®à®¤à¯‹ தவற௠உளà¯à®³à®¤à¯ அலà¯à®²à®¤à¯ à®®à¯à®•à®µà®°à®¿ தவறாக உளà¯à®³à®¤à¯.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{உரà¯à®ªà¯à®ªà®Ÿà®¿à®•à®³à¯ இலà¯à®²à¯ˆ}=1{1 உரà¯à®ªà¯à®ªà®Ÿà®¿}other{# உரà¯à®ªà¯à®ªà®Ÿà®¿à®•à®³à¯}}</translation>
<translation id="674375294223700098">தெரியாத à®à¯‡à®µà¯ˆà®¯à®•à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ பிழை.</translation>
<translation id="6753269504797312559">கà¯à®³à¯à®•à¯ˆ மதிபà¯à®ªà¯</translation>
<translation id="6757797048963528358">உஙà¯à®•à®³à¯ à®à®¾à®¤à®©à®®à¯ உறகà¯à®•à®¨à®¿à®²à¯ˆà®•à¯à®•à¯à®à¯ à®à¯†à®©à¯à®±à®¤à¯.</translation>
@@ -483,7 +515,6 @@
<translation id="6891596781022320156">கà¯à®³à¯à®•à¯ˆà®¯à®¿à®©à¯ நிலை ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="6895330447102777224">காரà¯à®Ÿà¯ உறà¯à®¤à®¿à®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="6897140037006041989">பயனர௠மà¯à®•à®µà®°à¯</translation>
-<translation id="6903907808598579934">ஒதà¯à®¤à®¿à®à¯ˆà®µà¯ˆ இயகà¯à®•à¯</translation>
<translation id="6915804003454593391">பயனரà¯:</translation>
<translation id="6957887021205513506">à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¿à®©à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ போலியானத௠போல௠தெரிகிறதà¯.</translation>
<translation id="6965382102122355670">à®à®°à®¿</translation>
@@ -491,9 +522,11 @@
<translation id="6970216967273061347">மாவடà¯à®Ÿà®®à¯</translation>
<translation id="6973656660372572881">நிலையான பà¯à®°à®¾à®•à¯à®¸à®¿ à®à¯‡à®µà¯ˆà®¯à®•à®™à¯à®•à®³à¯à®®à¯ .pac ஸà¯à®•à®¿à®°à®¿à®ªà¯à®Ÿà¯ URL ஆகிய இரணà¯à®Ÿà¯à®®à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
<translation id="6989763994942163495">மேமà¯à®ªà®Ÿà¯à®Ÿ அமைபà¯à®ªà¯à®•à®³à¯ˆà®•à¯ காணà¯à®ªà®¿...</translation>
+<translation id="7000990526846637657">வரலாற௠உளà¯à®³à¯€à®Ÿà¯à®•à®³à¯ à®à®¤à¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ</translation>
+<translation id="7009986207543992532"><ph name="DOMAIN" />கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®¯à®©à¯à®±à¯€à®°à¯à®•à®³à¯, ஆனால௠நீணà¯à®Ÿ à®à¯†à®²à¯à®²à¯à®ªà®Ÿà®¿à®•à¯ காலதà¯à®¤à¯ˆà®•à¯ கà¯à®£à¯à®Ÿ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯à¯à®³à¯à®³à®¤à¯, இதà¯à®ªà¯‹à®©à¯à®± à®à®¾à®©à¯à®±à®¿à®¤à®´à¯à®•à®³à¯ நமà¯à®ªà®¤à¯à®¤à®•à¯à®•à®µà¯ˆà®¯à®²à¯à®². <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">à®à¯€à®©à®¾ UnionPay</translation>
+<translation id="7012372675181957985">உஙà¯à®•à®³à¯ Google கணகà¯à®•à¯ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> à®à®©à¯à®± தளதà¯à®¤à®¿à®²à¯ உலாவல௠வரலாற௠தà¯à®Ÿà®°à¯à®ªà®¾à®© பிற தகவலà¯à®•à®³à¯ˆà®•à¯ கà¯à®£à¯à®Ÿà®¿à®°à¯à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯</translation>
<translation id="7029809446516969842">கடவà¯à®à¯à®à¯à®±à¯à®•à®³à¯</translation>
-<translation id="7050187094878475250"><ph name="DOMAIN" />஠அடைய à®®à¯à®¯à®±à¯à®à®¿à®¤à¯à®¤à¯à®³à¯à®³à¯€à®°à¯à®•à®³à¯, à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ நமà¯à®ªà¯à®µà®¤à®±à¯à®•à¯ à®à®¾à®¤à¯à®¤à®¿à®¯à®®à®±à¯à®± நீணà¯à®Ÿ à®à¯†à®²à¯à®²à¯à®ªà®Ÿà®¿à®•à¯à®•à®¾à®²à®¤à¯à®¤à¯ˆà®•à¯ கà¯à®£à¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
<translation id="7087282848513945231">மாகாணமà¯</translation>
<translation id="7088615885725309056">பழையவை</translation>
<translation id="7090678807593890770">Google இல௠<ph name="LINK" />à®à®¤à¯ தேடவà¯à®®à¯</translation>
@@ -512,13 +545,13 @@
<translation id="7246609911581847514">à®®à¯à®¤à®²à¯ à®®à¯à®±à¯ˆ நீஙà¯à®•à®³à¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®®à¯ பà¯à®¤à®¿à®¯ தளஙà¯à®•à®³à¯ˆ உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ அனà¯à®®à®¤à®¿à®•à¯à®• வேணà¯à®Ÿà¯à®®à¯ à®à®©à¯à®ªà®¤à®¾à®²à¯ இநà¯à®¤à®à¯ à®à¯†à®¯à¯à®¤à®¿à®¯à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯.</translation>
<translation id="724975217298816891">காரà¯à®Ÿà¯ விவரஙà¯à®•à®³à¯ˆà®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•, <ph name="CREDIT_CARD" /> இன௠காலாவதி தேதியையà¯à®®à¯ CVC à®à®£à¯à®£à¯ˆà®¯à¯à®®à¯ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯. உறà¯à®¤à®¿à®à¯†à®¯à¯à®¤ பினà¯à®©à®°à¯, உஙà¯à®•à®³à¯ காரà¯à®Ÿà¯ விவரஙà¯à®•à®³à¯ இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®±à¯à®•à¯à®ªà¯ பகிரபà¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="725866823122871198">உஙà¯à®•à®³à¯ கணினியின௠தேதி மறà¯à®±à¯à®®à¯ நேரம௠(<ph name="DATE_AND_TIME" />) தவறாக இரà¯à®ªà¯à®ªà®¤à®¾à®²à¯ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> கà¯à®•à®¾à®© தனிபà¯à®ªà®Ÿà¯à®Ÿ இணைபà¯à®ªà¯ˆ à®à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
-<translation id="7265986070661382626">இபà¯à®ªà¯‹à®¤à¯ <ph name="SITE" /> தளதà¯à®¤à¯ˆà®ªà¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯, à®à®©à¯†à®©à®¿à®²à¯ இணையதளம௠<ph name="BEGIN_LINK" />தனகà¯à®•à¯à®¤à¯ தானே பின௠à®à¯†à®¯à¯à®¤ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯<ph name="END_LINK" />. நெடà¯à®µà¯à®°à¯à®•à¯ பிழைகள௠மறà¯à®±à¯à®®à¯ தாகà¯à®•à¯à®¤à®²à¯à®•à®³à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à®¾à®•à¯à®®à¯, à®à®©à®µà¯‡ இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®¿à®±à®¿à®¤à¯ நேரம௠கழிதà¯à®¤à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="7269802741830436641">இநà¯à®¤ வலைபà¯à®ªà®•à¯à®•à®¤à¯à®¤à®¿à®²à¯ ஒர௠திரà¯à®ªà¯à®ªà®¿à®µà®¿à®Ÿà®²à¯ à®à¯à®´à®±à¯à®à®¿ உளà¯à®³à®¤à¯</translation>
<translation id="7275334191706090484">நிரà¯à®µà®•à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯ பà¯à®•à¯à®®à®¾à®°à¯à®•à¯à®•à¯à®•à®³à¯</translation>
<translation id="7298195798382681320">பரிநà¯à®¤à¯à®°à¯ˆà®¤à¯à®¤à®µà¯ˆ</translation>
-<translation id="7301833672208172928">வரலாறà¯à®±à¯ ஒதà¯à®¤à®¿à®à¯ˆà®µà¯ˆ இயகà¯à®•à¯</translation>
+<translation id="7309308571273880165"><ph name="CRASH_TIME" /> அனà¯à®±à¯ à®à®¿à®¤à¯ˆà®µà¯ அறிகà¯à®•à¯ˆ பெறபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯ (பயனர௠பதிவேறà¯à®±à®•à¯ கோரியà¯à®³à¯à®³à®¾à®°à¯, இனà¯à®©à¯à®®à¯ பதிவேறà¯à®±à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ)</translation>
<translation id="7334320624316649418">&amp;மறà¯à®µà®°à®¿à®à¯ˆà®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ à®à¯†à®¯à¯</translation>
<translation id="733923710415886693">à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ வெளிபà¯à®ªà®Ÿà¯ˆà®¤à¯à®¤à®©à¯à®®à¯ˆ மூலம௠à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¿à®©à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ வெளியிடபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="7351800657706554155"><ph name="SITE" /> இன௠à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ ரதà¯à®¤à¯à®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à®¾à®²à¯, அதறà¯à®•à¯à®à¯ à®à¯†à®²à¯à®² à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. பà¯à®¤à¯à®µà®¾à®• நெடà¯à®µà¯à®°à¯à®•à¯ பிழைகளà¯à®®à¯ பாதிபà¯à®ªà¯à®•à®³à¯à®®à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à¯‡. இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®¿à®±à®¿à®¤à¯ நேரம௠கழிதà¯à®¤à¯à®à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">கடà¯à®Ÿà®³à¯ˆ வரி</translation>
<translation id="7372973238305370288">தேடல௠மà¯à®Ÿà®¿à®µà¯</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -537,16 +570,17 @@
<translation id="7469372306589899959">காரà¯à®Ÿà¯ˆ உறà¯à®¤à®¿à®à¯†à®¯à¯à®•à®¿à®±à®¤à¯</translation>
<translation id="7481312909269577407">அடà¯à®¤à¯à®¤ பகà¯à®•à®®à¯</translation>
<translation id="7485870689360869515">தரவ௠à®à®¤à¯à®µà¯à®®à¯ இலà¯à®²à¯ˆ.</translation>
+<translation id="7508255263130623398">கிடைதà¯à®¤ பாலிà®à®¿ à®à®¾à®¤à®© à®à®Ÿà®¿ காலியாக உளà¯à®³à®¤à¯ அலà¯à®²à®¤à¯ தறà¯à®ªà¯‹à®¤à¯ˆà®¯ à®à®¾à®¤à®© à®à®Ÿà®¿à®¯à¯à®Ÿà®©à¯ பà¯à®°à¯à®¨à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="7514365320538308">பதிவிறகà¯à®•à¯</translation>
<translation id="7518003948725431193">வலை à®®à¯à®•à®µà®°à®¿à®•à¯à®•à®¾à®© வலைபà¯à®ªà®•à¯à®•à®™à¯à®•à®³à¯ à®à®¤à¯à®®à¯ காணபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ: <ph name="URL" /></translation>
<translation id="7537536606612762813">கடà¯à®Ÿà®¾à®¯à®®à¯</translation>
<translation id="7542995811387359312">இநà¯à®¤à®ªà¯ படிவம௠பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© இணைபà¯à®ªà¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¾à®¤ காரணதà¯à®¤à®¾à®²à¯, தானியஙà¯à®•à¯ கடன௠அடà¯à®Ÿà¯ˆ நிரபà¯à®ªà¯à®¤à®²à¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="7549584377607005141">à®à®°à®¿à®¯à®¾à®• காணà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®µà®¤à®±à¯à®•à¯ நீஙà¯à®•à®³à¯ à®à®±à¯à®•à®©à®µà¯‡ உளà¯à®³à®¿à®Ÿà¯à®Ÿ தரவ௠இநà¯à®¤ இணையபà¯à®ªà®•à¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ தேவைபà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯. இநà¯à®¤ தரவை நீஙà¯à®•à®³à¯ மீணà¯à®Ÿà¯à®®à¯ அனà¯à®ªà¯à®ªà®²à®¾à®®à¯, ஆனால௠அவà¯à®µà®¾à®±à¯ à®à¯†à®¯à¯à®µà®¤à®©à®¾à®²à¯ இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ à®à®±à¯à®•à®©à®µà¯‡ à®à¯†à®¯à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®¯ à®à®²à¯à®²à®¾à®à¯ à®à¯†à®¯à®²à¯ˆà®¯à¯à®®à¯ மீணà¯à®Ÿà¯à®®à¯ à®à¯†à®¯à¯à®µà¯€à®°à¯à®•à®³à¯.</translation>
<translation id="7554791636758816595">பà¯à®¤à®¿à®¯ தாவலà¯</translation>
-<translation id="7567204685887185387">இத௠<ph name="DOMAIN" /> தான௠à®à®©à¯à®ªà®¤à¯ˆ இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à®¿à®²à¯ மோà®à®Ÿà®¿ à®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="7568593326407688803">இநà¯à®¤à®ªà¯ பகà¯à®•à®®à®¾à®©à®¤à¯<ph name="ORIGINAL_LANGUAGE" />இல௠உளà¯à®³à®¤à¯ இதை à®®à¯à®´à®¿à®ªà¯†à®¯à®°à¯à®•à¯à®• விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾?</translation>
<translation id="7569952961197462199">Chrome இலிரà¯à®¨à¯à®¤à¯ கிரெடிட௠காரà¯à®Ÿà¯ˆ அகறà¯à®±à®µà®¾?</translation>
<translation id="7578104083680115302">Google இல௠நீஙà¯à®•à®³à¯ à®à¯‡à®®à®¿à®¤à¯à®¤à¯à®³à¯à®³ காரà¯à®Ÿà¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ பல தளஙà¯à®•à®³à®¿à®²à¯à®®à¯ பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à®¿à®²à¯à®®à¯ உஙà¯à®•à®³à¯à®Ÿà¯ˆà®¯ à®à®¾à®¤à®©à®™à¯à®•à®³à®¿à®²à¯ அனைதà¯à®¤à®¿à®²à¯à®®à¯ விரைவாகப௠பணம௠à®à¯†à®²à¯à®¤à¯à®¤à®²à®¾à®®à¯.</translation>
+<translation id="7588950540487816470">இயலà¯à®¨à®¿à®²à¯ˆ இணையமà¯</translation>
<translation id="7592362899630581445">பெயர௠கடà¯à®Ÿà¯à®ªà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ˆà®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¿à®©à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ மீறà¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ஆல௠தறà¯à®ªà¯‹à®¤à¯ இநà¯à®¤à®•à¯ கோரிகà¯à®•à¯ˆà®¯à¯ˆà®•à¯ கையாள à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" /> à® à®à®ªà¯à®ªà¯‹à®¤à¯à®®à¯ à®®à¯à®´à®¿à®ªà¯†à®¯à®°à¯à®•à¯à®• வேணà¯à®Ÿà®¾à®®à¯</translation>
@@ -557,6 +591,7 @@
<translation id="7637571805876720304">Chromium இலிரà¯à®¨à¯à®¤à¯ கிரெடிட௠காரà¯à®Ÿà¯ˆ அகறà¯à®±à®µà®¾?</translation>
<translation id="765676359832457558">மேமà¯à®ªà®Ÿà¯à®Ÿ அமைபà¯à®ªà¯à®•à®³à¯ˆ மறை...</translation>
<translation id="7658239707568436148">ரதà¯à®¤à¯ à®à¯†à®¯à¯</translation>
+<translation id="7667346355482952095">கிடைதà¯à®¤ பாலிà®à®¿ டோகà¯à®•à®©à¯ காலியாக உளà¯à®³à®¤à¯ அலà¯à®²à®¤à¯ தறà¯à®ªà¯‹à®¤à¯ˆà®¯ டோகà¯à®•à®©à¯à®Ÿà®©à¯ பà¯à®°à¯à®¨à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="7668654391829183341">அறியபà¯à®ªà®Ÿà®¾à®¤ à®à®¾à®¤à®©à®®à¯</translation>
<translation id="7674629440242451245">பà¯à®¤à®¿à®¯ Chrome à®…à®®à¯à®à®™à¯à®•à®³à®¿à®²à¯ ஆரà¯à®µà®®à®¾à®• உளà¯à®³à¯€à®°à¯à®•à®³à®¾? chrome.com/dev இல௠à®à®™à¯à®•à®³à¯à®Ÿà¯ˆà®¯ dev à®à¯‡à®©à®²à¯ˆ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> (பாதà¯à®•à®¾à®ªà¯à®ªà®±à¯à®± தளமà¯) கà¯à®•à¯à®à¯ à®à¯†à®²à¯à®²à®µà¯à®®à¯<ph name="END_LINK" /></translation>
@@ -573,10 +608,10 @@
<translation id="780301667611848630">தேவையிலà¯à®²à¯ˆ</translation>
<translation id="7805768142964895445">நிலை</translation>
<translation id="7813600968533626083">Chrome இலிரà¯à®¨à¯à®¤à¯ படிவப௠பரிநà¯à®¤à¯à®°à¯ˆà®¯à¯ˆ அகறà¯à®±à®µà®¾?</translation>
+<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />'கà¯à®•à¯ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> உளà¯à®³à®©</translation>
<translation id="785549533363645510">இரà¯à®ªà¯à®ªà®¿à®©à¯à®®à¯, நீஙà¯à®•à®³à¯ மறைநà¯à®¤à®¿à®°à¯à®•à¯à®•à®®à®¾à®Ÿà¯à®Ÿà¯€à®°à¯à®•à®³à¯. மறைநிலைகà¯à®•à¯à®à¯ à®à¯†à®²à¯à®µà®¤à¯ பணிகà¯à®•à®®à®°à¯à®¤à¯à®¤à¯à®®à¯ நிறà¯à®µà®©à®®à¯, இணையà®à¯ à®à¯‡à®µà¯ˆ வழஙà¯à®•à¯à®¨à®°à¯ அலà¯à®²à®¤à¯ நீஙà¯à®•à®³à¯ à®à¯†à®²à¯à®²à¯à®®à¯ இணையதளஙà¯à®•à®³à®¿à®Ÿà®®à¯ உஙà¯à®•à®³à¯ உலாவலை மறைகà¯à®•à®¾à®¤à¯.</translation>
<translation id="7887683347370398519">CVCà®à®à¯ à®à¯‹à®¤à®¿à®¤à¯à®¤à¯, மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="7894616681410591072">à®…à®à¯à®à®à¯‹! இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆ அணà¯à®•, <ph name="NAME" /> இடம௠அனà¯à®®à®¤à®¿ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯.</translation>
-<translation id="790025292736025802"><ph name="URL" /> காணபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="7912024687060120840">கோபà¯à®ªà¯à®±à¯ˆà®¯à®¿à®²à¯:</translation>
<translation id="7920092496846849526">இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà®²à®¾à®®à®¾ à®à®©, நீஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯à®•à®³à®¿à®Ÿà®®à¯ கேடà¯à®Ÿà¯à®³à¯à®³à¯€à®°à¯à®•à®³à¯.</translation>
<translation id="7935318582918952113">DOM டிஸà¯à®Ÿà®¿à®²à¯à®²à®°à¯</translation>
@@ -589,9 +624,10 @@
<translation id="7995512525968007366">கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="8012647001091218357">தறà¯à®ªà¯‹à®¤à¯ à®à®™à¯à®•à®³à®¾à®²à¯ உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à¯à®•à®³à¯ˆà®¤à¯ தà¯à®Ÿà®°à¯à®ªà¯à®•à¯à®³à¯à®³ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="8034522405403831421">இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ <ph name="SOURCE_LANGUAGE" /> à®®à¯à®´à®¿à®¯à®¿à®²à¯ உளà¯à®³à®¤à¯. இதை <ph name="TARGET_LANGUAGE" /> கà¯à®•à¯ à®®à¯à®´à®¿à®ªà¯†à®¯à®°à¯à®•à¯à®•à®µà®¾?</translation>
-<translation id="8034955203865359138">வரலாற௠உளà¯à®³à¯€à®Ÿà¯à®•à®³à¯ இலà¯à®²à¯ˆ.</translation>
<translation id="8088680233425245692">கடà¯à®Ÿà¯à®°à¯ˆà®¯à¯ˆà®•à¯ காடà¯à®Ÿà¯à®µà®¤à®¿à®²à¯ தோலà¯à®µà®¿.</translation>
+<translation id="8089520772729574115">1 மெ.பை. கà¯à®•à¯à®®à¯ கà¯à®±à¯ˆà®µà®¾à®• உளà¯à®³à®¤à¯</translation>
<translation id="8091372947890762290">à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¿à®²à¯ à®à¯†à®¯à®²à®¾à®•à¯à®•à®®à¯ நிலà¯à®µà¯ˆà®¯à®¿à®²à¯à®³à¯à®³à®¤à¯</translation>
+<translation id="8129262335948759431">அறியபà¯à®ªà®Ÿà®¾à®¤ தà¯à®•à¯ˆ</translation>
<translation id="8131740175452115882">உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> இன௠à®à¯‡à®µà¯ˆà®¯à®• <ph name="BEGIN_ABBR" />DNS à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®•à¯<ph name="END_ABBR" /> கணà¯à®Ÿà¯à®ªà®¿à®Ÿà®¿à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="8149426793427495338">உஙà¯à®•à®³à¯ கணினி உறகà¯à®•à®¨à®¿à®²à¯ˆà®•à¯à®•à¯à®à¯ à®à¯†à®©à¯à®±à®¤à¯.</translation>
@@ -600,6 +636,7 @@
<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" à®à®Ÿà®¿à®¯à¯à®Ÿà®©à¯ கூடிய நீடà¯à®Ÿà®¿à®ªà¯à®ªà®¿à®±à¯à®•à®¾à®© தவறான பà¯à®¤à¯à®ªà¯à®ªà®¿à®ªà¯à®ªà¯ URL.</translation>
<translation id="8218327578424803826">ஒதà¯à®•à¯à®•à®¿à®¯ இரà¯à®ªà¯à®ªà®¿à®Ÿà®®à¯:</translation>
<translation id="8225771182978767009">இநà¯à®¤à®•à¯ கணினியை அமைதà¯à®¤ நபர௠இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆà®¤à¯ தடà¯à®•à¯à®•à¯à®®à¯à®ªà®Ÿà®¿ தேரà¯à®µà¯à®à¯†à®¯à¯à®¤à¯à®³à¯à®³à®¾à®°à¯.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">நீஙà¯à®•à®³à¯ தேடà¯à®®à¯ பகà¯à®•à®®à®¾à®©à®¤à¯ நீஙà¯à®•à®³à¯ உளà¯à®³à®¿à®Ÿà¯à®Ÿ தகவலைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®¯à®¤à¯. மீணà¯à®Ÿà¯à®®à¯ அநà¯à®¤ பகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ திரà¯à®®à¯à®ªà®¿à®©à®¾à®²à¯, நீஙà¯à®•à®³à¯ à®à¯†à®¯à¯à®¤ à®à®¤à¯‡à®©à¯à®®à¯ à®à¯†à®¯à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ à®à¯†à®¯à¯à®¯ வேணà¯à®Ÿà®¿à®¯à®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. தà¯à®Ÿà®° விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾?</translation>
<translation id="8249320324621329438">கடைà®à®¿à®¯à®¾à®• à®à®Ÿà¯à®¤à¯à®¤à®¤à¯:</translation>
<translation id="8261506727792406068">நீகà¯à®•à¯</translation>
@@ -612,12 +649,17 @@
<translation id="8349305172487531364">பà¯à®•à¯à®®à®¾à®°à¯à®•à¯ படà¯à®Ÿà®¿</translation>
<translation id="8363502534493474904">விமானப௠பயனà¯à®®à¯à®±à¯ˆà®¯à¯ˆ à®®à¯à®Ÿà®•à¯à®•à¯à®¤à®²à¯</translation>
<translation id="8364627913115013041">அமைகà¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="8380941800586852976">ஆபதà¯à®¤à®¾à®©à®¤à¯</translation>
<translation id="8412145213513410671">à®à¯†à®¯à®²à®¿à®´à®ªà¯à®ªà¯à®•à®³à¯ (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">நீஙà¯à®•à®³à¯ கணà¯à®Ÿà®¿à®ªà¯à®ªà®¾à®• ஒரே கடவà¯à®à¯à®à¯à®±à¯à®±à¯à®Ÿà®°à¯ˆ இர௠மà¯à®±à¯ˆ உளà¯à®³à®¿à®Ÿ வேணà¯à®Ÿà¯à®®à¯.</translation>
<translation id="8428213095426709021">அமைபà¯à®ªà¯à®•à®³à¯</translation>
+<translation id="8433057134996913067">இதனால௠பெரà¯à®®à¯à®ªà®¾à®²à®¾à®© வலைதà¯à®¤à®³à®™à¯à®•à®³à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ வெளியேறà¯à®±à®ªà¯à®ªà®Ÿà¯à®µà¯€à®°à¯à®•à®³à¯.</translation>
<translation id="8437238597147034694">&amp;நகரà¯à®¤à¯à®¤à®²à¯ˆà®à¯ à®à¯†à®¯à®²à¯à®¤à®µà®¿à®°à¯</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 கிரெடிட௠காரà¯à®Ÿà¯}other{# கிரெடிட௠காரà¯à®Ÿà¯à®•à®³à¯}}</translation>
+<translation id="8483780878231876732">Google கணகà¯à®•à®¿à®²à¯ உளà¯à®³ காரà¯à®Ÿà¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤, Chrome இல௠உளà¯à®¨à¯à®´à¯ˆà®¯à®µà¯à®®à¯</translation>
<translation id="8488350697529856933">இதறà¯à®•à¯à®ªà¯ பà¯à®°à¯à®¨à¯à®¤à¯à®®à¯</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> பதிலளிகà¯à®• நீணà¯à®Ÿ நேரம௠à®à®Ÿà¯à®¤à¯à®¤à¯à®•à¯à®•à¯à®£à¯à®Ÿà®¤à¯.</translation>
+<translation id="852346902619691059"><ph name="DOMAIN" /> à®à®© இநà¯à®¤à®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®¤à¯à®¤à®¾à®²à¯ நிரூபிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ உஙà¯à®•à®³à¯ à®à®¾à®¤à®©à®¤à¯à®¤à®¿à®©à¯ இயகà¯à®• à®®à¯à®±à¯ˆà®®à¯ˆ நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Google Payments இல௠இநà¯à®¤ வகையான காரà¯à®Ÿà¯ ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯. வேறà¯à®°à¯ காரà¯à®Ÿà¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="8550022383519221471">உஙà¯à®•à®³à¯ டà¯à®®à¯ˆà®©à®¿à®±à¯à®•à¯ ஒதà¯à®¤à®¿à®à¯ˆà®¤à¯à®¤à®²à¯ à®à¯‡à®µà¯ˆ கிடைகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="8553075262323480129">பகà¯à®•à®¤à¯à®¤à®¿à®©à¯ மொழியைத௠தீரà¯à®®à®¾à®©à®¿à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à®¤à®¾à®²à¯ மொழிபெயரà¯à®ªà¯à®ªà¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯.</translation>
@@ -629,15 +671,12 @@
<translation id="8647750283161643317">à®à®²à¯à®²à®¾à®µà®±à¯à®±à¯ˆà®¯à¯à®®à¯ இயலà¯à®ªà¯à®¨à®¿à®²à¯ˆà®•à¯à®•à¯ மீடà¯à®Ÿà®®à¯ˆ</translation>
<translation id="8680787084697685621">கணகà¯à®•à¯ உளà¯à®¨à¯à®´à¯ˆà®µà¯ விவரஙà¯à®•à®³à¯ காலாவதியாகிவிடà¯à®Ÿà®©.</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> கà¯à®•à®¾à®© உஙà¯à®•à®³à¯ இணைபà¯à®ªà¯ கà¯à®±à®¿à®¯à®¾à®•à¯à®•à®®à¯ à®à¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
-<translation id="8713130696108419660">தà¯à®Ÿà®•à¯à®• விà®à¯ˆà®¯à®¿à®©à¯ கையà¯à®ªà¯à®ªà®®à¯ தவறானதà¯</translation>
<translation id="8725066075913043281">மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®à®¿à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="8728672262656704056">மறைநிலைகà¯à®•à¯à®à¯ à®à¯†à®©à¯à®±à¯à®µà®¿à®Ÿà¯à®Ÿà¯€à®°à¯à®•à®³à¯</translation>
<translation id="8730621377337864115">à®®à¯à®Ÿà®¿à®¨à¯à®¤à®¤à¯</translation>
<translation id="8738058698779197622">பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© இணைபà¯à®ªà¯ˆ அமைகà¯à®•, கடிகாரம௠à®à®°à®¿à®¯à®¾à®• அமைகà¯à®•à®ªà¯à®ªà®Ÿ வேணà¯à®Ÿà¯à®®à¯. இதறà¯à®•à¯à®•à¯ காரணமà¯, இணையதளஙà¯à®•à®³à¯ தஙà¯à®•à®³à¯ˆà®¤à¯ தானே அடையாளபà¯à®ªà®Ÿà¯à®¤à¯à®¤ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯à®•à®³à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ காலநேரதà¯à®¤à®¿à®±à¯à®•à¯‡ à®à¯†à®²à¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à¯à®®à¯. உஙà¯à®•à®³à¯ à®à®¾à®¤à®©à®¤à¯à®¤à®¿à®©à¯ கடிகாரம௠தவறாக இரà¯à®¨à¯à®¤à®¾à®²à¯, Chromium இநà¯à®¤à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯à®•à®³à¯ˆà®à¯ à®à®°à®¿à®ªà®¾à®°à¯à®•à¯à®•à®¾à®¤à¯.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />’s &lt;abbr id="dnsDefinition"&gt;DNS à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®•à¯&lt;/abbr&gt; கணà¯à®Ÿà®±à®¿à®¯ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. à®à®¿à®•à¯à®•à®²à¯ˆ ஆயà¯à®µà¯ à®à¯†à®¯à¯à®•à®¿à®±à®¤à¯.</translation>
-<translation id="8741995161408053644">உஙà¯à®•à®³à¯ Google கணகà¯à®•à¯ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> à®à®©à¯à®± தளதà¯à®¤à®¿à®²à¯ உலாவல௠வரலாற௠தà¯à®Ÿà®°à¯à®ªà®¾à®© பிற தகவலà¯à®•à®³à¯ˆà®•à¯ கà¯à®£à¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="8790007591277257123">&amp;நீகà¯à®•à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ à®à¯†à®¯à¯</translation>
-<translation id="8790687370365610530">Google பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à¯à®®à¯ தனிபà¯à®ªà®¯à®©à®¾à®•à¯à®•à®¿à®¯ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பெற, வரலாறà¯à®±à¯ ஒதà¯à®¤à®¿à®à¯ˆà®µà¯ˆ இயகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="8798099450830957504">இயலà¯à®ªà¯à®¨à®¿à®²à¯ˆ</translation>
<translation id="8804164990146287819">தனியà¯à®°à®¿à®®à¯ˆà®•à¯ கà¯à®³à¯à®•à¯ˆ</translation>
<translation id="8820817407110198400">பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®•à®³à¯</translation>
@@ -659,13 +698,11 @@
<translation id="8971063699422889582">à®à¯‡à®µà¯ˆà®¯à®•à®à¯ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ காலாவதியானதà¯.</translation>
<translation id="8987927404178983737">மாதமà¯</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ வெளிபà¯à®ªà®Ÿà¯ˆà®¤à¯à®¤à®©à¯à®®à¯ˆ கà¯à®³à¯à®•à¯ˆà®¯à®¿à®©à¯à®ªà®Ÿà®¿ பà¯à®¤à¯à®µà®¿à®²à¯ வெளியிடபà¯à®ªà®Ÿà®¾à®¤ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆà®à¯ à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ வழஙà¯à®•à®¿à®¯à¯à®³à¯à®³à®¤à¯. நமà¯à®ªà®•à®¤à¯à®¤à®©à¯à®®à¯ˆ மறà¯à®±à¯à®®à¯ தாகà¯à®•à¯à®¤à®²à¯à®•à®³à¯à®•à¯à®•à¯ à®à®¤à®¿à®°à®¾à®© பாதà¯à®•à®¾à®ªà¯à®ªà¯ˆ உறà¯à®¤à®¿à®à¯†à®¯à¯à®¯, à®à®¿à®² à®à®¾à®©à¯à®±à®¿à®¤à®´à¯à®•à®³à¯à®•à¯à®•à¯ இத௠தேவையான ஒனà¯à®±à®¾à®•à¯à®®à¯.</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> à®à®©à¯à®•à®¿à®± பà¯à®°à®¾à®•à¯à®¸à®¿à®•à¯à®•à¯ பயனரà¯à®ªà¯†à®¯à®°à¯à®®à¯ கடவà¯à®à¯à®à¯à®²à¯à®²à¯à®®à¯ தேவை.</translation>
<translation id="901974403500617787">கணினி அளவில௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®®à¯ கà¯à®Ÿà®¿à®•à®³à¯ பினà¯à®µà®°à¯à®®à¯ உரிமையாளரால௠மடà¯à®Ÿà¯à®®à¯‡ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ <ph name="TARGET_LANGUAGE" /> கà¯à®•à¯ à®®à¯à®´à®¿à®ªà¯†à®¯à®°à¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="9038649477754266430">பகà¯à®•à®™à¯à®•à®³à¯ˆ இனà¯à®©à¯à®®à¯ விரைவாக à®à®±à¯à®±, யூக à®à¯‡à®µà¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="9039213469156557790">மேலà¯à®®à¯, பாதà¯à®•à®¾à®ªà¯à®ªà®±à¯à®± பிற ஆதாரஙà¯à®•à®³à¯ இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à®¿à®²à¯ உளà¯à®³à®©. இநà¯à®¤ ஆதாரஙà¯à®•à®³à¯ˆ டà¯à®°à®¾à®©à¯à®¸à®¿à®Ÿà¯à®Ÿà®¿à®²à¯ இரà¯à®•à¯à®•à¯à®®à¯à®ªà¯‹à®¤à¯à®®à¯ பிறர௠பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà®²à®¾à®®à¯, மேலà¯à®®à¯ பகà¯à®•à®¤à¯à®¤à®¿à®©à¯ à®à¯†à®¯à®²à¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆ மாறà¯à®±, தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ அதை மாறà¯à®±à®¿à®¯à®®à¯ˆà®•à¯à®•à®²à®¾à®®à¯.</translation>
-<translation id="9049981332609050619">நீஙà¯à®•à®³à¯ <ph name="DOMAIN" /> ஠அடைய à®®à¯à®¯à®±à¯à®à®¿ à®à¯†à®¯à¯à®¤à¯€à®°à¯à®•à®³à¯, ஆனால௠à®à¯‡à®µà¯ˆà®¯à®•à®®à¯ ஒர௠à®à¯†à®²à¯à®²à®¾à®¤ à®à®¾à®©à¯à®±à®¿à®¤à®´à¯ˆ வழஙà¯à®•à®¿à®¯à®¤à¯.</translation>
<translation id="9050666287014529139">கடவà¯à®à¯à®à¯à®±à¯à®±à¯à®Ÿà®°à¯</translation>
<translation id="9065203028668620118">திரà¯à®¤à¯à®¤à¯</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> பகà¯à®•à®®à¯ à®à¯†à®¯à®²à¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
diff --git a/chromium/components/strings/components_strings_te.xtb b/chromium/components/strings/components_strings_te.xtb
index 1553bac910a..f600b657620 100644
--- a/chromium/components/strings/components_strings_te.xtb
+++ b/chromium/components/strings/components_strings_te.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="te">
+<translation id="1008557486741366299">ఇపà±à°ªà±à°¡à± కాదà±</translation>
<translation id="1015730422737071372">అదనపౠవివరాలనౠఅందింà°à°‚à°¡à°¿</translation>
<translation id="1032854598605920125">సవà±à°¯à°¦à°¿à°¶à°²à±‹ తిపà±à°ªà±</translation>
<translation id="1038842779957582377">తెలియని పేరà±</translation>
+<translation id="1053591932240354961"><ph name="SITE" /> Google Chrome à°ªà±à°°à°¾à°¸à±†à°¸à± à°à±‡à°¯à°²à±‡à°¨à°¿ విధంగా గజిబిజిగా ఉండే ఆధారాలనౠపంపినందà±à°¨ మీరౠపà±à°°à°¸à±à°¤à±à°¤à°‚ à°† వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°¨à°¿ సందరà±à°¶à°¿à°‚à°à°²à±‡à°°à±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, à°•à°¨à±à°• à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని à°à±‡à°¸à±‡ అవకాశం ఉంది. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;జోడింà°à°¡à°¾à°¨à±à°¨à°¿ à°°à°¦à±à°¦à± à°à±‡à°¯à°¿</translation>
<translation id="10614374240317010">à°à°ªà±à°ªà°Ÿà°¿à°•à°¿ సేవౠà°à±†à°¯à±à°¯à°¬à°¡à°µà±</translation>
-<translation id="1064422015032085147">వెబà±â€Œà°ªà±‡à°œà±€à°¨à°¿ హోసà±à°Ÿà± à°à±‡à°¸à±à°¤à±à°¨à±à°¨ సరà±à°µà°°à±â€Œà°ªà±ˆ అధిక భారం పడి ఉండవà°à±à°à± లేదా నిరà±à°µà°¹à°£à°²à±‹ భాగంగా దానà±à°¨à°¿ తాతà±à°•à°¾à°²à°¿à°•à°‚à°—à°¾ నిలిపివేసి ఉండవà°à±à°à±.
- à°à°•à±à°•à±à°µ à°Ÿà±à°°à°¾à°«à°¿à°•à± ఉతà±à°ªà°¨à±à°¨à°‚ కాకà±à°‚à°¡à°¾ మరియౠపరిసà±à°¥à°¿à°¤à°¿ à°…à°§à±à°µà°¾à°¨à±à°¨à°‚ కాకà±à°‚à°¡à°¾ నివారింà°à°¡à°¾à°¨à°¿à°•à°¿,
- à°ˆ URLà°•à°¿ à°…à°­à±à°¯à°°à±à°¥à°¨à°²à± తాతà±à°•à°¾à°²à°¿à°•à°‚à°—à°¾ ఆపివేయబడà±à°¡à°¾à°¯à°¿.</translation>
<translation id="106701514854093668">డెసà±à°•à±â€Œà°Ÿà°¾à°ªà±â€Œ à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
<translation id="1080116354587839789">వెడలà±à°ªà± సరిపోయేలా అమరà±à°à±</translation>
+<translation id="1103124106085518534">à°ªà±à°°à°¸à±à°¤à±à°¤à°¾à°¨à°¿à°•à°¿ పూరà±à°¤à°¯à°¿à°‚ది</translation>
<translation id="1103523840287552314">à°à°²à±à°²à°ªà±à°ªà±à°¡à±‚ <ph name="LANGUAGE" />నౠఅనà±à°µà°¦à°¿à°‚à°à±</translation>
<translation id="1107591249535594099">à°à°‚à°à±à°•à±à°¨à±à°¨à°Ÿà±à°²à°¯à°¿à°¤à±‡, Chrome వేగవంతమైన ఫారమౠపూరింపౠకోసం à°ˆ పరికరంలో మీ కారà±à°¡à± కాపీని నిలà±à°µ à°à±‡à°¸à±à°¤à±à°‚ది.</translation>
+<translation id="1111153019813902504">ఇటీవలి à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
<translation id="1113869188872983271">&amp;మళà±à°²à±€ à°•à±à°°à°®à°‚ à°à±‡à°¯à°¡à°¾à°¨à±à°¨à°¿ à°°à°¦à±à°¦à± à°à±‡à°¯à°¿</translation>
+<translation id="1126551341858583091">à°¸à±à°¥à°¾à°¨à°¿à°• నిలà±à°µà°²à±‹ పరిమాణం <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">విధాన కాషౠసరిపోయింది</translation>
<translation id="113188000913989374"><ph name="SITE" /> ఇలా à°à±†à°¬à±à°¤à±‹à°‚ది:</translation>
<translation id="1132774398110320017">Chrome à°¸à±à°µà°¯à°‚పూరà±à°¤à°¿ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±...</translation>
-<translation id="1150979032973867961">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ మీ à°•à°‚à°ªà±à°¯à±‚టరౠఆపరేటింగౠసిసà±à°Ÿà°®à± విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¦à±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±.</translation>
<translation id="1152921474424827756"><ph name="URL" /> à°¯à±à°•à±à°• <ph name="BEGIN_LINK" />కాషౠà°à±‡à°¯à°¬à°¡à°¿à°¨ కాపీ<ph name="END_LINK" />ని à°ªà±à°°à°¾à°ªà±à°¯à°¤ à°à±‡à°¯à°‚à°¡à°¿</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> à°à°¹à°¿à°‚à°à°¨à°¿ విధంగా కనెకà±à°·à°¨à±â€Œà°¨à± మూసివేసింది.</translation>
<translation id="1161325031994447685">Wi-Fià°•à°¿ మళà±à°²à±€ కనెకà±à°Ÿà± à°à±‡à°¯à°¡à°‚</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">à°¤à±à°²à°—à°¿à°‚à°à±</translation>
<translation id="1201402288615127009">తదà±à°ªà°°à°¿</translation>
<translation id="1201895884277373915">à°ˆ సైటౠనà±à°‚à°¡à°¿ మరింత</translation>
-<translation id="121201262018556460">మీరౠ<ph name="DOMAIN" />నౠà°à±‡à°°à±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¾à°°à±, కానీ సరà±à°µà°°à± బలహీన కీని కలిగి ఉనà±à°¨ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ అందింà°à°¿à°‚ది. దాడి à°à±‡à°¸à±‡à°µà°¾à°°à± à°ªà±à°°à±ˆà°µà±‡à°Ÿà± కీని విà°à±à°›à°¿à°¨à±à°¨à°‚ à°à±‡à°¶à°¾à°°à± మరియౠసరà±à°µà°°à± మీరౠà°à°¹à°¿à°‚à°à°¿à°¨ సరà±à°µà°°à± కాకపోవà°à±à°à± (మీరౠదాడి à°à±‡à°¸à±‡ వారితో à°•à°®à±à°¯à±‚నికేటౠà°à±‡à°¸à±à°¤à±à°‚à°¡à°µà°à±à°à±).</translation>
+<translation id="1206967143813997005">తపà±à°ªà± à°ªà±à°°à°¾à°°à°‚à°­ సంతకం</translation>
+<translation id="1209206284964581585">à°ªà±à°°à°¸à±à°¤à±à°¤à°¾à°¨à°¿à°•à°¿ దాà°à±</translation>
<translation id="1219129156119358924">సిసà±à°Ÿà°®à± à°­à°¦à±à°°à°¤</translation>
<translation id="1227224963052638717">తెలియని విధానం.</translation>
<translation id="1227633850867390598">విలà±à°µà°¨à± దాà°à°‚à°¡à°¿</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">à°…à°µà±à°¨à±</translation>
<translation id="1430915738399379752">à°®à±à°¦à±à°°à°¿à°‚à°à±</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /><ph name="DOMAIN" />లో పేజీని సందరà±à°¶à°¿à°‚à°à°¡à°¾à°¨à°¿à°•à°¿<ph name="END_LINK" /> à°à±‡à°¸à°¿à°¨ à°ªà±à°°à°¯à°¤à±à°¨à°‚ à°¬à±à°²à°¾à°•à± à°à±‡à°¯à°¬à°¡à°¿à°‚ది.</translation>
+<translation id="1491663344921578213">వెబà±â€Œà°¸à±ˆà°Ÿà± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ పినౠà°à±‡à°¯à°¬à°¡à±‡ పదà±à°§à°¤à°¿à°¨à°¿ ఉపయోగిసà±à°¤à±à°¨à±à°¨à°‚à°¦à±à°¨ మీరౠఇపà±à°ªà±à°¡à± <ph name="SITE" />ని సందరà±à°¶à°¿à°‚à°à°²à±‡à°°à±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, కావà±à°¨ à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని à°à±‡à°¸à±‡ అవకాశం ఉంది. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">à°ˆ పేజీ à°¯à±à°•à±à°• సేవౠà°à±‡à°¸à°¿à°¨ (అంటే పాతది) కాపీని à°à±‚à°ªà±à°¤à±à°‚ది.</translation>
<translation id="1519264250979466059">రూపకలà±à°ªà°¨ తేదీ</translation>
<translation id="1549470594296187301">à°ˆ లకà±à°·à°£à°¾à°¨à±à°¨à°¿ ఉపయోగింà°à°¡à°¾à°¨à°¿à°•à°¿ జావాసà±à°•à±à°°à°¿à°ªà±à°Ÿà± తపà±à°ªà°¨à°¿à°¸à°°à°¿à°—à°¾ à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°à°¾à°²à°¿.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">నెటà±â€Œà°µà°°à±à°•à± కానà±à°«à°¿à°—రేషనౠà°à±†à°²à±à°²à°¦à± మరియౠదిగà±à°®à°¤à°¿ à°à±‡à°¯à°¡à°‚ సాధà±à°¯à°‚ కాదà±.</translation>
<translation id="1644574205037202324">à°à°°à°¿à°¤à±à°°</translation>
<translation id="1645368109819982629">à°ªà±à°°à±‹à°Ÿà±‹à°•à°¾à°²à±â€Œà°•à± మదà±à°¦à°¤à± లేదà±</translation>
-<translation id="1655462015569774233">{1,plural, =1{à°ˆ సరà±à°µà°°à± ఇది <ph name="DOMAIN" /> అని నిరూపింà°à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± నినà±à°¨ à°®à±à°—ిసింది. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¸à°¿à°¨à°‚à°¦à±à°¨ లేదా దాడిà°à±‡à°¸à±‡à°µà°¾à°°à± మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగింà°à°¿à°¨à°‚à°¦à±à°¨ ఇలా జరిగి ఉండవà°à±à°à±. మీ à°•à°‚à°ªà±à°¯à±‚టరౠగడియారం à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="CURRENT_DATE" />à°•à°¿ సెటౠà°à±‡à°¯à°¬à°¡à°¿à°‚ది. అది సరిగà±à°—à°¾ ఉందా? సరిగà±à°—à°¾ లేకà±à°‚టే, మీరౠసిసà±à°Ÿà°®à± గడియారానà±à°¨à°¿ సరిà°à±‡à°¸à°¿, ఆపై à°ˆ పేజీని రీఫà±à°°à±†à°·à± à°à±‡à°¯à°¾à°²à°¿.}other{à°ˆ సరà±à°µà°°à± ఇది <ph name="DOMAIN" /> అని నిరూపింà°à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± # రోజà±à°² à°•à±à°°à°¿à°¤à°‚ à°®à±à°—ిసింది. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¸à°¿à°¨à°‚à°¦à±à°¨ లేదా దాడిà°à±‡à°¸à±‡à°µà°¾à°°à± మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగింà°à°¿à°¨à°‚à°¦à±à°¨ ఇలా జరిగి ఉండవà°à±à°à±. మీ à°•à°‚à°ªà±à°¯à±‚టరౠగడియారం à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="CURRENT_DATE" />à°•à°¿ సెటౠà°à±‡à°¯à°¬à°¡à°¿à°‚ది. అది సరిగà±à°—à°¾ ఉందా? సరిగà±à°—à°¾ లేకà±à°‚టే, మీరౠసిసà±à°Ÿà°®à± గడియారానà±à°¨à°¿ సరిà°à±‡à°¸à°¿, ఆపై à°ˆ పేజీని రీఫà±à°°à±†à°·à± à°à±‡à°¯à°¾à°²à°¿.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> సాధారణంగా మీ సమాà°à°¾à°°à°¾à°¨à±à°¨à°¿ à°°à°•à±à°·à°¿à°‚à°à°¡à°¾à°¨à°¿à°•à°¿ à°—à±à°ªà±à°¤à±€à°•à°°à°£à°¨à± ఉపయోగిసà±à°¤à±à°‚ది. Google Chrome ఈసారి <ph name="SITE" />à°•à°¿ కనెకà±à°Ÿà± à°à±‡à°¯à°¡à°¾à°¨à°¿à°•à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¿à°¨à°ªà±à°ªà±à°¡à±, వెబà±â€Œà°¸à±ˆà°Ÿà± అసాధారణ మరియౠతపà±à°ªà± ఆధారాలౠఅని à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దింà°à°¿à°‚ది. దాడి à°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ <ph name="SITE" />à°—à°¾ à°µà±à°¯à°µà°¹à°°à°¿à°‚à°à°¿ మోసగింà°à°¡à°¾à°¨à°¿à°•à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°¸à±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± లేదా Wi-Fi సైనà±-ఇనౠసà±à°•à±à°°à±€à°¨à± కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగింà°à°¿à°¨à°ªà±à°ªà±à°¡à± ఇలా జరగవà°à±à°à±. Google Chrome డేటా వినిమయం సంభవింà°à°• à°®à±à°‚దే కనెకà±à°·à°¨à±â€Œà°¨à± ఆపివేసినందà±à°¨ మీ సమాà°à°¾à°°à°‚ ఇపà±à°ªà°Ÿà°¿à°•à±€ à°¸à±à°°à°•à±à°·à°¿à°¤à°‚గానే ఉంది.</translation>
<translation id="168841957122794586">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ బలహీన à°•à±à°°à°¿à°ªà±à°Ÿà±‹à°—à±à°°à°¾à°«à°¿à°•à± కీని కలిగి ఉంది.</translation>
<translation id="1701955595840307032">సూà°à°¿à°¤ కంటెంటà±â€Œà°¨à± à°ªà±à°‚దండి</translation>
-<translation id="1706954506755087368">{1,plural, =1{à°ˆ సరà±à°µà°°à± ఇది <ph name="DOMAIN" /> అని నిరూపింà°à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ రేపటిది కావà°à±à°à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¸à°¿à°¨à°‚à°¦à±à°¨ లేదా దాడిà°à±‡à°¸à±‡à°µà°¾à°°à± మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగింà°à°¿à°¨à°‚à°¦à±à°¨ ఇలా జరిగి ఉండవà°à±à°à±.}other{à°ˆ సరà±à°µà°°à± ఇది <ph name="DOMAIN" /> అని నిరూపింà°à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ భవిషà±à°¯à°¤à±à°¤à±à°²à±‹ # రోజà±à°² తదà±à°ªà°°à°¿à°¦à°¿ కావà°à±à°à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¸à°¿à°¨à°‚à°¦à±à°¨ లేదా దాడిà°à±‡à°¸à±‡à°µà°¾à°°à± మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగింà°à°¿à°¨à°‚à°¦à±à°¨ ఇలా జరిగి ఉండవà°à±à°à±.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">సిసà±à°Ÿà°®à± నిరà±à°µà°¾à°¹à°•à±à°¡à°¿à°¨à°¿ సంపà±à°°à°¦à°¿à°‚à°à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
<translation id="17513872634828108">తెరిà°à°¿à°¨ à°Ÿà±à°¯à°¾à°¬à±â€à°²à±</translation>
<translation id="1753706481035618306">పేజీ సంఖà±à°¯</translation>
-<translation id="1761412452051366565">Google సూà°à°¿à°‚à°à±‡ à°µà±à°¯à°•à±à°¤à°¿à°—తీకృత కంటెంటà±â€Œà°¨à± à°ªà±à°‚దడానికి, సమకాలీకరణనౠఆనౠà°à±‡à°¯à°‚à°¡à°¿.</translation>
-<translation id="1763864636252898013">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ మీ పరికర ఆపరేటింగౠసిసà±à°Ÿà°®à± విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¦à±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows నెటà±â€Œà°µà°°à±à°•à± సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± అమలౠà°à±‡à°¯à°¡à°‚ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">దయà°à±‡à°¸à°¿ మీ సమకాలీకరణ పాసà±â€Œà°«à±à°°à±‡à°œà±â€Œà°¨à± నవీకరింà°à°‚à°¡à°¿.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">మీరౠఇటీవల సందరà±à°¶à°¿à°‚à°à°¿à°¨ à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à± ఇకà±à°•à°¡ కనిపిసà±à°¤à°¾à°¯à°¿.</translation>
<translation id="1821930232296380041">à°à±†à°²à±à°²à°¨à°¿ à°…à°­à±à°¯à°°à±à°¥à°¨ లేదా à°…à°­à±à°¯à°°à±à°¥à°¨ పరామితà±à°²à±</translation>
<translation id="1838667051080421715">మీరౠవెబౠపేజీ à°¯à±à°•à±à°• సోరà±à°¸à±â€Œà°¨à± వీకà±à°·à°¿à°¸à±à°¤à±à°¨à±à°¨à°¾à°°à±.</translation>
<translation id="1871208020102129563">à°ªà±à°°à°¾à°•à±à°¸à±€ à°¸à±à°¥à°¿à°°à°®à±ˆà°¨ à°ªà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±â€Œà°²à°¨à± ఉపయోగింà°à°¡à°¾à°¨à°¿à°•à°¿ సెటౠà°à±‡à°¯à°¬à°¡à°¿à°‚ది, .pac à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± URLనౠకాదà±.</translation>
<translation id="1883255238294161206">జాబితానౠకà±à°¦à°¿à°‚à°à±</translation>
<translation id="1898423065542865115">à°«à°¿à°²à±à°Ÿà°°à°¿à°‚à°—à±</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> మీ లాగినౠపà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ ఆమోదింà°à°²à±‡à°¦à± లేదా మీ లాగినౠపà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± à°®à±à°—ిసి ఉండవà°à±à°à±.</translation>
<translation id="194030505837763158"><ph name="LINK" />à°•à°¿ వెళà±à°²à°‚à°¡à°¿</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
<translation id="1973335181906896915">à°¶à±à°°à±‡à°£à°¿à°—à°¾ రూపà±à°‚దింà°à°¡à°‚లో లోపం</translation>
<translation id="1974060860693918893">ఆధà±à°¨à°¿à°•</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{మరియౠమరà±à°•à°Ÿà°¿}other{మరియౠమరో #}}</translation>
<translation id="2025186561304664664">à°ªà±à°°à°¾à°•à±à°¸à±€ à°¸à±à°µà°¯à°‚à°à°¾à°²à°•à°‚à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¬à°¡à±‡à°²à°¾ సెటౠà°à±‡à°¯à°¬à°¡à°¿à°‚ది.</translation>
<translation id="2030481566774242610">మీ ఉదà±à°¦à±‡à°¶à±à°¯à°‚ <ph name="LINK" />?</translation>
<translation id="2031925387125903299">మీరౠమà±à°¦à°Ÿà°¿à°¸à°¾à°°à°¿ à°•à±à°¤à±à°¤ సైటà±â€Œà°²à°¨à± సందరà±à°¶à°¿à°‚à°à°¿à°¨à°ªà±à°ªà±à°¡à± వాటిని మీ తలà±à°²à°¿à°¦à°‚à°¡à±à°°à±à°²à± ఆమోదింà°à°¾à°²à±à°¸à°¿à°¨ ఆవశà±à°¯à°•à°‚ ఉనà±à°¨à°‚à°¦à±à°¨ మీకౠఈ సందేశం కనిపిసà±à°¤à±‹à°‚ది.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />à°ªà±à°°à°¾à°•à±à°¸à±€ మరియౠఫైరà±â€Œà°µà°¾à°²à±â€Œà°¨à± తనిఖీ à°à±‡à°¯à°¡à°‚<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">జిపౠకోడà±</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 సూà°à°¨}other{# సూà°à°¨à°²à±}}</translation>
<translation id="2065985942032347596">à°ªà±à°°à°¾à°®à°¾à°£à±€à°•à°°à°£ అవసరం</translation>
<translation id="2079545284768500474">à°…à°¨à±à°¡à±</translation>
<translation id="20817612488360358">సిసà±à°Ÿà°®à± à°ªà±à°°à°¾à°•à±à°¸à±€ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à± ఉపయోగింà°à°¡à°¾à°¨à°¿à°•à°¿ సెటౠà°à±‡à°¯à°¬à°¡à±à°¡à°¾à°¯à°¿ కానీ à°¸à±à°ªà°·à±à°Ÿà°®à±ˆà°¨ à°ªà±à°°à°¾à°•à±à°¸à±€ కానà±à°«à°¿à°—రేషనౠకూడా పేరà±à°•à±à°¨à°¬à°¡à°¿à°‚ది.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°¨à± సవరింà°à±</translation>
<translation id="2166049586286450108">పూరà±à°¤à°¿ నిరà±à°µà°¾à°¹à°• à°ªà±à°°à°¾à°ªà±à°¯à°¤</translation>
<translation id="2166378884831602661">à°ˆ సైటౠసà±à°°à°•à±à°·à°¿à°¤à°®à±ˆà°¨ కనెకà±à°·à°¨à±â€Œà°¨à± అందింà°à°²à±‡à°¦à±</translation>
-<translation id="2171101176734966184"><ph name="DOMAIN" />నౠà°à±‡à°°à±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ మీరౠపà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¾à°°à±, కానీ సరà±à°µà°°à± బలహీనమైన సంతకం à°…à°²à±à°—ారిథమà±â€Œà°¨à± ఉపయోగింà°à°¿ సంతకం à°à±‡à°¸à°¿à°¨ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ అందింà°à°¿à°‚ది. అంటే సరà±à°µà°°à± అందింà°à°¿à°¨ à°­à°¦à±à°°à°¤ ఆధారాలౠనకిలీ కావà°à±à°à± మరియౠసరà±à°µà°°à± మీరౠà°à°¹à°¿à°‚à°à°¿à°¨ సరà±à°µà°°à± కాకపోవà°à±à°à± (మీరౠదాడి à°à±‡à°¸à±‡ వారితో à°•à°®à±à°¯à±‚నికేటౠà°à±‡à°¸à±à°¤à±à°‚à°¡à°µà°à±à°à±).</translation>
<translation id="2181821976797666341">విధానాలà±</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 à°à°¿à°°à±à°¨à°¾à°®à°¾}other{# à°à°¿à°°à±à°¨à°¾à°®à°¾à°²à±}}</translation>
<translation id="2212735316055980242">విధానం à°•à°¨à±à°—à±à°¨à°¬à°¡à°²à±‡à°¦à±</translation>
<translation id="2213606439339815911">నమోదà±à°²à°¨à± à°ªà±à°‚à°¦à±à°¤à±‹à°‚ది...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />విశà±à°²à±‡à°·à°£à°² à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°¨à±à°¨à°¿<ph name="END_LINK" /> ఉపయోగింà°à°¿ మీ కనెకà±à°·à°¨à±â€Œà°¨à± సరి à°à±‡à°¯à°‚à°¡à°¿</translation>
+<translation id="2239100178324503013">ఇపà±à°ªà±à°¡à±‡ పంపండి</translation>
<translation id="225207911366869382">à°ˆ విధానం కోసం à°ˆ విలà±à°µ తగà±à°—à°¿à°‚à°à°¬à°¡à°¿à°‚ది.</translation>
<translation id="2262243747453050782">HTTP లోపం</translation>
<translation id="2282872951544483773">à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేని à°ªà±à°°à°¯à±‹à°—ాలà±</translation>
<translation id="2292556288342944218">మీ ఇంటరà±à°¨à±†à°Ÿà± à°ªà±à°°à°¾à°ªà±à°¯à°¤ à°¬à±à°²à°¾à°•à± à°à±‡à°¯à°¬à°¡à°¿à°‚ది</translation>
<translation id="229702904922032456">మూల లేదా మధà±à°¯à°¸à±à°¥ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± à°®à±à°—ిసింది.</translation>
<translation id="230155334948463882">à°•à±à°¤à±à°¤ కారà±à°¡à°¾?</translation>
+<translation id="2305919008529760154">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ మోసపూరితంగా జారీ అయి ఉండవà°à±à°à±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడి à°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" />à°•à°¿ వినియోగదారౠపేరౠమరియౠపాసà±â€Œà°µà°°à±à°¡à± అవసరం.</translation>
+<translation id="2318774815570432836">వెబà±â€Œà°¸à±ˆà°Ÿà± HSTSని ఉపయోగిసà±à°¤à±à°¨à±à°¨à°‚à°¦à±à°¨ మీరౠపà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="SITE" />ని సందరà±à°¶à°¿à°‚à°à°²à±‡à°°à±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, కావà±à°¨ à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని à°à±‡à°¸à±‡ అవకాశం ఉంది. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155"><ph name="ENTRY_INDEX" />à°µ సూà°à°¿à°•à°²à±‹ à°à±†à°²à±à°²à°¨à°¿ à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à± విసà±à°®à°°à°¿à°‚à°à°¬à°¡à°¿à°‚ది</translation>
<translation id="2354001756790975382">ఇతర à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
<translation id="2359808026110333948">à°•à±à°¨à°¸à°¾à°—à±</translation>
<translation id="2365563543831475020"><ph name="CRASH_TIME" />à°•à°¿ సంగà±à°°à°¹à°¿à°‚à°à°¿à°¨ à°•à±à°°à°¾à°·à± నివేదిక à°…à°ªà±â€Œà°²à±‹à°¡à± కాలేదà±</translation>
<translation id="2367567093518048410">à°¸à±à°¥à°¾à°¯à°¿</translation>
+<translation id="2371153335857947666">{1,plural, =1{à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± నినà±à°¨ à°®à±à°—ిసింది. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¸à°¿à°¨à°‚à°¦à±à°¨ లేదా దాడిà°à±‡à°¸à±‡à°µà°¾à°°à± మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగింà°à°¿à°¨à°‚à°¦à±à°¨ ఇలా జరిగి ఉండవà°à±à°à±. మీ à°•à°‚à°ªà±à°¯à±‚టరౠగడియారం à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="CURRENT_DATE" />à°•à°¿ సెటౠà°à±‡à°¯à°¬à°¡à°¿à°‚ది. అది సరిగà±à°—à°¾ ఉందా? సరిగà±à°—à°¾ లేకà±à°‚టే, మీరౠసిసà±à°Ÿà°®à± గడియారానà±à°¨à°¿ సరిà°à±‡à°¸à°¿, ఆపై à°ˆ పేజీని రీఫà±à°°à±†à°·à± à°à±‡à°¯à°¾à°²à°¿. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.}other{à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± # రోజà±à°² à°•à±à°°à°¿à°¤à°‚ à°®à±à°—ిసింది. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¸à°¿à°¨à°‚à°¦à±à°¨ లేదా దాడిà°à±‡à°¸à±‡à°µà°¾à°°à± మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగింà°à°¿à°¨à°‚à°¦à±à°¨ ఇలా జరిగి ఉండవà°à±à°à±. మీ à°•à°‚à°ªà±à°¯à±‚టరౠగడియారం à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="CURRENT_DATE" />à°•à°¿ సెటౠà°à±‡à°¯à°¬à°¡à°¿à°‚ది. అది సరిగà±à°—à°¾ ఉందా? సరిగà±à°—à°¾ లేకà±à°‚టే, మీరౠసిసà±à°Ÿà°®à± గడియారానà±à°¨à°¿ సరిà°à±‡à°¸à°¿, ఆపై à°ˆ పేజీని రీఫà±à°°à±†à°·à± à°à±‡à°¯à°¾à°²à°¿. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">UI à°ªà±à°°à°¤à±à°¯à°¾à°®à±à°¨à°¾à°¯à°¾à°²à± à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేవà±</translation>
<translation id="2384307209577226199">à°à°‚à°Ÿà°°à±â€Œà°ªà±à°°à±ˆà°œà± డిఫాలà±à°Ÿà±</translation>
-<translation id="238526402387145295">వెబà±â€Œà°¸à±ˆà°Ÿà± <ph name="BEGIN_LINK" />HSTSని ఉపయోగిసà±à°¤à±‹à°‚ది<ph name="END_LINK" />, కావà±à°¨ మీరౠపà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="SITE" />ని సందరà±à°¶à°¿à°‚à°à°²à±‡à°°à±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, కావà±à°¨ à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని à°à±‡à°¸à±‡ అవకాశం ఉంది.</translation>
<translation id="2386255080630008482">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°°à°¦à±à°¦à± à°à±†à°¯à±à°¯à°¬à°¡à°¿à°‚ది.</translation>
<translation id="2392959068659972793">విలà±à°µ సెటౠà°à±‡à°¯à°¨à°¿ విధానాలనౠà°à±‚à°ªà±</translation>
<translation id="2396249848217231973">&amp;à°¤à±à°²à°—à°¿à°‚à°à°¡à°¾à°¨à±à°¨à°¿ à°°à°¦à±à°¦à± à°à±‡à°¯à°¿</translation>
-<translation id="2413528052993050574">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ ఉపసంహరింà°à°¬à°¡à°¿ ఉండవà°à±à°à±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±.</translation>
<translation id="2455981314101692989">à°ˆ వెబà±â€Œà°ªà±‡à°œà±€ à°ˆ ఫారమà±â€Œ కోసం à°¸à±à°µà°¯à°‚à°à°¾à°²à°•à°‚à°—à°¾ పూరà±à°¤à°¿ à°à±†à°¯à±à°¯à°¡à°¾à°¨à±à°¨à°¿ ఆపివేసింది.</translation>
+<translation id="2463739503403862330">పూరింà°à±</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />నెటà±â€Œà°µà°°à±à°•à± సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± అమలౠà°à±‡à°¯à°¡à°‚<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">à°à±†à°²à±à°²à°¨à°¿ శోధన URL.</translation>
<translation id="2491120439723279231">సరà±à°µà°°à± à°¯à±à°•à±à°• à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚లో లోపాలౠఉనà±à°¨à°¾à°¯à°¿.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">సమరà±à°ªà°¿à°‚à°à±</translation>
<translation id="2674170444375937751">మీ à°à°°à°¿à°¤à±à°° à°¨à±à°‚à°¡à°¿ à°ˆ పేజీలనౠతà±à°²à°—à°¿à°‚à°à°¦à°²à°¿à°à°¾à°°à°¾?</translation>
<translation id="2677748264148917807">నిషà±à°•à±à°°à°®à°¿à°‚à°à±</translation>
+<translation id="269990154133806163">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°° పారదరà±à°¶à°•à°¤ విధానానà±à°¨à°¿ ఉపయోగింà°à°¿ పబà±à°²à°¿à°•à±â€Œà°—à°¾ బహిరంగపరà°à°¬à°¡à°¨à°¿ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ అందింà°à°¿à°‚ది. à°•à±à°¨à±à°¨à°¿ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°²à°•à±, అవి విశà±à°µà°¸à°¨à±€à°¯à°®à±ˆà°¨à°µà°¨à°¿ మరియౠదాడి à°à±‡à°¸à±‡à°µà°¾à°°à°¿ à°¨à±à°‚à°¡à°¿ à°°à°•à±à°·à°£ à°•à°²à±à°ªà°¿à°‚à°à°—లవని నిరà±à°§à°¾à°°à°¿à°‚à°à°¡à°¾à°¨à°¿à°•à°¿ ఇది ఆవశà±à°¯à°•à°‚. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">విలà±à°µ ఆకృతికి సరిపోలలేదà±.</translation>
<translation id="2704951214193499422">Chromium à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ మీ కారà±à°¡à±â€Œà°¨à± నిరà±à°§à°¾à°°à°¿à°‚à°à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది. దయà°à±‡à°¸à°¿ తరà±à°µà°¾à°¤ మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
<translation id="2705137772291741111">à°ˆ సైటౠయà±à°•à±à°• సేవౠà°à±‡à°¯à°¬à°¡à°¿à°¨ (కాషౠà°à±‡à°¸à°¿à°¨) కాపీ à°à°¦à°µà°¦à°—ినటà±à°²à±à°—à°¾ లేదà±.</translation>
<translation id="2709516037105925701">à°¸à±à°µà°¯à°‚పూరà±à°¤à°¿</translation>
+<translation id="2712118517637785082">మీరౠ<ph name="DOMAIN" />కౠకనెకà±à°Ÿà± కావడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¾à°°à±, కానీ సరà±à°µà°°à± అందింà°à°¿à°¨ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ దానà±à°¨à°¿ జారీ à°à±‡à°¸à°¿à°¨à°µà°¾à°°à± à°°à°¦à±à°¦à± à°à±‡à°¸à°¾à°°à±. దీని à°ªà±à°°à°•à°¾à°°à°‚, సరà±à°µà°°à± అందింà°à°¿à°¨ à°­à°¦à±à°°à°¤à°¾ ఆధారాలౠఖà°à±à°à°¿à°¤à°‚à°—à°¾ విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¨à°¿à°µà°¿. మీరౠదాడి à°à±‡à°¸à±‡ వారితో à°•à°®à±à°¯à±‚నికేటౠà°à±‡à°¸à±à°¤à±à°‚à°¡à°µà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">à°…à°¨à±à°®à°¤à°¿ à°…à°¡à±à°—à±</translation>
<translation id="2721148159707890343">à°…à°­à±à°¯à°°à±à°¥à°¨ విజయవంతం అయింది</translation>
<translation id="2728127805433021124">సరà±à°µà°°à± à°¯à±à°•à±à°• à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°’à°• బలహీనమైన సంతకం à°…à°²à±à°—ారిథమౠఉపయోగింà°à°¿ సంతకం à°à±‡à°¯à°¬à°¡à°¿à°‚ది.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">à°à°¿à°°à±à°¨à°¾à°®à°¾ మరియౠశోధన బారà±</translation>
<translation id="2826760142808435982"><ph name="CIPHER" />నౠఉపయోగింà°à°¿ కనెకà±à°·à°¨à± à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°à°¬à°¡à°¿à°‚ది మరియౠపà±à°°à°¾à°®à°¾à°£à±€à°•à°°à°¿à°‚à°à°¬à°¡à°¿à°‚ది మరియౠ<ph name="KX" />నౠకీలకమైన పరివరà±à°¤à°¨ విధానంగా ఉపయోగిసà±à°¤à±à°‚ది.</translation>
<translation id="2835170189407361413">ఫారమà±â€Œà°¨à± à°¤à±à°¡à°¿à°à°¿à°µà±‡à°¯à°¿</translation>
-<translation id="2837049386027881519">కనెకà±à°·à°¨à±â€Œà°¨à± TLS లేదా SSL à°ªà±à°°à±‹à°Ÿà±‹à°•à°¾à°²à± à°¯à±à°•à±à°• పాత సంసà±à°•à°°à°£à°¨à± ఉపయోగింà°à°¿ మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿. సరà±à°µà°°à± à°à°¾à°²à°¾ పాత సాఫà±à°Ÿà±â€Œà°µà±‡à°°à±â€Œà°¨à± ఉపయోగిసà±à°¤à±‹à°‚దని మరియౠఇతర à°­à°¦à±à°°à°¤à°¾ సమసà±à°¯à°²à± ఉండవà°à±à°à°¨à°¿ సాధారణంగా దీని à°…à°°à±à°¥à°‚.</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" />లో సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ నకిలీదిగా కనిపిసà±à°¤à±‹à°‚ది.</translation>
<translation id="2889159643044928134">మళà±à°²à±€ లోడౠà°à±‡à°¯à°µà°¦à±à°¦à±</translation>
-<translation id="2896499918916051536">à°ˆ à°ªà±à°²à°—à°¿à°¨à±â€Œà°•à± మదà±à°¦à°¤à± లేదà±.</translation>
+<translation id="2900469785430194048">Google Chrome à°ˆ వెబà±â€Œà°ªà±‡à°œà±€à°¨à°¿ à°ªà±à°°à°¦à°°à±à°¶à°¿à°‚à°à°¡à°¾à°¨à°¿à°•à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°¸à±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± మెమరీ అయిపోయింది.</translation>
<translation id="2909946352844186028">నెటà±â€Œà°µà°°à±à°•à± మారà±à°ªà± à°—à±à°°à±à°¤à°¿à°‚à°à°¬à°¡à°¿à°‚ది.</translation>
-<translation id="2915500479781995473">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± à°®à±à°—ిసింది. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±. మీ à°•à°‚à°ªà±à°¯à±‚టరౠగడియారం à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="CURRENT_TIME" />à°•à°¿ సెటౠà°à±‡à°¯à°¬à°¡à°¿à°‚ది. అది సరిగà±à°—à°¾ ఉందా? లేకపోతే, మీరౠమీ సిసà±à°Ÿà°®à± గడియారానà±à°¨à°¿ సరిà°à±‡à°¸à°¿, ఆపై à°ˆ పేజీని à°°à°¿à°«à±à°°à±†à°·à± à°à±‡à°¯à°‚à°¡à°¿.</translation>
<translation id="2922350208395188000">సరà±à°µà°°à± à°¯à±à°•à±à°• à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ తనిఖీ à°à±†à°¯à±à°¯à°¬à°¡à°¦à±.</translation>
-<translation id="2941952326391522266">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ <ph name="DOMAIN2" /> à°¨à±à°‚à°¡à°¿ జారీ à°à±‡à°¯à°¬à°¡à°¿à°‚ది. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±.</translation>
<translation id="2948083400971632585">మీరౠసెటà±à°Ÿà°¿à°‚à°—à±â€Œà°² పేజీ à°¨à±à°‚à°¡à°¿ కనెకà±à°·à°¨à± కోసం కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¬à°¡à°¿à°¨ à° à°ªà±à°°à°¾à°•à±à°¸à±€à°²à°¨à± అయినా నిలిపివేయవà°à±à°à±.</translation>
<translation id="2955913368246107853">à°•à°¨à±à°—à±à°¨à± పటà±à°Ÿà±€à°¨à°¿ మూసివేయి</translation>
<translation id="2958431318199492670">నెటà±â€Œà°µà°°à±à°•à± కానà±à°«à°¿à°—రేషనౠONC à°ªà±à°°à°®à°¾à°£à°¾à°¨à°¿à°•à°¿ à°…à°¨à±à°•à±‚లంగా లేదà±. కానà±à°«à°¿à°—రేషనà±â€Œà°²à±‹à°¨à°¿ భాగాలౠదిగà±à°®à°¤à°¿ కాకపోయి ఉండకపోవà°à±à°à±.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">à°à±†à°²à±à°²à°¨à°¿ విధాన à°°à°•à°‚</translation>
<translation id="3032412215588512954">మీరౠఈ సైటà±â€Œà°¨à± మళà±à°²à±€ లోడౠà°à±‡à°¯à°¾à°²à°¨à±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
<translation id="3037605927509011580">ఆవà±, à°¸à±à°¨à°¾à°ªà±!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{సమకాలీకరింà°à°¿à°¨ పరికరాలà±à°²à±‹ కనీసం 1 అంశం}=1{1 అంశం (మరియౠసమకాలీకరింà°à°¿à°¨ పరికరాలà±à°²à±‹ మరినà±à°¨à°¿)}other{# అంశాలౠ(మరియౠసమకాలీకరింà°à°¿à°¨ పరికరాలà±à°²à±‹ మరినà±à°¨à°¿)}}</translation>
<translation id="3041612393474885105">సరà±à°Ÿà°¿à°«à°¿à°•à±†à°Ÿà± సమాà°à°¾à°°à°‚</translation>
<translation id="3063697135517575841">Chrome à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ మీ కారà±à°¡à±â€Œà°¨à± నిరà±à°§à°¾à°°à°¿à°‚à°à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది. దయà°à±‡à°¸à°¿ తరà±à°µà°¾à°¤ మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
<translation id="3093245981617870298">మీరౠఆఫà±â€Œà°²à±ˆà°¨à±â€Œà°²à±‹ ఉనà±à°¨à°¾à°°à±.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">సరికà±à°°à±à°¤à±à°¤à°¦à°¿</translation>
<translation id="3207960819495026254">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à± à°à±‡à°¯à°¬à°¡à°¿à°‚ది</translation>
-<translation id="3225919329040284222">అంతరà±à°¨à°¿à°°à±à°®à°¿à°¤ à°…à°‚à°à°¨à°¾à°²à°•à± సరిపోలని à°’à°• ధృవీకరణ పతà±à°°à°¾à°¨à±à°¨à°¿ సరà±à°µà°°à± సమరà±à°ªà°¿à°‚à°à°¿à°‚ది. మిమà±à°®à°²à±à°¨à°¿ సంరకà±à°·à°¿à°‚à°à±‡ దిశగా నిరà±à°¦à°¿à°·à±à°Ÿ, ఉనà±à°¨à°¤ à°¸à±à°§à°¾à°¯à°¿ à°­à°¦à±à°°à°¤à°¾ వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°² కోసం à°ˆ à°…à°‚à°à°¨à°¾à°²à± à°à±‡à°°à±à°à°¬à°¡à±à°¡à°¾à°¯à°¿.</translation>
<translation id="3226128629678568754">పేజీని లోడౠà°à±‡à°¯à°¡à°¾à°¨à°¿à°•à°¿ అవసరమైన డేటానౠమళà±à°²à±€ సమరà±à°ªà°¿à°‚à°à°¡à°‚ కోసం మళà±à°²à±€ లోడౠà°à±‡à°¯à°¿ బటనౠకà±à°²à°¿à°•à± à°à±‡à°¯à°‚à°¡à°¿.</translation>
<translation id="3228969707346345236">పేజీ ఇపà±à°ªà°Ÿà°¿à°•à±‡ <ph name="LANGUAGE" />లో ఉనà±à°¨à°‚à°¦à±à°¨ à°…à°¨à±à°µà°¾à°¦à°‚ విఫలమైంది.</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" /> కారà±à°¡à± CVCని నమోదౠà°à±‡à°¯à°‚à°¡à°¿</translation>
<translation id="3254409185687681395">à°ˆ పేజీని à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à± à°à±†à°¯à±à°¯à°¿</translation>
<translation id="3270847123878663523">&amp;మళà±à°²à±€ à°•à±à°°à°®à°‚ à°à±‡à°¯à°¡à°¾à°¨à±à°¨à°¿ à°°à°¦à±à°¦à± à°à±‡à°¯à°¿</translation>
<translation id="3286538390144397061">ఇపà±à°ªà±à°¡à± à°ªà±à°¨à°ƒà°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°à°‚à°¡à°¿</translation>
+<translation id="3303855915957856445">శోధన ఫలితాలౠà°à°µà±€ à°•à°¨à±à°—à±à°¨à°¬à°¡à°²à±‡à°¦à±</translation>
<translation id="3305707030755673451"><ph name="TIME" />à°¨ మీ సమకాలీకరణ రహసà±à°¯ పదబంధంతో మీ డేటా à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°à°¬à°¡à°¿à°‚ది. సమకాలీకరణనౠపà±à°°à°¾à°°à°‚à°­à°¿à°‚à°à°¡à°¾à°¨à°¿à°•à°¿ దీనà±à°¨à°¿ నమోదౠà°à±‡à°¯à°‚à°¡à°¿.</translation>
<translation id="333371639341676808">అదనపౠడైలాగà±â€Œà°²à°¨à± సృషà±à°Ÿà°¿à°‚à°à°•à±à°‚à°¡à°¾ à°ˆ పేజీని à°…à°¡à±à°¡à±à°•à±‹</translation>
+<translation id="3338095232262050444">à°¸à±à°°à°•à±à°·à°¿à°¤à°‚</translation>
<translation id="3340978935015468852">సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±</translation>
<translation id="3345135638360864351">à°ˆ సైటà±â€Œà°¨à°¿ à°ªà±à°°à°¾à°ªà±à°¯à°¤ à°à±‡à°¯à°¡à°¾à°¨à°¿à°•à°¿ మీరౠà°à±‡à°¸à°¿à°¨ à°…à°­à±à°¯à°°à±à°¥à°¨ <ph name="NAME" />à°•à°¿ పంపబడలేదà±. దయà°à±‡à°¸à°¿ మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
<translation id="3355823806454867987">à°ªà±à°°à°¾à°•à±à°¸à±€ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± మారà±à°à±...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">విరామానà±à°¨à°¿ à°ªà±à°‚దండి:</translation>
<translation id="3462200631372590220">à°…à°§à±à°¨à°¾à°¤à°¨à°‚ దాà°à±</translation>
<translation id="3479539252931486093">à°à°¹à°¿à°‚à°à°¨à°¿ విధంగా ఇది సంభవింà°à°¿à°‚దా? <ph name="BEGIN_LINK" />మాకౠతెలియజేయండి<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">ఇపà±à°ªà±à°¡à± కాదà±</translation>
<translation id="348000606199325318">à°•à±à°°à°¾à°·à± ID <ph name="CRASH_LOCAL_ID" /> (సరà±à°µà°°à± ID: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">మేమౠపà±à°°à°¸à±à°¤à±à°¤à°‚ మీ తలà±à°²à°¿/తండà±à°°à°¿à°¨à°¿ సంపà±à°°à°¦à°¿à°‚à°à°²à±‡à°•à°ªà±‹à°¯à°¾à°®à±. దయà°à±‡à°¸à°¿ మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
<translation id="3527085408025491307">ఫోలà±à°¡à°°à±</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">దీని కోసం పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± ఉపయోగింà°à°‚à°¡à°¿:</translation>
<translation id="3549644494707163724">మీ à°¸à±à°µà°‚à°¤ సమకాలీకరణ రహసà±à°¯ పదబంధంతో సమకాలీకరింà°à°¬à°¡à°¿à°¨ డేటా à°®à±à°¤à±à°¤à°¾à°¨à±à°¨à°¿ à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°à°‚à°¡à°¿</translation>
<translation id="3549761410225185768">మరో <ph name="NUM_TABS_MORE" />...</translation>
+<translation id="3555561725129903880">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ <ph name="DOMAIN2" /> à°¨à±à°‚à°¡à°¿ అందింà°à°¬à°¡à°¿ ఉండవà°à±à°à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగిసà±à°¤à±à°‚à°¡à°Ÿà°‚ వలన ఇలా జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">మీ కనెకà±à°·à°¨à± à°ªà±à°°à±ˆà°µà±‡à°Ÿà± కాదà±</translation>
<translation id="3583757800736429874">&amp;తరలింà°à°¡à°¾à°¨à±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ à°à±‡à°¯à°¿</translation>
<translation id="3586931643579894722">వివరాలనౠదాà°à°¿à°ªà±†à°Ÿà±à°Ÿà±</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">విలà±à°µà°¨à± à°à±‚పండి</translation>
<translation id="3630155396527302611">ఇపà±à°ªà°Ÿà°¿à°•à±‡ ఇది నెటà±â€Œà°µà°°à±à°•à±â€Œà°¨à± à°ªà±à°°à°¾à°ªà±à°¯à°¤ à°à±‡à°¯à°¡à°¾à°¨à°¿à°•à°¿ à°…à°¨à±à°®à°¤à°¿à°‚à°à°¬à°¡à°¿à°¨ à°ªà±à°°à±‹à°—à±à°°à°¾à°®à± వలె జాబితా à°à±‡à°¯à°¬à°¡à°¿ ఉంటే,
దీనà±à°¨à°¿ జాబితా à°¨à±à°‚à°¡à°¿ తీసివేసి, ఆపై మళà±à°²à±€ జోడింà°à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
+<translation id="3638794133396384728">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± à°®à±à°—ిసింది. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన ఇలా జరిగి ఉండవà°à±à°à±. మీ à°•à°‚à°ªà±à°¯à±‚టరౠగడియారం à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="CURRENT_TIME" />à°•à°¿ సెటౠà°à±‡à°¯à°¬à°¡à°¿à°‚ది. అది సరిగà±à°—à°¾ ఉందా? లేకపోతే, మీరౠమీ సిసà±à°Ÿà°®à± గడియారానà±à°¨à°¿ సరిà°à±‡à°¸à°¿, ఆపై à°ˆ పేజీని à°°à°¿à°«à±à°°à±†à°·à± à°à±‡à°¯à°‚à°¡à°¿. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">à°ˆ à°ªà±à°°à°¯à±‹à°—ాతà±à°®à°• లకà±à°·à°£à°¾à°²à± ఠసమయంలోనైనా మారవà°à±à°à±, విభజింà°à°¬à°¡à°µà°à±à°à± లేదా అదృశà±à°¯à°‚ కావà°à±à°à±. మీరౠఈ à°ªà±à°°à°¯à±‹à°—ాలలో ఒకదానà±à°¨à°¿ ఆనà±â€Œ à°à±‡à°¸à±à°¤à±‡ జరిగే దానికి మేమౠఖà°à±à°à°¿à°¤à°‚à°—à°¾ హామీలౠఇవà±à°µà°²à±‡à°®à± మరియౠమీ à°¬à±à°°à±Œà°œà°°à± ఆకసà±à°®à°¿à°•à°‚à°—à°¾ మూసà±à°•à±à°¨à°¿à°ªà±‹à°µà°à±à°à±. హాసà±à°¯à°¾à°¨à±à°¨à°¿ à°ªà±à°°à°•à±à°•à°¨ పెడితే, మీ à°¬à±à°°à±Œà°œà°°à± మీ à°®à±à°¤à±à°¤à°‚ డేటా à°¤à±à°²à°—à°¿à°‚à°à°µà°à±à°à± లేదా à°…à°¨à±à°•à±‹à°¨à°¿ విధంగా మీ à°­à°¦à±à°°à°¤à°¾ మరియౠగోపà±à°¯à°¤ రాజీపడవà°à±à°à±. మీరౠపà±à°°à°¾à°°à°‚à°­à°¿à°‚à°à°¿à°¨ à°à°µà±‡à°¨à°¿ à°ªà±à°°à°¯à±‹à°—ాలౠఈ à°¬à±à°°à±Œà°œà°°à± à°¯à±à°•à±à°• వినియోగదారà±à°²à°‚దరికి à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°à°¬à°¡à°¤à°¾à°¯à°¿. దయà°à±‡à°¸à°¿ జాగà±à°°à°¤à±à°¤à°—à°¾ à°•à±à°¨à°¸à°¾à°—à°‚à°¡à°¿.</translation>
<translation id="3650584904733503804">à°ªà±à°°à°¾à°®à°¾à°£à±€à°•à°°à°£ విజయవంతం అయింది</translation>
<translation id="3655670868607891010">మీరౠదీనà±à°¨à°¿ తరà°à±à°—à°¾ à°à±‚à°¸à±à°¤à±à°‚టే, à°ˆ <ph name="HELP_LINK" />ని à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
<translation id="3658742229777143148">à°ªà±à°¨à°°à±à°µà°¿à°®à°°à±à°¶</translation>
+<translation id="3678029195006412963">à°…à°­à±à°¯à°°à±à°¥à°¨à°•à± సంతకం అందింà°à°¡à°‚ సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±</translation>
<translation id="3681007416295224113">సరà±à°Ÿà°¿à°«à°¿à°•à±†à°Ÿà± సమాà°à°¾à°°à°‚</translation>
<translation id="3693415264595406141">పాసà±â€Œà°µà°°à±à°¡à±:</translation>
+<translation id="3696411085566228381">à°à°¦à±€ కాదà±</translation>
<translation id="3700528541715530410">à°…à°¯à±à°¯à±‹, మీకౠఈ పేజీని à°ªà±à°°à°¾à°ªà±à°¯à°¤ à°à±‡à°¯à°¡à°¾à°¨à°¿à°•à°¿ à°…à°¨à±à°®à°¤à°¿ లేనటà±à°²à± కనిపిసà±à°¤à±‹à°‚ది.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">లోడౠఅవà±à°¤à±‹à°‚ది...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">à°®à±à°¬à±ˆà°²à± డేటా లేదా Wi-Fiని ఆనౠà°à±‡à°¯à°¡à°‚</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />à°ªà±à°°à°¾à°•à±à°¸à±€, ఫైరà±â€Œà°µà°¾à°²à± మరియౠDNS కానà±à°«à°¿à°—రేషనà±â€Œà°¨à± తనిఖీ à°à±‡à°¯à°¡à°‚<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">మీరౠకాపీ à°à±‡à°¸à°¿à°¨ లింకà±</translation>
-<translation id="3744899669254331632">మీరౠసందరà±à°¶à°¿à°‚à°à°¾à°²à°¨à±à°•à±à°‚à°Ÿà±à°¨à±à°¨ <ph name="SITE" /> వెబà±â€Œà°¸à±ˆà°Ÿà± Chromium à°ªà±à°°à°¾à°¸à±†à°¸à± à°à±‡à°¯à°²à±‡à°¨à°¿ à°à°¿à°‚దరవందరైన ఆధారాలనౠపంపినందà±à°¨ à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ దానà±à°¨à°¿ సందరà±à°¶à°¿à°‚à°à°²à±‡à°°à±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚à°—à°¾ మాతà±à°°à°®à±‡ ఉంటాయి, కాబటà±à°Ÿà°¿ à°ˆ పేజీ బహà±à°¶à°¾ తరà±à°µà°¾à°¤ పని à°à±‡à°¯à°µà°à±à°à±.</translation>
<translation id="375403751935624634">సరà±à°µà°°à± లోపం వలà±à°² à°…à°¨à±à°µà°¾à°¦à°‚ విఫలమైంది.</translation>
<translation id="3759461132968374835">మీకౠఇటీవల నివేదింà°à°¿à°¨ à°•à±à°°à°¾à°·à±â€Œà°²à± లేవà±. à°•à±à°°à°¾à°·à±â€Œ నివేదన నిలిపివేసినపà±à°¡à± à°à°°à±à°ªà°¡à±‡ à°•à±à°°à°¾à°·à±â€Œà°²à± ఇకà±à°•à°¡ కనిపింà°à°µà±.</translation>
<translation id="3788090790273268753">à°ˆ సైటౠపà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à°¿à°•à°¿ 2016లో à°—à°¡à±à°µà± à°®à±à°—à±à°¸à±à°¤à±à°‚ది, à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à±à°²à±à°¸à±à°²à±‹ SHA-1ని ఉపయోగింà°à°¿ సంతకం à°à±‡à°¸à°¿à°¨ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ ఉంది.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">వైరà±à°§à±à°¯à°®à±ˆà°¨ పరికరం à°à°¡à±†à°‚టిఫైయరà±</translation>
<translation id="3885155851504623709">పారిషà±</translation>
<translation id="3901925938762663762">కారà±à°¡à± à°—à°¡à±à°µà± సమయం à°®à±à°—ిసింది</translation>
+<translation id="3910267023907260648">మీరౠ<ph name="DOMAIN" />à°•à°¿ కనెకà±à°Ÿà± à°à±‡à°¯à°¡à°¾à°¨à°¿à°•à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¾à°°à±, కానీ సరà±à°µà°°à± బలహీనమైన సంతకం à°…à°²à±à°—ారిథమà±â€Œà°¨à± ఉపయోగింà°à°¿ సంతకం à°à±‡à°¸à°¿à°¨ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ అందింà°à°¿à°‚ది. దీని à°ªà±à°°à°•à°¾à°°à°‚, సరà±à°µà°°à± అందింà°à°¿à°¨ à°­à°¦à±à°°à°¤à°¾ ఆధారాలౠనకిలీవి కావà°à±à°à± మరియౠసరà±à°µà°°à± మీరౠà°à°¹à°¿à°‚à°à°¿à°¨ సరà±à°µà°°à± కాకపోవà°à±à°à± (మీరౠదాడి à°à±‡à°¸à±‡ వారితో à°•à°®à±à°¯à±‚నికేటౠà°à±‡à°¸à±à°¤à±à°‚à°¡à°µà°à±à°à±). <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ రేపటిది కావà°à±à°à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¸à°¿à°¨à°‚à°¦à±à°¨ లేదా దాడిà°à±‡à°¸à±‡à°µà°¾à°°à± మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగింà°à°¿à°¨à°‚à°¦à±à°¨ ఇలా జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.}other{à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ భవిషà±à°¯à°¤à±à°¤à±à°²à±‹ # రోజà±à°² తదà±à°ªà°°à°¿à°¦à°¿ కావà°à±à°à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¸à°¿à°¨à°‚à°¦à±à°¨ లేదా దాడిà°à±‡à°¸à±‡à°µà°¾à°°à± మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగింà°à°¿à°¨à°‚à°¦à±à°¨ ఇలా జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF పతà±à°°à°¾à°¨à±à°¨à°¿ లోడౠà°à±†à°¯à±à°¯à°¡à°¾à°¨à°¿à°•à°¿ విఫలమైంది</translation>
<translation id="3963721102035795474">పాఠకà±à°¨à°¿ మోడà±</translation>
+<translation id="397105322502079400">గణిసà±à°¤à±‹à°‚ది...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> à°¬à±à°²à°¾à°•à± à°à±‡à°¯à°¬à°¡à°¿à°‚ది</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 వెబౠపేజీ సమీపంలో ఉంది}other{# వెబౠపేజీలౠసమీపంలో ఉనà±à°¨à°¾à°¯à°¿}}</translation>
<translation id="4021036232240155012">DNS అనేది వెబà±â€Œà°¸à±ˆà°Ÿà± పేరà±à°¨à± దాని ఇంటరà±à°¨à±†à°Ÿà± à°à°¿à°°à±à°¨à°¾à°®à°¾à°•à°¿ à°…à°¨à±à°µà°¦à°¿à°‚à°à±‡ నెటà±â€Œà°µà°°à±à°•à± సేవ.</translation>
<translation id="4030383055268325496">&amp;జోడింà°à°¡à°¾à°¨à±à°¨à°¿ à°°à°¦à±à°¦à± à°à±‡à°¯à°¿</translation>
-<translation id="4032534284272647190"><ph name="URL" />à°•à± à°ªà±à°°à°¾à°ªà±à°¯à°¤ తిరసà±à°•à°°à°¿à°‚à°à°¬à°¡à°¿à°‚ది.</translation>
<translation id="404928562651467259">హెà°à±à°à°°à°¿à°•</translation>
<translation id="4058922952496707368">à°•à±€ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">à°•à±à°²à°¯à°¿à°‚టౠమరియౠసరà±à°µà°°à± ఒకే SSL à°ªà±à°°à±‹à°Ÿà±‹à°•à°¾à°²à± సంసà±à°•à°°à°£ లేదా సైఫరౠసూటà±â€Œà°•à± మదà±à°¦à°¤à°¿à°µà±à°µà°µà±.</translation>
<translation id="4079302484614802869">à°ªà±à°°à°¾à°•à±à°¸à±€ కానà±à°«à°¿à°—రేషనౠసà±à°¥à°¿à°°à°®à±ˆà°¨ à°ªà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±â€Œà°²à°¨à± కాకà±à°‚à°¡à°¾, à°’à°• .pac à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± URLనౠఉపయోగింà°à°¡à°¾à°¨à°¿à°•à°¿ సెటౠà°à±‡à°¯à°¬à°¡à°¿à°‚ది.</translation>
<translation id="4103249731201008433">పరికరం à°•à±à°°à°® సంఖà±à°¯ à°à±†à°²à±à°²à°¦à±</translation>
<translation id="4103763322291513355">నిరోధిత జాబితాలో ఉనà±à°¨ URLà°² జాబితానౠమరియౠమీ సిసà±à°Ÿà°®à± నిరà±à°µà°¾à°¹à°•à±à°¨à°¿ à°¦à±à°µà°¾à°°à°¾ అమలౠà°à±‡à°¯à°¬à°¡à°¿à°¨ ఇతర విధానాలనౠà°à±‚డటానికి &lt;strong&gt;chrome://policy&lt;/strong&gt;ని సందరà±à°¶à°¿à°‚à°à°‚à°¡à°¿.</translation>
+<translation id="4110615724604346410">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ లోపాలనౠకలిగి ఉంది. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన ఇలా జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">విధానం పరిధికి మదà±à°¦à°¤à± లేదà±.</translation>
+<translation id="4118212371799607889">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ Chromium విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¦à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన ఇలా జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{మరో 1}other{మరో #}}</translation>
<translation id="4130226655945681476">నెటà±â€Œà°µà°°à±à°•à± కేబà±â€Œà°²à±â€Œà°²à±, మోడమౠమరియౠరూటరà±â€Œà°¨à± తనిఖీ à°à±‡à°¯à°¡à°‚</translation>
<translation id="4148925816941278100">అమెరికనౠà°à°•à±à°¸à±â€Œà°ªà±à°°à±†à°¸à±</translation>
<translation id="4169947484918424451">Chromium à°ˆ కారà±à°¡à±â€Œà°¨à± సేవౠà°à±‡à°¯à°¾à°²à°¨à°¿ మీరౠకోరà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">ఆపివేయబడింది</translation>
<translation id="4196861286325780578">&amp;తరలింà°à°¡à°¾à°¨à±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ à°à±‡à°¯à°¿</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ఫైరà±â€Œà°µà°¾à°²à± మరియౠయాంటీవైరసౠకానà±à°«à°¿à°—రేషనà±â€Œà°²à°¨à± తనిఖీ à°à±‡à°¯à°¡à°‚<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{à°à°¦à±€ లేదà±}=1{1 à°…à°¨à±à°µà°°à±à°¤à°¨à°‚ ($1)}=2{2 à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°²à± ($1, $2)}other{# à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°²à± ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">à°•à±à°°à°¾à°·à±â€Œà°²à±</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />నెటà±â€Œà°µà°°à±à°•à± సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± అమలౠà°à±‡à°¯à°¡à°‚ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">కాదà±</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(వినియోగదారౠపేరౠలేదà±)</translation>
<translation id="4300246636397505754">తలà±à°²à°¿/తండà±à°°à°¿ సూà°à°¨à°²à±</translation>
<translation id="4304224509867189079">లాగినà±</translation>
+<translation id="432290197980158659">సరà±à°µà°°à± అంతరà±à°¨à°¿à°°à±à°®à°¿à°¤ à°…à°‚à°à°¨à°¾à°²à°•à± సరిపోలని à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ అందింà°à°¿à°‚ది. మిమà±à°®à°²à±à°¨à°¿ సంరకà±à°·à°¿à°‚à°à±‡ దిశగా నిరà±à°§à°¿à°·à±à°Ÿ, ఉనà±à°¨à°¤ à°¸à±à°¥à°¾à°¯à°¿ à°­à°¦à±à°°à°¤à°¾ వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°² కోసం à°ˆ à°…à°‚à°à°¨à°¾à°²à± à°à±‡à°°à±à°à°¬à°¡à±à°¡à°¾à°¯à°¿. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">కథనానà±à°¨à°¿ à°•à°¨à±à°—à±à°¨à°¡à°‚ విఫలమైంది</translation>
+<translation id="4331708818696583467">à°¸à±à°°à°•à±à°·à°¿à°¤à°‚ కాదà±</translation>
<translation id="4372948949327679948">ఆశిసà±à°¤à±à°¨à±à°¨ <ph name="VALUE_TYPE" /> విలà±à°µ.</translation>
-<translation id="4377125064752653719"><ph name="DOMAIN" />నౠà°à±‡à°°à±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ మీరౠపà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¾à°°à±, కానీ సరà±à°µà°°à± అందింà°à°¿à°¨ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ దానà±à°¨à°¿ జారీ à°à±‡à°¸à°¿à°¨à°µà°¾à°°à± à°°à°¦à±à°¦à± à°à±‡à°¸à°¾à°°à±. సరà±à°µà°°à± అందింà°à°¿à°¨ à°­à°¦à±à°°à°¤ ఆధారాలౠఖà°à±à°à°¿à°¤à°‚à°—à°¾ విశà±à°µà°¸à°¿à°‚à°à°¬à°¡à°²à±‡à°¦à°¨à°¿ దీని à°…à°°à±à°¥à°‚. మీరౠదాడి à°à±‡à°¸à±‡ వారితో à°•à°®à±à°¯à±‚నికేటౠà°à±‡à°¸à±à°¤à±‚ ఉండవà°à±à°à±.</translation>
<translation id="4381091992796011497">యూజరౠపేరà±:</translation>
<translation id="4394049700291259645">ఆపివెయà±à°¯à°¿</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> à°¨à±à°‚à°¡à°¿ <ph name="END_DATE" /> వరకà±</translation>
<translation id="4406896451731180161">శోధన ఫలితాలà±</translation>
-<translation id="4424024547088906515">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ Chrome విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¦à±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> మీ లాగినౠపà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ ఆమోదింà°à°²à±‡à°¦à± లేదా à°à°¦à±€ అందింà°à°¿ ఉండకపోవà°à±à°à±.</translation>
<translation id="443673843213245140">à°ªà±à°°à°¾à°•à±à°¸à±€à°¨à°¿ ఉపయోగింà°à°¡à°‚ ఆపివేయబడింది కానీ à°¸à±à°ªà°·à±à°Ÿà°®à±ˆà°¨ à°ªà±à°°à°¾à°•à±à°¸à±€ కానà±à°«à°¿à°—రేషనౠపేరà±à°•à±à°¨à°¬à°¡à°¿à°‚ది.</translation>
<translation id="4458874409874303848">à°¸à±à°°à°•à±à°·à°¿à°¤ సైటà±â€Œà°²à±</translation>
<translation id="4461847750548395463">Google à°¸à±à°°à°•à±à°·à°¿à°¤ సైటà±â€Œà°²à°¨à± à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°à°¿à°¨à°‚à°¦à±à°¨ మీకౠఈ సందేశం కనిపిసà±à°¤à±‹à°‚ది.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">వివరాలà±</translation>
<translation id="4558551763791394412">మీ à°ªà±à°¡à°¿à°—à°¿à°‚à°ªà±à°²à°¨à± నిలిపివేయడం à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
<translation id="4587425331216688090">Chrome à°¨à±à°‚à°¡à°¿ à°à°¿à°°à±à°¨à°¾à°®à°¾à°¨à± తీసివేయాలా?</translation>
+<translation id="4589078953350245614">మీరౠ<ph name="DOMAIN" />à°•à°¿ కనెకà±à°Ÿà± కావడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¾à°°à±, కానీ సరà±à°µà°°à± à°’à°• à°à±†à°²à±à°²à±à°¬à°¾à°Ÿà± కాని à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ అందింà°à°¿à°‚ది. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459"><ph name="DOMAIN" />à°•à°¿ à°—à°² మీ కనెకà±à°·à°¨à± ఆధà±à°¨à°¿à°• సైఫరౠసూటౠఉపయోగింà°à°¿ à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°à°¬à°¡à°¿à°‚ది.</translation>
<translation id="4594403342090139922">&amp;à°¤à±à°²à°—à°¿à°‚à°à°¡à°¾à°¨à±à°¨à°¿ à°°à°¦à±à°¦à± à°à±‡à°¯à°¿</translation>
+<translation id="4627442949885028695">మరో పరికరం à°¨à±à°‚à°¡à°¿ à°•à±à°¨à°¸à°¾à°—à°¿à°‚à°à°‚à°¡à°¿</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">మీరౠపà±à°¡à°¿à°—ింపౠపేజీని వీకà±à°·à°¿à°¸à±à°¤à±à°¨à±à°¨à°¾à°°à±.</translation>
-<translation id="467662567472608290">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚లో లోపాలౠఉనà±à°¨à°¾à°¯à°¿. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> à°¬à±à°²à°¾à°•à± à°à±‡à°¯à°¬à°¡à°¿à°‚ది</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం à°à°°à±à°ªà°¡à°¿à°‚ది</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows నెటà±â€Œà°µà°°à±à°•à± సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± అమలౠà°à±‡à°¯à°¡à°‚<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">à°ªà±à°²à°¾à°Ÿà±â€Œà°«à°¾à°°à°®à±</translation>
<translation id="4744603770635761495">అమలౠà°à±‡à°¯à°—à°² మారà±à°—à°‚</translation>
<translation id="4756388243121344051">&amp;à°à°°à°¿à°¤à±à°°</translation>
+<translation id="4759238208242260848">డౌనà±â€Œà°²à±‹à°¡à±â€Œà°²à±</translation>
<translation id="4764776831041365478"><ph name="URL" /> వదà±à°¦ వెబà±â€Œà°ªà±‡à°œà±€ తాతà±à°•à°¾à°²à°¿à°•à°‚à°—à°¾ తెరà±à°à±à°•à±‹à°µà°Ÿà°‚ లేదౠలేదా అది à°•à±à°°à±à°¤à±à°¤ వెబౠà°à°¿à°°à±à°¨à°¾à°®à°¾à°•à± శాశà±à°µà°¤à°‚à°—à°¾ తరలింà°à°¬à°¡à°¿ ఉండవà°à±à°à±.</translation>
<translation id="4771973620359291008">తెలియని లోపం à°’à°•à°Ÿà°¿ à°à°°à±à°ªà°¡à°¿à°‚ది.</translation>
<translation id="4782449893814226250">మీరౠఈ పేజీని సందరà±à°¶à°¿à°‚à°à°¡à°¾à°¨à°¿à°•à°¿ à°…à°¨à±à°®à°¤à°¿à°‚à°à°®à°¨à°¿ కోరà±à°¤à±‚ మీ తలà±à°²à°¿à°¦à°‚à°¡à±à°°à±à°²à°•à± à°…à°­à±à°¯à°°à±à°¥à°¨ పంపారà±.</translation>
<translation id="4800132727771399293">మీ à°—à°¡à±à°µà± à°®à±à°—ింపౠతేదీ మరియౠCVCని తనిఖీ à°à±‡à°¸à°¿, మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿</translation>
-<translation id="4807049035289105102">వెబà±â€Œà°¸à±ˆà°Ÿà± Google Chrome à°ªà±à°°à°¾à°¸à±†à°¸à± à°à±‡à°¯à°²à±‡à°¨à°¿, గజిబిజిగా ఉండే ఆధారాలనౠపంపినందà±à°¨ మీరౠపà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="SITE" />ని సందరà±à°¶à°¿à°‚à°à°²à±‡à°°à±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, à°•à°¨à±à°• à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని à°à±‡à°¸à±‡ అవకాశం ఉంది.</translation>
<translation id="4813512666221746211">నెటà±â€Œà°µà°°à±à°•à± లోపం</translation>
<translation id="4816492930507672669">పేజీకి తగినటà±à°²à± అమరà±à°à±</translation>
<translation id="4850886885716139402">వీకà±à°·à°£</translation>
<translation id="4880827082731008257">శోధన à°à°°à°¿à°¤à±à°°</translation>
+<translation id="4884656795097055129">సమయం ఆసనà±à°¨à°®à±ˆà°¨à°ªà±à°ªà±à°¡à± మరినà±à°¨à°¿ కథనాలౠకనిపిసà±à°¤à°¾à°¯à°¿.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{మరియౠమరో 1 వెబౠపేజీ}other{మరియౠమరో # వెబౠపేజీలà±}}</translation>
<translation id="4923417429809017348">à°ˆ పేజీ తెలియని భాష à°¨à±à°‚à°¡à°¿ <ph name="LANGUAGE_LANGUAGE" />à°•à± à°…à°¨à±à°µà°¦à°¿à°‚à°à°¬à°¡à°¿à°‚ది</translation>
<translation id="4926049483395192435">à°–à°à±à°à°¿à°¤à°‚à°—à°¾ పేరà±à°•à±à°¨à°¾à°²à°¿.</translation>
<translation id="4930497775425430760">మీరౠమà±à°¦à°Ÿà°¿à°¸à°¾à°°à°¿ à°•à±à°¤à±à°¤ సైటà±â€Œà°²à°¨à± సందరà±à°¶à°¿à°‚à°à°¿à°¨à°ªà±à°ªà±à°¡à± వాటిని మీ తలà±à°²à°¿/తండà±à°°à°¿ ఆమోదింà°à°¾à°²à±à°¸à°¿à°¨ ఆవశà±à°¯à°•à°‚ ఉనà±à°¨à°‚à°¦à±à°¨ మీకౠఈ సందేశం కనిపిసà±à°¤à±‹à°‚ది.</translation>
<translation id="495170559598752135">à°à°°à±à°¯à°²à±</translation>
<translation id="4958444002117714549">జాబితానౠవిసà±à°¤à°°à°¿à°‚à°à±</translation>
+<translation id="4962322354953122629">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ Chrome విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¦à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన ఇలా జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911"><ph name="ORIGINAL_LANGUAGE" /> à°¨à±à°‚à°¡à°¿ <ph name="TARGET_LANGUAGE" />à°•à°¿ à°…à°¨à±à°µà°¦à°¿à°‚à°à°¾à°²à°¾?</translation>
+<translation id="4989809363548539747">à°ˆ à°ªà±à°²à°—à°¿à°¨à±â€Œà°•à± మదà±à°¦à°¤à± లేదà±</translation>
<translation id="5002932099480077015">à°ªà±à°°à°¾à°°à°‚à°­à°¿à°¸à±à°¤à±‡, వేగవంతమైన ఫారమౠపూరింపౠకోసం Chrome à°ˆ పరికరంలో మీ కారà±à°¡à± కాపీని నిలà±à°µ à°à±‡à°¸à±à°¤à±à°‚ది.</translation>
<translation id="5019198164206649151">à°¬à±à°¯à°¾à°•à°¿à°‚గౠనిలà±à°µ à°à±†à°²à±à°²à°¨à°¿ à°¸à±à°¥à°¿à°¤à°¿à°²à±‹ ఉంది</translation>
<translation id="5023310440958281426">మీ నిరà±à°µà°¾à°¹à°•à±à°¨à°¿ విధానాలనౠà°à±‚à°¡à°‚à°¡à°¿</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Google à°…à°¨à±à°µà°¾à°¦à°‚ à°—à±à°°à°¿à°‚à°à°¿</translation>
<translation id="5040262127954254034">గోపà±à°¯à°¤</translation>
<translation id="5045550434625856497">సరికాని పాసà±â€Œà°µà°°à±à°¡à±</translation>
+<translation id="5056549851600133418">మీ కోసం కథనాలà±</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />à°ªà±à°°à°¾à°•à±à°¸à±€ à°à°¿à°°à±à°¨à°¾à°®à°¾à°¨à± తనిఖీ à°à±‡à°¯à°¡à°‚<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°à±†à°²à±à°²à°¦à±.</translation>
<translation id="5089810972385038852">రాషà±à°Ÿà±à°°à°‚</translation>
-<translation id="5094747076828555589">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ Chromium విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¦à±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±.</translation>
<translation id="5095208057601539847">à°ªà±à°°à°¾à°µà°¿à°¨à±à°¸à±</translation>
<translation id="5115563688576182185">(64-బిటà±)</translation>
-<translation id="5122371513570456792">'<ph name="SEARCH_STRING" />' కోసం <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> à°•à°¨à±à°—à±à°¨à°¬à°¡à±à°¡à°¾à°¯à°¿.</translation>
<translation id="5141240743006678641">మీ Google ఆధారాలతో సమకాలీకరింà°à°¬à°¡à°¿à°¨ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°à°‚à°¡à°¿</translation>
<translation id="5145883236150621069">విధాన à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దనలో లోపం కోడౠఉంది</translation>
<translation id="5171045022955879922">URLనౠశోధింà°à°‚à°¡à°¿ లేదా టైపౠà°à±‡à°¯à°‚à°¡à°¿</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°² బారà±</translation>
<translation id="5199729219167945352">à°ªà±à°°à°¯à±‹à°—ాలà±</translation>
<translation id="5251803541071282808">à°•à±à°²à±Œà°¡à±</translation>
+<translation id="5277279256032773186">కారà±à°¯à°¾à°²à°¯à°‚లో Chrome ఉపయోగిసà±à°¤à±à°¨à±à°¨à°¾à°°à°¾? à°µà±à°¯à°¾à°ªà°¾à°° సంసà±à°¥à°²à± తమ ఉదà±à°¯à±‹à°—à±à°² కోసం Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± నిరà±à°µà°¹à°¿à°‚à°à°—లవà±. మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="5299298092464848405">విధానానà±à°¨à°¿ à°…à°¨à±à°µà°¯à°¿à°‚à°à°¡à°‚లో లోపం</translation>
<translation id="5300589172476337783">à°à±‚పింà°à±</translation>
<translation id="5308689395849655368">à°•à±à°°à°¾à°·à± నివేదిక నిలిపివెయà±à°¯à°¬à°¡à°¿à°‚ది.</translation>
<translation id="5317780077021120954">సేవౠà°à±‡à°¯à°¿</translation>
<translation id="5327248766486351172">పేరà±</translation>
+<translation id="5359637492792381994">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; à°ˆ సమయంలో దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°à±†à°²à±à°²à°¦à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన ఇలా జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">విధాన సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± నిలà±à°µ à°à±‡à°¯à°¡à°‚లో విఫలమైంది</translation>
-<translation id="540969355065856584">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ à°à±†à°²à±à°²à°¦à±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడి à°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±.</translation>
<translation id="5421136146218899937">à°¬à±à°°à±Œà°œà°¿à°‚గౠడేటానౠకà±à°²à°¿à°¯à°°à± à°à±†à°¯à±à°¯à°¿...</translation>
<translation id="5430298929874300616">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°¨à°¿ తీసివేయి</translation>
<translation id="5431657950005405462">మీ ఫైలౠకనà±à°—à±à°¨à°¬à°¡à°²à±‡à°¦à±</translation>
<translation id="5435775191620395718">à°ˆ పరికరం à°¨à±à°‚à°¡à°¿ à°à°°à°¿à°¤à±à°°à°¨à± à°à±‚à°ªà±à°¤à±‹à°‚ది. <ph name="BEGIN_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">మీ సమకాలీకరింà°à°¿à°¨ డేటా à°’à°• à°…à°¨à±à°•à±‚à°² రహసà±à°¯ పదబంధంతో సంరకà±à°·à°¿à°‚à°à°¬à°¡à°¿à°¨à°‚à°¦à±à°¨ à°µà±à°¯à°•à±à°¤à°¿à°—తీకృత కంటెంటౠసూà°à°¨à°²à± à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ నిలిపివేయబడà±à°¡à°¾à°¯à°¿.</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />"లో à°¸à±à°•à±€à°®à°¾ à°ªà±à°°à°¾à°®à°¾à°£à±€à°•à°°à°£ లోపం: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">à°ˆ <ph name="HOST_NAME" /> పేజీ à°•à°¨à±à°—à±à°¨à°¬à°¡à°²à±‡à°¦à±</translation>
<translation id="5455374756549232013">à°à±†à°²à±à°²à°¨à°¿ విధాన సమయమà±à°¦à±à°°</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">మీరౠఈ సైటà±â€Œ à°¨à±à°‚à°¡à°¿ నిషà±à°•à±à°°à°®à°¿à°‚à°à°¾à°²à°¨à±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
<translation id="5629630648637658800">విధాన సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± లోడౠà°à±‡à°¯à°¡à°‚లో విఫలమైంది</translation>
<translation id="5631439013527180824">à°à±†à°²à±à°²à°¨à°¿ పరికర నిరà±à°µà°¹à°£ టోకెనà±</translation>
-<translation id="5650551054760837876">శోధన ఫలితాలౠà°à°µà±€ à°¦à±à°°à°•à°²à±‡à°¦à±.</translation>
<translation id="5677928146339483299">à°¬à±à°²à°¾à°•à± à°à±†à°¯à±à°¯à°¬à°¡à°¿à°‚ది</translation>
<translation id="5710435578057952990">à°ˆ వెబà±â€â€Œà°¸à±ˆà°Ÿà± à°¯à±à°•à±à°• à°—à±à°°à±à°¤à°¿à°‚పౠనిరà±à°¥à°¾à°°à°¿à°‚à°à°¬à°¡à°²à±‡à°¦à±.</translation>
<translation id="5720705177508910913">à°ªà±à°°à°¸à±à°¤à±à°¤ వినియోగదారà±</translation>
+<translation id="572328651809341494">ఇటీవలి à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à±</translation>
<translation id="5784606427469807560">మీ కారà±à°¡à±â€Œà°¨à± నిరà±à°§à°¾à°°à°¿à°‚à°à°¡à°‚లో సమసà±à°¯ à°à°°à±à°ªà°¡à°¿à°‚ది. మీ ఇంటరà±à°¨à±†à°Ÿà± కనెకà±à°·à°¨à±â€Œà°¨à°¿ తనిఖీ à°à±‡à°¸à°¿, ఆపై మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
<translation id="5785756445106461925">అలాగే, à°ˆ పేజీలో à°¸à±à°°à°•à±à°·à°¿à°¤à°‚ కాని ఇతర వనరà±à°²à± ఉనà±à°¨à°¾à°¯à°¿. à°ˆ వనరà±à°²à°¨à± బదిలీ à°à±‡à°¸à±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± ఇతరà±à°²à± à°à±‚డగలరౠమరియౠదాడికి పాలà±à°ªà°¡à±‡à°µà°¾à°°à± పేజీ రూపానà±à°¨à°¿ మారà±à°à±‡à°²à°¾ వీటిని సవరింà°à°—లరà±.</translation>
+<translation id="5786044859038896871">మీరౠమీ కారà±à°¡à± సమాà°à°¾à°°à°‚ పూరింà°à°¾à°²à°¨à±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
+<translation id="5803412860119678065">మీరౠమీ <ph name="CARD_DETAIL" /> కారà±à°¡à± సమాà°à°¾à°°à°‚ పూరింà°à°¾à°²à°¨à±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
<translation id="5810442152076338065"><ph name="DOMAIN" />à°•à°¿ à°—à°² మీ కనెకà±à°·à°¨à± వాడà±à°•à°²à±‹ లేని సైఫరౠసూటౠఉపయోగింà°à°¿ à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°à°¬à°¡à°¿à°‚ది.</translation>
<translation id="5813119285467412249">&amp;జోడింà°à°¡à°¾à°¨à±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ à°à±‡à°¯à°¿</translation>
+<translation id="5814352347845180253">మీరౠ<ph name="SITE" /> మరియౠమరికà±à°¨à±à°¨à°¿ ఇతర సైటà±â€Œà°² à°¨à±à°‚à°¡à°¿ à°ªà±à°°à±€à°®à°¿à°¯à°‚ కంటెంటà±â€Œà°•à°¿ à°ªà±à°°à°¾à°ªà±à°¯à°¤à°¨à± కోలà±à°ªà±‹à°µà°à±à°à±.</translation>
+<translation id="5843436854350372569">మీరౠ<ph name="DOMAIN" />కౠకనెకà±à°Ÿà± కావడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¾à°°à±, కానీ సరà±à°µà°°à± బలహీన కీని కలిగి ఉనà±à°¨ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ అందింà°à°¿à°‚ది. దాడి à°à±‡à°¸à±‡à°µà°¾à°°à± à°ªà±à°°à±ˆà°µà±‡à°Ÿà± కీని విà°à±à°›à°¿à°¨à±à°¨à°‚ à°à±‡à°¸à°¾à°°à± మరియౠసరà±à°µà°°à± మీరౠà°à°¹à°¿à°‚à°à°¿à°¨ సరà±à°µà°°à± కాకపోవà°à±à°à± (మీరౠదాడి à°à±‡à°¸à±‡ వారితో à°•à°®à±à°¯à±‚నికేటౠà°à±‡à°¸à±à°¤à±à°‚à°¡à°µà°à±à°à±). <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">మీ నిరà±à°µà°¾à°¹à°•à±à°²à± à°ˆ సైటà±â€Œà°¨à± à°¬à±à°²à°¾à°•à± à°à±‡à°¸à°¿à°¨à°‚à°¦à±à°¨ మీకౠఈ సందేశం కనిపిసà±à°¤à±‹à°‚ది.</translation>
<translation id="5857090052475505287">à°•à±à°°à±à°¤à±à°¤ ఫోలà±à°¡à°°à±</translation>
<translation id="5869405914158311789">à°ˆ సైటà±â€Œà°¨à± à°à±‡à°°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¾à°®à±</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">తలà±à°²à°¿/తండà±à°°à°¿ సూà°à°¨à°²à±</translation>
<translation id="59107663811261420">à°ˆ à°µà±à°¯à°¾à°ªà°¾à°°à°¿ కోసం Google Payments à°ˆ రకమైన కారà±à°¡à±â€Œà°•à°¿ మదà±à°¦à°¤à°¿à°µà±à°µà°¦à±. దయà°à±‡à°¸à°¿ వేరà±à°• కారà±à°¡à±â€Œà°¨à± à°à°‚à°à±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="59174027418879706">à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°à°¬à°¡à°¿à°‚ది</translation>
+<translation id="5926846154125914413">మీరౠకà±à°¨à±à°¨à°¿ సైటà±â€Œà°² à°¨à±à°‚à°¡à°¿ à°ªà±à°°à±€à°®à°¿à°¯à°‚ కంటెంటà±â€Œà°•à°¿ à°ªà±à°°à°¾à°ªà±à°¯à°¤à°¨à± కోలà±à°ªà±‹à°µà°à±à°à±.</translation>
<translation id="5966707198760109579">వారం</translation>
<translation id="5967867314010545767">à°à°°à°¿à°¤à±à°° à°¨à±à°‚à°¡à°¿ తీసివేయి</translation>
<translation id="5975083100439434680">దూరంగా జూమౠà°à±†à°¯à±à°¯à°¿</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">à°¸à±à°µà°¯à°‚à°à°¾à°²à°•à°‚à°—à°¾</translation>
<translation id="6042308850641462728">మరింత</translation>
<translation id="6060685159320643512">జాగà±à°°à°¤à±à°¤, à°ˆ à°ªà±à°°à°¯à±‹à°—ాలౠవిఫలం కావà°à±à°à±</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{à°à°¦à±€ లేదà±}=1{1}other{#}}</translation>
<translation id="6146055958333702838">à°à°µà±ˆà°¨à°¾ కేబà±à°²à±â€Œà°²à°¨à± తనిఖీ à°à±‡à°¯à°‚à°¡à°¿ మరియౠమీరౠఉపయోగింà°à±‡ à°à°µà±ˆà°¨à°¾ రూటరà±â€Œà°²à±, మోడెమà±â€Œà°²à±
లేదా ఇతర నెటà±â€Œà°µà°°à±à°•à± పరికరాలనౠరీబూటౠà°à±‡à°¯à°‚à°¡à°¿.</translation>
<translation id="614940544461990577">ఇలా à°à±‡à°¸à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿:</translation>
<translation id="6150607114729249911">à°…à°¯à±à°¯à±‹! మీరౠఈ పేజీని సందరà±à°¶à°¿à°‚à°à°¾à°²à°‚టే మీ తలà±à°²à°¿à°¦à°‚à°¡à±à°°à±à°² à°…à°¨à±à°®à°¤à°¿ à°ªà±à°‚దాలి.</translation>
<translation id="6151417162996330722">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°à±†à°²à±à°²à±à°¬à°¾à°Ÿà± à°µà±à°¯à°µà°§à°¿ à°à°¾à°²à°¾ à°à°•à±à°•à±à°µ కాలం ఉంది.</translation>
-<translation id="6154808779448689242">అందింà°à°¬à°¡à°¿à°¨ విధాన టోకెనౠపà±à°°à°¸à±à°¤à±à°¤ టోకెనà±â€Œà°•à± సరిపోలలేదà±</translation>
<translation id="6165508094623778733">మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="6203231073485539293">మీ ఇంటరà±à°¨à±†à°Ÿà± కనెకà±à°·à°¨à±â€Œà°¨à± తనిఖీ à°à±‡à°¯à°‚à°¡à°¿</translation>
<translation id="6218753634732582820">Chromium à°¨à±à°‚à°¡à°¿ à°à°¿à°°à±à°¨à°¾à°®à°¾à°¨à± తీసివేయాలా?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">నెటà±â€Œà°µà°°à±à°•à± సూà°à°¨à°¨à± నిలిపివేసి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿</translation>
<translation id="6337534724793800597">పేరౠదà±à°µà°¾à°°à°¾ విధానాలనౠఫిలà±à°Ÿà°°à± à°à±‡à°¯à°¿</translation>
<translation id="6342069812937806050">ఇపà±à°ªà±à°¡à±‡</translation>
+<translation id="6345221851280129312">పరిమాణం తెలియదà±</translation>
<translation id="6355080345576803305">పబà±à°²à°¿à°•à± సెషనౠభరà±à°¤à±€</translation>
<translation id="6358450015545214790">దీని à°…à°°à±à°§à°‚ à°à°®à°¿à°Ÿà°¿?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 ఇతర సూà°à°¨}other{# ఇతర సూà°à°¨à°²à±}}</translation>
<translation id="6387478394221739770">à°…à°¦à±à°­à±à°¤à°®à±ˆà°¨ à°•à±à°°à±à°¤à±à°¤ Chrome లకà±à°·à°£à°¾à°² పటà±à°² ఆసకà±à°¤à°¿à°—à°¾ ఉనà±à°¨à°¾à°°à°¾? chrome.com/betaలో మా బీటా ఛానెలà±â€Œà°¨à± à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
-<translation id="641480858134062906"><ph name="URL" /> లోడౠà°à±†à°¯à±à°¯à°¡à°‚ విఫలమైంది</translation>
+<translation id="6389758589412724634">Chromium à°ˆ వెబà±â€Œà°ªà±‡à°œà±€à°¨à°¿ à°ªà±à°°à°¦à°°à±à°¶à°¿à°‚à°à°¡à°¾à°¨à°¿à°•à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°¸à±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± మెమరీ అయిపోయింది.</translation>
+<translation id="6416403317709441254"><ph name="SITE" /> Chromium à°ªà±à°°à°¾à°¸à±†à°¸à± à°à±‡à°¯à°²à±‡à°¨à°¿ రీతిలో గజిబిజిగా ఉండే ఆధారాలనౠపంపినందà±à°¨ మీరౠపà±à°°à°¸à±à°¤à±à°¤à°‚ à°† వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°¨à°¿ సందరà±à°¶à°¿à°‚à°à°²à±‡à°°à±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, కావà±à°¨ à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని à°à±‡à°¸à±‡ అవకాశం ఉంది. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°°à°¦à±à°¦à± à°à±†à°¯à±à°¯à°¬à°¡à°¿à°‚దా అని తనిఖీ à°à±†à°¯à±à°¯à°¡à°‚ సాధà±à°¯à°‚ కాలేదà±.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> కనెకà±à°Ÿà± కావడానికి నిరాకరింà°à°¿à°‚ది.</translation>
<translation id="6445051938772793705">దేశం</translation>
<translation id="6451458296329894277">ఫారమౠపà±à°¨à°ƒà°¸à°®à°°à±à°ªà°£à°¨à± నిరà±à°¥à°¾à°°à°¿à°‚à°à°‚à°¡à°¿</translation>
<translation id="6458467102616083041">విధానంà°à±‡ డిపాలà±à°Ÿà± శోధన ఆపివేయబడినందà±à°¨ విసà±à°®à°°à°¿à°‚à°à°¬à°¡à°¿à°‚ది.</translation>
+<translation id="6462969404041126431">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ ఉపసంహరింà°à°¬à°¡à°¿à°‚ది. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన ఇలా జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">పరికర విధానాలà±</translation>
<translation id="6489534406876378309">à°•à±à°°à°¾à°·à±â€Œà°²à°¨à± à°…à°ªà±â€Œà°²à±‹à°¡à± à°à±‡à°¯à°¡à°¾à°¨à±à°¨à°¿ à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°à°‚à°¡à°¿</translation>
<translation id="6529602333819889595">&amp;à°¤à±à°²à°—à°¿à°‚à°à°¡à°¾à°¨à±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ à°à±‡à°¯à°¿</translation>
+<translation id="6534179046333460208">à°ªà±à°°à°¤à±à°¯à°•à±à°· వెబౠసూà°à°¨à°²à±</translation>
<translation id="6550675742724504774">à°à°‚పికలà±</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" /> కంటే తకà±à°•à±à°µ</translation>
<translation id="6596325263575161958">à°—à±à°ªà±à°¤à±€à°•à°°à°£ à°à°‚పికలà±</translation>
<translation id="662080504995468778">ఇందà±à°²à±‹à°¨à±‡ ఉంà°à±</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> శోధన</translation>
-<translation id="6634865548447745291"><ph name="BEGIN_LINK" />à°ˆ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ ఉపసంహరింà°à°¬à°¡à°¿à°‚ది<ph name="END_LINK" /> కావà±à°¨ మీరౠఇపà±à°ªà±à°¡à± <ph name="SITE" />ని సందరà±à°¶à°¿à°‚à°à°²à±‡à°°à±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, కావà±à°¨ à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని à°à±‡à°¸à±‡ అవకాశం ఉంది.</translation>
<translation id="6644283850729428850">à°ˆ విధానం విలà±à°µ తగà±à°—à°¿à°‚à°à°¬à°¡à°¿à°‚ది.</translation>
+<translation id="6652240803263749613">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ మీ à°•à°‚à°ªà±à°¯à±‚టరౠఆపరేటింగౠసిసà±à°Ÿà°®à± విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¦à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన ఇలా జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">ఫోలà±à°¡à°°à±â€Œà°¨à± సవరింà°à°‚à°¡à°¿</translation>
<translation id="6660210980321319655">à°¸à±à°µà°¯à°‚à°à°¾à°²à°•à°‚à°—à°¾ నివేదింà°à°¬à°¡à°¿à°¨ సమయం <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Chromium à°¨à±à°‚à°¡à°¿ ఫారమౠసూà°à°¨à°¨à± తీసివేయాలా?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">à°®à±à°¨à±à°ªà°Ÿà°¿</translation>
<translation id="6710594484020273272">&lt;శోధన పదానà±à°¨à°¿ టైపౠà°à±‡à°¯à°‚à°¡à°¿&gt;</translation>
<translation id="6711464428925977395">à°ªà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±â€Œà°²à±‹ à°à°¦à±‹ తపà±à°ªà± ఉంది లేదా à°à°¿à°°à±à°¨à°¾à°®à°¾ సరైనది కాదà±.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{à°à°¦à±€ లేదà±}=1{1 అంశం}other{# అంశాలà±}}</translation>
<translation id="674375294223700098">తెలియని సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ లోపం.</translation>
<translation id="6753269504797312559">విధానం విలà±à°µ</translation>
<translation id="6757797048963528358">మీ పరికరం నిదà±à°°à°¾à°µà°¸à±à°¥à°•à°¿ వెళà±à°²à°¿à°‚ది.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">విధానం à°¸à±à°¥à°¾à°¯à°¿à°•à°¿ మదà±à°¦à°¤à± లేదà±.</translation>
<translation id="6895330447102777224">మీ కారà±à°¡à± నిరà±à°§à°¾à°°à°¿à°‚à°à°¬à°¡à°¿à°‚ది</translation>
<translation id="6897140037006041989">వినియోగదారౠపà±à°°à°¤à°¿à°¨à°¿à°§à°¿</translation>
-<translation id="6903907808598579934">సమకాలీకరణనౠఆనౠà°à±‡à°¯à°¿</translation>
<translation id="6915804003454593391">వినియోగదారà±:</translation>
<translation id="6957887021205513506">సరà±à°µà°°à± ధృవీకరణ పతà±à°°à°‚ à°à±†à°²à±à°²à°¦à±.</translation>
<translation id="6965382102122355670">సరే</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">జిలà±à°²à°¾</translation>
<translation id="6973656660372572881">రెండౠసà±à°¥à°¿à°° à°ªà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±à°²à± మరియౠఒక .pac à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± URL పేరà±à°•à±à°¨à°¬à°¡à±à°¡à°¾à°¯à°¿.</translation>
<translation id="6989763994942163495">à°…à°§à±à°¨à°¾à°¤à°¨ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± à°à±‚పింà°à±...</translation>
+<translation id="7000990526846637657">à°à°°à°¿à°¤à±à°° నమోదà±à°²à± à°à°µà±€ à°•à°¨à±à°—à±à°¨à°¬à°¡à°²à±‡à°¦à±</translation>
+<translation id="7009986207543992532">మీరౠ<ph name="DOMAIN" />à°•à°¿ కనెకà±à°Ÿà± కావడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¾à°°à±, కానీ సరà±à°µà°°à± అందింà°à°¿à°¨ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± కాలం విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¨à°‚à°¤ à°à°•à±à°•à±à°µ à°µà±à°¯à°µà°§à°¿ ఉంది. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">à°à±ˆà°¨à°¾ యూనియనౠపే</translation>
+<translation id="7012372675181957985">మీ Google ఖాతా <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />లో ఇతర à°¬à±à°°à±Œà°œà°¿à°‚à°—à± à°à°°à°¿à°¤à±à°° రూపాలౠఉండవà°à±à°à±.</translation>
<translation id="7029809446516969842">పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±</translation>
-<translation id="7050187094878475250">మీరౠ<ph name="DOMAIN" />ని à°à±‡à°°à±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¾à°°à±, కానీ సరà±à°µà°°à± అందింà°à°¿à°¨ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¨à°‚à°¤ à°à°•à±à°•à±à°µ à°à±†à°²à±à°²à±à°¬à°¾à°Ÿà± à°µà±à°¯à°µà°§à°¿à°¨à°¿ కలిగి ఉంది.</translation>
<translation id="7087282848513945231">కౌంటి</translation>
<translation id="7088615885725309056">పాతవి</translation>
<translation id="7090678807593890770"><ph name="LINK" /> కోసం Googleలో శోధింà°à°‚à°¡à°¿</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">మీరౠమà±à°¦à°Ÿà°¿à°¸à°¾à°°à°¿ à°•à±à°¤à±à°¤ సైటà±â€Œà°²à°¨à± సందరà±à°¶à°¿à°‚à°à°¿à°¨à°ªà±à°ªà±à°¡à± వాటిని మీ నిరà±à°µà°¾à°¹à°•à±à°²à± ఆమోదింà°à°¾à°²à±à°¸à°¿à°¨ ఆవశà±à°¯à°•à°‚ ఉనà±à°¨à°‚à°¦à±à°¨ మీకౠఈ సందేశం కనిపిసà±à°¤à±‹à°‚ది.</translation>
<translation id="724975217298816891">మీ కారà±à°¡à± వివరాలనౠనవీకరింà°à°¡à°¾à°¨à°¿à°•à°¿ <ph name="CREDIT_CARD" /> కారà±à°¡à± à°—à°¡à±à°µà± à°®à±à°—ింపౠతేదీ మరియౠCVCని నమోదౠà°à±‡à°¯à°‚à°¡à°¿. మీరౠనిరà±à°§à°¾à°°à°¿à°‚à°à°¿à°¨ తరà±à°µà°¾à°¤, మీ కారà±à°¡à± వివరాలౠఈ సైటà±â€Œà°¤à±‹ భాగసà±à°µà°¾à°®à±à°¯à°‚ à°à±‡à°¯à°¬à°¡à°¤à°¾à°¯à°¿.</translation>
<translation id="725866823122871198">మీ à°•à°‚à°ªà±à°¯à±‚టరౠతేదీ మరియౠసమయం (<ph name="DATE_AND_TIME" />) తపà±à°ªà±à°—à°¾ ఉనà±à°¨à°‚à°¦à±à°¨ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />à°•à°¿ à°ªà±à°°à±ˆà°µà±‡à°Ÿà± కనెకà±à°·à°¨à± à°à°°à±à°ªà°¾à°Ÿà± à°à±‡à°¯à°¬à°¡à°¦à±.</translation>
-<translation id="7265986070661382626">వెబà±â€Œà°¸à±ˆà°Ÿà± <ph name="BEGIN_LINK" />à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ పినౠà°à±‡à°¯à°¬à°¡à±‡ పదà±à°§à°¤à°¿à°¨à°¿ ఉపయోగిసà±à°¤à±‹à°‚ది<ph name="END_LINK" /> కావà±à°¨ మీరౠఇపà±à°ªà±à°¡à± <ph name="SITE" />ని సందరà±à°¶à°¿à°‚à°à°²à±‡à°°à±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, కావà±à°¨ à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని à°à±‡à°¸à±‡ అవకాశం ఉంది.</translation>
<translation id="7269802741830436641">à°ˆ వెబà±â€Œà°ªà±‡à°œà±€ దారిమళà±à°³à°¿à°‚à°à°¬à°¡à±à°¡ లూపà±â€Œà°¨à°¿ కలిగి ఉంది</translation>
<translation id="7275334191706090484">నిరà±à°µà°¹à°¿à°‚à°à°¬à°¡à°¿à°¨ à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
<translation id="7298195798382681320">సిఫారà±à°¸à± à°à±‡à°¯à°¬à°¡à°¿à°¨à°µà°¿</translation>
-<translation id="7301833672208172928">à°à°°à°¿à°¤à±à°° సమకాలీకరణనౠఆనౠà°à±‡à°¯à°¿</translation>
+<translation id="7309308571273880165"><ph name="CRASH_TIME" /> తేదీన సంగà±à°°à°¹à°¿à°‚à°à°¿à°¨ à°•à±à°°à°¾à°·à± నివేదిక (à°…à°ªà±â€Œà°²à±‹à°¡à± à°à±‡à°¯à°¾à°²à±à°¸à°¿à°‚దిగా వినియోగదారà±à°•à± à°…à°­à±à°¯à°°à±à°¥à°¨, ఇంకా à°…à°ªà±â€Œà°²à±‹à°¡à± à°à±‡à°¯à°²à±‡à°¦à±)</translation>
<translation id="7334320624316649418">&amp;మళà±à°²à±€ à°•à±à°°à°®à°‚ à°à±‡à°¯à°¡à°¾à°¨à±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ à°à±‡à°¯à°¿</translation>
<translation id="733923710415886693">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ పారదరà±à°¶à°•à°¤ à°¦à±à°µà°¾à°°à°¾ బహిరంగపరà°à°²à±‡à°¦à±.</translation>
+<translation id="7351800657706554155"><ph name="SITE" /> à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ ఉపసంహరింà°à°¬à°¡à°¿à°¨à°‚à°¦à±à°¨ మీరౠఆ సైటà±â€Œà°¨à± ఇపà±à°ªà±à°¡à± సందరà±à°¶à°¿à°‚à°à°²à±‡à°°à±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, à°•à°¨à±à°• à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని à°à±‡à°¸à±‡ అవకాశం ఉంది. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">ఆదేశ పంకà±à°¤à°¿</translation>
<translation id="7372973238305370288">శోధన ఫలితం</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">కారà±à°¡à±â€Œà°¨à°¿ నిరà±à°§à°¾à°°à°¿à°¸à±à°¤à±‹à°‚ది</translation>
<translation id="7481312909269577407">ఫారà±à°µà°¾à°°à±à°¡à±</translation>
<translation id="7485870689360869515">డేటా à°•à°¨à±à°—à±à°¨à°¬à°¡à°²à±‡à°¦à±.</translation>
+<translation id="7508255263130623398">అందింà°à°¬à°¡à°¿à°¨ విధాన పరికర id ఖాళీగా ఉంది లేదా à°ªà±à°°à°¸à±à°¤à±à°¤ పరికర idà°•à°¿ సరిపోలలేదà±</translation>
<translation id="7514365320538308">డౌనà±â€Œà°²à±‹à°¡à± à°à±‡à°¯à°¿</translation>
<translation id="7518003948725431193">వెబౠà°à°¿à°°à±à°¨à°¾à°®à°¾à°•à± వెబà±â€Œà°ªà±‡à°œà±€ à°•à°¨à±à°—à±à°¨à°¬à°¡à°²à±‡à°¦à±: <ph name="URL" /></translation>
<translation id="7537536606612762813">తపà±à°ªà°¨à°¿à°¸à°°à°¿</translation>
<translation id="7542995811387359312">à°ˆ ఫారమౠసà±à°°à°•à±à°·à°¿à°¤ కనెకà±à°·à°¨à±â€Œà°¨à°¿ ఉపయోగింà°à°¨à°‚à°¦à±à°¨ à°¸à±à°µà°¯à°‚à°à°¾à°²à°•à°‚à°—à°¾ à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à± పూరà±à°¤à°¿ à°à±†à°¯à±à°¯à°¡à°‚ ఆపివేయబడింది.</translation>
<translation id="7549584377607005141">à°ˆ వెబà±â€Œà°ªà±‡à°œà±€ సరిగà±à°—à°¾ à°ªà±à°°à°¦à°°à±à°¶à°¿à°‚à°à°¬à°¡à°Ÿà°¾à°¨à°¿à°•à°¿ మీరౠమà±à°¨à±à°ªà± నమోదౠà°à±‡à°¸à°¿à°¨ డేటా అవసరం. మీరౠఈ డేటానౠమళà±à°²à±€ పంపవà°à±à°à±, కానీ అలా à°à±‡à°¯à°¡à°‚ వలన à°ˆ పేజీ à°®à±à°¨à±à°ªà± à°ªà±à°°à°¦à°°à±à°¶à°¿à°‚à°à°¿à°¨ à°à°¦à±ˆà°¨à°¾ à°à°°à±à°¯ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ కావà°à±à°à±.</translation>
<translation id="7554791636758816595">à°•à±à°¤à±à°¤ à°Ÿà±à°¯à°¾à°¬à±</translation>
-<translation id="7567204685887185387">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపింà°à±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ మోసపూరితంగా జారీ à°…à°¯à±à°¯à°¿ ఉండవà°à±à°à±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన జరిగి ఉండవà°à±à°à±.</translation>
<translation id="7568593326407688803">à°ˆ పేజీ<ph name="ORIGINAL_LANGUAGE" />లో ఉంది మీరౠదీనà±à°¨à°¿ à°…à°¨à±à°µà°¦à°¿à°‚à°à°¾à°²à°¨à±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
<translation id="7569952961197462199">Chrome à°¨à±à°‚à°¡à°¿ à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°¨à± తీసివేయాలా?</translation>
<translation id="7578104083680115302">మీరౠGoogleతో సేవౠà°à±‡à°¸à°¿à°¨ కారà±à°¡à±â€Œà°²à°¨à± ఉపయోగింà°à°¿ పరికరాలà±à°²à±‹à°¨à°¿ సైటà±â€Œà°²à± మరియౠఅనà±à°µà°°à±à°¤à°¨à°¾à°²à±à°²à±‹ శీఘà±à°°à°‚à°—à°¾ à°à±†à°²à±à°²à°¿à°‚à°à°‚à°¡à°¿.</translation>
+<translation id="7588950540487816470">భౌతిక వెబà±</translation>
<translation id="7592362899630581445">సరà±à°µà°°à± à°¯à±à°•à±à°• à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ పేరౠపరిమితà±à°²à°¨à± ఉలà±à°²à°‚ఘిసà±à°¤à±‹à°‚ది.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ à°ˆ à°…à°­à±à°¯à°°à±à°¥à°¨à°¨à± నిరà±à°µà°¹à°¿à°‚à°à°²à±‡à°¦à±.</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" />నౠà°à°ªà±à°ªà°Ÿà°¿à°•à±€ à°…à°¨à±à°µà°¦à°¿à°‚à°à°µà°¦à±à°¦à±</translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">Chromium à°¨à±à°‚à°¡à°¿ à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°¨à± తీసివేయాలా?</translation>
<translation id="765676359832457558">à°…à°§à±à°¨à°¾à°¤à°¨ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± దాà°à±...</translation>
<translation id="7658239707568436148">à°°à°¦à±à°¦à± à°à±†à°¯à±à°¯à°¿</translation>
+<translation id="7667346355482952095">అందింà°à°¿à°¨ విధాన టోకెనౠఖాళీగా ఉంది లేదా à°ªà±à°°à°¸à±à°¤à±à°¤ టోకెనà±â€Œà°¤à±‹ సరిపోలలేదà±</translation>
<translation id="7668654391829183341">తెలియని పరికరం</translation>
<translation id="7674629440242451245">à°…à°¦à±à°­à±à°¤à°®à±ˆà°¨ à°•à±à°°à±à°¤à±à°¤ Chrome లకà±à°·à°£à°¾à°² పటà±à°² ఆసకà±à°¤à°¿à°—à°¾ ఉనà±à°¨à°¾à°°à°¾? chrome.com/devలో మా డెవలపరౠఛానెలà±â€Œà°¨à± à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" />à°•à°¿ à°•à±à°¨à°¸à°¾à°—à°¿à°‚à°à°‚à°¡à°¿ (à°…à°¸à±à°°à°•à±à°·à°¿à°¤à°‚)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">వదà±à°¦à± , ధనà±à°¯à°µà°¾à°¦à°¾à°²à±</translation>
<translation id="7805768142964895445">à°¸à±à°¥à°¿à°¤à°¿</translation>
<translation id="7813600968533626083">Chrome à°¨à±à°‚à°¡à°¿ ఫారమౠసూà°à°¨à°¨à± తీసివేయాలా?</translation>
+<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' కోసం <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> à°•à°¨à±à°—à±à°¨à°¬à°¡à±à°¡à°¾à°¯à°¿</translation>
<translation id="785549533363645510">అయితే, మీరౠఅదృశà±à°¯à°‚à°—à°¾ ఉండరà±. à°…à°œà±à°à°¾à°¤à°‚లోకి వెళà±à°²à°¡à°‚ వలన మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠమీ యజమానికి, మీ ఇంటరà±à°¨à±†à°Ÿà± సేవా à°ªà±à°°à°¦à°¾à°¤à°•à± లేదా మీరౠసందరà±à°¶à°¿à°‚à°à±‡ వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°²à°•à± కనిపింà°à°•à±à°‚à°¡à°¾ దాà°à°¬à°¡à°¦à±.</translation>
<translation id="7887683347370398519">మీ CVCని తనిఖీ à°à±‡à°¸à°¿, మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿</translation>
<translation id="7894616681410591072">à°…à°¯à±à°¯à±‹! à°ˆ పేజీని à°ªà±à°°à°¾à°ªà±à°¯à°¤ à°à±‡à°¯à°¡à°¾à°¨à°¿à°•à°¿ మీరౠ<ph name="NAME" /> à°¨à±à°‚à°¡à°¿ à°…à°¨à±à°®à°¤à°¿ à°ªà±à°‚దాలి.</translation>
-<translation id="790025292736025802"><ph name="URL" /> à°•à°¨à±à°—à±à°¨à°¬à°¡à°²à±‡à°¦à±</translation>
<translation id="7912024687060120840">ఫోలà±à°¡à°°à±â€Œà°²à±‹:</translation>
<translation id="7920092496846849526">మీరౠఈ పేజీని సందరà±à°¶à°¿à°‚à°à°¡à°¾à°¨à°¿à°•à°¿ à°…à°¨à±à°®à°¤à°¿à°‚à°à°®à°¨à°¿ కోరà±à°¤à±‚ మీ తలà±à°²à°¿/తండà±à°°à°¿à°•à°¿ à°…à°­à±à°¯à°°à±à°¥à°¨ పంపారà±.</translation>
<translation id="7935318582918952113">DOM à°¡à°¿à°¸à±à°Ÿà°¿à°²à±à°²à°°à±</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">పేరà±à°•à±à°¨à°¬à°¡à°²à±‡à°¦à±</translation>
<translation id="8012647001091218357">మేమౠపà±à°°à°¸à±à°¤à±à°¤à°‚ మీ తలà±à°²à°¿à°¦à°‚à°¡à±à°°à±à°²à°¨à± సంపà±à°°à°¦à°¿à°‚à°à°²à±‡à°•à°ªà±‹à°¯à°¾à°®à±. దయà°à±‡à°¸à°¿ మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿.</translation>
<translation id="8034522405403831421">à°ˆ పేజీ <ph name="SOURCE_LANGUAGE" />లో ఉంది. దీనà±à°¨à°¿ <ph name="TARGET_LANGUAGE" />లోకి à°…à°¨à±à°µà°¦à°¿à°‚à°à°¾à°²à°¾?</translation>
-<translation id="8034955203865359138">à°à°°à°¿à°¤à±à°° నమోదà±à°²à± à°•à°¨à±à°—à±à°¨à°¬à°¡à°²à±‡à°¦à±.</translation>
<translation id="8088680233425245692">కథనానà±à°¨à°¿ వీకà±à°·à°¿à°‚à°à°¡à°‚లో విఫలమైంది.</translation>
+<translation id="8089520772729574115">1 MB కంటే తకà±à°•à±à°µ</translation>
<translation id="8091372947890762290">సకà±à°°à°¿à°¯à°‚ సరà±à°µà°°à±â€Œà°²à±‹ పెండింగà±â€Œà°²à±‹ ఉంది</translation>
+<translation id="8129262335948759431">డేటా à°®à±à°¤à±à°¤à°‚ తెలియదà±</translation>
<translation id="8131740175452115882">నిరà±à°§à°¾à°°à°¿à°‚à°à±</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> సరà±à°µà°°à± <ph name="BEGIN_ABBR" />DNS à°à°¿à°°à±à°¨à°¾à°®à°¾<ph name="END_ABBR" />నౠకనà±à°—à±à°¨à°¡à°‚ సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±.</translation>
<translation id="8149426793427495338">మీ à°•à°‚à°ªà±à°¯à±‚టరౠనిదà±à°°à°¾à°µà°¸à±à°¥à°•à°¿ వెళà±à°²à°¿à°‚ది.</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">ID "<ph name="EXTENSION_ID" />" ఉనà±à°¨ à°ªà±à°¡à°¿à°—ింపౠకోసం నవీకరణ URL à°à±†à°²à±à°²à°¦à±.</translation>
<translation id="8218327578424803826">కేటాయింà°à°¿à°¨ à°¸à±à°¥à°¾à°¨à°‚:</translation>
<translation id="8225771182978767009">à°ˆ à°•à°‚à°ªà±à°¯à±‚à°Ÿà°°à±â€Œà°¨à± సెటపౠà°à±‡à°¸à°¿à°¨ à°µà±à°¯à°•à±à°¤à°¿ à°ˆ సైటà±â€Œà°¨à± à°¬à±à°²à°¾à°•à± à°à±‡à°¯à°¡à°¾à°¨à°¿à°•à°¿ à°à°‚à°à±à°•à±à°¨à±à°¨à°¾à°°à±.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">మీరౠవెతికే పేజీ మీరౠà°à°‚à°Ÿà°°à± à°à±‡à°¸à°¿à°¨ సమాà°à°¾à°°à°¾à°¨à±à°¨à°¿ ఉపయోగింà°à±à°•à±à°‚ది. à°† పేజీకి తిరిగి వెళà±à°³à°¡à°‚ à°¦à±à°µà°¾à°°à°¾ మీరౠà°à±‡à°¸à°¿à°¨ à° à°à°°à±à°¯ అయినా à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ à°à±†à°¯à±à°¯à°µà°²à°¸à°¿ వసà±à°¤à±à°‚ది. మీరౠకà±à°¨à°¸à°¾à°—ాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
<translation id="8249320324621329438">à°à°¿à°µà°°à°—à°¾ à°ªà±à°‚దబడినవి:</translation>
<translation id="8261506727792406068">à°¤à±à°²à°—à°¿à°‚à°à±</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°² పటà±à°Ÿà±€</translation>
<translation id="8363502534493474904">à°à°¯à°¿à°°à±â€Œà°ªà±à°²à±ˆà°¨à± మోడà±â€Œà°¨à± ఆఫౠà°à±‡à°¯à°¡à°‚</translation>
<translation id="8364627913115013041">సెటౠà°à±‡à°¯à°²à±‡à°¦à±.</translation>
+<translation id="8380941800586852976">అపాయకరమైనది</translation>
<translation id="8412145213513410671">à°•à±à°°à°¾à°·à±â€Œà°²à± (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">మీరౠఅదే పాసà±â€Œà°«à±à°°à±‡à°œà±â€Œà°¨à°¿ రెండà±à°¸à°¾à°°à±à°²à± à°–à°à±à°à°¿à°¤à°‚à°—à°¾ à°à°‚à°Ÿà°°à± à°à±†à°¯à±à°¯à°¾à°²à°¿.</translation>
<translation id="8428213095426709021">సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±</translation>
+<translation id="8433057134996913067">దీని వలన మీరౠà°à°¾à°²à°¾ వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°² à°¨à±à°‚à°¡à°¿ సైనౠఅవà±à°Ÿà± à°à±‡à°¯à°¬à°¡à°¤à°¾à°°à±.</translation>
<translation id="8437238597147034694">&amp;తరలింà°à°¡à°¾à°¨à±à°¨à°¿ à°°à°¦à±à°¦à± à°à±‡à°¯à°¿</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±}other{# à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°²à±}}</translation>
+<translation id="8483780878231876732">మీ Google ఖాతా à°¨à±à°‚à°¡à°¿ కారà±à°¡à±â€Œà°²à°¨à± ఉపయోగింà°à±‡à°‚à°¦à±à°•à±, Chromeà°•à°¿ సైనౠఇనౠà°à±‡à°¯à°‚à°¡à°¿</translation>
<translation id="8488350697529856933">వీటికి వరà±à°¤à°¿à°¸à±à°¤à±à°‚ది</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దింà°à°¡à°¾à°¨à°¿à°•à°¿ à°à°¾à°²à°¾ à°à°•à±à°•à±à°µ సమయం పటà±à°Ÿà°¿à°‚ది.</translation>
+<translation id="852346902619691059">à°ˆ సరà±à°µà°°à± ఇది à°’à°• <ph name="DOMAIN" /> అని నిరూపింà°à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ మీ పరికరం ఆపరేటింగౠసిసà±à°Ÿà°®à± విశà±à°µà°¸à°¿à°‚à°à°²à±‡à°¦à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—à°°à± à°à±‡à°¯à°¡à°‚ వలన లేదా దాడిà°à±‡à°¸à±‡ à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à°¿ అంతరాయం కలిగింà°à°¡à°‚ వలన ఇలా జరిగి ఉండవà°à±à°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Google Payments à°ˆ రకమైన కారà±à°¡à±â€Œà°•à°¿ మదà±à°¦à°¤à°¿à°µà±à°µà°¦à±. దయà°à±‡à°¸à°¿ వేరà±à°• కారà±à°¡à±â€Œà°¨à± à°à°‚à°à±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="8550022383519221471">సమకాలీకరణ సేవ మీ à°¡à±à°®à±ˆà°¨à±â€Œà°•à± à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±.</translation>
<translation id="8553075262323480129">పేజీ భాష నిరà±à°¥à°¾à°°à°¿à°‚à°à°²à±‡à°•à°ªà±‹à°¯à°¿à°¨à°‚à°¦à±à°¨ à°…à°¨à±à°µà°¾à°¦à°‚ విఫలమైంది.</translation>
@@ -633,15 +675,12 @@
<translation id="8647750283161643317">à°…à°¨à±à°¨à°¿à°‚టినీ డిఫాలà±à°Ÿà±â€Œà°•à± రీసెటౠà°à±‡à°¯à°¿</translation>
<translation id="8680787084697685621">ఖాతా సైనà±-ఇనౠవివరాల à°—à°¡à±à°µà± తేదీ à°®à±à°—ిసింది.</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" />కౠమీ కనెకà±à°·à°¨à± à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚à°à°¬à°¡à°²à±‡à°¦à±.</translation>
-<translation id="8713130696108419660">à°à±†à°²à±à°²à°¨à°¿ à°ªà±à°°à°¾à°°à°‚à°­ సంతకం</translation>
<translation id="8725066075913043281">మళà±à°³à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°‚à°¡à°¿</translation>
<translation id="8728672262656704056">మీరౠఅజà±à°à°¾à°¤à°‚à°—à°¾ ఉనà±à°¨à°¾à°°à±</translation>
<translation id="8730621377337864115">పూరà±à°¤à°¯à°¿à°‚ది</translation>
<translation id="8738058698779197622">à°¸à±à°°à°•à±à°·à°¿à°¤ కనెకà±à°·à°¨à±â€Œà°¨à± à°à°°à±à°ªà°¾à°Ÿà± à°à±‡à°¯à°¡à°¾à°¨à°¿à°•à°¿, మీ గడియారానà±à°¨à°¿ సరైన సమయానికి సెటౠà°à±‡à°¯à°¾à°²à°¿. à°à°‚à°¦à±à°•à°‚టే వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°²à± వాటిని à°—à±à°°à±à°¤à°¿à°‚à°à°¡à°¾à°¨à°¿à°•à°¿ ఉపయోగింà°à±‡ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°²à± నిరà±à°¦à°¿à°·à±à°Ÿ కాలవà±à°¯à°µà°§à±à°²à±à°²à±‹ మాతà±à°°à°®à±‡ à°à±†à°²à±à°²à±à°¬à°¾à°Ÿà± à°…à°µà±à°¤à°¾à°¯à°¿. మీ పరికరం à°¯à±à°•à±à°• గడియారం సమయం తపà±à°ªà±à°—à°¾ ఉనà±à°¨à°‚à°¦à±à°¨, Chromium à°ˆ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°²à°¨à± ధృవీకరింà°à°¡à°¾à°¨à°¿à°•à°¿ వీలà±à°ªà°¡à°²à±‡à°¦à±.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS à°à°¿à°°à±à°¨à°¾à°®à°¾&lt;/abbr&gt; à°•à°¨à±à°—à±à°¨à°¬à°¡à°²à±‡à°¦à±. సమసà±à°¯à°¨à± నిరà±à°§à°¾à°°à°¿à°¸à±à°¤à±‹à°‚ది.</translation>
-<translation id="8741995161408053644">మీ Google ఖాతా <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />లో ఇతర à°¬à±à°°à±Œà°œà°¿à°‚à°—à± à°à°°à°¿à°¤à±à°° రూపాలనౠకలిగి ఉండవà°à±à°à±.</translation>
<translation id="8790007591277257123">&amp;à°¤à±à°²à°—à°¿à°‚à°à°¡à°¾à°¨à±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ à°à±‡à°¯à°¿</translation>
-<translation id="8790687370365610530">Google సూà°à°¿à°‚à°à±‡ à°µà±à°¯à°•à±à°¤à°¿à°—తీకృత కంటెంటà±â€Œà°¨à± à°ªà±à°‚దడానికి, à°à°°à°¿à°¤à±à°° సమకాలీకరణనౠఆనౠà°à±‡à°¯à°‚à°¡à°¿.</translation>
<translation id="8798099450830957504">డిఫాలà±à°Ÿà±</translation>
<translation id="8804164990146287819">గోపà±à°¯à°¤à°¾ విధానం</translation>
<translation id="8820817407110198400">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">సరà±à°µà°°à± à°¯à±à°•à±à°• à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± à°®à±à°—ిసింది.</translation>
<translation id="8987927404178983737">నెల</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°° పారదరà±à°¶à°•à°¤ విధానానà±à°¨à°¿ ఉపయోగింà°à°¿ పబà±à°²à°¿à°•à±â€Œà°—à°¾ బహిరంగపరà°à°¬à°¡à°¨à°¿ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ అందింà°à°¿à°‚ది. à°•à±à°¨à±à°¨à°¿ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°²à°•à±, అవి విశà±à°µà°¸à°¨à±€à°¯à°®à±ˆà°¨à°µà°¨à°¿ మరియౠదాడి à°à±‡à°¸à±‡à°µà°¾à°°à°¿ à°¨à±à°‚à°¡à°¿ à°°à°•à±à°·à°£ à°•à°²à±à°ªà°¿à°‚à°à°—లవని నిరà±à°§à°¾à°°à°¿à°‚à°à°¡à°¾à°¨à°¿à°•à°¿, ఇది ఆవశà±à°¯à°•à°‚.</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> à°ªà±à°°à°¾à°•à±à°¸à±€à°•à°¿ వినియోగదారౠపేరౠమరియౠపాసà±â€Œà°µà°°à±à°¡à± అవసరం.</translation>
<translation id="901974403500617787">సిసà±à°Ÿà°®à± à°µà±à°¯à°¾à°ªà±à°¤à°‚à°—à°¾ వరà±à°¤à°¿à°‚పజేయబడే à°«à±à°²à°¾à°—à±â€Œà°²à± యజమాని à°¦à±à°µà°¾à°°à°¾ మాతà±à°°à°®à±‡ సెటౠà°à±‡à°¯à°¬à°¡à°¤à°¾à°¯à°¿: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">à°ˆ పేజీ <ph name="TARGET_LANGUAGE" />à°•à°¿ à°…à°¨à±à°µà°¦à°¿à°‚à°à°¬à°¡à°¿à°‚ది</translation>
<translation id="9038649477754266430">పేజీలనౠమరింత శీఘà±à°°à°‚à°—à°¾ లోడౠà°à±‡à°¯à°¡à°¾à°¨à°¿à°•à°¿ సూà°à°¨ సేవనౠఉపయోగింà°à°‚à°¡à°¿</translation>
<translation id="9039213469156557790">అలాగే, à°ˆ పేజీలో à°¸à±à°°à°•à±à°·à°¿à°¤à°‚ కాని ఇతర వనరà±à°²à± ఉనà±à°¨à°¾à°¯à°¿. à°ˆ వనరà±à°²à°¨à± బదిలీ à°à±‡à°¸à±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± ఇతరà±à°²à± à°à±‚డగలరౠమరియౠదాడికి పాలà±à°ªà°¡à±‡à°µà°¾à°°à± పేజీ à°ªà±à°°à°µà°°à±à°¤à°¨à°¨à± మారà±à°à±‡à°²à°¾ వీటిని సవరింà°à°—లరà±.</translation>
-<translation id="9049981332609050619">మీరౠ<ph name="DOMAIN" />ని à°à±‡à°°à±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°à°¾à°°à±, కానీ సరà±à°µà°°à± à°’à°• à°à±†à°²à±à°²à±à°¬à°¾à°Ÿà±à°²à±‹ లేని à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ని అందింà°à°¿à°‚ది.</translation>
<translation id="9050666287014529139">పాసà±â€Œà°«à±à°°à±‡à°œà±</translation>
<translation id="9065203028668620118">సవరింà°à±</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> పేజీ పని à°à±‡à°¯à°¡à°‚ లేదà±</translation>
diff --git a/chromium/components/strings/components_strings_th.xtb b/chromium/components/strings/components_strings_th.xtb
index 7b35b11c40f..f9d6822f622 100644
--- a/chromium/components/strings/components_strings_th.xtb
+++ b/chromium/components/strings/components_strings_th.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="th">
+<translation id="1008557486741366299">ไม่ใà¸à¹ˆà¸•à¸­à¸™à¸™à¸µà¹‰</translation>
<translation id="1015730422737071372">ให้รายละเอียดเà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡</translation>
<translation id="1032854598605920125">หมุนตามเข็มนาฬิà¸à¸²</translation>
<translation id="1038842779957582377">ไม่ทราà¸à¸à¸·à¹ˆà¸­</translation>
+<translation id="1053591932240354961">คุณไม่สามารถเข้าà¸à¸¡ <ph name="SITE" /> ได้ในขณะนี้ เนื่องจาà¸à¹€à¸§à¹‡à¸à¹„ซต์ส่งข้อมูลรัà¸à¸£à¸­à¸‡à¸—ี่ถูà¸à¹à¸›à¸¥à¸‡à¸‹à¸¶à¹ˆà¸‡ Google Chrome ไม่สามารถดำเนินà¸à¸²à¸£à¹„ด้ โดยปà¸à¸•à¸´à¸‚้อผิดà¸à¸¥à¸²à¸”ของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¹‚จมตีจะเà¸à¸´à¸”ขึ้นเà¸à¸µà¸¢à¸‡à¸à¸±à¹ˆà¸§à¸„ราว หน้านี้จึงอาจจะใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในภายหลัง <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¹€à¸à¸´à¹ˆà¸¡</translation>
<translation id="10614374240317010">ไม่เคยà¸à¸±à¸™à¸—ึà¸</translation>
-<translation id="1064422015032085147">เซิร์ฟเวอร์ที่โฮสต์หน้าเว็à¸à¸™à¸µà¹‰à¸­à¸²à¸ˆà¸—ำงานหนัà¸à¹€à¸à¸´à¸™à¹„ปหรืออยู่ระหว่างà¸à¸²à¸£à¸‹à¹ˆà¸­à¸¡à¸à¸³à¸£à¸¸à¸‡
- ทั้งนี้เà¸à¸·à¹ˆà¸­à¸«à¸¥à¸µà¸à¹€à¸¥à¸µà¹ˆà¸¢à¸‡à¹„ม่ให้เà¸à¸´à¸”à¸à¸²à¸£à¹€à¸‚้าà¸à¸¡à¸—ี่มาà¸à¹€à¸à¸´à¸™à¹„ปà¹à¸¥à¸°à¸—ำให้สถานà¸à¸²à¸£à¸“์à¹à¸¢à¹ˆà¸¥à¸‡
- ระà¸à¸à¸ˆà¸°à¹„ม่อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¸ªà¹ˆà¸‡à¸„ำขอไปยัง URL นี้à¸à¸±à¹ˆà¸§à¸„ราว</translation>
<translation id="106701514854093668">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸à¸™à¹€à¸”สà¸à¹Œà¸—็อป</translation>
<translation id="1080116354587839789">à¸à¸­à¸”ีà¸à¸±à¸à¸„วามà¸à¸§à¹‰à¸²à¸‡</translation>
+<translation id="1103124106085518534">เรียà¸à¸£à¹‰à¸­à¸¢à¹à¸¥à¹‰à¸§</translation>
<translation id="1103523840287552314">à¹à¸›à¸¥à¸ à¸²à¸©à¸²<ph name="LANGUAGE" />ทุà¸à¸„รั้ง</translation>
<translation id="1107591249535594099">หาà¸à¹€à¸¥à¸·à¸­à¸ Chrome จะจัดเà¸à¹‡à¸à¸ªà¸³à¹€à¸™à¸²à¸‚องà¸à¸±à¸•à¸£à¸à¸™à¸­à¸¸à¸›à¸à¸£à¸“์นี้เà¸à¸·à¹ˆà¸­à¸à¸²à¸£à¸à¸£à¸­à¸à¸‚้อมูลà¹à¸à¸à¸Ÿà¸­à¸£à¹Œà¸¡à¸­à¸¢à¹ˆà¸²à¸‡à¸£à¸§à¸”เร็ว</translation>
+<translation id="1111153019813902504">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸—ี่เà¸à¸´à¹ˆà¸‡à¸”ู</translation>
<translation id="1113869188872983271">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¸ˆà¸±à¸”ลำดัà¸à¹ƒà¸«à¸¡à¹ˆ</translation>
+<translation id="1126551341858583091">ขนาดà¸à¸™à¸à¸·à¹‰à¸™à¸—ี่เà¸à¹‡à¸à¸‚้อมูลในเครื่องคือ <ph name="CRASH_SIZE" /></translation>
<translation id="112840717907525620">à¹à¸„à¸à¸™à¹‚ยà¸à¸²à¸¢à¹ƒà¸à¹‰à¹„ด้</translation>
<translation id="113188000913989374"><ph name="SITE" /> à¸à¸­à¸à¸§à¹ˆà¸²:</translation>
<translation id="1132774398110320017">à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าป้อนข้อความอัตโนมัติของ Chrome...</translation>
-<translation id="1150979032973867961">เซิร์ฟเวอร์นี้ไม่สามารถà¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ด้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¸£à¸°à¸à¸à¸›à¸à¸´à¸à¸±à¸•à¸´à¸à¸²à¸£à¸‚องคอมà¸à¸´à¸§à¹€à¸•à¸­à¸£à¹Œà¸‚องคุณไม่เà¸à¸·à¹ˆà¸­à¸–ือใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัย โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="1152921474424827756">เข้าถึง<ph name="BEGIN_LINK" />สำเนาà¹à¸„à¸<ph name="END_LINK" />ของ <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> ปิดà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¹‚ดยไม่คาดคิด</translation>
<translation id="1161325031994447685">เà¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­ Wi-Fi ใหม่</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">ลà¸</translation>
<translation id="1201402288615127009">ถัดไป</translation>
<translation id="1201895884277373915">เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡à¸ˆà¸²à¸à¹„ซต์นี้</translation>
-<translation id="121201262018556460">คุณà¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸‚้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่มีคีย์ที่ไม่รัดà¸à¸¸à¸¡ ผู้โจมตีอาจทำให้คีย์ส่วนตัวเสียหายไปà¹à¸¥à¹‰à¸§à¹à¸¥à¸°à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸™à¸µà¹‰à¸­à¸²à¸ˆà¹„ม่ใà¸à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่คุณคิด (คุณอาจà¸à¸³à¸¥à¸±à¸‡à¸•à¸´à¸”ต่อà¸à¸±à¸à¸œà¸¹à¹‰à¹‚จมตี)</translation>
+<translation id="1206967143813997005">ลายเซ็นเริ่มต้นไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
+<translation id="1209206284964581585">ซ่อนไปà¸à¹ˆà¸­à¸™</translation>
<translation id="1219129156119358924">à¸à¸²à¸£à¸£à¸±à¸à¸©à¸²à¸„วามปลอดภัยของระà¸à¸</translation>
<translation id="1227224963052638717">นโยà¸à¸²à¸¢à¸—ี่ไม่รู้จัà¸</translation>
<translation id="1227633850867390598">ซ่อนค่า</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">ใà¸à¹ˆ</translation>
<translation id="1430915738399379752">à¸à¸´à¸¡à¸à¹Œ</translation>
<translation id="1442912890475371290">à¸à¸¥à¹‡à¸­à¸à¸„วามà¸à¸¢à¸²à¸¢à¸²à¸¡<ph name="BEGIN_LINK" />ที่จะเข้าà¸à¸¡à¸«à¸™à¹‰à¸²à¹€à¸§à¹‡à¸à¹ƒà¸™ <ph name="DOMAIN" /><ph name="END_LINK" /></translation>
+<translation id="1491663344921578213">คุณไม่สามารถเข้าà¸à¸¡ <ph name="SITE" /> ได้ในขณะนี้ เนื่องจาà¸à¹€à¸§à¹‡à¸à¹„ซต์ใà¸à¹‰à¸à¸²à¸£à¸•à¸£à¸¶à¸‡à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡ โดยปà¸à¸•à¸´à¸‚้อผิดà¸à¸¥à¸²à¸”ของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¹‚จมตีจะเà¸à¸´à¸”ขึ้นเà¸à¸µà¸¢à¸‡à¸à¸±à¹ˆà¸§à¸„ราว หน้านี้จึงอาจจะใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในภายหลัง <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">à¹à¸ªà¸”งสำเนาที่à¸à¸±à¸™à¸—ึà¸à¹„ว้ (หรือที่ล้าสมัย) ของหน้านี้</translation>
<translation id="1519264250979466059">วันที่สร้าง</translation>
<translation id="1549470594296187301">ต้องเปิดใà¸à¹‰ JavaScript เà¸à¸·à¹ˆà¸­à¹ƒà¸à¹‰à¸„ุณลัà¸à¸©à¸“ะนี้</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าเครือข่ายไม่ถูà¸à¸•à¹‰à¸­à¸‡à¹à¸¥à¸°à¹„ม่สามารถนำเข้า</translation>
<translation id="1644574205037202324">ประวัติà¸à¸²à¸£à¹€à¸‚้าà¸à¸¡</translation>
<translation id="1645368109819982629">ไม่รองรัà¸à¹‚ปรโตคอล</translation>
-<translation id="1655462015569774233">{1,plural, =1{เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยหมดอายุไปเมื่อวานนี้ โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ ขณะนี้นาฬิà¸à¸²à¸‚องคุณตั้งค่าไว้ที่วันที่ <ph name="CURRENT_DATE" /> à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่านี้ถูà¸à¸•à¹‰à¸­à¸‡à¹„หม หาà¸à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡ คุณควรà¹à¸à¹‰à¹„ขนาฬิà¸à¸²à¸‚องระà¸à¸à¹à¸¥à¸°à¸£à¸µà¹€à¸Ÿà¸£à¸à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰}other{เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยหมดอายุไปเมื่อ # วันที่ผ่านมา โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ ขณะนี้นาฬิà¸à¸²à¸‚องคุณตั้งค่าไว้ที่วันที่ <ph name="CURRENT_DATE" /> à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่านี้ถูà¸à¸•à¹‰à¸­à¸‡à¹„หม หาà¸à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡ คุณควรà¹à¸à¹‰à¹„ขนาฬิà¸à¸²à¸‚องระà¸à¸à¹à¸¥à¸°à¸£à¸µà¹€à¸Ÿà¸£à¸à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰}}</translation>
<translation id="1676269943528358898">โดยทั่วไป <ph name="SITE" /> จะใà¸à¹‰à¸à¸²à¸£à¹€à¸‚้ารหัสเà¸à¸·à¹ˆà¸­à¸›à¸à¸›à¹‰à¸­à¸‡à¸‚้อมูลของคุณ เมื่อ Google Chrome à¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸à¸±à¸ <ph name="SITE" /> ในครั้งนี้ เว็à¸à¹„ซต์ดังà¸à¸¥à¹ˆà¸²à¸§à¸ªà¹ˆà¸‡à¸‚้อมูลรัà¸à¸£à¸­à¸‡à¸—ี่ผิดปà¸à¸•à¸´à¹à¸¥à¸°à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡à¸à¸¥à¸±à¸à¸¡à¸² เหตุà¸à¸²à¸£à¸“์นี้อาจเà¸à¸´à¸”ขึ้นเมื่อผู้à¸à¸¸à¸à¸£à¸¸à¸à¸à¸¢à¸²à¸¢à¸²à¸¡à¸›à¸¥à¸­à¸¡à¹€à¸›à¹‡à¸™ <ph name="SITE" /> หรือหน้าจอà¸à¸²à¸£à¸¥à¸‡à¸à¸·à¹ˆà¸­à¹€à¸‚้าใà¸à¹‰ Wi-Fi รà¸à¸à¸§à¸™à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­ ข้อมูลของคุณยังปลอดภัยอยู่เนื่องจาภGoogle Chrome หยุดà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸à¹ˆà¸­à¸™à¸¡à¸µà¸à¸²à¸£à¹à¸¥à¸à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸‚้อมูล</translation>
<translation id="168841957122794586">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์มีคีย์à¸à¸²à¸£à¹€à¸‚้ารหัสที่ไม่รัดà¸à¸¸à¸¡</translation>
<translation id="1701955595840307032">รัà¸à¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸—ี่à¹à¸™à¸°à¸™à¸³</translation>
-<translation id="1706954506755087368">{1,plural, =1{เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยควรจะเริ่มใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ตั้งà¹à¸•à¹ˆà¸§à¸±à¸™à¸à¸£à¸¸à¹ˆà¸‡à¸™à¸µà¹‰ โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ}other{เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยควรจะเริ่มใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในอีภ# วันข้างหน้า โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ}}</translation>
<translation id="1710259589646384581">ระà¸à¸à¸›à¸à¸´à¸à¸±à¸•à¸´à¸à¸²à¸£</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">ลองติดต่อผู้ดูà¹à¸¥à¸£à¸°à¸à¸</translation>
<translation id="17513872634828108">à¹à¸—็à¸à¸—ี่เปิดอยู่</translation>
<translation id="1753706481035618306">เลขหน้า</translation>
-<translation id="1761412452051366565">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¸£à¸±à¸à¸„ำà¹à¸™à¸°à¸™à¸³à¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸—ี่เหมาะสำหรัà¸à¸„ุณจาภGoogle ให้เปิดà¸à¸²à¸£à¸‹à¸´à¸‡à¸„์</translation>
-<translation id="1763864636252898013">เซิร์ฟเวอร์นี้ไม่สามารถà¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ด้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¸£à¸°à¸à¸à¸›à¸à¸´à¸à¸±à¸•à¸´à¸à¸²à¸£à¸‚องอุปà¸à¸£à¸“์ของคุณไม่เà¸à¸·à¹ˆà¸­à¸–ือใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัย โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />ลองเรียà¸à¹ƒà¸à¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¹€à¸„รือข่ายของ Windows<ph name="END_LINK" /></translation>
<translation id="1783075131180517613">โปรดอัปเดตข้อความรหัสผ่านที่ซิงค์ของคุณ</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸—ี่คุณเข้าà¸à¸¡à¸¥à¹ˆà¸²à¸ªà¸¸à¸”จะปราà¸à¸à¸—ี่นี่</translation>
<translation id="1821930232296380041">คำขอหรือà¸à¸²à¸£à¸²à¸¡à¸´à¹€à¸•à¸­à¸£à¹Œà¸„ำขอไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="1838667051080421715">คุณà¸à¸³à¸¥à¸±à¸‡à¸”ูà¹à¸«à¸¥à¹ˆà¸‡à¸—ี่มาของหน้าเว็à¸</translation>
<translation id="1871208020102129563">à¸à¸£à¹‡à¸­à¸à¸‹à¸µà¸–ูà¸à¸•à¸±à¹‰à¸‡à¸„่าให้ใà¸à¹‰à¸à¸£à¹‡à¸­à¸à¸‹à¸µà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸à¸à¸„งที่ ไม่ใà¸à¹ˆ URL สคริปต์ .pac</translation>
<translation id="1883255238294161206">ยุà¸à¸£à¸²à¸¢à¸à¸²à¸£</translation>
<translation id="1898423065542865115">à¸à¸²à¸£à¸à¸£à¸­à¸‡</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> ไม่ยอมรัà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸à¸²à¸£à¹€à¸‚้าสู่ระà¸à¸à¸«à¸£à¸·à¸­à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸à¸²à¸£à¹€à¸‚้าสู่ระà¸à¸à¸­à¸²à¸ˆà¸«à¸¡à¸”อายุà¹à¸¥à¹‰à¸§</translation>
<translation id="194030505837763158">ไปที่ <ph name="LINK" /></translation>
<translation id="1962204205936693436">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸‚อง <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">ข้อผิดà¸à¸¥à¸²à¸”ในà¸à¸²à¸£à¸ˆà¸±à¸”เรียง</translation>
<translation id="1974060860693918893">ขั้นสูง</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{à¹à¸¥à¸°à¸­à¸µà¸ 1 à¹à¸­à¸›}other{à¹à¸¥à¸°à¸­à¸µà¸ # à¹à¸­à¸›}}</translation>
<translation id="2025186561304664664">à¸à¸£à¹‡à¸­à¸à¸‹à¸µà¸–ูà¸à¸•à¸±à¹‰à¸‡à¸„่าให้ทำà¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าโดยอัตโนมัติ</translation>
<translation id="2030481566774242610">หรือคุณหมายถึง <ph name="LINK" /></translation>
<translation id="2031925387125903299">คุณเห็นข้อความนี้เนื่องจาà¸à¸•à¹‰à¸­à¸‡à¹ƒà¸«à¹‰à¸œà¸¹à¹‰à¸›à¸à¸„รองอนุมัติà¸à¸²à¸£à¹€à¸‚้าà¸à¸¡à¹€à¸§à¹‡à¸à¹„ซต์ใหม่ในครั้งà¹à¸£à¸à¸‚องคุณ</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />ตรวจสอà¸à¸à¸£à¹‡à¸­à¸à¸‹à¸µà¹à¸¥à¸°à¹„ฟร์วอลล์<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">รหัสไปรษณีย์</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 คำà¹à¸™à¸°à¸™à¸³}other{# คำà¹à¸™à¸°à¸™à¸³}}</translation>
<translation id="2065985942032347596">ต้องมีà¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸à¸„วามถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="2079545284768500474">เลิà¸à¸—ำ</translation>
<translation id="20817612488360358">มีà¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ให้ใà¸à¹‰à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าà¸à¸£à¹‡à¸­à¸à¸‹à¸µà¸£à¸°à¸à¸ à¹à¸•à¹ˆà¸à¹‡à¸¡à¸µà¸à¸²à¸£à¸£à¸°à¸à¸¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าà¸à¸£à¹‡à¸­à¸à¸‹à¸µà¸­à¸¢à¹ˆà¸²à¸‡à¸à¸±à¸”เจนไว้ด้วยเà¸à¹ˆà¸™à¸à¸±à¸™</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">à¹à¸à¹‰à¹„ขà¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸</translation>
<translation id="2166049586286450108">à¸à¸²à¸£à¹€à¸‚้าถึงระดัà¸à¸œà¸¹à¹‰à¸”ูà¹à¸¥à¸£à¸°à¸à¸à¹‚ดยสมà¸à¸¹à¸£à¸“์</translation>
<translation id="2166378884831602661">เว็à¸à¹„ซต์นี้ไม่สามารถให้à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸—ี่ปลอดภัย</translation>
-<translation id="2171101176734966184">คุณà¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸‚้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่เซ็นà¸à¸·à¹ˆà¸­à¸”้วยอัลà¸à¸­à¸£à¸´à¸—ึมลายเซ็นที่ไม่รัดà¸à¸¸à¸¡ ซึ่งหมายความว่าข้อมูลรัà¸à¸£à¸­à¸‡à¸”้านความปลอดภัยที่เซิร์ฟเวอร์à¹à¸ªà¸”งอาจถูà¸à¸›à¸¥à¸­à¸¡à¹à¸›à¸¥à¸‡à¸‚ึ้น à¹à¸¥à¸°à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸”ังà¸à¸¥à¹ˆà¸²à¸§à¸­à¸²à¸ˆà¹„ม่ใà¸à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่คุณคิด (คุณอาจà¸à¸³à¸¥à¸±à¸‡à¸•à¸´à¸”ต่อà¸à¸±à¸à¸œà¸¹à¹‰à¹‚จมตี)</translation>
<translation id="2181821976797666341">นโยà¸à¸²à¸¢</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{ที่อยู่ 1 รายà¸à¸²à¸£}other{ที่อยู่ # รายà¸à¸²à¸£}}</translation>
<translation id="2212735316055980242">ไม่à¸à¸à¸™à¹‚ยà¸à¸²à¸¢</translation>
<translation id="2213606439339815911">à¸à¸³à¸¥à¸±à¸‡à¸”ึงรายà¸à¸²à¸£...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> ไม่à¸à¸£à¹‰à¸­à¸¡à¹ƒà¸à¹‰à¸‡à¸²à¸™</translation>
<translation id="2230458221926704099">à¹à¸à¹‰à¹„ขà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณด้วย<ph name="BEGIN_LINK" />à¹à¸­à¸›à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">ส่งเลย</translation>
<translation id="225207911366869382">เลิà¸à¹ƒà¸à¹‰à¸‡à¸²à¸™à¸„่านี้à¸à¸±à¸à¸™à¹‚ยà¸à¸²à¸¢à¸™à¸µà¹‰</translation>
<translation id="2262243747453050782">ข้อผิดà¸à¸¥à¸²à¸”ของ HTTP</translation>
<translation id="2282872951544483773">à¸à¸²à¸£à¸—ดลองที่ไม่à¸à¸£à¹‰à¸­à¸¡à¹ƒà¸à¹‰à¸‡à¸²à¸™</translation>
<translation id="2292556288342944218">à¸à¸²à¸£à¹€à¸‚้าถึงอินเทอร์เน็ตของคุณถูà¸à¸à¸¥à¹‡à¸­à¸</translation>
<translation id="229702904922032456">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่ออà¸à¹€à¸­à¸‡à¸«à¸£à¸·à¸­à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¹‚ดยคนà¸à¸¥à¸²à¸‡à¸«à¸¡à¸”อายุà¹à¸¥à¹‰à¸§</translation>
<translation id="230155334948463882">à¸à¸±à¸•à¸£à¹ƒà¸«à¸¡à¹ˆà¹ƒà¸à¹ˆà¹„หม</translation>
+<translation id="2305919008529760154">เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¸­à¸²à¸ˆà¸¡à¸µà¸à¸²à¸£à¸­à¸­à¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยปลอม สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> ต้องใà¸à¹‰à¸à¸·à¹ˆà¸­à¸œà¸¹à¹‰à¹ƒà¸à¹‰à¹à¸¥à¸°à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™</translation>
+<translation id="2318774815570432836">คุณไม่สามารถเข้าà¸à¸¡ <ph name="SITE" /> ได้ในขณะนี้ เนื่องจาà¸à¹€à¸§à¹‡à¸à¹„ซต์ดังà¸à¸¥à¹ˆà¸²à¸§à¹ƒà¸à¹‰ HSTS โดยปà¸à¸•à¸´à¸‚้อผิดà¸à¸¥à¸²à¸”ของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¹‚จมตีจะเà¸à¸´à¸”ขึ้นเà¸à¸µà¸¢à¸‡à¸à¸±à¹ˆà¸§à¸„ราว หน้านี้จึงอาจจะใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในภายหลัง <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸—ี่ไม่ถูà¸à¸•à¹‰à¸­à¸‡à¸–ูà¸à¹€à¸à¸´à¸à¹€à¸‰à¸¢à¸—ี่ดัà¸à¸™à¸µ <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸­à¸·à¹ˆà¸™à¹†</translation>
<translation id="2359808026110333948">ดำเนินà¸à¸²à¸£à¸•à¹ˆà¸­</translation>
<translation id="2365563543831475020">รายงานข้อขัดข้องเมื่อ <ph name="CRASH_TIME" /> ยังไม่ได้อัปโหลด</translation>
<translation id="2367567093518048410">ระดัà¸</translation>
+<translation id="2371153335857947666">{1,plural, =1{เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยหมดอายุไปเมื่อวานนี้ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ ขณะนี้นาฬิà¸à¸²à¸‚องคุณตั้งค่าไว้ที่วันที่ <ph name="CURRENT_DATE" /> à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่านี้ถูà¸à¸•à¹‰à¸­à¸‡à¹„หม หาà¸à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡ คุณควรà¹à¸à¹‰à¹„ขนาฬิà¸à¸²à¸‚องระà¸à¸à¹à¸¥à¸°à¸£à¸µà¹€à¸Ÿà¸£à¸à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" />}other{เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยหมดอายุไปเมื่อ # วันที่ผ่านมา สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ ขณะนี้นาฬิà¸à¸²à¸‚องคุณตั้งค่าไว้ที่วันที่ <ph name="CURRENT_DATE" /> à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่านี้ถูà¸à¸•à¹‰à¸­à¸‡à¹„หม หาà¸à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡ คุณควรà¹à¸à¹‰à¹„ขนาฬิà¸à¸²à¸‚องระà¸à¸à¹à¸¥à¸°à¸£à¸µà¹€à¸Ÿà¸£à¸à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">ไม่มีทางเลือภUI ที่à¸à¸£à¹‰à¸­à¸¡à¹ƒà¸à¹‰à¸‡à¸²à¸™</translation>
<translation id="2384307209577226199">ค่าเริ่มต้นขององค์à¸à¸£</translation>
-<translation id="238526402387145295">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้เนื่องจาà¸à¹€à¸§à¹‡à¸à¹„ซต์ดังà¸à¸¥à¹ˆà¸²à¸§<ph name="BEGIN_LINK" />ใà¸à¹‰ HSTS<ph name="END_LINK" /> โดยปà¸à¸•à¸´à¸‚้อผิดà¸à¸¥à¸²à¸”ของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¸à¸¸à¸à¸£à¸¸à¸à¸ˆà¸°à¹€à¸à¸´à¸”ขึ้นเà¸à¸µà¸¢à¸‡à¸à¸±à¹ˆà¸§à¸„ราว หน้านี้จึงน่าจะใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในภายหลัง</translation>
<translation id="2386255080630008482">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์ถูà¸à¹€à¸à¸´à¸à¸–อนà¹à¸¥à¹‰à¸§</translation>
<translation id="2392959068659972793">à¹à¸ªà¸”งนโยà¸à¸²à¸¢à¹‚ดยที่ไม่ได้ตั้งค่า</translation>
<translation id="2396249848217231973">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¸™à¸³à¸­à¸­à¸</translation>
-<translation id="2413528052993050574">เซิร์ฟเวอร์นี้ไม่สามารถà¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ด้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¸­à¸²à¸ˆà¸¡à¸µà¸à¸²à¸£à¹€à¸à¸´à¸à¸–อนใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัย โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="2455981314101692989">หน้าเว็à¸à¸™à¸µà¹‰à¸›à¸´à¸”ใà¸à¹‰à¸‡à¸²à¸™à¸à¸²à¸£à¸›à¹‰à¸­à¸™à¸­à¸±à¸•à¹‚นมัติสำหรัà¸à¸Ÿà¸­à¸£à¹Œà¸¡à¸™à¸µà¹‰</translation>
+<translation id="2463739503403862330">à¸à¸£à¸­à¸à¸‚้อมูล</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />เรียà¸à¹ƒà¸à¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¹€à¸„รือข่าย<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL ค้นหาไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="2491120439723279231">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์มีข้อผิดà¸à¸¥à¸²à¸”</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">ส่ง</translation>
<translation id="2674170444375937751">คุณà¹à¸™à¹ˆà¹ƒà¸ˆà¸«à¸£à¸·à¸­à¹„ม่ว่าต้องà¸à¸²à¸£à¸™à¸³à¸­à¸­à¸à¸«à¸™à¹‰à¸²à¹€à¸«à¸¥à¹ˆà¸²à¸™à¸µà¹‰à¸­à¸­à¸à¸ˆà¸²à¸à¸›à¸£à¸°à¸§à¸±à¸•à¸´à¸à¸²à¸£à¹€à¸‚้าà¸à¸¡à¸‚องคุณ</translation>
<translation id="2677748264148917807">ออà¸</translation>
+<translation id="269990154133806163">เซิร์ฟเวอร์à¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่ไม่เปิดเผยต่อสาธารณะโดยใà¸à¹‰à¸™à¹‚ยà¸à¸²à¸¢à¸„วามโปร่งใสของใà¸à¸£à¸±à¸à¸£à¸­à¸‡ นี่เป็นข้อà¸à¸³à¸«à¸™à¸”สำหรัà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸à¸²à¸‡à¸£à¸²à¸¢à¸à¸²à¸£ เà¸à¸·à¹ˆà¸­à¹ƒà¸«à¹‰à¹à¸™à¹ˆà¹ƒà¸ˆà¹„ด้ว่าใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸¡à¸µà¸„วามน่าเà¸à¸·à¹ˆà¸­à¸–ือà¹à¸¥à¸°à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¸œà¸¹à¹‰à¹‚จมตีได้ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">ค่าไม่ตรงà¸à¸±à¸à¸£à¸¹à¸›à¹à¸à¸</translation>
<translation id="2704951214193499422">Chromium ไม่สามารถยืนยันà¸à¸±à¸•à¸£à¸‚องคุณได้ในขณะนี้ โปรดลองอีà¸à¸„รั้งในภายหลัง</translation>
<translation id="2705137772291741111">อ่านสำเนาที่à¸à¸±à¸™à¸—ึà¸à¹„ว้ (à¹à¸„à¸) ของเว็à¸à¹„ซต์นี้ไม่ได้</translation>
<translation id="2709516037105925701">ป้อนอัตโนมัติ</translation>
+<translation id="2712118517637785082">คุณà¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸‚้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่เซิร์ฟเวอร์à¹à¸ªà¸”งถูà¸à¹€à¸à¸´à¸à¸–อนโดยผู้ออà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡ ซึ่งหมายความว่าข้อมูลรัà¸à¸£à¸­à¸‡à¸”้านความปลอดภัยที่เซิร์ฟเวอร์à¹à¸ªà¸”งมานั้นไม่สามารถเà¸à¸·à¹ˆà¸­à¸–ือได้ คุณอาจà¸à¸³à¸¥à¸±à¸‡à¸ªà¸·à¹ˆà¸­à¸ªà¸²à¸£à¸­à¸¢à¸¹à¹ˆà¸à¸±à¸à¸œà¸¹à¹‰à¹‚จมตี <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">ขออนุà¸à¸²à¸•</translation>
<translation id="2721148159707890343">คำขอสำเร็จ</translation>
<translation id="2728127805433021124">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์ถูà¸à¹€à¸‹à¹‡à¸™à¸à¸·à¹ˆà¸­à¸”้วยอัลà¸à¸­à¸£à¸´à¸—ึมลายเซ็นที่ไม่รัดà¸à¸¸à¸¡</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">ที่อยู่à¹à¸¥à¸°à¹à¸–à¸à¸„้นหา</translation>
<translation id="2826760142808435982">à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸–ูà¸à¹€à¸‚้ารหัสà¹à¸¥à¸°à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามถูà¸à¸•à¹‰à¸­à¸‡à¹‚ดยใà¸à¹‰ <ph name="CIPHER" /> à¹à¸¥à¸°à¹ƒà¸à¹‰ <ph name="KX" /> เป็นà¸à¸¥à¹„à¸à¸à¸²à¸£à¹à¸¥à¸à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸„ีย์</translation>
<translation id="2835170189407361413">ล้างฟอร์ม</translation>
-<translation id="2837049386027881519">à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸ˆà¸³à¹€à¸›à¹‡à¸™à¸•à¹‰à¸­à¸‡à¸¥à¸­à¸‡à¹ƒà¸«à¸¡à¹ˆà¸”้วยà¸à¸²à¸£à¹ƒà¸à¹‰à¹‚ปรโตคอล TLS หรือ SSL รุ่นเà¸à¹ˆà¸²à¸à¸§à¹ˆà¸²à¸™à¸µà¹‰ ซึ่งโดยทั่วไปหมายความว่าเซิร์ฟเวอร์นี้à¸à¸³à¸¥à¸±à¸‡à¹ƒà¸à¹‰à¸‹à¸­à¸Ÿà¸•à¹Œà¹à¸§à¸£à¹Œà¸£à¸¸à¹ˆà¸™à¹€à¸à¹ˆà¸²à¸¡à¸²à¸à¹à¸¥à¸°à¸­à¸²à¸ˆà¸¡à¸µà¸›à¸±à¸à¸«à¸²à¸”้านความปลอดภัยอื่นๆ</translation>
<translation id="284702764277384724">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่ <ph name="HOST_NAME" /> ดูเหมือนเป็นของปลอม</translation>
<translation id="2889159643044928134">อย่าโหลดซ้ำ</translation>
-<translation id="2896499918916051536">ไม่สนัà¸à¸ªà¸™à¸¸à¸™à¸›à¸¥à¸±à¹à¸à¸­à¸´à¸™à¸™à¸µà¹‰</translation>
+<translation id="2900469785430194048">Google Chrome หน่วยความจำเต็มเมื่อà¸à¸¢à¸²à¸¢à¸²à¸¡à¹à¸ªà¸”งหน้าเว็à¸à¸™à¸µà¹‰</translation>
<translation id="2909946352844186028">ตรวจà¸à¸à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¹€à¸„รือข่าย</translation>
-<translation id="2915500479781995473">เซิร์ฟเวอร์นี้ไม่สามารถà¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ด้ว่าเป็น <ph name="DOMAIN" /> เนื่องจาà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยได้หมดอายุà¹à¸¥à¹‰à¸§ โดยอาจมีสาเหตุมาจาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­ ขณะนี้นาฬิà¸à¸²à¹ƒà¸™à¸„อมà¸à¸´à¸§à¹€à¸•à¸­à¸£à¹Œà¸‚องคุณตั้งเวลาไว้ที่ <ph name="CURRENT_TIME" /> หาà¸à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡ โปรดตั้งนาฬิà¸à¸²à¸‚องระà¸à¸à¹ƒà¸«à¹‰à¸–ูà¸à¸•à¹‰à¸­à¸‡ à¹à¸¥à¹‰à¸§à¸£à¸µà¹€à¸Ÿà¸£à¸à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰à¸­à¸µà¸à¸„รั้ง</translation>
<translation id="2922350208395188000">ไม่สามารถตรวจสอà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์</translation>
-<translation id="2941952326391522266">เซิร์ฟเวอร์นี้ไม่สามารถà¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ด้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยมาจาภ<ph name="DOMAIN2" /> โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="2948083400971632585">คุณสามารถปิดใà¸à¹‰à¸‡à¸²à¸™à¸à¸£à¹‡à¸­à¸à¸‹à¸µà¸—ี่à¸à¸³à¸«à¸™à¸”ค่าสำหรัà¸à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸ˆà¸²à¸à¸«à¸™à¹‰à¸²à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าได้</translation>
<translation id="2955913368246107853">ปิดà¹à¸–à¸à¸„้นหา</translation>
<translation id="2958431318199492670">à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าเครือข่ายไม่เป็นไปตามมาตรà¸à¸²à¸™ ONC à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าà¸à¸²à¸‡à¸ªà¹ˆà¸§à¸™à¸­à¸²à¸ˆà¹„ม่ได้รัà¸à¸à¸²à¸£à¸™à¸³à¹€à¸‚้า</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">ประเภทนโยà¸à¸²à¸¢à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="3032412215588512954">คุณต้องà¸à¸²à¸£à¹‚หลดเว็à¸à¹„ซต์นี้ซ้ำใà¸à¹ˆà¹„หม</translation>
<translation id="3037605927509011580">à¹à¸¢à¹ˆà¸ˆà¸±à¸‡!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{อย่างน้อย 1 รายà¸à¸²à¸£à¸à¸™à¸­à¸¸à¸›à¸à¸£à¸“์ที่ซิงค์}=1{1 รายà¸à¸²à¸£ (à¹à¸¥à¸°à¸¡à¸²à¸à¸à¸§à¹ˆà¸²à¸à¸™à¸­à¸¸à¸›à¸à¸£à¸“์ที่ซิงค์)}other{# รายà¸à¸²à¸£ (à¹à¸¥à¸°à¸¡à¸²à¸à¸à¸§à¹ˆà¸²à¸à¸™à¸­à¸¸à¸›à¸à¸£à¸“์ที่ซิงค์)}}</translation>
<translation id="3041612393474885105">ข้อมูลในใà¸à¸£à¸±à¸à¸£à¸­à¸‡</translation>
<translation id="3063697135517575841">Chrome ไม่สามารถยืนยันà¸à¸±à¸•à¸£à¸‚องคุณได้ในขณะนี้ โปรดลองอีà¸à¸„รั้งในภายหลัง</translation>
<translation id="3093245981617870298">คุณออฟไลน์อยู่</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">ใหม่ที่สุด</translation>
<translation id="3207960819495026254">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¹à¸¥à¹‰à¸§</translation>
-<translation id="3225919329040284222">เซิร์ฟเวอร์à¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่ไม่ตรงà¸à¸±à¸à¸à¸²à¸£à¸„าดà¸à¸²à¸£à¸“์ที่มีอยู่ à¸à¸²à¸£à¸„าดà¸à¸²à¸£à¸“์เหล่านี้มีอยู่ในà¸à¸²à¸‡à¹€à¸§à¹‡à¸à¹„ซต์ที่มีà¸à¸²à¸£à¸£à¸±à¸à¸©à¸²à¸„วามปลอดภัยสูงเà¸à¸·à¹ˆà¸­à¸›à¸à¸›à¹‰à¸­à¸‡à¸„ุณ</translation>
<translation id="3226128629678568754">à¸à¸”ปุ่มโหลดซ้ำเà¸à¸·à¹ˆà¸­à¸ªà¹ˆà¸‡à¸‹à¹‰à¸³à¸‚้อมูลที่จำเป็นในà¸à¸²à¸£à¹‚หลดหน้าเว็à¸</translation>
<translation id="3228969707346345236">à¸à¸²à¸£à¹à¸›à¸¥à¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§à¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¸«à¸™à¹‰à¸²à¹€à¸§à¹‡à¸à¸™à¸µà¹‰à¹€à¸›à¹‡à¸™à¸ à¸²à¸©à¸²<ph name="LANGUAGE" />อยู่à¹à¸¥à¹‰à¸§</translation>
<translation id="323107829343500871">ป้อน CVC สำหรัภ<ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰</translation>
<translation id="3270847123878663523">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¸ˆà¸±à¸”ลำดัà¸à¹ƒà¸«à¸¡à¹ˆ</translation>
<translation id="3286538390144397061">รีสตาร์ทเดี๋ยวนี้</translation>
+<translation id="3303855915957856445">ไม่à¸à¸à¸œà¸¥à¸à¸²à¸£à¸„้นหา</translation>
<translation id="3305707030755673451">ข้อมูลของคุณได้รัà¸à¸à¸²à¸£à¹€à¸‚้ารหัสด้วยรหัสผ่านà¸à¸²à¸£à¸‹à¸´à¸‡à¸„์เมื่อวันที่ <ph name="TIME" /> โปรดป้อนรหัสผ่านเà¸à¸·à¹ˆà¸­à¹€à¸£à¸´à¹ˆà¸¡à¸‹à¸´à¸‡à¸„์</translation>
<translation id="333371639341676808">ป้องà¸à¸±à¸™à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰à¸ˆà¸²à¸à¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸à¸²à¸£à¹‚ต้ตอà¸à¹€à¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡</translation>
+<translation id="3338095232262050444">ปลอดภัย</translation>
<translation id="3340978935015468852">à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า</translation>
<translation id="3345135638360864351">ไม่สามารถส่งคำขอเข้าถึงไซต์นี้ไปยัง <ph name="NAME" /> ได้ โปรดลองอีà¸à¸„รั้ง</translation>
<translation id="3355823806454867987">เปลี่ยนà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าà¸à¸£à¹‡à¸­à¸à¸‹à¸µ...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">à¸à¹ˆà¸§à¸‡à¸à¸²à¸£à¸”ึงข้อมูล:</translation>
<translation id="3462200631372590220">ซ่อนข้อมูลขั้นสูง</translation>
<translation id="3479539252931486093">หาà¸à¹€à¸«à¸•à¸¸à¸à¸²à¸£à¸“์นี้ผิดปà¸à¸•à¸´ <ph name="BEGIN_LINK" />โปรดà¹à¸ˆà¹‰à¸‡à¹ƒà¸«à¹‰à¹€à¸£à¸²à¸—ราà¸<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">ไม่ใà¸à¹ˆà¸•à¸­à¸™à¸™à¸µà¹‰</translation>
<translation id="348000606199325318">รหัสข้อขัดข้อง <ph name="CRASH_LOCAL_ID" /> (รหัสเซิร์ฟเวอร์: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">เราไม่สามารถติดต่อผู้ปà¸à¸„รองของคุณได้ในขณะนี้ โปรดลองอีà¸à¸„รั้ง</translation>
<translation id="3527085408025491307">โฟลเดอร์</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">ใà¸à¹‰à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¸ªà¸³à¸«à¸£à¸±à¸:</translation>
<translation id="3549644494707163724">เข้ารหัสข้อมูลที่ซิงค์ทั้งหมดด้วยข้อความรหัสผ่านà¸à¸²à¸£à¸‹à¸´à¸‡à¸„์ของคุณเอง</translation>
<translation id="3549761410225185768">à¸à¸£à¹‰à¸­à¸¡à¹ƒà¸à¹‰à¸‡à¸²à¸™à¸­à¸µà¸ <ph name="NUM_TABS_MORE" /> à¹à¸—็à¸</translation>
+<translation id="3555561725129903880">เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยของเซิร์ฟเวอร์มาจาภ<ph name="DOMAIN2" /> สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณไม่เป็นส่วนตัว</translation>
<translation id="3583757800736429874">&amp;ทำซ้ำà¸à¸²à¸£à¸¢à¹‰à¸²à¸¢</translation>
<translation id="3586931643579894722">ซ่อนรายละเอียด</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">à¹à¸ªà¸”งค่า</translation>
<translation id="3630155396527302611">หาà¸à¹‚ปรà¹à¸à¸£à¸¡à¸­à¸¢à¸¹à¹ˆà¹ƒà¸™à¸£à¸²à¸¢à¸à¸²à¸£à¸—ี่ได้รัà¸à¸­à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸‚้าถึงเครือข่ายอยู่à¹à¸¥à¹‰à¸§
ลองนำโปรà¹à¸à¸£à¸¡à¸­à¸­à¸à¸ˆà¸²à¸à¸£à¸²à¸¢à¸à¸²à¸£à¹à¸¥à¸°à¹€à¸à¸´à¹ˆà¸¡à¸à¸¥à¸±à¸à¹€à¸‚้าไปใหม่</translation>
+<translation id="3638794133396384728">เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยของเซิร์ฟเวอร์หมดอายุไปà¹à¸¥à¹‰à¸§ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ ขณะนี้นาฬิà¸à¸²à¸‚องคุณตั้งค่าไว้ที่เวลา <ph name="CURRENT_TIME" /> à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่านี้ถูà¸à¸•à¹‰à¸­à¸‡à¹„หม หาà¸à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡ คุณควรà¹à¸à¹‰à¹„ขนาฬิà¸à¸²à¸‚องระà¸à¸à¹à¸¥à¸°à¸£à¸µà¹€à¸Ÿà¸£à¸à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">คุณลัà¸à¸©à¸“ะทดลองเหล่านี้อาจมีà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡ เสียหาย หรือยà¸à¹€à¸¥à¸´à¸à¹„ปได้ตลอดเวลา เราไม่รัà¸à¸›à¸£à¸°à¸à¸±à¸™à¹ƒà¸”ๆ เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸à¸ªà¸´à¹ˆà¸‡à¸—ี่อาจเà¸à¸´à¸”ขึ้นทั้งสิ้นหาà¸à¸„ุณเปิดใà¸à¹‰à¸à¸²à¸£à¸—ดลองรายà¸à¸²à¸£à¹ƒà¸”รายà¸à¸²à¸£à¸«à¸™à¸¶à¹ˆà¸‡à¸™à¸µà¹‰ เà¸à¸£à¸²à¸§à¹Œà¹€à¸‹à¸­à¸£à¹Œà¸‚องคุณอาจà¸à¸±à¸‡à¹‚ดยไม่มีสัà¸à¸à¸²à¸“เตือน ยิ่งไปà¸à¸§à¹ˆà¸²à¸™à¸±à¹‰à¸™ เà¸à¸£à¸²à¸§à¹Œà¹€à¸‹à¸­à¸£à¹Œà¸­à¸²à¸ˆà¸¥à¸à¸‚้อมูลทั้งหมดของคุณได้ หรือà¸à¸²à¸£à¸£à¸±à¸à¸©à¸²à¸„วามปลอดภัยà¹à¸¥à¸°à¸„วามเป็นส่วนตัวของคุณอาจโดนคุà¸à¸„ามโดยไม่คาดคิด à¸à¸²à¸£à¸—ดลองใดๆ ที่คุณเปิดใà¸à¹‰à¸‡à¸²à¸™à¸ˆà¸°à¹€à¸›à¸´à¸”ใà¸à¹‰à¸ªà¸³à¸«à¸£à¸±à¸à¸œà¸¹à¹‰à¹ƒà¸à¹‰à¸—ุà¸à¸„นที่ใà¸à¹‰à¹€à¸à¸£à¸²à¸§à¹Œà¹€à¸‹à¸­à¸£à¹Œà¸™à¸µà¹‰à¸”้วย โปรดดำเนินà¸à¸²à¸£à¸”้วยความระมัดระวัง</translation>
<translation id="3650584904733503804">à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸à¸ªà¸³à¹€à¸£à¹‡à¸ˆ</translation>
<translation id="3655670868607891010">หาà¸à¸„ุณเห็นข้อความนี้à¸à¹ˆà¸­à¸¢à¹† ให้ลองไปที่ <ph name="HELP_LINK" /></translation>
<translation id="3658742229777143148">à¸à¸²à¸£à¹à¸à¹‰à¹„ข</translation>
+<translation id="3678029195006412963">ไม่สามารถลงนามคำขอ</translation>
<translation id="3681007416295224113">ข้อมูลในใà¸à¸£à¸±à¸à¸£à¸­à¸‡</translation>
<translation id="3693415264595406141">รหัสผ่าน:</translation>
+<translation id="3696411085566228381">ไม่มี</translation>
<translation id="3700528541715530410">อà¹à¸° ดูเหมือนว่าคุณไม่มีสิทธิ์ในà¸à¸²à¸£à¹€à¸‚้าถึงหน้านี้</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">à¸à¸³à¸¥à¸±à¸‡à¹‚หลด...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">เปิดข้อมูลเครือข่ายมือถือหรือ Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ตรวจสอà¸à¸à¸£à¹‡à¸­à¸à¸‹à¸µ ไฟร์วอลล์ à¹à¸¥à¸°à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่า DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">ลิงà¸à¹Œà¸—ี่คุณคัดลอà¸à¸¡à¸²</translation>
-<translation id="3744899669254331632">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้เนื่องจาà¸à¹€à¸§à¹‡à¸à¹„ซต์ได้ส่งข้อมูลรัà¸à¸£à¸­à¸‡à¸—ี่มีà¸à¸²à¸£à¹à¸›à¸¥à¸‡à¸‚้อมูลซึ่ง Chromium ไม่สามารถดำเนินà¸à¸²à¸£à¹„ด้ ข้อผิดà¸à¸¥à¸²à¸”ของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¹‚จมตีมัà¸à¸ˆà¸°à¹€à¸à¸´à¸”ขึ้นà¸à¸±à¹ˆà¸§à¸„ราว ดังนั้นหน้านี้อาจจะใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในภายหลัง</translation>
<translation id="375403751935624634">à¸à¸²à¸£à¹à¸›à¸¥à¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§à¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¸‚้อผิดà¸à¸¥à¸²à¸”ของเซิร์ฟเวอร์</translation>
<translation id="3759461132968374835">คุณไม่ได้รายงานข้อขัดข้องเมื่อเร็วๆ นี้ ข้อขัดข้องที่เà¸à¸´à¸”ขึ้นเมื่อปิดใà¸à¹‰à¸‡à¸²à¸™à¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™à¸‚้อขัดข้อง จะไม่ปราà¸à¸à¸—ี่นี่</translation>
<translation id="3788090790273268753">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเว็à¸à¹„ซต์นี้จะหมดอายุในปี 2016 à¹à¸¥à¸°à¸à¸¥à¸¸à¹ˆà¸¡à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸™à¸µà¹‰à¸›à¸£à¸°à¸à¸­à¸à¸”้วยใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่ลงนามโดยใà¸à¹‰ SHA-1</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">ตัวà¸à¸µà¹‰à¸­à¸¸à¸›à¸à¸£à¸“์ขัดà¹à¸¢à¹‰à¸‡à¸à¸±à¸™</translation>
<translation id="3885155851504623709">เมือง</translation>
<translation id="3901925938762663762">à¸à¸±à¸•à¸£à¸«à¸¡à¸”อายุ</translation>
+<translation id="3910267023907260648">คุณà¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸‚้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่ลงนามด้วยอัลà¸à¸­à¸£à¸´à¸—ึมลายเซ็นที่ไม่รัดà¸à¸¸à¸¡ ซึ่งหมายความว่าข้อมูลรัà¸à¸£à¸­à¸‡à¸”้านความปลอดภัยที่เซิร์ฟเวอร์à¹à¸ªà¸”งอาจถูà¸à¸›à¸¥à¸­à¸¡à¹à¸›à¸¥à¸‡à¸‚ึ้น à¹à¸¥à¸°à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸”ังà¸à¸¥à¹ˆà¸²à¸§à¸­à¸²à¸ˆà¹„ม่ใà¸à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่คุณคิด (คุณอาจà¸à¸³à¸¥à¸±à¸‡à¸•à¸´à¸”ต่อà¸à¸±à¸à¸œà¸¹à¹‰à¹‚จมตี) <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยควรจะเริ่มใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ตั้งà¹à¸•à¹ˆà¸§à¸±à¸™à¸à¸£à¸¸à¹ˆà¸‡à¸™à¸µà¹‰ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" />}other{เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยควรจะเริ่มใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในอีภ# วันข้างหน้า สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">โหลดเอà¸à¸ªà¸²à¸£ PDF ล้มเหลว</translation>
<translation id="3963721102035795474">โหมดนัà¸à¸­à¹ˆà¸²à¸™</translation>
+<translation id="397105322502079400">à¸à¸³à¸¥à¸±à¸‡à¸„ำนวณ...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> ถูà¸à¸à¸¥à¹‡à¸­à¸</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{มีหน้าเว็ภ1 หน้าใà¸à¸¥à¹‰à¹†}other{มีหน้าเว็ภ# หน้าใà¸à¸¥à¹‰à¹†}}</translation>
<translation id="4021036232240155012">DNS คือà¸à¸£à¸´à¸à¸²à¸£à¹€à¸„รือข่ายที่à¹à¸›à¸¥à¸à¸·à¹ˆà¸­à¸‚องเว็à¸à¹„ซต์เป็นที่อยู่อินเทอร์เน็ต</translation>
<translation id="4030383055268325496">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¹€à¸à¸´à¹ˆà¸¡</translation>
-<translation id="4032534284272647190">à¸à¸²à¸£à¹€à¸‚้าถึง <ph name="URL" /> ถูà¸à¸›à¸à¸´à¹€à¸ªà¸˜</translation>
<translation id="404928562651467259">คำเตือน</translation>
<translation id="4058922952496707368">คีย์ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">ไคลเอ็นต์à¹à¸¥à¸°à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹„ม่รองรัà¸à¹‚ปรโตคอล SSL เวอร์à¸à¸±à¸™à¸—ั่วไปหรือà¸à¸¸à¸”à¸à¸²à¸£à¹€à¸‚้ารหัส</translation>
<translation id="4079302484614802869">à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าà¸à¸£à¹‡à¸­à¸à¸‹à¸µà¸¡à¸µà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าให้ใà¸à¹‰ URL สคริปต์ .pac ไม่ใà¸à¹ˆà¸à¸£à¹‡à¸­à¸à¸‹à¸µà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸à¸à¸„งที่</translation>
<translation id="4103249731201008433">หมายเลขซีเรียลของอุปà¸à¸£à¸“์ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="4103763322291513355">ไปที่ &lt;strong&gt;chrome://policy&lt;/strong&gt; เà¸à¸·à¹ˆà¸­à¸”ูรายà¸à¸²à¸£à¸‚อง URL ที่ไม่ได้รัà¸à¸­à¸™à¸¸à¸à¸²à¸• à¹à¸¥à¸°à¸™à¹‚ยà¸à¸²à¸¢à¸­à¸·à¹ˆà¸™à¹† ที่ผู้ดูà¹à¸¥à¸£à¸°à¸à¸à¸‚องคุณà¸à¸±à¸‡à¸„ัà¸à¹ƒà¸à¹‰</translation>
+<translation id="4110615724604346410">เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยของเซิร์ฟเวอร์มีข้อผิดà¸à¸¥à¸²à¸” สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">ขอà¸à¸‚่ายนโยà¸à¸²à¸¢à¹„ม่ได้รัà¸à¸à¸²à¸£à¸ªà¸™à¸±à¸à¸ªà¸™à¸¸à¸™</translation>
+<translation id="4118212371799607889">เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸° Chromium ไม่เà¸à¸·à¹ˆà¸­à¸–ือใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยของเซิร์ฟเวอร์นี้ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{อีภ1 รายà¸à¸²à¸£}other{อีภ# รายà¸à¸²à¸£}}</translation>
<translation id="4130226655945681476">ตรวจสอà¸à¸ªà¸²à¸¢à¹€à¸„รือข่าย โมเด็ม à¹à¸¥à¸°à¹€à¸£à¸²à¹€à¸•à¸­à¸£à¹Œ</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">คุณต้องà¸à¸²à¸£à¹ƒà¸«à¹‰ Chromium à¸à¸±à¸™à¸—ึà¸à¸à¸±à¸•à¸£à¸™à¸µà¹‰à¹„หม</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">ปิดà¸à¸²à¸£à¹ƒà¸à¹‰à¸‡à¸²à¸™à¹à¸¥à¹‰à¸§</translation>
<translation id="4196861286325780578">&amp;ทำซ้ำà¸à¸²à¸£à¸¢à¹‰à¸²à¸¢</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ตรวจสอà¸à¹„ฟร์วอลล์à¹à¸¥à¸°à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¹„วรัส<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{ไม่มี}=1{1 à¹à¸­à¸› ($1)}=2{2 à¹à¸­à¸› ($1, $2)}other{# à¹à¸­à¸› ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">à¸à¸²à¸£à¸‚ัดข้อง</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />ลองเรียà¸à¹ƒà¸à¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¹€à¸„รือข่าย<ph name="END_LINK" /></translation>
<translation id="4250680216510889253">ไม่มี</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(ไม่มีà¸à¸·à¹ˆà¸­à¸œà¸¹à¹‰à¹ƒà¸à¹‰)</translation>
<translation id="4300246636397505754">คำà¹à¸™à¸°à¸™à¸³à¸£à¸°à¸”ัà¸à¸à¸™à¸ªà¸¸à¸”</translation>
<translation id="4304224509867189079">เข้าสู่ระà¸à¸</translation>
+<translation id="432290197980158659">เซิร์ฟเวอร์à¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่ไม่ตรงà¸à¸±à¸à¸à¸²à¸£à¸„าดà¸à¸²à¸£à¸“์ที่มีอยู่ à¸à¸²à¸£à¸„าดà¸à¸²à¸£à¸“์เหล่านี้มีอยู่ในà¸à¸²à¸‡à¹€à¸§à¹‡à¸à¹„ซต์ที่มีà¸à¸²à¸£à¸£à¸±à¸à¸©à¸²à¸„วามปลอดภัยสูงเà¸à¸·à¹ˆà¸­à¸›à¸à¸›à¹‰à¸­à¸‡à¸„ุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">à¸à¸²à¸£à¸„้นหาà¸à¸—ความล้มเหลว</translation>
+<translation id="4331708818696583467">ไม่ปลอดภัย</translation>
<translation id="4372948949327679948">ค่า <ph name="VALUE_TYPE" /> ที่คาดไว้</translation>
-<translation id="4377125064752653719">คุณà¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸‚้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่เซิร์ฟเวอร์à¹à¸ˆà¹‰à¸‡à¸¡à¸²à¸–ูà¸à¹€à¸à¸´à¸à¸–อนโดยผู้ออà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡ ซึ่งหมายความว่าข้อมูลรัà¸à¸£à¸­à¸‡à¸”้านความปลอดภัยที่เซิร์ฟเวอร์à¹à¸ˆà¹‰à¸‡à¸¡à¸²à¸™à¸±à¹‰à¸™à¹„ม่สามารถเà¸à¸·à¹ˆà¸­à¸–ือได้ คุณอาจà¸à¸³à¸¥à¸±à¸‡à¸•à¸´à¸”ต่อà¸à¸±à¸à¸„นที่คิดจะโจมตีคุณ</translation>
<translation id="4381091992796011497">à¸à¸·à¹ˆà¸­à¸œà¸¹à¹‰à¹ƒà¸à¹‰:</translation>
<translation id="4394049700291259645">ปิดà¸à¸²à¸£à¹ƒà¸à¹‰à¸‡à¸²à¸™</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> ถึง <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">ผลà¸à¸²à¸£à¸„้นหา</translation>
-<translation id="4424024547088906515">เซิร์ฟเวอร์นี้ไม่สามารถà¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ด้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸° Chrome ไม่เà¸à¸·à¹ˆà¸­à¸–ือใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัย โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> ไม่ยอมรัà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸à¸²à¸£à¹€à¸‚้าสู่ระà¸à¸à¸«à¸£à¸·à¸­à¹„ม่ได้ให้ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¹„ว้</translation>
<translation id="443673843213245140">à¸à¸²à¸£à¹ƒà¸à¹‰à¸à¸£à¹‡à¸­à¸à¸‹à¸µà¸–ูà¸à¸›à¸´à¸”ใà¸à¹‰à¸‡à¸²à¸™ à¹à¸•à¹ˆà¸¡à¸µà¸à¸²à¸£à¸£à¸°à¸à¸¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าà¸à¸£à¹‡à¸­à¸à¸‹à¸µà¸­à¸¢à¹ˆà¸²à¸‡à¸à¸±à¸”เจน</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">คุณเห็นข้อความนี้เนื่องจาà¸à¸¡à¸µà¸à¸²à¸£à¹€à¸›à¸´à¸”ใà¸à¹‰ Google SafeSites</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">รายละเอียด</translation>
<translation id="4558551763791394412">ลองปิดใà¸à¹‰à¸ªà¹ˆà¸§à¸™à¸‚ยาย</translation>
<translation id="4587425331216688090">นำที่อยู่ออà¸à¸ˆà¸²à¸ Chrome ไหม</translation>
+<translation id="4589078953350245614">คุณà¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸‚้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่ไม่ถูà¸à¸•à¹‰à¸­à¸‡ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459">มีà¸à¸²à¸£à¹€à¸‚้ารหัสà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณà¸à¸±à¸ <ph name="DOMAIN" /> ด้วยà¸à¸¸à¸”à¸à¸²à¸£à¹€à¸‚้ารหัสที่ทันสมัย</translation>
<translation id="4594403342090139922">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¸™à¸³à¸­à¸­à¸</translation>
+<translation id="4627442949885028695">ดำเนินà¸à¸²à¸£à¸•à¹ˆà¸­à¸ˆà¸²à¸à¸­à¸¸à¸›à¸à¸£à¸“์อื่น</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">คุณà¸à¸³à¸¥à¸±à¸‡à¸”ูหน้าส่วนขยาย</translation>
-<translation id="467662567472608290">เซิร์ฟเวอร์นี้ไม่สามารถà¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ด้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยมีข้อผิดà¸à¸¥à¸²à¸” โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
-<translation id="4697214168136963651"><ph name="URL" /> ถูà¸à¸à¸¥à¹‡à¸­à¸</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณขัดข้อง</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />เรียà¸à¹ƒà¸à¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¹€à¸„รือข่ายของ Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">à¹à¸à¸¥à¸•à¸Ÿà¸­à¸£à¹Œà¸¡</translation>
<translation id="4744603770635761495">เส้นทางปà¸à¸´à¸à¸±à¸•à¸´à¸à¸²à¸£</translation>
<translation id="4756388243121344051">&amp;ประวัติà¸à¸²à¸£à¹€à¸‚้าà¸à¸¡</translation>
+<translation id="4759238208242260848">ดาวน์โหลด</translation>
<translation id="4764776831041365478">หน้าเว็à¸à¹ƒà¸™ <ph name="URL" /> อาจหยุดให้à¸à¸£à¸´à¸à¸²à¸£à¸à¸±à¹ˆà¸§à¸„ราวหรืออาจถูà¸à¸¢à¹‰à¸²à¸¢à¹„ปยังที่อยู่เว็à¸à¹ƒà¸«à¸¡à¹ˆà¸­à¸¢à¹ˆà¸²à¸‡à¸–าวร</translation>
<translation id="4771973620359291008">มีข้อผิดà¸à¸¥à¸²à¸”ที่ไม่ทราà¸à¹€à¸à¸´à¸”ขึ้น</translation>
<translation id="4782449893814226250">คุณถามผู้ปà¸à¸„รองว่าสามารถเข้าà¸à¸¡à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰à¹„ด้ไหมà¹à¸¥à¹‰à¸§</translation>
<translation id="4800132727771399293">ตรวจสอà¸à¸§à¸±à¸™à¸«à¸¡à¸”อายุà¹à¸¥à¸° CVC à¹à¸¥à¹‰à¸§à¸¥à¸­à¸‡à¸­à¸µà¸à¸„รั้ง</translation>
-<translation id="4807049035289105102">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้ เนื่องจาà¸à¹€à¸§à¹‡à¸à¹„ซต์ดังà¸à¸¥à¹ˆà¸²à¸§à¸ªà¹ˆà¸‡à¸‚้อมูลรัà¸à¸£à¸­à¸‡à¸—ี่เข้ารหัส ซึ่ง Google Chrome ไม่สามารถประมวลผลได้ โดยปà¸à¸•à¸´à¸‚้อผิดà¸à¸¥à¸²à¸”ของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¸à¸¸à¸à¸£à¸¸à¸à¸ˆà¸°à¹€à¸à¸´à¸”ขึ้นเà¸à¸µà¸¢à¸‡à¸à¸±à¹ˆà¸§à¸„ราว หน้านี้จึงอาจใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในภายหลัง</translation>
<translation id="4813512666221746211">ข้อผิดà¸à¸¥à¸²à¸”ของเครือข่าย</translation>
<translation id="4816492930507672669">à¸à¸­à¸”ีà¸à¸±à¸à¸«à¸™à¹‰à¸²</translation>
<translation id="4850886885716139402">มุมมอง</translation>
<translation id="4880827082731008257">ค้นประวัติà¸à¸²à¸£à¹€à¸‚้าà¸à¸¡</translation>
+<translation id="4884656795097055129">à¸à¸—ความอื่นๆ จะปราà¸à¸à¸‚ึ้นเมื่อถึงเวลาที่เหมาะสม</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> à¹à¸¥à¸° <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{à¹à¸¥à¸°à¸«à¸™à¹‰à¸²à¹€à¸§à¹‡à¸à¸­à¸µà¸ 1 หน้า}other{à¹à¸¥à¸°à¸«à¸™à¹‰à¸²à¹€à¸§à¹‡à¸à¸­à¸µà¸ # หน้า}}</translation>
<translation id="4923417429809017348">หน้านี้à¹à¸›à¸¥à¸ˆà¸²à¸à¸ à¸²à¸©à¸²à¸—ี่ไม่รู้จัà¸à¹€à¸›à¹‡à¸™à¸ à¸²à¸©à¸² <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">ต้องระà¸à¸¸</translation>
<translation id="4930497775425430760">คุณเห็นข้อความนี้เนื่องจาà¸à¸•à¹‰à¸­à¸‡à¹ƒà¸«à¹‰à¸œà¸¹à¹‰à¸›à¸à¸„รองอนุมัติà¸à¸²à¸£à¹€à¸‚้าà¸à¸¡à¹€à¸§à¹‡à¸à¹„ซต์ใหม่ในครั้งà¹à¸£à¸à¸‚องคุณ</translation>
<translation id="495170559598752135">à¸à¸²à¸£à¸—ำงาน</translation>
<translation id="4958444002117714549">ขยายรายà¸à¸²à¸£</translation>
+<translation id="4962322354953122629">เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸° Chrome ไม่เà¸à¸·à¹ˆà¸­à¸–ือใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยของเซิร์ฟเวอร์นี้ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911">à¹à¸›à¸¥à¸ˆà¸²à¸ <ph name="ORIGINAL_LANGUAGE" /> เป็น <ph name="TARGET_LANGUAGE" /> หรือไม่</translation>
+<translation id="4989809363548539747">ไม่รองรัà¸à¸›à¸¥à¸±à¹à¸à¸­à¸´à¸™à¸™à¸µà¹‰</translation>
<translation id="5002932099480077015">หาà¸à¹€à¸›à¸´à¸”ใà¸à¹‰ Chrome จะเà¸à¹‡à¸à¸ªà¸³à¹€à¸™à¸²à¸à¸²à¸£à¹Œà¸”ของคุณในอุปà¸à¸£à¸“์นี้เà¸à¸·à¹ˆà¸­à¹ƒà¸«à¹‰à¸à¸²à¸£à¸à¸£à¸­à¸à¸Ÿà¸­à¸£à¹Œà¸¡à¸—ำได้เร็วขึ้น</translation>
<translation id="5019198164206649151">ไม่สามารถจัดเà¸à¹‡à¸à¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¸£à¸°à¸à¸à¹à¸à¹‡à¸„เอนด์อยู่ในสถานะไม่ดี</translation>
<translation id="5023310440958281426">ตรวจสอà¸à¸™à¹‚ยà¸à¸²à¸¢à¸‚องผู้ดูà¹à¸¥à¸£à¸°à¸à¸à¸‚องคุณ</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸ Google à¹à¸›à¸¥à¸ à¸²à¸©à¸²</translation>
<translation id="5040262127954254034">ความเป็นส่วนตัว</translation>
<translation id="5045550434625856497">รหัสผ่านไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
+<translation id="5056549851600133418">à¸à¸—ความสำหรัà¸à¸„ุณ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />ตรวจสอà¸à¸—ี่อยู่à¸à¸£à¹‡à¸­à¸à¸‹à¸µ<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์ไม่สามารถใà¸à¹‰à¹„ด้ในขณะนี้</translation>
<translation id="5089810972385038852">รัà¸</translation>
-<translation id="5094747076828555589">เซิร์ฟเวอร์นี้ไม่สามารถà¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ด้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸° Chromium ไม่เà¸à¸·à¹ˆà¸­à¸–ือใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัย โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="5095208057601539847">จังหวัด</translation>
<translation id="5115563688576182185">(64 à¸à¸´à¸•)</translation>
-<translation id="5122371513570456792">à¸à¸ <ph name="NUMBER_OF_RESULTS" /><ph name="SEARCH_RESULTS" /> รายà¸à¸²à¸£à¸ªà¸³à¸«à¸£à¸±à¸ "<ph name="SEARCH_STRING" />"</translation>
<translation id="5141240743006678641">เข้ารหัสผ่านที่ซิงค์ด้วยข้อมูลรัà¸à¸£à¸­à¸‡ Google ของคุณ</translation>
<translation id="5145883236150621069">มีรหัสข้อผิดà¸à¸¥à¸²à¸”ในà¸à¸²à¸£à¸•à¸­à¸à¸à¸¥à¸±à¸à¸™à¹‚ยà¸à¸²à¸¢</translation>
<translation id="5171045022955879922">ค้นหาหรือà¸à¸´à¸¡à¸à¹Œ URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">à¹à¸–à¸à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸</translation>
<translation id="5199729219167945352">à¸à¸²à¸£à¸—ดลอง</translation>
<translation id="5251803541071282808">ระà¸à¸à¸„ลาวด์</translation>
+<translation id="5277279256032773186">หาà¸à¹ƒà¸à¹‰ Chrome ที่ทำงาน ธุรà¸à¸´à¸ˆà¸ªà¸²à¸¡à¸²à¸£à¸–จัดà¸à¸²à¸£à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome ให้à¸à¸™à¸±à¸à¸‡à¸²à¸™à¸‚องตนได้ เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡</translation>
<translation id="5299298092464848405">ข้อผิดà¸à¸¥à¸²à¸”ในà¸à¸²à¸£à¹à¸¢à¸à¸§à¸´à¹€à¸„ราะห์นโยà¸à¸²à¸¢</translation>
<translation id="5300589172476337783">à¹à¸ªà¸”ง</translation>
<translation id="5308689395849655368">à¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™à¸‚้อขัดข้องถูà¸à¸›à¸´à¸”ใà¸à¹‰à¸‡à¸²à¸™</translation>
<translation id="5317780077021120954">à¸à¸±à¸™à¸—ึà¸</translation>
<translation id="5327248766486351172">à¸à¸·à¹ˆà¸­</translation>
+<translation id="5359637492792381994">เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยของเซิร์ฟเวอร์ใà¸à¹‰à¹„ม่ได้ในขณะนี้ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">ไม่สามารถจัดเà¸à¹‡à¸à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่านโยà¸à¸²à¸¢</translation>
-<translation id="540969355065856584">เซิร์ฟเวอร์นี้ไม่สามารถà¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ด้ว่าเป็น <ph name="DOMAIN" /> เนื่องจาà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยไม่สามารถใà¸à¹‰à¹„ด้ในขณะนี้ ซึ่งอาจเป็นเà¸à¸£à¸²à¸°à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าที่ไม่ถูà¸à¸•à¹‰à¸­à¸‡à¸«à¸£à¸·à¸­à¸¡à¸µà¸œà¸¹à¹‰à¹‚จมตีที่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="5421136146218899937">ล้างข้อมูลà¸à¸²à¸£à¸—่องเว็à¸...</translation>
<translation id="5430298929874300616">นำà¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸­à¸­à¸</translation>
<translation id="5431657950005405462">ไม่à¸à¸à¹„ฟล์ของคุณ</translation>
<translation id="5435775191620395718">à¸à¸³à¸¥à¸±à¸‡à¹à¸ªà¸”งประวัติà¸à¸²à¸£à¹€à¸‚้าà¸à¸¡à¸ˆà¸²à¸à¸­à¸¸à¸›à¸à¸£à¸“์นี้ <ph name="BEGIN_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">à¸à¸²à¸£à¹à¸™à¸°à¸™à¸³à¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸—ี่เหมาะสมสำหรัà¸à¸„ุณปิดอยู่ เà¸à¸£à¸²à¸°à¸¡à¸µà¸à¸²à¸£à¸›à¸à¸›à¹‰à¸­à¸‡à¸‚้อมูลที่ซิงค์ด้วยรหัสผ่านที่à¸à¸³à¸«à¸™à¸”เอง</translation>
<translation id="5439770059721715174">ข้อผิดà¸à¸¥à¸²à¸”ในà¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸à¸£à¸¹à¸›à¹à¸à¸à¸—ี่ "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">ไม่à¸à¸à¸«à¸™à¹‰à¸² <ph name="HOST_NAME" /> นี้</translation>
<translation id="5455374756549232013">เวลาà¸à¸±à¸™à¸—ึà¸à¸‚องนโยà¸à¸²à¸¢à¹„ม่เหมาะสม</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">คุณต้องà¸à¸²à¸£à¸­à¸­à¸à¸ˆà¸²à¸à¹€à¸§à¹‡à¸à¹„ซต์นี้ใà¸à¹ˆà¹„หม</translation>
<translation id="5629630648637658800">ไม่สามารถโหลดà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่านโยà¸à¸²à¸¢</translation>
<translation id="5631439013527180824">โทเค็นà¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£à¸­à¸¸à¸›à¸à¸£à¸“์ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
-<translation id="5650551054760837876">ไม่à¸à¸à¸œà¸¥à¸¥à¸±à¸à¸˜à¹Œà¸à¸²à¸£à¸„้นหา</translation>
<translation id="5677928146339483299">ถูà¸à¸à¸¥à¹‡à¸­à¸</translation>
<translation id="5710435578057952990">ข้อมูลประจำตัวของเว็à¸à¹„ซต์นี้ยังไม่ได้รัà¸à¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™</translation>
<translation id="5720705177508910913">ผู้ใà¸à¹‰à¸›à¸±à¸ˆà¸ˆà¸¸à¸à¸±à¸™</translation>
+<translation id="572328651809341494">à¹à¸—็à¸à¸¥à¹ˆà¸²à¸ªà¸¸à¸”</translation>
<translation id="5784606427469807560">เà¸à¸´à¸”ปัà¸à¸«à¸²à¹ƒà¸™à¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸à¸±à¸•à¸£à¸‚องคุณ โปรดตรวจสอà¸à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸­à¸´à¸™à¹€à¸—อร์เน็ตà¹à¸¥à¸°à¸¥à¸­à¸‡à¸­à¸µà¸à¸„รั้ง</translation>
<translation id="5785756445106461925">นอà¸à¸ˆà¸²à¸à¸™à¸µà¹‰ หน้านี้ประà¸à¸­à¸à¸”้วยทรัà¸à¸¢à¸²à¸à¸£à¸­à¸·à¹ˆà¸™à¹† ซึ่งไม่ปลอดภัย ผู้อื่นสามารถดูทรัà¸à¸¢à¸²à¸à¸£à¹€à¸«à¸¥à¹ˆà¸²à¸™à¸µà¹‰à¸‚ณะถ่ายโอน à¹à¸¥à¸°à¸œà¸¹à¹‰à¸à¸¸à¸à¸£à¸¸à¸à¸ªà¸²à¸¡à¸²à¸£à¸–à¹à¸à¹‰à¹„ขเà¸à¸·à¹ˆà¸­à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸£à¸¹à¸›à¸¥à¸±à¸à¸©à¸“์ของหน้าได้</translation>
+<translation id="5786044859038896871">คุณต้องà¸à¸²à¸£à¸à¸£à¸­à¸à¸‚้อมูลà¸à¸±à¸•à¸£à¹„หม</translation>
+<translation id="5803412860119678065">คุณต้องà¸à¸²à¸£à¸à¸£à¸­à¸à¸‚้อมูล <ph name="CARD_DETAIL" /> ไหม</translation>
<translation id="5810442152076338065">มีà¸à¸²à¸£à¹€à¸‚้ารหัสà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณà¸à¸±à¸ <ph name="DOMAIN" /> ด้วยà¸à¸¸à¸”à¸à¸²à¸£à¹€à¸‚้ารหัสที่ล้าสมัยà¹à¸¥à¹‰à¸§</translation>
<translation id="5813119285467412249">&amp;ทำซ้ำà¸à¸²à¸£à¹€à¸à¸´à¹ˆà¸¡</translation>
+<translation id="5814352347845180253">คุณอาจสูà¸à¹€à¸ªà¸µà¸¢à¸ªà¸´à¸—ธิ์à¸à¸²à¸£à¹€à¸‚้าถึงเนื้อหาระดัà¸à¸à¸£à¸µà¹€à¸¡à¸µà¸¢à¸¡à¸ˆà¸²à¸ <ph name="SITE" /> à¹à¸¥à¸°à¹€à¸§à¹‡à¸à¹„ซต์อื่นๆ à¸à¸²à¸‡à¹à¸«à¹ˆà¸‡</translation>
+<translation id="5843436854350372569">คุณà¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸‚้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่มีคีย์ที่ไม่รัดà¸à¸¸à¸¡ ผู้โจมตีอาจทำให้คีย์ส่วนตัวเสียหายไปà¹à¸¥à¹‰à¸§à¹à¸¥à¸°à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸™à¸µà¹‰à¸­à¸²à¸ˆà¹„ม่ใà¸à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸—ี่คุณคิด (คุณอาจà¸à¸³à¸¥à¸±à¸‡à¸•à¸´à¸”ต่อà¸à¸±à¸à¸œà¸¹à¹‰à¹‚จมตี) <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">คุณเห็นข้อความนี้เนื่องจาà¸à¸œà¸¹à¹‰à¸ˆà¸±à¸”à¸à¸²à¸£à¸à¸¥à¹‡à¸­à¸à¹€à¸§à¹‡à¸à¹„ซต์นี้</translation>
<translation id="5857090052475505287">โฟลเดอร์ใหม่</translation>
<translation id="5869405914158311789">ไม่สามารถเข้าถึงเว็à¸à¹„ซต์นี้</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">คำà¹à¸™à¸°à¸™à¸³à¸£à¸°à¸”ัà¸à¸à¸™à¸ªà¸¸à¸”</translation>
<translation id="59107663811261420">Google Payments ไม่สนัà¸à¸ªà¸™à¸¸à¸™à¸à¸±à¸•à¸£à¸›à¸£à¸°à¹€à¸ à¸—นี้สำหรัà¸à¸œà¸¹à¹‰à¸‚ายรายนี้ โปรดเลือà¸à¸à¸±à¸•à¸£à¸­à¸·à¹ˆà¸™</translation>
<translation id="59174027418879706">เปิดใà¸à¹‰à¸‡à¸²à¸™à¹à¸¥à¹‰à¸§</translation>
+<translation id="5926846154125914413">คุณอาจสูà¸à¹€à¸ªà¸µà¸¢à¸ªà¸´à¸—ธิ์à¸à¸²à¸£à¹€à¸‚้าถึงเนื้อหาระดัà¸à¸à¸£à¸µà¹€à¸¡à¸µà¸¢à¸¡à¸ˆà¸²à¸à¹€à¸§à¹‡à¸à¹„ซต์à¸à¸²à¸‡à¹à¸«à¹ˆà¸‡</translation>
<translation id="5966707198760109579">สัปดาห์</translation>
<translation id="5967867314010545767">ลà¸à¸ˆà¸²à¸à¸›à¸£à¸°à¸§à¸±à¸•à¸´à¸à¸²à¸£à¹€à¸‚้าà¸à¸¡</translation>
<translation id="5975083100439434680">ย่อ</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">อัตโนมัติ</translation>
<translation id="6042308850641462728">เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡</translation>
<translation id="6060685159320643512">ระวัง à¸à¸²à¸£à¸—ดลองนี้อาจเป็นอันตราย</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{ไม่มี}=1{1}other{#}}</translation>
<translation id="6146055958333702838">ตรวจสายเคเà¸à¸´à¸¥à¹à¸¥à¸°à¸£à¸µà¸à¸¹à¸•à¹€à¸£à¸²à¹€à¸•à¸­à¸£à¹Œ โมเด็ม หรืออุปà¸à¸£à¸“์เครือข่ายอื่น
ที่คุณอาจใà¸à¹‰à¸‡à¸²à¸™à¸­à¸¢à¸¹à¹ˆ</translation>
<translation id="614940544461990577">ลอง:</translation>
<translation id="6150607114729249911">อà¹à¸°! คุณต้องถามผู้ปà¸à¸„รองว่าสามารถเข้าà¸à¸¡à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰à¹„ด้ไหม</translation>
<translation id="6151417162996330722">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸¡à¸µà¸£à¸°à¸¢à¸°à¹€à¸§à¸¥à¸²à¸—ี่สามารถใà¸à¹‰à¹„ด้นานเà¸à¸´à¸™à¹„ป</translation>
-<translation id="6154808779448689242">โทเค็นนโยà¸à¸²à¸¢à¸—ี่ส่งà¸à¸¥à¸±à¸à¹„ม่ตรงà¸à¸±à¸à¹‚ทเค็นปัจจุà¸à¸±à¸™</translation>
<translation id="6165508094623778733">เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡</translation>
<translation id="6203231073485539293">ตรวจสอà¸à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸­à¸´à¸™à¹€à¸—อร์เน็ต</translation>
<translation id="6218753634732582820">ต้องà¸à¸²à¸£à¸™à¸³à¸—ี่อยู่ออà¸à¸ˆà¸²à¸ Chromium ใà¸à¹ˆà¹„หม</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">ลองปิดà¸à¸²à¸£à¸„าดคะเนเครือข่าย</translation>
<translation id="6337534724793800597">à¸à¸£à¸­à¸‡à¸™à¹‚ยà¸à¸²à¸¢à¸•à¸²à¸¡à¸à¸·à¹ˆà¸­</translation>
<translation id="6342069812937806050">เà¸à¸´à¹ˆà¸‡à¹€à¸ªà¸£à¹‡à¸ˆ</translation>
+<translation id="6345221851280129312">ไม่ทราà¸à¸‚นาด</translation>
<translation id="6355080345576803305">à¸à¸²à¸£à¸¥à¸à¸¥à¹‰à¸²à¸‡à¹€à¸‹à¸ªà¸à¸±à¸™à¸ªà¸²à¸˜à¸²à¸£à¸“ะ</translation>
<translation id="6358450015545214790">นี่หมายถึงอะไร</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{อีภ1 คำà¹à¸™à¸°à¸™à¸³}other{อีภ# คำà¹à¸™à¸°à¸™à¸³}}</translation>
<translation id="6387478394221739770">หาà¸à¸ªà¸™à¹ƒà¸ˆà¹ƒà¸™à¸„ุณลัà¸à¸©à¸“ะสุดเจ๋งของ Chrome ใหม่ ลองใà¸à¹‰à¹€à¸§à¸­à¸£à¹Œà¸à¸±à¸™à¹€à¸à¸•à¹‰à¸²à¸‚องเราที่ chrome.com/beta</translation>
-<translation id="641480858134062906"><ph name="URL" /> ไม่สามารถโหลดได้</translation>
+<translation id="6389758589412724634">Chromium หน่วยความจำเต็มเมื่อà¸à¸¢à¸²à¸¢à¸²à¸¡à¹à¸ªà¸”งหน้าเว็à¸à¸™à¸µà¹‰</translation>
+<translation id="6416403317709441254">คุณไม่สามารถเข้าà¸à¸¡ <ph name="SITE" /> ได้ในขณะนี้ เนื่องจาà¸à¹€à¸§à¹‡à¸à¹„ซต์ส่งข้อมูลรัà¸à¸£à¸­à¸‡à¸—ี่ถูà¸à¹à¸›à¸¥à¸‡à¸‹à¸¶à¹ˆà¸‡ Chromium ไม่สามารถดำเนินà¸à¸²à¸£à¹„ด้ โดยปà¸à¸•à¸´à¸‚้อผิดà¸à¸¥à¸²à¸”ของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¹‚จมตีจะเà¸à¸´à¸”ขึ้นเà¸à¸µà¸¢à¸‡à¸à¸±à¹ˆà¸§à¸„ราว หน้านี้จึงอาจจะใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในภายหลัง <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">ไม่สามารถตรวจสอà¸à¸§à¹ˆà¸²à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸–ูà¸à¹€à¸à¸´à¸à¸–อนหรือไม่</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ปà¸à¸´à¹€à¸ªà¸˜à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­</translation>
<translation id="6445051938772793705">ประเทศ</translation>
<translation id="6451458296329894277">ยืนยันà¸à¸²à¸£à¸ªà¹ˆà¸‡à¹à¸à¸à¸Ÿà¸­à¸£à¹Œà¸¡à¸­à¸µà¸à¸„รั้ง</translation>
<translation id="6458467102616083041">ไม่ใà¸à¹‰à¸‡à¸²à¸™à¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¸à¸²à¸£à¸„้นหาเริ่มต้นถูà¸à¸›à¸´à¸”ใà¸à¹‰à¸‡à¸²à¸™à¸•à¸²à¸¡à¸™à¹‚ยà¸à¸²à¸¢</translation>
+<translation id="6462969404041126431">เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยของเซิร์ฟเวอร์อาจถูà¸à¹€à¸à¸´à¸à¸–อนไปà¹à¸¥à¹‰à¸§ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">นโยà¸à¸²à¸¢à¸­à¸¸à¸›à¸à¸£à¸“์</translation>
<translation id="6489534406876378309">เริ่มอัปโหลดข้อขัดข้อง</translation>
<translation id="6529602333819889595">&amp;ทำซ้ำà¸à¸²à¸£à¸™à¸³à¸­à¸­à¸</translation>
+<translation id="6534179046333460208">คำà¹à¸™à¸°à¸™à¸³ Physical Web</translation>
<translation id="6550675742724504774">ตัวเลือà¸</translation>
+<translation id="6593753688552673085">น้อยà¸à¸§à¹ˆà¸² <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">ตัวเลือà¸à¸à¸²à¸£à¹€à¸‚้ารหัส</translation>
<translation id="662080504995468778">อยู่ต่อ</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> ค้นหา</translation>
-<translation id="6634865548447745291">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้ เนื่องจาà¸<ph name="BEGIN_LINK" />ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸™à¸µà¹‰à¸–ูà¸à¹€à¸à¸´à¸à¸–อนà¹à¸¥à¹‰à¸§<ph name="END_LINK" /> โดยปà¸à¸•à¸´à¸‚้อผิดà¸à¸¥à¸²à¸”ของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¸à¸¸à¸à¸£à¸¸à¸à¸ˆà¸°à¹€à¸à¸´à¸”ขึ้นเà¸à¸µà¸¢à¸‡à¸à¸±à¹ˆà¸§à¸„ราว หน้านี้จึงน่าจะใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในภายหลัง</translation>
<translation id="6644283850729428850">นโยà¸à¸²à¸¢à¸™à¸µà¹‰à¸–ูà¸à¸¢à¸à¹€à¸¥à¸´à¸à¹à¸¥à¹‰à¸§</translation>
+<translation id="6652240803263749613">เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¸£à¸°à¸à¸à¸›à¸à¸´à¸à¸±à¸•à¸´à¸à¸²à¸£à¸‚องคอมà¸à¸´à¸§à¹€à¸•à¸­à¸£à¹Œà¹„ม่เà¸à¸·à¹ˆà¸­à¸–ือใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยของเซิร์ฟเวอร์นี้ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">à¹à¸à¹‰à¹„ขโฟลเดอร์</translation>
<translation id="6660210980321319655">รายงานอัตโนมัติเมื่อ<ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">ต้องà¸à¸²à¸£à¸™à¸³à¸„ำà¹à¸™à¸°à¸™à¸³à¸ªà¸³à¸«à¸£à¸±à¸à¹à¸à¸à¸Ÿà¸­à¸£à¹Œà¸¡à¸­à¸­à¸à¸ˆà¸²à¸ Chromium ใà¸à¹ˆà¹„หม</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">à¸à¹ˆà¸­à¸™à¸«à¸™à¹‰à¸²</translation>
<translation id="6710594484020273272">&lt;à¸à¸´à¸¡à¸à¹Œà¸‚้อความค้นหา&gt;</translation>
<translation id="6711464428925977395">à¸à¸£à¹‡à¸­à¸à¸‹à¸µà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¸œà¸´à¸”ปà¸à¸•à¸´à¸«à¸£à¸·à¸­à¸—ี่อยู่ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{ไม่มี}=1{1 รายà¸à¸²à¸£}other{# รายà¸à¸²à¸£}}</translation>
<translation id="674375294223700098">ข้อผิดà¸à¸¥à¸²à¸”ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์ที่ไม่รู้จัà¸</translation>
<translation id="6753269504797312559">ค่านโยà¸à¸²à¸¢</translation>
<translation id="6757797048963528358">อุปà¸à¸£à¸“์ของคุณเข้าสู่โหมดสลีปà¹à¸¥à¹‰à¸§</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">ระดัà¸à¸™à¹‚ยà¸à¸²à¸¢à¹„ม่ได้รัà¸à¸à¸²à¸£à¸ªà¸™à¸±à¸à¸ªà¸™à¸¸à¸™</translation>
<translation id="6895330447102777224">à¸à¸±à¸•à¸£à¸‚องคุณได้รัà¸à¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¹à¸¥à¹‰à¸§</translation>
<translation id="6897140037006041989">User agent</translation>
-<translation id="6903907808598579934">เปิดà¸à¸²à¸£à¸‹à¸´à¸‡à¸„์</translation>
<translation id="6915804003454593391">ผู้ใà¸à¹‰:</translation>
<translation id="6957887021205513506">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์น่าจะเป็นของปลอม</translation>
<translation id="6965382102122355670">ตà¸à¸¥à¸‡</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">เขต</translation>
<translation id="6973656660372572881">มีà¸à¸²à¸£à¸£à¸°à¸à¸¸à¸—ั้งà¸à¸£à¹‡à¸­à¸à¸‹à¸µà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸à¸à¸„งที่à¹à¸¥à¸° URL สคริปต์ .pac ไว้</translation>
<translation id="6989763994942163495">à¹à¸ªà¸”งà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าขั้นสูง...</translation>
+<translation id="7000990526846637657">ไม่à¸à¸à¸‚้อมูลประวัติà¸à¸²à¸£à¹€à¸‚้าà¸à¸¡</translation>
+<translation id="7009986207543992532">คุณà¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸‚้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่มีระยะเวลาà¸à¸²à¸£à¹ƒà¸à¹‰à¸‡à¸²à¸™à¹„ด้นานเà¸à¸´à¸™à¸à¸§à¹ˆà¸²à¸ˆà¸°à¹€à¸à¸·à¹ˆà¸­à¸–ือได้ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">à¸à¸±à¸à¸à¸µ Google ของคุณอาจมีประวัติà¸à¸²à¸£à¸—่องเว็à¸à¹ƒà¸™à¸£à¸¹à¸›à¹à¸à¸à¸­à¸·à¹ˆà¸™à¹† ที่ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">รหัสผ่าน</translation>
-<translation id="7050187094878475250">คุณà¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸‚้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹„ด้à¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่มีระยะเวลาที่สามารถใà¸à¹‰à¹„ด้นานเà¸à¸´à¸™à¸à¸§à¹ˆà¸²à¸—ี่จะเà¸à¸·à¹ˆà¸­à¸–ือได้</translation>
<translation id="7087282848513945231">อำเภอ</translation>
<translation id="7088615885725309056">เà¸à¹ˆà¸²à¸à¸§à¹ˆà¸²</translation>
<translation id="7090678807593890770">ค้นหา <ph name="LINK" /> จาภGoogle</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">คุณเห็นข้อความนี้เนื่องจาà¸à¸•à¹‰à¸­à¸‡à¹ƒà¸«à¹‰à¸œà¸¹à¹‰à¸ˆà¸±à¸”à¸à¸²à¸£à¸­à¸™à¸¸à¸¡à¸±à¸•à¸´à¸à¸²à¸£à¹€à¸‚้าà¸à¸¡à¹€à¸§à¹‡à¸à¹„ซต์ใหม่ในครั้งà¹à¸£à¸à¸‚องคุณ</translation>
<translation id="724975217298816891">ป้อนวันหมดอายุà¹à¸¥à¸° CVC สำหรัภ<ph name="CREDIT_CARD" /> เà¸à¸·à¹ˆà¸­à¸­à¸±à¸›à¹€à¸”ตรายละเอียดของà¸à¸±à¸•à¸£ เมื่อคุณยืนยันà¹à¸¥à¹‰à¸§ รายละเอียดà¸à¸±à¸•à¸£à¸‚องคุณจะà¹à¸à¸£à¹Œà¸à¸±à¸à¹€à¸§à¹‡à¸à¹„ซต์นี้</translation>
<translation id="725866823122871198">ไม่สามารถเริ่มà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§à¸à¸±à¸ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ได้เนื่องจาà¸à¸§à¸±à¸™à¸—ี่à¹à¸¥à¸°à¹€à¸§à¸¥à¸²à¸‚องคอมà¸à¸´à¸§à¹€à¸•à¸­à¸£à¹Œ (<ph name="DATE_AND_TIME" />) ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
-<translation id="7265986070661382626">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้ เนื่องจาà¸à¹€à¸§à¹‡à¸à¹„ซต์<ph name="BEGIN_LINK" />ใà¸à¹‰à¸à¸²à¸£à¸•à¸£à¸¶à¸‡à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡<ph name="END_LINK" /> โดยปà¸à¸•à¸´à¸‚้อผิดà¸à¸¥à¸²à¸”ของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¸à¸¸à¸à¸£à¸¸à¸à¸ˆà¸°à¹€à¸à¸´à¸”ขึ้นเà¸à¸µà¸¢à¸‡à¸à¸±à¹ˆà¸§à¸„ราว หน้านี้จึงน่าจะใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในภายหลัง</translation>
<translation id="7269802741830436641">หน้าเว็à¸à¸™à¸µà¹‰à¸¡à¸µà¸à¸²à¸£à¸§à¸™à¸£à¸­à¸à¹€à¸¡à¸·à¹ˆà¸­à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹€à¸ªà¹‰à¸™à¸—าง</translation>
<translation id="7275334191706090484">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸—ี่มีà¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£</translation>
<translation id="7298195798382681320">à¹à¸™à¸°à¸™à¸³</translation>
-<translation id="7301833672208172928">เปิดà¸à¸²à¸£à¸‹à¸´à¸‡à¸„์ประวัติà¸à¸²à¸£à¹€à¸‚้าà¸à¸¡</translation>
+<translation id="7309308571273880165">รายงานข้อขัดข้องเมื่อ <ph name="CRASH_TIME" /> (ผู้ใà¸à¹‰à¸‚อà¸à¸²à¸£à¸­à¸±à¸›à¹‚หลด ยังไม่ได้อัปโหลด)</translation>
<translation id="7334320624316649418">&amp;ทำซ้ำà¸à¸²à¸£à¸ˆà¸±à¸”ลำดัà¸à¹ƒà¸«à¸¡à¹ˆ</translation>
<translation id="733923710415886693">ไม่มีà¸à¸²à¸£à¹€à¸›à¸´à¸”เผยใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์ผ่านความโปร่งใสของใà¸à¸£à¸±à¸à¸£à¸­à¸‡</translation>
+<translation id="7351800657706554155">คุณไม่สามารถเข้าà¸à¸¡ <ph name="SITE" /> ได้ในขณะนี้ เนื่องจาà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเว็à¸à¹„ซต์ถูà¸à¹€à¸à¸´à¸à¸–อนà¹à¸¥à¹‰à¸§ โดยปà¸à¸•à¸´à¸‚้อผิดà¸à¸¥à¸²à¸”ของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¹‚จมตีจะเà¸à¸´à¸”ขึ้นเà¸à¸µà¸¢à¸‡à¸à¸±à¹ˆà¸§à¸„ราว หน้านี้จึงอาจจะใà¸à¹‰à¸‡à¸²à¸™à¹„ด้ในภายหลัง <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">à¸à¸£à¸£à¸—ัดคำสั่ง </translation>
<translation id="7372973238305370288">ผลà¸à¸²à¸£à¸„้นหา</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">à¸à¸³à¸¥à¸±à¸‡à¸¢à¸·à¸™à¸¢à¸±à¸™à¸à¸±à¸•à¸£</translation>
<translation id="7481312909269577407">ส่งต่อ</translation>
<translation id="7485870689360869515">ไม่à¸à¸à¸‚้อมูล</translation>
+<translation id="7508255263130623398">รหัสอุปà¸à¸£à¸“์นโยà¸à¸²à¸¢à¸—ี่ส่งà¸à¸¥à¸±à¸à¸§à¹ˆà¸²à¸‡à¹€à¸›à¸¥à¹ˆà¸²à¸«à¸£à¸·à¸­à¹„ม่ตรงà¸à¸±à¸à¸£à¸«à¸±à¸ªà¸­à¸¸à¸›à¸à¸£à¸“์ปัจจุà¸à¸±à¸™</translation>
<translation id="7514365320538308">ดาวน์โหลด</translation>
<translation id="7518003948725431193">ไม่à¸à¸à¸«à¸™à¹‰à¸²à¹€à¸§à¹‡à¸à¸ªà¸³à¸«à¸£à¸±à¸à¸—ี่อยู่เว็à¸: <ph name="URL" /></translation>
<translation id="7537536606612762813">จำเป็น</translation>
<translation id="7542995811387359312">à¸à¸²à¸£à¸›à¹‰à¸­à¸™à¸«à¸¡à¸²à¸¢à¹€à¸¥à¸‚à¸à¸±à¸•à¸£à¹€à¸„รดิตอัตโนมัติถูà¸à¸›à¸´à¸”ใà¸à¹‰à¸‡à¸²à¸™à¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¸Ÿà¸­à¸£à¹Œà¸¡à¸™à¸µà¹‰à¹„ม่ได้ใà¸à¹‰à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸—ี่ปลอดภัย</translation>
<translation id="7549584377607005141">หน้าเว็à¸à¸™à¸µà¹‰à¸•à¹‰à¸­à¸‡à¹ƒà¸à¹‰à¸‚้อมูลที่คุณป้อนà¸à¹ˆà¸­à¸™à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰à¹€à¸à¸·à¹ˆà¸­à¹ƒà¸«à¹‰à¹à¸ªà¸”งได้อย่างถูà¸à¸•à¹‰à¸­à¸‡ คุณสามารถส่งข้อมูลนี้ได้อีà¸à¸„รั้ง à¹à¸•à¹ˆà¸à¸²à¸£à¸—ำเà¸à¹ˆà¸™à¸™à¸±à¹‰à¸™à¸ˆà¸°à¹€à¸›à¹‡à¸™à¸à¸²à¸£à¸—ำสิ่งที่หน้าเว็à¸à¸™à¸µà¹‰à¹€à¸„ยดำเนินà¸à¸²à¸£à¸‹à¹‰à¸³à¸­à¸µà¸à¸„รั้ง</translation>
<translation id="7554791636758816595">à¹à¸—็à¸à¹ƒà¸«à¸¡à¹ˆ</translation>
-<translation id="7567204685887185387">เซิร์ฟเวอร์นี้ไม่สามารถà¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ด้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¸­à¸²à¸ˆà¸¡à¸µà¸à¸²à¸£à¸­à¸­à¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยปลอม โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้à¸à¸¸à¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="7568593326407688803">หน้าเว็à¸à¸™à¸µà¹‰à¹€à¸›à¹‡à¸™<ph name="ORIGINAL_LANGUAGE" />คุณต้องà¸à¸²à¸£à¹à¸›à¸¥à¸«à¸£à¸·à¸­à¹„ม่</translation>
<translation id="7569952961197462199">นำà¸à¸±à¸•à¸£à¹€à¸„รดิตออà¸à¸ˆà¸²à¸ Chrome ไหม</translation>
<translation id="7578104083680115302">à¸à¸³à¸£à¸°à¹€à¸‡à¸´à¸™à¸à¸™à¹€à¸§à¹‡à¸à¹„ซต์à¹à¸¥à¸°à¹à¸­à¸›à¹ƒà¸™à¸­à¸¸à¸›à¸à¸£à¸“์ต่างๆ ได้อย่างรวดเร็วด้วยà¸à¸±à¸•à¸£à¸—ี่คุณได้à¸à¸±à¸™à¸—ึà¸à¹„ว้à¸à¸±à¸ Google</translation>
+<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์ละเมิดข้อà¸à¸³à¸«à¸™à¸”à¸à¸·à¹ˆà¸­</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ไม่สามารถดำเนินà¸à¸²à¸£à¸à¸±à¸à¸„ำขอนี้ในขณะนี้</translation>
<translation id="7600965453749440009">ไม่ต้องà¹à¸›à¸¥à¸ à¸²à¸©à¸²<ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">ต้องà¸à¸²à¸£à¸™à¸³à¸à¸±à¸•à¸£à¹€à¸„รดิตออà¸à¸ˆà¸²à¸ Chromium ใà¸à¹ˆà¹„หม</translation>
<translation id="765676359832457558">ซ่อนà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าขั้นสูง...</translation>
<translation id="7658239707568436148">ยà¸à¹€à¸¥à¸´à¸</translation>
+<translation id="7667346355482952095">โทเค็นนโยà¸à¸²à¸¢à¸—ี่ส่งà¸à¸¥à¸±à¸à¸§à¹ˆà¸²à¸‡à¹€à¸›à¸¥à¹ˆà¸²à¸«à¸£à¸·à¸­à¹„ม่ตรงà¸à¸±à¸à¹‚ทเค็นปัจจุà¸à¸±à¸™</translation>
<translation id="7668654391829183341">อุปà¸à¸£à¸“์ที่ไม่รู้จัà¸</translation>
<translation id="7674629440242451245">หาà¸à¸ªà¸™à¹ƒà¸ˆà¹ƒà¸™à¸„ุณลัà¸à¸©à¸“ะใหม่ๆ สุดเจ๋งของ Chrome ลองใà¸à¹‰à¹€à¸§à¸­à¸£à¹Œà¸à¸±à¸™à¸—ี่à¸à¸³à¸¥à¸±à¸‡à¸à¸±à¸’นาของเราที่ chrome.com/dev</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ไปยัง <ph name="SITE" /> (ไม่ปลอดภัย)<ph name="END_LINK" /></translation>
@@ -577,25 +612,26 @@
<translation id="780301667611848630">ไม่ ขอà¸à¸„ุณ</translation>
<translation id="7805768142964895445">สถานะ</translation>
<translation id="7813600968533626083">นำคำà¹à¸™à¸°à¸™à¸³à¸ªà¸³à¸«à¸£à¸±à¸à¹à¸à¸à¸Ÿà¸­à¸£à¹Œà¸¡à¸­à¸­à¸à¸ˆà¸²à¸ Chrome ไหม</translation>
+<translation id="7815407501681723534">à¸à¸<ph name="SEARCH_RESULTS" /> <ph name="NUMBER_OF_RESULTS" /> รายà¸à¸²à¸£à¸ªà¸³à¸«à¸£à¸±à¸ "<ph name="SEARCH_STRING" />"</translation>
<translation id="785549533363645510">อย่างไรà¸à¹‡à¸•à¸²à¸¡ ระà¸à¸à¸¢à¸±à¸‡à¸¡à¸­à¸‡à¹€à¸«à¹‡à¸™à¸„ุณ à¸à¸²à¸£à¹€à¸‚้าสู่โหมดไม่ระà¸à¸¸à¸•à¸±à¸§à¸•à¸™à¹„ม่ได้เป็นà¸à¸²à¸£à¸‹à¹ˆà¸­à¸™à¸à¸²à¸£à¸—่องเว็à¸à¸ˆà¸²à¸à¸™à¸²à¸¢à¸ˆà¹‰à¸²à¸‡à¸‚องคุณ ผู้ให้à¸à¸£à¸´à¸à¸²à¸£à¸­à¸´à¸™à¹€à¸—อร์เน็ต หรือเว็à¸à¹„ซต์ที่คุณเข้าà¸à¸¡</translation>
<translation id="7887683347370398519">ตรวจสอภCVC à¹à¸¥à¸°à¸¥à¸­à¸‡à¸­à¸µà¸à¸„รั้ง</translation>
<translation id="7894616681410591072">อà¹à¸°! คุณต้องได้รัà¸à¸­à¸™à¸¸à¸à¸²à¸•à¸ˆà¸²à¸ <ph name="NAME" /> เà¸à¸·à¹ˆà¸­à¹€à¸‚้าถึงหน้านี้</translation>
-<translation id="790025292736025802">ไม่à¸à¸ <ph name="URL" /></translation>
<translation id="7912024687060120840">ในโฟลเดอร์:</translation>
<translation id="7920092496846849526">คุณได้ถามผู้ปà¸à¸„รองà¹à¸¥à¹‰à¸§à¸§à¹ˆà¸²à¸ªà¸²à¸¡à¸²à¸£à¸–เข้าà¸à¸¡à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰à¹„ด้ไหม</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7938958445268990899">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์ยังไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="7951415247503192394">(32 à¸à¸´à¸•)</translation>
<translation id="7956713633345437162">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸à¸™à¸¡à¸·à¸­à¸–ือ</translation>
-<translation id="7961015016161918242">ไม่เคย</translation>
+<translation id="7961015016161918242">ไม่ต้องเลย</translation>
<translation id="7962083544045318153">รหัสข้อขัดข้อง <ph name="CRASH_LOCAL_ID" /></translation>
<translation id="7983301409776629893">à¹à¸›à¸¥ <ph name="ORIGINAL_LANGUAGE" /> เป็น <ph name="TARGET_LANGUAGE" /> เสมอ</translation>
<translation id="7995512525968007366">ไม่ได้ระà¸à¸¸</translation>
<translation id="8012647001091218357">เราไม่สามารถติดต่อผู้ปà¸à¸„รองของคุณได้ในขณะนี้ โปรดลองอีà¸à¸„รั้ง</translation>
<translation id="8034522405403831421">หน้าเว็à¸à¸™à¸µà¹‰à¸­à¸¢à¸¹à¹ˆà¹ƒà¸™à¸ à¸²à¸©à¸²<ph name="SOURCE_LANGUAGE" /> ต้องà¸à¸²à¸£à¹à¸›à¸¥à¹€à¸›à¹‡à¸™à¸ à¸²à¸©à¸²<ph name="TARGET_LANGUAGE" />ไหม</translation>
-<translation id="8034955203865359138">ไม่à¸à¸à¸‚้อมูลประวัติà¸à¸²à¸£à¹€à¸‚้าà¸à¸¡</translation>
<translation id="8088680233425245692">à¸à¸²à¸£à¸”ูà¸à¸—ความล้มเหลว</translation>
+<translation id="8089520772729574115">ไม่ถึง 1 MB</translation>
<translation id="8091372947890762290">à¸à¸³à¸¥à¸±à¸‡à¸£à¸­à¸à¸²à¸£à¹€à¸›à¸´à¸”ใà¸à¹‰à¸‡à¸²à¸™à¸à¸™à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œ</translation>
+<translation id="8129262335948759431">ไม่ทราà¸à¸›à¸£à¸´à¸¡à¸²à¸“</translation>
<translation id="8131740175452115882">ยืนยัน</translation>
<translation id="8134994873729925007">ไม่à¸à¸<ph name="BEGIN_ABBR" />ที่อยู่ DNS<ph name="END_ABBR" /> ของเซิร์ฟเวอร์ของ <ph name="HOST_NAME" /></translation>
<translation id="8149426793427495338">คอมà¸à¸´à¸§à¹€à¸•à¸­à¸£à¹Œà¸‚องคุณเข้าสู่โหมดสลีปà¹à¸¥à¹‰à¸§</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">à¸à¸²à¸£à¸­à¸±à¸›à¹€à¸”ต URL ไม่ถูà¸à¸•à¹‰à¸­à¸‡à¸ªà¸³à¸«à¸£à¸±à¸à¸ªà¹ˆà¸§à¸™à¸‚ยายรหัส "<ph name="EXTENSION_ID" />"</translation>
<translation id="8218327578424803826">ตำà¹à¸«à¸™à¹ˆà¸‡à¸—ี่มอà¸à¸«à¸¡à¸²à¸¢:</translation>
<translation id="8225771182978767009">ผู้ที่ตั้งค่าคอมà¸à¸´à¸§à¹€à¸•à¸­à¸£à¹Œà¹€à¸„รื่องนี้เลือà¸à¸à¸¥à¹‡à¸­à¸à¹€à¸§à¹‡à¸à¹„ซต์นี้</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">หน้าที่คุณà¸à¸³à¸¥à¸±à¸‡à¸¡à¸­à¸‡à¸«à¸²à¹ƒà¸à¹‰à¸‚้อมูลที่คุณได้ป้อนไว้à¹à¸¥à¹‰à¸§ à¸à¸²à¸£à¸à¸¥à¸±à¸à¹„ปสู่หน้านั้นอาจทำให้คุณต้องทำซ้ำà¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¹ƒà¸”ๆ ที่คุณทำà¹à¸¥à¹‰à¸§ คุณต้องà¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸•à¹ˆà¸­à¸«à¸£à¸·à¸­à¹„ม่</translation>
<translation id="8249320324621329438">เรียà¸à¸”ูครั้งสุดท้ายเมื่อ:</translation>
<translation id="8261506727792406068">ลà¸</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">à¹à¸–à¸à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸</translation>
<translation id="8363502534493474904">ปิดโหมดà¸à¸™à¹€à¸„รื่องà¸à¸´à¸™</translation>
<translation id="8364627913115013041">ไม่ได้ตั้งค่า</translation>
+<translation id="8380941800586852976">อันตราย</translation>
<translation id="8412145213513410671">ข้อขัดข้อง (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">คุณต้องป้อนข้อความรหัสผ่านที่เหมือนà¸à¸±à¸™à¸ªà¸­à¸‡à¸„รั้ง</translation>
<translation id="8428213095426709021">à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า</translation>
+<translation id="8433057134996913067">วิธีนี้จะทำให้คุณออà¸à¸ˆà¸²à¸à¸£à¸°à¸à¸à¸‚องเว็à¸à¹„ซต์ส่วนใหà¸à¹ˆ</translation>
<translation id="8437238597147034694">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¸¢à¹‰à¸²à¸¢</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{à¸à¸±à¸•à¸£à¹€à¸„รดิต 1 ใà¸}other{à¸à¸±à¸•à¸£à¹€à¸„รดิต # ใà¸}}</translation>
+<translation id="8483780878231876732">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¹ƒà¸à¹‰à¸à¸²à¸£à¹Œà¸”จาà¸à¸à¸±à¸à¸à¸µ Google ให้ลงà¸à¸·à¹ˆà¸­à¹€à¸‚้าใà¸à¹‰ Chrome</translation>
<translation id="8488350697529856933">ใà¸à¹‰à¸à¸±à¸</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ใà¸à¹‰à¹€à¸§à¸¥à¸²à¸•à¸­à¸à¸à¸¥à¸±à¸à¸™à¸²à¸™à¹€à¸à¸´à¸™à¹„ป</translation>
+<translation id="852346902619691059">เซิร์ฟเวอร์นี้à¸à¸´à¸ªà¸¹à¸ˆà¸™à¹Œà¹„ม่ได้ว่าเป็น <ph name="DOMAIN" /> เà¸à¸£à¸²à¸°à¸£à¸°à¸à¸à¸›à¸à¸´à¸à¸±à¸•à¸´à¸à¸²à¸£à¸‚องอุปà¸à¸£à¸“์ไม่เà¸à¸·à¹ˆà¸­à¸–ือใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸„วามปลอดภัยของเซิร์ฟเวอร์นี้ สาเหตุอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้โจมตีขัดขวางà¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เà¸à¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Google Payments ไม่สนัà¸à¸ªà¸™à¸¸à¸™à¸à¸±à¸•à¸£à¸›à¸£à¸°à¹€à¸ à¸—นี้ โปรดเลือà¸à¸à¸±à¸•à¸£à¸­à¸·à¹ˆà¸™</translation>
<translation id="8550022383519221471">à¸à¸£à¸´à¸à¸²à¸£à¸‹à¸´à¸‡à¸„์ไม่มีให้à¸à¸£à¸´à¸à¸²à¸£à¸ªà¸³à¸«à¸£à¸±à¸à¹‚ดเมนของคุณ</translation>
<translation id="8553075262323480129">à¸à¸²à¸£à¹à¸›à¸¥à¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§à¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¹„ม่สามารถระà¸à¸¸à¸ à¸²à¸©à¸²à¸‚องหน้าเว็à¸à¸™à¸µà¹‰à¹„ด้</translation>
@@ -633,17 +675,14 @@
<translation id="8647750283161643317">รีเซ็ตทั้งหมดเป็นค่าเริ่มต้น</translation>
<translation id="8680787084697685621">รายละเอียดà¸à¸²à¸£à¸¥à¸‡à¸à¸·à¹ˆà¸­à¹€à¸‚้าใà¸à¹‰à¸à¸±à¸à¸à¸µà¹€à¸à¹ˆà¸²à¹€à¸à¸´à¸™à¹„ป</translation>
<translation id="8703575177326907206">à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณไปยัง <ph name="DOMAIN" /> ไม่ได้รัà¸à¸à¸²à¸£à¹€à¸‚้ารหัส</translation>
-<translation id="8713130696108419660">ลายเซ็นà¹à¸£à¸à¹€à¸£à¸´à¹ˆà¸¡à¹„ม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="8725066075913043281">ลองอีà¸à¸„รั้ง</translation>
<translation id="8728672262656704056">คุณได้เข้าสู่โหมดไม่ระà¸à¸¸à¸•à¸±à¸§à¸•à¸™à¹à¸¥à¹‰à¸§</translation>
<translation id="8730621377337864115">เสร็จสิ้น</translation>
<translation id="8738058698779197622">หาà¸à¸•à¹‰à¸­à¸‡à¹€à¸£à¸´à¹ˆà¸¡à¸à¸²à¸£à¹€à¸à¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸—ี่ปลอดภัย นาฬิà¸à¸²à¸ˆà¸°à¸•à¹‰à¸­à¸‡à¸•à¸±à¹‰à¸‡à¸„่าไว้อย่างถูà¸à¸•à¹‰à¸­à¸‡ เนื่องจาà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่เว็à¸à¹„ซต์ใà¸à¹‰à¹€à¸à¸·à¹ˆà¸­à¸£à¸°à¸à¸¸à¸•à¸™à¹€à¸­à¸‡à¸ˆà¸°à¹ƒà¸à¹‰à¹„ด้เฉà¸à¸²à¸°à¸à¹ˆà¸§à¸‡à¹€à¸§à¸¥à¸²à¸«à¸™à¸¶à¹ˆà¸‡à¹€à¸—่านั้น นาฬิà¸à¸²à¸‚องอุปà¸à¸£à¸“์ไม่ถูà¸à¸•à¹‰à¸­à¸‡ Chromium จึงไม่สามารถยืนยันใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¹€à¸«à¸¥à¹ˆà¸²à¸™à¸µà¹‰à¹„ด้</translation>
<translation id="8740359287975076522">ไม่à¸à¸&lt;abbr id="dnsDefinition"&gt;ที่อยู่ DNS&lt;/abbr&gt; ของ <ph name="HOST_NAME" /> à¸à¸³à¸¥à¸±à¸‡à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¸›à¸±à¸à¸«à¸²</translation>
-<translation id="8741995161408053644">à¸à¸±à¸à¸à¸µ Google ของคุณอาจมีประวัติà¸à¸²à¸£à¸—่องเว็à¸à¹ƒà¸™à¸£à¸¹à¸›à¹à¸à¸à¸­à¸·à¹ˆà¸™à¹† ที่ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="8790007591277257123">&amp;ทำซ้ำà¸à¸²à¸£à¸™à¸³à¸­à¸­à¸</translation>
-<translation id="8790687370365610530">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¹à¸™à¸°à¸™à¸³à¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸—ี่เหมาะสมสำหรัà¸à¸„ุณจาภGoogle ให้เปิดà¸à¸²à¸£à¸‹à¸´à¸‡à¸„์ประวัติà¸à¸²à¸£à¹€à¸‚้าà¸à¸¡</translation>
<translation id="8798099450830957504">ค่าเริ่มต้น</translation>
-<translation id="8804164990146287819">นโยà¸à¸²à¸¢à¸ªà¹ˆà¸§à¸™à¸à¸¸à¸„คล</translation>
+<translation id="8804164990146287819">นโยà¸à¸²à¸¢à¸„วามเป็นส่วนตัว</translation>
<translation id="8820817407110198400">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸</translation>
<translation id="8834246243508017242">เปิดใà¸à¹‰à¸à¸²à¸£à¸›à¹‰à¸­à¸™à¸‚้อความอัตโนมัติโดยใà¸à¹‰à¸£à¸²à¸¢à¸à¸·à¹ˆà¸­à¸•à¸´à¸”ต่อ…</translation>
<translation id="883848425547221593">à¸à¸¸à¹à¸à¸¡à¸²à¸£à¹Œà¸à¸­à¸·à¹ˆà¸™à¹†</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">ใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸‚องเซิร์ฟเวอร์หมดอายุà¹à¸¥à¹‰à¸§</translation>
<translation id="8987927404178983737">เดือน</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">เซิร์ฟเวอร์à¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่ไม่มีà¸à¸²à¸£à¹€à¸›à¸´à¸”เผยต่อสาธารณะโดยใà¸à¹‰à¸™à¹‚ยà¸à¸²à¸¢à¸„วามโปร่งใสของใà¸à¸£à¸±à¸à¸£à¸­à¸‡ ซึ่งเป็นข้อà¸à¸³à¸«à¸™à¸”สำหรัà¸à¹ƒà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸à¸²à¸‡à¸£à¸²à¸¢à¸à¸²à¸£ เà¸à¸·à¹ˆà¸­à¸¢à¸·à¸™à¸¢à¸±à¸™à¸§à¹ˆà¸²à¹€à¸à¸·à¹ˆà¸­à¸–ือได้à¹à¸¥à¸°à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¸à¸²à¸£à¸ˆà¸¹à¹ˆà¹‚จม</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> ของà¸à¸£à¹‡à¸­à¸à¸‹à¸µà¸•à¹‰à¸­à¸‡à¹ƒà¸à¹‰à¸à¸·à¹ˆà¸­à¸œà¸¹à¹‰à¹ƒà¸à¹‰à¹à¸¥à¸°à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™</translation>
<translation id="901974403500617787">à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าสถานะที่ใà¸à¹‰à¸—ั้งระà¸à¸à¸ªà¸²à¸¡à¸²à¸£à¸–ตั้งค่าได้โดยเจ้าของเท่านั้น: <ph name="OWNER_EMAIL" /></translation>
<translation id="9020542370529661692">หน้านี้ได้รัà¸à¸à¸²à¸£à¹à¸›à¸¥à¹€à¸›à¹‡à¸™ <ph name="TARGET_LANGUAGE" /> à¹à¸¥à¹‰à¸§</translation>
<translation id="9038649477754266430">ใà¸à¹‰à¸à¸£à¸´à¸à¸²à¸£à¸à¸²à¸£à¸„าดคะเนเà¸à¸·à¹ˆà¸­à¹‚หลดหน้าได้เร็วขึ้น</translation>
<translation id="9039213469156557790">นอà¸à¸ˆà¸²à¸à¸™à¸µà¹‰ หน้านี้ประà¸à¸­à¸à¸”้วยทรัà¸à¸¢à¸²à¸à¸£à¸­à¸·à¹ˆà¸™à¹† ซึ่งไม่ปลอดภัย ผู้อื่นสามารถดูทรัà¸à¸¢à¸²à¸à¸£à¹€à¸«à¸¥à¹ˆà¸²à¸™à¸µà¹‰à¸‚ณะถ่ายโอน à¹à¸¥à¸°à¸œà¸¹à¹‰à¸à¸¸à¸à¸£à¸¸à¸à¸ªà¸²à¸¡à¸²à¸£à¸–à¹à¸à¹‰à¹„ขเà¸à¸·à¹ˆà¸­à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸à¸²à¸£à¸—ำงานของหน้าได้</translation>
-<translation id="9049981332609050619">คุณà¸à¸¢à¸²à¸¢à¸²à¸¡à¹€à¸‚้าถึง <ph name="DOMAIN" /> à¹à¸•à¹ˆà¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹à¸ªà¸”งใà¸à¸£à¸±à¸à¸£à¸­à¸‡à¸—ี่ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="9050666287014529139">ข้อความรหัสผ่าน</translation>
<translation id="9065203028668620118">à¹à¸à¹‰à¹„ข</translation>
<translation id="9092364396508701805">หน้า <ph name="HOST_NAME" /> ไม่ทำงาน</translation>
diff --git a/chromium/components/strings/components_strings_tr.xtb b/chromium/components/strings/components_strings_tr.xtb
index b4c58371813..4a27fa7d35c 100644
--- a/chromium/components/strings/components_strings_tr.xtb
+++ b/chromium/components/strings/components_strings_tr.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="tr">
+<translation id="1008557486741366299">Åimdi DeÄŸil</translation>
<translation id="1015730422737071372">Diğer ayrıntıları sağlayın</translation>
<translation id="1032854598605920125">Saat yönĂ¼nde döndĂ¼r</translation>
<translation id="1038842779957582377">bilinmeyen ad</translation>
+<translation id="1053591932240354961"><ph name="SITE" /> web sitesi Google Chrome'un iÅŸleyemediÄŸi karışık kimlik bilgileri gönderdiÄŸi için bu web sitesini ÅŸu anda ziyaret edemezsiniz. AÄŸ hataları ve saldırılar genellikle geçici olduÄŸundan, bu sayfa muhtemelen daha sonra çalışacaktır. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">Eklemeyi &amp;Geri Al</translation>
<translation id="10614374240317010">Hiç kaydedilmeyecekler</translation>
-<translation id="1064422015032085147">Web sayfasını barındıran sunucu aşırı yĂ¼klenmiÅŸ veya bakımda olabilir.
- Çok fazla trafik oluÅŸturmaktan ve durumu daha da kötĂ¼leÅŸtirmekten
- kaçınmak için, bu URL'ye gelen istekler geçici olarak reddediliyor.</translation>
<translation id="106701514854093668">MasaĂ¼stĂ¼ Yer Ä°ÅŸaretleri</translation>
<translation id="1080116354587839789">Genişliğe sığdır</translation>
+<translation id="1103124106085518534">Åimdilik bitti</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> dilini daima çevir</translation>
<translation id="1107591249535594099">İşaretlenirse Chrome, formları daha hızlı doldurma amacıyla kartınızın bir kopyasını bu cihazda depolar.</translation>
+<translation id="1111153019813902504">Son yer iÅŸaretleri</translation>
<translation id="1113869188872983271">Sıralama değişikliğini &amp;geri al</translation>
+<translation id="1126551341858583091">Yerel depolama alanındaki boyut <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Politika önbelleÄŸi uygun</translation>
<translation id="113188000913989374"><ph name="SITE" /> web sitesinin mesajı:</translation>
<translation id="1132774398110320017">Chrome Otomatik Doldurma ayarları...</translation>
-<translation id="1150979032973867961">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. Bilgisayarınızın iÅŸletim sistemi, sunucunun gĂ¼venlik sertifikasına gĂ¼venmiyor. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantıya mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="1152921474424827756"><ph name="URL" /> sitesinin <ph name="BEGIN_LINK" />önbelleÄŸe alınmış bir kopyasına<ph name="END_LINK" /> eriÅŸin</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> bağlantıyı beklenmedik şekilde kapattı.</translation>
<translation id="1161325031994447685">Kablosuz aÄŸa yeniden baÄŸlanma</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Kaldır</translation>
<translation id="1201402288615127009">Sonraki</translation>
<translation id="1201895884277373915">Bu siteden daha çok</translation>
-<translation id="121201262018556460"><ph name="DOMAIN" /> alanına ulaÅŸmayı denediniz, ancak sunucu zayıf anahtar içeren bir sertifika sundu. Bir saldırgan özel anahtarı ele geçirmiÅŸ olabilir ve sunucu beklediÄŸiniz sunucu olmayabilir (bir saldırganla irtibat kuruyor olabilirsiniz).</translation>
+<translation id="1206967143813997005">BaÅŸlangıç anahtarlı imza hatalı</translation>
+<translation id="1209206284964581585">Åimdilik gizle</translation>
<translation id="1219129156119358924">Sistem GĂ¼venliÄŸi</translation>
<translation id="1227224963052638717">Bilinmeyen politika.</translation>
<translation id="1227633850867390598">DeÄŸeri gizle</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Evet</translation>
<translation id="1430915738399379752">Yazdır</translation>
<translation id="1442912890475371290"><ph name="BEGIN_LINK" /><ph name="DOMAIN" /> alan adındaki bir sayfayı ziyaret etme<ph name="END_LINK" /> girişimi engellendi.</translation>
+<translation id="1491663344921578213"><ph name="SITE" /> web sitesi, sertifika sabitleme yöntemini kullandığı için web sitesini ÅŸu anda ziyaret edemezsiniz. AÄŸ hataları ve saldırılar genellikle geçici olduÄŸundan, bu sayfa muhtemelen daha sonra çalışacaktır. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Bu sayfanın kaydedilmiÅŸ (eski olduÄŸu bilinen) bir kopyasını gösterin.</translation>
<translation id="1519264250979466059">OluÅŸturma Tarihi</translation>
<translation id="1549470594296187301">Bu özelliÄŸin kullanılabilmesi için JavaScript etkinleÅŸtirilmelidir.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">AÄŸ yapılandırması geçersiz, dolayısıyla içe aktarılamadı.</translation>
<translation id="1644574205037202324">GeçmiÅŸ</translation>
<translation id="1645368109819982629">Desteklenmeyen protokol</translation>
-<translation id="1655462015569774233">{1,plural, =1{Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikasının sĂ¼resi dĂ¼n sona erdi. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. Bilgisayarınızın saati geçerli olarak <ph name="CURRENT_DATE" /> tarihine ayarlı. Bu ayar doÄŸru görĂ¼nĂ¼yor mu? DeÄŸilse, sisteminizin saatini dĂ¼zeltmeli ve sonra bu sayfayı yenilemelisiniz.}other{Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası # gĂ¼n önce sona erdi. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. Bilgisayarınızın saati geçerli olarak <ph name="CURRENT_DATE" /> tarihine ayarlı. Bu ayar doÄŸru görĂ¼nĂ¼yor mu? DeÄŸilse, sisteminizin saatini dĂ¼zeltmeli ve sonra bu sayfayı yenilemelisiniz.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> normalde bilgilerinizi korumak için ÅŸifreleme kullanmaktadır. Google Chrome bu sefer <ph name="SITE" /> sitesine baÄŸlanmayı denediÄŸinde, web sitesi sıra dışı ve yanlış kimlik bilgileri döndĂ¼rdĂ¼. Bir saldırgan <ph name="SITE" /> gibi davranmaya çalışıyor olabilir ya da bir Kablosuz oturum açma ekranı baÄŸlantıyı kesmiÅŸtir. Google Chrome herhangi bir veri alışveriÅŸinden önce baÄŸlantıyı durdurduÄŸu için bilgileriniz hĂ¢lĂ¢ gĂ¼vendedir.</translation>
<translation id="168841957122794586">Sunucu sertifikasında zayıf bir şifreleme anahtarı var.</translation>
<translation id="1701955595840307032">Ă–nerilen içeriÄŸi al</translation>
-<translation id="1706954506755087368">{1,plural, =1{Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikasının alınma tarihinin yarın olduÄŸu iddia ediliyor. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.}other{Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikasının alınma tarihinin # gĂ¼n sonra olduÄŸu iddia ediliyor. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Sistem yöneticisiyle iletiÅŸime geçmeyi deneyin.</translation>
<translation id="17513872634828108">Açık sekmeler</translation>
<translation id="1753706481035618306">Sayfa numarası</translation>
-<translation id="1761412452051366565">Google tarafından önerilen kiÅŸiselleÅŸtirilmiÅŸ içeriÄŸi almak için senkronizasyonu açın.</translation>
-<translation id="1763864636252898013">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. cihazınızın iÅŸletim sistemi, sunucunun gĂ¼venlik sertifikasına gĂ¼venmiyor. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantıya mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows AÄŸ TeÅŸhislerini çalıştırmayı deneyin<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">LĂ¼tfen senkronizasyon parolanızı gĂ¼ncelleyin.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Son ziyaret ettiÄŸiniz yer iÅŸaretleri burada görĂ¼necek.</translation>
<translation id="1821930232296380041">Geçersiz istek veya istek parametreleri</translation>
<translation id="1838667051080421715">Bir web sayfasının kaynak kodunu görĂ¼yorsunuz.</translation>
<translation id="1871208020102129563">Proxy, bir .pac komut dosyası URL'sini değil, sabit proxy sunucuları kullanacak şekilde ayarlanır.</translation>
<translation id="1883255238294161206">Listeyi daralt</translation>
<translation id="1898423065542865115">Filtreleme</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> giriÅŸ sertifikanızı kabul etmedi veya giriÅŸ sertifikanızın son kullanım tarihi geçmiÅŸ olabilir.</translation>
<translation id="194030505837763158"><ph name="LINK" /> adresine git</translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> Yer Ä°ÅŸaretleri</translation>
<translation id="1973335181906896915">Serileştirme hatası</translation>
<translation id="1974060860693918893">GeliÅŸmiÅŸ</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{ve 1 uygulama daha}other{ve # uygulama daha}}</translation>
<translation id="2025186561304664664">Proxy, otomatik yapılandırıldı değerine ayarlandı.</translation>
<translation id="2030481566774242610">Åunu mu demek istediniz?: <ph name="LINK" /></translation>
<translation id="2031925387125903299">Ä°lk kez ziyaret ettiÄŸiniz yeni siteleri önce ebeveynlerinizin onaylaması gerektiÄŸi için bu iletiyi görĂ¼yorsunuz.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Proxy'yi ve gĂ¼venlik duvarını kontrol etme<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">Posta kodu</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 öneri}other{# öneri}}</translation>
<translation id="2065985942032347596">Kimlik Doğrulaması Gerekiyor</translation>
<translation id="2079545284768500474">Geri Al</translation>
<translation id="20817612488360358">Sistem proxy ayarları kullanılmak Ă¼zere ayarlandı, ancak açık bir proxy yapılandırması da belirtildi.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Yer Ä°ÅŸaretini DĂ¼zenle</translation>
<translation id="2166049586286450108">Tam Yönetici EriÅŸimi</translation>
<translation id="2166378884831602661">Bu site gĂ¼venli baÄŸlantı saÄŸlayamıyor</translation>
-<translation id="2171101176734966184"><ph name="DOMAIN" /> adresine eriÅŸme giriÅŸiminde bulundunuz ancak sunucu zayıf bir imza algoritması kullanılarak imzalanmış bir sertifika saÄŸladı. Bu, sunucunun saÄŸladığı gĂ¼venlik bilgilerinin sahte olabileceÄŸi anlamına gelir ve sunucu sizin beklediÄŸiniz sunucu olmayabilir (bir saldırgan ile irtibat kuruyor olabilirsiniz).</translation>
<translation id="2181821976797666341">Politikalar</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}other{# adres}}</translation>
<translation id="2212735316055980242">Politika bulunamadı</translation>
<translation id="2213606439339815911">GiriÅŸler getiriliyor...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> kullanılamıyor</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />Tanılama uygulamasını<ph name="END_LINK" /> kullanarak baÄŸlantınızı dĂ¼zeltin</translation>
+<translation id="2239100178324503013">Åimdi gönder</translation>
<translation id="225207911366869382">Bu deÄŸer bu politika için kullanımdan kaldırıldı.</translation>
<translation id="2262243747453050782">HTTP hatası</translation>
<translation id="2282872951544483773">Kullanılamayan Deneyler</translation>
<translation id="2292556288342944218">Ä°nternet eriÅŸiminiz engellendi</translation>
<translation id="229702904922032456">Bir kök ya da ara sertifikanın sĂ¼resi geçmiÅŸ.</translation>
<translation id="230155334948463882">Yeni bir kart mı?</translation>
+<translation id="2305919008529760154">Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası hileli bir ÅŸekilde yayınlanmış olabilir. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> için kullanıcı adı ve ÅŸifre gerekiyor.</translation>
+<translation id="2318774815570432836"><ph name="SITE" /> web sitesi HSTS kullandığı için bu web sitesini ÅŸu anda ziyaret edemezsiniz. AÄŸ hataları ve saldırılar genellikle geçici olduÄŸundan, bu sayfa muhtemelen daha sonra çalışacaktır. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155"><ph name="ENTRY_INDEX" /> dizininde yok sayılan geçersiz yer iÅŸareti</translation>
<translation id="2354001756790975382">DiÄŸer yer iÅŸaretleri</translation>
<translation id="2359808026110333948">Devam Et</translation>
<translation id="2365563543831475020">Yakalanan kilitlenme raporu (<ph name="CRASH_TIME" />) yĂ¼klenmedi</translation>
<translation id="2367567093518048410">DĂ¼zey</translation>
+<translation id="2371153335857947666">{1,plural, =1{Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikasının sĂ¼resi dĂ¼n sona erdi. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. Bilgisayarınızın saati ÅŸu anda <ph name="CURRENT_DATE" /> olarak ayarlanmış. Bu tarih doÄŸru mu? DeÄŸilse, sisteminizin saatini dĂ¼zeltmeli ve sonra bu sayfayı yenilemelisiniz. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.}other{Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası # gĂ¼n önce sona erdi. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. Bilgisayarınızın saati ÅŸu anda <ph name="CURRENT_DATE" /> olarak ayarlanmış. Bu tarih doÄŸru mu? DeÄŸilse, sisteminizin saatini dĂ¼zeltmeli ve sonra bu sayfayı yenilemelisiniz. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">Mevcut kullanıcı arayĂ¼zĂ¼ alternatifi yok</translation>
<translation id="2384307209577226199">Kuruluşun varsayılan ayarı</translation>
-<translation id="238526402387145295">Web sitesi <ph name="BEGIN_LINK" />HSTS kullandığı<ph name="END_LINK" /> için <ph name="SITE" /> sitesini ÅŸu anda ziyaret edemezsiniz. AÄŸ hataları ve saldırılar genellikle geçici olduÄŸundan, bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
<translation id="2386255080630008482">Sunucunun sertifikası iptal edildi.</translation>
<translation id="2392959068659972793">Hiçbir deÄŸer ayarlanmamış politikaları göster</translation>
<translation id="2396249848217231973">Silmeyi &amp;geri al</translation>
-<translation id="2413528052993050574">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası iptal edilmiÅŸ olabilir. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantıya mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="2455981314101692989">Bu web sayfası bu form için otomatik doldurmayı devre dışı bıraktı.</translation>
+<translation id="2463739503403862330">Doldur</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />AÄŸ TeÅŸhislerini Çalıştırma<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">Geçersiz arama URL'si.</translation>
<translation id="2491120439723279231">Sunucu sertifikası hatalar içeriyor.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Gönder</translation>
<translation id="2674170444375937751">Bu sayfaları geçmiÅŸinizden silmek istediÄŸinizden emin misiniz?</translation>
<translation id="2677748264148917807">Çık</translation>
+<translation id="269990154133806163">Sunucu, Sertifika Åeffaflığı politikası kullanılarak herkese açık bir ÅŸekilde saÄŸlanmayan bir sertifika sundu. GĂ¼venilir olduklarından emin olmak ve saldırganlara karşı korunmak için bazı sertifikalarda bu zorunludur. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">DeÄŸer, biçimle eÅŸleÅŸmiyor.</translation>
<translation id="2704951214193499422">Chromium, ÅŸu anda kartınızı onaylayamıyor. LĂ¼tfen daha sonra tekrar deneyin.</translation>
<translation id="2705137772291741111">Bu sitenin kaydedilen (önbelleÄŸe alınan) kopyası okunamadı.</translation>
<translation id="2709516037105925701">Otomatik doldurma</translation>
+<translation id="2712118517637785082"><ph name="DOMAIN" /> alan adına ulaÅŸmayı denediniz, ancak sunucunun saÄŸladığı sertifika, sertifikayı veren tarafından iptal edildi. Bu durum, sunucunun saÄŸladığı gĂ¼venlik kimlik bilgilerine kesinlikle gĂ¼venilmemesi gerektiÄŸi anlamına gelir. Bir saldırganla irtibat kuruyor olabilirsiniz. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Ä°zin iste</translation>
<translation id="2721148159707890343">İstek başarılı oldu</translation>
<translation id="2728127805433021124">Sunucunun sertifikası, zayıf bir imza algoritması kullanılarak imzalanmış.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Adres ve arama çubuÄŸu</translation>
<translation id="2826760142808435982">Bağlantı <ph name="CIPHER" /> kullanılarak şifrelenmiş ve kimliği doğrulanmıştır. Anahtar değişim mekanizması olarak <ph name="KX" /> kullanılır.</translation>
<translation id="2835170189407361413">Formu temizle</translation>
-<translation id="2837049386027881519">BaÄŸlantı, TLS veya SSL protokolĂ¼nĂ¼n eski bir sĂ¼rĂ¼mĂ¼ kullanılarak tekrar denendi. Bu genellikle sunucunun çok eski bir yazılım kullandığı ve baÅŸka gĂ¼venlik sorunları olabileceÄŸi anlamına gelir.</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> ana makinesindeki sunucu sertifikası sahte görĂ¼nĂ¼yor.</translation>
<translation id="2889159643044928134">Yeniden YĂ¼kleme</translation>
-<translation id="2896499918916051536">Bu eklenti desteklenmiyor.</translation>
+<translation id="2900469785430194048">Bu web sayfası görĂ¼ntĂ¼lenmeye çalışılırken Google Chrome'da bellek kalmadı.</translation>
<translation id="2909946352844186028">Bir ağ değişikliği algılandı.</translation>
-<translation id="2915500479781995473">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikasının sĂ¼resi dolmuÅŸ. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. Bilgisayarınızın saati ÅŸu anda <ph name="CURRENT_TIME" /> deÄŸerine ayarlı. Saat doÄŸru mu? DeÄŸilse sistem saatinizi dĂ¼zeltmeniz ve ardından bu sayfayı yenilemeniz gerekir.</translation>
<translation id="2922350208395188000">Sunucunun sertifikası kontrol edilemiyor.</translation>
-<translation id="2941952326391522266">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası <ph name="DOMAIN2" /> alan adından geliyor. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantıya mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="2948083400971632585">Ayarlar sayfasından, bir baÄŸlantı için yapılandırılmış proxy'leri devre dışı bırakabilirsiniz.</translation>
<translation id="2955913368246107853">Bulma çubuÄŸunu kapat</translation>
<translation id="2958431318199492670">AÄŸ yapılandırması ONC standardıyla uyumlu deÄŸil. Yapılandırmanın bazı bölĂ¼mleri içe aktarılamaz.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Yanlış politika tĂ¼rĂ¼</translation>
<translation id="3032412215588512954">Bu siteyi yeniden yĂ¼klemek istiyor musunuz?</translation>
<translation id="3037605927509011580">Hay aksi!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{senkronize edilmiÅŸ cihazlarda en az 1 Ă¶ÄŸe}=1{1 Ă¶ÄŸe (ve senkronize edilmiÅŸ cihazlarda daha fazlası)}other{# Ă¶ÄŸe (ve senkronize edilmiÅŸ cihazlarda daha fazlası)}}</translation>
<translation id="3041612393474885105">Sertifika Bilgileri</translation>
<translation id="3063697135517575841">Chrome ÅŸu anda kartınızı onaylayamıyor. LĂ¼tfen daha sonra tekrar deneyin.</translation>
<translation id="3093245981617870298">Çevrimdışısınız.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">En yeni</translation>
<translation id="3207960819495026254">Yer iÅŸareti koyuldu</translation>
-<translation id="3225919329040284222">Sunucu, yerleÅŸik beklentilerle eÅŸleÅŸmeyen bir sertifika sundu. Bu beklentiler sizi korumak amacıyla bazı yĂ¼ksek gĂ¼venlikli web sitelerinde bulunur.</translation>
<translation id="3226128629678568754">Sayfayı yĂ¼klemek Ă¼zere gereken verileri tekrar göndermek için yeniden yĂ¼kle dĂ¼ÄŸmesine basın.</translation>
<translation id="3228969707346345236">Sayfa zaten <ph name="LANGUAGE" /> dilinde olduÄŸundan çeviri iÅŸlemi baÅŸarısız oldu.</translation>
<translation id="323107829343500871"><ph name="CREDIT_CARD" /> numaralı kartın CVC kodunu girin</translation>
<translation id="3254409185687681395">Bu sayfaya yer iÅŸareti koy</translation>
<translation id="3270847123878663523">Sıralama Değişikliğini &amp;Geri Al</translation>
<translation id="3286538390144397061">Åimdi yeniden baÅŸlat</translation>
+<translation id="3303855915957856445">Arama sonucu bulunamadı</translation>
<translation id="3305707030755673451">Verileriniz <ph name="TIME" /> tarihinde senkronizasyon parolanızla ÅŸifrelendi. Senkronizasyonu baÅŸlatmak için senkronizasyon parolanızı girin.</translation>
<translation id="333371639341676808">Bu sayfanın ek iletişim kutusu oluşturmasına izin verme.</translation>
+<translation id="3338095232262050444">GĂ¼venli</translation>
<translation id="3340978935015468852">ayarlar</translation>
<translation id="3345135638360864351">Bu siteye eriÅŸim isteÄŸiniz <ph name="NAME" /> adlı kullanıcıya gönderilemedi. LĂ¼tfen tekrar deneyin.</translation>
<translation id="3355823806454867987">Proxy ayarlarını değiştir...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Getirme aralığı:</translation>
<translation id="3462200631372590220">GeliÅŸmiÅŸ bilgileri gizle</translation>
<translation id="3479539252931486093">Bu beklenmedik bir durum mu? <ph name="BEGIN_LINK" />Bize bildirin<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Åimdi deÄŸil</translation>
<translation id="348000606199325318">Kilitlenme KimliÄŸi: <ph name="CRASH_LOCAL_ID" /> (Sunucu KimliÄŸi: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Åu anda ebeveyninize eriÅŸemedik. LĂ¼tfen tekrar deneyin.</translation>
<translation id="3527085408025491307">Klasör</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Åunun için ÅŸifre kullan:</translation>
<translation id="3549644494707163724">Senkronize edilen tĂ¼m verileri kendi senkronizasyon parolanızla ÅŸifreleyin</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> tane daha...</translation>
+<translation id="3555561725129903880">Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası <ph name="DOMAIN2" /> alan adından geliyor. Bu durum yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Bağlantınız gizli değil</translation>
<translation id="3583757800736429874">Taşımayı &amp;Yeniden Yap</translation>
<translation id="3586931643579894722">Ayrıntıları gizle</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">DeÄŸeri göster</translation>
<translation id="3630155396527302611">AÄŸa eriÅŸmesine izin verilmiÅŸ bir program olarak zaten listeleniyorsa,
listeden kaldırıp tekrar eklemeyi deneyin.</translation>
+<translation id="3638794133396384728">Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikasının sĂ¼resi dolmuÅŸ. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. Bilgisayarınızın saati ÅŸu anda <ph name="CURRENT_TIME" /> olarak ayarlı. Bu saat doÄŸru mu? DeÄŸilse sistem saatinizi dĂ¼zeltmeniz ve ardından bu sayfayı yenilemeniz gerekir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Bu deneysel özellikler zaman zaman deÄŸiÅŸebilir, bozulabilir veya kullanımdan kaldırılabilir. Bu deneylerden herhangi birini açtığınızda tarayıcınızın aniden yanmaya baÅŸlaması mĂ¼mkĂ¼n olduÄŸundan, başınıza gelebilecekler konusunda kesinlikle hiçbir garanti vermeyiz. Åaka bir yana, tarayıcınız tĂ¼m verilerinizi silebilir ya da gĂ¼venliÄŸiniz ve gizliliÄŸiniz beklenmedik ÅŸekillerde riske girebilir. EtkinleÅŸtireceÄŸiniz her deney bu tarayıcının tĂ¼m kullanıcıları için etkin hale gelecektir. LĂ¼tfen dikkatle ilerleyin.</translation>
<translation id="3650584904733503804">Doğrulama başarılı</translation>
<translation id="3655670868607891010">Bunu çok sık görĂ¼yorsanız, ÅŸunları deneyin: <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">DĂ¼zeltme</translation>
+<translation id="3678029195006412963">İstek imzalanamadı</translation>
<translation id="3681007416295224113">Sertifika bilgileri</translation>
<translation id="3693415264595406141">Åifre:</translation>
+<translation id="3696411085566228381">yok</translation>
<translation id="3700528541715530410">Hata! Bu sayfaya eriÅŸim izninizin olmadığı görĂ¼lĂ¼yor.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">YĂ¼kleniyor...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Mobil veriyi veya kablosuz baÄŸlantıyı açma</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Proxy, gĂ¼venlik duvarı ve DNS yapılandırmasını kontrol etme<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Kopyaladığınız bağlantı</translation>
-<translation id="3744899669254331632">Web sitesi Chromium'un iÅŸleyemediÄŸi karışık kimlik bilgileri gönderdiÄŸinden <ph name="SITE" /> sitesini ÅŸu anda ziyaret edemezsiniz. AÄŸ hataları ve saldırılar genellikle geçici tĂ¼rdendir, dolayısıyla bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
<translation id="375403751935624634">Çeviri, bir sunucu hatası nedeniyle baÅŸarısız oldu.</translation>
<translation id="3759461132968374835">Son zamanda herhangi bir kilitlenme bildirmediniz. Kilitlenme bildirme özelliÄŸi devre dışıyken oluÅŸan kilitlenmeler burada görĂ¼nmez.</translation>
<translation id="3788090790273268753">Bu siteye iliÅŸkin sertifikanın sĂ¼resi 2016'da doluyor ve sertifika zinciri, SHA-1 kullanılarak imzalanmış bir sertifika içeriyor.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Çakışan cihaz tanımlayıcısı</translation>
<translation id="3885155851504623709">Bucak</translation>
<translation id="3901925938762663762">Kartın kullanım sĂ¼resi doldu</translation>
+<translation id="3910267023907260648"><ph name="DOMAIN" /> alan adına eriÅŸme giriÅŸiminde bulundunuz, ancak sunucu zayıf bir imza algoritması kullanılarak imzalanmış bir sertifika saÄŸladı. Bu durum, sunucunun saÄŸladığı gĂ¼venlik bilgilerinin sahte olabileceÄŸi anlamına gelir ve sunucu sizin beklediÄŸiniz sunucu olmayabilir (bir saldırgan ile irtibat kuruyor olabilirsiniz). <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikasının alınma tarihinin yarın olduÄŸu iddia ediliyor. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.}other{Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikasının alınma tarihinin # gĂ¼n sonra olduÄŸu iddia ediliyor. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">PDF dokĂ¼manı yĂ¼klenemedi</translation>
<translation id="3963721102035795474">Okuyucu Modu</translation>
+<translation id="397105322502079400">Hesaplanııyor...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> engellendi</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{Yakındaki 1 web sayfası}other{Yakındaki # web sayfası}}</translation>
<translation id="4021036232240155012">DNS, bir web sitesinin adını o siteye özgĂ¼ Ä°nternet adresine dönĂ¼ÅŸtĂ¼ren aÄŸ hizmetidir.</translation>
<translation id="4030383055268325496">Eklemeyi &amp;geri al</translation>
-<translation id="4032534284272647190"><ph name="URL" /> adresine eriÅŸim reddedildi.</translation>
<translation id="404928562651467259">UYARI</translation>
<translation id="4058922952496707368">"<ph name="SUBKEY" />" anahtarı: <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Ä°stemci ve sunucu, ortak bir SSL protokolĂ¼ sĂ¼rĂ¼mĂ¼nĂ¼ veya ÅŸifre setini desteklemiyor.</translation>
<translation id="4079302484614802869">Proxy yapılandırması sabit proxy sunucuları deÄŸil, bir .pac komut dosyası URL'sini kullanmak Ă¼zere ayarlandı.</translation>
<translation id="4103249731201008433">Cihazın seri numarası geçersiz</translation>
<translation id="4103763322291513355">Kara listeye alınmış URL'lerin ve sistem yöneticinizin zorunlu tuttuÄŸu diÄŸer politikaların listesini görmek için &lt;strong&gt;chrome://policy&lt;/strong&gt; adresini ziyaret edin.</translation>
+<translation id="4110615724604346410">Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası hatalar içeriyor. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Politika kapsamı desteklenmiyor.</translation>
+<translation id="4118212371799607889">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. Chromium, sunucunun gĂ¼venlik sertifikasına gĂ¼venmiyor. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 Ă¶ÄŸe daha}other{# Ă¶ÄŸe daha}}</translation>
<translation id="4130226655945681476">AÄŸ kabloları, modem ve yönlendirici kontrol ediliyor</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Chromium'un bu kartı kaydetmesini istiyor musunuz?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Devre dışı</translation>
<translation id="4196861286325780578">Taşımayı &amp;yeniden yap</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />GĂ¼venlik duvarı ve virĂ¼sten korunma yapılandırmalarını kontrol etme<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{yok}=1{1 uygulama ($1)}=2{2 uygulama ($1, $2)}other{# uygulama ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Kilitlenmeler</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />AÄŸ TeÅŸhislerini çalıştırmayı deneyin<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Hayır</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(Kullanıcı adı yok)</translation>
<translation id="4300246636397505754">Ebeveyn önerileri</translation>
<translation id="4304224509867189079">GiriÅŸ Yap</translation>
+<translation id="432290197980158659">Sunucu, yerleÅŸik beklentilerle eÅŸleÅŸmeyen bir sertifika sundu. Bu beklentiler sizi korumak amacıyla bazı yĂ¼ksek gĂ¼venlikli web sitelerinde bulunur. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Makale bulunamadı</translation>
+<translation id="4331708818696583467">GĂ¼venli DeÄŸil</translation>
<translation id="4372948949327679948">Beklenen <ph name="VALUE_TYPE" /> deÄŸeri.</translation>
-<translation id="4377125064752653719"><ph name="DOMAIN" /> adresine ulaÅŸmayı denediniz, ancak sunucunun saÄŸladığı sertifika, sertifikayı veren tarafından iptal edildi. Bu, sunucunun saÄŸladığı gĂ¼venlik kimlik bilgilerine kesinlikle gĂ¼venilmemesi gerektiÄŸi anlamına gelir. Bir saldırganla irtibat kuruyor olabilirsiniz.</translation>
<translation id="4381091992796011497">Kullanıcı Adı:</translation>
<translation id="4394049700291259645">Devre dışı bırak</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> - <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">arama sonuçları</translation>
-<translation id="4424024547088906515">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. Chrome, sunucunun gĂ¼venlik sertifikasına gĂ¼venmiyor. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantıya mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> giriş sertifikanızı kabul etmedi veya giriş sertifikası sağlanmamış olabilir.</translation>
<translation id="443673843213245140">Proxy kullanımı devre dışı, ancak açık bir proxy yapılandırması belirtildi.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Google SafeSites etkinleÅŸtirilmiÅŸ olduÄŸu için bu iletiyi görĂ¼yorsunuz.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Ayrıntılar</translation>
<translation id="4558551763791394412">Uzantılarınızı devre dışı bırakmayı deneyin</translation>
<translation id="4587425331216688090">Adres Chrome'dan kaldırılsın mı?</translation>
+<translation id="4589078953350245614"><ph name="DOMAIN" /> alan adına eriÅŸmeyi denediniz, ancak sunucu geçersiz bir sertifika sundu. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459"><ph name="DOMAIN" /> ile olan bağlantınız modern bir şifre seti kullanılarak şifrelendi.</translation>
<translation id="4594403342090139922">Silmeyi &amp;Geri Al</translation>
+<translation id="4627442949885028695">BaÅŸka bir cihazdan devam edin</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Bir uzantı sayfası görĂ¼ntĂ¼lĂ¼yorsunuz.</translation>
-<translation id="467662567472608290">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikasında hatalar var. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantıya mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> engellendi</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Bağlantınız kesildi</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows AÄŸ TeÅŸhislerini Çalıştırma<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">Platform</translation>
<translation id="4744603770635761495">Çalıştırılabilir Yol</translation>
<translation id="4756388243121344051">&amp;GeçmiÅŸ</translation>
+<translation id="4759238208242260848">Ä°ndirilenler</translation>
<translation id="4764776831041365478"><ph name="URL" /> adresindeki web sayfası, geçici olarak kullanılamıyor veya kalıcı olarak yeni bir web adresine taşınmış olabilir.</translation>
<translation id="4771973620359291008">Bilinmeyen bir hata oluÅŸtu.</translation>
<translation id="4782449893814226250">Ebeveynlerinize, bu sayfayı ziyaret etmenizin uygun olup olmadığını sordunuz.</translation>
<translation id="4800132727771399293">Son kullanma tarihinizi ve CVC'nizi kontrol edip tekrar deneyin</translation>
-<translation id="4807049035289105102"><ph name="SITE" /> web sitesi Google Chrome'un iÅŸleyemediÄŸi karışık kimlik bilgileri gönderdiÄŸi için bu siteyi ÅŸu anda ziyaret edemezsiniz. AÄŸ hataları ve saldırılar genellikle geçici olduÄŸundan bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
<translation id="4813512666221746211">Ağ hatası</translation>
<translation id="4816492930507672669">Sayfaya sığdır</translation>
<translation id="4850886885716139402">GörĂ¼ntĂ¼le</translation>
<translation id="4880827082731008257">GeçmiÅŸte ara</translation>
+<translation id="4884656795097055129">Zamanı geldiÄŸinde daha fazla haber gösterilecek.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{ve 1 web sayfası daha}other{ve # web sayfası daha}}</translation>
<translation id="4923417429809017348">Bu sayfa, bilinmeyen bir dilden <ph name="LANGUAGE_LANGUAGE" /> diline çevrildi</translation>
<translation id="4926049483395192435">Belirtilmelidir.</translation>
<translation id="4930497775425430760">Ä°lk kez ziyaret ettiÄŸiniz yeni siteleri önce ebeveyninizin onaylaması gerektiÄŸi için bu iletiyi görĂ¼yorsunuz.</translation>
<translation id="495170559598752135">Ä°ÅŸlemler</translation>
<translation id="4958444002117714549">Listeyi geniÅŸlet</translation>
+<translation id="4962322354953122629">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. Chrome, sunucunun gĂ¼venlik sertifikasına gĂ¼venmiyor. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911"><ph name="ORIGINAL_LANGUAGE" /> dilinden <ph name="TARGET_LANGUAGE" /> diline çevrilsin mi?</translation>
+<translation id="4989809363548539747">Bu eklenti desteklenmiyor</translation>
<translation id="5002932099480077015">Bu seçenek etkinleÅŸtirildiÄŸinde Chrome, formları daha hızlı doldurmak için kartınızın bir kopyasını bu cihazda saklar.</translation>
<translation id="5019198164206649151">Yedekleme deposu kötĂ¼ durumda</translation>
<translation id="5023310440958281426">Yöneticinizin politikalarını inceleyin.</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Google Çeviri Hakkında</translation>
<translation id="5040262127954254034">Gizlilik</translation>
<translation id="5045550434625856497">Hatalı parola</translation>
+<translation id="5056549851600133418">Size uygun makaleler</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Proxy adresini kontrol etme<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Sunucu sertifikası ÅŸu anda geçerli deÄŸil.</translation>
<translation id="5089810972385038852">Eyalet</translation>
-<translation id="5094747076828555589">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı; Chromium, sunucunun gĂ¼venlik sertifikasına gĂ¼venmiyor. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantıya mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="5095208057601539847">Bölge</translation>
<translation id="5115563688576182185">(64 bit)</translation>
-<translation id="5122371513570456792">"<ph name="SEARCH_STRING" />" için <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> sonuç bulundu.</translation>
<translation id="5141240743006678641">Senkronize edilen ÅŸifreleri Google kimlik bilgilerinizle ÅŸifreleyin</translation>
<translation id="5145883236150621069">Politika yanıtında hata kodu var</translation>
<translation id="5171045022955879922">Arayın veya URL'yi yazın</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Yer Ä°ÅŸareti ÇubuÄŸu</translation>
<translation id="5199729219167945352">Deneyler</translation>
<translation id="5251803541071282808">Bulut</translation>
+<translation id="5277279256032773186">Chrome'u iÅŸte mi kullanıyorsunuz? Ä°ÅŸletmeler, çalışanları için Chrome ayarlarını yönetebilir. Daha fazla bilgi edinin</translation>
<translation id="5299298092464848405">Politika ayrıştırma hatası</translation>
<translation id="5300589172476337783">Göster</translation>
<translation id="5308689395849655368">Kilitlenme bildirme devre dışı.</translation>
<translation id="5317780077021120954">Kaydet</translation>
<translation id="5327248766486351172">Ad</translation>
+<translation id="5359637492792381994">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası ÅŸu anda geçerli deÄŸil. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">Politika ayarları saklanamadı</translation>
-<translation id="540969355065856584">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası ÅŸu anda geçerli deÄŸil. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantıya mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="5421136146218899937">Tarama verilerini temizle...</translation>
<translation id="5430298929874300616">Yer işaretini kaldır</translation>
<translation id="5431657950005405462">Dosyanız bulunamadı</translation>
<translation id="5435775191620395718">Bu cihazdan geçmiÅŸ bilgileri gösteriliyor. <ph name="BEGIN_LINK" />Daha fazla bilgi edinin<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">Senkronize edilen verileriniz özel bir parolayla korunduÄŸu için kiÅŸiselleÅŸtirilmiÅŸ içerik önerileri ÅŸu anda devre dışı.</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" Ă¼zerinde ÅŸema doÄŸrulama hatası: <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Bu <ph name="HOST_NAME" /> sayfası bulunamıyor</translation>
<translation id="5455374756549232013">Politika zaman damgası yanlış</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Bu siteden ayrılmak istiyor musunuz?</translation>
<translation id="5629630648637658800">Politika ayarları yĂ¼klenemedi</translation>
<translation id="5631439013527180824">Geçersiz cihaz yönetimi jetonu</translation>
-<translation id="5650551054760837876">Arama sonucu bulunamadı.</translation>
<translation id="5677928146339483299">Engellenenler</translation>
<translation id="5710435578057952990">Bu web sitesinin kimliği doğrulanmadı.</translation>
<translation id="5720705177508910913">Geçerli kullanıcı</translation>
+<translation id="572328651809341494">Son sekmeler</translation>
<translation id="5784606427469807560">Kartınız onaylanırken bir sorun oluştu. İnternet bağlantınızı kontrol edip tekrar deneyin.</translation>
<translation id="5785756445106461925">Ayrıca, bu sayfa gĂ¼venli olmayan baÅŸka kaynaklar içeriyor. Bu kaynaklar, aktarım sırasında baÅŸkaları tarafından görĂ¼lebilir ve bir saldırgan tarafından sayfanın görĂ¼nĂ¼ÅŸĂ¼nĂ¼ deÄŸiÅŸtirmek Ă¼zere kullanılabilir.</translation>
+<translation id="5786044859038896871">Kart bilgilerinizin doldurulmasını istiyor musunuz?</translation>
+<translation id="5803412860119678065"><ph name="CARD_DETAIL" /> kartınıza ait bilgilerin doldurulmasını istiyor musunuz?</translation>
<translation id="5810442152076338065"><ph name="DOMAIN" /> ile olan bağlantınız eski bir şifre seti kullanılarak şifrelendi.</translation>
<translation id="5813119285467412249">Eklemeyi &amp;Yeniden Yap</translation>
+<translation id="5814352347845180253"><ph name="SITE" /> ve diÄŸer sitelerden alınan premium içeriÄŸe eriÅŸiminizi kaybedebilirsiniz.</translation>
+<translation id="5843436854350372569"><ph name="DOMAIN" /> alan adına ulaÅŸmayı denediniz, ancak sunucu zayıf anahtar içeren bir sertifika sundu. Bir saldırgan özel anahtarı ele geçirmiÅŸ olabilir ve sunucu beklediÄŸiniz sunucu olmayabilir (bir saldırganla irtibat kuruyor olabilirsiniz). <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Yöneticiniz bu siteyi engellediÄŸi için bu iletiyi görĂ¼yorsunuz.</translation>
<translation id="5857090052475505287">Yeni Klasör</translation>
<translation id="5869405914158311789">Bu siteye ulaşılamıyor</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Ebeveyn Ă–nerileri</translation>
<translation id="59107663811261420">Google Payments, bu satıcı için bu kart tĂ¼rĂ¼nĂ¼ desteklememektedir. LĂ¼tfen farklı bir kart seçin.</translation>
<translation id="59174027418879706">Etkin</translation>
+<translation id="5926846154125914413">Bazı sitelerden alınan premium içeriÄŸe eriÅŸiminizi kaybedebilirsiniz.</translation>
<translation id="5966707198760109579">Hafta</translation>
<translation id="5967867314010545767">GeçmiÅŸten kaldır.</translation>
<translation id="5975083100439434680">Uzaklaştır</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Otomatik</translation>
<translation id="6042308850641462728">Daha fazla</translation>
<translation id="6060685159320643512">Dikkatli olun, bu deneyler canınızı yakabilir</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{yok}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Kabloları kontrol edin ve kullandığınız yönlendiricileri, modemleri
veya diğer ağ cihazlarını yeniden başlatın.</translation>
<translation id="614940544461990577">Aşağıdakileri deneyin:</translation>
<translation id="6150607114729249911">Hata! Bu sayfayı ziyaret etmenizin uygun olup olmadığını ebeveynlerinize sormanız gerekiyor.</translation>
<translation id="6151417162996330722">Sunucu sertifikasının geçerlilik dönemi çok uzun.</translation>
-<translation id="6154808779448689242">DöndĂ¼rĂ¼len politika jetonu mevcut jetondan farklı</translation>
<translation id="6165508094623778733">Daha fazla bilgi edinin</translation>
<translation id="6203231073485539293">İnternet bağlantınızı kontrol edin</translation>
<translation id="6218753634732582820">Adres Chromium'dan kaldırılsın mı?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">AÄŸ tahmin özelliÄŸini devre dışı bırakmayı deneyin</translation>
<translation id="6337534724793800597">Politikalara ada göre filtre uygula</translation>
<translation id="6342069812937806050">Az önce</translation>
+<translation id="6345221851280129312">bilinmeyen boyut</translation>
<translation id="6355080345576803305">Herkese açık oturumu geçersiz kılma</translation>
<translation id="6358450015545214790">Bunlar ne anlama geliyor?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 öneri daha}other{# öneri daha}}</translation>
<translation id="6387478394221739770">Chrome'daki etkileyici, yeni özellikler ilginizi çekiyor mu? chrome.com/beta adresinden beta kanalımızı deneyin.</translation>
-<translation id="641480858134062906"><ph name="URL" /> yĂ¼klenemedi</translation>
+<translation id="6389758589412724634">Bu web sayfası görĂ¼ntĂ¼lenmeye çalışılırken Chromium'da bellek kalmadı.</translation>
+<translation id="6416403317709441254"><ph name="SITE" /> web sitesi Chromium'un iÅŸleyemediÄŸi karışık kimlik bilgileri gönderdiÄŸinden bu web sitesini ÅŸu anda ziyaret edemezsiniz. AÄŸ hataları ve saldırılar genellikle geçici tĂ¼rdendir, dolayısıyla bu sayfa muhtemelen daha sonra çalışacaktır. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">Sertifikanın iptal edilip edilmediği kontrol edilemiyor.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> bağlanmayı reddetti.</translation>
<translation id="6445051938772793705">Ăœlke</translation>
<translation id="6451458296329894277">Yeniden Form Gönderme Ä°ÅŸlemini Onayla</translation>
<translation id="6458467102616083041">Varsayılan arama politika tarafından devre dışı bırakıldığı için yoksayıldı.</translation>
+<translation id="6462969404041126431">Bu sunucu, <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası iptal edilmiÅŸ olabilir. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">Cihaz politikaları</translation>
<translation id="6489534406876378309">Kilitlenmeleri yĂ¼klemeye baÅŸla</translation>
<translation id="6529602333819889595">Silmeyi &amp;Yeniden Yap</translation>
+<translation id="6534179046333460208">Fiziksel Web önerileri</translation>
<translation id="6550675742724504774">Seçenekler</translation>
+<translation id="6593753688552673085"><ph name="UPPER_ESTIMATE" />'tan az</translation>
<translation id="6596325263575161958">Åifreleme seçenekleri</translation>
<translation id="662080504995468778">Kal</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> Arama</translation>
-<translation id="6634865548447745291"><ph name="BEGIN_LINK" />Bu sertifika iptal edildiÄŸi<ph name="END_LINK" /> için <ph name="SITE" /> sitesini ÅŸu anda ziyaret edemezsiniz. AÄŸ hataları ve saldırılar genellikle geçici olduÄŸundan, bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
<translation id="6644283850729428850">Bu politika uygun bulunmadı.</translation>
+<translation id="6652240803263749613">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. Bilgisayarınızın iÅŸletim sistemi, sunucunun gĂ¼venlik sertifikasına gĂ¼venmiyor. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">KlasörĂ¼ DĂ¼zenleyin</translation>
<translation id="6660210980321319655"><ph name="CRASH_TIME" /> tarihinde otomatik olarak rapor edildi</translation>
<translation id="6671697161687535275">Form önerisi Chromium'dan kaldırılsın mı?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">Ă–nceki</translation>
<translation id="6710594484020273272">&lt;Arama terimini yazın&gt;</translation>
<translation id="6711464428925977395">Proxy sunucusunda bir sorun var veya adres yanlış.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{yok}=1{1 Ă¶ÄŸe}other{# Ă¶ÄŸe}}</translation>
<translation id="674375294223700098">Bilinmeyen sunucu sertifikası hatası.</translation>
<translation id="6753269504797312559">Politika deÄŸeri</translation>
<translation id="6757797048963528358">Cihazınız uyku moduna geçti.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">Politika dĂ¼zeyi desteklenmiyor.</translation>
<translation id="6895330447102777224">Kartınız onaylandı</translation>
<translation id="6897140037006041989">Kullanıcı Aracısı</translation>
-<translation id="6903907808598579934">Senkronizasyonu aç</translation>
<translation id="6915804003454593391">Kullanıcı:</translation>
<translation id="6957887021205513506">Sunucunun sertifikası sahte görĂ¼nĂ¼yor.</translation>
<translation id="6965382102122355670">Tamam</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Bölge</translation>
<translation id="6973656660372572881">Hem sabit proxy sunucular hem de bir .pac komut dosyası URL'si belirtildi.</translation>
<translation id="6989763994942163495">GeliÅŸmiÅŸ ayarları göster...</translation>
+<translation id="7000990526846637657">GeçmiÅŸ giriÅŸi bulunamadı</translation>
+<translation id="7009986207543992532"><ph name="DOMAIN" /> alan adına eriÅŸmeyi denediniz ancak sunucu, geçerlilik dönemi gĂ¼venilir olmayacak kadar uzun olan bir sertifika sundu. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985"><ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> adresinde Google Hesabınıza iliÅŸkin baÅŸka biçimlerde tarama geçmiÅŸi olabilir.</translation>
<translation id="7029809446516969842">Åifreler</translation>
-<translation id="7050187094878475250"><ph name="DOMAIN" /> alan adına eriÅŸmeyi denediniz, ancak sunucu, geçerlilik dönemi gĂ¼venilir olmayacak kadar uzun olan bir sertifika sundu.</translation>
<translation id="7087282848513945231">İlçe</translation>
<translation id="7088615885725309056">Daha eski</translation>
<translation id="7090678807593890770">Google'da <ph name="LINK" /> araması yapın</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Ä°lk kez ziyaret ettiÄŸiniz yeni siteleri önce yöneticinizin onaylaması gerektiÄŸi için bu iletiyi görĂ¼yorsunuz.</translation>
<translation id="724975217298816891">Kart ayrıntılarınızı gĂ¼ncellemek için <ph name="CREDIT_CARD" /> numaralı karta iliÅŸkin son kullanma tarihini ve CVC kodunu girin. Onayladığınızda kart ayrıntılarınız bu siteyle paylaşılacaktır.</translation>
<translation id="725866823122871198">Bilgisayarınızın tarih ve saati (<ph name="DATE_AND_TIME" />) yanlış olduğundan <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> alan adına gizli bir bağlantı kurulamıyor.</translation>
-<translation id="7265986070661382626"><ph name="SITE" /> web sitesi <ph name="BEGIN_LINK" />sertifika sabitleme yöntemini kullandığı<ph name="END_LINK" /> için web sitesini ÅŸu anda ziyaret edemezsiniz. AÄŸ hataları ve saldırılar genellikle geçici olduÄŸundan, bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
<translation id="7269802741830436641">Bu web sayfasında yönlendirme döngĂ¼sĂ¼ var</translation>
<translation id="7275334191706090484">Yönetilen Yer Ä°ÅŸaretleri</translation>
<translation id="7298195798382681320">Ă–nerilenler</translation>
-<translation id="7301833672208172928">GeçmiÅŸ senkronizasyonunu aç</translation>
+<translation id="7309308571273880165">Kilitlenme raporu yakalandı (<ph name="CRASH_TIME" />) (yĂ¼kleme kullanıcı tarafından istendi, ancak henĂ¼z yĂ¼klenmedi)</translation>
<translation id="7334320624316649418">Sıralama değişikliğini &amp;yeniden yap</translation>
<translation id="733923710415886693">Sunucunun sertifikası, Sertifika Åeffaflığı aracılığıyla açıklanmadı.</translation>
+<translation id="7351800657706554155">Sertifikası iptal edildiÄŸi için <ph name="SITE" /> web sitesini ÅŸu anda ziyaret edemezsiniz. AÄŸ hataları ve saldırılar genellikle geçici olduÄŸundan, bu sayfa muhtemelen daha sonra çalışacaktır. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">Komut Satırı</translation>
<translation id="7372973238305370288">arama sonucu</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="7469372306589899959">Kart onaylanıyor</translation>
<translation id="7481312909269577407">Ä°leri</translation>
<translation id="7485870689360869515">Hiçbir veri bulunamadı.</translation>
+<translation id="7508255263130623398">DöndĂ¼rĂ¼len politika cihaz kimliÄŸi boÅŸ veya mevcut cihaz kimliÄŸiyle eÅŸleÅŸmiyor</translation>
<translation id="7514365320538308">Ä°ndir</translation>
<translation id="7518003948725431193">Åu web adresi için web sayfası bulunamadı:<ph name="URL" /></translation>
<translation id="7537536606612762813">Zorunlu</translation>
<translation id="7542995811387359312">Bu form gĂ¼venli baÄŸlantı kullanmadığından kredi kartı bilgilerini otomatik doldurma özelliÄŸi devre dışı bırakıldı.</translation>
<translation id="7549584377607005141">Bu Web sayfasının dĂ¼zgĂ¼n ÅŸekilde görĂ¼ntĂ¼lenmesi için, önceden girdiÄŸiniz veriler gerekiyor. Bu verileri tekrar gönderebilirsiniz, ancak bunu yaptığınızda bu sayfanın daha önce gerçekleÅŸtirdiÄŸi iÅŸlemler de tekrar edilir.</translation>
<translation id="7554791636758816595">Yeni Sekme</translation>
-<translation id="7567204685887185387">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. GĂ¼venlik sertifikası hileli bir ÅŸekilde yayınlanmış olabilir. Bu durum, bir yanlış yapılandırmadan veya baÄŸlantıya mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="7568593326407688803">Bu sayfanın dili<ph name="ORIGINAL_LANGUAGE" />Çevrilmesini istiyor musunuz?</translation>
<translation id="7569952961197462199">Kredi kartı Chrome'dan kaldırılsın mı?</translation>
<translation id="7578104083680115302">Google'a kaydettiÄŸiniz kartları kullanarak farklı cihazlardan sitelerde ve uygulamalarda ödemelerinizi hızla yapabilirsiniz.</translation>
+<translation id="7588950540487816470">Fiziksel Web</translation>
<translation id="7592362899630581445">Sunucunun sertifikası ad sınırlamasını ihlal ediyor.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> şu anda bu isteği işleme alamıyor.</translation>
<translation id="7600965453749440009"><ph name="LANGUAGE" /> dilini asla çevirme</translation>
@@ -561,6 +595,7 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="7637571805876720304">Kredi kartı Chromium'dan kaldırılsın mı?</translation>
<translation id="765676359832457558">Gelişmiş ayarları gizle...</translation>
<translation id="7658239707568436148">Ä°ptal</translation>
+<translation id="7667346355482952095">DöndĂ¼rĂ¼len politika jetonu boÅŸ veya mevcut jetonla eÅŸleÅŸmiyor</translation>
<translation id="7668654391829183341">Bilinmeyen cihaz</translation>
<translation id="7674629440242451245">Chrome'daki etkileyici, yeni özellikler ilginizi çekiyor mu? chrome.com/dev adresinden geliÅŸtirici kanalımızı deneyin.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" /><ph name="SITE" /> sitesine ilerle (gĂ¼venli deÄŸil)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="780301667611848630">Hayır, teÅŸekkĂ¼rler</translation>
<translation id="7805768142964895445">Durum</translation>
<translation id="7813600968533626083">Form önerisi Chrome'dan kaldırılsın mı?</translation>
+<translation id="7815407501681723534">"<ph name="SEARCH_STRING" />" için <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> bulundu.</translation>
<translation id="785549533363645510">Ancak görĂ¼nmez olmazsınız. Gizli moda geçmek göz atma etkinliÄŸinizi iÅŸvereninizden, Ä°nternet servis saÄŸlayıcınızdan veya ziyaret ettiÄŸiniz web sitelerinden gizlemez.</translation>
<translation id="7887683347370398519">CVC'nizi kontrol edin ve tekrar deneyin</translation>
<translation id="7894616681410591072">Hata! Bu sayfaya eriÅŸmeniz için <ph name="NAME" /> size izin vermelidir.</translation>
-<translation id="790025292736025802"><ph name="URL" /> bulunamadı</translation>
<translation id="7912024687060120840">BulunduÄŸu Klasör:</translation>
<translation id="7920092496846849526">Ebeveyninize bu sayfayı ziyaret etmenizin uygun olup olmadığını sordunuz.</translation>
<translation id="7935318582918952113">DOM Ayrıştırıcı</translation>
@@ -593,9 +628,10 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="7995512525968007366">Belirtilmedi</translation>
<translation id="8012647001091218357">Åu anda ebeveynlerinize eriÅŸemedik. LĂ¼tfen tekrar deneyin.</translation>
<translation id="8034522405403831421">Bu sayfa <ph name="SOURCE_LANGUAGE" /> dilinde. <ph name="TARGET_LANGUAGE" /> diline çevrilsin mi?</translation>
-<translation id="8034955203865359138">GeçmiÅŸ giriÅŸi bulunamadı.</translation>
<translation id="8088680233425245692">Makale görĂ¼ntĂ¼lenemedi.</translation>
+<translation id="8089520772729574115">1 MB'tan az</translation>
<translation id="8091372947890762290">EtkinleÅŸtirme sunucuda bekliyor</translation>
+<translation id="8129262335948759431">bilinmeyen miktar</translation>
<translation id="8131740175452115882">Onayla</translation>
<translation id="8134994873729925007"><ph name="HOST_NAME" /> ana makinesinin sunucu <ph name="BEGIN_ABBR" />DNS adresi<ph name="END_ABBR" /> bulunamadı.</translation>
<translation id="8149426793427495338">Bilgisayarınız uyku moduna geçti.</translation>
@@ -604,6 +640,7 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" kodlu uzantı için geçersiz gĂ¼ncelleme URL'si.</translation>
<translation id="8218327578424803826">Atanan Konum:</translation>
<translation id="8225771182978767009">Bu bilgisayarı kuran kiÅŸi bu siteyi engellemeyi seçmiÅŸ.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Aradığınız sayfa, girdiÄŸiniz bilgileri kullandı. O sayfaya dönmeniz, gerçekleÅŸtirdiÄŸiniz iÅŸlemlerin tekrarlanmasına yol açabilir. Devam etmek istiyor musunuz?</translation>
<translation id="8249320324621329438">Son getirilen:</translation>
<translation id="8261506727792406068">Sil</translation>
@@ -616,12 +653,17 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="8349305172487531364">Yer iÅŸaretleri çubuÄŸu</translation>
<translation id="8363502534493474904">Uçak modunu kapatma</translation>
<translation id="8364627913115013041">HenĂ¼z ayarlanmadı.</translation>
+<translation id="8380941800586852976">Tehlikeli</translation>
<translation id="8412145213513410671">Kilitlenme Sayısı (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Aynı parolayı iki kez girmelisiniz.</translation>
<translation id="8428213095426709021">Ayarlar</translation>
+<translation id="8433057134996913067">Bu iÅŸlem, çoÄŸu web sitesinden çıkış yapmanıza neden olacak.</translation>
<translation id="8437238597147034694">Taşımayı &amp;geri al</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 kredi kartı}other{# kredi kartı}}</translation>
+<translation id="8483780878231876732">Google Hesabınızda kayıtlı kartları kullanmak için Chrome'da oturum açın</translation>
<translation id="8488350697529856933">Uygulandığı yer</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ana makinesinin yanıt vermesi çok uzun sĂ¼rdĂ¼.</translation>
+<translation id="852346902619691059">Bu sunucu <ph name="DOMAIN" /> olduÄŸunu kanıtlayamadı. Cihazınızın iÅŸletim sistemi, sunucunun gĂ¼venlik sertifikasına gĂ¼venmiyor. Bu durum, yanlış yapılandırmadan veya baÄŸlantınıza mĂ¼dahale eden bir saldırgandan kaynaklanıyor olabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi edinin<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Google Payments, bu kart tĂ¼rĂ¼nĂ¼ desteklememektedir. LĂ¼tfen farklı bir kart seçin.</translation>
<translation id="8550022383519221471">Senkronizasyon hizmeti alan adınızda kullanılamıyor.</translation>
<translation id="8553075262323480129">Sayfanın dili belirlenemediÄŸinden çeviri baÅŸarısız oldu.</translation>
@@ -633,15 +675,12 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="8647750283161643317">TĂ¼mĂ¼nĂ¼ varsayılan deÄŸerlere sıfırla</translation>
<translation id="8680787084697685621">Hesap oturum açma ayrıntıları eski.</translation>
<translation id="8703575177326907206"><ph name="DOMAIN" /> bağlantınız şifrelenmedi.</translation>
-<translation id="8713130696108419660">BaÅŸlangıç anahtarlı imza bozuk</translation>
<translation id="8725066075913043281">Yeniden dene</translation>
<translation id="8728672262656704056">Gizli moda geçtiniz</translation>
<translation id="8730621377337864115">Bitti</translation>
<translation id="8738058698779197622">GĂ¼venli bir baÄŸlantı kurmak için saatinizin doÄŸru ayarlanmış olması gerekir. Bunun sebebi, web sitelerinin kendilerini tanımlamak için kullandıkları sertifikaların sadece belli sĂ¼reler için geçerli olmasıdır. Cihazınızın saati yanlış olduÄŸundan, Chromium bu sertifikaları doÄŸrulayamaz.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> ana makinesinin &lt;abbr id="dnsDefinition"&gt;DNS adresi&lt;/abbr&gt; bulunamadı. Sorun teşhis ediliyor.</translation>
-<translation id="8741995161408053644">Google Hesabınızın <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> adresinde baÅŸka biçimlerde tarama geçmiÅŸi olabilir.</translation>
<translation id="8790007591277257123">Silmeyi &amp;yeniden yap</translation>
-<translation id="8790687370365610530">Google tarafından önerilen kiÅŸiselleÅŸtirilmiÅŸ içeriÄŸi almak için geçmiÅŸ senkronizasyonunu açın.</translation>
<translation id="8798099450830957504">Varsayılan</translation>
<translation id="8804164990146287819">Gizlilik Politikası</translation>
<translation id="8820817407110198400">Favoriler</translation>
@@ -663,13 +702,11 @@ Hatırlatma! Bir dahaki sefere Gizli mod <ph name="SHORTCUT_KEY" /> kullanışlÄ
<translation id="8971063699422889582">Sunucu sertifikasının sĂ¼resi doldu.</translation>
<translation id="8987927404178983737">Ay</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Sunucu, Sertifika Åeffaflığı politikası kullanılarak herkese açık bir ÅŸekilde açıklanmayan bir sertifika sundu. GĂ¼venilir olduklarından emin olmak ve saldırganlara karşı koruma saÄŸlamak için bazı sertifikalarda bu zorunludur.</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> proxy'si için kullanıcı adı ve ÅŸifre gerekiyor.</translation>
<translation id="901974403500617787">TĂ¼m sistem için geçerli olan iÅŸaretler sadece sahibi <ph name="OWNER_EMAIL" /> tarafından ayarlanabilir.</translation>
<translation id="9020542370529661692">Bu sayfa <ph name="TARGET_LANGUAGE" /> diline çevrildi</translation>
<translation id="9038649477754266430">Sayfaları daha hızlı yĂ¼klemek için bir tahmin hizmeti kullan</translation>
<translation id="9039213469156557790">Ayrıca, bu sayfa gĂ¼venli olmayan baÅŸka kaynaklar içeriyor. Bu kaynaklar, aktarım sırasında baÅŸkaları tarafından görĂ¼lebilir ve bir saldırgan tarafından sayfanın davranışını deÄŸiÅŸtirmek Ă¼zere kullanılabilir.</translation>
-<translation id="9049981332609050619"><ph name="DOMAIN" /> alan adına eriÅŸmeye çalıştınız, ancak sunucu geçersiz bir sertifika saÄŸladı.</translation>
<translation id="9050666287014529139">Parola</translation>
<translation id="9065203028668620118">DĂ¼zenle</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> sayfası çalışmıyor</translation>
diff --git a/chromium/components/strings/components_strings_uk.xtb b/chromium/components/strings/components_strings_uk.xtb
index a48c523ce42..c025e66260c 100644
--- a/chromium/components/strings/components_strings_uk.xtb
+++ b/chromium/components/strings/components_strings_uk.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="uk">
+<translation id="1008557486741366299">Đе Đ·Đ°Ñ€Đ°Đ·</translation>
<translation id="1015730422737071372">ĐĐ°Đ´Đ°Ñ‚Đ¸ Đ´Đ¾Đ´Đ°Ñ‚ĐºĐ¾Đ²Ñƒ Ñ–Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ</translation>
<translation id="1032854598605920125">ĐĐ±ĐµÑ€Đ½ÑƒÑ‚Đ¸ Đ·Đ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºĐ¾Đ²Đ¾Ñ ÑÑ‚Ñ€Ñ–Đ»ĐºĐ¾Ñ</translation>
<translation id="1038842779957582377">ĐĐµĐ²Ñ–Đ´Đ¾Đ¼Đµ Ñ–Đ¼â€™Ñ</translation>
+<translation id="1053591932240354961">Đ—Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="SITE" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚ Đ½Đ°Đ´Ñ–ÑĐ»Đ°Đ² Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Ñ– Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Ñ– Đ´Đ°Đ½Ñ–, ÑĐºÑ– Google Chrome Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ¾Đ±Ñ€Đ¾Đ±Đ¸Ñ‚Đ¸. ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ¸ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ¹ Đ°Ñ‚Đ°ĐºĐ¸ Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Ñ–, Ñ‚Đ¾Đ¼Ñƒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ°, ÑĐºĐ¾Ñ€Ñ–Ñˆ Đ·Đ° Đ²Ñе, Đ·Đ°Đ¿Ñ€Đ°Ñ†ÑÑ” Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;Đ’Ñ–Đ´Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ Đ´Đ¾Đ´Đ°Đ²Đ°Đ½Đ½Ñ</translation>
<translation id="10614374240317010">ĐÑ–ĐºĐ¾Đ»Đ¸ Đ½Đµ Đ·Đ±ĐµÑ€Ñ–Đ³Đ°Đ»Đ¾ÑÑ</translation>
-<translation id="1064422015032085147">Đ¡ĐµÑ€Đ²ĐµÑ€, Đ½Đ° ÑĐºĐ¾Đ¼Ñƒ Ñ€Đ¾Đ·Đ¼Ñ–Ñ‰ĐµĐ½Đ¾ Ñ†Ñ Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ, Đ¿ĐµÑ€ĐµĐ²Đ°Đ½Ñ‚Đ°Đ¶ĐµĐ½Đ¸Đ¹ Đ°Đ±Đ¾ Đ¿Ñ€Đ¾Ñ…Đ¾Đ´Đ¸Ñ‚ÑŒ Ñ‚ĐµÑ…Đ½Ñ–Ñ‡Đ½Đµ Đ¾Đ±ÑĐ»ÑƒĐ³Đ¾Đ²ÑƒĐ²Đ°Đ½Đ½Ñ.
- Đ©Đ¾Đ± ÑƒĐ½Đ¸ĐºĐ½ÑƒÑ‚Đ¸ Đ½Đ°Đ´Đ¼Ñ–Ñ€Đ½Đ¾Đ³Đ¾ Ñ‚Ñ€Đ°Ñ„Ñ–ĐºÑƒ Ñ‚Đ° Đ½Đµ Đ¿Đ¾Đ³Ñ–Ñ€ÑˆĐ¸Ñ‚Đ¸ ÑĐ¸Ñ‚ÑƒĐ°Ñ†Ñ–Ñ,
- Đ·Đ°Đ¿Đ¸Ñ‚Đ¸ Đ½Đ° Ñ†Ñ URL-Đ°Đ´Ñ€ĐµÑу Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Đ¾ Đ½Đµ Đ½Đ°Đ´ÑилаÑÑ‚ÑŒÑÑ.</translation>
<translation id="106701514854093668">Đ—Đ°ĐºĐ»Đ°Đ´ĐºĐ¸ Đ´Đ»Ñ Đ½Đ°ÑÑ‚Ñ–Đ»ÑŒĐ½Đ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ°</translation>
<translation id="1080116354587839789">Đ—Đ° ÑˆĐ¸Ñ€Đ¸Đ½Đ¾Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸</translation>
+<translation id="1103124106085518534">Đ“Đ¾Ñ‚Đ¾Đ²Đ¾</translation>
<translation id="1103523840287552314">Đ—Đ°Đ²Đ¶Đ´Đ¸ Đ¿ĐµÑ€ĐµĐºĐ»Đ°Đ´Đ°Ñ‚Đ¸ Đ· Ñ‚Đ°ĐºĐ¾Ñ— Đ¼Đ¾Đ²Đ¸: <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Đ¯ĐºÑ‰Đ¾ Đ²Đ¸Đ±Ñ€Đ°Ñ‚Đ¸ Ñ†Ñ Đ¾Đ¿Ñ†Ñ–Ñ, Chrome Đ·Đ±ĐµÑ€Ñ–Đ³Đ°Ñ‚Đ¸Đ¼Đµ ĐºĐ¾Đ¿Ñ–Ñ Đ´Đ°Đ½Đ¸Ñ… Đ²Đ°ÑˆĐ¾Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸ Đ½Đ° Ñ†ÑŒĐ¾Đ¼Ñƒ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ— Đ´Đ»Ñ ÑˆĐ²Đ¸Đ´ÑˆĐ¾Đ³Đ¾ Đ·Đ°Đ¿Đ¾Đ²Đ½ĐµĐ½Đ½Ñ Ñ„Đ¾Ñ€Đ¼.</translation>
+<translation id="1111153019813902504">ĐÑÑ‚Đ°Đ½Đ½Ñ– Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
<translation id="1113869188872983271">&amp;Đ’Ñ–Đ´Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ Đ¿ĐµÑ€ĐµĐ²Đ¿Đ¾Ñ€ÑĐ´ĐºÑƒĐ²Đ°Đ½Đ½Ñ</translation>
+<translation id="1126551341858583091">ĐбÑÑĐ³ Đ»Đ¾ĐºĐ°Đ»ÑŒĐ½Đ¾Ñ— Đ¿Đ°Đ¼â€™ÑÑ‚Ñ– – <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">ĐĐµÑˆ-Đ¿Đ°Đ¼â€™ÑÑ‚ÑŒ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ° Đ½Đµ Đ¿Đ¾ÑˆĐºĐ¾Đ´Đ¶ĐµĐ½Đ¾</translation>
<translation id="113188000913989374">ĐŸĐ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½Đ½Ñ Ñ–Đ· ÑĐ°Đ¹Ñ‚Ñƒ <ph name="SITE" />:</translation>
<translation id="1132774398110320017">ĐĐ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½Đ½Ñ Đ°Đ²Ñ‚Đ¾Đ·Đ°Đ¿Đ¾Đ²Đ½ĐµĐ½Đ½Ñ Chrome…</translation>
-<translation id="1150979032973867961">Đ¦ĐµĐ¹ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ·Đ¼Ñ–Đ³ Đ´Đ¾Đ²ĐµÑÑ‚Đ¸, Ñ‰Đ¾ Đ²Ñ–Đ½ – Đ´Đ¾Đ¼ĐµĐ½ <ph name="DOMAIN" />. ĐĐ¿ĐµÑ€Đ°Ñ†Ñ–Đ¹Đ½Đ° ÑиÑÑ‚ĐµĐ¼Đ° Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ½Đµ Đ²Đ²Đ°Đ¶Đ°Ñ” Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ½Đ°Đ´Ñ–Đ¹Đ½Đ¸Đ¼. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
<translation id="1152921474424827756">Đ’Ñ–Đ´ĐºÑ€Đ¸Đ¹Ñ‚Đµ <ph name="BEGIN_LINK" />ĐºĐµÑˆĐ¾Đ²Đ°Đ½Ñƒ ĐºĐ¾Đ¿Ñ–Ñ<ph name="END_LINK" /> <ph name="URL" /></translation>
<translation id="1158211211994409885">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Đ½ĐµĐ¾Ñ‡Ñ–ĐºÑƒĐ²Đ°Đ½Đ¾ Ñ€Đ¾Đ·Ñ–Ñ€Đ²Đ°Đ² Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
<translation id="1161325031994447685">Đ·Đ½Đ¾Đ²Ñƒ Đ¿Ñ–Đ´â€™Ñ”Đ´Đ½Đ°Ñ‚Đ¸ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Ñ–Đ¹ Đ´Đ¾ Đ¼ĐµÑ€ĐµĐ¶Ñ– Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">Đ’Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸</translation>
<translation id="1201402288615127009">Đ”Đ°Đ»Ñ–</translation>
<translation id="1201895884277373915">Đ‘Ñ–Đ»ÑŒÑˆĐµ Đ· Ñ†ÑŒĐ¾Đ³Đ¾ ÑĐ°Đ¹Ñ‚Ñƒ</translation>
-<translation id="121201262018556460">Ви Đ¿Ñ€Đ¾Đ±ÑƒĐ²Đ°Đ»Đ¸ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />, Đ¿Ñ€Đ¾Ñ‚Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚, ÑĐºĐ¸Đ¹ Đ¼Ñ–ÑÑ‚Đ¸Ñ‚ÑŒ ÑĐ»Đ°Đ±ĐºĐ¸Đ¹ ĐºĐ»Ñч. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸Đº Đ·Đ»Đ°Đ¼Đ°Đ² ÑĐµĐºÑ€ĐµÑ‚Đ½Đ¸Đ¹ ĐºĐ»Ñч, Đ° ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Ñ” Ñ‚Đ¸Đ¼, ÑĐºĐ¸Đ¹ Đ²Đ°Đ¼ Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±ĐµĐ½ (Đ²Đ¸ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ¾Đ±Đ¼Ñ–Đ½ÑĐ²Đ°Ñ‚Đ¸ÑÑ Đ´Đ°Đ½Đ¸Đ¼Đ¸ Đ·Ñ– Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºĐ¾Đ¼).</translation>
+<translation id="1206967143813997005">ĐĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹ Đ¿Ñ–Đ´Đ¿Đ¸Ñ</translation>
+<translation id="1209206284964581585">ĐŸÑ€Đ¸Ñ…Đ¾Đ²Đ°Ñ‚Đ¸</translation>
<translation id="1219129156119358924">Đ‘ĐµĐ·Đ¿ĐµĐºĐ° ÑиÑÑ‚ĐµĐ¼Đ¸</translation>
<translation id="1227224963052638717">ĐĐµĐ²Ñ–Đ´Đ¾Đ¼Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾</translation>
<translation id="1227633850867390598">Đ¡Ñ…Đ¾Đ²Đ°Ñ‚Đ¸ Đ·Đ½Đ°Ñ‡ĐµĐ½Đ½Ñ</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">Ñ‚Đ°Đº</translation>
<translation id="1430915738399379752">Đ”Ñ€ÑƒĐº</translation>
<translation id="1442912890475371290">Đ—Đ°Đ±Đ»Đ¾ĐºĐ¾Đ²Đ°Đ½Đ¾ ÑĐ¿Ñ€Đ¾Đ±Ñƒ <ph name="BEGIN_LINK" />Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ Đ² Đ´Đ¾Đ¼ĐµĐ½Ñ– <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Đ—Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="SITE" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚ Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑ” Đ·Đ°ĐºÑ€Ñ–Đ¿Đ»ĐµĐ½Đ½Ñ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Ñ–Đ². ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ¸ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ¹ Đ°Ñ‚Đ°ĐºĐ¸ Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Ñ–, Ñ‚Đ¾Đ¼Ñƒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ°, ÑĐºĐ¾Ñ€Ñ–Ñˆ Đ·Đ° Đ²Ñе, Đ·Đ°Đ¿Ñ€Đ°Ñ†ÑÑ” Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">ĐŸĐ¾ĐºĐ°Đ·Đ°Ñ‚Đ¸ ÑÑ‚Đ°Ñ€Ñƒ Đ·Đ±ĐµÑ€ĐµĐ¶ĐµĐ½Ñƒ ĐºĐ¾Đ¿Ñ–Ñ Ñ†Ñ–Ñ”Ñ— ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸.</translation>
<translation id="1519264250979466059">Đ”Đ°Ñ‚Đ° ÑÑ‚Đ²Đ¾Ñ€ĐµĐ½Đ½Ñ Đ²ĐµÑ€ÑÑ–Ñ—</translation>
<translation id="1549470594296187301">Đ©Đ¾Đ± ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‚Đ¸ÑÑ Ñ†Ñ–Ñ”Ñ Ñ„ÑƒĐ½ĐºÑ†Ñ–Ñ”Ñ, Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±Đ½Đ¾ Đ²Đ²Ñ–Đ¼ĐºĐ½ÑƒÑ‚Đ¸ JavaScript.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">ĐĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ½ĐµĐ´Ñ–Đ¹ÑĐ½Đ° Ñ‚Đ° Đ½Đµ Đ¼Đ¾Đ¶Đµ Ñ–Đ¼Đ¿Đ¾Ñ€Ñ‚ÑƒĐ²Đ°Ñ‚Đ¸ÑÑ.</translation>
<translation id="1644574205037202324">ІÑÑ‚Đ¾Ñ€Ñ–Ñ</translation>
<translation id="1645368109819982629">ĐŸÑ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ» Đ½Đµ Đ¿Ñ–Đ´Ñ‚Ñ€Đ¸Đ¼ÑƒÑ”Ñ‚ÑŒÑÑ</translation>
-<translation id="1655462015569774233">{1,plural, =1{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ¿ĐµÑ€ĐµÑÑ‚Đ°Đ² Đ´Ñ–ÑÑ‚Đ¸ ÑƒÑ‡Đ¾Ñ€Đ°. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_DATE" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ.}one{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ¿ĐµÑ€ĐµÑÑ‚Đ°Đ² Đ´Ñ–ÑÑ‚Đ¸ # Đ´ĐµĐ½ÑŒ Ñ‚Đ¾Đ¼Ñƒ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_DATE" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ.}few{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ¿ĐµÑ€ĐµÑÑ‚Đ°Đ² Đ´Ñ–ÑÑ‚Đ¸ # Đ´Đ½Ñ– Ñ‚Đ¾Đ¼Ñƒ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_DATE" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ.}many{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ¿ĐµÑ€ĐµÑÑ‚Đ°Đ² Đ´Ñ–ÑÑ‚Đ¸ # Đ´Đ½Ñ–Đ² Ñ‚Đ¾Đ¼Ñƒ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_DATE" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ.}other{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ¿ĐµÑ€ĐµÑÑ‚Đ°Đ² Đ´Ñ–ÑÑ‚Đ¸ # Đ´Đ½Ñ Ñ‚Đ¾Đ¼Ñƒ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_DATE" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ.}}</translation>
<translation id="1676269943528358898">Веб-ÑĐ°Đ¹Ñ‚ <ph name="SITE" /> Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑ” ÑˆĐ¸Ñ„Ñ€ÑƒĐ²Đ°Đ½Đ½Ñ Đ´Đ»Ñ Đ·Đ°Ñ…Đ¸Ñту Đ²Đ°ÑˆĐ¾Ñ— Ñ–Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ—. ĐŸÑ–Đ´ Ñ‡Đ°Ñ Ñ†Ñ–Ñ”Ñ— ÑĐ¿Ñ€Đ¾Đ±Đ¸ Chrome Đ¿Ñ–Đ´â€™Ñ”Đ´Đ½Đ°Ñ‚Đ¸ÑÑ Đ´Đ¾ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸ <ph name="SITE" /> Đ· Đ½ĐµÑ— Đ¾Ñ‚Ñ€Đ¸Đ¼Đ°Đ½Đ¾ Đ½ĐµĐ·Đ²Đ¸Ñ‡Đ½Ñ– Đ¹ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Ñ– Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Ñ– Đ´Đ°Đ½Ñ–. Це Đ¼Đ¾Đ¶Đµ ÑÑ‚Đ°Ñ‚Đ¸ÑÑ, ĐºĐ¾Đ»Đ¸ Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸Đº Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ²Đ¸Đ´Đ°Đ²Đ°Ñ‚Đ¸ Ñебе Đ·Đ° Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚ <ph name="SITE" /> Đ°Đ±Đ¾ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ¿ĐµÑ€ĐµÑ€Đ²Đ°Đ½Đ¾ ĐµĐºÑ€Đ°Đ½Đ¾Đ¼ Đ²Ñ…Đ¾Đ´Ñƒ Wi-Fi. Đ’Đ°ÑˆĐ° Ñ–Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ Đ·Đ°Đ»Đ¸ÑˆĐ°Ñ”Ñ‚ÑŒÑÑ Đ·Đ°Ñ…Đ¸Ñ‰ĐµĐ½Đ¾Ñ, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Chrome Đ¿Ñ€Đ¸Đ¿Đ¸Đ½Đ¸Đ² Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ´Đ¾ Ñ‚Đ¾Đ³Đ¾, ÑĐº Đ¿Đ¾Ñ‡Đ°Đ²ÑÑ Đ¾Đ±Đ¼Ñ–Đ½ Đ±ÑƒĐ´ÑŒ-ÑĐºĐ¸Đ¼Đ¸ Đ´Đ°Đ½Đ¸Đ¼Đ¸.</translation>
<translation id="168841957122794586">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ¼Ñ–ÑÑ‚Đ¸Ñ‚ÑŒ ÑĐ»Đ°Đ±ĐºĐ¸Đ¹ ĐºÑ€Đ¸Đ¿Ñ‚Đ¾Đ³Ñ€Đ°Ñ„Ñ–Ñ‡Đ½Đ¸Đ¹ ĐºĐ»Ñч.</translation>
<translation id="1701955595840307032">ĐÑ‚Ñ€Đ¸Đ¼ÑƒĐ²Đ°Ñ‚Đ¸ Đ¿Ñ€Đ¾Đ¿Đ¾Đ½Đ¾Đ²Đ°Đ½Đ¸Đ¹ Đ²Đ¼Ñ–ÑÑ‚</translation>
-<translation id="1706954506755087368">{1,plural, =1{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ‡Đ½Đµ Đ´Ñ–ÑÑ‚Đ¸ Đ·Đ°Đ²Ñ‚Ñ€Đ°. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–.}one{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ‡Đ½Đµ Đ´Ñ–ÑÑ‚Đ¸ Ñ‡ĐµÑ€ĐµĐ· # Đ´ĐµĐ½ÑŒ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–.}few{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ‡Đ½Đµ Đ´Ñ–ÑÑ‚Đ¸ Ñ‡ĐµÑ€ĐµĐ· # Đ´Đ½Ñ–. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–.}many{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ‡Đ½Đµ Đ´Ñ–ÑÑ‚Đ¸ Ñ‡ĐµÑ€ĐµĐ· # Đ´Đ½Ñ–Đ². ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–.}other{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ‡Đ½Đµ Đ´Ñ–ÑÑ‚Đ¸ Ñ‡ĐµÑ€ĐµĐ· # Đ´Đ½Ñ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–.}}</translation>
<translation id="1710259589646384581">ĐĐ¡</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Đ—Đ²â€™ÑĐ¶Ñ–Ñ‚ÑŒÑÑ Ñ–Đ· ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¼ Đ°Đ´Đ¼Ñ–Đ½Ñ–ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Đ¾Đ¼.</translation>
<translation id="17513872634828108">Đ’Ñ–Đ´ĐºÑ€Đ¸Ñ‚Ñ– Đ²ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
<translation id="1753706481035618306">ĐĐ¾Đ¼ĐµÑ€ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸</translation>
-<translation id="1761412452051366565">Đ©Đ¾Đ± Đ¾Ñ‚Ñ€Đ¸Đ¼ÑƒĐ²Đ°Ñ‚Đ¸ Đ¿ĐµÑ€ÑĐ¾Đ½Đ°Đ»Ñ–Đ·Đ¾Đ²Đ°Đ½Ñ– Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ— Đ²Ñ–Đ´ Google, ÑƒĐ²Ñ–Đ¼ĐºĐ½Ñ–Ñ‚ÑŒ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ°Ñ†Ñ–Ñ.</translation>
-<translation id="1763864636252898013">Đ¦ĐµĐ¹ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ·Đ¼Ñ–Đ³ Đ´Đ¾Đ²ĐµÑÑ‚Đ¸, Ñ‰Đ¾ Đ²Ñ–Đ½ – Đ´Đ¾Đ¼ĐµĐ½ <ph name="DOMAIN" />. ĐĐ¿ĐµÑ€Đ°Ñ†Ñ–Đ¹Đ½Đ° ÑиÑÑ‚ĐµĐ¼Đ° Đ²Đ°ÑˆĐ¾Đ³Đ¾ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ Đ½Đµ Đ²Đ²Đ°Đ¶Đ°Ñ” Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ½Đ°Đ´Ñ–Đ¹Đ½Đ¸Đ¼. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ²ĐµĐ´Ñ–Ñ‚ÑŒ Đ´Ñ–Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ Đ¼ĐµÑ€ĐµĐ¶Ñ– Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">ĐĐ½Đ¾Đ²Ñ–Ñ‚ÑŒ Đ¿Đ°Ñ€Đ¾Đ»ÑŒĐ½Ñƒ Ñ„Ñ€Đ°Đ·Ñƒ Đ´Đ»Ñ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ°Ñ†Ñ–Ñ—.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Đ¢ÑƒÑ‚ Đ²Ñ–Đ´Đ¾Đ±Ñ€Đ°Đ¶Đ°Ñ‚Đ¸Đ¼ÑƒÑ‚ÑŒÑÑ Đ½ĐµÑ‰Đ¾Đ´Đ°Đ²Đ½Đ¾ Đ²Ñ–Đ´ĐºÑ€Đ¸Ñ‚Ñ– Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ¸.</translation>
<translation id="1821930232296380041">ĐĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹ Đ·Đ°Đ¿Đ¸Ñ‚ Đ°Đ±Đ¾ Đ¿Đ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ¸ Đ·Đ°Đ¿Đ¸Ñ‚Ñƒ</translation>
<translation id="1838667051080421715">Ви Đ±Đ°Ñ‡Đ¸Ñ‚Đµ Đ´Đ¶ĐµÑ€ĐµĐ»Đ¾ Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸.</translation>
<translation id="1871208020102129563">ĐŸÑ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½Đ° Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ°Đ½Đ½Ñ Ñ„Ñ–ĐºÑĐ¾Đ²Đ°Đ½Đ¸Ñ… Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Ñ–Đ², Đ° Đ½Đµ URL-Đ°Đ´Ñ€ĐµÑи ÑÑ†ĐµĐ½Đ°Ñ€Ñ–Ñ .pac.</translation>
<translation id="1883255238294161206">Đ—Đ³Đ¾Ñ€Đ½ÑƒÑ‚Đ¸ ÑĐ¿Đ¸ÑĐ¾Đº</translation>
<translation id="1898423065542865115">Đ¤Ñ–Đ»ÑŒÑ‚Ñ€ÑƒĐ²Đ°Đ½Đ½Ñ</translation>
-<translation id="1911837502049945214">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Đ½Đµ Đ¿Ñ€Đ¸Đ¹Đ½ÑĐ² Đ²Đ°Ñˆ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ²Ñ…Đ¾Đ´Ñƒ Đ°Đ±Đ¾ Ñ‚ĐµÑ€Đ¼Ñ–Đ½ Đ´Ñ–Ñ— ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ° Đ·Đ°ĐºÑ–Đ½Ñ‡Đ¸Đ²ÑÑ.</translation>
<translation id="194030505837763158">ĐŸĐµÑ€ĐµĐ¹Đ´Ñ–Ñ‚ÑŒ Đ·Đ° Đ°Đ´Ñ€ĐµÑĐ¾Ñ <ph name="LINK" /></translation>
<translation id="1962204205936693436">Đ—Đ°ĐºĐ»Đ°Đ´ĐºĐ¸ <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° ÑĐµÑ€Ñ–Đ°Đ»Ñ–Đ·Đ°Ñ†Ñ–Ñ—</translation>
<translation id="1974060860693918893">Đ Đ¾Đ·ÑˆĐ¸Ñ€ĐµĐ½Ñ–</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{Ñ– Ñ‰Đµ 1}one{Ñ– Ñ‰Đµ #}few{Ñ– Ñ‰Đµ #}many{Ñ– Ñ‰Đµ #}other{Ñ– Ñ‰Đµ #}}</translation>
<translation id="2025186561304664664">ĐŸÑ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€ уÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ½Đ° Đ°Đ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đµ Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½Đ½Ñ.</translation>
<translation id="2030481566774242610">ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, Đ²Đ¸ Đ¼Đ°Đ»Đ¸ Đ½Đ° ÑƒĐ²Đ°Đ·Ñ– <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Ви Đ±Đ°Ñ‡Đ¸Ñ‚Đµ Ñ†Đµ Đ¿Đ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½Đ½Ñ, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²Đ°ÑˆÑ– Đ±Đ°Ñ‚ÑŒĐºĐ¸ Đ¼Đ°ÑÑ‚ÑŒ ÑÑ…Đ²Đ°Đ»Đ¸Ñ‚Đ¸ ÑĐ°Đ¹Ñ‚Đ¸, ÑĐºÑ– Đ²Đ¸ Đ²Ñ–Đ´Đ²Ñ–Đ´ÑƒÑ”Ñ‚Đµ Đ²Đ¿ĐµÑ€ÑˆĐµ.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€Đ¸Ñ‚Đ¸ Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€ Ñ– Đ±Ñ€Đ°Đ½Đ´Đ¼Đ°ÑƒĐµÑ€<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">ĐŸĐ¾ÑˆÑ‚Đ¾Đ²Đ¸Đ¹ Ñ–Đ½Đ´ĐµĐºÑ</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ}one{# Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ}few{# Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ—}many{# Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Đ¹}other{# Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ—}}</translation>
<translation id="2065985942032347596">ĐŸĐ¾Ñ‚Ñ€Ñ–Đ±Đ½Đ° Đ°Đ²Ñ‚ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ†Ñ–Ñ</translation>
<translation id="2079545284768500474">Đ¡ĐºĐ°ÑÑƒĐ²Đ°Ñ‚Đ¸</translation>
<translation id="20817612488360358">Đ¡Đ¸ÑÑ‚ĐµĐ¼Đ½Ñ– Đ¿Đ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ¸ Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ´Đ»Ñ Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ°Đ½Đ½Ñ, але Ñ‡Ñ–Ñ‚ĐºĐ¾ Đ²ĐºĐ°Đ·Đ°Đ½Đ¾ Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½Đ½Ñ Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Đ°.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Đ ĐµĐ´Đ°Đ³ÑƒĐ²Đ°Ñ‚Đ¸ Đ·Đ°ĐºĐ»Đ°Đ´ĐºÑƒ</translation>
<translation id="2166049586286450108">ĐŸĐ¾Đ²Đ½Đ¸Đ¹ Đ°Đ´Đ¼Ñ–Đ½Ñ–ÑÑ‚Ñ€Đ°Ñ‚Đ¸Đ²Đ½Đ¸Đ¹ Đ´Đ¾ÑÑ‚ÑƒĐ¿</translation>
<translation id="2166378884831602661">Đ¦ĐµĐ¹ ÑĐ°Đ¹Ñ‚ Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ·Đ°Đ±ĐµĐ·Đ¿ĐµÑ‡Đ¸Ñ‚Đ¸ Đ·Đ°Ñ…Đ¸Ñ‰ĐµĐ½Đµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ</translation>
-<translation id="2171101176734966184">Ви Đ¿Ñ€Đ¾Đ±ÑƒĐ²Đ°Đ»Đ¸ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />, Đ¿Ñ€Đ¾Ñ‚Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚, Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ°Đ½Đ¸Đ¹ Ñ–Đ· Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ°Đ½Đ½ÑĐ¼ ÑĐ»Đ°Đ±ĐºĐ¾Đ³Đ¾ Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚Đ¼Ñƒ Đ¿Ñ–Đ´Đ¿Đ¸Ñу. Це Đ¾Đ·Đ½Đ°Ñ‡Đ°Ñ”, Ñ‰Đ¾ Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Ñ– Đ´Đ°Đ½Ñ– ÑиÑÑ‚ĐµĐ¼Đ¸ Đ·Đ°Ñ…Đ¸Ñту, Đ½Đ°Đ´Đ°Đ½Ñ– ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼, Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ±ÑƒÑ‚Đ¸ ÑÑ„Đ°Đ»ÑŒÑĐ¸Ñ„Ñ–ĐºĐ¾Đ²Đ°Đ½Đ¸Đ¼Đ¸, Đ° ÑĐµÑ€Đ²ĐµÑ€ – Đ½Đµ Ñ‚Đ¸Đ¼, ÑĐºĐ¸Đ¹ Đ²Đ°Đ¼ Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±ĐµĐ½ (Đ¼Đ¾Đ¶Đ»Đ¸Đ²Đ¾, Đ²Đ¸ Đ¾Đ±Đ¼Ñ–Đ½ÑÑ”Ñ‚ĐµÑÑ Đ´Đ°Đ½Đ¸Đ¼Đ¸ Đ·Ñ– Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºĐ¾Đ¼).</translation>
<translation id="2181821976797666341">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ°</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 Đ°Đ´Ñ€ĐµÑĐ°}one{# Đ°Đ´Ñ€ĐµÑĐ°}few{# Đ°Đ´Ñ€ĐµÑи}many{# Đ°Đ´Ñ€ĐµÑ}other{# Đ°Đ´Ñ€ĐµÑи}}</translation>
<translation id="2212735316055980242">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ¾ Đ½Đµ Đ·Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾</translation>
<translation id="2213606439339815911">ĐÑ‚Ñ€Đ¸Đ¼Đ°Đ½Đ½Ñ Đ·Đ°Đ¿Đ¸ÑÑ–Đ²â€¦</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> Đ½ĐµĐ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Đ¸Đ¹</translation>
<translation id="2230458221926704099">Đ’Ñ–Đ´Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ·Đ° Đ´Đ¾Đ¿Đ¾Đ¼Đ¾Đ³Đ¾Ñ <ph name="BEGIN_LINK" />Đ´Đ¾Đ´Đ°Ñ‚ĐºĐ° Đ´Đ»Ñ Đ´Ñ–Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºĐ¸<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">ĐĐ°Đ´Ñ–ÑĐ»Đ°Ñ‚Đ¸</translation>
<translation id="225207911366869382">Đ”Ñ–Ñ Ñ†ÑŒĐ¾Đ³Đ¾ Đ·Đ½Đ°Ñ‡ĐµĐ½Đ½Ñ Đ¿Ñ€Đ¸Đ¿Đ¸Đ½ĐµĐ½Đ¾ Đ´Đ»Ñ Ñ†ÑŒĐ¾Đ³Đ¾ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°</translation>
<translation id="2262243747453050782">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° HTTP</translation>
<translation id="2282872951544483773">ĐĐµĐ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Ñ– ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ°Đ»ÑŒĐ½Ñ– Ñ„ÑƒĐ½ĐºÑ†Ñ–Ñ—</translation>
<translation id="2292556288342944218">Đ’Đ°Ñˆ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đ´Đ¾ Đ†Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚Ñƒ Đ·Đ°Đ±Đ»Đ¾ĐºĐ¾Đ²Đ°Đ½Đ¾</translation>
<translation id="229702904922032456">Đ¢ĐµÑ€Đ¼Ñ–Đ½ Đ´Ñ–Ñ— ĐºĐ¾Ñ€ĐµĐ½ĐµĐ²Đ¾Đ³Đ¾ Đ°Đ±Đ¾ Đ¿Ñ€Đ¾Đ¼Ñ–Đ¶Đ½Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ° Đ·Đ°ĐºÑ–Đ½Ñ‡Đ¸Đ²ÑÑ.</translation>
<translation id="230155334948463882">ĐĐ¾Đ²Đ° ĐºĐ°Ñ€Ñ‚ĐºĐ°?</translation>
+<translation id="2305919008529760154">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ²Đ¸Đ´Đ°Đ»Đ¸ ÑˆĐ°Ñ…Ñ€Đ°Ñ—. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535">Đ”Đ»Ñ ÑĐ°Đ¹Ñ‚Ñƒ <ph name="DOMAIN" /> Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±Đ½Đ¾ Đ²Đ²ĐµÑÑ‚Đ¸ Ñ–Đ¼â€™Ñ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Đ° Ñ‚Đ° Đ¿Đ°Ñ€Đ¾Đ»ÑŒ.</translation>
+<translation id="2318774815570432836">Đ—Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="SITE" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚ Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑ” Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ» HSTS. ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ¸ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ¹ Đ°Ñ‚Đ°ĐºĐ¸ Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Ñ–, Ñ‚Đ¾Đ¼Ñƒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ°, ÑĐºĐ¾Ñ€Ñ–Ñˆ Đ·Đ° Đ²Ñе, Đ·Đ°Đ¿Ñ€Đ°Ñ†ÑÑ” Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">ĐĐµĐ´Ñ–Đ¹ÑĐ½Đ° Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ° Đ² Ñ–Đ½Đ´ĐµĐºÑÑ– <ph name="ENTRY_INDEX" /> Ñ–Đ³Đ½Đ¾Ñ€ÑƒÑ”Ñ‚ÑŒÑÑ</translation>
<translation id="2354001756790975382">Đ†Đ½ÑˆÑ– Đ·Đ°ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
<translation id="2359808026110333948">ĐŸÑ€Đ¾Đ´Đ¾Đ²Đ¶Đ¸Ñ‚Đ¸</translation>
<translation id="2365563543831475020">Đ—Đ²Ñ–Ñ‚ Đ¿Ñ€Đ¾ Đ°Đ²Đ°Ñ€Ñ–Đ¹Đ½Đµ Đ·Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ½Ñ Ñ€Đ¾Đ±Đ¾Ñ‚Đ¸ Đ¾ <ph name="CRASH_TIME" /> Đ½Đµ Đ·Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶ĐµĐ½Đ¾</translation>
<translation id="2367567093518048410">Đ Ñ–Đ²ĐµĐ½ÑŒ</translation>
+<translation id="2371153335857947666">{1,plural, =1{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ¿ĐµÑ€ĐµÑÑ‚Đ°Đ² Đ´Ñ–ÑÑ‚Đ¸ Đ²Ñ‡Đ¾Ñ€Đ°. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_DATE" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}one{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ¿ĐµÑ€ĐµÑÑ‚Đ°Đ² Đ´Ñ–ÑÑ‚Đ¸ # Đ´ĐµĐ½ÑŒ Ñ‚Đ¾Đ¼Ñƒ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_DATE" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}few{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ¿ĐµÑ€ĐµÑÑ‚Đ°Đ² Đ´Ñ–ÑÑ‚Đ¸ # Đ´Đ½Ñ– Ñ‚Đ¾Đ¼Ñƒ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_DATE" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}many{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ¿ĐµÑ€ĐµÑÑ‚Đ°Đ² Đ´Ñ–ÑÑ‚Đ¸ # Đ´Đ½Ñ–Đ² Ñ‚Đ¾Đ¼Ñƒ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_DATE" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}other{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ¿ĐµÑ€ĐµÑÑ‚Đ°Đ² Đ´Ñ–ÑÑ‚Đ¸ # Đ´Đ½Ñ Ñ‚Đ¾Đ¼Ñƒ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_DATE" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">ĐĐµĐ¼Đ°Ñ” Đ²Đ°Ñ€Ñ–Đ°Đ½Ñ‚Ñ–Đ² Ñ–Đ½Ñ‚ĐµÑ€Ñ„ĐµĐ¹Ñу ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Đ°</translation>
<translation id="2384307209577226199">Đ¡Ñ‚Đ°Đ½Đ´Đ°Ñ€Ñ‚Đ½Đµ ĐºĐ¾Ñ€Đ¿Đ¾Ñ€Đ°Ñ‚Đ¸Đ²Đ½Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾</translation>
-<translation id="238526402387145295">Đ—Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="SITE" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚ <ph name="BEGIN_LINK" />Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑ” Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ» HSTS<ph name="END_LINK" />. ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ¸ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ¹ Đ°Ñ‚Đ°ĐºĐ¸ Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Ñ” Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Đ¸Đ¼Đ¸, Ñ‚Đ¾Đ¼Ñƒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ¼Đ¾Đ¶Đµ Đ¿Ñ€Đ°Ñ†ÑĐ²Đ°Ñ‚Đ¸ Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ.</translation>
<translation id="2386255080630008482">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ²Ñ–Đ´ĐºĐ»Đ¸ĐºĐ°Đ½Đ¾.</translation>
<translation id="2392959068659972793">ĐŸĐ¾ĐºĐ°Đ·ÑƒĐ²Đ°Ñ‚Đ¸ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°, Đ´Đ»Ñ ÑĐºĐ¸Ñ… Đ½Đµ Đ²ÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ·Đ½Đ°Ñ‡ĐµĐ½Đ½Ñ</translation>
<translation id="2396249848217231973">&amp;Đ’Ñ–Đ´Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ Đ²Đ¸Đ´Đ°Đ»ĐµĐ½Đ½Ñ</translation>
-<translation id="2413528052993050574">Đ¦ĐµĐ¹ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ·Đ¼Ñ–Đ³ Đ´Đ¾Đ²ĐµÑÑ‚Đ¸, Ñ‰Đ¾ Đ²Ñ–Đ½ – Đ´Đ¾Đ¼ĐµĐ½ <ph name="DOMAIN" />. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ²Ñ–Đ´ĐºĐ»Đ¸ĐºĐ°Đ½Đ¾. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
<translation id="2455981314101692989">ĐĐ° Ñ†Ñ–Đ¹ Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½Ñ†Ñ– Đ²Đ¸Đ¼ĐºĐ½ĐµĐ½Đ¾ Đ°Đ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đµ Đ·Đ°Đ¿Đ¾Đ²Đ½ĐµĐ½Đ½Ñ Ñ†Ñ–Ñ”Ñ— Ñ„Đ¾Ñ€Đ¼Đ¸.</translation>
+<translation id="2463739503403862330">Đ—Đ°Đ¿Đ¾Đ²Đ½Đ¸Ñ‚Đ¸</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Đ¿Ñ€Đ¾Đ²ĐµÑÑ‚Đ¸ Đ´Ñ–Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ Đ¼ĐµÑ€ĐµĐ¶Ñ–<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">ĐĐµĐ´Ñ–Đ¹ÑĐ½Đ° URL-Đ°Đ´Ñ€ĐµÑĐ° Đ´Đ»Ñ Đ¿Đ¾ÑˆÑƒĐºÑƒ.</translation>
<translation id="2491120439723279231">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ¼Ñ–ÑÑ‚Đ¸Ñ‚ÑŒ Đ¿Đ¾Đ¼Đ¸Đ»ĐºĐ¸.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">ĐĐ°Đ´Ñ–ÑĐ»Đ°Ñ‚Đ¸</translation>
<translation id="2674170444375937751">Ви Đ´Ñ–Đ¹ÑĐ½Đ¾ Đ±Đ°Đ¶Đ°Ñ”Ñ‚Đµ Đ²Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸ ці ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸ Đ·Ñ– ÑĐ²Đ¾Ñ”Ñ— Ñ–ÑÑ‚Đ¾Ñ€Ñ–Ñ—?</translation>
<translation id="2677748264148917807">Đ’Đ¸Đ¹Ñ‚Đ¸</translation>
+<translation id="269990154133806163">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ без Ñ–Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ— Đ¿Ñ€Đ¾ Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€ĐºÑƒ. Це Đ¾Đ±Đ¾Đ²â€™ÑĐ·ĐºĐ¾Đ²Ñ– Đ´Đ°Đ½Ñ– Đ´Đ»Ñ Đ´ĐµÑĐºĐ¸Ñ… ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Ñ–Đ². Đ’Đ¾Đ½Đ¸ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¶ÑƒÑÑ‚ÑŒ Đ½Đ°Đ´Ñ–Đ¹Đ½Ñ–ÑÑ‚ÑŒ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ° Đ¹ Đ·Đ°Ñ…Đ¸Ñ‰Đ°ÑÑ‚ÑŒ Đ²Ñ–Đ´ Đ°Ñ‚Đ°Đº Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºÑ–Đ². <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">Đ—Đ½Đ°Ñ‡ĐµĐ½Đ½Ñ Đ½Đµ Đ²Ñ–Đ´Đ¿Đ¾Đ²Ñ–Đ´Đ°Ñ” Ñ„Đ¾Ñ€Đ¼Đ°Ñ‚Ñƒ.</translation>
<translation id="2704951214193499422">Chromium Đ½Đµ Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸ Đ´Đ°Đ½Ñ– Đ²Đ°ÑˆĐ¾Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸. Đ¡Đ¿Ñ€Đ¾Đ±ÑƒĐ¹Ñ‚Đµ Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ.</translation>
<translation id="2705137772291741111">Đе Đ²Đ´Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿Ñ€Đ¾Ñ‡Đ¸Ñ‚Đ°Ñ‚Đ¸ Đ·Đ±ĐµÑ€ĐµĐ¶ĐµĐ½Ñƒ (ĐºĐµÑˆĐ¾Đ²Đ°Đ½Ñƒ) ĐºĐ¾Đ¿Ñ–Ñ Ñ†ÑŒĐ¾Đ³Đ¾ ÑĐ°Đ¹Ñ‚Ñƒ.</translation>
<translation id="2709516037105925701">ĐĐ²Ñ‚Đ¾Đ·Đ°Đ¿Đ¾Đ²Đ½ĐµĐ½Đ½Ñ</translation>
+<translation id="2712118517637785082">Ви Đ½Đ°Đ¼Đ°Đ³Đ°Đ»Đ¸ÑÑ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />, але ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚, Đ²Ñ–Đ´ĐºĐ»Đ¸ĐºĐ°Đ½Đ¸Đ¹ Đ¹Đ¾Đ³Đ¾ Đ²Đ¸Đ´Đ°Đ²Ñ†ĐµĐ¼. Це Đ¾Đ·Đ½Đ°Ñ‡Đ°Ñ”, Ñ‰Đ¾ Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¸Đ¼ Đ´Đ°Đ½Đ¸Đ¼ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸, Đ½Đ°Đ´Đ°Đ½Đ¸Đ¼ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼, Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ´Đ¾Đ²Ñ–Ñ€ÑÑ‚Đ¸. Ви Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ¿ĐµÑ€ĐµĐ´Đ°Đ²Đ°Ñ‚Đ¸ ÑĐ²Đ¾Ñ— Đ´Đ°Đ½Ñ– Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºÑƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Đ—Đ°Đ¿Đ¸Ñ‚ÑƒĐ²Đ°Ñ‚Đ¸ Đ´Đ¾Đ·Đ²Ñ–Đ»</translation>
<translation id="2721148159707890343">Đ—Đ°Đ¿Đ¸Ñ‚ Đ½Đ°Đ´Ñ–ÑĐ»Đ°Đ½Đ¾</translation>
<translation id="2728127805433021124">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ°Đ½Đ¾ Đ· Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ°Đ½Đ½ÑĐ¼ ÑĐ»Đ°Đ±ĐºĐ¾Đ³Đ¾ Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚Đ¼Ñƒ Đ¿Ñ–Đ´Đ¿Đ¸Ñу.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">ĐĐ´Ñ€ĐµÑĐ½Đ¸Đ¹ Ñ– Đ¿Đ¾ÑˆÑƒĐºĐ¾Đ²Đ¸Đ¹ Ñ€ÑĐ´Đ¾Đº</translation>
<translation id="2826760142808435982">Đ—â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¾ Đ¹ Đ°Đ²Ñ‚ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ¾Đ²Đ°Đ½Đ¾ Đ· Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ°Đ½Đ½ÑĐ¼ ÑˆĐ¸Ñ„Ñ€Ñƒ <ph name="CIPHER" /> Ñ– Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑ” Đ¼ĐµÑ…Đ°Đ½Ñ–Đ·Đ¼ Đ¾Đ±Đ¼Ñ–Đ½Ñƒ ĐºĐ»ÑÑ‡Đ°Đ¼Đ¸ <ph name="KX" />.</translation>
<translation id="2835170189407361413">ĐÑ‡Đ¸ÑÑ‚Đ¸Ñ‚Đ¸ Ñ„Đ¾Ñ€Đ¼Ñƒ</translation>
-<translation id="2837049386027881519">ĐŸĐ¾Ñ‚Ñ€Ñ–Đ±Đ½Đ¾ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đ¸ ÑĐ¿Ñ€Đ¾Đ±Ñƒ Đ·'Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ·Đ° Đ´Đ¾Đ¿Đ¾Đ¼Đ¾Đ³Đ¾Ñ ÑÑ‚Đ°Ñ€Ñ–ÑˆĐ¾Ñ— Đ²ĐµÑ€ÑÑ–Ñ— Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»Ñƒ TLS Đ°Đ±Đ¾ SSL. ĐŸĐµÑ€ĐµĐ²Đ°Đ¶Đ½Đ¾ Ñ†Đµ Đ¾Đ·Đ½Đ°Ñ‡Đ°Ñ”, Ñ‰Đ¾ ÑĐµÑ€Đ²ĐµÑ€ Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑ” Đ´ÑƒĐ¶Đµ Đ·Đ°ÑÑ‚Đ°Ñ€Ñ–Đ»Đµ Đ¿Ñ€Đ¾Đ³Ñ€Đ°Đ¼Đ½Đµ Đ·Đ°Đ±ĐµĐ·Đ¿ĐµÑ‡ĐµĐ½Đ½Ñ Ñ‚Đ° Đ¼Đ¾Đ¶Đµ Đ¼Đ°Ñ‚Đ¸ Đ¹ Ñ–Đ½ÑˆÑ– Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ¸ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸.</translation>
<translation id="284702764277384724">Đ¡Ñ…Đ¾Đ¶Đµ, ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½Đ° Ñ…Đ¾ÑÑ‚Ñ– <ph name="HOST_NAME" /> Đ¿Ñ–Đ´Ñ€Đ¾Đ±Đ»ĐµĐ½Đ¾.</translation>
<translation id="2889159643044928134">Đе Đ¾Đ½Đ¾Đ²Đ»ÑĐ²Đ°Ñ‚Đ¸</translation>
-<translation id="2896499918916051536">Đ¦ĐµĐ¹ Đ¿Đ»Đ°Đ³Ñ–Đ½ Đ½Đµ Đ¿Ñ–Đ´Ñ‚Ñ€Đ¸Đ¼ÑƒÑ”Ñ‚ÑŒÑÑ.</translation>
+<translation id="2900469785430194048">ĐĐµĐ´Đ¾ÑÑ‚Đ°Ñ‚Đ½ÑŒĐ¾ Đ¿Đ°Đ¼â€™ÑÑ‚Ñ– Google Chrome, Ñ‰Đ¾Đ± Đ¿Đ¾ĐºĐ°Đ·Đ°Ñ‚Đ¸ Ñ†Ñ Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ.</translation>
<translation id="2909946352844186028">ВиÑĐ²Đ»ĐµĐ½Đ¾ Đ·Đ¼Ñ–Đ½Ñƒ Đ² Đ¼ĐµÑ€ĐµĐ¶Ñ–.</translation>
-<translation id="2915500479781995473">Đ¡ĐµÑ€Đ²ĐµÑ€Ñƒ Đ½Đµ Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ <ph name="DOMAIN" />. Đ¢ĐµÑ€Đ¼Ñ–Đ½ Đ´Ñ–Ñ— ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ° Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Ñ†ÑŒĐ¾Đ³Đ¾ Đ´Đ¾Đ¼ĐµĐ½Ñƒ Đ·Đ°ĐºÑ–Đ½Ñ‡Đ¸Đ²ÑÑ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ°Đ±Đ¾ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ»ĐµĐ½Đ½Ñ Đ²Đ°ÑˆĐ¾Đ³Đ¾ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºĐ¾Đ¼. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_TIME" />. Đ¯ĐºÑ‰Đ¾ Đ´Đ°Ñ‚Đ° Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ°, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ.</translation>
<translation id="2922350208395188000">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½ĐµĐ¼Đ¾Đ¶Đ»Đ¸Đ²Đ¾ Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€Đ¸Ñ‚Đ¸.</translation>
-<translation id="2941952326391522266">Đ¦ĐµĐ¹ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ·Đ¼Ñ–Đ³ Đ´Đ¾Đ²ĐµÑÑ‚Đ¸, Ñ‰Đ¾ Đ²Ñ–Đ½ – Đ´Đ¾Đ¼ĐµĐ½ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ…Đ¾Đ´Đ¸Ñ‚ÑŒ Ñ–Đ· Đ´Đ¾Đ¼ĐµĐ½Ñƒ <ph name="DOMAIN2" />. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
<translation id="2948083400971632585">Đ£ÑÑ– Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Đ¸, Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Ñ– Đ´Đ»Ñ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ, Đ¼Đ¾Đ¶Đ½Đ° Đ²Đ¸Đ¼ĐºĐ½ÑƒÑ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½Ñ†Ñ– Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½ÑŒ.</translation>
<translation id="2955913368246107853">Đ—Đ°ĐºÑ€Đ¸Ñ‚Đ¸ Đ¿Đ°Đ½ĐµĐ»ÑŒ Đ¿Đ¾ÑˆÑƒĐºÑƒ</translation>
<translation id="2958431318199492670">ĐĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ½Đµ Đ²Ñ–Đ´Đ¿Đ¾Đ²Ñ–Đ´Đ°Ñ” ÑÑ‚Đ°Đ½Đ´Đ°Ñ€Ñ‚Ñƒ ONC. Đ’Đ¾Đ½Đ° Đ¼Đ¾Đ¶Đµ Ñ–Đ¼Đ¿Đ¾Ñ€Ñ‚ÑƒĐ²Đ°Ñ‚Đ¸ÑÑ Ñ‡Đ°ÑÑ‚ĐºĐ¾Đ²Đ¾.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">ĐĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¸Đ¹ Ñ‚Đ¸Đ¿ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°</translation>
<translation id="3032412215588512954">ĐĐ½Đ¾Đ²Đ¸Ñ‚Đ¸ Ñ†ĐµĐ¹ ÑĐ°Đ¹Ñ‚?</translation>
<translation id="3037605927509011580">ĐÑ‚ Ñ…Đ°Đ»ĐµĐ¿Đ°!</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{Ñ‰Đ¾Đ½Đ°Đ¹Đ¼ĐµĐ½ÑˆĐµ 1 Đ·Đ°Đ¿Đ¸Ñ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ¾Đ²Đ°Đ½Đ¸Ñ… Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾ÑÑ…}=1{1 Đ·Đ°Đ¿Đ¸Ñ (Ñ– Đ±Ñ–Đ»ÑŒÑˆĐµ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ¾Đ²Đ°Đ½Đ¸Ñ… Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾ÑÑ…)}one{# Đ·Đ°Đ¿Đ¸Ñ (Ñ– Đ±Ñ–Đ»ÑŒÑˆĐµ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ¾Đ²Đ°Đ½Đ¸Ñ… Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾ÑÑ…)}few{# Đ·Đ°Đ¿Đ¸Ñи (Ñ– Đ±Ñ–Đ»ÑŒÑˆĐµ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ¾Đ²Đ°Đ½Đ¸Ñ… Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾ÑÑ…)}many{# Đ·Đ°Đ¿Đ¸ÑÑ–Đ² (Ñ– Đ±Ñ–Đ»ÑŒÑˆĐµ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ¾Đ²Đ°Đ½Đ¸Ñ… Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾ÑÑ…)}other{# Đ·Đ°Đ¿Đ¸Ñу (Ñ– Đ±Ñ–Đ»ÑŒÑˆĐµ Đ½Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ¾Đ²Đ°Đ½Đ¸Ñ… Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾ÑÑ…)}}</translation>
<translation id="3041612393474885105">Đ†Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ Đ¿Ñ€Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚</translation>
<translation id="3063697135517575841">Chrome Đ½Đµ Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸ Đ´Đ°Đ½Ñ– Đ²Đ°ÑˆĐ¾Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸. Đ¡Đ¿Ñ€Đ¾Đ±ÑƒĐ¹Ñ‚Đµ Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ.</translation>
<translation id="3093245981617870298">Ви Đ² Ñ€ĐµĐ¶Đ¸Đ¼Ñ– Đ¾Ñ„Đ»Đ°Đ¹Đ½</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">ĐĐ°Đ¹Đ½Đ¾Đ²Ñ–ÑˆĐµ</translation>
<translation id="3207960819495026254">Đ¡Ñ‚Đ²Đ¾Ñ€ĐµĐ½Đ¾ Đ·Đ°ĐºĐ»Đ°Đ´ĐºÑƒ</translation>
-<translation id="3225919329040284222">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚, ÑĐºĐ¸Đ¹ Đ½Đµ Đ²Ñ–Đ´Đ¿Đ¾Đ²Ñ–Đ´Đ°Ñ” Đ¾Ñ‡Ñ–ĐºÑƒĐ²Đ°Đ½Đ¸Đ¼ Đ²Đ±ÑƒĐ´Đ¾Đ²Đ°Đ½Đ¸Đ¼ Đ¿Đ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ°Đ¼. Đ¦Ñ– Đ¾Ñ‡Ñ–ĐºÑƒĐ²Đ°Đ½Ñ– Đ¿Đ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ¸ Đ²ÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ´Đ»Ñ Đ¿ĐµĐ²Đ½Đ¸Ñ… Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚Ñ–Đ² Ñ–Đ· Đ²Đ¸ÑĐ¾ĐºĐ¸Đ¼ Ñ€Ñ–Đ²Đ½ĐµĐ¼ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸, Ñ‰Đ¾Đ± Đ·Đ°Ñ…Đ¸ÑÑ‚Đ¸Ñ‚Đ¸ Đ²Đ°Ñ.</translation>
<translation id="3226128629678568754">ĐĐ°Ñ‚Đ¸ÑĐ½Ñ–Ñ‚ÑŒ ĐºĐ½Đ¾Đ¿ĐºÑƒ Đ¿ĐµÑ€ĐµĐ·Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶ĐµĐ½Đ½Ñ, Ñ‰Đ¾Đ± Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ½Đ¾ Đ½Đ°Đ´Ñ–ÑĐ»Đ°Ñ‚Đ¸ Đ´Đ°Đ½Ñ–, Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±Đ½Ñ– Đ´Đ»Ñ Đ·Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶ĐµĐ½Đ½Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸.</translation>
<translation id="3228969707346345236">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° Đ¿ĐµÑ€ĐµĐºĐ»Đ°Đ´Ñƒ. Đ¡Ñ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ Đ²Đ¶Đµ Đ¿ĐµÑ€ĐµĐºĐ»Đ°Đ´ĐµĐ½Đ¾ Ñ‚Đ°ĐºĐ¾Ñ Đ¼Đ¾Đ²Đ¾Ñ: <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Đ’Đ²ĐµÑÑ‚Đ¸ ĐºĐ¾Đ´ CVC ĐºĐ°Ñ€Ñ‚ĐºĐ¸ <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">Đ”Đ¾Đ´Đ°Ñ‚Đ¸ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ Đ´Đ¾ Đ·Đ°ĐºĐ»Đ°Đ´Đ¾Đº</translation>
<translation id="3270847123878663523">&amp;Đ’Ñ–Đ´Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ Đ¿ĐµÑ€ĐµĐ²Đ¿Đ¾Ñ€ÑĐ´ĐºÑƒĐ²Đ°Đ½Đ½Ñ</translation>
<translation id="3286538390144397061">ĐŸĐµÑ€ĐµĐ·Đ°Đ¿ÑƒÑÑ‚Đ¸Ñ‚Đ¸ Đ·Đ°Ñ€Đ°Đ·</translation>
+<translation id="3303855915957856445">ĐĐµĐ¼Đ°Ñ” Ñ€ĐµĐ·ÑƒĐ»ÑŒÑ‚Đ°Ñ‚Ñ–Đ²</translation>
<translation id="3305707030755673451">Đ’Đ°ÑˆÑ– Đ´Đ°Đ½Ñ– Đ±ÑƒĐ»Đ¾ Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¾ <ph name="TIME" /> Đ·Đ° Đ´Đ¾Đ¿Đ¾Đ¼Đ¾Đ³Đ¾Ñ Đ¿Đ°Ñ€Đ¾Đ»ÑŒĐ½Đ¾Ñ— Ñ„Ñ€Đ°Đ·Đ¸ Đ´Đ»Ñ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ°Ñ†Ñ–Ñ—. Đ’Đ²ĐµĐ´Ñ–Ñ‚ÑŒ Ñ—Ñ—, Ñ‰Đ¾Đ± Đ¿Đ¾Ñ‡Đ°Ñ‚Đ¸ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ°Ñ†Ñ–Ñ.</translation>
<translation id="333371639341676808">Đ—Đ°Đ±Đ¾Ñ€Đ¾Đ½Đ¸Ñ‚Đ¸ ÑÑ‚Đ²Đ¾Ñ€ĐµĐ½Đ½Ñ Đ´Đ¾Đ´Đ°Ñ‚ĐºĐ¾Đ²Đ¸Ñ… Đ´Ñ–Đ°Đ»Đ¾Đ³Đ¾Đ²Đ¸Ñ… Đ²Ñ–ĐºĐ¾Đ½ Ñ†Ñ–Ñ”Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¾Ñ.</translation>
+<translation id="3338095232262050444">ĐĐ°Đ´Ñ–Đ¹Đ½Đµ</translation>
<translation id="3340978935015468852">Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½Đ½Ñ</translation>
<translation id="3345135638360864351">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ½Đ°Đ´Ñ–ÑĐ»Đ°Ñ‚Đ¸ Đ·Đ°Đ¿Đ¸Ñ‚ Đ½Đ° Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đ´Đ¾ Ñ†ÑŒĐ¾Đ³Đ¾ ÑĐ°Đ¹Ñ‚Ñƒ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡ĐµĐ²Ñ– <ph name="NAME" />. ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Ñ–Ñ‚ÑŒ ÑĐ¿Ñ€Đ¾Đ±Ñƒ.</translation>
<translation id="3355823806454867987">Đ—Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½Đ½Ñ Đ¿Ñ€Đ¾ĐºÑÑ–...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Đ†Đ½Ñ‚ĐµÑ€Đ²Đ°Đ» Đ¾Ñ‚Ñ€Đ¸Đ¼Đ°Đ½Đ½Ñ:</translation>
<translation id="3462200631372590220">Đ¡Ñ…Đ¾Đ²Đ°Ñ‚Đ¸ Đ´Đ¾Đ´Đ°Ñ‚ĐºĐ¾Đ²Ñƒ Ñ–Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ</translation>
<translation id="3479539252931486093">Đе Đ¾Ñ‡Ñ–ĐºÑƒĐ²Đ°Đ»Đ¸? <ph name="BEGIN_LINK" />ĐŸĐ¾Đ²Ñ–Đ´Đ¾Đ¼Ñ‚Đµ Đ½Đ°Ñ<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">Đе Đ·Đ°Ñ€Đ°Đ·</translation>
<translation id="348000606199325318">Đ†Đ´ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ¾Ñ€ Đ°Đ²Đ°Ñ€Ñ–Đ¹Đ½Đ¾Đ³Đ¾ Đ·Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ½Ñ Ñ€Đ¾Đ±Đ¾Ñ‚Đ¸ <ph name="CRASH_LOCAL_ID" /> (Ñ–Đ´ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ¾Ñ€ ÑĐµÑ€Đ²ĐµÑ€Đ°: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ¾Đ´Đ½Đ¸Đ¼ Ñ–Đ· Đ²Đ°ÑˆĐ¸Ñ… Đ±Đ°Ñ‚ÑŒĐºÑ–Đ². ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Ñ–Ñ‚ÑŒ ÑĐ¿Ñ€Đ¾Đ±Ñƒ.</translation>
<translation id="3527085408025491307">ĐŸĐ°Đ¿ĐºĐ°</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Đ’Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒĐ²Đ°Ñ‚Đ¸ Đ¿Đ°Ñ€Đ¾Đ»ÑŒ Đ´Đ»Ñ:</translation>
<translation id="3549644494707163724">Đ¨Đ¸Ñ„Ñ€ÑƒĐ²Đ°Ñ‚Đ¸ Đ²ÑÑ– ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ¾Đ²Đ°Đ½Ñ– Đ´Đ°Đ½Ñ– Đ·Đ° Đ´Đ¾Đ¿Đ¾Đ¼Đ¾Đ³Đ¾Ñ Đ²Đ»Đ°ÑĐ½Đ¾Ñ— Đ¿Đ°Ñ€Đ¾Đ»ÑŒĐ½Đ¾Ñ— Ñ„Ñ€Đ°Đ·Đ¸ Đ´Đ»Ñ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ°Ñ†Ñ–Ñ—</translation>
<translation id="3549761410225185768">Ñ‰Đµ <ph name="NUM_TABS_MORE" />…</translation>
+<translation id="3555561725129903880">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ…Đ¾Đ´Đ¸Ñ‚ÑŒ Ñ–Đ· Đ´Đ¾Đ¼ĐµĐ½Ñƒ <ph name="DOMAIN2" />. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Đ—â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ½Đµ ĐºĐ¾Đ½Ñ„Ñ–Đ´ĐµĐ½Ñ†Ñ–Đ¹Đ½Đµ</translation>
<translation id="3583757800736429874">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đ¸ Đ¿ĐµÑ€ĐµĐ¼Ñ–Ñ‰ĐµĐ½Đ½Ñ</translation>
<translation id="3586931643579894722">Đ¡Ñ…Đ¾Đ²Đ°Ñ‚Đ¸ Đ´Đ¾ĐºĐ»Đ°Đ´Đ½Ñ– Đ´Đ°Đ½Ñ–</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">ĐŸĐ¾ĐºĐ°Đ·Đ°Ñ‚Đ¸ Đ·Đ½Đ°Ñ‡ĐµĐ½Đ½Ñ</translation>
<translation id="3630155396527302611">Đ¯ĐºÑ‰Đ¾ Ñ†Ñ–Đ¹ Đ¿Ñ€Đ¾Đ³Ñ€Đ°Đ¼Ñ– Đ²Đ¶Đµ Đ½Đ°Đ´Đ°Đ½Đ¾ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đ´Đ¾ Đ¼ĐµÑ€ĐµĐ¶Ñ–, ÑĐ¿Ñ€Đ¾Đ±ÑƒĐ¹Ñ‚Đµ
Đ²Đ¸Đ»ÑƒÑ‡Đ¸Ñ‚Đ¸ Ñ—Ñ— Đ·Ñ– ÑĐ¿Đ¸ÑĐºÑƒ Ñ‚Đ° Đ´Đ¾Đ´Đ°Ñ‚Đ¸ Đ·Đ½Đ¾Đ²Ñƒ.</translation>
+<translation id="3638794133396384728">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ½ĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. ĐĐ° Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸ĐºÑƒ Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· <ph name="CURRENT_TIME" />. Đ¯ĐºÑ‰Đ¾ Ñ‡Đ°Ñ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¸Đ¹, Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ¹Ñ‚Đµ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¹ Đ³Đ¾Đ´Đ¸Đ½Đ½Đ¸Đº Ñ– Đ¾Đ½Đ¾Đ²Ñ–Ñ‚ÑŒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">Đ¦Ñ– ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ°Đ»ÑŒĐ½Ñ– Ñ„ÑƒĐ½ĐºÑ†Ñ–Ñ— Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ±ÑƒĐ´ÑŒ-ĐºĐ¾Đ»Đ¸ Đ·Đ¼Ñ–Đ½ÑĐ²Đ°Ñ‚Đ¸ÑÑ, Đ²Đ¸Ñ…Đ¾Đ´Đ¸Ñ‚Đ¸ Đ· Đ»Đ°Đ´Ñƒ Ñ‡Đ¸ Đ·Đ½Đ¸ĐºĐ°Ñ‚Đ¸. ĐœĐ¸ Đ½Đµ Đ´Đ°Ñ”Đ¼Đ¾ Đ¶Đ¾Đ´Đ½Đ¸Ñ… Đ³Đ°Ñ€Đ°Đ½Ñ‚Ñ–Đ¹ Ñ‰Đ¾Đ´Đ¾ Đ¼Đ¾Đ¶Đ»Đ¸Đ²Đ¸Ñ… Đ½Đ°ÑĐ»Ñ–Đ´ĐºÑ–Đ² ÑƒĐ²Ñ–Đ¼ĐºĐ½ĐµĐ½Đ½Ñ Đ¾Đ´Đ½Ñ–Ñ”Ñ— Đ· Ñ†Đ¸Ñ… ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ°Đ»ÑŒĐ½Đ¸Ñ… Ñ„ÑƒĐ½ĐºÑ†Ñ–Đ¹, Đ° Đ²Đ°Ñˆ Đ²ĐµĐ±-Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Đ°Ñ‡ Đ¼Đ¾Đ¶Đµ Đ½Đ°Đ²Ñ–Ñ‚ÑŒ Ñ€Đ°Đ¿Ñ‚Đ¾Đ²Đ¾ Đ¿Ñ€Đ¸Đ¿Đ¸Đ½Đ¸Ñ‚Đ¸ Ñ€Đ¾Đ±Đ¾Ñ‚Ñƒ. Đ’Đ°Ñˆ Đ²ĐµĐ±-Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Đ°Ñ‡ Đ¼Đ¾Đ¶Đµ Đ²Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸ Đ²ÑÑ– Đ²Đ°ÑˆÑ– Đ´Đ°Đ½Ñ–, Đ° Đ²Đ°ÑˆÑƒ Đ±ĐµĐ·Đ¿ĐµĐºÑƒ Ñ‚Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ´ĐµĐ½Ñ†Ñ–Đ¹Đ½Ñ–ÑÑ‚ÑŒ Đ¼Đ¾Đ¶Đµ Đ±ÑƒÑ‚Đ¸ Đ¿Đ¾Ñ€ÑƒÑˆĐµĐ½Đ¾ Đ½ĐµĐ¾Ñ‡Ñ–ĐºÑƒĐ²Đ°Đ½Đ¸Đ¼ Ñ‡Đ¸Đ½Đ¾Đ¼. Đ‘ÑƒĐ´ÑŒ-ÑĐºÑ– Đ²Đ²Ñ–Đ¼ĐºĐ½ĐµĐ½Ñ– Đ²Đ°Đ¼Đ¸ ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ°Đ»ÑŒĐ½Ñ– Ñ„ÑƒĐ½ĐºÑ†Ñ–Ñ— Đ±ÑƒĐ´Đµ Đ²Đ²Ñ–Đ¼ĐºĐ½ĐµĐ½Đ¾ Đ´Đ»Ñ Đ²ÑÑ–Ñ… ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Ñ–Đ² Ñ†ÑŒĐ¾Đ³Đ¾ Đ²ĐµĐ±-Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Đ°Ñ‡Đ°. Đ—Đ°ÑÑ‚Đ¾ÑĐ¾Đ²ÑƒĐ¹Ñ‚Đµ Đ· Đ¾Đ±ĐµÑ€ĐµĐ¶Đ½Ñ–ÑÑ‚Ñ.</translation>
<translation id="3650584904733503804">ĐŸĐµÑ€ĐµĐ²Ñ–Ñ€ĐºÑƒ Đ·Đ°ĐºÑ–Đ½Ñ‡ĐµĐ½Đ¾</translation>
<translation id="3655670868607891010">Đ¯ĐºÑ‰Đ¾ Đ²Đ¸ Đ±Đ°Ñ‡Đ¸Ñ‚Đµ Ñ†Đµ Ñ‡Đ°ÑÑ‚Đ¾, ÑĐ¿Ñ€Đ¾Đ±ÑƒĐ¹Ñ‚Đµ <ph name="HELP_LINK" />.</translation>
<translation id="3658742229777143148">Đ ĐµĐ´Đ°ĐºÑ†Ñ–Ñ</translation>
+<translation id="3678029195006412963">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ°Ñ‚Đ¸ Đ·Đ°Đ¿Đ¸Ñ‚</translation>
<translation id="3681007416295224113">Đ†Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ Đ¿Ñ€Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚</translation>
<translation id="3693415264595406141">ĐŸĐ°Ñ€Đ¾Đ»ÑŒ:</translation>
+<translation id="3696411085566228381">Đ½ĐµĐ¼Đ°Ñ”</translation>
<translation id="3700528541715530410">Đ¡Ñ…Đ¾Đ¶Đµ, Đ²Đ¸ Đ½Đµ Đ¼Đ°Ñ”Ñ‚Đµ Đ´Đ¾Đ·Đ²Đ¾Đ»Ñƒ Đ½Đ° Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đ´Đ¾ цієї ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Đ—Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶ĐµĐ½Đ½Ñ...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">ÑƒĐ²Ñ–Đ¼ĐºĐ½ÑƒÑ‚Đ¸ Đ¼Đ¾Đ±Ñ–Đ»ÑŒĐ½Đ¸Đ¹ Đ†Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ°Đ±Đ¾ Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€Đ¸Ñ‚Đ¸ ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Đ°, Đ±Ñ€Đ°Đ½Đ´Đ¼Đ°ÑƒĐµÑ€Đ° Ñ‚Đ° DNS-ÑĐµÑ€Đ²ĐµÑ€Đ°<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">Đ¡ĐºĐ¾Đ¿Ñ–Đ¹Đ¾Đ²Đ°Đ½Đµ Đ¿Đ¾ÑĐ¸Đ»Đ°Đ½Đ½Ñ</translation>
-<translation id="3744899669254331632">Đ—Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="SITE" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚ Đ½Đ°Đ´Ñ–ÑĐ»Đ°Đ² Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Ñ– Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Ñ– Đ´Đ°Đ½Ñ–, ÑĐºÑ– Chromium Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ¾Đ±Ñ€Đ¾Đ±Đ¸Ñ‚Đ¸. ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ¸ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ¹ Đ°Ñ‚Đ°ĐºĐ¸ Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Ñ” Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Đ¸Đ¼Đ¸, Ñ‚Đ¾Đ¼Ñƒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ¼Đ¾Đ¶Đµ Đ¿Ñ€Đ°Ñ†ÑĐ²Đ°Ñ‚Đ¸ Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ.</translation>
<translation id="375403751935624634">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ²Đ¸ĐºĐ¾Đ½Đ°Ñ‚Đ¸ Đ¿ĐµÑ€ĐµĐºĐ»Đ°Đ´ Ñ‡ĐµÑ€ĐµĐ· Đ¿Đ¾Đ¼Đ¸Đ»ĐºÑƒ ÑĐµÑ€Đ²ĐµÑ€Đ°.</translation>
<translation id="3759461132968374835">Đ£ Đ²Đ°Ñ Đ½ĐµĐ¼Đ°Ñ” Đ¾ÑÑ‚Đ°Đ½Đ½Ñ–Ñ… Đ¿Đ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½ÑŒ Đ¿Ñ€Đ¾ Đ°Đ²Đ°Ñ€Ñ–Đ¹Đ½Đµ Đ·Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ½Ñ Ñ€Đ¾Đ±Đ¾Ñ‚Đ¸. Đ¢ÑƒÑ‚ Đ½Đµ Đ²Ñ–Đ´Đ¾Đ±Ñ€Đ°Đ¶Đ°Ñ‚Đ¸Đ¼ÑƒÑ‚ÑŒÑÑ Đ²Đ¸Đ¿Đ°Đ´ĐºĐ¸ Đ°Đ²Đ°Ñ€Ñ–Đ¹Đ½Đ¾Đ³Đ¾ Đ·Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ½Ñ Ñ€Đ¾Đ±Đ¾Ñ‚Đ¸, ÑĐºÑ– ÑÑ‚Đ°Đ»Đ¸ÑÑ, ĐºĐ¾Đ»Đ¸ Đ¿Đ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½Đ½Ñ Đ¿Ñ€Đ¾ Đ°Đ²Đ°Ñ€Ñ–Đ¹Đ½Đµ Đ·Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ½Ñ Ñ€Đ¾Đ±Đ¾Ñ‚Đ¸ Đ±ÑƒĐ»Đ¾ Đ²Đ¸Đ¼ĐºĐ½ĐµĐ½Đ¾.</translation>
<translation id="3788090790273268753">Đ¢ĐµÑ€Đ¼Ñ–Đ½ Đ´Ñ–Ñ— ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ° Đ´Đ»Ñ Ñ†ÑŒĐ¾Đ³Đ¾ ÑĐ°Đ¹Ñ‚Ñƒ Đ·Đ°ĐºÑ–Đ½Ñ‡ÑƒÑ”Ñ‚ÑŒÑÑ 2016 Ñ€Đ¾ĐºÑƒ. Đ›Đ°Đ½Ñ†ÑĐ¶Đ¾Đº ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ° Đ¼Ñ–ÑÑ‚Đ¸Ñ‚ÑŒ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚, Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ°Đ½Đ¸Đ¹ Đ·Đ° Đ´Đ¾Đ¿Đ¾Đ¼Đ¾Đ³Đ¾Ñ SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">ĐĐ¾Đ½Ñ„Đ»Ñ–ĐºÑ‚ÑƒÑÑ‡Đ¸Đ¹ Ñ–Đ´ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ¾Ñ€ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ</translation>
<translation id="3885155851504623709">ĐĐ±Ñ‰Đ¸Đ½Đ°</translation>
<translation id="3901925938762663762">Đ¢ĐµÑ€Đ¼Ñ–Đ½ Đ´Ñ–Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸ Đ¼Đ¸Đ½ÑƒĐ²</translation>
+<translation id="3910267023907260648">Ви Đ½Đ°Đ¼Đ°Đ³Đ°Đ»Đ¸ÑÑ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />, але ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚, Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ°Đ½Đ¸Đ¹ Ñ–Đ· Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ°Đ½Đ½ÑĐ¼ ÑĐ»Đ°Đ±ĐºĐ¾Đ³Đ¾ Đ°Đ»Đ³Đ¾Ñ€Đ¸Ñ‚Đ¼Ñƒ Đ¿Ñ–Đ´Đ¿Đ¸Ñу. Це Đ¾Đ·Đ½Đ°Ñ‡Đ°Ñ”, Ñ‰Đ¾ Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Ñ– Đ´Đ°Đ½Ñ– Đ±ĐµĐ·Đ¿ĐµĐºĐ¸, Đ½Đ°Đ´Đ°Đ½Ñ– ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼, Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ±ÑƒÑ‚Đ¸ ÑÑ„Đ°Đ»ÑŒÑĐ¸Ñ„Ñ–ĐºĐ¾Đ²Đ°Đ½Đ¸Đ¼Đ¸, Đ° ÑĐµÑ€Đ²ĐµÑ€ – Đ½Đµ Ñ‚Đ¸Đ¼, ÑĐºĐ¸Đ¹ Đ²Đ°Đ¼ Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±ĐµĐ½ (Đ²Đ¸ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ¿ĐµÑ€ĐµĐ´Đ°Đ²Đ°Ñ‚Đ¸ ÑĐ²Đ¾Ñ— Đ´Đ°Đ½Ñ– Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºÑƒ). <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ‡Đ½Đµ Đ´Ñ–ÑÑ‚Đ¸ Đ·Đ°Đ²Ñ‚Ñ€Đ°. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}one{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ‡Đ½Đµ Đ´Ñ–ÑÑ‚Đ¸ Ñ‡ĐµÑ€ĐµĐ· # Đ´ĐµĐ½ÑŒ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}few{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ‡Đ½Đµ Đ´Ñ–ÑÑ‚Đ¸ Ñ‡ĐµÑ€ĐµĐ· # Đ´Đ½Ñ–. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}many{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ‡Đ½Đµ Đ´Ñ–ÑÑ‚Đ¸ Ñ‡ĐµÑ€ĐµĐ· # Đ´Đ½Ñ–Đ². ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}other{Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¿Đ¾Ñ‡Đ½Đµ Đ´Ñ–ÑÑ‚Đ¸ Ñ‡ĐµÑ€ĐµĐ· # Đ´Đ½Ñ. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ·Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶Đ¸Ñ‚Đ¸ Đ´Đ¾ĐºÑƒĐ¼ĐµĐ½Ñ‚ PDF</translation>
<translation id="3963721102035795474">Đ ĐµĐ¶Đ¸Đ¼ Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Ñƒ</translation>
+<translation id="397105322502079400">ĐĐ±Ñ‡Đ¸ÑĐ»ĐµĐ½Đ½Ñ...</translation>
<translation id="3973234410852337861">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Đ·Đ°Đ±Đ»Đ¾ĐºĐ¾Đ²Đ°Đ½Đ¸Đ¹</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ¿Đ¾Ñ€ÑƒÑ‡}one{# Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ¿Đ¾Ñ€ÑƒÑ‡}few{# Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸ Đ¿Đ¾Ñ€ÑƒÑ‡}many{# Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½Đ¾Đº Đ¿Đ¾Ñ€ÑƒÑ‡}other{# Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸ Đ¿Đ¾Ñ€ÑƒÑ‡}}</translation>
<translation id="4021036232240155012">DNS – Ñ†Đµ Đ¼ĐµÑ€ĐµĐ¶ĐµĐ²Đ° ÑĐ»ÑƒĐ¶Đ±Đ°, ÑĐºĐ° Đ¿ĐµÑ€ĐµÑ‚Đ²Đ¾Ñ€ÑÑ” Đ½Đ°Đ·Đ²Ñƒ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚Ñƒ Đ½Đ° Đ¹Đ¾Đ³Đ¾ Ñ–Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚-Đ°Đ´Ñ€ĐµÑу.</translation>
<translation id="4030383055268325496">&amp;Đ’Ñ–Đ´Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ Đ´Đ¾Đ´Đ°Đ²Đ°Đ½Đ½Ñ</translation>
-<translation id="4032534284272647190">Đ£ Đ´Đ¾ÑÑ‚ÑƒĐ¿Ñ– Đ´Đ¾ <ph name="URL" /> Đ²Ñ–Đ´Đ¼Đ¾Đ²Đ»ĐµĐ½Đ¾.</translation>
<translation id="404928562651467259">Đ—ĐĐ¡Đ¢Đ•Đ Đ•Đ–Đ•ĐĐĐ¯</translation>
<translation id="4058922952496707368">ĐĐ»Ñч "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">ĐĐ»Ñ–Ñ”Đ½Ñ‚ Ñ– ÑĐµÑ€Đ²ĐµÑ€ Đ¿Ñ–Đ´Ñ‚Ñ€Đ¸Đ¼ÑƒÑÑ‚ÑŒ Ñ€Ñ–Đ·Đ½Ñ– Đ²ĐµÑ€ÑÑ–Ñ— Đ¿Ñ€Đ¾Ñ‚Đ¾ĐºĐ¾Đ»Ñƒ SSL Đ°Đ±Đ¾ Đ½Đ°Đ±Đ¾Ñ€Ñƒ ÑˆĐ¸Ñ„Ñ€Ñ–Đ².</translation>
<translation id="4079302484614802869">ĐĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½Đ° Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ°Đ½Đ½Ñ URL-Đ°Đ´Ñ€ĐµÑи ÑÑ†ĐµĐ½Đ°Ñ€Ñ–Ñ .pac, Đ° Đ½Đµ Ñ„Ñ–ĐºÑĐ¾Đ²Đ°Đ½Đ¸Ñ… Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Ñ–Đ².</translation>
<translation id="4103249731201008433">ĐĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹ ÑĐµÑ€Ñ–Đ¹Đ½Đ¸Đ¹ Đ½Đ¾Đ¼ĐµÑ€ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ</translation>
<translation id="4103763322291513355">ĐŸĐµÑ€ĐµĐ¹Đ´Ñ–Ñ‚ÑŒ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ &lt;strong&gt;chrome://policy&lt;/strong&gt;, Ñ‰Đ¾Đ± Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ½ÑƒÑ‚Đ¸ ÑĐ¿Đ¸ÑĐ¾Đº URL-Đ°Đ´Ñ€ĐµÑ Ñ–Đ· "Ñ‡Đ¾Ñ€Đ½Đ¾Đ³Đ¾" ÑĐ¿Đ¸ÑĐºÑƒ Đ¹ Ñ–Đ½ÑˆÑ– Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°, Ñ‰Đ¾ Đ¿Ñ€Đ¸Đ¼ÑƒÑĐ¾Đ²Đ¾ Đ·Đ°ÑÑ‚Đ¾ÑĐ¾Đ²ÑƒÑ”Ñ‚ÑŒÑÑ ÑиÑÑ‚ĐµĐ¼Đ½Đ¸Đ¼ Đ°Đ´Đ¼Ñ–Đ½Ñ–ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Đ¾Đ¼.</translation>
+<translation id="4110615724604346410">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¼Ñ–ÑÑ‚Đ¸Ñ‚ÑŒ Đ¿Đ¾Đ¼Đ¸Đ»ĐºĐ¸. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ¾ Đ½Đµ Đ¿Ñ–Đ´Ñ‚Ñ€Đ¸Đ¼ÑƒÑ”Ñ‚ÑŒÑÑ.</translation>
+<translation id="4118212371799607889">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Chromium Đ²Đ²Đ°Đ¶Đ°Ñ” Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ½ĐµĐ½Đ°Đ´Ñ–Đ¹Đ½Đ¸Đ¼. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{Ñ– Ñ‰Đµ 1 ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚ Đ´Đ°Đ½Đ¸Ñ…}one{Ñ– Ñ‰Đµ # ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚ Đ´Đ°Đ½Đ¸Ñ…}few{Ñ– Ñ‰Đµ # ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚Đ¸ Đ´Đ°Đ½Đ¸Ñ…}many{Ñ– Ñ‰Đµ # ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚Ñ–Đ² Đ´Đ°Đ½Đ¸Ñ…}other{Ñ– Ñ‰Đµ # ĐµĐ»ĐµĐ¼ĐµĐ½Ñ‚Đ° Đ´Đ°Đ½Đ¸Ñ…}}</translation>
<translation id="4130226655945681476">Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€Đ¸Ñ‚Đ¸ Đ¼ĐµÑ€ĐµĐ¶ĐµĐ²Đ¸Đ¹ ĐºĐ°Đ±ĐµĐ»ÑŒ, Đ¼Đ¾Đ´ĐµĐ¼ Ñ– Đ¼Đ°Ñ€ÑˆÑ€ÑƒÑ‚Đ¸Đ·Đ°Ñ‚Đ¾Ñ€</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Đ—Đ±ĐµÑ€ĐµĐ³Ñ‚Đ¸ Ñ†Ñ ĐºĐ°Ñ€Ñ‚ĐºÑƒ Đ² Chromium?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">Đ’Đ¸Đ¼ĐºĐ½ĐµĐ½Đ¾</translation>
<translation id="4196861286325780578">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đ¸ Đ¿ĐµÑ€ĐµĐ¼Ñ–Ñ‰ĐµĐ½Đ½Ñ</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€Đ¸Ñ‚Đ¸ ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ±Ñ€Đ°Đ½Đ´Đ¼Đ°ÑƒĐµÑ€Đ° Đ¹ Đ°Đ½Ñ‚Đ¸Đ²Ñ–Ñ€ÑƒÑĐ½Đ¾Ñ— Đ¿Ñ€Đ¾Đ³Ñ€Đ°Đ¼Đ¸<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{Đ½ĐµĐ¼Đ°Ñ”}=1{1 Đ´Đ¾Đ´Đ°Ñ‚Đ¾Đº ($1)}=2{2 Đ´Đ¾Đ´Đ°Ñ‚ĐºĐ¸ ($1, $2)}one{# Đ´Đ¾Đ´Đ°Ñ‚Đ¾Đº ($1, $2, $3)}few{# Đ´Đ¾Đ´Đ°Ñ‚ĐºĐ¸ ($1, $2, $3)}many{# Đ´Đ¾Đ´Đ°Ñ‚ĐºÑ–Đ² ($1, $2, $3)}other{# Đ´Đ¾Đ´Đ°Ñ‚ĐºĐ° ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Đ—Đ±Đ¾Ñ— Đ² Ñ€Đ¾Đ±Đ¾Ñ‚Ñ–</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />ĐŸÑ€Đ¾Đ²ĐµĐ´Ñ–Ñ‚ÑŒ Đ´Ñ–Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ Đ¼ĐµÑ€ĐµĐ¶Ñ–<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">Đ½Ñ–</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(ĐĐµĐ¼Đ°Ñ” Ñ–Đ¼ĐµĐ½Ñ– ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Đ°)</translation>
<translation id="4300246636397505754">ĐŸĐ¾Ñ€Đ°Đ´Đ¸ Đ´Đ»Ñ Đ±Đ°Ñ‚ÑŒĐºÑ–Đ²</translation>
<translation id="4304224509867189079">Đ’Ñ…Ñ–Đ´</translation>
+<translation id="432290197980158659">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚, ÑĐºĐ¸Đ¹ Đ½Đµ Đ²Ñ–Đ´Đ¿Đ¾Đ²Ñ–Đ´Đ°Ñ” Đ¾Ñ‡Ñ–ĐºÑƒĐ²Đ°Đ½Đ¸Đ¼ Đ²Đ±ÑƒĐ´Đ¾Đ²Đ°Đ½Đ¸Đ¼ Đ¿Đ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ°Đ¼. Đ¦Ñ– Đ¾Ñ‡Ñ–ĐºÑƒĐ²Đ°Đ½Ñ– Đ¿Đ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ¸ Đ²ĐºĐ»ÑÑ‡ĐµĐ½Đ¾ Đ´Đ»Ñ Đ¿ĐµĐ²Đ½Đ¸Ñ… Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚Ñ–Đ² Ñ–Đ· Đ²Đ¸ÑĐ¾ĐºĐ¸Đ¼ Ñ€Ñ–Đ²Đ½ĐµĐ¼ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸, Ñ‰Đ¾Đ± Đ·Đ°Ñ…Đ¸ÑÑ‚Đ¸Ñ‚Đ¸ Đ²Đ°Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">Đ¡Ñ‚Đ°Ñ‚Ñ‚Ñ Đ½Đµ Đ·Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾</translation>
+<translation id="4331708818696583467">ĐĐµĐ½Đ°Đ´Ñ–Đ¹Đ½Đµ</translation>
<translation id="4372948949327679948">ĐÑ‡Ñ–ĐºÑƒĐ²Đ°Đ½Đµ Đ·Đ½Đ°Ñ‡ĐµĐ½Đ½Ñ: <ph name="VALUE_TYPE" />.</translation>
-<translation id="4377125064752653719">Ви Đ¿Ñ€Đ¾Đ±ÑƒĐ²Đ°Đ»Đ¸ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />, Đ¿Ñ€Đ¾Ñ‚Đµ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚, Đ²Ñ–Đ´ĐºĐ»Đ¸ĐºĐ°Đ½Đ¸Đ¹ Đ¹Đ¾Đ³Đ¾ Đ²Đ¸Đ´Đ°Đ²Ñ†ĐµĐ¼. Це Đ¾Đ·Đ½Đ°Ñ‡Đ°Ñ”, Ñ‰Đ¾ Đ½Đµ Đ²Đ°Ñ€Ñ‚Đ¾ Đ´Đ¾Đ²Ñ–Ñ€ÑÑ‚Đ¸ Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¸Đ¼ Đ´Đ°Đ½Đ¸Đ¼ ÑиÑÑ‚ĐµĐ¼Đ¸ Đ·Đ°Ñ…Đ¸Ñту, Đ½Đ°Đ´Đ°Đ½Đ¸Đ¼ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ¼. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, Đ²Đ¸ Đ¾Đ±Đ¼Ñ–Đ½ÑÑ”Ñ‚ĐµÑÑ Đ´Đ°Đ½Đ¸Đ¼Đ¸ Đ·Ñ– Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºĐ¾Đ¼.</translation>
<translation id="4381091992796011497">Đ†Đ¼â€™Ñ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Đ°:</translation>
<translation id="4394049700291259645">Đ’Đ¸Đ¼ĐºĐ½ÑƒÑ‚Đ¸</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> – <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">Ñ€ĐµĐ·ÑƒĐ»ÑŒÑ‚Đ°Ñ‚Đ¸ Đ¿Đ¾ÑˆÑƒĐºÑƒ</translation>
-<translation id="4424024547088906515">Đ¦ĐµĐ¹ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ·Đ¼Ñ–Đ³ Đ´Đ¾Đ²ĐµÑÑ‚Đ¸, Ñ‰Đ¾ Đ²Ñ–Đ½ – Đ´Đ¾Đ¼ĐµĐ½ <ph name="DOMAIN" />. Chrome Đ½Đµ Đ²Đ²Đ°Đ¶Đ°Ñ” Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ½Đ°Đ´Ñ–Đ¹Đ½Đ¸Đ¼. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
+<translation id="4432688616882109544">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Đ½Đµ Đ¿Ñ€Đ¸Đ¹Đ½ÑĐ² Đ²Đ°Ñˆ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ²Ñ…Đ¾Đ´Ñƒ Đ°Đ±Đ¾ Đ²Đ¸ Đ½Đµ Đ½Đ°Đ´Đ°Đ»Đ¸ Ñ†ĐµĐ¹ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚.</translation>
<translation id="443673843213245140">Đ’Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ°Đ½Đ½Ñ Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Đ° Đ²Đ¸Đ¼ĐºĐ½ĐµĐ½Đ¾, але Ñ‡Ñ–Ñ‚ĐºĐ¾ Đ²ĐºĐ°Đ·Đ°Đ½Đ¾ Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½Đ½Ñ Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Đ°.</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">Ви Đ±Đ°Ñ‡Đ¸Ñ‚Đµ Ñ†Đµ Đ¿Đ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½Đ½Ñ, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²Đ²Ñ–Đ¼ĐºĐ½ĐµĐ½Đ¾ Google SafeSites.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Đ”ĐµÑ‚Đ°Đ»Ñ–</translation>
<translation id="4558551763791394412">Đ¡Đ¿Ñ€Đ¾Đ±ÑƒĐ¹Ñ‚Đµ Đ²Đ¸Đ¼ĐºĐ½ÑƒÑ‚Đ¸ Ñ€Đ¾Đ·ÑˆĐ¸Ñ€ĐµĐ½Đ½Ñ.</translation>
<translation id="4587425331216688090">Đ’Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸ Đ°Đ´Ñ€ĐµÑу Đ· Chrome?</translation>
+<translation id="4589078953350245614">Ви Đ½Đ°Đ¼Đ°Đ³Đ°Đ»Đ¸ÑÑ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />, але ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² Đ½ĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Đ—â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" /> ÑˆĐ¸Ñ„Ñ€ÑƒÑ”Ñ‚ÑŒÑÑ Đ·Đ° Đ´Đ¾Đ¿Đ¾Đ¼Đ¾Đ³Đ¾Ñ ÑÑƒÑ‡Đ°ÑĐ½Đ¾Đ³Đ¾ Đ½Đ°Đ±Đ¾Ñ€Ñƒ ÑˆĐ¸Ñ„Ñ€Ñ–Đ².</translation>
<translation id="4594403342090139922">&amp;Đ’Ñ–Đ´Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ Đ²Đ¸Đ´Đ°Đ»ĐµĐ½Đ½Ñ</translation>
+<translation id="4627442949885028695">ĐŸÑ€Đ¾Đ´Đ¾Đ²Đ¶Đ¸Ñ‚Đ¸ Đ½Đ° Ñ–Đ½ÑˆĐ¾Đ¼Ñƒ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ—</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Ви Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Đ°Ñ”Ñ‚Đµ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ Ñ€Đ¾Đ·ÑˆĐ¸Ñ€ĐµĐ½ÑŒ.</translation>
-<translation id="467662567472608290">Đ¦ĐµĐ¹ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ·Đ¼Ñ–Đ³ Đ´Đ¾Đ²ĐµÑÑ‚Đ¸, Ñ‰Đ¾ Đ²Ñ–Đ½ – Đ´Đ¾Đ¼ĐµĐ½ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ¼Ñ–ÑÑ‚Đ¸Ñ‚ÑŒ Đ¿Đ¾Đ¼Đ¸Đ»ĐºĐ¸. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
-<translation id="4697214168136963651">Đ¡Ñ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="URL" /> Đ·Đ°Đ±Đ»Đ¾ĐºĐ¾Đ²Đ°Đ½Đ¾</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Đ—â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Ñ€Đ¾Đ·Ñ–Ñ€Đ²Đ°Đ½Đ¾</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Đ¿Ñ€Đ¾Đ²ĐµÑÑ‚Đ¸ Đ´Ñ–Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºÑƒ Đ¼ĐµÑ€ĐµĐ¶Ñ– Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">ĐŸĐ»Đ°Ñ‚Ñ„Đ¾Ñ€Đ¼Đ°</translation>
<translation id="4744603770635761495">Đ’Đ¸ĐºĐ¾Đ½ÑƒĐ²Đ°Đ½Đ¸Đ¹ ÑˆĐ»ÑÑ…</translation>
<translation id="4756388243121344051">&amp;ІÑÑ‚Đ¾Ñ€Ñ–Ñ</translation>
+<translation id="4759238208242260848">Đ—Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶ĐµĐ½Đ½Ñ</translation>
<translation id="4764776831041365478">Веб-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ·Đ° Đ°Đ´Ñ€ĐµÑĐ¾Ñ <ph name="URL" /> Đ¼Đ¾Đ¶Đµ Đ±ÑƒÑ‚Đ¸ Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Đ¾ Đ½ĐµĐ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Đ¾Ñ Đ°Đ±Đ¾ Ñ—Ñ— Đ½Đ°Đ·Đ°Đ²Đ¶Đ´Đ¸ Đ¿ĐµÑ€ĐµĐ¼Ñ–Ñ‰ĐµĐ½Đ¾ Đ½Đ° Đ½Đ¾Đ²Ñƒ Đ²ĐµĐ±-Đ°Đ´Ñ€ĐµÑу.</translation>
<translation id="4771973620359291008">Đ’Đ¸Đ½Đ¸ĐºĐ»Đ° Đ½ĐµĐ²Ñ–Đ´Đ¾Đ¼Đ° Đ¿Đ¾Đ¼Đ¸Đ»ĐºĐ°.</translation>
<translation id="4782449893814226250">Ви Đ½Đ°Đ´Ñ–Ñлали Đ±Đ°Ñ‚ÑŒĐºĐ°Đ¼ Đ·Đ°Đ¿Đ¸Ñ‚ Đ½Đ° Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´ цієї ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸.</translation>
<translation id="4800132727771399293">ĐŸĐµÑ€ĐµĐ²Ñ–Ñ€Ñ‚Đµ Đ´Đ°Ñ‚Ñƒ Đ·Đ°ĐºÑ–Đ½Ñ‡ĐµĐ½Đ½Ñ Ñ‚ĐµÑ€Đ¼Ñ–Đ½Ñƒ Đ´Ñ–Ñ— Ñ‚Đ° ĐºĐ¾Đ´ CVC Ñ‚Đ° Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Ñ–Ñ‚ÑŒ ÑĐ¿Ñ€Đ¾Đ±Ñƒ</translation>
-<translation id="4807049035289105102">Đ—Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="SITE" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚ Đ½Đ°Đ´Ñ–ÑĐ»Đ°Đ² Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Ñ– Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Ñ– Đ´Đ°Đ½Ñ–, ÑĐºÑ– Google Chrome Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ¾Đ±Ñ€Đ¾Đ±Đ¸Ñ‚Đ¸. ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ¸ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ¹ Đ°Ñ‚Đ°ĐºĐ¸ Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Ñ” Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Đ¸Đ¼Đ¸, Ñ‚Đ¾Đ¼Ñƒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ¼Đ¾Đ¶Đµ Đ¿Ñ€Đ°Ñ†ÑĐ²Đ°Ñ‚Đ¸ Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ.</translation>
<translation id="4813512666221746211">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° Đ¼ĐµÑ€ĐµĐ¶Ñ–</translation>
<translation id="4816492930507672669">Đ—Đ° Ñ€Đ¾Đ·Đ¼Ñ–Ñ€Đ¾Đ¼ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸</translation>
<translation id="4850886885716139402">ĐŸĐµÑ€ĐµĐ³Đ»ÑĐ´</translation>
<translation id="4880827082731008257">ĐŸĐ¾ÑˆÑƒĐº Đ² Ñ–ÑÑ‚Đ¾Ñ€Ñ–Ñ—</translation>
+<translation id="4884656795097055129">Đ—Đ³Đ¾Đ´Đ¾Đ¼ тут з’ÑĐ²Đ»ÑÑ‚ÑŒÑÑ Ñ–Đ½ÑˆÑ– ÑÑ‚Đ°Ñ‚Ñ‚Ñ–.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{Ñ– Ñ‰Đµ 1 Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ°}one{Ñ– Ñ‰Đµ # Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ°}few{Ñ– Ñ‰Đµ # Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸}many{Ñ– Ñ‰Đµ # Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½Đ¾Đº}other{Ñ– Ñ‰Đµ # Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸}}</translation>
<translation id="4923417429809017348">Đ¦Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ Đ¿ĐµÑ€ĐµĐºĐ»Đ°Đ´ĐµĐ½Đ¾ Đ· Đ½ĐµĐ²Ñ–Đ´Đ¾Đ¼Đ¾Ñ— Đ¼Đ¾Đ²Đ¸ Đ¾Ñ€Đ¸Đ³Ñ–Đ½Đ°Đ»Ñƒ Ñ‚Đ°ĐºĐ¾Ñ Đ¼Đ¾Đ²Đ¾Ñ: <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">ĐŸĐ¾Ñ‚Ñ€Ñ–Đ±Đ½Đ¾ Đ²ĐºĐ°Đ·Đ°Ñ‚Đ¸.</translation>
<translation id="4930497775425430760">Ви Đ±Đ°Ñ‡Đ¸Ñ‚Đµ Ñ†Đµ Đ¿Đ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½Đ½Ñ, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ¾Đ´Đ¸Đ½ Ñ–Đ· Đ²Đ°ÑˆĐ¸Ñ… Đ±Đ°Ñ‚ÑŒĐºÑ–Đ² Đ¼Đ°Ñ” ÑÑ…Đ²Đ°Đ»Đ¸Ñ‚Đ¸ ÑĐ°Đ¹Ñ‚Đ¸, ÑĐºÑ– Đ²Đ¸ Đ²Ñ–Đ´Đ²Ñ–Đ´ÑƒÑ”Ñ‚Đµ Đ²Đ¿ĐµÑ€ÑˆĐµ.</translation>
<translation id="495170559598752135">Đ”Ñ–Ñ—</translation>
<translation id="4958444002117714549">Đ Đ¾Đ·Đ³Đ¾Ñ€Đ½ÑƒÑ‚Đ¸ ÑĐ¿Đ¸ÑĐ¾Đº</translation>
+<translation id="4962322354953122629">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Chrome Đ²Đ²Đ°Đ¶Đ°Ñ” Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ½ĐµĐ½Đ°Đ´Ñ–Đ¹Đ½Đ¸Đ¼. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">ĐŸĐµÑ€ĐµĐºĐ»Đ°ÑÑ‚Đ¸ Ñ†Ñ Đ¼Đ¾Đ²Đ½Ñƒ Đ¿Đ°Ñ€Ñƒ: <ph name="ORIGINAL_LANGUAGE" /> – <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Đ¦ĐµĐ¹ Đ¿Đ»Đ°Đ³Ñ–Đ½ Đ½Đµ Đ¿Ñ–Đ´Ñ‚Ñ€Đ¸Đ¼ÑƒÑ”Ñ‚ÑŒÑÑ</translation>
<translation id="5002932099480077015">ĐĐ¾Đ»Đ¸ Ñ†Ñ Ñ„ÑƒĐ½ĐºÑ†Ñ–Ñ Đ²Đ²Ñ–Đ¼ĐºĐ½ĐµĐ½Đ¾, Chrome Đ·Đ±ĐµÑ€Ñ–Đ³Đ°Ñ” ĐºĐ¾Đ¿Ñ–Ñ Đ´Đ°Đ½Đ¸Ñ… Đ²Đ°ÑˆĐ¾Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸ Đ½Đ° Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ—, Ñ‰Đ¾Đ± Đ²Đ¸ Đ¼Đ¾Đ³Đ»Đ¸ ÑˆĐ²Đ¸Đ´ÑˆĐµ Đ·Đ°Đ¿Đ¾Đ²Đ½ÑĐ²Đ°Ñ‚Đ¸ Ñ„Đ¾Ñ€Đ¼Đ¸.</translation>
<translation id="5019198164206649151">Đ ĐµĐ·ĐµÑ€Đ²Đ½Đ¸Đ¹ Đ½Đ¾ÑÑ–Đ¹ Đ¿Đ¾ÑˆĐºĐ¾Đ´Đ¶ĐµĐ½Đ¾</translation>
<translation id="5023310440958281426">ĐŸĐµÑ€ĐµĐ³Đ»ÑĐ½ÑŒÑ‚Đµ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ° ÑĐ²Đ¾Đ³Đ¾ Đ°Đ´Đ¼Ñ–Đ½Ñ–ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€Đ°</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">ĐŸÑ€Đ¾ ĐŸĐµÑ€ĐµĐºĐ»Đ°Đ´Đ°Ñ‡ Google</translation>
<translation id="5040262127954254034">ĐĐ¾Đ½Ñ„Ñ–Đ´ĐµĐ½Ñ†Ñ–Đ¹Đ½Ñ–ÑÑ‚ÑŒ</translation>
<translation id="5045550434625856497">ĐĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¸Đ¹ Đ¿Đ°Ñ€Đ¾Đ»ÑŒ</translation>
+<translation id="5056549851600133418">Đ¡Ñ‚Đ°Ñ‚Ñ‚Ñ– Đ´Đ»Ñ Đ²Đ°Ñ</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€Đ¸Ñ‚Đ¸ Đ°Đ´Ñ€ĐµÑу Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Đ°<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ·Đ°Ñ€Đ°Đ· Đ½ĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹.</translation>
<translation id="5089810972385038852">Đ¨Ñ‚Đ°Ñ‚</translation>
-<translation id="5094747076828555589">Đ¦ĐµĐ¹ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ·Đ¼Ñ–Đ³ Đ´Đ¾Đ²ĐµÑÑ‚Đ¸, Ñ‰Đ¾ Đ²Ñ–Đ½ – Đ´Đ¾Đ¼ĐµĐ½ <ph name="DOMAIN" />. Chromium Đ½Đµ Đ²Đ²Đ°Đ¶Đ°Ñ” Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ½Đ°Đ´Ñ–Đ¹Đ½Đ¸Đ¼. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
<translation id="5095208057601539847">ĐŸÑ€Đ¾Đ²Ñ–Đ½Ñ†Ñ–Ñ Ñ‡Đ¸ Đ¾Đ±Đ»Đ°ÑÑ‚ÑŒ</translation>
<translation id="5115563688576182185">(64-Ñ€Đ¾Đ·Ñ€ÑĐ´Đ½Đ° Đ²ĐµÑ€ÑÑ–Ñ)</translation>
-<translation id="5122371513570456792">Đ—Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾ Ñ€ĐµĐ·ÑƒĐ»ÑŒÑ‚Đ°Ñ‚Ñ–Đ² Đ·Đ° Đ·Đ°Đ¿Đ¸Ñ‚Đ¾Đ¼ "<ph name="SEARCH_STRING" />": <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" />.</translation>
<translation id="5141240743006678641">Đ¨Đ¸Ñ„Ñ€ÑƒĐ²Đ°Ñ‚Đ¸ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ¾Đ²Đ°Đ½Ñ– Đ¿Đ°Ñ€Đ¾Đ»Ñ– Đ·Đ° Đ´Đ¾Đ¿Đ¾Đ¼Đ¾Đ³Đ¾Ñ Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¸Ñ… Đ´Đ°Đ½Đ¸Ñ… Google</translation>
<translation id="5145883236150621069">Đ’Ñ–Đ´Đ¿Đ¾Đ²Ñ–Đ´ÑŒ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ° Đ¼Ñ–ÑÑ‚Đ¸Ñ‚ÑŒ ĐºĐ¾Đ´ Đ¿Đ¾Đ¼Đ¸Đ»ĐºĐ¸</translation>
<translation id="5171045022955879922">Đ—Đ½Đ°Đ¹Đ´Ñ–Ñ‚ÑŒ Đ°Đ±Đ¾ Đ²Đ²ĐµĐ´Ñ–Ñ‚ÑŒ URL-Đ°Đ´Ñ€ĐµÑу</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">ĐŸĐ°Đ½ĐµĐ»ÑŒ Đ·Đ°ĐºĐ»Đ°Đ´Đ¾Đº</translation>
<translation id="5199729219167945352">Đ•ĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ¸</translation>
<translation id="5251803541071282808">Đ¥Đ¼Đ°Ñ€Đ°</translation>
+<translation id="5277279256032773186">ĐĐ¾Ñ€Đ¸ÑÑ‚ÑƒÑ”Ñ‚ĐµÑÑ Chrome Đ½Đ° Ñ€Đ¾Đ±Đ¾Ñ‚Ñ–? ĐĐ¾Đ¼Đ¿Đ°Đ½Ñ–Ñ— Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²ÑƒĐ²Đ°Ñ‚Đ¸ Chrome Đ´Đ»Ñ ÑĐ²Đ¾Ñ—Ñ… Đ¿Ñ€Đ°Ñ†Ñ–Đ²Đ½Đ¸ĐºÑ–Đ². Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ</translation>
<translation id="5299298092464848405">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° Đ°Đ½Đ°Đ»Ñ–Đ·Ñƒ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°</translation>
<translation id="5300589172476337783">ĐŸĐ¾ĐºĐ°Đ·Đ°Ñ‚Đ¸</translation>
<translation id="5308689395849655368">ĐŸĐ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½Đ½Ñ Đ¿Ñ€Đ¾ Đ°Đ²Đ°Ñ€Ñ–Đ¹Đ½Đµ Đ·Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ½Ñ Ñ€Đ¾Đ±Đ¾Ñ‚Đ¸ Đ²Đ¸Đ¼ĐºĐ½ĐµĐ½Đ¾.</translation>
<translation id="5317780077021120954">Đ—Đ±ĐµÑ€ĐµĐ³Ñ‚Đ¸</translation>
<translation id="5327248766486351172">ĐĐ°Đ·Đ²Đ°</translation>
+<translation id="5359637492792381994">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ·Đ°Ñ€Đ°Đ· Đ½ĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° Đ·Đ±ĐµÑ€ĐµĐ¶ĐµĐ½Đ½Ñ Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½ÑŒ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°</translation>
-<translation id="540969355065856584">Đ¡ĐµÑ€Đ²ĐµÑ€Ñƒ Đ½Đµ Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ <ph name="DOMAIN" />. Đ™Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ·Đ°Ñ€Đ°Đ· Đ½ĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹. ĐœĐ¾Đ¶Đ»Đ¸Đ²Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Đ² Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
<translation id="5421136146218899937">ĐÑ‡Đ¸ÑÑ‚Đ¸Ñ‚Đ¸ Đ´Đ°Đ½Ñ– Đ²ĐµĐ±-Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Ñƒ...</translation>
<translation id="5430298929874300616">Đ’Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸ Đ·Đ°ĐºĐ»Đ°Đ´ĐºÑƒ</translation>
<translation id="5431657950005405462">Đ¤Đ°Đ¹Đ» Đ½Đµ Đ·Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾</translation>
<translation id="5435775191620395718">ĐŸĐ¾ĐºĐ°Đ·Đ°Đ½Đ¾ Ñ–ÑÑ‚Đ¾Ñ€Ñ–Ñ Đ· Ñ†ÑŒĐ¾Đ³Đ¾ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ. <ph name="BEGIN_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">ĐŸĐµÑ€ÑĐ¾Đ½Đ°Đ»Ñ–Đ·Đ¾Đ²Đ°Đ½Ñ– Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ— Đ²Đ¸Đ¼ĐºĐ½ĐµĐ½Đ¾, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²Đ°ÑˆÑ– ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ¾Đ²Đ°Đ½Ñ– Đ´Đ°Đ½Ñ– Đ·Đ°Ñ…Đ¸Ñ‰ĐµĐ½Đ¾ Đ¿Đ°Ñ€Đ¾Đ»ÑŒĐ½Đ¾Ñ Ñ„Ñ€Đ°Đ·Đ¾Ñ.</translation>
<translation id="5439770059721715174">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€ĐºĐ¸ ÑÑ…ĐµĐ¼Đ¸ Đ·Đ° Đ°Đ´Ñ€ĐµÑĐ¾Ñ "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">Đ¡Ñ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ Ñ…Đ¾Ñту <ph name="HOST_NAME" /> Đ½Đµ Đ·Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾</translation>
<translation id="5455374756549232013">ĐĐµĐ´Ñ–Đ¹ÑĐ½Đ° Đ¼Ñ–Ñ‚ĐºĐ° Ñ‡Đ°Ñу Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">ĐŸĐ¾ĐºĐ¸Đ½ÑƒÑ‚Đ¸ Ñ†ĐµĐ¹ ÑĐ°Đ¹Ñ‚?</translation>
<translation id="5629630648637658800">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° Đ·Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶ĐµĐ½Đ½Ñ Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½ÑŒ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°</translation>
<translation id="5631439013527180824">ĐĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹ Đ¼Đ°Ñ€ĐºĐµÑ€ ĐºĐµÑ€ÑƒĐ²Đ°Đ½Đ½Ñ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ</translation>
-<translation id="5650551054760837876">Đ ĐµĐ·ÑƒĐ»ÑŒÑ‚Đ°Ñ‚Ñ– Đ¿Đ¾ÑˆÑƒĐºÑƒ Đ²Ñ–Đ´ÑÑƒÑ‚Đ½Ñ–.</translation>
<translation id="5677928146339483299">Đ—Đ°Đ±Đ»Đ¾ĐºĐ¾Đ²Đ°Đ½Đ¾</translation>
<translation id="5710435578057952990">Đ†Đ´ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ†Ñ–Đ¹Đ½Ñƒ Ñ–Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ Ñ†ÑŒĐ¾Đ³Đ¾ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚Đ° Đ½Đµ Đ±ÑƒĐ»Đ¾ Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€ĐµĐ½Đ¾.</translation>
<translation id="5720705177508910913">ĐŸĐ¾Ñ‚Đ¾Ñ‡Đ½Đ¸Đ¹ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡</translation>
+<translation id="572328651809341494">ĐÑÑ‚Đ°Đ½Đ½Ñ– Đ²ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
<translation id="5784606427469807560">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸ Đ´Đ°Đ½Ñ– ĐºĐ°Ñ€Ñ‚ĐºĐ¸. ĐŸĐµÑ€ĐµĐ²Ñ–Ñ€Ñ‚Đµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ· Đ†Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚Đ¾Đ¼ Ñ– Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Ñ–Ñ‚ÑŒ ÑĐ¿Ñ€Đ¾Đ±Ñƒ.</translation>
<translation id="5785756445106461925">ĐĐºÑ€Ñ–Đ¼ Ñ†ÑŒĐ¾Đ³Đ¾, ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ¼Ñ–ÑÑ‚Đ¸Ñ‚ÑŒ Đ½ĐµĐ·Đ°Ñ…Đ¸Ñ‰ĐµĐ½Ñ– Ñ€ĐµÑурÑи. Đ†Đ½ÑˆÑ– Đ¾ÑĐ¾Đ±Đ¸ Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Đ°Ñ‚Đ¸ Ñ—Ñ… Đ¿Ñ–Đ´ Ñ‡Đ°Ñ Đ¿ĐµÑ€ĐµĐ´Đ°Đ²Đ°Đ½Đ½Ñ Đ´Đ°Đ½Đ¸Ñ…, Đ° Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºĐ¸ Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ·Đ¼Ñ–Đ½ÑĐ²Đ°Ñ‚Đ¸ Đ²Đ¸Đ³Đ»ÑĐ´ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸.</translation>
+<translation id="5786044859038896871">Đ’Đ²ĐµÑÑ‚Đ¸ Đ´Đ°Đ½Ñ– ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ¾Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸?</translation>
+<translation id="5803412860119678065">Đ’Đ²ĐµÑÑ‚Đ¸ Đ´Đ°Đ½Ñ– ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ¾Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸ <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">Đ—â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" /> ÑˆĐ¸Ñ„Ñ€ÑƒÑ”Ñ‚ÑŒÑÑ Đ·Đ° Đ´Đ¾Đ¿Đ¾Đ¼Đ¾Đ³Đ¾Ñ Đ·Đ°ÑÑ‚Đ°Ñ€Ñ–Đ»Đ¾Đ³Đ¾ Đ½Đ°Đ±Đ¾Ñ€Ñƒ ÑˆĐ¸Ñ„Ñ€Ñ–Đ².</translation>
<translation id="5813119285467412249">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đ¸ Đ´Đ¾Đ´Đ°Đ²Đ°Đ½Đ½Ñ</translation>
+<translation id="5814352347845180253">Ви Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ²Ñ‚Ñ€Đ°Ñ‚Đ¸Ñ‚Đ¸ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đ´Đ¾ Đ¿Đ»Đ°Ñ‚Đ½Đ¾Đ³Đ¾ Đ²Đ¼Ñ–Ñту Đ½Đ° ÑĐ°Đ¹Ñ‚Ñ– <ph name="SITE" /> Ñ– деÑĐºĐ¸Ñ… Ñ–Đ½ÑˆĐ¸Ñ… ÑĐ°Đ¹Ñ‚Đ°Ñ….</translation>
+<translation id="5843436854350372569">Ви Đ½Đ°Đ¼Đ°Đ³Đ°Đ»Đ¸ÑÑ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />, але ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚, ÑĐºĐ¸Đ¹ Đ¼Ñ–ÑÑ‚Đ¸Ñ‚ÑŒ ÑĐ»Đ°Đ±ĐºĐ¸Đ¹ ĐºĐ»Ñч. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸Đº Đ·Đ»Đ°Đ¼Đ°Đ² ÑĐµĐºÑ€ĐµÑ‚Đ½Đ¸Đ¹ ĐºĐ»Ñч, Đ° ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Ñ” Ñ‚Đ¸Đ¼, ÑĐºĐ¸Đ¹ Đ²Đ°Đ¼ Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±ĐµĐ½ (Đ²Đ¸ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ¿ĐµÑ€ĐµĐ´Đ°Đ²Đ°Ñ‚Đ¸ ÑĐ²Đ¾Ñ— Đ´Đ°Đ½Ñ– Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºÑƒ). <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Ви Đ±Đ°Ñ‡Đ¸Ñ‚Đµ Ñ†Đµ Đ¿Đ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½Đ½Ñ, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²Đ°Ñˆ Đ°Đ´Đ¼Ñ–Đ½Ñ–ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€ Đ·Đ°Đ±Đ»Đ¾ĐºÑƒĐ²Đ°Đ² Ñ†ĐµĐ¹ ÑĐ°Đ¹Ñ‚.</translation>
<translation id="5857090052475505287">ĐĐ¾Đ²Đ° Đ¿Đ°Đ¿ĐºĐ°</translation>
<translation id="5869405914158311789">ĐĐµĐ¼Đ°Ñ” Đ·Đ²â€™ÑĐ·ĐºÑƒ Ñ–Đ· ÑĐ°Đ¹Ñ‚Đ¾Đ¼</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">ĐŸĐ¾Ñ€Đ°Đ´Đ¸ Đ´Đ»Ñ Đ±Đ°Ñ‚ÑŒĐºÑ–Đ²</translation>
<translation id="59107663811261420">Đ¦ĐµĐ¹ Đ¿Ñ€Đ¾Đ´Đ°Đ²ĐµÑ†ÑŒ Đ½Đµ Đ¿Ñ€Đ¸Đ¹Đ¼Đ°Ñ” Ñ‚Đ°ĐºĐ¸Đ¹ Ñ‚Đ¸Đ¿ ĐºĐ°Ñ€Ñ‚ĐºĐ¸ Đ² Google Payments. Đ’Đ¸Đ±ĐµÑ€Ñ–Ñ‚ÑŒ Ñ–Đ½ÑˆÑƒ ĐºĐ°Ñ€Ñ‚ĐºÑƒ.</translation>
<translation id="59174027418879706">Đ£Đ²Ñ–Đ¼ĐºĐ½ĐµĐ½Đ¾</translation>
+<translation id="5926846154125914413">Ви Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ²Ñ‚Ñ€Đ°Ñ‚Đ¸Ñ‚Đ¸ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đ´Đ¾ Đ¿Đ»Đ°Ñ‚Đ½Đ¾Đ³Đ¾ Đ²Đ¼Ñ–Ñту Đ½Đ° деÑĐºĐ¸Ñ… ÑĐ°Đ¹Ñ‚Đ°Ñ….</translation>
<translation id="5966707198760109579">Đ¢Đ¸Đ¶Đ´ĐµĐ½ÑŒ</translation>
<translation id="5967867314010545767">Đ’Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸ Đ· Ñ–ÑÑ‚Đ¾Ñ€Ñ–Ñ—</translation>
<translation id="5975083100439434680">Đ—Đ¼ĐµĐ½ÑˆĐ¸Ñ‚Đ¸ Đ¼Đ°ÑÑˆÑ‚Đ°Đ±</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">ĐĐ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đ¾</translation>
<translation id="6042308850641462728">Đ‘Ñ–Đ»ÑŒÑˆĐµ</translation>
<translation id="6060685159320643512">ĐĐ±ĐµÑ€ĐµĐ¶Đ½Đ¾, ці ĐµĐºÑĐ¿ĐµÑ€Đ¸Đ¼ĐµĐ½Ñ‚Đ¸ Đ½ĐµĐ½Đ°Đ´Ñ–Đ¹Đ½Ñ–</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{Đ½ĐµĐ¼Đ°Ñ”}=1{1}one{#}few{#}many{#}other{#}}</translation>
<translation id="6146055958333702838">ĐŸĐµÑ€ĐµĐ²Ñ–Ñ€Ñ‚Đµ Đ²ÑÑ– ĐºĐ°Đ±ĐµĐ»Ñ– Ñ‚Đ° Đ¿ĐµÑ€ĐµĐ·Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶Ñ‚Đµ Đ²ÑÑ– Đ¼Đ°Ñ€ÑˆÑ€ÑƒÑ‚Đ¸Đ·Đ°Ñ‚Đ¾Ñ€Đ¸, Đ¼Đ¾Đ´ĐµĐ¼Đ¸ Ñ‡Đ¸ Ñ–Đ½ÑˆÑ– Đ¼ĐµÑ€ĐµĐ¶ĐµĐ²Ñ–
Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ—, ÑĐºÑ– Đ²Đ¸ Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑ”Ñ‚Đµ.</translation>
<translation id="614940544461990577">Đ¡Đ¿Ñ€Đ¾Đ±ÑƒĐ¹Ñ‚Đµ:</translation>
<translation id="6150607114729249911">Đ©Đ¾Đ± Đ²Ñ–Đ´Đ²Ñ–Đ´Đ°Ñ‚Đ¸ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ, Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±ĐµĐ½ Đ´Đ¾Đ·Đ²Ñ–Đ» Đ±Đ°Ñ‚ÑŒĐºÑ–Đ².</translation>
<translation id="6151417162996330722">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ¼Đ°Ñ” Đ·Đ°Đ´Đ¾Đ²Đ³Đ¸Đ¹ Ñ‚ĐµÑ€Đ¼Ñ–Đ½ Đ´Ñ–Ñ—.</translation>
-<translation id="6154808779448689242">ĐÑ‚Ñ€Đ¸Đ¼Đ°Đ½Đ¸Đ¹ Đ¼Đ°Ñ€ĐºĐµÑ€ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ° Đ½Đµ Đ·Đ±Ñ–Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ· Đ¿Đ¾Ñ‚Đ¾Ñ‡Đ½Đ¸Đ¼ Đ¼Đ°Ñ€ĐºĐµÑ€Đ¾Đ¼</translation>
<translation id="6165508094623778733">Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ</translation>
<translation id="6203231073485539293">ĐŸĐµÑ€ĐµĐ²Ñ–Ñ€Ñ‚Đµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ· Đ†Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚Đ¾Đ¼</translation>
<translation id="6218753634732582820">Đ’Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸ Đ°Đ´Ñ€ĐµÑу Đ· Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Đ¡Đ¿Ñ€Đ¾Đ±ÑƒĐ¹Ñ‚Đµ Đ²Đ¸Đ¼ĐºĐ½ÑƒÑ‚Đ¸ Đ¿Ñ€Đ¾Đ³Đ½Đ¾Đ·ÑƒĐ²Đ°Đ½Đ½Ñ Đ¼ĐµÑ€ĐµĐ¶Ñ–.</translation>
<translation id="6337534724793800597">Đ¤Ñ–Đ»ÑŒÑ‚Ñ€ÑƒĐ²Đ°Ñ‚Đ¸ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ° Đ·Đ° Đ½Đ°Đ·Đ²Đ¾Ñ</translation>
<translation id="6342069812937806050">Đ›Đ¸ÑˆĐµ Đ·Đ°Ñ€Đ°Đ·</translation>
+<translation id="6345221851280129312">Đ½ĐµĐ²Ñ–Đ´Đ¾Đ¼Đ¸Đ¹ Ñ€Đ¾Đ·Đ¼Ñ–Ñ€</translation>
<translation id="6355080345576803305">Đ—Đ°Đ¼Ñ–Đ½Đ° Đ·Đ°Đ³Đ°Đ»ÑŒĐ½Đ¾Đ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Đ¾Đ³Đ¾ ÑĐµĐ°Đ½Ñу</translation>
<translation id="6358450015545214790">Đ©Đ¾ Ñ†Đµ Đ¾Đ·Đ½Đ°Ñ‡Đ°Ñ”?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{Ñ– Ñ‰Đµ 1 Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ}one{Ñ– Ñ‰Đµ # Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ}few{Ñ– Ñ‰Đµ # Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ—}many{Ñ– Ñ‰Đµ # Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Đ¹}other{Ñ– Ñ‰Đµ # Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ—}}</translation>
<translation id="6387478394221739770">Đ¥Đ¾Ñ‡ĐµÑ‚Đµ ÑĐ¿Ñ€Đ¾Đ±ÑƒĐ²Đ°Ñ‚Đ¸ Đ½Đ¾Đ²Ñ– Ñ†Ñ–ĐºĐ°Đ²Ñ– Ñ„ÑƒĐ½ĐºÑ†Ñ–Ñ— Chrome? Đ—Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶Ñ‚Đµ Đ±ĐµÑ‚Đ°-Đ²ĐµÑ€ÑÑ–Ñ Đ·Ñ– ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸ chrome.com/beta.</translation>
-<translation id="641480858134062906">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ·Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶Đ¸Ñ‚Đ¸ <ph name="URL" /></translation>
+<translation id="6389758589412724634">ĐĐµĐ´Đ¾ÑÑ‚Đ°Ñ‚Đ½ÑŒĐ¾ Đ¿Đ°Đ¼â€™ÑÑ‚Ñ– Chromium, Ñ‰Đ¾Đ± Đ¿Đ¾ĐºĐ°Đ·Đ°Ñ‚Đ¸ Ñ†Ñ Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ.</translation>
+<translation id="6416403317709441254">Đ—Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="SITE" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚ Đ½Đ°Đ´Ñ–ÑĐ»Đ°Đ² Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Ñ– Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Ñ– Đ´Đ°Đ½Ñ–, ÑĐºÑ– Chromium Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ¾Đ±Ñ€Đ¾Đ±Đ¸Ñ‚Đ¸. ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ¸ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ¹ Đ°Ñ‚Đ°ĐºĐ¸ Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Ñ–, Ñ‚Đ¾Đ¼Ñƒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ°, ÑĐºĐ¾Ñ€Ñ–Ñˆ Đ·Đ° Đ²Ñе, Đ·Đ°Đ¿Ñ€Đ°Ñ†ÑÑ” Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">ĐĐµĐ¼Đ¾Đ¶Đ»Đ¸Đ²Đ¾ Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€Đ¸Ñ‚Đ¸, Ñ‡Đ¸ Ñ†ĐµĐ¹ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ÑƒĐ»Đ¾ Đ²Ñ–Đ´ĐºĐ»Đ¸ĐºĐ°Đ½Đ¾.</translation>
<translation id="6433595998831338502">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Đ²Ñ–Đ´Ñ…Đ¸Đ»Đ¸Đ² Đ·Đ°Đ¿Đ¸Ñ‚ Đ½Đ° Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
<translation id="6445051938772793705">ĐÑ€Đ°Ñ—Đ½Đ°</translation>
<translation id="6451458296329894277">ĐŸÑ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ½Đµ Đ½Đ°Đ´ÑĐ¸Đ»Đ°Đ½Đ½Ñ Ñ„Đ¾Ñ€Đ¼Đ¸</translation>
<translation id="6458467102616083041">Đ†Đ³Đ½Đ¾Ñ€ÑƒÑ”Ñ‚ÑŒÑÑ, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ¿Đ¾ÑˆÑƒĐº Đ·Đ° ÑƒĐ¼Đ¾Đ²Ñ‡Đ°Đ½Đ½ÑĐ¼ Đ²Đ¸Đ¼ĐºĐ½ĐµĐ½Đ¾ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾Đ¼.</translation>
+<translation id="6462969404041126431">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ²Ñ–Đ´ĐºĐ»Đ¸ĐºĐ°Đ½Đ¾. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ° Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ</translation>
<translation id="6489534406876378309">ĐŸĐ¾Ñ‡Đ°Ñ‚Đ¸ Đ·Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶ĐµĐ½Đ½Ñ Đ´Đ°Đ½Đ¸Ñ… Đ¿Ñ€Đ¾ Đ°Đ²Đ°Ñ€Ñ–Đ¹Đ½Đµ Đ·Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ½Ñ Ñ€Đ¾Đ±Đ¾Ñ‚Đ¸</translation>
<translation id="6529602333819889595">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đ¸ Đ²Đ¸Đ´Đ°Đ»ĐµĐ½Đ½Ñ</translation>
+<translation id="6534179046333460208">ĐŸÑ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ— ÑĐµÑ€Đ²Ñ–Ñу "Đ†Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ½Đ°Đ²ĐºĐ¾Đ»Đ¾ Đ½Đ°Ñ"</translation>
<translation id="6550675742724504774">ĐŸĐ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ¸</translation>
+<translation id="6593753688552673085">Đ¼ĐµĐ½ÑˆĐµ <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">ĐŸĐ°Ñ€Đ°Đ¼ĐµÑ‚Ñ€Đ¸ ÑˆĐ¸Ñ„Ñ€ÑƒĐ²Đ°Đ½Đ½Ñ</translation>
<translation id="662080504995468778">Đ—Đ°Đ»Đ¸ÑˆĐ¸Ñ‚Đ¸ÑÑ</translation>
<translation id="6628463337424475685">ĐŸĐ¾ÑˆÑƒĐº <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Đ—Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="SITE" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ <ph name="BEGIN_LINK" />Ñ†ĐµĐ¹ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ²Ñ–Đ´ĐºĐ»Đ¸ĐºĐ°Đ½Đ¾<ph name="END_LINK" />. ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ¸ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ¹ Đ°Ñ‚Đ°ĐºĐ¸ Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Ñ” Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Đ¸Đ¼Đ¸, Ñ‚Đ¾Đ¼Ñƒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ¼Đ¾Đ¶Đµ Đ¿Ñ€Đ°Ñ†ÑĐ²Đ°Ñ‚Đ¸ Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ.</translation>
<translation id="6644283850729428850">Це Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾ Đ±Ñ–Đ»ÑŒÑˆĐµ Đ½Đµ Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑ”Ñ‚ÑŒÑÑ.</translation>
+<translation id="6652240803263749613">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. ĐĐ¿ĐµÑ€Đ°Ñ†Ñ–Đ¹Đ½Đ° ÑиÑÑ‚ĐµĐ¼Đ° Đ²Đ°ÑˆĐ¾Đ³Đ¾ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Đ° Đ²Đ²Đ°Đ¶Đ°Ñ” Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ½ĐµĐ½Đ°Đ´Ñ–Đ¹Đ½Đ¸Đ¼. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Đ ĐµĐ´Đ°Đ³ÑƒĐ²Đ°Ñ‚Đ¸ Đ¿Đ°Đ¿ĐºÑƒ</translation>
<translation id="6660210980321319655">ĐĐ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đµ Đ¿Đ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½Đ½Ñ: <ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">Đ’Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸ Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ Đ°Đ²Ñ‚Đ¾Đ·Đ°Đ¿Đ¾Đ²Đ½ĐµĐ½Đ½Ñ Ñ„Đ¾Ñ€Đ¼ Ñ–Đ· Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">ĐŸĐ¾Đ¿ĐµÑ€ĐµĐ´Đ½Ñ”</translation>
<translation id="6710594484020273272">&lt;Đ’Đ²ĐµĐ´Ñ–Ñ‚ÑŒ Đ¿Đ¾ÑˆÑƒĐºĐ¾Đ²Đ¸Đ¹ Ñ‚ĐµÑ€Đ¼Ñ–Đ½&gt;</translation>
<translation id="6711464428925977395">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Đ° Đ°Đ±Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° Đ°Đ´Ñ€ĐµÑĐ°.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{Đ½ĐµĐ¼Đ°Ñ”}=1{1 Đ·Đ°Đ¿Đ¸Ñ}one{# Đ·Đ°Đ¿Đ¸Ñ}few{# Đ·Đ°Đ¿Đ¸Ñи}many{# Đ·Đ°Đ¿Đ¸ÑÑ–Đ²}other{# Đ·Đ°Đ¿Đ¸Ñу}}</translation>
<translation id="674375294223700098">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° "ĐĐµĐ²Ñ–Đ´Đ¾Đ¼Đ¸Đ¹ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ°".</translation>
<translation id="6753269504797312559">Đ—Đ½Đ°Ñ‡ĐµĐ½Đ½Ñ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ°</translation>
<translation id="6757797048963528358">Đ’Đ°Ñˆ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Ñ–Đ¹ Đ¿ĐµÑ€ĐµĐ¹ÑˆĐ¾Đ² у Ñ€ĐµĐ¶Đ¸Đ¼ ÑĐ½Ñƒ.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">ĐŸÑ€Đ°Đ²Đ¸Đ»Đ¾ Đ½Đµ Đ¿Ñ–Đ´Ñ‚Ñ€Đ¸Đ¼ÑƒÑ”Ñ‚ÑŒÑÑ.</translation>
<translation id="6895330447102777224">Đ”Đ°Đ½Ñ– ĐºĐ°Ñ€Ñ‚ĐºĐ¸ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¶ĐµĐ½Đ¾</translation>
<translation id="6897140037006041989">ĐĐ³ĐµĐ½Ñ‚ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Đ°</translation>
-<translation id="6903907808598579934">Đ£Đ²Ñ–Đ¼ĐºĐ½ÑƒÑ‚Đ¸ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ°Ñ†Ñ–Ñ</translation>
<translation id="6915804003454593391">ĐĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡:</translation>
<translation id="6957887021205513506">Đ¡Ñ…Đ¾Đ¶Đµ, Ñ‰Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ¿Ñ–Đ´Ñ€Đ¾Đ±Đ»ĐµĐ½Đ¾.</translation>
<translation id="6965382102122355670">ĐĐ</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Đ Đ°Đ¹Đ¾Đ½ Đ°Đ±Đ¾ Đ¾ĐºÑ€ÑƒĐ³</translation>
<translation id="6973656660372572881">Đ£ĐºĐ°Đ·Đ°Đ½Đ¾ Ñ„Ñ–ĐºÑĐ¾Đ²Đ°Đ½Ñ– Đ¿Ñ€Đ¾ĐºÑÑ–-ÑĐµÑ€Đ²ĐµÑ€Đ¸ Ñ‚Đ° URL-Đ°Đ´Ñ€ĐµÑĐ° ÑÑ†ĐµĐ½Đ°Ñ€Ñ–Ñ .pac.</translation>
<translation id="6989763994942163495">ĐŸĐ¾ĐºĐ°Đ·Đ°Ñ‚Đ¸ Ñ€Đ¾Đ·ÑˆĐ¸Ñ€ĐµĐ½Ñ– Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½Đ½Ñ...</translation>
+<translation id="7000990526846637657">ĐĐµĐ¼Đ°Ñ” Đ·Đ°Đ¿Đ¸ÑÑ–Đ² Đ² Ñ–ÑÑ‚Đ¾Ñ€Ñ–Ñ—</translation>
+<translation id="7009986207543992532">Ви Đ½Đ°Đ¼Đ°Đ³Đ°Đ»Đ¸ÑÑ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />, але ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Ñ–Đ· Đ·Đ°Đ´Đ¾Đ²Đ³Đ¸Đ¼ Ñ‚ĐµÑ€Đ¼Ñ–Đ½Đ¾Đ¼ Đ´Ñ–Ñ—. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">ІÑÑ‚Đ¾Ñ€Ñ–Ñ Đ²ĐµĐ±-Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Ñƒ Ñ‚Đ°ĐºĐ¾Đ¶ Đ¼Đ¾Đ¶Đµ Đ·Đ±ĐµÑ€Ñ–Đ³Đ°Ñ‚Đ¸ÑÑ Ñƒ Đ²Đ°ÑˆĐ¾Đ¼Ñƒ Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¾Đ¼Ñƒ Đ·Đ°Đ¿Đ¸ÑÑ– Google Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½Ñ†Ñ– <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">ĐŸĐ°Ñ€Đ¾Đ»Ñ–</translation>
-<translation id="7050187094878475250">Ви Đ½Đ°Đ¼Đ°Đ³Đ°Đ»Đ¸ÑÑ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />, але ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Ñ–Đ· Đ·Đ°Đ´Đ¾Đ²Đ³Đ¸Đ¼ Ñ‚ĐµÑ€Đ¼Ñ–Đ½Đ¾Đ¼ Đ´Ñ–Ñ—.</translation>
<translation id="7087282848513945231">ĐĐºÑ€ÑƒĐ³ Đ°Đ±Đ¾ Đ³Ñ€Đ°Ñ„ÑÑ‚Đ²Đ¾</translation>
<translation id="7088615885725309056">Đ”Đ°Đ²Đ½Ñ–ÑˆĐµ</translation>
<translation id="7090678807593890770">ĐŸĐ¾ÑˆÑƒĐºĐ°Đ¹Ñ‚Đµ Đ·Đ° Đ·Đ°Đ¿Đ¸Ñ‚Đ¾Đ¼ "<ph name="LINK" />" у Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Ви Đ±Đ°Ñ‡Đ¸Ñ‚Đµ Ñ†Đµ Đ¿Đ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½Đ½Ñ, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²Đ°Ñˆ Đ°Đ´Đ¼Ñ–Đ½Ñ–ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€ Đ¼Đ°Ñ” ÑÑ…Đ²Đ°Đ»Đ¸Ñ‚Đ¸ ÑĐ°Đ¹Ñ‚Đ¸, ÑĐºÑ– Đ²Đ¸ Đ²Ñ–Đ´Đ²Ñ–Đ´ÑƒÑ”Ñ‚Đµ Đ²Đ¿ĐµÑ€ÑˆĐµ.</translation>
<translation id="724975217298816891">Đ’Đ²ĐµĐ´Ñ–Ñ‚ÑŒ Ñ‚ĐµÑ€Đ¼Ñ–Đ½ Đ´Ñ–Ñ— Ñ‚Đ° ĐºĐ¾Đ´ CVC ĐºĐ°Ñ€Ñ‚ĐºĐ¸ <ph name="CREDIT_CARD" />, Ñ‰Đ¾Đ± Đ¾Đ½Đ¾Đ²Đ¸Ñ‚Đ¸ Ñ—Ñ— Đ´Đ°Đ½Ñ–. Đ©Đ¾Đ¹Đ½Đ¾ Đ²Đ¸ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đµ Đ´Đ°Đ½Ñ– ĐºĐ°Ñ€Ñ‚ĐºĐ¸, Ñ†ĐµĐ¹ ÑĐ°Đ¹Ñ‚ Đ¾Ñ‚Ñ€Đ¸Đ¼Đ°Ñ” Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đ´Đ¾ Đ½Đ¸Ñ….</translation>
<translation id="725866823122871198">Đе Đ²Đ´Đ°Ñ”Ñ‚ÑŒÑÑ Đ²ÑÑ‚Đ°Đ½Đ¾Đ²Đ¸Ñ‚Đ¸ ĐºĐ¾Đ½Ñ„Ñ–Đ´ĐµĐ½Ñ†Ñ–Đ¹Đ½Đµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ· <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ½Đ° ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€Ñ– Đ²ÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Ñ– Đ´Đ°Ñ‚Ñƒ Đ¹ Ñ‡Đ°Ñ (<ph name="DATE_AND_TIME" />).</translation>
-<translation id="7265986070661382626">Đ—Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="SITE" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Ñ†ĐµĐ¹ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚ <ph name="BEGIN_LINK" />Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑ” Đ·Đ°ĐºÑ€Ñ–Đ¿Đ»ĐµĐ½Đ½Ñ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Ñ–Đ²<ph name="END_LINK" />. ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ¸ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ¹ Đ°Ñ‚Đ°ĐºĐ¸ Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Ñ” Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Đ¸Đ¼Đ¸, Ñ‚Đ¾Đ¼Ñƒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ¼Đ¾Đ¶Đµ Đ¿Ñ€Đ°Ñ†ÑĐ²Đ°Ñ‚Đ¸ Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ.</translation>
<translation id="7269802741830436641">Đ¦Ñ Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ¼Đ°Ñ” Ñ†Đ¸ĐºĐ» Đ¿ĐµÑ€ĐµĐ½Đ°Đ¿Ñ€Đ°Đ²Đ»ĐµĐ½ÑŒ</translation>
<translation id="7275334191706090484">Đ—Đ°ĐºĐ»Đ°Đ´ĐºĐ¸, ÑĐºĐ¸Đ¼Đ¸ ĐºĐµÑ€ÑƒÑ” Đ°Đ´Đ¼Ñ–Đ½Ñ–ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€</translation>
<translation id="7298195798382681320">Đ ĐµĐºĐ¾Đ¼ĐµĐ½Đ´Đ¾Đ²Đ°Đ½Đµ</translation>
-<translation id="7301833672208172928">Đ£Đ²Ñ–Đ¼ĐºĐ½ÑƒÑ‚Đ¸ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ°Ñ†Ñ–Ñ Ñ–ÑÑ‚Đ¾Ñ€Ñ–Ñ—</translation>
+<translation id="7309308571273880165">Đ—Đ²Ñ–Ñ‚ Đ¿Ñ€Đ¾ Đ°Đ²Đ°Ñ€Ñ–Đ¹Đ½Đµ Đ·Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ½Ñ Ñ€Đ¾Đ±Đ¾Ñ‚Đ¸ ÑÑ‚Đ²Đ¾Ñ€ĐµĐ½Đ¾ <ph name="CRASH_TIME" /> (Ñ‰Đµ Đ½Đµ Đ·Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶ĐµĐ½Đ¾)</translation>
<translation id="7334320624316649418">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đ¸ Đ¿ĐµÑ€ĐµĐ²Đ¿Đ¾Ñ€ÑĐ´ĐºÑƒĐ²Đ°Đ½Đ½Ñ</translation>
<translation id="733923710415886693">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ½Đµ Đ½Đ°Đ´Đ°Đ² Ñ–Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ Đ¿Ñ€Đ¾ Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€ĐºÑƒ.</translation>
+<translation id="7351800657706554155">Đ—Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đ½Đ° Đ¿ĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ <ph name="SITE" />, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Ñ—Ñ— ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ²Ñ–Đ´ĐºĐ»Đ¸ĐºĐ°Đ½Đ¾. ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ¸ Đ¼ĐµÑ€ĐµĐ¶Ñ– Đ¹ Đ°Ñ‚Đ°ĐºĐ¸ Đ·Đ°Đ·Đ²Đ¸Ñ‡Đ°Đ¹ Ñ‚Đ¸Đ¼Ñ‡Đ°ÑĐ¾Đ²Ñ–, Ñ‚Đ¾Đ¼Ñƒ Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ°, ÑĐºĐ¾Ñ€Ñ–Ñˆ Đ·Đ° Đ²Ñе, Đ·Đ°Đ¿Ñ€Đ°Ñ†ÑÑ” Đ¿Ñ–Đ·Đ½Ñ–ÑˆĐµ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">ĐĐ¾Đ¼Đ°Đ½Đ´Đ½Đ¸Đ¹ Ñ€ÑĐ´Đ¾Đº</translation>
<translation id="7372973238305370288">Ñ€ĐµĐ·ÑƒĐ»ÑŒÑ‚Đ°Ñ‚ Đ¿Đ¾ÑˆÑƒĐºÑƒ</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">ĐŸÑ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¶ĐµĐ½Đ½Ñ Đ´Đ°Đ½Đ¸Ñ… ĐºĐ°Ñ€Ñ‚ĐºĐ¸</translation>
<translation id="7481312909269577407">ĐŸĐµÑ€ĐµÑĐ»Đ°Ñ‚Đ¸</translation>
<translation id="7485870689360869515">Đ”Đ°Đ½Đ¸Ñ… Đ½Đµ Đ·Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾.</translation>
+<translation id="7508255263130623398">ĐÑ‚Ñ€Đ¸Đ¼Đ°Đ½Đ¸Đ¹ Ñ–Đ´ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ¾Ñ€ Đ¿Ñ€Đ°Đ²Đ¸Đ» Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ Đ¿Đ¾Ñ€Đ¾Đ¶Đ½Ñ–Đ¹ Đ°Đ±Đ¾ Đ½Đµ Đ·Đ±Ñ–Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ· Đ¿Đ¾Ñ‚Đ¾Ñ‡Đ½Đ¸Đ¼ Ñ–Đ´ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ¾Ñ€Đ¾Đ¼ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ</translation>
<translation id="7514365320538308">Đ—Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶Đ¸Ñ‚Đ¸</translation>
<translation id="7518003948725431193">Đе Đ·Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾ Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½Đ¾Đº Đ´Đ»Ñ Đ²ĐµĐ±-Đ°Đ´Ñ€ĐµÑи <ph name="URL" /></translation>
<translation id="7537536606612762813">ĐĐ±Đ¾Đ²â€™ÑĐ·ĐºĐ¾Đ²Đµ</translation>
<translation id="7542995811387359312">ĐĐ²Ñ‚Đ¾Đ¼Đ°Ñ‚Đ¸Ñ‡Đ½Đµ Đ·Đ°Đ¿Đ¾Đ²Đ½ĐµĐ½Đ½Ñ ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ¾Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸ Đ²Đ¸Đ¼ĐºĐ½ĐµĐ½Đ¾, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ Ñ†Ñ Ñ„Đ¾Ñ€Đ¼Đ° Đ½Đµ Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑ” Đ±ĐµĐ·Đ¿ĐµÑ‡Đ½Đµ Đ·'Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
<translation id="7549584377607005141">Đ”Đ»Ñ Đ½Đ°Đ»ĐµĐ¶Đ½Đ¾Đ³Đ¾ Đ²Ñ–Đ´Đ¾Đ±Ñ€Đ°Đ¶ĐµĐ½Đ½Ñ Ñ†Ñ–Đ¹ Đ²ĐµĐ±-ÑÑ‚Đ¾Ñ€Ñ–Đ½Ñ†Ñ– Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±Đ½Ñ– Đ²Đ²ĐµĐ´ĐµĐ½Ñ– Đ²Đ°Đ¼Đ¸ Ñ€Đ°Đ½Ñ–ÑˆĐµ Đ´Đ°Đ½Ñ–. ĐœĐ¾Đ¶Đ½Đ° Ñ‰Đµ Ñ€Đ°Đ· Đ½Đ°Đ´Ñ–ÑĐ»Đ°Ñ‚Đ¸ Đ´Đ°Đ½Ñ–, Đ¾Đ´Đ½Đ°Đº Đ·Ñ€Đ¾Đ±Đ¸Đ²ÑˆĐ¸ Ñ†Đµ, Đ²Đ¸ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đµ Đ²ÑÑ– Đ´Ñ–Ñ—, ÑĐºÑ– Ñ†Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ²Đ¸ĐºĐ¾Đ½ÑƒĐ²Đ°Đ»Đ° Ñ€Đ°Đ½Ñ–ÑˆĐµ.</translation>
<translation id="7554791636758816595">ĐĐ¾Đ²Đ° Đ²ĐºĐ»Đ°Đ´ĐºĐ°</translation>
-<translation id="7567204685887185387">Đ¦ĐµĐ¹ ÑĐµÑ€Đ²ĐµÑ€ Đ½Đµ Đ·Đ¼Ñ–Đ³ Đ´Đ¾Đ²ĐµÑÑ‚Đ¸, Ñ‰Đ¾ Đ²Ñ–Đ½ – Đ´Đ¾Đ¼ĐµĐ½ <ph name="DOMAIN" />. ĐœĐ¾Đ¶Đ»Đ¸Đ²Đ¾, Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ²Đ¸Đ´Đ°Đ»Đ¸ ÑˆĐ°Ñ…Ñ€Đ°Ñ—. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ° ĐºĐ¾Đ½Ñ„Ñ–Đ³ÑƒÑ€Đ°Ñ†Ñ–Ñ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ.</translation>
<translation id="7568593326407688803">ĐœĐ¾Đ²Đ° цієї ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸:<ph name="ORIGINAL_LANGUAGE" />ĐŸĐµÑ€ĐµĐºĐ»Đ°ÑÑ‚Đ¸ Ñ—Ñ—?</translation>
<translation id="7569952961197462199">Đ’Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸ Đ´Đ°Đ½Ñ– ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ¾Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸ Đ· Chrome?</translation>
<translation id="7578104083680115302">Đ—Đ±ĐµÑ€Ñ–Đ³Đ°Đ¹Ñ‚Đµ ĐºĐ°Ñ€Ñ‚ĐºĐ¸ Đ² Google, Ñ‰Đ¾Đ± ÑˆĐ²Đ¸Đ´ĐºĐ¾ Đ¿Đ»Đ°Ñ‚Đ¸Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚Đ°Ñ… Ñ– Đ² Đ´Đ¾Đ´Đ°Ñ‚ĐºĐ°Ñ… Đ½Đ° Đ²ÑÑ–Ñ… ÑĐ²Đ¾Ñ—Ñ… Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾ÑÑ….</translation>
+<translation id="7588950540487816470">Đ†Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚ Đ½Đ°Đ²ĐºĐ¾Đ»Đ¾ Đ½Đ°Ñ</translation>
<translation id="7592362899630581445">Đ¡ĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ¿Đ¾Ñ€ÑƒÑˆÑƒÑ” Đ¾Đ±Đ¼ĐµĐ¶ÑƒĐ²Đ°Đ»ÑŒĐ½Ñ– ÑƒĐ¼Đ¾Đ²Đ¸ Ñ‰Đ¾Đ´Đ¾ Ñ–Đ¼ĐµĐ½.</translation>
<translation id="759889825892636187">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Đ·Đ°Ñ€Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ¾Đ±Ñ€Đ¾Đ±Đ¸Ñ‚Đ¸ Ñ†ĐµĐ¹ Đ·Đ°Đ¿Đ¸Ñ‚.</translation>
<translation id="7600965453749440009">ĐÑ–ĐºĐ¾Đ»Đ¸ Đ½Đµ Đ¿ĐµÑ€ĐµĐºĐ»Đ°Đ´Đ°Ñ‚Đ¸ Đ· Ñ‚Đ°ĐºĐ¾Ñ— Đ¼Đ¾Đ²Đ¸: <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">Đ’Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸ Đ´Đ°Đ½Ñ– ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ¾Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸ Đ· Chromium?</translation>
<translation id="765676359832457558">Đ¡Ñ…Đ¾Đ²Đ°Ñ‚Đ¸ Ñ€Đ¾Đ·ÑˆĐ¸Ñ€ĐµĐ½Ñ– Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½Đ½Ñ...</translation>
<translation id="7658239707568436148">Đ¡ĐºĐ°ÑÑƒĐ²Đ°Ñ‚Đ¸</translation>
+<translation id="7667346355482952095">ĐÑ‚Ñ€Đ¸Đ¼Đ°Đ½Đ¸Đ¹ Đ¼Đ°Ñ€ĐºĐµÑ€ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ° Đ¿Đ¾Ñ€Đ¾Đ¶Đ½Ñ–Đ¹ Đ°Đ±Đ¾ Đ½Đµ Đ·Đ±Ñ–Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ· Đ¿Đ¾Ñ‚Đ¾Ñ‡Đ½Đ¸Đ¼ Đ¼Đ°Ñ€ĐºĐµÑ€Đ¾Đ¼</translation>
<translation id="7668654391829183341">ĐĐµĐ²Ñ–Đ´Đ¾Đ¼Đ¸Đ¹ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Ñ–Đ¹</translation>
<translation id="7674629440242451245">Đ¥Đ¾Ñ‡ĐµÑ‚Đµ ÑĐ¿Ñ€Đ¾Đ±ÑƒĐ²Đ°Ñ‚Đ¸ Đ½Đ¾Đ²Ñ– Ñ†Ñ–ĐºĐ°Đ²Ñ– Ñ„ÑƒĐ½ĐºÑ†Ñ–Ñ— Chrome? Đ—Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶Ñ‚Đµ Đ²ĐµÑ€ÑÑ–Ñ Đ´Đ»Ñ Ñ€Đ¾Đ·Ñ€Đ¾Đ±Đ½Đ¸ĐºÑ–Đ² Đ·Ñ– ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸ chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />ĐŸĐµÑ€ĐµĐ¹Ñ‚Đ¸ Đ½Đ° ÑĐ°Đ¹Ñ‚ <ph name="SITE" /> (Đ½ĐµĐ±ĐµĐ·Đ¿ĐµÑ‡Đ½Đ¾)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">ĐÑ–, Đ´ÑĐºÑƒÑ</translation>
<translation id="7805768142964895445">Đ¡Ñ‚Đ°Ñ‚ÑƒÑ</translation>
<translation id="7813600968533626083">Đ’Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸ Đ´Đ°Đ½Ñ– Đ´Đ»Ñ Đ°Đ²Ñ‚Đ¾Đ·Đ°Đ¿Đ¾Đ²Đ½ĐµĐ½Đ½Ñ Ñ„Đ¾Ñ€Đ¼ Ñ–Đ· Chrome?</translation>
+<translation id="7815407501681723534">Đ—Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾ Ñ€ĐµĐ·ÑƒĐ»ÑŒÑ‚Đ°Ñ‚Ñ–Đ² Đ·Đ° Đ·Đ°Đ¿Đ¸Ñ‚Đ¾Đ¼ "<ph name="SEARCH_STRING" />": <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /></translation>
<translation id="785549533363645510">ĐĐ°Đ²Ñ–Ñ‚ÑŒ у Ñ€ĐµĐ¶Đ¸Đ¼Ñ– Đ°Đ½Đ¾Đ½Ñ–Đ¼Đ½Đ¾Đ³Đ¾ Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Ñƒ Đ²Đ°Ñˆ Ñ€Đ¾Đ±Đ¾Ñ‚Đ¾Đ´Đ°Đ²ĐµÑ†ÑŒ, Đ¿Đ¾ÑÑ‚Đ°Ñ‡Đ°Đ»ÑŒĐ½Đ¸Đº Đ¿Đ¾ÑĐ»ÑƒĐ³ Đ†Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚Ñƒ Ñ‡Đ¸ Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚Đ¸, ÑĐºÑ– Đ²Đ¸ Đ²Ñ–Đ´Đ²Ñ–Đ´ÑƒÑ”Ñ‚Đµ, Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ±Đ°Ñ‡Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Đ²Đ¸ Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Đ°Ñ”Ñ‚Đµ.</translation>
<translation id="7887683347370398519">ĐŸĐµÑ€ĐµĐ²Ñ–Ñ€Ñ‚Đµ ĐºĐ¾Đ´ CVC Đ¹ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€Ñ–Ñ‚ÑŒ ÑĐ¿Ñ€Đ¾Đ±Ñƒ</translation>
<translation id="7894616681410591072">Đ©Đ¾Đ± Đ¾Ñ‚Ñ€Đ¸Đ¼Đ°Ñ‚Đ¸ Đ´Đ¾ÑÑ‚ÑƒĐ¿ Đ´Đ¾ цієї ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸, <ph name="NAME" /> Đ¼Đ°Ñ” Đ½Đ°Đ´Đ°Ñ‚Đ¸ Đ²Đ°Đ¼ Đ´Đ¾Đ·Đ²Ñ–Đ».</translation>
-<translation id="790025292736025802"><ph name="URL" /> Đ½Đµ Đ·Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾</translation>
<translation id="7912024687060120840">Đ£ Đ¿Đ°Đ¿Ñ†Ñ–:</translation>
<translation id="7920092496846849526">Ви Đ½Đ°Đ´Ñ–Ñлали Đ¾Đ´Đ½Đ¾Đ¼Ñƒ Đ· Đ±Đ°Ñ‚ÑŒĐºÑ–Đ² Đ·Đ°Đ¿Đ¸Ñ‚ Đ½Đ° Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´ цієї ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸.</translation>
<translation id="7935318582918952113">ДиÑÑ‚Đ¸Đ»ÑÑ‚Đ¾Ñ€ DOM</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">Đе Đ²ĐºĐ°Đ·Đ°Đ½Đ¾</translation>
<translation id="8012647001091218357">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ²Đ°ÑˆĐ¸Đ¼Đ¸ Đ±Đ°Ñ‚ÑŒĐºĐ°Đ¼Đ¸. ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Ñ–Ñ‚ÑŒ ÑĐ¿Ñ€Đ¾Đ±Ñƒ.</translation>
<translation id="8034522405403831421">ĐœĐ¾Đ²Đ° цієї ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸: <ph name="SOURCE_LANGUAGE" />. ĐŸĐµÑ€ĐµĐºĐ»Đ°ÑÑ‚Đ¸ Ñ—Ñ— Ñ‚Đ°ĐºĐ¾Ñ Đ¼Đ¾Đ²Đ¾Ñ: <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">Đ—Đ°Đ¿Đ¸Ñи Đ² Ñ–ÑÑ‚Đ¾Ñ€Ñ–Ñ— Đ½Đµ Đ·Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾.</translation>
<translation id="8088680233425245692">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ½ÑƒÑ‚Đ¸ ÑÑ‚Đ°Ñ‚Ñ‚Ñ.</translation>
+<translation id="8089520772729574115">Đ¼ĐµĐ½ÑˆĐµ 1 ĐœĐ±</translation>
<translation id="8091372947890762290">ĐĐºÑ‚Đ¸Đ²Đ°Ñ†Ñ–Ñ Đ¾Ñ‡Ñ–ĐºÑƒÑ” Đ½Đ° ÑĐµÑ€Đ²ĐµÑ€Ñ–</translation>
+<translation id="8129262335948759431">Đ½ĐµĐ²Ñ–Đ´Đ¾Đ¼Đ° ĐºÑ–Đ»ÑŒĐºÑ–ÑÑ‚ÑŒ</translation>
<translation id="8131740175452115882">ĐŸÑ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸</translation>
<translation id="8134994873729925007">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ·Đ½Đ°Đ¹Ñ‚Đ¸ <ph name="BEGIN_ABBR" />Đ°Đ´Ñ€ĐµÑу DNS-ÑĐµÑ€Đ²ĐµÑ€Đ°<ph name="END_ABBR" /> Ñ…Đ¾Ñту <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">Đ’Đ°Ñˆ ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€ Đ¿ĐµÑ€ĐµĐ¹ÑˆĐ¾Đ² у Ñ€ĐµĐ¶Đ¸Đ¼ ÑĐ½Ñƒ.</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">ĐĐµĐ´Ñ–Đ¹ÑĐ½Đ° URL-Đ°Đ´Ñ€ĐµÑĐ° Đ´Đ»Ñ Đ¾Đ½Đ¾Đ²Đ»ĐµĐ½Đ½Ñ Ñ€Đ¾Đ·ÑˆĐ¸Ñ€ĐµĐ½Đ½Ñ Đ· Ñ–Đ´ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ¾Ñ€Đ¾Đ¼ "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Đ£ĐºĐ°Đ·Đ°Đ½Đµ Đ¼Ñ–ÑÑ†ĐµĐ·Đ½Đ°Ñ…Đ¾Đ´Đ¶ĐµĐ½Đ½Ñ:</translation>
<translation id="8225771182978767009">ĐĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡, ÑĐºĐ¸Đ¹ Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ² ĐºĐ¾Đ¼Đ¿â€™ÑÑ‚ĐµÑ€, Đ·Đ°Đ±Đ»Đ¾ĐºÑƒĐ²Đ°Đ² Ñ†ĐµĐ¹ ÑĐ°Đ¹Ñ‚.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Đ¡Ñ‚Đ¾Ñ€Ñ–Đ½ĐºĐ°, ÑĐºÑƒ Đ²Đ¸ ÑˆÑƒĐºĐ°Ñ”Ñ‚Đµ, Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒĐ²Đ°Đ»Đ° Ñ–Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ, Đ²Đ²ĐµĐ´ĐµĐ½Ñƒ Đ²Đ°Đ¼Đ¸. ĐŸĐ¾Đ²ĐµÑ€Đ½ĐµĐ½Đ½Ñ Đ´Đ¾ Ñ‚Đ°ĐºĐ¾Ñ— ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸ Đ¼Đ¾Đ¶Đµ Đ¿Ñ€Đ¸Đ·Đ²ĐµÑÑ‚Đ¸ Đ´Đ¾ Đ¿Đ¾Đ²Ñ‚Đ¾Ñ€ĐµĐ½Đ½Ñ Đ²Đ°ÑˆĐ¸Ñ… Đ¿Đ¾Đ¿ĐµÑ€ĐµĐ´Đ½Ñ–Ñ… Đ´Ñ–Đ¹. Ви Đ´Ñ–Đ¹ÑĐ½Đ¾ Đ±Đ°Đ¶Đ°Ñ”Ñ‚Đµ Đ¿Ñ€Đ¾Đ´Đ¾Đ²Đ¶Đ¸Ñ‚Đ¸?</translation>
<translation id="8249320324621329438">Đ’Đ¾ÑÑ‚Đ°Đ½Đ½Ñ” Đ¾Ñ‚Ñ€Đ¸Đ¼Đ°Đ½Đ¾:</translation>
<translation id="8261506727792406068">Đ’Đ¸Đ´Đ°Đ»Đ¸Ñ‚Đ¸</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">ĐŸĐ°Đ½ĐµĐ»ÑŒ Đ·Đ°ĐºĐ»Đ°Đ´Đ¾Đº</translation>
<translation id="8363502534493474904">Đ²Đ¸Đ¼ĐºĐ½ÑƒÑ‚Đ¸ Ñ€ĐµĐ¶Đ¸Đ¼ Đ¿Đ¾Đ»ÑŒĐ¾Ñ‚Ñƒ</translation>
<translation id="8364627913115013041">Đе Đ²ÑÑ‚Đ°Đ½Đ¾Đ²Đ»ĐµĐ½Đ¾.</translation>
+<translation id="8380941800586852976">ĐĐµĐ±ĐµĐ·Đ¿ĐµÑ‡Đ½Đ°</translation>
<translation id="8412145213513410671">ĐĐ²Đ°Ñ€Ñ–Đ¹Đ½Đµ Đ·Đ°Đ²ĐµÑ€ÑˆĐµĐ½Đ½Ñ Ñ€Đ¾Đ±Đ¾Ñ‚Đ¸ (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">ĐŸĐ¾Ñ‚Ñ€Ñ–Đ±Đ½Đ¾ Đ´Đ²Ñ–Ñ‡Ñ– Đ²Đ²ĐµÑÑ‚Đ¸ Đ¾Đ´Đ½Đ°ĐºĐ¾Đ²Ñƒ Đ¿Đ°Ñ€Đ¾Đ»ÑŒĐ½Ñƒ Ñ„Ñ€Đ°Đ·Ñƒ.</translation>
<translation id="8428213095426709021">ĐĐ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½Đ½Ñ</translation>
+<translation id="8433057134996913067">Ви Đ²Đ¸Đ¹Đ´ĐµÑ‚Đµ Đ· Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¾Đ³Đ¾ Đ·Đ°Đ¿Đ¸Ñу Đ½Đ° Đ±Ñ–Đ»ÑŒÑˆĐ¾ÑÑ‚Ñ– Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚Ñ–Đ².</translation>
<translation id="8437238597147034694">&amp;Đ’Ñ–Đ´Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ Đ¿ĐµÑ€ĐµĐ¼Ñ–Ñ‰ĐµĐ½Đ½Ñ</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ° ĐºĐ°Ñ€Ñ‚ĐºĐ°}one{# ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ° ĐºĐ°Ñ€Ñ‚ĐºĐ°}few{# ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Ñ– ĐºĐ°Ñ€Ñ‚ĐºĐ¸}many{# ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ¸Ñ… ĐºĐ°Ñ€Ñ‚Đ¾Đº}other{# ĐºÑ€ĐµĐ´Đ¸Ñ‚Đ½Đ¾Ñ— ĐºĐ°Ñ€Ñ‚ĐºĐ¸}}</translation>
+<translation id="8483780878231876732">Đ©Đ¾Đ± ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‚Đ¸ÑÑ ĐºĐ°Ñ€Ñ‚ĐºĐ°Đ¼Đ¸ у ÑĐ²Đ¾Ñ”Đ¼Ñƒ Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¾Đ¼Ñƒ Đ·Đ°Đ¿Đ¸ÑÑ– Google, ÑƒĐ²Ñ–Đ¹Đ´Ñ–Ñ‚ÑŒ у Chrome</translation>
<translation id="8488350697529856933">Đ—Đ°ÑÑ‚Đ¾ÑĐ¾Đ²ÑƒÑ”Ñ‚ÑŒÑÑ Đ´Đ¾:</translation>
<translation id="8498891568109133222">Đ¥Đ¾ÑÑ‚ <ph name="HOST_NAME" /> Đ´Đ¾Đ²Đ³Đ¾ Đ½Đµ Đ²Ñ–Đ´Đ¿Đ¾Đ²Ñ–Đ´Đ°Ñ”.</translation>
+<translation id="852346902619691059">Đе Đ²Đ´Đ°Đ»Đ¾ÑÑ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¸Ñ‚Đ¸, Ñ‰Đ¾ Ñ†Đµ ÑĐµÑ€Đ²ĐµÑ€ <ph name="DOMAIN" />. ĐĐ¿ĐµÑ€Đ°Ñ†Ñ–Đ¹Đ½Đ° ÑиÑÑ‚ĐµĐ¼Đ° Đ²Đ°ÑˆĐ¾Đ³Đ¾ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ Đ²Đ²Đ°Đ¶Đ°Ñ” Đ¹Đ¾Đ³Đ¾ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ Đ±ĐµĐ·Đ¿ĐµĐºĐ¸ Đ½ĐµĐ½Đ°Đ´Ñ–Đ¹Đ½Đ¸Đ¼. Đ†Đ¼Đ¾Đ²Ñ–Ñ€Đ½Ñ– Đ¿Ñ€Đ¸Ñ‡Đ¸Đ½Đ¸: ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ»Đ°ÑˆÑ‚Đ¾Đ²Đ°Đ½Đ¾ Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ°Đ±Đ¾ Ñ…Ñ‚Đ¾ÑÑŒ Đ½Đ°Đ¼Đ°Đ³Đ°Ñ”Ñ‚ÑŒÑÑ Đ¿ĐµÑ€ĐµÑ…Đ¾Đ¿Đ¸Ñ‚Đ¸ Đ²Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ. <ph name="BEGIN_LEARN_MORE_LINK" />Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Đ¦ĐµĐ¹ Ñ‚Đ¸Đ¿ ĐºĐ°Ñ€Ñ‚ĐºĐ¸ Đ½Đµ Đ¿Ñ–Đ´Ñ‚Ñ€Đ¸Đ¼ÑƒÑ”Ñ‚ÑŒÑÑ Đ² Google Payments. Đ’Đ¸Đ±ĐµÑ€Ñ–Ñ‚ÑŒ Ñ–Đ½ÑˆÑƒ ĐºĐ°Ñ€Ñ‚ĐºÑƒ.</translation>
<translation id="8550022383519221471">ĐŸĐ¾ÑĐ»ÑƒĐ³Đ° ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ°Ñ†Ñ–Ñ— Đ½ĐµĐ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Đ° Đ´Đ»Ñ Đ²Đ°ÑˆĐ¾Đ³Đ¾ Đ´Đ¾Đ¼ĐµĐ½Ñƒ.</translation>
<translation id="8553075262323480129">ĐŸĐ¾Đ¼Đ¸Đ»ĐºĐ° Đ¿ĐµÑ€ĐµĐºĐ»Đ°Đ´Ñƒ. ĐĐµĐ¼Đ¾Đ¶Đ»Đ¸Đ²Đ¾ Đ²Đ¸Đ·Đ½Đ°Ñ‡Đ¸Ñ‚Đ¸ Đ¼Đ¾Đ²Ñƒ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸.</translation>
@@ -633,15 +675,12 @@
<translation id="8647750283161643317">Đ¡ĐºĐ¸Đ½ÑƒÑ‚Đ¸ Đ²Ñе Đ´Đ¾ Đ½Đ°Đ»Đ°ÑˆÑ‚ÑƒĐ²Đ°Đ½ÑŒ Đ·Đ° ÑƒĐ¼Đ¾Đ²Ñ‡Đ°Đ½Đ½ÑĐ¼</translation>
<translation id="8680787084697685621">Đ”Đ°Đ½Ñ– Đ´Đ»Ñ Đ²Ñ…Đ¾Đ´Ñƒ Đ² Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¸Đ¹ Đ·Đ°Đ¿Đ¸Ñ Đ·Đ°ÑÑ‚Đ°Ñ€Ñ–Đ»Đ¸.</translation>
<translation id="8703575177326907206">Đ’Đ°ÑˆĐµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ· <ph name="DOMAIN" /> Đ½Đµ Đ·Đ°ÑˆĐ¸Ñ„Ñ€Đ¾Đ²Đ°Đ½Đ¾.</translation>
-<translation id="8713130696108419660">ĐĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹ Đ¿Đ¾Ñ‡Đ°Ñ‚ĐºĐ¾Đ²Đ¸Đ¹ Đ¿Ñ–Đ´Đ¿Đ¸Ñ</translation>
<translation id="8725066075913043281">ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đ¸ ÑĐ¿Ñ€Đ¾Đ±Ñƒ</translation>
<translation id="8728672262656704056">Ви Đ¿ĐµÑ€ĐµĐ¹ÑˆĐ»Đ¸ Đ² Ñ€ĐµĐ¶Đ¸Đ¼ Đ°Đ½Đ¾Đ½Ñ–Đ¼Đ½Đ¾Đ³Đ¾ Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Ñƒ</translation>
<translation id="8730621377337864115">Đ“Đ¾Ñ‚Đ¾Đ²Đ¾</translation>
<translation id="8738058698779197622">Đ©Đ¾Đ± уÑÑ‚Đ°Đ½Đ¾Đ²Đ¸Ñ‚Đ¸ Đ±ĐµĐ·Đ¿ĐµÑ‡Đ½Đµ Đ·â€™Ñ”Đ´Đ½Đ°Đ½Đ½Ñ, Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±Đ½Đ¾ Đ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¾ Đ²ĐºĐ°Đ·Đ°Ñ‚Đ¸ Ñ‡Đ°Ñ, Đ¾ÑĐºÑ–Đ»ÑŒĐºĐ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ¸, ÑĐºÑ– Đ²ĐµĐ±-ÑĐ°Đ¹Ñ‚Đ¸ Đ²Đ¸ĐºĐ¾Ñ€Đ¸ÑÑ‚Đ¾Đ²ÑƒÑÑ‚ÑŒ Đ´Đ»Ñ ÑĐ°Đ¼Đ¾Ñ–Đ´ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ†Ñ–Ñ— Đ´Ñ–Đ¹ÑĐ½Ñ– Đ»Đ¸ÑˆĐµ Đ¿Ñ€Đ¾Ñ‚ÑĐ³Đ¾Đ¼ Đ¿ĐµĐ²Đ½Đ¾Đ³Đ¾ Đ¿ĐµÑ€Ñ–Đ¾Đ´Ñƒ Ñ‡Đ°Ñу. Đ§Đ°Ñ Đ½Đ° Đ²Đ°ÑˆĐ¾Đ¼Ñƒ Đ¿Ñ€Đ¸ÑÑ‚Ñ€Đ¾Ñ— Đ½ĐµĐ¿Ñ€Đ°Đ²Đ¸Đ»ÑŒĐ½Đ¸Đ¹, Ñ‚Đ¾Đ¼Ñƒ Chromium Đ½Đµ Đ¼Đ¾Đ¶Đµ Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€Đ¸Ñ‚Đ¸ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ¸.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;ĐĐ´Ñ€ĐµÑу DNS&lt;/abbr&gt; Ñ…Đ¾Ñту <ph name="HOST_NAME" /> Đ½Đµ Đ·Đ½Đ°Đ¹Đ´ĐµĐ½Đ¾. Đ”Ñ–Đ°Đ³Đ½Đ¾ÑÑ‚Đ¸ĐºĐ° Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Đ¸.</translation>
-<translation id="8741995161408053644">Đ£ Đ²Đ°ÑˆĐ¾Đ¼Ñƒ Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¾Đ¼Ñƒ Đ·Đ°Đ¿Đ¸ÑÑ– Google Đ½Đ° ÑÑ‚Đ¾Ñ€Ñ–Đ½Ñ†Ñ– <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ±ÑƒÑ‚Đ¸ Ñ–Đ½ÑˆÑ– Ñ„Đ¾Ñ€Đ¼Đ¸ Ñ–ÑÑ‚Đ¾Ñ€Ñ–Ñ— Đ²ĐµĐ±-Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Ñƒ.</translation>
<translation id="8790007591277257123">&amp;ĐŸĐ¾Đ²Ñ‚Đ¾Ñ€Đ¸Ñ‚Đ¸ Đ²Đ¸Đ´Đ°Đ»ĐµĐ½Đ½Ñ</translation>
-<translation id="8790687370365610530">Đ©Đ¾Đ± Đ¾Ñ‚Ñ€Đ¸Đ¼ÑƒĐ²Đ°Ñ‚Đ¸ Đ¿Ñ€Đ¾Đ¿Đ¾Đ·Đ¸Ñ†Ñ–Ñ— Đ¿ĐµÑ€ÑĐ¾Đ½Đ°Đ»Ñ–Đ·Đ¾Đ²Đ°Đ½Đ¾Đ³Đ¾ Đ²Đ¼Ñ–Ñту Đ²Ñ–Đ´ Google, ÑƒĐ²Ñ–Đ¼ĐºĐ½Ñ–Ñ‚ÑŒ ÑĐ¸Đ½Ñ…Ñ€Đ¾Đ½Ñ–Đ·Đ°Ñ†Ñ–Ñ Ñ–ÑÑ‚Đ¾Ñ€Ñ–Ñ—.</translation>
<translation id="8798099450830957504">Đ—Đ° ÑƒĐ¼Đ¾Đ²Ñ‡Đ°Đ½Đ½ÑĐ¼</translation>
<translation id="8804164990146287819">ĐŸĐ¾Đ»Ñ–Ñ‚Đ¸ĐºĐ° ĐºĐ¾Đ½Ñ„Ñ–Đ´ĐµĐ½Ñ†Ñ–Đ¹Đ½Đ¾ÑÑ‚Ñ–</translation>
<translation id="8820817407110198400">Đ—Đ°ĐºĐ»Đ°Đ´ĐºĐ¸</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">Đ¢ĐµÑ€Đ¼Ñ–Đ½ Đ´Ñ–Ñ— ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ° ÑĐµÑ€Đ²ĐµÑ€Đ° Đ·Đ°Đ²ĐµÑ€ÑˆĐ¸Đ²ÑÑ.</translation>
<translation id="8987927404178983737">ĐœÑ–ÑÑць</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">Đ¡ĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚ без Ñ–Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ— Đ¿Ñ€Đ¾ Đ¿ĐµÑ€ĐµĐ²Ñ–Ñ€ĐºÑƒ. Це Đ¾Đ±Đ¾Đ²â€™ÑĐ·ĐºĐ¾Đ²Ñ– Đ´Đ°Đ½Ñ– Đ´Đ»Ñ Đ´ĐµÑĐºĐ¸Ñ… ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Ñ–Đ². Đ’Đ¾Đ½Đ¸ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¶ÑƒÑÑ‚ÑŒ Đ½Đ°Đ´Ñ–Đ¹Đ½Ñ–ÑÑ‚ÑŒ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ° Đ¹ Đ·Đ°Ñ…Đ¸Ñ‰Đ°ÑÑ‚ÑŒ Đ²Ñ–Đ´ Đ°Ñ‚Đ°Đº Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºÑ–Đ².</translation>
<translation id="9001074447101275817">Đ”Đ»Ñ Đ¿Ñ€Đ¾ĐºÑÑ– <ph name="DOMAIN" /> Đ¿Đ¾Ñ‚Ñ€Ñ–Đ±Đ½Đ¾ Đ²Đ²ĐµÑÑ‚Đ¸ Ñ–Đ¼â€™Ñ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Đ° Ñ‚Đ° Đ¿Đ°Ñ€Đ¾Đ»ÑŒ.</translation>
<translation id="901974403500617787">ĐŸĐ¾Đ·Đ½Đ°Ñ‡ĐºĐ¸, ÑĐºÑ– Đ·Đ°ÑÑ‚Đ¾ÑĐ¾Đ²ÑƒÑÑ‚ÑŒÑÑ Đ´Đ¾ Đ²Ñієї ÑиÑÑ‚ĐµĐ¼Đ¸, Đ¼Đ¾Đ¶Đµ Đ²ÑÑ‚Đ°Đ½Đ¾Đ²Đ»ÑĐ²Đ°Ñ‚Đ¸ Đ»Đ¸ÑˆĐµ Đ²Đ»Đ°ÑĐ½Đ¸Đº: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Đ¦Ñ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºÑƒ Đ¿ĐµÑ€ĐµĐºĐ»Đ°Đ´ĐµĐ½Đ¾ Ñ‚Đ°ĐºĐ¾Ñ Đ¼Đ¾Đ²Đ¾Ñ: <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">ĐĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ¹Ñ‚ĐµÑÑ ÑĐ»ÑƒĐ¶Đ±Đ¾Ñ Đ¿ĐµÑ€ĐµĐ´Đ±Đ°Ñ‡ĐµĐ½Đ½Ñ, Ñ‰Đ¾Đ± ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸ Đ·Đ°Đ²Đ°Đ½Ñ‚Đ°Đ¶ÑƒĐ²Đ°Đ»Đ¸ÑÑ ÑˆĐ²Đ¸Đ´ÑˆĐµ</translation>
<translation id="9039213469156557790">ĐĐºÑ€Ñ–Đ¼ Ñ†ÑŒĐ¾Đ³Đ¾, ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Đ¼Ñ–ÑÑ‚Đ¸Ñ‚ÑŒ Đ½ĐµĐ·Đ°Ñ…Đ¸Ñ‰ĐµĐ½Ñ– Ñ€ĐµÑурÑи. Đ†Đ½ÑˆÑ– Đ¾ÑĐ¾Đ±Đ¸ Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´Đ°Ñ‚Đ¸ Ñ—Ñ… Đ¿Ñ–Đ´ Ñ‡Đ°Ñ Đ¿ĐµÑ€ĐµĐ´Đ°Đ²Đ°Đ½Đ½Ñ Đ´Đ°Đ½Đ¸Ñ…, Đ° Đ·Đ»Đ¾Đ²Đ¼Đ¸ÑĐ½Đ¸ĐºĐ¸ Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ·Đ¼Ñ–Đ½ÑĐ²Đ°Ñ‚Đ¸ Ñ€Đ¾Đ±Đ¾Ñ‚Ñƒ ÑÑ‚Đ¾Ñ€Ñ–Đ½ĐºĐ¸.</translation>
-<translation id="9049981332609050619">Ви Đ¿Ñ€Đ¾Đ±ÑƒĐ²Đ°Đ»Đ¸ Đ·Đ²â€™ÑĐ·Đ°Ñ‚Đ¸ÑÑ Đ· Đ´Đ¾Đ¼ĐµĐ½Đ¾Đ¼ <ph name="DOMAIN" />, але ÑĐµÑ€Đ²ĐµÑ€ Đ½Đ°Đ´Đ°Đ² Đ½ĐµĐ´Ñ–Đ¹ÑĐ½Đ¸Đ¹ ÑĐµÑ€Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚.</translation>
<translation id="9050666287014529139">ĐŸĐ°Ñ€Đ¾Đ»ÑŒĐ½Đ° Ñ„Ñ€Đ°Đ·Đ°</translation>
<translation id="9065203028668620118">Đ ĐµĐ´Đ°Đ³ÑƒĐ²Đ°Ñ‚Đ¸</translation>
<translation id="9092364396508701805">Đ¡Ñ‚Đ¾Ñ€Ñ–Đ½ĐºĐ° Ñ…Đ¾Ñту <ph name="HOST_NAME" /> Đ½Đµ Đ¿Ñ€Đ°Ñ†ÑÑ”</translation>
diff --git a/chromium/components/strings/components_strings_vi.xtb b/chromium/components/strings/components_strings_vi.xtb
index 56ca9bfb67d..d9224fc1f0f 100644
--- a/chromium/components/strings/components_strings_vi.xtb
+++ b/chromium/components/strings/components_strings_vi.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="vi">
+<translation id="1008557486741366299">KhĂ´ng phải BĂ¢y giá»</translation>
<translation id="1015730422737071372">Cung cấp chi tiết bổ sung</translation>
<translation id="1032854598605920125">Xoay theo chiá»u kim đồng hồ</translation>
<translation id="1038842779957582377">tĂªn khĂ´ng biết</translation>
+<translation id="1053591932240354961">Bạn khĂ´ng thể truy cập <ph name="SITE" /> ngay bĂ¢y giá» do trang web gá»­i thĂ´ng tin đăng nhập Ä‘Ă£ mĂ£ hĂ³a mĂ  Google Chrome khĂ´ng thể xá»­ lĂ½. Lá»—i mạng vĂ  cĂ¡c cuá»™c tấn cĂ´ng mạng thÆ°á»ng chỉ lĂ  tạm thá»i, do Ä‘Ă³, trang nĂ y cĂ³ thể sẽ hoạt Ä‘á»™ng lại sau. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1055184225775184556">&amp;HoĂ n tĂ¡c thĂªm</translation>
<translation id="10614374240317010">KhĂ´ng bao giỠđược lÆ°u</translation>
-<translation id="1064422015032085147">MĂ¡y chủ lÆ°u trữ trang web cĂ³ thể bị quĂ¡ tải hoặc Ä‘ang được bảo trì.
- Äể trĂ¡nh tạo quĂ¡ nhiá»u lÆ°u lượng vĂ  khiến tình hình tồi tệ hÆ¡n,
- tạm thá»i khĂ´ng cho phĂ©p gá»­i yĂªu cầu tá»›i URL nĂ y</translation>
<translation id="106701514854093668">Dấu trang mĂ¡y tĂ­nh</translation>
<translation id="1080116354587839789">Vừa vá»›i chiá»u rá»™ng</translation>
+<translation id="1103124106085518534">ÄĂ£ xong</translation>
<translation id="1103523840287552314">Luôn dịch <ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">Nếu được chá»n, Chrome sẽ lÆ°u trữ bản sao thẻ của bạn trĂªn thiết bị nĂ y để Ä‘iá»n biểu mẫu nhanh hÆ¡n.</translation>
+<translation id="1111153019813902504">Dấu trang gần Ä‘Ă¢y</translation>
<translation id="1113869188872983271">&amp;HoĂ n tĂ¡c sắp xếp lại</translation>
+<translation id="1126551341858583091">KĂ­ch thÆ°á»›c trĂªn bá»™ nhá»› cục bá»™ lĂ  <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Bá»™ nhá»› cache chĂ­nh sĂ¡ch OK</translation>
<translation id="113188000913989374"><ph name="SITE" /> cho biết:</translation>
<translation id="1132774398110320017">CĂ i đặt tá»± Ä‘á»™ng Ä‘iá»n trĂªn Chrome...</translation>
-<translation id="1150979032973867961">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y khĂ´ng được hệ Ä‘iá»u hĂ nh mĂ¡y tĂ­nh của bạn tin cậy. Äiá»u nĂ y cĂ³ thể do định cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.</translation>
<translation id="1152921474424827756">Truy cập <ph name="BEGIN_LINK" />bản sao được lưu trong bộ nhớ cache<ph name="END_LINK" /> của <ph name="URL" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> Ä‘Ă£ bất ngá» Ä‘Ă³ng kết nối.</translation>
<translation id="1161325031994447685">Kết nối lại với Wi-Fi</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">XĂ³a</translation>
<translation id="1201402288615127009">Tiếp theo</translation>
<translation id="1201895884277373915">ThĂªm từ trang web nĂ y</translation>
-<translation id="121201262018556460">Bạn Ä‘Ă£ cố truy cập vĂ o <ph name="DOMAIN" /> nhÆ°ng mĂ¡y chủ xuất trình chứng chỉ chứa khĂ³a yếu. Kẻ tấn cĂ´ng cĂ³ thể Ä‘Ă£ phĂ¡ khĂ³a cĂ¡ nhĂ¢n vĂ  mĂ¡y chủ Ä‘Ă³ cĂ³ thể khĂ´ng phải lĂ  mĂ¡y chủ bạn mong đợi (bạn cĂ³ thể Ä‘ang giao tiếp vá»›i má»™t kẻ tấn cĂ´ng).</translation>
+<translation id="1206967143813997005">Chữ kĂ½ ban đầu khĂ´ng hợp lệ</translation>
+<translation id="1209206284964581585">Ẩn ngay bĂ¢y giá»</translation>
<translation id="1219129156119358924">Bảo mật hệ thống</translation>
<translation id="1227224963052638717">ChĂ­nh sĂ¡ch khĂ´ng xĂ¡c định.</translation>
<translation id="1227633850867390598">Ẩn giĂ¡ trị</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">CĂ³</translation>
<translation id="1430915738399379752">In</translation>
<translation id="1442912890475371290">ÄĂ£ chặn ná»— lá»±c <ph name="BEGIN_LINK" /> truy cập trang trĂªn <ph name="DOMAIN" /><ph name="END_LINK" />.</translation>
+<translation id="1491663344921578213">Bạn khĂ´ng thể truy cập <ph name="SITE" /> ngay bĂ¢y giá» do trang web sá»­ dụng tĂ­nh năng ghim chứng chỉ. Lá»—i mạng vĂ  cĂ¡c cuá»™c tấn cĂ´ng mạng thÆ°á»ng chỉ lĂ  tạm thá»i, do Ä‘Ă³, trang nĂ y cĂ³ thể sẽ hoạt Ä‘á»™ng lại sau. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1506687042165942984">Hiển thị bản sao Ä‘Ă£ lÆ°u (nghÄ©a lĂ  Ä‘Ă£ lá»—i thá»i) của trang nĂ y.</translation>
<translation id="1519264250979466059">NgĂ y tạo</translation>
<translation id="1549470594296187301">Bạn phải bật JavaScript để sá»­ dụng tĂ­nh năng nĂ y.</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">Cấu hình mạng khĂ´ng hợp lệ vĂ  khĂ´ng thể nhập được.</translation>
<translation id="1644574205037202324">Lịch sử</translation>
<translation id="1645368109819982629">Giao thức khĂ´ng được há»— trợ</translation>
-<translation id="1655462015569774233">{1,plural, =1{MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y Ä‘Ă£ hết hạn hĂ´m qua. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. Äồng hồ mĂ¡y tĂ­nh của bạn hiện được đặt lĂ  <ph name="CURRENT_DATE" />. NgĂ y nĂ y cĂ³ Ä‘Ăºng khĂ´ng? Nếu khĂ´ng Ä‘Ăºng, bạn phải sá»­a lại đồng hồ của hệ thống rồi lĂ m má»›i trang nĂ y.}other{MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y Ä‘Ă£ hết hạn cĂ¡ch Ä‘Ă¢y # ngĂ y. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. Äồng hồ mĂ¡y tĂ­nh của bạn hiện được đặt lĂ  <ph name="CURRENT_DATE" />. NgĂ y nĂ y cĂ³ Ä‘Ăºng khĂ´ng? Nếu khĂ´ng Ä‘Ăºng, bạn phải sá»­a lại đồng hồ của hệ thống rồi lĂ m má»›i trang nĂ y.}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> thÆ°á»ng sá»­ dụng mĂ£ hĂ³a để bảo vệ thĂ´ng tin của bạn. Khi Google Chrome tìm cĂ¡ch kết nối vá»›i <ph name="SITE" /> tại thá»i Ä‘iểm nĂ y, trang web Ä‘Ă£ gá»­i lại thĂ´ng tin đăng nhập khĂ´ng chĂ­nh xĂ¡c vĂ  bất thÆ°á»ng. Äiá»u nĂ y cĂ³ thể xảy ra khi kẻ tấn cĂ´ng Ä‘ang cố gắng giả mạo lĂ  <ph name="SITE" /> hoặc mĂ n hình đăng nhập Wi-Fi Ä‘Ă£ lĂ m giĂ¡n Ä‘oạn kết nối. ThĂ´ng tin của bạn vẫn an toĂ n do Google Chrome Ä‘Ă£ ngừng kết nối trÆ°á»›c khi bất kỳ dữ liệu nĂ o được trao đổi.</translation>
<translation id="168841957122794586">Chứng chỉ mĂ¡y chủ chứa khĂ³a mật mĂ£ yếu.</translation>
<translation id="1701955595840307032">Tải nội dung được đỠxuất</translation>
-<translation id="1706954506755087368">{1,plural, =1{MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y được Ä‘á» từ ngĂ y mai. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.}other{MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y được Ä‘á» # ngĂ y trong tÆ°Æ¡ng lai. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.}}</translation>
<translation id="1710259589646384581">OS</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">Thá»­ liĂªn hệ vá»›i quản trị viĂªn hệ thống.</translation>
<translation id="17513872634828108">Tab đang mở</translation>
<translation id="1753706481035618306">Số trang</translation>
-<translation id="1761412452051366565">Äể nhận ná»™i dung được cĂ¡ nhĂ¢n hĂ³a do Google Ä‘á» xuất, hĂ£y bật đồng bá»™ hĂ³a.</translation>
-<translation id="1763864636252898013">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y khĂ´ng được hệ Ä‘iá»u hĂ nh thiết bị của bạn tin cậy. Äiá»u nĂ y cĂ³ thể do định cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Thá»­ chạy Chẩn Ä‘oĂ¡n mạng của Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Vui lĂ²ng cập nhật cụm mật khẩu đồng bá»™ hĂ³a của bạn.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">Dấu trang bạn truy cập gần Ä‘Ă¢y sẽ xuất hiện ở Ä‘Ă¢y.</translation>
<translation id="1821930232296380041">YĂªu cầu hoặc tham số yĂªu cầu khĂ´ng hợp lệ</translation>
<translation id="1838667051080421715">Bạn đang xem nguồn của trang web.</translation>
<translation id="1871208020102129563">Proxy được đặt để sá»­ dụng mĂ¡y chủ proxy cố định chứ khĂ´ng phải URL tập lệnh .pac.</translation>
<translation id="1883255238294161206">Thu gá»n danh sĂ¡ch</translation>
<translation id="1898423065542865115">Lá»c</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> khĂ´ng chấp nhận chứng chỉ đăng nhập của bạn hoặc chứng chỉ đăng nhập của bạn cĂ³ thể Ä‘Ă£ hết hạn.</translation>
<translation id="194030505837763158">Truy cập <ph name="LINK" /></translation>
<translation id="1962204205936693436">Dấu trang của <ph name="DOMAIN" /></translation>
<translation id="1973335181906896915">Lá»—i nối tiếp hĂ³a</translation>
<translation id="1974060860693918893">NĂ¢ng cao</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{vĂ  1 ứng dụng khĂ¡c}other{vĂ  # ứng dụng khĂ¡c}}</translation>
<translation id="2025186561304664664">Proxy được đặt thĂ nh định cấu hình tá»± Ä‘á»™ng.</translation>
<translation id="2030481566774242610">Ă của bạn lĂ  <ph name="LINK" />?</translation>
<translation id="2031925387125903299">Bạn thấy thĂ´ng bĂ¡o nĂ y vì cha mẹ bạn cần phải phĂª duyệt cĂ¡c trang web má»›i vĂ o lần truy cập đầu tiĂªn của bạn.</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />Kiểm tra proxy vĂ  tÆ°á»ng lá»­a<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">MĂ£ zip</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 đỠxuất}other{# đỠxuất}}</translation>
<translation id="2065985942032347596">YĂªu cầu XĂ¡c thá»±c</translation>
<translation id="2079545284768500474">HoĂ n tĂ¡c</translation>
<translation id="20817612488360358">CĂ i đặt proxy hệ thống được đặt để sá»­ dụng nhÆ°ng cấu hình proxy rõ rĂ ng cÅ©ng được chỉ định.</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">Chỉnh sửa dấu trang</translation>
<translation id="2166049586286450108">Quyá»n truy cập quản trị đầy đủ</translation>
<translation id="2166378884831602661">Trang web nĂ y khĂ´ng thể cung cấp kết nối an toĂ n</translation>
-<translation id="2171101176734966184">Bạn Ä‘Ă£ cố truy cập vĂ o <ph name="DOMAIN" /> nhÆ°ng mĂ¡y chủ xuất trình má»™t chứng chỉ được kĂ½ bằng má»™t thuật toĂ¡n chữ kĂ½ yếu. Äiá»u nĂ y cĂ³ nghÄ©a lĂ  giấy ủy nhiệm bảo mật mĂ  mĂ¡y chủ xuất trình cĂ³ thể Ä‘Ă£ bị giả mạo vĂ  mĂ¡y chủ Ä‘Ă³ cĂ³ thể khĂ´ng phải lĂ  mĂ¡y chủ mĂ  bạn mong đợi (bạn cĂ³ thể Ä‘ang giao tiếp vá»›i má»™t kẻ tấn cĂ´ng).</translation>
<translation id="2181821976797666341">ChĂ­nh sĂ¡ch</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 địa chỉ}other{# địa chỉ}}</translation>
<translation id="2212735316055980242">KhĂ´ng tìm thấy chĂ­nh sĂ¡ch</translation>
<translation id="2213606439339815911">Äang tìm nạp cĂ¡c mục nhập...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> khĂ´ng cĂ³ sẵn</translation>
<translation id="2230458221926704099">Sá»­a kết nối bằng <ph name="BEGIN_LINK" />ứng dụng chẩn Ä‘oĂ¡n<ph name="END_LINK" /></translation>
+<translation id="2239100178324503013">Gá»­i bĂ¢y giá»</translation>
<translation id="225207911366869382">GiĂ¡ trị nĂ y khĂ´ng được dĂ¹ng cho chĂ­nh sĂ¡ch nĂ y nữa.</translation>
<translation id="2262243747453050782">Lá»—i HTTP</translation>
<translation id="2282872951544483773">Thá»­ nghiệm khĂ´ng khả dụng</translation>
<translation id="2292556288342944218">Quyá»n truy cập Internet của bạn bị chặn</translation>
<translation id="229702904922032456">Chứng chỉ sÆ¡ cấp hoặc trung cấp Ä‘Ă£ hết hạn.</translation>
<translation id="230155334948463882">Thẻ mới?</translation>
+<translation id="2305919008529760154">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y cĂ³ thể Ä‘Ă£ được cấp má»™t cĂ¡ch gian lận. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> yĂªu cầu tĂªn ngÆ°á»i dĂ¹ng vĂ  mật khẩu.</translation>
+<translation id="2318774815570432836">Bạn khĂ´ng thể truy cập <ph name="SITE" /> ngay bĂ¢y giá» vì trang web sá»­ dụng HSTS. Lá»—i mạng vĂ  cĂ¡c cuá»™c tấn cĂ´ng mạng thÆ°á»ng chỉ lĂ  tạm thá»i, do Ä‘Ă³, trang nĂ y cĂ³ thể sẽ hoạt Ä‘á»™ng lại sau. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2328300916057834155">ÄĂ£ bá» qua dấu trang khĂ´ng hợp lệ tại chỉ mục <ph name="ENTRY_INDEX" /></translation>
<translation id="2354001756790975382">Dấu trang khĂ¡c</translation>
<translation id="2359808026110333948">Tiếp tục</translation>
<translation id="2365563543831475020">BĂ¡o cĂ¡o sá»± cố được ghi lại vĂ o <ph name="CRASH_TIME" /> chÆ°a được tải lĂªn</translation>
<translation id="2367567093518048410">Mức độ</translation>
+<translation id="2371153335857947666">{1,plural, =1{MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y Ä‘Ă£ hết hạn hĂ´m qua. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. Äồng hồ của mĂ¡y tĂ­nh hiện được đặt lĂ  <ph name="CURRENT_DATE" />. NgĂ y nĂ y cĂ³ Ä‘Ăºng khĂ´ng? Nếu khĂ´ng Ä‘Ăºng, bạn phải sá»­a lại đồng hồ của hệ thống rồi lĂ m má»›i trang nĂ y. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.}other{MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y Ä‘Ă£ hết hạn cĂ¡ch Ä‘Ă¢y # ngĂ y. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. Äồng hồ của mĂ¡y tĂ­nh hiện được đặt lĂ  <ph name="CURRENT_DATE" />. NgĂ y nĂ y cĂ³ Ä‘Ăºng khĂ´ng? Nếu khĂ´ng Ä‘Ăºng, bạn phải sá»­a lại đồng hồ của hệ thống rồi lĂ m má»›i trang nĂ y. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="237718015863234333">KhĂ´ng cĂ³ giao diện ngÆ°á»i dĂ¹ng thay thế nĂ o</translation>
<translation id="2384307209577226199">Äặt mặc định trong mĂ´i trÆ°á»ng doanh nghiệp</translation>
-<translation id="238526402387145295">Bạn khĂ´ng thể truy cập <ph name="SITE" /> ngay bĂ¢y giá» do trang web <ph name="BEGIN_LINK" />sá»­ dụng HSTS<ph name="END_LINK" />. Lá»—i mạng vĂ  cĂ¡c cuá»™c tấn cĂ´ng mà£ng thÆ°á»ng chì‰ là€ tạm thá»i do Ä‘Ă³ trang nĂ y cĂ³ thể sẽ hoạt Ä‘á»™ng lại sau.</translation>
<translation id="2386255080630008482">Chứng chỉ của mĂ¡y chủ Ä‘Ă£ bị thu hồi.</translation>
<translation id="2392959068659972793">Hiển thị chĂ­nh sĂ¡ch khĂ´ng cĂ³ giĂ¡ trị được đặt</translation>
<translation id="2396249848217231973">&amp;HoĂ n tĂ¡c xĂ³a</translation>
-<translation id="2413528052993050574">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y cĂ³ thể Ä‘Ă£ bị thu hồi. Äiá»u nĂ y cĂ³ thể do định cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.</translation>
<translation id="2455981314101692989">Trang web nĂ y Ä‘Ă£ vĂ´ hiệu hĂ³a tĂ­nh năng tá»± Ä‘á»™ng Ä‘iá»n cho biểu mẫu nĂ y.</translation>
+<translation id="2463739503403862330">Äiá»n</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Chạy Chẩn Ä‘oĂ¡n mạng<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">URL tìm kiếm hợp lệ.</translation>
<translation id="2491120439723279231">Chứng chỉ của mĂ¡y chủ cĂ³ lá»—i.</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">Gá»­i</translation>
<translation id="2674170444375937751">Bạn cĂ³ chắc chắn muốn xĂ³a những trang nĂ y khá»i lịch sá»­ duyệt web của mình khĂ´ng?</translation>
<translation id="2677748264148917807">Rá»i khá»i</translation>
+<translation id="269990154133806163">MĂ¡y chủ Ä‘Ă£ xuất trình chứng chỉ khĂ´ng được tiết lá»™ cĂ´ng khai theo chĂ­nh sĂ¡ch TĂ­nh minh bạch của chứng chỉ. ÄĂ¢y lĂ  yĂªu cầu đối vá»›i má»™t số chứng chỉ, để đảm bảo chĂºng Ä‘Ă¡ng tin cậy vĂ  giĂºp chống lại những kẻ tấn cĂ´ng. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2704283930420550640">GiĂ¡ trị khĂ´ng khá»›p vá»›i định dạng.</translation>
<translation id="2704951214193499422">Chromium khĂ´ng thể xĂ¡c nhận thẻ của bạn tại thá»i Ä‘iểm nĂ y. Vui lĂ²ng thá»­ lại sau.</translation>
<translation id="2705137772291741111">KhĂ´ng thể Ä‘á»c được bản sao Ä‘Ă£ lÆ°u (Ä‘Ă£ lÆ°u vĂ o bá»™ nhá»› cache) của trang web nĂ y.</translation>
<translation id="2709516037105925701">TÆ°̀£ Ä‘Ă´̀£ng Ä‘iá»n</translation>
+<translation id="2712118517637785082">Bạn Ä‘Ă£ cố gắng truy cập <ph name="DOMAIN" /> nhÆ°ng chứng chỉ mĂ  mĂ¡y chủ xuất trình Ä‘Ă£ bị nhĂ  phĂ¡t hĂ nh thu hồi. Äiá»u nĂ y cĂ³ nghÄ©a lĂ  thĂ´ng tin đăng nhập bảo mật mĂ  mĂ¡y chủ xuất trình hoĂ n toĂ n khĂ´ng Ä‘Ă¡ng tin cậy. Bạn cĂ³ thể Ä‘ang kết nối vá»›i kẻ tấn cĂ´ng. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2712173769900027643">Xin phép</translation>
<translation id="2721148159707890343">YĂªu cầu Ä‘Ă£ thĂ nh cĂ´ng</translation>
<translation id="2728127805433021124">Chứng chỉ của mĂ¡y chủ Ä‘Ă£ được kĂ½ bằng thuật toĂ¡n chữ kĂ½ yếu.</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">Thanh địa chỉ vĂ  tìm kiếm</translation>
<translation id="2826760142808435982">Kết nối được mĂ£ hĂ³a vĂ  xĂ¡c thá»±c bằng <ph name="CIPHER" /> đồng thá»i sá»­ dụng <ph name="KX" /> lĂ m cÆ¡ chế trao đổi chĂ­nh.</translation>
<translation id="2835170189407361413">XĂ³a biểu mẫu</translation>
-<translation id="2837049386027881519">Phải thá»­ lại kết nối bằng phiĂªn bản giao thức TLS hoặc SSL cÅ© hÆ¡n. Äiá»u nĂ y thÆ°á»ng cĂ³ nghÄ©a lĂ  mĂ¡y chủ Ä‘ang sá»­ dụng phần má»m rất cÅ© vĂ  cĂ³ thể gặp cĂ¡c vấn Ä‘á» bảo mật khĂ¡c.</translation>
<translation id="284702764277384724">CĂ³ vẻ nhÆ° chứng chỉ mĂ¡y chủ tại <ph name="HOST_NAME" /> lĂ  giả mạo.</translation>
<translation id="2889159643044928134">KhĂ´ng tải lại</translation>
-<translation id="2896499918916051536">Plugin nĂ y khĂ´ng được há»— trợ.</translation>
+<translation id="2900469785430194048">Google Chrome Ä‘Ă£ hết bá»™ nhá»› khi cố gắng hiển thị trang web nĂ y.</translation>
<translation id="2909946352844186028">ÄĂ£ phĂ¡t hiện thấy thay đổi mạng.</translation>
-<translation id="2915500479781995473">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y Ä‘Ă£ hết hạn. Äiá»u nĂ y cĂ³ thể do định cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. Äồng hồ trĂªn mĂ¡y tĂ­nh của bạn hiện được đặt lĂ  <ph name="CURRENT_TIME" />. Giá» nĂ y cĂ³ Ä‘Ăºng khĂ´ng? Nếu khĂ´ng Ä‘Ăºng, bạn phải sá»­a lại giá» hệ thống rồi lĂ m má»›i trang nĂ y.</translation>
<translation id="2922350208395188000">KhĂ´ng thể kiểm tra chứng chỉ của mĂ¡y chủ.</translation>
-<translation id="2941952326391522266">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y lĂ  từ <ph name="DOMAIN2" />. Äiá»u nĂ y cĂ³ thể do định cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.</translation>
<translation id="2948083400971632585">Bạn cĂ³ thể tắt má»i proxy được định cấu hình cho kết nối từ trang cĂ i đặt.</translation>
<translation id="2955913368246107853">ÄĂ³ng thanh tìm</translation>
<translation id="2958431318199492670">Cấu hình mạng khĂ´ng tuĂ¢n thủ tiĂªu chuẩn ONC. CĂ¡c bá»™ phận của cấu hình cĂ³ thể khĂ´ng được nhập.</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">Loại chĂ­nh sĂ¡ch sai</translation>
<translation id="3032412215588512954">Bạn cĂ³ muốn tải lại trang web nĂ y khĂ´ng?</translation>
<translation id="3037605927509011580">Ă”i, há»ng! </translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{Ă­t nhất 1 mục trĂªn cĂ¡c thiết bị Ä‘Ă£ đồng bá»™ hĂ³a}=1{1 mục (vĂ  nhiá»u mục khĂ¡c trĂªn cĂ¡c thiết bị Ä‘Ă£ đồng bá»™ hĂ³a)}other{# mục (vĂ  nhiá»u mục khĂ¡c trĂªn cĂ¡c thiết bị Ä‘Ă£ đồng bá»™ hĂ³a)}}</translation>
<translation id="3041612393474885105">Thông tin Chứng chỉ</translation>
<translation id="3063697135517575841">Chrome khĂ´ng thể xĂ¡c nhận thẻ của bạn tại thá»i Ä‘iểm nĂ y. Vui lĂ²ng thá»­ lại sau.</translation>
<translation id="3093245981617870298">Bạn đang ngoại tuyến.</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">Mới nhất</translation>
<translation id="3207960819495026254">ÄĂ£ được Ä‘Ă¡nh dấu trang</translation>
-<translation id="3225919329040284222">MĂ¡y chủ Ä‘Æ°a ra chứng chỉ khĂ´ng khá»›p vá»›i kỳ vá»ng được tĂ­ch hợp sẵn. CĂ¡c kỳ vá»ng nĂ y cĂ³ trong má»™t số trang web nhất định, cĂ³ tĂ­nh bảo mật cao vá»›i mục Ä‘Ă­ch bảo vệ bạn.</translation>
<translation id="3226128629678568754">Nhấn nĂºt tải lại để gá»­i lại cĂ¡c dữ liệu cần thiết để tải trang.</translation>
<translation id="3228969707346345236">Dịch thất bại vì trang Ä‘Ă£ bằng <ph name="LANGUAGE" />.</translation>
<translation id="323107829343500871">Nhập CVC cho <ph name="CREDIT_CARD" /></translation>
<translation id="3254409185687681395">ÄĂ¡nh dấu trang nĂ y</translation>
<translation id="3270847123878663523">&amp;HoĂ n tĂ¡c sắp xếp lại</translation>
<translation id="3286538390144397061">Khởi Ä‘á»™ng lại Ngay bĂ¢y giá»</translation>
+<translation id="3303855915957856445">KhĂ´ng tìm thấy kết quả tìm kiếm nĂ o</translation>
<translation id="3305707030755673451">Dữ liệu của bạn Ä‘Ă£ được mĂ£ hĂ³a bằng cụm mật khẩu đồng bá»™ hĂ³a của bạn vĂ o <ph name="TIME" />. Nhập cụm mật khẩu Ä‘Ă³ để bắt đầu đồng bá»™ hĂ³a.</translation>
<translation id="333371639341676808">Ngăn khĂ´ng cho trang nĂ y tạo há»™p thoại bổ sung.</translation>
+<translation id="3338095232262050444">Bảo mật</translation>
<translation id="3340978935015468852">cĂ i đặt</translation>
<translation id="3345135638360864351">KhĂ´ng thể gá»­i yĂªu cầu truy cập trang web nĂ y của bạn tá»›i <ph name="NAME" />. Vui lĂ²ng thá»­ lại.</translation>
<translation id="3355823806454867987">Thay đổi cĂ i đặt proxy...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">Khoảng thá»i gian tìm nạp:</translation>
<translation id="3462200631372590220">Ẩn chi tiĂª̀t</translation>
<translation id="3479539252931486093">Trang web nĂ y cĂ³ nhÆ° bạn mong đợi khĂ´ng? HĂ£y <ph name="BEGIN_LINK" />cho chĂºng tĂ´i biết<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">KhĂ´ng phải bĂ¢y giá»</translation>
<translation id="348000606199325318">ID sá»± cố <ph name="CRASH_LOCAL_ID" /> (ID mĂ¡y chủ: <ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">ChĂºng tĂ´i khĂ´ng thể liĂªn lạc vá»›i cha mẹ của bạn vĂ o thá»i Ä‘iểm nĂ y. Vui lĂ²ng thá»­ lại.</translation>
<translation id="3527085408025491307">Thư mục</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">Sử dụng mật khẩu cho:</translation>
<translation id="3549644494707163724">MĂ£ hĂ³a tất cả dữ liệu Ä‘Ă£ đồng bá»™ hĂ³a bằng cụm mật khẩu đồng bá»™ hĂ³a của riĂªng bạn</translation>
<translation id="3549761410225185768"><ph name="NUM_TABS_MORE" /> tab nữa...</translation>
+<translation id="3555561725129903880">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y lĂ  từ <ph name="DOMAIN2" />. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3566021033012934673">Kết nối của bạn khĂ´ng phải lĂ  kết nối riĂªng tÆ°</translation>
<translation id="3583757800736429874">&amp;LĂ m lại di chuyển</translation>
<translation id="3586931643579894722">Ẩn chi tiết</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">Hiển thị giĂ¡ trị</translation>
<translation id="3630155396527302611">Nếu chÆ°Æ¡ng trình Ä‘Ă£ được liệt kĂª lĂ  chÆ°Æ¡ng trình được phĂ©p truy cập mạng, hĂ£y thá»­
xĂ³a chÆ°Æ¡ng trình nĂ y khá»i danh sĂ¡ch rồi thĂªm lại.</translation>
+<translation id="3638794133396384728">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y Ä‘Ă£ hết hạn. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. Äồng hồ của mĂ¡y tĂ­nh hiện được đặt thĂ nh <ph name="CURRENT_TIME" />. Äồng hồ nĂ y cĂ³ Ä‘Ăºng khĂ´ng? Nếu khĂ´ng Ä‘Ăºng, bạn phải sá»­a lại đồng hồ của hệ thống rồi lĂ m má»›i trang nĂ y. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="3648607100222897006">CĂ¡c tĂ­nh năng thá»­ nghiệm nĂ y cĂ³ thể thay đổi, há»ng hoặc biến mất bất kỳ lĂºc nĂ o. ChĂºng tĂ´i hoĂ n toĂ n khĂ´ng đảm bảo vá» những Ä‘iá»u cĂ³ thể xảy ra nếu bạn bật má»™t trong cĂ¡c thá»­ nghiệm nĂ y vĂ  trình duyệt của bạn thậm chĂ­ cĂ³ thể tá»± Ä‘á»™ng biến mất. NgoĂ i những Ä‘iá»u Ä‘Ă£ nĂ³i, trình duyệt của bạn cĂ³ thể xĂ³a tất cả dữ liệu của bạn hoặc tĂ­nh bảo mật vĂ  sá»± riĂªng tÆ° của bạn cĂ³ thể bị xĂ¢m phạm theo cĂ¡ch khĂ´ng mong đợi. Bất kỳ tĂ­nh năng thá»­ nghiệm nĂ o mĂ  bạn bật sẽ được bật cho tất cả ngÆ°á»i dĂ¹ng của trình duyệt nĂ y. HĂ£y tiến hĂ nh má»™t cĂ¡ch thận trá»ng.</translation>
<translation id="3650584904733503804">XĂ¡c thá»±c thĂ nh cĂ´ng</translation>
<translation id="3655670868607891010">Nếu bạn thÆ°á»ng xuyĂªn thấy thĂ´ng bĂ¡o nĂ y, hĂ£y thá»­ cĂ¡c <ph name="HELP_LINK" /> sau.</translation>
<translation id="3658742229777143148">Bản sửa đổi</translation>
+<translation id="3678029195006412963">KhĂ´ng thể kĂ½ yĂªu cầu</translation>
<translation id="3681007416295224113">Thông tin chứng chỉ</translation>
<translation id="3693415264595406141">Mật khẩu:</translation>
+<translation id="3696411085566228381">khĂ´ng cĂ³</translation>
<translation id="3700528541715530410">Rất tiếc, cĂ³ vẻ nhÆ° bạn khĂ´ng cĂ³ quyá»n truy cập trang nĂ y.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Äang tải...</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">Bật dữ liệu di dộng hoặc Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Kiểm tra proxy, tÆ°á»ng lá»­a vĂ  cấu hình DNS<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">LiĂªn kết Ä‘Ă£ sao chĂ©p</translation>
-<translation id="3744899669254331632">Bạn khĂ´ng thể truy cập <ph name="SITE" /> ngay bĂ¢y giá» vì trang web nĂ y Ä‘Ă£ gá»­i thĂ´ng tin đăng nhập há»—n Ä‘á»™n mĂ  Chromium khĂ´ng thể xá»­ lĂ½. Lá»—i mạng vĂ  cĂ¡c cuá»™c tấn cĂ´ng thÆ°á»ng chỉ diá»…n ra tạm thá»i nĂªn trang nĂ y cĂ³ thể sẽ hoạt Ä‘á»™ng sau.</translation>
<translation id="375403751935624634">KhĂ´ng thể dịch do lá»—i mĂ¡y chủ.</translation>
<translation id="3759461132968374835">Bạn khĂ´ng nhận được bĂ¡o cĂ¡o sá»± cố nĂ o gần Ä‘Ă¢y. Sá»± cố xảy ra khi bĂ¡o cĂ¡o sá»± cố Ä‘Ă£ bị tắt sẽ khĂ´ng xuất hiện ở Ä‘Ă¢y.</translation>
<translation id="3788090790273268753">Chứng chỉ cho trang web nĂ y sẽ hết hạn vĂ o năm 2016, đồng thá»i, chuá»—i chứng chỉ nĂ y chứa má»™t chứng chỉ Ä‘Ă£ kĂ½ bằng SHA-1.</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">Số nhận dạng thiết bị xung đột</translation>
<translation id="3885155851504623709">Xàƒ</translation>
<translation id="3901925938762663762">Thẻ Ä‘Ă£ hết hạn</translation>
+<translation id="3910267023907260648">Bạn Ä‘Ă£ cố gắng truy cập <ph name="DOMAIN" /> nhÆ°ng mĂ¡y chủ xuất trình má»™t chứng chỉ được kĂ½ bằng má»™t thuật toĂ¡n chữ kĂ½ yếu. Äiá»u nĂ y cĂ³ nghÄ©a lĂ  thĂ´ng tin đăng nhập bảo mật mĂ  mĂ¡y chủ xuất trình cĂ³ thể Ä‘Ă£ bị giả mạo vĂ  mĂ¡y chủ Ä‘Ă³ cĂ³ thể khĂ´ng phải lĂ  mĂ¡y chủ mĂ  bạn mong đợi (bạn cĂ³ thể Ä‘ang kết nối vá»›i kẻ tấn cĂ´ng). <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="3933571093587347751">{1,plural, =1{MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y được Ä‘á» lĂ  ngĂ y mai. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.}other{MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y được Ä‘á» lĂ  # ngĂ y nữa trong tÆ°Æ¡ng lai. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.}}</translation>
<translation id="3934680773876859118">KhĂ´ng thể tải tĂ i liệu PDF</translation>
<translation id="3963721102035795474">Chế Ä‘á»™ Ä‘á»c</translation>
+<translation id="397105322502079400">Äang tĂ­nh...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> bị chặn</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{1 trang web lĂ¢n cận}other{# trang web lĂ¢n cận}}</translation>
<translation id="4021036232240155012">DNS lĂ  dịch vụ mạng dịch tĂªn trang web sang địa chỉ Internet.</translation>
<translation id="4030383055268325496">&amp;HoĂ n tĂ¡c thĂªm</translation>
-<translation id="4032534284272647190">Truy cập tới <ph name="URL" /> bị từ chối.</translation>
<translation id="404928562651467259">CẢNH BĂO</translation>
<translation id="4058922952496707368">KhĂ³a "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4075732493274867456">Ứng dụng vĂ  mĂ¡y chủ khĂ´ng há»— trợ bá»™ mĂ£ hĂ³a hoặc phiĂªn bản giao thức SSL thĂ´ng thÆ°á»ng.</translation>
<translation id="4079302484614802869">Cấu hình proxy được đặt để sá»­ dụng URL tập lệnh .pac chứ khĂ´ng phải mĂ¡y chủ proxy cố định.</translation>
<translation id="4103249731201008433">Số sĂª-ri thiết bị khĂ´ng hợp lệ</translation>
<translation id="4103763322291513355">Truy cập &lt;strong&gt;chrome://policy&lt;/strong&gt; để xem danh sĂ¡ch cĂ¡c URL bị chặn quyá»n truy cập vĂ  cĂ¡c chĂ­nh sĂ¡ch khĂ¡c bị quản trị viĂªn hệ thống buá»™c phải thá»±c thi.</translation>
+<translation id="4110615724604346410">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y cĂ³ lá»—i. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4117700440116928470">Phạm vi chĂ­nh sĂ¡ch khĂ´ng được há»— trợ.</translation>
+<translation id="4118212371799607889">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y khĂ´ng được Chromium tin tưởng. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 mục khàc}other{# mục khĂ¡c}}</translation>
<translation id="4130226655945681476">Kiểm tra cĂ¡p mạng, modem vĂ  bá»™ định tuyến</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">Bạn cĂ³ muốn Chromium lÆ°u thẻ nĂ y khĂ´ng?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">ÄĂ£ bị vĂ´ hiệu</translation>
<translation id="4196861286325780578">&amp;LĂ m lại di chuyển</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Kiểm tra tÆ°á»ng lá»­a vĂ  cấu hình diệt vi-rĂºt<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{khĂ´ng cĂ³ gì}=1{1 ứng dụng ($1)}=2{2 ứng dụng ($1, $2)}other{# ứng dụng ($1, $2, $3)}}</translation>
<translation id="4220128509585149162">Sự cố</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Thá»­ chạy Chẩn Ä‘oĂ¡n mạng<ph name="END_LINK" />.</translation>
<translation id="4250680216510889253">KhĂ´ng</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(KhĂ´ng cĂ³ tĂªn ngÆ°á»i dĂ¹ng)</translation>
<translation id="4300246636397505754">Äá» xuất chĂ­nh</translation>
<translation id="4304224509867189079">Äăng nhập</translation>
+<translation id="432290197980158659">MĂ¡y chủ Ä‘Ă£ xuất trình chứng chỉ khĂ´ng khá»›p vá»›i cĂ¡c kỳ vá»ng được tĂ­ch hợp sẵn. CĂ¡c kỳ vá»ng nĂ y cĂ³ trong má»™t số trang web nhất định, cĂ³ tĂ­nh bảo mật cao vá»›i mục Ä‘Ă­ch bảo vệ bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4325863107915753736">KhĂ´ng tìm được bĂ i viết</translation>
+<translation id="4331708818696583467">KhĂ´ng bảo mật</translation>
<translation id="4372948949327679948">GiĂ¡ trị <ph name="VALUE_TYPE" /> mong đợi.</translation>
-<translation id="4377125064752653719">Bạn Ä‘Ă£ cố truy cập vĂ o <ph name="DOMAIN" /> nhÆ°ng chứng chỉ mĂ  mĂ¡y chủ xuất trình Ä‘Ă£ bị nhĂ  phĂ¡t hĂ nh thu hồi. Äiá»u nĂ y cĂ³ nghÄ©a lĂ  giấy ủy nhiệm bảo mật mĂ  mĂ¡y chủ xuất trình hoĂ n toĂ n khĂ´ng Ä‘Ă¡ng tin cậy. Bạn cĂ³ thể Ä‘ang giao tiếp vá»›i kẻ tấn cĂ´ng.</translation>
<translation id="4381091992796011497">TĂªn NgÆ°á»i dĂ¹ng:</translation>
<translation id="4394049700291259645">VĂ´ hiệu hĂ³a</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> đến <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">kết quả tìm kiếm</translation>
-<translation id="4424024547088906515">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y khĂ´ng được Chrome tin cậy. Äiá»u nĂ y cĂ³ thể do định cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> khĂ´ng chấp nhận chứng chỉ đăng nhập của bạn hoặc cĂ³ thể bạn chÆ°a cung cấp chứng chỉ đăng nhập.</translation>
<translation id="443673843213245140">ÄĂ£ tắt sá»­ dụng proxy nhÆ°ng cấu hình proxy rõ rĂ ng được chỉ định.</translation>
<translation id="4458874409874303848">Trang web an toĂ n</translation>
<translation id="4461847750548395463">Bạn thấy thĂ´ng bĂ¡o nĂ y vì Trang web an toĂ n của Google được bật.</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">Chi tiết</translation>
<translation id="4558551763791394412">Thá»­ tắt tiện Ă­ch.</translation>
<translation id="4587425331216688090">XĂ³a địa chỉ khá»i Chrome?</translation>
+<translation id="4589078953350245614">Bạn Ä‘Ă£ cố gắng truy cập <ph name="DOMAIN" /> nhÆ°ng mĂ¡y chủ Ä‘Ă£ xuất trình chứng chỉ khĂ´ng hợp lệ. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="4592951414987517459">Kết nối của bạn tá»›i <ph name="DOMAIN" /> được mĂ£ hĂ³a bằng bá»™ số 0 hiện đại.</translation>
<translation id="4594403342090139922">&amp;HoĂ n tĂ¡c xĂ³a</translation>
+<translation id="4627442949885028695">Tiếp tục từ thiết bị khĂ¡c</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">Bạn Ä‘ang xem trang tiện Ă­ch.</translation>
-<translation id="467662567472608290">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y cĂ³ lá»—i. Äiá»u nĂ y cĂ³ thể do định cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.</translation>
-<translation id="4697214168136963651"><ph name="URL" /> Ä‘Ă£ bị chặn</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">Kết nối của bạn bị giĂ¡n Ä‘oạn</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Chạy Chẩn Ä‘oĂ¡n mạng của Windows<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">NĂª̀€n tảng</translation>
<translation id="4744603770635761495">ÄÆ°á»ng dẫn thá»±c thi</translation>
<translation id="4756388243121344051">&amp;Lịch sử</translation>
+<translation id="4759238208242260848">Tải xuống</translation>
<translation id="4764776831041365478">Trang web tại <ph name="URL" /> cĂ³ thể tạm thá»i khĂ´ng hoạt Ä‘á»™ng hay được chuyển vÄ©nh viá»…n sang địa chỉ web má»›i.</translation>
<translation id="4771973620359291008">Xảy ra lỗi chưa biết.</translation>
<translation id="4782449893814226250">Bạn Ä‘Ă£ há»i cha mẹ mình xem cĂ³ thể truy cập vĂ o trang nĂ y hay khĂ´ng.</translation>
<translation id="4800132727771399293">Kiểm tra ngĂ y hết hạn vĂ  CVC của bạn rồi thá»­ lại</translation>
-<translation id="4807049035289105102">Bạn khĂ´ng thể truy cập <ph name="SITE" /> ngay bĂ¢y giá» do trang web gá»­i thĂ´ng tin đăng nhập Ä‘Ă£ mĂ£ hĂ³a mĂ  Google Chrome khĂ´ng thể xá»­ lĂ½. LĂ´̀ƒi mà£ng và€ càc cuĂ´̀£c tĂ¢̀n cĂ´ng mà£ng thÆ°Æ¡̀€ng chì‰ là€ tà£m thÆ¡̀€i, do Ä‘ò trang nà€y cò thĂª̀‰ sèƒ hoà£t Ä‘Ă´̀£ng là£i sau.</translation>
<translation id="4813512666221746211">Lỗi mạng</translation>
<translation id="4816492930507672669">Vừa với trang</translation>
<translation id="4850886885716139402">Xem</translation>
<translation id="4880827082731008257">Lịch sá»­ tìm kiếm</translation>
+<translation id="4884656795097055129">CĂ¡c bĂ i viết khĂ¡c sẽ xuất hiện khi đến Ä‘Ăºng thá»i Ä‘iểm.</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{vĂ  thĂªm 1 trang web}other{vĂ  thĂªm # trang web}}</translation>
<translation id="4923417429809017348">Trang nĂ y Ä‘Ă£ được dịch từ má»™t ngĂ´n ngữ khĂ´ng xĂ¡c định sang <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">Phải được chỉ định.</translation>
<translation id="4930497775425430760">Bạn thấy thĂ´ng bĂ¡o nĂ y vì cha mẹ bạn cần phải phĂª duyệt cĂ¡c trang web má»›i vĂ o lần truy cập đầu tiĂªn của bạn.</translation>
<translation id="495170559598752135">TĂ¡c vụ</translation>
<translation id="4958444002117714549">Mở rá»™ng danh sĂ¡ch</translation>
+<translation id="4962322354953122629">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y khĂ´ng được Chrome tin tưởng. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="498957508165411911">Dịch từ <ph name="ORIGINAL_LANGUAGE" /> sang <ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">Plugin nĂ y khĂ´ng được há»— trợ</translation>
<translation id="5002932099480077015">Nếu được bật, Chrome sẽ lÆ°u trữ bản sao thẻ của bạn trĂªn thiết bị nĂ y để Ä‘iá»n vĂ o biểu mẫu nhanh hÆ¡n.</translation>
<translation id="5019198164206649151">KhĂ´ng thể lÆ°u trữ do chÆ°Æ¡ng trình phụ trợ ở trạng thĂ¡i xấu</translation>
<translation id="5023310440958281426">Kiểm tra chĂ­nh sĂ¡ch của quản trị viĂªn của bạn</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">Giới thiệu vỠGoogle Dịch</translation>
<translation id="5040262127954254034">Bảo mật</translation>
<translation id="5045550434625856497">Mật khẩu sai</translation>
+<translation id="5056549851600133418">BĂ i viết dĂ nh cho bạn</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Kiểm tra địa chỉ proxy<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">Chứng chỉ của mĂ¡y chủ khĂ´ng hợp lệ tại thá»i Ä‘iểm nĂ y.</translation>
<translation id="5089810972385038852">TiĂª̀‰u bang</translation>
-<translation id="5094747076828555589">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y khĂ´ng được Chromium tin cậy. Äiá»u nĂ y cĂ³ thể do định cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.</translation>
<translation id="5095208057601539847">Tỉnh/thành phố</translation>
<translation id="5115563688576182185">(64 bit)</translation>
-<translation id="5122371513570456792">ÄĂ£ tìm thấy <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> cho '<ph name="SEARCH_STRING" />'.</translation>
<translation id="5141240743006678641">MĂ£ hĂ³a mật khẩu Ä‘Ă£ đồng bá»™ hĂ³a vá»›i thĂ´ng tin đăng nhập Google của bạn</translation>
<translation id="5145883236150621069">MĂ£ lá»—i cĂ³ trong phản hồi chĂ­nh sĂ¡ch</translation>
<translation id="5171045022955879922">Tìm kiếm hoặc nhập URL</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">Thanh Dấu trang</translation>
<translation id="5199729219167945352">Thử nghiệm</translation>
<translation id="5251803541071282808">ÄĂ¡m mĂ¢y</translation>
+<translation id="5277279256032773186">Sá»­ dụng Chrome ở cÆ¡ quan? CĂ¡c doanh nghiệp cĂ³ thể quản lĂ½ cĂ i đặt Chrome cho nhĂ¢n viĂªn của há». Tìm hiểu thĂªm</translation>
<translation id="5299298092464848405">Lá»—i phĂ¢n tĂ­ch cĂº phĂ¡p chĂ­nh sĂ¡ch</translation>
<translation id="5300589172476337783">Hiển thị</translation>
<translation id="5308689395849655368">BĂ¡o cĂ¡o sá»± cố bị tắt.</translation>
<translation id="5317780077021120954">LÆ°u</translation>
<translation id="5327248766486351172">TĂªn</translation>
+<translation id="5359637492792381994">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; hiện tại, chứng chỉ bảo mật của mĂ¡y chủ nĂ y khĂ´ng hợp lệ. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="536296301121032821">KhĂ´ng thể lÆ°u trữ cĂ i đặt chĂ­nh sĂ¡ch</translation>
-<translation id="540969355065856584">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y khĂ´ng hợp lệ tại thá»i Ä‘iểm nĂ y. Äiá»u nĂ y cĂ³ thể do định cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.</translation>
<translation id="5421136146218899937">XĂ³a dữ liệu duyệt web...</translation>
<translation id="5430298929874300616">XĂ³a dấu trang</translation>
<translation id="5431657950005405462">KhĂ´ng tìm thấy tệp của bạn</translation>
<translation id="5435775191620395718">Hiển thị lịch sá»­ từ thiết bị nĂ y. <ph name="BEGIN_LINK" />Tìm hiểu thĂªm<ph name="END_LINK" />.</translation>
-<translation id="5437003064129843501">TĂ­nh năng Ä‘á» xuất ná»™i dung được cĂ¡ nhĂ¢n hĂ³a hiện bị tắt vì dữ liệu Ä‘Ă£ đồng bá»™ hĂ³a của bạn được bảo vệ bằng cụm mật khẩu tĂ¹y chỉnh.</translation>
<translation id="5439770059721715174">Lá»—i xĂ¡c thá»±c lược đồ tại "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5452270690849572955">KhĂ´ng thể tìm thấy trang <ph name="HOST_NAME" /> nĂ y</translation>
<translation id="5455374756549232013">Dấu thá»i gian chĂ­nh sĂ¡ch khĂ´ng hợp lệ</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">Bạn cĂ³ muốn rá»i khá»i trang web nĂ y khĂ´ng?</translation>
<translation id="5629630648637658800">KhĂ´ng thể tải cĂ i đặt chĂ­nh sĂ¡ch</translation>
<translation id="5631439013527180824">MĂ£ thĂ´ng bĂ¡o quản lĂ½ thiết bị khĂ´ng hợp lệ</translation>
-<translation id="5650551054760837876">KhĂ´ng tìm thấy kết quả tìm kiếm.</translation>
<translation id="5677928146339483299">Bị chặn</translation>
<translation id="5710435578057952990">Nhận dạng trang web nĂ y chÆ°a được xĂ¡c minh.</translation>
<translation id="5720705177508910913">NgÆ°á»i dĂ¹ng hiện tại</translation>
+<translation id="572328651809341494">CĂ¡c tab gần Ä‘Ă¢y</translation>
<translation id="5784606427469807560">ÄĂ£ xảy ra sá»± cố khi xĂ¡c nhận thẻ của bạn. HĂ£y kiểm tra kết nối Internet của bạn vĂ  thá»­ lại.</translation>
<translation id="5785756445106461925">NgoĂ i ra, trang nĂ y bao gồm cĂ¡c tĂ i nguyĂªn khĂ¡c khĂ´ng an toĂ n. Những tĂ i nguyĂªn nĂ y cĂ³ thể bị ngÆ°á»i khĂ¡c xem khi Ä‘ang gá»­i vĂ  cĂ³ thể bị kẻ tấn cĂ´ng sá»­a đổi nhằm thay đổi giao diện của trang.</translation>
+<translation id="5786044859038896871">Bạn cĂ³ muốn Ä‘iá»n thĂ´ng tin thẻ của mình khĂ´ng?</translation>
+<translation id="5803412860119678065">Bạn cĂ³ muốn Ä‘iá»n <ph name="CARD_DETAIL" /> của mình khĂ´ng?</translation>
<translation id="5810442152076338065">Kết nối của bạn tá»›i <ph name="DOMAIN" /> được mĂ£ hĂ³a bằng bá»™ số 0 Ä‘Ă£ lá»—i thá»i.</translation>
<translation id="5813119285467412249">&amp;LĂ m lại thĂªm</translation>
+<translation id="5814352347845180253">Bạn cĂ³ thể mất quyá»n truy cập vĂ o ná»™i dung cao cấp từ <ph name="SITE" /> vĂ  má»™t số trang web khĂ¡c.</translation>
+<translation id="5843436854350372569">Bạn Ä‘Ă£ cố gắng truy cập <ph name="DOMAIN" /> nhÆ°ng mĂ¡y chủ xuất trình chứng chỉ chứa khĂ³a yếu. Kẻ tấn cĂ´ng cĂ³ thể Ä‘Ă£ phĂ¡ khĂ³a cĂ¡ nhĂ¢n vĂ  mĂ¡y chủ Ä‘Ă³ cĂ³ thể khĂ´ng phải lĂ  mĂ¡y chủ bạn mong đợi (bạn cĂ³ thể Ä‘ang kết nối vá»›i kẻ tấn cĂ´ng). <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="5855235287355719921">Bạn thấy thĂ´ng bĂ¡o nĂ y vì ngÆ°á»i quản lĂ½ của bạn Ä‘Ă£ chặn trang web nĂ y.</translation>
<translation id="5857090052475505287">Thư mục Mới</translation>
<translation id="5869405914158311789">KhĂ´ng thể truy cập trang web nĂ y</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">Äá» xuất chĂ­nh</translation>
<translation id="59107663811261420">Loại thẻ nĂ y khĂ´ng được Google Payments há»— trợ cho ngÆ°á»i bĂ¡n nĂ y. Vui lĂ²ng chá»n thẻ khĂ¡c.</translation>
<translation id="59174027418879706">ÄĂ£ bật</translation>
+<translation id="5926846154125914413">Bạn cĂ³ thể mất quyá»n truy cập vĂ o ná»™i dung cao cấp từ má»™t số trang web.</translation>
<translation id="5966707198760109579">Tuần</translation>
<translation id="5967867314010545767">XĂ³a khá»i lịch sá»­</translation>
<translation id="5975083100439434680">Thu nhá»</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">Tá»± Ä‘á»™ng</translation>
<translation id="6042308850641462728">ThĂªm</translation>
<translation id="6060685159320643512">HĂ£y cẩn thận, thá»­ nghiệm nĂ y cĂ³ thể gĂ¢y lá»—i</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{khĂ´ng cĂ³ gì}=1{1}other{#}}</translation>
<translation id="6146055958333702838">Kiểm tra má»i dĂ¢y cĂ¡p rồi khởi Ä‘á»™ng lại bá»™ định tuyến, modem hoặc cĂ¡c thiết bị
mạng khĂ¡c mĂ  bạn cĂ³ thể Ä‘ang sá»­ dụng.</translation>
<translation id="614940544461990577">HĂ£y thá»­:</translation>
<translation id="6150607114729249911">Rất tiếc! Bạn cần phải há»i cha mẹ mình xem cĂ³ thể truy cập trang nĂ y hay khĂ´ng.</translation>
<translation id="6151417162996330722">Chứng chỉ mĂ¡y chủ cĂ³ thá»i gian hiệu lá»±c quĂ¡ dĂ i.</translation>
-<translation id="6154808779448689242">MĂ£ thĂ´ng bĂ¡o chĂ­nh sĂ¡ch trả lại khĂ´ng phĂ¹ hợp vá»›i mĂ£ thĂ´ng bĂ¡o hiện tại</translation>
<translation id="6165508094623778733">Tìm hiểu thĂªm</translation>
<translation id="6203231073485539293">Kiểm tra kết nối Internet của bạn</translation>
<translation id="6218753634732582820">Bạn muốn xĂ³a địa chỉ khá»i Chromium?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">Thá»­ tắt dá»± Ä‘oĂ¡n mạng</translation>
<translation id="6337534724793800597">Lá»c chĂ­nh sĂ¡ch theo tĂªn</translation>
<translation id="6342069812937806050">Vừa mới</translation>
+<translation id="6345221851280129312">kĂ­ch thÆ°á»›c khĂ´ng xĂ¡c định</translation>
<translation id="6355080345576803305">Ghi đè phiĂªn cĂ´ng khai</translation>
<translation id="6358450015545214790">Những phần nĂ y cĂ³ Ă½ nghÄ©a gì?</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 Ä‘á» xuất khĂ¡c}other{# Ä‘á» xuất khĂ¡c}}</translation>
<translation id="6387478394221739770">Bạn quan tĂ¢m đến cĂ¡c tĂ­nh năng má»›i thĂº vị của Chrome? HĂ£y dĂ¹ng thá»­ kĂªnh thá»­ nghiệm beta của chĂºng tĂ´i tại chrome.com/beta.</translation>
-<translation id="641480858134062906">KhĂ´ng tải được <ph name="URL" /></translation>
+<translation id="6389758589412724634">Chromium Ä‘Ă£ hết bá»™ nhá»› khi cố gắng hiển thị trang web nĂ y.</translation>
+<translation id="6416403317709441254">Bạn khĂ´ng thể truy cập <ph name="SITE" /> ngay bĂ¢y giá» do trang web gá»­i thĂ´ng tin đăng nhập Ä‘Ă£ mĂ£ hĂ³a mĂ  Chromium khĂ´ng thể xá»­ lĂ½. Lá»—i mạng vĂ  cĂ¡c cuá»™c tấn cĂ´ng mạng thÆ°á»ng chỉ lĂ  tạm thá»i, do Ä‘Ă³, trang nĂ y cĂ³ thể sẽ hoạt Ä‘á»™ng lại sau. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6417515091412812850">KhĂ´ng thể kiểm tra liệu chứng chỉ Ä‘Ă£ bị thu hồi hay chÆ°a.</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> Ä‘Ă£ từ chối kết nối.</translation>
<translation id="6445051938772793705">Quốc gia</translation>
<translation id="6451458296329894277">XĂ¡c nhận việc Gá»­i lại Biểu mẫu</translation>
<translation id="6458467102616083041">Bị bá» qua vì chĂ­nh sĂ¡ch Ä‘Ă£ tắt tìm kiếm mặc định.</translation>
+<translation id="6462969404041126431">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y cĂ³ thể bị thu hồi. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="647261751007945333">ChĂ­nh sĂ¡ch thiết bị</translation>
<translation id="6489534406876378309">Bắt đầu tải lĂªn sá»± cố</translation>
<translation id="6529602333819889595">&amp;LĂ m lại xĂ³a</translation>
+<translation id="6534179046333460208">Äá» xuất Web trong cuá»™c sống</translation>
<translation id="6550675742724504774">TĂ¹y chá»n</translation>
+<translation id="6593753688552673085">dÆ°á»›i <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">TĂ¹y chá»n mĂ£ hĂ³a</translation>
<translation id="662080504995468778">Æ ̀‰ là£i</translation>
<translation id="6628463337424475685">Tìm kiếm trĂªn <ph name="ENGINE" /></translation>
-<translation id="6634865548447745291">Bạn khĂ´ng thể truy cập <ph name="SITE" /> ngay bĂ¢y giá» do <ph name="BEGIN_LINK" />chứng chỉ nĂ y Ä‘Ă£ bị thu hồi<ph name="END_LINK" />. Lá»—i mạng vĂ  cĂ¡c cuá»™c tấn cĂ´ng mà£ng thÆ°á»ng chì‰ là€ tạm thá»i, do Ä‘Ă³ trang nĂ y cĂ³ thể sẽ hoạt Ä‘á»™ng lại sau.</translation>
<translation id="6644283850729428850">ChĂ­nh sĂ¡ch nĂ y khĂ´ng được chấp thuận.</translation>
+<translation id="6652240803263749613">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y khĂ´ng được hệ Ä‘iá»u hĂ nh của mĂ¡y tĂ­nh tin tưởng. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6656103420185847513">Chỉnh sửa thư mục</translation>
<translation id="6660210980321319655"><ph name="CRASH_TIME" /> được bĂ¡o cĂ¡o tá»± Ä‘á»™ng</translation>
<translation id="6671697161687535275">Bạn muốn xĂ³a Ä‘á» xuất biểu mẫu khá»i Chromium?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">TrÆ°á»›c Ä‘Ă³</translation>
<translation id="6710594484020273272">&lt;Nhập cụm từ tìm kiếm&gt;</translation>
<translation id="6711464428925977395">ÄĂ£ xảy ra sá»± cố vá»›i mĂ¡y chủ proxy hoặc địa chỉ khĂ´ng chĂ­nh xĂ¡c.</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{khĂ´ng cĂ³ gì}=1{1 mục}other{# mục}}</translation>
<translation id="674375294223700098">Lá»—i chứng chỉ mĂ¡y chủ khĂ´ng xĂ¡c định.</translation>
<translation id="6753269504797312559">GiĂ¡ trị chĂ­nh sĂ¡ch</translation>
<translation id="6757797048963528358">Thiết bị của bạn Ä‘Ă£ chuyển sang chế Ä‘á»™ ngủ.</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">CĂ¢̀p chình sàch khĂ´ng Ä‘Æ°Æ¡̀£c hĂ´̀ƒ trÆ¡̀£.</translation>
<translation id="6895330447102777224">Thẻ của bạn Ä‘Ă£ được xĂ¡c nhận</translation>
<translation id="6897140037006041989">TĂ¡c nhĂ¢n NgÆ°á»i dĂ¹ng</translation>
-<translation id="6903907808598579934">Bật đồng bá»™ hĂ³a</translation>
<translation id="6915804003454593391">NgÆ°á»i dĂ¹ng:</translation>
<translation id="6957887021205513506">Chứng chỉ của mĂ¡y chủ dÆ°á»ng nhÆ° giả mạo.</translation>
<translation id="6965382102122355670">OK</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">Quận</translation>
<translation id="6973656660372572881">Cả hai mĂ¡y chủ proxy cố định vĂ  URL tập lệnh .pac Ä‘á»u được chỉ định.</translation>
<translation id="6989763994942163495">Hiển thị cĂ i đặt nĂ¢ng cao...</translation>
+<translation id="7000990526846637657">KhĂ´ng tìm thấy mục nhập lịch sá»­ nĂ o</translation>
+<translation id="7009986207543992532">Bạn Ä‘Ă£ cố gắng truy cập <ph name="DOMAIN" /> nhÆ°ng mĂ¡y chủ Ä‘Ă£ xuất trình chứng chỉ cĂ³ thá»i gian cĂ³ hiệu lá»±c quĂ¡ dĂ i để cĂ³ thể tin cậy. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7012372675181957985">TĂ i khoản Google của bạn cĂ³ thể cĂ³ cĂ¡c biểu mẫu lịch sá»­ duyệt web khĂ¡c tại <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /></translation>
<translation id="7029809446516969842">Mật khẩu</translation>
-<translation id="7050187094878475250">Bạn Ä‘Ă£ cố gắng truy cập <ph name="DOMAIN" /> nhÆ°ng mĂ¡y chủ Ä‘Ă£ hiển thị chứng chỉ cĂ³ thá»i gian hiệu lá»±c quĂ¡ dĂ i để cĂ³ thể tin cậy.</translation>
<translation id="7087282848513945231">Hạt</translation>
<translation id="7088615885725309056">Cũ hơn</translation>
<translation id="7090678807593890770">Tìm kiếm <ph name="LINK" /> trĂªn Google</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Bạn thấy thĂ´ng bĂ¡o nĂ y vì ngÆ°á»i quản lĂ½ của bạn cần phải phĂª duyệt cĂ¡c trang web má»›i vĂ o lần truy cập đầu tiĂªn của bạn.</translation>
<translation id="724975217298816891">Nhập ngĂ y hết hạn vĂ  CVC cho <ph name="CREDIT_CARD" /> để cập nhật chi tiết thẻ của bạn. Sau khi bạn xĂ¡c nhận, chi tiết thẻ của bạn sẽ được chia sẻ vá»›i trang web nĂ y.</translation>
<translation id="725866823122871198">KhĂ´ng thể thiết lập kết nối riĂªng tÆ° vá»›i <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> vì ngĂ y vĂ  giá» (<ph name="DATE_AND_TIME" />) trĂªn mĂ¡y tĂ­nh của bạn khĂ´ng Ä‘Ăºng.</translation>
-<translation id="7265986070661382626">Bạn khĂ´ng thể truy cập <ph name="SITE" /> ngay bĂ¢y giá» do trang web <ph name="BEGIN_LINK" />sá»­ dụng ghim chứng chỉ<ph name="END_LINK" />. Lá»—i mạng vĂ  cĂ¡c cuá»™c tấn cĂ´ng mà£ng thÆ°á»ng chì‰ là€ tạm thá»i do Ä‘Ă³ trang nĂ y cĂ³ thể sẽ hoạt Ä‘á»™ng lại sau.</translation>
<translation id="7269802741830436641">Trang web nĂ y lặp lại chuyển hÆ°á»›ng</translation>
<translation id="7275334191706090484">Dấu trang được quản lĂ½</translation>
<translation id="7298195798382681320">Äược Ä‘á» xuất</translation>
-<translation id="7301833672208172928">Bật đồng bá»™ hĂ³a lịch sá»­</translation>
+<translation id="7309308571273880165">BĂ¡o cĂ¡o sá»± cố được ghi lại vĂ o <ph name="CRASH_TIME" /> (ngÆ°á»i dĂ¹ng yĂªu cầu tải lĂªn, nhÆ°ng chÆ°a được tải lĂªn)</translation>
<translation id="7334320624316649418">&amp;LĂ m lại sắp xếp lại</translation>
<translation id="733923710415886693">Chứng chỉ của mĂ¡y chủ Ä‘Ă£ khĂ´ng được tiết lá»™ qua TĂ­nh minh bạch của chứng chỉ.</translation>
+<translation id="7351800657706554155">Bạn khĂ´ng thể truy cập <ph name="SITE" /> ngay bĂ¢y giá» do chứng chỉ của trang web Ä‘Ă£ bị thu hồi. CĂ¡c cuá»™c tấn cĂ´ng vĂ  lá»—i mạng thÆ°á»ng chỉ lĂ  tạm thá»i, do Ä‘Ă³ trang nĂ y cĂ³ thể sẽ hoạt Ä‘á»™ng lại sau. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="7353601530677266744">DĂ²ng Lệnh</translation>
<translation id="7372973238305370288">kết quả tìm kiếm</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@ LÆ°u Ă½! Chế Ä‘á»™ ẩn danh <ph name="SHORTCUT_KEY" /> cĂ³ thể hữu Ă­ch v
<translation id="7469372306589899959">Äang xĂ¡c nhận thẻ</translation>
<translation id="7481312909269577407">Chuyển tiếp</translation>
<translation id="7485870689360869515">KhĂ´ng tìm thấy dÆ°̀ƒ liệu.</translation>
+<translation id="7508255263130623398">ID thiết bị thuá»™c chĂ­nh sĂ¡ch trả lại trống hoặc khĂ´ng khá»›p vá»›i ID của thiết bị hiện tại</translation>
<translation id="7514365320538308">Tải xuống</translation>
<translation id="7518003948725431193">KhĂ´ng tìm thấy trang web nĂ o ứng vá»›i địa chỉ web:<ph name="URL" /></translation>
<translation id="7537536606612762813">Bắt buộc</translation>
<translation id="7542995811387359312">TĂ­nh năng tá»± Ä‘á»™ng Ä‘iá»n thẻ tĂ­n dụng Ä‘Ă£ bị vĂ´ hiệu hĂ³a vì biểu mẫu nĂ y khĂ´ng sá»­ dụng kết nối an toĂ n.</translation>
<translation id="7549584377607005141">Trang web nĂ y yĂªu cầu dữ liệu mĂ  bạn Ä‘Ă£ nhập trÆ°á»›c Ä‘Ă³ để được hiển thị Ä‘Ăºng cĂ¡ch. Bạn cĂ³ thể gá»­i lại dữ liệu nĂ y nhÆ°ng lĂ m nhÆ° vậy bạn sẽ lặp lại má»i hoạt Ä‘á»™ng mĂ  trang nĂ y Ä‘Ă£ thá»±c hiện trÆ°á»›c Ä‘Ă³.</translation>
<translation id="7554791636758816595">Tab má»›i</translation>
-<translation id="7567204685887185387">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y cĂ³ thể Ä‘Ă£ bị gian lận khi phĂ¡t hĂ nh. Äiá»u nĂ y cĂ³ thể do định cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn.</translation>
<translation id="7568593326407688803">Trang nĂ y bằng<ph name="ORIGINAL_LANGUAGE" />Bạn cĂ³ muốn dịch trang nĂ y khĂ´ng?</translation>
<translation id="7569952961197462199">XĂ³a thẻ tĂ­n dụng khá»i Chrome?</translation>
<translation id="7578104083680115302">Thanh toĂ¡n nhanh trĂªn cĂ¡c trang web vĂ  ứng dụng trong má»i thiết bị nhá» sá»­ dụng thẻ bạn Ä‘Ă£ lÆ°u vá»›i Google.</translation>
+<translation id="7588950540487816470">Web trong cuộc sống</translation>
<translation id="7592362899630581445">Chứng chỉ của mĂ¡y chủ vi phạm hạn chế tĂªn.</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> hiện khĂ´ng thể xá»­ lĂ½ yĂªu cầu nĂ y.</translation>
<translation id="7600965453749440009">Không bao giỠdịch <ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@ LÆ°u Ă½! Chế Ä‘á»™ ẩn danh <ph name="SHORTCUT_KEY" /> cĂ³ thể hữu Ă­ch v
<translation id="7637571805876720304">Bạn muốn xĂ³a thẻ tĂ­n dụng khá»i Chromium?</translation>
<translation id="765676359832457558">Ẩn cĂ i đặt nĂ¢ng cao...</translation>
<translation id="7658239707568436148">Hủy</translation>
+<translation id="7667346355482952095">MĂ£ thĂ´ng bĂ¡o chĂ­nh sĂ¡ch trả vá» trống hoặc khĂ´ng khá»›p vá»›i mĂ£ thĂ´ng bĂ¡o hiện tại</translation>
<translation id="7668654391829183341">Thiết bị khĂ´ng xĂ¡c định</translation>
<translation id="7674629440242451245">Bạn quan tĂ¢m đến cĂ¡c tĂ­nh năng má»›i thĂº vị của Chrome? HĂ£y dĂ¹ng thá»­ kĂªnh nhĂ  phĂ¡t triển của chĂºng tĂ´i tại chrome.com/dev.</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Tiếp tục truy cập <ph name="SITE" /> (khĂ´ng an toĂ n)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@ LÆ°u Ă½! Chế Ä‘á»™ ẩn danh <ph name="SHORTCUT_KEY" /> cĂ³ thể hữu Ă­ch v
<translation id="780301667611848630">KhĂ´ng, cảm Æ¡n</translation>
<translation id="7805768142964895445">Trạng thĂ¡i</translation>
<translation id="7813600968533626083">XĂ³a Ä‘á» xuất biểu mẫu khá»i Chrome?</translation>
+<translation id="7815407501681723534">ÄĂ£ tìm thấy <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> cho '<ph name="SEARCH_STRING" />'</translation>
<translation id="785549533363645510">Tuy nhiĂªn, bạn khĂ´ng ẩn. Việc chuyển sang chế Ä‘á»™ ẩn danh sẽ khĂ´ng ẩn thao tĂ¡c duyệt của bạn vá»›i chủ lao Ä‘á»™ng, nhĂ  cung cấp dịch vụ internet hoặc cĂ¡c trang web bạn truy cập.</translation>
<translation id="7887683347370398519">Kiểm tra CVC của bạn vĂ  thá»­ lại</translation>
<translation id="7894616681410591072">Rất tiếc! Bạn cần sá»± cho phĂ©p của <ph name="NAME" /> để truy cập trang nĂ y.</translation>
-<translation id="790025292736025802">KhĂ´ng tìm thấy <ph name="URL" /></translation>
<translation id="7912024687060120840">Trong thư mục:</translation>
<translation id="7920092496846849526">Bạn Ä‘Ă£ há»i cha mẹ mình xem cĂ³ thể truy cập vĂ o trang nĂ y hay khĂ´ng.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@ LÆ°u Ă½! Chế Ä‘á»™ ẩn danh <ph name="SHORTCUT_KEY" /> cĂ³ thể hữu Ă­ch v
<translation id="7995512525968007366">Không chỉ định</translation>
<translation id="8012647001091218357">ChĂºng tĂ´i khĂ´ng thể liĂªn lạc vá»›i cha mẹ của bạn vĂ o thá»i Ä‘iểm nĂ y. Vui lĂ²ng thá»­ lại.</translation>
<translation id="8034522405403831421">Trang nĂ y cĂ³ ngĂ´n ngữ lĂ  <ph name="SOURCE_LANGUAGE" />. Dịch trang nĂ y sang <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8034955203865359138">KhĂ´ng tìm thấy mục nhập lịch sá»­ nĂ o.</translation>
<translation id="8088680233425245692">KhĂ´ng xem được bĂ i viết.</translation>
+<translation id="8089520772729574115">dÆ°á»›i 1 MB</translation>
<translation id="8091372947890762290">KĂ­ch hoạt Ä‘ang chá» xá»­ lĂ½ trĂªn mĂ¡y chủ</translation>
+<translation id="8129262335948759431">số lượng khĂ´ng xĂ¡c định</translation>
<translation id="8131740175452115882">XĂ¡c nhận</translation>
<translation id="8134994873729925007">KhĂ´ng thể tìm thấy <ph name="BEGIN_ABBR" />địa chỉ DNS<ph name="END_ABBR" /> của mĂ¡y chủ của <ph name="HOST_NAME" />.</translation>
<translation id="8149426793427495338">MĂ¡y tĂ­nh của bạn Ä‘Ă£ chuyển sang chế Ä‘á»™ ngủ.</translation>
@@ -604,6 +640,7 @@ LÆ°u Ă½! Chế Ä‘á»™ ẩn danh <ph name="SHORTCUT_KEY" /> cĂ³ thể hữu Ă­ch v
<translation id="8201077131113104583">URL cập nhật khĂ´ng hợp lệ cho tiện Ă­ch cĂ³ ID "<ph name="EXTENSION_ID" />".</translation>
<translation id="8218327578424803826">Vị trĂ­ được gĂ¡n:</translation>
<translation id="8225771182978767009">NgÆ°á»i thiết lập mĂ¡y tĂ­nh nĂ y Ä‘Ă£ chá»n chặn trang web nĂ y.</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">Trang mĂ  bạn Ä‘ang tìm sá»­ dụng thĂ´ng tin bạn Ä‘Ă£ nhập vĂ o. Việc quay lại trang Ä‘Ă³ cĂ³ thể lặp lại bất kỳ tĂ¡c vụ nĂ o bạn Ä‘Ă£ thá»±c hiện. Bạn cĂ³ muốn tiếp tục khĂ´ng?</translation>
<translation id="8249320324621329438">Tìm nạp lần cuối:</translation>
<translation id="8261506727792406068">XĂ³a</translation>
@@ -616,12 +653,17 @@ LÆ°u Ă½! Chế Ä‘á»™ ẩn danh <ph name="SHORTCUT_KEY" /> cĂ³ thể hữu Ă­ch v
<translation id="8349305172487531364">Thanh dấu trang</translation>
<translation id="8363502534493474904">Tắt chế Ä‘á»™ trĂªn mĂ¡y bay</translation>
<translation id="8364627913115013041">Chưa được đặt.</translation>
+<translation id="8380941800586852976">Nguy hiểm</translation>
<translation id="8412145213513410671">Sự cố (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Bạn phải nhập cĂ¹ng má»™t cụm mật khẩu hai lần.</translation>
<translation id="8428213095426709021">CĂ i đặt</translation>
+<translation id="8433057134996913067">Thao tĂ¡c nĂ y sẽ đăng xuất bạn khá»i hầu hết cĂ¡c trang web.</translation>
<translation id="8437238597147034694">&amp;HoĂ n tĂ¡c di chuyển</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 thẻ tĂ­n dụng}other{# thẻ tĂ­n dụng}}</translation>
+<translation id="8483780878231876732">Äể sá»­ dụng thẻ từ TĂ i khoản Google, hĂ£y đăng nhập vĂ o Chrome</translation>
<translation id="8488350697529856933">Ăp dụng cho</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> mất quĂ¡ nhiá»u thá»i gian để phản hồi.</translation>
+<translation id="852346902619691059">MĂ¡y chủ nĂ y khĂ´ng chứng minh được rằng Ä‘Ă³ lĂ  <ph name="DOMAIN" />; chứng chỉ bảo mật của mĂ¡y chủ nĂ y khĂ´ng được hệ Ä‘iá»u hĂ nh của thiết bị tin tưởng. Äiá»u nĂ y cĂ³ thể do cấu hình sai hoặc cĂ³ kẻ tấn cĂ´ng chặn kết nối của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thĂªm<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="8530504477309582336">Google Payments khĂ´ng há»— trợ loại thẻ nĂ y. Vui lĂ²ng chá»n thẻ khĂ¡c.</translation>
<translation id="8550022383519221471">Dịch vụ đồng bá»™ hĂ³a khĂ´ng khả dụng cho tĂªn miá»n của bạn.</translation>
<translation id="8553075262323480129">Dịch thất bại do ngĂ´n ngữ của trang khĂ´ng được xĂ¡c định.</translation>
@@ -633,15 +675,12 @@ LÆ°u Ă½! Chế Ä‘á»™ ẩn danh <ph name="SHORTCUT_KEY" /> cĂ³ thể hữu Ă­ch v
<translation id="8647750283161643317">Äặt lại tất cả vá» mặc định</translation>
<translation id="8680787084697685621">Chi tiết đăng nhập tĂ i khoản Ä‘Ă£ lá»—i thá»i.</translation>
<translation id="8703575177326907206">Kết nối của bạn đến <ph name="DOMAIN" /> khĂ´ng được mĂ£ hĂ³a.</translation>
-<translation id="8713130696108419660">Chữ kĂ½ ban đầu khĂ´ng hợp lệ</translation>
<translation id="8725066075913043281">Thử lại</translation>
<translation id="8728672262656704056">Bạn Ä‘Ă£ truy cập ẩn danh</translation>
<translation id="8730621377337864115">HoĂ n tất</translation>
<translation id="8738058698779197622">Äể thiết lập kết nối an toĂ n, bạn cần đặt thá»i gian Ä‘Ăºng cho đồng hồ. NguyĂªn nhĂ¢n lĂ  do chứng chỉ mĂ  cĂ¡c trang web dĂ¹ng để tá»± nhận dạng chỉ cĂ³ hiệu lá»±c trong khoảng thá»i gian cụ thể. Vì đồng hồ trĂªn thiết bị của bạn khĂ´ng Ä‘Ăºng nĂªn Chromium khĂ´ng thể xĂ¡c minh cĂ¡c chứng chỉ nĂ y.</translation>
<translation id="8740359287975076522">KhĂ´ng thể tìm thấy &lt;abbr id="dnsDefinition"&gt;địa chỉ DNS&lt;/abbr&gt; của <ph name="HOST_NAME" />. Äang chẩn Ä‘oĂ¡n sá»± cố.</translation>
-<translation id="8741995161408053644">TĂ i khoản Google cĂ³ thể cĂ³ cĂ¡c biểu mẫu lịch sá»­ duyệt web khĂ¡c tại <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" />.</translation>
<translation id="8790007591277257123">&amp;LĂ m lại xĂ³a</translation>
-<translation id="8790687370365610530">Äể nhận ná»™i dung được cĂ¡ nhĂ¢n hĂ³a do Google Ä‘á» xuất, bật đồng bá»™ hĂ³a lịch sá»­.</translation>
<translation id="8798099450830957504">Mặc định</translation>
<translation id="8804164990146287819">ChĂ­nh sĂ¡ch bảo mật</translation>
<translation id="8820817407110198400">Dấu trang</translation>
@@ -663,13 +702,11 @@ LÆ°u Ă½! Chế Ä‘á»™ ẩn danh <ph name="SHORTCUT_KEY" /> cĂ³ thể hữu Ă­ch v
<translation id="8971063699422889582">Chứng chỉ của mĂ¡y chủ Ä‘Ă£ hết hạn.</translation>
<translation id="8987927404178983737">ThĂ¡ng</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">MĂ¡y chủ Ä‘Ă£ Ä‘Æ°a ra chứng chỉ khĂ´ng được tiết lá»™ cĂ´ng khai theo chĂ­nh sĂ¡ch TĂ­nh minh bạch của chứng chỉ. ÄĂ¢y lĂ  yĂªu cầu đối vá»›i má»™t số chứng chỉ, để đảm bảo chĂºng Ä‘Ă¡ng tin cậy vĂ  giĂºp chống lại những kẻ tấn cĂ´ng.</translation>
<translation id="9001074447101275817">Proxy <ph name="DOMAIN" /> yĂªu cầu tĂªn ngÆ°á»i dĂ¹ng vĂ  mật khẩu.</translation>
<translation id="901974403500617787">Chỉ chủ sở hữu má»›i cĂ³ thể đặt cá» Ă¡p dụng cho toĂ n hệ thống: <ph name="OWNER_EMAIL" />.</translation>
<translation id="9020542370529661692">Trang nĂ y Ä‘Ă£ được dịch sang <ph name="TARGET_LANGUAGE" /></translation>
-<translation id="9038649477754266430">Sá»­ dụng dịch vụ truy vấn dá»± Ä‘oĂ¡n để tải trang nhanh hÆ¡n</translation>
+<translation id="9038649477754266430">Sá»­ dụng dịch vụ gợi Ă½ để tải trang nhanh hÆ¡n</translation>
<translation id="9039213469156557790">NgoĂ i ra, trang nĂ y bao gồm cĂ¡c tĂ i nguyĂªn khĂ¡c khĂ´ng an toĂ n. Những tĂ i nguyĂªn nĂ y cĂ³ thể bị ngÆ°á»i khĂ¡c xem khi Ä‘ang gá»­i vĂ  cĂ³ thể bị kẻ tấn cĂ´ng sá»­a đổi nhằm thay đổi hĂ nh vi của trang.</translation>
-<translation id="9049981332609050619">Bạn Ä‘Ă£ cố truy cập vĂ o <ph name="DOMAIN" />, nhÆ°ng mĂ¡y chủ cho biết chứng chỉ khĂ´ng hợp lệ.</translation>
<translation id="9050666287014529139">Cụm mật khẩu</translation>
<translation id="9065203028668620118">Chỉnh sửa</translation>
<translation id="9092364396508701805">Trang <ph name="HOST_NAME" /> hiện khĂ´ng hoạt Ä‘á»™ng</translation>
diff --git a/chromium/components/strings/components_strings_zh-CN.xtb b/chromium/components/strings/components_strings_zh-CN.xtb
index 1ec7a9a6764..ce35f875efd 100644
--- a/chromium/components/strings/components_strings_zh-CN.xtb
+++ b/chromium/components/strings/components_strings_zh-CN.xtb
@@ -1,22 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-CN">
+<translation id="1008557486741366299">以åå†è¯´</translation>
<translation id="1015730422737071372">æ供其他详细信æ¯</translation>
<translation id="1032854598605920125">顺时针旋转</translation>
<translation id="1038842779957582377">未知å称</translation>
+<translation id="1053591932240354961">您目å‰æ— æ³•è®¿é—® <ph name="SITE" />,因为此网站å‘é€ç„凭æ®æ˜¯ä¹±ç ï¼ŒGoogle Chrome 无法处ç†ă€‚网络错误和攻击行为é€å¸¸æ˜¯æ‚æ—¶ç„,因此,此网页ç¨åå¯èƒ½å°±ä¼æ¢å¤æ­£å¸¸ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="1055184225775184556">撤消添å (&amp;U)</translation>
<translation id="10614374240317010">一律ä¸ä¿å­˜</translation>
-<translation id="1064422015032085147">托管该网页ç„æœå¡å™¨å¯èƒ½å·²è¶…è´Ÿè·æˆ–正在维æ¤ă€‚
- 为了é¿å…产生过å¤æµé‡ï¼Œè¿›è€Œé˜²æ­¢æƒ…况å˜å¾—更糟,系统已æ‚æ—¶ç¦æ­¢å‘该网å€å‘é€è¯·æ±‚。</translation>
<translation id="106701514854093668">æ¡Œé¢ä¹¦ç­¾</translation>
<translation id="1080116354587839789">适åˆçª—å£å®½åº¦</translation>
+<translation id="1103124106085518534">æ‚时没有新内容</translation>
<translation id="1103523840287552314">总是翻译<ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">选中å,Chrome ä¼å°†æ‚¨ç„信用å¡å‰¯æœ¬å­˜å‚¨åœ¨æ­¤è®¾å¤‡ä¸ï¼Œä»¥å å¿«è¡¨å•å¡«å†™é€Ÿåº¦ă€‚</translation>
+<translation id="1111153019813902504">最近用过ç„书签</translation>
<translation id="1113869188872983271">撤消顺åºè°ƒæ•´(&amp;U)</translation>
+<translation id="1126551341858583091">å ç”¨ç„本地存储空间为 <ph name="CRASH_SIZE" />。</translation>
<translation id="112840717907525620">策略缓存良好</translation>
<translation id="113188000913989374"><ph name="SITE" /> 显示ï¼</translation>
<translation id="1132774398110320017">Chrome自å¨å¡«å……设置…</translation>
-<translation id="1150979032973867961">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯<ph name="DOMAIN" />;您计算机ç„æ“作系统ä¸ä¿¡ä»»å…¶å®‰å…¨è¯ä¹¦ă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误或您ç„è¿æ¥è¢«æ‹¦æˆªäº†ă€‚</translation>
<translation id="1152921474424827756">访问<ph name="URL" />ç„<ph name="BEGIN_LINK" />缓存副本<ph name="END_LINK" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> æ„外终止了è¿æ¥ă€‚</translation>
<translation id="1161325031994447685">é‡æ–°è¿æ¥åˆ° Wi-Fi 网络</translation>
@@ -24,7 +26,8 @@
<translation id="1181037720776840403">删除</translation>
<translation id="1201402288615127009">下一步</translation>
<translation id="1201895884277373915">æ¥è‡ªè¯¥ç½‘ç«™ç„æ›´å¤å†…容</translation>
-<translation id="121201262018556460">您å°è¯•è®¿é—®ç„是 <ph name="DOMAIN" />,但是æœå¡å™¨å‡ºç¤ºç„è¯ä¹¦åŒ…å«å¼±å¯†é’¥ă€‚攻击者å¯èƒ½å·²ç»ç ´è§£äº†ç§é’¥ï¼Œå› æ­¤è¿™å¯èƒ½å¹¶ä¸æ˜¯æ‚¨æƒ³è¦è®¿é—®ç„æœå¡å™¨ï¼ˆæ‚¨å¯èƒ½æ­£åœ¨ä¸æ”»å‡»è€…进行é€ä¿¡ï¼‰ă€‚</translation>
+<translation id="1206967143813997005">åˆå§‹ç­¾åä¸æ­£ç¡®</translation>
+<translation id="1209206284964581585">æ‚æ—¶éè—</translation>
<translation id="1219129156119358924">系统安全</translation>
<translation id="1227224963052638717">æœªçŸ¥æ”¿ç­–ă€‚</translation>
<translation id="1227633850867390598">éè—值</translation>
@@ -45,6 +48,7 @@
<translation id="1426410128494586442">是</translation>
<translation id="1430915738399379752">打å°</translation>
<translation id="1442912890475371290">å°è¯•<ph name="BEGIN_LINK" />访问 <ph name="DOMAIN" /> 中ç„网页<ph name="END_LINK" />ç„行为已é­é˜»æ­¢ă€‚</translation>
+<translation id="1491663344921578213">您目å‰æ— æ³•è®¿é—® <ph name="SITE" />,因为此网站使用了è¯ä¹¦é”å®åŸèƒ½ă€‚网络错误和攻击行为é€å¸¸æ˜¯æ‚æ—¶ç„,因此,此网页ç¨åå¯èƒ½å°±ä¼æ¢å¤æ­£å¸¸ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="1506687042165942984">显示为此页é¢ä¿å­˜ç„å·²çŸ¥è¿‡æ—¶å‰¯æœ¬ă€‚</translation>
<translation id="1519264250979466059">æ„建日期</translation>
<translation id="1549470594296187301">å¿…é¡»å¯ç”¨ JavaScript æ‰èƒ½ä½¿ç”¨æ­¤åŸèƒ½ă€‚</translation>
@@ -59,36 +63,34 @@
<translation id="1644184664548287040">网络é…ç½®æ— æ•ˆï¼Œæ— æ³•å¯¼å…¥ă€‚</translation>
<translation id="1644574205037202324">å†å²è®°å½•</translation>
<translation id="1645368109819982629">åè®®ä¸å—支æŒ</translation>
-<translation id="1655462015569774233">{1,plural, =1{æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯ <ph name="DOMAIN" />;其安全è¯ä¹¦å·²åœ¨æ˜¨å¤©è¿‡æœŸă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或有攻击者拦截了您ç„è¿æ¥ă€‚计算机ç„时钟目å‰å·²è®¾ä¸º <ph name="CURRENT_DATE" />,该设置是å¦æ­£ç¡®ï¼Ÿå¦‚æœä¸æ­£ç¡®ï¼Œè¯·æ›´æ­£ç³»ç»Ÿç„时钟,然å刷新此页é¢ă€‚}other{æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯ <ph name="DOMAIN" />;其安全è¯ä¹¦å·²åœ¨ # 天å‰è¿‡æœŸă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或有攻击者拦截了您ç„è¿æ¥ă€‚计算机ç„时钟目å‰å·²è®¾ä¸º <ph name="CURRENT_DATE" />,该设置是å¦æ­£ç¡®ï¼Ÿå¦‚æœä¸æ­£ç¡®ï¼Œè¯·æ›´æ­£ç³»ç»Ÿç„时钟,然å刷新此页é¢ă€‚}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> é€å¸¸ä¼ä½¿ç”¨å å¯†æ€æœ¯æ¥ä¿æ¤æ‚¨ç„ä¿¡æ¯ă€‚Google Chrome 此次å°è¯•è¿æ¥åˆ° <ph name="SITE" /> 时,此网站å‘å›äº†å¼‚常ç„错误凭æ®ă€‚è¿™å¯èƒ½æ˜¯å› ä¸ºæœ‰æ”»å‡»è€…在试图冒充 <ph name="SITE" />,或 Wi-Fi 登录å±å¹•ä¸­æ–­äº†æ­¤æ¬¡è¿æ¥ă€‚请放心,您ç„ä¿¡æ¯ä»ç„¶æ˜¯å®‰å…¨ç„,因为 Google Chrome å°æœªè¿›è¡Œä»»ä½•æ•°æ®äº¤æ¢ä¾¿åœæ­¢äº†è¿æ¥ă€‚</translation>
<translation id="168841957122794586">æœå¡å™¨è¯ä¹¦åŒ…å«å¼±å å¯†å¯†é’¥ă€‚</translation>
<translation id="1701955595840307032">è·å–æ¨è内容</translation>
-<translation id="1706954506755087368">{1,plural, =1{æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯ <ph name="DOMAIN" />;其安全è¯ä¹¦æ˜å¤©æ‰ä¼ç”Ÿæ•ˆă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或有攻击者拦截了您ç„è¿æ¥ă€‚}other{æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯ <ph name="DOMAIN" />;其安全è¯ä¹¦ # 天åæ‰ä¼ç”Ÿæ•ˆă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或有攻击者拦截了您ç„è¿æ¥ă€‚}}</translation>
<translation id="1710259589646384581">æ“作系统</translation>
<translation id="1734864079702812349">ç¾å›½è¿é€å¡</translation>
<translation id="1734878702283171397">请å°è¯•è”系系统管ç†å‘˜ă€‚</translation>
<translation id="17513872634828108">ç›®å‰æ‰“å¼€ç„标签页</translation>
<translation id="1753706481035618306">页ç </translation>
-<translation id="1761412452051366565">è¦è·å– Google æ¨èç„个性化内容,请开å¯åŒæ­¥åŸèƒ½ă€‚</translation>
-<translation id="1763864636252898013">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯<ph name="DOMAIN" />;您设备ç„æ“作系统ä¸ä¿¡ä»»å…¶å®‰å…¨è¯ä¹¦ă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误或您ç„è¿æ¥è¢«æ‹¦æˆªäº†ă€‚</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />å°è¯•è¿è¡Œ Windows 网络è¯æ–­<ph name="END_LINK" />。</translation>
<translation id="1783075131180517613">请更新您ç„åŒæ­¥å¯†ç ă€‚</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">您最近访问过ç„ä¹¦ç­¾å°†æ˜¾ç¤ºåœ¨æ­¤å¤„ă€‚</translation>
<translation id="1821930232296380041">请求或请求å‚数无效</translation>
<translation id="1838667051080421715">您正在查看网页ç„æºä»£ç ă€‚</translation>
<translation id="1871208020102129563">代ç†å·²è®¾ç½®ä¸ºä½¿ç”¨å›ºå®ç„代ç†æœå¡å™¨ï¼Œè€Œä¸æ˜¯ .pac è„本网å€ă€‚</translation>
<translation id="1883255238294161206">æ˜å åˆ—表</translation>
<translation id="1898423065542865115">过滤</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> ä¸æ¥å—您ç„登录è¯ä¹¦ï¼Œæˆ–者您ç„登录è¯ä¹¦å¯èƒ½å·²è¿‡æœŸă€‚</translation>
<translation id="194030505837763158">请访问<ph name="LINK" /></translation>
<translation id="1962204205936693436"><ph name="DOMAIN" />书签</translation>
<translation id="1973335181906896915">åºåˆ—化错误</translation>
<translation id="1974060860693918893">高级</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{以åå¦å¤– 1 个应用}other{以åå¦å¤– # 个应用}}</translation>
<translation id="2025186561304664664">代ç†å·²è®¾ä¸ºè‡ªå¨é…ç½®ă€‚</translation>
<translation id="2030481566774242610">您是想访问<ph name="LINK" />å—?</translation>
<translation id="2031925387125903299">您之所以看到这æ¡æ¶ˆæ¯ï¼Œæ˜¯å› ä¸ºæ‚¨ç¬¬ä¸€æ¬¡è®¿é—®æ–°ç„网站时需è¦è·å¾—家长ç„æ‰¹å‡†ă€‚</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />检查代ç†æœå¡å™¨å’Œé˜²ç«å¢™<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">邮编</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 æ¡å»ºè®®}other{# æ¡å»ºè®®}}</translation>
<translation id="2065985942032347596">需è¦è¿›è¡Œèº«ä»½éªŒè¯</translation>
<translation id="2079545284768500474">撤消</translation>
<translation id="20817612488360358">已设置为使用系统代ç†è®¾ç½®ï¼Œä½†åŒæ—¶æŒ‡å®äº†ä¸€ä¸ªæ˜ç¡®ç„代ç†é…ç½®ă€‚</translation>
@@ -104,32 +106,34 @@
<translation id="2149973817440762519">修改书签</translation>
<translation id="2166049586286450108">完全ç„管ç†å‘˜è®¿é—®æƒé™</translation>
<translation id="2166378884831602661">此网站无法æ供安全è¿æ¥</translation>
-<translation id="2171101176734966184">您å°è¯•è®¿é—®ç„是 <ph name="DOMAIN" />,但是æœå¡å™¨å‡ºç¤ºç„è¯ä¹¦æ˜¯ä½¿ç”¨å¼±ç­¾å算法签署ç„ă€‚è¿™æ„味ç€æœå¡å™¨å‡ºç¤ºç„安全凭æ®å¯èƒ½æ˜¯ä¼ªé€ ç„,因此这å¯èƒ½å¹¶ä¸æ˜¯æ‚¨æƒ³è¦è®¿é—®ç„æœå¡å™¨ï¼ˆæ‚¨å¯èƒ½æ­£åœ¨ä¸æ”»å‡»è€…进行é€ä¿¡ï¼‰ă€‚</translation>
<translation id="2181821976797666341">政策</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 个地å€}other{# 个地å€}}</translation>
<translation id="2212735316055980242">找ä¸åˆ°ç­–ç•¥</translation>
<translation id="2213606439339815911">正在è·å–æ¡ç›®â€¦</translation>
-<translation id="2214283295778284209">无法访问 <ph name="SITE" /></translation>
<translation id="2230458221926704099">请使用<ph name="BEGIN_LINK" />è¯æ–­åº”用<ph name="END_LINK" />ä¿®å¤ç½‘络è¿æ¥</translation>
+<translation id="2239100178324503013">ç«‹å³å‘é€</translation>
<translation id="225207911366869382">适用äºè¯¥æ”¿ç­–ç„æ­¤å€¼å·²å¼ƒç”¨ă€‚</translation>
<translation id="2262243747453050782">HTTP 错误</translation>
<translation id="2282872951544483773">无法使用ç„å®éªŒåŸèƒ½</translation>
<translation id="2292556288342944218">您被ç¦æ­¢è®¿é—®äº’è”网</translation>
<translation id="229702904922032456">æ ¹è¯ä¹¦æˆ–中间è¯ä¹¦å·²è¿‡æœŸă€‚</translation>
<translation id="230155334948463882">è¦ä½¿ç”¨æ–°ä¿¡ç”¨å¡å—?</translation>
+<translation id="2305919008529760154">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœå¡å™¨ç„安全è¯ä¹¦é¢å‘æ¥æºæœ‰æ¬ºè¯ˆå«Œç–‘ă€‚å‡ºç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> è¦æ±‚æ供用户å和密ç ă€‚</translation>
+<translation id="2318774815570432836">您目å‰æ— æ³•è®¿é—® <ph name="SITE" />,因为此网站使用了 HSTSă€‚ç½‘ç»œé”™è¯¯å’Œæ”»å‡»è¡Œä¸ºé€å¸¸æ˜¯æ‚æ—¶ç„,因此,此网页ç¨åå¯èƒ½å°±ä¼æ¢å¤æ­£å¸¸ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="2328300916057834155">已忽略索引<ph name="ENTRY_INDEX" />中ç„无效书签</translation>
<translation id="2354001756790975382">其他书签</translation>
<translation id="2359808026110333948">继续</translation>
<translation id="2365563543831475020">äº <ph name="CRASH_TIME" /> è·å–ç„崩溃æ¥å‘未ä¸ä¼ </translation>
<translation id="2367567093518048410">级别</translation>
+<translation id="2371153335857947666">{1,plural, =1{æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœå¡å™¨ç„安全è¯ä¹¦å·²åœ¨æ˜¨å¤©è¿‡æœŸă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚计算机ç„时钟目å‰å·²è®¾ä¸º <ph name="CURRENT_DATE" />,该设置是å¦æ­£ç¡®ï¼Ÿå¦‚æœä¸æ­£ç¡®ï¼Œè¯·æ›´æ­£ç³»ç»Ÿç„时钟,然å刷新此网é¢ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。}other{æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœå¡å™¨ç„安全è¯ä¹¦å·²åœ¨ # 天å‰è¿‡æœŸă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚计算机ç„时钟目å‰å·²è®¾ä¸º <ph name="CURRENT_DATE" />,该设置是å¦æ­£ç¡®ï¼Ÿå¦‚æœä¸æ­£ç¡®ï¼Œè¯·æ›´æ­£ç³»ç»Ÿç„时钟,然å刷新此网é¢ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。}}</translation>
<translation id="237718015863234333">没有å¯ç”¨ç„ç•Œé¢å¤‡é€‰é¡¹</translation>
<translation id="2384307209577226199">在ä¼ä¸ç¯å¢ƒä¸­é»˜è®¤å®æ–½</translation>
-<translation id="238526402387145295">您目å‰æ— æ³•è®¿é—®<ph name="SITE" />,因为此网站<ph name="BEGIN_LINK" />使用了HSTS<ph name="END_LINK" />ă€‚ç½‘ç»œé”™è¯¯å’Œæ”»å‡»é€å¸¸æ˜¯æ‚æ—¶ç„,因此,此网页ç¨åå¯èƒ½ä¼æ¢å¤æ­£å¸¸ă€‚</translation>
<translation id="2386255080630008482">æœå¡å™¨ç„è¯ä¹¦å·²æ’¤æ¶ˆă€‚</translation>
<translation id="2392959068659972793">显示未设å®å€¼ç„政策</translation>
<translation id="2396249848217231973">撤消删除(&amp;U)</translation>
-<translation id="2413528052993050574">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯<ph name="DOMAIN" />;其安全è¯ä¹¦å¯èƒ½å·²è¢«æ’¤æ¶ˆă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误或您ç„è¿æ¥è¢«æ‹¦æˆªäº†ă€‚</translation>
<translation id="2455981314101692989">该网页已对该表å•åœç”¨è‡ªå¨å¡«å……åŸèƒ½ă€‚</translation>
+<translation id="2463739503403862330">å¡«å……</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />è¿è¡Œç½‘络è¯æ–­<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">æœç´¢ç½‘å€æ— æ•ˆă€‚</translation>
<translation id="2491120439723279231">æœå¡å™¨è¯ä¹¦ä¸­åŒ…å«é”™è¯¯ă€‚</translation>
@@ -151,10 +155,12 @@
<translation id="2653659639078652383">æ交</translation>
<translation id="2674170444375937751">ç¡®å®è¦ä»å†å²è®°å½•ä¸­åˆ é™¤è¿™äº›é¡µå—?</translation>
<translation id="2677748264148917807">离开</translation>
+<translation id="269990154133806163">该æœå¡å™¨æä¾›ç„è¯ä¹¦æœªæ ¹æ®è¯ä¹¦é€æ˜åº¦æ”¿ç­–公开æ«éœ²ă€‚部分è¯ä¹¦å¿…须符åˆè¿™é¡¹è§„å®ï¼Œä»¥ç¡®ä¿è¯ä¹¦å€¼å¾—信任,并ä¿æ¤ç”¨æˆ·ä¸ä¼é­åˆ°æ”»å‡»ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="2704283930420550640">值ä¸ç¬¦åˆæ ¼å¼è¦æ±‚。</translation>
<translation id="2704951214193499422">Chromium ç›®å‰æ— æ³•ç¡®è®¤æ‚¨ç„信用å¡ï¼Œè¯·ç¨åé‡è¯•ă€‚</translation>
<translation id="2705137772291741111">无法读å–此网站ç„å·²ä¿å­˜ï¼ˆç¼“å­˜ï¼‰å‰¯æœ¬ă€‚</translation>
<translation id="2709516037105925701">自å¨å¡«å……</translation>
+<translation id="2712118517637785082">您å°è¯•è¿æ¥åˆ° <ph name="DOMAIN" />,但æœå¡å™¨æä¾›ç„è¯ä¹¦å·²è¢«å…¶é¢å‘è€…æ’¤æ¶ˆă€‚åœ¨è¿™ç§æƒ…况下,请勿信任æœå¡å™¨æä¾›ç„安全凭æ®ă€‚您å¯èƒ½æ­£åœ¨ä¸æ”»å‡»è€…进行é€ä¿¡ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="2712173769900027643">请求批准</translation>
<translation id="2721148159707890343">请求æˆåŸ</translation>
<translation id="2728127805433021124">æœå¡å™¨ç„è¯ä¹¦æ˜¯ä½¿ç”¨å¼±ç­¾å算法进行签åç„。</translation>
@@ -166,14 +172,11 @@
<translation id="2824775600643448204">地å€å’Œæœç´¢æ </translation>
<translation id="2826760142808435982">该è¿æ¥ä½¿ç”¨ <ph name="CIPHER" /> 进行å å¯†å’Œèº«ä»½éªŒè¯ï¼Œå¹¶ä½¿ç”¨ <ph name="KX" /> 作为密钥交æ¢æœºåˆ¶ă€‚</translation>
<translation id="2835170189407361413">清除表å•</translation>
-<translation id="2837049386027881519">æ­¤è¿æ¥å¿…é¡»ä½¿ç”¨è¾ƒæ—§ç‰ˆæœ¬ç„ TLS 或 SSL åè®®é‡è¯•ï¼Œè¿™é€å¸¸æ„味ç€è¯¥æœå¡å™¨ä½¿ç”¨ç„软件版本过ä½æˆ–者å¯èƒ½å­˜åœ¨å…¶ä»–å®‰å…¨é—®é¢˜ă€‚</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> ä¸ç„æœå¡å™¨è¯ä¹¦ä¼¼ä¹æ˜¯ä¼ªé€ ç„。</translation>
<translation id="2889159643044928134">ä¸é‡æ–°å è½½</translation>
-<translation id="2896499918916051536">ä¸æ”¯æŒè¯¥æ’件。</translation>
+<translation id="2900469785430194048">Google Chrome 在å°è¯•æ˜¾ç¤ºæ­¤ç½‘页时内存ä¸è¶³ă€‚</translation>
<translation id="2909946352844186028">检测到了网络å˜åŒ–。</translation>
-<translation id="2915500479781995473">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯<ph name="DOMAIN" />;其安全è¯ä¹¦å·²è¿‡æœŸă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误或您ç„è¿æ¥è¢«æ‹¦æˆªäº†ă€‚计算机ç„时钟目å‰å·²è®¾ä¸º<ph name="CURRENT_TIME" />,该设置是å¦æ­£ç¡®ï¼Ÿå¦‚æœä¸æ­£ç¡®ï¼Œè¯·æ›´æ­£ç³»ç»Ÿç„时钟,然å刷新此页é¢ă€‚</translation>
<translation id="2922350208395188000">无法核å®æœå¡å™¨è¯ä¹¦ă€‚</translation>
-<translation id="2941952326391522266">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯<ph name="DOMAIN" />;其安全è¯ä¹¦æ¥è‡ª<ph name="DOMAIN2" />ă€‚å‡ºç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误或您ç„è¿æ¥è¢«æ‹¦æˆªäº†ă€‚</translation>
<translation id="2948083400971632585">您å¯ä»¥åœ¨è®¾ç½®é¡µé¢ä¸­åœç”¨ä»»ä½•é’ˆå¯¹æŸä¸ªè¿æ¥é…ç½®ç„代ç†ă€‚</translation>
<translation id="2955913368246107853">关闭查找æ </translation>
<translation id="2958431318199492670">网络é…ç½®ä¸ç¬¦åˆ ONC æ ‡å‡†ă€‚æ— æ³•å¯¼å…¥é…ç½®ç„æŸäº›éƒ¨åˆ†ă€‚</translation>
@@ -187,6 +190,7 @@
<translation id="3024663005179499861">策略类å‹æœ‰è¯¯</translation>
<translation id="3032412215588512954">è¦é‡æ–°å è½½è¯¥ç½‘ç«™å—?</translation>
<translation id="3037605927509011580">喔唷,崩溃啦ï¼</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{在已åŒæ­¥ç„设备ä¸è‡³å°‘有 1 项内容}=1{1 项内容(在已åŒæ­¥ç„设备ä¸è¿˜æœ‰æ›´å¤å†…容)}other{# 项内容(在已åŒæ­¥ç„设备ä¸è¿˜æœ‰æ›´å¤å†…容)}}</translation>
<translation id="3041612393474885105">è¯ä¹¦ä¿¡æ¯</translation>
<translation id="3063697135517575841">Chrome ç›®å‰æ— æ³•ç¡®è®¤æ‚¨ç„信用å¡ï¼Œè¯·ç¨åé‡è¯•ă€‚</translation>
<translation id="3093245981617870298">您处äºç¦»çº¿ç¶æ€ă€‚</translation>
@@ -203,15 +207,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">最å</translation>
<translation id="3207960819495026254">å·²å ä¹¦ç­¾</translation>
-<translation id="3225919329040284222">æœå¡å™¨æä¾›ç„è¯ä¹¦ä¸å†…置预期è¯ä¹¦ä¸åŒ¹é…ă€‚è¿™äº›é¢„æœŸè¯ä¹¦æ˜¯é’ˆå¯¹æŸäº›é«˜å®‰å…¨æ€§ç½‘ç«™æä¾›ç„,以便为您æä¾›ä¿æ¤ă€‚</translation>
<translation id="3226128629678568754">按“é‡æ–°å è½½â€æŒ‰é’®ï¼Œé‡æ–°æ交å è½½è¯¥ç½‘页所需ç„æ•°æ®ă€‚</translation>
<translation id="3228969707346345236">此网页已ç»æ˜¯<ph name="LANGUAGE" />ç½‘é¡µï¼Œå› æ­¤æ— æ³•ç¿»è¯‘ă€‚</translation>
<translation id="323107829343500871">输入“<ph name="CREDIT_CARD" />â€ç„银行å¡éªŒè¯ç  (CVC)</translation>
<translation id="3254409185687681395">为此页添å ä¹¦ç­¾</translation>
<translation id="3270847123878663523">撤消顺åºè°ƒæ•´(&amp;U)</translation>
<translation id="3286538390144397061">ç«‹å³é‡æ–°å¯å¨</translation>
+<translation id="3303855915957856445">未找到任何æœç´¢ç»“æœ</translation>
<translation id="3305707030755673451">您ç„æ•°æ®å·²äº <ph name="TIME" />使用您ç„åŒæ­¥å¯†ç å å¯†ă€‚输入该密ç å³å¯å¼€å§‹åŒæ­¥ă€‚</translation>
<translation id="333371639341676808">ç¦æ­¢æ­¤é¡µå†æ˜¾ç¤ºå¯¹è¯æ¡†ă€‚</translation>
+<translation id="3338095232262050444">安全</translation>
<translation id="3340978935015468852">设置</translation>
<translation id="3345135638360864351">无法将您访问此网站ç„请求å‘é€ç»™<ph name="NAME" />,请é‡è¯•ă€‚</translation>
<translation id="3355823806454867987">更改代ç†æœå¡å™¨è®¾ç½®...</translation>
@@ -229,6 +234,7 @@
<translation id="3452404311384756672">æ“å–时间间é”ï¼</translation>
<translation id="3462200631372590220">éè—详情</translation>
<translation id="3479539252931486093">ä¸åº”该出ç°è¿™ç§æƒ…况?请<ph name="BEGIN_LINK" />å‘诉我们<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">以åå†è¯´</translation>
<translation id="348000606199325318">崩溃 IDï¼<ph name="CRASH_LOCAL_ID" />(æœå¡å™¨ IDï¼<ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">我们æ‚时无法ä¸æ‚¨çˆ¶æ¯å–å¾—è”系,请é‡è¯•ă€‚</translation>
<translation id="3527085408025491307">文件夹</translation>
@@ -237,6 +243,7 @@
<translation id="3542684924769048008">使用以下项ç„密ç ï¼</translation>
<translation id="3549644494707163724">使用您自己ç„åŒæ­¥å¯†ç å å¯†æ‰€æœ‰å·²åŒæ­¥æ•°æ®</translation>
<translation id="3549761410225185768">还有 <ph name="NUM_TABS_MORE" /> 个…</translation>
+<translation id="3555561725129903880">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœå¡å™¨ç„安全è¯ä¹¦æ¥è‡ª <ph name="DOMAIN2" />ă€‚å‡ºç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="3566021033012934673">您ç„è¿æ¥ä¸æ˜¯ç§å¯†è¿æ¥</translation>
<translation id="3583757800736429874">æ¢å¤ç§»å¨(&amp;R)</translation>
<translation id="3586931643579894722">éè—详细信æ¯</translation>
@@ -247,12 +254,15 @@
<translation id="362276910939193118">显示所有å†å²è®°å½•</translation>
<translation id="3623476034248543066">显示值</translation>
<translation id="3630155396527302611">如æœå®ƒå·²åœ¨å¯è®¿é—®ç½‘络ç„程åºåˆ—表中,请å°è¯•å°†å®ƒä»è¯¥åˆ—表中移除,然åé‡æ–°æ·»å åˆ°å…¶ä¸­ă€‚</translation>
+<translation id="3638794133396384728">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœå¡å™¨ç„安全è¯ä¹¦å·²è¿‡æœŸă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚计算机ç„时钟目å‰å·²è®¾ä¸º <ph name="CURRENT_TIME" />,该设置是å¦æ­£ç¡®ï¼Ÿå¦‚æœä¸æ­£ç¡®ï¼Œè¯·æ›´æ­£ç³»ç»Ÿç„时钟,然ååˆ·æ–°æ­¤ç½‘é¡µă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="3648607100222897006">这些å®éªŒæ€§åŸèƒ½éæ—¶å¯èƒ½ä¼æ›´æ”¹ă€ä¸­æ­¢æˆ–å–æ¶ˆă€‚å› æ­¤ï¼Œæˆ‘ä»¬å®Œå…¨æ— æ³•ä¿è¯æ‚¨å¯ç”¨æŸé¡¹å®éªŒæ€§åŸèƒ½åä¼å‘生什么情况,您ç„æµè§ˆå™¨ç”至å¯èƒ½ä¼è‡ªå¨å´©æºƒă€‚请注æ„,您ç„æµè§ˆå™¨å¯èƒ½ä¼åˆ é™¤æ‚¨ç„所有数æ®ï¼Œæ‚¨ç„安全和éç§ä¹Ÿæœ‰å¯èƒ½å—到æ„å¤–ä¼¤å®³ă€‚æ‚¨å¯ç”¨ç„所有å®éªŒæ€§åŸèƒ½å°†ç”¨äºæ­¤æµè§ˆå™¨ç„æ‰€æœ‰ç”¨æˆ·ă€‚å¯ç”¨å‰ï¼Œè¯·å¡å¿…三æ€ă€‚</translation>
<translation id="3650584904733503804">验è¯æˆåŸ</translation>
<translation id="3655670868607891010">如æœæ‚¨é¢‘ç¹é‡åˆ°æ­¤é—®é¢˜ï¼Œè¯·å°è¯•è¿™äº›<ph name="HELP_LINK" />。</translation>
<translation id="3658742229777143148">修订版本</translation>
+<translation id="3678029195006412963">无法签署该请求</translation>
<translation id="3681007416295224113">è¯ä¹¦ä¿¡æ¯</translation>
<translation id="3693415264595406141">密ç ï¼</translation>
+<translation id="3696411085566228381">æ— </translation>
<translation id="3700528541715530410">糟糕,您似ä¹æ²¡æœ‰è®¿é—®æ­¤é¡µé¢ç„æƒé™ă€‚</translation>
<translation id="3704609568417268905"><ph name="TIME" /> - <ph name="BOOKMARKED" /> - <ph name="TITLE" /> - <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">正在å è½½...</translation>
@@ -260,7 +270,6 @@
<translation id="3714780639079136834">å¼€å¯ç§»å¨æ•°æ®ç½‘络或 Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />检查代ç†æœå¡å™¨ă€é˜²ç«å¢™å’Œ DNS é…ç½®<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">您å¤åˆ¶ç„链æ¥</translation>
-<translation id="3744899669254331632">您目å‰æ— æ³•è®¿é—® <ph name="SITE" />,因为此网站å‘é€äº† Chromium 无法处ç†ç„æ‚乱凭æ®ă€‚网络错误和攻击é€å¸¸æ˜¯æ‚æ—¶ç„,因此,此网页ç¨åå¯èƒ½ä¼æ¢å¤æ­£å¸¸ă€‚</translation>
<translation id="375403751935624634">ç”±äºæœå¡å™¨å‡ºé”™ï¼Œç¿»è¯‘å¤±è´¥ă€‚</translation>
<translation id="3759461132968374835">您最近未收到崩溃æ¥å‘ă€‚å´©æºƒæ¥å‘åœç”¨æ—¶å‘生ç„崩溃ä¸ä¼åœ¨æ­¤å¤„æ˜¾ç¤ºă€‚</translation>
<translation id="3788090790273268753">此网站ç„è¯ä¹¦å°†äº 2016 年过期,并且此网站ç„è¯ä¹¦é“¾åŒ…å«ä½¿ç”¨ SHA-1 签署ç„è¯ä¹¦ă€‚</translation>
@@ -272,19 +281,25 @@
<translation id="3884278016824448484">设备标识符存在冲çª</translation>
<translation id="3885155851504623709">区</translation>
<translation id="3901925938762663762">此信用å¡å·²è¿‡æœŸ</translation>
+<translation id="3910267023907260648">您å°è¯•è¿æ¥åˆ° <ph name="DOMAIN" />,但æœå¡å™¨æä¾›ç„è¯ä¹¦æ˜¯ä½¿ç”¨é˜²æ¤å›è–„å¼±ç„ç­¾å算法进行签署ç„ă€‚è¿™æ„味ç€æœå¡å™¨æä¾›ç„安全凭æ®å¯èƒ½æ˜¯ä¼ªé€ ç„,而且这个æœå¡å™¨å¯èƒ½å¹¶ä¸æ˜¯æ‚¨æƒ³è¦è®¿é—®ç„æœå¡å™¨ï¼ˆæ‚¨å¯èƒ½æ­£åœ¨ä¸æ”»å‡»è€…进行é€ä¿¡ï¼‰ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
+<translation id="3933571093587347751">{1,plural, =1{æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœå¡å™¨ç„安全è¯ä¹¦å¤§æ¦‚æ˜å¤©æ‰ä¼ç”Ÿæ•ˆă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。}other{æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœå¡å™¨ç„安全è¯ä¹¦å¤§æ¦‚ # 天åæ‰ä¼ç”Ÿæ•ˆă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。}}</translation>
<translation id="3934680773876859118">无法å è½½ PDF 文档</translation>
<translation id="3963721102035795474">阅读器模å¼</translation>
+<translation id="397105322502079400">正在计算...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> 已被å±è”½</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{附近有 1 个网页}other{附近有 # 个网页}}</translation>
<translation id="4021036232240155012">DNS 是一项网络æœå¡ï¼Œå¯å°†ç½‘ç«™ç„å称转译为其对应ç„互è”网地å€ă€‚</translation>
<translation id="4030383055268325496">撤消添å (&amp;U)</translation>
-<translation id="4032534284272647190"><ph name="URL" /> æ‹’ç»è®¿é—®ă€‚</translation>
<translation id="404928562651467259">è­¦å‘</translation>
<translation id="4058922952496707368">“<ph name="SUBKEY" />â€é”®ï¼<ph name="ERROR" /></translation>
<translation id="4075732493274867456">客户端和æœå¡å™¨ä¸æ”¯æŒä¸€èˆ¬ SSL å议版本或å å¯†å¥—件。</translation>
<translation id="4079302484614802869">代ç†é…置已设置为使用 .pac è„本网å€ï¼Œè€Œä¸æ˜¯å›ºå®ç„代ç†æœå¡å™¨ă€‚</translation>
<translation id="4103249731201008433">设备åºåˆ—å·æ— æ•ˆ</translation>
<translation id="4103763322291513355">请访问 &lt;strong&gt;chrome:// 政策&lt;/strong&gt;,查看列入黑åå•ç„网å€åˆ—表以å您ç„系统管ç†å‘˜å¼ºåˆ¶è¦æ±‚执行ç„å…¶ä»–æ”¿ç­–ă€‚</translation>
+<translation id="4110615724604346410">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœå¡å™¨ç„安全è¯ä¹¦æœ‰è¯¯ă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="4117700440116928470">政策范围ä¸å—支æŒă€‚</translation>
+<translation id="4118212371799607889">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›Chromium ä¸ä¿¡ä»»æœå¡å™¨ç„安全è¯ä¹¦ă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 项其他内容}other{# 项其他内容}}</translation>
<translation id="4130226655945681476">检查网线ă€è°ƒåˆ¶è§£è°ƒå™¨å’Œè·¯ç”±å™¨</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">您希望 Chromium ä¿å­˜æ­¤ä¿¡ç”¨å¡å—?</translation>
@@ -292,6 +307,7 @@
<translation id="4176463684765177261">å·²åœç”¨</translation>
<translation id="4196861286325780578">æ¢å¤ç§»å¨(&amp;R)</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />检查防ç«å¢™å’Œé˜²ç—…毒é…ç½®<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{æ— }=1{1 个应用 ($1)}=2{2 个应用($1ă€$2)}other{# 个应用($1ă€$2,$3)}}</translation>
<translation id="4220128509585149162">崩溃</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />å°è¯•è¿è¡Œç½‘络è¯æ–­<ph name="END_LINK" />。</translation>
<translation id="4250680216510889253">å¦</translation>
@@ -300,14 +316,15 @@
<translation id="4269787794583293679">(无用户å)</translation>
<translation id="4300246636397505754">家长建议</translation>
<translation id="4304224509867189079">登录</translation>
+<translation id="432290197980158659">该æœå¡å™¨æä¾›ç„è¯ä¹¦ä¸ç¬¦åˆå†…ç½®ç„预期æ¡ä»¶ă€‚我们针对特å®ç„高安全性网站内置了这些预期æ¡ä»¶ï¼Œä»¥ç¡®ä¿æ‚¨ç„æ•°æ®å®‰å…¨æ— è™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="4325863107915753736">找ä¸åˆ°æ–‡ç« </translation>
+<translation id="4331708818696583467">ä¸å®‰å…¨</translation>
<translation id="4372948949327679948">应使用<ph name="VALUE_TYPE" />å€¼ă€‚</translation>
-<translation id="4377125064752653719">您å°è¯•è®¿é—®ç„是 <ph name="DOMAIN" />,但æœå¡å™¨å‡ºç¤ºç„è¯ä¹¦å·²è¢«å…¶é¢å‘者åé”€ă€‚è¿™è¡¨æ˜ç»å¯¹ä¸åº”该信任此æœå¡å™¨å‡ºç¤ºç„安全凭æ®ă€‚您å¯èƒ½æ­£åœ¨ä¸æ”»å‡»è€…进行é€ä¿¡ă€‚</translation>
<translation id="4381091992796011497">用户åï¼</translation>
<translation id="4394049700291259645">åœç”¨</translation>
<translation id="4395129973926795186"><ph name="START_DATE" />至 <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">æœç´¢ç»“æœ</translation>
-<translation id="4424024547088906515">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯<ph name="DOMAIN" />ï¼›Chromeä¸ä¿¡ä»»å…¶å®‰å…¨è¯ä¹¦ă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误或您ç„è¿æ¥è¢«æ‹¦æˆªäº†ă€‚</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> ä¸æ¥å—您ç„登录è¯ä¹¦ï¼Œæˆ–者您å¯èƒ½æ²¡æœ‰æ供登录è¯ä¹¦ă€‚</translation>
<translation id="443673843213245140">å·²åœç”¨ä»£ç†ï¼Œä½†æ˜¯æŒ‡å®äº†æ˜ç¡®ç„代ç†é…ç½®ă€‚</translation>
<translation id="4458874409874303848">SafeSites</translation>
<translation id="4461847750548395463">您之所以看到这æ¡æ¶ˆæ¯ï¼Œæ˜¯å› ä¸º Google SafeSites 处äºå¯ç”¨ç¶æ€ă€‚</translation>
@@ -319,12 +336,12 @@
<translation id="4522570452068850558">详细信æ¯</translation>
<translation id="4558551763791394412">å°è¯•åœç”¨æ‰©å±•ç¨‹åºă€‚</translation>
<translation id="4587425331216688090">ä» Chrome 中移除地å€ï¼Ÿ</translation>
+<translation id="4589078953350245614">您å°è¯•è¿æ¥åˆ° <ph name="DOMAIN" />,但æœå¡å™¨æä¾›ç„è¯ä¹¦æ— æ•ˆă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="4592951414987517459">æ‚¨ä¸ <ph name="DOMAIN" /> 之间ç„è¿æ¥é‡‡ç”¨æ–°å‹å å¯†å¥—件进行了å å¯†ă€‚</translation>
<translation id="4594403342090139922">撤消删除(&amp;U)</translation>
+<translation id="4627442949885028695">é€è¿‡å…¶ä»–设备继续æµè§ˆ</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">您正在查看ç„是扩展程åºé¡µé¢ă€‚</translation>
-<translation id="467662567472608290">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯<ph name="DOMAIN" />;其安全è¯ä¹¦æœ‰è¯¯ă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误或您ç„è¿æ¥è¢«æ‹¦æˆªäº†ă€‚</translation>
-<translation id="4697214168136963651">已阻止 <ph name="URL" /></translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /><ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">您ç„è¿æ¥å·²ä¸­æ–­</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />è¿è¡Œ Windows 网络è¯æ–­<ph name="END_LINK" /></translation>
@@ -332,21 +349,26 @@
<translation id="4728558894243024398">å¹³å°</translation>
<translation id="4744603770635761495">å¯æ‰§è¡Œæ–‡ä»¶è·¯å¾„</translation>
<translation id="4756388243121344051">å†å²è®°å½•(&amp;H)</translation>
+<translation id="4759238208242260848">下载内容</translation>
<translation id="4764776831041365478">网å€ä¸º <ph name="URL" /> ç„网页å¯èƒ½æ‚时无法è¿æ¥ï¼Œæˆ–者它已永久性地移å¨åˆ°äº†æ–°ç½‘å€ă€‚</translation>
<translation id="4771973620359291008">å‘ç”ŸæœªçŸ¥é”™è¯¯ă€‚</translation>
<translation id="4782449893814226250">å·²å‘您父æ¯æ出å…许您访问此网页ç„è¯·æ±‚ă€‚</translation>
<translation id="4800132727771399293">请检查您ç„到期日期和银行å¡éªŒè¯ç  (CVC),然åé‡è¯•</translation>
-<translation id="4807049035289105102">您目å‰æ— æ³•è®¿é—® <ph name="SITE" />,因为此网站å‘é€äº† Google Chrome 无法处ç†ç„æ‚乱凭æ®ă€‚网络错误和攻击é€å¸¸æ˜¯æ‚æ—¶ç„,因此,此网页ç¨åå¯èƒ½ä¼æ¢å¤æ­£å¸¸ă€‚</translation>
<translation id="4813512666221746211">网络错误</translation>
<translation id="4816492930507672669">适åˆé¡µé¢å¤§å°</translation>
<translation id="4850886885716139402">视图</translation>
<translation id="4880827082731008257">æœç´¢å†å²è®°å½•</translation>
+<translation id="4884656795097055129">系统ä¼é€‚时显示更å¤æ–‡ç« ă€‚</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />ă€<ph name="TYPE_2" />ă€<ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{å’Œå¦å¤– 1 个网页}other{å’Œå¦å¤– # 个网页}}</translation>
<translation id="4923417429809017348">翻译æœå¡å™¨å·²å°†æ­¤ç½‘页ä»æŸç§æœªçŸ¥è¯­è¨€ç¿»è¯‘æˆäº†<ph name="LANGUAGE_LANGUAGE" />。</translation>
<translation id="4926049483395192435">必须指å®ă€‚</translation>
<translation id="4930497775425430760">您之所以看到这æ¡æ¶ˆæ¯ï¼Œæ˜¯å› ä¸ºæ‚¨ç¬¬ä¸€æ¬¡è®¿é—®æ–°ç„网站时需è¦è·å¾—家长ç„æ‰¹å‡†ă€‚</translation>
<translation id="495170559598752135">æ“作</translation>
<translation id="4958444002117714549">展开列表</translation>
+<translation id="4962322354953122629">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›Chrome ä¸ä¿¡ä»»æœå¡å™¨ç„安全è¯ä¹¦ă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="498957508165411911">是å¦å°†<ph name="ORIGINAL_LANGUAGE" />翻译æˆ<ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">该æ’件ä¸å—支æŒ</translation>
<translation id="5002932099480077015">如æœæ‚¨é€‰ä¸­æ­¤é¡¹ï¼ŒChrome ä¼å°†æ‚¨ç„å¡ç„副本存储在此设备ä¸ï¼Œä»¥å å¿«è¡¨å•å¡«å†™é€Ÿåº¦ă€‚</translation>
<translation id="5019198164206649151">å备存储ç¶æ€ä¸ä½³</translation>
<translation id="5023310440958281426">请查看管ç†å‘˜åˆ¶å®ç„政策</translation>
@@ -354,13 +376,12 @@
<translation id="5031870354684148875">å…³äº Google 翻译</translation>
<translation id="5040262127954254034">éç§è®¾ç½®</translation>
<translation id="5045550434625856497">密ç ä¸æ­£ç¡®</translation>
+<translation id="5056549851600133418">为您æ¨èç„文章</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />检查代ç†æœå¡å™¨åœ°å€<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">æœå¡å™¨ç„è¯ä¹¦ç›®å‰æ— æ•ˆă€‚</translation>
<translation id="5089810972385038852">å·</translation>
-<translation id="5094747076828555589">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯<ph name="DOMAIN" />ï¼›Chromiumä¸ä¿¡ä»»å…¶å®‰å…¨è¯ä¹¦ă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误或您ç„è¿æ¥è¢«æ‹¦æˆªäº†ă€‚</translation>
<translation id="5095208057601539847">çœ</translation>
<translation id="5115563688576182185">(64 ä½ï¼‰</translation>
-<translation id="5122371513570456792">找到了 <ph name="NUMBER_OF_RESULTS" /> 个ä¸â€œ<ph name="SEARCH_STRING" />â€ç›¸ç¬¦ç„<ph name="SEARCH_RESULTS" />。</translation>
<translation id="5141240743006678641">ä½¿ç”¨æ‚¨ç„ Google 凭æ®å å¯†å·²åŒæ­¥ç„密ç </translation>
<translation id="5145883236150621069">ç­–ç•¥å“应中存在错误代ç </translation>
<translation id="5171045022955879922">æœç´¢æˆ–输入网å€</translation>
@@ -369,18 +390,18 @@
<translation id="5190835502935405962">书签æ </translation>
<translation id="5199729219167945352">å®éªŒ</translation>
<translation id="5251803541071282808">云端</translation>
+<translation id="5277279256032773186">使用 Chrome å公?ä¼ä¸å¯ä»¥ä¸ºå…¶å‘˜å·¥ç®¡ç† Chrome è®¾ç½®ă€‚äº†è§£è¯¦æƒ…</translation>
<translation id="5299298092464848405">解æ策略时出错</translation>
<translation id="5300589172476337783">显示</translation>
<translation id="5308689395849655368">å·²åœç”¨å´©æºƒæ¥å‘。</translation>
<translation id="5317780077021120954">ä¿å­˜</translation>
<translation id="5327248766486351172">å称</translation>
+<translation id="5359637492792381994">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœå¡å™¨ç„安全è¯ä¹¦ç›®å‰æ— æ•ˆă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="536296301121032821">无法存储策略设置</translation>
-<translation id="540969355065856584">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯ <ph name="DOMAIN" />;其安全è¯ä¹¦ç›®å‰æ— æ•ˆă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误或您ç„è¿æ¥è¢«æ‹¦æˆªäº†ă€‚</translation>
<translation id="5421136146218899937">清除æµè§ˆæ•°æ®...</translation>
<translation id="5430298929874300616">移除书签</translation>
<translation id="5431657950005405462">找ä¸åˆ°æ‚¨ç„文件</translation>
<translation id="5435775191620395718">ç›®å‰æ˜¾ç¤ºç„是此设备中ç„å†å²è®°å½•ă€‚<ph name="BEGIN_LINK" />了解详情<ph name="END_LINK" />。</translation>
-<translation id="5437003064129843501">您ç„å·²åŒæ­¥æ•°æ®å—自å®ä¹‰å¯†ç ä¿æ¤ï¼Œå› æ­¤ä¸ªæ€§åŒ–内容æ¨èåŸèƒ½å½“å‰å·²åœç”¨ă€‚</translation>
<translation id="5439770059721715174">“<ph name="ERROR_PATH" />â€ä¸­å­˜åœ¨æ¨¡å¼éªŒè¯é”™è¯¯ï¼<ph name="ERROR" /></translation>
<translation id="5452270690849572955">找ä¸åˆ° <ph name="HOST_NAME" /> ç„网页</translation>
<translation id="5455374756549232013">策略时间戳无效</translation>
@@ -403,14 +424,18 @@
<translation id="5622887735448669177">è¦ç¦»å¼€æ­¤ç½‘ç«™å—?</translation>
<translation id="5629630648637658800">无法å è½½ç­–略设置</translation>
<translation id="5631439013527180824">设备管ç†ä»¤ç‰Œæ— æ•ˆ</translation>
-<translation id="5650551054760837876">未找到æœç´¢ç»“æœă€‚</translation>
<translation id="5677928146339483299">å·²å±è”½</translation>
<translation id="5710435578057952990">此网站å°æœªç»è¿‡èº«ä»½éªŒè¯ă€‚</translation>
<translation id="5720705177508910913">当å‰ç”¨æˆ·</translation>
+<translation id="572328651809341494">最近打开ç„标签页</translation>
<translation id="5784606427469807560">确认您ç„信用å¡æ—¶å‡ºç°é—®é¢˜ă€‚请检查您ç„互è”网è¿æ¥ï¼Œç„¶åé‡è¯•ă€‚</translation>
<translation id="5785756445106461925">而且,此页中包å«å…¶ä»–ä¸å®‰å…¨ç„资æºă€‚他人能在这些资æºä¼ è¾“过程中进行查看,攻击者也å¯ä»¥ä¿®æ”¹è¿™äº›èµ„æºï¼Œä»è€Œæ”¹å˜æ­¤é¡µç„å¤–è§‚ă€‚</translation>
+<translation id="5786044859038896871">è¦å¡«å……您ç„信用å¡ä¿¡æ¯å—?</translation>
+<translation id="5803412860119678065">è¦å¡«å……您ç„“<ph name="CARD_DETAIL" />â€å—?</translation>
<translation id="5810442152076338065">æ‚¨ä¸ <ph name="DOMAIN" /> 之间ç„è¿æ¥é‡‡ç”¨è¿‡æ—¶ç„å å¯†å¥—件进行了å å¯†ă€‚</translation>
<translation id="5813119285467412249">æ¢å¤æ·»å (&amp;R)</translation>
+<translation id="5814352347845180253">您å¯èƒ½æ— æ³•å†è®¿é—® <ph name="SITE" /> 以å其他一些网站ä¸ç„ä»˜è´¹å†…å®¹ă€‚</translation>
+<translation id="5843436854350372569">您å°è¯•è®¿é—® <ph name="DOMAIN" />,但æœå¡å™¨æä¾›ç„è¯ä¹¦åŒ…å«é˜²æ¤å›è–„å¼±ç„å¯†é’¥ă€‚æ”»å‡»è€…å¯èƒ½å·²ç ´è§£ç§é’¥ï¼Œè€Œä¸”这个æœå¡å™¨å¯èƒ½å¹¶ä¸æ˜¯æ‚¨æƒ³è¦è®¿é—®ç„æœå¡å™¨ï¼ˆæ‚¨å¯èƒ½æ­£åœ¨ä¸æ”»å‡»è€…进行é€ä¿¡ï¼‰ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="5855235287355719921">您之所以看到这æ¡æ¶ˆæ¯ï¼Œæ˜¯å› ä¸ºç®¡ç†å‘˜å±è”½äº†æ­¤ç½‘站。</translation>
<translation id="5857090052475505287">新文件夹</translation>
<translation id="5869405914158311789">无法访问此网站</translation>
@@ -418,6 +443,7 @@
<translation id="5872918882028971132">家长建议</translation>
<translation id="59107663811261420">Google Payments ä¸æ”¯æŒä½¿ç”¨è¿™ç§ç±»å‹ç„信用å¡å‘此商家付款,请选择其他å¡ă€‚</translation>
<translation id="59174027418879706">å·²å¯ç”¨</translation>
+<translation id="5926846154125914413">您å¯èƒ½æ— æ³•å†è®¿é—®æŸäº›ç½‘ç«™ä¸ç„ä»˜è´¹å†…å®¹ă€‚</translation>
<translation id="5966707198760109579">周</translation>
<translation id="5967867314010545767">ä»å†å²è®°å½•ä¸­ç§»é™¤</translation>
<translation id="5975083100439434680">缩å°</translation>
@@ -429,11 +455,11 @@
<translation id="604124094241169006">自å¨</translation>
<translation id="6042308850641462728">æ›´å¤</translation>
<translation id="6060685159320643512">请å°å¿ƒï¼Œè¿™äº›å®éªŒæ€§åŸèƒ½å¯èƒ½æœ‰é£é™©</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{无}=1{1 个}other{# 个}}</translation>
<translation id="6146055958333702838">请检查所有网线是å¦éƒ½å·²è¿å¥½ï¼Œç„¶åé‡æ–°å¯å¨æ‚¨å¯èƒ½æ­£åœ¨ä½¿ç”¨ç„任何路由器ă€è°ƒåˆ¶è§£è°ƒå™¨æˆ–å…¶ä»–ç½‘ç»œè®¾å¤‡ă€‚</translation>
<translation id="614940544461990577">请试试以下å法ï¼</translation>
<translation id="6150607114729249911">糟糕ï¼æ‚¨å¿…须先å¾å¾—家长åŒæ„,然åæ‰èƒ½è®¿é—®æ­¤ç½‘é¡µă€‚</translation>
<translation id="6151417162996330722">该æœå¡å™¨è¯ä¹¦ç„æœ‰æ•ˆæœŸè¿‡é•¿ă€‚</translation>
-<translation id="6154808779448689242">è¿”å›ç„策略令牌ä¸å½“å‰ä»¤ç‰Œä¸åŒ¹é…</translation>
<translation id="6165508094623778733">了解详情</translation>
<translation id="6203231073485539293">请检查您ç„互è”网è¿æ¥æ˜¯å¦æ­£å¸¸</translation>
<translation id="6218753634732582820">è¦ä» Chromium 中移除地å€å—?</translation>
@@ -446,24 +472,30 @@
<translation id="6328639280570009161">请å°è¯•åœç”¨ç½‘络è”想查询åŸèƒ½</translation>
<translation id="6337534724793800597">按å称过滤政策</translation>
<translation id="6342069812937806050">åˆåˆ</translation>
+<translation id="6345221851280129312">大å°æœªçŸ¥</translation>
<translation id="6355080345576803305">覆盖公用自å©ç»ˆç«¯</translation>
<translation id="6358450015545214790">这分别æ„味ç€ä»€ä¹ˆï¼Ÿ</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 æ¡å…¶ä»–建议}other{# æ¡å…¶ä»–建议}}</translation>
<translation id="6387478394221739770">æƒ³è¯•è¯•è¶…é…·ç„ Chrome æ–°åŸèƒ½ï¼Ÿæ¬¢è¿è®¿é—® chrome.com/beta,试用我们ç„测试版ï¼</translation>
-<translation id="641480858134062906">无法å è½½ <ph name="URL" /></translation>
+<translation id="6389758589412724634">Chromium 在å°è¯•æ˜¾ç¤ºæ­¤ç½‘页时内存ä¸è¶³ă€‚</translation>
+<translation id="6416403317709441254">您目å‰æ— æ³•è®¿é—® <ph name="SITE" />,因为此网站å‘é€ç„凭æ®æ˜¯ä¹±ç ï¼ŒChromium 无法处ç†ă€‚网络错误和攻击行为é€å¸¸æ˜¯æ‚æ—¶ç„,因此,此网页ç¨åå¯èƒ½å°±ä¼æ¢å¤æ­£å¸¸ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="6417515091412812850">无法检查è¯ä¹¦æ˜¯å¦å·²å销。</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> æ‹’ç»äº†æˆ‘们ç„è¿æ¥è¯·æ±‚。</translation>
<translation id="6445051938772793705">国家/地区</translation>
<translation id="6451458296329894277">确认é‡æ–°æ交表å•</translation>
<translation id="6458467102616083041">ç”±äºé»˜è®¤æœç´¢è¢«æ”¿ç­–åœç”¨ï¼Œæ”¿ç­–å€¼å·²è¢«å¿½ç•¥ă€‚</translation>
+<translation id="6462969404041126431">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />ï¼›æœå¡å™¨ç„安全è¯ä¹¦å¯èƒ½é­åˆ°æ’¤æ¶ˆă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="647261751007945333">设备政策</translation>
<translation id="6489534406876378309">开始ä¸ä¼ å´©æºƒæ•°æ®</translation>
<translation id="6529602333819889595">æ¢å¤åˆ é™¤(&amp;R)</translation>
+<translation id="6534179046333460208">å®ç‰©ç½‘建议</translation>
<translation id="6550675742724504774">选项</translation>
+<translation id="6593753688552673085">ä¸åˆ° <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">å å¯†é€‰é¡¹</translation>
<translation id="662080504995468778">留下</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> æœç´¢</translation>
-<translation id="6634865548447745291">您目å‰æ— æ³•è®¿é—®<ph name="SITE" />,因为<ph name="BEGIN_LINK" />æ­¤è¯ä¹¦å·²è¢«æ’¤æ¶ˆ<ph name="END_LINK" />ă€‚ç½‘ç»œé”™è¯¯å’Œæ”»å‡»é€å¸¸æ˜¯æ‚æ—¶ç„,因此,此网页ç¨åå¯èƒ½ä¼æ¢å¤æ­£å¸¸ă€‚</translation>
<translation id="6644283850729428850">æ­¤æ”¿ç­–å·²å¼ƒç”¨ă€‚</translation>
+<translation id="6652240803263749613">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />;您计算机ç„æ“作系统ä¸ä¿¡ä»»æœå¡å™¨ç„安全è¯ä¹¦ă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="6656103420185847513">修改文件夹</translation>
<translation id="6660210980321319655">自å¨æ¥å‘时间ï¼<ph name="CRASH_TIME" /></translation>
<translation id="6671697161687535275">è¦ä» Chromium 中移除表å•å¡«å†™å»ºè®®å—?</translation>
@@ -471,6 +503,7 @@
<translation id="6710213216561001401">ä¸ä¸€ä¸ª</translation>
<translation id="6710594484020273272">&lt;输入æœç´¢å­—è¯&gt;</translation>
<translation id="6711464428925977395">代ç†æœå¡å™¨å‡ºç°é—®é¢˜ï¼Œæˆ–者地å€æœ‰è¯¯ă€‚</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{无}=1{1 项内容}other{# 项内容}}</translation>
<translation id="674375294223700098">未知ç„æœå¡å™¨è¯ä¹¦é”™è¯¯ă€‚</translation>
<translation id="6753269504797312559">政策值</translation>
<translation id="6757797048963528358">您ç„设备已进入休眠模å¼ă€‚</translation>
@@ -482,7 +515,6 @@
<translation id="6891596781022320156">政策级别ä¸å—支æŒă€‚</translation>
<translation id="6895330447102777224">已确认您ç„信用å¡</translation>
<translation id="6897140037006041989">用户代ç†</translation>
-<translation id="6903907808598579934">å¼€å¯åŒæ­¥åŸèƒ½</translation>
<translation id="6915804003454593391">用户ï¼</translation>
<translation id="6957887021205513506">该æœå¡å™¨ç„è¯ä¹¦ä¼¼ä¹æ˜¯ä¼ªé€ ç„。</translation>
<translation id="6965382102122355670">ç¡®å®</translation>
@@ -490,9 +522,11 @@
<translation id="6970216967273061347">区</translation>
<translation id="6973656660372572881">固å®ä»£ç†æœå¡å™¨å’Œ .pac è„本网å€å‡å·²æŒ‡å®ă€‚</translation>
<translation id="6989763994942163495">显示高级设置...</translation>
+<translation id="7000990526846637657">未找到任何记录æ¡ç›®</translation>
+<translation id="7009986207543992532">您å°è¯•è¿æ¥åˆ° <ph name="DOMAIN" />,但æœå¡å™¨æä¾›ç„è¯ä¹¦æœ‰æ•ˆæœŸè¿‡é•¿ï¼Œå› æ­¤é¾ä»¥ä¿¡ä»»ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="7012363358306927923">中国银è”</translation>
+<translation id="7012372675181957985">æ‚¨ç„ Google å¸å·åœ¨ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ä¸å¯èƒ½æœ‰å…¶ä»–å½¢å¼ç„æµè§ˆè®°å½•</translation>
<translation id="7029809446516969842">密ç </translation>
-<translation id="7050187094878475250">您å°è¯•è®¿é—® <ph name="DOMAIN" />,但æœå¡å™¨æä¾›ç„è¯ä¹¦ä¸å¯ä¿¡ï¼ˆæœ‰æ•ˆæœŸè¿‡é•¿ï¼‰ă€‚</translation>
<translation id="7087282848513945231">å¿/郡</translation>
<translation id="7088615885725309056">å¾€å‰</translation>
<translation id="7090678807593890770">请在 Google 中æœç´¢â€œ<ph name="LINK" />â€</translation>
@@ -511,13 +545,13 @@
<translation id="7246609911581847514">您之所以看到这æ¡æ¶ˆæ¯ï¼Œæ˜¯å› ä¸ºæ‚¨ç¬¬ä¸€æ¬¡è®¿é—®æ–°ç„网站时需è¦è·å¾—管ç†å‘˜ç„æ‰¹å‡†ă€‚</translation>
<translation id="724975217298816891">输入“<ph name="CREDIT_CARD" />â€ç„过期日期和银行å¡éªŒè¯ç  (CVC) 以更新您ç„信用å¡è¯¦æƒ…ă€‚åœ¨æ‚¨ç¡®è®¤å,您ç„信用å¡è¯¦æƒ…å°†ä¸æ­¤ç½‘ç«™å…±äº«ă€‚</translation>
<translation id="725866823122871198">您计算机ç„日期和时间(<ph name="DATE_AND_TIME" />)ä¸æ­£ç¡®ï¼Œå› æ­¤æ— æ³•ä¸ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§å¯†è¿æ¥ă€‚</translation>
-<translation id="7265986070661382626">您目å‰æ— æ³•è®¿é—®<ph name="SITE" />,因为此网站<ph name="BEGIN_LINK" />使用了è¯ä¹¦é”å®<ph name="END_LINK" />ă€‚ç½‘ç»œé”™è¯¯å’Œæ”»å‡»é€å¸¸æ˜¯æ‚æ—¶ç„,因此,此网页ç¨åå¯èƒ½ä¼æ¢å¤æ­£å¸¸ă€‚</translation>
<translation id="7269802741830436641">此网页包å«é‡å®å‘循ç¯</translation>
<translation id="7275334191706090484">å—管ç†ç„书签</translation>
<translation id="7298195798382681320">æ¨è</translation>
-<translation id="7301833672208172928">å¼€å¯å†å²è®°å½•åŒæ­¥åŸèƒ½</translation>
+<translation id="7309308571273880165">崩溃æ¥å‘è·å–时间ï¼<ph name="CRASH_TIME" />(用户已请求ä¸ä¼ ï¼Œä½†å°æœªä¸ä¼ ï¼‰</translation>
<translation id="7334320624316649418">æ¢å¤é¡ºåºè°ƒæ•´(&amp;R)</translation>
<translation id="733923710415886693">该æœå¡å™¨ç„è¯ä¹¦æœªé€è¿‡è¯ä¹¦é€æ˜åº¦æ”¿ç­–进行æ«éœ²ă€‚</translation>
+<translation id="7351800657706554155">您目å‰æ— æ³•è®¿é—® <ph name="SITE" />,因为其è¯ä¹¦å·²è¢«æ’¤æ¶ˆă€‚网络错误和攻击行为é€å¸¸æ˜¯æ‚æ—¶ç„,因此,此网页ç¨åå¯èƒ½å°±ä¼æ¢å¤æ­£å¸¸ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="7353601530677266744">命令行</translation>
<translation id="7372973238305370288">æœç´¢ç»“æœ</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -536,26 +570,28 @@
<translation id="7469372306589899959">确认信用å¡</translation>
<translation id="7481312909269577407">å‰è¿›</translation>
<translation id="7485870689360869515">找ä¸åˆ°æ•°æ®ă€‚</translation>
+<translation id="7508255263130623398">è¿”å›ç„政策设备 ID 为空,或ä¸å½“å‰ç„设备 ID ä¸ä¸€è‡´</translation>
<translation id="7514365320538308">下载</translation>
<translation id="7518003948725431193">找ä¸åˆ°ä¸ä»¥ä¸‹ç½‘å€å¯¹åº”ç„网页ï¼<ph name="URL" /></translation>
<translation id="7537536606612762813">强制</translation>
<translation id="7542995811387359312">ç”±äºè¯¥è¡¨å•ä¸ä½¿ç”¨å®‰å…¨è¿æ¥ï¼Œå› æ­¤è‡ªå¨å¡«å†™ä¿¡ç”¨å¡ä¿¡æ¯ç„åŸèƒ½å·²åœç”¨ă€‚</translation>
<translation id="7549584377607005141">此网页需è¦ä½¿ç”¨æ‚¨ä¹‹å‰è¾“å…¥ç„æ•°æ®æ‰èƒ½æ­£å¸¸æ˜¾ç¤ºă€‚您å¯ä»¥é‡æ–°å‘é€è¿™äº›æ•°æ®ï¼Œä¸è¿‡ï¼Œè¿™ä¹ˆåä¼é‡å¤æ‰§è¡Œæ­¤ç½‘页之å‰æ‰§è¡Œè¿‡ç„所有æ“ä½œă€‚</translation>
<translation id="7554791636758816595">新标签页</translation>
-<translation id="7567204685887185387">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å®ƒæ˜¯<ph name="DOMAIN" />;其安全è¯ä¹¦å¯èƒ½æ˜¯ç”±éª—å­å‘出ç„ă€‚å‡ºç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误或您ç„è¿æ¥è¢«æ‹¦æˆªäº†ă€‚</translation>
<translation id="7568593326407688803">此网页为<ph name="ORIGINAL_LANGUAGE" />网页,是å¦éœ€è¦ç¿»è¯‘?</translation>
<translation id="7569952961197462199">ä» Chrome 中移除信用å¡ä¿¡æ¯ï¼Ÿ</translation>
<translation id="7578104083680115302">é€è¿‡å„ç§è®¾å¤‡åœ¨ç½‘站和应用中购物时,您都å¯ä»¥ä½¿ç”¨ Google 为您ä¿å­˜ç„银行å¡ä¿¡æ¯å¿«é€Ÿä»˜æ¬¾ă€‚</translation>
+<translation id="7588950540487816470">å®ç‰©ç½‘</translation>
<translation id="7592362899630581445">æœå¡å™¨ç„è¯ä¹¦è¿å了域åé™åˆ¶ă€‚</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ç›®å‰æ— æ³•å¤„ç†æ­¤è¯·æ±‚。</translation>
<translation id="7600965453749440009">一律ä¸ç¿»è¯‘<ph name="LANGUAGE" /></translation>
<translation id="7610193165460212391">值超出了范围 (<ph name="VALUE" />)。</translation>
<translation id="7613889955535752492">过期时间ï¼<ph name="EXPIRATION_YEAR" /> å¹´ <ph name="EXPIRATION_MONTH" /> 月</translation>
-<translation id="7615602087246926389">您已ç»ä½¿ç”¨ä¸åŒç‰ˆæœ¬ç„ Google å¸æˆ·å¯†ç å å¯†äº†æ•°æ®ă€‚è¯·åœ¨ä¸‹æ–¹è¾“å…¥ă€‚</translation>
+<translation id="7615602087246926389">您已ç»ä½¿ç”¨ä¸åŒç‰ˆæœ¬ç„ Google å¸å·å¯†ç å å¯†äº†æ•°æ®ă€‚è¯·åœ¨ä¸‹æ–¹è¾“å…¥ă€‚</translation>
<translation id="7634554953375732414">您ä¸æ­¤ç½‘站建立ç„ä¸æ˜¯ç§å¯†è¿æ¥ă€‚</translation>
<translation id="7637571805876720304">è¦ä» Chromium 中移除信用å¡å—?</translation>
<translation id="765676359832457558">éè—高级设置...</translation>
<translation id="7658239707568436148">å–消</translation>
+<translation id="7667346355482952095">è¿”å›ç„政策令牌为空或ä¸å½“å‰ä»¤ç‰Œä¸åŒ¹é…</translation>
<translation id="7668654391829183341">未知设备</translation>
<translation id="7674629440242451245">æƒ³è¯•è¯•è¶…é…·ç„ Chrome æ–°åŸèƒ½ï¼Ÿæ¬¢è¿è®¿é—® chrome.com/dev,试用我们ç„测试版ï¼</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />继续å‰å¾€<ph name="SITE" />(ä¸å®‰å…¨ï¼‰<ph name="END_LINK" /></translation>
@@ -572,10 +608,10 @@
<translation id="780301667611848630">ä¸ç”¨äº†ï¼Œè°¢è°¢</translation>
<translation id="7805768142964895445">ç¶æ€</translation>
<translation id="7813600968533626083">ä» Chrome 中移除表å•å»ºè®®ï¼Ÿ</translation>
+<translation id="7815407501681723534">找到了 <ph name="NUMBER_OF_RESULTS" /> 个ä¸â€œ<ph name="SEARCH_STRING" />â€ç›¸ç¬¦ç„<ph name="SEARCH_RESULTS" /></translation>
<translation id="785549533363645510">但是,这并ä¸æ„味ç€æ‚¨èƒ½å®Œå…¨éèº«ă€‚å³ä½¿æ‚¨è¿›å…¥é身模å¼ï¼Œæ‚¨ç„雇主ă€äº’è”网æœå¡æ供商和您访问ç„网站ä»ç„¶èƒ½çœ‹åˆ°æ‚¨ç„æµè§ˆæ´»å¨ă€‚</translation>
<translation id="7887683347370398519">请检查您ç„银行å¡éªŒè¯ç  (CVC),然åé‡è¯•</translation>
<translation id="7894616681410591072">糟糕ï¼æ‚¨å¿…须先å¾å¾—<ph name="NAME" />ç„åŒæ„,然åæ‰èƒ½è®¿é—®æ­¤ç½‘é¡µă€‚</translation>
-<translation id="790025292736025802">未找到 <ph name="URL" /></translation>
<translation id="7912024687060120840">在以下文件夹中ï¼</translation>
<translation id="7920092496846849526">å·²å‘您父æ¯æ出å…许您访问此网页ç„è¯·æ±‚ă€‚</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -588,9 +624,10 @@
<translation id="7995512525968007366">未指å®</translation>
<translation id="8012647001091218357">我们æ‚时无法ä¸æ‚¨çˆ¶æ¯å–å¾—è”系,请é‡è¯•ă€‚</translation>
<translation id="8034522405403831421">此网页ç„æºè¯­è¨€ä¸º<ph name="SOURCE_LANGUAGE" />,è¦å°†å…¶ç¿»è¯‘æˆ<ph name="TARGET_LANGUAGE" />å—?</translation>
-<translation id="8034955203865359138">未找到任何å†å²è®°å½•æ¡ç›®ă€‚</translation>
<translation id="8088680233425245692">æ— æ³•æŸ¥çœ‹æ–‡ç« ă€‚</translation>
+<translation id="8089520772729574115">å°äº 1 MB</translation>
<translation id="8091372947890762290">正等待在æœå¡å™¨ä¸æ¿€æ´»</translation>
+<translation id="8129262335948759431">æ•°é‡æœªçŸ¥</translation>
<translation id="8131740175452115882">确认</translation>
<translation id="8134994873729925007">找ä¸åˆ° <ph name="HOST_NAME" /> ç„æœå¡å™¨ <ph name="BEGIN_ABBR" />DNS 地å€<ph name="END_ABBR" />。</translation>
<translation id="8149426793427495338">您ç„计算机已进入休眠模å¼ă€‚</translation>
@@ -599,6 +636,7 @@
<translation id="8201077131113104583">ID 为“<ph name="EXTENSION_ID" />â€ç„扩展程åºç„更新网å€æ— æ•ˆă€‚</translation>
<translation id="8218327578424803826">分é…ç„ä½ç½®ï¼</translation>
<translation id="8225771182978767009">设置此计算机ç„用户已选择å±è”½æ­¤ç½‘站。</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />ă€<ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">您所查找ç„网页è¦ä½¿ç”¨å·²è¾“å…¥ç„ä¿¡æ¯ă€‚è¿”å›æ­¤é¡µå¯èƒ½éœ€è¦é‡å¤å·²è¿›è¡Œç„所有æ“ä½œă€‚æ˜¯å¦è¦ç»§ç»­æ“作?</translation>
<translation id="8249320324621329438">最å一次æ“å–时间ï¼</translation>
<translation id="8261506727792406068">删除</translation>
@@ -611,12 +649,17 @@
<translation id="8349305172487531364">书签æ </translation>
<translation id="8363502534493474904">关闭é£è¡Œæ¨¡å¼</translation>
<translation id="8364627913115013041">æœªè®¾ç½®ă€‚</translation>
+<translation id="8380941800586852976">å±é™©</translation>
<translation id="8412145213513410671">崩溃次数(<ph name="CRASH_COUNT" /> 次)</translation>
<translation id="8412392972487953978">您两次输入ç„密ç å¿…须相åŒă€‚</translation>
<translation id="8428213095426709021">设置</translation>
+<translation id="8433057134996913067">这将使您退出大å¤æ•°ç½‘站。</translation>
<translation id="8437238597147034694">撤消移å¨(&amp;U)</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 张信用å¡}other{# 张信用å¡}}</translation>
+<translation id="8483780878231876732">è¦ä½¿ç”¨æ‚¨ Google å¸å·ä¸­ç„信用å¡ï¼Œè¯·ç™»å½• Chrome</translation>
<translation id="8488350697529856933">适用对象</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ç„å“åº”æ—¶é—´è¿‡é•¿ă€‚</translation>
+<translation id="852346902619691059">æ­¤æœå¡å™¨æ— æ³•è¯æ˜å…¶æ‰€åœ¨ç½‘域是 <ph name="DOMAIN" />;您设备ç„æ“作系统ä¸ä¿¡ä»»æœå¡å™¨ç„安全è¯ä¹¦ă€‚出ç°æ­¤é—®é¢˜ç„åŸå› å¯èƒ½æ˜¯é…置有误,或是有攻击者拦截您ç„è¿æ¥ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" />。</translation>
<translation id="8530504477309582336">Google Payments ä¸æ”¯æŒè¿™ç§ç±»å‹ç„信用å¡ï¼Œè¯·é€‰æ‹©å…¶ä»–å¡ă€‚</translation>
<translation id="8550022383519221471">您ç„域ä¸æ”¯æŒåŒæ­¥æœå¡ă€‚</translation>
<translation id="8553075262323480129">系统无法确å®è¯¥ç½‘页ç„è¯­è¨€ï¼Œå› æ­¤æ— æ³•è¿›è¡Œç¿»è¯‘ă€‚</translation>
@@ -626,17 +669,14 @@
<translation id="8591846766485502580">您之所以看到这æ¡æ¶ˆæ¯ï¼Œæ˜¯å› ä¸ºæ‚¨ç„一ä½å®¶é•¿å±è”½äº†æ­¤ç½‘站。</translation>
<translation id="859285277496340001">è¯ä¹¦æœªæŒ‡å®ç”¨äºæ£€æŸ¥æ˜¯å¦å·²å销è¯ä¹¦ç„æœºåˆ¶ă€‚</translation>
<translation id="8647750283161643317">全部é‡ç½®ä¸ºé»˜è®¤å€¼</translation>
-<translation id="8680787084697685621">å¸æˆ·ç™»å½•è¯¦ç»†ä¿¡æ¯å·²è¿‡æœŸă€‚</translation>
+<translation id="8680787084697685621">å¸å·ç™»å½•è¯¦ç»†ä¿¡æ¯å·²è¿‡æœŸă€‚</translation>
<translation id="8703575177326907206">æ‚¨ä¸ <ph name="DOMAIN" /> ç„è¿æ¥æœªå å¯†ă€‚</translation>
-<translation id="8713130696108419660">åˆå§‹ç­¾å错误</translation>
<translation id="8725066075913043281">é‡è¯•</translation>
<translation id="8728672262656704056">您已进入é身模å¼</translation>
<translation id="8730621377337864115">完æˆ</translation>
<translation id="8738058698779197622">è¦å»ºç«‹å®‰å…¨è¿æ¥ï¼Œæ‚¨ç„æ—¶é’Ÿè®¾ç½®å¿…é¡»æ­£ç¡®ă€‚è¿™æ˜¯å› ä¸ºï¼Œç½‘ç«™ç”¨äºè¯æ˜èº«ä»½ç„è¯ä¹¦ä»…在特å®æ—¶é—´æ®µæœ‰æ•ˆă€‚ç”±äºæ‚¨è®¾å¤‡ç„时钟ä¸æ­£ç¡®ï¼Œå› æ­¤ Chromium 无法验è¯è¿™äº›è¯ä¹¦ă€‚</translation>
<translation id="8740359287975076522">无法找到 <ph name="HOST_NAME" /> ç„ &lt;abbr id="dnsDefinition"&gt;DNS 地å€&lt;/abbr&gt;ă€‚æ­£åœ¨è¯æ–­è¯¥é—®é¢˜ă€‚</translation>
-<translation id="8741995161408053644">æ‚¨ç„ Google å¸æˆ·åœ¨ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ä¸å¯èƒ½æœ‰å…¶ä»–å½¢å¼ç„æµè§ˆè®°å½•ă€‚</translation>
<translation id="8790007591277257123">æ¢å¤åˆ é™¤(&amp;R)</translation>
-<translation id="8790687370365610530">è¦è·å– Google æ¨èç„个性化内容,请开å¯å†å²è®°å½•åŒæ­¥åŸèƒ½ă€‚</translation>
<translation id="8798099450830957504">默认</translation>
<translation id="8804164990146287819">éç§æƒæ”¿ç­–</translation>
<translation id="8820817407110198400">书签</translation>
@@ -652,19 +692,17 @@
<translation id="8891727572606052622">代ç†æ¨¡å¼æ— æ•ˆă€‚</translation>
<translation id="889901481107108152">æ±æ­‰ï¼Œæ­¤é¡¹å®éªŒæ€§åŸèƒ½ä¸èƒ½ç”¨äºæ‚¨ç„å¹³å°ă€‚</translation>
<translation id="8903921497873541725">放大</translation>
-<translation id="8931333241327730545">è¦å°†æ­¤å¡ç„ä¿¡æ¯ä¿å­˜åˆ°æ‚¨ç„ Google å¸æˆ·å—?</translation>
+<translation id="8931333241327730545">è¦å°†æ­¤å¡ç„ä¿¡æ¯ä¿å­˜åˆ°æ‚¨ç„ Google å¸å·å—?</translation>
<translation id="8932102934695377596">您ç„时钟慢了</translation>
<translation id="8954894007019320973">(续)</translation>
<translation id="8971063699422889582">æœå¡å™¨ç„è¯ä¹¦å·²è¿‡æœŸă€‚</translation>
<translation id="8987927404178983737">月</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">该æœå¡å™¨æ供了一个未é€è¿‡è¯ä¹¦é€æ˜åº¦æ”¿ç­–公开æ«éœ²ç„è¯ä¹¦ă€‚æŸäº›è¯ä¹¦å¿…é¡»é€è¿‡è¯ä¹¦é€æ˜åº¦æ”¿ç­–进行公开æ«éœ²ï¼Œä»¥ç¡®ä¿å®ƒä»¬å€¼å¾—信任且能ä¿æ¤ç”¨æˆ·å…é­æ”»å‡»ă€‚</translation>
<translation id="9001074447101275817">ä»£ç† (<ph name="DOMAIN" />) è¦æ±‚æ供用户å和密ç ă€‚</translation>
<translation id="901974403500617787">应用äºæ•´ä¸ªç³»ç»Ÿç„设置åªèƒ½ç”±ä»¥ä¸‹æ‰€æœ‰è€…设å®ï¼<ph name="OWNER_EMAIL" />。</translation>
<translation id="9020542370529661692">已将此网页内容翻译æˆ<ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">使用è”想查询æœå¡æ›´å¿«é€Ÿåœ°å è½½ç½‘页</translation>
<translation id="9039213469156557790">而且,此页中包å«å…¶ä»–ä¸å®‰å…¨ç„资æºă€‚他人能在这些资æºä¼ è¾“过程中进行查看,而攻击者å¯ä»¥ä¿®æ”¹è¿™äº›èµ„æºï¼Œä»è€Œæ”¹å˜æ­¤é¡µç„è¡Œä¸ºă€‚</translation>
-<translation id="9049981332609050619">您试图访问 <ph name="DOMAIN" />,但æœå¡å™¨æä¾›ç„è¯ä¹¦æ— æ•ˆă€‚</translation>
<translation id="9050666287014529139">密ç </translation>
<translation id="9065203028668620118">修改</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> 网页无法正常è¿ä½œ</translation>
diff --git a/chromium/components/strings/components_strings_zh-TW.xtb b/chromium/components/strings/components_strings_zh-TW.xtb
index 98bbb19fd22..e001e2535e3 100644
--- a/chromium/components/strings/components_strings_zh-TW.xtb
+++ b/chromium/components/strings/components_strings_zh-TW.xtb
@@ -1,23 +1,24 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-TW">
+<translation id="1008557486741366299">ç¾åœ¨ä¸è¦</translation>
<translation id="1015730422737071372">æ供其他詳細資è¨</translation>
<translation id="1032854598605920125">順時é‡æ—‹è½‰</translation>
<translation id="1038842779957582377">ä¸æ˜å稱</translation>
+<translation id="1053591932240354961">ç›®å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為這個網站傳é€ç„憑證å«æœ‰äº‚碼,Google Chrome 無法處ç†ă€‚網路錯誤和攻æ“行為é€å¸¸æ˜¯æ«æ™‚性ç„,因此這個網é å¯èƒ½ç¨å¾Œå°±æœƒæ¢å¾©æ­£å¸¸ç‹€æ…‹ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1055184225775184556">復åŸæ–°å¢(&amp;U)</translation>
<translation id="10614374240317010">一律ä¸å„²å­˜</translation>
-<translation id="1064422015032085147">代管這個網é ç„伺æœå™¨å¯èƒ½å·²è¶…è¼‰æˆ–æ­£åœ¨é€²è¡Œç¶­è­·ă€‚
- 為了é¿å…產生éå¤ç„æµé‡ï¼Œå°è‡´æƒ…æ³æƒ¡åŒ–,
- ç›®å‰ç³»çµ±å·²æ«æ™‚ç¦æ­¢å‚³é€è¦æ±‚至這個網å€ă€‚</translation>
<translation id="106701514854093668">電腦版書籤</translation>
<translation id="1080116354587839789">符åˆè¦–窗寬度</translation>
+<translation id="1103124106085518534">æ«æ™‚沒有最新內容</translation>
<translation id="1103523840287552314">一律翻譯<ph name="LANGUAGE" /></translation>
<translation id="1107591249535594099">勾é¸å¾Œï¼ŒChrome 會在這個è£ç½®ä¸å„²å­˜æ‚¨ç„信用å¡è¤‡æœ¬ï¼Œä»¥ä¾¿æ›´å¿«å¡«å¯«è³‡è¨ă€‚</translation>
+<translation id="1111153019813902504">最近使用éç„書籤</translation>
<translation id="1113869188872983271">復åŸé‡æ–°æ’åº(&amp;U)</translation>
+<translation id="1126551341858583091">佔用ç„本機儲存空間大å°ï¼<ph name="CRASH_SIZE" />。</translation>
<translation id="112840717907525620">政策快å–正確</translation>
<translation id="113188000913989374"><ph name="SITE" /> 顯示ï¼</translation>
<translation id="1132774398110320017">Chrome 自動填入設å®...</translation>
-<translation id="1150979032973867961">伺æœå™¨ç„¡æ³•è­‰æ˜å…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證未å–得您電腦作業系統ç„ä¿¡ä»»ă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–有攻æ“者攔截您ç„連ç·æ‰€è‡´ă€‚</translation>
<translation id="1152921474424827756">å­˜å– <ph name="URL" /> ç„<ph name="BEGIN_LINK" />é åº«å­˜æª”副本<ph name="END_LINK" /></translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> æ„外中斷連ç·ă€‚</translation>
<translation id="1161325031994447685">é‡æ–°é€£ç·è‡³ Wi-Fi 網路</translation>
@@ -25,7 +26,8 @@
<translation id="1181037720776840403">移除</translation>
<translation id="1201402288615127009">繼續</translation>
<translation id="1201895884277373915">這個網站ç„æ›´å¤å…§å®¹</translation>
-<translation id="121201262018556460">您嘗試å‰å¾€ <ph name="DOMAIN" />,但伺æœå™¨æ‰€æä¾›ç„憑證å«æœ‰é˜²è­·å›è–„å¼±ç„é‡‘é‘°ă€‚æ”»æ“者å¯èƒ½å·²ç ´å£ç§å¯†é‡‘鑰,而該伺æœå™¨å¯èƒ½ä¸¦é您ç„目標伺æœå™¨ (您ç„連ç·å°è±¡å¯èƒ½æ˜¯æ”»æ“者ç„電腦)。</translation>
+<translation id="1206967143813997005">縮寫簽å無效</translation>
+<translation id="1209206284964581585">æ«æ™‚é±è—</translation>
<translation id="1219129156119358924">系統安全性</translation>
<translation id="1227224963052638717">ä¸æ˜æ”¿ç­–。</translation>
<translation id="1227633850867390598">é±è—政策值</translation>
@@ -46,6 +48,7 @@
<translation id="1426410128494586442">是</translation>
<translation id="1430915738399379752">列å°</translation>
<translation id="1442912890475371290">å·²å°é–<ph name="BEGIN_LINK" />造訪ä½æ–¼ <ph name="DOMAIN" /> ç„網é <ph name="END_LINK" />ç„è¦æ±‚。</translation>
+<translation id="1491663344921578213">ç›®å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為這個網站使用憑證é–å®åŸèƒ½ă€‚網路錯誤和攻æ“行為é€å¸¸æ˜¯æ«æ™‚性ç„,因此這個網é å¯èƒ½ç¨å¾Œå°±æœƒæ¢å¾©æ­£å¸¸ç‹€æ…‹ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1506687042165942984">顯示這個網é ç„儲存複本 (亦å³ç¾å·²ä¸å†ä½¿ç”¨ç„版本)。</translation>
<translation id="1519264250979466059">建立日期</translation>
<translation id="1549470594296187301">您必須啟用 JavaScript æ‰èƒ½ä½¿ç”¨é€™é …åŸèƒ½ă€‚</translation>
@@ -60,36 +63,34 @@
<translation id="1644184664548287040">網路設å®ç„¡æ•ˆï¼Œç„¡æ³•åŒ¯å…¥ă€‚</translation>
<translation id="1644574205037202324">æ­·å²ç´€éŒ„</translation>
<translation id="1645368109819982629">ä¸æ”¯æ´ç„é€è¨å”å®</translation>
-<translation id="1655462015569774233">{1,plural, =1{這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證已在昨天éæœŸă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截您ç„連ç·ă€‚您電腦ç„時é˜ç›®å‰è¨­ç‚º <ph name="CURRENT_DATE" />,這是正確ç„時間å—?如æœä¸æ˜¯ç„話,請更新系統時é˜ï¼Œç„¶å¾Œé‡æ–°æ•´ç†é€™å€‹ç¶²é ă€‚}other{這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證已在 # 天å‰éæœŸă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截您ç„連ç·ă€‚您電腦ç„時é˜ç›®å‰è¨­ç‚º <ph name="CURRENT_DATE" />,這是正確ç„時間å—?如æœä¸æ˜¯ç„話,請更新系統時é˜ï¼Œç„¶å¾Œé‡æ–°æ•´ç†é€™å€‹ç¶²é ă€‚}}</translation>
<translation id="1676269943528358898"><ph name="SITE" /> é€å¸¸ä½¿ç”¨å å¯†æ–¹å¼ä¿è­·æ‚¨ç„資è¨ă€‚但 Google Chrome 這次嘗試連ç·åˆ° <ph name="SITE" /> 時,該網站傳å›äº†ç•°å¸¸ä¸”錯誤ç„æ†‘è­‰ă€‚é€™å¯èƒ½æ˜¯å› ç‚ºæœ‰æ”»æ“者ä¼åœ–å½è£æˆ <ph name="SITE" />,或是å—到 Wi-Fi 登入畫é¢å½±éŸ¿è€Œé€ æˆé€£ç·ä¸­æ–·ă€‚ä¸é請放心,Google Chrome å·²å時åœæ­¢é€£ç·ï¼Œä¸¦æœªå‚³è¼¸ä»»ä½•è³‡æ–™ï¼Œå› æ­¤æ‚¨ç„資è¨ä»ç„¶å®‰å…¨ç„¡è™ă€‚</translation>
<translation id="168841957122794586">伺æœå™¨æ†‘è­‰å«æœ‰é˜²è­·å›è–„å¼±ç„å å¯†ç·¨è­¯é‡‘鑰。</translation>
<translation id="1701955595840307032">å–å¾—æ¨è–¦å…§å®¹</translation>
-<translation id="1706954506755087368">{1,plural, =1{這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證é å®æ˜å¤©æ‰ç”Ÿæ•ˆă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截您ç„連ç·ă€‚}other{這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證é å® # 天後æ‰ç”Ÿæ•ˆă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截您ç„連ç·ă€‚}}</translation>
<translation id="1710259589646384581">作業系統</translation>
<translation id="1734864079702812349">Amex</translation>
<translation id="1734878702283171397">建議您與系統管ç†å“¡è¯çµ¡ă€‚</translation>
<translation id="17513872634828108">開啟分é </translation>
<translation id="1753706481035618306">é ç¢¼</translation>
-<translation id="1761412452051366565">如è¦å–å¾—å€‹äººåŒ–ç„ Google æ¨è–¦å…§å®¹ï¼Œè«‹é–‹å•ŸåŒæ­¥è™•ç†åŸèƒ½ă€‚</translation>
-<translation id="1763864636252898013">伺æœå™¨ç„¡æ³•è­‰æ˜å…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證未å–得您è£ç½®ä½œæ¥­ç³»çµ±ç„ä¿¡ä»»ă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–有攻æ“者攔截您ç„連ç·æ‰€è‡´ă€‚</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />嘗試執行 Windows 網路診斷<ph name="END_LINK" />。</translation>
<translation id="1783075131180517613">請更新您ç„åŒæ­¥é€é—œå¯†èªă€‚</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
+<translation id="1815084229389833348">這裡會顯示你最近造訪éç„æ›¸ç±¤ă€‚</translation>
<translation id="1821930232296380041">è¦æ±‚或è¦æ±‚åƒæ•¸ç„¡æ•ˆ</translation>
<translation id="1838667051080421715">ç›®å‰é¡¯ç¤ºç„是網é åŸå§‹ç¢¼ă€‚</translation>
<translation id="1871208020102129563">Proxy 設å®ç‚ºä½¿ç”¨å›ºå®ç„ Proxy 伺æœå™¨ï¼Œè€Œé .pac 指令碼網å€ă€‚</translation>
<translation id="1883255238294161206">收åˆæ¸…å–®</translation>
<translation id="1898423065542865115">篩é¸</translation>
-<translation id="1911837502049945214"><ph name="HOST_NAME" /> ä¸æ¥å—您ç„登入憑證,或是您ç„登入憑證å¯èƒ½å·²éæœŸă€‚</translation>
<translation id="194030505837763158">å‰å¾€ <ph name="LINK" /></translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> 書籤</translation>
<translation id="1973335181906896915">åºåˆ—化錯誤</translation>
<translation id="1974060860693918893">進é</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{以åå¦å¤– 1 個應用程å¼}other{以åå¦å¤– # 個應用程å¼}}</translation>
<translation id="2025186561304664664">Proxy 已設為自動設å®ă€‚</translation>
<translation id="2030481566774242610">您è¦æ‰¾ç„是 <ph name="LINK" /> å—?</translation>
<translation id="2031925387125903299">Chrome 顯示這則è¨æ¯æ˜¯å› ç‚ºæ‚¨é¦–次ç€è¦½ç„新網站需è¦ç²å¾—您ç„å®¶é•·æ ¸å‡†ă€‚</translation>
<translation id="2032962459168915086"><ph name="BEGIN_LINK" />檢查 Proxy 和防ç«ç‰†<ph name="END_LINK" /></translation>
<translation id="2053553514270667976">郵éå€è™Ÿ</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 個建議項目}other{# 個建議項目}}</translation>
<translation id="2065985942032347596">需è¦é©—è­‰</translation>
<translation id="2079545284768500474">復åŸ</translation>
<translation id="20817612488360358">雖然系統 Proxy 設å®å·²è¨­ç‚ºä½¿ç”¨ï¼Œä¸é也指å®äº†æ˜ç¢º Proxy 設å®ă€‚</translation>
@@ -105,32 +106,34 @@
<translation id="2149973817440762519">編輯書籤</translation>
<translation id="2166049586286450108">完整管ç†å“¡å­˜å–æ¬</translation>
<translation id="2166378884831602661">這個網站無法æ供安全連ç·</translation>
-<translation id="2171101176734966184">您嘗試å‰å¾€ <ph name="DOMAIN" />,但該伺æœå™¨æä¾›ç„憑證是以防護å›è¼ƒå¼±ç„簽章演算法進行簽署,這代表該伺æœå™¨æä¾›ç„安全èªè­‰å¯èƒ½é­åˆ°å½é€ ï¼Œä¸”該伺æœå™¨å¯èƒ½ä¸¦é您ç„目標伺æœå™¨ (您ç„連ç·å°è±¡å¯èƒ½æ˜¯æ”»æ“者ç„電腦)。</translation>
<translation id="2181821976797666341">政策</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 個地å€}other{# 個地å€}}</translation>
<translation id="2212735316055980242">找ä¸åˆ°æ”¿ç­–</translation>
<translation id="2213606439339815911">正在擷å–é …ç›®...</translation>
-<translation id="2214283295778284209"><ph name="SITE" /> 無法使用</translation>
<translation id="2230458221926704099">請使用<ph name="BEGIN_LINK" />診斷應用程å¼<ph name="END_LINK" />修正連ç·å•é¡Œ</translation>
+<translation id="2239100178324503013">ç«‹å³å‚³é€</translation>
<translation id="225207911366869382">這個政策值已é­æ±°æ›ă€‚</translation>
<translation id="2262243747453050782">HTTP 錯誤</translation>
<translation id="2282872951544483773">無法使用ç„實驗性åŸèƒ½</translation>
<translation id="2292556288342944218">您ç„網é›ç¶²è·¯å­˜å–æ¬é­åˆ°å°é–</translation>
<translation id="229702904922032456">根憑證或中繼憑證已éæœŸă€‚</translation>
<translation id="230155334948463882">新信用å¡ï¼Ÿ</translation>
+<translation id="2305919008529760154">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證核發來æºæœ‰è©æ¬ºå«Œç–‘。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> è¦æ±‚æ供使用者åç¨±å’Œå¯†ç¢¼ă€‚</translation>
+<translation id="2318774815570432836">ç›®å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為這個網站使用 HSTSă€‚ç¶²è·¯éŒ¯èª¤å’Œæ”»æ“行為é€å¸¸æ˜¯æ«æ™‚性ç„,因此這個網é å¯èƒ½ç¨å¾Œå°±æœƒæ¢å¾©æ­£å¸¸ç‹€æ…‹ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2328300916057834155">å·²å¿½ç•¥ç´¢å¼•ă€Œ<ph name="ENTRY_INDEX" />ă€ç„無效書籤</translation>
<translation id="2354001756790975382">其他書籤</translation>
<translation id="2359808026110333948">繼續</translation>
<translation id="2365563543831475020">當機報å‘æ“·å–時間ï¼<ph name="CRASH_TIME" /> (å°æœªä¸å‚³)</translation>
<translation id="2367567093518048410">ç­‰ç´</translation>
+<translation id="2371153335857947666">{1,plural, =1{這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證已在昨天éæœŸă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚電腦ç„時é˜ç›®å‰è¨­ç‚º <ph name="CURRENT_DATE" />,這是正確ç„時間å—?如æœä¸æ˜¯ç„話,請更新系統時é˜ï¼Œç„¶å¾Œé‡æ–°æ•´ç†é€™å€‹ç¶²é ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" />}other{這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證已在 # 天å‰éæœŸă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚電腦ç„時é˜ç›®å‰è¨­ç‚º <ph name="CURRENT_DATE" />,這是正確ç„時間å—?如æœä¸æ˜¯ç„話,請更新系統時é˜ï¼Œç„¶å¾Œé‡æ–°æ•´ç†é€™å€‹ç¶²é ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="237718015863234333">沒有å¯ç”¨ç„替代使用者介é¢</translation>
<translation id="2384307209577226199">ä¼æ¥­é è¨­</translation>
-<translation id="238526402387145295">您目å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為這個網站<ph name="BEGIN_LINK" />使用 HSTS<ph name="END_LINK" />ă€‚ç¶²è·¯éŒ¯èª¤å’Œæ”»æ“行為é€å¸¸æ˜¯æ«æ™‚性ç„,所以這個網é å¯èƒ½ç¨å¾Œå°±èƒ½æ­£å¸¸ä½¿ç”¨ă€‚</translation>
<translation id="2386255080630008482">伺æœå™¨æ†‘證已é­æ’¤é·ă€‚</translation>
<translation id="2392959068659972793">顯示å°æœªè¨­å®ä»»ä½•å€¼ç„政策</translation>
<translation id="2396249848217231973">復åŸåˆªé™¤(&amp;U)</translation>
-<translation id="2413528052993050574">伺æœå™¨ç„¡æ³•è­‰æ˜å…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證已é­æ’¤é·ă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–有攻æ“者攔截您ç„連ç·æ‰€è‡´ă€‚</translation>
<translation id="2455981314101692989">這個網é å·²åœç”¨é€™å€‹è¡¨å–®ç„自動填入åŸèƒ½ă€‚</translation>
+<translation id="2463739503403862330">å¡«å…¥</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />執行網路診斷<ph name="END_LINK" /></translation>
<translation id="2479410451996844060">無效ç„æœå°‹ç¶²å€ă€‚</translation>
<translation id="2491120439723279231">伺æœå™¨æ†‘è­‰å«æœ‰éŒ¯èª¤ă€‚</translation>
@@ -152,10 +155,12 @@
<translation id="2653659639078652383">æ交</translation>
<translation id="2674170444375937751">確å®è¦å¾æ‚¨ç„紀錄中刪除這些網é å—?</translation>
<translation id="2677748264148917807">離開</translation>
+<translation id="269990154133806163">這個伺æœå™¨ç„憑證並未根æ“憑證é€æ˜åŒ–政策å°å¤–å…¬é–‹ă€‚éƒ¨åˆ†æ†‘è­‰å¿…é ˆç¬¦åˆé€™é …è¦å®ï¼Œä»¥ç¢ºä¿æ†‘證值得信任,ä¸æœƒè®“使用者é­åˆ°æ”»æ“。<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2704283930420550640">政策值格å¼ä¸ç¬¦ă€‚</translation>
<translation id="2704951214193499422">Chromium ç›®å‰ç„¡æ³•é©—證您ç„信用å¡ï¼Œè«‹ç¨å¾Œå†è©¦ă€‚</translation>
<translation id="2705137772291741111">已儲存 (å¿«å–) 這個網站ç„複本,但無法讀å–。</translation>
<translation id="2709516037105925701">自動填入</translation>
+<translation id="2712118517637785082">ä½ å˜—è©¦é€£ä¸ <ph name="DOMAIN" />,但伺æœå™¨ç„憑證已é­åˆ°æ ¸ç™¼å–®ä½æ’¤é·ă€‚在這種情æ³ä¸‹ï¼Œè«‹å‹¿ä¿¡ä»»ä¼ºæœå™¨æä¾›ç„å®‰å…¨æ€§æ†‘è­‰ă€‚ä½ ç„連ç·å°è±¡å¯èƒ½æ˜¯æ”»æ“者ç„é›»è…¦ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2712173769900027643">è¦æ±‚æ¬é™</translation>
<translation id="2721148159707890343">è¦æ±‚æˆåŸ</translation>
<translation id="2728127805433021124">伺æœå™¨æ†‘證是以防護å›è¼ƒå¼±ç„ç°½ç« æ¼”ç®—æ³•é€²è¡Œç°½ç½²ă€‚</translation>
@@ -167,14 +172,11 @@
<translation id="2824775600643448204">網å€èˆ‡æœå°‹åˆ—</translation>
<translation id="2826760142808435982">連ç·æ¡ç”¨ <ph name="CIPHER" /> å å¯†ï¼Œä¸¦è¨­æœ‰ <ph name="KX" /> 金鑰交æ›æ©Ÿåˆ¶ă€‚</translation>
<translation id="2835170189407361413">清除表單</translation>
-<translation id="2837049386027881519">必須使用較èˆç‰ˆç„ TLS 或 SSL é€è¨å”å®é‡è©¦é€£ç·ă€‚這é€å¸¸è¡¨ç¤ºä¼ºæœå™¨æ‰€ä½¿ç”¨ç„軟體é常è€èˆï¼Œè€Œä¸”å¯èƒ½ç”¢ç”Ÿå…¶ä»–安全å•é¡Œă€‚</translation>
<translation id="284702764277384724"><ph name="HOST_NAME" /> 疑似使用å½é€ ç„伺æœå™¨æ†‘è­‰ă€‚</translation>
<translation id="2889159643044928134">ä¸è¦é‡æ–°è¼‰å…¥</translation>
-<translation id="2896499918916051536">系統ä¸æ”¯æ´é€™å€‹å¤–æ›ç¨‹å¼ă€‚</translation>
+<translation id="2900469785430194048">Google Chrome 嘗試顯示這個網é æ™‚ç”¨ç›¡äº†è¨˜æ†¶é«”ă€‚</translation>
<translation id="2909946352844186028">系統åµæ¸¬åˆ°ç¶²è·¯è®æ›´ă€‚</translation>
-<translation id="2915500479781995473">伺æœå™¨ç„¡æ³•è­‰æ˜å…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證已éæœŸă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–有攻æ“者攔截您ç„連ç·æ‰€è‡´ă€‚您電腦時é˜ç›®å‰è¨­å®ç„時間是 <ph name="CURRENT_TIME" />,是å¦æ­£ç¢ºï¼Ÿå¦‚æœè¨­å®æœ‰èª¤ï¼Œè«‹æ›´æ­£æ‚¨ç³»çµ±ç„時é˜ï¼Œå†é‡æ–°æ•´ç†é€™å€‹é é¢ă€‚</translation>
<translation id="2922350208395188000">無法檢查伺æœå™¨æ†‘è­‰ă€‚</translation>
-<translation id="2941952326391522266">伺æœå™¨ç„¡æ³•è­‰æ˜å…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證來自 <ph name="DOMAIN2" /> ç¶²åŸŸă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–有攻æ“者攔截您ç„連ç·æ‰€è‡´ă€‚</translation>
<translation id="2948083400971632585">您å¯ä»¥åœ¨è¨­å®é é¢åœç”¨ä»»ä½•ç‚ºé€£ç·è¨­ç½®ç„ Proxy。</translation>
<translation id="2955913368246107853">關閉æœå°‹åˆ—</translation>
<translation id="2958431318199492670">網路設å®æœªéµå¾ª ONC 標準,系統å¯èƒ½ç„¡æ³•åŒ¯å…¥éƒ¨åˆ†è¨­å®ă€‚</translation>
@@ -188,6 +190,7 @@
<translation id="3024663005179499861">政策é¡å‹æœ‰èª¤</translation>
<translation id="3032412215588512954">您è¦é‡æ–°è¼‰å…¥é€™å€‹ç¶²ç«™å—?</translation>
<translation id="3037605927509011580">糟糕ï¼</translation>
+<translation id="3040955737384246924">{COUNT,plural, =0{在已åŒæ­¥ç„è£ç½®ä¸è‡³å°‘有 1 個項目}=1{1 個項目 (在已åŒæ­¥ç„è£ç½®ä¸é‚„有更å¤é …ç›®)}other{# 個項目 (在已åŒæ­¥ç„è£ç½®ä¸é‚„有更å¤é …ç›®)}}</translation>
<translation id="3041612393474885105">憑證資è¨</translation>
<translation id="3063697135517575841">Chrome ç›®å‰ç„¡æ³•é©—證您ç„信用å¡ï¼Œè«‹ç¨å¾Œå†è©¦ă€‚</translation>
<translation id="3093245981617870298">您處於離ç·ç‹€æ…‹ă€‚</translation>
@@ -206,15 +209,16 @@
<ph name="PLATFORM_TEXT" /></translation>
<translation id="3202578601642193415">最新記錄</translation>
<translation id="3207960819495026254">å·²å å…¥æ›¸ç±¤</translation>
-<translation id="3225919329040284222">伺æœå™¨å‘ˆç¾ç„憑證與內建ç„é æœŸæ¢ä»¶ä¸ç¬¦ă€‚我們在系統中é‡å°ç‰¹å®é«˜å®‰å…¨æ€§ç„網站內建了這些é æœŸæ¢ä»¶ï¼Œç›®ç„在於ä¿è­·æ‚¨ç„資料安全無è™ă€‚</translation>
<translation id="3226128629678568754">按下é‡æ–°è¼‰å…¥æŒ‰éˆ•ï¼Œé‡æ–°æ交載入網é æ‰€éœ€ç„è³‡æ–™ă€‚</translation>
<translation id="3228969707346345236">網é å·²ç¶“是<ph name="LANGUAGE" />ï¼Œç¿»è­¯ä½œæ¥­å¤±æ•—ă€‚</translation>
<translation id="323107829343500871">輸入 <ph name="CREDIT_CARD" /> ç„信用å¡å®‰å…¨ç¢¼</translation>
<translation id="3254409185687681395">ææ­¤é å å…¥æ›¸ç±¤</translation>
<translation id="3270847123878663523">復åŸé‡æ–°æ’åº(&amp;U)</translation>
<translation id="3286538390144397061">ç«‹å³é‡æ–°å•Ÿå‹•</translation>
+<translation id="3303855915957856445">找ä¸åˆ°ç›¸ç¬¦ç„æœå°‹çµæœ</translation>
<translation id="3305707030755673451">您已在 <ph name="TIME" />使用åŒæ­¥é€é—œå¯†èªå°è³‡æ–™é€²è¡Œå å¯†ï¼Œè«‹è¼¸å…¥é€é—œå¯†èªé–‹å§‹é€²è¡ŒåŒæ­¥ă€‚</translation>
<translation id="333371639341676808">防止此網é ç”¢ç”Ÿå…¶ä»–å°è©±æ–¹å¡ă€‚</translation>
+<translation id="3338095232262050444">安全</translation>
<translation id="3340978935015468852">設å®</translation>
<translation id="3345135638360864351">無法將您ç„網站存å–è¦æ±‚傳é€çµ¦<ph name="NAME" />,請å†è©¦ä¸€æ¬¡ă€‚</translation>
<translation id="3355823806454867987">è®æ›´ Proxy 設å®...</translation>
@@ -232,6 +236,7 @@
<translation id="3452404311384756672">æ“·å–é–“é”ï¼</translation>
<translation id="3462200631372590220">é±è—詳細資料</translation>
<translation id="3479539252931486093">這是未é æœŸç„情æ³å—?<ph name="BEGIN_LINK" />é€çŸ¥æˆ‘們<ph name="END_LINK" /></translation>
+<translation id="3479552764303398839">ç¾åœ¨ä¸è¦</translation>
<translation id="348000606199325318">當機 IDï¼<ph name="CRASH_LOCAL_ID" /> (伺æœå™¨ IDï¼<ph name="CRASH_ID" />)</translation>
<translation id="3498215018399854026">我們æ«æ™‚無法與您ç„家長è¯çµ¡ï¼Œè«‹å†è©¦ä¸€æ¬¡ă€‚</translation>
<translation id="3527085408025491307">資料夾</translation>
@@ -240,6 +245,7 @@
<translation id="3542684924769048008">é¸æ“‡å¯†ç¢¼ï¼</translation>
<translation id="3549644494707163724">使用您ç„é€é—œå¯†èªå°æ‰€æœ‰å·²åŒæ­¥è™•ç†ç„資料進行å å¯†</translation>
<translation id="3549761410225185768">還有 <ph name="NUM_TABS_MORE" /> 個分é ...</translation>
+<translation id="3555561725129903880">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證來自 <ph name="DOMAIN2" />。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3566021033012934673">您ç„連ç·ä¸æ˜¯ç§äººé€£ç·</translation>
<translation id="3583757800736429874">é‡å移動(&amp;R)</translation>
<translation id="3586931643579894722">é±è—詳細資è¨</translation>
@@ -251,12 +257,15 @@
<translation id="3623476034248543066">顯示政策值</translation>
<translation id="3630155396527302611">如æœç¨‹å¼å·²åˆ—在å…許存å–網路ç„清單中,建議您
å¾æ¸…單中將其移除,然後å†é‡æ–°å å…¥ă€‚</translation>
+<translation id="3638794133396384728">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證已éæœŸă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚電腦ç„時é˜ç›®å‰è¨­ç‚º <ph name="CURRENT_TIME" />,這是正確ç„時間å—?如æœä¸æ˜¯ç„話,請更新系統時é˜ï¼Œç„¶å¾Œé‡æ–°æ•´ç†é€™å€‹ç¶²é ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3648607100222897006">這些實驗性åŸèƒ½é¨æ™‚都有å¯èƒ½è®å‹•ă€ä¸­æ–·æˆ–æ¶ˆå¤±ă€‚æˆ‘å€‘å®Œå…¨ç„¡æ³•ä¿è­‰å•Ÿç”¨é€™äº›å¯¦é©—性åŸèƒ½æœƒå°è‡´ä½•ç¨®å¾Œæœï¼Œæ‚¨ç„ç€è¦½å™¨èªªä¸å®æœƒçªç„¶è‡ªå·±ç‡’æ‰ă€‚當然這åªæ˜¯ç©ç¬‘話,ä¸é您ç„ç€è¦½å™¨å¯èƒ½çœŸç„會刪除您ç„所有資料,或是æ„外洩æ¼æ‚¨ç„安全性和é±ç§æ¬è¨­å®ă€‚åªè¦æ‚¨å•Ÿç”¨äº†ä»»ä½•å¯¦é©—性åŸèƒ½ï¼Œé€™å€‹ç€è¦½å™¨ç„所有使用者都會啟用該åŸèƒ½ă€‚使用時請務必å°å¿ƒè¬¹æ…。</translation>
<translation id="3650584904733503804">é©—è­‰æˆåŸ</translation>
<translation id="3655670868607891010">如æœæ‚¨ç¶“常看到這個é é¢ï¼Œè«‹åƒè€ƒé€™äº›èªªæ˜ï¼<ph name="HELP_LINK" />。</translation>
<translation id="3658742229777143148">修訂版本</translation>
+<translation id="3678029195006412963">無法簽署è¦æ±‚</translation>
<translation id="3681007416295224113">憑證資è¨</translation>
<translation id="3693415264595406141">密碼ï¼</translation>
+<translation id="3696411085566228381">ç„¡</translation>
<translation id="3700528541715530410">糟糕ï¼æ‚¨æ²’有這個網é ç„å­˜å–æ¬é™ă€‚</translation>
<translation id="3704609568417268905"><ph name="TIME" />,<ph name="BOOKMARKED" />,<ph name="TITLE" />,<ph name="DOMAIN" /></translation>
<translation id="370665806235115550">載入中…</translation>
@@ -264,7 +273,6 @@
<translation id="3714780639079136834">開啟行動數æ“或 Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />檢查 Proxyă€é˜²ç«ç‰†å’Œ DNS 設å®<ph name="END_LINK" /></translation>
<translation id="3739623965217189342">您複製ç„連çµ</translation>
-<translation id="3744899669254331632"><ph name="SITE" /> 傳é€ç„憑證å—åˆ°å¹²æ“¾ï¼Œé€ æˆ Chromium 無法處ç†ï¼Œå› æ­¤æ‚¨ç›®å‰ç„¡æ³•é€ è¨ªè©²ç¶²ç«™ă€‚網路錯誤和攻æ“é€å¸¸æ˜¯æ«æ™‚性狀態,因此這個網é å¯èƒ½ç¨å¾Œå°±æœƒæ¢å¾©æ­£å¸¸é‹ä½œă€‚</translation>
<translation id="375403751935624634">伺æœå™¨éŒ¯èª¤ï¼Œç¿»è­¯ä½œæ¥­å¤±æ•—。</translation>
<translation id="3759461132968374835">最近沒有收到當機資è¨ă€‚當機å›å ±åŸèƒ½åœç”¨æ™‚發生ç„當機ä¸æœƒåˆ—åœ¨é€™è£¡ă€‚</translation>
<translation id="3788090790273268753">這個網站ç„憑證將於 2016 年到期,且憑證éˆçµåŒ…å«ä½¿ç”¨ SHA-1 進行簽署ç„æ†‘è­‰ă€‚</translation>
@@ -276,19 +284,25 @@
<translation id="3884278016824448484">è£ç½®è­˜åˆ¥ç¢¼ç™¼ç”Ÿè¡çª</translation>
<translation id="3885155851504623709">轄å€</translation>
<translation id="3901925938762663762">這張信用å¡å·²é期</translation>
+<translation id="3910267023907260648">ä½ å˜—è©¦é€£ä¸ <ph name="DOMAIN" />,但伺æœå™¨ç„憑證是以防護å›è–„å¼±ç„ç°½ç« æ¼”ç®—æ³•é€²è¡Œç°½ç½²ă€‚é€™ä»£è¡¨ä¼ºæœå™¨æä¾›ç„安全性憑證å¯èƒ½é­åˆ°å½é€ ï¼Œè€Œä¸”這個伺æœå™¨å¯èƒ½ä¸¦ä¸æ˜¯ä½ ç„目標伺æœå™¨ (ä½ ç„連ç·å°è±¡å¯èƒ½æ˜¯æ”»æ“者ç„電腦)。<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3933571093587347751">{1,plural, =1{這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證é å®æ˜å¤©æ‰ç”Ÿæ•ˆă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" />}other{這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證é å® # 天後æ‰ç”Ÿæ•ˆă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" />}}</translation>
<translation id="3934680773876859118">無法載入 PDF 文件</translation>
<translation id="3963721102035795474">閱讀器模å¼</translation>
+<translation id="397105322502079400">計算中…</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> é­åˆ°å°é–</translation>
+<translation id="40103911065039147">{URL_count,plural, =1{附近有 1 個網é }other{附近有 # 個網é }}</translation>
<translation id="4021036232240155012">DNS 這項網路æœå‹™æœƒå°‡ç¶²ç«™ç„å稱轉譯æˆç¶²é›ç¶²è·¯ä½å€ă€‚</translation>
<translation id="4030383055268325496">復åŸæ–°å¢(&amp;U)</translation>
-<translation id="4032534284272647190">ç€è¦½ <ph name="URL" /> é­åˆ°æ‹’絕。</translation>
<translation id="404928562651467259">è­¦å‘</translation>
<translation id="4058922952496707368">éµă€Œ<ph name="SUBKEY" />ă€ï¼<ph name="ERROR" /></translation>
<translation id="4075732493274867456">用戶端和伺æœå™¨ä¸æ”¯æ´ä¸€èˆ¬ SSL é€è¨å”å®ç‰ˆæœ¬æˆ–å å¯†å¥—件。</translation>
<translation id="4079302484614802869">Proxy 設å®å·²è¨­ç‚ºä½¿ç”¨ .pac 指令碼網å€ï¼Œè€Œé固å®ç„ Proxy 伺æœå™¨ă€‚</translation>
<translation id="4103249731201008433">è£ç½®åºè™Ÿç„¡æ•ˆ</translation>
<translation id="4103763322291513355">è«‹å‰å¾€ &lt;strong&gt;chrome://policy&lt;/strong&gt; 查看列入黑åå–®ç„網å€æ¸…單,以å其他系統管ç†å“¡å¼·åˆ¶åŸ·è¡Œç„æ”¿ç­–ă€‚</translation>
+<translation id="4110615724604346410">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證å«æœ‰éŒ¯èª¤ă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4117700440116928470">系統ä¸æ”¯æ´é€™é …政策ç„範åœă€‚</translation>
+<translation id="4118212371799607889">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />ï¼›Chromium ä¸ä¿¡ä»»ä¼ºæœå™¨ç„å®‰å…¨æ€§æ†‘è­‰ă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{以åå¦å¤– 1 項表單資料}other{以åå¦å¤– # 項表單資料}}</translation>
<translation id="4130226655945681476">檢查網路ç·ă€æ•¸æ“機和路由器</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4169947484918424451">您希望 Chromium 儲存這張信用å¡å—?</translation>
@@ -296,6 +310,7 @@
<translation id="4176463684765177261">å·²åœç”¨</translation>
<translation id="4196861286325780578">é‡å移動(&amp;R)</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />檢查防ç«ç‰†å’Œé˜²æ¯’軟體設å®<ph name="END_LINK" /></translation>
+<translation id="4206349416402437184">{COUNT,plural, =0{ç„¡}=1{1 å€‹æ‡‰ç”¨ç¨‹å¼ ($1)}=2{2 å€‹æ‡‰ç”¨ç¨‹å¼ ($1ă€$2)}other{# å€‹æ‡‰ç”¨ç¨‹å¼ ($1ă€$2ă€$3)}}</translation>
<translation id="4220128509585149162">當機</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />嘗試執行網路診斷<ph name="END_LINK" />。</translation>
<translation id="4250680216510889253">å¦</translation>
@@ -304,14 +319,15 @@
<translation id="4269787794583293679">(沒有使用者å稱)</translation>
<translation id="4300246636397505754">家長建議</translation>
<translation id="4304224509867189079">登入</translation>
+<translation id="432290197980158659">這個伺æœå™¨ç„憑證ä¸ç¬¦åˆå…§å»ºç„é æœŸæ¢ä»¶ă€‚我們é‡å°ç‰¹å®ç„高安全性網站內建了這些é æœŸæ¢ä»¶ï¼Œä»¥ç¢ºä¿ä½ ç„資料安全無è™ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4325863107915753736">找ä¸åˆ°æ–‡ç« </translation>
+<translation id="4331708818696583467">ä¸å®‰å…¨</translation>
<translation id="4372948949327679948">é æœŸç„ă€Œ<ph name="VALUE_TYPE" />ă€å€¼ă€‚</translation>
-<translation id="4377125064752653719">您嘗試å‰å¾€ <ph name="DOMAIN" />,但是發行者已撤é·ä¼ºæœå™¨æä¾›ç„æ†‘è­‰ă€‚åœ¨é€™ç¨®æƒ…æ³ä¸‹ï¼Œè«‹å‹¿ä¿¡ä»»ä¼ºæœå™¨æä¾›ç„安全性憑證,因為您ç„連ç·å°è±¡å¯èƒ½æ˜¯æ”»æ“者ç„é›»è…¦ă€‚</translation>
<translation id="4381091992796011497">使用者å稱ï¼</translation>
<translation id="4394049700291259645">åœç”¨</translation>
<translation id="4395129973926795186"><ph name="START_DATE" /> 至 <ph name="END_DATE" /></translation>
<translation id="4406896451731180161">æœå°‹çµæœ</translation>
-<translation id="4424024547088906515">伺æœå™¨ç„¡æ³•è­‰æ˜å…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證未å–å¾— Chrome ç„ä¿¡ä»»ă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–有攻æ“者攔截您ç„連ç·æ‰€è‡´ă€‚</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> ä¸æ¥å—ä½ ç„登入憑證,或是你å¯èƒ½æœªæä¾›ç™»å…¥æ†‘è­‰ă€‚</translation>
<translation id="443673843213245140">雖然已åœç”¨ Proxy,ä¸é已指å®æ˜ç¢º Proxy 設å®ă€‚</translation>
<translation id="4458874409874303848">安全網站</translation>
<translation id="4461847750548395463">Chrome 顯示這則è¨æ¯æ˜¯å› ç‚º Google å®‰å…¨ç¶²ç«™å·²ç¶“å•Ÿç”¨ă€‚</translation>
@@ -323,12 +339,12 @@
<translation id="4522570452068850558">詳細資è¨</translation>
<translation id="4558551763791394412">試試看åœç”¨æ“´å……åŸèƒ½ă€‚</translation>
<translation id="4587425331216688090">è¦å¾ Chrome 中移除地å€å—?</translation>
+<translation id="4589078953350245614">ä½ å˜—è©¦é€£ä¸ <ph name="DOMAIN" />,但伺æœå™¨æä¾›ç„æ†‘è­‰ç„¡æ•ˆă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4592951414987517459">æ‚¨ç„ <ph name="DOMAIN" /> 連ç·ä½¿ç”¨æ–°å‹å å¯†å¥—件進行å å¯†ă€‚</translation>
<translation id="4594403342090139922">復åŸåˆªé™¤(&amp;U)</translation>
+<translation id="4627442949885028695">é€é其他è£ç½®ç¹¼çºŒç€è¦½</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670097147947922288">您正在ç€è¦½æ“´å……åŸèƒ½é é¢ă€‚</translation>
-<translation id="467662567472608290">伺æœå™¨ç„¡æ³•è­‰æ˜å…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證å«æœ‰éŒ¯èª¤ă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–有攻æ“者攔截您ç„連ç·æ‰€è‡´ă€‚</translation>
-<translation id="4697214168136963651">系統已å°é– <ph name="URL" /></translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
<translation id="4708268264240856090">您ç„連ç·å·²ä¸­æ–·</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />執行 Windows 網路診斷<ph name="END_LINK" /></translation>
@@ -336,21 +352,26 @@
<translation id="4728558894243024398">å¹³å°</translation>
<translation id="4744603770635761495">å¯åŸ·è¡Œæª”ç„路徑</translation>
<translation id="4756388243121344051">記錄(&amp;H)</translation>
+<translation id="4759238208242260848">下載</translation>
<translation id="4764776831041365478"><ph name="URL" /> ç„網é å¯èƒ½æ«æ™‚無法使用或被永久移至新網å€ă€‚</translation>
<translation id="4771973620359291008">發生ä¸æ˜ç„éŒ¯èª¤ă€‚</translation>
<translation id="4782449893814226250">您已詢å•å®¶é•·æ˜¯å¦åŒæ„您造訪這個網é ă€‚</translation>
<translation id="4800132727771399293">請檢查您ç„有效期é™å’Œä¿¡ç”¨å¡å®‰å…¨ç¢¼ï¼Œç„¶å¾Œå†è©¦ä¸€æ¬¡</translation>
-<translation id="4807049035289105102">您目å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為這個網站傳é€ç„憑證是亂碼,Google Chrome 無法處ç†ă€‚網路錯誤和攻æ“行為é€å¸¸æ˜¯æ«æ™‚性ç„,因此這個網é å¯èƒ½ç¨å¾Œå°±æœƒæ­£å¸¸é‹ä½œă€‚</translation>
<translation id="4813512666221746211">網路錯誤</translation>
<translation id="4816492930507672669">ä¾é é¢å¤§å°è‡ªå‹•èª¿æ•´</translation>
<translation id="4850886885716139402">檢視</translation>
<translation id="4880827082731008257">æœå°‹ç´€éŒ„</translation>
+<translation id="4884656795097055129">系統會é©æ™‚顯示更å¤æ–‡ç« ă€‚</translation>
+<translation id="4895877746940133817"><ph name="TYPE_1" />ă€<ph name="TYPE_2" />,<ph name="TYPE_3" /></translation>
+<translation id="4914479371620770914">{URL_count,plural, =1{還有å¦å¤– 1 個網é }other{還有å¦å¤– # 個網é }}</translation>
<translation id="4923417429809017348">系統已將此網é å¾ä¸æ˜èªè¨€ç¿»è­¯æˆ<ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4926049483395192435">必須指å®ă€‚</translation>
<translation id="4930497775425430760">Chrome 顯示這則è¨æ¯æ˜¯å› ç‚ºæ‚¨é¦–次ç€è¦½ç„新網站需è¦ç²å¾—您ç„å®¶é•·æ ¸å‡†ă€‚</translation>
<translation id="495170559598752135">動作</translation>
<translation id="4958444002117714549">展開清單</translation>
+<translation id="4962322354953122629">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />ï¼›Chrome ä¸ä¿¡ä»»ä¼ºæœå™¨ç„å®‰å…¨æ€§æ†‘è­‰ă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="498957508165411911">將網é å…§å®¹ç”±<ph name="ORIGINAL_LANGUAGE" />翻譯æˆ<ph name="TARGET_LANGUAGE" />?</translation>
+<translation id="4989809363548539747">這是ä¸æ”¯æ´ç„外æ›ç¨‹å¼</translation>
<translation id="5002932099480077015">啟用後,Chrome 會將您ç„信用å¡è¤‡æœ¬å„²å­˜åœ¨é€™å€‹è£ç½®ä¸ï¼Œä»¥å å¿«è¡¨å–®å¡«å¯«é€Ÿåº¦ă€‚</translation>
<translation id="5019198164206649151">備份儲存狀態ä¸ä½³</translation>
<translation id="5023310440958281426">請查看您ç„管ç†å“¡æ”¿ç­–</translation>
@@ -358,13 +379,12 @@
<translation id="5031870354684148875">é—œæ–¼ă€ŒGoogle 翻譯ă€</translation>
<translation id="5040262127954254034">é±ç§æ¬</translation>
<translation id="5045550434625856497">密碼ä¸æ­£ç¢º</translation>
+<translation id="5056549851600133418">為您æ¨è–¦ç„文章</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />檢查 Proxy ä½å€<ph name="END_LINK" /></translation>
<translation id="5087286274860437796">伺æœå™¨æ†‘證目å‰ç„¡æ•ˆă€‚</translation>
<translation id="5089810972385038852">å·</translation>
-<translation id="5094747076828555589">伺æœå™¨ç„¡æ³•è­‰æ˜å…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證未å–å¾— Chromium ç„ä¿¡ä»»ă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–有攻æ“者攔截您ç„連ç·æ‰€è‡´ă€‚</translation>
<translation id="5095208057601539847">çœ</translation>
<translation id="5115563688576182185">(64 ä½å…ƒ)</translation>
-<translation id="5122371513570456792">找到 <ph name="NUMBER_OF_RESULTS" /> å€‹èˆ‡ă€Œ<ph name="SEARCH_STRING" />ă€ç›¸ç¬¦ç„<ph name="SEARCH_RESULTS" />。</translation>
<translation id="5141240743006678641">ä½¿ç”¨æ‚¨ç„ Google 憑證å°å·²åŒæ­¥è™•ç†ç„密碼進行å å¯†</translation>
<translation id="5145883236150621069">政策å›æ‡‰ä¸­å­˜åœ¨éŒ¯èª¤ä»£ç¢¼</translation>
<translation id="5171045022955879922">æœå°‹æˆ–輸入網å€</translation>
@@ -373,18 +393,18 @@
<translation id="5190835502935405962">書籤列</translation>
<translation id="5199729219167945352">實驗性åŸèƒ½</translation>
<translation id="5251803541071282808">雲端</translation>
+<translation id="5277279256032773186">在工作環境使用 Chrome å—?ä¼æ¥­å¯ä»¥ç®¡ç†å“¡å·¥ç„ Chrome 設å®ă€‚ç­è§£è©³æƒ…</translation>
<translation id="5299298092464848405">解æ政策時發生錯誤</translation>
<translation id="5300589172476337783">顯示</translation>
<translation id="5308689395849655368">當機報å‘åŸèƒ½å·²åœç”¨ă€‚</translation>
<translation id="5317780077021120954">儲存</translation>
<translation id="5327248766486351172">å稱</translation>
+<translation id="5359637492792381994">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證目å‰ç„¡æ•ˆă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="536296301121032821">無法儲存政策設å®</translation>
-<translation id="540969355065856584">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€å±¬ç¶²åŸŸç‚º <ph name="DOMAIN" />;其安全性憑證目å‰ç„¡æ•ˆă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截您ç„連ç·æ‰€è‡´ă€‚</translation>
<translation id="5421136146218899937">清除ç€è¦½è³‡æ–™...</translation>
<translation id="5430298929874300616">移除書籤</translation>
<translation id="5431657950005405462">找ä¸åˆ°æ‚¨ç„檔案</translation>
<translation id="5435775191620395718">ç›®å‰é¡¯ç¤ºé€™å€‹è£ç½®ç„æ­·å²ç´€éŒ„。<ph name="BEGIN_LINK" />ç­è§£è©³æƒ…<ph name="END_LINK" /></translation>
-<translation id="5437003064129843501">您ç„åŒæ­¥è™•ç†è³‡æ–™å—到自訂é€é—œå¯†èªä¿è­·ï¼Œå› æ­¤ç³»çµ±ç›®å‰ç„¡æ³•ç‚ºæ‚¨æ供個人化ç„æ¨è–¦å…§å®¹ă€‚</translation>
<translation id="5439770059721715174">ă€Œ<ph name="ERROR_PATH" />ă€ç™¼ç”Ÿæ¶æ§‹é©—證錯誤ï¼<ph name="ERROR" /></translation>
<translation id="5452270690849572955">找ä¸åˆ° <ph name="HOST_NAME" /> 網é </translation>
<translation id="5455374756549232013">政策時間戳記有誤</translation>
@@ -407,14 +427,18 @@
<translation id="5622887735448669177">您è¦é›¢é–‹é€™å€‹ç¶²ç«™å—?</translation>
<translation id="5629630648637658800">無法載入政策設å®</translation>
<translation id="5631439013527180824">è£ç½®ç®¡ç†ç¬¦è¨˜ç„¡æ•ˆ</translation>
-<translation id="5650551054760837876">找ä¸åˆ°æœå°‹çµæœă€‚</translation>
<translation id="5677928146339483299">å·²å°é–</translation>
<translation id="5710435578057952990">此網é ç„èº«åˆ†æœªç¶“é©—è­‰ă€‚</translation>
<translation id="5720705177508910913">ç›®å‰ä½¿ç”¨è€…</translation>
+<translation id="572328651809341494">最近開啟ç„分é </translation>
<translation id="5784606427469807560">驗證您ç„信用å¡æ™‚發生å•é¡Œă€‚請檢查網é›ç¶²è·¯é€£ç·ï¼Œç„¶å¾Œå†è©¦ä¸€æ¬¡ă€‚</translation>
<translation id="5785756445106461925">此外,這個網é å«æœ‰å…¶ä»–ä¸å®‰å…¨ç„資æºă€‚其他人å¯èƒ½æœƒåœ¨è³‡æºå‚³è¼¸æœŸé–“檢視這些資æºï¼Œæ”»æ“者也å¯èƒ½æœƒä¿®æ”¹é€™äº›è³‡æºï¼Œé€²è€Œè®æ›´ç¶²é å¤–è§€ă€‚</translation>
+<translation id="5786044859038896871">è¦å¡«å…¥ä½ ç„信用å¡è³‡è¨å—?</translation>
+<translation id="5803412860119678065">è¦å¡«å…¥ä½ ç„ <ph name="CARD_DETAIL" /> 資è¨å—?</translation>
<translation id="5810442152076338065">æ‚¨ç„ <ph name="DOMAIN" /> 連ç·ä½¿ç”¨éèˆç„å å¯†å¥—件進行å å¯†ă€‚</translation>
<translation id="5813119285467412249">é‡åæ–°å¢(&amp;R)</translation>
+<translation id="5814352347845180253">您å¯èƒ½ç„¡æ³•å†å­˜å– <ph name="SITE" /> å’Œå¦ä¸€äº›ç¶²ç«™ç„ä»˜è²»å…§å®¹ă€‚</translation>
+<translation id="5843436854350372569">ä½ å˜—è©¦é€£ä¸ <ph name="DOMAIN" />,但伺æœå™¨ç„憑證å«æœ‰é˜²è­·å›è–„å¼±ç„é‡‘é‘°ă€‚æ”»æ“者å¯èƒ½å·²ç ´è§£ç§å¯†é‡‘鑰,而且這個伺æœå™¨å¯èƒ½ä¸¦ä¸æ˜¯ä½ ç„目標伺æœå™¨ (ä½ ç„連ç·å°è±¡å¯èƒ½æ˜¯æ”»æ“者ç„電腦)。<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="5855235287355719921">Chrome 顯示這則è¨æ¯æ˜¯å› ç‚ºæ‚¨ç„管ç†å“¡å·²å°é–é€™å€‹ç¶²ç«™ă€‚</translation>
<translation id="5857090052475505287">新資料夾</translation>
<translation id="5869405914158311789">無法連ä¸é€™å€‹ç¶²ç«™</translation>
@@ -422,6 +446,7 @@
<translation id="5872918882028971132">家長建議</translation>
<translation id="59107663811261420">é€™å€‹å•†å®¶ç„ Google Payments ä¸æ”¯æ´æ­¤é¡å‹å¡ç‰‡ï¼Œè«‹é¸å–其他å¡ç‰‡ă€‚</translation>
<translation id="59174027418879706">已啟用</translation>
+<translation id="5926846154125914413">您å¯èƒ½ç„¡æ³•å†å­˜å–部分網站ç„ä»˜è²»å…§å®¹ă€‚</translation>
<translation id="5966707198760109579">週</translation>
<translation id="5967867314010545767">å¾ç´€éŒ„中移除</translation>
<translation id="5975083100439434680">縮å°</translation>
@@ -433,12 +458,12 @@
<translation id="604124094241169006">自動</translation>
<translation id="6042308850641462728">詳細資è¨</translation>
<translation id="6060685159320643512">請注æ„,這些實驗性åŸèƒ½å¯èƒ½å°é›»è…¦æœ‰å®³</translation>
+<translation id="6108835911243775197">{COUNT,plural, =0{ç„¡}=1{1}other{#}}</translation>
<translation id="6146055958333702838">檢查您ç„網路ç·æ˜¯å¦ç©©å›ºé€£æ¥ă€‚é‡æ–°å•Ÿå‹•æ‚¨å¯èƒ½æ­£åœ¨ä½¿ç”¨ç„任何路由器ă€
數æ“機或其他網路è£ç½®ă€‚</translation>
<translation id="614940544461990577">建議å法ï¼</translation>
<translation id="6150607114729249911">注æ„ï¼æ‚¨å¿…須徵求家長åŒæ„,æ‰èƒ½ç€è¦½é€™å€‹ç¶²é ă€‚</translation>
<translation id="6151417162996330722">伺æœå™¨æ†‘è­‰ç„有效期é™å¤ªé•·ă€‚</translation>
-<translation id="6154808779448689242">傳å›ç„政策符記與目å‰ç¬¦è¨˜ä¸ç›¸ç¬¦</translation>
<translation id="6165508094623778733">ç­è§£è©³æƒ…</translation>
<translation id="6203231073485539293">檢查網é›ç¶²è·¯é€£ç·</translation>
<translation id="6218753634732582820">è¦å¾ Chromium 中移除地å€å—?</translation>
@@ -451,24 +476,30 @@
<translation id="6328639280570009161">建議åœç”¨ç¶²è·¯é æ¸¬åŸèƒ½</translation>
<translation id="6337534724793800597">ä¾å稱篩é¸æ”¿ç­–</translation>
<translation id="6342069812937806050">剛剛</translation>
+<translation id="6345221851280129312">大å°ä¸æ˜</translation>
<translation id="6355080345576803305">公開工作é段覆寫</translation>
<translation id="6358450015545214790">我需è¦é€²ä¸€æ­¥è³‡è¨</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{以åå¦å¤– 1 個建議項目}other{以åå¦å¤– # 個建議項目}}</translation>
<translation id="6387478394221739770">想æ¶å…ˆè©¦ç”¨é…·ç‚«ç„ Chrome æ–°åŸèƒ½å—?請å‰å¾€ chrome.com/beta 安è£æ¸¬è©¦ç‰ˆă€‚</translation>
-<translation id="641480858134062906">無法載入 <ph name="URL" /></translation>
+<translation id="6389758589412724634">Chromium 嘗試顯示這個網é æ™‚ç”¨ç›¡äº†è¨˜æ†¶é«”ă€‚</translation>
+<translation id="6416403317709441254">ç›®å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為這個網站傳é€ç„憑證å«æœ‰äº‚碼,Chromium 無法處ç†ă€‚網路錯誤和攻æ“行為é€å¸¸æ˜¯æ«æ™‚性ç„,因此這個網é å¯èƒ½ç¨å¾Œå°±æœƒæ¢å¾©æ­£å¸¸ç‹€æ…‹ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6417515091412812850">無法檢查憑證是å¦å·²é­æ’¤é·ă€‚</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> 拒絕連ç·ă€‚</translation>
<translation id="6445051938772793705">國家/地å€</translation>
<translation id="6451458296329894277">確èªé‡æ–°æ交表單</translation>
<translation id="6458467102616083041">由於政策åœç”¨äº†é è¨­æœå°‹ï¼Œå› æ­¤é­åˆ°ç•¥é。</translation>
+<translation id="6462969404041126431">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;伺æœå™¨ç„安全性憑證å¯èƒ½é­åˆ°æ’¤é·ă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="647261751007945333">è£ç½®æ”¿ç­–</translation>
<translation id="6489534406876378309">開始ä¸å‚³ç•¶æ©Ÿå ±å‘</translation>
<translation id="6529602333819889595">é‡å刪除(&amp;R)</translation>
+<translation id="6534179046333460208">實體化網路建議</translation>
<translation id="6550675742724504774">é¸é …</translation>
+<translation id="6593753688552673085">ä¸åˆ° <ph name="UPPER_ESTIMATE" /></translation>
<translation id="6596325263575161958">å å¯†é¸é …</translation>
<translation id="662080504995468778">ä¸é›¢é–‹</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> æœå°‹</translation>
-<translation id="6634865548447745291">您目å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為<ph name="BEGIN_LINK" />這個網站ç„憑證已é­æ’¤é·<ph name="END_LINK" />ă€‚ç¶²è·¯éŒ¯èª¤å’Œæ”»æ“行為é€å¸¸æ˜¯æ«æ™‚性ç„,所以這個網é å¯èƒ½ç¨å¾Œå°±èƒ½æ­£å¸¸ä½¿ç”¨ă€‚</translation>
<translation id="6644283850729428850">這項政策已é­å–ä»£ă€‚</translation>
+<translation id="6652240803263749613">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />;電腦ç„作業系統ä¸ä¿¡ä»»ä¼ºæœå™¨ç„å®‰å…¨æ€§æ†‘è­‰ă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6656103420185847513">編輯資料夾</translation>
<translation id="6660210980321319655">已自動å›å ± (<ph name="CRASH_TIME" />)</translation>
<translation id="6671697161687535275">è¦å¾ Chromium 中移除表單填寫建議å—?</translation>
@@ -476,6 +507,7 @@
<translation id="6710213216561001401">è¿”å›</translation>
<translation id="6710594484020273272">&lt;輸入æœå°‹å­—è©&gt;</translation>
<translation id="6711464428925977395">Proxy 伺æœå™¨ç™¼ç”ŸéŒ¯èª¤ï¼Œæˆ–是ä½å€ä¸æ­£ç¢ºă€‚</translation>
+<translation id="6731320287533051140">{COUNT,plural, =0{無}=1{1 個項目}other{# 個項目}}</translation>
<translation id="674375294223700098">ä¸æ˜ç„伺æœå™¨æ†‘è­‰éŒ¯èª¤ă€‚</translation>
<translation id="6753269504797312559">政策值</translation>
<translation id="6757797048963528358">您ç„è£ç½®å·²é€²å…¥ç¡çœ æ¨¡å¼ă€‚</translation>
@@ -487,7 +519,6 @@
<translation id="6891596781022320156">系統ä¸æ”¯æ´é€™é …政策ç„層ç´ă€‚</translation>
<translation id="6895330447102777224">您ç„信用å¡å·²é€éé©—è­‰</translation>
<translation id="6897140037006041989">使用者代ç†ç¨‹å¼</translation>
-<translation id="6903907808598579934">é–‹å•ŸåŒæ­¥è™•ç†åŸèƒ½</translation>
<translation id="6915804003454593391">使用者ï¼</translation>
<translation id="6957887021205513506">伺æœå™¨æ†‘證疑似å½é€ ă€‚</translation>
<translation id="6965382102122355670">確å®</translation>
@@ -495,9 +526,11 @@
<translation id="6970216967273061347">å€</translation>
<translation id="6973656660372572881">已指å®å›ºå®ç„ Proxy 伺æœå™¨å’Œ .pac 指令碼網å€ă€‚</translation>
<translation id="6989763994942163495">顯示進é設å®...</translation>
+<translation id="7000990526846637657">找ä¸åˆ°ä»»ä½•ç´€éŒ„é …ç›®</translation>
+<translation id="7009986207543992532">ä½ å˜—è©¦é€£ä¸ <ph name="DOMAIN" />,但伺æœå™¨æä¾›ç„憑證有效期é™å¤ªé•·ï¼Œå› æ­¤é›£ä»¥ä¿¡ä»»ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7012363358306927923">中國é€è¯</translation>
+<translation id="7012372675181957985">ä½ ä»å¯å‰å¾€ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> å­˜å– Google 帳戶中ä¿å­˜ç„å„種ç€è¦½ç´€éŒ„</translation>
<translation id="7029809446516969842">密碼</translation>
-<translation id="7050187094878475250">您嘗試連ç·è‡³ <ph name="DOMAIN" />,但伺æœå™¨æä¾›ç„憑證有效期é™å¤ªé•·ï¼Œå› æ­¤é›£ä»¥ä¿¡ä»»ă€‚</translation>
<translation id="7087282848513945231">郡</translation>
<translation id="7088615885725309056">較èˆè¨˜éŒ„</translation>
<translation id="7090678807593890770">è«‹é€é Google æœå°‹ă€Œ<ph name="LINK" />ă€</translation>
@@ -516,13 +549,13 @@
<translation id="7246609911581847514">Chrome 顯示這則è¨æ¯æ˜¯å› ç‚ºæ‚¨é¦–次ç€è¦½ç„新網站需è¦ç²å¾—管ç†å“¡æ ¸å‡†ă€‚</translation>
<translation id="724975217298816891">請輸入 <ph name="CREDIT_CARD" /> ç„有效日期和信用å¡å®‰å…¨ç¢¼ï¼Œæ›´æ–°æ‚¨ç„信用å¡è©³ç´°è³‡è¨ă€‚完æˆé©—證後,這個網站就會å–得您ç„信用å¡è©³ç´°è³‡è¨ă€‚</translation>
<translation id="725866823122871198">您電腦ç„日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•èˆ‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§äººé€£ç·ă€‚</translation>
-<translation id="7265986070661382626">您目å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為這個網站<ph name="BEGIN_LINK" />使用憑證固å®åŸèƒ½<ph name="END_LINK" />ă€‚ç¶²è·¯éŒ¯èª¤å’Œæ”»æ“行為é€å¸¸æ˜¯æ«æ™‚性ç„,所以這個網é å¯èƒ½ç¨å¾Œå°±èƒ½æ­£å¸¸ä½¿ç”¨ă€‚</translation>
<translation id="7269802741830436641">這個網é å«æœ‰é‡æ–°å°å‘迴圈</translation>
<translation id="7275334191706090484">å—管ç†æ›¸ç±¤</translation>
<translation id="7298195798382681320">建議æ¡ç”¨</translation>
-<translation id="7301833672208172928">é–‹å•Ÿæ­·å²ç´€éŒ„åŒæ­¥è™•ç†åŸèƒ½</translation>
+<translation id="7309308571273880165">當機報å‘æ“·å–時間ï¼<ph name="CRASH_TIME" /> (使用者è¦æ±‚ä¸å‚³ï¼Œä½†å°æœªä¸å‚³)</translation>
<translation id="7334320624316649418">é‡åé‡æ–°æ’åº(&amp;R)</translation>
<translation id="733923710415886693">伺æœå™¨æ†‘證未ä¾æ†‘è­‰é€æ˜åŒ–æ”¿ç­–å…¬é–‹ă€‚</translation>
+<translation id="7351800657706554155">ç›®å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為這個網站ç„憑證已é­æ’¤é·ă€‚網路錯誤和攻æ“行為é€å¸¸æ˜¯æ«æ™‚性ç„,因此這個網é å¯èƒ½ç¨å¾Œå°±æœƒæ¢å¾©æ­£å¸¸ç‹€æ…‹ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="7353601530677266744">命令列</translation>
<translation id="7372973238305370288">æœå°‹çµæœ</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -541,16 +574,17 @@
<translation id="7469372306589899959">正在驗證信用å¡</translation>
<translation id="7481312909269577407">å¾€å‰</translation>
<translation id="7485870689360869515">找ä¸åˆ°ä»»ä½•è³‡æ–™ă€‚</translation>
+<translation id="7508255263130623398">傳å›ç„政策è£ç½® ID 沒有任何內容,或是與目å‰ç„è£ç½® ID ä¸ç¬¦</translation>
<translation id="7514365320538308">下載</translation>
<translation id="7518003948725431193">找ä¸åˆ°æ­¤ç¶²å€ç„網é ï¼<ph name="URL" /></translation>
<translation id="7537536606612762813">強制</translation>
<translation id="7542995811387359312">由於這個表單並未æ¡ç”¨å å¯†é€£ç·æ–¹å¼ï¼Œæ‰€ä»¥ä¿¡ç”¨å¡è‡ªå‹•å¡«å…¥åŸèƒ½å·²åœç”¨ă€‚</translation>
<translation id="7549584377607005141">這個網é éœ€è¦ä½¿ç”¨æ‚¨å…ˆå‰è¼¸å…¥ç„資料æ‰èƒ½æ­£ç¢ºé¡¯ç¤ºă€‚您å¯ä»¥é‡æ–°å‚³é€é€™äº›è³‡æ–™ï¼Œä¸é這麼å會é‡è¤‡åŸ·è¡Œé€™å€‹ç¶²é å…ˆå‰åŸ·è¡Œéç„ä»»ä½•å‹•ä½œă€‚</translation>
<translation id="7554791636758816595">æ–°å¢åˆ†é </translation>
-<translation id="7567204685887185387">伺æœå™¨ç„¡æ³•è­‰æ˜å…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證是以欺è©æ–¹å¼ç™¼è¡Œă€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–有攻æ“者攔截您ç„連ç·æ‰€è‡´ă€‚</translation>
<translation id="7568593326407688803">此網é ç‚º<ph name="ORIGINAL_LANGUAGE" />您è¦ç¿»è­¯ç¶²é å…§å®¹å—?</translation>
<translation id="7569952961197462199">è¦å¾ Chrome 中移除信用å¡å—?</translation>
<translation id="7578104083680115302">在ä¸åŒç„è£ç½®ä¸é€éå„個網站和應用程å¼æ¶ˆè²»æ™‚,使用您讓 Google 儲存ç„信用å¡è³‡æ–™å³å¯å¿«é€Ÿä»˜æ¬¾ă€‚</translation>
+<translation id="7588950540487816470">實體化網路</translation>
<translation id="7592362899630581445">伺æœå™¨æ†‘è­‰ç„å稱ä¸ç¬¦åˆé™åˆ¶ă€‚</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ç›®å‰ç„¡æ³•è™•ç†é€™é …è¦æ±‚。</translation>
<translation id="7600965453749440009">一律ä¸ç¿»è­¯<ph name="LANGUAGE" /></translation>
@@ -561,6 +595,7 @@
<translation id="7637571805876720304">è¦å¾ Chromium 中移除信用å¡å—?</translation>
<translation id="765676359832457558">é±è—進é設å®...</translation>
<translation id="7658239707568436148">å–消</translation>
+<translation id="7667346355482952095">傳å›ç„政策憑證沒有任何內容,或是與目å‰ç„憑證ä¸ç¬¦</translation>
<translation id="7668654391829183341">ä¸æ˜ç„è£ç½®</translation>
<translation id="7674629440242451245">想æ¶å…ˆè©¦ç”¨é…·ç‚«ç„ Chrome æ–°åŸèƒ½å—?請å‰å¾€ chrome.com/dev 安è£é–‹ç™¼äººå“¡ç‰ˆă€‚</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />繼續å‰å¾€ <ph name="SITE" /> 網站 (ä¸å®‰å…¨)<ph name="END_LINK" /></translation>
@@ -577,10 +612,10 @@
<translation id="780301667611848630">ä¸ç”¨äº†ï¼Œè¬è¬</translation>
<translation id="7805768142964895445">狀態</translation>
<translation id="7813600968533626083">è¦å¾ Chrome 中移除建議å—?</translation>
+<translation id="7815407501681723534">找到 <ph name="NUMBER_OF_RESULTS" /> å€‹èˆ‡ă€Œ<ph name="SEARCH_STRING" />ă€ç›¸ç¬¦ç„<ph name="SEARCH_RESULTS" /></translation>
<translation id="785549533363645510">ä¸é,這並ä¸æ„味著您å¯ä»¥å®Œå…¨é±å½¢ă€‚使用無痕模å¼æ™‚,您ç„雇主和網é›ç¶²è·¯æœå‹™ä¾›æ‡‰å•†ä»ç„¶å¯ä»¥è¿½è¹¤æ‚¨ç„ç€è¦½ç´€éŒ„,您所造訪ç„網站也å¯èƒ½æœƒè¨˜éŒ„您ç„ç€è¦½è¡Œç‚ºă€‚</translation>
<translation id="7887683347370398519">è«‹æª¢æŸ¥æ‚¨ç„ CVC,然後å†è©¦ä¸€æ¬¡</translation>
<translation id="7894616681410591072">注æ„ï¼æ‚¨éœ€è¦å–å¾— <ph name="NAME" /> ç„æˆæ¬æ‰èƒ½å­˜å–這個網é ă€‚</translation>
-<translation id="790025292736025802">找ä¸åˆ° <ph name="URL" /></translation>
<translation id="7912024687060120840">在以下資料夾中ï¼</translation>
<translation id="7920092496846849526">您已詢å•å®¶é•·æ˜¯å¦åŒæ„您造訪這個網é ă€‚</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
@@ -593,9 +628,10 @@
<translation id="7995512525968007366">未指å®</translation>
<translation id="8012647001091218357">我們æ«æ™‚無法與您ç„家長è¯çµ¡ï¼Œè«‹å†è©¦ä¸€æ¬¡ă€‚</translation>
<translation id="8034522405403831421">這是<ph name="SOURCE_LANGUAGE" />網é ï¼Œéœ€è¦ç¿»è­¯æˆ<ph name="TARGET_LANGUAGE" />å—?</translation>
-<translation id="8034955203865359138">找ä¸åˆ°ä»»ä½•ç´€éŒ„項目。</translation>
<translation id="8088680233425245692">ç„¡æ³•æŸ¥çœ‹æ–‡ç« ă€‚</translation>
+<translation id="8089520772729574115">ä¸åˆ° 1 MB</translation>
<translation id="8091372947890762290">å°æœªåœ¨ä¼ºæœå™¨ä¸å•Ÿå‹•</translation>
+<translation id="8129262335948759431">資料é‡ä¸æ˜</translation>
<translation id="8131740175452115882">確èª</translation>
<translation id="8134994873729925007">找ä¸åˆ° <ph name="HOST_NAME" /> ç„伺æœå™¨ <ph name="BEGIN_ABBR" />DNS ä½å€<ph name="END_ABBR" />。</translation>
<translation id="8149426793427495338">您ç„電腦已進入ç¡çœ æ¨¡å¼ă€‚</translation>
@@ -604,6 +640,7 @@
<translation id="8201077131113104583">æ“´å……åŸèƒ½ (IDï¼ă€Œ<ph name="EXTENSION_ID" />ă€) ç„更新網å€ç„¡æ•ˆă€‚</translation>
<translation id="8218327578424803826">指派ç„ä½ç½®ï¼</translation>
<translation id="8225771182978767009">設å®é€™éƒ¨é›»è…¦ç„使用者é¸æ“‡å°é–é€™å€‹ç¶²ç«™ă€‚</translation>
+<translation id="822964464349305906"><ph name="TYPE_1" />ă€<ph name="TYPE_2" /></translation>
<translation id="8241707690549784388">您尋找ç„網é ä½¿ç”¨äº†æ‚¨è¼¸å…¥ç„è³‡æ–™ă€‚è¿”å›è©²é æœƒé‡è¤‡æ‚¨å‰›æ‰ç„è¡Œå‹•ă€‚æ‚¨ç¢ºå®è¦ç¹¼çºŒå—?</translation>
<translation id="8249320324621329438">ä¸æ¬¡æ“·å–時間ï¼</translation>
<translation id="8261506727792406068">刪除</translation>
@@ -616,12 +653,17 @@
<translation id="8349305172487531364">書籤列</translation>
<translation id="8363502534493474904">關閉飛航模å¼</translation>
<translation id="8364627913115013041">未設å®ă€‚</translation>
+<translation id="8380941800586852976">ä¸å®‰å…¨</translation>
<translation id="8412145213513410671">當機次數 (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">您必須輸入兩次相åŒç„é€é—œå¯†èªă€‚</translation>
<translation id="8428213095426709021">設å®</translation>
+<translation id="8433057134996913067">您會因此登出大å¤æ•¸ç¶²ç«™ă€‚</translation>
<translation id="8437238597147034694">復åŸç§»å‹•(&amp;U)</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 張信用å¡}other{# 張信用å¡}}</translation>
+<translation id="8483780878231876732">如è¦ä½¿ç”¨æ‚¨ç„ Google 帳戶中ç„信用å¡ï¼Œè«‹ç™»å…¥ Chrome</translation>
<translation id="8488350697529856933">é©ç”¨å°è±¡</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ç„å›æ‡‰æ™‚é–“é長。</translation>
+<translation id="852346902619691059">這個伺æœå™¨ç„¡æ³•è­‰æ˜æ‰€åœ¨ç¶²åŸŸæ˜¯ <ph name="DOMAIN" />ï¼›è£ç½®ç„作業系統ä¸ä¿¡ä»»ä¼ºæœå™¨ç„å®‰å…¨æ€§æ†‘è­‰ă€‚é€™å¯èƒ½æ˜¯å› ç‚ºè¨­å®éŒ¯èª¤ï¼Œæˆ–是有攻æ“者攔截你ç„連ç·ă€‚<ph name="BEGIN_LEARN_MORE_LINK" />ç­è§£è©³æƒ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="8530504477309582336">Google Payments ä¸æ”¯æ´æ­¤é¡å‹å¡ç‰‡ï¼Œè«‹é¸å–其他å¡ç‰‡ă€‚</translation>
<translation id="8550022383519221471">您ç„網域無法使用åŒæ­¥è™•ç†æœå‹™</translation>
<translation id="8553075262323480129">無法判å®ç¶²é ç„èªè¨€ï¼Œç¿»è­¯ä½œæ¥­å¤±æ•—。</translation>
@@ -633,15 +675,12 @@
<translation id="8647750283161643317">全部é‡è¨­ç‚ºé è¨­å€¼</translation>
<translation id="8680787084697685621">帳戶登入詳細資料已éæœŸă€‚</translation>
<translation id="8703575177326907206">您到 <ph name="DOMAIN" /> ç„連ç·æœªå å¯†ă€‚</translation>
-<translation id="8713130696108419660">åˆå§‹ç°½å錯誤</translation>
<translation id="8725066075913043281">å†è©¦ä¸€æ¬¡</translation>
<translation id="8728672262656704056">您已啟用無痕模å¼ă€‚</translation>
<translation id="8730621377337864115">完æˆ</translation>
<translation id="8738058698779197622">您必須正確設å®æ™‚é˜ï¼Œæ‰èƒ½å»ºç«‹å®‰å…¨é€£ç·ă€‚這是因為網站驗證身分時所使用ç„憑證僅於特å®ä¸€æ®µæ™‚é–“å…§æœ‰æ•ˆă€‚ç”±æ–¼æ‚¨è£ç½®ç„時é˜ä¸æ­£ç¢ºï¼Œå› æ­¤ Chromium ç„¡æ³•é©—è­‰é€™äº›æ†‘è­‰ă€‚</translation>
<translation id="8740359287975076522">找ä¸åˆ° <ph name="HOST_NAME" /> ç„ &lt;abbr id="dnsDefinition"&gt;DNS ä½å€&lt;/abbr&gt;,正在診斷å•é¡Œă€‚</translation>
-<translation id="8741995161408053644">您ä»å¯å‰å¾€ <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> å­˜å– Google 帳戶中ä¿å­˜ç„å„種ç€è¦½ç´€éŒ„。</translation>
<translation id="8790007591277257123">é‡å刪除(&amp;R)</translation>
-<translation id="8790687370365610530">如è¦å–å¾—å€‹äººåŒ–ç„ Google æ¨è–¦å…§å®¹ï¼Œè«‹é–‹å•Ÿæ­·å²ç´€éŒ„åŒæ­¥è™•ç†åŸèƒ½ă€‚</translation>
<translation id="8798099450830957504">é è¨­</translation>
<translation id="8804164990146287819">é±ç§æ¬æ”¿ç­–</translation>
<translation id="8820817407110198400">書籤</translation>
@@ -663,13 +702,11 @@
<translation id="8971063699422889582">伺æœå™¨æ†‘證已éæœŸă€‚</translation>
<translation id="8987927404178983737">月</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8997023839087525404">該伺æœå™¨ç„憑證並未根æ“憑證é€æ˜åŒ–政策å°å¤–å…¬é–‹ă€‚éƒ¨åˆ†æ†‘è­‰å¿…é ˆç¬¦åˆé€™é …è¦å®ï¼Œä»¥ç¢ºä¿æ†‘證值得信任,ä¸æœƒè®“使用者é­åˆ°æ”»æ“。</translation>
<translation id="9001074447101275817"><ph name="DOMAIN" /> Proxy è¦æ±‚æ供使用者åç¨±å’Œå¯†ç¢¼ă€‚</translation>
<translation id="901974403500617787">這些設å®æœƒå¥—用至整個系統,åªæœ‰ä»¥ä¸‹ä½¿ç”¨è€…å¯è¨­å®ï¼<ph name="OWNER_EMAIL" />。</translation>
<translation id="9020542370529661692">此網é å…§å®¹å·²ç¿»è­¯æˆ<ph name="TARGET_LANGUAGE" /></translation>
<translation id="9038649477754266430">使用é æ¸¬æŸ¥è©¢å­—串æœå‹™ï¼Œè®“系統更快載入網é </translation>
<translation id="9039213469156557790">此外,這個網é å«æœ‰å…¶ä»–ä¸å®‰å…¨ç„資æºă€‚其他人å¯èƒ½æœƒåœ¨è³‡æºå‚³è¼¸æœŸé–“檢視這些資æºï¼Œæ”»æ“者也å¯èƒ½æœƒä¿®æ”¹é€™äº›è³‡æºï¼Œé€²è€Œè®æ›´ç¶²é è¡Œç‚ºă€‚</translation>
-<translation id="9049981332609050619">您嘗試連ç·è‡³ <ph name="DOMAIN" />,但伺æœå™¨æä¾›ç„æ†‘è­‰ç„¡æ•ˆă€‚</translation>
<translation id="9050666287014529139">é€é—œå¯†èª</translation>
<translation id="9065203028668620118">編輯</translation>
<translation id="9092364396508701805"><ph name="HOST_NAME" /> é é¢ç„¡æ³•æ­£å¸¸é‹ä½œ</translation>
diff --git a/chromium/components/subresource_filter.gypi b/chromium/components/subresource_filter.gypi
deleted file mode 100644
index 6fc89918897..00000000000
--- a/chromium/components/subresource_filter.gypi
+++ /dev/null
@@ -1,151 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/subresource_filter/core/browser
- 'target_name': 'subresource_filter_core_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../components/components.gyp:variations',
- '../components/prefs/prefs.gyp:prefs',
- 'subresource_filter_core_common',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'subresource_filter/core/browser/ruleset_distributor.h',
- 'subresource_filter/core/browser/ruleset_service.cc',
- 'subresource_filter/core/browser/ruleset_service.h',
- 'subresource_filter/core/browser/subresource_filter_constants.cc',
- 'subresource_filter/core/browser/subresource_filter_constants.h',
- 'subresource_filter/core/browser/subresource_filter_features.cc',
- 'subresource_filter/core/browser/subresource_filter_features.h',
- ],
- },
- {
- # GN version: //components/subresource_filter/core/browser:test_support
- 'target_name': 'subresource_filter_core_browser_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../components/components.gyp:variations',
- '../testing/gtest.gyp:gtest',
- 'subresource_filter_core_browser',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'subresource_filter/core/browser/subresource_filter_features_test_support.cc',
- 'subresource_filter/core/browser/subresource_filter_features_test_support.h',
- ],
- },
- {
- # GN version: //components/subresource_filter/core/common
- 'target_name': 'subresource_filter_core_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'subresource_filter/core/common/activation_state.cc',
- 'subresource_filter/core/common/activation_state.h',
- 'subresource_filter/core/common/closed_hash_map.h',
- 'subresource_filter/core/common/fuzzy_pattern_matching.cc',
- 'subresource_filter/core/common/fuzzy_pattern_matching.h',
- 'subresource_filter/core/common/knuth_morris_pratt.h',
- 'subresource_filter/core/common/memory_mapped_ruleset.cc',
- 'subresource_filter/core/common/memory_mapped_ruleset.h',
- 'subresource_filter/core/common/ngram_extractor.h',
- 'subresource_filter/core/common/string_splitter.h',
- 'subresource_filter/core/common/uint64_hasher.h',
- ],
- },
- ],
- 'conditions': [
- ['OS != "ios"', {
- 'targets': [
- {
- # GN version: //components/subresource_filter/content/common
- 'target_name': 'subresource_filter_content_common',
- 'type': 'static_library',
- 'dependencies': [
- '../content/content.gyp:content_common',
- '../ipc/ipc.gyp:ipc',
- 'subresource_filter_core_common',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'subresource_filter/content/common/subresource_filter_message_generator.cc',
- 'subresource_filter/content/common/subresource_filter_message_generator.h',
- 'subresource_filter/content/common/subresource_filter_messages.h',
- ],
- },
- {
- # GN version: //components/subresource_filter/content/renderer
- 'target_name': 'subresource_filter_content_renderer',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../content/content.gyp:content_renderer',
- '../ipc/ipc.gyp:ipc',
- 'subresource_filter_content_common',
- 'subresource_filter_core_common',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'subresource_filter/content/renderer/ruleset_dealer.cc',
- 'subresource_filter/content/renderer/ruleset_dealer.h',
- 'subresource_filter/content/renderer/subresource_filter_agent.cc',
- 'subresource_filter/content/renderer/subresource_filter_agent.h',
- ],
- },
- {
- # GN version: //components/subresource_filter/content/browser
- 'target_name': 'subresource_filter_content_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../ipc/ipc.gyp:ipc',
- 'subresource_filter_content_common',
- 'subresource_filter_core_browser',
- 'subresource_filter_core_common',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'subresource_filter/content/browser/content_ruleset_distributor.cc',
- 'subresource_filter/content/browser/content_ruleset_distributor.h',
- 'subresource_filter/content/browser/content_subresource_filter_driver.cc',
- 'subresource_filter/content/browser/content_subresource_filter_driver.h',
- 'subresource_filter/content/browser/content_subresource_filter_driver_factory.cc',
- 'subresource_filter/content/browser/content_subresource_filter_driver_factory.h',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/subresource_filter/DEPS b/chromium/components/subresource_filter/DEPS
index f913c8b7ef8..b69525f4b1e 100644
--- a/chromium/components/subresource_filter/DEPS
+++ b/chromium/components/subresource_filter/DEPS
@@ -1,7 +1,11 @@
include_rules = [
"+components/prefs",
+ "+components/test_runner",
"+components/variations",
# subresource_filter is a layered component; subdirectories must explicitly
# introduce the ability to use non-core layers as appropriate.
"-components/subresource_filter/content",
+ "+net/base",
+ "+third_party/flatbuffers",
+ "+third_party/protobuf",
]
diff --git a/chromium/components/subresource_filter/content/browser/BUILD.gn b/chromium/components/subresource_filter/content/browser/BUILD.gn
index f196665c38c..93a56b29842 100644
--- a/chromium/components/subresource_filter/content/browser/BUILD.gn
+++ b/chromium/components/subresource_filter/content/browser/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser") {
+static_library("browser") {
sources = [
"content_ruleset_distributor.cc",
"content_ruleset_distributor.h",
@@ -10,6 +10,8 @@ source_set("browser") {
"content_subresource_filter_driver.h",
"content_subresource_filter_driver_factory.cc",
"content_subresource_filter_driver_factory.h",
+ "subresource_filter_navigation_throttle.cc",
+ "subresource_filter_navigation_throttle.h",
]
deps = [
"//base",
@@ -29,12 +31,15 @@ source_set("unit_tests") {
sources = [
"content_ruleset_distributor_unittest.cc",
"content_subresource_filter_driver_factory_unittest.cc",
+ "subresource_filter_navigation_throttle_unittests.cc",
]
deps = [
":browser",
"//base/test:test_support",
"//components/safe_browsing_db:util",
"//components/subresource_filter/content/common",
+ "//components/subresource_filter/core/browser",
+ "//components/subresource_filter/core/browser:test_support",
"//content/test:test_support",
"//ipc",
"//ipc:test_support",
diff --git a/chromium/components/subresource_filter/content/browser/content_ruleset_distributor_unittest.cc b/chromium/components/subresource_filter/content/browser/content_ruleset_distributor_unittest.cc
index c4db8453374..b06730200a3 100644
--- a/chromium/components/subresource_filter/content/browser/content_ruleset_distributor_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/content_ruleset_distributor_unittest.cc
@@ -69,7 +69,7 @@ class SubresourceFilterContentRulesetDistributorTest : public ::testing::Test {
content::TestBrowserContext* browser_context() { return &browser_context_; }
base::FilePath scoped_temp_file() const {
- return scoped_temp_dir_.path().AppendASCII("data");
+ return scoped_temp_dir_.GetPath().AppendASCII("data");
}
void AssertSetRulesetForProcessMessageWithContent(
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver.h b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver.h
index 567ef267872..8f0cb61acf4 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver.h
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver.h
@@ -20,11 +20,11 @@ class ContentSubresourceFilterDriver {
public:
explicit ContentSubresourceFilterDriver(
content::RenderFrameHost* render_frame_host);
- ~ContentSubresourceFilterDriver();
+ virtual ~ContentSubresourceFilterDriver();
// Instructs the agent on the renderer to set up the subresource filter for
// the currently ongoing provisional document load in the frame.
- void ActivateForProvisionalLoad(ActivationState activation_state);
+ virtual void ActivateForProvisionalLoad(ActivationState activation_state);
private:
// The RenderFrameHost that this driver belongs to.
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
index aec0b81d45c..3a3747d4b1e 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -4,11 +4,15 @@
#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
-#include "components/safe_browsing_db/util.h"
+#include "base/metrics/histogram_macros.h"
#include "components/subresource_filter/content/browser/content_subresource_filter_driver.h"
+#include "components/subresource_filter/content/common/subresource_filter_messages.h"
+#include "components/subresource_filter/core/browser/subresource_filter_client.h"
#include "components/subresource_filter/core/browser/subresource_filter_features.h"
+#include "components/subresource_filter/core/common/activation_list.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
+#include "ipc/ipc_message_macros.h"
#include "url/gurl.h"
namespace subresource_filter {
@@ -19,12 +23,13 @@ const char ContentSubresourceFilterDriverFactory::kWebContentsUserDataKey[] =
// static
void ContentSubresourceFilterDriverFactory::CreateForWebContents(
- content::WebContents* web_contents) {
+ content::WebContents* web_contents,
+ std::unique_ptr<SubresourceFilterClient> client) {
if (FromWebContents(web_contents))
return;
- web_contents->SetUserData(
- kWebContentsUserDataKey,
- new ContentSubresourceFilterDriverFactory(web_contents));
+ web_contents->SetUserData(kWebContentsUserDataKey,
+ new ContentSubresourceFilterDriverFactory(
+ web_contents, std::move(client)));
}
// static
@@ -36,8 +41,11 @@ ContentSubresourceFilterDriverFactory::FromWebContents(
}
ContentSubresourceFilterDriverFactory::ContentSubresourceFilterDriverFactory(
- content::WebContents* web_contents)
- : content::WebContentsObserver(web_contents) {
+ content::WebContents* web_contents,
+ std::unique_ptr<SubresourceFilterClient> client)
+ : content::WebContentsObserver(web_contents),
+ client_(std::move(client)),
+ activation_state_(ActivationState::DISABLED) {
content::RenderFrameHost* main_frame_host = web_contents->GetMainFrame();
if (main_frame_host && main_frame_host->IsRenderFrameLive())
CreateDriverForFrameHostIfNeeded(main_frame_host);
@@ -56,22 +64,95 @@ void ContentSubresourceFilterDriverFactory::CreateDriverForFrameHostIfNeeded(
}
}
+void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() {
+ client_->ToggleNotificationVisibility(activation_state() ==
+ ActivationState::ENABLED);
+}
+
+bool ContentSubresourceFilterDriverFactory::IsWhitelisted(
+ const GURL& url) const {
+ return whitelisted_set().find(url.host()) != whitelisted_set().end();
+}
+
+bool ContentSubresourceFilterDriverFactory::IsHit(const GURL& url) const {
+ return safe_browsing_blacklisted_patterns_set().find(url.host() +
+ url.path()) !=
+ safe_browsing_blacklisted_patterns_set().end();
+}
+
+
void ContentSubresourceFilterDriverFactory::
OnMainResourceMatchedSafeBrowsingBlacklist(
const GURL& url,
const std::vector<GURL>& redirect_urls,
- safe_browsing::ThreatPatternType threat_type) {
- if (threat_type != safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS)
+ safe_browsing::SBThreatType threat_type,
+ safe_browsing::ThreatPatternType threat_type_metadata) {
+ bool proceed = false;
+ if (GetCurrentActivationList() ==
+ ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL) {
+ proceed = (threat_type_metadata ==
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
+ } else if (GetCurrentActivationList() ==
+ ActivationList::PHISHING_INTERSTITIAL) {
+ proceed = (threat_type == safe_browsing::SB_THREAT_TYPE_URL_PHISHING);
+ }
+ if (!proceed)
return;
- activate_on_origins_.insert(url.host());
- for (const auto& url : redirect_urls) {
- activate_on_origins_.insert(url.host());
+ AddToActivationHitsSet(url);
+}
+
+void ContentSubresourceFilterDriverFactory::AddHostOfURLToWhitelistSet(
+ const GURL& url) {
+ if (!url.host().empty() && url.SchemeIsHTTPOrHTTPS())
+ whitelisted_hosts_.insert(url.host());
+}
+
+void ContentSubresourceFilterDriverFactory::AddToActivationHitsSet(
+ const GURL& url) {
+ if (!url.host().empty() && url.SchemeIsHTTPOrHTTPS())
+ safe_browsing_blacklisted_patterns_.insert(url.host() + url.path());
+}
+
+void ContentSubresourceFilterDriverFactory::ReadyToCommitMainFrameNavigation(
+ content::RenderFrameHost* render_frame_host,
+ const GURL& url) {
+ if (ShouldActivateForMainFrameURL(url)) {
+ set_activation_state(GetMaximumActivationState());
+ ActivateForFrameHostIfNeeded(render_frame_host, url);
}
}
-bool ContentSubresourceFilterDriverFactory::ShouldActivateForURL(
+bool ContentSubresourceFilterDriverFactory::ShouldActivateForMainFrameURL(
+ const GURL& url) const {
+ if (GetCurrentActivationScope() == ActivationScope::ALL_SITES)
+ return !IsWhitelisted(url);
+ else if (GetCurrentActivationScope() == ActivationScope::ACTIVATION_LIST)
+ return IsHit(url) && !IsWhitelisted(url);
+ return false;
+}
+
+void ContentSubresourceFilterDriverFactory::ActivateForFrameHostIfNeeded(
+ content::RenderFrameHost* render_frame_host,
const GURL& url) {
- return activation_set().find(url.host()) != activation_set().end();
+ if (activation_state_ != ActivationState::DISABLED) {
+ DriverFromFrameHost(render_frame_host)
+ ->ActivateForProvisionalLoad(GetMaximumActivationState());
+ }
+}
+
+void ContentSubresourceFilterDriverFactory::OnReloadRequested() {
+ UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.Prompt.NumReloads", true);
+ const GURL whitelist_url(web_contents()->GetLastCommittedURL());
+ AddHostOfURLToWhitelistSet(whitelist_url);
+ web_contents()->GetController().Reload(true);
+}
+
+void ContentSubresourceFilterDriverFactory::SetDriverForFrameHostForTesting(
+ content::RenderFrameHost* render_frame_host,
+ std::unique_ptr<ContentSubresourceFilterDriver> driver) {
+ auto iterator_and_inserted =
+ frame_drivers_.insert(std::make_pair(render_frame_host, nullptr));
+ iterator_and_inserted.first->second = std::move(driver);
}
ContentSubresourceFilterDriver*
@@ -96,9 +177,30 @@ void ContentSubresourceFilterDriverFactory::DidStartProvisionalLoadForFrame(
const GURL& validated_url,
bool is_error_page,
bool is_iframe_srcdoc) {
- // TODO(melandory): Replace placeholder with actual activation logic.
- DriverFromFrameHost(render_frame_host)
- ->ActivateForProvisionalLoad(GetMaximumActivationState());
+ safe_browsing_blacklisted_patterns_.clear();
+ if (!render_frame_host->GetParent()) {
+ client_->ToggleNotificationVisibility(false);
+ set_activation_state(ActivationState::DISABLED);
+ } else {
+ ActivateForFrameHostIfNeeded(render_frame_host, validated_url);
+ }
+}
+
+bool ContentSubresourceFilterDriverFactory::OnMessageReceived(
+ const IPC::Message& message,
+ content::RenderFrameHost* render_frame_host) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ContentSubresourceFilterDriverFactory, message)
+ IPC_MESSAGE_HANDLER(SubresourceFilterHostMsg_DidDisallowFirstSubresource,
+ OnFirstSubresourceLoadDisallowed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void ContentSubresourceFilterDriverFactory::set_activation_state(
+ const ActivationState& new_activation_state) {
+ activation_state_ = new_activation_state;
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
index 29a7e73d22e..049e85f3f87 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/supports_user_data.h"
+#include "components/safe_browsing_db/util.h"
#include "content/public/browser/web_contents_observer.h"
#include "url/gurl.h"
@@ -21,46 +22,97 @@ class WebContents;
class RenderFrameHost;
} // namespace content
-namespace safe_browsing {
-enum class ThreatPatternType;
-}
-
namespace subresource_filter {
-using OriginSet = std::set<std::string>;
+using HostSet = std::set<std::string>;
class ContentSubresourceFilterDriver;
+class SubresourceFilterClient;
+enum class ActivationState;
// Controls the activation of subresource filtering for each page load in a
// WebContents and manufactures the per-frame ContentSubresourceFilterDrivers.
+// TODO(melandory): Once https://crbug.com/621856 is fixed this class should
+// take care of passing the activation information not only to the main frame,
+// but also to the subframes.
class ContentSubresourceFilterDriverFactory
: public base::SupportsUserData::Data,
public content::WebContentsObserver {
public:
- static void CreateForWebContents(content::WebContents* web_contents);
+ static void CreateForWebContents(
+ content::WebContents* web_contents,
+ std::unique_ptr<SubresourceFilterClient> client);
static ContentSubresourceFilterDriverFactory* FromWebContents(
content::WebContents* web_contents);
explicit ContentSubresourceFilterDriverFactory(
- content::WebContents* web_contents);
+ content::WebContents* web_contents,
+ std::unique_ptr<SubresourceFilterClient> client);
~ContentSubresourceFilterDriverFactory() override;
+ ContentSubresourceFilterDriver* DriverFromFrameHost(
+ content::RenderFrameHost* render_frame_host);
+
+ bool IsWhitelisted(const GURL& url) const;
+ bool IsBlacklisted(const GURL& url) const;
+
+ // Whitelists the host of |url|, so that page loads with the main-frame
+ // document being loaded from this host will be exempted from subresource
+ // filtering for the lifetime of this WebContents.
+ void AddHostOfURLToWhitelistSet(const GURL& url);
+
+ void AddToActivationHitsSet(const GURL& url);
+
+ // Called when Safe Browsing detects that the |url| corresponding to the load
+ // of the main frame belongs to the blacklist with |threat_type|. If the
+ // blacklist is the Safe Browsing Social Engineering ads landing, then |url|
+ // and |redirects| are saved.
void OnMainResourceMatchedSafeBrowsingBlacklist(
const GURL& url,
const std::vector<GURL>& redirect_urls,
- safe_browsing::ThreatPatternType threat_type);
- const OriginSet& activation_set() { return activate_on_origins_; }
- bool ShouldActivateForURL(const GURL& url);
+ safe_browsing::SBThreatType threat_type,
+ safe_browsing::ThreatPatternType threat_type_metadata);
+
+ // Reloads the page and inserts the url to the whitelist.
+ void OnReloadRequested();
+
+ // Checks if all preconditions are fulfilled and if so, activates filtering
+ // for the given |render_frame_host|. |url| is used to check web site specific
+ // preconditions and should be the web URL of the page where caller is
+ // intended to activate the Safe Browsing Subresource Filter.
+ // TODO(melandory) While due to crbug.com/621856 we cannot yet get rid of
+ // SubresourceFilterNavigationThrottle, it would still make sense to change
+ // its semantics so that its only responsibility is to emulate
+ // DidRedirectNavigation and ReadyToCommitNavigation for us before we get
+ // these from WebContentsObserver for free. Then, the throttle would no longer
+ // contain any subresource filter specific logic, and those pieces of logic
+ // would all be moved into here.
+ void ReadyToCommitMainFrameNavigation(
+ content::RenderFrameHost* render_frame_host,
+ const GURL& url);
+
+ const HostSet& safe_browsing_blacklisted_patterns_set() const {
+ return safe_browsing_blacklisted_patterns_;
+ }
+ const HostSet& whitelisted_set() const { return whitelisted_hosts_; }
+ ActivationState activation_state() { return activation_state_; }
private:
+ friend class ContentSubresourceFilterDriverFactoryTest;
+ friend class SubresourceFilterNavigationThrottleTest;
+
typedef std::map<content::RenderFrameHost*,
std::unique_ptr<ContentSubresourceFilterDriver>>
FrameHostToOwnedDriverMap;
+ void SetDriverForFrameHostForTesting(
+ content::RenderFrameHost* render_frame_host,
+ std::unique_ptr<ContentSubresourceFilterDriver> driver);
+
void CreateDriverForFrameHostIfNeeded(
content::RenderFrameHost* render_frame_host);
- ContentSubresourceFilterDriver* DriverFromFrameHost(
- content::RenderFrameHost* render_frame_host);
+
+ void OnFirstSubresourceLoadDisallowed();
// content::WebContentsObserver:
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
@@ -70,12 +122,34 @@ class ContentSubresourceFilterDriverFactory
const GURL& validated_url,
bool is_error_page,
bool is_iframe_srcdoc) override;
+ bool OnMessageReceived(const IPC::Message& message,
+ content::RenderFrameHost* render_frame_host) override;
+
+ // Checks base on the value of |urr| and current activation scope if
+ // activation signal should be sent.
+ bool ShouldActivateForMainFrameURL(const GURL& url) const;
+ void ActivateForFrameHostIfNeeded(content::RenderFrameHost* render_frame_host,
+ const GURL& url);
+
+ void set_activation_state(const ActivationState& new_activation_state);
+
+ bool IsHit(const GURL& url) const;
static const char kWebContentsUserDataKey[];
FrameHostToOwnedDriverMap frame_drivers_;
+ std::unique_ptr<SubresourceFilterClient> client_;
+
+ HostSet whitelisted_hosts_;
+
+ // Host+path list of the URLs, where the Safe Browsing detected hit to the
+ // threat list of interest. When the navigation is commited
+ // |safe_browsing_blacklisted_patterns_| is used to determine whenever
+ // the activation signal should be sent. All entities are deleted from the
+ // list on navigation commit event.
+ HostSet safe_browsing_blacklisted_patterns_;
- OriginSet activate_on_origins_;
+ ActivationState activation_state_;
DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterDriverFactory);
};
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
index 7aa7fbb4d7d..8661f448dba 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
@@ -3,25 +3,138 @@
// found in the LICENSE file.
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial.h"
#include "components/safe_browsing_db/util.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_driver.h"
#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
+#include "components/subresource_filter/core/browser/subresource_filter_client.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h"
+#include "content/public/browser/web_contents.h"
#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+namespace {
+
+const char kExampleUrlWithParams[] = "https://example.com/soceng?q=engsoc";
+const char kTestUrl[] = "https://test.com";
+const char kExampleUrl[] = "https://example.com";
+const char kExampleLoginUrl[] = "https://example.com/login";
+
+struct ActivationListTestData {
+ bool should_add;
+ const char* const activation_list;
+ safe_browsing::SBThreatType threat_type;
+ safe_browsing::ThreatPatternType threat_type_metadata;
+};
+
+const ActivationListTestData kActivationListTestData[] = {
+ {false, "", safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {false, subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
+ safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::NONE},
+ {false, subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
+ safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::MALWARE_LANDING},
+ {false, subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
+ safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::MALWARE_DISTRIBUTION},
+ {true, subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
+ safe_browsing::SB_THREAT_TYPE_URL_MALWARE,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {false, subresource_filter::kActivationListPhishingInterstitial,
+ safe_browsing::SB_THREAT_TYPE_API_ABUSE,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {false, subresource_filter::kActivationListPhishingInterstitial,
+ safe_browsing::SB_THREAT_TYPE_BLACKLISTED_RESOURCE,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {false, subresource_filter::kActivationListPhishingInterstitial,
+ safe_browsing::SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {false, subresource_filter::kActivationListPhishingInterstitial,
+ safe_browsing::SB_THREAT_TYPE_BINARY_MALWARE_URL,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {false, subresource_filter::kActivationListPhishingInterstitial,
+ safe_browsing::SB_THREAT_TYPE_URL_UNWANTED,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {false, subresource_filter::kActivationListPhishingInterstitial,
+ safe_browsing::SB_THREAT_TYPE_URL_MALWARE,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {false, subresource_filter::kActivationListPhishingInterstitial,
+ safe_browsing::SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {false, subresource_filter::kActivationListPhishingInterstitial,
+ safe_browsing::SB_THREAT_TYPE_SAFE,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+ {true, subresource_filter::kActivationListPhishingInterstitial,
+ safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::NONE},
+};
+
+} // namespace
+
namespace subresource_filter {
+class MockSubresourceFilterDriver : public ContentSubresourceFilterDriver {
+ public:
+ explicit MockSubresourceFilterDriver(
+ content::RenderFrameHost* render_frame_host)
+ : ContentSubresourceFilterDriver(render_frame_host) {}
+
+ ~MockSubresourceFilterDriver() override = default;
+
+ MOCK_METHOD1(ActivateForProvisionalLoad, void(ActivationState));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterDriver);
+};
+
+class MockSubresourceFilterClient : public SubresourceFilterClient {
+ public:
+ MockSubresourceFilterClient() {}
+
+ ~MockSubresourceFilterClient() override = default;
+
+ MOCK_METHOD1(ToggleNotificationVisibility, void(bool));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterClient);
+};
+
class ContentSubresourceFilterDriverFactoryTest
: public content::RenderViewHostTestHarness {
public:
ContentSubresourceFilterDriverFactoryTest() {}
~ContentSubresourceFilterDriverFactoryTest() override {}
- // content::RenderViewHostTestHarness:
+ // content::RenderViewHostImplTestHarness:
void SetUp() override {
RenderViewHostTestHarness::SetUp();
- ContentSubresourceFilterDriverFactory::CreateForWebContents(web_contents());
+ client_ = new MockSubresourceFilterClient();
+ ContentSubresourceFilterDriverFactory::CreateForWebContents(
+ web_contents(), base::WrapUnique(client()));
+ driver_ = new MockSubresourceFilterDriver(main_rfh());
+ SetDriverForFrameHostForTesting(main_rfh(), driver());
+ // Add a subframe.
+ content::RenderFrameHostTester* rfh_tester =
+ content::RenderFrameHostTester::For(main_rfh());
+ rfh_tester->InitializeRenderFrameIfNeeded();
+ subframe_rfh_ = rfh_tester->AppendChild("Child");
+ subframe_driver_ = new MockSubresourceFilterDriver(subframe_rfh());
+ SetDriverForFrameHostForTesting(subframe_rfh(), subframe_driver());
+ }
+
+ void SetDriverForFrameHostForTesting(
+ content::RenderFrameHost* render_frame_host,
+ ContentSubresourceFilterDriver* driver) {
+ factory()->SetDriverForFrameHostForTesting(render_frame_host,
+ base::WrapUnique(driver));
}
ContentSubresourceFilterDriverFactory* factory() {
@@ -29,13 +142,100 @@ class ContentSubresourceFilterDriverFactoryTest
web_contents());
}
+ MockSubresourceFilterClient* client() { return client_; }
+ MockSubresourceFilterDriver* driver() { return driver_; }
+
+ MockSubresourceFilterDriver* subframe_driver() { return subframe_driver_; }
+ content::RenderFrameHost* subframe_rfh() { return subframe_rfh_; }
+
+ void BlacklistURLWithRedirectsNavigateAndCommit(
+ const GURL& bad_url,
+ const std::vector<GURL>& redirects,
+ const GURL& url,
+ bool should_activate) {
+ EXPECT_CALL(*client(), ToggleNotificationVisibility(false)).Times(1);
+ content::WebContentsTester::For(web_contents())->StartNavigation(url);
+ ::testing::Mock::VerifyAndClearExpectations(client());
+ factory()->OnMainResourceMatchedSafeBrowsingBlacklist(
+ bad_url, redirects, safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
+
+ ActivateAndExpectForFrameHostForUrl(driver(), main_rfh(), url,
+ should_activate);
+ content::RenderFrameHostTester::For(main_rfh())
+ ->SimulateNavigationCommit(url);
+ }
+
+ void ActivateAndExpectForFrameHostForUrl(MockSubresourceFilterDriver* driver,
+ content::RenderFrameHost* rfh,
+ const GURL& url,
+ bool should_activate) {
+ EXPECT_CALL(*driver, ActivateForProvisionalLoad(::testing::_))
+ .Times(should_activate);
+ factory()->ReadyToCommitMainFrameNavigation(rfh, url);
+ ::testing::Mock::VerifyAndClearExpectations(driver);
+ }
+
+ void NavigateAndCommitSubframe(const GURL& url, bool should_activate) {
+ EXPECT_CALL(*subframe_driver(), ActivateForProvisionalLoad(::testing::_))
+ .Times(should_activate);
+ EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0);
+
+ factory()->DidStartProvisionalLoadForFrame(
+ subframe_rfh(), url /* validated_url */, false /* is_error_page */,
+ false /* is_iframe_srcdoc */);
+ factory()->DidCommitProvisionalLoadForFrame(
+ subframe_rfh(), url, ui::PageTransition::PAGE_TRANSITION_AUTO_SUBFRAME);
+ ::testing::Mock::VerifyAndClearExpectations(subframe_driver());
+ ::testing::Mock::VerifyAndClearExpectations(client());
+ }
+
+ void BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ const GURL& bad_url,
+ const std::vector<GURL>& redirects,
+ const GURL& url,
+ bool should_activate) {
+ BlacklistURLWithRedirectsNavigateAndCommit(bad_url, redirects, url,
+ should_activate);
+
+ NavigateAndCommitSubframe(GURL(kExampleLoginUrl), should_activate);
+ }
+
+ void SpecialCaseNavSeq(const GURL& bad_url,
+ const std::vector<GURL>& redirects,
+ bool should_activate) {
+ // This test-case examinse the nevigation woth following sequence of event:
+ // DidStartProvisional(main, "example.com")
+ // ReadyToCommitMainFrameNavigation(“example.comâ€)
+ // DidCommitProvisional(main, "example.com")
+ // DidStartProvisional(sub, "example.com/login")
+ // DidCommitProvisional(sub, "example.com/login")
+ // DidCommitProvisional(main, "example.com#ref")
+
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ bad_url, redirects, GURL(kExampleUrl), should_activate);
+ EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_)).Times(0);
+ EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0);
+ content::RenderFrameHostTester::For(main_rfh())
+ ->SimulateNavigationCommit(GURL(kExampleUrl));
+ ::testing::Mock::VerifyAndClearExpectations(driver());
+ ::testing::Mock::VerifyAndClearExpectations(client());
+ }
+
private:
+ // Owned by the factory.
+ MockSubresourceFilterClient* client_;
+ MockSubresourceFilterDriver* driver_;
+
+ content::RenderFrameHost* subframe_rfh_;
+ MockSubresourceFilterDriver* subframe_driver_;
+
DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterDriverFactoryTest);
};
class ContentSubresourceFilterDriverFactoryThreatTypeTest
: public ContentSubresourceFilterDriverFactoryTest,
- public ::testing::WithParamInterface<safe_browsing::ThreatPatternType> {
+ public ::testing::WithParamInterface<ActivationListTestData> {
public:
ContentSubresourceFilterDriverFactoryThreatTypeTest() {}
~ContentSubresourceFilterDriverFactoryThreatTypeTest() override {}
@@ -44,73 +244,197 @@ class ContentSubresourceFilterDriverFactoryThreatTypeTest
DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterDriverFactoryThreatTypeTest);
};
-TEST_F(ContentSubresourceFilterDriverFactoryTest, SocEngHitEmptyRedirects) {
- factory()->OnMainResourceMatchedSafeBrowsingBlacklist(
- GURL("https://example.com/soceng?q=engsoc"), std::vector<GURL>(),
- safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
- EXPECT_EQ(1U, factory()->activation_set().size());
- EXPECT_TRUE(factory()->ShouldActivateForURL(GURL("https://example.com")));
- EXPECT_TRUE(factory()->ShouldActivateForURL(GURL("http://example.com")));
- EXPECT_TRUE(
- factory()->ShouldActivateForURL(GURL("http://example.com/42?q=42!")));
- EXPECT_TRUE(
- factory()->ShouldActivateForURL(GURL("https://example.com/42?q=42!")));
- EXPECT_TRUE(
- factory()->ShouldActivateForURL(GURL("http://example.com/awesomepath")));
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ ActivateForFrameHostNotNeeded) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_DISABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeNoSites, kActivationListSocialEngineeringAdsInterstitial);
+ ActivateAndExpectForFrameHostForUrl(driver(), main_rfh(), GURL(kTestUrl),
+ false /* should_activate */);
+ const GURL url(kExampleUrlWithParams);
+ BlacklistURLWithRedirectsNavigateAndCommit(url, std::vector<GURL>(), url,
+ false /* should_activate */);
+ BlacklistURLWithRedirectsNavigateAndCommit(url, std::vector<GURL>(),
+ GURL("https://not-example.com"),
+ false /* should_activate */);
}
-TEST_F(ContentSubresourceFilterDriverFactoryTest, SocEngHitWithRedirects) {
- std::vector<GURL> redirects;
- redirects.push_back(GURL("https://example1.com"));
- redirects.push_back(GURL("https://example2.com"));
- redirects.push_back(GURL("https://example3.com"));
- factory()->OnMainResourceMatchedSafeBrowsingBlacklist(
- GURL("https://example.com/engsoc/q=soceng"), redirects,
- safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
- EXPECT_EQ(4U, factory()->activation_set().size());
- EXPECT_TRUE(factory()->ShouldActivateForURL(GURL("https://example.com")));
- for (const auto& redirect : redirects) {
- EXPECT_TRUE(factory()->ShouldActivateForURL(redirect));
- EXPECT_TRUE(factory()->ShouldActivateForURL(redirect.GetWithEmptyPath()));
- EXPECT_TRUE(
- factory()->ShouldActivateForURL(GURL("http://" + redirect.host())));
- EXPECT_TRUE(factory()->ShouldActivateForURL(
- GURL("http://" + redirect.host() + "/path?q=q")));
- }
+TEST_F(ContentSubresourceFilterDriverFactoryTest, ActivateForFrameHostNeeded) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+
+ const GURL url(kExampleUrlWithParams);
+ BlacklistURLWithRedirectsNavigateAndCommit(url, std::vector<GURL>(), url,
+ true /* should_activate */);
+ BlacklistURLWithRedirectsNavigateAndCommit(
+ url, std::vector<GURL>(), GURL(kExampleUrl), false /* should_activate */);
}
TEST_P(ContentSubresourceFilterDriverFactoryThreatTypeTest, NonSocEngHit) {
+ const ActivationListTestData& test_data = GetParam();
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeNoSites, test_data.activation_list);
+
std::vector<GURL> redirects;
redirects.push_back(GURL("https://example1.com"));
redirects.push_back(GURL("https://example2.com"));
redirects.push_back(GURL("https://example3.com"));
const GURL test_url("https://example.com/nonsoceng?q=engsocnon");
+
+ BlacklistURLWithRedirectsNavigateAndCommit(GURL::EmptyGURL(),
+ std::vector<GURL>(), test_url,
+ false /* should_activate */);
+ EXPECT_CALL(*client(), ToggleNotificationVisibility(false)).Times(1);
+ content::WebContentsTester::For(web_contents())->StartNavigation(test_url);
+ ::testing::Mock::VerifyAndClearExpectations(client());
factory()->OnMainResourceMatchedSafeBrowsingBlacklist(
- GURL(test_url), std::vector<GURL>(), GetParam());
- EXPECT_EQ(0U, factory()->activation_set().size());
- EXPECT_FALSE(factory()->ShouldActivateForURL(GURL(test_url)));
- EXPECT_FALSE(
- factory()->ShouldActivateForURL(GURL(test_url.GetWithEmptyPath())));
- EXPECT_FALSE(factory()->ShouldActivateForURL(
- GURL("http://" + test_url.host() + "/path?q=q")));
- for (const auto& redirect : redirects) {
- EXPECT_FALSE(factory()->ShouldActivateForURL(redirect));
- EXPECT_FALSE(factory()->ShouldActivateForURL(redirect.GetWithEmptyPath()));
- EXPECT_FALSE(
- factory()->ShouldActivateForURL(GURL("http://" + redirect.host())));
- EXPECT_FALSE(factory()->ShouldActivateForURL(
- GURL("http://" + redirect.host() + "/path?q=q")));
- }
+ test_url, redirects, test_data.threat_type,
+ test_data.threat_type_metadata);
+ ActivateAndExpectForFrameHostForUrl(driver(), main_rfh(), test_url, false);
+ content::RenderFrameHostTester::For(main_rfh())
+ ->SimulateNavigationCommit(test_url);
};
-INSTANTIATE_TEST_CASE_P(
- NoSonEngHit,
- ContentSubresourceFilterDriverFactoryThreatTypeTest,
- testing::Values(
- safe_browsing::ThreatPatternType::NONE,
- safe_browsing::ThreatPatternType::MALWARE_LANDING,
- safe_browsing::ThreatPatternType::MALWARE_DISTRIBUTION,
- safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_LANDING));
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ ActivationPromptNotShownForNonMainFrames) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+ BlacklistURLWithRedirectsNavigateAndCommit(
+ GURL::EmptyGURL(), std::vector<GURL>(), GURL(kExampleUrl),
+ false /* should_prompt */);
+}
+
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ DidStartProvisionalLoadScopeAllSitesStateDryRun) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateDryRun,
+ kActivationScopeAllSites,
+ kActivationListSocialEngineeringAdsInterstitial);
+ const GURL url(kExampleUrlWithParams);
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ url, std::vector<GURL>(), url, true /* should_activate */);
+ factory()->AddHostOfURLToWhitelistSet(url);
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ url, std::vector<GURL>(), GURL(kExampleUrlWithParams),
+ false /* should_activate */);
+}
+
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ DidStartProvisionalLoadScopeAllSitesStateEnabled) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeAllSites,
+ kActivationListSocialEngineeringAdsInterstitial);
+ const GURL url(kExampleUrlWithParams);
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ url, std::vector<GURL>(), url, true /* should_activate */);
+ factory()->AddHostOfURLToWhitelistSet(url);
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ url, std::vector<GURL>(), GURL(kExampleUrlWithParams),
+ false /* should_activate */);
+}
+
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ DidStartProvisionalLoadScopeActivationListSitesStateEnabled) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+ const GURL url(kExampleUrlWithParams);
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ url, std::vector<GURL>(), url, true /* should_activate */);
+ factory()->AddHostOfURLToWhitelistSet(url);
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ url, std::vector<GURL>(), GURL(kExampleUrlWithParams),
+ false /* should_activate */);
+}
+
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ DidStartProvisionalLoadScopeActivationListSitesStateDryRun) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateDryRun,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+ const GURL url(kExampleUrlWithParams);
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ url, std::vector<GURL>(), url, true /* should_activate */);
+ factory()->AddHostOfURLToWhitelistSet(url);
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ url, std::vector<GURL>(), url, false /* should_activate */);
+}
+
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ DidStartProvisionalLoadScopeNoSites) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateDryRun,
+ kActivationScopeNoSites, kActivationListSocialEngineeringAdsInterstitial);
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ GURL::EmptyGURL(), std::vector<GURL>(), GURL(kExampleUrlWithParams),
+ false /* should_activate */);
+}
+
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ DidStartProvisionalLoadScopeActivationList) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateDisabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+ BlacklistURLWithRedirectsNavigateMainFrameAndSubrame(
+ GURL::EmptyGURL(), std::vector<GURL>(), GURL(kExampleUrlWithParams),
+ false /* should_activate */);
+}
+
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ SpecialCaseNavigationAllSitesDryRun) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateDryRun,
+ kActivationScopeAllSites);
+ SpecialCaseNavSeq(GURL::EmptyGURL(), std::vector<GURL>(),
+ true /* should_activate */);
+}
+
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ SpecialCaseNavigationAllSitesEnabled) {
+ // Check that when the experiment is enabled for all site, the activation
+ // signal is always sent.
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeAllSites);
+ SpecialCaseNavSeq(GURL::EmptyGURL(), std::vector<GURL>(),
+ true /* should_activate */);
+}
+
+TEST_F(ContentSubresourceFilterDriverFactoryTest,
+ SpecialCaseNavigationActivationListEnabled) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+ SpecialCaseNavSeq(GURL(kExampleUrl), std::vector<GURL>(),
+ true /* should_activate */);
+}
+
+INSTANTIATE_TEST_CASE_P(NoSonEngHit,
+ ContentSubresourceFilterDriverFactoryThreatTypeTest,
+ ::testing::ValuesIn(kActivationListTestData));
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.cc
new file mode 100644
index 00000000000..7e9dee25ffe
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.cc
@@ -0,0 +1,42 @@
+// 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 "components/subresource_filter/content/browser/subresource_filter_navigation_throttle.h"
+
+#include "components/subresource_filter/content/browser/content_subresource_filter_driver.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features.h"
+#include "components/subresource_filter/core/common/activation_state.h"
+#include "content/public/browser/navigation_handle.h"
+
+namespace subresource_filter {
+
+// static
+std::unique_ptr<content::NavigationThrottle>
+SubresourceFilterNavigationThrottle::Create(content::NavigationHandle* handle) {
+ return std::unique_ptr<content::NavigationThrottle>(
+ new SubresourceFilterNavigationThrottle(handle));
+}
+
+SubresourceFilterNavigationThrottle::SubresourceFilterNavigationThrottle(
+ content::NavigationHandle* handle)
+ : content::NavigationThrottle(handle) {}
+
+SubresourceFilterNavigationThrottle::~SubresourceFilterNavigationThrottle() {}
+
+content::NavigationThrottle::ThrottleCheckResult
+SubresourceFilterNavigationThrottle::WillProcessResponse() {
+ if (!navigation_handle()->GetURL().SchemeIsHTTPOrHTTPS())
+ return NavigationThrottle::PROCEED;
+
+ ContentSubresourceFilterDriverFactory::FromWebContents(
+ navigation_handle()->GetWebContents())
+ ->ReadyToCommitMainFrameNavigation(
+ navigation_handle()->GetRenderFrameHost(),
+ navigation_handle()->GetURL());
+
+ return NavigationThrottle::PROCEED;
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.h b/chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.h
new file mode 100644
index 00000000000..a6205123e23
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.h
@@ -0,0 +1,48 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_NAVIGATION_THROTTLE_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_NAVIGATION_THROTTLE_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "url/gurl.h"
+
+namespace content {
+class NavigationHandle;
+} // content
+
+namespace subresource_filter {
+
+// This class has two resposibilities:
+// * it tracks the redirects that happen after Safe Browsing detects that the
+// page being loaded contains deceptive embedded content. If such a redirect
+// happens and leads to new domains, these are also put on the activation list
+// of the tab.
+// * it creates a ContentSubresourceFilterDriver for the tab when the final site
+// of a (potentially empty) redirect chain is reached and any URL of the
+// redirect chain was on the activation list.
+// This throttle is active only for main frame http or https navigations and
+// doesn't act on subframe navigations or subresource loads.
+class SubresourceFilterNavigationThrottle : public content::NavigationThrottle {
+ public:
+ static std::unique_ptr<content::NavigationThrottle> Create(
+ content::NavigationHandle* handle);
+ ~SubresourceFilterNavigationThrottle() override;
+
+ // content::NavigationThrottle implementation:
+ ThrottleCheckResult WillProcessResponse() override;
+
+ private:
+ explicit SubresourceFilterNavigationThrottle(
+ content::NavigationHandle* navigation_handle);
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterNavigationThrottle);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_NAVIGATION_THROTTLE_
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle_unittests.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle_unittests.cc
new file mode 100644
index 00000000000..335eed78205
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_navigation_throttle_unittests.cc
@@ -0,0 +1,278 @@
+// 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 "components/subresource_filter/content/browser/subresource_filter_navigation_throttle.h"
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial.h"
+#include "components/safe_browsing_db/util.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_driver.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
+#include "components/subresource_filter/core/browser/subresource_filter_client.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::NavigationThrottle;
+
+namespace {
+
+const char kExampleURL[] = "http://example.com";
+const char kTestURL[] = "http://test.com";
+const char kRedirectURLFirst[] = "http://example1.com";
+const char kRedirectURLSecond[] = "http://example2.com";
+const char kRedirectURLThird[] = "http://example3.com";
+const char kNonWebURL[] = "chrome://settings";
+
+} // namespace
+
+namespace subresource_filter {
+
+class MockSubresourceFilterDriver : public ContentSubresourceFilterDriver {
+ public:
+ explicit MockSubresourceFilterDriver(
+ content::RenderFrameHost* render_frame_host)
+ : ContentSubresourceFilterDriver(render_frame_host) {}
+
+ ~MockSubresourceFilterDriver() override {}
+
+ MOCK_METHOD1(ActivateForProvisionalLoad, void(ActivationState));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterDriver);
+};
+
+class MockSubresourceFilterClient : public SubresourceFilterClient {
+ public:
+ MockSubresourceFilterClient() {}
+
+ ~MockSubresourceFilterClient() override = default;
+
+ MOCK_METHOD1(ToggleNotificationVisibility, void(bool));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterClient);
+};
+
+class SubresourceFilterNavigationThrottleTest
+ : public content::RenderViewHostTestHarness {
+ public:
+ SubresourceFilterNavigationThrottleTest() {}
+
+ // content::RenderViewHostTestHarness:
+ void SetUp() override {
+ RenderViewHostTestHarness::SetUp();
+ ContentSubresourceFilterDriverFactory::CreateForWebContents(
+ web_contents(), base::MakeUnique<MockSubresourceFilterClient>());
+
+ driver_ = new MockSubresourceFilterDriver(main_rfh());
+ factory()->SetDriverForFrameHostForTesting(main_rfh(),
+ base::WrapUnique(driver_));
+ }
+
+ void TearDown() override {
+ handle_.reset();
+ RenderViewHostTestHarness::TearDown();
+ }
+
+ void SetUpNavigationHandleForURL(const GURL& url) {
+ handle_ = content::NavigationHandle::CreateNavigationHandleForTesting(
+ url, main_rfh());
+ handle_->RegisterThrottleForTesting(
+ SubresourceFilterNavigationThrottle::Create(handle_.get()));
+ }
+
+ content::NavigationHandle* handle() { return handle_.get(); }
+
+ ContentSubresourceFilterDriverFactory* factory() {
+ return ContentSubresourceFilterDriverFactory::FromWebContents(
+ web_contents());
+ }
+
+ MockSubresourceFilterDriver* driver() { return driver_; }
+
+ NavigationThrottle::ThrottleCheckResult SimulateWillStart() {
+ return handle()->CallWillStartRequestForTesting(
+ false /* is_post */, content::Referrer(), false /* has_user_gesture */,
+ ui::PAGE_TRANSITION_LINK, false /* is_external_protocol */);
+ }
+
+ NavigationThrottle::ThrottleCheckResult SimulateRedirects(
+ const GURL& redirect) {
+ return handle()->CallWillRedirectRequestForTesting(
+ redirect, false /* new_method_is_post */, GURL() /* new_referrer_url */,
+ false /* new_is_external_protocol */);
+ }
+
+ void SimulateWillProcessResponse() {
+ handle()->CallWillProcessResponseForTesting(main_rfh(), std::string());
+ }
+
+ private:
+ // Owned by the factory.
+ MockSubresourceFilterDriver* driver_;
+ std::unique_ptr<content::NavigationHandle> handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterNavigationThrottleTest);
+};
+
+TEST_F(SubresourceFilterNavigationThrottleTest, RequestWithoutRedirects) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+
+ const GURL url(kExampleURL);
+ SetUpNavigationHandleForURL(url);
+ SimulateWillStart();
+ factory()->OnMainResourceMatchedSafeBrowsingBlacklist(
+ url, std::vector<GURL>(), safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
+ EXPECT_CALL(*driver(), ActivateForProvisionalLoad(ActivationState::ENABLED))
+ .Times(1);
+ SimulateWillProcessResponse();
+ ::testing::Mock::VerifyAndClearExpectations(driver());
+}
+
+TEST_F(SubresourceFilterNavigationThrottleTest,
+ RequestWithoutRedirectsNoActivation) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+
+ const GURL url_with_activation(kExampleURL);
+ const GURL url_without_activation(kTestURL);
+
+ factory()->OnMainResourceMatchedSafeBrowsingBlacklist(
+ url_with_activation, std::vector<GURL>(),
+ safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
+
+ SetUpNavigationHandleForURL(url_without_activation);
+ SimulateWillStart();
+
+ EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_)).Times(0);
+ SimulateWillProcessResponse();
+ ::testing::Mock::VerifyAndClearExpectations(driver());
+}
+
+TEST_F(SubresourceFilterNavigationThrottleTest,
+ RequestToNonWebURLNoActivation) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+
+ const GURL non_web_url(kNonWebURL);
+
+ factory()->OnMainResourceMatchedSafeBrowsingBlacklist(
+ non_web_url, std::vector<GURL>(),
+ safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
+
+ SetUpNavigationHandleForURL(non_web_url);
+ SimulateWillStart();
+
+ EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_)).Times(0);
+ SimulateWillProcessResponse();
+ ::testing::Mock::VerifyAndClearExpectations(driver());
+}
+
+TEST_F(SubresourceFilterNavigationThrottleTest,
+ AddRedirectFromNavThrottleToServiceEmptyInitRedirects) {
+ // Navigations |url| -> |redirect|. Safe Browsing classifies the |url| as
+ // containing deceptive content.
+ // Test checks that both |url| and |redirect| are in the activation set.
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+
+ const GURL url(kExampleURL);
+ const GURL redirect(kRedirectURLFirst);
+
+ SetUpNavigationHandleForURL(url);
+ SimulateWillStart();
+ factory()->OnMainResourceMatchedSafeBrowsingBlacklist(
+ redirect, std::vector<GURL>(), safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
+ SimulateRedirects(redirect);
+
+ EXPECT_CALL(*driver(), ActivateForProvisionalLoad(ActivationState::ENABLED))
+ .Times(1);
+ SimulateWillProcessResponse();
+ ::testing::Mock::VerifyAndClearExpectations(driver());
+}
+
+TEST_F(SubresourceFilterNavigationThrottleTest,
+ AddRedirectFromNavThrottleToServiceNonEmptyInitRedirects) {
+ // Navigations |redirects| -> |url| -> |redirect_after_sb_classification|.
+ // Safe Browsing classifies the |url| as containing deceptive content.
+ // Test checks that |url| it doesn't lead to sending the activation signal.
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+
+ const GURL url(kExampleURL);
+ const GURL redirect_after_sb_classification(kTestURL);
+ const GURL first_redirect(kRedirectURLFirst);
+ const GURL second_redirect(kRedirectURLSecond);
+ const GURL third_redirect(kRedirectURLThird);
+
+ SetUpNavigationHandleForURL(url);
+ SimulateWillStart();
+
+ std::vector<GURL> redirects = {first_redirect, second_redirect,
+ third_redirect};
+ SimulateRedirects(redirect_after_sb_classification);
+ factory()->OnMainResourceMatchedSafeBrowsingBlacklist(
+ url, redirects, safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
+
+ EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_)).Times(0);
+ SimulateWillProcessResponse();
+ ::testing::Mock::VerifyAndClearExpectations(driver());
+}
+
+TEST_F(SubresourceFilterNavigationThrottleTest,
+ RequestRedirectWithMatchRedirectTest) {
+ base::FieldTrialList field_trial_list(nullptr);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled,
+ kActivationScopeActivationList,
+ kActivationListSocialEngineeringAdsInterstitial);
+
+ const GURL init_url(kExampleURL);
+ const GURL redirect_with_match(kRedirectURLFirst);
+ const GURL final_url(kRedirectURLSecond);
+ std::vector<GURL> redirects = {redirect_with_match};
+ SetUpNavigationHandleForURL(init_url);
+ SimulateWillStart();
+ SimulateRedirects(redirect_with_match);
+ SimulateRedirects(final_url);
+ factory()->OnMainResourceMatchedSafeBrowsingBlacklist(
+ final_url, redirects, safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS);
+ EXPECT_CALL(*driver(), ActivateForProvisionalLoad(ActivationState::ENABLED))
+ .Times(1);
+ SimulateWillProcessResponse();
+ ::testing::Mock::VerifyAndClearExpectations(driver());
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/common/BUILD.gn b/chromium/components/subresource_filter/content/common/BUILD.gn
index 6654a365f9e..a6aee28496a 100644
--- a/chromium/components/subresource_filter/content/common/BUILD.gn
+++ b/chromium/components/subresource_filter/content/common/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("common") {
+static_library("common") {
sources = [
"subresource_filter_message_generator.cc",
"subresource_filter_message_generator.h",
diff --git a/chromium/components/subresource_filter/content/common/subresource_filter_messages.h b/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
index f7f625a4cec..b682a842bb8 100644
--- a/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
+++ b/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
@@ -31,3 +31,12 @@ IPC_MESSAGE_CONTROL1(SubresourceFilterMsg_SetRulesetForProcess,
// If no message arrives, the default behavior is ActivationState::DISABLED.
IPC_MESSAGE_ROUTED1(SubresourceFilterMsg_ActivateForProvisionalLoad,
subresource_filter::ActivationState /* activation_state */);
+
+// ----------------------------------------------------------------------------
+// Messages sent from the renderer to the browser.
+// ----------------------------------------------------------------------------
+
+// Sent to the browser the first time a subresource load is disallowed for the
+// most recently commited document load in a frame. It is used to trigger a
+// UI prompt to inform the user and allow them to turn off filtering.
+IPC_MESSAGE_ROUTED0(SubresourceFilterHostMsg_DidDisallowFirstSubresource)
diff --git a/chromium/components/subresource_filter/content/renderer/BUILD.gn b/chromium/components/subresource_filter/content/renderer/BUILD.gn
index 7af2f1085e6..e50e46d57c5 100644
--- a/chromium/components/subresource_filter/content/renderer/BUILD.gn
+++ b/chromium/components/subresource_filter/content/renderer/BUILD.gn
@@ -2,8 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("renderer") {
+static_library("renderer") {
sources = [
+ "document_subresource_filter.cc",
+ "document_subresource_filter.h",
"ruleset_dealer.cc",
"ruleset_dealer.h",
"subresource_filter_agent.cc",
@@ -16,5 +18,27 @@ source_set("renderer") {
"//content/public/common",
"//content/public/renderer",
"//ipc",
+ "//third_party/WebKit/public:blink",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "document_subresource_filter_unittest.cc",
+ "subresource_filter_agent_unittest.cc",
+ ]
+ deps = [
+ ":renderer",
+ "//base",
+ "//base/test:test_support",
+ "//components/subresource_filter/content/common",
+ "//components/subresource_filter/core/common",
+ "//components/subresource_filter/core/common:test_support",
+ "//content/public/renderer",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//third_party/WebKit/public:blink",
+ "//url",
]
}
diff --git a/chromium/components/subresource_filter/content/renderer/document_subresource_filter.cc b/chromium/components/subresource_filter/content/renderer/document_subresource_filter.cc
new file mode 100644
index 00000000000..f62bab9a09f
--- /dev/null
+++ b/chromium/components/subresource_filter/content/renderer/document_subresource_filter.cc
@@ -0,0 +1,144 @@
+// 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 "components/subresource_filter/content/renderer/document_subresource_filter.h"
+
+#include <climits>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/trace_event/trace_event.h"
+#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+
+namespace subresource_filter {
+
+namespace {
+
+proto::ElementType ToElementType(
+ blink::WebURLRequest::RequestContext request_context) {
+ switch (request_context) {
+ case blink::WebURLRequest::RequestContextAudio:
+ case blink::WebURLRequest::RequestContextVideo:
+ case blink::WebURLRequest::RequestContextTrack:
+ return proto::ELEMENT_TYPE_MEDIA;
+ case blink::WebURLRequest::RequestContextBeacon:
+ case blink::WebURLRequest::RequestContextPing:
+ return proto::ELEMENT_TYPE_PING;
+ case blink::WebURLRequest::RequestContextEmbed:
+ case blink::WebURLRequest::RequestContextObject:
+ case blink::WebURLRequest::RequestContextPlugin:
+ return proto::ELEMENT_TYPE_OBJECT;
+ case blink::WebURLRequest::RequestContextEventSource:
+ case blink::WebURLRequest::RequestContextFetch:
+ case blink::WebURLRequest::RequestContextXMLHttpRequest:
+ return proto::ELEMENT_TYPE_XMLHTTPREQUEST;
+ case blink::WebURLRequest::RequestContextFavicon:
+ case blink::WebURLRequest::RequestContextImage:
+ case blink::WebURLRequest::RequestContextImageSet:
+ return proto::ELEMENT_TYPE_IMAGE;
+ case blink::WebURLRequest::RequestContextFont:
+ return proto::ELEMENT_TYPE_FONT;
+ case blink::WebURLRequest::RequestContextFrame:
+ case blink::WebURLRequest::RequestContextForm:
+ case blink::WebURLRequest::RequestContextHyperlink:
+ case blink::WebURLRequest::RequestContextIframe:
+ case blink::WebURLRequest::RequestContextInternal:
+ case blink::WebURLRequest::RequestContextLocation:
+ return proto::ELEMENT_TYPE_SUBDOCUMENT;
+ case blink::WebURLRequest::RequestContextScript:
+ case blink::WebURLRequest::RequestContextServiceWorker:
+ case blink::WebURLRequest::RequestContextSharedWorker:
+ return proto::ELEMENT_TYPE_SCRIPT;
+ case blink::WebURLRequest::RequestContextStyle:
+ case blink::WebURLRequest::RequestContextXSLT:
+ return proto::ELEMENT_TYPE_STYLESHEET;
+
+ case blink::WebURLRequest::RequestContextPrefetch:
+ case blink::WebURLRequest::RequestContextSubresource:
+ return proto::ELEMENT_TYPE_OTHER;
+
+ case blink::WebURLRequest::RequestContextCSPReport:
+ case blink::WebURLRequest::RequestContextDownload:
+ case blink::WebURLRequest::RequestContextImport:
+ case blink::WebURLRequest::RequestContextManifest:
+ case blink::WebURLRequest::RequestContextUnspecified:
+ default:
+ return proto::ELEMENT_TYPE_UNSPECIFIED;
+ }
+}
+
+} // namespace
+
+DocumentSubresourceFilter::DocumentSubresourceFilter(
+ ActivationState activation_state,
+ const scoped_refptr<const MemoryMappedRuleset>& ruleset,
+ const std::vector<GURL>& ancestor_document_urls,
+ const base::Closure& first_disallowed_load_callback)
+ : activation_state_(activation_state),
+ ruleset_(ruleset),
+ ruleset_matcher_(ruleset_->data(), ruleset_->length()),
+ first_disallowed_load_callback_(first_disallowed_load_callback) {
+ DCHECK_NE(activation_state_, ActivationState::DISABLED);
+ DCHECK(ruleset);
+
+ if (ancestor_document_urls.empty())
+ return;
+
+ document_origin_ = url::Origin(ancestor_document_urls.front());
+
+ url::Origin parent_document_origin;
+ for (auto iter = ancestor_document_urls.rbegin(),
+ rend = ancestor_document_urls.rend();
+ iter != rend; ++iter) {
+ const GURL& document_url(*iter);
+ if (ruleset_matcher_.ShouldDisableFilteringForDocument(
+ document_url, parent_document_origin,
+ proto::ACTIVATION_TYPE_DOCUMENT)) {
+ filtering_disabled_for_document_ = true;
+ return;
+ }
+ parent_document_origin = url::Origin(document_url);
+ }
+
+ // TODO(pkalinnikov): Implement GENERICBLOCK activation type as well.
+ // TODO(pkalinnikov): Match several activation types in a batch.
+}
+
+DocumentSubresourceFilter::~DocumentSubresourceFilter() = default;
+
+bool DocumentSubresourceFilter::allowLoad(
+ const blink::WebURL& resourceUrl,
+ blink::WebURLRequest::RequestContext request_context) {
+ TRACE_EVENT1("loader", "DocumentSubresourceFilter::allowLoad", "url",
+ resourceUrl.string().utf8());
+
+ ++num_loads_total_;
+
+ if (filtering_disabled_for_document_)
+ return true;
+
+ if (resourceUrl.protocolIs(url::kDataScheme))
+ return true;
+
+ ++num_loads_evaluated_;
+ if (ruleset_matcher_.ShouldDisallowResourceLoad(
+ GURL(resourceUrl), document_origin_,
+ ToElementType(request_context))) {
+ ++num_loads_matching_rules_;
+ if (activation_state_ == ActivationState::ENABLED) {
+ if (!first_disallowed_load_callback_.is_null()) {
+ DCHECK_EQ(num_loads_disallowed_, 0u);
+ first_disallowed_load_callback_.Run();
+ first_disallowed_load_callback_.Reset();
+ }
+ ++num_loads_disallowed_;
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/renderer/document_subresource_filter.h b/chromium/components/subresource_filter/content/renderer/document_subresource_filter.h
new file mode 100644
index 00000000000..dd05ab644d6
--- /dev/null
+++ b/chromium/components/subresource_filter/content/renderer/document_subresource_filter.h
@@ -0,0 +1,89 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_RENDERER_DOCUMENT_SUBRESOURCE_FILTER_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_RENDERER_DOCUMENT_SUBRESOURCE_FILTER_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "components/subresource_filter/core/common/activation_state.h"
+#include "components/subresource_filter/core/common/indexed_ruleset.h"
+#include "third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace subresource_filter {
+
+class MemoryMappedRuleset;
+
+// Performs filtering of subresource loads in the scope of a given document.
+class DocumentSubresourceFilter
+ : public blink::WebDocumentSubresourceFilter,
+ public base::SupportsWeakPtr<DocumentSubresourceFilter> {
+ public:
+ // Constructs a new filter that will:
+ // -- Operate at the prescribed |activation_state|, which must be either
+ // ActivationState::DRYRUN or ActivationState::ENABLED. In the former
+ // case filtering will be performed but no loads will be disallowed.
+ // -- Hold a reference to and use |ruleset| for its entire lifetime.
+ // -- Expect |ancestor_document_urls| to be the URLs of documents loaded into
+ // nested frames, starting with the current frame and ending with the main
+ // frame. This provides the context for evaluating domain-specific rules.
+ // -- Invoke |first_disallowed_load_callback|, if it is non-null, on the
+ // first disallowed subresource load.
+ DocumentSubresourceFilter(
+ ActivationState activation_state,
+ const scoped_refptr<const MemoryMappedRuleset>& ruleset,
+ const std::vector<GURL>& ancestor_document_urls,
+ const base::Closure& first_disallowed_load_callback);
+ ~DocumentSubresourceFilter() override;
+
+ // blink::WebDocumentSubresourceFilter:
+ bool allowLoad(const blink::WebURL& resourceUrl,
+ blink::WebURLRequest::RequestContext) override;
+
+ // The number of subresource loads that went through the allowLoad method.
+ size_t num_loads_total() const { return num_loads_total_; }
+ // Statistics on the number of subresource loads that were evaluated, were
+ // matched by filtering rules, and were disallowed, respectively, during the
+ // lifetime of |this| filter.
+ size_t num_loads_evaluated() const { return num_loads_evaluated_; }
+ size_t num_loads_matching_rules() const { return num_loads_matching_rules_; }
+ size_t num_loads_disallowed() const { return num_loads_disallowed_; }
+
+ private:
+ ActivationState activation_state_;
+ scoped_refptr<const MemoryMappedRuleset> ruleset_;
+ IndexedRulesetMatcher ruleset_matcher_;
+ url::Origin document_origin_;
+
+ base::Closure first_disallowed_load_callback_;
+
+ size_t num_loads_total_ = 0;
+ size_t num_loads_evaluated_ = 0;
+ size_t num_loads_matching_rules_ = 0;
+ size_t num_loads_disallowed_ = 0;
+
+ // Even when subresource filtering is activated at the page level by the
+ // |activation_state| passed into the constructor, the current document or
+ // ancestors thereof may still match special filtering rules that specifically
+ // disable the application of other types of rules on these documents. See
+ // proto::ActivationType for details.
+ //
+ // Indicates whether the document is subject to a whitelist rule with DOCUMENT
+ // activation type.
+ bool filtering_disabled_for_document_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(DocumentSubresourceFilter);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_RENDERER_DOCUMENT_SUBRESOURCE_FILTER_H_
diff --git a/chromium/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc b/chromium/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc
new file mode 100644
index 00000000000..97ecc439161
--- /dev/null
+++ b/chromium/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc
@@ -0,0 +1,124 @@
+// 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 "components/subresource_filter/content/renderer/document_subresource_filter.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
+#include "components/subresource_filter/core/common/test_ruleset_creator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "url/gurl.h"
+
+namespace subresource_filter {
+
+namespace {
+
+const char kTestAlphaURL[] = "http://example.com/alpha";
+const char kTestAlphaDataURI[] = "data:text/plain,alpha";
+const char kTestBetaURL[] = "http://example.com/beta";
+
+const char kTestAlphaURLPathSuffix[] = "alpha";
+
+class TestCallbackReceiver {
+ public:
+ TestCallbackReceiver() = default;
+ base::Closure closure() {
+ return base::Bind(&TestCallbackReceiver::CallbackMethod,
+ base::Unretained(this));
+ }
+ size_t callback_count() const { return callback_count_; }
+
+ private:
+ void CallbackMethod() { ++callback_count_; }
+
+ size_t callback_count_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(TestCallbackReceiver);
+};
+
+} // namespace
+
+class DocumentSubresourceFilterTest : public ::testing::Test {
+ public:
+ DocumentSubresourceFilterTest() {}
+
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestAlphaURLPathSuffix));
+ }
+
+ void SetTestRulesetToDisallowURLsWithPathSuffix(base::StringPiece suffix) {
+ testing::TestRulesetPair test_ruleset_pair;
+ ASSERT_NO_FATAL_FAILURE(
+ test_ruleset_creator_.CreateRulesetToDisallowURLsWithPathSuffix(
+ suffix, &test_ruleset_pair));
+ ruleset_ = new MemoryMappedRuleset(
+ testing::TestRuleset::Open(test_ruleset_pair.indexed));
+ }
+
+ const MemoryMappedRuleset* ruleset() { return ruleset_.get(); }
+
+ private:
+ testing::TestRulesetCreator test_ruleset_creator_;
+ scoped_refptr<const MemoryMappedRuleset> ruleset_;
+
+ DISALLOW_COPY_AND_ASSIGN(DocumentSubresourceFilterTest);
+};
+
+TEST_F(DocumentSubresourceFilterTest, DryRun) {
+ blink::WebURLRequest::RequestContext request_context =
+ blink::WebURLRequest::RequestContextImage;
+ TestCallbackReceiver first_disallowed_load_callback_receiver;
+ DocumentSubresourceFilter filter(
+ ActivationState::DRYRUN, ruleset(), std::vector<GURL>(),
+ first_disallowed_load_callback_receiver.closure());
+ EXPECT_TRUE(filter.allowLoad(GURL(kTestAlphaURL), request_context));
+ EXPECT_TRUE(filter.allowLoad(GURL(kTestAlphaDataURI), request_context));
+ EXPECT_TRUE(filter.allowLoad(GURL(kTestBetaURL), request_context));
+ EXPECT_EQ(3u, filter.num_loads_total());
+ EXPECT_EQ(2u, filter.num_loads_evaluated());
+ EXPECT_EQ(1u, filter.num_loads_matching_rules());
+ EXPECT_EQ(0u, filter.num_loads_disallowed());
+ EXPECT_EQ(0u, first_disallowed_load_callback_receiver.callback_count());
+}
+
+TEST_F(DocumentSubresourceFilterTest, Enabled) {
+ blink::WebURLRequest::RequestContext request_context =
+ blink::WebURLRequest::RequestContextImage;
+ DocumentSubresourceFilter filter(ActivationState::ENABLED, ruleset(),
+ std::vector<GURL>(), base::Closure());
+ EXPECT_FALSE(filter.allowLoad(GURL(kTestAlphaURL), request_context));
+ EXPECT_TRUE(filter.allowLoad(GURL(kTestAlphaDataURI), request_context));
+ EXPECT_TRUE(filter.allowLoad(GURL(kTestBetaURL), request_context));
+ EXPECT_EQ(3u, filter.num_loads_total());
+ EXPECT_EQ(2u, filter.num_loads_evaluated());
+ EXPECT_EQ(1u, filter.num_loads_matching_rules());
+ EXPECT_EQ(1u, filter.num_loads_disallowed());
+}
+
+TEST_F(DocumentSubresourceFilterTest,
+ CallbackFiredExactlyOnceAfterFirstDisallowedLoad) {
+ blink::WebURLRequest::RequestContext request_context =
+ blink::WebURLRequest::RequestContextImage;
+ TestCallbackReceiver first_disallowed_load_callback_receiver;
+ DocumentSubresourceFilter filter(
+ ActivationState::ENABLED, ruleset(), std::vector<GURL>(),
+ first_disallowed_load_callback_receiver.closure());
+ EXPECT_TRUE(filter.allowLoad(GURL(kTestAlphaDataURI), request_context));
+ EXPECT_EQ(0u, first_disallowed_load_callback_receiver.callback_count());
+ EXPECT_FALSE(filter.allowLoad(GURL(kTestAlphaURL), request_context));
+ EXPECT_EQ(1u, first_disallowed_load_callback_receiver.callback_count());
+ EXPECT_FALSE(filter.allowLoad(GURL(kTestAlphaURL), request_context));
+ EXPECT_EQ(1u, first_disallowed_load_callback_receiver.callback_count());
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/renderer/ruleset_dealer.cc b/chromium/components/subresource_filter/content/renderer/ruleset_dealer.cc
index df0bfc58dad..cab81330dab 100644
--- a/chromium/components/subresource_filter/content/renderer/ruleset_dealer.cc
+++ b/chromium/components/subresource_filter/content/renderer/ruleset_dealer.cc
@@ -17,6 +17,11 @@ namespace subresource_filter {
RulesetDealer::RulesetDealer() = default;
RulesetDealer::~RulesetDealer() = default;
+void RulesetDealer::SetRulesetFile(base::File ruleset_file) {
+ DCHECK(ruleset_file.IsValid());
+ ruleset_ = new MemoryMappedRuleset(std::move(ruleset_file));
+}
+
bool RulesetDealer::OnControlMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RulesetDealer, message)
@@ -29,9 +34,7 @@ bool RulesetDealer::OnControlMessageReceived(const IPC::Message& message) {
void RulesetDealer::OnSetRulesetForProcess(
const IPC::PlatformFileForTransit& platform_file) {
- base::File file = IPC::PlatformFileForTransitToFile(platform_file);
- DCHECK(file.IsValid());
- ruleset_ = new MemoryMappedRuleset(std::move(file));
+ SetRulesetFile(IPC::PlatformFileForTransitToFile(platform_file));
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/renderer/ruleset_dealer.h b/chromium/components/subresource_filter/content/renderer/ruleset_dealer.h
index 2054c61a8c7..556342b6d22 100644
--- a/chromium/components/subresource_filter/content/renderer/ruleset_dealer.h
+++ b/chromium/components/subresource_filter/content/renderer/ruleset_dealer.h
@@ -28,14 +28,17 @@ class RulesetDealer : public content::RenderThreadObserver {
RulesetDealer();
~RulesetDealer() override;
- const scoped_refptr<MemoryMappedRuleset>& ruleset() { return ruleset_; }
+ // Sets the |ruleset_file| to memory map and distribute from now on.
+ void SetRulesetFile(base::File ruleset_file);
+
+ const scoped_refptr<const MemoryMappedRuleset>& ruleset() { return ruleset_; }
private:
// content::RenderThreadObserver:
bool OnControlMessageReceived(const IPC::Message& message) override;
void OnSetRulesetForProcess(const IPC::PlatformFileForTransit& file);
- scoped_refptr<MemoryMappedRuleset> ruleset_;
+ scoped_refptr<const MemoryMappedRuleset> ruleset_;
DISALLOW_COPY_AND_ASSIGN(RulesetDealer);
};
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
index 4330a5e6e41..9f40c190b14 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -4,97 +4,137 @@
#include "components/subresource_filter/content/renderer/subresource_filter_agent.h"
-#include <climits>
-
+#include "base/logging.h"
#include "base/memory/ref_counted.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
+#include "base/metrics/histogram_macros.h"
#include "components/subresource_filter/content/common/subresource_filter_messages.h"
+#include "components/subresource_filter/content/renderer/document_subresource_filter.h"
#include "components/subresource_filter/content/renderer/ruleset_dealer.h"
#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
#include "content/public/renderer/render_frame.h"
#include "ipc/ipc_message.h"
-#include "third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "url/gurl.h"
namespace subresource_filter {
-namespace {
-
-// Placeholder subresource filter implementation that treats the entire ruleset
-// as the UTF-8 representation of a string, and will disallow subresource loads
-// from URL paths having this string as a suffix.
-// TODO(engedy): Replace this with the actual filtering logic.
-class PathSuffixFilter : public blink::WebDocumentSubresourceFilter {
- public:
- explicit PathSuffixFilter(const scoped_refptr<MemoryMappedRuleset>& ruleset)
- : ruleset_(ruleset) {
- static_assert(CHAR_BIT == 8, "Assumed char was 8 bits.");
- disallowed_suffix_ = base::StringPiece(
- reinterpret_cast<const char*>(ruleset_->data()), ruleset_->length());
- }
- ~PathSuffixFilter() override {}
-
- bool allowLoad(const blink::WebURL& resourceUrl,
- blink::WebURLRequest::RequestContext) override {
- return disallowed_suffix_.empty() ||
- !base::EndsWith(GURL(resourceUrl).path(), disallowed_suffix_,
- base::CompareCase::SENSITIVE);
- }
-
- private:
- scoped_refptr<MemoryMappedRuleset> ruleset_;
- base::StringPiece disallowed_suffix_;
-
- DISALLOW_COPY_AND_ASSIGN(PathSuffixFilter);
-};
-
-} // namespace
-
SubresourceFilterAgent::SubresourceFilterAgent(
content::RenderFrame* render_frame,
RulesetDealer* ruleset_dealer)
: content::RenderFrameObserver(render_frame),
ruleset_dealer_(ruleset_dealer),
- activation_state_for_provisional_load_(ActivationState::DISABLED) {}
+ activation_state_for_provisional_load_(ActivationState::DISABLED) {
+ DCHECK(ruleset_dealer);
+}
SubresourceFilterAgent::~SubresourceFilterAgent() = default;
+std::vector<GURL> SubresourceFilterAgent::GetAncestorDocumentURLs() {
+ std::vector<GURL> urls;
+ // As a temporary workaround for --isolate-extensions, ignore the ancestor
+ // hierarchy after crossing an extension/non-extension boundary. This,
+ // however, will not be a satisfactory solution for OOPIF in general.
+ // See: https://crbug.com/637415.
+ blink::WebFrame* frame = render_frame()->GetWebFrame();
+ do {
+ urls.push_back(frame->document().url());
+ frame = frame->parent();
+ } while (frame && frame->isWebLocalFrame());
+ return urls;
+}
+
+void SubresourceFilterAgent::SetSubresourceFilterForCommittedLoad(
+ std::unique_ptr<blink::WebDocumentSubresourceFilter> filter) {
+ blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame();
+ web_frame->dataSource()->setSubresourceFilter(filter.release());
+}
+
+void SubresourceFilterAgent::
+ SignalFirstSubresourceDisallowedForCommittedLoad() {
+ render_frame()->Send(new SubresourceFilterHostMsg_DidDisallowFirstSubresource(
+ render_frame()->GetRoutingID()));
+}
+
+void SubresourceFilterAgent::ActivateForProvisionalLoad(
+ ActivationState activation_state) {
+ activation_state_for_provisional_load_ = activation_state;
+}
+
+void SubresourceFilterAgent::RecordHistogramsOnLoadCommitted() {
+ UMA_HISTOGRAM_ENUMERATION(
+ "SubresourceFilter.DocumentLoad.ActivationState",
+ static_cast<int>(activation_state_for_provisional_load_),
+ static_cast<int>(ActivationState::LAST) + 1);
+
+ if (activation_state_for_provisional_load_ != ActivationState::DISABLED) {
+ UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.DocumentLoad.RulesetIsAvailable",
+ !!ruleset_dealer_->ruleset());
+ }
+}
+
+void SubresourceFilterAgent::RecordHistogramsOnLoadFinished() {
+ DCHECK(filter_for_last_committed_load_);
+ UMA_HISTOGRAM_COUNTS_1000(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Total",
+ filter_for_last_committed_load_->num_loads_total());
+ UMA_HISTOGRAM_COUNTS_1000(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Evaluated",
+ filter_for_last_committed_load_->num_loads_evaluated());
+ UMA_HISTOGRAM_COUNTS_1000(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.MatchedRules",
+ filter_for_last_committed_load_->num_loads_matching_rules());
+ UMA_HISTOGRAM_COUNTS_1000(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Disallowed",
+ filter_for_last_committed_load_->num_loads_disallowed());
+}
+
void SubresourceFilterAgent::OnDestruct() {
delete this;
}
void SubresourceFilterAgent::DidStartProvisionalLoad() {
activation_state_for_provisional_load_ = ActivationState::DISABLED;
+ filter_for_last_committed_load_.reset();
}
void SubresourceFilterAgent::DidCommitProvisionalLoad(
bool is_new_navigation,
bool is_same_page_navigation) {
- if (activation_state_for_provisional_load_ == ActivationState::ENABLED &&
+ RecordHistogramsOnLoadCommitted();
+ if (activation_state_for_provisional_load_ != ActivationState::DISABLED &&
ruleset_dealer_->ruleset()) {
- blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame();
- web_frame->dataSource()->setSubresourceFilter(
- new PathSuffixFilter(ruleset_dealer_->ruleset()));
+ std::vector<GURL> ancestor_document_urls = GetAncestorDocumentURLs();
+ base::Closure first_disallowed_load_callback(
+ base::Bind(&SubresourceFilterAgent::
+ SignalFirstSubresourceDisallowedForCommittedLoad,
+ AsWeakPtr()));
+ std::unique_ptr<DocumentSubresourceFilter> filter(
+ new DocumentSubresourceFilter(
+ activation_state_for_provisional_load_, ruleset_dealer_->ruleset(),
+ ancestor_document_urls, first_disallowed_load_callback));
+ filter_for_last_committed_load_ = filter->AsWeakPtr();
+ SetSubresourceFilterForCommittedLoad(std::move(filter));
}
+ activation_state_for_provisional_load_ = ActivationState::DISABLED;
+}
+
+void SubresourceFilterAgent::DidFinishLoad() {
+ if (!filter_for_last_committed_load_)
+ return;
+
+ RecordHistogramsOnLoadFinished();
}
bool SubresourceFilterAgent::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(SubresourceFilterAgent, message)
IPC_MESSAGE_HANDLER(SubresourceFilterMsg_ActivateForProvisionalLoad,
- OnActivateForProvisionalLoad)
+ ActivateForProvisionalLoad)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void SubresourceFilterAgent::OnActivateForProvisionalLoad(
- ActivationState activation_state) {
- activation_state_for_provisional_load_ = activation_state;
-}
-
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
index a93c77acce3..731563a048a 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
@@ -5,40 +5,74 @@
#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_RENDERER_SUBRESOURCE_FILTER_AGENT_H_
#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_RENDERER_SUBRESOURCE_FILTER_AGENT_H_
+#include <memory>
+#include <vector>
+
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "components/subresource_filter/core/common/activation_state.h"
#include "content/public/renderer/render_frame_observer.h"
+class GURL;
+
+namespace blink {
+class WebDocumentSubresourceFilter;
+} // namespace blink
+
namespace subresource_filter {
class RulesetDealer;
+class DocumentSubresourceFilter;
// The renderer-side agent of the ContentSubresourceFilterDriver. There is one
// instance per RenderFrame, responsible for setting up the subresource filter
// for the ongoing provisional document load in the frame when instructed to do
// so by the driver.
-class SubresourceFilterAgent : public content::RenderFrameObserver {
+class SubresourceFilterAgent
+ : public content::RenderFrameObserver,
+ public base::SupportsWeakPtr<SubresourceFilterAgent> {
public:
+ // The |ruleset_dealer| must not be null and must outlive this instance. The
+ // |render_frame| may be null in unittests.
explicit SubresourceFilterAgent(content::RenderFrame* render_frame,
RulesetDealer* ruleset_dealer);
~SubresourceFilterAgent() override;
+ protected:
+ // Below methods are protected virtual so they can be mocked out in tests.
+
+ // Returns the URLs of documents loaded into nested frames starting with the
+ // current frame and ending with the main frame. The returned array is
+ // guaranteed to have at least one element.
+ virtual std::vector<GURL> GetAncestorDocumentURLs();
+
+ // Injects the provided subresource |filter| into the DocumentLoader
+ // orchestrating the most recently committed load.
+ virtual void SetSubresourceFilterForCommittedLoad(
+ std::unique_ptr<blink::WebDocumentSubresourceFilter> filter);
+
+ // Informs the browser that the first subresource load has been disallowed for
+ // the most recently committed load. Not called if all resources are allowed.
+ virtual void SignalFirstSubresourceDisallowedForCommittedLoad();
+
private:
+ void ActivateForProvisionalLoad(ActivationState activation_state);
+ void RecordHistogramsOnLoadCommitted();
+ void RecordHistogramsOnLoadFinished();
+
// content::RenderFrameObserver:
void OnDestruct() override;
void DidStartProvisionalLoad() override;
void DidCommitProvisionalLoad(bool is_new_navigation,
bool is_same_page_navigation) override;
-
- // content::RenderFrameObserver:
+ void DidFinishLoad() override;
bool OnMessageReceived(const IPC::Message& message) override;
- void OnActivateForProvisionalLoad(ActivationState activation_state);
-
// Owned by the ChromeContentRendererClient and outlives us.
RulesetDealer* ruleset_dealer_;
ActivationState activation_state_for_provisional_load_;
+ base::WeakPtr<DocumentSubresourceFilter> filter_for_last_committed_load_;
DISALLOW_COPY_AND_ASSIGN(SubresourceFilterAgent);
};
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
new file mode 100644
index 00000000000..9e3d181e7b8
--- /dev/null
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -0,0 +1,410 @@
+// 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 "components/subresource_filter/content/renderer/subresource_filter_agent.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "base/test/histogram_tester.h"
+#include "components/subresource_filter/content/common/subresource_filter_messages.h"
+#include "components/subresource_filter/content/renderer/ruleset_dealer.h"
+#include "components/subresource_filter/core/common/test_ruleset_creator.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "url/gurl.h"
+
+namespace subresource_filter {
+
+namespace {
+
+// The SubresourceFilterAgent with its dependencies on Blink mocked out.
+//
+// This approach is somewhat rudimentary, but appears to be the best compromise
+// considering the alternatives:
+// -- Passing in a TestRenderFrame would itself require bringing up a
+// significant number of supporting classes.
+// -- Using a RenderViewTest would not allow having any non-filtered resource
+// loads due to not having a child thread and ResourceDispatcher.
+// The real implementations of the mocked-out methods are exercised in:
+// chrome/browser/subresource_filter/subresource_filter_browsertest.cc.
+class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent {
+ public:
+ explicit SubresourceFilterAgentUnderTest(RulesetDealer* ruleset_dealer)
+ : SubresourceFilterAgent(nullptr /* RenderFrame */, ruleset_dealer) {}
+ ~SubresourceFilterAgentUnderTest() = default;
+
+ MOCK_METHOD0(GetAncestorDocumentURLs, std::vector<GURL>());
+ MOCK_METHOD0(OnSetSubresourceFilterForCommittedLoadCalled, void());
+ MOCK_METHOD0(SignalFirstSubresourceDisallowedForCommittedLoad, void());
+ void SetSubresourceFilterForCommittedLoad(
+ std::unique_ptr<blink::WebDocumentSubresourceFilter> filter) override {
+ last_injected_filter_ = std::move(filter);
+ OnSetSubresourceFilterForCommittedLoadCalled();
+ }
+
+ blink::WebDocumentSubresourceFilter* filter() {
+ return last_injected_filter_.get();
+ }
+
+ std::unique_ptr<blink::WebDocumentSubresourceFilter> TakeFilter() {
+ return std::move(last_injected_filter_);
+ }
+
+ private:
+ std::unique_ptr<blink::WebDocumentSubresourceFilter> last_injected_filter_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterAgentUnderTest);
+};
+
+const char kTestFirstURL[] = "http://example.com/alpha";
+const char kTestSecondURL[] = "http://example.com/beta";
+const char kTestFirstURLPathSuffix[] = "alpha";
+const char kTestSecondURLPathSuffix[] = "beta";
+const char kTestBothURLsPathSuffix[] = "a";
+
+} // namespace
+
+class SubresourceFilterAgentTest : public ::testing::Test {
+ public:
+ SubresourceFilterAgentTest() {}
+
+ protected:
+ void SetUp() override { ResetAgent(); }
+
+ void ResetAgent() {
+ agent_.reset(new ::testing::StrictMock<SubresourceFilterAgentUnderTest>(
+ &ruleset_dealer_));
+ ON_CALL(*agent(), GetAncestorDocumentURLs())
+ .WillByDefault(::testing::Return(std::vector<GURL>(
+ {GURL("http://inner.com/"), GURL("http://outer.com/")})));
+ }
+
+ void SetTestRulesetToDisallowURLsWithPathSuffix(base::StringPiece suffix) {
+ testing::TestRulesetPair test_ruleset_pair;
+ ASSERT_NO_FATAL_FAILURE(
+ test_ruleset_creator_.CreateRulesetToDisallowURLsWithPathSuffix(
+ suffix, &test_ruleset_pair));
+ ruleset_dealer_.SetRulesetFile(
+ testing::TestRuleset::Open(test_ruleset_pair.indexed));
+ }
+
+ void StartLoadWithoutSettingActivationState() {
+ agent_as_rfo()->DidStartProvisionalLoad();
+ agent_as_rfo()->DidCommitProvisionalLoad(
+ true /* is_new_navigation */, false /* is_same_page_navigation */);
+ }
+
+ void StartLoadAndSetActivationState(ActivationState activation_state) {
+ agent_as_rfo()->DidStartProvisionalLoad();
+ EXPECT_TRUE(agent_as_rfo()->OnMessageReceived(
+ SubresourceFilterMsg_ActivateForProvisionalLoad(0, activation_state)));
+ agent_as_rfo()->DidCommitProvisionalLoad(
+ true /* is_new_navigation */, false /* is_same_page_navigation */);
+ }
+
+ void FinishLoad() { agent_as_rfo()->DidFinishLoad(); }
+
+ void ExpectSubresourceFilterGetsInjected() {
+ EXPECT_CALL(*agent(), GetAncestorDocumentURLs());
+ EXPECT_CALL(*agent(), OnSetSubresourceFilterForCommittedLoadCalled());
+ }
+
+ void ExpectSignalAboutFirstSubresourceDisallowed() {
+ EXPECT_CALL(*agent(), SignalFirstSubresourceDisallowedForCommittedLoad());
+ }
+
+ void ExpectNoSubresourceFilterGetsInjected() {
+ EXPECT_CALL(*agent(), OnSetSubresourceFilterForCommittedLoadCalled())
+ .Times(0);
+ }
+
+ void ExpectNoSignalAboutFirstSubresourceDisallowed() {
+ EXPECT_CALL(*agent(), SignalFirstSubresourceDisallowedForCommittedLoad())
+ .Times(0);
+ }
+
+ void ExpectLoadAllowed(base::StringPiece url_spec, bool allowed) {
+ blink::WebURL url = GURL(url_spec);
+ blink::WebURLRequest::RequestContext request_context =
+ blink::WebURLRequest::RequestContextImage;
+ EXPECT_EQ(allowed, agent()->filter()->allowLoad(url, request_context));
+ }
+
+ SubresourceFilterAgentUnderTest* agent() { return agent_.get(); }
+ content::RenderFrameObserver* agent_as_rfo() {
+ return static_cast<content::RenderFrameObserver*>(agent_.get());
+ }
+
+ private:
+ testing::TestRulesetCreator test_ruleset_creator_;
+ RulesetDealer ruleset_dealer_;
+
+ std::unique_ptr<SubresourceFilterAgentUnderTest> agent_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterAgentTest);
+};
+
+TEST_F(SubresourceFilterAgentTest, DisabledByDefault_NoFilterIsInjected) {
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix));
+ ExpectNoSubresourceFilterGetsInjected();
+ StartLoadWithoutSettingActivationState();
+ FinishLoad();
+}
+
+TEST_F(SubresourceFilterAgentTest, Disabled_NoFilterIsInjected) {
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix));
+ ExpectNoSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::DISABLED);
+ FinishLoad();
+}
+
+TEST_F(SubresourceFilterAgentTest,
+ EnabledButRulesetUnavailable_NoFilterIsInjected) {
+ ExpectNoSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::ENABLED);
+ FinishLoad();
+}
+
+TEST_F(SubresourceFilterAgentTest, Enabled_FilteringIsInEffectForOneLoad) {
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
+
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::ENABLED);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ ExpectSignalAboutFirstSubresourceDisallowed();
+ ExpectLoadAllowed(kTestFirstURL, false);
+ ExpectLoadAllowed(kTestSecondURL, true);
+ FinishLoad();
+
+ ExpectNoSubresourceFilterGetsInjected();
+ StartLoadWithoutSettingActivationState();
+ FinishLoad();
+}
+
+TEST_F(SubresourceFilterAgentTest, Enabled_NewRulesetIsPickedUpAtNextLoad) {
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::ENABLED);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ // Set the new ruleset just after the deadline for being used for the current
+ // load, to exercises doing filtering based on obseleted rulesets.
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestSecondURLPathSuffix));
+
+ ExpectSignalAboutFirstSubresourceDisallowed();
+ ExpectLoadAllowed(kTestFirstURL, false);
+ ExpectLoadAllowed(kTestSecondURL, true);
+ FinishLoad();
+
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::ENABLED);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ ExpectSignalAboutFirstSubresourceDisallowed();
+ ExpectLoadAllowed(kTestFirstURL, true);
+ ExpectLoadAllowed(kTestSecondURL, false);
+ FinishLoad();
+}
+
+// If a provisional load is aborted, the RenderFrameObservers might not receive
+// any further notifications about that load. It is thus possible that there
+// will be two RenderFrameObserver::DidStartProvisionalLoad in a row. Make sure
+// that the activation decision does not outlive the first provisional load.
+TEST_F(SubresourceFilterAgentTest,
+ Enabled_FilteringNoLongerEffectAfterProvisionalLoadIsCancelled) {
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix));
+ ExpectNoSubresourceFilterGetsInjected();
+ agent_as_rfo()->DidStartProvisionalLoad();
+ EXPECT_TRUE(agent_as_rfo()->OnMessageReceived(
+ SubresourceFilterMsg_ActivateForProvisionalLoad(
+ 0, ActivationState::ENABLED)));
+ agent_as_rfo()->DidStartProvisionalLoad();
+ agent_as_rfo()->DidCommitProvisionalLoad(true /* is_new_navigation */,
+ false /* is_same_page_navigation */);
+ FinishLoad();
+}
+
+TEST_F(SubresourceFilterAgentTest, DryRun_ResourcesAreEvaluatedButNotFiltered) {
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::DRYRUN);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ ExpectLoadAllowed(kTestFirstURL, true);
+ ExpectLoadAllowed(kTestSecondURL, true);
+ FinishLoad();
+}
+
+TEST_F(SubresourceFilterAgentTest,
+ SignalFirstSubresourceDisallowed_OncePerDocumentLoad) {
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::ENABLED);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ ExpectSignalAboutFirstSubresourceDisallowed();
+ ExpectLoadAllowed(kTestFirstURL, false);
+ ExpectNoSignalAboutFirstSubresourceDisallowed();
+ ExpectLoadAllowed(kTestFirstURL, false);
+ ExpectLoadAllowed(kTestSecondURL, true);
+ FinishLoad();
+
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::ENABLED);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ ExpectLoadAllowed(kTestSecondURL, true);
+ ExpectSignalAboutFirstSubresourceDisallowed();
+ ExpectLoadAllowed(kTestFirstURL, false);
+ FinishLoad();
+}
+
+TEST_F(SubresourceFilterAgentTest,
+ SignalFirstSubresourceDisallowed_ComesAfterAgentDestroyed) {
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::ENABLED);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ auto filter = agent()->TakeFilter();
+ ResetAgent();
+ EXPECT_FALSE(filter->allowLoad(GURL(kTestFirstURL),
+ blink::WebURLRequest::RequestContextImage));
+}
+
+TEST_F(SubresourceFilterAgentTest, Disabled_HistogramSamples) {
+ base::HistogramTester histogram_tester;
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestBothURLsPathSuffix));
+ StartLoadWithoutSettingActivationState();
+ FinishLoad();
+
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.ActivationState",
+ static_cast<int>(ActivationState::DISABLED), 1);
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.DocumentLoad.RulesetIsAvailable", 0);
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Total", 0);
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Evaluated", 0);
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Disallowed", 0);
+}
+
+TEST_F(SubresourceFilterAgentTest,
+ EnabledButRulesetUnavailable_HistogramSamples) {
+ base::HistogramTester histogram_tester;
+ StartLoadAndSetActivationState(ActivationState::ENABLED);
+ FinishLoad();
+
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.ActivationState",
+ static_cast<int>(ActivationState::ENABLED), 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.RulesetIsAvailable", 0, 1);
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Total", 0);
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Evaluated", 0);
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.MatchedRules", 0);
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Disallowed", 0);
+}
+
+TEST_F(SubresourceFilterAgentTest, Enabled_HistogramSamples) {
+ base::HistogramTester histogram_tester;
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::ENABLED);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ ExpectSignalAboutFirstSubresourceDisallowed();
+ ExpectLoadAllowed(kTestFirstURL, false);
+ ExpectLoadAllowed(kTestFirstURL, false);
+ ExpectLoadAllowed(kTestSecondURL, true);
+ FinishLoad();
+
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::ENABLED);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ ExpectSignalAboutFirstSubresourceDisallowed();
+ ExpectLoadAllowed(kTestFirstURL, false);
+ ExpectLoadAllowed(kTestSecondURL, true);
+ FinishLoad();
+
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.ActivationState",
+ static_cast<int>(ActivationState::ENABLED), 2);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.RulesetIsAvailable", 1, 2);
+ EXPECT_THAT(histogram_tester.GetAllSamples(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Total"),
+ ::testing::ElementsAre(base::Bucket(2, 1), base::Bucket(3, 1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Evaluated"),
+ ::testing::ElementsAre(base::Bucket(2, 1), base::Bucket(3, 1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.MatchedRules"),
+ ::testing::ElementsAre(base::Bucket(1, 1), base::Bucket(2, 1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Disallowed"),
+ ::testing::ElementsAre(base::Bucket(1, 1), base::Bucket(2, 1)));
+}
+
+TEST_F(SubresourceFilterAgentTest, DryRun_HistogramSamples) {
+ base::HistogramTester histogram_tester;
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState::DRYRUN);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ // In dry-run mode, loads to the first URL should be recorded as
+ // `MatchedRules`, but still be allowed to proceed and not recorded as
+ // `Disallowed`.
+ ExpectLoadAllowed(kTestFirstURL, true);
+ ExpectLoadAllowed(kTestFirstURL, true);
+ ExpectLoadAllowed(kTestSecondURL, true);
+ FinishLoad();
+
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.ActivationState",
+ static_cast<int>(ActivationState::DRYRUN), 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.RulesetIsAvailable", 1, 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Total", 3, 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Evaluated", 3, 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.MatchedRules", 2, 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Disallowed", 0, 1);
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/browser/BUILD.gn b/chromium/components/subresource_filter/core/browser/BUILD.gn
index 63b8458b868..9e3ba6f1ee1 100644
--- a/chromium/components/subresource_filter/core/browser/BUILD.gn
+++ b/chromium/components/subresource_filter/core/browser/BUILD.gn
@@ -2,11 +2,12 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser") {
+static_library("browser") {
sources = [
"ruleset_distributor.h",
"ruleset_service.cc",
"ruleset_service.h",
+ "subresource_filter_client.h",
"subresource_filter_constants.cc",
"subresource_filter_constants.h",
"subresource_filter_features.cc",
@@ -17,10 +18,11 @@ source_set("browser") {
"//components/prefs:prefs",
"//components/subresource_filter/core/common",
"//components/variations",
+ "//third_party/protobuf:protobuf_lite",
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"subresource_filter_features_test_support.cc",
@@ -29,6 +31,7 @@ source_set("test_support") {
deps = [
":browser",
"//base",
+ "//base/test:test_support",
"//components/variations",
"//testing/gtest",
]
@@ -46,6 +49,7 @@ source_set("unit_tests") {
"//base",
"//base/test:test_support",
"//components/prefs:test_support",
+ "//components/subresource_filter/core/common:test_support",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/components/subresource_filter/core/browser/ruleset_service.cc b/chromium/components/subresource_filter/core/browser/ruleset_service.cc
index c64359144a9..c35c51f43de 100644
--- a/chromium/components/subresource_filter/core/browser/ruleset_service.cc
+++ b/chromium/components/subresource_filter/core/browser/ruleset_service.cc
@@ -7,11 +7,13 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/files/file_proxy.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/rand_util.h"
#include "base/sequenced_task_runner.h"
@@ -22,6 +24,11 @@
#include "components/prefs/pref_service.h"
#include "components/subresource_filter/core/browser/ruleset_distributor.h"
#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
+#include "components/subresource_filter/core/common/copying_file_stream.h"
+#include "components/subresource_filter/core/common/indexed_ruleset.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
+#include "components/subresource_filter/core/common/unindexed_ruleset.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
namespace subresource_filter {
@@ -29,9 +36,6 @@ namespace subresource_filter {
namespace {
-// The current binary format version of the serialized ruleset.
-const int kCurrentRulesetFormatVersion = 10;
-
// Names of the preferences storing the most recent ruleset version that
// was successfully stored to disk.
const char kSubresourceFilterRulesetContentVersion[] =
@@ -39,179 +43,376 @@ const char kSubresourceFilterRulesetContentVersion[] =
const char kSubresourceFilterRulesetFormatVersion[] =
"subresource_filter.ruleset_version.format";
-base::FilePath GetSubdirectoryPathForVersion(const base::FilePath& base_dir,
- const RulesetVersion& version) {
- return base_dir.AppendASCII(version.AsString());
+void RecordIndexAndWriteRulesetResult(
+ RulesetService::IndexAndWriteRulesetResult result) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "SubresourceFilter.WriteRuleset.Result", static_cast<int>(result),
+ static_cast<int>(RulesetService::IndexAndWriteRulesetResult::MAX));
}
-base::FilePath GetRulesetDataFilePath(const base::FilePath& version_directory) {
- return version_directory.Append(kRulesetDataFileName);
-}
+// Implements operations on a `sentinel file`, which is used as a safeguard to
+// prevent crash-looping if ruleset indexing crashes on start-up.
+//
+// The sentinel file is placed in the ruleset version directory just before
+// indexing commences, and removed afterwards. Therefore, if a sentinel file is
+// found on next start-up, it is an indication that the previous indexing
+// operation may have crashed, and indexing will not be attempted again.
+//
+// Admittedly, this approach errs on the side of caution, and false positives
+// can happen. For example, the sentinel file may fail to be removed in case of
+// an unclean shutdown, or an unrelated crash as well. This should not be a
+// problem, however, as the sentinel file only affects one version of the
+// ruleset, and it is expected that version updates will be frequent enough.
+class SentinelFile {
+ public:
+ static bool IsPresent(base::FilePath& path) { return base::PathExists(path); }
+
+ static bool Create(base::FilePath& path) {
+ return base::WriteFile(path, nullptr, 0) == 0;
+ }
-// Returns a duplicate of the file wrapped by |file_proxy|. Temporary workaround
-// because base::FileProxy exposes neither the underlying file nor a Duplicate()
-// method.
-base::File DuplicateHandle(base::FileProxy* file_proxy) {
- DCHECK(file_proxy);
- DCHECK(file_proxy->IsValid());
- base::File file = file_proxy->TakeFile();
- base::File duplicate = file.Duplicate();
- file_proxy->SetFile(std::move(file));
- return duplicate;
-}
+ static bool Remove(base::FilePath& path) {
+ return base::DeleteFile(path, false /* recursive */);
+ }
+};
} // namespace
-// RulesetVersion ------------------------------------------------------------
+// UnindexedRulesetInfo ------------------------------------------------------
+
+UnindexedRulesetInfo::UnindexedRulesetInfo() = default;
+UnindexedRulesetInfo::~UnindexedRulesetInfo() = default;
+
+// IndexedRulesetVersion ------------------------------------------------------
-RulesetVersion::RulesetVersion() = default;
-RulesetVersion::RulesetVersion(const std::string& content_version,
- int format_version)
+IndexedRulesetVersion::IndexedRulesetVersion() = default;
+IndexedRulesetVersion::IndexedRulesetVersion(const std::string& content_version,
+ int format_version)
: content_version(content_version), format_version(format_version) {}
-RulesetVersion::~RulesetVersion() = default;
-RulesetVersion& RulesetVersion::operator=(const RulesetVersion&) = default;
+IndexedRulesetVersion::~IndexedRulesetVersion() = default;
+IndexedRulesetVersion& IndexedRulesetVersion::operator=(
+ const IndexedRulesetVersion&) = default;
// static
-void RulesetVersion::RegisterPrefs(PrefRegistrySimple* registry) {
+void IndexedRulesetVersion::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(kSubresourceFilterRulesetContentVersion,
std::string());
registry->RegisterIntegerPref(kSubresourceFilterRulesetFormatVersion, 0);
}
// static
-int RulesetVersion::CurrentFormatVersion() {
- return kCurrentRulesetFormatVersion;
+int IndexedRulesetVersion::CurrentFormatVersion() {
+ return RulesetIndexer::kIndexedFormatVersion;
}
-void RulesetVersion::ReadFromPrefs(PrefService* local_state) {
+void IndexedRulesetVersion::ReadFromPrefs(PrefService* local_state) {
format_version =
local_state->GetInteger(kSubresourceFilterRulesetFormatVersion);
content_version =
local_state->GetString(kSubresourceFilterRulesetContentVersion);
}
-bool RulesetVersion::IsValid() const {
+bool IndexedRulesetVersion::IsValid() const {
return format_version != 0 && !content_version.empty();
}
-bool RulesetVersion::IsCurrentFormatVersion() const {
+bool IndexedRulesetVersion::IsCurrentFormatVersion() const {
return format_version == CurrentFormatVersion();
}
-void RulesetVersion::SaveToPrefs(PrefService* local_state) const {
- DCHECK(IsValid());
+void IndexedRulesetVersion::SaveToPrefs(PrefService* local_state) const {
local_state->SetInteger(kSubresourceFilterRulesetFormatVersion,
format_version);
local_state->SetString(kSubresourceFilterRulesetContentVersion,
content_version);
}
-std::string RulesetVersion::AsString() const {
- DCHECK(IsValid());
- return base::IntToString(format_version) + "_" + content_version;
+base::FilePath IndexedRulesetVersion::GetSubdirectoryPathForVersion(
+ const base::FilePath& base_dir) const {
+ return base_dir.AppendASCII(base::IntToString(format_version))
+ .AppendASCII(content_version);
}
// RulesetService ------------------------------------------------------------
+// static
+decltype(&RulesetService::IndexRuleset) RulesetService::g_index_ruleset_func =
+ &RulesetService::IndexRuleset;
+
+// static
+decltype(&base::ReplaceFile) RulesetService::g_replace_file_func =
+ &base::ReplaceFile;
+
RulesetService::RulesetService(
PrefService* local_state,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
- const base::FilePath& base_dir)
+ const base::FilePath& indexed_ruleset_base_dir)
: local_state_(local_state),
blocking_task_runner_(blocking_task_runner),
- base_dir_(base_dir) {
+ indexed_ruleset_base_dir_(indexed_ruleset_base_dir) {
DCHECK_NE(local_state_->GetInitializationStatus(),
PrefService::INITIALIZATION_STATUS_WAITING);
- RulesetVersion version_on_disk;
- version_on_disk.ReadFromPrefs(local_state_);
- if (version_on_disk.IsCurrentFormatVersion())
- OpenAndPublishRuleset(version_on_disk);
+ IndexedRulesetVersion most_recently_indexed_version;
+ most_recently_indexed_version.ReadFromPrefs(local_state_);
+ if (most_recently_indexed_version.IsValid() &&
+ most_recently_indexed_version.IsCurrentFormatVersion())
+ OpenAndPublishRuleset(most_recently_indexed_version);
}
RulesetService::~RulesetService() {}
-void RulesetService::StoreAndPublishUpdatedRuleset(
- std::vector<uint8_t> ruleset_data,
- const std::string& new_content_version) {
- // TODO(engedy): The |format_version| corresponds to the output of the
- // indexing step that will ultimately be performed here.
- RulesetVersion new_version(new_content_version,
- RulesetVersion::CurrentFormatVersion());
- base::PostTaskAndReplyWithResult(
- blocking_task_runner_.get(), FROM_HERE,
- base::Bind(&WriteRuleset, base_dir_, new_version,
- std::move(ruleset_data)),
- base::Bind(&RulesetService::OnWrittenRuleset, AsWeakPtr(), new_version));
+void RulesetService::IndexAndStoreAndPublishRulesetIfNeeded(
+ const UnindexedRulesetInfo& unindexed_ruleset_info) {
+ // Trying to store a ruleset with the same version for a second time would not
+ // only be futile, but would fail on Windows due to "File System Tunneling" as
+ // long as the previously stored copy of the rules is still in use.
+ IndexedRulesetVersion most_recently_indexed_version;
+ most_recently_indexed_version.ReadFromPrefs(local_state_);
+ if (most_recently_indexed_version.IsCurrentFormatVersion() &&
+ most_recently_indexed_version.content_version ==
+ unindexed_ruleset_info.content_version)
+ return;
+
+ IndexAndStoreRuleset(
+ unindexed_ruleset_info,
+ base::Bind(&RulesetService::OpenAndPublishRuleset, AsWeakPtr()));
}
void RulesetService::RegisterDistributor(
std::unique_ptr<RulesetDistributor> distributor) {
if (ruleset_data_ && ruleset_data_->IsValid())
- distributor->PublishNewVersion(DuplicateHandle(ruleset_data_.get()));
+ distributor->PublishNewVersion(ruleset_data_->DuplicateFile());
distributors_.push_back(std::move(distributor));
}
-void RulesetService::NotifyRulesetVersionAvailable(
- const std::string& rules,
- const base::Version& version) {}
+// static
+base::FilePath RulesetService::GetRulesetDataFilePath(
+ const base::FilePath& version_directory) {
+ return version_directory.Append(kRulesetDataFileName);
+}
+
+// static
+base::FilePath RulesetService::GetLicenseFilePath(
+ const base::FilePath& version_directory) {
+ return version_directory.Append(kLicenseFileName);
+}
+
+// static
+base::FilePath RulesetService::GetSentinelFilePath(
+ const base::FilePath& version_directory) {
+ return version_directory.Append(kSentinelFileName);
+}
// static
-bool RulesetService::WriteRuleset(const base::FilePath& base_dir,
- const RulesetVersion& version,
- std::vector<uint8_t> data) {
+IndexedRulesetVersion RulesetService::IndexAndWriteRuleset(
+ const base::FilePath& indexed_ruleset_base_dir,
+ const UnindexedRulesetInfo& unindexed_ruleset_info) {
base::ThreadRestrictions::AssertIOAllowed();
+
+ base::File unindexed_ruleset_file(
+ unindexed_ruleset_info.ruleset_path,
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+ if (!unindexed_ruleset_file.IsValid()) {
+ RecordIndexAndWriteRulesetResult(
+ IndexAndWriteRulesetResult::FAILED_OPENING_UNINDEXED_RULESET);
+ return IndexedRulesetVersion();
+ }
+
+ IndexedRulesetVersion indexed_version(
+ unindexed_ruleset_info.content_version,
+ IndexedRulesetVersion::CurrentFormatVersion());
+ base::FilePath indexed_ruleset_version_dir =
+ indexed_version.GetSubdirectoryPathForVersion(indexed_ruleset_base_dir);
+
+ if (!base::CreateDirectory(indexed_ruleset_version_dir)) {
+ RecordIndexAndWriteRulesetResult(
+ IndexAndWriteRulesetResult::FAILED_CREATING_VERSION_DIR);
+ return IndexedRulesetVersion();
+ }
+
+ base::FilePath sentinel_path(
+ GetSentinelFilePath(indexed_ruleset_version_dir));
+ if (SentinelFile::IsPresent(sentinel_path)) {
+ RecordIndexAndWriteRulesetResult(
+ IndexAndWriteRulesetResult::ABORTED_BECAUSE_SENTINEL_FILE_PRESENT);
+ return IndexedRulesetVersion();
+ }
+
+ if (!SentinelFile::Create(sentinel_path)) {
+ RecordIndexAndWriteRulesetResult(
+ IndexAndWriteRulesetResult::FAILED_CREATING_SENTINEL_FILE);
+ return IndexedRulesetVersion();
+ }
+
+ // --- Begin of guarded section.
+ //
+ // Crashes or errors occurring here will leave behind a sentinel file that
+ // will prevent this version of the ruleset from ever being indexed again.
+
+ RulesetIndexer indexer;
+ if (!(*g_index_ruleset_func)(std::move(unindexed_ruleset_file), &indexer)) {
+ RecordIndexAndWriteRulesetResult(
+ IndexAndWriteRulesetResult::FAILED_PARSING_UNINDEXED_RULESET);
+ return IndexedRulesetVersion();
+ }
+
+ // --- End of guarded section.
+
+ if (!SentinelFile::Remove(sentinel_path)) {
+ RecordIndexAndWriteRulesetResult(
+ IndexAndWriteRulesetResult::FAILED_DELETING_SENTINEL_FILE);
+ return IndexedRulesetVersion();
+ }
+
+ IndexAndWriteRulesetResult result = WriteRuleset(
+ indexed_ruleset_version_dir, unindexed_ruleset_info.license_path,
+ indexer.data(), indexer.size());
+ RecordIndexAndWriteRulesetResult(result);
+ if (result != IndexAndWriteRulesetResult::SUCCESS)
+ return IndexedRulesetVersion();
+
+ DCHECK(indexed_version.IsValid());
+ return indexed_version;
+}
+
+// static
+bool RulesetService::IndexRuleset(base::File unindexed_ruleset_file,
+ RulesetIndexer* indexer) {
+ SCOPED_UMA_HISTOGRAM_TIMER("SubresourceFilter.IndexRuleset.WallDuration");
+
+ int64_t unindexed_ruleset_size = unindexed_ruleset_file.GetLength();
+ CopyingFileInputStream copying_stream(std::move(unindexed_ruleset_file));
+ google::protobuf::io::CopyingInputStreamAdaptor zero_copy_stream_adaptor(
+ &copying_stream, 4096 /* buffer_size */);
+ UnindexedRulesetReader reader(&zero_copy_stream_adaptor);
+
+ size_t num_unsupported_rules = 0;
+ proto::FilteringRules ruleset_chunk;
+ while (reader.ReadNextChunk(&ruleset_chunk)) {
+ for (const proto::UrlRule& rule : ruleset_chunk.url_rules()) {
+ if (!indexer->AddUrlRule(rule))
+ ++num_unsupported_rules;
+ }
+ }
+ indexer->Finish();
+
+ UMA_HISTOGRAM_COUNTS_10000(
+ "SubresourceFilter.IndexRuleset.NumUnsupportedRules",
+ num_unsupported_rules);
+
+ return reader.num_bytes_read() == unindexed_ruleset_size;
+}
+
+// static
+RulesetService::IndexAndWriteRulesetResult RulesetService::WriteRuleset(
+ const base::FilePath& indexed_ruleset_version_dir,
+ const base::FilePath& license_source_path,
+ const uint8_t* indexed_ruleset_data,
+ size_t indexed_ruleset_size) {
base::ScopedTempDir scratch_dir;
- if (!scratch_dir.CreateUniqueTempDirUnderPath(base_dir))
- return false;
+ if (!scratch_dir.CreateUniqueTempDirUnderPath(
+ indexed_ruleset_version_dir.DirName())) {
+ return IndexAndWriteRulesetResult::FAILED_CREATING_SCRATCH_DIR;
+ }
static_assert(sizeof(uint8_t) == sizeof(char), "Expected char = byte.");
- const int data_size_in_chars = base::checked_cast<int>(data.size());
- if (base::WriteFile(GetRulesetDataFilePath(scratch_dir.path()),
- reinterpret_cast<const char*>(data.data()),
+ const int data_size_in_chars = base::checked_cast<int>(indexed_ruleset_size);
+ if (base::WriteFile(GetRulesetDataFilePath(scratch_dir.GetPath()),
+ reinterpret_cast<const char*>(indexed_ruleset_data),
data_size_in_chars) != data_size_in_chars) {
- return false;
+ return IndexAndWriteRulesetResult::FAILED_WRITING_RULESET_DATA;
+ }
+
+ if (base::PathExists(license_source_path) &&
+ !base::CopyFile(license_source_path,
+ GetLicenseFilePath(scratch_dir.GetPath()))) {
+ return IndexAndWriteRulesetResult::FAILED_WRITING_LICENSE;
+ }
+
+ // Creating a temporary directory also makes sure the path (except for the
+ // final segment) gets created. ReplaceFile would not create the path.
+ DCHECK(base::PathExists(indexed_ruleset_version_dir.DirName()));
+
+ // Need to manually delete the previously stored ruleset with the same
+ // version, if any, as ReplaceFile would not overwrite a non-empty directory.
+ // Due to the same-version check in IndexAndStoreAndPublishRulesetIfNeeded, we
+ // would not normally find a pre-existing copy at this point unless the
+ // previous write was interrupted.
+ if (!base::DeleteFile(indexed_ruleset_version_dir, true)) {
+ return IndexAndWriteRulesetResult::FAILED_DELETE_PREEXISTING;
}
- DCHECK(base::PathExists(base_dir));
- if (base::ReplaceFile(scratch_dir.path(),
- GetSubdirectoryPathForVersion(base_dir, version),
- nullptr)) {
- scratch_dir.Take();
- return true;
+ base::File::Error error;
+ if (!(*g_replace_file_func)(scratch_dir.GetPath(),
+ indexed_ruleset_version_dir, &error)) {
+ // While enumerators of base::File::Error all have negative values, the
+ // histogram records the absolute values.
+ UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.WriteRuleset.ReplaceFileError",
+ -error, -base::File::FILE_ERROR_MAX);
+ return IndexAndWriteRulesetResult::FAILED_REPLACE_FILE;
}
- return false;
+ scratch_dir.Take();
+ return IndexAndWriteRulesetResult::SUCCESS;
}
-void RulesetService::OnWrittenRuleset(const RulesetVersion& version,
- bool success) {
- if (!success)
+void RulesetService::IndexAndStoreRuleset(
+ const UnindexedRulesetInfo& unindexed_ruleset_info,
+ const WriteRulesetCallback& success_callback) {
+ if (unindexed_ruleset_info.content_version.empty())
return;
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_.get(), FROM_HERE,
+ base::Bind(&RulesetService::IndexAndWriteRuleset,
+ indexed_ruleset_base_dir_, unindexed_ruleset_info),
+ base::Bind(&RulesetService::OnWrittenRuleset, AsWeakPtr(),
+ success_callback));
+}
+void RulesetService::OnWrittenRuleset(
+ const WriteRulesetCallback& result_callback,
+ const IndexedRulesetVersion& version) {
+ DCHECK(!result_callback.is_null());
+ if (!version.IsValid())
+ return;
version.SaveToPrefs(local_state_);
- OpenAndPublishRuleset(version);
+ result_callback.Run(version);
}
-void RulesetService::OpenAndPublishRuleset(const RulesetVersion& version) {
+void RulesetService::OpenAndPublishRuleset(
+ const IndexedRulesetVersion& version) {
ruleset_data_.reset(new base::FileProxy(blocking_task_runner_.get()));
// On Windows, open the file with FLAG_SHARE_DELETE to allow deletion while
// there are handles to it still open. Note that creating a new file at the
- // same path would still be impossible until after the last of those handles
- // is closed.
+ // same path would still be impossible until after the last handle is closed.
ruleset_data_->CreateOrOpen(
- GetRulesetDataFilePath(GetSubdirectoryPathForVersion(base_dir_, version)),
+ GetRulesetDataFilePath(
+ version.GetSubdirectoryPathForVersion(indexed_ruleset_base_dir_)),
base::File::FLAG_OPEN | base::File::FLAG_READ |
base::File::FLAG_SHARE_DELETE,
base::Bind(&RulesetService::OnOpenedRuleset, AsWeakPtr()));
}
void RulesetService::OnOpenedRuleset(base::File::Error error) {
- // This should not happen unless |base_dir| has been tampered with.
- if (!ruleset_data_ || !ruleset_data_->IsValid())
+ // The file has just been successfully written, so a failure here is unlikely
+ // unless |indexed_ruleset_base_dir_| has been tampered with or there are disk
+ // errors. Still, restore the invariant that a valid version in preferences
+ // always points to an existing version of disk by invalidating the prefs.
+ if (error != base::File::FILE_OK) {
+ IndexedRulesetVersion().SaveToPrefs(local_state_);
return;
+ }
+
+ // A second call to OpenAndPublishRuleset() may have reset |ruleset_data_| to
+ // a new instance that is in the process of calling CreateOrOpen() on a newer
+ // version. Bail out.
+ DCHECK(ruleset_data_);
+ if (!ruleset_data_->IsValid())
+ return;
+
DCHECK_EQ(error, base::File::Error::FILE_OK);
for (auto& distributor : distributors_)
- distributor->PublishNewVersion(DuplicateHandle(ruleset_data_.get()));
+ distributor->PublishNewVersion(ruleset_data_->DuplicateFile());
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/browser/ruleset_service.h b/chromium/components/subresource_filter/core/browser/ruleset_service.h
index 33ddbfab713..d01579a6846 100644
--- a/chromium/components/subresource_filter/core/browser/ruleset_service.h
+++ b/chromium/components/subresource_filter/core/browser/ruleset_service.h
@@ -11,8 +11,11 @@
#include <string>
#include <vector>
+#include "base/callback_forward.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
@@ -28,15 +31,45 @@ class SequencedTaskRunner;
namespace subresource_filter {
+class RulesetIndexer;
class RulesetDistributor;
-// Encapsulates the combination of the binary format version of the ruleset, and
-// the version of the ruleset's contents.
-struct RulesetVersion {
- RulesetVersion();
- RulesetVersion(const std::string& content_version, int format_version);
- ~RulesetVersion();
- RulesetVersion& operator=(const RulesetVersion&);
+// Encapsulates information about a version of unindexed subresource
+// filtering rules on disk.
+struct UnindexedRulesetInfo {
+ UnindexedRulesetInfo();
+ ~UnindexedRulesetInfo();
+
+ // The version of the ruleset contents. Because the wire format of unindexed
+ // rules is expected to be stable over time (at least backwards compatible),
+ // the unindexed ruleset is uniquely identified by its content version.
+ //
+ // The version string must not be empty, but can be any string otherwise.
+ // There is no ordering defined on versions.
+ std::string content_version;
+
+ // The path to the file containing the unindexed subresource filtering rules.
+ base::FilePath ruleset_path;
+
+ // The (optional) path to a file containing the applicable license, which will
+ // be copied next to the indexed ruleset. For convenience, the lack of license
+ // can be indicated not only by setting |license_path| to empty, but also by
+ // setting it to any non existent path.
+ base::FilePath license_path;
+};
+
+// Encapsulates the combination of the binary format version of the indexed
+// ruleset, and the version of the ruleset contents.
+//
+// In contrast to the unindexed ruleset, the binary format of the index data
+// structures is expected to evolve over time, so the indexed ruleset is
+// identified by a pair of versions: the content version of the rules that have
+// been indexed; and the binary format version of the indexed data structures.
+struct IndexedRulesetVersion {
+ IndexedRulesetVersion();
+ IndexedRulesetVersion(const std::string& content_version, int format_version);
+ ~IndexedRulesetVersion();
+ IndexedRulesetVersion& operator=(const IndexedRulesetVersion&);
static void RegisterPrefs(PrefRegistrySimple* registry);
@@ -47,45 +80,67 @@ struct RulesetVersion {
void SaveToPrefs(PrefService* local_state) const;
void ReadFromPrefs(PrefService* local_state);
- std::string AsString() const;
+ base::FilePath GetSubdirectoryPathForVersion(
+ const base::FilePath& base_dir) const;
std::string content_version;
int format_version = 0;
};
-// Responsible for versioned storage of subresource filtering rules, and for
-// supplying the most up-to-date version to the registered RulesetDistributors
-// for distribution.
+// Responsible for indexing subresource filtering rules that are downloaded
+// through the component updater; for versioned storage of the indexed ruleset;
+// and for supplying the most up-to-date version of the indexed ruleset to the
+// RulesetDistributors for distribution.
//
-// Files corresponding to each version of the ruleset are stored in a separate
-// subdirectory inside |ruleset_base_dir| named after the version. The version
-// information of the most recent successfully stored ruleset is written into
-// |local_state|. The invariant is maintained that the version pointed to by
-// preferences will exist on disk at any point in time. All file operations are
-// posted to |blocking_task_runner|.
+// Files corresponding to each version of the indexed ruleset are stored in a
+// separate subdirectory inside |indexed_ruleset_base_dir| named after the
+// version. The version information of the most recent successfully stored
+// ruleset is written into |local_state|. The invariant is maintained that the
+// version pointed to by preferences, if valid, will exist on disk at any point
+// in time. All file operations are posted to |blocking_task_runner|.
class RulesetService : public base::SupportsWeakPtr<RulesetService> {
public:
+ // Enumerates the possible outcomes of indexing a ruleset and writing it to
+ // disk. Used in UMA histograms, so the order of enumerators should not be
+ // changed.
+ enum class IndexAndWriteRulesetResult {
+ SUCCESS,
+ FAILED_CREATING_SCRATCH_DIR,
+ FAILED_WRITING_RULESET_DATA,
+ FAILED_WRITING_LICENSE,
+ FAILED_REPLACE_FILE,
+ FAILED_DELETE_PREEXISTING,
+ FAILED_OPENING_UNINDEXED_RULESET,
+ FAILED_PARSING_UNINDEXED_RULESET,
+ FAILED_CREATING_VERSION_DIR,
+ FAILED_CREATING_SENTINEL_FILE,
+ FAILED_DELETING_SENTINEL_FILE,
+ ABORTED_BECAUSE_SENTINEL_FILE_PRESENT,
+
+ // Insert new values before this line.
+ MAX,
+ };
+
+ // Creates a new instance that will immediately publish the most recently
+ // indexed version of the ruleset if one is available according to prefs.
+ // See class comments for details of arguments.
RulesetService(PrefService* local_state,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
- const base::FilePath& base_dir);
+ const base::FilePath& indexed_ruleset_base_dir);
virtual ~RulesetService();
- // Notifies that new data has arrived from the component updater.
- virtual void NotifyRulesetVersionAvailable(const std::string& rules,
- const base::Version& version);
-
- // Persists a new |content_version| of the |ruleset_data|, then, on success,
- // publishes it through the registered distributors. The |ruleset_data| must
- // be a function of the |content_version| in the mathematical sense, i.e.
- // different |ruleset_data| contents should have different |content_versions|.
+ // Indexes, stores, and publishes the given unindexed ruleset, unless its
+ // |content_version| matches that of the most recently indexed version, in
+ // which case it does nothing. The files comprising the unindexed ruleset
+ // need to remain accessible even after the method returns.
//
- // Trying to store a ruleset with the same version for a second time will
- // silenty fail on Windows if the previously stored copy of the rules is
- // still in use. This, however, means that the new rules must have been
- // successfully stored on the first try, otherwise they would not have been
- // published. Therefore, the operation would have been idempotent anyway.
- void StoreAndPublishUpdatedRuleset(std::vector<uint8_t> ruleset_data,
- const std::string& content_version);
+ // Computation-heavy steps and I/O are performed on a background thread.
+ // Still, to prevent start-up congestion, this method should be called at the
+ // earliest shortly after start-up.
+ //
+ // Virtual so that it can be mocked out in tests.
+ virtual void IndexAndStoreAndPublishRulesetIfNeeded(
+ const UnindexedRulesetInfo& unindexed_ruleset_info);
// Registers a |distributor| that will be notified each time a new version of
// the ruleset becomes avalable. The |distributor| will be destroyed along
@@ -94,27 +149,72 @@ class RulesetService : public base::SupportsWeakPtr<RulesetService> {
private:
friend class SubresourceFilteringRulesetServiceTest;
-
- // Writes a new |version| of the ruleset |data| into the correspondingly named
- // subdirectory under |base_dir|, and returns true on success.
+ FRIEND_TEST_ALL_PREFIXES(SubresourceFilteringRulesetServiceTest,
+ NewRuleset_WriteFailure);
+ FRIEND_TEST_ALL_PREFIXES(SubresourceFilteringRulesetServiceDeathTest,
+ NewRuleset_IndexingCrash);
+
+ using WriteRulesetCallback =
+ base::Callback<void(const IndexedRulesetVersion&)>;
+
+ static base::FilePath GetRulesetDataFilePath(
+ const base::FilePath& version_directory);
+ static base::FilePath GetLicenseFilePath(
+ const base::FilePath& version_directory);
+ static base::FilePath GetSentinelFilePath(
+ const base::FilePath& version_directory);
+
+ // Reads the ruleset described in |unindexed_ruleset_info|, indexes it, and
+ // calls WriteRuleset() to persist the indexed ruleset. Returns the resulting
+ // indexed ruleset version, or an invalid version on error. To be called on
+ // the |blocking_task_runner_|.
+ static IndexedRulesetVersion IndexAndWriteRuleset(
+ const base::FilePath& indexed_ruleset_base_dir,
+ const UnindexedRulesetInfo& unindexed_ruleset_info);
+
+ // Reads the rules from the |unindexed_ruleset_file|, and indexes them using
+ // |indexer|. Returns whether the entire ruleset could be parsed.
+ static bool IndexRuleset(base::File unindexed_ruleset_file,
+ RulesetIndexer* indexer);
+
+ // Writes all files comprising the given |indexed_version| of the ruleset
+ // into the corresponding subdirectory in |indexed_ruleset_base_dir|.
+ // More specifically, it writes:
+ // -- the |indexed_ruleset_data| of the given |indexed_ruleset_size|,
+ // -- a copy of the LICENSE file at |license_path|, if exists.
+ // Returns true on success. To be called on the |blocking_task_runner_|.
+ // Attempts not to leave an incomplete copy in the target directory.
//
- // It will attempt to overwrite the previously stored ruleset with the same
- // version, if any. Doing so is needed in case the earlier write was
- // interrupted, but will silently fail on Windows in case the earlier write
- // was successful and the ruleset is in use. See the comment above regarding
- // why this is not an issue in practice.
- static bool WriteRuleset(const base::FilePath& base_dir,
- const RulesetVersion& version,
- std::vector<uint8_t> data);
-
- void OnWrittenRuleset(const RulesetVersion& version, bool success);
- void OpenAndPublishRuleset(const RulesetVersion& version);
+ // Writing is factored out into this separate function so it can be
+ // independently exercised in tests.
+ static IndexAndWriteRulesetResult WriteRuleset(
+ const base::FilePath& indexed_ruleset_version_dir,
+ const base::FilePath& license_source_path,
+ const uint8_t* indexed_ruleset_data,
+ size_t indexed_ruleset_size);
+
+ // Indirections for accessing these routines, so as to allow overriding and
+ // injecting faults in tests.
+ static decltype(&IndexRuleset) g_index_ruleset_func;
+ static decltype(&base::ReplaceFile) g_replace_file_func;
+
+ // Posts a task to the |blocking_task_runner_| to index and persist the given
+ // unindexed ruleset. Then, on success, updates the most recently indexed
+ // version in preferences and invokes |success_callback| on the calling
+ // thread. There is no callback on failure.
+ void IndexAndStoreRuleset(const UnindexedRulesetInfo& unindexed_ruleset_info,
+ const WriteRulesetCallback& success_callback);
+
+ void OnWrittenRuleset(const WriteRulesetCallback& result_callback,
+ const IndexedRulesetVersion& version);
+
+ void OpenAndPublishRuleset(const IndexedRulesetVersion& version);
void OnOpenedRuleset(base::File::Error error);
PrefService* const local_state_;
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
- const base::FilePath base_dir_;
+ const base::FilePath indexed_ruleset_base_dir_;
std::unique_ptr<base::FileProxy> ruleset_data_;
std::vector<std::unique_ptr<RulesetDistributor>> distributors_;
diff --git a/chromium/components/subresource_filter/core/browser/ruleset_service_unittest.cc b/chromium/components/subresource_filter/core/browser/ruleset_service_unittest.cc
index 2165d7b1194..bdc571f88a1 100644
--- a/chromium/components/subresource_filter/core/browser/ruleset_service_unittest.cc
+++ b/chromium/components/subresource_filter/core/browser/ruleset_service_unittest.cc
@@ -7,22 +7,27 @@
#include <stddef.h>
#include <stdint.h>
-#include <iterator>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
+#include "base/environment.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/histogram_tester.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
#include "components/prefs/testing_pref_service.h"
#include "components/subresource_filter/core/browser/ruleset_distributor.h"
+#include "components/subresource_filter/core/common/test_ruleset_creator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,11 +35,51 @@ namespace subresource_filter {
namespace {
+// Testing constants ----------------------------------------------------------
+
const char kTestContentVersion1[] = "1.2.3.4";
const char kTestContentVersion2[] = "1.2.3.5";
-const uint8_t kDummyRuleset1[] = {11, 0, 12, 13, 14};
-const uint8_t kDummyRuleset2[] = {21, 0, 22, 23};
+const char kTestDisallowedSuffix1[] = "foo";
+const char kTestDisallowedSuffix2[] = "bar";
+const char kTestLicenseContents[] = "Lorem ipsum";
+
+// Helpers --------------------------------------------------------------------
+
+template <typename Fun>
+class ScopedFunctionOverride {
+ public:
+ ScopedFunctionOverride(Fun* target, Fun replacement)
+ : target_(target), replacement_(replacement) {
+ std::swap(*target_, replacement_);
+ }
+
+ ~ScopedFunctionOverride() { std::swap(*target_, replacement_); }
+
+ private:
+ Fun* target_;
+ Fun replacement_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedFunctionOverride);
+};
+
+template <typename Fun>
+std::unique_ptr<ScopedFunctionOverride<Fun>> OverrideFunctionForScope(
+ Fun* target,
+ Fun replacement) {
+ return base::MakeUnique<ScopedFunctionOverride<Fun>>(target, replacement);
+}
+
+std::vector<uint8_t> ReadFileContents(base::File* file) {
+ size_t length = base::checked_cast<size_t>(file->GetLength());
+ std::vector<uint8_t> contents(length);
+ static_assert(sizeof(uint8_t) == sizeof(char), "Expected char = byte.");
+ file->Read(0, reinterpret_cast<char*>(contents.data()),
+ base::checked_cast<int>(length));
+ return contents;
+}
+
+// Mocks ----------------------------------------------------------------------
class MockRulesetDistributor : public RulesetDistributor {
public:
@@ -53,22 +98,31 @@ class MockRulesetDistributor : public RulesetDistributor {
DISALLOW_COPY_AND_ASSIGN(MockRulesetDistributor);
};
-std::vector<uint8_t> ReadFileContents(base::File* file) {
- size_t length = base::checked_cast<size_t>(file->GetLength());
- std::vector<uint8_t> contents(length);
- static_assert(sizeof(uint8_t) == sizeof(char), "Expected char = byte.");
- file->Read(0, reinterpret_cast<char*>(contents.data()),
- base::checked_cast<int>(length));
- return contents;
+bool MockFailingReplaceFile(const base::FilePath&,
+ const base::FilePath&,
+ base::File::Error* error) {
+ *error = base::File::FILE_ERROR_NOT_FOUND;
+ return false;
}
-template <typename T, int N>
-std::vector<T> AsVector(const T (&array)[N]) {
- return std::vector<T>(std::begin(array), std::end(array));
+#if GTEST_HAS_DEATH_TEST
+bool MockCrashingIndexRuleset(base::File, RulesetIndexer*) {
+ LOG(FATAL) << "Synthetic crash.";
+ return false;
+}
+#else
+bool MockFailingIndexRuleset(base::File, RulesetIndexer*) {
+ return false;
}
+#endif
} // namespace
+// Test fixtures --------------------------------------------------------------
+
+using testing::TestRulesetPair;
+using testing::TestRulesetCreator;
+
class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
public:
SubresourceFilteringRulesetServiceTest()
@@ -78,16 +132,27 @@ class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
protected:
void SetUp() override {
- RulesetVersion::RegisterPrefs(pref_service_.registry());
+ IndexedRulesetVersion::RegisterPrefs(pref_service_.registry());
- ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
+ SetUpTempDir();
ResetService(CreateRulesetService());
RunUntilIdle();
+
+ ASSERT_NO_FATAL_FAILURE(
+ ruleset_creator_.CreateRulesetToDisallowURLsWithPathSuffix(
+ kTestDisallowedSuffix1, &test_ruleset_1_));
+ ASSERT_NO_FATAL_FAILURE(
+ ruleset_creator_.CreateRulesetToDisallowURLsWithPathSuffix(
+ kTestDisallowedSuffix2, &test_ruleset_2_));
+ }
+
+ virtual void SetUpTempDir() {
+ ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
}
std::unique_ptr<RulesetService> CreateRulesetService() {
- return base::WrapUnique(
- new RulesetService(&pref_service_, task_runner_, base_dir()));
+ return base::MakeUnique<RulesetService>(&pref_service_, task_runner_,
+ base_dir());
}
void ResetService(std::unique_ptr<RulesetService> new_service = nullptr) {
@@ -100,14 +165,54 @@ class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
}
}
- void StoreAndPublishUpdatedRuleset(const std::vector<uint8_t>& ruleset_data,
- const std::string& new_content_version) {
- service()->StoreAndPublishUpdatedRuleset(ruleset_data, new_content_version);
+ // Creates a new file with the given license |contents| at a unique temporary
+ // path, which is returned in |path|.
+ void CreateTestLicenseFile(const std::string& contents,
+ base::FilePath* path) {
+ ASSERT_NO_FATAL_FAILURE(
+ test_ruleset_creator()->GetUniqueTemporaryPath(path));
+ ASSERT_EQ(static_cast<int>(contents.size()),
+ base::WriteFile(*path, contents.data(),
+ static_cast<int>(contents.size())));
+ }
+
+ void IndexAndStoreAndPublishUpdatedRuleset(
+ const TestRulesetPair& test_ruleset_pair,
+ const std::string& new_content_version,
+ const base::FilePath& license_path = base::FilePath()) {
+ UnindexedRulesetInfo ruleset_info;
+ ruleset_info.ruleset_path = test_ruleset_pair.unindexed.path;
+ ruleset_info.license_path = license_path;
+ ruleset_info.content_version = new_content_version;
+ service()->IndexAndStoreAndPublishRulesetIfNeeded(ruleset_info);
}
- void WritePreexistingRuleset(const RulesetVersion& version,
- const std::vector<uint8_t>& data) {
- RulesetService::WriteRuleset(base_dir(), version, data);
+ bool WriteRuleset(const TestRulesetPair& test_ruleset_pair,
+ const IndexedRulesetVersion& indexed_version,
+ const base::FilePath& license_path = base::FilePath()) {
+ return RulesetService::WriteRuleset(
+ indexed_version.GetSubdirectoryPathForVersion(base_dir()),
+ license_path, test_ruleset_pair.indexed.contents.data(),
+ test_ruleset_pair.indexed.contents.size()) ==
+ RulesetService::IndexAndWriteRulesetResult::SUCCESS;
+ }
+
+ base::FilePath GetExpectedRulesetDataFilePath(
+ const IndexedRulesetVersion& version) const {
+ return RulesetService::GetRulesetDataFilePath(
+ version.GetSubdirectoryPathForVersion(base_dir()));
+ }
+
+ base::FilePath GetExpectedLicenseFilePath(
+ const IndexedRulesetVersion& version) const {
+ return RulesetService::GetLicenseFilePath(
+ version.GetSubdirectoryPathForVersion(base_dir()));
+ }
+
+ base::FilePath GetExpectedSentinelFilePath(
+ const IndexedRulesetVersion& version) const {
+ return RulesetService::GetSentinelFilePath(
+ version.GetSubdirectoryPathForVersion(base_dir()));
}
void RunUntilIdle() { task_runner_->RunUntilIdle(); }
@@ -130,11 +235,21 @@ class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
ASSERT_EQ(-1, file->Write(0, kTest, sizeof(kTest)));
}
+ void AssertNoPendingTasks() { ASSERT_FALSE(task_runner_->HasPendingTask()); }
+
PrefService* prefs() { return &pref_service_; }
RulesetService* service() { return service_.get(); }
MockRulesetDistributor* mock_distributor() { return mock_distributor_; }
+
+ virtual base::FilePath effective_temp_dir() const {
+ return scoped_temp_dir_.GetPath();
+ }
+
+ TestRulesetCreator* test_ruleset_creator() { return &ruleset_creator_; }
+ const TestRulesetPair& test_ruleset_1() const { return test_ruleset_1_; }
+ const TestRulesetPair& test_ruleset_2() const { return test_ruleset_2_; }
base::FilePath base_dir() const {
- return scoped_temp_dir_.path().AppendASCII("Ruleset Base Dir");
+ return effective_temp_dir().AppendASCII("Rules").AppendASCII("Indexed");
}
private:
@@ -142,6 +257,10 @@ class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
base::ThreadTaskRunnerHandle task_runner_handle_;
TestingPrefServiceSimple pref_service_;
+ TestRulesetCreator ruleset_creator_;
+ TestRulesetPair test_ruleset_1_;
+ TestRulesetPair test_ruleset_2_;
+
base::ScopedTempDir scoped_temp_dir_;
std::unique_ptr<RulesetService> service_;
MockRulesetDistributor* mock_distributor_; // Weak, owned by |service_|.
@@ -149,6 +268,129 @@ class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
DISALLOW_COPY_AND_ASSIGN(SubresourceFilteringRulesetServiceTest);
};
+// Specialized test fixture for death tests. It exposes the temporary directory
+// used by the parent process as an environment variable that is consumed by the
+// child process, so that both processes use the same temporary directory. This
+// would not otherwise be the case on Windows, where children are not `forked`
+// and therefore would create their own unique temp directory.
+class SubresourceFilteringRulesetServiceDeathTest
+ : public SubresourceFilteringRulesetServiceTest {
+ public:
+ SubresourceFilteringRulesetServiceDeathTest()
+ : environment_(base::Environment::Create()) {}
+
+ protected:
+ void SetUpTempDir() override {
+ if (environment_->HasVar(kInheritedTempDirKey)) {
+ std::string value;
+ ASSERT_TRUE(environment_->GetVar(kInheritedTempDirKey, &value));
+ inherited_temp_dir_ = base::FilePath::FromUTF8Unsafe(value);
+ } else {
+ SubresourceFilteringRulesetServiceTest::SetUpTempDir();
+ environment_->SetVar(kInheritedTempDirKey,
+ effective_temp_dir().AsUTF8Unsafe());
+ }
+ }
+
+ void TearDown() override {
+ SubresourceFilteringRulesetServiceTest::TearDown();
+ if (inherited_temp_dir_.empty())
+ environment_->UnSetVar(kInheritedTempDirKey);
+ }
+
+ base::FilePath effective_temp_dir() const override {
+ if (!inherited_temp_dir_.empty())
+ return inherited_temp_dir_;
+ return SubresourceFilteringRulesetServiceTest::effective_temp_dir();
+ }
+
+ private:
+ static const char kInheritedTempDirKey[];
+
+ std::unique_ptr<base::Environment> environment_;
+ base::FilePath inherited_temp_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilteringRulesetServiceDeathTest);
+};
+
+// static
+const char SubresourceFilteringRulesetServiceDeathTest::kInheritedTempDirKey[] =
+ "SUBRESOURCE_FILTERING_RULESET_SERVICE_DEATH_TEST_TEMP_DIR";
+
+// Tests ---------------------------------------------------------------------
+
+TEST_F(SubresourceFilteringRulesetServiceTest, PathsAreSane) {
+ IndexedRulesetVersion indexed_version(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
+
+ base::FilePath ruleset_data_path =
+ GetExpectedRulesetDataFilePath(indexed_version);
+ base::FilePath license_path = GetExpectedLicenseFilePath(indexed_version);
+ base::FilePath sentinel_path = GetExpectedSentinelFilePath(indexed_version);
+
+ base::FilePath version_dir = ruleset_data_path.DirName();
+ EXPECT_NE(ruleset_data_path, license_path);
+ EXPECT_NE(ruleset_data_path, sentinel_path);
+ EXPECT_EQ(version_dir, license_path.DirName());
+ EXPECT_EQ(version_dir, sentinel_path.DirName());
+
+ EXPECT_TRUE(base_dir().IsParent(version_dir));
+ EXPECT_PRED_FORMAT2(::testing::IsSubstring,
+ base::IntToString(indexed_version.format_version),
+ version_dir.MaybeAsASCII());
+ EXPECT_PRED_FORMAT2(::testing::IsSubstring, indexed_version.content_version,
+ version_dir.MaybeAsASCII());
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest, WriteRuleset) {
+ base::FilePath original_license_path;
+ ASSERT_NO_FATAL_FAILURE(
+ CreateTestLicenseFile(kTestLicenseContents, &original_license_path));
+ IndexedRulesetVersion indexed_version(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
+
+ ASSERT_TRUE(
+ WriteRuleset(test_ruleset_1(), indexed_version, original_license_path));
+
+ base::File indexed_ruleset_data;
+ indexed_ruleset_data.Initialize(
+ GetExpectedRulesetDataFilePath(indexed_version),
+ base::File::FLAG_READ | base::File::FLAG_OPEN);
+ ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+ &indexed_ruleset_data, test_ruleset_1().indexed.contents));
+ std::string actual_license_contents;
+ ASSERT_TRUE(base::ReadFileToString(
+ GetExpectedLicenseFilePath(indexed_version), &actual_license_contents));
+ EXPECT_EQ(kTestLicenseContents, actual_license_contents);
+}
+
+// If the unindexed ruleset is not accompanied by a LICENSE file, there should
+// be no such file created next to the indexed ruleset. The lack of license can
+// be indicated by |license_path| being either an empty or non-existent path.
+TEST_F(SubresourceFilteringRulesetServiceTest,
+ WriteRuleset_NonExistentLicensePath) {
+ base::FilePath nonexistent_license_path;
+ ASSERT_NO_FATAL_FAILURE(test_ruleset_creator()->GetUniqueTemporaryPath(
+ &nonexistent_license_path));
+ IndexedRulesetVersion indexed_version(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
+ ASSERT_TRUE(WriteRuleset(test_ruleset_1(), indexed_version,
+ nonexistent_license_path));
+ EXPECT_TRUE(
+ base::PathExists(GetExpectedRulesetDataFilePath(indexed_version)));
+ EXPECT_FALSE(base::PathExists(GetExpectedLicenseFilePath(indexed_version)));
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest, WriteRuleset_EmptyLicensePath) {
+ IndexedRulesetVersion indexed_version(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
+ ASSERT_TRUE(
+ WriteRuleset(test_ruleset_1(), indexed_version, base::FilePath()));
+ EXPECT_TRUE(
+ base::PathExists(GetExpectedRulesetDataFilePath(indexed_version)));
+ EXPECT_FALSE(base::PathExists(GetExpectedLicenseFilePath(indexed_version)));
+}
+
TEST_F(SubresourceFilteringRulesetServiceTest, Startup_NoRulesetNotPublished) {
EXPECT_EQ(0u, mock_distributor()->published_rulesets().size());
}
@@ -158,9 +400,9 @@ TEST_F(SubresourceFilteringRulesetServiceTest, Startup_NoRulesetNotPublished) {
// but ensure some sane behavior just in case.
TEST_F(SubresourceFilteringRulesetServiceTest,
Startup_MissingRulesetNotPublished) {
- RulesetVersion current_version(kTestContentVersion1,
- RulesetVersion::CurrentFormatVersion());
- // `Forget` to write ruleset data.
+ IndexedRulesetVersion current_version(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
+ // "Forget" to write ruleset data.
current_version.SaveToPrefs(prefs());
ResetService(CreateRulesetService());
@@ -170,11 +412,12 @@ TEST_F(SubresourceFilteringRulesetServiceTest,
TEST_F(SubresourceFilteringRulesetServiceTest,
Startup_LegacyFormatRulesetNotPublished) {
- int legacy_format_version = RulesetVersion::CurrentFormatVersion() - 1;
- RulesetVersion legacy_version(kTestContentVersion1, legacy_format_version);
+ int legacy_format_version = IndexedRulesetVersion::CurrentFormatVersion() - 1;
+ IndexedRulesetVersion legacy_version(kTestContentVersion1,
+ legacy_format_version);
ASSERT_TRUE(legacy_version.IsValid());
legacy_version.SaveToPrefs(prefs());
- WritePreexistingRuleset(legacy_version, AsVector(kDummyRuleset1));
+ WriteRuleset(test_ruleset_1(), legacy_version);
ResetService(CreateRulesetService());
RunUntilIdle();
@@ -183,114 +426,378 @@ TEST_F(SubresourceFilteringRulesetServiceTest,
TEST_F(SubresourceFilteringRulesetServiceTest,
Startup_ExistingRulesetPublished) {
- const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
- RulesetVersion current_version(kTestContentVersion1,
- RulesetVersion::CurrentFormatVersion());
+ IndexedRulesetVersion current_version(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
current_version.SaveToPrefs(prefs());
- WritePreexistingRuleset(current_version, AsVector(kDummyRuleset1));
+ WriteRuleset(test_ruleset_1(), current_version);
ResetService(CreateRulesetService());
RunUntilIdle();
ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &mock_distributor()->published_rulesets()[0], dummy_ruleset));
+ &mock_distributor()->published_rulesets()[0],
+ test_ruleset_1().indexed.contents));
}
TEST_F(SubresourceFilteringRulesetServiceTest, NewRuleset_Published) {
- const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
- service()->StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), kTestContentVersion1);
RunUntilIdle();
ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &mock_distributor()->published_rulesets()[0], dummy_ruleset));
+ &mock_distributor()->published_rulesets()[0],
+ test_ruleset_1().indexed.contents));
MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
service()->RegisterDistributor(base::WrapUnique(new_distributor));
ASSERT_EQ(1u, new_distributor->published_rulesets().size());
ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &new_distributor->published_rulesets()[0], dummy_ruleset));
+ &new_distributor->published_rulesets()[0],
+ test_ruleset_1().indexed.contents));
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
+ NewRulesetWithEmptyVersion_NotPublished) {
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), std::string());
+ RunUntilIdle();
+
+ ASSERT_EQ(0u, mock_distributor()->published_rulesets().size());
+ MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
+ service()->RegisterDistributor(base::WrapUnique(new_distributor));
+ ASSERT_EQ(0u, new_distributor->published_rulesets().size());
}
TEST_F(SubresourceFilteringRulesetServiceTest, NewRuleset_Persisted) {
- const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
- service()->StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
+ base::HistogramTester histogram_tester;
+
+ base::FilePath original_license_path;
+ CreateTestLicenseFile(kTestLicenseContents, &original_license_path);
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), kTestContentVersion1,
+ original_license_path);
RunUntilIdle();
- RulesetVersion stored_version;
+ IndexedRulesetVersion stored_version;
stored_version.ReadFromPrefs(prefs());
EXPECT_EQ(kTestContentVersion1, stored_version.content_version);
- EXPECT_EQ(RulesetVersion::CurrentFormatVersion(),
+ EXPECT_EQ(IndexedRulesetVersion::CurrentFormatVersion(),
stored_version.format_version);
+ EXPECT_FALSE(base::PathExists(GetExpectedSentinelFilePath(stored_version)));
+
+ // The unindexed ruleset was accompanied by a LICENSE file, ensure it is
+ // copied next to the indexed ruleset.
+ std::string actual_license_contents;
+ ASSERT_TRUE(base::ReadFileToString(GetExpectedLicenseFilePath(stored_version),
+ &actual_license_contents));
+ EXPECT_EQ(kTestLicenseContents, actual_license_contents);
+
ResetService(CreateRulesetService());
RunUntilIdle();
ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &mock_distributor()->published_rulesets()[0], dummy_ruleset));
+ &mock_distributor()->published_rulesets()[0],
+ test_ruleset_1().indexed.contents));
+
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.IndexRuleset.WallDuration", 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.IndexRuleset.NumUnsupportedRules", 0, 1);
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.WriteRuleset.ReplaceFileError", 0);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.WriteRuleset.Result",
+ static_cast<int>(RulesetService::IndexAndWriteRulesetResult::SUCCESS), 1);
}
+// Test the scenario where a faulty copy of the ruleset resides on disk, that
+// is, when there is something in the directory corresponding to a ruleset
+// version, but preferences do not indicate that a valid copy of that version is
+// stored. The expectation is that the directory is overwritten with a correct
+// contents when the same version of the ruleset is fed to the service again.
TEST_F(SubresourceFilteringRulesetServiceTest,
- NewRulesetTwice_SecondRulesetPrevails) {
- const std::vector<uint8_t> dummy_ruleset_1(AsVector(kDummyRuleset1));
- const std::vector<uint8_t> dummy_ruleset_2(AsVector(kDummyRuleset2));
+ NewRuleset_OverwritesBadCopyOfSameVersionOnDisk) {
+ // Emulate a bad ruleset by writing |test_ruleset_2| into the directory
+ // corresponding to |test_ruleset_1| and not updating prefs.
+ IndexedRulesetVersion same_version_but_incomplete(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
+ WriteRuleset(test_ruleset_2(), same_version_but_incomplete);
+
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), kTestContentVersion1);
+ RunUntilIdle();
- StoreAndPublishUpdatedRuleset(dummy_ruleset_1, kTestContentVersion1);
+ IndexedRulesetVersion stored_version;
+ stored_version.ReadFromPrefs(prefs());
+ EXPECT_EQ(kTestContentVersion1, stored_version.content_version);
+ EXPECT_EQ(IndexedRulesetVersion::CurrentFormatVersion(),
+ stored_version.format_version);
+ EXPECT_FALSE(base::PathExists(GetExpectedSentinelFilePath(stored_version)));
+
+ ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
+ ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+ &mock_distributor()->published_rulesets()[0],
+ test_ruleset_1().indexed.contents));
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
+ NewRuleset_SuccessWithUnsupportedRules) {
+ base::HistogramTester histogram_tester;
+
+ // URL patterns longer than 255 characters are not supported.
+ const std::string kTooLongSuffix(1000, 'a');
+ TestRulesetPair ruleset_with_unsupported_rule;
+ ASSERT_NO_FATAL_FAILURE(
+ test_ruleset_creator()
+ ->CreateUnindexedRulesetToDisallowURLsWithPathSuffix(
+ kTooLongSuffix, &ruleset_with_unsupported_rule.unindexed));
+ IndexAndStoreAndPublishUpdatedRuleset(ruleset_with_unsupported_rule,
+ kTestContentVersion1);
+ RunUntilIdle();
+
+ IndexedRulesetVersion stored_version;
+ stored_version.ReadFromPrefs(prefs());
+ EXPECT_EQ(kTestContentVersion1, stored_version.content_version);
+ EXPECT_EQ(IndexedRulesetVersion::CurrentFormatVersion(),
+ stored_version.format_version);
+ EXPECT_FALSE(base::PathExists(GetExpectedSentinelFilePath(stored_version)));
+
+ ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
+
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.IndexRuleset.WallDuration", 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.IndexRuleset.NumUnsupportedRules", 1, 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.WriteRuleset.Result",
+ static_cast<int>(RulesetService::IndexAndWriteRulesetResult::SUCCESS), 1);
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
+ NewRuleset_CannotOpenUnindexedRulesetFile) {
+ base::HistogramTester histogram_tester;
+ UnindexedRulesetInfo ruleset_info;
+ ruleset_info.ruleset_path = base::FilePath(); // Non-existent.
+ ruleset_info.content_version = kTestContentVersion1;
+ service()->IndexAndStoreAndPublishRulesetIfNeeded(ruleset_info);
RunUntilIdle();
- StoreAndPublishUpdatedRuleset(dummy_ruleset_2, kTestContentVersion2);
+ IndexedRulesetVersion stored_version;
+ stored_version.ReadFromPrefs(prefs());
+ EXPECT_FALSE(stored_version.IsValid());
+
+ // Expect no sentinel file. Although it is unlikely that we will magically
+ // find the file on a subsequent attempt, failing this early is cheap.
+ IndexedRulesetVersion failed_version(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
+ EXPECT_FALSE(base::PathExists(GetExpectedSentinelFilePath(failed_version)));
+
+ ASSERT_EQ(0u, mock_distributor()->published_rulesets().size());
+
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.WriteRuleset.Result",
+ static_cast<int>(RulesetService::IndexAndWriteRulesetResult::
+ FAILED_OPENING_UNINDEXED_RULESET),
+ 1);
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest, NewRuleset_ParseFailure) {
+ base::HistogramTester histogram_tester;
+ const std::string kGarbage(10000, '\xff');
+ ASSERT_TRUE(base::AppendToFile(test_ruleset_1().unindexed.path,
+ kGarbage.data(),
+ static_cast<int>(kGarbage.size())));
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), kTestContentVersion1);
+ RunUntilIdle();
+
+ IndexedRulesetVersion stored_version;
+ stored_version.ReadFromPrefs(prefs());
+ EXPECT_FALSE(stored_version.IsValid());
+
+ // Expect that a sentinel file is left behind. The parse failure is most
+ // likely permanent, there is no point to retrying indexing on next start-up.
+ IndexedRulesetVersion failed_version(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
+ EXPECT_TRUE(base::PathExists(GetExpectedSentinelFilePath(failed_version)));
+
+ ASSERT_EQ(0u, mock_distributor()->published_rulesets().size());
+
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.WriteRuleset.Result",
+ static_cast<int>(RulesetService::IndexAndWriteRulesetResult::
+ FAILED_PARSING_UNINDEXED_RULESET),
+ 1);
+}
+
+TEST_F(SubresourceFilteringRulesetServiceDeathTest, NewRuleset_IndexingCrash) {
+#if GTEST_HAS_DEATH_TEST
+ auto scoped_override(OverrideFunctionForScope(
+ &RulesetService::g_index_ruleset_func, &MockCrashingIndexRuleset));
+ EXPECT_DEATH(
+ {
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(),
+ kTestContentVersion1);
+ RunUntilIdle();
+ },
+ "Synthetic crash");
+#else
+ auto scoped_override(OverrideFunctionForScope(
+ &RulesetService::g_index_ruleset_func, &MockFailingIndexRuleset));
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), kTestContentVersion1);
+ RunUntilIdle();
+#endif
+
+ // Expect that a sentinel file is left behind as a warning not to attempt
+ // indexing this version again, and thus to prevent crashing again.
+ IndexedRulesetVersion crashed_version(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
+ EXPECT_TRUE(base::PathExists(GetExpectedSentinelFilePath(crashed_version)));
+
+ base::HistogramTester histogram_tester;
+ ResetService(CreateRulesetService());
+ RunUntilIdle();
+
+ ASSERT_EQ(0u, mock_distributor()->published_rulesets().size());
+
+ // The subsequent indexing attempt should be aborted.
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), kTestContentVersion1);
+ RunUntilIdle();
+
+ IndexedRulesetVersion stored_version;
+ stored_version.ReadFromPrefs(prefs());
+ EXPECT_FALSE(stored_version.IsValid());
+
+ ASSERT_EQ(0u, mock_distributor()->published_rulesets().size());
+
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.WriteRuleset.Result",
+ static_cast<int>(RulesetService::IndexAndWriteRulesetResult::
+ ABORTED_BECAUSE_SENTINEL_FILE_PRESENT),
+ 1);
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest, NewRuleset_WriteFailure) {
+ base::HistogramTester histogram_tester;
+ auto scoped_override(OverrideFunctionForScope(
+ &RulesetService::g_replace_file_func, &MockFailingReplaceFile));
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), kTestContentVersion1);
+ RunUntilIdle();
+
+ IndexedRulesetVersion stored_version;
+ stored_version.ReadFromPrefs(prefs());
+ EXPECT_FALSE(stored_version.IsValid());
+
+ ASSERT_EQ(0u, mock_distributor()->published_rulesets().size());
+
+ // Expect that the sentinel file is already gone. Write failures are quite
+ // frequent and are often transient, so it is worth attempting indexing again.
+ IndexedRulesetVersion failed_version(
+ kTestContentVersion1, IndexedRulesetVersion::CurrentFormatVersion());
+ EXPECT_FALSE(base::PathExists(GetExpectedSentinelFilePath(failed_version)));
+
+ using IndexAndWriteRulesetResult = RulesetService::IndexAndWriteRulesetResult;
+ histogram_tester.ExpectTotalCount(
+ "SubresourceFilter.IndexRuleset.WallDuration", 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.IndexRuleset.NumUnsupportedRules", 0, 1);
+ base::File::Error expected_error = base::File::FILE_ERROR_NOT_FOUND;
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.WriteRuleset.ReplaceFileError", -expected_error, 1);
+ histogram_tester.ExpectUniqueSample(
+ "SubresourceFilter.WriteRuleset.Result",
+ static_cast<int>(IndexAndWriteRulesetResult::FAILED_REPLACE_FILE), 1);
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
+ NewRulesetTwice_SecondRulesetPrevails) {
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), kTestContentVersion1);
+ RunUntilIdle();
+
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_2(), kTestContentVersion2);
RunUntilIdle();
// This verifies that the contents from the first version of the ruleset file
// can still be read after it has been deprecated.
ASSERT_EQ(2u, mock_distributor()->published_rulesets().size());
ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &mock_distributor()->published_rulesets()[0], dummy_ruleset_1));
+ &mock_distributor()->published_rulesets()[0],
+ test_ruleset_1().indexed.contents));
ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &mock_distributor()->published_rulesets()[1], dummy_ruleset_2));
+ &mock_distributor()->published_rulesets()[1],
+ test_ruleset_2().indexed.contents));
MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
service()->RegisterDistributor(base::WrapUnique(new_distributor));
ASSERT_EQ(1u, new_distributor->published_rulesets().size());
ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &new_distributor->published_rulesets()[0], dummy_ruleset_2));
+ &new_distributor->published_rulesets()[0],
+ test_ruleset_2().indexed.contents));
- RulesetVersion stored_version;
+ IndexedRulesetVersion stored_version;
stored_version.ReadFromPrefs(prefs());
EXPECT_EQ(kTestContentVersion2, stored_version.content_version);
}
TEST_F(SubresourceFilteringRulesetServiceTest,
+ NewRulesetTwiceWithTheSameVersion_SecondIsIgnored) {
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), kTestContentVersion1);
+ RunUntilIdle();
+
+ // For good measure, also violate the requirement that versions should
+ // uniquely identify the contents.
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_2(), kTestContentVersion1);
+ ASSERT_NO_FATAL_FAILURE(AssertNoPendingTasks());
+
+ ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
+ ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+ &mock_distributor()->published_rulesets()[0],
+ test_ruleset_1().indexed.contents));
+
+ MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
+ service()->RegisterDistributor(base::WrapUnique(new_distributor));
+ ASSERT_EQ(1u, new_distributor->published_rulesets().size());
+ ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+ &new_distributor->published_rulesets()[0],
+ test_ruleset_1().indexed.contents));
+
+ IndexedRulesetVersion stored_version;
+ stored_version.ReadFromPrefs(prefs());
+ EXPECT_EQ(kTestContentVersion1, stored_version.content_version);
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
NewRulesetSetShortlyBeforeDestruction_NoCrashes) {
- const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
for (size_t num_tasks_inbetween = 0; num_tasks_inbetween < 5u;
++num_tasks_inbetween) {
SCOPED_TRACE(::testing::Message() << "#Tasks: " << num_tasks_inbetween);
- StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(),
+ kTestContentVersion1);
RunPendingTasksNTimes(num_tasks_inbetween);
ResetService();
RunUntilIdle();
- base::DeleteFile(base_dir(), false);
+ EXPECT_TRUE(base::DeleteFile(base_dir(), true));
ResetService(CreateRulesetService());
}
+
+ // Must pump out PostTaskWithReply tasks that are referencing the very same
+ // task runner to avoid circular dependencies and leaks on shutdown.
+ RunUntilIdle();
}
TEST_F(SubresourceFilteringRulesetServiceTest,
NewRulesetTwiceInQuickSuccession_SecondRulesetPrevails) {
- const std::vector<uint8_t> dummy_ruleset_1(AsVector(kDummyRuleset1));
- const std::vector<uint8_t> dummy_ruleset_2(AsVector(kDummyRuleset2));
for (size_t num_tasks_inbetween = 0; num_tasks_inbetween < 5u;
++num_tasks_inbetween) {
SCOPED_TRACE(::testing::Message() << "#Tasks: " << num_tasks_inbetween);
- StoreAndPublishUpdatedRuleset(dummy_ruleset_1, kTestContentVersion1);
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(),
+ kTestContentVersion1);
RunPendingTasksNTimes(num_tasks_inbetween);
- StoreAndPublishUpdatedRuleset(dummy_ruleset_2, kTestContentVersion2);
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_2(),
+ kTestContentVersion2);
RunUntilIdle();
// Optionally permit a "hazardous" publication of either the old or new
@@ -300,53 +807,37 @@ TEST_F(SubresourceFilteringRulesetServiceTest,
if (mock_distributor()->published_rulesets().size() == 2) {
base::File* file = &mock_distributor()->published_rulesets()[0];
ASSERT_TRUE(file->IsValid());
- EXPECT_THAT(ReadFileContents(file),
- testing::AnyOf(testing::Eq(dummy_ruleset_1),
- testing::Eq(dummy_ruleset_2)));
+ EXPECT_THAT(
+ ReadFileContents(file),
+ ::testing::AnyOf(::testing::Eq(test_ruleset_1().indexed.contents),
+ ::testing::Eq(test_ruleset_2().indexed.contents)));
}
ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &mock_distributor()->published_rulesets().back(), dummy_ruleset_2));
+ &mock_distributor()->published_rulesets().back(),
+ test_ruleset_2().indexed.contents));
MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
service()->RegisterDistributor(base::WrapUnique(new_distributor));
ASSERT_EQ(1u, new_distributor->published_rulesets().size());
ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &new_distributor->published_rulesets()[0], dummy_ruleset_2));
+ &new_distributor->published_rulesets()[0],
+ test_ruleset_2().indexed.contents));
- RulesetVersion stored_version;
+ IndexedRulesetVersion stored_version;
stored_version.ReadFromPrefs(prefs());
EXPECT_EQ(kTestContentVersion2, stored_version.content_version);
- }
-}
-
-TEST_F(SubresourceFilteringRulesetServiceTest,
- NewRulesetTwiceForTheSameVersion_SuccessAtLeastOnce) {
- const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
-
- StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
- RunUntilIdle();
-
- StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
- RunUntilIdle();
- ASSERT_LE(1u, mock_distributor()->published_rulesets().size());
- ASSERT_GE(2u, mock_distributor()->published_rulesets().size());
- ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &mock_distributor()->published_rulesets().front(), dummy_ruleset));
- ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &mock_distributor()->published_rulesets().back(), dummy_ruleset));
+ ResetService();
+ RunUntilIdle();
- MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
- service()->RegisterDistributor(base::WrapUnique(new_distributor));
- ASSERT_EQ(1u, new_distributor->published_rulesets().size());
- ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
- &new_distributor->published_rulesets()[0], dummy_ruleset));
+ EXPECT_TRUE(base::DeleteFile(base_dir(), true));
+ IndexedRulesetVersion().SaveToPrefs(prefs());
+ ResetService(CreateRulesetService());
+ }
}
TEST_F(SubresourceFilteringRulesetServiceTest, RulesetIsReadonly) {
- const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
-
- service()->StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
+ IndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), kTestContentVersion1);
RunUntilIdle();
ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_client.h b/chromium/components/subresource_filter/core/browser/subresource_filter_client.h
new file mode 100644
index 00000000000..f834a10263e
--- /dev/null
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_client.h
@@ -0,0 +1,25 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
+
+namespace subresource_filter {
+
+class SubresourceFilterClient {
+ public:
+ virtual ~SubresourceFilterClient() = default;
+
+ // Changes the visibility of the prompt that informs the user that potentially
+ // deceptive content has been blocked on the page according to the passed
+ // |visibility| parameter. When |visibility| is set to true, an icon on the
+ // right side of the omnibox is displayed. If the user clicks on the icon then
+ // a bubble is shown that explains the feature and alalows the user to turn it
+ // off.
+ virtual void ToggleNotificationVisibility(bool visibility) = 0;
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_constants.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_constants.cc
index 664990e33ae..dd9b9a44da5 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_constants.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_constants.cc
@@ -6,10 +6,22 @@
namespace subresource_filter {
-const base::FilePath::CharType kRulesetBaseDirectoryName[] =
- FILE_PATH_LITERAL("Subresource Filtering Rules");
+const base::FilePath::CharType kTopLevelDirectoryName[] =
+ FILE_PATH_LITERAL("Subresource Filter");
+
+const base::FilePath::CharType kIndexedRulesetBaseDirectoryName[] =
+ FILE_PATH_LITERAL("Indexed Rules");
+
+const base::FilePath::CharType kUnindexedRulesetBaseDirectoryName[] =
+ FILE_PATH_LITERAL("Unindexed Rules");
const base::FilePath::CharType kRulesetDataFileName[] =
FILE_PATH_LITERAL("Ruleset Data");
+const base::FilePath::CharType kLicenseFileName[] =
+ FILE_PATH_LITERAL("LICENSE");
+
+const base::FilePath::CharType kSentinelFileName[] =
+ FILE_PATH_LITERAL("Indexing in Progress");
+
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h b/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h
index b06c400e450..0d52ad778bf 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_constants.h
@@ -9,13 +9,35 @@
namespace subresource_filter {
-// The name of the directory under the user data directory, where filtering
-// rules are stored.
-extern const base::FilePath::CharType kRulesetBaseDirectoryName[];
+// The name of the top-level directory under the user data directory that
+// contains all files and subdirectories related to the subresource filter.
+extern const base::FilePath::CharType kTopLevelDirectoryName[];
+
+// Paths under |kTopLevelDirectoryName|
+// ------------------------------------
+
+// The name of the subdirectory under the top-level directory that stores
+// versions of indexed rulesets. Files that belong to an IndexedRulesetVersion
+// are stored under /format_version/content_version/.
+extern const base::FilePath::CharType kIndexedRulesetBaseDirectoryName[];
+
+// The name of the subdirectory under the top-level directory that stores
+// versions of unindexed rulesets downloaded through the component updater.
+extern const base::FilePath::CharType kUnindexedRulesetBaseDirectoryName[];
+
+// Paths under IndexedRulesetVersion::GetSubdirectoryPathForVersion
+// ----------------------------------------------------------------
// The name of the file that actually stores the ruleset contents.
extern const base::FilePath::CharType kRulesetDataFileName[];
+// The name of the applicable license file, if any, stored next to the ruleset.
+extern const base::FilePath::CharType kLicenseFileName[];
+
+// The name of the sentinel file that is temporarily stored to indicate that the
+// ruleset is being indexed.
+extern const base::FilePath::CharType kSentinelFileName[];
+
} // namespace subresource_filter
#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CONSTANTS_H_
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
index 3e16a9f98d7..e85213c37a6 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/variations/variations_associated_data.h"
@@ -19,6 +20,16 @@ const char kActivationStateDryRun[] = "dryrun";
const char kActivationStateEnabled[] = "enabled";
const char kActivationStateDisabled[] = "disabled";
+const char kActivationScopeParameterName[] = "activation_scope";
+const char kActivationScopeAllSites[] = "all_sites";
+const char kActivationScopeActivationList[] = "activation_list";
+const char kActivationScopeNoSites[] = "no_sites";
+
+const char kActivationListsParameterName[] = "activation_lists";
+const char kActivationListSocialEngineeringAdsInterstitial[] =
+ "social_engineering_ads_interstitial";
+const char kActivationListPhishingInterstitial[] = "phishing_interstitial";
+
ActivationState GetMaximumActivationState() {
std::string activation_state = variations::GetVariationParamValueByFeature(
kSafeBrowsingSubresourceFilter, kActivationStateParameterName);
@@ -29,4 +40,34 @@ ActivationState GetMaximumActivationState() {
return ActivationState::DISABLED;
}
+ActivationScope GetCurrentActivationScope() {
+ std::string activation_scope = variations::GetVariationParamValueByFeature(
+ kSafeBrowsingSubresourceFilter, kActivationScopeParameterName);
+ if (base::LowerCaseEqualsASCII(activation_scope, kActivationScopeAllSites))
+ return ActivationScope::ALL_SITES;
+ else if (base::LowerCaseEqualsASCII(activation_scope,
+ kActivationScopeActivationList))
+ return ActivationScope::ACTIVATION_LIST;
+ return ActivationScope::NO_SITES;
+}
+
+ActivationList GetCurrentActivationList() {
+ std::string activation_lists = variations::GetVariationParamValueByFeature(
+ kSafeBrowsingSubresourceFilter, kActivationListsParameterName);
+ ActivationList activation_list_type = ActivationList::NONE;
+ for (const base::StringPiece& activation_list :
+ base::SplitStringPiece(activation_lists, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ if (base::LowerCaseEqualsASCII(activation_list,
+ kActivationListPhishingInterstitial)) {
+ return ActivationList::PHISHING_INTERSTITIAL;
+ } else if (base::LowerCaseEqualsASCII(
+ activation_list,
+ kActivationListSocialEngineeringAdsInterstitial)) {
+ activation_list_type = ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL;
+ }
+ }
+ return activation_list_type;
+}
+
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features.h b/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
index 612a2d9f1d6..b19b2dc1333 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -6,6 +6,8 @@
#define COMPONENTS_SUBRESOURCE_FILTER_SUBRESOURCE_FILTER_FEATURES_H_
#include "base/feature_list.h"
+#include "components/subresource_filter/core/common/activation_list.h"
+#include "components/subresource_filter/core/common/activation_scope.h"
#include "components/subresource_filter/core/common/activation_state.h"
namespace subresource_filter {
@@ -19,11 +21,31 @@ extern const char kActivationStateDryRun[];
extern const char kActivationStateEnabled[];
extern const char kActivationStateDisabled[];
+extern const char kActivationScopeParameterName[];
+extern const char kActivationScopeAllSites[];
+extern const char kActivationScopeActivationList[];
+extern const char kActivationScopeNoSites[];
+
+extern const char kActivationListsParameterName[];
+extern const char kActivationListSocialEngineeringAdsInterstitial[];
+extern const char kActivationListPhishingInterstitial[];
+
// Returns the maximum degree to which subresource filtering should be activated
// on any RenderFrame. This will be ActivationState::DISABLED unless the feature
// is enabled and variation parameters prescribe a higher activation state.
ActivationState GetMaximumActivationState();
+// Returns the current activation scope, that is, the subset of page loads where
+// subresource filtering should be activated. The function returns
+// ActivationScope::NO_SITES unless the feature is enabled and variation
+// parameters prescribe a wider activation scope.
+ActivationScope GetCurrentActivationScope();
+
+// Returns current activation list, based on the values from variation params in
+// the feature |kSafeBrowsingSubresourceFilter|. When the corresponding
+// variation param is empty, returns most conservative ActivationList::NONE.
+ActivationList GetCurrentActivationList();
+
} // namespace subresource_filter
#endif // COMPONENTS_SUBRESOURCE_FILTER_SUBRESOURCE_FILTER_FEATURES_H_
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
index 6b9cee67bab..5396c019832 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
@@ -22,12 +22,24 @@ const char kTestExperimentGroupName[] = "GroupNameShouldNotMatter";
ScopedSubresourceFilterFeatureToggle::ScopedSubresourceFilterFeatureToggle(
base::FeatureList::OverrideState feature_state,
- const std::string& maximum_activation_state) {
- base::FeatureList::ClearInstanceForTesting();
+ const std::string& maximum_activation_state,
+ const std::string& activation_scope)
+ : ScopedSubresourceFilterFeatureToggle(feature_state,
+ maximum_activation_state,
+ activation_scope,
+ std::string()) {}
+
+ScopedSubresourceFilterFeatureToggle::ScopedSubresourceFilterFeatureToggle(
+ base::FeatureList::OverrideState feature_state,
+ const std::string& maximum_activation_state,
+ const std::string& activation_scope,
+ const std::string& activation_lists) {
variations::testing::ClearAllVariationParams();
std::map<std::string, std::string> variation_params;
variation_params[kActivationStateParameterName] = maximum_activation_state;
+ variation_params[kActivationScopeParameterName] = activation_scope;
+ variation_params[kActivationListsParameterName] = activation_lists;
EXPECT_TRUE(variations::AssociateVariationParams(
kTestFieldTrialName, kTestExperimentGroupName, variation_params));
@@ -37,12 +49,24 @@ ScopedSubresourceFilterFeatureToggle::ScopedSubresourceFilterFeatureToggle(
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
feature_list->RegisterFieldTrialOverride(kSafeBrowsingSubresourceFilter.name,
feature_state, field_trial);
- base::FeatureList::SetInstance(std::move(feature_list));
+
+ // Since we are adding a scoped feature list after browser start, copy over
+ // the existing feature list to prevent inconsistency.
+ base::FeatureList* existing_feature_list = base::FeatureList::GetInstance();
+ if (existing_feature_list) {
+ std::string enabled_features;
+ std::string disabled_features;
+ base::FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features,
+ &disabled_features);
+ feature_list->InitializeFromCommandLine(enabled_features,
+ disabled_features);
+ }
+
+ scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
}
ScopedSubresourceFilterFeatureToggle::~ScopedSubresourceFilterFeatureToggle() {
variations::testing::ClearAllVariationParams();
- base::FeatureList::ClearInstanceForTesting();
}
} // namespace testing
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.h b/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.h
index 0c301b9d409..f2065e9cb40 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.h
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features_test_support.h
@@ -9,6 +9,7 @@
#include "base/feature_list.h"
#include "base/macros.h"
+#include "base/test/scoped_feature_list.h"
namespace subresource_filter {
namespace testing {
@@ -20,10 +21,20 @@ class ScopedSubresourceFilterFeatureToggle {
public:
ScopedSubresourceFilterFeatureToggle(
base::FeatureList::OverrideState feature_state,
- const std::string& maximum_activation_state);
+ const std::string& maximum_activation_state,
+ const std::string& activation_scope);
+
+ ScopedSubresourceFilterFeatureToggle(
+ base::FeatureList::OverrideState feature_state,
+ const std::string& maximum_activation_state,
+ const std::string& activation_scope,
+ const std::string& activation_lists);
+
~ScopedSubresourceFilterFeatureToggle();
private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+
DISALLOW_COPY_AND_ASSIGN(ScopedSubresourceFilterFeatureToggle);
};
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
index 78637e42047..51a3d58c827 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
@@ -40,9 +40,146 @@ TEST(SubresourceFilterFeaturesTest, ActivationState) {
testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
test_case.feature_enabled ? base::FeatureList::OVERRIDE_ENABLE_FEATURE
: base::FeatureList::OVERRIDE_USE_DEFAULT,
- test_case.activation_state_param);
+ test_case.activation_state_param, kActivationScopeNoSites);
EXPECT_EQ(test_case.expected_activation_state, GetMaximumActivationState());
+ EXPECT_EQ(ActivationScope::NO_SITES, GetCurrentActivationScope());
+ }
+}
+
+TEST(SubresourceFilterFeaturesTest, ActivationScope) {
+ const struct {
+ bool feature_enabled;
+ const char* activation_scope_param;
+ ActivationScope expected_activation_scope;
+ } kTestCases[] = {
+ {false, "", ActivationScope::NO_SITES},
+ {false, "no_sites", ActivationScope::NO_SITES},
+ {false, "allsites", ActivationScope::NO_SITES},
+ {false, "enabled", ActivationScope::NO_SITES},
+ {false, "%$ garbage !%", ActivationScope::NO_SITES},
+ {true, "", ActivationScope::NO_SITES},
+ {true, "nosites", ActivationScope::NO_SITES},
+ {true, "No_sites", ActivationScope::NO_SITES},
+ {true, "no_sites", ActivationScope::NO_SITES},
+ {true, "%$ garbage !%", ActivationScope::NO_SITES},
+ {true, kActivationScopeAllSites, ActivationScope::ALL_SITES},
+ {true, kActivationScopeActivationList, ActivationScope::ACTIVATION_LIST}};
+
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(::testing::Message("Enabled = ") << test_case.feature_enabled);
+ SCOPED_TRACE(::testing::Message("ActivationScopeParam = \"")
+ << test_case.activation_scope_param << "\"");
+
+ base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ test_case.feature_enabled ? base::FeatureList::OVERRIDE_ENABLE_FEATURE
+ : base::FeatureList::OVERRIDE_USE_DEFAULT,
+ kActivationStateDisabled, test_case.activation_scope_param);
+
+ EXPECT_EQ(ActivationState::DISABLED, GetMaximumActivationState());
+ EXPECT_EQ(test_case.expected_activation_scope, GetCurrentActivationScope());
+ }
+}
+
+TEST(SubresourceFilterFeaturesTest, ActivationStateAndScope) {
+ const struct {
+ bool feature_enabled;
+ const char* activation_state_param;
+ ActivationState expected_activation_state;
+ const char* activation_scope_param;
+ ActivationScope expected_activation_scope;
+ } kTestCases[] = {
+ {false, kActivationStateDisabled, ActivationState::DISABLED,
+ kActivationScopeNoSites, ActivationScope::NO_SITES},
+ {true, kActivationStateDisabled, ActivationState::DISABLED,
+ kActivationScopeNoSites, ActivationScope::NO_SITES},
+ {true, kActivationStateDisabled, ActivationState::DISABLED,
+ kActivationScopeAllSites, ActivationScope::ALL_SITES},
+ {true, kActivationStateDisabled, ActivationState::DISABLED,
+ kActivationScopeActivationList, ActivationScope::ACTIVATION_LIST},
+ {true, kActivationStateDisabled, ActivationState::DISABLED,
+ kActivationScopeAllSites, ActivationScope::ALL_SITES},
+ {true, kActivationStateDryRun, ActivationState::DRYRUN,
+ kActivationScopeNoSites, ActivationScope::NO_SITES},
+ {true, kActivationStateDryRun, ActivationState::DRYRUN,
+ kActivationScopeAllSites, ActivationScope::ALL_SITES},
+ {true, kActivationStateDryRun, ActivationState::DRYRUN,
+ kActivationScopeActivationList, ActivationScope::ACTIVATION_LIST},
+ {true, kActivationStateDryRun, ActivationState::DRYRUN,
+ kActivationScopeAllSites, ActivationScope::ALL_SITES},
+ {true, kActivationStateEnabled, ActivationState::ENABLED,
+ kActivationScopeNoSites, ActivationScope::NO_SITES},
+ {true, kActivationStateEnabled, ActivationState::ENABLED,
+ kActivationScopeAllSites, ActivationScope::ALL_SITES},
+ {true, kActivationStateEnabled, ActivationState::ENABLED,
+ kActivationScopeActivationList, ActivationScope::ACTIVATION_LIST},
+ {true, kActivationStateEnabled, ActivationState::ENABLED,
+ kActivationScopeAllSites, ActivationScope::ALL_SITES},
+ {false, kActivationStateEnabled, ActivationState::DISABLED,
+ kActivationScopeAllSites, ActivationScope::NO_SITES}};
+
+ for (const auto& test_case : kTestCases) {
+ base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ test_case.feature_enabled ? base::FeatureList::OVERRIDE_ENABLE_FEATURE
+ : base::FeatureList::OVERRIDE_USE_DEFAULT,
+ test_case.activation_state_param, test_case.activation_scope_param);
+
+ EXPECT_EQ(test_case.expected_activation_scope, GetCurrentActivationScope());
+ EXPECT_EQ(test_case.expected_activation_state, GetMaximumActivationState());
+ }
+}
+
+TEST(SubresourceFilterFeaturesTest, ActivationList) {
+ const std::string activation_soc_eng(
+ kActivationListSocialEngineeringAdsInterstitial);
+ const std::string activation_phishing(kActivationListPhishingInterstitial);
+ const std::string socEngPhising = activation_soc_eng + activation_phishing;
+ const std::string socEngCommaPhising =
+ activation_soc_eng + "," + activation_phishing;
+ const std::string phishingCommaSocEng =
+ activation_phishing + "," + activation_soc_eng;
+ const std::string socEngCommaPhisingCommaGarbage =
+ socEngCommaPhising + "," + "Garbage";
+ const struct {
+ bool feature_enabled;
+ const char* activation_list_param;
+ ActivationList expected_activation_list;
+ } kTestCases[] = {
+ {false, "", ActivationList::NONE},
+ {false, "social eng ads intertitial", ActivationList::NONE},
+ {false, "phishing,interstital", ActivationList::NONE},
+ {false, "%$ garbage !%", ActivationList::NONE},
+ {true, "", ActivationList::NONE},
+ {true, "social eng ads intertitial", ActivationList::NONE},
+ {true, "phishing interstital", ActivationList::NONE},
+ {true, "%$ garbage !%", ActivationList::NONE},
+ {true, kActivationListSocialEngineeringAdsInterstitial,
+ ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL},
+ {true, kActivationListPhishingInterstitial,
+ ActivationList::PHISHING_INTERSTITIAL},
+ {true, socEngPhising.c_str(), ActivationList::NONE},
+ {true, socEngCommaPhising.c_str(), ActivationList::PHISHING_INTERSTITIAL},
+ {true, phishingCommaSocEng.c_str(),
+ ActivationList::PHISHING_INTERSTITIAL},
+ {true, socEngCommaPhisingCommaGarbage.c_str(),
+ ActivationList::PHISHING_INTERSTITIAL},
+ {true, "List1, List2", ActivationList::NONE}};
+
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(::testing::Message("Enabled = ") << test_case.feature_enabled);
+ SCOPED_TRACE(::testing::Message("ActivationListParam = \"")
+ << test_case.activation_list_param << "\"");
+
+ base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
+ testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
+ test_case.feature_enabled ? base::FeatureList::OVERRIDE_ENABLE_FEATURE
+ : base::FeatureList::OVERRIDE_USE_DEFAULT,
+ kActivationStateDisabled, kActivationScopeNoSites,
+ test_case.activation_list_param);
+
+ EXPECT_EQ(test_case.expected_activation_list, GetCurrentActivationList());
}
}
diff --git a/chromium/components/subresource_filter/core/common/BUILD.gn b/chromium/components/subresource_filter/core/common/BUILD.gn
index 1b38ff528e7..4e12cc3b6d3 100644
--- a/chromium/components/subresource_filter/core/common/BUILD.gn
+++ b/chromium/components/subresource_filter/core/common/BUILD.gn
@@ -1,23 +1,58 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
+# 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.
-source_set("common") {
+static_library("common") {
sources = [
+ "activation_scope.cc",
+ "activation_scope.h",
"activation_state.cc",
"activation_state.h",
"closed_hash_map.h",
+ "copying_file_stream.cc",
+ "copying_file_stream.h",
"fuzzy_pattern_matching.cc",
"fuzzy_pattern_matching.h",
+ "indexed_ruleset.cc",
+ "indexed_ruleset.h",
"knuth_morris_pratt.h",
"memory_mapped_ruleset.cc",
"memory_mapped_ruleset.h",
"ngram_extractor.h",
"string_splitter.h",
"uint64_hasher.h",
+ "unindexed_ruleset.cc",
+ "unindexed_ruleset.h",
+ "url_pattern.cc",
+ "url_pattern.h",
+ "url_pattern_matching.h",
]
+
+ public_deps = [
+ "//components/subresource_filter/core/common/flat:flatbuffer",
+ "//components/subresource_filter/core/common/proto:proto",
+ ]
+
deps = [
"//base",
+ "//net",
+ "//third_party/flatbuffers:flatbuffers",
+ "//third_party/protobuf:protobuf_lite",
+ "//url",
+ ]
+}
+
+static_library("test_support") {
+ testonly = true
+ sources = [
+ "test_ruleset_creator.cc",
+ "test_ruleset_creator.h",
+ ]
+ deps = [
+ ":common",
+ "//base",
+ "//testing/gtest",
+ "//third_party/protobuf:protobuf_lite",
]
}
@@ -26,13 +61,18 @@ source_set("unit_tests") {
sources = [
"closed_hash_map_unittest.cc",
"fuzzy_pattern_matching_unittest.cc",
+ "indexed_ruleset_unittest.cc",
"knuth_morris_pratt_unittest.cc",
"ngram_extractor_unittest.cc",
"string_splitter_unittest.cc",
+ "unindexed_ruleset_unittest.cc",
+ "url_pattern_matching_unittest.cc",
]
deps = [
":common",
"//base",
"//testing/gtest",
+ "//third_party/protobuf:protobuf_lite",
+ "//url",
]
}
diff --git a/chromium/components/subresource_filter/core/common/activation_list.h b/chromium/components/subresource_filter/core/common/activation_list.h
new file mode 100644
index 00000000000..87b6408de09
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/activation_list.h
@@ -0,0 +1,19 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_ACTIVATION_LIST_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_ACTIVATION_LIST_H_
+
+namespace subresource_filter {
+
+enum class ActivationList {
+ NONE,
+ SOCIAL_ENG_ADS_INTERSTITIAL,
+ PHISHING_INTERSTITIAL,
+ LAST = PHISHING_INTERSTITIAL,
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_ACTIVATION_LIST_H_
diff --git a/chromium/components/subresource_filter/core/common/activation_scope.cc b/chromium/components/subresource_filter/core/common/activation_scope.cc
new file mode 100644
index 00000000000..9b939570e99
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/activation_scope.cc
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/core/common/activation_scope.h"
+
+#include <ostream>
+
+#include "base/logging.h"
+
+namespace subresource_filter {
+
+std::ostream& operator<<(std::ostream& os, const ActivationScope& state) {
+ switch (state) {
+ case ActivationScope::NO_SITES:
+ os << "NO_SITES";
+ break;
+ case ActivationScope::ALL_SITES:
+ os << "ALL_SITES";
+ break;
+ case ActivationScope::ACTIVATION_LIST:
+ os << "ACTIVATION_LIST";
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return os;
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/activation_scope.h b/chromium/components/subresource_filter/core/common/activation_scope.h
new file mode 100644
index 00000000000..aa65d368b8a
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/activation_scope.h
@@ -0,0 +1,29 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_ACTIVATION_SCOPE_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_ACTIVATION_SCOPE_H_
+
+#include <iosfwd>
+
+namespace subresource_filter {
+
+// Defines the scope of triggering the Safe Browsing Subresource Filter.
+enum class ActivationScope {
+ NO_SITES,
+ // Allows to activate Safe Browsing Subresource Filter only on web sites from
+ // the Safe Browsing blacklist.
+ ACTIVATION_LIST,
+ // Testing only. Allows to send activation signal to the RenderFrame for each
+ // load.
+ ALL_SITES,
+ LAST = ACTIVATION_LIST,
+};
+
+// For logging use only.
+std::ostream& operator<<(std::ostream& os, const ActivationScope& state);
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_ACTIVATION_SCOPE_H_
diff --git a/chromium/components/subresource_filter/core/common/activation_state.h b/chromium/components/subresource_filter/core/common/activation_state.h
index 6a92e411936..4f568d502e7 100644
--- a/chromium/components/subresource_filter/core/common/activation_state.h
+++ b/chromium/components/subresource_filter/core/common/activation_state.h
@@ -16,7 +16,7 @@ enum class ActivationState {
// allowed to proceed regardless. Used for stability and performance testing.
DRYRUN,
ENABLED,
- LAST = ENABLED
+ LAST = ENABLED,
};
// For logging use only.
diff --git a/chromium/components/subresource_filter/core/common/copying_file_stream.cc b/chromium/components/subresource_filter/core/common/copying_file_stream.cc
new file mode 100644
index 00000000000..5d4b82bfbf8
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/copying_file_stream.cc
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/core/common/copying_file_stream.h"
+
+namespace subresource_filter {
+
+// CopyingFileInputStream ------------------------------------------------------
+
+CopyingFileInputStream::~CopyingFileInputStream() = default;
+
+CopyingFileInputStream::CopyingFileInputStream(base::File file)
+ : file_(std::move(file)) {}
+
+int CopyingFileInputStream::Read(void* buffer, int size) {
+ return file_.ReadAtCurrentPosNoBestEffort(static_cast<char*>(buffer), size);
+}
+
+// CopyingFileOutputStream -----------------------------------------------------
+CopyingFileOutputStream::~CopyingFileOutputStream() = default;
+
+CopyingFileOutputStream::CopyingFileOutputStream(base::File file)
+ : file_(std::move(file)) {}
+
+bool CopyingFileOutputStream::Write(const void* buffer, int size) {
+ return file_.WriteAtCurrentPos(static_cast<const char*>(buffer), size) ==
+ size;
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/copying_file_stream.h b/chromium/components/subresource_filter/core/common/copying_file_stream.h
new file mode 100644
index 00000000000..f8318163da4
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/copying_file_stream.h
@@ -0,0 +1,51 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_COPYING_FILE_STREAM_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_COPYING_FILE_STREAM_H_
+
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+namespace subresource_filter {
+
+// Implements a CopyingInputStream that reads from a base::File. Can be used in
+// combination with CopyingInputStreamAdaptor for reading from that file through
+// the ZeroCopyInputStream interface.
+class CopyingFileInputStream : public google::protobuf::io::CopyingInputStream {
+ public:
+ explicit CopyingFileInputStream(base::File file);
+ ~CopyingFileInputStream() override;
+
+ // google::protobuf::io::CopyingInputStream:
+ int Read(void* buffer, int size) override;
+
+ private:
+ base::File file_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopyingFileInputStream);
+};
+
+// Implements a CopyingOutputStream that writes to a base::File. Can be used in
+// combination with CopyingOutputStreamAdaptor for writing to that file through
+// the ZeroCopyOutputStream interface.
+class CopyingFileOutputStream
+ : public google::protobuf::io::CopyingOutputStream {
+ public:
+ explicit CopyingFileOutputStream(base::File file);
+ ~CopyingFileOutputStream() override;
+
+ // google::protobuf::io::CopyingOutputStream:
+ bool Write(const void* buffer, int size) override;
+
+ private:
+ base::File file_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopyingFileOutputStream);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_COPYING_FILE_STREAM_H_
diff --git a/chromium/components/subresource_filter/core/common/flat/BUILD.gn b/chromium/components/subresource_filter/core/common/flat/BUILD.gn
new file mode 100644
index 00000000000..195c0cd11e0
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/flat/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/flatbuffers/flatbuffer.gni")
+
+flatbuffer("flatbuffer") {
+ sources = [
+ "rules.fbs",
+ ]
+}
diff --git a/chromium/components/subresource_filter/core/common/flat/rules.fbs b/chromium/components/subresource_filter/core/common/flat/rules.fbs
new file mode 100644
index 00000000000..c75502838e4
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/flat/rules.fbs
@@ -0,0 +1,117 @@
+namespace subresource_filter.flat;
+
+// Corresponds to subresource_filter::proto::UrlPatternType.
+enum UrlPatternType : ubyte {
+ SUBSTRING,
+ WILDCARDED,
+ REGEXP,
+}
+
+// Corresponds to subresource_filter::proto::AnchorType.
+enum AnchorType : ubyte {
+ NONE,
+ BOUNDARY,
+ SUBDOMAIN,
+}
+
+// URL rule matching options. These correspond to multiple fields of
+// subresource_filter::proto::UrlRule, but here, they are represented as flags
+// of the same bitmask to allow for compact storage.
+enum OptionFlag : ubyte (bit_flags) {
+ IS_WHITELIST,
+ APPLIES_TO_FIRST_PARTY,
+ APPLIES_TO_THIRD_PARTY,
+ IS_MATCH_CASE,
+}
+
+// The flat representation of a single URL rule. For more details regarding the
+// fields please see the comments to subresource_filter::proto::UrlRule.
+table UrlRule {
+ // Rule matching options, a bitmask consisting of OptionFlags.
+ options : ubyte;
+
+ // A bitmask of element types, same as proto::UrlRule::element_types. Enables
+ // all element types except POPUP by default.
+ element_types : ushort = 2047;
+
+ // A bitmask of activation types, same as proto::UrlRule::activation_types.
+ // Disables all activation types by default.
+ activation_types : ubyte = 0;
+
+ // Use SUBSTRING as default, since it's the most used pattern type. Same as
+ // the corresponding proto::UrlRule::url_pattern_type.
+ url_pattern_type : UrlPatternType = SUBSTRING;
+
+ // Use NONE as default, since most of the rules are not anchored.
+ anchor_left : AnchorType = NONE;
+ anchor_right : AnchorType = NONE;
+
+ // The list of domains to be included/excluded from the filter's affected set.
+ // If a particular string in the list starts with '~' then the respective
+ // domain is excluded, otherwise included.
+ domains : [string];
+
+ // A URL pattern in the format defined by |url_pattern_type|.
+ url_pattern : string;
+
+ // The compound Knuth-Morris-Pratt failure function corresponding to
+ // |url_pattern|. Used for SUBSTRING and WILDCARDED URL patterns only.
+ //
+ // The |url_pattern| is split into subpatterns separated by a '*' wildcard.
+ // Then for each subpattern a failure function of the KMP algorithm is built,
+ // with the caveat that if some subpattern contains at least one '^'
+ // placeholder, all the separator characters in this subpattern are
+ // considered equivalent, and the failure function subarray is prefixed with
+ // the value 1.
+ //
+ // The failure functions of subpatterns are stored sequentially in the
+ // |failure_function| array. Some subpatterns, however, will not have a
+ // corresponding failure function, e.g. the first subpattern if the rule's
+ // |anchor_left| is BOUNDARY.
+ failure_function : [ubyte];
+}
+
+// Contains an N-gram (acting as a key in a hash table) and a list of URL rules
+// associated with that N-gram.
+table NGramToRules {
+ // A string consisting of N (up to 8) non-special characters, which are stored
+ // in the lowest N non-zero bytes, lower bytes corresponding to later symbols.
+ ngram : ulong;
+
+ // The list of rules containing |ngram| as a substring of their URL pattern.
+ rule_list : [UrlRule];
+}
+
+// A data structure used to select only a handful of URL rule candidates that
+// need to be matched against a certain resource URL.
+table UrlPatternIndex {
+ // The N of an N-gram index. Note: |n| should be between 1 and 8.
+ n : uint;
+
+ // A hash table with open addressing. The keys of the table are N-grams.
+ ngram_index : [NGramToRules];
+
+ // The slot that is pointed to by all empty slots of |ngram_index| hash table.
+ // Note: This is a workaround needed because null offsets are not allowed as
+ // elements of FlatBuffer arrays.
+ ngram_index_empty_slot : NGramToRules;
+
+ // A list storing the rules that doesn't contain any valid N-grams in their
+ // URL patterns. Contains all the REGEXP rules as well.
+ // TODO(pkalinnikov): Think about better implementation for the fallback
+ // index. Possibly make it a hash map and maybe merge it with the N-gram
+ // index, since we can treat any sequence of characters shorter than N as an
+ // N-gram with zero bytes used for padding.
+ fallback_rules : [UrlRule];
+}
+
+// The top-level data structure used to store URL rules.
+table IndexedRuleset {
+ // The index of all blacklist URL rules.
+ blacklist_index : UrlPatternIndex;
+
+ // The index of all whitelist URL rules.
+ whitelist_index : UrlPatternIndex;
+}
+
+root_type IndexedRuleset;
diff --git a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.cc b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.cc
index a0f47bc73de..96b0f5cb787 100644
--- a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.cc
+++ b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.cc
@@ -24,37 +24,15 @@ bool StartsWithFuzzyImpl(base::StringPiece text, base::StringPiece subpattern) {
} // namespace
-void BuildFailureFunctionFuzzy(base::StringPiece subpattern,
- std::vector<size_t>* failure) {
- BuildFailureFunction<IsEqualOrBothSeparators>(subpattern, failure);
-}
-
bool StartsWithFuzzy(base::StringPiece text, base::StringPiece subpattern) {
- if (subpattern.size() <= text.size())
- return StartsWithFuzzyImpl(text, subpattern);
-
- return subpattern.size() == text.size() + 1 &&
- subpattern.back() == kSeparatorPlaceholder &&
- StartsWithFuzzyImpl(text, subpattern.substr(0, text.size()));
+ return subpattern.size() <= text.size() &&
+ StartsWithFuzzyImpl(text, subpattern);
}
bool EndsWithFuzzy(base::StringPiece text, base::StringPiece subpattern) {
- if (subpattern.size() > text.size() + 1)
- return false;
-
- if (subpattern.size() <= text.size() &&
- StartsWithFuzzyImpl(text.substr(text.size() - subpattern.size()),
- subpattern)) {
- return true;
- }
-
- DCHECK(!subpattern.empty());
- if (subpattern.back() != kSeparatorPlaceholder)
- return false;
- subpattern.remove_suffix(1);
- DCHECK_LE(subpattern.size(), text.size());
- return StartsWithFuzzy(text.substr(text.size() - subpattern.size()),
- subpattern);
+ return subpattern.size() <= text.size() &&
+ StartsWithFuzzyImpl(text.substr(text.size() - subpattern.size()),
+ subpattern);
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.h b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.h
index b9f7701a7c0..15e9fe79262 100644
--- a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.h
+++ b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching.h
@@ -5,9 +5,9 @@
// The separator placeholder '^' symbol is used in subpatterns to match any
// separator character, which is any ASCII symbol except letters, digits, and
// the following: '_', '-', '.', '%'. Note that the separator placeholder
-// character '^' is itself a separator, as well as '\0'. In addition, a
-// separator placeholder at the end of the pattern can be matched by the end of
-// |text|.
+// character '^' is itself a separator, as well as '\0'.
+// TODO(pkalinnikov): In addition, a separator placeholder at the end of the
+// pattern can be matched by the end of |text|.
//
// We define a fuzzy occurrence as an occurrence of a |subpattern| in |text|
// such that all its non-placeholder characters are equal to the corresponding
@@ -19,6 +19,7 @@
#include <stddef.h>
+#include <type_traits>
#include <vector>
#include "base/logging.h"
@@ -75,23 +76,33 @@ bool EndsWithFuzzy(base::StringPiece text, base::StringPiece subpattern);
// equality predicate transitive and symmetric which is needed for KMP. However,
// the separators will need to be checked in a second pass for KMP match
// candidates, which is implemented by AllOccurrencesFuzzy.
+template <typename FailureFunctionElement>
void BuildFailureFunctionFuzzy(base::StringPiece subpattern,
- std::vector<size_t>* failure);
+ std::vector<FailureFunctionElement>* failure) {
+ static_assert(std::is_unsigned<FailureFunctionElement>::value,
+ "The type is not unsigned.");
+ BuildFailureFunction<FailureFunctionElement, IsEqualOrBothSeparators>(
+ subpattern, failure);
+}
// Iterator range that yields all fuzzy occurrences of |subpattern| in |text|.
// The values in the range are the positions just beyond each occurrence.
+// Out-of-range iterators are dereferenced to base::StringPiece::npos.
//
// The |failure| array is the failure function created by
// BuildFailureFunctionFuzzy for the same |subpattern|, and containing at least
// subpattern.size() values.
-class AllOccurrencesFuzzy : private AllOccurrences<IsEqualOrBothSeparators> {
+template <typename IntType>
+class AllOccurrencesFuzzy
+ : private AllOccurrences<IntType, IsEqualOrBothSeparators> {
public:
- using Base = AllOccurrences<IsEqualOrBothSeparators>;
+ using Base = AllOccurrences<IntType, IsEqualOrBothSeparators>;
+ using BaseIterator = typename Base::Iterator;
- class Iterator : public Base::Iterator {
+ class Iterator : public BaseIterator {
public:
Iterator& operator++() {
- Base::Iterator::operator++();
+ BaseIterator::operator++();
AdvanceWhileFalsePositive();
return *this;
}
@@ -105,38 +116,38 @@ class AllOccurrencesFuzzy : private AllOccurrences<IsEqualOrBothSeparators> {
private:
friend class AllOccurrencesFuzzy;
- explicit Iterator(const Base::Iterator& base_iterator)
- : Base::Iterator(base_iterator) {
+ explicit Iterator(const BaseIterator& base_iterator)
+ : BaseIterator(base_iterator) {
AdvanceWhileFalsePositive();
}
const AllOccurrencesFuzzy& owner() const {
- return *static_cast<const AllOccurrencesFuzzy*>(owner_);
+ return *static_cast<const AllOccurrencesFuzzy*>(BaseIterator::owner_);
}
// Moves the iterator forward until it either reaches the end, or meets an
// occurrence exactly matching all non-placeholder separators.
void AdvanceWhileFalsePositive() {
- while (match_end_ != base::StringPiece::npos && !IsMatch())
- Base::Iterator::operator++();
+ while (BaseIterator::match_end_ != base::StringPiece::npos && !IsMatch())
+ BaseIterator::operator++();
}
// Returns whether the currenct match meets all separators.
bool IsMatch() const {
- DCHECK_LE(match_end_, owner().text_.size());
- DCHECK_GE(match_end_, owner().pattern_.size());
+ DCHECK_LE(BaseIterator::match_end_, owner().text_.size());
+ DCHECK_GE(BaseIterator::match_end_, owner().pattern_.size());
// TODO(pkalinnikov): Store a vector of separator positions externally and
// check if they are equal to the corresponding characters of the |text|.
- return StartsWithFuzzy(
- owner().text_.substr(match_end_ - owner().pattern_.size()),
- owner().pattern_);
+ return StartsWithFuzzy(owner().text_.substr(BaseIterator::match_end_ -
+ owner().pattern_.size()),
+ owner().pattern_);
}
};
AllOccurrencesFuzzy(base::StringPiece text,
base::StringPiece subpattern,
- const size_t* failure)
+ const IntType* failure)
: Base(text, subpattern, failure) {}
Iterator begin() const { return Iterator(Base::begin()); }
diff --git a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc
index 8c7a744ed8c..0dc78a50899 100644
--- a/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc
+++ b/chromium/components/subresource_filter/core/common/fuzzy_pattern_matching_unittest.cc
@@ -16,11 +16,12 @@ TEST(FuzzyPatternMatchingTest, StartsWithFuzzy) {
const char* subpattern;
bool expected_starts_with;
} kTestCases[] = {
- {"abc", "", true}, {"abc", "a", true}, {"abc", "ab", true},
- {"abc", "abc", true}, {"abc", "abcd", false}, {"abc", "abc^", true},
- {"abc", "abc^^", false}, {"abc", "abcd^", false}, {"abc", "ab^", false},
- {"abc", "bc", false}, {"abc", "bc^", false}, {"abc", "^abc", false},
+ {"abc", "", true}, {"abc", "a", true}, {"abc", "ab", true},
+ {"abc", "abc", true}, {"abc", "abcd", false}, {"abc", "abc^^", false},
+ {"abc", "abcd^", false}, {"abc", "ab^", false}, {"abc", "bc", false},
+ {"abc", "bc^", false}, {"abc", "^abc", false},
};
+ // TODO(pkalinnikov): Make end-of-string match '^' again.
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(testing::Message()
@@ -39,11 +40,12 @@ TEST(FuzzyPatternMatchingTest, EndsWithFuzzy) {
const char* subpattern;
bool expected_ends_with;
} kTestCases[] = {
- {"abc", "", true}, {"abc", "c", true}, {"abc", "bc", true},
- {"abc", "abc", true}, {"abc", "0abc", false}, {"abc", "abc^", true},
- {"abc", "abc^^", false}, {"abc", "abcd^", false}, {"abc", "ab^", false},
- {"abc", "ab", false}, {"abc", "bc^", true}, {"abc", "^abc", false},
+ {"abc", "", true}, {"abc", "c", true}, {"abc", "bc", true},
+ {"abc", "abc", true}, {"abc", "0abc", false}, {"abc", "abc^^", false},
+ {"abc", "abcd^", false}, {"abc", "ab^", false}, {"abc", "ab", false},
+ {"abc", "^abc", false},
};
+ // TODO(pkalinnikov): Make end-of-string match '^' again.
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(testing::Message()
@@ -93,7 +95,7 @@ TEST(FuzzyPatternMatchingTest, AllOccurrences) {
std::vector<size_t> failure;
BuildFailureFunctionFuzzy(test_case.subpattern, &failure);
- const auto& occurrences = AllOccurrencesFuzzy(
+ const auto& occurrences = AllOccurrencesFuzzy<size_t>(
test_case.text, test_case.subpattern, failure.data());
std::vector<size_t> matches(occurrences.begin(), occurrences.end());
EXPECT_EQ(test_case.expected_matches, matches);
diff --git a/chromium/components/subresource_filter/core/common/indexed_ruleset.cc b/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
new file mode 100644
index 00000000000..58985d85616
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
@@ -0,0 +1,511 @@
+// 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 "components/subresource_filter/core/common/indexed_ruleset.h"
+
+#include <algorithm>
+#include <limits>
+#include <string>
+
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "components/subresource_filter/core/common/ngram_extractor.h"
+#include "components/subresource_filter/core/common/url_pattern.h"
+#include "components/subresource_filter/core/common/url_pattern_matching.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h"
+
+namespace subresource_filter {
+
+namespace {
+
+// Checks whether a URL |rule| can be converted to its FlatBuffers equivalent,
+// and performs the actual conversion.
+class UrlRuleFlatBufferConverter {
+ public:
+ // Creates the converter, and initializes |is_convertible| bit. If
+ // |is_convertible| == true, then all the fields, needed for serializing the
+ // |rule| to FlatBuffer, are initialized (|options|, |anchor_right|, etc.).
+ UrlRuleFlatBufferConverter(const proto::UrlRule& rule) : rule_(rule) {
+ is_convertible_ = InitializeOptions() && InitializeElementTypes() &&
+ InitializeActivationTypes() && InitializeUrlPattern();
+ }
+
+ // Returns whether the |rule| can be converted to its FlatBuffers equivalent.
+ // The conversion is not possible if the rule has attributes not supported by
+ // this client version.
+ bool is_convertible() const { return is_convertible_; }
+
+ // Writes the URL |rule| to the FlatBuffer using the |builder|, and returns
+ // the offset to the serialized rule.
+ flatbuffers::Offset<flat::UrlRule> SerializeConvertedRule(
+ flatbuffers::FlatBufferBuilder* builder) const {
+ DCHECK(is_convertible());
+
+ flatbuffers::Offset<
+ flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>>
+ domains_offset;
+ if (rule_.domains_size()) {
+ std::vector<flatbuffers::Offset<flatbuffers::String>> domains;
+ domains.reserve(rule_.domains_size());
+
+ std::string domain;
+ for (const auto& domain_list_item : rule_.domains()) {
+ domain.clear();
+ domain.reserve(domain_list_item.domain().size() + 1);
+ if (domain_list_item.exclude())
+ domain += '~';
+ domain += domain_list_item.domain();
+ domains.push_back(builder->CreateString(domain));
+ }
+ domains_offset = builder->CreateVector(domains);
+ }
+
+ auto url_pattern_offset = builder->CreateString(rule_.url_pattern());
+
+ std::vector<uint8_t> failure_function;
+ BuildFailureFunction(UrlPattern(rule_), &failure_function);
+ auto failure_function_offset =
+ builder->CreateVector(failure_function.data(), failure_function.size());
+
+ return flat::CreateUrlRule(*builder, options_, element_types_,
+ activation_types_, url_pattern_type_,
+ anchor_left_, anchor_right_, domains_offset,
+ url_pattern_offset, failure_function_offset);
+ }
+
+ private:
+ static bool ConvertAnchorType(proto::AnchorType anchor_type,
+ flat::AnchorType* result) {
+ switch (anchor_type) {
+ case proto::ANCHOR_TYPE_NONE:
+ *result = flat::AnchorType_NONE;
+ break;
+ case proto::ANCHOR_TYPE_BOUNDARY:
+ *result = flat::AnchorType_BOUNDARY;
+ break;
+ case proto::ANCHOR_TYPE_SUBDOMAIN:
+ *result = flat::AnchorType_SUBDOMAIN;
+ break;
+ default:
+ return false; // Unsupported anchor type.
+ }
+ return true;
+ }
+
+ bool InitializeOptions() {
+ if (rule_.semantics() == proto::RULE_SEMANTICS_WHITELIST) {
+ options_ |= flat::OptionFlag_IS_WHITELIST;
+ } else if (rule_.semantics() != proto::RULE_SEMANTICS_BLACKLIST) {
+ return false; // Unsupported semantics.
+ }
+
+ switch (rule_.source_type()) {
+ case proto::SOURCE_TYPE_ANY:
+ options_ |= flat::OptionFlag_APPLIES_TO_THIRD_PARTY;
+ // Note: fall through here intentionally.
+ case proto::SOURCE_TYPE_FIRST_PARTY:
+ options_ |= flat::OptionFlag_APPLIES_TO_FIRST_PARTY;
+ break;
+ case proto::SOURCE_TYPE_THIRD_PARTY:
+ options_ |= flat::OptionFlag_APPLIES_TO_THIRD_PARTY;
+ break;
+
+ default:
+ return false; // Unsupported source type.
+ }
+
+ if (rule_.match_case())
+ options_ |= flat::OptionFlag_IS_MATCH_CASE;
+
+ return true;
+ }
+
+ bool InitializeElementTypes() {
+ static_assert(
+ proto::ELEMENT_TYPE_ALL <= std::numeric_limits<uint16_t>::max(),
+ "Element types can not be stored in uint16_t.");
+ if ((rule_.element_types() & proto::ELEMENT_TYPE_ALL) !=
+ rule_.element_types()) {
+ return false; // Unsupported element types.
+ }
+ element_types_ = static_cast<uint16_t>(rule_.element_types());
+ // Note: Normally we can not distinguish between the main plugin resource
+ // and any other loads it makes. We treat them both as OBJECT requests.
+ if (element_types_ & proto::ELEMENT_TYPE_OBJECT_SUBREQUEST)
+ element_types_ |= proto::ELEMENT_TYPE_OBJECT;
+ return true;
+ }
+
+ bool InitializeActivationTypes() {
+ static_assert(
+ proto::ACTIVATION_TYPE_ALL <= std::numeric_limits<uint8_t>::max(),
+ "Activation types can not be stored in uint8_t.");
+ if ((rule_.activation_types() & proto::ACTIVATION_TYPE_ALL) !=
+ rule_.activation_types()) {
+ return false; // Unsupported activation types.
+ }
+ activation_types_ = static_cast<uint8_t>(rule_.activation_types());
+ return true;
+ }
+
+ bool InitializeUrlPattern() {
+ if (rule_.url_pattern().size() >
+ static_cast<size_t>(std::numeric_limits<uint8_t>::max())) {
+ // Failure function can not always be stored as an array of uint8_t in
+ // case the pattern's length exceeds 255.
+ return false;
+ }
+
+ switch (rule_.url_pattern_type()) {
+ case proto::URL_PATTERN_TYPE_SUBSTRING:
+ url_pattern_type_ = flat::UrlPatternType_SUBSTRING;
+ break;
+ case proto::URL_PATTERN_TYPE_WILDCARDED:
+ url_pattern_type_ = flat::UrlPatternType_WILDCARDED;
+ break;
+ case proto::URL_PATTERN_TYPE_REGEXP:
+ url_pattern_type_ = flat::UrlPatternType_REGEXP;
+ break;
+
+ default:
+ return false; // Unsupported URL pattern type.
+ }
+
+ if (!ConvertAnchorType(rule_.anchor_left(), &anchor_left_) ||
+ !ConvertAnchorType(rule_.anchor_right(), &anchor_right_)) {
+ return false;
+ }
+ if (anchor_right_ == flat::AnchorType_SUBDOMAIN)
+ return false; // Unsupported right anchor.
+
+ return true;
+ }
+
+ const proto::UrlRule& rule_;
+
+ uint8_t options_ = 0;
+ uint16_t element_types_ = 0;
+ uint8_t activation_types_ = 0;
+ flat::UrlPatternType url_pattern_type_ = flat::UrlPatternType_WILDCARDED;
+ flat::AnchorType anchor_left_ = flat::AnchorType_NONE;
+ flat::AnchorType anchor_right_ = flat::AnchorType_NONE;
+
+ bool is_convertible_ = true;
+};
+
+} // namespace
+
+// RulesetIndexer --------------------------------------------------------------
+
+// static
+const int RulesetIndexer::kIndexedFormatVersion = 10;
+
+RulesetIndexer::MutableUrlPatternIndex::MutableUrlPatternIndex() = default;
+RulesetIndexer::MutableUrlPatternIndex::~MutableUrlPatternIndex() = default;
+
+RulesetIndexer::RulesetIndexer() = default;
+RulesetIndexer::~RulesetIndexer() = default;
+
+bool RulesetIndexer::AddUrlRule(const proto::UrlRule& rule) {
+ UrlRuleFlatBufferConverter converter(rule);
+ if (!converter.is_convertible())
+ return false;
+ auto rule_offset = converter.SerializeConvertedRule(&builder_);
+
+ MutableUrlPatternIndex* index_part =
+ (rule.semantics() == proto::RULE_SEMANTICS_BLACKLIST ? &blacklist_
+ : &whitelist_);
+
+ NGram ngram = 0;
+ if (rule.url_pattern_type() != proto::URL_PATTERN_TYPE_REGEXP) {
+ ngram =
+ GetMostDistinctiveNGram(index_part->ngram_index, rule.url_pattern());
+ }
+
+ if (ngram) {
+ index_part->ngram_index[ngram].push_back(rule_offset);
+ } else {
+ // TODO(pkalinnikov): Index fallback rules as well.
+ index_part->fallback_rules.push_back(rule_offset);
+ }
+
+ return true;
+}
+
+void RulesetIndexer::Finish() {
+ auto blacklist_offset = SerializeUrlPatternIndex(blacklist_);
+ auto whitelist_offset = SerializeUrlPatternIndex(whitelist_);
+
+ auto url_rules_index_offset =
+ flat::CreateIndexedRuleset(builder_, blacklist_offset, whitelist_offset);
+ builder_.Finish(url_rules_index_offset);
+}
+
+NGram RulesetIndexer::GetMostDistinctiveNGram(
+ const MutableNGramIndex& ngram_index,
+ base::StringPiece pattern) {
+ size_t min_list_size = std::numeric_limits<size_t>::max();
+ NGram best_ngram = 0;
+
+ auto ngrams = CreateNGramExtractor<kNGramSize, NGram>(
+ pattern, [](char c) { return c == '*' || c == '^'; });
+
+ for (uint64_t ngram : ngrams) {
+ const MutableUrlRuleList* rules = ngram_index.Get(ngram);
+ const size_t list_size = rules ? rules->size() : 0;
+ if (list_size < min_list_size) {
+ // TODO(pkalinnikov): Pick random of the same-sized lists.
+ min_list_size = list_size;
+ best_ngram = ngram;
+ if (list_size == 0)
+ break;
+ }
+ }
+
+ return best_ngram;
+}
+
+flatbuffers::Offset<flat::UrlPatternIndex>
+RulesetIndexer::SerializeUrlPatternIndex(const MutableUrlPatternIndex& index) {
+ const MutableNGramIndex& ngram_index = index.ngram_index;
+
+ std::vector<flatbuffers::Offset<flat::NGramToRules>> flat_hash_table(
+ ngram_index.table_size());
+
+ flatbuffers::Offset<flat::NGramToRules> empty_slot_offset =
+ flat::CreateNGramToRules(builder_);
+ for (size_t i = 0, size = ngram_index.table_size(); i != size; ++i) {
+ const uint32_t entry_index = ngram_index.hash_table()[i];
+ if (entry_index >= ngram_index.size()) {
+ flat_hash_table[i] = empty_slot_offset;
+ continue;
+ }
+ const MutableNGramIndex::EntryType& entry =
+ ngram_index.entries()[entry_index];
+ auto rules_offset = builder_.CreateVector(entry.second);
+ flat_hash_table[i] =
+ flat::CreateNGramToRules(builder_, entry.first, rules_offset);
+ }
+ auto ngram_index_offset = builder_.CreateVector(flat_hash_table);
+
+ auto fallback_rules_offset = builder_.CreateVector(index.fallback_rules);
+
+ return flat::CreateUrlPatternIndex(builder_, kNGramSize, ngram_index_offset,
+ empty_slot_offset, fallback_rules_offset);
+}
+
+// IndexedRulesetMatcher -------------------------------------------------------
+
+namespace {
+
+using FlatUrlRuleList = flatbuffers::Vector<flatbuffers::Offset<flat::UrlRule>>;
+using FlatNGramIndex =
+ flatbuffers::Vector<flatbuffers::Offset<flat::NGramToRules>>;
+
+// Returns whether the |origin| matches the list of |domains|. A match means
+// that the longest domain in |domains| that |origin| is a sub-domain of is not
+// an exception OR all the |domains| are exceptions and neither matches the
+// |origin|. Thus, domain filters with more domain components trump filters with
+// fewer domain components, i.e. the more specific a filter is, the higher the
+// priority.
+//
+// TODO(pkalinnikov): Make it fast.
+bool DoesInitiatorMatchDomainList(
+ const url::Origin& initiator,
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>&
+ domains) {
+ if (!domains.size())
+ return true;
+ // Unique |initiator| matches lists of exception domains only.
+ if (initiator.unique()) {
+ for (const flatbuffers::String* domain_filter : domains) {
+ DCHECK_GT(domain_filter->size(), 0u);
+ if (domain_filter->Get(0) != '~')
+ return false;
+ }
+ return true;
+ }
+
+ size_t max_domain_length = 0;
+ bool is_positive = true;
+ bool negatives_only = true;
+
+ for (flatbuffers::uoffset_t i = 0, size = domains.size(); i != size; ++i) {
+ const flatbuffers::String* domain_filter = domains.Get(i);
+ if (domain_filter->Length() <= max_domain_length)
+ continue;
+
+ base::StringPiece filter_piece(domain_filter->c_str(),
+ domain_filter->Length());
+ const bool is_negative = (domain_filter->Get(0) == '~');
+ if (is_negative) {
+ filter_piece.remove_prefix(1);
+ if (filter_piece.length() == max_domain_length)
+ continue;
+ } else {
+ negatives_only = false;
+ }
+
+ if (!initiator.DomainIs(filter_piece))
+ continue;
+ max_domain_length = filter_piece.length();
+ is_positive = !is_negative;
+ }
+
+ return max_domain_length ? is_positive : negatives_only;
+}
+
+// Returns whether |url| is a third party in respect to |first_party_origin|.
+bool IsThirdPartyUrl(const GURL& url, const url::Origin& first_party_origin) {
+ // TODO(pkalinnikov): Avoid converting Origin to GURL.
+ return first_party_origin.unique() ||
+ !net::registry_controlled_domains::SameDomainOrHost(
+ url, GURL(first_party_origin.Serialize()),
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+}
+
+// Returns true iff the request to |url| of type |element_type| requested by
+// |initiator| matches the |rule|'s metadata: resource type, first/third party,
+// domain list.
+bool DoesRuleMetadataMatch(const flat::UrlRule& rule,
+ const url::Origin& initiator,
+ proto::ElementType element_type,
+ proto::ActivationType activation_type,
+ bool is_third_party) {
+ if (element_type != proto::ELEMENT_TYPE_UNSPECIFIED &&
+ !(rule.element_types() & element_type)) {
+ return false;
+ }
+ if (activation_type != proto::ACTIVATION_TYPE_UNSPECIFIED &&
+ !(rule.activation_types() & activation_type)) {
+ return false;
+ }
+
+ if (is_third_party &&
+ !(rule.options() & flat::OptionFlag_APPLIES_TO_THIRD_PARTY)) {
+ return false;
+ }
+ if (!is_third_party &&
+ !(rule.options() & flat::OptionFlag_APPLIES_TO_FIRST_PARTY)) {
+ return false;
+ }
+
+ return !rule.domains() ||
+ DoesInitiatorMatchDomainList(initiator, *rule.domains());
+}
+
+bool MatchesAny(const FlatUrlRuleList* rules,
+ const GURL& url,
+ const url::Origin& initiator,
+ proto::ElementType element_type,
+ proto::ActivationType activation_type,
+ bool is_third_party) {
+ if (!rules)
+ return false;
+ for (const flat::UrlRule* rule : *rules) {
+ DCHECK_NE(rule, nullptr);
+
+ if (rule->url_pattern_type() != flat::UrlPatternType_REGEXP) {
+ const uint8_t* begin = rule->failure_function()->data();
+ const uint8_t* end = begin + rule->failure_function()->size();
+ if (!IsUrlPatternMatch(url, UrlPattern(*rule), begin, end))
+ continue;
+ } else {
+ // TODO(pkalinnikov): Implement REGEXP rules matching.
+ continue;
+ }
+
+ if (DoesRuleMetadataMatch(*rule, initiator, element_type, activation_type,
+ is_third_party)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace
+
+bool IndexedRulesetMatcher::Verify(const uint8_t* buffer, size_t size) {
+ const auto* indexed_ruleset = flat::GetIndexedRuleset(buffer);
+ flatbuffers::Verifier verifier(buffer, size);
+ return indexed_ruleset->Verify(verifier);
+}
+
+IndexedRulesetMatcher::IndexedRulesetMatcher(const uint8_t* buffer, size_t size)
+ : root_(flat::GetIndexedRuleset(buffer)) {
+ const flat::UrlPatternIndex* index = root_->blacklist_index();
+ DCHECK(!index || index->n() == kNGramSize);
+ index = root_->whitelist_index();
+ DCHECK(!index || index->n() == kNGramSize);
+}
+
+bool IndexedRulesetMatcher::ShouldDisableFilteringForDocument(
+ const GURL& document_url,
+ const url::Origin& parent_document_origin,
+ proto::ActivationType activation_type) const {
+ if (!document_url.is_valid() ||
+ activation_type == proto::ACTIVATION_TYPE_UNSPECIFIED) {
+ return false;
+ }
+ return IsMatch(root_->whitelist_index(), document_url, parent_document_origin,
+ proto::ELEMENT_TYPE_UNSPECIFIED, activation_type,
+ IsThirdPartyUrl(document_url, parent_document_origin));
+}
+
+bool IndexedRulesetMatcher::ShouldDisallowResourceLoad(
+ const GURL& url,
+ const url::Origin& document_origin,
+ proto::ElementType element_type) const {
+ if (!url.is_valid() || element_type == proto::ELEMENT_TYPE_UNSPECIFIED)
+ return false;
+ const bool is_third_party = IsThirdPartyUrl(url, document_origin);
+ return IsMatch(root_->blacklist_index(), url, document_origin, element_type,
+ proto::ACTIVATION_TYPE_UNSPECIFIED, is_third_party) &&
+ !IsMatch(root_->whitelist_index(), url, document_origin, element_type,
+ proto::ACTIVATION_TYPE_UNSPECIFIED, is_third_party);
+}
+
+bool IndexedRulesetMatcher::IsMatch(const flat::UrlPatternIndex* index,
+ const GURL& url,
+ const url::Origin& initiator,
+ proto::ElementType element_type,
+ proto::ActivationType activation_type,
+ bool is_third_party) {
+ if (!index)
+ return false;
+ const FlatNGramIndex* hash_table = index->ngram_index();
+ const flat::NGramToRules* empty_slot = index->ngram_index_empty_slot();
+ DCHECK_NE(hash_table, nullptr);
+
+ NGramHashTableProber prober;
+
+ auto ngrams = CreateNGramExtractor<kNGramSize, uint64_t>(
+ url.spec(), [](char) { return false; });
+ for (uint64_t ngram : ngrams) {
+ const size_t slot_index = prober.FindSlot(
+ ngram, base::strict_cast<size_t>(hash_table->size()),
+ [hash_table, empty_slot](NGram ngram, size_t slot_index) {
+ const flat::NGramToRules* entry = hash_table->Get(slot_index);
+ DCHECK_NE(entry, nullptr);
+ return entry == empty_slot || entry->ngram() == ngram;
+ });
+ DCHECK_LT(slot_index, hash_table->size());
+
+ const flat::NGramToRules* entry = hash_table->Get(slot_index);
+ if (entry == empty_slot)
+ continue;
+ if (MatchesAny(entry->rule_list(), url, initiator, element_type,
+ activation_type, is_third_party)) {
+ return true;
+ }
+ }
+
+ const FlatUrlRuleList* rules = index->fallback_rules();
+ return MatchesAny(rules, url, initiator, element_type, activation_type,
+ is_third_party);
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/indexed_ruleset.h b/chromium/components/subresource_filter/core/common/indexed_ruleset.h
new file mode 100644
index 00000000000..fd65b5cf359
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/indexed_ruleset.h
@@ -0,0 +1,150 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_INDEXED_RULESET_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_INDEXED_RULESET_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_piece.h"
+#include "components/subresource_filter/core/common/closed_hash_map.h"
+#include "components/subresource_filter/core/common/flat/rules_generated.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
+#include "components/subresource_filter/core/common/uint64_hasher.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace subresource_filter {
+
+// The integer type used to represent N-grams.
+using NGram = uint64_t;
+// The hasher used for hashing N-grams.
+using NGramHasher = Uint64Hasher;
+// The hash table probe sequence used both by the ruleset builder and matcher.
+using NGramHashTableProber = DefaultProber<NGram, NGramHasher>;
+
+constexpr size_t kNGramSize = 6;
+static_assert(kNGramSize <= sizeof(NGram), "NGram type is too narrow.");
+
+// The class used to construct flat data structures representing the set of URL
+// filtering rules, as well as the index of those. Internally owns a
+// FlatBufferBuilder storing the structures.
+class RulesetIndexer {
+ public:
+ // The current binary format version of the indexed ruleset.
+ static const int kIndexedFormatVersion;
+
+ RulesetIndexer();
+ ~RulesetIndexer();
+
+ // Adds |rule| to the ruleset and the index unless the |rule| has unsupported
+ // filter options, in which case the data structures remain unmodified.
+ // Returns whether the |rule| has been serialized and added to the index.
+ bool AddUrlRule(const proto::UrlRule& rule);
+
+ // Finalizes construction of the data structures.
+ void Finish();
+
+ // Returns a pointer to the buffer containing the serialized flat data
+ // structures. Should only be called after Finish().
+ const uint8_t* data() const { return builder_.GetBufferPointer(); }
+
+ // Returns the size of the buffer.
+ size_t size() const { return base::strict_cast<size_t>(builder_.GetSize()); }
+
+ private:
+ using MutableUrlRuleList = std::vector<flatbuffers::Offset<flat::UrlRule>>;
+ using MutableNGramIndex =
+ ClosedHashMap<NGram, MutableUrlRuleList, NGramHashTableProber>;
+
+ // Encapsulates a subset of the rules, and an index built on the URL patterns
+ // in these rules. The ruleset is divided into parts according to metadata of
+ // the rules. Currently there are two parts: blacklist and whitelist.
+ struct MutableUrlPatternIndex {
+ // This index contains all non-REGEXP rules that have at least one
+ // acceptable N-gram. For a single rule the N-gram used as an index key is
+ // picked greedily (see GetMostDistinctiveNGram).
+ MutableNGramIndex ngram_index;
+
+ // A fallback list that contains all the rules with no acceptable N-gram,
+ // and all the REGEXP rules.
+ MutableUrlRuleList fallback_rules;
+
+ MutableUrlPatternIndex();
+ ~MutableUrlPatternIndex();
+ };
+
+ // Returns an N-gram of the |pattern| encoded into the NGram integer type. The
+ // N-gram is picked using a greedy heuristic, i.e. the one is chosen which
+ // corresponds to the shortest list of rules within the |index|. If there are
+ // no valid N-grams in the |pattern|, the return value is 0.
+ static NGram GetMostDistinctiveNGram(const MutableNGramIndex& index,
+ base::StringPiece pattern);
+
+ // Serialized an |index| built over a part of the ruleset, and returns its
+ // offset in the FlatBuffer.
+ flatbuffers::Offset<flat::UrlPatternIndex> SerializeUrlPatternIndex(
+ const MutableUrlPatternIndex& index);
+
+ MutableUrlPatternIndex blacklist_;
+ MutableUrlPatternIndex whitelist_;
+
+ flatbuffers::FlatBufferBuilder builder_;
+
+ DISALLOW_COPY_AND_ASSIGN(RulesetIndexer);
+};
+
+// Matches URLs against the FlatBuffer representation of an indexed ruleset.
+class IndexedRulesetMatcher {
+ public:
+ // Returns whether the |buffer| of the given |size| contains a valid
+ // flat::IndexedRuleset FlatBuffer.
+ static bool Verify(const uint8_t* buffer, size_t size);
+
+ // Creates an instance that matches URLs against the flat::IndexedRuleset
+ // provided as the root object of serialized data in the |buffer| of the given
+ // |size|.
+ IndexedRulesetMatcher(const uint8_t* buffer, size_t size);
+
+ // Returns whether the subset of subresource filtering rules specified by the
+ // |activation_type| should be disabled for the |document| loaded from
+ // |parent_document_origin|. Always returns false if |activation_type| ==
+ // ACTIVATION_TYPE_UNSPECIFIED or the |document_url| is not valid. Unlike
+ // page-level activation, such rules can be used to have fine-grained control
+ // over the activation of filtering within (sub-)documents.
+ bool ShouldDisableFilteringForDocument(
+ const GURL& document_url,
+ const url::Origin& parent_document_origin,
+ proto::ActivationType activation_type) const;
+ // TODO(pkalinnikov): GetActivationTypesForDocument.
+
+ // Returns whether the network request to |url| of |element_type| initiated by
+ // |document_origin| is not allowed to proceed. Always returns false if the
+ // |url| is not valid or |element_type| == ELEMENT_TYPE_UNSPECIFIED.
+ bool ShouldDisallowResourceLoad(const GURL& url,
+ const url::Origin& document_origin,
+ proto::ElementType element_type) const;
+
+ private:
+ // Returns whether the network request matches a particular part of the index.
+ // |is_third_party| should reflect relation between |url| and |initiator|.
+ static bool IsMatch(const flat::UrlPatternIndex* index,
+ const GURL& url,
+ const url::Origin& initiator,
+ proto::ElementType element_type,
+ proto::ActivationType activation_type,
+ bool is_third_party);
+
+ const flat::IndexedRuleset* root_;
+
+ DISALLOW_COPY_AND_ASSIGN(IndexedRulesetMatcher);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_INDEXED_RULESET_H_
diff --git a/chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc b/chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
new file mode 100644
index 00000000000..1cd4a6c8902
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
@@ -0,0 +1,612 @@
+// 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 "components/subresource_filter/core/common/indexed_ruleset.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
+#include "components/subresource_filter/core/common/url_pattern.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+
+namespace {
+
+constexpr proto::AnchorType kAnchorNone = proto::ANCHOR_TYPE_NONE;
+constexpr proto::AnchorType kBoundary = proto::ANCHOR_TYPE_BOUNDARY;
+constexpr proto::AnchorType kSubdomain = proto::ANCHOR_TYPE_SUBDOMAIN;
+constexpr proto::UrlPatternType kSubstring = proto::URL_PATTERN_TYPE_SUBSTRING;
+
+constexpr proto::SourceType kAnyParty = proto::SOURCE_TYPE_ANY;
+constexpr proto::SourceType kFirstParty = proto::SOURCE_TYPE_FIRST_PARTY;
+constexpr proto::SourceType kThirdParty = proto::SOURCE_TYPE_THIRD_PARTY;
+
+// Note: Returns unique origin on origin_string == nullptr.
+url::Origin GetOrigin(const char* origin_string) {
+ return origin_string ? url::Origin(GURL(origin_string)) : url::Origin();
+}
+
+} // namespace
+
+class IndexedRulesetTest : public testing::Test {
+ public:
+ IndexedRulesetTest() = default;
+
+ protected:
+ bool ShouldAllow(
+ const char* url,
+ const char* initiator = nullptr,
+ proto::ElementType element_type = proto::ELEMENT_TYPE_OTHER) const {
+ DCHECK_NE(matcher_.get(), nullptr);
+ url::Origin origin = GetOrigin(initiator);
+ return !matcher_->ShouldDisallowResourceLoad(GURL(url), origin,
+ element_type);
+ }
+
+ bool ShouldDeactivate(const char* document_url,
+ const char* initiator = nullptr,
+ proto::ActivationType activation_type =
+ proto::ACTIVATION_TYPE_UNSPECIFIED) const {
+ DCHECK(matcher_);
+ url::Origin origin = GetOrigin(initiator);
+ return matcher_->ShouldDisableFilteringForDocument(GURL(document_url),
+ origin, activation_type);
+ }
+
+ proto::UrlRule CreateRule(const UrlPattern& url_pattern,
+ proto::SourceType source_type,
+ bool is_whitelist) {
+ proto::UrlRule rule;
+ rule.set_semantics(is_whitelist ? proto::RULE_SEMANTICS_WHITELIST
+ : proto::RULE_SEMANTICS_BLACKLIST);
+
+ rule.set_source_type(source_type);
+ rule.set_element_types(proto::ELEMENT_TYPE_ALL);
+
+ rule.set_url_pattern_type(url_pattern.type);
+ rule.set_anchor_left(url_pattern.anchor_left);
+ rule.set_anchor_right(url_pattern.anchor_right);
+ rule.set_match_case(url_pattern.match_case);
+ rule.set_url_pattern(url_pattern.url_pattern.as_string());
+ return rule;
+ }
+
+ void AddSimpleRule(const UrlPattern& url_pattern, bool is_whitelist) {
+ proto::UrlRule rule = CreateRule(url_pattern, kAnyParty, is_whitelist);
+ EXPECT_TRUE(indexer_.AddUrlRule(rule));
+ }
+
+ void AddBlacklistRule(const UrlPattern& url_pattern,
+ proto::SourceType source_type = kAnyParty) {
+ indexer_.AddUrlRule(CreateRule(url_pattern, source_type, false));
+ }
+
+ void AddBlacklistRuleWithElementTypes(const UrlPattern& url_pattern,
+ int32_t element_types) {
+ proto::UrlRule rule = CreateRule(url_pattern, kAnyParty, false);
+ rule.set_element_types(element_types);
+ EXPECT_TRUE(indexer_.AddUrlRule(rule));
+ }
+
+ void AddWhitelistRuleWithActivationTypes(const UrlPattern& url_pattern,
+ int32_t activation_types) {
+ proto::UrlRule rule = CreateRule(url_pattern, kAnyParty, true);
+ rule.set_element_types(proto::ELEMENT_TYPE_UNSPECIFIED);
+ rule.set_activation_types(activation_types);
+ EXPECT_TRUE(indexer_.AddUrlRule(rule));
+ }
+
+ void AddBlacklistRule(const UrlPattern& url_pattern,
+ const std::vector<std::string>& domains) {
+ proto::UrlRule rule = CreateRule(url_pattern, kAnyParty, false);
+
+ for (std::string domain_pattern : domains) {
+ auto* domain = rule.add_domains();
+ if (domain_pattern[0] == '~') {
+ domain_pattern.erase(0, 1);
+ domain->set_exclude(true);
+ }
+ domain->set_domain(domain_pattern);
+ }
+ EXPECT_TRUE(indexer_.AddUrlRule(rule));
+ }
+
+ void Finish() {
+ indexer_.Finish();
+ matcher_.reset(new IndexedRulesetMatcher(indexer_.data(), indexer_.size()));
+ }
+
+ void Reset() {
+ matcher_.reset(nullptr);
+ indexer_.~RulesetIndexer();
+ new (&indexer_) RulesetIndexer();
+ }
+
+ RulesetIndexer indexer_;
+ std::unique_ptr<IndexedRulesetMatcher> matcher_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexedRulesetTest);
+};
+
+TEST_F(IndexedRulesetTest, OneRuleWithoutMetaInfo) {
+ const struct {
+ UrlPattern url_pattern;
+ const char* url;
+ bool expect_allowed;
+ } kTestCases[] = {
+ // SUBSTRING
+ {{"abcd", kSubstring}, "http://example.com/abcd", false},
+ {{"abcd", kSubstring}, "http://example.com/dcab", true},
+ {{"42", kSubstring}, "http://example.com/adcd/picture42.png", false},
+ {{"&test", kSubstring},
+ "http://example.com/params?para1=false&test=true",
+ false},
+ {{"-test-42.", kSubstring}, "http://example.com/unit-test-42.1", false},
+ {{"/abcdtest160x600.", kSubstring},
+ "http://example.com/abcdtest160x600.png",
+ false},
+
+ // WILDCARDED
+ {{"http://example.com/abcd/picture*.png"},
+ "http://example.com/abcd/picture42.png",
+ false},
+ {{"example.com", kSubdomain, kAnchorNone}, "http://example.com", false},
+ {{"example.com", kSubdomain, kAnchorNone},
+ "http://test.example.com",
+ false},
+ {{"example.com", kSubdomain, kAnchorNone},
+ "https://test.example.com.com",
+ false},
+ {{"example.com", kSubdomain, kAnchorNone},
+ "https://test.rest.example.com",
+ false},
+ {{"example.com", kSubdomain, kAnchorNone},
+ "https://test_example.com",
+ true},
+
+ {{"http://example.com", kBoundary, kAnchorNone},
+ "http://example.com/",
+ false},
+ {{"http://example.com", kBoundary, kAnchorNone},
+ "http://example.com/42",
+ false},
+ {{"http://example.com", kBoundary, kAnchorNone},
+ "http://example.com/42/http://example.com/",
+ false},
+ {{"http://example.com", kBoundary, kAnchorNone},
+ "http://example.com/42/http://example.info/",
+ false},
+ {{"http://example.com/", kBoundary, kBoundary},
+ "http://example.com",
+ false},
+ {{"http://example.com/", kBoundary, kBoundary},
+ "http://example.com/42",
+ true},
+ {{"http://example.com/", kBoundary, kBoundary},
+ "http://example.info/42/http://example.com/",
+ true},
+ {{"http://example.com/", kBoundary, kBoundary},
+ "http://example.info/42/http://example.com/",
+ true},
+ {{"http://example.com/", kBoundary, kBoundary},
+ "http://example.com/",
+ false},
+ {{"http://example.com/", kBoundary, kBoundary},
+ "http://example.com/42.swf",
+ true},
+ {{"http://example.com/", kBoundary, kBoundary},
+ "http://example.info/redirect/http://example.com/",
+ true},
+ {{"pdf", kAnchorNone, kBoundary}, "http://example.com/abcd.pdf", false},
+ {{"pdf", kAnchorNone, kBoundary}, "http://example.com/pdfium", true},
+ {{"http://example.com^"}, "http://example.com/", false},
+ {{"http://example.com^"}, "http://example.com:8000/", false},
+ {{"http://example.com^"}, "http://example.com.ru", true},
+ {{"^example.com^"},
+ "http://example.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82",
+ false},
+ {{"^42.loss^"},
+ "http://example.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82",
+ false},
+
+ // FIXME(pkalinnikov): The '^' at the end should match end-of-string.
+ // {"^%D1%82%D0%B5%D1%81%D1%82^",
+ // "http://example.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82",
+ // false},
+ // {"/abcd/*/picture^", "http://example.com/abcd/42/picture", false},
+
+ {{"/abcd/*/picture^"},
+ "http://example.com/abcd/42/loss/picture?param",
+ false},
+ {{"/abcd/*/picture^"}, "http://example.com/abcd//picture/42", false},
+ {{"/abcd/*/picture^"}, "http://example.com/abcd/picture", true},
+ {{"/abcd/*/picture^"}, "http://example.com/abcd/42/pictureraph", true},
+ {{"/abcd/*/picture^"}, "http://example.com/abcd/42/picture.swf", true},
+ {{"test.example.com^", kSubdomain, kAnchorNone},
+ "http://test.example.com/42.swf",
+ false},
+ {{"test.example.com^", kSubdomain, kAnchorNone},
+ "http://server1.test.example.com/42.swf",
+ false},
+ {{"test.example.com^", kSubdomain, kAnchorNone},
+ "https://test.example.com:8000/",
+ false},
+ {{"test.example.com^", kSubdomain, kAnchorNone},
+ "http://test.example.com.ua/42.swf",
+ true},
+ {{"test.example.com^", kSubdomain, kAnchorNone},
+ "http://example.com/redirect/http://test.example.com/",
+ true},
+
+ {{"/abcd/*"}, "https://example.com/abcd/", false},
+ {{"/abcd/*"}, "http://example.com/abcd/picture.jpeg", false},
+ {{"/abcd/*"}, "https://example.com/abcd", true},
+ {{"/abcd/*"}, "http://abcd.example.com", true},
+ {{"*/abcd/"}, "https://example.com/abcd/", false},
+ {{"*/abcd/"}, "http://example.com/abcd/picture.jpeg", false},
+ {{"*/abcd/"}, "https://example.com/test-abcd/", true},
+ {{"*/abcd/"}, "http://abcd.example.com", true},
+
+ // FIXME(pkalinnikov): Implement REGEXP matching.
+ // REGEXP
+ // {"/test|rest\\d+/", "http://example.com/test42", false},
+ // {"/test|rest\\d+/", "http://example.com/test", false},
+ // {"/test|rest\\d+/", "http://example.com/rest42", false},
+ // {"/test|rest\\d+/", "http://example.com/rest", true},
+ // {"/example\\.com/.*\\/[a-zA-Z0-9]{3}/", "http://example.com/abcd/42y",
+ // false},
+ // {"/example\\.com/.*\\/[a-zA-Z0-9]{3}/", "http://example.com/abcd/%42y",
+ // true},
+ // {"||example.com^*/test.htm", "http://example.com/unit/test.html",
+ // false},
+ // {"||example.com^*/test.htm", "http://examole.com/test.htm", true},
+ };
+
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "Rule: " << test_case.url_pattern.url_pattern
+ << "; URL: " << test_case.url);
+
+ AddBlacklistRule(test_case.url_pattern);
+ Finish();
+
+ EXPECT_EQ(test_case.expect_allowed, ShouldAllow(test_case.url));
+ Reset();
+ }
+}
+
+TEST_F(IndexedRulesetTest, OneRuleWithThirdParty) {
+ const struct {
+ const char* url_pattern;
+ proto::SourceType source_type;
+
+ const char* url;
+ const char* initiator;
+ bool expect_allowed;
+ } kTestCases[] = {
+ {"example.com", kThirdParty, "http://example.com", "http://exmpl.org",
+ false},
+ {"example.com", kThirdParty, "http://example.com", "http://example.com",
+ true},
+ {"example.com", kThirdParty, "http://example.com/path?k=v",
+ "http://exmpl.org", false},
+ {"example.com", kThirdParty, "http://example.com/path?k=v",
+ "http://example.com", true},
+ {"example.com", kFirstParty, "http://example.com/path?k=v",
+ "http://example.com", false},
+ {"example.com", kFirstParty, "http://example.com/path?k=v",
+ "http://exmpl.com", true},
+ {"example.com", kAnyParty, "http://example.com/path?k=v",
+ "http://example.com", false},
+ {"example.com", kAnyParty, "http://example.com/path?k=v",
+ "http://exmpl.com", false},
+ {"example.com", kThirdParty, "http://subdomain.example.com",
+ "http://example.com", true},
+ {"example.com", kThirdParty, "http://example.com", nullptr, false},
+
+ // Public Suffix List tests.
+ {"example.com", kThirdParty, "http://two.example.com",
+ "http://one.example.com", true},
+ {"example.com", kThirdParty, "http://example.com",
+ "http://one.example.com", true},
+ {"example.com", kThirdParty, "http://two.example.com",
+ "http://example.com", true},
+ {"example.com", kThirdParty, "http://example.com", "http://example.org",
+ false},
+ {"appspot.com", kThirdParty, "http://two.appspot.org",
+ "http://one.appspot.com", true},
+ };
+
+ for (auto test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "Rule: " << test_case.url_pattern << "; source: "
+ << (int)test_case.source_type << "; URL: " << test_case.url
+ << "; Initiator: " << test_case.initiator);
+
+ AddBlacklistRule(UrlPattern(test_case.url_pattern, kSubstring),
+ test_case.source_type);
+ Finish();
+
+ EXPECT_EQ(test_case.expect_allowed,
+ ShouldAllow(test_case.url, test_case.initiator));
+ Reset();
+ }
+}
+
+TEST_F(IndexedRulesetTest, OneRuleWithDomainList) {
+ const struct {
+ const char* url_pattern;
+ std::vector<std::string> domains;
+
+ const char* url;
+ const char* initiator;
+ bool expect_allowed;
+ } kTestCases[] = {
+ {"example.com",
+ {"domain1.com", "domain2.com"},
+ "http://example.com",
+ "http://domain1.com",
+ false},
+
+ {"example.com",
+ {"domain1.com", "domain2.com"},
+ "http://example.com",
+ "http://not_domain1.com",
+ true},
+
+ {"example.com",
+ {"domain1.com", "domain2.com"},
+ "http://example.com",
+ "http://domain2.com",
+ false},
+
+ {"example.com",
+ {"domain1.com", "domain2.com"},
+ "http://example.com",
+ "http://subdomain.domain2.com",
+ false},
+
+ {"example.com",
+ {"domain1.com", "domain2.com"},
+ "http://example.com",
+ "http://domain3.com",
+ true},
+
+ {"example.com",
+ {"~domain1.com", "~domain2.com"},
+ "http://example.com",
+ "http://domain2.com",
+ true},
+
+ {"example.com",
+ {"~domain1.com", "~domain2.com"},
+ "http://example.com",
+ "http://domain3.com",
+ false},
+
+ {"example.com",
+ {"domain1.com", "~subdomain1.domain1.com"},
+ "http://example.com",
+ "http://subdomain2.domain1.com",
+ false},
+
+ {"example.com",
+ {"domain1.com", "~subdomain1.domain1.com"},
+ "http://example.com",
+ "http://subdomain1.domain1.com",
+ true},
+
+ {"example.com",
+ {"domain1.com", "domain2.com"},
+ "http://example.com",
+ nullptr,
+ true},
+
+ // The following test addresses a former bug in domain list matcher. When
+ // "domain.com" was matched, the positive filters lookup stopped, and the
+ // next domain was considered as a negative. The initial character was
+ // skipped (supposing it's a '~') and the remainder was considered a
+ // domain. So "ddomain.com" would be matched and thus the whole rule would
+ // be classified as non-matching, which is not correct.
+ {"ex.com",
+ {"domain.com", "ddomain.com", "~sub.domain.com"},
+ "http://ex.com",
+ "http://domain.com",
+ false},
+ };
+
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message() << "Rule: " << test_case.url_pattern
+ << "; URL: " << test_case.url
+ << "; Initiator: " << test_case.initiator);
+
+ AddBlacklistRule(UrlPattern(test_case.url_pattern, kSubstring),
+ test_case.domains);
+ Finish();
+
+ EXPECT_EQ(test_case.expect_allowed,
+ ShouldAllow(test_case.url, test_case.initiator));
+ Reset();
+ }
+}
+
+TEST_F(IndexedRulesetTest, OneRuleWithElementTypes) {
+ constexpr proto::ElementType kAll = proto::ELEMENT_TYPE_ALL;
+ constexpr proto::ElementType kImage = proto::ELEMENT_TYPE_IMAGE;
+ constexpr proto::ElementType kFont = proto::ELEMENT_TYPE_FONT;
+ constexpr proto::ElementType kScript = proto::ELEMENT_TYPE_SCRIPT;
+ constexpr proto::ElementType kSubdoc = proto::ELEMENT_TYPE_SUBDOCUMENT;
+ constexpr proto::ElementType kPopup = proto::ELEMENT_TYPE_POPUP;
+
+ const struct {
+ const char* url_pattern;
+ int32_t element_types;
+
+ const char* url;
+ proto::ElementType element_type;
+ bool expect_allowed;
+ } kTestCases[] = {
+ {"ex.com", kAll, "http://ex.com/img.jpg", kImage, false},
+ {"ex.com", kAll & ~kPopup, "http://ex.com/img", kPopup, true},
+
+ {"ex.com", kImage, "http://ex.com/img.jpg", kImage, false},
+ {"ex.com", kAll & ~kImage, "http://ex.com/img.jpg", kImage, true},
+ {"ex.com", kScript, "http://ex.com/img.jpg", kImage, true},
+ {"ex.com", kAll & ~kScript, "http://ex.com/img.jpg", kImage, false},
+
+ {"ex.com", kImage | kFont, "http://ex.com/font", kFont, false},
+ {"ex.com", kImage | kFont, "http://ex.com/image", kImage, false},
+ {"ex.com", kImage | kFont, "http://ex.com/video",
+ proto::ELEMENT_TYPE_MEDIA, true},
+ {"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/font", kFont, true},
+ {"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/scr", kScript, true},
+ {"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/img", kImage, false},
+ {"ex.com$subdocument,~subdocument", kSubdoc & ~kSubdoc,
+ "http://ex.com/sub", kSubdoc, true},
+
+ {"ex.com", kAll, "http://ex.com", proto::ELEMENT_TYPE_OTHER, false},
+ {"ex.com", kAll, "http://ex.com", proto::ELEMENT_TYPE_UNSPECIFIED, true},
+ };
+
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "Rule: " << test_case.url_pattern << "; ElementTypes: "
+ << (int)test_case.element_types << "; URL: " << test_case.url
+ << "; ElementType: " << (int)test_case.element_type);
+
+ AddBlacklistRuleWithElementTypes(
+ UrlPattern(test_case.url_pattern, kSubstring), test_case.element_types);
+ Finish();
+
+ EXPECT_EQ(test_case.expect_allowed,
+ ShouldAllow(test_case.url, nullptr /* initiator */,
+ test_case.element_type));
+ Reset();
+ }
+}
+
+TEST_F(IndexedRulesetTest, OneRuleWithActivationTypes) {
+ constexpr proto::ActivationType kNone = proto::ACTIVATION_TYPE_UNSPECIFIED;
+ constexpr proto::ActivationType kDocument = proto::ACTIVATION_TYPE_DOCUMENT;
+
+ const struct {
+ const char* url_pattern;
+ int32_t activation_types;
+
+ const char* document_url;
+ proto::ActivationType activation_type;
+ bool expect_disabled;
+ } kTestCases[] = {
+ {"example.com", kDocument, "http://example.com", kDocument, true},
+ {"xample.com", kDocument, "http://example.com", kDocument, true},
+ {"exampl.com", kDocument, "http://example.com", kDocument, false},
+
+ {"example.com", kNone, "http://example.com", kDocument, false},
+ {"example.com", kDocument, "http://example.com", kNone, false},
+ {"example.com", kNone, "http://example.com", kNone, false},
+
+ // Invalid GURL.
+ {"example.com", kDocument, "http;//example.com", kDocument, false},
+ };
+
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "Rule: " << test_case.url_pattern
+ << "; ActivationTypes: " << (int)test_case.activation_types
+ << "; DocURL: " << test_case.document_url
+ << "; ActivationType: " << (int)test_case.activation_type);
+
+ AddWhitelistRuleWithActivationTypes(
+ UrlPattern(test_case.url_pattern, kSubstring),
+ test_case.activation_types);
+ Finish();
+
+ EXPECT_EQ(test_case.expect_disabled,
+ ShouldDeactivate(test_case.document_url, nullptr /* initiator */,
+ test_case.activation_type));
+ EXPECT_EQ(test_case.expect_disabled,
+ ShouldDeactivate(test_case.document_url, "http://example.com/",
+ test_case.activation_type));
+ EXPECT_EQ(test_case.expect_disabled,
+ ShouldDeactivate(test_case.document_url, "http://xmpl.com/",
+ test_case.activation_type));
+ Reset();
+ }
+}
+
+TEST_F(IndexedRulesetTest, EmptyRuleset) {
+ Finish();
+ EXPECT_TRUE(ShouldAllow("http://example.com"));
+ EXPECT_TRUE(ShouldAllow("http://another.example.com?param=val"));
+ EXPECT_TRUE(ShouldAllow(nullptr));
+}
+
+TEST_F(IndexedRulesetTest, NoRuleApplies) {
+ AddSimpleRule(UrlPattern("?filtered_content=", kSubstring), false);
+ AddSimpleRule(UrlPattern("&filtered_content=", kSubstring), false);
+ Finish();
+
+ EXPECT_TRUE(ShouldAllow("http://example.com"));
+ EXPECT_TRUE(ShouldAllow("http://example.com?filtered_not"));
+}
+
+TEST_F(IndexedRulesetTest, SimpleBlacklist) {
+ AddSimpleRule(UrlPattern("?param=", kSubstring), false);
+ Finish();
+
+ EXPECT_TRUE(ShouldAllow("https://example.com"));
+ EXPECT_FALSE(ShouldAllow("http://example.org?param=image1"));
+}
+
+TEST_F(IndexedRulesetTest, SimpleWhitelist) {
+ AddSimpleRule(UrlPattern("example.com/?filtered_content=", kSubstring), true);
+ Finish();
+
+ EXPECT_TRUE(ShouldAllow("https://example.com?filtered_content=image1"));
+}
+
+TEST_F(IndexedRulesetTest, BlacklistWhitelist) {
+ AddSimpleRule(UrlPattern("?filter=", kSubstring), false);
+ AddSimpleRule(UrlPattern("whitelisted.com/?filter=", kSubstring), true);
+ Finish();
+
+ EXPECT_TRUE(ShouldAllow("https://whitelisted.com?filter=off"));
+ EXPECT_TRUE(ShouldAllow("https://notblacklisted.com"));
+ EXPECT_FALSE(ShouldAllow("http://blacklisted.com?filter=on"));
+}
+
+TEST_F(IndexedRulesetTest, BlacklistAndActivationType) {
+ const auto kDocument = proto::ACTIVATION_TYPE_DOCUMENT;
+
+ AddSimpleRule(UrlPattern("example.com", kSubstring), false);
+ AddWhitelistRuleWithActivationTypes(UrlPattern("example.com", kSubstring),
+ kDocument);
+ Finish();
+
+ EXPECT_TRUE(ShouldDeactivate("https://example.com", nullptr, kDocument));
+ EXPECT_FALSE(ShouldDeactivate("https://xample.com", nullptr, kDocument));
+ EXPECT_FALSE(ShouldAllow("https://example.com"));
+ EXPECT_TRUE(ShouldAllow("https://xample.com"));
+}
+
+TEST_F(IndexedRulesetTest, RuleWithUnsupportedOptions) {
+ auto rule = CreateRule(UrlPattern("exmpl"), proto::SOURCE_TYPE_ANY, false);
+ rule.set_activation_types(rule.activation_types() |
+ (proto::ACTIVATION_TYPE_MAX << 1));
+ rule.set_element_types(rule.element_types() | (proto::ELEMENT_TYPE_MAX << 1));
+ EXPECT_FALSE(indexer_.AddUrlRule(rule));
+
+ AddSimpleRule(UrlPattern("example.com", kSubstring), false);
+ Finish();
+
+ EXPECT_TRUE(ShouldAllow("https://exmpl.com"));
+ EXPECT_FALSE(ShouldAllow("https://example.com"));
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/knuth_morris_pratt.h b/chromium/components/subresource_filter/core/common/knuth_morris_pratt.h
index 8e910e64009..29e50e7307b 100644
--- a/chromium/components/subresource_filter/core/common/knuth_morris_pratt.h
+++ b/chromium/components/subresource_filter/core/common/knuth_morris_pratt.h
@@ -24,8 +24,12 @@
#include <functional>
#include <iterator>
+#include <limits>
+#include <type_traits>
#include <vector>
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
#include "base/strings/string_piece.h"
namespace subresource_filter {
@@ -34,10 +38,13 @@ namespace subresource_filter {
// |pattern| at the end of the |failure| vector. The EquivalentTo should be a
// bool(char, char) functor returning true iff the two characters are
// equivalent, and is required to be reflexive, symmetric and transitive.
-template <typename EquivalentTo = std::equal_to<char>>
+template <typename IntType, typename EquivalentTo = std::equal_to<char>>
void BuildFailureFunction(base::StringPiece pattern,
- std::vector<size_t>* failure,
+ std::vector<IntType>* failure,
EquivalentTo equivalent_to = EquivalentTo()) {
+ static_assert(std::is_unsigned<IntType>::value, "IntType is not unsigned.");
+ DCHECK_LE(pattern.size(), std::numeric_limits<IntType>::max());
+
if (pattern.empty())
return;
@@ -46,7 +53,7 @@ void BuildFailureFunction(base::StringPiece pattern,
for (size_t i = 1; i != pattern.size(); ++i) {
const char c = pattern[i];
- size_t prefix_match_size = failure->back();
+ IntType prefix_match_size = failure->back();
DCHECK_LT(prefix_match_size, i);
while (prefix_match_size && !equivalent_to(pattern[prefix_match_size], c))
prefix_match_size = (*failure)[base_index + prefix_match_size - 1];
@@ -71,13 +78,16 @@ void BuildFailureFunction(base::StringPiece pattern,
// The |failure| array is the failure function created by BuildFailureFunction
// with the same EquivalentTo and |pattern|, and containing at least
// pattern.size() values.
-template <typename EquivalentTo = std::equal_to<char>>
+template <typename IntType, typename EquivalentTo = std::equal_to<char>>
size_t FindOccurrence(base::StringPiece text,
base::StringPiece pattern,
- const size_t* failure,
- size_t prefix_match_size,
+ const IntType* failure,
+ IntType prefix_match_size,
EquivalentTo equivalent_to = EquivalentTo()) {
+ static_assert(std::is_unsigned<IntType>::value, "IntType is not unsigned.");
DCHECK_LE(prefix_match_size, pattern.size());
+ DCHECK_LE(pattern.size(), std::numeric_limits<IntType>::max());
+
if (prefix_match_size == pattern.size())
return 0;
@@ -95,27 +105,28 @@ size_t FindOccurrence(base::StringPiece text,
// Same as FindOccurrence, but starts the search from scratch, i.e. with
// prefix_match_size == 0.
-template <typename EquivalentTo = std::equal_to<char>>
+template <typename IntType, typename EquivalentTo = std::equal_to<char>>
size_t FindFirstOccurrence(base::StringPiece text,
base::StringPiece pattern,
- const size_t* failure,
+ const IntType* failure,
EquivalentTo equivalent_to = EquivalentTo()) {
- return FindOccurrence(text, pattern, failure, 0, equivalent_to);
+ return FindOccurrence(text, pattern, failure, static_cast<IntType>(0),
+ equivalent_to);
}
// Same as FindOccurrence, but preforms the search assuming the |text| starts
// right after a full match of the |pattern|. The returned value is either
// base::StringPiece::npos if no more occurrences found, or is within the range
// [1, text.size()] if there are occurrences apart from the virtual prefix.
-template <typename EquivalentTo = std::equal_to<char>>
+template <typename IntType, typename EquivalentTo = std::equal_to<char>>
size_t FindNextOccurrence(base::StringPiece text,
base::StringPiece pattern,
- const size_t* failure,
+ const IntType* failure,
EquivalentTo equivalent_to = EquivalentTo()) {
if (pattern.empty())
return text.empty() ? base::StringPiece::npos : 1;
- const size_t prefix_match_size = failure[pattern.size() - 1];
+ const IntType prefix_match_size = failure[pattern.size() - 1];
return FindOccurrence(text, pattern, failure, prefix_match_size,
equivalent_to);
}
@@ -124,10 +135,13 @@ size_t FindNextOccurrence(base::StringPiece text,
// with respect to EquivalentTo relation between characters, and iterate over
// them using an input iterator. The values pointed to by an iterator indicate
// positions of occurrences, i.e. indices of |text| characters coming *after*
-// the occurrences.
-template <typename EquivalentTo = std::equal_to<char>>
+// the occurrences. Out-of-range iterators are dereferenced to
+// base::StringPiece::npos.
+template <typename IntType, typename EquivalentTo = std::equal_to<char>>
class AllOccurrences {
public:
+ static_assert(std::is_unsigned<IntType>::value, "IntType is not unsigned.");
+
class Iterator : public std::iterator<std::input_iterator_tag, size_t> {
public:
bool operator==(const Iterator& rhs) const {
@@ -173,7 +187,7 @@ class AllOccurrences {
AllOccurrences(base::StringPiece text,
base::StringPiece pattern,
- const size_t* failure,
+ const IntType* failure,
EquivalentTo equivalent_to = EquivalentTo())
: text_(text),
pattern_(pattern),
@@ -198,7 +212,7 @@ class AllOccurrences {
base::StringPiece text_;
base::StringPiece pattern_;
- const size_t* failure_;
+ const IntType* failure_;
EquivalentTo equivalent_to_;
};
@@ -220,13 +234,14 @@ class AllOccurrences {
// // text[|match_end|-pattern.size()..|match_end|-1]
// ... process the |match_end| ...
// }
-template <typename EquivalentTo = std::equal_to<char>>
-AllOccurrences<EquivalentTo> CreateAllOccurrences(
+template <typename IntType, typename EquivalentTo = std::equal_to<char>>
+AllOccurrences<IntType, EquivalentTo> CreateAllOccurrences(
base::StringPiece text,
base::StringPiece pattern,
- const size_t* failure,
+ const IntType* failure,
EquivalentTo equivalent_to = EquivalentTo()) {
- return AllOccurrences<EquivalentTo>(text, pattern, failure, equivalent_to);
+ return AllOccurrences<IntType, EquivalentTo>(text, pattern, failure,
+ equivalent_to);
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/proto/BUILD.gn b/chromium/components/subresource_filter/core/common/proto/BUILD.gn
new file mode 100644
index 00000000000..b0ccabe19c3
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/proto/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+ sources = [
+ "rules.proto",
+ ]
+}
diff --git a/chromium/components/subresource_filter/core/common/proto/rules.proto b/chromium/components/subresource_filter/core/common/proto/rules.proto
new file mode 100644
index 00000000000..f651c04abd2
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/proto/rules.proto
@@ -0,0 +1,194 @@
+// 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.
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package subresource_filter.proto;
+option java_package = "org.chromium.components.subresource_filter.proto";
+
+// The type of a subresource filtering rule.
+enum RuleType {
+ RULE_TYPE_UNSPECIFIED = 0;
+
+ RULE_TYPE_COMMENT = 1; // Comment rule.
+ RULE_TYPE_URL = 2; // Network level filtering rule based on URL pattern.
+ RULE_TYPE_CSS = 3; // Element hiding rule based on a CSS selector.
+};
+
+// The format of a URL pattern.
+enum UrlPatternType {
+ URL_PATTERN_TYPE_UNSPECIFIED = 0;
+
+ // A pattern without special characters, e.g. "example.com".
+ URL_PATTERN_TYPE_SUBSTRING = 1;
+
+ // The pattern contains one or more wildcards, namely '*' and/or '^'
+ // characters. The '*' matches any sequence of characters, while the '^'
+ // matches a separator, i.e. anything but a letter, a digit, or one of [-._%].
+ URL_PATTERN_TYPE_WILDCARDED = 2;
+
+ // The pattern is a regular expression.
+ URL_PATTERN_TYPE_REGEXP = 3;
+};
+
+// Types of anchors that can be used to constrain where a URL pattern must
+// begin/end in the URL in order to be considered a match.
+enum AnchorType {
+ ANCHOR_TYPE_UNSPECIFIED = 0;
+
+ // Acts like a '*' wildcard at the respective end of a pattern.
+ ANCHOR_TYPE_NONE = 1;
+ // The pattern must match from the start/until the end of the URL.
+ ANCHOR_TYPE_BOUNDARY = 2;
+ // The pattern must match starting with the TLD+n of the URL's domain, but the
+ // scheme and subdomains (if any) can be arbitrary.
+ ANCHOR_TYPE_SUBDOMAIN = 3;
+};
+
+// The types of subresource requests that a URL rule should be applied to.
+// Note: Values are used as flags in a bitmask.
+enum ElementType {
+ option allow_alias = true;
+ ELEMENT_TYPE_UNSPECIFIED = 0;
+
+ ELEMENT_TYPE_OTHER = 1;
+ ELEMENT_TYPE_SCRIPT = 2;
+ ELEMENT_TYPE_IMAGE = 4;
+ ELEMENT_TYPE_STYLESHEET = 8;
+ ELEMENT_TYPE_OBJECT = 16;
+ ELEMENT_TYPE_XMLHTTPREQUEST = 32;
+ ELEMENT_TYPE_OBJECT_SUBREQUEST = 64;
+ ELEMENT_TYPE_SUBDOCUMENT = 128;
+ ELEMENT_TYPE_PING = 256;
+ ELEMENT_TYPE_MEDIA = 512;
+ ELEMENT_TYPE_FONT = 1024;
+ ELEMENT_TYPE_POPUP = 2048;
+
+ // NOTE: Keep these two values consistent with the values above.
+ ELEMENT_TYPE_MAX = 2048;
+ ELEMENT_TYPE_ALL = 4095;
+};
+
+// The options controlling whether or not to activate filtering for subresources
+// of documents that match the URL pattern of the rule.
+// Note: Values are used as flags in a bitmask.
+enum ActivationType {
+ option allow_alias = true;
+ ACTIVATION_TYPE_UNSPECIFIED = 0;
+
+ ACTIVATION_TYPE_DOCUMENT = 1; // Disable all rules on the page.
+ ACTIVATION_TYPE_ELEMHIDE = 2; // Disable CSS rules on the page.
+ ACTIVATION_TYPE_GENERICHIDE = 4; // Disable generic CSS rules on the page.
+ ACTIVATION_TYPE_GENERICBLOCK = 8; // Disable generic URL rules on the page.
+
+ // NOTE: Keep these two values consistent with the values above.
+ ACTIVATION_TYPE_MAX = 8;
+ ACTIVATION_TYPE_ALL = 15;
+};
+
+// The semantics of a rule. Defines how the rule relates to other rules and how
+// it influences the filtering decision.
+enum RuleSemantics {
+ RULE_SEMANTICS_UNSPECIFIED = 0;
+
+ // Matching subresource requests should be aborted, matching elements should
+ // be hidden.
+ RULE_SEMANTICS_BLACKLIST = 1;
+ // If the rule matches, it suppresses any matching RULE_SEMANTICS_BLACKLIST
+ // rule.
+ RULE_SEMANTICS_WHITELIST = 2;
+}
+
+// The type of relation between the source of the requested subresource and that
+// of the document.
+enum SourceType {
+ SOURCE_TYPE_UNSPECIFIED = 0;
+
+ SOURCE_TYPE_ANY = 1; // Doesn't matter.
+ SOURCE_TYPE_THIRD_PARTY = 2; // Requesting a trird-party resource.
+ SOURCE_TYPE_FIRST_PARTY = 3; // Requesting a first-party resource.
+}
+
+// An item of the domain list.
+message DomainListItem {
+ // The UTF-8 representation of the domain, e.g. "subdomain.example.com".
+ optional string domain = 1;
+
+ // Defines whether the domain is excluded from the set of domains.
+ optional bool exclude = 2;
+}
+
+// A network level filtering rule based on a URL pattern. Corresponds to
+// RULE_TYPE_URL.
+message UrlRule {
+ // The semantics of the rule.
+ optional RuleSemantics semantics = 1;
+
+ // Restricts application of the rule to first-party/third-party requests.
+ optional SourceType source_type = 2;
+
+ // Stores the ElementTypes that the rule applies to as a bitwise OR of the
+ // corresponding ElementType values.
+ optional int32 element_types = 3;
+
+ // Stores the ActivationTypes associated with the rule as a bitwise OR of the
+ // corresponding ActivationType values.
+ optional int32 activation_types = 4;
+
+ // The rule applies only to subresources of documents loaded from included
+ // domains (or subdomains thereof). If the list is empty, the rule is applied
+ // on documents from all domains.
+ // If |domains| is empty or has exceptions only, the rule is called generic.
+ // Otherwise is it called domain specific, i.e. applies to a limited number of
+ // domains.
+ repeated DomainListItem domains = 5;
+
+ // The format of |url_pattern|.
+ optional UrlPatternType url_pattern_type = 6;
+
+ // Defines where the URL pattern must start in the URL in order to be
+ // considered a match. Never used with REGEXP patterns.
+ optional AnchorType anchor_left = 7;
+
+ // Defines where the URL pattern must end in the URL in order to be
+ // considered a match. Never used with REGEXP patterns. Never equals to
+ // ANCHOR_TYPE_SUBDOMAIN.
+ optional AnchorType anchor_right = 8;
+
+ // When set, the rule applies only to URLs that match |url_pattern| in a
+ // case-sensitive way.
+ optional bool match_case = 9;
+
+ // The URL pattern of the format prescribed by |url_pattern_type|.
+ optional string url_pattern = 10;
+}
+
+// Element hiding rule based on a CSS selector. Corresponds to RULE_TYPE_CSS.
+message CssRule {
+ // The semantics of the rule.
+ optional RuleSemantics semantics = 1;
+
+ // The list of domains, same as UrlRule::domains.
+ repeated DomainListItem domains = 2;
+
+ // A CSS selector as specified in http://www.w3.org/TR/css3-selectors.
+ optional string css_selector = 3;
+}
+
+// A comment line.
+message Comment {
+ // Comment text.
+ optional string text = 1;
+
+ // For special key-value comments, if any.
+ optional string key = 2;
+ optional string value = 3;
+}
+
+// A container for lists of non-comment rules collated by RuleType.
+message FilteringRules {
+ repeated UrlRule url_rules = 1;
+ repeated CssRule css_rules = 2;
+}
diff --git a/chromium/components/subresource_filter/core/common/string_splitter.h b/chromium/components/subresource_filter/core/common/string_splitter.h
index a3103346b21..f3b4e85b06b 100644
--- a/chromium/components/subresource_filter/core/common/string_splitter.h
+++ b/chromium/components/subresource_filter/core/common/string_splitter.h
@@ -29,8 +29,8 @@ class StringSplitter {
// |splitter|'s |text|, starting from |head|.
Iterator(const StringSplitter& splitter,
base::StringPiece::const_iterator head)
- : splitter_(splitter), current_(head, 0), end_(splitter.text_.end()) {
- DCHECK_GE(head, splitter_.text_.begin());
+ : splitter_(&splitter), current_(head, 0), end_(splitter.text_.end()) {
+ DCHECK_GE(head, splitter_->text_.begin());
DCHECK_LE(head, end_);
Advance();
@@ -59,15 +59,15 @@ class StringSplitter {
private:
void Advance() {
auto begin = current_.end();
- while (begin != end_ && splitter_.is_separator_(*begin))
+ while (begin != end_ && splitter_->is_separator_(*begin))
++begin;
auto end = begin;
- while (end != end_ && !splitter_.is_separator_(*end))
+ while (end != end_ && !splitter_->is_separator_(*end))
++end;
current_ = base::StringPiece(begin, end - begin);
}
- const StringSplitter& splitter_;
+ const StringSplitter* splitter_;
// Contains the token currently pointed to by the iterator.
base::StringPiece current_;
diff --git a/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc b/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc
new file mode 100644
index 00000000000..81dd7b3d211
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc
@@ -0,0 +1,128 @@
+// 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 "components/subresource_filter/core/common/test_ruleset_creator.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/subresource_filter/core/common/indexed_ruleset.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
+#include "components/subresource_filter/core/common/unindexed_ruleset.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+namespace subresource_filter {
+
+namespace {
+
+// The methods below assume that char and uint8_t are interchangeable.
+static_assert(CHAR_BIT == 8, "Assumed char was 8 bits.");
+
+proto::UrlRule CreateSuffixRule(base::StringPiece suffix) {
+ proto::UrlRule rule;
+ rule.set_semantics(proto::RULE_SEMANTICS_BLACKLIST);
+ rule.set_source_type(proto::SOURCE_TYPE_ANY);
+ rule.set_element_types(proto::ELEMENT_TYPE_ALL);
+ rule.set_url_pattern_type(proto::URL_PATTERN_TYPE_SUBSTRING);
+ rule.set_anchor_left(proto::ANCHOR_TYPE_NONE);
+ rule.set_anchor_right(proto::ANCHOR_TYPE_BOUNDARY);
+ rule.set_url_pattern(suffix.as_string());
+ return rule;
+}
+
+std::vector<uint8_t> SerializeUnindexedRulesetWithSingleRule(
+ const proto::UrlRule& rule) {
+ std::string ruleset_contents;
+ google::protobuf::io::StringOutputStream output(&ruleset_contents);
+ UnindexedRulesetWriter ruleset_writer(&output);
+ ruleset_writer.AddUrlRule(rule);
+ ruleset_writer.Finish();
+
+ auto data = reinterpret_cast<const uint8_t*>(ruleset_contents.data());
+ return std::vector<uint8_t>(data, data + ruleset_contents.size());
+}
+
+std::vector<uint8_t> SerializeIndexedRulesetWithSingleRule(
+ const proto::UrlRule& rule) {
+ RulesetIndexer indexer;
+ EXPECT_TRUE(indexer.AddUrlRule(rule));
+ indexer.Finish();
+ return std::vector<uint8_t>(indexer.data(), indexer.data() + indexer.size());
+}
+
+} // namespace
+
+namespace testing {
+
+// TestRuleset -----------------------------------------------------------------
+
+TestRuleset::TestRuleset() = default;
+TestRuleset::~TestRuleset() = default;
+
+// static
+base::File TestRuleset::Open(const TestRuleset& ruleset) {
+ base::File file;
+ file.Initialize(ruleset.path, base::File::FLAG_OPEN | base::File::FLAG_READ |
+ base::File::FLAG_SHARE_DELETE);
+ return file;
+}
+
+// TestRulesetPair -------------------------------------------------------------
+
+TestRulesetPair::TestRulesetPair() = default;
+TestRulesetPair::~TestRulesetPair() = default;
+
+// TestRulesetCreator ----------------------------------------------------------
+
+TestRulesetCreator::TestRulesetCreator() = default;
+TestRulesetCreator::~TestRulesetCreator() = default;
+
+void TestRulesetCreator::CreateRulesetToDisallowURLsWithPathSuffix(
+ base::StringPiece suffix,
+ TestRulesetPair* test_ruleset_pair) {
+ DCHECK(test_ruleset_pair);
+ proto::UrlRule suffix_rule = CreateSuffixRule(suffix);
+ ASSERT_NO_FATAL_FAILURE(CreateTestRulesetFromContents(
+ SerializeUnindexedRulesetWithSingleRule(suffix_rule),
+ &test_ruleset_pair->unindexed));
+ ASSERT_NO_FATAL_FAILURE(CreateTestRulesetFromContents(
+ SerializeIndexedRulesetWithSingleRule(suffix_rule),
+ &test_ruleset_pair->indexed));
+}
+
+void TestRulesetCreator::CreateUnindexedRulesetToDisallowURLsWithPathSuffix(
+ base::StringPiece suffix,
+ TestRuleset* test_unindexed_ruleset) {
+ DCHECK(test_unindexed_ruleset);
+ proto::UrlRule suffix_rule = CreateSuffixRule(suffix);
+ ASSERT_NO_FATAL_FAILURE(CreateTestRulesetFromContents(
+ SerializeUnindexedRulesetWithSingleRule(suffix_rule),
+ test_unindexed_ruleset));
+}
+
+void TestRulesetCreator::GetUniqueTemporaryPath(base::FilePath* path) {
+ DCHECK(path);
+ ASSERT_TRUE(scoped_temp_dir_.IsValid() ||
+ scoped_temp_dir_.CreateUniqueTempDir());
+ *path = scoped_temp_dir_.GetPath().AppendASCII(
+ base::IntToString(next_unique_file_suffix++));
+}
+
+void TestRulesetCreator::CreateTestRulesetFromContents(
+ std::vector<uint8_t> ruleset_contents,
+ TestRuleset* ruleset) {
+ DCHECK(ruleset);
+
+ ruleset->contents = std::move(ruleset_contents);
+ ASSERT_NO_FATAL_FAILURE(GetUniqueTemporaryPath(&ruleset->path));
+ int ruleset_size_as_int = base::checked_cast<int>(ruleset->contents.size());
+ int num_bytes_written = base::WriteFile(
+ ruleset->path, reinterpret_cast<const char*>(ruleset->contents.data()),
+ ruleset_size_as_int);
+ ASSERT_EQ(ruleset_size_as_int, num_bytes_written);
+}
+
+} // namespace testing
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/test_ruleset_creator.h b/chromium/components/subresource_filter/core/common/test_ruleset_creator.h
new file mode 100644
index 00000000000..83c4cd3bff4
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/test_ruleset_creator.h
@@ -0,0 +1,87 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TEST_RULESET_CREATOR_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TEST_RULESET_CREATOR_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+
+namespace subresource_filter {
+namespace testing {
+
+// Encapsulates a testing subresource filtering ruleset serialized either in
+// indexed or unindexed format. The ruleset |contents| can be accessed directly
+// as a byte buffer, as well as through the file |path| pointing to a temporary
+// file that is cleaned up when the TestRulesetCreator is destroyed.
+struct TestRuleset {
+ TestRuleset();
+ ~TestRuleset();
+
+ // Convenience function to open a read-only file handle to |ruleset|.
+ static base::File Open(const TestRuleset& ruleset);
+
+ std::vector<uint8_t> contents;
+ base::FilePath path;
+};
+
+// Encapsulates the same ruleset in both indexed and unindexed formats.
+struct TestRulesetPair {
+ TestRulesetPair();
+ ~TestRulesetPair();
+
+ TestRuleset unindexed;
+ TestRuleset indexed;
+};
+
+// Helper class to create subresource filtering rulesets for testing.
+//
+// All temporary files and paths are cleaned up when the instance goes out of
+// scope, but file handles already open can still be used and read even after
+// this has happened.
+class TestRulesetCreator {
+ public:
+ TestRulesetCreator();
+ ~TestRulesetCreator();
+
+ // Creates both the indexed and unindexed versions of a testing ruleset that
+ // consists of single filtering rule that disallows subresource loads from URL
+ // paths having the given |suffix|.
+ // Enclose call in ASSERT_NO_FATAL_FAILURE to detect errors.
+ void CreateRulesetToDisallowURLsWithPathSuffix(
+ base::StringPiece suffix,
+ TestRulesetPair* test_ruleset_pair);
+
+ // Same as above, but only creates an unindexed ruleset.
+ void CreateUnindexedRulesetToDisallowURLsWithPathSuffix(
+ base::StringPiece suffix,
+ TestRuleset* test_unindexed_ruleset);
+
+ // Returns a unique |path| that is valid for the lifetime of this instance.
+ // No file at |path| will be automatically created.
+ void GetUniqueTemporaryPath(base::FilePath* path);
+
+ private:
+ // Writes the |ruleset_contents| to a temporary file, and initializes
+ // |ruleset| to have the same |contents|, and the |path| to this file.
+ void CreateTestRulesetFromContents(std::vector<uint8_t> ruleset_contents,
+ TestRuleset* ruleset);
+
+ base::ScopedTempDir scoped_temp_dir_;
+ int next_unique_file_suffix = 1;
+
+ DISALLOW_COPY_AND_ASSIGN(TestRulesetCreator);
+};
+
+} // namespace testing
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TEST_RULESET_CREATOR_H_
diff --git a/chromium/components/subresource_filter/core/common/unindexed_ruleset.cc b/chromium/components/subresource_filter/core/common/unindexed_ruleset.cc
new file mode 100644
index 00000000000..641a73d906d
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/unindexed_ruleset.cc
@@ -0,0 +1,70 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/core/common/unindexed_ruleset.h"
+
+#include "base/numerics/safe_conversions.h"
+
+namespace subresource_filter {
+
+// UnindexedRulesetReader ------------------------------------------------------
+
+UnindexedRulesetReader::UnindexedRulesetReader(
+ google::protobuf::io::ZeroCopyInputStream* stream)
+ : coded_stream_(stream) {}
+
+UnindexedRulesetReader::~UnindexedRulesetReader() = default;
+
+bool UnindexedRulesetReader::ReadNextChunk(proto::FilteringRules* chunk) {
+ uint32_t chunk_size = 0;
+ if (!coded_stream_.ReadVarint32(&chunk_size))
+ return false;
+ auto limit = coded_stream_.PushLimit(chunk_size);
+ if (!chunk->ParseFromCodedStream(&coded_stream_))
+ return false;
+ coded_stream_.PopLimit(limit);
+ return true;
+}
+
+// UnindexedRulesetWriter ------------------------------------------------------
+
+UnindexedRulesetWriter::UnindexedRulesetWriter(
+ google::protobuf::io::ZeroCopyOutputStream* stream,
+ int max_rules_per_chunk)
+ : coded_stream_(stream), max_rules_per_chunk_(max_rules_per_chunk) {}
+
+UnindexedRulesetWriter::~UnindexedRulesetWriter() {
+ DCHECK_EQ(pending_chunk_.url_rules_size(), 0);
+ DCHECK_EQ(pending_chunk_.css_rules_size(), 0);
+}
+
+bool UnindexedRulesetWriter::AddUrlRule(const proto::UrlRule& rule) {
+ DCHECK(!had_error());
+ pending_chunk_.add_url_rules()->CopyFrom(rule);
+ if (pending_chunk_.url_rules_size() >= max_rules_per_chunk_) {
+ DCHECK_EQ(pending_chunk_.url_rules_size(), max_rules_per_chunk_);
+ return WritePendingChunk();
+ }
+ return true;
+}
+
+bool UnindexedRulesetWriter::Finish() {
+ DCHECK(!had_error());
+ const bool success = !pending_chunk_.url_rules_size() || WritePendingChunk();
+ if (success)
+ coded_stream_.Trim();
+ return success;
+}
+
+bool UnindexedRulesetWriter::WritePendingChunk() {
+ DCHECK(!had_error());
+ DCHECK_GT(pending_chunk_.url_rules_size(), 0);
+
+ proto::FilteringRules chunk;
+ chunk.Swap(&pending_chunk_);
+ coded_stream_.WriteVarint32(base::checked_cast<uint32_t>(chunk.ByteSize()));
+ return !had_error() && chunk.SerializeToCodedStream(&coded_stream_);
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/unindexed_ruleset.h b/chromium/components/subresource_filter/core/common/unindexed_ruleset.h
new file mode 100644
index 00000000000..af847ea8a06
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/unindexed_ruleset.h
@@ -0,0 +1,100 @@
+// 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.
+
+// Semantically speaking, an unindexed ruleset consists of a single
+// proto::FilteringRules message. However, because the ruleset can be relatively
+// large, we want to avoid deserializing all of it at once, as doing so can lead
+// to memory allocation bursts.
+//
+// To work around the limitation that partial (or streaming) deserialization is
+// not supported by the proto parser, the UnindexedRulesetReader/Writer classes
+// implement a format where the ruleset is split into several chunks. Each chunk
+// is itself a proto::FilteringRules message. If all chunks were merged, they
+// would add up to the original proto::FilteringRules message representing the
+// entire ruleset.
+//
+// Consumers of an unindexed ruleset in this format will be able to read it one
+// chunk at a time, and are expected to fully process and discard the chunk
+// before reading the next one. In practice, this should not be an issue as
+// indexing of the ruleset is expected to be performed in an on-line fashion.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_UNINDEXED_RULESET_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_UNINDEXED_RULESET_H_
+
+#include "base/macros.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
+#include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h"
+
+namespace subresource_filter {
+
+// Reads an unindexed ruleset from |stream| one chunk at a time.
+class UnindexedRulesetReader {
+ public:
+ // Note: The |stream| should outlive |this| instance.
+ explicit UnindexedRulesetReader(
+ google::protobuf::io::ZeroCopyInputStream* stream);
+ ~UnindexedRulesetReader();
+
+ // Reads the next ruleset |chunk| from the |input|. Returns false iff reached
+ // the end of the stream or an error occurred. Once returned false, calling
+ // ReadNextChunk is undefined befaviour.
+ bool ReadNextChunk(proto::FilteringRules* chunk);
+
+ // Returns how many bytes of the |stream| have been consumed.
+ int num_bytes_read() const { return coded_stream_.CurrentPosition(); }
+
+ private:
+ google::protobuf::io::CodedInputStream coded_stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnindexedRulesetReader);
+};
+
+// Divides an unindexed ruleset into chunks and writes them into |stream|.
+//
+// Writing methods of this class return bool false if an I/O error occurrs
+// during these calls. In this case the UnindexedRulesetWriter becomes broken,
+// and write operations should not be used further.
+class UnindexedRulesetWriter {
+ public:
+ // Creates an instance that will write proto::FilteringRules chunks to the
+ // |stream|, with each chunk containing up to |max_rules_per_chunk| rules.
+ explicit UnindexedRulesetWriter(
+ google::protobuf::io::ZeroCopyOutputStream* stream,
+ int max_rules_per_chunk = 64);
+ ~UnindexedRulesetWriter();
+
+ int max_rules_per_chunk() const { return max_rules_per_chunk_; }
+
+ // Returns whether an I/O error occurred since this object was created.
+ bool had_error() const { return coded_stream_.HadError(); }
+
+ // Places the |rule| to the current chunk, and serializes the chunk if it has
+ // grown up to |max_rules_per_chunk|.
+ bool AddUrlRule(const proto::UrlRule& rule);
+ // TODO(pkalinnikov): Implement AddCssRule when needed.
+
+ // Finalizes the serialization of the unindexed ruleset, i.e., writes the
+ // final chunk of rules, if there are any still pending. This method *should*
+ // be called exactly once when interaction with |this| instance ends, unless
+ // some of the writing operations returned false, which indicates an error.
+ // After calling Finish write operations should not be used any more.
+ bool Finish();
+
+ private:
+ // Writes the non-empty |pending_chunk_| to the |coded_stream_|. Always leaves
+ // the |panding_chunk_| empty, regardless of whether an error occurred.
+ bool WritePendingChunk();
+
+ google::protobuf::io::CodedOutputStream coded_stream_;
+
+ const int max_rules_per_chunk_ = 0;
+ proto::FilteringRules pending_chunk_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnindexedRulesetWriter);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_UNINDEXED_RULESET_H_
diff --git a/chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc b/chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc
new file mode 100644
index 00000000000..812d1b9ea09
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc
@@ -0,0 +1,203 @@
+// 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 "components/subresource_filter/core/common/unindexed_ruleset.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
+#include "components/subresource_filter/core/common/url_pattern.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+namespace subresource_filter {
+
+namespace {
+
+bool IsEqual(const proto::UrlRule& first, const proto::UrlRule& second) {
+ // Note: The domain list is omitted for simplicity.
+ return first.semantics() == second.semantics() &&
+ first.source_type() == second.source_type() &&
+ first.element_types() == second.element_types() &&
+ first.activation_types() == second.activation_types() &&
+ first.url_pattern_type() == second.url_pattern_type() &&
+ first.anchor_left() == second.anchor_left() &&
+ first.anchor_right() == second.anchor_right() &&
+ first.match_case() == second.match_case() &&
+ first.url_pattern() == second.url_pattern();
+}
+
+proto::UrlRule CreateRule(const UrlPattern& url_pattern,
+ proto::SourceType source_type,
+ bool is_whitelist) {
+ proto::UrlRule rule;
+ rule.set_semantics(is_whitelist ? proto::RULE_SEMANTICS_WHITELIST
+ : proto::RULE_SEMANTICS_BLACKLIST);
+
+ rule.set_source_type(source_type);
+ rule.set_element_types(proto::ELEMENT_TYPE_ALL);
+
+ rule.set_url_pattern_type(url_pattern.type);
+ rule.set_anchor_left(url_pattern.anchor_left);
+ rule.set_anchor_right(url_pattern.anchor_right);
+ rule.set_match_case(url_pattern.match_case);
+ rule.set_url_pattern(url_pattern.url_pattern.as_string());
+ return rule;
+}
+
+// The helper class used for building UnindexedRulesets.
+class UnindexedRulesetTestBuilder {
+ public:
+ // Initializes the builder that writes the ruleset to StringOutputStream.
+ UnindexedRulesetTestBuilder()
+ : output_(
+ new google::protobuf::io::StringOutputStream(&ruleset_contents_)),
+ ruleset_writer_(output_.get()) {}
+
+ // Initializes the builder that writes the ruleset to an array of |array_size|
+ // through an ArrayOutputStream.
+ UnindexedRulesetTestBuilder(int array_size)
+ : ruleset_contents_(array_size, '\0'),
+ output_(
+ new google::protobuf::io::ArrayOutputStream(&ruleset_contents_[0],
+ array_size)),
+ ruleset_writer_(output_.get()) {}
+
+ int max_rules_per_chunk() const {
+ return ruleset_writer_.max_rules_per_chunk();
+ }
+
+ bool AddUrlRule(const UrlPattern& url_pattern,
+ proto::SourceType source_type,
+ bool is_whitelist) {
+ url_rules_.push_back(CreateRule(url_pattern, source_type, is_whitelist));
+ return !ruleset_writer_.had_error() &&
+ ruleset_writer_.AddUrlRule(url_rules_.back());
+ }
+
+ bool AddUrlRules(int number_of_rules) {
+ for (int i = 0; i < number_of_rules; ++i) {
+ std::string url_pattern = "example" + base::IntToString(i) + ".com";
+ if (!AddUrlRule(UrlPattern(url_pattern), proto::SOURCE_TYPE_ANY, i & 1))
+ return false;
+ }
+ return true;
+ }
+
+ bool Finish() {
+ if (!ruleset_writer_.had_error() && ruleset_writer_.Finish()) {
+ // Note: This line has effect only when |output_| is an ArrayOutputStream.
+ ruleset_contents_.resize(output_->ByteCount());
+ return true;
+ }
+ return false;
+ }
+
+ const std::vector<proto::UrlRule>& url_rules() const { return url_rules_; }
+ const std::string& ruleset_contents() const { return ruleset_contents_; }
+
+ private:
+ std::vector<proto::UrlRule> url_rules_;
+ std::string ruleset_contents_;
+ std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output_;
+ UnindexedRulesetWriter ruleset_writer_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnindexedRulesetTestBuilder);
+};
+
+bool IsRulesetValid(const std::string& ruleset_contents,
+ const std::vector<proto::UrlRule>& expected_url_rules) {
+ google::protobuf::io::ArrayInputStream array_input(ruleset_contents.data(),
+ ruleset_contents.size());
+ UnindexedRulesetReader reader(&array_input);
+ proto::FilteringRules chunk;
+ std::vector<proto::UrlRule> read_rules;
+ while (reader.ReadNextChunk(&chunk)) {
+ read_rules.insert(read_rules.end(), chunk.url_rules().begin(),
+ chunk.url_rules().end());
+ }
+ if (base::checked_cast<size_t>(reader.num_bytes_read()) !=
+ ruleset_contents.size()) {
+ return false;
+ }
+
+ if (expected_url_rules.size() != read_rules.size())
+ return false;
+ for (size_t i = 0, size = read_rules.size(); i != size; ++i) {
+ if (!IsEqual(expected_url_rules[i], read_rules[i]))
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+TEST(UnindexedRulesetTest, EmptyRuleset) {
+ UnindexedRulesetTestBuilder builder;
+ EXPECT_TRUE(builder.Finish());
+ EXPECT_TRUE(IsRulesetValid(builder.ruleset_contents(), builder.url_rules()));
+}
+
+TEST(UnindexedRulesetTest, OneUrlRule) {
+ UnindexedRulesetTestBuilder builder;
+ EXPECT_TRUE(builder.AddUrlRule(UrlPattern("example.com"),
+ proto::SOURCE_TYPE_THIRD_PARTY, false));
+ EXPECT_TRUE(builder.Finish());
+ EXPECT_TRUE(IsRulesetValid(builder.ruleset_contents(), builder.url_rules()));
+}
+
+TEST(UnindexedRulesetTest, ManyUrlRules) {
+ UnindexedRulesetTestBuilder builder;
+ EXPECT_TRUE(builder.AddUrlRules(1234));
+ EXPECT_TRUE(builder.Finish());
+ EXPECT_TRUE(IsRulesetValid(builder.ruleset_contents(), builder.url_rules()));
+}
+
+TEST(UnindexedRulesetTest, ExactlyMaxRulesPerChunk) {
+ UnindexedRulesetTestBuilder builder;
+ EXPECT_TRUE(builder.AddUrlRules(builder.max_rules_per_chunk()));
+ EXPECT_TRUE(builder.Finish());
+ EXPECT_TRUE(IsRulesetValid(builder.ruleset_contents(), builder.url_rules()));
+}
+
+TEST(UnindexedRulesetTest, MaxRulesPerChunkPlusOne) {
+ UnindexedRulesetTestBuilder builder;
+ EXPECT_TRUE(builder.AddUrlRules(builder.max_rules_per_chunk() + 1));
+ EXPECT_TRUE(builder.Finish());
+ EXPECT_TRUE(IsRulesetValid(builder.ruleset_contents(), builder.url_rules()));
+}
+
+TEST(UnindexedRulesetTest, ErrorOnWrite) {
+ UnindexedRulesetTestBuilder builder(1000);
+ EXPECT_FALSE(builder.AddUrlRules(1234));
+}
+
+TEST(UnindexedRulesetTest, ReadCorruptedInput) {
+ UnindexedRulesetTestBuilder builder;
+ EXPECT_TRUE(builder.AddUrlRules(1000));
+ EXPECT_TRUE(builder.Finish());
+
+ {
+ std::string ruleset_contents = builder.ruleset_contents();
+ ASSERT_GE(ruleset_contents.size(), static_cast<size_t>(2000));
+ ruleset_contents[100] ^= 239;
+ ruleset_contents[1000] ^= 3;
+ EXPECT_FALSE(IsRulesetValid(ruleset_contents, builder.url_rules()));
+ }
+
+ {
+ std::string ruleset_contents = builder.ruleset_contents();
+ ASSERT_GT(ruleset_contents.size(), static_cast<size_t>(100));
+ ruleset_contents.resize(100);
+ EXPECT_FALSE(IsRulesetValid(ruleset_contents, builder.url_rules()));
+ }
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/url_pattern.cc b/chromium/components/subresource_filter/core/common/url_pattern.cc
new file mode 100644
index 00000000000..1cfa663762a
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/url_pattern.cc
@@ -0,0 +1,76 @@
+// 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 "components/subresource_filter/core/common/url_pattern.h"
+
+#include "components/subresource_filter/core/common/flat/rules_generated.h"
+
+namespace subresource_filter {
+
+namespace {
+
+proto::UrlPatternType ConvertUrlPatternType(flat::UrlPatternType type) {
+ switch (type) {
+ case flat::UrlPatternType_SUBSTRING:
+ return proto::URL_PATTERN_TYPE_SUBSTRING;
+ case flat::UrlPatternType_WILDCARDED:
+ return proto::URL_PATTERN_TYPE_WILDCARDED;
+ case flat::UrlPatternType_REGEXP:
+ return proto::URL_PATTERN_TYPE_REGEXP;
+ default:
+ return proto::URL_PATTERN_TYPE_UNSPECIFIED;
+ }
+}
+
+proto::AnchorType ConvertAnchorType(flat::AnchorType type) {
+ switch (type) {
+ case flat::AnchorType_NONE:
+ return proto::ANCHOR_TYPE_NONE;
+ case flat::AnchorType_BOUNDARY:
+ return proto::ANCHOR_TYPE_BOUNDARY;
+ case flat::AnchorType_SUBDOMAIN:
+ return proto::ANCHOR_TYPE_SUBDOMAIN;
+ default:
+ return proto::ANCHOR_TYPE_UNSPECIFIED;
+ }
+}
+
+base::StringPiece ConvertString(const flatbuffers::String* string) {
+ return string ? base::StringPiece(string->data(), string->size())
+ : base::StringPiece();
+}
+
+} // namespace
+
+UrlPattern::UrlPattern() = default;
+
+UrlPattern::UrlPattern(base::StringPiece url_pattern,
+ proto::UrlPatternType type)
+ : type(type), url_pattern(url_pattern) {}
+
+UrlPattern::UrlPattern(base::StringPiece url_pattern,
+ proto::AnchorType anchor_left,
+ proto::AnchorType anchor_right)
+ : type(proto::URL_PATTERN_TYPE_WILDCARDED),
+ url_pattern(url_pattern),
+ anchor_left(anchor_left),
+ anchor_right(anchor_right) {}
+
+UrlPattern::UrlPattern(const flat::UrlRule& rule)
+ : type(ConvertUrlPatternType(rule.url_pattern_type())),
+ url_pattern(ConvertString(rule.url_pattern())),
+ anchor_left(ConvertAnchorType(rule.anchor_left())),
+ anchor_right(ConvertAnchorType(rule.anchor_right())),
+ match_case(!!(rule.options() & flat::OptionFlag_IS_MATCH_CASE)) {}
+
+UrlPattern::UrlPattern(const proto::UrlRule& rule)
+ : type(rule.url_pattern_type()),
+ url_pattern(rule.url_pattern()),
+ anchor_left(rule.anchor_left()),
+ anchor_right(rule.anchor_right()),
+ match_case(rule.match_case()) {}
+
+UrlPattern::~UrlPattern() = default;
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/url_pattern.h b/chromium/components/subresource_filter/core/common/url_pattern.h
new file mode 100644
index 00000000000..f49b5ea610b
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/url_pattern.h
@@ -0,0 +1,53 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_H_
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "components/subresource_filter/core/common/proto/rules.pb.h"
+
+namespace subresource_filter {
+
+namespace flat {
+struct UrlRule; // The FlatBuffers version of UrlRule.
+}
+
+// The structure used to mirror a URL pattern regardless of the representation
+// of the UrlRule that owns it.
+struct UrlPattern {
+ UrlPattern();
+
+ // Creates a |url_pattern| of a certain |type|.
+ UrlPattern(base::StringPiece url_pattern,
+ proto::UrlPatternType type = proto::URL_PATTERN_TYPE_WILDCARDED);
+
+ // Creates a WILDCARDED |url_pattern| with the specified anchors.
+ UrlPattern(base::StringPiece url_pattern,
+ proto::AnchorType anchor_left,
+ proto::AnchorType anchor_right);
+
+ // The following constructors create UrlPattern from one of the UrlRule
+ // representations. The passed in |rule| must outlive the created instance.
+ explicit UrlPattern(const flat::UrlRule& rule);
+ explicit UrlPattern(const proto::UrlRule& rule);
+
+ ~UrlPattern();
+
+ proto::UrlPatternType type = proto::URL_PATTERN_TYPE_UNSPECIFIED;
+ base::StringPiece url_pattern;
+
+ proto::AnchorType anchor_left = proto::ANCHOR_TYPE_NONE;
+ proto::AnchorType anchor_right = proto::ANCHOR_TYPE_NONE;
+
+ bool match_case = false;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UrlPattern);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_H_
diff --git a/chromium/components/subresource_filter/core/common/url_pattern_matching.h b/chromium/components/subresource_filter/core/common/url_pattern_matching.h
new file mode 100644
index 00000000000..937b703edfa
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/url_pattern_matching.h
@@ -0,0 +1,277 @@
+// 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.
+
+// The matching logic distinguishes between the terms URL pattern and
+// subpattern. A URL pattern usually stands for the full thing, e.g.
+// "example.com^*path*par=val^", whereas subpattern denotes a maximal substring
+// of a pattern not containing the wildcard '*' character. For the example above
+// the subpatterns are: "example.com^", "path" and "par=val^".
+//
+// The separator placeholder '^' symbol is used in subpatterns to match any
+// separator character, which is any ASCII symbol except letters, digits, and
+// the following: '_', '-', '.', '%'. Note that the separator placeholder
+// character '^' is itself a separator, as well as '\0'.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_MATCHING_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_MATCHING_H_
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "components/subresource_filter/core/common/fuzzy_pattern_matching.h"
+#include "components/subresource_filter/core/common/knuth_morris_pratt.h"
+#include "components/subresource_filter/core/common/string_splitter.h"
+#include "components/subresource_filter/core/common/url_pattern.h"
+#include "url/gurl.h"
+#include "url/third_party/mozilla/url_parse.h"
+
+namespace subresource_filter {
+
+// Public interface declaration ------------------------------------------------
+
+// Builds a compound Knuth-Morris-Pratt failure function used to match URLs
+// against the |pattern|.
+//
+// The |pattern| is split on the '*' wildcard symbol and then a failure function
+// is built for each subpattern by BuildFailureFunctionFuzzy or
+// BuildFailureFunction (depending on whether the subpattern contains separator
+// placeholders), and appended to the returned vector. Some of the subpatterns
+// can be exempted from being indexed. E.g., if the |pattern| has a BOUNDARY
+// left anchor, the first subpattern can be matched by checking if it's a prefix
+// of a URL.
+//
+// Each subpattern indexed with BuildFailureFunctionFuzzy is prepended with a
+// value 1 (to distinguish them from the subpatterns indexed with
+// BuildFailureFunction, their failure functions always start with 0).
+//
+// The URL |pattern| must be normalized. Namely, it must not have the following
+// substrings: **, *<END>, <BEGIN>*. If the the |pattern| has a BOUNDARY anchor,
+// the corresponding side of its string must not end with a '*' wildcard.
+template <typename IntType>
+void BuildFailureFunction(const UrlPattern& pattern,
+ std::vector<IntType>* failure);
+
+// Returns whether the |url| matches the URL |pattern|. The |failure| function
+// between |failure_begin| and |failure_end| must be the output of
+// BuildFailureFunction() called with the same |pattern|.
+//
+// TODO(pkalinnikov): Outline algorithms implemented in this function.
+template <typename FailureIter>
+bool IsUrlPatternMatch(const GURL& url,
+ const UrlPattern& pattern,
+ FailureIter failure_begin,
+ FailureIter failure_end);
+
+// Implementation --------------------------------------------------------------
+
+namespace impl {
+
+class IsWildcard {
+ public:
+ bool operator()(char c) const { return c == '*'; }
+};
+
+// Returns whether |position| within the |url| belongs to its |host| component
+// and corresponds to the beginning of a (sub-)domain.
+inline bool IsSubdomainAnchored(base::StringPiece url,
+ url::Component host,
+ size_t position) {
+ DCHECK_LE(position, url.size());
+ const size_t host_begin = static_cast<size_t>(host.begin);
+ const size_t host_end = static_cast<size_t>(host.end());
+ DCHECK_LE(host_end, url.size());
+
+ return position == host_begin ||
+ (position > host_begin && position <= host_end &&
+ url[position - 1] == '.');
+}
+
+// Returns the position just beyond the leftmost fuzzy occurrence of
+// |subpattern| in the |text|.
+template <typename IntType>
+inline size_t FindFirstOccurrenceFuzzy(base::StringPiece text,
+ base::StringPiece subpattern,
+ const IntType* failure) {
+ return *AllOccurrencesFuzzy<IntType>(text, subpattern, failure).begin();
+}
+
+// Returns the position just beyond the leftmost occurrence of |subpattern| in
+// the |url|, such that it satisfies a SUBDOMAIN anchor.
+template <typename IntType>
+inline size_t FindSubdomainAnchored(base::StringPiece url,
+ url::Component host,
+ base::StringPiece subpattern,
+ const IntType* failure) {
+ auto occurrences = AllOccurrences<IntType>(url, subpattern, failure);
+ return *std::find_if(occurrences.begin(), occurrences.end(),
+ [url, host, subpattern](size_t match_end_position) {
+ DCHECK_GE(match_end_position, subpattern.size());
+ return IsSubdomainAnchored(
+ url, host, match_end_position - subpattern.size());
+ });
+}
+
+// Returns the position just beyond the leftmost fuzzy occurrence of
+// |subpattern| in the |url|, such that it satisfies a SUBDOMAIN anchor.
+template <typename IntType>
+inline size_t FindSubdomainAnchoredFuzzy(base::StringPiece url,
+ url::Component host,
+ base::StringPiece subpattern,
+ const IntType* failure) {
+ auto occurrences = AllOccurrencesFuzzy<IntType>(url, subpattern, failure);
+ return *std::find_if(occurrences.begin(), occurrences.end(),
+ [url, host, subpattern](size_t match_end_position) {
+ DCHECK_GE(match_end_position, subpattern.size());
+ return IsSubdomainAnchored(
+ url, host, match_end_position - subpattern.size());
+ });
+}
+
+} // namespace impl
+
+template <typename IntType>
+void BuildFailureFunction(const UrlPattern& pattern,
+ std::vector<IntType>* failure) {
+ StringSplitter<impl::IsWildcard> subpatterns(pattern.url_pattern);
+ auto subpattern_it = subpatterns.begin();
+ auto subpattern_end = subpatterns.end();
+
+ if (subpattern_it == subpattern_end)
+ return;
+ if (pattern.anchor_left == proto::ANCHOR_TYPE_BOUNDARY)
+ ++subpattern_it;
+
+ while (subpattern_it != subpattern_end) {
+ const base::StringPiece part = *subpattern_it++;
+ DCHECK(!part.empty());
+ if (pattern.anchor_right == proto::ANCHOR_TYPE_BOUNDARY &&
+ subpattern_it == subpattern_end) {
+ break;
+ }
+
+ if (part.find(kSeparatorPlaceholder) == base::StringPiece::npos) {
+ BuildFailureFunction(part, failure);
+ } else {
+ // Prepend the value '1' to the failure function to let matchers
+ // distinguish between the subpatterns with separator placeholders and
+ // those without.
+ failure->push_back(1);
+ BuildFailureFunctionFuzzy(part, failure);
+ }
+ }
+}
+
+template <typename FailureIter>
+bool IsUrlPatternMatch(const GURL& url,
+ const UrlPattern& pattern,
+ FailureIter failure_begin,
+ FailureIter failure_end) {
+ DCHECK(url.is_valid());
+
+ StringSplitter<impl::IsWildcard> subpatterns(pattern.url_pattern);
+ auto subpattern_it = subpatterns.begin();
+ auto subpattern_end = subpatterns.end();
+
+ if (subpattern_it == subpattern_end) {
+ return pattern.anchor_left != proto::ANCHOR_TYPE_BOUNDARY ||
+ pattern.anchor_right != proto::ANCHOR_TYPE_BOUNDARY ||
+ url.is_empty();
+ }
+
+ const base::StringPiece spec = url.possibly_invalid_spec();
+ const url::Component host_part = url.parsed_for_possibly_invalid_spec().host;
+
+ base::StringPiece subpattern = *subpattern_it++;
+ if (subpattern_it == subpattern_end &&
+ pattern.anchor_right == proto::ANCHOR_TYPE_BOUNDARY) {
+ if (!EndsWithFuzzy(spec, subpattern))
+ return false;
+ if (pattern.anchor_left == proto::ANCHOR_TYPE_BOUNDARY)
+ return spec.size() == subpattern.size();
+ if (pattern.anchor_left == proto::ANCHOR_TYPE_SUBDOMAIN) {
+ DCHECK_LE(subpattern.size(), spec.size());
+ return url.has_host() &&
+ impl::IsSubdomainAnchored(spec, host_part,
+ spec.size() - subpattern.size());
+ }
+ return true;
+ }
+
+ base::StringPiece text = spec;
+ if (pattern.anchor_left == proto::ANCHOR_TYPE_BOUNDARY) {
+ if (!StartsWithFuzzy(spec, subpattern))
+ return false;
+ if (subpattern_it == subpattern_end)
+ return true;
+ text.remove_prefix(subpattern.size());
+ } else if (pattern.anchor_left == proto::ANCHOR_TYPE_SUBDOMAIN) {
+ if (!url.has_host())
+ return false;
+
+ const bool has_separator_placeholders = (*failure_begin != 0);
+ if (has_separator_placeholders)
+ ++failure_begin;
+
+ const size_t position =
+ has_separator_placeholders
+ ? impl::FindSubdomainAnchoredFuzzy(spec, host_part, subpattern,
+ &*failure_begin)
+ : impl::FindSubdomainAnchored(spec, host_part, subpattern,
+ &*failure_begin);
+ if (position == base::StringPiece::npos)
+ return false;
+ if (subpattern_it == subpattern_end)
+ return true;
+ text.remove_prefix(position);
+ } else {
+ DCHECK_EQ(pattern.anchor_left, proto::ANCHOR_TYPE_NONE);
+ // Get back to the initial subpattern, process it in the loop below.
+ subpattern_it = subpatterns.begin();
+ }
+
+ while (subpattern_it != subpattern_end) {
+ subpattern = *subpattern_it++;
+ DCHECK(!subpattern.empty());
+
+ if (subpattern_it == subpattern_end &&
+ pattern.anchor_right == proto::ANCHOR_TYPE_BOUNDARY) {
+ break;
+ }
+
+ // The subpatterns with separator placeholders were indexed differently and
+ // should be matched accordingly. Their failure functions were prepended by
+ // a non-zero value, and we need to skip it. If the value turned to be zero,
+ // it is the initial value of a failure function of a regular substring.
+ CHECK(failure_begin < failure_end);
+ const bool has_separator_placeholders = (*failure_begin != 0);
+ if (has_separator_placeholders)
+ ++failure_begin;
+ CHECK(static_cast<size_t>(std::distance(failure_begin, failure_end)) >=
+ subpattern.size());
+
+ // If the subpattern has separator placeholders, it should be matched with
+ // FindFirstOccurrenceOfSubpattern, otherwise it can be found as a regular
+ // substring.
+ const size_t match_end =
+ (has_separator_placeholders
+ ? impl::FindFirstOccurrenceFuzzy(text, subpattern, &*failure_begin)
+ : FindFirstOccurrence(text, subpattern, &*failure_begin));
+ if (match_end == base::StringPiece::npos)
+ return false;
+ text.remove_prefix(match_end);
+ failure_begin += subpattern.size();
+ }
+
+ return pattern.anchor_right != proto::ANCHOR_TYPE_BOUNDARY ||
+ EndsWithFuzzy(text, subpattern);
+}
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_URL_PATTERN_MATCHING_H_
diff --git a/chromium/components/subresource_filter/core/common/url_pattern_matching_unittest.cc b/chromium/components/subresource_filter/core/common/url_pattern_matching_unittest.cc
new file mode 100644
index 00000000000..cdf36add41c
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/url_pattern_matching_unittest.cc
@@ -0,0 +1,152 @@
+// 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 "components/subresource_filter/core/common/url_pattern_matching.h"
+
+#include <vector>
+
+#include "components/subresource_filter/core/common/url_pattern.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace subresource_filter {
+
+namespace {
+
+constexpr proto::AnchorType kAnchorNone = proto::ANCHOR_TYPE_NONE;
+constexpr proto::AnchorType kBoundary = proto::ANCHOR_TYPE_BOUNDARY;
+constexpr proto::AnchorType kSubdomain = proto::ANCHOR_TYPE_SUBDOMAIN;
+
+} // namespace
+
+TEST(UrlPatternMatchingTest, BuildFailureFunctionForUrlPattern) {
+ const struct {
+ UrlPattern url_pattern;
+ std::vector<size_t> expected_failure_function;
+ } kTestCases[] = {
+ {{"abcd", proto::URL_PATTERN_TYPE_SUBSTRING}, {0, 0, 0, 0}},
+ {{"&a?a/"}, {0, 0, 0, 0, 0}},
+ {{"^a?a/"}, {1, 0, 0, 1, 2, 3}},
+
+ {{"abc*abc", kBoundary, kAnchorNone}, {0, 0, 0}},
+ {{"abc*aaa", kBoundary, kAnchorNone}, {0, 1, 2}},
+ {{"aaa*abc", kBoundary, kAnchorNone}, {0, 0, 0}},
+
+ {{"abc*abc", kAnchorNone, kBoundary}, {0, 0, 0}},
+ {{"abc*aaa", kAnchorNone, kBoundary}, {0, 0, 0}},
+ {{"aaa*abc", kAnchorNone, kBoundary}, {0, 1, 2}},
+
+ {{"abc*cca", kSubdomain, kAnchorNone}, {0, 0, 0, 0, 1, 0}},
+ {{"abc*cca", kBoundary, kAnchorNone}, {0, 1, 0}},
+ {{"abc*cca"}, {0, 0, 0, 0, 1, 0}},
+
+ {{"abc*abacaba*cab"}, {0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0}},
+ {{"aaa*a^d*^^b"}, {0, 1, 2, 1, 0, 0, 0, 1, 0, 1, 0}},
+ {{"aaa*a^d*^^b", kAnchorNone, kBoundary}, {0, 1, 2, 1, 0, 0, 0}},
+ {{"^^a*a^d*^^b", kBoundary, kAnchorNone}, {1, 0, 0, 0, 1, 0, 1, 0}},
+ };
+
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "Pattern: " << test_case.url_pattern.url_pattern
+ << "; Anchors: "
+ << static_cast<int>(test_case.url_pattern.anchor_left) << ", "
+ << static_cast<int>(test_case.url_pattern.anchor_right));
+
+ std::vector<size_t> failure;
+ BuildFailureFunction(test_case.url_pattern, &failure);
+ EXPECT_EQ(test_case.expected_failure_function, failure);
+ }
+}
+
+TEST(UrlPatternMatchingTest, IsUrlPatternMatch) {
+ const struct {
+ UrlPattern url_pattern;
+ const char* url;
+ bool expect_match;
+ } kTestCases[] = {
+ {{"xampl", proto::URL_PATTERN_TYPE_SUBSTRING},
+ "http://example.com",
+ true},
+ {{"example", proto::URL_PATTERN_TYPE_SUBSTRING},
+ "http://example.com",
+ true},
+ {{"/a?a"}, "http://ex.com/a?a", true},
+ {{"^abc"}, "http://ex.com/abc?a", true},
+ {{"^abc"}, "http://ex.com/a?abc", true},
+ {{"^abc"}, "http://ex.com/abc?abc", true},
+
+ {{"http://ex", kBoundary, kAnchorNone}, "http://example.com", true},
+ {{"mple.com/", kAnchorNone, kBoundary}, "http://example.com", true},
+
+ // Note: "example.com" will be normalized into "example.com/".
+ {{"http://*mpl", kBoundary, kAnchorNone}, "http://example.com", true},
+ {{"mpl*com/", kAnchorNone, kBoundary}, "http://example.com", true},
+ {{"example^com"}, "http://example.com", false},
+ {{"example^com"}, "http://example/com", true},
+ {{"example.com^"}, "http://example.com:8080", true},
+ {{"http*.com/", kBoundary, kBoundary}, "http://example.com", true},
+ {{"http*.org/", kBoundary, kBoundary}, "http://example.com", false},
+
+ {{"/path?*&p1=*&p2="}, "http://ex.com/aaa/path/bbb?k=v&p1=0&p2=1", false},
+ {{"/path?*&p1=*&p2="}, "http://ex.com/aaa/path?k=v&p1=0&p2=1", true},
+ {{"/path?*&p1=*&p2="}, "http://ex.com/aaa/path?k=v&k=v&p1=0&p2=1", true},
+ {{"/path?*&p1=*&p2="},
+ "http://ex.com/aaa/path?k=v&p1=0&p3=10&p2=1",
+ true},
+ {{"/path?*&p1=*&p2="}, "http://ex.com/aaa/path&p1=0&p2=1", false},
+ {{"/path?*&p1=*&p2="}, "http://ex.com/aaa/path?k=v&p2=0&p1=1", false},
+
+ {{"abc*def*ghijk*xyz"},
+ "http://example.com/abcdeffffghijkmmmxyzzz",
+ true},
+ {{"abc*cdef"}, "http://example.com/abcdef", false},
+
+ {{"^^a^^"}, "http://ex.com/?a=/", true},
+ {{"^^a^^"}, "http://ex.com/?a=/&b=0", true},
+ {{"^^a^^"}, "http://ex.com/?a=", false},
+
+ {{"ex.com^path^*k=v^"}, "http://ex.com/path/?k1=v1&ak=v&kk=vv", true},
+ {{"ex.com^path^*k=v^"}, "http://ex.com/p/path/?k1=v1&ak=v&kk=vv", false},
+ {{"a^a&a^a&"}, "http://ex.com/a/a/a/a/?a&a&a&a&a", true},
+
+ {{"abc*def^"}, "http://ex.com/abc/a/ddef/", true},
+
+ {{"https://example.com/"}, "http://example.com/", false},
+ {{"example.com/", kSubdomain, kAnchorNone}, "http://example.com/", true},
+ {{"examp", kSubdomain, kAnchorNone}, "http://example.com/", true},
+ {{"xamp", kSubdomain, kAnchorNone}, "http://example.com/", false},
+ {{"examp", kSubdomain, kAnchorNone}, "http://test.example.com/", true},
+ {{"t.examp", kSubdomain, kAnchorNone}, "http://test.example.com/", false},
+ {{"com^", kSubdomain, kAnchorNone}, "http://test.example.com/", true},
+ {{"x.com", kSubdomain, kAnchorNone}, "http://ex.com/?url=x.com", false},
+ {{"ex.com/", kSubdomain, kBoundary}, "http://ex.com/", true},
+ {{"ex.com^", kSubdomain, kBoundary}, "http://ex.com/", true},
+ {{"ex.co", kSubdomain, kBoundary}, "http://ex.com/", false},
+ {{"ex.com", kSubdomain, kBoundary}, "http://rex.com.ex.com/", false},
+ {{"ex.com/", kSubdomain, kBoundary}, "http://rex.com.ex.com/", true},
+ {{"http", kSubdomain, kBoundary}, "http://http.com/", false},
+ {{"http", kSubdomain, kAnchorNone}, "http://http.com/", true},
+ {{"/example.com", kSubdomain, kBoundary}, "http://example.com/", false},
+ {{"/example.com/", kSubdomain, kBoundary}, "http://example.com/", false},
+ };
+
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message()
+ << "Rule: " << test_case.url_pattern.url_pattern
+ << "; Anchors: "
+ << static_cast<int>(test_case.url_pattern.anchor_left) << ", "
+ << static_cast<int>(test_case.url_pattern.anchor_right)
+ << "; URL: " << GURL(test_case.url));
+
+ std::vector<size_t> failure;
+ BuildFailureFunction(test_case.url_pattern, &failure);
+ const bool is_match =
+ IsUrlPatternMatch(GURL(test_case.url), test_case.url_pattern,
+ failure.begin(), failure.end());
+ EXPECT_EQ(test_case.expect_match, is_match);
+ }
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/suggestions.gypi b/chromium/components/suggestions.gypi
deleted file mode 100644
index f5fd5fc3ed8..00000000000
--- a/chromium/components/suggestions.gypi
+++ /dev/null
@@ -1,59 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/suggestions
- 'target_name': 'suggestions',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../ui/gfx/gfx.gyp:gfx',
- '../url/url.gyp:url_lib',
- 'components.gyp:data_use_measurement_core',
- 'components.gyp:image_fetcher',
- 'components.gyp:keyed_service_core',
- 'components.gyp:pref_registry',
- 'components.gyp:sync_driver',
- 'components.gyp:variations',
- 'components.gyp:variations_net',
- ],
- 'sources': [
- 'suggestions/blacklist_store.cc',
- 'suggestions/blacklist_store.h',
- 'suggestions/image_encoder.h',
- 'suggestions/image_manager.cc',
- 'suggestions/image_manager.h',
- 'suggestions/proto/suggestions.proto',
- 'suggestions/suggestions_pref_names.cc',
- 'suggestions/suggestions_pref_names.h',
- 'suggestions/suggestions_service.cc',
- 'suggestions/suggestions_service.h',
- 'suggestions/suggestions_store.cc',
- 'suggestions/suggestions_store.h',
- ],
- 'variables': {
- 'proto_in_dir': 'suggestions/proto',
- 'proto_out_dir': 'components/suggestions/proto',
- },
- 'includes': [ '../build/protoc.gypi' ],
- 'conditions': [
- ['OS == "ios"', {
- 'sources': [
- 'suggestions/image_encoder_ios.mm',
- ]
- }, { # 'OS != "ios"'
- 'sources': [
- 'suggestions/image_encoder.cc',
- ]
- }
- ]]
- },
- ],
-}
diff --git a/chromium/components/suggestions/BUILD.gn b/chromium/components/suggestions/BUILD.gn
index 40ac92f0ef1..174726add9b 100644
--- a/chromium/components/suggestions/BUILD.gn
+++ b/chromium/components/suggestions/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("suggestions") {
+static_library("suggestions") {
sources = [
"blacklist_store.cc",
"blacklist_store.h",
@@ -33,7 +33,7 @@ source_set("suggestions") {
"//components/leveldb_proto",
"//components/pref_registry",
"//components/signin/core/browser",
- "//components/sync_driver:sync_driver",
+ "//components/sync",
"//components/variations",
"//components/variations/net",
"//google_apis",
@@ -61,7 +61,7 @@ source_set("unit_tests") {
"//components/leveldb_proto:test_support",
"//components/pref_registry:test_support",
"//components/signin/core/browser:test_support",
- "//components/sync_driver:test_support",
+ "//components/sync:test_support_sync_driver",
"//net:test_support",
"//testing/gmock",
"//testing/gtest",
diff --git a/chromium/components/suggestions/DEPS b/chromium/components/suggestions/DEPS
index c3f05896dd0..78c843337ca 100644
--- a/chromium/components/suggestions/DEPS
+++ b/chromium/components/suggestions/DEPS
@@ -7,7 +7,7 @@ include_rules = [
"+components/pref_registry",
"+components/prefs",
"+components/signin/core/browser",
- "+components/sync_driver",
+ "+components/sync/driver",
"+components/variations",
"+google_apis",
"+net",
diff --git a/chromium/components/suggestions/image_encoder_ios.mm b/chromium/components/suggestions/image_encoder_ios.mm
index 1fe64d056ea..d182926bb82 100644
--- a/chromium/components/suggestions/image_encoder_ios.mm
+++ b/chromium/components/suggestions/image_encoder_ios.mm
@@ -17,8 +17,8 @@ std::unique_ptr<SkBitmap> DecodeJPEGToSkBitmap(const void* encoded_data,
size_t size) {
NSData* data = [NSData dataWithBytes:encoded_data length:size];
UIImage* image = [UIImage imageWithData:data scale:1.0];
- return base::WrapUnique(
- new SkBitmap(skia::CGImageToSkBitmap(image.CGImage, [image size], YES)));
+ return base::MakeUnique<SkBitmap>(
+ skia::CGImageToSkBitmap(image.CGImage, [image size], YES));
}
bool EncodeSkBitmapToJPEG(const SkBitmap& bitmap,
diff --git a/chromium/components/suggestions/image_manager_unittest.cc b/chromium/components/suggestions/image_manager_unittest.cc
index e0f5b28558c..a5869e8c8f2 100644
--- a/chromium/components/suggestions/image_manager_unittest.cc
+++ b/chromium/components/suggestions/image_manager_unittest.cc
@@ -52,6 +52,7 @@ class MockImageFetcher : public ImageFetcher {
base::Callback<void(const std::string&,
const gfx::Image&)>));
MOCK_METHOD1(SetImageFetcherDelegate, void(ImageFetcherDelegate*));
+ MOCK_METHOD1(SetDataUseServiceName, void(DataUseServiceName));
};
class ImageManagerTest : public testing::Test {
diff --git a/chromium/components/suggestions/suggestions_service.cc b/chromium/components/suggestions/suggestions_service.cc
index cdf80f3d506..16fe605c213 100644
--- a/chromium/components/suggestions/suggestions_service.cc
+++ b/chromium/components/suggestions/suggestions_service.cc
@@ -23,7 +23,7 @@
#include "components/suggestions/blacklist_store.h"
#include "components/suggestions/image_manager.h"
#include "components/suggestions/suggestions_store.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/sync_service.h"
#include "components/variations/net/variations_http_headers.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/oauth2_token_service.h"
@@ -65,7 +65,7 @@ enum SyncState {
SYNC_OR_HISTORY_SYNC_DISABLED,
};
-SyncState GetSyncState(sync_driver::SyncService* sync) {
+SyncState GetSyncState(syncer::SyncService* sync) {
if (!sync || !sync->CanSyncStart())
return SYNC_OR_HISTORY_SYNC_DISABLED;
if (!sync->IsSyncActive() || !sync->ConfigurationDone())
@@ -196,7 +196,7 @@ class SuggestionsService::AccessTokenFetcher
SuggestionsService::SuggestionsService(
const SigninManagerBase* signin_manager,
OAuth2TokenService* token_service,
- sync_driver::SyncService* sync_service,
+ syncer::SyncService* sync_service,
net::URLRequestContextGetter* url_request_context,
std::unique_ptr<SuggestionsStore> suggestions_store,
std::unique_ptr<ImageManager> thumbnail_manager,
diff --git a/chromium/components/suggestions/suggestions_service.h b/chromium/components/suggestions/suggestions_service.h
index d29f15edca7..5b118e11d2a 100644
--- a/chromium/components/suggestions/suggestions_service.h
+++ b/chromium/components/suggestions/suggestions_service.h
@@ -20,29 +20,29 @@
#include "base/time/time.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/suggestions/proto/suggestions.pb.h"
-#include "components/sync_driver/sync_service_observer.h"
+#include "components/sync/driver/sync_service_observer.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "url/gurl.h"
+class OAuth2TokenService;
+class SigninManagerBase;
+
namespace gfx {
class Image;
-}
+} // namespce gfx
namespace net {
class URLRequestContextGetter;
} // namespace net
-namespace sync_driver {
+namespace syncer {
class SyncService;
-}
+} // namespace syncer
namespace user_prefs {
class PrefRegistrySyncable;
} // namespace user_prefs
-class OAuth2TokenService;
-class SigninManagerBase;
-
namespace suggestions {
class BlacklistStore;
@@ -52,7 +52,7 @@ class SuggestionsStore;
// An interface to fetch server suggestions asynchronously.
class SuggestionsService : public KeyedService,
public net::URLFetcherDelegate,
- public sync_driver::SyncServiceObserver {
+ public syncer::SyncServiceObserver {
public:
using ResponseCallback = base::Callback<void(const SuggestionsProfile&)>;
using BitmapCallback = base::Callback<void(const GURL&, const gfx::Image&)>;
@@ -62,7 +62,7 @@ class SuggestionsService : public KeyedService,
SuggestionsService(const SigninManagerBase* signin_manager,
OAuth2TokenService* token_service,
- sync_driver::SyncService* sync_service,
+ syncer::SyncService* sync_service,
net::URLRequestContextGetter* url_request_context,
std::unique_ptr<SuggestionsStore> suggestions_store,
std::unique_ptr<ImageManager> thumbnail_manager,
@@ -137,7 +137,7 @@ class SuggestionsService : public KeyedService,
static GURL BuildSuggestionsBlacklistURL(const GURL& candidate_url);
static GURL BuildSuggestionsBlacklistClearURL();
- // sync_driver::SyncServiceObserver implementation.
+ // syncer::SyncServiceObserver implementation.
void OnStateChanged() override;
// Sets default timestamp for suggestions which do not have expiry timestamp.
@@ -188,8 +188,8 @@ class SuggestionsService : public KeyedService,
base::ThreadChecker thread_checker_;
- sync_driver::SyncService* sync_service_;
- ScopedObserver<sync_driver::SyncService, sync_driver::SyncServiceObserver>
+ syncer::SyncService* sync_service_;
+ ScopedObserver<syncer::SyncService, syncer::SyncServiceObserver>
sync_service_observer_;
net::URLRequestContextGetter* url_request_context_;
diff --git a/chromium/components/suggestions/suggestions_service_unittest.cc b/chromium/components/suggestions/suggestions_service_unittest.cc
index e95923c7ebf..4ba50733719 100644
--- a/chromium/components/suggestions/suggestions_service_unittest.cc
+++ b/chromium/components/suggestions/suggestions_service_unittest.cc
@@ -19,8 +19,8 @@
#include "components/suggestions/image_manager.h"
#include "components/suggestions/proto/suggestions.pb.h"
#include "components/suggestions/suggestions_store.h"
-#include "components/sync_driver/fake_sync_service.h"
-#include "components/sync_driver/sync_service.h"
+#include "components/sync/driver/fake_sync_service.h"
+#include "components/sync/driver/sync_service.h"
#include "net/base/escape.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
@@ -118,7 +118,7 @@ SuggestionsProfile CreateSuggestionsProfileWithExpiryTimestamps() {
return profile;
}
-class MockSyncService : public sync_driver::FakeSyncService {
+class MockSyncService : public syncer::FakeSyncService {
public:
MockSyncService() {}
virtual ~MockSyncService() {}
@@ -340,7 +340,7 @@ TEST_F(SuggestionsServiceTest, FetchSuggestionsData) {
suggestions_service->FetchSuggestionsData();
// Let the network request run.
- io_message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Ensure that CheckCallback() ran once.
EXPECT_EQ(1, suggestions_data_callback_count_);
@@ -363,7 +363,7 @@ TEST_F(SuggestionsServiceTest, FetchSuggestionsDataSyncNotInitializedEnabled) {
suggestions_service->FetchSuggestionsData();
// Let any network request run.
- io_message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Ensure that CheckCallback() didn't run.
EXPECT_EQ(0, suggestions_data_callback_count_);
@@ -398,7 +398,7 @@ TEST_F(SuggestionsServiceTest, FetchSuggestionsDataSyncDisabled) {
suggestions_service->FetchSuggestionsData();
// Let any network request run.
- io_message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Ensure that CheckCallback didn't run again.
EXPECT_EQ(1, suggestions_data_callback_count_);
@@ -420,7 +420,7 @@ TEST_F(SuggestionsServiceTest, FetchSuggestionsDataNoAccessToken) {
suggestions_service->FetchSuggestionsData();
// No network request should be sent.
- io_message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
EXPECT_FALSE(HasPendingSuggestionsRequest(suggestions_service.get()));
EXPECT_EQ(0, suggestions_data_callback_count_);
}
@@ -443,7 +443,7 @@ TEST_F(SuggestionsServiceTest, IssueRequestIfNoneOngoingError) {
SuggestionsService::BuildSuggestionsURL());
// (Testing only) wait until suggestion fetch is complete.
- io_message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
TEST_F(SuggestionsServiceTest, IssueRequestIfNoneOngoingResponseNotOK) {
@@ -465,7 +465,7 @@ TEST_F(SuggestionsServiceTest, IssueRequestIfNoneOngoingResponseNotOK) {
SuggestionsService::BuildSuggestionsURL());
// (Testing only) wait until suggestion fetch is complete.
- io_message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
// Expect no suggestions in the cache.
SuggestionsProfile empty_suggestions;
@@ -506,12 +506,10 @@ TEST_F(SuggestionsServiceTest, BlacklistURL) {
Blacklist(suggestions_service.get(), blacklisted_url);
EXPECT_EQ(1, suggestions_data_callback_count_);
- // Wait on the upload task. This only works when the scheduling task is not
- // for future execution (note how both the SuggestionsService's scheduling
- // delay and the BlacklistStore's candidacy delay are zero). Then wait on
- // the blacklist request, then again on the next blacklist scheduling task.
- base::RunLoop().RunUntilIdle();
- io_message_loop_.RunUntilIdle();
+ // Wait on the upload task, the blacklist request and the next blacklist
+ // scheduling task. This only works when the scheduling task is not for future
+ // execution (note how both the SuggestionsService's scheduling delay and the
+ // BlacklistStore's candidacy delay are zero).
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2, suggestions_data_callback_count_);
@@ -591,10 +589,6 @@ TEST_F(SuggestionsServiceTest, BlacklistURLRequestFails) {
// RunUntilIdle on the MessageLoop only works when the task is not posted for
// the future.
base::RunLoop().RunUntilIdle();
- io_message_loop_.RunUntilIdle();
- base::RunLoop().RunUntilIdle();
- io_message_loop_.RunUntilIdle();
- base::RunLoop().RunUntilIdle();
CheckSuggestionsData();
}
diff --git a/chromium/components/supervised_user_error_page.gypi b/chromium/components/supervised_user_error_page.gypi
deleted file mode 100644
index a405aa973fb..00000000000
--- a/chromium/components/supervised_user_error_page.gypi
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- 'targets': [
- {
- # GN version: //components/supervused_user_error_page
- 'target_name': 'supervised_user_error_page',
- 'type': 'static_library',
- 'dependencies': [
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- '../base/base.gyp:base',
- '../ui/base/ui_base.gyp:ui_base'
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'supervised_user_error_page/supervised_user_error_page.cc',
- 'supervised_user_error_page/supervised_user_error_page.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/supervised_user_error_page/BUILD.gn b/chromium/components/supervised_user_error_page/BUILD.gn
index 410712845e9..0940bfbcb32 100644
--- a/chromium/components/supervised_user_error_page/BUILD.gn
+++ b/chromium/components/supervised_user_error_page/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("supervised_user_error_page") {
+static_library("supervised_user_error_page") {
sources = [
"supervised_user_error_page.cc",
"supervised_user_error_page.h",
@@ -14,6 +14,30 @@ source_set("supervised_user_error_page") {
"//components/strings",
"//ui/base",
]
+
+ if (target_os == "android") {
+ sources += [
+ "supervised_user_error_page_android.cc",
+ "supervised_user_error_page_android.h",
+ ]
+ deps += [ "//components/web_restrictions:interfaces" ]
+ }
+}
+
+if (target_os == "android") {
+ source_set("gin") {
+ sources = [
+ "gin_wrapper.cc",
+ "gin_wrapper.h",
+ ]
+ deps = [
+ "//components/web_restrictions:interfaces",
+ "//content/public/renderer",
+ "//gin",
+ "//third_party/WebKit/public:blink_headers",
+ "//url",
+ ]
+ }
}
source_set("unit_tests") {
diff --git a/chromium/components/supervised_user_error_page/DEPS b/chromium/components/supervised_user_error_page/DEPS
index 9b9f6275336..df1aec067f3 100644
--- a/chromium/components/supervised_user_error_page/DEPS
+++ b/chromium/components/supervised_user_error_page/DEPS
@@ -1,4 +1,10 @@
include_rules = [
- "+ui/base",
+ "+components/web_restrictions/interfaces",
+ "+content/public/renderer",
+ "+gin",
"+grit",
+ "+third_party/WebKit",
+ "+ui/base",
+ "+url",
+ "+v8",
] \ No newline at end of file
diff --git a/chromium/components/supervised_user_error_page/gin_wrapper.cc b/chromium/components/supervised_user_error_page/gin_wrapper.cc
new file mode 100644
index 00000000000..23728d8d7e0
--- /dev/null
+++ b/chromium/components/supervised_user_error_page/gin_wrapper.cc
@@ -0,0 +1,112 @@
+// 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 "components/supervised_user_error_page/gin_wrapper.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/renderer/render_frame.h"
+#include "gin/handle.h"
+#include "gin/object_template_builder.h"
+#include "third_party/WebKit/public/web/WebKit.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+
+using web_restrictions::mojom::WebRestrictionsPtr;
+
+namespace supervised_user_error_page {
+
+GinWrapper::Loader::Loader(
+ content::RenderFrame* render_frame,
+ const std::string& url,
+ const web_restrictions::mojom::WebRestrictionsPtr& web_restrictions_service)
+ : content::RenderFrameObserver(render_frame),
+ url_(url),
+ web_restrictions_service_(web_restrictions_service) {}
+
+void GinWrapper::Loader::DidClearWindowObject() {
+
+ InstallGinWrapper();
+
+ // Once the gin wrapper has been installed we don't need to observe the
+ // render frame. Delete the loader so that the wrapper isn't re-installed when
+ // something else is loaded into the frame.
+ delete this;
+}
+
+void GinWrapper::Loader::InstallGinWrapper() {
+ v8::Isolate* isolate = blink::mainThreadIsolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Context> context =
+ render_frame()->GetWebFrame()->mainWorldScriptContext();
+ if (context.IsEmpty())
+ return;
+ v8::Context::Scope context_scope(context);
+ gin::Handle<GinWrapper> controller = gin::CreateHandle(
+ isolate, new GinWrapper(render_frame(), url_, web_restrictions_service_));
+ if (controller.IsEmpty())
+ return;
+ v8::Local<v8::Object> global = context->Global();
+ global->Set(gin::StringToV8(isolate, "webRestrictions"), controller.ToV8());
+}
+
+void GinWrapper::Loader::OnDestruct() {
+ delete this;
+}
+
+gin::WrapperInfo GinWrapper::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+// static
+void GinWrapper::InstallWhenFrameReady(
+ content::RenderFrame* render_frame,
+ const std::string& url,
+ const WebRestrictionsPtr& web_restrictions_service) {
+ new Loader(render_frame, url, web_restrictions_service);
+}
+
+GinWrapper::GinWrapper(content::RenderFrame* render_frame,
+ const std::string& url,
+ const WebRestrictionsPtr& web_restrictions_service)
+ : url_(url),
+ web_restrictions_service_(web_restrictions_service),
+ weak_ptr_factory_(this) {}
+
+GinWrapper::~GinWrapper() {}
+
+bool GinWrapper::RequestPermission(
+ v8::Local<v8::Function> setRequestStatusCallback) {
+ setRequestStatusCallback_.Reset(blink::mainThreadIsolate(),
+ setRequestStatusCallback);
+ web_restrictions_service_->RequestPermission(
+ url_, base::Bind(&GinWrapper::OnAccessRequestAdded,
+ weak_ptr_factory_.GetWeakPtr()));
+ return true;
+}
+
+void GinWrapper::OnAccessRequestAdded(bool success) {
+ if (setRequestStatusCallback_.IsEmpty()) {
+ return;
+ }
+
+ v8::Isolate* isolate = blink::mainThreadIsolate();
+ v8::Local<v8::Value> args = v8::Boolean::New(isolate, success);
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Function> callback =
+ v8::Local<v8::Function>::New(isolate, setRequestStatusCallback_);
+ v8::Local<v8::Context> context = callback->CreationContext();
+ if (context.IsEmpty())
+ return;
+
+ v8::Context::Scope context_scope(context);
+ v8::MicrotasksScope microtasks(isolate,
+ v8::MicrotasksScope::kDoNotRunMicrotasks);
+
+ callback->Call(context->Global(), 1, &args);
+}
+
+gin::ObjectTemplateBuilder GinWrapper::GetObjectTemplateBuilder(
+ v8::Isolate* isolate) {
+ return gin::Wrappable<GinWrapper>::GetObjectTemplateBuilder(isolate)
+ .SetMethod("requestPermission", &GinWrapper::RequestPermission);
+}
+
+} // namespace web_restrictions
diff --git a/chromium/components/supervised_user_error_page/gin_wrapper.h b/chromium/components/supervised_user_error_page/gin_wrapper.h
new file mode 100644
index 00000000000..b59104190b7
--- /dev/null
+++ b/chromium/components/supervised_user_error_page/gin_wrapper.h
@@ -0,0 +1,78 @@
+// 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 COMPONENTS_SUPERVISED_USER_ERROR_PAGE_GIN_WRAPPER_H_
+#define COMPONENTS_SUPERVISED_USER_ERROR_PAGE_GIN_WRAPPER_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/web_restrictions/interfaces/web_restrictions.mojom.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "gin/wrappable.h"
+#include "url/gurl.h"
+#include "v8/include/v8.h"
+
+namespace content {
+class RenderFrame;
+}
+
+namespace supervised_user_error_page {
+
+class GinWrapper : public gin::Wrappable<GinWrapper> {
+ public:
+ static gin::WrapperInfo kWrapperInfo;
+
+ static void InstallWhenFrameReady(
+ content::RenderFrame* render_frame,
+ const std::string& url,
+ const web_restrictions::mojom::WebRestrictionsPtr&
+ web_restrictions_service);
+
+ private:
+ class Loader : public content::RenderFrameObserver {
+ public:
+ Loader(content::RenderFrame* render_frame,
+ const std::string& url,
+ const web_restrictions::mojom::WebRestrictionsPtr&
+ web_restrictions_service);
+ ~Loader() override = default;
+
+ void DidClearWindowObject() override;
+ void OnDestruct() override;
+
+ private:
+ void InstallGinWrapper();
+
+ std::string url_;
+ const web_restrictions::mojom::WebRestrictionsPtr&
+ web_restrictions_service_;
+ DISALLOW_COPY_AND_ASSIGN(Loader);
+ };
+
+ GinWrapper(content::RenderFrame* render_frame,
+ const std::string& url,
+ const web_restrictions::mojom::WebRestrictionsPtr&
+ web_restrictions_service);
+ ~GinWrapper() override;
+
+ // Request permission to allow visiting the currently blocked site.
+ bool RequestPermission(v8::Local<v8::Function> setRequestStatusCallback);
+
+ void OnAccessRequestAdded(bool success);
+
+ // gin::WrappableBase
+ gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) override;
+
+ const std::string url_;
+ const web_restrictions::mojom::WebRestrictionsPtr& web_restrictions_service_;
+ v8::Global<v8::Function> setRequestStatusCallback_;
+ base::WeakPtrFactory<GinWrapper> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GinWrapper);
+};
+
+} // namespace supervised_user_error_page.
+
+#endif // COMPONENTS_SUPERVISED_USER_ERROR_PAGE_GIN_WRAPPER_H_
diff --git a/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.js b/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.js
index ca0bbec39b1..8615994d926 100644
--- a/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.js
+++ b/chromium/components/supervised_user_error_page/resources/supervised_user_block_interstitial.js
@@ -15,7 +15,11 @@ function initialize() {
if (loadTimeData.getBoolean('allowAccessRequests')) {
$('request-access-button').onclick = function(event) {
$('request-access-button').hidden = true;
- sendCommand('request');
+ if (window.domAutomationController) {
+ sendCommand('request');
+ } else {
+ window.webRestrictions.requestPermission(setRequestStatus);
+ }
};
} else {
$('request-access-button').hidden = true;
@@ -48,7 +52,7 @@ function initialize() {
}
var showDetailsLink = loadTimeData.getString('showDetailsLink');
$('show-details-link').hidden = !showDetailsLink;
- $('back-button').hidden = showDetailsLink;
+ $('back-button').hidden = showDetailsLink || !window.domAutomationController;
$('back-button').onclick = function(event) {
sendCommand('back');
};
@@ -66,7 +70,8 @@ function initialize() {
$('information-container').classList.remove('hidden-on-mobile');
$('request-access-button').classList.remove('hidden-on-mobile');
};
- if (loadTimeData.getBoolean('showFeedbackLink')) {
+ if (window.domAutomationController &&
+ loadTimeData.getBoolean('showFeedbackLink')) {
$('feedback-link').onclick = function(event) {
sendCommand('feedback');
};
@@ -80,6 +85,7 @@ function initialize() {
* @param {boolean} isSuccessful Whether the request was successful or not.
*/
function setRequestStatus(isSuccessful) {
+ console.log('setRequestStatus(' + isSuccessful +')');
$('block-page-message').hidden = true;
if (isSuccessful) {
$('request-failed-message').hidden = true;
@@ -87,7 +93,7 @@ function setRequestStatus(isSuccessful) {
$('show-details-link').hidden = true;
$('hide-details-link').hidden = true;
$('details').hidden = true;
- $('back-button').hidden = false;
+ $('back-button').hidden = !window.domAutomationController;
$('request-access-button').hidden = true;
} else {
$('request-failed-message').hidden = false;
diff --git a/chromium/components/supervised_user_error_page/supervised_user_error_page.cc b/chromium/components/supervised_user_error_page/supervised_user_error_page.cc
index ffb0fa8dca3..449c24ceca4 100644
--- a/chromium/components/supervised_user_error_page/supervised_user_error_page.cc
+++ b/chromium/components/supervised_user_error_page/supervised_user_error_page.cc
@@ -5,7 +5,9 @@
#include "components/supervised_user_error_page/supervised_user_error_page.h"
#include "base/macros.h"
+#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "grit/components_resources.h"
#include "grit/components_strings.h"
@@ -83,10 +85,10 @@ int GetBlockMessageID(FilteringBehaviorReason reason,
std::string BuildHtml(bool allow_access_requests,
const std::string& profile_image_url,
const std::string& profile_image_url2,
- const base::string16& custodian,
- const base::string16& custodian_email,
- const base::string16& second_custodian,
- const base::string16& second_custodian_email,
+ const std::string& custodian,
+ const std::string& custodian_email,
+ const std::string& second_custodian,
+ const std::string& second_custodian_email,
bool is_child_account,
FilteringBehaviorReason reason,
const std::string& app_locale) {
@@ -102,10 +104,12 @@ std::string BuildHtml(bool allow_access_requests,
BuildAvatarImageUrl(profile_image_url2, kAvatarSize1x));
strings.SetString("secondAvatarURL2x",
BuildAvatarImageUrl(profile_image_url2, kAvatarSize2x));
- strings.SetString("custodianName", custodian);
- strings.SetString("custodianEmail", custodian_email);
- strings.SetString("secondCustodianName", second_custodian);
- strings.SetString("secondCustodianEmail", second_custodian_email);
+ base::string16 custodian16 = base::UTF8ToUTF16(custodian);
+ strings.SetString("custodianName", custodian16);
+ strings.SetString("custodianEmail", base::UTF8ToUTF16(custodian_email));
+ strings.SetString("secondCustodianName", base::UTF8ToUTF16(second_custodian));
+ strings.SetString("secondCustodianEmail",
+ base::UTF8ToUTF16(second_custodian_email));
base::string16 block_message;
if (allow_access_requests) {
if (is_child_account) {
@@ -114,8 +118,8 @@ std::string BuildHtml(bool allow_access_requests,
? IDS_CHILD_BLOCK_INTERSTITIAL_MESSAGE_SINGLE_PARENT
: IDS_CHILD_BLOCK_INTERSTITIAL_MESSAGE_MULTI_PARENT);
} else {
- block_message =
- l10n_util::GetStringFUTF16(IDS_BLOCK_INTERSTITIAL_MESSAGE, custodian);
+ block_message = l10n_util::GetStringFUTF16(IDS_BLOCK_INTERSTITIAL_MESSAGE,
+ custodian16);
}
} else {
block_message = l10n_util::GetStringUTF16(
@@ -160,9 +164,9 @@ std::string BuildHtml(bool allow_access_requests,
}
} else {
request_sent_message = l10n_util::GetStringFUTF16(
- IDS_BLOCK_INTERSTITIAL_REQUEST_SENT_MESSAGE, custodian);
+ IDS_BLOCK_INTERSTITIAL_REQUEST_SENT_MESSAGE, custodian16);
request_failed_message = l10n_util::GetStringFUTF16(
- IDS_BLOCK_INTERSTITIAL_REQUEST_FAILED_MESSAGE, custodian);
+ IDS_BLOCK_INTERSTITIAL_REQUEST_FAILED_MESSAGE, custodian16);
}
strings.SetString("requestSentMessage", request_sent_message);
strings.SetString("requestFailedMessage", request_failed_message);
@@ -172,7 +176,8 @@ std::string BuildHtml(bool allow_access_requests,
.GetRawDataResource(IDR_SUPERVISED_USER_BLOCK_INTERSTITIAL_HTML)
.as_string();
webui::AppendWebUiCssTextDefaults(&html);
- return webui::GetI18nTemplateHtml(html, &strings);
+ std::string error_html = webui::GetI18nTemplateHtml(html, &strings);
+ return error_html;
}
} // namespace supervised_user_error_page
diff --git a/chromium/components/supervised_user_error_page/supervised_user_error_page.h b/chromium/components/supervised_user_error_page/supervised_user_error_page.h
index 1254b095b80..01ca3e21951 100644
--- a/chromium/components/supervised_user_error_page/supervised_user_error_page.h
+++ b/chromium/components/supervised_user_error_page/supervised_user_error_page.h
@@ -7,8 +7,6 @@
#include <string>
-#include "base/strings/string16.h"
-
namespace supervised_user_error_page {
enum FilteringBehaviorReason {
@@ -27,10 +25,10 @@ int GetBlockMessageID(
std::string BuildHtml(bool allow_access_requests,
const std::string& profile_image_url,
const std::string& profile_image_url2,
- const base::string16& custodian,
- const base::string16& custodian_email,
- const base::string16& second_custodian,
- const base::string16& second_custodian_email,
+ const std::string& custodian,
+ const std::string& custodian_email,
+ const std::string& second_custodian,
+ const std::string& second_custodian_email,
bool is_child_account,
FilteringBehaviorReason reason,
const std::string& app_locale);
diff --git a/chromium/components/supervised_user_error_page/supervised_user_error_page_android.cc b/chromium/components/supervised_user_error_page/supervised_user_error_page_android.cc
new file mode 100644
index 00000000000..280f073b960
--- /dev/null
+++ b/chromium/components/supervised_user_error_page/supervised_user_error_page_android.cc
@@ -0,0 +1,36 @@
+// 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 "components/supervised_user_error_page/supervised_user_error_page_android.h"
+
+#include "base/macros.h"
+#include "components/supervised_user_error_page/supervised_user_error_page.h"
+#include "grit/components_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace supervised_user_error_page {
+
+std::string BuildHtmlFromWebRestrictionsResult(
+ const web_restrictions::mojom::ClientResultPtr& result,
+ const std::string app_locale) {
+ // Check if Webview has the resources it needs to build the error page.
+ // It only will have it is built as Monochrome.
+ if (ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_SUPERVISED_USER_BLOCK_INTERSTITIAL_HTML).empty()) {
+ return std::string();
+ }
+ return BuildHtml(
+ result->intParams["Allow access requests"],
+ result->stringParams["Profile image URL"],
+ result->stringParams["Second profile image URL"],
+ result->stringParams["Custodian"],
+ result->stringParams["Custodian email"],
+ result->stringParams["Second custodian"],
+ result->stringParams["Second custodian email"],
+ result->intParams["Is child account"],
+ static_cast<FilteringBehaviorReason>(result->intParams["Reason"]),
+ app_locale);
+}
+
+} // namespace supervised_user_error_page
diff --git a/chromium/components/supervised_user_error_page/supervised_user_error_page_android.h b/chromium/components/supervised_user_error_page/supervised_user_error_page_android.h
new file mode 100644
index 00000000000..745f8610057
--- /dev/null
+++ b/chromium/components/supervised_user_error_page/supervised_user_error_page_android.h
@@ -0,0 +1,18 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SUPERVISED_USER_ERROR_PAGE_SUPERVISED_USER_ERROR_PAGE_ANDROID_H_
+#define COMPONENTS_SUPERVISED_USER_ERROR_PAGE_SUPERVISED_USER_ERROR_PAGE_ANDROID_H_
+
+#include "components/web_restrictions/interfaces/web_restrictions.mojom.h"
+
+namespace supervised_user_error_page {
+
+std::string BuildHtmlFromWebRestrictionsResult(
+ const web_restrictions::mojom::ClientResultPtr& result,
+ const std::string app_locale);
+
+} // namespace supervised_user_error_page
+
+#endif // COMPONENTS_SUPERVISED_USER_ERROR_PAGE_SUPERVISED_USER_ERROR_PAGE_ANDROID_H_
diff --git a/chromium/components/supervised_user_error_page/supervised_user_error_page_unittest.cc b/chromium/components/supervised_user_error_page/supervised_user_error_page_unittest.cc
index e4c65dabc10..f6b8c391d42 100644
--- a/chromium/components/supervised_user_error_page/supervised_user_error_page_unittest.cc
+++ b/chromium/components/supervised_user_error_page/supervised_user_error_page_unittest.cc
@@ -71,13 +71,11 @@ class SupervisedUserErrorPageTest_BuildHtml
TEST_P(SupervisedUserErrorPageTest_BuildHtml, BuildHtml) {
BuildHtmlTestParameter param = GetParam();
- std::string result =
- BuildHtml(param.allow_access_requests, param.profile_image_url,
- param.profile_image_url2, base::UTF8ToUTF16(param.custodian),
- base::UTF8ToUTF16(param.custodian_email),
- base::UTF8ToUTF16(param.second_custodian),
- base::UTF8ToUTF16(param.second_custodian_email),
- param.is_child_account, param.reason, "");
+ std::string result = BuildHtml(
+ param.allow_access_requests, param.profile_image_url,
+ param.profile_image_url2, param.custodian, param.custodian_email,
+ param.second_custodian, param.second_custodian_email,
+ param.is_child_account, param.reason, "");
// The result should contain the original HTML plus scripts that plug values
// into it. The test can't easily check that the scripts are correct, but
// can check that the output contains the expected values.
diff --git a/chromium/components/sync/BUILD.gn b/chromium/components/sync/BUILD.gn
new file mode 100644
index 00000000000..850ec8f7d64
--- /dev/null
+++ b/chromium/components/sync/BUILD.gn
@@ -0,0 +1,1099 @@
+# 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("//build/buildflag_header.gni")
+import("//build/config/features.gni")
+import("//components/sync/protocol/protocol_sources.gni")
+import("//testing/test.gni")
+
+static_library("sync") {
+ sources = [
+ "api/attachments/attachment.cc",
+ "api/attachments/attachment.h",
+ "api/attachments/attachment_id.cc",
+ "api/attachments/attachment_id.h",
+ "api/attachments/attachment_metadata.cc",
+ "api/attachments/attachment_metadata.h",
+ "api/attachments/attachment_store.cc",
+ "api/attachments/attachment_store.h",
+ "api/attachments/attachment_store_backend.cc",
+ "api/attachments/attachment_store_backend.h",
+ "api/conflict_resolution.cc",
+ "api/conflict_resolution.h",
+ "api/data_batch.h",
+ "api/data_type_error_handler.h",
+ "api/data_type_error_handler_impl.cc",
+ "api/data_type_error_handler_impl.h",
+ "api/entity_change.cc",
+ "api/entity_change.h",
+ "api/entity_data.cc",
+ "api/entity_data.h",
+ "api/local_change_observer.h",
+ "api/metadata_batch.cc",
+ "api/metadata_batch.h",
+ "api/metadata_change_list.h",
+ "api/model_type_change_processor.cc",
+ "api/model_type_change_processor.h",
+ "api/model_type_service.cc",
+ "api/model_type_service.h",
+ "api/model_type_store.cc",
+ "api/model_type_store.h",
+ "api/string_ordinal.h",
+ "api/sync_change.cc",
+ "api/sync_change.h",
+ "api/sync_change_processor.cc",
+ "api/sync_change_processor.h",
+ "api/sync_data.cc",
+ "api/sync_data.h",
+ "api/sync_error.cc",
+ "api/sync_error.h",
+ "api/sync_error_factory.cc",
+ "api/sync_error_factory.h",
+ "api/sync_merge_result.cc",
+ "api/sync_merge_result.h",
+ "api/syncable_service.cc",
+ "api/syncable_service.h",
+ "api/time.h",
+ "base/attachment_id_proto.cc",
+ "base/attachment_id_proto.h",
+ "base/bind_to_task_runner.h",
+ "base/cancelation_observer.cc",
+ "base/cancelation_observer.h",
+ "base/cancelation_signal.cc",
+ "base/cancelation_signal.h",
+ "base/cryptographer.cc",
+ "base/cryptographer.h",
+ "base/data_type_histogram.cc",
+ "base/data_type_histogram.h",
+ "base/encryptor.h",
+ "base/enum_set.h",
+ "base/experiments.h",
+ "base/extensions_activity.cc",
+ "base/extensions_activity.h",
+ "base/get_session_name.cc",
+ "base/get_session_name.h",
+ "base/get_session_name_ios.h",
+ "base/get_session_name_ios.mm",
+ "base/get_session_name_linux.cc",
+ "base/get_session_name_linux.h",
+ "base/get_session_name_mac.h",
+ "base/get_session_name_mac.mm",
+ "base/get_session_name_win.cc",
+ "base/get_session_name_win.h",
+ "base/immutable.h",
+ "base/invalidation_interface.cc",
+ "base/invalidation_interface.h",
+ "base/logging.cc",
+ "base/logging.h",
+ "base/model_type.h",
+ "base/nigori.cc",
+ "base/nigori.h",
+ "base/node_ordinal.cc",
+ "base/node_ordinal.h",
+ "base/ordinal.h",
+ "base/passphrase_type.cc",
+ "base/passphrase_type.h",
+ "base/progress_marker_map.cc",
+ "base/progress_marker_map.h",
+ "base/proto_value_ptr.h",
+ "base/stop_source.h",
+ "base/sync_db_util.h",
+ "base/syncer_error.cc",
+ "base/syncer_error.h",
+ "base/time.cc",
+ "base/time.h",
+ "base/unique_position.cc",
+ "base/unique_position.h",
+ "base/unrecoverable_error_handler.h",
+ "base/unrecoverable_error_info.cc",
+ "base/unrecoverable_error_info.h",
+ "base/weak_handle.cc",
+ "base/weak_handle.h",
+ "core/activation_context.cc",
+ "core/activation_context.h",
+ "core/attachments/attachment_downloader.h",
+ "core/attachments/attachment_downloader_impl.h",
+ "core/attachments/attachment_service.h",
+ "core/attachments/attachment_service_impl.h",
+ "core/attachments/attachment_service_proxy.h",
+ "core/attachments/attachment_service_proxy_for_test.h",
+ "core/attachments/attachment_store_frontend.h",
+ "core/attachments/attachment_uploader.h",
+ "core/attachments/attachment_uploader_impl.h",
+ "core/attachments/attachment_util.h",
+ "core/attachments/fake_attachment_downloader.h",
+ "core/attachments/fake_attachment_uploader.h",
+ "core/attachments/in_memory_attachment_store.h",
+ "core/attachments/on_disk_attachment_store.h",
+ "core/base_node.cc",
+ "core/base_node.h",
+ "core/base_transaction.cc",
+ "core/base_transaction.h",
+ "core/change_record.cc",
+ "core/change_record.h",
+ "core/configure_reason.h",
+ "core/data_batch_impl.cc",
+ "core/data_batch_impl.h",
+ "core/data_type_association_stats.cc",
+ "core/data_type_association_stats.h",
+ "core/data_type_debug_info_listener.cc",
+ "core/data_type_debug_info_listener.h",
+ "core/delete_journal.cc",
+ "core/delete_journal.h",
+ "core/http_bridge.cc",
+ "core/http_bridge.h",
+ "core/http_bridge_network_resources.cc",
+ "core/http_bridge_network_resources.h",
+ "core/http_post_provider_factory.h",
+ "core/http_post_provider_interface.h",
+ "core/internal_components_factory.h",
+ "core/internal_components_factory_impl.cc",
+ "core/internal_components_factory_impl.h",
+ "core/model_type_connector.cc",
+ "core/model_type_connector.h",
+ "core/model_type_processor.cc",
+ "core/model_type_processor.h",
+ "core/model_type_processor_proxy.cc",
+ "core/model_type_processor_proxy.h",
+ "core/model_type_store_backend.cc",
+ "core/model_type_store_backend.h",
+ "core/model_type_store_impl.cc",
+ "core/model_type_store_impl.h",
+ "core/network_resources.h",
+ "core/non_blocking_sync_common.cc",
+ "core/non_blocking_sync_common.h",
+ "core/processor_entity_tracker.cc",
+ "core/processor_entity_tracker.h",
+ "core/read_node.cc",
+ "core/read_node.h",
+ "core/read_transaction.cc",
+ "core/read_transaction.h",
+ "core/shared_model_type_processor.cc",
+ "core/shared_model_type_processor.h",
+ "core/shutdown_reason.h",
+ "core/simple_metadata_change_list.cc",
+ "core/simple_metadata_change_list.h",
+ "core/sync_auth_provider.h",
+ "core/sync_db_util.cc",
+ "core/sync_encryption_handler.cc",
+ "core/sync_encryption_handler.h",
+ "core/sync_manager.cc",
+ "core/sync_manager.h",
+ "core/sync_manager_factory.cc",
+ "core/sync_manager_factory.h",
+ "core/user_share.cc",
+ "core/user_share.h",
+ "core/write_node.cc",
+ "core/write_node.h",
+ "core/write_transaction.cc",
+ "core/write_transaction.h",
+ "core_impl/attachments/attachment_downloader.cc",
+ "core_impl/attachments/attachment_downloader_impl.cc",
+ "core_impl/attachments/attachment_service.cc",
+ "core_impl/attachments/attachment_service_impl.cc",
+ "core_impl/attachments/attachment_service_proxy.cc",
+ "core_impl/attachments/attachment_service_proxy_for_test.cc",
+ "core_impl/attachments/attachment_store_frontend.cc",
+ "core_impl/attachments/attachment_uploader.cc",
+ "core_impl/attachments/attachment_uploader_impl.cc",
+ "core_impl/attachments/attachment_util.cc",
+ "core_impl/attachments/fake_attachment_downloader.cc",
+ "core_impl/attachments/fake_attachment_uploader.cc",
+ "core_impl/attachments/in_memory_attachment_store.cc",
+ "core_impl/attachments/on_disk_attachment_store.cc",
+ "core_impl/attachments/task_queue.cc",
+ "core_impl/change_reorder_buffer.cc",
+ "core_impl/change_reorder_buffer.h",
+ "core_impl/debug_info_event_listener.cc",
+ "core_impl/debug_info_event_listener.h",
+ "core_impl/js_mutation_event_observer.cc",
+ "core_impl/js_mutation_event_observer.h",
+ "core_impl/js_sync_encryption_handler_observer.cc",
+ "core_impl/js_sync_encryption_handler_observer.h",
+ "core_impl/js_sync_manager_observer.cc",
+ "core_impl/js_sync_manager_observer.h",
+ "core_impl/model_type_connector_proxy.cc",
+ "core_impl/model_type_connector_proxy.h",
+ "core_impl/protocol_event_buffer.cc",
+ "core_impl/protocol_event_buffer.h",
+ "core_impl/sync_encryption_handler_impl.cc",
+ "core_impl/sync_encryption_handler_impl.h",
+ "core_impl/sync_manager_impl.cc",
+ "core_impl/sync_manager_impl.h",
+ "core_impl/syncapi_internal.cc",
+ "core_impl/syncapi_internal.h",
+ "core_impl/syncapi_server_connection_manager.cc",
+ "core_impl/syncapi_server_connection_manager.h",
+ "device_info/device_count_metrics_provider.cc",
+ "device_info/device_count_metrics_provider.h",
+ "device_info/device_info.cc",
+ "device_info/device_info.h",
+ "device_info/device_info_data_type_controller.cc",
+ "device_info/device_info_data_type_controller.h",
+ "device_info/device_info_service.cc",
+ "device_info/device_info_service.h",
+ "device_info/device_info_sync_service.cc",
+ "device_info/device_info_sync_service.h",
+ "device_info/device_info_tracker.h",
+ "device_info/device_info_util.cc",
+ "device_info/device_info_util.h",
+ "device_info/local_device_info_provider.h",
+ "device_info/local_device_info_provider_impl.cc",
+ "device_info/local_device_info_provider_impl.h",
+ "driver/about_sync_util.cc",
+ "driver/about_sync_util.h",
+ "driver/backend_data_type_configurer.cc",
+ "driver/backend_data_type_configurer.h",
+ "driver/backend_migrator.cc",
+ "driver/backend_migrator.h",
+ "driver/change_processor.cc",
+ "driver/change_processor.h",
+ "driver/data_type_controller.cc",
+ "driver/data_type_controller.h",
+ "driver/data_type_encryption_handler.cc",
+ "driver/data_type_encryption_handler.h",
+ "driver/data_type_manager.cc",
+ "driver/data_type_manager.h",
+ "driver/data_type_manager_impl.cc",
+ "driver/data_type_manager_impl.h",
+ "driver/data_type_manager_observer.h",
+ "driver/data_type_status_table.cc",
+ "driver/data_type_status_table.h",
+ "driver/directory_data_type_controller.cc",
+ "driver/directory_data_type_controller.h",
+ "driver/frontend_data_type_controller.cc",
+ "driver/frontend_data_type_controller.h",
+ "driver/generic_change_processor.cc",
+ "driver/generic_change_processor.h",
+ "driver/generic_change_processor_factory.cc",
+ "driver/generic_change_processor_factory.h",
+ "driver/glue/browser_thread_model_worker.cc",
+ "driver/glue/browser_thread_model_worker.h",
+ "driver/glue/chrome_report_unrecoverable_error.cc",
+ "driver/glue/chrome_report_unrecoverable_error.h",
+ "driver/glue/sync_backend_host.cc",
+ "driver/glue/sync_backend_host.h",
+ "driver/glue/sync_backend_host_core.cc",
+ "driver/glue/sync_backend_host_core.h",
+ "driver/glue/sync_backend_host_impl.cc",
+ "driver/glue/sync_backend_host_impl.h",
+ "driver/glue/sync_backend_registrar.cc",
+ "driver/glue/sync_backend_registrar.h",
+ "driver/glue/ui_model_worker.cc",
+ "driver/glue/ui_model_worker.h",
+ "driver/invalidation_adapter.cc",
+ "driver/invalidation_adapter.h",
+ "driver/invalidation_helper.cc",
+ "driver/invalidation_helper.h",
+ "driver/model_association_manager.cc",
+ "driver/model_association_manager.h",
+ "driver/model_associator.h",
+ "driver/model_type_controller.cc",
+ "driver/model_type_controller.h",
+ "driver/non_ui_data_type_controller.cc",
+ "driver/non_ui_data_type_controller.h",
+ "driver/pref_names.cc",
+ "driver/pref_names.h",
+ "driver/protocol_event_observer.cc",
+ "driver/protocol_event_observer.h",
+ "driver/proxy_data_type_controller.cc",
+ "driver/proxy_data_type_controller.h",
+ "driver/shared_change_processor.cc",
+ "driver/shared_change_processor.h",
+ "driver/shared_change_processor_ref.cc",
+ "driver/shared_change_processor_ref.h",
+ "driver/signin_manager_wrapper.cc",
+ "driver/signin_manager_wrapper.h",
+ "driver/startup_controller.cc",
+ "driver/startup_controller.h",
+ "driver/sync_api_component_factory.h",
+ "driver/sync_client.cc",
+ "driver/sync_client.h",
+ "driver/sync_driver_switches.cc",
+ "driver/sync_driver_switches.h",
+ "driver/sync_error_controller.cc",
+ "driver/sync_error_controller.h",
+ "driver/sync_frontend.cc",
+ "driver/sync_frontend.h",
+ "driver/sync_prefs.cc",
+ "driver/sync_prefs.h",
+ "driver/sync_service.cc",
+ "driver/sync_service.h",
+ "driver/sync_service_observer.cc",
+ "driver/sync_service_observer.h",
+ "driver/sync_service_utils.cc",
+ "driver/sync_service_utils.h",
+ "driver/sync_stopped_reporter.cc",
+ "driver/sync_stopped_reporter.h",
+ "driver/sync_type_preference_provider.h",
+ "driver/sync_util.cc",
+ "driver/sync_util.h",
+ "driver/system_encryptor.cc",
+ "driver/system_encryptor.h",
+ "driver/ui_data_type_controller.cc",
+ "driver/ui_data_type_controller.h",
+ "driver/user_selectable_sync_type.h",
+ "engine/commit_queue.cc",
+ "engine/commit_queue.h",
+ "engine/cycle/commit_counters.cc",
+ "engine/cycle/commit_counters.h",
+ "engine/cycle/model_neutral_state.cc",
+ "engine/cycle/model_neutral_state.h",
+ "engine/cycle/status_counters.cc",
+ "engine/cycle/status_counters.h",
+ "engine/cycle/sync_cycle_snapshot.cc",
+ "engine/cycle/sync_cycle_snapshot.h",
+ "engine/cycle/type_debug_info_observer.cc",
+ "engine/cycle/type_debug_info_observer.h",
+ "engine/cycle/update_counters.cc",
+ "engine/cycle/update_counters.h",
+ "engine/events/clear_server_data_request_event.cc",
+ "engine/events/clear_server_data_request_event.h",
+ "engine/events/clear_server_data_response_event.cc",
+ "engine/events/clear_server_data_response_event.h",
+ "engine/events/commit_request_event.cc",
+ "engine/events/commit_request_event.h",
+ "engine/events/commit_response_event.cc",
+ "engine/events/commit_response_event.h",
+ "engine/events/configure_get_updates_request_event.cc",
+ "engine/events/configure_get_updates_request_event.h",
+ "engine/events/get_updates_response_event.cc",
+ "engine/events/get_updates_response_event.h",
+ "engine/events/normal_get_updates_request_event.cc",
+ "engine/events/normal_get_updates_request_event.h",
+ "engine/events/poll_get_updates_request_event.cc",
+ "engine/events/poll_get_updates_request_event.h",
+ "engine/events/protocol_event.cc",
+ "engine/events/protocol_event.h",
+ "engine/model_safe_worker.cc",
+ "engine/model_safe_worker.h",
+ "engine/passive_model_worker.cc",
+ "engine/passive_model_worker.h",
+ "engine/polling_constants.cc",
+ "engine/polling_constants.h",
+ "engine/sync_status.cc",
+ "engine/sync_status.h",
+ "engine/sync_string_conversions.cc",
+ "engine/sync_string_conversions.h",
+ "engine_impl/all_status.cc",
+ "engine_impl/all_status.h",
+ "engine_impl/apply_control_data_updates.cc",
+ "engine_impl/apply_control_data_updates.h",
+ "engine_impl/backoff_delay_provider.cc",
+ "engine_impl/backoff_delay_provider.h",
+ "engine_impl/clear_server_data.cc",
+ "engine_impl/clear_server_data.h",
+ "engine_impl/commit.cc",
+ "engine_impl/commit.h",
+ "engine_impl/commit_contribution.cc",
+ "engine_impl/commit_contribution.h",
+ "engine_impl/commit_contributor.cc",
+ "engine_impl/commit_contributor.h",
+ "engine_impl/commit_processor.cc",
+ "engine_impl/commit_processor.h",
+ "engine_impl/commit_util.cc",
+ "engine_impl/commit_util.h",
+ "engine_impl/conflict_resolver.cc",
+ "engine_impl/conflict_resolver.h",
+ "engine_impl/conflict_util.cc",
+ "engine_impl/conflict_util.h",
+ "engine_impl/cycle/data_type_tracker.cc",
+ "engine_impl/cycle/data_type_tracker.h",
+ "engine_impl/cycle/debug_info_getter.h",
+ "engine_impl/cycle/directory_type_debug_info_emitter.cc",
+ "engine_impl/cycle/directory_type_debug_info_emitter.h",
+ "engine_impl/cycle/nudge_tracker.cc",
+ "engine_impl/cycle/nudge_tracker.h",
+ "engine_impl/cycle/status_controller.cc",
+ "engine_impl/cycle/status_controller.h",
+ "engine_impl/cycle/sync_cycle.cc",
+ "engine_impl/cycle/sync_cycle.h",
+ "engine_impl/cycle/sync_cycle_context.cc",
+ "engine_impl/cycle/sync_cycle_context.h",
+ "engine_impl/directory_commit_contribution.cc",
+ "engine_impl/directory_commit_contribution.h",
+ "engine_impl/directory_commit_contributor.cc",
+ "engine_impl/directory_commit_contributor.h",
+ "engine_impl/directory_update_handler.cc",
+ "engine_impl/directory_update_handler.h",
+ "engine_impl/get_commit_ids.cc",
+ "engine_impl/get_commit_ids.h",
+ "engine_impl/get_updates_delegate.cc",
+ "engine_impl/get_updates_delegate.h",
+ "engine_impl/get_updates_processor.cc",
+ "engine_impl/get_updates_processor.h",
+ "engine_impl/model_type_registry.cc",
+ "engine_impl/model_type_registry.h",
+ "engine_impl/model_type_worker.cc",
+ "engine_impl/model_type_worker.h",
+ "engine_impl/net/server_connection_manager.cc",
+ "engine_impl/net/server_connection_manager.h",
+ "engine_impl/net/url_translator.cc",
+ "engine_impl/net/url_translator.h",
+ "engine_impl/non_blocking_type_commit_contribution.cc",
+ "engine_impl/non_blocking_type_commit_contribution.h",
+ "engine_impl/nudge_handler.cc",
+ "engine_impl/nudge_handler.h",
+ "engine_impl/nudge_source.cc",
+ "engine_impl/nudge_source.h",
+ "engine_impl/process_updates_util.cc",
+ "engine_impl/process_updates_util.h",
+ "engine_impl/sync_cycle_event.cc",
+ "engine_impl/sync_cycle_event.h",
+ "engine_impl/sync_engine_event_listener.cc",
+ "engine_impl/sync_engine_event_listener.h",
+ "engine_impl/sync_scheduler.cc",
+ "engine_impl/sync_scheduler.h",
+ "engine_impl/sync_scheduler_impl.cc",
+ "engine_impl/sync_scheduler_impl.h",
+ "engine_impl/syncer.cc",
+ "engine_impl/syncer.h",
+ "engine_impl/syncer_proto_util.cc",
+ "engine_impl/syncer_proto_util.h",
+ "engine_impl/syncer_types.h",
+ "engine_impl/syncer_util.cc",
+ "engine_impl/syncer_util.h",
+ "engine_impl/traffic_logger.cc",
+ "engine_impl/traffic_logger.h",
+ "engine_impl/update_applicator.cc",
+ "engine_impl/update_applicator.h",
+ "engine_impl/update_handler.cc",
+ "engine_impl/update_handler.h",
+ "engine_impl/worker_entity_tracker.cc",
+ "engine_impl/worker_entity_tracker.h",
+ "js/js_backend.h",
+ "js/js_controller.h",
+ "js/js_event_details.cc",
+ "js/js_event_details.h",
+ "js/js_event_handler.h",
+ "js/sync_js_controller.cc",
+ "js/sync_js_controller.h",
+ "protocol/proto_enum_conversions.cc",
+ "protocol/proto_enum_conversions.h",
+ "protocol/proto_value_conversions.cc",
+ "protocol/proto_value_conversions.h",
+ "protocol/sync_protocol_error.cc",
+ "protocol/sync_protocol_error.h",
+ "syncable/dir_open_result.h",
+ "syncable/directory.cc",
+ "syncable/directory.h",
+ "syncable/directory_backing_store.cc",
+ "syncable/directory_backing_store.h",
+ "syncable/directory_change_delegate.h",
+ "syncable/entry.cc",
+ "syncable/entry.h",
+ "syncable/entry_kernel.cc",
+ "syncable/entry_kernel.h",
+ "syncable/in_memory_directory_backing_store.cc",
+ "syncable/in_memory_directory_backing_store.h",
+ "syncable/invalid_directory_backing_store.cc",
+ "syncable/invalid_directory_backing_store.h",
+ "syncable/metahandle_set.h",
+ "syncable/model_neutral_mutable_entry.cc",
+ "syncable/model_neutral_mutable_entry.h",
+ "syncable/model_type.cc",
+ "syncable/mutable_entry.cc",
+ "syncable/mutable_entry.h",
+ "syncable/nigori_handler.cc",
+ "syncable/nigori_handler.h",
+ "syncable/nigori_util.cc",
+ "syncable/nigori_util.h",
+ "syncable/on_disk_directory_backing_store.cc",
+ "syncable/on_disk_directory_backing_store.h",
+ "syncable/parent_child_index.cc",
+ "syncable/parent_child_index.h",
+ "syncable/scoped_kernel_lock.cc",
+ "syncable/scoped_kernel_lock.h",
+ "syncable/scoped_parent_child_index_updater.cc",
+ "syncable/scoped_parent_child_index_updater.h",
+ "syncable/syncable_base_transaction.cc",
+ "syncable/syncable_base_transaction.h",
+ "syncable/syncable_base_write_transaction.cc",
+ "syncable/syncable_base_write_transaction.h",
+ "syncable/syncable_changes_version.h",
+ "syncable/syncable_columns.h",
+ "syncable/syncable_delete_journal.cc",
+ "syncable/syncable_delete_journal.h",
+ "syncable/syncable_enum_conversions.cc",
+ "syncable/syncable_enum_conversions.h",
+ "syncable/syncable_id.cc",
+ "syncable/syncable_id.h",
+ "syncable/syncable_model_neutral_write_transaction.cc",
+ "syncable/syncable_model_neutral_write_transaction.h",
+ "syncable/syncable_proto_util.cc",
+ "syncable/syncable_proto_util.h",
+ "syncable/syncable_read_transaction.cc",
+ "syncable/syncable_read_transaction.h",
+ "syncable/syncable_util.cc",
+ "syncable/syncable_util.h",
+ "syncable/syncable_write_transaction.cc",
+ "syncable/syncable_write_transaction.h",
+ "syncable/transaction_observer.h",
+ "syncable/write_transaction_info.cc",
+ "syncable/write_transaction_info.h",
+ ]
+
+ configs += [ "//build/config:precompiled_headers" ]
+
+ public_deps = [
+ "//components/sync/core_impl/attachments/proto",
+ "//components/sync/protocol",
+ ]
+ deps = [
+ "//base",
+ "//base:i18n",
+ "//base/third_party/dynamic_annotations",
+ "//components/data_use_measurement/core",
+ "//components/invalidation/public",
+ "//components/metrics",
+ "//components/os_crypt",
+ "//components/pref_registry",
+ "//components/prefs",
+ "//components/signin/core/browser",
+ "//components/version_info",
+ "//crypto",
+ "//google_apis",
+ "//net",
+ "//sql",
+ "//third_party/cacheinvalidation",
+ "//third_party/leveldatabase",
+ "//third_party/zlib",
+ "//url",
+ ]
+
+ if (is_android) {
+ deps += [ "//components/sync/android:jni_headers" ]
+ sources += [
+ "android/model_type_helper.cc",
+ "android/model_type_helper.h",
+ "android/sync_jni_registrar.cc",
+ "android/sync_jni_registrar.h",
+ ]
+ }
+
+ if (is_chromeos) {
+ # Required by get_session_name.cc on Chrome OS.
+ deps += [ "//chromeos" ]
+ }
+
+ if (is_mac) {
+ libs = [
+ "CoreFoundation.framework",
+ "SystemConfiguration.framework", # Required by get_session_name_mac.mm.
+ ]
+ }
+
+ if (enable_configuration_policy) {
+ sources += [
+ "driver/sync_policy_handler.cc",
+ "driver/sync_policy_handler.h",
+ ]
+ deps += [
+ "//components/policy:generated",
+ "//components/policy/core/browser",
+ ]
+ }
+
+ configs += [ "//build/config/compiler:wexit_time_destructors" ]
+}
+
+static_library("test_support_sync_core") {
+ testonly = true
+ sources = [
+ "base/fake_encryptor.cc",
+ "base/fake_encryptor.h",
+ "base/mock_unrecoverable_error_handler.cc",
+ "base/mock_unrecoverable_error_handler.h",
+ "base/model_type_test_util.cc",
+ "base/model_type_test_util.h",
+ "base/test_unrecoverable_error_handler.cc",
+ "base/test_unrecoverable_error_handler.h",
+ "engine_impl/cycle/mock_debug_info_getter.cc",
+ "engine_impl/cycle/mock_debug_info_getter.h",
+ "engine_impl/cycle/test_util.cc",
+ "engine_impl/cycle/test_util.h",
+ "js/js_test_util.cc",
+ "js/js_test_util.h",
+ "test/callback_counter.h",
+ "test/directory_backing_store_corruption_testing.cc",
+ "test/directory_backing_store_corruption_testing.h",
+ "test/engine/fake_model_worker.cc",
+ "test/engine/fake_model_worker.h",
+ "test/engine/fake_sync_scheduler.cc",
+ "test/engine/fake_sync_scheduler.h",
+ "test/engine/mock_connection_manager.cc",
+ "test/engine/mock_connection_manager.h",
+ "test/engine/mock_model_type_processor.cc",
+ "test/engine/mock_model_type_processor.h",
+ "test/engine/mock_model_type_worker.cc",
+ "test/engine/mock_model_type_worker.h",
+ "test/engine/mock_nudge_handler.cc",
+ "test/engine/mock_nudge_handler.h",
+ "test/engine/mock_update_handler.cc",
+ "test/engine/mock_update_handler.h",
+ "test/engine/single_type_mock_server.cc",
+ "test/engine/single_type_mock_server.h",
+ "test/engine/test_directory_setter_upper.cc",
+ "test/engine/test_directory_setter_upper.h",
+ "test/engine/test_id_factory.h",
+ "test/engine/test_syncable_utils.cc",
+ "test/engine/test_syncable_utils.h",
+ "test/fake_sync_encryption_handler.cc",
+ "test/fake_sync_encryption_handler.h",
+ "test/mock_invalidation.cc",
+ "test/mock_invalidation.h",
+ "test/mock_invalidation_tracker.cc",
+ "test/mock_invalidation_tracker.h",
+ "test/null_directory_change_delegate.cc",
+ "test/null_directory_change_delegate.h",
+ "test/null_transaction_observer.cc",
+ "test/null_transaction_observer.h",
+ "test/test_directory_backing_store.cc",
+ "test/test_directory_backing_store.h",
+ "test/test_transaction_observer.cc",
+ "test/test_transaction_observer.h",
+ "test/trackable_mock_invalidation.cc",
+ "test/trackable_mock_invalidation.h",
+ ]
+
+ public_deps = [
+ "//base",
+ "//components/sync",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+
+ defines = [ "SYNC_TEST" ]
+ configs += [ "//build/config/compiler:wexit_time_destructors" ]
+}
+
+static_library("test_support_sync_core_impl") {
+ testonly = true
+ sources = [
+ "api/data_type_error_handler_mock.cc",
+ "api/data_type_error_handler_mock.h",
+ "core/test/fake_model_type_connector.h",
+ "core/test/fake_model_type_processor.h",
+ "core/test/fake_sync_manager.h",
+ "core/test/model_type_store_test_util.h",
+ "core/test/sync_manager_factory_for_profile_sync_test.h",
+ "core/test/test_entry_factory.h",
+ "core/test/test_internal_components_factory.h",
+ "core/test/test_user_share.h",
+ "core_impl/test/fake_model_type_connector.cc",
+ "core_impl/test/fake_model_type_processor.cc",
+ "core_impl/test/fake_sync_manager.cc",
+ "core_impl/test/model_type_store_test_util.cc",
+ "core_impl/test/sync_manager_factory_for_profile_sync_test.cc",
+ "core_impl/test/sync_manager_for_profile_sync_test.cc",
+ "core_impl/test/sync_manager_for_profile_sync_test.h",
+ "core_impl/test/test_entry_factory.cc",
+ "core_impl/test/test_internal_components_factory.cc",
+ "core_impl/test/test_user_share.cc",
+ ]
+
+ public_deps = [
+ ":test_support_sync_core",
+ "//base",
+ "//components/sync",
+ "//testing/gtest",
+ ]
+
+ defines = [ "SYNC_TEST" ]
+ configs += [ "//build/config/compiler:wexit_time_destructors" ]
+}
+
+static_library("test_support_sync_api") {
+ testonly = true
+ sources = [
+ "api/fake_model_type_change_processor.cc",
+ "api/fake_model_type_change_processor.h",
+ "api/fake_model_type_service.cc",
+ "api/fake_model_type_service.h",
+ "api/fake_sync_change_processor.cc",
+ "api/fake_sync_change_processor.h",
+ "api/fake_syncable_service.cc",
+ "api/fake_syncable_service.h",
+ "api/mock_model_type_store.cc",
+ "api/mock_model_type_store.h",
+ "api/stub_model_type_service.cc",
+ "api/stub_model_type_service.h",
+ "api/sync_change_processor_wrapper_for_test.cc",
+ "api/sync_change_processor_wrapper_for_test.h",
+ "api/sync_error_factory_mock.cc",
+ "api/sync_error_factory_mock.h",
+ ]
+
+ defines = [ "SYNC_TEST" ]
+
+ public_deps = [
+ "//base",
+ "//components/sync",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
+static_library("test_support_sync_driver") {
+ testonly = true
+ sources = [
+ "device_info/local_device_info_provider_mock.cc",
+ "device_info/local_device_info_provider_mock.h",
+ "driver/change_processor_mock.cc",
+ "driver/change_processor_mock.h",
+ "driver/data_type_controller_mock.cc",
+ "driver/data_type_controller_mock.h",
+ "driver/data_type_manager_mock.cc",
+ "driver/data_type_manager_mock.h",
+ "driver/fake_data_type_controller.cc",
+ "driver/fake_data_type_controller.h",
+ "driver/fake_generic_change_processor.cc",
+ "driver/fake_generic_change_processor.h",
+ "driver/fake_sync_client.cc",
+ "driver/fake_sync_client.h",
+ "driver/fake_sync_service.cc",
+ "driver/fake_sync_service.h",
+ "driver/frontend_data_type_controller_mock.cc",
+ "driver/frontend_data_type_controller_mock.h",
+ "driver/glue/sync_backend_host_mock.cc",
+ "driver/glue/sync_backend_host_mock.h",
+ "driver/model_associator_mock.cc",
+ "driver/model_associator_mock.h",
+ "driver/non_ui_data_type_controller_mock.cc",
+ "driver/non_ui_data_type_controller_mock.h",
+ "driver/sync_api_component_factory_mock.cc",
+ "driver/sync_api_component_factory_mock.h",
+ ]
+
+ public_deps = [
+ "//components/sync",
+ ]
+
+ deps = [
+ ":test_support_sync_core_impl",
+ "//base",
+ "//components/syncable_prefs:test_support",
+ "//components/version_info",
+ "//google_apis",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "api/attachments/attachment_id_unittest.cc",
+ "api/attachments/attachment_metadata_unittest.cc",
+ "api/attachments/attachment_unittest.cc",
+ "api/entity_data_unittest.cc",
+ "api/model_type_service_unittest.cc",
+ "api/sync_change_unittest.cc",
+ "api/sync_data_unittest.cc",
+ "api/sync_error_unittest.cc",
+ "api/sync_merge_result_unittest.cc",
+ "base/attachment_id_proto_unittest.cc",
+ "base/bind_to_task_runner_unittest.cc",
+ "base/cancelation_signal_unittest.cc",
+ "base/cryptographer_unittest.cc",
+ "base/data_type_histogram_unittest.cc",
+ "base/enum_set_unittest.cc",
+ "base/get_session_name_unittest.cc",
+ "base/immutable_unittest.cc",
+ "base/nigori_unittest.cc",
+ "base/node_ordinal_unittest.cc",
+ "base/ordinal_unittest.cc",
+ "base/proto_value_ptr_unittest.cc",
+ "base/protobuf_unittest.cc",
+ "base/unique_position_unittest.cc",
+ "base/weak_handle_unittest.cc",
+ "core/change_record_unittest.cc",
+ "core/data_batch_impl_unittest.cc",
+ "core/http_bridge_unittest.cc",
+ "core/model_type_store_backend_unittest.cc",
+ "core/model_type_store_impl_unittest.cc",
+ "core/processor_entity_tracker_unittest.cc",
+ "core/shared_model_type_processor_unittest.cc",
+ "core/simple_metadata_change_list_unittest.cc",
+ "core_impl/attachments/attachment_downloader_impl_unittest.cc",
+ "core_impl/attachments/attachment_service_impl_unittest.cc",
+ "core_impl/attachments/attachment_service_proxy_unittest.cc",
+ "core_impl/attachments/attachment_store_frontend_unittest.cc",
+ "core_impl/attachments/attachment_store_test_template.h",
+ "core_impl/attachments/attachment_uploader_impl_unittest.cc",
+ "core_impl/attachments/fake_attachment_downloader_unittest.cc",
+ "core_impl/attachments/fake_attachment_uploader_unittest.cc",
+ "core_impl/attachments/in_memory_attachment_store_unittest.cc",
+ "core_impl/attachments/on_disk_attachment_store_unittest.cc",
+ "core_impl/attachments/task_queue_unittest.cc",
+ "core_impl/debug_info_event_listener_unittest.cc",
+ "core_impl/js_mutation_event_observer_unittest.cc",
+ "core_impl/js_sync_encryption_handler_observer_unittest.cc",
+ "core_impl/js_sync_manager_observer_unittest.cc",
+ "core_impl/model_type_connector_proxy_unittest.cc",
+ "core_impl/protocol_event_buffer_unittest.cc",
+ "core_impl/sync_encryption_handler_impl_unittest.cc",
+ "core_impl/sync_manager_impl_unittest.cc",
+ "core_impl/syncapi_server_connection_manager_unittest.cc",
+ "device_info/device_count_metrics_provider_unittest.cc",
+ "device_info/device_info_data_type_controller_unittest.cc",
+ "device_info/device_info_service_unittest.cc",
+ "device_info/device_info_sync_service_unittest.cc",
+ "device_info/device_info_util_unittest.cc",
+ "device_info/local_device_info_provider_impl_unittest.cc",
+ "driver/about_sync_util_unittest.cc",
+ "driver/backend_migrator_unittest.cc",
+ "driver/data_type_manager_impl_unittest.cc",
+ "driver/frontend_data_type_controller_unittest.cc",
+ "driver/generic_change_processor_unittest.cc",
+ "driver/glue/browser_thread_model_worker_unittest.cc",
+ "driver/glue/sync_backend_host_impl_unittest.cc",
+ "driver/glue/sync_backend_registrar_unittest.cc",
+ "driver/glue/ui_model_worker_unittest.cc",
+ "driver/model_association_manager_unittest.cc",
+ "driver/model_type_controller_unittest.cc",
+ "driver/non_ui_data_type_controller_unittest.cc",
+ "driver/shared_change_processor_unittest.cc",
+ "driver/startup_controller_unittest.cc",
+ "driver/sync_prefs_unittest.cc",
+ "driver/sync_stopped_reporter_unittest.cc",
+ "driver/sync_util_unittest.cc",
+ "driver/system_encryptor_unittest.cc",
+ "driver/ui_data_type_controller_unittest.cc",
+ "engine/cycle/sync_cycle_snapshot_unittest.cc",
+ "engine/model_safe_worker_unittest.cc",
+ "engine_impl/apply_control_data_updates_unittest.cc",
+ "engine_impl/backoff_delay_provider_unittest.cc",
+ "engine_impl/cycle/nudge_tracker_unittest.cc",
+ "engine_impl/cycle/status_controller_unittest.cc",
+ "engine_impl/directory_commit_contribution_unittest.cc",
+ "engine_impl/directory_update_handler_unittest.cc",
+ "engine_impl/get_updates_processor_unittest.cc",
+ "engine_impl/model_type_registry_unittest.cc",
+ "engine_impl/model_type_worker_unittest.cc",
+ "engine_impl/sync_scheduler_impl_unittest.cc",
+ "engine_impl/syncer_proto_util_unittest.cc",
+ "engine_impl/syncer_unittest.cc",
+ "engine_impl/syncer_util_unittest.cc",
+ "engine_impl/worker_entity_tracker_unittest.cc",
+ "js/js_event_details_unittest.cc",
+ "js/sync_js_controller_unittest.cc",
+ "protocol/proto_enum_conversions_unittest.cc",
+ "protocol/proto_value_conversions_unittest.cc",
+ "syncable/directory_backing_store_unittest.cc",
+ "syncable/directory_unittest.cc",
+ "syncable/directory_unittest.h",
+ "syncable/entry_kernel_unittest.cc",
+ "syncable/model_type_unittest.cc",
+ "syncable/nigori_util_unittest.cc",
+ "syncable/parent_child_index_unittest.cc",
+ "syncable/syncable_enum_conversions_unittest.cc",
+ "syncable/syncable_id_unittest.cc",
+ "syncable/syncable_unittest.cc",
+ "syncable/syncable_util_unittest.cc",
+ ]
+
+ configs += [ "//build/config:precompiled_headers" ]
+
+ data = [
+ "//chrome/test/data/sync/",
+ "//net/tools/testserver/",
+ "//third_party/pyftpdlib/",
+ "//third_party/pywebsocket/",
+ "//third_party/tlslite/",
+ "$root_out_dir/pyproto/google/",
+ ]
+
+ deps = [
+ ":test_support_sync_api",
+ ":test_support_sync_core",
+ ":test_support_sync_core_impl",
+ ":test_support_sync_driver",
+ "//base",
+ "//base/test:test_support",
+ "//components/invalidation/impl",
+ "//components/os_crypt:test_support",
+ "//components/pref_registry:test_support",
+ "//components/prefs:test_support",
+ "//components/signin/core/browser:test_support",
+ "//components/sync",
+ "//components/syncable_prefs",
+ "//components/syncable_prefs:test_support",
+ "//components/version_info",
+ "//google_apis",
+ "//google_apis:test_support",
+ "//net",
+ "//net:test_support",
+ "//sql",
+ "//sql:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//third_party/leveldatabase",
+ "//third_party/protobuf:protobuf_lite",
+ "//url",
+ ]
+
+ if (is_chromeos) {
+ # Required by get_session_name_unittest.cc on Chrome OS.
+ deps += [ "//chromeos" ]
+ }
+
+ if (is_ios) {
+ sources -= [ "core/http_bridge_unittest.cc" ]
+ }
+
+ if (enable_configuration_policy) {
+ sources += [ "driver/sync_policy_handler_unittest.cc" ]
+ deps += [
+ "//components/policy:generated",
+ "//components/policy/core/browser",
+ ]
+ }
+
+ defines = [ "SYNC_TEST" ]
+}
+
+static_library("test_support_sync_fake_server") {
+ testonly = true
+ sources = [
+ "test/fake_server/bookmark_entity.cc",
+ "test/fake_server/bookmark_entity.h",
+ "test/fake_server/bookmark_entity_builder.cc",
+ "test/fake_server/bookmark_entity_builder.h",
+ "test/fake_server/entity_builder_factory.cc",
+ "test/fake_server/entity_builder_factory.h",
+ "test/fake_server/fake_server.cc",
+ "test/fake_server/fake_server.h",
+ "test/fake_server/fake_server_entity.cc",
+ "test/fake_server/fake_server_entity.h",
+ "test/fake_server/fake_server_http_post_provider.cc",
+ "test/fake_server/fake_server_http_post_provider.h",
+ "test/fake_server/fake_server_network_resources.cc",
+ "test/fake_server/fake_server_network_resources.h",
+ "test/fake_server/fake_server_verifier.cc",
+ "test/fake_server/fake_server_verifier.h",
+ "test/fake_server/permanent_entity.cc",
+ "test/fake_server/permanent_entity.h",
+ "test/fake_server/sessions_hierarchy.cc",
+ "test/fake_server/sessions_hierarchy.h",
+ "test/fake_server/tombstone_entity.cc",
+ "test/fake_server/tombstone_entity.h",
+ "test/fake_server/unique_client_entity.cc",
+ "test/fake_server/unique_client_entity.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/sync",
+ "//net",
+ "//testing/gtest",
+ "//url",
+ ]
+
+ public_deps = [
+ "//third_party/protobuf:protobuf_lite",
+ ]
+
+ configs += [ "//build/config/compiler:wexit_time_destructors" ]
+}
+
+static_library("test_support_sync_testserver") {
+ testonly = true
+ sources = [
+ "test/local_sync_test_server.cc",
+ "test/local_sync_test_server.h",
+ ]
+
+ configs += [ "//build/config/compiler:wexit_time_destructors" ]
+
+ public_deps = [
+ "//base",
+ "//net:test_support",
+ ]
+ deps = [
+ ":sync",
+
+ # The sync test server uses Python modules generated by the sync protos.
+ "//third_party/protobuf:py_proto",
+ ]
+}
+
+if (!is_ios) {
+ executable("run_sync_testserver") {
+ testonly = true
+ sources = [
+ "tools/testserver/run_sync_testserver.cc",
+ ]
+
+ deps = [
+ ":test_support_sync_testserver",
+ "//base",
+ "//base/test:test_support",
+ "//build/config/sanitizers:deps",
+ "//build/win:default_exe_manifest",
+ "//net:test_support",
+ "//testing/gtest",
+ ]
+ }
+}
+
+if (is_android) {
+ import("//build/config/android/rules.gni")
+
+ generate_jni("fake_server_jni") {
+ testonly = true
+ jni_package = "sync/test/fake_server"
+ sources = [
+ "//chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/FakeServerHelper.java",
+ ]
+ }
+
+ _test_support_sync_prepared_protos_dir =
+ "$root_gen_dir/test_support_sync_proto_java_prepare/"
+ action("test_support_sync_proto_java_prepare") {
+ script = "//components/sync/protocol/prepare_protos_for_java_tests.py"
+ inputs = sync_protocol_sources
+ outputs = process_file_template(
+ sync_protocol_sources,
+ [ "$_test_support_sync_prepared_protos_dir/{{source_file_part}}" ])
+ args = [
+ "--output_dir",
+ rebase_path(_test_support_sync_prepared_protos_dir, root_build_dir),
+ ]
+ args += rebase_path(sync_protocol_sources, root_build_dir)
+ }
+
+ proto_java_library("test_support_sync_proto_java") {
+ proto_path = _test_support_sync_prepared_protos_dir
+ sources = get_target_outputs(":test_support_sync_proto_java_prepare")
+ deps = [
+ ":test_support_sync_proto_java_prepare",
+ ]
+ }
+
+ android_library("sync_java_test_support") {
+ testonly = true
+ deps = [
+ "android:sync_java",
+ "//base:base_java",
+ ]
+ java_files = [ "test/android/javatests/src/org/chromium/components/sync/test/util/MockSyncContentResolverDelegate.java" ]
+ }
+
+ static_library("test_support_sync_fake_server_android") {
+ testonly = true
+ sources = [
+ "test/fake_server/android/fake_server_helper_android.cc",
+ "test/fake_server/android/fake_server_helper_android.h",
+ ]
+ deps = [
+ ":fake_server_jni",
+ ":sync",
+ ":test_support_sync_fake_server",
+ "//base",
+ "//testing/gtest",
+ "//url:url",
+ ]
+ }
+}
diff --git a/chromium/components/sync/android/BUILD.gn b/chromium/components/sync/android/BUILD.gn
new file mode 100644
index 00000000000..f386884a2d9
--- /dev/null
+++ b/chromium/components/sync/android/BUILD.gn
@@ -0,0 +1,69 @@
+# 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("//build/config/android/config.gni")
+import("//build/config/android/rules.gni")
+
+android_library("sync_java") {
+ deps = [
+ "//base:base_java",
+ "//components/signin/core/browser/android:java",
+ "//net/android:net_java",
+ "//third_party/android_tools:android_gcm_java",
+ "//third_party/android_tools:android_support_annotations_java",
+ "//third_party/cacheinvalidation:cacheinvalidation_javalib",
+ "//third_party/cacheinvalidation:cacheinvalidation_proto_java",
+ "//third_party/jsr-305:jsr_305_javalib",
+ google_play_services_library,
+ ]
+ srcjar_deps = [ ":java_enums" ]
+ java_files = [
+ "java/src/org/chromium/components/sync/AndroidSyncSettings.java",
+ "java/src/org/chromium/components/sync/ModelTypeHelper.java",
+ "java/src/org/chromium/components/sync/PassphraseType.java",
+ "java/src/org/chromium/components/sync/SyncConstants.java",
+ "java/src/org/chromium/components/sync/SyncContentResolverDelegate.java",
+ "java/src/org/chromium/components/sync/SystemSyncContentResolverDelegate.java",
+ "java/src/org/chromium/components/sync/notifier/InvalidationClientNameGenerator.java",
+ "java/src/org/chromium/components/sync/notifier/InvalidationClientNameProvider.java",
+ "java/src/org/chromium/components/sync/notifier/InvalidationIntentProtocol.java",
+ "java/src/org/chromium/components/sync/notifier/InvalidationPreferences.java",
+ "java/src/org/chromium/components/sync/notifier/RandomizedInvalidationClientNameGenerator.java",
+ ]
+}
+
+android_library("sync_javatests") {
+ testonly = true
+ deps = [
+ ":sync_java",
+ "//base:base_java",
+ "//base:base_java_test_support",
+ "//components/signin/core/browser/android:java",
+ "//components/signin/core/browser/android:signin_java_test_support",
+ "//components/sync:sync_java_test_support",
+ "//third_party/cacheinvalidation:cacheinvalidation_javalib",
+ "//third_party/cacheinvalidation:cacheinvalidation_proto_java",
+ "//third_party/jsr-305:jsr_305_javalib",
+ ]
+ java_files = [
+ "javatests/src/org/chromium/components/sync/AndroidSyncSettingsTest.java",
+ "javatests/src/org/chromium/components/sync/notifier/InvalidationClientNameProviderTest.java",
+ "javatests/src/org/chromium/components/sync/notifier/InvalidationPreferencesTest.java",
+ ]
+}
+
+java_cpp_enum("java_enums") {
+ sources = [
+ "//components/sync/base/model_type.h",
+ "//components/sync/base/stop_source.h",
+ "//components/sync/protocol/sync_protocol_error.h",
+ ]
+}
+
+generate_jni("jni_headers") {
+ sources = [
+ "java/src/org/chromium/components/sync/ModelTypeHelper.java",
+ ]
+ jni_package = "syncer"
+}
diff --git a/chromium/components/sync/core_impl/attachments/proto/BUILD.gn b/chromium/components/sync/core_impl/attachments/proto/BUILD.gn
new file mode 100644
index 00000000000..6ec4b950fdb
--- /dev/null
+++ b/chromium/components/sync/core_impl/attachments/proto/BUILD.gn
@@ -0,0 +1,14 @@
+# 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("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+ # This should only get compiled into the sync component.
+ visibility = [ "//components/sync" ]
+
+ sources = [
+ "attachment_store.proto",
+ ]
+}
diff --git a/chromium/components/sync/protocol/BUILD.gn b/chromium/components/sync/protocol/BUILD.gn
new file mode 100644
index 00000000000..50c3e7fa9a6
--- /dev/null
+++ b/chromium/components/sync/protocol/BUILD.gn
@@ -0,0 +1,11 @@
+# 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("//third_party/protobuf/proto_library.gni")
+import("protocol_sources.gni")
+
+proto_library("protocol") {
+ sources = sync_protocol_sources
+ extra_configs = [ "//build/config/compiler:wexit_time_destructors" ]
+}
diff --git a/chromium/components/sync/protocol/protocol_sources.gni b/chromium/components/sync/protocol/protocol_sources.gni
new file mode 100644
index 00000000000..a34b214bab4
--- /dev/null
+++ b/chromium/components/sync/protocol/protocol_sources.gni
@@ -0,0 +1,52 @@
+# 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.
+
+sync_protocol_sources = [
+ "//components/sync/protocol/app_notification_specifics.proto",
+ "//components/sync/protocol/app_setting_specifics.proto",
+ "//components/sync/protocol/app_specifics.proto",
+ "//components/sync/protocol/app_list_specifics.proto",
+ "//components/sync/protocol/arc_package_specifics.proto",
+ "//components/sync/protocol/article_specifics.proto",
+ "//components/sync/protocol/attachments.proto",
+ "//components/sync/protocol/autofill_specifics.proto",
+ "//components/sync/protocol/bookmark_specifics.proto",
+ "//components/sync/protocol/client_commands.proto",
+ "//components/sync/protocol/client_debug_info.proto",
+ "//components/sync/protocol/device_info_specifics.proto",
+ "//components/sync/protocol/dictionary_specifics.proto",
+ "//components/sync/protocol/encryption.proto",
+ "//components/sync/protocol/entity_metadata.proto",
+ "//components/sync/protocol/experiment_status.proto",
+ "//components/sync/protocol/experiments_specifics.proto",
+ "//components/sync/protocol/extension_setting_specifics.proto",
+ "//components/sync/protocol/extension_specifics.proto",
+ "//components/sync/protocol/favicon_image_specifics.proto",
+ "//components/sync/protocol/favicon_tracking_specifics.proto",
+ "//components/sync/protocol/get_updates_caller_info.proto",
+ "//components/sync/protocol/history_delete_directive_specifics.proto",
+ "//components/sync/protocol/history_status.proto",
+ "//components/sync/protocol/nigori_specifics.proto",
+ "//components/sync/protocol/managed_user_setting_specifics.proto",
+ "//components/sync/protocol/managed_user_shared_setting_specifics.proto",
+ "//components/sync/protocol/managed_user_specifics.proto",
+ "//components/sync/protocol/managed_user_whitelist_specifics.proto",
+ "//components/sync/protocol/model_type_state.proto",
+ "//components/sync/protocol/password_specifics.proto",
+ "//components/sync/protocol/preference_specifics.proto",
+ "//components/sync/protocol/printer_specifics.proto",
+ "//components/sync/protocol/priority_preference_specifics.proto",
+ "//components/sync/protocol/reading_list_specifics.proto",
+ "//components/sync/protocol/search_engine_specifics.proto",
+ "//components/sync/protocol/session_specifics.proto",
+ "//components/sync/protocol/sync.proto",
+ "//components/sync/protocol/sync_enums.proto",
+ "//components/sync/protocol/synced_notification_app_info_specifics.proto",
+ "//components/sync/protocol/synced_notification_specifics.proto",
+ "//components/sync/protocol/test.proto",
+ "//components/sync/protocol/theme_specifics.proto",
+ "//components/sync/protocol/typed_url_specifics.proto",
+ "//components/sync/protocol/unique_position.proto",
+ "//components/sync/protocol/wifi_credential_specifics.proto",
+]
diff --git a/chromium/components/sync/tools/BUILD.gn b/chromium/components/sync/tools/BUILD.gn
new file mode 100644
index 00000000000..8951abfb3a9
--- /dev/null
+++ b/chromium/components/sync/tools/BUILD.gn
@@ -0,0 +1,54 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//testing/test.gni")
+
+source_set("common") {
+ testonly = true
+
+ sources = [
+ "null_invalidation_state_tracker.cc",
+ "null_invalidation_state_tracker.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/invalidation/impl",
+ "//components/sync",
+ ]
+}
+
+test("sync_listen_notifications") {
+ sources = [
+ "sync_listen_notifications.cc",
+ ]
+
+ defines = [ "SYNC_TEST" ]
+
+ deps = [
+ ":common",
+ "//base",
+ "//components/invalidation/impl",
+ "//components/sync:test_support_sync_core",
+ "//jingle:notifier",
+ "//net:test_support",
+ ]
+}
+
+test("sync_client") {
+ sources = [
+ "sync_client.cc",
+ ]
+
+ defines = [ "SYNC_TEST" ]
+
+ deps = [
+ ":common",
+ "//base",
+ "//components/invalidation/impl",
+ "//components/sync:test_support_sync_core",
+ "//jingle:notifier",
+ "//net:test_support",
+ ]
+}
diff --git a/chromium/components/sync_bookmarks.gypi b/chromium/components/sync_bookmarks.gypi
deleted file mode 100644
index a599993e934..00000000000
--- a/chromium/components/sync_bookmarks.gypi
+++ /dev/null
@@ -1,35 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/sync_bookmarks
- 'target_name': 'sync_bookmarks',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../sync/sync.gyp:sync',
- '../ui/gfx/gfx.gyp:gfx',
- 'bookmarks_browser',
- 'favicon_core',
- 'history_core_browser',
- 'sync_driver',
- 'undo_component',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'sync_bookmarks/bookmark_change_processor.cc',
- 'sync_bookmarks/bookmark_change_processor.h',
- 'sync_bookmarks/bookmark_data_type_controller.cc',
- 'sync_bookmarks/bookmark_data_type_controller.h',
- 'sync_bookmarks/bookmark_model_associator.cc',
- 'sync_bookmarks/bookmark_model_associator.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/sync_bookmarks/BUILD.gn b/chromium/components/sync_bookmarks/BUILD.gn
index a1eb017f43b..12b3607bff8 100644
--- a/chromium/components/sync_bookmarks/BUILD.gn
+++ b/chromium/components/sync_bookmarks/BUILD.gn
@@ -4,7 +4,7 @@
import("//build/config/features.gni")
-source_set("sync_bookmarks") {
+static_library("sync_bookmarks") {
sources = [
"bookmark_change_processor.cc",
"bookmark_change_processor.h",
@@ -19,9 +19,8 @@ source_set("sync_bookmarks") {
"//components/bookmarks/browser",
"//components/favicon/core",
"//components/history/core/browser",
- "//components/sync_driver",
+ "//components/sync",
"//components/undo",
- "//sync",
"//ui/gfx",
]
}
@@ -40,9 +39,8 @@ source_set("unit_tests") {
"//components/bookmarks/test",
"//components/history/core/browser",
"//components/prefs:test_support",
- "//components/sync_driver",
- "//components/sync_driver:test_support",
- "//sync",
+ "//components/sync",
+ "//components/sync:test_support_sync_driver",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/components/sync_bookmarks/DEPS b/chromium/components/sync_bookmarks/DEPS
index 53ccb4a78c5..0d5798c76af 100644
--- a/chromium/components/sync_bookmarks/DEPS
+++ b/chromium/components/sync_bookmarks/DEPS
@@ -4,8 +4,7 @@ include_rules = [
"+components/favicon/core",
"+components/history/core/browser",
"+components/prefs",
- "+components/sync_driver",
+ "+components/sync",
"+components/undo",
- "+sync",
"+ui/gfx",
]
diff --git a/chromium/components/sync_bookmarks/bookmark_change_processor.cc b/chromium/components/sync_bookmarks/bookmark_change_processor.cc
index 5577df49210..f840fe02081 100644
--- a/chromium/components/sync_bookmarks/bookmark_change_processor.cc
+++ b/chromium/components/sync_bookmarks/bookmark_change_processor.cc
@@ -9,7 +9,7 @@
#include <map>
#include <stack>
#include <string>
-#include <vector>
+#include <utility>
#include "base/location.h"
#include "base/strings/string16.h"
@@ -21,15 +21,15 @@
#include "components/bookmarks/browser/bookmark_utils.h"
#include "components/favicon/core/favicon_service.h"
#include "components/history/core/browser/history_service.h"
-#include "components/sync_driver/sync_client.h"
+#include "components/sync/core/change_record.h"
+#include "components/sync/core/read_node.h"
+#include "components/sync/core/write_node.h"
+#include "components/sync/core/write_transaction.h"
+#include "components/sync/driver/sync_client.h"
+#include "components/sync/syncable/entry.h" // TODO(tim): Investigating bug 121587.
+#include "components/sync/syncable/syncable_write_transaction.h"
#include "components/undo/bookmark_undo_service.h"
#include "components/undo/bookmark_undo_utils.h"
-#include "sync/internal_api/public/change_record.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/write_node.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/syncable/entry.h" // TODO(tim): Investigating bug 121587.
-#include "sync/syncable/syncable_write_transaction.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/image/image_util.h"
@@ -38,21 +38,21 @@ using bookmarks::BookmarkNode;
using syncer::ChangeRecord;
using syncer::ChangeRecordList;
-namespace browser_sync {
+namespace sync_bookmarks {
static const char kMobileBookmarksTag[] = "synced_bookmarks";
BookmarkChangeProcessor::BookmarkChangeProcessor(
- sync_driver::SyncClient* sync_client,
+ syncer::SyncClient* sync_client,
BookmarkModelAssociator* model_associator,
- syncer::DataTypeErrorHandler* error_handler)
- : sync_driver::ChangeProcessor(error_handler),
+ std::unique_ptr<syncer::DataTypeErrorHandler> err_handler)
+ : syncer::ChangeProcessor(std::move(err_handler)),
bookmark_model_(NULL),
sync_client_(sync_client),
model_associator_(model_associator) {
DCHECK(model_associator);
DCHECK(sync_client);
- DCHECK(error_handler);
+ DCHECK(error_handler());
}
BookmarkChangeProcessor::~BookmarkChangeProcessor() {
@@ -136,7 +136,7 @@ void BookmarkChangeProcessor::RemoveSyncNodeHierarchy(
syncer::SyncError::DATATYPE_ERROR,
"Failed to init sync node from chrome node",
syncer::BOOKMARKS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
+ error_handler()->OnUnrecoverableError(error);
return;
}
RemoveSyncNodeHierarchy(&trans, &topmost_sync_node, model_associator_);
@@ -310,7 +310,7 @@ int64_t BookmarkChangeProcessor::CreateSyncNode(
if (!PlaceSyncNode(CREATE, parent, index, trans, &sync_child, associator)) {
syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
"Failed to create sync node.", syncer::BOOKMARKS);
- error_handler->OnSingleDataTypeUnrecoverableError(error);
+ error_handler->OnUnrecoverableError(error);
return syncer::kInvalidId;
}
@@ -374,7 +374,7 @@ int64_t BookmarkChangeProcessor::UpdateSyncNode(
syncer::SyncError::DATATYPE_ERROR,
"Failed to init sync node from chrome node",
syncer::BOOKMARKS);
- error_handler->OnSingleDataTypeUnrecoverableError(error);
+ error_handler->OnUnrecoverableError(error);
return syncer::kInvalidId;
}
UpdateSyncNodeProperties(node, model, &sync_node, error_handler);
@@ -416,7 +416,7 @@ void BookmarkChangeProcessor::BookmarkNodeMoved(BookmarkModel* model,
syncer::SyncError::DATATYPE_ERROR,
"Failed to init sync node from chrome node",
syncer::BOOKMARKS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
+ error_handler()->OnUnrecoverableError(error);
return;
}
@@ -426,7 +426,7 @@ void BookmarkChangeProcessor::BookmarkNodeMoved(BookmarkModel* model,
syncer::SyncError::DATATYPE_ERROR,
"Failed to place sync node",
syncer::BOOKMARKS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
+ error_handler()->OnUnrecoverableError(error);
return;
}
}
@@ -488,7 +488,7 @@ void BookmarkChangeProcessor::BookmarkNodeChildrenReordered(
syncer::SyncError::DATATYPE_ERROR,
"Failed to init sync node from chrome node",
syncer::BOOKMARKS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
+ error_handler()->OnUnrecoverableError(error);
return;
}
DCHECK_EQ(sync_child.GetParentId(),
@@ -500,7 +500,7 @@ void BookmarkChangeProcessor::BookmarkNodeChildrenReordered(
syncer::SyncError::DATATYPE_ERROR,
"Failed to place sync node",
syncer::BOOKMARKS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
+ error_handler()->OnUnrecoverableError(error);
return;
}
}
@@ -625,7 +625,7 @@ void BookmarkChangeProcessor::ApplyChangesFromSyncModel(
syncer::SyncError::DATATYPE_ERROR,
"Failed to create foster parent",
syncer::BOOKMARKS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
+ error_handler()->OnUnrecoverableError(error);
return;
}
}
@@ -686,7 +686,7 @@ void BookmarkChangeProcessor::ApplyChangesFromSyncModel(
syncer::SyncError::DATATYPE_ERROR,
"Failed to load sync node",
syncer::BOOKMARKS);
- error_handler()->OnSingleDataTypeUnrecoverableError(error);
+ error_handler()->OnUnrecoverableError(error);
return;
}
@@ -764,7 +764,7 @@ void BookmarkChangeProcessor::UpdateBookmarkWithSyncData(
const syncer::BaseNode& sync_node,
BookmarkModel* model,
const BookmarkNode* node,
- sync_driver::SyncClient* sync_client) {
+ syncer::SyncClient* sync_client) {
DCHECK_EQ(sync_node.GetIsFolder(), node->is_folder());
const sync_pb::BookmarkSpecifics& specifics =
sync_node.GetBookmarkSpecifics();
@@ -800,7 +800,7 @@ const BookmarkNode* BookmarkChangeProcessor::CreateBookmarkNode(
const syncer::BaseNode* sync_node,
const BookmarkNode* parent,
BookmarkModel* model,
- sync_driver::SyncClient* sync_client,
+ syncer::SyncClient* sync_client,
int index) {
return CreateBookmarkNode(base::UTF8ToUTF16(sync_node->GetTitle()),
GURL(sync_node->GetBookmarkSpecifics().url()),
@@ -816,7 +816,7 @@ const BookmarkNode* BookmarkChangeProcessor::CreateBookmarkNode(
const syncer::BaseNode* sync_node,
const BookmarkNode* parent,
BookmarkModel* model,
- sync_driver::SyncClient* sync_client,
+ syncer::SyncClient* sync_client,
int index) {
DCHECK(parent);
@@ -847,7 +847,7 @@ bool BookmarkChangeProcessor::SetBookmarkFavicon(
const syncer::BaseNode* sync_node,
const BookmarkNode* bookmark_node,
BookmarkModel* bookmark_model,
- sync_driver::SyncClient* sync_client) {
+ syncer::SyncClient* sync_client) {
const sync_pb::BookmarkSpecifics& specifics =
sync_node->GetBookmarkSpecifics();
const std::string& icon_bytes_str = specifics.favicon();
@@ -936,7 +936,7 @@ void BookmarkChangeProcessor::SetSyncNodeMetaInfo(
// static
void BookmarkChangeProcessor::ApplyBookmarkFavicon(
const BookmarkNode* bookmark_node,
- sync_driver::SyncClient* sync_client,
+ syncer::SyncClient* sync_client,
const GURL& icon_url,
const scoped_refptr<base::RefCountedMemory>& bitmap_data) {
history::HistoryService* history = sync_client->GetHistoryService();
@@ -977,4 +977,4 @@ bool BookmarkChangeProcessor::CanSyncNode(const BookmarkNode* node) {
return bookmark_model_->client()->CanSyncNode(node);
}
-} // namespace browser_sync
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_bookmarks/bookmark_change_processor.h b/chromium/components/sync_bookmarks/bookmark_change_processor.h
index 4e70d40edc7..df214019d20 100644
--- a/chromium/components/sync_bookmarks/bookmark_change_processor.h
+++ b/chromium/components/sync_bookmarks/bookmark_change_processor.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <memory>
+#include <set>
#include <vector>
#include "base/compiler_specific.h"
@@ -15,37 +16,35 @@
#include "base/threading/thread_checker.h"
#include "components/bookmarks/browser/bookmark_model_observer.h"
#include "components/bookmarks/browser/bookmark_node.h"
+#include "components/sync/api/data_type_error_handler.h"
+#include "components/sync/driver/change_processor.h"
#include "components/sync_bookmarks/bookmark_model_associator.h"
-#include "components/sync_driver/change_processor.h"
-#include "sync/internal_api/public/data_type_error_handler.h"
class Profile;
namespace base {
class RefCountedMemory;
-}
+} // namespace base
namespace syncer {
+class SyncClient;
class WriteNode;
class WriteTransaction;
} // namespace syncer
-namespace sync_driver {
-class SyncClient;
-}
-
-namespace browser_sync {
+namespace sync_bookmarks {
// This class is responsible for taking changes from the BookmarkModel
// and applying them to the sync API 'syncable' model, and vice versa.
// All operations and use of this class are from the UI thread.
// This is currently bookmarks specific.
class BookmarkChangeProcessor : public bookmarks::BookmarkModelObserver,
- public sync_driver::ChangeProcessor {
+ public syncer::ChangeProcessor {
public:
- BookmarkChangeProcessor(sync_driver::SyncClient* sync_client,
- BookmarkModelAssociator* model_associator,
- syncer::DataTypeErrorHandler* error_handler);
+ BookmarkChangeProcessor(
+ syncer::SyncClient* sync_client,
+ BookmarkModelAssociator* model_associator,
+ std::unique_ptr<syncer::DataTypeErrorHandler> error_handler);
~BookmarkChangeProcessor() override;
// bookmarks::BookmarkModelObserver:
@@ -98,7 +97,7 @@ class BookmarkChangeProcessor : public bookmarks::BookmarkModelObserver,
static void UpdateBookmarkWithSyncData(const syncer::BaseNode& sync_node,
bookmarks::BookmarkModel* model,
const bookmarks::BookmarkNode* node,
- sync_driver::SyncClient* sync_client);
+ syncer::SyncClient* sync_client);
// Creates a bookmark node under the given parent node from the given sync
// node. Returns the newly created node. The created node is placed at the
@@ -107,7 +106,7 @@ class BookmarkChangeProcessor : public bookmarks::BookmarkModelObserver,
const syncer::BaseNode* sync_node,
const bookmarks::BookmarkNode* parent,
bookmarks::BookmarkModel* model,
- sync_driver::SyncClient* sync_client,
+ syncer::SyncClient* sync_client,
int index);
// Overload of CreateBookmarkNode function above that helps to avoid
@@ -118,7 +117,7 @@ class BookmarkChangeProcessor : public bookmarks::BookmarkModelObserver,
const syncer::BaseNode* sync_node,
const bookmarks::BookmarkNode* parent,
bookmarks::BookmarkModel* model,
- sync_driver::SyncClient* sync_client,
+ syncer::SyncClient* sync_client,
int index);
// Sets the favicon of the given bookmark node from the given sync node.
@@ -128,14 +127,14 @@ class BookmarkChangeProcessor : public bookmarks::BookmarkModelObserver,
static bool SetBookmarkFavicon(const syncer::BaseNode* sync_node,
const bookmarks::BookmarkNode* bookmark_node,
bookmarks::BookmarkModel* model,
- sync_driver::SyncClient* sync_client);
+ syncer::SyncClient* sync_client);
// Applies the 1x favicon |bitmap_data| and |icon_url| to |bookmark_node|.
// |profile| is the profile that contains the HistoryService and BookmarkModel
// for the bookmark in question.
static void ApplyBookmarkFavicon(
const bookmarks::BookmarkNode* bookmark_node,
- sync_driver::SyncClient* sync_client,
+ syncer::SyncClient* sync_client,
const GURL& icon_url,
const scoped_refptr<base::RefCountedMemory>& bitmap_data);
@@ -248,7 +247,7 @@ class BookmarkChangeProcessor : public bookmarks::BookmarkModelObserver,
// |running_| is true.
bookmarks::BookmarkModel* bookmark_model_;
- sync_driver::SyncClient* sync_client_;
+ syncer::SyncClient* sync_client_;
// The two models should be associated according to this ModelAssociator.
BookmarkModelAssociator* model_associator_;
@@ -256,6 +255,6 @@ class BookmarkChangeProcessor : public bookmarks::BookmarkModelObserver,
DISALLOW_COPY_AND_ASSIGN(BookmarkChangeProcessor);
};
-} // namespace browser_sync
+} // namespace sync_bookmarks
#endif // COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_CHANGE_PROCESSOR_H_
diff --git a/chromium/components/sync_bookmarks/bookmark_data_type_controller.cc b/chromium/components/sync_bookmarks/bookmark_data_type_controller.cc
index 85e71fabe1a..1a2e494eb6b 100644
--- a/chromium/components/sync_bookmarks/bookmark_data_type_controller.cc
+++ b/chromium/components/sync_bookmarks/bookmark_data_type_controller.cc
@@ -7,29 +7,26 @@
#include "base/metrics/histogram.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/history/core/browser/history_service.h"
-#include "components/sync_driver/sync_api_component_factory.h"
-#include "components/sync_driver/sync_client.h"
+#include "components/sync/driver/sync_api_component_factory.h"
+#include "components/sync/driver/sync_client.h"
using bookmarks::BookmarkModel;
-namespace browser_sync {
+namespace sync_bookmarks {
BookmarkDataTypeController::BookmarkDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client)
- : FrontendDataTypeController(ui_thread, error_callback, sync_client),
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client)
+ : syncer::FrontendDataTypeController(syncer::BOOKMARKS,
+ dump_stack,
+ sync_client),
history_service_observer_(this),
bookmark_model_observer_(this) {}
-syncer::ModelType BookmarkDataTypeController::type() const {
- return syncer::BOOKMARKS;
-}
-
-BookmarkDataTypeController::~BookmarkDataTypeController() {
-}
+BookmarkDataTypeController::~BookmarkDataTypeController() {}
bool BookmarkDataTypeController::StartModels() {
+ DCHECK(CalledOnValidThread());
if (!DependentsLoaded()) {
BookmarkModel* bookmark_model = sync_client_->GetBookmarkModel();
bookmark_model_observer_.Add(bookmark_model);
@@ -42,14 +39,16 @@ bool BookmarkDataTypeController::StartModels() {
}
void BookmarkDataTypeController::CleanUpState() {
+ DCHECK(CalledOnValidThread());
history_service_observer_.RemoveAll();
bookmark_model_observer_.RemoveAll();
}
void BookmarkDataTypeController::CreateSyncComponents() {
- sync_driver::SyncApiComponentFactory::SyncComponents sync_components =
+ DCHECK(CalledOnValidThread());
+ syncer::SyncApiComponentFactory::SyncComponents sync_components =
sync_client_->GetSyncApiComponentFactory()->CreateBookmarkSyncComponents(
- sync_client_->GetSyncService(), this);
+ sync_client_->GetSyncService(), CreateErrorHandler());
set_model_associator(sync_components.model_associator);
set_change_processor(sync_components.change_processor);
}
@@ -59,6 +58,7 @@ void BookmarkDataTypeController::BookmarkModelChanged() {
void BookmarkDataTypeController::BookmarkModelLoaded(BookmarkModel* model,
bool ids_reassigned) {
+ DCHECK(CalledOnValidThread());
DCHECK(model->loaded());
bookmark_model_observer_.RemoveAll();
@@ -77,6 +77,7 @@ void BookmarkDataTypeController::BookmarkModelBeingDeleted(
// Check that both the bookmark model and the history service (for favicons)
// are loaded.
bool BookmarkDataTypeController::DependentsLoaded() {
+ DCHECK(CalledOnValidThread());
BookmarkModel* bookmark_model = sync_client_->GetBookmarkModel();
if (!bookmark_model || !bookmark_model->loaded())
return false;
@@ -91,6 +92,7 @@ bool BookmarkDataTypeController::DependentsLoaded() {
void BookmarkDataTypeController::OnHistoryServiceLoaded(
history::HistoryService* service) {
+ DCHECK(CalledOnValidThread());
DCHECK_EQ(state_, MODEL_STARTING);
history_service_observer_.RemoveAll();
@@ -106,4 +108,4 @@ void BookmarkDataTypeController::HistoryServiceBeingDeleted(
CleanUpState();
}
-} // namespace browser_sync
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_bookmarks/bookmark_data_type_controller.h b/chromium/components/sync_bookmarks/bookmark_data_type_controller.h
index 578e2de85d6..62c2741586d 100644
--- a/chromium/components/sync_bookmarks/bookmark_data_type_controller.h
+++ b/chromium/components/sync_bookmarks/bookmark_data_type_controller.h
@@ -12,27 +12,22 @@
#include "base/scoped_observer.h"
#include "components/bookmarks/browser/base_bookmark_model_observer.h"
#include "components/history/core/browser/history_service_observer.h"
-#include "components/sync_driver/frontend_data_type_controller.h"
+#include "components/sync/driver/frontend_data_type_controller.h"
-namespace browser_sync {
+namespace sync_bookmarks {
// A class that manages the startup and shutdown of bookmark sync.
-class BookmarkDataTypeController : public FrontendDataTypeController,
+class BookmarkDataTypeController : public syncer::FrontendDataTypeController,
public bookmarks::BaseBookmarkModelObserver,
public history::HistoryServiceObserver {
public:
- BookmarkDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client);
-
- // FrontendDataTypeController:
- syncer::ModelType type() const override;
-
- private:
+ // |dump_stack| is called when an unrecoverable error occurs.
+ BookmarkDataTypeController(const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client);
~BookmarkDataTypeController() override;
- // FrontendDataTypeController:
+ private:
+ // syncer::FrontendDataTypeController:
bool StartModels() override;
void CleanUpState() override;
void CreateSyncComponents() override;
@@ -60,6 +55,6 @@ class BookmarkDataTypeController : public FrontendDataTypeController,
DISALLOW_COPY_AND_ASSIGN(BookmarkDataTypeController);
};
-} // namespace browser_sync
+} // namespace sync_bookmarks
#endif // COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_DATA_TYPE_CONTROLLER_H__
diff --git a/chromium/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc b/chromium/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc
index b2d37942330..8090509e082 100644
--- a/chromium/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_data_type_controller_unittest.cc
@@ -18,23 +18,23 @@
#include "components/bookmarks/test/test_bookmark_client.h"
#include "components/history/core/browser/history_service.h"
#include "components/prefs/testing_pref_service.h"
-#include "components/sync_driver/change_processor_mock.h"
-#include "components/sync_driver/data_type_controller_mock.h"
-#include "components/sync_driver/fake_sync_client.h"
-#include "components/sync_driver/fake_sync_service.h"
-#include "components/sync_driver/model_associator_mock.h"
-#include "components/sync_driver/sync_api_component_factory_mock.h"
-#include "sync/api/sync_error.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/driver/change_processor_mock.h"
+#include "components/sync/driver/data_type_controller_mock.h"
+#include "components/sync/driver/fake_sync_client.h"
+#include "components/sync/driver/fake_sync_service.h"
+#include "components/sync/driver/model_associator_mock.h"
+#include "components/sync/driver/sync_api_component_factory_mock.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using bookmarks::BookmarkModel;
-using browser_sync::BookmarkDataTypeController;
-using sync_driver::ChangeProcessorMock;
-using sync_driver::DataTypeController;
-using sync_driver::ModelAssociatorMock;
-using sync_driver::ModelLoadCallbackMock;
-using sync_driver::StartCallbackMock;
+using sync_bookmarks::BookmarkDataTypeController;
+using syncer::ChangeProcessorMock;
+using syncer::DataTypeController;
+using syncer::ModelAssociatorMock;
+using syncer::ModelLoadCallbackMock;
+using syncer::StartCallbackMock;
using testing::_;
using testing::DoAll;
using testing::InvokeWithoutArgs;
@@ -54,7 +54,7 @@ class HistoryMock : public history::HistoryService {
} // namespace
class SyncBookmarkDataTypeControllerTest : public testing::Test,
- public sync_driver::FakeSyncClient {
+ public syncer::FakeSyncClient {
public:
SyncBookmarkDataTypeControllerTest() {}
@@ -63,10 +63,8 @@ class SyncBookmarkDataTypeControllerTest : public testing::Test,
history::HistoryService* GetHistoryService() override {
return history_service_.get();
}
- sync_driver::SyncService* GetSyncService() override {
- return &service_;
- }
- sync_driver::SyncApiComponentFactory* GetSyncApiComponentFactory() override {
+ syncer::SyncService* GetSyncService() override { return &service_; }
+ syncer::SyncApiComponentFactory* GetSyncApiComponentFactory() override {
return profile_sync_factory_.get();
}
@@ -74,12 +72,10 @@ class SyncBookmarkDataTypeControllerTest : public testing::Test,
model_associator_ = new ModelAssociatorMock();
change_processor_ = new ChangeProcessorMock();
history_service_.reset(new HistoryMock());
- profile_sync_factory_.reset(
- new SyncApiComponentFactoryMock(model_associator_,
- change_processor_));
- bookmark_dtc_ =
- new BookmarkDataTypeController(base::ThreadTaskRunnerHandle::Get(),
- base::Bind(&base::DoNothing), this);
+ profile_sync_factory_.reset(new syncer::SyncApiComponentFactoryMock(
+ model_associator_, change_processor_));
+ bookmark_dtc_.reset(
+ new BookmarkDataTypeController(base::Bind(&base::DoNothing), this));
}
protected:
@@ -89,8 +85,8 @@ class SyncBookmarkDataTypeControllerTest : public testing::Test,
};
void CreateBookmarkModel(BookmarkLoadPolicy bookmark_load_policy) {
- bookmark_model_.reset(new BookmarkModel(
- base::WrapUnique(new bookmarks::TestBookmarkClient())));
+ bookmark_model_.reset(
+ new BookmarkModel(base::MakeUnique<bookmarks::TestBookmarkClient>()));
if (bookmark_load_policy == LOAD_MODEL) {
TestingPrefServiceSimple prefs;
bookmark_model_->Load(&prefs, base::FilePath(),
@@ -109,7 +105,6 @@ class SyncBookmarkDataTypeControllerTest : public testing::Test,
void SetAssociateExpectations() {
EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
WillRepeatedly(Return(true));
- EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _));
EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true)));
EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
@@ -136,11 +131,11 @@ class SyncBookmarkDataTypeControllerTest : public testing::Test,
}
base::MessageLoop message_loop_;
- scoped_refptr<BookmarkDataTypeController> bookmark_dtc_;
- std::unique_ptr<SyncApiComponentFactoryMock> profile_sync_factory_;
+ std::unique_ptr<syncer::SyncApiComponentFactoryMock> profile_sync_factory_;
std::unique_ptr<BookmarkModel> bookmark_model_;
std::unique_ptr<HistoryMock> history_service_;
- sync_driver::FakeSyncService service_;
+ std::unique_ptr<BookmarkDataTypeController> bookmark_dtc_;
+ syncer::FakeSyncService service_;
ModelAssociatorMock* model_associator_;
ChangeProcessorMock* change_processor_;
StartCallbackMock start_callback_;
@@ -244,7 +239,6 @@ TEST_F(SyncBookmarkDataTypeControllerTest, StartAssociationFailed) {
CreateBookmarkModel(LOAD_MODEL);
SetStartExpectations();
// Set up association to fail.
- EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _));
EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
WillRepeatedly(Return(true));
EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
@@ -266,7 +260,6 @@ TEST_F(SyncBookmarkDataTypeControllerTest,
CreateBookmarkModel(LOAD_MODEL);
SetStartExpectations();
// Set up association to fail with an unrecoverable error.
- EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _));
EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
WillRepeatedly(Return(true));
EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
diff --git a/chromium/components/sync_bookmarks/bookmark_model_associator.cc b/chromium/components/sync_bookmarks/bookmark_model_associator.cc
index a3fbf638206..6ccdea35b42 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_associator.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_associator.cc
@@ -4,14 +4,12 @@
#include "components/sync_bookmarks/bookmark_model_associator.h"
-#include <memory>
+#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/containers/hash_tables.h"
#include "base/format_macros.h"
#include "base/location.h"
-#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -20,27 +18,27 @@
#include "base/threading/thread_task_runner_handle.h"
#include "components/bookmarks/browser/bookmark_client.h"
#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_merge_result.h"
+#include "components/sync/base/cryptographer.h"
+#include "components/sync/base/data_type_histogram.h"
+#include "components/sync/core/delete_journal.h"
+#include "components/sync/core/read_node.h"
+#include "components/sync/core/read_transaction.h"
+#include "components/sync/core/write_node.h"
+#include "components/sync/core/write_transaction.h"
+#include "components/sync/core_impl/syncapi_internal.h"
+#include "components/sync/driver/sync_client.h"
+#include "components/sync/syncable/entry.h"
+#include "components/sync/syncable/syncable_write_transaction.h"
#include "components/sync_bookmarks/bookmark_change_processor.h"
-#include "components/sync_driver/sync_client.h"
#include "components/undo/bookmark_undo_service.h"
#include "components/undo/bookmark_undo_utils.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_merge_result.h"
-#include "sync/internal_api/public/delete_journal.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/write_node.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/internal_api/syncapi_internal.h"
-#include "sync/syncable/entry.h"
-#include "sync/syncable/syncable_write_transaction.h"
-#include "sync/util/cryptographer.h"
-#include "sync/util/data_type_histogram.h"
using bookmarks::BookmarkModel;
using bookmarks::BookmarkNode;
-namespace browser_sync {
+namespace sync_bookmarks {
// The sync protocol identifies top-level entities by means of well-known tags,
// which should not be confused with titles. Each tag corresponds to a
@@ -308,14 +306,14 @@ void BookmarkModelAssociator::Context::MarkForVersionUpdate(
BookmarkModelAssociator::BookmarkModelAssociator(
BookmarkModel* bookmark_model,
- sync_driver::SyncClient* sync_client,
+ syncer::SyncClient* sync_client,
syncer::UserShare* user_share,
- syncer::DataTypeErrorHandler* unrecoverable_error_handler,
+ std::unique_ptr<syncer::DataTypeErrorHandler> unrecoverable_error_handler,
bool expect_mobile_bookmarks_folder)
: bookmark_model_(bookmark_model),
sync_client_(sync_client),
user_share_(user_share),
- unrecoverable_error_handler_(unrecoverable_error_handler),
+ unrecoverable_error_handler_(std::move(unrecoverable_error_handler)),
expect_mobile_bookmarks_folder_(expect_mobile_bookmarks_folder),
weak_factory_(this) {
DCHECK(bookmark_model_);
@@ -729,7 +727,7 @@ syncer::SyncError BookmarkModelAssociator::BuildAssociations(
for (int i = index; i < parent_node->child_count(); ++i) {
int64_t sync_child_id = BookmarkChangeProcessor::CreateSyncNode(
parent_node, bookmark_model_, i, trans, this,
- unrecoverable_error_handler_);
+ unrecoverable_error_handler_.get());
if (syncer::kInvalidId == sync_child_id) {
return unrecoverable_error_handler_->CreateAndUploadError(
FROM_HERE, "Failed to create sync node.", model_type());
@@ -791,7 +789,7 @@ int BookmarkModelAssociator::RemoveSyncNodeHierarchy(
syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
"Could not lookup bookmark node for ID deletion.",
syncer::BOOKMARKS);
- unrecoverable_error_handler_->OnSingleDataTypeUnrecoverableError(error);
+ unrecoverable_error_handler_->OnUnrecoverableError(error);
return 0;
}
@@ -946,7 +944,7 @@ void BookmarkModelAssociator::PersistAssociations() {
syncer::SyncError::DATATYPE_ERROR,
"Could not lookup bookmark node for ID persistence.",
syncer::BOOKMARKS);
- unrecoverable_error_handler_->OnSingleDataTypeUnrecoverableError(error);
+ unrecoverable_error_handler_->OnUnrecoverableError(error);
return;
}
const BookmarkNode* node = GetChromeNodeFromSyncId(sync_id);
@@ -1015,4 +1013,4 @@ syncer::SyncError BookmarkModelAssociator::CheckModelSyncState(
return syncer::SyncError();
}
-} // namespace browser_sync
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_bookmarks/bookmark_model_associator.h b/chromium/components/sync_bookmarks/bookmark_model_associator.h
index 28d5229efd9..926a3510037 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_associator.h
+++ b/chromium/components/sync_bookmarks/bookmark_model_associator.h
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <map>
+#include <memory>
#include <set>
#include <stack>
#include <string>
@@ -21,9 +22,9 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/threading/thread_checker.h"
-#include "components/sync_driver/model_associator.h"
-#include "sync/internal_api/public/data_type_error_handler.h"
-#include "sync/internal_api/public/util/unrecoverable_error_handler.h"
+#include "components/sync/api/data_type_error_handler.h"
+#include "components/sync/base/unrecoverable_error_handler.h"
+#include "components/sync/driver/model_associator.h"
class GURL;
@@ -35,23 +36,20 @@ class BookmarkNode;
namespace syncer {
class BaseNode;
class BaseTransaction;
-struct UserShare;
-class WriteTransaction;
-}
-
-namespace sync_driver {
class SyncClient;
+class WriteTransaction;
+struct UserShare;
}
-namespace browser_sync {
+namespace sync_bookmarks {
// Contains all model association related logic:
// * Algorithm to associate bookmark model and sync model.
// * Methods to get a bookmark node for a given sync node and vice versa.
// * Persisting model associations and loading them back.
class BookmarkModelAssociator
- : public sync_driver::
- PerDataTypeAssociatorInterface<bookmarks::BookmarkNode, int64_t> {
+ : public syncer::PerDataTypeAssociatorInterface<bookmarks::BookmarkNode,
+ int64_t> {
public:
static syncer::ModelType model_type() { return syncer::BOOKMARKS; }
// |expect_mobile_bookmarks_folder| controls whether or not we
@@ -59,9 +57,9 @@ class BookmarkModelAssociator
// Should be set to true only by mobile clients.
BookmarkModelAssociator(
bookmarks::BookmarkModel* bookmark_model,
- sync_driver::SyncClient* sync_client,
+ syncer::SyncClient* sync_client,
syncer::UserShare* user_share,
- syncer::DataTypeErrorHandler* unrecoverable_error_handler,
+ std::unique_ptr<syncer::DataTypeErrorHandler> unrecoverable_error_handler,
bool expect_mobile_bookmarks_folder);
~BookmarkModelAssociator() override;
@@ -292,9 +290,9 @@ class BookmarkModelAssociator
base::ThreadChecker thread_checker_;
bookmarks::BookmarkModel* bookmark_model_;
- sync_driver::SyncClient* sync_client_;
+ syncer::SyncClient* sync_client_;
syncer::UserShare* user_share_;
- syncer::DataTypeErrorHandler* unrecoverable_error_handler_;
+ std::unique_ptr<syncer::DataTypeErrorHandler> unrecoverable_error_handler_;
const bool expect_mobile_bookmarks_folder_;
BookmarkIdToSyncIdMap id_map_;
SyncIdToBookmarkNodeMap id_map_inverse_;
@@ -309,6 +307,6 @@ class BookmarkModelAssociator
DISALLOW_COPY_AND_ASSIGN(BookmarkModelAssociator);
};
-} // namespace browser_sync
+} // namespace sync_bookmarks
#endif // COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_ASSOCIATOR_H_
diff --git a/chromium/components/sync_driver.gypi b/chromium/components/sync_driver.gypi
deleted file mode 100644
index 6f98f993391..00000000000
--- a/chromium/components/sync_driver.gypi
+++ /dev/null
@@ -1,207 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/sync_driver
- 'target_name': 'sync_driver',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../sync/sync.gyp:sync',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_proto_cpp',
- 'data_use_measurement_core',
- 'invalidation_public',
- 'metrics',
- 'os_crypt',
- 'signin_core_browser',
- 'version_info',
- ],
- 'export_dependent_settings': [
- '../sync/sync.gyp:sync',
- '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'sync_driver/about_sync_util.cc',
- 'sync_driver/about_sync_util.h',
- 'sync_driver/backend_data_type_configurer.cc',
- 'sync_driver/backend_data_type_configurer.h',
- 'sync_driver/backend_migrator.cc',
- 'sync_driver/backend_migrator.h',
- 'sync_driver/change_processor.cc',
- 'sync_driver/change_processor.h',
- 'sync_driver/data_type_controller.cc',
- 'sync_driver/data_type_controller.h',
- 'sync_driver/data_type_encryption_handler.cc',
- 'sync_driver/data_type_encryption_handler.h',
- 'sync_driver/data_type_manager.cc',
- 'sync_driver/data_type_manager.h',
- 'sync_driver/data_type_manager_impl.cc',
- 'sync_driver/data_type_manager_impl.h',
- 'sync_driver/data_type_manager_observer.h',
- 'sync_driver/data_type_status_table.cc',
- 'sync_driver/data_type_status_table.h',
- 'sync_driver/device_count_metrics_provider.cc',
- 'sync_driver/device_count_metrics_provider.h',
- 'sync_driver/device_info.cc',
- 'sync_driver/device_info.h',
- 'sync_driver/device_info_data_type_controller.cc',
- 'sync_driver/device_info_data_type_controller.h',
- 'sync_driver/device_info_service.cc',
- 'sync_driver/device_info_service.h',
- 'sync_driver/device_info_sync_service.cc',
- 'sync_driver/device_info_sync_service.h',
- 'sync_driver/device_info_tracker.h',
- 'sync_driver/device_info_util.cc',
- 'sync_driver/device_info_util.h',
- 'sync_driver/directory_data_type_controller.cc',
- 'sync_driver/directory_data_type_controller.h',
- 'sync_driver/frontend_data_type_controller.cc',
- 'sync_driver/frontend_data_type_controller.h',
- 'sync_driver/generic_change_processor.cc',
- 'sync_driver/generic_change_processor.h',
- 'sync_driver/generic_change_processor_factory.cc',
- 'sync_driver/generic_change_processor_factory.h',
- 'sync_driver/glue/browser_thread_model_worker.cc',
- 'sync_driver/glue/browser_thread_model_worker.h',
- 'sync_driver/glue/chrome_report_unrecoverable_error.cc',
- 'sync_driver/glue/chrome_report_unrecoverable_error.h',
- 'sync_driver/glue/sync_backend_host.cc',
- 'sync_driver/glue/sync_backend_host.h',
- 'sync_driver/glue/sync_backend_host_core.cc',
- 'sync_driver/glue/sync_backend_host_core.h',
- 'sync_driver/glue/sync_backend_host_impl.cc',
- 'sync_driver/glue/sync_backend_host_impl.h',
- 'sync_driver/glue/sync_backend_registrar.cc',
- 'sync_driver/glue/sync_backend_registrar.h',
- 'sync_driver/glue/ui_model_worker.cc',
- 'sync_driver/glue/ui_model_worker.h',
- 'sync_driver/invalidation_adapter.cc',
- 'sync_driver/invalidation_adapter.h',
- 'sync_driver/invalidation_helper.cc',
- 'sync_driver/invalidation_helper.h',
- 'sync_driver/local_device_info_provider.h',
- 'sync_driver/local_device_info_provider_impl.cc',
- 'sync_driver/local_device_info_provider_impl.h',
- 'sync_driver/model_association_manager.cc',
- 'sync_driver/model_association_manager.h',
- 'sync_driver/model_associator.h',
- 'sync_driver/non_blocking_data_type_controller.cc',
- 'sync_driver/non_blocking_data_type_controller.h',
- 'sync_driver/non_ui_data_type_controller.cc',
- 'sync_driver/non_ui_data_type_controller.h',
- 'sync_driver/non_ui_model_type_controller.cc',
- 'sync_driver/non_ui_model_type_controller.h',
- 'sync_driver/pref_names.cc',
- 'sync_driver/pref_names.h',
- 'sync_driver/profile_sync_auth_provider.cc',
- 'sync_driver/profile_sync_auth_provider.h',
- 'sync_driver/protocol_event_observer.cc',
- 'sync_driver/protocol_event_observer.h',
- 'sync_driver/proxy_data_type_controller.cc',
- 'sync_driver/proxy_data_type_controller.h',
- 'sync_driver/shared_change_processor.cc',
- 'sync_driver/shared_change_processor.h',
- 'sync_driver/shared_change_processor_ref.cc',
- 'sync_driver/shared_change_processor_ref.h',
- 'sync_driver/signin_manager_wrapper.cc',
- 'sync_driver/signin_manager_wrapper.h',
- 'sync_driver/startup_controller.cc',
- 'sync_driver/startup_controller.h',
- 'sync_driver/sync_api_component_factory.h',
- 'sync_driver/sync_client.cc',
- 'sync_driver/sync_client.h',
- 'sync_driver/sync_driver_switches.cc',
- 'sync_driver/sync_driver_switches.h',
- 'sync_driver/sync_error_controller.cc',
- 'sync_driver/sync_error_controller.h',
- 'sync_driver/sync_frontend.cc',
- 'sync_driver/sync_frontend.h',
- 'sync_driver/sync_prefs.cc',
- 'sync_driver/sync_prefs.h',
- 'sync_driver/sync_service.cc',
- 'sync_driver/sync_service.h',
- 'sync_driver/sync_service_observer.cc',
- 'sync_driver/sync_service_observer.h',
- 'sync_driver/sync_service_utils.cc',
- 'sync_driver/sync_service_utils.h',
- 'sync_driver/sync_stopped_reporter.cc',
- 'sync_driver/sync_stopped_reporter.h',
- 'sync_driver/sync_type_preference_provider.h',
- 'sync_driver/sync_util.cc',
- 'sync_driver/sync_util.h',
- 'sync_driver/system_encryptor.cc',
- 'sync_driver/system_encryptor.h',
- 'sync_driver/ui_data_type_controller.cc',
- 'sync_driver/ui_data_type_controller.h',
- 'sync_driver/ui_model_type_controller.cc',
- 'sync_driver/ui_model_type_controller.h',
- 'sync_driver/user_selectable_sync_type.h',
- ],
- 'conditions': [
- ['configuration_policy==1', {
- 'dependencies': [
- 'policy',
- 'policy_component',
- ],
- 'sources': [
- 'sync_driver/sync_policy_handler.cc',
- 'sync_driver/sync_policy_handler.h',
- ],
- }],
- ],
- },
- {
- 'target_name': 'sync_driver_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'sync_driver',
- 'version_info',
- '../base/base.gyp:base',
- '../sync/sync.gyp:sync',
- '../sync/sync.gyp:test_support_sync_internal_api',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'sync_driver/change_processor_mock.cc',
- 'sync_driver/change_processor_mock.h',
- 'sync_driver/data_type_controller_mock.cc',
- 'sync_driver/data_type_controller_mock.h',
- 'sync_driver/data_type_manager_mock.cc',
- 'sync_driver/data_type_manager_mock.h',
- 'sync_driver/fake_data_type_controller.cc',
- 'sync_driver/fake_data_type_controller.h',
- 'sync_driver/fake_generic_change_processor.cc',
- 'sync_driver/fake_generic_change_processor.h',
- 'sync_driver/fake_sync_client.cc',
- 'sync_driver/fake_sync_client.h',
- 'sync_driver/fake_sync_service.cc',
- 'sync_driver/fake_sync_service.h',
- 'sync_driver/frontend_data_type_controller_mock.cc',
- 'sync_driver/frontend_data_type_controller_mock.h',
- 'sync_driver/glue/sync_backend_host_mock.cc',
- 'sync_driver/glue/sync_backend_host_mock.h',
- 'sync_driver/local_device_info_provider_mock.cc',
- 'sync_driver/local_device_info_provider_mock.h',
- 'sync_driver/model_associator_mock.cc',
- 'sync_driver/model_associator_mock.h',
- 'sync_driver/non_ui_data_type_controller_mock.cc',
- 'sync_driver/non_ui_data_type_controller_mock.h',
- 'sync_driver/sync_api_component_factory_mock.cc',
- 'sync_driver/sync_api_component_factory_mock.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/sync_driver/BUILD.gn b/chromium/components/sync_driver/BUILD.gn
deleted file mode 100644
index 4717d29133e..00000000000
--- a/chromium/components/sync_driver/BUILD.gn
+++ /dev/null
@@ -1,265 +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("//build/buildflag_header.gni")
-import("//build/config/features.gni")
-
-source_set("sync_driver") {
- sources = [
- "about_sync_util.cc",
- "about_sync_util.h",
- "backend_data_type_configurer.cc",
- "backend_data_type_configurer.h",
- "backend_migrator.cc",
- "backend_migrator.h",
- "change_processor.cc",
- "change_processor.h",
- "data_type_controller.cc",
- "data_type_controller.h",
- "data_type_encryption_handler.cc",
- "data_type_encryption_handler.h",
- "data_type_manager.cc",
- "data_type_manager.h",
- "data_type_manager_impl.cc",
- "data_type_manager_impl.h",
- "data_type_manager_observer.h",
- "data_type_status_table.cc",
- "data_type_status_table.h",
- "device_count_metrics_provider.cc",
- "device_count_metrics_provider.h",
- "device_info.cc",
- "device_info.h",
- "device_info_data_type_controller.cc",
- "device_info_data_type_controller.h",
- "device_info_service.cc",
- "device_info_service.h",
- "device_info_sync_service.cc",
- "device_info_sync_service.h",
- "device_info_tracker.h",
- "device_info_util.cc",
- "device_info_util.h",
- "directory_data_type_controller.cc",
- "directory_data_type_controller.h",
- "frontend_data_type_controller.cc",
- "frontend_data_type_controller.h",
- "generic_change_processor.cc",
- "generic_change_processor.h",
- "generic_change_processor_factory.cc",
- "generic_change_processor_factory.h",
- "glue/browser_thread_model_worker.cc",
- "glue/browser_thread_model_worker.h",
- "glue/chrome_report_unrecoverable_error.cc",
- "glue/chrome_report_unrecoverable_error.h",
- "glue/sync_backend_host.cc",
- "glue/sync_backend_host.h",
- "glue/sync_backend_host_core.cc",
- "glue/sync_backend_host_core.h",
- "glue/sync_backend_host_impl.cc",
- "glue/sync_backend_host_impl.h",
- "glue/sync_backend_registrar.cc",
- "glue/sync_backend_registrar.h",
- "glue/ui_model_worker.cc",
- "glue/ui_model_worker.h",
- "invalidation_adapter.cc",
- "invalidation_adapter.h",
- "invalidation_helper.cc",
- "invalidation_helper.h",
- "local_device_info_provider.h",
- "local_device_info_provider_impl.cc",
- "local_device_info_provider_impl.h",
- "model_association_manager.cc",
- "model_association_manager.h",
- "model_associator.h",
- "non_blocking_data_type_controller.cc",
- "non_blocking_data_type_controller.h",
- "non_ui_data_type_controller.cc",
- "non_ui_data_type_controller.h",
- "non_ui_model_type_controller.cc",
- "non_ui_model_type_controller.h",
- "pref_names.cc",
- "pref_names.h",
- "profile_sync_auth_provider.cc",
- "profile_sync_auth_provider.h",
- "protocol_event_observer.cc",
- "protocol_event_observer.h",
- "proxy_data_type_controller.cc",
- "proxy_data_type_controller.h",
- "shared_change_processor.cc",
- "shared_change_processor.h",
- "shared_change_processor_ref.cc",
- "shared_change_processor_ref.h",
- "signin_manager_wrapper.cc",
- "signin_manager_wrapper.h",
- "startup_controller.cc",
- "startup_controller.h",
- "sync_api_component_factory.h",
- "sync_client.cc",
- "sync_client.h",
- "sync_driver_switches.cc",
- "sync_driver_switches.h",
- "sync_error_controller.cc",
- "sync_error_controller.h",
- "sync_frontend.cc",
- "sync_frontend.h",
- "sync_prefs.cc",
- "sync_prefs.h",
- "sync_service.cc",
- "sync_service.h",
- "sync_service_observer.cc",
- "sync_service_observer.h",
- "sync_service_utils.cc",
- "sync_service_utils.h",
- "sync_stopped_reporter.cc",
- "sync_stopped_reporter.h",
- "sync_type_preference_provider.h",
- "sync_util.cc",
- "sync_util.h",
- "system_encryptor.cc",
- "system_encryptor.h",
- "ui_data_type_controller.cc",
- "ui_data_type_controller.h",
- "ui_model_type_controller.cc",
- "ui_model_type_controller.h",
- "user_selectable_sync_type.h",
- ]
-
- public_deps = [
- "//sync",
- "//third_party/cacheinvalidation",
- ]
-
- deps = [
- "//base",
- "//base/third_party/dynamic_annotations",
- "//components/data_use_measurement/core",
- "//components/invalidation/public",
- "//components/metrics",
- "//components/os_crypt",
- "//components/pref_registry",
- "//components/prefs",
- "//components/signin/core/browser",
- "//components/version_info",
- "//google_apis",
- "//net",
- ]
-
- if (enable_configuration_policy) {
- sources += [
- "sync_policy_handler.cc",
- "sync_policy_handler.h",
- ]
- deps += [
- "//components/policy",
- "//components/policy:policy_component",
- ]
- }
-}
-
-source_set("test_support") {
- testonly = true
- sources = [
- "change_processor_mock.cc",
- "change_processor_mock.h",
- "data_type_controller_mock.cc",
- "data_type_controller_mock.h",
- "data_type_manager_mock.cc",
- "data_type_manager_mock.h",
- "fake_data_type_controller.cc",
- "fake_data_type_controller.h",
- "fake_generic_change_processor.cc",
- "fake_generic_change_processor.h",
- "fake_sync_client.cc",
- "fake_sync_client.h",
- "fake_sync_service.cc",
- "fake_sync_service.h",
- "frontend_data_type_controller_mock.cc",
- "frontend_data_type_controller_mock.h",
- "glue/sync_backend_host_mock.cc",
- "glue/sync_backend_host_mock.h",
- "local_device_info_provider_mock.cc",
- "local_device_info_provider_mock.h",
- "model_associator_mock.cc",
- "model_associator_mock.h",
- "non_ui_data_type_controller_mock.cc",
- "non_ui_data_type_controller_mock.h",
- "sync_api_component_factory_mock.cc",
- "sync_api_component_factory_mock.h",
- ]
-
- public_deps = [
- ":sync_driver",
- "//sync",
- ]
-
- deps = [
- "//base",
- "//components/syncable_prefs:test_support",
- "//components/version_info",
- "//google_apis",
- "//sync:test_support_sync_internal_api",
- "//testing/gmock",
- "//testing/gtest",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "about_sync_util_unittest.cc",
- "backend_migrator_unittest.cc",
- "data_type_manager_impl_unittest.cc",
- "device_count_metrics_provider_unittest.cc",
- "device_info_data_type_controller_unittest.cc",
- "device_info_service_unittest.cc",
- "device_info_sync_service_unittest.cc",
- "device_info_util_unittest.cc",
- "frontend_data_type_controller_unittest.cc",
- "generic_change_processor_unittest.cc",
- "glue/browser_thread_model_worker_unittest.cc",
- "glue/sync_backend_host_impl_unittest.cc",
- "glue/sync_backend_registrar_unittest.cc",
- "glue/ui_model_worker_unittest.cc",
- "local_device_info_provider_unittest.cc",
- "model_association_manager_unittest.cc",
- "non_blocking_data_type_controller_unittest.cc",
- "non_ui_data_type_controller_unittest.cc",
- "non_ui_model_type_controller_unittest.cc",
- "profile_sync_auth_provider_unittest.cc",
- "shared_change_processor_unittest.cc",
- "startup_controller_unittest.cc",
- "sync_prefs_unittest.cc",
- "sync_stopped_reporter_unittest.cc",
- "sync_util_unittest.cc",
- "system_encryptor_unittest.cc",
- "ui_data_type_controller_unittest.cc",
- "ui_model_type_controller_unittest.cc",
- ]
- deps = [
- ":test_support",
- "//base",
- "//base/test:test_support",
- "//components/invalidation/impl",
- "//components/os_crypt:test_support",
- "//components/pref_registry:test_support",
- "//components/prefs:test_support",
- "//components/signin/core/browser:test_support",
- "//components/syncable_prefs",
- "//components/syncable_prefs:test_support",
- "//components/version_info",
- "//net:test_support",
- "//sync:test_support_sync_api",
- "//sync:test_support_sync_internal_api",
- "//testing/gmock",
- "//testing/gtest",
- "//url",
- ]
-
- if (enable_configuration_policy) {
- sources += [ "sync_policy_handler_unittest.cc" ]
- deps += [
- "//components/policy",
- "//components/policy:policy_component",
- ]
- }
-}
diff --git a/chromium/components/sync_sessions.gypi b/chromium/components/sync_sessions.gypi
deleted file mode 100644
index b56fb0fab39..00000000000
--- a/chromium/components/sync_sessions.gypi
+++ /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.
-
-{
- 'targets': [
- {
- # GN version: //components/sync_sessions
- 'target_name': 'sync_sessions',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../sync/sync.gyp:sync',
- '../url/url.gyp:url_lib',
- 'bookmarks_browser',
- 'history_core_browser',
- 'prefs/prefs.gyp:prefs',
- 'sync_driver',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'sync_sessions/favicon_cache.cc',
- 'sync_sessions/favicon_cache.h',
- 'sync_sessions/local_session_event_router.h',
- 'sync_sessions/open_tabs_ui_delegate.cc',
- 'sync_sessions/open_tabs_ui_delegate.h',
- 'sync_sessions/revisit/bookmarks_by_url_provider_impl.cc',
- 'sync_sessions/revisit/bookmarks_by_url_provider_impl.h',
- 'sync_sessions/revisit/bookmarks_page_revisit_observer.cc',
- 'sync_sessions/revisit/bookmarks_page_revisit_observer.h',
- 'sync_sessions/revisit/current_tab_matcher.cc',
- 'sync_sessions/revisit/current_tab_matcher.h',
- 'sync_sessions/revisit/offset_tab_matcher.cc',
- 'sync_sessions/revisit/offset_tab_matcher.h',
- 'sync_sessions/revisit/page_equality.h',
- 'sync_sessions/revisit/page_visit_observer.h',
- 'sync_sessions/revisit/page_revisit_broadcaster.cc',
- 'sync_sessions/revisit/page_revisit_broadcaster.h',
- 'sync_sessions/revisit/sessions_page_revisit_observer.cc',
- 'sync_sessions/revisit/sessions_page_revisit_observer.h',
- 'sync_sessions/revisit/typed_url_page_revisit_observer.cc',
- 'sync_sessions/revisit/typed_url_page_revisit_observer.h',
- 'sync_sessions/revisit/typed_url_page_revisit_task.cc',
- 'sync_sessions/revisit/typed_url_page_revisit_task.h',
- 'sync_sessions/session_data_type_controller.cc',
- 'sync_sessions/session_data_type_controller.h',
- 'sync_sessions/sessions_sync_manager.cc',
- 'sync_sessions/sessions_sync_manager.h',
- 'sync_sessions/synced_tab_delegate.cc',
- 'sync_sessions/synced_tab_delegate.h',
- 'sync_sessions/synced_session.cc',
- 'sync_sessions/synced_session.h',
- 'sync_sessions/synced_session_tracker.cc',
- 'sync_sessions/synced_session_tracker.h',
- 'sync_sessions/synced_window_delegate.h',
- 'sync_sessions/synced_window_delegates_getter.cc',
- 'sync_sessions/synced_window_delegates_getter.h',
- 'sync_sessions/sync_sessions_client.cc',
- 'sync_sessions/sync_sessions_client.h',
- 'sync_sessions/sync_sessions_metrics.cc',
- 'sync_sessions/sync_sessions_metrics.h',
- 'sync_sessions/tab_node_pool.cc',
- 'sync_sessions/tab_node_pool.h',
- ],
- 'conditions': [
- ['OS!="ios"', {
- 'dependencies': [
- 'sessions_content',
- ],
- }, { # OS==ios
- 'dependencies': [
- 'sessions_ios',
- ],
- }],
- ],
- },
- {
- 'target_name': 'sync_sessions_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'sync_sessions',
- '../base/base.gyp:base',
- '../sync/sync.gyp:sync',
- '../testing/gtest.gyp:gtest',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'sync_sessions/fake_sync_sessions_client.cc',
- 'sync_sessions/fake_sync_sessions_client.h',
- ],
- }
- ]
-}
diff --git a/chromium/components/sync_sessions/BUILD.gn b/chromium/components/sync_sessions/BUILD.gn
index c66737c46d2..1515037ebfe 100644
--- a/chromium/components/sync_sessions/BUILD.gn
+++ b/chromium/components/sync_sessions/BUILD.gn
@@ -2,12 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# GYP version: components/sync_sessions.gypi:sync_sessions
-source_set("sync_sessions") {
+static_library("sync_sessions") {
sources = [
"favicon_cache.cc",
"favicon_cache.h",
"local_session_event_router.h",
+ "lost_navigations_recorder.cc",
+ "lost_navigations_recorder.h",
"open_tabs_ui_delegate.cc",
"open_tabs_ui_delegate.h",
"revisit/bookmarks_by_url_provider_impl.cc",
@@ -49,32 +50,38 @@ source_set("sync_sessions") {
"tab_node_pool.h",
]
+ public_deps = [
+ "//components/sessions",
+ "//components/sync",
+ ]
+
deps = [
"//base",
"//components/bookmarks/browser",
"//components/favicon/core",
"//components/history/core/browser",
"//components/prefs",
- "//components/sessions",
- "//components/sync_driver",
"//components/variations",
- "//sync",
"//ui/base:base",
"//ui/gfx",
"//url",
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"fake_sync_sessions_client.cc",
"fake_sync_sessions_client.h",
+ "session_sync_test_helper.cc",
+ "session_sync_test_helper.h",
]
public_deps = [
":sync_sessions",
"//base",
+ "//components/sync",
+ "//testing/gtest",
"//url",
]
@@ -85,6 +92,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"favicon_cache_unittest.cc",
+ "lost_navigations_recorder_unittest.cc",
"revisit/bookmarks_page_revisit_observer_unittest.cc",
"revisit/current_tab_matcher_unittest.cc",
"revisit/offset_tab_matcher_unittest.cc",
@@ -105,10 +113,10 @@ source_set("unit_tests") {
"//components/history/core/browser",
"//components/prefs:test_support",
"//components/sessions:test_support",
- "//components/sync_driver",
- "//components/sync_driver:test_support",
- "//sync",
- "//sync:test_support_sync_api",
+ "//components/sync",
+ "//components/sync:test_support_sync_api",
+ "//components/sync:test_support_sync_core",
+ "//components/sync:test_support_sync_driver",
"//testing/gmock",
"//testing/gtest",
"//ui/base:base",
diff --git a/chromium/components/sync_sessions/DEPS b/chromium/components/sync_sessions/DEPS
index 1fd82cac309..564d4219c36 100644
--- a/chromium/components/sync_sessions/DEPS
+++ b/chromium/components/sync_sessions/DEPS
@@ -4,9 +4,8 @@ include_rules = [
"+components/history/core/browser",
"+components/prefs",
"+components/sessions",
- "+components/sync_driver",
+ "+components/sync",
"+components/variations",
- "+sync",
"+ui/base/page_transition_types.h",
"+ui/gfx",
]
diff --git a/chromium/components/sync_sessions/fake_sync_sessions_client.cc b/chromium/components/sync_sessions/fake_sync_sessions_client.cc
index 8632a9347d4..9bdc8213a55 100644
--- a/chromium/components/sync_sessions/fake_sync_sessions_client.cc
+++ b/chromium/components/sync_sessions/fake_sync_sessions_client.cc
@@ -28,12 +28,12 @@ bool FakeSyncSessionsClient::ShouldSyncURL(const GURL& url) const {
return url.is_valid();
}
-browser_sync::SyncedWindowDelegatesGetter*
+SyncedWindowDelegatesGetter*
FakeSyncSessionsClient::GetSyncedWindowDelegatesGetter() {
return nullptr;
}
-std::unique_ptr<browser_sync::LocalSessionEventRouter>
+std::unique_ptr<LocalSessionEventRouter>
FakeSyncSessionsClient::GetLocalSessionEventRouter() {
return nullptr;
}
diff --git a/chromium/components/sync_sessions/fake_sync_sessions_client.h b/chromium/components/sync_sessions/fake_sync_sessions_client.h
index 3bd4cc7a2cc..7b17f3a1d88 100644
--- a/chromium/components/sync_sessions/fake_sync_sessions_client.h
+++ b/chromium/components/sync_sessions/fake_sync_sessions_client.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_SYNC_SESSIONS_FAKE_SYNC_SESSIONS_CLIENT_H_
#define COMPONENTS_SYNC_SESSIONS_FAKE_SYNC_SESSIONS_CLIENT_H_
+#include <memory>
+
#include "base/macros.h"
#include "components/sync_sessions/sync_sessions_client.h"
@@ -21,10 +23,9 @@ class FakeSyncSessionsClient : public SyncSessionsClient {
favicon::FaviconService* GetFaviconService() override;
history::HistoryService* GetHistoryService() override;
bool ShouldSyncURL(const GURL& url) const override;
- browser_sync::SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter()
+ SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter() override;
+ std::unique_ptr<LocalSessionEventRouter> GetLocalSessionEventRouter()
override;
- std::unique_ptr<browser_sync::LocalSessionEventRouter>
- GetLocalSessionEventRouter() override;
private:
DISALLOW_COPY_AND_ASSIGN(FakeSyncSessionsClient);
diff --git a/chromium/components/sync_sessions/favicon_cache.cc b/chromium/components/sync_sessions/favicon_cache.cc
index 51e9494d3fb..52e48cfe5da 100644
--- a/chromium/components/sync_sessions/favicon_cache.cc
+++ b/chromium/components/sync_sessions/favicon_cache.cc
@@ -7,20 +7,18 @@
#include <utility>
#include "base/location.h"
-#include "base/macros.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/favicon/core/favicon_service.h"
#include "components/history/core/browser/history_service.h"
-#include "components/history/core/browser/history_types.h"
-#include "sync/api/time.h"
-#include "sync/protocol/favicon_image_specifics.pb.h"
-#include "sync/protocol/favicon_tracking_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/time.h"
+#include "components/sync/protocol/favicon_image_specifics.pb.h"
+#include "components/sync/protocol/favicon_tracking_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
#include "ui/gfx/favicon_size.h"
-namespace browser_sync {
+namespace sync_sessions {
// Synced favicon storage and tracking.
// Note: we don't use the favicon service for storing these because these
@@ -1047,4 +1045,4 @@ void FaviconCache::OnURLsDeleted(history::HistoryService* history_service,
}
}
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/favicon_cache.h b/chromium/components/sync_sessions/favicon_cache.h
index af478075606..c5bb13b8dc6 100644
--- a/chromium/components/sync_sessions/favicon_cache.h
+++ b/chromium/components/sync_sessions/favicon_cache.h
@@ -26,9 +26,9 @@
#include "components/history/core/browser/history_service_observer.h"
#include "components/history/core/browser/history_types.h"
#include "components/sessions/core/session_id.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/api/syncable_service.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/api/syncable_service.h"
#include "url/gurl.h"
namespace chrome {
@@ -43,7 +43,7 @@ namespace history {
class HistoryService;
}
-namespace browser_sync {
+namespace sync_sessions {
enum IconSize {
SIZE_INVALID,
@@ -250,6 +250,6 @@ class FaviconCache : public syncer::SyncableService,
DISALLOW_COPY_AND_ASSIGN(FaviconCache);
};
-} // namespace browser_sync
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_FAVICON_CACHE_H_
diff --git a/chromium/components/sync_sessions/favicon_cache_unittest.cc b/chromium/components/sync_sessions/favicon_cache_unittest.cc
index 0eb20923ed9..52173803e11 100644
--- a/chromium/components/sync_sessions/favicon_cache_unittest.cc
+++ b/chromium/components/sync_sessions/favicon_cache_unittest.cc
@@ -4,26 +4,24 @@
#include "components/sync_sessions/favicon_cache.h"
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
-#include "sync/api/attachments/attachment_id.h"
-#include "sync/api/sync_change_processor_wrapper_for_test.h"
-#include "sync/api/sync_error_factory_mock.h"
-#include "sync/api/time.h"
-#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
-#include "sync/protocol/favicon_image_specifics.pb.h"
-#include "sync/protocol/favicon_tracking_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/attachments/attachment_id.h"
+#include "components/sync/api/sync_change_processor_wrapper_for_test.h"
+#include "components/sync/api/sync_error_factory_mock.h"
+#include "components/sync/api/time.h"
+#include "components/sync/core/attachments/attachment_service_proxy_for_test.h"
+#include "components/sync/protocol/favicon_image_specifics.pb.h"
+#include "components/sync/protocol/favicon_tracking_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace browser_sync {
+namespace sync_sessions {
namespace {
@@ -244,7 +242,7 @@ int GetFaviconId(const syncer::SyncChange change) {
std::string tag = syncer::SyncDataLocal(change.sync_data()).GetTag();
const std::string kPrefix = "http://bla.com/";
const std::string kSuffix = ".ico";
- if (tag.find(kPrefix) != 0)
+ if (!base::StartsWith(tag, kPrefix, base::CompareCase::SENSITIVE))
return -1;
std::string temp = tag.substr(kPrefix.length());
if (temp.rfind(kSuffix) <= 0)
@@ -401,8 +399,8 @@ testing::AssertionResult SyncFaviconCacheTest::VerifyLocalCustomIcons(
std::unique_ptr<syncer::SyncChangeProcessor>
SyncFaviconCacheTest::CreateAndPassProcessor() {
- return base::WrapUnique(
- new syncer::SyncChangeProcessorWrapperForTest(sync_processor_.get()));
+ return base::MakeUnique<syncer::SyncChangeProcessorWrapperForTest>(
+ sync_processor_.get());
}
std::unique_ptr<syncer::SyncErrorFactory>
@@ -455,7 +453,7 @@ void SyncFaviconCacheTest::TriggerSyncFaviconReceived(
icon_url,
icon_bytes,
last_visit_time_ms);
- message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
// A freshly constructed cache should be empty.
@@ -1933,4 +1931,4 @@ TEST_F(SyncFaviconCacheTest, MixedThreshold) {
EXPECT_EQ(0, GetFaviconId(changes[5]));
}
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/local_session_event_router.h b/chromium/components/sync_sessions/local_session_event_router.h
index 8cf9e956cee..51b07c3db03 100644
--- a/chromium/components/sync_sessions/local_session_event_router.h
+++ b/chromium/components/sync_sessions/local_session_event_router.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "url/gurl.h"
-namespace browser_sync {
+namespace sync_sessions {
class SyncedTabDelegate;
@@ -58,6 +58,6 @@ class LocalSessionEventRouter {
DISALLOW_COPY_AND_ASSIGN(LocalSessionEventRouter);
};
-} // namespace browser_sync
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_LOCAL_SESSION_EVENT_ROUTER_H_
diff --git a/chromium/components/sync_sessions/lost_navigations_recorder.cc b/chromium/components/sync_sessions/lost_navigations_recorder.cc
new file mode 100644
index 00000000000..c3dab185a08
--- /dev/null
+++ b/chromium/components/sync_sessions/lost_navigations_recorder.cc
@@ -0,0 +1,136 @@
+// 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 "components/sync_sessions/lost_navigations_recorder.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "components/sync/syncable/entry.h"
+
+namespace sync_sessions {
+
+LostNavigationsRecorder::LostNavigationsRecorder()
+ : recorder_state_(RECORDER_STATE_NOT_SYNCING) {}
+
+LostNavigationsRecorder::~LostNavigationsRecorder() {}
+
+void LostNavigationsRecorder::OnLocalChange(
+ const syncer::syncable::Entry* current_entry,
+ const syncer::SyncChange& change) {
+ if (change.sync_data().GetSpecifics().session().has_tab()) {
+ TransitionState(current_entry->GetSyncing(),
+ current_entry->GetIsUnsynced());
+ }
+ RecordChange(change);
+}
+
+// Record a change either by adjusting our list of tabs or by recording the set
+// of navigations in the updated tab.
+void LostNavigationsRecorder::RecordChange(const syncer::SyncChange& change) {
+ sync_pb::SessionSpecifics session_specifics =
+ change.sync_data().GetSpecifics().session();
+ if (session_specifics.has_header()) {
+ DeleteTabs(session_specifics.header());
+ return;
+ } else if (!session_specifics.has_tab()) {
+ // There isn't any data we care about if neither a tab or window is
+ // modified.
+ return;
+ }
+ sync_pb::SessionTab tab = session_specifics.tab();
+ id_type tab_id = tab.tab_id();
+
+ IdSet& latest = latest_navigation_ids_[tab_id];
+ latest.clear();
+
+ for (sync_pb::TabNavigation nav : tab.navigation()) {
+ id_type uid = nav.unique_id();
+ // Only record an id if it's "new" i.e. larger than the largest seen for
+ // that tab. If the id is smaller than this, it's not new; ids are generated
+ // in increasing order.
+ if (uid > max_recorded_for_tab_[tab_id]) {
+ recorded_navigation_ids_[tab_id].insert(uid);
+ max_recorded_for_tab_[tab_id] = uid;
+ }
+ latest.insert(nav.unique_id());
+ }
+}
+
+void LostNavigationsRecorder::DeleteTabs(const sync_pb::SessionHeader& header) {
+ IdSet new_tab_ids;
+ IdSet current_tab_ids;
+ // Find the set of tab ids that are still there after the deletion.
+ for (sync_pb::SessionWindow window : header.window()) {
+ for (id_type tab_id : window.tab()) {
+ new_tab_ids.insert(tab_id);
+ }
+ }
+ for (auto pair : recorded_navigation_ids_) {
+ current_tab_ids.insert(pair.first);
+ }
+ // The set of deleted tabs is the difference between the set of tabs before
+ // the pending change and the set of tabs following the pending change.
+ IdSet deleted_tabs =
+ base::STLSetDifference<IdSet>(current_tab_ids, new_tab_ids);
+ for (id_type tab_id : deleted_tabs) {
+ recorded_navigation_ids_.erase(tab_id);
+ latest_navigation_ids_.erase(tab_id);
+ max_recorded_for_tab_.erase(tab_id);
+ }
+}
+
+// Change the current state of the recorder, possibly triggering reconciliation,
+// based on the status of the directory entry. Reconciliation triggers on the
+// observation of two conditions.
+// 1) The entry transitioning into the syncing state
+// 2) If we miss the transition to syncing state, the entry transitioning into
+// the synced state.
+void LostNavigationsRecorder::TransitionState(bool is_syncing,
+ bool is_unsynced) {
+ switch (recorder_state_) {
+ case RECORDER_STATE_NOT_SYNCING:
+ // If a sync cycle is happening or already finished, reconcile.
+ // It's possible that this will trigger reconciliation multiple times per
+ // sync cycle; once per tab that finishes the cycle in the synced state
+ // and the user performs a navigation in. In theory this will cause
+ // under-counting, since reconciliation clears each tab's remembered set
+ // of navigations. In practice the number of unique tabs written to in
+ // between two adjacent sync cycles should be pretty low,
+ // making the undercounting tolerable.
+ if (is_syncing || !is_unsynced) {
+ ReconcileLostNavs();
+ }
+ // If we're currently in a sync cycle, remember that.
+ if (is_syncing) {
+ recorder_state_ = RECORDER_STATE_SYNCING;
+ }
+ break;
+ case RECORDER_STATE_SYNCING:
+ if (!is_syncing) {
+ recorder_state_ = RECORDER_STATE_NOT_SYNCING;
+ }
+ break;
+ }
+}
+
+// Reconcile the number of "lost" navigations by checking all the unique ids we
+// recorded against what was actually synced.
+void LostNavigationsRecorder::ReconcileLostNavs() {
+ for (auto pair : recorded_navigation_ids_) {
+ id_type tab_id = pair.first;
+ IdSet& latest = latest_navigation_ids_[tab_id];
+ IdSet& recorded = recorded_navigation_ids_[tab_id];
+ if (recorded.size() < 1) {
+ continue;
+ }
+
+ // The set of lost navigations is anything we recorded as new that's not
+ // present in latest.
+ IdSet lost_navs = base::STLSetDifference<IdSet>(recorded, latest);
+ int quantity_lost = lost_navs.size();
+ UMA_HISTOGRAM_COUNTS("Sync.LostNavigationCount", quantity_lost);
+ recorded.clear();
+ }
+}
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/lost_navigations_recorder.h b/chromium/components/sync_sessions/lost_navigations_recorder.h
new file mode 100644
index 00000000000..f90d8e79cb5
--- /dev/null
+++ b/chromium/components/sync_sessions/lost_navigations_recorder.h
@@ -0,0 +1,58 @@
+// 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 COMPONENTS_SYNC_SESSIONS_LOST_NAVIGATIONS_RECORDER_H_
+#define COMPONENTS_SYNC_SESSIONS_LOST_NAVIGATIONS_RECORDER_H_
+
+#include <map>
+#include <set>
+
+#include "base/macros.h"
+#include "components/sessions/core/session_id.h"
+#include "components/sync/api/local_change_observer.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/protocol/session_specifics.pb.h"
+
+namespace sync_sessions {
+
+// Recorder class that tracks the number of navigations written locally that
+// aren't synced. This is done by recording set of locally observed navigations
+// and reconciling these sets against what was ultimately synced. These
+// navigations ultimately feed chrome history, so losing them prevents them from
+// being reflected in the history page.
+class LostNavigationsRecorder : public syncer::LocalChangeObserver {
+ public:
+ typedef SessionID::id_type id_type;
+ typedef std::set<id_type> IdSet;
+ enum RecorderState { RECORDER_STATE_NOT_SYNCING, RECORDER_STATE_SYNCING };
+
+ LostNavigationsRecorder();
+ ~LostNavigationsRecorder() override;
+
+ // syncer::LocalChangeObserver implementation.
+ void OnLocalChange(const syncer::syncable::Entry* current_entry,
+ const syncer::SyncChange& change) override;
+
+ private:
+ void RecordChange(const syncer::SyncChange& change);
+ void DeleteTabs(const sync_pb::SessionHeader& header);
+ void TransitionState(bool is_syncing, bool is_unsynced);
+ void ReconcileLostNavs();
+
+ // State that records whether the most recently observed directory state was
+ // syncing or not syncing.
+ RecorderState recorder_state_;
+
+ // The set of all navigation ids we've observed for each tab_id since the last
+ // sync.
+ std::map<id_type, IdSet> recorded_navigation_ids_;
+ // The set of navigation ids most recently recorded for each tab_id.
+ std::map<id_type, IdSet> latest_navigation_ids_;
+ // The maximum navigation_id recorded for each tab_id.
+ std::map<id_type, id_type> max_recorded_for_tab_;
+ DISALLOW_COPY_AND_ASSIGN(LostNavigationsRecorder);
+};
+}; // namespace sync_sessions
+
+#endif // COMPONENTS_SYNC_SESSIONS_LOST_NAVIGATIONS_RECORDER_H_
diff --git a/chromium/components/sync_sessions/lost_navigations_recorder_unittest.cc b/chromium/components/sync_sessions/lost_navigations_recorder_unittest.cc
new file mode 100644
index 00000000000..d3c19769422
--- /dev/null
+++ b/chromium/components/sync_sessions/lost_navigations_recorder_unittest.cc
@@ -0,0 +1,399 @@
+// 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 "components/sync_sessions/lost_navigations_recorder.h"
+
+#include <memory>
+#include <string>
+
+#include "base/message_loop/message_loop.h"
+#include "base/test/histogram_tester.h"
+#include "components/sync/core/attachments/attachment_service_proxy_for_test.h"
+#include "components/sync/syncable/entry.h"
+#include "components/sync/syncable/mutable_entry.h"
+#include "components/sync/syncable/syncable_base_transaction.h"
+#include "components/sync/syncable/syncable_read_transaction.h"
+#include "components/sync/syncable/syncable_write_transaction.h"
+#include "components/sync/test/engine/test_directory_setter_upper.h"
+#include "components/sync/test/engine/test_id_factory.h"
+#include "components/sync_sessions/sessions_sync_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using syncer::syncable::Entry;
+using syncer::syncable::Id;
+using syncer::syncable::MutableEntry;
+using syncer::syncable::WriteTransaction;
+
+namespace sync_sessions {
+namespace {
+typedef SessionID::id_type id_type;
+
+const char kTab1SyncTag[] = "tab-YWRkcjHvv74=";
+const char kTab2SyncTag[] = "tab-2FyZDHvv74=";
+
+class LostNavigationsRecorderTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ dir_maker_.SetUp();
+ _id = 1;
+ }
+
+ void TearDown() override { dir_maker_.TearDown(); }
+
+ syncer::syncable::Directory* directory() { return dir_maker_.directory(); }
+
+ LostNavigationsRecorder* recorder() { return &recorder_; }
+
+ void AddNavigation(sync_pb::SessionSpecifics* tab_base,
+ id_type id_override = -1) {
+ sync_pb::SessionTab* tab = tab_base->mutable_tab();
+ sync_pb::TabNavigation* navigation = tab->add_navigation();
+ navigation->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED);
+ navigation->set_unique_id(id_override > 0 ? id_override : _id++);
+ }
+
+ void BuildTabSpecifics(const std::string& tag,
+ int tab_id,
+ sync_pb::SessionSpecifics* tab_base,
+ int num_unique_navs = 1) {
+ tab_base->set_session_tag(tag);
+ tab_base->set_tab_node_id(0);
+ sync_pb::SessionTab* tab = tab_base->mutable_tab();
+ tab->set_tab_id(tab_id);
+ tab->set_current_navigation_index(0);
+ for (int i = 0; i < num_unique_navs; ++i) {
+ AddNavigation(tab_base);
+ }
+ }
+
+ void BuildWindowSpecifics(int window_id,
+ sync_pb::SessionSpecifics* window_base) {
+ sync_pb::SessionHeader* header = window_base->mutable_header();
+ sync_pb::SessionWindow* window = header->add_window();
+ window->set_window_id(window_id);
+ }
+
+ const Id& CreateEntry() {
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::CREATE,
+ syncer::SESSIONS, wtrans.root_id(),
+ "entrynamutable_entry");
+ EXPECT_TRUE(mutable_entry.good());
+ return mutable_entry.GetId();
+ }
+
+ const syncer::SyncData CreateLocalData(
+ const sync_pb::SessionSpecifics& specifics,
+ const std::string& sync_tag) const {
+ sync_pb::EntitySpecifics entity;
+ entity.mutable_session()->CopyFrom(specifics);
+ return syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity);
+ }
+
+ syncer::SyncChange MakeChange(const std::string& sync_tag,
+ const sync_pb::SessionSpecifics& specifics,
+ syncer::SyncChange::SyncChangeType type) const {
+ return syncer::SyncChange(FROM_HERE, type,
+ CreateLocalData(specifics, sync_tag));
+ }
+
+ void RecordChange(const Entry* entry, int num_unique_navs) {
+ sync_pb::EntitySpecifics specifics;
+ BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(),
+ num_unique_navs);
+ RecordChange(entry, specifics);
+ }
+
+ void RecordChange(const Entry* entry, sync_pb::EntitySpecifics specifics) {
+ syncer::SyncChange change = MakeChange(kTab1SyncTag, specifics.session(),
+ syncer::SyncChange::ACTION_UPDATE);
+ recorder()->OnLocalChange(entry, change);
+ }
+
+ void TriggerReconcile(MutableEntry* mutable_entry,
+ bool trigger_by_syncing = true,
+ sync_pb::EntitySpecifics* specifics = nullptr) {
+ mutable_entry->PutSyncing(trigger_by_syncing);
+ mutable_entry->PutIsUnsynced(trigger_by_syncing);
+ if (specifics == nullptr) {
+ RecordChange(mutable_entry, 0);
+ } else {
+ RecordChange(mutable_entry, *specifics);
+ }
+ }
+
+ private:
+ base::MessageLoop message_loop;
+ id_type _id;
+ LostNavigationsRecorder recorder_;
+ syncer::TestDirectorySetterUpper dir_maker_;
+};
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsNoneLost) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+ mutable_entry.PutIsUnsynced(true);
+
+ RecordChange(&mutable_entry, 6);
+
+ TriggerReconcile(&mutable_entry);
+ histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsOneLost) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+ mutable_entry.PutIsUnsynced(true);
+
+ RecordChange(&mutable_entry, 1);
+ RecordChange(&mutable_entry, 1);
+
+ TriggerReconcile(&mutable_entry);
+
+ histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 1, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsMultipleLost) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+ mutable_entry.PutIsUnsynced(true);
+
+ RecordChange(&mutable_entry, 5);
+ RecordChange(&mutable_entry, 1);
+
+ TriggerReconcile(&mutable_entry);
+ histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 5, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleWritesWhileSyncing) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+
+ sync_pb::EntitySpecifics specifics;
+ BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+ mutable_entry.PutIsUnsynced(true);
+ RecordChange(&mutable_entry, specifics);
+
+ mutable_entry.PutSyncing(true);
+ RecordChange(&mutable_entry, specifics);
+
+ specifics.mutable_session()->mutable_tab()->clear_navigation();
+ for (int i = 0; i < 5; i++) {
+ AddNavigation(specifics.mutable_session());
+ RecordChange(&mutable_entry, specifics);
+ }
+
+ TriggerReconcile(&mutable_entry, false);
+ histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleWritesMultipleEntriesNoneLost) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ const Id& id2 = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+ MutableEntry mutable_entry2(&wtrans, syncer::syncable::GET_BY_ID, id2);
+ mutable_entry.PutIsUnsynced(true);
+ mutable_entry2.PutIsUnsynced(true);
+
+ sync_pb::EntitySpecifics specifics;
+ sync_pb::EntitySpecifics specifics2;
+ BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+ BuildTabSpecifics(kTab2SyncTag, 2, specifics2.mutable_session(), 5);
+ RecordChange(&mutable_entry, specifics);
+ RecordChange(&mutable_entry2, specifics2);
+
+ mutable_entry.PutSyncing(true);
+ mutable_entry2.PutSyncing(true);
+ RecordChange(&mutable_entry, specifics);
+ RecordChange(&mutable_entry2, specifics2);
+
+ specifics.mutable_session()->mutable_tab()->clear_navigation();
+ specifics2.mutable_session()->mutable_tab()->clear_navigation();
+ for (int i = 0; i < 5; i++) {
+ AddNavigation(specifics.mutable_session());
+ AddNavigation(specifics2.mutable_session());
+
+ RecordChange(&mutable_entry, specifics);
+ RecordChange(&mutable_entry2, specifics2);
+ }
+
+ TriggerReconcile(&mutable_entry, false, &specifics);
+ TriggerReconcile(&mutable_entry2, false, &specifics2);
+
+ histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 4);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleWritesMultipleEntriesMultipleLost) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ const Id& id2 = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+ MutableEntry mutable_entry2(&wtrans, syncer::syncable::GET_BY_ID, id2);
+ mutable_entry.PutIsUnsynced(true);
+ mutable_entry2.PutIsUnsynced(true);
+
+ sync_pb::EntitySpecifics specifics;
+ sync_pb::EntitySpecifics specifics2;
+ BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+ BuildTabSpecifics(kTab2SyncTag, 2, specifics2.mutable_session(), 5);
+ RecordChange(&mutable_entry, specifics);
+ RecordChange(&mutable_entry2, specifics2);
+
+ mutable_entry.PutSyncing(true);
+ mutable_entry2.PutSyncing(true);
+ RecordChange(&mutable_entry, specifics);
+ RecordChange(&mutable_entry2, specifics2);
+
+ specifics.mutable_session()->mutable_tab()->clear_navigation();
+ specifics2.mutable_session()->mutable_tab()->clear_navigation();
+ for (int i = 0; i < 5; i++) {
+ AddNavigation(specifics.mutable_session());
+ AddNavigation(specifics2.mutable_session());
+
+ RecordChange(&mutable_entry, specifics);
+ RecordChange(&mutable_entry2, specifics2);
+ }
+
+ specifics.mutable_session()
+ ->mutable_tab()
+ ->mutable_navigation()
+ ->DeleteSubrange(0, 2);
+ specifics2.mutable_session()
+ ->mutable_tab()
+ ->mutable_navigation()
+ ->DeleteSubrange(0, 2);
+ RecordChange(&mutable_entry, specifics);
+ RecordChange(&mutable_entry, specifics2);
+
+ TriggerReconcile(&mutable_entry, false, &specifics);
+ TriggerReconcile(&mutable_entry2, false, &specifics2);
+
+ histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 2, 2);
+}
+
+TEST_F(LostNavigationsRecorderTest, NoWritesWhileSyncingMultipleLost) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+
+ sync_pb::EntitySpecifics specifics;
+ BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+ syncer::SyncChange change = MakeChange(kTab1SyncTag, specifics.session(),
+ syncer::SyncChange::ACTION_UPDATE);
+ mutable_entry.PutIsUnsynced(true);
+ recorder()->OnLocalChange(&mutable_entry, change);
+
+ specifics.mutable_session()->mutable_tab()->clear_navigation();
+ AddNavigation(specifics.mutable_session());
+ change = MakeChange(kTab1SyncTag, specifics.session(),
+ syncer::SyncChange::ACTION_UPDATE);
+ recorder()->OnLocalChange(&mutable_entry, change);
+
+ mutable_entry.PutIsUnsynced(false);
+ recorder()->OnLocalChange(&mutable_entry, change);
+ histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 5, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, WindowChangeDoesNotTriggerReconcile) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ const Id& id2 = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+ MutableEntry mutable_entry2(&wtrans, syncer::syncable::GET_BY_ID, id2);
+ mutable_entry.PutIsUnsynced(true);
+
+ RecordChange(&mutable_entry, 1);
+
+ sync_pb::EntitySpecifics specifics;
+ BuildWindowSpecifics(1, specifics.mutable_session());
+ RecordChange(&mutable_entry2, specifics);
+
+ EXPECT_EQ(0ul,
+ histogram_tester.GetAllSamples("Sync.LostNavigationCount").size());
+}
+
+TEST_F(LostNavigationsRecorderTest, Samutable_entryNavigationSetAcrossStates) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+
+ sync_pb::EntitySpecifics specifics;
+ BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+ syncer::SyncChange change = MakeChange(kTab1SyncTag, specifics.session(),
+ syncer::SyncChange::ACTION_UPDATE);
+ mutable_entry.PutIsUnsynced(true);
+ recorder()->OnLocalChange(&mutable_entry, change);
+ recorder()->OnLocalChange(&mutable_entry, change);
+
+ mutable_entry.PutIsUnsynced(false);
+ recorder()->OnLocalChange(&mutable_entry, change);
+ histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, RevisitPreviousNavs) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+ mutable_entry.PutIsUnsynced(true);
+
+ sync_pb::EntitySpecifics specifics;
+ BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 3);
+ RecordChange(&mutable_entry, specifics);
+
+ AddNavigation(specifics.mutable_session());
+ RecordChange(&mutable_entry, specifics);
+
+ specifics.mutable_session()
+ ->mutable_tab()
+ ->mutable_navigation()
+ ->RemoveLast();
+ RecordChange(&mutable_entry, specifics);
+
+ TriggerReconcile(&mutable_entry, true, &specifics);
+
+ histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 1, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsMultipleLostWithOverlap) {
+ base::HistogramTester histogram_tester;
+ const Id& id = CreateEntry();
+ WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+ MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+ mutable_entry.PutIsUnsynced(true);
+
+ sync_pb::EntitySpecifics specifics;
+ BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+ RecordChange(&mutable_entry, specifics);
+
+ AddNavigation(specifics.mutable_session());
+ AddNavigation(specifics.mutable_session());
+
+ specifics.mutable_session()
+ ->mutable_tab()
+ ->mutable_navigation()
+ ->DeleteSubrange(0, 2);
+ RecordChange(&mutable_entry, specifics);
+
+ TriggerReconcile(&mutable_entry, true, &specifics);
+
+ histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 2, 1);
+}
+
+}; // namespace
+}; // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/open_tabs_ui_delegate.cc b/chromium/components/sync_sessions/open_tabs_ui_delegate.cc
index 9943d0c5bf7..23084300735 100644
--- a/chromium/components/sync_sessions/open_tabs_ui_delegate.cc
+++ b/chromium/components/sync_sessions/open_tabs_ui_delegate.cc
@@ -4,8 +4,8 @@
#include "components/sync_sessions/open_tabs_ui_delegate.h"
-namespace sync_driver {
+namespace sync_sessions {
OpenTabsUIDelegate::~OpenTabsUIDelegate() {}
-} // namespace sync_driver
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/open_tabs_ui_delegate.h b/chromium/components/sync_sessions/open_tabs_ui_delegate.h
index 911b83e9da2..cf8fd5faee4 100644
--- a/chromium/components/sync_sessions/open_tabs_ui_delegate.h
+++ b/chromium/components/sync_sessions/open_tabs_ui_delegate.h
@@ -14,7 +14,7 @@
#include "components/sessions/core/session_types.h"
#include "components/sync_sessions/synced_session.h"
-namespace sync_driver {
+namespace sync_sessions {
class OpenTabsUIDelegate {
public:
@@ -64,6 +64,6 @@ class OpenTabsUIDelegate {
virtual ~OpenTabsUIDelegate();
};
-} // namespace sync_driver
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_OPEN_TABS_UI_DELEGATE_H_
diff --git a/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer.h b/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer.h
index 6953755030f..5ae4bba00d8 100644
--- a/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer.h
+++ b/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer.h
@@ -37,7 +37,7 @@ class BookmarksByUrlProvider {
// processing in task/thread, which is okay since it only accesses values in
// memory. Potential slow downs could occur when it fails to get bookmarks lock
// and when the number of matching Bookmarks for a single URL is very large.
-class BookmarksPageRevisitObserver : public sync_sessions::PageVisitObserver {
+class BookmarksPageRevisitObserver : public PageVisitObserver {
public:
explicit BookmarksPageRevisitObserver(
std::unique_ptr<BookmarksByUrlProvider> provider);
diff --git a/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc b/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc
index a6e887ec3a1..9ead16bc0a1 100644
--- a/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc
+++ b/chromium/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc
@@ -4,13 +4,9 @@
#include "components/sync_sessions/revisit/bookmarks_page_revisit_observer.h"
-#include <memory>
-#include <vector>
-
#include "base/memory/ptr_util.h"
#include "base/test/histogram_tester.h"
#include "components/bookmarks/browser/bookmark_node.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -39,7 +35,7 @@ class TestBookmarksByUrlProvider : public BookmarksByUrlProvider {
void RunObserver(const std::vector<const bookmarks::BookmarkNode*>& nodes) {
BookmarksPageRevisitObserver observer(
- base::WrapUnique(new TestBookmarksByUrlProvider(nodes)));
+ base::MakeUnique<TestBookmarksByUrlProvider>(nodes));
observer.OnPageVisit(kExampleGurl, PageVisitObserver::kTransitionPage);
}
diff --git a/chromium/components/sync_sessions/revisit/current_tab_matcher_unittest.cc b/chromium/components/sync_sessions/revisit/current_tab_matcher_unittest.cc
index 600ee7e311c..4add6b797e0 100644
--- a/chromium/components/sync_sessions/revisit/current_tab_matcher_unittest.cc
+++ b/chromium/components/sync_sessions/revisit/current_tab_matcher_unittest.cc
@@ -12,8 +12,6 @@
#include "components/sessions/core/serialized_navigation_entry.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "components/sessions/core/session_types.h"
-#include "components/sync_sessions/revisit/page_equality.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -23,8 +21,8 @@ namespace sync_sessions {
namespace {
-static const std::string kExampleUrl = "http://www.example.com";
-static const std::string kDifferentUrl = "http://www.different.com";
+const char kExampleUrl[] = "http://www.example.com";
+const char kDifferentUrl[] = "http://www.different.com";
sessions::SerializedNavigationEntry Entry(const std::string& url) {
return sessions::SerializedNavigationEntryTestHelper::CreateNavigation(url,
diff --git a/chromium/components/sync_sessions/revisit/offset_tab_matcher_unittest.cc b/chromium/components/sync_sessions/revisit/offset_tab_matcher_unittest.cc
index c2b7a08c469..4388c29d241 100644
--- a/chromium/components/sync_sessions/revisit/offset_tab_matcher_unittest.cc
+++ b/chromium/components/sync_sessions/revisit/offset_tab_matcher_unittest.cc
@@ -12,8 +12,6 @@
#include "components/sessions/core/serialized_navigation_entry.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "components/sessions/core/session_types.h"
-#include "components/sync_sessions/revisit/page_equality.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -23,8 +21,8 @@ namespace sync_sessions {
namespace {
-static const std::string kExampleUrl = "http://www.example.com";
-static const std::string kDifferentUrl = "http://www.different.com";
+const char kExampleUrl[] = "http://www.example.com";
+const char kDifferentUrl[] = "http://www.different.com";
sessions::SerializedNavigationEntry Entry(const std::string& url) {
return sessions::SerializedNavigationEntryTestHelper::CreateNavigation(url,
diff --git a/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.cc b/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.cc
index 66fe702c596..9cbf32c98ee 100644
--- a/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.cc
+++ b/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.cc
@@ -8,7 +8,6 @@
#include <string>
#include <vector>
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "components/bookmarks/browser/bookmark_model.h"
@@ -20,21 +19,20 @@
#include "components/sync_sessions/sessions_sync_manager.h"
#include "components/sync_sessions/sync_sessions_client.h"
-namespace browser_sync {
+namespace sync_sessions {
namespace {
// Simple implementation of ForeignSessionsProvider that delegates to
// SessionsSyncManager. It holds onto a non-owning pointer, with the assumption
// that this class is only used by classes owned by SessionsSyncManager itself.
-class SessionsSyncManagerWrapper
- : public sync_sessions::ForeignSessionsProvider {
+class SessionsSyncManagerWrapper : public ForeignSessionsProvider {
public:
explicit SessionsSyncManagerWrapper(SessionsSyncManager* manager)
: manager_(manager) {}
~SessionsSyncManagerWrapper() override{};
bool GetAllForeignSessions(
- std::vector<const sync_driver::SyncedSession*>* sessions) override {
+ std::vector<const SyncedSession*>* sessions) override {
return manager_->GetAllForeignSessions(sessions);
}
@@ -47,26 +45,24 @@ class SessionsSyncManagerWrapper
PageRevisitBroadcaster::PageRevisitBroadcaster(
SessionsSyncManager* manager,
- sync_sessions::SyncSessionsClient* sessions_client)
+ SyncSessionsClient* sessions_client)
: sessions_client_(sessions_client) {
const std::string group_name =
base::FieldTrialList::FindFullName("PageRevisitInstrumentation");
bool shouldInstrument = group_name == "Enabled";
if (shouldInstrument) {
- revisit_observers_.push_back(new sync_sessions::SessionsPageRevisitObserver(
- base::WrapUnique(new SessionsSyncManagerWrapper(manager))));
+ revisit_observers_.push_back(new SessionsPageRevisitObserver(
+ base::MakeUnique<SessionsSyncManagerWrapper>(manager)));
history::HistoryService* history = sessions_client_->GetHistoryService();
if (history) {
- revisit_observers_.push_back(
- new sync_sessions::TypedUrlPageRevisitObserver(history));
+ revisit_observers_.push_back(new TypedUrlPageRevisitObserver(history));
}
bookmarks::BookmarkModel* bookmarks = sessions_client_->GetBookmarkModel();
if (bookmarks) {
- revisit_observers_.push_back(
- new sync_sessions::BookmarksPageRevisitObserver(base::WrapUnique(
- new sync_sessions::BookmarksByUrlProviderImpl(bookmarks))));
+ revisit_observers_.push_back(new BookmarksPageRevisitObserver(
+ base::MakeUnique<BookmarksByUrlProviderImpl>(bookmarks)));
}
}
}
@@ -76,7 +72,7 @@ PageRevisitBroadcaster::~PageRevisitBroadcaster() {}
void PageRevisitBroadcaster::OnPageVisit(const GURL& url,
const ui::PageTransition transition) {
if (sessions_client_->ShouldSyncURL(url)) {
- sync_sessions::PageVisitObserver::TransitionType converted(
+ PageVisitObserver::TransitionType converted(
ConvertTransitionEnum(transition));
for (auto* observer : revisit_observers_) {
observer->OnPageVisit(url, converted);
@@ -85,52 +81,51 @@ void PageRevisitBroadcaster::OnPageVisit(const GURL& url,
}
// Static
-sync_sessions::PageVisitObserver::TransitionType
-PageRevisitBroadcaster::ConvertTransitionEnum(
+PageVisitObserver::TransitionType PageRevisitBroadcaster::ConvertTransitionEnum(
const ui::PageTransition original) {
switch (ui::PageTransitionStripQualifier(original)) {
case ui::PAGE_TRANSITION_LINK:
if (original & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) {
- return sync_sessions::PageVisitObserver::kTransitionCopyPaste;
+ return PageVisitObserver::kTransitionCopyPaste;
} else {
- return sync_sessions::PageVisitObserver::kTransitionPage;
+ return PageVisitObserver::kTransitionPage;
}
case ui::PAGE_TRANSITION_TYPED:
- return sync_sessions::PageVisitObserver::kTransitionOmniboxUrl;
+ return PageVisitObserver::kTransitionOmniboxUrl;
case ui::PAGE_TRANSITION_AUTO_BOOKMARK:
- return sync_sessions::PageVisitObserver::kTransitionBookmark;
+ return PageVisitObserver::kTransitionBookmark;
case ui::PAGE_TRANSITION_AUTO_SUBFRAME:
case ui::PAGE_TRANSITION_MANUAL_SUBFRAME:
// These are not expected, we only expect top-level frame transitions.
- return sync_sessions::PageVisitObserver::kTransitionUnknown;
+ return PageVisitObserver::kTransitionUnknown;
case ui::PAGE_TRANSITION_GENERATED:
- return sync_sessions::PageVisitObserver::kTransitionOmniboxDefaultSearch;
+ return PageVisitObserver::kTransitionOmniboxDefaultSearch;
case ui::PAGE_TRANSITION_AUTO_TOPLEVEL:
if (original & ui::PAGE_TRANSITION_FORWARD_BACK) {
- return sync_sessions::PageVisitObserver::kTransitionForwardBackward;
+ return PageVisitObserver::kTransitionForwardBackward;
} else {
- return sync_sessions::PageVisitObserver::kTransitionUnknown;
+ return PageVisitObserver::kTransitionUnknown;
}
case ui::PAGE_TRANSITION_FORM_SUBMIT:
- return sync_sessions::PageVisitObserver::kTransitionPage;
+ return PageVisitObserver::kTransitionPage;
case ui::PAGE_TRANSITION_RELOAD:
// Refreshing pages also carry PAGE_TRANSITION_RELOAD but the url never
// changes so we don't expect to ever get them.
- return sync_sessions::PageVisitObserver::kTransitionRestore;
+ return PageVisitObserver::kTransitionRestore;
case ui::PAGE_TRANSITION_KEYWORD:
case ui::PAGE_TRANSITION_KEYWORD_GENERATED:
- return sync_sessions::PageVisitObserver::kTransitionOmniboxTemplateSearch;
+ return PageVisitObserver::kTransitionOmniboxTemplateSearch;
default:
- return sync_sessions::PageVisitObserver::kTransitionUnknown;
+ return PageVisitObserver::kTransitionUnknown;
}
}
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.h b/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.h
index 8e56575ea6b..bf987899b10 100644
--- a/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.h
+++ b/chromium/components/sync_sessions/revisit/page_revisit_broadcaster.h
@@ -15,7 +15,7 @@ namespace sync_sessions {
class SyncSessionsClient;
}
-namespace browser_sync {
+namespace sync_sessions {
class SessionsSyncManager;
@@ -25,7 +25,7 @@ class SessionsSyncManager;
class PageRevisitBroadcaster {
public:
PageRevisitBroadcaster(SessionsSyncManager* manager,
- sync_sessions::SyncSessionsClient* sessions_client);
+ SyncSessionsClient* sessions_client);
~PageRevisitBroadcaster();
// Broadcasts to all observers the given page visit event. Should only be
@@ -39,17 +39,17 @@ class PageRevisitBroadcaster {
// observers to depend on ui/, and the high bit masks don't work for emitting
// histograms. Some of the high bit masks correspond to cases we're
// particularly interested in and want to treat as first class values.
- static sync_sessions::PageVisitObserver::TransitionType ConvertTransitionEnum(
+ static PageVisitObserver::TransitionType ConvertTransitionEnum(
const ui::PageTransition original);
// The client of this sync sessions datatype.
- sync_sessions::SyncSessionsClient* const sessions_client_;
+ SyncSessionsClient* const sessions_client_;
- ScopedVector<sync_sessions::PageVisitObserver> revisit_observers_;
+ ScopedVector<PageVisitObserver> revisit_observers_;
DISALLOW_COPY_AND_ASSIGN(PageRevisitBroadcaster);
};
-} // namespace browser_sync
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_REVISIT_PAGE_REVISIT_BROADCASTER_H_
diff --git a/chromium/components/sync_sessions/revisit/page_revisit_broadcaster_unittest.cc b/chromium/components/sync_sessions/revisit/page_revisit_broadcaster_unittest.cc
index 8a7e950a098..a2e13fd403c 100644
--- a/chromium/components/sync_sessions/revisit/page_revisit_broadcaster_unittest.cc
+++ b/chromium/components/sync_sessions/revisit/page_revisit_broadcaster_unittest.cc
@@ -6,13 +6,9 @@
#include <stdint.h>
-#include "components/sync_sessions/revisit/page_visit_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/page_transition_types.h"
-using sync_sessions::PageVisitObserver;
-
-namespace browser_sync {
+namespace sync_sessions {
class SyncPageRevisitBroadcasterTest : public ::testing::Test {
protected:
@@ -109,4 +105,4 @@ TEST_F(SyncPageRevisitBroadcasterTest, ConvertUnknown) {
ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
}
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.cc b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.cc
index 8c81975dcb3..ccb603aa25e 100644
--- a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.cc
+++ b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.cc
@@ -53,20 +53,19 @@ void SessionsPageRevisitObserver::CheckForRevisit(
CurrentTabMatcher current_matcher(page_equality);
OffsetTabMatcher offset_matcher(page_equality);
- std::vector<const sync_driver::SyncedSession*> foreign_sessions;
+ std::vector<const SyncedSession*> foreign_sessions;
if (provider_->GetAllForeignSessions(&foreign_sessions)) {
- for (const sync_driver::SyncedSession* session : foreign_sessions) {
- for (const std::pair<const SessionID::id_type, sessions::SessionWindow*>&
- key_value : session->windows) {
- for (const sessions::SessionTab* tab : key_value.second->tabs) {
+ for (const SyncedSession* session : foreign_sessions) {
+ for (const auto& key_value : session->windows) {
+ for (const auto& tab : key_value.second->tabs) {
// These matchers look identical and could easily implement an
// interface and we could iterate through a vector of matchers here.
// However this would cause quite a bit of overhead at the inner most
// loop of something that takes linear time in relation to the number
// of open foreign tabs. A small fraction of users have thousands of
// open tabs.
- current_matcher.Check(tab);
- offset_matcher.Check(tab);
+ current_matcher.Check(tab.get());
+ offset_matcher.Check(tab.get());
}
}
}
diff --git a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.h b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.h
index 294e9c8bddd..a865ef49926 100644
--- a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.h
+++ b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer.h
@@ -18,14 +18,11 @@ namespace sessions {
struct SessionTab;
} // namespace sessions
-namespace sync_driver {
-struct SyncedSession;
-} // namespace sync_driver
-
namespace sync_sessions {
class CurrentTabMatcher;
class OffsetTabMatcher;
+struct SyncedSession;
// A simple interface to abstract away who is providing sessions.
class ForeignSessionsProvider {
@@ -34,7 +31,7 @@ class ForeignSessionsProvider {
// Returned boolean representes if there were foreign sessions and the vector
// should be examimed.
virtual bool GetAllForeignSessions(
- std::vector<const sync_driver::SyncedSession*>* sessions) = 0;
+ std::vector<const SyncedSession*>* sessions) = 0;
virtual ~ForeignSessionsProvider() {}
};
diff --git a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
index 179895e35c2..e7b3181d3d3 100644
--- a/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
+++ b/chromium/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
@@ -4,29 +4,27 @@
#include "components/sync_sessions/revisit/sessions_page_revisit_observer.h"
-#include <memory>
#include <string>
+#include <utility>
#include "base/memory/ptr_util.h"
#include "base/test/histogram_tester.h"
#include "components/sessions/core/serialized_navigation_entry.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "components/sessions/core/session_types.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
#include "components/sync_sessions/synced_session.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using sessions::SessionTab;
using sessions::SessionWindow;
-using sync_driver::SyncedSession;
namespace sync_sessions {
namespace {
-static const std::string kExampleUrl = "http://www.example.com";
-static const std::string kDifferentUrl = "http://www.different.com";
+static const char kExampleUrl[] = "http://www.example.com";
+static const char kDifferentUrl[] = "http://www.different.com";
class TestForeignSessionsProvider : public ForeignSessionsProvider {
public:
@@ -76,7 +74,7 @@ class SessionsPageRevisitObserverTest : public ::testing::Test {
std::vector<const SyncedSession*> sessions;
sessions.push_back(session);
SessionsPageRevisitObserver observer(
- base::WrapUnique(new TestForeignSessionsProvider(sessions, true)));
+ base::MakeUnique<TestForeignSessionsProvider>(sessions, true));
CheckAndExpect(&observer, url, current_match, offset_match);
}
};
@@ -84,44 +82,44 @@ class SessionsPageRevisitObserverTest : public ::testing::Test {
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoSessions) {
std::vector<const SyncedSession*> sessions;
SessionsPageRevisitObserver observer(
- base::WrapUnique(new TestForeignSessionsProvider(sessions, true)));
+ base::MakeUnique<TestForeignSessionsProvider>(sessions, true));
CheckAndExpect(&observer, GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoWindows) {
- std::unique_ptr<SyncedSession> session(new SyncedSession());
+ std::unique_ptr<SyncedSession> session = base::MakeUnique<SyncedSession>();
CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoTabs) {
- std::unique_ptr<SyncedSession> session(new SyncedSession());
- session->windows[0] = new SessionWindow();
+ std::unique_ptr<SyncedSession> session = base::MakeUnique<SyncedSession>();
+ session->windows[0] = base::MakeUnique<SessionWindow>();
CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoEntries) {
- std::unique_ptr<SessionWindow> window(new SessionWindow());
- window->tabs.push_back(new SessionTab());
- std::unique_ptr<SyncedSession> session(new SyncedSession());
- session->windows[0] = window.release();
+ std::unique_ptr<SessionWindow> window = base::MakeUnique<SessionWindow>();
+ window->tabs.push_back(base::MakeUnique<SessionTab>());
+ std::unique_ptr<SyncedSession> session = base::MakeUnique<SyncedSession>();
+ session->windows[0] = std::move(window);
CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersSingle) {
- std::unique_ptr<SessionTab> tab(new SessionTab());
+ std::unique_ptr<SessionTab> tab = base::MakeUnique<SessionTab>();
tab->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
tab->current_navigation_index = 0;
- std::unique_ptr<SessionWindow> window(new SessionWindow());
- window->tabs.push_back(tab.release());
- std::unique_ptr<SyncedSession> session(new SyncedSession());
- session->windows[0] = window.release();
+ std::unique_ptr<SessionWindow> window = base::MakeUnique<SessionWindow>();
+ window->tabs.push_back(std::move(tab));
+ std::unique_ptr<SyncedSession> session = base::MakeUnique<SyncedSession>();
+ session->windows[0] = std::move(window);
CheckAndExpect(session.get(), GURL(kExampleUrl), true, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersFalseProvider) {
- std::unique_ptr<SessionTab> tab(new SessionTab());
+ std::unique_ptr<SessionTab> tab = base::MakeUnique<SessionTab>();
tab->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
@@ -129,40 +127,40 @@ TEST_F(SessionsPageRevisitObserverTest, RunMatchersFalseProvider) {
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
tab->current_navigation_index = 1;
- std::unique_ptr<SessionWindow> window(new SessionWindow());
- window->tabs.push_back(tab.release());
- std::unique_ptr<SyncedSession> session(new SyncedSession());
- session->windows[0] = window.release();
+ std::unique_ptr<SessionWindow> window = base::MakeUnique<SessionWindow>();
+ window->tabs.push_back(std::move(tab));
+ std::unique_ptr<SyncedSession> session = base::MakeUnique<SyncedSession>();
+ session->windows[0] = std::move(window);
// The provider returns false when asked for foreign sessions, even though
// it has has a valid tab.
std::vector<const SyncedSession*> sessions;
sessions.push_back(session.get());
SessionsPageRevisitObserver observer(
- base::WrapUnique(new TestForeignSessionsProvider(sessions, false)));
+ base::MakeUnique<TestForeignSessionsProvider>(sessions, false));
CheckAndExpect(&observer, GURL(kExampleUrl), false, false);
}
TEST_F(SessionsPageRevisitObserverTest, RunMatchersMany) {
- std::unique_ptr<SessionTab> tab1(new SessionTab());
+ std::unique_ptr<SessionTab> tab1 = base::MakeUnique<SessionTab>();
tab1->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
tab1->current_navigation_index = 0;
- std::unique_ptr<SessionTab> tab2(new SessionTab());
+ std::unique_ptr<SessionTab> tab2 = base::MakeUnique<SessionTab>();
tab2->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kDifferentUrl, ""));
tab2->current_navigation_index = 0;
- std::unique_ptr<SessionTab> tab3(new SessionTab());
+ std::unique_ptr<SessionTab> tab3 = base::MakeUnique<SessionTab>();
tab3->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kDifferentUrl, ""));
tab3->current_navigation_index = 0;
- std::unique_ptr<SessionTab> tab4(new SessionTab());
+ std::unique_ptr<SessionTab> tab4 = base::MakeUnique<SessionTab>();
tab4->navigations.push_back(
sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
kExampleUrl, ""));
@@ -171,25 +169,25 @@ TEST_F(SessionsPageRevisitObserverTest, RunMatchersMany) {
kDifferentUrl, ""));
tab4->current_navigation_index = 1;
- std::unique_ptr<SessionWindow> window1(new SessionWindow());
- window1->tabs.push_back(tab1.release());
- std::unique_ptr<SessionWindow> window2(new SessionWindow());
- window2->tabs.push_back(tab2.release());
- std::unique_ptr<SessionWindow> window3(new SessionWindow());
- window3->tabs.push_back(tab3.release());
- window3->tabs.push_back(tab4.release());
+ std::unique_ptr<SessionWindow> window1 = base::MakeUnique<SessionWindow>();
+ window1->tabs.push_back(std::move(tab1));
+ std::unique_ptr<SessionWindow> window2 = base::MakeUnique<SessionWindow>();
+ window2->tabs.push_back(std::move(tab2));
+ std::unique_ptr<SessionWindow> window3 = base::MakeUnique<SessionWindow>();
+ window3->tabs.push_back(std::move(tab3));
+ window3->tabs.push_back(std::move(tab4));
- std::unique_ptr<SyncedSession> session1(new SyncedSession());
- session1->windows[1] = window1.release();
- std::unique_ptr<SyncedSession> session2(new SyncedSession());
- session2->windows[2] = window2.release();
- session2->windows[3] = window3.release();
+ std::unique_ptr<SyncedSession> session1 = base::MakeUnique<SyncedSession>();
+ session1->windows[1] = std::move(window1);
+ std::unique_ptr<SyncedSession> session2 = base::MakeUnique<SyncedSession>();
+ session2->windows[2] = std::move(window2);
+ session2->windows[3] = std::move(window3);
std::vector<const SyncedSession*> sessions;
sessions.push_back(session1.get());
sessions.push_back(session2.get());
SessionsPageRevisitObserver observer(
- base::WrapUnique(new TestForeignSessionsProvider(sessions, true)));
+ base::MakeUnique<TestForeignSessionsProvider>(sessions, true));
base::HistogramTester histogram_tester;
CheckAndExpect(&observer, GURL(kExampleUrl), true, true);
diff --git a/chromium/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc b/chromium/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc
index 747910b4871..f102220b428 100644
--- a/chromium/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc
+++ b/chromium/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc
@@ -22,7 +22,7 @@ void TypedUrlPageRevisitObserver::OnPageVisit(
const PageVisitObserver::TransitionType transition) {
if (history_) {
history_->ScheduleDBTask(
- base::WrapUnique(new TypedUrlPageRevisitTask(url, transition)),
+ base::MakeUnique<TypedUrlPageRevisitTask>(url, transition),
&task_tracker_);
}
}
diff --git a/chromium/components/sync_sessions/revisit/typed_url_page_revisit_task_unittest.cc b/chromium/components/sync_sessions/revisit/typed_url_page_revisit_task_unittest.cc
index d8bf3fab5f3..ac6db2c1e32 100644
--- a/chromium/components/sync_sessions/revisit/typed_url_page_revisit_task_unittest.cc
+++ b/chromium/components/sync_sessions/revisit/typed_url_page_revisit_task_unittest.cc
@@ -7,10 +7,7 @@
#include "base/test/histogram_tester.h"
#include "base/time/time.h"
#include "components/history/core/browser/history_backend.h"
-#include "components/history/core/browser/history_types.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
namespace sync_sessions {
diff --git a/chromium/components/sync_sessions/session_data_type_controller.cc b/chromium/components/sync_sessions/session_data_type_controller.cc
index 6398cb63a01..ec144668b07 100644
--- a/chromium/components/sync_sessions/session_data_type_controller.cc
+++ b/chromium/components/sync_sessions/session_data_type_controller.cc
@@ -4,24 +4,22 @@
#include "components/sync_sessions/session_data_type_controller.h"
+#include <set>
+
#include "components/prefs/pref_service.h"
-#include "components/sync_driver/sync_client.h"
+#include "components/sync/driver/sync_client.h"
#include "components/sync_sessions/sync_sessions_client.h"
#include "components/sync_sessions/synced_window_delegate.h"
#include "components/sync_sessions/synced_window_delegates_getter.h"
-namespace browser_sync {
+namespace sync_sessions {
SessionDataTypeController::SessionDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
- sync_driver::LocalDeviceInfoProvider* local_device,
+ const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
+ syncer::LocalDeviceInfoProvider* local_device,
const char* history_disabled_pref_name)
- : UIDataTypeController(ui_thread,
- error_callback,
- syncer::SESSIONS,
- sync_client),
+ : UIDataTypeController(syncer::SESSIONS, dump_stack, sync_client),
sync_client_(sync_client),
local_device_(local_device),
history_disabled_pref_name_(history_disabled_pref_name),
@@ -32,19 +30,18 @@ SessionDataTypeController::SessionDataTypeController(
pref_registrar_.Add(
history_disabled_pref_name_,
base::Bind(&SessionDataTypeController::OnSavingBrowserHistoryPrefChanged,
- base::Unretained(this)));
+ base::AsWeakPtr(this)));
}
SessionDataTypeController::~SessionDataTypeController() {}
bool SessionDataTypeController::StartModels() {
- DCHECK(ui_thread()->BelongsToCurrentThread());
- browser_sync::SyncedWindowDelegatesGetter* synced_window_getter =
+ DCHECK(CalledOnValidThread());
+ SyncedWindowDelegatesGetter* synced_window_getter =
sync_client_->GetSyncSessionsClient()->GetSyncedWindowDelegatesGetter();
- std::set<const browser_sync::SyncedWindowDelegate*> window =
+ std::set<const SyncedWindowDelegate*> window =
synced_window_getter->GetSyncedWindowDelegates();
- for (std::set<const browser_sync::SyncedWindowDelegate*>::const_iterator i =
- window.begin();
+ for (std::set<const SyncedWindowDelegate*>::const_iterator i = window.begin();
i != window.end(); ++i) {
if ((*i)->IsSessionRestoreInProgress()) {
waiting_on_session_restore_ = true;
@@ -53,8 +50,9 @@ bool SessionDataTypeController::StartModels() {
}
if (!local_device_->GetLocalDeviceInfo()) {
- subscription_ = local_device_->RegisterOnInitializedCallback(base::Bind(
- &SessionDataTypeController::OnLocalDeviceInfoInitialized, this));
+ subscription_ = local_device_->RegisterOnInitializedCallback(
+ base::Bind(&SessionDataTypeController::OnLocalDeviceInfoInitialized,
+ base::AsWeakPtr(this)));
waiting_on_local_device_info_ = true;
}
@@ -62,17 +60,18 @@ bool SessionDataTypeController::StartModels() {
}
void SessionDataTypeController::StopModels() {
+ DCHECK(CalledOnValidThread());
subscription_.reset();
}
bool SessionDataTypeController::ReadyForStart() const {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
return !sync_client_->GetPrefService()->GetBoolean(
history_disabled_pref_name_);
}
void SessionDataTypeController::OnSessionRestoreComplete() {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
waiting_on_session_restore_ = false;
MaybeCompleteLoading();
}
@@ -88,7 +87,7 @@ void SessionDataTypeController::MaybeCompleteLoading() {
}
void SessionDataTypeController::OnLocalDeviceInfoInitialized() {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
subscription_.reset();
waiting_on_local_device_info_ = false;
@@ -96,7 +95,7 @@ void SessionDataTypeController::OnLocalDeviceInfoInitialized() {
}
void SessionDataTypeController::OnSavingBrowserHistoryPrefChanged() {
- DCHECK(ui_thread()->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
if (sync_client_->GetPrefService()->GetBoolean(history_disabled_pref_name_)) {
// If history and tabs persistence is turned off then generate an
// unrecoverable error. SESSIONS won't be a registered type on the next
@@ -106,9 +105,9 @@ void SessionDataTypeController::OnSavingBrowserHistoryPrefChanged() {
FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR,
"History and tab saving is now disabled by policy.",
syncer::SESSIONS);
- OnSingleDataTypeUnrecoverableError(error);
+ CreateErrorHandler()->OnUnrecoverableError(error);
}
}
}
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/session_data_type_controller.h b/chromium/components/sync_sessions/session_data_type_controller.h
index 601501bc7c1..44222a2564b 100644
--- a/chromium/components/sync_sessions/session_data_type_controller.h
+++ b/chromium/components/sync_sessions/session_data_type_controller.h
@@ -9,22 +9,22 @@
#include "base/macros.h"
#include "components/prefs/pref_change_registrar.h"
-#include "components/sync_driver/local_device_info_provider.h"
-#include "components/sync_driver/ui_data_type_controller.h"
+#include "components/sync/device_info/local_device_info_provider.h"
+#include "components/sync/driver/ui_data_type_controller.h"
-namespace browser_sync {
+namespace sync_sessions {
// Overrides StartModels to avoid sync contention with sessions during
// a session restore operation at startup and to wait for the local
// device info to become available.
-class SessionDataTypeController : public sync_driver::UIDataTypeController {
+class SessionDataTypeController : public syncer::UIDataTypeController {
public:
- SessionDataTypeController(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
- const base::Closure& error_callback,
- sync_driver::SyncClient* sync_client,
- sync_driver::LocalDeviceInfoProvider* local_device,
- const char* history_disabled_pref_name);
+ // |dump_stack| is called when an unrecoverable error occurs.
+ SessionDataTypeController(const base::Closure& dump_stack,
+ syncer::SyncClient* sync_client,
+ syncer::LocalDeviceInfoProvider* local_device,
+ const char* history_disabled_pref_name);
+ ~SessionDataTypeController() override;
// UIDataTypeController interface.
bool StartModels() override;
@@ -34,20 +34,16 @@ class SessionDataTypeController : public sync_driver::UIDataTypeController {
// Called when asynchronous session restore has completed.
void OnSessionRestoreComplete();
- protected:
- ~SessionDataTypeController() override;
-
private:
bool IsWaiting();
void MaybeCompleteLoading();
void OnLocalDeviceInfoInitialized();
void OnSavingBrowserHistoryPrefChanged();
- sync_driver::SyncClient* const sync_client_;
+ syncer::SyncClient* const sync_client_;
- sync_driver::LocalDeviceInfoProvider* const local_device_;
- std::unique_ptr<sync_driver::LocalDeviceInfoProvider::Subscription>
- subscription_;
+ syncer::LocalDeviceInfoProvider* const local_device_;
+ std::unique_ptr<syncer::LocalDeviceInfoProvider::Subscription> subscription_;
// Name of the pref that indicates whether saving history is disabled.
const char* history_disabled_pref_name_;
@@ -61,6 +57,6 @@ class SessionDataTypeController : public sync_driver::UIDataTypeController {
DISALLOW_COPY_AND_ASSIGN(SessionDataTypeController);
};
-} // namespace browser_sync
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_SESSION_DATA_TYPE_CONTROLLER_H_
diff --git a/chromium/components/sync_sessions/session_data_type_controller_unittest.cc b/chromium/components/sync_sessions/session_data_type_controller_unittest.cc
index 42f69ae164b..5dc16c41be1 100644
--- a/chromium/components/sync_sessions/session_data_type_controller_unittest.cc
+++ b/chromium/components/sync_sessions/session_data_type_controller_unittest.cc
@@ -4,6 +4,8 @@
#include "components/sync_sessions/session_data_type_controller.h"
+#include <set>
+
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_path.h"
@@ -13,17 +15,17 @@
#include "base/threading/thread_task_runner_handle.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
-#include "components/sync_driver/fake_sync_client.h"
-#include "components/sync_driver/local_device_info_provider_mock.h"
-#include "components/sync_driver/sync_api_component_factory_mock.h"
+#include "components/sync/device_info/local_device_info_provider_mock.h"
+#include "components/sync/driver/fake_sync_client.h"
+#include "components/sync/driver/sync_api_component_factory_mock.h"
#include "components/sync_sessions/fake_sync_sessions_client.h"
#include "components/sync_sessions/synced_window_delegate.h"
#include "components/sync_sessions/synced_window_delegates_getter.h"
#include "testing/gtest/include/gtest/gtest.h"
-using sync_driver::LocalDeviceInfoProviderMock;
+using syncer::LocalDeviceInfoProviderMock;
-namespace browser_sync {
+namespace sync_sessions {
namespace {
@@ -77,36 +79,34 @@ class MockSyncedWindowDelegatesGetter : public SyncedWindowDelegatesGetter {
std::set<const SyncedWindowDelegate*> delegates_;
};
-class TestSyncSessionsClient : public sync_sessions::FakeSyncSessionsClient {
+class TestSyncSessionsClient : public FakeSyncSessionsClient {
public:
- browser_sync::SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter()
- override {
+ SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter() override {
return synced_window_getter_;
}
void SetSyncedWindowDelegatesGetter(
- browser_sync::SyncedWindowDelegatesGetter* synced_window_getter) {
+ SyncedWindowDelegatesGetter* synced_window_getter) {
synced_window_getter_ = synced_window_getter;
}
private:
- browser_sync::SyncedWindowDelegatesGetter* synced_window_getter_;
+ SyncedWindowDelegatesGetter* synced_window_getter_;
};
class SessionDataTypeControllerTest : public testing::Test,
- public sync_driver::FakeSyncClient {
+ public syncer::FakeSyncClient {
public:
SessionDataTypeControllerTest()
- : sync_driver::FakeSyncClient(&profile_sync_factory_),
+ : syncer::FakeSyncClient(&profile_sync_factory_),
load_finished_(false),
- last_type_(syncer::UNSPECIFIED),
- weak_ptr_factory_(this) {}
+ last_type_(syncer::UNSPECIFIED) {}
~SessionDataTypeControllerTest() override {}
// FakeSyncClient overrides.
PrefService* GetPrefService() override { return &prefs_; }
- sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override {
+ SyncSessionsClient* GetSyncSessionsClient() override {
return sync_sessions_client_.get();
}
@@ -125,30 +125,22 @@ class SessionDataTypeControllerTest : public testing::Test,
"cache_guid", "Wayne Gretzky's Hacking Box", "Chromium 10k",
"Chrome 10k", sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "device_id"));
- controller_ = new SessionDataTypeController(
- base::ThreadTaskRunnerHandle::Get(), base::Bind(&base::DoNothing), this,
- local_device_.get(), kSavingBrowserHistoryDisabled);
+ controller_.reset(new SessionDataTypeController(
+ base::Bind(&base::DoNothing), this, local_device_.get(),
+ kSavingBrowserHistoryDisabled));
load_finished_ = false;
last_type_ = syncer::UNSPECIFIED;
last_error_ = syncer::SyncError();
}
- void TearDown() override {
- controller_ = NULL;
- local_device_.reset();
- synced_window_getter_.reset();
- synced_window_delegate_.reset();
- sync_sessions_client_.reset();
- }
-
void Start() {
controller_->LoadModels(
base::Bind(&SessionDataTypeControllerTest::OnLoadFinished,
- weak_ptr_factory_.GetWeakPtr()));
+ base::Unretained(this)));
}
- void OnLoadFinished(syncer::ModelType type, syncer::SyncError error) {
+ void OnLoadFinished(syncer::ModelType type, const syncer::SyncError& error) {
load_finished_ = true;
last_type_ = type;
last_error_ = error;
@@ -174,6 +166,10 @@ class SessionDataTypeControllerTest : public testing::Test,
return testing::AssertionSuccess();
}
+ bool load_finished() const { return load_finished_; }
+ LocalDeviceInfoProviderMock* local_device() { return local_device_.get(); }
+ SessionDataTypeController* controller() { return controller_.get(); }
+
protected:
void SetSessionRestoreInProgress(bool is_restore_in_progress) {
synced_window_delegate_->SetSessionRestoreInProgress(
@@ -183,95 +179,83 @@ class SessionDataTypeControllerTest : public testing::Test,
controller_->OnSessionRestoreComplete();
}
- scoped_refptr<SessionDataTypeController> controller_;
- std::unique_ptr<MockSyncedWindowDelegatesGetter> synced_window_getter_;
- std::unique_ptr<LocalDeviceInfoProviderMock> local_device_;
- std::unique_ptr<MockSyncedWindowDelegate> synced_window_delegate_;
- std::unique_ptr<TestSyncSessionsClient> sync_sessions_client_;
- bool load_finished_;
-
private:
base::MessageLoop message_loop_;
TestingPrefServiceSimple prefs_;
- SyncApiComponentFactoryMock profile_sync_factory_;
+ std::unique_ptr<MockSyncedWindowDelegate> synced_window_delegate_;
+ std::unique_ptr<MockSyncedWindowDelegatesGetter> synced_window_getter_;
+ syncer::SyncApiComponentFactoryMock profile_sync_factory_;
+ std::unique_ptr<TestSyncSessionsClient> sync_sessions_client_;
+ std::unique_ptr<LocalDeviceInfoProviderMock> local_device_;
+ std::unique_ptr<SessionDataTypeController> controller_;
+
+ bool load_finished_;
syncer::ModelType last_type_;
syncer::SyncError last_error_;
- base::WeakPtrFactory<SessionDataTypeControllerTest> weak_ptr_factory_;
};
TEST_F(SessionDataTypeControllerTest, StartModels) {
Start();
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_LOADED,
- controller_->state());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_LOADED, controller()->state());
EXPECT_TRUE(LoadResult());
}
TEST_F(SessionDataTypeControllerTest, StartModelsDelayedByLocalDevice) {
- local_device_->SetInitialized(false);
+ local_device()->SetInitialized(false);
Start();
- EXPECT_FALSE(load_finished_);
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_STARTING,
- controller_->state());
+ EXPECT_FALSE(load_finished());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING, controller()->state());
- local_device_->SetInitialized(true);
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_LOADED,
- controller_->state());
+ local_device()->SetInitialized(true);
+ EXPECT_EQ(syncer::DataTypeController::MODEL_LOADED, controller()->state());
EXPECT_TRUE(LoadResult());
}
TEST_F(SessionDataTypeControllerTest, StartModelsDelayedByRestoreInProgress) {
SetSessionRestoreInProgress(true);
Start();
- EXPECT_FALSE(load_finished_);
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_STARTING,
- controller_->state());
+ EXPECT_FALSE(load_finished());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING, controller()->state());
SetSessionRestoreInProgress(false);
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_LOADED,
- controller_->state());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_LOADED, controller()->state());
EXPECT_TRUE(LoadResult());
}
TEST_F(SessionDataTypeControllerTest,
StartModelsDelayedByLocalDeviceThenRestoreInProgress) {
- local_device_->SetInitialized(false);
+ local_device()->SetInitialized(false);
SetSessionRestoreInProgress(true);
Start();
- EXPECT_FALSE(load_finished_);
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_STARTING,
- controller_->state());
+ EXPECT_FALSE(load_finished());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING, controller()->state());
- local_device_->SetInitialized(true);
- EXPECT_FALSE(load_finished_);
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_STARTING,
- controller_->state());
+ local_device()->SetInitialized(true);
+ EXPECT_FALSE(load_finished());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING, controller()->state());
SetSessionRestoreInProgress(false);
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_LOADED,
- controller_->state());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_LOADED, controller()->state());
EXPECT_TRUE(LoadResult());
}
TEST_F(SessionDataTypeControllerTest,
StartModelsDelayedByRestoreInProgressThenLocalDevice) {
- local_device_->SetInitialized(false);
+ local_device()->SetInitialized(false);
SetSessionRestoreInProgress(true);
Start();
- EXPECT_FALSE(load_finished_);
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_STARTING,
- controller_->state());
+ EXPECT_FALSE(load_finished());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING, controller()->state());
SetSessionRestoreInProgress(false);
- EXPECT_FALSE(load_finished_);
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_STARTING,
- controller_->state());
+ EXPECT_FALSE(load_finished());
+ EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING, controller()->state());
- local_device_->SetInitialized(true);
- EXPECT_EQ(sync_driver::DataTypeController::MODEL_LOADED,
- controller_->state());
+ local_device()->SetInitialized(true);
+ EXPECT_EQ(syncer::DataTypeController::MODEL_LOADED, controller()->state());
EXPECT_TRUE(LoadResult());
}
} // namespace
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/session_sync_test_helper.cc b/chromium/components/sync_sessions/session_sync_test_helper.cc
new file mode 100644
index 00000000000..ac5b699d988
--- /dev/null
+++ b/chromium/components/sync_sessions/session_sync_test_helper.cc
@@ -0,0 +1,142 @@
+// 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 "components/sync_sessions/session_sync_test_helper.h"
+
+#include <stddef.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/sync/protocol/session_specifics.pb.h"
+#include "components/sync/protocol/sync_enums.pb.h"
+#include "components/sync_sessions/synced_session.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sync_sessions {
+
+static const char* kClientName = "name";
+static const char* kAppId = "app_id";
+static const char* kVirtualUrl = "http://foo/1";
+static const char* kReferrer = "referrer";
+static const char* kTitle = "title";
+
+// static
+void SessionSyncTestHelper::BuildSessionSpecifics(
+ const std::string& tag,
+ sync_pb::SessionSpecifics* meta) {
+ meta->set_session_tag(tag);
+ sync_pb::SessionHeader* header = meta->mutable_header();
+ header->set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
+ header->set_client_name(kClientName);
+}
+
+// static
+void SessionSyncTestHelper::AddWindowSpecifics(
+ int window_id,
+ const std::vector<int>& tab_list,
+ sync_pb::SessionSpecifics* meta) {
+ sync_pb::SessionHeader* header = meta->mutable_header();
+ sync_pb::SessionWindow* window = header->add_window();
+ window->set_window_id(window_id);
+ window->set_selected_tab_index(0);
+ window->set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
+ for (auto iter = tab_list.begin(); iter != tab_list.end(); ++iter) {
+ window->add_tab(*iter);
+ }
+}
+
+// static
+void SessionSyncTestHelper::VerifySyncedSession(
+ const std::string& tag,
+ const std::vector<std::vector<SessionID::id_type>>& windows,
+ const SyncedSession& session) {
+ ASSERT_EQ(tag, session.session_tag);
+ ASSERT_EQ(SyncedSession::TYPE_LINUX, session.device_type);
+ ASSERT_EQ(kClientName, session.session_name);
+ ASSERT_EQ(windows.size(), session.windows.size());
+
+ // We assume the window id's are in increasing order.
+ int i = 0;
+ for (std::vector<std::vector<int>>::const_iterator win_iter = windows.begin();
+ win_iter != windows.end(); ++win_iter, ++i) {
+ sessions::SessionWindow* win_ptr;
+ auto map_iter = session.windows.find(i);
+ if (map_iter != session.windows.end())
+ win_ptr = map_iter->second.get();
+ else
+ FAIL();
+ ASSERT_EQ(win_iter->size(), win_ptr->tabs.size());
+ ASSERT_EQ(0, win_ptr->selected_tab_index);
+ ASSERT_EQ(sessions::SessionWindow::TYPE_TABBED, win_ptr->type);
+ int j = 0;
+ for (auto tab_iter = (*win_iter).begin(); tab_iter != (*win_iter).end();
+ ++tab_iter, ++j) {
+ sessions::SessionTab* tab = win_ptr->tabs[j].get();
+ ASSERT_EQ(*tab_iter, tab->tab_id.id());
+ ASSERT_EQ(1U, tab->navigations.size());
+ ASSERT_EQ(1, tab->tab_visual_index);
+ ASSERT_EQ(0, tab->current_navigation_index);
+ ASSERT_TRUE(tab->pinned);
+ ASSERT_EQ(kAppId, tab->extension_app_id);
+ ASSERT_EQ(1U, tab->navigations.size());
+ ASSERT_EQ(tab->navigations[0].virtual_url(), GURL(kVirtualUrl));
+ ASSERT_EQ(tab->navigations[0].referrer_url(), GURL(kReferrer));
+ ASSERT_EQ(tab->navigations[0].title(), base::ASCIIToUTF16(kTitle));
+ ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+ tab->navigations[0].transition_type(), ui::PAGE_TRANSITION_TYPED));
+ }
+ }
+}
+
+void SessionSyncTestHelper::BuildTabSpecifics(
+ const std::string& tag,
+ int window_id,
+ int tab_id,
+ sync_pb::SessionSpecifics* tab_base) {
+ BuildTabSpecifics(tag, window_id, tab_id, ++max_tab_node_id_, tab_base);
+}
+
+void SessionSyncTestHelper::BuildTabSpecifics(
+ const std::string& tag,
+ int window_id,
+ int tab_id,
+ int tab_node_id,
+ sync_pb::SessionSpecifics* tab_base) {
+ tab_base->set_session_tag(tag);
+ tab_base->set_tab_node_id(tab_node_id);
+ sync_pb::SessionTab* tab = tab_base->mutable_tab();
+ tab->set_tab_id(tab_id);
+ tab->set_tab_visual_index(1);
+ tab->set_current_navigation_index(0);
+ tab->set_pinned(true);
+ tab->set_extension_app_id(kAppId);
+ sync_pb::TabNavigation* navigation = tab->add_navigation();
+ navigation->set_virtual_url(kVirtualUrl);
+ navigation->set_referrer(kReferrer);
+ navigation->set_title(kTitle);
+ navigation->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED);
+}
+
+void SessionSyncTestHelper::Reset() {
+ max_tab_node_id_ = 0;
+}
+
+sync_pb::SessionSpecifics SessionSyncTestHelper::BuildForeignSession(
+ const std::string& tag,
+ const std::vector<SessionID::id_type>& tab_list,
+ std::vector<sync_pb::SessionSpecifics>* tabs) {
+ sync_pb::SessionSpecifics meta;
+ BuildSessionSpecifics(tag, &meta);
+ AddWindowSpecifics(0, tab_list, &meta);
+ std::vector<sync_pb::SessionSpecifics> tabs1;
+ tabs1.resize(tab_list.size());
+ for (size_t i = 0; i < tab_list.size(); ++i) {
+ BuildTabSpecifics(tag, 0, tab_list[i], &tabs1[i]);
+ }
+
+ if (tabs)
+ tabs->swap(tabs1);
+ return meta;
+}
+
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/session_sync_test_helper.h b/chromium/components/sync_sessions/session_sync_test_helper.h
new file mode 100644
index 00000000000..ce6dd7906de
--- /dev/null
+++ b/chromium/components/sync_sessions/session_sync_test_helper.h
@@ -0,0 +1,69 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_TEST_HELPER_H_
+#define COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_TEST_HELPER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/sessions/core/session_id.h"
+
+namespace sync_pb {
+class SessionSpecifics;
+}
+
+namespace sync_sessions {
+
+struct SyncedSession;
+
+class SessionSyncTestHelper {
+ public:
+ SessionSyncTestHelper() : max_tab_node_id_(0) {}
+
+ static void BuildSessionSpecifics(const std::string& tag,
+ sync_pb::SessionSpecifics* meta);
+
+ static void AddWindowSpecifics(int window_id,
+ const std::vector<int>& tab_list,
+ sync_pb::SessionSpecifics* meta);
+
+ static void VerifySyncedSession(
+ const std::string& tag,
+ const std::vector<std::vector<SessionID::id_type>>& windows,
+ const SyncedSession& session);
+
+ // Build a SessionSpecifics object with a tab and sample data. Uses a
+ // monotonically increasing variable to generate tab_node_ids and avoid
+ // conflicts.
+ void BuildTabSpecifics(const std::string& tag,
+ int window_id,
+ int tab_id,
+ sync_pb::SessionSpecifics* tab_base);
+
+ // Overload of BuildTabSpecifics to allow forcing a specific tab_node_id.
+ // Typically only useful to test reusing tab_node_ids.
+ void BuildTabSpecifics(const std::string& tag,
+ int window_id,
+ int tab_id,
+ int tab_node_id,
+ sync_pb::SessionSpecifics* tab_base);
+
+ sync_pb::SessionSpecifics BuildForeignSession(
+ const std::string& tag,
+ const std::vector<SessionID::id_type>& tab_list,
+ std::vector<sync_pb::SessionSpecifics>* tabs);
+
+ void Reset();
+
+ private:
+ int max_tab_node_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(SessionSyncTestHelper);
+};
+
+} // namespace sync_sessions
+
+#endif // COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_TEST_HELPER_H_
diff --git a/chromium/components/sync_sessions/sessions_sync_manager.cc b/chromium/components/sync_sessions/sessions_sync_manager.cc
index a678c44f567..e97f1bc9181 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager.cc
+++ b/chromium/components/sync_sessions/sessions_sync_manager.cc
@@ -7,28 +7,29 @@
#include <algorithm>
#include <utility>
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
-#include "components/sync_driver/local_device_info_provider.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/api/sync_merge_result.h"
+#include "components/sync/api/time.h"
+#include "components/sync/device_info/local_device_info_provider.h"
+#include "components/sync/syncable/syncable_util.h"
#include "components/sync_sessions/sync_sessions_client.h"
#include "components/sync_sessions/synced_tab_delegate.h"
#include "components/sync_sessions/synced_window_delegate.h"
#include "components/sync_sessions/synced_window_delegates_getter.h"
#include "components/variations/variations_associated_data.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/api/sync_merge_result.h"
-#include "sync/api/time.h"
-#include "sync/syncable/syncable_util.h"
using sessions::SerializedNavigationEntry;
-using sync_driver::DeviceInfo;
-using sync_driver::LocalDeviceInfoProvider;
+using syncer::DeviceInfo;
+using syncer::LocalDeviceInfoProvider;
using syncer::SyncChange;
using syncer::SyncData;
-namespace browser_sync {
+namespace sync_sessions {
namespace {
@@ -56,8 +57,8 @@ bool TabsRecencyComparator(const sessions::SessionTab* t1,
// Comparator function for use with std::sort that will sort sessions by
// descending modified_time (i.e., most recent first).
-bool SessionsRecencyComparator(const sync_driver::SyncedSession* s1,
- const sync_driver::SyncedSession* s2) {
+bool SessionsRecencyComparator(const SyncedSession* s1,
+ const SyncedSession* s2) {
return s1->modified_time > s2->modified_time;
}
@@ -78,7 +79,7 @@ std::string TagFromSpecifics(const sync_pb::SessionSpecifics& specifics) {
// lifetime of SessionSyncManager.
SessionsSyncManager::SessionsSyncManager(
sync_sessions::SyncSessionsClient* sessions_client,
- sync_driver::SyncPrefs* sync_prefs,
+ syncer::SyncPrefs* sync_prefs,
LocalDeviceInfoProvider* local_device,
std::unique_ptr<LocalSessionEventRouter> router,
const base::Closure& sessions_updated_callback,
@@ -120,6 +121,15 @@ syncer::SyncMergeResult SessionsSyncManager::MergeDataAndStartSyncing(
error_handler_ = std::move(error_handler);
sync_processor_ = std::move(sync_processor);
+ // It's possible(via RebuildAssociations) for lost_navigations_recorder_ to
+ // persist between sync being stopped and started. If it did persist, it's
+ // already associated with |sync_processor|, so leave it alone.
+ if (!lost_navigations_recorder_.get()) {
+ lost_navigations_recorder_ =
+ base::MakeUnique<sync_sessions::LostNavigationsRecorder>();
+ sync_processor_->AddLocalChangeObserver(lost_navigations_recorder_.get());
+ }
+
local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID;
// Make sure we have a machine tag. We do this now (versus earlier) as it's
@@ -187,8 +197,7 @@ void SessionsSyncManager::AssociateWindows(
sync_pb::SessionSpecifics specifics;
specifics.set_session_tag(local_tag);
sync_pb::SessionHeader* header_s = specifics.mutable_header();
- sync_driver::SyncedSession* current_session =
- session_tracker_.GetSession(local_tag);
+ SyncedSession* current_session = session_tracker_.GetSession(local_tag);
current_session->modified_time = base::Time::Now();
header_s->set_client_name(current_session_name_);
// SessionDataTypeController ensures that the local device info
@@ -238,15 +247,15 @@ void SessionsSyncManager::AssociateWindows(
continue;
if (synced_tab->IsPlaceholderTab()) {
- // For tabs without WebContents update the |tab_id|, as it could have
- // changed after a session restore.
+ // For tabs without WebContents update the |tab_id| and |window_id|,
+ // as it could have changed after a session restore.
// Note: We cannot check if a tab is valid if it has no WebContents.
// We assume any such tab is valid and leave the contents of
// corresponding sync node unchanged.
if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID &&
tab_id > TabNodePool::kInvalidTabID) {
- AssociateRestoredPlaceholderTab(*synced_tab, tab_id, restored_tabs,
- change_output);
+ AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id,
+ restored_tabs, change_output);
found_tabs = true;
window_s.add_tab(tab_id);
}
@@ -273,9 +282,9 @@ void SessionsSyncManager::AssociateWindows(
// Update this window's representation in the synced session tracker.
session_tracker_.PutWindowInSession(local_tag, window_id);
- BuildSyncedSessionFromSpecifics(local_tag, window_s,
- current_session->modified_time,
- current_session->windows[window_id]);
+ BuildSyncedSessionFromSpecifics(
+ local_tag, window_s, current_session->modified_time,
+ current_session->windows[window_id].get());
}
}
}
@@ -437,6 +446,11 @@ void SessionsSyncManager::OnFaviconsChanged(const std::set<GURL>& page_urls,
void SessionsSyncManager::StopSyncing(syncer::ModelType type) {
local_event_router_->Stop();
+ if (sync_processor_.get() && lost_navigations_recorder_.get()) {
+ sync_processor_->RemoveLocalChangeObserver(
+ lost_navigations_recorder_.get());
+ lost_navigations_recorder_.reset();
+ }
sync_processor_.reset(NULL);
error_handler_.reset();
session_tracker_.Clear();
@@ -450,7 +464,7 @@ void SessionsSyncManager::StopSyncing(syncer::ModelType type) {
syncer::SyncDataList SessionsSyncManager::GetAllSyncData(
syncer::ModelType type) const {
syncer::SyncDataList list;
- const sync_driver::SyncedSession* session = NULL;
+ const SyncedSession* session = NULL;
if (!session_tracker_.LookupLocalSession(&session))
return syncer::SyncDataList();
@@ -464,11 +478,9 @@ syncer::SyncDataList SessionsSyncManager::GetAllSyncData(
current_machine_tag(), current_session_name_, header_entity);
list.push_back(data);
- sync_driver::SyncedSession::SyncedWindowMap::const_iterator win_iter;
- for (win_iter = session->windows.begin(); win_iter != session->windows.end();
- ++win_iter) {
- std::vector<sessions::SessionTab*>::const_iterator tabs_iter;
- for (tabs_iter = win_iter->second->tabs.begin();
+ for (auto win_iter = session->windows.begin();
+ win_iter != session->windows.end(); ++win_iter) {
+ for (auto tabs_iter = win_iter->second->tabs.begin();
tabs_iter != win_iter->second->tabs.end(); ++tabs_iter) {
sync_pb::EntitySpecifics entity;
sync_pb::SessionSpecifics* specifics = entity.mutable_session();
@@ -489,8 +501,7 @@ syncer::SyncDataList SessionsSyncManager::GetAllSyncData(
return list;
}
-bool SessionsSyncManager::GetLocalSession(
- const sync_driver::SyncedSession** local_session) {
+bool SessionsSyncManager::GetLocalSession(const SyncedSession** local_session) {
if (current_machine_tag_.empty())
return false;
*local_session = session_tracker_.GetSession(current_machine_tag());
@@ -579,7 +590,7 @@ syncer::SyncChange SessionsSyncManager::TombstoneTab(
}
bool SessionsSyncManager::GetAllForeignSessions(
- std::vector<const sync_driver::SyncedSession*>* sessions) {
+ std::vector<const SyncedSession*>* sessions) {
if (!session_tracker_.LookupAllForeignSessions(
sessions, SyncedSessionTracker::PRESENTABLE))
return false;
@@ -645,7 +656,7 @@ bool SessionsSyncManager::InitFromSyncModel(
// Cleanup all foreign sessions, since orphaned tabs may have been added after
// the header.
- std::vector<const sync_driver::SyncedSession*> sessions;
+ std::vector<const SyncedSession*> sessions;
session_tracker_.LookupAllForeignSessions(&sessions,
SyncedSessionTracker::RAW);
for (const auto* session : sessions) {
@@ -664,7 +675,7 @@ void SessionsSyncManager::UpdateTrackerWithForeignSession(
std::string foreign_session_tag = specifics.session_tag();
DCHECK_NE(foreign_session_tag, current_machine_tag());
- sync_driver::SyncedSession* foreign_session =
+ SyncedSession* foreign_session =
session_tracker_.GetSession(foreign_session_tag);
if (specifics.has_header()) {
// Read in the header data for this foreign session. Header data is
@@ -696,9 +707,9 @@ void SessionsSyncManager::UpdateTrackerWithForeignSession(
const sync_pb::SessionWindow& window_s = header.window(i);
SessionID::id_type window_id = window_s.window_id();
session_tracker_.PutWindowInSession(foreign_session_tag, window_id);
- BuildSyncedSessionFromSpecifics(foreign_session_tag, window_s,
- modification_time,
- foreign_session->windows[window_id]);
+ BuildSyncedSessionFromSpecifics(
+ foreign_session_tag, window_s, modification_time,
+ foreign_session->windows[window_id].get());
}
// Delete any closed windows and unused tabs as necessary.
session_tracker_.CleanupSession(foreign_session_tag);
@@ -761,33 +772,33 @@ void SessionsSyncManager::InitializeCurrentMachineTag() {
void SessionsSyncManager::PopulateSessionHeaderFromSpecifics(
const sync_pb::SessionHeader& header_specifics,
base::Time mtime,
- sync_driver::SyncedSession* session_header) {
+ SyncedSession* session_header) {
if (header_specifics.has_client_name())
session_header->session_name = header_specifics.client_name();
if (header_specifics.has_device_type()) {
switch (header_specifics.device_type()) {
case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
- session_header->device_type = sync_driver::SyncedSession::TYPE_WIN;
+ session_header->device_type = SyncedSession::TYPE_WIN;
break;
case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
- session_header->device_type = sync_driver::SyncedSession::TYPE_MACOSX;
+ session_header->device_type = SyncedSession::TYPE_MACOSX;
break;
case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
- session_header->device_type = sync_driver::SyncedSession::TYPE_LINUX;
+ session_header->device_type = SyncedSession::TYPE_LINUX;
break;
case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
- session_header->device_type = sync_driver::SyncedSession::TYPE_CHROMEOS;
+ session_header->device_type = SyncedSession::TYPE_CHROMEOS;
break;
case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
- session_header->device_type = sync_driver::SyncedSession::TYPE_PHONE;
+ session_header->device_type = SyncedSession::TYPE_PHONE;
break;
case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
- session_header->device_type = sync_driver::SyncedSession::TYPE_TABLET;
+ session_header->device_type = SyncedSession::TYPE_TABLET;
break;
case sync_pb::SyncEnums_DeviceType_TYPE_OTHER:
// Intentionally fall-through
default:
- session_header->device_type = sync_driver::SyncedSession::TYPE_OTHER;
+ session_header->device_type = SyncedSession::TYPE_OTHER;
break;
}
}
@@ -816,7 +827,7 @@ void SessionsSyncManager::BuildSyncedSessionFromSpecifics(
}
}
session_window->timestamp = mtime;
- session_window->tabs.resize(specifics.tab_size(), NULL);
+ session_window->tabs.resize(specifics.tab_size());
for (int i = 0; i < specifics.tab_size(); i++) {
SessionID::id_type tab_id = specifics.tab(i);
session_tracker_.PutTabInWindow(session_tag, session_window->window_id.id(),
@@ -906,7 +917,7 @@ bool SessionsSyncManager::GetForeignSessionTabs(
for (size_t j = 0; j < windows.size(); ++j) {
const sessions::SessionWindow* window = windows[j];
for (size_t t = 0; t < window->tabs.size(); ++t) {
- sessions::SessionTab* const tab = window->tabs[t];
+ sessions::SessionTab* const tab = window->tabs[t].get();
if (tab->navigations.empty())
continue;
const sessions::SerializedNavigationEntry& current_navigation =
@@ -948,6 +959,7 @@ void SessionsSyncManager::LocalTabDelegateToSpecifics(
void SessionsSyncManager::AssociateRestoredPlaceholderTab(
const SyncedTabDelegate& tab_delegate,
SessionID::id_type new_tab_id,
+ SessionID::id_type new_window_id,
const syncer::SyncDataList& restored_tabs,
syncer::SyncChangeList* change_output) {
DCHECK_NE(tab_delegate.GetSyncId(), TabNodePool::kInvalidTabNodeID);
@@ -974,11 +986,14 @@ void SessionsSyncManager::AssociateRestoredPlaceholderTab(
TabLink* tab_link = new TabLink(tab_delegate.GetSyncId(), &tab_delegate);
local_tab_map_[new_tab_id] = make_linked_ptr<TabLink>(tab_link);
- if (specifics->tab().tab_id() == new_tab_id)
+ if (specifics->tab().tab_id() == new_tab_id &&
+ specifics->tab().window_id() == new_window_id)
return;
- // The tab_id changed (e.g due to session restore), so update sync.
+ // Either the tab_id or window_id changed (e.g due to session restore), so
+ // update the sync node.
specifics->mutable_tab()->set_tab_id(new_tab_id);
+ specifics->mutable_tab()->set_window_id(new_window_id);
syncer::SyncData data = syncer::SyncData::CreateLocalData(
TabNodePool::TabIdToTag(current_machine_tag_, specifics->tab_node_id()),
current_session_name_, entity);
@@ -1038,8 +1053,8 @@ void SessionsSyncManager::SetSessionTabFromDelegate(
if (is_supervised) {
int offset = session_tab->navigations.size();
- const std::vector<const SerializedNavigationEntry*>& blocked_navigations =
- *tab_delegate.GetBlockedNavigations();
+ const std::vector<std::unique_ptr<const SerializedNavigationEntry>>&
+ blocked_navigations = *tab_delegate.GetBlockedNavigations();
for (size_t i = 0; i < blocked_navigations.size(); ++i) {
session_tab->navigations.push_back(*blocked_navigations[i]);
session_tab->navigations.back().set_index(offset + i);
@@ -1073,7 +1088,7 @@ SessionsSyncManager::synced_window_delegates_getter() const {
}
void SessionsSyncManager::DoGarbageCollection() {
- std::vector<const sync_driver::SyncedSession*> sessions;
+ std::vector<const SyncedSession*> sessions;
if (!session_tracker_.LookupAllForeignSessions(&sessions,
SyncedSessionTracker::RAW))
return; // No foreign sessions.
@@ -1103,4 +1118,4 @@ std::string SessionsSyncManager::TagHashFromSpecifics(
TagFromSpecifics(specifics));
}
-}; // namespace browser_sync
+}; // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/sessions_sync_manager.h b/chromium/components/sync_sessions/sessions_sync_manager.h
index 952851ee4d2..a0ff584d3f0 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager.h
+++ b/chromium/components/sync_sessions/sessions_sync_manager.h
@@ -20,25 +20,23 @@
#include "base/time/time.h"
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/session_types.h"
-#include "components/sync_driver/device_info.h"
-#include "components/sync_driver/sync_prefs.h"
+#include "components/sync/api/syncable_service.h"
+#include "components/sync/device_info/device_info.h"
+#include "components/sync/driver/sync_prefs.h"
#include "components/sync_sessions/favicon_cache.h"
#include "components/sync_sessions/local_session_event_router.h"
+#include "components/sync_sessions/lost_navigations_recorder.h"
#include "components/sync_sessions/open_tabs_ui_delegate.h"
#include "components/sync_sessions/revisit/page_revisit_broadcaster.h"
#include "components/sync_sessions/synced_session.h"
#include "components/sync_sessions/synced_session_tracker.h"
#include "components/sync_sessions/tab_node_pool.h"
-#include "sync/api/syncable_service.h"
namespace syncer {
-class SyncErrorFactory;
-}
-
-namespace sync_driver {
class LocalDeviceInfoProvider;
+class SyncErrorFactory;
class SyncPrefs;
-}
+} // namespace syncer
namespace sync_pb {
class SessionHeader;
@@ -52,21 +50,20 @@ namespace extensions {
class ExtensionSessionsTest;
} // namespace extensions
-namespace browser_sync {
+namespace sync_sessions {
-class DataTypeErrorHandler;
class SyncedTabDelegate;
class SyncedWindowDelegatesGetter;
// Contains all logic for associating the Chrome sessions model and
// the sync sessions model.
class SessionsSyncManager : public syncer::SyncableService,
- public sync_driver::OpenTabsUIDelegate,
+ public OpenTabsUIDelegate,
public LocalSessionEventHandler {
public:
- SessionsSyncManager(sync_sessions::SyncSessionsClient* sessions_client,
- sync_driver::SyncPrefs* sync_prefs,
- sync_driver::LocalDeviceInfoProvider* local_device,
+ SessionsSyncManager(SyncSessionsClient* sessions_client,
+ syncer::SyncPrefs* sync_prefs,
+ syncer::LocalDeviceInfoProvider* local_device,
std::unique_ptr<LocalSessionEventRouter> router,
const base::Closure& sessions_updated_callback,
const base::Closure& datatype_refresh_callback);
@@ -89,7 +86,7 @@ class SessionsSyncManager : public syncer::SyncableService,
const std::string& pageurl,
scoped_refptr<base::RefCountedMemory>* favicon_png) const override;
bool GetAllForeignSessions(
- std::vector<const sync_driver::SyncedSession*>* sessions) override;
+ std::vector<const SyncedSession*>* sessions) override;
bool GetForeignSession(
const std::string& tag,
std::vector<const sessions::SessionWindow*>* windows) override;
@@ -100,8 +97,7 @@ class SessionsSyncManager : public syncer::SyncableService,
const std::string& tag,
std::vector<const sessions::SessionTab*>* tabs) override;
void DeleteForeignSession(const std::string& tag) override;
- bool GetLocalSession(
- const sync_driver::SyncedSession** local_session) override;
+ bool GetLocalSession(const SyncedSession** local_session) override;
// LocalSessionEventHandler implementation.
void OnLocalTabModified(SyncedTabDelegate* modified_tab) override;
@@ -232,7 +228,7 @@ class SessionsSyncManager : public syncer::SyncableService,
static void PopulateSessionHeaderFromSpecifics(
const sync_pb::SessionHeader& header_specifics,
base::Time mtime,
- sync_driver::SyncedSession* session_header);
+ SyncedSession* session_header);
// Builds |session_window| from the session specifics window
// provided and updates the SessionTracker with foreign session data created.
@@ -289,8 +285,8 @@ class SessionsSyncManager : public syncer::SyncableService,
// into memory yet (e.g on android) and we don't have a WebContents. In this
// case we can't do a full association, but we still want to update tab IDs
// as they may have changed after a session was restored. This method
- // compares new_tab_id against the previously persisted tab ID (from
- // our TabNodePool) and updates it if it differs.
+ // compares new_tab_id and new_window_id against the previously persisted tab
+ // ID and window ID (from our TabNodePool) and updates them if either differs.
// |restored_tabs| is a filtered tab-only subset of initial sync data, if
// available (during MergeDataAndStartSyncing). It can be used to obtain
// baseline SessionSpecifics for tabs we can't fully associate any other
@@ -300,6 +296,7 @@ class SessionsSyncManager : public syncer::SyncableService,
void AssociateRestoredPlaceholderTab(
const SyncedTabDelegate& tab_delegate,
SessionID::id_type new_tab_id,
+ SessionID::id_type new_window_id,
const syncer::SyncDataList& restored_tabs,
syncer::SyncChangeList* change_output);
@@ -324,7 +321,7 @@ class SessionsSyncManager : public syncer::SyncableService,
SyncedWindowDelegatesGetter* synced_window_delegates_getter() const;
// The client of this sync sessions datatype.
- sync_sessions::SyncSessionsClient* const sessions_client_;
+ SyncSessionsClient* const sessions_client_;
// Mapping of current open (local) tabs to their sync identifiers.
TabLinksMap local_tab_map_;
@@ -344,13 +341,13 @@ class SessionsSyncManager : public syncer::SyncableService,
// proves that we are still relevant.
bool local_tab_pool_out_of_sync_;
- sync_driver::SyncPrefs* sync_prefs_;
+ syncer::SyncPrefs* sync_prefs_;
std::unique_ptr<syncer::SyncErrorFactory> error_handler_;
std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
// Local device info provider, owned by ProfileSyncService.
- const sync_driver::LocalDeviceInfoProvider* const local_device_;
+ const syncer::LocalDeviceInfoProvider* const local_device_;
// Unique client tag.
std::string current_machine_tag_;
@@ -371,6 +368,9 @@ class SessionsSyncManager : public syncer::SyncableService,
// Owns revisiting instrumentation logic for page visit events.
PageRevisitBroadcaster page_revisit_broadcaster_;
+ std::unique_ptr<sync_sessions::LostNavigationsRecorder>
+ lost_navigations_recorder_;
+
// Callback to inform interested observer that new sessions data has arrived.
base::Closure sessions_updated_callback_;
@@ -380,6 +380,6 @@ class SessionsSyncManager : public syncer::SyncableService,
DISALLOW_COPY_AND_ASSIGN(SessionsSyncManager);
};
-} // namespace browser_sync
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_SESSIONS_SYNC_MANAGER_H_
diff --git a/chromium/components/sync_sessions/sync_sessions_client.h b/chromium/components/sync_sessions/sync_sessions_client.h
index 9d53cd781ae..fab928ffeff 100644
--- a/chromium/components/sync_sessions/sync_sessions_client.h
+++ b/chromium/components/sync_sessions/sync_sessions_client.h
@@ -15,11 +15,6 @@ namespace bookmarks {
class BookmarkModel;
}
-namespace browser_sync {
-class LocalSessionEventRouter;
-class SyncedWindowDelegatesGetter;
-}
-
namespace favicon {
class FaviconService;
}
@@ -30,6 +25,9 @@ class HistoryService;
namespace sync_sessions {
+class LocalSessionEventRouter;
+class SyncedWindowDelegatesGetter;
+
// Interface for clients of a sync sessions datatype. Should be used as a getter
// for services and data the Sync Sessions datatype depends on.
class SyncSessionsClient {
@@ -50,12 +48,11 @@ class SyncSessionsClient {
virtual bool ShouldSyncURL(const GURL& url) const = 0;
// Returns the SyncedWindowDelegatesGetter for this client.
- virtual browser_sync::SyncedWindowDelegatesGetter*
- GetSyncedWindowDelegatesGetter() = 0;
+ virtual SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter() = 0;
// Returns a LocalSessionEventRouter instance that is customized for the
// embedder's context.
- virtual std::unique_ptr<browser_sync::LocalSessionEventRouter>
+ virtual std::unique_ptr<LocalSessionEventRouter>
GetLocalSessionEventRouter() = 0;
// TODO(zea): add getters for the history and favicon services for the favicon
diff --git a/chromium/components/sync_sessions/sync_sessions_metrics.cc b/chromium/components/sync_sessions/sync_sessions_metrics.cc
index fb037975b18..de5f03abd29 100644
--- a/chromium/components/sync_sessions/sync_sessions_metrics.cc
+++ b/chromium/components/sync_sessions/sync_sessions_metrics.cc
@@ -19,9 +19,9 @@ namespace sync_sessions {
// static
void SyncSessionsMetrics::RecordYoungestForeignTabAgeOnNTP(
- browser_sync::SessionsSyncManager* sessions_sync_manager) {
+ SessionsSyncManager* sessions_sync_manager) {
if (sessions_sync_manager != NULL) {
- std::vector<const sync_driver::SyncedSession*> foreign_sessions;
+ std::vector<const SyncedSession*> foreign_sessions;
sessions_sync_manager->GetAllForeignSessions(&foreign_sessions);
base::Time best(MaxTabTimestamp(foreign_sessions));
base::Time now(base::Time::Now());
@@ -40,19 +40,18 @@ void SyncSessionsMetrics::RecordYoungestForeignTabAgeOnNTP(
// static
base::Time SyncSessionsMetrics::MaxTabTimestamp(
- const std::vector<const sync_driver::SyncedSession*>& sessions) {
+ const std::vector<const SyncedSession*>& sessions) {
// While Sessions are ordered by recency, windows and tabs are not. Because
// the timestamp of sessions are updated when windows/tabs are removed, we
// only need to search until all the remaining sessions are older than the
// most recent tab we've found so far.
base::Time best(base::Time::UnixEpoch());
- for (const sync_driver::SyncedSession* session : sessions) {
+ for (const SyncedSession* session : sessions) {
if (session->modified_time < best) {
break;
}
- for (const std::pair<const SessionID::id_type, sessions::SessionWindow*>&
- key_value : session->windows) {
- for (const sessions::SessionTab* tab : key_value.second->tabs) {
+ for (const auto& key_value : session->windows) {
+ for (const auto& tab : key_value.second->tabs) {
best = std::max(best, tab->timestamp);
}
}
diff --git a/chromium/components/sync_sessions/sync_sessions_metrics.h b/chromium/components/sync_sessions/sync_sessions_metrics.h
index 6d9b63aad0a..90770b42118 100644
--- a/chromium/components/sync_sessions/sync_sessions_metrics.h
+++ b/chromium/components/sync_sessions/sync_sessions_metrics.h
@@ -11,15 +11,10 @@ namespace base {
class Time;
} // namespace base
-namespace browser_sync {
-class SessionsSyncManager;
-} // namespace browser_sync
+namespace sync_sessions {
-namespace sync_driver {
+class SessionsSyncManager;
struct SyncedSession;
-} // namespace sync_driver
-
-namespace sync_sessions {
class SyncSessionsMetrics {
public:
@@ -29,7 +24,7 @@ class SyncSessionsMetrics {
// session present, or a foreign tab with a timestamp in the future then no
// metric is emitted.
static void RecordYoungestForeignTabAgeOnNTP(
- browser_sync::SessionsSyncManager* sessions_sync_manager);
+ SessionsSyncManager* sessions_sync_manager);
private:
friend class SyncSessionsMetricsTest;
@@ -39,7 +34,7 @@ class SyncSessionsMetrics {
// always be greater or equal to children window/tab timestamps. No navigation
// timestamps are checked.
static base::Time MaxTabTimestamp(
- const std::vector<const sync_driver::SyncedSession*>& sessions);
+ const std::vector<const SyncedSession*>& sessions);
};
} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc b/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc
index a016250dd72..f351d3de168 100644
--- a/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc
+++ b/chromium/components/sync_sessions/sync_sessions_metrics_unittest.cc
@@ -5,6 +5,7 @@
#include "components/sync_sessions/sync_sessions_metrics.h"
#include <algorithm>
+#include <memory>
#include "base/memory/ptr_util.h"
#include "base/test/histogram_tester.h"
@@ -15,7 +16,6 @@
#include "components/sync_sessions/synced_session.h"
#include "testing/gtest/include/gtest/gtest.h"
-using sync_driver::SyncedSession;
using sessions::SessionWindow;
using sessions::SessionTab;
using base::Time;
@@ -25,20 +25,20 @@ namespace sync_sessions {
namespace {
-class FakeSessionsSyncManager : public browser_sync::SessionsSyncManager {
+class FakeSessionsSyncManager : public SessionsSyncManager {
public:
FakeSessionsSyncManager(SyncSessionsClient* sessions_client,
std::vector<std::unique_ptr<SyncedSession>>* sessions)
- : browser_sync::SessionsSyncManager(sessions_client,
- nullptr,
- nullptr,
- nullptr,
- base::Closure(),
- base::Closure()),
+ : SessionsSyncManager(sessions_client,
+ nullptr,
+ nullptr,
+ nullptr,
+ base::Closure(),
+ base::Closure()),
sessions_(sessions) {}
bool GetAllForeignSessions(
- std::vector<const sync_driver::SyncedSession*>* sessions) override {
+ std::vector<const SyncedSession*>* sessions) override {
for (auto& session : *sessions_) {
sessions->push_back(session.get());
}
@@ -65,18 +65,20 @@ class SyncSessionsMetricsTest : public ::testing::Test {
void PushTab(size_t tabIndex, int windowIndex, Time timestamp) {
// First add sessions/windows as necessary.
while (tabIndex >= sessions_.size()) {
- sessions_.push_back(base::WrapUnique(new SyncedSession()));
+ sessions_.push_back(base::MakeUnique<SyncedSession>());
}
if (sessions_[tabIndex]->windows.find(windowIndex) ==
sessions_[tabIndex]->windows.end()) {
- sessions_[tabIndex]->windows[windowIndex] = new SessionWindow();
+ sessions_[tabIndex]->windows[windowIndex] =
+ base::MakeUnique<SessionWindow>();
}
sessions_[tabIndex]->modified_time =
std::max(sessions_[tabIndex]->modified_time, timestamp);
sessions_[tabIndex]->windows[windowIndex]->timestamp = std::max(
sessions_[tabIndex]->windows[windowIndex]->timestamp, timestamp);
- sessions_[tabIndex]->windows[windowIndex]->tabs.push_back(new SessionTab());
+ sessions_[tabIndex]->windows[windowIndex]->tabs.push_back(
+ base::MakeUnique<SessionTab>());
sessions_[tabIndex]->windows[windowIndex]->tabs.back()->timestamp =
timestamp;
}
@@ -89,7 +91,6 @@ class SyncSessionsMetricsTest : public ::testing::Test {
std::max(sessions_[tabIndex]->modified_time, timestamp);
sessions_[tabIndex]->windows[windowIndex]->timestamp = std::max(
sessions_[tabIndex]->windows[windowIndex]->timestamp, timestamp);
- delete sessions_[tabIndex]->windows[windowIndex]->tabs.back();
sessions_[tabIndex]->windows[windowIndex]->tabs.pop_back();
}
@@ -102,9 +103,7 @@ class SyncSessionsMetricsTest : public ::testing::Test {
return SyncSessionsMetrics::MaxTabTimestamp(typed_sessions);
}
- browser_sync::SessionsSyncManager* get_sessions_sync_manager() {
- return &fake_manager_;
- }
+ SessionsSyncManager* get_sessions_sync_manager() { return &fake_manager_; }
private:
std::vector<std::unique_ptr<SyncedSession>> sessions_;
diff --git a/chromium/components/sync_sessions/synced_session.cc b/chromium/components/sync_sessions/synced_session.cc
index 3cb4a54b6ee..c22e1728d20 100644
--- a/chromium/components/sync_sessions/synced_session.cc
+++ b/chromium/components/sync_sessions/synced_session.cc
@@ -4,23 +4,18 @@
#include "components/sync_sessions/synced_session.h"
-#include "base/stl_util.h"
-
-namespace sync_driver {
+namespace sync_sessions {
SyncedSession::SyncedSession()
: session_tag("invalid"), device_type(TYPE_UNSET) {}
-SyncedSession::~SyncedSession() {
- STLDeleteContainerPairSecondPointers(windows.begin(), windows.end());
-}
+SyncedSession::~SyncedSession() {}
sync_pb::SessionHeader SyncedSession::ToSessionHeader() const {
sync_pb::SessionHeader header;
- SyncedWindowMap::const_iterator iter;
- for (iter = windows.begin(); iter != windows.end(); ++iter) {
+ for (const auto& window_pair : windows) {
sync_pb::SessionWindow* w = header.add_window();
- w->CopyFrom(iter->second->ToSyncData());
+ w->CopyFrom(window_pair.second->ToSyncData());
}
header.set_client_name(session_name);
switch (device_type) {
@@ -51,4 +46,4 @@ sync_pb::SessionHeader SyncedSession::ToSessionHeader() const {
return header;
}
-} // namespace sync_driver
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/synced_session.h b/chromium/components/sync_sessions/synced_session.h
index d9696dcb9e5..e0defd96623 100644
--- a/chromium/components/sync_sessions/synced_session.h
+++ b/chromium/components/sync_sessions/synced_session.h
@@ -6,6 +6,7 @@
#define COMPONENTS_SYNC_SESSIONS_SYNCED_SESSION_H_
#include <map>
+#include <memory>
#include <set>
#include <string>
@@ -13,21 +14,18 @@
#include "base/time/time.h"
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/session_types.h"
-#include "sync/protocol/session_specifics.pb.h"
+#include "components/sync/protocol/session_specifics.pb.h"
namespace sessions {
struct SessionWindow;
}
-namespace sync_driver {
+namespace sync_sessions {
// Defines a synced session for use by session sync. A synced session is a
// list of windows along with a unique session identifer (tag) and meta-data
// about the device being synced.
struct SyncedSession {
- typedef std::map<SessionID::id_type, sessions::SessionWindow*>
- SyncedWindowMap;
-
// The type of device.
// Please keep in sync with ForeignSessionHelper.java
enum DeviceType {
@@ -56,9 +54,9 @@ struct SyncedSession {
// and all children tab mtimes.
base::Time modified_time;
- // Map of windows that make up this session. Windowws are owned by the session
- // itself and free'd on destruction.
- SyncedWindowMap windows;
+ // Map of windows that make up this session.
+ std::map<SessionID::id_type, std::unique_ptr<sessions::SessionWindow>>
+ windows;
// A tab node id is part of the identifier for the sync tab objects. Tab node
// ids are not used for interacting with the model/browser tabs. However, when
@@ -103,6 +101,6 @@ struct SyncedSession {
DISALLOW_COPY_AND_ASSIGN(SyncedSession);
};
-} // namespace sync_driver
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_SYNCED_SESSION_H_
diff --git a/chromium/components/sync_sessions/synced_session_tracker.cc b/chromium/components/sync_sessions/synced_session_tracker.cc
index abff52e7bae..a74b877c085 100644
--- a/chromium/components/sync_sessions/synced_session_tracker.cc
+++ b/chromium/components/sync_sessions/synced_session_tracker.cc
@@ -4,20 +4,22 @@
#include "components/sync_sessions/synced_session_tracker.h"
+#include <utility>
+
#include "base/logging.h"
-#include "base/stl_util.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/sync_sessions/sync_sessions_client.h"
-namespace browser_sync {
+namespace sync_sessions {
namespace {
// Helper for iterating through all tabs within a window, and all navigations
// within a tab, to find if there's a valid syncable url.
-bool ShouldSyncSessionWindow(sync_sessions::SyncSessionsClient* sessions_client,
+bool ShouldSyncSessionWindow(SyncSessionsClient* sessions_client,
const sessions::SessionWindow& window) {
- for (sessions::SessionTab* const tab : window.tabs) {
+ for (const auto& tab : window.tabs) {
for (const sessions::SerializedNavigationEntry& navigation :
tab->navigations) {
if (sessions_client->ShouldSyncURL(navigation.virtual_url())) {
@@ -29,10 +31,9 @@ bool ShouldSyncSessionWindow(sync_sessions::SyncSessionsClient* sessions_client,
}
// Presentable means |foreign_session| must have syncable content.
-bool IsPresentable(sync_sessions::SyncSessionsClient* sessions_client,
- sync_driver::SyncedSession* foreign_session) {
- for (sync_driver::SyncedSession::SyncedWindowMap::const_iterator iter =
- foreign_session->windows.begin();
+bool IsPresentable(SyncSessionsClient* sessions_client,
+ SyncedSession* foreign_session) {
+ for (auto iter = foreign_session->windows.begin();
iter != foreign_session->windows.end(); ++iter) {
if (ShouldSyncSessionWindow(sessions_client, *(iter->second))) {
return true;
@@ -43,8 +44,7 @@ bool IsPresentable(sync_sessions::SyncSessionsClient* sessions_client,
} // namespace
-SyncedSessionTracker::SyncedSessionTracker(
- sync_sessions::SyncSessionsClient* sessions_client)
+SyncedSessionTracker::SyncedSessionTracker(SyncSessionsClient* sessions_client)
: sessions_client_(sessions_client) {}
SyncedSessionTracker::~SyncedSessionTracker() {
@@ -57,14 +57,13 @@ void SyncedSessionTracker::SetLocalSessionTag(
}
bool SyncedSessionTracker::LookupAllForeignSessions(
- std::vector<const sync_driver::SyncedSession*>* sessions,
+ std::vector<const SyncedSession*>* sessions,
SessionLookup lookup) const {
DCHECK(sessions);
sessions->clear();
- for (SyncedSessionMap::const_iterator i = synced_session_map_.begin();
- i != synced_session_map_.end(); ++i) {
- sync_driver::SyncedSession* foreign_session = i->second;
- if (i->first != local_session_tag_ &&
+ for (const auto& session_pair : synced_session_map_) {
+ SyncedSession* foreign_session = session_pair.second.get();
+ if (session_pair.first != local_session_tag_ &&
(lookup == RAW || IsPresentable(sessions_client_, foreign_session))) {
sessions->push_back(foreign_session);
}
@@ -77,15 +76,13 @@ bool SyncedSessionTracker::LookupSessionWindows(
std::vector<const sessions::SessionWindow*>* windows) const {
DCHECK(windows);
windows->clear();
- SyncedSessionMap::const_iterator iter = synced_session_map_.find(session_tag);
+
+ auto iter = synced_session_map_.find(session_tag);
if (iter == synced_session_map_.end())
return false;
- windows->clear();
- for (sync_driver::SyncedSession::SyncedWindowMap::const_iterator window_iter =
- iter->second->windows.begin();
- window_iter != iter->second->windows.end(); ++window_iter) {
- windows->push_back(window_iter->second);
- }
+ for (const auto& window_pair : iter->second->windows)
+ windows->push_back(window_pair.second.get());
+
return true;
}
@@ -94,84 +91,76 @@ bool SyncedSessionTracker::LookupSessionTab(
SessionID::id_type tab_id,
const sessions::SessionTab** tab) const {
DCHECK(tab);
- SyncedTabMap::const_iterator tab_map_iter = synced_tab_map_.find(tag);
+ auto tab_map_iter = synced_tab_map_.find(tag);
if (tab_map_iter == synced_tab_map_.end()) {
// We have no record of this session.
*tab = nullptr;
return false;
}
- IDToSessionTabMap::const_iterator tab_iter =
- tab_map_iter->second.find(tab_id);
+ auto tab_iter = tab_map_iter->second.find(tab_id);
if (tab_iter == tab_map_iter->second.end()) {
// We have no record of this tab.
*tab = nullptr;
return false;
}
- *tab = tab_iter->second.tab_ptr;
+ *tab = tab_iter->second;
return true;
}
void SyncedSessionTracker::LookupTabNodeIds(const std::string& session_tag,
std::set<int>* tab_node_ids) {
tab_node_ids->clear();
- SyncedSessionMap::const_iterator session_iter =
- synced_session_map_.find(session_tag);
+ auto session_iter = synced_session_map_.find(session_tag);
if (session_iter != synced_session_map_.end()) {
tab_node_ids->insert(session_iter->second->tab_node_ids.begin(),
session_iter->second->tab_node_ids.end());
}
- // Incase an invalid node id was included, remove it.
+ // In case an invalid node id was included, remove it.
tab_node_ids->erase(TabNodePool::kInvalidTabNodeID);
}
bool SyncedSessionTracker::LookupLocalSession(
- const sync_driver::SyncedSession** output) const {
- SyncedSessionMap::const_iterator it =
- synced_session_map_.find(local_session_tag_);
+ const SyncedSession** output) const {
+ auto it = synced_session_map_.find(local_session_tag_);
if (it != synced_session_map_.end()) {
- *output = it->second;
+ *output = it->second.get();
return true;
}
return false;
}
-sync_driver::SyncedSession* SyncedSessionTracker::GetSession(
+SyncedSession* SyncedSessionTracker::GetSession(
const std::string& session_tag) {
- sync_driver::SyncedSession* synced_session = NULL;
- if (synced_session_map_.find(session_tag) != synced_session_map_.end()) {
- synced_session = synced_session_map_[session_tag];
- } else {
- synced_session = new sync_driver::SyncedSession;
- DVLOG(1) << "Creating new session with tag " << session_tag << " at "
- << synced_session;
- synced_session->session_tag = session_tag;
- synced_session_map_[session_tag] = synced_session;
- }
- DCHECK(synced_session);
- return synced_session;
+ if (synced_session_map_.find(session_tag) != synced_session_map_.end())
+ return synced_session_map_[session_tag].get();
+
+ std::unique_ptr<SyncedSession> synced_session =
+ base::MakeUnique<SyncedSession>();
+ DVLOG(1) << "Creating new session with tag " << session_tag << " at "
+ << synced_session.get();
+ synced_session->session_tag = session_tag;
+ synced_session_map_[session_tag] = std::move(synced_session);
+
+ return synced_session_map_[session_tag].get();
}
bool SyncedSessionTracker::DeleteSession(const std::string& session_tag) {
- // Cleanup first, which will take care of orphaned SessionTab and
- // SessionWindow objects. The SyncedSession destructor will only delete things
- // that it is currently the parent of.
- CleanupSession(session_tag);
+ unmapped_windows_.erase(session_tag);
+ unmapped_tabs_.erase(session_tag);
bool header_existed = false;
- SyncedSessionMap::iterator iter = synced_session_map_.find(session_tag);
+ auto iter = synced_session_map_.find(session_tag);
if (iter != synced_session_map_.end()) {
- sync_driver::SyncedSession* session = iter->second;
// An implicitly created session that has children tabs but no header node
// will have never had the device_type changed from unset.
- header_existed =
- session->device_type != sync_driver::SyncedSession::TYPE_UNSET;
- synced_session_map_.erase(iter);
+ header_existed = iter->second->device_type != SyncedSession::TYPE_UNSET;
// SyncedSession's destructor will trigger deletion of windows which will in
- // turn trigger the deletion of tabs. This doesn't affect wrappers.
- delete session;
+ // turn trigger the deletion of tabs. This doesn't affect the convenience
+ // maps.
+ synced_session_map_.erase(iter);
}
- // These two erase(...) calls only affect the wrappers.
+ // These two erase(...) calls only affect the convenience maps.
synced_window_map_.erase(session_tag);
synced_tab_map_.erase(session_tag);
@@ -180,130 +169,66 @@ bool SyncedSessionTracker::DeleteSession(const std::string& session_tag) {
void SyncedSessionTracker::ResetSessionTracking(
const std::string& session_tag) {
- // Reset window tracking.
- GetSession(session_tag)->windows.clear();
- SyncedWindowMap::iterator window_iter = synced_window_map_.find(session_tag);
- if (window_iter != synced_window_map_.end()) {
- for (IDToSessionWindowMap::iterator window_map_iter =
- window_iter->second.begin();
- window_map_iter != window_iter->second.end(); ++window_map_iter) {
- window_map_iter->second.owned = false;
- // We clear out the tabs to prevent double referencing of the same tab.
- // All tabs that are in use will be added back as needed.
- window_map_iter->second.window_ptr->tabs.clear();
- }
- }
+ SyncedSession* session = GetSession(session_tag);
- // Reset tab tracking.
- SyncedTabMap::iterator tab_iter = synced_tab_map_.find(session_tag);
- if (tab_iter != synced_tab_map_.end()) {
- for (IDToSessionTabMap::iterator tab_map_iter = tab_iter->second.begin();
- tab_map_iter != tab_iter->second.end(); ++tab_map_iter) {
- tab_map_iter->second.owned = false;
+ for (auto& window_pair : session->windows) {
+ // First unmap the tabs in the window.
+ for (auto& tab : window_pair.second->tabs) {
+ SessionID::id_type tab_id = tab->tab_id.id();
+ unmapped_tabs_[session_tag][tab_id] = std::move(tab);
}
+ window_pair.second->tabs.clear();
+
+ // Then unmap the window itself.
+ unmapped_windows_[session_tag][window_pair.first] =
+ std::move(window_pair.second);
}
+ session->windows.clear();
}
void SyncedSessionTracker::DeleteForeignTab(const std::string& session_tag,
int tab_node_id) {
- SyncedSessionMap::const_iterator session_iter =
- synced_session_map_.find(session_tag);
+ auto session_iter = synced_session_map_.find(session_tag);
if (session_iter != synced_session_map_.end()) {
session_iter->second->tab_node_ids.erase(tab_node_id);
}
}
-bool SyncedSessionTracker::DeleteOldSessionWindowIfNecessary(
- const SessionWindowWrapper& window_wrapper) {
- if (!window_wrapper.owned) {
- DVLOG(1) << "Deleting closed window "
- << window_wrapper.window_ptr->window_id.id();
- // Clear the tabs first, since we don't want the destructor to destroy
- // them. Their deletion will be handled by DeleteOldSessionTabIfNecessary.
- window_wrapper.window_ptr->tabs.clear();
- delete window_wrapper.window_ptr;
- return true;
- }
- return false;
-}
-
-bool SyncedSessionTracker::DeleteOldSessionTabIfNecessary(
- const SessionTabWrapper& tab_wrapper) {
- if (!tab_wrapper.owned) {
- if (VLOG_IS_ON(1)) {
- sessions::SessionTab* tab_ptr = tab_wrapper.tab_ptr;
- std::string title;
- if (tab_ptr->navigations.size() > 0) {
- title =
- " (" +
- base::UTF16ToUTF8(
- tab_ptr->navigations[tab_ptr->navigations.size() - 1].title()) +
- ")";
- }
- DVLOG(1) << "Deleting closed tab " << tab_ptr->tab_id.id() << title
- << " from window " << tab_ptr->window_id.id();
- }
- unmapped_tabs_.erase(tab_wrapper.tab_ptr);
- delete tab_wrapper.tab_ptr;
- return true;
- }
- return false;
-}
-
void SyncedSessionTracker::CleanupSession(const std::string& session_tag) {
- // Go through and delete any windows or tabs without owners.
- SyncedWindowMap::iterator window_iter = synced_window_map_.find(session_tag);
- if (window_iter != synced_window_map_.end()) {
- for (IDToSessionWindowMap::iterator iter = window_iter->second.begin();
- iter != window_iter->second.end();) {
- SessionWindowWrapper window_wrapper = iter->second;
- if (DeleteOldSessionWindowIfNecessary(window_wrapper))
- window_iter->second.erase(iter++);
- else
- ++iter;
- }
- }
+ for (const auto& window_pair : unmapped_windows_[session_tag])
+ synced_window_map_[session_tag].erase(window_pair.first);
+ unmapped_windows_[session_tag].clear();
- SyncedTabMap::iterator tab_iter = synced_tab_map_.find(session_tag);
- if (tab_iter != synced_tab_map_.end()) {
- for (IDToSessionTabMap::iterator iter = tab_iter->second.begin();
- iter != tab_iter->second.end();) {
- SessionTabWrapper tab_wrapper = iter->second;
- if (DeleteOldSessionTabIfNecessary(tab_wrapper)) {
- tab_iter->second.erase(iter++);
- } else {
- ++iter;
- }
- }
- }
+ for (const auto& tab_pair : unmapped_tabs_[session_tag])
+ synced_tab_map_[session_tag].erase(tab_pair.first);
+ unmapped_tabs_[session_tag].clear();
}
void SyncedSessionTracker::PutWindowInSession(const std::string& session_tag,
SessionID::id_type window_id) {
- sessions::SessionWindow* window_ptr = nullptr;
- IDToSessionWindowMap::iterator iter =
- synced_window_map_[session_tag].find(window_id);
- if (iter != synced_window_map_[session_tag].end()) {
- iter->second.owned = true;
- window_ptr = iter->second.window_ptr;
- DVLOG(1) << "Putting seen window " << window_id << " at " << window_ptr
+ std::unique_ptr<sessions::SessionWindow> window;
+
+ auto iter = unmapped_windows_[session_tag].find(window_id);
+ if (iter != unmapped_windows_[session_tag].end()) {
+ DCHECK_EQ(synced_window_map_[session_tag][window_id], iter->second.get());
+ window = std::move(iter->second);
+ unmapped_windows_[session_tag].erase(iter);
+ DVLOG(1) << "Putting seen window " << window_id << " at " << window.get()
<< "in " << (session_tag == local_session_tag_ ? "local session"
: session_tag);
} else {
// Create the window.
- window_ptr = new sessions::SessionWindow();
- window_ptr->window_id.set_id(window_id);
- synced_window_map_[session_tag][window_id] =
- SessionWindowWrapper(window_ptr, IS_OWNED);
- DVLOG(1) << "Putting new window " << window_id << " at " << window_ptr
+ window = base::MakeUnique<sessions::SessionWindow>();
+ window->window_id.set_id(window_id);
+ synced_window_map_[session_tag][window_id] = window.get();
+ DVLOG(1) << "Putting new window " << window_id << " at " << window.get()
<< "in " << (session_tag == local_session_tag_ ? "local session"
: session_tag);
}
- DCHECK(window_ptr);
- DCHECK_EQ(window_ptr->window_id.id(), window_id);
- DCHECK_EQ(reinterpret_cast<sessions::SessionWindow*>(NULL),
- GetSession(session_tag)->windows[window_id]);
- GetSession(session_tag)->windows[window_id] = window_ptr;
+ DCHECK_EQ(window->window_id.id(), window_id);
+ DCHECK(GetSession(session_tag)->windows.end() ==
+ GetSession(session_tag)->windows.find(window_id));
+ GetSession(session_tag)->windows[window_id] = std::move(window);
}
void SyncedSessionTracker::PutTabInWindow(const std::string& session_tag,
@@ -321,38 +246,27 @@ void SyncedSessionTracker::PutTabInWindow(const std::string& session_tag,
// We know that we will eventually process (via GetTab) every single tab node
// in the system, so we permit ourselves to use kInvalidTabNodeID here and
// rely on the later update to build the mapping (or a restart).
- sessions::SessionTab* tab_ptr =
- GetTabImpl(session_tag, tab_id, TabNodePool::kInvalidTabNodeID);
+ GetTabImpl(session_tag, tab_id, TabNodePool::kInvalidTabNodeID);
+
+ // The tab should be unmapped.
+ std::unique_ptr<sessions::SessionTab> tab;
+ auto it = unmapped_tabs_[session_tag].find(tab_id);
+ if (it != unmapped_tabs_[session_tag].end()) {
+ tab = std::move(it->second);
+ unmapped_tabs_[session_tag].erase(it);
+ }
+ DCHECK(tab);
- // It's up to the caller to ensure this never happens. Tabs should not
- // belong to more than one window or appear twice within the same window.
- //
- // If this condition were violated, we would double-free during shutdown.
- // That could cause all sorts of hard to diagnose crashes, possibly in code
- // far away from here. We crash early to avoid this.
- //
- // See http://crbug.com/360822.
- CHECK(!synced_tab_map_[session_tag][tab_id].owned);
-
- // Only tabs that were just created in GetTabImpl(...) are still present in
- // unmapped_tabs_. Most of the time when PutTabInWindow(...) is invoked, the
- // specified tab was already a child of the specified window, and hasn't been
- // in unmapped_tabs_ for quite some time. However, this is not a problem, as
- // std::set::erase(...) will simply have no effect in these cases.
- unmapped_tabs_.erase(tab_ptr);
- synced_tab_map_[session_tag][tab_id].owned = true;
-
- tab_ptr->window_id.set_id(window_id);
+ tab->window_id.set_id(window_id);
DVLOG(1) << " - tab " << tab_id << " added to window " << window_id;
DCHECK(GetSession(session_tag)->windows.find(window_id) !=
GetSession(session_tag)->windows.end());
- std::vector<sessions::SessionTab*>& window_tabs =
- GetSession(session_tag)->windows[window_id]->tabs;
+ auto& window_tabs = GetSession(session_tag)->windows[window_id]->tabs;
if (window_tabs.size() <= tab_index) {
- window_tabs.resize(tab_index + 1, nullptr);
+ window_tabs.resize(tab_index + 1);
}
DCHECK(!window_tabs[tab_index]);
- window_tabs[tab_index] = tab_ptr;
+ window_tabs[tab_index] = std::move(tab);
}
sessions::SessionTab* SyncedSessionTracker::GetTab(
@@ -368,9 +282,9 @@ sessions::SessionTab* SyncedSessionTracker::GetTabImpl(
SessionID::id_type tab_id,
int tab_node_id) {
sessions::SessionTab* tab_ptr = nullptr;
- IDToSessionTabMap::iterator iter = synced_tab_map_[session_tag].find(tab_id);
+ auto iter = synced_tab_map_[session_tag].find(tab_id);
if (iter != synced_tab_map_[session_tag].end()) {
- tab_ptr = iter->second.tab_ptr;
+ tab_ptr = iter->second;
if (tab_node_id != TabNodePool::kInvalidTabNodeID &&
tab_id != TabNodePool::kInvalidTabID) {
// TabIDs are not stable across restarts of a client. Consider this
@@ -390,7 +304,7 @@ sessions::SessionTab* SyncedSessionTracker::GetTabImpl(
// We can also wind up here if we created this tab as an out-of-order
// update to the header node for this session before actually associating
// the tab itself, so the tab node id wasn't available at the time and
- // is currenlty kInvalidTabNodeID.
+ // is currently kInvalidTabNodeID.
//
// In both cases, we can safely throw it into the set of node ids.
GetSession(session_tag)->tab_node_ids.insert(tab_node_id);
@@ -400,22 +314,20 @@ sessions::SessionTab* SyncedSessionTracker::GetTabImpl(
std::string title;
if (tab_ptr->navigations.size() > 0) {
title =
- " (" +
- base::UTF16ToUTF8(
- tab_ptr->navigations[tab_ptr->navigations.size() - 1].title()) +
- ")";
+ " (" + base::UTF16ToUTF8(tab_ptr->navigations.back().title()) + ")";
}
DVLOG(1) << "Getting "
<< (session_tag == local_session_tag_ ? "local session"
: session_tag)
- << "'s seen tab " << tab_id << " at " << tab_ptr << title;
+ << "'s seen tab " << tab_id << " at " << tab_ptr << " " << title;
}
} else {
- tab_ptr = new sessions::SessionTab();
- tab_ptr->tab_id.set_id(tab_id);
- synced_tab_map_[session_tag][tab_id] =
- SessionTabWrapper(tab_ptr, NOT_OWNED);
- unmapped_tabs_.insert(tab_ptr);
+ std::unique_ptr<sessions::SessionTab> tab =
+ base::MakeUnique<sessions::SessionTab>();
+ tab_ptr = tab.get();
+ tab->tab_id.set_id(tab_id);
+ synced_tab_map_[session_tag][tab_id] = tab_ptr;
+ unmapped_tabs_[session_tag][tab_id] = std::move(tab);
GetSession(session_tag)->tab_node_ids.insert(tab_node_id);
DVLOG(1) << "Getting "
<< (session_tag == local_session_tag_ ? "local session"
@@ -428,25 +340,19 @@ sessions::SessionTab* SyncedSessionTracker::GetTabImpl(
}
void SyncedSessionTracker::Clear() {
- // Cleanup first, which will take care of orphaned SessionTab and
- // SessionWindow objects. The SyncedSession destructor will only delete things
- // that is currently parents.
- for (const auto& kv : synced_session_map_) {
- CleanupSession(kv.first);
- }
+ // Cleanup unmapped tabs and windows.
+ unmapped_windows_.clear();
+ unmapped_tabs_.clear();
// Delete SyncedSession objects (which also deletes all their windows/tabs).
- STLDeleteValues(&synced_session_map_);
+ synced_session_map_.clear();
- // Go through and delete any tabs we had allocated but had not yet placed into
- // a SyncedSession object.
- STLDeleteElements(&unmapped_tabs_);
-
- // Get rid of our Window/Tab maps (does not delete the actual Window/Tabs
+ // Get rid of our convenience maps (does not delete the actual Window/Tabs
// themselves; they should have all been deleted above).
synced_window_map_.clear();
synced_tab_map_.clear();
+
local_session_tag_.clear();
}
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/synced_session_tracker.h b/chromium/components/sync_sessions/synced_session_tracker.h
index 4fab1c317d1..63e8429fd0b 100644
--- a/chromium/components/sync_sessions/synced_session_tracker.h
+++ b/chromium/components/sync_sessions/synced_session_tracker.h
@@ -8,6 +8,7 @@
#include <stddef.h>
#include <map>
+#include <memory>
#include <set>
#include <string>
#include <vector>
@@ -19,14 +20,13 @@
#include "components/sync_sessions/tab_node_pool.h"
namespace sync_sessions {
-class SyncSessionsClient;
-}
-namespace browser_sync {
+class SyncSessionsClient;
// Class to manage synced sessions. The tracker will own all SyncedSession
// and SyncedSessionTab objects it creates, and deletes them appropriately on
// destruction.
+//
// Note: SyncedSession objects are created for all synced sessions, including
// the local session (whose tag we maintain separately).
class SyncedSessionTracker {
@@ -37,8 +37,7 @@ class SyncedSessionTracker {
PRESENTABLE // Have one window with at least one tab with syncable content.
};
- explicit SyncedSessionTracker(
- sync_sessions::SyncSessionsClient* sessions_client);
+ explicit SyncedSessionTracker(SyncSessionsClient* sessions_client);
~SyncedSessionTracker();
// We track and distinguish the local session from foreign sessions.
@@ -49,12 +48,11 @@ class SyncedSessionTracker {
// SyncedSessionTracker. Lookup parameter is used to decide which foreign tabs
// should be include.
// Returns true if we had foreign sessions to fill it with, false otherwise.
- bool LookupAllForeignSessions(
- std::vector<const sync_driver::SyncedSession*>* sessions,
- SessionLookup lookup) const;
+ bool LookupAllForeignSessions(std::vector<const SyncedSession*>* sessions,
+ SessionLookup lookup) const;
// Attempts to look up the session windows associatd with the session given
- // by |session_tag|. Ownership Of SessionWindows stays within the
+ // by |session_tag|. Ownership of SessionWindows stays within the
// SyncedSessionTracker.
// If lookup succeeds:
// - Fills windows with the SessionWindow pointers, returns true.
@@ -76,12 +74,12 @@ class SyncedSessionTracker {
// Allows retrieval of existing data for the local session. Unlike GetSession
// this won't create-if-not-present.
- bool LookupLocalSession(const sync_driver::SyncedSession** output) const;
+ bool LookupLocalSession(const SyncedSession** output) const;
// Returns a pointer to the SyncedSession object associated with
// |session_tag|. If none exists, creates one. Ownership of the
// SyncedSession remains within the SyncedSessionTracker.
- sync_driver::SyncedSession* GetSession(const std::string& session_tag);
+ SyncedSession* GetSession(const std::string& session_tag);
// Deletes the session associated with |session_tag| if it exists.
// Returns true if the session existed and was deleted, false otherwise.
@@ -89,12 +87,11 @@ class SyncedSessionTracker {
// Resets the tracking information for the session specified by |session_tag|.
// This involves clearing all the windows and tabs from the session, while
- // keeping pointers saved in the synced_window_map_ and synced_tab_map_.
- // Once reset, all calls to PutWindowInSession and PutTabInWindow will denote
- // that the requested windows and tabs are owned (by setting the boolean
- // in their SessionWindowWrapper/SessionTabWrapper to true) and add them back
- // to their session. The next call to CleanupSession(...) will delete those
- // windows and tabs not owned.
+ // keeping pointers saved in the synced_window_map_ and synced_tab_map_. Once
+ // reset, all calls to PutWindowInSession and PutTabInWindow will denote that
+ // the requested windows and tabs are owned and add them back to their
+ // session. The next call to CleanupSession(...) will delete those windows and
+ // tabs not owned.
void ResetSessionTracking(const std::string& session_tag);
// Tracks the deletion of a foreign tab by removing the given |tab_node_id|
@@ -107,21 +104,20 @@ class SyncedSessionTracker {
void DeleteForeignTab(const std::string& session_tag, int tab_node_id);
// Deletes those windows and tabs associated with |session_tag| that are no
- // longer owned.
- // See ResetSessionTracking(...).
+ // longer owned. See ResetSessionTracking(...).
void CleanupSession(const std::string& session_tag);
// Adds the window with id |window_id| to the session specified by
- // |session_tag|, and markes the window as being owned. If none existed for
- // that session, creates one. Similarly, if the session did not exist yet,
- // creates it. Ownership of the SessionWindow remains within the
- // SyncedSessionTracker.
+ // |session_tag|. If none existed for that session, creates one. Similarly, if
+ // the session did not exist yet, creates it. Ownership of the SessionWindow
+ // remains within the SyncedSessionTracker.
void PutWindowInSession(const std::string& session_tag,
SessionID::id_type window_id);
- // Adds the tab with id |tab_id| to the window |window_id|, and marks it as
- // being owned. If none existed for that session, creates one. Ownership of
- // the SessionTab remains within the SyncedSessionTracker.
+ // Adds the tab with id |tab_id| to the window |window_id|. If none existed
+ // for that session, creates one. Ownership of the SessionTab remains within
+ // the SyncedSessionTracker.
+ //
// Note: GetSession(..) must have already been called with |session_tag| to
// ensure we having mapping information for this session.
void PutTabInWindow(const std::string& session_tag,
@@ -155,7 +151,7 @@ class SyncedSessionTracker {
// Returns the number of tabs associated with the specified session tag.
size_t num_synced_tabs(const std::string& session_tag) const {
- SyncedTabMap::const_iterator iter = synced_tab_map_.find(session_tag);
+ auto iter = synced_tab_map_.find(session_tag);
if (iter != synced_tab_map_.end()) {
return iter->second.size();
} else {
@@ -164,91 +160,44 @@ class SyncedSessionTracker {
}
private:
- // This enum is only used as a named input param for wrapper constructors. The
- // name of this enum and the wrapper's |owned| member variable are a bit
- // misleading. Technically you could argue that the data objects are in charge
- // of deleting their children data objects during their destructors, but this
- // tracker will often circumvent this mechanism. This tracker ensures that the
- // lifetime of both data object and wrapper are as identical as possible.
-
- // Alternatively, this |owned| concept can be thought of as being orphaned or
- // not. Although all data objects are tied to a session (via tag), they don't
- // always have a parent. Suppose we have information about a tab but no
- // information about it's parent window. This tab would be 'not owned', aka
- // orphaned. CleanupSession(...) can then delete any orphanted data objects
- // and wrapper for a given session via session tag.
- enum OwnedState { IS_OWNED, NOT_OWNED };
-
- // Datatypes for accessing session data. Neither of the *Wrappers actually
- // have ownership of the Windows/Tabs, they just provide id-based access to
- // them. The ownership remains within its containing session (for windows and
- // mapped tabs, unmapped tabs are owned by the unmapped_tabs_ container).
- // Note, we pair pointers with bools so that we can track what is owned and
- // what can be deleted (see ResetSessionTracking(..) and CleanupSession(..)
- // above). IsOwned is used as a wrapper constructor parameter for readability.
- struct SessionTabWrapper {
- SessionTabWrapper() : tab_ptr(NULL), owned(false) {}
-
- SessionTabWrapper(sessions::SessionTab* tab_ptr, OwnedState owned)
- : tab_ptr(tab_ptr), owned(owned == IS_OWNED) {}
-
- sessions::SessionTab* tab_ptr;
-
- // This is used as part of a mark-and-sweep approach to garbage
- // collection for closed tabs that are no longer "in use", or "owned".
- // ResetSessionTracking will clear |owned| bits, and if it is not claimed
- // by a window by the time CleanupSession is called it will be deleted.
- bool owned;
- };
- typedef std::map<SessionID::id_type, SessionTabWrapper> IDToSessionTabMap;
- typedef std::map<std::string, IDToSessionTabMap> SyncedTabMap;
-
- struct SessionWindowWrapper {
- SessionWindowWrapper() : window_ptr(NULL), owned(false) {}
- SessionWindowWrapper(sessions::SessionWindow* window_ptr, OwnedState owned)
- : window_ptr(window_ptr), owned(owned == IS_OWNED) {}
- sessions::SessionWindow* window_ptr;
- bool owned;
- };
- typedef std::map<SessionID::id_type, SessionWindowWrapper>
- IDToSessionWindowMap;
- typedef std::map<std::string, IDToSessionWindowMap> SyncedWindowMap;
-
- typedef std::map<std::string, sync_driver::SyncedSession*> SyncedSessionMap;
-
- // Helper methods for deleting SessionWindows and SessionTabs without owners.
- bool DeleteOldSessionWindowIfNecessary(
- const SessionWindowWrapper& window_wrapper);
- bool DeleteOldSessionTabIfNecessary(const SessionTabWrapper& tab_wrapper);
-
// Implementation for GetTab(...) above, permits invalid tab_node_id.
sessions::SessionTab* GetTabImpl(const std::string& session_tag,
SessionID::id_type tab_id,
int tab_node_id);
// The client of the sync sessions datatype.
- sync_sessions::SyncSessionsClient* const sessions_client_;
-
- // Per client mapping of tab id's to their SessionTab objects.
- // Key: session tag.
- // Value: Tab id to SessionTabWrapper map.
- SyncedTabMap synced_tab_map_;
-
- // Per client mapping of the window id's to their SessionWindow objects.
- // Key: session_tag
- // Value: Window id to SessionWindowWrapper map.
- SyncedWindowMap synced_window_map_;
-
- // Per client mapping synced session objects.
- // Key: session tag.
- // Value: SyncedSession object pointer.
- SyncedSessionMap synced_session_map_;
-
- // The set of tabs that we have seen, and created SessionTab objects for, but
- // have not yet mapped to SyncedSessions. These are temporarily orphaned
- // tabs, and won't be deleted if we delete synced_session_map_, but are still
- // owned by the SyncedSessionTracker itself (and deleted on Clear()).
- std::set<sessions::SessionTab*> unmapped_tabs_;
+ SyncSessionsClient* const sessions_client_;
+
+ // The mapping of tab/window ids to their SessionTab/SessionWindow objects.
+ // The SessionTab/SessionWindow objects referred to may be owned either by the
+ // session in the |synced_session_map_| or be temporarily unmapped and live in
+ // the |unmapped_tabs_|/|unmapped_windows_| collections.
+ //
+ // Map: session tag -> (tab/window id -> SessionTab*/SessionWindow*)
+ std::map<std::string, std::map<SessionID::id_type, sessions::SessionTab*>>
+ synced_tab_map_;
+ std::map<std::string, std::map<SessionID::id_type, sessions::SessionWindow*>>
+ synced_window_map_;
+
+ // The collection that owns the SyncedSessions, and transitively, all of the
+ // windows and tabs they contain.
+ //
+ // Map: session tag -> owned SyncedSession
+ std::map<std::string, std::unique_ptr<SyncedSession>> synced_session_map_;
+
+ // The collection of tabs/windows not owned by a SyncedSession. This is the
+ // case either because 1. (in the case of tabs) they were newly created by
+ // GetTab() and not yet added to a session, or 2. they were removed from their
+ // owning session by a call to ResetSessionTracking() and not yet added back.
+ //
+ // Map: session tag -> (tab/window id -> owned SessionTab/SessionWindow)
+ std::map<std::string,
+ std::map<SessionID::id_type, std::unique_ptr<sessions::SessionTab>>>
+ unmapped_tabs_;
+ std::map<
+ std::string,
+ std::map<SessionID::id_type, std::unique_ptr<sessions::SessionWindow>>>
+ unmapped_windows_;
// The tag for this machine's local session, so we can distinguish the foreign
// sessions.
@@ -257,6 +206,6 @@ class SyncedSessionTracker {
DISALLOW_COPY_AND_ASSIGN(SyncedSessionTracker);
};
-} // namespace browser_sync
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_SYNCED_SESSION_TRACKER_H_
diff --git a/chromium/components/sync_sessions/synced_session_tracker_unittest.cc b/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
index 9b804aeaa14..68c1f471a1f 100644
--- a/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
+++ b/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
@@ -4,18 +4,14 @@
#include "components/sync_sessions/synced_session_tracker.h"
-#include <string>
-#include <vector>
-
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
-#include "components/sessions/core/session_types.h"
#include "components/sync_sessions/fake_sync_sessions_client.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace browser_sync {
+namespace sync_sessions {
namespace {
@@ -32,13 +28,13 @@ class SyncedSessionTrackerTest : public testing::Test {
SyncedSessionTracker* GetTracker() { return &tracker_; }
private:
- sync_sessions::FakeSyncSessionsClient sessions_client_;
+ FakeSyncSessionsClient sessions_client_;
SyncedSessionTracker tracker_;
};
TEST_F(SyncedSessionTrackerTest, GetSession) {
- sync_driver::SyncedSession* session1 = GetTracker()->GetSession("tag");
- sync_driver::SyncedSession* session2 = GetTracker()->GetSession("tag2");
+ SyncedSession* session1 = GetTracker()->GetSession("tag");
+ SyncedSession* session2 = GetTracker()->GetSession("tag2");
ASSERT_EQ(session1, GetTracker()->GetSession("tag"));
ASSERT_NE(session1, session2);
// Should clean up memory on its own.
@@ -52,7 +48,7 @@ TEST_F(SyncedSessionTrackerTest, GetTabUnmapped) {
TEST_F(SyncedSessionTrackerTest, PutWindowInSession) {
GetTracker()->PutWindowInSession("tag", 0);
- sync_driver::SyncedSession* session = GetTracker()->GetSession("tag");
+ SyncedSession* session = GetTracker()->GetSession("tag");
ASSERT_EQ(1U, session->windows.size());
// Should clean up memory on its own.
}
@@ -61,15 +57,16 @@ TEST_F(SyncedSessionTrackerTest, PutTabInWindow) {
GetTracker()->PutWindowInSession("tag", 10);
GetTracker()->PutTabInWindow("tag", 10, 15,
0); // win id 10, tab id 15, tab ind 0.
- sync_driver::SyncedSession* session = GetTracker()->GetSession("tag");
+ SyncedSession* session = GetTracker()->GetSession("tag");
ASSERT_EQ(1U, session->windows.size());
ASSERT_EQ(1U, session->windows[10]->tabs.size());
- ASSERT_EQ(GetTracker()->GetTab("tag", 15, 1), session->windows[10]->tabs[0]);
+ ASSERT_EQ(GetTracker()->GetTab("tag", 15, 1),
+ session->windows[10]->tabs[0].get());
// Should clean up memory on its own.
}
TEST_F(SyncedSessionTrackerTest, LookupAllForeignSessions) {
- std::vector<const sync_driver::SyncedSession*> sessions;
+ std::vector<const SyncedSession*> sessions;
ASSERT_FALSE(GetTracker()->LookupAllForeignSessions(
&sessions, SyncedSessionTracker::PRESENTABLE));
GetTracker()->GetSession("tag1");
@@ -149,10 +146,10 @@ TEST_F(SyncedSessionTrackerTest, Complex) {
ASSERT_EQ(2U, GetTracker()->num_synced_sessions());
ASSERT_FALSE(GetTracker()->DeleteSession(tag3));
- sync_driver::SyncedSession* session = GetTracker()->GetSession(tag1);
- sync_driver::SyncedSession* session2 = GetTracker()->GetSession(tag2);
- sync_driver::SyncedSession* session3 = GetTracker()->GetSession(tag3);
- session3->device_type = sync_driver::SyncedSession::TYPE_OTHER;
+ SyncedSession* session = GetTracker()->GetSession(tag1);
+ SyncedSession* session2 = GetTracker()->GetSession(tag2);
+ SyncedSession* session3 = GetTracker()->GetSession(tag3);
+ session3->device_type = SyncedSession::TYPE_OTHER;
ASSERT_EQ(3U, GetTracker()->num_synced_sessions());
ASSERT_TRUE(session);
@@ -182,7 +179,7 @@ TEST_F(SyncedSessionTrackerTest, Complex) {
ASSERT_EQ(0U, windows.size());
// The sessions don't have valid tabs, lookup should not succeed.
- std::vector<const sync_driver::SyncedSession*> sessions;
+ std::vector<const SyncedSession*> sessions;
ASSERT_FALSE(GetTracker()->LookupAllForeignSessions(
&sessions, SyncedSessionTracker::PRESENTABLE));
ASSERT_TRUE(GetTracker()->LookupAllForeignSessions(
@@ -286,7 +283,7 @@ TEST_F(SyncedSessionTrackerTest, SessionTracking) {
std::string tag2 = "tag2";
// Create some session information that is stale.
- sync_driver::SyncedSession* session1 = GetTracker()->GetSession(tag1);
+ SyncedSession* session1 = GetTracker()->GetSession(tag1);
GetTracker()->PutWindowInSession(tag1, 0);
GetTracker()->PutTabInWindow(tag1, 0, 0, 0);
GetTracker()->PutTabInWindow(tag1, 0, 1, 1);
@@ -301,7 +298,7 @@ TEST_F(SyncedSessionTrackerTest, SessionTracking) {
ASSERT_EQ(6U, GetTracker()->num_synced_tabs(tag1));
// Create a session that should not be affected.
- sync_driver::SyncedSession* session2 = GetTracker()->GetSession(tag2);
+ SyncedSession* session2 = GetTracker()->GetSession(tag2);
GetTracker()->PutWindowInSession(tag2, 2);
GetTracker()->PutTabInWindow(tag2, 2, 1, 0);
ASSERT_EQ(1U, session2->windows.size());
@@ -368,4 +365,4 @@ TEST_F(SyncedSessionTrackerTest, DeleteForeignTab) {
EXPECT_TRUE(result.empty());
}
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/synced_tab_delegate.cc b/chromium/components/sync_sessions/synced_tab_delegate.cc
index 29b21fc3dc8..e36a0d9717e 100644
--- a/chromium/components/sync_sessions/synced_tab_delegate.cc
+++ b/chromium/components/sync_sessions/synced_tab_delegate.cc
@@ -4,14 +4,9 @@
#include "components/sync_sessions/synced_tab_delegate.h"
-#include "base/logging.h"
-#include "components/sync_sessions/sync_sessions_client.h"
-
-using browser_sync::SyncedTabDelegate;
-
-namespace browser_sync {
+namespace sync_sessions {
SyncedTabDelegate::SyncedTabDelegate() {}
SyncedTabDelegate::~SyncedTabDelegate() {}
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/synced_tab_delegate.h b/chromium/components/sync_sessions/synced_tab_delegate.h
index def7256dd32..c78c7e42627 100644
--- a/chromium/components/sync_sessions/synced_tab_delegate.h
+++ b/chromium/components/sync_sessions/synced_tab_delegate.h
@@ -19,7 +19,7 @@ namespace sync_sessions {
class SyncSessionsClient;
}
-namespace browser_sync {
+namespace sync_sessions {
// A SyncedTabDelegate is used to insulate the sync code from depending
// directly on WebContents, NavigationController, and the extensions TabHelper.
@@ -48,14 +48,14 @@ class SyncedTabDelegate {
// Supervised user related methods.
virtual bool ProfileIsSupervised() const = 0;
- virtual const std::vector<const sessions::SerializedNavigationEntry*>*
+ virtual const std::vector<
+ std::unique_ptr<const sessions::SerializedNavigationEntry>>*
GetBlockedNavigations() const = 0;
// Session sync related methods.
virtual int GetSyncId() const = 0;
virtual void SetSyncId(int sync_id) = 0;
- virtual bool ShouldSync(
- sync_sessions::SyncSessionsClient* sessions_client) = 0;
+ virtual bool ShouldSync(SyncSessionsClient* sessions_client) = 0;
// Whether this tab is a placeholder tab. On some platforms, tabs can be
// restored without bringing all their state into memory, and are just
@@ -67,6 +67,6 @@ class SyncedTabDelegate {
SyncedTabDelegate();
};
-} // namespace browser_sync
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_SYNCED_TAB_DELEGATE_H__
diff --git a/chromium/components/sync_sessions/synced_window_delegate.h b/chromium/components/sync_sessions/synced_window_delegate.h
index 7c779a47c5c..af99cacf0fc 100644
--- a/chromium/components/sync_sessions/synced_window_delegate.h
+++ b/chromium/components/sync_sessions/synced_window_delegate.h
@@ -9,7 +9,7 @@
#include "components/sessions/core/session_id.h"
-namespace browser_sync {
+namespace sync_sessions {
class SyncedTabDelegate;
@@ -65,6 +65,6 @@ class SyncedWindowDelegate {
virtual ~SyncedWindowDelegate() {}
};
-} // namespace browser_sync
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_SYNCED_WINDOW_DELEGATE_H_
diff --git a/chromium/components/sync_sessions/synced_window_delegates_getter.cc b/chromium/components/sync_sessions/synced_window_delegates_getter.cc
index 65e7e73be84..9c496f46f97 100644
--- a/chromium/components/sync_sessions/synced_window_delegates_getter.cc
+++ b/chromium/components/sync_sessions/synced_window_delegates_getter.cc
@@ -4,10 +4,10 @@
#include "components/sync_sessions/synced_window_delegates_getter.h"
-namespace browser_sync {
+namespace sync_sessions {
SyncedWindowDelegatesGetter::SyncedWindowDelegatesGetter() {}
SyncedWindowDelegatesGetter::~SyncedWindowDelegatesGetter() {}
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/synced_window_delegates_getter.h b/chromium/components/sync_sessions/synced_window_delegates_getter.h
index b694ed8b925..35e8f1c3cb9 100644
--- a/chromium/components/sync_sessions/synced_window_delegates_getter.h
+++ b/chromium/components/sync_sessions/synced_window_delegates_getter.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "components/sessions/core/session_id.h"
-namespace browser_sync {
+namespace sync_sessions {
class SyncedWindowDelegate;
@@ -31,6 +31,6 @@ class SyncedWindowDelegatesGetter {
DISALLOW_COPY_AND_ASSIGN(SyncedWindowDelegatesGetter);
};
-} // namespace browser_sync
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_SYNCED_WINDOW_DELEGATES_GETTER_H_
diff --git a/chromium/components/sync_sessions/tab_node_pool.cc b/chromium/components/sync_sessions/tab_node_pool.cc
index df1dc9bb85e..6ad5da7771d 100644
--- a/chromium/components/sync_sessions/tab_node_pool.cc
+++ b/chromium/components/sync_sessions/tab_node_pool.cc
@@ -7,13 +7,13 @@
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_data.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/protocol/session_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/protocol/session_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
-namespace browser_sync {
+namespace sync_sessions {
const size_t TabNodePool::kFreeNodesLowWatermark = 25;
const size_t TabNodePool::kFreeNodesHighWatermark = 100;
@@ -179,4 +179,4 @@ void TabNodePool::SetMachineTag(const std::string& machine_tag) {
machine_tag_ = machine_tag;
}
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/tab_node_pool.h b/chromium/components/sync_sessions/tab_node_pool.h
index 77021a13947..b197e00b1f5 100644
--- a/chromium/components/sync_sessions/tab_node_pool.h
+++ b/chromium/components/sync_sessions/tab_node_pool.h
@@ -13,13 +13,13 @@
#include "base/macros.h"
#include "components/sessions/core/session_id.h"
-#include "sync/api/sync_change_processor.h"
+#include "components/sync/api/sync_change_processor.h"
namespace syncer {
class SyncChangeProcessor;
-}
+} // namespace syncer
-namespace browser_sync {
+namespace sync_sessions {
// A pool for managing free/used tab sync nodes for the *local* session.
// Performs lazy creation of sync nodes when necessary.
@@ -159,6 +159,6 @@ class TabNodePool {
DISALLOW_COPY_AND_ASSIGN(TabNodePool);
};
-} // namespace browser_sync
+} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_TAB_NODE_POOL_H_
diff --git a/chromium/components/sync_sessions/tab_node_pool_unittest.cc b/chromium/components/sync_sessions/tab_node_pool_unittest.cc
index 5c0a4d770d9..e52397b3214 100644
--- a/chromium/components/sync_sessions/tab_node_pool_unittest.cc
+++ b/chromium/components/sync_sessions/tab_node_pool_unittest.cc
@@ -4,16 +4,14 @@
#include "components/sync_sessions/tab_node_pool.h"
-#include <stddef.h>
-
#include <vector>
-#include "sync/api/sync_change.h"
-#include "sync/protocol/session_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/protocol/session_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace browser_sync {
+namespace sync_sessions {
class SyncTabNodePoolTest : public testing::Test {
protected:
@@ -261,4 +259,4 @@ TEST_F(SyncTabNodePoolTest, TabPoolFreeNodeLimits) {
} // namespace
-} // namespace browser_sync
+} // namespace sync_sessions
diff --git a/chromium/components/sync_ui_strings.grdp b/chromium/components/sync_ui_strings.grdp
index 0512cb9c201..b5cbb0b02fd 100644
--- a/chromium/components/sync_ui_strings.grdp
+++ b/chromium/components/sync_ui_strings.grdp
@@ -16,6 +16,9 @@
<message name="IDS_SYNC_DATATYPE_PASSWORDS" desc="Saved passwords, one of the data types that we allow syncing.">
Passwords
</message>
+ <message name="IDS_SYNC_DATATYPE_PREFERENCES" desc="Settings, one of the data types that we allow syncing.">
+ Settings
+ </message>
<message name="IDS_SYNC_DATATYPE_TABS" desc="Open Tabs, one of the data types that we allow syncing.">
Open tabs
</message>
diff --git a/chromium/components/syncable_prefs.gypi b/chromium/components/syncable_prefs.gypi
deleted file mode 100644
index 66943f4bc04..00000000000
--- a/chromium/components/syncable_prefs.gypi
+++ /dev/null
@@ -1,64 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/syncable_prefs
- 'target_name': 'syncable_prefs',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../sync/sync.gyp:sync',
- 'pref_registry',
- 'prefs/prefs.gyp:prefs',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'syncable_prefs/pref_model_associator.cc',
- 'syncable_prefs/pref_model_associator.h',
- 'syncable_prefs/pref_model_associator_client.h',
- 'syncable_prefs/pref_service_syncable.cc',
- 'syncable_prefs/pref_service_syncable.h',
- 'syncable_prefs/pref_service_syncable_factory.cc',
- 'syncable_prefs/pref_service_syncable_factory.h',
- 'syncable_prefs/pref_service_syncable_observer.h',
- 'syncable_prefs/synced_pref_change_registrar.cc',
- 'syncable_prefs/synced_pref_change_registrar.h',
- 'syncable_prefs/synced_pref_observer.h',
- ],
- 'conditions': [
- ['configuration_policy==1', {
- # This define is only used for compiling the .cc files in this target.
- 'defines': [ "SYNCABLE_PREFS_USE_POLICY" ],
- 'dependencies': [
- 'cloud_policy_code_generate',
- 'policy_component_browser',
- 'policy_component_common',
- ],
- }],
- ],
- },
- {
- # GN version: //components/syncable_prefs:test_support
- 'target_name': 'syncable_prefs_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../testing/gtest.gyp:gtest',
- 'syncable_prefs',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'syncable_prefs/pref_service_mock_factory.cc',
- 'syncable_prefs/pref_service_mock_factory.h',
- 'syncable_prefs/testing_pref_service_syncable.cc',
- 'syncable_prefs/testing_pref_service_syncable.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/syncable_prefs/BUILD.gn b/chromium/components/syncable_prefs/BUILD.gn
index a4977ce007a..05532f93408 100644
--- a/chromium/components/syncable_prefs/BUILD.gn
+++ b/chromium/components/syncable_prefs/BUILD.gn
@@ -4,7 +4,7 @@
import("//build/config/features.gni")
-source_set("syncable_prefs") {
+static_library("syncable_prefs") {
sources = [
"pref_model_associator.cc",
"pref_model_associator.h",
@@ -23,21 +23,18 @@ source_set("syncable_prefs") {
"//base",
"//components/pref_registry",
"//components/prefs",
- "//sync",
+ "//components/sync",
]
if (enable_configuration_policy) {
# This define is only used for compiling the .cc files in this target.
defines = [ "SYNCABLE_PREFS_USE_POLICY" ]
- deps += [
- "//components/policy:policy_component_browser",
- "//components/policy:policy_component_common",
- ]
+ deps += [ "//components/policy/core/browser" ]
}
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"pref_service_mock_factory.cc",
@@ -67,7 +64,7 @@ source_set("unit_tests") {
":test_support",
"//components/pref_registry",
"//components/prefs",
- "//sync:test_support_sync_api",
+ "//components/sync:test_support_sync_api",
"//testing/gtest",
]
}
diff --git a/chromium/components/syncable_prefs/DEPS b/chromium/components/syncable_prefs/DEPS
index 3bfaed6bcb6..3d0c3a3efe4 100644
--- a/chromium/components/syncable_prefs/DEPS
+++ b/chromium/components/syncable_prefs/DEPS
@@ -3,7 +3,7 @@ include_rules = [
"+components/policy/core/common",
"+components/pref_registry",
"+components/prefs",
- "+sync",
+ "+components/sync",
# syncable_prefs can be used on all platforms, including iOS. Do not allow
# platform-specific dependencies.
diff --git a/chromium/components/syncable_prefs/pref_model_associator.cc b/chromium/components/syncable_prefs/pref_model_associator.cc
index 4cbdd558881..a2758de670f 100644
--- a/chromium/components/syncable_prefs/pref_model_associator.cc
+++ b/chromium/components/syncable_prefs/pref_model_associator.cc
@@ -12,16 +12,15 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/prefs/pref_service.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/protocol/preference_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
#include "components/syncable_prefs/pref_model_associator_client.h"
#include "components/syncable_prefs/pref_service_syncable.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/protocol/preference_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
using syncer::PREFERENCES;
using syncer::PRIORITY_PREFERENCES;
@@ -70,8 +69,6 @@ PrefModelAssociator::~PrefModelAssociator() {
DCHECK(CalledOnValidThread());
pref_service_ = NULL;
- STLDeleteContainerPairSecondPointers(synced_pref_observers_.begin(),
- synced_pref_observers_.end());
synced_pref_observers_.clear();
}
@@ -157,6 +154,14 @@ void PrefModelAssociator::InitPrefAndAssociate(
// we'll send the new user controlled value to the syncer.
}
+void PrefModelAssociator::RegisterMergeDataFinishedCallback(
+ const base::Closure& callback) {
+ if (!models_associated_)
+ callback_list_.push_back(callback);
+ else
+ callback.Run();
+}
+
syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing(
syncer::ModelType type,
const syncer::SyncDataList& initial_sync_data,
@@ -213,6 +218,10 @@ syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing(
if (merge_result.error().IsSet())
return merge_result;
+ for (const auto& callback : callback_list_)
+ callback.Run();
+ callback_list_.clear();
+
models_associated_ = true;
pref_service_->OnIsSyncingChanged();
return merge_result;
@@ -287,10 +296,8 @@ base::Value* PrefModelAssociator::MergeListValues(const base::Value& from_value,
static_cast<const base::ListValue&>(to_value);
base::ListValue* result = to_list_value.DeepCopy();
- for (base::ListValue::const_iterator i = from_list_value.begin();
- i != from_list_value.end(); ++i) {
- base::Value* value = (*i)->DeepCopy();
- result->AppendIfNotPresent(value);
+ for (const auto& value : from_list_value) {
+ result->AppendIfNotPresent(value->CreateDeepCopy());
}
return result;
}
@@ -432,21 +439,20 @@ bool PrefModelAssociator::IsPrefSynced(const std::string& name) const {
void PrefModelAssociator::AddSyncedPrefObserver(const std::string& name,
SyncedPrefObserver* observer) {
- SyncedPrefObserverList* observers = synced_pref_observers_[name];
- if (observers == NULL) {
- observers = new SyncedPrefObserverList;
- synced_pref_observers_[name] = observers;
- }
+ std::unique_ptr<SyncedPrefObserverList>& observers =
+ synced_pref_observers_[name];
+ if (!observers)
+ observers = base::MakeUnique<SyncedPrefObserverList>();
+
observers->AddObserver(observer);
}
void PrefModelAssociator::RemoveSyncedPrefObserver(const std::string& name,
SyncedPrefObserver* observer) {
- SyncedPrefObserverMap::iterator observer_iter =
- synced_pref_observers_.find(name);
+ auto observer_iter = synced_pref_observers_.find(name);
if (observer_iter == synced_pref_observers_.end())
return;
- SyncedPrefObserverList* observers = observer_iter->second;
+ SyncedPrefObserverList* observers = observer_iter->second.get();
observers->RemoveObserver(observer);
}
@@ -528,11 +534,10 @@ void PrefModelAssociator::SetPrefService(PrefServiceSyncable* pref_service) {
void PrefModelAssociator::NotifySyncedPrefObservers(const std::string& path,
bool from_sync) const {
- SyncedPrefObserverMap::const_iterator observer_iter =
- synced_pref_observers_.find(path);
+ auto observer_iter = synced_pref_observers_.find(path);
if (observer_iter == synced_pref_observers_.end())
return;
- SyncedPrefObserverList* observers = observer_iter->second;
+ SyncedPrefObserverList* observers = observer_iter->second.get();
FOR_EACH_OBSERVER(SyncedPrefObserver, *observers,
OnSyncedPrefChanged(path, from_sync));
}
diff --git a/chromium/components/syncable_prefs/pref_model_associator.h b/chromium/components/syncable_prefs/pref_model_associator.h
index 6eaab7ef7bd..8df666206b1 100644
--- a/chromium/components/syncable_prefs/pref_model_associator.h
+++ b/chromium/components/syncable_prefs/pref_model_associator.h
@@ -9,15 +9,17 @@
#include <memory>
#include <set>
#include <string>
+#include <vector>
+#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/threading/non_thread_safe.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/syncable_service.h"
#include "components/syncable_prefs/synced_pref_observer.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/syncable_service.h"
namespace base {
class Value;
@@ -120,6 +122,10 @@ class PrefModelAssociator
void SetPrefModelAssociatorClientForTesting(
const PrefModelAssociatorClient* client);
+ // Register callback method which will get called at the end of
+ // PrefModelAssociator::MergeDataAndStartSyncing().
+ void RegisterMergeDataFinishedCallback(const base::Closure& callback);
+
protected:
friend class PrefServiceSyncableTest;
@@ -184,15 +190,17 @@ class PrefModelAssociator
// Map prefs to lists of observers. Observers will receive notification when
// a pref changes, including the detail of whether or not the change came
// from sync.
- typedef base::ObserverList<SyncedPrefObserver> SyncedPrefObserverList;
- typedef base::hash_map<std::string, SyncedPrefObserverList*>
- SyncedPrefObserverMap;
+ using SyncedPrefObserverList = base::ObserverList<SyncedPrefObserver>;
+ using SyncedPrefObserverMap =
+ base::hash_map<std::string, std::unique_ptr<SyncedPrefObserverList>>;
void NotifySyncedPrefObservers(const std::string& path, bool from_sync) const;
SyncedPrefObserverMap synced_pref_observers_;
const PrefModelAssociatorClient* client_; // Weak.
+ std::vector<base::Closure> callback_list_;
+
DISALLOW_COPY_AND_ASSIGN(PrefModelAssociator);
};
diff --git a/chromium/components/syncable_prefs/pref_service_syncable.cc b/chromium/components/syncable_prefs/pref_service_syncable.cc
index c656381877d..ab5e156b6ec 100644
--- a/chromium/components/syncable_prefs/pref_service_syncable.cc
+++ b/chromium/components/syncable_prefs/pref_service_syncable.cc
@@ -35,6 +35,7 @@ PrefServiceSyncable::PrefServiceSyncable(
pref_registry,
read_error_callback,
async),
+ pref_service_forked_(false),
pref_sync_associator_(pref_model_associator_client, syncer::PREFERENCES),
priority_pref_sync_associator_(pref_model_associator_client,
syncer::PRIORITY_PREFERENCES) {
@@ -153,6 +154,11 @@ void PrefServiceSyncable::RemoveSyncedPrefObserver(
priority_pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
}
+void PrefServiceSyncable::RegisterMergeDataFinishedCallback(
+ const base::Closure& callback) {
+ pref_sync_associator_.RegisterMergeDataFinishedCallback(callback);
+}
+
// Set the PrefModelAssociatorClient to use for that object during tests.
void PrefServiceSyncable::SetPrefModelAssociatorClientForTesting(
const PrefModelAssociatorClient* pref_model_associator_client) {
diff --git a/chromium/components/syncable_prefs/pref_service_syncable.h b/chromium/components/syncable_prefs/pref_service_syncable.h
index 2aa7d7f61e5..9e467b4bff8 100644
--- a/chromium/components/syncable_prefs/pref_service_syncable.h
+++ b/chromium/components/syncable_prefs/pref_service_syncable.h
@@ -73,6 +73,8 @@ class PrefServiceSyncable : public PrefService {
void AddObserver(PrefServiceSyncableObserver* observer);
void RemoveObserver(PrefServiceSyncableObserver* observer);
+ void RegisterMergeDataFinishedCallback(const base::Closure& callback);
+
// TODO(zea): Have PrefServiceSyncable implement
// syncer::SyncableService directly.
syncer::SyncableService* GetSyncableService(const syncer::ModelType& type);
diff --git a/chromium/components/syncable_prefs/pref_service_syncable_unittest.cc b/chromium/components/syncable_prefs/pref_service_syncable_unittest.cc
index 5aaa09616db..b7e2cfaa829 100644
--- a/chromium/components/syncable_prefs/pref_service_syncable_unittest.cc
+++ b/chromium/components/syncable_prefs/pref_service_syncable_unittest.cc
@@ -15,17 +15,17 @@
#include "base/strings/utf_string_conversions.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/scoped_user_pref_update.h"
+#include "components/sync/api/attachments/attachment_id.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/sync_error_factory_mock.h"
+#include "components/sync/api/syncable_service.h"
+#include "components/sync/core/attachments/attachment_service_proxy_for_test.h"
+#include "components/sync/protocol/preference_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
#include "components/syncable_prefs/pref_model_associator.h"
#include "components/syncable_prefs/pref_model_associator_client.h"
#include "components/syncable_prefs/testing_pref_service_syncable.h"
-#include "sync/api/attachments/attachment_id.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/sync_error_factory_mock.h"
-#include "sync/api/syncable_service.h"
-#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
-#include "sync/protocol/preference_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
using syncer::SyncChange;
@@ -46,6 +46,10 @@ const char kDefaultCharsetPrefName[] = "default_charset";
const char kNonDefaultCharsetValue[] = "foo";
const char kDefaultCharsetValue[] = "utf-8";
+void Increment(int* num) {
+ (*num)++;
+}
+
class TestPrefModelAssociatorClient : public PrefModelAssociatorClient {
public:
TestPrefModelAssociatorClient() {}
@@ -121,7 +125,6 @@ class PrefServiceSyncableTest : public testing::Test {
pref_sync_service_ = reinterpret_cast<PrefModelAssociator*>(
prefs_.GetSyncableService(syncer::PREFERENCES));
ASSERT_TRUE(pref_sync_service_);
- next_pref_remote_sync_node_id_ = 0;
}
syncer::SyncChange MakeRemoteChange(int64_t id,
@@ -170,7 +173,7 @@ class PrefServiceSyncableTest : public testing::Test {
test_processor_ = new TestSyncProcessorStub(output);
syncer::SyncMergeResult r = pref_sync_service_->MergeDataAndStartSyncing(
syncer::PREFERENCES, initial_data, base::WrapUnique(test_processor_),
- base::WrapUnique(new syncer::SyncErrorFactoryMock()));
+ base::MakeUnique<syncer::SyncErrorFactoryMock>());
EXPECT_FALSE(r.error().IsSet());
}
@@ -311,7 +314,7 @@ TEST_F(PrefServiceSyncableTest, FailModelAssociation) {
stub->FailNextProcessSyncChanges();
syncer::SyncMergeResult r = pref_sync_service_->MergeDataAndStartSyncing(
syncer::PREFERENCES, syncer::SyncDataList(), base::WrapUnique(stub),
- base::WrapUnique(new syncer::SyncErrorFactoryMock()));
+ base::MakeUnique<syncer::SyncErrorFactoryMock>());
EXPECT_TRUE(r.error().IsSet());
}
@@ -555,6 +558,17 @@ TEST_F(PrefServiceSyncableTest, DeletePreference) {
EXPECT_TRUE(pref->IsDefaultValue());
}
+TEST_F(PrefServiceSyncableTest, RegisterMergeDataFinishedCallback) {
+ int num_callbacks = 0;
+
+ prefs_.RegisterMergeDataFinishedCallback(
+ base::Bind(&Increment, &num_callbacks));
+ EXPECT_EQ(0, num_callbacks);
+
+ InitWithNoSyncData();
+ EXPECT_EQ(1, num_callbacks);
+}
+
} // namespace
} // namespace syncable_prefs
diff --git a/chromium/components/test_runner/BUILD.gn b/chromium/components/test_runner/BUILD.gn
index 283dacc96bb..e8063ad67ce 100644
--- a/chromium/components/test_runner/BUILD.gn
+++ b/chromium/components/test_runner/BUILD.gn
@@ -89,18 +89,18 @@ component("test_runner") {
"web_frame_test_client.h",
"web_frame_test_proxy.cc",
"web_frame_test_proxy.h",
- "web_task.cc",
- "web_task.h",
"web_test_delegate.h",
"web_test_interfaces.cc",
"web_test_interfaces.h",
- "web_test_proxy.cc",
- "web_test_proxy.h",
"web_test_runner.h",
"web_view_test_client.cc",
"web_view_test_client.h",
+ "web_view_test_proxy.cc",
+ "web_view_test_proxy.h",
"web_widget_test_client.cc",
"web_widget_test_client.h",
+ "web_widget_test_proxy.cc",
+ "web_widget_test_proxy.h",
]
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
@@ -114,6 +114,7 @@ component("test_runner") {
"//cc/blink",
"//gin",
"//gpu",
+ "//gpu/command_buffer/client:gles2_interface",
"//net",
"//skia",
"//third_party/WebKit/public:blink",
@@ -200,18 +201,12 @@ group("resources") {
}
}
-if (is_mac || is_win) {
- # GYP version: components/test_runner/test_runner.gyp:layout_test_helper
+if (is_win) {
executable("layout_test_helper") {
sources = [
- "helper/layout_test_helper_mac.mm",
"helper/layout_test_helper_win.cc",
]
- if (is_mac) {
- libs = [ "AppKit.framework" ]
- }
-
deps = [
"//build/config/sanitizers:deps",
"//build/win:default_exe_manifest",
diff --git a/chromium/components/test_runner/test_runner.gyp b/chromium/components/test_runner/test_runner.gyp
deleted file mode 100644
index cc3f598b59d..00000000000
--- a/chromium/components/test_runner/test_runner.gyp
+++ /dev/null
@@ -1,224 +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.
-
-{
- 'variables': {
- # This turns on e.g. the filename-based detection of which
- # platforms to include source files on (e.g. files ending in
- # _mac.h or _mac.cc are only compiled on MacOSX).
- 'chromium_code': 1,
- },
- 'targets': [
- {
- # GN version: //components/test_runner:test_runner
- 'target_name': 'test_runner',
- 'type': '<(component)',
- 'defines': [
- 'TEST_RUNNER_IMPLEMENTATION',
- ],
- 'dependencies': [
- 'resources',
- '../../base/base.gyp:base',
- '../../base/base.gyp:base_i18n',
- '../../cc/cc.gyp:cc',
- '../../cc/blink/cc_blink.gyp:cc_blink',
- '../../gin/gin.gyp:gin',
- '../../gpu/gpu.gyp:gpu',
- '../../net/net.gyp:net',
- '../../skia/skia.gyp:skia',
- '../../third_party/WebKit/public/blink.gyp:blink',
- '../../ui/display/display.gyp:display',
- '../../ui/events/blink/events_blink.gyp:events_blink',
- '../../ui/events/events.gyp:dom_keycode_converter',
- '../../ui/events/events.gyp:events_base',
- '../../ui/gfx/gfx.gyp:gfx',
- '../../ui/gfx/gfx.gyp:gfx_geometry',
- '../../ui/gfx/gfx.gyp:gfx_test_support',
- '../../url/url.gyp:url_lib',
- '../../v8/src/v8.gyp:v8',
- ],
- 'include_dirs': [
- '..',
- ],
- # Note: sources list duplicated in GN build.
- 'sources': [
- 'accessibility_controller.cc',
- 'accessibility_controller.h',
- 'app_banner_client.cc',
- 'app_banner_client.h',
- 'event_sender.cc',
- 'event_sender.h',
- 'gamepad_controller.cc',
- 'gamepad_controller.h',
- 'gc_controller.cc',
- 'gc_controller.h',
- 'layout_and_paint_async_then.cc',
- 'layout_and_paint_async_then.h',
- 'layout_dump.cc',
- 'layout_dump.h',
- 'layout_test_runtime_flags.cc',
- 'layout_test_runtime_flags.h',
- 'mock_color_chooser.cc',
- 'mock_color_chooser.h',
- 'mock_content_settings_client.cc',
- 'mock_content_settings_client.h',
- 'mock_credential_manager_client.cc',
- 'mock_credential_manager_client.h',
- 'mock_grammar_check.cc',
- 'mock_grammar_check.h',
- 'mock_screen_orientation_client.cc',
- 'mock_screen_orientation_client.h',
- 'mock_spell_check.cc',
- 'mock_spell_check.h',
- 'mock_web_audio_device.cc',
- 'mock_web_audio_device.h',
- 'mock_web_document_subresource_filter.cc',
- 'mock_web_document_subresource_filter.h',
- 'mock_web_media_stream_center.cc',
- 'mock_web_media_stream_center.h',
- 'mock_web_midi_accessor.cc',
- 'mock_web_midi_accessor.h',
- 'mock_web_speech_recognizer.cc',
- 'mock_web_speech_recognizer.h',
- 'mock_web_theme_engine.cc',
- 'mock_web_theme_engine.h',
- 'mock_web_user_media_client.cc',
- 'mock_web_user_media_client.h',
- 'mock_webrtc_data_channel_handler.cc',
- 'mock_webrtc_data_channel_handler.h',
- 'mock_webrtc_dtmf_sender_handler.cc',
- 'mock_webrtc_dtmf_sender_handler.h',
- 'mock_webrtc_peer_connection_handler.cc',
- 'mock_webrtc_peer_connection_handler.h',
- 'pixel_dump.cc',
- 'pixel_dump.h',
- 'spell_check_client.cc',
- 'spell_check_client.h',
- 'test_common.cc',
- 'test_common.h',
- 'test_interfaces.cc',
- 'test_interfaces.h',
- 'test_plugin.cc',
- 'test_plugin.h',
- 'test_preferences.cc',
- 'test_preferences.h',
- 'test_runner.cc',
- 'test_runner.h',
- 'test_runner_export.h',
- 'test_runner_for_specific_view.cc',
- 'test_runner_for_specific_view.h',
- 'text_input_controller.cc',
- 'text_input_controller.h',
- 'tracked_dictionary.cc',
- 'tracked_dictionary.h',
- 'web_ax_object_proxy.cc',
- 'web_ax_object_proxy.h',
- 'web_frame_test_client.cc',
- 'web_frame_test_client.h',
- 'web_frame_test_proxy.cc',
- 'web_frame_test_proxy.h',
- 'web_task.cc',
- 'web_task.h',
- 'web_test_delegate.h',
- 'web_test_interfaces.cc',
- 'web_test_interfaces.h',
- 'web_test_proxy.cc',
- 'web_test_proxy.h',
- 'web_test_runner.h',
- 'web_view_test_client.cc',
- 'web_view_test_client.h',
- 'web_widget_test_client.cc',
- 'web_widget_test_client.h',
- ],
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS
- },
- },
- 'conditions': [
- ['OS=="win"', {
- 'configurations': {
- 'Debug_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'LinkIncremental': '<(msvs_large_module_debug_link_mode)',
- },
- },
- },
- },
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- }], # OS=="win"
- ],
- },
- {
- # GN version: //components/test_runner:resources
- 'target_name': 'resources',
- 'type': 'none',
- 'conditions': [
- ['OS=="win"', {
- 'copies': [{
- 'destination': '<(PRODUCT_DIR)',
- 'files': ['resources/fonts/AHEM____.TTF'],
- }],
- }],
- ['OS=="mac"', {
- 'all_dependent_settings': {
- 'mac_bundle_resources': [
- 'resources/fonts/AHEM____.TTF',
- 'resources/fonts/ChromiumAATTest.ttf',
- '<(SHARED_INTERMEDIATE_DIR)/webkit/missingImage.png',
- '<(SHARED_INTERMEDIATE_DIR)/webkit/textAreaResizeCorner.png',
- ],
- },
- }],
- ['use_x11 == 1', {
- 'copies': [{
- 'destination': '<(PRODUCT_DIR)',
- 'files': [
- 'resources/fonts/AHEM____.TTF',
- 'resources/fonts/fonts.conf',
- '../../third_party/gardiner_mod/GardinerModBug.ttf',
- '../../third_party/gardiner_mod/GardinerModCat.ttf',
- ]
- }],
- }],
- ['OS=="android"', {
- 'copies': [{
- 'destination': '<(PRODUCT_DIR)',
- 'files': [
- 'resources/fonts/AHEM____.TTF',
- 'resources/fonts/android_main_fonts.xml',
- 'resources/fonts/android_fallback_fonts.xml',
- ]
- }],
- }],
- ],
- },
- ],
- 'conditions': [
- ['OS=="mac" or OS=="win"', {
- 'targets': [
- {
- # GN version: //components/test_runner:layout_test_helper
- 'target_name': 'layout_test_helper',
- 'type': 'executable',
- 'sources': [
- 'helper/layout_test_helper_mac.mm',
- 'helper/layout_test_helper_win.cc',
- ],
- 'conditions': [
- ['OS=="mac"', {
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
- ],
- },
- }],
- ],
- },
- ],
- }], # OS=="mac" or OS=="win"
- ]
-}
diff --git a/chromium/components/timers.gypi b/chromium/components/timers.gypi
deleted file mode 100644
index 205a8021595..00000000000
--- a/chromium/components/timers.gypi
+++ /dev/null
@@ -1,23 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/timers
- 'target_name': 'timers',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'timers/alarm_timer_chromeos.cc',
- 'timers/alarm_timer_chromeos.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/toolbar.gypi b/chromium/components/toolbar.gypi
deleted file mode 100644
index 1166d46db54..00000000000
--- a/chromium/components/toolbar.gypi
+++ /dev/null
@@ -1,63 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/toolbar
- 'target_name': 'toolbar',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/gfx.gyp:gfx_vector_icons',
- '../url/url.gyp:url_lib',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- 'google_core_browser',
- 'prefs/prefs.gyp:prefs',
- 'security_state',
- 'url_formatter/url_formatter.gyp:url_formatter',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'toolbar/toolbar_model.cc',
- 'toolbar/toolbar_model.h',
- 'toolbar/toolbar_model_delegate.h',
- 'toolbar/toolbar_model_impl.cc',
- 'toolbar/toolbar_model_impl.h',
- ],
- },
- {
- # GN version: //components/toolbar:test_support
- 'target_name': 'toolbar_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../ui/gfx/gfx.gyp:gfx_vector_icons',
- 'components_resources.gyp:components_resources',
- 'toolbar',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'toolbar/test_toolbar_model.cc',
- 'toolbar/test_toolbar_model.h',
- ],
- 'conditions': [
- ['toolkit_views==1', {
- # Needed to get the TOOLKIT_VIEWS define.
- 'dependencies': [
- '<(DEPTH)/ui/views/views.gyp:views',
- ],
- }],
- ],
- },
- ],
-}
diff --git a/chromium/components/toolbar/BUILD.gn b/chromium/components/toolbar/BUILD.gn
index 67cee0f0419..18e685664d6 100644
--- a/chromium/components/toolbar/BUILD.gn
+++ b/chromium/components/toolbar/BUILD.gn
@@ -4,9 +4,8 @@
import("//build/config/ui.gni")
-source_set("toolbar") {
+static_library("toolbar") {
sources = [
- "toolbar_model.cc",
"toolbar_model.h",
"toolbar_model_delegate.h",
"toolbar_model_impl.cc",
@@ -28,7 +27,7 @@ source_set("toolbar") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
diff --git a/chromium/components/toolbar/test_toolbar_model.cc b/chromium/components/toolbar/test_toolbar_model.cc
index 6ad5b94d501..31d0f5d0b40 100644
--- a/chromium/components/toolbar/test_toolbar_model.cc
+++ b/chromium/components/toolbar/test_toolbar_model.cc
@@ -8,8 +8,7 @@
#include "ui/gfx/vector_icons_public.h"
TestToolbarModel::TestToolbarModel()
- : perform_search_term_replacement_(false),
- security_level_(security_state::SecurityStateModel::NONE),
+ : security_level_(security_state::SecurityStateModel::NONE),
#if defined(TOOLKIT_VIEWS)
icon_(gfx::VectorIconId::LOCATION_BAR_HTTP),
#else
@@ -20,10 +19,6 @@ TestToolbarModel::TestToolbarModel()
TestToolbarModel::~TestToolbarModel() {}
-base::string16 TestToolbarModel::GetText() const {
- return text_;
-}
-
base::string16 TestToolbarModel::GetFormattedURL(size_t* prefix_end) const {
return text_;
}
@@ -32,11 +27,6 @@ GURL TestToolbarModel::GetURL() const {
return url_;
}
-bool TestToolbarModel::WouldPerformSearchTermReplacement(
- bool ignore_editing) const {
- return perform_search_term_replacement_;
-}
-
security_state::SecurityStateModel::SecurityLevel
TestToolbarModel::GetSecurityLevel(bool ignore_editing) const {
return security_level_;
@@ -51,6 +41,10 @@ gfx::VectorIconId TestToolbarModel::GetVectorIcon() const {
return icon_;
}
+base::string16 TestToolbarModel::GetSecureVerboseText() const {
+ return base::string16();
+}
+
base::string16 TestToolbarModel::GetEVCertName() const {
return (security_level_ == security_state::SecurityStateModel::EV_SECURE)
? ev_cert_name_
diff --git a/chromium/components/toolbar/test_toolbar_model.h b/chromium/components/toolbar/test_toolbar_model.h
index 5e5015c98fb..108ef0be7f6 100644
--- a/chromium/components/toolbar/test_toolbar_model.h
+++ b/chromium/components/toolbar/test_toolbar_model.h
@@ -23,23 +23,18 @@ class TestToolbarModel : public ToolbarModel {
public:
TestToolbarModel();
~TestToolbarModel() override;
- base::string16 GetText() const override;
base::string16 GetFormattedURL(size_t* prefix_end) const override;
GURL GetURL() const override;
- bool WouldPerformSearchTermReplacement(bool ignore_editing) const override;
security_state::SecurityStateModel::SecurityLevel GetSecurityLevel(
bool ignore_editing) const override;
int GetIcon() const override;
gfx::VectorIconId GetVectorIcon() const override;
+ base::string16 GetSecureVerboseText() const override;
base::string16 GetEVCertName() const override;
bool ShouldDisplayURL() const override;
void set_text(const base::string16& text) { text_ = text; }
void set_url(const GURL& url) { url_ = url;}
- void set_perform_search_term_replacement(
- bool perform_search_term_replacement) {
- perform_search_term_replacement_ = perform_search_term_replacement;
- }
void set_security_level(
security_state::SecurityStateModel::SecurityLevel security_level) {
security_level_ = security_level;
@@ -55,7 +50,6 @@ class TestToolbarModel : public ToolbarModel {
private:
base::string16 text_;
GURL url_;
- bool perform_search_term_replacement_;
security_state::SecurityStateModel::SecurityLevel security_level_;
gfx::VectorIconId icon_;
base::string16 ev_cert_name_;
diff --git a/chromium/components/toolbar/toolbar_model.cc b/chromium/components/toolbar/toolbar_model.cc
deleted file mode 100644
index b7f1f2ec4d8..00000000000
--- a/chromium/components/toolbar/toolbar_model.cc
+++ /dev/null
@@ -1,18 +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 "components/toolbar/toolbar_model.h"
-
-ToolbarModel::ToolbarModel()
- : input_in_progress_(false),
- url_replacement_enabled_(true) {
-}
-
-ToolbarModel::~ToolbarModel() {
-}
-
-bool ToolbarModel::WouldReplaceURL() const {
- return WouldPerformSearchTermReplacement(false);
-}
-
diff --git a/chromium/components/toolbar/toolbar_model.h b/chromium/components/toolbar/toolbar_model.h
index afc86a9c1e9..19c60d1cb31 100644
--- a/chromium/components/toolbar/toolbar_model.h
+++ b/chromium/components/toolbar/toolbar_model.h
@@ -18,24 +18,12 @@ namespace gfx {
enum class VectorIconId;
}
-namespace net {
-class X509Certificate;
-}
-
// This class is the model used by the toolbar, location bar and autocomplete
// edit. It populates its states from the current navigation entry retrieved
// from the navigation controller returned by GetNavigationController().
class ToolbarModel {
public:
- virtual ~ToolbarModel();
-
- // Returns the text to be displayed in the toolbar for the current page.
- // This will have been formatted for display to the user.
- // - If the current page's URL is a search URL for the user's default search
- // engine, the query will be extracted and returned for display instead
- // of the URL.
- // - Otherwise, the text will contain the URL returned by GetFormattedURL().
- virtual base::string16 GetText() const = 0;
+ virtual ~ToolbarModel() = default;
// Returns a formatted URL for display in the toolbar. The formatting
// includes:
@@ -48,12 +36,6 @@ class ToolbarModel {
// Returns the URL of the current navigation entry.
virtual GURL GetURL() const = 0;
- // Returns true if a call to GetText() would successfully replace the URL
- // with search terms. If |ignore_editing| is true, the result reflects the
- // underlying state of the page without regard to any user edits that may be
- // in progress in the omnibox.
- virtual bool WouldPerformSearchTermReplacement(bool ignore_editing) const = 0;
-
// Returns the security level that the toolbar should display. If
// |ignore_editing| is true, the result reflects the underlying state of the
// page without regard to any user edits that may be in progress in the
@@ -61,10 +43,6 @@ class ToolbarModel {
virtual security_state::SecurityStateModel::SecurityLevel GetSecurityLevel(
bool ignore_editing) const = 0;
- // Returns true if a call to GetText() would return something other than the
- // URL because of search term replacement.
- bool WouldReplaceURL() const;
-
// Returns the resource_id of the icon to show to the left of the address,
// based on the current URL. When search term replacement is active, this
// returns a search icon. This doesn't cover specialized icons while the
@@ -74,6 +52,9 @@ class ToolbarModel {
// Like GetIcon(), but gets the vector asset ID.
virtual gfx::VectorIconId GetVectorIcon() const = 0;
+ // Returns text for the omnibox secure verbose chip.
+ virtual base::string16 GetSecureVerboseText() const = 0;
+
// Returns the name of the EV cert holder. This returns an empty string if
// the security level is not EV_SECURE.
virtual base::string16 GetEVCertName() const = 0;
@@ -88,20 +69,11 @@ class ToolbarModel {
}
bool input_in_progress() const { return input_in_progress_; }
- // Whether URL replacement should be enabled.
- void set_url_replacement_enabled(bool enabled) {
- url_replacement_enabled_ = enabled;
- }
- bool url_replacement_enabled() const {
- return url_replacement_enabled_;
- }
-
protected:
- ToolbarModel();
+ ToolbarModel() : input_in_progress_(false) {}
private:
bool input_in_progress_;
- bool url_replacement_enabled_;
DISALLOW_COPY_AND_ASSIGN(ToolbarModel);
};
diff --git a/chromium/components/toolbar/toolbar_model_delegate.h b/chromium/components/toolbar/toolbar_model_delegate.h
index 33f95c883d0..1fb8e83514f 100644
--- a/chromium/components/toolbar/toolbar_model_delegate.h
+++ b/chromium/components/toolbar/toolbar_model_delegate.h
@@ -40,15 +40,12 @@ class ToolbarModelDelegate {
// user edits that may be in progress.
virtual SecurityLevel GetSecurityLevel() const = 0;
- // Returns search terms as in search::GetSearchTerms() if such terms should
- // appear in the omnibox (i.e. the page is sufficiently secure, search term
- // replacement is enabled, editing is not in progress, etc.) given that the
- // page has a security level of |security_level|.
- virtual base::string16 GetSearchTerms(SecurityLevel security_level) const = 0;
-
// Returns the certificate for the current navigation entry.
virtual scoped_refptr<net::X509Certificate> GetCertificate() const = 0;
+ // Returns true if the current page fails the malware check.
+ virtual bool FailsMalwareCheck() const = 0;
+
protected:
virtual ~ToolbarModelDelegate() {}
};
diff --git a/chromium/components/toolbar/toolbar_model_impl.cc b/chromium/components/toolbar/toolbar_model_impl.cc
index f6c7410c5e0..9329852843e 100644
--- a/chromium/components/toolbar/toolbar_model_impl.cc
+++ b/chromium/components/toolbar/toolbar_model_impl.cc
@@ -34,14 +34,6 @@ ToolbarModelImpl::~ToolbarModelImpl() {
}
// ToolbarModelImpl Implementation.
-base::string16 ToolbarModelImpl::GetText() const {
- base::string16 search_terms(GetSearchTerms(false));
- if (!search_terms.empty())
- return search_terms;
-
- return GetFormattedURL(NULL);
-}
-
base::string16 ToolbarModelImpl::GetFormattedURL(size_t* prefix_end) const {
GURL url(GetURL());
// Note that we can't unescape spaces here, because if the user copies this
@@ -70,11 +62,6 @@ GURL ToolbarModelImpl::GetURL() const {
return delegate_->GetURL(&url) ? url : GURL(url::kAboutBlankURL);
}
-bool ToolbarModelImpl::WouldPerformSearchTermReplacement(
- bool ignore_editing) const {
- return !GetSearchTerms(ignore_editing).empty();
-}
-
SecurityStateModel::SecurityLevel ToolbarModelImpl::GetSecurityLevel(
bool ignore_editing) const {
// When editing or empty, assume no security style.
@@ -86,6 +73,7 @@ SecurityStateModel::SecurityLevel ToolbarModelImpl::GetSecurityLevel(
int ToolbarModelImpl::GetIcon() const {
switch (GetSecurityLevel(false)) {
case SecurityStateModel::NONE:
+ case SecurityStateModel::HTTP_SHOW_WARNING:
return IDR_LOCATION_BAR_HTTP;
case SecurityStateModel::EV_SECURE:
case SecurityStateModel::SECURE:
@@ -93,9 +81,9 @@ int ToolbarModelImpl::GetIcon() const {
case SecurityStateModel::SECURITY_WARNING:
// Surface Dubious as Neutral.
return IDR_LOCATION_BAR_HTTP;
- case SecurityStateModel::SECURITY_POLICY_WARNING:
+ case SecurityStateModel::SECURE_WITH_POLICY_INSTALLED_CERT:
return IDR_OMNIBOX_HTTPS_POLICY_WARNING;
- case SecurityStateModel::SECURITY_ERROR:
+ case SecurityStateModel::DANGEROUS:
return IDR_OMNIBOX_HTTPS_INVALID;
}
@@ -107,6 +95,7 @@ gfx::VectorIconId ToolbarModelImpl::GetVectorIcon() const {
#if !defined(OS_ANDROID) && !defined(OS_IOS)
switch (GetSecurityLevel(false)) {
case SecurityStateModel::NONE:
+ case SecurityStateModel::HTTP_SHOW_WARNING:
return gfx::VectorIconId::LOCATION_BAR_HTTP;
case SecurityStateModel::EV_SECURE:
case SecurityStateModel::SECURE:
@@ -114,9 +103,9 @@ gfx::VectorIconId ToolbarModelImpl::GetVectorIcon() const {
case SecurityStateModel::SECURITY_WARNING:
// Surface Dubious as Neutral.
return gfx::VectorIconId::LOCATION_BAR_HTTP;
- case SecurityStateModel::SECURITY_POLICY_WARNING:
+ case SecurityStateModel::SECURE_WITH_POLICY_INSTALLED_CERT:
return gfx::VectorIconId::BUSINESS;
- case SecurityStateModel::SECURITY_ERROR:
+ case SecurityStateModel::DANGEROUS:
return gfx::VectorIconId::LOCATION_BAR_HTTPS_INVALID;
}
#endif
@@ -142,13 +131,19 @@ base::string16 ToolbarModelImpl::GetEVCertName() const {
base::UTF8ToUTF16(cert->subject().country_name));
}
-bool ToolbarModelImpl::ShouldDisplayURL() const {
- return delegate_->ShouldDisplayURL();
+base::string16 ToolbarModelImpl::GetSecureVerboseText() const {
+ switch (GetSecurityLevel(false)) {
+ case SecurityStateModel::SECURE:
+ return l10n_util::GetStringUTF16(IDS_SECURE_VERBOSE_STATE);
+ case SecurityStateModel::DANGEROUS:
+ return l10n_util::GetStringUTF16(delegate_->FailsMalwareCheck()
+ ? IDS_DANGEROUS_VERBOSE_STATE
+ : IDS_NOT_SECURE_VERBOSE_STATE);
+ default:
+ return base::string16();
+ }
}
-base::string16 ToolbarModelImpl::GetSearchTerms(bool ignore_editing) const {
- if (!url_replacement_enabled() || (input_in_progress() && !ignore_editing))
- return base::string16();
-
- return delegate_->GetSearchTerms(GetSecurityLevel(ignore_editing));
+bool ToolbarModelImpl::ShouldDisplayURL() const {
+ return delegate_->ShouldDisplayURL();
}
diff --git a/chromium/components/toolbar/toolbar_model_impl.h b/chromium/components/toolbar/toolbar_model_impl.h
index 4b823f6324b..c60177ef3a4 100644
--- a/chromium/components/toolbar/toolbar_model_impl.h
+++ b/chromium/components/toolbar/toolbar_model_impl.h
@@ -17,10 +17,6 @@
class ToolbarModelDelegate;
-namespace net {
-class X509Certificate;
-}
-
// This class is the model used by the toolbar, location bar and autocomplete
// edit. It populates its states from the current navigation entry retrieved
// from the navigation controller returned by GetNavigationController().
@@ -32,23 +28,16 @@ class ToolbarModelImpl : public ToolbarModel {
private:
// ToolbarModel:
- base::string16 GetText() const override;
base::string16 GetFormattedURL(size_t* prefix_end) const override;
GURL GetURL() const override;
- bool WouldPerformSearchTermReplacement(bool ignore_editing) const override;
security_state::SecurityStateModel::SecurityLevel GetSecurityLevel(
bool ignore_editing) const override;
int GetIcon() const override;
gfx::VectorIconId GetVectorIcon() const override;
+ base::string16 GetSecureVerboseText() const override;
base::string16 GetEVCertName() const override;
bool ShouldDisplayURL() const override;
- // Returns search terms as in search::GetSearchTerms() if such terms should
- // appear in the omnibox (i.e. the page is sufficiently secure, search term
- // replacement is enabled, editing is not in progress, etc.). If
- // |ignore_editing| is true, the "editing not in progress" check is skipped.
- base::string16 GetSearchTerms(bool ignore_editing) const;
-
ToolbarModelDelegate* delegate_;
const size_t max_url_display_chars_;
diff --git a/chromium/components/tools/metrics/browser_components_metrics.py b/chromium/components/tools/metrics/browser_components_metrics.py
deleted file mode 100755
index c1f5b4b05d0..00000000000
--- a/chromium/components/tools/metrics/browser_components_metrics.py
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-"""Generates the metrics collected weekly for the Browser Components project.
-
-See
-http://www.chromium.org/developers/design-documents/browser-components
-for details.
-"""
-
-import os
-import sys
-
-
-# This is done so that we can import checkdeps. If not invoked as
-# main, our user must ensure it is in PYTHONPATH.
-if __name__ == '__main__':
- sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..',
- 'buildtools', 'checkdeps'))
-
-
-import count_ifdefs
-import checkdeps
-import results
-
-
-# Preprocessor pattern to find OS_XYZ defines.
-PREPROCESSOR_PATTERN = 'OS_[A-Z]+'
-
-
-class BrowserComponentsMetricsGenerator(object):
- def __init__(self, checkout_root):
- self.checkout_root = checkout_root
- self.chrome_browser = os.path.join(checkout_root, 'chrome', 'browser')
-
- def CountIfdefs(self, skip_tests):
- return count_ifdefs.CountIfdefs(
- PREPROCESSOR_PATTERN, self.chrome_browser, skip_tests)
-
- def CountViolations(self, skip_tests):
- deps_checker = checkdeps.DepsChecker(self.checkout_root,
- ignore_temp_rules=True,
- skip_tests=skip_tests)
- deps_checker.results_formatter = results.CountViolationsFormatter()
- deps_checker.CheckDirectory(os.path.join('chrome', 'browser'))
- return int(deps_checker.results_formatter.GetResults())
-
-
-def main():
- generator = BrowserComponentsMetricsGenerator(
- os.path.join(os.path.dirname(__file__), '..', '..', '..'))
-
- print "All metrics are for chrome/browser.\n"
- print "OS ifdefs, all: %d" % generator.CountIfdefs(False)
- print "OS ifdefs, -tests: %d" % generator.CountIfdefs(True)
- print ("Intended DEPS violations, all: %d" %
- generator.CountViolations(False))
- print "Intended DEPS violations, -tests: %d" % generator.CountViolations(True)
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/chromium/components/tools/metrics/count_ifdefs.py b/chromium/components/tools/metrics/count_ifdefs.py
deleted file mode 100755
index 2e3c2adf02d..00000000000
--- a/chromium/components/tools/metrics/count_ifdefs.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-"""Counts the number of #if or #ifdef lines containing at least one
-preprocessor token that is a full match for the given pattern, in the
-given directory.
-"""
-
-
-import optparse
-import os
-import re
-import sys
-
-
-# Filename extensions we know will be handled by the C preprocessor.
-# We ignore files not matching these.
-CPP_EXTENSIONS = [
- '.h',
- '.cc',
- '.m',
- '.mm',
-]
-
-
-def _IsTestFile(filename):
- """Does a rudimentary check to try to skip test files; this could be
- improved but is good enough for basic metrics generation.
- """
- return re.match('(test|mock|dummy)_.*|.*_[a-z]*test\.(h|cc|mm)', filename)
-
-
-def CountIfdefs(token_pattern, directory, skip_tests=False):
- """Returns the number of lines in files in |directory| and its
- subdirectories that have an extension from |CPP_EXTENSIONS| and are
- an #if or #ifdef line with a preprocessor token fully matching
- the string |token_pattern|.
-
- If |skip_tests| is true, a best effort is made to ignore test files.
- """
- token_line_re = re.compile(r'^#if(def)?.*\b(%s)\b.*$' % token_pattern)
- count = 0
- for root, dirs, files in os.walk(directory):
- for filename in files:
- if os.path.splitext(filename)[1] in CPP_EXTENSIONS:
- if not skip_tests or not _IsTestFile(filename):
- with open(os.path.join(root, filename)) as f:
- for line in f:
- line = line.strip()
- if token_line_re.match(line):
- count += 1
- return count
-
-
-def PrintUsage():
- print "Usage: %s [--skip-tests] TOKEN_PATTERN DIRECTORY" % sys.argv[0]
-
-
-def main():
- option_parser = optparse.OptionParser()
- option_parser.add_option('', '--skip-tests', action='store_true',
- dest='skip_tests', default=False,
- help='Skip test files.')
- options, args = option_parser.parse_args()
-
- if len(args) < 2:
- PrintUsage()
- return 1
- else:
- print CountIfdefs(args[0], args[1], options.skip_tests)
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/chromium/components/tools/metrics/count_ifdefs_unittest.py b/chromium/components/tools/metrics/count_ifdefs_unittest.py
deleted file mode 100755
index 9b8c3229a0f..00000000000
--- a/chromium/components/tools/metrics/count_ifdefs_unittest.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-"""Tests for count_ifdefs.
-"""
-
-import os
-import unittest
-
-import count_ifdefs
-
-
-class CountIfdefsTest(unittest.TestCase):
-
- def setUp(self):
- self.root = os.path.join(os.path.dirname(__file__), 'testdata')
-
- def testNormal(self):
- count = count_ifdefs.CountIfdefs('OS_[A-Z]+', self.root)
- self.failUnless(count == 6)
-
- def testSkipTests(self):
- count = count_ifdefs.CountIfdefs('OS_[A-Z]+', self.root, True)
- self.failUnless(count == 4)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/chromium/components/tracing.gyp b/chromium/components/tracing.gyp
deleted file mode 100644
index 91071d657e6..00000000000
--- a/chromium/components/tracing.gyp
+++ /dev/null
@@ -1,60 +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.
-
-# This file is intentionally a gyp file rather than a gypi for dependencies
-# reasons. The other gypi files include content.gyp and content_common depends
-# on this, thus if you try to rename this to gypi and include it in
-# components.gyp, you will get a circular dependency error.
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets' : [
- {
- 'target_name': 'tracing',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../ipc/ipc.gyp:ipc',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'TRACING_IMPLEMENTATION=1',
- ],
- 'sources': [
- 'tracing/browser/trace_config_file.cc',
- 'tracing/browser/trace_config_file.h',
- 'tracing/child/child_memory_dump_manager_delegate_impl.cc',
- 'tracing/child/child_memory_dump_manager_delegate_impl.h',
- 'tracing/child/child_trace_message_filter.cc',
- 'tracing/child/child_trace_message_filter.h',
- 'tracing/common/graphics_memory_dump_provider_android.cc',
- 'tracing/common/graphics_memory_dump_provider_android.h',
- 'tracing/common/process_metrics_memory_dump_provider.cc',
- 'tracing/common/process_metrics_memory_dump_provider.h',
- 'tracing/common/trace_to_console.cc',
- 'tracing/common/trace_to_console.h',
- 'tracing/common/tracing_messages.cc',
- 'tracing/common/tracing_messages.h',
- 'tracing/common/tracing_switches.cc',
- 'tracing/common/tracing_switches.h',
- 'tracing/core/scattered_stream_writer.cc',
- 'tracing/core/scattered_stream_writer.h',
- 'tracing/core/trace_ring_buffer.cc',
- 'tracing/core/trace_ring_buffer.h',
- 'tracing/tracing_export.h',
- ],
- 'target_conditions': [
- ['>(nacl_untrusted_build)==1', {
- 'sources!': [
- 'tracing/common/process_metrics_memory_dump_provider.cc',
- ],
- }],
- ]
- },
- ],
-}
diff --git a/chromium/components/tracing/BUILD.gn b/chromium/components/tracing/BUILD.gn
index ea3ea2ee927..0d5109701b8 100644
--- a/chromium/components/tracing/BUILD.gn
+++ b/chromium/components/tracing/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//third_party/protobuf/proto_library.gni")
+
component("tracing") {
sources = [
"child/child_memory_dump_manager_delegate_impl.cc",
@@ -14,8 +16,16 @@ component("tracing") {
"common/process_metrics_memory_dump_provider.h",
"common/tracing_messages.cc",
"common/tracing_messages.h",
+ "core/proto_utils.cc",
+ "core/proto_utils.h",
+ "core/proto_zero_message.cc",
+ "core/proto_zero_message.h",
+ "core/proto_zero_message_handle.cc",
+ "core/proto_zero_message_handle.h",
"core/scattered_stream_writer.cc",
"core/scattered_stream_writer.h",
+ "core/trace_buffer_writer.cc",
+ "core/trace_buffer_writer.h",
"core/trace_ring_buffer.cc",
"core/trace_ring_buffer.h",
"tracing_export.h",
@@ -28,6 +38,10 @@ component("tracing") {
"//ipc",
]
+ public_deps = [
+ "//components/tracing/proto:protos",
+ ]
+
if (is_nacl) {
sources -= [ "common/process_metrics_memory_dump_provider.cc" ]
}
@@ -51,6 +65,26 @@ component("startup_tracing") {
]
}
+# For unit testing of generated stubs.
+proto_library("proto_zero_testing_messages") {
+ visibility = [ "//components/tracing/*" ]
+
+ sources = [
+ "test/example_proto/library.proto",
+ "test/example_proto/library_internals/galaxies.proto",
+ "test/example_proto/test_messages.proto",
+ "test/example_proto/upper_import.proto",
+ ]
+
+ proto_in_dir = "test/example_proto"
+
+ generator_plugin_label = "tools/proto_zero_plugin:proto_zero_plugin"
+ generator_plugin_suffix = ".pbzero"
+ generator_plugin_options = "wrapper_namespace=pbzero"
+ generate_cc = true
+ generate_python = false
+}
+
source_set("unit_tests") {
testonly = true
@@ -58,13 +92,20 @@ source_set("unit_tests") {
"child/child_trace_message_filter_unittest.cc",
"common/graphics_memory_dump_provider_android_unittest.cc",
"common/process_metrics_memory_dump_provider_unittest.cc",
+ "core/proto_utils_unittest.cc",
+ "core/proto_zero_message_unittest.cc",
"core/scattered_stream_writer_unittest.cc",
+ "core/trace_buffer_writer_unittest.cc",
"core/trace_ring_buffer_unittest.cc",
+ "test/fake_scattered_buffer.cc",
+ "test/proto_zero_generation_unittest.cc",
]
deps = [
+ ":proto_zero_testing_messages",
":tracing",
"//base/test:test_support",
+ "//components/tracing/proto:golden_protos_for_tests",
"//ipc",
"//testing/gmock:gmock",
"//testing/gtest",
diff --git a/chromium/components/tracing/OWNERS b/chromium/components/tracing/OWNERS
index aef4aa6236e..1d9100e7b8d 100644
--- a/chromium/components/tracing/OWNERS
+++ b/chromium/components/tracing/OWNERS
@@ -1,6 +1,2 @@
-dsinclair@chromium.org
+file://base/trace_event/OWNERS
jbauman@chromium.org
-nduca@chromium.org
-oysteine@chromium.org
-primiano@chromium.org
-simonhatch@chromium.org
diff --git a/chromium/components/tracing/browser/trace_config_file_unittest.cc b/chromium/components/tracing/browser/trace_config_file_unittest.cc
index e8e00e82c0d..887437c6c33 100644
--- a/chromium/components/tracing/browser/trace_config_file_unittest.cc
+++ b/chromium/components/tracing/browser/trace_config_file_unittest.cc
@@ -108,7 +108,7 @@ TEST(TraceConfigFileTest, ValidContent) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
ASSERT_TRUE(
- base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ base::CreateTemporaryFileInDir(temp_dir.GetPath(), &trace_config_file));
ASSERT_NE(-1, base::WriteFile(
trace_config_file, content.c_str(), (int)content.length()));
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
@@ -131,7 +131,7 @@ TEST(TraceConfigFileTest, ValidContentWithOnlyTraceConfig) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
ASSERT_TRUE(
- base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ base::CreateTemporaryFileInDir(temp_dir.GetPath(), &trace_config_file));
ASSERT_NE(-1, base::WriteFile(
trace_config_file, content.c_str(), (int)content.length()));
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
@@ -152,7 +152,7 @@ TEST(TraceConfigFileTest, ContentWithAbsoluteResultFilePath) {
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
const base::FilePath result_file_path =
- temp_dir.path().Append(FILE_PATH_LITERAL("trace_result_file.log"));
+ temp_dir.GetPath().Append(FILE_PATH_LITERAL("trace_result_file.log"));
ASSERT_TRUE(result_file_path.IsAbsolute());
std::string result_file_path_str = result_file_path.AsUTF8Unsafe();
@@ -167,7 +167,7 @@ TEST(TraceConfigFileTest, ContentWithAbsoluteResultFilePath) {
base::FilePath trace_config_file;
ASSERT_TRUE(
- base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ base::CreateTemporaryFileInDir(temp_dir.GetPath(), &trace_config_file));
ASSERT_NE(-1, base::WriteFile(
trace_config_file, content.c_str(), (int)content.length()));
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
@@ -185,7 +185,7 @@ TEST(TraceConfigFileTest, ContentWithNegtiveDuration) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
ASSERT_TRUE(
- base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ base::CreateTemporaryFileInDir(temp_dir.GetPath(), &trace_config_file));
ASSERT_NE(-1, base::WriteFile(
trace_config_file, content.c_str(), (int)content.length()));
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
@@ -209,7 +209,7 @@ TEST(TraceConfigFileTest, ContentWithoutTraceConfig) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
ASSERT_TRUE(
- base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ base::CreateTemporaryFileInDir(temp_dir.GetPath(), &trace_config_file));
ASSERT_NE(-1, base::WriteFile(
trace_config_file, content.c_str(), (int)content.length()));
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
@@ -226,7 +226,7 @@ TEST(TraceConfigFileTest, InvalidContent) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
ASSERT_TRUE(
- base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ base::CreateTemporaryFileInDir(temp_dir.GetPath(), &trace_config_file));
ASSERT_NE(-1, base::WriteFile(
trace_config_file, content.c_str(), (int)content.length()));
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
@@ -241,7 +241,7 @@ TEST(TraceConfigFileTest, EmptyContent) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
ASSERT_TRUE(
- base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ base::CreateTemporaryFileInDir(temp_dir.GetPath(), &trace_config_file));
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
switches::kTraceConfigFile, trace_config_file);
diff --git a/chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.cc b/chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.cc
index 20078e7c32e..f0c4517b2ea 100644
--- a/chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.cc
+++ b/chromium/components/tracing/child/child_memory_dump_manager_delegate_impl.cc
@@ -37,7 +37,7 @@ ChildMemoryDumpManagerDelegateImpl::~ChildMemoryDumpManagerDelegateImpl() {}
void ChildMemoryDumpManagerDelegateImpl::SetChildTraceMessageFilter(
ChildTraceMessageFilter* ctmf) {
- const auto& task_runner = ctmf ? (ctmf->ipc_task_runner()) : nullptr;
+ auto* task_runner = ctmf ? (ctmf->ipc_task_runner()) : nullptr;
// Check that we are either registering the CTMF or tearing it down, but not
// replacing a valid instance with another one (should never happen).
DCHECK(!ctmf_ || (!ctmf && ctmf_task_runner_));
diff --git a/chromium/components/tracing/child/child_trace_message_filter.cc b/chromium/components/tracing/child/child_trace_message_filter.cc
index 0a7ecd06294..8c04aa2aad6 100644
--- a/chromium/components/tracing/child/child_trace_message_filter.cc
+++ b/chromium/components/tracing/child/child_trace_message_filter.cc
@@ -30,8 +30,8 @@ ChildTraceMessageFilter::ChildTraceMessageFilter(
pending_memory_dump_guid_(0) {
}
-void ChildTraceMessageFilter::OnFilterAdded(IPC::Sender* sender) {
- sender_ = sender;
+void ChildTraceMessageFilter::OnFilterAdded(IPC::Channel* channel) {
+ sender_ = channel;
sender_->Send(new TracingHostMsg_ChildSupportsTracing());
ChildMemoryDumpManagerDelegateImpl::GetInstance()->SetChildTraceMessageFilter(
this);
diff --git a/chromium/components/tracing/child/child_trace_message_filter.h b/chromium/components/tracing/child/child_trace_message_filter.h
index 3f189b6811f..287abd3503d 100644
--- a/chromium/components/tracing/child/child_trace_message_filter.h
+++ b/chromium/components/tracing/child/child_trace_message_filter.h
@@ -29,7 +29,7 @@ class TRACING_EXPORT ChildTraceMessageFilter : public IPC::MessageFilter {
base::SingleThreadTaskRunner* ipc_task_runner);
// IPC::MessageFilter implementation.
- void OnFilterAdded(IPC::Sender* sender) override;
+ void OnFilterAdded(IPC::Channel* channel) override;
void OnFilterRemoved() override;
bool OnMessageReceived(const IPC::Message& message) override;
diff --git a/chromium/components/tracing/child/child_trace_message_filter_unittest.cc b/chromium/components/tracing/child/child_trace_message_filter_unittest.cc
index 8a7ccec7e4e..4a090dd91ed 100644
--- a/chromium/components/tracing/child/child_trace_message_filter_unittest.cc
+++ b/chromium/components/tracing/child/child_trace_message_filter_unittest.cc
@@ -8,6 +8,7 @@
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_macros.h"
#include "base/run_loop.h"
#include "components/tracing/common/tracing_messages.h"
#include "ipc/ipc_message.h"
diff --git a/chromium/components/tracing/common/graphics_memory_dump_provider_android_unittest.cc b/chromium/components/tracing/common/graphics_memory_dump_provider_android_unittest.cc
index 6b67383467a..5416b2ced24 100644
--- a/chromium/components/tracing/common/graphics_memory_dump_provider_android_unittest.cc
+++ b/chromium/components/tracing/common/graphics_memory_dump_provider_android_unittest.cc
@@ -15,12 +15,12 @@ TEST(GraphicsMemoryDumpProviderTest, ParseResponse) {
base::trace_event::ProcessMemoryDump pmd(
nullptr, {base::trace_event::MemoryDumpLevelOfDetail::DETAILED});
- auto instance = GraphicsMemoryDumpProvider::GetInstance();
+ auto* instance = GraphicsMemoryDumpProvider::GetInstance();
char buf[] = "graphics_total 12\ngraphics_pss 34\ngl_total 56\ngl_pss 78";
instance->ParseResponseAndAddToDump(buf, strlen(buf), &pmd);
// Check the "graphics" row.
- auto mad = pmd.GetAllocatorDump(kDumpBaseName + std::string("graphics"));
+ auto* mad = pmd.GetAllocatorDump(kDumpBaseName + std::string("graphics"));
ASSERT_TRUE(mad);
std::string json;
mad->attributes_for_testing()->AppendAsTraceFormat(&json);
diff --git a/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc b/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc
index 100eacf9fad..d2c00c347f0 100644
--- a/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc
+++ b/chromium/components/tracing/common/process_metrics_memory_dump_provider.cc
@@ -160,16 +160,14 @@ uint32_t ReadLinuxProcSmapsFile(FILE* smaps_file,
std::unique_ptr<base::ProcessMetrics> CreateProcessMetrics(
base::ProcessId process) {
if (process == base::kNullProcessId)
- return base::WrapUnique(
- base::ProcessMetrics::CreateCurrentProcessMetrics());
+ return base::ProcessMetrics::CreateCurrentProcessMetrics();
#if defined(OS_LINUX) || defined(OS_ANDROID)
// Just pass ProcessId instead of handle since they are the same in linux and
// android.
- return base::WrapUnique(base::ProcessMetrics::CreateProcessMetrics(process));
+ return base::ProcessMetrics::CreateProcessMetrics(process);
#else
// Creating process metrics for child processes in mac or windows requires
- // additional information like ProcessHandle or port provider. This is a non
- // needed use case.
+ // additional information like ProcessHandle or port provider.
NOTREACHED();
return std::unique_ptr<base::ProcessMetrics>();
#endif // defined(OS_LINUX) || defined(OS_ANDROID)
diff --git a/chromium/components/tracing/core/proto_utils.cc b/chromium/components/tracing/core/proto_utils.cc
new file mode 100644
index 00000000000..8e80d31c506
--- /dev/null
+++ b/chromium/components/tracing/core/proto_utils.cc
@@ -0,0 +1,89 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/tracing/core/proto_utils.h"
+
+#include <limits>
+
+#include "base/sys_byteorder.h"
+
+#define CHECK_PTR_LE(a, b) \
+ CHECK_LE(reinterpret_cast<const void*>(a), reinterpret_cast<const void*>(b))
+namespace tracing {
+namespace v2 {
+namespace proto {
+
+const uint8_t* ParseVarInt(const uint8_t* start,
+ const uint8_t* end,
+ uint64_t* value) {
+ const uint8_t* pos = start;
+ uint64_t shift = 0;
+ *value = 0;
+ do {
+ CHECK_PTR_LE(pos, end - 1);
+ DCHECK_LT(shift, 64ull);
+ *value |= static_cast<uint64_t>(*pos & 0x7f) << shift;
+ shift += 7;
+ } while (*pos++ & 0x80);
+ return pos;
+}
+
+const uint8_t* ParseField(const uint8_t* start,
+ const uint8_t* end,
+ uint32_t* field_id,
+ FieldType* field_type,
+ uint64_t* field_intvalue) {
+ // The first byte of a proto field is structured as follows:
+ // The least 3 significant bits determine the field type.
+ // The most 5 significant bits determine the field id. If MSB == 1, the
+ // field id continues on the next bytes following the VarInt encoding.
+ const uint8_t kFieldTypeNumBits = 3;
+ const uint8_t kFieldTypeMask = (1 << kFieldTypeNumBits) - 1; // 0000 0111;
+
+ const uint8_t* pos = start;
+ CHECK_PTR_LE(pos, end - 1);
+ *field_type = static_cast<FieldType>(*pos & kFieldTypeMask);
+
+ uint64_t raw_field_id;
+ pos = ParseVarInt(pos, end, &raw_field_id);
+ raw_field_id >>= kFieldTypeNumBits;
+
+ DCHECK_LE(raw_field_id, std::numeric_limits<uint32_t>::max());
+ *field_id = static_cast<uint32_t>(raw_field_id);
+
+ switch (*field_type) {
+ case kFieldTypeFixed64: {
+ CHECK_PTR_LE(pos + sizeof(uint64_t), end);
+ memcpy(field_intvalue, pos, sizeof(uint64_t));
+ *field_intvalue = base::ByteSwapToLE64(*field_intvalue);
+ pos += sizeof(uint64_t);
+ break;
+ }
+ case kFieldTypeFixed32: {
+ CHECK_PTR_LE(pos + sizeof(uint32_t), end);
+ uint32_t tmp;
+ memcpy(&tmp, pos, sizeof(uint32_t));
+ *field_intvalue = base::ByteSwapToLE32(tmp);
+ pos += sizeof(uint32_t);
+ break;
+ }
+ case kFieldTypeVarInt: {
+ pos = ParseVarInt(pos, end, field_intvalue);
+ break;
+ }
+ case kFieldTypeLengthDelimited: {
+ pos = ParseVarInt(pos, end, field_intvalue);
+ pos += *field_intvalue;
+ CHECK_PTR_LE(pos, end);
+ break;
+ }
+ default:
+ NOTREACHED() << "Unsupported proto field type " << *field_type;
+ }
+ return pos;
+}
+
+} // namespace proto
+} // namespace v2
+} // namespace tracing
diff --git a/chromium/components/tracing/core/proto_utils.h b/chromium/components/tracing/core/proto_utils.h
new file mode 100644
index 00000000000..79c89e00855
--- /dev/null
+++ b/chromium/components/tracing/core/proto_utils.h
@@ -0,0 +1,182 @@
+// 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 COMPONENTS_TRACING_CORE_PROTO_UTILS_H_
+#define COMPONENTS_TRACING_CORE_PROTO_UTILS_H_
+
+#include <inttypes.h>
+
+#include <type_traits>
+
+#include "base/logging.h"
+#include "components/tracing/tracing_export.h"
+
+namespace tracing {
+namespace v2 {
+namespace proto {
+
+// See https://developers.google.com/protocol-buffers/docs/encoding wire types.
+
+enum FieldType : uint32_t {
+ kFieldTypeVarInt = 0,
+ kFieldTypeFixed64 = 1,
+ kFieldTypeLengthDelimited = 2,
+ kFieldTypeFixed32 = 5,
+};
+
+class ProtoFieldDescriptor {
+ public:
+ enum Type {
+ TYPE_INVALID = 0,
+ TYPE_DOUBLE = 1,
+ TYPE_FLOAT = 2,
+ TYPE_INT64 = 3,
+ TYPE_UINT64 = 4,
+ TYPE_INT32 = 5,
+ TYPE_FIXED64 = 6,
+ TYPE_FIXED32 = 7,
+ TYPE_BOOL = 8,
+ TYPE_STRING = 9,
+ TYPE_MESSAGE = 11,
+ // TYPE_GROUP = 10 is not supported.
+ TYPE_BYTES = 12,
+ TYPE_UINT32 = 13,
+ TYPE_ENUM = 14,
+ TYPE_SFIXED32 = 15,
+ TYPE_SFIXED64 = 16,
+ TYPE_SINT32 = 17,
+ TYPE_SINT64 = 18,
+ };
+
+ ProtoFieldDescriptor(const char* name,
+ Type type,
+ uint32_t number,
+ bool is_repeated)
+ : name_(name), type_(type), number_(number), is_repeated_(is_repeated) {
+ }
+
+ const char* name() const {
+ return name_;
+ }
+
+ Type type() const {
+ return type_;
+ }
+
+ uint32_t number() const {
+ return number_;
+ }
+
+ bool is_repeated() const {
+ return is_repeated_;
+ }
+
+ bool is_valid() const {
+ return type_ != Type::TYPE_INVALID;
+ }
+
+ private:
+ const char* const name_;
+ const Type type_;
+ const uint32_t number_;
+ const bool is_repeated_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProtoFieldDescriptor);
+};
+
+// Maximum message size supported: 256 MiB (4 x 7-bit due to varint encoding).
+constexpr size_t kMessageLengthFieldSize = 4;
+constexpr size_t kMaxMessageLength = (1u << (kMessageLengthFieldSize * 7)) - 1;
+
+// Field tag is encoded as 32-bit varint (5 bytes at most).
+// Largest value of simple (not length-delimited) field is 64-bit varint
+// (10 bytes at most). 15 bytes buffer is enough to store a simple field.
+constexpr size_t kMaxTagEncodedSize = 5;
+constexpr size_t kMaxSimpleFieldEncodedSize = kMaxTagEncodedSize + 10;
+
+// Proto types: (int|uint|sint)(32|64), bool, enum.
+constexpr uint32_t MakeTagVarInt(uint32_t field_id) {
+ return (field_id << 3) | kFieldTypeVarInt;
+}
+
+// Proto types: fixed64, sfixed64, fixed32, sfixed32, double, float.
+template <typename T>
+constexpr uint32_t MakeTagFixed(uint32_t field_id) {
+ static_assert(sizeof(T) == 8 || sizeof(T) == 4, "Value must be 4 or 8 bytes");
+ return (field_id << 3) |
+ (sizeof(T) == 8 ? kFieldTypeFixed64 : kFieldTypeFixed32);
+}
+
+// Proto types: string, bytes, embedded messages.
+constexpr uint32_t MakeTagLengthDelimited(uint32_t field_id) {
+ return (field_id << 3) | kFieldTypeLengthDelimited;
+}
+
+// Proto tipes: sint64, sint32.
+template <typename T>
+inline typename std::make_unsigned<T>::type ZigZagEncode(T value) {
+ return (value << 1) ^ (value >> (sizeof(T) * 8 - 1));
+}
+
+template <typename T>
+inline uint8_t* WriteVarInt(T value, uint8_t* target) {
+ // Avoid arithmetic (sign expanding) shifts.
+ typedef typename std::make_unsigned<T>::type unsigned_T;
+ unsigned_T unsigned_value = static_cast<unsigned_T>(value);
+
+ while (unsigned_value >= 0x80) {
+ *target++ = static_cast<uint8_t>(unsigned_value) | 0x80;
+ unsigned_value >>= 7;
+ }
+ *target = static_cast<uint8_t>(unsigned_value);
+ return target + 1;
+}
+
+// Writes a fixed-size redundant encoding of the given |value|. This is
+// used to backfill fixed-size reservations for the length field using a
+// non-canonical varint encoding (e.g. \x81\x80\x80\x00 instead of \x01).
+// See https://github.com/google/protobuf/issues/1530.
+// In particular, this is used for nested messages. The size of a nested message
+// is not known until all its field have been written. |kMessageLengthFieldSize|
+// bytes are reserved to encode the size field and backfilled at the end.
+inline void WriteRedundantVarInt(uint32_t value, uint8_t* buf) {
+ for (size_t i = 0; i < kMessageLengthFieldSize; ++i) {
+ const uint8_t msb = (i < kMessageLengthFieldSize - 1) ? 0x80 : 0;
+ buf[i] = static_cast<uint8_t>(value) | msb;
+ value >>= 7;
+ }
+ DCHECK_EQ(0u, value) << "Message is too long";
+}
+
+template <uint32_t field_id>
+void StaticAssertSingleBytePreamble() {
+ static_assert(field_id < 16,
+ "Proto field id too big to fit in a single byte preamble");
+};
+
+// Parses a VarInt from the encoded buffer [start, end). |end| is STL-style and
+// points one byte past the end of buffer.
+// The parsed int value is stored in the output arg |value|. Returns a pointer
+// to the next unconsumed byte (so start < retval <= end).
+TRACING_EXPORT const uint8_t* ParseVarInt(const uint8_t* start,
+ const uint8_t* end,
+ uint64_t* value);
+
+// Parses a protobuf field and computes its id, type and value.
+// Returns a pointer to the next unconsumed byte (|start| < retval <= end) that
+// is either the beginning of the next field or the end of the parent message.
+// In the case of a kFieldTypeLengthDelimited field, |field_intvalue| will store
+// the length of the payload (either a string or a nested message). In this
+// case, the start of the payload will be at (return value) - |field_intvalue|.
+TRACING_EXPORT const uint8_t* ParseField(const uint8_t* start,
+ const uint8_t* end,
+ uint32_t* field_id,
+ FieldType* field_type,
+ uint64_t* field_intvalue);
+
+} // namespace proto
+} // namespace v2
+} // namespace tracing
+
+#endif // COMPONENTS_TRACING_CORE_PROTO_UTILS_H_
diff --git a/chromium/components/tracing/core/proto_utils_unittest.cc b/chromium/components/tracing/core/proto_utils_unittest.cc
new file mode 100644
index 00000000000..5d6ce183917
--- /dev/null
+++ b/chromium/components/tracing/core/proto_utils_unittest.cc
@@ -0,0 +1,192 @@
+// 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 "components/tracing/core/proto_utils.h"
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace tracing {
+namespace v2 {
+namespace proto {
+namespace {
+
+struct VarIntExpectation {
+ const char* encoded;
+ size_t encoded_size;
+ uint64_t int_value;
+};
+
+const VarIntExpectation kVarIntExpectations[] = {
+ {"\x00", 1, 0},
+ {"\x01", 1, 0x1},
+ {"\x7f", 1, 0x7F},
+ {"\xFF\x01", 2, 0xFF},
+ {"\xFF\x7F", 2, 0x3FFF},
+ {"\x80\x80\x01", 3, 0x4000},
+ {"\xFF\xFF\x7F", 3, 0x1FFFFF},
+ {"\x80\x80\x80\x01", 4, 0x200000},
+ {"\xFF\xFF\xFF\x7F", 4, 0xFFFFFFF},
+ {"\x80\x80\x80\x80\x01", 5, 0x10000000},
+ {"\xFF\xFF\xFF\xFF\x0F", 5, 0xFFFFFFFF},
+ {"\x80\x80\x80\x80\x10", 5, 0x100000000},
+ {"\xFF\xFF\xFF\xFF\x7F", 5, 0x7FFFFFFFF},
+ {"\x80\x80\x80\x80\x80\x01", 6, 0x800000000},
+ {"\xFF\xFF\xFF\xFF\xFF\x7F", 6, 0x3FFFFFFFFFF},
+ {"\x80\x80\x80\x80\x80\x80\x01", 7, 0x40000000000},
+ {"\xFF\xFF\xFF\xFF\xFF\xFF\x7F", 7, 0x1FFFFFFFFFFFF},
+ {"\x80\x80\x80\x80\x80\x80\x80\x01", 8, 0x2000000000000},
+ {"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F", 8, 0xFFFFFFFFFFFFFF},
+ {"\x80\x80\x80\x80\x80\x80\x80\x80\x01", 9, 0x100000000000000},
+ {"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F", 9, 0x7FFFFFFFFFFFFFFF},
+ {"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", 10, 0x8000000000000000},
+ {"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01", 10, 0xFFFFFFFFFFFFFFFF},
+};
+
+struct FieldExpectation {
+ const char* encoded;
+ size_t encoded_size;
+ uint32_t id;
+ FieldType type;
+ uint64_t int_value;
+};
+
+const FieldExpectation kFieldExpectations[] = {
+ {"\x08\x00", 2, 1, kFieldTypeVarInt, 0},
+ {"\x08\x42", 2, 1, kFieldTypeVarInt, 0x42},
+ {"\xF8\x07\x42", 3, 127, kFieldTypeVarInt, 0x42},
+ {"\x90\x4D\xFF\xFF\xFF\xFF\x0F", 7, 1234, kFieldTypeVarInt, 0xFFFFFFFF},
+ {"\x7D\x42\x00\x00\x00", 5, 15, kFieldTypeFixed32, 0x42},
+ {"\x95\x4D\x78\x56\x34\x12", 6, 1234, kFieldTypeFixed32, 0x12345678},
+ {"\x79\x42\x00\x00\x00\x00\x00\x00\x00", 9, 15, kFieldTypeFixed64, 0x42},
+ {"\x91\x4D\x08\x07\x06\x05\x04\x03\x02\x01", 10, 1234, kFieldTypeFixed64,
+ 0x0102030405060708},
+ {"\x0A\x00", 2, 1, kFieldTypeLengthDelimited, 0},
+ {"\x0A\x04|abc", 6, 1, kFieldTypeLengthDelimited, 4},
+ {"\x92\x4D\x04|abc", 7, 1234, kFieldTypeLengthDelimited, 4},
+ {"\x92\x4D\x83\x01|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd"
+ "efghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx",
+ 135, 1234, kFieldTypeLengthDelimited, 131},
+};
+
+TEST(ProtoUtilsTest, FieldPreambleEncoding) {
+ // According to C++ standard, right shift of negative value has
+ // implementation-defined resulting value.
+ if ((static_cast<int32_t>(0x80000000u) >> 31) != -1)
+ FAIL() << "Platform has unsupported negative number format or arithmetic";
+
+ EXPECT_EQ(0x08u, MakeTagVarInt(1));
+ EXPECT_EQ(0x09u, MakeTagFixed<uint64_t>(1));
+ EXPECT_EQ(0x0Au, MakeTagLengthDelimited(1));
+ EXPECT_EQ(0x0Du, MakeTagFixed<uint32_t>(1));
+
+ EXPECT_EQ(0x03F8u, MakeTagVarInt(0x7F));
+ EXPECT_EQ(0x03F9u, MakeTagFixed<int64_t>(0x7F));
+ EXPECT_EQ(0x03FAu, MakeTagLengthDelimited(0x7F));
+ EXPECT_EQ(0x03FDu, MakeTagFixed<int32_t>(0x7F));
+
+ EXPECT_EQ(0x0400u, MakeTagVarInt(0x80));
+ EXPECT_EQ(0x0401u, MakeTagFixed<double>(0x80));
+ EXPECT_EQ(0x0402u, MakeTagLengthDelimited(0x80));
+ EXPECT_EQ(0x0405u, MakeTagFixed<float>(0x80));
+
+ EXPECT_EQ(0x01FFF8u, MakeTagVarInt(0x3fff));
+ EXPECT_EQ(0x01FFF9u, MakeTagFixed<int64_t>(0x3fff));
+ EXPECT_EQ(0x01FFFAu, MakeTagLengthDelimited(0x3fff));
+ EXPECT_EQ(0x01FFFDu, MakeTagFixed<int32_t>(0x3fff));
+
+ EXPECT_EQ(0x020000u, MakeTagVarInt(0x4000));
+ EXPECT_EQ(0x020001u, MakeTagFixed<int64_t>(0x4000));
+ EXPECT_EQ(0x020002u, MakeTagLengthDelimited(0x4000));
+ EXPECT_EQ(0x020005u, MakeTagFixed<int32_t>(0x4000));
+}
+
+TEST(ProtoUtilsTest, ZigZagEncoding) {
+ EXPECT_EQ(0u, ZigZagEncode(0));
+ EXPECT_EQ(1u, ZigZagEncode(-1));
+ EXPECT_EQ(2u, ZigZagEncode(1));
+ EXPECT_EQ(3u, ZigZagEncode(-2));
+ EXPECT_EQ(4294967293u, ZigZagEncode(-2147483647));
+ EXPECT_EQ(4294967294u, ZigZagEncode(2147483647));
+ EXPECT_EQ(std::numeric_limits<uint32_t>::max(),
+ ZigZagEncode(std::numeric_limits<int32_t>::min()));
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
+ ZigZagEncode(std::numeric_limits<int64_t>::min()));
+}
+
+TEST(ProtoUtilsTest, VarIntEncoding) {
+ for (size_t i = 0; i < arraysize(kVarIntExpectations); ++i) {
+ const VarIntExpectation& exp = kVarIntExpectations[i];
+ uint8_t buf[32];
+ uint8_t* res = WriteVarInt<uint64_t>(exp.int_value, buf);
+ ASSERT_EQ(exp.encoded_size, static_cast<size_t>(res - buf));
+ ASSERT_EQ(0, memcmp(buf, exp.encoded, exp.encoded_size));
+
+ if (exp.int_value <= std::numeric_limits<uint32_t>::max()) {
+ uint8_t* res = WriteVarInt<uint32_t>(exp.int_value, buf);
+ ASSERT_EQ(exp.encoded_size, static_cast<size_t>(res - buf));
+ ASSERT_EQ(0, memcmp(buf, exp.encoded, exp.encoded_size));
+ }
+ }
+}
+
+TEST(ProtoUtilsTest, RedundantVarIntEncoding) {
+ uint8_t buf[kMessageLengthFieldSize];
+
+ WriteRedundantVarInt(0, buf);
+ EXPECT_EQ(0, memcmp("\x80\x80\x80\x00", buf, sizeof(buf)));
+
+ WriteRedundantVarInt(1, buf);
+ EXPECT_EQ(0, memcmp("\x81\x80\x80\x00", buf, sizeof(buf)));
+
+ WriteRedundantVarInt(0x80, buf);
+ EXPECT_EQ(0, memcmp("\x80\x81\x80\x00", buf, sizeof(buf)));
+
+ WriteRedundantVarInt(0x332211, buf);
+ EXPECT_EQ(0, memcmp("\x91\xC4\xCC\x01", buf, sizeof(buf)));
+
+ // Largest allowed length.
+ WriteRedundantVarInt(0x0FFFFFFF, buf);
+ EXPECT_EQ(0, memcmp("\xFF\xFF\xFF\x7F", buf, sizeof(buf)));
+}
+
+TEST(ProtoUtilsTest, VarIntDecoding) {
+ for (size_t i = 0; i < arraysize(kVarIntExpectations); ++i) {
+ const VarIntExpectation& exp = kVarIntExpectations[i];
+ uint64_t value = std::numeric_limits<uint64_t>::max();
+ const uint8_t* res = ParseVarInt(
+ reinterpret_cast<const uint8_t*>(exp.encoded),
+ reinterpret_cast<const uint8_t*>(exp.encoded + exp.encoded_size),
+ &value);
+ ASSERT_EQ(reinterpret_cast<const void*>(exp.encoded + exp.encoded_size),
+ reinterpret_cast<const void*>(res));
+ ASSERT_EQ(exp.int_value, value);
+ }
+}
+
+TEST(ProtoUtilsTest, FieldDecoding) {
+ for (size_t i = 0; i < arraysize(kFieldExpectations); ++i) {
+ const FieldExpectation& exp = kFieldExpectations[i];
+ FieldType field_type = kFieldTypeVarInt;
+ uint32_t field_id = std::numeric_limits<uint32_t>::max();
+ uint64_t field_intvalue = std::numeric_limits<uint64_t>::max();
+ const uint8_t* res = ParseField(
+ reinterpret_cast<const uint8_t*>(exp.encoded),
+ reinterpret_cast<const uint8_t*>(exp.encoded + exp.encoded_size),
+ &field_id, &field_type, &field_intvalue);
+ ASSERT_EQ(reinterpret_cast<const void*>(exp.encoded + exp.encoded_size),
+ reinterpret_cast<const void*>(res));
+ ASSERT_EQ(exp.id, field_id);
+ ASSERT_EQ(exp.type, field_type);
+ ASSERT_EQ(exp.int_value, field_intvalue);
+ }
+}
+
+} // namespace
+} // namespace proto
+} // namespace v2
+} // namespace tracing
diff --git a/chromium/components/tracing/core/proto_zero_message.cc b/chromium/components/tracing/core/proto_zero_message.cc
new file mode 100644
index 00000000000..a555683428c
--- /dev/null
+++ b/chromium/components/tracing/core/proto_zero_message.cc
@@ -0,0 +1,129 @@
+// 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 "components/tracing/core/proto_zero_message.h"
+
+#include <string.h>
+
+#include "components/tracing/core/proto_zero_message_handle.h"
+
+#if !defined(ARCH_CPU_LITTLE_ENDIAN)
+// The memcpy() for float and double below needs to be adjusted if we want to
+// support big endian CPUs. There doesn't seem to be a compelling need today.
+#error big-endian CPUs not supported by this translation unit.
+#endif
+
+namespace tracing {
+namespace v2 {
+
+ProtoZeroMessage::ProtoZeroMessage() {
+ // Do NOT add any code here, use the Reset() method below instead.
+ // Ctor and Dtor of ProtoZeroMessage are never called, with the exeception
+ // of root (non-nested) messages. Nested messages are allocated in the
+ // |nested_messages_arena_| and implictly destroyed when the arena of the
+ // root message goes away. This is fine as long as all the fields are PODs,
+ // hence the static_assert below.
+ static_assert(base::is_trivially_destructible<ProtoZeroMessage>::value,
+ "ProtoZeroMessage must be trivially destructible");
+
+ static_assert(
+ sizeof(ProtoZeroMessage::nested_messages_arena_) >=
+ kMaxNestingDepth * (sizeof(ProtoZeroMessage) -
+ sizeof(ProtoZeroMessage::nested_messages_arena_)),
+ "ProtoZeroMessage::nested_messages_arena_ is too small");
+}
+
+// This method is called to initialize both root and nested messages.
+void ProtoZeroMessage::Reset(ScatteredStreamWriter* stream_writer) {
+ stream_writer_ = stream_writer;
+ size_ = 0;
+ size_field_.reset();
+ size_already_written_ = 0;
+ nested_message_ = nullptr;
+ nesting_depth_ = 0;
+#if DCHECK_IS_ON()
+ sealed_ = false;
+ handle_ = nullptr;
+#endif
+}
+
+void ProtoZeroMessage::AppendString(uint32_t field_id, const char* str) {
+ AppendBytes(field_id, str, strlen(str));
+}
+
+void ProtoZeroMessage::AppendBytes(uint32_t field_id,
+ const void* src,
+ size_t size) {
+ if (nested_message_)
+ EndNestedMessage();
+
+ DCHECK_LT(size, proto::kMaxMessageLength);
+ // Write the proto preamble (field id, type and length of the field).
+ uint8_t buffer[proto::kMaxSimpleFieldEncodedSize];
+ uint8_t* pos = buffer;
+ pos = proto::WriteVarInt(proto::MakeTagLengthDelimited(field_id), pos);
+ pos = proto::WriteVarInt(static_cast<uint32_t>(size), pos);
+ WriteToStream(buffer, pos);
+
+ const uint8_t* src_u8 = reinterpret_cast<const uint8_t*>(src);
+ WriteToStream(src_u8, src_u8 + size);
+}
+
+size_t ProtoZeroMessage::Finalize() {
+ if (nested_message_)
+ EndNestedMessage();
+
+ if (size_field_.is_valid()) {
+// Write the length of the nested message a posteriori, using a leading-zero
+// redundant varint encoding.
+#if DCHECK_IS_ON()
+ DCHECK(!sealed_);
+#endif
+ DCHECK_LT(size_, proto::kMaxMessageLength);
+ DCHECK_EQ(proto::kMessageLengthFieldSize, size_field_.size());
+ proto::WriteRedundantVarInt(
+ static_cast<uint32_t>(size_ - size_already_written_),
+ size_field_.begin);
+ size_field_.reset();
+ }
+
+#if DCHECK_IS_ON()
+ sealed_ = true;
+ if (handle_)
+ handle_->reset_message();
+#endif
+
+ return size_;
+}
+
+void ProtoZeroMessage::BeginNestedMessageInternal(uint32_t field_id,
+ ProtoZeroMessage* message) {
+ if (nested_message_)
+ EndNestedMessage();
+
+ // Write the proto preamble for the nested message.
+ uint8_t data[proto::kMaxTagEncodedSize];
+ uint8_t* data_end =
+ proto::WriteVarInt(proto::MakeTagLengthDelimited(field_id), data);
+ WriteToStream(data, data_end);
+
+ message->Reset(stream_writer_);
+ CHECK_LT(nesting_depth_, kMaxNestingDepth);
+ message->nesting_depth_ = nesting_depth_ + 1;
+
+ // The length of the nested message cannot be known upfront. So right now
+ // just reserve the bytes to encode the size after the nested message is done.
+ message->set_size_field(
+ stream_writer_->ReserveBytes(proto::kMessageLengthFieldSize));
+ size_ += proto::kMessageLengthFieldSize;
+ nested_message_ = message;
+}
+
+void ProtoZeroMessage::EndNestedMessage() {
+ size_ += nested_message_->Finalize();
+ nested_message_ = nullptr;
+}
+
+} // namespace v2
+} // namespace tracing
diff --git a/chromium/components/tracing/core/proto_zero_message.h b/chromium/components/tracing/core/proto_zero_message.h
new file mode 100644
index 00000000000..2e6bf4a1c3e
--- /dev/null
+++ b/chromium/components/tracing/core/proto_zero_message.h
@@ -0,0 +1,213 @@
+// 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 COMPONENTS_TRACING_CORE_PROTO_ZERO_MESSAGE_H_
+#define COMPONENTS_TRACING_CORE_PROTO_ZERO_MESSAGE_H_
+
+#include <stdint.h>
+
+#include <type_traits>
+
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/template_util.h"
+#include "build/build_config.h"
+#include "components/tracing/core/proto_utils.h"
+#include "components/tracing/core/scattered_stream_writer.h"
+#include "components/tracing/tracing_export.h"
+
+namespace tracing {
+namespace v2 {
+
+class ProtoZeroMessageHandleBase;
+
+// Base class extended by the proto C++ stubs generated by the ProtoZero
+// compiler (see //components/tracing/tools/). This class provides the minimal
+// runtime required to support append-only operations and is desiged for
+// performance. None of the methods require any dynamic memory allocation.
+class TRACING_EXPORT ProtoZeroMessage {
+ public:
+ ProtoZeroMessage();
+
+ // Clears up the state, allowing the message to be reused as a fresh one.
+ void Reset(ScatteredStreamWriter*);
+
+ // Commits all the changes to the buffer (backfills the size field of this and
+ // all nested messages) and seals the message. Returns the size of the message
+ // (and all nested sub-messages), without taking into account any chunking.
+ // Finalize is idempotent and can be called several times w/o side effects.
+ size_t Finalize();
+
+ // Optional. If is_valid() == true, the corresponding memory region (its
+ // length == proto::kMessageLengthFieldSize) is backfilled with the size of
+ // this message (minus |size_already_written| below) when the message is
+ // finalized. This is the mechanism used by messages to backfill their
+ // corresponding size field in the parent message.
+ ContiguousMemoryRange size_field() const { return size_field_; }
+ void set_size_field(const ContiguousMemoryRange& reserved_range) {
+ size_field_ = reserved_range;
+ }
+
+ // This is to deal with case of backfilling the size of a root (non-nested)
+ // message which is split into multiple chunks. Upon finalization only the
+ // partial size that lies in the last chunk has to be backfilled.
+ void inc_size_already_written(size_t size) { size_already_written_ += size; }
+
+#if DCHECK_IS_ON()
+ // Only for ProtoZeroMessageHandleBase.
+ void set_handle(ProtoZeroMessageHandleBase* handle) { handle_ = handle; }
+#endif
+
+ protected:
+ // Proto types: uint64, uint32, int64, int32, bool, enum.
+ template <typename T>
+ void AppendVarInt(uint32_t field_id, T value) {
+ if (nested_message_)
+ EndNestedMessage();
+
+ uint8_t buffer[proto::kMaxSimpleFieldEncodedSize];
+ uint8_t* pos = buffer;
+
+ pos = proto::WriteVarInt(proto::MakeTagVarInt(field_id), pos);
+ // WriteVarInt encodes signed values in two's complement form.
+ pos = proto::WriteVarInt(value, pos);
+ WriteToStream(buffer, pos);
+ }
+
+ // Proto types: sint64, sint32.
+ template <typename T>
+ void AppendSignedVarInt(uint32_t field_id, T value) {
+ AppendVarInt(field_id, proto::ZigZagEncode(value));
+ }
+
+ // Proto types: bool, enum (small).
+ // Faster version of AppendVarInt for tiny numbers.
+ void AppendTinyVarInt(uint32_t field_id, int32_t value) {
+ DCHECK(0 <= value && value < 0x80);
+ if (nested_message_)
+ EndNestedMessage();
+
+ uint8_t buffer[proto::kMaxSimpleFieldEncodedSize];
+ uint8_t* pos = buffer;
+ // MakeTagVarInt gets super optimized here for constexpr.
+ pos = proto::WriteVarInt(proto::MakeTagVarInt(field_id), pos);
+ *pos++ = static_cast<uint8_t>(value);
+ WriteToStream(buffer, pos);
+ }
+
+ // Proto types: fixed64, sfixed64, fixed32, sfixed32, double, float.
+ template <typename T>
+ void AppendFixed(uint32_t field_id, T value) {
+ if (nested_message_)
+ EndNestedMessage();
+
+ uint8_t buffer[proto::kMaxSimpleFieldEncodedSize];
+ uint8_t* pos = buffer;
+
+ pos = proto::WriteVarInt(proto::MakeTagFixed<T>(field_id), pos);
+ memcpy(pos, &value, sizeof(T));
+ pos += sizeof(T);
+ // TODO(kraynov): Optimize memcpy performance, see http://crbug.com/624311 .
+ WriteToStream(buffer, pos);
+ }
+
+ void AppendString(uint32_t field_id, const char* str);
+ void AppendBytes(uint32_t field_id, const void* value, size_t size);
+
+ // Begins a nested message, using the static storage provided by the parent
+ // class (see comment in |nested_messages_arena_|). The nested message ends
+ // either when Finalize() is called or when any other Append* method is called
+ // in the parent class.
+ // The template argument T is supposed to be a stub class auto generated from
+ // a .proto, hence a subclass of ProtoZeroMessage.
+ template <class T>
+ T* BeginNestedMessage(uint32_t field_id) {
+ // This is to prevent subclasses (which should be autogenerated, though), to
+ // introduce extra state fields (which wouldn't be initialized by Reset()).
+ static_assert(std::is_base_of<ProtoZeroMessage, T>::value,
+ "T must be a subclass of ProtoZeroMessage");
+ static_assert(sizeof(T) == sizeof(ProtoZeroMessage),
+ "ProtoZeroMessage subclasses cannot introduce extra state.");
+ T* message = reinterpret_cast<T*>(nested_messages_arena_);
+ BeginNestedMessageInternal(field_id, message);
+ return message;
+ }
+
+ private:
+ friend class ProtoZeroMessageTest;
+ FRIEND_TEST_ALL_PREFIXES(ProtoZeroMessageTest, BasicTypesNoNesting);
+ FRIEND_TEST_ALL_PREFIXES(ProtoZeroMessageTest, BackfillSizeOnFinalization);
+ FRIEND_TEST_ALL_PREFIXES(ProtoZeroMessageTest, NestedMessagesSimple);
+ FRIEND_TEST_ALL_PREFIXES(ProtoZeroMessageTest, StressTest);
+ FRIEND_TEST_ALL_PREFIXES(ProtoZeroMessageTest, MessageHandle);
+
+ enum : uint32_t { kMaxNestingDepth = 8 };
+
+ void BeginNestedMessageInternal(uint32_t field_id, ProtoZeroMessage*);
+
+ // Called by Finalize and Append* methods.
+ void EndNestedMessage();
+
+ void WriteToStream(const uint8_t* src_begin, const uint8_t* src_end) {
+#if DCHECK_IS_ON()
+ DCHECK(!sealed_);
+#endif
+ DCHECK(src_begin < src_end);
+ const size_t size = static_cast<size_t>(src_end - src_begin);
+ stream_writer_->WriteBytes(src_begin, size);
+ size_ += size;
+ }
+
+ // Only POD fields are allowed. This class's dtor is never called.
+ // See the comment on the static_assert in the the corresponding .cc file.
+
+ // The stream writer interface used for the serialization.
+ ScatteredStreamWriter* stream_writer_;
+
+ // Keeps track of the size of the current message.
+ size_t size_;
+
+ ContiguousMemoryRange size_field_;
+ size_t size_already_written_;
+
+ // Used to detect attemps to create messages with a nesting level >
+ // kMaxNestingDepth. |nesting_depth_| == 0 for root (non-nested) messages.
+ uint32_t nesting_depth_;
+
+#if DCHECK_IS_ON()
+ // When true, no more changes to the message are allowed. This is to DCHECK
+ // attempts of writing to a message which has been Finalize()-d.
+ bool sealed_;
+
+ ProtoZeroMessageHandleBase* handle_;
+#endif
+
+ // Pointer to the last child message created through BeginNestedMessage(), if
+ // any. nullptr otherwise. There is no need to keep track of more than one
+ // message per nesting level as the proto-zero API contract mandates that
+ // nested fields can be filled only in a stacked fashion. In other words,
+ // nested messages are finalized and sealed when any other field is set in the
+ // parent message (or the parent message itself is finalized) and cannot be
+ // accessed anymore afterwards.
+ ProtoZeroMessage* nested_message_;
+
+ // The root message owns the storage for all its nested messages, up to a max
+ // of kMaxNestingDepth levels (see the .cc file). Note that the boundaries of
+ // the arena are meaningful only for the root message. The static_assert in
+ // the .cc file guarantees that the sizeof(nested_messages_arena_) is enough
+ // to contain up to kMaxNestingDepth messages.
+ ALIGNAS(sizeof(void*)) uint8_t nested_messages_arena_[512];
+
+ // DO NOT add any fields below |nested_messages_arena_|. The memory layout of
+ // nested messages would overflow the storage allocated by the root message.
+
+ DISALLOW_COPY_AND_ASSIGN(ProtoZeroMessage);
+};
+
+} // namespace v2
+} // namespace tracing
+
+#endif // COMPONENTS_TRACING_CORE_PROTO_ZERO_MESSAGE_H_
diff --git a/chromium/components/tracing/core/proto_zero_message_handle.cc b/chromium/components/tracing/core/proto_zero_message_handle.cc
new file mode 100644
index 00000000000..b40f135fe32
--- /dev/null
+++ b/chromium/components/tracing/core/proto_zero_message_handle.cc
@@ -0,0 +1,67 @@
+// 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 "components/tracing/core/proto_zero_message_handle.h"
+
+#include "base/logging.h"
+#include "components/tracing/core/proto_zero_message.h"
+
+namespace tracing {
+namespace v2 {
+
+namespace {
+
+inline void FinalizeMessageIfSet(ProtoZeroMessage* message) {
+ if (message) {
+ message->Finalize();
+#if DCHECK_IS_ON()
+ message->set_handle(nullptr);
+#endif
+ }
+}
+
+} // namespace
+
+ProtoZeroMessageHandleBase::ProtoZeroMessageHandleBase(
+ ProtoZeroMessage* message)
+ : message_(message) {
+#if DCHECK_IS_ON()
+ message_->set_handle(this);
+#endif
+}
+
+ProtoZeroMessageHandleBase::~ProtoZeroMessageHandleBase() {
+ FinalizeMessageIfSet(message_);
+}
+
+ProtoZeroMessageHandleBase::ProtoZeroMessageHandleBase(
+ ProtoZeroMessageHandleBase&& other) {
+ Move(&other);
+}
+
+ProtoZeroMessageHandleBase& ProtoZeroMessageHandleBase::operator=(
+ ProtoZeroMessageHandleBase&& other) {
+ // If the current handle was pointing to a message and is being reset to a new
+ // one, finalize the old message.
+ FinalizeMessageIfSet(message_);
+
+ Move(&other);
+ return *this;
+}
+
+void ProtoZeroMessageHandleBase::Move(ProtoZeroMessageHandleBase* other) {
+ // In theory other->message_ could be nullptr, if |other| is a handle that has
+ // been std::move-d (and hence empty). There isn't a legitimate use case for
+ // doing so, though. Therefore this case is deliberately ignored (if hit, it
+ // will manifest as a segfault when dereferencing |message_| below) to avoid a
+ // useless null-check.
+ message_ = other->message_;
+ other->message_ = nullptr;
+#if DCHECK_IS_ON()
+ message_->set_handle(this);
+#endif
+}
+
+} // namespace v2
+} // namespace tracing
diff --git a/chromium/components/tracing/core/proto_zero_message_handle.h b/chromium/components/tracing/core/proto_zero_message_handle.h
new file mode 100644
index 00000000000..2f83ec9638f
--- /dev/null
+++ b/chromium/components/tracing/core/proto_zero_message_handle.h
@@ -0,0 +1,69 @@
+// 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 COMPONENTS_TRACING_CORE_PROTO_ZERO_MESSAGE_HANDLE_H_
+#define COMPONENTS_TRACING_CORE_PROTO_ZERO_MESSAGE_HANDLE_H_
+
+#include "base/macros.h"
+#include "components/tracing/tracing_export.h"
+
+namespace tracing {
+namespace v2 {
+
+class ProtoZeroMessage;
+
+// ProtoZeroMessageHandle allows to decouple the lifetime of a proto message
+// from the underlying storage. It gives the following guarantees:
+// - The underlying message is finalized (if still alive) if the handle goes
+// out of scope.
+// - In Debug / DCHECK_ALWAYS_ON builds, the handle becomes null once the
+// message is finalized. This is to enforce the append-only API. For instance
+// when adding two repeated messages, the addition of the 2nd one forces
+// the finalization of the first.
+// Think about this as a WeakPtr<ProtoZeroMessage> which calls
+// ProtoZeroMessage::Finalize() when going out of scope.
+
+class TRACING_EXPORT ProtoZeroMessageHandleBase {
+ public:
+ ~ProtoZeroMessageHandleBase();
+
+ // Move-only type.
+ ProtoZeroMessageHandleBase(ProtoZeroMessageHandleBase&& other);
+ ProtoZeroMessageHandleBase& operator=(ProtoZeroMessageHandleBase&& other);
+
+ protected:
+ explicit ProtoZeroMessageHandleBase(ProtoZeroMessage*);
+ ProtoZeroMessage& operator*() const { return *message_; }
+ ProtoZeroMessage* operator->() const { return message_; }
+
+ private:
+ friend class ProtoZeroMessage;
+
+ void reset_message() { message_ = nullptr; }
+ void Move(ProtoZeroMessageHandleBase* other);
+
+ ProtoZeroMessage* message_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProtoZeroMessageHandleBase);
+};
+
+template <typename T>
+class ProtoZeroMessageHandle : ProtoZeroMessageHandleBase {
+ public:
+ explicit ProtoZeroMessageHandle(T* message)
+ : ProtoZeroMessageHandleBase(message) {}
+
+ T& operator*() const {
+ return static_cast<T&>(ProtoZeroMessageHandleBase::operator*());
+ }
+
+ T* operator->() const {
+ return static_cast<T*>(ProtoZeroMessageHandleBase::operator->());
+ }
+};
+
+} // namespace v2
+} // namespace tracing
+
+#endif // COMPONENTS_TRACING_CORE_PROTO_ZERO_MESSAGE_HANDLE_H_
diff --git a/chromium/components/tracing/core/proto_zero_message_unittest.cc b/chromium/components/tracing/core/proto_zero_message_unittest.cc
new file mode 100644
index 00000000000..90fecd6b4c7
--- /dev/null
+++ b/chromium/components/tracing/core/proto_zero_message_unittest.cc
@@ -0,0 +1,327 @@
+// 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 "components/tracing/core/proto_zero_message.h"
+
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include "base/hash.h"
+#include "components/tracing/core/proto_utils.h"
+#include "components/tracing/core/proto_zero_message_handle.h"
+#include "components/tracing/test/fake_scattered_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace tracing {
+namespace v2 {
+
+const size_t kChunkSize = 16;
+const uint8_t kTestBytes[] = {0, 0, 0, 0, 0x42, 1, 0x42, 0xff, 0x42, 0};
+const char kStartWatermark[] = {'a', 'b', 'c', 'd', '1', '2', '3', '\0'};
+const char kEndWatermark[] = {'9', '8', '7', '6', 'z', 'w', 'y', '\0'};
+
+class FakeRootMessage : public ProtoZeroMessage {};
+class FakeChildMessage : public ProtoZeroMessage {};
+
+class ProtoZeroMessageTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ buffer_.reset(new FakeScatteredBuffer(kChunkSize));
+ stream_writer_.reset(new ScatteredStreamWriter(buffer_.get()));
+ readback_pos_ = 0;
+ }
+
+ void TearDown() override {
+ // Check that none of the messages created by the text fixtures below did
+ // under/overflow their heap boundaries.
+ for (std::unique_ptr<uint8_t[]>& mem : messages_) {
+ EXPECT_STREQ(kStartWatermark, reinterpret_cast<char*>(mem.get()));
+ EXPECT_STREQ(kEndWatermark,
+ reinterpret_cast<char*>(mem.get() + sizeof(kStartWatermark) +
+ sizeof(ProtoZeroMessage)));
+ mem.reset();
+ }
+ messages_.clear();
+ stream_writer_.reset();
+ buffer_.reset();
+ }
+
+ FakeRootMessage* NewMessage() {
+ std::unique_ptr<uint8_t[]> mem(
+ new uint8_t[sizeof(kStartWatermark) + sizeof(FakeRootMessage) +
+ sizeof(kEndWatermark)]);
+ uint8_t* msg_start = mem.get() + sizeof(kStartWatermark);
+ memcpy(mem.get(), kStartWatermark, sizeof(kStartWatermark));
+ memset(msg_start, 0, sizeof(FakeRootMessage));
+ memcpy(msg_start + sizeof(FakeRootMessage), kEndWatermark,
+ sizeof(kEndWatermark));
+ messages_.push_back(std::move(mem));
+ FakeRootMessage* msg = reinterpret_cast<FakeRootMessage*>(msg_start);
+ msg->Reset(stream_writer_.get());
+ return msg;
+ }
+
+ size_t GetNumSerializedBytes() {
+ if (buffer_->chunks().empty())
+ return 0;
+ return buffer_->chunks().size() * kChunkSize -
+ stream_writer_->bytes_available();
+ }
+
+ std::string GetNextSerializedBytes(size_t num_bytes) {
+ size_t old_readback_pos = readback_pos_;
+ readback_pos_ += num_bytes;
+ return buffer_->GetBytesAsString(old_readback_pos, num_bytes);
+ }
+
+ static void BuildNestedMessages(uint32_t depth, ProtoZeroMessage* msg) {
+ for (uint32_t i = 1; i <= 128; ++i)
+ msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes));
+
+ if (depth < ProtoZeroMessage::kMaxNestingDepth) {
+ auto* nested_msg =
+ msg->BeginNestedMessage<FakeChildMessage>(1 + depth * 10);
+ BuildNestedMessages(depth + 1, nested_msg);
+ }
+
+ for (uint32_t i = 129; i <= 256; ++i)
+ msg->AppendVarInt(i, 42);
+
+ if ((depth & 2) == 0)
+ msg->Finalize();
+ }
+
+ private:
+ std::unique_ptr<FakeScatteredBuffer> buffer_;
+ std::unique_ptr<ScatteredStreamWriter> stream_writer_;
+ std::vector<std::unique_ptr<uint8_t[]>> messages_;
+ size_t readback_pos_;
+};
+
+TEST_F(ProtoZeroMessageTest, BasicTypesNoNesting) {
+ ProtoZeroMessage* msg = NewMessage();
+ msg->AppendVarInt(1 /* field_id */, 0);
+ msg->AppendVarInt(2 /* field_id */, std::numeric_limits<uint32_t>::max());
+ msg->AppendVarInt(3 /* field_id */, 42);
+ msg->AppendVarInt(4 /* field_id */, std::numeric_limits<uint64_t>::max());
+ msg->AppendFixed(5 /* field_id */, 3.1415f /* float */);
+ msg->AppendFixed(6 /* field_id */, 3.14159265358979323846 /* double */);
+ msg->AppendBytes(7 /* field_id */, kTestBytes, sizeof(kTestBytes));
+
+ // Field ids > 16 are expected to be varint encoded (preamble > 1 byte)
+ msg->AppendString(257 /* field_id */, "0123456789abcdefABCDEF");
+ msg->AppendSignedVarInt(3 /* field_id */, -21);
+
+ EXPECT_EQ(74u, msg->Finalize());
+ EXPECT_EQ(74u, GetNumSerializedBytes());
+
+ // These lines match the serialization of the Append* calls above.
+ ASSERT_EQ("0800", GetNextSerializedBytes(2));
+ ASSERT_EQ("10FFFFFFFF0F", GetNextSerializedBytes(6));
+ ASSERT_EQ("182A", GetNextSerializedBytes(2));
+ ASSERT_EQ("20FFFFFFFFFFFFFFFFFF01", GetNextSerializedBytes(11));
+ ASSERT_EQ("2D560E4940", GetNextSerializedBytes(5));
+ ASSERT_EQ("31182D4454FB210940", GetNextSerializedBytes(9));
+ ASSERT_EQ("3A0A00000000420142FF4200", GetNextSerializedBytes(12));
+ ASSERT_EQ("8A101630313233343536373839616263646566414243444546",
+ GetNextSerializedBytes(25));
+ ASSERT_EQ("1829", GetNextSerializedBytes(2));
+}
+
+TEST_F(ProtoZeroMessageTest, NestedMessagesSimple) {
+ ProtoZeroMessage* root_msg = NewMessage();
+ root_msg->AppendVarInt(1 /* field_id */, 1);
+
+ FakeChildMessage* nested_msg =
+ root_msg->BeginNestedMessage<FakeChildMessage>(128 /* field_id */);
+ ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(nested_msg) % sizeof(void*));
+ nested_msg->AppendVarInt(2 /* field_id */, 2);
+
+ nested_msg =
+ root_msg->BeginNestedMessage<FakeChildMessage>(129 /* field_id */);
+ nested_msg->AppendVarInt(4 /* field_id */, 2);
+
+ root_msg->AppendVarInt(5 /* field_id */, 3);
+
+ // The expected size of the root message is supposed to be 20 bytes:
+ // 2 bytes for the varint field (id: 1) (1 for preamble and one for payload)
+ // 6 bytes for the preamble of the 1st nested message (2 for id, 4 for size)
+ // 2 bytes for the varint field (id: 2) of the 1st nested message
+ // 6 bytes for the premable of the 2nd nested message
+ // 2 bytes for the varint field (id: 4) of the 2nd nested message.
+ // 2 bytes for the last varint (id : 5) field of the root message.
+ // Test also that finalization is idempontent and Finalize() can be safely
+ // called more than once without side effects.
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_EQ(20u, root_msg->Finalize());
+ EXPECT_EQ(20u, GetNumSerializedBytes());
+ }
+
+ ASSERT_EQ("0801", GetNextSerializedBytes(2));
+
+ ASSERT_EQ("820882808000", GetNextSerializedBytes(6));
+ ASSERT_EQ("1002", GetNextSerializedBytes(2));
+
+ ASSERT_EQ("8A0882808000", GetNextSerializedBytes(6));
+ ASSERT_EQ("2002", GetNextSerializedBytes(2));
+
+ ASSERT_EQ("2803", GetNextSerializedBytes(2));
+}
+
+// Checks that the size field of root and nested messages is properly written
+// on finalization.
+TEST_F(ProtoZeroMessageTest, BackfillSizeOnFinalization) {
+ ProtoZeroMessage* root_msg = NewMessage();
+ uint8_t root_msg_size[proto::kMessageLengthFieldSize] = {};
+ root_msg->set_size_field(
+ {&root_msg_size[0], &root_msg_size[proto::kMessageLengthFieldSize]});
+ root_msg->AppendVarInt(1, 0x42);
+
+ FakeChildMessage* nested_msg_1 =
+ root_msg->BeginNestedMessage<FakeChildMessage>(2);
+ nested_msg_1->AppendVarInt(3, 0x43);
+
+ FakeChildMessage* nested_msg_2 =
+ nested_msg_1->BeginNestedMessage<FakeChildMessage>(4);
+ uint8_t buf200[200];
+ memset(buf200, 0x42, sizeof(buf200));
+ nested_msg_2->AppendBytes(5, buf200, sizeof(buf200));
+
+ root_msg->inc_size_already_written(6);
+
+ // The value returned by Finalize() should be == the full size of |root_msg|.
+ EXPECT_EQ(217u, root_msg->Finalize());
+ EXPECT_EQ(217u, GetNumSerializedBytes());
+
+ // However the size written in the size field should take into account the
+ // inc_size_already_written() call and be equal to 118 - 6 = 112, encoded
+ // in a rendundant varint encoding of kMessageLengthFieldSize bytes.
+ EXPECT_STREQ("\xD3\x81\x80\x00", reinterpret_cast<char*>(root_msg_size));
+
+ // Skip 2 bytes for the 0x42 varint + 1 byte for the |nested_msg_1| preamble.
+ GetNextSerializedBytes(3);
+
+ // Check that the size of |nested_msg_1| was backfilled. Its size is:
+ // 203 bytes for |nest_mesg_2| (see below) + 5 bytes for its preamble +
+ // 2 bytes for the 0x43 varint = 210 bytes.
+ EXPECT_EQ("D2818000", GetNextSerializedBytes(4));
+
+ // Skip 2 bytes for the 0x43 varint + 1 byte for the |nested_msg_2| preamble.
+ GetNextSerializedBytes(3);
+
+ // Check that the size of |nested_msg_2| was backfilled. Its size is:
+ // 200 bytes (for |buf200|) + 3 bytes for its preamble = 203 bytes.
+ EXPECT_EQ("CB818000", GetNextSerializedBytes(4));
+}
+
+TEST_F(ProtoZeroMessageTest, StressTest) {
+ std::vector<ProtoZeroMessage*> nested_msgs;
+
+ ProtoZeroMessage* root_msg = NewMessage();
+ BuildNestedMessages(0, root_msg);
+ root_msg->Finalize();
+
+ // The main point of this test is to stress the code paths and test for
+ // unexpected crashes of the production code. The actual serialization is
+ // already covered in the other text fixtures. Keeping just a final smoke test
+ // here on the full buffer hash.
+ std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes());
+ uint32_t buf_hash = base::SuperFastHash(full_buf.data(), full_buf.size());
+ EXPECT_EQ(0x14BC1BA3u, buf_hash);
+}
+
+TEST_F(ProtoZeroMessageTest, MessageHandle) {
+ FakeRootMessage* msg1 = NewMessage();
+ FakeRootMessage* msg2 = NewMessage();
+ FakeRootMessage* msg3 = NewMessage();
+ FakeRootMessage* ignored_msg = NewMessage();
+ uint8_t msg1_size[proto::kMessageLengthFieldSize] = {};
+ uint8_t msg2_size[proto::kMessageLengthFieldSize] = {};
+ uint8_t msg3_size[proto::kMessageLengthFieldSize] = {};
+ msg1->set_size_field(
+ {&msg1_size[0], &msg1_size[proto::kMessageLengthFieldSize]});
+ msg2->set_size_field(
+ {&msg2_size[0], &msg2_size[proto::kMessageLengthFieldSize]});
+ msg3->set_size_field(
+ {&msg3_size[0], &msg3_size[proto::kMessageLengthFieldSize]});
+
+ // Test that the handle going out of scope causes the finalization of the
+ // target message.
+ {
+ ProtoZeroMessageHandle<FakeRootMessage> handle1(msg1);
+ handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */);
+ ASSERT_EQ(0u, msg1_size[0]);
+ }
+ ASSERT_EQ(0x83u, msg1_size[0]);
+
+ // Test that the handle can be late initialized.
+ ProtoZeroMessageHandle<FakeRootMessage> handle2(ignored_msg);
+ handle2 = ProtoZeroMessageHandle<FakeRootMessage>(msg2);
+ handle2->AppendBytes(1 /* field_id */, kTestBytes, 2 /* size */);
+ ASSERT_EQ(0u, msg2_size[0]); // |msg2| should not be finalized yet.
+
+ // Test that std::move works and does NOT cause finalization of the moved
+ // message.
+ ProtoZeroMessageHandle<FakeRootMessage> handle_swp(ignored_msg);
+ handle_swp = std::move(handle2);
+ ASSERT_EQ(0u, msg2_size[0]); // msg2 should be NOT finalized yet.
+ handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 3 /* size */);
+
+ ProtoZeroMessageHandle<FakeRootMessage> handle3(msg3);
+ handle3->AppendBytes(1 /* field_id */, kTestBytes, 4 /* size */);
+ ASSERT_EQ(0u, msg3_size[0]); // msg2 should be NOT finalized yet.
+
+ // Both |handle3| and |handle_swp| point to a valid message (respectively,
+ // |msg3| and |msg2|). Now move |handle3| into |handle_swp|.
+ handle_swp = std::move(handle3);
+ ASSERT_EQ(0x89u, msg2_size[0]); // |msg2| should be finalized at this point.
+
+ // At this point writing into handle_swp should actually write into |msg3|.
+ ASSERT_EQ(msg3, &*handle_swp);
+ handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 8 /* size */);
+ ProtoZeroMessageHandle<FakeRootMessage> another_handle(ignored_msg);
+ handle_swp = std::move(another_handle);
+ ASSERT_EQ(0x90u, msg3_size[0]); // |msg3| should be finalized at this point.
+
+#if DCHECK_IS_ON()
+ // In developer builds w/ DCHECK on a finalized message should invalidate the
+ // handle, in order to early catch bugs in the client code.
+ FakeRootMessage* msg4 = NewMessage();
+ ProtoZeroMessageHandle<FakeRootMessage> handle4(msg4);
+ ASSERT_EQ(msg4, &*handle4);
+ msg4->Finalize();
+ ASSERT_EQ(nullptr, &*handle4);
+#endif
+
+ // Test also the behavior of handle with non-root (nested) messages.
+
+ ContiguousMemoryRange size_msg_2;
+ {
+ auto* nested_msg_1 = NewMessage()->BeginNestedMessage<FakeChildMessage>(3);
+ ProtoZeroMessageHandle<FakeChildMessage> child_handle_1(nested_msg_1);
+ ContiguousMemoryRange size_msg_1 = nested_msg_1->size_field();
+ memset(size_msg_1.begin, 0, size_msg_1.size());
+ child_handle_1->AppendVarInt(1, 0x11);
+
+ auto* nested_msg_2 = NewMessage()->BeginNestedMessage<FakeChildMessage>(2);
+ size_msg_2 = nested_msg_2->size_field();
+ memset(size_msg_2.begin, 0, size_msg_2.size());
+ ProtoZeroMessageHandle<FakeChildMessage> child_handle_2(nested_msg_2);
+ child_handle_2->AppendVarInt(2, 0xFF);
+
+ // |nested_msg_1| should not be finalized yet.
+ ASSERT_EQ(0u, size_msg_1.begin[0]);
+
+ // This move should cause |nested_msg_1| to be finalized, but not
+ // |nested_msg_2|, which will be finalized only after the current scope.
+ child_handle_1 = std::move(child_handle_2);
+ ASSERT_EQ(0x82u, size_msg_1.begin[0]);
+ ASSERT_EQ(0u, size_msg_2.begin[0]);
+ }
+ ASSERT_EQ(0x83u, size_msg_2.begin[0]);
+}
+
+} // namespace v2
+} // namespace tracing
diff --git a/chromium/components/tracing/core/scattered_stream_writer.cc b/chromium/components/tracing/core/scattered_stream_writer.cc
index 73e2a36ae20..37ca5b35507 100644
--- a/chromium/components/tracing/core/scattered_stream_writer.cc
+++ b/chromium/components/tracing/core/scattered_stream_writer.cc
@@ -13,6 +13,8 @@
namespace tracing {
namespace v2 {
+ScatteredStreamWriter::Delegate::~Delegate() {}
+
ScatteredStreamWriter::ScatteredStreamWriter(Delegate* delegate)
: delegate_(delegate),
cur_range_({nullptr, nullptr}),
@@ -62,7 +64,7 @@ void ScatteredStreamWriter::WriteBytes(const uint8_t* src, size_t size) {
// TODO(primiano): perf optimization: I suspect that at the end this will always
// be called with |size| == 4, in which case we might just hardcode it.
ContiguousMemoryRange ScatteredStreamWriter::ReserveBytes(size_t size) {
- // Assume the reservations are always < TraceRingBuffer::Chunk::kSize.
+ // Assume the reservations are always < kChunkSize.
if (write_ptr_ + size > cur_range_.end) {
Extend();
DCHECK_LE(write_ptr_ + size, cur_range_.end);
diff --git a/chromium/components/tracing/core/scattered_stream_writer.h b/chromium/components/tracing/core/scattered_stream_writer.h
index f5b0b770d85..53fcd881dcd 100644
--- a/chromium/components/tracing/core/scattered_stream_writer.h
+++ b/chromium/components/tracing/core/scattered_stream_writer.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include "base/logging.h"
#include "base/macros.h"
#include "components/tracing/tracing_export.h"
@@ -16,6 +17,10 @@ namespace v2 {
struct ContiguousMemoryRange {
uint8_t* begin;
uint8_t* end; // STL style: one byte past the end of the buffer.
+
+ inline bool is_valid() const { return begin != nullptr; }
+ inline void reset() { begin = nullptr; }
+ inline size_t size() { return static_cast<size_t>(end - begin); }
};
// This class deals with the following problem: append-only proto messages want
@@ -33,8 +38,9 @@ struct ContiguousMemoryRange {
// ContiguousMemoryRange and defers the chunk-chaining logic to the Delegate.
class TRACING_EXPORT ScatteredStreamWriter {
public:
- class Delegate {
+ class TRACING_EXPORT Delegate {
public:
+ virtual ~Delegate();
virtual ContiguousMemoryRange GetNewBuffer() = 0;
};
@@ -48,6 +54,16 @@ class TRACING_EXPORT ScatteredStreamWriter {
// is guaranteed to be contiguous and not span across chunks.
ContiguousMemoryRange ReserveBytes(size_t size);
+ // Fast (but unsafe) version of the above. The caller must have previously
+ // checked that there are at least |size| contiguos bytes available.
+ // Returns only the start pointer of the reservation.
+ uint8_t* ReserveBytesUnsafe(size_t size) {
+ uint8_t* begin = write_ptr_;
+ write_ptr_ += size;
+ DCHECK_LE(write_ptr_, cur_range_.end);
+ return begin;
+ }
+
// Resets the buffer boundaries and the write pointer to the given |range|.
// Subsequent WriteByte(s) will write into |range|.
void Reset(ContiguousMemoryRange range);
diff --git a/chromium/components/tracing/core/scattered_stream_writer_unittest.cc b/chromium/components/tracing/core/scattered_stream_writer_unittest.cc
index 7cb52ac5d87..424aa0013d5 100644
--- a/chromium/components/tracing/core/scattered_stream_writer_unittest.cc
+++ b/chromium/components/tracing/core/scattered_stream_writer_unittest.cc
@@ -7,36 +7,18 @@
#include <string.h>
#include <memory>
-#include <vector>
-#include "base/strings/string_number_conversions.h"
+#include "components/tracing/test/fake_scattered_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace tracing {
namespace v2 {
namespace {
-class MockDelegate : public ScatteredStreamWriter::Delegate {
- public:
- static const size_t kChunkSize = 8;
-
- ContiguousMemoryRange GetNewBuffer() override {
- std::unique_ptr<uint8_t[]> chunk(new uint8_t[kChunkSize]);
- uint8_t* begin = chunk.get();
- memset(begin, 0, kChunkSize);
- chunks.push_back(std::move(chunk));
- return {begin, begin + kChunkSize};
- }
-
- std::string GetChunkAsString(int chunk_index) {
- return base::HexEncode(chunks[chunk_index].get(), kChunkSize);
- }
-
- std::vector<std::unique_ptr<uint8_t[]>> chunks;
-};
+const size_t kChunkSize = 8;
TEST(ScatteredStreamWriterTest, ScatteredWrites) {
- MockDelegate delegate;
+ FakeScatteredBuffer delegate(kChunkSize);
ScatteredStreamWriter ssw(&delegate);
const uint8_t kOneByteBuf[] = {0x40};
@@ -47,38 +29,38 @@ TEST(ScatteredStreamWriterTest, ScatteredWrites) {
kTwentyByteBuf[i] = 0xA0 + i;
// Writing up to the chunk size should cause only the initial extension.
- for (uint8_t i = 0; i < MockDelegate::kChunkSize; ++i) {
+ for (uint8_t i = 0; i < kChunkSize; ++i) {
ssw.WriteByte(i);
- EXPECT_EQ(MockDelegate::kChunkSize - i - 1, ssw.bytes_available());
+ EXPECT_EQ(kChunkSize - i - 1, ssw.bytes_available());
}
- EXPECT_EQ(1u, delegate.chunks.size());
+ EXPECT_EQ(1u, delegate.chunks().size());
EXPECT_EQ(0u, ssw.bytes_available());
// This extra write will cause the first extension.
ssw.WriteBytes(kOneByteBuf, sizeof(kOneByteBuf));
- EXPECT_EQ(2u, delegate.chunks.size());
+ EXPECT_EQ(2u, delegate.chunks().size());
EXPECT_EQ(7u, ssw.bytes_available());
// This starts at offset 1, to make sure we don't hardcode any assumption
// about alignment.
ContiguousMemoryRange reserved_range_1 = ssw.ReserveBytes(4);
- EXPECT_EQ(2u, delegate.chunks.size());
+ EXPECT_EQ(2u, delegate.chunks().size());
EXPECT_EQ(3u, ssw.bytes_available());
ssw.WriteByte(0xFF);
ssw.WriteBytes(kThreeByteBuf, sizeof(kThreeByteBuf));
- EXPECT_EQ(3u, delegate.chunks.size());
+ EXPECT_EQ(3u, delegate.chunks().size());
EXPECT_EQ(7u, ssw.bytes_available());
ContiguousMemoryRange reserved_range_2 = ssw.ReserveBytes(4);
ssw.WriteBytes(kTwentyByteBuf, sizeof(kTwentyByteBuf));
- EXPECT_EQ(6u, delegate.chunks.size());
+ EXPECT_EQ(6u, delegate.chunks().size());
EXPECT_EQ(7u, ssw.bytes_available());
// Writing reserved bytes should not change the bytes_available().
memcpy(reserved_range_1.begin, kFourByteBuf, sizeof(kFourByteBuf));
memcpy(reserved_range_2.begin, kFourByteBuf, sizeof(kFourByteBuf));
- EXPECT_EQ(6u, delegate.chunks.size());
+ EXPECT_EQ(6u, delegate.chunks().size());
EXPECT_EQ(7u, ssw.bytes_available());
// Check that reserving more bytes than what left creates a brand new chunk
@@ -86,8 +68,13 @@ TEST(ScatteredStreamWriterTest, ScatteredWrites) {
for (uint8_t i = 0; i < 5; ++i)
ssw.WriteByte(0xFF);
memcpy(ssw.ReserveBytes(4).begin, kFourByteBuf, sizeof(kFourByteBuf));
- EXPECT_EQ(7u, delegate.chunks.size());
- EXPECT_EQ(4u, ssw.bytes_available());
+ memcpy(ssw.ReserveBytesUnsafe(3), kThreeByteBuf, sizeof(kThreeByteBuf));
+ memcpy(ssw.ReserveBytes(3).begin, kThreeByteBuf, sizeof(kThreeByteBuf));
+ memcpy(ssw.ReserveBytesUnsafe(1), kOneByteBuf, sizeof(kOneByteBuf));
+ memcpy(ssw.ReserveBytes(1).begin, kOneByteBuf, sizeof(kOneByteBuf));
+
+ EXPECT_EQ(8u, delegate.chunks().size());
+ EXPECT_EQ(3u, ssw.bytes_available());
EXPECT_EQ("0001020304050607", delegate.GetChunkAsString(0));
EXPECT_EQ("4060616263FF5051", delegate.GetChunkAsString(1));
@@ -95,7 +82,8 @@ TEST(ScatteredStreamWriterTest, ScatteredWrites) {
EXPECT_EQ("A3A4A5A6A7A8A9AA", delegate.GetChunkAsString(3));
EXPECT_EQ("ABACADAEAFB0B1B2", delegate.GetChunkAsString(4));
EXPECT_EQ("B3FFFFFFFFFF0000", delegate.GetChunkAsString(5));
- EXPECT_EQ("6061626300000000", delegate.GetChunkAsString(6));
+ EXPECT_EQ("6061626350515200", delegate.GetChunkAsString(6));
+ EXPECT_EQ("5051524040000000", delegate.GetChunkAsString(7));
// Finally reset the writer to a new buffer.
uint8_t other_buffer[8] = {0};
diff --git a/chromium/components/tracing/core/trace_buffer_writer.cc b/chromium/components/tracing/core/trace_buffer_writer.cc
new file mode 100644
index 00000000000..641521ed456
--- /dev/null
+++ b/chromium/components/tracing/core/trace_buffer_writer.cc
@@ -0,0 +1,206 @@
+// 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 "components/tracing/core/trace_buffer_writer.h"
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "components/tracing/core/proto_utils.h"
+#include "components/tracing/proto/event.pbzero.h"
+#include "components/tracing/proto/events_chunk.pbzero.h"
+
+namespace tracing {
+namespace v2 {
+
+namespace {
+
+using ChunkProto = pbzero::tracing::proto::EventsChunk;
+
+const size_t kEventPreambleSize = 1 + proto::kMessageLengthFieldSize;
+
+// TODO(primiano): replace 16 with a more reasonable size, that is, the size
+// of a simple trace event with no args.
+const size_t kMinEventSize = 16;
+
+} // namespace
+
+TraceBufferWriter::TraceBufferWriter(TraceRingBuffer* trace_ring_buffer,
+ uint32_t writer_id)
+ : trace_ring_buffer_(trace_ring_buffer),
+ writer_id_(writer_id),
+ chunk_seq_id_(0),
+ chunk_(nullptr),
+ event_data_start_in_current_chunk_(nullptr),
+ stream_writer_(this) {
+ event_.Reset(&stream_writer_);
+}
+
+TraceBufferWriter::~TraceBufferWriter() {}
+
+void TraceBufferWriter::FinalizeCurrentEvent() {
+ if (UNLIKELY(!chunk_))
+ return;
+
+ // Finalize the last event added. This ensures that it and all its nested
+ // fields are committed to the ring buffer and sealed. No further changes to
+ // the chunks's memory can be made from the |event_| after this point.
+ event_.Finalize();
+
+ // In the unlikely event that the last event did wrap over one or more chunks,
+ // is is now time to return those chunks (all but the active one) back.
+ TraceRingBuffer::Chunk* retained_chunk = chunk_->next_in_owner_list();
+ if (UNLIKELY(retained_chunk)) {
+ while (retained_chunk) {
+ TraceRingBuffer::Chunk* next = retained_chunk->next_in_owner_list();
+ retained_chunk->set_next_in_owner_list(nullptr);
+ trace_ring_buffer_->ReturnChunk(retained_chunk);
+ retained_chunk = next;
+ }
+ chunk_->set_next_in_owner_list(nullptr);
+ }
+}
+
+TraceEventHandle TraceBufferWriter::AddEvent() {
+ FinalizeCurrentEvent();
+
+ // In order to start a new event at least kMessageLengthFieldSize + 1 bytes
+ // are required in the chunk to write the preamble and size of the event
+ // itself. We take a bit more room here, it doesn't make a lot of sense
+ // starting a partial event that will fragment immediately after.
+ static_assert(kMinEventSize >= proto::kMessageLengthFieldSize + 1,
+ "kMinEventSize too small");
+ if (stream_writer_.bytes_available() < kMinEventSize)
+ stream_writer_.Reset(AcquireNewChunk(false /* is_fragmenting_event */));
+
+ event_.Reset(&stream_writer_);
+ WriteEventPreambleForNewChunk(
+ stream_writer_.ReserveBytesUnsafe(kEventPreambleSize));
+ DCHECK_EQ(stream_writer_.write_ptr(), event_data_start_in_current_chunk_);
+ return TraceEventHandle(static_cast<pbzero::tracing::proto::Event*>(&event_));
+}
+
+// This is invoked by the ProtoZeroMessage write methods when reaching the
+// end of the current chunk during a write.
+ContiguousMemoryRange TraceBufferWriter::GetNewBuffer() {
+ return AcquireNewChunk(true /* is_fragmenting_event */);
+}
+
+void TraceBufferWriter::FinalizeCurrentChunk(bool is_fragmenting_event) {
+ DCHECK(!is_fragmenting_event || chunk_);
+ if (!chunk_)
+ return;
+ uint8_t* write_ptr = stream_writer_.write_ptr();
+ DCHECK_GE(write_ptr, chunk_->payload());
+ DCHECK_LE(write_ptr, chunk_->end() - 2);
+
+ if (is_fragmenting_event) {
+ proto::StaticAssertSingleBytePreamble<
+ ChunkProto::kLastEventContinuesOnNextChunkFieldNumber>();
+ *write_ptr++ = static_cast<uint8_t>(proto::MakeTagVarInt(
+ ChunkProto::kLastEventContinuesOnNextChunkFieldNumber));
+ *write_ptr++ = 1; // = true.
+ }
+
+ DCHECK_LT(static_cast<uintptr_t>(write_ptr - chunk_->payload()), kChunkSize);
+ chunk_->set_used_size(static_cast<uint32_t>(write_ptr - chunk_->payload()));
+}
+
+// There are paths that lead to AcquireNewChunk():
+// When |is_fragmenting_event| = false:
+// AddEvent() is called and there isn't enough room in the current chunk to
+// start a new event (or we don't have a chunk yet).
+// When |is_fragmenting_event| = true:
+// The client is writing an event, a ProtoZeroMessage::Append* method hits
+// the boundary of the chunk and requests a new one via GetNewBuffer().
+ContiguousMemoryRange TraceBufferWriter::AcquireNewChunk(
+ bool is_fragmenting_event) {
+ FinalizeCurrentChunk(is_fragmenting_event);
+ TraceRingBuffer::Chunk* new_chunk = trace_ring_buffer_->TakeChunk(writer_id_);
+ if (is_fragmenting_event) {
+ // Backfill the size field of the event with the partial size accumulated
+ // so far in the old chunk. WriteEventPreambleForNewChunk() will take care
+ // of resetting the |size_field| of the event to the new chunk.
+ DCHECK_GE(event_data_start_in_current_chunk_, chunk_->payload());
+ DCHECK_LE(event_data_start_in_current_chunk_,
+ chunk_->end() - proto::kMessageLengthFieldSize);
+ const uint32_t event_partial_size = static_cast<uint32_t>(
+ stream_writer_.write_ptr() - event_data_start_in_current_chunk_);
+ proto::WriteRedundantVarInt(event_partial_size, event_.size_field().begin);
+ event_.inc_size_already_written(event_partial_size);
+
+ // If this is a continuation of an event, this writer needs to retain the
+ // old chunk. The client might still be able to write to it. This is to deal
+ // with the case of a nested message which is started in one chunk and
+ // ends in another one. The finalization needs to write-back the size field
+ // in the old chunk.
+ new_chunk->set_next_in_owner_list(chunk_);
+ } else if (chunk_) {
+ // Otherwise, if this is a new event, the previous chunk can be returned.
+ trace_ring_buffer_->ReturnChunk(chunk_);
+ }
+ chunk_ = new_chunk;
+
+ // Write the protobuf for the chunk header. The generated C++ stub for
+ // events_chunk.proto cannot be used here because that would re-enter this
+ // class and make this code extremely hard to reason about.
+ uint8_t* chunk_proto = new_chunk->payload();
+
+ proto::StaticAssertSingleBytePreamble<ChunkProto::kWriterIdFieldNumber>();
+ *chunk_proto++ = static_cast<uint8_t>(
+ proto::MakeTagVarInt(ChunkProto::kWriterIdFieldNumber));
+ chunk_proto = proto::WriteVarInt(writer_id_, chunk_proto);
+
+ proto::StaticAssertSingleBytePreamble<ChunkProto::kSeqIdFieldNumber>();
+ *chunk_proto++ =
+ static_cast<uint8_t>(proto::MakeTagVarInt(ChunkProto::kSeqIdFieldNumber));
+ chunk_proto = proto::WriteVarInt(chunk_seq_id_, chunk_proto);
+
+ if (is_fragmenting_event) {
+ proto::StaticAssertSingleBytePreamble<
+ ChunkProto::kFirstEventContinuesFromPrevChunkFieldNumber>();
+ *chunk_proto++ = static_cast<uint8_t>(proto::MakeTagVarInt(
+ ChunkProto::kFirstEventContinuesFromPrevChunkFieldNumber));
+ *chunk_proto++ = 1; // = true.
+ }
+
+ ++chunk_seq_id_;
+
+ // If the new chunk was requested while writing an event (the event spans
+ // across chunks) write a new preamble for the partial event in the new chunk.
+ if (is_fragmenting_event)
+ chunk_proto = WriteEventPreambleForNewChunk(chunk_proto);
+
+ // We reserve 2 bytes from the end, so that FinalizeCurrentChunk() can use
+ // them to write the |last_event_continues_on_next_chunk| field.
+ return {chunk_proto, new_chunk->end() - 2};
+}
+
+// Writes the one-byte preamble for the start of either a new or a partial
+// event and reserves kMessageLengthFieldSize bytes for its length. Also
+// keeps size-field the bookkeeping up to date. Returns the pointer in the chunk
+// past the event preamble, where the event proto should be written.
+uint8_t* TraceBufferWriter::WriteEventPreambleForNewChunk(uint8_t* begin) {
+ // The caller must have ensured to have enough room in the chunk. The event
+ // preamble itself cannot be fragmented.
+ uint8_t* const end = begin + kEventPreambleSize;
+ proto::StaticAssertSingleBytePreamble<ChunkProto::kEventsFieldNumber>();
+ *begin++ = static_cast<uint8_t>(
+ proto::MakeTagLengthDelimited(ChunkProto::kEventsFieldNumber));
+ ContiguousMemoryRange range = {begin, end};
+ event_.set_size_field(range);
+ event_data_start_in_current_chunk_ = end;
+ return end;
+}
+
+void TraceBufferWriter::Flush() {
+ if (!chunk_)
+ return;
+ FinalizeCurrentEvent();
+ FinalizeCurrentChunk(false /* is_fragmenting_event */);
+ trace_ring_buffer_->ReturnChunk(chunk_);
+ chunk_ = nullptr;
+}
+
+} // namespace v2
+} // namespace tracing
diff --git a/chromium/components/tracing/core/trace_buffer_writer.h b/chromium/components/tracing/core/trace_buffer_writer.h
new file mode 100644
index 00000000000..2a6b5e0bf93
--- /dev/null
+++ b/chromium/components/tracing/core/trace_buffer_writer.h
@@ -0,0 +1,103 @@
+// 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 COMPONENTS_TRACING_CORE_TRACE_BUFFER_WRITER_H_
+#define COMPONENTS_TRACING_CORE_TRACE_BUFFER_WRITER_H_
+
+#include "base/macros.h"
+#include "components/tracing/core/proto_zero_message.h"
+#include "components/tracing/core/proto_zero_message_handle.h"
+#include "components/tracing/core/scattered_stream_writer.h"
+#include "components/tracing/core/trace_ring_buffer.h"
+#include "components/tracing/tracing_export.h"
+
+// Fwd declaration from the generated components/tracing/proto/event.pbzero.h.
+namespace pbzero {
+namespace tracing {
+namespace proto {
+class Event;
+} // namespace proto
+} // namespace tracing
+} // namespace pbzero
+
+namespace tracing {
+namespace v2 {
+
+using TraceEventHandle = ProtoZeroMessageHandle<pbzero::tracing::proto::Event>;
+
+// This class is the entry-point to add events to the TraceRingBuffer.
+// It acts as a glue layer between the protobuf classes (ProtoZeroMessage) and
+// the chunked trace ring buffer (TraceRingBuffer). This class is deliberately
+// NOT thread safe. The expected design is that each thread owns an instance of
+// TraceBufferWriter and that trace events produced on one thread are not passed
+// to other threads.
+class TRACING_EXPORT TraceBufferWriter
+ : public ScatteredStreamWriter::Delegate {
+ public:
+ // |trace_ring_buffer| is the underlying ring buffer for taking and returning
+ // chunks. |writer_id| is an identifier, unique for each instance, which is
+ // appended to the header of each chunk. Its purpose is to allow the importer
+ // to reconstruct the logical sequence of chunks for a given writer. Think to
+ // this as a thread-id (just, in rare cases, some threads can have more than
+ // one writer).
+ TraceBufferWriter(TraceRingBuffer* trace_ring_buffer, uint32_t writer_id);
+ ~TraceBufferWriter() override;
+
+ // Adds a new event and returns a handle to it. The new event is valid (can be
+ // populated) until the next call to AddEvent(). The new event is finalized
+ // and fully committed to the ring buffer on the next call to AddEvent() or
+ // when the returned handle goes out of scope, whichever comes first.
+ TraceEventHandle AddEvent();
+
+ // ScatteredStreamWriter::Delegate implementation.
+ // Called by the ProtoZeroMessage's ScatteredStreamWriter when the caller
+ // tries to append a new field and the write overflows the current chunk.
+ ContiguousMemoryRange GetNewBuffer() override;
+
+ // Finalize the pending event (if any) and returns back all chunks to the
+ // |trace_ring_buffer_|.
+ void Flush();
+
+ const ScatteredStreamWriter& stream_writer() const { return stream_writer_; }
+
+ uint32_t writer_id() const { return writer_id_; }
+
+ private:
+ void FinalizeCurrentEvent();
+ void FinalizeCurrentChunk(bool is_fragmenting_event);
+ ContiguousMemoryRange AcquireNewChunk(bool event_continues_from_prev_chunk);
+ uint8_t* WriteEventPreambleForNewChunk(uint8_t* begin);
+
+ TraceRingBuffer* trace_ring_buffer_;
+
+ // Unique id of this writer (see comment in the ctor).
+ const uint32_t writer_id_;
+
+ // Monotonic counter (within the scope of writer_id_) of chunks.
+ uint32_t chunk_seq_id_;
+
+ // The last chunk acquired from the ring buffer. nullptr before the first call
+ // to AddEvent(). Each instance can own more than one chunk at any given time
+ // (to deal with messages larger than a chunk). This is being tracked through
+ // the singly linked list Chunk::next_in_owner_list().
+ TraceRingBuffer::Chunk* chunk_;
+
+ // Used to work out how many bytes for the current |event_| lie in the current
+ // |chunk_|.
+ uint8_t* event_data_start_in_current_chunk_;
+
+ ScatteredStreamWriter stream_writer_;
+
+ // This field should be a proto::Event. However, ProtoZeroMessage subclasses
+ // are stateless by design. This avoids to pull the full tree of autogenerated
+ // headers for the stub classes and reduce build time.
+ ProtoZeroMessage event_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceBufferWriter);
+};
+
+} // namespace v2
+} // namespace tracing
+
+#endif // COMPONENTS_TRACING_CORE_TRACE_BUFFER_WRITER_H_
diff --git a/chromium/components/tracing/core/trace_buffer_writer_unittest.cc b/chromium/components/tracing/core/trace_buffer_writer_unittest.cc
new file mode 100644
index 00000000000..662ed52fe04
--- /dev/null
+++ b/chromium/components/tracing/core/trace_buffer_writer_unittest.cc
@@ -0,0 +1,312 @@
+// 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 "components/tracing/core/trace_buffer_writer.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/tracing/core/trace_ring_buffer.h"
+#include "components/tracing/proto/event.pbzero.h"
+#include "components/tracing/test/golden_protos/events_chunk.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace tracing {
+namespace v2 {
+namespace {
+
+class MockEvent : public pbzero::tracing::proto::Event {
+ public:
+ static TraceEventHandle Add(TraceBufferWriter* writer, size_t event_size) {
+ TraceEventHandle handle = writer->AddEvent();
+ MockEvent* mock_event = static_cast<MockEvent*>(&*handle);
+
+ size_t buffer_size = 0;
+ DCHECK_GT(event_size, 2u);
+ if (event_size < (1 << 7) + 2)
+ buffer_size = event_size - 2;
+ else if (event_size < (1 << 14) + 3)
+ buffer_size = event_size - 3;
+ else if (event_size < (1 << 21) + 4)
+ buffer_size = event_size - 4;
+ else
+ NOTREACHED();
+
+ DCHECK(buffer_size);
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[buffer_size]);
+ memset(buf.get(), 0, buffer_size);
+ mock_event->AppendBytes(1, buf.get(), buffer_size);
+
+ return handle;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockEvent);
+};
+
+constexpr uint32_t kNumChunks = 10;
+constexpr size_t kBufferSize = kNumChunks * kChunkSize;
+
+class TraceBufferWriterTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ ring_buf_mem_.reset(new uint8_t[kBufferSize]);
+ memset(ring_buf_mem_.get(), 0, kBufferSize);
+ ring_buf_.reset(new TraceRingBuffer(ring_buf_mem_.get(), kBufferSize));
+
+ // Estimate the size required to fill one event.
+ std::unique_ptr<TraceBufferWriter> writer = CreateWriter(1);
+ MockEvent::Add(&*writer, 4);
+ event_size_to_fill_chunk_ = writer->stream_writer().bytes_available() + 4;
+ writer.reset();
+ ring_buf_.reset(new TraceRingBuffer(ring_buf_mem_.get(), kBufferSize));
+ }
+
+ void TearDown() override {
+ ring_buf_.reset();
+ ring_buf_mem_.reset();
+ }
+
+ std::unique_ptr<TraceBufferWriter> CreateWriter(uint32_t writer_id) {
+ return base::WrapUnique(new TraceBufferWriter(ring_buf_.get(), writer_id));
+ }
+
+ const TraceRingBuffer::Chunk* GetChunk(uint32_t i) {
+ DCHECK_LT(i, kNumChunks);
+ return &ring_buf_->chunks_for_testing()[i];
+ }
+
+ ::tracing::proto::EventsChunk ReadBackAndTestChunk(
+ uint32_t chunk_id,
+ uint32_t expected_writer_id,
+ uint32_t expected_seq_id,
+ int expected_num_events,
+ bool expected_first_event_continues,
+ bool expected_last_event_continues) {
+ const TraceRingBuffer::Chunk* chunk = GetChunk(chunk_id);
+ ::tracing::proto::EventsChunk parsed_chunk;
+ EXPECT_TRUE(
+ parsed_chunk.ParseFromArray(chunk->payload(), chunk->used_size()));
+
+ EXPECT_TRUE(parsed_chunk.has_writer_id());
+ EXPECT_EQ(expected_writer_id, parsed_chunk.writer_id());
+
+ EXPECT_TRUE(parsed_chunk.has_seq_id());
+ EXPECT_EQ(expected_seq_id, parsed_chunk.seq_id());
+
+ EXPECT_EQ(expected_first_event_continues,
+ parsed_chunk.first_event_continues_from_prev_chunk());
+ EXPECT_EQ(expected_last_event_continues,
+ parsed_chunk.last_event_continues_on_next_chunk());
+ EXPECT_EQ(expected_num_events, parsed_chunk.events_size());
+ return parsed_chunk;
+ }
+
+ const TraceRingBuffer& ring_buffer() const { return *ring_buf_; }
+ size_t event_size_to_fill_chunk() const { return event_size_to_fill_chunk_; }
+
+ private:
+ std::unique_ptr<uint8_t[]> ring_buf_mem_;
+ std::unique_ptr<TraceRingBuffer> ring_buf_;
+ size_t event_size_to_fill_chunk_;
+};
+
+TEST_F(TraceBufferWriterTest, SingleEvent) {
+ const uint32_t kWriterId = 0x42;
+ std::unique_ptr<TraceBufferWriter> writer = CreateWriter(kWriterId);
+ MockEvent::Add(writer.get(), 7);
+ writer->Flush();
+
+ auto parsed_chunk = ReadBackAndTestChunk(0, kWriterId, 0, 1, false, false);
+ EXPECT_EQ(7u, parsed_chunk.events(0).size());
+}
+
+TEST_F(TraceBufferWriterTest, ManySmallEvents) {
+ const uint32_t kWriterId = 0x42;
+ std::unique_ptr<TraceBufferWriter> writer = CreateWriter(kWriterId);
+
+ uint32_t last_owned_chunk_id = 1;
+ uint32_t num_times_did_switch_to_chunk[kNumChunks] = {};
+
+ // kBufferSize here is just an upper bound to prevent the test to get stuck
+ // undefinitely in the loop if it fails.
+ for (size_t i = 0; i < kBufferSize; i++) {
+ MockEvent::Add(&*writer, 5);
+
+ // Small events shouldn't never cause more than a chunk to be owned. Check
+ // that TraceBufferWriter doesn't accidentally retain chunks.
+ uint32_t num_chunks_owned = 0;
+ for (uint32_t chunk_id = 0; chunk_id < kNumChunks; chunk_id++) {
+ const bool is_owned = GetChunk(chunk_id)->is_owned();
+ num_chunks_owned += is_owned ? 1 : 0;
+ if (is_owned && chunk_id != last_owned_chunk_id) {
+ last_owned_chunk_id = chunk_id;
+ num_times_did_switch_to_chunk[chunk_id]++;
+ }
+ }
+ ASSERT_EQ(1u, num_chunks_owned);
+
+ // Stop once the last chunk has been filled twice.
+ if (num_times_did_switch_to_chunk[kNumChunks - 1] == 2)
+ break;
+ }
+
+ // Test the wrap-over logic: all chunks should have been filled twice.
+ for (uint32_t chunk_id = 0; chunk_id < kNumChunks; chunk_id++)
+ EXPECT_EQ(2u, num_times_did_switch_to_chunk[chunk_id]);
+
+ // Test that Flush() releases all chunks.
+ writer->Flush();
+ for (uint32_t chunk_id = 0; chunk_id < kNumChunks; chunk_id++)
+ EXPECT_FALSE(GetChunk(chunk_id)->is_owned());
+}
+
+TEST_F(TraceBufferWriterTest, OneWriterWithFragmentingEvents) {
+ const uint32_t kWriterId = 0x42;
+ std::unique_ptr<TraceBufferWriter> writer = CreateWriter(kWriterId);
+
+ MockEvent::Add(&*writer, event_size_to_fill_chunk());
+
+ EXPECT_TRUE(GetChunk(0)->is_owned());
+ EXPECT_FALSE(GetChunk(1)->is_owned());
+
+ MockEvent::Add(&*writer, event_size_to_fill_chunk());
+ EXPECT_TRUE(GetChunk(1)->is_owned());
+ EXPECT_FALSE(GetChunk(2)->is_owned());
+
+ // Create one event which starts at the beginning of chunk 2 and overflows
+ // into chunk 3.
+ MockEvent::Add(&*writer, event_size_to_fill_chunk() + 1);
+ EXPECT_TRUE(GetChunk(2)->is_owned());
+ EXPECT_TRUE(GetChunk(3)->is_owned());
+
+ // Adding a new event should cause the chunk 2 to be released, while chunk
+ // 3 is still retained.
+ MockEvent::Add(&*writer, 4);
+ EXPECT_FALSE(GetChunk(2)->is_owned());
+ EXPECT_TRUE(GetChunk(3)->is_owned());
+
+ // Now add a very large event which spans across 3 chunks (chunks 3, 4 and 5).
+ MockEvent::Add(&*writer, event_size_to_fill_chunk() * 2 + 1);
+ EXPECT_TRUE(GetChunk(3)->is_owned());
+ EXPECT_TRUE(GetChunk(4)->is_owned());
+ EXPECT_TRUE(GetChunk(5)->is_owned());
+
+ // Add a final small event and check that chunks 3 and 4 are released.
+ MockEvent::Add(&*writer, 4);
+ EXPECT_FALSE(GetChunk(3)->is_owned());
+ EXPECT_FALSE(GetChunk(4)->is_owned());
+ EXPECT_TRUE(GetChunk(5)->is_owned());
+
+ // Flush and readback the chunks using the official protos.
+ writer->Flush();
+
+ // The first two chunks should have one event each, neither of them wrapping.
+ auto chunk = ReadBackAndTestChunk(0, kWriterId, 0, 1, false, false);
+ EXPECT_EQ(event_size_to_fill_chunk(), chunk.events(0).size());
+
+ chunk = ReadBackAndTestChunk(1, kWriterId, 1, 1, false, false);
+ EXPECT_EQ(event_size_to_fill_chunk(), chunk.events(0).size());
+
+ // Chunk 2 should have one partial event, which overflows into 3.
+ chunk = ReadBackAndTestChunk(2, kWriterId, 2, 1, false, true);
+ EXPECT_EQ(event_size_to_fill_chunk(), chunk.events(0).size());
+
+ // Chunk 3 should have the overflowing event from above, a small event, and
+ // the beginning of the very large event.
+ chunk = ReadBackAndTestChunk(3, kWriterId, 3, 3, true, true);
+ EXPECT_EQ(4u, chunk.events(1).size());
+
+ // Chunk 4 should contain the partial continuation of the large event.
+ chunk = ReadBackAndTestChunk(4, kWriterId, 4, 1, true, true);
+ EXPECT_EQ(event_size_to_fill_chunk() - 2, chunk.events(0).size());
+
+ // Chunk 5 should contain the end of the large event and the final small one.
+ chunk = ReadBackAndTestChunk(5, kWriterId, 5, 2, true, false);
+ EXPECT_EQ(4u, chunk.events(1).size());
+}
+
+TEST_F(TraceBufferWriterTest, ManyWriters) {
+ const uint32_t kNumWriters = kNumChunks / 2;
+ std::unique_ptr<TraceBufferWriter> writer[kNumWriters];
+
+ for (uint32_t i = 0; i < kNumWriters; ++i) {
+ writer[i] = CreateWriter(i + 1);
+ MockEvent::Add(writer[i].get(), 4);
+ EXPECT_EQ(writer[i]->writer_id(), GetChunk(i)->owner());
+ }
+
+ // Write one large and one small event on each writer.
+ for (uint32_t i = 0; i < kNumWriters; ++i) {
+ MockEvent::Add(writer[i].get(), event_size_to_fill_chunk());
+ MockEvent::Add(writer[i].get(), 5 + i);
+ }
+
+ // At this point the first 5 chunks should be returned and the last 5 owned
+ // by the respective 5 writers.
+ for (uint32_t i = 0; i < kNumWriters; ++i)
+ EXPECT_FALSE(GetChunk(i)->is_owned());
+ for (uint32_t i = kNumWriters; i < kNumWriters * 2; ++i)
+ EXPECT_EQ(writer[i - kNumWriters]->writer_id(), GetChunk(i)->owner());
+
+ // Write one large event to writer 0 (currently owning chunk 5). That will
+ // make it return the chunk 5 and take ownership of chunks [0, 4].
+ MockEvent::Add(writer[0].get(), event_size_to_fill_chunk());
+ auto retain_event =
+ MockEvent::Add(writer[0].get(), event_size_to_fill_chunk() * 4 + 1);
+ for (uint32_t i = 0; i < 5; ++i)
+ EXPECT_EQ(writer[0]->writer_id(), GetChunk(i)->owner());
+
+ // At this point the only free chunk is chunk 5. Attempting a write from
+ // another writer should fill that.
+ EXPECT_FALSE(GetChunk(5)->is_owned());
+ auto retain_event_2 =
+ MockEvent::Add(writer[3].get(), event_size_to_fill_chunk());
+
+ // Now all the chunks are taken.
+ for (uint32_t i = 0; i < kNumChunks; ++i)
+ EXPECT_TRUE(GetChunk(i)->is_owned());
+
+ // An attempt to write a larger event on another write should cause the ring
+ // buffer to fall in bankrupcy mode.
+ auto retain_event_3 =
+ MockEvent::Add(writer[4].get(), event_size_to_fill_chunk());
+ EXPECT_EQ(ring_buffer().num_chunks(), ring_buffer().GetNumChunksTaken());
+
+ // A small writer to the writer 0 should cause it to return all chunks but the
+ // last one and leave the bankrupcy chunk.
+ retain_event = MockEvent::Add(writer[0].get(), 7);
+ EXPECT_LT(ring_buffer().GetNumChunksTaken(), ring_buffer().num_chunks());
+ EXPECT_EQ(writer[0]->writer_id(), GetChunk(4)->owner());
+ for (uint32_t i = 0; i < 3; ++i)
+ EXPECT_FALSE(GetChunk(i)->is_owned());
+
+ // Flush all the writers and test that all chunks are returned.
+ for (uint32_t i = 0; i < kNumWriters; ++i)
+ writer[i]->Flush();
+ for (uint32_t i = 0; i < kNumChunks; ++i)
+ EXPECT_FALSE(GetChunk(i)->is_owned());
+
+ // Readback and test the content of the chunks.
+
+ auto chunk =
+ ReadBackAndTestChunk(4, writer[0]->writer_id(), 6, 2, true, false);
+ EXPECT_EQ(7u, chunk.events(1).size());
+
+ // writer[1] and writer[2] just have a continuation and a small event each.
+ chunk = ReadBackAndTestChunk(6, writer[1]->writer_id(), 1, 2, true, false);
+ EXPECT_EQ(5u + 1, chunk.events(1).size());
+
+ chunk = ReadBackAndTestChunk(7, writer[2]->writer_id(), 1, 2, true, false);
+ EXPECT_EQ(5u + 2, chunk.events(1).size());
+
+ // writer[3] did the last write before the bankrupcy and has one extra event.
+ ReadBackAndTestChunk(8, writer[3]->writer_id(), 1, 3, true, true);
+
+ // writer[4] overflew in the bankrupcy chunk and has 3 events as well.
+ ReadBackAndTestChunk(9, writer[4]->writer_id(), 1, 3, true, true);
+}
+
+} // namespace
+} // namespace v2
+} // namespace tracing
diff --git a/chromium/components/tracing/core/trace_ring_buffer.cc b/chromium/components/tracing/core/trace_ring_buffer.cc
index 2a52bf61db1..582ed279ccc 100644
--- a/chromium/components/tracing/core/trace_ring_buffer.cc
+++ b/chromium/components/tracing/core/trace_ring_buffer.cc
@@ -10,20 +10,22 @@ namespace tracing {
namespace v2 {
TraceRingBuffer::TraceRingBuffer(uint8_t* begin, size_t size)
- : num_chunks_(size / Chunk::kSize), current_chunk_idx_(0) {
+ : num_chunks_(size / kChunkSize),
+ num_chunks_taken_(0),
+ current_chunk_idx_(0) {
DCHECK_GT(num_chunks_, 0u);
DCHECK_EQ(0ul, reinterpret_cast<uintptr_t>(begin) % sizeof(uintptr_t));
chunks_.reset(new Chunk[num_chunks_]);
uint8_t* chunk_begin = begin;
for (size_t i = 0; i < num_chunks_; ++i) {
chunks_[i].Initialize(chunk_begin);
- chunk_begin += Chunk::kSize;
+ chunk_begin += kChunkSize;
}
}
TraceRingBuffer::~TraceRingBuffer() {}
-TraceRingBuffer::Chunk* TraceRingBuffer::TakeChunk() {
+TraceRingBuffer::Chunk* TraceRingBuffer::TakeChunk(uint32_t writer_id) {
base::AutoLock lock(lock_);
DCHECK_GT(num_chunks_, 0ul);
DCHECK_LT(current_chunk_idx_, num_chunks_);
@@ -32,34 +34,56 @@ TraceRingBuffer::Chunk* TraceRingBuffer::TakeChunk() {
current_chunk_idx_ = (current_chunk_idx_ + 1) % num_chunks_;
if (!chunk->is_owned()) {
chunk->Clear();
- chunk->set_owner(base::PlatformThread::CurrentId());
+ DCHECK_NE(0u, writer_id);
+ chunk->set_owner(writer_id);
+ num_chunks_taken_++;
return chunk;
}
}
// Bankrupcy: there are more threads than chunks. All chunks were in flight.
if (!bankrupcy_chunk_storage_) {
- bankrupcy_chunk_storage_.reset(new uint8_t[Chunk::kSize]);
+ bankrupcy_chunk_storage_.reset(new uint8_t[kChunkSize]);
bankrupcy_chunk_.Initialize(&bankrupcy_chunk_storage_.get()[0]);
}
bankrupcy_chunk_.Clear();
return &bankrupcy_chunk_;
}
-void TraceRingBuffer::ReturnChunk(TraceRingBuffer::Chunk* chunk,
- uint32_t used_size) {
+void TraceRingBuffer::ReturnChunk(TraceRingBuffer::Chunk* chunk) {
+ // Returning a chunk without using it is quite odd, very likely a bug.
+ DCHECK_GT(chunk->used_size(), 0u);
+
+ // The caller should never return chunks which are part of a retaining chain.
+ DCHECK(!chunk->next_in_owner_list());
+
+ if (chunk == &bankrupcy_chunk_)
+ return;
+
+ // TODO(primiano): this lock might be removed in favor of acquire/release
+ // semantics on the two vars below. Check once the reader of these are landed.
base::AutoLock lock(lock_);
- chunk->set_used_size(used_size);
chunk->clear_owner();
+ num_chunks_taken_--;
+}
+
+bool TraceRingBuffer::IsBankrupcyChunkForTesting(const Chunk* chunk) const {
+ return chunk == &bankrupcy_chunk_;
+}
+
+size_t TraceRingBuffer::GetNumChunksTaken() const {
+ base::AutoLock lock(lock_);
+ return num_chunks_taken_;
}
TraceRingBuffer::Chunk::Chunk()
- : begin_(nullptr), owner_(base::kInvalidThreadId) {}
+ : begin_(nullptr), owner_(kNoChunkOwner), next_in_owner_list_(nullptr) {}
TraceRingBuffer::Chunk::~Chunk() {}
void TraceRingBuffer::Chunk::Clear() {
set_used_size(0);
+ set_next_in_owner_list(nullptr);
}
void TraceRingBuffer::Chunk::Initialize(uint8_t* begin) {
diff --git a/chromium/components/tracing/core/trace_ring_buffer.h b/chromium/components/tracing/core/trace_ring_buffer.h
index 4a86a8bbc4f..88ac3503b14 100644
--- a/chromium/components/tracing/core/trace_ring_buffer.h
+++ b/chromium/components/tracing/core/trace_ring_buffer.h
@@ -5,21 +5,24 @@
#ifndef COMPONENTS_TRACING_CORE_TRACE_RING_BUFFER_H_
#define COMPONENTS_TRACING_CORE_TRACE_RING_BUFFER_H_
+#include <memory>
+
#include "base/atomicops.h"
#include "base/macros.h"
#include "base/synchronization/lock.h"
-#include "base/threading/thread.h"
#include "components/tracing/tracing_export.h"
namespace tracing {
namespace v2 {
+static const uint32_t kNoChunkOwner = 0;
+static const size_t kChunkSize = 32 * 1024;
+
class TRACING_EXPORT TraceRingBuffer {
public:
class Chunk {
public:
using Header = base::subtle::Atomic32;
- static constexpr size_t kSize = 32 * 1024;
Chunk();
~Chunk();
@@ -30,7 +33,7 @@ class TRACING_EXPORT TraceRingBuffer {
uint8_t* begin() const { return begin_; }
Header* header() const { return reinterpret_cast<Header*>(begin_); }
uint8_t* payload() const { return begin_ + sizeof(Header); }
- uint8_t* end() const { return begin_ + kSize; }
+ uint8_t* end() const { return begin_ + kChunkSize; }
void set_used_size(uint32_t size) {
base::subtle::NoBarrier_Store(header(), size);
@@ -39,14 +42,26 @@ class TRACING_EXPORT TraceRingBuffer {
return base::subtle::NoBarrier_Load(header());
}
+ void set_next_in_owner_list(Chunk* next) { next_in_owner_list_ = next; }
+ Chunk* next_in_owner_list() const { return next_in_owner_list_; }
+
+ // Owner is a flag matching the id of the TraceBufferWriter, 0 if not owned.
// Accesses to |owner_| must happen under the buffer |lock_|.
- bool is_owned() const { return owner_ != base::kInvalidThreadId; }
- void clear_owner() { owner_ = base::kInvalidThreadId; }
- void set_owner(base::PlatformThreadId tid) { owner_ = tid; }
+ bool is_owned() const { return owner_ != kNoChunkOwner; }
+ uint32_t owner() const { return owner_; }
+ void clear_owner() { owner_ = kNoChunkOwner; }
+ void set_owner(uint32_t owner) {
+ DCHECK_NE(kNoChunkOwner, owner);
+ owner_ = owner;
+ }
private:
uint8_t* begin_;
- base::PlatformThreadId owner_; // kInvalidThreadId -> Chunk is not owned.
+ uint32_t owner_;
+
+ // When a chunk is owned, this is the next pointer to keep track of all
+ // owned chunks in a singly linked list.
+ Chunk* next_in_owner_list_;
DISALLOW_COPY_AND_ASSIGN(Chunk);
};
@@ -54,13 +69,23 @@ class TRACING_EXPORT TraceRingBuffer {
TraceRingBuffer(uint8_t* begin, size_t size);
~TraceRingBuffer();
- Chunk* TakeChunk();
- void ReturnChunk(Chunk* chunk, uint32_t used_size);
+ Chunk* TakeChunk(uint32_t writer_id);
+ void ReturnChunk(Chunk* chunk);
+
+ size_t num_chunks() const { return num_chunks_; }
+
+ // Returns the number of chunks taken and not returned, without counting any
+ // bankrupcy chunk obtained when the ring buffer was full.
+ size_t GetNumChunksTaken() const;
+
+ const Chunk* chunks_for_testing() const { return chunks_.get(); }
+ bool IsBankrupcyChunkForTesting(const Chunk*) const;
private:
- base::Lock lock_;
+ mutable base::Lock lock_;
std::unique_ptr<Chunk[]> chunks_;
const size_t num_chunks_;
+ size_t num_chunks_taken_;
size_t current_chunk_idx_;
// An emergency chunk used in the rare case in which all chunks are in flight.
diff --git a/chromium/components/tracing/core/trace_ring_buffer_unittest.cc b/chromium/components/tracing/core/trace_ring_buffer_unittest.cc
index 0738f82516d..5a1a41b3b13 100644
--- a/chromium/components/tracing/core/trace_ring_buffer_unittest.cc
+++ b/chromium/components/tracing/core/trace_ring_buffer_unittest.cc
@@ -11,29 +11,29 @@ namespace v2 {
namespace {
-const size_t kChunkSize = TraceRingBuffer::Chunk::kSize;
-
-bool overlap(uint8_t* start1, uint8_t* end1, uint8_t* start2, uint8_t* end2) {
- return start1 < end2 && start2 < end1;
-}
-
TEST(TraceRingBufferTest, BasicChunkWrapping) {
const uint32_t kNumChunks = 5;
const size_t kBufferSize = kChunkSize * kNumChunks;
std::unique_ptr<uint8_t[]> storage(new uint8_t[kBufferSize]);
TraceRingBuffer ring_buffer(storage.get(), kBufferSize);
+ EXPECT_EQ(0u, ring_buffer.GetNumChunksTaken());
uint8_t* last_chunk_end = nullptr;
+
// Fill the buffer twice to test wrapping logic.
for (uint32_t i = 0; i < kNumChunks * 2; ++i) {
- TraceRingBuffer::Chunk* chunk = ring_buffer.TakeChunk();
+ TraceRingBuffer::Chunk* chunk = ring_buffer.TakeChunk(42 /* owner */);
ASSERT_NE(nullptr, chunk);
+ EXPECT_EQ(1u, ring_buffer.GetNumChunksTaken());
+ EXPECT_EQ(42u, chunk->owner());
const uint32_t chunk_idx = i % kNumChunks;
EXPECT_EQ(chunk_idx == 0 ? storage.get() : last_chunk_end, chunk->begin());
const uint32_t kPayloadSize = (chunk_idx + 1) * 8;
memset(chunk->payload(), static_cast<int>(chunk_idx + 1), kPayloadSize);
last_chunk_end = chunk->end();
- ring_buffer.ReturnChunk(chunk, /* used_size = */ kPayloadSize);
+ chunk->set_used_size(kPayloadSize);
+ ring_buffer.ReturnChunk(chunk);
+ EXPECT_EQ(0u, ring_buffer.GetNumChunksTaken());
}
// Now scrape the |storage| buffer and check its contents.
@@ -48,32 +48,35 @@ TEST(TraceRingBufferTest, BasicChunkWrapping) {
TEST(TraceRingBufferTest, ChunkBankrupcyDoesNotCrash) {
const size_t kNumChunks = 2;
- const size_t kBufferSize = TraceRingBuffer::Chunk::kSize * kNumChunks;
+ const size_t kBufferSize = kChunkSize * kNumChunks;
std::unique_ptr<uint8_t[]> storage(new uint8_t[kBufferSize]);
TraceRingBuffer ring_buffer(storage.get(), kBufferSize);
- TraceRingBuffer::Chunk* chunk1 = ring_buffer.TakeChunk();
+ TraceRingBuffer::Chunk* chunk1 = ring_buffer.TakeChunk(1);
ASSERT_NE(nullptr, chunk1);
- TraceRingBuffer::Chunk* chunk2 = ring_buffer.TakeChunk();
+ TraceRingBuffer::Chunk* chunk2 = ring_buffer.TakeChunk(1);
ASSERT_NE(nullptr, chunk2);
+ EXPECT_EQ(2u, ring_buffer.GetNumChunksTaken());
+
for (int i = 0; i < 3; ++i) {
- TraceRingBuffer::Chunk* bankrupcy_chunk = ring_buffer.TakeChunk();
+ TraceRingBuffer::Chunk* bankrupcy_chunk = ring_buffer.TakeChunk(1);
ASSERT_NE(nullptr, bankrupcy_chunk);
- ASSERT_FALSE(overlap(bankrupcy_chunk->begin(), bankrupcy_chunk->end(),
- storage.get(), storage.get() + kBufferSize));
+ ASSERT_TRUE(ring_buffer.IsBankrupcyChunkForTesting(bankrupcy_chunk));
// Make sure that the memory of the bankrupty chunk can be dereferenced.
memset(bankrupcy_chunk->begin(), 0, kChunkSize);
}
+ EXPECT_EQ(2u, ring_buffer.GetNumChunksTaken());
// Return a chunk and check that the ring buffer is not bankrupt anymore.
- ring_buffer.ReturnChunk(chunk2, 42);
- TraceRingBuffer::Chunk* chunk = ring_buffer.TakeChunk();
+ chunk2->set_used_size(42);
+ ring_buffer.ReturnChunk(chunk2);
+ EXPECT_EQ(1u, ring_buffer.GetNumChunksTaken());
+ TraceRingBuffer::Chunk* chunk = ring_buffer.TakeChunk(1);
ASSERT_NE(nullptr, chunk);
- ASSERT_TRUE(overlap(chunk->begin(), chunk->end(), storage.get(),
- storage.get() + kBufferSize));
+ ASSERT_FALSE(ring_buffer.IsBankrupcyChunkForTesting(chunk));
}
} // namespace
diff --git a/chromium/components/tracing/docs/adding_memory_infra_tracing.md b/chromium/components/tracing/docs/adding_memory_infra_tracing.md
index f60f65e7f5a..7960e153dd1 100644
--- a/chromium/components/tracing/docs/adding_memory_infra_tracing.md
+++ b/chromium/components/tracing/docs/adding_memory_infra_tracing.md
@@ -148,7 +148,7 @@ base::trace_event::MemoryAllocatorDump* target_mad =
// When creating an edge, you can assign an importance to this edge. If all
// edges have the same importance, the size of the allocation will be split
// between all sources which create a dump for the allocation. If one
-// edge has higher importance than the others, its soruce will be assigned the
+// edge has higher importance than the others, its source will be assigned the
// full size of the allocation.
const int kImportance = 1;
process_memory_dump->AddOwnershipEdge(
diff --git a/chromium/components/tracing/proto/BUILD.gn b/chromium/components/tracing/proto/BUILD.gn
new file mode 100644
index 00000000000..263b05a65ee
--- /dev/null
+++ b/chromium/components/tracing/proto/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+tracing_proto_sources = [
+ "event.proto",
+ "events_chunk.proto",
+]
+
+# Stubs generated using custom plugin.
+proto_library("protos") {
+ visibility = [ "//components/tracing/*" ]
+
+ proto_in_dir = "."
+ sources = tracing_proto_sources
+
+ generator_plugin_label =
+ "//components/tracing/tools/proto_zero_plugin:proto_zero_plugin"
+ generator_plugin_suffix = ".pbzero"
+ generator_plugin_options = "wrapper_namespace=pbzero"
+ generate_cc = false
+ generate_python = false
+}
+
+# Official protobuf C++ stubs to test conformance.
+proto_library("golden_protos_for_tests") {
+ visibility = [ "//components/tracing/*" ]
+ testonly = true
+
+ proto_in_dir = "."
+ proto_out_dir = "components/tracing/test/golden_protos"
+ sources = tracing_proto_sources
+
+ generate_python = false
+}
diff --git a/chromium/components/tracing/proto/event.proto b/chromium/components/tracing/proto/event.proto
new file mode 100644
index 00000000000..24bb7ad93ce
--- /dev/null
+++ b/chromium/components/tracing/proto/event.proto
@@ -0,0 +1,35 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package tracing.proto;
+
+// Note on field numbers: fields in the range [1, 15] can be encoded using a
+// single byte preamble. Hence they should be used only for the most commonly
+// used fields (to save trace size). Use the range 16+ for fields that are not
+// expected to be used frequently.
+message Event {
+ // Using ASCII codes as enum values, according to the legacy phase arguments
+ // ("ph") of the Trace Event Format doc (https://goo.gl/mSXylN).
+ enum EventType {
+ METADATA = 77; // = 'M'.
+ COMPLETE = 88; // = 'X'.
+ };
+
+ optional EventType type = 1;
+
+ oneof name {
+ int64 name_id = 2;
+ string name_str = 16;
+ }
+
+ optional int64 category_id = 4;
+
+ optional uint64 timestamp = 5;
+ optional uint64 thread_timestamp = 6;
+
+ // TODO(primiano,kraynov): Add args and further fields in next CLs.
+}
diff --git a/chromium/components/tracing/proto/events_chunk.proto b/chromium/components/tracing/proto/events_chunk.proto
new file mode 100644
index 00000000000..aedec76048c
--- /dev/null
+++ b/chromium/components/tracing/proto/events_chunk.proto
@@ -0,0 +1,36 @@
+// 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.
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package tracing.proto;
+
+// An EventsChunk is a fixed portion of the trace ring buffer which is written
+// exclusively by one writer (almost always 1 writer == 1 thread). It contains
+// a variable number of variable-sized events. Events can be fragmented across
+// several chunks.
+
+message EventsChunk {
+ // Chunks produced by the same trace writer have the same writer_id. This
+ // allows to identify the next chunk for a writer (thread) in the ring buffer.
+ optional uint32 writer_id = 1;
+
+ // A monotonic counter within the writer, to establish sequencing of chunks.
+ optional uint32 seq_id = 2;
+
+ // Each event is a byte sequence that encapsulates the bytes for a single
+ // Event (see event.proto) or an incomplete fragment.
+ // Why this isn't just a "repeated Events" field? An Event can spawn across
+ // several chunks. In this case the reader has to first glue the byte
+ // sequences together and then process the event.
+ repeated bytes events = 3;
+
+ // The first entry of |events| is a fragment which continues from the previous
+ // chunk.
+ optional bool first_event_continues_from_prev_chunk = 4;
+
+ // The last entry of |events| is a fragment and contiues into the next chunk.
+ optional bool last_event_continues_on_next_chunk = 5;
+}
diff --git a/chromium/components/tracing/tools/proto_zero_plugin/BUILD.gn b/chromium/components/tracing/tools/proto_zero_plugin/BUILD.gn
new file mode 100644
index 00000000000..cdf0eb16073
--- /dev/null
+++ b/chromium/components/tracing/tools/proto_zero_plugin/BUILD.gn
@@ -0,0 +1,16 @@
+# 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.
+
+if (current_toolchain == host_toolchain) {
+ executable("proto_zero_plugin") {
+ sources = [
+ "proto_zero_generator.cc",
+ "proto_zero_generator.h",
+ "proto_zero_plugin.cc",
+ ]
+ deps = [
+ "//third_party/protobuf:protoc_lib",
+ ]
+ }
+}
diff --git a/chromium/components/tracing/tools/proto_zero_plugin/DEPS b/chromium/components/tracing/tools/proto_zero_plugin/DEPS
new file mode 100644
index 00000000000..97db67c0df7
--- /dev/null
+++ b/chromium/components/tracing/tools/proto_zero_plugin/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+third_party/protobuf",
+]
diff --git a/chromium/components/tracing/tools/proto_zero_plugin/proto_zero_generator.cc b/chromium/components/tracing/tools/proto_zero_plugin/proto_zero_generator.cc
new file mode 100644
index 00000000000..cd2a0c9509c
--- /dev/null
+++ b/chromium/components/tracing/tools/proto_zero_plugin/proto_zero_generator.cc
@@ -0,0 +1,660 @@
+// 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 "proto_zero_generator.h"
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "third_party/protobuf/src/google/protobuf/descriptor.h"
+#include "third_party/protobuf/src/google/protobuf/io/printer.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h"
+#include "third_party/protobuf/src/google/protobuf/stubs/strutil.h"
+
+namespace tracing {
+namespace proto {
+
+using google::protobuf::Descriptor; // Message descriptor.
+using google::protobuf::EnumDescriptor;
+using google::protobuf::EnumValueDescriptor;
+using google::protobuf::FieldDescriptor;
+using google::protobuf::FileDescriptor;
+using google::protobuf::compiler::GeneratorContext;
+using google::protobuf::io::Printer;
+using google::protobuf::io::ZeroCopyOutputStream;
+
+using google::protobuf::Split;
+using google::protobuf::StripPrefixString;
+using google::protobuf::StripString;
+using google::protobuf::StripSuffixString;
+using google::protobuf::UpperString;
+
+namespace {
+
+inline std::string ProtoStubName(const FileDescriptor* proto) {
+ return StripSuffixString(proto->name(), ".proto") + ".pbzero";
+}
+
+class GeneratorJob {
+ public:
+ GeneratorJob(const FileDescriptor *file,
+ Printer* stub_h_printer,
+ Printer* stub_cc_printer)
+ : source_(file), stub_h_(stub_h_printer), stub_cc_(stub_cc_printer) {
+ }
+
+ bool GenerateStubs() {
+ Preprocess();
+ GeneratePrologue();
+ for (const EnumDescriptor* enumeration: enums_)
+ GenerateEnumDescriptor(enumeration);
+ for (const Descriptor* message : messages_)
+ GenerateMessageDescriptor(message);
+ GenerateEpilogue();
+ return error_.empty();
+ }
+
+ void SetOption(const std::string& name, const std::string& value) {
+ if (name == "wrapper_namespace") {
+ wrapper_namespace_ = value;
+ } else {
+ Abort(std::string() + "Unknown plugin option '" + name + "'.");
+ }
+ }
+
+ // If generator fails to produce stubs for a particular proto definitions
+ // it finishes with undefined output and writes the first error occured.
+ const std::string& GetFirstError() const {
+ return error_;
+ }
+
+ private:
+ // Only the first error will be recorded.
+ void Abort(const std::string& reason) {
+ if (error_.empty())
+ error_ = reason;
+ }
+
+ // Get full name (including outer descriptors) of proto descriptor.
+ template <class T>
+ inline std::string GetDescriptorName(const T* descriptor) {
+ if (!package_.empty()) {
+ return StripPrefixString(descriptor->full_name(), package_ + ".");
+ } else {
+ return descriptor->full_name();
+ }
+ }
+
+ // Get C++ class name corresponding to proto descriptor.
+ // Nested names are splitted by underscores. Underscores in type names aren't
+ // prohibited but not recommended in order to avoid name collisions.
+ template <class T>
+ inline std::string GetCppClassName(const T* descriptor, bool full = false) {
+ std::string name = GetDescriptorName(descriptor);
+ StripString(&name, ".", '_');
+ if (full)
+ name = full_namespace_prefix_ + name;
+ return name;
+ }
+
+ inline std::string GetFieldNumberConstant(const FieldDescriptor* field) {
+ std::string name = field->camelcase_name();
+ if (!name.empty()) {
+ name.at(0) = toupper(name.at(0));
+ name = "k" + name + "FieldNumber";
+ } else {
+ // Protoc allows fields like 'bool _ = 1'.
+ Abort("Empty field name in camel case notation.");
+ }
+ return name;
+ }
+
+ // Small enums can be written faster without involving VarInt encoder.
+ inline bool IsTinyEnumField(const FieldDescriptor* field) {
+ if (field->type() != FieldDescriptor::TYPE_ENUM)
+ return false;
+ const EnumDescriptor* enumeration = field->enum_type();
+
+ for (int i = 0; i < enumeration->value_count(); ++i) {
+ int32_t value = enumeration->value(i)->number();
+ if (value < 0 || value > 0x7F)
+ return false;
+ }
+ return true;
+ }
+
+ void CollectDescriptors() {
+ // Collect message descriptors in DFS order.
+ std::vector<const Descriptor*> stack;
+ for (int i = 0; i < source_->message_type_count(); ++i)
+ stack.push_back(source_->message_type(i));
+
+ while (!stack.empty()) {
+ const Descriptor* message = stack.back();
+ stack.pop_back();
+ messages_.push_back(message);
+ for (int i = 0; i < message->nested_type_count(); ++i) {
+ stack.push_back(message->nested_type(i));
+ }
+ }
+
+ // Collect enums.
+ for (int i = 0; i < source_->enum_type_count(); ++i)
+ enums_.push_back(source_->enum_type(i));
+
+ for (const Descriptor* message : messages_) {
+ for (int i = 0; i < message->enum_type_count(); ++i) {
+ enums_.push_back(message->enum_type(i));
+ }
+ }
+ }
+
+ void CollectDependencies() {
+ // Public import basically means that callers only need to import this
+ // proto in order to use the stuff publicly imported by this proto.
+ for (int i = 0; i < source_->public_dependency_count(); ++i)
+ public_imports_.insert(source_->public_dependency(i));
+
+ if (source_->weak_dependency_count() > 0)
+ Abort("Weak imports are not supported.");
+
+ // Sanity check. Collect public imports (of collected imports) in DFS order.
+ // Visibilty for current proto:
+ // - all imports listed in current proto,
+ // - public imports of everything imported (recursive).
+ std::vector<const FileDescriptor*> stack;
+ for (int i = 0; i < source_->dependency_count(); ++i) {
+ const FileDescriptor* import = source_->dependency(i);
+ stack.push_back(import);
+ if (public_imports_.count(import) == 0) {
+ private_imports_.insert(import);
+ }
+ }
+
+ while (!stack.empty()) {
+ const FileDescriptor* import = stack.back();
+ stack.pop_back();
+ // Having imports under different packages leads to unnecessary
+ // complexity with namespaces.
+ if (import->package() != package_)
+ Abort("Imported proto must be in the same package.");
+
+ for (int i = 0; i < import->public_dependency_count(); ++i) {
+ stack.push_back(import->public_dependency(i));
+ }
+ }
+
+ // Collect descriptors of messages and enums used in current proto.
+ // It will be used to generate necessary forward declarations and performed
+ // sanity check guarantees that everything lays in the same namespace.
+ for (const Descriptor* message : messages_) {
+ for (int i = 0; i < message->field_count(); ++i) {
+ const FieldDescriptor* field = message->field(i);
+
+ if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ if (public_imports_.count(field->message_type()->file()) == 0) {
+ // Avoid multiple forward declarations since
+ // public imports have been already included.
+ referenced_messages_.insert(field->message_type());
+ }
+ } else if (field->type() == FieldDescriptor::TYPE_ENUM) {
+ if (public_imports_.count(field->enum_type()->file()) == 0) {
+ referenced_enums_.insert(field->enum_type());
+ }
+ }
+ }
+ }
+ }
+
+ void Preprocess() {
+ // Package name maps to a series of namespaces.
+ package_ = source_->package();
+ namespaces_ = Split(package_, ".");
+ if (!wrapper_namespace_.empty())
+ namespaces_.insert(namespaces_.begin(), wrapper_namespace_);
+
+ full_namespace_prefix_ = "::";
+ for (const std::string& ns : namespaces_)
+ full_namespace_prefix_ += ns + "::";
+
+ CollectDescriptors();
+ CollectDependencies();
+ }
+
+ // Print top header, namespaces and forward declarations.
+ void GeneratePrologue() {
+ std::string greeting =
+ "// Autogenerated. DO NOT EDIT.\n"
+ "// Protobuf compiler (protoc) has generated these stubs with\n"
+ "// //components/tracing/tools/proto_zero_plugin.\n";
+ std::string guard = package_ + "_" + source_->name() + "_H_";
+ UpperString(&guard);
+ StripString(&guard, ".-/\\", '_');
+
+ stub_h_->Print(
+ "$greeting$\n"
+ "#ifndef $guard$\n"
+ "#define $guard$\n\n"
+ "#include <stddef.h>\n"
+ "#include <stdint.h>\n\n"
+ "#include \"components/tracing/core/proto_zero_message.h\"\n",
+ "greeting", greeting,
+ "guard", guard);
+ stub_cc_->Print(
+ "$greeting$\n"
+ "#include \"$name$.h\"\n",
+ "greeting", greeting,
+ "name", ProtoStubName(source_));
+
+ // Print includes for public imports.
+ for (const FileDescriptor* dependency : public_imports_) {
+ // Dependency name could contatin slashes but importing from upper-level
+ // directories is not possible anyway since build system process each
+ // proto file individually. Hence proto lookup path always equal to the
+ // directory where particular proto file is located and protoc does not
+ // allow reference to upper directory (aka ..) in import path.
+ //
+ // Laconically said:
+ // - source_->name() may never have slashes,
+ // - dependency->name() may have slashes but always reffers to inner path.
+ stub_h_->Print(
+ "#include \"$name$.h\"\n",
+ "name", ProtoStubName(dependency));
+ }
+ stub_h_->Print("\n");
+
+ // Print includes for private imports to .cc file.
+ for (const FileDescriptor* dependency : private_imports_) {
+ stub_cc_->Print(
+ "#include \"$name$.h\"\n",
+ "name", ProtoStubName(dependency));
+ }
+ stub_cc_->Print("\n");
+
+ if (messages_.size() > 0) {
+ stub_cc_->Print(
+ "namespace {\n"
+ " static const ::tracing::v2::proto::ProtoFieldDescriptor "
+ "kInvalidField = {\"\", "
+ "::tracing::v2::proto::ProtoFieldDescriptor::Type::TYPE_INVALID, "
+ "0, false};\n"
+ "}\n\n");
+ }
+
+ // Print namespaces.
+ for (const std::string& ns : namespaces_) {
+ stub_h_->Print("namespace $ns$ {\n", "ns", ns);
+ stub_cc_->Print("namespace $ns$ {\n", "ns", ns);
+ }
+ stub_h_->Print("\n");
+ stub_cc_->Print("\n");
+
+ // Print forward declarations.
+ for (const Descriptor* message : referenced_messages_) {
+ stub_h_->Print(
+ "class $class$;\n",
+ "class", GetCppClassName(message));
+ }
+ for (const EnumDescriptor* enumeration : referenced_enums_) {
+ stub_h_->Print(
+ "enum $class$ : int32_t;\n",
+ "class", GetCppClassName(enumeration));
+ }
+ stub_h_->Print("\n");
+ }
+
+ void GenerateEnumDescriptor(const EnumDescriptor* enumeration) {
+ stub_h_->Print(
+ "enum $class$ : int32_t {\n",
+ "class", GetCppClassName(enumeration));
+ stub_h_->Indent();
+
+ std::string value_name_prefix;
+ if (enumeration->containing_type() != nullptr)
+ value_name_prefix = GetCppClassName(enumeration) + "_";
+
+ for (int i = 0; i < enumeration->value_count(); ++i) {
+ const EnumValueDescriptor* value = enumeration->value(i);
+ stub_h_->Print(
+ "$name$ = $number$,\n",
+ "name", value_name_prefix + value->name(),
+ "number", std::to_string(value->number()));
+ }
+
+ stub_h_->Outdent();
+ stub_h_->Print("};\n\n");
+ }
+
+ void GenerateSimpleFieldDescriptor(const FieldDescriptor* field) {
+ std::map<std::string, std::string> setter;
+ setter["id"] = std::to_string(field->number());
+ setter["name"] = field->name();
+ setter["action"] = field->is_repeated() ? "add" : "set";
+
+ std::string appender;
+ std::string cpp_type;
+
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_BOOL: {
+ appender = "AppendTinyVarInt";
+ cpp_type = "bool";
+ break;
+ }
+ case FieldDescriptor::TYPE_INT32: {
+ appender = "AppendVarInt";
+ cpp_type = "int32_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_INT64: {
+ appender = "AppendVarInt";
+ cpp_type = "int64_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_UINT32: {
+ appender = "AppendVarInt";
+ cpp_type = "uint32_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_UINT64: {
+ appender = "AppendVarInt";
+ cpp_type = "uint64_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_SINT32: {
+ appender = "AppendSignedVarInt";
+ cpp_type = "int32_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_SINT64: {
+ appender = "AppendSignedVarInt";
+ cpp_type = "int64_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_FIXED32: {
+ appender = "AppendFixed";
+ cpp_type = "uint32_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_FIXED64: {
+ appender = "AppendFixed";
+ cpp_type = "uint64_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_SFIXED32: {
+ appender = "AppendFixed";
+ cpp_type = "int32_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_SFIXED64: {
+ appender = "AppendFixed";
+ cpp_type = "int64_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_FLOAT: {
+ appender = "AppendFixed";
+ cpp_type = "float";
+ break;
+ }
+ case FieldDescriptor::TYPE_DOUBLE: {
+ appender = "AppendFixed";
+ cpp_type = "double";
+ break;
+ }
+ case FieldDescriptor::TYPE_ENUM: {
+ appender = IsTinyEnumField(field) ? "AppendTinyVarInt" : "AppendVarInt";
+ cpp_type = GetCppClassName(field->enum_type(), true);
+ break;
+ }
+ case FieldDescriptor::TYPE_STRING: {
+ appender = "AppendString";
+ cpp_type = "const char*";
+ break;
+ }
+ case FieldDescriptor::TYPE_BYTES: {
+ stub_h_->Print(
+ setter,
+ "void $action$_$name$(const uint8_t* data, size_t size) {\n"
+ " AppendBytes($id$, data, size);\n"
+ "}\n");
+ return;
+ }
+ default: {
+ Abort("Unsupported field type.");
+ return;
+ }
+ }
+ setter["appender"] = appender;
+ setter["cpp_type"] = cpp_type;
+ stub_h_->Print(
+ setter,
+ "void $action$_$name$($cpp_type$ value) {\n"
+ " $appender$($id$, value);\n"
+ "}\n");
+ }
+
+ void GenerateNestedMessageFieldDescriptor(const FieldDescriptor* field) {
+ std::string action = field->is_repeated() ? "add" : "set";
+ std::string inner_class = GetCppClassName(field->message_type());
+ std::string outer_class = GetCppClassName(field->containing_type());
+
+ stub_h_->Print(
+ "$inner_class$* $action$_$name$();\n",
+ "name", field->name(),
+ "action", action,
+ "inner_class", inner_class);
+ stub_cc_->Print(
+ "$inner_class$* $outer_class$::$action$_$name$() {\n"
+ " return BeginNestedMessage<$inner_class$>($id$);\n"
+ "}\n\n",
+ "id", std::to_string(field->number()),
+ "name", field->name(),
+ "action", action,
+ "inner_class", inner_class,
+ "outer_class", outer_class);
+ }
+
+ void GenerateReflectionForMessageFields(const Descriptor* message) {
+ const bool has_fields = (message->field_count() > 0);
+
+ // Field number constants.
+ if (has_fields) {
+ stub_h_->Print("enum : int32_t {\n");
+ stub_h_->Indent();
+
+ for (int i = 0; i < message->field_count(); ++i) {
+ const FieldDescriptor* field = message->field(i);
+ stub_h_->Print(
+ "$name$ = $id$,\n",
+ "name", GetFieldNumberConstant(field),
+ "id", std::to_string(field->number()));
+ }
+ stub_h_->Outdent();
+ stub_h_->Print("};\n");
+ }
+
+ // Fields reflection table.
+ stub_h_->Print(
+ "static const ::tracing::v2::proto::ProtoFieldDescriptor* "
+ "GetFieldDescriptor(uint32_t field_id);\n");
+
+ std::string class_name = GetCppClassName(message);
+ if (has_fields) {
+ stub_cc_->Print(
+ "static const ::tracing::v2::proto::ProtoFieldDescriptor "
+ "kFields_$class$[] = {\n",
+ "class", class_name);
+ stub_cc_->Indent();
+ for (int i = 0; i < message->field_count(); ++i) {
+ const FieldDescriptor* field = message->field(i);
+ std::string type_const =
+ std::string("TYPE_") + FieldDescriptor::TypeName(field->type());
+ UpperString(&type_const);
+ stub_cc_->Print(
+ "{\"$name$\", "
+ "::tracing::v2::proto::ProtoFieldDescriptor::Type::$type$, "
+ "$number$, $is_repeated$},\n",
+ "name", field->name(),
+ "type", type_const,
+ "number", std::to_string(field->number()),
+ "is_repeated", std::to_string(field->is_repeated()));
+ }
+ stub_cc_->Outdent();
+ stub_cc_->Print("};\n\n");
+ }
+
+ // Fields reflection getter.
+ stub_cc_->Print(
+ "const ::tracing::v2::proto::ProtoFieldDescriptor* "
+ "$class$::GetFieldDescriptor(uint32_t field_id) {\n",
+ "class", class_name);
+ stub_cc_->Indent();
+ if (has_fields) {
+ stub_cc_->Print("switch (field_id) {\n");
+ stub_cc_->Indent();
+ for (int i = 0; i < message->field_count(); ++i) {
+ stub_cc_->Print(
+ "case $field$:\n"
+ " return &kFields_$class$[$id$];\n",
+ "class", class_name,
+ "field", GetFieldNumberConstant(message->field(i)),
+ "id", std::to_string(i));
+ }
+ stub_cc_->Print(
+ "default:\n"
+ " return &kInvalidField;\n");
+ stub_cc_->Outdent();
+ stub_cc_->Print("}\n");
+ } else {
+ stub_cc_->Print("return &kInvalidField;\n");
+ }
+ stub_cc_->Outdent();
+ stub_cc_->Print("}\n\n");
+ }
+
+ void GenerateMessageDescriptor(const Descriptor* message) {
+ stub_h_->Print(
+ "class $name$ : public ::tracing::v2::ProtoZeroMessage {\n"
+ " public:\n",
+ "name", GetCppClassName(message));
+ stub_h_->Indent();
+
+ GenerateReflectionForMessageFields(message);
+
+ // Using statements for nested messages.
+ for (int i = 0; i < message->nested_type_count(); ++i) {
+ const Descriptor* nested_message = message->nested_type(i);
+ stub_h_->Print(
+ "using $local_name$ = $global_name$;\n",
+ "local_name", nested_message->name(),
+ "global_name", GetCppClassName(nested_message, true));
+ }
+
+ // Using statements for nested enums.
+ for (int i = 0; i < message->enum_type_count(); ++i) {
+ const EnumDescriptor* nested_enum = message->enum_type(i);
+ stub_h_->Print(
+ "using $local_name$ = $global_name$;\n",
+ "local_name", nested_enum->name(),
+ "global_name", GetCppClassName(nested_enum, true));
+ }
+
+ // Values of nested enums.
+ for (int i = 0; i < message->enum_type_count(); ++i) {
+ const EnumDescriptor* nested_enum = message->enum_type(i);
+ std::string value_name_prefix = GetCppClassName(nested_enum) + "_";
+
+ for (int j = 0; j < nested_enum->value_count(); ++j) {
+ const EnumValueDescriptor* value = nested_enum->value(j);
+ stub_h_->Print(
+ "static const $class$ $name$ = $full_name$;\n",
+ "class", nested_enum->name(),
+ "name", value->name(),
+ "full_name", value_name_prefix + value->name());
+ }
+ }
+
+ // Field descriptors.
+ for (int i = 0; i < message->field_count(); ++i) {
+ const FieldDescriptor* field = message->field(i);
+ if (field->is_packed()) {
+ Abort("Packed repeated fields are not supported.");
+ return;
+ }
+ if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+ GenerateSimpleFieldDescriptor(field);
+ } else {
+ GenerateNestedMessageFieldDescriptor(field);
+ }
+ }
+
+ stub_h_->Outdent();
+ stub_h_->Print("};\n\n");
+ }
+
+ void GenerateEpilogue() {
+ for (unsigned i = 0; i < namespaces_.size(); ++i) {
+ stub_h_->Print("} // Namespace.\n");
+ stub_cc_->Print("} // Namespace.\n");
+ }
+ stub_h_->Print("#endif // Include guard.\n");
+ }
+
+ const FileDescriptor* const source_;
+ Printer* const stub_h_;
+ Printer* const stub_cc_;
+ std::string error_;
+
+ std::string package_;
+ std::string wrapper_namespace_;
+ std::vector<std::string> namespaces_;
+ std::string full_namespace_prefix_;
+ std::vector<const Descriptor*> messages_;
+ std::vector<const EnumDescriptor*> enums_;
+
+ std::set<const FileDescriptor*> public_imports_;
+ std::set<const FileDescriptor*> private_imports_;
+ std::set<const Descriptor*> referenced_messages_;
+ std::set<const EnumDescriptor*> referenced_enums_;
+};
+
+} // namespace
+
+ProtoZeroGenerator::ProtoZeroGenerator() {
+}
+
+ProtoZeroGenerator::~ProtoZeroGenerator() {
+}
+
+bool ProtoZeroGenerator::Generate(const FileDescriptor* file,
+ const std::string& options,
+ GeneratorContext* context,
+ std::string* error) const {
+
+ const std::unique_ptr<ZeroCopyOutputStream> stub_h_file_stream(
+ context->Open(ProtoStubName(file) + ".h"));
+ const std::unique_ptr<ZeroCopyOutputStream> stub_cc_file_stream(
+ context->Open(ProtoStubName(file) + ".cc"));
+
+ // Variables are delimited by $.
+ Printer stub_h_printer(stub_h_file_stream.get(), '$');
+ Printer stub_cc_printer(stub_cc_file_stream.get(), '$');
+ GeneratorJob job(file, &stub_h_printer, &stub_cc_printer);
+
+ // Parse additional options.
+ for (const std::string& option : Split(options, ",")) {
+ std::vector<std::string> option_pair = Split(option, "=");
+ job.SetOption(option_pair[0], option_pair[1]);
+ }
+
+ if (!job.GenerateStubs()) {
+ *error = job.GetFirstError();
+ return false;
+ }
+ return true;
+}
+
+} // namespace proto
+} // namespace tracing
diff --git a/chromium/components/tracing/tools/proto_zero_plugin/proto_zero_generator.h b/chromium/components/tracing/tools/proto_zero_plugin/proto_zero_generator.h
new file mode 100644
index 00000000000..6bdaf1e4f01
--- /dev/null
+++ b/chromium/components/tracing/tools/proto_zero_plugin/proto_zero_generator.h
@@ -0,0 +1,30 @@
+// 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 COMPONENTS_TRACING_PROTO_ZERO_PLUGIN_PROTO_ZERO_GENERATOR_H_
+#define COMPONENTS_TRACING_PROTO_ZERO_PLUGIN_PROTO_ZERO_GENERATOR_H_
+
+#include <string>
+
+#include "third_party/protobuf/src/google/protobuf/compiler/code_generator.h"
+
+namespace tracing {
+namespace proto {
+
+class ProtoZeroGenerator : public google::protobuf::compiler::CodeGenerator {
+ public:
+ explicit ProtoZeroGenerator();
+ ~ProtoZeroGenerator() override;
+
+ // CodeGenerator implementation
+ bool Generate(const google::protobuf::FileDescriptor* file,
+ const std::string& options,
+ google::protobuf::compiler::GeneratorContext* context,
+ std::string* error) const override;
+};
+
+} // namesapce proto
+} // namespace tracing
+
+#endif // COMPONENTS_TRACING_PROTO_ZERO_PLUGIN_PROTO_ZERO_GENERATOR_H_
diff --git a/chromium/components/tracing/tools/proto_zero_plugin/proto_zero_plugin.cc b/chromium/components/tracing/tools/proto_zero_plugin/proto_zero_plugin.cc
new file mode 100644
index 00000000000..5ed63a827f4
--- /dev/null
+++ b/chromium/components/tracing/tools/proto_zero_plugin/proto_zero_plugin.cc
@@ -0,0 +1,12 @@
+// 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 "third_party/protobuf/src/google/protobuf/compiler/plugin.h"
+
+#include "proto_zero_generator.h"
+
+int main(int argc, char* argv[]) {
+ tracing::proto::ProtoZeroGenerator generator;
+ return google::protobuf::compiler::PluginMain(argc, argv, &generator);
+}
diff --git a/chromium/components/tracing_nacl.gyp b/chromium/components/tracing_nacl.gyp
deleted file mode 100644
index 9b0b511ddfa..00000000000
--- a/chromium/components/tracing_nacl.gyp
+++ /dev/null
@@ -1,52 +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.
-
-{
- 'includes': [
- '../build/common_untrusted.gypi',
- ],
- 'conditions': [
- ['disable_nacl==0 and disable_nacl_untrusted==0', {
- 'targets': [
- {
- 'target_name': 'tracing_nacl',
- 'type': 'none',
- 'defines!': ['CONTENT_IMPLEMENTATION'],
- 'dependencies': [
- '../base/base_nacl.gyp:base_nacl',
- '../base/base_nacl.gyp:base_nacl_nonsfi',
- '../ipc/ipc_nacl.gyp:ipc_nacl',
- '../ipc/ipc_nacl.gyp:ipc_nacl_nonsfi',
- ],
- 'include_dirs': [
- '..',
- ],
- 'variables': {
- 'nacl_untrusted_build': 1,
- 'nlib_target': 'libtracing_nacl.a',
- 'build_glibc': 0,
- 'build_newlib': 0,
- 'build_irt': 1,
- 'build_pnacl_newlib': 0,
- 'build_nonsfi_helper': 1,
- },
- 'sources': [
- 'tracing/browser/trace_config_file.cc',
- 'tracing/browser/trace_config_file.h',
- 'tracing/child/child_memory_dump_manager_delegate_impl.cc',
- 'tracing/child/child_memory_dump_manager_delegate_impl.h',
- 'tracing/child/child_trace_message_filter.cc',
- 'tracing/child/child_trace_message_filter.h',
- 'tracing/common/tracing_messages.cc',
- 'tracing/common/tracing_messages.h',
- 'tracing/common/tracing_switches.cc',
- 'tracing/common/tracing_switches.h',
- 'tracing/tracing_export.h',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/translate.gypi b/chromium/components/translate.gypi
deleted file mode 100644
index d4babfa7335..00000000000
--- a/chromium/components/translate.gypi
+++ /dev/null
@@ -1,249 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/translate/core/browser
- 'target_name': 'translate_core_browser',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../google_apis/google_apis.gyp:google_apis',
- '../net/net.gyp:net',
- '../ui/base/ui_base.gyp:ui_base',
- '../url/url.gyp:url_lib',
- 'components_resources.gyp:components_resources',
- 'components_strings.gyp:components_strings',
- 'data_use_measurement_core',
- 'infobars_core',
- 'language_usage_metrics',
- 'pref_registry',
- 'translate_core_common',
- 'variations',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'translate/core/browser/language_state.cc',
- 'translate/core/browser/language_state.h',
- 'translate/core/browser/page_translated_details.h',
- 'translate/core/browser/translate_accept_languages.cc',
- 'translate/core/browser/translate_accept_languages.h',
- 'translate/core/browser/translate_browser_metrics.cc',
- 'translate/core/browser/translate_browser_metrics.h',
- 'translate/core/browser/translate_client.h',
- 'translate/core/browser/translate_download_manager.cc',
- 'translate/core/browser/translate_download_manager.h',
- 'translate/core/browser/translate_driver.h',
- 'translate/core/browser/translate_error_details.h',
- 'translate/core/browser/translate_event_details.cc',
- 'translate/core/browser/translate_event_details.h',
- 'translate/core/browser/translate_experiment.cc',
- 'translate/core/browser/translate_experiment.h',
- 'translate/core/browser/translate_language_list.cc',
- 'translate/core/browser/translate_language_list.h',
- 'translate/core/browser/translate_manager.cc',
- 'translate/core/browser/translate_manager.h',
- 'translate/core/browser/translate_prefs.cc',
- 'translate/core/browser/translate_prefs.h',
- 'translate/core/browser/translate_script.cc',
- 'translate/core/browser/translate_script.h',
- 'translate/core/browser/translate_step.h',
- 'translate/core/browser/translate_ui_delegate.cc',
- 'translate/core/browser/translate_ui_delegate.h',
- 'translate/core/browser/translate_url_fetcher.cc',
- 'translate/core/browser/translate_url_fetcher.h',
- 'translate/core/browser/translate_url_util.cc',
- 'translate/core/browser/translate_url_util.h',
- ],
- 'conditions': [
- ['use_aura==0', {
- 'sources': [
- 'translate/core/browser/translate_infobar_delegate.cc',
- 'translate/core/browser/translate_infobar_delegate.h',
- ],
- }],
- ['OS == "mac"', {
- 'sources': [
- 'translate/core/browser/options_menu_model.cc',
- 'translate/core/browser/options_menu_model.h',
- ],
- }],
- ],
- },
- {
- # GN version: //components/translate/core/common
- 'target_name': 'translate_core_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'translate/core/common/language_detection_details.cc',
- 'translate/core/common/language_detection_details.h',
- 'translate/core/common/translate_constants.cc',
- 'translate/core/common/translate_constants.h',
- 'translate/core/common/translate_errors.h',
- 'translate/core/common/translate_metrics.cc',
- 'translate/core/common/translate_metrics.h',
- 'translate/core/common/translate_pref_names.cc',
- 'translate/core/common/translate_pref_names.h',
- 'translate/core/common/translate_switches.cc',
- 'translate/core/common/translate_switches.h',
- 'translate/core/common/translate_util.cc',
- 'translate/core/common/translate_util.h',
- ],
- },
- {
- # GN version: //components/translate/core/language_detection
- 'target_name': 'translate_core_language_detection',
- 'type': 'static_library',
- 'dependencies': [
- 'translate_core_common',
- '../base/base.gyp:base',
- '../url/url.gyp:url_lib',
- '../third_party/cld_2/cld_2.gyp:cld_2',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'translate/core/language_detection/language_detection_util.cc',
- 'translate/core/language_detection/language_detection_util.h',
- ],
- },
- ],
- 'conditions': [
- ['OS != "ios"', {
- 'targets': [
- {
- # GN version: //components/translate/content/browser
- 'target_name': 'translate_content_browser',
- 'type': 'static_library',
- 'dependencies': [
- 'translate_content_common',
- 'translate_core_browser',
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'translate/content/browser/content_translate_driver.cc',
- 'translate/content/browser/content_translate_driver.h',
- ],
- },
- {
- # GN version: //components/translate/content/common
- 'target_name': 'translate_content_common',
- 'type': 'static_library',
- 'dependencies': [
- 'translate_core_common',
- 'translate_core_language_detection',
- '../base/base.gyp:base',
- '../ipc/ipc.gyp:ipc',
- '../url/ipc/url_ipc.gyp:url_ipc',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'translate/content/common/translate_messages.cc',
- 'translate/content/common/translate_messages.h',
- ],
- },
- {
- # GN version: //components/translate/content/renderer
- 'target_name': 'translate_content_renderer',
- 'type': 'static_library',
- 'dependencies': [
- 'translate_content_common',
- 'translate_core_common',
- 'translate_core_language_detection',
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../content/content.gyp:content_renderer',
- '../ipc/ipc.gyp:ipc',
- '../third_party/WebKit/public/blink.gyp:blink',
- '../third_party/cld_2/cld_2.gyp:cld_2',
- '../url/url.gyp:url_lib',
- '../v8/src/v8.gyp:v8',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'translate/content/renderer/translate_helper.cc',
- 'translate/content/renderer/translate_helper.h',
- ],
- },
- ],
- }],
- ['OS == "ios"', {
- 'targets': [
- {
- # GN version: //components/translate/ios/browser
- 'target_name': 'translate_ios_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'translate_core_language_detection',
- 'translate_core_browser',
- 'translate_core_common',
- 'translate_ios_injected_js',
- '../base/base.gyp:base',
- '../ios/web/ios_web.gyp:ios_web',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'translate/ios/browser/ios_translate_driver.h',
- 'translate/ios/browser/ios_translate_driver.mm',
- 'translate/ios/browser/js_language_detection_manager.h',
- 'translate/ios/browser/js_language_detection_manager.mm',
- 'translate/ios/browser/js_translate_manager.h',
- 'translate/ios/browser/js_translate_manager.mm',
- 'translate/ios/browser/language_detection_controller.h',
- 'translate/ios/browser/language_detection_controller.mm',
- 'translate/ios/browser/translate_controller.h',
- 'translate/ios/browser/translate_controller.mm',
- ],
- },
- {
- # GN version: //components/translate/ios/browser:injected_js
- 'target_name': 'translate_ios_injected_js',
- 'type': 'none',
- 'sources': [
- 'translate/ios/browser/resources/language_detection.js',
- 'translate/ios/browser/resources/translate_ios.js',
- ],
- 'link_settings': {
- 'mac_bundle_resources': [
- '<(SHARED_INTERMEDIATE_DIR)/translate_ios.js',
- '<(SHARED_INTERMEDIATE_DIR)/language_detection.js',
- ],
- },
- 'includes': [
- '../ios/web/js_compile_checked.gypi',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/translate/content/browser/BUILD.gn b/chromium/components/translate/content/browser/BUILD.gn
index 1a4b1d8e526..efe80df1460 100644
--- a/chromium/components/translate/content/browser/BUILD.gn
+++ b/chromium/components/translate/content/browser/BUILD.gn
@@ -4,20 +4,21 @@
import("//build/config/features.gni")
-source_set("browser") {
+static_library("browser") {
sources = [
"content_translate_driver.cc",
"content_translate_driver.h",
]
- deps = [
+ public_deps = [
"//base",
"//components/translate/content/common",
"//components/translate/core/browser",
"//components/translate/core/common",
+ ]
+ deps = [
"//content/public/browser",
"//content/public/common",
- "//ipc",
"//net",
]
}
diff --git a/chromium/components/translate/content/common/BUILD.gn b/chromium/components/translate/content/common/BUILD.gn
index 37e271535ad..7e782e1d0bb 100644
--- a/chromium/components/translate/content/common/BUILD.gn
+++ b/chromium/components/translate/content/common/BUILD.gn
@@ -1,20 +1,16 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//build/config/features.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
-static_library("common") {
+mojom("common") {
sources = [
- "translate_messages.cc",
- "translate_messages.h",
+ "translate.mojom",
]
- deps = [
- "//base",
- "//components/translate/core/common",
- "//components/translate/core/language_detection",
- "//content/public/common",
- "//ipc",
+ public_deps = [
+ "//mojo/common:common_custom_types",
+ "//url/mojo:url_mojom_gurl",
]
}
diff --git a/chromium/components/translate/content/common/translate.mojom b/chromium/components/translate/content/common/translate.mojom
new file mode 100644
index 00000000000..e0916071873
--- /dev/null
+++ b/chromium/components/translate/content/common/translate.mojom
@@ -0,0 +1,65 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module translate.mojom;
+
+import "mojo/common/common_custom_types.mojom";
+import "url/mojo/url.mojom";
+
+enum TranslateError {
+ NONE,
+ NETWORK,
+ INITIALIZATION_ERROR,
+ UNKNOWN_LANGUAGE,
+ UNSUPPORTED_LANGUAGE,
+ IDENTICAL_LANGUAGES,
+ TRANSLATION_ERROR,
+ TRANSLATION_TIMEOUT,
+ UNEXPECTED_SCRIPT_ERROR,
+ BAD_ORIGIN,
+ SCRIPT_LOAD_ERROR,
+ TRANSLATE_ERROR_MAX,
+};
+
+struct LanguageDetectionDetails {
+ mojo.common.mojom.Time time;
+ url.mojom.Url url;
+ string content_language;
+ string cld_language;
+ bool is_cld_reliable;
+ bool has_notranslate;
+ string html_root_language;
+ string adopted_language;
+ string contents;
+};
+
+interface Page {
+ // Requests that the page be translated from |source_lang| to
+ // |target_lang|.
+ //
+ // If a Translate request is already in progress with a matching
+ // |target_lang|, this request will respond with |cancelled| set
+ // to |true|.
+ //
+ // If a Translate request is already in progress with a different
+ // |target_lang|, that request will respond with |cancelled| set
+ // to |true| and this request will proceed normally.
+ //
+ // If |cancelled| is |true| all other response values should be
+ // ignored.
+ Translate(string translate_script, string source_lang, string target_lang)
+ => (bool cancelled, string original_lang, string translated_lang,
+ TranslateError error);
+
+ // Requests that the page be reverted to its original language with
+ // no translation applied.
+ RevertTranslation();
+};
+
+interface ContentTranslateDriver {
+ // Notification that a new page is ready to translate,
+ // and the language for it has been determined.
+ RegisterPage(Page page, LanguageDetectionDetails details,
+ bool page_needs_translation);
+};
diff --git a/chromium/components/translate/content/common/translate.typemap b/chromium/components/translate/content/common/translate.typemap
new file mode 100644
index 00000000000..3aafd6a88ea
--- /dev/null
+++ b/chromium/components/translate/content/common/translate.typemap
@@ -0,0 +1,23 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//components/translate/content/common/translate.mojom"
+public_headers = [
+ "//components/translate/core/common/language_detection_details.h",
+ "//components/translate/core/common/translate_errors.h",
+]
+traits_headers =
+ [ "//components/translate/content/common/translate_struct_traits.h" ]
+sources = [
+ "//components/translate/content/common/translate_struct_traits.cc",
+]
+deps = [
+ "//base",
+ "//components/translate/core/common",
+]
+
+type_mappings = [
+ "translate.mojom.LanguageDetectionDetails=translate::LanguageDetectionDetails",
+ "translate.mojom.TranslateError=translate::TranslateErrors::Type",
+]
diff --git a/chromium/components/translate/content/renderer/BUILD.gn b/chromium/components/translate/content/renderer/BUILD.gn
index 03dba499b77..0a16d44682d 100644
--- a/chromium/components/translate/content/renderer/BUILD.gn
+++ b/chromium/components/translate/content/renderer/BUILD.gn
@@ -17,9 +17,9 @@ static_library("renderer") {
"//components/translate/core/language_detection",
"//content/public/common",
"//content/public/renderer",
- "//ipc",
+ "//services/shell/public/cpp",
"//third_party/WebKit/public:blink",
- "//third_party/cld_2",
+ "//third_party/cld",
"//url",
"//v8",
]
diff --git a/chromium/components/translate/core/browser/BUILD.gn b/chromium/components/translate/core/browser/BUILD.gn
index 5efd47f223a..ab04d4f1154 100644
--- a/chromium/components/translate/core/browser/BUILD.gn
+++ b/chromium/components/translate/core/browser/BUILD.gn
@@ -4,8 +4,10 @@
import("//build/config/ui.gni")
-source_set("browser") {
+static_library("browser") {
sources = [
+ "language_model.cc",
+ "language_model.h",
"language_state.cc",
"language_state.h",
"page_translated_details.h",
@@ -28,6 +30,10 @@ source_set("browser") {
"translate_manager.h",
"translate_prefs.cc",
"translate_prefs.h",
+ "translate_ranker.cc",
+ "translate_ranker.h",
+ "translate_ranker_metrics_provider.cc",
+ "translate_ranker_metrics_provider.h",
"translate_script.cc",
"translate_script.h",
"translate_step.h",
@@ -43,11 +49,14 @@ source_set("browser") {
"//base",
"//base:i18n",
"//components/data_use_measurement/core",
+ "//components/keyed_service/core",
"//components/language_usage_metrics",
+ "//components/metrics",
"//components/pref_registry",
"//components/prefs",
"//components/resources:components_resources",
"//components/strings",
+ "//components/translate/core/browser/proto",
"//components/translate/core/common",
"//components/variations",
"//google_apis",
@@ -76,6 +85,7 @@ source_set("browser") {
source_set("unit_tests") {
testonly = true
sources = [
+ "language_model_unittest.cc",
"language_state_unittest.cc",
"mock_translate_driver.cc",
"mock_translate_driver.h",
@@ -83,6 +93,7 @@ source_set("unit_tests") {
"translate_language_list_unittest.cc",
"translate_manager_unittest.cc",
"translate_prefs_unittest.cc",
+ "translate_ranker_unittest.cc",
"translate_script_unittest.cc",
"translate_ui_delegate_unittest.cc",
]
@@ -92,6 +103,8 @@ source_set("unit_tests") {
"//components/infobars/core",
"//components/pref_registry:test_support",
"//components/prefs",
+ "//components/prefs:test_support",
+ "//components/translate/core/browser/proto",
"//components/translate/core/common",
"//components/variations",
"//net:test_support",
diff --git a/chromium/components/translate/core/browser/proto/BUILD.gn b/chromium/components/translate/core/browser/proto/BUILD.gn
new file mode 100644
index 00000000000..c064a49e781
--- /dev/null
+++ b/chromium/components/translate/core/browser/proto/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+ sources = [
+ "translate_ranker_model.proto",
+ ]
+}
diff --git a/chromium/components/translate/core/common/BUILD.gn b/chromium/components/translate/core/common/BUILD.gn
index f4d461ffdc5..237c1aee014 100644
--- a/chromium/components/translate/core/common/BUILD.gn
+++ b/chromium/components/translate/core/common/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("common") {
+static_library("common") {
sources = [
"language_detection_details.cc",
"language_detection_details.h",
diff --git a/chromium/components/translate/core/language_detection/BUILD.gn b/chromium/components/translate/core/language_detection/BUILD.gn
index 98f4d1f4749..d40e3bb8129 100644
--- a/chromium/components/translate/core/language_detection/BUILD.gn
+++ b/chromium/components/translate/core/language_detection/BUILD.gn
@@ -4,7 +4,7 @@
import("//build/config/features.gni")
-source_set("language_detection") {
+static_library("language_detection") {
sources = [
"language_detection_util.cc",
"language_detection_util.h",
@@ -13,7 +13,7 @@ source_set("language_detection") {
deps = [
"//base",
"//components/translate/core/common",
- "//third_party/cld_2",
+ "//third_party/cld",
"//url",
]
}
diff --git a/chromium/components/typemaps.gni b/chromium/components/typemaps.gni
index 3589d2c2ed5..f173d9c9c52 100644
--- a/chromium/components/typemaps.gni
+++ b/chromium/components/typemaps.gni
@@ -4,5 +4,7 @@
typemaps = [
"//components/autofill/content/public/cpp/autofill_types.typemap",
+ "//components/password_manager/content/public/cpp/credential_manager.typemap",
"//components/safe_json/public/interfaces/safe_json.typemap",
+ "//components/translate/content/common/translate.typemap",
]
diff --git a/chromium/components/undo.gypi b/chromium/components/undo.gypi
deleted file mode 100644
index 17ca2d8da91..00000000000
--- a/chromium/components/undo.gypi
+++ /dev/null
@@ -1,33 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/undo
- 'target_name': 'undo_component',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../ui/base/ui_base.gyp:ui_base',
- 'bookmarks_browser',
- 'components_strings.gyp:components_strings',
- 'keyed_service_core',
- ],
- 'sources': [
- 'undo/bookmark_undo_service.cc',
- 'undo/bookmark_undo_service.h',
- 'undo/bookmark_undo_utils.cc',
- 'undo/bookmark_undo_utils.h',
- 'undo/undo_manager.cc',
- 'undo/undo_manager.h',
- 'undo/undo_manager_observer.h',
- 'undo/undo_operation.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/undo/undo_manager_test.cc b/chromium/components/undo/undo_manager_test.cc
index 19bbdc33071..eea15985fab 100644
--- a/chromium/components/undo/undo_manager_test.cc
+++ b/chromium/components/undo/undo_manager_test.cc
@@ -88,7 +88,7 @@ void TestUndoService::Redo() {
}
void TestUndoService::TriggerOperation() {
- undo_manager_.AddUndoOperation(base::WrapUnique(new TestUndoOperation(this)));
+ undo_manager_.AddUndoOperation(base::MakeUnique<TestUndoOperation>(this));
}
void TestUndoService::RecordUndoCall() {
diff --git a/chromium/components/update_client.gypi b/chromium/components/update_client.gypi
deleted file mode 100644
index 0cfa4b2f480..00000000000
--- a/chromium/components/update_client.gypi
+++ /dev/null
@@ -1,98 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/update_client
- 'target_name': 'update_client',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../courgette/courgette.gyp:courgette_lib',
- '../crypto/crypto.gyp:crypto',
- '../third_party/libxml/libxml.gyp:libxml',
- '../third_party/zlib/google/zip.gyp:zip',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- 'client_update_protocol',
- 'crx_file',
- ],
-
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'update_client/action.cc',
- 'update_client/action.h',
- 'update_client/action_update.cc',
- 'update_client/action_update.h',
- 'update_client/action_update_check.cc',
- 'update_client/action_update_check.h',
- 'update_client/action_wait.cc',
- 'update_client/action_wait.h',
- 'update_client/background_downloader_win.cc',
- 'update_client/background_downloader_win.h',
- 'update_client/component_patcher.cc',
- 'update_client/component_patcher.h',
- 'update_client/component_patcher_operation.cc',
- 'update_client/component_patcher_operation.h',
- 'update_client/component_unpacker.cc',
- 'update_client/component_unpacker.h',
- 'update_client/configurator.h',
- 'update_client/crx_downloader.cc',
- 'update_client/crx_downloader.h',
- 'update_client/crx_update_item.h',
- 'update_client/persisted_data.cc',
- 'update_client/persisted_data.h',
- 'update_client/ping_manager.cc',
- 'update_client/ping_manager.h',
- 'update_client/request_sender.cc',
- 'update_client/request_sender.h',
- 'update_client/task.h',
- 'update_client/task_update.cc',
- 'update_client/task_update.h',
- 'update_client/update_checker.cc',
- 'update_client/update_checker.h',
- 'update_client/update_client.cc',
- 'update_client/update_client.h',
- 'update_client/update_client_internal.h',
- 'update_client/update_engine.cc',
- 'update_client/update_engine.h',
- 'update_client/update_query_params.cc',
- 'update_client/update_query_params.h',
- 'update_client/update_query_params_delegate.cc',
- 'update_client/update_query_params_delegate.h',
- 'update_client/update_response.cc',
- 'update_client/update_response.h',
- 'update_client/url_fetcher_downloader.cc',
- 'update_client/url_fetcher_downloader.h',
- 'update_client/utils.cc',
- 'update_client/utils.h',
- ],
- },
- {
- # GN version: //components/update_client:test_support
- 'target_name': 'update_client_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'update_client',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- ],
-
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'update_client/test_configurator.cc',
- 'update_client/test_configurator.h',
- 'update_client/test_installer.cc',
- 'update_client/test_installer.h',
- 'update_client/url_request_post_interceptor.cc',
- 'update_client/url_request_post_interceptor.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/update_client/BUILD.gn b/chromium/components/update_client/BUILD.gn
index 7783b09877a..69a82d87156 100644
--- a/chromium/components/update_client/BUILD.gn
+++ b/chromium/components/update_client/BUILD.gn
@@ -2,7 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("update_client") {
+import("//net/features.gni")
+
+static_library("update_client") {
sources = [
"action.cc",
"action.h",
@@ -66,7 +68,7 @@ source_set("update_client") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"test_configurator.cc",
@@ -115,7 +117,6 @@ source_set("unit_tests") {
testonly = true
sources = [
"component_patcher_unittest.cc",
- "crx_downloader_unittest.cc",
"persisted_data_unittest.cc",
"ping_manager_unittest.cc",
"request_sender_unittest.cc",
@@ -126,6 +127,10 @@ source_set("unit_tests") {
"utils_unittest.cc",
]
+ if (!disable_file_support) {
+ sources += [ "crx_downloader_unittest.cc" ]
+ }
+
deps = [
":test_support",
":unit_tests_bundle_data",
diff --git a/chromium/components/update_client/action.cc b/chromium/components/update_client/action.cc
index c550b2f1c60..c979e2a102e 100644
--- a/chromium/components/update_client/action.cc
+++ b/chromium/components/update_client/action.cc
@@ -5,6 +5,8 @@
#include "components/update_client/action.h"
#include <algorithm>
+#include <memory>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
@@ -29,7 +31,7 @@ namespace {
bool CanTryDiffUpdate(const CrxUpdateItem* update_item,
const scoped_refptr<Configurator>& config) {
return HasDiffUpdate(update_item) && !update_item->diff_update_failed &&
- config->DeltasEnabled();
+ config->EnabledDeltas();
}
} // namespace
@@ -100,7 +102,7 @@ size_t ActionImpl::ChangeAllItemsState(CrxUpdateItem::State from,
CrxUpdateItem::State to) {
DCHECK(thread_checker_.CalledOnValidThread());
size_t count = 0;
- for (auto item : update_context_->update_items) {
+ for (auto* item : update_context_->update_items) {
if (item->state == from) {
ChangeItemState(item, to);
++count;
@@ -123,6 +125,21 @@ void ActionImpl::UpdateCrx() {
CrxUpdateItem* item = FindUpdateItemById(id);
DCHECK(item);
+ item->update_begin = base::TimeTicks::Now();
+
+ if (item->component.supports_group_policy_enable_component_updates &&
+ !update_context_->enabled_component_updates) {
+ item->error_category =
+ static_cast<int>(Action::ErrorCategory::kServiceError);
+ item->error_code =
+ static_cast<int>(Action::ServiceError::ERROR_UPDATE_DISABLED);
+ item->extra_code1 = 0;
+ ChangeItemState(item, CrxUpdateItem::State::kNoUpdate);
+
+ UpdateCrxComplete(item);
+ return;
+ }
+
std::unique_ptr<Action> update_action(
CanTryDiffUpdate(item, update_context_->config)
? ActionUpdateDiff::Create()
@@ -136,6 +153,9 @@ void ActionImpl::UpdateCrx() {
}
void ActionImpl::UpdateCrxComplete(CrxUpdateItem* item) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(item);
+
update_context_->ping_manager->SendPing(item);
update_context_->queue.pop();
@@ -143,12 +163,19 @@ void ActionImpl::UpdateCrxComplete(CrxUpdateItem* item) {
if (update_context_->queue.empty()) {
UpdateComplete(0);
} else {
- // TODO(sorin): the value of timing interval between CRX updates might have
- // to be injected at the call site of update_client::UpdateClient::Update.
- const int wait_sec = update_context_->config->UpdateDelay();
+ DCHECK(!item->update_begin.is_null());
+
+ // Assume that the cost of applying the update is proportional with how
+ // long it took to apply it. Then delay the next update by the same time
+ // interval or the value provided by the configurator, whichever is less.
+ const base::TimeDelta max_update_delay =
+ base::TimeDelta::FromSeconds(update_context_->config->UpdateDelay());
+ const base::TimeDelta update_cost(base::TimeTicks::Now() -
+ item->update_begin);
+ DCHECK(update_cost >= base::TimeDelta());
std::unique_ptr<ActionWait> action_wait(
- new ActionWait(base::TimeDelta::FromSeconds(wait_sec)));
+ new ActionWait(std::min(update_cost, max_update_delay)));
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&Action::Run, base::Unretained(action_wait.get()),
diff --git a/chromium/components/update_client/action.h b/chromium/components/update_client/action.h
index 5b67134bc64..455aac4ee9e 100644
--- a/chromium/components/update_client/action.h
+++ b/chromium/components/update_client/action.h
@@ -40,6 +40,7 @@ class Action {
enum class ServiceError {
ERROR_WAIT = 1,
+ ERROR_UPDATE_DISABLED = 2,
};
using Callback = base::Callback<void(int error)>;
diff --git a/chromium/components/update_client/action_update.cc b/chromium/components/update_client/action_update.cc
index 2e33c1e54a6..fef4eb8db02 100644
--- a/chromium/components/update_client/action_update.cc
+++ b/chromium/components/update_client/action_update.cc
@@ -139,7 +139,7 @@ void ActionUpdate::DoInstallOnBlockingTaskRunner(
CrxUpdateItem* item,
const base::FilePath& crx_path) {
unpacker_ = new ComponentUnpacker(
- item->component.pk_hash, crx_path, item->component.fingerprint,
+ item->component.pk_hash, crx_path, item->next_fp,
item->component.installer,
update_context->config->CreateOutOfProcessPatcher(),
update_context->blocking_task_runner);
@@ -295,7 +295,7 @@ bool ActionUpdateFull::IsBackgroundDownload(const CrxUpdateItem* item) {
// On demand component updates are always downloaded in foreground.
return !item->on_demand && item->component.allows_background_download &&
- update_context_->config->UseBackgroundDownloader();
+ update_context_->config->EnabledBackgroundDownloader();
}
std::vector<GURL> ActionUpdateFull::GetUrls(const CrxUpdateItem* item) {
diff --git a/chromium/components/update_client/action_update_check.cc b/chromium/components/update_client/action_update_check.cc
index 6263d165f39..b68b4b445f1 100644
--- a/chromium/components/update_client/action_update_check.cc
+++ b/chromium/components/update_client/action_update_check.cc
@@ -29,8 +29,8 @@ namespace update_client {
namespace {
// Returns true if the |proposed| version is newer than |current| version.
-bool IsVersionNewer(const Version& current, const std::string& proposed) {
- Version proposed_ver(proposed);
+bool IsVersionNewer(const base::Version& current, const std::string& proposed) {
+ base::Version proposed_ver(proposed);
return proposed_ver.IsValid() && current.CompareTo(proposed_ver) < 0;
}
@@ -66,11 +66,11 @@ void ActionUpdateCheck::Run(UpdateContext* update_context, Callback callback) {
item->id = GetCrxComponentID(crx_component);
item->component = crx_component;
- item->last_check = base::Time::Now();
+ item->last_check = base::TimeTicks::Now();
item->crx_urls.clear();
item->crx_diffurls.clear();
item->previous_version = crx_component.version;
- item->next_version = Version();
+ item->next_version = base::Version();
item->previous_fp = crx_component.fingerprint;
item->next_fp.clear();
item->on_demand = update_context->is_foreground;
@@ -91,6 +91,7 @@ void ActionUpdateCheck::Run(UpdateContext* update_context, Callback callback) {
update_checker_->CheckForUpdates(
update_context_->update_items, extra_request_parameters_,
+ update_context_->enabled_component_updates,
base::Bind(&ActionUpdateCheck::UpdateCheckComplete,
base::Unretained(this)));
}
@@ -155,7 +156,7 @@ void ActionUpdateCheck::OnUpdateCheckSucceeded(
}
// Parse the members of the result and queue an upgrade for this CRX.
- crx->next_version = Version(it->manifest.version);
+ crx->next_version = base::Version(it->manifest.version);
VLOG(1) << "Update found for CRX: " << crx->id;
diff --git a/chromium/components/update_client/action_wait.cc b/chromium/components/update_client/action_wait.cc
index f18d7ccdbb3..a4fddefb89c 100644
--- a/chromium/components/update_client/action_wait.cc
+++ b/chromium/components/update_client/action_wait.cc
@@ -36,7 +36,7 @@ void ActionWait::Run(UpdateContext* update_context, Callback callback) {
// control flow to the update engine, as the updates in this context are
// completed with an error.
while (!update_context->queue.empty()) {
- const auto item = FindUpdateItemById(update_context->queue.front());
+ auto* item = FindUpdateItemById(update_context->queue.front());
if (!item) {
item->error_category = static_cast<int>(ErrorCategory::kServiceError);
item->error_code = static_cast<int>(ServiceError::ERROR_WAIT);
diff --git a/chromium/components/update_client/background_downloader_win.cc b/chromium/components/update_client/background_downloader_win.cc
index 20d75c3e57a..857e2bb4416 100644
--- a/chromium/components/update_client/background_downloader_win.cc
+++ b/chromium/components/update_client/background_downloader_win.cc
@@ -12,6 +12,7 @@
#include <functional>
#include <iomanip>
#include <limits>
+#include <memory>
#include <utility>
#include <vector>
@@ -459,7 +460,7 @@ void BackgroundDownloader::DoStartDownload(const GURL& url) {
void BackgroundDownloader::BeginDownload(const GURL& url) {
DCHECK(task_runner()->RunsTasksOnCurrentThread());
- download_start_time_ = base::Time::Now();
+ download_start_time_ = base::TimeTicks::Now();
job_stuck_begin_time_ = download_start_time_;
HRESULT hr = BeginDownloadHelper(url);
@@ -572,7 +573,7 @@ void BackgroundDownloader::EndDownload(HRESULT error) {
DCHECK(!TimerIsRunning());
- const base::Time download_end_time(base::Time::Now());
+ const base::TimeTicks download_end_time(base::TimeTicks::Now());
const base::TimeDelta download_time =
download_end_time >= download_start_time_
? download_end_time - download_start_time_
@@ -690,7 +691,7 @@ bool BackgroundDownloader::OnStateQueued() {
bool BackgroundDownloader::OnStateTransferring() {
// Resets the baseline for detecting a stuck job since the job is transferring
// data and it is making progress.
- job_stuck_begin_time_ = base::Time::Now();
+ job_stuck_begin_time_ = base::TimeTicks::Now();
int64_t downloaded_bytes = -1;
int64_t total_bytes = -1;
@@ -799,7 +800,7 @@ HRESULT BackgroundDownloader::InitializeNewJob(
bool BackgroundDownloader::IsStuck() {
const base::TimeDelta job_stuck_timeout(
base::TimeDelta::FromMinutes(kJobStuckTimeoutMin));
- return job_stuck_begin_time_ + job_stuck_timeout < base::Time::Now();
+ return job_stuck_begin_time_ + job_stuck_timeout < base::TimeTicks::Now();
}
HRESULT BackgroundDownloader::CompleteJob() {
@@ -873,8 +874,8 @@ HRESULT BackgroundDownloader::ClearGit() {
};
for (auto cookie : cookies) {
- hr = git->RevokeInterfaceFromGlobal(cookie);
- DCHECK(SUCCEEDED(hr));
+ // TODO(sorin): check the result of the call, see crbug.com/644857.
+ git->RevokeInterfaceFromGlobal(cookie);
}
return S_OK;
diff --git a/chromium/components/update_client/background_downloader_win.h b/chromium/components/update_client/background_downloader_win.h
index 243461e644e..cf90d18d58a 100644
--- a/chromium/components/update_client/background_downloader_win.h
+++ b/chromium/components/update_client/background_downloader_win.h
@@ -8,6 +8,8 @@
#include <windows.h>
#include <bits.h>
+#include <memory>
+
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
@@ -134,10 +136,10 @@ class BackgroundDownloader : public CrxDownloader {
base::win::ScopedComPtr<IBackgroundCopyJob> job_;
// Contains the time when the download of the current url has started.
- base::Time download_start_time_;
+ base::TimeTicks download_start_time_;
// Contains the time when the BITS job is last seen making progress.
- base::Time job_stuck_begin_time_;
+ base::TimeTicks job_stuck_begin_time_;
// Contains the path of the downloaded file if the download was successful.
base::FilePath response_;
diff --git a/chromium/components/update_client/component_patcher.h b/chromium/components/update_client/component_patcher.h
index 9714abe27e2..ff61bf198c6 100644
--- a/chromium/components/update_client/component_patcher.h
+++ b/chromium/components/update_client/component_patcher.h
@@ -16,7 +16,7 @@
// prodversionmin="2.0.143.0"
// codebasediff="http://example.com/diff_1.2.3.4.crx"
// hashdiff="123" sizediff="101"
-// fp="1.123" />
+// fp="1.123"/>
// The component updater will attempt a differential update if it is available
// and allowed to, and fall back to a full update if it fails.
//
diff --git a/chromium/components/update_client/component_patcher_operation.cc b/chromium/components/update_client/component_patcher_operation.cc
index 2da622daacb..956bc021446 100644
--- a/chromium/components/update_client/component_patcher_operation.cc
+++ b/chromium/components/update_client/component_patcher_operation.cc
@@ -208,8 +208,8 @@ void DeltaUpdateOpPatch::DoRun(const ComponentUnpacker::Callback& callback) {
if (operation_ == kBsdiff) {
DonePatching(callback,
- courgette::ApplyBinaryPatch(input_abs_path_, patch_abs_path_,
- output_abs_path_));
+ bsdiff::ApplyBinaryPatch(input_abs_path_, patch_abs_path_,
+ output_abs_path_));
} else if (operation_ == kCourgette) {
DonePatching(callback, courgette::ApplyEnsemblePatch(
input_abs_path_.value().c_str(),
@@ -224,7 +224,7 @@ void DeltaUpdateOpPatch::DonePatching(
const ComponentUnpacker::Callback& callback,
int result) {
if (operation_ == kBsdiff) {
- if (result == courgette::OK) {
+ if (result == bsdiff::OK) {
callback.Run(ComponentUnpacker::kNone, 0);
} else {
callback.Run(ComponentUnpacker::kDeltaOperationFailure,
diff --git a/chromium/components/update_client/component_patcher_unittest.cc b/chromium/components/update_client/component_patcher_unittest.cc
index ba8fafafafb..a684e12bf46 100644
--- a/chromium/components/update_client/component_patcher_unittest.cc
+++ b/chromium/components/update_client/component_patcher_unittest.cc
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/path_service.h"
#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "components/update_client/component_patcher.h"
#include "components/update_client/component_patcher_operation.h"
@@ -68,8 +69,8 @@ ComponentPatcherOperationTest::ComponentPatcherOperationTest() {
EXPECT_TRUE(unpack_dir_.CreateUniqueTempDir());
EXPECT_TRUE(input_dir_.CreateUniqueTempDir());
EXPECT_TRUE(installed_dir_.CreateUniqueTempDir());
- installer_ = new ReadOnlyTestInstaller(installed_dir_.path());
- task_runner_ = base::MessageLoop::current()->task_runner();
+ installer_ = new ReadOnlyTestInstaller(installed_dir_.GetPath());
+ task_runner_ = base::ThreadTaskRunnerHandle::Get();
}
ComponentPatcherOperationTest::~ComponentPatcherOperationTest() {
@@ -79,7 +80,7 @@ ComponentPatcherOperationTest::~ComponentPatcherOperationTest() {
TEST_F(ComponentPatcherOperationTest, CheckCreateOperation) {
EXPECT_TRUE(base::CopyFile(
test_file("binary_output.bin"),
- input_dir_.path().Append(FILE_PATH_LITERAL("binary_output.bin"))));
+ input_dir_.GetPath().Append(FILE_PATH_LITERAL("binary_output.bin"))));
std::unique_ptr<base::DictionaryValue> command_args(
new base::DictionaryValue());
@@ -90,7 +91,7 @@ TEST_F(ComponentPatcherOperationTest, CheckCreateOperation) {
TestCallback callback;
scoped_refptr<DeltaUpdateOp> op = new DeltaUpdateOpCreate();
- op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(), NULL,
+ op->Run(command_args.get(), input_dir_.GetPath(), unpack_dir_.GetPath(), NULL,
base::Bind(&TestCallback::Set, base::Unretained(&callback)),
task_runner_);
base::RunLoop().RunUntilIdle();
@@ -99,7 +100,7 @@ TEST_F(ComponentPatcherOperationTest, CheckCreateOperation) {
EXPECT_EQ(ComponentUnpacker::kNone, callback.error_);
EXPECT_EQ(0, callback.extra_code_);
EXPECT_TRUE(base::ContentsEqual(
- unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")),
+ unpack_dir_.GetPath().Append(FILE_PATH_LITERAL("output.bin")),
test_file("binary_output.bin")));
}
@@ -107,7 +108,7 @@ TEST_F(ComponentPatcherOperationTest, CheckCreateOperation) {
TEST_F(ComponentPatcherOperationTest, CheckCopyOperation) {
EXPECT_TRUE(base::CopyFile(
test_file("binary_output.bin"),
- installed_dir_.path().Append(FILE_PATH_LITERAL("binary_output.bin"))));
+ installed_dir_.GetPath().Append(FILE_PATH_LITERAL("binary_output.bin"))));
std::unique_ptr<base::DictionaryValue> command_args(
new base::DictionaryValue());
@@ -118,7 +119,7 @@ TEST_F(ComponentPatcherOperationTest, CheckCopyOperation) {
TestCallback callback;
scoped_refptr<DeltaUpdateOp> op = new DeltaUpdateOpCopy();
- op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(),
+ op->Run(command_args.get(), input_dir_.GetPath(), unpack_dir_.GetPath(),
installer_.get(),
base::Bind(&TestCallback::Set, base::Unretained(&callback)),
task_runner_);
@@ -128,7 +129,7 @@ TEST_F(ComponentPatcherOperationTest, CheckCopyOperation) {
EXPECT_EQ(ComponentUnpacker::kNone, callback.error_);
EXPECT_EQ(0, callback.extra_code_);
EXPECT_TRUE(base::ContentsEqual(
- unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")),
+ unpack_dir_.GetPath().Append(FILE_PATH_LITERAL("output.bin")),
test_file("binary_output.bin")));
}
@@ -136,9 +137,9 @@ TEST_F(ComponentPatcherOperationTest, CheckCopyOperation) {
TEST_F(ComponentPatcherOperationTest, CheckCourgetteOperation) {
EXPECT_TRUE(base::CopyFile(
test_file("binary_input.bin"),
- installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin"))));
+ installed_dir_.GetPath().Append(FILE_PATH_LITERAL("binary_input.bin"))));
EXPECT_TRUE(base::CopyFile(test_file("binary_courgette_patch.bin"),
- input_dir_.path().Append(FILE_PATH_LITERAL(
+ input_dir_.GetPath().Append(FILE_PATH_LITERAL(
"binary_courgette_patch.bin"))));
std::unique_ptr<base::DictionaryValue> command_args(
@@ -152,7 +153,7 @@ TEST_F(ComponentPatcherOperationTest, CheckCourgetteOperation) {
TestCallback callback;
scoped_refptr<DeltaUpdateOp> op =
CreateDeltaUpdateOp("courgette", NULL /* out_of_process_patcher */);
- op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(),
+ op->Run(command_args.get(), input_dir_.GetPath(), unpack_dir_.GetPath(),
installer_.get(),
base::Bind(&TestCallback::Set, base::Unretained(&callback)),
task_runner_);
@@ -162,7 +163,7 @@ TEST_F(ComponentPatcherOperationTest, CheckCourgetteOperation) {
EXPECT_EQ(ComponentUnpacker::kNone, callback.error_);
EXPECT_EQ(0, callback.extra_code_);
EXPECT_TRUE(base::ContentsEqual(
- unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")),
+ unpack_dir_.GetPath().Append(FILE_PATH_LITERAL("output.bin")),
test_file("binary_output.bin")));
}
@@ -170,10 +171,10 @@ TEST_F(ComponentPatcherOperationTest, CheckCourgetteOperation) {
TEST_F(ComponentPatcherOperationTest, CheckBsdiffOperation) {
EXPECT_TRUE(base::CopyFile(
test_file("binary_input.bin"),
- installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin"))));
- EXPECT_TRUE(base::CopyFile(
- test_file("binary_bsdiff_patch.bin"),
- input_dir_.path().Append(FILE_PATH_LITERAL("binary_bsdiff_patch.bin"))));
+ installed_dir_.GetPath().Append(FILE_PATH_LITERAL("binary_input.bin"))));
+ EXPECT_TRUE(base::CopyFile(test_file("binary_bsdiff_patch.bin"),
+ input_dir_.GetPath().Append(FILE_PATH_LITERAL(
+ "binary_bsdiff_patch.bin"))));
std::unique_ptr<base::DictionaryValue> command_args(
new base::DictionaryValue());
@@ -186,7 +187,7 @@ TEST_F(ComponentPatcherOperationTest, CheckBsdiffOperation) {
TestCallback callback;
scoped_refptr<DeltaUpdateOp> op =
CreateDeltaUpdateOp("bsdiff", NULL /* out_of_process_patcher */);
- op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(),
+ op->Run(command_args.get(), input_dir_.GetPath(), unpack_dir_.GetPath(),
installer_.get(),
base::Bind(&TestCallback::Set, base::Unretained(&callback)),
task_runner_);
@@ -196,7 +197,7 @@ TEST_F(ComponentPatcherOperationTest, CheckBsdiffOperation) {
EXPECT_EQ(ComponentUnpacker::kNone, callback.error_);
EXPECT_EQ(0, callback.extra_code_);
EXPECT_TRUE(base::ContentsEqual(
- unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")),
+ unpack_dir_.GetPath().Append(FILE_PATH_LITERAL("output.bin")),
test_file("binary_output.bin")));
}
diff --git a/chromium/components/update_client/configurator.h b/chromium/components/update_client/configurator.h
index 7f55b9b761e..384b23de6bf 100644
--- a/chromium/components/update_client/configurator.h
+++ b/chromium/components/update_client/configurator.h
@@ -58,6 +58,11 @@ class Configurator : public base::RefCountedThreadSafe<Configurator> {
// disabled. Similarly, these URLs have a fall back behavior too.
virtual std::vector<GURL> PingUrl() const = 0;
+ // The ProdId is used as a prefix in some of the version strings which appear
+ // in the protocol requests. Possible values include "chrome", "chromecrx",
+ // "chromiumcrx", and "unknown".
+ virtual std::string GetProdId() const = 0;
+
// Version of the application. Used to compare the component manifests.
virtual base::Version GetBrowserVersion() const = 0;
@@ -99,14 +104,20 @@ class Configurator : public base::RefCountedThreadSafe<Configurator> {
CreateOutOfProcessPatcher() const = 0;
// True means that this client can handle delta updates.
- virtual bool DeltasEnabled() const = 0;
+ virtual bool EnabledDeltas() const = 0;
+
+ // True if component updates are enabled. Updates for all components are
+ // enabled by default. This method allows enabling or disabling
+ // updates for certain components such as the plugins. Updates for some
+ // components are always enabled and can't be disabled programatically.
+ virtual bool EnabledComponentUpdates() const = 0;
// True means that the background downloader can be used for downloading
// non on-demand components.
- virtual bool UseBackgroundDownloader() const = 0;
+ virtual bool EnabledBackgroundDownloader() const = 0;
// True if signing of update checks is enabled.
- virtual bool UseCupSigning() const = 0;
+ virtual bool EnabledCupSigning() const = 0;
// Gets a task runner to a blocking pool of threads suitable for worker jobs.
virtual scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner()
@@ -120,6 +131,10 @@ class Configurator : public base::RefCountedThreadSafe<Configurator> {
// persistent storage.
virtual PrefService* GetPrefService() const = 0;
+ // Returns true if the Chrome is installed for the current user only, or false
+ // if Chrome is installed for all users on the machine.
+ virtual bool IsPerUserInstall() const = 0;
+
protected:
friend class base::RefCountedThreadSafe<Configurator>;
diff --git a/chromium/components/update_client/crx_update_item.h b/chromium/components/update_client/crx_update_item.h
index b7c1ba1f157..5dd749cf71b 100644
--- a/chromium/components/update_client/crx_update_item.h
+++ b/chromium/components/update_client/crx_update_item.h
@@ -79,7 +79,11 @@ struct CrxUpdateItem {
std::string id;
CrxComponent component;
- base::Time last_check;
+ // Time when an update check for this CRX has happened.
+ base::TimeTicks last_check;
+
+ // Time when the update of this CRX has begun.
+ base::TimeTicks update_begin;
// A component can be made available for download from several urls.
std::vector<GURL> crx_urls;
@@ -90,8 +94,8 @@ struct CrxUpdateItem {
std::string hashdiff_sha256;
// The from/to version and fingerprint values.
- Version previous_version;
- Version next_version;
+ base::Version previous_version;
+ base::Version next_version;
std::string previous_fp;
std::string next_fp;
diff --git a/chromium/components/update_client/persisted_data.cc b/chromium/components/update_client/persisted_data.cc
index 673ba1e6b16..4f2c34a4630 100644
--- a/chromium/components/update_client/persisted_data.cc
+++ b/chromium/components/update_client/persisted_data.cc
@@ -28,33 +28,62 @@ PersistedData::~PersistedData() {
DCHECK(thread_checker_.CalledOnValidThread());
}
-int PersistedData::GetDateLastRollCall(const std::string& id) const {
+int PersistedData::GetInt(const std::string& id,
+ const std::string& key,
+ int fallback) const {
DCHECK(thread_checker_.CalledOnValidThread());
+ // We assume ids do not contain '.' characters.
+ DCHECK_EQ(std::string::npos, id.find('.'));
if (!pref_service_)
- return kDateLastRollCallUnknown;
- int dlrc = kDateLastRollCallUnknown;
+ return fallback;
const base::DictionaryValue* dict =
pref_service_->GetDictionary(kPersistedDataPreference);
- // We assume ids do not contain '.' characters.
- DCHECK_EQ(std::string::npos, id.find('.'));
- if (!dict->GetInteger(base::StringPrintf("apps.%s.dlrc", id.c_str()), &dlrc))
- return kDateLastRollCallUnknown;
- return dlrc;
+ if (!dict)
+ return fallback;
+ int result = 0;
+ return dict->GetInteger(
+ base::StringPrintf("apps.%s.%s", id.c_str(), key.c_str()), &result)
+ ? result
+ : fallback;
}
-std::string PersistedData::GetPingFreshness(const std::string& id) const {
+std::string PersistedData::GetString(const std::string& id,
+ const std::string& key) const {
DCHECK(thread_checker_.CalledOnValidThread());
+ // We assume ids do not contain '.' characters.
+ DCHECK_EQ(std::string::npos, id.find('.'));
if (!pref_service_)
return std::string();
- std::string freshness;
const base::DictionaryValue* dict =
pref_service_->GetDictionary(kPersistedDataPreference);
- // We assume ids do not contain '.' characters.
- DCHECK_EQ(std::string::npos, id.find('.'));
- if (!dict->GetString(base::StringPrintf("apps.%s.pf", id.c_str()),
- &freshness))
+ if (!dict)
return std::string();
- return base::StringPrintf("{%s}", freshness.c_str());
+ std::string result;
+ return dict->GetString(
+ base::StringPrintf("apps.%s.%s", id.c_str(), key.c_str()), &result)
+ ? result
+ : std::string();
+}
+
+int PersistedData::GetDateLastRollCall(const std::string& id) const {
+ return GetInt(id, "dlrc", kDateLastRollCallUnknown);
+}
+
+std::string PersistedData::GetPingFreshness(const std::string& id) const {
+ std::string result = GetString(id, "pf");
+ return !result.empty() ? base::StringPrintf("{%s}", result.c_str()) : result;
+}
+
+std::string PersistedData::GetCohort(const std::string& id) const {
+ return GetString(id, "cohort");
+}
+
+std::string PersistedData::GetCohortName(const std::string& id) const {
+ return GetString(id, "cohortname");
+}
+
+std::string PersistedData::GetCohortHint(const std::string& id) const {
+ return GetString(id, "cohorthint");
}
void PersistedData::SetDateLastRollCall(const std::vector<std::string>& ids,
@@ -72,6 +101,32 @@ void PersistedData::SetDateLastRollCall(const std::vector<std::string>& ids,
}
}
+void PersistedData::SetString(const std::string& id,
+ const std::string& key,
+ const std::string& value) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!pref_service_)
+ return;
+ DictionaryPrefUpdate update(pref_service_, kPersistedDataPreference);
+ update->SetString(base::StringPrintf("apps.%s.%s", id.c_str(), key.c_str()),
+ value);
+}
+
+void PersistedData::SetCohort(const std::string& id,
+ const std::string& cohort) {
+ SetString(id, "cohort", cohort);
+}
+
+void PersistedData::SetCohortName(const std::string& id,
+ const std::string& cohort_name) {
+ SetString(id, "cohortname", cohort_name);
+}
+
+void PersistedData::SetCohortHint(const std::string& id,
+ const std::string& cohort_hint) {
+ SetString(id, "cohorthint", cohort_hint);
+}
+
void PersistedData::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(kPersistedDataPreference);
}
diff --git a/chromium/components/update_client/persisted_data.h b/chromium/components/update_client/persisted_data.h
index 6b24e571258..06d4d0d2d07 100644
--- a/chromium/components/update_client/persisted_data.h
+++ b/chromium/components/update_client/persisted_data.h
@@ -52,7 +52,27 @@ class PersistedData {
// This is called only via update_client's RegisterUpdateClientPreferences.
static void RegisterPrefs(PrefRegistrySimple* registry);
+ // These functions return cohort data for the specified |id|. "Cohort"
+ // indicates the membership of the client in any release channels components
+ // have set up in a machine-readable format, while "CohortName" does so in a
+ // human-readable form. "CohortHint" indicates the client's channel selection
+ // preference.
+ std::string GetCohort(const std::string& id) const;
+ std::string GetCohortHint(const std::string& id) const;
+ std::string GetCohortName(const std::string& id) const;
+
+ // These functions set cohort data for the specified |id|.
+ void SetCohort(const std::string& id, const std::string& cohort);
+ void SetCohortHint(const std::string& id, const std::string& cohort_hint);
+ void SetCohortName(const std::string& id, const std::string& cohort_name);
+
private:
+ int GetInt(const std::string& id, const std::string& key, int fallback) const;
+ std::string GetString(const std::string& id, const std::string& key) const;
+ void SetString(const std::string& id,
+ const std::string& key,
+ const std::string& value);
+
base::ThreadChecker thread_checker_;
PrefService* pref_service_;
diff --git a/chromium/components/update_client/persisted_data_unittest.cc b/chromium/components/update_client/persisted_data_unittest.cc
index dfe242c2a61..cc5f875f31a 100644
--- a/chromium/components/update_client/persisted_data_unittest.cc
+++ b/chromium/components/update_client/persisted_data_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 <memory>
#include <string>
#include <vector>
@@ -50,4 +51,41 @@ TEST(PersistedDataTest, SharedPref) {
EXPECT_EQ(-2, metadata->GetDateLastRollCall("someotherappid"));
}
+TEST(PersistedDataTest, SimpleCohort) {
+ std::unique_ptr<TestingPrefServiceSimple> pref(
+ new TestingPrefServiceSimple());
+ PersistedData::RegisterPrefs(pref->registry());
+ std::unique_ptr<PersistedData> metadata(new PersistedData(pref.get()));
+ EXPECT_EQ("", metadata->GetCohort("someappid"));
+ EXPECT_EQ("", metadata->GetCohort("someotherappid"));
+ EXPECT_EQ("", metadata->GetCohortHint("someappid"));
+ EXPECT_EQ("", metadata->GetCohortHint("someotherappid"));
+ EXPECT_EQ("", metadata->GetCohortName("someappid"));
+ EXPECT_EQ("", metadata->GetCohortName("someotherappid"));
+ metadata->SetCohort("someappid", "c1");
+ metadata->SetCohort("someotherappid", "c2");
+ metadata->SetCohortHint("someappid", "ch1");
+ metadata->SetCohortHint("someotherappid", "ch2");
+ metadata->SetCohortName("someappid", "cn1");
+ metadata->SetCohortName("someotherappid", "cn2");
+ EXPECT_EQ("c1", metadata->GetCohort("someappid"));
+ EXPECT_EQ("c2", metadata->GetCohort("someotherappid"));
+ EXPECT_EQ("ch1", metadata->GetCohortHint("someappid"));
+ EXPECT_EQ("ch2", metadata->GetCohortHint("someotherappid"));
+ EXPECT_EQ("cn1", metadata->GetCohortName("someappid"));
+ EXPECT_EQ("cn2", metadata->GetCohortName("someotherappid"));
+ metadata->SetCohort("someappid", "oc1");
+ metadata->SetCohort("someotherappid", "oc2");
+ metadata->SetCohortHint("someappid", "och1");
+ metadata->SetCohortHint("someotherappid", "och2");
+ metadata->SetCohortName("someappid", "ocn1");
+ metadata->SetCohortName("someotherappid", "ocn2");
+ EXPECT_EQ("oc1", metadata->GetCohort("someappid"));
+ EXPECT_EQ("oc2", metadata->GetCohort("someotherappid"));
+ EXPECT_EQ("och1", metadata->GetCohortHint("someappid"));
+ EXPECT_EQ("och2", metadata->GetCohortHint("someotherappid"));
+ EXPECT_EQ("ocn1", metadata->GetCohortName("someappid"));
+ EXPECT_EQ("ocn2", metadata->GetCohortName("someotherappid"));
+}
+
} // namespace update_client
diff --git a/chromium/components/update_client/ping_manager.cc b/chromium/components/update_client/ping_manager.cc
index 59ee87523e3..47ae77c3cf4 100644
--- a/chromium/components/update_client/ping_manager.cc
+++ b/chromium/components/update_client/ping_manager.cc
@@ -162,10 +162,10 @@ std::string BuildPing(const Configurator& config, const CrxUpdateItem* item) {
ping_event.c_str(), // ping event
BuildDownloadCompleteEventElements(item).c_str())); // download events
- return BuildProtocolRequest(config.GetBrowserVersion().GetString(),
- config.GetChannel(), config.GetLang(),
- config.GetOSLongName(),
- config.GetDownloadPreference(), app_element, "");
+ return BuildProtocolRequest(
+ config.GetProdId(), config.GetBrowserVersion().GetString(),
+ config.GetChannel(), config.GetLang(), config.GetOSLongName(),
+ config.GetDownloadPreference(), app_element, "");
}
// Sends a fire and forget ping. The instances of this class have no
diff --git a/chromium/components/update_client/request_sender.cc b/chromium/components/update_client/request_sender.cc
index 7f48dd72351..b99648a6c25 100644
--- a/chromium/components/update_client/request_sender.cc
+++ b/chromium/components/update_client/request_sender.cc
@@ -207,7 +207,7 @@ GURL RequestSender::BuildUpdateUrl(const GURL& url,
std::string RequestSender::GetStringHeaderValue(const net::URLFetcher* source,
const char* header_name) {
- const auto response_headers(source->GetResponseHeaders());
+ auto* response_headers(source->GetResponseHeaders());
if (!response_headers)
return std::string();
@@ -219,7 +219,7 @@ std::string RequestSender::GetStringHeaderValue(const net::URLFetcher* source,
int64_t RequestSender::GetInt64HeaderValue(const net::URLFetcher* source,
const char* header_name) {
- const auto response_headers(source->GetResponseHeaders());
+ auto* response_headers(source->GetResponseHeaders());
return response_headers ? response_headers->GetInt64HeaderValue(header_name)
: -1;
}
diff --git a/chromium/components/update_client/request_sender_unittest.cc b/chromium/components/update_client/request_sender_unittest.cc
index 3b1c635c41b..1c34b3a2e07 100644
--- a/chromium/components/update_client/request_sender_unittest.cc
+++ b/chromium/components/update_client/request_sender_unittest.cc
@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/components/update_client/test_configurator.cc b/chromium/components/update_client/test_configurator.cc
index 1da523f8fc9..edf5ddfac50 100644
--- a/chromium/components/update_client/test_configurator.cc
+++ b/chromium/components/update_client/test_configurator.cc
@@ -4,9 +4,12 @@
#include "components/update_client/test_configurator.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
#include "base/version.h"
#include "components/prefs/pref_service.h"
#include "components/update_client/component_patcher_operation.h"
+#include "net/url_request/url_request_test_util.h"
#include "url/gurl.h"
namespace update_client {
@@ -29,7 +32,8 @@ TestConfigurator::TestConfigurator(
brand_("TEST"),
initial_time_(0),
ondemand_time_(0),
- use_cup_signing_(false),
+ enabled_cup_signing_(false),
+ enabled_component_updates_(true),
context_(new net::TestURLRequestContextGetter(network_task_runner)) {}
TestConfigurator::~TestConfigurator() {
@@ -69,6 +73,10 @@ std::vector<GURL> TestConfigurator::PingUrl() const {
return UpdateUrl();
}
+std::string TestConfigurator::GetProdId() const {
+ return "fake_prodid";
+}
+
base::Version TestConfigurator::GetBrowserVersion() const {
// Needs to be larger than the required version in tested component manifests.
return base::Version("30.0");
@@ -107,16 +115,20 @@ scoped_refptr<OutOfProcessPatcher> TestConfigurator::CreateOutOfProcessPatcher()
return NULL;
}
-bool TestConfigurator::DeltasEnabled() const {
+bool TestConfigurator::EnabledDeltas() const {
return true;
}
-bool TestConfigurator::UseBackgroundDownloader() const {
+bool TestConfigurator::EnabledComponentUpdates() const {
+ return enabled_component_updates_;
+}
+
+bool TestConfigurator::EnabledBackgroundDownloader() const {
return false;
}
-bool TestConfigurator::UseCupSigning() const {
- return use_cup_signing_;
+bool TestConfigurator::EnabledCupSigning() const {
+ return enabled_cup_signing_;
}
void TestConfigurator::SetBrand(const std::string& brand) {
@@ -131,8 +143,13 @@ void TestConfigurator::SetInitialDelay(int seconds) {
initial_time_ = seconds;
}
-void TestConfigurator::SetUseCupSigning(bool use_cup_signing) {
- use_cup_signing_ = use_cup_signing;
+void TestConfigurator::SetEnabledCupSigning(bool enabled_cup_signing) {
+ enabled_cup_signing_ = enabled_cup_signing;
+}
+
+void TestConfigurator::SetEnabledComponentUpdates(
+ bool enabled_component_updates) {
+ enabled_component_updates_ = enabled_component_updates;
}
void TestConfigurator::SetDownloadPreference(
@@ -158,4 +175,8 @@ PrefService* TestConfigurator::GetPrefService() const {
return nullptr;
}
+bool TestConfigurator::IsPerUserInstall() const {
+ return true;
+}
+
} // namespace update_client
diff --git a/chromium/components/update_client/test_configurator.h b/chromium/components/update_client/test_configurator.h
index 8a653794a22..89132f5a771 100644
--- a/chromium/components/update_client/test_configurator.h
+++ b/chromium/components/update_client/test_configurator.h
@@ -14,15 +14,20 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "components/update_client/configurator.h"
-#include "net/url_request/url_request_test_util.h"
+#include "url/gurl.h"
-class GURL;
class PrefService;
namespace base {
class SequencedTaskRunner;
+class SingleThreadTaskRunner;
} // namespace base
+namespace net {
+class TestURLRequestContextGetter;
+class URLRequestContextGetter;
+} // namespace net
+
namespace update_client {
#define POST_INTERCEPT_SCHEME "https"
@@ -64,6 +69,7 @@ class TestConfigurator : public Configurator {
int UpdateDelay() const override;
std::vector<GURL> UpdateUrl() const override;
std::vector<GURL> PingUrl() const override;
+ std::string GetProdId() const override;
base::Version GetBrowserVersion() const override;
std::string GetChannel() const override;
std::string GetBrand() const override;
@@ -73,18 +79,21 @@ class TestConfigurator : public Configurator {
std::string GetDownloadPreference() const override;
net::URLRequestContextGetter* RequestContext() const override;
scoped_refptr<OutOfProcessPatcher> CreateOutOfProcessPatcher() const override;
- bool DeltasEnabled() const override;
- bool UseBackgroundDownloader() const override;
- bool UseCupSigning() const override;
+ bool EnabledDeltas() const override;
+ bool EnabledComponentUpdates() const override;
+ bool EnabledBackgroundDownloader() const override;
+ bool EnabledCupSigning() const override;
scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner()
const override;
PrefService* GetPrefService() const override;
+ bool IsPerUserInstall() const override;
void SetBrand(const std::string& brand);
void SetOnDemandTime(int seconds);
void SetInitialDelay(int seconds);
void SetDownloadPreference(const std::string& download_preference);
- void SetUseCupSigning(bool use_cup_signing);
+ void SetEnabledCupSigning(bool use_cup_signing);
+ void SetEnabledComponentUpdates(bool enabled_component_updates);
void SetUpdateCheckUrl(const GURL& url);
void SetPingUrl(const GURL& url);
@@ -99,7 +108,8 @@ class TestConfigurator : public Configurator {
int initial_time_;
int ondemand_time_;
std::string download_preference_;
- bool use_cup_signing_;
+ bool enabled_cup_signing_;
+ bool enabled_component_updates_;
GURL update_check_url_;
GURL ping_url_;
diff --git a/chromium/components/update_client/test_installer.cc b/chromium/components/update_client/test_installer.cc
index ad6015b9800..21a3b2a3bed 100644
--- a/chromium/components/update_client/test_installer.cc
+++ b/chromium/components/update_client/test_installer.cc
@@ -62,7 +62,7 @@ bool VersionedTestInstaller::Install(const base::DictionaryValue& manifest,
const base::FilePath& unpack_path) {
std::string version_string;
manifest.GetStringASCII("version", &version_string);
- Version version(version_string.c_str());
+ base::Version version(version_string.c_str());
base::FilePath path;
path = install_directory_.AppendASCII(version.GetString());
diff --git a/chromium/components/update_client/test_installer.h b/chromium/components/update_client/test_installer.h
index b6ef1826e1b..97e582ee8b8 100644
--- a/chromium/components/update_client/test_installer.h
+++ b/chromium/components/update_client/test_installer.h
@@ -75,7 +75,7 @@ class VersionedTestInstaller : public TestInstaller {
~VersionedTestInstaller() override;
base::FilePath install_directory_;
- Version current_version_;
+ base::Version current_version_;
};
} // namespace update_client
diff --git a/chromium/components/update_client/update_checker.cc b/chromium/components/update_client/update_checker.cc
index 6080b13a6c6..8e01b595e4d 100644
--- a/chromium/components/update_client/update_checker.cc
+++ b/chromium/components/update_client/update_checker.cc
@@ -48,7 +48,7 @@ update_client::InstallerAttributes SanitizeInstallerAttributes(
// Returns true if at least one item requires network encryption.
bool IsEncryptionRequired(const std::vector<CrxUpdateItem*>& items) {
- for (const auto& item : items) {
+ for (const auto* item : items) {
if (item->component.requires_network_encryption)
return true;
}
@@ -64,15 +64,16 @@ bool IsEncryptionRequired(const std::vector<CrxUpdateItem*>& items) {
// An app element looks like this:
// <app appid="hnimpnehoodheedghdeeijklkeaacbdc"
// version="0.1.2.3" installsource="ondemand">
-// <updatecheck />
+// <updatecheck/>
// <packages>
-// <package fp="abcd" />
+// <package fp="abcd"/>
// </packages>
// </app>
std::string BuildUpdateCheckRequest(const Configurator& config,
const std::vector<CrxUpdateItem*>& items,
PersistedData* metadata,
- const std::string& additional_attributes) {
+ const std::string& additional_attributes,
+ bool enabled_component_updates) {
const std::string brand(SanitizeBrand(config.GetBrand()));
std::string app_elements;
for (size_t i = 0; i != items.size(); ++i) {
@@ -86,14 +87,29 @@ std::string BuildUpdateCheckRequest(const Configurator& config,
base::StringAppendF(&app, " brand=\"%s\"", brand.c_str());
if (item->on_demand)
base::StringAppendF(&app, " installsource=\"ondemand\"");
-
- for (const auto& attr : installer_attributes)
+ for (const auto& attr : installer_attributes) {
base::StringAppendF(&app, " %s=\"%s\"", attr.first.c_str(),
attr.second.c_str());
-
+ }
+ const std::string cohort = metadata->GetCohort(item->id);
+ const std::string cohort_name = metadata->GetCohortName(item->id);
+ const std::string cohort_hint = metadata->GetCohortHint(item->id);
+ if (!cohort.empty())
+ base::StringAppendF(&app, " cohort=\"%s\"", cohort.c_str());
+ if (!cohort_name.empty())
+ base::StringAppendF(&app, " cohortname=\"%s\"", cohort_name.c_str());
+ if (!cohort_hint.empty())
+ base::StringAppendF(&app, " cohorthint=\"%s\"", cohort_hint.c_str());
base::StringAppendF(&app, ">");
- base::StringAppendF(&app, "<updatecheck />");
- base::StringAppendF(&app, "<ping rd=\"%d\" ping_freshness=\"%s\" />",
+
+ base::StringAppendF(&app, "<updatecheck");
+ if (item->component.supports_group_policy_enable_component_updates &&
+ !enabled_component_updates) {
+ base::StringAppendF(&app, " updatedisabled=\"true\"");
+ }
+ base::StringAppendF(&app, "/>");
+
+ base::StringAppendF(&app, "<ping rd=\"%d\" ping_freshness=\"%s\"/>",
metadata->GetDateLastRollCall(item->id),
metadata->GetPingFreshness(item->id).c_str());
if (!item->component.fingerprint.empty()) {
@@ -109,9 +125,9 @@ std::string BuildUpdateCheckRequest(const Configurator& config,
}
return BuildProtocolRequest(
- config.GetBrowserVersion().GetString(), config.GetChannel(),
- config.GetLang(), config.GetOSLongName(), config.GetDownloadPreference(),
- app_elements, additional_attributes);
+ config.GetProdId(), config.GetBrowserVersion().GetString(),
+ config.GetChannel(), config.GetLang(), config.GetOSLongName(),
+ config.GetDownloadPreference(), app_elements, additional_attributes);
}
class UpdateCheckerImpl : public UpdateChecker {
@@ -124,6 +140,7 @@ class UpdateCheckerImpl : public UpdateChecker {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override;
private:
@@ -153,6 +170,7 @@ UpdateCheckerImpl::~UpdateCheckerImpl() {
bool UpdateCheckerImpl::CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -169,13 +187,13 @@ bool UpdateCheckerImpl::CheckForUpdates(
std::unique_ptr<std::vector<std::string>> ids_checked(
new std::vector<std::string>());
- for (auto crx : items_to_check)
+ for (auto* crx : items_to_check)
ids_checked->push_back(crx->id);
request_sender_.reset(new RequestSender(config_));
request_sender_->Send(
- config_->UseCupSigning(),
+ config_->EnabledCupSigning(),
BuildUpdateCheckRequest(*config_, items_to_check, metadata_,
- additional_attributes),
+ additional_attributes, enabled_component_updates),
urls, base::Bind(&UpdateCheckerImpl::OnRequestSenderComplete,
base::Unretained(this), base::Passed(&ids_checked)));
return true;
@@ -194,6 +212,17 @@ void UpdateCheckerImpl::OnRequestSenderComplete(
int daynum = update_response.results().daystart_elapsed_days;
if (daynum != UpdateResponse::kNoDaystart)
metadata_->SetDateLastRollCall(*ids_checked, daynum);
+ for (const auto& result : update_response.results().list) {
+ auto entry = result.cohort_attrs.find(UpdateResponse::Result::kCohort);
+ if (entry != result.cohort_attrs.end())
+ metadata_->SetCohort(result.extension_id, entry->second);
+ entry = result.cohort_attrs.find(UpdateResponse::Result::kCohortName);
+ if (entry != result.cohort_attrs.end())
+ metadata_->SetCohortName(result.extension_id, entry->second);
+ entry = result.cohort_attrs.find(UpdateResponse::Result::kCohortHint);
+ if (entry != result.cohort_attrs.end())
+ metadata_->SetCohortHint(result.extension_id, entry->second);
+ }
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(update_check_callback_, error,
update_response.results(), retry_after_sec));
diff --git a/chromium/components/update_client/update_checker.h b/chromium/components/update_client/update_checker.h
index 2705018ba95..d3080c3c848 100644
--- a/chromium/components/update_client/update_checker.h
+++ b/chromium/components/update_client/update_checker.h
@@ -42,6 +42,7 @@ class UpdateChecker {
virtual bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) = 0;
static std::unique_ptr<UpdateChecker> Create(
diff --git a/chromium/components/update_client/update_checker_unittest.cc b/chromium/components/update_client/update_checker_unittest.cc
index 8bac5ea1fc0..b914e848e8d 100644
--- a/chromium/components/update_client/update_checker_unittest.cc
+++ b/chromium/components/update_client/update_checker_unittest.cc
@@ -175,7 +175,7 @@ TEST_F(UpdateCheckerTest, UpdateCheckSuccess) {
items_to_check.push_back(&item);
update_checker_->CheckForUpdates(
- items_to_check, "extra=\"params\"",
+ items_to_check, "extra=\"params\"", true,
base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
@@ -196,7 +196,7 @@ TEST_F(UpdateCheckerTest, UpdateCheckSuccess) {
string::npos,
post_interceptor_->GetRequests()[0].find(
"<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\" "
- "brand=\"TEST\" ap=\"some_ap\"><updatecheck /><ping rd=\"-2\" "));
+ "brand=\"TEST\" ap=\"some_ap\"><updatecheck/><ping rd=\"-2\" "));
EXPECT_NE(string::npos,
post_interceptor_->GetRequests()[0].find(
"<packages><package fp=\"fp1\"/></packages></app>"));
@@ -204,6 +204,11 @@ TEST_F(UpdateCheckerTest, UpdateCheckSuccess) {
EXPECT_NE(string::npos,
post_interceptor_->GetRequests()[0].find("<hw physmemory="));
+ // Tests that the progid is injected correctly from the configurator.
+ EXPECT_NE(string::npos,
+ post_interceptor_->GetRequests()[0].find(
+ " version=\"fake_prodid-30.0\" prodversion=\"30.0\" "));
+
// Sanity check the arguments of the callback after parsing.
EXPECT_EQ(0, error_);
EXPECT_EQ(1ul, results_.list.size());
@@ -226,8 +231,9 @@ TEST_F(UpdateCheckerTest, UpdateCheckInvalidAp) {
items_to_check.push_back(&item);
update_checker_->CheckForUpdates(
- items_to_check, "", base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
- base::Unretained(this)));
+ items_to_check, "", true,
+ base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
+ base::Unretained(this)));
RunThreads();
@@ -235,7 +241,7 @@ TEST_F(UpdateCheckerTest, UpdateCheckInvalidAp) {
string::npos,
post_interceptor_->GetRequests()[0].find(
"app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\" "
- "brand=\"TEST\"><updatecheck /><ping rd=\"-2\" "));
+ "brand=\"TEST\"><updatecheck/><ping rd=\"-2\" "));
EXPECT_NE(string::npos,
post_interceptor_->GetRequests()[0].find(
"<packages><package fp=\"fp1\"/></packages></app>"));
@@ -253,8 +259,9 @@ TEST_F(UpdateCheckerTest, UpdateCheckSuccessNoBrand) {
items_to_check.push_back(&item);
update_checker_->CheckForUpdates(
- items_to_check, "", base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
- base::Unretained(this)));
+ items_to_check, "", true,
+ base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
+ base::Unretained(this)));
RunThreads();
@@ -262,7 +269,7 @@ TEST_F(UpdateCheckerTest, UpdateCheckSuccessNoBrand) {
string::npos,
post_interceptor_->GetRequests()[0].find(
"<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
- "<updatecheck /><ping rd=\"-2\" "));
+ "<updatecheck/><ping rd=\"-2\" "));
EXPECT_NE(string::npos,
post_interceptor_->GetRequests()[0].find(
"<packages><package fp=\"fp1\"/></packages></app>"));
@@ -280,8 +287,9 @@ TEST_F(UpdateCheckerTest, UpdateCheckError) {
items_to_check.push_back(&item);
update_checker_->CheckForUpdates(
- items_to_check, "", base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
- base::Unretained(this)));
+ items_to_check, "", true,
+ base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
+ base::Unretained(this)));
RunThreads();
EXPECT_EQ(1, post_interceptor_->GetHitCount())
@@ -306,7 +314,7 @@ TEST_F(UpdateCheckerTest, UpdateCheckDownloadPreference) {
items_to_check.push_back(&item);
update_checker_->CheckForUpdates(
- items_to_check, "extra=\"params\"",
+ items_to_check, "extra=\"params\"", true,
base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
@@ -324,7 +332,7 @@ TEST_F(UpdateCheckerTest, UpdateCheckCupError) {
EXPECT_TRUE(post_interceptor_->ExpectRequest(
new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
- config_->SetUseCupSigning(true);
+ config_->SetEnabledCupSigning(true);
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
CrxUpdateItem item(BuildCrxUpdateItem());
@@ -332,8 +340,9 @@ TEST_F(UpdateCheckerTest, UpdateCheckCupError) {
items_to_check.push_back(&item);
update_checker_->CheckForUpdates(
- items_to_check, "", base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
- base::Unretained(this)));
+ items_to_check, "", true,
+ base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
+ base::Unretained(this)));
RunThreads();
@@ -347,7 +356,7 @@ TEST_F(UpdateCheckerTest, UpdateCheckCupError) {
string::npos,
post_interceptor_->GetRequests()[0].find(
"<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\" "
- "brand=\"TEST\"><updatecheck /><ping rd=\"-2\" "));
+ "brand=\"TEST\"><updatecheck/><ping rd=\"-2\" "));
EXPECT_NE(string::npos,
post_interceptor_->GetRequests()[0].find(
"<packages><package fp=\"fp1\"/></packages></app>"));
@@ -370,8 +379,9 @@ TEST_F(UpdateCheckerTest, UpdateCheckRequiresEncryptionError) {
items_to_check.push_back(&item);
update_checker_->CheckForUpdates(
- items_to_check, "", base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
- base::Unretained(this)));
+ items_to_check, "", true,
+ base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
+ base::Unretained(this)));
RunThreads();
EXPECT_EQ(-1, error_);
@@ -394,13 +404,13 @@ TEST_F(UpdateCheckerTest, UpdateCheckDateLastRollCall) {
// Do two update-checks.
update_checker_->CheckForUpdates(
- items_to_check, "extra=\"params\"",
+ items_to_check, "extra=\"params\"", true,
base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
update_checker_->CheckForUpdates(
- items_to_check, "extra=\"params\"",
+ items_to_check, "extra=\"params\"", true,
base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
@@ -415,4 +425,84 @@ TEST_F(UpdateCheckerTest, UpdateCheckDateLastRollCall) {
"<ping rd=\"3383\" ping_freshness="));
}
+TEST_F(UpdateCheckerTest, UpdateCheckUpdateDisabled) {
+ EXPECT_TRUE(post_interceptor_->ExpectRequest(
+ new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
+
+ config_->SetBrand("");
+ update_checker_ = UpdateChecker::Create(config_, metadata_.get());
+
+ CrxUpdateItem item(BuildCrxUpdateItem());
+
+ // Tests the scenario where:
+ // * the component does not support group policies.
+ // * the component updates are disabled.
+ // Expects the group policy to be ignored and the update check to not
+ // include the "updatedisabled" attribute.
+ EXPECT_FALSE(item.component.supports_group_policy_enable_component_updates);
+ std::vector<CrxUpdateItem*> items_to_check;
+ items_to_check.push_back(&item);
+ update_checker_->CheckForUpdates(
+ items_to_check, "", false,
+ base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
+ base::Unretained(this)));
+ RunThreads();
+ EXPECT_NE(
+ string::npos,
+ post_interceptor_->GetRequests()[0].find(
+ "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
+ "<updatecheck/>"));
+
+ // Tests the scenario where:
+ // * the component supports group policies.
+ // * the component updates are disabled.
+ // Expects the update check to include the "updatedisabled" attribute.
+ item.component.supports_group_policy_enable_component_updates = true;
+ update_checker_ = UpdateChecker::Create(config_, metadata_.get());
+ update_checker_->CheckForUpdates(
+ items_to_check, "", false,
+ base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
+ base::Unretained(this)));
+ RunThreads();
+ EXPECT_NE(
+ string::npos,
+ post_interceptor_->GetRequests()[1].find(
+ "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
+ "<updatecheck updatedisabled=\"true\"/>"));
+
+ // Tests the scenario where:
+ // * the component does not support group policies.
+ // * the component updates are enabled.
+ // Expects the update check to not include the "updatedisabled" attribute.
+ item.component.supports_group_policy_enable_component_updates = false;
+ update_checker_ = UpdateChecker::Create(config_, metadata_.get());
+ update_checker_->CheckForUpdates(
+ items_to_check, "", true,
+ base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
+ base::Unretained(this)));
+ RunThreads();
+ EXPECT_NE(
+ string::npos,
+ post_interceptor_->GetRequests()[2].find(
+ "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
+ "<updatecheck/>"));
+
+ // Tests the scenario where:
+ // * the component supports group policies.
+ // * the component updates are enabled.
+ // Expects the update check to not include the "updatedisabled" attribute.
+ item.component.supports_group_policy_enable_component_updates = true;
+ update_checker_ = UpdateChecker::Create(config_, metadata_.get());
+ update_checker_->CheckForUpdates(
+ items_to_check, "", true,
+ base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
+ base::Unretained(this)));
+ RunThreads();
+ EXPECT_NE(
+ string::npos,
+ post_interceptor_->GetRequests()[3].find(
+ "<app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
+ "<updatecheck/>"));
+}
+
} // namespace update_client
diff --git a/chromium/components/update_client/update_client.cc b/chromium/components/update_client/update_client.cc
index 176d5b9d511..db4b21bb5bf 100644
--- a/chromium/components/update_client/update_client.cc
+++ b/chromium/components/update_client/update_client.cc
@@ -55,7 +55,9 @@ CrxUpdateItem::~CrxUpdateItem() {
}
CrxComponent::CrxComponent()
- : allows_background_download(true), requires_network_encryption(true) {}
+ : allows_background_download(true),
+ requires_network_encryption(true),
+ supports_group_policy_enable_component_updates(false) {}
CrxComponent::CrxComponent(const CrxComponent& other) = default;
@@ -196,7 +198,7 @@ bool UpdateClientImpl::GetCrxUpdateState(const std::string& id,
bool UpdateClientImpl::IsUpdating(const std::string& id) const {
DCHECK(thread_checker_.CalledOnValidThread());
- for (const auto& task : tasks_) {
+ for (const auto* task : tasks_) {
const auto ids(task->GetIds());
if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
return true;
@@ -225,14 +227,14 @@ void UpdateClientImpl::Stop() {
// they have not picked up by the update engine, and not shared with any
// task runner yet.
while (!task_queue_.empty()) {
- const auto task(task_queue_.front());
+ auto* task(task_queue_.front());
task_queue_.pop();
task->Cancel();
}
}
void UpdateClientImpl::SendUninstallPing(const std::string& id,
- const Version& version,
+ const base::Version& version,
int reason) {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chromium/components/update_client/update_client.h b/chromium/components/update_client/update_client.h
index 5f1a8ebb730..e3506f2c42d 100644
--- a/chromium/components/update_client/update_client.h
+++ b/chromium/components/update_client/update_client.h
@@ -199,10 +199,11 @@ struct CrxComponent {
// The current version if the CRX is updated. Otherwise, "0" or "0.0" if
// the CRX is installed.
- Version version;
+ base::Version version;
std::string fingerprint; // Optional.
std::string name; // Optional.
+ std::vector<std::string> handled_mime_types;
// Optional.
// Valid values for the name part of an attribute match
@@ -219,6 +220,12 @@ struct CrxComponent {
// note, the confidentiality of the downloads is enforced by the server,
// which only returns secure download URLs in this case.
bool requires_network_encryption;
+
+ // True if the component allows enabling or disabling updates by group policy.
+ // This member should be set to |false| for data, non-binary components, such
+ // as CRLSet, Supervised User Whitelists, STH Set, Origin Trials, and File
+ // Type Policies.
+ bool supports_group_policy_enable_component_updates;
};
// All methods are safe to call only from the browser's main thread. Once an
@@ -314,7 +321,7 @@ class UpdateClient : public base::RefCounted<UpdateClient> {
// other side effects regarding installs or updates done through an instance
// of this class.
virtual void SendUninstallPing(const std::string& id,
- const Version& version,
+ const base::Version& version,
int reason) = 0;
// Returns status details about a CRX update. The function returns true in
diff --git a/chromium/components/update_client/update_client_internal.h b/chromium/components/update_client/update_client_internal.h
index 47e9af611c6..066235849dc 100644
--- a/chromium/components/update_client/update_client_internal.h
+++ b/chromium/components/update_client/update_client_internal.h
@@ -53,7 +53,7 @@ class UpdateClientImpl : public UpdateClient {
bool IsUpdating(const std::string& id) const override;
void Stop() override;
void SendUninstallPing(const std::string& id,
- const Version& version,
+ const base::Version& version,
int reason) override;
private:
diff --git a/chromium/components/update_client/update_client_unittest.cc b/chromium/components/update_client/update_client_unittest.cc
index a869f9a3cf9..5d2db64811b 100644
--- a/chromium/components/update_client/update_client_unittest.cc
+++ b/chromium/components/update_client/update_client_unittest.cc
@@ -148,7 +148,7 @@ class UpdateClientTest : public testing::Test {
// Returns the full path to a test file.
static base::FilePath TestFilePath(const char* file);
- scoped_refptr<update_client::Configurator> config() { return config_; }
+ scoped_refptr<update_client::TestConfigurator> config() { return config_; }
update_client::PersistedData* metadata() { return metadata_.get(); }
base::Closure quit_closure() { return quit_closure_; }
@@ -162,7 +162,7 @@ class UpdateClientTest : public testing::Test {
std::unique_ptr<base::SequencedWorkerPoolOwner> worker_pool_;
- scoped_refptr<update_client::Configurator> config_;
+ scoped_refptr<update_client::TestConfigurator> config_;
std::unique_ptr<TestingPrefServiceSimple> pref_;
std::unique_ptr<update_client::PersistedData> metadata_;
@@ -210,7 +210,7 @@ TEST_F(UpdateClientTest, OneCrxNoUpdate) {
CrxComponent crx;
crx.name = "test_jebg";
crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = Version("0.9");
+ crx.version = base::Version("0.9");
crx.installer = new TestInstaller;
components->push_back(crx);
}
@@ -235,7 +235,9 @@ TEST_F(UpdateClientTest, OneCrxNoUpdate) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
+ EXPECT_TRUE(enabled_component_updates);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(update_check_callback, 0, UpdateResponse::Results(), 0));
@@ -309,13 +311,13 @@ TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
CrxComponent crx1;
crx1.name = "test_jebg";
crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx1.version = Version("0.9");
+ crx1.version = base::Version("0.9");
crx1.installer = new TestInstaller;
CrxComponent crx2;
crx2.name = "test_abag";
crx2.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
- crx2.version = Version("2.2");
+ crx2.version = base::Version("2.2");
crx2.installer = new TestInstaller;
components->push_back(crx1);
@@ -342,6 +344,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
/*
Fake the following response:
@@ -495,13 +498,13 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
CrxComponent crx1;
crx1.name = "test_jebg";
crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx1.version = Version("0.9");
+ crx1.version = base::Version("0.9");
crx1.installer = new TestInstaller;
CrxComponent crx2;
crx2.name = "test_ihfo";
crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
- crx2.version = Version("0.8");
+ crx2.version = base::Version("0.8");
crx2.installer = new TestInstaller;
components->push_back(crx1);
@@ -528,6 +531,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
/*
Fake the following response:
@@ -743,13 +747,13 @@ TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
CrxComponent crx1;
crx1.name = "test_jebg";
crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx1.version = Version("0.9");
+ crx1.version = base::Version("0.9");
crx1.installer = new TestInstaller;
CrxComponent crx2;
crx2.name = "test_ihfo";
crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
- crx2.version = Version("0.8");
+ crx2.version = base::Version("0.8");
crx2.installer = new TestInstaller;
components->push_back(crx1);
@@ -776,6 +780,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
/*
Fake the following response:
@@ -997,9 +1002,9 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
crx.installer = installer;
if (num_calls == 1) {
- crx.version = Version("0.8");
+ crx.version = base::Version("0.8");
} else if (num_calls == 2) {
- crx.version = Version("1.0");
+ crx.version = base::Version("1.0");
} else {
NOTREACHED();
}
@@ -1027,6 +1032,7 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
static int num_call = 0;
++num_call;
@@ -1085,8 +1091,7 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
0ecde26c262bad942b112990'
fp='22'
hashdiff_sha256='73c6e2d4f783fc4ca5481e89e0b8bfce7aec
- 8ead3686290c94792658ec06f2f2'
- />
+ 8ead3686290c94792658ec06f2f2'/>
</packages>
</manifest>
</updatecheck>
@@ -1294,7 +1299,7 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
CrxComponent crx;
crx.name = "test_jebg";
crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = Version("0.9");
+ crx.version = base::Version("0.9");
crx.installer = installer;
components->push_back(crx);
}
@@ -1319,6 +1324,7 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
/*
Fake the following response:
@@ -1473,9 +1479,9 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
crx.installer = installer;
if (num_calls == 1) {
- crx.version = Version("0.8");
+ crx.version = base::Version("0.8");
} else if (num_calls == 2) {
- crx.version = Version("1.0");
+ crx.version = base::Version("1.0");
} else {
NOTREACHED();
}
@@ -1503,6 +1509,7 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
static int num_call = 0;
++num_call;
@@ -1561,8 +1568,7 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
0ecde26c262bad942b112990'
fp='22'
hashdiff_sha256='73c6e2d4f783fc4ca5481e89e0b8bfce7aec
- 8ead3686290c94792658ec06f2f2'
- />
+ 8ead3686290c94792658ec06f2f2'/>
</packages>
</manifest>
</updatecheck>
@@ -1763,7 +1769,7 @@ TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
CrxComponent crx;
crx.name = "test_jebg";
crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = Version("0.9");
+ crx.version = base::Version("0.9");
crx.installer = new TestInstaller;
components->push_back(crx);
}
@@ -1793,6 +1799,7 @@ TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
@@ -1867,7 +1874,7 @@ TEST_F(UpdateClientTest, OneCrxInstall) {
CrxComponent crx;
crx.name = "test_jebg";
crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = Version("0.0");
+ crx.version = base::Version("0.0");
crx.installer = new TestInstaller;
components->push_back(crx);
@@ -1893,6 +1900,7 @@ TEST_F(UpdateClientTest, OneCrxInstall) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
/*
Fake the following response:
@@ -2043,7 +2051,7 @@ TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
CrxComponent crx;
crx.name = "test_jebg";
crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = Version("0.0");
+ crx.version = base::Version("0.0");
crx.installer = new TestInstaller;
components->push_back(crx);
@@ -2080,6 +2088,7 @@ TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
@@ -2174,6 +2183,7 @@ TEST_F(UpdateClientTest, EmptyIdList) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
return false;
}
@@ -2220,6 +2230,7 @@ TEST_F(UpdateClientTest, SendUninstallPing) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
return false;
}
@@ -2273,7 +2284,7 @@ TEST_F(UpdateClientTest, RetryAfter) {
CrxComponent crx;
crx.name = "test_jebg";
crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = Version("0.9");
+ crx.version = base::Version("0.9");
crx.installer = new TestInstaller;
components->push_back(crx);
}
@@ -2318,6 +2329,7 @@ TEST_F(UpdateClientTest, RetryAfter) {
bool CheckForUpdates(
const std::vector<CrxUpdateItem*>& items_to_check,
const std::string& additional_attributes,
+ bool enabled_component_updates,
const UpdateCheckCallback& update_check_callback) override {
static int num_call = 0;
++num_call;
@@ -2436,4 +2448,253 @@ TEST_F(UpdateClientTest, RetryAfter) {
update_client->RemoveObserver(&observer);
}
+// Tests the update check for two CRXs scenario. The first component supports
+// the group policy to enable updates, and has its updates disabled. The second
+// component has an update. The server does not honor the "updatedisabled"
+// attribute and returns updates for both components.
+TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
+ class DataCallbackFake {
+ public:
+ static void Callback(const std::vector<std::string>& ids,
+ std::vector<CrxComponent>* components) {
+ CrxComponent crx1;
+ crx1.name = "test_jebg";
+ crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
+ crx1.version = base::Version("0.9");
+ crx1.installer = new TestInstaller;
+ crx1.supports_group_policy_enable_component_updates = true;
+
+ CrxComponent crx2;
+ crx2.name = "test_ihfo";
+ crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
+ crx2.version = base::Version("0.8");
+ crx2.installer = new TestInstaller;
+
+ components->push_back(crx1);
+ components->push_back(crx2);
+ }
+ };
+
+ class CompletionCallbackFake {
+ public:
+ static void Callback(const base::Closure& quit_closure, int error) {
+ EXPECT_EQ(0, error);
+ quit_closure.Run();
+ }
+ };
+
+ class FakeUpdateChecker : public UpdateChecker {
+ public:
+ static std::unique_ptr<UpdateChecker> Create(
+ const scoped_refptr<Configurator>& config,
+ PersistedData* metadata) {
+ return std::unique_ptr<UpdateChecker>(new FakeUpdateChecker());
+ }
+
+ bool CheckForUpdates(
+ const std::vector<CrxUpdateItem*>& items_to_check,
+ const std::string& additional_attributes,
+ bool enabled_component_updates,
+ const UpdateCheckCallback& update_check_callback) override {
+ /*
+ Fake the following response:
+
+ <?xml version='1.0' encoding='UTF-8'?>
+ <response protocol='3.0'>
+ <app appid='jebgalgnebhfojomionfpkfelancnnkf'>
+ <updatecheck status='ok'>
+ <urls>
+ <url codebase='http://localhost/download/'/>
+ </urls>
+ <manifest version='1.0' prodversionmin='11.0.1.0'>
+ <packages>
+ <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'
+ hash_sha256='6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd
+ 7c9b12cb7cc067667bde87'/>
+ </packages>
+ </manifest>
+ </updatecheck>
+ </app>
+ <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
+ <updatecheck status='ok'>
+ <urls>
+ <url codebase='http://localhost/download/'/>
+ </urls>
+ <manifest version='1.0' prodversionmin='11.0.1.0'>
+ <packages>
+ <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
+ hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
+ 309f156ea6d27229c0b3f9'/>
+ </packages>
+ </manifest>
+ </updatecheck>
+ </app>
+ </response>
+ */
+
+ // UpdateClient reads the state of |enabled_component_updates| from the
+ // configurator instance, persists its value in the corresponding
+ // update context, and propagates it down to each of the update actions,
+ // and further down to the UpdateChecker instance.
+ EXPECT_FALSE(enabled_component_updates);
+
+ UpdateResponse::Result::Manifest::Package package1;
+ package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx";
+ package1.hash_sha256 =
+ "6fc4b93fd11134de1300c2c0bb88c12b644a4ec0fd7c9b12cb7cc067667bde87";
+
+ UpdateResponse::Result result1;
+ result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf";
+ result1.crx_urls.push_back(GURL("http://localhost/download/"));
+ result1.manifest.version = "1.0";
+ result1.manifest.browser_min_version = "11.0.1.0";
+ result1.manifest.packages.push_back(package1);
+
+ UpdateResponse::Result::Manifest::Package package2;
+ package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
+ package2.hash_sha256 =
+ "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
+
+ UpdateResponse::Result result2;
+ result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc";
+ result2.crx_urls.push_back(GURL("http://localhost/download/"));
+ result2.manifest.version = "1.0";
+ result2.manifest.browser_min_version = "11.0.1.0";
+ result2.manifest.packages.push_back(package2);
+
+ UpdateResponse::Results results;
+ results.list.push_back(result1);
+ results.list.push_back(result2);
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(update_check_callback, 0, results, 0));
+ return true;
+ }
+ };
+
+ class FakeCrxDownloader : public CrxDownloader {
+ public:
+ static std::unique_ptr<CrxDownloader> Create(
+ bool is_background_download,
+ net::URLRequestContextGetter* context_getter,
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+ return std::unique_ptr<CrxDownloader>(new FakeCrxDownloader());
+ }
+
+ private:
+ FakeCrxDownloader()
+ : CrxDownloader(base::ThreadTaskRunnerHandle::Get(), nullptr) {}
+ ~FakeCrxDownloader() override {}
+
+ void DoStartDownload(const GURL& url) override {
+ DownloadMetrics download_metrics;
+ FilePath path;
+ Result result;
+ if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
+ download_metrics.url = url;
+ download_metrics.downloader = DownloadMetrics::kNone;
+ download_metrics.error = 0;
+ download_metrics.downloaded_bytes = 53638;
+ download_metrics.total_bytes = 53638;
+ download_metrics.download_time_ms = 2000;
+
+ EXPECT_TRUE(MakeTestFile(
+ TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
+
+ result.error = 0;
+ result.response = path;
+ result.downloaded_bytes = 53638;
+ result.total_bytes = 53638;
+ } else {
+ NOTREACHED();
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress,
+ base::Unretained(this), result));
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&FakeCrxDownloader::OnDownloadComplete,
+ base::Unretained(this), true, result, download_metrics));
+ }
+ };
+
+ class FakePingManager : public FakePingManagerImpl {
+ public:
+ explicit FakePingManager(const scoped_refptr<Configurator>& config)
+ : FakePingManagerImpl(config) {}
+ ~FakePingManager() override {
+ const auto& ping_items = items();
+ EXPECT_EQ(2U, ping_items.size());
+ EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id);
+ EXPECT_EQ(base::Version("0.9"), ping_items[0].previous_version);
+ EXPECT_EQ(base::Version("1.0"), ping_items[0].next_version);
+ EXPECT_EQ(4, ping_items[0].error_category);
+ EXPECT_EQ(2, ping_items[0].error_code);
+ EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id);
+ EXPECT_EQ(base::Version("0.8"), ping_items[1].previous_version);
+ EXPECT_EQ(base::Version("1.0"), ping_items[1].next_version);
+ EXPECT_EQ(0, ping_items[1].error_category);
+ EXPECT_EQ(0, ping_items[1].error_code);
+ }
+ };
+
+ // Disables updates for the components declaring support for the group policy.
+ config()->SetEnabledComponentUpdates(false);
+ std::unique_ptr<FakePingManager> ping_manager(new FakePingManager(config()));
+ scoped_refptr<UpdateClient> update_client(new UpdateClientImpl(
+ config(), std::move(ping_manager), &FakeUpdateChecker::Create,
+ &FakeCrxDownloader::Create));
+
+ MockObserver observer;
+ {
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "jebgalgnebhfojomionfpkfelancnnkf"))
+ .Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
+ "jebgalgnebhfojomionfpkfelancnnkf"))
+ .Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED,
+ "jebgalgnebhfojomionfpkfelancnnkf"))
+ .Times(1);
+ }
+ {
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
+ "ihfokbkgjpifnbbojhneepfflplebdkc"))
+ .Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
+ "ihfokbkgjpifnbbojhneepfflplebdkc"))
+ .Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
+ "ihfokbkgjpifnbbojhneepfflplebdkc"))
+ .Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ "ihfokbkgjpifnbbojhneepfflplebdkc"))
+ .Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
+ "ihfokbkgjpifnbbojhneepfflplebdkc"))
+ .Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
+ "ihfokbkgjpifnbbojhneepfflplebdkc"))
+ .Times(1);
+ }
+
+ update_client->AddObserver(&observer);
+
+ std::vector<std::string> ids;
+ ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf"));
+ ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc"));
+
+ update_client->Update(
+ ids, base::Bind(&DataCallbackFake::Callback),
+ base::Bind(&CompletionCallbackFake::Callback, quit_closure()));
+
+ RunThreads();
+
+ update_client->RemoveObserver(&observer);
+}
+
} // namespace update_client
diff --git a/chromium/components/update_client/update_engine.cc b/chromium/components/update_client/update_engine.cc
index e356e99b7f7..a04898edf68 100644
--- a/chromium/components/update_client/update_engine.cc
+++ b/chromium/components/update_client/update_engine.cc
@@ -31,6 +31,7 @@ UpdateContext::UpdateContext(
PingManager* ping_manager)
: config(config),
is_foreground(is_foreground),
+ enabled_component_updates(config->EnabledComponentUpdates()),
ids(ids),
crx_data_callback(crx_data_callback),
notify_observers_callback(notify_observers_callback),
@@ -43,7 +44,7 @@ UpdateContext::UpdateContext(
retry_after_sec_(0) {}
UpdateContext::~UpdateContext() {
- STLDeleteElements(&update_items);
+ base::STLDeleteElements(&update_items);
}
UpdateEngine::UpdateEngine(
@@ -66,7 +67,7 @@ UpdateEngine::~UpdateEngine() {
bool UpdateEngine::GetUpdateState(const std::string& id,
CrxUpdateItem* update_item) {
DCHECK(thread_checker_.CalledOnValidThread());
- for (const auto& context : update_contexts_) {
+ for (const auto* context : update_contexts_) {
const auto& update_items = context->update_items;
const auto it = std::find_if(update_items.begin(), update_items.end(),
[id](const CrxUpdateItem* update_item) {
@@ -127,8 +128,9 @@ void UpdateEngine::UpdateComplete(UpdateContext* update_context, int error) {
if (throttle_sec >= 0)
throttle_updates_until_ =
throttle_sec
- ? base::Time::Now() + base::TimeDelta::FromSeconds(throttle_sec)
- : base::Time();
+ ? base::TimeTicks::Now() +
+ base::TimeDelta::FromSeconds(throttle_sec)
+ : base::TimeTicks();
auto callback = update_context->callback;
@@ -142,7 +144,7 @@ bool UpdateEngine::IsThrottled(bool is_foreground) const {
if (is_foreground || throttle_updates_until_.is_null())
return false;
- const auto now(base::Time::Now());
+ const auto now(base::TimeTicks::Now());
// Throttle the calls in the interval (t - 1 day, t) to limit the effect of
// unset clocks or clock drift.
diff --git a/chromium/components/update_client/update_engine.h b/chromium/components/update_client/update_engine.h
index a82864cb009..fd546c8565f 100644
--- a/chromium/components/update_client/update_engine.h
+++ b/chromium/components/update_client/update_engine.h
@@ -25,6 +25,7 @@
#include "components/update_client/update_client.h"
namespace base {
+class TimeTicks;
class SequencedTaskRunner;
class SingleThreadTaskRunner;
} // namespace base
@@ -89,7 +90,7 @@ class UpdateEngine {
// effect of rejecting the update call if the update call occurs before
// a certain time, which is negotiated with the server as part of the
// update protocol. See the comments for X-Retry-After header.
- base::Time throttle_updates_until_;
+ base::TimeTicks throttle_updates_until_;
DISALLOW_COPY_AND_ASSIGN(UpdateEngine);
};
@@ -114,6 +115,9 @@ struct UpdateContext {
// True if this update has been initiated by the user.
bool is_foreground;
+ // True if the component updates are enabled in this context.
+ const bool enabled_component_updates;
+
// Contains the ids of all CRXs in this context.
const std::vector<std::string> ids;
diff --git a/chromium/components/update_client/update_response.cc b/chromium/components/update_client/update_response.cc
index e89a774ae7a..41670d317de 100644
--- a/chromium/components/update_client/update_response.cc
+++ b/chromium/components/update_client/update_response.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <memory>
+#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -20,6 +21,9 @@
namespace update_client {
static const char* kExpectedResponseProtocol = "3.0";
+const char UpdateResponse::Result::kCohort[] = "cohort";
+const char UpdateResponse::Result::kCohortHint[] = "cohorthint";
+const char UpdateResponse::Result::kCohortName[] = "cohortname";
UpdateResponse::UpdateResponse() {
}
@@ -32,8 +36,7 @@ UpdateResponse::Results::Results(const Results& other) = default;
UpdateResponse::Results::~Results() {
}
-UpdateResponse::Result::Result() {
-}
+UpdateResponse::Result::Result() {}
UpdateResponse::Result::Result(const Result& other) = default;
UpdateResponse::Result::~Result() {
}
@@ -93,6 +96,21 @@ static std::string GetAttribute(xmlNode* node, const char* attribute_name) {
return std::string();
}
+// Returns the value of a named attribute, or nullptr .
+static std::unique_ptr<std::string> GetAttributePtr(
+ xmlNode* node,
+ const char* attribute_name) {
+ const xmlChar* name = reinterpret_cast<const xmlChar*>(attribute_name);
+ for (xmlAttr* attr = node->properties; attr != NULL; attr = attr->next) {
+ if (!xmlStrcmp(attr->name, name) && attr->children &&
+ attr->children->content) {
+ return base::MakeUnique<std::string>(
+ reinterpret_cast<const char*>(attr->children->content));
+ }
+ }
+ return nullptr;
+}
+
// This is used for the xml parser to report errors. This assumes the context
// is a pointer to a std::string where the error message should be appended.
static void XmlErrorFunc(void* context, const char* message, ...) {
@@ -162,7 +180,7 @@ bool ParseManifestTag(xmlNode* manifest,
*error = "Missing version for manifest.";
return false;
}
- Version version(result->manifest.version);
+ base::Version version(result->manifest.version);
if (!version.IsValid()) {
*error = "Invalid version: '";
*error += result->manifest.version;
@@ -174,7 +192,7 @@ bool ParseManifestTag(xmlNode* manifest,
result->manifest.browser_min_version =
GetAttribute(manifest, "prodversionmin");
if (result->manifest.browser_min_version.length()) {
- Version browser_min_version(result->manifest.browser_min_version);
+ base::Version browser_min_version(result->manifest.browser_min_version);
if (!browser_min_version.IsValid()) {
*error = "Invalid prodversionmin: '";
*error += result->manifest.browser_min_version;
@@ -268,6 +286,17 @@ bool ParseUpdateCheckTag(xmlNode* updatecheck,
bool ParseAppTag(xmlNode* app,
UpdateResponse::Result* result,
std::string* error) {
+ // Read cohort information.
+ auto cohort = GetAttributePtr(app, "cohort");
+ static const char* attrs[] = {UpdateResponse::Result::kCohort,
+ UpdateResponse::Result::kCohortHint,
+ UpdateResponse::Result::kCohortName};
+ for (const auto& attr : attrs) {
+ auto value = GetAttributePtr(app, attr);
+ if (value)
+ result->cohort_attrs.insert({attr, *value});
+ }
+
// Read the crx id.
result->extension_id = GetAttribute(app, "appid");
if (result->extension_id.empty()) {
diff --git a/chromium/components/update_client/update_response.h b/chromium/components/update_client/update_response.h
index 6c0ea9bd935..01b49aaafa9 100644
--- a/chromium/components/update_client/update_response.h
+++ b/chromium/components/update_client/update_response.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_UPDATE_CLIENT_UPDATE_RESPONSE_H_
#define COMPONENTS_UPDATE_CLIENT_UPDATE_RESPONSE_H_
+#include <map>
+#include <memory>
#include <string>
#include <vector>
@@ -99,6 +101,15 @@ class UpdateResponse {
std::vector<GURL> crx_diffurls;
Manifest manifest;
+
+ // The server has instructed the client to set its [key] to [value] for each
+ // key-value pair in this string.
+ std::map<std::string, std::string> cohort_attrs;
+
+ // The following are the only allowed keys in |cohort_attrs|.
+ static const char kCohort[];
+ static const char kCohortHint[];
+ static const char kCohortName[];
};
static const int kNoDaystart = -1;
diff --git a/chromium/components/update_client/update_response_unittest.cc b/chromium/components/update_client/update_response_unittest.cc
index 20f08b074e7..bb7010c8939 100644
--- a/chromium/components/update_client/update_response_unittest.cc
+++ b/chromium/components/update_client/update_response_unittest.cc
@@ -99,7 +99,7 @@ const char* kMissingAppId =
"<response protocol='3.0'>"
" <app>"
" <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'"
- " version='1.2.3.4' />"
+ " version='1.2.3.4'/>"
" </app>"
"</response>";
@@ -108,7 +108,7 @@ const char* kInvalidCodebase =
"<response protocol='3.0'>"
" <app appid='12345' status='ok'>"
" <updatecheck codebase='example.com/extension_1.2.3.4.crx'"
- " version='1.2.3.4' />"
+ " version='1.2.3.4'/>"
" </app>"
"</response>";
@@ -116,7 +116,7 @@ const char* kMissingVersion =
"<?xml version='1.0'?>"
"<response protocol='3.0'>"
" <app appid='12345' status='ok'>"
- " <updatecheck codebase='http://example.com/extension_1.2.3.4.crx' />"
+ " <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'/>"
" </app>"
"</response>";
@@ -175,7 +175,7 @@ const char* kSimilarTagnames =
const char* kWithDaystart =
"<?xml version='1.0' encoding='UTF-8'?>"
"<response protocol='3.0'>"
- " <daystart elapsed_seconds='456' />"
+ " <daystart elapsed_seconds='456'/>"
" <app appid='12345'>"
" <updatecheck status='ok'>"
" <urls>"
@@ -195,7 +195,7 @@ const char* kNoUpdate =
"<?xml version='1.0' encoding='UTF-8'?>"
"<response protocol='3.0'>"
" <app appid='12345'>"
- " <updatecheck status='noupdate' />"
+ " <updatecheck status='noupdate'/>"
" </app>"
"</response>";
@@ -220,6 +220,27 @@ const char* kTwoAppsOneError =
" </app>"
"</response>";
+// Includes two <app> tags, both of which set the cohort.
+const char* kTwoAppsSetCohort =
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ "<response protocol='3.0'>"
+ " <app appid='aaaaaaaa' cohort='1:2q3/'>"
+ " <updatecheck status='noupdate'/>"
+ " </app>"
+ " <app appid='bbbbbbbb' cohort='1:33z@0.33' cohortname='cname'>"
+ " <updatecheck status='ok'>"
+ " <urls>"
+ " <url codebase='http://example.com/'/>"
+ " </urls>"
+ " <manifest version='1.2.3.4' prodversionmin='2.0.143.0'>"
+ " <packages>"
+ " <package name='extension_1_2_3_4.crx'/>"
+ " </packages>"
+ " </manifest>"
+ " </updatecheck>"
+ " </app>"
+ "</response>";
+
TEST(ComponentUpdaterUpdateResponseTest, TestParser) {
UpdateResponse parser;
@@ -312,6 +333,30 @@ TEST(ComponentUpdaterUpdateResponseTest, TestParser) {
EXPECT_EQ(1u, parser.results().list.size());
firstResult = &parser.results().list[0];
EXPECT_EQ(firstResult->extension_id, "bbbbbbbb");
+
+ // Parse xml with two apps setting the cohort info.
+ EXPECT_TRUE(parser.Parse(kTwoAppsSetCohort));
+ EXPECT_TRUE(parser.errors().empty());
+ EXPECT_EQ(2u, parser.results().list.size());
+ firstResult = &parser.results().list[0];
+ EXPECT_EQ(firstResult->extension_id, "aaaaaaaa");
+ EXPECT_NE(firstResult->cohort_attrs.find("cohort"),
+ firstResult->cohort_attrs.end());
+ EXPECT_EQ(firstResult->cohort_attrs.find("cohort")->second, "1:2q3/");
+ EXPECT_EQ(firstResult->cohort_attrs.find("cohortname"),
+ firstResult->cohort_attrs.end());
+ EXPECT_EQ(firstResult->cohort_attrs.find("cohorthint"),
+ firstResult->cohort_attrs.end());
+ const UpdateResponse::Result* secondResult = &parser.results().list[1];
+ EXPECT_EQ(secondResult->extension_id, "bbbbbbbb");
+ EXPECT_NE(secondResult->cohort_attrs.find("cohort"),
+ secondResult->cohort_attrs.end());
+ EXPECT_EQ(secondResult->cohort_attrs.find("cohort")->second, "1:33z@0.33");
+ EXPECT_NE(secondResult->cohort_attrs.find("cohortname"),
+ secondResult->cohort_attrs.end());
+ EXPECT_EQ(secondResult->cohort_attrs.find("cohortname")->second, "cname");
+ EXPECT_EQ(secondResult->cohort_attrs.find("cohorthint"),
+ secondResult->cohort_attrs.end());
}
} // namespace update_client
diff --git a/chromium/components/update_client/url_fetcher_downloader.cc b/chromium/components/update_client/url_fetcher_downloader.cc
index 6a74d881263..f94e9730e92 100644
--- a/chromium/components/update_client/url_fetcher_downloader.cc
+++ b/chromium/components/update_client/url_fetcher_downloader.cc
@@ -46,7 +46,7 @@ void UrlFetcherDownloader::DoStartDownload(const GURL& url) {
VLOG(1) << "Starting background download: " << url.spec();
url_fetcher_->Start();
- download_start_time_ = base::Time::Now();
+ download_start_time_ = base::TimeTicks::Now();
downloaded_bytes_ = -1;
total_bytes_ = -1;
@@ -55,7 +55,7 @@ void UrlFetcherDownloader::DoStartDownload(const GURL& url) {
void UrlFetcherDownloader::OnURLFetchComplete(const net::URLFetcher* source) {
DCHECK(thread_checker_.CalledOnValidThread());
- const base::Time download_end_time(base::Time::Now());
+ const base::TimeTicks download_end_time(base::TimeTicks::Now());
const base::TimeDelta download_time =
download_end_time >= download_start_time_
? download_end_time - download_start_time_
@@ -98,7 +98,8 @@ void UrlFetcherDownloader::OnURLFetchComplete(const net::URLFetcher* source) {
void UrlFetcherDownloader::OnURLFetchDownloadProgress(
const net::URLFetcher* source,
int64_t current,
- int64_t total) {
+ int64_t total,
+ int64_t current_network_bytes) {
DCHECK(thread_checker_.CalledOnValidThread());
downloaded_bytes_ = current;
diff --git a/chromium/components/update_client/url_fetcher_downloader.h b/chromium/components/update_client/url_fetcher_downloader.h
index 4f2fbdec4db..fe613dfcfa2 100644
--- a/chromium/components/update_client/url_fetcher_downloader.h
+++ b/chromium/components/update_client/url_fetcher_downloader.h
@@ -46,11 +46,12 @@ class UrlFetcherDownloader : public CrxDownloader,
void OnURLFetchComplete(const net::URLFetcher* source) override;
void OnURLFetchDownloadProgress(const net::URLFetcher* source,
int64_t current,
- int64_t total) override;
+ int64_t total,
+ int64_t current_network_bytes) override;
std::unique_ptr<net::URLFetcher> url_fetcher_;
net::URLRequestContextGetter* context_getter_;
- base::Time download_start_time_;
+ base::TimeTicks download_start_time_;
int64_t downloaded_bytes_;
int64_t total_bytes_;
diff --git a/chromium/components/update_client/utils.cc b/chromium/components/update_client/utils.cc
index 717984d8999..39ab431a7b5 100644
--- a/chromium/components/update_client/utils.cc
+++ b/chromium/components/update_client/utils.cc
@@ -66,18 +66,36 @@ std::string HexStringToID(const std::string& hexstr) {
return id;
}
+std::string GetOSVersion() {
+#if defined(OS_WIN)
+ int32_t major = 0;
+ int32_t minor = 0;
+ int32_t bugfix = 0;
+ base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+ return base::StringPrintf("%d.%d.%d", major, minor, bugfix);
+#else
+ return base::SysInfo().OperatingSystemVersion();
+#endif
+}
+
+std::string GetServicePack() {
+#if defined(OS_WIN)
+ return base::win::OSInfo::GetInstance()->service_pack_str();
+#else
+ return std::string();
+#endif
+}
+
} // namespace
-std::string BuildProtocolRequest(const std::string& browser_version,
+std::string BuildProtocolRequest(const std::string& prod_id,
+ const std::string& browser_version,
const std::string& channel,
const std::string& lang,
const std::string& os_long_name,
const std::string& download_preference,
const std::string& request_body,
const std::string& additional_attributes) {
- const std::string prod_id(
- UpdateQueryParams::GetProdIdString(UpdateQueryParams::CHROME));
-
std::string request(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<request protocol=\"3.0\" ");
@@ -91,8 +109,8 @@ std::string BuildProtocolRequest(const std::string& browser_version,
"version=\"%s-%s\" prodversion=\"%s\" "
"requestid=\"{%s}\" lang=\"%s\" updaterchannel=\"%s\" prodchannel=\"%s\" "
"os=\"%s\" arch=\"%s\" nacl_arch=\"%s\"",
- prod_id.c_str(),
- browser_version.c_str(), // "version"
+ prod_id.c_str(), // "version" is prefixed by prod_id.
+ browser_version.c_str(),
browser_version.c_str(), // "prodversion"
base::GenerateGUID().c_str(), // "requestid"
lang.c_str(), // "lang",
@@ -117,11 +135,18 @@ std::string BuildProtocolRequest(const std::string& browser_version,
GetPhysicalMemoryGB()); // "physmem" in GB.
// OS version and platform information.
+ const std::string os_version = GetOSVersion();
+ const std::string os_sp = GetServicePack();
+
base::StringAppendF(
- &request, "<os platform=\"%s\" version=\"%s\" arch=\"%s\"/>",
+ &request, "<os platform=\"%s\" arch=\"%s\"",
os_long_name.c_str(), // "platform"
- base::SysInfo().OperatingSystemVersion().c_str(), // "version"
base::SysInfo().OperatingSystemArchitecture().c_str()); // "arch"
+ if (!os_version.empty())
+ base::StringAppendF(&request, " version=\"%s\"", os_version.c_str());
+ if (!os_sp.empty())
+ base::StringAppendF(&request, " sp=\"%s\"", os_sp.c_str());
+ base::StringAppendF(&request, "/>");
// The actual payload of the request.
base::StringAppendF(&request, "%s</request>", request_body.c_str());
diff --git a/chromium/components/update_client/utils.h b/chromium/components/update_client/utils.h
index f800b4fb895..3adda89eabd 100644
--- a/chromium/components/update_client/utils.h
+++ b/chromium/components/update_client/utils.h
@@ -40,7 +40,7 @@ using InstallerAttribute = std::pair<std::string, std::string>;
// For example:
//
// <?xml version="1.0" encoding="UTF-8"?>
-// <request protocol="3.0" version="chrome-32.0.1.0" prodversion="32.0.1.0"
+// <request protocol="3.0" version="chrome-32.0.1.0" prodversion="32.0.1.0"
// requestid="{7383396D-B4DD-46E1-9104-AAC6B918E792}"
// updaterchannel="canary" arch="x86" nacl_arch="x86-64"
// ADDITIONAL ATTRIBUTES>
@@ -56,7 +56,8 @@ using InstallerAttribute = std::pair<std::string, std::string>;
// If specified, |additional_attributes| are appended as attributes of the
// request element. The additional attributes have to be well-formed for
// insertion in the request element.
-std::string BuildProtocolRequest(const std::string& browser_version,
+std::string BuildProtocolRequest(const std::string& prod_id,
+ const std::string& browser_version,
const std::string& channel,
const std::string& lang,
const std::string& os_long_name,
diff --git a/chromium/components/update_client/utils_unittest.cc b/chromium/components/update_client/utils_unittest.cc
index 5865419e67a..9370a879b06 100644
--- a/chromium/components/update_client/utils_unittest.cc
+++ b/chromium/components/update_client/utils_unittest.cc
@@ -23,17 +23,22 @@ base::FilePath MakeTestFilePath(const char* file) {
namespace update_client {
-TEST(UpdateClientUtils, BuildProtocolRequest_DownloadPreference) {
- const string emptystr;
+TEST(UpdateClientUtils, BuildProtocolRequest_ProdIdVersion) {
+ // Verifies that |prod_id| and |version| are serialized.
+ const string request =
+ BuildProtocolRequest("some_prod_id", "1.0", "", "", "", "", "", "");
+ EXPECT_NE(string::npos, request.find(" version=\"some_prod_id-1.0\" "));
+}
+TEST(UpdateClientUtils, BuildProtocolRequest_DownloadPreference) {
// Verifies that an empty |download_preference| is not serialized.
- const string request_no_dlpref = BuildProtocolRequest(
- emptystr, emptystr, emptystr, emptystr, emptystr, emptystr, emptystr);
+ const string request_no_dlpref =
+ BuildProtocolRequest("", "", "", "", "", "", "", "");
EXPECT_EQ(string::npos, request_no_dlpref.find(" dlpref="));
// Verifies that |download_preference| is serialized.
- const string request_with_dlpref = BuildProtocolRequest(
- emptystr, emptystr, emptystr, emptystr, "some pref", emptystr, emptystr);
+ const string request_with_dlpref =
+ BuildProtocolRequest("", "", "", "", "", "some pref", "", "");
EXPECT_NE(string::npos, request_with_dlpref.find(" dlpref=\"some pref\""));
}
@@ -94,14 +99,14 @@ TEST(UpdateClientUtils, IsValidInstallerAttributeName) {
const char* const valid_names[] = {"A", "Z", "a", "a-b", "A_B",
"z", "0", "9", "-_"};
- for (const auto& name : valid_names)
+ for (const char* name : valid_names)
EXPECT_TRUE(IsValidInstallerAttribute(
make_pair(std::string(name), std::string("value"))));
const char* const invalid_names[] = {
"", "a=1", " name", "name ", "na me", "<name", "name>",
"\"", "\\", "\xaa", ".", ",", ";", "+"};
- for (const auto& name : invalid_names)
+ for (const char* name : invalid_names)
EXPECT_FALSE(IsValidInstallerAttribute(
make_pair(std::string(name), std::string("value"))));
}
@@ -119,13 +124,13 @@ TEST(UpdateClientUtils, IsValidInstallerAttributeValue) {
const char* const valid_values[] = {"", "a=1", "A", "Z", "a",
"z", "0", "9", "-.,;+_="};
- for (const auto& value : valid_values)
+ for (const char* value : valid_values)
EXPECT_TRUE(IsValidInstallerAttribute(
make_pair(std::string("name"), std::string(value))));
const char* const invalid_values[] = {" ap", "ap ", "a p", "<ap",
"ap>", "\"", "\\", "\xaa"};
- for (const auto& value : invalid_values)
+ for (const char* value : invalid_values)
EXPECT_FALSE(IsValidInstallerAttribute(
make_pair(std::string("name"), std::string(value))));
}
diff --git a/chromium/components/upload_list.gypi b/chromium/components/upload_list.gypi
deleted file mode 100644
index e0bf6b14e3d..00000000000
--- a/chromium/components/upload_list.gypi
+++ /dev/null
@@ -1,25 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/upload_list
- 'target_name': 'upload_list',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'upload_list/crash_upload_list.cc',
- 'upload_list/crash_upload_list.h',
- 'upload_list/upload_list.cc',
- 'upload_list/upload_list.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/upload_list/BUILD.gn b/chromium/components/upload_list/BUILD.gn
index 5c15ea925ee..46b869229ca 100644
--- a/chromium/components/upload_list/BUILD.gn
+++ b/chromium/components/upload_list/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("upload_list") {
+static_library("upload_list") {
sources = [
"crash_upload_list.cc",
"crash_upload_list.h",
diff --git a/chromium/components/upload_list/crash_upload_list.cc b/chromium/components/upload_list/crash_upload_list.cc
index 1c7d570e859..9b00ed2cbd3 100644
--- a/chromium/components/upload_list/crash_upload_list.cc
+++ b/chromium/components/upload_list/crash_upload_list.cc
@@ -4,17 +4,17 @@
#include "components/upload_list/crash_upload_list.h"
+#include <utility>
+
#include "base/files/file_path.h"
#include "base/path_service.h"
-#include "base/threading/sequenced_worker_pool.h"
// static
-const char* CrashUploadList::kReporterLogFilename = "uploads.log";
+const char CrashUploadList::kReporterLogFilename[] = "uploads.log";
-CrashUploadList::CrashUploadList(
- Delegate* delegate,
- const base::FilePath& upload_log_path,
- const scoped_refptr<base::SequencedWorkerPool>& worker_pool)
- : UploadList(delegate, upload_log_path, worker_pool) {}
+CrashUploadList::CrashUploadList(Delegate* delegate,
+ const base::FilePath& upload_log_path,
+ scoped_refptr<base::TaskRunner> task_runner)
+ : UploadList(delegate, upload_log_path, std::move(task_runner)) {}
-CrashUploadList::~CrashUploadList() {}
+CrashUploadList::~CrashUploadList() = default;
diff --git a/chromium/components/upload_list/crash_upload_list.h b/chromium/components/upload_list/crash_upload_list.h
index 095bcfee1b2..7e4dc8c55c8 100644
--- a/chromium/components/upload_list/crash_upload_list.h
+++ b/chromium/components/upload_list/crash_upload_list.h
@@ -11,7 +11,7 @@
namespace base {
class FilePath;
-class SequencedWorkerPool;
+class TaskRunner;
}
// An upload list manager for crash reports from breakpad.
@@ -19,12 +19,12 @@ class CrashUploadList : public UploadList {
public:
// Should match kReporterLogFilename in
// breakpad/src/client/apple/Framework/BreakpadDefines.h.
- static const char* kReporterLogFilename;
+ static const char kReporterLogFilename[];
// Creates a new crash upload list with the given callback delegate.
CrashUploadList(Delegate* delegate,
const base::FilePath& upload_log_path,
- const scoped_refptr<base::SequencedWorkerPool>& worker_pool);
+ scoped_refptr<base::TaskRunner> task_runner);
protected:
~CrashUploadList() override;
diff --git a/chromium/components/upload_list/upload_list.cc b/chromium/components/upload_list/upload_list.cc
index cdaf6b16678..082c01dfa05 100644
--- a/chromium/components/upload_list/upload_list.cc
+++ b/chromium/components/upload_list/upload_list.cc
@@ -11,11 +11,12 @@
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/location.h"
+#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
UploadList::UploadInfo::UploadInfo(const std::string& upload_id,
const base::Time& upload_time,
@@ -28,37 +29,52 @@ UploadList::UploadInfo::UploadInfo(const std::string& upload_id,
capture_time(capture_time),
state(state) {}
+UploadList::UploadInfo::UploadInfo(const std::string& local_id,
+ const base::Time& capture_time,
+ State state,
+ const base::string16& file_size)
+ : local_id(local_id),
+ capture_time(capture_time),
+ state(state),
+ file_size(file_size) {}
+
UploadList::UploadInfo::UploadInfo(const std::string& upload_id,
const base::Time& upload_time)
: upload_id(upload_id), upload_time(upload_time), state(State::Uploaded) {}
-UploadList::UploadInfo::~UploadInfo() {}
+UploadList::UploadInfo::UploadInfo(const UploadInfo& upload_info)
+ : upload_id(upload_info.upload_id),
+ upload_time(upload_info.upload_time),
+ local_id(upload_info.local_id),
+ capture_time(upload_info.capture_time),
+ state(upload_info.state),
+ file_size(upload_info.file_size) {}
-UploadList::UploadList(
- Delegate* delegate,
- const base::FilePath& upload_log_path,
- const scoped_refptr<base::SequencedWorkerPool>& worker_pool)
+UploadList::UploadInfo::~UploadInfo() = default;
+
+UploadList::UploadList(Delegate* delegate,
+ const base::FilePath& upload_log_path,
+ scoped_refptr<base::TaskRunner> task_runner)
: delegate_(delegate),
upload_log_path_(upload_log_path),
- worker_pool_(worker_pool) {}
+ task_runner_(std::move(task_runner)) {}
-UploadList::~UploadList() {}
+UploadList::~UploadList() = default;
void UploadList::LoadUploadListAsynchronously() {
- DCHECK(thread_checker_.CalledOnValidThread());
- worker_pool_->PostTask(
- FROM_HERE,
- base::Bind(&UploadList::PerformLoadAndNotifyDelegate,
- this, base::ThreadTaskRunnerHandle::Get()));
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UploadList::PerformLoadAndNotifyDelegate, this,
+ base::SequencedTaskRunnerHandle::Get()));
}
void UploadList::ClearDelegate() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
delegate_ = NULL;
}
void UploadList::PerformLoadAndNotifyDelegate(
- const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+ scoped_refptr<base::SequencedTaskRunner> task_runner) {
std::vector<UploadInfo> uploads;
LoadUploadList(&uploads);
task_runner->PostTask(
@@ -78,6 +94,10 @@ void UploadList::LoadUploadList(std::vector<UploadInfo>* uploads) {
}
}
+const base::FilePath& UploadList::upload_log_path() const {
+ return upload_log_path_;
+}
+
void UploadList::ParseLogEntries(
const std::vector<std::string>& log_entries,
std::vector<UploadInfo>* uploads) {
@@ -120,7 +140,7 @@ void UploadList::ParseLogEntries(
}
void UploadList::SetUploadsAndNotifyDelegate(std::vector<UploadInfo> uploads) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
uploads_ = std::move(uploads);
if (delegate_)
delegate_->OnUploadListAvailable();
@@ -128,8 +148,21 @@ void UploadList::SetUploadsAndNotifyDelegate(std::vector<UploadInfo> uploads) {
void UploadList::GetUploads(size_t max_count,
std::vector<UploadInfo>* uploads) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
std::copy(uploads_.begin(),
uploads_.begin() + std::min(uploads_.size(), max_count),
std::back_inserter(*uploads));
}
+
+void UploadList::RequestSingleCrashUploadAsync(const std::string& local_id) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UploadList::RequestSingleCrashUpload, this, local_id));
+}
+
+void UploadList::RequestSingleCrashUpload(const std::string& local_id) {
+ // Manual uploads for not-yet uploaded crash reports are only available for
+ // Crashpad systems and for Android.
+ NOTREACHED();
+}
diff --git a/chromium/components/upload_list/upload_list.h b/chromium/components/upload_list/upload_list.h
index f324d561b3c..ebcab5054bb 100644
--- a/chromium/components/upload_list/upload_list.h
+++ b/chromium/components/upload_list/upload_list.h
@@ -13,12 +13,12 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/threading/thread_checker.h"
+#include "base/sequence_checker.h"
#include "base/time/time.h"
namespace base {
class SequencedTaskRunner;
-class SequencedWorkerPool;
+class TaskRunner;
}
// Loads and parses an upload list text file of the format
@@ -35,8 +35,9 @@ class UploadList : public base::RefCountedThreadSafe<UploadList> {
struct UploadInfo {
enum class State {
NotUploaded = 0,
- Pending = 1,
- Uploaded = 2,
+ Pending,
+ Pending_UserRequested,
+ Uploaded,
};
UploadInfo(const std::string& upload_id,
@@ -44,7 +45,13 @@ class UploadList : public base::RefCountedThreadSafe<UploadList> {
const std::string& local_id,
const base::Time& capture_time,
State state);
+ // Constructor for locally stored data.
+ UploadInfo(const std::string& local_id,
+ const base::Time& capture_time,
+ State state,
+ const base::string16& file_size);
UploadInfo(const std::string& upload_id, const base::Time& upload_time);
+ UploadInfo(const UploadInfo& upload_info);
~UploadInfo();
// These fields are only valid when |state| == UploadInfo::State::Uploaded.
@@ -59,6 +66,9 @@ class UploadList : public base::RefCountedThreadSafe<UploadList> {
base::Time capture_time;
State state;
+
+ // Formatted file size for locally stored data.
+ base::string16 file_size;
};
class Delegate {
@@ -74,12 +84,15 @@ class UploadList : public base::RefCountedThreadSafe<UploadList> {
// Creates a new upload list with the given callback delegate.
UploadList(Delegate* delegate,
const base::FilePath& upload_log_path,
- const scoped_refptr<base::SequencedWorkerPool>& worker_pool);
+ scoped_refptr<base::TaskRunner> task_runner);
// Starts loading the upload list. OnUploadListAvailable will be called when
// loading is complete.
void LoadUploadListAsynchronously();
+ // Asynchronously requests a user triggered upload.
+ void RequestSingleCrashUploadAsync(const std::string& local_id);
+
// Clears the delegate, so that any outstanding asynchronous load will not
// call the delegate on completion.
void ClearDelegate();
@@ -95,12 +108,17 @@ class UploadList : public base::RefCountedThreadSafe<UploadList> {
// Reads the upload log and stores the entries in |uploads|.
virtual void LoadUploadList(std::vector<UploadInfo>* uploads);
+ // Requests a user triggered upload for a crash report with a given id.
+ virtual void RequestSingleCrashUpload(const std::string& local_id);
+
+ const base::FilePath& upload_log_path() const;
+
private:
friend class base::RefCountedThreadSafe<UploadList>;
// Manages the background thread work for LoadUploadListAsynchronously().
void PerformLoadAndNotifyDelegate(
- const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+ scoped_refptr<base::SequencedTaskRunner> task_runner);
// Calls the delegate's callback method, if there is a delegate. Stores
// the newly loaded |uploads| into |uploads_| on the delegate's task runner.
@@ -110,15 +128,17 @@ class UploadList : public base::RefCountedThreadSafe<UploadList> {
void ParseLogEntries(const std::vector<std::string>& log_entries,
std::vector<UploadInfo>* uploads);
- // |thread_checker_| ensures that |uploads_| is only set from the task runner
- // that created the UploadList.
- base::ThreadChecker thread_checker_;
+ // Ensures that this class' thread unsafe state is only accessed from the
+ // sequence that owns this UploadList.
+ base::SequenceChecker sequence_checker_;
+
std::vector<UploadInfo> uploads_;
+
Delegate* delegate_;
const base::FilePath upload_log_path_;
- scoped_refptr<base::SequencedWorkerPool> worker_pool_;
+ const scoped_refptr<base::TaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(UploadList);
};
diff --git a/chromium/components/upload_list/upload_list_unittest.cc b/chromium/components/upload_list/upload_list_unittest.cc
index 76a958d0541..837f7fb817f 100644
--- a/chromium/components/upload_list/upload_list_unittest.cc
+++ b/chromium/components/upload_list/upload_list_unittest.cc
@@ -11,11 +11,13 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
-#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/task_runner.h"
+#include "base/threading/thread.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -29,12 +31,14 @@ const char kTestCaptureTime[] = "2345678901";
class UploadListTest : public testing::Test,
public UploadList::Delegate {
public:
- UploadListTest() : worker_pool_owner_(1, "UploadListTest") {}
+ UploadListTest() : worker_thread_("UploadListTest") {}
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ ASSERT_TRUE(worker_thread_.Start());
}
+ protected:
void WriteUploadLog(const std::string& log_data) {
ASSERT_GT(base::WriteFile(log_path(), log_data.c_str(),
static_cast<int>(log_data.size())),
@@ -53,18 +57,21 @@ class UploadListTest : public testing::Test,
quit_closure_.Run();
}
- const scoped_refptr<base::SequencedWorkerPool> worker_pool() {
- return worker_pool_owner_.pool();
+ scoped_refptr<base::TaskRunner> task_runner() const {
+ return worker_thread_.task_runner();
}
+
base::FilePath log_path() {
- return temp_dir_.path().Append(FILE_PATH_LITERAL("uploads.log"));
+ return temp_dir_.GetPath().Append(FILE_PATH_LITERAL("uploads.log"));
}
private:
base::MessageLoop message_loop_;
base::ScopedTempDir temp_dir_;
- base::SequencedWorkerPoolOwner worker_pool_owner_;
+ base::Thread worker_thread_;
base::Closure quit_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(UploadListTest);
};
// These tests test that UploadList can parse a vector of log entry strings of
@@ -80,7 +87,7 @@ TEST_F(UploadListTest, ParseUploadTimeUploadId) {
WriteUploadLog(test_entry);
scoped_refptr<UploadList> upload_list =
- new UploadList(this, log_path(), worker_pool());
+ new UploadList(this, log_path(), task_runner());
upload_list->LoadUploadListAsynchronously();
WaitForUploadList();
@@ -108,7 +115,7 @@ TEST_F(UploadListTest, ParseUploadTimeUploadIdLocalId) {
WriteUploadLog(test_entry);
scoped_refptr<UploadList> upload_list =
- new UploadList(this, log_path(), worker_pool());
+ new UploadList(this, log_path(), task_runner());
upload_list->LoadUploadListAsynchronously();
WaitForUploadList();
@@ -137,7 +144,7 @@ TEST_F(UploadListTest, ParseUploadTimeUploadIdCaptureTime) {
WriteUploadLog(test_entry);
scoped_refptr<UploadList> upload_list =
- new UploadList(this, log_path(), worker_pool());
+ new UploadList(this, log_path(), task_runner());
upload_list->LoadUploadListAsynchronously();
WaitForUploadList();
@@ -165,7 +172,7 @@ TEST_F(UploadListTest, ParseLocalIdCaptureTime) {
WriteUploadLog(test_entry);
scoped_refptr<UploadList> upload_list =
- new UploadList(this, log_path(), worker_pool());
+ new UploadList(this, log_path(), task_runner());
upload_list->LoadUploadListAsynchronously();
WaitForUploadList();
@@ -197,7 +204,7 @@ TEST_F(UploadListTest, ParseUploadTimeUploadIdLocalIdCaptureTime) {
WriteUploadLog(test_entry);
scoped_refptr<UploadList> upload_list =
- new UploadList(this, log_path(), worker_pool());
+ new UploadList(this, log_path(), task_runner());
upload_list->LoadUploadListAsynchronously();
WaitForUploadList();
@@ -229,7 +236,7 @@ TEST_F(UploadListTest, ParseMultipleEntries) {
WriteUploadLog(test_entry);
scoped_refptr<UploadList> upload_list =
- new UploadList(this, log_path(), worker_pool());
+ new UploadList(this, log_path(), task_runner());
upload_list->LoadUploadListAsynchronously();
WaitForUploadList();
@@ -266,7 +273,7 @@ TEST_F(UploadListTest, ParseWithState) {
WriteUploadLog(test_entry);
scoped_refptr<UploadList> upload_list =
- new UploadList(this, log_path(), worker_pool());
+ new UploadList(this, log_path(), task_runner());
upload_list->LoadUploadListAsynchronously();
WaitForUploadList();
@@ -298,7 +305,7 @@ TEST_F(UploadListTest, SimultaneousAccess) {
WriteUploadLog(test_entry);
scoped_refptr<UploadList> upload_list =
- new UploadList(this, log_path(), worker_pool());
+ new UploadList(this, log_path(), task_runner());
// Queue up a bunch of loads, waiting only for the first one to complete.
// Clearing the delegate prevents the QuitClosure from being Run more than
diff --git a/chromium/components/url_formatter/BUILD.gn b/chromium/components/url_formatter/BUILD.gn
index 0bd6e01e818..b391e73962e 100644
--- a/chromium/components/url_formatter/BUILD.gn
+++ b/chromium/components/url_formatter/BUILD.gn
@@ -2,14 +2,22 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("url_formatter") {
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
+static_library("url_formatter") {
sources = [
+ "android/component_jni_registrar.cc",
+ "android/component_jni_registrar.h",
"elide_url.cc",
"elide_url.h",
"url_fixer.cc",
"url_fixer.h",
"url_formatter.cc",
"url_formatter.h",
+ "url_formatter_android.cc",
+ "url_formatter_android.h",
]
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
@@ -17,12 +25,15 @@ source_set("url_formatter") {
deps = [
"//base",
+ "//base:i18n",
"//net",
"//third_party/icu",
"//url",
]
- if (!is_android) {
+ if (is_android) {
+ deps += [ "android:jni_headers" ]
+ } else {
deps += [ "//ui/gfx" ]
}
}
diff --git a/chromium/components/url_formatter/DEPS b/chromium/components/url_formatter/DEPS
index 7035914143c..5451f010dd0 100644
--- a/chromium/components/url_formatter/DEPS
+++ b/chromium/components/url_formatter/DEPS
@@ -4,6 +4,7 @@ include_rules = [
"-content",
"-ios",
+ "+jni",
"+net",
"+ui/gfx",
]
diff --git a/chromium/components/url_formatter/android/BUILD.gn b/chromium/components/url_formatter/android/BUILD.gn
new file mode 100644
index 00000000000..b4d97e8c1a1
--- /dev/null
+++ b/chromium/components/url_formatter/android/BUILD.gn
@@ -0,0 +1,23 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+android_library("url_formatter_java") {
+ deps = [
+ "//base:base_java",
+ ]
+
+ java_files = [
+ "java/src/org/chromium/components/url_formatter/UrlFormatter.java",
+ ]
+}
+
+generate_jni("jni_headers") {
+ sources = [
+ "java/src/org/chromium/components/url_formatter/UrlFormatter.java",
+ ]
+
+ jni_package = "url_formatter"
+}
diff --git a/chromium/components/url_formatter/elide_url.cc b/chromium/components/url_formatter/elide_url.cc
index a27506bfb1a..e19da1f7339 100644
--- a/chromium/components/url_formatter/elide_url.cc
+++ b/chromium/components/url_formatter/elide_url.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
@@ -127,6 +128,16 @@ bool ShouldShowScheme(base::StringPiece scheme,
return true;
}
+// TODO(jshin): Come up with a way to show Bidi URLs 'safely' (e.g. wrap up
+// the entire url with {LSI, PDI} and individual domain labels with {FSI, PDI}).
+// See http://crbug.com/650760 . For now, fall back to punycode if there's a
+// strong RTL character.
+base::string16 HostForDisplay(base::StringPiece host_in_puny) {
+ base::string16 host = url_formatter::IDNToUnicode(host_in_puny);
+ return base::i18n::StringContainsStrongRTLChars(host) ?
+ base::ASCIIToUTF16(host_in_puny) : host;
+}
+
} // namespace
namespace url_formatter {
@@ -363,7 +374,7 @@ base::string16 FormatUrlForSecurityDisplay(const GURL& url,
base::string16 result;
if (ShouldShowScheme(scheme, scheme_display))
result = base::UTF8ToUTF16(scheme) + scheme_separator;
- result += base::UTF8ToUTF16(host);
+ result += HostForDisplay(host);
const int port = origin.IntPort();
const int default_port = url::DefaultPortForScheme(
@@ -389,7 +400,7 @@ base::string16 FormatOriginForSecurityDisplay(
base::string16 result;
if (ShouldShowScheme(scheme, scheme_display))
result = base::UTF8ToUTF16(scheme) + scheme_separator;
- result += base::UTF8ToUTF16(host);
+ result += HostForDisplay(host);
int port = static_cast<int>(origin.port());
const int default_port = url::DefaultPortForScheme(
diff --git a/chromium/components/url_formatter/elide_url.h b/chromium/components/url_formatter/elide_url.h
index bb34f7c3f5f..fb07e4ecfe9 100644
--- a/chromium/components/url_formatter/elide_url.h
+++ b/chromium/components/url_formatter/elide_url.h
@@ -64,9 +64,11 @@ enum class SchemeDisplay {
// other circumstances when people need to distinguish sites, origins, or
// otherwise-simplified URLs from each other).
//
-// Internationalized domain names (IDN) may be presented in Unicode if
-// they're regarded safe. See |url_formatter::FormatUrl| for more details on
-// the algorithm).
+// Internationalized domain names (IDN) will be presented in Unicode if
+// they're regarded safe except that domain names with RTL characters
+// will still be in ACE/punycode for now (http://crbug.com/650760).
+// See http://dev.chromium.org/developers/design-documents/idn-in-google-chrome
+// for details on the algorithm.
//
// - Omits the path for standard schemes, excepting file and filesystem.
// - Omits the port if it is the default for the scheme.
diff --git a/chromium/components/url_formatter/elide_url_unittest.cc b/chromium/components/url_formatter/elide_url_unittest.cc
index fd5b89d4e13..56058fe78fb 100644
--- a/chromium/components/url_formatter/elide_url_unittest.cc
+++ b/chromium/components/url_formatter/elide_url_unittest.cc
@@ -258,8 +258,8 @@ const OriginTestData common_tests[] = {
L"https://www.google.com", L"www.google.com", L"www.google.com"},
{"Standard HTTP port, IDN Chinese",
"http://\xe4\xb8\xad\xe5\x9b\xbd.icom.museum:80",
- L"http://xn--fiqs8s.icom.museum", L"xn--fiqs8s.icom.museum",
- L"http://xn--fiqs8s.icom.museum"},
+ L"http://\x4e2d\x56fd.icom.museum", L"\x4e2d\x56fd.icom.museum",
+ L"http://\x4e2d\x56fd.icom.museum"},
{"HTTP URL, IDN Hebrew (RTL)",
"http://"
"\xd7\x90\xd7\x99\xd7\xa7\xd7\x95\xd7\xb4\xd7\x9d."
diff --git a/chromium/components/url_formatter/url_fixer.cc b/chromium/components/url_formatter/url_fixer.cc
index 53abe4e0c4a..c49b31ba08c 100644
--- a/chromium/components/url_formatter/url_fixer.cc
+++ b/chromium/components/url_formatter/url_fixer.cc
@@ -480,7 +480,10 @@ std::string SegmentURLInternal(std::string* text, url::Parsed* parts) {
// Construct the text to parse by inserting the scheme.
std::string inserted_text(scheme);
- inserted_text.append(url::kStandardSchemeSeparator);
+ // Assume a leading colon was meant to be a scheme separator (which GURL will
+ // fix up for us into the full "://"). Otherwise add the separator ourselves.
+ if (first_nonwhite == text->end() || *first_nonwhite != ':')
+ inserted_text.append(url::kStandardSchemeSeparator);
std::string text_to_parse(text->begin(), first_nonwhite);
text_to_parse.append(inserted_text);
text_to_parse.append(first_nonwhite, text->end());
diff --git a/chromium/components/url_formatter/url_fixer_unittest.cc b/chromium/components/url_formatter/url_fixer_unittest.cc
index a425489494e..48ad0e6666e 100644
--- a/chromium/components/url_formatter/url_fixer_unittest.cc
+++ b/chromium/components/url_formatter/url_fixer_unittest.cc
@@ -182,12 +182,11 @@ static const SegmentCase segment_cases[] = {
url::Component(), // query
url::Component(), // ref
},
- // Can't do anything useful with this.
- { ":b005::68]", "",
- url::Component(0, 0), // scheme
+ { ":b005::68]", "http",
+ url::Component(), // scheme
url::Component(), // username
url::Component(), // password
- url::Component(), // host
+ url::Component(1, 9), // host
url::Component(), // port
url::Component(), // path
url::Component(), // query
@@ -297,8 +296,10 @@ struct FixupCase {
{"[::]:80", "http://[::]/"},
{"[::]:80/path", "http://[::]/path"},
{"[::]:180/path", "http://[::]:180/path"},
- // TODO(pmarks): Maybe we should parse bare IPv6 literals someday.
- {"::1", "::1"},
+ // TODO(pmarks): Maybe we should parse bare IPv6 literals someday. Currently
+ // the first colon is treated as a scheme separator, and we default
+ // unspecified schemes to "http".
+ {"::1", "http://:1/"},
// Semicolon as scheme separator for standard schemes.
{"http;//www.google.com/", "http://www.google.com/"},
{"about;chrome", "chrome://chrome/"},
@@ -375,7 +376,7 @@ TEST(URLFixerTest, FixupFile) {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath original;
ASSERT_TRUE(MakeTempFile(
- temp_dir_.path(),
+ temp_dir_.GetPath(),
base::FilePath(FILE_PATH_LITERAL("url fixer upper existing file.txt")),
&original));
@@ -460,7 +461,7 @@ TEST(URLFixerTest, FixupRelativeFile) {
FILE_PATH_LITERAL("url_fixer_upper_existing_file.txt"));
base::ScopedTempDir temp_dir_;
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- ASSERT_TRUE(MakeTempFile(temp_dir_.path(), file_part, &full_path));
+ ASSERT_TRUE(MakeTempFile(temp_dir_.GetPath(), file_part, &full_path));
full_path = base::MakeAbsoluteFilePath(full_path);
ASSERT_FALSE(full_path.empty());
@@ -469,23 +470,25 @@ TEST(URLFixerTest, FixupRelativeFile) {
FixupCase value = fixup_cases[i];
base::FilePath input = base::FilePath::FromUTF8Unsafe(value.input);
EXPECT_EQ(value.output,
- url_formatter::FixupRelativeFile(temp_dir_.path(),
- input).possibly_invalid_spec());
+ url_formatter::FixupRelativeFile(temp_dir_.GetPath(), input)
+ .possibly_invalid_spec());
}
// make sure the existing file got fixed-up to a file URL, and that there
// are no backslashes
EXPECT_TRUE(IsMatchingFileURL(
- url_formatter::FixupRelativeFile(temp_dir_.path(),
- file_part).possibly_invalid_spec(), full_path));
+ url_formatter::FixupRelativeFile(temp_dir_.GetPath(), file_part)
+ .possibly_invalid_spec(),
+ full_path));
EXPECT_TRUE(base::DeleteFile(full_path, false));
// create a filename we know doesn't exist and make sure it doesn't get
// fixed up to a file URL
base::FilePath nonexistent_file(
FILE_PATH_LITERAL("url_fixer_upper_nonexistent_file.txt"));
- std::string fixedup(url_formatter::FixupRelativeFile(
- temp_dir_.path(), nonexistent_file).possibly_invalid_spec());
+ std::string fixedup(
+ url_formatter::FixupRelativeFile(temp_dir_.GetPath(), nonexistent_file)
+ .possibly_invalid_spec());
EXPECT_NE(std::string("file:///"), fixedup.substr(0, 8));
EXPECT_FALSE(IsMatchingFileURL(fixedup, nonexistent_file));
@@ -495,7 +498,7 @@ TEST(URLFixerTest, FixupRelativeFile) {
base::FilePath sub_dir(FILE_PATH_LITERAL("url fixer-upper dir"));
base::FilePath sub_file(
FILE_PATH_LITERAL("url fixer-upper existing file.txt"));
- base::FilePath new_dir = temp_dir_.path().Append(sub_dir);
+ base::FilePath new_dir = temp_dir_.GetPath().Append(sub_dir);
base::CreateDirectory(new_dir);
ASSERT_TRUE(MakeTempFile(new_dir, sub_file, &full_path));
full_path = base::MakeAbsoluteFilePath(full_path);
@@ -504,8 +507,9 @@ TEST(URLFixerTest, FixupRelativeFile) {
// test file in the subdir
base::FilePath relative_file = sub_dir.Append(sub_file);
EXPECT_TRUE(IsMatchingFileURL(
- url_formatter::FixupRelativeFile(temp_dir_.path(),
- relative_file).possibly_invalid_spec(), full_path));
+ url_formatter::FixupRelativeFile(temp_dir_.GetPath(), relative_file)
+ .possibly_invalid_spec(),
+ full_path));
// test file in the subdir with different slashes and escaping.
base::FilePath::StringType relative_file_str = sub_dir.value() +
@@ -513,18 +517,20 @@ TEST(URLFixerTest, FixupRelativeFile) {
base::ReplaceSubstringsAfterOffset(&relative_file_str, 0,
FILE_PATH_LITERAL(" "), FILE_PATH_LITERAL("%20"));
EXPECT_TRUE(IsMatchingFileURL(
- url_formatter::FixupRelativeFile(temp_dir_.path(),
- base::FilePath(relative_file_str)).possibly_invalid_spec(),
- full_path));
+ url_formatter::FixupRelativeFile(temp_dir_.GetPath(),
+ base::FilePath(relative_file_str))
+ .possibly_invalid_spec(),
+ full_path));
// test relative directories and duplicate slashes
// (should resolve to the same file as above)
relative_file_str = sub_dir.value() + FILE_PATH_LITERAL("/../") +
sub_dir.value() + FILE_PATH_LITERAL("///./") + sub_file.value();
EXPECT_TRUE(IsMatchingFileURL(
- url_formatter::FixupRelativeFile(temp_dir_.path(),
- base::FilePath(relative_file_str)).possibly_invalid_spec(),
- full_path));
+ url_formatter::FixupRelativeFile(temp_dir_.GetPath(),
+ base::FilePath(relative_file_str))
+ .possibly_invalid_spec(),
+ full_path));
// done with the subdir
EXPECT_TRUE(base::DeleteFile(full_path, false));
diff --git a/chromium/components/url_formatter/url_formatter.cc b/chromium/components/url_formatter/url_formatter.cc
index 75f17262d47..4455db3e633 100644
--- a/chromium/components/url_formatter/url_formatter.cc
+++ b/chromium/components/url_formatter/url_formatter.cc
@@ -29,7 +29,7 @@ namespace url_formatter {
namespace {
base::string16 IDNToUnicodeWithAdjustments(
- const std::string& host,
+ base::StringPiece host,
base::OffsetAdjuster::Adjustments* adjustments);
bool IDNToUnicodeOneComponent(const base::char16* comp,
size_t comp_len,
@@ -192,8 +192,7 @@ base::string16 FormatViewSourceUrl(
// TODO(brettw): We may want to skip this step in the case of file URLs to
// allow unicode UNC hostnames regardless of encodings.
base::string16 IDNToUnicodeWithAdjustments(
- const std::string& host,
- base::OffsetAdjuster::Adjustments* adjustments) {
+ base::StringPiece host, base::OffsetAdjuster::Adjustments* adjustments) {
if (adjustments)
adjustments->clear();
// Convert the ASCII input to a base::string16 for ICU.
@@ -782,7 +781,7 @@ void AppendFormattedHost(const GURL& url, base::string16* output) {
HostComponentTransform(), output, NULL, NULL);
}
-base::string16 IDNToUnicode(const std::string& host) {
+base::string16 IDNToUnicode(base::StringPiece host) {
return IDNToUnicodeWithAdjustments(host, nullptr);
}
diff --git a/chromium/components/url_formatter/url_formatter.gyp b/chromium/components/url_formatter/url_formatter.gyp
deleted file mode 100644
index 9375e96d93d..00000000000
--- a/chromium/components/url_formatter/url_formatter.gyp
+++ /dev/null
@@ -1,39 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/url_formatter
- 'target_name': 'url_formatter',
- 'type': 'static_library',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../net/net.gyp:net',
- '../../third_party/icu/icu.gyp:icui18n',
- '../../third_party/icu/icu.gyp:icuuc',
- '../../url/url.gyp:url_lib',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'elide_url.cc',
- 'elide_url.h',
- 'url_fixer.cc',
- 'url_fixer.h',
- 'url_formatter.cc',
- 'url_formatter.h',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
-
- 'conditions': [
- ['OS != "android"', {
- 'dependencies': [
- '../../ui/gfx/gfx.gyp:gfx',
- ]
- }],
- ],
- },
- ],
-}
diff --git a/chromium/components/url_formatter/url_formatter.h b/chromium/components/url_formatter/url_formatter.h
index 87b7ba5bcf7..90f2bbf9b73 100644
--- a/chromium/components/url_formatter/url_formatter.h
+++ b/chromium/components/url_formatter/url_formatter.h
@@ -22,6 +22,7 @@
#include <vector>
#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
#include "base/strings/utf_offset_string_conversions.h"
#include "net/base/escape.h"
@@ -133,7 +134,7 @@ void AppendFormattedHost(const GURL& url, base::string16* output);
//
// The input should be the canonicalized ASCII host name from GURL. This
// function does NOT accept UTF-8!
-base::string16 IDNToUnicode(const std::string& host);
+base::string16 IDNToUnicode(base::StringPiece host);
// If |text| starts with "www." it is removed, otherwise |text| is returned
// unmodified.
diff --git a/chromium/components/url_formatter/url_formatter_android.cc b/chromium/components/url_formatter/url_formatter_android.cc
new file mode 100644
index 00000000000..bc2e16cb9f5
--- /dev/null
+++ b/chromium/components/url_formatter/url_formatter_android.cc
@@ -0,0 +1,77 @@
+// 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 "components/url_formatter/url_formatter_android.h"
+
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "components/url_formatter/elide_url.h"
+#include "components/url_formatter/url_fixer.h"
+#include "components/url_formatter/url_formatter.h"
+#include "jni/UrlFormatter_jni.h"
+#include "url/gurl.h"
+
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
+namespace {
+
+GURL ConvertJavaStringToGURL(JNIEnv* env, jstring url) {
+ return url ? GURL(base::android::ConvertJavaStringToUTF8(env, url)) : GURL();
+}
+
+} // namespace
+
+namespace url_formatter {
+
+namespace android {
+
+static ScopedJavaLocalRef<jstring> FixupUrl(JNIEnv* env,
+ const JavaParamRef<jclass>& clazz,
+ const JavaParamRef<jstring>& url) {
+ DCHECK(url);
+ GURL fixed_url = url_formatter::FixupURL(
+ base::android::ConvertJavaStringToUTF8(env, url), std::string());
+
+ return fixed_url.is_valid()
+ ? base::android::ConvertUTF8ToJavaString(env, fixed_url.spec())
+ : ScopedJavaLocalRef<jstring>();
+}
+
+static ScopedJavaLocalRef<jstring> FormatUrlForDisplay(
+ JNIEnv* env,
+ const JavaParamRef<jclass>& clazz,
+ const JavaParamRef<jstring>& url) {
+ return base::android::ConvertUTF16ToJavaString(
+ env, url_formatter::FormatUrl(ConvertJavaStringToGURL(env, url)));
+}
+
+static ScopedJavaLocalRef<jstring> FormatUrlForSecurityDisplay(
+ JNIEnv* env,
+ const JavaParamRef<jclass>& clazz,
+ const JavaParamRef<jstring>& url) {
+ return base::android::ConvertUTF16ToJavaString(
+ env, url_formatter::FormatUrlForSecurityDisplay(
+ ConvertJavaStringToGURL(env, url)));
+}
+
+static ScopedJavaLocalRef<jstring> FormatUrlForSecurityDisplayOmitScheme(
+ JNIEnv* env,
+ const JavaParamRef<jclass>& clazz,
+ const JavaParamRef<jstring>& url) {
+ return base::android::ConvertUTF16ToJavaString(
+ env, url_formatter::FormatUrlForSecurityDisplay(
+ ConvertJavaStringToGURL(env, url),
+ url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS));
+}
+
+bool RegisterUrlFormatterNatives(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+
+} // namespace url_formatter
diff --git a/chromium/components/url_formatter/url_formatter_android.h b/chromium/components/url_formatter/url_formatter_android.h
new file mode 100644
index 00000000000..fdf3d91f575
--- /dev/null
+++ b/chromium/components/url_formatter/url_formatter_android.h
@@ -0,0 +1,20 @@
+// 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 COMPONENTS_URL_FORMATTER_URL_FORMATTER_ANDROID_H_
+#define COMPONENTS_URL_FORMATTER_URL_FORMATTER_ANDROID_H_
+
+#include <jni.h>
+
+namespace url_formatter {
+
+namespace android {
+
+bool RegisterUrlFormatterNatives(JNIEnv* env);
+
+} // namespace android
+
+} // namespace url_formatter
+
+#endif // COMPONENTS_URL_FORMATTER_URL_FORMATTER_ANDROID_H_
diff --git a/chromium/components/url_matcher.gypi b/chromium/components/url_matcher.gypi
deleted file mode 100644
index 4d2e328d333..00000000000
--- a/chromium/components/url_matcher.gypi
+++ /dev/null
@@ -1,43 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'url_matcher',
- 'type': '<(component)',
- 'dependencies': [
- '../third_party/re2/re2.gyp:re2',
- '../base/base.gyp:base',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../url/url.gyp:url_lib',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'URL_MATCHER_IMPLEMENTATION',
- ],
- 'sources': [
- 'url_matcher/regex_set_matcher.cc',
- 'url_matcher/regex_set_matcher.h',
- 'url_matcher/string_pattern.cc',
- 'url_matcher/string_pattern.h',
- 'url_matcher/substring_set_matcher.cc',
- 'url_matcher/substring_set_matcher.h',
- 'url_matcher/url_matcher.cc',
- 'url_matcher/url_matcher.h',
- 'url_matcher/url_matcher_constants.cc',
- 'url_matcher/url_matcher_constants.h',
- 'url_matcher/url_matcher_export.h',
- 'url_matcher/url_matcher_factory.cc',
- 'url_matcher/url_matcher_factory.h',
- 'url_matcher/url_matcher_helpers.cc',
- 'url_matcher/url_matcher_helpers.h',
- ],
- # Disable c4267 warnings until we fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- },
- ],
-}
diff --git a/chromium/components/url_matcher/regex_set_matcher.cc b/chromium/components/url_matcher/regex_set_matcher.cc
index d597f0001a5..ac48123aaf8 100644
--- a/chromium/components/url_matcher/regex_set_matcher.cc
+++ b/chromium/components/url_matcher/regex_set_matcher.cc
@@ -108,7 +108,7 @@ void RegexSetMatcher::RebuildMatcher() {
}
void RegexSetMatcher::DeleteSubstringPatterns() {
- STLDeleteElements(&substring_patterns_);
+ base::STLDeleteElements(&substring_patterns_);
}
} // namespace url_matcher
diff --git a/chromium/components/url_matcher/regex_set_matcher_unittest.cc b/chromium/components/url_matcher/regex_set_matcher_unittest.cc
index dd54e51d2fb..49d9a57761b 100644
--- a/chromium/components/url_matcher/regex_set_matcher_unittest.cc
+++ b/chromium/components/url_matcher/regex_set_matcher_unittest.cc
@@ -26,14 +26,14 @@ TEST(RegexSetMatcherTest, MatchRegexes) {
std::set<StringPattern::ID> result1;
matcher.Match("http://abracadabra.com", &result1);
EXPECT_EQ(2U, result1.size());
- EXPECT_TRUE(ContainsKey(result1, 42));
- EXPECT_TRUE(ContainsKey(result1, 239));
+ EXPECT_TRUE(base::ContainsKey(result1, 42));
+ EXPECT_TRUE(base::ContainsKey(result1, 239));
std::set<StringPattern::ID> result2;
matcher.Match("https://abfffffffffffffffffffffffffffffff.fi/cf", &result2);
EXPECT_EQ(2U, result2.size());
- EXPECT_TRUE(ContainsKey(result2, 17));
- EXPECT_TRUE(ContainsKey(result2, 42));
+ EXPECT_TRUE(base::ContainsKey(result2, 17));
+ EXPECT_TRUE(base::ContainsKey(result2, 42));
std::set<StringPattern::ID> result3;
matcher.Match("http://nothing.com/", &result3);
@@ -56,7 +56,7 @@ TEST(RegexSetMatcherTest, CaseSensitivity) {
std::set<StringPattern::ID> result2;
matcher.Match("http://aaa.net/quaaACK", &result2);
EXPECT_EQ(1U, result2.size());
- EXPECT_TRUE(ContainsKey(result2, 57));
+ EXPECT_TRUE(base::ContainsKey(result2, 57));
}
} // namespace url_matcher
diff --git a/chromium/components/url_matcher/url_matcher.cc b/chromium/components/url_matcher/url_matcher.cc
index 91cd15b61b2..8e5cd9ebfdc 100644
--- a/chromium/components/url_matcher/url_matcher.cc
+++ b/chromium/components/url_matcher/url_matcher.cc
@@ -222,7 +222,7 @@ bool URLMatcherCondition::IsMatch(
const std::set<StringPattern::ID>& matching_patterns,
const GURL& url) const {
DCHECK(string_pattern_);
- if (!ContainsKey(matching_patterns, string_pattern_->id()))
+ if (!base::ContainsKey(matching_patterns, string_pattern_->id()))
return false;
// The criteria HOST_CONTAINS, PATH_CONTAINS, QUERY_CONTAINS are based on
// a substring match on the raw URL. In case of a match, we need to verify
@@ -262,9 +262,9 @@ const char kQuerySeparator = '&';
URLMatcherConditionFactory::URLMatcherConditionFactory() : id_counter_(0) {}
URLMatcherConditionFactory::~URLMatcherConditionFactory() {
- STLDeleteElements(&substring_pattern_singletons_);
- STLDeleteElements(&regex_pattern_singletons_);
- STLDeleteElements(&origin_and_path_regex_pattern_singletons_);
+ base::STLDeleteElements(&substring_pattern_singletons_);
+ base::STLDeleteElements(&regex_pattern_singletons_);
+ base::STLDeleteElements(&origin_and_path_regex_pattern_singletons_);
}
std::string URLMatcherConditionFactory::CanonicalizeURLForComponentSearches(
@@ -465,7 +465,7 @@ void URLMatcherConditionFactory::ForgetUnusedPatterns(
const std::set<StringPattern::ID>& used_patterns) {
PatternSingletons::iterator i = substring_pattern_singletons_.begin();
while (i != substring_pattern_singletons_.end()) {
- if (ContainsKey(used_patterns, (*i)->id())) {
+ if (base::ContainsKey(used_patterns, (*i)->id())) {
++i;
} else {
delete *i;
@@ -474,7 +474,7 @@ void URLMatcherConditionFactory::ForgetUnusedPatterns(
}
i = regex_pattern_singletons_.begin();
while (i != regex_pattern_singletons_.end()) {
- if (ContainsKey(used_patterns, (*i)->id())) {
+ if (base::ContainsKey(used_patterns, (*i)->id())) {
++i;
} else {
delete *i;
@@ -483,7 +483,7 @@ void URLMatcherConditionFactory::ForgetUnusedPatterns(
}
i = origin_and_path_regex_pattern_singletons_.begin();
while (i != origin_and_path_regex_pattern_singletons_.end()) {
- if (ContainsKey(used_patterns, (*i)->id())) {
+ if (base::ContainsKey(used_patterns, (*i)->id())) {
++i;
} else {
delete *i;
@@ -513,30 +513,26 @@ URLMatcherCondition URLMatcherConditionFactory::CreateCondition(
PatternSingletons::const_iterator iter =
pattern_singletons->find(&search_pattern);
- if (iter != pattern_singletons->end()) {
+ if (iter != pattern_singletons->end())
return URLMatcherCondition(criterion, *iter);
- } else {
- StringPattern* new_pattern =
- new StringPattern(pattern, id_counter_++);
- pattern_singletons->insert(new_pattern);
- return URLMatcherCondition(criterion, new_pattern);
- }
+
+ StringPattern* new_pattern = new StringPattern(pattern, id_counter_++);
+ pattern_singletons->insert(new_pattern);
+ return URLMatcherCondition(criterion, new_pattern);
}
std::string URLMatcherConditionFactory::CanonicalizeHostSuffix(
const std::string& suffix) const {
- if (!suffix.empty() && suffix[suffix.size() - 1] == '.')
- return suffix;
- else
- return suffix + ".";
+ if (suffix.empty())
+ return ".";
+ return suffix.back() == '.' ? suffix : suffix + ".";
}
std::string URLMatcherConditionFactory::CanonicalizeHostPrefix(
const std::string& prefix) const {
- if (!prefix.empty() && prefix[0] == '.')
- return prefix;
- else
- return "." + prefix;
+ if (prefix.empty())
+ return ".";
+ return prefix[0] == '.' ? prefix : "." + prefix;
}
std::string URLMatcherConditionFactory::CanonicalizeHostname(
@@ -788,7 +784,7 @@ bool URLMatcherConditionSet::IsMatch(
for (QueryConditions::const_iterator i = query_conditions_.begin();
i != query_conditions_.end();
++i) {
- if (!ContainsKey(matching_patterns, i->string_pattern()->id()))
+ if (!base::ContainsKey(matching_patterns, i->string_pattern()->id()))
return false;
}
for (QueryConditions::const_iterator i = query_conditions_.begin();
diff --git a/chromium/components/url_matcher/url_matcher_factory.cc b/chromium/components/url_matcher/url_matcher_factory.cc
index 848e5d46939..5793f68e82f 100644
--- a/chromium/components/url_matcher/url_matcher_factory.cc
+++ b/chromium/components/url_matcher/url_matcher_factory.cc
@@ -234,7 +234,7 @@ URLMatcherFactory::CreateURLMatcherScheme(const base::Value* value,
return nullptr;
}
}
- return base::WrapUnique(new URLMatcherSchemeFilter(schemas));
+ return base::MakeUnique<URLMatcherSchemeFilter>(schemas);
}
// static
@@ -268,7 +268,7 @@ std::unique_ptr<URLMatcherPortFilter> URLMatcherFactory::CreateURLMatcherPorts(
}
}
- return base::WrapUnique(new URLMatcherPortFilter(ranges));
+ return base::MakeUnique<URLMatcherPortFilter>(ranges);
}
} // namespace url_matcher
diff --git a/chromium/components/user_manager.gypi b/chromium/components/user_manager.gypi
deleted file mode 100644
index 9cb57d213fa..00000000000
--- a/chromium/components/user_manager.gypi
+++ /dev/null
@@ -1,84 +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.
-
-{
- 'variables': {
- # Cross-platform user_manager sources.
- 'user_manager_shared_sources': [
- 'user_manager/empty_user_info.cc',
- 'user_manager/empty_user_info.h',
- 'user_manager/user_info.cc',
- 'user_manager/user_info.h',
- 'user_manager/user_info_impl.cc',
- 'user_manager/user_info_impl.h',
- 'user_manager/user_manager_export.h',
- ],
- # Chrome OS user_manager sources.
- 'user_manager_chromeos_sources': [
- 'user_manager/known_user.cc',
- 'user_manager/known_user.h',
- 'user_manager/remove_user_delegate.h',
- 'user_manager/user.cc',
- 'user_manager/user.h',
- 'user_manager/user_image/user_image.cc',
- 'user_manager/user_image/user_image.h',
- 'user_manager/user_manager.cc',
- 'user_manager/user_manager.h',
- 'user_manager/user_manager_base.cc',
- 'user_manager/user_manager_base.h',
- 'user_manager/user_type.h',
- ],
- },
- 'targets': [{
- 'target_name': 'user_manager',
- 'type': '<(component)',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/components/components.gyp:signin_core_account_id',
- '<(DEPTH)/skia/skia.gyp:skia',
- '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
- ],
- 'defines': [
- 'USER_MANAGER_IMPLEMENTATION',
- ],
- 'include_dirs': [
- '<(DEPTH)',
- '<(DEPTH)/ui/chromeos/ui_chromeos.gyp:ui_chromeos_resources',
- '<(DEPTH)/ui/chromeos/ui_chromeos.gyp:ui_chromeos_strings',
- ],
- 'sources': [ '<@(user_manager_shared_sources)' ],
- 'conditions': [
- ['chromeos == 1', {
- 'dependencies': [
- '<(DEPTH)/components/components.gyp:session_manager_component',
- '<(DEPTH)/components/prefs/prefs.gyp:prefs',
- '<(DEPTH)/google_apis/google_apis.gyp:google_apis',
- '<(DEPTH)/url/url.gyp:url_lib',
- ],
- 'sources': [ '<@(user_manager_chromeos_sources)' ],
- }],
- ],
- },
- {
- # GN version: //components/user_manager:test_support
- 'target_name': 'user_manager_test_support',
- 'type': 'static_library',
- 'conditions': [
- ['chromeos == 1', {
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/base/base.gyp:test_support_base',
- '<(DEPTH)/skia/skia.gyp:skia',
- '<(DEPTH)/testing/gmock.gyp:gmock',
- '<(DEPTH)/testing/gtest.gyp:gtest',
- 'user_manager',
- ],
- 'sources': [
- 'user_manager/fake_user_manager.cc',
- 'user_manager/fake_user_manager.h',
- ],
- }],
- ]
- },],
-}
diff --git a/chromium/components/user_manager/OWNERS b/chromium/components/user_manager/OWNERS
index d5382f0829c..b280edc9c78 100644
--- a/chromium/components/user_manager/OWNERS
+++ b/chromium/components/user_manager/OWNERS
@@ -1,4 +1,3 @@
achuith@chromium.org
alemate@chromium.org
-dzhioev@chromium.org
xiyuan@chromium.org
diff --git a/chromium/components/user_manager/known_user.cc b/chromium/components/user_manager/known_user.cc
index 19fc5d97fd7..8ad90614b9f 100644
--- a/chromium/components/user_manager/known_user.cc
+++ b/chromium/components/user_manager/known_user.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <memory>
+#include <utility>
#include "base/logging.h"
#include "base/values.h"
@@ -137,7 +138,7 @@ void UpdatePrefs(const AccountId& account_id,
std::unique_ptr<base::DictionaryValue> new_value(new base::DictionaryValue());
new_value->MergeDictionary(&values);
UpdateIdentity(account_id, *new_value);
- update->Append(new_value.release());
+ update->Append(std::move(new_value));
}
bool GetStringPref(const AccountId& account_id,
diff --git a/chromium/components/user_manager/user_manager_base.cc b/chromium/components/user_manager/user_manager_base.cc
index 58d405fb536..5c960408303 100644
--- a/chromium/components/user_manager/user_manager_base.cc
+++ b/chromium/components/user_manager/user_manager_base.cc
@@ -16,6 +16,7 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -851,7 +852,8 @@ void UserManagerBase::GuestUserLoggedIn() {
void UserManagerBase::AddUserRecord(User* user) {
// Add the user to the front of the user list.
ListPrefUpdate prefs_users_update(GetLocalState(), kRegularUsers);
- prefs_users_update->Insert(0, new base::StringValue(user->email()));
+ prefs_users_update->Insert(
+ 0, base::MakeUnique<base::StringValue>(user->email()));
users_.insert(users_.begin(), user);
}
@@ -964,7 +966,7 @@ User* UserManagerBase::RemoveRegularOrSupervisedUserFromList(
} else {
if ((*it)->HasGaiaAccount() || (*it)->IsSupervised()) {
const std::string user_email = (*it)->email();
- prefs_users_update->Append(new base::StringValue(user_email));
+ prefs_users_update->AppendString(user_email);
}
++it;
}
@@ -1042,7 +1044,7 @@ void UserManagerBase::SendGaiaUserLoginMetrics(const AccountId& account_id) {
account_id != AccountId::FromUserEmail(last_email) &&
time_to_login.InSeconds() <= kLogoutToLoginDelayMaxSec) {
UMA_HISTOGRAM_CUSTOM_COUNTS("UserManager.LogoutToLoginDelay",
- time_to_login.InSeconds(), 0,
+ time_to_login.InSeconds(), 1,
kLogoutToLoginDelayMaxSec, 50);
}
}
diff --git a/chromium/components/user_prefs.gypi b/chromium/components/user_prefs.gypi
deleted file mode 100644
index b558435f817..00000000000
--- a/chromium/components/user_prefs.gypi
+++ /dev/null
@@ -1,101 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'user_prefs',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- 'prefs/prefs.gyp:prefs',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'USER_PREFS_IMPLEMENTATION',
- ],
- 'sources': [
- 'user_prefs/user_prefs.cc',
- 'user_prefs/user_prefs.h',
- 'user_prefs/user_prefs_export.h',
- ],
- },
- {
- 'target_name': 'user_prefs_tracked',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- ],
- 'sources': [
- 'user_prefs/tracked/device_id.h',
- 'user_prefs/tracked/device_id_mac.cc',
- 'user_prefs/tracked/device_id_stub.cc',
- 'user_prefs/tracked/device_id_win.cc',
- 'user_prefs/tracked/dictionary_hash_store_contents.cc',
- 'user_prefs/tracked/dictionary_hash_store_contents.h',
- 'user_prefs/tracked/hash_store_contents.h',
- 'user_prefs/tracked/interceptable_pref_filter.cc',
- 'user_prefs/tracked/interceptable_pref_filter.h',
- 'user_prefs/tracked/pref_hash_calculator.cc',
- 'user_prefs/tracked/pref_hash_calculator.h',
- 'user_prefs/tracked/pref_hash_filter.cc',
- 'user_prefs/tracked/pref_hash_filter.h',
- 'user_prefs/tracked/pref_hash_store.h',
- 'user_prefs/tracked/pref_hash_store_impl.cc',
- 'user_prefs/tracked/pref_hash_store_impl.h',
- 'user_prefs/tracked/pref_hash_store_transaction.h',
- 'user_prefs/tracked/pref_names.cc',
- 'user_prefs/tracked/pref_names.h',
- 'user_prefs/tracked/pref_service_hash_store_contents.cc',
- 'user_prefs/tracked/pref_service_hash_store_contents.h',
- 'user_prefs/tracked/segregated_pref_store.cc',
- 'user_prefs/tracked/segregated_pref_store.h',
- 'user_prefs/tracked/tracked_atomic_preference.cc',
- 'user_prefs/tracked/tracked_atomic_preference.h',
- 'user_prefs/tracked/tracked_preference.h',
- 'user_prefs/tracked/tracked_preference_helper.cc',
- 'user_prefs/tracked/tracked_preference_helper.h',
- 'user_prefs/tracked/tracked_preference_histogram_names.cc',
- 'user_prefs/tracked/tracked_preference_histogram_names.h',
- 'user_prefs/tracked/tracked_preference_validation_delegate.h',
- 'user_prefs/tracked/tracked_preferences_migration.cc',
- 'user_prefs/tracked/tracked_preferences_migration.h',
- 'user_prefs/tracked/tracked_split_preference.cc',
- 'user_prefs/tracked/tracked_split_preference.h',
- ],
- 'conditions': [
- ['OS=="win" or (OS=="mac" and OS!="ios")', {
- 'sources!': [
- 'user_prefs/tracked/device_id_stub.cc',
- ],
- }],
- ['OS=="ios"', {
- 'sources!': [
- 'user_prefs/tracked/device_id_mac.cc',
- ],
- }],
- ],
-
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- 'target_name': 'user_prefs_tracked_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- ],
- 'sources': [
- 'user_prefs/tracked/mock_validation_delegate.cc',
- 'user_prefs/tracked/mock_validation_delegate.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/user_prefs/tracked/BUILD.gn b/chromium/components/user_prefs/tracked/BUILD.gn
index 3afd2bc7744..d2108c61762 100644
--- a/chromium/components/user_prefs/tracked/BUILD.gn
+++ b/chromium/components/user_prefs/tracked/BUILD.gn
@@ -23,8 +23,8 @@ static_library("user_prefs_tracked") {
"pref_hash_store_transaction.h",
"pref_names.cc",
"pref_names.h",
- "pref_service_hash_store_contents.cc",
- "pref_service_hash_store_contents.h",
+ "registry_hash_store_contents_win.cc",
+ "registry_hash_store_contents_win.h",
"segregated_pref_store.cc",
"segregated_pref_store.h",
"tracked_atomic_preference.cc",
@@ -56,7 +56,7 @@ static_library("user_prefs_tracked") {
]
}
-source_set("user_prefs_tracked_test_support") {
+static_library("user_prefs_tracked_test_support") {
testonly = true
sources = [
"mock_validation_delegate.cc",
@@ -76,7 +76,7 @@ source_set("unit_tests") {
"pref_hash_calculator_unittest.cc",
"pref_hash_filter_unittest.cc",
"pref_hash_store_impl_unittest.cc",
- "pref_service_hash_store_contents_unittest.cc",
+ "registry_hash_store_contents_win_unittest.cc",
"segregated_pref_store_unittest.cc",
"tracked_preferences_migration_unittest.cc",
]
@@ -85,6 +85,7 @@ source_set("unit_tests") {
":user_prefs_tracked",
":user_prefs_tracked_test_support",
"//base:base",
+ "//base/test:test_support",
"//components/prefs:test_support",
"//testing/gtest",
]
diff --git a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc b/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc
index 899cafabec1..288c1bf45db 100644
--- a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc
+++ b/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc
@@ -12,42 +12,10 @@
#include "components/prefs/persistent_pref_store.h"
namespace {
-
const char kPreferenceMACs[] = "protection.macs";
const char kSuperMACPref[] = "protection.super_mac";
-
-class MutablePreferenceMacDictionary
- : public HashStoreContents::MutableDictionary {
- public:
- explicit MutablePreferenceMacDictionary(base::DictionaryValue* storage);
-
- // MutableDictionary implementation
- base::DictionaryValue* operator->() override;
-
- private:
- base::DictionaryValue* storage_;
-
- DISALLOW_COPY_AND_ASSIGN(MutablePreferenceMacDictionary);
-};
-
-MutablePreferenceMacDictionary::MutablePreferenceMacDictionary(
- base::DictionaryValue* storage)
- : storage_(storage) {
}
-base::DictionaryValue* MutablePreferenceMacDictionary::operator->() {
- base::DictionaryValue* mac_dictionary = NULL;
-
- if (!storage_->GetDictionary(kPreferenceMACs, &mac_dictionary)) {
- mac_dictionary = new base::DictionaryValue;
- storage_->Set(kPreferenceMACs, mac_dictionary);
- }
-
- return mac_dictionary;
-}
-
-} // namespace
-
DictionaryHashStoreContents::DictionaryHashStoreContents(
base::DictionaryValue* storage)
: storage_(storage) {
@@ -60,28 +28,82 @@ void DictionaryHashStoreContents::RegisterProfilePrefs(
registry->RegisterStringPref(kSuperMACPref, std::string());
}
-std::string DictionaryHashStoreContents::hash_store_id() const {
- return "";
+bool DictionaryHashStoreContents::IsCopyable() const {
+ return false;
+}
+
+std::unique_ptr<HashStoreContents> DictionaryHashStoreContents::MakeCopy()
+ const {
+ NOTREACHED() << "DictionaryHashStoreContents does not support MakeCopy";
+ return nullptr;
+}
+
+base::StringPiece DictionaryHashStoreContents::GetUMASuffix() const {
+ // To stay consistent with existing reported data, do not append a suffix
+ // when reporting UMA stats for this content.
+ return base::StringPiece();
}
void DictionaryHashStoreContents::Reset() {
storage_->Remove(kPreferenceMACs, NULL);
}
-bool DictionaryHashStoreContents::IsInitialized() const {
- return storage_->GetDictionary(kPreferenceMACs, NULL);
+bool DictionaryHashStoreContents::GetMac(const std::string& path,
+ std::string* out_value) {
+ const base::DictionaryValue* macs_dict = GetContents();
+ if (macs_dict)
+ return macs_dict->GetString(path, out_value);
+
+ return false;
}
-const base::DictionaryValue* DictionaryHashStoreContents::GetContents() const {
- const base::DictionaryValue* mac_dictionary = NULL;
- storage_->GetDictionary(kPreferenceMACs, &mac_dictionary);
- return mac_dictionary;
+bool DictionaryHashStoreContents::GetSplitMacs(
+ const std::string& path,
+ std::map<std::string, std::string>* split_macs) {
+ DCHECK(split_macs);
+ DCHECK(split_macs->empty());
+
+ const base::DictionaryValue* macs_dict = GetContents();
+ const base::DictionaryValue* split_macs_dict = NULL;
+ if (!macs_dict || !macs_dict->GetDictionary(path, &split_macs_dict))
+ return false;
+ for (base::DictionaryValue::Iterator it(*split_macs_dict); !it.IsAtEnd();
+ it.Advance()) {
+ std::string mac_string;
+ if (!it.value().GetAsString(&mac_string)) {
+ NOTREACHED();
+ continue;
+ }
+ split_macs->insert(make_pair(it.key(), mac_string));
+ }
+ return true;
}
-std::unique_ptr<HashStoreContents::MutableDictionary>
-DictionaryHashStoreContents::GetMutableContents() {
- return std::unique_ptr<MutableDictionary>(
- new MutablePreferenceMacDictionary(storage_));
+void DictionaryHashStoreContents::SetMac(const std::string& path,
+ const std::string& value) {
+ base::DictionaryValue* macs_dict = GetMutableContents(true);
+ macs_dict->SetString(path, value);
+}
+
+void DictionaryHashStoreContents::SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) {
+ // DictionaryValue handles a '.' delimiter.
+ SetMac(path + '.' + split_path, value);
+}
+
+void DictionaryHashStoreContents::ImportEntry(const std::string& path,
+ const base::Value* in_value) {
+ base::DictionaryValue* macs_dict = GetMutableContents(true);
+ macs_dict->Set(path, in_value->DeepCopy());
+}
+
+bool DictionaryHashStoreContents::RemoveEntry(const std::string& path) {
+ base::DictionaryValue* macs_dict = GetMutableContents(false);
+ if (macs_dict)
+ return macs_dict->RemovePath(path, NULL);
+
+ return false;
}
std::string DictionaryHashStoreContents::GetSuperMac() const {
@@ -93,3 +115,20 @@ std::string DictionaryHashStoreContents::GetSuperMac() const {
void DictionaryHashStoreContents::SetSuperMac(const std::string& super_mac) {
storage_->SetString(kSuperMACPref, super_mac);
}
+
+const base::DictionaryValue* DictionaryHashStoreContents::GetContents() const {
+ const base::DictionaryValue* macs_dict = NULL;
+ storage_->GetDictionary(kPreferenceMACs, &macs_dict);
+ return macs_dict;
+}
+
+base::DictionaryValue* DictionaryHashStoreContents::GetMutableContents(
+ bool create_if_null) {
+ base::DictionaryValue* macs_dict = NULL;
+ storage_->GetDictionary(kPreferenceMACs, &macs_dict);
+ if (!macs_dict && create_if_null) {
+ macs_dict = new base::DictionaryValue;
+ storage_->Set(kPreferenceMACs, macs_dict);
+ }
+ return macs_dict;
+}
diff --git a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h b/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h
index b47d0e0bce4..f231c257bdd 100644
--- a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h
+++ b/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h
@@ -5,12 +5,12 @@
#ifndef COMPONENTS_USER_PREFS_TRACKED_DICTIONARY_HASH_STORE_CONTENTS_H_
#define COMPONENTS_USER_PREFS_TRACKED_DICTIONARY_HASH_STORE_CONTENTS_H_
-#include "base/compiler_specific.h"
#include "base/macros.h"
#include "components/user_prefs/tracked/hash_store_contents.h"
namespace base {
class DictionaryValue;
+class Value;
} // namespace base
namespace user_prefs {
@@ -31,17 +31,31 @@ class DictionaryHashStoreContents : public HashStoreContents {
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// HashStoreContents implementation
- std::string hash_store_id() const override;
+ bool IsCopyable() const override;
+ std::unique_ptr<HashStoreContents> MakeCopy() const override;
+ base::StringPiece GetUMASuffix() const override;
void Reset() override;
- bool IsInitialized() const override;
+ bool GetMac(const std::string& path, std::string* out_value) override;
+ bool GetSplitMacs(const std::string& path,
+ std::map<std::string, std::string>* split_macs) override;
+ void SetMac(const std::string& path, const std::string& value) override;
+ void SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) override;
+ void ImportEntry(const std::string& path,
+ const base::Value* in_value) override;
+ bool RemoveEntry(const std::string& path) override;
const base::DictionaryValue* GetContents() const override;
- std::unique_ptr<MutableDictionary> GetMutableContents() override;
std::string GetSuperMac() const override;
void SetSuperMac(const std::string& super_mac) override;
private:
base::DictionaryValue* storage_;
+ // Helper function to get a mutable version of the macs from |storage_|,
+ // creating it if needed and |create_if_null| is true.
+ base::DictionaryValue* GetMutableContents(bool create_if_null);
+
DISALLOW_COPY_AND_ASSIGN(DictionaryHashStoreContents);
};
diff --git a/chromium/components/user_prefs/tracked/hash_store_contents.h b/chromium/components/user_prefs/tracked/hash_store_contents.h
index 94323843cc1..9cc8abba090 100644
--- a/chromium/components/user_prefs/tracked/hash_store_contents.h
+++ b/chromium/components/user_prefs/tracked/hash_store_contents.h
@@ -5,12 +5,15 @@
#ifndef COMPONENTS_USER_PREFS_TRACKED_HASH_STORE_CONTENTS_H_
#define COMPONENTS_USER_PREFS_TRACKED_HASH_STORE_CONTENTS_H_
+#include <map>
#include <memory>
#include <string>
+#include "base/strings/string_piece.h"
namespace base {
class DictionaryValue;
+class Value;
} // namespace base
// Provides access to the contents of a preference hash store. The store
@@ -19,41 +22,65 @@ class DictionaryValue;
// MACs.
// Version: a client-defined version number for the format of Contents.
// Super MAC: a MAC that authenticates the entirety of Contents.
-// Legacy hash stores may have an ID that was incorporated into MAC
-// calculations. The ID, if any, is available via |hash_store_id()|.
class HashStoreContents {
public:
- // Used to modify a DictionaryValue stored in the preference hash store. The
- // MutableDictionary should be destroyed when modifications are complete in
- // order to allow them to be committed to the underlying storage.
- class MutableDictionary {
- public:
- virtual ~MutableDictionary() {}
- // Returns the DictionaryValue, which will be created if it does not already
- // exist.
- virtual base::DictionaryValue* operator->() = 0;
- };
-
virtual ~HashStoreContents() {}
- // Returns the hash-store ID. May be empty.
- virtual std::string hash_store_id() const = 0;
+ // Returns true if this implementation of HashStoreContents can be copied via
+ // MakeCopy().
+ virtual bool IsCopyable() const = 0;
+
+ // Returns a copy of this HashStoreContents. Must only be called on
+ // lightweight implementations (which return true from IsCopyable()) and only
+ // in scenarios where a copy cannot be avoided.
+ virtual std::unique_ptr<HashStoreContents> MakeCopy() const = 0;
+
+ // Returns the suffix to be appended to UMA histograms for this store type.
+ // The returned value must either be an empty string or one of the values in
+ // histograms.xml's TrackedPreferencesExternalValidators.
+ virtual base::StringPiece GetUMASuffix() const = 0;
// Discards all data related to this hash store.
virtual void Reset() = 0;
- // Indicates whether any data is currently stored for this hash store.
- virtual bool IsInitialized() const = 0;
+ // Outputs the MAC validating the preference at path. Returns true if a MAC
+ // was successfully read and false otherwise.
+ virtual bool GetMac(const std::string& path, std::string* out_value) = 0;
- // Retrieves the contents of this hash store. May return NULL if the hash
- // store has not been initialized.
- virtual const base::DictionaryValue* GetContents() const = 0;
+ // Outputs the MACS validating the split preference at path. Returns true if
+ // MACS were successfully read and false otherwise.
+ virtual bool GetSplitMacs(const std::string& path,
+ std::map<std::string, std::string>* out_value) = 0;
+
+ // Set the MAC validating the preference at path.
+ virtual void SetMac(const std::string& path, const std::string& value) = 0;
- // Provides mutable access to the contents of this hash store.
- virtual std::unique_ptr<MutableDictionary> GetMutableContents() = 0;
+ // Set the MAC validating the split preference at path and split_path.
+ // For example, |path| is 'extension' and |split_path| is some extenson id.
+ virtual void SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) = 0;
+
+ // Sets the MAC for the preference at |path|.
+ // If |path| is a split preference |in_value| must be a DictionaryValue whose
+ // keys are keys in the split preference and whose values are MACs of the
+ // corresponding values in the split preference.
+ // If |path| is an atomic preference |in_value| must be a StringValue
+ // containing a MAC of the preference value.
+ virtual void ImportEntry(const std::string& path,
+ const base::Value* in_value) = 0;
+
+ // Removes the MAC (for atomic preferences) or MACs (for split preferences)
+ // at |path|. Returns true if there was an entry at |path| which was
+ // successfully removed.
+ virtual bool RemoveEntry(const std::string& path) = 0;
+
+ // Only needed if this store supports super MACs.
+ virtual const base::DictionaryValue* GetContents() const = 0;
// Retrieves the super MAC value previously stored by SetSuperMac. May be
- // empty if no super MAC has been stored.
+ // empty if no super MAC has been stored or if this store does not support
+ // super MACs.
virtual std::string GetSuperMac() const = 0;
// Stores a super MAC value for this hash store.
diff --git a/chromium/components/user_prefs/tracked/mock_validation_delegate.cc b/chromium/components/user_prefs/tracked/mock_validation_delegate.cc
index d2936af55be..e0e88283c48 100644
--- a/chromium/components/user_prefs/tracked/mock_validation_delegate.cc
+++ b/chromium/components/user_prefs/tracked/mock_validation_delegate.cc
@@ -20,6 +20,16 @@ size_t MockValidationDelegate::CountValidationsOfState(
return count;
}
+size_t MockValidationDelegate::CountExternalValidationsOfState(
+ PrefHashStoreTransaction::ValueState value_state) const {
+ size_t count = 0;
+ for (size_t i = 0; i < validations_.size(); ++i) {
+ if (validations_[i].external_validation_value_state == value_state)
+ ++count;
+ }
+ return count;
+}
+
const MockValidationDelegate::ValidationEvent*
MockValidationDelegate::GetEventForPath(const std::string& pref_path) const {
for (size_t i = 0; i < validations_.size(); ++i) {
@@ -33,26 +43,31 @@ void MockValidationDelegate::OnAtomicPreferenceValidation(
const std::string& pref_path,
const base::Value* value,
PrefHashStoreTransaction::ValueState value_state,
+ PrefHashStoreTransaction::ValueState external_validation_value_state,
bool is_personal) {
- RecordValidation(pref_path, value_state, is_personal,
- PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
+ RecordValidation(pref_path, value_state, external_validation_value_state,
+ is_personal, PrefHashFilter::TRACKING_STRATEGY_ATOMIC);
}
void MockValidationDelegate::OnSplitPreferenceValidation(
const std::string& pref_path,
const base::DictionaryValue* dict_value,
const std::vector<std::string>& invalid_keys,
+ const std::vector<std::string>& external_validation_invalid_keys,
PrefHashStoreTransaction::ValueState value_state,
+ PrefHashStoreTransaction::ValueState external_validation_value_state,
bool is_personal) {
- RecordValidation(pref_path, value_state, is_personal,
- PrefHashFilter::TRACKING_STRATEGY_SPLIT);
+ RecordValidation(pref_path, value_state, external_validation_value_state,
+ is_personal, PrefHashFilter::TRACKING_STRATEGY_SPLIT);
}
void MockValidationDelegate::RecordValidation(
const std::string& pref_path,
PrefHashStoreTransaction::ValueState value_state,
+ PrefHashStoreTransaction::ValueState external_validation_value_state,
bool is_personal,
PrefHashFilter::PrefTrackingStrategy strategy) {
- validations_.push_back(
- ValidationEvent(pref_path, value_state, is_personal, strategy));
+ validations_.push_back(ValidationEvent(pref_path, value_state,
+ external_validation_value_state,
+ is_personal, strategy));
}
diff --git a/chromium/components/user_prefs/tracked/mock_validation_delegate.h b/chromium/components/user_prefs/tracked/mock_validation_delegate.h
index 0b8cb12ce43..de95f0599ed 100644
--- a/chromium/components/user_prefs/tracked/mock_validation_delegate.h
+++ b/chromium/components/user_prefs/tracked/mock_validation_delegate.h
@@ -20,17 +20,21 @@
class MockValidationDelegate : public TrackedPreferenceValidationDelegate {
public:
struct ValidationEvent {
- ValidationEvent(const std::string& path,
- PrefHashStoreTransaction::ValueState state,
- bool is_personal,
- PrefHashFilter::PrefTrackingStrategy tracking_strategy)
+ ValidationEvent(
+ const std::string& path,
+ PrefHashStoreTransaction::ValueState state,
+ PrefHashStoreTransaction::ValueState external_validation_state,
+ bool is_personal,
+ PrefHashFilter::PrefTrackingStrategy tracking_strategy)
: pref_path(path),
value_state(state),
+ external_validation_value_state(external_validation_state),
is_personal(is_personal),
strategy(tracking_strategy) {}
std::string pref_path;
PrefHashStoreTransaction::ValueState value_state;
+ PrefHashStoreTransaction::ValueState external_validation_value_state;
bool is_personal;
PrefHashFilter::PrefTrackingStrategy strategy;
};
@@ -45,6 +49,10 @@ class MockValidationDelegate : public TrackedPreferenceValidationDelegate {
size_t CountValidationsOfState(
PrefHashStoreTransaction::ValueState value_state) const;
+ // Returns the number of external validations of a given value state.
+ size_t CountExternalValidationsOfState(
+ PrefHashStoreTransaction::ValueState value_state) const;
+
// Returns the event for the preference with a given path.
const ValidationEvent* GetEventForPath(const std::string& pref_path) const;
@@ -53,20 +61,25 @@ class MockValidationDelegate : public TrackedPreferenceValidationDelegate {
const std::string& pref_path,
const base::Value* value,
PrefHashStoreTransaction::ValueState value_state,
+ PrefHashStoreTransaction::ValueState external_validation_value_state,
bool is_personal) override;
void OnSplitPreferenceValidation(
const std::string& pref_path,
const base::DictionaryValue* dict_value,
const std::vector<std::string>& invalid_keys,
+ const std::vector<std::string>& external_validation_invalid_keys,
PrefHashStoreTransaction::ValueState value_state,
+ PrefHashStoreTransaction::ValueState external_validation_value_state,
bool is_personal) override;
private:
// Adds a new validation event.
- void RecordValidation(const std::string& pref_path,
- PrefHashStoreTransaction::ValueState value_state,
- bool is_personal,
- PrefHashFilter::PrefTrackingStrategy strategy);
+ void RecordValidation(
+ const std::string& pref_path,
+ PrefHashStoreTransaction::ValueState value_state,
+ PrefHashStoreTransaction::ValueState external_validation_value_state,
+ bool is_personal,
+ PrefHashFilter::PrefTrackingStrategy strategy);
std::vector<ValidationEvent> validations_;
diff --git a/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc b/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc
index a2de0466ef2..1b3ecd793f5 100644
--- a/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc
+++ b/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc
@@ -8,6 +8,7 @@
#include <string>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -91,9 +92,9 @@ TEST(PrefHashCalculatorTest, CatchHashChanges) {
nested_empty_dict->Set("a", new base::DictionaryValue);
nested_empty_dict->Set("b", new base::ListValue);
std::unique_ptr<base::ListValue> nested_empty_list(new base::ListValue);
- nested_empty_list->Append(new base::DictionaryValue);
- nested_empty_list->Append(new base::ListValue);
- nested_empty_list->Append(nested_empty_dict->DeepCopy());
+ nested_empty_list->Append(base::MakeUnique<base::DictionaryValue>());
+ nested_empty_list->Append(base::MakeUnique<base::ListValue>());
+ nested_empty_list->Append(nested_empty_dict->CreateDeepCopy());
// A dictionary with an empty dictionary, an empty list, and nested empty
// dictionaries/lists in it.
diff --git a/chromium/components/user_prefs/tracked/pref_hash_filter.cc b/chromium/components/user_prefs/tracked/pref_hash_filter.cc
index 2f0c6e71f5f..1101080cd76 100644
--- a/chromium/components/user_prefs/tracked/pref_hash_filter.cc
+++ b/chromium/components/user_prefs/tracked/pref_hash_filter.cc
@@ -8,9 +8,11 @@
#include <algorithm>
#include <utility>
+#include "base/bind.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/metrics/histogram.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
@@ -51,16 +53,27 @@ void CleanupDeprecatedTrackedPreferences(
PrefHashFilter::PrefHashFilter(
std::unique_ptr<PrefHashStore> pref_hash_store,
+ StoreContentsPair external_validation_hash_store_pair,
const std::vector<TrackedPreferenceMetadata>& tracked_preferences,
const base::Closure& on_reset_on_load,
TrackedPreferenceValidationDelegate* delegate,
size_t reporting_ids_count,
bool report_super_mac_validity)
: pref_hash_store_(std::move(pref_hash_store)),
+ external_validation_hash_store_pair_(
+ external_validation_hash_store_pair.first
+ ? base::make_optional(
+ std::move(external_validation_hash_store_pair))
+ : base::nullopt),
on_reset_on_load_(on_reset_on_load),
report_super_mac_validity_(report_super_mac_validity) {
DCHECK(pref_hash_store_);
DCHECK_GE(reporting_ids_count, tracked_preferences.size());
+ // Verify that, if |external_validation_hash_store_pair_| is present, both its
+ // items are non-null.
+ DCHECK(!external_validation_hash_store_pair_.has_value() ||
+ (external_validation_hash_store_pair_->first &&
+ external_validation_hash_store_pair_->second));
for (size_t i = 0; i < tracked_preferences.size(); ++i) {
const TrackedPreferenceMetadata& metadata = tracked_preferences[i];
@@ -132,14 +145,14 @@ void PrefHashFilter::ClearResetTime(PrefService* user_prefs) {
}
void PrefHashFilter::Initialize(base::DictionaryValue* pref_store_contents) {
+ DictionaryHashStoreContents dictionary_contents(pref_store_contents);
std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
- pref_hash_store_->BeginTransaction(std::unique_ptr<HashStoreContents>(
- new DictionaryHashStoreContents(pref_store_contents))));
+ pref_hash_store_->BeginTransaction(&dictionary_contents));
for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin();
it != tracked_paths_.end(); ++it) {
const std::string& initialized_path = it->first;
const TrackedPreference* initialized_preference = it->second;
- const base::Value* value = NULL;
+ const base::Value* value = nullptr;
pref_store_contents->Get(initialized_path, &value);
initialized_preference->OnNewValue(value, hash_store_transaction.get());
}
@@ -156,30 +169,42 @@ void PrefHashFilter::FilterUpdate(const std::string& path) {
// Updates the stored hashes for |changed_paths_| before serializing data to
// disk. This is required as storing the hash everytime a pref's value changes
// is too expensive (see perf regression @ http://crbug.com/331273).
-void PrefHashFilter::FilterSerializeData(
+PrefFilter::OnWriteCallbackPair PrefHashFilter::FilterSerializeData(
base::DictionaryValue* pref_store_contents) {
+ // Generate the callback pair before clearing |changed_paths_|.
+ PrefFilter::OnWriteCallbackPair callback_pair =
+ GetOnWriteSynchronousCallbacks(pref_store_contents);
+
if (!changed_paths_.empty()) {
base::TimeTicks checkpoint = base::TimeTicks::Now();
{
+ DictionaryHashStoreContents dictionary_contents(pref_store_contents);
std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
- pref_hash_store_->BeginTransaction(std::unique_ptr<HashStoreContents>(
- new DictionaryHashStoreContents(pref_store_contents))));
+ pref_hash_store_->BeginTransaction(&dictionary_contents));
+
+ std::unique_ptr<PrefHashStoreTransaction>
+ external_validation_hash_store_transaction;
+ if (external_validation_hash_store_pair_) {
+ external_validation_hash_store_transaction =
+ external_validation_hash_store_pair_->first->BeginTransaction(
+ external_validation_hash_store_pair_->second.get());
+ }
+
for (ChangedPathsMap::const_iterator it = changed_paths_.begin();
it != changed_paths_.end(); ++it) {
const std::string& changed_path = it->first;
const TrackedPreference* changed_preference = it->second;
- const base::Value* value = NULL;
+ const base::Value* value = nullptr;
pref_store_contents->Get(changed_path, &value);
changed_preference->OnNewValue(value, hash_store_transaction.get());
}
changed_paths_.clear();
}
- // TODO(gab): Remove this histogram by Feb 21 2014; after sufficient timing
- // data has been gathered from the wild to be confident this doesn't
- // significantly affect performance on the UI thread.
UMA_HISTOGRAM_TIMES("Settings.FilterSerializeDataTime",
base::TimeTicks::Now() - checkpoint);
}
+
+ return callback_pair;
}
void PrefHashFilter::FinalizeFilterOnLoad(
@@ -191,9 +216,17 @@ void PrefHashFilter::FinalizeFilterOnLoad(
bool did_reset = false;
{
+ DictionaryHashStoreContents dictionary_contents(pref_store_contents.get());
std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
- pref_hash_store_->BeginTransaction(std::unique_ptr<HashStoreContents>(
- new DictionaryHashStoreContents(pref_store_contents.get()))));
+ pref_hash_store_->BeginTransaction(&dictionary_contents));
+
+ std::unique_ptr<PrefHashStoreTransaction>
+ external_validation_hash_store_transaction;
+ if (external_validation_hash_store_pair_) {
+ external_validation_hash_store_transaction =
+ external_validation_hash_store_pair_->first->BeginTransaction(
+ external_validation_hash_store_pair_->second.get());
+ }
CleanupDeprecatedTrackedPreferences(
pref_store_contents.get(), hash_store_transaction.get());
@@ -205,8 +238,9 @@ void PrefHashFilter::FinalizeFilterOnLoad(
for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin();
it != tracked_paths_.end(); ++it) {
- if (it->second->EnforceAndReport(pref_store_contents.get(),
- hash_store_transaction.get())) {
+ if (it->second->EnforceAndReport(
+ pref_store_contents.get(), hash_store_transaction.get(),
+ external_validation_hash_store_transaction.get())) {
did_reset = true;
prefs_altered = true;
}
@@ -225,12 +259,114 @@ void PrefHashFilter::FinalizeFilterOnLoad(
on_reset_on_load_.Run();
}
- // TODO(gab): Remove this histogram by Feb 21 2014; after sufficient timing
- // data has been gathered from the wild to be confident this doesn't
- // significantly affect startup.
UMA_HISTOGRAM_TIMES("Settings.FilterOnLoadTime",
base::TimeTicks::Now() - checkpoint);
post_filter_on_load_callback.Run(std::move(pref_store_contents),
prefs_altered);
}
+
+// static
+void PrefHashFilter::ClearFromExternalStore(
+ HashStoreContents* external_validation_hash_store_contents,
+ const base::DictionaryValue* changed_paths_and_macs) {
+ DCHECK(!changed_paths_and_macs->empty());
+
+ for (base::DictionaryValue::Iterator it(*changed_paths_and_macs);
+ !it.IsAtEnd(); it.Advance()) {
+ external_validation_hash_store_contents->RemoveEntry(it.key());
+ }
+}
+
+// static
+void PrefHashFilter::FlushToExternalStore(
+ std::unique_ptr<HashStoreContents> external_validation_hash_store_contents,
+ std::unique_ptr<base::DictionaryValue> changed_paths_and_macs,
+ bool write_success) {
+ DCHECK(!changed_paths_and_macs->empty());
+ DCHECK(external_validation_hash_store_contents);
+ if (!write_success)
+ return;
+
+ for (base::DictionaryValue::Iterator it(*changed_paths_and_macs);
+ !it.IsAtEnd(); it.Advance()) {
+ const std::string& changed_path = it.key();
+
+ const base::DictionaryValue* split_values = nullptr;
+ if (it.value().GetAsDictionary(&split_values)) {
+ for (base::DictionaryValue::Iterator inner_it(*split_values);
+ !inner_it.IsAtEnd(); inner_it.Advance()) {
+ std::string mac;
+ bool is_string = inner_it.value().GetAsString(&mac);
+ DCHECK(is_string);
+
+ external_validation_hash_store_contents->SetSplitMac(
+ changed_path, inner_it.key(), mac);
+ }
+ } else {
+ const base::StringValue* value_as_string;
+ bool is_string = it.value().GetAsString(&value_as_string);
+ DCHECK(is_string);
+
+ external_validation_hash_store_contents->SetMac(
+ changed_path, value_as_string->GetString());
+ }
+ }
+}
+
+PrefFilter::OnWriteCallbackPair PrefHashFilter::GetOnWriteSynchronousCallbacks(
+ base::DictionaryValue* pref_store_contents) {
+ if (changed_paths_.empty() || !external_validation_hash_store_pair_) {
+ return std::make_pair(base::Closure(),
+ base::Callback<void(bool success)>());
+ }
+
+ std::unique_ptr<base::DictionaryValue> changed_paths_macs =
+ base::MakeUnique<base::DictionaryValue>();
+
+ for (ChangedPathsMap::const_iterator it = changed_paths_.begin();
+ it != changed_paths_.end(); ++it) {
+ const std::string& changed_path = it->first;
+ const TrackedPreference* changed_preference = it->second;
+
+ switch (changed_preference->GetType()) {
+ case TrackedPreferenceType::ATOMIC: {
+ const base::Value* new_value = nullptr;
+ pref_store_contents->Get(changed_path, &new_value);
+ changed_paths_macs->SetStringWithoutPathExpansion(
+ changed_path,
+ external_validation_hash_store_pair_->first->ComputeMac(
+ changed_path, new_value));
+ break;
+ }
+ case TrackedPreferenceType::SPLIT: {
+ const base::DictionaryValue* dict_value = nullptr;
+ pref_store_contents->GetDictionary(changed_path, &dict_value);
+ changed_paths_macs->SetWithoutPathExpansion(
+ changed_path,
+ external_validation_hash_store_pair_->first->ComputeSplitMacs(
+ changed_path, dict_value));
+ break;
+ }
+ }
+ }
+
+ DCHECK(external_validation_hash_store_pair_->second->IsCopyable())
+ << "External HashStoreContents must be copyable as it needs to be used "
+ "off-thread";
+
+ std::unique_ptr<HashStoreContents> hash_store_contents_copy =
+ external_validation_hash_store_pair_->second->MakeCopy();
+
+ // We can use raw pointers for the first callback instead of making more
+ // copies as it will be executed in sequence before the second callback,
+ // which owns the pointers.
+ HashStoreContents* raw_contents = hash_store_contents_copy.get();
+ base::DictionaryValue* raw_changed_paths_macs = changed_paths_macs.get();
+
+ return std::make_pair(
+ base::Bind(&ClearFromExternalStore, base::Unretained(raw_contents),
+ base::Unretained(raw_changed_paths_macs)),
+ base::Bind(&FlushToExternalStore, base::Passed(&hash_store_contents_copy),
+ base::Passed(&changed_paths_macs)));
+}
diff --git a/chromium/components/user_prefs/tracked/pref_hash_filter.h b/chromium/components/user_prefs/tracked/pref_hash_filter.h
index 8652a7f817c..07c92db9506 100644
--- a/chromium/components/user_prefs/tracked/pref_hash_filter.h
+++ b/chromium/components/user_prefs/tracked/pref_hash_filter.h
@@ -15,7 +15,10 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/files/file_path.h"
#include "base/macros.h"
+#include "base/optional.h"
+#include "components/user_prefs/tracked/hash_store_contents.h"
#include "components/user_prefs/tracked/interceptable_pref_filter.h"
#include "components/user_prefs/tracked/tracked_preference.h"
@@ -64,6 +67,9 @@ class PrefHashFilter : public InterceptablePrefFilter {
ValueType value_type;
};
+ using StoreContentsPair = std::pair<std::unique_ptr<PrefHashStore>,
+ std::unique_ptr<HashStoreContents>>;
+
// Constructs a PrefHashFilter tracking the specified |tracked_preferences|
// using |pref_hash_store| to check/store hashes. An optional |delegate| is
// notified of the status of each preference as it is checked.
@@ -73,8 +79,11 @@ class PrefHashFilter : public InterceptablePrefFilter {
// than |tracked_preferences.size()|). If |report_super_mac_validity| is true,
// the state of the super MAC will be reported via UMA during
// FinalizeFilterOnLoad.
+ // |external_validation_hash_store_pair_| will be used (if non-null) to
+ // perform extra validations without triggering resets.
PrefHashFilter(
std::unique_ptr<PrefHashStore> pref_hash_store,
+ StoreContentsPair external_validation_hash_store_pair_,
const std::vector<TrackedPreferenceMetadata>& tracked_preferences,
const base::Closure& on_reset_on_load,
TrackedPreferenceValidationDelegate* delegate,
@@ -101,7 +110,8 @@ class PrefHashFilter : public InterceptablePrefFilter {
// PrefFilter remaining implementation.
void FilterUpdate(const std::string& path) override;
- void FilterSerializeData(base::DictionaryValue* pref_store_contents) override;
+ OnWriteCallbackPair FilterSerializeData(
+ base::DictionaryValue* pref_store_contents) override;
private:
// InterceptablePrefFilter implementation.
@@ -110,6 +120,25 @@ class PrefHashFilter : public InterceptablePrefFilter {
std::unique_ptr<base::DictionaryValue> pref_store_contents,
bool prefs_altered) override;
+ // Helper function to generate FilterSerializeData()'s pre-write and
+ // post-write callbacks. The returned callbacks are thread-safe.
+ OnWriteCallbackPair GetOnWriteSynchronousCallbacks(
+ base::DictionaryValue* pref_store_contents);
+
+ // Clears the MACs contained in |external_validation_hash_store_contents|
+ // which are present in |paths_to_clear|.
+ static void ClearFromExternalStore(
+ HashStoreContents* external_validation_hash_store_contents,
+ const base::DictionaryValue* changed_paths_and_macs);
+
+ // Flushes the MACs contained in |changed_paths_and_mac| to
+ // external_hash_store_contents if |write_success|, otherwise discards the
+ // changes.
+ static void FlushToExternalStore(
+ std::unique_ptr<HashStoreContents> external_hash_store_contents,
+ std::unique_ptr<base::DictionaryValue> changed_paths_and_macs,
+ bool write_success);
+
// Callback to be invoked only once (and subsequently reset) on the next
// FilterOnLoad event. It will be allowed to modify the |prefs| handed to
// FilterOnLoad before handing them back to this PrefHashFilter.
@@ -120,12 +149,18 @@ class PrefHashFilter : public InterceptablePrefFilter {
typedef base::ScopedPtrHashMap<std::string,
std::unique_ptr<TrackedPreference>>
TrackedPreferencesMap;
+
// A map from changed paths to their corresponding TrackedPreferences (which
// aren't owned by this map).
typedef std::map<std::string, const TrackedPreference*> ChangedPathsMap;
std::unique_ptr<PrefHashStore> pref_hash_store_;
+ // A store and contents on which to perform extra validations without
+ // triggering resets.
+ // Will be null if the platform does not support external validation.
+ const base::Optional<StoreContentsPair> external_validation_hash_store_pair_;
+
// Invoked if a reset occurs in a call to FilterOnLoad.
const base::Closure on_reset_on_load_;
diff --git a/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc b/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc
index 97201b5a1e6..1d3afd4b9fc 100644
--- a/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc
+++ b/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc
@@ -18,7 +18,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_samples.h"
#include "base/metrics/statistics_recorder.h"
@@ -157,7 +157,12 @@ class MockPrefHashStore : public PrefHashStore {
// PrefHashStore implementation.
std::unique_ptr<PrefHashStoreTransaction> BeginTransaction(
- std::unique_ptr<HashStoreContents> storage) override;
+ HashStoreContents* storage) override;
+ std::string ComputeMac(const std::string& path,
+ const base::Value* new_value) override;
+ std::unique_ptr<base::DictionaryValue> ComputeSplitMacs(
+ const std::string& path,
+ const base::DictionaryValue* split_values) override;
private:
// A MockPrefHashStoreTransaction is handed to the caller on
@@ -175,6 +180,7 @@ class MockPrefHashStore : public PrefHashStore {
}
// PrefHashStoreTransaction implementation.
+ base::StringPiece GetStoreUMASuffix() const override;
PrefHashStoreTransaction::ValueState CheckValue(
const std::string& path,
const base::Value* value) const override;
@@ -247,12 +253,29 @@ void MockPrefHashStore::SetInvalidKeysResult(
}
std::unique_ptr<PrefHashStoreTransaction> MockPrefHashStore::BeginTransaction(
- std::unique_ptr<HashStoreContents> storage) {
+ HashStoreContents* storage) {
EXPECT_FALSE(transaction_active_);
return std::unique_ptr<PrefHashStoreTransaction>(
new MockPrefHashStoreTransaction(this));
}
+std::string MockPrefHashStore::ComputeMac(const std::string& path,
+ const base::Value* new_value) {
+ return "atomic mac for: " + path;
+};
+
+std::unique_ptr<base::DictionaryValue> MockPrefHashStore::ComputeSplitMacs(
+ const std::string& path,
+ const base::DictionaryValue* split_values) {
+ std::unique_ptr<base::DictionaryValue> macs_dict(new base::DictionaryValue);
+ for (base::DictionaryValue::Iterator it(*split_values); !it.IsAtEnd();
+ it.Advance()) {
+ macs_dict->SetStringWithoutPathExpansion(
+ it.key(), "split mac for: " + path + "/" + it.key());
+ }
+ return macs_dict;
+};
+
PrefHashStoreTransaction::ValueState MockPrefHashStore::RecordCheckValue(
const std::string& path,
const base::Value* value,
@@ -279,6 +302,11 @@ void MockPrefHashStore::RecordStoreHash(
.second);
}
+base::StringPiece
+MockPrefHashStore::MockPrefHashStoreTransaction::GetStoreUMASuffix() const {
+ return "unused";
+}
+
PrefHashStoreTransaction::ValueState
MockPrefHashStore::MockPrefHashStoreTransaction::CheckValue(
const std::string& path,
@@ -359,6 +387,189 @@ std::vector<PrefHashFilter::TrackedPreferenceMetadata> GetConfiguration(
return configuration;
}
+class MockHashStoreContents : public HashStoreContents {
+ public:
+ MockHashStoreContents(){};
+
+ // Returns the number of hashes stored.
+ size_t stored_hashes_count() const { return dictionary_.size(); }
+
+ // Returns the number of paths cleared.
+ size_t cleared_paths_count() const { return removed_entries_.size(); }
+
+ // Returns the stored MAC for an Atomic preference.
+ std::string GetStoredMac(const std::string& path) const;
+ // Returns the stored MAC for a Split preference.
+ std::string GetStoredSplitMac(const std::string& path,
+ const std::string& split_path) const;
+
+ // HashStoreContents implementation.
+ bool IsCopyable() const override;
+ std::unique_ptr<HashStoreContents> MakeCopy() const override;
+ base::StringPiece GetUMASuffix() const override;
+ void Reset() override;
+ bool GetMac(const std::string& path, std::string* out_value) override;
+ bool GetSplitMacs(const std::string& path,
+ std::map<std::string, std::string>* split_macs) override;
+ void SetMac(const std::string& path, const std::string& value) override;
+ void SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) override;
+ void ImportEntry(const std::string& path,
+ const base::Value* in_value) override;
+ bool RemoveEntry(const std::string& path) override;
+ const base::DictionaryValue* GetContents() const override;
+ std::string GetSuperMac() const override;
+ void SetSuperMac(const std::string& super_mac) override;
+
+ private:
+ MockHashStoreContents(MockHashStoreContents* origin_mock);
+
+ // Records calls to this mock's SetMac/SetSplitMac methods.
+ void RecordSetMac(const std::string& path, const std::string& mac) {
+ dictionary_.SetStringWithoutPathExpansion(path, mac);
+ }
+ void RecordSetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& mac) {
+ base::DictionaryValue* mac_dict = nullptr;
+ dictionary_.GetDictionaryWithoutPathExpansion(path, &mac_dict);
+ if (!mac_dict) {
+ mac_dict = new base::DictionaryValue;
+ dictionary_.SetWithoutPathExpansion(path, mac_dict);
+ }
+ mac_dict->SetStringWithoutPathExpansion(split_path, mac);
+ }
+
+ // Records a call to this mock's RemoveEntry method.
+ void RecordRemoveEntry(const std::string& path) {
+ // Don't expect the same pref to be cleared more than once.
+ EXPECT_EQ(removed_entries_.end(), removed_entries_.find(path));
+ removed_entries_.insert(path);
+ }
+
+ base::DictionaryValue dictionary_;
+ std::set<std::string> removed_entries_;
+
+ // The code being tested copies its HashStoreContents for use in a callback
+ // which can be executed during shutdown. To be able to capture the behavior
+ // of the copy, we make it forward calls to the mock it was created from.
+ // Once set, |origin_mock_| must outlive this instance.
+ MockHashStoreContents* origin_mock_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockHashStoreContents);
+};
+
+std::string MockHashStoreContents::GetStoredMac(const std::string& path) const {
+ const base::Value* out_value;
+ if (dictionary_.GetWithoutPathExpansion(path, &out_value)) {
+ const base::StringValue* value_as_string;
+ EXPECT_TRUE(out_value->GetAsString(&value_as_string));
+
+ return value_as_string->GetString();
+ }
+
+ return std::string();
+}
+
+std::string MockHashStoreContents::GetStoredSplitMac(
+ const std::string& path,
+ const std::string& split_path) const {
+ const base::Value* out_value;
+ if (dictionary_.GetWithoutPathExpansion(path, &out_value)) {
+ const base::DictionaryValue* value_as_dict;
+ EXPECT_TRUE(out_value->GetAsDictionary(&value_as_dict));
+
+ if (value_as_dict->GetWithoutPathExpansion(split_path, &out_value)) {
+ const base::StringValue* value_as_string;
+ EXPECT_TRUE(out_value->GetAsString(&value_as_string));
+
+ return value_as_string->GetString();
+ }
+ }
+
+ return std::string();
+}
+
+MockHashStoreContents::MockHashStoreContents(MockHashStoreContents* origin_mock)
+ : origin_mock_(origin_mock) {}
+
+bool MockHashStoreContents::IsCopyable() const {
+ return true;
+}
+
+std::unique_ptr<HashStoreContents> MockHashStoreContents::MakeCopy() const {
+ // Return a new MockHashStoreContents which forwards all requests to this
+ // mock instance.
+ return std::unique_ptr<HashStoreContents>(
+ new MockHashStoreContents(const_cast<MockHashStoreContents*>(this)));
+}
+
+base::StringPiece MockHashStoreContents::GetUMASuffix() const {
+ return "Unused";
+}
+
+void MockHashStoreContents::Reset() {
+ ADD_FAILURE() << "Unexpected call.";
+}
+
+bool MockHashStoreContents::GetMac(const std::string& path,
+ std::string* out_value) {
+ ADD_FAILURE() << "Unexpected call.";
+ return false;
+}
+
+bool MockHashStoreContents::GetSplitMacs(
+ const std::string& path,
+ std::map<std::string, std::string>* split_macs) {
+ ADD_FAILURE() << "Unexpected call.";
+ return false;
+}
+
+void MockHashStoreContents::SetMac(const std::string& path,
+ const std::string& value) {
+ if (origin_mock_)
+ origin_mock_->RecordSetMac(path, value);
+ else
+ RecordSetMac(path, value);
+}
+
+void MockHashStoreContents::SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) {
+ if (origin_mock_)
+ origin_mock_->RecordSetSplitMac(path, split_path, value);
+ else
+ RecordSetSplitMac(path, split_path, value);
+}
+
+void MockHashStoreContents::ImportEntry(const std::string& path,
+ const base::Value* in_value) {
+ ADD_FAILURE() << "Unexpected call.";
+}
+
+bool MockHashStoreContents::RemoveEntry(const std::string& path) {
+ if (origin_mock_)
+ origin_mock_->RecordRemoveEntry(path);
+ else
+ RecordRemoveEntry(path);
+ return true;
+}
+
+const base::DictionaryValue* MockHashStoreContents::GetContents() const {
+ ADD_FAILURE() << "Unexpected call.";
+ return nullptr;
+}
+
+std::string MockHashStoreContents::GetSuperMac() const {
+ ADD_FAILURE() << "Unexpected call.";
+ return std::string();
+}
+
+void MockHashStoreContents::SetSuperMac(const std::string& super_mac) {
+ ADD_FAILURE() << "Unexpected call.";
+}
+
class PrefHashFilterTest
: public testing::TestWithParam<PrefHashFilter::EnforcementLevel> {
public:
@@ -386,9 +597,22 @@ class PrefHashFilterTest
PrefHashFilter::TrackedPreferenceMetadata>& configuration) {
std::unique_ptr<MockPrefHashStore> temp_mock_pref_hash_store(
new MockPrefHashStore);
+ std::unique_ptr<MockPrefHashStore>
+ temp_mock_external_validation_pref_hash_store(new MockPrefHashStore);
+ std::unique_ptr<MockHashStoreContents>
+ temp_mock_external_validation_hash_store_contents(
+ new MockHashStoreContents);
mock_pref_hash_store_ = temp_mock_pref_hash_store.get();
+ mock_external_validation_pref_hash_store_ =
+ temp_mock_external_validation_pref_hash_store.get();
+ mock_external_validation_hash_store_contents_ =
+ temp_mock_external_validation_hash_store_contents.get();
pref_hash_filter_.reset(new PrefHashFilter(
- std::move(temp_mock_pref_hash_store), configuration,
+ std::move(temp_mock_pref_hash_store),
+ PrefHashFilter::StoreContentsPair(
+ std::move(temp_mock_external_validation_pref_hash_store),
+ std::move(temp_mock_external_validation_hash_store_contents)),
+ configuration,
base::Bind(&PrefHashFilterTest::RecordReset, base::Unretained(this)),
&mock_validation_delegate_, arraysize(kTestTrackedPrefs), true));
}
@@ -414,6 +638,8 @@ class PrefHashFilterTest
}
MockPrefHashStore* mock_pref_hash_store_;
+ MockPrefHashStore* mock_external_validation_pref_hash_store_;
+ MockHashStoreContents* mock_external_validation_hash_store_contents_;
std::unique_ptr<base::DictionaryValue> pref_store_contents_;
MockValidationDelegate mock_validation_delegate_;
std::unique_ptr<PrefHashFilter> pref_hash_filter_;
@@ -1035,6 +1261,132 @@ TEST_P(PrefHashFilterTest, DontResetReportOnly) {
}
}
+TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacks) {
+ base::DictionaryValue root_dict;
+ // Ownership of the following values is transfered to |root_dict|.
+ base::Value* int_value1 = new base::FundamentalValue(1);
+ base::Value* int_value2 = new base::FundamentalValue(2);
+ base::DictionaryValue* dict_value = new base::DictionaryValue;
+ dict_value->Set("a", new base::FundamentalValue(true));
+ root_dict.Set(kAtomicPref, int_value1);
+ root_dict.Set(kAtomicPref2, int_value2);
+ root_dict.Set(kSplitPref, dict_value);
+
+ // Skip updating kAtomicPref2.
+ pref_hash_filter_->FilterUpdate(kAtomicPref);
+ pref_hash_filter_->FilterUpdate(kSplitPref);
+
+ PrefHashFilter::OnWriteCallbackPair callbacks =
+ pref_hash_filter_->FilterSerializeData(&root_dict);
+
+ ASSERT_FALSE(callbacks.first.is_null());
+
+ // Prefs should be cleared from the external validation store only once the
+ // before-write callback is run.
+ ASSERT_EQ(
+ 0u, mock_external_validation_hash_store_contents_->cleared_paths_count());
+ callbacks.first.Run();
+ ASSERT_EQ(
+ 2u, mock_external_validation_hash_store_contents_->cleared_paths_count());
+
+ // No pref write should occur before the after-write callback is run.
+ ASSERT_EQ(
+ 0u, mock_external_validation_hash_store_contents_->stored_hashes_count());
+
+ callbacks.second.Run(true);
+
+ ASSERT_EQ(
+ 2u, mock_external_validation_hash_store_contents_->stored_hashes_count());
+ ASSERT_EQ(
+ "atomic mac for: atomic_pref",
+ mock_external_validation_hash_store_contents_->GetStoredMac(kAtomicPref));
+ ASSERT_EQ("split mac for: split_pref/a",
+ mock_external_validation_hash_store_contents_->GetStoredSplitMac(
+ kSplitPref, "a"));
+
+ // The callbacks should write directly to the contents without going through
+ // a pref hash store.
+ ASSERT_EQ(0u,
+ mock_external_validation_pref_hash_store_->stored_paths_count());
+}
+
+TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacksWithFailure) {
+ base::DictionaryValue root_dict;
+ // Ownership of the following values is transfered to |root_dict|.
+ base::Value* int_value1 = new base::FundamentalValue(1);
+ root_dict.Set(kAtomicPref, int_value1);
+
+ // Only update kAtomicPref.
+ pref_hash_filter_->FilterUpdate(kAtomicPref);
+
+ PrefHashFilter::OnWriteCallbackPair callbacks =
+ pref_hash_filter_->FilterSerializeData(&root_dict);
+
+ ASSERT_FALSE(callbacks.first.is_null());
+
+ callbacks.first.Run();
+
+ // The pref should have been cleared from the external validation store.
+ ASSERT_EQ(
+ 1u, mock_external_validation_hash_store_contents_->cleared_paths_count());
+
+ callbacks.second.Run(false);
+
+ // Expect no writes to the external validation hash store contents.
+ ASSERT_EQ(0u,
+ mock_external_validation_pref_hash_store_->stored_paths_count());
+ ASSERT_EQ(
+ 0u, mock_external_validation_hash_store_contents_->stored_hashes_count());
+}
+
+TEST_P(PrefHashFilterTest, ExternalValidationValueChanged) {
+ // Ownership of this value is transfered to |pref_store_contents_|.
+ base::Value* int_value = new base::FundamentalValue(1234);
+ pref_store_contents_->Set(kAtomicPref, int_value);
+
+ base::DictionaryValue* dict_value = new base::DictionaryValue;
+ dict_value->SetString("a", "foo");
+ dict_value->SetInteger("b", 1234);
+ dict_value->SetInteger("c", 56);
+ dict_value->SetBoolean("d", false);
+ pref_store_contents_->Set(kSplitPref, dict_value);
+
+ mock_external_validation_pref_hash_store_->SetCheckResult(
+ kAtomicPref, PrefHashStoreTransaction::CHANGED);
+ mock_external_validation_pref_hash_store_->SetCheckResult(
+ kSplitPref, PrefHashStoreTransaction::CHANGED);
+
+ std::vector<std::string> mock_invalid_keys;
+ mock_invalid_keys.push_back("a");
+ mock_invalid_keys.push_back("c");
+ mock_external_validation_pref_hash_store_->SetInvalidKeysResult(
+ kSplitPref, mock_invalid_keys);
+
+ DoFilterOnLoad(false);
+
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_external_validation_pref_hash_store_->checked_paths_count());
+ ASSERT_EQ(2u,
+ mock_external_validation_pref_hash_store_->stored_paths_count());
+ ASSERT_EQ(
+ 1u, mock_external_validation_pref_hash_store_->transactions_performed());
+
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_.recorded_validations_count());
+
+ // Regular validation should not have any CHANGED prefs.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_.CountValidationsOfState(
+ PrefHashStoreTransaction::UNCHANGED));
+
+ // External validation should have two CHANGED prefs (kAtomic and kSplit).
+ ASSERT_EQ(2u, mock_validation_delegate_.CountExternalValidationsOfState(
+ PrefHashStoreTransaction::CHANGED));
+ ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
+ mock_validation_delegate_.CountExternalValidationsOfState(
+ PrefHashStoreTransaction::UNCHANGED));
+}
+
INSTANTIATE_TEST_CASE_P(PrefHashFilterTestInstance,
PrefHashFilterTest,
testing::Values(PrefHashFilter::NO_ENFORCEMENT,
diff --git a/chromium/components/user_prefs/tracked/pref_hash_store.h b/chromium/components/user_prefs/tracked/pref_hash_store.h
index 2fdc617301a..67808fd3939 100644
--- a/chromium/components/user_prefs/tracked/pref_hash_store.h
+++ b/chromium/components/user_prefs/tracked/pref_hash_store.h
@@ -6,6 +6,10 @@
#define COMPONENTS_PREFS_TRACKED_PREF_HASH_STORE_H_
#include <memory>
+#include <string>
+
+#include "base/values.h"
+#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
class HashStoreContents;
class PrefHashStoreTransaction;
@@ -21,8 +25,24 @@ class PrefHashStore {
// of operations on the hash store. |storage| MAY be used as the backing store
// depending on the implementation. Therefore the HashStoreContents used for
// related transactions should correspond to the same underlying data store.
+ // |storage| must outlive the returned transaction.
virtual std::unique_ptr<PrefHashStoreTransaction> BeginTransaction(
- std::unique_ptr<HashStoreContents> storage) = 0;
+ HashStoreContents* storage) = 0;
+
+ // Computes the MAC to be associated with |path| and |value| in this store.
+ // PrefHashStoreTransaction typically uses this internally but it's also
+ // exposed for users that want to compute MACs ahead of time for asynchronous
+ // operations.
+ virtual std::string ComputeMac(const std::string& path,
+ const base::Value* value) = 0;
+
+ // Computes the MAC to be associated with |path| and |split_values| in this
+ // store. PrefHashStoreTransaction typically uses this internally but it's
+ // also exposed for users that want to compute MACs ahead of time for
+ // asynchronous operations.
+ virtual std::unique_ptr<base::DictionaryValue> ComputeSplitMacs(
+ const std::string& path,
+ const base::DictionaryValue* split_values) = 0;
};
#endif // COMPONENTS_PREFS_TRACKED_PREF_HASH_STORE_H_
diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc b/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc
index c756d6f28f7..80438d6954a 100644
--- a/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc
+++ b/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc
@@ -10,9 +10,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram.h"
-#include "base/values.h"
#include "components/user_prefs/tracked/hash_store_contents.h"
-#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
class PrefHashStoreImpl::PrefHashStoreTransactionImpl
: public PrefHashStoreTransaction {
@@ -20,10 +18,11 @@ class PrefHashStoreImpl::PrefHashStoreTransactionImpl
// Constructs a PrefHashStoreTransactionImpl which can use the private
// members of its |outer| PrefHashStoreImpl.
PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer,
- std::unique_ptr<HashStoreContents> storage);
+ HashStoreContents* storage);
~PrefHashStoreTransactionImpl() override;
// PrefHashStoreTransaction implementation.
+ base::StringPiece GetStoreUMASuffix() const override;
ValueState CheckValue(const std::string& path,
const base::Value* value) const override;
void StoreHash(const std::string& path, const base::Value* value) override;
@@ -40,23 +39,8 @@ class PrefHashStoreImpl::PrefHashStoreTransactionImpl
bool StampSuperMac() override;
private:
- bool GetSplitMacs(const std::string& path,
- std::map<std::string, std::string>* split_macs) const;
-
- HashStoreContents* contents() {
- return outer_->legacy_hash_store_contents_
- ? outer_->legacy_hash_store_contents_.get()
- : contents_.get();
- }
-
- const HashStoreContents* contents() const {
- return outer_->legacy_hash_store_contents_
- ? outer_->legacy_hash_store_contents_.get()
- : contents_.get();
- }
-
PrefHashStoreImpl* outer_;
- std::unique_ptr<HashStoreContents> contents_;
+ HashStoreContents* contents_;
bool super_mac_valid_;
bool super_mac_dirty_;
@@ -73,20 +57,44 @@ PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed,
PrefHashStoreImpl::~PrefHashStoreImpl() {
}
-void PrefHashStoreImpl::set_legacy_hash_store_contents(
- std::unique_ptr<HashStoreContents> legacy_hash_store_contents) {
- legacy_hash_store_contents_ = std::move(legacy_hash_store_contents);
-}
-
std::unique_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction(
- std::unique_ptr<HashStoreContents> storage) {
+ HashStoreContents* storage) {
return std::unique_ptr<PrefHashStoreTransaction>(
new PrefHashStoreTransactionImpl(this, std::move(storage)));
}
+std::string PrefHashStoreImpl::ComputeMac(const std::string& path,
+ const base::Value* value) {
+ return pref_hash_calculator_.Calculate(path, value);
+}
+
+std::unique_ptr<base::DictionaryValue> PrefHashStoreImpl::ComputeSplitMacs(
+ const std::string& path,
+ const base::DictionaryValue* split_values) {
+ DCHECK(split_values);
+
+ std::string keyed_path(path);
+ keyed_path.push_back('.');
+ const size_t common_part_length = keyed_path.length();
+
+ std::unique_ptr<base::DictionaryValue> split_macs(new base::DictionaryValue);
+
+ for (base::DictionaryValue::Iterator it(*split_values); !it.IsAtEnd();
+ it.Advance()) {
+ // Keep the common part from the old |keyed_path| and replace the key to
+ // get the new |keyed_path|.
+ keyed_path.replace(common_part_length, std::string::npos, it.key());
+
+ split_macs->SetStringWithoutPathExpansion(
+ it.key(), ComputeMac(keyed_path, &it.value()));
+ }
+
+ return split_macs;
+}
+
PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl(
PrefHashStoreImpl* outer,
- std::unique_ptr<HashStoreContents> storage)
+ HashStoreContents* storage)
: outer_(outer),
contents_(std::move(storage)),
super_mac_valid_(false),
@@ -94,40 +102,36 @@ PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl(
if (!outer_->use_super_mac_)
return;
- // The store must be initialized and have a valid super MAC to be trusted.
-
- const base::DictionaryValue* store_contents = contents()->GetContents();
- if (!store_contents)
- return;
-
- std::string super_mac = contents()->GetSuperMac();
+ // The store must have a valid super MAC to be trusted.
+ std::string super_mac = contents_->GetSuperMac();
if (super_mac.empty())
return;
- super_mac_valid_ = outer_->pref_hash_calculator_.Validate(
- contents()->hash_store_id(), store_contents,
- super_mac) == PrefHashCalculator::VALID;
+ super_mac_valid_ =
+ outer_->pref_hash_calculator_.Validate(
+ "", contents_->GetContents(), super_mac) == PrefHashCalculator::VALID;
}
PrefHashStoreImpl::PrefHashStoreTransactionImpl::
~PrefHashStoreTransactionImpl() {
if (super_mac_dirty_ && outer_->use_super_mac_) {
// Get the dictionary of hashes (or NULL if it doesn't exist).
- const base::DictionaryValue* hashes_dict = contents()->GetContents();
- contents()->SetSuperMac(outer_->pref_hash_calculator_.Calculate(
- contents()->hash_store_id(), hashes_dict));
+ const base::DictionaryValue* hashes_dict = contents_->GetContents();
+ contents_->SetSuperMac(outer_->ComputeMac("", hashes_dict));
}
}
+base::StringPiece
+PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetStoreUMASuffix() const {
+ return contents_->GetUMASuffix();
+}
+
PrefHashStoreTransaction::ValueState
PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue(
const std::string& path,
const base::Value* initial_value) const {
- const base::DictionaryValue* hashes_dict = contents()->GetContents();
-
std::string last_hash;
- if (hashes_dict)
- hashes_dict->GetString(path, &last_hash);
+ contents_->GetMac(path, &last_hash);
if (last_hash.empty()) {
// In the absence of a hash for this pref, always trust a NULL value, but
@@ -158,9 +162,8 @@ PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue(
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash(
const std::string& path,
const base::Value* new_value) {
- const std::string mac =
- outer_->pref_hash_calculator_.Calculate(path, new_value);
- (*contents()->GetMutableContents())->SetString(path, mac);
+ const std::string mac = outer_->ComputeMac(path, new_value);
+ contents_->SetMac(path, mac);
super_mac_dirty_ = true;
}
@@ -172,7 +175,7 @@ PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue(
DCHECK(invalid_keys && invalid_keys->empty());
std::map<std::string, std::string> split_macs;
- const bool has_hashes = GetSplitMacs(path, &split_macs);
+ const bool has_hashes = contents_->GetSplitMacs(path, &split_macs);
// Treat NULL and empty the same; otherwise we would need to store a hash for
// the entire dictionary (or some other special beacon) to differentiate these
@@ -232,53 +235,30 @@ PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue(
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash(
const std::string& path,
const base::DictionaryValue* split_value) {
- std::unique_ptr<HashStoreContents::MutableDictionary> mutable_dictionary =
- contents()->GetMutableContents();
- (*mutable_dictionary)->Remove(path, NULL);
+ contents_->RemoveEntry(path);
if (split_value) {
- std::string keyed_path(path);
- keyed_path.push_back('.');
- const size_t common_part_length = keyed_path.length();
- for (base::DictionaryValue::Iterator it(*split_value); !it.IsAtEnd();
- it.Advance()) {
- // Keep the common part from the old |keyed_path| and replace the key to
- // get the new |keyed_path|.
- keyed_path.replace(common_part_length, std::string::npos, it.key());
- (*mutable_dictionary)
- ->SetString(keyed_path, outer_->pref_hash_calculator_.Calculate(
- keyed_path, &it.value()));
- }
- }
- super_mac_dirty_ = true;
-}
+ std::unique_ptr<base::DictionaryValue> split_macs =
+ outer_->ComputeSplitMacs(path, split_value);
-bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetSplitMacs(
- const std::string& key,
- std::map<std::string, std::string>* split_macs) const {
- DCHECK(split_macs);
- DCHECK(split_macs->empty());
+ for (base::DictionaryValue::Iterator it(*split_macs); !it.IsAtEnd();
+ it.Advance()) {
+ const base::StringValue* value_as_string;
+ bool is_string = it.value().GetAsString(&value_as_string);
+ DCHECK(is_string);
- const base::DictionaryValue* hashes_dict = contents()->GetContents();
- const base::DictionaryValue* split_mac_dictionary = NULL;
- if (!hashes_dict || !hashes_dict->GetDictionary(key, &split_mac_dictionary))
- return false;
- for (base::DictionaryValue::Iterator it(*split_mac_dictionary); !it.IsAtEnd();
- it.Advance()) {
- std::string mac_string;
- if (!it.value().GetAsString(&mac_string)) {
- NOTREACHED();
- continue;
+ contents_->SetSplitMac(path, it.key(), value_as_string->GetString());
}
- split_macs->insert(make_pair(it.key(), mac_string));
}
- return true;
+ super_mac_dirty_ = true;
}
bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::HasHash(
const std::string& path) const {
- const base::DictionaryValue* hashes_dict = contents()->GetContents();
- return hashes_dict && hashes_dict->Get(path, NULL);
+ std::string out_value;
+ std::map<std::string, std::string> out_values;
+ return contents_->GetMac(path, &out_value) ||
+ contents_->GetSplitMacs(path, &out_values);
}
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash(
@@ -286,7 +266,7 @@ void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash(
const base::Value* hash) {
DCHECK(hash);
- (*contents()->GetMutableContents())->Set(path, hash->DeepCopy());
+ contents_->ImportEntry(path, hash);
if (super_mac_valid_)
super_mac_dirty_ = true;
@@ -294,8 +274,7 @@ void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash(
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearHash(
const std::string& path) {
- if ((*contents()->GetMutableContents())->RemovePath(path, NULL) &&
- super_mac_valid_) {
+ if (contents_->RemoveEntry(path) && super_mac_valid_) {
super_mac_dirty_ = true;
}
}
diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_impl.h b/chromium/components/user_prefs/tracked/pref_hash_store_impl.h
index 254d8f3f89f..1b5682eed4e 100644
--- a/chromium/components/user_prefs/tracked/pref_hash_store_impl.h
+++ b/chromium/components/user_prefs/tracked/pref_hash_store_impl.h
@@ -5,17 +5,11 @@
#ifndef COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_STORE_IMPL_H_
#define COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_STORE_IMPL_H_
-#include <memory>
-#include <string>
-
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "components/user_prefs/tracked/pref_hash_calculator.h"
#include "components/user_prefs/tracked/pref_hash_store.h"
-class HashStoreContents;
-class PrefHashStoreTransaction;
-
// Implements PrefHashStoreImpl by storing preference hashes in a
// HashStoreContents.
class PrefHashStoreImpl : public PrefHashStore {
@@ -41,24 +35,24 @@ class PrefHashStoreImpl : public PrefHashStore {
~PrefHashStoreImpl() override;
- // Provides an external HashStoreContents implementation to be used.
- // BeginTransaction() will ignore |storage| if this is provided.
- void set_legacy_hash_store_contents(
- std::unique_ptr<HashStoreContents> legacy_hash_store_contents);
-
// Clears the contents of this PrefHashStore. |IsInitialized()| will return
// false after this call.
void Reset();
// PrefHashStore implementation.
std::unique_ptr<PrefHashStoreTransaction> BeginTransaction(
- std::unique_ptr<HashStoreContents> storage) override;
+ HashStoreContents* storage) override;
+
+ std::string ComputeMac(const std::string& path,
+ const base::Value* new_value) override;
+ std::unique_ptr<base::DictionaryValue> ComputeSplitMacs(
+ const std::string& path,
+ const base::DictionaryValue* split_values) override;
private:
class PrefHashStoreTransactionImpl;
const PrefHashCalculator pref_hash_calculator_;
- std::unique_ptr<HashStoreContents> legacy_hash_store_contents_;
bool use_super_mac_;
DISALLOW_COPY_AND_ASSIGN(PrefHashStoreImpl);
diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc b/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc
index 10867e66d45..f5d92182a53 100644
--- a/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc
+++ b/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc
@@ -15,16 +15,60 @@
#include "testing/gtest/include/gtest/gtest.h"
class PrefHashStoreImplTest : public testing::Test {
+ public:
+ PrefHashStoreImplTest() : contents_(&pref_store_contents_) {}
+
protected:
- std::unique_ptr<HashStoreContents> CreateHashStoreContents() {
- return std::unique_ptr<HashStoreContents>(
- new DictionaryHashStoreContents(&pref_store_contents_));
- }
+ HashStoreContents* GetHashStoreContents() { return &contents_; }
private:
base::DictionaryValue pref_store_contents_;
+ // Must be declared after |pref_store_contents_| as it needs to be outlived
+ // by it.
+ DictionaryHashStoreContents contents_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefHashStoreImplTest);
};
+TEST_F(PrefHashStoreImplTest, ComputeMac) {
+ base::StringValue string_1("string1");
+ base::StringValue string_2("string2");
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+
+ std::string computed_mac_1 = pref_hash_store.ComputeMac("path1", &string_1);
+ std::string computed_mac_2 = pref_hash_store.ComputeMac("path1", &string_2);
+ std::string computed_mac_3 = pref_hash_store.ComputeMac("path2", &string_1);
+
+ // Quick sanity checks here, see pref_hash_calculator_unittest.cc for more
+ // complete tests.
+ EXPECT_EQ(computed_mac_1, pref_hash_store.ComputeMac("path1", &string_1));
+ EXPECT_NE(computed_mac_1, computed_mac_2);
+ EXPECT_NE(computed_mac_1, computed_mac_3);
+ EXPECT_EQ(64U, computed_mac_1.size());
+}
+
+TEST_F(PrefHashStoreImplTest, ComputeSplitMacs) {
+ base::DictionaryValue dict;
+ dict.Set("a", new base::StringValue("string1"));
+ dict.Set("b", new base::StringValue("string2"));
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+
+ std::unique_ptr<base::DictionaryValue> computed_macs =
+ pref_hash_store.ComputeSplitMacs("foo.bar", &dict);
+
+ std::string mac_1;
+ std::string mac_2;
+ ASSERT_TRUE(computed_macs->GetString("a", &mac_1));
+ ASSERT_TRUE(computed_macs->GetString("b", &mac_2));
+
+ EXPECT_EQ(2U, computed_macs->size());
+
+ base::StringValue string_1("string1");
+ base::StringValue string_2("string2");
+ EXPECT_EQ(pref_hash_store.ComputeMac("foo.bar.a", &string_1), mac_1);
+ EXPECT_EQ(pref_hash_store.ComputeMac("foo.bar.b", &string_2), mac_2);
+}
+
TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
base::StringValue string_1("string1");
base::StringValue string_2("string2");
@@ -33,7 +77,7 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
// 32 NULL bytes is the seed that was used to generate the legacy hash.
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
// Only NULL should be trusted in the absence of a hash.
EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
@@ -63,14 +107,14 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
transaction->CheckValue("path1", &dict));
}
- ASSERT_FALSE(CreateHashStoreContents()->GetSuperMac().empty());
+ ASSERT_FALSE(GetHashStoreContents()->GetSuperMac().empty());
{
// |pref_hash_store2| should trust its initial hashes dictionary and thus
// trust new unknown values.
PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store2.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store2.BeginTransaction(GetHashStoreContents()));
EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
transaction->CheckValue("new_path", &string_1));
EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
@@ -80,14 +124,14 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
}
// Manually corrupt the super MAC.
- CreateHashStoreContents()->SetSuperMac(std::string(64, 'A'));
+ GetHashStoreContents()->SetSuperMac(std::string(64, 'A'));
{
// |pref_hash_store3| should no longer trust its initial hashes dictionary
// and thus shouldn't trust non-NULL unknown values.
PrefHashStoreImpl pref_hash_store3(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store3.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store3.BeginTransaction(GetHashStoreContents()));
EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
transaction->CheckValue("new_path", &string_1));
EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
@@ -105,7 +149,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
ASSERT_FALSE(transaction->IsSuperMACValid());
ASSERT_FALSE(transaction->HasHash("path1"));
@@ -122,7 +166,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
// Make a copy of the stored hash for future use.
const base::Value* hash = NULL;
- ASSERT_TRUE(CreateHashStoreContents()->GetContents()->Get("path1", &hash));
+ ASSERT_TRUE(GetHashStoreContents()->GetContents()->Get("path1", &hash));
std::unique_ptr<base::Value> path_1_string_1_hash_copy(hash->DeepCopy());
hash = NULL;
@@ -130,7 +174,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
ASSERT_TRUE(transaction->IsSuperMACValid());
ASSERT_TRUE(transaction->HasHash("path1"));
@@ -149,18 +193,18 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
ASSERT_TRUE(transaction->IsSuperMACValid());
ASSERT_FALSE(transaction->HasHash("path1"));
}
// Invalidate the super MAC.
- CreateHashStoreContents()->SetSuperMac(std::string());
+ GetHashStoreContents()->SetSuperMac(std::string());
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
ASSERT_FALSE(transaction->IsSuperMACValid());
ASSERT_FALSE(transaction->HasHash("path1"));
@@ -178,7 +222,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
ASSERT_FALSE(transaction->IsSuperMACValid());
ASSERT_TRUE(transaction->HasHash("path1"));
EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
@@ -196,7 +240,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
ASSERT_FALSE(transaction->IsSuperMACValid());
// Test StampSuperMac.
@@ -207,7 +251,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
ASSERT_TRUE(transaction->IsSuperMACValid());
// Store the hash of a different value to test an "over-import".
@@ -221,7 +265,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
ASSERT_TRUE(transaction->IsSuperMACValid());
// "Over-import". An import should preserve validity.
@@ -236,7 +280,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
ASSERT_TRUE(transaction->IsSuperMACValid());
EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
transaction->CheckValue("path1", &string_1));
@@ -253,19 +297,19 @@ TEST_F(PrefHashStoreImplTest, SuperMACDisabled) {
// Pass |use_super_mac| => false.
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", false);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
transaction->StoreHash("path1", &string_2);
EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
transaction->CheckValue("path1", &string_2));
}
- ASSERT_TRUE(CreateHashStoreContents()->GetSuperMac().empty());
+ ASSERT_TRUE(GetHashStoreContents()->GetSuperMac().empty());
{
PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", false);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store2.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store2.BeginTransaction(GetHashStoreContents()));
EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
transaction->CheckValue("new_path", &string_1));
}
@@ -289,7 +333,7 @@ TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
// No hashes stored yet and hashes dictionary is empty (and thus not
// trusted).
@@ -359,21 +403,21 @@ TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
// trust new unknown values.
PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store2.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store2.BeginTransaction(GetHashStoreContents()));
EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
EXPECT_TRUE(invalid_keys.empty());
}
// Manually corrupt the super MAC.
- CreateHashStoreContents()->SetSuperMac(std::string(64, 'A'));
+ GetHashStoreContents()->SetSuperMac(std::string(64, 'A'));
{
// |pref_hash_store3| should no longer trust its initial hashes dictionary
// and thus shouldn't trust unknown values.
PrefHashStoreImpl pref_hash_store3(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store3.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store3.BeginTransaction(GetHashStoreContents()));
EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE,
transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
EXPECT_TRUE(invalid_keys.empty());
@@ -388,7 +432,7 @@ TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
// Store hashes for a random dict to be overwritten below.
base::DictionaryValue initial_dict;
@@ -424,7 +468,7 @@ TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
// update the stored hash of hashes).
PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store2.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store2.BeginTransaction(GetHashStoreContents()));
base::DictionaryValue tested_dict;
tested_dict.Set("a", new base::StringValue("foo"));
@@ -454,7 +498,7 @@ TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) {
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
transaction->StoreHash("path1", &string);
EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED,
@@ -465,7 +509,7 @@ TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) {
// Load a new |pref_hash_store2| in which the hashes dictionary is trusted.
PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- pref_hash_store2.BeginTransaction(CreateHashStoreContents()));
+ pref_hash_store2.BeginTransaction(GetHashStoreContents()));
std::vector<std::string> invalid_keys;
EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE,
transaction->CheckSplitValue("path1", &dict, &invalid_keys));
diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h b/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h
index b8e2cf75e75..55d99d2d03f 100644
--- a/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h
+++ b/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h
@@ -8,6 +8,8 @@
#include <string>
#include <vector>
+#include "base/strings/string_piece.h"
+
namespace base {
class DictionaryValue;
class Value;
@@ -36,11 +38,17 @@ class PrefHashStoreTransaction {
TRUSTED_UNKNOWN_VALUE,
// NULL values are inherently trusted.
TRUSTED_NULL_VALUE,
+ // This transaction's store type is not supported.
+ UNSUPPORTED,
};
// Finalizes any remaining work after the transaction has been performed.
virtual ~PrefHashStoreTransaction() {}
+ // Returns the suffix to be appended to UMA histograms for the store contained
+ // in this transaction.
+ virtual base::StringPiece GetStoreUMASuffix() const = 0;
+
// Checks |initial_value| against the existing stored value hash.
virtual ValueState CheckValue(const std::string& path,
const base::Value* initial_value) const = 0;
diff --git a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.cc b/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.cc
deleted file mode 100644
index d175541281f..00000000000
--- a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.cc
+++ /dev/null
@@ -1,146 +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 "components/user_prefs/tracked/pref_service_hash_store_contents.h"
-
-#include "base/values.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/scoped_user_pref_update.h"
-
-namespace {
-
-// Implements get-or-create of a dictionary value and holds a
-// DictionaryPrefUpdate.
-class PrefServiceMutableDictionary
- : public HashStoreContents::MutableDictionary {
- public:
- // Creates an instance that provides mutable access to a dictionary value
- // named |key| that is a child of |kProfilePreferenceHashes| in
- // |prefs|.
- PrefServiceMutableDictionary(const std::string& key,
- PrefService* pref_service);
-
- // HashStoreContents::MutableDictionary implementation
- base::DictionaryValue* operator->() override;
-
- private:
- const std::string key_;
- DictionaryPrefUpdate update_;
-};
-
-PrefServiceMutableDictionary::PrefServiceMutableDictionary(
- const std::string& key,
- PrefService* pref_service)
- : key_(key),
- update_(pref_service,
- PrefServiceHashStoreContents::kProfilePreferenceHashes) {
- DCHECK(!key_.empty());
-}
-
-base::DictionaryValue* PrefServiceMutableDictionary::operator->() {
- base::DictionaryValue* dictionary = NULL;
- if (!update_->GetDictionaryWithoutPathExpansion(key_, &dictionary)) {
- dictionary = new base::DictionaryValue;
- update_->SetWithoutPathExpansion(key_, dictionary);
- }
- return dictionary;
-}
-
-} // namespace
-
-// static
-const char PrefServiceHashStoreContents::kProfilePreferenceHashes[] =
- "profile.preference_hashes";
-
-// static
-const char PrefServiceHashStoreContents::kHashOfHashesDict[] = "hash_of_hashes";
-
-// static
-const char PrefServiceHashStoreContents::kStoreVersionsDict[] =
- "store_versions";
-
-PrefServiceHashStoreContents::PrefServiceHashStoreContents(
- const std::string& hash_store_id,
- PrefService* pref_service)
- : hash_store_id_(hash_store_id), pref_service_(pref_service) {
- // TODO(erikwright): Remove in M40+.
- DictionaryPrefUpdate update(pref_service_, kProfilePreferenceHashes);
- update->RemovePath(kStoreVersionsDict, NULL);
-}
-
-// static
-void PrefServiceHashStoreContents::RegisterPrefs(PrefRegistrySimple* registry) {
- // Register the top level dictionary to map profile names to dictionaries of
- // tracked preferences.
- registry->RegisterDictionaryPref(kProfilePreferenceHashes);
-}
-
-// static
-void PrefServiceHashStoreContents::ResetAllPrefHashStores(
- PrefService* pref_service) {
- pref_service->ClearPref(kProfilePreferenceHashes);
-}
-
-std::string PrefServiceHashStoreContents::hash_store_id() const {
- return hash_store_id_;
-}
-
-void PrefServiceHashStoreContents::Reset() {
- DictionaryPrefUpdate update(pref_service_, kProfilePreferenceHashes);
-
- update->RemoveWithoutPathExpansion(hash_store_id_, NULL);
-
- // Remove this store's entry in the kHashOfHashesDict.
- base::DictionaryValue* hash_of_hashes_dict;
- if (update->GetDictionaryWithoutPathExpansion(kHashOfHashesDict,
- &hash_of_hashes_dict)) {
- hash_of_hashes_dict->RemoveWithoutPathExpansion(hash_store_id_, NULL);
- if (hash_of_hashes_dict->empty())
- update->RemovePath(kHashOfHashesDict, NULL);
- }
-
- if (update->empty())
- pref_service_->ClearPref(kProfilePreferenceHashes);
-}
-
-bool PrefServiceHashStoreContents::IsInitialized() const {
- const base::DictionaryValue* pref_hash_dicts =
- pref_service_->GetDictionary(kProfilePreferenceHashes);
- return pref_hash_dicts->GetDictionaryWithoutPathExpansion(hash_store_id_,
- NULL);
-}
-
-const base::DictionaryValue* PrefServiceHashStoreContents::GetContents() const {
- const base::DictionaryValue* pref_hash_dicts =
- pref_service_->GetDictionary(kProfilePreferenceHashes);
- const base::DictionaryValue* hashes_dict = NULL;
- pref_hash_dicts->GetDictionaryWithoutPathExpansion(hash_store_id_,
- &hashes_dict);
- return hashes_dict;
-}
-
-std::unique_ptr<HashStoreContents::MutableDictionary>
-PrefServiceHashStoreContents::GetMutableContents() {
- return std::unique_ptr<HashStoreContents::MutableDictionary>(
- new PrefServiceMutableDictionary(hash_store_id_, pref_service_));
-}
-
-std::string PrefServiceHashStoreContents::GetSuperMac() const {
- const base::DictionaryValue* pref_hash_dicts =
- pref_service_->GetDictionary(kProfilePreferenceHashes);
- const base::DictionaryValue* hash_of_hashes_dict = NULL;
- std::string hash_of_hashes;
- if (pref_hash_dicts->GetDictionaryWithoutPathExpansion(
- kHashOfHashesDict, &hash_of_hashes_dict)) {
- hash_of_hashes_dict->GetStringWithoutPathExpansion(hash_store_id_,
- &hash_of_hashes);
- }
- return hash_of_hashes;
-}
-
-void PrefServiceHashStoreContents::SetSuperMac(const std::string& super_mac) {
- PrefServiceMutableDictionary(kHashOfHashesDict, pref_service_)
- ->SetStringWithoutPathExpansion(hash_store_id_, super_mac);
-}
diff --git a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.h b/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.h
deleted file mode 100644
index 05417d81c8e..00000000000
--- a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.h
+++ /dev/null
@@ -1,72 +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 COMPONENTS_USER_PREFS_TRACKED_PREF_SERVICE_HASH_STORE_CONTENTS_H_
-#define COMPONENTS_USER_PREFS_TRACKED_PREF_SERVICE_HASH_STORE_CONTENTS_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "components/user_prefs/tracked/hash_store_contents.h"
-
-class PrefRegistrySimple;
-class PrefService;
-
-// Implements HashStoreContents by storing hashes in a PrefService. Multiple
-// separate hash stores may coexist in the PrefService by using distinct hash
-// store IDs.
-// TODO(erikwright): This class is only used to recreate preference state as in
-// M35, to test migration behaviour. Remove this class when
-// ProfilePrefStoreManagerTest no longer depends on it.
-class PrefServiceHashStoreContents : public HashStoreContents {
- public:
- // Constructs a HashStoreContents that stores hashes in |pref_service|.
- // Multiple hash stores can use the same |pref_service| with distinct
- // |hash_store_id|s.
- //
- // |pref_service| must have previously been configured using |RegisterPrefs|.
- PrefServiceHashStoreContents(const std::string& hash_store_id,
- PrefService* pref_service);
-
- // A dictionary pref which maps profile names to dictionary values which hold
- // hashes of profile prefs that we track to detect changes that happen outside
- // of Chrome.
- static const char kProfilePreferenceHashes[];
-
- // The name of a dict that is stored as a child of
- // |prefs::kProfilePreferenceHashes|. Each child node is a string whose name
- // is a hash store ID and whose value is the super MAC for the corresponding
- // hash store.
- static const char kHashOfHashesDict[];
-
- // The name of a dict that is stored as a child of
- // |prefs::kProfilePreferenceHashes|. Each child node is a number whose name
- // is a hash store ID and whose value is the version of the corresponding
- // hash store.
- static const char kStoreVersionsDict[];
-
- // Registers required preferences.
- static void RegisterPrefs(PrefRegistrySimple* registry);
-
- // Deletes stored hashes for all profiles from |pref_service|.
- static void ResetAllPrefHashStores(PrefService* pref_service);
-
- // HashStoreContents implementation
- std::string hash_store_id() const override;
- void Reset() override;
- bool IsInitialized() const override;
- const base::DictionaryValue* GetContents() const override;
- std::unique_ptr<MutableDictionary> GetMutableContents() override;
- std::string GetSuperMac() const override;
- void SetSuperMac(const std::string& super_mac) override;
-
- private:
- const std::string hash_store_id_;
- PrefService* pref_service_;
-
- DISALLOW_COPY_AND_ASSIGN(PrefServiceHashStoreContents);
-};
-
-#endif // COMPONENTS_PREFS_TRACKED_PREF_SERVICE_HASH_STORE_CONTENTS_H_
diff --git a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents_unittest.cc b/chromium/components/user_prefs/tracked/pref_service_hash_store_contents_unittest.cc
deleted file mode 100644
index 3cfb10542af..00000000000
--- a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents_unittest.cc
+++ /dev/null
@@ -1,152 +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 "components/user_prefs/tracked/pref_service_hash_store_contents.h"
-
-#include <string>
-
-#include "base/values.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class PrefServiceHashStoreContentsTest : public testing::Test {
- public:
- void SetUp() override {
- PrefServiceHashStoreContents::RegisterPrefs(local_state_.registry());
- }
-
- protected:
- TestingPrefServiceSimple local_state_;
-};
-
-TEST_F(PrefServiceHashStoreContentsTest, hash_store_id) {
- PrefServiceHashStoreContents contents("store_id", &local_state_);
- ASSERT_EQ("store_id", contents.hash_store_id());
-}
-
-TEST_F(PrefServiceHashStoreContentsTest, IsInitialized) {
- {
- PrefServiceHashStoreContents contents("store_id", &local_state_);
- ASSERT_FALSE(contents.IsInitialized());
- (*contents.GetMutableContents())->Set("foo", new base::StringValue("bar"));
- ASSERT_TRUE(contents.IsInitialized());
- }
- {
- PrefServiceHashStoreContents contents("store_id", &local_state_);
- ASSERT_TRUE(contents.IsInitialized());
- PrefServiceHashStoreContents other_contents("other_store_id",
- &local_state_);
- ASSERT_FALSE(other_contents.IsInitialized());
- }
-}
-
-TEST_F(PrefServiceHashStoreContentsTest, Reset) {
- ASSERT_FALSE(local_state_.GetUserPrefValue(
- PrefServiceHashStoreContents::kProfilePreferenceHashes));
-
- {
- PrefServiceHashStoreContents contents("store_id", &local_state_);
- ASSERT_FALSE(contents.IsInitialized());
- (*contents.GetMutableContents())->Set("foo", new base::StringValue("bar"));
- ASSERT_TRUE(contents.IsInitialized());
- PrefServiceHashStoreContents other_contents("other_store_id",
- &local_state_);
- (*other_contents.GetMutableContents())
- ->Set("foo", new base::StringValue("bar"));
- }
-
- ASSERT_TRUE(local_state_.GetUserPrefValue(
- PrefServiceHashStoreContents::kProfilePreferenceHashes));
-
- {
- PrefServiceHashStoreContents contents("store_id", &local_state_);
- ASSERT_TRUE(contents.IsInitialized());
- contents.Reset();
- ASSERT_FALSE(contents.IsInitialized());
- }
-
- ASSERT_TRUE(local_state_.GetUserPrefValue(
- PrefServiceHashStoreContents::kProfilePreferenceHashes));
-
- {
- PrefServiceHashStoreContents contents("store_id", &local_state_);
- ASSERT_FALSE(contents.IsInitialized());
- PrefServiceHashStoreContents other_contents("other_store_id",
- &local_state_);
- ASSERT_TRUE(other_contents.IsInitialized());
- }
-
- {
- PrefServiceHashStoreContents other_contents("other_store_id",
- &local_state_);
- other_contents.Reset();
- }
-
- ASSERT_FALSE(local_state_.GetUserPrefValue(
- PrefServiceHashStoreContents::kProfilePreferenceHashes));
-}
-
-TEST_F(PrefServiceHashStoreContentsTest, GetAndSetContents) {
- {
- PrefServiceHashStoreContents contents("store_id", &local_state_);
- ASSERT_EQ(NULL, contents.GetContents());
- (*contents.GetMutableContents())->Set("foo", new base::StringValue("bar"));
- ASSERT_FALSE(contents.GetContents() == NULL);
- std::string actual_value;
- ASSERT_TRUE(contents.GetContents()->GetString("foo", &actual_value));
- ASSERT_EQ("bar", actual_value);
- PrefServiceHashStoreContents other_contents("other_store_id",
- &local_state_);
- ASSERT_EQ(NULL, other_contents.GetContents());
- }
- {
- PrefServiceHashStoreContents contents("store_id", &local_state_);
- ASSERT_FALSE(contents.GetContents() == NULL);
- }
-}
-
-TEST_F(PrefServiceHashStoreContentsTest, GetAndSetSuperMac) {
- {
- PrefServiceHashStoreContents contents("store_id", &local_state_);
- ASSERT_TRUE(contents.GetSuperMac().empty());
- (*contents.GetMutableContents())->Set("foo", new base::StringValue("bar"));
- ASSERT_TRUE(contents.GetSuperMac().empty());
- contents.SetSuperMac("0123456789");
- ASSERT_EQ("0123456789", contents.GetSuperMac());
- }
- {
- PrefServiceHashStoreContents contents("store_id", &local_state_);
- ASSERT_EQ("0123456789", contents.GetSuperMac());
- PrefServiceHashStoreContents other_contents("other_store_id",
- &local_state_);
- ASSERT_TRUE(other_contents.GetSuperMac().empty());
- }
-}
-
-TEST_F(PrefServiceHashStoreContentsTest, ResetAllPrefHashStores) {
- {
- PrefServiceHashStoreContents contents_1("store_id_1", &local_state_);
- PrefServiceHashStoreContents contents_2("store_id_2", &local_state_);
- (*contents_1.GetMutableContents())
- ->Set("foo", new base::StringValue("bar"));
- (*contents_2.GetMutableContents())
- ->Set("foo", new base::StringValue("bar"));
- }
- {
- PrefServiceHashStoreContents contents_1("store_id_1", &local_state_);
- PrefServiceHashStoreContents contents_2("store_id_2", &local_state_);
- ASSERT_TRUE(contents_1.IsInitialized());
- ASSERT_TRUE(contents_2.IsInitialized());
- }
-
- PrefServiceHashStoreContents::ResetAllPrefHashStores(&local_state_);
-
- {
- PrefServiceHashStoreContents contents_1("store_id_1", &local_state_);
- PrefServiceHashStoreContents contents_2("store_id_2", &local_state_);
- ASSERT_FALSE(contents_1.IsInitialized());
- ASSERT_FALSE(contents_2.IsInitialized());
- }
-}
diff --git a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc
new file mode 100644
index 00000000000..03d789839c5
--- /dev/null
+++ b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/user_prefs/tracked/registry_hash_store_contents_win.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "base/win/registry.h"
+#include "components/user_prefs/tracked/tracked_preference_histogram_names.h"
+
+using base::win::RegistryValueIterator;
+
+namespace {
+
+constexpr size_t kMacSize = 64;
+
+base::string16 GetSplitPrefKeyName(const base::string16& reg_key_name,
+ const std::string& split_key_name) {
+ return reg_key_name + L"\\" + base::UTF8ToUTF16(split_key_name);
+}
+
+bool ReadMacFromRegistry(const base::win::RegKey& key,
+ const std::string& value_name,
+ std::string* out_mac) {
+ base::string16 string_value;
+ if (key.ReadValue(base::UTF8ToUTF16(value_name).c_str(), &string_value) ==
+ ERROR_SUCCESS &&
+ string_value.size() == kMacSize) {
+ out_mac->assign(base::UTF16ToUTF8(string_value));
+ return true;
+ }
+ return false;
+}
+
+// Removes |value_name| under |reg_key_name|. Returns true if found and
+// successfully removed.
+bool ClearAtomicMac(const base::string16& reg_key_name,
+ const std::string& value_name) {
+ base::win::RegKey key;
+ if (key.Open(HKEY_CURRENT_USER, reg_key_name.c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ return key.DeleteValue(base::UTF8ToUTF16(value_name).c_str()) ==
+ ERROR_SUCCESS;
+ }
+ return false;
+}
+
+// Deletes |split_key_name| under |reg_key_name|. Returns true if found and
+// successfully removed.
+bool ClearSplitMac(const base::string16& reg_key_name,
+ const std::string& split_key_name) {
+ base::win::RegKey key;
+ if (key.Open(HKEY_CURRENT_USER,
+ GetSplitPrefKeyName(reg_key_name, split_key_name).c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ return key.DeleteKey(L"") == ERROR_SUCCESS;
+ }
+ return false;
+}
+
+} // namespace
+
+RegistryHashStoreContentsWin::RegistryHashStoreContentsWin(
+ const base::string16& registry_path,
+ const base::string16& store_key)
+ : preference_key_name_(registry_path + L"\\PreferenceMACs\\" + store_key) {}
+
+RegistryHashStoreContentsWin::RegistryHashStoreContentsWin(
+ const RegistryHashStoreContentsWin& other) = default;
+
+bool RegistryHashStoreContentsWin::IsCopyable() const {
+ return true;
+}
+
+std::unique_ptr<HashStoreContents> RegistryHashStoreContentsWin::MakeCopy()
+ const {
+ return base::WrapUnique(new RegistryHashStoreContentsWin(*this));
+}
+
+base::StringPiece RegistryHashStoreContentsWin::GetUMASuffix() const {
+ return user_prefs::tracked::kTrackedPrefRegistryValidationSuffix;
+}
+
+void RegistryHashStoreContentsWin::Reset() {
+ base::win::RegKey key;
+ if (key.Open(HKEY_CURRENT_USER, preference_key_name_.c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ LONG result = key.DeleteKey(L"");
+ DCHECK(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND) << result;
+ }
+}
+
+bool RegistryHashStoreContentsWin::GetMac(const std::string& path,
+ std::string* out_value) {
+ base::win::RegKey key;
+ if (key.Open(HKEY_CURRENT_USER, preference_key_name_.c_str(),
+ KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ return ReadMacFromRegistry(key, path, out_value);
+ }
+
+ return false;
+}
+
+bool RegistryHashStoreContentsWin::GetSplitMacs(
+ const std::string& path,
+ std::map<std::string, std::string>* split_macs) {
+ DCHECK(split_macs);
+ DCHECK(split_macs->empty());
+
+ RegistryValueIterator iter_key(
+ HKEY_CURRENT_USER,
+ GetSplitPrefKeyName(preference_key_name_, path).c_str());
+
+ for (; iter_key.Valid(); ++iter_key) {
+ split_macs->insert(make_pair(base::UTF16ToUTF8(iter_key.Name()),
+ base::UTF16ToUTF8(iter_key.Value())));
+ }
+
+ return !split_macs->empty();
+}
+
+void RegistryHashStoreContentsWin::SetMac(const std::string& path,
+ const std::string& value) {
+ base::win::RegKey key;
+ DCHECK_EQ(kMacSize, value.size());
+
+ if (key.Create(HKEY_CURRENT_USER, preference_key_name_.c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ key.WriteValue(base::UTF8ToUTF16(path).c_str(),
+ base::UTF8ToUTF16(value).c_str());
+ }
+}
+
+void RegistryHashStoreContentsWin::SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) {
+ base::win::RegKey key;
+ DCHECK_EQ(kMacSize, value.size());
+
+ if (key.Create(HKEY_CURRENT_USER,
+ GetSplitPrefKeyName(preference_key_name_, path).c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ key.WriteValue(base::UTF8ToUTF16(split_path).c_str(),
+ base::UTF8ToUTF16(value).c_str());
+ }
+}
+
+bool RegistryHashStoreContentsWin::RemoveEntry(const std::string& path) {
+ return ClearAtomicMac(preference_key_name_, path) ||
+ ClearSplitMac(preference_key_name_, path);
+}
+
+void RegistryHashStoreContentsWin::ImportEntry(const std::string& path,
+ const base::Value* in_value) {
+ NOTREACHED()
+ << "RegistryHashStoreContents does not support the ImportEntry operation";
+}
+
+const base::DictionaryValue* RegistryHashStoreContentsWin::GetContents() const {
+ NOTREACHED()
+ << "RegistryHashStoreContents does not support the GetContents operation";
+ return NULL;
+}
+
+std::string RegistryHashStoreContentsWin::GetSuperMac() const {
+ NOTREACHED()
+ << "RegistryHashStoreContents does not support the GetSuperMac operation";
+ return NULL;
+}
+
+void RegistryHashStoreContentsWin::SetSuperMac(const std::string& super_mac) {
+ NOTREACHED()
+ << "RegistryHashStoreContents does not support the SetSuperMac operation";
+}
diff --git a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h
new file mode 100644
index 00000000000..b44898ef698
--- /dev/null
+++ b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h
@@ -0,0 +1,49 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_USER_PREFS_TRACKED_PREF_REGISTRY_HASH_STORE_CONTENTS_WIN_H_
+#define COMPONENTS_USER_PREFS_TRACKED_PREF_REGISTRY_HASH_STORE_CONTENTS_WIN_H_
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/user_prefs/tracked/hash_store_contents.h"
+
+// Implements HashStoreContents by storing MACs in the Windows registry.
+class RegistryHashStoreContentsWin : public HashStoreContents {
+ public:
+ // Constructs a RegistryHashStoreContents which acts on a registry entry
+ // defined by |registry_path| and |store_key|.
+ explicit RegistryHashStoreContentsWin(const base::string16& registry_path,
+ const base::string16& store_key);
+
+ // HashStoreContents overrides:
+ bool IsCopyable() const override;
+ std::unique_ptr<HashStoreContents> MakeCopy() const override;
+ base::StringPiece GetUMASuffix() const override;
+ void Reset() override;
+ bool GetMac(const std::string& path, std::string* out_value) override;
+ bool GetSplitMacs(const std::string& path,
+ std::map<std::string, std::string>* split_macs) override;
+ void SetMac(const std::string& path, const std::string& value) override;
+ void SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) override;
+ bool RemoveEntry(const std::string& path) override;
+
+ // Unsupported HashStoreContents overrides:
+ void ImportEntry(const std::string& path,
+ const base::Value* in_value) override;
+ const base::DictionaryValue* GetContents() const override;
+ std::string GetSuperMac() const override;
+ void SetSuperMac(const std::string& super_mac) override;
+
+ private:
+ // Helper constructor for |MakeCopy|.
+ explicit RegistryHashStoreContentsWin(
+ const RegistryHashStoreContentsWin& other);
+
+ const base::string16 preference_key_name_;
+};
+
+#endif // COMPONENTS_USER_PREFS_TRACKED_PREF_REGISTRY_HASH_STORE_CONTENTS_H_
diff --git a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc
new file mode 100644
index 00000000000..a34d7ade788
--- /dev/null
+++ b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc
@@ -0,0 +1,119 @@
+// 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 "components/user_prefs/tracked/registry_hash_store_contents_win.h"
+
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/values.h"
+#include "base/win/registry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+constexpr base::char16 kRegistryPath[] = L"Foo\\TestStore";
+constexpr base::char16 kStoreKey[] = L"test_store_key";
+
+// Hex-encoded MACs are 64 characters long.
+constexpr char kTestStringA[] =
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+constexpr char kTestStringB[] =
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
+
+constexpr char kAtomicPrefPath[] = "path1";
+constexpr char kSplitPrefPath[] = "extension";
+
+class RegistryHashStoreContentsWinTest : public testing::Test {
+ protected:
+ RegistryHashStoreContentsWinTest() {}
+
+ void SetUp() override {
+ registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+
+ contents.reset(new RegistryHashStoreContentsWin(kRegistryPath, kStoreKey));
+ }
+
+ std::unique_ptr<HashStoreContents> contents;
+
+ private:
+ registry_util::RegistryOverrideManager registry_override_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegistryHashStoreContentsWinTest);
+};
+
+} // namespace
+
+TEST_F(RegistryHashStoreContentsWinTest, TestSetAndGetMac) {
+ std::string stored_mac;
+ EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+
+ contents->SetMac(kAtomicPrefPath, kTestStringA);
+
+ EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_EQ(kTestStringA, stored_mac);
+}
+
+TEST_F(RegistryHashStoreContentsWinTest, TestSetAndGetSplitMacs) {
+ std::map<std::string, std::string> split_macs;
+ EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+
+ contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA);
+ contents->SetSplitMac(kSplitPrefPath, "b", kTestStringB);
+
+ EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+ EXPECT_EQ(2U, split_macs.size());
+ EXPECT_EQ(kTestStringA, split_macs.at("a"));
+ EXPECT_EQ(kTestStringB, split_macs.at("b"));
+}
+
+TEST_F(RegistryHashStoreContentsWinTest, TestRemoveAtomicMac) {
+ contents->SetMac(kAtomicPrefPath, kTestStringA);
+
+ std::string stored_mac;
+ EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_EQ(kTestStringA, stored_mac);
+
+ contents->RemoveEntry(kAtomicPrefPath);
+
+ EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+}
+
+TEST_F(RegistryHashStoreContentsWinTest, TestRemoveSplitMacs) {
+ contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA);
+ contents->SetSplitMac(kSplitPrefPath, "b", kTestStringB);
+
+ std::map<std::string, std::string> split_macs;
+ EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+ EXPECT_EQ(2U, split_macs.size());
+
+ contents->RemoveEntry(kSplitPrefPath);
+
+ split_macs.clear();
+ EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+ EXPECT_EQ(0U, split_macs.size());
+}
+
+TEST_F(RegistryHashStoreContentsWinTest, TestReset) {
+ contents->SetMac(kAtomicPrefPath, kTestStringA);
+ contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA);
+
+ std::string stored_mac;
+ EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_EQ(kTestStringA, stored_mac);
+
+ std::map<std::string, std::string> split_macs;
+ EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+ EXPECT_EQ(1U, split_macs.size());
+
+ contents->Reset();
+
+ stored_mac.clear();
+ EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_TRUE(stored_mac.empty());
+
+ split_macs.clear();
+ EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+ EXPECT_EQ(0U, split_macs.size());
+}
diff --git a/chromium/components/user_prefs/tracked/segregated_pref_store.cc b/chromium/components/user_prefs/tracked/segregated_pref_store.cc
index c5a6e25c2f3..af8dfe34be7 100644
--- a/chromium/components/user_prefs/tracked/segregated_pref_store.cc
+++ b/chromium/components/user_prefs/tracked/segregated_pref_store.cc
@@ -166,14 +166,16 @@ SegregatedPrefStore::~SegregatedPrefStore() {
}
PersistentPrefStore* SegregatedPrefStore::StoreForKey(const std::string& key) {
- return (ContainsKey(selected_preference_names_, key)
+ return (base::ContainsKey(selected_preference_names_, key)
? selected_pref_store_
- : default_pref_store_).get();
+ : default_pref_store_)
+ .get();
}
const PersistentPrefStore* SegregatedPrefStore::StoreForKey(
const std::string& key) const {
- return (ContainsKey(selected_preference_names_, key)
+ return (base::ContainsKey(selected_preference_names_, key)
? selected_pref_store_
- : default_pref_store_).get();
+ : default_pref_store_)
+ .get();
}
diff --git a/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc b/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc
index f3efce22f72..5d32d027d5e 100644
--- a/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc
+++ b/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc
@@ -104,10 +104,10 @@ TEST_F(SegregatedPrefStoreTest, StoreValues) {
// Properly stores new values.
segregated_store_->SetValue(kSelectedPref,
- base::WrapUnique(new base::StringValue(kValue1)),
+ base::MakeUnique<base::StringValue>(kValue1),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
segregated_store_->SetValue(kUnselectedPref,
- base::WrapUnique(new base::StringValue(kValue2)),
+ base::MakeUnique<base::StringValue>(kValue2),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
ASSERT_TRUE(selected_store_->GetValue(kSelectedPref, NULL));
@@ -129,10 +129,10 @@ TEST_F(SegregatedPrefStoreTest, StoreValues) {
TEST_F(SegregatedPrefStoreTest, ReadValues) {
selected_store_->SetValue(kSelectedPref,
- base::WrapUnique(new base::StringValue(kValue1)),
+ base::MakeUnique<base::StringValue>(kValue1),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
default_store_->SetValue(kUnselectedPref,
- base::WrapUnique(new base::StringValue(kValue2)),
+ base::MakeUnique<base::StringValue>(kValue2),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
// Works properly with values that are already there.
@@ -157,11 +157,11 @@ TEST_F(SegregatedPrefStoreTest, Observer) {
EXPECT_TRUE(observer_.initialization_success);
EXPECT_TRUE(observer_.changed_keys.empty());
segregated_store_->SetValue(kSelectedPref,
- base::WrapUnique(new base::StringValue(kValue1)),
+ base::MakeUnique<base::StringValue>(kValue1),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
observer_.VerifyAndResetChangedKey(kSelectedPref);
segregated_store_->SetValue(kUnselectedPref,
- base::WrapUnique(new base::StringValue(kValue2)),
+ base::MakeUnique<base::StringValue>(kValue2),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
observer_.VerifyAndResetChangedKey(kUnselectedPref);
}
diff --git a/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc b/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc
index 4eb4b6129d2..e2b76784b81 100644
--- a/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc
+++ b/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc
@@ -24,6 +24,10 @@ TrackedAtomicPreference::TrackedAtomicPreference(
delegate_(delegate) {
}
+TrackedPreferenceType TrackedAtomicPreference::GetType() const {
+ return TrackedPreferenceType::ATOMIC;
+}
+
void TrackedAtomicPreference::OnNewValue(
const base::Value* value,
PrefHashStoreTransaction* transaction) const {
@@ -32,20 +36,31 @@ void TrackedAtomicPreference::OnNewValue(
bool TrackedAtomicPreference::EnforceAndReport(
base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* transaction) const {
+ PrefHashStoreTransaction* transaction,
+ PrefHashStoreTransaction* external_validation_transaction) const {
const base::Value* value = NULL;
pref_store_contents->Get(pref_path_, &value);
PrefHashStoreTransaction::ValueState value_state =
transaction->CheckValue(pref_path_, value);
+ helper_.ReportValidationResult(value_state, transaction->GetStoreUMASuffix());
- helper_.ReportValidationResult(value_state);
+ PrefHashStoreTransaction::ValueState external_validation_value_state =
+ PrefHashStoreTransaction::UNSUPPORTED;
+ if (external_validation_transaction) {
+ external_validation_value_state =
+ external_validation_transaction->CheckValue(pref_path_, value);
+ helper_.ReportValidationResult(
+ external_validation_value_state,
+ external_validation_transaction->GetStoreUMASuffix());
+ }
- TrackedPreferenceHelper::ResetAction reset_action =
- helper_.GetAction(value_state);
if (delegate_) {
delegate_->OnAtomicPreferenceValidation(pref_path_, value, value_state,
+ external_validation_value_state,
helper_.IsPersonal());
}
+ TrackedPreferenceHelper::ResetAction reset_action =
+ helper_.GetAction(value_state);
helper_.ReportAction(reset_action);
bool was_reset = false;
@@ -61,5 +76,16 @@ bool TrackedAtomicPreference::EnforceAndReport(
transaction->StoreHash(pref_path_, new_value);
}
+ // Update MACs in the external store if there is one and there either was a
+ // reset or external validation failed.
+ if (external_validation_transaction &&
+ (was_reset ||
+ external_validation_value_state !=
+ PrefHashStoreTransaction::UNCHANGED)) {
+ const base::Value* new_value = nullptr;
+ pref_store_contents->Get(pref_path_, &new_value);
+ external_validation_transaction->StoreHash(pref_path_, new_value);
+ }
+
return was_reset;
}
diff --git a/chromium/components/user_prefs/tracked/tracked_atomic_preference.h b/chromium/components/user_prefs/tracked/tracked_atomic_preference.h
index 04bd0eaae85..e279af85947 100644
--- a/chromium/components/user_prefs/tracked/tracked_atomic_preference.h
+++ b/chromium/components/user_prefs/tracked/tracked_atomic_preference.h
@@ -30,10 +30,13 @@ class TrackedAtomicPreference : public TrackedPreference {
TrackedPreferenceValidationDelegate* delegate);
// TrackedPreference implementation.
+ TrackedPreferenceType GetType() const override;
void OnNewValue(const base::Value* value,
PrefHashStoreTransaction* transaction) const override;
- bool EnforceAndReport(base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* transaction) const override;
+ bool EnforceAndReport(
+ base::DictionaryValue* pref_store_contents,
+ PrefHashStoreTransaction* transaction,
+ PrefHashStoreTransaction* external_validation_transaction) const override;
private:
const std::string pref_path_;
diff --git a/chromium/components/user_prefs/tracked/tracked_preference.h b/chromium/components/user_prefs/tracked/tracked_preference.h
index 4773ac1cd3c..97666a0fcf8 100644
--- a/chromium/components/user_prefs/tracked/tracked_preference.h
+++ b/chromium/components/user_prefs/tracked/tracked_preference.h
@@ -12,12 +12,16 @@ class DictionaryValue;
class Value;
}
+enum class TrackedPreferenceType { ATOMIC, SPLIT };
+
// A TrackedPreference tracks changes to an individual preference, reporting and
// reacting to them according to preference-specific and browser-wide policies.
class TrackedPreference {
public:
virtual ~TrackedPreference() {}
+ virtual TrackedPreferenceType GetType() const = 0;
+
// Notifies the underlying TrackedPreference about its new |value| which
// can update hashes in the corresponding hash store via |transaction|.
virtual void OnNewValue(const base::Value* value,
@@ -27,10 +31,14 @@ class TrackedPreference {
// is valid. Responds to verification failures according to
// preference-specific and browser-wide policy and reports results to via UMA.
// May use |transaction| to check/modify hashes in the corresponding hash
- // store.
+ // store. Performs validation and reports results without enforcing for
+ // |external_validation_transaction|. This call assumes exclusive access to
+ // |external_validation_transaction| and its associated state and as such
+ // should only be called before any other subsystem is made aware of it.
virtual bool EnforceAndReport(
base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* transaction) const = 0;
+ PrefHashStoreTransaction* transaction,
+ PrefHashStoreTransaction* external_validation_transaction) const = 0;
};
#endif // COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_H_
diff --git a/chromium/components/user_prefs/tracked/tracked_preference_helper.cc b/chromium/components/user_prefs/tracked/tracked_preference_helper.cc
index f2e6883cf8a..fb36a2a1518 100644
--- a/chromium/components/user_prefs/tracked/tracked_preference_helper.cc
+++ b/chromium/components/user_prefs/tracked/tracked_preference_helper.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "components/user_prefs/tracked/tracked_preference_histogram_names.h"
TrackedPreferenceHelper::TrackedPreferenceHelper(
@@ -37,6 +38,10 @@ TrackedPreferenceHelper::ResetAction TrackedPreferenceHelper::GetAction(
case PrefHashStoreTransaction::SECURE_LEGACY:
// Accept secure legacy device ID based hashes.
return DONT_RESET;
+ case PrefHashStoreTransaction::UNSUPPORTED:
+ NOTREACHED()
+ << "GetAction should not be called with an UNSUPPORTED value state";
+ return DONT_RESET;
case PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE: // Falls through.
case PrefHashStoreTransaction::CHANGED:
return enforce_ ? DO_RESET : WANTED_RESET;
@@ -51,46 +56,53 @@ bool TrackedPreferenceHelper::IsPersonal() const {
}
void TrackedPreferenceHelper::ReportValidationResult(
- PrefHashStoreTransaction::ValueState value_state) const {
+ PrefHashStoreTransaction::ValueState value_state,
+ base::StringPiece validation_type_suffix) const {
+ const char* histogram_name = nullptr;
switch (value_state) {
case PrefHashStoreTransaction::UNCHANGED:
- UMA_HISTOGRAM_ENUMERATION(
- user_prefs::tracked::kTrackedPrefHistogramUnchanged, reporting_id_,
- reporting_ids_count_);
- return;
+ histogram_name = user_prefs::tracked::kTrackedPrefHistogramUnchanged;
+ break;
case PrefHashStoreTransaction::CLEARED:
- UMA_HISTOGRAM_ENUMERATION(
- user_prefs::tracked::kTrackedPrefHistogramCleared, reporting_id_,
- reporting_ids_count_);
- return;
+ histogram_name = user_prefs::tracked::kTrackedPrefHistogramCleared;
+ break;
case PrefHashStoreTransaction::SECURE_LEGACY:
- UMA_HISTOGRAM_ENUMERATION(
- user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId,
- reporting_id_, reporting_ids_count_);
- return;
+ histogram_name =
+ user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId;
+ break;
case PrefHashStoreTransaction::CHANGED:
- UMA_HISTOGRAM_ENUMERATION(
- user_prefs::tracked::kTrackedPrefHistogramChanged, reporting_id_,
- reporting_ids_count_);
- return;
+ histogram_name = user_prefs::tracked::kTrackedPrefHistogramChanged;
+ break;
case PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE:
- UMA_HISTOGRAM_ENUMERATION(
- user_prefs::tracked::kTrackedPrefHistogramInitialized, reporting_id_,
- reporting_ids_count_);
- return;
+ histogram_name = user_prefs::tracked::kTrackedPrefHistogramInitialized;
+ break;
case PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE:
- UMA_HISTOGRAM_ENUMERATION(
- user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized,
- reporting_id_, reporting_ids_count_);
- return;
+ histogram_name =
+ user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized;
+ break;
case PrefHashStoreTransaction::TRUSTED_NULL_VALUE:
- UMA_HISTOGRAM_ENUMERATION(
- user_prefs::tracked::kTrackedPrefHistogramNullInitialized,
- reporting_id_, reporting_ids_count_);
+ histogram_name =
+ user_prefs::tracked::kTrackedPrefHistogramNullInitialized;
+ break;
+ case PrefHashStoreTransaction::UNSUPPORTED:
+ NOTREACHED() << "ReportValidationResult should not be called with an "
+ "UNSUPPORTED value state";
return;
}
- NOTREACHED() << "Unexpected PrefHashStoreTransaction::ValueState: "
- << value_state;
+ DCHECK(histogram_name);
+
+ std::string full_histogram_name(histogram_name);
+ if (!validation_type_suffix.empty()) {
+ full_histogram_name.push_back('.');
+ validation_type_suffix.AppendToString(&full_histogram_name);
+ }
+
+ // Using FactoryGet to allow dynamic histogram names. This is equivalent to
+ // UMA_HISTOGRAM_ENUMERATION(name, reporting_id_, reporting_ids_count_);
+ base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
+ full_histogram_name, 1, reporting_ids_count_, reporting_ids_count_ + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(reporting_id_);
}
void TrackedPreferenceHelper::ReportAction(ResetAction reset_action) const {
diff --git a/chromium/components/user_prefs/tracked/tracked_preference_helper.h b/chromium/components/user_prefs/tracked/tracked_preference_helper.h
index 883e3e8f789..57b35fb32a3 100644
--- a/chromium/components/user_prefs/tracked/tracked_preference_helper.h
+++ b/chromium/components/user_prefs/tracked/tracked_preference_helper.h
@@ -42,8 +42,9 @@ class TrackedPreferenceHelper {
bool IsPersonal() const;
// Reports |value_state| via UMA under |reporting_id_|.
- void ReportValidationResult(
- PrefHashStoreTransaction::ValueState value_state) const;
+ // |validation_type_suffix| is appended to the reported histogram's name.
+ void ReportValidationResult(PrefHashStoreTransaction::ValueState value_state,
+ base::StringPiece validation_type_suffix) const;
// Reports |reset_action| via UMA under |reporting_id_|.
void ReportAction(ResetAction reset_action) const;
diff --git a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc b/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc
index deb4236dd1a..431bb9a31cf 100644
--- a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc
+++ b/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc
@@ -25,6 +25,7 @@ const char kTrackedPrefHistogramWantedReset[] =
const char kTrackedPrefHistogramReset[] = "Settings.TrackedPreferenceReset";
const char kTrackedSplitPrefHistogramChanged[] =
"Settings.TrackedSplitPreferenceChanged.";
+const char kTrackedPrefRegistryValidationSuffix[] = "FromRegistry";
} // namespace tracked
} // namespace user_prefs
diff --git a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h b/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h
index c5a82a557b5..31b9ce30448 100644
--- a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h
+++ b/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h
@@ -18,6 +18,7 @@ extern const char kTrackedPrefHistogramNullInitialized[];
extern const char kTrackedPrefHistogramWantedReset[];
extern const char kTrackedPrefHistogramReset[];
extern const char kTrackedSplitPrefHistogramChanged[];
+extern const char kTrackedPrefRegistryValidationSuffix[];
} // namespace tracked
} // namespace user_prefs
diff --git a/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h b/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h
index 8ea9c80a0a5..d010df5aee3 100644
--- a/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h
+++ b/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h
@@ -28,6 +28,7 @@ class TrackedPreferenceValidationDelegate {
const std::string& pref_path,
const base::Value* value,
PrefHashStoreTransaction::ValueState value_state,
+ PrefHashStoreTransaction::ValueState external_validation_value_state,
bool is_personal) = 0;
// Notifies observes of the result (|value_state|) of checking the split
@@ -37,7 +38,9 @@ class TrackedPreferenceValidationDelegate {
const std::string& pref_path,
const base::DictionaryValue* dict_value,
const std::vector<std::string>& invalid_keys,
+ const std::vector<std::string>& external_validation_invalid_keys,
PrefHashStoreTransaction::ValueState value_state,
+ PrefHashStoreTransaction::ValueState external_validation_value_state,
bool is_personal) = 0;
};
diff --git a/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc b/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc
index 0835a1450a0..50299141ed5 100644
--- a/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc
+++ b/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc
@@ -36,7 +36,6 @@ class TrackedPreferencesMigrator
register_on_successful_protected_store_write_callback,
std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- std::unique_ptr<HashStoreContents> legacy_pref_hash_store,
InterceptablePrefFilter* unprotected_pref_filter,
InterceptablePrefFilter* protected_pref_filter);
@@ -79,7 +78,6 @@ class TrackedPreferencesMigrator
std::unique_ptr<PrefHashStore> unprotected_pref_hash_store_;
std::unique_ptr<PrefHashStore> protected_pref_hash_store_;
- std::unique_ptr<HashStoreContents> legacy_pref_hash_store_;
std::unique_ptr<base::DictionaryValue> unprotected_prefs_;
std::unique_ptr<base::DictionaryValue> protected_prefs_;
@@ -122,10 +120,9 @@ void ScheduleSourcePrefStoreCleanup(
void CleanupMigratedHashes(const std::set<std::string>& migrated_pref_names,
PrefHashStore* origin_pref_hash_store,
base::DictionaryValue* origin_pref_store) {
+ DictionaryHashStoreContents dictionary_contents(origin_pref_store);
std::unique_ptr<PrefHashStoreTransaction> transaction(
- origin_pref_hash_store->BeginTransaction(
- std::unique_ptr<HashStoreContents>(
- new DictionaryHashStoreContents(origin_pref_store))));
+ origin_pref_hash_store->BeginTransaction(&dictionary_contents));
for (std::set<std::string>::const_iterator it = migrated_pref_names.begin();
it != migrated_pref_names.end();
++it) {
@@ -141,17 +138,13 @@ void MigratePrefsFromOldToNewStore(const std::set<std::string>& pref_names,
base::DictionaryValue* old_store,
base::DictionaryValue* new_store,
PrefHashStore* new_hash_store,
- HashStoreContents* legacy_hash_store,
bool* old_store_needs_cleanup,
- bool* new_store_altered,
- bool* used_legacy_pref_hashes) {
+ bool* new_store_altered) {
const base::DictionaryValue* old_hash_store_contents =
DictionaryHashStoreContents(old_store).GetContents();
- const base::DictionaryValue* legacy_hash_store_contents =
- legacy_hash_store->GetContents();
+ DictionaryHashStoreContents dictionary_contents(new_store);
std::unique_ptr<PrefHashStoreTransaction> new_hash_store_transaction(
- new_hash_store->BeginTransaction(std::unique_ptr<HashStoreContents>(
- new DictionaryHashStoreContents(new_store))));
+ new_hash_store->BeginTransaction(&dictionary_contents));
for (std::set<std::string>::const_iterator it = pref_names.begin();
it != pref_names.end();
@@ -186,11 +179,6 @@ void MigratePrefsFromOldToNewStore(const std::set<std::string>& pref_names,
const base::Value* old_hash = NULL;
if (old_hash_store_contents)
old_hash_store_contents->Get(pref_name, &old_hash);
- if (!old_hash && legacy_hash_store_contents) {
- legacy_hash_store_contents->Get(pref_name, &old_hash);
- if (old_hash)
- *used_legacy_pref_hashes = true;
- }
if (old_hash) {
new_hash_store_transaction->ImportHash(pref_name, old_hash);
*new_store_altered = true;
@@ -219,7 +207,6 @@ TrackedPreferencesMigrator::TrackedPreferencesMigrator(
register_on_successful_protected_store_write_callback,
std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- std::unique_ptr<HashStoreContents> legacy_pref_hash_store,
InterceptablePrefFilter* unprotected_pref_filter,
InterceptablePrefFilter* protected_pref_filter)
: unprotected_pref_names_(unprotected_pref_names),
@@ -231,8 +218,7 @@ TrackedPreferencesMigrator::TrackedPreferencesMigrator(
register_on_successful_protected_store_write_callback_(
register_on_successful_protected_store_write_callback),
unprotected_pref_hash_store_(std::move(unprotected_pref_hash_store)),
- protected_pref_hash_store_(std::move(protected_pref_hash_store)),
- legacy_pref_hash_store_(std::move(legacy_pref_hash_store)) {
+ protected_pref_hash_store_(std::move(protected_pref_hash_store)) {
// The callbacks bound below will own this TrackedPreferencesMigrator by
// reference.
unprotected_pref_filter->InterceptNextFilterOnLoad(
@@ -271,29 +257,18 @@ void TrackedPreferencesMigrator::MigrateIfReady() {
if (!protected_prefs_ || !unprotected_prefs_)
return;
- bool used_legacy_pref_hashes = false;
bool protected_prefs_need_cleanup = false;
bool unprotected_prefs_altered = false;
- MigratePrefsFromOldToNewStore(unprotected_pref_names_,
- protected_prefs_.get(),
- unprotected_prefs_.get(),
- unprotected_pref_hash_store_.get(),
- legacy_pref_hash_store_.get(),
- &protected_prefs_need_cleanup,
- &unprotected_prefs_altered,
- &used_legacy_pref_hashes);
+ MigratePrefsFromOldToNewStore(
+ unprotected_pref_names_, protected_prefs_.get(), unprotected_prefs_.get(),
+ unprotected_pref_hash_store_.get(), &protected_prefs_need_cleanup,
+ &unprotected_prefs_altered);
bool unprotected_prefs_need_cleanup = false;
bool protected_prefs_altered = false;
- MigratePrefsFromOldToNewStore(protected_pref_names_,
- unprotected_prefs_.get(),
- protected_prefs_.get(),
- protected_pref_hash_store_.get(),
- legacy_pref_hash_store_.get(),
- &unprotected_prefs_need_cleanup,
- &protected_prefs_altered,
- &used_legacy_pref_hashes);
- UMA_HISTOGRAM_BOOLEAN("Settings.MigratedHashesFromLocalState",
- used_legacy_pref_hashes);
+ MigratePrefsFromOldToNewStore(
+ protected_pref_names_, unprotected_prefs_.get(), protected_prefs_.get(),
+ protected_pref_hash_store_.get(), &unprotected_prefs_need_cleanup,
+ &protected_prefs_altered);
if (!unprotected_prefs_altered && !protected_prefs_altered) {
// Clean up any MACs that might have been previously migrated from the
@@ -308,7 +283,6 @@ void TrackedPreferencesMigrator::MigrateIfReady() {
CleanupMigratedHashes(protected_pref_names_,
unprotected_pref_hash_store_.get(),
unprotected_prefs_.get());
- legacy_pref_hash_store_->Reset();
}
// Hand the processed prefs back to their respective filters.
@@ -354,7 +328,6 @@ void SetupTrackedPreferencesMigration(
register_on_successful_protected_store_write_callback,
std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- std::unique_ptr<HashStoreContents> legacy_pref_hash_store,
InterceptablePrefFilter* unprotected_pref_filter,
InterceptablePrefFilter* protected_pref_filter) {
scoped_refptr<TrackedPreferencesMigrator> prefs_migrator(
@@ -364,7 +337,6 @@ void SetupTrackedPreferencesMigration(
register_on_successful_unprotected_store_write_callback,
register_on_successful_protected_store_write_callback,
std::move(unprotected_pref_hash_store),
- std::move(protected_pref_hash_store),
- std::move(legacy_pref_hash_store), unprotected_pref_filter,
+ std::move(protected_pref_hash_store), unprotected_pref_filter,
protected_pref_filter));
}
diff --git a/chromium/components/user_prefs/tracked/tracked_preferences_migration.h b/chromium/components/user_prefs/tracked/tracked_preferences_migration.h
index 3b5939228bb..3c96668a88d 100644
--- a/chromium/components/user_prefs/tracked/tracked_preferences_migration.h
+++ b/chromium/components/user_prefs/tracked/tracked_preferences_migration.h
@@ -23,12 +23,11 @@ class PrefHashStore;
// (un)protected_store_cleaner| and
// |register_on_successful_(un)protected_store_write_callback| are used to do
// post-migration cleanup tasks. Those should be bound to weak pointers to avoid
-// blocking shutdown. |(un)protected_pref_hash_store| and
-// |legacy_pref_hash_store| are used to migrate MACs along with their protected
-// preferences and/or from the legacy location in Local State. Migrated MACs
-// will only be cleared from their old location in a subsequent run. The
-// migration framework is resilient to a failed cleanup (it will simply try
-// again in the next Chrome run).
+// blocking shutdown. |(un)protected_pref_hash_store| is used to migrate MACs
+// along with their protected preferences. Migrated MACs will only be cleared
+// from their old location in a subsequent run. The migration framework is
+// resilient to a failed cleanup (it will simply try again in the next Chrome
+// run).
void SetupTrackedPreferencesMigration(
const std::set<std::string>& unprotected_pref_names,
const std::set<std::string>& protected_pref_names,
@@ -41,7 +40,6 @@ void SetupTrackedPreferencesMigration(
register_on_successful_protected_store_write_callback,
std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- std::unique_ptr<HashStoreContents> legacy_pref_hash_store,
InterceptablePrefFilter* unprotected_pref_filter,
InterceptablePrefFilter* protected_pref_filter);
diff --git a/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc b/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc
index 534ee21cd47..b1137543d3c 100644
--- a/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc
+++ b/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc
@@ -22,7 +22,6 @@
#include "components/user_prefs/tracked/pref_hash_store.h"
#include "components/user_prefs/tracked/pref_hash_store_impl.h"
#include "components/user_prefs/tracked/pref_hash_store_transaction.h"
-#include "components/user_prefs/tracked/pref_service_hash_store_contents.h"
#include "components/user_prefs/tracked/tracked_preferences_migration.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -48,9 +47,11 @@ class SimpleInterceptablePrefFilter : public InterceptablePrefFilter {
public:
// PrefFilter remaining implementation.
void FilterUpdate(const std::string& path) override { ADD_FAILURE(); }
- void FilterSerializeData(
+ OnWriteCallbackPair FilterSerializeData(
base::DictionaryValue* pref_store_contents) override {
ADD_FAILURE();
+ return std::make_pair(base::Closure(),
+ base::Callback<void(bool success)>());
}
private:
@@ -87,7 +88,6 @@ class TrackedPreferencesMigrationTest : public testing::Test {
protected_store_migration_complete_(false) {}
void SetUp() override {
- PrefServiceHashStoreContents::RegisterPrefs(local_state_.registry());
Reset();
}
@@ -123,9 +123,6 @@ class TrackedPreferencesMigrationTest : public testing::Test {
new PrefHashStoreImpl(kSeed, kDeviceId, false)),
std::unique_ptr<PrefHashStore>(
new PrefHashStoreImpl(kSeed, kDeviceId, true)),
- std::unique_ptr<HashStoreContents>(
- new PrefServiceHashStoreContents(kHashStoreId, &local_state_)),
-
&mock_unprotected_pref_filter_, &mock_protected_pref_filter_);
// Verify initial expectations are met.
@@ -147,16 +144,6 @@ class TrackedPreferencesMigrationTest : public testing::Test {
PresetStoreValueHash(store_id, key, value);
}
- // Sets |key| to |value| in the test store identified by |store_id| before
- // migration begins. Stores the value hash in Local State as in M36 and
- // earlier.
- void PresetLegacyStoreValue(MockPrefStoreID store_id,
- const std::string& key,
- const std::string value) {
- PresetStoreValueOnly(store_id, key, value);
- PresetLegacyValueHash(key, value);
- }
-
// Stores a hash for |key| and |value| in the hash store identified by
// |store_id| before migration begins.
void PresetStoreValueHash(MockPrefStoreID store_id,
@@ -177,24 +164,8 @@ class TrackedPreferencesMigrationTest : public testing::Test {
DCHECK(store);
base::StringValue string_value(value);
- pref_hash_store
- ->BeginTransaction(std::unique_ptr<HashStoreContents>(
- new DictionaryHashStoreContents(store)))
- ->StoreHash(key, &string_value);
- }
-
- // Stores a hash for |key| and |value| in the legacy hash store in
- // local_state.
- void PresetLegacyValueHash(const std::string& key,
- const std::string value) {
- std::unique_ptr<PrefHashStore> pref_hash_store(
- new PrefHashStoreImpl(kSeed, kDeviceId, true));
-
- base::StringValue string_value(value);
- PrefHashStoreImpl(kSeed, kDeviceId, true)
- .BeginTransaction(std::unique_ptr<HashStoreContents>(
- new PrefServiceHashStoreContents(kHashStoreId, &local_state_)))
- ->StoreHash(key, &string_value);
+ DictionaryHashStoreContents contents(store);
+ pref_hash_store->BeginTransaction(&contents)->StoreHash(key, &string_value);
}
// Returns true if the store opposite to |store_id| is observed for its next
@@ -255,16 +226,6 @@ class TrackedPreferencesMigrationTest : public testing::Test {
static_cast<std::string*>(NULL));
}
- // Determines whether |expected_pref_in_hash_store| has a hash in the Local
- // State hash store.
- bool ContainsLegacyHash(const std::string& expected_pref_in_hash_store) {
- const base::DictionaryValue* hash_store_contents =
- PrefServiceHashStoreContents(kHashStoreId, &local_state_).GetContents();
- return hash_store_contents &&
- hash_store_contents->GetString(expected_pref_in_hash_store,
- static_cast<std::string*>(NULL));
- }
-
// Both stores need to hand their prefs over in order for migration to kick
// in.
void HandPrefsToMigrator(MockPrefStoreID store_id) {
@@ -396,7 +357,6 @@ class TrackedPreferencesMigrationTest : public testing::Test {
store->SetString(key, value);
}
- static const char kHashStoreId[];
static const char kSeed[];
static const char kDeviceId[];
@@ -421,9 +381,6 @@ class TrackedPreferencesMigrationTest : public testing::Test {
};
// static
-const char TrackedPreferencesMigrationTest::kHashStoreId[] = "hash-store-id";
-
-// static
const char TrackedPreferencesMigrationTest::kSeed[] = "seed";
// static
@@ -482,208 +439,6 @@ TEST_F(TrackedPreferencesMigrationTest, NoMigrationRequired) {
EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
}
-TEST_F(TrackedPreferencesMigrationTest, LegacyHashMigrationOnly) {
- PresetLegacyStoreValue(
- MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref, kUnprotectedPrefValue);
- PresetLegacyStoreValue(
- MOCK_PROTECTED_PREF_STORE, kProtectedPref, kProtectedPrefValue);
-
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
-
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
-
- EXPECT_TRUE(ContainsLegacyHash(kProtectedPref));
- EXPECT_TRUE(ContainsLegacyHash(kUnprotectedPref));
-
- // Hand unprotected prefs to the migrator which should wait for the protected
- // prefs.
- HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
- EXPECT_FALSE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
- EXPECT_FALSE(MigrationCompleted());
-
- // Hand protected prefs to the migrator which should proceed with the
- // migration synchronously.
- HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
- EXPECT_TRUE(MigrationCompleted());
-
- // Prefs should have been handed back over.
- EXPECT_TRUE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
-
- // There is no pending cleanup task for the modern hash stores.
- EXPECT_FALSE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_FALSE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
-
- // Both stores were modified as hashes were moved from Local State.
- EXPECT_TRUE(StoreModifiedByMigration(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(StoreModifiedByMigration(MOCK_PROTECTED_PREF_STORE));
-
- base::StringPairs expected_unprotected_values;
- expected_unprotected_values.push_back(
- std::make_pair(kUnprotectedPref, kUnprotectedPrefValue));
- VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE, expected_unprotected_values);
-
- base::StringPairs expected_protected_values;
- expected_protected_values.push_back(
- std::make_pair(kProtectedPref, kProtectedPrefValue));
- VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
-
- EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
-
- EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
-
- // The Local State hash store will not be reset until the next run.
- EXPECT_TRUE(ContainsLegacyHash(kProtectedPref));
- EXPECT_TRUE(ContainsLegacyHash(kUnprotectedPref));
-
- Reset();
-
- HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
- HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
- EXPECT_TRUE(MigrationCompleted());
-
- // Neither store was modified.
- EXPECT_FALSE(StoreModifiedByMigration(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_FALSE(StoreModifiedByMigration(MOCK_PROTECTED_PREF_STORE));
-
- EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
-
- EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
-
- EXPECT_FALSE(ContainsLegacyHash(kProtectedPref));
- EXPECT_FALSE(ContainsLegacyHash(kUnprotectedPref));
-}
-
-TEST_F(TrackedPreferencesMigrationTest, FullMigrationWithLegacyHashStore) {
- // Store some values with matching MACs in Local State.
- PresetLegacyStoreValue(
- MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref, kUnprotectedPrefValue);
- PresetLegacyStoreValue(MOCK_UNPROTECTED_PREF_STORE,
- kPreviouslyUnprotectedPref,
- kPreviouslyUnprotectedPrefValue);
- PresetLegacyStoreValue(
- MOCK_PROTECTED_PREF_STORE, kProtectedPref, kProtectedPrefValue);
- PresetLegacyStoreValue(MOCK_PROTECTED_PREF_STORE,
- kPreviouslyProtectedPref,
- kPreviouslyProtectedPrefValue);
-
- // Verify that there are no MACs in Preferences or Secure Preferences.
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- // Verify that there are MACs in Local State.
- EXPECT_TRUE(ContainsLegacyHash(kUnprotectedPref));
- EXPECT_TRUE(ContainsLegacyHash(kPreviouslyUnprotectedPref));
- EXPECT_TRUE(ContainsLegacyHash(kProtectedPref));
- EXPECT_TRUE(ContainsLegacyHash(kPreviouslyProtectedPref));
-
- // Perform a first-pass migration.
- HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
- HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
- EXPECT_TRUE(MigrationCompleted());
-
- // All values should have been moved to their preferred locations, including
- // MACs.
- base::StringPairs expected_unprotected_values;
- expected_unprotected_values.push_back(
- std::make_pair(kUnprotectedPref, kUnprotectedPrefValue));
- expected_unprotected_values.push_back(
- std::make_pair(kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
- base::StringPairs expected_protected_values;
- expected_protected_values.push_back(
- std::make_pair(kProtectedPref, kProtectedPrefValue));
- expected_protected_values.push_back(std::make_pair(
- kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
-
- VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE, expected_unprotected_values);
- VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
-
- EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
-
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
-
- EXPECT_FALSE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- // Removing the values from their previous locations is deferred until the new
- // locations are persisted.
- EXPECT_TRUE(ContainsLegacyHash(kUnprotectedPref));
- EXPECT_TRUE(ContainsLegacyHash(kPreviouslyUnprotectedPref));
- EXPECT_TRUE(ContainsLegacyHash(kProtectedPref));
- EXPECT_TRUE(ContainsLegacyHash(kPreviouslyProtectedPref));
-
- EXPECT_TRUE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_TRUE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
-
- SimulateSuccessfulWrite(MOCK_UNPROTECTED_PREF_STORE);
- SimulateSuccessfulWrite(MOCK_PROTECTED_PREF_STORE);
-
- Reset();
-
- HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
- HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
- EXPECT_TRUE(MigrationCompleted());
-
- // In this run the MACs should have been removed from their previous
- // locations. There is no more pending action.
- EXPECT_FALSE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
- EXPECT_FALSE(
- WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
-
- EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
- EXPECT_TRUE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
- EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
- EXPECT_FALSE(
- ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
-
- EXPECT_FALSE(ContainsLegacyHash(kUnprotectedPref));
- EXPECT_FALSE(ContainsLegacyHash(kPreviouslyUnprotectedPref));
- EXPECT_FALSE(ContainsLegacyHash(kProtectedPref));
- EXPECT_FALSE(ContainsLegacyHash(kPreviouslyProtectedPref));
-
- VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE, expected_unprotected_values);
- VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
-}
-
TEST_F(TrackedPreferencesMigrationTest, FullMigration) {
PresetStoreValue(
MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref, kUnprotectedPrefValue);
diff --git a/chromium/components/user_prefs/tracked/tracked_split_preference.cc b/chromium/components/user_prefs/tracked/tracked_split_preference.cc
index 37bac10b760..2094d97b71e 100644
--- a/chromium/components/user_prefs/tracked/tracked_split_preference.cc
+++ b/chromium/components/user_prefs/tracked/tracked_split_preference.cc
@@ -27,6 +27,10 @@ TrackedSplitPreference::TrackedSplitPreference(
delegate_(delegate) {
}
+TrackedPreferenceType TrackedSplitPreference::GetType() const {
+ return TrackedPreferenceType::SPLIT;
+}
+
void TrackedSplitPreference::OnNewValue(
const base::Value* value,
PrefHashStoreTransaction* transaction) const {
@@ -40,7 +44,8 @@ void TrackedSplitPreference::OnNewValue(
bool TrackedSplitPreference::EnforceAndReport(
base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* transaction) const {
+ PrefHashStoreTransaction* transaction,
+ PrefHashStoreTransaction* external_validation_transaction) const {
base::DictionaryValue* dict_value = NULL;
if (!pref_store_contents->GetDictionary(pref_path_, &dict_value) &&
pref_store_contents->Get(pref_path_, NULL)) {
@@ -56,14 +61,27 @@ bool TrackedSplitPreference::EnforceAndReport(
if (value_state == PrefHashStoreTransaction::CHANGED)
helper_.ReportSplitPreferenceChangedCount(invalid_keys.size());
- helper_.ReportValidationResult(value_state);
+ helper_.ReportValidationResult(value_state, transaction->GetStoreUMASuffix());
+
+ PrefHashStoreTransaction::ValueState external_validation_value_state =
+ PrefHashStoreTransaction::UNSUPPORTED;
+ std::vector<std::string> external_validation_invalid_keys;
+ if (external_validation_transaction) {
+ external_validation_value_state =
+ external_validation_transaction->CheckSplitValue(
+ pref_path_, dict_value, &external_validation_invalid_keys);
+ helper_.ReportValidationResult(
+ external_validation_value_state,
+ external_validation_transaction->GetStoreUMASuffix());
+ }
- TrackedPreferenceHelper::ResetAction reset_action =
- helper_.GetAction(value_state);
if (delegate_) {
- delegate_->OnSplitPreferenceValidation(pref_path_, dict_value, invalid_keys,
- value_state, helper_.IsPersonal());
+ delegate_->OnSplitPreferenceValidation(
+ pref_path_, dict_value, invalid_keys, external_validation_invalid_keys,
+ value_state, external_validation_value_state, helper_.IsPersonal());
}
+ TrackedPreferenceHelper::ResetAction reset_action =
+ helper_.GetAction(value_state);
helper_.ReportAction(reset_action);
bool was_reset = false;
@@ -88,5 +106,16 @@ bool TrackedSplitPreference::EnforceAndReport(
transaction->StoreSplitHash(pref_path_, new_dict_value);
}
+ // Update MACs in the external store if there is one and there either was a
+ // reset or external validation failed.
+ if (external_validation_transaction &&
+ (was_reset ||
+ external_validation_value_state !=
+ PrefHashStoreTransaction::UNCHANGED)) {
+ const base::DictionaryValue* new_dict_value = nullptr;
+ pref_store_contents->GetDictionary(pref_path_, &new_dict_value);
+ external_validation_transaction->StoreSplitHash(pref_path_, new_dict_value);
+ }
+
return was_reset;
}
diff --git a/chromium/components/user_prefs/tracked/tracked_split_preference.h b/chromium/components/user_prefs/tracked/tracked_split_preference.h
index f2700a4ddab..359c8e1f570 100644
--- a/chromium/components/user_prefs/tracked/tracked_split_preference.h
+++ b/chromium/components/user_prefs/tracked/tracked_split_preference.h
@@ -33,10 +33,13 @@ class TrackedSplitPreference : public TrackedPreference {
TrackedPreferenceValidationDelegate* delegate);
// TrackedPreference implementation.
+ TrackedPreferenceType GetType() const override;
void OnNewValue(const base::Value* value,
PrefHashStoreTransaction* transaction) const override;
- bool EnforceAndReport(base::DictionaryValue* pref_store_contents,
- PrefHashStoreTransaction* transaction) const override;
+ bool EnforceAndReport(
+ base::DictionaryValue* pref_store_contents,
+ PrefHashStoreTransaction* transaction,
+ PrefHashStoreTransaction* external_validation_transaction) const override;
private:
const std::string pref_path_;
diff --git a/chromium/components/variations.gypi b/chromium/components/variations.gypi
deleted file mode 100644
index e67f11f0814..00000000000
--- a/chromium/components/variations.gypi
+++ /dev/null
@@ -1,179 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/variations
- 'target_name': 'variations',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- # List of dependencies is intentionally very minimal. Please avoid
- # adding extra dependencies without first checking with OWNERS.
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- '../third_party/mt19937ar/mt19937ar.gyp:mt19937ar',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- '../third_party/zlib/google/zip.gyp:compression_utils',
- 'crash_core_common',
- 'prefs/prefs.gyp:prefs',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'variations/active_field_trials.cc',
- 'variations/active_field_trials.h',
- 'variations/android/component_jni_registrar.cc',
- 'variations/android/component_jni_registrar.h',
- 'variations/android/variations_associated_data_android.cc',
- 'variations/android/variations_associated_data_android.h',
- 'variations/android/variations_seed_bridge.cc',
- 'variations/android/variations_seed_bridge.h',
- 'variations/caching_permuted_entropy_provider.cc',
- 'variations/caching_permuted_entropy_provider.h',
- 'variations/entropy_provider.cc',
- 'variations/entropy_provider.h',
- 'variations/experiment_labels.cc',
- 'variations/experiment_labels.h',
- 'variations/metrics_util.cc',
- 'variations/metrics_util.h',
- 'variations/pref_names.cc',
- 'variations/pref_names.h',
- 'variations/processed_study.cc',
- 'variations/processed_study.h',
- 'variations/proto/client_variations.proto',
- 'variations/proto/permuted_entropy_cache.proto',
- 'variations/proto/study.proto',
- 'variations/proto/variations_seed.proto',
- 'variations/study_filtering.cc',
- 'variations/study_filtering.h',
- "variations/synthetic_trials.cc",
- "variations/synthetic_trials.h",
- 'variations/variations_associated_data.cc',
- 'variations/variations_associated_data.h',
- 'variations/variations_experiment_util.cc',
- 'variations/variations_experiment_util.h',
- 'variations/variations_http_header_provider.cc',
- 'variations/variations_http_header_provider.h',
- 'variations/variations_request_scheduler.cc',
- 'variations/variations_request_scheduler.h',
- 'variations/variations_request_scheduler_mobile.cc',
- 'variations/variations_request_scheduler_mobile.h',
- 'variations/variations_seed_processor.cc',
- 'variations/variations_seed_processor.h',
- 'variations/variations_seed_simulator.cc',
- 'variations/variations_seed_simulator.h',
- 'variations/variations_seed_store.cc',
- 'variations/variations_seed_store.h',
- 'variations/variations_switches.cc',
- 'variations/variations_switches.h',
- 'variations/variations_url_constants.cc',
- 'variations/variations_url_constants.h',
- 'variations/variations_util.cc',
- 'variations/variations_util.h',
- ],
- 'variables': {
- 'proto_in_dir': 'variations/proto',
- 'proto_out_dir': 'components/variations/proto',
- },
- 'includes': [ '../build/protoc.gypi' ],
- 'conditions': [
- ['OS == "android"', {
- 'dependencies': [
- 'variations_jni_headers',
- ],
- }],
- ['OS!="android" and OS!="ios"', {
- 'sources!': [
- 'variations/variations_request_scheduler_mobile.cc',
- ],
- }],
- ],
- },
- {
- # GN version: //components/variations/service
- 'target_name': 'variations_service',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../ui/base/ui_base.gyp:ui_base',
- 'data_use_measurement_core',
- 'metrics',
- 'network_time',
- 'pref_registry',
- 'prefs/prefs.gyp:prefs',
- 'variations',
- 'version_info',
- 'web_resource',
- ],
- 'sources': [
- 'variations/service/ui_string_overrider.h',
- 'variations/service/ui_string_overrider.cc',
- 'variations/service/variations_service.cc',
- 'variations/service/variations_service.h',
- 'variations/service/variations_service_client.h',
- ],
- },
- {
- # GN version: //components/variations/net:net
- 'target_name': 'variations_net',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- 'components.gyp:google_core_browser',
- 'components.gyp:metrics',
- 'variations',
- ],
- 'export_dependent_settings': [
- 'components.gyp:metrics',
- ],
- 'sources': [
- 'variations/net/variations_http_headers.cc',
- 'variations/net/variations_http_headers.h',
- ],
- },
- ],
- 'conditions': [
- ['OS=="android"', {
- 'targets': [
- {
- # GN version: //components/variations/android:variations_java
- 'target_name': 'variations_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'variables': {
- 'java_in_dir': 'variations/android/java',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN version: //components/variations:jni
- 'target_name': 'variations_jni_headers',
- 'type': 'none',
- 'sources': [
- 'variations/android/java/src/org/chromium/components/variations/VariationsAssociatedData.java',
- 'variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedBridge.java',
- ],
- 'variables': {
- 'jni_gen_package': 'variations',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- ],
- }],
- ]
-}
diff --git a/chromium/components/variations/BUILD.gn b/chromium/components/variations/BUILD.gn
index 32c71f2210f..f4e62354bf9 100644
--- a/chromium/components/variations/BUILD.gn
+++ b/chromium/components/variations/BUILD.gn
@@ -6,7 +6,7 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-source_set("variations") {
+static_library("variations") {
sources = [
"active_field_trials.cc",
"active_field_trials.h",
@@ -82,7 +82,6 @@ source_set("variations") {
}
if (is_android) {
- # GYP: //components/variations.gypi:variations_jni_headers
generate_jni("jni") {
sources = [
"android/java/src/org/chromium/components/variations/VariationsAssociatedData.java",
diff --git a/chromium/components/variations/android/BUILD.gn b/chromium/components/variations/android/BUILD.gn
index 0bcadfddab0..e557e9ea27d 100644
--- a/chromium/components/variations/android/BUILD.gn
+++ b/chromium/components/variations/android/BUILD.gn
@@ -4,7 +4,6 @@
import("//build/config/android/rules.gni")
-# GYP: //components/variations.gypi:variations_java
android_library("variations_java") {
deps = [
"//base:base_java",
diff --git a/chromium/components/variations/android/variations_associated_data_android.cc b/chromium/components/variations/android/variations_associated_data_android.cc
index 42e5ae18875..1dd80969781 100644
--- a/chromium/components/variations/android/variations_associated_data_android.cc
+++ b/chromium/components/variations/android/variations_associated_data_android.cc
@@ -13,6 +13,8 @@
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
namespace variations {
diff --git a/chromium/components/variations/android/variations_seed_bridge.cc b/chromium/components/variations/android/variations_seed_bridge.cc
index 5c2788bb7cd..f5b73e9a2ec 100644
--- a/chromium/components/variations/android/variations_seed_bridge.cc
+++ b/chromium/components/variations/android/variations_seed_bridge.cc
@@ -43,10 +43,6 @@ ScopedJavaLocalRef<jbyteArray> StringToJavaByteArray(
namespace variations {
namespace android {
-bool RegisterVariationsSeedBridge(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
void GetVariationsFirstRunSeed(std::string* seed_data,
std::string* seed_signature,
std::string* seed_country,
@@ -93,10 +89,10 @@ void SetJavaFirstRunPrefsForTesting(const std::string& seed_data,
bool is_gzip_compressed) {
JNIEnv* env = AttachCurrentThread();
Java_VariationsSeedBridge_setVariationsFirstRunSeed(
- env, GetApplicationContext(), StringToJavaByteArray(env, seed_data).obj(),
- ConvertUTF8ToJavaString(env, seed_signature).obj(),
- ConvertUTF8ToJavaString(env, seed_country).obj(),
- ConvertUTF8ToJavaString(env, response_date).obj(),
+ env, GetApplicationContext(), StringToJavaByteArray(env, seed_data),
+ ConvertUTF8ToJavaString(env, seed_signature),
+ ConvertUTF8ToJavaString(env, seed_country),
+ ConvertUTF8ToJavaString(env, response_date),
static_cast<jboolean>(is_gzip_compressed));
}
diff --git a/chromium/components/variations/android/variations_seed_bridge.h b/chromium/components/variations/android/variations_seed_bridge.h
index 85e633f7736..c83f6f39e67 100644
--- a/chromium/components/variations/android/variations_seed_bridge.h
+++ b/chromium/components/variations/android/variations_seed_bridge.h
@@ -11,8 +11,6 @@
namespace variations {
namespace android {
-bool RegisterVariationsSeedBridge(JNIEnv* env);
-
// Return the first run seed data pulled from the Java side of application.
void GetVariationsFirstRunSeed(std::string* seed_data,
std::string* seed_signature,
diff --git a/chromium/components/variations/entropy_provider_unittest.cc b/chromium/components/variations/entropy_provider_unittest.cc
index 3c679dd0bc1..cde08e0aed9 100644
--- a/chromium/components/variations/entropy_provider_unittest.cc
+++ b/chromium/components/variations/entropy_provider_unittest.cc
@@ -13,6 +13,7 @@
#include "base/guid.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "components/variations/metrics_util.h"
@@ -189,7 +190,8 @@ TEST(EntropyProviderTest, UseOneTimeRandomizationSHA1) {
// Note that depending on the one-time random initialization, they
// _might_ actually give the same result, but we know that given
// the particular client_id we use for unit tests they won't.
- base::FieldTrialList field_trial_list(new SHA1EntropyProvider("client_id"));
+ base::FieldTrialList field_trial_list(
+ base::MakeUnique<SHA1EntropyProvider>("client_id"));
const int kNoExpirationYear = base::FieldTrialList::kNoExpirationYear;
scoped_refptr<base::FieldTrial> trials[] = {
base::FieldTrialList::FactoryGetFieldTrial(
@@ -219,7 +221,7 @@ TEST(EntropyProviderTest, UseOneTimeRandomizationPermuted) {
// _might_ actually give the same result, but we know that given
// the particular client_id we use for unit tests they won't.
base::FieldTrialList field_trial_list(
- new PermutedEntropyProvider(1234, kMaxLowEntropySize));
+ base::MakeUnique<PermutedEntropyProvider>(1234, kMaxLowEntropySize));
const int kNoExpirationYear = base::FieldTrialList::kNoExpirationYear;
scoped_refptr<base::FieldTrial> trials[] = {
base::FieldTrialList::FactoryGetFieldTrial(
@@ -245,7 +247,7 @@ TEST(EntropyProviderTest, UseOneTimeRandomizationWithCustomSeedPermuted) {
// Ensures that two trials with different names but the same custom seed used
// for one time randomization produce the same group assignments.
base::FieldTrialList field_trial_list(
- new PermutedEntropyProvider(1234, kMaxLowEntropySize));
+ base::MakeUnique<PermutedEntropyProvider>(1234, kMaxLowEntropySize));
const int kNoExpirationYear = base::FieldTrialList::kNoExpirationYear;
const uint32_t kCustomSeed = 9001;
scoped_refptr<base::FieldTrial> trials[] = {
diff --git a/chromium/components/variations/net/BUILD.gn b/chromium/components/variations/net/BUILD.gn
index c037d46fec3..148bf79a12d 100644
--- a/chromium/components/variations/net/BUILD.gn
+++ b/chromium/components/variations/net/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("net") {
+static_library("net") {
sources = [
"variations_http_headers.cc",
"variations_http_headers.h",
diff --git a/chromium/components/variations/processed_study.cc b/chromium/components/variations/processed_study.cc
index 8bf91e3b3ff..8c1f8d0f8a1 100644
--- a/chromium/components/variations/processed_study.cc
+++ b/chromium/components/variations/processed_study.cc
@@ -27,13 +27,13 @@ bool ValidateStudyAndComputeTotalProbability(
return false;
}
if (study.filter().has_min_version() &&
- !Version::IsValidWildcardString(study.filter().min_version())) {
+ !base::Version::IsValidWildcardString(study.filter().min_version())) {
DVLOG(1) << study.name() << " has invalid min version: "
<< study.filter().min_version();
return false;
}
if (study.filter().has_max_version() &&
- !Version::IsValidWildcardString(study.filter().max_version())) {
+ !base::Version::IsValidWildcardString(study.filter().max_version())) {
DVLOG(1) << study.name() << " has invalid max version: "
<< study.filter().max_version();
return false;
diff --git a/chromium/components/variations/service/BUILD.gn b/chromium/components/variations/service/BUILD.gn
index 099be5c2884..d2ea94f1029 100644
--- a/chromium/components/variations/service/BUILD.gn
+++ b/chromium/components/variations/service/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("service") {
+static_library("service") {
sources = [
"ui_string_overrider.cc",
"ui_string_overrider.h",
diff --git a/chromium/components/variations/service/variations_service.cc b/chromium/components/variations/service/variations_service.cc
index b583668618d..8f5d5df8efa 100644
--- a/chromium/components/variations/service/variations_service.cc
+++ b/chromium/components/variations/service/variations_service.cc
@@ -12,7 +12,7 @@
#include "base/build_time.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
@@ -502,8 +502,8 @@ std::unique_ptr<VariationsService> VariationsService::Create(
#endif
result.reset(new VariationsService(
std::move(client),
- base::WrapUnique(new web_resource::ResourceRequestAllowedNotifier(
- local_state, disable_network_switch)),
+ base::MakeUnique<web_resource::ResourceRequestAllowedNotifier>(
+ local_state, disable_network_switch),
local_state, state_manager, ui_string_overrider));
return result;
}
@@ -514,8 +514,8 @@ std::unique_ptr<VariationsService> VariationsService::CreateForTesting(
PrefService* local_state) {
return base::WrapUnique(new VariationsService(
std::move(client),
- base::WrapUnique(new web_resource::ResourceRequestAllowedNotifier(
- local_state, nullptr)),
+ base::MakeUnique<web_resource::ResourceRequestAllowedNotifier>(
+ local_state, nullptr),
local_state, nullptr, UIStringOverrider()));
}
@@ -560,7 +560,7 @@ void VariationsService::DoActualFetch() {
if (!last_request_started_time_.is_null())
time_since_last_fetch = now - last_request_started_time_;
UMA_HISTOGRAM_CUSTOM_COUNTS("Variations.TimeSinceLastFetchAttempt",
- time_since_last_fetch.InMinutes(), 0,
+ time_since_last_fetch.InMinutes(), 1,
base::TimeDelta::FromDays(7).InMinutes(), 50);
UMA_HISTOGRAM_COUNTS_100("Variations.RequestCount", request_count_);
++request_count_;
@@ -644,13 +644,15 @@ void VariationsService::OnURLFetchComplete(const net::URLFetcher* source) {
// The fetcher will be deleted when the request is handled.
std::unique_ptr<const net::URLFetcher> request(
pending_seed_request_.release());
- const net::URLRequestStatus& request_status = request->GetStatus();
- if (request_status.status() != net::URLRequestStatus::SUCCESS) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Variations.FailedRequestErrorCode",
- -request_status.error());
+ const net::URLRequestStatus& status = request->GetStatus();
+ const int response_code = request->GetResponseCode();
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "Variations.SeedFetchResponseOrErrorCode",
+ status.is_success() ? response_code : status.error());
+
+ if (status.status() != net::URLRequestStatus::SUCCESS) {
DVLOG(1) << "Variations server request failed with error: "
- << request_status.error() << ": "
- << net::ErrorToString(request_status.error());
+ << status.error() << ": " << net::ErrorToString(status.error());
// It's common for the very first fetch attempt to fail (e.g. the network
// may not yet be available). In such a case, try again soon, rather than
// waiting the full time interval.
@@ -659,11 +661,6 @@ void VariationsService::OnURLFetchComplete(const net::URLFetcher* source) {
return;
}
- // Log the response code.
- const int response_code = request->GetResponseCode();
- UMA_HISTOGRAM_SPARSE_SLOWLY("Variations.SeedFetchResponseCode",
- response_code);
-
const base::TimeDelta latency =
base::TimeTicks::Now() - last_request_started_time_;
diff --git a/chromium/components/variations/service/variations_service_unittest.cc b/chromium/components/variations/service/variations_service_unittest.cc
index 6abfc8a8f5c..d6293876b09 100644
--- a/chromium/components/variations/service/variations_service_unittest.cc
+++ b/chromium/components/variations/service/variations_service_unittest.cc
@@ -272,17 +272,13 @@ TEST_F(VariationsServiceTest, CreateTrialsFromSeed) {
TestingPrefServiceSimple prefs;
VariationsService::RegisterPrefs(prefs.registry());
- // Setup base::FeatureList.
- base::FeatureList::ClearInstanceForTesting();
- base::FeatureList::SetInstance(base::WrapUnique(new base::FeatureList()));
-
// Create a local base::FieldTrialList, to hold the field trials created in
// this test.
base::FieldTrialList field_trial_list(nullptr);
// Create a variations service.
TestVariationsService service(
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs);
service.SetCreateTrialsFromSeedCalledForTesting(false);
@@ -303,17 +299,13 @@ TEST_F(VariationsServiceTest, CreateTrialsFromSeedNoLastFetchTime) {
TestingPrefServiceSimple prefs;
VariationsService::RegisterPrefs(prefs.registry());
- // Setup base::FeatureList.
- base::FeatureList::ClearInstanceForTesting();
- base::FeatureList::SetInstance(base::WrapUnique(new base::FeatureList()));
-
// Create a local base::FieldTrialList, to hold the field trials created in
// this test.
base::FieldTrialList field_trial_list(nullptr);
// Create a variations service
TestVariationsService service(
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs);
service.SetCreateTrialsFromSeedCalledForTesting(false);
@@ -334,17 +326,13 @@ TEST_F(VariationsServiceTest, CreateTrialsFromOutdatedSeed) {
TestingPrefServiceSimple prefs;
VariationsService::RegisterPrefs(prefs.registry());
- // Setup base::FeatureList.
- base::FeatureList::ClearInstanceForTesting();
- base::FeatureList::SetInstance(base::WrapUnique(new base::FeatureList()));
-
// Create a local base::FieldTrialList, to hold the field trials created in
// this test.
base::FieldTrialList field_trial_list(nullptr);
// Create a variations service.
TestVariationsService service(
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs);
service.SetCreateTrialsFromSeedCalledForTesting(false);
@@ -368,11 +356,11 @@ TEST_F(VariationsServiceTest, GetVariationsServerURL) {
std::string value;
std::unique_ptr<TestVariationsServiceClient> client =
- base::WrapUnique(new TestVariationsServiceClient());
+ base::MakeUnique<TestVariationsServiceClient>();
TestVariationsServiceClient* raw_client = client.get();
VariationsService service(
std::move(client),
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs, NULL, UIStringOverrider());
GURL url = service.GetVariationsServerURL(&prefs, std::string());
EXPECT_TRUE(base::StartsWith(url.spec(), default_variations_url,
@@ -407,7 +395,7 @@ TEST_F(VariationsServiceTest, VariationsURLHasOSNameParam) {
TestingPrefServiceSimple prefs;
VariationsService::RegisterPrefs(prefs.registry());
TestVariationsService service(
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs);
const GURL url = service.GetVariationsServerURL(&prefs, std::string());
@@ -423,7 +411,7 @@ TEST_F(VariationsServiceTest, RequestsInitiallyNotAllowed) {
// Pass ownership to TestVariationsService, but keep a weak pointer to
// manipulate it for this test.
std::unique_ptr<web_resource::TestRequestAllowedNotifier> test_notifier =
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs));
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs);
web_resource::TestRequestAllowedNotifier* raw_notifier = test_notifier.get();
TestVariationsService test_service(std::move(test_notifier), &prefs);
@@ -443,7 +431,7 @@ TEST_F(VariationsServiceTest, RequestsInitiallyAllowed) {
// Pass ownership to TestVariationsService, but keep a weak pointer to
// manipulate it for this test.
std::unique_ptr<web_resource::TestRequestAllowedNotifier> test_notifier =
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs));
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs);
web_resource::TestRequestAllowedNotifier* raw_notifier = test_notifier.get();
TestVariationsService test_service(std::move(test_notifier), &prefs);
@@ -457,7 +445,7 @@ TEST_F(VariationsServiceTest, SeedStoredWhenOKStatus) {
VariationsService::RegisterPrefs(prefs.registry());
TestVariationsService service(
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs);
service.set_intercepts_fetch(false);
@@ -486,7 +474,7 @@ TEST_F(VariationsServiceTest, SeedNotStoredWhenNonOKStatus) {
VariationsService::RegisterPrefs(prefs.registry());
TestVariationsService service(
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs);
service.set_intercepts_fetch(false);
for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) {
@@ -508,7 +496,7 @@ TEST_F(VariationsServiceTest, RequestGzipCompressedSeed) {
net::TestURLFetcherFactory factory;
TestVariationsService service(
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs);
service.set_intercepts_fetch(false);
service.DoActualFetch();
@@ -544,7 +532,7 @@ TEST_F(VariationsServiceTest, InstanceManipulations) {
for (size_t i = 0; i < arraysize(cases); ++i) {
TestVariationsService service(
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs);
service.set_intercepts_fetch(false);
service.DoActualFetch();
@@ -568,7 +556,7 @@ TEST_F(VariationsServiceTest, CountryHeader) {
VariationsService::RegisterPrefs(prefs.registry());
TestVariationsService service(
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs);
service.set_intercepts_fetch(false);
@@ -591,8 +579,8 @@ TEST_F(VariationsServiceTest, Observer) {
TestingPrefServiceSimple prefs;
VariationsService::RegisterPrefs(prefs.registry());
VariationsService service(
- base::WrapUnique(new TestVariationsServiceClient()),
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<TestVariationsServiceClient>(),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs, NULL, UIStringOverrider());
struct {
@@ -691,8 +679,8 @@ TEST_F(VariationsServiceTest, LoadPermanentConsistencyCountry) {
TestingPrefServiceSimple prefs;
VariationsService::RegisterPrefs(prefs.registry());
VariationsService service(
- base::WrapUnique(new TestVariationsServiceClient()),
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<TestVariationsServiceClient>(),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs, NULL, UIStringOverrider());
if (test.pref_value_before) {
@@ -763,7 +751,7 @@ TEST_F(VariationsServiceTest, OverrideStoredPermanentCountry) {
TestingPrefServiceSimple prefs;
VariationsService::RegisterPrefs(prefs.registry());
TestVariationsService service(
- base::WrapUnique(new web_resource::TestRequestAllowedNotifier(&prefs)),
+ base::MakeUnique<web_resource::TestRequestAllowedNotifier>(&prefs),
&prefs);
if (!test.pref_value_before.empty()) {
diff --git a/chromium/components/variations/study_filtering.cc b/chromium/components/variations/study_filtering.cc
index f5b3f26f9c5..479b9e959ec 100644
--- a/chromium/components/variations/study_filtering.cc
+++ b/chromium/components/variations/study_filtering.cc
@@ -164,10 +164,10 @@ bool CheckStudyCountry(const Study_Filter& filter, const std::string& country) {
// that this means this overrides the exclude_country in case that ever occurs
// (which it shouldn't).
if (filter.country_size() > 0)
- return ContainsValue(filter.country(), country);
+ return base::ContainsValue(filter.country(), country);
// Omit if matches any of the exclude entries.
- return !ContainsValue(filter.exclude_country(), country);
+ return !base::ContainsValue(filter.exclude_country(), country);
}
bool IsStudyExpired(const Study& study, const base::Time& date_time) {
@@ -288,14 +288,14 @@ void FilterAndValidateStudies(const VariationsSeed& seed,
if (internal::IsStudyExpired(study, reference_date)) {
expired_studies.push_back(&study);
- } else if (!ContainsKey(created_studies, study.name())) {
+ } else if (!base::ContainsKey(created_studies, study.name())) {
ProcessedStudy::ValidateAndAppendStudy(&study, false, filtered_studies);
created_studies.insert(study.name());
}
}
for (size_t i = 0; i < expired_studies.size(); ++i) {
- if (!ContainsKey(created_studies, expired_studies[i]->name())) {
+ if (!base::ContainsKey(created_studies, expired_studies[i]->name())) {
ProcessedStudy::ValidateAndAppendStudy(expired_studies[i], true,
filtered_studies);
}
diff --git a/chromium/components/variations/study_filtering_unittest.cc b/chromium/components/variations/study_filtering_unittest.cc
index 0715432a583..0c9dfa06e35 100644
--- a/chromium/components/variations/study_filtering_unittest.cc
+++ b/chromium/components/variations/study_filtering_unittest.cc
@@ -280,8 +280,8 @@ TEST(VariationsStudyFilteringTest, CheckStudyVersion) {
for (size_t i = 0; i < arraysize(min_test_cases); ++i) {
filter.set_min_version(min_test_cases[i].min_version);
- const bool result =
- internal::CheckStudyVersion(filter, Version(min_test_cases[i].version));
+ const bool result = internal::CheckStudyVersion(
+ filter, base::Version(min_test_cases[i].version));
EXPECT_EQ(min_test_cases[i].expected_result, result) <<
"Min. version case " << i << " failed!";
}
@@ -289,8 +289,8 @@ TEST(VariationsStudyFilteringTest, CheckStudyVersion) {
for (size_t i = 0; i < arraysize(max_test_cases); ++i) {
filter.set_max_version(max_test_cases[i].max_version);
- const bool result =
- internal::CheckStudyVersion(filter, Version(max_test_cases[i].version));
+ const bool result = internal::CheckStudyVersion(
+ filter, base::Version(max_test_cases[i].version));
EXPECT_EQ(max_test_cases[i].expected_result, result) <<
"Max version case " << i << " failed!";
}
@@ -302,16 +302,14 @@ TEST(VariationsStudyFilteringTest, CheckStudyVersion) {
filter.set_max_version(max_test_cases[j].max_version);
if (!min_test_cases[i].expected_result) {
- const bool result =
- internal::CheckStudyVersion(
- filter, Version(min_test_cases[i].version));
+ const bool result = internal::CheckStudyVersion(
+ filter, base::Version(min_test_cases[i].version));
EXPECT_FALSE(result) << "Case " << i << "," << j << " failed!";
}
if (!max_test_cases[j].expected_result) {
- const bool result =
- internal::CheckStudyVersion(
- filter, Version(max_test_cases[j].version));
+ const bool result = internal::CheckStudyVersion(
+ filter, base::Version(max_test_cases[j].version));
EXPECT_FALSE(result) << "Case " << i << "," << j << " failed!";
}
}
diff --git a/chromium/components/variations/variations_associated_data.cc b/chromium/components/variations/variations_associated_data.cc
index 9aa51d379f3..d257d01999f 100644
--- a/chromium/components/variations/variations_associated_data.cc
+++ b/chromium/components/variations/variations_associated_data.cc
@@ -11,11 +11,15 @@
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
+#include "base/strings/string_split.h"
+#include "components/variations/variations_http_header_provider.h"
namespace variations {
namespace {
+const char kGroupTesting[] = "Testing";
+
// The internal singleton accessor for the map, used to keep it thread-safe.
class GroupMapAccessor {
public:
@@ -124,7 +128,7 @@ class VariationsParamAssociator {
return false;
const VariationKey key(trial_name, group_name);
- if (ContainsKey(variation_params_, key))
+ if (base::ContainsKey(variation_params_, key))
return false;
variation_params_[key] = params;
@@ -138,7 +142,7 @@ class VariationsParamAssociator {
const std::string group_name =
base::FieldTrialList::FindFullName(trial_name);
const VariationKey key(trial_name, group_name);
- if (!ContainsKey(variation_params_, key))
+ if (!base::ContainsKey(variation_params_, key))
return false;
*params = variation_params_[key];
@@ -252,6 +256,26 @@ std::string GetVariationParamValueByFeature(const base::Feature& feature,
// They simply wrap existing functions in this file.
namespace testing {
+VariationParamsManager::VariationParamsManager(
+ const std::string& trial_name,
+ const std::map<std::string, std::string>& params) {
+ SetVariationParams(trial_name, params);
+}
+
+VariationParamsManager::~VariationParamsManager() {
+ ClearAllVariationIDs();
+ ClearAllVariationParams();
+ field_trial_list_.reset();
+}
+
+void VariationParamsManager::SetVariationParams(
+ const std::string& trial_name,
+ const std::map<std::string, std::string>& params) {
+ field_trial_list_.reset(new base::FieldTrialList(nullptr));
+ variations::AssociateVariationParams(trial_name, kGroupTesting, params);
+ base::FieldTrialList::CreateFieldTrial(trial_name, kGroupTesting);
+}
+
void ClearAllVariationIDs() {
GroupMapAccessor::GetInstance()->ClearAllMapsForTesting();
}
diff --git a/chromium/components/variations/variations_associated_data.h b/chromium/components/variations/variations_associated_data.h
index 3eb9567cc3a..a4156c293d6 100644
--- a/chromium/components/variations/variations_associated_data.h
+++ b/chromium/components/variations/variations_associated_data.h
@@ -6,7 +6,9 @@
#define COMPONENTS_VARIATIONS_VARIATIONS_ASSOCIATED_DATA_H_
#include <map>
+#include <memory>
#include <string>
+#include <vector>
#include "base/metrics/field_trial.h"
#include "components/variations/active_field_trials.h"
@@ -48,6 +50,7 @@ struct Feature;
namespace variations {
typedef int VariationID;
+class VariationsHttpHeaderProvider;
const VariationID EMPTY_ID = 0;
@@ -153,17 +156,42 @@ std::string GetVariationParamValue(const std::string& trial_name,
// variation associated with the specified |feature|. A feature is associated
// with at most one variation, through the variation's associated field trial,
// and selected group. See base/feature_list.h for more information on
-// features. If the feature is not enabled, or if there's no associated
-// variation params, returns false and does not modify |params|. Calling this
-// function will result in the associated field trial being marked as active if
-// found (i.e. group() will be called on it), if it wasn't already. Currently,
-// this information is only available from the browser process. Thread safe.
+// features. If the feature is not enabled, or the specified parameter does not
+// exist, returns an empty string.Calling this function will result in the
+// associated field trial being marked as active if found (i.e. group() will be
+// called on it), if it wasn't already. Currently, this information is only
+// available from the browser process. Thread safe.
std::string GetVariationParamValueByFeature(const base::Feature& feature,
const std::string& param_name);
// Expose some functions for testing.
namespace testing {
+// Use this class as a member in your test class to set variation params for
+// your tests. You can directly set the parameters in the constructor (if they
+// are used by other members upon construction). You can change them later
+// arbitrarily many times using the SetVariationParams function. Internally, it
+// creates a FieldTrialList as a member. It works well for multiple tests of a
+// given test class, as it clears the parameters when this class is destructed.
+// Note that it clears all parameters (not just those registered here).
+class VariationParamsManager {
+ public:
+ VariationParamsManager(const std::string& trial_name,
+ const std::map<std::string, std::string>& params);
+ ~VariationParamsManager();
+
+ // Associates |params| with the given |trial_name|. It creates a new group,
+ // used only for testing. Between two calls of this function,
+ // ClearAllVariationParams() has to be called.
+ void SetVariationParams(const std::string& trial_name,
+ const std::map<std::string, std::string>& params);
+
+ private:
+ std::unique_ptr<base::FieldTrialList> field_trial_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(VariationParamsManager);
+};
+
// Clears all of the mapped associations.
void ClearAllVariationIDs();
diff --git a/chromium/components/variations/variations_associated_data_unittest.cc b/chromium/components/variations/variations_associated_data_unittest.cc
index 05cdecea048..5bdd1d8481a 100644
--- a/chromium/components/variations/variations_associated_data_unittest.cc
+++ b/chromium/components/variations/variations_associated_data_unittest.cc
@@ -7,6 +7,7 @@
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/metrics/field_trial.h"
+#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace variations {
@@ -34,16 +35,6 @@ scoped_refptr<base::FieldTrial> CreateFieldTrial(
base::FieldTrial::SESSION_RANDOMIZED, default_group_number);
}
-void CreateFeatureWithTrial(const base::Feature& feature,
- base::FeatureList::OverrideState override_state,
- base::FieldTrial* trial) {
- base::FeatureList::ClearInstanceForTesting();
- std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->RegisterFieldTrialOverride(feature.name, override_state,
- trial);
- base::FeatureList::SetInstance(std::move(feature_list));
-}
-
} // namespace
class VariationsAssociatedDataTest : public ::testing::Test {
@@ -58,8 +49,18 @@ class VariationsAssociatedDataTest : public ::testing::Test {
testing::ClearAllVariationParams();
}
+ void CreateFeatureWithTrial(const base::Feature& feature,
+ base::FeatureList::OverrideState override_state,
+ base::FieldTrial* trial) {
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->RegisterFieldTrialOverride(feature.name, override_state,
+ trial);
+ scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
+ }
+
private:
base::FieldTrialList field_trial_list_;
+ base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(VariationsAssociatedDataTest);
};
diff --git a/chromium/components/variations/variations_http_header_provider.cc b/chromium/components/variations/variations_http_header_provider.cc
index d77a4bf8e3d..5af7151403c 100644
--- a/chromium/components/variations/variations_http_header_provider.cc
+++ b/chromium/components/variations/variations_http_header_provider.cc
@@ -56,12 +56,32 @@ std::string VariationsHttpHeaderProvider::GetVariationsString() {
return ids_string;
}
+bool VariationsHttpHeaderProvider::ForceVariationIds(
+ const std::string& command_line_variation_ids,
+ std::vector<std::string>* variation_ids) {
+ if (!command_line_variation_ids.empty()) {
+ // Combine |variation_ids| with |command_line_variation_ids|.
+ std::vector<std::string> variation_ids_flags =
+ base::SplitString(command_line_variation_ids, ",",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ variation_ids->insert(variation_ids->end(), variation_ids_flags.begin(),
+ variation_ids_flags.end());
+ }
+
+ if (!variation_ids->empty()) {
+ // Create default variation ids which will always be included in the
+ // X-Client-Data request header.
+ return SetDefaultVariationIds(*variation_ids);
+ }
+ return true;
+}
+
+
bool VariationsHttpHeaderProvider::SetDefaultVariationIds(
- const std::string& variation_ids) {
+ const std::vector<std::string>& variation_ids) {
default_variation_ids_set_.clear();
default_trigger_id_set_.clear();
- for (const base::StringPiece& entry : base::SplitStringPiece(
- variation_ids, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+ for (const std::string& entry : variation_ids) {
if (entry.empty()) {
default_variation_ids_set_.clear();
default_trigger_id_set_.clear();
@@ -70,7 +90,7 @@ bool VariationsHttpHeaderProvider::SetDefaultVariationIds(
bool trigger_id =
base::StartsWith(entry, "t", base::CompareCase::SENSITIVE);
// Remove the "t" prefix if it's there.
- base::StringPiece trimmed_entry = trigger_id ? entry.substr(1) : entry;
+ std::string trimmed_entry = trigger_id ? entry.substr(1) : entry;
int variation_id = 0;
if (!base::StringToInt(trimmed_entry, &variation_id)) {
@@ -166,7 +186,7 @@ void VariationsHttpHeaderProvider::InitVariationIDsCacheIfNeeded() {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Variations.HeaderConstructionTime",
- (base::TimeTicks::Now() - before_time).InMicroseconds(), 0,
+ (base::TimeTicks::Now() - before_time).InMicroseconds(), 1,
base::TimeDelta::FromSeconds(1).InMicroseconds(), 50);
variation_ids_cache_initialized_ = true;
diff --git a/chromium/components/variations/variations_http_header_provider.h b/chromium/components/variations/variations_http_header_provider.h
index b92daca3a54..349fea9951c 100644
--- a/chromium/components/variations/variations_http_header_provider.h
+++ b/chromium/components/variations/variations_http_header_provider.h
@@ -41,12 +41,19 @@ class VariationsHttpHeaderProvider : public base::FieldTrialList::Observer,
// a leading and trailing space, e.g. " 123 234 345 ".
std::string GetVariationsString();
+ // Forces the list of |variation_ids| (which will be modified by adding the
+ // comma-separated |command_line_variation_ids|). This is a wrapper function
+ // around SetDefaultVariationIds.
+ bool ForceVariationIds(
+ const std::string& command_line_variation_ids,
+ std::vector<std::string>* variation_ids);
+
// Sets *additional* variation ids and trigger variation ids to be encoded in
- // the X-Client-Data request header. This is intended for development use to
- // force a server side experiment id. |variation_ids| should be a
- // comma-separated string of numeric experiment ids. If an id is prefixed
- // with "t" it will be treated as a trigger experiment id.
- bool SetDefaultVariationIds(const std::string& variation_ids);
+ // the X-Client-Data request header. This is intended for development use to
+ // force a server side experiment id. |variation_ids| should be a list of
+ // strings of numeric experiment ids. If an id is prefixed with "t" it will
+ // be treated as a trigger experiment id.
+ bool SetDefaultVariationIds(const std::vector<std::string>& variation_ids);
// Resets any cached state for tests.
void ResetForTesting();
diff --git a/chromium/components/variations/variations_http_header_provider_unittest.cc b/chromium/components/variations/variations_http_header_provider_unittest.cc
index 90552c84476..a1b9d3da8fc 100644
--- a/chromium/components/variations/variations_http_header_provider_unittest.cc
+++ b/chromium/components/variations/variations_http_header_provider_unittest.cc
@@ -65,7 +65,7 @@ TEST_F(VariationsHttpHeaderProviderTest, SetDefaultVariationIds_Valid) {
VariationsHttpHeaderProvider provider;
// Valid experiment ids.
- EXPECT_TRUE(provider.SetDefaultVariationIds("12,456,t789"));
+ EXPECT_TRUE(provider.SetDefaultVariationIds({"12", "456", "t789"}));
provider.InitVariationIDsCacheIfNeeded();
std::string variations = provider.GetClientDataHeader();
EXPECT_FALSE(variations.empty());
@@ -83,12 +83,14 @@ TEST_F(VariationsHttpHeaderProviderTest, SetDefaultVariationIds_Invalid) {
VariationsHttpHeaderProvider provider;
// Invalid experiment ids.
- EXPECT_FALSE(provider.SetDefaultVariationIds("abcd12,456"));
+ EXPECT_FALSE(provider.SetDefaultVariationIds(
+ std::vector<std::string>{"abcd12", "456"}));
provider.InitVariationIDsCacheIfNeeded();
EXPECT_TRUE(provider.GetClientDataHeader().empty());
// Invalid trigger experiment id
- EXPECT_FALSE(provider.SetDefaultVariationIds("12,tabc456"));
+ EXPECT_FALSE(provider.SetDefaultVariationIds(
+ std::vector<std::string>{"12", "tabc456"}));
provider.InitVariationIDsCacheIfNeeded();
EXPECT_TRUE(provider.GetClientDataHeader().empty());
}
@@ -131,7 +133,10 @@ TEST_F(VariationsHttpHeaderProviderTest, GetVariationsString) {
CreateTrialAndAssociateId("t2", "g2", GOOGLE_WEB_PROPERTIES, 124);
VariationsHttpHeaderProvider provider;
- provider.SetDefaultVariationIds("100,200");
+ std::vector<std::string> ids;
+ ids.push_back("100");
+ ids.push_back("200");
+ provider.SetDefaultVariationIds(ids);
EXPECT_EQ(" 100 123 124 200 ", provider.GetVariationsString());
}
diff --git a/chromium/components/variations/variations_request_scheduler.cc b/chromium/components/variations/variations_request_scheduler.cc
index 08d39d10ce2..dfc39d9c138 100644
--- a/chromium/components/variations/variations_request_scheduler.cc
+++ b/chromium/components/variations/variations_request_scheduler.cc
@@ -47,7 +47,7 @@ void VariationsRequestScheduler::OnAppEnterForeground() {
base::TimeDelta VariationsRequestScheduler::GetFetchPeriod() const {
// The fetch interval can be overridden by a variation param.
std::string period_min_str =
- variations::GetVariationParamValue("VarationsServiceControl",
+ variations::GetVariationParamValue("VariationsServiceControl",
"fetch_period_min");
size_t period_min;
if (base::StringToSizeT(period_min_str, &period_min))
diff --git a/chromium/components/variations/variations_seed_processor_unittest.cc b/chromium/components/variations/variations_seed_processor_unittest.cc
index 1ab8a497a38..7703eed3b1a 100644
--- a/chromium/components/variations/variations_seed_processor_unittest.cc
+++ b/chromium/components/variations/variations_seed_processor_unittest.cc
@@ -17,10 +17,12 @@
#include "base/feature_list.h"
#include "base/format_macros.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
#include "components/variations/processed_study.h"
#include "components/variations/study_filtering.h"
#include "components/variations/variations_associated_data.h"
@@ -117,8 +119,6 @@ class VariationsSeedProcessorTest : public ::testing::Test {
// process singletons.
testing::ClearAllVariationIDs();
testing::ClearAllVariationParams();
-
- base::FeatureList::ClearInstanceForTesting();
}
bool CreateTrialFromStudy(const Study& study) {
@@ -621,7 +621,6 @@ TEST_F(VariationsSeedProcessorTest, FeatureEnabledOrDisableByTrial) {
SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
base::FieldTrialList field_trial_list(nullptr);
- base::FeatureList::ClearInstanceForTesting();
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Study study;
@@ -638,7 +637,8 @@ TEST_F(VariationsSeedProcessorTest, FeatureEnabledOrDisableByTrial) {
association->add_disable_feature(test_case.disable_feature);
EXPECT_TRUE(CreateTrialFromStudyWithFeatureList(study, feature_list.get()));
- base::FeatureList::SetInstance(std::move(feature_list));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatureList(std::move(feature_list));
// |kUnrelatedFeature| should not be affected.
EXPECT_FALSE(base::FeatureList::IsEnabled(kUnrelatedFeature));
@@ -744,7 +744,6 @@ TEST_F(VariationsSeedProcessorTest, FeatureAssociationAndForcing) {
test_case.disable_features_command_line, static_cast<int>(group)));
base::FieldTrialList field_trial_list(nullptr);
- base::FeatureList::ClearInstanceForTesting();
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
feature_list->InitializeFromCommandLine(
test_case.enable_features_command_line,
@@ -773,7 +772,8 @@ TEST_F(VariationsSeedProcessorTest, FeatureAssociationAndForcing) {
->set_forcing_feature_off(test_case.feature.name);
EXPECT_TRUE(CreateTrialFromStudyWithFeatureList(study, feature_list.get()));
- base::FeatureList::SetInstance(std::move(feature_list));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatureList(std::move(feature_list));
// Trial should not be activated initially, but later might get activated
// depending on the expected values.
@@ -814,7 +814,6 @@ TEST_F(VariationsSeedProcessorTest, FeaturesInExpiredStudies) {
base::StringPrintf("Test[%" PRIuS "]: %s", i, test_case.feature.name));
base::FieldTrialList field_trial_list(nullptr);
- base::FeatureList::ClearInstanceForTesting();
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
feature_list->InitializeFromCommandLine(std::string(), std::string());
@@ -837,7 +836,8 @@ TEST_F(VariationsSeedProcessorTest, FeaturesInExpiredStudies) {
}
EXPECT_TRUE(CreateTrialFromStudyWithFeatureList(study, feature_list.get()));
- base::FeatureList::SetInstance(std::move(feature_list));
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatureList(std::move(feature_list));
// Tthe feature should not be enabled, because the study is expired.
EXPECT_EQ(test_case.expected_feature_enabled,
@@ -868,11 +868,8 @@ TEST_F(VariationsSeedProcessorTest, LowEntropyStudyTest) {
// An entorpy value of 0.1 will cause the AA group to be chosen, since AA is
// the only non-default group, and has a probability percent above 0.1.
- base::MockEntropyProvider* mock_high_entropy_provider =
- new base::MockEntropyProvider(0.1);
-
- // The field trial list takes ownership of the provider.
- base::FieldTrialList field_trial_list(mock_high_entropy_provider);
+ base::FieldTrialList field_trial_list(
+ base::MakeUnique<base::MockEntropyProvider>(0.1));
// Use a stack instance, since nothing takes ownership of this provider.
// This entropy value will cause the default group to be chosen since it's a
diff --git a/chromium/components/variations/variations_seed_store.cc b/chromium/components/variations/variations_seed_store.cc
index 65b1efd1b5c..8067651b435 100644
--- a/chromium/components/variations/variations_seed_store.cc
+++ b/chromium/components/variations/variations_seed_store.cc
@@ -112,7 +112,10 @@ base::Time TruncateToUTCDay(const base::Time& time) {
exploded.second = 0;
exploded.millisecond = 0;
- return base::Time::FromUTCExploded(exploded);
+ base::Time out_time;
+ bool conversion_success = base::Time::FromUTCExploded(exploded, &out_time);
+ DCHECK(conversion_success);
+ return out_time;
}
VariationsSeedDateChangeState GetSeedDateChangeState(
diff --git a/chromium/components/variations/variations_url_constants.cc b/chromium/components/variations/variations_url_constants.cc
index dce446a641b..f530ff5cc93 100644
--- a/chromium/components/variations/variations_url_constants.cc
+++ b/chromium/components/variations/variations_url_constants.cc
@@ -4,10 +4,17 @@
#include "components/variations/variations_url_constants.h"
+#include "build/build_config.h"
+
namespace variations {
// Default server of Variations seed info.
+#if defined(OS_ANDROID)
+const char kDefaultServerUrl[] =
+ "https://clientservices.googleapis.com/chrome-variations/seed";
+#else
const char kDefaultServerUrl[] =
"https://clients4.google.com/chrome-variations/seed";
+#endif
} // namespace variations
diff --git a/chromium/components/version_info.gypi b/chromium/components/version_info.gypi
deleted file mode 100644
index d81d85d3935..00000000000
--- a/chromium/components/version_info.gypi
+++ /dev/null
@@ -1,94 +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.
-
-{
- 'variables': {
- 'conditions': [
- ['branding == "Chrome"', {
- 'use_unofficial_version_number%': 0,
- }, {
- 'use_unofficial_version_number%': 1,
- }],
- ],
- },
- 'targets': [
- {
- # GN version: //components/version_info
- 'target_name': 'version_info',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'components_strings.gyp:components_strings',
- 'generate_version_info',
- ],
- 'sources': [
- 'version_info/version_info.cc',
- 'version_info/version_info.h',
- ],
- 'conditions': [
- ['use_unofficial_version_number==1', {
- 'dependencies': [
- '../ui/base/ui_base.gyp:ui_base',
- ],
- 'defines': ['USE_UNOFFICIAL_VERSION_NUMBER'],
- }],
- ],
- },
- {
- # GN version: //components/version_info:generate_version
- 'target_name': 'generate_version_info',
- 'type': 'none',
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)',
- ],
- },
- # Because generate_version_info generates a header, the target must set
- # the hard_dependency flag.
- 'hard_dependency': 1,
- 'actions': [
- {
- 'action_name': 'generation_version_info',
- 'message': 'Generating version information',
- 'variables': {
- 'extra_version_flags': [],
- 'lastchange_path': '../build/util/LASTCHANGE',
- 'version_py_path': '../build/util/version.py',
- 'template_input_path': 'version_info/version_info_values.h.version',
- # Use VERSION and BRANDING files from //chrome even if this is bad
- # dependency until they are moved to src/ for VERSION and to the
- # version_info component for BRANDING. Synchronisation with TPM and
- # all release script is required for thoses moves. They are tracked
- # by issues http://crbug.com/512347 and http://crbug.com/513603.
- 'version_path': '../chrome/VERSION',
- 'branding_path': '../chrome/app/theme/<(branding_path_component)/BRANDING',
- },
- 'inputs': [
- '<(version_py_path)',
- '<(template_input_path)',
- '<(version_path)',
- '<(branding_path)',
- '<(lastchange_path)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/components/version_info/version_info_values.h',
- ],
- 'action': [
- 'python',
- '<(version_py_path)',
- '-f', '<(version_path)',
- '-f', '<(branding_path)',
- '-f', '<(lastchange_path)',
- '<@(extra_version_flags)',
- '<(template_input_path)',
- '<@(_outputs)',
- ],
- },
- ],
- },
- ],
-}
diff --git a/chromium/components/version_info/BUILD.gn b/chromium/components/version_info/BUILD.gn
index 6c043e53a91..5dbee5f87a5 100644
--- a/chromium/components/version_info/BUILD.gn
+++ b/chromium/components/version_info/BUILD.gn
@@ -3,13 +3,14 @@
# found in the LICENSE file.
import("//build/config/chrome_build.gni")
-import("//chrome/version.gni")
+import("//build/util/process_version.gni")
+import("//chrome/process_version_rc_template.gni") # For branding_file_path.
declare_args() {
use_unofficial_version_number = !is_chrome_branded
}
-source_set("version_info") {
+static_library("version_info") {
sources = [
"version_info.cc",
"version_info.h",
@@ -29,5 +30,10 @@ source_set("version_info") {
process_version("generate_version_info") {
template_file = "version_info_values.h.version"
+ sources = [
+ "//build/util/LASTCHANGE",
+ "//chrome/VERSION",
+ branding_file_path,
+ ]
output = "$target_gen_dir/version_info_values.h"
}
diff --git a/chromium/components/version_ui.gypi b/chromium/components/version_ui.gypi
deleted file mode 100644
index 9212ce159ff..00000000000
--- a/chromium/components/version_ui.gypi
+++ /dev/null
@@ -1,27 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/version_ui
- 'target_name': 'version_ui',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'variations',
- '../base/base.gyp:base',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'version_ui/version_handler_helper.cc',
- 'version_ui/version_handler_helper.h',
- 'version_ui/version_ui_constants.cc',
- 'version_ui/version_ui_constants.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/version_ui/BUILD.gn b/chromium/components/version_ui/BUILD.gn
index a6693b67eae..91b80b27a72 100644
--- a/chromium/components/version_ui/BUILD.gn
+++ b/chromium/components/version_ui/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("version_ui") {
+static_library("version_ui") {
sources = [
"version_handler_helper.cc",
"version_handler_helper.h",
diff --git a/chromium/components/version_ui/resources/about_version.html b/chromium/components/version_ui/resources/about_version.html
index 066fb2afc97..9900014c133 100644
--- a/chromium/components/version_ui/resources/about_version.html
+++ b/chromium/components/version_ui/resources/about_version.html
@@ -77,9 +77,6 @@ about:version template page
</td>
</tr>
<if expr="not is_ios">
- <tr><td class="label">Blink</td>
- <td class="version" id="blink_version" i18n-content="blink_version"></td>
- </tr>
<tr><td class="label">JavaScript</td>
<td class="version" id="js_engine">
<span i18n-content="js_engine"></span>
diff --git a/chromium/components/version_ui/version_ui_constants.cc b/chromium/components/version_ui/version_ui_constants.cc
index 410e496203a..b60803c9415 100644
--- a/chromium/components/version_ui/version_ui_constants.cc
+++ b/chromium/components/version_ui/version_ui_constants.cc
@@ -19,7 +19,6 @@ const char kReturnVariationInfo[] = "returnVariationInfo";
// Strings.
const char kApplicationLabel[] = "application_label";
const char kARC[] = "arc_label";
-const char kBlinkVersion[] = "blink_version";
const char kCL[] = "cl";
const char kCommandLine[] = "command_line";
const char kCommandLineName[] = "command_line_name";
diff --git a/chromium/components/visitedlink.gypi b/chromium/components/visitedlink.gypi
deleted file mode 100644
index bca40f2f9b5..00000000000
--- a/chromium/components/visitedlink.gypi
+++ /dev/null
@@ -1,66 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'visitedlink_common',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../ipc/ipc.gyp:ipc',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'visitedlink/common/visitedlink_common.cc',
- 'visitedlink/common/visitedlink_common.h',
- 'visitedlink/common/visitedlink_message_generator.cc',
- 'visitedlink/common/visitedlink_message_generator.h',
- 'visitedlink/common/visitedlink_messages.h',
- ],
- },
- {
- 'target_name': 'visitedlink_browser',
- 'type': 'static_library',
- 'include_dirs': [
- '../skia/config',
- ],
- 'dependencies': [
- 'visitedlink_common',
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- ],
- 'sources': [
- 'visitedlink/browser/visitedlink_delegate.h',
- 'visitedlink/browser/visitedlink_event_listener.cc',
- 'visitedlink/browser/visitedlink_event_listener.h',
- 'visitedlink/browser/visitedlink_master.cc',
- 'visitedlink/browser/visitedlink_master.h',
- ],
- }
- ],
- 'conditions': [
- ['OS != "ios"', {
- 'targets': [
- {
- 'target_name': 'visitedlink_renderer',
- 'type': 'static_library',
- 'dependencies': [
- 'visitedlink_common',
- '../base/base.gyp:base',
- '../content/content.gyp:content_common',
- '../content/content.gyp:content_renderer',
- '../third_party/WebKit/public/blink.gyp:blink',
- ],
- 'sources': [
- 'visitedlink/renderer/visitedlink_slave.cc',
- 'visitedlink/renderer/visitedlink_slave.h',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/visitedlink/DEPS b/chromium/components/visitedlink/DEPS
index 1c40d981eb6..e7d54f924c0 100644
--- a/chromium/components/visitedlink/DEPS
+++ b/chromium/components/visitedlink/DEPS
@@ -1,3 +1,5 @@
include_rules = [
- "+ipc",
+ "+mojo/public",
+ "+content/public/common",
+ "+services/shell/public",
]
diff --git a/chromium/components/visitedlink/browser/BUILD.gn b/chromium/components/visitedlink/browser/BUILD.gn
index a8ce9ea7f6c..49796fd4ff1 100644
--- a/chromium/components/visitedlink/browser/BUILD.gn
+++ b/chromium/components/visitedlink/browser/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser") {
+static_library("browser") {
sources = [
"visitedlink_delegate.h",
"visitedlink_event_listener.cc",
diff --git a/chromium/components/visitedlink/browser/visitedlink_event_listener.cc b/chromium/components/visitedlink/browser/visitedlink_event_listener.cc
index dd9c9f77fca..37cdcd502a3 100644
--- a/chromium/components/visitedlink/browser/visitedlink_event_listener.cc
+++ b/chromium/components/visitedlink/browser/visitedlink_event_listener.cc
@@ -4,13 +4,14 @@
#include "components/visitedlink/browser/visitedlink_event_listener.h"
-#include "base/memory/shared_memory.h"
+#include "base/bind.h"
#include "components/visitedlink/browser/visitedlink_delegate.h"
-#include "components/visitedlink/common/visitedlink_messages.h"
+#include "components/visitedlink/common/visitedlink.mojom.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host.h"
+#include "services/shell/public/cpp/interface_provider.h"
using base::Time;
using base::TimeDelta;
@@ -19,7 +20,7 @@ using content::RenderWidgetHost;
namespace {
// The amount of time we wait to accumulate visited link additions.
-const int kCommitIntervalMs = 100;
+constexpr int kCommitIntervalMs = 100;
// Size of the buffer after which individual link updates deemed not warranted
// and the overall update should be used instead.
@@ -42,20 +43,18 @@ class VisitedLinkUpdater {
explicit VisitedLinkUpdater(int render_process_id)
: reset_needed_(false),
invalidate_hashes_(false),
- render_process_id_(render_process_id) {}
+ render_process_id_(render_process_id) {
+ content::RenderProcessHost::FromID(render_process_id)
+ ->GetRemoteInterfaces()
+ ->GetInterface(&sink_);
+ }
// Informs the renderer about a new visited link table.
- void SendVisitedLinkTable(base::SharedMemory* table_memory) {
- content::RenderProcessHost* process =
- content::RenderProcessHost::FromID(render_process_id_);
- if (!process)
- return; // Happens in tests
- base::SharedMemoryHandle handle_for_process;
- table_memory->ShareReadOnlyToProcess(process->GetHandle(),
- &handle_for_process);
- if (base::SharedMemory::IsHandleValid(handle_for_process))
- process->Send(new ChromeViewMsg_VisitedLink_NewTable(
- handle_for_process));
+ void SendVisitedLinkTable(mojo::SharedBufferHandle table) {
+ mojo::ScopedSharedBufferHandle client_table =
+ table.Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY);
+ if (client_table.is_valid())
+ sink_->UpdateVisitedLinks(std::move(client_table));
}
// Buffers |links| to update, but doesn't actually relay them.
@@ -98,7 +97,7 @@ class VisitedLinkUpdater {
return;
if (reset_needed_) {
- process->Send(new ChromeViewMsg_VisitedLink_Reset(invalidate_hashes_));
+ sink_->ResetVisitedLinks(invalidate_hashes_);
reset_needed_ = false;
invalidate_hashes_ = false;
return;
@@ -107,7 +106,7 @@ class VisitedLinkUpdater {
if (pending_.empty())
return;
- process->Send(new ChromeViewMsg_VisitedLink_Add(pending_));
+ sink_->AddVisitedLinks(pending_);
pending_.clear();
}
@@ -116,13 +115,13 @@ class VisitedLinkUpdater {
bool reset_needed_;
bool invalidate_hashes_;
int render_process_id_;
+ mojom::VisitedLinkNotificationSinkPtr sink_;
VisitedLinkCommon::Fingerprints pending_;
};
VisitedLinkEventListener::VisitedLinkEventListener(
- VisitedLinkMaster* master,
content::BrowserContext* browser_context)
- : master_(master),
+ : coalesce_timer_(&default_coalesce_timer_),
browser_context_(browser_context) {
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
content::NotificationService::AllBrowserContextsAndSources());
@@ -137,8 +136,10 @@ VisitedLinkEventListener::~VisitedLinkEventListener() {
pending_visited_links_.clear();
}
-void VisitedLinkEventListener::NewTable(base::SharedMemory* table_memory) {
- if (!table_memory)
+void VisitedLinkEventListener::NewTable(mojo::SharedBufferHandle table) {
+ DCHECK(table.is_valid());
+ shared_memory_ = table.Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY);
+ if (!shared_memory_.is_valid())
return;
// Send to all RenderProcessHosts.
@@ -149,23 +150,24 @@ void VisitedLinkEventListener::NewTable(base::SharedMemory* table_memory) {
if (!process)
continue;
- i->second->SendVisitedLinkTable(table_memory);
+ i->second->SendVisitedLinkTable(shared_memory_.get());
}
}
void VisitedLinkEventListener::Add(VisitedLinkMaster::Fingerprint fingerprint) {
pending_visited_links_.push_back(fingerprint);
- if (!coalesce_timer_.IsRunning()) {
- coalesce_timer_.Start(FROM_HERE,
- TimeDelta::FromMilliseconds(kCommitIntervalMs), this,
- &VisitedLinkEventListener::CommitVisitedLinks);
+ if (!coalesce_timer_->IsRunning()) {
+ coalesce_timer_->Start(
+ FROM_HERE, TimeDelta::FromMilliseconds(kCommitIntervalMs),
+ base::Bind(&VisitedLinkEventListener::CommitVisitedLinks,
+ base::Unretained(this)));
}
}
void VisitedLinkEventListener::Reset(bool invalidate_hashes) {
pending_visited_links_.clear();
- coalesce_timer_.Stop();
+ coalesce_timer_->Stop();
for (Updaters::iterator i = updaters_.begin(); i != updaters_.end(); ++i) {
i->second->AddReset(invalidate_hashes);
@@ -173,6 +175,11 @@ void VisitedLinkEventListener::Reset(bool invalidate_hashes) {
}
}
+void VisitedLinkEventListener::SetCoalesceTimerForTest(
+ base::Timer* coalesce_timer_override) {
+ coalesce_timer_ = coalesce_timer_override;
+}
+
void VisitedLinkEventListener::CommitVisitedLinks() {
// Send to all RenderProcessHosts.
for (Updaters::iterator i = updaters_.begin(); i != updaters_.end(); ++i) {
@@ -195,13 +202,12 @@ void VisitedLinkEventListener::Observe(
return;
// Happens on browser start up.
- if (!master_->shared_memory())
+ if (!shared_memory_.is_valid())
return;
- updaters_[process->GetID()] =
- make_linked_ptr(new VisitedLinkUpdater(process->GetID()));
- updaters_[process->GetID()]->SendVisitedLinkTable(
- master_->shared_memory());
+ updaters_[process->GetID()].reset(
+ new VisitedLinkUpdater(process->GetID()));
+ updaters_[process->GetID()]->SendVisitedLinkTable(shared_memory_.get());
break;
}
case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
diff --git a/chromium/components/visitedlink/browser/visitedlink_event_listener.h b/chromium/components/visitedlink/browser/visitedlink_event_listener.h
index 7439471bdef..15b4dd844f8 100644
--- a/chromium/components/visitedlink/browser/visitedlink_event_listener.h
+++ b/chromium/components/visitedlink/browser/visitedlink_event_listener.h
@@ -6,18 +6,14 @@
#define COMPONENTS_VISITEDLINK_BROWSER_VISITEDLINK_EVENT_LISTENER_H_
#include <map>
+#include <memory>
#include "base/macros.h"
-#include "base/memory/linked_ptr.h"
#include "base/timer/timer.h"
#include "components/visitedlink/browser/visitedlink_master.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-namespace base {
-class SharedMemory;
-}
-
namespace content {
class BrowserContext;
}
@@ -32,14 +28,17 @@ class VisitedLinkUpdater;
class VisitedLinkEventListener : public VisitedLinkMaster::Listener,
public content::NotificationObserver {
public:
- VisitedLinkEventListener(VisitedLinkMaster* master,
- content::BrowserContext* browser_context);
+ explicit VisitedLinkEventListener(content::BrowserContext* browser_context);
~VisitedLinkEventListener() override;
- void NewTable(base::SharedMemory* table_memory) override;
+ void NewTable(mojo::SharedBufferHandle table) override;
void Add(VisitedLinkMaster::Fingerprint fingerprint) override;
void Reset(bool invalidate_hashes) override;
+ // Sets a custom timer to use for coalescing events for testing.
+ // |coalesce_timer_override| must outlive this.
+ void SetCoalesceTimerForTest(base::Timer* coalesce_timer_override);
+
private:
void CommitVisitedLinks();
@@ -48,16 +47,22 @@ class VisitedLinkEventListener : public VisitedLinkMaster::Listener,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
- base::OneShotTimer coalesce_timer_;
+ // The default Timer to use for coalescing events. This should not be used
+ // directly to allow overriding it in tests. Instead, |coalesce_timer_|
+ // should be used.
+ base::OneShotTimer default_coalesce_timer_;
+ // A pointer to either |default_coalesce_timer_| or to an override set using
+ // SetCoalesceTimerForTest(). This does not own the timer.
+ base::Timer* coalesce_timer_;
VisitedLinkCommon::Fingerprints pending_visited_links_;
content::NotificationRegistrar registrar_;
// Map between renderer child ids and their VisitedLinkUpdater.
- typedef std::map<int, linked_ptr<VisitedLinkUpdater> > Updaters;
+ typedef std::map<int, std::unique_ptr<VisitedLinkUpdater>> Updaters;
Updaters updaters_;
- VisitedLinkMaster* master_;
+ mojo::ScopedSharedBufferHandle shared_memory_;
// Used to filter RENDERER_PROCESS_CREATED notifications to renderers that
// belong to this BrowserContext.
diff --git a/chromium/components/visitedlink/browser/visitedlink_master.cc b/chromium/components/visitedlink/browser/visitedlink_master.cc
index 792c7507a21..0447c15a85c 100644
--- a/chromium/components/visitedlink/browser/visitedlink_master.cc
+++ b/chromium/components/visitedlink/browser/visitedlink_master.cc
@@ -16,6 +16,7 @@
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/rand_util.h"
#include "base/strings/string_util.h"
@@ -62,7 +63,8 @@ namespace {
// It is not necessary to generate a cryptographically strong random string,
// only that it be reasonably different for different users.
void GenerateSalt(uint8_t salt[LINK_SALT_LENGTH]) {
- DCHECK_EQ(LINK_SALT_LENGTH, 8) << "This code assumes the length of the salt";
+ static_assert(LINK_SALT_LENGTH == 8,
+ "This code assumes the length of the salt");
uint64_t randval = base::RandUint64();
memcpy(salt, &randval, 8);
}
@@ -123,15 +125,15 @@ void AsyncClose(FILE** file) {
struct VisitedLinkMaster::LoadFromFileResult
: public base::RefCountedThreadSafe<LoadFromFileResult> {
LoadFromFileResult(base::ScopedFILE file,
- std::unique_ptr<base::SharedMemory> shared_memory,
- Fingerprint* hash_table,
+ mojo::ScopedSharedBufferHandle shared_memory,
+ mojo::ScopedSharedBufferMapping hash_table,
int32_t num_entries,
int32_t used_count,
uint8_t salt[LINK_SALT_LENGTH]);
base::ScopedFILE file;
- std::unique_ptr<base::SharedMemory> shared_memory;
- Fingerprint* hash_table;
+ mojo::ScopedSharedBufferHandle shared_memory;
+ mojo::ScopedSharedBufferMapping hash_table;
int32_t num_entries;
int32_t used_count;
uint8_t salt[LINK_SALT_LENGTH];
@@ -145,14 +147,14 @@ struct VisitedLinkMaster::LoadFromFileResult
VisitedLinkMaster::LoadFromFileResult::LoadFromFileResult(
base::ScopedFILE file,
- std::unique_ptr<base::SharedMemory> shared_memory,
- Fingerprint* hash_table,
+ mojo::ScopedSharedBufferHandle shared_memory,
+ mojo::ScopedSharedBufferMapping hash_table,
int32_t num_entries,
int32_t used_count,
uint8_t salt[LINK_SALT_LENGTH])
: file(std::move(file)),
shared_memory(std::move(shared_memory)),
- hash_table(hash_table),
+ hash_table(std::move(hash_table)),
num_entries(num_entries),
used_count(used_count) {
memcpy(this->salt, salt, LINK_SALT_LENGTH);
@@ -224,7 +226,7 @@ VisitedLinkMaster::VisitedLinkMaster(content::BrowserContext* browser_context,
bool persist_to_disk)
: browser_context_(browser_context),
delegate_(delegate),
- listener_(new VisitedLinkEventListener(this, browser_context)),
+ listener_(base::MakeUnique<VisitedLinkEventListener>(browser_context)),
persist_to_disk_(persist_to_disk),
table_is_loading_from_file_(false),
weak_ptr_factory_(this) {
@@ -277,7 +279,6 @@ VisitedLinkMaster::~VisitedLinkMaster() {
void VisitedLinkMaster::InitMembers() {
file_ = NULL;
- shared_memory_ = NULL;
shared_memory_serial_ = 0;
used_items_ = 0;
table_size_override_ = 0;
@@ -294,6 +295,9 @@ bool VisitedLinkMaster::Init() {
if (!CreateURLTable(DefaultTableSize()))
return false;
+ if (shared_memory_.is_valid())
+ listener_->NewTable(shared_memory_.get());
+
#ifndef NDEBUG
DebugValidate();
#endif
@@ -662,19 +666,20 @@ bool VisitedLinkMaster::LoadApartFromFile(
return false; // Header isn't valid.
// Allocate and read the table.
- std::unique_ptr<base::SharedMemory> shared_memory;
- VisitedLinkCommon::Fingerprint* hash_table;
+ mojo::ScopedSharedBufferHandle shared_memory;
+ mojo::ScopedSharedBufferMapping hash_table;
if (!CreateApartURLTable(num_entries, salt, &shared_memory, &hash_table))
return false;
- if (!ReadFromFile(file_closer.get(), kFileHeaderSize, hash_table,
+ if (!ReadFromFile(file_closer.get(), kFileHeaderSize,
+ GetHashTableFromMapping(hash_table),
num_entries * sizeof(Fingerprint))) {
return false;
}
- *load_from_file_result =
- new LoadFromFileResult(std::move(file_closer), std::move(shared_memory),
- hash_table, num_entries, used_count, salt);
+ *load_from_file_result = new LoadFromFileResult(
+ std::move(file_closer), std::move(shared_memory), std::move(hash_table),
+ num_entries, used_count, salt);
return true;
}
@@ -715,9 +720,9 @@ void VisitedLinkMaster::OnTableLoadComplete(
DCHECK(load_from_file_result.get());
// Delete the previous table.
- DCHECK(shared_memory_);
- delete shared_memory_;
- shared_memory_ = nullptr;
+ DCHECK(shared_memory_.is_valid());
+ shared_memory_.reset();
+ hash_table_mapping_.reset();
// Assign the open file.
DCHECK(!file_);
@@ -726,11 +731,12 @@ void VisitedLinkMaster::OnTableLoadComplete(
*file_ = load_from_file_result->file.release();
// Assign the loaded table.
- DCHECK(load_from_file_result->shared_memory.get());
+ DCHECK(load_from_file_result->shared_memory.is_valid());
DCHECK(load_from_file_result->hash_table);
memcpy(salt_, load_from_file_result->salt, LINK_SALT_LENGTH);
- shared_memory_ = load_from_file_result->shared_memory.release();
- hash_table_ = load_from_file_result->hash_table;
+ shared_memory_ = std::move(load_from_file_result->shared_memory);
+ hash_table_mapping_ = std::move(load_from_file_result->hash_table);
+ hash_table_ = GetHashTableFromMapping(hash_table_mapping_);
table_length_ = load_from_file_result->num_entries;
used_items_ = load_from_file_result->used_count;
@@ -739,7 +745,7 @@ void VisitedLinkMaster::OnTableLoadComplete(
#endif
// Send an update notification to all child processes.
- listener_->NewTable(shared_memory_);
+ listener_->NewTable(shared_memory_.get());
if (!added_since_load_.empty() || !deleted_since_load_.empty()) {
// Resize the table if the table doesn't have enough capacity.
@@ -859,11 +865,12 @@ bool VisitedLinkMaster::GetDatabaseFileName(base::FilePath* filename) {
// Initializes the shared memory structure. The salt should already be filled
// in so that it can be written to the shared memory
bool VisitedLinkMaster::CreateURLTable(int32_t num_entries) {
- std::unique_ptr<base::SharedMemory> shared_memory;
- VisitedLinkCommon::Fingerprint* hash_table;
+ mojo::ScopedSharedBufferHandle shared_memory;
+ mojo::ScopedSharedBufferMapping hash_table;
if (CreateApartURLTable(num_entries, salt_, &shared_memory, &hash_table)) {
- shared_memory_ = shared_memory.release();
- hash_table_ = hash_table;
+ shared_memory_ = std::move(shared_memory);
+ hash_table_mapping_ = std::move(hash_table);
+ hash_table_ = GetHashTableFromMapping(hash_table_mapping_);
table_length_ = num_entries;
used_items_ = 0;
return true;
@@ -876,8 +883,8 @@ bool VisitedLinkMaster::CreateURLTable(int32_t num_entries) {
bool VisitedLinkMaster::CreateApartURLTable(
int32_t num_entries,
const uint8_t salt[LINK_SALT_LENGTH],
- std::unique_ptr<base::SharedMemory>* shared_memory,
- VisitedLinkCommon::Fingerprint** hash_table) {
+ mojo::ScopedSharedBufferHandle* shared_memory,
+ mojo::ScopedSharedBufferMapping* hash_table) {
DCHECK(salt);
DCHECK(shared_memory);
DCHECK(hash_table);
@@ -887,41 +894,38 @@ bool VisitedLinkMaster::CreateApartURLTable(
num_entries * sizeof(Fingerprint) + sizeof(SharedHeader);
// Create the shared memory object.
- std::unique_ptr<base::SharedMemory> sh_mem(new base::SharedMemory());
- if (!sh_mem)
+ mojo::ScopedSharedBufferHandle shared_buffer =
+ mojo::SharedBufferHandle::Create(alloc_size);
+ if (!shared_buffer.is_valid())
return false;
-
- base::SharedMemoryCreateOptions options;
- options.size = alloc_size;
- options.share_read_only = true;
-
- if (!sh_mem->Create(options) || !sh_mem->Map(alloc_size))
+ mojo::ScopedSharedBufferMapping hash_table_mapping =
+ shared_buffer->Map(alloc_size);
+ if (!hash_table_mapping)
return false;
- memset(sh_mem->memory(), 0, alloc_size);
+ memset(hash_table_mapping.get(), 0, alloc_size);
// Save the header for other processes to read.
- SharedHeader* header = static_cast<SharedHeader*>(sh_mem->memory());
+ SharedHeader* header = static_cast<SharedHeader*>(hash_table_mapping.get());
header->length = num_entries;
memcpy(header->salt, salt, LINK_SALT_LENGTH);
- // Our table pointer is just the data immediately following the size.
- *hash_table = reinterpret_cast<Fingerprint*>(
- static_cast<char*>(sh_mem->memory()) + sizeof(SharedHeader));
-
- *shared_memory = std::move(sh_mem);
+ *shared_memory = std::move(shared_buffer);
+ *hash_table = std::move(hash_table_mapping);
return true;
}
bool VisitedLinkMaster::BeginReplaceURLTable(int32_t num_entries) {
- base::SharedMemory *old_shared_memory = shared_memory_;
- Fingerprint* old_hash_table = hash_table_;
+ mojo::ScopedSharedBufferHandle old_shared_memory = std::move(shared_memory_);
+ mojo::ScopedSharedBufferMapping old_hash_table_mapping =
+ std::move(hash_table_mapping_);
int32_t old_table_length = table_length_;
if (!CreateURLTable(num_entries)) {
// Try to put back the old state.
- shared_memory_ = old_shared_memory;
- hash_table_ = old_hash_table;
+ shared_memory_ = std::move(old_shared_memory);
+ hash_table_mapping_ = std::move(old_hash_table_mapping);
+ hash_table_ = GetHashTableFromMapping(hash_table_mapping_);
table_length_ = old_table_length;
return false;
}
@@ -934,10 +938,8 @@ bool VisitedLinkMaster::BeginReplaceURLTable(int32_t num_entries) {
}
void VisitedLinkMaster::FreeURLTable() {
- if (shared_memory_) {
- delete shared_memory_;
- shared_memory_ = NULL;
- }
+ shared_memory_.reset();
+ hash_table_mapping_.reset();
if (!persist_to_disk_ || !file_)
return;
PostIOTask(FROM_HERE, base::Bind(&AsyncClose, file_));
@@ -970,34 +972,37 @@ bool VisitedLinkMaster::ResizeTableIfNecessary() {
}
void VisitedLinkMaster::ResizeTable(int32_t new_size) {
- DCHECK(shared_memory_ && shared_memory_->memory() && hash_table_);
+ DCHECK(shared_memory_.is_valid() && hash_table_mapping_);
shared_memory_serial_++;
#ifndef NDEBUG
DebugValidate();
#endif
- base::SharedMemory* old_shared_memory = shared_memory_;
- Fingerprint* old_hash_table = hash_table_;
+ mojo::ScopedSharedBufferMapping old_hash_table_mapping =
+ std::move(hash_table_mapping_);
int32_t old_table_length = table_length_;
- if (!BeginReplaceURLTable(new_size))
+ if (!BeginReplaceURLTable(new_size)) {
+ hash_table_mapping_ = std::move(old_hash_table_mapping);
+ hash_table_ = GetHashTableFromMapping(hash_table_mapping_);
return;
-
- // Now we have two tables, our local copy which is the old one, and the new
- // one loaded into this object where we need to copy the data.
- for (int32_t i = 0; i < old_table_length; i++) {
- Fingerprint cur = old_hash_table[i];
- if (cur)
- AddFingerprint(cur, false);
}
-
- // On error unmapping, just forget about it since we can't do anything
- // else to release it.
- delete old_shared_memory;
+ {
+ Fingerprint* old_hash_table =
+ GetHashTableFromMapping(old_hash_table_mapping);
+ // Now we have two tables, our local copy which is the old one, and the new
+ // one loaded into this object where we need to copy the data.
+ for (int32_t i = 0; i < old_table_length; i++) {
+ Fingerprint cur = old_hash_table[i];
+ if (cur)
+ AddFingerprint(cur, false);
+ }
+ }
+ old_hash_table_mapping.reset();
// Send an update notification to all child processes so they read the new
// table.
- listener_->NewTable(shared_memory_);
+ listener_->NewTable(shared_memory_.get());
#ifndef NDEBUG
DebugValidate();
@@ -1065,16 +1070,9 @@ void VisitedLinkMaster::OnTableRebuildComplete(
// Replace the old table with a new blank one.
shared_memory_serial_++;
- // We are responsible for freeing it AFTER it has been replaced if
- // replacement succeeds.
- base::SharedMemory* old_shared_memory = shared_memory_;
-
int new_table_size = NewTableSizeForCount(
static_cast<int>(fingerprints.size() + added_since_rebuild_.size()));
if (BeginReplaceURLTable(new_table_size)) {
- // Free the old table.
- delete old_shared_memory;
-
// Add the stored fingerprints to the hash table.
for (const auto& fingerprint : fingerprints)
AddFingerprint(fingerprint, false);
@@ -1092,7 +1090,7 @@ void VisitedLinkMaster::OnTableRebuildComplete(
deleted_since_rebuild_.clear();
// Send an update notification to all child processes.
- listener_->NewTable(shared_memory_);
+ listener_->NewTable(shared_memory_.get());
// All tabs which was loaded when table was being rebuilt
// invalidate their links again.
listener_->Reset(false);
@@ -1201,4 +1199,13 @@ void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() {
master_->OnTableRebuildComplete(success_, fingerprints_);
}
+// static
+VisitedLinkCommon::Fingerprint* VisitedLinkMaster::GetHashTableFromMapping(
+ const mojo::ScopedSharedBufferMapping& hash_table_mapping) {
+ DCHECK(hash_table_mapping);
+ // Our table pointer is just the data immediately following the header.
+ return reinterpret_cast<Fingerprint*>(
+ static_cast<char*>(hash_table_mapping.get()) + sizeof(SharedHeader));
+}
+
} // namespace visitedlink
diff --git a/chromium/components/visitedlink/browser/visitedlink_master.h b/chromium/components/visitedlink/browser/visitedlink_master.h
index f7f4ca56b16..6eb50972bdd 100644
--- a/chromium/components/visitedlink/browser/visitedlink_master.h
+++ b/chromium/components/visitedlink/browser/visitedlink_master.h
@@ -18,11 +18,11 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/sequenced_worker_pool.h"
#include "build/build_config.h"
#include "components/visitedlink/common/visitedlink_common.h"
+#include "mojo/public/cpp/system/buffer.h"
#if defined(OS_WIN)
#include <windows.h>
@@ -58,7 +58,7 @@ class VisitedLinkMaster : public VisitedLinkCommon {
// Called when link coloring database has been created or replaced. The
// argument is the new table handle.
- virtual void NewTable(base::SharedMemory*) = 0;
+ virtual void NewTable(mojo::SharedBufferHandle table) = 0;
// Called when new link has been added. The argument is the fingerprint
// (hash) of the link.
@@ -105,7 +105,9 @@ class VisitedLinkMaster : public VisitedLinkCommon {
// object won't work.
bool Init();
- base::SharedMemory* shared_memory() { return shared_memory_; }
+ const mojo::SharedBufferHandle& shared_memory() {
+ return shared_memory_.get();
+ }
// Adds a URL to the table.
void AddURL(const GURL& url);
@@ -320,11 +322,10 @@ class VisitedLinkMaster : public VisitedLinkCommon {
// Structure is filled with 0s and shared header with salt. The result of
// allocation is saved into |shared_memory| and |hash_table| points to the
// beginning of Fingerprint table in |shared_memory|.
- static bool CreateApartURLTable(
- int32_t num_entries,
- const uint8_t salt[LINK_SALT_LENGTH],
- std::unique_ptr<base::SharedMemory>* shared_memory,
- VisitedLinkCommon::Fingerprint** hash_table);
+ static bool CreateApartURLTable(int32_t num_entries,
+ const uint8_t salt[LINK_SALT_LENGTH],
+ mojo::ScopedSharedBufferHandle* shared_memory,
+ mojo::ScopedSharedBufferMapping* hash_table);
// A wrapper for CreateURLTable, this will allocate a new table, initialized
// to empty. The caller is responsible for saving the shared memory pointer
@@ -390,6 +391,11 @@ class VisitedLinkMaster : public VisitedLinkCommon {
return hash - 1;
}
+ // Returns a pointer to the start of the hash table, given the mapping
+ // containing the hash table.
+ static Fingerprint* GetHashTableFromMapping(
+ const mojo::ScopedSharedBufferMapping& hash_table_mapping);
+
// Reference to the browser context that this object belongs to
// (it knows the path to where the data is stored)
content::BrowserContext* browser_context_;
@@ -435,7 +441,12 @@ class VisitedLinkMaster : public VisitedLinkCommon {
bool persist_to_disk_;
// Shared memory consists of a SharedHeader followed by the table.
- base::SharedMemory *shared_memory_;
+ mojo::ScopedSharedBufferHandle shared_memory_;
+
+ // A mapping of the table including the SharedHeader.
+ // GetHashTableFromMapping() can be used to obtain a pointer to the hash table
+ // contained in this mapping.
+ mojo::ScopedSharedBufferMapping hash_table_mapping_;
// When we generate new tables, we increment the serial number of the
// shared memory object.
diff --git a/chromium/components/visitedlink/common/BUILD.gn b/chromium/components/visitedlink/common/BUILD.gn
index 712e8d09efe..b131dd1eeb2 100644
--- a/chromium/components/visitedlink/common/BUILD.gn
+++ b/chromium/components/visitedlink/common/BUILD.gn
@@ -2,19 +2,28 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("common") {
+import("//mojo/public/tools/bindings/mojom.gni")
+
+static_library("common") {
sources = [
"visitedlink_common.cc",
"visitedlink_common.h",
- "visitedlink_message_generator.cc",
- "visitedlink_message_generator.h",
- "visitedlink_messages.h",
+ ]
+ public_deps = [
+ ":interfaces",
]
deps = [
+ ":interfaces",
"//base",
"//content/public/common",
"//ipc",
"//url",
]
}
+
+mojom("interfaces") {
+ sources = [
+ "visitedlink.mojom",
+ ]
+}
diff --git a/chromium/components/visitedlink/common/OWNERS b/chromium/components/visitedlink/common/OWNERS
index 42444bcd16d..08850f42120 100644
--- a/chromium/components/visitedlink/common/OWNERS
+++ b/chromium/components/visitedlink/common/OWNERS
@@ -1,2 +1,2 @@
-per-file *_messages*.h=set noparent
-per-file *_messages*.h=file://ipc/SECURITY_OWNERS
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/visitedlink/common/visitedlink.mojom b/chromium/components/visitedlink/common/visitedlink.mojom
new file mode 100644
index 00000000000..9a8ce865de4
--- /dev/null
+++ b/chromium/components/visitedlink/common/visitedlink.mojom
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module visitedlink.mojom;
+
+interface VisitedLinkNotificationSink {
+ // Notification that the visited link database has been replaced. It has one
+ // SharedMemoryHandle argument consisting of the table handle.
+ UpdateVisitedLinks(handle<shared_buffer> table_handle);
+
+ // Notification that one or more links have been added and the link coloring
+ // state for the given hashes must be re-calculated.
+ AddVisitedLinks(array<uint64> link_hashes);
+
+ // Notification that one or more history items have been deleted, which at
+ // this point means that all link coloring state must be re-calculated.
+ // |invalidate_cached_hashes| is used to inform renderer process to invalidate
+ // cached visited links hashes. The flag is needed because the salt will
+ // change after loading the visitedlink table from the database file.
+ ResetVisitedLinks(bool invalidate_cached_hashes);
+};
diff --git a/chromium/components/visitedlink/common/visitedlink_message_generator.cc b/chromium/components/visitedlink/common/visitedlink_message_generator.cc
deleted file mode 100644
index 9ab374eda84..00000000000
--- a/chromium/components/visitedlink/common/visitedlink_message_generator.cc
+++ /dev/null
@@ -1,40 +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.
-
-// Get basic type definitions.
-#define IPC_MESSAGE_IMPL
-#include "components/visitedlink/common/visitedlink_message_generator.h"
-
-// Generate constructors.
-#include "ipc/struct_constructor_macros.h"
-#include "components/visitedlink/common/visitedlink_message_generator.h"
-
-// Generate destructors.
-#include "ipc/struct_destructor_macros.h"
-#include "components/visitedlink/common/visitedlink_message_generator.h"
-
-// Generate param traits size methods.
-#include "ipc/param_traits_size_macros.h"
-namespace IPC {
-#include "components/visitedlink/common/visitedlink_message_generator.h"
-} // namespace IPC
-
-// Generate param traits write methods.
-#include "ipc/param_traits_write_macros.h"
-namespace IPC {
-#include "components/visitedlink/common/visitedlink_message_generator.h"
-} // namespace IPC
-
-// Generate param traits read methods.
-#include "ipc/param_traits_read_macros.h"
-namespace IPC {
-#include "components/visitedlink/common/visitedlink_message_generator.h"
-} // namespace IPC
-
-// Generate param traits log methods.
-#include "ipc/param_traits_log_macros.h"
-namespace IPC {
-#include "components/visitedlink/common/visitedlink_message_generator.h"
-} // namespace IPC
-
diff --git a/chromium/components/visitedlink/common/visitedlink_message_generator.h b/chromium/components/visitedlink/common/visitedlink_message_generator.h
deleted file mode 100644
index e4a496bafb3..00000000000
--- a/chromium/components/visitedlink/common/visitedlink_message_generator.h
+++ /dev/null
@@ -1,7 +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.
-
-// Multiply-included file, no traditional include guard.
-
-#include "components/visitedlink/common/visitedlink_messages.h"
diff --git a/chromium/components/visitedlink/common/visitedlink_messages.h b/chromium/components/visitedlink/common/visitedlink_messages.h
deleted file mode 100644
index f2c1d880232..00000000000
--- a/chromium/components/visitedlink/common/visitedlink_messages.h
+++ /dev/null
@@ -1,32 +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.
-
-// Multiply-included file, no traditional include guard.
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/memory/shared_memory.h"
-#include "content/public/common/common_param_traits_macros.h"
-#include "ipc/ipc_message_macros.h"
-
-#define IPC_MESSAGE_START VisitedLinkMsgStart
-
-// History system notification that the visited link database has been
-// replaced. It has one SharedMemoryHandle argument consisting of the table
-// handle. This handle is valid in the context of the renderer
-IPC_MESSAGE_CONTROL1(ChromeViewMsg_VisitedLink_NewTable,
- base::SharedMemoryHandle)
-
-// History system notification that a link has been added and the link
-// coloring state for the given hash must be re-calculated.
-IPC_MESSAGE_CONTROL1(ChromeViewMsg_VisitedLink_Add, std::vector<uint64_t>)
-
-// History system notification that one or more history items have been
-// deleted, which at this point means that all link coloring state must be
-// re-calculated. Boolean flag is used to inform renderer process to invalidate
-// cached visited links hashes. The flag is needed because the salt will change
-// after loading the visitedlink table from the database file.
-IPC_MESSAGE_CONTROL1(ChromeViewMsg_VisitedLink_Reset, bool)
diff --git a/chromium/components/visitedlink/renderer/BUILD.gn b/chromium/components/visitedlink/renderer/BUILD.gn
index 01a11f07e86..1887406bba7 100644
--- a/chromium/components/visitedlink/renderer/BUILD.gn
+++ b/chromium/components/visitedlink/renderer/BUILD.gn
@@ -4,7 +4,7 @@
assert(!is_ios)
-source_set("renderer") {
+static_library("renderer") {
sources = [
"visitedlink_slave.cc",
"visitedlink_slave.h",
diff --git a/chromium/components/visitedlink/renderer/visitedlink_slave.cc b/chromium/components/visitedlink/renderer/visitedlink_slave.cc
index c159aba9257..bbc9b5d96b4 100644
--- a/chromium/components/visitedlink/renderer/visitedlink_slave.cc
+++ b/chromium/components/visitedlink/renderer/visitedlink_slave.cc
@@ -8,88 +8,79 @@
#include <stdint.h>
#include "base/logging.h"
-#include "base/memory/shared_memory.h"
-#include "components/visitedlink/common/visitedlink_messages.h"
#include "third_party/WebKit/public/web/WebView.h"
using blink::WebView;
namespace visitedlink {
-VisitedLinkSlave::VisitedLinkSlave() : shared_memory_(NULL) {}
+VisitedLinkSlave::VisitedLinkSlave() : binding_(this), weak_factory_(this) {}
VisitedLinkSlave::~VisitedLinkSlave() {
FreeTable();
}
-bool VisitedLinkSlave::OnControlMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(VisitedLinkSlave, message)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_VisitedLink_NewTable,
- OnUpdateVisitedLinks)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_VisitedLink_Add, OnAddVisitedLinks)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_VisitedLink_Reset, OnResetVisitedLinks)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
+base::Callback<void(mojom::VisitedLinkNotificationSinkRequest)>
+VisitedLinkSlave::GetBindCallback() {
+ return base::Bind(&VisitedLinkSlave::Bind, weak_factory_.GetWeakPtr());
}
-// This function's job is to initialize the table with the given
-// shared memory handle. This memory is mapped into the process.
-void VisitedLinkSlave::OnUpdateVisitedLinks(base::SharedMemoryHandle table) {
- DCHECK(base::SharedMemory::IsHandleValid(table)) << "Bad table handle";
- // since this function may be called again to change the table, we may need
- // to free old objects
+// Initializes the table with the given shared memory handle. This memory is
+// mapped into the process.
+void VisitedLinkSlave::UpdateVisitedLinks(
+ mojo::ScopedSharedBufferHandle table) {
+ DCHECK(table.is_valid()) << "Bad table handle";
+ // Since this function may be called again to change the table, we may need
+ // to free old objects.
FreeTable();
- DCHECK(shared_memory_ == NULL && hash_table_ == NULL);
-
- // create the shared memory object
- shared_memory_ = new base::SharedMemory(table, true);
- if (!shared_memory_)
- return;
+ DCHECK(hash_table_ == NULL);
+
+ int32_t table_len = 0;
+ {
+ // Map the header into our process so we can see how long the rest is,
+ // and set the salt.
+ mojo::ScopedSharedBufferMapping header_memory =
+ table->Map(sizeof(SharedHeader));
+ if (!header_memory)
+ return;
+
+ SharedHeader* header = static_cast<SharedHeader*>(header_memory.get());
+ table_len = header->length;
+ memcpy(salt_, header->salt, sizeof(salt_));
+ }
- // map the header into our process so we can see how long the rest is,
- // and set the salt
- if (!shared_memory_->Map(sizeof(SharedHeader)))
+ // Now we know the length, so map the table contents.
+ table_mapping_ =
+ table->MapAtOffset(table_len * sizeof(Fingerprint), sizeof(SharedHeader));
+ if (!table_mapping_)
return;
- SharedHeader* header =
- static_cast<SharedHeader*>(shared_memory_->memory());
- DCHECK(header);
- int32_t table_len = header->length;
- memcpy(salt_, header->salt, sizeof(salt_));
- shared_memory_->Unmap();
-
- // now do the whole table because we know the length
- if (!shared_memory_->Map(sizeof(SharedHeader) +
- table_len * sizeof(Fingerprint))) {
- shared_memory_->Close();
- return;
- }
- // commit the data
- DCHECK(shared_memory_->memory());
- hash_table_ = reinterpret_cast<Fingerprint*>(
- static_cast<char*>(shared_memory_->memory()) + sizeof(SharedHeader));
+ // Commit the data.
+ hash_table_ = reinterpret_cast<Fingerprint*>(table_mapping_.get());
table_length_ = table_len;
}
-void VisitedLinkSlave::OnAddVisitedLinks(
- const VisitedLinkSlave::Fingerprints& fingerprints) {
+void VisitedLinkSlave::AddVisitedLinks(
+ const std::vector<VisitedLinkSlave::Fingerprint>& fingerprints) {
for (size_t i = 0; i < fingerprints.size(); ++i)
WebView::updateVisitedLinkState(fingerprints[i]);
}
-void VisitedLinkSlave::OnResetVisitedLinks(bool invalidate_hashes) {
+void VisitedLinkSlave::ResetVisitedLinks(bool invalidate_hashes) {
WebView::resetVisitedLinkState(invalidate_hashes);
}
void VisitedLinkSlave::FreeTable() {
- if (shared_memory_) {
- delete shared_memory_;
- shared_memory_ = NULL;
- }
+ if (!hash_table_)
+ return;
+
+ table_mapping_.reset();
hash_table_ = NULL;
table_length_ = 0;
}
+void VisitedLinkSlave::Bind(mojom::VisitedLinkNotificationSinkRequest request) {
+ binding_.Bind(std::move(request));
+}
+
} // namespace visitedlink
diff --git a/chromium/components/visitedlink/renderer/visitedlink_slave.h b/chromium/components/visitedlink/renderer/visitedlink_slave.h
index 31cae89a62d..bbf0cfde2f8 100644
--- a/chromium/components/visitedlink/renderer/visitedlink_slave.h
+++ b/chromium/components/visitedlink/renderer/visitedlink_slave.h
@@ -7,33 +7,41 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "base/memory/shared_memory.h"
+#include "base/memory/weak_ptr.h"
+#include "components/visitedlink/common/visitedlink.mojom.h"
#include "components/visitedlink/common/visitedlink_common.h"
-#include "content/public/renderer/render_thread_observer.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/buffer.h"
namespace visitedlink {
// Reads the link coloring database provided by the master. There can be any
// number of slaves reading the same database.
class VisitedLinkSlave : public VisitedLinkCommon,
- public content::RenderThreadObserver {
+ public mojom::VisitedLinkNotificationSink {
public:
VisitedLinkSlave();
~VisitedLinkSlave() override;
- // RenderThreadObserver implementation.
- bool OnControlMessageReceived(const IPC::Message& message) override;
+ base::Callback<void(mojom::VisitedLinkNotificationSinkRequest)>
+ GetBindCallback();
- // Message handlers.
- void OnUpdateVisitedLinks(base::SharedMemoryHandle table);
- void OnAddVisitedLinks(const VisitedLinkSlave::Fingerprints& fingerprints);
- void OnResetVisitedLinks(bool invalidate_hashes);
+ // mojom::VisitedLinkNotificationSink overrides.
+ void UpdateVisitedLinks(mojo::ScopedSharedBufferHandle table) override;
+ void AddVisitedLinks(
+ const std::vector<VisitedLinkSlave::Fingerprint>& fingerprints) override;
+ void ResetVisitedLinks(bool invalidate_hashes) override;
private:
void FreeTable();
- // shared memory consists of a SharedHeader followed by the table
- base::SharedMemory* shared_memory_;
+ void Bind(mojom::VisitedLinkNotificationSinkRequest request);
+
+ mojo::ScopedSharedBufferMapping table_mapping_;
+
+ mojo::Binding<mojom::VisitedLinkNotificationSink> binding_;
+
+ base::WeakPtrFactory<VisitedLinkSlave> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(VisitedLinkSlave);
};
diff --git a/chromium/components/wallpaper.gypi b/chromium/components/wallpaper.gypi
deleted file mode 100644
index 1cafb7e3959..00000000000
--- a/chromium/components/wallpaper.gypi
+++ /dev/null
@@ -1,47 +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.
-{
- 'targets': [
- {
- 'target_name': 'wallpaper',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content',
- '../skia/skia.gyp:skia',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/gfx.gyp:gfx_geometry',
- '../url/url.gyp:url_lib',
- 'prefs/prefs.gyp:prefs',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines':[
- 'WALLPAPER_IMPLEMENTATION',
- ],
- 'sources': [
- 'wallpaper/wallpaper_layout.h',
- 'wallpaper/wallpaper_files_id.cc',
- 'wallpaper/wallpaper_files_id.h',
- 'wallpaper/wallpaper_resizer.cc',
- 'wallpaper/wallpaper_resizer.h',
- 'wallpaper/wallpaper_resizer_observer.h',
- ],
- 'conditions': [
- ['chromeos==1', {
- 'dependencies': [
- '../chromeos/chromeos.gyp:chromeos',
- '../components/components.gyp:signin_core_account_id',
- '../components/components.gyp:user_manager',
- ],
- 'sources': [
- 'wallpaper/wallpaper_manager_base.cc',
- 'wallpaper/wallpaper_manager_base.h',
- ],
- }],
- ],
- },
- ],
-}
diff --git a/chromium/components/wallpaper/wallpaper_manager_base.cc b/chromium/components/wallpaper/wallpaper_manager_base.cc
index a29a4b36365..e0d38e34ad4 100644
--- a/chromium/components/wallpaper/wallpaper_manager_base.cc
+++ b/chromium/components/wallpaper/wallpaper_manager_base.cc
@@ -10,6 +10,7 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
@@ -63,6 +64,11 @@ const unsigned kLoadMaxDelayMs = 2000;
// color.
const SkColor kDefaultWallpaperColor = SK_ColorGRAY;
+#if DCHECK_IS_ON()
+base::LazyInstance<base::SequenceChecker>::Leaky g_wallpaper_sequence_checker =
+ LAZY_INSTANCE_INITIALIZER;
+#endif
+
// The path ids for directories.
int dir_user_data_path_id = -1; // chrome::DIR_USER_DATA
int dir_chromeos_wallpapers_path_id = -1; // chrome::DIR_CHROMEOS_WALLPAPERS
@@ -158,6 +164,12 @@ WallpaperInfo::WallpaperInfo(const std::string& in_location,
WallpaperInfo::~WallpaperInfo() {
}
+void AssertCalledOnWallpaperSequence() {
+#if DCHECK_IS_ON()
+ DCHECK(g_wallpaper_sequence_checker.Get().CalledOnValidSequence());
+#endif
+}
+
const char kWallpaperSequenceTokenName[] = "wallpaper-sequence";
const char kSmallWallpaperSuffix[] = "_small";
diff --git a/chromium/components/wallpaper/wallpaper_manager_base.h b/chromium/components/wallpaper/wallpaper_manager_base.h
index 69ca35f6099..a734d2f5f03 100644
--- a/chromium/components/wallpaper/wallpaper_manager_base.h
+++ b/chromium/components/wallpaper/wallpaper_manager_base.h
@@ -80,6 +80,10 @@ struct WALLPAPER_EXPORT WallpaperInfo {
}
};
+// Asserts that the current task is sequenced with any other task that calls
+// this.
+void WALLPAPER_EXPORT AssertCalledOnWallpaperSequence();
+
class WallpaperManagerBrowserTest;
// Name of wallpaper sequence token.
diff --git a/chromium/components/wallpaper/wallpaper_resizer.cc b/chromium/components/wallpaper/wallpaper_resizer.cc
index 47e391d5380..93640fd3330 100644
--- a/chromium/components/wallpaper/wallpaper_resizer.cc
+++ b/chromium/components/wallpaper/wallpaper_resizer.cc
@@ -4,18 +4,17 @@
#include "components/wallpaper/wallpaper_resizer.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "base/threading/worker_pool.h"
+#include "base/task_runner.h"
#include "components/wallpaper/wallpaper_resizer_observer.h"
#include "third_party/skia/include/core/SkImage.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/skia_util.h"
-using base::SequencedWorkerPool;
-
namespace wallpaper {
namespace {
@@ -30,8 +29,8 @@ void Resize(SkBitmap orig_bitmap,
const gfx::Size& target_size,
WallpaperLayout layout,
SkBitmap* resized_bitmap_out,
- SequencedWorkerPool* worker_pool) {
- DCHECK(worker_pool->RunsTasksOnCurrentThread());
+ base::TaskRunner* task_runner) {
+ DCHECK(task_runner->RunsTasksOnCurrentThread());
SkBitmap new_bitmap = orig_bitmap;
const int orig_width = orig_bitmap.width();
@@ -104,15 +103,16 @@ uint32_t WallpaperResizer::GetImageId(const gfx::ImageSkia& image) {
return image_rep.is_null() ? 0 : image_rep.sk_bitmap().getGenerationID();
}
-WallpaperResizer::WallpaperResizer(const gfx::ImageSkia& image,
- const gfx::Size& target_size,
- WallpaperLayout layout,
- base::SequencedWorkerPool* worker_pool_ptr)
+WallpaperResizer::WallpaperResizer(
+ const gfx::ImageSkia& image,
+ const gfx::Size& target_size,
+ WallpaperLayout layout,
+ scoped_refptr<base::TaskRunner> task_runner)
: image_(image),
original_image_id_(GetImageId(image_)),
target_size_(target_size),
layout_(layout),
- worker_pool_(worker_pool_ptr),
+ task_runner_(std::move(task_runner)),
weak_ptr_factory_(this) {
image_.MakeThreadSafe();
}
@@ -122,11 +122,10 @@ WallpaperResizer::~WallpaperResizer() {
void WallpaperResizer::StartResize() {
SkBitmap* resized_bitmap = new SkBitmap;
- scoped_refptr<SequencedWorkerPool> worker_pool_refptr(worker_pool_);
- if (!worker_pool_->PostTaskAndReply(
+ if (!task_runner_->PostTaskAndReply(
FROM_HERE,
base::Bind(&Resize, *image_.bitmap(), target_size_, layout_,
- resized_bitmap, base::RetainedRef(worker_pool_refptr)),
+ resized_bitmap, base::RetainedRef(task_runner_)),
base::Bind(&WallpaperResizer::OnResizeFinished,
weak_ptr_factory_.GetWeakPtr(),
base::Owned(resized_bitmap)))) {
diff --git a/chromium/components/wallpaper/wallpaper_resizer.h b/chromium/components/wallpaper/wallpaper_resizer.h
index 658f7bb5bea..836470d58af 100644
--- a/chromium/components/wallpaper/wallpaper_resizer.h
+++ b/chromium/components/wallpaper/wallpaper_resizer.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "components/wallpaper/wallpaper_layout.h"
@@ -19,7 +20,7 @@
#include "ui/gfx/image/image_skia.h"
namespace base {
-class SequencedWorkerPool;
+class TaskRunner;
}
namespace wallpaper {
@@ -37,16 +38,15 @@ class WALLPAPER_EXPORT WallpaperResizer {
WallpaperResizer(const gfx::ImageSkia& image,
const gfx::Size& target_size,
WallpaperLayout layout,
- base::SequencedWorkerPool* worker_pool_ptr);
+ scoped_refptr<base::TaskRunner> task_runner);
~WallpaperResizer();
const gfx::ImageSkia& image() const { return image_; }
uint32_t original_image_id() const { return original_image_id_; }
WallpaperLayout layout() const { return layout_; }
- base::SequencedWorkerPool* worker_pool() const { return worker_pool_; }
- // Called on the UI thread to run Resize() on the worker pool and post an
+ // Called on the UI thread to run Resize() on the task runner and post an
// OnResizeFinished() task back to the UI thread on completion.
void StartResize();
@@ -73,7 +73,7 @@ class WALLPAPER_EXPORT WallpaperResizer {
WallpaperLayout layout_;
- base::SequencedWorkerPool* worker_pool_;
+ scoped_refptr<base::TaskRunner> task_runner_;
base::WeakPtrFactory<WallpaperResizer> weak_ptr_factory_;
diff --git a/chromium/components/wallpaper/wallpaper_resizer_unittest.cc b/chromium/components/wallpaper/wallpaper_resizer_unittest.cc
index 7d4fefb6bf4..fadf11c3cb7 100644
--- a/chromium/components/wallpaper/wallpaper_resizer_unittest.cc
+++ b/chromium/components/wallpaper/wallpaper_resizer_unittest.cc
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
-#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/threading/thread.h"
#include "components/wallpaper/wallpaper_resizer_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/image/image_skia_rep.h"
@@ -62,15 +62,19 @@ namespace wallpaper {
class WallpaperResizerTest : public testing::Test,
public WallpaperResizerObserver {
public:
- WallpaperResizerTest() : worker_pool_owner_(1, "WallpaperResizerTest") {}
+ WallpaperResizerTest() : worker_thread_("WallpaperResizerTest") {}
~WallpaperResizerTest() override {}
+ void SetUp() override {
+ ASSERT_TRUE(worker_thread_.Start());
+ }
+
gfx::ImageSkia Resize(const gfx::ImageSkia& image,
const gfx::Size& target_size,
WallpaperLayout layout) {
std::unique_ptr<WallpaperResizer> resizer;
resizer.reset(
- new WallpaperResizer(image, target_size, layout, worker_pool()));
+ new WallpaperResizer(image, target_size, layout, task_runner()));
resizer->AddObserver(this);
resizer->StartResize();
WaitForResize();
@@ -78,8 +82,8 @@ class WallpaperResizerTest : public testing::Test,
return resizer->image();
}
- base::SequencedWorkerPool* worker_pool() {
- return worker_pool_owner_.pool().get();
+ scoped_refptr<base::TaskRunner> task_runner() {
+ return worker_thread_.task_runner();
}
void WaitForResize() { base::RunLoop().Run(); }
@@ -88,7 +92,7 @@ class WallpaperResizerTest : public testing::Test,
private:
base::MessageLoop message_loop_;
- base::SequencedWorkerPoolOwner worker_pool_owner_;
+ base::Thread worker_thread_;
DISALLOW_COPY_AND_ASSIGN(WallpaperResizerTest);
};
@@ -149,7 +153,7 @@ TEST_F(WallpaperResizerTest, ImageId) {
// Create a WallpaperResizer and check that it reports an original image ID
// both pre- and post-resize that matches the ID returned by GetImageId().
WallpaperResizer resizer(image, gfx::Size(10, 20), WALLPAPER_LAYOUT_STRETCH,
- worker_pool());
+ task_runner());
EXPECT_EQ(WallpaperResizer::GetImageId(image), resizer.original_image_id());
resizer.AddObserver(this);
resizer.StartResize();
diff --git a/chromium/components/web_cache.gypi b/chromium/components/web_cache.gypi
deleted file mode 100644
index 98ec9802c94..00000000000
--- a/chromium/components/web_cache.gypi
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'targets': [
- {
- # GN version: //components/web_cache/public/interfaces
- 'target_name': 'web_cache_mojo_bindings',
- 'type': 'static_library',
- 'sources': [
- # NOTE: Sources duplicated in //components/web_cache/public/interfaces/BUILD.gn
- 'web_cache/public/interfaces/web_cache.mojom',
- ],
- 'includes': [ '../mojo/mojom_bindings_generator.gypi'],
- },
- {
- 'target_name': 'web_cache_browser',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/content/content.gyp:content_browser',
- '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
- 'web_cache_mojo_bindings',
- ],
- 'sources': [
- 'web_cache/browser/web_cache_manager.cc',
- 'web_cache/browser/web_cache_manager.h',
- ],
- # Disable c4267 warnings until we fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- },
- {
- 'target_name': 'web_cache_renderer',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/content/content.gyp:content_renderer',
- '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
- 'web_cache_mojo_bindings',
- ],
- 'sources': [
- 'web_cache/renderer/web_cache_impl.cc',
- 'web_cache/renderer/web_cache_impl.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/web_cache/browser/BUILD.gn b/chromium/components/web_cache/browser/BUILD.gn
index 9b566c5fa97..00f49a47149 100644
--- a/chromium/components/web_cache/browser/BUILD.gn
+++ b/chromium/components/web_cache/browser/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("browser") {
+static_library("browser") {
sources = [
"web_cache_manager.cc",
"web_cache_manager.h",
diff --git a/chromium/components/web_cache/renderer/BUILD.gn b/chromium/components/web_cache/renderer/BUILD.gn
index 4f3df24f15d..fdc2b055fbd 100644
--- a/chromium/components/web_cache/renderer/BUILD.gn
+++ b/chromium/components/web_cache/renderer/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("renderer") {
+static_library("renderer") {
sources = [
"web_cache_impl.cc",
"web_cache_impl.h",
diff --git a/chromium/components/web_contents_delegate_android.gypi b/chromium/components/web_contents_delegate_android.gypi
deleted file mode 100644
index 17a3f5f71fe..00000000000
--- a/chromium/components/web_contents_delegate_android.gypi
+++ /dev/null
@@ -1,76 +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.
-
-{
- 'conditions': [
- ['OS=="android"', {
- 'targets': [
- {
- # GN: //components/web_contents_delegate_android:web_contents_delegate_android
- 'target_name': 'web_contents_delegate_android',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../net/net.gyp:net',
- '../skia/skia.gyp:skia',
- '../ui/android/ui_android.gyp:ui_android',
- '../ui/base/ui_base.gyp:ui_base',
- '../ui/gfx/gfx.gyp:gfx',
- '../ui/gfx/gfx.gyp:gfx_geometry',
- 'web_contents_delegate_android_jni_headers',
- ],
- 'include_dirs': [
- '..',
- '../skia/config',
- ],
- 'sources': [
- 'web_contents_delegate_android/color_chooser_android.cc',
- 'web_contents_delegate_android/color_chooser_android.h',
- 'web_contents_delegate_android/component_jni_registrar.cc',
- 'web_contents_delegate_android/component_jni_registrar.h',
- 'web_contents_delegate_android/validation_message_bubble_android.cc',
- 'web_contents_delegate_android/validation_message_bubble_android.h',
- 'web_contents_delegate_android/web_contents_delegate_android.cc',
- 'web_contents_delegate_android/web_contents_delegate_android.h',
- ],
- },
- {
- # GN: //components/web_contents_delegate_android:web_contents_delegate_android_java
- # and //components/web_contents_delegate_android:web_contents_delegate_android_java_resources
- 'target_name': 'web_contents_delegate_android_java',
- 'type': 'none',
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_java',
- '../ui/android/ui_android.gyp:ui_java',
- ],
- 'variables': {
- 'java_in_dir': 'web_contents_delegate_android/android/java',
- 'has_java_resources': 1,
- 'R_package': 'org.chromium.components.web_contents_delegate_android',
- 'R_package_relpath': 'org/chromium/components/web_contents_delegate_android',
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN: //components/web_contents_delegate_android:web_contents_delegate_android_jni_headers
- 'target_name': 'web_contents_delegate_android_jni_headers',
- 'type': 'none',
- 'sources': [
- 'web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java',
- 'web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/ValidationMessageBubble.java',
- 'web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java',
- ],
- 'variables': {
- 'jni_gen_package': 'web_contents_delegate_android',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/components/web_contents_delegate_android/BUILD.gn b/chromium/components/web_contents_delegate_android/BUILD.gn
index 6aa3cd4ff07..6b2dc26ebd4 100644
--- a/chromium/components/web_contents_delegate_android/BUILD.gn
+++ b/chromium/components/web_contents_delegate_android/BUILD.gn
@@ -4,7 +4,6 @@
import("//build/config/android/rules.gni")
-# GYP: //components/web_contents_delegate_android:web_contents_delegate_android
static_library("web_contents_delegate_android") {
sources = [
"color_chooser_android.cc",
@@ -31,13 +30,11 @@ static_library("web_contents_delegate_android") {
]
}
-# GYP: //components/web_contents_delegate_android:web_contents_delegate_android_java
android_resources("web_contents_delegate_android_java_resources") {
custom_package = "org.chromium.components.web_contents_delegate_android"
resource_dirs = [ "android/java/res" ]
}
-# GYP: //components/web_contents_delegate_android:web_contents_delegate_android_java
android_library("web_contents_delegate_android_java") {
deps = [
":web_contents_delegate_android_java_resources",
@@ -52,7 +49,6 @@ android_library("web_contents_delegate_android_java") {
]
}
-# GYP: //components/web_contents_delegate_android:web_contents_delegate_android_jni_headers
generate_jni("web_contents_delegate_android_jni_headers") {
sources = [
"android/java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java",
diff --git a/chromium/components/web_contents_delegate_android/OWNERS b/chromium/components/web_contents_delegate_android/OWNERS
index 48569ad0937..4048140c419 100644
--- a/chromium/components/web_contents_delegate_android/OWNERS
+++ b/chromium/components/web_contents_delegate_android/OWNERS
@@ -1,2 +1,2 @@
-sievers@chromium.org
+boliu@chromium.org
tedchoc@chromium.org
diff --git a/chromium/components/web_contents_delegate_android/color_chooser_android.cc b/chromium/components/web_contents_delegate_android/color_chooser_android.cc
index 838be6c4ea3..5aeb8ee8aca 100644
--- a/chromium/components/web_contents_delegate_android/color_chooser_android.cc
+++ b/chromium/components/web_contents_delegate_android/color_chooser_android.cc
@@ -37,11 +37,7 @@ ColorChooserAndroid::ColorChooserAndroid(
ScopedJavaLocalRef<jstring> label = ConvertUTF16ToJavaString(
env, suggestion.label);
Java_ColorChooserAndroid_addToColorSuggestionArray(
- env,
- suggestions_array.obj(),
- i,
- suggestion.color,
- label.obj());
+ env, suggestions_array, i, suggestion.color, label);
}
}
@@ -52,11 +48,8 @@ ColorChooserAndroid::ColorChooserAndroid(
content_view_core->GetJavaObject();
if (!java_content_view_core.is_null()) {
j_color_chooser_.Reset(Java_ColorChooserAndroid_createColorChooserAndroid(
- env,
- reinterpret_cast<intptr_t>(this),
- java_content_view_core.obj(),
- initial_color,
- suggestions_array.obj()));
+ env, reinterpret_cast<intptr_t>(this), java_content_view_core,
+ initial_color, suggestions_array));
}
}
if (j_color_chooser_.is_null())
@@ -69,7 +62,7 @@ ColorChooserAndroid::~ColorChooserAndroid() {
void ColorChooserAndroid::End() {
if (!j_color_chooser_.is_null()) {
JNIEnv* env = AttachCurrentThread();
- Java_ColorChooserAndroid_closeColorChooser(env, j_color_chooser_.obj());
+ Java_ColorChooserAndroid_closeColorChooser(env, j_color_chooser_);
}
}
diff --git a/chromium/components/web_contents_delegate_android/validation_message_bubble_android.cc b/chromium/components/web_contents_delegate_android/validation_message_bubble_android.cc
index a57763697a0..0dd5eee1628 100644
--- a/chromium/components/web_contents_delegate_android/validation_message_bubble_android.cc
+++ b/chromium/components/web_contents_delegate_android/validation_message_bubble_android.cc
@@ -43,19 +43,16 @@ ValidationMessageBubbleAndroid::ValidationMessageBubbleAndroid(
JNIEnv* env = base::android::AttachCurrentThread();
java_validation_message_bubble_.Reset(
Java_ValidationMessageBubble_createAndShow(
- env,
- java_content_view_core.obj(),
- anchor_in_root_view.x(),
- anchor_in_root_view.y(),
- anchor_in_root_view.width(),
+ env, java_content_view_core, anchor_in_root_view.x(),
+ anchor_in_root_view.y(), anchor_in_root_view.width(),
anchor_in_root_view.height(),
- ConvertUTF16ToJavaString(env, main_text).obj(),
- ConvertUTF16ToJavaString(env, sub_text).obj()));
+ ConvertUTF16ToJavaString(env, main_text),
+ ConvertUTF16ToJavaString(env, sub_text)));
}
ValidationMessageBubbleAndroid::~ValidationMessageBubbleAndroid() {
Java_ValidationMessageBubble_close(base::android::AttachCurrentThread(),
- java_validation_message_bubble_.obj());
+ java_validation_message_bubble_);
}
void ValidationMessageBubbleAndroid::SetPositionRelativeToAnchor(
@@ -66,18 +63,9 @@ void ValidationMessageBubbleAndroid::SetPositionRelativeToAnchor(
return;
Java_ValidationMessageBubble_setPositionRelativeToAnchor(
- base::android::AttachCurrentThread(),
- java_validation_message_bubble_.obj(),
- java_content_view_core.obj(),
- anchor_in_root_view.x(),
- anchor_in_root_view.y(),
- anchor_in_root_view.width(),
- anchor_in_root_view.height());
-}
-
-// static
-bool ValidationMessageBubbleAndroid::Register(JNIEnv* env) {
- return RegisterNativesImpl(env);
+ base::android::AttachCurrentThread(), java_validation_message_bubble_,
+ java_content_view_core, anchor_in_root_view.x(), anchor_in_root_view.y(),
+ anchor_in_root_view.width(), anchor_in_root_view.height());
}
} // namespace web_contents_delegate_android
diff --git a/chromium/components/web_contents_delegate_android/validation_message_bubble_android.h b/chromium/components/web_contents_delegate_android/validation_message_bubble_android.h
index 181efc131a0..1fe027b1850 100644
--- a/chromium/components/web_contents_delegate_android/validation_message_bubble_android.h
+++ b/chromium/components/web_contents_delegate_android/validation_message_bubble_android.h
@@ -33,8 +33,6 @@ class ValidationMessageBubbleAndroid {
content::RenderWidgetHost* widget_host,
const gfx::Rect& anchor_in_screen);
- static bool Register(JNIEnv* env);
-
private:
base::android::ScopedJavaGlobalRef<jobject> java_validation_message_bubble_;
};
diff --git a/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc b/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc
index 986470f8353..1468e809c2b 100644
--- a/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc
+++ b/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc
@@ -69,10 +69,10 @@ WebContents* WebContentsDelegateAndroid::OpenURLFromTab(
const GURL& url = params.url;
WindowOpenDisposition disposition = params.disposition;
- if (!source || (disposition != CURRENT_TAB &&
- disposition != NEW_FOREGROUND_TAB &&
- disposition != NEW_BACKGROUND_TAB &&
- disposition != OFF_THE_RECORD)) {
+ if (!source || (disposition != WindowOpenDisposition::CURRENT_TAB &&
+ disposition != WindowOpenDisposition::NEW_FOREGROUND_TAB &&
+ disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB &&
+ disposition != WindowOpenDisposition::OFF_THE_RECORD)) {
NOTIMPLEMENTED();
return NULL;
}
@@ -82,9 +82,9 @@ WebContents* WebContentsDelegateAndroid::OpenURLFromTab(
if (obj.is_null())
return WebContentsDelegate::OpenURLFromTab(source, params);
- if (disposition == NEW_FOREGROUND_TAB ||
- disposition == NEW_BACKGROUND_TAB ||
- disposition == OFF_THE_RECORD) {
+ if (disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
+ disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB ||
+ disposition == WindowOpenDisposition::OFF_THE_RECORD) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jstring> java_url =
ConvertUTF8ToJavaString(env, url.spec());
@@ -93,13 +93,9 @@ WebContents* WebContentsDelegateAndroid::OpenURLFromTab(
ScopedJavaLocalRef<jobject> post_data;
if (params.uses_post && params.post_data)
post_data = params.post_data->ToJavaObject(env);
- Java_WebContentsDelegateAndroid_openNewTab(env,
- obj.obj(),
- java_url.obj(),
- extra_headers.obj(),
- post_data.obj(),
- disposition,
- params.is_renderer_initiated);
+ Java_WebContentsDelegateAndroid_openNewTab(
+ env, obj, java_url, extra_headers, post_data,
+ static_cast<int>(disposition), params.is_renderer_initiated);
return NULL;
}
@@ -130,10 +126,8 @@ void WebContentsDelegateAndroid::NavigationStateChanged(
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_navigationStateChanged(
- env,
- obj.obj(),
- changed_flags);
+ Java_WebContentsDelegateAndroid_navigationStateChanged(env, obj,
+ changed_flags);
}
void WebContentsDelegateAndroid::VisibleSSLStateChanged(
@@ -142,9 +136,7 @@ void WebContentsDelegateAndroid::VisibleSSLStateChanged(
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_visibleSSLStateChanged(
- env,
- obj.obj());
+ Java_WebContentsDelegateAndroid_visibleSSLStateChanged(env, obj);
}
void WebContentsDelegateAndroid::ActivateContents(WebContents* contents) {
@@ -152,25 +144,15 @@ void WebContentsDelegateAndroid::ActivateContents(WebContents* contents) {
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_activateContents(env, obj.obj());
+ Java_WebContentsDelegateAndroid_activateContents(env, obj);
}
void WebContentsDelegateAndroid::LoadingStateChanged(WebContents* source,
bool to_different_document) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
- if (obj.is_null())
- return;
- bool has_stopped = source == NULL || !source->IsLoading();
-
- if (has_stopped) {
- Java_WebContentsDelegateAndroid_onLoadStopped(env, obj.obj());
- } else {
- Java_WebContentsDelegateAndroid_onLoadStarted(
- env,
- obj.obj(),
- to_different_document);
- }
+ Java_WebContentsDelegateAndroid_loadingStateChanged(env, obj,
+ to_different_document);
}
void WebContentsDelegateAndroid::LoadProgressChanged(WebContents* source,
@@ -179,10 +161,7 @@ void WebContentsDelegateAndroid::LoadProgressChanged(WebContents* source,
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_notifyLoadProgressChanged(
- env,
- obj.obj(),
- progress);
+ Java_WebContentsDelegateAndroid_notifyLoadProgressChanged(env, obj, progress);
}
void WebContentsDelegateAndroid::RendererUnresponsive(WebContents* source) {
@@ -190,7 +169,7 @@ void WebContentsDelegateAndroid::RendererUnresponsive(WebContents* source) {
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_rendererUnresponsive(env, obj.obj());
+ Java_WebContentsDelegateAndroid_rendererUnresponsive(env, obj);
}
void WebContentsDelegateAndroid::RendererResponsive(WebContents* source) {
@@ -198,7 +177,7 @@ void WebContentsDelegateAndroid::RendererResponsive(WebContents* source) {
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_rendererResponsive(env, obj.obj());
+ Java_WebContentsDelegateAndroid_rendererResponsive(env, obj);
}
bool WebContentsDelegateAndroid::ShouldCreateWebContents(
@@ -217,8 +196,8 @@ bool WebContentsDelegateAndroid::ShouldCreateWebContents(
return true;
ScopedJavaLocalRef<jstring> java_url =
ConvertUTF8ToJavaString(env, target_url.spec());
- return Java_WebContentsDelegateAndroid_shouldCreateWebContents(env, obj.obj(),
- java_url.obj());
+ return Java_WebContentsDelegateAndroid_shouldCreateWebContents(env, obj,
+ java_url);
}
bool WebContentsDelegateAndroid::OnGoToEntryOffset(int offset) {
@@ -226,13 +205,15 @@ bool WebContentsDelegateAndroid::OnGoToEntryOffset(int offset) {
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return true;
- return Java_WebContentsDelegateAndroid_onGoToEntryOffset(env, obj.obj(),
- offset);
+ return Java_WebContentsDelegateAndroid_onGoToEntryOffset(env, obj, offset);
}
void WebContentsDelegateAndroid::WebContentsCreated(
- WebContents* source_contents, int opener_render_frame_id,
- const std::string& frame_name, const GURL& target_url,
+ WebContents* source_contents,
+ int opener_render_process_id,
+ int opener_render_frame_id,
+ const std::string& frame_name,
+ const GURL& target_url,
WebContents* new_contents) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
@@ -247,10 +228,10 @@ void WebContentsDelegateAndroid::WebContentsCreated(
jnew_contents = new_contents->GetJavaWebContents();
Java_WebContentsDelegateAndroid_webContentsCreated(
- env, obj.obj(), jsource_contents.obj(), opener_render_frame_id,
- base::android::ConvertUTF8ToJavaString(env, frame_name).obj(),
- base::android::ConvertUTF8ToJavaString(env, target_url.spec()).obj(),
- jnew_contents.obj());
+ env, obj, jsource_contents, opener_render_frame_id,
+ base::android::ConvertUTF8ToJavaString(env, frame_name),
+ base::android::ConvertUTF8ToJavaString(env, target_url.spec()),
+ jnew_contents);
}
void WebContentsDelegateAndroid::CloseContents(WebContents* source) {
@@ -258,7 +239,7 @@ void WebContentsDelegateAndroid::CloseContents(WebContents* source) {
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_closeContents(env, obj.obj());
+ Java_WebContentsDelegateAndroid_closeContents(env, obj);
}
void WebContentsDelegateAndroid::MoveContents(WebContents* source,
@@ -298,12 +279,7 @@ bool WebContentsDelegateAndroid::AddMessageToConsole(
NOTREACHED();
}
return Java_WebContentsDelegateAndroid_addMessageToConsole(
- env,
- GetJavaDelegate(env).obj(),
- jlevel,
- jmessage.obj(),
- line_no,
- jsource_id.obj());
+ env, GetJavaDelegate(env), jlevel, jmessage, line_no, jsource_id);
}
// This is either called from TabContents::DidNavigateMainFramePostCommit() with
@@ -321,9 +297,7 @@ void WebContentsDelegateAndroid::UpdateTargetURL(WebContents* source,
return;
ScopedJavaLocalRef<jstring> java_url =
ConvertUTF8ToJavaString(env, source->GetURL().spec());
- Java_WebContentsDelegateAndroid_onUpdateUrl(env,
- obj.obj(),
- java_url.obj());
+ Java_WebContentsDelegateAndroid_onUpdateUrl(env, obj, java_url);
}
void WebContentsDelegateAndroid::HandleKeyboardEvent(
@@ -335,8 +309,7 @@ void WebContentsDelegateAndroid::HandleKeyboardEvent(
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_handleKeyboardEvent(
- env, obj.obj(), key_event);
+ Java_WebContentsDelegateAndroid_handleKeyboardEvent(env, obj, key_event);
}
}
@@ -345,8 +318,7 @@ bool WebContentsDelegateAndroid::TakeFocus(WebContents* source, bool reverse) {
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return WebContentsDelegate::TakeFocus(source, reverse);
- return Java_WebContentsDelegateAndroid_takeFocus(
- env, obj.obj(), reverse);
+ return Java_WebContentsDelegateAndroid_takeFocus(env, obj, reverse);
}
void WebContentsDelegateAndroid::ShowRepostFormWarningDialog(
@@ -355,7 +327,26 @@ void WebContentsDelegateAndroid::ShowRepostFormWarningDialog(
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_showRepostFormWarningDialog(env, obj.obj());
+ Java_WebContentsDelegateAndroid_showRepostFormWarningDialog(env, obj);
+}
+
+ScopedJavaLocalRef<jobject>
+WebContentsDelegateAndroid::GetContentVideoViewEmbedder() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
+ if (obj.is_null())
+ return ScopedJavaLocalRef<jobject>();
+
+ return Java_WebContentsDelegateAndroid_getContentVideoViewEmbedder(env, obj);
+}
+
+bool WebContentsDelegateAndroid::ShouldBlockMediaRequest(const GURL& url) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
+ if (obj.is_null())
+ return false;
+ ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
+ return Java_WebContentsDelegateAndroid_shouldBlockMediaRequest(env, obj, j_url);
}
void WebContentsDelegateAndroid::EnterFullscreenModeForTab(
@@ -365,8 +356,7 @@ void WebContentsDelegateAndroid::EnterFullscreenModeForTab(
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_toggleFullscreenModeForTab(env, obj.obj(),
- true);
+ Java_WebContentsDelegateAndroid_toggleFullscreenModeForTab(env, obj, true);
}
void WebContentsDelegateAndroid::ExitFullscreenModeForTab(
@@ -375,8 +365,7 @@ void WebContentsDelegateAndroid::ExitFullscreenModeForTab(
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_toggleFullscreenModeForTab(env, obj.obj(),
- false);
+ Java_WebContentsDelegateAndroid_toggleFullscreenModeForTab(env, obj, false);
}
bool WebContentsDelegateAndroid::IsFullscreenForTabOrPending(
@@ -385,8 +374,7 @@ bool WebContentsDelegateAndroid::IsFullscreenForTabOrPending(
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return false;
- return Java_WebContentsDelegateAndroid_isFullscreenForTabOrPending(
- env, obj.obj());
+ return Java_WebContentsDelegateAndroid_isFullscreenForTabOrPending(env, obj);
}
void WebContentsDelegateAndroid::ShowValidationMessage(
@@ -425,14 +413,4 @@ void WebContentsDelegateAndroid::RequestAppBannerFromDevTools(
content::WebContents* web_contents) {
}
-// ----------------------------------------------------------------------------
-// Native JNI methods
-// ----------------------------------------------------------------------------
-
-// Register native methods
-
-bool RegisterWebContentsDelegateAndroid(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace web_contents_delegate_android
diff --git a/chromium/components/web_contents_delegate_android/web_contents_delegate_android.h b/chromium/components/web_contents_delegate_android/web_contents_delegate_android.h
index 26568221673..7edcdd6549c 100644
--- a/chromium/components/web_contents_delegate_android/web_contents_delegate_android.h
+++ b/chromium/components/web_contents_delegate_android/web_contents_delegate_android.h
@@ -72,6 +72,7 @@ class WebContentsDelegateAndroid : public content::WebContentsDelegate {
void RendererUnresponsive(content::WebContents* source) override;
void RendererResponsive(content::WebContents* source) override;
void WebContentsCreated(content::WebContents* source_contents,
+ int opener_render_process_id,
int opener_render_frame_id,
const std::string& frame_name,
const GURL& target_url,
@@ -101,6 +102,9 @@ class WebContentsDelegateAndroid : public content::WebContentsDelegate {
const content::NativeWebKeyboardEvent& event) override;
bool TakeFocus(content::WebContents* source, bool reverse) override;
void ShowRepostFormWarningDialog(content::WebContents* source) override;
+ base::android::ScopedJavaLocalRef<jobject>
+ GetContentVideoViewEmbedder() override;
+ bool ShouldBlockMediaRequest(const GURL& url) override;
void EnterFullscreenModeForTab(content::WebContents* web_contents,
const GURL& origin) override;
void ExitFullscreenModeForTab(content::WebContents* web_contents) override;
@@ -128,8 +132,6 @@ class WebContentsDelegateAndroid : public content::WebContentsDelegate {
std::unique_ptr<ValidationMessageBubbleAndroid> validation_message_bubble_;
};
-bool RegisterWebContentsDelegateAndroid(JNIEnv* env);
-
} // namespace web_contents_delegate_android
#endif // COMPONENTS_WEB_CONTENTS_DELEGATE_ANDROID_WEB_CONTENTS_DELEGATE_ANDROID_H_
diff --git a/chromium/components/web_modal.gypi b/chromium/components/web_modal.gypi
deleted file mode 100644
index cb257daa647..00000000000
--- a/chromium/components/web_modal.gypi
+++ /dev/null
@@ -1,48 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/web_modal
- 'target_name': 'web_modal',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../skia/skia.gyp:skia',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'web_modal/modal_dialog_host.cc',
- 'web_modal/modal_dialog_host.h',
- 'web_modal/single_web_contents_dialog_manager.h',
- 'web_modal/web_contents_modal_dialog_host.cc',
- 'web_modal/web_contents_modal_dialog_host.h',
- 'web_modal/web_contents_modal_dialog_manager.cc',
- 'web_modal/web_contents_modal_dialog_manager.h',
- 'web_modal/web_contents_modal_dialog_manager_delegate.cc',
- 'web_modal/web_contents_modal_dialog_manager_delegate.h',
- ],
- },
- {
- # GN version: //components/web_modal:test_support
- 'target_name': 'web_modal_test_support',
- 'type': 'static_library',
- 'dependencies': [
- 'web_modal',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'web_modal/test_web_contents_modal_dialog_host.cc',
- 'web_modal/test_web_contents_modal_dialog_host.h',
- 'web_modal/test_web_contents_modal_dialog_manager_delegate.cc',
- 'web_modal/test_web_contents_modal_dialog_manager_delegate.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager.cc b/chromium/components/web_modal/web_contents_modal_dialog_manager.cc
index 52b40458029..a417685ac10 100644
--- a/chromium/components/web_modal/web_contents_modal_dialog_manager.cc
+++ b/chromium/components/web_modal/web_contents_modal_dialog_manager.cc
@@ -35,12 +35,6 @@ void WebContentsModalDialogManager::SetDelegate(
}
}
-void WebContentsModalDialogManager::ShowModalDialog(gfx::NativeWindow dialog) {
- std::unique_ptr<SingleWebContentsDialogManager> mgr(
- CreateNativeWebModalManager(dialog, this));
- ShowDialogWithManager(dialog, std::move(mgr));
-}
-
// TODO(gbillock): Maybe "ShowBubbleWithManager"?
void WebContentsModalDialogManager::ShowDialogWithManager(
gfx::NativeWindow dialog,
diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager.h b/chromium/components/web_modal/web_contents_modal_dialog_manager.h
index 6505301c215..9d964d1c4ed 100644
--- a/chromium/components/web_modal/web_contents_modal_dialog_manager.h
+++ b/chromium/components/web_modal/web_contents_modal_dialog_manager.h
@@ -9,6 +9,7 @@
#include <memory>
#include "base/macros.h"
+#include "build/build_config.h"
#include "components/web_modal/single_web_contents_dialog_manager.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
@@ -29,13 +30,13 @@ class WebContentsModalDialogManager
WebContentsModalDialogManagerDelegate* delegate() const { return delegate_; }
void SetDelegate(WebContentsModalDialogManagerDelegate* d);
+#if defined(OS_MACOSX)
+ // Note: This method is not defined inside components/web_modal/ as its
+ // definition (needed for Cocoa builds) depends on chrome/browser/ui/cocoa/.
static SingleWebContentsDialogManager* CreateNativeWebModalManager(
gfx::NativeWindow dialog,
SingleWebContentsDialogManagerDelegate* native_delegate);
-
- // Shows the dialog as a web contents modal dialog. The dialog will notify via
- // WillClose() when it is being destroyed.
- void ShowModalDialog(gfx::NativeWindow dialog);
+#endif
// Allow clients to supply their own native dialog manager. Suitable for
// bubble clients.
diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc b/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
index 75c749eb1c8..43fc22ec55f 100644
--- a/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
+++ b/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
@@ -123,17 +123,6 @@ class WebContentsModalDialogManagerTest
DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManagerTest);
};
-SingleWebContentsDialogManager*
-WebContentsModalDialogManager::CreateNativeWebModalManager(
- gfx::NativeWindow dialog,
- SingleWebContentsDialogManagerDelegate* native_delegate) {
- NOTREACHED();
- return new TestNativeWebContentsModalDialogManager(
- dialog,
- native_delegate,
- &unused_tracker);
-}
-
// Test that the dialog is shown immediately when the delegate indicates the web
// contents is visible.
TEST_F(WebContentsModalDialogManagerTest, WebContentsVisible) {
diff --git a/chromium/components/web_resource.gypi b/chromium/components/web_resource.gypi
deleted file mode 100644
index c3a05034519..00000000000
--- a/chromium/components/web_resource.gypi
+++ /dev/null
@@ -1,50 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/web_resource
- 'target_name': 'web_resource',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../ui/base/ui_base.gyp:ui_base',
- '../net/net.gyp:net',
- 'pref_registry',
- 'version_info',
- ],
- 'sources': [
- 'web_resource/eula_accepted_notifier.cc',
- 'web_resource/eula_accepted_notifier.h',
- 'web_resource/promo_resource_service.cc',
- 'web_resource/promo_resource_service.h',
- 'web_resource/resource_request_allowed_notifier.cc',
- 'web_resource/resource_request_allowed_notifier.h',
- 'web_resource/web_resource_pref_names.cc',
- 'web_resource/web_resource_pref_names.h',
- 'web_resource/web_resource_service.cc',
- 'web_resource/web_resource_service.h',
- ],
- },
- {
- # GN version: //components/web_resources:test_support
- 'target_name': 'web_resource_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'web_resource',
- ],
- 'sources': [
- 'web_resource/resource_request_allowed_notifier_test_util.cc',
- 'web_resource/resource_request_allowed_notifier_test_util.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/web_resource/BUILD.gn b/chromium/components/web_resource/BUILD.gn
index 02287212bec..7d4f5f4d7b2 100644
--- a/chromium/components/web_resource/BUILD.gn
+++ b/chromium/components/web_resource/BUILD.gn
@@ -6,8 +6,6 @@ static_library("web_resource") {
sources = [
"eula_accepted_notifier.cc",
"eula_accepted_notifier.h",
- "promo_resource_service.cc",
- "promo_resource_service.h",
"resource_request_allowed_notifier.cc",
"resource_request_allowed_notifier.h",
"web_resource_pref_names.cc",
diff --git a/chromium/components/web_resource/promo_resource_service.cc b/chromium/components/web_resource/promo_resource_service.cc
deleted file mode 100644
index dbefc3037ae..00000000000
--- a/chromium/components/web_resource/promo_resource_service.cc
+++ /dev/null
@@ -1,31 +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 "components/web_resource/promo_resource_service.h"
-
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/web_resource/web_resource_pref_names.h"
-
-namespace web_resource {
-
-static const char kPrefPromoObject[] = "promo";
-
-// static
-void PromoResourceService::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterStringPref(prefs::kNtpPromoResourceCacheUpdate, "0");
- registry->RegisterDictionaryPref(kPrefPromoObject);
-}
-
-// static
-void PromoResourceService::ClearLocalState(PrefService* local_state) {
- local_state->ClearPref(prefs::kNtpPromoResourceCacheUpdate);
- local_state->ClearPref(kPrefPromoObject);
-}
-
-PromoResourceService::PromoResourceService() {}
-
-PromoResourceService::~PromoResourceService() {}
-
-} // namespace web_resource
diff --git a/chromium/components/web_resource/promo_resource_service.h b/chromium/components/web_resource/promo_resource_service.h
deleted file mode 100644
index 83ef9ddfdf2..00000000000
--- a/chromium/components/web_resource/promo_resource_service.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 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 COMPONENTS_WEB_RESOURCE_PROMO_RESOURCE_SERVICE_H_
-#define COMPONENTS_WEB_RESOURCE_PROMO_RESOURCE_SERVICE_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-
-class PrefRegistrySimple;
-class PrefService;
-
-namespace web_resource {
-
-// This class is being removed <https://crbug.com/576772>. It currently only
-// exists to delete its old preferences.
-class PromoResourceService {
- public:
- static void RegisterPrefs(PrefRegistrySimple* registry);
- static void ClearLocalState(PrefService* local_state);
-
- private:
- PromoResourceService();
- ~PromoResourceService();
-
- DISALLOW_COPY_AND_ASSIGN(PromoResourceService);
-};
-
-} // namespace web_resource
-
-#endif // COMPONENTS_WEB_RESOURCE_PROMO_RESOURCE_SERVICE_H_
diff --git a/chromium/components/web_resource/web_resource_pref_names.cc b/chromium/components/web_resource/web_resource_pref_names.cc
index 51ae76f570b..5fb4df7fb36 100644
--- a/chromium/components/web_resource/web_resource_pref_names.cc
+++ b/chromium/components/web_resource/web_resource_pref_names.cc
@@ -9,7 +9,4 @@ namespace prefs {
// A boolean pref of the EULA accepted flag.
const char kEulaAccepted[] = "EulaAccepted";
-// Last time of update of promo_resource_cache.
-const char kNtpPromoResourceCacheUpdate[] = "ntp.promo_resource_cache_update";
-
} // namespace prefs
diff --git a/chromium/components/web_resource/web_resource_pref_names.h b/chromium/components/web_resource/web_resource_pref_names.h
index 0fa4f43789b..5aad2b61c6e 100644
--- a/chromium/components/web_resource/web_resource_pref_names.h
+++ b/chromium/components/web_resource/web_resource_pref_names.h
@@ -8,7 +8,6 @@
namespace prefs {
extern const char kEulaAccepted[];
-extern const char kNtpPromoResourceCacheUpdate[];
} // namespace prefs
diff --git a/chromium/components/web_resource/web_resource_service.cc b/chromium/components/web_resource/web_resource_service.cc
index 6e05d4159c1..544b9d8809e 100644
--- a/chromium/components/web_resource/web_resource_service.cc
+++ b/chromium/components/web_resource/web_resource_service.cc
@@ -79,7 +79,7 @@ void WebResourceService::OnURLFetchComplete(const net::URLFetcher* source) {
// (on Android in particular) we short-cut the full parsing in the case of
// trivially "empty" JSONs.
if (data.empty() || data == "{}") {
- OnUnpackFinished(base::WrapUnique(new base::DictionaryValue()));
+ OnUnpackFinished(base::MakeUnique<base::DictionaryValue>());
} else {
parse_json_callback_.Run(data,
base::Bind(&WebResourceService::OnUnpackFinished,
diff --git a/chromium/components/web_restrictions.gypi b/chromium/components/web_restrictions.gypi
deleted file mode 100644
index fa42754f54f..00000000000
--- a/chromium/components/web_restrictions.gypi
+++ /dev/null
@@ -1,117 +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.
-
-{
- 'conditions': [
- ['OS == "android"', {
- 'targets': [
- {
- # GN: //components/web_restrictions:web_restrictions_java
- 'target_name': 'web_restrictions_java',
- 'type': 'none',
- 'variables': {
- 'java_in_dir': 'web_restrictions/browser/java',
- },
- 'dependencies': [
- '../base/base.gyp:base',
- ],
- 'includes': [ '../build/java.gypi' ],
- },
- {
- # GN: //components/web_restrictions:web_restrictions_jni_headers
- 'target_name': 'web_restrictions_jni_headers',
- 'type': 'none',
- 'sources': [
- 'web_restrictions/browser/java/src/org/chromium/components/webrestrictions/WebRestrictionsClient.java',
- ],
- 'variables': {
- 'jni_gen_package': 'components/web_restrictions',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- # GN: //components/web_restrictions:browser
- 'target_name': 'web_restrictions_browser',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/content/content.gyp:content_browser',
- 'web_restrictions_jni_headers',
- ],
- 'sources': [
- "web_restrictions/browser/web_restrictions_client.cc",
- "web_restrictions/browser/web_restrictions_client.h",
- "web_restrictions/browser/web_restrictions_resource_throttle.cc",
- "web_restrictions/browser/web_restrictions_resource_throttle.h",
- ],
- },
- {
- # GN: //components/web_restrictions:renderer
- 'target_name': 'web_restrictions_renderer',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/content/content.gyp:content_browser',
- 'web_restrictions_jni_headers',
- ],
- 'sources': [
- "web_restrictions/renderer/web_restrictions_gin_wrapper.cc",
- "web_restrictions/renderer/web_restrictions_gin_wrapper.h",
- ],
- },
- {
- 'target_name': 'web_restrictions_test_support_jni_headers',
- 'type': 'none',
- 'sources': [
- 'web_restrictions/browser/javatest/src/org/chromium/components/webrestrictions/MockWebRestrictionsClient.java',
- ],
- 'variables': {
- 'jni_gen_package': 'components/web_restrictions',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- 'target_name': 'web_restrictions_test_support_java',
- 'type': 'none',
- 'dependencies': [
- 'components.gyp:web_restrictions_java',
- '../base/base.gyp:base_java',
- ],
- 'variables': {
- 'java_in_dir': [
- 'web_restrictions/browser/javatest/'
- ],
- },
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'web_restrictions_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- 'web_restrictions_test_support_jni_headers',
- ],
- 'sources': [
- 'web_restrictions/browser/mock_web_restrictions_client.cc',
- 'web_restrictions/browser/mock_web_restrictions_client.h',
- ],
- },
- {
- 'target_name': 'components_web_restrictions_junit_tests',
- 'type': 'none',
- 'dependencies': [
- '../testing/android/junit/junit_test.gyp:junit_test_support',
- ],
- 'variables': {
- 'main_class': 'org.chromium.testing.local.JunitTestMain',
- 'src_paths': [
- '../testing/android/junit/DummyTest.java',
- ],
- 'wrapper_script_name': 'helper/<(_target_name)',
- },
- 'includes': [ '../build/host_jar.gypi' ],
- },
- ],
- }]]
-}
diff --git a/chromium/components/web_restrictions/BUILD.gn b/chromium/components/web_restrictions/BUILD.gn
index f6850ef7629..89c8b33d7de 100644
--- a/chromium/components/web_restrictions/BUILD.gn
+++ b/chromium/components/web_restrictions/BUILD.gn
@@ -3,73 +3,71 @@
# found in the LICENSE file.
import("//build/config/android/rules.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
import("//testing/test.gni")
if (is_android) {
- # GYP: components.gyp:web_restrictions_java
android_library("web_restrictions_java") {
java_files = [
- "browser/java/src/org/chromium/components/webrestrictions/WebRestrictionsContentProvider.java",
- "browser/java/src/org/chromium/components/webrestrictions/WebRestrictionsClient.java",
+ "browser/java/src/org/chromium/components/webrestrictions/browser/WebRestrictionsContentProvider.java",
+ "browser/java/src/org/chromium/components/webrestrictions/browser/WebRestrictionsClient.java",
+ "browser/java/src/org/chromium/components/webrestrictions/browser/WebRestrictionsClientResult.java",
]
deps = [
"//base:base_java",
]
}
- # GYP: //components/components_test.gyp:components_junit_tests
junit_binary("components_web_restrictions_junit_tests") {
java_files = [
- "browser/junit/src/org/chromium/components/webrestrictions/WebRestrictionsContentProviderTest.java",
- "browser/junit/src/org/chromium/components/webrestrictions/WebRestrictionsClientTest.java",
+ "browser/junit/src/org/chromium/components/webrestrictions/browser/WebRestrictionsContentProviderTest.java",
+ "browser/junit/src/org/chromium/components/webrestrictions/browser/WebRestrictionsClientTest.java",
]
deps = [
":web_restrictions_java",
"//base:base_java",
- "//third_party/junit:hamcrest",
+ "//third_party/hamcrest:hamcrest_java",
]
}
generate_jni("web_restrictions_jni_headers") {
sources = [
- "browser/java/src/org/chromium/components/webrestrictions/WebRestrictionsClient.java",
+ "browser/java/src/org/chromium/components/webrestrictions/browser/WebRestrictionsClient.java",
+ "browser/java/src/org/chromium/components/webrestrictions/browser/WebRestrictionsClientResult.java",
]
jni_package = "web_restrictions"
}
- # GYP: components.gyp:web_restrictions_browser
static_library("browser") {
sources = [
"browser/web_restrictions_client.cc",
"browser/web_restrictions_client.h",
+ "browser/web_restrictions_client_result.cc",
+ "browser/web_restrictions_client_result.h",
+ "browser/web_restrictions_mojo_implementation.cc",
+ "browser/web_restrictions_mojo_implementation.h",
"browser/web_restrictions_resource_throttle.cc",
"browser/web_restrictions_resource_throttle.h",
]
deps = [
+ ":interfaces",
":web_restrictions_jni_headers",
"//base",
"//content/public/browser",
- "//net",
+ "//mojo/public/cpp/bindings:bindings",
+ "//net:net",
]
}
- # GYP: components.gyp:web_restrictions_renderer
- static_library("renderer") {
+ mojom("interfaces") {
sources = [
- "renderer/web_restrictions_gin_wrapper.cc",
- "renderer/web_restrictions_gin_wrapper.h",
- ]
- deps = [
- "//base",
- "//content/public/renderer",
- "//gin",
- "//third_party/WebKit/public:blink_headers",
+ "interfaces/web_restrictions.mojom",
]
}
generate_jni("test_support_jni_headers") {
sources = [
- "browser/javatest/src/org/chromium/components/webrestrictions/MockWebRestrictionsClient.java",
+ "browser/javatest/src/org/chromium/components/webrestrictions/browser/MockWebRestrictionsClient.java",
]
jni_package = "web_restrictions"
deps = [
@@ -78,7 +76,7 @@ if (is_android) {
}
android_library("test_support_java") {
- java_files = [ "browser/javatest/src/org/chromium/components/webrestrictions/MockWebRestrictionsClient.java" ]
+ java_files = [ "browser/javatest/src/org/chromium/components/webrestrictions/browser/MockWebRestrictionsClient.java" ]
deps = [
":web_restrictions_java",
"//base:base_java",
diff --git a/chromium/components/web_restrictions/browser/DEPS b/chromium/components/web_restrictions/browser/DEPS
index 9e20e2009ad..084960ff934 100644
--- a/chromium/components/web_restrictions/browser/DEPS
+++ b/chromium/components/web_restrictions/browser/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+content/public/browser",
"+content/public/test",
"+jni",
+ "+mojo/public/cpp/bindings",
"+net",
"+url",
]
diff --git a/chromium/components/web_restrictions/browser/mock_web_restrictions_client.cc b/chromium/components/web_restrictions/browser/mock_web_restrictions_client.cc
index acc849cc3e0..28edb45778d 100644
--- a/chromium/components/web_restrictions/browser/mock_web_restrictions_client.cc
+++ b/chromium/components/web_restrictions/browser/mock_web_restrictions_client.cc
@@ -18,9 +18,5 @@ MockWebRestrictionsClient::~MockWebRestrictionsClient() {
base::android::AttachCurrentThread());
}
-bool MockWebRestrictionsClient::Register(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace web_restrictions
diff --git a/chromium/components/web_restrictions/browser/mock_web_restrictions_client.h b/chromium/components/web_restrictions/browser/mock_web_restrictions_client.h
index 45dd4eb1603..056f2cf4fc2 100644
--- a/chromium/components/web_restrictions/browser/mock_web_restrictions_client.h
+++ b/chromium/components/web_restrictions/browser/mock_web_restrictions_client.h
@@ -17,8 +17,6 @@ class MockWebRestrictionsClient {
MockWebRestrictionsClient();
~MockWebRestrictionsClient();
-
- static bool Register(JNIEnv* env);
};
} // namespace web_restrictions
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_client.cc b/chromium/components/web_restrictions/browser/web_restrictions_client.cc
index bb1a99bbb2e..559821d61b1 100644
--- a/chromium/components/web_restrictions/browser/web_restrictions_client.cc
+++ b/chromium/components/web_restrictions/browser/web_restrictions_client.cc
@@ -7,6 +7,7 @@
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/public/browser/browser_thread.h"
#include "jni/WebRestrictionsClient_jni.h"
@@ -20,18 +21,18 @@ namespace {
const size_t kMaxCacheSize = 100;
bool RequestPermissionTask(
- const GURL& url,
+ const std::string& url,
const base::android::JavaRef<jobject>& java_provider) {
JNIEnv* env = base::android::AttachCurrentThread();
return Java_WebRestrictionsClient_requestPermission(
- env, java_provider.obj(),
- base::android::ConvertUTF8ToJavaString(env, url.spec()).obj());
+ env, java_provider,
+ base::android::ConvertUTF8ToJavaString(env, url));
}
bool CheckSupportsRequestTask(
const base::android::JavaRef<jobject>& java_provider) {
JNIEnv* env = base::android::AttachCurrentThread();
- return Java_WebRestrictionsClient_supportsRequest(env, java_provider.obj());
+ return Java_WebRestrictionsClient_supportsRequest(env, java_provider);
}
} // namespace
@@ -43,7 +44,6 @@ bool WebRestrictionsClient::Register(JNIEnv* env) {
WebRestrictionsClient::WebRestrictionsClient()
: initialized_(false), supports_request_(false) {
- single_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
base::SequencedWorkerPool* worker_pool =
content::BrowserThread::GetBlockingPool();
background_task_runner_ =
@@ -56,17 +56,27 @@ WebRestrictionsClient::~WebRestrictionsClient() {
if (java_provider_.is_null())
return;
JNIEnv* env = base::android::AttachCurrentThread();
- Java_WebRestrictionsClient_onDestroy(env, java_provider_.obj());
+ Java_WebRestrictionsClient_onDestroy(env, java_provider_);
java_provider_.Reset();
}
void WebRestrictionsClient::SetAuthority(
const std::string& content_provider_authority) {
- DCHECK(single_thread_task_runner_->BelongsToCurrentThread());
+ // This is called from the UI thread, but class members should only be
+ // accessed from the IO thread.
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::Bind(&WebRestrictionsClient::SetAuthorityTask,
+ base::Unretained(this), content_provider_authority));
+}
+
+void WebRestrictionsClient::SetAuthorityTask(
+ const std::string& content_provider_authority) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// Destroy any existing content resolver.
JNIEnv* env = base::android::AttachCurrentThread();
if (!java_provider_.is_null()) {
- Java_WebRestrictionsClient_onDestroy(env, java_provider_.obj());
+ Java_WebRestrictionsClient_onDestroy(env, java_provider_);
java_provider_.Reset();
}
ClearCache();
@@ -78,8 +88,7 @@ void WebRestrictionsClient::SetAuthority(
return;
java_provider_.Reset(Java_WebRestrictionsClient_create(
env,
- base::android::ConvertUTF8ToJavaString(env, content_provider_authority)
- .obj(),
+ base::android::ConvertUTF8ToJavaString(env, content_provider_authority),
reinterpret_cast<jlong>(this)));
supports_request_ = false;
base::PostTaskAndReplyWithResult(
@@ -91,18 +100,17 @@ void WebRestrictionsClient::SetAuthority(
UrlAccess WebRestrictionsClient::ShouldProceed(
bool is_main_frame,
- const GURL& url,
+ const std::string& url,
const base::Callback<void(bool)>& callback) {
- DCHECK(single_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!initialized_)
return ALLOW;
- auto iter = cache_.find(url);
- if (iter != cache_.end()) {
+
+ std::unique_ptr<const WebRestrictionsClientResult> result =
+ cache_.GetCacheEntry(url);
+ if (result) {
RecordURLAccess(url);
- JNIEnv* env = base::android::AttachCurrentThread();
- return Java_ShouldProceedResult_shouldProceed(env, iter->second.obj())
- ? ALLOW
- : DISALLOW;
+ return result->ShouldProceed() ? ALLOW : DISALLOW;
}
base::PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE,
@@ -118,62 +126,8 @@ bool WebRestrictionsClient::SupportsRequest() const {
return initialized_ && supports_request_;
}
-int WebRestrictionsClient::GetResultColumnCount(const GURL& url) const {
- DCHECK(single_thread_task_runner_->BelongsToCurrentThread());
- if (!initialized_)
- return 0;
- auto iter = cache_.find(url);
- if (iter == cache_.end())
- return 0;
- return Java_ShouldProceedResult_getColumnCount(
- base::android::AttachCurrentThread(), iter->second.obj());
-}
-
-std::string WebRestrictionsClient::GetResultColumnName(const GURL& url,
- int column) const {
- DCHECK(single_thread_task_runner_->BelongsToCurrentThread());
- if (!initialized_)
- return std::string();
- auto iter = cache_.find(url);
- if (iter == cache_.end())
- return std::string();
-
- JNIEnv* env = base::android::AttachCurrentThread();
- return base::android::ConvertJavaStringToUTF8(
- env,
- Java_ShouldProceedResult_getColumnName(env, iter->second.obj(), column)
- .obj());
-}
-
-int WebRestrictionsClient::GetResultIntValue(const GURL& url,
- int column) const {
- DCHECK(single_thread_task_runner_->BelongsToCurrentThread());
- if (!initialized_)
- return 0;
- auto iter = cache_.find(url);
- if (iter == cache_.end())
- return 0;
- return Java_ShouldProceedResult_getInt(base::android::AttachCurrentThread(),
- iter->second.obj(), column);
-}
-
-std::string WebRestrictionsClient::GetResultStringValue(const GURL& url,
- int column) const {
- DCHECK(single_thread_task_runner_->BelongsToCurrentThread());
- if (!initialized_)
- return std::string();
- auto iter = cache_.find(url);
- if (iter == cache_.end())
- return std::string();
-
- JNIEnv* env = base::android::AttachCurrentThread();
- return base::android::ConvertJavaStringToUTF8(
- env, Java_ShouldProceedResult_getString(env, iter->second.obj(), column)
- .obj());
-}
-
void WebRestrictionsClient::RequestPermission(
- const GURL& url,
+ const std::string& url,
const base::Callback<void(bool)>& request_success) {
if (!initialized_) {
request_success.Run(false);
@@ -184,40 +138,43 @@ void WebRestrictionsClient::RequestPermission(
base::Bind(&RequestPermissionTask, url, java_provider_), request_success);
}
-void WebRestrictionsClient::OnWebRestrictionsChanged() {
- single_thread_task_runner_->PostTask(
- FROM_HERE,
+void WebRestrictionsClient::OnWebRestrictionsChanged(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
base::Bind(&WebRestrictionsClient::ClearCache, base::Unretained(this)));
}
-void WebRestrictionsClient::RecordURLAccess(const GURL& url) {
- DCHECK(single_thread_task_runner_->BelongsToCurrentThread());
+void WebRestrictionsClient::RecordURLAccess(const std::string& url) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// Move the URL to the front of the cache.
recent_urls_.remove(url);
recent_urls_.push_front(url);
}
-void WebRestrictionsClient::UpdateCache(std::string provider_authority,
- GURL url,
+void WebRestrictionsClient::UpdateCache(const std::string& provider_authority,
+ const std::string& url,
ScopedJavaGlobalRef<jobject> result) {
- DCHECK(single_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// If the webrestrictions provider changed when the old one was being queried,
// do not update the cache for the new provider.
if (provider_authority != provider_authority_)
return;
RecordURLAccess(url);
if (recent_urls_.size() >= kMaxCacheSize) {
- cache_.erase(recent_urls_.back());
+ cache_.RemoveCacheEntry(recent_urls_.back());
recent_urls_.pop_back();
}
- cache_[url] = result;
+ cache_.SetCacheEntry(url, WebRestrictionsClientResult(result));
}
-void WebRestrictionsClient::RequestSupportKnown(std::string provider_authority,
- bool supports_request) {
+void WebRestrictionsClient::RequestSupportKnown(
+ const std::string& provider_authority,
+ bool supports_request) {
// |supports_request_| is initialized to false.
DCHECK(!supports_request_);
- DCHECK(single_thread_task_runner_->BelongsToCurrentThread());
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// If the webrestrictions provider changed when the old one was being queried,
// ignore the result.
if (provider_authority != provider_authority_)
@@ -227,40 +184,66 @@ void WebRestrictionsClient::RequestSupportKnown(std::string provider_authority,
void WebRestrictionsClient::OnShouldProceedComplete(
std::string provider_authority,
- const GURL& url,
+ const std::string& url,
const base::Callback<void(bool)>& callback,
const ScopedJavaGlobalRef<jobject>& result) {
UpdateCache(provider_authority, url, result);
- JNIEnv* env = base::android::AttachCurrentThread();
- callback.Run(Java_ShouldProceedResult_shouldProceed(env, result.obj()));
+ callback.Run(cache_.GetCacheEntry(url)->ShouldProceed());
}
void WebRestrictionsClient::ClearCache() {
- DCHECK(single_thread_task_runner_->BelongsToCurrentThread());
- cache_.clear();
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ cache_.Clear();
recent_urls_.clear();
}
+std::unique_ptr<WebRestrictionsClientResult>
+WebRestrictionsClient::GetCachedWebRestrictionsResult(const std::string& url) {
+ return cache_.GetCacheEntry(url);
+}
+
// static
ScopedJavaGlobalRef<jobject> WebRestrictionsClient::ShouldProceedTask(
- const GURL& url,
+ const std::string& url,
const base::android::JavaRef<jobject>& java_provider) {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaGlobalRef<jobject> result(
Java_WebRestrictionsClient_shouldProceed(
- env, java_provider.obj(),
- base::android::ConvertUTF8ToJavaString(env, url.spec()).obj()));
+ env, java_provider,
+ base::android::ConvertUTF8ToJavaString(env, url)));
return result;
}
-void NotifyWebRestrictionsChanged(
- JNIEnv* env,
- const base::android::JavaParamRef<jobject>& clazz,
- jlong provider_ptr) {
- WebRestrictionsClient* provider =
- reinterpret_cast<WebRestrictionsClient*>(provider_ptr);
- // TODO(knn): Also reload existing interstitials/error pages.
- provider->OnWebRestrictionsChanged();
+WebRestrictionsClient::Cache::Cache() = default;
+
+WebRestrictionsClient::Cache::~Cache() = default;
+
+std::unique_ptr<WebRestrictionsClientResult>
+WebRestrictionsClient::Cache::GetCacheEntry(const std::string& url) {
+ base::AutoLock lock(lock_);
+ auto iter = cache_data_.find(url);
+ if (iter == cache_data_.end())
+ return nullptr;
+ // This has to be thread-safe, so copy the data.
+ return std::unique_ptr<WebRestrictionsClientResult>(
+ new WebRestrictionsClientResult(iter->second));
+}
+
+void WebRestrictionsClient::Cache::SetCacheEntry(
+ const std::string& url,
+ const WebRestrictionsClientResult& entry) {
+ base::AutoLock lock(lock_);
+ cache_data_.emplace(url, entry);
+}
+
+void WebRestrictionsClient::Cache::RemoveCacheEntry(const std::string& url) {
+ base::AutoLock lock(lock_);
+ cache_data_.erase(url);
+}
+
+void WebRestrictionsClient::Cache::Clear() {
+ base::AutoLock lock(lock_);
+ cache_data_.clear();
}
} // namespace web_restrictions
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_client.h b/chromium/components/web_restrictions/browser/web_restrictions_client.h
index bad0b608ef0..3bd54d9342c 100644
--- a/chromium/components/web_restrictions/browser/web_restrictions_client.h
+++ b/chromium/components/web_restrictions/browser/web_restrictions_client.h
@@ -6,9 +6,10 @@
#define COMPONENTS_WEB_RESTRICTION_WEB_RESTRICTIONS_CLIENT_H_
#include <jni.h>
+
#include <list>
-#include <map>
#include <string>
+#include <unordered_map>
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
@@ -17,7 +18,8 @@
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
-#include "url/gurl.h"
+#include "base/synchronization/lock.h"
+#include "components/web_restrictions/browser/web_restrictions_client_result.h"
namespace web_restrictions {
@@ -42,44 +44,67 @@ class WebRestrictionsClient {
// WebRestrictionsProvider:
UrlAccess ShouldProceed(bool is_main_frame,
- const GURL& url,
+ const std::string& url,
const base::Callback<void(bool)>& callback);
bool SupportsRequest() const;
- int GetResultColumnCount(const GURL& url) const;
-
- std::string GetResultColumnName(const GURL& url, int column) const;
-
- int GetResultIntValue(const GURL& url, int column) const;
-
- std::string GetResultStringValue(const GURL& url, int column) const;
-
- void RequestPermission(const GURL& url,
+ void RequestPermission(const std::string& url,
const base::Callback<void(bool)>& callback);
- void OnWebRestrictionsChanged();
+ void OnWebRestrictionsChanged(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj);
- private:
-
- void RecordURLAccess(const GURL& url);
+ // Get a cached WebRestrictionsResult synchronously, for use when building
+ // error pages etc.. May be called on any thread, and will return a fresh copy
+ // of the result (hence thread safe).
+ std::unique_ptr<WebRestrictionsClientResult> GetCachedWebRestrictionsResult(
+ const std::string& url);
- void UpdateCache(std::string provider_authority,
- GURL url,
+ private:
+ // Make the test classes friends, so that they can set the authority
+ // synchronously
+ friend class WebRestrictionsResourceThrottleTest;
+ friend class WebRestrictionsClientTest;
+
+ class Cache {
+ public:
+ Cache();
+ ~Cache();
+ std::unique_ptr<WebRestrictionsClientResult> GetCacheEntry(
+ const std::string& url);
+ void SetCacheEntry(const std::string& url,
+ const WebRestrictionsClientResult& entry);
+ void RemoveCacheEntry(const std::string& url);
+ void Clear();
+
+ private:
+ base::Lock lock_;
+ std::unordered_map<std::string, WebRestrictionsClientResult> cache_data_;
+ DISALLOW_COPY_AND_ASSIGN(Cache);
+ };
+
+ void SetAuthorityTask(const std::string& content_provider_authority);
+
+ void RecordURLAccess(const std::string& url);
+
+ void UpdateCache(const std::string& provider_authority,
+ const std::string& url,
base::android::ScopedJavaGlobalRef<jobject> result);
- void RequestSupportKnown(std::string provider_authority,
+ void RequestSupportKnown(const std::string& provider_authority,
bool supports_request);
void ClearCache();
static base::android::ScopedJavaGlobalRef<jobject> ShouldProceedTask(
- const GURL& url,
+ const std::string& url,
const base::android::JavaRef<jobject>& java_provider);
void OnShouldProceedComplete(
std::string provider_authority,
- const GURL& url,
+ const std::string& url,
const base::Callback<void(bool)>& callback,
const base::android::ScopedJavaGlobalRef<jobject>& result);
@@ -88,12 +113,10 @@ class WebRestrictionsClient {
bool supports_request_;
base::android::ScopedJavaGlobalRef<jobject> java_provider_;
std::string provider_authority_;
+ Cache cache_;
scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> single_thread_task_runner_;
-
- std::map<GURL, base::android::ScopedJavaGlobalRef<jobject>> cache_;
- std::list<GURL> recent_urls_;
+ std::list<std::string> recent_urls_;
DISALLOW_COPY_AND_ASSIGN(WebRestrictionsClient);
};
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_client_result.cc b/chromium/components/web_restrictions/browser/web_restrictions_client_result.cc
new file mode 100644
index 00000000000..6eab3d5beb9
--- /dev/null
+++ b/chromium/components/web_restrictions/browser/web_restrictions_client_result.cc
@@ -0,0 +1,54 @@
+// 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 "base/android/jni_string.h"
+#include "components/web_restrictions/browser/web_restrictions_client_result.h"
+#include "jni/WebRestrictionsClientResult_jni.h"
+
+namespace web_restrictions {
+
+WebRestrictionsClientResult::WebRestrictionsClientResult(
+ base::android::ScopedJavaGlobalRef<jobject>& jresult)
+ : jresult_(jresult) {}
+
+WebRestrictionsClientResult::~WebRestrictionsClientResult() = default;
+
+WebRestrictionsClientResult::WebRestrictionsClientResult(
+ const WebRestrictionsClientResult& other) = default;
+
+int WebRestrictionsClientResult::GetInt(int column) const {
+ return Java_WebRestrictionsClientResult_getInt(
+ base::android::AttachCurrentThread(), jresult_.obj(), column);
+}
+
+std::string WebRestrictionsClientResult::GetString(int column) const {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return base::android::ConvertJavaStringToUTF8(
+ env,
+ Java_WebRestrictionsClientResult_getString(env, jresult_.obj(), column));
+}
+
+std::string WebRestrictionsClientResult::GetColumnName(int column) const {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return base::android::ConvertJavaStringToUTF8(
+ env, Java_WebRestrictionsClientResult_getColumnName(env, jresult_.obj(),
+ column));
+}
+
+bool WebRestrictionsClientResult::ShouldProceed() const {
+ return Java_WebRestrictionsClientResult_shouldProceed(
+ base::android::AttachCurrentThread(), jresult_.obj());
+}
+
+int web_restrictions::WebRestrictionsClientResult::GetColumnCount() const {
+ return Java_WebRestrictionsClientResult_getColumnCount(
+ base::android::AttachCurrentThread(), jresult_.obj());
+}
+
+bool web_restrictions::WebRestrictionsClientResult::IsString(int column) const {
+ return Java_WebRestrictionsClientResult_isString(
+ base::android::AttachCurrentThread(), jresult_.obj(), column);
+}
+
+} // namespace web_restrictions
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_client_result.h b/chromium/components/web_restrictions/browser/web_restrictions_client_result.h
new file mode 100644
index 00000000000..aaf6e6c5732
--- /dev/null
+++ b/chromium/components/web_restrictions/browser/web_restrictions_client_result.h
@@ -0,0 +1,36 @@
+// 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 COMPONENTS_WEB_RESTRICTIONS_BROWSER_WEB_RESTRICTIONS_CLIENT_RESULT_H_
+#define COMPONENTS_WEB_RESTRICTIONS_BROWSER_WEB_RESTRICTIONS_CLIENT_RESULT_H_
+
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+
+namespace web_restrictions {
+
+// Wrapper for Java WebRestrictionsResult
+class WebRestrictionsClientResult {
+ public:
+ WebRestrictionsClientResult(
+ base::android::ScopedJavaGlobalRef<jobject>& jresult);
+ WebRestrictionsClientResult(const WebRestrictionsClientResult& other);
+ ~WebRestrictionsClientResult();
+
+ bool ShouldProceed() const;
+ int GetColumnCount() const;
+ bool IsString(int column) const;
+ int GetInt(int column) const;
+ std::string GetString(int column) const;
+ std::string GetColumnName(int column) const;
+
+ private:
+ base::android::ScopedJavaGlobalRef<jobject> jresult_;
+};
+
+} // namespace web_restrictions
+
+#endif // COMPONENTS_WEB_RESTRICTIONS_BROWSER_WEB_RESTRICTIONS_CLIENT_RESULT_H_
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_client_unittest.cc b/chromium/components/web_restrictions/browser/web_restrictions_client_unittest.cc
index df9782c42fe..d3dd7f2327f 100644
--- a/chromium/components/web_restrictions/browser/web_restrictions_client_unittest.cc
+++ b/chromium/components/web_restrictions/browser/web_restrictions_client_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <memory>
+
#include "base/bind.h"
#include "base/run_loop.h"
#include "components/web_restrictions/browser/mock_web_restrictions_client.h"
@@ -10,6 +12,7 @@
#include "testing/gtest/include/gtest/gtest.h"
using web_restrictions::WebRestrictionsClient;
+using web_restrictions::WebRestrictionsClientResult;
using web_restrictions::MockWebRestrictionsClient;
namespace {
@@ -23,8 +26,13 @@ void ResultCallback(const base::Closure& quit_closure, bool result) {
} // namespace
+namespace web_restrictions {
+
class WebRestrictionsClientTest : public testing::Test {
protected:
+ void SetAuthority(std::string authority) {
+ client_.SetAuthorityTask(authority);
+ }
// Mock the Java WebRestrictionsClient. The real version
// would need a content provider to do anything.
MockWebRestrictionsClient mock_;
@@ -33,90 +41,90 @@ class WebRestrictionsClientTest : public testing::Test {
};
TEST_F(WebRestrictionsClientTest, ShouldProceed) {
- client_.SetAuthority("Good");
+ SetAuthority("Good");
// First call should go to Web Restrictions Content Provider, and return a
// delayed result.
{
g_returned_result = false;
base::RunLoop run_loop;
- EXPECT_EQ(web_restrictions::PENDING,
+ ASSERT_EQ(web_restrictions::PENDING,
client_.ShouldProceed(
- true, GURL("http://example.com"),
+ true, "http://example.com",
base::Bind(&ResultCallback, run_loop.QuitClosure())));
run_loop.Run();
EXPECT_TRUE(g_returned_result);
- EXPECT_EQ(1, client_.GetResultColumnCount(GURL("http://example.com")));
}
// A repeated call should go to the cache and return a result immediately.
{
base::RunLoop run_loop;
- EXPECT_EQ(web_restrictions::ALLOW,
+ ASSERT_EQ(web_restrictions::ALLOW,
client_.ShouldProceed(
- true, GURL("http://example.com"),
+ true, "http://example.com",
base::Bind(&ResultCallback, run_loop.QuitClosure())));
}
// However a different url should miss the cache
{
g_returned_result = false;
base::RunLoop run_loop;
- EXPECT_EQ(web_restrictions::PENDING,
+ ASSERT_EQ(web_restrictions::PENDING,
client_.ShouldProceed(
- true, GURL("http://example.com/2"),
+ true, "http://example.com/2",
base::Bind(&ResultCallback, run_loop.QuitClosure())));
run_loop.Run();
EXPECT_TRUE(g_returned_result);
}
// Switching the authority should clear the cache.
{
- client_.SetAuthority("Good2");
+ SetAuthority("Good2");
g_returned_result = false;
base::RunLoop run_loop;
- EXPECT_EQ(web_restrictions::PENDING,
+ ASSERT_EQ(web_restrictions::PENDING,
client_.ShouldProceed(
- true, GURL("http://example.com/2"),
+ true, "http://example.com/2",
base::Bind(&ResultCallback, run_loop.QuitClosure())));
run_loop.Run();
EXPECT_TRUE(g_returned_result);
}
// Try getting a bad result
{
- client_.SetAuthority("Bad");
+ SetAuthority("Bad");
g_returned_result = true;
base::RunLoop run_loop;
- EXPECT_EQ(web_restrictions::PENDING,
+ ASSERT_EQ(web_restrictions::PENDING,
client_.ShouldProceed(
- true, GURL("http://example.com/2"),
+ true, "http://example.com/2",
base::Bind(&ResultCallback, run_loop.QuitClosure())));
run_loop.Run();
EXPECT_FALSE(g_returned_result);
- EXPECT_EQ(3, client_.GetResultColumnCount(GURL("http://example.com/2")));
- EXPECT_EQ(42, client_.GetResultIntValue(GURL("http://example.com/2"), 1));
- EXPECT_EQ("Error string",
- client_.GetResultColumnName(GURL("http://example.com/2"), 2));
- EXPECT_EQ("http://example.com/2",
- client_.GetResultStringValue(GURL("http://example.com/2"), 2));
+ std::unique_ptr<const WebRestrictionsClientResult> result =
+ client_.GetCachedWebRestrictionsResult("http://example.com/2");
+ ASSERT_NE(nullptr, result.get());
+ EXPECT_EQ(42, result->GetInt(1));
+ EXPECT_EQ("http://example.com/2", result->GetString(2));
}
}
TEST_F(WebRestrictionsClientTest, RequestPermission) {
- client_.SetAuthority("Good");
{
+ SetAuthority("Good");
base::RunLoop run_loop;
g_returned_result = false;
client_.RequestPermission(
- GURL("http://example.com"),
+ "http://example.com",
base::Bind(&ResultCallback, run_loop.QuitClosure()));
run_loop.Run();
EXPECT_TRUE(g_returned_result);
- client_.SetAuthority("Bad");
}
{
+ SetAuthority("Bad");
base::RunLoop run_loop;
g_returned_result = true;
client_.RequestPermission(
- GURL("http://example.com"),
+ "http://example.com",
base::Bind(&ResultCallback, run_loop.QuitClosure()));
run_loop.Run();
EXPECT_FALSE(g_returned_result);
}
}
+
+} // namespace web_restrictions
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_mojo_implementation.cc b/chromium/components/web_restrictions/browser/web_restrictions_mojo_implementation.cc
new file mode 100644
index 00000000000..fe3b6809ae3
--- /dev/null
+++ b/chromium/components/web_restrictions/browser/web_restrictions_mojo_implementation.cc
@@ -0,0 +1,69 @@
+// 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 "components/web_restrictions/browser/web_restrictions_mojo_implementation.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "components/web_restrictions/browser/web_restrictions_client.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace web_restrictions {
+
+namespace {
+
+void ClientRequestPermissionCallback(
+ const mojom::WebRestrictions::RequestPermissionCallback& callback,
+ bool result) {
+ callback.Run(result);
+}
+
+} // namespace
+
+WebRestrictionsMojoImplementation::WebRestrictionsMojoImplementation(
+ WebRestrictionsClient* client)
+ : web_restrictions_client_(client) {}
+
+WebRestrictionsMojoImplementation::~WebRestrictionsMojoImplementation() {}
+
+void WebRestrictionsMojoImplementation::Create(
+ WebRestrictionsClient* client,
+ mojo::InterfaceRequest<mojom::WebRestrictions> request) {
+ mojo::MakeStrongBinding(
+ base::MakeUnique<WebRestrictionsMojoImplementation>(client),
+ std::move(request));
+}
+
+void WebRestrictionsMojoImplementation::GetResult(
+ const std::string& url,
+ const GetResultCallback& callback) {
+ std::unique_ptr<const WebRestrictionsClientResult> web_restrictions_result(
+ web_restrictions_client_->GetCachedWebRestrictionsResult(url));
+ mojom::ClientResultPtr result = mojom::ClientResult::New();
+ if (!web_restrictions_result) {
+ callback.Run(std::move(result));
+ return;
+ }
+ int columnCount = web_restrictions_result->GetColumnCount();
+ for (int i = 0; i < columnCount; i++) {
+ if (web_restrictions_result->IsString(i)) {
+ result->stringParams[web_restrictions_result->GetColumnName(i)] =
+ web_restrictions_result->GetString(i);
+ } else {
+ result->intParams[web_restrictions_result->GetColumnName(i)] =
+ web_restrictions_result->GetInt(i);
+ }
+ }
+ callback.Run(std::move(result));
+}
+
+void WebRestrictionsMojoImplementation::RequestPermission(
+ const std::string& url,
+ const mojom::WebRestrictions::RequestPermissionCallback& callback) {
+ web_restrictions_client_->RequestPermission(
+ url, base::Bind(&ClientRequestPermissionCallback, callback));
+}
+
+} // namespace web_restrictions
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_mojo_implementation.h b/chromium/components/web_restrictions/browser/web_restrictions_mojo_implementation.h
new file mode 100644
index 00000000000..c13c03a76f2
--- /dev/null
+++ b/chromium/components/web_restrictions/browser/web_restrictions_mojo_implementation.h
@@ -0,0 +1,35 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEB_RESTRICTIONS_BROWSER_WEB_RESTRICTIONS_MOJO_IMPLEMENTATION_H_
+#define COMPONENTS_WEB_RESTRICTIONS_BROWSER_WEB_RESTRICTIONS_MOJO_IMPLEMENTATION_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "components/web_restrictions/interfaces/web_restrictions.mojom.h"
+
+namespace web_restrictions {
+
+class WebRestrictionsClient;
+
+class WebRestrictionsMojoImplementation : public mojom::WebRestrictions {
+ public:
+ explicit WebRestrictionsMojoImplementation(WebRestrictionsClient* client);
+ ~WebRestrictionsMojoImplementation() override;
+
+ static void Create(WebRestrictionsClient* client,
+ mojo::InterfaceRequest<mojom::WebRestrictions> request);
+
+ private:
+ void GetResult(const std::string& url,
+ const GetResultCallback& callback) override;
+ void RequestPermission(const std::string& url,
+ const RequestPermissionCallback& callback) override;
+
+ WebRestrictionsClient* web_restrictions_client_;
+};
+
+} // namespace web_restrictions
+#endif // COMPONENTS_WEB_RESTRICTIONS_BROWSER_WEB_RESTRICTIONS_MOJO_IMPLEMENTATION_H_
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle.cc b/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle.cc
index 378fa9216ce..6f83f08faee 100644
--- a/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle.cc
+++ b/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle.cc
@@ -43,7 +43,7 @@ bool WebRestrictionsResourceThrottle::ShouldDefer(const GURL& url) {
if (provider_->SupportsRequest() && !is_main_frame_)
return false;
UrlAccess access = provider_->ShouldProceed(
- is_main_frame_, url,
+ is_main_frame_, url.spec(),
base::Bind(&WebRestrictionsResourceThrottle::OnCheckResult,
weak_ptr_factory_.GetWeakPtr()));
if (access == DISALLOW)
diff --git a/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc b/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc
index f3e7342f0f2..d3b54b882fb 100644
--- a/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc
+++ b/chromium/components/web_restrictions/browser/web_restrictions_resource_throttle_unittest.cc
@@ -60,8 +60,12 @@ class WebRestrictionsResourceThrottleTest : public testing::Test {
throttle_.set_controller_for_testing(&controller_);
}
+ void SetAuthority(std::string authority) {
+ provider_.SetAuthorityTask(authority);
+ }
+
void StartProvider() {
- provider_.SetAuthority("Good");
+ SetAuthority("Good");
bool defer;
throttle_.WillStartRequest(&defer);
run_loop_.Run();
@@ -89,7 +93,7 @@ TEST_F(WebRestrictionsResourceThrottleTest, WillStartRequest_NoAuthority) {
TEST_F(WebRestrictionsResourceThrottleTest, WillStartRequest_DeferredAllow) {
// Test deferring with a resource provider, and that the correct results
// are received.
- provider_.SetAuthority("Good");
+ SetAuthority("Good");
bool defer;
throttle_.WillStartRequest(&defer);
EXPECT_TRUE(defer);
@@ -99,7 +103,7 @@ TEST_F(WebRestrictionsResourceThrottleTest, WillStartRequest_DeferredAllow) {
}
TEST_F(WebRestrictionsResourceThrottleTest, WillStartRequest_DeferredForbid) {
- provider_.SetAuthority("Bad");
+ SetAuthority("Bad");
bool defer;
throttle_.WillStartRequest(&defer);
EXPECT_TRUE(defer);
@@ -123,7 +127,7 @@ TEST_F(WebRestrictionsResourceThrottleTest, WillStartRequest_Subresource) {
throttle.set_controller_for_testing(&test_controller);
bool defer;
throttle.WillStartRequest(&defer);
- EXPECT_FALSE(defer);
+ ASSERT_FALSE(defer);
}
TEST_F(WebRestrictionsResourceThrottleTest, WillRedirectRequest_KnownUrl) {
@@ -134,7 +138,7 @@ TEST_F(WebRestrictionsResourceThrottleTest, WillRedirectRequest_KnownUrl) {
redirect.new_url = GURL("http://example.com");
bool defer;
throttle_.WillRedirectRequest(redirect, &defer);
- EXPECT_FALSE(defer);
+ ASSERT_FALSE(defer);
}
TEST_F(WebRestrictionsResourceThrottleTest, WillRedirectRequest_NewUrl) {
@@ -148,7 +152,7 @@ TEST_F(WebRestrictionsResourceThrottleTest, WillRedirectRequest_NewUrl) {
throttle_.set_controller_for_testing(&test_controller);
bool defer;
throttle_.WillRedirectRequest(redirect, &defer);
- EXPECT_TRUE(defer);
+ ASSERT_TRUE(defer);
// If we don't wait for the callback it may happen after the exit, which
// results in accesses the redirect_url after the stack frame is freed.
test_run_loop.Run();
diff --git a/chromium/components/mus/public/interfaces/OWNERS b/chromium/components/web_restrictions/interfaces/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/components/mus/public/interfaces/OWNERS
+++ b/chromium/components/web_restrictions/interfaces/OWNERS
diff --git a/chromium/components/web_restrictions/interfaces/web_restrictions.mojom b/chromium/components/web_restrictions/interfaces/web_restrictions.mojom
new file mode 100644
index 00000000000..b47e5b91472
--- /dev/null
+++ b/chromium/components/web_restrictions/interfaces/web_restrictions.mojom
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module web_restrictions.mojom;
+
+struct ClientResult {
+ map<string, int32> intParams;
+ map<string, string> stringParams;
+};
+
+interface WebRestrictions {
+ // Get the cached result, if any, of requesting access to a URL; including
+ // key/value pairs for custom error ints and strings. This has to be
+ // synchronous since it is needed to show the error page, and delaying the
+ // error page can result in a race with the Webview API.
+ [Sync]
+ GetResult(string url) => (ClientResult reply);
+
+ // Request
+ RequestPermission(string url) => (bool result);
+};
diff --git a/chromium/components/web_restrictions/renderer/DEPS b/chromium/components/web_restrictions/renderer/DEPS
deleted file mode 100644
index dae8c787f9b..00000000000
--- a/chromium/components/web_restrictions/renderer/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
- "+content/public/renderer",
- "+gin",
- "+third_party/WebKit",
-]
diff --git a/chromium/components/web_restrictions/renderer/web_restrictions_gin_wrapper.cc b/chromium/components/web_restrictions/renderer/web_restrictions_gin_wrapper.cc
deleted file mode 100644
index d94358767df..00000000000
--- a/chromium/components/web_restrictions/renderer/web_restrictions_gin_wrapper.cc
+++ /dev/null
@@ -1,60 +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 "components/web_restrictions/renderer/web_restrictions_gin_wrapper.h"
-
-#include "content/public/renderer/render_frame.h"
-#include "gin/handle.h"
-#include "gin/object_template_builder.h"
-#include "third_party/WebKit/public/web/WebKit.h"
-#include "third_party/WebKit/public/web/WebLocalFrame.h"
-
-namespace web_restrictions {
-
-gin::WrapperInfo WebRestrictionsGinWrapper::kWrapperInfo = {
- gin::kEmbedderNativeGin};
-
-// static
-void WebRestrictionsGinWrapper::Install(content::RenderFrame* render_frame) {
- v8::Isolate* isolate = blink::mainThreadIsolate();
- v8::HandleScope handle_scope(isolate);
- v8::Local<v8::Context> context =
- render_frame->GetWebFrame()->mainWorldScriptContext();
- if (context.IsEmpty())
- return;
- v8::Context::Scope context_scope(context);
- gin::Handle<WebRestrictionsGinWrapper> controller =
- gin::CreateHandle(isolate, new WebRestrictionsGinWrapper(render_frame));
- if (controller.IsEmpty())
- return;
- v8::Local<v8::Object> global = context->Global();
- global->Set(gin::StringToV8(isolate, "webRestriction"), controller.ToV8());
-}
-
-WebRestrictionsGinWrapper::WebRestrictionsGinWrapper(
- content::RenderFrame* render_frame)
- : content::RenderFrameObserver(render_frame) {}
-
-WebRestrictionsGinWrapper::~WebRestrictionsGinWrapper() {}
-
-bool WebRestrictionsGinWrapper::RequestPermission() {
- if (!render_frame())
- return false;
- render_frame()->GetWebFrame()->reload();
- return true;
-}
-
-void WebRestrictionsGinWrapper::OnDestruct() {
- // Do nothing. Overrides version that deletes RenderFrameObserver.
-}
-
-gin::ObjectTemplateBuilder WebRestrictionsGinWrapper::GetObjectTemplateBuilder(
- v8::Isolate* isolate) {
- return gin::Wrappable<WebRestrictionsGinWrapper>::GetObjectTemplateBuilder(
- isolate)
- .SetMethod("requestPermission",
- &WebRestrictionsGinWrapper::RequestPermission);
-}
-
-} // namespace web_restrictions
diff --git a/chromium/components/web_restrictions/renderer/web_restrictions_gin_wrapper.h b/chromium/components/web_restrictions/renderer/web_restrictions_gin_wrapper.h
deleted file mode 100644
index e7d3d3fc4f1..00000000000
--- a/chromium/components/web_restrictions/renderer/web_restrictions_gin_wrapper.h
+++ /dev/null
@@ -1,46 +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 COMPONENTS_WEB_RESTRICTION_WEB_RESTRICTION_GIN_WRAPPER_H_
-#define COMPONENTS_WEB_RESTRICTION_WEB_RESTRICTION_GIN_WRAPPER_H_
-
-#include "base/macros.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "gin/wrappable.h"
-
-namespace content {
-class RenderFrame;
-}
-
-namespace web_restrictions {
-
-class WebRestrictionsGinWrapper
- : public gin::Wrappable<WebRestrictionsGinWrapper>,
- public content::RenderFrameObserver {
- public:
- static gin::WrapperInfo kWrapperInfo;
-
- static void Install(content::RenderFrame* render_frame);
-
- private:
- explicit WebRestrictionsGinWrapper(content::RenderFrame* render_frame);
- ~WebRestrictionsGinWrapper() override;
-
- // Override OnDestruct to prevent the wrapper going away when the
- // RenderFrame does
- void OnDestruct() override;
-
- // Request permission to allow visiting the currently blocked site.
- bool RequestPermission();
-
- // gin::WrappableBase
- gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
- v8::Isolate* isolate) override;
-
- DISALLOW_COPY_AND_ASSIGN(WebRestrictionsGinWrapper);
-};
-
-} // namespace web_restrictions.
-
-#endif // COMPONENTS_WEB_RESTRICTION_WEB_RESTRICTION_GIN_WRAPPER_H_
diff --git a/chromium/components/webcrypto/BUILD.gn b/chromium/components/webcrypto/BUILD.gn
index 91ad2c8468a..1b13587e66f 100644
--- a/chromium/components/webcrypto/BUILD.gn
+++ b/chromium/components/webcrypto/BUILD.gn
@@ -5,7 +5,7 @@
import("//testing/test.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
-source_set("webcrypto") {
+static_library("webcrypto") {
sources = [
"algorithm_dispatch.cc",
"algorithm_dispatch.h",
@@ -85,7 +85,6 @@ source_set("unit_tests") {
deps = [
":webcrypto",
"//base/test:test_support",
- "//components/test_runner:test_runner",
"//crypto",
"//crypto:platform",
"//testing/gtest",
@@ -107,13 +106,10 @@ source_set("fuzzer_support") {
]
deps = [
":webcrypto",
+ "//base",
"//crypto",
"//crypto:platform",
"//third_party/WebKit/public:blink",
-
- # This contains a helper function for initializing Blink (needed for
- # PartitionAlloc initialization).
- "//components/test_runner:test_runner",
]
}
@@ -141,6 +137,18 @@ fuzzer_test("webcrypto_ec_import_key_spki_fuzzer") {
]
}
+# Tests the import of raw (X9.62) formatted EC keys.
+fuzzer_test("webcrypto_ec_import_key_raw_fuzzer") {
+ sources = [
+ "ec_import_key_raw_fuzzer.cc",
+ ]
+ deps = [
+ ":fuzzer_support",
+ ":webcrypto",
+ "//third_party/WebKit/public:blink_headers",
+ ]
+}
+
# Tests the import of PKCS8 formatted RSA keys.
fuzzer_test("webcrypto_rsa_import_key_pkcs8_fuzzer") {
sources = [
diff --git a/chromium/components/webcrypto/DEPS b/chromium/components/webcrypto/DEPS
index 14ca3e02e19..5cdc8e79e93 100644
--- a/chromium/components/webcrypto/DEPS
+++ b/chromium/components/webcrypto/DEPS
@@ -1,5 +1,4 @@
include_rules = [
- "+components/test_runner",
"+crypto",
"+third_party/re2",
"+third_party/WebKit/public/platform",
diff --git a/chromium/components/webcrypto/algorithm_dispatch.cc b/chromium/components/webcrypto/algorithm_dispatch.cc
index d8d8117bc45..5c503167051 100644
--- a/chromium/components/webcrypto/algorithm_dispatch.cc
+++ b/chromium/components/webcrypto/algorithm_dispatch.cc
@@ -103,6 +103,20 @@ Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
if (status.IsError())
return status;
+ // The Web Crypto spec says to reject secret and private keys generated with
+ // empty usages:
+ //
+ // https://w3c.github.io/webcrypto/Overview.html#dfn-SubtleCrypto-method-generateKey
+ //
+ // (14.3.6.8):
+ // If result is a CryptoKey object:
+ // If the [[type]] internal slot of result is "secret" or "private"
+ // and usages is empty, then throw a SyntaxError.
+ //
+ // (14.3.6.9)
+ // If result is a CryptoKeyPair object:
+ // If the [[usages]] internal slot of the privateKey attribute of
+ // result is the empty sequence, then throw a SyntaxError.
const blink::WebCryptoKey* key = NULL;
if (result->type() == GenerateKeyResult::TYPE_SECRET_KEY)
key = &result->secret_key();
@@ -111,13 +125,11 @@ Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
if (key == NULL)
return Status::ErrorUnexpected();
- // This should only fail if an algorithm is implemented incorrectly and
- // does not do its own check of the usages.
if (key->usages() == 0) {
- DCHECK(false) << "Key usages for generateKey() must not be empty";
return Status::ErrorCreateKeyEmptyUsages();
}
- return status;
+
+ return Status::Success();
}
Status ImportKey(blink::WebCryptoKeyFormat format,
@@ -131,11 +143,24 @@ Status ImportKey(blink::WebCryptoKeyFormat format,
if (status.IsError())
return status;
- status = impl->VerifyKeyUsagesBeforeImportKey(format, usages);
+ status =
+ impl->ImportKey(format, key_data, algorithm, extractable, usages, key);
if (status.IsError())
return status;
- return impl->ImportKey(format, key_data, algorithm, extractable, usages, key);
+ // The Web Crypto spec says to reject secret and private keys imported with
+ // empty usages:
+ //
+ // https://w3c.github.io/webcrypto/Overview.html#dfn-SubtleCrypto-method-importKey
+ //
+ // 14.3.9.9: If the [[type]] internal slot of result is "secret" or "private"
+ // and usages is empty, then throw a SyntaxError.
+ if (key->usages() == 0 && (key->type() == blink::WebCryptoKeyTypeSecret ||
+ key->type() == blink::WebCryptoKeyTypePrivate)) {
+ return Status::ErrorCreateKeyEmptyUsages();
+ }
+
+ return Status::Success();
}
Status ExportKey(blink::WebCryptoKeyFormat format,
@@ -210,19 +235,9 @@ Status UnwrapKey(blink::WebCryptoKeyFormat format,
if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
return Status::ErrorUnexpected();
- // Fail fast if the import is doomed to fail.
- const AlgorithmImplementation* import_impl = NULL;
- Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl);
- if (status.IsError())
- return status;
-
- status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usages);
- if (status.IsError())
- return status;
-
std::vector<uint8_t> buffer;
- status = DecryptDontCheckKeyUsage(wrapping_algorithm, wrapping_key,
- wrapped_key_data, &buffer);
+ Status status = DecryptDontCheckKeyUsage(wrapping_algorithm, wrapping_key,
+ wrapped_key_data, &buffer);
if (status.IsError())
return status;
@@ -276,12 +291,6 @@ Status DeriveKey(const blink::WebCryptoAlgorithm& algorithm,
if (status.IsError())
return status;
- // Fail fast if the requested key usages are incorect.
- status = import_impl->VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormatRaw, usages);
- if (status.IsError())
- return status;
-
// Determine how many bits long the derived key should be.
unsigned int length_bits = 0;
bool has_length_bits = false;
diff --git a/chromium/components/webcrypto/algorithm_implementation.cc b/chromium/components/webcrypto/algorithm_implementation.cc
index 8db7482ce73..fe4622a6e91 100644
--- a/chromium/components/webcrypto/algorithm_implementation.cc
+++ b/chromium/components/webcrypto/algorithm_implementation.cc
@@ -75,12 +75,6 @@ Status AlgorithmImplementation::GetKeyLength(
return Status::ErrorUnsupported();
}
-Status AlgorithmImplementation::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- return Status::ErrorUnsupportedImportKeyFormat();
-}
-
Status AlgorithmImplementation::ImportKey(
blink::WebCryptoKeyFormat format,
const CryptoData& key_data,
@@ -88,95 +82,13 @@ Status AlgorithmImplementation::ImportKey(
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
- switch (format) {
- case blink::WebCryptoKeyFormatRaw:
- return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatSpki:
- return ImportKeySpki(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatPkcs8:
- return ImportKeyPkcs8(key_data, algorithm, extractable, usages, key);
- case blink::WebCryptoKeyFormatJwk:
- return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
- default:
- return Status::ErrorUnsupported();
- }
-}
-
-Status AlgorithmImplementation::ImportKeyRaw(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- return Status::ErrorUnsupportedImportKeyFormat();
-}
-
-Status AlgorithmImplementation::ImportKeyPkcs8(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- return Status::ErrorUnsupportedImportKeyFormat();
-}
-
-Status AlgorithmImplementation::ImportKeySpki(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- return Status::ErrorUnsupportedImportKeyFormat();
-}
-
-Status AlgorithmImplementation::ImportKeyJwk(
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const {
- return Status::ErrorUnsupportedImportKeyFormat();
+ return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::ExportKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
- switch (format) {
- case blink::WebCryptoKeyFormatRaw:
- return ExportKeyRaw(key, buffer);
- case blink::WebCryptoKeyFormatSpki:
- return ExportKeySpki(key, buffer);
- case blink::WebCryptoKeyFormatPkcs8:
- return ExportKeyPkcs8(key, buffer);
- case blink::WebCryptoKeyFormatJwk:
- return ExportKeyJwk(key, buffer);
- default:
- return Status::ErrorUnsupported();
- }
-}
-
-Status AlgorithmImplementation::ExportKeyRaw(
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupportedExportKeyFormat();
-}
-
-Status AlgorithmImplementation::ExportKeyPkcs8(
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupportedExportKeyFormat();
-}
-
-Status AlgorithmImplementation::ExportKeySpki(
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupportedExportKeyFormat();
-}
-
-Status AlgorithmImplementation::ExportKeyJwk(
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const {
- return Status::ErrorUnsupportedExportKeyFormat();
+ return Status::ErrorUnsupported();
}
Status AlgorithmImplementation::SerializeKeyForClone(
diff --git a/chromium/components/webcrypto/algorithm_implementation.h b/chromium/components/webcrypto/algorithm_implementation.h
index b65a3517872..b6461dcf4be 100644
--- a/chromium/components/webcrypto/algorithm_implementation.h
+++ b/chromium/components/webcrypto/algorithm_implementation.h
@@ -38,65 +38,80 @@ class Status;
// to Encrypt()/Decrypt() the corresponding key usages may not be present
// (when wrapping/unwrapping).
//
-// An AlgorithmImplementation can also assume that
-// crypto::EnsureOpenSSLInit() will be called before any of its
-// methods are invoked (except the constructor).
+// An AlgorithmImplementation can also assume that crypto::EnsureOpenSSLInit()
+// will be called before any of its methods are invoked (except the
+// constructor).
class AlgorithmImplementation {
public:
virtual ~AlgorithmImplementation();
- // This method corresponds to Web Crypto's crypto.subtle.encrypt().
+ // This is what is run whenever the spec says:
+ // "Let result be the result of performing the encrypt operation"
+ //
+ // (crypto.subtle.encrypt() dispatches to this)
virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) const;
- // This method corresponds to Web Crypto's crypto.subtle.decrypt().
+ // This is what is run whenever the spec says:
+ // "Let result be the result of performing the decrypt operation"
+ //
+ // (crypto.subtle.decrypt() dispatches to this)
virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) const;
- // This method corresponds to Web Crypto's crypto.subtle.sign().
+ // This is what is run whenever the spec says:
+ // "Let result be the result of performing the sign operation"
+ //
+ // (crypto.subtle.sign() dispatches to this)
virtual Status Sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8_t>* buffer) const;
- // This method corresponds to Web Crypto's crypto.subtle.verify().
+ // This is what is run whenever the spec says:
+ // "Let result be the result of performing the verify operation"
+ //
+ // (crypto.subtle.verify() dispatches to this)
virtual Status Verify(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& signature,
const CryptoData& data,
bool* signature_match) const;
- // This method corresponds to Web Crypto's crypto.subtle.digest().
+ // This is what is run whenever the spec says:
+ // "Let result be the result of performing the digest operation"
+ //
+ // (crypto.subtle.digest() dispatches to this)
virtual Status Digest(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& data,
std::vector<uint8_t>* buffer) const;
- // This method corresponds to Web Crypto's crypto.subtle.generateKey().
+ // This is what is run whenever the spec says:
+ // "Let result be the result of executing the generate key operation"
//
- // Implementations MUST verify |usages| and return an error if it is not
- // appropriate.
+ // (crypto.subtle.generateKey() dispatches to this)
virtual Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
GenerateKeyResult* result) const;
- // This method corresponds to Web Crypto's "derive bits" operation. It is
- // essentially crypto.subtle.deriveBits() with the exception that the length
- // can be "null" (|has_length_bits = true|).
+ // This is what is run whenever the spec says:
+ // "Let result be a new ArrayBuffer containing the result of executing the
+ // derive bits operation"
//
- // In cases where the length was not specified, an appropriate default for the
- // algorithm should be used (as described by the spec).
+ // (crypto.subtle.deriveBits() dispatches to this)
virtual Status DeriveBits(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& base_key,
bool has_optional_length_bits,
unsigned int optional_length_bits,
std::vector<uint8_t>* derived_bytes) const;
- // This method corresponds with Web Crypto's "Get key length" operation.
+ // This is what is run whenever the spec says:
+ // "Let length be the result of executing the get key length algorithm"
//
// In the Web Crypto spec the operation returns either "null" or an
// "Integer". In this code "null" is represented by setting
@@ -106,86 +121,24 @@ class AlgorithmImplementation {
bool* has_length_bits,
unsigned int* length_bits) const;
- // -----------------------------------------------
- // Key import
- // -----------------------------------------------
-
- // VerifyKeyUsagesBeforeImportKey() must be called before either
- // importing a key, or unwrapping a key.
- //
- // Implementations should return an error if the requested usages are invalid
- // when importing for the specified format.
+ // This is what is run whenever the spec says:
+ // "Let result be the result of performing the import key operation"
//
- // For instance, importing an RSA-SSA key with 'spki' format and Sign usage
- // is invalid. The 'spki' format implies it will be a public key, and public
- // keys do not support signing.
+ // (crypto.subtle.importKey() dispatches to this).
+ virtual Status ImportKey(blink::WebCryptoKeyFormat format,
+ const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const;
+
+ // This is what is run whenever the spec says:
+ // "Let result be the result of performing the export key operation"
//
- // When called with format=JWK the key type may be unknown. The
- // ImportKeyJwk() must do the final usage check.
- virtual Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const;
-
- // Dispatches to the format-specific ImportKey* method.
- Status ImportKey(blink::WebCryptoKeyFormat format,
- const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const;
-
- // This method corresponds to Web Crypto's
- // crypto.subtle.importKey(format='raw').
- virtual Status ImportKeyRaw(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const;
-
- // This method corresponds to Web Crypto's
- // crypto.subtle.importKey(format='pkcs8').
- virtual Status ImportKeyPkcs8(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const;
-
- // This method corresponds to Web Crypto's
- // crypto.subtle.importKey(format='spki').
- virtual Status ImportKeySpki(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const;
-
- // This method corresponds to Web Crypto's
- // crypto.subtle.importKey(format='jwk').
- virtual Status ImportKeyJwk(const CryptoData& key_data,
- const blink::WebCryptoAlgorithm& algorithm,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const;
-
- // -----------------------------------------------
- // Key export
- // -----------------------------------------------
-
- // Dispatches to the format-specific ExportKey* method.
- Status ExportKey(blink::WebCryptoKeyFormat format,
- const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const;
-
- virtual Status ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const;
-
- virtual Status ExportKeyPkcs8(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const;
-
- virtual Status ExportKeySpki(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const;
-
- virtual Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const;
+ // (crypto.subtle.exportKey() dispatches to this).
+ virtual Status ExportKey(blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ std::vector<uint8_t>* buffer) const;
// -----------------------------------------------
// Structured clone
diff --git a/chromium/components/webcrypto/algorithms/aes.cc b/chromium/components/webcrypto/algorithms/aes.cc
index 7ba9a5095b9..f46ea15a119 100644
--- a/chromium/components/webcrypto/algorithms/aes.cc
+++ b/chromium/components/webcrypto/algorithms/aes.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "components/webcrypto/algorithms/secret_key_util.h"
+#include "components/webcrypto/algorithms/util.h"
#include "components/webcrypto/blink_key_handle.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/jwk.h"
@@ -59,7 +60,7 @@ Status AesAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
GenerateKeyResult* result) const {
- Status status = CheckSecretKeyCreationUsages(all_key_usages_, usages);
+ Status status = CheckKeyCreationUsages(all_key_usages_, usages);
if (status.IsError())
return status;
@@ -77,23 +78,44 @@ Status AesAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
extractable, usages, keylen_bits, result);
}
-Status AesAlgorithm::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
+Status AesAlgorithm::ImportKey(blink::WebCryptoKeyFormat format,
+ const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const {
switch (format) {
case blink::WebCryptoKeyFormatRaw:
+ return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
case blink::WebCryptoKeyFormatJwk:
- return CheckSecretKeyCreationUsages(all_key_usages_, usages);
+ return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
}
+Status AesAlgorithm::ExportKey(blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ std::vector<uint8_t>* buffer) const {
+ switch (format) {
+ case blink::WebCryptoKeyFormatRaw:
+ return ExportKeyRaw(key, buffer);
+ case blink::WebCryptoKeyFormatJwk:
+ return ExportKeyJwk(key, buffer);
+ default:
+ return Status::ErrorUnsupportedExportKeyFormat();
+ }
+}
+
Status AesAlgorithm::ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
+ Status status = CheckKeyCreationUsages(all_key_usages_, usages);
+ if (status.IsError())
+ return status;
+
const unsigned int keylen_bytes = key_data.byte_length();
// 192-bit AES is intentionally unsupported (http://crbug.com/533699).
@@ -117,10 +139,14 @@ Status AesAlgorithm::ImportKeyJwk(const CryptoData& key_data,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
+ Status status = CheckKeyCreationUsages(all_key_usages_, usages);
+ if (status.IsError())
+ return status;
+
std::vector<uint8_t> raw_data;
JwkReader jwk;
- Status status = ReadSecretKeyNoExpectedAlgJwk(key_data, extractable, usages,
- &raw_data, &jwk);
+ status = ReadSecretKeyNoExpectedAlgJwk(key_data, extractable, usages,
+ &raw_data, &jwk);
if (status.IsError())
return status;
diff --git a/chromium/components/webcrypto/algorithms/aes.h b/chromium/components/webcrypto/algorithms/aes.h
index 65b82d74590..b7b0ad55961 100644
--- a/chromium/components/webcrypto/algorithms/aes.h
+++ b/chromium/components/webcrypto/algorithms/aes.h
@@ -33,40 +33,47 @@ class AesAlgorithm : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
GenerateKeyResult* result) const override;
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override;
+ Status ImportKey(blink::WebCryptoKeyFormat format,
+ const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const override;
+ Status ExportKey(blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ std::vector<uint8_t>* buffer) const override;
+
+ Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
+ blink::WebCryptoKeyType type,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ const CryptoData& key_data,
+ blink::WebCryptoKey* key) const override;
+
+ Status GetKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
+ bool* has_length_bits,
+ unsigned int* length_bits) const override;
+
+ private:
Status ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
+ blink::WebCryptoKey* key) const;
Status ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
+ blink::WebCryptoKey* key) const;
Status ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
+ std::vector<uint8_t>* buffer) const;
Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
+ std::vector<uint8_t>* buffer) const;
- Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& key_data,
- blink::WebCryptoKey* key) const override;
-
- Status GetKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
- bool* has_length_bits,
- unsigned int* length_bits) const override;
-
- private:
const blink::WebCryptoKeyUsageMask all_key_usages_;
const std::string jwk_suffix_;
};
diff --git a/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc b/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
index b246d11f9a4..57cff25478b 100644
--- a/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
@@ -23,9 +23,7 @@ namespace {
blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(
const std::vector<uint8_t>& iv) {
return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
- blink::WebCryptoAlgorithmIdAesCbc,
- new blink::WebCryptoAesCbcParams(iv.data(),
- static_cast<unsigned int>(iv.size())));
+ blink::WebCryptoAlgorithmIdAesCbc, new blink::WebCryptoAesCbcParams(iv));
}
blink::WebCryptoAlgorithm CreateAesCbcKeyGenAlgorithm(
diff --git a/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc b/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
index cd578815076..eaee87eee7a 100644
--- a/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
@@ -24,9 +24,7 @@ blink::WebCryptoAlgorithm CreateAesCtrAlgorithm(
uint8_t length_bits) {
return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
blink::WebCryptoAlgorithmIdAesCtr,
- new blink::WebCryptoAesCtrParams(
- length_bits, counter.data(),
- static_cast<unsigned int>(counter.size())));
+ new blink::WebCryptoAesCtrParams(length_bits, counter));
}
class WebCryptoAesCtrTest : public WebCryptoTestBase {};
diff --git a/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc b/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
index 8b03a5352f7..d0a851b0566 100644
--- a/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
@@ -26,11 +26,8 @@ blink::WebCryptoAlgorithm CreateAesGcmAlgorithm(
unsigned int tag_length_bits) {
return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
blink::WebCryptoAlgorithmIdAesGcm,
- new blink::WebCryptoAesGcmParams(
- iv.data(), static_cast<unsigned int>(iv.size()), true,
- additional_data.data(),
- static_cast<unsigned int>(additional_data.size()), true,
- tag_length_bits));
+ new blink::WebCryptoAesGcmParams(iv, true, additional_data, true,
+ tag_length_bits));
}
blink::WebCryptoAlgorithm CreateAesGcmKeyGenAlgorithm(
diff --git a/chromium/components/webcrypto/algorithms/asymmetric_key_util.cc b/chromium/components/webcrypto/algorithms/asymmetric_key_util.cc
index d38ad1544a5..57a3a4a8463 100644
--- a/chromium/components/webcrypto/algorithms/asymmetric_key_util.cc
+++ b/chromium/components/webcrypto/algorithms/asymmetric_key_util.cc
@@ -94,20 +94,6 @@ Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key,
return Status::Success();
}
-Status CheckPrivateKeyCreationUsages(
- blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages) {
- return CheckKeyCreationUsages(all_possible_usages, actual_usages,
- EmptyUsagePolicy::REJECT_EMPTY);
-}
-
-Status CheckPublicKeyCreationUsages(
- blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages) {
- return CheckKeyCreationUsages(all_possible_usages, actual_usages,
- EmptyUsagePolicy::ALLOW_EMPTY);
-}
-
Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
int expected_pkey_id,
crypto::ScopedEVP_PKEY* out_pkey) {
@@ -144,33 +130,6 @@ Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
return Status::Success();
}
-Status VerifyUsagesBeforeImportAsymmetricKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask all_public_key_usages,
- blink::WebCryptoKeyUsageMask all_private_key_usages,
- blink::WebCryptoKeyUsageMask usages) {
- switch (format) {
- case blink::WebCryptoKeyFormatSpki:
- return CheckPublicKeyCreationUsages(all_public_key_usages, usages);
- case blink::WebCryptoKeyFormatPkcs8:
- return CheckPrivateKeyCreationUsages(all_private_key_usages, usages);
- case blink::WebCryptoKeyFormatJwk: {
- // The JWK could represent either a public key or private key. The usages
- // must make sense for one of the two. The usages will be checked again by
- // ImportKeyJwk() once the key type has been determined.
- if (CheckPublicKeyCreationUsages(all_public_key_usages, usages)
- .IsError() &&
- CheckPrivateKeyCreationUsages(all_private_key_usages, usages)
- .IsError()) {
- return Status::ErrorCreateKeyBadUsages();
- }
- return Status::Success();
- }
- default:
- return Status::ErrorUnsupportedImportKeyFormat();
- }
-}
-
Status GetUsagesForGenerateAsymmetricKey(
blink::WebCryptoKeyUsageMask combined_usages,
blink::WebCryptoKeyUsageMask all_public_usages,
@@ -178,17 +137,18 @@ Status GetUsagesForGenerateAsymmetricKey(
blink::WebCryptoKeyUsageMask* public_usages,
blink::WebCryptoKeyUsageMask* private_usages) {
// Ensure that the combined usages is a subset of the total possible usages.
- Status status =
- CheckKeyCreationUsages(all_public_usages | all_private_usages,
- combined_usages, EmptyUsagePolicy::ALLOW_EMPTY);
+ Status status = CheckKeyCreationUsages(all_public_usages | all_private_usages,
+ combined_usages);
if (status.IsError())
return status;
*public_usages = combined_usages & all_public_usages;
*private_usages = combined_usages & all_private_usages;
- // Ensure that the private key has non-empty usages.
- return CheckPrivateKeyCreationUsages(all_private_usages, *private_usages);
+ // NOTE: empty private_usages is allowed at this layer. Such keys will be
+ // rejected at a higher layer.
+
+ return Status::Success();
}
} // namespace webcrypto
diff --git a/chromium/components/webcrypto/algorithms/asymmetric_key_util.h b/chromium/components/webcrypto/algorithms/asymmetric_key_util.h
index 51ed79a8d13..ee067b0eed7 100644
--- a/chromium/components/webcrypto/algorithms/asymmetric_key_util.h
+++ b/chromium/components/webcrypto/algorithms/asymmetric_key_util.h
@@ -32,19 +32,6 @@ Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key);
-// Checks that a private key can be created using |actual_usages|, where
-// |all_possible_usages| is the full set of allowed private key usages. Note
-// that private keys are not allowed to have empty usages.
-Status CheckPrivateKeyCreationUsages(
- blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages);
-
-// Checks that a public key can be created using |actual_usages|, where
-// |all_possible_usages| is the full set of allowed public key usages
-Status CheckPublicKeyCreationUsages(
- blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages);
-
// Imports SPKI bytes to an EVP_PKEY for a public key. The resulting asymmetric
// key may be invalid, and should be verified using something like
// RSA_check_key(). The only validation performed by this function is to ensure
@@ -61,13 +48,6 @@ Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
int expected_pkey_id,
crypto::ScopedEVP_PKEY* pkey);
-// Verifies that |usages| is valid when importing a key of the given format.
-Status VerifyUsagesBeforeImportAsymmetricKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask all_public_key_usages,
- blink::WebCryptoKeyUsageMask all_private_key_usages,
- blink::WebCryptoKeyUsageMask usages);
-
// Splits the combined usages given to GenerateKey() into the respective usages
// for the public key and private key. Returns an error if the usages are
// invalid.
diff --git a/chromium/components/webcrypto/algorithms/ec.cc b/chromium/components/webcrypto/algorithms/ec.cc
index 09b9ae408c9..3900d3c1a8d 100644
--- a/chromium/components/webcrypto/algorithms/ec.cc
+++ b/chromium/components/webcrypto/algorithms/ec.cc
@@ -19,6 +19,7 @@
#include "components/webcrypto/generate_key_result.h"
#include "components/webcrypto/jwk.h"
#include "components/webcrypto/status.h"
+#include "crypto/auto_cbb.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
@@ -110,23 +111,23 @@ Status VerifyEcKeyAfterSpkiOrPkcs8Import(
blink::WebCryptoNamedCurve expected_named_curve) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey));
- if (!ec.get())
+ EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey);
+ if (!ec)
return Status::ErrorUnexpected();
// When importing an ECPrivateKey, the public key is optional. If it was
// omitted then the public key will be calculated by BoringSSL and added into
// the EC_KEY. However an encoding flag is set such that when exporting to
// PKCS8 format the public key is once again omitted. Remove this flag.
- unsigned int enc_flags = EC_KEY_get_enc_flags(ec.get());
+ unsigned int enc_flags = EC_KEY_get_enc_flags(ec);
enc_flags &= ~EC_PKEY_NO_PUBKEY;
- EC_KEY_set_enc_flags(ec.get(), enc_flags);
+ EC_KEY_set_enc_flags(ec, enc_flags);
- if (!EC_KEY_check_key(ec.get()))
+ if (!EC_KEY_check_key(ec))
return Status::ErrorEcKeyInvalid();
// Make sure the curve matches the expected curve name.
- int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
+ int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
blink::WebCryptoNamedCurve named_curve = blink::WebCryptoNamedCurveP256;
Status status = NidToWebCryptoCurve(curve_nid, &named_curve);
if (status.IsError())
@@ -290,11 +291,93 @@ Status EcAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
return Status::Success();
}
-Status EcAlgorithm::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- return VerifyUsagesBeforeImportAsymmetricKey(format, all_public_key_usages_,
- all_private_key_usages_, usages);
+Status EcAlgorithm::ImportKey(blink::WebCryptoKeyFormat format,
+ const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const {
+ switch (format) {
+ case blink::WebCryptoKeyFormatRaw:
+ return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
+ case blink::WebCryptoKeyFormatPkcs8:
+ return ImportKeyPkcs8(key_data, algorithm, extractable, usages, key);
+ case blink::WebCryptoKeyFormatSpki:
+ return ImportKeySpki(key_data, algorithm, extractable, usages, key);
+ case blink::WebCryptoKeyFormatJwk:
+ return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
+ default:
+ return Status::ErrorUnsupportedImportKeyFormat();
+ }
+}
+
+Status EcAlgorithm::ExportKey(blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ std::vector<uint8_t>* buffer) const {
+ switch (format) {
+ case blink::WebCryptoKeyFormatRaw:
+ return ExportKeyRaw(key, buffer);
+ case blink::WebCryptoKeyFormatPkcs8:
+ return ExportKeyPkcs8(key, buffer);
+ case blink::WebCryptoKeyFormatSpki:
+ return ExportKeySpki(key, buffer);
+ case blink::WebCryptoKeyFormatJwk:
+ return ExportKeyJwk(key, buffer);
+ default:
+ return Status::ErrorUnsupportedExportKeyFormat();
+ }
+}
+
+Status EcAlgorithm::ImportKeyRaw(const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ Status status = CheckKeyCreationUsages(all_public_key_usages_, usages);
+ if (status.IsError())
+ return status;
+
+ const blink::WebCryptoEcKeyImportParams* params =
+ algorithm.ecKeyImportParams();
+
+ // Create an EC_KEY.
+ crypto::ScopedEC_KEY ec;
+ status = CreateEC_KEY(params->namedCurve(), &ec);
+ if (status.IsError())
+ return status;
+
+ crypto::ScopedEC_POINT point(EC_POINT_new(EC_KEY_get0_group(ec.get())));
+ if (!point.get())
+ return Status::OperationError();
+
+ // Convert the "raw" input from X9.62 format to an EC_POINT.
+ if (!EC_POINT_oct2point(EC_KEY_get0_group(ec.get()), point.get(),
+ key_data.bytes(), key_data.byte_length(), nullptr)) {
+ return Status::DataError();
+ }
+
+ // Copy the point (public key) into the EC_KEY.
+ if (!EC_KEY_set_public_key(ec.get(), point.get()))
+ return Status::OperationError();
+
+ // Verify the key.
+ if (!EC_KEY_check_key(ec.get()))
+ return Status::ErrorEcKeyInvalid();
+
+ // Wrap the EC_KEY into an EVP_PKEY.
+ crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
+ if (!pkey || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get()))
+ return Status::OperationError();
+
+ blink::WebCryptoKeyAlgorithm key_algorithm =
+ blink::WebCryptoKeyAlgorithm::createEc(algorithm.id(),
+ params->namedCurve());
+
+ // Wrap the EVP_PKEY into a WebCryptoKey
+ return CreateWebCryptoPublicKey(std::move(pkey), key_algorithm, extractable,
+ usages, key);
}
Status EcAlgorithm::ImportKeyPkcs8(const CryptoData& key_data,
@@ -302,9 +385,12 @@ Status EcAlgorithm::ImportKeyPkcs8(const CryptoData& key_data,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
+ Status status = CheckKeyCreationUsages(all_private_key_usages_, usages);
+ if (status.IsError())
+ return status;
+
crypto::ScopedEVP_PKEY private_key;
- Status status =
- ImportUnverifiedPkeyFromPkcs8(key_data, EVP_PKEY_EC, &private_key);
+ status = ImportUnverifiedPkeyFromPkcs8(key_data, EVP_PKEY_EC, &private_key);
if (status.IsError())
return status;
@@ -327,9 +413,12 @@ Status EcAlgorithm::ImportKeySpki(const CryptoData& key_data,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
+ Status status = CheckKeyCreationUsages(all_public_key_usages_, usages);
+ if (status.IsError())
+ return status;
+
crypto::ScopedEVP_PKEY public_key;
- Status status =
- ImportUnverifiedPkeyFromSpki(key_data, EVP_PKEY_EC, &public_key);
+ status = ImportUnverifiedPkeyFromSpki(key_data, EVP_PKEY_EC, &public_key);
if (status.IsError())
return status;
@@ -388,9 +477,9 @@ Status EcAlgorithm::ImportKeyJwk(const CryptoData& key_data,
// Now that the key type is known, verify the usages.
if (is_private_key) {
- status = CheckPrivateKeyCreationUsages(all_private_key_usages_, usages);
+ status = CheckKeyCreationUsages(all_private_key_usages_, usages);
} else {
- status = CheckPublicKeyCreationUsages(all_public_key_usages_, usages);
+ status = CheckKeyCreationUsages(all_public_key_usages_, usages);
}
if (status.IsError())
@@ -455,6 +544,36 @@ Status EcAlgorithm::ImportKeyJwk(const CryptoData& key_data,
usages, key);
}
+Status EcAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
+ std::vector<uint8_t>* buffer) const {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ if (key.type() != blink::WebCryptoKeyTypePublic)
+ return Status::ErrorUnexpectedKeyType();
+
+ EVP_PKEY* pkey = GetEVP_PKEY(key);
+
+ EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey);
+ if (!ec)
+ return Status::ErrorUnexpected();
+
+ // Serialize the public key as an uncompressed point in X9.62 form.
+ uint8_t* raw;
+ size_t raw_len;
+ crypto::AutoCBB cbb;
+ if (!CBB_init(cbb.get(), 0) ||
+ !EC_POINT_point2cbb(cbb.get(), EC_KEY_get0_group(ec),
+ EC_KEY_get0_public_key(ec),
+ POINT_CONVERSION_UNCOMPRESSED, nullptr) ||
+ !CBB_finish(cbb.get(), &raw, &raw_len)) {
+ return Status::OperationError();
+ }
+ buffer->assign(raw, raw + raw_len);
+ OPENSSL_free(raw);
+
+ return Status::Success();
+}
+
Status EcAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
std::vector<uint8_t>* buffer) const {
if (key.type() != blink::WebCryptoKeyTypePrivate)
@@ -485,8 +604,8 @@ Status EcAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
EVP_PKEY* pkey = GetEVP_PKEY(key);
- crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey));
- if (!ec.get())
+ EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey);
+ if (!ec)
return Status::ErrorUnexpected();
// No "alg" is set for EC keys.
@@ -499,13 +618,13 @@ Status EcAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
if (status.IsError())
return status;
- int degree_bytes = GetGroupDegreeInBytes(ec.get());
+ int degree_bytes = GetGroupDegreeInBytes(ec);
jwk.SetString("crv", crv);
crypto::ScopedBIGNUM x;
crypto::ScopedBIGNUM y;
- status = GetPublicKey(ec.get(), &x, &y);
+ status = GetPublicKey(ec, &x, &y);
if (status.IsError())
return status;
@@ -518,7 +637,7 @@ Status EcAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
return status;
if (key.type() == blink::WebCryptoKeyTypePrivate) {
- const BIGNUM* d = EC_KEY_get0_private_key(ec.get());
+ const BIGNUM* d = EC_KEY_get0_private_key(ec);
status = WritePaddedBIGNUM("d", d, degree_bytes, &jwk);
if (status.IsError())
return status;
diff --git a/chromium/components/webcrypto/algorithms/ec.h b/chromium/components/webcrypto/algorithms/ec.h
index 1e9bd3e8b50..048bc50e5a5 100644
--- a/chromium/components/webcrypto/algorithms/ec.h
+++ b/chromium/components/webcrypto/algorithms/ec.h
@@ -32,45 +32,61 @@ class EcAlgorithm : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
GenerateKeyResult* result) const override;
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override;
+ Status ImportKey(blink::WebCryptoKeyFormat format,
+ const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const override;
+
+ Status ExportKey(blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ std::vector<uint8_t>* buffer) const override;
+
+ Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
+ blink::WebCryptoKeyType type,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ const CryptoData& key_data,
+ blink::WebCryptoKey* key) const override;
+
+ private:
+ Status ImportKeyRaw(const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const;
Status ImportKeyPkcs8(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
+ blink::WebCryptoKey* key) const;
Status ImportKeySpki(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
+ blink::WebCryptoKey* key) const;
Status ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
+ blink::WebCryptoKey* key) const;
+
+ Status ExportKeyRaw(const blink::WebCryptoKey& key,
+ std::vector<uint8_t>* buffer) const;
Status ExportKeyPkcs8(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
+ std::vector<uint8_t>* buffer) const;
Status ExportKeySpki(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
+ std::vector<uint8_t>* buffer) const;
Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
+ std::vector<uint8_t>* buffer) const;
- Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& key_data,
- blink::WebCryptoKey* key) const override;
-
- private:
const blink::WebCryptoKeyUsageMask all_public_key_usages_;
const blink::WebCryptoKeyUsageMask all_private_key_usages_;
};
diff --git a/chromium/components/webcrypto/algorithms/ecdh.cc b/chromium/components/webcrypto/algorithms/ecdh.cc
index de82db439ed..8afca5c2841 100644
--- a/chromium/components/webcrypto/algorithms/ecdh.cc
+++ b/chromium/components/webcrypto/algorithms/ecdh.cc
@@ -79,20 +79,17 @@ class EcdhImplementation : public EcAlgorithm {
return Status::ErrorEcdhCurveMismatch();
}
- crypto::ScopedEC_KEY public_key_ec(
- EVP_PKEY_get1_EC_KEY(GetEVP_PKEY(public_key)));
+ EC_KEY* public_key_ec = EVP_PKEY_get0_EC_KEY(GetEVP_PKEY(public_key));
- const EC_POINT* public_key_point =
- EC_KEY_get0_public_key(public_key_ec.get());
+ const EC_POINT* public_key_point = EC_KEY_get0_public_key(public_key_ec);
- crypto::ScopedEC_KEY private_key_ec(
- EVP_PKEY_get1_EC_KEY(GetEVP_PKEY(base_key)));
+ EC_KEY* private_key_ec = EVP_PKEY_get0_EC_KEY(GetEVP_PKEY(base_key));
// The size of the shared secret is the field size in bytes (rounded up).
// Note that, if rounding was required, the most significant bits of the
// secret are zero. So for P-521, the maximum length is 528 bits, not 521.
- int field_size_bytes = NumBitsToBytes(
- EC_GROUP_get_degree(EC_KEY_get0_group(private_key_ec.get())));
+ int field_size_bytes =
+ NumBitsToBytes(EC_GROUP_get_degree(EC_KEY_get0_group(private_key_ec)));
// If a desired key length was not specified, default to the field size
// (rounded up to nearest byte).
@@ -115,7 +112,7 @@ class EcdhImplementation : public EcAlgorithm {
derived_bytes->resize(NumBitsToBytes(length_bits));
int result = ECDH_compute_key(derived_bytes->data(), derived_bytes->size(),
- public_key_point, private_key_ec.get(), 0);
+ public_key_point, private_key_ec, 0);
if (result < 0 || static_cast<size_t>(result) != derived_bytes->size())
return Status::OperationError();
diff --git a/chromium/components/webcrypto/algorithms/ecdh_unittest.cc b/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
index 5faccbd380b..387b16ae9b2 100644
--- a/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
@@ -219,7 +219,7 @@ TEST_F(WebCryptoEcdhTest, DeriveKeyHmac19Bits) {
ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
EXPECT_EQ(3u, raw_key.size());
// The last 7 bits of the key should be zero.
- EXPECT_EQ(0, raw_key[raw_key.size() - 1] & 0x1f);
+ EXPECT_EQ(0, raw_key.back() & 0x1f);
}
// Derive an HMAC key with no specified length (just the hash of SHA-256).
diff --git a/chromium/components/webcrypto/algorithms/ecdsa.cc b/chromium/components/webcrypto/algorithms/ecdsa.cc
index a77e77dd39c..0b829a8d212 100644
--- a/chromium/components/webcrypto/algorithms/ecdsa.cc
+++ b/chromium/components/webcrypto/algorithms/ecdsa.cc
@@ -46,11 +46,11 @@ Status GetPKeyAndDigest(const blink::WebCryptoAlgorithm& algorithm,
Status GetEcGroupOrderSize(EVP_PKEY* pkey, size_t* order_size_bytes) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey));
- if (!ec.get())
+ EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey);
+ if (!ec)
return Status::ErrorUnexpected();
- const EC_GROUP* group = EC_KEY_get0_group(ec.get());
+ const EC_GROUP* group = EC_KEY_get0_group(ec);
crypto::ScopedBIGNUM order(BN_new());
if (!EC_GROUP_get_order(group, order.get(), NULL))
diff --git a/chromium/components/webcrypto/algorithms/hkdf.cc b/chromium/components/webcrypto/algorithms/hkdf.cc
index bc10c35bc8a..b2ce2bec354 100644
--- a/chromium/components/webcrypto/algorithms/hkdf.cc
+++ b/chromium/components/webcrypto/algorithms/hkdf.cc
@@ -29,19 +29,32 @@ class HkdfImplementation : public AlgorithmImplementation {
public:
HkdfImplementation() {}
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override {
- if (format != blink::WebCryptoKeyFormatRaw)
- return Status::ErrorUnsupportedImportKeyFormat();
- return CheckSecretKeyCreationUsages(kValidUsages, usages);
+ Status ImportKey(blink::WebCryptoKeyFormat format,
+ const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const override {
+ switch (format) {
+ case blink::WebCryptoKeyFormatRaw:
+ return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
+ default:
+ return Status::ErrorUnsupportedImportKeyFormat();
+ }
}
Status ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override {
+ blink::WebCryptoKey* key) const {
+ Status status = CheckKeyCreationUsages(kValidUsages, usages);
+ if (status.IsError())
+ return status;
+
+ if (extractable)
+ return Status::ErrorImportExtractableKdfKey();
+
return CreateWebCryptoSecretKey(
key_data, blink::WebCryptoKeyAlgorithm::createWithoutParams(
blink::WebCryptoAlgorithmIdHkdf),
@@ -92,6 +105,10 @@ class HkdfImplementation : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const override {
+ // NOTE: Unlike ImportKeyRaw(), this does not enforce extractable==false.
+ // This is intentional. Although keys cannot currently be created with
+ // extractable==true, earlier implementations permitted this, so
+ // de-serialization by structured clone should not reject them.
return CreateWebCryptoSecretKey(key_data, algorithm, extractable, usages,
key);
}
diff --git a/chromium/components/webcrypto/algorithms/hmac.cc b/chromium/components/webcrypto/algorithms/hmac.cc
index b02d70c2a9a..523088f5ad5 100644
--- a/chromium/components/webcrypto/algorithms/hmac.cc
+++ b/chromium/components/webcrypto/algorithms/hmac.cc
@@ -96,15 +96,16 @@ Status SignHmac(const std::vector<uint8_t>& raw_key,
size_t hmac_expected_length = EVP_MD_size(digest_algorithm);
buffer->resize(hmac_expected_length);
- crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result(
- buffer->data(), hmac_expected_length);
unsigned int hmac_actual_length;
- unsigned char* const success =
- HMAC(digest_algorithm, raw_key.data(), raw_key.size(), data.bytes(),
- data.byte_length(), hmac_result.safe_buffer(), &hmac_actual_length);
- if (!success || hmac_actual_length != hmac_expected_length)
+ if (!HMAC(digest_algorithm, raw_key.data(), raw_key.size(), data.bytes(),
+ data.byte_length(), buffer->data(), &hmac_actual_length)) {
return Status::OperationError();
+ }
+
+ // HMAC() promises to use at most EVP_MD_CTX_size(). If this was not the
+ // case then memory corruption may have just occurred.
+ CHECK_EQ(hmac_expected_length, hmac_actual_length);
return Status::Success();
}
@@ -117,7 +118,7 @@ class HmacImplementation : public AlgorithmImplementation {
bool extractable,
blink::WebCryptoKeyUsageMask usages,
GenerateKeyResult* result) const override {
- Status status = CheckSecretKeyCreationUsages(kAllKeyUsages, usages);
+ Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
if (status.IsError())
return status;
@@ -141,29 +142,50 @@ class HmacImplementation : public AlgorithmImplementation {
extractable, usages, keylen_bits, result);
}
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override {
+ Status ImportKey(blink::WebCryptoKeyFormat format,
+ const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const override {
switch (format) {
case blink::WebCryptoKeyFormatRaw:
+ return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
case blink::WebCryptoKeyFormatJwk:
- return CheckSecretKeyCreationUsages(kAllKeyUsages, usages);
+ return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
}
+ Status ExportKey(blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ std::vector<uint8_t>* buffer) const override {
+ switch (format) {
+ case blink::WebCryptoKeyFormatRaw:
+ return ExportKeyRaw(key, buffer);
+ case blink::WebCryptoKeyFormatJwk:
+ return ExportKeyJwk(key, buffer);
+ default:
+ return Status::ErrorUnsupportedExportKeyFormat();
+ }
+ }
+
Status ImportKeyRaw(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override {
+ blink::WebCryptoKey* key) const {
+ Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
+ if (status.IsError())
+ return status;
+
const blink::WebCryptoHmacImportParams* params =
algorithm.hmacImportParams();
unsigned int keylen_bits = 0;
- Status status = GetHmacImportKeyLengthBits(params, key_data.byte_length(),
- &keylen_bits);
+ status = GetHmacImportKeyLengthBits(params, key_data.byte_length(),
+ &keylen_bits);
if (status.IsError())
return status;
@@ -189,7 +211,11 @@ class HmacImplementation : public AlgorithmImplementation {
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override {
+ blink::WebCryptoKey* key) const {
+ Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
+ if (status.IsError())
+ return status;
+
const char* algorithm_name =
GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
if (!algorithm_name)
@@ -197,8 +223,8 @@ class HmacImplementation : public AlgorithmImplementation {
std::vector<uint8_t> raw_data;
JwkReader jwk;
- Status status = ReadSecretKeyNoExpectedAlgJwk(key_data, extractable, usages,
- &raw_data, &jwk);
+ status = ReadSecretKeyNoExpectedAlgJwk(key_data, extractable, usages,
+ &raw_data, &jwk);
if (status.IsError())
return status;
status = jwk.VerifyAlg(algorithm_name);
@@ -210,13 +236,13 @@ class HmacImplementation : public AlgorithmImplementation {
}
Status ExportKeyRaw(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override {
+ std::vector<uint8_t>* buffer) const {
*buffer = GetSymmetricKeyData(key);
return Status::Success();
}
Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override {
+ std::vector<uint8_t>* buffer) const {
const std::vector<uint8_t>& raw_data = GetSymmetricKeyData(key);
const char* algorithm_name =
diff --git a/chromium/components/webcrypto/algorithms/pbkdf2.cc b/chromium/components/webcrypto/algorithms/pbkdf2.cc
index 8dd059e000d..f2a8e24bf1f 100644
--- a/chromium/components/webcrypto/algorithms/pbkdf2.cc
+++ b/chromium/components/webcrypto/algorithms/pbkdf2.cc
@@ -27,12 +27,15 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
public:
Pbkdf2Implementation() {}
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override {
+ Status ImportKey(blink::WebCryptoKeyFormat format,
+ const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const override {
switch (format) {
case blink::WebCryptoKeyFormatRaw:
- return CheckSecretKeyCreationUsages(kAllKeyUsages, usages);
+ return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
@@ -42,7 +45,14 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override {
+ blink::WebCryptoKey* key) const {
+ Status status = CheckKeyCreationUsages(kAllKeyUsages, usages);
+ if (status.IsError())
+ return status;
+
+ if (extractable)
+ return Status::ErrorImportExtractableKdfKey();
+
const blink::WebCryptoKeyAlgorithm key_algorithm =
blink::WebCryptoKeyAlgorithm::createWithoutParams(
blink::WebCryptoAlgorithmIdPbkdf2);
@@ -64,6 +74,12 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
if (optional_length_bits % 8)
return Status::ErrorPbkdf2InvalidLength();
+ // According to RFC 2898 "dkLength" (derived key length) is
+ // described as being a "positive integer", so it is an error for
+ // it to be 0.
+ if (optional_length_bits == 0)
+ return Status::ErrorPbkdf2DeriveBitsLengthZero();
+
const blink::WebCryptoPbkdf2Params* params = algorithm.pbkdf2Params();
if (params->iterations() == 0)
@@ -93,6 +109,10 @@ class Pbkdf2Implementation : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
const CryptoData& key_data,
blink::WebCryptoKey* key) const override {
+ // NOTE: Unlike ImportKeyRaw(), this does not enforce extractable==false.
+ // This is intentional. Although keys cannot currently be created with
+ // extractable==true, earlier implementations permitted this, so
+ // de-serialization by structured clone should not reject them.
return CreateWebCryptoSecretKey(key_data, algorithm, extractable, usages,
key);
}
diff --git a/chromium/components/webcrypto/algorithms/rsa.cc b/chromium/components/webcrypto/algorithms/rsa.cc
index c1fbc3ce582..d0b20cdf685 100644
--- a/chromium/components/webcrypto/algorithms/rsa.cc
+++ b/chromium/components/webcrypto/algorithms/rsa.cc
@@ -336,11 +336,37 @@ Status RsaHashedAlgorithm::GenerateKey(
return Status::Success();
}
-Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const {
- return VerifyUsagesBeforeImportAsymmetricKey(format, all_public_key_usages_,
- all_private_key_usages_, usages);
+Status RsaHashedAlgorithm::ImportKey(blink::WebCryptoKeyFormat format,
+ const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const {
+ switch (format) {
+ case blink::WebCryptoKeyFormatPkcs8:
+ return ImportKeyPkcs8(key_data, algorithm, extractable, usages, key);
+ case blink::WebCryptoKeyFormatSpki:
+ return ImportKeySpki(key_data, algorithm, extractable, usages, key);
+ case blink::WebCryptoKeyFormatJwk:
+ return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
+ default:
+ return Status::ErrorUnsupportedImportKeyFormat();
+ }
+}
+
+Status RsaHashedAlgorithm::ExportKey(blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ std::vector<uint8_t>* buffer) const {
+ switch (format) {
+ case blink::WebCryptoKeyFormatPkcs8:
+ return ExportKeyPkcs8(key, buffer);
+ case blink::WebCryptoKeyFormatSpki:
+ return ExportKeySpki(key, buffer);
+ case blink::WebCryptoKeyFormatJwk:
+ return ExportKeyJwk(key, buffer);
+ default:
+ return Status::ErrorUnsupportedExportKeyFormat();
+ }
}
Status RsaHashedAlgorithm::ImportKeyPkcs8(
@@ -349,9 +375,12 @@ Status RsaHashedAlgorithm::ImportKeyPkcs8(
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
+ Status status = CheckKeyCreationUsages(all_private_key_usages_, usages);
+ if (status.IsError())
+ return status;
+
crypto::ScopedEVP_PKEY private_key;
- Status status =
- ImportUnverifiedPkeyFromPkcs8(key_data, EVP_PKEY_RSA, &private_key);
+ status = ImportUnverifiedPkeyFromPkcs8(key_data, EVP_PKEY_RSA, &private_key);
if (status.IsError())
return status;
@@ -376,9 +405,12 @@ Status RsaHashedAlgorithm::ImportKeySpki(
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key) const {
+ Status status = CheckKeyCreationUsages(all_public_key_usages_, usages);
+ if (status.IsError())
+ return status;
+
crypto::ScopedEVP_PKEY public_key;
- Status status =
- ImportUnverifiedPkeyFromSpki(key_data, EVP_PKEY_RSA, &public_key);
+ status = ImportUnverifiedPkeyFromSpki(key_data, EVP_PKEY_RSA, &public_key);
if (status.IsError())
return status;
@@ -412,9 +444,9 @@ Status RsaHashedAlgorithm::ImportKeyJwk(
// Once the key type is known, verify the usages.
if (jwk.is_private_key) {
- status = CheckPrivateKeyCreationUsages(all_private_key_usages_, usages);
+ status = CheckKeyCreationUsages(all_private_key_usages_, usages);
} else {
- status = CheckPublicKeyCreationUsages(all_public_key_usages_, usages);
+ status = CheckKeyCreationUsages(all_public_key_usages_, usages);
}
if (status.IsError())
diff --git a/chromium/components/webcrypto/algorithms/rsa.h b/chromium/components/webcrypto/algorithms/rsa.h
index 840c6272a37..c66eff21186 100644
--- a/chromium/components/webcrypto/algorithms/rsa.h
+++ b/chromium/components/webcrypto/algorithms/rsa.h
@@ -40,45 +40,52 @@ class RsaHashedAlgorithm : public AlgorithmImplementation {
blink::WebCryptoKeyUsageMask usages,
GenerateKeyResult* result) const override;
- Status VerifyKeyUsagesBeforeImportKey(
- blink::WebCryptoKeyFormat format,
- blink::WebCryptoKeyUsageMask usages) const override;
+ Status ImportKey(blink::WebCryptoKeyFormat format,
+ const CryptoData& key_data,
+ const blink::WebCryptoAlgorithm& algorithm,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ blink::WebCryptoKey* key) const override;
+ Status ExportKey(blink::WebCryptoKeyFormat format,
+ const blink::WebCryptoKey& key,
+ std::vector<uint8_t>* buffer) const override;
+
+ Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
+ blink::WebCryptoKeyType type,
+ bool extractable,
+ blink::WebCryptoKeyUsageMask usages,
+ const CryptoData& key_data,
+ blink::WebCryptoKey* key) const override;
+
+ private:
Status ImportKeyPkcs8(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
+ blink::WebCryptoKey* key) const;
Status ImportKeySpki(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
+ blink::WebCryptoKey* key) const;
Status ImportKeyJwk(const CryptoData& key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
- blink::WebCryptoKey* key) const override;
+ blink::WebCryptoKey* key) const;
Status ExportKeyPkcs8(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
+ std::vector<uint8_t>* buffer) const;
Status ExportKeySpki(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
+ std::vector<uint8_t>* buffer) const;
Status ExportKeyJwk(const blink::WebCryptoKey& key,
- std::vector<uint8_t>* buffer) const override;
+ std::vector<uint8_t>* buffer) const;
- Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
- blink::WebCryptoKeyType type,
- bool extractable,
- blink::WebCryptoKeyUsageMask usages,
- const CryptoData& key_data,
- blink::WebCryptoKey* key) const override;
-
- private:
const blink::WebCryptoKeyUsageMask all_public_key_usages_;
const blink::WebCryptoKeyUsageMask all_private_key_usages_;
};
diff --git a/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
index 5fbce4fb063..4712edd4916 100644
--- a/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
@@ -26,9 +26,7 @@ blink::WebCryptoAlgorithm CreateRsaOaepAlgorithm(
const std::vector<uint8_t>& label) {
return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
blink::WebCryptoAlgorithmIdRsaOaep,
- new blink::WebCryptoRsaOaepParams(
- !label.empty(), label.data(),
- static_cast<unsigned int>(label.size())));
+ new blink::WebCryptoRsaOaepParams(!label.empty(), label));
}
std::string Base64EncodeUrlSafe(const std::vector<uint8_t>& input) {
diff --git a/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
index 5d5c4fee5cc..fea882a5f39 100644
--- a/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
@@ -965,21 +965,15 @@ TEST_F(WebCryptoRsaSsaTest, ImportJwkRsaFailures) {
}
// Try importing an RSA-SSA key from JWK format, having specified both Sign and
-// Verify usage, and an invalid JWK.
+// Verify usage, AND an invalid JWK.
//
-// The test must fail with a usage error BEFORE attempting to read the JWK data.
-// Although both Sign and Verify are valid usages for RSA-SSA keys, it is
-// invalid to have them both at the same time for one key (since Sign applies to
-// private keys, whereas Verify applies to public keys).
-//
-// If the implementation does not fail fast, this test will crash dereferencing
-// invalid memory.
-TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaJwkBadUsageFailFast) {
- CryptoData bad_data(NULL, 128); // Invalid buffer of length 128.
+// Parsing the invalid JWK will fail before the usage check is done.
+TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaJwkBadUsageAndData) {
+ std::string bad_data = "hello";
blink::WebCryptoKey key;
- ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
- ImportKey(blink::WebCryptoKeyFormatJwk, bad_data,
+ ASSERT_EQ(Status::ErrorJwkNotDictionary(),
+ ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(bad_data),
CreateRsaHashedImportAlgorithm(
blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::WebCryptoAlgorithmIdSha256),
diff --git a/chromium/components/webcrypto/algorithms/secret_key_util.cc b/chromium/components/webcrypto/algorithms/secret_key_util.cc
index 3110e26dc21..9f0b0bf993a 100644
--- a/chromium/components/webcrypto/algorithms/secret_key_util.cc
+++ b/chromium/components/webcrypto/algorithms/secret_key_util.cc
@@ -50,13 +50,6 @@ Status CreateWebCryptoSecretKey(const CryptoData& key_data,
return Status::Success();
}
-Status CheckSecretKeyCreationUsages(
- blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages) {
- return CheckKeyCreationUsages(all_possible_usages, actual_usages,
- EmptyUsagePolicy::REJECT_EMPTY);
-}
-
void WriteSecretKeyJwk(const CryptoData& raw_key_data,
const std::string& algorithm,
bool extractable,
diff --git a/chromium/components/webcrypto/algorithms/secret_key_util.h b/chromium/components/webcrypto/algorithms/secret_key_util.h
index 5a0adfb6029..511440628d4 100644
--- a/chromium/components/webcrypto/algorithms/secret_key_util.h
+++ b/chromium/components/webcrypto/algorithms/secret_key_util.h
@@ -41,11 +41,6 @@ Status CreateWebCryptoSecretKey(const CryptoData& key_data,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoKey* key);
-// Checks that |actual_usages| is a non-empty subset of |all_possible_usages|.
-Status CheckSecretKeyCreationUsages(
- blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages);
-
// Writes a JWK-formatted symmetric key to |jwk_key_data|.
// * raw_key_data: The actual key data
// * algorithm: The JWK algorithm name (i.e. "alg")
diff --git a/chromium/components/webcrypto/algorithms/sha.cc b/chromium/components/webcrypto/algorithms/sha.cc
index 5baa0e2fdbe..cd380a040d8 100644
--- a/chromium/components/webcrypto/algorithms/sha.cc
+++ b/chromium/components/webcrypto/algorithms/sha.cc
@@ -125,7 +125,7 @@ class ShaImplementation : public AlgorithmImplementation {
} // namespace
std::unique_ptr<AlgorithmImplementation> CreateShaImplementation() {
- return base::WrapUnique(new ShaImplementation());
+ return base::MakeUnique<ShaImplementation>();
}
std::unique_ptr<blink::WebCryptoDigestor> CreateDigestorImplementation(
diff --git a/chromium/components/webcrypto/algorithms/test_helpers.cc b/chromium/components/webcrypto/algorithms/test_helpers.cc
index 01a86bde3b7..8751735496e 100644
--- a/chromium/components/webcrypto/algorithms/test_helpers.cc
+++ b/chromium/components/webcrypto/algorithms/test_helpers.cc
@@ -18,7 +18,6 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/values.h"
-#include "components/test_runner/test_common.h"
#include "components/webcrypto/algorithm_dispatch.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/generate_key_result.h"
@@ -42,9 +41,7 @@ bool Base64DecodeUrlSafe(const std::string& input, std::string* output) {
} // namespace
// static
-void WebCryptoTestBase::SetUpTestCase() {
- test_runner::EnsureBlinkInitialized();
-}
+void WebCryptoTestBase::SetUpTestCase() {}
void PrintTo(const Status& status, ::std::ostream* os) {
*os << StatusToString(status);
@@ -114,8 +111,7 @@ blink::WebCryptoAlgorithm CreateRsaHashedKeyGenAlgorithm(
return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
algorithm_id,
new blink::WebCryptoRsaHashedKeyGenParams(
- CreateAlgorithm(hash_id), modulus_length, public_exponent.data(),
- static_cast<unsigned int>(public_exponent.size())));
+ CreateAlgorithm(hash_id), modulus_length, public_exponent));
}
std::vector<uint8_t> Corrupted(const std::vector<uint8_t>& input) {
diff --git a/chromium/components/webcrypto/algorithms/util.cc b/chromium/components/webcrypto/algorithms/util.cc
index 4a3b747acc2..de4c1bf7994 100644
--- a/chromium/components/webcrypto/algorithms/util.cc
+++ b/chromium/components/webcrypto/algorithms/util.cc
@@ -47,17 +47,11 @@ void TruncateToBitLength(size_t length_bits, std::vector<uint8_t>* bytes) {
// Zero any "unused bits" in the final byte.
if (remainder_bits)
- (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits);
+ bytes->back() &= ~((0xFF) >> remainder_bits);
}
Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages,
- EmptyUsagePolicy empty_usage_policy) {
- if (actual_usages == 0 &&
- empty_usage_policy == EmptyUsagePolicy::REJECT_EMPTY) {
- return Status::ErrorCreateKeyEmptyUsages();
- }
-
+ blink::WebCryptoKeyUsageMask actual_usages) {
if (!ContainsKeyUsages(all_possible_usages, actual_usages))
return Status::ErrorCreateKeyBadUsages();
return Status::Success();
diff --git a/chromium/components/webcrypto/algorithms/util.h b/chromium/components/webcrypto/algorithms/util.h
index 2132683412c..62bb22dec35 100644
--- a/chromium/components/webcrypto/algorithms/util.h
+++ b/chromium/components/webcrypto/algorithms/util.h
@@ -52,19 +52,10 @@ T NumBitsToBytes(T x) {
return (x / 8) + (7 + (x % 8)) / 8;
}
-enum class EmptyUsagePolicy {
- // Allow keys to have empty usages.
- ALLOW_EMPTY,
-
- // Do not allow keys to have empty usages.
- REJECT_EMPTY,
-};
-
// Verifies whether a key can be created using |actual_usages| when the
// algorithm supports |all_possible_usages|.
Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
- blink::WebCryptoKeyUsageMask actual_usages,
- EmptyUsagePolicy empty_usage_policy);
+ blink::WebCryptoKeyUsageMask actual_usages);
// TODO(eroman): This doesn't really belong in this file. Move it into Blink
// instead.
diff --git a/chromium/components/webcrypto/ec_import_key_raw_fuzzer.cc b/chromium/components/webcrypto/ec_import_key_raw_fuzzer.cc
new file mode 100644
index 00000000000..eeb1a555edc
--- /dev/null
+++ b/chromium/components/webcrypto/ec_import_key_raw_fuzzer.cc
@@ -0,0 +1,15 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "components/webcrypto/fuzzer_support.h"
+
+// Entry point for LibFuzzer.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ webcrypto::ImportEcKeyFromRawFuzzData(data, size);
+
+ return 0;
+}
diff --git a/chromium/components/webcrypto/fuzzer_support.cc b/chromium/components/webcrypto/fuzzer_support.cc
index f44f8bc3f22..4c5efc3a4df 100644
--- a/chromium/components/webcrypto/fuzzer_support.cc
+++ b/chromium/components/webcrypto/fuzzer_support.cc
@@ -6,25 +6,26 @@
#include "base/command_line.h"
#include "base/lazy_instance.h"
-#include "components/test_runner/test_common.h"
+#include "base/numerics/safe_conversions.h"
#include "components/webcrypto/algorithm_dispatch.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/status.h"
+#include "third_party/WebKit/public/platform/Platform.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
+#include "third_party/WebKit/public/web/WebKit.h"
namespace webcrypto {
namespace {
// This mock is used to initialize blink.
-class InitOnce {
+class InitOnce : NON_EXPORTED_BASE(public blink::Platform) {
public:
InitOnce() {
- // EnsureBlinkInitialized() depends on the command line singleton being
- // initialized.
base::CommandLine::Init(0, nullptr);
- test_runner::EnsureBlinkInitialized();
+ blink::Platform::initialize(this);
}
+ ~InitOnce() override {}
};
base::LazyInstance<InitOnce>::Leaky g_once = LAZY_INSTANCE_INITIALIZER;
@@ -83,7 +84,53 @@ void ImportEcKeyFromDerFuzzData(const uint8_t* data,
blink::WebCryptoKey key;
webcrypto::Status status = webcrypto::ImportKey(
- format, webcrypto::CryptoData(data, size),
+ format, webcrypto::CryptoData(data, base::checked_cast<uint32_t>(size)),
+ CreateEcImportAlgorithm(algorithm_id, curve), true, usages, &key);
+
+ // These errors imply a bad setup of parameters, and means ImportKey() may not
+ // be testing the actual parsing.
+ DCHECK_NE(status.error_details(),
+ Status::ErrorUnsupportedImportKeyFormat().error_details());
+ DCHECK_NE(status.error_details(),
+ Status::ErrorCreateKeyBadUsages().error_details());
+}
+
+void ImportEcKeyFromRawFuzzData(const uint8_t* data, size_t size) {
+ EnsureInitialized();
+
+ // There are 3 possible EC named curves. Consume the first byte to decide on
+ // the curve.
+ uint8_t curve_index = 0;
+ if (size > 0) {
+ curve_index = data[0];
+ data++;
+ size--;
+ }
+
+ blink::WebCryptoNamedCurve curve;
+
+ switch (curve_index % 3) {
+ case 0:
+ curve = blink::WebCryptoNamedCurveP256;
+ break;
+ case 1:
+ curve = blink::WebCryptoNamedCurveP384;
+ break;
+ default:
+ curve = blink::WebCryptoNamedCurveP521;
+ break;
+ }
+
+ // Always use ECDSA as the algorithm. Shouldn't make an difference for import.
+ blink::WebCryptoAlgorithmId algorithm_id = blink::WebCryptoAlgorithmIdEcdsa;
+
+ // Use key usages that are compatible with the chosen algorithm and key type.
+ blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageVerify;
+
+ blink::WebCryptoKey key;
+ webcrypto::Status status = webcrypto::ImportKey(
+ blink::WebCryptoKeyFormatRaw,
+ webcrypto::CryptoData(data, base::checked_cast<uint32_t>(size)),
CreateEcImportAlgorithm(algorithm_id, curve), true, usages, &key);
// These errors imply a bad setup of parameters, and means ImportKey() may not
@@ -116,7 +163,7 @@ void ImportRsaKeyFromDerFuzzData(const uint8_t* data,
blink::WebCryptoKey key;
webcrypto::Status status = webcrypto::ImportKey(
- format, webcrypto::CryptoData(data, size),
+ format, webcrypto::CryptoData(data, base::checked_cast<uint32_t>(size)),
CreateRsaHashedImportAlgorithm(algorithm_id, hash_id), true, usages,
&key);
diff --git a/chromium/components/webcrypto/fuzzer_support.h b/chromium/components/webcrypto/fuzzer_support.h
index 43cde789f38..4ca621b0e33 100644
--- a/chromium/components/webcrypto/fuzzer_support.h
+++ b/chromium/components/webcrypto/fuzzer_support.h
@@ -16,6 +16,8 @@ void ImportEcKeyFromDerFuzzData(const uint8_t* data,
size_t size,
blink::WebCryptoKeyFormat format);
+void ImportEcKeyFromRawFuzzData(const uint8_t* data, size_t size);
+
void ImportRsaKeyFromDerFuzzData(const uint8_t* data,
size_t size,
blink::WebCryptoKeyFormat format);
diff --git a/chromium/components/webcrypto/status.cc b/chromium/components/webcrypto/status.cc
index 4747a7f0864..6ba4cbfccde 100644
--- a/chromium/components/webcrypto/status.cc
+++ b/chromium/components/webcrypto/status.cc
@@ -351,11 +351,22 @@ Status Status::ErrorPbkdf2DeriveBitsLengthNotSpecified() {
"No length was specified for the PBKDF2 Derive Bits operation.");
}
+Status Status::ErrorPbkdf2DeriveBitsLengthZero() {
+ return Status(
+ blink::WebCryptoErrorTypeOperation,
+ "A length of 0 was specified for PBKDF2's Derive Bits operation.");
+}
+
Status Status::ErrorPbkdf2Iterations0() {
return Status(blink::WebCryptoErrorTypeOperation,
"PBKDF2 requires iterations > 0");
}
+Status Status::ErrorImportExtractableKdfKey() {
+ return Status(blink::WebCryptoErrorTypeSyntax,
+ "KDF keys must set extractable=false");
+}
+
Status::Status(blink::WebCryptoErrorType error_type,
const std::string& error_details_utf8)
: type_(TYPE_ERROR),
diff --git a/chromium/components/webcrypto/status.h b/chromium/components/webcrypto/status.h
index 2772e32d5b3..5933623e848 100644
--- a/chromium/components/webcrypto/status.h
+++ b/chromium/components/webcrypto/status.h
@@ -267,9 +267,16 @@ class Status {
// No length parameter was provided for PBKDF2's Derive Bits operation.
static Status ErrorPbkdf2DeriveBitsLengthNotSpecified();
+ // PBKDF2's deriveBits() was called with an unsupported length of 0.
+ static Status ErrorPbkdf2DeriveBitsLengthZero();
+
// PBKDF2 was called with iterations == 0.
static Status ErrorPbkdf2Iterations0();
+ // Tried importing a key with extractable=true for one of the *KDF
+ // algorithms.
+ static Status ErrorImportExtractableKdfKey();
+
private:
enum Type { TYPE_ERROR, TYPE_SUCCESS };
diff --git a/chromium/components/webcrypto/webcrypto.gyp b/chromium/components/webcrypto/webcrypto.gyp
deleted file mode 100644
index e4cf9af5507..00000000000
--- a/chromium/components/webcrypto/webcrypto.gyp
+++ /dev/null
@@ -1,69 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'webcrypto',
- 'type': 'static_library',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../crypto/crypto.gyp:crypto',
- '../../third_party/boringssl/boringssl.gyp:boringssl',
- '../../third_party/WebKit/public/blink.gyp:blink',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'algorithm_dispatch.cc',
- 'algorithm_dispatch.h',
- 'algorithm_implementation.cc',
- 'algorithm_implementation.h',
- 'algorithm_implementations.h',
- 'algorithm_registry.cc',
- 'algorithm_registry.h',
- 'algorithms/aes.cc',
- 'algorithms/aes.h',
- 'algorithms/aes_cbc.cc',
- 'algorithms/aes_ctr.cc',
- 'algorithms/aes_gcm.cc',
- 'algorithms/aes_kw.cc',
- 'algorithms/asymmetric_key_util.cc',
- 'algorithms/asymmetric_key_util.h',
- 'algorithms/ec.cc',
- 'algorithms/ec.h',
- 'algorithms/ecdh.cc',
- 'algorithms/ecdsa.cc',
- 'algorithms/hkdf.cc',
- 'algorithms/hmac.cc',
- 'algorithms/pbkdf2.cc',
- 'algorithms/rsa.cc',
- 'algorithms/rsa.h',
- 'algorithms/rsa_oaep.cc',
- 'algorithms/rsa_pss.cc',
- 'algorithms/rsa_sign.cc',
- 'algorithms/rsa_sign.h',
- 'algorithms/rsa_ssa.cc',
- 'algorithms/secret_key_util.cc',
- 'algorithms/secret_key_util.h',
- 'algorithms/sha.cc',
- 'algorithms/util.cc',
- 'algorithms/util.h',
- 'blink_key_handle.cc',
- 'blink_key_handle.h',
- 'crypto_data.cc',
- 'crypto_data.h',
- 'generate_key_result.cc',
- 'generate_key_result.h',
- 'jwk.cc',
- 'jwk.h',
- 'status.cc',
- 'status.h',
- 'webcrypto_impl.cc',
- 'webcrypto_impl.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/webcrypto/webcrypto_impl.cc b/chromium/components/webcrypto/webcrypto_impl.cc
index 7986b774114..cac891e7a4b 100644
--- a/chromium/components/webcrypto/webcrypto_impl.cc
+++ b/chromium/components/webcrypto/webcrypto_impl.cc
@@ -13,11 +13,11 @@
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/task_runner.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "base/threading/worker_pool.h"
#include "components/webcrypto/algorithm_dispatch.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/generate_key_result.h"
@@ -38,9 +38,9 @@ namespace {
// WebCrypto operations can be slow. For instance generating an RSA key can
// take seconds.
//
-// The strategy used here is to run a sequenced worker pool for all WebCrypto
-// operations (except structured cloning). This same pool is also used by
-// requests started from Blink Web Workers.
+// The strategy used here is to run a worker pool for all WebCrypto operations
+// (except structured cloning). This same pool is also used by requests started
+// from Blink Web Workers.
//
// A few notes to keep in mind:
//
@@ -71,18 +71,24 @@ namespace {
// be deleted while running in the crypto worker pool.
class CryptoThreadPool {
public:
- CryptoThreadPool()
- : worker_pool_(new base::SequencedWorkerPool(1, "WebCrypto")),
- task_runner_(worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
- worker_pool_->GetSequenceToken(),
- base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) {}
+ CryptoThreadPool() : worker_thread_("WebCrypto") {
+ base::Thread::Options options;
+ options.joinable = false;
+ worker_thread_.StartWithOptions(options);
+ }
static bool PostTask(const tracked_objects::Location& from_here,
const base::Closure& task);
private:
- scoped_refptr<base::SequencedWorkerPool> worker_pool_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ // TODO(gab): the pool is currently using a single non-joinable thread to
+ // mimic the old behavior of using a CONTINUE_ON_SHUTDOWN SequencedTaskRunner
+ // on a single-threaded SequencedWorkerPool, but we'd like to consider using
+ // the TaskScheduler here and allowing multiple threads (SEQUENCED or even
+ // PARALLEL ExecutionMode: http://crbug.com/623700).
+ base::Thread worker_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(CryptoThreadPool);
};
base::LazyInstance<CryptoThreadPool>::Leaky crypto_thread_pool =
@@ -90,7 +96,8 @@ base::LazyInstance<CryptoThreadPool>::Leaky crypto_thread_pool =
bool CryptoThreadPool::PostTask(const tracked_objects::Location& from_here,
const base::Closure& task) {
- return crypto_thread_pool.Get().task_runner_->PostTask(from_here, task);
+ return crypto_thread_pool.Get().worker_thread_.task_runner()->PostTask(
+ from_here, task);
}
void CompleteWithThreadPoolError(blink::WebCryptoResult* result) {
@@ -175,17 +182,16 @@ struct BaseState {
struct EncryptState : public BaseState {
EncryptState(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> data,
const blink::WebCryptoResult& result)
: BaseState(result),
algorithm(algorithm),
key(key),
- data(data, data + data_size) {}
+ data(std::move(data)) {}
const blink::WebCryptoAlgorithm algorithm;
const blink::WebCryptoKey key;
- const std::vector<uint8_t> data;
+ const blink::WebVector<unsigned char> data;
std::vector<uint8_t> buffer;
};
@@ -212,21 +218,20 @@ struct GenerateKeyState : public BaseState {
struct ImportKeyState : public BaseState {
ImportKeyState(blink::WebCryptoKeyFormat format,
- const unsigned char* key_data,
- unsigned int key_data_size,
+ blink::WebVector<unsigned char> key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
const blink::WebCryptoResult& result)
: BaseState(result),
format(format),
- key_data(key_data, key_data + key_data_size),
+ key_data(std::move(key_data)),
algorithm(algorithm),
extractable(extractable),
usages(usages) {}
const blink::WebCryptoKeyFormat format;
- const std::vector<uint8_t> key_data;
+ const blink::WebVector<unsigned char> key_data;
const blink::WebCryptoAlgorithm algorithm;
const bool extractable;
const blink::WebCryptoKeyUsageMask usages;
@@ -251,22 +256,20 @@ typedef EncryptState SignState;
struct VerifySignatureState : public BaseState {
VerifySignatureState(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
- const unsigned char* signature,
- unsigned int signature_size,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> signature,
+ blink::WebVector<unsigned char> data,
const blink::WebCryptoResult& result)
: BaseState(result),
algorithm(algorithm),
key(key),
- signature(signature, signature + signature_size),
- data(data, data + data_size),
+ signature(std::move(signature)),
+ data(std::move(data)),
verify_result(false) {}
const blink::WebCryptoAlgorithm algorithm;
const blink::WebCryptoKey key;
- const std::vector<uint8_t> signature;
- const std::vector<uint8_t> data;
+ blink::WebVector<unsigned char> signature;
+ blink::WebVector<unsigned char> data;
bool verify_result;
};
@@ -293,8 +296,7 @@ struct WrapKeyState : public BaseState {
struct UnwrapKeyState : public BaseState {
UnwrapKeyState(blink::WebCryptoKeyFormat format,
- const unsigned char* wrapped_key,
- unsigned wrapped_key_size,
+ blink::WebVector<unsigned char> wrapped_key,
const blink::WebCryptoKey& wrapping_key,
const blink::WebCryptoAlgorithm& unwrap_algorithm,
const blink::WebCryptoAlgorithm& unwrapped_key_algorithm,
@@ -303,7 +305,7 @@ struct UnwrapKeyState : public BaseState {
const blink::WebCryptoResult& result)
: BaseState(result),
format(format),
- wrapped_key(wrapped_key, wrapped_key + wrapped_key_size),
+ wrapped_key(std::move(wrapped_key)),
wrapping_key(wrapping_key),
unwrap_algorithm(unwrap_algorithm),
unwrapped_key_algorithm(unwrapped_key_algorithm),
@@ -311,7 +313,7 @@ struct UnwrapKeyState : public BaseState {
usages(usages) {}
const blink::WebCryptoKeyFormat format;
- const std::vector<uint8_t> wrapped_key;
+ blink::WebVector<unsigned char> wrapped_key;
const blink::WebCryptoKey wrapping_key;
const blink::WebCryptoAlgorithm unwrap_algorithm;
const blink::WebCryptoAlgorithm unwrapped_key_algorithm;
@@ -592,13 +594,12 @@ WebCryptoImpl::~WebCryptoImpl() {
void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) {
DCHECK(!algorithm.isNull());
std::unique_ptr<EncryptState> state(
- new EncryptState(algorithm, key, data, data_size, result));
+ new EncryptState(algorithm, key, std::move(data), result));
if (!CryptoThreadPool::PostTask(
FROM_HERE, base::Bind(DoEncrypt, base::Passed(&state)))) {
CompleteWithThreadPoolError(&result);
@@ -607,13 +608,12 @@ void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm,
void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) {
DCHECK(!algorithm.isNull());
std::unique_ptr<DecryptState> state(
- new DecryptState(algorithm, key, data, data_size, result));
+ new DecryptState(algorithm, key, std::move(data), result));
if (!CryptoThreadPool::PostTask(
FROM_HERE, base::Bind(DoDecrypt, base::Passed(&state)))) {
CompleteWithThreadPoolError(&result);
@@ -621,13 +621,12 @@ void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm,
}
void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) {
DCHECK(!algorithm.isNull());
std::unique_ptr<DigestState> state(new DigestState(
- algorithm, blink::WebCryptoKey::createNull(), data, data_size, result));
+ algorithm, blink::WebCryptoKey::createNull(), std::move(data), result));
if (!CryptoThreadPool::PostTask(FROM_HERE,
base::Bind(DoDigest, base::Passed(&state)))) {
CompleteWithThreadPoolError(&result);
@@ -649,14 +648,13 @@ void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm,
}
void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format,
- const unsigned char* key_data,
- unsigned int key_data_size,
+ blink::WebVector<unsigned char> key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoResult result) {
std::unique_ptr<ImportKeyState> state(new ImportKeyState(
- format, key_data, key_data_size, algorithm, extractable, usages, result));
+ format, std::move(key_data), algorithm, extractable, usages, result));
if (!CryptoThreadPool::PostTask(
FROM_HERE, base::Bind(DoImportKey, base::Passed(&state)))) {
CompleteWithThreadPoolError(&result);
@@ -676,11 +674,10 @@ void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format,
void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) {
std::unique_ptr<SignState> state(
- new SignState(algorithm, key, data, data_size, result));
+ new SignState(algorithm, key, std::move(data), result));
if (!CryptoThreadPool::PostTask(FROM_HERE,
base::Bind(DoSign, base::Passed(&state)))) {
CompleteWithThreadPoolError(&result);
@@ -689,13 +686,11 @@ void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm,
void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
- const unsigned char* signature,
- unsigned int signature_size,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> signature,
+ blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) {
std::unique_ptr<VerifySignatureState> state(new VerifySignatureState(
- algorithm, key, signature, signature_size, data, data_size, result));
+ algorithm, key, std::move(signature), std::move(data), result));
if (!CryptoThreadPool::PostTask(FROM_HERE,
base::Bind(DoVerify, base::Passed(&state)))) {
CompleteWithThreadPoolError(&result);
@@ -717,8 +712,7 @@ void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format,
void WebCryptoImpl::unwrapKey(
blink::WebCryptoKeyFormat format,
- const unsigned char* wrapped_key,
- unsigned wrapped_key_size,
+ blink::WebVector<unsigned char> wrapped_key,
const blink::WebCryptoKey& wrapping_key,
const blink::WebCryptoAlgorithm& unwrap_algorithm,
const blink::WebCryptoAlgorithm& unwrapped_key_algorithm,
@@ -726,7 +720,7 @@ void WebCryptoImpl::unwrapKey(
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoResult result) {
std::unique_ptr<UnwrapKeyState> state(new UnwrapKeyState(
- format, wrapped_key, wrapped_key_size, wrapping_key, unwrap_algorithm,
+ format, std::move(wrapped_key), wrapping_key, unwrap_algorithm,
unwrapped_key_algorithm, extractable, usages, result));
if (!CryptoThreadPool::PostTask(
FROM_HERE, base::Bind(DoUnwrapKey, base::Passed(&state)))) {
@@ -763,9 +757,9 @@ void WebCryptoImpl::deriveKey(
}
}
-blink::WebCryptoDigestor* WebCryptoImpl::createDigestor(
+std::unique_ptr<blink::WebCryptoDigestor> WebCryptoImpl::createDigestor(
blink::WebCryptoAlgorithmId algorithm_id) {
- return webcrypto::CreateDigestor(algorithm_id).release();
+ return webcrypto::CreateDigestor(algorithm_id);
}
bool WebCryptoImpl::deserializeKeyForClone(
diff --git a/chromium/components/webcrypto/webcrypto_impl.h b/chromium/components/webcrypto/webcrypto_impl.h
index af5f6fcc356..20de3ed802d 100644
--- a/chromium/components/webcrypto/webcrypto_impl.h
+++ b/chromium/components/webcrypto/webcrypto_impl.h
@@ -27,25 +27,21 @@ class WebCryptoImpl : public blink::WebCrypto {
void encrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) override;
void decrypt(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) override;
void digest(const blink::WebCryptoAlgorithm& algorithm,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) override;
void generateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
blink::WebCryptoResult result) override;
void importKey(blink::WebCryptoKeyFormat format,
- const unsigned char* key_data,
- unsigned int key_data_size,
+ blink::WebVector<unsigned char> key_data,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usages,
@@ -55,15 +51,12 @@ class WebCryptoImpl : public blink::WebCrypto {
blink::WebCryptoResult result) override;
void sign(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) override;
void verifySignature(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
- const unsigned char* signature,
- unsigned int signature_size,
- const unsigned char* data,
- unsigned int data_size,
+ blink::WebVector<unsigned char> signature,
+ blink::WebVector<unsigned char> data,
blink::WebCryptoResult result) override;
void wrapKey(blink::WebCryptoKeyFormat format,
const blink::WebCryptoKey& key,
@@ -71,8 +64,7 @@ class WebCryptoImpl : public blink::WebCrypto {
const blink::WebCryptoAlgorithm& wrap_algorithm,
blink::WebCryptoResult result) override;
void unwrapKey(blink::WebCryptoKeyFormat format,
- const unsigned char* wrapped_key,
- unsigned wrapped_key_size,
+ blink::WebVector<unsigned char> wrapped_key,
const blink::WebCryptoKey& wrapping_key,
const blink::WebCryptoAlgorithm& unwrap_algorithm,
const blink::WebCryptoAlgorithm& unwrapped_key_algorithm,
@@ -96,10 +88,8 @@ class WebCryptoImpl : public blink::WebCrypto {
// This method returns a digestor object that can be used to synchronously
// compute a digest one chunk at a time. Thus, the consume does not need to
// hold onto a large buffer with all the data to digest. Chunks can be given
- // one at a time and the digest will be computed piecemeal. The allocated
- // WebCrytpoDigestor that is returned by createDigestor must be freed by the
- // caller.
- blink::WebCryptoDigestor* createDigestor(
+ // one at a time and the digest will be computed piecemeal.
+ std::unique_ptr<blink::WebCryptoDigestor> createDigestor(
blink::WebCryptoAlgorithmId algorithm_id) override;
bool deserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
diff --git a/chromium/components/webdata.gypi b/chromium/components/webdata.gypi
deleted file mode 100644
index 48d9ac5a827..00000000000
--- a/chromium/components/webdata.gypi
+++ /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.
-
-{
- 'targets': [
- {
- 'target_name': 'webdata_common',
- 'type': '<(component)',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../sql/sql.gyp:sql',
- ],
- 'defines': [
- 'WEBDATA_IMPLEMENTATION',
- ],
- 'sources': [
- 'webdata/common/web_data_request_manager.cc',
- 'webdata/common/web_data_request_manager.h',
- 'webdata/common/web_data_results.h',
- 'webdata/common/web_data_service_base.cc',
- 'webdata/common/web_data_service_base.h',
- 'webdata/common/web_data_service_consumer.h',
- 'webdata/common/web_database.cc',
- 'webdata/common/web_database.h',
- 'webdata/common/web_database_backend.cc',
- 'webdata/common/web_database_backend.h',
- 'webdata/common/web_database_service.cc',
- 'webdata/common/web_database_service.h',
- 'webdata/common/web_database_table.cc',
- 'webdata/common/web_database_table.h',
- 'webdata/common/webdata_constants.cc',
- 'webdata/common/webdata_constants.h',
- 'webdata/common/webdata_export.h'
- ],
- },
- ],
-}
diff --git a/chromium/components/webdata/common/web_data_service_base.h b/chromium/components/webdata/common/web_data_service_base.h
index adad9f10480..2783beb2d81 100644
--- a/chromium/components/webdata/common/web_data_service_base.h
+++ b/chromium/components/webdata/common/web_data_service_base.h
@@ -36,7 +36,8 @@ class WEBDATA_EXPORT WebDataServiceBase
// takes a single parameter, the sql::InitStatus value from trying
// to open the database.
// TODO(joi): Should we combine this with WebDatabaseService::InitCallback?
- typedef base::Callback<void(sql::InitStatus)> ProfileErrorCallback;
+ typedef base::Callback<void(sql::InitStatus, const std::string&)>
+ ProfileErrorCallback;
typedef base::Closure DBLoadedCallback;
diff --git a/chromium/components/webdata/common/web_database.cc b/chromium/components/webdata/common/web_database.cc
index a24a4b88a51..c731270a2f7 100644
--- a/chromium/components/webdata/common/web_database.cc
+++ b/chromium/components/webdata/common/web_database.cc
@@ -65,6 +65,11 @@ void WebDatabase::CommitTransaction() {
db_.CommitTransaction();
}
+std::string WebDatabase::GetDiagnosticInfo(int extended_error,
+ sql::Statement* statement) {
+ return db_.GetDiagnosticInfo(extended_error, statement);
+}
+
sql::Connection* WebDatabase::GetSQLConnection() {
return &db_;
}
diff --git a/chromium/components/webdata/common/web_database.h b/chromium/components/webdata/common/web_database.h
index bd914f446ef..79931bedba7 100644
--- a/chromium/components/webdata/common/web_database.h
+++ b/chromium/components/webdata/common/web_database.h
@@ -41,6 +41,13 @@ class WEBDATA_EXPORT WebDatabase {
// Retrieves a table based on its |key|.
WebDatabaseTable* GetTable(WebDatabaseTable::TypeKey key);
+ // Call before Init() to set the error callback to be used for the
+ // underlying database connection.
+ void set_error_callback(
+ const sql::Connection::ErrorCallback& error_callback) {
+ db_.set_error_callback(error_callback);
+ }
+
// Initialize the database given a name. The name defines where the SQLite
// file is. If this returns an error code, no other method should be called.
//
@@ -53,6 +60,8 @@ class WEBDATA_EXPORT WebDatabase {
void BeginTransaction();
void CommitTransaction();
+ std::string GetDiagnosticInfo(int extended_error, sql::Statement* statement);
+
// Exposed for testing only.
sql::Connection* GetSQLConnection();
diff --git a/chromium/components/webdata/common/web_database_backend.cc b/chromium/components/webdata/common/web_database_backend.cc
index 7cb343e62f0..a4446061f91 100644
--- a/chromium/components/webdata/common/web_database_backend.cc
+++ b/chromium/components/webdata/common/web_database_backend.cc
@@ -4,6 +4,7 @@
#include "components/webdata/common/web_database_backend.h"
+#include <algorithm>
#include <utility>
#include "base/bind.h"
@@ -11,6 +12,7 @@
#include "components/webdata/common/web_data_request_manager.h"
#include "components/webdata/common/web_database.h"
#include "components/webdata/common/web_database_table.h"
+#include "sql/error_delegate_util.h"
using base::Bind;
using base::FilePath;
@@ -24,8 +26,8 @@ WebDatabaseBackend::WebDatabaseBackend(
request_manager_(new WebDataRequestManager()),
init_status_(sql::INIT_FAILURE),
init_complete_(false),
- delegate_(delegate) {
-}
+ catastrophic_error_occurred_(false),
+ delegate_(delegate) {}
void WebDatabaseBackend::AddTable(std::unique_ptr<WebDatabaseTable> table) {
DCHECK(!db_.get());
@@ -35,31 +37,8 @@ void WebDatabaseBackend::AddTable(std::unique_ptr<WebDatabaseTable> table) {
void WebDatabaseBackend::InitDatabase() {
LoadDatabaseIfNecessary();
if (delegate_) {
- delegate_->DBLoaded(init_status_);
- }
-}
-
-sql::InitStatus WebDatabaseBackend::LoadDatabaseIfNecessary() {
- if (init_complete_ || db_path_.empty()) {
- return init_status_;
- }
- init_complete_ = true;
- db_.reset(new WebDatabase());
-
- for (ScopedVector<WebDatabaseTable>::iterator it = tables_.begin();
- it != tables_.end(); ++it) {
- db_->AddTable(*it);
- }
-
- init_status_ = db_->Init(db_path_);
- if (init_status_ != sql::INIT_OK) {
- LOG(ERROR) << "Cannot initialize the web database: " << init_status_;
- db_.reset(NULL);
- return init_status_;
+ delegate_->DBLoaded(init_status_, diagnostics_);
}
-
- db_->BeginTransaction();
- return init_status_;
}
void WebDatabaseBackend::ShutdownDatabase() {
@@ -113,6 +92,50 @@ WebDatabaseBackend::~WebDatabaseBackend() {
ShutdownDatabase();
}
+void WebDatabaseBackend::LoadDatabaseIfNecessary() {
+ if (init_complete_ || db_path_.empty())
+ return;
+
+ init_complete_ = true;
+ db_.reset(new WebDatabase());
+
+ for (const auto& table : tables_)
+ db_->AddTable(table);
+
+ // Unretained to avoid a ref loop since we own |db_|.
+ db_->set_error_callback(base::Bind(&WebDatabaseBackend::DatabaseErrorCallback,
+ base::Unretained(this)));
+ diagnostics_.clear();
+ catastrophic_error_occurred_ = false;
+ init_status_ = db_->Init(db_path_);
+
+ if (init_status_ != sql::INIT_OK) {
+ LOG(ERROR) << "Cannot initialize the web database: " << init_status_;
+ db_.reset();
+ return;
+ }
+
+ // A catastrophic error might have happened and recovered.
+ if (catastrophic_error_occurred_) {
+ init_status_ = sql::INIT_OK_WITH_DATA_LOSS;
+ LOG(WARNING)
+ << "Webdata recovered from a catastrophic error. Data loss possible.";
+ }
+ db_->BeginTransaction();
+}
+
+void WebDatabaseBackend::DatabaseErrorCallback(int error,
+ sql::Statement* statement) {
+ // We ignore any further error callbacks after the first catastrophic error.
+ if (!catastrophic_error_occurred_ && sql::IsErrorCatastrophic(error)) {
+ catastrophic_error_occurred_ = true;
+ diagnostics_ = db_->GetDiagnosticInfo(error, statement);
+ diagnostics_ += sql::GetCorruptFileDiagnosticsInfo(db_path_);
+
+ db_->GetSQLConnection()->RazeAndClose();
+ }
+}
+
void WebDatabaseBackend::Commit() {
DCHECK(db_);
DCHECK_EQ(sql::INIT_OK, init_status_);
diff --git a/chromium/components/webdata/common/web_database_backend.h b/chromium/components/webdata/common/web_database_backend.h
index 341bb76d7ac..dbb694aaab3 100644
--- a/chromium/components/webdata/common/web_database_backend.h
+++ b/chromium/components/webdata/common/web_database_backend.h
@@ -39,7 +39,11 @@ class WEBDATA_EXPORT WebDatabaseBackend
virtual ~Delegate() {}
// Invoked when the backend has finished loading the db.
- virtual void DBLoaded(sql::InitStatus status) = 0;
+ // |status| is the result of initializing the db.
+ // |diagnostics| contains diagnostic information about the db, and it will
+ // only be populated when an error occurs.
+ virtual void DBLoaded(sql::InitStatus status,
+ const std::string& diagnostics) = 0;
};
WebDatabaseBackend(
@@ -54,12 +58,6 @@ class WEBDATA_EXPORT WebDatabaseBackend
// Callback is called synchronously.
void InitDatabase();
- // Opens the database file from the profile path if an init has not yet been
- // attempted. Separated from the constructor to ease construction/destruction
- // of this object on one thread but database access on the DB thread. Returns
- // the status of the database.
- sql::InitStatus LoadDatabaseIfNecessary();
-
// Shuts down the database.
void ShutdownDatabase();
@@ -90,6 +88,14 @@ class WEBDATA_EXPORT WebDatabaseBackend
virtual ~WebDatabaseBackend();
private:
+ // Opens the database file from the profile path if an init has not yet been
+ // attempted. Separated from the constructor to ease construction/destruction
+ // of this object on one thread but database access on the DB thread.
+ void LoadDatabaseIfNecessary();
+
+ // Invoked on a db error.
+ void DatabaseErrorCallback(int error, sql::Statement* statement);
+
// Commit the current transaction.
void Commit();
@@ -119,6 +125,14 @@ class WEBDATA_EXPORT WebDatabaseBackend
// fails), used to avoid continually trying to reinit if the db init fails.
bool init_complete_;
+ // True if a catastrophic database error occurs and further error callbacks
+ // from the database should be ignored.
+ bool catastrophic_error_occurred_;
+
+ // If a catastrophic database error has occurred, this contains any available
+ // diagnostic information.
+ std::string diagnostics_;
+
// Delegate. See the class definition above for more information.
std::unique_ptr<Delegate> delegate_;
diff --git a/chromium/components/webdata/common/web_database_migration_unittest.cc b/chromium/components/webdata/common/web_database_migration_unittest.cc
index 36d68bb26b9..996f9594d70 100644
--- a/chromium/components/webdata/common/web_database_migration_unittest.cc
+++ b/chromium/components/webdata/common/web_database_migration_unittest.cc
@@ -88,7 +88,7 @@ class WebDatabaseMigrationTest : public testing::Test {
base::FilePath GetDatabasePath() {
const base::FilePath::CharType kWebDatabaseFilename[] =
FILE_PATH_LITERAL("TestWebDatabase.sqlite3");
- return temp_dir_.path().Append(base::FilePath(kWebDatabaseFilename));
+ return temp_dir_.GetPath().Append(base::FilePath(kWebDatabaseFilename));
}
// The textual contents of |file| are read from
diff --git a/chromium/components/webdata/common/web_database_service.cc b/chromium/components/webdata/common/web_database_service.cc
index 3ecd6f3ac6c..79bc298022c 100644
--- a/chromium/components/webdata/common/web_database_service.cc
+++ b/chromium/components/webdata/common/web_database_service.cc
@@ -27,12 +27,11 @@ class WebDatabaseService::BackendDelegate
: web_database_service_(web_database_service),
callback_thread_(base::ThreadTaskRunnerHandle::Get()) {}
- void DBLoaded(sql::InitStatus status) override {
+ void DBLoaded(sql::InitStatus status,
+ const std::string& diagnostics) override {
callback_thread_->PostTask(
- FROM_HERE,
- base::Bind(&WebDatabaseService::OnDatabaseLoadDone,
- web_database_service_,
- status));
+ FROM_HERE, base::Bind(&WebDatabaseService::OnDatabaseLoadDone,
+ web_database_service_, status, diagnostics));
}
private:
const base::WeakPtr<WebDatabaseService> web_database_service_;
@@ -133,23 +132,33 @@ void WebDatabaseService::RegisterDBErrorCallback(
error_callbacks_.push_back(callback);
}
-void WebDatabaseService::OnDatabaseLoadDone(sql::InitStatus status) {
- if (status == sql::INIT_OK) {
- db_loaded_ = true;
-
- for (size_t i = 0; i < loaded_callbacks_.size(); i++) {
- if (!loaded_callbacks_[i].is_null())
- loaded_callbacks_[i].Run();
- }
-
- loaded_callbacks_.clear();
- } else {
+void WebDatabaseService::OnDatabaseLoadDone(sql::InitStatus status,
+ const std::string& diagnostics) {
+ // The INIT_OK_WITH_DATA_LOSS status is an initialization success but with
+ // suspected data loss, so we also run the error callbacks.
+ if (status != sql::INIT_OK) {
// Notify that the database load failed.
- for (size_t i = 0; i < error_callbacks_.size(); i++) {
- if (!error_callbacks_[i].is_null())
- error_callbacks_[i].Run(status);
+ while (!error_callbacks_.empty()) {
+ // The profile error callback is a message box that runs in a nested run
+ // loop. While it's being displayed, other OnDatabaseLoadDone() will run
+ // (posted from WebDatabaseBackend::Delegate::DBLoaded()). We need to make
+ // sure that after the callback running the message box returns, it checks
+ // |error_callbacks_| before it accesses it.
+ DBLoadErrorCallback error_callback = error_callbacks_.back();
+ error_callbacks_.pop_back();
+ if (!error_callback.is_null())
+ error_callback.Run(status, diagnostics);
}
+ }
+
+ if (status == sql::INIT_OK || status == sql::INIT_OK_WITH_DATA_LOSS) {
+ db_loaded_ = true;
- error_callbacks_.clear();
+ while (!loaded_callbacks_.empty()) {
+ DBLoadedCallback loaded_callback = loaded_callbacks_.back();
+ loaded_callbacks_.pop_back();
+ if (!loaded_callback.is_null())
+ loaded_callback.Run();
+ }
}
}
diff --git a/chromium/components/webdata/common/web_database_service.h b/chromium/components/webdata/common/web_database_service.h
index 2c68a3b0105..5ce19a05709 100644
--- a/chromium/components/webdata/common/web_database_service.h
+++ b/chromium/components/webdata/common/web_database_service.h
@@ -50,12 +50,13 @@ class WebDataServiceConsumer;
class WEBDATA_EXPORT WebDatabaseService
: public base::RefCountedDeleteOnMessageLoop<WebDatabaseService> {
public:
- typedef base::Callback<std::unique_ptr<WDTypedResult>(WebDatabase*)> ReadTask;
- typedef base::Callback<WebDatabase::State(WebDatabase*)> WriteTask;
+ using ReadTask = base::Callback<std::unique_ptr<WDTypedResult>(WebDatabase*)>;
+ using WriteTask = base::Callback<WebDatabase::State(WebDatabase*)>;
// Types for managing DB loading callbacks.
- typedef base::Closure DBLoadedCallback;
- typedef base::Callback<void(sql::InitStatus)> DBLoadErrorCallback;
+ using DBLoadedCallback = base::Closure;
+ using DBLoadErrorCallback =
+ base::Callback<void(sql::InitStatus, const std::string&)>;
// Takes the path to the WebDatabase file.
// WebDatabaseService lives on |ui_thread| and posts tasks to |db_thread|.
@@ -119,12 +120,13 @@ class WEBDATA_EXPORT WebDatabaseService
friend class base::RefCountedDeleteOnMessageLoop<WebDatabaseService>;
friend class base::DeleteHelper<WebDatabaseService>;
- typedef std::vector<DBLoadedCallback> LoadedCallbacks;
- typedef std::vector<DBLoadErrorCallback> ErrorCallbacks;
+ using LoadedCallbacks = std::vector<DBLoadedCallback>;
+ using ErrorCallbacks = std::vector<DBLoadErrorCallback>;
virtual ~WebDatabaseService();
- void OnDatabaseLoadDone(sql::InitStatus status);
+ void OnDatabaseLoadDone(sql::InitStatus status,
+ const std::string& diagnostics);
base::FilePath path_;
diff --git a/chromium/components/webdata_services.gypi b/chromium/components/webdata_services.gypi
deleted file mode 100644
index 3e7b5ec9a26..00000000000
--- a/chromium/components/webdata_services.gypi
+++ /dev/null
@@ -1,49 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/webdata_services
- 'target_name': 'webdata_services',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../sql/sql.gyp:sql',
- '../sync/sync.gyp:sync',
- 'autofill_core_browser',
- 'keyed_service_core',
- 'password_manager_core_browser',
- 'search_engines',
- 'signin_core_browser',
- 'webdata_common',
- ],
- 'sources': [
- 'webdata_services/web_data_service_wrapper.cc',
- 'webdata_services/web_data_service_wrapper.h',
- ],
- },
- {
- # GN version: //components/webdata_services:test_support
- 'target_name': 'webdata_services_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'autofill_core_browser',
- 'signin_core_browser',
- 'webdata_services',
- ],
- 'sources': [
- 'webdata_services/web_data_service_test_util.cc',
- 'webdata_services/web_data_service_test_util.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/webdata_services/BUILD.gn b/chromium/components/webdata_services/BUILD.gn
index 8626a4c089e..1818a437aa5 100644
--- a/chromium/components/webdata_services/BUILD.gn
+++ b/chromium/components/webdata_services/BUILD.gn
@@ -17,13 +17,13 @@ static_library("webdata_services") {
"//components/password_manager/core/browser",
"//components/search_engines",
"//components/signin/core/browser",
+ "//components/sync",
"//components/webdata/common",
"//sql",
- "//sync",
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"web_data_service_test_util.cc",
diff --git a/chromium/components/webdata_services/DEPS b/chromium/components/webdata_services/DEPS
index fd192716922..ff4a094d4ac 100644
--- a/chromium/components/webdata_services/DEPS
+++ b/chromium/components/webdata_services/DEPS
@@ -5,7 +5,7 @@ include_rules = [
"+components/search_engines/keyword_table.h",
"+components/search_engines/keyword_web_data_service.h",
"+components/signin/core/browser/webdata",
+ "+components/sync",
"+components/webdata/common",
"+sql",
- "+sync",
]
diff --git a/chromium/components/webdata_services/web_data_service_wrapper.h b/chromium/components/webdata_services/web_data_service_wrapper.h
index ecc8c33d3a3..3da8cd9348d 100644
--- a/chromium/components/webdata_services/web_data_service_wrapper.h
+++ b/chromium/components/webdata_services/web_data_service_wrapper.h
@@ -12,8 +12,8 @@
#include "base/memory/ref_counted.h"
#include "build/build_config.h"
#include "components/keyed_service/core/keyed_service.h"
+#include "components/sync/api/syncable_service.h"
#include "sql/init_status.h"
-#include "sync/api/syncable_service.h"
class KeywordWebDataService;
class TokenWebData;
@@ -46,7 +46,14 @@ class WebDataServiceWrapper : public KeyedService {
};
// Shows an error message if a loading error occurs.
- using ShowErrorCallback = void (*)(ErrorType, sql::InitStatus);
+ // |error_type| shows which service encountered an error while loading.
+ // |init_status| is the returned status of initializing the underlying
+ // database.
+ // |diagnostics| contains information about the underlying database
+ // which can help in identifying the cause of the error.
+ using ShowErrorCallback = void (*)(ErrorType error_type,
+ sql::InitStatus init_status,
+ const std::string& diagnostics);
// Constructor for WebDataServiceWrapper that initializes the different
// WebDataServices and starts the synchronization services using |flare|.
diff --git a/chromium/components/webmessaging.gypi b/chromium/components/webmessaging.gypi
deleted file mode 100644
index 1ea14fb5d2d..00000000000
--- a/chromium/components/webmessaging.gypi
+++ /dev/null
@@ -1,69 +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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- 'mojom_files': [
- 'webmessaging/public/interfaces/broadcast_channel.mojom',
- ],
- },
- 'targets': [
- {
- # GN version: //components/webmessaging/webmessaging
- 'target_name': 'webmessaging',
- 'type': 'static_library',
- 'dependencies': [
- 'webmessaging_mojo_bindings',
- '../base/base.gyp:base',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'webmessaging/broadcast_channel_provider.cc',
- 'webmessaging/broadcast_channel_provider.h',
- ],
- },
- {
- 'target_name': 'webmessaging_mojo_bindings',
- 'type': 'static_library',
- 'sources': [ '<@(mojom_files)' ],
- 'dependencies': [
- '../url/url.gyp:url_mojom',
- ],
- 'export_dependent_settings': [
- '../url/url.gyp:url_mojom',
- ],
- 'variables': {
- 'mojom_typemaps': [
- '../url/mojo/gurl.typemap',
- '../url/mojo/origin.typemap',
- ],
- },
- 'includes': [
- '../mojo/mojom_bindings_generator.gypi',
- ],
- },
- {
- 'target_name': 'webmessaging_mojo_bindings_for_blink',
- 'type': 'static_library',
- 'sources': [ '<@(mojom_files)' ],
- 'dependencies': [
- '../url/url.gyp:url_mojom_for_blink',
- ],
- 'export_dependent_settings': [
- '../url/url.gyp:url_mojom_for_blink',
- ],
- 'variables': {
- 'for_blink': 'true',
- 'mojom_typemaps': [
- '../third_party/WebKit/Source/platform/mojo/KURL.typemap',
- '../third_party/WebKit/Source/platform/mojo/SecurityOrigin.typemap',
- ],
- },
- 'includes': [
- '../mojo/mojom_bindings_generator.gypi',
- ],
- },
- ],
-}
diff --git a/chromium/components/webmessaging/BUILD.gn b/chromium/components/webmessaging/BUILD.gn
deleted file mode 100644
index dc816734c7f..00000000000
--- a/chromium/components/webmessaging/BUILD.gn
+++ /dev/null
@@ -1,17 +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.
-
-static_library("webmessaging") {
- sources = [
- "broadcast_channel_provider.cc",
- "broadcast_channel_provider.h",
- ]
-
- deps = [
- "//base",
- "//components/webmessaging/public/interfaces",
- "//mojo/common",
- "//url",
- ]
-}
diff --git a/chromium/components/webmessaging/DEPS b/chromium/components/webmessaging/DEPS
deleted file mode 100644
index ef8ad28d9d4..00000000000
--- a/chromium/components/webmessaging/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+mojo/public",
-]
diff --git a/chromium/components/webmessaging/OWNERS b/chromium/components/webmessaging/OWNERS
deleted file mode 100644
index 1b10b3436d9..00000000000
--- a/chromium/components/webmessaging/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-mek@chromium.org
diff --git a/chromium/components/webmessaging/broadcast_channel_provider.cc b/chromium/components/webmessaging/broadcast_channel_provider.cc
deleted file mode 100644
index 78d3dc6cc5a..00000000000
--- a/chromium/components/webmessaging/broadcast_channel_provider.cc
+++ /dev/null
@@ -1,115 +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 "components/webmessaging/broadcast_channel_provider.h"
-
-#include "base/bind.h"
-#include "base/stl_util.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace webmessaging {
-
-// There is a one-to-one mapping of BroadcastChannel instances in the renderer
-// and Connection instances in the browser. The Connection is owned by a
-// BroadcastChannelProvider.
-class BroadcastChannelProvider::Connection
- : public mojom::BroadcastChannelClient {
- public:
- Connection(const url::Origin& origin,
- const mojo::String& name,
- mojom::BroadcastChannelClientAssociatedPtrInfo client,
- mojom::BroadcastChannelClientAssociatedRequest connection,
- webmessaging::BroadcastChannelProvider* service);
-
- void OnMessage(const mojo::String& message) override;
- void MessageToClient(const mojo::String& message) const {
- client_->OnMessage(message);
- }
- const url::Origin& origin() const { return origin_; }
- const std::string& name() const { return name_; }
-
- void set_connection_error_handler(const base::Closure& error_handler) {
- binding_.set_connection_error_handler(error_handler);
- client_.set_connection_error_handler(error_handler);
- }
-
- private:
- mojo::AssociatedBinding<mojom::BroadcastChannelClient> binding_;
- mojom::BroadcastChannelClientAssociatedPtr client_;
-
- webmessaging::BroadcastChannelProvider* service_;
- url::Origin origin_;
- std::string name_;
-};
-
-BroadcastChannelProvider::Connection::Connection(
- const url::Origin& origin,
- const mojo::String& name,
- mojom::BroadcastChannelClientAssociatedPtrInfo client,
- mojom::BroadcastChannelClientAssociatedRequest connection,
- webmessaging::BroadcastChannelProvider* service)
- : binding_(this, std::move(connection)),
- service_(service),
- origin_(origin),
- name_(name) {
- client_.Bind(std::move(client));
-}
-
-void BroadcastChannelProvider::Connection::OnMessage(
- const mojo::String& message) {
- service_->ReceivedMessageOnConnection(this, message);
-}
-
-BroadcastChannelProvider::BroadcastChannelProvider() {}
-
-void BroadcastChannelProvider::Connect(
- mojo::InterfaceRequest<mojom::BroadcastChannelProvider> request) {
- bindings_.AddBinding(this, std::move(request));
-}
-
-void BroadcastChannelProvider::ConnectToChannel(
- const url::Origin& origin,
- const mojo::String& name,
- mojom::BroadcastChannelClientAssociatedPtrInfo client,
- mojom::BroadcastChannelClientAssociatedRequest connection) {
- std::unique_ptr<Connection> c(new Connection(origin, name, std::move(client),
- std::move(connection), this));
- c->set_connection_error_handler(
- base::Bind(&BroadcastChannelProvider::UnregisterConnection,
- base::Unretained(this), c.get()));
- connections_[origin].insert(std::make_pair(name, std::move(c)));
-}
-
-BroadcastChannelProvider::~BroadcastChannelProvider() {}
-
-void BroadcastChannelProvider::UnregisterConnection(Connection* c) {
- url::Origin origin = c->origin();
- auto& connections = connections_[origin];
- for (auto it = connections.lower_bound(c->name()),
- end = connections.upper_bound(c->name());
- it != end; ++it) {
- if (it->second.get() == c) {
- connections.erase(it);
- break;
- }
- }
- if (connections.empty())
- connections_.erase(origin);
-}
-
-void BroadcastChannelProvider::ReceivedMessageOnConnection(
- Connection* c,
- const mojo::String& message) {
- auto& connections = connections_[c->origin()];
- for (auto it = connections.lower_bound(c->name()),
- end = connections.upper_bound(c->name());
- it != end; ++it) {
- if (it->second.get() != c)
- it->second->MessageToClient(message);
- }
-}
-
-} // namespace webmessaging
diff --git a/chromium/components/webmessaging/broadcast_channel_provider.h b/chromium/components/webmessaging/broadcast_channel_provider.h
deleted file mode 100644
index 1b4904bc6aa..00000000000
--- a/chromium/components/webmessaging/broadcast_channel_provider.h
+++ /dev/null
@@ -1,46 +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 COMPONENTS_WEBMESSAGING_BROADCAST_CHANNEL_PROVIDER_H_
-#define COMPONENTS_WEBMESSAGING_BROADCAST_CHANNEL_PROVIDER_H_
-
-#include <map>
-
-#include "base/memory/ref_counted.h"
-#include "components/webmessaging/public/interfaces/broadcast_channel.mojom.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "url/origin.h"
-
-namespace webmessaging {
-
-class BroadcastChannelProvider
- : public base::RefCountedThreadSafe<BroadcastChannelProvider>,
- public mojom::BroadcastChannelProvider {
- public:
- BroadcastChannelProvider();
- void Connect(mojo::InterfaceRequest<mojom::BroadcastChannelProvider> request);
-
- void ConnectToChannel(
- const url::Origin& origin,
- const mojo::String& name,
- mojom::BroadcastChannelClientAssociatedPtrInfo client,
- mojom::BroadcastChannelClientAssociatedRequest connection) override;
-
- private:
- friend class base::RefCountedThreadSafe<BroadcastChannelProvider>;
- class Connection;
-
- ~BroadcastChannelProvider() override;
-
- void UnregisterConnection(Connection*);
- void ReceivedMessageOnConnection(Connection*, const mojo::String& message);
-
- mojo::BindingSet<mojom::BroadcastChannelProvider> bindings_;
- std::map<url::Origin, std::multimap<std::string, std::unique_ptr<Connection>>>
- connections_;
-};
-
-} // namespace webmessaging
-
-#endif // COMPONENTS_WEBMESSAGING_BROADCAST_CHANNEL_PROVIDER_H_
diff --git a/chromium/components/webmessaging/public/interfaces/BUILD.gn b/chromium/components/webmessaging/public/interfaces/BUILD.gn
deleted file mode 100644
index fa0bdf0eae3..00000000000
--- a/chromium/components/webmessaging/public/interfaces/BUILD.gn
+++ /dev/null
@@ -1,14 +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.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("interfaces") {
- sources = [
- "broadcast_channel.mojom",
- ]
- deps = [
- "//url/mojo:url_mojom_origin",
- ]
-}
diff --git a/chromium/components/webmessaging/public/interfaces/OWNERS b/chromium/components/webmessaging/public/interfaces/OWNERS
deleted file mode 100644
index 08850f42120..00000000000
--- a/chromium/components/webmessaging/public/interfaces/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/webmessaging/public/interfaces/broadcast_channel.mojom b/chromium/components/webmessaging/public/interfaces/broadcast_channel.mojom
deleted file mode 100644
index fedc6df534f..00000000000
--- a/chromium/components/webmessaging/public/interfaces/broadcast_channel.mojom
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module webmessaging.mojom;
-
-import "url/mojo/origin.mojom";
-
-// A pair of BroadcastChannelClient interfaces is used to represent a connection
-// to a particular channel. One client is implemented in the browser, for
-// messages sent from the renderer to the browser, and one client is implemented
-// in the renderer for messages from the browser to the renderer.
-interface BroadcastChannelClient {
- // Messages are passed as SerializedScriptValue.
- OnMessage(string message);
-};
-
-// This interface is used to set up connections to broadcast channels. All
-// connections to channels made from the same event loop should be made
-// through the same BroadcastChannelProvider connection to ensure correct
-// ordering of messages.
-// Typically the browser will have one instance of a BroadcastChannelProvider
-// per storage partition, to which all connections from renderers in that
-// partition are bound. This instance will then forward messages received on a
-// particular connection to all other connections in the same storage partition
-// with the same origin and name.
-interface BroadcastChannelProvider {
- // Connect to the channel identified by the |origin| and |name|. Messages can
- // be sent to the channel using |sender|, and messages to the channel will be
- // received by |receiver|.
- ConnectToChannel(url.mojom.Origin origin, string name,
- associated BroadcastChannelClient receiver,
- associated BroadcastChannelClient& sender);
-};
diff --git a/chromium/components/webp_transcode.gypi b/chromium/components/webp_transcode.gypi
deleted file mode 100644
index 78e6cc0bd45..00000000000
--- a/chromium/components/webp_transcode.gypi
+++ /dev/null
@@ -1,26 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/webp_transcode
- 'target_name': 'webp_transcode',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../ios/net/ios_net.gyp:ios_net',
- '../net/net.gyp:net',
- '../third_party/libwebp/libwebp.gyp:libwebp_dec',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'webp_transcode/webp_decoder.h',
- 'webp_transcode/webp_decoder.mm',
- ],
- },
- ],
-}
diff --git a/chromium/components/webp_transcode/BUILD.gn b/chromium/components/webp_transcode/BUILD.gn
deleted file mode 100644
index acc30d6a3f7..00000000000
--- a/chromium/components/webp_transcode/BUILD.gn
+++ /dev/null
@@ -1,52 +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.
-
-source_set("webp_transcode") {
- sources = [
- "webp_decoder.h",
- "webp_decoder.mm",
- ]
-
- deps = [
- "//base",
- "//ios/net",
- "//net",
- "//third_party/libwebp:libwebp_dec",
- ]
-}
-
-bundle_data("unit_tests_bundle_data") {
- visibility = [ ":unit_tests" ]
- testonly = true
- sources = [
- "//components/test/data/webp_transcode/test.jpg",
- "//components/test/data/webp_transcode/test.webp",
- "//components/test/data/webp_transcode/test_alpha.png",
- "//components/test/data/webp_transcode/test_alpha.webp",
- "//components/test/data/webp_transcode/test_small.tiff",
- "//components/test/data/webp_transcode/test_small.webp",
- ]
- outputs = [
- "{{bundle_resources_dir}}/" +
- "{{source_root_relative_dir}}/{{source_file_part}}",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "webp_decoder_unittest.mm",
- ]
-
- deps = [
- ":unit_tests_bundle_data",
- ":webp_transcode",
- "//base",
- "//net",
- "//net:test_support",
- "//testing/gmock",
- "//testing/gtest",
- "//third_party/ocmock",
- ]
-}
diff --git a/chromium/components/webp_transcode/DEPS b/chromium/components/webp_transcode/DEPS
deleted file mode 100644
index 1e71d47cca0..00000000000
--- a/chromium/components/webp_transcode/DEPS
+++ /dev/null
@@ -1,12 +0,0 @@
-include_rules = [
- "+net",
- # Only WebP decoding is allowed (no encoding).
- "+third_party/libwebp/webp/decode.h",
- "+third_party/ocmock",
-
- # webp_transcode should not depend on //ios for library size reasons.
- "-ios",
- "+ios/net",
- # webp_transcode is only used by iOS.
- "-content",
-]
diff --git a/chromium/components/webp_transcode/OWNERS b/chromium/components/webp_transcode/OWNERS
deleted file mode 100644
index fa3d0c2c438..00000000000
--- a/chromium/components/webp_transcode/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-droger@chromium.org
-sdefresne@chromium.org
diff --git a/chromium/components/webp_transcode/README b/chromium/components/webp_transcode/README
deleted file mode 100644
index 448482547e3..00000000000
--- a/chromium/components/webp_transcode/README
+++ /dev/null
@@ -1,2 +0,0 @@
-webp_transcode is used to convert WebP images to other formats supported by the
-iOS web views.
diff --git a/chromium/components/webp_transcode/webp_decoder.h b/chromium/components/webp_transcode/webp_decoder.h
deleted file mode 100644
index 1cfd6ffad8a..00000000000
--- a/chromium/components/webp_transcode/webp_decoder.h
+++ /dev/null
@@ -1,78 +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.
-
-#ifndef COMPONENTS_WEBP_TRANSCODE_WEBP_DECODER_H_
-#define COMPONENTS_WEBP_TRANSCODE_WEBP_DECODER_H_
-
-#import <Foundation/Foundation.h>
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/memory/ref_counted.h"
-#include "third_party/libwebp/webp/decode.h"
-
-@class NSData;
-
-namespace webp_transcode {
-
-// Decodes a WebP image into either JPEG, PNG or uncompressed TIFF.
-class WebpDecoder : public base::RefCountedThreadSafe<WebpDecoder> {
- public:
- // Format of the decoded image.
- // This enum is used for UMA reporting, keep it in sync with the histogram
- // definition.
- enum DecodedImageFormat { JPEG = 1, PNG, TIFF, DECODED_FORMAT_COUNT };
-
- class Delegate : public base::RefCountedThreadSafe<WebpDecoder::Delegate> {
- public:
- virtual void OnFinishedDecoding(bool success) = 0;
- virtual void SetImageFeatures(size_t total_size, // In bytes.
- DecodedImageFormat format) = 0;
- virtual void OnDataDecoded(NSData* data) = 0;
-
- protected:
- friend class base::RefCountedThreadSafe<WebpDecoder::Delegate>;
- virtual ~Delegate() {}
- };
-
- explicit WebpDecoder(WebpDecoder::Delegate* delegate);
-
- // For tests.
- static size_t GetHeaderSize();
-
- // Main entry point.
- void OnDataReceived(const base::scoped_nsobject<NSData>& data);
-
- // Stops the decoding.
- void Stop();
-
- private:
- struct WebPIDecoderDeleter {
- inline void operator()(WebPIDecoder* ptr) const { WebPIDelete(ptr); }
- };
-
- enum State { READING_FEATURES, READING_DATA, DONE };
-
- friend class base::RefCountedThreadSafe<WebpDecoder>;
- virtual ~WebpDecoder();
-
- // Implements WebP image decoding state machine steps.
- void DoReadFeatures(NSData* data);
- void DoReadData(NSData* data);
- bool DoSendData();
-
- scoped_refptr<WebpDecoder::Delegate> delegate_;
- WebPDecoderConfig config_;
- WebpDecoder::State state_;
- std::unique_ptr<WebPIDecoder, WebPIDecoderDeleter> incremental_decoder_;
- base::scoped_nsobject<NSData> output_buffer_;
- base::scoped_nsobject<NSMutableData> features_;
- int has_alpha_;
-};
-
-} // namespace webp_transcode
-
-#endif // COMPONENTS_WEBP_TRANSCODE_WEBP_DECODER_H_
diff --git a/chromium/components/webp_transcode/webp_decoder.mm b/chromium/components/webp_transcode/webp_decoder.mm
deleted file mode 100644
index 38ae361e5d7..00000000000
--- a/chromium/components/webp_transcode/webp_decoder.mm
+++ /dev/null
@@ -1,252 +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 "components/webp_transcode/webp_decoder.h"
-
-#import <Foundation/Foundation.h>
-#include <stdint.h>
-#import <UIKit/UIKit.h>
-
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-
-namespace {
-
-const uint8_t kNumIfdEntries = 15;
-const unsigned int kExtraDataSize = 16;
-// 10b for signature/header + n * 12b entries + 4b for IFD terminator:
-const unsigned int kExtraDataOffset = 10 + 12 * kNumIfdEntries + 4;
-const unsigned int kHeaderSize = kExtraDataOffset + kExtraDataSize;
-const int kRecompressionThreshold = 64 * 64; // Threshold in pixels.
-const CGFloat kJpegQuality = 0.85;
-
-// Adapted from libwebp example dwebp.c.
-void PutLE16(uint8_t* const dst, uint32_t value) {
- dst[0] = (value >> 0) & 0xff;
- dst[1] = (value >> 8) & 0xff;
-}
-
-void PutLE32(uint8_t* const dst, uint32_t value) {
- PutLE16(dst + 0, (value >> 0) & 0xffff);
- PutLE16(dst + 2, (value >> 16) & 0xffff);
-}
-
-void WriteTiffHeader(uint8_t* dst,
- int width,
- int height,
- int bytes_per_px,
- bool has_alpha) {
- // For non-alpha case, we omit tag 0x152 (ExtraSamples).
- const uint8_t num_ifd_entries =
- has_alpha ? kNumIfdEntries : kNumIfdEntries - 1;
- uint8_t tiff_header[kHeaderSize] = {
- 0x49, 0x49, 0x2a, 0x00, // little endian signature
- 8, 0, 0, 0, // offset to the unique IFD that follows
- // IFD (offset = 8). Entries must be written in increasing tag order.
- num_ifd_entries, 0, // Number of entries in the IFD (12 bytes each).
- 0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 10: Width (TBD)
- 0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 22: Height (TBD)
- 0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0, // 34: BitsPerSample: 8888
- kExtraDataOffset + 0, 0, 0, 0,
- 0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 46: Compression: none
- 0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 58: Photometric: RGB
- 0x11, 0x01, 4, 0, 1, 0, 0, 0, // 70: Strips offset:
- kHeaderSize, 0, 0, 0, // data follows header
- 0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 82: Orientation: topleft
- 0x15, 0x01, 3, 0, 1, 0, 0, 0, // 94: SamplesPerPixels
- bytes_per_px, 0, 0, 0,
- 0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 106: Rows per strip (TBD)
- 0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 118: StripByteCount (TBD)
- 0x1a, 0x01, 5, 0, 1, 0, 0, 0, // 130: X-resolution
- kExtraDataOffset + 8, 0, 0, 0,
- 0x1b, 0x01, 5, 0, 1, 0, 0, 0, // 142: Y-resolution
- kExtraDataOffset + 8, 0, 0, 0,
- 0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration
- 0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
- 0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 178: ExtraSamples: rgbA
- 0, 0, 0, 0, // 190: IFD terminator
- // kExtraDataOffset:
- 8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample
- 72, 0, 0, 0, 1, 0, 0, 0 // 72 pixels/inch, for X/Y-resolution
- };
-
- // Fill placeholders in IFD:
- PutLE32(tiff_header + 10 + 8, width);
- PutLE32(tiff_header + 22 + 8, height);
- PutLE32(tiff_header + 106 + 8, height);
- PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height);
- if (!has_alpha)
- PutLE32(tiff_header + 178, 0);
-
- memcpy(dst, tiff_header, kHeaderSize);
-}
-
-} // namespace
-
-namespace webp_transcode {
-
-// static
-size_t WebpDecoder::GetHeaderSize() {
- return kHeaderSize;
-}
-
-WebpDecoder::WebpDecoder(WebpDecoder::Delegate* delegate)
- : delegate_(delegate), state_(READING_FEATURES), has_alpha_(0) {
- DCHECK(delegate_.get());
- const bool rv = WebPInitDecoderConfig(&config_);
- DCHECK(rv);
-}
-
-WebpDecoder::~WebpDecoder() {
- WebPFreeDecBuffer(&config_.output);
-}
-
-void WebpDecoder::OnDataReceived(const base::scoped_nsobject<NSData>& data) {
- DCHECK(data);
- switch (state_) {
- case READING_FEATURES:
- DoReadFeatures(data);
- break;
- case READING_DATA:
- DoReadData(data);
- break;
- case DONE:
- DLOG(WARNING) << "Received WebP data but decoding is finished. Ignoring.";
- break;
- }
-}
-
-void WebpDecoder::Stop() {
- if (state_ != DONE) {
- state_ = DONE;
- DLOG(WARNING) << "Unexpected end of WebP data.";
- delegate_->OnFinishedDecoding(false);
- }
-}
-
-void WebpDecoder::DoReadFeatures(NSData* data) {
- DCHECK_EQ(READING_FEATURES, state_);
- DCHECK(data);
- if (features_)
- [features_ appendData:data];
- else
- features_.reset([[NSMutableData alloc] initWithData:data]);
- VP8StatusCode status =
- WebPGetFeatures(static_cast<const uint8_t*>([features_ bytes]),
- [features_ length], &config_.input);
- switch (status) {
- case VP8_STATUS_OK: {
- has_alpha_ = config_.input.has_alpha;
- const uint32_t width = config_.input.width;
- const uint32_t height = config_.input.height;
- const size_t bytes_per_px = has_alpha_ ? 4 : 3;
- const int stride = bytes_per_px * width;
- const size_t image_data_size = stride * height;
- const size_t total_size = image_data_size + kHeaderSize;
- // Force pre-multiplied alpha.
- config_.output.colorspace = has_alpha_ ? MODE_rgbA : MODE_RGB;
- config_.output.u.RGBA.stride = stride;
- // Create the output buffer.
- config_.output.u.RGBA.size = image_data_size;
- uint8_t* dst = static_cast<uint8_t*>(malloc(total_size));
- if (!dst) {
- DLOG(ERROR) << "Could not allocate WebP decoding buffer (size = "
- << total_size << ").";
- delegate_->OnFinishedDecoding(false);
- state_ = DONE;
- break;
- }
- WriteTiffHeader(dst, width, height, bytes_per_px, has_alpha_);
- output_buffer_.reset([[NSData alloc] initWithBytesNoCopy:dst
- length:total_size
- freeWhenDone:YES]);
- config_.output.is_external_memory = 1;
- config_.output.u.RGBA.rgba = dst + kHeaderSize;
- // Start decoding.
- state_ = READING_DATA;
- incremental_decoder_.reset(WebPINewDecoder(&config_.output));
- DoReadData(features_);
- features_.reset();
- break;
- }
- case VP8_STATUS_NOT_ENOUGH_DATA:
- // Do nothing.
- break;
- default:
- DLOG(ERROR) << "Error in WebP image features.";
- delegate_->OnFinishedDecoding(false);
- state_ = DONE;
- break;
- }
-}
-
-void WebpDecoder::DoReadData(NSData* data) {
- DCHECK_EQ(READING_DATA, state_);
- DCHECK(incremental_decoder_);
- DCHECK(data);
- VP8StatusCode status =
- WebPIAppend(incremental_decoder_.get(),
- static_cast<const uint8_t*>([data bytes]), [data length]);
- switch (status) {
- case VP8_STATUS_SUSPENDED:
- // Do nothing: re-compression to JPEG or PNG cannot be done incrementally.
- // Wait for the whole image to be decoded.
- break;
- case VP8_STATUS_OK: {
- bool rv = DoSendData();
- DLOG_IF(ERROR, !rv) << "Error in WebP image conversion.";
- state_ = DONE;
- delegate_->OnFinishedDecoding(rv);
- break;
- }
- default:
- DLOG(ERROR) << "Error in WebP image decoding.";
- delegate_->OnFinishedDecoding(false);
- state_ = DONE;
- break;
- }
-}
-
-bool WebpDecoder::DoSendData() {
- DCHECK_EQ(READING_DATA, state_);
- int width, height;
- uint8_t* data_ptr = WebPIDecGetRGB(incremental_decoder_.get(), nullptr,
- &width, &height, nullptr);
- if (!data_ptr)
- return false;
- DCHECK_EQ(static_cast<const uint8_t*>([output_buffer_ bytes]) + kHeaderSize,
- data_ptr);
- base::scoped_nsobject<NSData> result_data;
- // When the WebP image is larger than |kRecompressionThreshold| it is
- // compressed to JPEG or PNG. Otherwise, the uncompressed TIFF is used.
- DecodedImageFormat format = TIFF;
- if (width * height > kRecompressionThreshold) {
- base::scoped_nsobject<UIImage> tiff_image(
- [[UIImage alloc] initWithData:output_buffer_]);
- if (!tiff_image)
- return false;
- // Compress to PNG if the image is transparent, JPEG otherwise.
- // TODO(droger): Use PNG instead of JPEG if the WebP image is lossless.
- if (has_alpha_) {
- result_data.reset([UIImagePNGRepresentation(tiff_image) retain]);
- format = PNG;
- } else {
- result_data.reset(
- [UIImageJPEGRepresentation(tiff_image, kJpegQuality) retain]);
- format = JPEG;
- }
- if (!result_data)
- return false;
- } else {
- result_data.reset([output_buffer_ retain]);
- }
- UMA_HISTOGRAM_ENUMERATION("WebP.DecodedImageFormat", format,
- DECODED_FORMAT_COUNT);
- delegate_->SetImageFeatures([result_data length], format);
- delegate_->OnDataDecoded(result_data);
- output_buffer_.reset();
- return true;
-}
-
-} // namespace webp_transcode
diff --git a/chromium/components/webp_transcode/webp_decoder_unittest.mm b/chromium/components/webp_transcode/webp_decoder_unittest.mm
deleted file mode 100644
index 5a82d068796..00000000000
--- a/chromium/components/webp_transcode/webp_decoder_unittest.mm
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright 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 "components/webp_transcode/webp_decoder.h"
-
-#import <CoreGraphics/CoreGraphics.h>
-#import <Foundation/Foundation.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/base_paths.h"
-#include "base/files/file_path.h"
-#include "base/ios/ios_util.h"
-#include "base/logging.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/path_service.h"
-#include "base/strings/sys_string_conversions.h"
-#include "build/build_config.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace webp_transcode {
-namespace {
-
-class WebpDecoderDelegate : public WebpDecoder::Delegate {
- public:
- WebpDecoderDelegate() : image_([[NSMutableData alloc] init]) {}
-
- NSData* GetImage() const { return image_; }
-
- // WebpDecoder::Delegate methods.
- MOCK_METHOD1(OnFinishedDecoding, void(bool success));
- MOCK_METHOD2(SetImageFeatures,
- void(size_t total_size, WebpDecoder::DecodedImageFormat format));
- void OnDataDecoded(NSData* data) override { [image_ appendData:data]; }
-
- private:
- virtual ~WebpDecoderDelegate() {}
-
- base::scoped_nsobject<NSMutableData> image_;
-};
-
-class WebpDecoderTest : public testing::Test {
- public:
- WebpDecoderTest()
- : delegate_(new WebpDecoderDelegate),
- decoder_(new WebpDecoder(delegate_.get())) {}
-
- NSData* LoadImage(const base::FilePath& filename) {
- base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
- path = path.AppendASCII("components/test/data/webp_transcode")
- .Append(filename);
- return
- [NSData dataWithContentsOfFile:base::SysUTF8ToNSString(path.value())];
- }
-
- std::vector<uint8_t>* DecompressData(NSData* data,
- WebpDecoder::DecodedImageFormat format) {
- base::ScopedCFTypeRef<CGDataProviderRef> provider(
- CGDataProviderCreateWithCFData((CFDataRef)data));
- base::ScopedCFTypeRef<CGImageRef> image;
- switch (format) {
- case WebpDecoder::JPEG:
- image.reset(CGImageCreateWithJPEGDataProvider(
- provider, nullptr, false, kCGRenderingIntentDefault));
- break;
- case WebpDecoder::PNG:
- image.reset(CGImageCreateWithPNGDataProvider(
- provider, nullptr, false, kCGRenderingIntentDefault));
- break;
- case WebpDecoder::TIFF:
- ADD_FAILURE() << "Data already decompressed";
- return nil;
- case WebpDecoder::DECODED_FORMAT_COUNT:
- ADD_FAILURE() << "Unknown format";
- return nil;
- }
- size_t width = CGImageGetWidth(image);
- size_t height = CGImageGetHeight(image);
- base::ScopedCFTypeRef<CGColorSpaceRef> color_space(
- CGColorSpaceCreateDeviceRGB());
- size_t bytes_per_pixel = 4;
- size_t bytes_per_row = bytes_per_pixel * width;
- size_t bits_per_component = 8;
- std::vector<uint8_t>* result =
- new std::vector<uint8_t>(width * height * bytes_per_pixel, 0);
- base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate(
- &result->front(), width, height, bits_per_component, bytes_per_row,
- color_space, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big));
- CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
- // Check that someting has been written in |result|.
- std::vector<uint8_t> zeroes(width * height * bytes_per_pixel, 0);
- EXPECT_NE(0, memcmp(&result->front(), &zeroes.front(), zeroes.size()))
- << "Decompression failed.";
- return result;
- }
-
- // Compares data, allowing an averaged absolute difference of 1.
- bool CompareUncompressedData(const uint8_t* ptr_1,
- const uint8_t* ptr_2,
- size_t size) {
- uint64_t difference = 0;
- for (size_t i = 0; i < size; ++i) {
- // Casting to int to avoid overflow.
- int error = abs(int(ptr_1[i]) - int(ptr_2[i]));
- EXPECT_GE(difference + error, difference)
- << "Image difference too big (overflow).";
- difference += error;
- }
- double average_difference = double(difference) / double(size);
- DLOG(INFO) << "Average image difference: " << average_difference;
- return average_difference < 1.5;
- }
-
- bool CheckCompressedImagesEqual(NSData* data_1,
- NSData* data_2,
- WebpDecoder::DecodedImageFormat format) {
- std::unique_ptr<std::vector<uint8_t>> uncompressed_1(
- DecompressData(data_1, format));
- std::unique_ptr<std::vector<uint8_t>> uncompressed_2(
- DecompressData(data_2, format));
- if (uncompressed_1->size() != uncompressed_2->size()) {
- DLOG(ERROR) << "Image sizes don't match";
- return false;
- }
- return CompareUncompressedData(&uncompressed_1->front(),
- &uncompressed_2->front(),
- uncompressed_1->size());
- }
-
- bool CheckTiffImagesEqual(NSData* image_1, NSData* image_2) {
- if ([image_1 length] != [image_2 length]) {
- DLOG(ERROR) << "Image lengths don't match";
- return false;
- }
- // Compare headers.
- const size_t kHeaderSize = WebpDecoder::GetHeaderSize();
- NSData* header_1 = [image_1 subdataWithRange:NSMakeRange(0, kHeaderSize)];
- NSData* header_2 = [image_2 subdataWithRange:NSMakeRange(0, kHeaderSize)];
- if (!header_1 || !header_2)
- return false;
- if (![header_1 isEqualToData:header_2]) {
- DLOG(ERROR) << "Headers don't match.";
- return false;
- }
- return CompareUncompressedData(
- static_cast<const uint8_t*>([image_1 bytes]) + kHeaderSize,
- static_cast<const uint8_t*>([image_2 bytes]) + kHeaderSize,
- [image_1 length] - kHeaderSize);
- }
-
- protected:
- scoped_refptr<WebpDecoderDelegate> delegate_;
- scoped_refptr<WebpDecoder> decoder_;
-};
-
-} // namespace
-
-TEST_F(WebpDecoderTest, DecodeToJpeg) {
-// TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
-#if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
- if (base::ios::IsRunningOnIOS9OrLater())
- return;
-#endif
- // Load a WebP image from disk.
- base::scoped_nsobject<NSData> webp_image(
- [LoadImage(base::FilePath("test.webp")) retain]);
- ASSERT_TRUE(webp_image != nil);
- // Load reference image.
- base::scoped_nsobject<NSData> jpg_image(
- [LoadImage(base::FilePath("test.jpg")) retain]);
- ASSERT_TRUE(jpg_image != nil);
- // Convert to JPEG.
- EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
- EXPECT_CALL(*delegate_, SetImageFeatures(testing::_, WebpDecoder::JPEG))
- .Times(1);
- decoder_->OnDataReceived(webp_image);
- // Compare to reference image.
- EXPECT_TRUE(CheckCompressedImagesEqual(jpg_image, delegate_->GetImage(),
- WebpDecoder::JPEG));
-}
-
-TEST_F(WebpDecoderTest, DecodeToPng) {
-// TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
-#if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
- if (base::ios::IsRunningOnIOS9OrLater())
- return;
-#endif
- // Load a WebP image from disk.
- base::scoped_nsobject<NSData> webp_image(
- [LoadImage(base::FilePath("test_alpha.webp")) retain]);
- ASSERT_TRUE(webp_image != nil);
- // Load reference image.
- base::scoped_nsobject<NSData> png_image(
- [LoadImage(base::FilePath("test_alpha.png")) retain]);
- ASSERT_TRUE(png_image != nil);
- // Convert to PNG.
- EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
- EXPECT_CALL(*delegate_, SetImageFeatures(testing::_, WebpDecoder::PNG))
- .Times(1);
- decoder_->OnDataReceived(webp_image);
- // Compare to reference image.
- EXPECT_TRUE(CheckCompressedImagesEqual(png_image, delegate_->GetImage(),
- WebpDecoder::PNG));
-}
-
-TEST_F(WebpDecoderTest, DecodeToTiff) {
-// TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
-#if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
- if (base::ios::IsRunningOnIOS9OrLater())
- return;
-#endif
- // Load a WebP image from disk.
- base::scoped_nsobject<NSData> webp_image(
- [LoadImage(base::FilePath("test_small.webp")) retain]);
- ASSERT_TRUE(webp_image != nil);
- // Load reference image.
- base::scoped_nsobject<NSData> tiff_image(
- [LoadImage(base::FilePath("test_small.tiff")) retain]);
- ASSERT_TRUE(tiff_image != nil);
- // Convert to TIFF.
- EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
- EXPECT_CALL(*delegate_, SetImageFeatures([tiff_image length],
- WebpDecoder::TIFF)).Times(1);
- decoder_->OnDataReceived(webp_image);
- // Compare to reference image.
- EXPECT_TRUE(CheckTiffImagesEqual(tiff_image, delegate_->GetImage()));
-}
-
-TEST_F(WebpDecoderTest, StreamedDecode) {
-// TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
-#if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
- if (base::ios::IsRunningOnIOS9OrLater())
- return;
-#endif
- // Load a WebP image from disk.
- base::scoped_nsobject<NSData> webp_image(
- [LoadImage(base::FilePath("test.webp")) retain]);
- ASSERT_TRUE(webp_image != nil);
- // Load reference image.
- base::scoped_nsobject<NSData> jpg_image(
- [LoadImage(base::FilePath("test.jpg")) retain]);
- ASSERT_TRUE(jpg_image != nil);
- // Convert to JPEG in chunks.
- EXPECT_CALL(*delegate_, OnFinishedDecoding(true)).Times(1);
- EXPECT_CALL(*delegate_, SetImageFeatures(testing::_, WebpDecoder::JPEG))
- .Times(1);
- const size_t kChunkSize = 10;
- unsigned int num_chunks = 0;
- while ([webp_image length] > kChunkSize) {
- base::scoped_nsobject<NSData> chunk(
- [[webp_image subdataWithRange:NSMakeRange(0, kChunkSize)] retain]);
- decoder_->OnDataReceived(chunk);
- webp_image.reset([[webp_image
- subdataWithRange:NSMakeRange(kChunkSize, [webp_image length] -
- kChunkSize)] retain]);
- ++num_chunks;
- }
- if ([webp_image length] > 0u) {
- decoder_->OnDataReceived(webp_image);
- ++num_chunks;
- }
- ASSERT_GT(num_chunks, 3u) << "Not enough chunks";
- // Compare to reference image.
- EXPECT_TRUE(CheckCompressedImagesEqual(jpg_image, delegate_->GetImage(),
- WebpDecoder::JPEG));
-}
-
-TEST_F(WebpDecoderTest, InvalidFormat) {
- EXPECT_CALL(*delegate_, OnFinishedDecoding(false)).Times(1);
- const char dummy_image[] = "(>'-')> <('-'<) ^('-')^ <('-'<) (>'-')>";
- base::scoped_nsobject<NSData> data(
- [[NSData alloc] initWithBytes:dummy_image length:arraysize(dummy_image)]);
- decoder_->OnDataReceived(data);
- EXPECT_EQ(0u, [delegate_->GetImage() length]);
-}
-
-TEST_F(WebpDecoderTest, DecodeAborted) {
- EXPECT_CALL(*delegate_, OnFinishedDecoding(false)).Times(1);
- decoder_->Stop();
- EXPECT_EQ(0u, [delegate_->GetImage() length]);
-}
-
-} // namespace webp_transcode
diff --git a/chromium/components/webusb.gypi b/chromium/components/webusb.gypi
deleted file mode 100644
index caf6c92064a..00000000000
--- a/chromium/components/webusb.gypi
+++ /dev/null
@@ -1,25 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'webusb',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../device/core/core.gyp:device_core',
- '../device/usb/usb.gyp:device_usb',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'webusb/webusb_browser_client.h',
- 'webusb/webusb_detector.cc',
- 'webusb/webusb_detector.h',
- ],
- },
- ],
-}
diff --git a/chromium/components/webusb/BUILD.gn b/chromium/components/webusb/BUILD.gn
deleted file mode 100644
index 44afe3d2fe3..00000000000
--- a/chromium/components/webusb/BUILD.gn
+++ /dev/null
@@ -1,38 +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.
-
-source_set("webusb") {
- sources = [
- "webusb_browser_client.h",
- "webusb_detector.cc",
- "webusb_detector.h",
- ]
-
- public_deps = [
- "//base",
- "//device/usb",
- ]
- deps = [
- "//device/core",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "webusb_detector_unittest.cc",
- ]
-
- deps = [
- ":webusb",
- "//base",
- "//device/core",
- "//device/core:mocks",
- "//device/usb",
- "//device/usb:test_support",
- "//testing/gmock",
- "//testing/gtest",
- "//url",
- ]
-}
diff --git a/chromium/components/webusb/DEPS b/chromium/components/webusb/DEPS
deleted file mode 100644
index 49984a9389d..00000000000
--- a/chromium/components/webusb/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
- "+base",
- "+device/core",
- "+device/usb",
-]
diff --git a/chromium/components/webusb/OWNERS b/chromium/components/webusb/OWNERS
deleted file mode 100644
index 4f346dec4da..00000000000
--- a/chromium/components/webusb/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-juncai@chromium.org
-reillyg@chromium.org
-rockot@chromium.org
diff --git a/chromium/components/webusb/webusb_browser_client.h b/chromium/components/webusb/webusb_browser_client.h
deleted file mode 100644
index a576f10d4f8..00000000000
--- a/chromium/components/webusb/webusb_browser_client.h
+++ /dev/null
@@ -1,31 +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 COMPONENTS_WEBUSB_WEBUSB_BROWSER_CLIENT_H_
-#define COMPONENTS_WEBUSB_WEBUSB_BROWSER_CLIENT_H_
-
-#include <string>
-
-#include "base/strings/string16.h"
-
-class GURL;
-
-namespace webusb {
-
-// Interface to allow the webusb module to make browser-process-specific
-// calls.
-class WebUsbBrowserClient {
- public:
- virtual ~WebUsbBrowserClient() {}
-
- virtual void OnDeviceAdded(const base::string16& product_name,
- const GURL& landing_page,
- const std::string& notification_id) = 0;
-
- virtual void OnDeviceRemoved(const std::string& notification_id) = 0;
-};
-
-} // namespace webusb
-
-#endif // COMPONENTS_WEBUSB_WEBUSB_BROWSER_CLIENT_H_
diff --git a/chromium/components/webusb/webusb_detector.cc b/chromium/components/webusb/webusb_detector.cc
deleted file mode 100644
index 2ac3522c2c7..00000000000
--- a/chromium/components/webusb/webusb_detector.cc
+++ /dev/null
@@ -1,56 +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 "components/webusb/webusb_detector.h"
-
-#include "components/webusb/webusb_browser_client.h"
-#include "device/core/device_client.h"
-#include "device/usb/usb_device.h"
-#include "device/usb/usb_ids.h"
-
-namespace webusb {
-
-WebUsbDetector::WebUsbDetector(WebUsbBrowserClient* webusb_browser_client)
- : webusb_browser_client_(webusb_browser_client), observer_(this) {
- Initialize();
-}
-
-WebUsbDetector::~WebUsbDetector() {}
-
-void WebUsbDetector::Initialize() {
- if (!webusb_browser_client_) {
- return;
- }
-
- device::UsbService* usb_service =
- device::DeviceClient::Get()->GetUsbService();
- if (!usb_service)
- return;
-
- observer_.Add(usb_service);
-}
-
-void WebUsbDetector::OnDeviceAdded(scoped_refptr<device::UsbDevice> device) {
- const base::string16& product_name = device->product_string();
- if (product_name.empty()) {
- return;
- }
-
- const GURL& landing_page = device->webusb_landing_page();
- if (!landing_page.is_valid()) {
- return;
- }
-
- std::string notification_id = device->guid();
-
- webusb_browser_client_->OnDeviceAdded(product_name, landing_page,
- notification_id);
-}
-
-void WebUsbDetector::OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) {
- std::string notification_id = device->guid();
- webusb_browser_client_->OnDeviceRemoved(notification_id);
-}
-
-} // namespace webusb
diff --git a/chromium/components/webusb/webusb_detector.h b/chromium/components/webusb/webusb_detector.h
deleted file mode 100644
index cbf5a62ebf6..00000000000
--- a/chromium/components/webusb/webusb_detector.h
+++ /dev/null
@@ -1,46 +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 COMPONENTS_WEBUSB_WEBUSB_DETECTOR_H_
-#define COMPONENTS_WEBUSB_WEBUSB_DETECTOR_H_
-
-#include "base/macros.h"
-#include "base/scoped_observer.h"
-#include "device/usb/usb_service.h"
-
-namespace device {
-class UsbDevice;
-}
-
-namespace webusb {
-
-class UsbDevice;
-class WebUsbBrowserClient;
-
-class WebUsbDetector : public device::UsbService::Observer {
- public:
- explicit WebUsbDetector(WebUsbBrowserClient* webusb_browser_client);
-
- ~WebUsbDetector() override;
-
- private:
- // Initializes the WebUsbDetector.
- void Initialize();
-
- // UsbService::observer override:
- void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override;
-
- // UsbService::observer override:
- void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override;
-
- WebUsbBrowserClient* webusb_browser_client_ = nullptr;
-
- ScopedObserver<device::UsbService, device::UsbService::Observer> observer_;
-
- DISALLOW_COPY_AND_ASSIGN(WebUsbDetector);
-};
-
-} // namespace webusb
-
-#endif // COMPONENTS_WEBUSB_WEBUSB_DETECTOR_H_
diff --git a/chromium/components/webusb/webusb_detector_unittest.cc b/chromium/components/webusb/webusb_detector_unittest.cc
deleted file mode 100644
index eebede8a307..00000000000
--- a/chromium/components/webusb/webusb_detector_unittest.cc
+++ /dev/null
@@ -1,445 +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 "components/webusb/webusb_detector.h"
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/webusb/webusb_browser_client.h"
-#include "device/core/mock_device_client.h"
-#include "device/usb/mock_usb_device.h"
-#include "device/usb/mock_usb_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace {
-
-// usb device product name
-const char* kProductName_1 = "Google Product A";
-const char* kProductName_2 = "Google Product B";
-const char* kProductName_3 = "Google Product C";
-
-// usb device landing page
-const char* kLandingPage_1 = "https://www.google.com/A";
-const char* kLandingPage_2 = "https://www.google.com/B";
-const char* kLandingPage_3 = "https://www.google.com/C";
-
-} // namespace
-
-namespace webusb {
-
-namespace {
-
-class MockWebUsbBrowserClient : public webusb::WebUsbBrowserClient {
- public:
- MockWebUsbBrowserClient() {}
-
- ~MockWebUsbBrowserClient() override {}
-
- // webusb::WebUsbBrowserClient implementation
- MOCK_METHOD3(OnDeviceAdded,
- void(const base::string16& product_name,
- const GURL& landing_page,
- const std::string& notification_id));
-
- // webusb::WebUsbBrowserClient implementation
- MOCK_METHOD1(OnDeviceRemoved, void(const std::string& notification_id));
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockWebUsbBrowserClient);
-};
-
-} // namespace
-
-class WebUsbDetectorTest : public testing::Test {
- public:
- WebUsbDetectorTest() {}
-
- ~WebUsbDetectorTest() override = default;
-
- protected:
- device::MockDeviceClient device_client_;
- MockWebUsbBrowserClient mock_webusb_browser_client_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WebUsbDetectorTest);
-};
-
-TEST_F(WebUsbDetectorTest, UsbDeviceAdded) {
- base::string16 product_name = base::UTF8ToUTF16(kProductName_1);
- GURL landing_page(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page));
- std::string guid = device->guid();
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name, landing_page, guid))
- .Times(1);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(testing::_))
- .Times(0);
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-
- device_client_.usb_service()->AddDevice(device);
-}
-
-TEST_F(WebUsbDetectorTest, UsbDeviceAddedAndRemoved) {
- base::string16 product_name = base::UTF8ToUTF16(kProductName_1);
- GURL landing_page(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page));
- std::string guid = device->guid();
-
- {
- testing::InSequence s;
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name, landing_page, guid))
- .Times(1);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid)).Times(1);
- }
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-
- device_client_.usb_service()->AddDevice(device);
- device_client_.usb_service()->RemoveDevice(device);
-}
-
-TEST_F(WebUsbDetectorTest, UsbDeviceWithoutProductNameAddedAndRemoved) {
- std::string product_name = "";
- GURL landing_page(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device(new device::MockUsbDevice(
- 0, 1, "Google", product_name, "002", landing_page));
- std::string guid = device->guid();
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(testing::_, testing::_, testing::_))
- .Times(0);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid)).Times(1);
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-
- device_client_.usb_service()->AddDevice(device);
- device_client_.usb_service()->RemoveDevice(device);
-}
-
-TEST_F(WebUsbDetectorTest, UsbDeviceWithoutLandingPageAddedAndRemoved) {
- GURL landing_page("");
- scoped_refptr<device::MockUsbDevice> device(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page));
- std::string guid = device->guid();
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(testing::_, testing::_, testing::_))
- .Times(0);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid)).Times(1);
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-
- device_client_.usb_service()->AddDevice(device);
- device_client_.usb_service()->RemoveDevice(device);
-}
-
-TEST_F(WebUsbDetectorTest, WebUsbBrowserClientIsNullptr) {
- GURL landing_page(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page));
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(testing::_, testing::_, testing::_))
- .Times(0);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(testing::_))
- .Times(0);
-
- webusb::WebUsbDetector webusb_detector(nullptr);
-
- device_client_.usb_service()->AddDevice(device);
- device_client_.usb_service()->RemoveDevice(device);
-}
-
-TEST_F(WebUsbDetectorTest, NoUsbService) {
- GURL landing_page(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page));
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(testing::_, testing::_, testing::_))
- .Times(0);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(testing::_))
- .Times(0);
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-}
-
-TEST_F(WebUsbDetectorTest, UsbDeviceWasThereBeforeAndThenRemoved) {
- GURL landing_page(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page));
- std::string guid = device->guid();
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(testing::_, testing::_, testing::_))
- .Times(0);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid)).Times(1);
-
- // usb device was added before webusb_detector was created
- device_client_.usb_service()->AddDevice(device);
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-
- device_client_.usb_service()->RemoveDevice(device);
-}
-
-TEST_F(
- WebUsbDetectorTest,
- ThreeUsbDevicesWereThereBeforeAndThenRemovedBeforeWebUsbDetectorWasCreated) {
- base::string16 product_name_1 = base::UTF8ToUTF16(kProductName_1);
- GURL landing_page_1(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device_1(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page_1));
- std::string guid_1 = device_1->guid();
-
- base::string16 product_name_2 = base::UTF8ToUTF16(kProductName_2);
- GURL landing_page_2(kLandingPage_2);
- scoped_refptr<device::MockUsbDevice> device_2(new device::MockUsbDevice(
- 3, 4, "Google", kProductName_2, "005", landing_page_2));
- std::string guid_2 = device_2->guid();
-
- base::string16 product_name_3 = base::UTF8ToUTF16(kProductName_3);
- GURL landing_page_3(kLandingPage_3);
- scoped_refptr<device::MockUsbDevice> device_3(new device::MockUsbDevice(
- 6, 7, "Google", kProductName_3, "008", landing_page_3));
- std::string guid_3 = device_3->guid();
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_1, landing_page_1, guid_1))
- .Times(0);
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_2, landing_page_2, guid_2))
- .Times(0);
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_3, landing_page_3, guid_3))
- .Times(0);
-
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_1)).Times(0);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_2)).Times(0);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_3)).Times(0);
-
- // three usb devices were added and removed before webusb_detector was
- // created
- device_client_.usb_service()->AddDevice(device_1);
- device_client_.usb_service()->AddDevice(device_2);
- device_client_.usb_service()->AddDevice(device_3);
-
- device_client_.usb_service()->RemoveDevice(device_1);
- device_client_.usb_service()->RemoveDevice(device_2);
- device_client_.usb_service()->RemoveDevice(device_3);
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-}
-
-TEST_F(
- WebUsbDetectorTest,
- ThreeUsbDevicesWereThereBeforeAndThenRemovedAfterWebUsbDetectorWasCreated) {
- base::string16 product_name_1 = base::UTF8ToUTF16(kProductName_1);
- GURL landing_page_1(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device_1(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page_1));
- std::string guid_1 = device_1->guid();
-
- base::string16 product_name_2 = base::UTF8ToUTF16(kProductName_2);
- GURL landing_page_2(kLandingPage_2);
- scoped_refptr<device::MockUsbDevice> device_2(new device::MockUsbDevice(
- 3, 4, "Google", kProductName_2, "005", landing_page_2));
- std::string guid_2 = device_2->guid();
-
- base::string16 product_name_3 = base::UTF8ToUTF16(kProductName_3);
- GURL landing_page_3(kLandingPage_3);
- scoped_refptr<device::MockUsbDevice> device_3(new device::MockUsbDevice(
- 6, 7, "Google", kProductName_3, "008", landing_page_3));
- std::string guid_3 = device_3->guid();
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_1, landing_page_1, guid_1))
- .Times(0);
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_2, landing_page_2, guid_2))
- .Times(0);
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_3, landing_page_3, guid_3))
- .Times(0);
-
- {
- testing::InSequence s;
-
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_1)).Times(1);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_2)).Times(1);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_3)).Times(1);
- }
-
- // three usb devices were added before webusb_detector was created
- device_client_.usb_service()->AddDevice(device_1);
- device_client_.usb_service()->AddDevice(device_2);
- device_client_.usb_service()->AddDevice(device_3);
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-
- device_client_.usb_service()->RemoveDevice(device_1);
- device_client_.usb_service()->RemoveDevice(device_2);
- device_client_.usb_service()->RemoveDevice(device_3);
-}
-
-TEST_F(WebUsbDetectorTest,
- TwoUsbDevicesWereThereBeforeAndThenRemovedAndNewUsbDeviceAdded) {
- base::string16 product_name_1 = base::UTF8ToUTF16(kProductName_1);
- GURL landing_page_1(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device_1(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page_1));
- std::string guid_1 = device_1->guid();
-
- base::string16 product_name_2 = base::UTF8ToUTF16(kProductName_2);
- GURL landing_page_2(kLandingPage_2);
- scoped_refptr<device::MockUsbDevice> device_2(new device::MockUsbDevice(
- 3, 4, "Google", kProductName_2, "005", landing_page_2));
- std::string guid_2 = device_2->guid();
-
- base::string16 product_name_3 = base::UTF8ToUTF16(kProductName_3);
- GURL landing_page_3(kLandingPage_3);
- scoped_refptr<device::MockUsbDevice> device_3(new device::MockUsbDevice(
- 6, 7, "Google", kProductName_3, "008", landing_page_3));
- std::string guid_3 = device_3->guid();
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_1, landing_page_1, guid_1))
- .Times(0);
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_3, landing_page_3, guid_3))
- .Times(0);
-
- {
- testing::InSequence s;
-
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_1)).Times(1);
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_2, landing_page_2, guid_2))
- .Times(1);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_3)).Times(1);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_2)).Times(1);
- }
-
- // two usb devices were added before webusb_detector was created
- device_client_.usb_service()->AddDevice(device_1);
- device_client_.usb_service()->AddDevice(device_3);
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-
- device_client_.usb_service()->RemoveDevice(device_1);
- device_client_.usb_service()->AddDevice(device_2);
- device_client_.usb_service()->RemoveDevice(device_3);
- device_client_.usb_service()->RemoveDevice(device_2);
-}
-
-TEST_F(WebUsbDetectorTest, ThreeUsbDevicesAddedAndRemoved) {
- base::string16 product_name_1 = base::UTF8ToUTF16(kProductName_1);
- GURL landing_page_1(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device_1(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page_1));
- std::string guid_1 = device_1->guid();
-
- base::string16 product_name_2 = base::UTF8ToUTF16(kProductName_2);
- GURL landing_page_2(kLandingPage_2);
- scoped_refptr<device::MockUsbDevice> device_2(new device::MockUsbDevice(
- 3, 4, "Google", kProductName_2, "005", landing_page_2));
- std::string guid_2 = device_2->guid();
-
- base::string16 product_name_3 = base::UTF8ToUTF16(kProductName_3);
- GURL landing_page_3(kLandingPage_3);
- scoped_refptr<device::MockUsbDevice> device_3(new device::MockUsbDevice(
- 6, 7, "Google", kProductName_3, "008", landing_page_3));
- std::string guid_3 = device_3->guid();
-
- {
- testing::InSequence s;
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_1, landing_page_1, guid_1))
- .Times(1);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_1)).Times(1);
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_2, landing_page_2, guid_2))
- .Times(1);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_2)).Times(1);
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_3, landing_page_3, guid_3))
- .Times(1);
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_3)).Times(1);
- }
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-
- device_client_.usb_service()->AddDevice(device_1);
- device_client_.usb_service()->RemoveDevice(device_1);
- device_client_.usb_service()->AddDevice(device_2);
- device_client_.usb_service()->RemoveDevice(device_2);
- device_client_.usb_service()->AddDevice(device_3);
- device_client_.usb_service()->RemoveDevice(device_3);
-}
-
-TEST_F(WebUsbDetectorTest, ThreeUsbDeviceAddedAndRemovedDifferentOrder) {
- base::string16 product_name_1 = base::UTF8ToUTF16(kProductName_1);
- GURL landing_page_1(kLandingPage_1);
- scoped_refptr<device::MockUsbDevice> device_1(new device::MockUsbDevice(
- 0, 1, "Google", kProductName_1, "002", landing_page_1));
- std::string guid_1 = device_1->guid();
-
- base::string16 product_name_2 = base::UTF8ToUTF16(kProductName_2);
- GURL landing_page_2(kLandingPage_2);
- scoped_refptr<device::MockUsbDevice> device_2(new device::MockUsbDevice(
- 3, 4, "Google", kProductName_2, "005", landing_page_2));
- std::string guid_2 = device_2->guid();
-
- base::string16 product_name_3 = base::UTF8ToUTF16(kProductName_3);
- GURL landing_page_3(kLandingPage_3);
- scoped_refptr<device::MockUsbDevice> device_3(new device::MockUsbDevice(
- 6, 7, "Google", kProductName_3, "008", landing_page_3));
- std::string guid_3 = device_3->guid();
-
- {
- testing::InSequence s;
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_1, landing_page_1, guid_1))
- .Times(1);
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_2, landing_page_2, guid_2))
- .Times(1);
-
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_2)).Times(1);
-
- EXPECT_CALL(mock_webusb_browser_client_,
- OnDeviceAdded(product_name_3, landing_page_3, guid_3))
- .Times(1);
-
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_1)).Times(1);
-
- EXPECT_CALL(mock_webusb_browser_client_, OnDeviceRemoved(guid_3)).Times(1);
- }
-
- webusb::WebUsbDetector webusb_detector(&mock_webusb_browser_client_);
-
- device_client_.usb_service()->AddDevice(device_1);
- device_client_.usb_service()->AddDevice(device_2);
- device_client_.usb_service()->RemoveDevice(device_2);
- device_client_.usb_service()->AddDevice(device_3);
- device_client_.usb_service()->RemoveDevice(device_1);
- device_client_.usb_service()->RemoveDevice(device_3);
-}
-
-} // namespace webusb
diff --git a/chromium/components/wifi.gypi b/chromium/components/wifi.gypi
deleted file mode 100644
index 3d712152cef..00000000000
--- a/chromium/components/wifi.gypi
+++ /dev/null
@@ -1,81 +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.
-
-{
- 'targets': [
- {
- 'target_name': 'wifi_component',
- 'type': '<(component)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../crypto/crypto.gyp:crypto',
- '../third_party/libxml/libxml.gyp:libxml',
- 'onc_component',
- ],
- 'include_dirs': [
- '..',
- ],
- 'defines': [
- 'WIFI_IMPLEMENTATION',
- ],
- 'sources': [
- 'wifi/network_properties.cc',
- 'wifi/network_properties.h',
- 'wifi/wifi_export.h',
- 'wifi/wifi_service.cc',
- 'wifi/wifi_service.h',
- 'wifi/wifi_service_mac.mm',
- 'wifi/wifi_service_win.cc',
- ],
- 'conditions': [
- ['OS == "win"', {
- 'link_settings': {
- 'libraries': [
- '-liphlpapi.lib',
- ],
- },
- }],
- ['OS == "mac"', {
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/CoreWLAN.framework',
- '$(SDKROOT)/System/Library/Frameworks/SystemConfiguration.framework',
- ]
- },
- }],
- ],
- },
- {
- 'target_name': 'wifi_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- 'onc_component',
- 'wifi_component',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'wifi/fake_wifi_service.cc',
- 'wifi/fake_wifi_service.h',
- ],
- },
- {
- 'target_name': 'wifi_test',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'onc_component',
- 'wifi_component',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- 'wifi/wifi_test.cc',
- ],
- },
- ],
-}
diff --git a/chromium/components/wifi/BUILD.gn b/chromium/components/wifi/BUILD.gn
index 7cd31469401..878e1f69cdb 100644
--- a/chromium/components/wifi/BUILD.gn
+++ b/chromium/components/wifi/BUILD.gn
@@ -35,7 +35,7 @@ component("wifi") {
}
}
-source_set("test_support") {
+static_library("test_support") {
sources = [
"fake_wifi_service.cc",
"fake_wifi_service.h",
diff --git a/chromium/components/wifi_sync.gypi b/chromium/components/wifi_sync.gypi
deleted file mode 100644
index ad3d6fde60e..00000000000
--- a/chromium/components/wifi_sync.gypi
+++ /dev/null
@@ -1,34 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/wifi_sync
- 'target_name': 'wifi_sync',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../components/components.gyp:onc_component',
- '../sync/sync.gyp:sync',
- ],
- 'sources': [
- 'wifi_sync/network_state_helper_chromeos.cc',
- 'wifi_sync/network_state_helper_chromeos.h',
- 'wifi_sync/wifi_config_delegate.h',
- 'wifi_sync/wifi_config_delegate_chromeos.cc',
- 'wifi_sync/wifi_config_delegate_chromeos.h',
- 'wifi_sync/wifi_credential.cc',
- 'wifi_sync/wifi_credential.h',
- 'wifi_sync/wifi_credential_syncable_service.cc',
- 'wifi_sync/wifi_credential_syncable_service.h',
- 'wifi_sync/wifi_credential_syncable_service_factory.cc',
- 'wifi_sync/wifi_credential_syncable_service_factory.h',
- 'wifi_sync/wifi_security_class.cc',
- 'wifi_sync/wifi_security_class.h',
- 'wifi_sync/wifi_security_class_chromeos.cc',
- ],
- },
- ],
-}
diff --git a/chromium/components/wifi_sync/BUILD.gn b/chromium/components/wifi_sync/BUILD.gn
index 72ac120899b..c70b793edbe 100644
--- a/chromium/components/wifi_sync/BUILD.gn
+++ b/chromium/components/wifi_sync/BUILD.gn
@@ -26,8 +26,8 @@ source_set("wifi_sync") {
"//components/keyed_service/content",
"//components/keyed_service/core",
"//components/onc",
+ "//components/sync",
"//content/public/browser",
- "//sync",
]
if (is_chromeos) {
@@ -51,7 +51,7 @@ source_set("unit_tests") {
"//base",
"//chromeos",
"//components/onc",
- "//sync:test_support_sync_api",
+ "//components/sync:test_support_sync_api",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/components/wifi_sync/DEPS b/chromium/components/wifi_sync/DEPS
index 54fb2831a03..9b1111c30f5 100644
--- a/chromium/components/wifi_sync/DEPS
+++ b/chromium/components/wifi_sync/DEPS
@@ -5,9 +5,9 @@ include_rules = [
"+components/keyed_service/content",
"+components/keyed_service/core",
"+components/onc",
+ "+components/sync/api",
+ "+components/sync/core/attachments",
+ "+components/sync/protocol",
"+content/public/browser",
- "+sync/api",
- "+sync/internal_api/public/attachments",
- "+sync/protocol",
"+third_party/cros_system_api/dbus/service_constants.h",
]
diff --git a/chromium/components/wifi_sync/wifi_config_delegate_chromeos_unittest.cc b/chromium/components/wifi_sync/wifi_config_delegate_chromeos_unittest.cc
index 7a84f66af26..1551a4ab41c 100644
--- a/chromium/components/wifi_sync/wifi_config_delegate_chromeos_unittest.cc
+++ b/chromium/components/wifi_sync/wifi_config_delegate_chromeos_unittest.cc
@@ -224,7 +224,7 @@ TEST_F(WifiConfigDelegateChromeOsTest,
if (!create_configuration_error_callback().is_null()) {
create_configuration_error_callback().Run(
"Config.CreateConfiguration Failed",
- base::WrapUnique(new base::DictionaryValue()));
+ base::MakeUnique<base::DictionaryValue>());
}
}
diff --git a/chromium/components/wifi_sync/wifi_credential.cc b/chromium/components/wifi_sync/wifi_credential.cc
index e4e9544cb92..bbbb492f260 100644
--- a/chromium/components/wifi_sync/wifi_credential.cc
+++ b/chromium/components/wifi_sync/wifi_credential.cc
@@ -50,7 +50,7 @@ std::unique_ptr<base::DictionaryValue> WifiCredential::ToOncProperties() const {
if (!WifiSecurityClassToOncSecurityString(security_class(), &onc_security)) {
NOTREACHED() << "Failed to convert SecurityClass with value "
<< security_class();
- return base::WrapUnique(new base::DictionaryValue());
+ return base::MakeUnique<base::DictionaryValue>();
}
std::unique_ptr<base::DictionaryValue> onc_properties(
diff --git a/chromium/components/wifi_sync/wifi_credential_syncable_service.cc b/chromium/components/wifi_sync/wifi_credential_syncable_service.cc
index 090533e5ad9..a244bd45ece 100644
--- a/chromium/components/wifi_sync/wifi_credential_syncable_service.cc
+++ b/chromium/components/wifi_sync/wifi_credential_syncable_service.cc
@@ -5,18 +5,19 @@
#include "components/wifi_sync/wifi_credential_syncable_service.h"
#include <stdint.h>
+
#include <utility>
#include <vector>
#include "base/logging.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_error_factory.h"
+#include "components/sync/api/sync_merge_result.h"
+#include "components/sync/protocol/sync.pb.h"
#include "components/wifi_sync/wifi_credential.h"
#include "components/wifi_sync/wifi_security_class.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/api/sync_merge_result.h"
-#include "sync/protocol/sync.pb.h"
namespace wifi_sync {
diff --git a/chromium/components/wifi_sync/wifi_credential_syncable_service.h b/chromium/components/wifi_sync/wifi_credential_syncable_service.h
index 3b5f938e93e..1e413b06944 100644
--- a/chromium/components/wifi_sync/wifi_credential_syncable_service.h
+++ b/chromium/components/wifi_sync/wifi_credential_syncable_service.h
@@ -12,11 +12,11 @@
#include "base/macros.h"
#include "components/keyed_service/core/keyed_service.h"
+#include "components/sync/api/sync_change_processor.h"
+#include "components/sync/api/syncable_service.h"
#include "components/wifi_sync/wifi_config_delegate.h"
#include "components/wifi_sync/wifi_credential.h"
#include "components/wifi_sync/wifi_security_class.h"
-#include "sync/api/sync_change_processor.h"
-#include "sync/api/syncable_service.h"
namespace wifi_sync {
diff --git a/chromium/components/wifi_sync/wifi_credential_syncable_service_factory.cc b/chromium/components/wifi_sync/wifi_credential_syncable_service_factory.cc
index 6f42289e74f..efd8a25269a 100644
--- a/chromium/components/wifi_sync/wifi_credential_syncable_service_factory.cc
+++ b/chromium/components/wifi_sync/wifi_credential_syncable_service_factory.cc
@@ -96,9 +96,9 @@ WifiCredentialSyncableServiceFactory::BuildWifiConfigDelegateChromeOs(
// ChromeBrowserMainPartsChromeos, and destroyed after all
// KeyedService instances are destroyed.
chromeos::NetworkHandler* network_handler = chromeos::NetworkHandler::Get();
- return base::WrapUnique(new WifiConfigDelegateChromeOs(
+ return base::MakeUnique<WifiConfigDelegateChromeOs>(
GetUserHash(context, !ignore_login_state_for_test_),
- network_handler->managed_network_configuration_handler()));
+ network_handler->managed_network_configuration_handler());
}
#endif
diff --git a/chromium/components/wifi_sync/wifi_credential_syncable_service_unittest.cc b/chromium/components/wifi_sync/wifi_credential_syncable_service_unittest.cc
index bbcfa79a0fc..710e9bd41c5 100644
--- a/chromium/components/wifi_sync/wifi_credential_syncable_service_unittest.cc
+++ b/chromium/components/wifi_sync/wifi_credential_syncable_service_unittest.cc
@@ -15,17 +15,17 @@
#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "base/tracked_objects.h"
+#include "components/sync/api/attachments/attachment_id.h"
+#include "components/sync/api/fake_sync_change_processor.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/api/sync_data.h"
+#include "components/sync/api/sync_error.h"
+#include "components/sync/api/sync_error_factory_mock.h"
+#include "components/sync/core/attachments/attachment_service_proxy_for_test.h"
+#include "components/sync/protocol/sync.pb.h"
#include "components/wifi_sync/wifi_config_delegate.h"
#include "components/wifi_sync/wifi_credential.h"
#include "components/wifi_sync/wifi_security_class.h"
-#include "sync/api/attachments/attachment_id.h"
-#include "sync/api/fake_sync_change_processor.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_error_factory_mock.h"
-#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
-#include "sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace wifi_sync {
@@ -146,8 +146,7 @@ class WifiCredentialSyncableServiceTest : public testing::Test {
change_processor_ = change_processor.get();
syncable_service_->MergeDataAndStartSyncing(
syncer::WIFI_CREDENTIALS, syncer::SyncDataList(),
- std::move(change_processor),
- base::WrapUnique(new SyncErrorFactoryMock()));
+ std::move(change_processor), base::MakeUnique<SyncErrorFactoryMock>());
}
private:
diff --git a/chromium/components/wifi_sync/wifi_security_class.h b/chromium/components/wifi_sync/wifi_security_class.h
index 1802b3525af..726635de15f 100644
--- a/chromium/components/wifi_sync/wifi_security_class.h
+++ b/chromium/components/wifi_sync/wifi_security_class.h
@@ -8,7 +8,7 @@
#include <string>
#include "build/build_config.h"
-#include "sync/protocol/sync.pb.h"
+#include "components/sync/protocol/sync.pb.h"
namespace wifi_sync {
diff --git a/chromium/components/zoom.gypi b/chromium/components/zoom.gypi
deleted file mode 100644
index 01ce038382a..00000000000
--- a/chromium/components/zoom.gypi
+++ /dev/null
@@ -1,53 +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.
-
-{
- 'targets': [
- {
- # GN version: //components/zoom
- 'target_name': 'zoom',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../ipc/ipc.gyp:ipc',
- '../net/net.gyp:net',
- '../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'zoom/page_zoom.cc',
- 'zoom/page_zoom.h',
- 'zoom/page_zoom_constants.cc',
- 'zoom/page_zoom_constants.h',
- 'zoom/zoom_controller.cc',
- 'zoom/zoom_controller.h',
- 'zoom/zoom_event_manager.cc',
- 'zoom/zoom_event_manager.h',
- 'zoom/zoom_event_manager_observer.h',
- 'zoom/zoom_observer.h'
- ],
- },
- {
- 'target_name': 'zoom_test_support',
- 'type': 'static_library',
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../content/content.gyp:content_browser',
- '../content/content.gyp:content_common',
- '../components/components.gyp:zoom',
- ],
- 'sources': [
- 'zoom/test/zoom_test_utils.cc',
- 'zoom/test/zoom_test_utils.h'
- ],
- }
- ],
-}
diff --git a/chromium/components/zoom/BUILD.gn b/chromium/components/zoom/BUILD.gn
index 4a2f3ea569c..42451b03979 100644
--- a/chromium/components/zoom/BUILD.gn
+++ b/chromium/components/zoom/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("zoom") {
+static_library("zoom") {
sources = [
"page_zoom.cc",
"page_zoom.h",
@@ -27,7 +27,7 @@ source_set("zoom") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"test/zoom_test_utils.cc",
diff --git a/chromium/components/zoom/page_zoom_constants.cc b/chromium/components/zoom/page_zoom_constants.cc
index 55bc6d2485e..388a337ae11 100644
--- a/chromium/components/zoom/page_zoom_constants.cc
+++ b/chromium/components/zoom/page_zoom_constants.cc
@@ -8,11 +8,12 @@
namespace zoom {
-// This list is duplicated in chrome/browser/resources/pdf/viewport.js. Please
-// make sure the two match.
-const double kPresetZoomFactors[] = {0.25, 0.333, 0.5, 0.666, 0.75, 0.9,
- 1.0, 1.1, 1.25, 1.5, 1.75, 2.0,
- 2.5, 3.0, 4.0, 5.0};
+// This list is duplicated in chrome/browser/resources/pdf/viewport.js and in
+// chrome/browser/resources/settings/appearance_page/appearance_page.js. Please
+// make sure the three match.
+const double kPresetZoomFactors[] = {0.25, 1 / 3.0, 0.5, 2 / 3.0, 0.75, 0.8,
+ 0.9, 1.0, 1.1, 1.25, 1.5, 1.75, 2.0, 2.5,
+ 3.0, 4.0, 5.0};
const std::size_t kPresetZoomFactorsSize = arraysize(kPresetZoomFactors);
} // namespace ui_zoom
diff --git a/chromium/components/zoom/zoom_controller.cc b/chromium/components/zoom/zoom_controller.cc
index 6ae4ddbaed9..1fa5f7f6382 100644
--- a/chromium/components/zoom/zoom_controller.cc
+++ b/chromium/components/zoom/zoom_controller.cc
@@ -25,7 +25,7 @@ double ZoomController::GetZoomLevelForWebContents(
if (!web_contents)
return 0.0;
- auto zoom_controller = FromWebContents(web_contents);
+ auto* zoom_controller = FromWebContents(web_contents);
if (zoom_controller)
return zoom_controller->GetZoomLevel();